From 7210f6e912c754fa989e16de440ec06cd31ca1f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Dec 2016 10:19:48 -0800 Subject: [PATCH 0001/1283] local changes Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 38 ++++++++++++++++++++++++++++++- src/smt/theory_pb.h | 52 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 1f11b9bf5..00232b7d5 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -227,7 +227,43 @@ namespace smt { SASSERT(sum >= k()); return true; } - + + // cardinality + + // + // + lbool theory_pb::cardinality::assign_at_least(theory_pb& th, literal lit) { + // literal is assigned to false. + context& ctx = th.get_context(); + SASSERT(m_type == le_t); + SASSERT(m_bound > 0); + SASSERT(m_args.size() >= 2*m_bound); + SASSERT(m_watch_sum < m_bound); + unsigned index = m_bound + 1; + bool all_false = true; + for (unsigned i = 0; i <= m_bound; ++i) { + if (m_args[i] == lit) { + index = i; + break; + } + all_false &= (value(args[i]) == l_false); + } + + for (unsigned i = m_bound + 1; i < m_args.size(); ++i) { + if (value(m_args[i]) != l_false) { + std::swap(m_args[index], m_args[i]); + // watch m_args[index] now + // end-clause-case + } + } + + if (all_false) { + + } + + return l_undef; + } + theory_pb::theory_pb(ast_manager& m, theory_pb_params& p): theory(m.mk_family_id("pb")), m_params(p), diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 7f621f9c5..4ad9feb06 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -181,6 +181,55 @@ namespace smt { }; + enum card_t { + eq_t, + le_t, + ge_t + }; + + struct cardinality { + literal m_lit; // literal repesenting predicate + card_t m_type; + literal_vector m_args; + unsigned m_bound; + unsigned m_watch_sum; + unsigned m_num_propagations; + unsigned m_compilation_threshold; + lbool m_compiled; + + cardinality(literal l, card_t t, unsigned bound): + m_lit(l), + m_type(t), + m_bound(bound), + m_watch_sum(0), + m_num_propagations(0), + m_compilation_threshold(0), + m_compiled(0) + {} + + std::ostream& display(std::ostream& out) const; + + app_ref to_expr(context& ctx); + + lbool assign_at_least(literal lit); + // + // lit occurs within m_bound positions + // m_bound <= m_args.size()/2 + // m_lit is pos + // type at least: m_args >= m_bound + // lit occurs with opposite sign in m_args + // type at most: m_args <= m_bound + // lit occurs with same sign in m_args + // search for literal above m_bound, such that + // either lit' is positive, type = ge_t + // lit' is negative, type = le_t + // lit' is unassigned + // swap lit and lit' in watch list + // If there is a single unassigned lit', and no other to swap, perform unit propagation + // If there are no literals to swap with, then create conflict clause + // + }; + struct row_info { unsigned m_slack; // slack variable in simplex tableau numeral m_bound; // bound @@ -216,9 +265,6 @@ namespace smt { theory_pb_params m_params; svector m_var_infos; -// u_map m_lwatch; // per literal. -// u_map m_vwatch; // per variable. -// u_map m_ineqs; // per inequality. arg_map m_ineq_rep; // Simplex: representative inequality u_map m_ineq_row_info; // Simplex: row information per variable uint_set m_vars; // Simplex: 0-1 variables. From e36eba116877f537060d1428b77fc7d75798ff9f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Dec 2016 09:58:23 -0800 Subject: [PATCH 0002/1283] added cardinality solver Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 5 + src/smt/theory_pb.cpp | 456 +++++++++++++++++++++++++++++++++++++--- src/smt/theory_pb.h | 113 ++++++---- 3 files changed, 501 insertions(+), 73 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index e6d4d0c07..f8d8cbaf8 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3342,6 +3342,11 @@ namespace smt { bool context::restart(lbool& status, unsigned curr_lvl) { + std::cout << "restart: " << m_lemmas.size() << "\n"; + for (unsigned i = 0; i < m_lemmas.size(); ++i) { + display_clause(std::cout, m_lemmas[i]); std::cout << "\n"; + } + if (m_last_search_failure != OK) { if (status != l_false) { // build candidate model before returning diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 7b066f1be..9c162164f 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -228,41 +228,193 @@ namespace smt { return true; } - // cardinality + // ----------------------------- + // cardinality constraints - // - // - lbool theory_pb::cardinality::assign_at_least(theory_pb& th, literal lit) { - // literal is assigned to false. + void theory_pb::card::negate() { + m_lit.neg(); + unsigned sz = size(); + for (unsigned i = 0; i < sz; ++i) { + m_args[i].neg(); + } + m_bound = sz - m_bound + 1; + } + + lbool theory_pb::card::assign(theory_pb& th, literal lit) { + TRACE("pb", tout << "assign: " << m_lit << " " << ~lit << " " << m_bound << "\n";); + // literal is assigned to false. context& ctx = th.get_context(); - SASSERT(m_type == le_t); SASSERT(m_bound > 0); - SASSERT(m_args.size() >= 2*m_bound); - SASSERT(m_watch_sum < m_bound); + SASSERT(ctx.get_assignment(lit) == l_false); unsigned index = m_bound + 1; - bool all_false = true; for (unsigned i = 0; i <= m_bound; ++i) { if (m_args[i] == lit) { index = i; break; } - all_false &= (value(args[i]) == l_false); } + SASSERT(index <= m_bound); + SASSERT(m_args[index] == lit); + + unsigned sz = size(); - for (unsigned i = m_bound + 1; i < m_args.size(); ++i) { - if (value(m_args[i]) != l_false) { + // find a literal to swap with: + for (unsigned i = m_bound + 1; i < sz; ++i) { + literal lit2 = m_args[i]; + if (ctx.get_assignment(lit2) != l_false) { + TRACE("pb", tout << "swap " << lit2 << "\n";); std::swap(m_args[index], m_args[i]); - // watch m_args[index] now - // end-clause-case + if (ctx.get_assignment(m_args[0]) == l_false) { + std::swap(m_args[0], m_args[index]); + } + th.watch_literal(lit2, this); + return l_undef; } } - if (all_false) { - - } + // conflict + if (0 != index && ctx.get_assignment(m_args[0]) == l_false) { + TRACE("pb", tout << "conflict " << m_args[0] << " " << lit << "\n";); + set_conflict(th, m_args[0], lit); + return l_false; + } - return l_undef; + TRACE("pb", tout << "no swap " << index << " " << lit << "\n";); + // there are no literals to swap with, + // prepare for unit propagation by swapping the false literal into + // position 0. Then literals in positions 1..m_bound have to be + // assigned l_true. + if (index != 0) { + std::swap(m_args[index], m_args[0]); + } + SASSERT(m_args[0] == lit); + literal_vector lits; + lits.push_back(~lit); + for (unsigned i = m_bound + 1; i < sz; ++i) { + SASSERT(ctx.get_assignment(m_args[i]) == l_false); + lits.push_back(~m_args[i]); + } + + for (unsigned i = 1; i <= m_bound; ++i) { + literal lit2 = m_args[i]; + lbool value = ctx.get_assignment(lit2); + switch (value) { + case l_true: + break; + case l_false: + TRACE("pb", tout << "conflict: " << lit << " " << lit2 << "\n";); + set_conflict(th, lit, lit2); + return l_false; + case l_undef: + SASSERT(validate_assign(th, lits, lit2)); + th.add_assign(*this, lits, lit2); + break; + } + } + + return l_true; } + + void theory_pb::card::set_conflict(theory_pb& th, literal l1, literal l2) { + SASSERT(validate_conflict(th)); + context& ctx = th.get_context(); + literal_vector lits; + SASSERT(ctx.get_assignment(l1) == l_false); + SASSERT(ctx.get_assignment(l2) == l_false); + lits.push_back(l1); + lits.push_back(l2); + unsigned sz = size(); + for (unsigned i = m_bound + 1; i < sz; ++i) { + SASSERT(ctx.get_assignment(m_args[i]) == l_false); + lits.push_back(m_args[i]); + } + th.add_clause(*this, lits); + } + + bool theory_pb::card::validate_conflict(theory_pb& th) { + context& ctx = th.get_context(); + unsigned num_false = 0; + for (unsigned i = 0; i < size(); ++i) { + if (ctx.get_assignment(m_args[i]) == l_false) { + ++num_false; + } + } + return size() - num_false < m_bound; + } + + bool theory_pb::card::validate_assign(theory_pb& th, literal_vector const& lits, literal l) { + context& ctx = th.get_context(); + SASSERT(ctx.get_assignment(l) == l_undef); + for (unsigned i = 0; i < lits.size(); ++i) { + SASSERT(ctx.get_assignment(lits[i]) == l_true); + } + return size() - lits.size() <= m_bound; + } + + void theory_pb::card::init_watch(theory_pb& th, bool is_true) { + context& ctx = th.get_context(); + + if (lit().sign() == is_true) { + negate(); + } + // put the non-false literals into the head. + unsigned i = 0, j = 0, sz = size(); + for (i = 0; i < sz; ++i) { + if (ctx.get_assignment(lit(i)) != l_false) { + if (j != i) { + std::swap(m_args[i], m_args[j]); + } + ++j; + } + } + // j is the number of non-false, sz - j the number of false. + if (j < m_bound) { + set_conflict(th, m_args[m_bound], m_args[m_bound-1]); + } + else if (j == m_bound) { + literal_vector lits(size() - m_bound, m_args.c_ptr() + m_bound); + for (i = 0; i < j; ++i) { + if (ctx.get_assignment(lit(i)) == l_undef) { + th.add_assign(*this, lits, lit(i)); + } + } + } + else { + for (unsigned i = 0; i <= m_bound; ++i) { + th.watch_literal(lit(i), this); + } + } + } + + + void theory_pb::card::add_arg(literal lit) { + if (lit == false_literal) { + return; + } + else if (lit == true_literal) { + if (m_bound > 0) { + --m_bound; + } + } + else { + m_args.push_back(lit); + } + + } + + void theory_pb::card::inc_propagations(theory_pb& th) { + ++m_num_propagations; + if (m_compiled == l_false && m_num_propagations >= m_compilation_threshold) { + // m_compiled = l_undef; + // th.m_to_compile.push_back(&c); + } + } + + + + + // ------------------------ + // theory_pb theory_pb::theory_pb(ast_manager& m, theory_pb_params& p): theory(m.mk_family_id("pb")), @@ -281,6 +433,7 @@ namespace smt { reset_eh(); } + theory * theory_pb::mk_fresh(context * new_ctx) { return alloc(theory_pb, new_ctx->get_manager(), m_params); } @@ -451,6 +604,7 @@ namespace smt { bool theory_pb::internalize_atom(app * atom, bool gate_ctx) { context& ctx = get_context(); + TRACE("pb", tout << mk_pp(atom, get_manager()) << "\n";); if (ctx.b_internalized(atom)) { return false; } @@ -462,12 +616,16 @@ namespace smt { ctx.set_var_theory(abv, get_id()); return true; } + + if (internalize_card(atom, gate_ctx)) { + return true; + } + SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom) || m_util.is_ge(atom) || m_util.is_at_least_k(atom) || m_util.is_eq(atom)); - unsigned num_args = atom->get_num_args(); bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); @@ -680,7 +838,7 @@ namespace smt { return negate?~literal(bv):literal(bv); } - void theory_pb::del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index) { + void theory_pb::del_watch(ineq_watch& watch, unsigned index, ineq& c, unsigned ineq_index) { SASSERT(c.is_ge()); if (index < watch.size()) { std::swap(watch[index], watch[watch.size()-1]); @@ -730,6 +888,7 @@ namespace smt { } } + void theory_pb::watch_literal(literal lit, ineq* c) { init_watch(lit.var()); ptr_vector* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; @@ -740,6 +899,7 @@ namespace smt { ineqs->push_back(c); } + void theory_pb::watch_var(bool_var v, ineq* c) { init_watch(v); ptr_vector* ineqs = m_var_infos[v].m_var_watch; @@ -774,6 +934,182 @@ namespace smt { } } + // ---------------------------- + // cardinality constraints + + class theory_pb::card_justification : public theory_propagation_justification { + card& m_card; + public: + card_justification(card& c, family_id fid, region & r, + unsigned num_lits, literal const * lits, literal consequent): + theory_propagation_justification(fid, r, num_lits, lits, consequent), + m_card(c) + {} + card& get_card() { return m_card; } + }; + + + bool theory_pb::is_cardinality_constraint(app * atom) { + if (m_util.is_ge(atom) && m_util.has_unit_coefficients(atom)) { + return true; + } + if (m_util.is_at_most_k(atom)) { + return true; + } + // TBD: other conditions + return false; + } + + bool theory_pb::internalize_card(app * atom, bool gate_ctx) { + if (!is_cardinality_constraint(atom)) { + return false; + } + context& ctx = get_context(); + unsigned num_args = atom->get_num_args(); + bool_var abv = ctx.mk_bool_var(atom); + ctx.set_var_theory(abv, get_id()); + unsigned bound = m_util.get_k(atom).get_unsigned(); + + card* c = alloc(card, literal(abv), bound); + + for (unsigned i = 0; i < num_args; ++i) { + expr* arg = atom->get_arg(i); + c->add_arg(compile_arg(arg)); + } + + literal lit(abv); + + if (c->k() == 0) { + ctx.mk_th_axiom(get_id(), 1, &lit); + dealloc(c); + } + else if (c->k() > c->size()) { + lit.neg(); + ctx.mk_th_axiom(get_id(), 1, &lit); + dealloc(c); + } + else if (c->k() == c->size()) { + literal_vector lits; + for (unsigned i = 0; i < c->size(); ++i) { + lits.push_back(~c->lit(i)); + } + lits.push_back(lit); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + lit.neg(); + for (unsigned i = 0; i < c->size(); ++i) { + literal lits2[2] = { lit, c->lit(i) }; + ctx.mk_th_axiom(get_id(), 2, lits2); + } + dealloc(c); + } + else { + SASSERT(0 < c->k() && c->k() < c->size()); + + // initialize compilation thresholds, TBD + + init_watch(abv); + m_var_infos[abv].m_card = c; + m_card_trail.push_back(abv); + } + return true; + } + + void theory_pb::watch_literal(literal lit, card* c) { + init_watch(lit.var()); + ptr_vector* cards = m_var_infos[lit.var()].m_lit_cwatch[lit.sign()]; + if (cards == 0) { + cards = alloc(ptr_vector); + m_var_infos[lit.var()].m_lit_cwatch[lit.sign()] = cards; + } + cards->push_back(c); + } + + + void theory_pb::unwatch_literal(literal lit, card* c) { + if (m_var_infos.size() <= static_cast(lit.var())) { + return; + } + ptr_vector* cards = m_var_infos[lit.var()].m_lit_cwatch[lit.sign()]; + if (cards) { + remove(*cards, c); + } + } + + void theory_pb::remove(ptr_vector& cards, card* c) { + for (unsigned j = 0; j < cards.size(); ++j) { + if (cards[j] == c) { + std::swap(cards[j], cards[cards.size()-1]); + cards.pop_back(); + break; + } + } + } + + std::ostream& theory_pb::display(std::ostream& out, card const& c, bool values) const { + ast_manager& m = get_manager(); + context& ctx = get_context(); + out << c.lit(); + if (c.lit() != null_literal) { + if (values) { + out << "@(" << ctx.get_assignment(c.lit()); + if (ctx.get_assignment(c.lit()) != l_undef) { + out << ":" << ctx.get_assign_level(c.lit()); + } + out << ")"; + } + ctx.display_literal_verbose(out, c.lit()); out << "\n"; + } + else { + out << " "; + } + for (unsigned i = 0; i < c.size(); ++i) { + literal l = c.lit(i); + out << l; + if (values) { + out << "@(" << ctx.get_assignment(l); + if (ctx.get_assignment(l) != l_undef) { + out << ":" << ctx.get_assign_level(l); + } + out << ") "; + } + } + out << " >= " << c.k() << "\n"; + if (c.num_propagations()) out << "propagations: " << c.num_propagations() << "\n"; + return out; + } + + + void theory_pb::add_clause(card& c, literal_vector const& lits) { + m_stats.m_num_conflicts++; + context& ctx = get_context(); + justification* js = 0; + if (proofs_enabled()) { + js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); + } + c.inc_propagations(*this); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + } + + void theory_pb::add_assign(card& c, literal_vector const& lits, literal l) { + c.inc_propagations(*this); + m_stats.m_num_propagations++; + context& ctx = get_context(); + TRACE("pb", tout << "#prop:" << c.num_propagations() << " - " << lits << " " << c.lit() << " => " << l << "\n";); + + ctx.assign(l, ctx.mk_justification( + card_justification( + c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); + } + + void theory_pb::clear_watch(card& c) { + for (unsigned i = 0; i <= c.k(); ++i) { + literal w = c.lit(i); + unwatch_literal(w, &c); + } + } + + // + void theory_pb::collect_statistics(::statistics& st) const { st.update("pb conflicts", m_stats.m_num_conflicts); st.update("pb propagations", m_stats.m_num_propagations); @@ -791,6 +1127,8 @@ namespace smt { } m_ineqs_trail.reset(); m_ineqs_lim.reset(); + m_card_trail.reset(); + m_card_lim.reset(); m_stats.reset(); m_to_compile.reset(); } @@ -807,6 +1145,7 @@ namespace smt { void theory_pb::assign_eh(bool_var v, bool is_true) { ptr_vector* ineqs = 0; + context& ctx = get_context(); literal nlit(v, is_true); init_watch(v); TRACE("pb", tout << "assign: " << ~nlit << "\n";); @@ -867,6 +1206,39 @@ namespace smt { assign_eq(*c, is_true); } } + + ptr_vector* cards = m_var_infos[v].m_lit_cwatch[nlit.sign()]; + if (cards != 0 && !ctx.inconsistent()) { + ptr_vector::iterator it = cards->begin(), it2 = it, end = cards->end(); + for (; it != end; ++it) { + if (ctx.get_assignment((*it)->lit()) != l_true) { + continue; + } + switch ((*it)->assign(*this, nlit)) { + case l_false: // conflict + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + cards->set_end(it2); + return; + case l_undef: // watch literal was swapped + break; + case l_true: // unit propagation, keep watching the literal + if (it2 != it) { + *it2 = *it; + } + ++it2; + break; + } + } + cards->set_end(it2); + } + + card* crd = m_var_infos[v].m_card; + if (crd != 0 && !ctx.inconsistent()) { + crd->init_watch(*this, is_true); + } + } literal_vector& theory_pb::get_all_literals(ineq& c, bool negate) { @@ -931,6 +1303,7 @@ namespace smt { } }; + class theory_pb::negate_ineq : public trail { ineq& c; public: @@ -953,7 +1326,6 @@ namespace smt { ctx.push_trail(value_trail(c.m_nfixed)); ctx.push_trail(rewatch_vars(*this, c)); - clear_watch(c); SASSERT(c.is_ge()); unsigned sz = c.size(); if (c.lit().sign() == is_true) { @@ -1112,7 +1484,7 @@ namespace smt { inequalities are unit literals and formulas in negation normal form (inequalities are closed under negation). */ - bool theory_pb::assign_watch_ge(bool_var v, bool is_true, watch_list& watch, unsigned watch_index) { + bool theory_pb::assign_watch_ge(bool_var v, bool is_true, ineq_watch& watch, unsigned watch_index) { bool removed = false; context& ctx = get_context(); ineq& c = *watch[watch_index]; @@ -1343,6 +1715,7 @@ namespace smt { void theory_pb::push_scope_eh() { m_ineqs_lim.push_back(m_ineqs_trail.size()); + m_card_lim.push_back(m_card_trail.size()); } void theory_pb::pop_scope_eh(unsigned num_scopes) { @@ -1370,6 +1743,20 @@ namespace smt { dealloc(c); } m_ineqs_lim.resize(new_lim); + + + new_lim = m_card_lim.size() - num_scopes; + sz = m_card_lim[new_lim]; + while (m_card_trail.size() > sz) { + bool_var v = m_card_trail.back(); + m_card_trail.pop_back(); + card* c = m_var_infos[v].m_card; + clear_watch(*c); + m_var_infos[v].m_card = 0; + dealloc(c); + } + + m_card_lim.resize(new_lim); } void theory_pb::clear_watch(ineq& c) { @@ -1454,11 +1841,8 @@ namespace smt { inc_propagations(c); m_stats.m_num_propagations++; context& ctx = get_context(); - TRACE("pb", tout << "#prop:" << c.m_num_propagations << " - "; - for (unsigned i = 0; i < lits.size(); ++i) { - tout << lits[i] << " "; - } - tout << "=> " << l << "\n"; + TRACE("pb", tout << "#prop:" << c.m_num_propagations << " - " << lits; + tout << " => " << l << "\n"; display(tout, c, true);); ctx.assign(l, ctx.mk_justification( @@ -1466,7 +1850,7 @@ namespace smt { c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); } - + void theory_pb::add_clause(ineq& c, literal_vector const& lits) { inc_propagations(c); @@ -2113,9 +2497,9 @@ namespace smt { } void theory_pb::display_watch(std::ostream& out, bool_var v, bool sign) const { - watch_list const* w = m_var_infos[v].m_lit_watch[sign]; + ineq_watch const* w = m_var_infos[v].m_lit_watch[sign]; if (!w) return; - watch_list const& wl = *w; + ineq_watch const& wl = *w; out << "watch: " << literal(v, sign) << " |-> "; for (unsigned i = 0; i < wl.size(); ++i) { out << wl[i]->lit() << " "; @@ -2129,10 +2513,10 @@ namespace smt { display_watch(out, vi, true); } for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { - watch_list const* w = m_var_infos[vi].m_var_watch; + ineq_watch const* w = m_var_infos[vi].m_var_watch; if (!w) continue; out << "watch (v): " << literal(vi) << " |-> "; - watch_list const& wl = *w; + ineq_watch const& wl = *w; for (unsigned i = 0; i < wl.size(); ++i) { out << wl[i]->lit() << " "; } @@ -2144,6 +2528,14 @@ namespace smt { display(out, *c, true); } } + + for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { + card* c = m_var_infos[vi].m_card; + if (c) { + display(out, *c, true); + } + } + } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 4ad9feb06..f86615e6c 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -37,6 +37,9 @@ namespace smt { class negate_ineq; class remove_var; class undo_bound; + + class card_justification; + typedef rational numeral; typedef simplex::simplex simplex; typedef simplex::row row; @@ -181,55 +184,55 @@ namespace smt { }; - enum card_t { - eq_t, - le_t, - ge_t - }; - - struct cardinality { + // cardinality constraint args >= bound + class card { literal m_lit; // literal repesenting predicate - card_t m_type; literal_vector m_args; unsigned m_bound; - unsigned m_watch_sum; unsigned m_num_propagations; unsigned m_compilation_threshold; lbool m_compiled; - cardinality(literal l, card_t t, unsigned bound): + public: + card(literal l, unsigned bound): m_lit(l), - m_type(t), m_bound(bound), - m_watch_sum(0), m_num_propagations(0), m_compilation_threshold(0), - m_compiled(0) - {} + m_compiled(l_false) + { + } + + literal lit() const { return m_lit; } + literal lit(unsigned i) const { return m_args[i]; } + unsigned k() const { return m_bound; } + unsigned size() const { return m_args.size(); } + unsigned num_propagations() const { return m_num_propagations; } + void add_arg(literal l); + + void init_watch(theory_pb& th, bool is_true); - std::ostream& display(std::ostream& out) const; + lbool assign(theory_pb& th, literal lit); + + void negate(); app_ref to_expr(context& ctx); - lbool assign_at_least(literal lit); - // - // lit occurs within m_bound positions - // m_bound <= m_args.size()/2 - // m_lit is pos - // type at least: m_args >= m_bound - // lit occurs with opposite sign in m_args - // type at most: m_args <= m_bound - // lit occurs with same sign in m_args - // search for literal above m_bound, such that - // either lit' is positive, type = ge_t - // lit' is negative, type = le_t - // lit' is unassigned - // swap lit and lit' in watch list - // If there is a single unassigned lit', and no other to swap, perform unit propagation - // If there are no literals to swap with, then create conflict clause - // + void inc_propagations(theory_pb& th); + private: + + bool validate_conflict(theory_pb& th); + + bool validate_assign(theory_pb& th, literal_vector const& lits, literal l); + + void set_conflict(theory_pb& th, literal l1, literal l2); }; + typedef ptr_vector card_watch; + typedef ptr_vector ineq_watch; + typedef map arg_map; + + struct row_info { unsigned m_slack; // slack variable in simplex tableau numeral m_bound; // bound @@ -239,18 +242,21 @@ namespace smt { row_info(): m_slack(0) {} }; - typedef ptr_vector watch_list; - typedef map arg_map; struct var_info { - watch_list* m_lit_watch[2]; - watch_list* m_var_watch; - ineq* m_ineq; + ineq_watch* m_lit_watch[2]; + ineq_watch* m_var_watch; + ineq* m_ineq; + + card_watch* m_lit_cwatch[2]; + card* m_card; - var_info(): m_var_watch(0), m_ineq(0) + var_info(): m_var_watch(0), m_ineq(0), m_card(0) { m_lit_watch[0] = 0; m_lit_watch[1] = 0; + m_lit_cwatch[0] = 0; + m_lit_cwatch[1] = 0; } void reset() { @@ -258,6 +264,9 @@ namespace smt { dealloc(m_lit_watch[1]); dealloc(m_var_watch); dealloc(m_ineq); + dealloc(m_lit_cwatch[0]); + dealloc(m_lit_cwatch[1]); + dealloc(m_card); } }; @@ -287,9 +296,11 @@ namespace smt { // internalize_atom: literal compile_arg(expr* arg); - void add_watch(ineq& c, unsigned index); - void del_watch(watch_list& watch, unsigned index, ineq& c, unsigned ineq_index); void init_watch(bool_var v); + + // general purpose pb constraints + void add_watch(ineq& c, unsigned index); + void del_watch(ineq_watch& watch, unsigned index, ineq& c, unsigned ineq_index); void init_watch_literal(ineq& c); void init_watch_var(ineq& c); void clear_watch(ineq& c); @@ -298,11 +309,31 @@ namespace smt { void unwatch_literal(literal w, ineq* c); void unwatch_var(bool_var v, ineq* c); void remove(ptr_vector& ineqs, ineq* c); - bool assign_watch_ge(bool_var v, bool is_true, watch_list& watch, unsigned index); + + bool assign_watch_ge(bool_var v, bool is_true, ineq_watch& watch, unsigned index); void assign_watch(bool_var v, bool is_true, ineq& c); void assign_ineq(ineq& c, bool is_true); void assign_eq(ineq& c, bool is_true); + // cardinality constraints + // these are cheaper to handle than general purpose PB constraints + // and in the common case PB constraints with small coefficients can + // be handled using cardinality constraints. + + unsigned_vector m_card_trail; + unsigned_vector m_card_lim; + bool is_cardinality_constraint(app * atom); + bool internalize_card(app * atom, bool gate_ctx); + + void watch_literal(literal lit, card* c); + void unwatch_literal(literal w, card* c); + void add_clause(card& c, literal_vector const& lits); + void add_assign(card& c, literal_vector const& lits, literal l); + void remove(ptr_vector& cards, card* c); + void clear_watch(card& c); + std::ostream& display(std::ostream& out, card const& c, bool values = false) const; + + // simplex: literal set_explain(literal_vector& explains, unsigned var, literal expl); bool update_bound(bool_var v, literal explain, bool is_lower, mpq_inf const& bound); From cb6c6332b36a4605527eb6897f6c68115340815a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Dec 2016 12:44:30 -0800 Subject: [PATCH 0003/1283] update conflict resolution for cardinality case Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb_rewriter.cpp | 2 +- src/smt/smt_context.cpp | 4 - src/smt/smt_context_pp.cpp | 7 +- src/smt/smt_internalizer.cpp | 1 + src/smt/theory_pb.cpp | 476 +++++++++++-------------------- src/smt/theory_pb.h | 27 +- 6 files changed, 189 insertions(+), 328 deletions(-) diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 0fdbc858d..b193a8a45 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -264,7 +264,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons result = m_util.mk_eq(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k); } } - else if (all_unit && k.is_one()) { + else if (all_unit && k.is_one() && sz < 10) { result = mk_or(m, sz, m_args.c_ptr()); } else if (all_unit && k == rational(sz)) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index f8d8cbaf8..05baff532 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3342,10 +3342,6 @@ namespace smt { bool context::restart(lbool& status, unsigned curr_lvl) { - std::cout << "restart: " << m_lemmas.size() << "\n"; - for (unsigned i = 0; i < m_lemmas.size(); ++i) { - display_clause(std::cout, m_lemmas[i]); std::cout << "\n"; - } if (m_last_search_failure != OK) { if (status != l_false) { diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index ff45c5089..84848d8e9 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -599,21 +599,20 @@ namespace smt { break; case b_justification::BIN_CLAUSE: { literal l2 = j.get_literal(); - out << "bin-clause "; - display_literal(out, l2); + out << "bin-clause " << 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) out << literal_vector(cls->get_num_literals(), cls->begin_literals()); break; } case b_justification::JUSTIFICATION: { out << "justification "; literal_vector lits; const_cast(*m_conflict_resolution).justification2literals(j.get_justification(), lits); - display_literals_verbose(out, lits.size(), lits.c_ptr()); + out << lits; break; } default: diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index f7936eacd..a0905cf3b 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1343,6 +1343,7 @@ namespace smt { cls->swap_lits(1, w2_idx); TRACE("mk_th_lemma", display_clause(tout, cls); tout << "\n";); } + // display_clause(std::cout, cls); std::cout << "\n"; m_lemmas.push_back(cls); add_watch_literal(cls, 0); add_watch_literal(cls, 1); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 9c162164f..ecdcc0618 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -65,9 +65,6 @@ namespace smt { }; }; - const unsigned theory_pb::null_index = UINT_MAX; - - unsigned theory_pb::arg_t::get_hash() const { return get_composite_hash(*this, size()); } @@ -275,7 +272,7 @@ namespace smt { // conflict if (0 != index && ctx.get_assignment(m_args[0]) == l_false) { TRACE("pb", tout << "conflict " << m_args[0] << " " << lit << "\n";); - set_conflict(th, m_args[0], lit); + set_conflict(th, lit); return l_false; } @@ -289,6 +286,7 @@ namespace smt { } SASSERT(m_args[0] == lit); literal_vector lits; + lits.push_back(m_lit); lits.push_back(~lit); for (unsigned i = m_bound + 1; i < sz; ++i) { SASSERT(ctx.get_assignment(m_args[i]) == l_false); @@ -303,7 +301,7 @@ namespace smt { break; case l_false: TRACE("pb", tout << "conflict: " << lit << " " << lit2 << "\n";); - set_conflict(th, lit, lit2); + set_conflict(th, lit2); return l_false; case l_undef: SASSERT(validate_assign(th, lits, lit2)); @@ -314,15 +312,26 @@ namespace smt { return l_true; } + + /** + \brief The conflict clause position for cardinality constraint have the following properties: + 0. The position for the literal corresponding to the cardinality constraint. + 1. The literal at position 0 of the cardinality constraint. + 2. The asserting literal. + 3. .. the remaining false literals. + */ - void theory_pb::card::set_conflict(theory_pb& th, literal l1, literal l2) { + void theory_pb::card::set_conflict(theory_pb& th, literal l) { SASSERT(validate_conflict(th)); context& ctx = th.get_context(); + literal l0 = m_args[0]; literal_vector lits; - SASSERT(ctx.get_assignment(l1) == l_false); - SASSERT(ctx.get_assignment(l2) == l_false); - lits.push_back(l1); - lits.push_back(l2); + SASSERT(ctx.get_assignment(l0) == l_false); + SASSERT(ctx.get_assignment(l) == l_false); + SASSERT(ctx.get_assignment(lit()) == l_true); + lits.push_back(~lit()); + lits.push_back(l0); + lits.push_back(l); unsigned sz = size(); for (unsigned i = m_bound + 1; i < sz; ++i) { SASSERT(ctx.get_assignment(m_args[i]) == l_false); @@ -369,7 +378,20 @@ namespace smt { } // j is the number of non-false, sz - j the number of false. if (j < m_bound) { - set_conflict(th, m_args[m_bound], m_args[m_bound-1]); + std::swap(m_args[0], m_args[m_bound-1]); + // + // we need the assignment level of the asserting literal to be maximal. + // such that conflict resolution can use the asserting literal as a starting + // point. + if (ctx.get_assign_level(m_args[0]) > ctx.get_assign_level(m_args[m_bound])) { + std::swap(m_args[0], m_args[m_bound]); + } + for (i = m_bound + 1; i < sz; ++i) { + if (ctx.get_assign_level(m_args[i]) > ctx.get_assign_level(m_args[m_bound])) { + std::swap(m_args[i], m_args[m_bound]); + } + } + set_conflict(th, m_args[m_bound]); } else if (j == m_bound) { literal_vector lits(size() - m_bound, m_args.c_ptr() + m_bound); @@ -557,7 +579,6 @@ namespace smt { } row r = m_simplex.get_infeasible_row(); - // m_simplex.display_row(std::cout, r, true); mpz const& coeff = m_simplex.get_base_coeff(r); bool_var base_var = m_simplex.get_base_var(r); SASSERT(m_simplex.below_lower(base_var) || m_simplex.above_upper(base_var)); @@ -1086,6 +1107,7 @@ namespace smt { if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); } + resolve_conflict(c, lits); c.inc_propagations(*this); ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); } @@ -1094,7 +1116,7 @@ namespace smt { c.inc_propagations(*this); m_stats.m_num_propagations++; context& ctx = get_context(); - TRACE("pb", tout << "#prop:" << c.num_propagations() << " - " << lits << " " << c.lit() << " => " << l << "\n";); + TRACE("pb", tout << "#prop: " << c.num_propagations() << " - " << lits << " " << c.lit() << " => " << l << "\n";); ctx.assign(l, ctx.mk_justification( card_justification( @@ -1488,7 +1510,6 @@ namespace smt { bool removed = false; context& ctx = get_context(); ineq& c = *watch[watch_index]; - //display(std::cout << v << " ", c, true); unsigned w = c.find_lit(v, 0, c.watch_size()); SASSERT(ctx.get_assignment(c.lit()) == l_true); SASSERT(is_true == c.lit(w).sign()); @@ -1856,229 +1877,128 @@ namespace smt { inc_propagations(c); m_stats.m_num_conflicts++; context& ctx = get_context(); -#if 0 - if (m_stats.m_num_conflicts == 1000) { - display(std::cout); - } -#endif - TRACE("pb", tout << "#prop:" << c.m_num_propagations << " - "; - for (unsigned i = 0; i < lits.size(); ++i) { - tout << lits[i] << " "; - } - tout << "\n"; - display(tout, c, true);); - + TRACE("pb", tout << "#prop:" << c.m_num_propagations << " - " << lits << "\n"; + display(tout, c, true);); justification* js = 0; - - if (m_conflict_frequency == 0 || (m_conflict_frequency -1 == (c.m_num_propagations % m_conflict_frequency))) { - resolve_conflict(c); - } if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); } - TRACE("pb", tout << lits << "\n";); ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); } - void theory_pb::set_mark(bool_var v, unsigned idx) { - SASSERT(v != null_bool_var); - if (v >= static_cast(m_conseq_index.size())) { - m_conseq_index.resize(v+1, null_index); + int theory_pb::get_coeff(bool_var v) const { + return m_coeffs.get(v, 0); + } + + + void theory_pb::reset_coeffs() { + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + m_coeffs[m_active_coeffs[i]] = 0; } - SASSERT(!is_marked(v) || m_conseq_index[v] == idx); - m_marked.push_back(v); - m_conseq_index[v] = idx; + m_active_coeffs.reset(); } - bool theory_pb::is_marked(bool_var v) const { - return - (v < static_cast(m_conseq_index.size())) && - (m_conseq_index[v] != null_index); - } - - void theory_pb::unset_mark(bool_var v) { - SASSERT(v != null_bool_var); - if (v < static_cast(m_conseq_index.size())) { - m_conseq_index[v] = null_index; - } - } - - void theory_pb::unset_marks() { - for (unsigned i = 0; i < m_marked.size(); ++i) { - unset_mark(m_marked[i]); - } - m_marked.reset(); - } - - void theory_pb::process_antecedent(literal l, numeral coeff) { + void theory_pb::process_antecedent(literal l, int offset) { context& ctx = get_context(); + SASSERT(ctx.get_assignment(l) == l_false); bool_var v = l.var(); unsigned lvl = ctx.get_assign_level(v); - if (ctx.get_assignment(l) != l_false) { - m_lemma.m_k -= coeff; - if (m_learn_complements && is_marked(v)) { - SASSERT(ctx.get_assignment(l) == l_true); - numeral& lcoeff = m_lemma[m_conseq_index[v]].second; - lcoeff -= coeff; - if (!lcoeff.is_pos()) { - // perhaps let lemma simplification change coefficient - // when negative? - remove_from_lemma(m_conseq_index[v]); - } - } + TRACE("pb", tout << l << " " << ctx.is_marked(v) << " " << m_conflict_lvl << " " << ctx.get_base_level() << "\n";); + if (lvl > ctx.get_base_level() && !ctx.is_marked(v) && lvl == m_conflict_lvl) { + ctx.set_mark(v); + ++m_num_marks; } - else if (lvl > ctx.get_base_level()) { - if (is_marked(v)) { - m_lemma[m_conseq_index[v]].second += coeff; - SASSERT(m_lemma[m_conseq_index[v]].second.is_pos()); - } - else { - if (lvl == m_conflict_lvl) { - TRACE("pb", tout << "add mark: " << l << " " << coeff << "\n";); - ++m_num_marks; - } - set_mark(v, m_lemma.size()); - m_lemma.push_back(std::make_pair(l, coeff)); - } - TRACE("pb_verbose", tout - << "ante: " << m_lemma.lit(m_conseq_index[v]) << "*" - << m_lemma.coeff(m_conseq_index[v]) << " " << lvl << "\n";); + if (lvl > ctx.get_base_level()) { + inc_coeff(l, offset); } } - void theory_pb::process_ineq(ineq& c, literal conseq, numeral coeff1) { - - // - // Create CUT. - // - - // - // . find coeff2 - // . find lcm of coefficients to conseq. - // . multiply m_lemma by lcm/coeff coefficient to align. - // . create lcm/coeff_2 to multiply on this side. - // . cut resolve constraints. - // - + void theory_pb::process_card(card& c, int offset) { context& ctx = get_context(); - numeral coeff2 = (conseq==null_literal)?numeral::one():numeral::zero(); - for (unsigned i = 0; i < c.size(); ++i) { - if (c.lit(i) == conseq) { - coeff2 = c.coeff(i); - break; - } + process_antecedent(c.lit(0), offset); + for (unsigned i = c.k() + 1; i < c.size(); ++i) { + process_antecedent(c.lit(i), offset); } - SASSERT(coeff2.is_pos()); - numeral lc = lcm(coeff1, coeff2); - numeral g = lc/coeff1; - SASSERT(g.is_int()); - if (g > numeral::one()) { - for (unsigned i = 0; i < m_lemma.size(); ++i) { - m_lemma[i].second *= g; - } - m_lemma.m_k *= g; + for (unsigned i = 1; i <= c.k(); ++i) { + inc_coeff(c.lit(i), offset); } - g = lc/coeff2; - SASSERT(g.is_int()); - m_lemma.m_k += g*c.k(); - - for (unsigned i = 0; i < c.size(); ++i) { - process_antecedent(c.lit(i), g*c.coeff(i)); - } - - SASSERT(ctx.get_assignment(c.lit()) == l_true); if (ctx.get_assign_level(c.lit()) > ctx.get_base_level()) { - m_ineq_literals.push_back(c.lit()); + m_antecedents.push_back(c.lit()); } + SASSERT(ctx.get_assignment(c.lit()) == l_true); + } + + void theory_pb::inc_coeff(literal l, int offset) { + if (l.sign()) { + m_bound -= offset; + } + bool_var v = l.var(); + SASSERT(v != null_bool_var); + if (static_cast(m_coeffs.size()) <= v) { + m_coeffs.resize(v + 1, 0); + } + if (m_coeffs[v] == 0) { + m_active_coeffs.push_back(v); + } + int inc = l.sign() ? -offset : offset; + m_coeffs[v] += inc; } - // - // modeled after sat_solver/smt_context - // - bool theory_pb::resolve_conflict(ineq& c) { + bool theory_pb::resolve_conflict(card& c, literal_vector const& confl) { - if (!c.is_ge()) { - return false; - } - TRACE("pb", display(tout, c, true);); + TRACE("pb", display(tout, c, true); get_context().display(tout);); bool_var v; - literal conseq; context& ctx = get_context(); - unsigned& lvl = m_conflict_lvl = 0; - for (unsigned i = 0; i < c.size(); ++i) { - if (ctx.get_assignment(c.lit(i)) == l_false) { - lvl = std::max(lvl, ctx.get_assign_level(c.lit(i))); - } + m_conflict_lvl = 0; + for (unsigned i = 0; i < confl.size(); ++i) { + literal lit = confl[i]; + SASSERT(ctx.get_assignment(lit) == l_false); + m_conflict_lvl = std::max(m_conflict_lvl, ctx.get_assign_level(lit)); } - if (lvl < ctx.get_assign_level(c.lit()) || lvl == ctx.get_base_level()) { + if (m_conflict_lvl < ctx.get_assign_level(c.lit()) || m_conflict_lvl == ctx.get_base_level()) { return false; } - unset_marks(); + reset_coeffs(); m_num_marks = 0; - m_lemma.reset(); - m_lemma.m_k.reset(); - m_ineq_literals.reset(); - process_ineq(c, null_literal, numeral::one()); // add consequent to lemma. + m_bound = c.k(); + m_antecedents.reset(); + literal_vector ante; + process_card(c, 1); + // point into stack of assigned literals literal_vector const& lits = ctx.assigned_literals(); SASSERT(!lits.empty()); unsigned idx = lits.size()-1; - + b_justification js; + literal conseq = ~confl[2]; + while (m_num_marks > 0) { - TRACE("pb_verbose", display(tout << "lemma ", m_lemma);); + v = conseq.var(); + TRACE("pb", display_resolved_lemma(tout << conseq << "\n");); - lbool is_sat = m_lemma.normalize(false); - if (is_sat == l_false) { - break; - } - if (is_sat == l_true) { - IF_VERBOSE(0, verbose_stream() << "lemma already evaluated\n";); - TRACE("pb", tout << "lemma already evaluated\n";); - return false; - } - TRACE("pb", display(tout, m_lemma);); - SASSERT(m_lemma.well_formed()); - // - // find the next marked variable in the assignment stack - // - do { - conseq = lits[idx]; - v = conseq.var(); - --idx; + int offset = get_coeff(v); + + if (offset == 0) { + goto process_next_resolvent; } - while (!is_marked(v) && idx > 0); - if (idx == 0 && !is_marked(v)) { - // - // Yes, this can (currently) happen because - // the decisions for performing unit propagation - // are made asynchronously. - // In other words, PB unit propagation does not follow the - // same order as the assignment stack. - // It is not a correctness bug but causes to miss lemmas. - // - IF_VERBOSE(12, display_resolved_lemma(verbose_stream());); - TRACE("pb", display_resolved_lemma(tout);); - return false; + else if (offset < 0) { + offset = -offset; } + + js = ctx.get_justification(v); + + TRACE("pb", tout << "conseq: " << conseq << "\n";); - unsigned conseq_index = m_conseq_index[v]; - numeral conseq_coeff = m_lemma.coeff(conseq_index); + inc_coeff(conseq, offset); - TRACE("pb", display(tout, m_lemma, true); - tout << "conseq: " << conseq << " at index: " << conseq_index << "\n";); - - SASSERT(~conseq == m_lemma.lit(conseq_index)); - - remove_from_lemma(conseq_index); - - b_justification js = ctx.get_justification(v); + m_bound += offset; // // Resolve selected conseq with antecedents. @@ -2092,109 +2012,68 @@ namespace smt { if (cjs && !is_proof_justification(*cjs)) { TRACE("pb", tout << "skipping justification for clause over: " << conseq << " " << typeid(*cjs).name() << "\n";); - m_ineq_literals.push_back(conseq); break; } unsigned num_lits = cls.get_num_literals(); if (cls.get_literal(0) == conseq) { - process_antecedent(cls.get_literal(1), conseq_coeff); + process_antecedent(cls.get_literal(1), offset); } else { SASSERT(cls.get_literal(1) == conseq); - process_antecedent(cls.get_literal(0), conseq_coeff); + process_antecedent(cls.get_literal(0), offset); } for (unsigned i = 2; i < num_lits; ++i) { - process_antecedent(cls.get_literal(i), conseq_coeff); + process_antecedent(cls.get_literal(i), offset); } - TRACE("pb", for (unsigned i = 0; i < num_lits; ++i) tout << cls.get_literal(i) << " "; tout << "\n";); + TRACE("pb", tout << literal_vector(cls.get_num_literals(), cls.begin_literals()) << "\n";); break; } case b_justification::BIN_CLAUSE: - process_antecedent(~js.get_literal(), conseq_coeff); + process_antecedent(~js.get_literal(), offset); TRACE("pb", tout << "binary: " << js.get_literal() << "\n";); break; case b_justification::AXIOM: - if (ctx.get_assign_level(v) > ctx.get_base_level()) { - m_ineq_literals.push_back(conseq); - } TRACE("pb", tout << "axiom " << conseq << "\n";); break; case b_justification::JUSTIFICATION: { justification* j = js.get_justification(); - pb_justification* pbj = 0; + card_justification* pbj = 0; - if (!conseq.sign() && j->get_from_theory() == get_id()) { - pbj = dynamic_cast(j); + if (j->get_from_theory() == get_id()) { + pbj = dynamic_cast(j); } - if (pbj && pbj->get_ineq().is_eq()) { - // only resolve >= that are positive consequences. - pbj = 0; - } - if (pbj && pbj->get_ineq().lit() == conseq) { - // can't resolve against literal representing inequality. - pbj = 0; - } - if (pbj) { - // weaken the lemma and resolve. - TRACE("pb", display(tout << "resolve with inequality", pbj->get_ineq(), true);); - process_ineq(pbj->get_ineq(), conseq, conseq_coeff); + if (pbj == 0) { + TRACE("pb", tout << "skip justification for " << conseq << "\n";); } else { - TRACE("pb", tout << "skipping justification for " << conseq - << " from theory " << j->get_from_theory() << " " - << typeid(*j).name() << "\n";); - m_ineq_literals.push_back(conseq); + process_card(pbj->get_card(), offset); } break; } default: UNREACHABLE(); } - } - TRACE("pb", - for (unsigned i = 0; i < m_ineq_literals.size(); ++i) { - tout << m_ineq_literals[i] << " "; - } - display(tout << "=> ", m_lemma);); + process_next_resolvent: - // 3x + 3y + z + u >= 4 - // ~x /\ ~y => z + u >= - - IF_VERBOSE(14, display(verbose_stream() << "lemma1: ", m_lemma);); - hoist_maximal_values(); - lbool is_true = m_lemma.normalize(false); - m_lemma.prune(false); - - IF_VERBOSE(14, display(verbose_stream() << "lemma2: ", m_lemma);); - //unsigned l_size = m_ineq_literals.size() + ((is_true==l_false)?0:m_lemma.size()); - //if (s_min_l_size >= l_size) { - // verbose_stream() << "(pb.conflict min size: " << l_size << ")\n"; - // s_min_l_size = l_size; - //} - //IF_VERBOSE(1, verbose_stream() << "(pb.conflict " << m_ineq_literals.size() << " " << m_lemma.size() << "\n";); - switch(is_true) { - case l_true: - UNREACHABLE(); - return false; - case l_false: - inc_propagations(c); - m_stats.m_num_conflicts++; - for (unsigned i = 0; i < m_ineq_literals.size(); ++i) { - m_ineq_literals[i].neg(); + // find the next marked variable in the assignment stack + // + while (true) { + conseq = lits[idx]; + v = conseq.var(); + if (ctx.is_marked(v)) break; + SASSERT(idx > 0); + --idx; } - TRACE("pb", tout << m_ineq_literals << "\n";); - ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), justify(m_ineq_literals), CLS_AUX_LEMMA, 0); - break; - default: { - app_ref tmp = m_lemma.to_expr(false, ctx, get_manager()); - internalize_atom(tmp, false); - ctx.mark_as_relevant(tmp.get()); - literal l(ctx.get_bool_var(tmp)); - add_assign(c, m_ineq_literals, l); - break; - } + + SASSERT(ctx.get_assign_level(v) == m_conflict_lvl); + ctx.unset_mark(v); + --idx; + --m_num_marks; } + + TRACE("pb", display_resolved_lemma(tout << "done\n");); + return true; } @@ -2219,30 +2098,6 @@ namespace smt { return js; } - void theory_pb::hoist_maximal_values() { - for (unsigned i = 0; i < m_lemma.size(); ++i) { - if (m_lemma.coeff(i) >= m_lemma.k()) { - m_ineq_literals.push_back(~m_lemma.lit(i)); - std::swap(m_lemma[i], m_lemma[m_lemma.size()-1]); - m_lemma.pop_back(); - --i; - } - } - } - - void theory_pb::remove_from_lemma(unsigned idx) { - // Remove conseq from lemma: - literal lit = m_lemma.lit(idx); - unsigned last = m_lemma.size()-1; - if (idx != last) { - m_lemma[idx] = m_lemma[last]; - m_conseq_index[m_lemma.lit(idx).var()] = idx; - } - m_lemma.pop_back(); - unset_mark(lit.var()); - --m_num_marks; - } - // debug methods void theory_pb::validate_watch(ineq const& c) const { @@ -2333,32 +2188,45 @@ namespace smt { unsigned lvl; out << "num marks: " << m_num_marks << "\n"; out << "conflict level: " << m_conflict_lvl << "\n"; - for (unsigned i = 0; i < lits.size(); ++i) { + for (unsigned i = lits.size(); i > 0;) { + --i; v = lits[i].var(); lvl = ctx.get_assign_level(v); - out << lits[i] - << "@ " << lvl - << " " << (is_marked(v)?"m":"u") - << "\n"; - - if (lvl == m_conflict_lvl && is_marked(v)) { - out << "skipped: " << lits[i] << ":"<< i << "\n"; + out << lvl << ": " << lits[i] << " " << (ctx.is_marked(v)?"m":"u") << " "; + ctx.display(out, ctx.get_justification(v)); + } + + if (!m_antecedents.empty()) { + out << m_antecedents << " ==> "; + } + int bound = m_bound; + uint_set seen; + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + if (seen.contains(v)) { + continue; + } + seen.insert(v); + int coeff = get_coeff(v); + if (coeff == 0) { + // skip + } + else if (coeff == 1) { + out << literal(v) << " "; + } + else if (coeff == -1) { + out << literal(v, true) << " "; + bound -= coeff; + } + else if (coeff > 0) { + out << coeff << " " << literal(v) << " "; + } + else { + out << (-coeff) << " " << literal(v, true) << " "; + bound -= coeff; } } - display(out, m_lemma, true); - - unsigned nc = 0; - for (unsigned i = 0; i < m_lemma.size(); ++i) { - v = m_lemma.lit(i).var(); - lvl = ctx.get_assign_level(v); - if (lvl == m_conflict_lvl) ++nc; - out << m_lemma.lit(i) - << "@" << lvl - << " " << (is_marked(v)?"m":"u") - << " " << ctx.get_assignment(m_lemma.lit(i)) - << "\n"; - } - out << "num conflicts: " << nc << "\n"; + out << " >= " << bound << "\n"; } std::ostream& theory_pb::display(std::ostream& out, arg_t const& c, bool values) const { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index f86615e6c..756997b7a 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -225,7 +225,7 @@ namespace smt { bool validate_assign(theory_pb& th, literal_vector const& lits, literal l); - void set_conflict(theory_pb& th, literal l1, literal l2); + void set_conflict(theory_pb& th, literal l); }; typedef ptr_vector card_watch; @@ -366,22 +366,19 @@ namespace smt { // unsigned m_num_marks; unsigned m_conflict_lvl; - arg_t m_lemma; - literal_vector m_ineq_literals; - svector m_marked; + svector m_coeffs; + svector m_active_coeffs; + int m_bound; + literal_vector m_antecedents; - // bool_var |-> index into m_lemma - unsigned_vector m_conseq_index; - static const unsigned null_index; - bool is_marked(bool_var v) const; - void set_mark(bool_var v, unsigned idx); - void unset_mark(bool_var v); - void unset_marks(); + void inc_coeff(literal l, int offset); + int get_coeff(bool_var v) const; - bool resolve_conflict(ineq& c); - void process_antecedent(literal l, numeral coeff); - void process_ineq(ineq& c, literal conseq, numeral coeff); - void remove_from_lemma(unsigned idx); + void reset_coeffs(); + + bool resolve_conflict(card& c, literal_vector const& conflict_clause); + void process_antecedent(literal l, int offset); + void process_card(card& c, int offset); bool is_proof_justification(justification const& j) const; void hoist_maximal_values(); From 975474f56082c33145195888fbf5c8df61eb38d7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Jan 2017 17:05:51 -0800 Subject: [PATCH 0004/1283] fixing bounds calculation Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 189 +++++++++++++++++++++++++++++++++--------- src/smt/theory_pb.h | 4 + 2 files changed, 156 insertions(+), 37 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index ecdcc0618..b215433d9 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -28,6 +28,7 @@ Notes: #include "pb_rewriter_def.h" #include "sparse_matrix_def.h" #include "simplex_def.h" +#include "mpz.h" namespace smt { @@ -244,7 +245,15 @@ namespace smt { SASSERT(m_bound > 0); SASSERT(ctx.get_assignment(lit) == l_false); unsigned index = m_bound + 1; - for (unsigned i = 0; i <= m_bound; ++i) { + // + // We give preference to a watched literal in position 1..m_bound. + // Notice, that if a literal occurs multiple + // times in m_args, within [0..m_bound] then it is inserted into the watch + // list for this cardinality constraint. For each occurrence, a callback + // to assign is made. + // + for (unsigned i = m_bound + 1; i > 0; ) { + --i; if (m_args[i] == lit) { index = i; break; @@ -261,9 +270,6 @@ namespace smt { if (ctx.get_assignment(lit2) != l_false) { TRACE("pb", tout << "swap " << lit2 << "\n";); std::swap(m_args[index], m_args[i]); - if (ctx.get_assignment(m_args[0]) == l_false) { - std::swap(m_args[0], m_args[index]); - } th.watch_literal(lit2, this); return l_undef; } @@ -1016,9 +1022,8 @@ namespace smt { } lits.push_back(lit); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - lit.neg(); for (unsigned i = 0; i < c->size(); ++i) { - literal lits2[2] = { lit, c->lit(i) }; + literal lits2[2] = { ~lit, c->lit(i) }; ctx.mk_th_axiom(get_id(), 2, lits2); } dealloc(c); @@ -1104,7 +1109,7 @@ namespace smt { m_stats.m_num_conflicts++; context& ctx = get_context(); justification* js = 0; - if (proofs_enabled()) { + if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); } resolve_conflict(c, lits); @@ -1117,7 +1122,6 @@ namespace smt { m_stats.m_num_propagations++; context& ctx = get_context(); TRACE("pb", tout << "#prop: " << c.num_propagations() << " - " << lits << " " << c.lit() << " => " << l << "\n";); - ctx.assign(l, ctx.mk_justification( card_justification( c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); @@ -1910,9 +1914,7 @@ namespace smt { ctx.set_mark(v); ++m_num_marks; } - if (lvl > ctx.get_base_level()) { - inc_coeff(l, offset); - } + inc_coeff(l, offset); } void theory_pb::process_card(card& c, int offset) { @@ -1930,25 +1932,113 @@ namespace smt { SASSERT(ctx.get_assignment(c.lit()) == l_true); } - void theory_pb::inc_coeff(literal l, int offset) { - if (l.sign()) { - m_bound -= offset; + void theory_pb::validate_lemma() { + uint_set seen; + int value = -m_bound; + context& ctx = get_context(); + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + if (seen.contains(v)) { + continue; + } + seen.insert(v); + int coeff = get_coeff(v); + if (coeff == 0) continue; + if (coeff < 0 && ctx.get_assignment(v) != l_true) { + value -= coeff; + } + else if (coeff > 0 && ctx.get_assignment(v) != l_false) { + value += coeff; + } } + std::cout << "bound: " << m_bound << " value " << value << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; + } + + void theory_pb::inc_coeff(literal l, int offset) { + SASSERT(offset > 0); bool_var v = l.var(); SASSERT(v != null_bool_var); if (static_cast(m_coeffs.size()) <= v) { m_coeffs.resize(v + 1, 0); } - if (m_coeffs[v] == 0) { + int coeff0 = m_coeffs[v]; + if (coeff0 == 0) { m_active_coeffs.push_back(v); } + int inc = l.sign() ? -offset : offset; - m_coeffs[v] += inc; + int coeff1 = inc + coeff0; + m_coeffs[v] = coeff1; + + if (coeff0 > 0 && 0 > coeff1) { + m_bound += coeff1; + } + else if (coeff0 < 0 && 0 < coeff1) { + m_bound += coeff0; + } } + + /** + \brief attempt a cut and simplification of constraints. + */ + void theory_pb::cut() { + unsigned g = 0; + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + int coeff = m_coeffs[v]; + if (coeff == 0) { + m_active_coeffs[i] = m_active_coeffs.back(); + m_active_coeffs.pop_back(); + continue; + } + if (coeff < 0) { + coeff = -coeff; + } + if (m_bound < coeff) { + m_coeffs[v] = m_bound; + } + if (g == 0) { + g = static_cast(coeff); + } + else if (g != 1) { + g = u_gcd(g, static_cast(coeff)); + } + } + if (g != 1 && g != 0) { + uint_set seen; + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + if (!seen.contains(v)) { + seen.insert(v); + m_coeffs[v] /= g; + } + } + m_bound /= g; + TRACE("pb", display_resolved_lemma(tout << "cut\n");); + } + } + +#if 0 + void theory_pb::reduce2(int s1, int alpha, bool_var v, card& asserting) { + // m_coeffs one for each boolean variable. + int beta = coeff_of(v); + if (beta == 1) { + process_card(asserting, alpha); + return; + } + int s2 = slack(asserting); + while (beta * s1 + s2 * alpha >= 0) { + bool_var x = pick_var(asserting); + reduce(); + reduce_degree(); + s2 = s2 + delta_slack; + } + } +#endif bool theory_pb::resolve_conflict(card& c, literal_vector const& confl) { - TRACE("pb", display(tout, c, true); get_context().display(tout);); + TRACE("pb", display(tout, c, true); ); bool_var v; context& ctx = get_context(); @@ -1966,9 +2056,11 @@ namespace smt { m_num_marks = 0; m_bound = c.k(); m_antecedents.reset(); + m_resolved.reset(); literal_vector ante; process_card(c, 1); + // point into stack of assigned literals literal_vector const& lits = ctx.assigned_literals(); @@ -1977,12 +2069,12 @@ namespace smt { b_justification js; literal conseq = ~confl[2]; + while (m_num_marks > 0) { v = conseq.var(); TRACE("pb", display_resolved_lemma(tout << conseq << "\n");); - int offset = get_coeff(v); if (offset == 0) { @@ -1991,19 +2083,20 @@ namespace smt { else if (offset < 0) { offset = -offset; } + SASSERT(offset > 0); js = ctx.get_justification(v); - - TRACE("pb", tout << "conseq: " << conseq << "\n";); + validate_lemma(); + // ctx.display(std::cout, js); inc_coeff(conseq, offset); - m_bound += offset; - // // Resolve selected conseq with antecedents. // + int bound = 1; + switch(js.get_kind()) { case b_justification::CLAUSE: { @@ -2016,7 +2109,7 @@ namespace smt { } unsigned num_lits = cls.get_num_literals(); if (cls.get_literal(0) == conseq) { - process_antecedent(cls.get_literal(1), offset); + process_antecedent(cls.get_literal(1), offset); } else { SASSERT(cls.get_literal(1) == conseq); @@ -2047,12 +2140,14 @@ namespace smt { } else { process_card(pbj->get_card(), offset); + bound = pbj->get_card().k(); } break; } default: UNREACHABLE(); } + m_bound += offset * bound; process_next_resolvent: @@ -2068,11 +2163,30 @@ namespace smt { SASSERT(ctx.get_assign_level(v) == m_conflict_lvl); ctx.unset_mark(v); + m_resolved.push_back(idx); --idx; --m_num_marks; } + validate_lemma(); TRACE("pb", display_resolved_lemma(tout << "done\n");); + + + uint_set seen; + int count = 0, sz = 0; + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + if (seen.contains(v)) { + continue; + } + seen.insert(v); + int coeff = get_coeff(v); + if (coeff == 0) continue; + if (coeff < 0) coeff = -coeff; + ++sz; + count += coeff; + } + std::cout << "New " << count << "(" << sz << ") >= " << m_bound << " " << c.size() << " >= " << c.k() << " new diff: " << count - m_bound << " old diff: " << c.size() - c.k() << "\n"; return true; } @@ -2188,19 +2302,18 @@ namespace smt { unsigned lvl; out << "num marks: " << m_num_marks << "\n"; out << "conflict level: " << m_conflict_lvl << "\n"; - for (unsigned i = lits.size(); i > 0;) { - --i; - v = lits[i].var(); + for (unsigned i = 0; i < m_resolved.size(); ++i) { + v = lits[m_resolved[i]].var(); lvl = ctx.get_assign_level(v); - out << lvl << ": " << lits[i] << " " << (ctx.is_marked(v)?"m":"u") << " "; + out << lvl << ": " << lits[i] << " "; ctx.display(out, ctx.get_justification(v)); } if (!m_antecedents.empty()) { out << m_antecedents << " ==> "; } - int bound = m_bound; uint_set seen; + bool first = true; for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; if (seen.contains(v)) { @@ -2209,24 +2322,26 @@ namespace smt { seen.insert(v); int coeff = get_coeff(v); if (coeff == 0) { - // skip + continue; } - else if (coeff == 1) { - out << literal(v) << " "; + if (!first) { + out << " + "; + } + if (coeff == 1) { + out << literal(v); } else if (coeff == -1) { - out << literal(v, true) << " "; - bound -= coeff; + out << literal(v, true); } else if (coeff > 0) { - out << coeff << " " << literal(v) << " "; + out << coeff << " * " << literal(v); } else { - out << (-coeff) << " " << literal(v, true) << " "; - bound -= coeff; + out << (-coeff) << " * " << literal(v, true); } + first = false; } - out << " >= " << bound << "\n"; + out << " >= " << m_bound << "\n"; } std::ostream& theory_pb::display(std::ostream& out, arg_t const& c, bool values) const { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 756997b7a..ad143b24a 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -365,6 +365,7 @@ namespace smt { // Conflict resolution, cutting plane derivation. // unsigned m_num_marks; + unsigned_vector m_resolved; unsigned m_conflict_lvl; svector m_coeffs; svector m_active_coeffs; @@ -379,8 +380,11 @@ namespace smt { bool resolve_conflict(card& c, literal_vector const& conflict_clause); void process_antecedent(literal l, int offset); void process_card(card& c, int offset); + void cut(); bool is_proof_justification(justification const& j) const; + void validate_lemma(); + void hoist_maximal_values(); void validate_final_check(); From e1640fcee92dd4a140b2fa9c5fe8f2224b183298 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Jan 2017 16:08:33 -0800 Subject: [PATCH 0005/1283] cardinality reduction Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 119 ++++++++++++++++++++++++++++++++++-------- src/smt/theory_pb.h | 7 ++- 2 files changed, 103 insertions(+), 23 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index b215433d9..8988032ba 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1895,6 +1895,11 @@ namespace smt { return m_coeffs.get(v, 0); } + int theory_pb::get_abs_coeff(bool_var v) const { + int coeff = get_coeff(v); + if (coeff < 0) coeff = -coeff; + return coeff; + } void theory_pb::reset_coeffs() { for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { @@ -1932,7 +1937,7 @@ namespace smt { SASSERT(ctx.get_assignment(c.lit()) == l_true); } - void theory_pb::validate_lemma() { + bool theory_pb::validate_lemma() { uint_set seen; int value = -m_bound; context& ctx = get_context(); @@ -1951,7 +1956,87 @@ namespace smt { value += coeff; } } - std::cout << "bound: " << m_bound << " value " << value << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; + std::cout << "bound: " << m_bound << " value " << value << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; + return value < 0; + } + + int theory_pb::arg_max(uint_set& seen, int& max_coeff) { + max_coeff = 0; + int arg_max = -1; + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + if (seen.contains(v)) { + continue; + } + int coeff = get_abs_coeff(v); + if (coeff > 0 && (max_coeff == 0 || max_coeff < coeff)) { + arg_max = v; + max_coeff = coeff; + } + } + return arg_max; + } + + literal theory_pb::cardinality_reduction() { + uint_set seen; + int s = 0; + int new_bound = 0; + int coeff; + while (s < m_bound) { + int arg = arg_max(seen, coeff); + if (arg == -1) break; + s += coeff; + ++new_bound; + seen.insert(arg); + } + int slack = m_bound; + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + coeff = get_abs_coeff(m_active_coeffs[i]); + slack = std::min(slack, coeff - 1); + } + + while (slack > 0) { + bool found = false; + int v = 0; + for (unsigned i = 0; !found && i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + coeff = get_abs_coeff(v); + if (0 < coeff && coeff < slack) { + found = true; + } + } + if (!found) { + break; + } + slack -= coeff; + m_coeffs[v] = 0; // deactivate coefficient. + } + // create cardinality constraint + literal card_lit = null_literal; + card* c = alloc(card, card_lit, new_bound); + seen.reset(); + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + if (seen.contains(v)) continue; + seen.insert(v); + coeff = get_coeff(v); + if (coeff < 0) { + c->add_arg(literal(v, true)); + m_coeffs[v] = -1; + } + else if (coeff > 0) { + c->add_arg(literal(v, false)); + m_coeffs[v] = 1; + } + } + + // display(std::cout, *c, true); + dealloc(c); + + m_bound = new_bound; + validate_lemma(); + + return card_lit; } void theory_pb::inc_coeff(literal l, int offset) { @@ -2017,24 +2102,6 @@ namespace smt { TRACE("pb", display_resolved_lemma(tout << "cut\n");); } } - -#if 0 - void theory_pb::reduce2(int s1, int alpha, bool_var v, card& asserting) { - // m_coeffs one for each boolean variable. - int beta = coeff_of(v); - if (beta == 1) { - process_card(asserting, alpha); - return; - } - int s2 = slack(asserting); - while (beta * s1 + s2 * alpha >= 0) { - bool_var x = pick_var(asserting); - reduce(); - reduce_degree(); - s2 = s2 + delta_slack; - } - } -#endif bool theory_pb::resolve_conflict(card& c, literal_vector const& confl) { @@ -2180,13 +2247,21 @@ namespace smt { continue; } seen.insert(v); - int coeff = get_coeff(v); + int coeff = get_abs_coeff(v); if (coeff == 0) continue; - if (coeff < 0) coeff = -coeff; ++sz; count += coeff; } std::cout << "New " << count << "(" << sz << ") >= " << m_bound << " " << c.size() << " >= " << c.k() << " new diff: " << count - m_bound << " old diff: " << c.size() - c.k() << "\n"; + literal card_lit = cardinality_reduction(); + + if (card_lit != null_literal) { + for (unsigned i = 0; i < m_antecedents.size(); ++i) { + m_antecedents[i].neg(); + } + m_antecedents.push_back(card_lit); + ctx.mk_clause(m_antecedents.size(), m_antecedents.c_ptr(), 0, CLS_AUX_LEMMA, 0); // TBD add delete handler to GC card closure. + } return true; } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index ad143b24a..93f3a8eeb 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -373,9 +373,14 @@ namespace smt { literal_vector m_antecedents; void inc_coeff(literal l, int offset); + int get_coeff(bool_var v) const; + int get_abs_coeff(bool_var v) const; + + int arg_max(uint_set& seen, int& coeff); void reset_coeffs(); + literal cardinality_reduction(); bool resolve_conflict(card& c, literal_vector const& conflict_clause); void process_antecedent(literal l, int offset); @@ -383,7 +388,7 @@ namespace smt { void cut(); bool is_proof_justification(justification const& j) const; - void validate_lemma(); + bool validate_lemma(); void hoist_maximal_values(); From 238e85867a40f4e8922a25504ba1a7ab7f0ff0fd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Jan 2017 15:40:39 -0800 Subject: [PATCH 0006/1283] working on card Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 257 +++++++++++++++++++++++++++++------------- src/smt/theory_pb.h | 11 +- 2 files changed, 185 insertions(+), 83 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 8988032ba..b8d4ea230 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -996,15 +996,15 @@ namespace smt { bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); unsigned bound = m_util.get_k(atom).get_unsigned(); + literal lit(abv); - card* c = alloc(card, literal(abv), bound); + card* c = alloc(card, lit, bound); for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); c->add_arg(compile_arg(arg)); } - literal lit(abv); if (c->k() == 0) { ctx.mk_th_axiom(get_id(), 1, &lit); @@ -1016,16 +1016,7 @@ namespace smt { dealloc(c); } else if (c->k() == c->size()) { - literal_vector lits; - for (unsigned i = 0; i < c->size(); ++i) { - lits.push_back(~c->lit(i)); - } - lits.push_back(lit); - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - for (unsigned i = 0; i < c->size(); ++i) { - literal lits2[2] = { ~lit, c->lit(i) }; - ctx.mk_th_axiom(get_id(), 2, lits2); - } + card2conjunction(*c); dealloc(c); } else { @@ -1040,6 +1031,23 @@ namespace smt { return true; } + // \brief define cardinality constraint as conjunction. + // + void theory_pb::card2conjunction(card const& c) { + context& ctx = get_context(); + literal lit = c.lit(); + literal_vector lits; + for (unsigned i = 0; i < c.size(); ++i) { + lits.push_back(~c.lit(i)); + } + lits.push_back(lit); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + for (unsigned i = 0; i < c.size(); ++i) { + literal lits2[2] = { ~lit, c.lit(i) }; + ctx.mk_th_axiom(get_id(), 2, lits2); + } + } + void theory_pb::watch_literal(literal lit, card* c) { init_watch(lit.var()); ptr_vector* cards = m_var_infos[lit.var()].m_lit_cwatch[lit.sign()]; @@ -1112,9 +1120,12 @@ namespace smt { if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); } - resolve_conflict(c, lits); c.inc_propagations(*this); - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + if (!resolve_conflict(c, lits)) { + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + } + std::cout << "inconsistent: " << ctx.inconsistent() << "\n"; + SASSERT(ctx.inconsistent()); } void theory_pb::add_assign(card& c, literal_vector const& lits, literal l) { @@ -1938,25 +1949,24 @@ namespace smt { } bool theory_pb::validate_lemma() { - uint_set seen; int value = -m_bound; context& ctx = get_context(); + normalize_active_coeffs(); for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; - if (seen.contains(v)) { - continue; - } - seen.insert(v); int coeff = get_coeff(v); - if (coeff == 0) continue; + SASSERT(coeff != 0); if (coeff < 0 && ctx.get_assignment(v) != l_true) { value -= coeff; } else if (coeff > 0 && ctx.get_assignment(v) != l_false) { value += coeff; } + else if (coeff == 0) { + std::cout << "unexpected 0 coefficient\n"; + } } - std::cout << "bound: " << m_bound << " value " << value << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; + std::cout << "bound: " << m_bound << " value " << value << " coeffs: " << m_active_coeffs.size() << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; return value < 0; } @@ -1977,18 +1987,21 @@ namespace smt { return arg_max; } - literal theory_pb::cardinality_reduction() { - uint_set seen; + literal theory_pb::cardinality_reduction(card*& c) { + normalize_active_coeffs(); + SASSERT(m_seen.empty()); + c = 0; int s = 0; int new_bound = 0; int coeff; while (s < m_bound) { - int arg = arg_max(seen, coeff); + int arg = arg_max(m_seen, coeff); if (arg == -1) break; s += coeff; ++new_bound; - seen.insert(arg); + m_seen.insert(arg); } + m_seen.reset(); // use a trail int slack = m_bound; for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { coeff = get_abs_coeff(m_active_coeffs[i]); @@ -2013,32 +2026,92 @@ namespace smt { } // create cardinality constraint literal card_lit = null_literal; - card* c = alloc(card, card_lit, new_bound); - seen.reset(); for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; - if (seen.contains(v)) continue; - seen.insert(v); coeff = get_coeff(v); if (coeff < 0) { - c->add_arg(literal(v, true)); m_coeffs[v] = -1; } else if (coeff > 0) { - c->add_arg(literal(v, false)); m_coeffs[v] = 1; } - } - - // display(std::cout, *c, true); - dealloc(c); + } m_bound = new_bound; - validate_lemma(); + if (validate_lemma()) { + ast_manager& m = get_manager(); + context& ctx = get_context(); + pb_util pb(m); + expr_ref atom(pb.mk_fresh_bool(), m); + bool_var abv = ctx.mk_bool_var(atom); + ctx.set_var_theory(abv, get_id()); + card_lit = literal(abv); + c = alloc(card, card_lit, new_bound); + normalize_active_coeffs(); + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + if (coeff < 0) { + c->add_arg(literal(v, true)); + } + else if (coeff > 0) { + c->add_arg(literal(v, false)); + } + } + m_stats.m_num_predicates++; + // display(std::cout, *c, true); + if (c->k() == 0) { + UNREACHABLE(); + } + else if (c->size() < c->k()) { + card_lit = false_literal; + dealloc(c); + c = 0; + } + else if (c->size() == c->k()) { + card_lit = null_literal; + unsigned lvl = UINT_MAX; + for (unsigned i = 0; i < c->size(); ++i) { + literal lit = c->lit(i); + if (ctx.get_assignment(lit) == l_false && ctx.get_assign_level(lit) < lvl) { + lvl = ctx.get_assign_level(lit); + card_lit = lit; + } + } + std::cout << "cardinality: " << card_lit << " " << atom << "\n"; + dealloc(c); + c = 0; + } + else { + init_watch(abv); + m_var_infos[abv].m_card = c; + m_card_trail.push_back(abv); + } + } return card_lit; } + void theory_pb::normalize_active_coeffs() { + SASSERT(m_seen.empty()); + unsigned i = 0, j = 0, sz = m_active_coeffs.size(); + for (; i < sz; ++i) { + bool_var v = m_active_coeffs[i]; + if (!m_seen.contains(v) && get_coeff(v) != 0) { + m_seen.insert(v); + if (j != i) { + m_active_coeffs[j] = m_active_coeffs[i]; + } + ++j; + } + } + sz = j; + m_active_coeffs.shrink(sz); + for (i = 0; i < sz; ++i) { + m_seen.remove(m_active_coeffs[i]); + } + SASSERT(m_seen.empty()); + } + void theory_pb::inc_coeff(literal l, int offset) { SASSERT(offset > 0); bool_var v = l.var(); @@ -2055,11 +2128,11 @@ namespace smt { int coeff1 = inc + coeff0; m_coeffs[v] = coeff1; - if (coeff0 > 0 && 0 > coeff1) { - m_bound += coeff1; + if (coeff0 > 0 && inc < 0) { + m_bound -= coeff0 - std::max(0, coeff1); } - else if (coeff0 < 0 && 0 < coeff1) { - m_bound += coeff0; + else if (coeff0 < 0 && inc > 0) { + m_bound -= std::min(0, coeff1) + coeff0; } } @@ -2068,37 +2141,36 @@ namespace smt { */ void theory_pb::cut() { unsigned g = 0; - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + for (unsigned i = 0; g != 1 && i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; - int coeff = m_coeffs[v]; + int coeff = get_abs_coeff(v); if (coeff == 0) { - m_active_coeffs[i] = m_active_coeffs.back(); - m_active_coeffs.pop_back(); continue; } - if (coeff < 0) { - coeff = -coeff; - } - if (m_bound < coeff) { - m_coeffs[v] = m_bound; + if (m_bound < coeff) { + if (get_coeff(v) > 0) { + m_coeffs[v] = m_bound; + } + else { + m_coeffs[v] = -m_bound; + } + coeff = m_bound; } + SASSERT(0 < coeff && coeff <= m_bound); if (g == 0) { g = static_cast(coeff); } - else if (g != 1) { + else { g = u_gcd(g, static_cast(coeff)); } } - if (g != 1 && g != 0) { - uint_set seen; + if (g >= 2) { + normalize_active_coeffs(); for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; - if (!seen.contains(v)) { - seen.insert(v); - m_coeffs[v] /= g; - } + m_coeffs[m_active_coeffs[i]] /= g; } m_bound /= g; + std::cout << "CUT " << g << "\n"; TRACE("pb", display_resolved_lemma(tout << "cut\n");); } } @@ -2119,6 +2191,8 @@ namespace smt { return false; } + std::cout << c.lit() << "\n"; + reset_coeffs(); m_num_marks = 0; m_bound = c.k(); @@ -2142,22 +2216,30 @@ namespace smt { v = conseq.var(); TRACE("pb", display_resolved_lemma(tout << conseq << "\n");); - int offset = get_coeff(v); + int offset = get_abs_coeff(v); if (offset == 0) { goto process_next_resolvent; } - else if (offset < 0) { - offset = -offset; + SASSERT(validate_lemma()); + if (offset > 1000) { + while (m_num_marks > 0 && idx > 0) { + v = lits[idx].var(); + if (ctx.is_marked(v)) { + ctx.unset_mark(v); + } + --idx; + } + return false; } + SASSERT(offset > 0); js = ctx.get_justification(v); - validate_lemma(); // ctx.display(std::cout, js); - inc_coeff(conseq, offset); + // // Resolve selected conseq with antecedents. // @@ -2167,6 +2249,7 @@ namespace smt { switch(js.get_kind()) { case b_justification::CLAUSE: { + inc_coeff(conseq, offset); clause& cls = *js.get_clause(); justification* cjs = cls.get_justification(); if (cjs && !is_proof_justification(*cjs)) { @@ -2189,6 +2272,7 @@ namespace smt { break; } case b_justification::BIN_CLAUSE: + inc_coeff(conseq, offset); process_antecedent(~js.get_literal(), offset); TRACE("pb", tout << "binary: " << js.get_literal() << "\n";); break; @@ -2204,11 +2288,17 @@ namespace smt { } if (pbj == 0) { TRACE("pb", tout << "skip justification for " << conseq << "\n";); + inc_coeff(conseq, offset); } else { - process_card(pbj->get_card(), offset); - bound = pbj->get_card().k(); + card& c2 = pbj->get_card(); + process_card(c2, offset); + unsigned i = 0; + for (i = 0; i < c2.size() && c2.lit(i) != conseq; ++i) {} + std::cout << c2.lit() << " index at " << i << " of " << c2.size(); + bound = c2.k(); } + std::cout << " offset: " << offset << " bound: " << bound << "\n"; break; } default: @@ -2234,36 +2324,45 @@ namespace smt { --idx; --m_num_marks; } - validate_lemma(); + SASSERT(validate_lemma()); TRACE("pb", display_resolved_lemma(tout << "done\n");); - - uint_set seen; + + normalize_active_coeffs(); int count = 0, sz = 0; for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; - if (seen.contains(v)) { - continue; - } - seen.insert(v); int coeff = get_abs_coeff(v); - if (coeff == 0) continue; + SASSERT(coeff > 0); ++sz; count += coeff; } std::cout << "New " << count << "(" << sz << ") >= " << m_bound << " " << c.size() << " >= " << c.k() << " new diff: " << count - m_bound << " old diff: " << c.size() - c.k() << "\n"; - literal card_lit = cardinality_reduction(); + card* cr = 0; + literal card_lit = cardinality_reduction(cr); if (card_lit != null_literal) { - for (unsigned i = 0; i < m_antecedents.size(); ++i) { - m_antecedents[i].neg(); - } - m_antecedents.push_back(card_lit); - ctx.mk_clause(m_antecedents.size(), m_antecedents.c_ptr(), 0, CLS_AUX_LEMMA, 0); // TBD add delete handler to GC card closure. + ctx.assign(card_lit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), card_lit, 0, 0))); } - return true; + if (cr != 0) { + m_antecedents.reset(); + m_antecedents.push_back(card_lit); + unsigned slack = cr ? (cr->size() - cr->k()) : 0; + for (unsigned i = 0; 0 < slack && i < cr->size(); ++i) { + literal lit = cr->lit(i); + SASSERT(lit.var() != conseq.var() || lit == ~conseq); + if (lit.var() != conseq.var() && ctx.get_assignment(lit) == l_false) { + m_antecedents.push_back(~lit); + --slack; + } + } + ctx.assign(~conseq, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), ~conseq, 0, 0))); + std::cout << conseq << " " << ctx.get_assignment(conseq) << "\n"; + } + + return card_lit != null_literal; } bool theory_pb::is_proof_justification(justification const& j) const { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 93f3a8eeb..db58e7a07 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -324,6 +324,7 @@ namespace smt { unsigned_vector m_card_lim; bool is_cardinality_constraint(app * atom); bool internalize_card(app * atom, bool gate_ctx); + void card2conjunction(card const& c); void watch_literal(literal lit, card* c); void unwatch_literal(literal w, card* c); @@ -367,20 +368,22 @@ namespace smt { unsigned m_num_marks; unsigned_vector m_resolved; unsigned m_conflict_lvl; + + // Conflict PB constraints svector m_coeffs; svector m_active_coeffs; int m_bound; literal_vector m_antecedents; + uint_set m_seen; + void normalize_active_coeffs(); void inc_coeff(literal l, int offset); - int get_coeff(bool_var v) const; - int get_abs_coeff(bool_var v) const; - + int get_abs_coeff(bool_var v) const; int arg_max(uint_set& seen, int& coeff); void reset_coeffs(); - literal cardinality_reduction(); + literal cardinality_reduction(card*& c); bool resolve_conflict(card& c, literal_vector const& conflict_clause); void process_antecedent(literal l, int offset); From e17c130422354c839191c6aa7c04d19a8543fc6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 19 Jan 2017 17:55:15 -0800 Subject: [PATCH 0007/1283] updated cardinality Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 31 ++++ src/smt/theory_pb.cpp | 331 +++++----------------------------------- src/smt/theory_pb.h | 6 +- 3 files changed, 70 insertions(+), 298 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 22b2f60e6..3a62f4507 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -691,6 +691,30 @@ class FuncDeclRef(AstRef): """ return Z3_get_decl_kind(self.ctx_ref(), self.ast) + def params(self): + ctx = self.ctx + n = Z3_get_decl_num_parameters(self.ctx_ref(), self.ast) + result = [ None for i in range(n) ] + for i in range(n): + k = Z3_get_decl_parameter_kind(self.ctx_ref(), self.ast, i) + if k == Z3_PARAMETER_INT: + result[i] = Z3_get_decl_int_parameter(self.ctx_ref(), self.ast, i) + elif k == Z3_PARAMETER_DOUBLE: + result[i] = Z3_get_decl_double_parameter(self.ctx_ref(), self.ast, i) + elif k == Z3_PARAMETER_RATIONAL: + result[i] = Z3_get_decl_rational_parameter(self.ctx_ref(), self.ast, i) + elif k == Z3_PARAMETER_SYMBOL: + result[i] = Z3_get_decl_symbol_parameter(self.ctx_ref(), self.ast, i) + elif k == Z3_PARAMETER_SORT: + result[i] = SortRef(Z3_get_decl_sort_parameter(self.ctx_ref(), self.ast, i), ctx) + elif k == Z3_PARAMETER_AST: + result[i] = ExprRef(Z3_get_decl_ast_parameter(self.ctx_ref(), self.ast, i), ctx) + elif k == Z3_PARAMETER_FUNC_DECL: + result[i] = FuncDeclRef(Z3_get_decl_func_decl_parameter(self.ctx_ref(), self.ast, i), ctx) + else: + assert(False) + return result + def __call__(self, *args): """Create a Z3 application expression using the function `self`, and the given arguments. @@ -2637,6 +2661,13 @@ class RatNumRef(ArithRef): """ return self.denominator().as_long() + def is_int(self): + return self.denominator().is_int() and self.denominator_as_long() == 1 + + def as_long(self): + _z3_assert(self.is_int(), "Expected integer fraction") + return self.numerator_as_long() + def as_decimal(self, prec): """ Return a Z3 rational value as a string in decimal notation using at most `prec` decimal places. diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index b8d4ea230..f7c36b5c4 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -438,9 +438,6 @@ namespace smt { } } - - - // ------------------------ // theory_pb @@ -454,7 +451,6 @@ namespace smt { m_learn_complements = p.m_pb_learn_complements; m_conflict_frequency = p.m_pb_conflict_frequency; m_enable_compilation = p.m_pb_enable_compilation; - m_enable_simplex = p.m_pb_enable_simplex; } theory_pb::~theory_pb() { @@ -466,169 +462,6 @@ namespace smt { return alloc(theory_pb, new_ctx->get_manager(), m_params); } - class theory_pb::remove_var : public trail { - theory_pb& pb; - unsigned v; - public: - remove_var(theory_pb& pb, unsigned v): pb(pb), v(v) {} - virtual void undo(context& ctx) { - pb.m_vars.remove(v); - pb.m_simplex.unset_lower(v); - pb.m_simplex.unset_upper(v); - } - }; - - class theory_pb::undo_bound : public trail { - theory_pb& pb; - unsigned m_v; - bool m_is_lower; - scoped_eps_numeral m_last_bound; - bool m_last_bound_valid; - literal m_last_explain; - - public: - undo_bound(theory_pb& pb, unsigned v, - bool is_lower, - scoped_eps_numeral& last_bound, - bool last_bound_valid, - literal last_explain): - pb(pb), - m_v(v), - m_is_lower(is_lower), - m_last_bound(last_bound), - m_last_bound_valid(last_bound_valid), - m_last_explain(last_explain) {} - - virtual void undo(context& ctx) { - if (m_is_lower) { - if (m_last_bound_valid) { - pb.m_simplex.set_lower(m_v, m_last_bound); - } - else { - pb.m_simplex.unset_lower(m_v); - } - pb.set_explain(pb.m_explain_lower, m_v, m_last_explain); - } - else { - if (m_last_bound_valid) { - pb.m_simplex.set_upper(m_v, m_last_bound); - } - else { - pb.m_simplex.unset_upper(m_v); - } - pb.set_explain(pb.m_explain_upper, m_v, m_last_explain); - } - m_last_bound.reset(); - } - }; - - literal theory_pb::set_explain(literal_vector& explains, unsigned var, literal expl) { - if (var >= explains.size()) { - explains.resize(var+1, null_literal); - } - literal last_explain = explains[var]; - explains[var] = expl; - return last_explain; - } - - bool theory_pb::update_bound(bool_var v, literal explain, bool is_lower, mpq_inf const& bound) { - if (is_lower) { - if (m_simplex.above_lower(v, bound)) { - scoped_eps_numeral last_bound(m_mpq_inf_mgr); - if (m_simplex.upper_valid(v)) { - m_simplex.get_upper(v, last_bound); - if (m_mpq_inf_mgr.gt(bound, last_bound)) { - literal lit = m_explain_upper.get(v, null_literal); - TRACE("pb", tout << ~lit << " " << ~explain << "\n";); - get_context().mk_clause(~lit, ~explain, justify(~lit, ~explain)); - return false; - } - } - bool last_bound_valid = m_simplex.lower_valid(v); - if (last_bound_valid) { - m_simplex.get_lower(v, last_bound); - } - m_simplex.set_lower(v, bound); - literal last_explain = set_explain(m_explain_lower, v, explain); - get_context().push_trail(undo_bound(*this, v, true, last_bound, last_bound_valid, last_explain)); - } - } - else { - if (m_simplex.below_upper(v, bound)) { - scoped_eps_numeral last_bound(m_mpq_inf_mgr); - if (m_simplex.lower_valid(v)) { - m_simplex.get_lower(v, last_bound); - if (m_mpq_inf_mgr.gt(last_bound, bound)) { - literal lit = m_explain_lower.get(v, null_literal); - TRACE("pb", tout << ~lit << " " << ~explain << "\n";); - get_context().mk_clause(~lit, ~explain, justify(~lit, ~explain)); - return false; - } - } - bool last_bound_valid = m_simplex.upper_valid(v); - if (last_bound_valid) { - m_simplex.get_upper(v, last_bound); - } - m_simplex.set_upper(v, bound); - literal last_explain = set_explain(m_explain_upper, v, explain); - get_context().push_trail(undo_bound(*this, v, false, last_bound, last_bound_valid, last_explain)); - } - } - return true; - }; - - bool theory_pb::check_feasible() { - context& ctx = get_context(); - lbool is_sat = m_simplex.make_feasible(); - if (l_false != is_sat) { - return true; - } - - row r = m_simplex.get_infeasible_row(); - mpz const& coeff = m_simplex.get_base_coeff(r); - bool_var base_var = m_simplex.get_base_var(r); - SASSERT(m_simplex.below_lower(base_var) || m_simplex.above_upper(base_var)); - bool cant_increase = m_simplex.below_lower(base_var)?m_mpz_mgr.is_pos(coeff):m_mpz_mgr.is_neg(coeff); - - literal_vector explains; - row_iterator it = m_simplex.row_begin(r), end = m_simplex.row_end(r); - for (; it != end; ++it) { - bool_var v = it->m_var; - if (v == base_var) { - if (m_simplex.below_lower(base_var)) { - explains.push_back(m_explain_lower.get(v, null_literal)); - } - else { - explains.push_back(m_explain_upper.get(v, null_literal)); - } - } - else if (cant_increase == m_mpz_mgr.is_pos(it->m_coeff)) { - explains.push_back(m_explain_lower.get(v, null_literal)); - } - else { - explains.push_back(m_explain_upper.get(v, null_literal)); - } - } - - literal_vector lits; - for (unsigned i = 0; i < explains.size(); ++i) { - literal lit(explains[i]); - if (lit != null_literal) { - lits.push_back(~lit); - } - } - - m_stats.m_num_conflicts++; - justification* js = 0; - if (proofs_enabled()) { - js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); - } - TRACE("pb", tout << lits << "\n";); - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); - - return false; - } - bool theory_pb::internalize_atom(app * atom, bool gate_ctx) { context& ctx = get_context(); TRACE("pb", tout << mk_pp(atom, get_manager()) << "\n";); @@ -639,6 +472,7 @@ namespace smt { m_stats.m_num_predicates++; if (m_util.is_aux_bool(atom)) { + std::cout << "aux bool\n"; bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); return true; @@ -706,7 +540,7 @@ namespace smt { break; } - if (c->k().is_one() && c->is_ge() && !m_enable_simplex) { + if (c->k().is_one() && c->is_ge()) { literal_vector& lits = get_lits(); lits.push_back(~lit); for (unsigned i = 0; i < c->size(); ++i) { @@ -752,64 +586,6 @@ namespace smt { m_var_infos[abv].m_ineq = c; m_ineqs_trail.push_back(abv); - if (m_enable_simplex) { - // - // TBD: using abv as slack identity doesn't quite - // work if psuedo-Booleans are used - // in a nested way. So assume - // - - arg_t rep(c->args()); - rep.remove_negations(); // normalize representative - numeral k = rep.k(); - theory_var slack; - bool_var abv2; - TRACE("pb", display(tout << abv <<"\n", rep);); - if (m_ineq_rep.find(rep, abv2)) { - slack = abv2; - TRACE("pb", - tout << "Old row: " << abv << " |-> " << slack << " "; - tout << m_ineq_row_info.find(abv2).m_bound << " vs. " << k << "\n"; - display(tout, rep);); - } - else { - m_ineq_rep.insert(rep, abv); - svector vars; - scoped_mpz_vector coeffs(m_mpz_mgr); - for (unsigned i = 0; i < rep.size(); ++i) { - unsigned v = rep.lit(i).var(); - m_simplex.ensure_var(v); - vars.push_back(v); - if (!m_vars.contains(v)) { - mpq_inf zero(mpq(0),mpq(0)), one(mpq(1),mpq(0)); - switch(ctx.get_assignment(rep.lit(i))) { - case l_true: - VERIFY(update_bound(v, literal(v), true, one)); - m_simplex.set_lower(v, one); - break; - case l_false: - VERIFY(update_bound(v, ~literal(v), false, zero)); - m_simplex.set_upper(v, zero); - break; - default: - m_simplex.set_lower(v, zero); - m_simplex.set_upper(v, one); - break; - } - m_vars.insert(v); - ctx.push_trail(remove_var(*this, v)); - } - coeffs.push_back(rep.coeff(i).to_mpq().numerator()); - } - slack = abv; - m_simplex.ensure_var(slack); - vars.push_back(slack); - coeffs.push_back(mpz(-1)); - m_simplex.add_row(slack, vars.size(), vars.c_ptr(), coeffs.c_ptr()); - TRACE("pb", tout << "New row: " << abv << " " << k << "\n"; display(tout, rep);); - } - m_ineq_row_info.insert(abv, row_info(slack, k, rep)); - } TRACE("pb", display(tout, *c);); @@ -1124,7 +900,6 @@ namespace smt { if (!resolve_conflict(c, lits)) { ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); } - std::cout << "inconsistent: " << ctx.inconsistent() << "\n"; SASSERT(ctx.inconsistent()); } @@ -1154,7 +929,6 @@ namespace smt { st.update("pb compilations", m_stats.m_num_compiles); st.update("pb compiled clauses", m_stats.m_num_compiled_clauses); st.update("pb compiled vars", m_stats.m_num_compiled_vars); - m_simplex.collect_statistics(st); } void theory_pb::reset_eh() { @@ -1188,17 +962,6 @@ namespace smt { TRACE("pb", tout << "assign: " << ~nlit << "\n";); ineqs = m_var_infos[v].m_lit_watch[nlit.sign()]; if (ineqs != 0) { - if (m_enable_simplex) { - mpq_inf num(mpq(is_true?1:0),mpq(0)); - if (!update_bound(v, ~nlit, is_true, num)) { - return; - } - - if (!check_feasible()) { - return; - } - } - for (unsigned i = 0; i < ineqs->size(); ++i) { SASSERT((*ineqs)[i]->is_ge()); if (assign_watch_ge(v, is_true, *ineqs, i)) { @@ -1216,26 +979,6 @@ namespace smt { } ineq* c = m_var_infos[v].m_ineq; if (c != 0) { - if (m_enable_simplex) { - row_info const& info = m_ineq_row_info.find(v); - scoped_eps_numeral coeff(m_mpq_inf_mgr); - coeff = std::make_pair(info.m_bound.to_mpq(), mpq(0)); - unsigned slack = info.m_slack; - if (is_true) { - update_bound(slack, literal(v), true, coeff); - if (c->is_eq()) { - update_bound(slack, literal(v), false, coeff); - } - } - else if (c->is_ge()) { - m_mpq_inf_mgr.sub(coeff, std::make_pair(mpq(1),mpq(0)), coeff); - update_bound(slack, ~literal(v), false, coeff); - } - - if (!check_feasible()) { - return; - } - } if (c->is_ge()) { assign_ineq(*c, is_true); } @@ -1765,16 +1508,6 @@ namespace smt { clear_watch(*c); m_var_infos[v].m_ineq = 0; m_ineqs_trail.pop_back(); - if (m_enable_simplex) { - row_info r_info; - VERIFY(m_ineq_row_info.find(v, r_info)); - m_ineq_row_info.erase(v); - bool_var v2 = m_ineq_rep.find(r_info.m_rep); - if (v == v2) { - m_simplex.del_row(r_info.m_slack); - m_ineq_rep.erase(r_info.m_rep); - } - } m_to_compile.erase(c); dealloc(c); } @@ -1925,7 +1658,6 @@ namespace smt { bool_var v = l.var(); unsigned lvl = ctx.get_assign_level(v); - TRACE("pb", tout << l << " " << ctx.is_marked(v) << " " << m_conflict_lvl << " " << ctx.get_base_level() << "\n";); if (lvl > ctx.get_base_level() && !ctx.is_marked(v) && lvl == m_conflict_lvl) { ctx.set_mark(v); ++m_num_marks; @@ -1963,10 +1695,10 @@ namespace smt { value += coeff; } else if (coeff == 0) { - std::cout << "unexpected 0 coefficient\n"; + UNREACHABLE(); } } - std::cout << "bound: " << m_bound << " value " << value << " coeffs: " << m_active_coeffs.size() << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; + // std::cout << "bound: " << m_bound << " value " << value << " coeffs: " << m_active_coeffs.size() << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; return value < 0; } @@ -1990,27 +1722,33 @@ namespace smt { literal theory_pb::cardinality_reduction(card*& c) { normalize_active_coeffs(); SASSERT(m_seen.empty()); + SASSERT(m_seen_trail.empty()); c = 0; int s = 0; int new_bound = 0; - int coeff; while (s < m_bound) { + int coeff; int arg = arg_max(m_seen, coeff); if (arg == -1) break; s += coeff; ++new_bound; m_seen.insert(arg); + m_seen_trail.push_back(arg); } - m_seen.reset(); // use a trail + for (unsigned i = 0; i < m_seen_trail.size(); ++i) { + m_seen.remove(m_seen_trail[i]); + } + m_seen_trail.reset(); int slack = m_bound; for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - coeff = get_abs_coeff(m_active_coeffs[i]); + int coeff = get_abs_coeff(m_active_coeffs[i]); slack = std::min(slack, coeff - 1); } while (slack > 0) { bool found = false; int v = 0; + int coeff = 0; for (unsigned i = 0; !found && i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; coeff = get_abs_coeff(v); @@ -2028,7 +1766,7 @@ namespace smt { literal card_lit = null_literal; for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; - coeff = get_coeff(v); + int coeff = get_coeff(v); if (coeff < 0) { m_coeffs[v] = -1; } @@ -2047,15 +1785,18 @@ namespace smt { ctx.set_var_theory(abv, get_id()); card_lit = literal(abv); c = alloc(card, card_lit, new_bound); - normalize_active_coeffs(); for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; + int coeff = get_coeff(v); if (coeff < 0) { c->add_arg(literal(v, true)); } else if (coeff > 0) { c->add_arg(literal(v, false)); } + else { + UNREACHABLE(); + } } m_stats.m_num_predicates++; // display(std::cout, *c, true); @@ -2077,7 +1818,7 @@ namespace smt { card_lit = lit; } } - std::cout << "cardinality: " << card_lit << " " << atom << "\n"; + SASSERT(card_lit != null_literal); dealloc(c); c = 0; } @@ -2132,7 +1873,7 @@ namespace smt { m_bound -= coeff0 - std::max(0, coeff1); } else if (coeff0 < 0 && inc > 0) { - m_bound -= std::min(0, coeff1) + coeff0; + m_bound -= std::min(0, coeff1) - coeff0; } } @@ -2191,7 +1932,7 @@ namespace smt { return false; } - std::cout << c.lit() << "\n"; + // std::cout << c.lit() << "\n"; reset_coeffs(); m_num_marks = 0; @@ -2214,7 +1955,6 @@ namespace smt { while (m_num_marks > 0) { v = conseq.var(); - TRACE("pb", display_resolved_lemma(tout << conseq << "\n");); int offset = get_abs_coeff(v); @@ -2236,8 +1976,12 @@ namespace smt { SASSERT(offset > 0); js = ctx.get_justification(v); - // ctx.display(std::cout, js); - + + TRACE("pb", + display_resolved_lemma(tout << conseq << "\n"); + ctx.display(tout, js);); + + m_resolved.push_back(conseq); // @@ -2249,7 +1993,6 @@ namespace smt { switch(js.get_kind()) { case b_justification::CLAUSE: { - inc_coeff(conseq, offset); clause& cls = *js.get_clause(); justification* cjs = cls.get_justification(); if (cjs && !is_proof_justification(*cjs)) { @@ -2274,10 +2017,8 @@ namespace smt { case b_justification::BIN_CLAUSE: inc_coeff(conseq, offset); process_antecedent(~js.get_literal(), offset); - TRACE("pb", tout << "binary: " << js.get_literal() << "\n";); break; case b_justification::AXIOM: - TRACE("pb", tout << "axiom " << conseq << "\n";); break; case b_justification::JUSTIFICATION: { justification* j = js.get_justification(); @@ -2295,10 +2036,11 @@ namespace smt { process_card(c2, offset); unsigned i = 0; for (i = 0; i < c2.size() && c2.lit(i) != conseq; ++i) {} - std::cout << c2.lit() << " index at " << i << " of " << c2.size(); + // std::cout << c2.lit() << " index at " << i << " of " << c2.size(); bound = c2.k(); } - std::cout << " offset: " << offset << " bound: " << bound << "\n"; + + // std::cout << " offset: " << offset << " bound: " << bound << "\n"; break; } default: @@ -2320,7 +2062,6 @@ namespace smt { SASSERT(ctx.get_assign_level(v) == m_conflict_lvl); ctx.unset_mark(v); - m_resolved.push_back(idx); --idx; --m_num_marks; } @@ -2338,7 +2079,7 @@ namespace smt { ++sz; count += coeff; } - std::cout << "New " << count << "(" << sz << ") >= " << m_bound << " " << c.size() << " >= " << c.k() << " new diff: " << count - m_bound << " old diff: " << c.size() - c.k() << "\n"; + // std::cout << "New " << count << "(" << sz << ") >= " << m_bound << " " << c.size() << " >= " << c.k() << " new diff: " << count - m_bound << " old diff: " << c.size() - c.k() << "\n"; card* cr = 0; literal card_lit = cardinality_reduction(cr); @@ -2350,7 +2091,8 @@ namespace smt { m_antecedents.reset(); m_antecedents.push_back(card_lit); unsigned slack = cr ? (cr->size() - cr->k()) : 0; - for (unsigned i = 0; 0 < slack && i < cr->size(); ++i) { + for (unsigned i = 0; 0 < slack; ++i) { + SASSERT(i < cr->size()); literal lit = cr->lit(i); SASSERT(lit.var() != conseq.var() || lit == ~conseq); if (lit.var() != conseq.var() && ctx.get_assignment(lit) == l_false) { @@ -2358,8 +2100,9 @@ namespace smt { --slack; } } + SASSERT(slack == 0); ctx.assign(~conseq, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), ~conseq, 0, 0))); - std::cout << conseq << " " << ctx.get_assignment(conseq) << "\n"; + // std::cout << "slack " << slack << " " << conseq << " " << ctx.get_assignment(conseq) << "\n"; } return card_lit != null_literal; @@ -2477,9 +2220,9 @@ namespace smt { out << "num marks: " << m_num_marks << "\n"; out << "conflict level: " << m_conflict_lvl << "\n"; for (unsigned i = 0; i < m_resolved.size(); ++i) { - v = lits[m_resolved[i]].var(); + v = m_resolved[i].var(); lvl = ctx.get_assign_level(v); - out << lvl << ": " << lits[i] << " "; + out << lvl << ": " << m_resolved[i] << " "; ctx.display(out, ctx.get_justification(v)); } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index db58e7a07..4e61709e7 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -291,7 +291,6 @@ namespace smt { unsigned m_conflict_frequency; bool m_learn_complements; bool m_enable_compilation; - bool m_enable_simplex; rational m_max_compiled_coeff; // internalize_atom: @@ -336,8 +335,6 @@ namespace smt { // simplex: - literal set_explain(literal_vector& explains, unsigned var, literal expl); - bool update_bound(bool_var v, literal explain, bool is_lower, mpq_inf const& bound); bool check_feasible(); std::ostream& display(std::ostream& out, ineq const& c, bool values = false) const; @@ -366,7 +363,7 @@ namespace smt { // Conflict resolution, cutting plane derivation. // unsigned m_num_marks; - unsigned_vector m_resolved; + literal_vector m_resolved; unsigned m_conflict_lvl; // Conflict PB constraints @@ -375,6 +372,7 @@ namespace smt { int m_bound; literal_vector m_antecedents; uint_set m_seen; + unsigned_vector m_seen_trail; void normalize_active_coeffs(); void inc_coeff(literal l, int offset); From d68cb5aee78c48cad73b9db9fc327021435434d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 20 Jan 2017 07:44:00 -0800 Subject: [PATCH 0008/1283] working on conflict resolution Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 146 ++++++++++++++++++++++-------------------- src/smt/theory_pb.h | 14 +++- 2 files changed, 91 insertions(+), 69 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index f7c36b5c4..c0eb379d9 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -446,7 +446,8 @@ namespace smt { m_params(p), m_simplex(m.limit()), m_util(m), - m_max_compiled_coeff(rational(8)) + m_max_compiled_coeff(rational(8)), + m_card_reinit(false) { m_learn_complements = p.m_pb_learn_complements; m_conflict_frequency = p.m_pb_conflict_frequency; @@ -942,6 +943,7 @@ namespace smt { m_card_lim.reset(); m_stats.reset(); m_to_compile.reset(); + m_card_reinit = false; } void theory_pb::new_eq_eh(theory_var v1, theory_var v2) { @@ -1526,6 +1528,9 @@ namespace smt { } m_card_lim.resize(new_lim); + + add_cardinality_lemma(); + } void theory_pb::clear_watch(ineq& c) { @@ -1719,11 +1724,10 @@ namespace smt { return arg_max; } - literal theory_pb::cardinality_reduction(card*& c) { + literal theory_pb::cardinality_reduction(literal prop_lit) { normalize_active_coeffs(); SASSERT(m_seen.empty()); SASSERT(m_seen_trail.empty()); - c = 0; int s = 0; int new_bound = 0; while (s < m_bound) { @@ -1762,8 +1766,6 @@ namespace smt { slack -= coeff; m_coeffs[v] = 0; // deactivate coefficient. } - // create cardinality constraint - literal card_lit = null_literal; for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { bool_var v = m_active_coeffs[i]; int coeff = get_coeff(v); @@ -1777,59 +1779,34 @@ namespace smt { m_bound = new_bound; if (validate_lemma()) { - ast_manager& m = get_manager(); - context& ctx = get_context(); - pb_util pb(m); - expr_ref atom(pb.mk_fresh_bool(), m); - bool_var abv = ctx.mk_bool_var(atom); - ctx.set_var_theory(abv, get_id()); - card_lit = literal(abv); - c = alloc(card, card_lit, new_bound); - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; - int coeff = get_coeff(v); - if (coeff < 0) { - c->add_arg(literal(v, true)); - } - else if (coeff > 0) { - c->add_arg(literal(v, false)); - } - else { - UNREACHABLE(); - } - } - m_stats.m_num_predicates++; - // display(std::cout, *c, true); - if (c->k() == 0) { - UNREACHABLE(); - } - else if (c->size() < c->k()) { - card_lit = false_literal; - dealloc(c); - c = 0; - } - else if (c->size() == c->k()) { - card_lit = null_literal; - unsigned lvl = UINT_MAX; - for (unsigned i = 0; i < c->size(); ++i) { - literal lit = c->lit(i); + SASSERT(m_bound > 0); + if (m_bound > static_cast(m_active_coeffs.size())) { + return false_literal; + } + if (m_bound == m_active_coeffs.size()) { + prop_lit = null_literal; + context& ctx = get_context(); + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + literal lit(get_coeff(v) < 0); + unsigned lvl = UINT_MAX; if (ctx.get_assignment(lit) == l_false && ctx.get_assign_level(lit) < lvl) { + prop_lit = lit; lvl = ctx.get_assign_level(lit); - card_lit = lit; } } - SASSERT(card_lit != null_literal); - dealloc(c); - c = 0; + SASSERT(prop_lit != null_literal); } else { - init_watch(abv); - m_var_infos[abv].m_card = c; - m_card_trail.push_back(abv); + m_card_reinit = true; + return prop_lit; } } + else { + TRACE("pb", display_resolved_lemma(tout);); + } - return card_lit; + return null_literal; } void theory_pb::normalize_active_coeffs() { @@ -1915,7 +1892,45 @@ namespace smt { TRACE("pb", display_resolved_lemma(tout << "cut\n");); } } + + void theory_pb::add_cardinality_lemma() { + context& ctx = get_context(); + ast_manager& m = get_manager(); + if (ctx.inconsistent() || !m_card_reinit) { + return; + } + m_card_reinit = false; + + pb_util pb(m); + expr_ref pred(pb.mk_fresh_bool(), m); + bool_var abv = ctx.mk_bool_var(pred); + ctx.set_var_theory(abv, get_id()); + literal lit(abv); + card* c = alloc(card, lit, m_bound); + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + bool_var v = m_active_coeffs[i]; + int coeff = get_coeff(v); + SASSERT(coeff != 0); + c->add_arg(literal(v, coeff < 0)); + } + + init_watch(abv); + m_var_infos[abv].m_card = c; + m_card_trail.push_back(abv); + for (unsigned i = 0; i < m_antecedents.size(); ++i) { + m_antecedents[i].neg(); + } + m_antecedents.push_back(lit); + TRACE("pb", tout << m_antecedents << "\n";); + justification* js = 0; + if (proofs_enabled()) { + js = 0; // + } + ++m_stats.m_num_predicates; + ctx.mk_clause(m_antecedents.size(), m_antecedents.c_ptr(), js, CLS_AUX_LEMMA, 0); + } + bool theory_pb::resolve_conflict(card& c, literal_vector const& confl) { TRACE("pb", display(tout, c, true); ); @@ -1923,6 +1938,7 @@ namespace smt { bool_var v; context& ctx = get_context(); m_conflict_lvl = 0; + m_card_reinit = false; for (unsigned i = 0; i < confl.size(); ++i) { literal lit = confl[i]; SASSERT(ctx.get_assignment(lit) == l_false); @@ -1993,6 +2009,7 @@ namespace smt { switch(js.get_kind()) { case b_justification::CLAUSE: { + inc_coeff(conseq, offset); clause& cls = *js.get_clause(); justification* cjs = cls.get_justification(); if (cjs && !is_proof_justification(*cjs)) { @@ -2080,32 +2097,25 @@ namespace smt { count += coeff; } // std::cout << "New " << count << "(" << sz << ") >= " << m_bound << " " << c.size() << " >= " << c.k() << " new diff: " << count - m_bound << " old diff: " << c.size() - c.k() << "\n"; - card* cr = 0; - literal card_lit = cardinality_reduction(cr); + literal prop_lit = cardinality_reduction(~conseq); - if (card_lit != null_literal) { - ctx.assign(card_lit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), card_lit, 0, 0))); - } - - if (cr != 0) { - m_antecedents.reset(); - m_antecedents.push_back(card_lit); - unsigned slack = cr ? (cr->size() - cr->k()) : 0; - for (unsigned i = 0; 0 < slack; ++i) { - SASSERT(i < cr->size()); - literal lit = cr->lit(i); - SASSERT(lit.var() != conseq.var() || lit == ~conseq); - if (lit.var() != conseq.var() && ctx.get_assignment(lit) == l_false) { + if (prop_lit != null_literal) { + TRACE("pb", tout << "cardinality literal: " << prop_lit << "\n";); + SASSERT(static_cast(m_active_coeffs.size()) >= m_bound); + unsigned slack = m_active_coeffs.size() - m_bound; + for (unsigned i = 0; i < slack; ++i) { + bool_var v = m_active_coeffs[i]; + literal lit(v, get_coeff(v) < 0); + SASSERT(lit.var() != prop_lit.var() || lit == prop_lit); + if (lit != prop_lit && ctx.get_assignment(lit) == l_false) { m_antecedents.push_back(~lit); --slack; } } - SASSERT(slack == 0); - ctx.assign(~conseq, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), ~conseq, 0, 0))); - // std::cout << "slack " << slack << " " << conseq << " " << ctx.get_assignment(conseq) << "\n"; + ctx.assign(prop_lit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), prop_lit, 0, 0))); } - return card_lit != null_literal; + return prop_lit != null_literal; } bool theory_pb::is_proof_justification(justification const& j) const { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 4e61709e7..5046d7ab3 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -270,6 +270,15 @@ namespace smt { } }; + struct card_reinit { + literal_vector m_lits; + card* m_card; + + card_reinit(literal_vector const& lits, card* c): + m_lits(lits), + m_card(c) + {} + }; theory_pb_params m_params; @@ -293,6 +302,8 @@ namespace smt { bool m_enable_compilation; rational m_max_compiled_coeff; + bool m_card_reinit; + // internalize_atom: literal compile_arg(expr* arg); void init_watch(bool_var v); @@ -381,7 +392,8 @@ namespace smt { int arg_max(uint_set& seen, int& coeff); void reset_coeffs(); - literal cardinality_reduction(card*& c); + literal cardinality_reduction(literal propagation_lit); + void add_cardinality_lemma(); bool resolve_conflict(card& c, literal_vector const& conflict_clause); void process_antecedent(literal l, int offset); From 904f87feaca2db704ce603b9cf464b45fedfd6ce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 20 Jan 2017 21:36:52 -0800 Subject: [PATCH 0009/1283] working on card Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 3 +++ src/smt/theory_pb.cpp | 45 +++++++++++++++++++++++++++++++++-------- src/smt/theory_pb.h | 16 +++++---------- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3bb4996c7..5853f8fd1 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3719,6 +3719,9 @@ namespace smt { svector expr_signs; for (unsigned i = 0; i < num_lits; i++) { literal l = lits[i]; + if (get_assignment(l) != l_false) { + std::cout << l << " " << get_assignment(l) << "\n"; + } SASSERT(get_assignment(l) == l_false); expr_lits.push_back(bool_var2expr(l.var())); expr_signs.push_back(l.sign()); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index c0eb379d9..22c7ddc24 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -236,6 +236,7 @@ namespace smt { m_args[i].neg(); } m_bound = sz - m_bound + 1; + SASSERT(m_bound > 0); } lbool theory_pb::card::assign(theory_pb& th, literal lit) { @@ -259,6 +260,10 @@ namespace smt { break; } } + if (index == m_bound + 1) { + // literal is no longer watched. + return l_undef; + } SASSERT(index <= m_bound); SASSERT(m_args[index] == lit); @@ -401,7 +406,9 @@ namespace smt { } else if (j == m_bound) { literal_vector lits(size() - m_bound, m_args.c_ptr() + m_bound); - for (i = 0; i < j; ++i) { + th.negate(lits); + lits.push_back(lit()); + for (i = 0; i < m_bound; ++i) { if (ctx.get_assignment(lit(i)) == l_undef) { th.add_assign(*this, lits, lit(i)); } @@ -473,9 +480,9 @@ namespace smt { m_stats.m_num_predicates++; if (m_util.is_aux_bool(atom)) { - std::cout << "aux bool\n"; bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); + // std::cout << "aux bool " << ctx.get_scope_level() << " " << mk_pp(atom, get_manager()) << " " << literal(abv) << "\n"; return true; } @@ -909,6 +916,7 @@ namespace smt { m_stats.m_num_propagations++; context& ctx = get_context(); TRACE("pb", tout << "#prop: " << c.num_propagations() << " - " << lits << " " << c.lit() << " => " << l << "\n";); + SASSERT(validate_antecedents(lits)); ctx.assign(l, ctx.mk_justification( card_justification( c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); @@ -1528,9 +1536,6 @@ namespace smt { } m_card_lim.resize(new_lim); - - add_cardinality_lemma(); - } void theory_pb::clear_watch(ineq& c) { @@ -1619,6 +1624,7 @@ namespace smt { tout << " => " << l << "\n"; display(tout, c, true);); + SASSERT(validate_antecedents(lits)); ctx.assign(l, ctx.mk_justification( pb_justification( c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); @@ -1672,7 +1678,7 @@ namespace smt { void theory_pb::process_card(card& c, int offset) { context& ctx = get_context(); - process_antecedent(c.lit(0), offset); + inc_coeff(c.lit(0), offset); for (unsigned i = c.k() + 1; i < c.size(); ++i) { process_antecedent(c.lit(i), offset); } @@ -1893,7 +1899,10 @@ namespace smt { } } - void theory_pb::add_cardinality_lemma() { + bool theory_pb::can_propagate() { return m_card_reinit; } + + + void theory_pb::propagate() { context& ctx = get_context(); ast_manager& m = get_manager(); if (ctx.inconsistent() || !m_card_reinit) { @@ -1901,11 +1910,15 @@ namespace smt { } m_card_reinit = false; + if (!validate_antecedents(m_antecedents)) { + return; + } pb_util pb(m); expr_ref pred(pb.mk_fresh_bool(), m); bool_var abv = ctx.mk_bool_var(pred); ctx.set_var_theory(abv, get_id()); literal lit(abv); + // std::cout << "fresh " << pred << " " << lit << "\n"; card* c = alloc(card, lit, m_bound); for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { @@ -1967,7 +1980,6 @@ namespace smt { b_justification js; literal conseq = ~confl[2]; - while (m_num_marks > 0) { v = conseq.var(); @@ -2112,6 +2124,7 @@ namespace smt { --slack; } } + SASSERT(validate_antecedents(m_antecedents)); ctx.assign(prop_lit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), prop_lit, 0, 0))); } @@ -2220,6 +2233,22 @@ namespace smt { SASSERT(!c.is_eq() || (sum == c.k()) == (ctx.get_assignment(c.lit()) == l_true)); } + bool theory_pb::validate_antecedents(literal_vector const& lits) { + context& ctx = get_context(); + for (unsigned i = 0; i < lits.size(); ++i) { + if (ctx.get_assignment(lits[i]) != l_true) { + return false; + } + } + return true; + } + + void theory_pb::negate(literal_vector & lits) { + for (unsigned i = 0; i < lits.size(); ++i) { + lits[i].neg(); + } + } + // display methods void theory_pb::display_resolved_lemma(std::ostream& out) const { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 5046d7ab3..ab83160ce 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -201,6 +201,7 @@ namespace smt { m_compilation_threshold(0), m_compiled(l_false) { + SASSERT(bound > 0); } literal lit() const { return m_lit; } @@ -270,16 +271,6 @@ namespace smt { } }; - struct card_reinit { - literal_vector m_lits; - card* m_card; - - card_reinit(literal_vector const& lits, card* c): - m_lits(lits), - m_card(c) - {} - }; - theory_pb_params m_params; svector m_var_infos; @@ -393,7 +384,6 @@ namespace smt { void reset_coeffs(); literal cardinality_reduction(literal propagation_lit); - void add_cardinality_lemma(); bool resolve_conflict(card& c, literal_vector const& conflict_clause); void process_antecedent(literal l, int offset); @@ -409,6 +399,8 @@ namespace smt { void validate_final_check(ineq& c); void validate_assign(ineq const& c, literal_vector const& lits, literal l) const; void validate_watch(ineq const& c) const; + bool validate_antecedents(literal_vector const& lits); + void negate(literal_vector & lits); bool proofs_enabled() const { return get_manager().proofs_enabled(); } justification* justify(literal l1, literal l2); @@ -437,6 +429,8 @@ namespace smt { virtual model_value_proc * mk_value(enode * n, model_generator & mg); virtual void init_model(model_generator & m); virtual bool include_func_interp(func_decl* f) { return false; } + virtual bool can_propagate(); + virtual void propagate(); static literal assert_ge(context& ctx, unsigned k, unsigned n, literal const* xs); }; From 127bae85bd4e111da1f61318545fe6d404180b5f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 22 Jan 2017 15:33:29 -0800 Subject: [PATCH 0010/1283] fixing card Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 553 ++++++++++++++++++++++++------------------ src/smt/theory_pb.h | 31 ++- 2 files changed, 341 insertions(+), 243 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 22c7ddc24..10f869677 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -236,42 +236,35 @@ namespace smt { m_args[i].neg(); } m_bound = sz - m_bound + 1; - SASSERT(m_bound > 0); + SASSERT(sz >= m_bound && m_bound > 0); } - lbool theory_pb::card::assign(theory_pb& th, literal lit) { - TRACE("pb", tout << "assign: " << m_lit << " " << ~lit << " " << m_bound << "\n";); + lbool theory_pb::card::assign(theory_pb& th, literal alit) { // literal is assigned to false. context& ctx = th.get_context(); - SASSERT(m_bound > 0); - SASSERT(ctx.get_assignment(lit) == l_false); - unsigned index = m_bound + 1; - // - // We give preference to a watched literal in position 1..m_bound. - // Notice, that if a literal occurs multiple - // times in m_args, within [0..m_bound] then it is inserted into the watch - // list for this cardinality constraint. For each occurrence, a callback - // to assign is made. - // - for (unsigned i = m_bound + 1; i > 0; ) { - --i; - if (m_args[i] == lit) { - index = i; + unsigned sz = size(); + unsigned bound = k(); + TRACE("pb", tout << "assign: " << m_lit << " " << ~alit << " " << bound << "\n";); + + SASSERT(0 < bound && bound < sz); + SASSERT(ctx.get_assignment(alit) == l_false); + SASSERT(ctx.get_assignment(m_lit) == l_true); + unsigned index = 0; + for (index = 0; index <= bound; ++index) { + if (lit(index) == alit) { break; } } - if (index == m_bound + 1) { + if (index == bound + 1) { // literal is no longer watched. return l_undef; } - SASSERT(index <= m_bound); - SASSERT(m_args[index] == lit); - - unsigned sz = size(); + SASSERT(index <= bound); + SASSERT(lit(index) == alit); // find a literal to swap with: - for (unsigned i = m_bound + 1; i < sz; ++i) { - literal lit2 = m_args[i]; + for (unsigned i = bound + 1; i < sz; ++i) { + literal lit2 = lit(i); if (ctx.get_assignment(lit2) != l_false) { TRACE("pb", tout << "swap " << lit2 << "\n";); std::swap(m_args[index], m_args[i]); @@ -281,37 +274,36 @@ namespace smt { } // conflict - if (0 != index && ctx.get_assignment(m_args[0]) == l_false) { - TRACE("pb", tout << "conflict " << m_args[0] << " " << lit << "\n";); - set_conflict(th, lit); + if (bound != index && ctx.get_assignment(lit(bound)) == l_false) { + TRACE("pb", tout << "conflict " << lit(bound) << " " << alit << "\n";); + set_conflict(th, alit); return l_false; } - TRACE("pb", tout << "no swap " << index << " " << lit << "\n";); + TRACE("pb", tout << "no swap " << index << " " << alit << "\n";); // there are no literals to swap with, // prepare for unit propagation by swapping the false literal into - // position 0. Then literals in positions 1..m_bound have to be + // position bound. Then literals in positions 0..bound-1 have to be // assigned l_true. - if (index != 0) { - std::swap(m_args[index], m_args[0]); + if (index != bound) { + std::swap(m_args[index], m_args[bound]); } - SASSERT(m_args[0] == lit); - literal_vector lits; + SASSERT(th.validate_unit_propagation(*this)); + literal_vector& lits = th.get_literals(); lits.push_back(m_lit); - lits.push_back(~lit); - for (unsigned i = m_bound + 1; i < sz; ++i) { - SASSERT(ctx.get_assignment(m_args[i]) == l_false); - lits.push_back(~m_args[i]); + for (unsigned i = bound; i < sz; ++i) { + SASSERT(ctx.get_assignment(lit(i)) == l_false); + lits.push_back(~lit(i)); } - for (unsigned i = 1; i <= m_bound; ++i) { - literal lit2 = m_args[i]; + for (unsigned i = 0; i < bound; ++i) { + literal lit2 = lit(i); lbool value = ctx.get_assignment(lit2); switch (value) { case l_true: break; case l_false: - TRACE("pb", tout << "conflict: " << lit << " " << lit2 << "\n";); + TRACE("pb", tout << "conflict: " << alit << " " << lit2 << "\n";); set_conflict(th, lit2); return l_false; case l_undef: @@ -335,16 +327,13 @@ namespace smt { void theory_pb::card::set_conflict(theory_pb& th, literal l) { SASSERT(validate_conflict(th)); context& ctx = th.get_context(); - literal l0 = m_args[0]; - literal_vector lits; - SASSERT(ctx.get_assignment(l0) == l_false); + literal_vector& lits = th.get_literals(); SASSERT(ctx.get_assignment(l) == l_false); SASSERT(ctx.get_assignment(lit()) == l_true); lits.push_back(~lit()); - lits.push_back(l0); lits.push_back(l); unsigned sz = size(); - for (unsigned i = m_bound + 1; i < sz; ++i) { + for (unsigned i = m_bound; i < sz; ++i) { SASSERT(ctx.get_assignment(m_args[i]) == l_false); lits.push_back(m_args[i]); } @@ -373,13 +362,22 @@ namespace smt { void theory_pb::card::init_watch(theory_pb& th, bool is_true) { context& ctx = th.get_context(); - + th.clear_watch(*this); if (lit().sign() == is_true) { negate(); } + SASSERT(ctx.get_assignment(lit()) == l_true); + unsigned j = 0, sz = size(), bound = k(); + if (bound == sz) { + literal_vector& lits = th.get_literals(); + lits.push_back(lit()); + for (unsigned i = 0; i < sz && !ctx.inconsistent(); ++i) { + th.add_assign(*this, lits, lit(i)); + } + return; + } // put the non-false literals into the head. - unsigned i = 0, j = 0, sz = size(); - for (i = 0; i < sz; ++i) { + for (unsigned i = 0; i < sz; ++i) { if (ctx.get_assignment(lit(i)) != l_false) { if (j != i) { std::swap(m_args[i], m_args[j]); @@ -387,35 +385,42 @@ namespace smt { ++j; } } + DEBUG_CODE( + bool is_false = false; + for (unsigned k = 0; k < sz; ++k) { + SASSERT(!is_false || ctx.get_assignment(lit(k)) == l_false); + is_false = ctx.get_assignment(lit(k)) == l_false; + }); + // j is the number of non-false, sz - j the number of false. - if (j < m_bound) { - std::swap(m_args[0], m_args[m_bound-1]); + if (j < bound) { + SASSERT(0 < bound && bound < sz); + literal alit = lit(j); + // // we need the assignment level of the asserting literal to be maximal. // such that conflict resolution can use the asserting literal as a starting // point. - if (ctx.get_assign_level(m_args[0]) > ctx.get_assign_level(m_args[m_bound])) { - std::swap(m_args[0], m_args[m_bound]); - } - for (i = m_bound + 1; i < sz; ++i) { - if (ctx.get_assign_level(m_args[i]) > ctx.get_assign_level(m_args[m_bound])) { - std::swap(m_args[i], m_args[m_bound]); + // + + for (unsigned i = bound; i < sz; ++i) { + if (ctx.get_assign_level(alit) < ctx.get_assign_level(lit(i))) { + std::swap(m_args[j], m_args[i]); + alit = lit(j); } } - set_conflict(th, m_args[m_bound]); + set_conflict(th, alit); } - else if (j == m_bound) { - literal_vector lits(size() - m_bound, m_args.c_ptr() + m_bound); + else if (j == bound) { + literal_vector lits(sz - bound, m_args.c_ptr() + bound); th.negate(lits); lits.push_back(lit()); - for (i = 0; i < m_bound; ++i) { - if (ctx.get_assignment(lit(i)) == l_undef) { - th.add_assign(*this, lits, lit(i)); - } + for (unsigned i = 0; i < bound && !ctx.inconsistent(); ++i) { + th.add_assign(*this, lits, lit(i)); } } else { - for (unsigned i = 0; i <= m_bound; ++i) { + for (unsigned i = 0; i <= bound; ++i) { th.watch_literal(lit(i), this); } } @@ -454,7 +459,9 @@ namespace smt { m_simplex(m.limit()), m_util(m), m_max_compiled_coeff(rational(8)), - m_card_reinit(false) + m_cardinality_lemma(false), + m_antecedent_exprs(m), + m_cardinality_exprs(m) { m_learn_complements = p.m_pb_learn_complements; m_conflict_frequency = p.m_pb_conflict_frequency; @@ -465,7 +472,6 @@ namespace smt { reset_eh(); } - theory * theory_pb::mk_fresh(context * new_ctx) { return alloc(theory_pb, new_ctx->get_manager(), m_params); } @@ -474,7 +480,7 @@ namespace smt { context& ctx = get_context(); TRACE("pb", tout << mk_pp(atom, get_manager()) << "\n";); if (ctx.b_internalized(atom)) { - return false; + return true; } SASSERT(!ctx.b_internalized(atom)); m_stats.m_num_predicates++; @@ -482,7 +488,7 @@ namespace smt { if (m_util.is_aux_bool(atom)) { bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); - // std::cout << "aux bool " << ctx.get_scope_level() << " " << mk_pp(atom, get_manager()) << " " << literal(abv) << "\n"; + std::cout << "aux bool " << ctx.get_scope_level() << " " << mk_pp(atom, get_manager()) << " " << literal(abv) << "\n"; return true; } @@ -549,7 +555,7 @@ namespace smt { } if (c->k().is_one() && c->is_ge()) { - literal_vector& lits = get_lits(); + literal_vector& lits = get_literals(); lits.push_back(~lit); for (unsigned i = 0; i < c->size(); ++i) { lits.push_back(c->lit(i)); @@ -764,7 +770,7 @@ namespace smt { if (m_util.is_ge(atom) && m_util.has_unit_coefficients(atom)) { return true; } - if (m_util.is_at_most_k(atom)) { + if (m_util.is_at_least_k(atom)) { return true; } // TBD: other conditions @@ -772,16 +778,30 @@ namespace smt { } bool theory_pb::internalize_card(app * atom, bool gate_ctx) { + context& ctx = get_context(); + if (ctx.b_internalized(atom)) { + return true; + } + if (!is_cardinality_constraint(atom)) { return false; - } - context& ctx = get_context(); + } unsigned num_args = atom->get_num_args(); bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); unsigned bound = m_util.get_k(atom).get_unsigned(); literal lit(abv); + if (bound == 0) { + ctx.mk_th_axiom(get_id(), 1, &lit); + return true; + } + if (bound > num_args) { + lit.neg(); + ctx.mk_th_axiom(get_id(), 1, &lit); + return true; + } + card* c = alloc(card, lit, bound); for (unsigned i = 0; i < num_args; ++i) { @@ -789,25 +809,21 @@ namespace smt { c->add_arg(compile_arg(arg)); } + if (bound == c->size() || bound == 1) { + std::cout << "is-clause\n"; + } - if (c->k() == 0) { - ctx.mk_th_axiom(get_id(), 1, &lit); - dealloc(c); - } - else if (c->k() > c->size()) { - lit.neg(); - ctx.mk_th_axiom(get_id(), 1, &lit); - dealloc(c); - } - else if (c->k() == c->size()) { + if (bound == c->size()) { card2conjunction(*c); dealloc(c); } + else if (1 == c->size()) { + card2disjunction(*c); + dealloc(c); + } else { - SASSERT(0 < c->k() && c->k() < c->size()); - - // initialize compilation thresholds, TBD - + SASSERT(0 < c->k() && c->k() < c->size()); + // initialize compilation thresholds, TBD init_watch(abv); m_var_infos[abv].m_card = c; m_card_trail.push_back(abv); @@ -820,7 +836,7 @@ namespace smt { void theory_pb::card2conjunction(card const& c) { context& ctx = get_context(); literal lit = c.lit(); - literal_vector lits; + literal_vector& lits = get_literals(); for (unsigned i = 0; i < c.size(); ++i) { lits.push_back(~c.lit(i)); } @@ -832,6 +848,21 @@ namespace smt { } } + void theory_pb::card2disjunction(card const& c) { + context& ctx = get_context(); + literal lit = c.lit(); + literal_vector& lits = get_literals(); + for (unsigned i = 0; i < c.size(); ++i) { + lits.push_back(c.lit(i)); + } + lits.push_back(~lit); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + for (unsigned i = 0; i < c.size(); ++i) { + literal lits2[2] = { lit, ~c.lit(i) }; + ctx.mk_th_axiom(get_id(), 2, lits2); + } + } + void theory_pb::watch_literal(literal lit, card* c) { init_watch(lit.var()); ptr_vector* cards = m_var_infos[lit.var()].m_lit_cwatch[lit.sign()]; @@ -911,21 +942,25 @@ namespace smt { SASSERT(ctx.inconsistent()); } - void theory_pb::add_assign(card& c, literal_vector const& lits, literal l) { + void theory_pb::add_assign(card& c, literal_vector const& lits, literal l) { + context& ctx = get_context(); + if (ctx.get_assignment(l) == l_true) { + return; + } c.inc_propagations(*this); m_stats.m_num_propagations++; - context& ctx = get_context(); TRACE("pb", tout << "#prop: " << c.num_propagations() << " - " << lits << " " << c.lit() << " => " << l << "\n";); SASSERT(validate_antecedents(lits)); + SASSERT(validate_unit_propagation(c)); ctx.assign(l, ctx.mk_justification( card_justification( c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); } void theory_pb::clear_watch(card& c) { - for (unsigned i = 0; i <= c.k(); ++i) { - literal w = c.lit(i); - unwatch_literal(w, &c); + unsigned sz = std::min(c.k() + 1, c.size()); + for (unsigned i = 0; i < sz; ++i) { + unwatch_literal(c.lit(i), &c); } } @@ -951,7 +986,7 @@ namespace smt { m_card_lim.reset(); m_stats.reset(); m_to_compile.reset(); - m_card_reinit = false; + m_cardinality_lemma = false; } void theory_pb::new_eq_eh(theory_var v1, theory_var v2) { @@ -998,7 +1033,7 @@ namespace smt { } ptr_vector* cards = m_var_infos[v].m_lit_cwatch[nlit.sign()]; - if (cards != 0 && !ctx.inconsistent()) { + if (cards != 0 && !cards->empty() && !ctx.inconsistent()) { ptr_vector::iterator it = cards->begin(), it2 = it, end = cards->end(); for (; it != end; ++it) { if (ctx.get_assignment((*it)->lit()) != l_true) { @@ -1009,6 +1044,7 @@ namespace smt { for (; it != end; ++it, ++it2) { *it2 = *it; } + SASSERT(ctx.inconsistent()); cards->set_end(it2); return; case l_undef: // watch literal was swapped @@ -1033,7 +1069,7 @@ namespace smt { literal_vector& theory_pb::get_all_literals(ineq& c, bool negate) { context& ctx = get_context(); - literal_vector& lits = get_lits(); + literal_vector& lits = get_literals(); for (unsigned i = 0; i < c.size(); ++i) { literal l = c.lit(i); switch(ctx.get_assignment(l)) { @@ -1048,14 +1084,13 @@ namespace smt { } } return lits; - } literal_vector& theory_pb::get_helpful_literals(ineq& c, bool negate) { scoped_mpz sum(m_mpz_mgr); mpz const& k = c.mpz_k(); context& ctx = get_context(); - literal_vector& lits = get_lits(); + literal_vector& lits = get_literals(); for (unsigned i = 0; sum < k && i < c.size(); ++i) { literal l = c.lit(i); if (ctx.get_assignment(l) == l_true) { @@ -1070,7 +1105,7 @@ namespace smt { literal_vector& theory_pb::get_unhelpful_literals(ineq& c, bool negate) { context& ctx = get_context(); - literal_vector& lits = get_lits(); + literal_vector& lits = get_literals(); for (unsigned i = 0; i < c.size(); ++i) { literal l = c.lit(i); if (ctx.get_assignment(l) == l_false) { @@ -1154,10 +1189,8 @@ namespace smt { literal_vector& lits = get_unhelpful_literals(c, true); lits.push_back(c.lit()); for (unsigned i = 0; i < sz; ++i) { - if (ctx.get_assignment(c.lit(i)) == l_undef) { - DEBUG_CODE(validate_assign(c, lits, c.lit(i));); - add_assign(c, lits, c.lit(i)); - } + DEBUG_CODE(validate_assign(c, lits, c.lit(i));); + add_assign(c, lits, c.lit(i)); } } } @@ -1600,11 +1633,6 @@ namespace smt { } } - literal_vector& theory_pb::get_lits() { - m_literals.reset(); - return m_literals; - } - class theory_pb::pb_justification : public theory_propagation_justification { ineq& m_ineq; public: @@ -1657,10 +1685,10 @@ namespace smt { } void theory_pb::reset_coeffs() { - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - m_coeffs[m_active_coeffs[i]] = 0; + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + m_coeffs[m_active_vars[i]] = 0; } - m_active_coeffs.reset(); + m_active_vars.reset(); } void theory_pb::process_antecedent(literal l, int offset) { @@ -1678,25 +1706,25 @@ namespace smt { void theory_pb::process_card(card& c, int offset) { context& ctx = get_context(); - inc_coeff(c.lit(0), offset); - for (unsigned i = c.k() + 1; i < c.size(); ++i) { + SASSERT(c.k() <= c.size()); + SASSERT(ctx.get_assignment(c.lit()) == l_true); + for (unsigned i = c.k(); i < c.size(); ++i) { process_antecedent(c.lit(i), offset); } - for (unsigned i = 1; i <= c.k(); ++i) { + for (unsigned i = 0; i < c.k(); ++i) { inc_coeff(c.lit(i), offset); } if (ctx.get_assign_level(c.lit()) > ctx.get_base_level()) { m_antecedents.push_back(c.lit()); } - SASSERT(ctx.get_assignment(c.lit()) == l_true); } bool theory_pb::validate_lemma() { int value = -m_bound; context& ctx = get_context(); normalize_active_coeffs(); - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; int coeff = get_coeff(v); SASSERT(coeff != 0); if (coeff < 0 && ctx.get_assignment(v) != l_true) { @@ -1705,53 +1733,103 @@ namespace smt { else if (coeff > 0 && ctx.get_assignment(v) != l_false) { value += coeff; } - else if (coeff == 0) { - UNREACHABLE(); - } } - // std::cout << "bound: " << m_bound << " value " << value << " coeffs: " << m_active_coeffs.size() << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; + // std::cout << "bound: " << m_bound << " value " << value << " coeffs: " << m_active_vars.size() << " lemma is " << (value >= 0 ? "sat" : "unsat") << "\n"; return value < 0; } - int theory_pb::arg_max(uint_set& seen, int& max_coeff) { + int theory_pb::arg_max(int& max_coeff) { max_coeff = 0; int arg_max = -1; - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; - if (seen.contains(v)) { - continue; - } - int coeff = get_abs_coeff(v); - if (coeff > 0 && (max_coeff == 0 || max_coeff < coeff)) { - arg_max = v; - max_coeff = coeff; + while (!m_active_coeffs.empty()) { + max_coeff = m_active_coeffs.back(); + if (m_coeff2args[max_coeff].empty()) { + m_active_coeffs.pop_back(); } - } + else { + arg_max = m_coeff2args[max_coeff].back(); + m_coeff2args[max_coeff].pop_back(); + break; + } + } return arg_max; } - literal theory_pb::cardinality_reduction(literal prop_lit) { + literal theory_pb::get_asserting_literal(literal p) { + if (get_abs_coeff(p.var()) != 0) { + return p; + } + context& ctx = get_context(); + unsigned lvl = 0; + + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + literal lit(v, get_coeff(v) < 0); + if (ctx.get_assignment(lit) == l_false && ctx.get_assign_level(lit) > lvl) { + p = lit; + } + } + + return p; + } + + void theory_pb::reset_arg_max() { + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + int coeff = get_abs_coeff(m_active_vars[i]); + if (static_cast(m_coeff2args.size()) > coeff) { + m_coeff2args[coeff].reset(); + } + } + } + + bool theory_pb::init_arg_max() { + if (m_coeff2args.size() < (1 << 10)) { + m_coeff2args.resize(1 << 10); + } + m_active_coeffs.reset(); + if (m_active_vars.empty()) { + return false; + } + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + int coeff = get_abs_coeff(v); + if (coeff >= static_cast(m_coeff2args.size())) { + reset_arg_max(); + return false; + } + if (m_coeff2args[coeff].empty()) { + m_active_coeffs.push_back(coeff); + } + m_coeff2args[coeff].push_back(v); + } + std::sort(m_active_coeffs.begin(), m_active_coeffs.end()); + for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { + std::cout << m_active_coeffs[i] << " "; + } + std::cout << "\n"; + return true; + } + + void theory_pb::add_cardinality_lemma() { + context& ctx = get_context(); normalize_active_coeffs(); SASSERT(m_seen.empty()); - SASSERT(m_seen_trail.empty()); int s = 0; int new_bound = 0; + if (!init_arg_max()) { + return; + } while (s < m_bound) { int coeff; - int arg = arg_max(m_seen, coeff); + int arg = arg_max(coeff); if (arg == -1) break; s += coeff; ++new_bound; - m_seen.insert(arg); - m_seen_trail.push_back(arg); } - for (unsigned i = 0; i < m_seen_trail.size(); ++i) { - m_seen.remove(m_seen_trail[i]); - } - m_seen_trail.reset(); + reset_arg_max(); int slack = m_bound; - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - int coeff = get_abs_coeff(m_active_coeffs[i]); + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + int coeff = get_abs_coeff(m_active_vars[i]); slack = std::min(slack, coeff - 1); } @@ -1759,8 +1837,8 @@ namespace smt { bool found = false; int v = 0; int coeff = 0; - for (unsigned i = 0; !found && i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; + for (unsigned i = 0; !found && i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; coeff = get_abs_coeff(v); if (0 < coeff && coeff < slack) { found = true; @@ -1772,8 +1850,8 @@ namespace smt { slack -= coeff; m_coeffs[v] = 0; // deactivate coefficient. } - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; int coeff = get_coeff(v); if (coeff < 0) { m_coeffs[v] = -1; @@ -1784,54 +1862,51 @@ namespace smt { } m_bound = new_bound; - if (validate_lemma()) { - SASSERT(m_bound > 0); - if (m_bound > static_cast(m_active_coeffs.size())) { - return false_literal; - } - if (m_bound == m_active_coeffs.size()) { - prop_lit = null_literal; - context& ctx = get_context(); - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; - literal lit(get_coeff(v) < 0); - unsigned lvl = UINT_MAX; - if (ctx.get_assignment(lit) == l_false && ctx.get_assign_level(lit) < lvl) { - prop_lit = lit; - lvl = ctx.get_assign_level(lit); - } - } - SASSERT(prop_lit != null_literal); - } - else { - m_card_reinit = true; - return prop_lit; - } + if (!validate_lemma()) { + return; } - else { - TRACE("pb", display_resolved_lemma(tout);); + SASSERT(m_bound > 0); + if (m_bound > static_cast(m_active_vars.size())) { + return; + } + if (m_bound == m_active_vars.size()) { + return; } - return null_literal; + m_antecedent_exprs.reset(); + m_antecedent_signs.reset(); + m_cardinality_exprs.reset(); + m_cardinality_signs.reset(); + for (unsigned i = 0; i < m_antecedents.size(); ++i) { + literal lit = m_antecedents[i]; + m_antecedent_exprs.push_back(ctx.bool_var2expr(lit.var())); + m_antecedent_signs.push_back(lit.sign()); + } + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + m_cardinality_exprs.push_back(ctx.bool_var2expr(v)); + m_cardinality_signs.push_back(get_coeff(v) < 0); + } + m_cardinality_lemma = true; } void theory_pb::normalize_active_coeffs() { SASSERT(m_seen.empty()); - unsigned i = 0, j = 0, sz = m_active_coeffs.size(); + unsigned i = 0, j = 0, sz = m_active_vars.size(); for (; i < sz; ++i) { - bool_var v = m_active_coeffs[i]; + bool_var v = m_active_vars[i]; if (!m_seen.contains(v) && get_coeff(v) != 0) { m_seen.insert(v); if (j != i) { - m_active_coeffs[j] = m_active_coeffs[i]; + m_active_vars[j] = m_active_vars[i]; } ++j; } } sz = j; - m_active_coeffs.shrink(sz); + m_active_vars.shrink(sz); for (i = 0; i < sz; ++i) { - m_seen.remove(m_active_coeffs[i]); + m_seen.remove(m_active_vars[i]); } SASSERT(m_seen.empty()); } @@ -1845,7 +1920,7 @@ namespace smt { } int coeff0 = m_coeffs[v]; if (coeff0 == 0) { - m_active_coeffs.push_back(v); + m_active_vars.push_back(v); } int inc = l.sign() ? -offset : offset; @@ -1865,8 +1940,8 @@ namespace smt { */ void theory_pb::cut() { unsigned g = 0; - for (unsigned i = 0; g != 1 && i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; + for (unsigned i = 0; g != 1 && i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; int coeff = get_abs_coeff(v); if (coeff == 0) { continue; @@ -1890,8 +1965,8 @@ namespace smt { } if (g >= 2) { normalize_active_coeffs(); - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - m_coeffs[m_active_coeffs[i]] /= g; + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + m_coeffs[m_active_vars[i]] /= g; } m_bound /= g; std::cout << "CUT " << g << "\n"; @@ -1899,48 +1974,48 @@ namespace smt { } } - bool theory_pb::can_propagate() { return m_card_reinit; } + bool theory_pb::can_propagate() { return m_cardinality_lemma; } void theory_pb::propagate() { context& ctx = get_context(); ast_manager& m = get_manager(); - if (ctx.inconsistent() || !m_card_reinit) { + if (!m_cardinality_lemma) { return; } - m_card_reinit = false; + m_cardinality_lemma = false; + if (ctx.inconsistent()) { + return; + } + m_antecedents.reset(); - if (!validate_antecedents(m_antecedents)) { - return; + for (unsigned i = 0; i < m_antecedent_exprs.size(); ++i) { + expr* a = m_antecedent_exprs[i].get(); + if (!ctx.b_internalized(a)) { + std::cout << "not internalized " << mk_pp(a, m) << "\n"; + return; + } + m_antecedents.push_back(~literal(ctx.get_bool_var(a), m_antecedent_signs[i])); } + for (unsigned i = 0; i < m_cardinality_exprs.size(); ++i) { + expr* a = m_cardinality_exprs[i].get(); + if (!ctx.b_internalized(a)) { + std::cout << "not internalized " << mk_pp(a, m) << "\n"; + return; + } + if (m_cardinality_signs[i]) { + m_cardinality_exprs[i] = m.mk_not(a); + } + } pb_util pb(m); - expr_ref pred(pb.mk_fresh_bool(), m); - bool_var abv = ctx.mk_bool_var(pred); - ctx.set_var_theory(abv, get_id()); - literal lit(abv); - // std::cout << "fresh " << pred << " " << lit << "\n"; - - card* c = alloc(card, lit, m_bound); - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; - int coeff = get_coeff(v); - SASSERT(coeff != 0); - c->add_arg(literal(v, coeff < 0)); - } - - init_watch(abv); - m_var_infos[abv].m_card = c; - m_card_trail.push_back(abv); - for (unsigned i = 0; i < m_antecedents.size(); ++i) { - m_antecedents[i].neg(); - } - m_antecedents.push_back(lit); - TRACE("pb", tout << m_antecedents << "\n";); + app_ref atl(pb.mk_at_least_k(m_cardinality_exprs.size(), m_cardinality_exprs.c_ptr(), m_bound), m); + VERIFY(internalize_card(atl, false)); + bool_var abv = ctx.get_bool_var(atl); + m_antecedents.push_back(literal(abv)); justification* js = 0; if (proofs_enabled()) { js = 0; // } - ++m_stats.m_num_predicates; ctx.mk_clause(m_antecedents.size(), m_antecedents.c_ptr(), js, CLS_AUX_LEMMA, 0); } @@ -1951,7 +2026,7 @@ namespace smt { bool_var v; context& ctx = get_context(); m_conflict_lvl = 0; - m_card_reinit = false; + m_cardinality_lemma = false; for (unsigned i = 0; i < confl.size(); ++i) { literal lit = confl[i]; SASSERT(ctx.get_assignment(lit) == l_false); @@ -2100,35 +2175,29 @@ namespace smt { normalize_active_coeffs(); - int count = 0, sz = 0; - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; - int coeff = get_abs_coeff(v); - SASSERT(coeff > 0); - ++sz; - count += coeff; - } - // std::cout << "New " << count << "(" << sz << ") >= " << m_bound << " " << c.size() << " >= " << c.k() << " new diff: " << count - m_bound << " old diff: " << c.size() - c.k() << "\n"; - literal prop_lit = cardinality_reduction(~conseq); - if (prop_lit != null_literal) { - TRACE("pb", tout << "cardinality literal: " << prop_lit << "\n";); - SASSERT(static_cast(m_active_coeffs.size()) >= m_bound); - unsigned slack = m_active_coeffs.size() - m_bound; - for (unsigned i = 0; i < slack; ++i) { - bool_var v = m_active_coeffs[i]; - literal lit(v, get_coeff(v) < 0); - SASSERT(lit.var() != prop_lit.var() || lit == prop_lit); - if (lit != prop_lit && ctx.get_assignment(lit) == l_false) { - m_antecedents.push_back(~lit); - --slack; - } + literal alit = get_asserting_literal(~conseq); + int slack = -m_bound; + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + slack += get_abs_coeff(v); + } + slack -= get_abs_coeff(alit.var()); + + for (unsigned i = 0; 0 <= slack; ++i) { + SASSERT(i < m_active_vars.size()); + bool_var v = m_active_vars[i]; + literal lit(v, get_coeff(v) < 0); + if (v != alit.var() && ctx.get_assignment(lit) == l_false) { + m_antecedents.push_back(~lit); + slack -= get_abs_coeff(v); } - SASSERT(validate_antecedents(m_antecedents)); - ctx.assign(prop_lit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), prop_lit, 0, 0))); } + SASSERT(validate_antecedents(m_antecedents)); + ctx.assign(alit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), alit, 0, 0))); - return prop_lit != null_literal; + add_cardinality_lemma(); + return true; } bool theory_pb::is_proof_justification(justification const& j) const { @@ -2243,6 +2312,14 @@ namespace smt { return true; } + bool theory_pb::validate_unit_propagation(card const& c) { + context& ctx = get_context(); + for (unsigned i = c.k(); i < c.size(); ++i) { + SASSERT(ctx.get_assignment(c.lit(i)) == l_false); + } + return true; + } + void theory_pb::negate(literal_vector & lits) { for (unsigned i = 0; i < lits.size(); ++i) { lits[i].neg(); @@ -2270,8 +2347,8 @@ namespace smt { } uint_set seen; bool first = true; - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - bool_var v = m_active_coeffs[i]; + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; if (seen.contains(v)) { continue; } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index ab83160ce..36fb3a256 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -185,6 +185,14 @@ namespace smt { }; // cardinality constraint args >= bound + // unit propagation on cardinality constraints is valid if the literals + // from k() up to size are false. + // In this case the literals 0..k()-1 need to be true. + // The literals in position 0..k() are watched. + // whenever they are assigned to false, then find a literal among + // k() + 1.. sz() to swap with. + // If none are available, then perform unit propagation. + // class card { literal m_lit; // literal repesenting predicate literal_vector m_args; @@ -293,7 +301,7 @@ namespace smt { bool m_enable_compilation; rational m_max_compiled_coeff; - bool m_card_reinit; + bool m_cardinality_lemma; // internalize_atom: literal compile_arg(expr* arg); @@ -326,6 +334,7 @@ namespace smt { bool is_cardinality_constraint(app * atom); bool internalize_card(app * atom, bool gate_ctx); void card2conjunction(card const& c); + void card2disjunction(card const& c); void watch_literal(literal lit, card* c); void unwatch_literal(literal w, card* c); @@ -370,20 +379,31 @@ namespace smt { // Conflict PB constraints svector m_coeffs; - svector m_active_coeffs; + svector m_active_vars; int m_bound; literal_vector m_antecedents; uint_set m_seen; - unsigned_vector m_seen_trail; + expr_ref_vector m_antecedent_exprs; + svector m_antecedent_signs; + expr_ref_vector m_cardinality_exprs; + svector m_cardinality_signs; void normalize_active_coeffs(); void inc_coeff(literal l, int offset); int get_coeff(bool_var v) const; int get_abs_coeff(bool_var v) const; - int arg_max(uint_set& seen, int& coeff); + int arg_max(int& coeff); + + literal_vector& get_literals() { m_literals.reset(); return m_literals; } + + vector > m_coeff2args; + unsigned_vector m_active_coeffs; + bool init_arg_max(); + void reset_arg_max(); void reset_coeffs(); - literal cardinality_reduction(literal propagation_lit); + void add_cardinality_lemma(); + literal get_asserting_literal(literal conseq); bool resolve_conflict(card& c, literal_vector const& conflict_clause); void process_antecedent(literal l, int offset); @@ -399,6 +419,7 @@ namespace smt { void validate_final_check(ineq& c); void validate_assign(ineq const& c, literal_vector const& lits, literal l) const; void validate_watch(ineq const& c) const; + bool validate_unit_propagation(card const& c); bool validate_antecedents(literal_vector const& lits); void negate(literal_vector & lits); From 49d7fd4f9c823f48c3d43325e2652f87b6d00dc9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Jan 2017 09:27:57 -0800 Subject: [PATCH 0011/1283] updates Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 9 ++ src/smt/smt_context.h | 11 ++- src/smt/theory_pb.cpp | 213 +++++++++++++++++++++++++--------------- src/smt/theory_pb.h | 26 +++-- 4 files changed, 174 insertions(+), 85 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 5853f8fd1..0116146d8 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1985,6 +1985,15 @@ namespace smt { m_watches[(~cls->get_literal(idx)).index()].remove_clause(cls); } + /** + \brief Remove boolean variable from watch lists. + */ + void context::remove_watch(bool_var v) { + literal lit(v); + m_watches[lit.index()].reset(); + m_watches[(~lit).index()].reset(); + } + /** \brief Update the index used for backward subsumption. */ diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index b9b068442..84547de19 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -302,6 +302,7 @@ namespace smt { } #endif + clause_vector const& get_lemmas() const { return m_lemmas; } literal get_literal(expr * n) const; @@ -604,8 +605,6 @@ namespace smt { void remove_cls_occs(clause * cls); - void mark_as_deleted(clause * cls); - void del_clause(clause * cls); void del_clauses(clause_vector & v, unsigned old_size); @@ -630,6 +629,14 @@ namespace smt { void reassert_units(unsigned units_to_reassert_lim); + public: + // \brief exposed for PB solver to participate in GC + + void remove_watch(bool_var v); + + void mark_as_deleted(clause * cls); + + // ----------------------------------- // // Internalization diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 10f869677..768816925 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -289,31 +289,12 @@ namespace smt { std::swap(m_args[index], m_args[bound]); } SASSERT(th.validate_unit_propagation(*this)); - literal_vector& lits = th.get_literals(); - lits.push_back(m_lit); - for (unsigned i = bound; i < sz; ++i) { - SASSERT(ctx.get_assignment(lit(i)) == l_false); - lits.push_back(~lit(i)); - } - for (unsigned i = 0; i < bound; ++i) { - literal lit2 = lit(i); - lbool value = ctx.get_assignment(lit2); - switch (value) { - case l_true: - break; - case l_false: - TRACE("pb", tout << "conflict: " << alit << " " << lit2 << "\n";); - set_conflict(th, lit2); - return l_false; - case l_undef: - SASSERT(validate_assign(th, lits, lit2)); - th.add_assign(*this, lits, lit2); - break; - } + for (unsigned i = 0; i < bound && !ctx.inconsistent(); ++i) { + th.add_assign(*this, lit(i)); } - return l_true; + return ctx.inconsistent() ? l_false : l_true; } /** @@ -369,10 +350,8 @@ namespace smt { SASSERT(ctx.get_assignment(lit()) == l_true); unsigned j = 0, sz = size(), bound = k(); if (bound == sz) { - literal_vector& lits = th.get_literals(); - lits.push_back(lit()); for (unsigned i = 0; i < sz && !ctx.inconsistent(); ++i) { - th.add_assign(*this, lits, lit(i)); + th.add_assign(*this, lit(i)); } return; } @@ -412,11 +391,8 @@ namespace smt { set_conflict(th, alit); } else if (j == bound) { - literal_vector lits(sz - bound, m_args.c_ptr() + bound); - th.negate(lits); - lits.push_back(lit()); for (unsigned i = 0; i < bound && !ctx.inconsistent(); ++i) { - th.add_assign(*this, lits, lit(i)); + th.add_assign(*this, lit(i)); } } else { @@ -457,9 +433,11 @@ namespace smt { theory(m.mk_family_id("pb")), m_params(p), m_simplex(m.limit()), - m_util(m), + pb(m), m_max_compiled_coeff(rational(8)), m_cardinality_lemma(false), + m_restart_lim(3), + m_restart_inc(0), m_antecedent_exprs(m), m_cardinality_exprs(m) { @@ -485,7 +463,7 @@ namespace smt { SASSERT(!ctx.b_internalized(atom)); m_stats.m_num_predicates++; - if (m_util.is_aux_bool(atom)) { + if (pb.is_aux_bool(atom)) { bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); std::cout << "aux bool " << ctx.get_scope_level() << " " << mk_pp(atom, get_manager()) << " " << literal(abv) << "\n"; @@ -496,17 +474,17 @@ namespace smt { return true; } - SASSERT(m_util.is_at_most_k(atom) || m_util.is_le(atom) || - m_util.is_ge(atom) || m_util.is_at_least_k(atom) || - m_util.is_eq(atom)); + SASSERT(pb.is_at_most_k(atom) || pb.is_le(atom) || + pb.is_ge(atom) || pb.is_at_least_k(atom) || + pb.is_eq(atom)); unsigned num_args = atom->get_num_args(); bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); - ineq* c = alloc(ineq, m_mpz_mgr, literal(abv), m_util.is_eq(atom)); - c->m_args[0].m_k = m_util.get_k(atom); + ineq* c = alloc(ineq, m_mpz_mgr, literal(abv), pb.is_eq(atom)); + c->m_args[0].m_k = pb.get_k(atom); numeral& k = c->m_args[0].m_k; arg_t& args = c->m_args[0]; @@ -514,10 +492,10 @@ namespace smt { for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); literal l = compile_arg(arg); - numeral c = m_util.get_coeff(atom, i); + numeral c = pb.get_coeff(atom, i); args.push_back(std::make_pair(l, c)); } - if (m_util.is_at_most_k(atom) || m_util.is_le(atom)) { + if (pb.is_at_most_k(atom) || pb.is_le(atom)) { // turn W <= k into -W >= -k for (unsigned i = 0; i < args.size(); ++i) { args[i].second = -args[i].second; @@ -525,7 +503,7 @@ namespace smt { k = -k; } else { - SASSERT(m_util.is_at_least_k(atom) || m_util.is_ge(atom) || m_util.is_eq(atom)); + SASSERT(pb.is_at_least_k(atom) || pb.is_ge(atom) || pb.is_eq(atom)); } TRACE("pb", display(tout, *c);); //app_ref fml1(m), fml2(m); @@ -640,7 +618,6 @@ namespace smt { // is available. if (!has_bv) { app_ref tmp(m), fml(m); - pb_util pb(m); tmp = pb.mk_fresh_bool(); fml = m.mk_iff(tmp, arg); TRACE("pb", tout << "create proxy " << fml << "\n";); @@ -754,23 +731,38 @@ namespace smt { // ---------------------------- // cardinality constraints - class theory_pb::card_justification : public theory_propagation_justification { + + class theory_pb::card_justification : public justification { card& m_card; + family_id m_fid; public: - card_justification(card& c, family_id fid, region & r, - unsigned num_lits, literal const * lits, literal consequent): - theory_propagation_justification(fid, r, num_lits, lits, consequent), - m_card(c) - {} + card_justification(card& c, family_id fid) + : justification(true), m_card(c), m_fid(fid) {} + card& get_card() { return m_card; } + + virtual void get_antecedents(conflict_resolution& cr) { + cr.mark_literal(m_card.lit()); + for (unsigned i = m_card.k(); i < m_card.size(); ++i) { + cr.mark_literal(~m_card.lit(i)); + } + } + + virtual theory_id get_from_theory() const { + return m_fid; + } + + virtual proof* mk_proof(smt::conflict_resolution& cr) { return 0; } + + }; bool theory_pb::is_cardinality_constraint(app * atom) { - if (m_util.is_ge(atom) && m_util.has_unit_coefficients(atom)) { + if (pb.is_ge(atom) && pb.has_unit_coefficients(atom)) { return true; } - if (m_util.is_at_least_k(atom)) { + if (pb.is_at_least_k(atom)) { return true; } // TBD: other conditions @@ -789,7 +781,7 @@ namespace smt { unsigned num_args = atom->get_num_args(); bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); - unsigned bound = m_util.get_k(atom).get_unsigned(); + unsigned bound = pb.get_k(atom).get_unsigned(); literal lit(abv); if (bound == 0) { @@ -801,8 +793,11 @@ namespace smt { ctx.mk_th_axiom(get_id(), 1, &lit); return true; } + + // hack to differentiate constraints that come from input vs. lemmas. + bool aux = pb.is_at_least_k(atom); - card* c = alloc(card, lit, bound); + card* c = alloc(card, lit, bound, aux); for (unsigned i = 0; i < num_args; ++i) { expr* arg = atom->get_arg(i); @@ -923,7 +918,7 @@ namespace smt { } } out << " >= " << c.k() << "\n"; - if (c.num_propagations()) out << "propagations: " << c.num_propagations() << "\n"; + if (c.all_propagations()) out << "propagations: " << c.all_propagations() << "\n"; return out; } @@ -942,19 +937,16 @@ namespace smt { SASSERT(ctx.inconsistent()); } - void theory_pb::add_assign(card& c, literal_vector const& lits, literal l) { + void theory_pb::add_assign(card& c, literal l) { context& ctx = get_context(); if (ctx.get_assignment(l) == l_true) { return; } c.inc_propagations(*this); m_stats.m_num_propagations++; - TRACE("pb", tout << "#prop: " << c.num_propagations() << " - " << lits << " " << c.lit() << " => " << l << "\n";); - SASSERT(validate_antecedents(lits)); + TRACE("pb", tout << "#prop: " << c.num_propagations() << " - " << c.lit() << " => " << l << "\n";); SASSERT(validate_unit_propagation(c)); - ctx.assign(l, ctx.mk_justification( - card_justification( - c, get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), l))); + ctx.assign(l, ctx.mk_justification(card_justification(c, get_id()))); } void theory_pb::clear_watch(card& c) { @@ -1459,6 +1451,83 @@ namespace smt { compile_ineq(*m_to_compile[i]); } m_to_compile.reset(); + + return; + + if (m_restart_lim <= m_restart_inc) { + m_restart_inc = 0; + if (gc()) { + m_restart_lim = 3; + } + else { + m_restart_lim *= 4; + m_restart_lim /= 3; + } + } + ++m_restart_inc; + } + + bool theory_pb::gc() { + + context& ctx = get_context(); + + unsigned z = 0, nz = 0; + m_occs.reset(); + for (unsigned i = 0; i < m_card_trail.size(); ++i) { + bool_var v = m_card_trail[i]; + if (v == null_bool_var) continue; + card* c = m_var_infos[v].m_card; + if (c) { + unsigned np = c->num_propagations(); + c->reset_propagations(); + literal lit = c->lit(); + if (c->is_aux() && ctx.get_assign_level(lit) > ctx.get_search_level()) { + double activity = ctx.get_activity(v); + // std::cout << "activity: " << ctx.get_activity(v) << " " << np << "\n"; + if (activity <= 0) { + nz++; + } + else { + z++; + clear_watch(*c); + m_var_infos[v].m_card = 0; + dealloc(c); + m_card_trail[i] = null_bool_var; + ctx.remove_watch(v); + // TBD: maybe v was used in a clause for propagation. + m_occs.insert(v); + } + } + } + } + clause_vector const& lemmas = ctx.get_lemmas(); + for (unsigned i = 0; i < lemmas.size(); ++i) { + clause* cl = lemmas[i]; + if (!cl->deleted()) { + unsigned sz = cl->get_num_literals(); + for (unsigned j = 0; j < sz; ++j) { + literal lit = cl->get_literal(j); + if (m_occs.contains(lit.var())) { + //std::cout << "deleting clause " << lit << " " << sz << "\n"; + //ctx.mark_as_deleted(cl); + break; + } + } + } + } + + std::cout << "zs: " << z << " nzs: " << nz << " lemmas: " << ctx.get_lemmas().size() << " trail: " << m_card_trail.size() << "\n"; + return z*10 >= nz; + + m_occs.reset(); + for (unsigned i = 0; i < lemmas.size(); ++i) { + clause* cl = lemmas[i]; + unsigned sz = cl->get_num_literals(); + for (unsigned j = 0; j < sz; ++j) { + unsigned idx = cl->get_literal(j).index(); + m_occs.insert(idx); + } + } } @@ -1562,10 +1631,12 @@ namespace smt { while (m_card_trail.size() > sz) { bool_var v = m_card_trail.back(); m_card_trail.pop_back(); - card* c = m_var_infos[v].m_card; - clear_watch(*c); - m_var_infos[v].m_card = 0; - dealloc(c); + if (v != null_bool_var) { + card* c = m_var_infos[v].m_card; + clear_watch(*c); + m_var_infos[v].m_card = 0; + dealloc(c); + } } m_card_lim.resize(new_lim); @@ -1803,22 +1874,18 @@ namespace smt { m_coeff2args[coeff].push_back(v); } std::sort(m_active_coeffs.begin(), m_active_coeffs.end()); - for (unsigned i = 0; i < m_active_coeffs.size(); ++i) { - std::cout << m_active_coeffs[i] << " "; - } - std::cout << "\n"; return true; } void theory_pb::add_cardinality_lemma() { context& ctx = get_context(); normalize_active_coeffs(); - SASSERT(m_seen.empty()); int s = 0; int new_bound = 0; if (!init_arg_max()) { return; } + // TBD: can be optimized while (s < m_bound) { int coeff; int arg = arg_max(coeff); @@ -1826,12 +1893,8 @@ namespace smt { s += coeff; ++new_bound; } + int slack = m_active_coeffs.empty() ? m_bound : (std::min(m_bound, static_cast(m_active_coeffs[0]) - 1)); reset_arg_max(); - int slack = m_bound; - for (unsigned i = 0; i < m_active_vars.size(); ++i) { - int coeff = get_abs_coeff(m_active_vars[i]); - slack = std::min(slack, coeff - 1); - } while (slack > 0) { bool found = false; @@ -2007,7 +2070,6 @@ namespace smt { m_cardinality_exprs[i] = m.mk_not(a); } } - pb_util pb(m); app_ref atl(pb.mk_at_least_k(m_cardinality_exprs.size(), m_cardinality_exprs.c_ptr(), m_bound), m); VERIFY(internalize_card(atl, false)); bool_var abv = ctx.get_bool_var(atl); @@ -2138,9 +2200,6 @@ namespace smt { else { card& c2 = pbj->get_card(); process_card(c2, offset); - unsigned i = 0; - for (i = 0; i < c2.size() && c2.lit(i) != conseq; ++i) {} - // std::cout << c2.lit() << " index at " << i << " of " << c2.size(); bound = c2.k(); } @@ -2185,7 +2244,7 @@ namespace smt { slack -= get_abs_coeff(alit.var()); for (unsigned i = 0; 0 <= slack; ++i) { - SASSERT(i < m_active_vars.size()); + SASSERT(i < m_active_vars.size()); bool_var v = m_active_vars[i]; literal lit(v, get_coeff(v) < 0); if (v != alit.var() && ctx.get_assignment(lit) == l_false) { @@ -2196,7 +2255,7 @@ namespace smt { SASSERT(validate_antecedents(m_antecedents)); ctx.assign(alit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), alit, 0, 0))); - add_cardinality_lemma(); + // add_cardinality_lemma(); return true; } diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 36fb3a256..e48816c1c 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -198,16 +198,20 @@ namespace smt { literal_vector m_args; unsigned m_bound; unsigned m_num_propagations; + unsigned m_all_propagations; unsigned m_compilation_threshold; lbool m_compiled; + bool m_aux; public: - card(literal l, unsigned bound): + card(literal l, unsigned bound, bool is_aux): m_lit(l), m_bound(bound), m_num_propagations(0), + m_all_propagations(0), m_compilation_threshold(0), - m_compiled(l_false) + m_compiled(l_false), + m_aux(is_aux) { SASSERT(bound > 0); } @@ -216,6 +220,7 @@ namespace smt { literal lit(unsigned i) const { return m_args[i]; } unsigned k() const { return m_bound; } unsigned size() const { return m_args.size(); } + unsigned all_propagations() const { return m_all_propagations; } unsigned num_propagations() const { return m_num_propagations; } void add_arg(literal l); @@ -228,6 +233,11 @@ namespace smt { app_ref to_expr(context& ctx); void inc_propagations(theory_pb& th); + + void reset_propagations() { m_all_propagations += m_num_propagations; m_num_propagations = 0; } + + bool is_aux() const { return m_aux; } + private: bool validate_conflict(theory_pb& th); @@ -293,7 +303,7 @@ namespace smt { unsigned_vector m_ineqs_trail; unsigned_vector m_ineqs_lim; literal_vector m_literals; // temporary vector - pb_util m_util; + pb_util pb; stats m_stats; ptr_vector m_to_compile; // inequalities to compile. unsigned m_conflict_frequency; @@ -302,6 +312,9 @@ namespace smt { rational m_max_compiled_coeff; bool m_cardinality_lemma; + unsigned m_restart_lim; + unsigned m_restart_inc; + uint_set m_occs; // internalize_atom: literal compile_arg(expr* arg); @@ -330,7 +343,7 @@ namespace smt { // be handled using cardinality constraints. unsigned_vector m_card_trail; - unsigned_vector m_card_lim; + unsigned_vector m_card_lim; bool is_cardinality_constraint(app * atom); bool internalize_card(app * atom, bool gate_ctx); void card2conjunction(card const& c); @@ -339,9 +352,10 @@ namespace smt { void watch_literal(literal lit, card* c); void unwatch_literal(literal w, card* c); void add_clause(card& c, literal_vector const& lits); - void add_assign(card& c, literal_vector const& lits, literal l); + void add_assign(card& c, literal l); void remove(ptr_vector& cards, card* c); - void clear_watch(card& c); + void clear_watch(card& c); + bool gc(); std::ostream& display(std::ostream& out, card const& c, bool values = false) const; From 0123b63f8a429d5e16060a67ff78cc6a93a515b9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Jan 2017 16:12:46 -0800 Subject: [PATCH 0012/1283] experimenting with cardinalities Signed-off-by: Nikolaj Bjorner --- src/sat/sat_types.h | 75 +----------------- src/smt/theory_pb.cpp | 172 ++++++++++++++++++++++++++++++++++++++---- src/smt/theory_pb.h | 22 +++--- src/util/uint_set.h | 80 +++++++++++++++++++- 4 files changed, 246 insertions(+), 103 deletions(-) diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 28d8d761a..44d3383fb 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -25,6 +25,7 @@ Revision History: #include"z3_exception.h" #include"common_msgs.h" #include"vector.h" +#include"uint_set.h" #include namespace sat { @@ -150,79 +151,7 @@ namespace sat { return out; } - class uint_set { - svector m_in_set; - svector m_set; - public: - typedef svector::const_iterator iterator; - void insert(unsigned v) { - m_in_set.reserve(v+1, false); - if (m_in_set[v]) - return; - m_in_set[v] = true; - m_set.push_back(v); - } - - void remove(unsigned v) { - if (contains(v)) { - m_in_set[v] = false; - unsigned i = 0; - for (i = 0; i < m_set.size() && m_set[i] != v; ++i) - ; - SASSERT(i < m_set.size()); - m_set[i] = m_set.back(); - m_set.pop_back(); - } - } - - uint_set& operator=(uint_set const& other) { - m_in_set = other.m_in_set; - m_set = other.m_set; - return *this; - } - - bool contains(unsigned v) const { - return v < m_in_set.size() && m_in_set[v] != 0; - } - - bool empty() const { - return m_set.empty(); - } - - // erase some variable from the set - unsigned erase() { - SASSERT(!empty()); - unsigned v = m_set.back(); - m_set.pop_back(); - m_in_set[v] = false; - return v; - } - unsigned size() const { return m_set.size(); } - iterator begin() const { return m_set.begin(); } - iterator end() const { return m_set.end(); } - void reset() { m_set.reset(); m_in_set.reset(); } - void finalize() { m_set.finalize(); m_in_set.finalize(); } - uint_set& operator&=(uint_set const& other) { - unsigned j = 0; - for (unsigned i = 0; i < m_set.size(); ++i) { - if (other.contains(m_set[i])) { - m_set[j] = m_set[i]; - ++j; - } - else { - m_in_set[m_set[i]] = false; - } - } - m_set.resize(j); - return *this; - } - uint_set& operator|=(uint_set const& other) { - for (unsigned i = 0; i < other.m_set.size(); ++i) { - insert(other.m_set[i]); - } - return *this; - } - }; + typedef tracked_uint_set uint_set; typedef uint_set bool_var_set; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 768816925..445780360 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -26,10 +26,8 @@ Notes: #include "uint_set.h" #include "smt_model_generator.h" #include "pb_rewriter_def.h" -#include "sparse_matrix_def.h" -#include "simplex_def.h" #include "mpz.h" - +#include "smt_kernel.h" namespace smt { @@ -239,6 +237,15 @@ namespace smt { SASSERT(sz >= m_bound && m_bound > 0); } + app_ref theory_pb::card::to_expr(theory_pb& th) { + ast_manager& m = th.get_manager(); + expr_ref_vector args(m); + for (unsigned i = 0; i < size(); ++i) { + args.push_back(th.literal2expr(m_args[i])); + } + return app_ref(th.pb.mk_at_least_k(args.size(), args.c_ptr(), k()), m); + } + lbool theory_pb::card::assign(theory_pb& th, literal alit) { // literal is assigned to false. context& ctx = th.get_context(); @@ -432,7 +439,6 @@ namespace smt { theory_pb::theory_pb(ast_manager& m, theory_pb_params& p): theory(m.mk_family_id("pb")), m_params(p), - m_simplex(m.limit()), pb(m), m_max_compiled_coeff(rational(8)), m_cardinality_lemma(false), @@ -1809,6 +1815,69 @@ namespace smt { return value < 0; } + bool theory_pb::validate_implies(app_ref& A, app_ref& B) { + static bool validating = false; + if (validating) return true; + validating = true; + ast_manager& m = get_manager(); + smt_params fp; + kernel k(m, fp); + k.assert_expr(A); + k.assert_expr(m.mk_not(B)); + lbool is_sat = k.check(); + validating = false; + std::cout << is_sat << "\n"; + if (is_sat != l_false) { + std::cout << A << "\n"; + std::cout << B << "\n"; + } + SASSERT(is_sat == l_false); + return true; + } + + app_ref theory_pb::justification2expr(b_justification& js, literal conseq) { + ast_manager& m = get_manager(); + app_ref result(m.mk_true(), m); + expr_ref_vector args(m); + vector coeffs; + switch(js.get_kind()) { + + case b_justification::CLAUSE: { + clause& cls = *js.get_clause(); + justification* cjs = cls.get_justification(); + if (cjs && !is_proof_justification(*cjs)) { + break; + } + for (unsigned i = 0; i < cls.get_num_literals(); ++i) { + literal lit = cls.get_literal(i); + args.push_back(literal2expr(lit)); + } + result = m.mk_or(args.size(), args.c_ptr()); + break; + } + case b_justification::BIN_CLAUSE: + result = m.mk_or(literal2expr(conseq), literal2expr(~js.get_literal())); + break; + case b_justification::AXIOM: + break; + case b_justification::JUSTIFICATION: { + justification* j = js.get_justification(); + card_justification* pbj = 0; + if (j->get_from_theory() == get_id()) { + pbj = dynamic_cast(j); + } + if (pbj != 0) { + card& c2 = pbj->get_card(); + result = card2expr(c2); + } + break; + } + default: + break; + } + return result; + } + int theory_pb::arg_max(int& max_coeff) { max_coeff = 0; int arg_max = -1; @@ -1954,12 +2023,12 @@ namespace smt { } void theory_pb::normalize_active_coeffs() { - SASSERT(m_seen.empty()); + while (!m_active_var_set.empty()) m_active_var_set.erase(); unsigned i = 0, j = 0, sz = m_active_vars.size(); for (; i < sz; ++i) { bool_var v = m_active_vars[i]; - if (!m_seen.contains(v) && get_coeff(v) != 0) { - m_seen.insert(v); + if (!m_active_var_set.contains(v) && get_coeff(v) != 0) { + m_active_var_set.insert(v); if (j != i) { m_active_vars[j] = m_active_vars[i]; } @@ -1968,10 +2037,6 @@ namespace smt { } sz = j; m_active_vars.shrink(sz); - for (i = 0; i < sz; ++i) { - m_seen.remove(m_active_vars[i]); - } - SASSERT(m_seen.empty()); } void theory_pb::inc_coeff(literal l, int offset) { @@ -2087,6 +2152,7 @@ namespace smt { bool_var v; context& ctx = get_context(); + ast_manager& m = get_manager(); m_conflict_lvl = 0; m_cardinality_lemma = false; for (unsigned i = 0; i < confl.size(); ++i) { @@ -2109,6 +2175,8 @@ namespace smt { process_card(c, 1); + app_ref A(m), B(m), C(m); + DEBUG_CODE(A = c.to_expr(*this);); // point into stack of assigned literals literal_vector const& lits = ctx.assigned_literals(); @@ -2211,6 +2279,15 @@ namespace smt { } m_bound += offset * bound; + DEBUG_CODE( + B = justification2expr(js, conseq); + C = active2expr(); + B = m.mk_and(A, B); + validate_implies(B, C); + A = C;); + + cut(); + process_next_resolvent: // find the next marked variable in the assignment stack @@ -2235,12 +2312,49 @@ namespace smt { normalize_active_coeffs(); - literal alit = get_asserting_literal(~conseq); + if (m_bound > 0 && m_active_vars.empty()) { + return false; + } + int slack = -m_bound; for (unsigned i = 0; i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; slack += get_abs_coeff(v); } + +#if 1 + //std::cout << slack << " " << m_bound << "\n"; + unsigned i = 0; + literal_vector const& alits = ctx.assigned_literals(); + + literal alit = get_asserting_literal(~conseq); + slack -= get_abs_coeff(alit.var()); + + for (i = alits.size(); 0 <= slack && i > 0; ) { + --i; + literal lit = alits[i]; + bool_var v = lit.var(); + // -3*x >= k + if (m_active_var_set.contains(v) && v != alit.var()) { + int coeff = get_coeff(v); + //std::cout << coeff << " " << lit << "\n"; + if (coeff < 0 && !lit.sign()) { + slack += coeff; + m_antecedents.push_back(lit); + //std::cout << "ante: " << lit << "\n"; + } + else if (coeff > 0 && lit.sign()) { + slack -= coeff; + m_antecedents.push_back(lit); + //std::cout << "ante: " << lit << "\n"; + } + } + } + SASSERT(slack < 0); + +#else + + literal alit = get_asserting_literal(~conseq); slack -= get_abs_coeff(alit.var()); for (unsigned i = 0; 0 <= slack; ++i) { @@ -2251,10 +2365,22 @@ namespace smt { m_antecedents.push_back(~lit); slack -= get_abs_coeff(v); } + if (slack < 0) { + std::cout << i << " " << m_active_vars.size() << "\n"; + } } +#endif SASSERT(validate_antecedents(m_antecedents)); ctx.assign(alit, ctx.mk_justification(theory_propagation_justification(get_id(), ctx.get_region(), m_antecedents.size(), m_antecedents.c_ptr(), alit, 0, 0))); + DEBUG_CODE( + m_antecedents.push_back(~alit); + expr_ref_vector args(m); + for (unsigned i = 0; i < m_antecedents.size(); ++i) { + args.push_back(literal2expr(m_antecedents[i])); + } + B = m.mk_not(m.mk_and(args.size(), args.c_ptr())); + validate_implies(A, B); ); // add_cardinality_lemma(); return true; } @@ -2379,10 +2505,26 @@ namespace smt { return true; } - void theory_pb::negate(literal_vector & lits) { - for (unsigned i = 0; i < lits.size(); ++i) { - lits[i].neg(); + app_ref theory_pb::literal2expr(literal lit) { + ast_manager& m = get_manager(); + app_ref arg(m.mk_const(symbol(lit.var()), m.mk_bool_sort()), m); + return app_ref(lit.sign() ? m.mk_not(arg) : arg, m); + } + + app_ref theory_pb::active2expr() { + ast_manager& m = get_manager(); + expr_ref_vector args(m); + vector coeffs; + normalize_active_coeffs(); + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + int coeff = get_coeff(v); + literal lit(v, get_coeff(v) < 0); + args.push_back(literal2expr(lit)); + coeffs.push_back(rational(get_abs_coeff(v))); } + rational k(m_bound); + return app_ref(pb.mk_ge(args.size(), coeffs.c_ptr(), args.c_ptr(), k), m); } // display methods diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index e48816c1c..56f3d1e76 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -24,6 +24,7 @@ Notes: #include "pb_decl_plugin.h" #include "smt_clause.h" #include "theory_pb_params.h" +#include "smt_b_justification.h" #include "simplex.h" namespace smt { @@ -41,9 +42,6 @@ namespace smt { class card_justification; typedef rational numeral; - typedef simplex::simplex simplex; - typedef simplex::row row; - typedef simplex::row_iterator row_iterator; typedef unsynch_mpq_inf_manager eps_manager; typedef _scoped_numeral scoped_eps_numeral; @@ -230,7 +228,7 @@ namespace smt { void negate(); - app_ref to_expr(context& ctx); + app_ref to_expr(theory_pb& th); void inc_propagations(theory_pb& th); @@ -292,12 +290,6 @@ namespace smt { theory_pb_params m_params; svector m_var_infos; - arg_map m_ineq_rep; // Simplex: representative inequality - u_map m_ineq_row_info; // Simplex: row information per variable - uint_set m_vars; // Simplex: 0-1 variables. - simplex m_simplex; // Simplex: tableau - literal_vector m_explain_lower; // Simplex: explanations for lower bounds - literal_vector m_explain_upper; // Simplex: explanations for upper bounds unsynch_mpq_inf_manager m_mpq_inf_mgr; // Simplex: manage inf_mpq numerals mutable unsynch_mpz_manager m_mpz_mgr; // Simplex: manager mpz numerals unsigned_vector m_ineqs_trail; @@ -396,7 +388,7 @@ namespace smt { svector m_active_vars; int m_bound; literal_vector m_antecedents; - uint_set m_seen; + tracked_uint_set m_active_var_set; expr_ref_vector m_antecedent_exprs; svector m_antecedent_signs; expr_ref_vector m_cardinality_exprs; @@ -425,17 +417,21 @@ namespace smt { void cut(); bool is_proof_justification(justification const& j) const; - bool validate_lemma(); void hoist_maximal_values(); + bool validate_lemma(); void validate_final_check(); void validate_final_check(ineq& c); void validate_assign(ineq const& c, literal_vector const& lits, literal l) const; void validate_watch(ineq const& c) const; bool validate_unit_propagation(card const& c); bool validate_antecedents(literal_vector const& lits); - void negate(literal_vector & lits); + bool validate_implies(app_ref& A, app_ref& B); + app_ref active2expr(); + app_ref literal2expr(literal lit); + app_ref card2expr(card& c) { return c.to_expr(*this); } + app_ref justification2expr(b_justification& js, literal conseq); bool proofs_enabled() const { return get_manager().proofs_enabled(); } justification* justify(literal l1, literal l2); diff --git a/src/util/uint_set.h b/src/util/uint_set.h index e78a4b0b6..7ff497709 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -25,9 +25,9 @@ Revision History: COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); class uint_set : unsigned_vector { - + public: - + typedef unsigned data; uint_set() {} @@ -253,5 +253,81 @@ inline std::ostream & operator<<(std::ostream & target, const uint_set & s) { return target; } + +class tracked_uint_set { + svector m_in_set; + svector m_set; +public: + typedef svector::const_iterator iterator; + void insert(unsigned v) { + m_in_set.reserve(v+1, false); + if (m_in_set[v]) + return; + m_in_set[v] = true; + m_set.push_back(v); + } + + void remove(unsigned v) { + if (contains(v)) { + m_in_set[v] = false; + unsigned i = 0; + for (i = 0; i < m_set.size() && m_set[i] != v; ++i) + ; + SASSERT(i < m_set.size()); + m_set[i] = m_set.back(); + m_set.pop_back(); + } + } + + tracked_uint_set& operator=(tracked_uint_set const& other) { + m_in_set = other.m_in_set; + m_set = other.m_set; + return *this; + } + + bool contains(unsigned v) const { + return v < m_in_set.size() && m_in_set[v] != 0; + } + + bool empty() const { + return m_set.empty(); + } + + // erase some variable from the set + unsigned erase() { + SASSERT(!empty()); + unsigned v = m_set.back(); + m_set.pop_back(); + m_in_set[v] = false; + return v; + } + unsigned size() const { return m_set.size(); } + iterator begin() const { return m_set.begin(); } + iterator end() const { return m_set.end(); } + void reset() { m_set.reset(); m_in_set.reset(); } + void finalize() { m_set.finalize(); m_in_set.finalize(); } + tracked_uint_set& operator&=(tracked_uint_set const& other) { + unsigned j = 0; + for (unsigned i = 0; i < m_set.size(); ++i) { + if (other.contains(m_set[i])) { + m_set[j] = m_set[i]; + ++j; + } + else { + m_in_set[m_set[i]] = false; + } + } + m_set.resize(j); + return *this; + } + tracked_uint_set& operator|=(tracked_uint_set const& other) { + for (unsigned i = 0; i < other.m_set.size(); ++i) { + insert(other.m_set[i]); + } + return *this; + } +}; + + #endif /* UINT_SET_H_ */ From 92e2d920fd5354a6cb8586b4947403e5c26faab4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Jan 2017 14:03:27 -0800 Subject: [PATCH 0013/1283] working on card for sat Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 1 + src/sat/card_extension.cpp | 686 +++++++++++++++++++++++++++ src/sat/card_extension.h | 142 ++++++ src/sat/sat_extension.h | 4 + src/sat/sat_justification.h | 2 +- src/sat/sat_solver.cpp | 4 + src/sat/sat_solver.h | 1 + src/smt/theory_pb.h | 11 - 8 files changed, 839 insertions(+), 12 deletions(-) create mode 100644 src/sat/card_extension.cpp create mode 100644 src/sat/card_extension.h diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index d88a73708..41051fd40 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -1,5 +1,6 @@ z3_add_component(sat SOURCES + card_extension.cpp dimacs.cpp sat_asymm_branch.cpp sat_clause.cpp diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp new file mode 100644 index 000000000..985579f18 --- /dev/null +++ b/src/sat/card_extension.cpp @@ -0,0 +1,686 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + card_extension.cpp + +Abstract: + + Extension for cardinality reasoning. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-01-30 + +Revision History: + +--*/ + +#include"card_extension.h" +#include"sat_types.h" + +namespace sat { + + card_extension::card::card(unsigned index, literal lit, literal_vector const& lits, unsigned k): + m_index(index), + m_lit(lit), + m_k(k), + m_size(lits.size()), + m_lits(lits) { + } + + void card_extension::card::negate() { + m_lit.neg(); + for (unsigned i = 0; i < m_size; ++i) { + m_lits[i].neg(); + } + m_k = m_size - m_k + 1; + SASSERT(m_size >= m_k && m_k > 0); + } + + void card_extension::init_watch(bool_var v) { + if (m_var_infos.size() <= static_cast(v)) { + m_var_infos.resize(static_cast(v)+100); + } + } + + void card_extension::init_watch(card& c, bool is_true) { + clear_watch(c); + if (c.lit().sign() == is_true) { + c.negate(); + } + SASSERT(s().value(c.lit()) == l_true); + unsigned j = 0, sz = c.size(), bound = c.k(); + if (bound == sz) { + for (unsigned i = 0; i < sz && !s().inconsistent(); ++i) { + assign(c, c[i]); + } + return; + } + // put the non-false literals into the head. + for (unsigned i = 0; i < sz; ++i) { + if (s().value(c[i]) != l_false) { + if (j != i) { + c.swap(i, j); + } + ++j; + } + } + DEBUG_CODE( + bool is_false = false; + for (unsigned k = 0; k < sz; ++k) { + SASSERT(!is_false || s().value(c[k]) == l_false); + is_false = s().value(c[k]) == l_false; + }); + + // j is the number of non-false, sz - j the number of false. + if (j < bound) { + SASSERT(0 < bound && bound < sz); + literal alit = c[j]; + + // + // we need the assignment level of the asserting literal to be maximal. + // such that conflict resolution can use the asserting literal as a starting + // point. + // + + for (unsigned i = bound; i < sz; ++i) { + if (s().lvl(alit) < s().lvl(c[i])) { + c.swap(i, j); + alit = c[j]; + } + } + set_conflict(c, alit); + } + else if (j == bound) { + for (unsigned i = 0; i < bound && !s().inconsistent(); ++i) { + assign(c, c[i]); + } + } + else { + for (unsigned i = 0; i <= bound; ++i) { + watch_literal(c, c[i]); + } + } + } + + void card_extension::clear_watch(card& c) { + unsigned sz = std::min(c.k() + 1, c.size()); + for (unsigned i = 0; i < sz; ++i) { + unwatch_literal(c[i], &c); + } + } + + void card_extension::unwatch_literal(literal lit, card* c) { + if (m_var_infos.size() <= static_cast(lit.var())) { + return; + } + ptr_vector* cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; + if (cards) { + remove(*cards, c); + } + } + + void card_extension::remove(ptr_vector& cards, card* c) { + for (unsigned j = 0; j < cards.size(); ++j) { + if (cards[j] == c) { + std::swap(cards[j], cards[cards.size()-1]); + cards.pop_back(); + break; + } + } + } + + void card_extension::assign(card& c, literal lit) { + if (s().value(lit) == l_true) { + return; + } + m_stats.m_num_propagations++; + //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); + SASSERT(validate_unit_propagation(c)); + s().assign(lit, justification::mk_ext_justification(c.index())); + + } + + void card_extension::watch_literal(card& c, literal lit) { + init_watch(lit.var()); + ptr_vector* cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; + if (cards == 0) { + cards = alloc(ptr_vector); + m_var_infos[lit.var()].m_lit_watch[lit.sign()] = cards; + } + cards->push_back(&c); + } + + void card_extension::set_conflict(card& c, literal lit) { + SASSERT(validate_conflict(c)); + literal_vector& lits = get_literals(); + SASSERT(s().value(lit) == l_false); + SASSERT(s().value(c.lit()) == l_true); + lits.push_back(~c.lit()); + lits.push_back(lit); + unsigned sz = c.size(); + for (unsigned i = c.k(); i < sz; ++i) { + SASSERT(s().value(c[i]) == l_false); + lits.push_back(c[i]); + } + + m_stats.m_num_conflicts++; + if (!resolve_conflict(c, lits)) { + s().mk_clause_core(lits.size(), lits.c_ptr(), true); + } + SASSERT(s().inconsistent()); + } + + void card_extension::normalize_active_coeffs() { + while (!m_active_var_set.empty()) m_active_var_set.erase(); + unsigned i = 0, j = 0, sz = m_active_vars.size(); + for (; i < sz; ++i) { + bool_var v = m_active_vars[i]; + if (!m_active_var_set.contains(v) && get_coeff(v) != 0) { + m_active_var_set.insert(v); + if (j != i) { + m_active_vars[j] = m_active_vars[i]; + } + ++j; + } + } + sz = j; + m_active_vars.shrink(sz); + } + + void card_extension::inc_coeff(literal l, int offset) { + SASSERT(offset > 0); + bool_var v = l.var(); + SASSERT(v != null_bool_var); + if (static_cast(m_coeffs.size()) <= v) { + m_coeffs.resize(v + 1, 0); + } + int coeff0 = m_coeffs[v]; + if (coeff0 == 0) { + m_active_vars.push_back(v); + } + + int inc = l.sign() ? -offset : offset; + int coeff1 = inc + coeff0; + m_coeffs[v] = coeff1; + + if (coeff0 > 0 && inc < 0) { + m_bound -= coeff0 - std::max(0, coeff1); + } + else if (coeff0 < 0 && inc > 0) { + m_bound -= std::min(0, coeff1) - coeff0; + } + } + + int card_extension::get_coeff(bool_var v) const { + return m_coeffs.get(v, 0); + } + + int card_extension::get_abs_coeff(bool_var v) const { + int coeff = get_coeff(v); + if (coeff < 0) coeff = -coeff; + return coeff; + } + + void card_extension::reset_coeffs() { + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + m_coeffs[m_active_vars[i]] = 0; + } + m_active_vars.reset(); + } + + bool card_extension::resolve_conflict(card& c, literal_vector const& conflict_clause) { + + bool_var v; + m_conflict_lvl = 0; + for (unsigned i = 0; i < c.size(); ++i) { + literal lit = c[i]; + SASSERT(s().value(lit) == l_false); + m_conflict_lvl = std::max(m_conflict_lvl, s().lvl(lit)); + } + if (m_conflict_lvl < s().lvl(c.lit()) || m_conflict_lvl == 0) { + return false; + } + + reset_coeffs(); + m_num_marks = 0; + m_bound = c.k(); + m_conflict.reset(); + literal_vector const& lits = s().m_trail; + unsigned idx = lits.size()-1; + justification js; + literal consequent = ~conflict_clause[1]; + process_card(c, 1); + literal alit; + + while (m_num_marks > 0) { + + v = consequent.var(); + + int offset = get_abs_coeff(v); + + if (offset == 0) { + goto process_next_resolvent; + } + if (offset > 1000) { + goto bail_out; + } + + SASSERT(offset > 0); + + js = s().m_justification[v]; + + int bound = 1; + switch(js.get_kind()) { + case justification::NONE: + break; + case justification::BINARY: + inc_coeff(consequent, offset); + process_antecedent(~(js.get_literal()), offset); + break; + case justification::TERNARY: + inc_coeff(consequent, offset); + process_antecedent(~(js.get_literal1()), offset); + process_antecedent(~(js.get_literal2()), offset); + break; + case justification::CLAUSE: { + inc_coeff(consequent, offset); + clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); + unsigned i = 0; + if (consequent != null_literal) { + SASSERT(c[0] == consequent || c[1] == consequent); + if (c[0] == consequent) { + i = 1; + } + else { + process_antecedent(~c[0], offset); + i = 2; + } + } + unsigned sz = c.size(); + for (; i < sz; i++) + process_antecedent(~c[i], offset); + break; + } + case justification::EXT_JUSTIFICATION: { + unsigned index = js.get_ext_justification_idx(); + card& c2 = *m_constraints[index]; + process_card(c2, offset); + bound = c2.k(); + break; + } + default: + UNREACHABLE(); + break; + } + m_bound += offset * bound; + + // cut(); + + process_next_resolvent: + + // find the next marked variable in the assignment stack + // + while (true) { + consequent = lits[idx]; + v = consequent.var(); + if (s().is_marked(v)) break; + SASSERT(idx > 0); + --idx; + } + + SASSERT(s().lvl(v) == m_conflict_lvl); + s().reset_mark(v); + --idx; + --m_num_marks; + } + + SASSERT(validate_lemma()); + + normalize_active_coeffs(); + + if (m_bound > 0 && m_active_vars.empty()) { + return false; + } + + int slack = -m_bound; + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + slack += get_abs_coeff(v); + } + + alit = get_asserting_literal(~consequent); + slack -= get_abs_coeff(alit.var()); + m_conflict.push_back(alit); + + for (unsigned i = lits.size(); 0 <= slack && i > 0; ) { + --i; + literal lit = lits[i]; + bool_var v = lit.var(); + if (m_active_var_set.contains(v) && v != alit.var()) { + int coeff = get_coeff(v); + if (coeff < 0 && !lit.sign()) { + slack += coeff; + m_conflict.push_back(~lit); + } + else if (coeff > 0 && lit.sign()) { + slack -= coeff; + m_conflict.push_back(~lit); + } + } + } + SASSERT(slack < 0); + SASSERT(validate_conflict(m_conflict)); + + s().mk_clause_core(m_conflict.size(), m_conflict.c_ptr(), true); + return true; + + bail_out: + while (m_num_marks > 0 && idx > 0) { + v = lits[idx].var(); + if (s().is_marked(v)) { + s().reset_mark(v); + } + --idx; + } + return false; + } + + void card_extension::process_card(card& c, int offset) { + SASSERT(c.k() <= c.size()); + SASSERT(s().value(c.lit()) == l_true); + for (unsigned i = c.k(); i < c.size(); ++i) { + process_antecedent(c[i], offset); + } + for (unsigned i = 0; i < c.k(); ++i) { + inc_coeff(c[i], offset); + } + if (s().lvl(c.lit()) > 0) { + m_conflict.push_back(~c.lit()); + } + } + + void card_extension::process_antecedent(literal l, int offset) { + SASSERT(s().value(l) == l_false); + bool_var v = l.var(); + unsigned lvl = s().lvl(v); + + if (lvl > 0 && !s().is_marked(v) && lvl == m_conflict_lvl) { + s().mark(v); + ++m_num_marks; + } + inc_coeff(l, offset); + } + + literal card_extension::get_asserting_literal(literal p) { + if (get_abs_coeff(p.var()) != 0) { + return p; + } + unsigned lvl = 0; + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + literal lit(v, get_coeff(v) < 0); + if (s().value(lit) == l_false && s().lvl(lit) > lvl) { + p = lit; + } + } + return p; + } + + card_extension::card_extension(): m_solver(0) {} + + card_extension::~card_extension() { + for (unsigned i = 0; i < m_var_infos.size(); ++i) { + m_var_infos[i].reset(); + } + m_var_trail.reset(); + m_var_lim.reset(); + m_stats.reset(); + } + + void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { + unsigned index = m_constraints.size(); + card* c = alloc(card, index, literal(v, false), lits, k); + m_constraints.push_back(c); + init_watch(v); + m_var_infos[v].m_card = c; + m_var_trail.push_back(v); + } + + void card_extension::propagate(literal l, ext_constraint_idx idx, bool & keep) { + UNREACHABLE(); + } + + void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { + card& c = *m_constraints[idx]; + + DEBUG_CODE( + bool found = false; + for (unsigned i = 0; !found && i < c.k(); ++i) { + found = c[i] == l; + } + SASSERT(found);); + + for (unsigned i = c.k(); i < c.size(); ++i) { + SASSERT(s().value(c[i]) == l_false); + r.push_back(c[i]); + } + } + + lbool card_extension::add_assign(card& c, literal alit) { + // literal is assigned to false. + unsigned sz = c.size(); + unsigned bound = c.k(); + TRACE("pb", tout << "assign: " << c.lit() << " " << ~alit << " " << bound << "\n";); + + SASSERT(0 < bound && bound < sz); + SASSERT(s().value(alit) == l_false); + SASSERT(s().value(c.lit()) == l_true); + unsigned index = 0; + for (index = 0; index <= bound; ++index) { + if (c[index] == alit) { + break; + } + } + if (index == bound + 1) { + // literal is no longer watched. + return l_undef; + } + SASSERT(index <= bound); + SASSERT(c[index] == alit); + + // find a literal to swap with: + for (unsigned i = bound + 1; i < sz; ++i) { + literal lit2 = c[i]; + if (s().value(lit2) != l_false) { + c.swap(index, i); + watch_literal(c, lit2); + return l_undef; + } + } + + // conflict + if (bound != index && s().value(c[bound]) == l_false) { + TRACE("sat", tout << "conflict " << c[bound] << " " << alit << "\n";); + set_conflict(c, alit); + return l_false; + } + + TRACE("pb", tout << "no swap " << index << " " << alit << "\n";); + // there are no literals to swap with, + // prepare for unit propagation by swapping the false literal into + // position bound. Then literals in positions 0..bound-1 have to be + // assigned l_true. + if (index != bound) { + c.swap(index, bound); + } + SASSERT(validate_unit_propagation(c)); + + for (unsigned i = 0; i < bound && !s().inconsistent(); ++i) { + assign(c, c[i]); + } + + return s().inconsistent() ? l_false : l_true; + } + + void card_extension::asserted(literal l) { + bool_var v = l.var(); + ptr_vector* cards = m_var_infos[v].m_lit_watch[!l.sign()]; + if (cards != 0 && !cards->empty() && !s().inconsistent()) { + ptr_vector::iterator it = cards->begin(), it2 = it, end = cards->end(); + for (; it != end; ++it) { + card& c = *(*it); + if (s().value(c.lit()) != l_true) { + continue; + } + switch (add_assign(c, l)) { + case l_false: // conflict + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + SASSERT(s().inconsistent()); + cards->set_end(it2); + return; + case l_undef: // watch literal was swapped + break; + case l_true: // unit propagation, keep watching the literal + if (it2 != it) { + *it2 = *it; + } + ++it2; + break; + } + } + cards->set_end(it2); + } + + card* crd = m_var_infos[v].m_card; + if (crd != 0 && !s().inconsistent()) { + init_watch(*crd, !l.sign()); + } + } + + check_result card_extension::check() { return CR_DONE; } + + void card_extension::push() { + m_var_lim.push_back(m_var_trail.size()); + } + + void card_extension::pop(unsigned n) { + unsigned new_lim = m_var_lim.size() - n; + unsigned sz = m_var_lim[new_lim]; + while (m_var_trail.size() > sz) { + bool_var v = m_var_trail.back(); + m_var_trail.pop_back(); + if (v != null_bool_var) { + card* c = m_var_infos[v].m_card; + clear_watch(*c); + m_var_infos[v].m_card = 0; + dealloc(c); + } + } + m_var_lim.resize(new_lim); + } + + void card_extension::simplify() {} + void card_extension::clauses_modifed() {} + lbool card_extension::get_phase(bool_var v) { return l_undef; } + + void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { + watch const* w = m_var_infos[v].m_lit_watch[sign]; + if (w) { + watch const& wl = *w; + out << "watch: " << literal(v, sign) << " |-> "; + for (unsigned i = 0; i < wl.size(); ++i) { + out << wl[i]->lit() << " "; + } + out << "\n"; + } + } + + void card_extension::display(std::ostream& out, card& c, bool values) const { + out << c.lit(); + if (c.lit() != null_literal) { + if (values) { + out << "@(" << s().value(c.lit()); + if (s().value(c.lit()) != l_undef) { + out << ":" << s().lvl(c.lit()); + } + out << ")"; + } + out << c.lit() << "\n"; + } + else { + out << " "; + } + for (unsigned i = 0; i < c.size(); ++i) { + literal l = c[i]; + out << l; + if (values) { + out << "@(" << s().value(l); + if (s().value(l) != l_undef) { + out << ":" << s().lvl(l); + } + out << ") "; + } + } + out << " >= " << c.k() << "\n"; + } + + std::ostream& card_extension::display(std::ostream& out) const { + for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { + display_watch(out, vi, false); + display_watch(out, vi, true); + } + for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { + card* c = m_var_infos[vi].m_card; + if (c) { + display(out, *c, true); + } + } + return out; + } + + void card_extension::collect_statistics(statistics& st) const { + st.update("card propagations", m_stats.m_num_propagations); + st.update("card conflicts", m_stats.m_num_conflicts); + } + + bool card_extension::validate_conflict(card& c) { + if (!validate_unit_propagation(c)) return false; + for (unsigned i = 0; i < c.k(); ++i) { + if (s().value(c[i]) == l_false) return true; + } + return false; + } + bool card_extension::validate_unit_propagation(card const& c) { + for (unsigned i = c.k(); i < c.size(); ++i) { + if (s().value(c[i]) != l_false) return false; + } + return true; + } + bool card_extension::validate_lemma() { + int value = -m_bound; + normalize_active_coeffs(); + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + int coeff = get_coeff(v); + SASSERT(coeff != 0); + if (coeff < 0 && s().value(v) != l_true) { + value -= coeff; + } + else if (coeff > 0 && s().value(v) != l_false) { + value += coeff; + } + } + return value < 0; + } + + bool card_extension::validate_assign(literal_vector const& lits, literal lit) { return true; } + bool card_extension::validate_conflict(literal_vector const& lits) { return true; } + + +}; + diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h new file mode 100644 index 000000000..db8e041c2 --- /dev/null +++ b/src/sat/card_extension.h @@ -0,0 +1,142 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + card_extension.h + +Abstract: + + Cardinality extensions. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-01-30 + +Revision History: + +--*/ +#ifndef CARD_EXTENSION_H_ +#define CARD_EXTENSION_H_ + +#include"sat_extension.h" +#include"sat_solver.h" + +namespace sat { + + class card_extension : public extension { + struct stats { + unsigned m_num_propagations; + unsigned m_num_conflicts; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + class card { + unsigned m_index; + literal m_lit; + unsigned m_k; + unsigned m_size; + literal_vector m_lits; + public: + card(unsigned index, literal lit, literal_vector const& lits, unsigned k); + unsigned index() const { return m_index; } + literal lit() const { return m_lit; } + literal operator[](unsigned i) const { return m_lits[i]; } + unsigned k() const { return m_k; } + unsigned size() const { return m_size; } + void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } + void negate(); + }; + + typedef ptr_vector watch; + struct var_info { + watch* m_lit_watch[2]; + card* m_card; + var_info(): m_card(0) { + m_lit_watch[0] = 0; + m_lit_watch[1] = 0; + } + void reset() { + dealloc(m_card); + dealloc(m_lit_watch[0]); + dealloc(m_lit_watch[1]); + } + }; + + + solver* m_solver; + stats m_stats; + + ptr_vector m_constraints; + + // watch literals + svector m_var_infos; + unsigned_vector m_var_trail; + unsigned_vector m_var_lim; + + // conflict resolution + unsigned m_num_marks; + unsigned m_conflict_lvl; + svector m_coeffs; + svector m_active_vars; + int m_bound; + tracked_uint_set m_active_var_set; + literal_vector m_conflict; + literal_vector m_literals; + + solver& s() const { return *m_solver; } + void init_watch(card& c, bool is_true); + void init_watch(bool_var v); + void assign(card& c, literal lit); + lbool add_assign(card& c, literal lit); + void watch_literal(card& c, literal lit); + void set_conflict(card& c, literal lit); + void clear_watch(card& c); + void reset_coeffs(); + + void unwatch_literal(literal w, card* c); + void remove(ptr_vector& cards, card* c); + + void normalize_active_coeffs(); + void inc_coeff(literal l, int offset); + int get_coeff(bool_var v) const; + int get_abs_coeff(bool_var v) const; + + literal_vector& get_literals() { m_literals.reset(); return m_literals; } + literal get_asserting_literal(literal conseq); + bool resolve_conflict(card& c, literal_vector const& conflict_clause); + void process_antecedent(literal l, int offset); + void process_card(card& c, int offset); + void cut(); + + // validation utilities + bool validate_conflict(card& c); + bool validate_assign(literal_vector const& lits, literal lit); + bool validate_lemma(); + bool validate_unit_propagation(card const& c); + bool validate_conflict(literal_vector const& lits); + + void display(std::ostream& out, card& c, bool values) const; + void display_watch(std::ostream& out, bool_var v, bool sign) const; + public: + card_extension(); + virtual ~card_extension(); + void set_solver(solver* s) { m_solver = s; } + void add_at_least(bool_var v, literal_vector const& lits, unsigned k); + virtual void propagate(literal l, ext_constraint_idx idx, bool & keep); + virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r); + virtual void asserted(literal l); + virtual check_result check(); + virtual void push(); + virtual void pop(unsigned n); + virtual void simplify(); + virtual void clauses_modifed(); + virtual lbool get_phase(bool_var v); + virtual std::ostream& display(std::ostream& out) const; + virtual void collect_statistics(statistics& st) const; + }; + +}; + +#endif diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index b0b1c5d96..f1a48c0a8 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -21,6 +21,7 @@ Revision History: #include"sat_types.h" #include"params.h" +#include"statistics.h" namespace sat { @@ -30,6 +31,7 @@ namespace sat { class extension { public: + virtual ~extension() {} virtual void propagate(literal l, ext_constraint_idx idx, bool & keep) = 0; virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0; virtual void asserted(literal l) = 0; @@ -39,6 +41,8 @@ namespace sat { virtual void simplify() = 0; virtual void clauses_modifed() = 0; virtual lbool get_phase(bool_var v) = 0; + virtual std::ostream& display(std::ostream& out) const = 0; + virtual void collect_statistics(statistics& st) const = 0; }; }; diff --git a/src/sat/sat_justification.h b/src/sat/sat_justification.h index 00da9f30e..8c5331d17 100644 --- a/src/sat/sat_justification.h +++ b/src/sat/sat_justification.h @@ -33,7 +33,7 @@ namespace sat { explicit justification(literal l):m_val1(l.to_uint()), m_val2(BINARY) {} justification(literal l1, literal l2):m_val1(l1.to_uint()), m_val2(TERNARY + (l2.to_uint() << 3)) {} explicit justification(clause_offset cls_off):m_val1(cls_off), m_val2(CLAUSE) {} - justification mk_ext_justification(ext_justification_idx idx) { return justification(idx, EXT_JUSTIFICATION); } + static justification mk_ext_justification(ext_justification_idx idx) { return justification(idx, EXT_JUSTIFICATION); } kind get_kind() const { return static_cast(m_val2 & 7); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index bf3dc1988..647c5f9ed 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2752,6 +2752,7 @@ namespace sat { m_scc.collect_statistics(st); m_asymm_branch.collect_statistics(st); m_probing.collect_statistics(st); + if (m_ext) m_ext->collect_statistics(st); } void solver::reset_statistics() { @@ -2856,6 +2857,9 @@ namespace sat { display_units(out); display_binary(out); out << m_clauses << m_learned; + if (m_ext) { + m_ext->display(out); + } out << ")\n"; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 54b8a9bb2..b42acc680 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -145,6 +145,7 @@ namespace sat { friend class probing; friend class iff3_finder; friend class mus; + friend class card_extension; friend struct mk_stat; public: solver(params_ref const & p, reslimit& l, extension * ext); diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 56f3d1e76..90673768b 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -250,16 +250,6 @@ namespace smt { typedef map arg_map; - struct row_info { - unsigned m_slack; // slack variable in simplex tableau - numeral m_bound; // bound - arg_t m_rep; // representative - row_info(theory_var slack, numeral const& b, arg_t const& r): - m_slack(slack), m_bound(b), m_rep(r) {} - row_info(): m_slack(0) {} - }; - - struct var_info { ineq_watch* m_lit_watch[2]; ineq_watch* m_var_watch; @@ -290,7 +280,6 @@ namespace smt { theory_pb_params m_params; svector m_var_infos; - unsynch_mpq_inf_manager m_mpq_inf_mgr; // Simplex: manage inf_mpq numerals mutable unsynch_mpz_manager m_mpz_mgr; // Simplex: manager mpz numerals unsigned_vector m_ineqs_trail; unsigned_vector m_ineqs_lim; From 32b5e54c8dbd870f216d098483781c41a04be81d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Jan 2017 17:22:06 -0800 Subject: [PATCH 0014/1283] working on card extension Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 251 +++++++++++++++++++++++++++---------- src/sat/card_extension.h | 23 +++- 2 files changed, 204 insertions(+), 70 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 985579f18..2af1a5b5e 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -50,7 +50,7 @@ namespace sat { if (c.lit().sign() == is_true) { c.negate(); } - SASSERT(s().value(c.lit()) == l_true); + SASSERT(value(c.lit()) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); if (bound == sz) { for (unsigned i = 0; i < sz && !s().inconsistent(); ++i) { @@ -60,7 +60,7 @@ namespace sat { } // put the non-false literals into the head. for (unsigned i = 0; i < sz; ++i) { - if (s().value(c[i]) != l_false) { + if (value(c[i]) != l_false) { if (j != i) { c.swap(i, j); } @@ -70,8 +70,8 @@ namespace sat { DEBUG_CODE( bool is_false = false; for (unsigned k = 0; k < sz; ++k) { - SASSERT(!is_false || s().value(c[k]) == l_false); - is_false = s().value(c[k]) == l_false; + SASSERT(!is_false || value(c[k]) == l_false); + is_false = value(c[k]) == l_false; }); // j is the number of non-false, sz - j the number of false. @@ -86,7 +86,7 @@ namespace sat { // for (unsigned i = bound; i < sz; ++i) { - if (s().lvl(alit) < s().lvl(c[i])) { + if (lvl(alit) < lvl(c[i])) { c.swap(i, j); alit = c[j]; } @@ -133,7 +133,7 @@ namespace sat { } void card_extension::assign(card& c, literal lit) { - if (s().value(lit) == l_true) { + if (value(lit) == l_true) { return; } m_stats.m_num_propagations++; @@ -155,19 +155,20 @@ namespace sat { void card_extension::set_conflict(card& c, literal lit) { SASSERT(validate_conflict(c)); - literal_vector& lits = get_literals(); - SASSERT(s().value(lit) == l_false); - SASSERT(s().value(c.lit()) == l_true); - lits.push_back(~c.lit()); - lits.push_back(lit); - unsigned sz = c.size(); - for (unsigned i = c.k(); i < sz; ++i) { - SASSERT(s().value(c[i]) == l_false); - lits.push_back(c[i]); - } m_stats.m_num_conflicts++; - if (!resolve_conflict(c, lits)) { + if (!resolve_conflict(c, lit)) { + + literal_vector& lits = get_literals(); + SASSERT(value(lit) == l_false); + SASSERT(value(c.lit()) == l_true); + lits.push_back(~c.lit()); + lits.push_back(lit); + unsigned sz = c.size(); + for (unsigned i = c.k(); i < sz; ++i) { + SASSERT(value(c[i]) == l_false); + lits.push_back(c[i]); + } s().mk_clause_core(lits.size(), lits.c_ptr(), true); } SASSERT(s().inconsistent()); @@ -231,16 +232,16 @@ namespace sat { m_active_vars.reset(); } - bool card_extension::resolve_conflict(card& c, literal_vector const& conflict_clause) { + bool card_extension::resolve_conflict(card& c, literal alit) { bool_var v; m_conflict_lvl = 0; for (unsigned i = 0; i < c.size(); ++i) { literal lit = c[i]; - SASSERT(s().value(lit) == l_false); - m_conflict_lvl = std::max(m_conflict_lvl, s().lvl(lit)); + SASSERT(value(lit) == l_false); + m_conflict_lvl = std::max(m_conflict_lvl, lvl(lit)); } - if (m_conflict_lvl < s().lvl(c.lit()) || m_conflict_lvl == 0) { + if (m_conflict_lvl < lvl(c.lit()) || m_conflict_lvl == 0) { return false; } @@ -251,14 +252,14 @@ namespace sat { literal_vector const& lits = s().m_trail; unsigned idx = lits.size()-1; justification js; - literal consequent = ~conflict_clause[1]; + literal consequent = ~alit; process_card(c, 1); - literal alit; + + DEBUG_CODE(active2pb(m_A);); while (m_num_marks > 0) { - + SASSERT(value(consequent) == l_true); v = consequent.var(); - int offset = get_abs_coeff(v); if (offset == 0) { @@ -268,9 +269,11 @@ namespace sat { goto bail_out; } + SASSERT(validate_lemma()); SASSERT(offset > 0); js = s().m_justification[v]; + DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); int bound = 1; switch(js.get_kind()) { @@ -289,15 +292,13 @@ namespace sat { inc_coeff(consequent, offset); clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); unsigned i = 0; - if (consequent != null_literal) { - SASSERT(c[0] == consequent || c[1] == consequent); - if (c[0] == consequent) { - i = 1; - } - else { - process_antecedent(~c[0], offset); - i = 2; - } + SASSERT(c[0] == consequent || c[1] == consequent); + if (c[0] == consequent) { + i = 1; + } + else { + process_antecedent(~c[0], offset); + i = 2; } unsigned sz = c.size(); for (; i < sz; i++) @@ -316,6 +317,11 @@ namespace sat { break; } m_bound += offset * bound; + + DEBUG_CODE( + active2pb(m_C); + SASSERT(validate_resolvent()); + m_A = m_C;); // cut(); @@ -331,7 +337,7 @@ namespace sat { --idx; } - SASSERT(s().lvl(v) == m_conflict_lvl); + SASSERT(lvl(v) == m_conflict_lvl); s().reset_mark(v); --idx; --m_num_marks; @@ -390,24 +396,24 @@ namespace sat { void card_extension::process_card(card& c, int offset) { SASSERT(c.k() <= c.size()); - SASSERT(s().value(c.lit()) == l_true); + SASSERT(value(c.lit()) == l_true); for (unsigned i = c.k(); i < c.size(); ++i) { process_antecedent(c[i], offset); } for (unsigned i = 0; i < c.k(); ++i) { inc_coeff(c[i], offset); } - if (s().lvl(c.lit()) > 0) { + if (lvl(c.lit()) > 0) { m_conflict.push_back(~c.lit()); } } void card_extension::process_antecedent(literal l, int offset) { - SASSERT(s().value(l) == l_false); + SASSERT(value(l) == l_false); bool_var v = l.var(); - unsigned lvl = s().lvl(v); + unsigned level = lvl(v); - if (lvl > 0 && !s().is_marked(v) && lvl == m_conflict_lvl) { + if (level > 0 && !s().is_marked(v) && level == m_conflict_lvl) { s().mark(v); ++m_num_marks; } @@ -418,12 +424,13 @@ namespace sat { if (get_abs_coeff(p.var()) != 0) { return p; } - unsigned lvl = 0; + unsigned level = 0; for (unsigned i = 0; i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; literal lit(v, get_coeff(v) < 0); - if (s().value(lit) == l_false && s().lvl(lit) > lvl) { + if (value(lit) == l_false && lvl(lit) > level) { p = lit; + level = lvl(lit); } } return p; @@ -463,21 +470,24 @@ namespace sat { } SASSERT(found);); + r.push_back(c.lit()); + SASSERT(value(c.lit()) == l_true); for (unsigned i = c.k(); i < c.size(); ++i) { - SASSERT(s().value(c[i]) == l_false); - r.push_back(c[i]); + SASSERT(value(c[i]) == l_false); + r.push_back(~c[i]); } } + lbool card_extension::add_assign(card& c, literal alit) { // literal is assigned to false. unsigned sz = c.size(); unsigned bound = c.k(); - TRACE("pb", tout << "assign: " << c.lit() << " " << ~alit << " " << bound << "\n";); + TRACE("sat", tout << "assign: " << c.lit() << " " << ~alit << " " << bound << "\n";); SASSERT(0 < bound && bound < sz); - SASSERT(s().value(alit) == l_false); - SASSERT(s().value(c.lit()) == l_true); + SASSERT(value(alit) == l_false); + SASSERT(value(c.lit()) == l_true); unsigned index = 0; for (index = 0; index <= bound; ++index) { if (c[index] == alit) { @@ -494,7 +504,7 @@ namespace sat { // find a literal to swap with: for (unsigned i = bound + 1; i < sz; ++i) { literal lit2 = c[i]; - if (s().value(lit2) != l_false) { + if (value(lit2) != l_false) { c.swap(index, i); watch_literal(c, lit2); return l_undef; @@ -502,13 +512,13 @@ namespace sat { } // conflict - if (bound != index && s().value(c[bound]) == l_false) { + if (bound != index && value(c[bound]) == l_false) { TRACE("sat", tout << "conflict " << c[bound] << " " << alit << "\n";); set_conflict(c, alit); return l_false; } - TRACE("pb", tout << "no swap " << index << " " << alit << "\n";); + TRACE("sat", tout << "no swap " << index << " " << alit << "\n";); // there are no literals to swap with, // prepare for unit propagation by swapping the false literal into // position bound. Then literals in positions 0..bound-1 have to be @@ -532,7 +542,7 @@ namespace sat { ptr_vector::iterator it = cards->begin(), it2 = it, end = cards->end(); for (; it != end; ++it) { card& c = *(*it); - if (s().value(c.lit()) != l_true) { + if (value(c.lit()) != l_true) { continue; } switch (add_assign(c, l)) { @@ -604,9 +614,9 @@ namespace sat { out << c.lit(); if (c.lit() != null_literal) { if (values) { - out << "@(" << s().value(c.lit()); - if (s().value(c.lit()) != l_undef) { - out << ":" << s().lvl(c.lit()); + out << "@(" << value(c.lit()); + if (value(c.lit()) != l_undef) { + out << ":" << lvl(c.lit()); } out << ")"; } @@ -619,9 +629,9 @@ namespace sat { literal l = c[i]; out << l; if (values) { - out << "@(" << s().value(l); - if (s().value(l) != l_undef) { - out << ":" << s().lvl(l); + out << "@(" << value(l); + if (value(l) != l_undef) { + out << ":" << lvl(l); } out << ") "; } @@ -651,35 +661,142 @@ namespace sat { bool card_extension::validate_conflict(card& c) { if (!validate_unit_propagation(c)) return false; for (unsigned i = 0; i < c.k(); ++i) { - if (s().value(c[i]) == l_false) return true; + if (value(c[i]) == l_false) return true; } return false; } bool card_extension::validate_unit_propagation(card const& c) { + if (value(c.lit()) != l_true) return false; for (unsigned i = c.k(); i < c.size(); ++i) { - if (s().value(c[i]) != l_false) return false; + if (value(c[i]) != l_false) return false; } return true; } bool card_extension::validate_lemma() { - int value = -m_bound; + int val = -m_bound; normalize_active_coeffs(); for (unsigned i = 0; i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; int coeff = get_coeff(v); + literal lit(v, false); SASSERT(coeff != 0); - if (coeff < 0 && s().value(v) != l_true) { - value -= coeff; + if (coeff < 0 && value(lit) != l_true) { + val -= coeff; } - else if (coeff > 0 && s().value(v) != l_false) { - value += coeff; + else if (coeff > 0 && value(lit) != l_false) { + val += coeff; } } - return value < 0; + return val < 0; } - bool card_extension::validate_assign(literal_vector const& lits, literal lit) { return true; } - bool card_extension::validate_conflict(literal_vector const& lits) { return true; } + void card_extension::active2pb(ineq& p) { + normalize_active_coeffs(); + p.reset(m_bound); + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + literal lit(v, get_coeff(v) < 0); + p.m_lits.push_back(lit); + p.m_coeffs.push_back(get_abs_coeff(v)); + } + } + + void card_extension::justification2pb(justification const& js, literal lit, unsigned offset, ineq& p) { + switch (js.get_kind()) { + case justification::NONE: + p.reset(0); + break; + case justification::BINARY: + p.reset(offset); + p.push(lit, offset); + p.push(~js.get_literal(), offset); + break; + case justification::TERNARY: + p.reset(offset); + p.push(lit, offset); + p.push(~(js.get_literal1()), offset); + p.push(~(js.get_literal2()), offset); + break; + case justification::CLAUSE: { + p.reset(offset); + clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); + unsigned sz = c.size(); + for (unsigned i = 0; i < sz; i++) + p.push(~c[i], offset); + break; + } + case justification::EXT_JUSTIFICATION: { + unsigned index = js.get_ext_justification_idx(); + card& c = *m_constraints[index]; + p.reset(offset*c.k()); + for (unsigned i = 0; i < c.size(); ++i) { + p.push(c[i], offset); + } + break; + } + default: + UNREACHABLE(); + break; + } + } + + + // validate that m_A & m_B implies m_C + + bool card_extension::validate_resolvent() { + u_map coeffs; + unsigned k = m_A.m_k + m_B.m_k; + for (unsigned i = 0; i < m_A.m_lits.size(); ++i) { + unsigned coeff = m_A.m_coeffs[i]; + SASSERT(!coeffs.contains(m_A.m_lits[i].index())); + coeffs.insert(m_A.m_lits[i].index(), coeff); + } + for (unsigned i = 0; i < m_B.m_lits.size(); ++i) { + unsigned coeff1 = m_B.m_coeffs[i], coeff2; + literal lit = m_B.m_lits[i]; + if (coeffs.find((~lit).index(), coeff2)) { + if (coeff1 == coeff2) { + coeffs.remove((~lit).index()); + k += coeff1; + } + else if (coeff1 < coeff2) { + coeffs.insert((~lit).index(), coeff2 - coeff1); + k += coeff1; + } + else { + SASSERT(coeff2 < coeff1); + coeffs.remove((~lit).index()); + coeffs.insert(lit.index(), coeff1 - coeff2); + k += coeff2; + } + } + else if (coeffs.find(lit.index(), coeff2)) { + coeffs.insert(lit.index(), coeff1 + coeff2); + } + else { + coeffs.insert(lit.index(), coeff1); + } + } + // C is above the sum of A and B + for (unsigned i = 0; i < m_C.m_lits.size(); ++i) { + literal lit = m_C.m_lits[i]; + unsigned coeff; + if (coeffs.find(lit.index(), coeff)) { + SASSERT(coeff <= m_C.m_coeffs[i]); + coeffs.remove(lit.index()); + } + } + SASSERT(coeffs.empty()); + SASSERT(m_C.m_k <= k); + return true; + } + + bool card_extension::validate_conflict(literal_vector const& lits) { + for (unsigned i = 0; i < lits.size(); ++i) { + if (value(lits[i]) != l_false) return false; + } + return true; + } }; diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index db8e041c2..1593ef26f 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -23,7 +23,7 @@ Revision History: #include"sat_solver.h" namespace sat { - + class card_extension : public extension { struct stats { unsigned m_num_propagations; @@ -31,7 +31,7 @@ namespace sat { stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; - + class card { unsigned m_index; literal m_lit; @@ -49,6 +49,14 @@ namespace sat { void negate(); }; + struct ineq { + literal_vector m_lits; + unsigned_vector m_coeffs; + unsigned m_k; + void reset(unsigned k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } + void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } + }; + typedef ptr_vector watch; struct var_info { watch* m_lit_watch[2]; @@ -95,6 +103,10 @@ namespace sat { void clear_watch(card& c); void reset_coeffs(); + inline lbool value(literal lit) const { return m_solver->value(lit); } + inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } + inline unsigned lvl(bool_var v) const { return m_solver->lvl(v); } + void unwatch_literal(literal w, card* c); void remove(ptr_vector& cards, card* c); @@ -105,7 +117,7 @@ namespace sat { literal_vector& get_literals() { m_literals.reset(); return m_literals; } literal get_asserting_literal(literal conseq); - bool resolve_conflict(card& c, literal_vector const& conflict_clause); + bool resolve_conflict(card& c, literal alit); void process_antecedent(literal l, int offset); void process_card(card& c, int offset); void cut(); @@ -117,6 +129,11 @@ namespace sat { bool validate_unit_propagation(card const& c); bool validate_conflict(literal_vector const& lits); + ineq m_A, m_B, m_C; + void active2pb(ineq& p); + void justification2pb(justification const& j, literal lit, unsigned offset, ineq& p); + bool validate_resolvent(); + void display(std::ostream& out, card& c, bool values) const; void display_watch(std::ostream& out, bool_var v, bool sign) const; public: From 685fb5d7c4b37c4760de1f66c326ecc73750eb00 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Jan 2017 18:42:39 -0800 Subject: [PATCH 0015/1283] preparing for cardinality Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 64 +++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 742a4fb1d..72340bc1c 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -36,6 +36,7 @@ Notes: #include"model_v2_pp.h" #include"tactic.h" #include"ast_pp.h" +#include"pb_decl_plugin.h" #include struct goal2sat::imp { @@ -48,6 +49,7 @@ struct goal2sat::imp { m_t(t), m_root(r), m_sign(s), m_idx(idx) {} }; ast_manager & m; + pb_util pb; svector m_frame_stack; svector m_result_stack; obj_map m_cache; @@ -64,6 +66,7 @@ struct goal2sat::imp { imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external): m(_m), + pb(m), m_solver(s), m_map(map), m_dep2asm(dep2asm), @@ -113,7 +116,7 @@ struct goal2sat::imp { return m_true; } - void convert_atom(expr * t, bool root, bool sign) { + bool convert_atom(expr * t, bool root, bool sign) { SASSERT(m.is_bool(t)); sat::literal l; sat::bool_var v = m_map.to_bool_var(t); @@ -144,6 +147,15 @@ struct goal2sat::imp { mk_clause(l); else m_result_stack.push_back(l); + return true; + } + + bool convert_app(app* t, bool root, bool sign) { + return convert_atom(t, root, sign); + } + + bool convert_pb(app* t, bool root, bool sign) { + } bool process_cached(app * t, bool root, bool sign) { @@ -160,16 +172,15 @@ struct goal2sat::imp { return false; } + bool visit(expr * t, bool root, bool sign) { if (!is_app(t)) { - convert_atom(t, root, sign); - return true; + return convert_atom(t, root, sign); } if (process_cached(to_app(t), root, sign)) return true; if (to_app(t)->get_family_id() != m.get_basic_family_id()) { - convert_atom(t, root, sign); - return true; + return convert_app(to_app(t), root, sign); } switch (to_app(t)->get_decl_kind()) { case OP_NOT: @@ -184,8 +195,7 @@ struct goal2sat::imp { m_frame_stack.push_back(frame(to_app(t), root, sign, 0)); return false; } - convert_atom(t, root, sign); - return true; + return convert_atom(t, root, sign); case OP_XOR: case OP_IMPLIES: case OP_DISTINCT: { @@ -195,8 +205,7 @@ struct goal2sat::imp { throw_op_not_handled(strm.str()); } default: - convert_atom(t, root, sign); - return true; + return convert_atom(t, root, sign); } } @@ -353,22 +362,29 @@ struct goal2sat::imp { } void convert(app * t, bool root, bool sign) { - SASSERT(t->get_family_id() == m.get_basic_family_id()); - switch (to_app(t)->get_decl_kind()) { - case OP_OR: - convert_or(t, root, sign); + if (t->get_family_id() == m.get_basic_family_id()) { + switch (to_app(t)->get_decl_kind()) { + case OP_OR: + convert_or(t, root, sign); + break; + case OP_AND: + convert_and(t, root, sign); + break; + case OP_ITE: + convert_ite(t, root, sign); + break; + case OP_IFF: + case OP_EQ: + convert_iff(t, root, sign); break; - case OP_AND: - convert_and(t, root, sign); - break; - case OP_ITE: - convert_ite(t, root, sign); - break; - case OP_IFF: - case OP_EQ: - convert_iff(t, root, sign); - break; - default: + default: + UNREACHABLE(); + } + } + else if (t->get_family_id() == pb.get_fid()) { + NOT_IMPLEMENTED_YET(); + } + else { UNREACHABLE(); } } From 8b7bafbd9f714dca95e7b839173a61fc0651de57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Jan 2017 21:23:53 -0800 Subject: [PATCH 0016/1283] updates Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 31 +++++- src/sat/card_extension.cpp | 29 ++++- src/sat/card_extension.h | 3 +- src/sat/sat_extension.h | 2 + src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 16 ++- src/sat/sat_solver.h | 3 +- src/sat/sat_solver/inc_sat_solver.cpp | 14 ++- src/sat/tactic/goal2sat.cpp | 151 +++++++++++++++++++++++--- 9 files changed, 221 insertions(+), 29 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 37c87cd5b..6ba55d12a 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -49,6 +49,7 @@ struct pb2bv_rewriter::imp { expr_ref_vector m_args; rational m_k; vector m_coeffs; + bool m_enable_card; template expr_ref mk_le_ge(expr_ref_vector& fmls, expr* a, expr* b, expr* bound) { @@ -238,12 +239,13 @@ struct pb2bv_rewriter::imp { pb(m), bv(m), m_trail(m), - m_args(m) + m_args(m), + m_enable_card(false) {} bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { - if (f->get_family_id() == pb.get_family_id()) { - mk_pb(full, f, sz, args, result); + if (f->get_family_id() == pb.get_family_id() && mk_pb(full, f, sz, args, result)) { + // skip } else if (au.is_le(f) && is_pb(args[0], args[1])) { result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); @@ -349,29 +351,36 @@ struct pb2bv_rewriter::imp { return false; } - void mk_pb(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { + bool mk_pb(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { SASSERT(f->get_family_id() == pb.get_family_id()); + std::cout << "card: " << m_enable_card << "\n"; if (is_or(f)) { result = m.mk_or(sz, args); } else if (pb.is_at_most_k(f) && pb.get_k(f).is_unsigned()) { + if (m_enable_card) return false; result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_at_least_k(f) && pb.get_k(f).is_unsigned()) { + if (m_enable_card) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + if (m_enable_card) return false; result = m_sort.eq(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + if (m_enable_card) return false; result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { + if (m_enable_card) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } else { result = mk_bv(f, sz, args); } + return true; } // definitions used for sorting network @@ -396,6 +405,12 @@ struct pb2bv_rewriter::imp { void mk_clause(unsigned n, literal const* lits) { m_imp.m_lemmas.push_back(mk_or(m, n, lits)); } + + void enable_card(bool f) { + std::cout << "set " << f << "\n"; + m_enable_card = f; + m_enable_card = true; + } }; struct card2bv_rewriter_cfg : public default_rewriter_cfg { @@ -407,6 +422,7 @@ struct pb2bv_rewriter::imp { return m_r.mk_app_core(f, num, args, result); } card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {} + void enable_card(bool f) { m_r.enable_card(f); } }; class card_pb_rewriter : public rewriter_tpl { @@ -415,6 +431,7 @@ struct pb2bv_rewriter::imp { card_pb_rewriter(imp& i, ast_manager & m): rewriter_tpl(m, false, m_cfg), m_cfg(i, m) {} + void enable_card(bool f) { m_cfg.enable_card(f); } }; card_pb_rewriter m_rw; @@ -424,9 +441,13 @@ struct pb2bv_rewriter::imp { m_fresh(m), m_num_translated(0), m_rw(*this, m) { + m_rw.enable_card(p.get_bool("cardinality_solver", false)); } - void updt_params(params_ref const & p) {} + void updt_params(params_ref const & p) { + m_params.append(p); + m_rw.enable_card(m_params.get_bool("cardinality_solver", false)); + } unsigned get_num_steps() const { return m_rw.get_num_steps(); } void cleanup() { m_rw.cleanup(); } void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 2af1a5b5e..756e9642c 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -144,12 +144,14 @@ namespace sat { } void card_extension::watch_literal(card& c, literal lit) { + TRACE("sat", tout << "watch: " << lit << "\n";); init_watch(lit.var()); ptr_vector* cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; if (cards == 0) { cards = alloc(ptr_vector); m_var_infos[lit.var()].m_lit_watch[lit.sign()] = cards; } + TRACE("sat", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); cards->push_back(&c); } @@ -436,7 +438,9 @@ namespace sat { return p; } - card_extension::card_extension(): m_solver(0) {} + card_extension::card_extension(): m_solver(0) { + TRACE("sat", tout << this << "\n";); + } card_extension::~card_extension() { for (unsigned i = 0; i < m_var_infos.size(); ++i) { @@ -537,7 +541,10 @@ namespace sat { void card_extension::asserted(literal l) { bool_var v = l.var(); + if (v >= m_var_infos.size()) return; ptr_vector* cards = m_var_infos[v].m_lit_watch[!l.sign()]; + TRACE("sat", tout << "retrieve: " << v << " " << !l.sign() << "\n";); + TRACE("sat", tout << "asserted: " << l << " " << (cards ? "non-empty" : "empty") << "\n";); if (cards != 0 && !cards->empty() && !s().inconsistent()) { ptr_vector::iterator it = cards->begin(), it2 = it, end = cards->end(); for (; it != end; ++it) { @@ -545,7 +552,7 @@ namespace sat { if (value(c.lit()) != l_true) { continue; } - switch (add_assign(c, l)) { + switch (add_assign(c, ~l)) { case l_false: // conflict for (; it != end; ++it, ++it2) { *it2 = *it; @@ -579,6 +586,7 @@ namespace sat { } void card_extension::pop(unsigned n) { + TRACE("sat", tout << "pop:" << n << "\n";); unsigned new_lim = m_var_lim.size() - n; unsigned sz = m_var_lim[new_lim]; while (m_var_trail.size() > sz) { @@ -598,6 +606,21 @@ namespace sat { void card_extension::clauses_modifed() {} lbool card_extension::get_phase(bool_var v) { return l_undef; } + extension* card_extension::copy(solver* s) { + card_extension* result = alloc(card_extension); + result->set_solver(s); + for (unsigned i = 0; i < m_constraints.size(); ++i) { + literal_vector lits; + card& c = *m_constraints[i]; + for (unsigned i = 0; i < c.size(); ++i) { + lits.push_back(c[i]); + } + result->add_at_least(c.lit().var(), lits, c.k()); + } + return result; + } + + void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { watch const* w = m_var_infos[v].m_lit_watch[sign]; if (w) { @@ -647,7 +670,7 @@ namespace sat { for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { card* c = m_var_infos[vi].m_card; if (c) { - display(out, *c, true); + display(out, *c, false); } } return out; diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 1593ef26f..5c3f1e293 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -139,7 +139,7 @@ namespace sat { public: card_extension(); virtual ~card_extension(); - void set_solver(solver* s) { m_solver = s; } + virtual void set_solver(solver* s) { m_solver = s; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); virtual void propagate(literal l, ext_constraint_idx idx, bool & keep); virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r); @@ -152,6 +152,7 @@ namespace sat { virtual lbool get_phase(bool_var v); virtual std::ostream& display(std::ostream& out) const; virtual void collect_statistics(statistics& st) const; + virtual extension* copy(solver* s); }; }; diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index f1a48c0a8..c065e132e 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -32,6 +32,7 @@ namespace sat { class extension { public: virtual ~extension() {} + virtual void set_solver(solver* s) = 0; virtual void propagate(literal l, ext_constraint_idx idx, bool & keep) = 0; virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0; virtual void asserted(literal l) = 0; @@ -43,6 +44,7 @@ namespace sat { virtual lbool get_phase(bool_var v) = 0; virtual std::ostream& display(std::ostream& out) const = 0; virtual void collect_statistics(statistics& st) const = 0; + virtual extension* copy(solver* s) = 0; }; }; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 60708fd5c..940fa8c45 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -23,4 +23,5 @@ def_module_params('sat', ('core.minimize', BOOL, False, 'minimize computed core'), ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('parallel_threads', UINT, 1, 'number of parallel threads to use'), + ('cardinality_solver', BOOL, False, 'enable cardinality based solver'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 647c5f9ed..d4349d2c2 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -54,6 +54,7 @@ namespace sat { m_conflicts = 0; m_next_simplify = 0; m_num_checkpoints = 0; + if (m_ext) m_ext->set_solver(this); } solver::~solver() { @@ -84,13 +85,15 @@ namespace sat { VERIFY(v == mk_var(ext, dvar)); } } - unsigned sz = src.scope_lvl() == 0 ? src.m_trail.size() : src.m_scopes[0].m_trail_lim; - for (unsigned i = 0; i < sz; ++i) { - assign(src.m_trail[i], justification()); + { + unsigned sz = src.scope_lvl() == 0 ? src.m_trail.size() : src.m_scopes[0].m_trail_lim; + for (unsigned i = 0; i < sz; ++i) { + assign(src.m_trail[i], justification()); + } } + // copy binary clauses { - // copy binary clauses unsigned sz = src.m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { literal l = ~to_literal(l_idx); @@ -107,6 +110,7 @@ namespace sat { } } } + { literal_vector buffer; // copy clause @@ -120,6 +124,10 @@ namespace sat { mk_clause_core(buffer); } } + + if (src.get_extension()) { + m_ext = src.get_extension()->copy(this); + } } // ----------------------- diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b42acc680..25c823446 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -74,7 +74,7 @@ namespace sat { reslimit& m_rlimit; config m_config; stats m_stats; - extension * m_ext; + scoped_ptr m_ext; par* m_par; random_gen m_rand; clause_allocator m_cls_allocator; @@ -251,6 +251,7 @@ namespace sat { void set_par(par* p); bool canceled() { return !m_rlimit.inc(); } config const& get_config() { return m_config; } + extension* get_extension() const { return m_ext.get(); } typedef std::pair bin_clause; protected: watch_list & get_wlist(literal l) { return m_watches[l.index()]; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 65a7b021c..e20ca9583 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -20,6 +20,7 @@ Notes: #include "solver.h" #include "tactical.h" #include "sat_solver.h" +#include "card_extension.h" #include "tactic2solver.h" #include "aig_tactic.h" #include "propagate_values_tactic.h" @@ -35,6 +36,8 @@ Notes: #include "ast_translation.h" #include "ast_util.h" #include "propagate_values_tactic.h" +#include "sat_params.hpp" + // incremental SAT solver. class inc_sat_solver : public solver { @@ -68,7 +71,8 @@ class inc_sat_solver : public solver { typedef obj_map dep2asm_t; public: inc_sat_solver(ast_manager& m, params_ref const& p): - m(m), m_solver(p, m.limit(), 0), + m(m), + m_solver(p, m.limit(), alloc(sat::card_extension)), m_params(p), m_optimize_model(false), m_fmls(m), m_asmsf(m), @@ -79,6 +83,8 @@ public: m_dep_core(m), m_unknown("no reason given") { m_params.set_bool("elim_vars", false); + sat_params p1(m_params); + m_params.set_bool("cardinality_solver", p1.cardinality_solver()); m_solver.updt_params(m_params); init_preprocess(); } @@ -86,6 +92,7 @@ public: virtual ~inc_sat_solver() {} virtual solver* translate(ast_manager& dst_m, params_ref const& p) { + std::cout << "translate\n"; ast_translation tr(m, dst_m); if (m_num_scopes > 0) { throw default_exception("Cannot translate sat solver at non-base level"); @@ -210,8 +217,11 @@ public: sat::solver::collect_param_descrs(r); } virtual void updt_params(params_ref const & p) { - m_params = p; + m_params.append(p); + sat_params p1(p); + m_params.set_bool("cardinality_solver", p1.cardinality_solver()); m_params.set_bool("elim_vars", false); + std::cout << m_params << "\n"; m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 72340bc1c..41fb4dfce 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -37,6 +37,7 @@ Notes: #include"tactic.h" #include"ast_pp.h" #include"pb_decl_plugin.h" +#include"card_extension.h" #include struct goal2sat::imp { @@ -50,6 +51,7 @@ struct goal2sat::imp { }; ast_manager & m; pb_util pb; + sat::card_extension* m_ext; svector m_frame_stack; svector m_result_stack; obj_map m_cache; @@ -67,6 +69,7 @@ struct goal2sat::imp { imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external): m(_m), pb(m), + m_ext(0), m_solver(s), m_map(map), m_dep2asm(dep2asm), @@ -75,6 +78,11 @@ struct goal2sat::imp { m_default_external(default_external) { updt_params(p); m_true = sat::null_bool_var; + sat::extension* e = m_solver.get_extension(); + if (e) { + sat::card_extension* ce = dynamic_cast(e); + m_ext = ce; + } } void updt_params(params_ref const & p) { @@ -116,7 +124,7 @@ struct goal2sat::imp { return m_true; } - bool convert_atom(expr * t, bool root, bool sign) { + void convert_atom(expr * t, bool root, bool sign) { SASSERT(m.is_bool(t)); sat::literal l; sat::bool_var v = m_map.to_bool_var(t); @@ -147,15 +155,17 @@ struct goal2sat::imp { mk_clause(l); else m_result_stack.push_back(l); - return true; } bool convert_app(app* t, bool root, bool sign) { - return convert_atom(t, root, sign); - } - - bool convert_pb(app* t, bool root, bool sign) { - + if (m_ext && t->get_family_id() == pb.get_family_id()) { + m_frame_stack.push_back(frame(to_app(t), root, sign, 0)); + return false; + } + else { + convert_atom(t, root, sign); + return true; + } } bool process_cached(app * t, bool root, bool sign) { @@ -175,7 +185,8 @@ struct goal2sat::imp { bool visit(expr * t, bool root, bool sign) { if (!is_app(t)) { - return convert_atom(t, root, sign); + convert_atom(t, root, sign); + return true; } if (process_cached(to_app(t), root, sign)) return true; @@ -195,7 +206,10 @@ struct goal2sat::imp { m_frame_stack.push_back(frame(to_app(t), root, sign, 0)); return false; } - return convert_atom(t, root, sign); + else { + convert_atom(t, root, sign); + return true; + } case OP_XOR: case OP_IMPLIES: case OP_DISTINCT: { @@ -205,7 +219,8 @@ struct goal2sat::imp { throw_op_not_handled(strm.str()); } default: - return convert_atom(t, root, sign); + convert_atom(t, root, sign); + return true; } } @@ -361,6 +376,95 @@ struct goal2sat::imp { } } + void convert_pb_args(app* t, sat::literal_vector& lits) { + unsigned num_args = t->get_num_args(); + unsigned sz = m_result_stack.size(); + for (unsigned i = 0; i < num_args; ++i) { + sat::literal lit(m_result_stack[sz - num_args + i]); + if (!m_solver.is_external(lit.var())) { + sat::bool_var w = m_solver.mk_var(true); + sat::literal lit2(w, false); + mk_clause(lit, ~lit2); + mk_clause(~lit, lit2); + lit = lit2; + } + lits.push_back(lit); + } + } + + void convert_at_least_k(app* t, rational k, bool root, bool sign) { + SASSERT(k.is_unsigned()); + sat::literal_vector lits; + unsigned sz = m_result_stack.size(); + convert_pb_args(t, lits); + sat::bool_var v = m_solver.mk_var(true); + sat::literal lit(v, sign); + m_ext->add_at_least(v, lits, k.get_unsigned()); + TRACE("sat", tout << "root: " << root << " lit: " << lit << "\n";); + if (root) { + m_result_stack.reset(); + mk_clause(lit); + } + else { + m_result_stack.shrink(sz - t->get_num_args()); + m_result_stack.push_back(lit); + } + } + + void convert_at_most_k(app* t, rational k, bool root, bool sign) { + SASSERT(k.is_unsigned()); + sat::literal_vector lits; + unsigned sz = m_result_stack.size(); + convert_pb_args(t, lits); + for (unsigned i = 0; i < lits.size(); ++i) { + lits[i].neg(); + } + sat::bool_var v = m_solver.mk_var(true); + m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned() + 1); + if (root) { + m_result_stack.reset(); + mk_clause(sat::literal(v, sign)); + } + else { + m_result_stack.shrink(sz - t->get_num_args()); + m_result_stack.push_back(sat::literal(v, sign)); + } + } + + void convert_eq_k(app* t, rational k, bool root, bool sign) { + SASSERT(k.is_unsigned()); + sat::literal_vector lits; + convert_pb_args(t, lits); + sat::bool_var v1 = m_solver.mk_var(true); + sat::bool_var v2 = m_solver.mk_var(true); + sat::literal l1(v1, false), l2(v2, false); + m_ext->add_at_least(v1, lits, k.get_unsigned()); + for (unsigned i = 0; i < lits.size(); ++i) { + lits[i].neg(); + } + m_ext->add_at_least(v2, lits, lits.size() - k.get_unsigned() + 1); + if (root) { + m_result_stack.reset(); + if (sign) { + mk_clause(~l1, ~l2); + } + else { + mk_clause(l1); + mk_clause(l2); + } + m_result_stack.reset(); + } + else { + sat::bool_var v = m_solver.mk_var(); + sat::literal l(v, false); + mk_clause(~l, l1); + mk_clause(~l, l2); + mk_clause(~l1, ~l2, l); + m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); + m_result_stack.push_back(l); + } + } + void convert(app * t, bool root, bool sign) { if (t->get_family_id() == m.get_basic_family_id()) { switch (to_app(t)->get_decl_kind()) { @@ -376,13 +480,34 @@ struct goal2sat::imp { case OP_IFF: case OP_EQ: convert_iff(t, root, sign); - break; + break; default: UNREACHABLE(); } } - else if (t->get_family_id() == pb.get_fid()) { - NOT_IMPLEMENTED_YET(); + else if (m_ext && t->get_family_id() == pb.get_family_id()) { + switch (t->get_decl_kind()) { + case OP_AT_MOST_K: + convert_at_most_k(t, pb.get_k(t), root, sign); + break; + case OP_AT_LEAST_K: + convert_at_least_k(t, pb.get_k(t), root, sign); + break; + case OP_PB_LE: + SASSERT(pb.has_unit_coefficients(t)); + convert_at_most_k(t, pb.get_k(t), root, sign); + break; + case OP_PB_GE: + SASSERT(pb.has_unit_coefficients(t)); + convert_at_least_k(t, pb.get_k(t), root, sign); + break; + case OP_PB_EQ: + SASSERT(pb.has_unit_coefficients(t)); + convert_eq_k(t, pb.get_k(t), root, sign); + break; + default: + UNREACHABLE(); + } } else { UNREACHABLE(); From c12ee4ea1a8bf9e5b1cb4de31a8157b25c2b6094 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jan 2017 06:45:19 -0800 Subject: [PATCH 0017/1283] memory allocate Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 2ce39e6fd..91e56c865 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -456,7 +456,7 @@ namespace sat { void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { unsigned index = m_constraints.size(); - card* c = new (memory::allocate(__FILE__,__LINE__, "card", card::get_obj_size(lits.size()))) card(index, literal(v, false), lits, k); + card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, literal(v, false), lits, k); m_constraints.push_back(c); init_watch(v); m_var_infos[v].m_card = c; From 9f461dbe7b6d48632f8d25973fcdf27c81918622 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jan 2017 06:46:01 -0800 Subject: [PATCH 0018/1283] local Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 2ce39e6fd..a8c1bcb8d 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -159,6 +159,7 @@ namespace sat { } void card_extension::set_conflict(card& c, literal lit) { + std::cout << "conflict\n"; SASSERT(validate_conflict(c)); m_stats.m_num_conflicts++; @@ -689,8 +690,8 @@ namespace sat { } void card_extension::collect_statistics(statistics& st) const { - st.update("card propagations", m_stats.m_num_propagations); - st.update("card conflicts", m_stats.m_num_conflicts); + st.update("cardinality propagations", m_stats.m_num_propagations); + st.update("cardinality conflicts", m_stats.m_num_conflicts); } bool card_extension::validate_conflict(card& c) { From 7faa35ebdb6936f77a8f0120ec07feaaa047011e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jan 2017 18:47:30 -0800 Subject: [PATCH 0019/1283] fixing card Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 1 + src/sat/card_extension.cpp | 112 ++++++++++++++++++---------- src/sat/card_extension.h | 1 + src/sat/sat_solver.cpp | 8 +- 4 files changed, 78 insertions(+), 44 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 6ba55d12a..4c8f5d665 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -355,6 +355,7 @@ struct pb2bv_rewriter::imp { SASSERT(f->get_family_id() == pb.get_family_id()); std::cout << "card: " << m_enable_card << "\n"; if (is_or(f)) { + if (m_enable_card) return false; result = m.mk_or(sz, args); } else if (pb.is_at_most_k(f) && pb.get_k(f).is_unsigned()) { diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index ac11e2f71..1950a8d84 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -159,23 +159,19 @@ namespace sat { } void card_extension::set_conflict(card& c, literal lit) { - std::cout << "conflict\n"; SASSERT(validate_conflict(c)); - m_stats.m_num_conflicts++; if (!resolve_conflict(c, lit)) { - - literal_vector& lits = get_literals(); - SASSERT(value(lit) == l_false); - SASSERT(value(c.lit()) == l_true); - lits.push_back(~c.lit()); - lits.push_back(lit); + + m_conflict.reset(); + m_conflict.push_back(~c.lit()); unsigned sz = c.size(); for (unsigned i = c.k(); i < sz; ++i) { - SASSERT(value(c[i]) == l_false); - lits.push_back(c[i]); + m_conflict.push_back(c[i]); } - s().mk_clause_core(lits.size(), lits.c_ptr(), true); + m_conflict.push_back(lit); + SASSERT(validate_conflict(m_conflict)); + s().assign(lit, justification::mk_ext_justification(0)); } SASSERT(s().inconsistent()); } @@ -242,7 +238,7 @@ namespace sat { bool_var v; m_conflict_lvl = 0; - for (unsigned i = 0; i < c.size(); ++i) { + for (unsigned i = c.k(); i < c.size(); ++i) { literal lit = c[i]; SASSERT(value(lit) == l_false); m_conflict_lvl = std::max(m_conflict_lvl, lvl(lit)); @@ -276,6 +272,7 @@ namespace sat { } SASSERT(validate_lemma()); + SASSERT(offset > 0); js = s().m_justification[v]; @@ -284,17 +281,22 @@ namespace sat { int bound = 1; switch(js.get_kind()) { case justification::NONE: + //std::cout << "NONE\n"; + inc_coeff(consequent, offset); break; case justification::BINARY: + //std::cout << "BINARY\n"; inc_coeff(consequent, offset); - process_antecedent(~(js.get_literal()), offset); + process_antecedent((js.get_literal()), offset); break; case justification::TERNARY: + //std::cout << "TERNARY\n"; inc_coeff(consequent, offset); - process_antecedent(~(js.get_literal1()), offset); - process_antecedent(~(js.get_literal2()), offset); + process_antecedent((js.get_literal1()), offset); + process_antecedent((js.get_literal2()), offset); break; case justification::CLAUSE: { + //std::cout << "CLAUSE\n"; inc_coeff(consequent, offset); clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); unsigned i = 0; @@ -303,15 +305,16 @@ namespace sat { i = 1; } else { - process_antecedent(~c[0], offset); + process_antecedent(c[0], offset); i = 2; } - unsigned sz = c.size(); + unsigned sz = c.size(); for (; i < sz; i++) - process_antecedent(~c[i], offset); + process_antecedent(c[i], offset); break; } case justification::EXT_JUSTIFICATION: { + //std::cout << "CARDINALITY\n"; unsigned index = js.get_ext_justification_idx(); card& c2 = *m_constraints[index]; process_card(c2, offset); @@ -365,7 +368,6 @@ namespace sat { alit = get_asserting_literal(~consequent); slack -= get_abs_coeff(alit.var()); - m_conflict.push_back(alit); for (unsigned i = lits.size(); 0 <= slack && i > 0; ) { --i; @@ -383,10 +385,13 @@ namespace sat { } } } + m_conflict.push_back(alit); SASSERT(slack < 0); SASSERT(validate_conflict(m_conflict)); - s().mk_clause_core(m_conflict.size(), m_conflict.c_ptr(), true); + // std::cout << alit << ": " << m_conflict << "\n"; + s().assign(alit, justification::mk_ext_justification(0)); + // s().mk_clause_core(m_conflict.size(), m_conflict.c_ptr(), true); return true; bail_out: @@ -444,6 +449,7 @@ namespace sat { card_extension::card_extension(): m_solver(0) { TRACE("sat", tout << this << "\n";); + m_constraints.push_back(0); // dummy constraint for conflicts } card_extension::~card_extension() { @@ -469,20 +475,29 @@ namespace sat { } void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { - card& c = *m_constraints[idx]; - - DEBUG_CODE( - bool found = false; - for (unsigned i = 0; !found && i < c.k(); ++i) { - found = c[i] == l; + if (idx == 0) { + SASSERT(m_conflict.back() == l); + for (unsigned i = 0; i + 1 < m_conflict.size(); ++i) { + SASSERT(value(m_conflict[i]) == l_false); + r.push_back(~m_conflict[i]); + } + } + else { + card& c = *m_constraints[idx]; + + DEBUG_CODE( + bool found = false; + for (unsigned i = 0; !found && i < c.k(); ++i) { + found = c[i] == l; + } + SASSERT(found);); + + r.push_back(c.lit()); + SASSERT(value(c.lit()) == l_true); + for (unsigned i = c.k(); i < c.size(); ++i) { + SASSERT(value(c[i]) == l_false); + r.push_back(~c[i]); } - SASSERT(found);); - - r.push_back(c.lit()); - SASSERT(value(c.lit()) == l_true); - for (unsigned i = c.k(); i < c.size(); ++i) { - SASSERT(value(c[i]) == l_false); - r.push_back(~c[i]); } } @@ -613,7 +628,8 @@ namespace sat { extension* card_extension::copy(solver* s) { card_extension* result = alloc(card_extension); result->set_solver(s); - for (unsigned i = 0; i < m_constraints.size(); ++i) { + result->m_constraints.push_back(0); + for (unsigned i = 1; i < m_constraints.size(); ++i) { literal_vector lits; card& c = *m_constraints[i]; for (unsigned i = 0; i < c.size(); ++i) { @@ -626,7 +642,6 @@ namespace sat { if (v != null_bool_var) { card* c = m_var_infos[v].m_card; card* c2 = m_constraints[c->index()]; - result->m_var_trail.reserve(v + 10); NOT_IMPLEMENTED_YET(); } } @@ -646,6 +661,13 @@ namespace sat { } } + void card_extension::display(std::ostream& out, ineq& ineq) const { + for (unsigned i = 0; i < ineq.m_lits.size(); ++i) { + out << ineq.m_coeffs[i] << "*" << ineq.m_lits[i] << " "; + } + out << ">= " << ineq.m_k << "\n"; + } + void card_extension::display(std::ostream& out, card& c, bool values) const { out << c.lit(); if (c.lit() != null_literal && values) { @@ -740,25 +762,26 @@ namespace sat { void card_extension::justification2pb(justification const& js, literal lit, unsigned offset, ineq& p) { switch (js.get_kind()) { case justification::NONE: - p.reset(0); + p.reset(offset); + p.push(lit, offset); break; case justification::BINARY: p.reset(offset); p.push(lit, offset); - p.push(~js.get_literal(), offset); + p.push(js.get_literal(), offset); break; case justification::TERNARY: p.reset(offset); p.push(lit, offset); - p.push(~(js.get_literal1()), offset); - p.push(~(js.get_literal2()), offset); + p.push(js.get_literal1(), offset); + p.push(js.get_literal2(), offset); break; case justification::CLAUSE: { p.reset(offset); clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) - p.push(~c[i], offset); + p.push(c[i], offset); break; } case justification::EXT_JUSTIFICATION: { @@ -822,6 +845,15 @@ namespace sat { coeffs.remove(lit.index()); } } + if (!coeffs.empty() || m_C.m_k > k) { + display(std::cout, m_A); + display(std::cout, m_B); + display(std::cout, m_C); + u_map::iterator it = coeffs.begin(), end = coeffs.end(); + for (; it != end; ++it) { + std::cout << to_literal(it->m_key) << ": " << it->m_value << "\n"; + } + } SASSERT(coeffs.empty()); SASSERT(m_C.m_k <= k); return true; diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index e1ed197d1..947f6e5d3 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -138,6 +138,7 @@ namespace sat { void justification2pb(justification const& j, literal lit, unsigned offset, ineq& p); bool validate_resolvent(); + void display(std::ostream& out, ineq& p) const; void display(std::ostream& out, card& c, bool values) const; void display_watch(std::ostream& out, bool_var v, bool sign) const; public: diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index ec224e6b8..3d36e0b53 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -565,7 +565,7 @@ namespace sat { while (m_qhead < m_trail.size()) { checkpoint(); m_cleaner.dec(); - SASSERT(!m_inconsistent); + if (m_inconsistent) return false; l = m_trail[m_qhead]; TRACE("sat_propagate", tout << "propagating: " << l << " " << m_justification[l.var()] << "\n";); m_qhead++; @@ -1682,7 +1682,7 @@ namespace sat { m_conflicts_since_restart++; m_conflicts_since_gc++; - m_conflict_lvl = get_max_lvl(m_not_l, m_conflict); + m_conflict_lvl = get_max_lvl(m_not_l == literal() ? m_not_l : ~m_not_l, m_conflict); TRACE("sat", tout << "conflict detected at level " << m_conflict_lvl << " for "; if (m_not_l == literal()) tout << "null literal\n"; else tout << m_not_l << "\n";); @@ -1710,7 +1710,7 @@ namespace sat { process_antecedent(m_not_l, num_marks); } - literal consequent = m_not_l; + literal consequent = m_not_l == null_literal ? m_not_l : ~m_not_l; justification js = m_conflict; do { @@ -2033,7 +2033,7 @@ namespace sat { } } - literal consequent = m_not_l; + literal consequent = m_not_l == null_literal ? m_not_l : ~m_not_l; justification js = m_conflict; From d889fcdca6432db36684a9de23626a659f7f5a8b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jan 2017 19:26:54 -0800 Subject: [PATCH 0020/1283] fix translation of <= Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 41fb4dfce..eb90edd3d 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -420,7 +420,7 @@ struct goal2sat::imp { lits[i].neg(); } sat::bool_var v = m_solver.mk_var(true); - m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned() + 1); + m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); if (root) { m_result_stack.reset(); mk_clause(sat::literal(v, sign)); @@ -442,7 +442,7 @@ struct goal2sat::imp { for (unsigned i = 0; i < lits.size(); ++i) { lits[i].neg(); } - m_ext->add_at_least(v2, lits, lits.size() - k.get_unsigned() + 1); + m_ext->add_at_least(v2, lits, lits.size() - k.get_unsigned()); if (root) { m_result_stack.reset(); if (sign) { From 669c01824205bd25df46c3c6b7141391eaa314b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Feb 2017 07:43:43 -0800 Subject: [PATCH 0021/1283] updates on cardinality solver Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 3 +- src/sat/card_extension.cpp | 67 ++++++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7abbd48ee..e2b01dd59 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -368,7 +368,8 @@ public: break; } remove_soft(core, asms); - is_sat = check_sat_hill_climb(asms); + //is_sat = check_sat_hill_climb(asms); + is_sat = l_true; } TRACE("opt", tout << "num cores: " << cores.size() << "\n"; diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 1950a8d84..c8503b46c 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -161,8 +161,7 @@ namespace sat { void card_extension::set_conflict(card& c, literal lit) { SASSERT(validate_conflict(c)); m_stats.m_num_conflicts++; - if (!resolve_conflict(c, lit)) { - + if (!resolve_conflict(c, lit)) { m_conflict.reset(); m_conflict.push_back(~c.lit()); unsigned sz = c.size(); @@ -366,15 +365,46 @@ namespace sat { slack += get_abs_coeff(v); } - alit = get_asserting_literal(~consequent); - slack -= get_abs_coeff(alit.var()); - - for (unsigned i = lits.size(); 0 <= slack && i > 0; ) { - --i; + ++idx; + alit = null_literal; +#if 0 + while (0 <= slack) { + literal lit = lits[idx]; + bool_var v = lit.var(); + if (m_active_vars.contains(v)) { + int coeff = get_coeff(v); + bool append = false; + if (coeff < 0 && !lit.sign()) { + slack += coeff; + append = true; + } + else if (coeff > 0 && lit.sign()) { + slack -= coeff; + append = true; + } + if (append) { + if (alit == null_literal) { + alit = ~lit; + } + else { + m_conflict.push_back(~lit); + } + } + } + SASSERT(idx > 0 || slack < 0); + --idx; + } + if (alit != null_literal) { + m_conflict.push_back(alit); + } +#else + for (unsigned i = 0; 0 <= slack; ++i) { + SASSERT(i <= idx); literal lit = lits[i]; bool_var v = lit.var(); - if (m_active_var_set.contains(v) && v != alit.var()) { + if (m_active_vars.contains(v)) { int coeff = get_coeff(v); + if (coeff < 0 && !lit.sign()) { slack += coeff; m_conflict.push_back(~lit); @@ -385,13 +415,20 @@ namespace sat { } } } - m_conflict.push_back(alit); + + if (!m_conflict.empty()) { + alit = m_conflict.back(); + } +#endif + + if (m_conflict.empty()) { + IF_VERBOSE(0, verbose_stream() << "(empty conflict)\n";); + return false; + } SASSERT(slack < 0); SASSERT(validate_conflict(m_conflict)); - - // std::cout << alit << ": " << m_conflict << "\n"; + s().assign(alit, justification::mk_ext_justification(0)); - // s().mk_clause_core(m_conflict.size(), m_conflict.c_ptr(), true); return true; bail_out: @@ -399,6 +436,7 @@ namespace sat { v = lits[idx].var(); if (s().is_marked(v)) { s().reset_mark(v); + --m_num_marks; } --idx; } @@ -561,7 +599,8 @@ namespace sat { void card_extension::asserted(literal l) { bool_var v = l.var(); if (v >= m_var_infos.size()) return; - ptr_vector* cards = m_var_infos[v].m_lit_watch[!l.sign()]; + var_info& vinfo = m_var_infos[v]; + ptr_vector* cards = vinfo.m_lit_watch[!l.sign()]; TRACE("sat", tout << "retrieve: " << v << " " << !l.sign() << "\n";); TRACE("sat", tout << "asserted: " << l << " " << (cards ? "non-empty" : "empty") << "\n";); if (cards != 0 && !cards->empty() && !s().inconsistent()) { @@ -592,7 +631,7 @@ namespace sat { cards->set_end(it2); } - card* crd = m_var_infos[v].m_card; + card* crd = vinfo.m_card; if (crd != 0 && !s().inconsistent()) { init_watch(*crd, !l.sign()); } From becce1d0433096bd11a2f644c4342490a9f9f281 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Feb 2017 12:09:16 -0800 Subject: [PATCH 0022/1283] local Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 8 -------- src/sat/sat_solver.cpp | 14 +++++++++----- src/sat/sat_solver.h | 1 + 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index c8503b46c..afa768863 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -676,14 +676,6 @@ namespace sat { } result->add_at_least(c.lit().var(), lits, c.k()); } - for (unsigned i = 0; i < m_var_trail.size(); ++i) { - bool_var v = m_var_trail[i]; - if (v != null_bool_var) { - card* c = m_var_infos[v].m_card; - card* c2 = m_constraints[c->index()]; - NOT_IMPLEMENTED_YET(); - } - } return result; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3d36e0b53..8326235d9 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -75,7 +75,7 @@ namespace sat { void solver::copy(solver const & src) { pop_to_base_level(); SASSERT(m_mc.empty() && src.m_mc.empty()); - SASSERT(scope_lvl() == 0); + SASSERT(at_search_lvl()); // create new vars if (num_vars() < src.num_vars()) { for (bool_var v = num_vars(); v < src.num_vars(); v++) { @@ -85,8 +85,15 @@ namespace sat { VERIFY(v == mk_var(ext, dvar)); } } + // + // register the extension before performing assignments. + // the assignments may call back into the extension. + // + if (src.get_extension()) { + m_ext = src.get_extension()->copy(this); + } { - unsigned sz = src.scope_lvl() == 0 ? src.m_trail.size() : src.m_scopes[0].m_trail_lim; + unsigned sz = scope_lvl() == 0 ? src.m_trail.size() : src.m_scopes[0].m_trail_lim; for (unsigned i = 0; i < sz; ++i) { assign(src.m_trail[i], justification()); } @@ -125,9 +132,6 @@ namespace sat { } } - if (src.get_extension()) { - m_ext = src.get_extension()->copy(this); - } m_user_scope_literals.reset(); m_user_scope_literals.append(src.m_user_scope_literals); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 25c823446..e17c9e3bf 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -220,6 +220,7 @@ namespace sat { bool is_external(bool_var v) const { return m_external[v] != 0; } bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } unsigned scope_lvl() const { return m_scope_lvl; } + bool at_search_lvl() const { return m_scope_lvl == 0; } lbool value(literal l) const { return static_cast(m_assignment[l.index()]); } lbool value(bool_var v) const { return static_cast(m_assignment[literal(v, false).index()]); } unsigned lvl(bool_var v) const { return m_level[v]; } From e9e0293d1aa58981ab1a545350bba829c0040b9d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Feb 2017 10:19:51 -0800 Subject: [PATCH 0023/1283] local updates Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 2 -- src/opt/maxres.cpp | 6 ++++-- src/sat/sat_solver.cpp | 4 ---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 4c8f5d665..1dd4ea6fa 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -353,7 +353,6 @@ struct pb2bv_rewriter::imp { bool mk_pb(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { SASSERT(f->get_family_id() == pb.get_family_id()); - std::cout << "card: " << m_enable_card << "\n"; if (is_or(f)) { if (m_enable_card) return false; result = m.mk_or(sz, args); @@ -408,7 +407,6 @@ struct pb2bv_rewriter::imp { } void enable_card(bool f) { - std::cout << "set " << f << "\n"; m_enable_card = f; m_enable_card = true; } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index e2b01dd59..50464b570 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -345,6 +345,9 @@ public: while (is_sat == l_false) { core.reset(); s().get_unsat_core(core); + //expr_ref_vector core1(m); + //core1.append(core.size(), core.c_ptr()); + //std::cout << core1 << "\n"; // verify_core(core); model_ref mdl; get_mus_model(mdl); @@ -368,8 +371,7 @@ public: break; } remove_soft(core, asms); - //is_sat = check_sat_hill_climb(asms); - is_sat = l_true; + is_sat = check_sat_hill_climb(asms); } TRACE("opt", tout << "num cores: " << cores.size() << "\n"; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 44e0459f3..3aee7e8ad 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -136,7 +136,6 @@ namespace sat { m_user_scope_literals.reset(); m_user_scope_literals.append(src.m_user_scope_literals); - std::cout << "copy: " << init_trail_size() << " " << src.init_trail_size() << "\n"; } // ----------------------- @@ -1152,9 +1151,6 @@ namespace sat { } void solver::reinit_assumptions() { - if (at_search_lvl()) { - std::cout << " " << init_trail_size() << " " << m_trail.size() << "\n"; - } if (tracking_assumptions() && at_base_lvl()) { TRACE("sat", tout << m_assumptions << "\n";); push(); From 505133a4b3eebca15d3a93125ab24283de5fc3e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Feb 2017 17:06:15 -0800 Subject: [PATCH 0024/1283] debugging card Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 23 ++++++++++++++++------- src/sat/sat_solver.cpp | 16 +++++++++++++--- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index afa768863..712162e44 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -234,9 +234,8 @@ namespace sat { } bool card_extension::resolve_conflict(card& c, literal alit) { - bool_var v; - m_conflict_lvl = 0; + m_conflict_lvl = lvl(~alit); for (unsigned i = c.k(); i < c.size(); ++i) { literal lit = c[i]; SASSERT(value(lit) == l_false); @@ -245,6 +244,7 @@ namespace sat { if (m_conflict_lvl < lvl(c.lit()) || m_conflict_lvl == 0) { return false; } + std::cout << "conflict level: " << m_conflict_lvl << " " << lvl(~alit) << "\n"; reset_coeffs(); m_num_marks = 0; @@ -351,10 +351,11 @@ namespace sat { --m_num_marks; } + DEBUG_CODE(for (bool_var i = 0; i < static_cast(s().num_vars()); ++i) SASSERT(!s().is_marked(i));); SASSERT(validate_lemma()); normalize_active_coeffs(); - + if (m_bound > 0 && m_active_vars.empty()) { return false; } @@ -367,11 +368,13 @@ namespace sat { ++idx; alit = null_literal; -#if 0 +#if 1 + std::cout << c.size() << " >= " << c.k() << "\n"; + std::cout << m_active_vars.size() << ": " << slack + m_bound << " >= " << m_bound << "\n"; while (0 <= slack) { literal lit = lits[idx]; bool_var v = lit.var(); - if (m_active_vars.contains(v)) { + if (m_active_var_set.contains(v)) { int coeff = get_coeff(v); bool append = false; if (coeff < 0 && !lit.sign()) { @@ -394,6 +397,9 @@ namespace sat { SASSERT(idx > 0 || slack < 0); --idx; } + if (alit == null_literal) { + return false; + } if (alit != null_literal) { m_conflict.push_back(alit); } @@ -402,7 +408,7 @@ namespace sat { SASSERT(i <= idx); literal lit = lits[i]; bool_var v = lit.var(); - if (m_active_vars.contains(v)) { + if (m_active_var_set.contains(v)) { int coeff = get_coeff(v); if (coeff < 0 && !lit.sign()) { @@ -514,6 +520,7 @@ namespace sat { void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { if (idx == 0) { + std::cout << "antecedents0: " << l << " " << m_conflict.size() << "\n"; SASSERT(m_conflict.back() == l); for (unsigned i = 0; i + 1 < m_conflict.size(); ++i) { SASSERT(value(m_conflict[i]) == l_false); @@ -529,7 +536,8 @@ namespace sat { found = c[i] == l; } SASSERT(found);); - + + std::cout << "antecedents: " << idx << ": " << l << " " << c.size() - c.k() + 1 << "\n"; r.push_back(c.lit()); SASSERT(value(c.lit()) == l_true); for (unsigned i = c.k(); i < c.size(); ++i) { @@ -834,6 +842,7 @@ namespace sat { // validate that m_A & m_B implies m_C bool card_extension::validate_resolvent() { + std::cout << "validate resolvent\n"; u_map coeffs; unsigned k = m_A.m_k + m_B.m_k; for (unsigned i = 0; i < m_A.m_lits.size(); ++i) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f7f8bfa54..6eafd8906 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1726,12 +1726,13 @@ namespace sat { m_lemma.push_back(null_literal); unsigned num_marks = 0; + literal consequent = null_literal; if (m_not_l != null_literal) { TRACE("sat_conflict", tout << "not_l: " << m_not_l << "\n";); process_antecedent(m_not_l, num_marks); + consequent = ~m_not_l; } - literal consequent = m_not_l; justification js = m_conflict; do { @@ -1900,11 +1901,12 @@ namespace sat { } m_lemma.reset(); m_lemma.push_back(null_literal); // asserted literal + literal consequent = null_literal; if (m_not_l != null_literal) { TRACE("sat", tout << "not_l: " << m_not_l << "\n";); process_antecedent_for_init(m_not_l); + consequent = ~m_not_l; } - literal consequent = m_not_l; justification js = m_conflict; SASSERT(m_trail.size() > 0); @@ -2008,6 +2010,7 @@ namespace sat { } + static int count = 0; void solver::resolve_conflict_for_unsat_core() { TRACE("sat", display(tout); unsigned level = 0; @@ -2039,6 +2042,7 @@ namespace sat { unsigned old_size = m_unmark.size(); int idx = skip_literals_above_conflict_level(); + literal consequent = m_not_l; if (m_not_l != null_literal) { justification js = m_justification[m_not_l.var()]; TRACE("sat", tout << "not_l: " << m_not_l << "\n"; @@ -2052,9 +2056,9 @@ namespace sat { else { process_consequent_for_unsat_core(m_not_l, js); } + consequent = ~m_not_l; } - literal consequent = m_not_l; justification js = m_conflict; while (true) { @@ -2093,6 +2097,9 @@ namespace sat { set_model(m_mus.get_model()); IF_VERBOSE(2, verbose_stream() << "(sat.core: " << m_core << ")\n";); } + + ++count; + SASSERT(count == 1); } @@ -2116,6 +2123,9 @@ namespace sat { literal_vector::iterator end = m_ext_antecedents.end(); for (; it != end; ++it) r = std::max(r, lvl(*it)); + if (true || r != scope_lvl() || r != lvl(not_l)) { + std::cout << "get max level " << r << " scope level " << scope_lvl() << " lvl(l): " << lvl(not_l) << "\n"; + } return r; } default: From 0b711c5ef8391c48fa906aa581232712860821c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Feb 2017 15:41:08 -0800 Subject: [PATCH 0025/1283] adding drat Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 1 + src/opt/maxres.cpp | 6 +- src/sat/card_extension.cpp | 126 +++++++++++++++++++------- src/sat/card_extension.h | 6 +- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 2 +- src/sat/sat_drat.cpp | 67 ++++++++++++++ src/sat/sat_drat.h | 41 +++++++++ src/sat/sat_extension.h | 1 + src/sat/sat_params.pyg | 3 +- src/sat/sat_solver.cpp | 41 +++++++-- src/sat/sat_solver.h | 3 + src/sat/sat_solver/inc_sat_solver.cpp | 6 +- src/sat/tactic/goal2sat.cpp | 4 +- 14 files changed, 255 insertions(+), 53 deletions(-) create mode 100644 src/sat/sat_drat.cpp create mode 100644 src/sat/sat_drat.h diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index 41051fd40..6ffbb8c71 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -8,6 +8,7 @@ z3_add_component(sat sat_clause_use_list.cpp sat_cleaner.cpp sat_config.cpp + sat_drat.cpp sat_elim_eqs.cpp sat_iff3_finder.cpp sat_integrity_checker.cpp diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index c4929d35b..6c8d5af3a 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -352,9 +352,9 @@ public: while (is_sat == l_false) { core.reset(); s().get_unsat_core(core); - //expr_ref_vector core1(m); - //core1.append(core.size(), core.c_ptr()); - //std::cout << core1 << "\n"; + expr_ref_vector core1(m); + core1.append(core.size(), core.c_ptr()); + std::cout << core1 << "\n"; // verify_core(core); model_ref mdl; get_mus_model(mdl); diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 712162e44..2bcccfb1a 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -94,7 +94,7 @@ namespace sat { alit = c[j]; } } - set_conflict(c, alit); + set_conflict(c); } else if (j == bound) { for (unsigned i = 0; i < bound && !s().inconsistent(); ++i) { @@ -136,32 +136,40 @@ namespace sat { } void card_extension::assign(card& c, literal lit) { - if (value(lit) == l_true) { - return; + switch (value(lit)) { + case l_true: + break; + case l_false: + set_conflict(c); + break; + default: + m_stats.m_num_propagations++; + //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); + SASSERT(validate_unit_propagation(c)); + s().assign(lit, justification::mk_ext_justification(c.index())); + break; } - m_stats.m_num_propagations++; - //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); - SASSERT(validate_unit_propagation(c)); - s().assign(lit, justification::mk_ext_justification(c.index())); - } void card_extension::watch_literal(card& c, literal lit) { - TRACE("sat", tout << "watch: " << lit << "\n";); + TRACE("sat_verbose", tout << "watch: " << lit << "\n";); init_watch(lit.var()); ptr_vector* cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; if (cards == 0) { cards = alloc(ptr_vector); m_var_infos[lit.var()].m_lit_watch[lit.sign()] = cards; } - TRACE("sat", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); + TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); cards->push_back(&c); } - void card_extension::set_conflict(card& c, literal lit) { + void card_extension::set_conflict(card& c) { + TRACE("sat", display(tout, c, true); ); SASSERT(validate_conflict(c)); m_stats.m_num_conflicts++; - if (!resolve_conflict(c, lit)) { + literal lit = last_false_literal(c); + if (!resolve_conflict(c, lit)) { + TRACE("sat", tout << "bail out conflict resolution\n";); m_conflict.reset(); m_conflict.push_back(~c.lit()); unsigned sz = c.size(); @@ -169,11 +177,40 @@ namespace sat { m_conflict.push_back(c[i]); } m_conflict.push_back(lit); - SASSERT(validate_conflict(m_conflict)); + // SASSERT(validate_conflict(m_conflict)); s().assign(lit, justification::mk_ext_justification(0)); } SASSERT(s().inconsistent()); } + + literal card_extension::last_false_literal(card& c) { + while (!m_active_var_set.empty()) m_active_var_set.erase(); + reset_coeffs(); + for (unsigned i = 0; i < c.size(); ++i) { + bool_var v = c[i].var(); + m_active_var_set.insert(v); + m_active_vars.push_back(v); + m_coeffs.setx(v, c[i].sign() ? -1 : 1, 0); + } + literal_vector const& lits = s().m_trail; + for (unsigned i = lits.size(); i > 0; ) { + --i; + literal lit = lits[i]; + bool_var v = lit.var(); + if (m_active_var_set.contains(v) && + (m_coeffs[v] > 0 == lits[i].sign())) { + //std::cout << "last literal: " << lit << "\n"; + for (unsigned j = 0; j < c.size(); ++j) { + if (~lit == c[j] && j != c.k()-1) { + // std::cout << "POSITION " << j << " bound " << c.k() << "\n"; + } + } + return ~lit; + } + } + UNREACHABLE(); + return null_literal; + } void card_extension::normalize_active_coeffs() { while (!m_active_var_set.empty()) m_active_var_set.erase(); @@ -244,7 +281,7 @@ namespace sat { if (m_conflict_lvl < lvl(c.lit()) || m_conflict_lvl == 0) { return false; } - std::cout << "conflict level: " << m_conflict_lvl << " " << lvl(~alit) << "\n"; + // std::cout << "conflict level: " << m_conflict_lvl << " " << lvl(~alit) << "\n"; reset_coeffs(); m_num_marks = 0; @@ -263,6 +300,8 @@ namespace sat { v = consequent.var(); int offset = get_abs_coeff(v); + // TRACE("sat", display(tout, m_A);); + if (offset == 0) { goto process_next_resolvent; } @@ -365,12 +404,14 @@ namespace sat { bool_var v = m_active_vars[i]; slack += get_abs_coeff(v); } + + TRACE("sat", display(tout, m_A);); ++idx; alit = null_literal; #if 1 - std::cout << c.size() << " >= " << c.k() << "\n"; - std::cout << m_active_vars.size() << ": " << slack + m_bound << " >= " << m_bound << "\n"; + // std::cout << c.size() << " >= " << c.k() << "\n"; + // std::cout << m_active_vars.size() << ": " << slack + m_bound << " >= " << m_bound << "\n"; while (0 <= slack) { literal lit = lits[idx]; bool_var v = lit.var(); @@ -432,7 +473,9 @@ namespace sat { return false; } SASSERT(slack < 0); - SASSERT(validate_conflict(m_conflict)); + SASSERT(validate_conflict(m_conflict, m_A)); + + TRACE("sat", tout << m_conflict << "\n";); s().assign(alit, justification::mk_ext_justification(0)); return true; @@ -520,7 +563,7 @@ namespace sat { void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { if (idx == 0) { - std::cout << "antecedents0: " << l << " " << m_conflict.size() << "\n"; + // std::cout << "antecedents0: " << l << " " << m_conflict.size() << "\n"; SASSERT(m_conflict.back() == l); for (unsigned i = 0; i + 1 < m_conflict.size(); ++i) { SASSERT(value(m_conflict[i]) == l_false); @@ -537,7 +580,7 @@ namespace sat { } SASSERT(found);); - std::cout << "antecedents: " << idx << ": " << l << " " << c.size() - c.k() + 1 << "\n"; + // std::cout << "antecedents: " << idx << ": " << l << " " << c.size() - c.k() + 1 << "\n"; r.push_back(c.lit()); SASSERT(value(c.lit()) == l_true); for (unsigned i = c.k(); i < c.size(); ++i) { @@ -552,7 +595,7 @@ namespace sat { // literal is assigned to false. unsigned sz = c.size(); unsigned bound = c.k(); - TRACE("sat", tout << "assign: " << c.lit() << " " << ~alit << " " << bound << "\n";); + TRACE("sat", tout << "assign: " << c.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); SASSERT(0 < bound && bound < sz); SASSERT(value(alit) == l_false); @@ -583,11 +626,11 @@ namespace sat { // conflict if (bound != index && value(c[bound]) == l_false) { TRACE("sat", tout << "conflict " << c[bound] << " " << alit << "\n";); - set_conflict(c, alit); + set_conflict(c); return l_false; } - TRACE("sat", tout << "no swap " << index << " " << alit << "\n";); + // TRACE("sat", tout << "no swap " << index << " " << alit << "\n";); // there are no literals to swap with, // prepare for unit propagation by swapping the false literal into // position bound. Then literals in positions 0..bound-1 have to be @@ -609,8 +652,8 @@ namespace sat { if (v >= m_var_infos.size()) return; var_info& vinfo = m_var_infos[v]; ptr_vector* cards = vinfo.m_lit_watch[!l.sign()]; - TRACE("sat", tout << "retrieve: " << v << " " << !l.sign() << "\n";); - TRACE("sat", tout << "asserted: " << l << " " << (cards ? "non-empty" : "empty") << "\n";); + //TRACE("sat", tout << "retrieve: " << v << " " << !l.sign() << "\n";); + //TRACE("sat", tout << "asserted: " << l << " " << (cards ? "non-empty" : "empty") << "\n";); if (cards != 0 && !cards->empty() && !s().inconsistent()) { ptr_vector::iterator it = cards->begin(), it2 = it, end = cards->end(); for (; it != end; ++it) { @@ -652,7 +695,7 @@ namespace sat { } void card_extension::pop(unsigned n) { - TRACE("sat", tout << "pop:" << n << "\n";); + TRACE("sat_verbose", tout << "pop:" << n << "\n";); unsigned new_lim = m_var_lim.size() - n; unsigned sz = m_var_lim[new_lim]; while (m_var_trail.size() > sz) { @@ -690,9 +733,9 @@ namespace sat { void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { watch const* w = m_var_infos[v].m_lit_watch[sign]; - if (w) { + if (w && !w->empty()) { watch const& wl = *w; - out << "watch: " << literal(v, sign) << " |-> "; + out << literal(v, sign) << " |-> "; for (unsigned i = 0; i < wl.size(); ++i) { out << wl[i]->lit() << " "; } @@ -708,7 +751,7 @@ namespace sat { } void card_extension::display(std::ostream& out, card& c, bool values) const { - out << c.lit(); + out << c.lit() << "[" << c.size() << "]"; if (c.lit() != null_literal && values) { out << "@(" << value(c.lit()); if (value(c.lit()) != l_undef) { @@ -750,6 +793,21 @@ namespace sat { return out; } + std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const { + if (idx == 0) { + out << "conflict: " << m_conflict; + } + else { + card& c = *m_constraints[idx]; + out << "bound " << c.lit() << ": "; + for (unsigned i = c.k(); i < c.size(); ++i) { + out << c[i] << " "; + } + out << ">= " << c.k(); + } + return out; + } + void card_extension::collect_statistics(statistics& st) const { st.update("cardinality propagations", m_stats.m_num_propagations); st.update("cardinality conflicts", m_stats.m_num_conflicts); @@ -842,7 +900,6 @@ namespace sat { // validate that m_A & m_B implies m_C bool card_extension::validate_resolvent() { - std::cout << "validate resolvent\n"; u_map coeffs; unsigned k = m_A.m_k + m_B.m_k; for (unsigned i = 0; i < m_A.m_lits.size(); ++i) { @@ -899,11 +956,18 @@ namespace sat { return true; } - bool card_extension::validate_conflict(literal_vector const& lits) { + bool card_extension::validate_conflict(literal_vector const& lits, ineq& p) { for (unsigned i = 0; i < lits.size(); ++i) { if (value(lits[i]) != l_false) return false; } - return true; + unsigned value = 0; + for (unsigned i = 0; i < p.m_lits.size(); ++i) { + unsigned coeff = p.m_coeffs[i]; + if (!lits.contains(p.m_lits[i])) { + value += coeff; + } + } + return value < p.m_k; } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 947f6e5d3..ac434ef5c 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -103,7 +103,8 @@ namespace sat { void assign(card& c, literal lit); lbool add_assign(card& c, literal lit); void watch_literal(card& c, literal lit); - void set_conflict(card& c, literal lit); + void set_conflict(card& c); + literal last_false_literal(card& c); void clear_watch(card& c); void reset_coeffs(); @@ -131,7 +132,7 @@ namespace sat { bool validate_assign(literal_vector const& lits, literal lit); bool validate_lemma(); bool validate_unit_propagation(card const& c); - bool validate_conflict(literal_vector const& lits); + bool validate_conflict(literal_vector const& lits, ineq& p); ineq m_A, m_B, m_C; void active2pb(ineq& p); @@ -156,6 +157,7 @@ namespace sat { virtual void clauses_modifed(); virtual lbool get_phase(bool_var v); virtual std::ostream& display(std::ostream& out) const; + virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); }; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 9206ea8bc..3e132c738 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -113,6 +113,7 @@ namespace sat { m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); + m_drat = p.drat(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 405cbd092..34983f451 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -73,7 +73,7 @@ namespace sat { bool m_dyn_sub_res; bool m_core_minimize; bool m_core_minimize_partial; - + bool m_drat; symbol m_always_true; symbol m_always_false; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp new file mode 100644 index 000000000..7e30c18ff --- /dev/null +++ b/src/sat/sat_drat.cpp @@ -0,0 +1,67 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_drat.cpp + +Abstract: + + Produce DRAT proofs. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-2-3 + +Notes: + +--*/ +#include "sat_solver.h" +#include "sat_drat.h" + + +namespace sat { + drat::drat(solver& s): + s(s), + m_out(0) + { + if (s.m_config.m_drat) { + m_out = alloc(std::ofstream, "proof.drat"); + } + } + + drat::~drat() { + dealloc(m_out); + } + void drat::add_empty() { + (*m_out) << "0\n"; + } + void drat::add_literal(literal l) { + (*m_out) << l << " 0\n"; + } + void drat::add_binary(literal l1, literal l2) { + (*m_out) << l1 << " " << l2 << " 0\n"; + } + void drat::add_ternary(literal l1, literal l2, literal l3) { + (*m_out) << l1 << " " << l2 << " " << l3 << " 0\n"; + } + void drat::add_clause(clause& c) { + unsigned sz = c.size(); + for (unsigned i = 0; i < sz; ++i) { + (*m_out) << c[i] << " "; + } + (*m_out) << "0\n"; + } + void drat::del_literal(literal l) { + (*m_out) << "d "; + add_literal(l); + } + void drat::del_binary(literal l1, literal l2) { + (*m_out) << "d "; + add_binary(l1, l2); + } + void drat::del_clause(clause& c) { + (*m_out) << "d "; + add_clause(c); + } +} diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h new file mode 100644 index 000000000..9d34c57b4 --- /dev/null +++ b/src/sat/sat_drat.h @@ -0,0 +1,41 @@ +/*++ +Copyright (c) 2014 Microsoft Corporation + +Module Name: + + sat_drat.h + +Abstract: + + Produce DRAT proofs. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-2-3 + +Notes: + +--*/ +#ifndef SAT_DRAT_H_ +#define SAT_DRAT_H_ + +namespace sat { + class drat { + solver& s; + std::ostream* m_out; + public: + drat(solver& s); + ~drat(); + void add_empty(); + void add_literal(literal l); + void add_binary(literal l1, literal l2); + void add_ternary(literal l1, literal l2, literal l3); + void add_clause(clause& c); + void del_literal(literal l); + void del_binary(literal l1, literal l2); + void del_clause(clause& c); + }; + +}; + +#endif diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index c065e132e..e8d92d085 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -43,6 +43,7 @@ namespace sat { virtual void clauses_modifed() = 0; virtual lbool get_phase(bool_var v) = 0; virtual std::ostream& display(std::ostream& out) const = 0; + virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; virtual void collect_statistics(statistics& st) const = 0; virtual extension* copy(solver* s) = 0; }; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 940fa8c45..feefe653f 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -24,4 +24,5 @@ def_module_params('sat', ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('parallel_threads', UINT, 1, 'number of parallel threads to use'), ('cardinality_solver', BOOL, False, 'enable cardinality based solver'), - ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'))) + ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), + ('drat', BOOL, False, 'produce DRAT proofs'),)) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 6eafd8906..54122c019 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -42,6 +42,7 @@ namespace sat { m_asymm_branch(*this, p), m_probing(*this, p), m_mus(*this), + m_drat(*this), m_inconsistent(false), m_num_frozen(0), m_activity_inc(128), @@ -199,7 +200,11 @@ namespace sat { } void solver::del_clause(clause& c) { - if (!c.is_learned()) m_stats.m_non_learned_generation++; + if (!c.is_learned()) { + m_stats.m_non_learned_generation++; + } else if (m_config.m_drat) { + m_drat.del_clause(c); + } m_cls_allocator.del_clause(&c); m_stats.m_del_clause++; } @@ -214,9 +219,10 @@ namespace sat { } ++m_stats.m_non_learned_generation; } - + switch (num_lits) { case 0: + if (m_config.m_drat) m_drat.add_empty(); set_conflict(justification()); return 0; case 1: @@ -233,6 +239,8 @@ namespace sat { } void solver::mk_bin_clause(literal l1, literal l2, bool learned) { + if (learned && m_config.m_drat) + m_drat.add_binary(l1, l2); if (propagate_bin_clause(l1, l2)) { if (at_base_lvl()) return; @@ -266,6 +274,8 @@ namespace sat { clause * solver::mk_ter_clause(literal * lits, bool learned) { + if (learned && m_config.m_drat) + m_drat.add_ternary(lits[0], lits[1], lits[2]); m_stats.m_mk_ter_clause++; clause * r = m_cls_allocator.mk_clause(3, lits, learned); bool reinit = attach_ter_clause(*r); @@ -309,8 +319,10 @@ namespace sat { SASSERT(!learned || r->is_learned()); bool reinit = attach_nary_clause(*r); if (reinit && !learned) push_reinit_stack(*r); - if (learned) + if (learned) { m_learned.push_back(r); + if (m_config.m_drat) m_drat.add_clause(*r); + } else m_clauses.push_back(r); return r; @@ -516,8 +528,10 @@ namespace sat { void solver::assign_core(literal l, justification j) { SASSERT(value(l) == l_undef); TRACE("sat_assign_core", tout << l << " " << j << " level: " << scope_lvl() << "\n";); - if (at_base_lvl()) + if (at_base_lvl()) { j = justification(); // erase justification for level 0 + if (m_config.m_drat) m_drat.add_literal(l); + } m_assignment[l.index()] = l_true; m_assignment[(~l).index()] = l_false; bool_var v = l.var(); @@ -2058,6 +2072,10 @@ namespace sat { } consequent = ~m_not_l; } + std::cout << "CONFLICT: " << m_core << "\n"; + display_status(std::cout); + ++count; + exit(0); justification js = m_conflict; @@ -2098,8 +2116,6 @@ namespace sat { IF_VERBOSE(2, verbose_stream() << "(sat.core: " << m_core << ")\n";); } - ++count; - SASSERT(count == 1); } @@ -2124,7 +2140,7 @@ namespace sat { for (; it != end; ++it) r = std::max(r, lvl(*it)); if (true || r != scope_lvl() || r != lvl(not_l)) { - std::cout << "get max level " << r << " scope level " << scope_lvl() << " lvl(l): " << lvl(not_l) << "\n"; + // std::cout << "get max level " << r << " scope level " << scope_lvl() << " lvl(l): " << lvl(not_l) << "\n"; } return r; } @@ -2862,12 +2878,14 @@ namespace sat { } void solver::display_units(std::ostream & out) const { - unsigned end = init_trail_size(); + unsigned end = m_trail.size(); // init_trail_size(); for (unsigned i = 0; i < end; i++) { out << m_trail[i] << " "; - } - if (end != 0) + display_justification(out, m_justification[m_trail[i].var()]); out << "\n"; + } + //if (end != 0) + // out << "\n"; } void solver::display(std::ostream & out) const { @@ -2886,6 +2904,9 @@ namespace sat { if (js.is_clause()) { out << *(m_cls_allocator.get_clause(js.get_clause_offset())); } + else if (js.is_ext_justification() && m_ext) { + m_ext->display_justification(out << " ", js.get_ext_justification_idx()); + } } unsigned solver::num_clauses() const { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 3702047d1..2ab9d5c50 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -33,6 +33,7 @@ Revision History: #include"sat_iff3_finder.h" #include"sat_probing.h" #include"sat_mus.h" +#include"sat_drat.h" #include"sat_par.h" #include"params.h" #include"statistics.h" @@ -87,6 +88,7 @@ namespace sat { asymm_branch m_asymm_branch; probing m_probing; mus m_mus; // MUS for minimal core extraction + drat m_drat; // DRAT for generating proofs bool m_inconsistent; // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a @@ -146,6 +148,7 @@ namespace sat { friend class probing; friend class iff3_finder; friend class mus; + friend class drat; friend class card_extension; friend struct mk_stat; public: diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 69e624337..7715c4b5d 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -208,7 +208,7 @@ public: } virtual ast_manager& get_manager() const { return m; } virtual void assert_expr(expr * t) { - TRACE("sat", tout << mk_pp(t, m) << "\n";); + TRACE("goal2sat", tout << mk_pp(t, m) << "\n";); m_fmls.push_back(t); } virtual void set_produce_models(bool f) {} @@ -376,7 +376,7 @@ private: init_preprocess(); SASSERT(g->models_enabled()); SASSERT(!g->proofs_enabled()); - TRACE("sat", g->display(tout);); + TRACE("goal2sat", g->display(tout);); try { (*m_preprocess)(g, m_subgoals, m_mc, m_pc, m_dep_core); } @@ -393,7 +393,7 @@ private: } g = m_subgoals[0]; expr_ref_vector atoms(m); - TRACE("sat", g->display_with_dependencies(tout);); + TRACE("goal2sat", g->display_with_dependencies(tout);); m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index eb90edd3d..923006da2 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -400,7 +400,7 @@ struct goal2sat::imp { sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, k.get_unsigned()); - TRACE("sat", tout << "root: " << root << " lit: " << lit << "\n";); + TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); if (root) { m_result_stack.reset(); mk_clause(lit); @@ -616,7 +616,7 @@ struct goal2sat::imp { } f = m.mk_or(fmls.size(), fmls.c_ptr()); } - TRACE("sat", tout << mk_pp(f, m) << "\n";); + TRACE("goal2sat", tout << mk_pp(f, m) << "\n";); process(f); skip_dep: ; From 61341b8879fa6f14c4cf1327e10745180fc75e8f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Feb 2017 17:56:22 -0800 Subject: [PATCH 0026/1283] adding drat Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 2 + src/sat/sat_config.h | 2 + src/sat/sat_drat.cpp | 121 ++++++++++++++++++++++++++++++++--------- src/sat/sat_drat.h | 34 ++++++++---- src/sat/sat_params.pyg | 5 +- src/sat/sat_solver.cpp | 26 +++++---- src/sat/sat_solver.h | 1 + 7 files changed, 144 insertions(+), 47 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 3e132c738..77a93c1e9 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -114,6 +114,8 @@ namespace sat { m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); m_drat = p.drat(); + m_drat_check = p.drat_check(); + m_drat_file = p.drat_file(); m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 34983f451..03616b6d8 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -74,6 +74,8 @@ namespace sat { bool m_core_minimize; bool m_core_minimize_partial; bool m_drat; + symbol m_drat_file; + bool m_drat_check; symbol m_always_true; symbol m_always_false; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 7e30c18ff..26f0bc98e 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2014 Microsoft Corporation +Copyright (c) 2017 Microsoft Corporation Module Name: @@ -9,6 +9,9 @@ Abstract: Produce DRAT proofs. + Check them using a very simple forward checker + that interacts with external plugins. + Author: Nikolaj Bjorner (nbjorner) 2017-2-3 @@ -25,43 +28,109 @@ namespace sat { s(s), m_out(0) { - if (s.m_config.m_drat) { - m_out = alloc(std::ofstream, "proof.drat"); + if (s.m_config.m_drat && s.m_config.m_drat_file != symbol()) { + m_out = alloc(std::ofstream, s.m_config.m_drat_file.str().c_str()); } } drat::~drat() { dealloc(m_out); } - void drat::add_empty() { - (*m_out) << "0\n"; + + std::ostream& operator<<(std::ostream& out, drat::status st) { + switch (st) { + case drat::status::learned: return out << "l"; + case drat::status::asserted: return out << "a"; + case drat::status::deleted: return out << "d"; + default: return out; + } } - void drat::add_literal(literal l) { - (*m_out) << l << " 0\n"; - } - void drat::add_binary(literal l1, literal l2) { - (*m_out) << l1 << " " << l2 << " 0\n"; - } - void drat::add_ternary(literal l1, literal l2, literal l3) { - (*m_out) << l1 << " " << l2 << " " << l3 << " 0\n"; - } - void drat::add_clause(clause& c) { - unsigned sz = c.size(); + + void drat::dump(unsigned sz, literal const* c, status st) { + if (is_cleaned(sz, c)) return; + switch (st) { + case status::asserted: return; + case status::learned: break; + case status::deleted: (*m_out) << "d "; break; + } + literal last = null_literal; for (unsigned i = 0; i < sz; ++i) { - (*m_out) << c[i] << " "; + if (c[i] != last) { + (*m_out) << c[i] << " "; + last = c[i]; + } } (*m_out) << "0\n"; } - void drat::del_literal(literal l) { - (*m_out) << "d "; - add_literal(l); + + bool drat::is_cleaned(unsigned n, literal const* c) const { + literal last = null_literal; + for (unsigned i = 0; i < n; ++i) { + if (c[i] == last) return true; + last = c[i]; + } + return false; } - void drat::del_binary(literal l1, literal l2) { - (*m_out) << "d "; - add_binary(l1, l2); + + void drat::append(unsigned n, literal const* c, status st) { + if (is_cleaned(n, c)) return; + m_status.push_back(st); + m_proof.push_back(0); // TBD + + + std::cout << st << " "; + literal last = null_literal; + for (unsigned i = 0; i < n; ++i) { + if (c[i] != last) { + std::cout << c[i] << " "; + last = c[i]; + } + + } + std::cout << "\n"; } - void drat::del_clause(clause& c) { - (*m_out) << "d "; - add_clause(c); + + drat::status drat::get_status(bool learned) const { + return learned || s.m_searching ? status::learned : status::asserted; + } + + void drat::add() { + if (m_out) (*m_out) << "0\n"; + if (s.m_config.m_drat_check) append(0, 0, status::learned); + } + void drat::add(literal l, bool learned) { + status st = get_status(learned); + if (m_out) dump(1, &l, st); + if (s.m_config.m_drat_check) append(1, &l, st); + } + void drat::add(literal l1, literal l2, bool learned) { + literal ls[2] = {l1, l2}; + status st = get_status(learned); + if (m_out) dump(2, ls, st); + if (s.m_config.m_drat_check) append(2, ls, st); + } + void drat::add(literal l1, literal l2, literal l3, bool learned) { + literal ls[3] = {l1, l2, l3}; + status st = get_status(learned); + if (m_out) dump(3, ls, st); + if (s.m_config.m_drat_check) append(3, ls, get_status(learned)); + } + void drat::add(clause& c, bool learned) { + status st = get_status(learned); + if (m_out) dump(c.size(), c.begin(), st); + if (s.m_config.m_drat_check) append(c.size(), c.begin(), get_status(learned)); + } + void drat::del(literal l) { + if (m_out) dump(1, &l, status::deleted); + if (s.m_config.m_drat_check) append(1, &l, status::deleted); + } + void drat::del(literal l1, literal l2) { + literal ls[2] = {l1, l2}; + if (m_out) dump(2, ls, status::deleted); + if (s.m_config.m_drat_check) append(2, ls, status::deleted); + } + void drat::del(clause& c) { + if (m_out) dump(c.size(), c.begin(), status::deleted); + if (s.m_config.m_drat_check) append(c.size(), c.begin(), status::deleted); } } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 9d34c57b4..0e2cfe262 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2014 Microsoft Corporation +Copyright (c) 2017 Microsoft Corporation Module Name: @@ -21,19 +21,33 @@ Notes: namespace sat { class drat { + enum status { asserted, learned, deleted }; + solver& s; - std::ostream* m_out; + std::ostream* m_out; + ptr_vector m_proof; + svector m_status; + literal_vector m_units; + vector m_watches; + char_vector m_assignment; + + void dump(unsigned n, literal const* lits, status st); + void append(unsigned n, literal const* lits, status st); + friend std::ostream& operator<<(std::ostream & out, status st); + status get_status(bool learned) const; + bool is_cleaned(unsigned n, literal const* lits) const; + public: drat(solver& s); ~drat(); - void add_empty(); - void add_literal(literal l); - void add_binary(literal l1, literal l2); - void add_ternary(literal l1, literal l2, literal l3); - void add_clause(clause& c); - void del_literal(literal l); - void del_binary(literal l1, literal l2); - void del_clause(clause& c); + void add(); + void add(literal l, bool learned); + void add(literal l1, literal l2, bool learned); + void add(literal l1, literal l2, literal l3, bool learned); + void add(clause& c, bool learned); + void del(literal l); + void del(literal l1, literal l2); + void del(clause& c); }; }; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index feefe653f..69b2bcea1 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -25,4 +25,7 @@ def_module_params('sat', ('parallel_threads', UINT, 1, 'number of parallel threads to use'), ('cardinality_solver', BOOL, False, 'enable cardinality based solver'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), - ('drat', BOOL, False, 'produce DRAT proofs'),)) + ('drat', BOOL, False, 'produce DRAT proofs'), + ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), + ('drat.check', BOOL, False, 'build up internal proof and check'), + )) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 54122c019..fb4caac43 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -44,6 +44,7 @@ namespace sat { m_mus(*this), m_drat(*this), m_inconsistent(false), + m_searching(false), m_num_frozen(0), m_activity_inc(128), m_case_split_queue(m_activity), @@ -202,8 +203,9 @@ namespace sat { void solver::del_clause(clause& c) { if (!c.is_learned()) { m_stats.m_non_learned_generation++; - } else if (m_config.m_drat) { - m_drat.del_clause(c); + } + if (m_config.m_drat) { + m_drat.del(c); } m_cls_allocator.del_clause(&c); m_stats.m_del_clause++; @@ -222,7 +224,7 @@ namespace sat { switch (num_lits) { case 0: - if (m_config.m_drat) m_drat.add_empty(); + if (m_config.m_drat) m_drat.add(); set_conflict(justification()); return 0; case 1: @@ -239,8 +241,8 @@ namespace sat { } void solver::mk_bin_clause(literal l1, literal l2, bool learned) { - if (learned && m_config.m_drat) - m_drat.add_binary(l1, l2); + if (m_config.m_drat) + m_drat.add(l1, l2, learned); if (propagate_bin_clause(l1, l2)) { if (at_base_lvl()) return; @@ -274,8 +276,8 @@ namespace sat { clause * solver::mk_ter_clause(literal * lits, bool learned) { - if (learned && m_config.m_drat) - m_drat.add_ternary(lits[0], lits[1], lits[2]); + if (m_config.m_drat) + m_drat.add(lits[0], lits[1], lits[2], learned); m_stats.m_mk_ter_clause++; clause * r = m_cls_allocator.mk_clause(3, lits, learned); bool reinit = attach_ter_clause(*r); @@ -321,10 +323,12 @@ namespace sat { if (reinit && !learned) push_reinit_stack(*r); if (learned) { m_learned.push_back(r); - if (m_config.m_drat) m_drat.add_clause(*r); } - else + else { m_clauses.push_back(r); + } + if (m_config.m_drat) + m_drat.add(*r, learned); return r; } @@ -529,8 +533,9 @@ namespace sat { SASSERT(value(l) == l_undef); TRACE("sat_assign_core", tout << l << " " << j << " level: " << scope_lvl() << "\n";); if (at_base_lvl()) { + if (m_config.m_drat) m_drat.add(l, !j.is_none()); + j = justification(); // erase justification for level 0 - if (m_config.m_drat) m_drat.add_literal(l); } m_assignment[l.index()] = l_true; m_assignment[(~l).index()] = l_false; @@ -753,6 +758,7 @@ namespace sat { if (m_config.m_num_parallel > 1 && !m_par) { return check_par(num_lits, lits); } + flet _searching(m_searching, true); #ifdef CLONE_BEFORE_SOLVING if (m_mc.empty()) { m_clone = alloc(solver, m_params, 0 /* do not clone extension */); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 2ab9d5c50..5041feba2 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -90,6 +90,7 @@ namespace sat { mus m_mus; // MUS for minimal core extraction drat m_drat; // DRAT for generating proofs bool m_inconsistent; + bool m_searching; // A conflict is usually a single justification. That is, a justification // for false. If m_not_l is not null_literal, then m_conflict is a // justification for l, and the conflict is union of m_no_l and m_conflict; From 5f70e4823df0725fc83c9a2354a2030dff41eff2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Feb 2017 22:41:40 -0800 Subject: [PATCH 0027/1283] adding drat forward checking Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 298 +++++++++++++++++++++++++++++++++++++---- src/sat/sat_drat.h | 35 ++++- src/sat/sat_solver.cpp | 10 +- 3 files changed, 304 insertions(+), 39 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 26f0bc98e..44e4a669b 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -26,7 +26,8 @@ Notes: namespace sat { drat::drat(solver& s): s(s), - m_out(0) + m_out(0), + m_inconsistent(false) { if (s.m_config.m_drat && s.m_config.m_drat_file != symbol()) { m_out = alloc(std::ofstream, s.m_config.m_drat_file.str().c_str()); @@ -35,6 +36,15 @@ namespace sat { drat::~drat() { dealloc(m_out); + for (unsigned i = 0; i < m_proof.size(); ++i) { + clause* c = m_proof[i]; + if (m_status[i] == status::deleted || m_status[i] == status::external) { + s.m_cls_allocator.del_clause(c); + } + else if (c && c->size() == 2) { + s.m_cls_allocator.del_clause(c); + } + } } std::ostream& operator<<(std::ostream& out, drat::status st) { @@ -46,15 +56,15 @@ namespace sat { } } - void drat::dump(unsigned sz, literal const* c, status st) { - if (is_cleaned(sz, c)) return; + void drat::dump(unsigned n, literal const* c, status st) { + if (is_cleaned(n, c)) return; switch (st) { case status::asserted: return; case status::learned: break; case status::deleted: (*m_out) << "d "; break; } literal last = null_literal; - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; i < n; ++i) { if (c[i] != last) { (*m_out) << c[i] << " "; last = c[i]; @@ -72,22 +82,251 @@ namespace sat { return false; } - void drat::append(unsigned n, literal const* c, status st) { - if (is_cleaned(n, c)) return; - m_status.push_back(st); - m_proof.push_back(0); // TBD - - - std::cout << st << " "; + void drat::trace(std::ostream& out, unsigned n, literal const* c, status st) { + out << st << " "; literal last = null_literal; for (unsigned i = 0; i < n; ++i) { + declare(c[i]); if (c[i] != last) { - std::cout << c[i] << " "; + out << c[i] << " "; last = c[i]; - } - + } } - std::cout << "\n"; + out << "\n"; + } + + void drat::append(literal l, status st) { + trace(std::cout, 1, &l, st); + if (st == status::learned) { + verify(1, &l); + } + if (st == status::deleted) { + return; + } + assign_propagate(l); + } + + void drat::append(literal l1, literal l2, status st) { + literal lits[2] = { l1, l2 }; + trace(std::cout, 2, lits, st); + if (st == status::deleted) { + // noop + // don't record binary as deleted. + } + else { + if (st == status::learned) { + verify(2, lits); + } + clause* c = s.m_cls_allocator.mk_clause(2, lits, st == status::learned); + m_proof.push_back(c); + m_status.push_back(st); + m_watches[(~l1).index()].push_back(c); + m_watches[(~l2).index()].push_back(c); + + if (value(l1) == l_false && value(l2) == l_false) { + m_inconsistent = true; + } + else if (value(l1) == l_false) { + assign_propagate(l2); + } + else if (value(l2) == l_false) { + assign_propagate(l1); + } + } + } + + void drat::append(clause& c, status st) { + unsigned n = c.size(); + if (is_cleaned(n, c.begin())) return; + trace(std::cout, n, c.begin(), st); + + if (st == status::learned) { + verify(n, c.begin()); + } + + m_status.push_back(st); + m_proof.push_back(&c); + if (st == status::deleted) { + del_watch(c, c[0]); + del_watch(c, c[1]); + return; + } + literal l1 = null_literal, l2 = null_literal; + for (unsigned i = 0; i < n; ++i) { + if (value(c[i]) != l_false) { + if (l1 == null_literal) { + l1 = c[i]; + } + else { + l2 = c[i]; + break; + } + } + } + if (l2 == null_literal && l1 != null_literal) { + assign_propagate(l1); + } + else if (l1 == null_literal) { + m_inconsistent = true; + } + else { + m_watches[(~l1).index()].push_back(&c); + m_watches[(~l2).index()].push_back(&c); + } + } + + void drat::del_watch(clause& c, literal l) { + watch& w = m_watches[(~l).index()]; + for (unsigned i = 0; i < w.size(); ++i) { + if (w[i] == &c) { + w[i] = w.back(); + w.pop_back(); + break; + } + } + } + + + void drat::declare(literal l) { + unsigned n = static_cast(l.var()); + while (m_assignment.size() <= n) { + m_assignment.push_back(l_undef); + m_watches.push_back(watch()); + m_watches.push_back(watch()); + } + } + + void drat::verify(unsigned n, literal const* c) { + if (m_inconsistent) { + std::cout << "inconsistent\n"; + return; + } + unsigned num_units = m_units.size(); + for (unsigned i = 0; !m_inconsistent && i < n; ++i) { + assign_propagate(~c[i]); + } + for (unsigned i = num_units; i < m_units.size(); ++i) { + m_assignment[m_units[i].var()] = l_undef; + } + m_units.resize(num_units); + bool ok = m_inconsistent; + m_inconsistent = false; + if (ok) { + std::cout << "Verified\n"; + } + else { + std::cout << "Verification failed\n"; + display(std::cout); + } + } + + void drat::display(std::ostream& out) const { + out << "units: " << m_units << "\n"; +#if 0 + for (unsigned i = 0; i < m_assignment.size(); ++i) { + lbool v = value(literal(i, false)); + if (v != l_undef) std::cout << i << ": " << v << "\n"; + } +#endif + for (unsigned i = 0; i < m_proof.size(); ++i) { + clause* c = m_proof[i]; + if (m_status[i] != status::deleted && c) { + out << i << ": " << *c << "\n"; + } + } +#if 0 + for (unsigned i = 0; i < m_assignment.size(); ++i) { + watch const& w1 = m_watches[2*i]; + watch const& w2 = m_watches[2*i + 1]; + if (!w1.empty()) { + out << i << " |-> "; + for (unsigned i = 0; i < w1.size(); ++i) out << w1[i] << " "; + out << "\n"; + } + if (!w2.empty()) { + out << "-" << i << " |-> "; + for (unsigned i = 0; i < w2.size(); ++i) out << w2[i] << " "; + out << "\n"; + } + } +#endif + } + + lbool drat::value(literal l) const { + lbool v = m_assignment[l.var()]; + return v == l_undef || !l.sign() ? v : ~v; + } + + void drat::assign(literal l) { + lbool new_value = l.sign() ? l_false : l_true; + lbool old_value = value(l); + if (new_value != old_value) { + if (old_value == l_undef) { + m_assignment[l.var()] = new_value; + m_units.push_back(l); + } + else { + m_inconsistent = true; + } + } + } + + void drat::assign_propagate(literal l) { + unsigned num_units = m_units.size(); + assign(l); + for (unsigned i = num_units; !m_inconsistent && i < m_units.size(); ++i) { + propagate(m_units[i]); + } + } + + void drat::propagate(literal l) { + watch& clauses = m_watches[l.index()]; + watch::iterator it = clauses.begin(); + watch::iterator it2 = it; + watch::iterator end = clauses.end(); + for (; it != end; ++it) { + clause& c = *(*it); + if (c[0] == ~l) { + std::swap(c[0], c[1]); + } + if (c[1] != ~l) { + *it2 = *it; + it2++; + continue; + } + SASSERT(c[1] == ~l); + if (value(c[0]) == l_true) { + it2++; + } + else { + literal * l_it = c.begin() + 2; + literal * l_end = c.end(); + bool done = false; + for (; l_it != l_end && !done; ++l_it) { + if (value(*l_it) != l_false) { + c[1] = *l_it; + *l_it = ~l; + m_watches[(~c[1]).index()].push_back(&c); + done = true; + } + } + if (done) + continue; + else if (value(c[0]) == l_false) { + m_inconsistent = true; + goto end_process_watch; + } + else { + *it2 = *it; + it2++; + assign(c[0]); + } + } + } + end_process_watch: + for (; it != end; ++it, ++it2) + *it2 = *it; + clauses.set_end(it2); } drat::status drat::get_status(bool learned) const { @@ -96,41 +335,44 @@ namespace sat { void drat::add() { if (m_out) (*m_out) << "0\n"; - if (s.m_config.m_drat_check) append(0, 0, status::learned); + if (s.m_config.m_drat_check) { + if (m_inconsistent) std::cout << "Verified\n"; + else std::cout << "Failed to verify\n"; + } } void drat::add(literal l, bool learned) { status st = get_status(learned); if (m_out) dump(1, &l, st); - if (s.m_config.m_drat_check) append(1, &l, st); + if (s.m_config.m_drat_check) append(l, st); } void drat::add(literal l1, literal l2, bool learned) { literal ls[2] = {l1, l2}; status st = get_status(learned); if (m_out) dump(2, ls, st); - if (s.m_config.m_drat_check) append(2, ls, st); - } - void drat::add(literal l1, literal l2, literal l3, bool learned) { - literal ls[3] = {l1, l2, l3}; - status st = get_status(learned); - if (m_out) dump(3, ls, st); - if (s.m_config.m_drat_check) append(3, ls, get_status(learned)); + if (s.m_config.m_drat_check) append(l1, l2, st); } void drat::add(clause& c, bool learned) { status st = get_status(learned); if (m_out) dump(c.size(), c.begin(), st); - if (s.m_config.m_drat_check) append(c.size(), c.begin(), get_status(learned)); + if (s.m_config.m_drat_check) append(c, get_status(learned)); + } + void drat::add(unsigned n, literal const* lits, unsigned m, premise * const* premises) { + if (s.m_config.m_drat_check) { + clause* c = s.m_cls_allocator.mk_clause(n, lits, true); + append(*c, status::external); + } } void drat::del(literal l) { if (m_out) dump(1, &l, status::deleted); - if (s.m_config.m_drat_check) append(1, &l, status::deleted); + if (s.m_config.m_drat_check) append(l, status::deleted); } void drat::del(literal l1, literal l2) { literal ls[2] = {l1, l2}; if (m_out) dump(2, ls, status::deleted); - if (s.m_config.m_drat_check) append(2, ls, status::deleted); + if (s.m_config.m_drat_check) append(l1, l2, status::deleted); } void drat::del(clause& c) { if (m_out) dump(c.size(), c.begin(), status::deleted); - if (s.m_config.m_drat_check) append(c.size(), c.begin(), status::deleted); + if (s.m_config.m_drat_check) append(c, status::deleted); } } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 0e2cfe262..cb39a99ba 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -21,30 +21,51 @@ Notes: namespace sat { class drat { - enum status { asserted, learned, deleted }; - + enum status { asserted, learned, deleted, external }; + typedef ptr_vector watch; + struct premise { + enum { t_clause, t_unit, t_ext } m_type; + union evidence { + clause* m_clause; + literal m_literal; + } m_evidence; + }; solver& s; std::ostream* m_out; ptr_vector m_proof; svector m_status; literal_vector m_units; - vector m_watches; - char_vector m_assignment; + vector m_watches; + svector m_assignment; + bool m_inconsistent; - void dump(unsigned n, literal const* lits, status st); - void append(unsigned n, literal const* lits, status st); + void dump(unsigned n, literal const* c, status st); + void append(literal l, status st); + void append(literal l1, literal l2, status st); + void append(clause& c, status st); friend std::ostream& operator<<(std::ostream & out, status st); status get_status(bool learned) const; bool is_cleaned(unsigned n, literal const* lits) const; + void declare(literal l); + void assign(literal l); + void propagate(literal l); + void assign_propagate(literal l); + void del_watch(clause& c, literal l); + void verify(unsigned n, literal const* c); + lbool value(literal l) const; + void trace(std::ostream& out, unsigned n, literal const* c, status st); + void display(std::ostream& out) const; + public: drat(solver& s); ~drat(); void add(); void add(literal l, bool learned); void add(literal l1, literal l2, bool learned); - void add(literal l1, literal l2, literal l3, bool learned); void add(clause& c, bool learned); + void add(unsigned n, literal const* c, unsigned m, premise* const* premises); + void del(literal l); void del(literal l1, literal l2); void del(clause& c); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index fb4caac43..9b48bae1e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -207,7 +207,9 @@ namespace sat { if (m_config.m_drat) { m_drat.del(c); } - m_cls_allocator.del_clause(&c); + else if (!m_config.m_drat || !m_config.m_drat_check) { + m_cls_allocator.del_clause(&c); + } m_stats.m_del_clause++; } @@ -276,13 +278,12 @@ namespace sat { clause * solver::mk_ter_clause(literal * lits, bool learned) { - if (m_config.m_drat) - m_drat.add(lits[0], lits[1], lits[2], learned); m_stats.m_mk_ter_clause++; clause * r = m_cls_allocator.mk_clause(3, lits, learned); bool reinit = attach_ter_clause(*r); if (reinit && !learned) push_reinit_stack(*r); - + if (m_config.m_drat) m_drat.add(*r, learned); + if (learned) m_learned.push_back(r); else @@ -494,6 +495,7 @@ namespace sat { void solver::dettach_bin_clause(literal l1, literal l2, bool learned) { get_wlist(~l1).erase(watched(l2, learned)); get_wlist(~l2).erase(watched(l1, learned)); + if (m_config.m_drat) m_drat.del(l1, l2); } void solver::dettach_clause(clause & c) { From 15283e4e7c167de3d7749921e999b53cb7eefa97 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Feb 2017 10:08:57 -0800 Subject: [PATCH 0028/1283] expose extension conflict resolution as plugin to sat solver Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 282 ++++++++++++++++++------------------- src/sat/card_extension.h | 9 +- src/sat/sat_drat.cpp | 63 ++++++--- src/sat/sat_drat.h | 19 ++- src/sat/sat_extension.h | 1 + src/sat/sat_solver.cpp | 145 +++---------------- src/sat/sat_solver.h | 4 +- src/sat/sat_types.h | 1 + src/smt/theory_pb.cpp | 6 +- 9 files changed, 223 insertions(+), 307 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 2bcccfb1a..1273cfc29 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -94,7 +94,7 @@ namespace sat { alit = c[j]; } } - set_conflict(c); + set_conflict(c, alit); } else if (j == bound) { for (unsigned i = 0; i < bound && !s().inconsistent(); ++i) { @@ -140,12 +140,24 @@ namespace sat { case l_true: break; case l_false: - set_conflict(c); + set_conflict(c, lit); break; default: m_stats.m_num_propagations++; + m_num_propagations_since_pop++; //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); SASSERT(validate_unit_propagation(c)); + if (s().m_config.m_drat) { + svector ps; + literal_vector lits; + lits.push_back(~c.lit()); + for (unsigned i = c.k(); i < c.size(); ++i) { + lits.push_back(c[i]); + } + lits.push_back(lit); + ps.push_back(drat::premise(drat::s_ext(), c.lit())); + s().m_drat.add(lits, ps); + } s().assign(lit, justification::mk_ext_justification(c.index())); break; } @@ -163,23 +175,10 @@ namespace sat { cards->push_back(&c); } - void card_extension::set_conflict(card& c) { + void card_extension::set_conflict(card& c, literal lit) { TRACE("sat", display(tout, c, true); ); SASSERT(validate_conflict(c)); - m_stats.m_num_conflicts++; - literal lit = last_false_literal(c); - if (!resolve_conflict(c, lit)) { - TRACE("sat", tout << "bail out conflict resolution\n";); - m_conflict.reset(); - m_conflict.push_back(~c.lit()); - unsigned sz = c.size(); - for (unsigned i = c.k(); i < sz; ++i) { - m_conflict.push_back(c[i]); - } - m_conflict.push_back(lit); - // SASSERT(validate_conflict(m_conflict)); - s().assign(lit, justification::mk_ext_justification(0)); - } + s().set_conflict(justification::mk_ext_justification(c.index()), ~lit); SASSERT(s().inconsistent()); } @@ -251,6 +250,15 @@ namespace sat { else if (coeff0 < 0 && inc > 0) { m_bound -= std::min(0, coeff1) - coeff0; } + // reduce coefficient to be no larger than bound. + if (coeff1 > m_bound) { + //if (m_bound > 1) std::cout << m_bound << " " << coeff1 << "\n"; + m_coeffs[v] = m_bound; + } + else if (coeff1 < 0 && -coeff1 > m_bound) { + //if (m_bound > 1) std::cout << m_bound << " " << coeff1 << "\n"; + m_coeffs[v] = -m_bound; + } } int card_extension::get_coeff(bool_var v) const { @@ -270,81 +278,82 @@ namespace sat { m_active_vars.reset(); } - bool card_extension::resolve_conflict(card& c, literal alit) { - bool_var v; - m_conflict_lvl = lvl(~alit); - for (unsigned i = c.k(); i < c.size(); ++i) { - literal lit = c[i]; - SASSERT(value(lit) == l_false); - m_conflict_lvl = std::max(m_conflict_lvl, lvl(lit)); - } - if (m_conflict_lvl < lvl(c.lit()) || m_conflict_lvl == 0) { + bool card_extension::resolve_conflict() { + if (0 == m_num_propagations_since_pop) return false; - } - // std::cout << "conflict level: " << m_conflict_lvl << " " << lvl(~alit) << "\n"; - reset_coeffs(); m_num_marks = 0; - m_bound = c.k(); - m_conflict.reset(); + m_bound = 0; + m_lemma.reset(); + m_lemma.push_back(null_literal); + literal consequent = s().m_not_l; + justification js = s().m_conflict; + m_conflict_lvl = s().get_max_lvl(consequent, js); + if (consequent != null_literal) { + consequent.neg(); + process_antecedent(consequent, 1); + } literal_vector const& lits = s().m_trail; unsigned idx = lits.size()-1; - justification js; - literal consequent = ~alit; - process_card(c, 1); + int offset = 1; + unsigned num_card = 0; + unsigned num_steps = 0; DEBUG_CODE(active2pb(m_A);); - while (m_num_marks > 0) { - SASSERT(value(consequent) == l_true); - v = consequent.var(); - int offset = get_abs_coeff(v); - + do { // TRACE("sat", display(tout, m_A);); if (offset == 0) { goto process_next_resolvent; } - if (offset > 1000) { + // TBD: need proper check for overflow. + if (offset > (1 << 12)) { + // std::cout << "offset: " << offset << "\n"; goto bail_out; } - SASSERT(validate_lemma()); - - SASSERT(offset > 0); + ++num_steps; + + SASSERT(offset > 0); + SASSERT(m_bound >= 0); - js = s().m_justification[v]; DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); - int bound = 1; switch(js.get_kind()) { case justification::NONE: - //std::cout << "NONE\n"; + SASSERT (consequent != null_literal); + m_lemma.push_back(~consequent); + m_bound += offset; inc_coeff(consequent, offset); break; case justification::BINARY: - //std::cout << "BINARY\n"; + m_bound += offset; + SASSERT (consequent != null_literal); inc_coeff(consequent, offset); - process_antecedent((js.get_literal()), offset); + process_antecedent(js.get_literal(), offset); break; case justification::TERNARY: - //std::cout << "TERNARY\n"; + m_bound += offset; + SASSERT (consequent != null_literal); inc_coeff(consequent, offset); - process_antecedent((js.get_literal1()), offset); - process_antecedent((js.get_literal2()), offset); + process_antecedent(js.get_literal1(), offset); + process_antecedent(js.get_literal2(), offset); break; case justification::CLAUSE: { - //std::cout << "CLAUSE\n"; - inc_coeff(consequent, offset); + m_bound += offset; clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); - unsigned i = 0; - SASSERT(c[0] == consequent || c[1] == consequent); - if (c[0] == consequent) { - i = 1; - } - else { - process_antecedent(c[0], offset); - i = 2; + unsigned i = 0; + if (consequent != null_literal) { + inc_coeff(consequent, offset); + if (c[0] == consequent) { + i = 1; + } + else { + SASSERT(c[1] == consequent); + process_antecedent(c[0], offset); + i = 2; + } } unsigned sz = c.size(); for (; i < sz; i++) @@ -352,19 +361,23 @@ namespace sat { break; } case justification::EXT_JUSTIFICATION: { - //std::cout << "CARDINALITY\n"; + ++num_card; unsigned index = js.get_ext_justification_idx(); - card& c2 = *m_constraints[index]; - process_card(c2, offset); - bound = c2.k(); + card& c = *m_constraints[index]; + m_bound += offset * c.k(); + if (!process_card(c, offset)) { + std::cout << "failed to process card\n"; + goto bail_out; + } break; } default: UNREACHABLE(); break; } - m_bound += offset * bound; + SASSERT(validate_lemma()); + DEBUG_CODE( active2pb(m_C); SASSERT(validate_resolvent()); @@ -376,6 +389,7 @@ namespace sat { // find the next marked variable in the assignment stack // + bool_var v; while (true) { consequent = lits[idx]; v = consequent.var(); @@ -388,17 +402,20 @@ namespace sat { s().reset_mark(v); --idx; --m_num_marks; + js = s().m_justification[v]; + offset = get_abs_coeff(v); + SASSERT(value(consequent) == l_true); } + while (m_num_marks > 0); + + std::cout << m_num_propagations_since_pop << " " << num_steps << " " << num_card << "\n"; + // std::cout << consequent << "\n"; DEBUG_CODE(for (bool_var i = 0; i < static_cast(s().num_vars()); ++i) SASSERT(!s().is_marked(i));); SASSERT(validate_lemma()); normalize_active_coeffs(); - if (m_bound > 0 && m_active_vars.empty()) { - return false; - } - int slack = -m_bound; for (unsigned i = 0; i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; @@ -408,10 +425,11 @@ namespace sat { TRACE("sat", display(tout, m_A);); ++idx; - alit = null_literal; -#if 1 + consequent = null_literal; + // std::cout << c.size() << " >= " << c.k() << "\n"; // std::cout << m_active_vars.size() << ": " << slack + m_bound << " >= " << m_bound << "\n"; + while (0 <= slack) { literal lit = lits[idx]; bool_var v = lit.var(); @@ -427,62 +445,48 @@ namespace sat { append = true; } if (append) { - if (alit == null_literal) { - alit = ~lit; + if (consequent == null_literal) { + consequent = ~lit; } else { - m_conflict.push_back(~lit); + m_lemma.push_back(~lit); } } } SASSERT(idx > 0 || slack < 0); --idx; } - if (alit == null_literal) { - return false; - } - if (alit != null_literal) { - m_conflict.push_back(alit); - } -#else - for (unsigned i = 0; 0 <= slack; ++i) { - SASSERT(i <= idx); - literal lit = lits[i]; - bool_var v = lit.var(); - if (m_active_var_set.contains(v)) { - int coeff = get_coeff(v); - - if (coeff < 0 && !lit.sign()) { - slack += coeff; - m_conflict.push_back(~lit); - } - else if (coeff > 0 && lit.sign()) { - slack -= coeff; - m_conflict.push_back(~lit); - } - } - } - - if (!m_conflict.empty()) { - alit = m_conflict.back(); - } -#endif - if (m_conflict.empty()) { - IF_VERBOSE(0, verbose_stream() << "(empty conflict)\n";); - return false; - } SASSERT(slack < 0); - SASSERT(validate_conflict(m_conflict, m_A)); - TRACE("sat", tout << m_conflict << "\n";); + if (consequent == null_literal) { + std::cout << "null literal: " << m_lemma.empty() << "\n"; + if (!m_lemma.empty()) return false; + } + else { + m_lemma[0] = consequent; + SASSERT(validate_conflict(m_lemma, m_A)); + } + TRACE("sat", tout << m_lemma << "\n";); + + if (s().m_config.m_drat) { + svector ps; // TBD fill in + s().m_drat.add(m_lemma, ps); + } + + // std::cout << m_lemma << "\n"; + s().m_lemma.reset(); + s().m_lemma.append(m_lemma); + for (unsigned i = 1; i < m_lemma.size(); ++i) { + s().mark(m_lemma[i].var()); + } + m_stats.m_num_conflicts++; - s().assign(alit, justification::mk_ext_justification(0)); return true; bail_out: while (m_num_marks > 0 && idx > 0) { - v = lits[idx].var(); + bool_var v = lits[idx].var(); if (s().is_marked(v)) { s().reset_mark(v); --m_num_marks; @@ -492,7 +496,7 @@ namespace sat { return false; } - void card_extension::process_card(card& c, int offset) { + bool card_extension::process_card(card& c, int offset) { SASSERT(c.k() <= c.size()); SASSERT(value(c.lit()) == l_true); for (unsigned i = c.k(); i < c.size(); ++i) { @@ -502,8 +506,9 @@ namespace sat { inc_coeff(c[i], offset); } if (lvl(c.lit()) > 0) { - m_conflict.push_back(~c.lit()); + m_lemma.push_back(~c.lit()); } + return (lvl(c.lit()) <= m_conflict_lvl); } void card_extension::process_antecedent(literal l, int offset) { @@ -536,7 +541,6 @@ namespace sat { card_extension::card_extension(): m_solver(0) { TRACE("sat", tout << this << "\n";); - m_constraints.push_back(0); // dummy constraint for conflicts } card_extension::~card_extension() { @@ -562,31 +566,21 @@ namespace sat { } void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { - if (idx == 0) { - // std::cout << "antecedents0: " << l << " " << m_conflict.size() << "\n"; - SASSERT(m_conflict.back() == l); - for (unsigned i = 0; i + 1 < m_conflict.size(); ++i) { - SASSERT(value(m_conflict[i]) == l_false); - r.push_back(~m_conflict[i]); - } - } - else { - card& c = *m_constraints[idx]; - - DEBUG_CODE( - bool found = false; - for (unsigned i = 0; !found && i < c.k(); ++i) { - found = c[i] == l; - } - SASSERT(found);); - - // std::cout << "antecedents: " << idx << ": " << l << " " << c.size() - c.k() + 1 << "\n"; - r.push_back(c.lit()); - SASSERT(value(c.lit()) == l_true); - for (unsigned i = c.k(); i < c.size(); ++i) { - SASSERT(value(c[i]) == l_false); - r.push_back(~c[i]); + card& c = *m_constraints[idx]; + + DEBUG_CODE( + bool found = false; + for (unsigned i = 0; !found && i < c.k(); ++i) { + found = c[i] == l; } + SASSERT(found);); + + // std::cout << "antecedents: " << idx << ": " << l << " " << c.size() - c.k() + 1 << "\n"; + r.push_back(c.lit()); + SASSERT(value(c.lit()) == l_true); + for (unsigned i = c.k(); i < c.size(); ++i) { + SASSERT(value(c[i]) == l_false); + r.push_back(~c[i]); } } @@ -626,7 +620,7 @@ namespace sat { // conflict if (bound != index && value(c[bound]) == l_false) { TRACE("sat", tout << "conflict " << c[bound] << " " << alit << "\n";); - set_conflict(c); + set_conflict(c, alit); return l_false; } @@ -709,6 +703,7 @@ namespace sat { } } m_var_lim.resize(new_lim); + m_num_propagations_since_pop = 0; } void card_extension::simplify() {} @@ -718,7 +713,6 @@ namespace sat { extension* card_extension::copy(solver* s) { card_extension* result = alloc(card_extension); result->set_solver(s); - result->m_constraints.push_back(0); for (unsigned i = 1; i < m_constraints.size(); ++i) { literal_vector lits; card& c = *m_constraints[i]; @@ -795,7 +789,7 @@ namespace sat { std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const { if (idx == 0) { - out << "conflict: " << m_conflict; + out << "conflict: " << m_lemma; } else { card& c = *m_constraints[idx]; @@ -860,7 +854,7 @@ namespace sat { switch (js.get_kind()) { case justification::NONE: p.reset(offset); - p.push(lit, offset); + p.push(lit, offset); break; case justification::BINARY: p.reset(offset); @@ -938,7 +932,7 @@ namespace sat { literal lit = m_C.m_lits[i]; unsigned coeff; if (coeffs.find(lit.index(), coeff)) { - SASSERT(coeff <= m_C.m_coeffs[i]); + SASSERT(coeff <= m_C.m_coeffs[i] || m_C.m_coeffs[i] == m_C.m_k); coeffs.remove(lit.index()); } } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index ac434ef5c..3434a280b 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -94,8 +94,9 @@ namespace sat { svector m_active_vars; int m_bound; tracked_uint_set m_active_var_set; - literal_vector m_conflict; + literal_vector m_lemma; literal_vector m_literals; + unsigned m_num_propagations_since_pop; solver& s() const { return *m_solver; } void init_watch(card& c, bool is_true); @@ -103,7 +104,7 @@ namespace sat { void assign(card& c, literal lit); lbool add_assign(card& c, literal lit); void watch_literal(card& c, literal lit); - void set_conflict(card& c); + void set_conflict(card& c, literal lit); literal last_false_literal(card& c); void clear_watch(card& c); void reset_coeffs(); @@ -122,9 +123,8 @@ namespace sat { literal_vector& get_literals() { m_literals.reset(); return m_literals; } literal get_asserting_literal(literal conseq); - bool resolve_conflict(card& c, literal alit); void process_antecedent(literal l, int offset); - void process_card(card& c, int offset); + bool process_card(card& c, int offset); void cut(); // validation utilities @@ -148,6 +148,7 @@ namespace sat { virtual void set_solver(solver* s) { m_solver = s; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); virtual void propagate(literal l, ext_constraint_idx idx, bool & keep); + virtual bool resolve_conflict(); virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r); virtual void asserted(literal l); virtual check_result check(); diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 44e4a669b..fb161a998 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -52,6 +52,7 @@ namespace sat { case drat::status::learned: return out << "l"; case drat::status::asserted: return out << "a"; case drat::status::deleted: return out << "d"; + case drat::status::external: return out << "e"; default: return out; } } @@ -60,16 +61,11 @@ namespace sat { if (is_cleaned(n, c)) return; switch (st) { case status::asserted: return; + case status::external: return; // requires extension to drat format. case status::learned: break; case status::deleted: (*m_out) << "d "; break; } - literal last = null_literal; - for (unsigned i = 0; i < n; ++i) { - if (c[i] != last) { - (*m_out) << c[i] << " "; - last = c[i]; - } - } + for (unsigned i = 0; i < n; ++i) (*m_out) << c[i] << " "; (*m_out) << "0\n"; } @@ -186,7 +182,6 @@ namespace sat { } } - void drat::declare(literal l) { unsigned n = static_cast(l.var()); while (m_assignment.size() <= n) { @@ -196,11 +191,8 @@ namespace sat { } } - void drat::verify(unsigned n, literal const* c) { - if (m_inconsistent) { - std::cout << "inconsistent\n"; - return; - } + bool drat::is_drup(unsigned n, literal const* c) { + if (m_inconsistent || n == 0) return true; unsigned num_units = m_units.size(); for (unsigned i = 0; !m_inconsistent && i < n; ++i) { assign_propagate(~c[i]); @@ -211,12 +203,38 @@ namespace sat { m_units.resize(num_units); bool ok = m_inconsistent; m_inconsistent = false; - if (ok) { - std::cout << "Verified\n"; + return ok; + } + + bool drat::is_drat(unsigned n, literal const* c) { + if (m_inconsistent || n == 0) return true; + literal l = c[0]; + literal_vector lits(n - 1, c + 1); + for (unsigned i = 0; m_proof.size(); ++i) { + status st = m_status[i]; + if (m_proof[i] && (st == status::asserted || st == status::external)) { + clause& c = *m_proof[i]; + unsigned j = 0; + for (; j < c.size() && c[j] != ~l; ++j) {} + if (j != c.size()) { + lits.append(j, c.begin()); + lits.append(c.size() - j - 1, c.begin() + j + 1); + if (!is_drup(lits.size(), lits.c_ptr())) return false; + lits.resize(n - 1); + } + } + } + return true; + } + + void drat::verify(unsigned n, literal const* c) { + if (is_drup(n, c) || is_drat(n, c)) { + std::cout << "Verified\n"; } else { std::cout << "Verification failed\n"; display(std::cout); + exit(0); } } @@ -356,11 +374,18 @@ namespace sat { if (m_out) dump(c.size(), c.begin(), st); if (s.m_config.m_drat_check) append(c, get_status(learned)); } - void drat::add(unsigned n, literal const* lits, unsigned m, premise * const* premises) { + void drat::add(literal_vector const& lits, svector const& premises) { if (s.m_config.m_drat_check) { - clause* c = s.m_cls_allocator.mk_clause(n, lits, true); - append(*c, status::external); - } + switch (lits.size()) { + case 0: add(); break; + case 1: append(lits[0], status::external); break; + default: { + clause* c = s.m_cls_allocator.mk_clause(lits.size(), lits.c_ptr(), true); + append(*c, status::external); + break; + } + } + } } void drat::del(literal l) { if (m_out) dump(1, &l, status::deleted); diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index cb39a99ba..fd4b3f868 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -21,15 +21,22 @@ Notes: namespace sat { class drat { - enum status { asserted, learned, deleted, external }; - typedef ptr_vector watch; + public: + struct s_ext {}; + struct s_unit {}; struct premise { enum { t_clause, t_unit, t_ext } m_type; - union evidence { + union { clause* m_clause; literal m_literal; - } m_evidence; + }; + premise(s_ext, literal l): m_type(t_ext), m_literal(l) {} + premise(s_unit, literal l): m_type(t_unit), m_literal(l) {} + premise(clause* c): m_type(t_clause), m_clause(c) {} }; + private: + enum status { asserted, learned, deleted, external }; + typedef ptr_vector watch; solver& s; std::ostream* m_out; ptr_vector m_proof; @@ -53,6 +60,8 @@ namespace sat { void assign_propagate(literal l); void del_watch(clause& c, literal l); void verify(unsigned n, literal const* c); + bool is_drup(unsigned n, literal const* c); + bool is_drat(unsigned n, literal const* c); lbool value(literal l) const; void trace(std::ostream& out, unsigned n, literal const* c, status st); void display(std::ostream& out) const; @@ -64,7 +73,7 @@ namespace sat { void add(literal l, bool learned); void add(literal l1, literal l2, bool learned); void add(clause& c, bool learned); - void add(unsigned n, literal const* c, unsigned m, premise* const* premises); + void add(literal_vector const& c, svector const& premises); void del(literal l); void del(literal l1, literal l2); diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index e8d92d085..042f68e24 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -37,6 +37,7 @@ namespace sat { virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0; virtual void asserted(literal l) = 0; virtual check_result check() = 0; + virtual bool resolve_conflict() { return false; } // stores result in sat::solver::m_lemma virtual void push() = 0; virtual void pop(unsigned n) = 0; virtual void simplify() = 0; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 9b48bae1e..dc9622a6b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1739,11 +1739,17 @@ namespace sat { return false; } - m_lemma.reset(); - forget_phase_of_vars(m_conflict_lvl); + if (m_ext && m_ext->resolve_conflict()) { + learn_lemma_and_backjump(); + return true; + } + + m_lemma.reset(); + unsigned idx = skip_literals_above_conflict_level(); + // save space for first uip m_lemma.push_back(null_literal); @@ -1820,6 +1826,11 @@ namespace sat { while (num_marks > 0); m_lemma[0] = ~consequent; + learn_lemma_and_backjump(); + return true; + } + + void solver::learn_lemma_and_backjump() { TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";); if (m_config.m_minimize_lemmas) { @@ -1851,7 +1862,6 @@ namespace sat { } decay_activity(); updt_phase_counters(); - return true; } void solver::process_antecedent_for_unsat_core(literal antecedent) { @@ -1917,122 +1927,6 @@ namespace sat { } } - bool solver::resolve_conflict_for_init() { - if (m_conflict_lvl == 0) { - return false; - } - m_lemma.reset(); - m_lemma.push_back(null_literal); // asserted literal - literal consequent = null_literal; - if (m_not_l != null_literal) { - TRACE("sat", tout << "not_l: " << m_not_l << "\n";); - process_antecedent_for_init(m_not_l); - consequent = ~m_not_l; - } - justification js = m_conflict; - - SASSERT(m_trail.size() > 0); - unsigned idx = m_trail.size(); - while (process_consequent_for_init(consequent, js)) { - while (true) { - --idx; - literal l = m_trail[idx]; - if (is_marked(l.var())) - break; - SASSERT(idx > 0); - } - consequent = m_trail[idx]; - bool_var c_var = consequent.var(); - if (lvl(consequent) == 0) { - return false; - } - SASSERT(m_conflict_lvl == 1); - js = m_justification[c_var]; - reset_mark(c_var); - } - - unsigned new_scope_lvl = 0; - m_lemma[0] = ~consequent; - for (unsigned i = 1; i < m_lemma.size(); ++i) { - bool_var var = m_lemma[i].var(); - if (is_marked(var)) { - reset_mark(var); - new_scope_lvl = std::max(new_scope_lvl, lvl(var)); - } - else { - m_lemma[i] = m_lemma.back(); - m_lemma.pop_back(); - --i; - } - } - TRACE("sat", tout << "lemma: " << m_lemma << "\n"; display(tout); tout << "assignment:\n"; display_assignment(tout);); - if (new_scope_lvl == 0) { - pop_reinit(m_scope_lvl); - } - else { - unassign_vars(idx); - } - mk_clause_core(m_lemma.size(), m_lemma.c_ptr(), true); - TRACE("sat", tout << "Trail: " << m_trail << "\n";); - m_inconsistent = false; - return true; - } - - bool solver::process_consequent_for_init(literal consequent, justification const& js) { - switch (js.get_kind()) { - case justification::NONE: - return false; - case justification::BINARY: - process_antecedent_for_init(~(js.get_literal())); - break; - case justification::TERNARY: - process_antecedent_for_init(~(js.get_literal1())); - process_antecedent_for_init(~(js.get_literal2())); - break; - case justification::CLAUSE: { - clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); - unsigned i = 0; - if (consequent != null_literal) { - SASSERT(c[0] == consequent || c[1] == consequent); - if (c[0] == consequent) { - i = 1; - } - else { - process_antecedent_for_init(~c[0]); - i = 2; - } - } - unsigned sz = c.size(); - for (; i < sz; i++) - process_antecedent_for_init(~c[i]); - break; - } - case justification::EXT_JUSTIFICATION: { - fill_ext_antecedents(consequent, js); - literal_vector::iterator it = m_ext_antecedents.begin(); - literal_vector::iterator end = m_ext_antecedents.end(); - for (; it != end; ++it) - process_antecedent_for_init(*it); - break; - } - default: - UNREACHABLE(); - break; - } - return true; - } - - void solver::process_antecedent_for_init(literal antecedent) { - bool_var var = antecedent.var(); - SASSERT(var < num_vars()); - if (!is_marked(var) && lvl(var) > 0) { - mark(var); - m_lemma.push_back(~antecedent); - } - } - - - static int count = 0; void solver::resolve_conflict_for_unsat_core() { TRACE("sat", display(tout); unsigned level = 0; @@ -2080,12 +1974,8 @@ namespace sat { } consequent = ~m_not_l; } - std::cout << "CONFLICT: " << m_core << "\n"; - display_status(std::cout); - ++count; - exit(0); - justification js = m_conflict; + justification js = m_conflict; while (true) { process_consequent_for_unsat_core(consequent, js); @@ -2140,16 +2030,13 @@ namespace sat { } case justification::EXT_JUSTIFICATION: { unsigned r = 0; - if (not_l != null_literal) - r = lvl(~not_l); + SASSERT(not_l != null_literal); + r = lvl(not_l); fill_ext_antecedents(~not_l, js); literal_vector::iterator it = m_ext_antecedents.begin(); literal_vector::iterator end = m_ext_antecedents.end(); for (; it != end; ++it) r = std::max(r, lvl(*it)); - if (true || r != scope_lvl() || r != lvl(not_l)) { - // std::cout << "get max level " << r << " scope level " << scope_lvl() << " lvl(l): " << lvl(not_l) << "\n"; - } return r; } default: diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 5041feba2..f43418d22 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -378,14 +378,12 @@ namespace sat { literal_vector m_ext_antecedents; bool resolve_conflict(); bool resolve_conflict_core(); + void learn_lemma_and_backjump(); unsigned get_max_lvl(literal consequent, justification js); void process_antecedent(literal antecedent, unsigned & num_marks); void resolve_conflict_for_unsat_core(); void process_antecedent_for_unsat_core(literal antecedent); void process_consequent_for_unsat_core(literal consequent, justification const& js); - bool resolve_conflict_for_init(); - void process_antecedent_for_init(literal antecedent); - bool process_consequent_for_init(literal consequent, justification const& js); void fill_ext_antecedents(literal consequent, justification js); unsigned skip_literals_above_conflict_level(); void forget_phase_of_vars(unsigned from_lvl); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 44d3383fb..74354a999 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -138,6 +138,7 @@ namespace sat { typedef svector model; + inline void negate(literal_vector& ls) { for (unsigned i = 0; i < ls.size(); ++i) ls[i].neg(); } inline lbool value_at(bool_var v, model const & m) { return m[v]; } inline lbool value_at(literal l, model const & m) { lbool r = value_at(l.var(), m); return l.sign() ? ~r : r; } diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 445780360..591577d2a 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -811,7 +811,7 @@ namespace smt { } if (bound == c->size() || bound == 1) { - std::cout << "is-clause\n"; + // } if (bound == c->size()) { @@ -1827,11 +1827,11 @@ namespace smt { lbool is_sat = k.check(); validating = false; std::cout << is_sat << "\n"; - if (is_sat != l_false) { + if (is_sat == l_true) { std::cout << A << "\n"; std::cout << B << "\n"; } - SASSERT(is_sat == l_false); + SASSERT(is_sat != l_true); return true; } From 7aeaf11ee44f03bb7b9ad72f729c92e36a01fba6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Feb 2017 22:24:20 -0800 Subject: [PATCH 0029/1283] adding clause sharing to par mode Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 112 ++++++++++++------------------- src/sat/card_extension.h | 1 - src/sat/sat_clause.cpp | 4 +- src/sat/sat_par.cpp | 133 ++++++++++++++++++++++++++++++++++++- src/sat/sat_par.h | 40 ++++++++++- src/sat/sat_solver.cpp | 43 +++++++----- src/sat/sat_solver.h | 7 +- 7 files changed, 249 insertions(+), 91 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 1273cfc29..c051ded15 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -181,35 +181,6 @@ namespace sat { s().set_conflict(justification::mk_ext_justification(c.index()), ~lit); SASSERT(s().inconsistent()); } - - literal card_extension::last_false_literal(card& c) { - while (!m_active_var_set.empty()) m_active_var_set.erase(); - reset_coeffs(); - for (unsigned i = 0; i < c.size(); ++i) { - bool_var v = c[i].var(); - m_active_var_set.insert(v); - m_active_vars.push_back(v); - m_coeffs.setx(v, c[i].sign() ? -1 : 1, 0); - } - literal_vector const& lits = s().m_trail; - for (unsigned i = lits.size(); i > 0; ) { - --i; - literal lit = lits[i]; - bool_var v = lit.var(); - if (m_active_var_set.contains(v) && - (m_coeffs[v] > 0 == lits[i].sign())) { - //std::cout << "last literal: " << lit << "\n"; - for (unsigned j = 0; j < c.size(); ++j) { - if (~lit == c[j] && j != c.k()-1) { - // std::cout << "POSITION " << j << " bound " << c.k() << "\n"; - } - } - return ~lit; - } - } - UNREACHABLE(); - return null_literal; - } void card_extension::normalize_active_coeffs() { while (!m_active_var_set.empty()) m_active_var_set.erase(); @@ -252,11 +223,9 @@ namespace sat { } // reduce coefficient to be no larger than bound. if (coeff1 > m_bound) { - //if (m_bound > 1) std::cout << m_bound << " " << coeff1 << "\n"; m_coeffs[v] = m_bound; } else if (coeff1 < 0 && -coeff1 > m_bound) { - //if (m_bound > 1) std::cout << m_bound << " " << coeff1 << "\n"; m_coeffs[v] = -m_bound; } } @@ -302,19 +271,19 @@ namespace sat { DEBUG_CODE(active2pb(m_A);); do { - // TRACE("sat", display(tout, m_A);); if (offset == 0) { goto process_next_resolvent; } // TBD: need proper check for overflow. if (offset > (1 << 12)) { - // std::cout << "offset: " << offset << "\n"; goto bail_out; } ++num_steps; + // TRACE("sat", display(tout, m_A);); + TRACE("sat", tout << "process consequent: " << consequent << ":\n"; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); SASSERT(m_bound >= 0); @@ -366,7 +335,7 @@ namespace sat { card& c = *m_constraints[index]; m_bound += offset * c.k(); if (!process_card(c, offset)) { - std::cout << "failed to process card\n"; + TRACE("sat", tout << "failed to process card\n";); goto bail_out; } break; @@ -378,11 +347,13 @@ namespace sat { SASSERT(validate_lemma()); + DEBUG_CODE( active2pb(m_C); - SASSERT(validate_resolvent()); + //SASSERT(validate_resolvent()); m_A = m_C;); + TRACE("sat", display(tout << "conflict:\n", m_A);); // cut(); process_next_resolvent: @@ -404,31 +375,32 @@ namespace sat { --m_num_marks; js = s().m_justification[v]; offset = get_abs_coeff(v); + if (offset > m_bound) { + m_coeffs[v] = (get_coeff(v) < 0) ? -m_bound : m_bound; + offset = m_bound; + // TBD: also adjust coefficient in m_A. + } SASSERT(value(consequent) == l_true); + } while (m_num_marks > 0); - - std::cout << m_num_propagations_since_pop << " " << num_steps << " " << num_card << "\n"; - // std::cout << consequent << "\n"; DEBUG_CODE(for (bool_var i = 0; i < static_cast(s().num_vars()); ++i) SASSERT(!s().is_marked(i));); SASSERT(validate_lemma()); normalize_active_coeffs(); + if (consequent == null_literal) { + return false; + } int slack = -m_bound; for (unsigned i = 0; i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; slack += get_abs_coeff(v); } - - TRACE("sat", display(tout, m_A);); - ++idx; consequent = null_literal; - - // std::cout << c.size() << " >= " << c.k() << "\n"; - // std::cout << m_active_vars.size() << ": " << slack + m_bound << " >= " << m_bound << "\n"; + ++idx; while (0 <= slack) { literal lit = lits[idx]; @@ -450,6 +422,11 @@ namespace sat { } else { m_lemma.push_back(~lit); + if (lvl(lit) == m_conflict_lvl) { + TRACE("sat", tout << "Bail out on no progress " << lit << "\n";); + IF_VERBOSE(1, verbose_stream() << "bail cardinality lemma\n";); + return false; + } } } } @@ -460,7 +437,6 @@ namespace sat { SASSERT(slack < 0); if (consequent == null_literal) { - std::cout << "null literal: " << m_lemma.empty() << "\n"; if (!m_lemma.empty()) return false; } else { @@ -473,8 +449,7 @@ namespace sat { svector ps; // TBD fill in s().m_drat.add(m_lemma, ps); } - - // std::cout << m_lemma << "\n"; + s().m_lemma.reset(); s().m_lemma.append(m_lemma); for (unsigned i = 1; i < m_lemma.size(); ++i) { @@ -575,7 +550,6 @@ namespace sat { } SASSERT(found);); - // std::cout << "antecedents: " << idx << ": " << l << " " << c.size() - c.k() + 1 << "\n"; r.push_back(c.lit()); SASSERT(value(c.lit()) == l_true); for (unsigned i = c.k(); i < c.size(); ++i) { @@ -788,17 +762,12 @@ namespace sat { } std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const { - if (idx == 0) { - out << "conflict: " << m_lemma; - } - else { - card& c = *m_constraints[idx]; - out << "bound " << c.lit() << ": "; - for (unsigned i = c.k(); i < c.size(); ++i) { - out << c[i] << " "; - } - out << ">= " << c.k(); + card& c = *m_constraints[idx]; + out << "bound " << c.lit() << ": "; + for (unsigned i = 0; i < c.size(); ++i) { + out << c[i] << " "; } + out << ">= " << c.k(); return out; } @@ -932,22 +901,29 @@ namespace sat { literal lit = m_C.m_lits[i]; unsigned coeff; if (coeffs.find(lit.index(), coeff)) { - SASSERT(coeff <= m_C.m_coeffs[i] || m_C.m_coeffs[i] == m_C.m_k); + if (coeff > m_C.m_coeffs[i] && m_C.m_coeffs[i] < m_C.m_k) { + std::cout << i << ": " << m_C.m_coeffs[i] << " " << m_C.m_k << "\n"; + goto violated; + } coeffs.remove(lit.index()); } } - if (!coeffs.empty() || m_C.m_k > k) { - display(std::cout, m_A); - display(std::cout, m_B); - display(std::cout, m_C); - u_map::iterator it = coeffs.begin(), end = coeffs.end(); - for (; it != end; ++it) { - std::cout << to_literal(it->m_key) << ": " << it->m_value << "\n"; - } - } + if (!coeffs.empty()) goto violated; + if (m_C.m_k > k) goto violated; SASSERT(coeffs.empty()); SASSERT(m_C.m_k <= k); return true; + + violated: + display(std::cout, m_A); + display(std::cout, m_B); + display(std::cout, m_C); + u_map::iterator it = coeffs.begin(), end = coeffs.end(); + for (; it != end; ++it) { + std::cout << to_literal(it->m_key) << ": " << it->m_value << "\n"; + } + + return false; } bool card_extension::validate_conflict(literal_vector const& lits, ineq& p) { diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 3434a280b..dbc8f7b07 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -105,7 +105,6 @@ namespace sat { lbool add_assign(card& c, literal lit); void watch_literal(card& c, literal lit); void set_conflict(card& c, literal lit); - literal last_false_literal(card& c); void clear_watch(card& c); void reset_coeffs(); diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 1efbd6758..68af09ec7 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -198,13 +198,13 @@ namespace sat { size_t size = clause::get_obj_size(num_lits); void * mem = m_allocator.allocate(size); clause * cls = new (mem) clause(m_id_gen.mk(), num_lits, lits, learned); - TRACE("sat", tout << "alloc: " << cls->id() << " " << *cls << " " << (learned?"l":"a") << "\n";); + TRACE("sat_clause", tout << "alloc: " << cls->id() << " " << *cls << " " << (learned?"l":"a") << "\n";); SASSERT(!learned || cls->is_learned()); return cls; } void clause_allocator::del_clause(clause * cls) { - TRACE("sat", tout << "delete: " << cls->id() << " " << *cls << "\n";); + TRACE("sat_clause", tout << "delete: " << cls->id() << " " << *cls << "\n";); m_id_gen.recycle(cls->id()); #if defined(_AMD64_) #if defined(Z3DEBUG) diff --git a/src/sat/sat_par.cpp b/src/sat/sat_par.cpp index 7a185a3b5..585bd8bcc 100644 --- a/src/sat/sat_par.cpp +++ b/src/sat/sat_par.cpp @@ -17,13 +17,84 @@ Revision History: --*/ #include "sat_par.h" +#include "sat_clause.h" +#include "sat_solver.h" namespace sat { + void par::vector_pool::next(unsigned& index) { + SASSERT(index < m_size); + unsigned n = index + 2 + get_length(index); + if (n >= m_size) { + index = 0; + } + else { + index = n; + } + } + + void par::vector_pool::reserve(unsigned num_threads, unsigned sz) { + m_vectors.reset(); + m_vectors.resize(sz, 0); + m_heads.reset(); + m_heads.resize(num_threads, 0); + m_tail = 0; + m_size = sz; + } + + void par::vector_pool::begin_add_vector(unsigned owner, unsigned n) { + unsigned capacity = n + 2; + m_vectors.reserve(m_size + capacity, 0); + IF_VERBOSE(3, verbose_stream() << owner << ": begin-add " << n << " tail: " << m_tail << " size: " << m_size << "\n";); + if (m_tail >= m_size) { + // move tail to the front. + for (unsigned i = 0; i < m_heads.size(); ++i) { + while (m_heads[i] < capacity) { + next(m_heads[i]); + } + IF_VERBOSE(3, verbose_stream() << owner << ": head: " << m_heads[i] << "\n";); + } + m_tail = 0; + } + else { + for (unsigned i = 0; i < m_heads.size(); ++i) { + while (m_tail < m_heads[i] && m_heads[i] < m_tail + capacity) { + next(m_heads[i]); + } + IF_VERBOSE(3, verbose_stream() << owner << ": head: " << m_heads[i] << "\n";); + } + } + m_vectors[m_tail++] = owner; + m_vectors[m_tail++] = n; + } + + void par::vector_pool::add_vector_elem(unsigned e) { + m_vectors[m_tail++] = e; + } + + bool par::vector_pool::get_vector(unsigned owner, unsigned& n, unsigned const*& ptr) { + unsigned head = m_heads[owner]; + SASSERT(head < m_size); + while (head != m_tail) { + IF_VERBOSE(3, verbose_stream() << owner << ": head: " << head << " tail: " << m_tail << "\n";); + bool is_self = owner == get_owner(head); + next(m_heads[owner]); + if (!is_self) { + n = get_length(head); + ptr = get_ptr(head); + return true; + } + head = m_heads[owner]; + } + return false; + } + par::par() {} - void par::exchange(literal_vector const& in, unsigned& limit, literal_vector& out) { + void par::exchange(solver& s, literal_vector const& in, unsigned& limit, literal_vector& out) { + if (s.m_par_syncing_clauses) return; + flet _disable_sync_clause(s.m_par_syncing_clauses, true); #pragma omp critical (par_solver) { if (limit < m_units.size()) { @@ -40,6 +111,64 @@ namespace sat { limit = m_units.size(); } } - + + void par::share_clause(solver& s, literal l1, literal l2) { + if (s.m_par_syncing_clauses) return; + flet _disable_sync_clause(s.m_par_syncing_clauses, true); + #pragma omp critical (par_solver) + { + IF_VERBOSE(3, verbose_stream() << s.m_par_id << ": share " << l1 << " " << l2 << "\n";); + m_pool.begin_add_vector(s.m_par_id, 2); + m_pool.add_vector_elem(l1.index()); + m_pool.add_vector_elem(l2.index()); + } + } + + void par::share_clause(solver& s, clause const& c) { + if (s.m_par_syncing_clauses) return; + flet _disable_sync_clause(s.m_par_syncing_clauses, true); + unsigned n = c.size(); + unsigned owner = s.m_par_id; + #pragma omp critical (par_solver) + { + if (enable_add(c)) { + IF_VERBOSE(3, verbose_stream() << owner << ": share " << c << "\n";); + m_pool.begin_add_vector(owner, n); + for (unsigned i = 0; i < n; ++i) { + m_pool.add_vector_elem(c[i].index()); + } + } + } + } + + void par::get_clauses(solver& s) { + if (s.m_par_syncing_clauses) return; + flet _disable_sync_clause(s.m_par_syncing_clauses, true); + #pragma omp critical (par_solver) + { + _get_clauses(s); + } + } + + void par::_get_clauses(solver& s) { + unsigned n; + unsigned const* ptr; + unsigned owner = s.m_par_id; + while (m_pool.get_vector(owner, n, ptr)) { + m_lits.reset(); + for (unsigned i = 0; i < n; ++i) { + m_lits.push_back(to_literal(ptr[i])); + } + IF_VERBOSE(3, verbose_stream() << s.m_par_id << ": retrieve " << m_lits << "\n";); + SASSERT(n >= 2); + s.mk_clause_core(m_lits.size(), m_lits.c_ptr(), true); + } + } + + bool par::enable_add(clause const& c) const { + // plingeling, glucose heuristic: + return (c.size() <= 40 && c.glue() <= 8) || c.glue() <= 2; + } + }; diff --git a/src/sat/sat_par.h b/src/sat/sat_par.h index 2b2592de7..f76b47536 100644 --- a/src/sat/sat_par.h +++ b/src/sat/sat_par.h @@ -26,12 +26,50 @@ Revision History: namespace sat { class par { + + // shared pool of learned clauses. + class vector_pool { + unsigned_vector m_vectors; + unsigned m_size; + unsigned m_tail; + unsigned_vector m_heads; + void next(unsigned& index); + unsigned get_owner(unsigned index) const { return m_vectors[index]; } + unsigned get_length(unsigned index) const { return m_vectors[index+1]; } + unsigned const* get_ptr(unsigned index) const { return m_vectors.c_ptr() + index + 2; } + public: + vector_pool() {} + void reserve(unsigned num_owners, unsigned sz); + void begin_add_vector(unsigned owner, unsigned n); + void add_vector_elem(unsigned e); + bool get_vector(unsigned owner, unsigned& n, unsigned const*& ptr); + }; + + bool enable_add(clause const& c) const; + void _get_clauses(solver& s); + typedef hashtable index_set; literal_vector m_units; index_set m_unit_set; + literal_vector m_lits; + vector_pool m_pool; public: + par(); - void exchange(literal_vector const& in, unsigned& limit, literal_vector& out); + + // reserve space + void reserve(unsigned num_owners, unsigned sz) { m_pool.reserve(num_owners, sz); } + + // exchange unit literals + void exchange(solver& s, literal_vector const& in, unsigned& limit, literal_vector& out); + + // add clause to shared clause pool + void share_clause(solver& s, clause const& c); + + void share_clause(solver& s, literal l1, literal l2); + + // receive clauses from shared clause pool + void get_clauses(solver& s); }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index dc9622a6b..beb53fd93 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -36,6 +36,8 @@ namespace sat { m_config(p), m_ext(ext), m_par(0), + m_par_syncing_clauses(false), + m_par_id(0), m_cleaner(*this), m_simplifier(*this, p), m_scc(*this, p), @@ -234,6 +236,7 @@ namespace sat { return 0; case 2: mk_bin_clause(lits[0], lits[1], learned); + if (learned && m_par) m_par->share_clause(*this, lits[0], lits[1]); return 0; case 3: return mk_ter_clause(lits, learned); @@ -836,6 +839,7 @@ namespace sat { vector rlims(num_extra_solvers); ptr_vector solvers(num_extra_solvers); sat::par par; + par.reserve(num_threads, 1 << 9); symbol saved_phase = m_params.get_sym("phase", symbol("caching")); for (int i = 0; i < num_extra_solvers; ++i) { m_params.set_uint("random_seed", m_rand()); @@ -844,10 +848,10 @@ namespace sat { } solvers[i] = alloc(sat::solver, m_params, rlims[i], 0); solvers[i]->copy(*this); - solvers[i]->set_par(&par); + solvers[i]->set_par(&par, i); scoped_rlimit.push_child(&solvers[i]->rlimit()); } - set_par(&par); + set_par(&par, num_extra_solvers); m_params.set_sym("phase", saved_phase); int finished_id = -1; std::string ex_msg; @@ -901,7 +905,7 @@ namespace sat { } } } - set_par(0); + set_par(0, 0); if (finished_id != -1 && finished_id < num_extra_solvers) { m_stats = solvers[finished_id]->m_stats; } @@ -923,7 +927,9 @@ namespace sat { \brief import lemmas/units from parallel sat solvers. */ void solver::exchange_par() { - if (m_par) { + if (m_par && at_base_lvl()) m_par->get_clauses(*this); + if (m_par && at_base_lvl()) { + // std::cout << scope_lvl() << " " << search_lvl() << "\n"; SASSERT(scope_lvl() == search_lvl()); // TBD: import also dependencies of assumptions. unsigned sz = init_trail_size(); @@ -937,7 +943,7 @@ namespace sat { } } m_par_limit_out = sz; - m_par->exchange(out, m_par_limit_in, in); + m_par->exchange(*this, out, m_par_limit_in, in); for (unsigned i = 0; !inconsistent() && i < in.size(); ++i) { literal lit = in[i]; SASSERT(lit.var() < m_par_num_vars); @@ -952,11 +958,13 @@ namespace sat { } } - void solver::set_par(par* p) { + void solver::set_par(par* p, unsigned id) { m_par = p; m_par_num_vars = num_vars(); m_par_limit_in = 0; m_par_limit_out = 0; + m_par_id = id; + m_par_syncing_clauses = false; } bool_var solver::next_var() { @@ -1855,10 +1863,11 @@ namespace sat { unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.c_ptr()); pop_reinit(m_scope_lvl - new_scope_lvl); - TRACE("sat_conflict_detail", display(tout); tout << "assignment:\n"; display_assignment(tout);); + TRACE("sat_conflict_detail", tout << new_scope_lvl << "\n"; display(tout);); clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.c_ptr(), true); if (lemma) { lemma->set_glue(glue); + if (m_par) m_par->share_clause(*this, *lemma); } decay_activity(); updt_phase_counters(); @@ -1881,8 +1890,7 @@ namespace sat { TRACE("sat", tout << "processing consequent: "; if (consequent == null_literal) tout << "null\n"; else tout << consequent << "\n"; - display_justification(tout << "js kind: ", js); - tout << "\n";); + display_justification(tout << "js kind: ", js) << "\n";); switch (js.get_kind()) { case justification::NONE: break; @@ -1962,8 +1970,7 @@ namespace sat { if (m_not_l != null_literal) { justification js = m_justification[m_not_l.var()]; TRACE("sat", tout << "not_l: " << m_not_l << "\n"; - display_justification(tout, js); - tout << "\n";); + display_justification(tout, js) << "\n";); process_antecedent_for_unsat_core(m_not_l); if (is_assumption(~m_not_l)) { @@ -2774,10 +2781,15 @@ namespace sat { void solver::display_units(std::ostream & out) const { unsigned end = m_trail.size(); // init_trail_size(); + unsigned level = 0; for (unsigned i = 0; i < end; i++) { - out << m_trail[i] << " "; - display_justification(out, m_justification[m_trail[i].var()]); - out << "\n"; + literal lit = m_trail[i]; + if (lvl(lit) > level) { + level = lvl(lit); + out << "level: " << level << " - "; + } + out << lit << " "; + display_justification(out, m_justification[lit.var()]) << "\n"; } //if (end != 0) // out << "\n"; @@ -2794,7 +2806,7 @@ namespace sat { out << ")\n"; } - void solver::display_justification(std::ostream & out, justification const& js) const { + std::ostream& solver::display_justification(std::ostream & out, justification const& js) const { out << js; if (js.is_clause()) { out << *(m_cls_allocator.get_clause(js.get_clause_offset())); @@ -2802,6 +2814,7 @@ namespace sat { else if (js.is_ext_justification() && m_ext) { m_ext->display_justification(out << " ", js.get_ext_justification_idx()); } + return out; } unsigned solver::num_clauses() const { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index f43418d22..af1b8f213 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -134,9 +134,11 @@ namespace sat { literal_set m_assumption_set; // set of enabled assumptions literal_vector m_core; // unsat core + unsigned m_par_id; unsigned m_par_limit_in; unsigned m_par_limit_out; unsigned m_par_num_vars; + bool m_par_syncing_clauses; void del_clauses(clause * const * begin, clause * const * end); @@ -151,6 +153,7 @@ namespace sat { friend class mus; friend class drat; friend class card_extension; + friend class par; friend struct mk_stat; public: solver(params_ref const & p, reslimit& l, extension * ext); @@ -257,7 +260,7 @@ namespace sat { m_num_checkpoints = 0; if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG); } - void set_par(par* p); + void set_par(par* p, unsigned id); bool canceled() { return !m_rlimit.inc(); } config const& get_config() { return m_config; } extension* get_extension() const { return m_ext.get(); } @@ -525,7 +528,7 @@ namespace sat { void display_dimacs(std::ostream & out) const; void display_wcnf(std::ostream & out, unsigned sz, literal const* lits, unsigned const* weights) const; void display_assignment(std::ostream & out) const; - void display_justification(std::ostream & out, justification const& j) const; + std::ostream& display_justification(std::ostream & out, justification const& j) const; protected: void display_binary(std::ostream & out) const; From fe105d94a08c3e65fbd83f3ed3e8d21f14ee8266 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Feb 2017 12:00:35 -0800 Subject: [PATCH 0030/1283] fixes to sat-par Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 3 -- src/sat/card_extension.cpp | 4 +-- src/sat/sat_par.cpp | 49 +++++++++++++++++++++++++------- src/sat/sat_par.h | 16 ++++++++++- src/sat/sat_solver.cpp | 57 +++++++++++++++----------------------- 5 files changed, 78 insertions(+), 51 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 6c8d5af3a..7e9381e1d 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -352,9 +352,6 @@ public: while (is_sat == l_false) { core.reset(); s().get_unsat_core(core); - expr_ref_vector core1(m); - core1.append(core.size(), core.c_ptr()); - std::cout << core1 << "\n"; // verify_core(core); model_ref mdl; get_mus_model(mdl); diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index c051ded15..351c487bd 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -378,7 +378,7 @@ namespace sat { if (offset > m_bound) { m_coeffs[v] = (get_coeff(v) < 0) ? -m_bound : m_bound; offset = m_bound; - // TBD: also adjust coefficient in m_A. + DEBUG_CODE(active2pb(m_A);); } SASSERT(value(consequent) == l_true); @@ -424,7 +424,7 @@ namespace sat { m_lemma.push_back(~lit); if (lvl(lit) == m_conflict_lvl) { TRACE("sat", tout << "Bail out on no progress " << lit << "\n";); - IF_VERBOSE(1, verbose_stream() << "bail cardinality lemma\n";); + IF_VERBOSE(3, verbose_stream() << "(sat.card bail resolve)\n";); return false; } } diff --git a/src/sat/sat_par.cpp b/src/sat/sat_par.cpp index 585bd8bcc..8b8c8e309 100644 --- a/src/sat/sat_par.cpp +++ b/src/sat/sat_par.cpp @@ -50,10 +50,12 @@ namespace sat { if (m_tail >= m_size) { // move tail to the front. for (unsigned i = 0; i < m_heads.size(); ++i) { + // the tail could potentially loop around full circle before one of the heads picks up anything. + // in this case the we miss the newly inserted record. while (m_heads[i] < capacity) { next(m_heads[i]); } - IF_VERBOSE(3, verbose_stream() << owner << ": head: " << m_heads[i] << "\n";); + IF_VERBOSE(3, verbose_stream() << owner << ": head: " << m_heads[i] << "\n";); } m_tail = 0; } @@ -75,8 +77,8 @@ namespace sat { bool par::vector_pool::get_vector(unsigned owner, unsigned& n, unsigned const*& ptr) { unsigned head = m_heads[owner]; - SASSERT(head < m_size); while (head != m_tail) { + SASSERT(head < m_size); IF_VERBOSE(3, verbose_stream() << owner << ": head: " << head << " tail: " << m_tail << "\n";); bool is_self = owner == get_owner(head); next(m_heads[owner]); @@ -86,11 +88,40 @@ namespace sat { return true; } head = m_heads[owner]; + if (head == 0 && m_tail >= m_size) { + break; + } } return false; } - par::par() {} + par::par(solver& s): m_scoped_rlimit(s.rlimit()) {} + + par::~par() { + for (unsigned i = 0; i < m_solvers.size(); ++i) { + dealloc(m_solvers[i]); + } + } + + void par::init_solvers(solver& s, unsigned num_extra_solvers) { + unsigned num_threads = num_extra_solvers + 1; + m_solvers.resize(num_extra_solvers, 0); + symbol saved_phase = s.m_params.get_sym("phase", symbol("caching")); + for (unsigned i = 0; i < num_extra_solvers; ++i) { + m_limits.push_back(reslimit()); + s.m_params.set_uint("random_seed", s.m_rand()); + if (i == 1 + num_threads/2) { + s.m_params.set_sym("phase", symbol("random")); + } + m_solvers[i] = alloc(sat::solver, s.m_params, m_limits[i], 0); + m_solvers[i]->copy(s); + m_solvers[i]->set_par(this, i); + m_scoped_rlimit.push_child(&m_solvers[i]->rlimit()); + } + s.set_par(this, num_extra_solvers); + s.m_params.set_sym("phase", saved_phase); + } + void par::exchange(solver& s, literal_vector const& in, unsigned& limit, literal_vector& out) { if (s.m_par_syncing_clauses) return; @@ -125,18 +156,16 @@ namespace sat { } void par::share_clause(solver& s, clause const& c) { - if (s.m_par_syncing_clauses) return; + if (!enable_add(c) || s.m_par_syncing_clauses) return; flet _disable_sync_clause(s.m_par_syncing_clauses, true); unsigned n = c.size(); unsigned owner = s.m_par_id; #pragma omp critical (par_solver) { - if (enable_add(c)) { - IF_VERBOSE(3, verbose_stream() << owner << ": share " << c << "\n";); - m_pool.begin_add_vector(owner, n); - for (unsigned i = 0; i < n; ++i) { - m_pool.add_vector_elem(c[i].index()); - } + IF_VERBOSE(3, verbose_stream() << owner << ": share " << c << "\n";); + m_pool.begin_add_vector(owner, n); + for (unsigned i = 0; i < n; ++i) { + m_pool.add_vector_elem(c[i].index()); } } } diff --git a/src/sat/sat_par.h b/src/sat/sat_par.h index f76b47536..dd2e93f95 100644 --- a/src/sat/sat_par.h +++ b/src/sat/sat_par.h @@ -22,6 +22,7 @@ Revision History: #include"sat_types.h" #include"hashtable.h" #include"map.h" +#include"rlimit.h" namespace sat { @@ -53,13 +54,26 @@ namespace sat { index_set m_unit_set; literal_vector m_lits; vector_pool m_pool; + + scoped_limits m_scoped_rlimit; + vector m_limits; + ptr_vector m_solvers; + public: - par(); + par(solver& s); + + ~par(); + + void init_solvers(solver& s, unsigned num_extra_solvers); // reserve space void reserve(unsigned num_owners, unsigned sz) { m_pool.reserve(num_owners, sz); } + solver& get_solver(unsigned i) { return *m_solvers[i]; } + + void cancel_solver(unsigned i) { m_limits[i].cancel(); } + // exchange unit literals void exchange(solver& s, literal_vector const& in, unsigned& limit, literal_vector& out); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index beb53fd93..2dcbf7cbb 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -835,35 +835,21 @@ namespace sat { lbool solver::check_par(unsigned num_lits, literal const* lits) { int num_threads = static_cast(m_config.m_num_parallel); int num_extra_solvers = num_threads - 1; - scoped_limits scoped_rlimit(rlimit()); - vector rlims(num_extra_solvers); - ptr_vector solvers(num_extra_solvers); - sat::par par; - par.reserve(num_threads, 1 << 9); - symbol saved_phase = m_params.get_sym("phase", symbol("caching")); - for (int i = 0; i < num_extra_solvers; ++i) { - m_params.set_uint("random_seed", m_rand()); - if (i == 1 + num_threads/2) { - m_params.set_sym("phase", symbol("random")); - } - solvers[i] = alloc(sat::solver, m_params, rlims[i], 0); - solvers[i]->copy(*this); - solvers[i]->set_par(&par, i); - scoped_rlimit.push_child(&solvers[i]->rlimit()); - } - set_par(&par, num_extra_solvers); - m_params.set_sym("phase", saved_phase); + sat::par par(*this); + par.reserve(num_threads, 1 << 16); + par.init_solvers(*this, num_extra_solvers); int finished_id = -1; std::string ex_msg; par_exception_kind ex_kind; unsigned error_code = 0; lbool result = l_undef; + bool canceled = false; #pragma omp parallel for for (int i = 0; i < num_threads; ++i) { try { lbool r = l_undef; if (i < num_extra_solvers) { - r = solvers[i]->check(num_lits, lits); + r = par.get_solver(i).check(num_lits, lits); } else { r = check(num_lits, lits); @@ -879,40 +865,40 @@ namespace sat { } if (first) { if (r == l_true && i < num_extra_solvers) { - set_model(solvers[i]->get_model()); + set_model(par.get_solver(i).get_model()); } else if (r == l_false && i < num_extra_solvers) { m_core.reset(); - m_core.append(solvers[i]->get_core()); + m_core.append(par.get_solver(i).get_core()); } for (int j = 0; j < num_extra_solvers; ++j) { if (i != j) { - rlims[j].cancel(); + par.cancel_solver(j); } } + if (i != num_extra_solvers) { + canceled = rlimit().inc(); + rlimit().cancel(); + } } } catch (z3_error & err) { - if (i == 0) { - error_code = err.error_code(); - ex_kind = ERROR_EX; - } + error_code = err.error_code(); + ex_kind = ERROR_EX; } catch (z3_exception & ex) { - if (i == 0) { - ex_msg = ex.msg(); - ex_kind = DEFAULT_EX; - } + ex_msg = ex.msg(); + ex_kind = DEFAULT_EX; } } set_par(0, 0); if (finished_id != -1 && finished_id < num_extra_solvers) { - m_stats = solvers[finished_id]->m_stats; + m_stats = par.get_solver(finished_id).m_stats; + } + if (!canceled) { + rlimit().reset_cancel(); } - for (int i = 0; i < num_extra_solvers; ++i) { - dealloc(solvers[i]); - } if (finished_id == -1) { switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); @@ -1728,10 +1714,10 @@ namespace sat { bool solver::resolve_conflict_core() { - m_stats.m_conflict++; m_conflicts++; m_conflicts_since_restart++; m_conflicts_since_gc++; + m_stats.m_conflict++; m_conflict_lvl = get_max_lvl(m_not_l, m_conflict); TRACE("sat", tout << "conflict detected at level " << m_conflict_lvl << " for "; @@ -1751,6 +1737,7 @@ namespace sat { if (m_ext && m_ext->resolve_conflict()) { learn_lemma_and_backjump(); + m_stats.m_conflict--; return true; } From 4831c45ad8fcc5796b07faf070e47603b662756e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Feb 2017 13:38:07 -0800 Subject: [PATCH 0031/1283] fix issues in par Signed-off-by: Nikolaj Bjorner --- src/sat/sat_par.cpp | 14 +++++++++----- src/sat/sat_solver.cpp | 14 +++++++++++--- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_par.cpp b/src/sat/sat_par.cpp index 8b8c8e309..cd8901e09 100644 --- a/src/sat/sat_par.cpp +++ b/src/sat/sat_par.cpp @@ -77,9 +77,14 @@ namespace sat { bool par::vector_pool::get_vector(unsigned owner, unsigned& n, unsigned const*& ptr) { unsigned head = m_heads[owner]; + unsigned iterations = 0; while (head != m_tail) { + ++iterations; + if (head == 0 && m_tail >= m_size) { + break; + } SASSERT(head < m_size); - IF_VERBOSE(3, verbose_stream() << owner << ": head: " << head << " tail: " << m_tail << "\n";); + IF_VERBOSE((iterations > m_size ? 0 : 3), verbose_stream() << owner << ": head: " << head << " tail: " << m_tail << "\n";); bool is_self = owner == get_owner(head); next(m_heads[owner]); if (!is_self) { @@ -88,9 +93,6 @@ namespace sat { return true; } head = m_heads[owner]; - if (head == 0 && m_tail >= m_size) { - break; - } } return false; } @@ -107,8 +109,10 @@ namespace sat { unsigned num_threads = num_extra_solvers + 1; m_solvers.resize(num_extra_solvers, 0); symbol saved_phase = s.m_params.get_sym("phase", symbol("caching")); - for (unsigned i = 0; i < num_extra_solvers; ++i) { + for (unsigned i = 0; i < num_extra_solvers; ++i) { m_limits.push_back(reslimit()); + } + for (unsigned i = 0; i < num_extra_solvers; ++i) { s.m_params.set_uint("random_seed", s.m_rand()); if (i == 1 + num_threads/2) { s.m_params.set_sym("phase", symbol("random")); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2dcbf7cbb..c843fc900 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -364,6 +364,11 @@ namespace sat { } unsigned some_idx = c.size() >> 1; literal block_lit = c[some_idx]; + if (m_watches.size() <= (~c[0]).index()) std::cout << c << "\n"; + if (m_watches.size() <= (~c[1]).index()) std::cout << c << "\n"; + if (m_watches[(~c[0]).index()].size() >= 20000) { + std::cout << m_par_id << ": " << c << "\n"; + } 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; @@ -836,7 +841,8 @@ namespace sat { int num_threads = static_cast(m_config.m_num_parallel); int num_extra_solvers = num_threads - 1; sat::par par(*this); - par.reserve(num_threads, 1 << 16); + // par.reserve(num_threads, 1 << 16); + par.reserve(num_threads, 1 << 9); par.init_solvers(*this, num_extra_solvers); int finished_id = -1; std::string ex_msg; @@ -877,8 +883,10 @@ namespace sat { } } if (i != num_extra_solvers) { - canceled = rlimit().inc(); - rlimit().cancel(); + canceled = !rlimit().inc(); + if (!canceled) { + rlimit().cancel(); + } } } } From 66089a7aef8d4ba53f834f09da1a3c6223419d60 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Feb 2017 16:09:46 -0800 Subject: [PATCH 0032/1283] fix compiler errors and memory issue with drat Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 12 +++++++----- src/sat/sat_drat.h | 10 +++++----- src/sat/sat_par.cpp | 2 +- src/sat/sat_solver.cpp | 4 ++-- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index fb161a998..6d0c2979b 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -58,7 +58,6 @@ namespace sat { } void drat::dump(unsigned n, literal const* c, status st) { - if (is_cleaned(n, c)) return; switch (st) { case status::asserted: return; case status::external: return; // requires extension to drat format. @@ -69,8 +68,9 @@ namespace sat { (*m_out) << "0\n"; } - bool drat::is_cleaned(unsigned n, literal const* c) const { + bool drat::is_cleaned(clause& c) const { literal last = null_literal; + unsigned n = c.size(); for (unsigned i = 0; i < n; ++i) { if (c[i] == last) return true; last = c[i]; @@ -133,7 +133,6 @@ namespace sat { void drat::append(clause& c, status st) { unsigned n = c.size(); - if (is_cleaned(n, c.begin())) return; trace(std::cout, n, c.begin(), st); if (st == status::learned) { @@ -394,10 +393,13 @@ namespace sat { void drat::del(literal l1, literal l2) { literal ls[2] = {l1, l2}; if (m_out) dump(2, ls, status::deleted); - if (s.m_config.m_drat_check) append(l1, l2, status::deleted); + if (s.m_config.m_drat_check) + append(l1, l2, status::deleted); } void drat::del(clause& c) { if (m_out) dump(c.size(), c.begin(), status::deleted); - if (s.m_config.m_drat_check) append(c, status::deleted); + if (s.m_config.m_drat_check) + append(c, status::deleted); + else s.m_cls_allocator.del_clause(&c); } } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index fd4b3f868..7236d8065 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -28,10 +28,10 @@ namespace sat { enum { t_clause, t_unit, t_ext } m_type; union { clause* m_clause; - literal m_literal; + unsigned m_literal; }; - premise(s_ext, literal l): m_type(t_ext), m_literal(l) {} - premise(s_unit, literal l): m_type(t_unit), m_literal(l) {} + premise(s_ext, literal l): m_type(t_ext), m_literal(l.index()) {} + premise(s_unit, literal l): m_type(t_unit), m_literal(l.index()) {} premise(clause* c): m_type(t_clause), m_clause(c) {} }; private: @@ -52,7 +52,6 @@ namespace sat { void append(clause& c, status st); friend std::ostream& operator<<(std::ostream & out, status st); status get_status(bool learned) const; - bool is_cleaned(unsigned n, literal const* lits) const; void declare(literal l); void assign(literal l); @@ -74,7 +73,8 @@ namespace sat { void add(literal l1, literal l2, bool learned); void add(clause& c, bool learned); void add(literal_vector const& c, svector const& premises); - + + bool is_cleaned(clause& c) const; void del(literal l); void del(literal l1, literal l2); void del(clause& c); diff --git a/src/sat/sat_par.cpp b/src/sat/sat_par.cpp index cd8901e09..f3e2be5c2 100644 --- a/src/sat/sat_par.cpp +++ b/src/sat/sat_par.cpp @@ -84,7 +84,7 @@ namespace sat { break; } SASSERT(head < m_size); - IF_VERBOSE((iterations > m_size ? 0 : 3), verbose_stream() << owner << ": head: " << head << " tail: " << m_tail << "\n";); + IF_VERBOSE(static_cast(iterations > m_size ? 0 : 3), verbose_stream() << owner << ": head: " << head << " tail: " << m_tail << "\n";); bool is_self = owner == get_owner(head); next(m_heads[owner]); if (!is_self) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c843fc900..fabca528d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -206,10 +206,10 @@ namespace sat { if (!c.is_learned()) { m_stats.m_non_learned_generation++; } - if (m_config.m_drat) { + if (m_config.m_drat && !m_drat.is_cleaned(c)) { m_drat.del(c); } - else if (!m_config.m_drat || !m_config.m_drat_check) { + else if (!m_config.m_drat || !m_config.m_drat_check || m_drat.is_cleaned(c)) { m_cls_allocator.del_clause(&c); } m_stats.m_del_clause++; From 61ade5e6cba53785f3e255f5f0d1dd22f06ad129 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Feb 2017 20:57:08 -0800 Subject: [PATCH 0033/1283] tune cardinality solver for cache misses Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 43 ++++++++++++++++++++++----- src/sat/card_extension.h | 9 ++++-- src/sat/sat_cleaner.cpp | 9 ++++-- src/sat/sat_par.cpp | 2 +- src/sat/sat_simplifier.cpp | 3 ++ src/sat/sat_solver.cpp | 11 ++++--- src/sat/sat_solver.h | 3 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 25 +++++++++++----- src/sat/tactic/sat_tactic.cpp | 2 +- src/shell/dimacs_frontend.cpp | 5 ++-- src/test/sat_user_scope.cpp | 4 +-- 12 files changed, 85 insertions(+), 33 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 351c487bd..546a6905d 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -119,20 +119,37 @@ namespace sat { if (m_var_infos.size() <= static_cast(lit.var())) { return; } - ptr_vector* cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; + ptr_vector*& cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; if (cards) { - remove(*cards, c); + if (remove(*cards, c)) { + std::cout << "Empty: " << cards->empty() << "\n"; + cards = set_tag_empty(cards); + } } } - void card_extension::remove(ptr_vector& cards, card* c) { - for (unsigned j = 0; j < cards.size(); ++j) { + ptr_vector* card_extension::set_tag_empty(ptr_vector* c) { + return TAG(ptr_vector*, c, 1); + } + + bool card_extension::is_tag_empty(ptr_vector* c) { + return !c || GET_TAG(c) == 1; + } + + ptr_vector* card_extension::set_tag_non_empty(ptr_vector* c) { + return UNTAG(ptr_vector*, c); + } + + bool card_extension::remove(ptr_vector& cards, card* c) { + unsigned sz = cards.size(); + for (unsigned j = 0; j < sz; ++j) { if (cards[j] == c) { - std::swap(cards[j], cards[cards.size()-1]); + std::swap(cards[j], cards[sz-1]); cards.pop_back(); - break; + return sz == 1; } } + return false; } void card_extension::assign(card& c, literal lit) { @@ -171,6 +188,10 @@ namespace sat { cards = alloc(ptr_vector); m_var_infos[lit.var()].m_lit_watch[lit.sign()] = cards; } + else if (is_tag_empty(cards)) { + cards = set_tag_non_empty(cards); + m_var_infos[lit.var()].m_lit_watch[lit.sign()] = cards; + } TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); cards->push_back(&c); } @@ -617,13 +638,16 @@ namespace sat { void card_extension::asserted(literal l) { bool_var v = l.var(); + if (s().inconsistent()) return; if (v >= m_var_infos.size()) return; var_info& vinfo = m_var_infos[v]; ptr_vector* cards = vinfo.m_lit_watch[!l.sign()]; //TRACE("sat", tout << "retrieve: " << v << " " << !l.sign() << "\n";); //TRACE("sat", tout << "asserted: " << l << " " << (cards ? "non-empty" : "empty") << "\n";); - if (cards != 0 && !cards->empty() && !s().inconsistent()) { - ptr_vector::iterator it = cards->begin(), it2 = it, end = cards->end(); + static unsigned is_empty = 0, non_empty = 0; + if (!is_tag_empty(cards)) { + ptr_vector::iterator begin = cards->begin(); + ptr_vector::iterator it = begin, it2 = it, end = cards->end(); for (; it != end; ++it) { card& c = *(*it); if (value(c.lit()) != l_true) { @@ -648,6 +672,9 @@ namespace sat { } } cards->set_end(it2); + if (cards->empty()) { + m_var_infos[v].m_lit_watch[!l.sign()] = set_tag_empty(cards); + } } card* crd = vinfo.m_card; diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index dbc8f7b07..4a01bc7cc 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -71,11 +71,14 @@ namespace sat { } void reset() { dealloc(m_card); - dealloc(m_lit_watch[0]); - dealloc(m_lit_watch[1]); + dealloc(card_extension::set_tag_non_empty(m_lit_watch[0])); + dealloc(card_extension::set_tag_non_empty(m_lit_watch[1])); } }; + ptr_vector* set_tag_empty(ptr_vector* c); + bool is_tag_empty(ptr_vector* c); + static ptr_vector* set_tag_non_empty(ptr_vector* c); solver* m_solver; stats m_stats; @@ -113,7 +116,7 @@ namespace sat { inline unsigned lvl(bool_var v) const { return m_solver->lvl(v); } void unwatch_literal(literal w, card* c); - void remove(ptr_vector& cards, card* c); + bool remove(ptr_vector& cards, card* c); void normalize_active_coeffs(); void inc_coeff(literal l, int offset); diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 959f5e94f..10751c622 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -142,12 +142,17 @@ namespace sat { c.shrink(new_sz); *it2 = *it; it2++; - if (!c.frozen()) { - if (new_sz == 3) + if (!c.frozen()) { + if (new_sz == 3) s.attach_ter_clause(c); else s.attach_nary_clause(c); } + if (s.m_config.m_drat) { + // for optimization, could also report deletion + // of previous version of clause. + s.m_drat.add(c, true); + } } } } diff --git a/src/sat/sat_par.cpp b/src/sat/sat_par.cpp index cd8901e09..ec6e39822 100644 --- a/src/sat/sat_par.cpp +++ b/src/sat/sat_par.cpp @@ -117,7 +117,7 @@ namespace sat { if (i == 1 + num_threads/2) { s.m_params.set_sym("phase", symbol("random")); } - m_solvers[i] = alloc(sat::solver, s.m_params, m_limits[i], 0); + m_solvers[i] = alloc(sat::solver, s.m_params, m_limits[i]); m_solvers[i]->copy(s); m_solvers[i]->set_par(this, i); m_scoped_rlimit.push_child(&m_solvers[i]->rlimit()); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index bd975115b..8bfa4bb69 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -304,6 +304,9 @@ namespace sat { s.attach_ter_clause(c); else s.attach_nary_clause(c); + if (s.m_config.m_drat) { + s.m_drat.add(c, true); + } } } cs.set_end(it2); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c843fc900..9b50db8e8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -31,10 +31,9 @@ Revision History: namespace sat { - solver::solver(params_ref const & p, reslimit& l, extension * ext): + solver::solver(params_ref const & p, reslimit& l): m_rlimit(l), m_config(p), - m_ext(ext), m_par(0), m_par_syncing_clauses(false), m_par_id(0), @@ -59,7 +58,6 @@ namespace sat { m_conflicts = 0; m_next_simplify = 0; m_num_checkpoints = 0; - if (m_ext) m_ext->set_solver(this); } solver::~solver() { @@ -77,6 +75,11 @@ namespace sat { ++m_stats.m_non_learned_generation; } + void solver::set_extension(extension* ext) { + m_ext = ext; + if (ext) ext->set_solver(this); + } + void solver::copy(solver const & src) { pop_to_base_level(); SASSERT(m_mc.empty() && src.m_mc.empty()); @@ -771,7 +774,7 @@ namespace sat { flet _searching(m_searching, true); #ifdef CLONE_BEFORE_SOLVING if (m_mc.empty()) { - m_clone = alloc(solver, m_params, 0 /* do not clone extension */); + m_clone = alloc(solver, m_params); SASSERT(m_clone); } #endif diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index af1b8f213..d5affd2d4 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -156,7 +156,7 @@ namespace sat { friend class par; friend struct mk_stat; public: - solver(params_ref const & p, reslimit& l, extension * ext); + solver(params_ref const & p, reslimit& l); ~solver(); // ----------------------- @@ -264,6 +264,7 @@ namespace sat { bool canceled() { return !m_rlimit.inc(); } config const& get_config() { return m_config; } extension* get_extension() const { return m_ext.get(); } + void set_extension(extension* e); typedef std::pair bin_clause; protected: watch_list & get_wlist(literal l) { return m_watches[l.index()]; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 7715c4b5d..eec734dc7 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -72,7 +72,7 @@ class inc_sat_solver : public solver { public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), - m_solver(p, m.limit(), alloc(sat::card_extension)), + m_solver(p, m.limit()), m_params(p), m_optimize_model(false), m_fmls(m), m_asmsf(m), diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 923006da2..1fcaa78b1 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -78,11 +78,6 @@ struct goal2sat::imp { m_default_external(default_external) { updt_params(p); m_true = sat::null_bool_var; - sat::extension* e = m_solver.get_extension(); - if (e) { - sat::card_extension* ce = dynamic_cast(e); - m_ext = ce; - } } void updt_params(params_ref const & p) { @@ -158,7 +153,8 @@ struct goal2sat::imp { } bool convert_app(app* t, bool root, bool sign) { - if (m_ext && t->get_family_id() == pb.get_family_id()) { + if (t->get_family_id() == pb.get_family_id()) { + ensure_extension(); m_frame_stack.push_back(frame(to_app(t), root, sign, 0)); return false; } @@ -465,6 +461,20 @@ struct goal2sat::imp { } } + void ensure_extension() { + if (!m_ext) { + sat::extension* ext = m_solver.get_extension(); + if (ext) { + m_ext = dynamic_cast(ext); + SASSERT(m_ext); + } + if (!m_ext) { + m_ext = alloc(sat::card_extension); + m_solver.set_extension(m_ext); + } + } + } + void convert(app * t, bool root, bool sign) { if (t->get_family_id() == m.get_basic_family_id()) { switch (to_app(t)->get_decl_kind()) { @@ -485,7 +495,8 @@ struct goal2sat::imp { UNREACHABLE(); } } - else if (m_ext && t->get_family_id() == pb.get_family_id()) { + else if (t->get_family_id() == pb.get_family_id()) { + ensure_extension(); switch (t->get_decl_kind()) { case OP_AT_MOST_K: convert_at_most_k(t, pb.get_k(t), root, sign); diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index f99e46851..4432d0e3c 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -34,7 +34,7 @@ class sat_tactic : public tactic { imp(ast_manager & _m, params_ref const & p): m(_m), - m_solver(p, m.limit(), 0), + m_solver(p, m.limit()), m_params(p) { SASSERT(!m.proofs_enabled()); } diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 09645a25a..4cc9ec610 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -126,7 +126,6 @@ static void track_clauses(sat::solver const& src, } } - unsigned read_dimacs(char const * file_name) { g_start_time = clock(); register_on_timeout_proc(on_timeout); @@ -134,7 +133,7 @@ unsigned read_dimacs(char const * file_name) { params_ref p = gparams::get_module("sat"); p.set_bool("produce_models", true); reslimit limit; - sat::solver solver(p, limit, 0); + sat::solver solver(p, limit); g_solver = &solver; if (file_name) { @@ -152,7 +151,7 @@ unsigned read_dimacs(char const * file_name) { lbool r; vector tracking_clauses; - sat::solver solver2(p, limit, 0); + sat::solver solver2(p, limit); if (p.get_bool("dimacs.core", false)) { g_solver = &solver2; sat::literal_vector assumptions; diff --git a/src/test/sat_user_scope.cpp b/src/test/sat_user_scope.cpp index aa717f371..ebda383f9 100644 --- a/src/test/sat_user_scope.cpp +++ b/src/test/sat_user_scope.cpp @@ -59,7 +59,7 @@ static void init_vars(sat::solver& s) { static void check_coherence(sat::solver& s1, trail_t& t) { params_ref p; reslimit rlim; - sat::solver s2(p, rlim, 0); + sat::solver s2(p, rlim); init_vars(s2); sat::literal_vector cls; for (unsigned i = 0; i < t.size(); ++i) { @@ -85,7 +85,7 @@ void tst_sat_user_scope() { trail_t trail; params_ref p; reslimit rlim; - sat::solver s(p, rlim, 0); // incremental solver + sat::solver s(p, rlim); // incremental solver init_vars(s); while (true) { for (unsigned i = 0; i < s_num_frames; ++i) { From b6b6035cfb9bb06878f496b03ab5a19d9548a0a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Feb 2017 16:50:39 -0800 Subject: [PATCH 0034/1283] tuning and fixing drat checker Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 35 ++++---- src/ast/rewriter/pb2bv_rewriter.h | 1 + src/sat/sat_drat.cpp | 120 ++++++++++++++++---------- src/sat/sat_drat.h | 9 +- src/sat/sat_params.pyg | 1 - src/sat/sat_solver.cpp | 34 +++++++- src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 2 - src/tactic/portfolio/pb2bv_solver.cpp | 4 +- 9 files changed, 140 insertions(+), 67 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 1dd4ea6fa..9bc54ae74 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -49,7 +49,7 @@ struct pb2bv_rewriter::imp { expr_ref_vector m_args; rational m_k; vector m_coeffs; - bool m_enable_card; + bool m_keep_cardinality_constraints; template expr_ref mk_le_ge(expr_ref_vector& fmls, expr* a, expr* b, expr* bound) { @@ -240,7 +240,7 @@ struct pb2bv_rewriter::imp { bv(m), m_trail(m), m_args(m), - m_enable_card(false) + m_keep_cardinality_constraints(true) {} bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { @@ -354,27 +354,27 @@ struct pb2bv_rewriter::imp { bool mk_pb(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { SASSERT(f->get_family_id() == pb.get_family_id()); if (is_or(f)) { - if (m_enable_card) return false; + if (m_keep_cardinality_constraints) return false; result = m.mk_or(sz, args); } else if (pb.is_at_most_k(f) && pb.get_k(f).is_unsigned()) { - if (m_enable_card) return false; + if (m_keep_cardinality_constraints) return false; result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_at_least_k(f) && pb.get_k(f).is_unsigned()) { - if (m_enable_card) return false; + if (m_keep_cardinality_constraints) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - if (m_enable_card) return false; + if (m_keep_cardinality_constraints) return false; result = m_sort.eq(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - if (m_enable_card) return false; + if (m_keep_cardinality_constraints) return false; result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - if (m_enable_card) return false; + if (m_keep_cardinality_constraints) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } else { @@ -406,9 +406,8 @@ struct pb2bv_rewriter::imp { m_imp.m_lemmas.push_back(mk_or(m, n, lits)); } - void enable_card(bool f) { - m_enable_card = f; - m_enable_card = true; + void keep_cardinality_constraints(bool f) { + m_keep_cardinality_constraints = f; } }; @@ -421,7 +420,7 @@ struct pb2bv_rewriter::imp { return m_r.mk_app_core(f, num, args, result); } card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {} - void enable_card(bool f) { m_r.enable_card(f); } + void keep_cardinality_constraints(bool f) { m_r.keep_cardinality_constraints(f); } }; class card_pb_rewriter : public rewriter_tpl { @@ -430,7 +429,7 @@ struct pb2bv_rewriter::imp { card_pb_rewriter(imp& i, ast_manager & m): rewriter_tpl(m, false, m_cfg), m_cfg(i, m) {} - void enable_card(bool f) { m_cfg.enable_card(f); } + void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); } }; card_pb_rewriter m_rw; @@ -440,13 +439,17 @@ struct pb2bv_rewriter::imp { m_fresh(m), m_num_translated(0), m_rw(*this, m) { - m_rw.enable_card(p.get_bool("cardinality_solver", false)); + m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", true)); } void updt_params(params_ref const & p) { m_params.append(p); - m_rw.enable_card(m_params.get_bool("cardinality_solver", false)); + m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", true)); } + 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"); + } + unsigned get_num_steps() const { return m_rw.get_num_steps(); } void cleanup() { m_rw.cleanup(); } void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { @@ -483,6 +486,8 @@ struct pb2bv_rewriter::imp { pb2bv_rewriter::pb2bv_rewriter(ast_manager & m, params_ref const& p) { m_imp = alloc(imp, m, p); } pb2bv_rewriter::~pb2bv_rewriter() { dealloc(m_imp); } void pb2bv_rewriter::updt_params(params_ref const & p) { m_imp->updt_params(p); } +void pb2bv_rewriter::collect_param_descrs(param_descrs& r) const { m_imp->collect_param_descrs(r); } + ast_manager & pb2bv_rewriter::m() const { return m_imp->m; } unsigned pb2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } void pb2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } diff --git a/src/ast/rewriter/pb2bv_rewriter.h b/src/ast/rewriter/pb2bv_rewriter.h index 47d8361cb..c5a86221d 100644 --- a/src/ast/rewriter/pb2bv_rewriter.h +++ b/src/ast/rewriter/pb2bv_rewriter.h @@ -31,6 +31,7 @@ public: ~pb2bv_rewriter(); void updt_params(params_ref const & p); + void collect_param_descrs(param_descrs& r) const; ast_manager & m() const; unsigned get_num_steps() const; void cleanup(); diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 6d0c2979b..7f6368972 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -38,10 +38,7 @@ namespace sat { dealloc(m_out); for (unsigned i = 0; i < m_proof.size(); ++i) { clause* c = m_proof[i]; - if (m_status[i] == status::deleted || m_status[i] == status::external) { - s.m_cls_allocator.del_clause(c); - } - else if (c && c->size() == 2) { + if (c && (c->size() == 2 || m_status[i] == status::deleted || m_status[i] == status::external)) { s.m_cls_allocator.del_clause(c); } } @@ -116,8 +113,10 @@ namespace sat { clause* c = s.m_cls_allocator.mk_clause(2, lits, st == status::learned); m_proof.push_back(c); m_status.push_back(st); - m_watches[(~l1).index()].push_back(c); - m_watches[(~l2).index()].push_back(c); + unsigned idx = m_watched_clauses.size(); + m_watched_clauses.push_back(watched_clause(c, l1, l2)); + m_watches[(~l1).index()].push_back(idx); + m_watches[(~l2).index()].push_back(idx); if (value(l1) == l_false && value(l2) == l_false) { m_inconsistent = true; @@ -146,34 +145,43 @@ namespace sat { del_watch(c, c[1]); return; } - literal l1 = null_literal, l2 = null_literal; + unsigned num_watch = 0; + literal l1, l2; for (unsigned i = 0; i < n; ++i) { if (value(c[i]) != l_false) { - if (l1 == null_literal) { - l1 = c[i]; + if (num_watch == 0) { + l1 = c[i]; + ++num_watch; } else { l2 = c[i]; + ++num_watch; break; } } } - if (l2 == null_literal && l1 != null_literal) { - assign_propagate(l1); + switch (num_watch) { + case 0: + m_inconsistent = true; + break; + case 1: + assign_propagate(l1); + break; + default: { + SASSERT(num_watch == 2); + unsigned idx = m_watched_clauses.size(); + m_watched_clauses.push_back(watched_clause(&c, l1, l2)); + m_watches[(~l1).index()].push_back(idx); + m_watches[(~l2).index()].push_back(idx); + break; } - else if (l1 == null_literal) { - m_inconsistent = true; - } - else { - m_watches[(~l1).index()].push_back(&c); - m_watches[(~l2).index()].push_back(&c); } } void drat::del_watch(clause& c, literal l) { watch& w = m_watches[(~l).index()]; for (unsigned i = 0; i < w.size(); ++i) { - if (w[i] == &c) { + if (m_watched_clauses[w[i]].m_clause == &c) { w[i] = w.back(); w.pop_back(); break; @@ -196,6 +204,9 @@ namespace sat { for (unsigned i = 0; !m_inconsistent && i < n; ++i) { assign_propagate(~c[i]); } + if (!m_inconsistent) { + TRACE("sat", display(tout);); + } for (unsigned i = num_units; i < m_units.size(); ++i) { m_assignment[m_units[i].var()] = l_undef; } @@ -233,36 +244,53 @@ namespace sat { else { std::cout << "Verification failed\n"; display(std::cout); + TRACE("sat", display(tout); s.display(tout);); + UNREACHABLE(); exit(0); } } void drat::display(std::ostream& out) const { out << "units: " << m_units << "\n"; -#if 0 +#if 1 for (unsigned i = 0; i < m_assignment.size(); ++i) { - lbool v = value(literal(i, false)); - if (v != l_undef) std::cout << i << ": " << v << "\n"; + lbool v = value(literal(i, false)); + if (v != l_undef) out << i << ": " << v << "\n"; } #endif for (unsigned i = 0; i < m_proof.size(); ++i) { clause* c = m_proof[i]; if (m_status[i] != status::deleted && c) { + unsigned num_true = 0; + unsigned num_undef = 0; + for (unsigned j = 0; j < c->size(); ++j) { + switch (value((*c)[j])) { + case l_true: num_true++; break; + case l_undef: num_undef++; break; + default: break; + } + } + if (num_true == 0 && num_undef == 0) { + out << "False "; + } + if (num_true == 0 && num_undef == 1) { + out << "Unit "; + } out << i << ": " << *c << "\n"; } } -#if 0 +#if 1 for (unsigned i = 0; i < m_assignment.size(); ++i) { watch const& w1 = m_watches[2*i]; watch const& w2 = m_watches[2*i + 1]; if (!w1.empty()) { out << i << " |-> "; - for (unsigned i = 0; i < w1.size(); ++i) out << w1[i] << " "; + for (unsigned i = 0; i < w1.size(); ++i) out << *(m_watched_clauses[w1[i]].m_clause) << " "; out << "\n"; } if (!w2.empty()) { out << "-" << i << " |-> "; - for (unsigned i = 0; i < w2.size(); ++i) out << w2[i] << " "; + for (unsigned i = 0; i < w2.size(); ++i) out << *(m_watched_clauses[w2[i]].m_clause) << " "; out << "\n"; } } @@ -302,41 +330,45 @@ namespace sat { watch::iterator it2 = it; watch::iterator end = clauses.end(); for (; it != end; ++it) { - clause& c = *(*it); - if (c[0] == ~l) { - std::swap(c[0], c[1]); + unsigned idx = *it; + watched_clause& wc = m_watched_clauses[idx]; + clause& c = *wc.m_clause; + + TRACE("sat", tout << "Propagate " << l << " " << c << " watch: " << wc.m_l1 << " " << wc.m_l2 << "\n";); + if (wc.m_l1 == ~l) { + std::swap(wc.m_l1, wc.m_l2); } - if (c[1] != ~l) { + if (wc.m_l2 != ~l) { + std::cout << wc.m_l1 << " " << wc.m_l2 << " ~l: " << ~l << "\n"; + std::cout << *wc.m_clause << "\n"; + } + SASSERT(wc.m_l2 == ~l); + if (value(wc.m_l1) == l_true) { *it2 = *it; it2++; - continue; - } - SASSERT(c[1] == ~l); - if (value(c[0]) == l_true) { - it2++; } else { - literal * l_it = c.begin() + 2; - literal * l_end = c.end(); bool done = false; - for (; l_it != l_end && !done; ++l_it) { - if (value(*l_it) != l_false) { - c[1] = *l_it; - *l_it = ~l; - m_watches[(~c[1]).index()].push_back(&c); + for (unsigned i = 0; !done && i < c.size(); ++i) { + literal lit = c[i]; + if (lit != wc.m_l1 && lit != wc.m_l2 && value(lit) != l_false) { + wc.m_l2 = lit; + m_watches[(~lit).index()].push_back(idx); done = true; - } + } } - if (done) + if (done) { + it2++; continue; - else if (value(c[0]) == l_false) { + } + else if (value(wc.m_l1) == l_false) { m_inconsistent = true; goto end_process_watch; } else { *it2 = *it; it2++; - assign(c[0]); + assign(wc.m_l1); } } } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 7236d8065..8edaa5001 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -36,7 +36,14 @@ namespace sat { }; private: enum status { asserted, learned, deleted, external }; - typedef ptr_vector watch; + struct watched_clause { + clause* m_clause; + literal m_l1, m_l2; + watched_clause(clause* c, literal l1, literal l2): + m_clause(c), m_l1(l1), m_l2(l2) {} + }; + svector m_watched_clauses; + typedef svector watch; solver& s; std::ostream* m_out; ptr_vector m_proof; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 69b2bcea1..98e7fabf1 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -23,7 +23,6 @@ def_module_params('sat', ('core.minimize', BOOL, False, 'minimize computed core'), ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('parallel_threads', UINT, 1, 'number of parallel threads to use'), - ('cardinality_solver', BOOL, False, 'enable cardinality based solver'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat', BOOL, False, 'produce DRAT proofs'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 221140590..73829c6b8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -718,8 +718,8 @@ namespace sat { assign_core(c[0], justification(cls_off)); #ifdef UPDATE_GLUE if (update && c.is_learned() && c.glue() > 2) { - unsigned glue = num_diff_levels(c.size(), c.begin()); - if (glue+1 < c.glue()) { + unsigned glue; + if (num_diff_levels_below(c.size(), c.begin(), c.glue()-1, glue)) { c.set_glue(glue); } } @@ -2142,6 +2142,26 @@ namespace sat { return r; } + bool solver::num_diff_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue) { + m_diff_levels.reserve(scope_lvl() + 1, false); + glue = 0; + unsigned i = 0; + for (; i < num && glue < max_glue; i++) { + SASSERT(value(lits[i]) != l_undef); + unsigned lit_lvl = lvl(lits[i]); + if (m_diff_levels[lit_lvl] == false) { + m_diff_levels[lit_lvl] = true; + glue++; + } + } + num = i; + // reset m_diff_levels. + for (i = 0; i < num; i++) + m_diff_levels[lvl(lits[i])] = false; + return glue < max_glue; + } + + /** \brief Process an antecedent for lemma minimization. */ @@ -2278,11 +2298,14 @@ namespace sat { unsigned sz = m_lemma.size(); unsigned i = 1; // the first literal is the FUIP unsigned j = 1; + //bool drop = false; + //unsigned bound = sz/5+10; for (; i < sz; i++) { literal l = m_lemma[i]; if (implied_by_marked(l)) { TRACE("sat", tout << "drop: " << l << "\n";); m_unmark.push_back(l.var()); + //drop = true; } else { if (j != i) { @@ -2290,6 +2313,13 @@ namespace sat { } j++; } +#if 0 + if (!drop && i >= bound) { + // std::cout << "drop\n"; + j = sz; + break; + } +#endif } reset_unmark(0); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index d5affd2d4..0e8f17298 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -394,6 +394,7 @@ namespace sat { void updt_phase_counters(); svector m_diff_levels; unsigned num_diff_levels(unsigned num, literal const * lits); + bool num_diff_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue); // lemma minimization typedef approx_set_tpl level_approx_set; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index eec734dc7..9e8a31c5d 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -84,7 +84,6 @@ public: m_unknown("no reason given") { m_params.set_bool("elim_vars", false); sat_params p1(m_params); - m_params.set_bool("cardinality_solver", p1.cardinality_solver()); m_solver.updt_params(m_params); init_preprocess(); } @@ -219,7 +218,6 @@ public: virtual void updt_params(params_ref const & p) { m_params.append(p); sat_params p1(p); - m_params.set_bool("cardinality_solver", p1.cardinality_solver()); m_params.set_bool("elim_vars", false); std::cout << m_params << "\n"; m_solver.updt_params(m_params); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index bfd533e8a..106cba954 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -70,8 +70,8 @@ public: return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } + virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); m_rewriter.updt_params(p); } + virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); m_rewriter.collect_param_descrs(r); } virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } virtual void collect_statistics(statistics & st) const { From eaf845c2f48f6c2bed0264ea75bd4f9e53973bae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Feb 2017 18:04:24 -0800 Subject: [PATCH 0035/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 11 ++++++++--- src/sat/sat_solver.cpp | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 546a6905d..cd7271811 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -120,9 +120,8 @@ namespace sat { return; } ptr_vector*& cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; - if (cards) { + if (!is_tag_empty(cards)) { if (remove(*cards, c)) { - std::cout << "Empty: " << cards->empty() << "\n"; cards = set_tag_empty(cards); } } @@ -291,6 +290,7 @@ namespace sat { unsigned num_steps = 0; DEBUG_CODE(active2pb(m_A);); + std::cout << m_num_marks << "\n"; do { if (offset == 0) { @@ -298,6 +298,7 @@ namespace sat { } // TBD: need proper check for overflow. if (offset > (1 << 12)) { + std::cout << "Offset: " << offset << "\n"; goto bail_out; } @@ -386,6 +387,9 @@ namespace sat { consequent = lits[idx]; v = consequent.var(); if (s().is_marked(v)) break; + if (idx == 0) { + goto bail_out; + } SASSERT(idx > 0); --idx; } @@ -481,7 +485,8 @@ namespace sat { return true; bail_out: - while (m_num_marks > 0 && idx > 0) { + std::cout << "bail num marks: " << m_num_marks << " idx: " << idx << "\n"; + while (m_num_marks > 0 && idx >= 0) { bool_var v = lits[idx].var(); if (s().is_marked(v)) { s().reset_mark(v); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 73829c6b8..f5f9de6fc 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -371,6 +371,7 @@ namespace sat { if (m_watches.size() <= (~c[1]).index()) std::cout << c << "\n"; if (m_watches[(~c[0]).index()].size() >= 20000) { std::cout << m_par_id << ": " << c << "\n"; + enable_trace("sat"); } m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); From 6b4aec9b74fb10d53a68fa15e2f7091b1d9a4f07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Feb 2017 20:59:28 -0800 Subject: [PATCH 0036/1283] fixing bugs in dealing with non-0 based cardinality constraints Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 53 +++++++++++++++++++++++++------------- src/sat/card_extension.h | 6 +++-- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index cd7271811..17dcd7f5f 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -53,6 +53,7 @@ namespace sat { if (c.lit().sign() == is_true) { c.negate(); } + TRACE("sat", display(tout << "init watch: ", c, true);); SASSERT(value(c.lit()) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); if (bound == sz) { @@ -131,7 +132,7 @@ namespace sat { return TAG(ptr_vector*, c, 1); } - bool card_extension::is_tag_empty(ptr_vector* c) { + bool card_extension::is_tag_empty(ptr_vector const* c) { return !c || GET_TAG(c) == 1; } @@ -255,9 +256,7 @@ namespace sat { } int card_extension::get_abs_coeff(bool_var v) const { - int coeff = get_coeff(v); - if (coeff < 0) coeff = -coeff; - return coeff; + return abs(get_coeff(v)); } void card_extension::reset_coeffs() { @@ -267,6 +266,13 @@ namespace sat { m_active_vars.reset(); } + void card_extension::reset_marked_literals() { + for (unsigned i = 0; i < m_marked_literals.size(); ++i) { + s().unmark_lit(m_marked_literals[i]); + } + m_marked_literals.reset(); + } + bool card_extension::resolve_conflict() { if (0 == m_num_propagations_since_pop) return false; @@ -290,7 +296,8 @@ namespace sat { unsigned num_steps = 0; DEBUG_CODE(active2pb(m_A);); - std::cout << m_num_marks << "\n"; + unsigned init_marks = m_num_marks; + do { if (offset == 0) { @@ -298,7 +305,6 @@ namespace sat { } // TBD: need proper check for overflow. if (offset > (1 << 12)) { - std::cout << "Offset: " << offset << "\n"; goto bail_out; } @@ -388,6 +394,7 @@ namespace sat { v = consequent.var(); if (s().is_marked(v)) break; if (idx == 0) { + std::cout << num_steps << " " << init_marks << "\n"; goto bail_out; } SASSERT(idx > 0); @@ -414,6 +421,7 @@ namespace sat { SASSERT(validate_lemma()); normalize_active_coeffs(); + reset_marked_literals(); if (consequent == null_literal) { return false; @@ -427,6 +435,7 @@ namespace sat { consequent = null_literal; ++idx; + unsigned num_atoms = m_lemma.size(); while (0 <= slack) { literal lit = lits[idx]; bool_var v = lit.var(); @@ -447,11 +456,6 @@ namespace sat { } else { m_lemma.push_back(~lit); - if (lvl(lit) == m_conflict_lvl) { - TRACE("sat", tout << "Bail out on no progress " << lit << "\n";); - IF_VERBOSE(3, verbose_stream() << "(sat.card bail resolve)\n";); - return false; - } } } } @@ -459,10 +463,18 @@ namespace sat { --idx; } + for (unsigned i = 1; i < std::min(m_lemma.size(), num_atoms + 1); ++i) { + if (lvl(m_lemma[i]) == m_conflict_lvl) { + TRACE("sat", tout << "Bail out on no progress " << lit << "\n";); + IF_VERBOSE(3, verbose_stream() << "(sat.card bail resolve)\n";); + return false; + } + } + SASSERT(slack < 0); if (consequent == null_literal) { - if (!m_lemma.empty()) return false; + if (!m_lemma.empty()) return false; } else { m_lemma[0] = consequent; @@ -478,6 +490,7 @@ namespace sat { s().m_lemma.reset(); s().m_lemma.append(m_lemma); for (unsigned i = 1; i < m_lemma.size(); ++i) { + CTRACE("sat", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); s().mark(m_lemma[i].var()); } m_stats.m_num_conflicts++; @@ -485,6 +498,7 @@ namespace sat { return true; bail_out: + reset_marked_literals(); std::cout << "bail num marks: " << m_num_marks << " idx: " << idx << "\n"; while (m_num_marks > 0 && idx >= 0) { bool_var v = lits[idx].var(); @@ -498,18 +512,21 @@ namespace sat { } bool card_extension::process_card(card& c, int offset) { - SASSERT(c.k() <= c.size()); - SASSERT(value(c.lit()) == l_true); + literal lit = c.lit(); + SASSERT(c.k() <= c.size()); + SASSERT(value(lit) == l_true); for (unsigned i = c.k(); i < c.size(); ++i) { process_antecedent(c[i], offset); } for (unsigned i = 0; i < c.k(); ++i) { inc_coeff(c[i], offset); } - if (lvl(c.lit()) > 0) { - m_lemma.push_back(~c.lit()); + if (lvl(lit) > 0 && !s().is_marked_lit(lit)) { + m_lemma.push_back(~lit); + s().mark_lit(lit); + m_marked_literals.push_back(lit); } - return (lvl(c.lit()) <= m_conflict_lvl); + return (lvl(lit) <= m_conflict_lvl); } void card_extension::process_antecedent(literal l, int offset) { @@ -733,7 +750,7 @@ namespace sat { void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { watch const* w = m_var_infos[v].m_lit_watch[sign]; - if (w && !w->empty()) { + if (!is_tag_empty(w)) { watch const& wl = *w; out << literal(v, sign) << " |-> "; for (unsigned i = 0; i < wl.size(); ++i) { diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 4a01bc7cc..654665c22 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -76,8 +76,8 @@ namespace sat { } }; - ptr_vector* set_tag_empty(ptr_vector* c); - bool is_tag_empty(ptr_vector* c); + static ptr_vector* set_tag_empty(ptr_vector* c); + static bool is_tag_empty(ptr_vector const* c); static ptr_vector* set_tag_non_empty(ptr_vector* c); solver* m_solver; @@ -99,6 +99,7 @@ namespace sat { tracked_uint_set m_active_var_set; literal_vector m_lemma; literal_vector m_literals; + literal_vector m_marked_literals; unsigned m_num_propagations_since_pop; solver& s() const { return *m_solver; } @@ -110,6 +111,7 @@ namespace sat { void set_conflict(card& c, literal lit); void clear_watch(card& c); void reset_coeffs(); + void reset_marked_literals(); inline lbool value(literal lit) const { return m_solver->value(lit); } inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } From 8b4f3ac6f0244c463aa3881c3d78134e433adab8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Feb 2017 18:04:54 -0500 Subject: [PATCH 0037/1283] fix drat checker Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 2 +- src/sat/card_extension.cpp | 91 ++++++----------- src/sat/card_extension.h | 6 +- src/sat/sat_asymm_branch.cpp | 6 +- src/sat/sat_cleaner.cpp | 4 +- src/sat/sat_config.cpp | 6 +- src/sat/sat_config.h | 2 +- src/sat/sat_drat.cpp | 113 ++++++++++++++-------- src/sat/sat_drat.h | 2 + src/sat/sat_elim_eqs.cpp | 31 +++--- src/sat/{sat_par.cpp => sat_parallel.cpp} | 34 +++---- src/sat/{sat_par.h => sat_parallel.h} | 8 +- src/sat/sat_params.pyg | 2 +- src/sat/sat_simplifier.cpp | 23 ++++- src/sat/sat_solver.cpp | 29 +++--- src/sat/sat_solver.h | 8 +- 16 files changed, 201 insertions(+), 166 deletions(-) rename src/sat/{sat_par.cpp => sat_parallel.cpp} (86%) rename src/sat/{sat_par.h => sat_parallel.h} (96%) diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index 6ffbb8c71..00c988f5c 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -14,7 +14,7 @@ z3_add_component(sat sat_integrity_checker.cpp sat_model_converter.cpp sat_mus.cpp - sat_par.cpp + sat_parallel.cpp sat_probing.cpp sat_scc.cpp sat_simplifier.cpp diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 17dcd7f5f..0e03708c9 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -266,12 +266,6 @@ namespace sat { m_active_vars.reset(); } - void card_extension::reset_marked_literals() { - for (unsigned i = 0; i < m_marked_literals.size(); ++i) { - s().unmark_lit(m_marked_literals[i]); - } - m_marked_literals.reset(); - } bool card_extension::resolve_conflict() { if (0 == m_num_propagations_since_pop) @@ -280,7 +274,7 @@ namespace sat { m_num_marks = 0; m_bound = 0; m_lemma.reset(); - m_lemma.push_back(null_literal); + // m_lemma.push_back(null_literal); literal consequent = s().m_not_l; justification js = s().m_conflict; m_conflict_lvl = s().get_max_lvl(consequent, js); @@ -292,8 +286,6 @@ namespace sat { unsigned idx = lits.size()-1; int offset = 1; - unsigned num_card = 0; - unsigned num_steps = 0; DEBUG_CODE(active2pb(m_A);); unsigned init_marks = m_num_marks; @@ -305,11 +297,13 @@ namespace sat { } // TBD: need proper check for overflow. if (offset > (1 << 12)) { + IF_VERBOSE(2, verbose_stream() << "offset: " << offset << "\n"; + active2pb(m_A); + display(verbose_stream(), m_A); + ); goto bail_out; } - ++num_steps; - // TRACE("sat", display(tout, m_A);); TRACE("sat", tout << "process consequent: " << consequent << ":\n"; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); @@ -320,9 +314,7 @@ namespace sat { switch(js.get_kind()) { case justification::NONE: SASSERT (consequent != null_literal); - m_lemma.push_back(~consequent); m_bound += offset; - inc_coeff(consequent, offset); break; case justification::BINARY: m_bound += offset; @@ -358,14 +350,10 @@ namespace sat { break; } case justification::EXT_JUSTIFICATION: { - ++num_card; unsigned index = js.get_ext_justification_idx(); card& c = *m_constraints[index]; m_bound += offset * c.k(); - if (!process_card(c, offset)) { - TRACE("sat", tout << "failed to process card\n";); - goto bail_out; - } + process_card(c, offset); break; } default: @@ -394,7 +382,7 @@ namespace sat { v = consequent.var(); if (s().is_marked(v)) break; if (idx == 0) { - std::cout << num_steps << " " << init_marks << "\n"; + IF_VERBOSE(2, verbose_stream() << "did not find marked literal\n";); goto bail_out; } SASSERT(idx > 0); @@ -421,65 +409,45 @@ namespace sat { SASSERT(validate_lemma()); normalize_active_coeffs(); - reset_marked_literals(); - if (consequent == null_literal) { - return false; - } int slack = -m_bound; for (unsigned i = 0; i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; slack += get_abs_coeff(v); } - - consequent = null_literal; ++idx; - - unsigned num_atoms = m_lemma.size(); while (0 <= slack) { literal lit = lits[idx]; bool_var v = lit.var(); if (m_active_var_set.contains(v)) { int coeff = get_coeff(v); - bool append = false; if (coeff < 0 && !lit.sign()) { slack += coeff; - append = true; + m_lemma.push_back(~lit); } else if (coeff > 0 && lit.sign()) { slack -= coeff; - append = true; - } - if (append) { - if (consequent == null_literal) { - consequent = ~lit; - } - else { - m_lemma.push_back(~lit); - } + m_lemma.push_back(~lit); } } + if (idx == 0 && slack >= 0) { + IF_VERBOSE(2, verbose_stream() << "(sat.card non-asserting)\n";); + goto bail_out; + } SASSERT(idx > 0 || slack < 0); --idx; } - for (unsigned i = 1; i < std::min(m_lemma.size(), num_atoms + 1); ++i) { - if (lvl(m_lemma[i]) == m_conflict_lvl) { - TRACE("sat", tout << "Bail out on no progress " << lit << "\n";); - IF_VERBOSE(3, verbose_stream() << "(sat.card bail resolve)\n";); - return false; - } + if (m_lemma.size() >= 2 && lvl(m_lemma[1]) == m_conflict_lvl) { + // TRACE("sat", tout << "Bail out on no progress " << lit << "\n";); + IF_VERBOSE(2, verbose_stream() << "(sat.card bail non-asserting resolvent)\n";); + goto bail_out; } SASSERT(slack < 0); - if (consequent == null_literal) { - if (!m_lemma.empty()) return false; - } - else { - m_lemma[0] = consequent; - SASSERT(validate_conflict(m_lemma, m_A)); - } + SASSERT(validate_conflict(m_lemma, m_A)); + TRACE("sat", tout << m_lemma << "\n";); if (s().m_config.m_drat) { @@ -498,8 +466,6 @@ namespace sat { return true; bail_out: - reset_marked_literals(); - std::cout << "bail num marks: " << m_num_marks << " idx: " << idx << "\n"; while (m_num_marks > 0 && idx >= 0) { bool_var v = lits[idx].var(); if (s().is_marked(v)) { @@ -511,22 +477,18 @@ namespace sat { return false; } - bool card_extension::process_card(card& c, int offset) { + void card_extension::process_card(card& c, int offset) { literal lit = c.lit(); SASSERT(c.k() <= c.size()); SASSERT(value(lit) == l_true); + SASSERT(0 < offset); for (unsigned i = c.k(); i < c.size(); ++i) { process_antecedent(c[i], offset); } for (unsigned i = 0; i < c.k(); ++i) { inc_coeff(c[i], offset); } - if (lvl(lit) > 0 && !s().is_marked_lit(lit)) { - m_lemma.push_back(~lit); - s().mark_lit(lit); - m_marked_literals.push_back(lit); - } - return (lvl(lit) <= m_conflict_lvl); + process_antecedent(~lit, c.k() * offset); } void card_extension::process_antecedent(literal l, int offset) { @@ -900,6 +862,7 @@ namespace sat { for (unsigned i = 0; i < c.size(); ++i) { p.push(c[i], offset); } + p.push(~c.lit(), offset*c.k()); break; } default: @@ -977,7 +940,10 @@ namespace sat { bool card_extension::validate_conflict(literal_vector const& lits, ineq& p) { for (unsigned i = 0; i < lits.size(); ++i) { - if (value(lits[i]) != l_false) return false; + if (value(lits[i]) != l_false) { + TRACE("sat", tout << "literal " << lits[i] << " is not false\n";); + return false; + } } unsigned value = 0; for (unsigned i = 0; i < p.m_lits.size(); ++i) { @@ -986,6 +952,9 @@ namespace sat { value += coeff; } } + CTRACE("sat", value >= p.m_k, tout << "slack: " << value << " bound " << p.m_k << "\n"; + display(tout, p); + tout << lits << "\n";); return value < p.m_k; } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 654665c22..3b65afb6b 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -98,8 +98,7 @@ namespace sat { int m_bound; tracked_uint_set m_active_var_set; literal_vector m_lemma; - literal_vector m_literals; - literal_vector m_marked_literals; +// literal_vector m_literals; unsigned m_num_propagations_since_pop; solver& s() const { return *m_solver; } @@ -125,10 +124,9 @@ namespace sat { int get_coeff(bool_var v) const; int get_abs_coeff(bool_var v) const; - literal_vector& get_literals() { m_literals.reset(); return m_literals; } literal get_asserting_literal(literal conseq); void process_antecedent(literal l, int offset); - bool process_card(card& c, int offset); + void process_card(card& c, int offset); void cut(); // validation utilities diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 8a761ea3a..efadc5266 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -169,7 +169,9 @@ namespace sat { literal l = c[i]; switch (s.value(l)) { case l_undef: - c[j] = l; + if (i != j) { + std::swap(c[i], c[j]); + } j++; break; case l_false: @@ -201,6 +203,8 @@ namespace sat { default: c.shrink(new_sz); s.attach_clause(c); + if (s.m_config.m_drat) s.m_drat.add(c, true); + // if (s.m_config.m_drat) s.m_drat.del(c0); // TBD SASSERT(s.m_qhead == s.m_trail.size()); return true; } diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 10751c622..94da1dd4f 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -99,7 +99,9 @@ namespace sat { m_elim_literals++; break; case l_undef: - c[j] = c[i]; + if (i != j) { + std::swap(c[j], c[i]); + } j++; break; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 77a93c1e9..cd756d79b 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -35,7 +35,7 @@ namespace sat { m_glue("glue"), m_glue_psm("glue_psm"), m_psm_glue("psm_glue") { - m_num_parallel = 1; + m_num_threads = 1; updt_params(p); } @@ -78,7 +78,7 @@ namespace sat { m_burst_search = p.burst_search(); m_max_conflicts = p.max_conflicts(); - m_num_parallel = p.parallel_threads(); + m_num_threads = p.threads(); // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); @@ -113,7 +113,7 @@ namespace sat { m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); - m_drat = p.drat(); + m_drat = p.drat() && p.threads() == 1; m_drat_check = p.drat_check(); m_drat_file = p.drat_file(); m_dyn_sub_res = p.dyn_sub_res(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 03616b6d8..6f29f485e 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -57,7 +57,7 @@ namespace sat { unsigned m_random_seed; unsigned m_burst_search; unsigned m_max_conflicts; - unsigned m_num_parallel; + unsigned m_num_threads; unsigned m_simplify_mult1; double m_simplify_mult2; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 7f6368972..ba4173eed 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -79,7 +79,6 @@ namespace sat { out << st << " "; literal last = null_literal; for (unsigned i = 0; i < n; ++i) { - declare(c[i]); if (c[i] != last) { out << c[i] << " "; last = c[i]; @@ -89,7 +88,7 @@ namespace sat { } void drat::append(literal l, status st) { - trace(std::cout, 1, &l, st); + IF_VERBOSE(10, trace(verbose_stream(), 1, &l, st);); if (st == status::learned) { verify(1, &l); } @@ -101,7 +100,7 @@ namespace sat { void drat::append(literal l1, literal l2, status st) { literal lits[2] = { l1, l2 }; - trace(std::cout, 2, lits, st); + IF_VERBOSE(10, trace(verbose_stream(), 2, lits, st);); if (st == status::deleted) { // noop // don't record binary as deleted. @@ -132,7 +131,7 @@ namespace sat { void drat::append(clause& c, status st) { unsigned n = c.size(); - trace(std::cout, n, c.begin(), st); + IF_VERBOSE(10, trace(verbose_stream(), n, c.begin(), st);); if (st == status::learned) { verify(n, c.begin()); @@ -205,8 +204,12 @@ namespace sat { assign_propagate(~c[i]); } if (!m_inconsistent) { - TRACE("sat", display(tout);); + DEBUG_CODE(validate_propagation();); } + for (unsigned i = 0; i < m_units.size(); ++i) { + SASSERT(m_assignment[m_units[i].var()] != l_undef); + } + for (unsigned i = num_units; i < m_units.size(); ++i) { m_assignment[m_units[i].var()] = l_undef; } @@ -218,9 +221,37 @@ namespace sat { bool drat::is_drat(unsigned n, literal const* c) { if (m_inconsistent || n == 0) return true; - literal l = c[0]; - literal_vector lits(n - 1, c + 1); - for (unsigned i = 0; m_proof.size(); ++i) { + for (unsigned i = 0; i < n; ++i) { + if (is_drat(n, c, i)) return true; + } + return false; + } + + void drat::validate_propagation() const { + for (unsigned i = 0; i < m_proof.size(); ++i) { + status st = m_status[i]; + if (m_proof[i] && st != status::deleted) { + clause& c = *m_proof[i]; + unsigned num_undef = 0, num_true = 0; + for (unsigned j = 0; j < c.size(); ++j) { + switch (value(c[j])) { + case l_false: break; + case l_true: num_true++; break; + case l_undef: num_undef++; break; + } + } + CTRACE("sat", num_true == 0 && num_undef == 1, display(tout);); + SASSERT(num_true != 0 || num_undef != 1); + } + } + } + + bool drat::is_drat(unsigned n, literal const* c, unsigned pos) { + SASSERT(pos < n); + literal l = c[pos]; + literal_vector lits(n, c); + SASSERT(lits.size() == n); + for (unsigned i = 0; i < m_proof.size(); ++i) { status st = m_status[i]; if (m_proof[i] && (st == status::asserted || st == status::external)) { clause& c = *m_proof[i]; @@ -230,21 +261,22 @@ namespace sat { lits.append(j, c.begin()); lits.append(c.size() - j - 1, c.begin() + j + 1); if (!is_drup(lits.size(), lits.c_ptr())) return false; - lits.resize(n - 1); + lits.resize(n); } } } return true; + } void drat::verify(unsigned n, literal const* c) { - if (is_drup(n, c) || is_drat(n, c)) { - std::cout << "Verified\n"; - } - else { + if (!is_drup(n, c) && !is_drat(n, c)) { std::cout << "Verification failed\n"; display(std::cout); - TRACE("sat", display(tout); s.display(tout);); + TRACE("sat", + tout << literal_vector(n, c) << "\n"; + display(tout); + s.display(tout);); UNREACHABLE(); exit(0); } @@ -252,12 +284,10 @@ namespace sat { void drat::display(std::ostream& out) const { out << "units: " << m_units << "\n"; -#if 1 for (unsigned i = 0; i < m_assignment.size(); ++i) { lbool v = value(literal(i, false)); if (v != l_undef) out << i << ": " << v << "\n"; } -#endif for (unsigned i = 0; i < m_proof.size(); ++i) { clause* c = m_proof[i]; if (m_status[i] != status::deleted && c) { @@ -276,10 +306,9 @@ namespace sat { if (num_true == 0 && num_undef == 1) { out << "Unit "; } - out << i << ": " << *c << "\n"; + out << m_status[i] << " " << i << ": " << *c << "\n"; } } -#if 1 for (unsigned i = 0; i < m_assignment.size(); ++i) { watch const& w1 = m_watches[2*i]; watch const& w2 = m_watches[2*i + 1]; @@ -294,25 +323,27 @@ namespace sat { out << "\n"; } } -#endif } lbool drat::value(literal l) const { - lbool v = m_assignment[l.var()]; - return v == l_undef || !l.sign() ? v : ~v; + lbool val = m_assignment.get(l.var(), l_undef); + return val == l_undef || !l.sign() ? val : ~val; } void drat::assign(literal l) { lbool new_value = l.sign() ? l_false : l_true; lbool old_value = value(l); - if (new_value != old_value) { - if (old_value == l_undef) { - m_assignment[l.var()] = new_value; - m_units.push_back(l); - } - else { - m_inconsistent = true; - } +// TRACE("sat", tout << "assign " << l << " := " << new_value << " from " << old_value << "\n";); + switch (old_value) { + case l_false: + m_inconsistent = true; + break; + case l_true: + break; + case l_undef: + m_assignment.setx(l.var(), new_value, l_undef); + m_units.push_back(l); + break; } } @@ -334,14 +365,11 @@ namespace sat { watched_clause& wc = m_watched_clauses[idx]; clause& c = *wc.m_clause; - TRACE("sat", tout << "Propagate " << l << " " << c << " watch: " << wc.m_l1 << " " << wc.m_l2 << "\n";); + //TRACE("sat", tout << "Propagate " << l << " " << c << " watch: " << wc.m_l1 << " " << wc.m_l2 << "\n";); if (wc.m_l1 == ~l) { std::swap(wc.m_l1, wc.m_l2); } - if (wc.m_l2 != ~l) { - std::cout << wc.m_l1 << " " << wc.m_l2 << " ~l: " << ~l << "\n"; - std::cout << *wc.m_clause << "\n"; - } + SASSERT(wc.m_l2 == ~l); if (value(wc.m_l1) == l_true) { *it2 = *it; @@ -358,7 +386,6 @@ namespace sat { } } if (done) { - it2++; continue; } else if (value(wc.m_l1) == l_false) { @@ -385,22 +412,26 @@ namespace sat { void drat::add() { if (m_out) (*m_out) << "0\n"; if (s.m_config.m_drat_check) { - if (m_inconsistent) std::cout << "Verified\n"; - else std::cout << "Failed to verify\n"; + SASSERT(m_inconsistent); } } void drat::add(literal l, bool learned) { + declare(l); status st = get_status(learned); if (m_out) dump(1, &l, st); if (s.m_config.m_drat_check) append(l, st); } void drat::add(literal l1, literal l2, bool learned) { + declare(l1); + declare(l2); literal ls[2] = {l1, l2}; status st = get_status(learned); if (m_out) dump(2, ls, st); if (s.m_config.m_drat_check) append(l1, l2, st); } void drat::add(clause& c, bool learned) { + TRACE("sat", tout << "add: " << c << "\n";); + for (unsigned i = 0; i < c.size(); ++i) declare(c[i]); status st = get_status(learned); if (m_out) dump(c.size(), c.begin(), st); if (s.m_config.m_drat_check) append(c, get_status(learned)); @@ -429,9 +460,11 @@ namespace sat { append(l1, l2, status::deleted); } void drat::del(clause& c) { + TRACE("sat", tout << "del: " << c << "\n";); if (m_out) dump(c.size(), c.begin(), status::deleted); - if (s.m_config.m_drat_check) - append(c, status::deleted); - else s.m_cls_allocator.del_clause(&c); + if (s.m_config.m_drat_check) { + clause* c1 = s.m_cls_allocator.mk_clause(c.size(), c.begin(), c.is_learned()); + append(*c1, status::deleted); + } } } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 8edaa5001..e9663628b 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -68,9 +68,11 @@ namespace sat { void verify(unsigned n, literal const* c); bool is_drup(unsigned n, literal const* c); bool is_drat(unsigned n, literal const* c); + bool is_drat(unsigned n, literal const* c, unsigned pos); lbool value(literal l) const; void trace(std::ostream& out, unsigned n, literal const* c, status st); void display(std::ostream& out) const; + void validate_propagation() const; public: drat(solver& s); diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 6a7ca6280..8cde147cc 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -117,7 +117,9 @@ namespace sat { break; // clause was satisfied if (val == l_false) continue; // skip - c[j] = l; + if (i != j) { + std::swap(c[i], c[j]); + } j++; } if (i < sz) { @@ -136,16 +138,7 @@ namespace sat { return; } TRACE("elim_eqs", tout << "after removing duplicates: " << c << " j: " << j << "\n";); - if (j < sz) - c.shrink(j); - else - c.update_approx(); - SASSERT(c.size() == j); - DEBUG_CODE({ - for (unsigned i = 0; i < c.size(); i++) { - SASSERT(c[i] == norm(roots, c[i])); - } - }); + SASSERT(j >= 1); switch (j) { case 1: @@ -160,8 +153,22 @@ namespace sat { SASSERT(*it == &c); *it2 = *it; it2++; - if (!c.frozen()) + if (j < sz) { + if (m_solver.m_config.m_drat) m_solver.m_drat.del(c); + c.shrink(j); + if (m_solver.m_config.m_drat) m_solver.m_drat.add(c, true); + } + else + c.update_approx(); + + DEBUG_CODE({ + for (unsigned i = 0; i < sz; i++) { + SASSERT(c[i] == norm(roots, c[i])); + } }); + + if (!c.frozen()) { m_solver.attach_clause(c); + } break; } } diff --git a/src/sat/sat_par.cpp b/src/sat/sat_parallel.cpp similarity index 86% rename from src/sat/sat_par.cpp rename to src/sat/sat_parallel.cpp index 8d2c20d56..da0714907 100644 --- a/src/sat/sat_par.cpp +++ b/src/sat/sat_parallel.cpp @@ -3,9 +3,9 @@ Copyright (c) 2017 Microsoft Corporation Module Name: - sat_par.cpp + sat_parallel.cpp -Abstract: + Abstract: Utilities for parallel SAT solving. @@ -16,14 +16,14 @@ Author: Revision History: --*/ -#include "sat_par.h" +#include "sat_parallel.h" #include "sat_clause.h" #include "sat_solver.h" namespace sat { - void par::vector_pool::next(unsigned& index) { + void parallel::vector_pool::next(unsigned& index) { SASSERT(index < m_size); unsigned n = index + 2 + get_length(index); if (n >= m_size) { @@ -34,7 +34,7 @@ namespace sat { } } - void par::vector_pool::reserve(unsigned num_threads, unsigned sz) { + void parallel::vector_pool::reserve(unsigned num_threads, unsigned sz) { m_vectors.reset(); m_vectors.resize(sz, 0); m_heads.reset(); @@ -43,7 +43,7 @@ namespace sat { m_size = sz; } - void par::vector_pool::begin_add_vector(unsigned owner, unsigned n) { + void parallel::vector_pool::begin_add_vector(unsigned owner, unsigned n) { unsigned capacity = n + 2; m_vectors.reserve(m_size + capacity, 0); IF_VERBOSE(3, verbose_stream() << owner << ": begin-add " << n << " tail: " << m_tail << " size: " << m_size << "\n";); @@ -71,11 +71,11 @@ namespace sat { m_vectors[m_tail++] = n; } - void par::vector_pool::add_vector_elem(unsigned e) { + void parallel::vector_pool::add_vector_elem(unsigned e) { m_vectors[m_tail++] = e; } - bool par::vector_pool::get_vector(unsigned owner, unsigned& n, unsigned const*& ptr) { + bool parallel::vector_pool::get_vector(unsigned owner, unsigned& n, unsigned const*& ptr) { unsigned head = m_heads[owner]; unsigned iterations = 0; while (head != m_tail) { @@ -97,15 +97,15 @@ namespace sat { return false; } - par::par(solver& s): m_scoped_rlimit(s.rlimit()) {} + parallel::parallel(solver& s): m_scoped_rlimit(s.rlimit()) {} - par::~par() { + parallel::~parallel() { for (unsigned i = 0; i < m_solvers.size(); ++i) { dealloc(m_solvers[i]); } } - void par::init_solvers(solver& s, unsigned num_extra_solvers) { + void parallel::init_solvers(solver& s, unsigned num_extra_solvers) { unsigned num_threads = num_extra_solvers + 1; m_solvers.resize(num_extra_solvers, 0); symbol saved_phase = s.m_params.get_sym("phase", symbol("caching")); @@ -127,7 +127,7 @@ namespace sat { } - void par::exchange(solver& s, literal_vector const& in, unsigned& limit, literal_vector& out) { + void parallel::exchange(solver& s, literal_vector const& in, unsigned& limit, literal_vector& out) { if (s.m_par_syncing_clauses) return; flet _disable_sync_clause(s.m_par_syncing_clauses, true); #pragma omp critical (par_solver) @@ -147,7 +147,7 @@ namespace sat { } } - void par::share_clause(solver& s, literal l1, literal l2) { + void parallel::share_clause(solver& s, literal l1, literal l2) { if (s.m_par_syncing_clauses) return; flet _disable_sync_clause(s.m_par_syncing_clauses, true); #pragma omp critical (par_solver) @@ -159,7 +159,7 @@ namespace sat { } } - void par::share_clause(solver& s, clause const& c) { + void parallel::share_clause(solver& s, clause const& c) { if (!enable_add(c) || s.m_par_syncing_clauses) return; flet _disable_sync_clause(s.m_par_syncing_clauses, true); unsigned n = c.size(); @@ -174,7 +174,7 @@ namespace sat { } } - void par::get_clauses(solver& s) { + void parallel::get_clauses(solver& s) { if (s.m_par_syncing_clauses) return; flet _disable_sync_clause(s.m_par_syncing_clauses, true); #pragma omp critical (par_solver) @@ -183,7 +183,7 @@ namespace sat { } } - void par::_get_clauses(solver& s) { + void parallel::_get_clauses(solver& s) { unsigned n; unsigned const* ptr; unsigned owner = s.m_par_id; @@ -198,7 +198,7 @@ namespace sat { } } - bool par::enable_add(clause const& c) const { + bool parallel::enable_add(clause const& c) const { // plingeling, glucose heuristic: return (c.size() <= 40 && c.glue() <= 8) || c.glue() <= 2; } diff --git a/src/sat/sat_par.h b/src/sat/sat_parallel.h similarity index 96% rename from src/sat/sat_par.h rename to src/sat/sat_parallel.h index dd2e93f95..9d060aaaf 100644 --- a/src/sat/sat_par.h +++ b/src/sat/sat_parallel.h @@ -3,7 +3,7 @@ Copyright (c) 2017 Microsoft Corporation Module Name: - sat_par.h + sat_parallel.h Abstract: @@ -26,7 +26,7 @@ Revision History: namespace sat { - class par { + class parallel { // shared pool of learned clauses. class vector_pool { @@ -61,9 +61,9 @@ namespace sat { public: - par(solver& s); + parallel(solver& s); - ~par(); + ~parallel(); void init_solvers(solver& s, unsigned num_extra_solvers); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 98e7fabf1..4a013a7fd 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -22,7 +22,7 @@ def_module_params('sat', ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), - ('parallel_threads', UINT, 1, 'number of parallel threads to use'), + ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat', BOOL, False, 'produce DRAT proofs'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 8bfa4bb69..3c4d784cb 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -554,7 +554,9 @@ namespace sat { literal l = c[i]; switch (value(l)) { case l_undef: - c[j] = l; + if (i != j) { + std::swap(c[j], c[i]); + } j++; break; case l_false: @@ -567,12 +569,18 @@ namespace sat { break; case l_true: r = true; - c[j] = l; + if (i != j) { + std::swap(c[j], c[i]); + } j++; break; } } - c.shrink(j); + if (j < sz) { + if (s.m_config.m_drat) s.m_drat.del(c); + c.shrink(j); + if (s.m_config.m_drat) s.m_drat.add(c, true); + } return r; } @@ -588,7 +596,9 @@ namespace sat { literal l = c[i]; switch (value(l)) { case l_undef: - c[j] = l; + if (i != j) { + std::swap(c[j], c[i]); + } j++; break; case l_false: @@ -597,7 +607,7 @@ namespace sat { return true; } } - c.shrink(j); + c.shrink(j); return false; } @@ -642,6 +652,8 @@ namespace sat { m_num_elim_lits++; insert_elim_todo(l.var()); c.elim(l); + if (s.m_config.m_drat) s.m_drat.add(c, true); + // if (s.m_config.m_drat) s.m_drat.del(c0); // can delete previous version clause_use_list & occurs = m_use_list.get(l); occurs.erase_not_removed(c); m_sub_counter -= occurs.size()/2; @@ -1418,6 +1430,7 @@ namespace sat { else s.m_stats.m_mk_clause++; clause * new_c = s.m_cls_allocator.mk_clause(m_new_cls.size(), m_new_cls.c_ptr(), false); + if (s.m_config.m_drat) s.m_drat.add(*new_c, true); s.m_clauses.push_back(new_c); m_use_list.insert(*new_c); if (m_sub_counter > 0) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f5f9de6fc..78b10d9e1 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -212,9 +212,7 @@ namespace sat { if (m_config.m_drat && !m_drat.is_cleaned(c)) { m_drat.del(c); } - else if (!m_config.m_drat || !m_config.m_drat_check || m_drat.is_cleaned(c)) { - m_cls_allocator.del_clause(&c); - } + m_cls_allocator.del_clause(&c); m_stats.m_del_clause++; } @@ -769,7 +767,7 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); - if (m_config.m_num_parallel > 1 && !m_par) { + if (m_config.m_num_threads > 1 && !m_par) { return check_par(num_lits, lits); } flet _searching(m_searching, true); @@ -842,9 +840,9 @@ namespace sat { }; lbool solver::check_par(unsigned num_lits, literal const* lits) { - int num_threads = static_cast(m_config.m_num_parallel); + int num_threads = static_cast(m_config.m_num_threads); int num_extra_solvers = num_threads - 1; - sat::par par(*this); + sat::parallel par(*this); // par.reserve(num_threads, 1 << 16); par.reserve(num_threads, 1 << 9); par.init_solvers(*this, num_extra_solvers); @@ -956,7 +954,7 @@ namespace sat { } } - void solver::set_par(par* p, unsigned id) { + void solver::set_par(parallel* p, unsigned id) { m_par = p; m_par_num_vars = num_vars(); m_par_limit_in = 0; @@ -1662,7 +1660,9 @@ namespace sat { case l_false: break; case l_undef: - c[j] = c[i]; + if (i != j) { + std::swap(c[i], c[j]); + } j++; break; } @@ -1680,7 +1680,12 @@ namespace sat { mk_bin_clause(c[0], c[1], true); return false; default: - c.shrink(new_sz); + if (new_sz != sz) { + std::cout << "shrinking " << c << "\n"; + if (m_config.m_drat) m_drat.del(c); + c.shrink(new_sz); + if (m_config.m_drat) m_drat.add(c, true); + } attach_clause(c); return true; } @@ -1749,7 +1754,6 @@ namespace sat { if (m_ext && m_ext->resolve_conflict()) { learn_lemma_and_backjump(); - m_stats.m_conflict--; return true; } @@ -2815,7 +2819,10 @@ namespace sat { literal lit = m_trail[i]; if (lvl(lit) > level) { level = lvl(lit); - out << "level: " << level << " - "; + out << level << ": "; + } + else { + out << " "; } out << lit << " "; display_justification(out, m_justification[lit.var()]) << "\n"; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 0e8f17298..30d4ca4ad 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -34,7 +34,7 @@ Revision History: #include"sat_probing.h" #include"sat_mus.h" #include"sat_drat.h" -#include"sat_par.h" +#include"sat_parallel.h" #include"params.h" #include"statistics.h" #include"stopwatch.h" @@ -76,7 +76,7 @@ namespace sat { config m_config; stats m_stats; scoped_ptr m_ext; - par* m_par; + parallel* m_par; random_gen m_rand; clause_allocator m_cls_allocator; cleaner m_cleaner; @@ -153,7 +153,7 @@ namespace sat { friend class mus; friend class drat; friend class card_extension; - friend class par; + friend class parallel; friend struct mk_stat; public: solver(params_ref const & p, reslimit& l); @@ -260,7 +260,7 @@ namespace sat { m_num_checkpoints = 0; if (memory::get_allocation_size() > m_config.m_max_memory) throw solver_exception(Z3_MAX_MEMORY_MSG); } - void set_par(par* p, unsigned id); + void set_par(parallel* p, unsigned id); bool canceled() { return !m_rlimit.inc(); } config const& get_config() { return m_config; } extension* get_extension() const { return m_ext.get(); } From 8f7c804e8668e764301ca953cb68dde928e0ca3b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Feb 2017 11:57:27 -0500 Subject: [PATCH 0038/1283] fix non-linear model bug found Giles Reger and Martin Suda Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 1 + src/smt/theory_arith_core.h | 6 +++++- src/smt/theory_arith_nl.h | 12 +++++++++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 5a0f8db95..77882f186 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -946,6 +946,7 @@ namespace smt { // // ----------------------------------- typedef int_hashtable > row_set; + bool m_model_depends_on_computed_epsilon; unsigned m_nl_rounds; bool m_nl_gb_exhausted; unsigned m_nl_strategy_idx; // for fairness diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 9db5e8c72..513cf36a4 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1405,6 +1405,7 @@ namespace smt { template final_check_status theory_arith::final_check_core() { + m_model_depends_on_computed_epsilon = false; unsigned old_idx = m_final_check_idx; final_check_status result = FC_DONE; final_check_status ok; @@ -1669,6 +1670,7 @@ namespace smt { m_liberal_final_check(true), m_changed_assignment(false), m_assume_eq_head(0), + m_model_depends_on_computed_epsilon(false), m_nl_rounds(0), m_nl_gb_exhausted(false), m_nl_new_exprs(m), @@ -3220,7 +3222,9 @@ namespace smt { m_factory = alloc(arith_factory, get_manager()); m.register_factory(m_factory); compute_epsilon(); - refine_epsilon(); + if (!m_model_depends_on_computed_epsilon) { + refine_epsilon(); + } } template diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index dd91ffbfb..52a117cd5 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -638,6 +638,7 @@ namespace smt { if (!val.get_infinitesimal().is_zero() && !computed_epsilon) { compute_epsilon(); computed_epsilon = true; + m_model_depends_on_computed_epsilon = true; } return val.get_rational().to_rational() + m_epsilon.to_rational() * val.get_infinitesimal().to_rational(); } @@ -652,14 +653,18 @@ namespace smt { bool theory_arith::check_monomial_assignment(theory_var v, bool & computed_epsilon) { SASSERT(is_pure_monomial(var2expr(v))); expr * m = var2expr(v); - rational val(1); + rational val(1), v_val; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); theory_var curr = expr2var(arg); SASSERT(curr != null_theory_var); - val *= get_value(curr, computed_epsilon); + v_val = get_value(curr, computed_epsilon); + TRACE("non_linear", tout << mk_pp(arg, get_manager()) << " = " << v_val << "\n";); + val *= v_val; } - return get_value(v, computed_epsilon) == val; + v_val = get_value(v, computed_epsilon); + TRACE("non_linear", tout << "v" << v << " := " << v_val << " == " << val << "\n";); + return v_val == val; } @@ -2356,6 +2361,7 @@ namespace smt { */ template final_check_status theory_arith::process_non_linear() { + m_model_depends_on_computed_epsilon = false; if (m_nl_monomials.empty()) return FC_DONE; From 690689424dfcb98f6a6d991321ff3d0545d45177 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Feb 2017 15:35:13 -0500 Subject: [PATCH 0039/1283] fix parallel solving bugs Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 4 ++- src/sat/card_extension.cpp | 4 +-- src/sat/sat_parallel.cpp | 44 ++++++++++++--------------- src/sat/sat_parallel.h | 6 ++-- src/sat/sat_solver.cpp | 39 +++++++++--------------- src/sat/sat_solver/inc_sat_solver.cpp | 2 -- 6 files changed, 43 insertions(+), 56 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 7e9381e1d..f43c9cc16 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -327,6 +327,7 @@ public: m_found_feasible_optimum = true; } + virtual lbool operator()() { m_defs.reset(); switch(m_st) { @@ -731,7 +732,7 @@ public: m_assignment[i] = is_true(m_soft[i]); } - DEBUG_CODE(verify_assignment();); + // DEBUG_CODE(verify_assignment();); m_upper = upper; trace(); @@ -866,6 +867,7 @@ public: if (is_sat == l_false) { IF_VERBOSE(0, verbose_stream() << "assignment is infeasible\n";); } + IF_VERBOSE(1, verbose_stream() << "verified\n";); } }; diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 0e03708c9..f6bff3cd5 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -297,7 +297,7 @@ namespace sat { } // TBD: need proper check for overflow. if (offset > (1 << 12)) { - IF_VERBOSE(2, verbose_stream() << "offset: " << offset << "\n"; + IF_VERBOSE(12, verbose_stream() << "offset: " << offset << "\n"; active2pb(m_A); display(verbose_stream(), m_A); ); @@ -698,7 +698,7 @@ namespace sat { extension* card_extension::copy(solver* s) { card_extension* result = alloc(card_extension); result->set_solver(s); - for (unsigned i = 1; i < m_constraints.size(); ++i) { + for (unsigned i = 0; i < m_constraints.size(); ++i) { literal_vector lits; card& c = *m_constraints[i]; for (unsigned i = 0; i < c.size(); ++i) { diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index da0714907..493e9fe18 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -39,33 +39,22 @@ namespace sat { m_vectors.resize(sz, 0); m_heads.reset(); m_heads.resize(num_threads, 0); + m_at_end.reset(); + m_at_end.resize(num_threads, true); m_tail = 0; m_size = sz; } void parallel::vector_pool::begin_add_vector(unsigned owner, unsigned n) { + SASSERT(m_tail < m_size); unsigned capacity = n + 2; m_vectors.reserve(m_size + capacity, 0); IF_VERBOSE(3, verbose_stream() << owner << ": begin-add " << n << " tail: " << m_tail << " size: " << m_size << "\n";); - if (m_tail >= m_size) { - // move tail to the front. - for (unsigned i = 0; i < m_heads.size(); ++i) { - // the tail could potentially loop around full circle before one of the heads picks up anything. - // in this case the we miss the newly inserted record. - while (m_heads[i] < capacity) { - next(m_heads[i]); - } - IF_VERBOSE(3, verbose_stream() << owner << ": head: " << m_heads[i] << "\n";); - } - m_tail = 0; - } - else { - for (unsigned i = 0; i < m_heads.size(); ++i) { - while (m_tail < m_heads[i] && m_heads[i] < m_tail + capacity) { - next(m_heads[i]); - } - IF_VERBOSE(3, verbose_stream() << owner << ": head: " << m_heads[i] << "\n";); + for (unsigned i = 0; i < m_heads.size(); ++i) { + while (m_tail < m_heads[i] && m_heads[i] < m_tail + capacity) { + next(m_heads[i]); } + m_at_end[i] = false; } m_vectors[m_tail++] = owner; m_vectors[m_tail++] = n; @@ -75,18 +64,23 @@ namespace sat { m_vectors[m_tail++] = e; } + void parallel::vector_pool::end_add_vector() { + if (m_tail >= m_size) { + m_tail = 0; + } + } + + bool parallel::vector_pool::get_vector(unsigned owner, unsigned& n, unsigned const*& ptr) { unsigned head = m_heads[owner]; unsigned iterations = 0; - while (head != m_tail) { + while (head != m_tail || !m_at_end[owner]) { ++iterations; - if (head == 0 && m_tail >= m_size) { - break; - } - SASSERT(head < m_size); - IF_VERBOSE(static_cast(iterations > m_size ? 0 : 3), verbose_stream() << owner << ": head: " << head << " tail: " << m_tail << "\n";); + SASSERT(head < m_size && m_tail < m_size); bool is_self = owner == get_owner(head); next(m_heads[owner]); + IF_VERBOSE(static_cast(iterations > m_size ? 0 : 3), verbose_stream() << owner << ": [" << head << ":" << m_heads[owner] << "] tail: " << m_tail << "\n";); + m_at_end[owner] = (m_heads[owner] == m_tail); if (!is_self) { n = get_length(head); ptr = get_ptr(head); @@ -156,6 +150,7 @@ namespace sat { m_pool.begin_add_vector(s.m_par_id, 2); m_pool.add_vector_elem(l1.index()); m_pool.add_vector_elem(l2.index()); + m_pool.end_add_vector(); } } @@ -171,6 +166,7 @@ namespace sat { for (unsigned i = 0; i < n; ++i) { m_pool.add_vector_elem(c[i].index()); } + m_pool.end_add_vector(); } } diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index 9d060aaaf..56dc83aba 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#ifndef SAT_PAR_H_ -#define SAT_PAR_H_ +#ifndef SAT_PARALLEL_H_ +#define SAT_PARALLEL_H_ #include"sat_types.h" #include"hashtable.h" @@ -34,6 +34,7 @@ namespace sat { unsigned m_size; unsigned m_tail; unsigned_vector m_heads; + svector m_at_end; void next(unsigned& index); unsigned get_owner(unsigned index) const { return m_vectors[index]; } unsigned get_length(unsigned index) const { return m_vectors[index+1]; } @@ -42,6 +43,7 @@ namespace sat { vector_pool() {} void reserve(unsigned num_owners, unsigned sz); void begin_add_vector(unsigned owner, unsigned n); + void end_add_vector(); void add_vector_elem(unsigned e); bool get_vector(unsigned owner, unsigned& n, unsigned const*& ptr); }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 78b10d9e1..3b96fa098 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -100,11 +100,10 @@ namespace sat { if (src.get_extension()) { m_ext = src.get_extension()->copy(this); } - { - unsigned sz = src.init_trail_size(); - for (unsigned i = 0; i < sz; ++i) { - assign(src.m_trail[i], justification()); - } + + unsigned trail_sz = src.init_trail_size(); + for (unsigned i = 0; i < trail_sz; ++i) { + assign(src.m_trail[i], justification()); } // copy binary clauses @@ -365,12 +364,6 @@ namespace sat { } unsigned some_idx = c.size() >> 1; literal block_lit = c[some_idx]; - if (m_watches.size() <= (~c[0]).index()) std::cout << c << "\n"; - if (m_watches.size() <= (~c[1]).index()) std::cout << c << "\n"; - if (m_watches[(~c[0]).index()].size() >= 20000) { - std::cout << m_par_id << ": " << c << "\n"; - enable_trace("sat"); - } 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; @@ -843,7 +836,6 @@ namespace sat { int num_threads = static_cast(m_config.m_num_threads); int num_extra_solvers = num_threads - 1; sat::parallel par(*this); - // par.reserve(num_threads, 1 << 16); par.reserve(num_threads, 1 << 9); par.init_solvers(*this, num_extra_solvers); int finished_id = -1; @@ -872,13 +864,6 @@ namespace sat { } } if (first) { - if (r == l_true && i < num_extra_solvers) { - set_model(par.get_solver(i).get_model()); - } - else if (r == l_false && i < num_extra_solvers) { - m_core.reset(); - m_core.append(par.get_solver(i).get_core()); - } for (int j = 0; j < num_extra_solvers; ++j) { if (i != j) { par.cancel_solver(j); @@ -901,14 +886,21 @@ namespace sat { ex_kind = DEFAULT_EX; } } - set_par(0, 0); + if (finished_id != -1 && finished_id < num_extra_solvers) { m_stats = par.get_solver(finished_id).m_stats; } + if (result == l_true && finished_id != -1 && finished_id < num_extra_solvers) { + set_model(par.get_solver(finished_id).get_model()); + } + else if (result == l_false && finished_id != -1 && finished_id < num_extra_solvers) { + m_core.reset(); + m_core.append(par.get_solver(finished_id).get_core()); + } if (!canceled) { rlimit().reset_cancel(); } - + set_par(0, 0); if (finished_id == -1) { switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); @@ -925,8 +917,7 @@ namespace sat { void solver::exchange_par() { if (m_par && at_base_lvl()) m_par->get_clauses(*this); if (m_par && at_base_lvl()) { - // std::cout << scope_lvl() << " " << search_lvl() << "\n"; - SASSERT(scope_lvl() == search_lvl()); + // SASSERT(scope_lvl() == search_lvl()); // TBD: import also dependencies of assumptions. unsigned sz = init_trail_size(); unsigned num_in = 0, num_out = 0; @@ -1681,7 +1672,6 @@ namespace sat { return false; default: if (new_sz != sz) { - std::cout << "shrinking " << c << "\n"; if (m_config.m_drat) m_drat.del(c); c.shrink(new_sz); if (m_config.m_drat) m_drat.add(c, true); @@ -2320,7 +2310,6 @@ namespace sat { } #if 0 if (!drop && i >= bound) { - // std::cout << "drop\n"; j = sz; break; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 9e8a31c5d..02abebbb5 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -91,7 +91,6 @@ public: virtual ~inc_sat_solver() {} virtual solver* translate(ast_manager& dst_m, params_ref const& p) { - std::cout << "translate\n"; ast_translation tr(m, dst_m); if (m_num_scopes > 0) { throw default_exception("Cannot translate sat solver at non-base level"); @@ -219,7 +218,6 @@ public: m_params.append(p); sat_params p1(p); m_params.set_bool("elim_vars", false); - std::cout << m_params << "\n"; m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); } From 42deeb3498c3f4fe84ab3e2251ef3a61612c56f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Feb 2017 11:49:07 -0800 Subject: [PATCH 0040/1283] testing lookahead Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/test/CMakeLists.txt | 1 + src/sat/card_extension.cpp | 32 ++- src/sat/card_extension.h | 1 + src/sat/sat_config.cpp | 2 +- src/sat/sat_elim_eqs.cpp | 6 +- src/sat/sat_extension.h | 1 + src/sat/sat_lookahead.h | 394 ++++++++++++++++++++++++++ src/sat/sat_parallel.cpp | 11 +- src/sat/sat_params.pyg | 1 - src/sat/sat_simplifier.cpp | 4 + src/sat/sat_solver.cpp | 16 +- src/sat/sat_solver.h | 1 + src/test/main.cpp | 1 + 13 files changed, 456 insertions(+), 15 deletions(-) create mode 100644 src/sat/sat_lookahead.h diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index 6ea07e84c..7ea5f4589 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -92,6 +92,7 @@ add_executable(test-z3 rational.cpp rcf.cpp region.cpp + sat_lookahead.cpp sat_user_scope.cpp simple_parser.cpp simplex.cpp diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index f6bff3cd5..8fd0d89a8 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -709,6 +709,37 @@ namespace sat { return result; } + void card_extension::find_mutexes(literal_vector& lits, vector & mutexes) { + literal_set slits(lits); + bool change = false; + for (unsigned i = 0; i < m_constraints.size(); ++i) { + card& c = *m_constraints[i]; + if (c.size() == c.k() + 1) { + literal_vector mux; + for (unsigned j = 0; j < c.size(); ++j) { + literal lit = ~c[j]; + if (slits.contains(lit)) { + mux.push_back(lit); + } + } + if (mux.size() <= 1) { + continue; + } + + for (unsigned j = 0; j < mux.size(); ++j) { + slits.remove(mux[j]); + } + change = true; + mutexes.push_back(mux); + } + } + if (!change) return; + literal_set::iterator it = slits.begin(), end = slits.end(); + lits.reset(); + for (; it != end; ++it) { + lits.push_back(*it); + } + } void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { watch const* w = m_var_infos[v].m_lit_watch[sign]; @@ -957,7 +988,6 @@ namespace sat { tout << lits << "\n";); return value < p.m_k; } - }; diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 3b65afb6b..65a991ec2 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -163,6 +163,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); + virtual void find_mutexes(literal_vector& lits, vector & mutexes); }; }; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index cd756d79b..e5fac42ae 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -113,9 +113,9 @@ namespace sat { m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); - m_drat = p.drat() && p.threads() == 1; m_drat_check = p.drat_check(); m_drat_file = p.drat_file(); + m_drat = (m_drat_check || m_drat_file != symbol("")) && p.threads() == 1; m_dyn_sub_res = p.dyn_sub_res(); } diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 8cde147cc..36dc3a8d9 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -151,8 +151,6 @@ namespace sat { break; default: SASSERT(*it == &c); - *it2 = *it; - it2++; if (j < sz) { if (m_solver.m_config.m_drat) m_solver.m_drat.del(c); c.shrink(j); @@ -162,10 +160,12 @@ namespace sat { c.update_approx(); DEBUG_CODE({ - for (unsigned i = 0; i < sz; i++) { + for (unsigned i = 0; i < j; i++) { SASSERT(c[i] == norm(roots, c[i])); } }); + *it2 = *it; + it2++; if (!c.frozen()) { m_solver.attach_clause(c); } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 042f68e24..aae99c28f 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -47,6 +47,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; virtual void collect_statistics(statistics& st) const = 0; virtual extension* copy(solver* s) = 0; + virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; }; }; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h new file mode 100644 index 000000000..f70ceab38 --- /dev/null +++ b/src/sat/sat_lookahead.h @@ -0,0 +1,394 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_lookahead.h + +Abstract: + + Lookahead SAT solver in the style of March. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-2-11 + +Notes: + +--*/ +#ifndef _SAT_LOOKAHEAD_H_ +#define _SAT_LOOKAHEAD_H_ + +namespace sat { + class lookahead { + solver& s; + + struct config { + double m_dl_success; + }; + + config m_config; + double m_delta_trigger; + literal_vector m_trail; + literal_vector m_units; + unsigned_vector m_units_lim; + unsigned_vector m_learned_lim; + + + void init() { + m_delta_trigger = s.num_vars()/10; + m_config.m_dl_success = 0.8; + } + + void push(literal lit) { + m_learned_lim.push_back(s.m_learned.size()); + m_units_lim.push_back(m_units.size()); + m_trail.push_back(lit); + s.push(); + assign(lit); + } + + void pop() { + s.pop(1); + unsigned old_sz = m_learned_lim.back(); + m_learned_lim.pop_back(); + for (unsigned i = old_sz; i < s.m_learned.size(); ++i) { + clause* r = s.m_learned[i]; + s.dettach_clause(*r); + s.m_cls_allocator.del_clause(r); + } + s.m_learned.shrink(old_sz); + literal lits[2] = { m_trail.back(), null_literal }; + unsigned new_unit_sz = m_units_lim.back(); + for (unsigned i = m_units.size(); i > new_unit_sz; ) { + --i; + lits[1] = m_units[i]; + clause * r = s.m_cls_allocator.mk_clause(2, lits, true); + s.m_learned.push_back(r); + } + m_units.shrink(new_unit_sz); + m_units_lim.pop_back(); + m_trail.pop_back(); + } + + unsigned diff(unsigned value0) const { + unsigned value1 = get_state_value(); + SASSERT(value1 >= value0); + return value1 - value0; + } + + unsigned mix_diff(unsigned l, unsigned r) const { + return l + r + (1 << 10) * l * r; + } + + void get_resolvent_units(literal lit) { + if (inconsistent()) return; + for (unsigned i = s.m_trail.size(); i > 0; ) { + --i; + literal l = s.m_trail[i]; + if (l == lit) break; + SASSERT(s.lvl(l) == s.scope_lvl()); + watch_list& wlist = s.m_watches[(~l).index()]; + watch_list::iterator it = wlist.begin(), end = wlist.end(); + for (; it != end; ++it) { + switch (it->get_kind()) { + case watched::TERNARY: + if (s.value(it->get_literal1()) == l_false && + s.value(it->get_literal()) == l_false) { + m_units.push_back(l); + goto done_watch_list; + } + break; + case watched::CLAUSE: { + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + if (c.size() == 2) break; + SASSERT(c.size() > 2); + if (c[0] == l && s.value(c[1]) == l_false) { + DEBUG_CODE(for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false);); + m_units.push_back(l); + goto done_watch_list; + } + if (c[1] == l && s.value(c[0]) == l_false) { + DEBUG_CODE(for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false);); + m_units.push_back(l); + goto done_watch_list; + } + break; + } + default: + break; + } + } + done_watch_list: + continue; + } + } + + literal choose() { + literal l; + while (!choose1(l)) {}; + return l; + } + + unsigned get_state_value() const { + return s.m_learned.size(); + } + + bool choose1(literal& l) { + literal_vector P; + pre_select(P); + l = null_literal; + if (P.empty()) { + return true; + } + unsigned value0 = get_state_value(); + unsigned h = 0, count = 1; + literal_vector& units = m_units;; + for (unsigned i = 0; i < P.size(); ++i) { + literal lit = P[i]; + + push(lit); + if (do_double(value0)) double_look(); + if (inconsistent()) { + pop(); + assign(~lit); + if (do_double(value0)) double_look(); + if (inconsistent()) return true; + continue; + } + unsigned diff1 = diff(value0); + pop(); + + push(~lit); + if (do_double(value0)) double_look(); + bool unsat2 = inconsistent(); + unsigned diff2 = diff(value0); + pop(); + + if (unsat2) { + assign(lit); + continue; + } + + unsigned mixd = mix_diff(diff1, diff2); + + if (mixd > h || (mixd == h && s.m_rand(count) == 0)) { + h = mixd; + l = diff1 < diff2 ? lit : ~lit; + ++count; + } + } + return l != null_literal; + } + + void double_look() { + literal_vector P; + pre_select(P); + for (unsigned i = 0; !inconsistent() && i < P.size(); ++i) { + literal lit = P[i]; + + push(lit); + bool unsat = inconsistent(); + pop(); + if (unsat) { + assign(~lit); + continue; + } + + push(~lit); + unsat = inconsistent(); + pop(); + if (unsat) { + assign(lit); + } + + } + update_delta_trigger(); + } + + void assign(literal l) { + s.assign(l, justification()); + s.propagate(false); + get_resolvent_units(l); + } + + bool inconsistent() { return s.inconsistent(); } + + void pre_select(literal_vector& P) { + select_variables(P); + order_by_implication_trees(P); + } + + void order_by_implication_trees(literal_vector& P) { + literal_set roots; + literal_vector nodes, parent; + + // + // Extract binary clauses in watch list. + // Produce implication graph between literals in P. + // + + for (unsigned i = 0; i < P.size(); ++i) { + literal lit1 = P[i], lit2; + + // + // lit2 => lit1, where lit2 is a root. + // make lit1 a root instead of lit2 + // + + watch_list& wlist = s.m_watches[(~lit1).index()]; + watch_list::iterator it = wlist.begin(), end = wlist.end(); + lit2 = null_literal; + for (; it != end; ++it) { + switch (it->get_kind()) { + case watched::BINARY: + lit2 = it->get_literal(); + break; + case watched::CLAUSE: { + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + if (c.size() == 2) { + if (c[0] == ~lit1) { + lit2 = c[1]; + } + else { + SASSERT(c[1] == ~lit1); + lit2 = c[0]; + } + } + break; + } + default: + break; + } + + if (lit2 != null_literal && roots.contains(lit2)) { + // lit2 => lit1 + // if lit2 is a root, put it under lit2 + parent.setx(lit2.index(), lit1, null_literal); + roots.remove(lit2); + roots.insert(lit1); + goto found; + } + } + + // + // lit1 => lit2. + // if lit2 is a node, put lit1 above lit2 + // + + it = s.m_watches[lit1.index()].begin(); + end = s.m_watches[lit1.index()].end(); + for (; it != end; ++it) { + lit2 = null_literal; + switch (it->get_kind()) { + case watched::BINARY: + lit2 = it->get_literal(); + break; + case watched::CLAUSE: { + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + if (c.size() == 2) { + if (c[0] == lit1) { + lit2 = c[1]; + } + else { + SASSERT(c[1] == lit1); + lit2 = c[0]; + } + } + break; + } + default: + break; + } + + if (lit2 != null_literal && nodes.contains(lit2)) { + // lit1 => lit2 + parent.setx(lit1.index(), lit2, null_literal); + nodes.insert(lit1); + goto found; + } + } + std::cout << "no parents or children of literal " << lit1 << "\n"; + nodes.push_back(lit1); + roots.insert(lit1); + found: + ; + } + std::cout << "implication trees\n"; + for (unsigned i = 0; i < parent.size(); ++i) { + literal p = parent[i]; + if (p != null_literal) { + std::cout << to_literal(i) << " |-> " << p << "\n"; + } + } + + } + + void select_variables(literal_vector& P) { + for (unsigned i = 0; i < s.num_vars(); ++i) { + if (s.value(i) == l_undef) { + P.push_back(literal(i, false)); + } + } + } + + bool do_double(unsigned value0) { + unsigned value1 = get_state_value(); + return !inconsistent() && value1 - value0 > m_delta_trigger; + } + + void update_delta_trigger() { + if (inconsistent()) { + m_delta_trigger -= (1 - m_config.m_dl_success) / m_config.m_dl_success; + } + else { + m_delta_trigger += 1; + } + if (m_delta_trigger >= s.num_vars()) { + // reset it. + } + } + + lbool search() { + literal_vector trail; + +#define BACKTRACK \ + if (inconsistent()) { \ + if (trail.empty()) return l_false; \ + pop(); \ + assign(~trail.back()); \ + trail.pop_back(); \ + continue; \ + } \ + + while (true) { + s.checkpoint(); + BACKTRACK; + literal l = choose(); + TRACE("sat", tout << l << "\n";); + BACKTRACK; + if (l == null_literal) { + return l_true; + } + push(l); + trail.push_back(l); + } + } + + public: + lookahead(solver& s) : s(s) { + init(); + } + + lbool check() { + return search(); + } + + }; +} + +#endif + diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 493e9fe18..bc7ac408e 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -185,12 +185,17 @@ namespace sat { unsigned owner = s.m_par_id; while (m_pool.get_vector(owner, n, ptr)) { m_lits.reset(); - for (unsigned i = 0; i < n; ++i) { - m_lits.push_back(to_literal(ptr[i])); + bool usable_clause = true; + for (unsigned i = 0; usable_clause && i < n; ++i) { + literal lit(to_literal(ptr[i])); + m_lits.push_back(lit); + usable_clause = lit.var() <= s.m_par_num_vars && !s.was_eliminated(lit.var()); } IF_VERBOSE(3, verbose_stream() << s.m_par_id << ": retrieve " << m_lits << "\n";); SASSERT(n >= 2); - s.mk_clause_core(m_lits.size(), m_lits.c_ptr(), true); + if (usable_clause) { + s.mk_clause_core(m_lits.size(), m_lits.c_ptr(), true); + } } } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 4a013a7fd..3413d5e6a 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -24,7 +24,6 @@ def_module_params('sat', ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), - ('drat', BOOL, False, 'produce DRAT proofs'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), )) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3c4d784cb..03ff7ec98 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -35,6 +35,10 @@ namespace sat { void use_list::insert(clause & c) { unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) { + if (m_use_list.size() <= c[i].index()) { + std::cout << c[i] << "\n"; + std::cout << m_use_list.size() << "\n"; + } m_use_list[c[i].index()].insert(c); } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3b96fa098..476295f7a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -836,7 +836,7 @@ namespace sat { int num_threads = static_cast(m_config.m_num_threads); int num_extra_solvers = num_threads - 1; sat::parallel par(*this); - par.reserve(num_threads, 1 << 9); + par.reserve(num_threads, 1 << 12); par.init_solvers(*this, num_extra_solvers); int finished_id = -1; std::string ex_msg; @@ -3076,17 +3076,21 @@ namespace sat { } } vector _mutexes; + literal_vector _lits(lits); + if (m_ext) { + m_ext->find_mutexes(_lits, mutexes); + } unsigned_vector ps; - for (unsigned i = 0; i < lits.size(); ++i) { - ps.push_back(lits[i].index()); + for (unsigned i = 0; i < _lits.size(); ++i) { + ps.push_back(_lits[i].index()); } mc.cliques(ps, _mutexes); for (unsigned i = 0; i < _mutexes.size(); ++i) { - literal_vector lits; + literal_vector clique; for (unsigned j = 0; j < _mutexes[i].size(); ++j) { - lits.push_back(to_literal(_mutexes[i][j])); + clique.push_back(to_literal(_mutexes[i][j])); } - mutexes.push_back(lits); + mutexes.push_back(clique); } return l_true; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 30d4ca4ad..37e5f1bb6 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -154,6 +154,7 @@ namespace sat { friend class drat; friend class card_extension; friend class parallel; + friend class lookahead; friend struct mk_stat; public: solver(params_ref const & p, reslimit& l); diff --git a/src/test/main.cpp b/src/test/main.cpp index 9239d0119..18b83e90e 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -229,6 +229,7 @@ int main(int argc, char ** argv) { TST(model_evaluator); TST(get_consequences); TST(pb2bv); + TST_ARGV(sat_lookahead); //TST_ARGV(hs); } From c347018cb87ad93e7c2cfb60e3008640922ea75b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Feb 2017 11:49:30 -0800 Subject: [PATCH 0041/1283] testing lookahead Signed-off-by: Nikolaj Bjorner --- src/test/sat_lookahead.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/sat_lookahead.cpp diff --git a/src/test/sat_lookahead.cpp b/src/test/sat_lookahead.cpp new file mode 100644 index 000000000..d6993421b --- /dev/null +++ b/src/test/sat_lookahead.cpp @@ -0,0 +1,30 @@ +#include "sat_solver.h" +#include "sat_lookahead.h" +#include "dimacs.h" + +void tst_sat_lookahead(char ** argv, int argc, int& i) { + if (argc != i + 2) { + std::cout << "require dimacs file name\n"; + return; + } + enable_trace("sat"); + reslimit limit; + params_ref params; + sat::solver solver(params, limit); + sat::lookahead lh(solver); + char const* file_name = argv[i + 1]; + ++i; + + { + std::ifstream in(file_name); + if (in.bad() || in.fail()) { + std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; + exit(ERR_OPEN_FILE); + } + parse_dimacs(in, solver); + } + + IF_VERBOSE(20, solver.display_status(verbose_stream());); + + std::cout << lh.check() << "\n"; +} From 2bcb875559f65ff7894ad79801b9c3f612bbdc8b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 Feb 2017 08:36:16 -0800 Subject: [PATCH 0042/1283] add option to disable cardinality solver Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 10 ++++++++++ src/ast/pb_decl_plugin.h | 3 +++ src/sat/sat_params.pyg | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 6 +++--- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 09f020ca6..16ece2d40 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -44,6 +44,7 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p case OP_PB_LE: sym = m_pble_sym; break; case OP_PB_GE: sym = m_pbge_sym; break; case OP_PB_EQ: sym = m_pbeq_sym; break; + case OP_PB_ODD: sym = symbol("is-odd"); break; default: break; } switch(k) { @@ -55,6 +56,14 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p func_decl_info info(m_family_id, k, 1, parameters); return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info); } + case OP_PB_ODD:{ + if (num_parameters != 0) { + m.raise_exception("function expects no parameters"); + } + func_decl_info info(m_family_id, k, 0, parameters); + return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info); + } + case OP_PB_GE: case OP_PB_LE: case OP_PB_EQ: { @@ -97,6 +106,7 @@ void pb_decl_plugin::get_op_names(svector & op_names, symbol const op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE)); op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE)); op_names.push_back(builtin_name(m_pbeq_sym.bare_str(), OP_PB_EQ)); + op_names.push_back(builtin_name("is-odd", OP_PB_ODD)); } } diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 0750dcac7..fdd64561b 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -35,6 +35,7 @@ enum pb_op_kind { OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k) OP_PB_GE, // pseudo-Boolean >= OP_PB_EQ, // equality + OP_PB_ODD, // parity of arguments is odd OP_PB_AUX_BOOL, // auxiliary internal Boolean variable. LAST_PB_OP }; @@ -95,12 +96,14 @@ public: app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); app * mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); app * mk_lt(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); + app * mk_odd(unsigned num_args, expr * const * args); bool is_at_most_k(func_decl *a) const; bool is_at_most_k(expr *a) const { return is_app(a) && is_at_most_k(to_app(a)->get_decl()); } bool is_at_most_k(expr *a, rational& k) const; bool is_at_least_k(func_decl *a) const; bool is_at_least_k(expr *a) const { return is_app(a) && is_at_least_k(to_app(a)->get_decl()); } bool is_at_least_k(expr *a, rational& k) const; + bool is_odd(expr* a) const; rational get_k(func_decl *a) const; rational get_k(expr *a) const { return get_k(to_app(a)->get_decl()); } bool is_le(func_decl *a) const; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 3413d5e6a..e3ca12b73 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -26,4 +26,5 @@ def_module_params('sat', ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), + ('cardinality.solver', BOOL, True, 'use cardinality solver'), )) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 02abebbb5..d2ae541a8 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -82,9 +82,7 @@ public: m_num_scopes(0), m_dep_core(m), m_unknown("no reason given") { - m_params.set_bool("elim_vars", false); - sat_params p1(m_params); - m_solver.updt_params(m_params); + updt_params(p); init_preprocess(); } @@ -218,8 +216,10 @@ public: m_params.append(p); sat_params p1(p); m_params.set_bool("elim_vars", false); + m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); + } virtual void collect_statistics(statistics & st) const { if (m_preprocess) m_preprocess->collect_statistics(st); From 7e391a8a5780fd5dbcb304dced1ee954b743c0bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 Feb 2017 08:38:38 -0800 Subject: [PATCH 0043/1283] add option to disable cardinality solver Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 12 +----------- src/ast/pb_decl_plugin.h | 3 --- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 16ece2d40..bfe39e3ae 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -44,7 +44,6 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p case OP_PB_LE: sym = m_pble_sym; break; case OP_PB_GE: sym = m_pbge_sym; break; case OP_PB_EQ: sym = m_pbeq_sym; break; - case OP_PB_ODD: sym = symbol("is-odd"); break; default: break; } switch(k) { @@ -55,15 +54,7 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p } func_decl_info info(m_family_id, k, 1, parameters); return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info); - } - case OP_PB_ODD:{ - if (num_parameters != 0) { - m.raise_exception("function expects no parameters"); - } - func_decl_info info(m_family_id, k, 0, parameters); - return m.mk_func_decl(sym, arity, domain, m.mk_bool_sort(), info); - } - + } case OP_PB_GE: case OP_PB_LE: case OP_PB_EQ: { @@ -106,7 +97,6 @@ void pb_decl_plugin::get_op_names(svector & op_names, symbol const op_names.push_back(builtin_name(m_pble_sym.bare_str(), OP_PB_LE)); op_names.push_back(builtin_name(m_pbge_sym.bare_str(), OP_PB_GE)); op_names.push_back(builtin_name(m_pbeq_sym.bare_str(), OP_PB_EQ)); - op_names.push_back(builtin_name("is-odd", OP_PB_ODD)); } } diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index fdd64561b..0750dcac7 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -35,7 +35,6 @@ enum pb_op_kind { OP_PB_LE, // pseudo-Boolean <= (generalizes at_most_k) OP_PB_GE, // pseudo-Boolean >= OP_PB_EQ, // equality - OP_PB_ODD, // parity of arguments is odd OP_PB_AUX_BOOL, // auxiliary internal Boolean variable. LAST_PB_OP }; @@ -96,14 +95,12 @@ public: app * mk_ge(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); app * mk_eq(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); app * mk_lt(unsigned num_args, rational const * coeffs, expr * const * args, rational const& k); - app * mk_odd(unsigned num_args, expr * const * args); bool is_at_most_k(func_decl *a) const; bool is_at_most_k(expr *a) const { return is_app(a) && is_at_most_k(to_app(a)->get_decl()); } bool is_at_most_k(expr *a, rational& k) const; bool is_at_least_k(func_decl *a) const; bool is_at_least_k(expr *a) const { return is_app(a) && is_at_least_k(to_app(a)->get_decl()); } bool is_at_least_k(expr *a, rational& k) const; - bool is_odd(expr* a) const; rational get_k(func_decl *a) const; rational get_k(expr *a) const { return get_k(to_app(a)->get_decl()); } bool is_le(func_decl *a) const; From dc588b54f798102e87ee4d5810036092323850f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 19 Feb 2017 11:31:34 -0800 Subject: [PATCH 0044/1283] add sorting-based pb encoding in the style of minisat+ Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 188 +++++++++++++++++++++++++++- src/sat/sat_lookahead.h | 161 ++++++++++++------------ src/util/sorting_network.h | 2 +- 3 files changed, 263 insertions(+), 88 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 9bc54ae74..c0a13fa77 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -96,10 +96,10 @@ struct pb2bv_rewriter::imp { case l_undef: tout << "= "; break; case l_false: tout << ">= "; break; } - tout << m_k << "\n";); + tout << k << "\n";); if (k.is_zero()) { if (is_le != l_false) { - return expr_ref(m.mk_not(mk_or(m, sz, args)), m); + return expr_ref(m.mk_not(::mk_or(m, sz, args)), m); } else { return expr_ref(m.mk_true(), m); @@ -108,6 +108,15 @@ struct pb2bv_rewriter::imp { if (k.is_neg()) { return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m); } + + expr_ref result(m); + switch (is_le) { + case l_true: if (mk_le(sz, args, k, result)) return result; else break; + case l_false: if (mk_ge(sz, args, k, result)) return result; else break; + case l_undef: if (mk_eq(sz, args, k, result)) return result; else break; + } + + // fall back to divide and conquer encoding. SASSERT(k.is_pos()); expr_ref zero(m), bound(m); expr_ref_vector es(m), fmls(m); @@ -139,12 +148,12 @@ struct pb2bv_rewriter::imp { } switch (is_le) { case l_true: - return mk_and(fmls); + return ::mk_and(fmls); case l_false: if (!es.empty()) { fmls.push_back(bv.mk_ule(bound, es.back())); } - return mk_or(fmls); + return ::mk_or(fmls); case l_undef: if (es.empty()) { fmls.push_back(m.mk_bool_val(k.is_zero())); @@ -152,13 +161,180 @@ struct pb2bv_rewriter::imp { else { fmls.push_back(m.mk_eq(bound, es.back())); } - return mk_and(fmls); + return ::mk_and(fmls); default: UNREACHABLE(); return expr_ref(m.mk_true(), m); } } + /** + \brief MiniSat+ based encoding of PB constraints. + The procedure is described in "Translating Pseudo-Boolean Constraints into SAT " +         Niklas Een, Niklas Sörensson, JSAT 2006. + */ + + const unsigned primes[7] = { 2, 3, 5, 7, 11, 13, 17}; + + vector m_min_base; + rational m_min_cost; + vector m_base; + + void create_basis(vector const& seq, rational carry_in, rational cost) { + if (cost >= m_min_cost) { + return; + } + rational delta_cost(0); + for (unsigned i = 0; i < seq.size(); ++i) { + delta_cost += seq[i]; + } + if (cost + delta_cost < m_min_cost) { + m_min_cost = cost + delta_cost; + m_min_base = m_base; + m_min_base.push_back(delta_cost + rational::one()); + } + + for (unsigned i = 0; i < sizeof(primes)/sizeof(*primes); ++i) { + vector seq1; + rational p(primes[i]); + rational rest = carry_in; + // create seq1 + for (unsigned j = 0; j < seq.size(); ++j) { + rest += seq[j] % p; + if (seq[j] >= p) { + seq1.push_back(div(seq[j], p)); + } + } + + m_base.push_back(p); + create_basis(seq1, div(rest, p), cost + rest); + m_base.pop_back(); + } + } + + bool create_basis() { + m_base.reset(); + m_min_cost = rational(INT_MAX); + m_min_base.reset(); + rational cost(0); + create_basis(m_coeffs, rational::zero(), cost); + m_base = m_min_base; + TRACE("pb", + tout << "Base: "; + for (unsigned i = 0; i < m_base.size(); ++i) { + tout << m_base[i] << " "; + } + tout << "\n";); + return + !m_base.empty() && + m_base.back().is_unsigned() && + m_base.back().get_unsigned() <= 20*m_base.size(); + } + + /** + \brief Check if 'out mod n >= lim'. + */ + expr_ref mod_ge(ptr_vector const& out, unsigned n, unsigned lim) { + TRACE("pb", for (unsigned i = 0; i < out.size(); ++i) tout << mk_pp(out[i], m) << " "; tout << "\n"; + tout << "n:" << n << " lim: " << lim << "\n";); + if (lim == n) { + return expr_ref(m.mk_false(), m); + } + if (lim == 0) { + return expr_ref(m.mk_true(), m); + } + SASSERT(0 < lim && lim < n); + expr_ref_vector ors(m); + for (unsigned j = 0; j + lim - 1 < out.size(); j += n) { + expr_ref tmp(m); + tmp = out[j + lim - 1]; + if (j + n < out.size()) { + tmp = m.mk_and(tmp, m.mk_not(out[j + n])); + } + ors.push_back(tmp); + } + return ::mk_or(ors); + } + + bool mk_ge(unsigned sz, expr * const* args, rational bound, expr_ref& result) { + if (!create_basis()) return false; + if (!bound.is_unsigned()) return false; + vector coeffs(m_coeffs); + result = m.mk_true(); + expr_ref_vector carry(m), new_carry(m); + for (unsigned i = 0; i < m_base.size(); ++i) { + rational b_i = m_base[i]; + unsigned B = b_i.get_unsigned(); + unsigned d_i = (bound % b_i).get_unsigned(); + bound = div(bound, b_i); + for (unsigned j = 0; j < coeffs.size(); ++j) { + rational c = coeffs[j] % b_i; + SASSERT(c.is_unsigned()); + for (unsigned k = 0; k < c.get_unsigned(); ++k) { + carry.push_back(args[j]); + } + coeffs[j] = div(coeffs[j], b_i); + } + TRACE("pb", tout << "Carry: " << carry << "\n"; + for (unsigned j = 0; j < coeffs.size(); ++j) tout << coeffs[j] << " "; + tout << "\n"; + ); + ptr_vector out; + m_sort.sorting(carry.size(), carry.c_ptr(), out); + + expr_ref gt = mod_ge(out, B, d_i + 1); + expr_ref ge = mod_ge(out, B, d_i); + result = mk_or(gt, mk_and(ge, result)); + TRACE("pb", tout << result << "\n";); + + new_carry.reset(); + for (unsigned j = B - 1; j < out.size(); j += B) { + new_carry.push_back(out[j]); + } + carry.reset(); + carry.append(new_carry); + } + TRACE("pb", tout << result << "\n";); + return true; + } + + expr_ref mk_and(expr_ref& a, expr_ref& b) { + if (m.is_true(a)) return b; + if (m.is_true(b)) return a; + if (m.is_false(a)) return a; + if (m.is_false(b)) return b; + return expr_ref(m.mk_and(a, b), m); + } + + expr_ref mk_or(expr_ref& a, expr_ref& b) { + if (m.is_true(a)) return a; + if (m.is_true(b)) return b; + if (m.is_false(a)) return b; + if (m.is_false(b)) return a; + return expr_ref(m.mk_or(a, b), m); + } + + bool mk_le(unsigned sz, expr * const* args, rational const& k, expr_ref& result) { + expr_ref_vector args1(m); + rational bound(-k); + for (unsigned i = 0; i < sz; ++i) { + args1.push_back(mk_not(args[i])); + bound += m_coeffs[i]; + } + return mk_ge(sz, args1.c_ptr(), bound, result); + } + + bool mk_eq(unsigned sz, expr * const* args, rational const& k, expr_ref& result) { + expr_ref r1(m), r2(m); + if (mk_ge(sz, args, k, r1) && mk_le(sz, args, k, r2)) { + result = m.mk_and(r1, r2); + return true; + } + else { + return false; + } + } + expr_ref mk_bv(func_decl * f, unsigned sz, expr * const* args) { decl_kind kind = f->get_decl_kind(); rational k = pb.get_k(f); @@ -403,7 +579,7 @@ struct pb2bv_rewriter::imp { } void mk_clause(unsigned n, literal const* lits) { - m_imp.m_lemmas.push_back(mk_or(m, n, lits)); + m_imp.m_lemmas.push_back(::mk_or(m, n, lits)); } void keep_cardinality_constraints(bool f) { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index f70ceab38..eb713ab7c 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -33,6 +33,7 @@ namespace sat { literal_vector m_units; unsigned_vector m_units_lim; unsigned_vector m_learned_lim; + unsigned_vector m_binary; void init() { @@ -44,6 +45,7 @@ namespace sat { m_learned_lim.push_back(s.m_learned.size()); m_units_lim.push_back(m_units.size()); m_trail.push_back(lit); + m_binary.push_back(0); s.push(); assign(lit); } @@ -58,27 +60,31 @@ namespace sat { s.m_cls_allocator.del_clause(r); } s.m_learned.shrink(old_sz); - literal lits[2] = { m_trail.back(), null_literal }; unsigned new_unit_sz = m_units_lim.back(); - for (unsigned i = m_units.size(); i > new_unit_sz; ) { - --i; - lits[1] = m_units[i]; + for (unsigned i = new_unit_sz; i < m_units.size(); ++i) { + literal lits[2] = { ~m_trail.back(), m_units[i] }; clause * r = s.m_cls_allocator.mk_clause(2, lits, true); s.m_learned.push_back(r); } m_units.shrink(new_unit_sz); m_units_lim.pop_back(); m_trail.pop_back(); + m_binary.pop_back(); } - unsigned diff(unsigned value0) const { - unsigned value1 = get_state_value(); - SASSERT(value1 >= value0); - return value1 - value0; + unsigned diff() const { return m_binary.back() + m_units.size() - m_units_lim.back(); } + + unsigned mix_diff(unsigned l, unsigned r) const { return l + r + (1 << 10) * l * r; } + + clause const& get_clause(watch_list::iterator it) const { + clause_offset cls_off = it->get_clause_offset(); + return *(s.m_cls_allocator.get_clause(cls_off)); } - unsigned mix_diff(unsigned l, unsigned r) const { - return l + r + (1 << 10) * l * r; + bool is_nary_propagation(clause const& c, literal l) const { + bool r = c.size() > 2 && ((c[0] == l && s.value(c[1]) == l_false) || (c[1] == l && s.value(c[0]) == l_false)); + DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false);); + return r; } void get_resolvent_units(literal lit) { @@ -94,34 +100,33 @@ namespace sat { switch (it->get_kind()) { case watched::TERNARY: if (s.value(it->get_literal1()) == l_false && - s.value(it->get_literal()) == l_false) { + s.value(it->get_literal2()) == l_false) { m_units.push_back(l); - goto done_watch_list; + goto done_finding_unit; } break; case watched::CLAUSE: { - clause_offset cls_off = it->get_clause_offset(); - clause & c = *(s.m_cls_allocator.get_clause(cls_off)); - if (c.size() == 2) break; - SASSERT(c.size() > 2); - if (c[0] == l && s.value(c[1]) == l_false) { - DEBUG_CODE(for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false);); + clause const & c = get_clause(it); + SASSERT(c[0] == l || c[1] == l); + if (is_nary_propagation(c, l)) { m_units.push_back(l); - goto done_watch_list; - } - if (c[1] == l && s.value(c[0]) == l_false) { - DEBUG_CODE(for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false);); - m_units.push_back(l); - goto done_watch_list; - } + goto done_finding_unit; + } break; } default: break; } } - done_watch_list: + done_finding_unit: + + // + // TBD: count binary clauses created by propagation. + // They used to be in the watch list of l.index(), + // both new literals in watch list should be unassigned. + // continue; + } } @@ -131,10 +136,6 @@ namespace sat { return l; } - unsigned get_state_value() const { - return s.m_learned.size(); - } - bool choose1(literal& l) { literal_vector P; pre_select(P); @@ -142,28 +143,26 @@ namespace sat { if (P.empty()) { return true; } - unsigned value0 = get_state_value(); unsigned h = 0, count = 1; - literal_vector& units = m_units;; for (unsigned i = 0; i < P.size(); ++i) { literal lit = P[i]; push(lit); - if (do_double(value0)) double_look(); + if (do_double()) double_look(P); if (inconsistent()) { pop(); assign(~lit); - if (do_double(value0)) double_look(); + if (do_double()) double_look(P); if (inconsistent()) return true; continue; } - unsigned diff1 = diff(value0); + unsigned diff1 = diff(); pop(); push(~lit); - if (do_double(value0)) double_look(); + if (do_double()) double_look(P); bool unsat2 = inconsistent(); - unsigned diff2 = diff(value0); + unsigned diff2 = diff(); pop(); if (unsat2) { @@ -173,25 +172,28 @@ namespace sat { unsigned mixd = mix_diff(diff1, diff2); + if (mixd > h || (mixd == h && s.m_rand(count) == 0)) { + CTRACE("sat", l != null_literal, tout << lit << " diff1: " << diff1 << " diff2: " << diff2 << "\n";); + if (mixd > h) count = 1; else ++count; h = mixd; l = diff1 < diff2 ? lit : ~lit; - ++count; } } return l != null_literal; } - void double_look() { - literal_vector P; - pre_select(P); + void double_look(literal_vector const& P) { + bool unsat; for (unsigned i = 0; !inconsistent() && i < P.size(); ++i) { literal lit = P[i]; + if (s.value(lit) != l_undef) continue; push(lit); - bool unsat = inconsistent(); + unsat = inconsistent(); pop(); if (unsat) { + TRACE("sat", tout << "unit: " << ~lit << "\n";); assign(~lit); continue; } @@ -200,6 +202,7 @@ namespace sat { unsat = inconsistent(); pop(); if (unsat) { + TRACE("sat", tout << "unit: " << lit << "\n";); assign(lit); } @@ -211,6 +214,7 @@ namespace sat { s.assign(l, justification()); s.propagate(false); get_resolvent_units(l); + TRACE("sat", s.display(tout << l << " @ " << s.scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } bool inconsistent() { return s.inconsistent(); } @@ -220,6 +224,18 @@ namespace sat { order_by_implication_trees(P); } + void check_binary(clause const& c, literal lit1, literal& lit2) { + if (c.size() == 2) { + if (c[0] == lit1) { + lit2 = c[1]; + } + else { + SASSERT(c[1] == lit1); + lit2 = c[0]; + } + } + } + void order_by_implication_trees(literal_vector& P) { literal_set roots; literal_vector nodes, parent; @@ -246,28 +262,19 @@ namespace sat { lit2 = it->get_literal(); break; case watched::CLAUSE: { - clause_offset cls_off = it->get_clause_offset(); - clause & c = *(s.m_cls_allocator.get_clause(cls_off)); - if (c.size() == 2) { - if (c[0] == ~lit1) { - lit2 = c[1]; - } - else { - SASSERT(c[1] == ~lit1); - lit2 = c[0]; - } - } + clause const & c = get_clause(it); + check_binary(c, lit1, lit2); break; } default: break; } - if (lit2 != null_literal && roots.contains(lit2)) { - // lit2 => lit1 + if (lit2 != null_literal && roots.contains(~lit2)) { + // ~lit2 => lit1 // if lit2 is a root, put it under lit2 - parent.setx(lit2.index(), lit1, null_literal); - roots.remove(lit2); + parent.setx((~lit2).index(), lit1, null_literal); + roots.remove(~lit2); roots.insert(lit1); goto found; } @@ -287,17 +294,8 @@ namespace sat { lit2 = it->get_literal(); break; case watched::CLAUSE: { - clause_offset cls_off = it->get_clause_offset(); - clause & c = *(s.m_cls_allocator.get_clause(cls_off)); - if (c.size() == 2) { - if (c[0] == lit1) { - lit2 = c[1]; - } - else { - SASSERT(c[1] == lit1); - lit2 = c[0]; - } - } + clause const & c = get_clause(it); + check_binary(c, ~lit1, lit2); break; } default: @@ -311,19 +309,21 @@ namespace sat { goto found; } } - std::cout << "no parents or children of literal " << lit1 << "\n"; nodes.push_back(lit1); roots.insert(lit1); found: ; - } - std::cout << "implication trees\n"; - for (unsigned i = 0; i < parent.size(); ++i) { - literal p = parent[i]; - if (p != null_literal) { - std::cout << to_literal(i) << " |-> " << p << "\n"; - } - } + } + TRACE("sat", + tout << "implication trees\n"; + for (unsigned i = 0; i < parent.size(); ++i) { + literal p = parent[i]; + if (p != null_literal) { + tout << to_literal(i) << " |-> " << p << "\n"; + } + }); + + // TBD: extract ordering. } @@ -335,9 +335,8 @@ namespace sat { } } - bool do_double(unsigned value0) { - unsigned value1 = get_state_value(); - return !inconsistent() && value1 - value0 > m_delta_trigger; + bool do_double() { + return !inconsistent() && diff() > m_delta_trigger; } void update_delta_trigger() { @@ -368,11 +367,11 @@ namespace sat { s.checkpoint(); BACKTRACK; literal l = choose(); - TRACE("sat", tout << l << "\n";); BACKTRACK; if (l == null_literal) { return l_true; } + TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); push(l); trail.push_back(l); } diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index b0efbd346..33514730f 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -558,7 +558,7 @@ Notes: m_stats.m_num_compiled_clauses++; m_stats.m_num_clause_vars += n; literal_vector tmp(n, ls); - TRACE("pb", for (unsigned i = 0; i < n; ++i) tout << ls[i] << " "; tout << "\n";); + TRACE("pb_verbose", for (unsigned i = 0; i < n; ++i) tout << ls[i] << " "; tout << "\n";); ctx.mk_clause(n, tmp.c_ptr()); } From 2885ca77148f27fec5cd2710ae1f5d54f0e1f7c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 19 Feb 2017 11:35:31 -0800 Subject: [PATCH 0045/1283] tune cardinalities Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 51 ++++++++++++++++++++++++++++++++++--- src/sat/sat_solver.cpp | 22 ++++++++++++++++ src/sat/sat_solver.h | 1 + src/sat/tactic/goal2sat.cpp | 4 +++ src/util/uint_set.h | 7 ++++- 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 8fd0d89a8..b69b0aae5 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -273,8 +273,6 @@ namespace sat { reset_coeffs(); m_num_marks = 0; m_bound = 0; - m_lemma.reset(); - // m_lemma.push_back(null_literal); literal consequent = s().m_not_l; justification js = s().m_conflict; m_conflict_lvl = s().get_max_lvl(consequent, js); @@ -415,6 +413,51 @@ namespace sat { bool_var v = m_active_vars[i]; slack += get_abs_coeff(v); } + + m_lemma.reset(); + +#if 1 + m_lemma.push_back(null_literal); + for (unsigned i = 0; 0 <= slack && i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + int coeff = get_coeff(v); + lbool val = m_solver->value(v); + bool is_true = val == l_true; + bool append = coeff != 0 && val != l_undef && (coeff < 0 == is_true); + + if (append) { + literal lit(v, !is_true); + if (lvl(lit) == m_conflict_lvl) { + if (m_lemma[0] == null_literal) { + slack -= abs(coeff); + m_lemma[0] = ~lit; + } + } + else { + slack -= abs(coeff); + m_lemma.push_back(~lit); + } + } + } + + if (slack >= 0) { + IF_VERBOSE(2, verbose_stream() << "(sat.card bail slack objective not met " << slack << ")\n";); + goto bail_out; + } + + if (m_lemma[0] == null_literal) { + m_lemma[0] = m_lemma.back(); + m_lemma.pop_back(); + unsigned level = lvl(m_lemma[0]); + for (unsigned i = 1; i < m_lemma.size(); ++i) { + if (lvl(m_lemma[i]) > level) { + level = lvl(m_lemma[i]); + std::swap(m_lemma[0], m_lemma[i]); + } + } + IF_VERBOSE(2, verbose_stream() << "(sat.card set level to " << level << " < " << m_conflict_lvl << ")\n";); + } +#else ++idx; while (0 <= slack) { literal lit = lits[idx]; @@ -437,13 +480,15 @@ namespace sat { SASSERT(idx > 0 || slack < 0); --idx; } - if (m_lemma.size() >= 2 && lvl(m_lemma[1]) == m_conflict_lvl) { // TRACE("sat", tout << "Bail out on no progress " << lit << "\n";); IF_VERBOSE(2, verbose_stream() << "(sat.card bail non-asserting resolvent)\n";); goto bail_out; } +#endif + + SASSERT(slack < 0); SASSERT(validate_conflict(m_lemma, m_A)); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 476295f7a..740eea371 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -176,6 +176,28 @@ namespace sat { return v; } + void solver::set_external(bool_var v) { + if (m_external[v]) return; + m_external[v] = true; + + if (!m_ext) return; + + lbool val = value(v); + + switch (val) { + case l_true: { + m_ext->asserted(literal(v, false)); + break; + } + case l_false: { + m_ext->asserted(literal(v, true)); + break; + } + default: + break; + } + } + void solver::mk_clause(unsigned num_lits, literal * lits) { m_model_is_current = false; DEBUG_CODE({ diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 37e5f1bb6..9393a8e10 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -227,6 +227,7 @@ namespace sat { unsigned num_clauses() const; unsigned num_restarts() const { return m_restarts; } bool is_external(bool_var v) const { return m_external[v] != 0; } + void set_external(bool_var v); bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } unsigned scope_lvl() const { return m_scope_lvl; } unsigned search_lvl() const { return m_search_lvl; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 1fcaa78b1..87d69b35e 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -378,11 +378,15 @@ struct goal2sat::imp { for (unsigned i = 0; i < num_args; ++i) { sat::literal lit(m_result_stack[sz - num_args + i]); if (!m_solver.is_external(lit.var())) { +#if 1 + m_solver.set_external(lit.var()); +#else sat::bool_var w = m_solver.mk_var(true); sat::literal lit2(w, false); mk_clause(lit, ~lit2); mk_clause(~lit, lit2); lit = lit2; +#endif } lits.push_back(lit); } diff --git a/src/util/uint_set.h b/src/util/uint_set.h index 7ff497709..d0cc8a32a 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -304,7 +304,12 @@ public: unsigned size() const { return m_set.size(); } iterator begin() const { return m_set.begin(); } iterator end() const { return m_set.end(); } - void reset() { m_set.reset(); m_in_set.reset(); } + // void reset() { m_set.reset(); m_in_set.reset(); } + void reset() { + unsigned sz = m_set.size(); + for (unsigned i = 0; i < sz; ++i) m_in_set[m_set[i]] = false; + m_set.reset(); + } void finalize() { m_set.finalize(); m_in_set.finalize(); } tracked_uint_set& operator&=(tracked_uint_set const& other) { unsigned j = 0; From 98c5a779b43e22ea79b8dea4f88a3d635644beb9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 20 Feb 2017 16:55:00 -0800 Subject: [PATCH 0046/1283] add xor parity solver feature Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 15 +- src/sat/card_extension.cpp | 567 ++++++++++++++++++++++---- src/sat/card_extension.h | 109 ++++- src/sat/sat_params.pyg | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 1 + src/sat/tactic/goal2sat.cpp | 79 +++- 6 files changed, 665 insertions(+), 108 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index c0a13fa77..24f9bf44b 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -50,6 +50,7 @@ struct pb2bv_rewriter::imp { rational m_k; vector m_coeffs; bool m_keep_cardinality_constraints; + unsigned m_min_arity; template expr_ref mk_le_ge(expr_ref_vector& fmls, expr* a, expr* b, expr* bound) { @@ -416,7 +417,8 @@ struct pb2bv_rewriter::imp { bv(m), m_trail(m), m_args(m), - m_keep_cardinality_constraints(true) + m_keep_cardinality_constraints(true), + m_min_arity(8) {} bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { @@ -530,27 +532,26 @@ struct pb2bv_rewriter::imp { bool mk_pb(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { SASSERT(f->get_family_id() == pb.get_family_id()); if (is_or(f)) { - if (m_keep_cardinality_constraints) return false; result = m.mk_or(sz, args); } else if (pb.is_at_most_k(f) && pb.get_k(f).is_unsigned()) { - if (m_keep_cardinality_constraints) return false; + if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_at_least_k(f) && pb.get_k(f).is_unsigned()) { - if (m_keep_cardinality_constraints) return false; + if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - if (m_keep_cardinality_constraints) return false; + if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.eq(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - if (m_keep_cardinality_constraints) return false; + if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); } else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { - if (m_keep_cardinality_constraints) return false; + if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } else { diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index b69b0aae5..fd8986cae 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Extension for cardinality reasoning. + Extension for cardinality and xor reasoning. Author: @@ -42,6 +42,16 @@ namespace sat { SASSERT(m_size >= m_k && m_k > 0); } + card_extension::xor::xor(unsigned index, literal lit, literal_vector const& lits): + m_index(index), + m_lit(lit), + m_size(lits.size()) + { + for (unsigned i = 0; i < lits.size(); ++i) { + m_lits[i] = lits[i]; + } + } + void card_extension::init_watch(bool_var v) { if (m_var_infos.size() <= static_cast(v)) { m_var_infos.resize(static_cast(v)+100); @@ -120,7 +130,7 @@ namespace sat { if (m_var_infos.size() <= static_cast(lit.var())) { return; } - ptr_vector*& cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; + ptr_vector*& cards = m_var_infos[lit.var()].m_card_watch[lit.sign()]; if (!is_tag_empty(cards)) { if (remove(*cards, c)) { cards = set_tag_empty(cards); @@ -128,30 +138,6 @@ namespace sat { } } - ptr_vector* card_extension::set_tag_empty(ptr_vector* c) { - return TAG(ptr_vector*, c, 1); - } - - bool card_extension::is_tag_empty(ptr_vector const* c) { - return !c || GET_TAG(c) == 1; - } - - ptr_vector* card_extension::set_tag_non_empty(ptr_vector* c) { - return UNTAG(ptr_vector*, c); - } - - bool card_extension::remove(ptr_vector& cards, card* c) { - unsigned sz = cards.size(); - for (unsigned j = 0; j < sz; ++j) { - if (cards[j] == c) { - std::swap(cards[j], cards[sz-1]); - cards.pop_back(); - return sz == 1; - } - } - return false; - } - void card_extension::assign(card& c, literal lit) { switch (value(lit)) { case l_true: @@ -183,14 +169,14 @@ namespace sat { void card_extension::watch_literal(card& c, literal lit) { TRACE("sat_verbose", tout << "watch: " << lit << "\n";); init_watch(lit.var()); - ptr_vector* cards = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; + ptr_vector* cards = m_var_infos[lit.var()].m_card_watch[lit.sign()]; if (cards == 0) { cards = alloc(ptr_vector); - m_var_infos[lit.var()].m_lit_watch[lit.sign()] = cards; + m_var_infos[lit.var()].m_card_watch[lit.sign()] = cards; } else if (is_tag_empty(cards)) { cards = set_tag_non_empty(cards); - m_var_infos[lit.var()].m_lit_watch[lit.sign()] = cards; + m_var_infos[lit.var()].m_card_watch[lit.sign()] = cards; } TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); cards->push_back(&c); @@ -202,6 +188,155 @@ namespace sat { s().set_conflict(justification::mk_ext_justification(c.index()), ~lit); SASSERT(s().inconsistent()); } + + void card_extension::clear_watch(xor& x) { + unwatch_literal(x[0], &x); + unwatch_literal(x[1], &x); + } + + void card_extension::unwatch_literal(literal lit, xor* c) { + if (m_var_infos.size() <= static_cast(lit.var())) { + return; + } + xor_watch* xors = m_var_infos[lit.var()].m_xor_watch; + if (!is_tag_empty(xors)) { + if (remove(*xors, c)) { + xors = set_tag_empty(xors); + } + } + } + + bool card_extension::parity(xor const& x, unsigned offset) const { + bool odd = false; + unsigned sz = x.size(); + for (unsigned i = offset; i < sz; ++i) { + SASSERT(value(x[i]) != l_undef); + if (value(x[i]) == l_true) { + odd = !odd; + } + } + return odd; + } + + void card_extension::init_watch(xor& x, bool is_true) { + clear_watch(x); + if (x.lit().sign() == is_true) { + x.negate(); + } + unsigned sz = x.size(); + unsigned j = 0; + for (unsigned i = 0; i < sz && j < 2; ++i) { + if (value(x[i]) == l_undef) { + x.swap(i, j); + ++j; + } + } + switch (j) { + case 0: + if (!parity(x, 0)) { + set_conflict(x, x[0]); + } + break; + case 1: + assign(x, parity(x, 1) ? ~x[0] : x[0]); + break; + default: + SASSERT(j == 2); + watch_literal(x, x[0]); + watch_literal(x, x[1]); + break; + } + } + + void card_extension::assign(xor& x, literal lit) { + switch (value(lit)) { + case l_true: + break; + case l_false: + set_conflict(x, lit); + break; + default: + m_stats.m_num_propagations++; + m_num_propagations_since_pop++; + if (s().m_config.m_drat) { + svector ps; + literal_vector lits; + lits.push_back(~x.lit()); + for (unsigned i = 1; i < x.size(); ++i) { + lits.push_back(x[i]); + } + lits.push_back(lit); + ps.push_back(drat::premise(drat::s_ext(), x.lit())); + s().m_drat.add(lits, ps); + } + s().assign(lit, justification::mk_ext_justification(x.index())); + break; + } + } + + void card_extension::watch_literal(xor& x, literal lit) { + TRACE("sat_verbose", tout << "watch: " << lit << "\n";); + init_watch(lit.var()); + xor_watch*& xors = m_var_infos[lit.var()].m_xor_watch; + if (xors == 0) { + xors = alloc(ptr_vector); + } + else if (is_tag_empty(xors)) { + xors = set_tag_non_empty(xors); + } + xors->push_back(&x); + TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); + } + + + void card_extension::set_conflict(xor& x, literal lit) { + TRACE("sat", display(tout, x, true); ); + SASSERT(validate_conflict(x)); + s().set_conflict(justification::mk_ext_justification(x.index()), ~lit); + SASSERT(s().inconsistent()); + } + + lbool card_extension::add_assign(xor& x, literal alit) { + // literal is assigned + unsigned sz = x.size(); + TRACE("sat", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); + + SASSERT(value(alit) != l_undef); + SASSERT(value(x.lit()) == l_true); + unsigned index = 0; + for (; index <= 2; ++index) { + if (x[index].var() == alit.var()) break; + } + if (index == 2) { + // literal is no longer watched. + return l_undef; + } + SASSERT(x[index].var() == alit.var()); + + // find a literal to swap with: + for (unsigned i = 2; i < sz; ++i) { + literal lit2 = x[i]; + if (value(lit2) == l_undef) { + x.swap(index, i); + watch_literal(x, lit2); + return l_undef; + } + } + if (index == 0) { + x.swap(0, 1); + } + // alit resides at index 1. + SASSERT(x[1].var() == alit.var()); + if (value(x[0]) == l_undef) { + bool p = parity(x, 1); + assign(x, p ? ~x[0] : x[0]); + } + else if (!parity(x, 0)) { + set_conflict(x, x[0]); + } + return s().inconsistent() ? l_false : l_true; + } + void card_extension::normalize_active_coeffs() { while (!m_active_var_set.empty()) m_active_var_set.erase(); @@ -288,6 +423,8 @@ namespace sat { unsigned init_marks = m_num_marks; + vector jus; + do { if (offset == 0) { @@ -349,9 +486,22 @@ namespace sat { } case justification::EXT_JUSTIFICATION: { unsigned index = js.get_ext_justification_idx(); - card& c = *m_constraints[index]; - m_bound += offset * c.k(); - process_card(c, offset); + if (is_card_index(index)) { + card& c = index2card(index); + m_bound += offset * c.k(); + process_card(c, offset); + } + else { + // jus.push_back(js); + m_lemma.reset(); + m_bound += offset; + inc_coeff(consequent, offset); + get_xor_antecedents(idx, m_lemma); + // get_antecedents(consequent, index, m_lemma); + for (unsigned i = 0; i < m_lemma.size(); ++i) { + process_antecedent(~m_lemma[i], offset); + } + } break; } default: @@ -424,7 +574,6 @@ namespace sat { lbool val = m_solver->value(v); bool is_true = val == l_true; bool append = coeff != 0 && val != l_undef && (coeff < 0 == is_true); - if (append) { literal lit(v, !is_true); if (lvl(lit) == m_conflict_lvl) { @@ -440,6 +589,17 @@ namespace sat { } } + if (jus.size() > 1) { + std::cout << jus.size() << "\n"; + for (unsigned i = 0; i < jus.size(); ++i) { + s().display_justification(std::cout, jus[i]); std::cout << "\n"; + } + std::cout << m_lemma << "\n"; + active2pb(m_A); + display(std::cout, m_A); + } + + if (slack >= 0) { IF_VERBOSE(2, verbose_stream() << "(sat.card bail slack objective not met " << slack << ")\n";); goto bail_out; @@ -564,7 +724,7 @@ namespace sat { return p; } - card_extension::card_extension(): m_solver(0) { + card_extension::card_extension(): m_solver(0), m_has_xor(false) { TRACE("sat", tout << this << "\n";); } @@ -578,33 +738,170 @@ namespace sat { } void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { - unsigned index = m_constraints.size(); + unsigned index = 2*m_cards.size(); card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, literal(v, false), lits, k); - m_constraints.push_back(c); + m_cards.push_back(c); init_watch(v); m_var_infos[v].m_card = c; m_var_trail.push_back(v); } + void card_extension::add_xor(bool_var v, literal_vector const& lits) { + m_has_xor = true; + unsigned index = 2*m_xors.size()+1; + xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, literal(v, false), lits); + m_xors.push_back(x); + init_watch(v); + m_var_infos[v].m_xor = x; + m_var_trail.push_back(v); + } + + void card_extension::propagate(literal l, ext_constraint_idx idx, bool & keep) { UNREACHABLE(); } - void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { - card& c = *m_constraints[idx]; - - DEBUG_CODE( - bool found = false; - for (unsigned i = 0; !found && i < c.k(); ++i) { - found = c[i] == l; + + void card_extension::ensure_parity_size(bool_var v) { + if (m_parity_marks.size() <= static_cast(v)) { + m_parity_marks.resize(static_cast(v) + 1, 0); + } + } + + unsigned card_extension::get_parity(bool_var v) { + return m_parity_marks.get(v, 0); + } + + void card_extension::inc_parity(bool_var v) { + ensure_parity_size(v); + m_parity_marks[v]++; + } + + void card_extension::reset_parity(bool_var v) { + ensure_parity_size(v); + m_parity_marks[v] = 0; + } + + /** + \brief perform parity resolution on xor premises. + The idea is to collect premises based on xor resolvents. + Variables that are repeated an even number of times cancel out. + */ + void card_extension::get_xor_antecedents(unsigned index, literal_vector& r) { + literal_vector const& lits = s().m_trail; + literal l = lits[index + 1]; + unsigned level = lvl(l); + bool_var v = l.var(); + SASSERT(s().m_justification[v].get_kind() == justification::EXT_JUSTIFICATION); + SASSERT(!is_card_index(s().m_justification[v].get_ext_justification_idx())); + + unsigned num_marks = 0; + unsigned count = 0; + while (true) { + ++count; + justification js = s().m_justification[v]; + if (js.get_kind() == justification::EXT_JUSTIFICATION) { + unsigned idx = js.get_ext_justification_idx(); + if (is_card_index(idx)) { + r.push_back(l); + } + else { + xor& x = index2xor(idx); + if (lvl(x.lit()) > 0) r.push_back(x.lit()); + if (x[1].var() == l.var()) { + x.swap(0, 1); + } + SASSERT(x[0].var() == l.var()); + for (unsigned i = 1; i < x.size(); ++i) { + literal lit(value(x[i]) == l_true ? x[i] : ~x[i]); + inc_parity(lit.var()); + if (true || lvl(lit) == level) { + ++num_marks; + } + else { + m_parity_trail.push_back(lit); + } + } + } } - SASSERT(found);); + else { + r.push_back(l); + } + while (num_marks > 0) { + l = lits[index]; + v = l.var(); + unsigned n = get_parity(v); + if (n > 0) { + reset_parity(v); + if (n > 1) { + IF_VERBOSE(2, verbose_stream() << "parity greater than 1: " << l << " " << n << "\n";); + } + if (n % 2 == 1) { + break; + } + IF_VERBOSE(2, verbose_stream() << "skip even parity: " << l << "\n";); + --num_marks; + } + --index; + } + if (num_marks == 0) { + break; + } + --index; + --num_marks; + } + + // now walk the defined literals + + for (unsigned i = 0; i < m_parity_trail.size(); ++i) { + literal lit = m_parity_trail[i]; + if (get_parity(lit.var()) % 2 == 1) { + r.push_back(lit); + } + else { + IF_VERBOSE(2, verbose_stream() << "skip even parity: " << lit << "\n";); + } + reset_parity(lit.var()); + } + m_parity_trail.reset(); + } + + void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { + if (is_card_index(idx)) { + card& c = index2card(idx); - r.push_back(c.lit()); - SASSERT(value(c.lit()) == l_true); - for (unsigned i = c.k(); i < c.size(); ++i) { - SASSERT(value(c[i]) == l_false); - r.push_back(~c[i]); + DEBUG_CODE( + bool found = false; + for (unsigned i = 0; !found && i < c.k(); ++i) { + found = c[i] == l; + } + SASSERT(found);); + + r.push_back(c.lit()); + SASSERT(value(c.lit()) == l_true); + for (unsigned i = c.k(); i < c.size(); ++i) { + SASSERT(value(c[i]) == l_false); + r.push_back(~c[i]); + } + } + else { + xor& x = index2xor(idx); + r.push_back(x.lit()); + TRACE("sat", display(tout << l << " ", x, true);); + SASSERT(value(x.lit()) == l_true); + SASSERT(x[0].var() == l.var() || x[1].var() == l.var()); + if (x[0].var() == l.var()) { + SASSERT(value(x[1]) != l_undef); + r.push_back(value(x[1]) == l_true ? x[1] : ~x[1]); + } + else { + SASSERT(value(x[0]) != l_undef); + r.push_back(value(x[0]) == l_true ? x[0] : ~x[0]); + } + for (unsigned i = 2; i < x.size(); ++i) { + SASSERT(value(x[i]) != l_undef); + r.push_back(value(x[i]) == l_true ? x[i] : ~x[i]); + } } } @@ -670,10 +967,11 @@ namespace sat { if (s().inconsistent()) return; if (v >= m_var_infos.size()) return; var_info& vinfo = m_var_infos[v]; - ptr_vector* cards = vinfo.m_lit_watch[!l.sign()]; - //TRACE("sat", tout << "retrieve: " << v << " " << !l.sign() << "\n";); - //TRACE("sat", tout << "asserted: " << l << " " << (cards ? "non-empty" : "empty") << "\n";); - static unsigned is_empty = 0, non_empty = 0; + ptr_vector* cards = vinfo.m_card_watch[!l.sign()]; + card* crd = vinfo.m_card; + xor* x = vinfo.m_xor; + ptr_vector* xors = vinfo.m_xor_watch; + if (!is_tag_empty(cards)) { ptr_vector::iterator begin = cards->begin(); ptr_vector::iterator it = begin, it2 = it, end = cards->end(); @@ -702,14 +1000,56 @@ namespace sat { } cards->set_end(it2); if (cards->empty()) { - m_var_infos[v].m_lit_watch[!l.sign()] = set_tag_empty(cards); + m_var_infos[v].m_card_watch[!l.sign()] = set_tag_empty(cards); } } - card* crd = vinfo.m_card; if (crd != 0 && !s().inconsistent()) { init_watch(*crd, !l.sign()); } + if (m_has_xor && !s().inconsistent()) { + asserted_xor(l, xors, x); + } + } + + + void card_extension::asserted_xor(literal l, ptr_vector* xors, xor* x) { + TRACE("sat", tout << l << " " << !is_tag_empty(xors) << " " << (x != 0) << "\n";); + if (!is_tag_empty(xors)) { + ptr_vector::iterator begin = xors->begin(); + ptr_vector::iterator it = begin, it2 = it, end = xors->end(); + for (; it != end; ++it) { + xor& c = *(*it); + if (value(c.lit()) != l_true) { + continue; + } + switch (add_assign(c, ~l)) { + case l_false: // conflict + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + SASSERT(s().inconsistent()); + xors->set_end(it2); + return; + case l_undef: // watch literal was swapped + break; + case l_true: // unit propagation, keep watching the literal + if (it2 != it) { + *it2 = *it; + } + ++it2; + break; + } + } + xors->set_end(it2); + if (xors->empty()) { + m_var_infos[l.var()].m_xor_watch = set_tag_empty(xors); + } + } + + if (x != 0 && !s().inconsistent()) { + init_watch(*x, !l.sign()); + } } check_result card_extension::check() { return CR_DONE; } @@ -730,6 +1070,10 @@ namespace sat { clear_watch(*c); m_var_infos[v].m_card = 0; dealloc(c); + xor* x = m_var_infos[v].m_xor; + clear_watch(*x); + m_var_infos[v].m_xor = 0; + dealloc(x); } } m_var_lim.resize(new_lim); @@ -743,22 +1087,30 @@ namespace sat { extension* card_extension::copy(solver* s) { card_extension* result = alloc(card_extension); result->set_solver(s); - for (unsigned i = 0; i < m_constraints.size(); ++i) { + for (unsigned i = 0; i < m_cards.size(); ++i) { literal_vector lits; - card& c = *m_constraints[i]; + card& c = *m_cards[i]; for (unsigned i = 0; i < c.size(); ++i) { lits.push_back(c[i]); } result->add_at_least(c.lit().var(), lits, c.k()); } + for (unsigned i = 0; i < m_xors.size(); ++i) { + literal_vector lits; + xor& x = *m_xors[i]; + for (unsigned i = 0; i < x.size(); ++i) { + lits.push_back(x[i]); + } + result->add_xor(x.lit().var(), lits); + } return result; } void card_extension::find_mutexes(literal_vector& lits, vector & mutexes) { literal_set slits(lits); bool change = false; - for (unsigned i = 0; i < m_constraints.size(); ++i) { - card& c = *m_constraints[i]; + for (unsigned i = 0; i < m_cards.size(); ++i) { + card& c = *m_cards[i]; if (c.size() == c.k() + 1) { literal_vector mux; for (unsigned j = 0; j < c.size(); ++j) { @@ -786,10 +1138,10 @@ namespace sat { } } - void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { - watch const* w = m_var_infos[v].m_lit_watch[sign]; + void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { + card_watch const* w = m_var_infos[v].m_card_watch[sign]; if (!is_tag_empty(w)) { - watch const& wl = *w; + card_watch const& wl = *w; out << literal(v, sign) << " |-> "; for (unsigned i = 0; i < wl.size(); ++i) { out << wl[i]->lit() << " "; @@ -798,6 +1150,18 @@ namespace sat { } } + void card_extension::display_watch(std::ostream& out, bool_var v) const { + xor_watch const* w = m_var_infos[v].m_xor_watch; + if (!is_tag_empty(w)) { + xor_watch const& wl = *w; + out << "v" << v << " |-> "; + for (unsigned i = 0; i < wl.size(); ++i) { + out << wl[i]->lit() << " "; + } + out << "\n"; + } + } + void card_extension::display(std::ostream& out, ineq& ineq) const { for (unsigned i = 0; i < ineq.m_lits.size(); ++i) { out << ineq.m_coeffs[i] << "*" << ineq.m_lits[i] << " "; @@ -805,6 +1169,35 @@ namespace sat { out << ">= " << ineq.m_k << "\n"; } + void card_extension::display(std::ostream& out, xor& x, bool values) const { + out << "xor " << x.lit(); + if (x.lit() != null_literal && values) { + out << "@(" << value(x.lit()); + if (value(x.lit()) != l_undef) { + out << ":" << lvl(x.lit()); + } + out << "): "; + } + else { + out << ": "; + } + for (unsigned i = 0; i < x.size(); ++i) { + literal l = x[i]; + out << l; + if (values) { + out << "@(" << value(l); + if (value(l) != l_undef) { + out << ":" << lvl(l); + } + out << ") "; + } + else { + out << " "; + } + } + out << "\n"; + } + void card_extension::display(std::ostream& out, card& c, bool values) const { out << c.lit() << "[" << c.size() << "]"; if (c.lit() != null_literal && values) { @@ -838,23 +1231,33 @@ namespace sat { for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { display_watch(out, vi, false); display_watch(out, vi, true); + display_watch(out, vi); } for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { card* c = m_var_infos[vi].m_card; - if (c) { - display(out, *c, false); - } + if (c) display(out, *c, false); + xor* x = m_var_infos[vi].m_xor; + if (x) display(out, *x, false); } return out; } std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const { - card& c = *m_constraints[idx]; - out << "bound " << c.lit() << ": "; - for (unsigned i = 0; i < c.size(); ++i) { - out << c[i] << " "; + if (is_card_index(idx)) { + card& c = index2card(idx); + out << "bound " << c.lit() << ": "; + for (unsigned i = 0; i < c.size(); ++i) { + out << c[i] << " "; + } + out << ">= " << c.k(); + } + else { + xor& x = index2xor(idx); + out << "xor " << x.lit() << ": "; + for (unsigned i = 0; i < x.size(); ++i) { + out << x[i] << " "; + } } - out << ">= " << c.k(); return out; } @@ -870,6 +1273,9 @@ namespace sat { } return false; } + bool card_extension::validate_conflict(xor& x) { + return !parity(x, 0); + } bool card_extension::validate_unit_propagation(card const& c) { if (value(c.lit()) != l_true) return false; for (unsigned i = c.k(); i < c.size(); ++i) { @@ -933,12 +1339,23 @@ namespace sat { } case justification::EXT_JUSTIFICATION: { unsigned index = js.get_ext_justification_idx(); - card& c = *m_constraints[index]; - p.reset(offset*c.k()); - for (unsigned i = 0; i < c.size(); ++i) { - p.push(c[i], offset); + if (is_card_index(index)) { + card& c = index2card(index); + p.reset(offset*c.k()); + for (unsigned i = 0; i < c.size(); ++i) { + p.push(c[i], offset); + } + p.push(~c.lit(), offset*c.k()); + } + else { + literal_vector ls; + get_antecedents(lit, index, ls); + p.reset(offset); + for (unsigned i = 0; i < ls.size(); ++i) { + p.push(~ls[i], offset); + } + p.push(~index2xor(index).lit(), offset); } - p.push(~c.lit(), offset*c.k()); break; } default: diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 65a991ec2..4e0c10cd2 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -32,9 +32,7 @@ namespace sat { void reset() { memset(this, 0, sizeof(*this)); } }; - // class card_allocator; class card { - //friend class card_allocator; unsigned m_index; literal m_lit; unsigned m_k; @@ -53,6 +51,22 @@ namespace sat { void negate(); }; + class xor { + unsigned m_index; + literal m_lit; + unsigned m_size; + literal m_lits[0]; + public: + static size_t get_obj_size(unsigned num_lits) { return sizeof(xor) + num_lits * sizeof(literal); } + xor(unsigned index, literal lit, literal_vector const& lits); + unsigned index() const { return m_index; } + literal lit() const { return m_lit; } + literal operator[](unsigned i) const { return m_lits[i]; } + unsigned size() const { return m_size; } + void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } + void negate() { m_lits[0].neg(); } + }; + struct ineq { literal_vector m_lits; unsigned_vector m_coeffs; @@ -61,29 +75,48 @@ namespace sat { void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } }; - typedef ptr_vector watch; + typedef ptr_vector card_watch; + typedef ptr_vector xor_watch; struct var_info { - watch* m_lit_watch[2]; - card* m_card; - var_info(): m_card(0) { - m_lit_watch[0] = 0; - m_lit_watch[1] = 0; + card_watch* m_card_watch[2]; + xor_watch* m_xor_watch; + card* m_card; + xor* m_xor; + var_info(): m_xor_watch(0), m_card(0), m_xor(0) { + m_card_watch[0] = 0; + m_card_watch[1] = 0; } void reset() { dealloc(m_card); - dealloc(card_extension::set_tag_non_empty(m_lit_watch[0])); - dealloc(card_extension::set_tag_non_empty(m_lit_watch[1])); + dealloc(m_xor); + dealloc(card_extension::set_tag_non_empty(m_card_watch[0])); + dealloc(card_extension::set_tag_non_empty(m_card_watch[1])); + dealloc(card_extension::set_tag_non_empty(m_xor_watch)); } }; + + template + static ptr_vector* set_tag_empty(ptr_vector* c) { + return TAG(ptr_vector*, c, 1); + } + + template + static bool is_tag_empty(ptr_vector const* c) { + return !c || GET_TAG(c) == 1; + } + + template + static ptr_vector* set_tag_non_empty(ptr_vector* c) { + return UNTAG(ptr_vector*, c); + } + - static ptr_vector* set_tag_empty(ptr_vector* c); - static bool is_tag_empty(ptr_vector const* c); - static ptr_vector* set_tag_non_empty(ptr_vector* c); solver* m_solver; stats m_stats; - ptr_vector m_constraints; + ptr_vector m_cards; + ptr_vector m_xors; // watch literals svector m_var_infos; @@ -98,8 +131,14 @@ namespace sat { int m_bound; tracked_uint_set m_active_var_set; literal_vector m_lemma; -// literal_vector m_literals; unsigned m_num_propagations_since_pop; + bool m_has_xor; + unsigned_vector m_parity_marks; + literal_vector m_parity_trail; + void ensure_parity_size(bool_var v); + unsigned get_parity(bool_var v); + void inc_parity(bool_var v); + void reset_parity(bool_var v); solver& s() const { return *m_solver; } void init_watch(card& c, bool is_true); @@ -111,13 +150,44 @@ namespace sat { void clear_watch(card& c); void reset_coeffs(); void reset_marked_literals(); + void unwatch_literal(literal w, card* c); + + // xor specific functionality + void clear_watch(xor& x); + void watch_literal(xor& x, literal lit); + void unwatch_literal(literal w, xor* x); + void init_watch(xor& x, bool is_true); + void assign(xor& x, literal lit); + void set_conflict(xor& x, literal lit); + bool parity(xor const& x, unsigned offset) const; + lbool add_assign(xor& x, literal alit); + void asserted_xor(literal l, ptr_vector* xors, xor* x); + + bool is_card_index(unsigned idx) const { return 0 == (idx & 0x1); } + card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 1]; } + xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 1]; } + void get_xor_antecedents(unsigned index, literal_vector& r); + + + template + bool remove(ptr_vector& ts, T* t) { + unsigned sz = ts.size(); + for (unsigned j = 0; j < sz; ++j) { + if (ts[j] == t) { + std::swap(ts[j], ts[sz-1]); + ts.pop_back(); + return sz == 1; + } + } + return false; + } + + inline lbool value(literal lit) const { return m_solver->value(lit); } inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } inline unsigned lvl(bool_var v) const { return m_solver->lvl(v); } - void unwatch_literal(literal w, card* c); - bool remove(ptr_vector& cards, card* c); void normalize_active_coeffs(); void inc_coeff(literal l, int offset); @@ -131,6 +201,7 @@ namespace sat { // validation utilities bool validate_conflict(card& c); + bool validate_conflict(xor& x); bool validate_assign(literal_vector const& lits, literal lit); bool validate_lemma(); bool validate_unit_propagation(card const& c); @@ -143,12 +214,16 @@ namespace sat { void display(std::ostream& out, ineq& p) const; void display(std::ostream& out, card& c, bool values) const; + void display(std::ostream& out, xor& c, bool values) const; + void display_watch(std::ostream& out, bool_var v) const; void display_watch(std::ostream& out, bool_var v, bool sign) const; + public: card_extension(); virtual ~card_extension(); virtual void set_solver(solver* s) { m_solver = s; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); + void add_xor(bool_var v, literal_vector const& lits); virtual void propagate(literal l, ext_constraint_idx idx, bool & keep); virtual bool resolve_conflict(); virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index e3ca12b73..a51e72e25 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -26,5 +26,5 @@ def_module_params('sat', ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), - ('cardinality.solver', BOOL, True, 'use cardinality solver'), + ('cardinality.solver', BOOL, False, 'use cardinality/xor solver'), )) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index d2ae541a8..83b8362cf 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -217,6 +217,7 @@ public: sat_params p1(p); m_params.set_bool("elim_vars", false); m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); + m_params.set_bool("cardinality_solver", p1.cardinality_solver()); m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 87d69b35e..93367013e 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -65,6 +65,7 @@ struct goal2sat::imp { expr_ref_vector m_trail; expr_ref_vector m_interpreted_atoms; bool m_default_external; + bool m_cardinality_solver; imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external): m(_m), @@ -83,6 +84,8 @@ struct goal2sat::imp { void updt_params(params_ref const & p) { m_ite_extra = p.get_bool("ite_extra", true); m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + m_cardinality_solver = p.get_bool("cardinality_solver", false); + std::cout << p << "\n"; } void throw_op_not_handled(std::string const& s) { @@ -339,7 +342,7 @@ struct goal2sat::imp { } } - void convert_iff(app * t, bool root, bool sign) { + void convert_iff2(app * t, bool root, bool sign) { TRACE("goal2sat", tout << "convert_iff " << root << " " << sign << "\n" << mk_ismt2_pp(t, m) << "\n";); unsigned sz = m_result_stack.size(); SASSERT(sz >= 2); @@ -372,8 +375,33 @@ struct goal2sat::imp { } } - void convert_pb_args(app* t, sat::literal_vector& lits) { - unsigned num_args = t->get_num_args(); + void convert_iff(app * t, bool root, bool sign) { + TRACE("goal2sat", tout << "convert_iff " << root << " " << sign << "\n" << mk_ismt2_pp(t, m) << "\n";); + unsigned sz = m_result_stack.size(); + unsigned num = get_num_args(t); + SASSERT(sz >= num && num >= 2); + if (num == 2) { + convert_iff2(t, root, sign); + return; + } + sat::literal_vector lits; + convert_pb_args(num, lits); + sat::bool_var v = m_solver.mk_var(true); + ensure_extension(); + if (lits.size() % 2 == 0) lits[0].neg(); + m_ext->add_xor(v, lits); + sat::literal lit(v, sign); + if (root) { + m_result_stack.reset(); + mk_clause(lit); + } + else { + m_result_stack.shrink(sz - num); + m_result_stack.push_back(lit); + } + } + + void convert_pb_args(unsigned num_args, sat::literal_vector& lits) { unsigned sz = m_result_stack.size(); for (unsigned i = 0; i < num_args; ++i) { sat::literal lit(m_result_stack[sz - num_args + i]); @@ -396,7 +424,7 @@ struct goal2sat::imp { SASSERT(k.is_unsigned()); sat::literal_vector lits; unsigned sz = m_result_stack.size(); - convert_pb_args(t, lits); + convert_pb_args(t->get_num_args(), lits); sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, k.get_unsigned()); @@ -415,7 +443,7 @@ struct goal2sat::imp { SASSERT(k.is_unsigned()); sat::literal_vector lits; unsigned sz = m_result_stack.size(); - convert_pb_args(t, lits); + convert_pb_args(t->get_num_args(), lits); for (unsigned i = 0; i < lits.size(); ++i) { lits[i].neg(); } @@ -434,7 +462,7 @@ struct goal2sat::imp { void convert_eq_k(app* t, rational k, bool root, bool sign) { SASSERT(k.is_unsigned()); sat::literal_vector lits; - convert_pb_args(t, lits); + convert_pb_args(t->get_num_args(), lits); sat::bool_var v1 = m_solver.mk_var(true); sat::bool_var v2 = m_solver.mk_var(true); sat::literal l1(v1, false), l2(v2, false); @@ -528,6 +556,41 @@ struct goal2sat::imp { UNREACHABLE(); } } + + + unsigned get_num_args(app* t) { + + if (m.is_iff(t) && m_cardinality_solver) { + unsigned n = 2; + while (m.is_iff(t->get_arg(1))) { + ++n; + t = to_app(t->get_arg(1)); + } + return n; + } + else { + return t->get_num_args(); + } + } + + expr* get_arg(app* t, unsigned idx) { + if (m.is_iff(t) && m_cardinality_solver) { + while (idx >= 1) { + SASSERT(m.is_iff(t)); + t = to_app(t->get_arg(1)); + --idx; + } + if (m.is_iff(t)) { + return t->get_arg(idx); + } + else { + return t; + } + } + else { + return t->get_arg(idx); + } + } void process(expr * n) { //SASSERT(m_result_stack.empty()); @@ -559,9 +622,9 @@ struct goal2sat::imp { visit(t->get_arg(0), root, !sign); continue; } - unsigned num = t->get_num_args(); + unsigned num = get_num_args(t); while (fr.m_idx < num) { - expr * arg = t->get_arg(fr.m_idx); + expr * arg = get_arg(t, fr.m_idx); fr.m_idx++; if (!visit(arg, false, false)) goto loop; From 122a12c980f211a474fae06f10353d398ea86bc3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Feb 2017 09:12:10 -0800 Subject: [PATCH 0047/1283] fix build on downlevel compilers Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 24f9bf44b..b905ebff0 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -26,6 +26,8 @@ Notes: #include"ast_pp.h" #include"lbool.h" +const unsigned g_primes[7] = { 2, 3, 5, 7, 11, 13, 17}; + struct pb2bv_rewriter::imp { @@ -175,7 +177,6 @@ struct pb2bv_rewriter::imp {          Niklas Een, Niklas Sörensson, JSAT 2006. */ - const unsigned primes[7] = { 2, 3, 5, 7, 11, 13, 17}; vector m_min_base; rational m_min_cost; @@ -195,9 +196,9 @@ struct pb2bv_rewriter::imp { m_min_base.push_back(delta_cost + rational::one()); } - for (unsigned i = 0; i < sizeof(primes)/sizeof(*primes); ++i) { + for (unsigned i = 0; i < sizeof(g_primes)/sizeof(*g_primes); ++i) { vector seq1; - rational p(primes[i]); + rational p(g_primes[i]); rational rest = carry_in; // create seq1 for (unsigned j = 0; j < seq.size(); ++j) { From 77aac8d96fc115fef9cbf4c3cdd007a190df41ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Feb 2017 17:04:10 -0800 Subject: [PATCH 0048/1283] fix handling of global parameters, exceptions when optimization call gets cancelled Signed-off-by: Nikolaj Bjorner --- src/api/api_context.h | 6 +++--- src/api/api_opt.cpp | 8 +++++++- src/sat/tactic/goal2sat.cpp | 1 - 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/api/api_context.h b/src/api/api_context.h index 4685fd04e..d26cb0b1e 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -113,13 +113,13 @@ namespace api { ~context(); ast_manager & m() const { return *(m_manager.get()); } - context_params & params() { return m_params; } + context_params & params() { m_params.updt_params(); return m_params; } bool produce_proofs() const { return m().proofs_enabled(); } bool produce_models() const { return m_params.m_model; } bool produce_unsat_cores() const { return m_params.m_unsat_core; } bool use_auto_config() const { return m_params.m_auto_config; } - unsigned get_timeout() const { return m_params.m_timeout; } - unsigned get_rlimit() const { return m_params.m_rlimit; } + unsigned get_timeout() { return params().m_timeout; } + unsigned get_rlimit() { return params().m_rlimit; } arith_util & autil() { return m_arith_util; } bv_util & bvutil() { return m_bv_util; } datalog::dl_decl_util & datalog_util() { return m_datalog_util; } diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 3d8580178..6fbc86ab6 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -129,6 +129,7 @@ extern "C" { cancel_eh eh(mk_c(c)->m().limit()); unsigned timeout = to_optimize_ptr(o)->get_params().get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = mk_c(c)->get_rlimit(); + std::cout << "Timeout: " << timeout << "\n"; api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); @@ -137,8 +138,13 @@ extern "C" { r = to_optimize_ptr(o)->optimize(); } catch (z3_exception& ex) { - mk_c(c)->handle_exception(ex); r = l_undef; + if (ex.msg() == "canceled" && mk_c(c)->m().canceled()) { + to_optimize_ptr(o)->set_reason_unknown(ex.msg()); + } + else { + mk_c(c)->handle_exception(ex); + } } // to_optimize_ref(d).cleanup(); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 93367013e..30a458ece 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -85,7 +85,6 @@ struct goal2sat::imp { m_ite_extra = p.get_bool("ite_extra", true); m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); m_cardinality_solver = p.get_bool("cardinality_solver", false); - std::cout << p << "\n"; } void throw_op_not_handled(std::string const& s) { From 747ff19abad1cc118338623267ef749ee44f57e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Feb 2017 20:34:39 -0800 Subject: [PATCH 0049/1283] adding skeleton for local search Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 1 + src/sat/sat_local_search.cpp | 77 +++++++++++++++++ src/sat/sat_local_search.h | 125 +++++++++++++++++++++++++++ src/sat/sat_lookahead.h | 35 +++++--- 4 files changed, 226 insertions(+), 12 deletions(-) create mode 100644 src/sat/sat_local_search.cpp create mode 100644 src/sat/sat_local_search.h diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index 00c988f5c..5494049d7 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -12,6 +12,7 @@ z3_add_component(sat sat_elim_eqs.cpp sat_iff3_finder.cpp sat_integrity_checker.cpp + sat_local_search.cpp sat_model_converter.cpp sat_mus.cpp sat_parallel.cpp diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp new file mode 100644 index 000000000..5b8f44783 --- /dev/null +++ b/src/sat/sat_local_search.cpp @@ -0,0 +1,77 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_local_search.cpp + +Abstract: + + Local search module for cardinality clauses. + +Author: + + Sixue Liu 2017-2-21 + +Notes: + +--*/ + +#include "sat_local_search.h" + +namespace sat { + + void local_search::init() { + + } + + bool_var local_search::pick_var() { + + return null_bool_var; + } + + void local_search::flip(bool_var v) { + + + } + + bool local_search::tie_breaker_sat(int, int) { + + return false; + } + + bool local_search::tie_breaker_ccd(int, int) { + + return false; + } + + void local_search::calculate_and_update_ob() { + + } + + void local_search::verify_solution() { + + } + + void local_search::display(std::ostream& out) { + + } + + local_search::local_search(solver& s) { + + } + + local_search::~local_search() { + + } + + void local_search::add_soft(literal l, double weight) { + + } + + lbool local_search::operator()() { + return l_undef; + } + + +} diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h new file mode 100644 index 000000000..169596888 --- /dev/null +++ b/src/sat/sat_local_search.h @@ -0,0 +1,125 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_local_search.h + +Abstract: + + Local search module for cardinality clauses. + +Author: + + Sixue Liu 2017-2-21 + +Notes: + +--*/ +#ifndef _SAT_LOCAL_SEARCH_H_ +#define _SAT_LOCAL_SEARCH_H_ + +#include "vector.h" +#include "sat_types.h" + +namespace sat { + + class local_search { + + typedef svector bool_vector; + + // data structure for a term in objective function + struct ob_term { + int var_id; // variable id, begin with 1 + int coefficient; // non-zero integer + }; + + // data structure for a term in constraint + struct term { + int constraint_id; // constraint it belongs to + int var_id; // variable id, begin with 1 + bool sense; // 1 for positive, 0 for negative + //int coefficient; // all constraints are cardinality: coefficient=1 + }; + + // parameters of the instance + int num_vars; // var index from 1 to num_vars + int num_constraints; // constraint index from 1 to num_constraint + int max_constraint_len; + int min_constraint_len; + + // objective function: maximize + int ob_num_terms; // how many terms are in the objective function + ob_term* ob_constraint; // the objective function *constraint*, sorting as decending order + + + // terms arrays + vector > var_term; //var_term[i][j] means the j'th term of var i + vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i + + // information about the variable + int_vector coefficient_in_ob_constraint; // initilized to be 0 + int_vector score; + int_vector sscore; // slack score + + int_vector time_stamp; // the flip time stamp + bool_vector conf_change; // whether its configure changes since its last flip + int_vector cscc; // how many times its constraint state configure changes since its last flip + vector var_neighbor; // all of its neighborhoods variable + /* TBD: other scores */ + + // information about the constraints + int_vector constraint_k; // the right side k of a constraint + int_vector constraint_slack; // =constraint_k[i]-true_terms[i], if >=0 then sat + int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing + bool_vector has_true_ob_terms; + + // unsat constraint stack + int_vector unsat_stack; // store all the unsat constraits + int_vector index_in_unsat_stack; // which position is a contraint in the unsat_stack + + // configuration changed decreasing variables (score>0 and conf_change==true) + int_vector goodvar_stack; + bool_vector already_in_goodvar_stack; + // information about solution + bool_vector cur_solution; // the current solution + int objective_value; // the objective function value corresponds to the current solution + bool_vector best_solution; // the best solution so far + int best_objective_value = 0; // the objective value corresponds to the best solution so far + // for non-known instance, set as maximal + int best_known_value = INT_MAX; // best known value for this instance + + // cutoff + int cutoff_time = 1; // seconds + int max_steps = 2000000000; // < 2147483647 + + // for tuning + int s_id = 0; // strategy id + + void init(); + bool_var pick_var(); + void flip(bool_var v); + bool tie_breaker_sat(int, int); + bool tie_breaker_ccd(int, int); + + + void calculate_and_update_ob(); + + void verify_solution(); + + void display(std::ostream& out); + + public: + local_search(solver& s); + + ~local_search(); + + void add_soft(literal l, double weight); + + lbool operator()(); + + + }; +} + +#endif diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index eb713ab7c..4872a548a 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -281,7 +281,7 @@ namespace sat { } // - // lit1 => lit2. + // lit1 => lit2.n // if lit2 is a node, put lit1 above lit2 // @@ -351,23 +351,34 @@ namespace sat { } } + lbool backtrack(literal_vector& trail) { + if (inconsistent()) { + if (trail.empty()) return l_false; + pop(); + assign(~trail.back()); + trail.pop_back(); + return l_true; + } + return l_undef; + } + lbool search() { literal_vector trail; -#define BACKTRACK \ - if (inconsistent()) { \ - if (trail.empty()) return l_false; \ - pop(); \ - assign(~trail.back()); \ - trail.pop_back(); \ - continue; \ - } \ - while (true) { s.checkpoint(); - BACKTRACK; + switch (backtrack(trail)) { + case l_true: continue; + case l_false: return l_false; + case l_undef: break; + } + literal l = choose(); - BACKTRACK; + switch (backtrack(trail)) { + case l_true: continue; + case l_false: return l_false; + case l_undef: break; + } if (l == null_literal) { return l_true; } From eec1d9ef849f79f37c2a45114b811302c84662e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Feb 2017 21:19:13 -0800 Subject: [PATCH 0050/1283] porting more code Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 394 +++++++++++++++++++++++++++++++++-- src/sat/sat_local_search.h | 81 ++++--- 2 files changed, 428 insertions(+), 47 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 5b8f44783..ed13b5a1a 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -22,28 +22,175 @@ Notes: namespace sat { void local_search::init() { - + constraint_slack.resize(num_constraints + 1); + cur_solution.resize(num_vars + 1); + // etc. initialize other vectors. + init_greedy(); } - bool_var local_search::pick_var() { + void local_search::init_orig() { + int v, c; - return null_bool_var; + for (c = 1; c <= num_constraints; ++c) { + constraint_slack[c] = constraint_k[c]; + } + + // init unsat stack + m_unsat_stack.reset(); + + // init solution: random now + init_cur_solution(); + + // init varibale information + // variable 0 is the virtual variable + + score.resize(num_vars+1, 0); score[0] = INT_MIN; + sscore.resize(num_vars+1, 0); sscore[0] = INT_MIN; + time_stamp.resize(num_vars+1, 0); time_stamp[0] = max_steps; + conf_change.resize(num_vars+1, true); conf_change[0] = false; + cscc.resize(num_vars+1, 1); cscc[0] = 0; + + // figure out slack, and init unsat stack + for (c = 1; c <= num_constraints; ++c) { + for (unsigned i = 0; i < constraint_term[c].size(); ++i) { + v = constraint_term[c][i].var_id; + if (cur_solution[v] == constraint_term[c][i].sense) + --constraint_slack[c]; + } + // constraint_slack[c] = constraint_k[c] - true_terms_count[c]; + // violate the at-most-k constraint + if (constraint_slack[c] < 0) + unsat(c); + } + + // figure out variables scores, pscores and sscores + for (v = 1; v <= num_vars; ++v) { + for (unsigned i = 0; i < var_term[v].size(); ++i) { + c = var_term[v][i].constraint_id; + if (cur_solution[v] != var_term[v][i].sense) { + // will ++true_terms_count[c] + // will --slack + if (constraint_slack[c] <= 0) { + --sscore[v]; + if (constraint_slack[c] == 0) + --score[v]; + } + } + else { // if (cur_solution[v] == var_term[v][i].sense) + // will --true_terms_count[c] + // will ++slack + if (constraint_slack[c] <= -1) { + ++sscore[v]; + if (constraint_slack[c] == -1) + ++score[v]; + } + } + } + } + + // TBD: maybe use util\uint_set or tracked_uint_set instead? + + // init goodvars and okvars stack + for (v = 1; v <= num_vars; ++v) { + if (score[v] > 0) { // && conf_change[v] == true + already_in_goodvar_stack[v] = true; + goodvar_stack.push_back(v); + } + else + already_in_goodvar_stack[v] = false; + } } - void local_search::flip(bool_var v) { - - + void local_search::init_cur_solution() { + for (int v = 1; v <= num_vars; ++v) { + cur_solution[v] = (rand() % 2 == 1); + } } - bool local_search::tie_breaker_sat(int, int) { - - return false; - } - - bool local_search::tie_breaker_ccd(int, int) { - - return false; + void local_search::init_greedy() { + int v, c; + for (c = 1; c <= num_constraints; ++c) { + constraint_slack[c] = constraint_k[c]; + } + + // init unsat stack + m_unsat_stack.reset(); + + // init solution: greedy + init_cur_solution(); + + // init varibale information + // variable 0 is the virtual variable + score[0] = INT_MIN; + sscore[0] = INT_MIN; + time_stamp[0] = max_steps; + conf_change[0] = false; + cscc[0] = 0; + for (v = 1; v <= num_vars; ++v) { + score[v] = 0; + sscore[v] = 0; + time_stamp[v] = 0; + conf_change[v] = true; + cscc[v] = 1; + // greedy here!! + if (coefficient_in_ob_constraint[v] > 0) { + cur_solution[v] = true; + } + else if (coefficient_in_ob_constraint[v] < 0) { + cur_solution[v] = false; + } + } + + // figure out slack, and init unsat stack + for (c = 1; c <= num_constraints; ++c) { + for (unsigned i = 0; i < constraint_term[c].size(); ++i) { + v = constraint_term[c][i].var_id; + if (cur_solution[v] == constraint_term[c][i].sense) + //++true_terms_count[c]; + --constraint_slack[c]; + } + //constraint_slack[c] = constraint_k[c] - true_terms_count[c]; + // violate the at-most-k constraint + if (constraint_slack[c] < 0) + unsat(c); + } + + // figure out variables scores, pscores and sscores + for (v = 1; v <= num_vars; ++v) { + for (unsigned i = 0; i < var_term[v].size(); ++i) { + c = var_term[v][i].constraint_id; + if (cur_solution[v] != var_term[v][i].sense) { + // will ++true_terms_count[c] + // will --slack + if (constraint_slack[c] <= 0) { + --sscore[v]; + if (constraint_slack[c] == 0) + --score[v]; + } + } + else { // if (cur_solution[v] == var_term[v][i].sense) + // will --true_terms_count[c] + // will ++slack + if (constraint_slack[c] <= -1) { + ++sscore[v]; + if (constraint_slack[c] == -1) + ++score[v]; + } + } + } + } + + // init goodvars and okvars stack + for (v = 1; v <= num_vars; ++v) { + if (score[v] > 0) { // && conf_change[v] == true + already_in_goodvar_stack[v] = true; + goodvar_stack.push_back(v); + } + else + already_in_goodvar_stack[v] = false; + } } + void local_search::calculate_and_update_ob() { @@ -72,6 +219,225 @@ namespace sat { lbool local_search::operator()() { return l_undef; } + + + void local_search::flip(int flipvar) + { + // already changed truth value!!!! + cur_solution[flipvar] = !cur_solution[flipvar]; + + int v, c; + int org_flipvar_score = score[flipvar]; + int org_flipvar_sscore = sscore[flipvar]; + + // update related clauses and neighbor vars + for (unsigned i = 0; i < var_term[flipvar].size(); ++i) { + c = var_term[flipvar][i].constraint_id; + if (cur_solution[flipvar] == var_term[flipvar][i].sense) { + //++true_terms_count[c]; + --constraint_slack[c]; + if (constraint_slack[c] == -2) { // from -1 to -2 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flipping the slack increasing var will no long sat this constraint + if (cur_solution[v] == constraint_term[c][j].sense) + //score[v] -= constraint_weight[c]; + --score[v]; + } + } + else if (constraint_slack[c] == -1) { // from 0 to -1: sat -> unsat + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + ++cscc[v]; + //score[v] += constraint_weight[c]; + ++score[v]; + // slack increasing var + if (cur_solution[v] == constraint_term[c][j].sense) + ++sscore[v]; + } + unsat(c); + } + else if (constraint_slack[c] == 0) { // from 1 to 0 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack decreasing var will falsify this constraint + if (cur_solution[v] != constraint_term[c][j].sense) { + //score[v] -= constraint_weight[c]; + --score[v]; + --sscore[v]; + } + } + } + } + else { // if (cur_solution[flipvar] != var_term[i].sense) + //--true_terms_count[c]; + ++constraint_slack[c]; + if (constraint_slack[c] == 1) { // from 0 to 1 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack decreasing var will no long falsify this constraint + if (cur_solution[v] != constraint_term[c][j].sense) { + //score[v] += constraint_weight[c]; + ++score[v]; + ++sscore[v]; + } + } + } + else if (constraint_slack[c] == 0) { // from -1 to 0: unsat -> sat + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + ++cscc[v]; + //score[v] -= constraint_weight[c]; + --score[v]; + // slack increasing var no longer sat this var + if (cur_solution[v] == constraint_term[c][j].sense) + --sscore[v]; + } + sat(c); + } + else if (constraint_slack[c] == -1) { // from -2 to -1 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack increasing var will satisfy this constraint + if (cur_solution[v] == constraint_term[c][j].sense) + //score[v] += constraint_weight[c]; + ++score[v]; + } + } + } + } + + score[flipvar] = -org_flipvar_score; + sscore[flipvar] = -org_flipvar_sscore; + + conf_change[flipvar] = false; + cscc[flipvar] = 0; + + /* update CCD */ + // remove the vars no longer okvar in okvar stack + // remove the vars no longer goodvar in goodvar stack + for (unsigned i = goodvar_stack.size(); i > 0;) { + --i; + v = goodvar_stack[i]; + if (score[v] <= 0) { + goodvar_stack[i] = goodvar_stack.back(); + goodvar_stack.pop_back(); + already_in_goodvar_stack[v] = false; + } + } + // update all flipvar's neighbor's conf_change to true, add goodvar/okvar + for (unsigned i = 0; i < var_neighbor[flipvar].size(); ++i) { + v = var_neighbor[flipvar][i]; + conf_change[v] = true; + if (score[v] > 0 && !already_in_goodvar_stack[v]) { + goodvar_stack.push_back(v); + already_in_goodvar_stack[v] = true; + } + } + } + + bool local_search::tie_breaker_sat(int v, int best_var) + { + // most improvement on objective value + int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint[v] : coefficient_in_ob_constraint[v]; + int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint[best_var] : coefficient_in_ob_constraint[best_var]; + // break tie 1: max imp + if (v_imp > b_imp) + return true; + else if (v_imp == b_imp) { + // break tie 2: conf_change + if (conf_change[v] && !conf_change[best_var]) + return true; + else if (conf_change[v] == conf_change[best_var]) { + // break tie 3: time_stamp + if (time_stamp[v] < time_stamp[best_var]) + return true; + } + } + return false; + } + + bool local_search::tie_breaker_ccd(int v, int best_var) + { + // break tie 1: max score + if (score[v] > score[best_var]) + return true; + else if (score[v] == score[best_var]) { + // break tie 2: max sscore + if (sscore[v] > sscore[best_var]) + return true; + else if (sscore[v] == sscore[best_var]) { + // break tie 3: cscc + if (cscc[v] > cscc[best_var]) + return true; + else if (cscc[v] == cscc[best_var]) { + // break tie 4: oldest one + if (time_stamp[v] < time_stamp[best_var]) + return true; + } + } + } + return false; + } + + int local_search::pick_var() + { + int c, v; + int best_var = 0; + + // SAT Mode + if (m_unsat_stack.empty()) { + //++as; + for (int i = 1; i <= ob_num_terms; ++i) { + v = ob_constraint[i].var_id; + if (tie_breaker_sat(v, best_var)) + best_var = v; + } + return best_var; + } + + // Unsat Mode: CCD > RD + // CCD mode + if (!goodvar_stack.empty()) { + //++ccd; + best_var = goodvar_stack[0]; + for (unsigned i = 1; i < goodvar_stack.size(); ++i) { + v = goodvar_stack[i]; + if (tie_breaker_ccd(v, best_var)) + best_var = v; + } + return best_var; + } + + // Diversification Mode + c = m_unsat_stack[rand() % m_unsat_stack.size()]; // a random unsat constraint + // Within c, from all slack increasing var, choose the oldest one + for (unsigned i = 0; i < constraint_term[c].size(); ++i) { + v = constraint_term[c][i].var_id; + if (cur_solution[v] == constraint_term[c][i].sense && time_stamp[v] < time_stamp[best_var]) + best_var = v; + } + //++rd; + return best_var; + } + + void local_search::set_parameters() { + if (s_id == 0) + max_steps = num_vars; + else if (s_id == 1) + max_steps = (int) (1.5 * num_vars); + else if (s_id == 1) + max_steps = 2 * num_vars; + else if (s_id == 2) + max_steps = (int) (2.5 * num_vars); + else if (s_id == 3) + max_steps = 3 * num_vars; + else { + std::cout << "Invalid strategy id!" << std::endl; + exit(-1); + } + } + } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 169596888..8de3aadaa 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -30,78 +30,82 @@ namespace sat { // data structure for a term in objective function struct ob_term { - int var_id; // variable id, begin with 1 - int coefficient; // non-zero integer + int var_id; // variable id, begin with 1 + int coefficient; // non-zero integer }; // data structure for a term in constraint struct term { - int constraint_id; // constraint it belongs to - int var_id; // variable id, begin with 1 - bool sense; // 1 for positive, 0 for negative - //int coefficient; // all constraints are cardinality: coefficient=1 + int constraint_id; // constraint it belongs to + int var_id; // variable id, begin with 1 + bool sense; // 1 for positive, 0 for negative + //int coefficient; // all constraints are cardinality: coefficient=1 }; // parameters of the instance - int num_vars; // var index from 1 to num_vars - int num_constraints; // constraint index from 1 to num_constraint - int max_constraint_len; - int min_constraint_len; + int num_vars; // var index from 1 to num_vars + int num_constraints; // constraint index from 1 to num_constraint + int max_constraint_len; + int min_constraint_len; // objective function: maximize - int ob_num_terms; // how many terms are in the objective function - ob_term* ob_constraint; // the objective function *constraint*, sorting as decending order + int ob_num_terms; // how many terms are in the objective function + ob_term* ob_constraint; // the objective function *constraint*, sorting as decending order // terms arrays - vector > var_term; //var_term[i][j] means the j'th term of var i - vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i + vector > var_term; // var_term[i][j] means the j'th term of var i + vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i // information about the variable - int_vector coefficient_in_ob_constraint; // initilized to be 0 + int_vector coefficient_in_ob_constraint; // initilized to be 0 int_vector score; - int_vector sscore; // slack score + int_vector sscore; // slack score - int_vector time_stamp; // the flip time stamp - bool_vector conf_change; // whether its configure changes since its last flip - int_vector cscc; // how many times its constraint state configure changes since its last flip - vector var_neighbor; // all of its neighborhoods variable + int_vector time_stamp; // the flip time stamp + bool_vector conf_change; // whether its configure changes since its last flip + int_vector cscc; // how many times its constraint state configure changes since its last flip + vector var_neighbor; // all of its neighborhoods variable /* TBD: other scores */ // information about the constraints - int_vector constraint_k; // the right side k of a constraint + int_vector constraint_k; // the right side k of a constraint int_vector constraint_slack; // =constraint_k[i]-true_terms[i], if >=0 then sat int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing bool_vector has_true_ob_terms; // unsat constraint stack - int_vector unsat_stack; // store all the unsat constraits - int_vector index_in_unsat_stack; // which position is a contraint in the unsat_stack + int_vector m_unsat_stack; // store all the unsat constraits + int_vector m_index_in_unsat_stack; // which position is a contraint in the unsat_stack // configuration changed decreasing variables (score>0 and conf_change==true) int_vector goodvar_stack; bool_vector already_in_goodvar_stack; // information about solution - bool_vector cur_solution; // the current solution - int objective_value; // the objective function value corresponds to the current solution - bool_vector best_solution; // the best solution so far - int best_objective_value = 0; // the objective value corresponds to the best solution so far + bool_vector cur_solution; // the current solution + int objective_value; // the objective function value corresponds to the current solution + bool_vector best_solution; // the best solution so far + int best_objective_value = 0; // the objective value corresponds to the best solution so far // for non-known instance, set as maximal - int best_known_value = INT_MAX; // best known value for this instance + int best_known_value = INT_MAX; // best known value for this instance // cutoff - int cutoff_time = 1; // seconds - int max_steps = 2000000000; // < 2147483647 + int cutoff_time = 1; // seconds + int max_steps = 2000000000; // < 2147483647 // for tuning - int s_id = 0; // strategy id + int s_id = 0; // strategy id void init(); - bool_var pick_var(); - void flip(bool_var v); + void init_orig(); + void init_greedy(); + void init_cur_solution(); + int pick_var(); + void flip(int v); bool tie_breaker_sat(int, int); bool tie_breaker_ccd(int, int); + void set_parameters(); void calculate_and_update_ob(); @@ -109,6 +113,17 @@ namespace sat { void display(std::ostream& out); + void unsat(int constraint_id) { m_unsat_stack.push_back(constraint_id); } + + void sat(int c) { + int last_unsat_constraint = m_unsat_stack.back(); + m_unsat_stack.pop_back(); + int index = m_index_in_unsat_stack[c]; + // swap the deleted one with the last one and pop + m_unsat_stack[index] = last_unsat_constraint; + m_index_in_unsat_stack[last_unsat_constraint] = index; + } + public: local_search(solver& s); From eec10c6e32ec0c468d6adaf25f571ec767dfcb8d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Feb 2017 21:33:18 -0800 Subject: [PATCH 0051/1283] porting more code Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 326 ++++++++++++++++++----------------- 1 file changed, 168 insertions(+), 158 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index ed13b5a1a..22722de98 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -1,21 +1,21 @@ /*++ -Copyright (c) 2017 Microsoft Corporation + Copyright (c) 2017 Microsoft Corporation -Module Name: + Module Name: - sat_local_search.cpp + sat_local_search.cpp -Abstract: + Abstract: - Local search module for cardinality clauses. + Local search module for cardinality clauses. -Author: + Author: - Sixue Liu 2017-2-21 + Sixue Liu 2017-2-21 -Notes: + Notes: ---*/ + --*/ #include "sat_local_search.h" @@ -29,7 +29,7 @@ namespace sat { } void local_search::init_orig() { - int v, c; + int v, c; for (c = 1; c <= num_constraints; ++c) { constraint_slack[c] = constraint_k[c]; @@ -108,7 +108,7 @@ namespace sat { } void local_search::init_greedy() { - int v, c; + int v, c; for (c = 1; c <= num_constraints; ++c) { constraint_slack[c] = constraint_k[c]; } @@ -223,100 +223,110 @@ namespace sat { void local_search::flip(int flipvar) { - // already changed truth value!!!! - cur_solution[flipvar] = !cur_solution[flipvar]; + // already changed truth value!!!! + cur_solution[flipvar] = !cur_solution[flipvar]; - int v, c; - int org_flipvar_score = score[flipvar]; - int org_flipvar_sscore = sscore[flipvar]; + int v, c; + int org_flipvar_score = score[flipvar]; + int org_flipvar_sscore = sscore[flipvar]; - // update related clauses and neighbor vars - for (unsigned i = 0; i < var_term[flipvar].size(); ++i) { - c = var_term[flipvar][i].constraint_id; - if (cur_solution[flipvar] == var_term[flipvar][i].sense) { - //++true_terms_count[c]; - --constraint_slack[c]; - if (constraint_slack[c] == -2) { // from -1 to -2 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flipping the slack increasing var will no long sat this constraint - if (cur_solution[v] == constraint_term[c][j].sense) - //score[v] -= constraint_weight[c]; - --score[v]; - } - } - else if (constraint_slack[c] == -1) { // from 0 to -1: sat -> unsat - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - ++cscc[v]; - //score[v] += constraint_weight[c]; - ++score[v]; - // slack increasing var - if (cur_solution[v] == constraint_term[c][j].sense) - ++sscore[v]; - } - unsat(c); - } - else if (constraint_slack[c] == 0) { // from 1 to 0 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack decreasing var will falsify this constraint - if (cur_solution[v] != constraint_term[c][j].sense) { - //score[v] -= constraint_weight[c]; - --score[v]; - --sscore[v]; - } - } - } - } - else { // if (cur_solution[flipvar] != var_term[i].sense) - //--true_terms_count[c]; - ++constraint_slack[c]; - if (constraint_slack[c] == 1) { // from 0 to 1 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack decreasing var will no long falsify this constraint - if (cur_solution[v] != constraint_term[c][j].sense) { - //score[v] += constraint_weight[c]; - ++score[v]; - ++sscore[v]; - } - } - } - else if (constraint_slack[c] == 0) { // from -1 to 0: unsat -> sat - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - ++cscc[v]; + // update related clauses and neighbor vars + svector const& constraints = var_term[flipvar]; + unsigned num_constraints = constraints.size(); + for (unsigned i = 0; i < num_constraints; ++i) { + c = constraints[i].constraint_id; + if (cur_solution[flipvar] == constraints[i].sense) { + //++true_terms_count[c]; + --constraint_slack[c]; + switch (constraint_slack[c]) { + case -2: // from -1 to -2 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flipping the slack increasing var will no long sat this constraint + if (cur_solution[v] == constraint_term[c][j].sense) //score[v] -= constraint_weight[c]; --score[v]; - // slack increasing var no longer sat this var - if (cur_solution[v] == constraint_term[c][j].sense) - --sscore[v]; - } - sat(c); } - else if (constraint_slack[c] == -1) { // from -2 to -1 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack increasing var will satisfy this constraint - if (cur_solution[v] == constraint_term[c][j].sense) - //score[v] += constraint_weight[c]; - ++score[v]; + break; + case -1: // from 0 to -1: sat -> unsat + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + ++cscc[v]; + //score[v] += constraint_weight[c]; + ++score[v]; + // slack increasing var + if (cur_solution[v] == constraint_term[c][j].sense) + ++sscore[v]; + } + unsat(c); + break; + case 0: // from 1 to 0 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack decreasing var will falsify this constraint + if (cur_solution[v] != constraint_term[c][j].sense) { + //score[v] -= constraint_weight[c]; + --score[v]; + --sscore[v]; } } - } - } + break; + default: + break; + } + } + else { // if (cur_solution[flipvar] != var_term[i].sense) + //--true_terms_count[c]; + ++constraint_slack[c]; + switch (constraint_slack[c]) { + case 1: // from 0 to 1 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack decreasing var will no long falsify this constraint + if (cur_solution[v] != constraint_term[c][j].sense) { + //score[v] += constraint_weight[c]; + ++score[v]; + ++sscore[v]; + } + } + break; + case 0: // from -1 to 0: unsat -> sat + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + ++cscc[v]; + //score[v] -= constraint_weight[c]; + --score[v]; + // slack increasing var no longer sat this var + if (cur_solution[v] == constraint_term[c][j].sense) + --sscore[v]; + } + sat(c); + break; + case -1: // from -2 to -1 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack increasing var will satisfy this constraint + if (cur_solution[v] == constraint_term[c][j].sense) + //score[v] += constraint_weight[c]; + ++score[v]; + } + break; + default: + break; + } + } + } - score[flipvar] = -org_flipvar_score; - sscore[flipvar] = -org_flipvar_sscore; + score[flipvar] = -org_flipvar_score; + sscore[flipvar] = -org_flipvar_sscore; - conf_change[flipvar] = false; - cscc[flipvar] = 0; + conf_change[flipvar] = false; + cscc[flipvar] = 0; - /* update CCD */ - // remove the vars no longer okvar in okvar stack - // remove the vars no longer goodvar in goodvar stack - for (unsigned i = goodvar_stack.size(); i > 0;) { + /* update CCD */ + // remove the vars no longer okvar in okvar stack + // remove the vars no longer goodvar in goodvar stack + for (unsigned i = goodvar_stack.size(); i > 0;) { --i; v = goodvar_stack[i]; if (score[v] <= 0) { @@ -324,69 +334,69 @@ namespace sat { goodvar_stack.pop_back(); already_in_goodvar_stack[v] = false; } - } - // update all flipvar's neighbor's conf_change to true, add goodvar/okvar - for (unsigned i = 0; i < var_neighbor[flipvar].size(); ++i) { + } + // update all flipvar's neighbor's conf_change to true, add goodvar/okvar + for (unsigned i = 0; i < var_neighbor[flipvar].size(); ++i) { v = var_neighbor[flipvar][i]; conf_change[v] = true; if (score[v] > 0 && !already_in_goodvar_stack[v]) { goodvar_stack.push_back(v); already_in_goodvar_stack[v] = true; } - } + } } bool local_search::tie_breaker_sat(int v, int best_var) { - // most improvement on objective value - int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint[v] : coefficient_in_ob_constraint[v]; - int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint[best_var] : coefficient_in_ob_constraint[best_var]; - // break tie 1: max imp - if (v_imp > b_imp) - return true; - else if (v_imp == b_imp) { - // break tie 2: conf_change - if (conf_change[v] && !conf_change[best_var]) - return true; - else if (conf_change[v] == conf_change[best_var]) { - // break tie 3: time_stamp - if (time_stamp[v] < time_stamp[best_var]) - return true; - } - } - return false; + // most improvement on objective value + int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint[v] : coefficient_in_ob_constraint[v]; + int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint[best_var] : coefficient_in_ob_constraint[best_var]; + // break tie 1: max imp + if (v_imp > b_imp) + return true; + else if (v_imp == b_imp) { + // break tie 2: conf_change + if (conf_change[v] && !conf_change[best_var]) + return true; + else if (conf_change[v] == conf_change[best_var]) { + // break tie 3: time_stamp + if (time_stamp[v] < time_stamp[best_var]) + return true; + } + } + return false; } bool local_search::tie_breaker_ccd(int v, int best_var) { - // break tie 1: max score - if (score[v] > score[best_var]) - return true; - else if (score[v] == score[best_var]) { - // break tie 2: max sscore - if (sscore[v] > sscore[best_var]) - return true; - else if (sscore[v] == sscore[best_var]) { - // break tie 3: cscc - if (cscc[v] > cscc[best_var]) - return true; - else if (cscc[v] == cscc[best_var]) { - // break tie 4: oldest one - if (time_stamp[v] < time_stamp[best_var]) - return true; - } - } - } - return false; + // break tie 1: max score + if (score[v] > score[best_var]) + return true; + else if (score[v] == score[best_var]) { + // break tie 2: max sscore + if (sscore[v] > sscore[best_var]) + return true; + else if (sscore[v] == sscore[best_var]) { + // break tie 3: cscc + if (cscc[v] > cscc[best_var]) + return true; + else if (cscc[v] == cscc[best_var]) { + // break tie 4: oldest one + if (time_stamp[v] < time_stamp[best_var]) + return true; + } + } + } + return false; } int local_search::pick_var() { - int c, v; - int best_var = 0; + int c, v; + int best_var = 0; - // SAT Mode - if (m_unsat_stack.empty()) { + // SAT Mode + if (m_unsat_stack.empty()) { //++as; for (int i = 1; i <= ob_num_terms; ++i) { v = ob_constraint[i].var_id; @@ -394,11 +404,11 @@ namespace sat { best_var = v; } return best_var; - } + } - // Unsat Mode: CCD > RD - // CCD mode - if (!goodvar_stack.empty()) { + // Unsat Mode: CCD > RD + // CCD mode + if (!goodvar_stack.empty()) { //++ccd; best_var = goodvar_stack[0]; for (unsigned i = 1; i < goodvar_stack.size(); ++i) { @@ -407,35 +417,35 @@ namespace sat { best_var = v; } return best_var; - } + } - // Diversification Mode - c = m_unsat_stack[rand() % m_unsat_stack.size()]; // a random unsat constraint - // Within c, from all slack increasing var, choose the oldest one - for (unsigned i = 0; i < constraint_term[c].size(); ++i) { + // Diversification Mode + c = m_unsat_stack[rand() % m_unsat_stack.size()]; // a random unsat constraint + // Within c, from all slack increasing var, choose the oldest one + for (unsigned i = 0; i < constraint_term[c].size(); ++i) { v = constraint_term[c][i].var_id; if (cur_solution[v] == constraint_term[c][i].sense && time_stamp[v] < time_stamp[best_var]) best_var = v; - } - //++rd; - return best_var; + } + //++rd; + return best_var; } void local_search::set_parameters() { - if (s_id == 0) + if (s_id == 0) max_steps = num_vars; - else if (s_id == 1) + else if (s_id == 1) max_steps = (int) (1.5 * num_vars); - else if (s_id == 1) + else if (s_id == 1) max_steps = 2 * num_vars; - else if (s_id == 2) + else if (s_id == 2) max_steps = (int) (2.5 * num_vars); - else if (s_id == 3) + else if (s_id == 3) max_steps = 3 * num_vars; - else { + else { std::cout << "Invalid strategy id!" << std::endl; exit(-1); - } + } } From d8bb10d37f5adb2cca62bffda949a4422d907465 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Feb 2017 22:43:23 -0800 Subject: [PATCH 0052/1283] porting more code Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 346 ++++++++++++++++++----------------- src/sat/sat_local_search.h | 43 +++-- src/sat/sat_solver.h | 1 + 3 files changed, 201 insertions(+), 189 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 22722de98..95f021537 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -18,6 +18,7 @@ --*/ #include "sat_local_search.h" +#include "sat_solver.h" namespace sat { @@ -28,12 +29,68 @@ namespace sat { init_greedy(); } - void local_search::init_orig() { - int v, c; - - for (c = 1; c <= num_constraints; ++c) { - constraint_slack[c] = constraint_k[c]; + void local_search::init_cur_solution() { + for (unsigned v = 1; v <= num_vars; ++v) { + cur_solution[v] = (rand() % 2 == 1); } + } + + // figure out slack, and init unsat stack + void local_search::init_slack() { + for (unsigned c = 1; c <= num_constraints; ++c) { + for (unsigned i = 0; i < constraint_term[c].size(); ++i) { + unsigned v = constraint_term[c][i].var_id; + if (cur_solution[v] == constraint_term[c][i].sense) + --constraint_slack[c]; + } + // constraint_slack[c] = constraint_k[c] - true_terms_count[c]; + // violate the at-most-k constraint + if (constraint_slack[c] < 0) + unsat(c); + } + } + + // figure out variables scores, pscores and sscores + void local_search::init_scores() { + for (unsigned v = 1; v <= num_vars; ++v) { + for (unsigned i = 0; i < var_term[v].size(); ++i) { + int c = var_term[v][i].constraint_id; + if (cur_solution[v] != var_term[v][i].sense) { + // will ++true_terms_count[c] + // will --slack + if (constraint_slack[c] <= 0) { + --sscore[v]; + if (constraint_slack[c] == 0) + --score[v]; + } + } + else { // if (cur_solution[v] == var_term[v][i].sense) + // will --true_terms_count[c] + // will ++slack + if (constraint_slack[c] <= -1) { + ++sscore[v]; + if (constraint_slack[c] == -1) + ++score[v]; + } + } + } + } + } + + // init goodvars and okvars stack + void local_search::init_goodvars() { + goodvar_stack.reset(); + already_in_goodvar_stack.resize(num_vars+1, false); + for (unsigned v = 1; v <= num_vars; ++v) { + if (score[v] > 0) { // && conf_change[v] == true + already_in_goodvar_stack[v] = true; + goodvar_stack.push_back(v); + } + } + } + + void local_search::init_orig() { + constraint_slack = constraint_k; // init unsat stack m_unsat_stack.reset(); @@ -49,69 +106,14 @@ namespace sat { time_stamp.resize(num_vars+1, 0); time_stamp[0] = max_steps; conf_change.resize(num_vars+1, true); conf_change[0] = false; cscc.resize(num_vars+1, 1); cscc[0] = 0; - - // figure out slack, and init unsat stack - for (c = 1; c <= num_constraints; ++c) { - for (unsigned i = 0; i < constraint_term[c].size(); ++i) { - v = constraint_term[c][i].var_id; - if (cur_solution[v] == constraint_term[c][i].sense) - --constraint_slack[c]; - } - // constraint_slack[c] = constraint_k[c] - true_terms_count[c]; - // violate the at-most-k constraint - if (constraint_slack[c] < 0) - unsat(c); - } - - // figure out variables scores, pscores and sscores - for (v = 1; v <= num_vars; ++v) { - for (unsigned i = 0; i < var_term[v].size(); ++i) { - c = var_term[v][i].constraint_id; - if (cur_solution[v] != var_term[v][i].sense) { - // will ++true_terms_count[c] - // will --slack - if (constraint_slack[c] <= 0) { - --sscore[v]; - if (constraint_slack[c] == 0) - --score[v]; - } - } - else { // if (cur_solution[v] == var_term[v][i].sense) - // will --true_terms_count[c] - // will ++slack - if (constraint_slack[c] <= -1) { - ++sscore[v]; - if (constraint_slack[c] == -1) - ++score[v]; - } - } - } - } - - // TBD: maybe use util\uint_set or tracked_uint_set instead? - - // init goodvars and okvars stack - for (v = 1; v <= num_vars; ++v) { - if (score[v] > 0) { // && conf_change[v] == true - already_in_goodvar_stack[v] = true; - goodvar_stack.push_back(v); - } - else - already_in_goodvar_stack[v] = false; - } - } - void local_search::init_cur_solution() { - for (int v = 1; v <= num_vars; ++v) { - cur_solution[v] = (rand() % 2 == 1); - } + init_slack(); + init_scores(); + init_goodvars(); } void local_search::init_greedy() { - int v, c; - for (c = 1; c <= num_constraints; ++c) { - constraint_slack[c] = constraint_k[c]; - } + constraint_slack = constraint_k; // init unsat stack m_unsat_stack.reset(); @@ -121,74 +123,21 @@ namespace sat { // init varibale information // variable 0 is the virtual variable - score[0] = INT_MIN; - sscore[0] = INT_MIN; - time_stamp[0] = max_steps; - conf_change[0] = false; - cscc[0] = 0; - for (v = 1; v <= num_vars; ++v) { - score[v] = 0; - sscore[v] = 0; - time_stamp[v] = 0; - conf_change[v] = true; - cscc[v] = 1; + + score.resize(num_vars+1, 0); score[0] = INT_MIN; + sscore.resize(num_vars+1, 0); sscore[0] = INT_MIN; + time_stamp.resize(num_vars+1, 0); time_stamp[0] = max_steps; + conf_change.resize(num_vars+1, true); conf_change[0] = false; + cscc.resize(num_vars+1, 1); cscc[0] = 0; + for (unsigned v = 1; v <= num_vars; ++v) { // greedy here!! - if (coefficient_in_ob_constraint[v] > 0) { - cur_solution[v] = true; - } - else if (coefficient_in_ob_constraint[v] < 0) { - cur_solution[v] = false; - } - } - - // figure out slack, and init unsat stack - for (c = 1; c <= num_constraints; ++c) { - for (unsigned i = 0; i < constraint_term[c].size(); ++i) { - v = constraint_term[c][i].var_id; - if (cur_solution[v] == constraint_term[c][i].sense) - //++true_terms_count[c]; - --constraint_slack[c]; - } - //constraint_slack[c] = constraint_k[c] - true_terms_count[c]; - // violate the at-most-k constraint - if (constraint_slack[c] < 0) - unsat(c); - } - - // figure out variables scores, pscores and sscores - for (v = 1; v <= num_vars; ++v) { - for (unsigned i = 0; i < var_term[v].size(); ++i) { - c = var_term[v][i].constraint_id; - if (cur_solution[v] != var_term[v][i].sense) { - // will ++true_terms_count[c] - // will --slack - if (constraint_slack[c] <= 0) { - --sscore[v]; - if (constraint_slack[c] == 0) - --score[v]; - } - } - else { // if (cur_solution[v] == var_term[v][i].sense) - // will --true_terms_count[c] - // will ++slack - if (constraint_slack[c] <= -1) { - ++sscore[v]; - if (constraint_slack[c] == -1) - ++score[v]; - } - } - } - } - - // init goodvars and okvars stack - for (v = 1; v <= num_vars; ++v) { - if (score[v] > 0) { // && conf_change[v] == true - already_in_goodvar_stack[v] = true; - goodvar_stack.push_back(v); - } - else - already_in_goodvar_stack[v] = false; + if (coefficient_in_ob_constraint[v] != 0) + cur_solution[v] = (coefficient_in_ob_constraint[v] > 0); } + + init_slack(); + init_scores(); + init_goodvars(); } @@ -206,6 +155,75 @@ namespace sat { local_search::local_search(solver& s) { + // TBD: use solver::copy as a guideline for importing state from a solver. + + // TBD initialize variables + s.num_vars(); + + // copy units + unsigned trail_sz = s.init_trail_size(); + for (unsigned i = 0; i < trail_sz; ++i) { + unsigned id = constraint_term.size(); + term t; + t.constraint_id = id; + t.var_id = s.m_trail[i].var(); + t.sense = s.m_trail[i].sign(); + var_term[t.var_id].push_back(t); + constraint_term.push_back(svector()); + constraint_term[id].push_back(t); + constraint_k.push_back(0); + } + + // TBD copy binary: + s.m_watches.size(); + { + unsigned sz = s.m_watches.size(); + for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { + literal l = ~to_literal(l_idx); + watch_list const & wlist = s.m_watches[l_idx]; + watch_list::const_iterator it = wlist.begin(); + watch_list::const_iterator end = wlist.end(); + for (; it != end; ++it) { + if (!it->is_binary_non_learned_clause()) + continue; + literal l2 = it->get_literal(); + if (l.index() > l2.index()) + continue; + + unsigned id = constraint_term.size(); + constraint_term.push_back(svector()); + + // TBD: add clause l, l2; + + constraint_k.push_back(1); + } + } + } + + + clause_vector::const_iterator it = s.m_clauses.begin(); + clause_vector::const_iterator end = s.m_clauses.end(); + for (; it != end; ++it) { + clause const& c = *(*it); + unsigned sz = c.size(); + unsigned id = constraint_term.size(); + constraint_term.push_back(svector()); + for (unsigned i = 0; i < sz; ++i) { + term t; + t.constraint_id = id; + t.var_id = c[i].var(); + t.sense = c[i].sign(); + var_term[t.var_id].push_back(t); + constraint_term[id].push_back(t); + } + constraint_k.push_back(sz-1); + } + + // TBD initialize cardinalities from m_ext, retrieve cardinality constraints. + // optionally handle xor constraints. + + num_vars = s.num_vars(); + num_constraints = constraint_term.size(); } local_search::~local_search() { @@ -221,12 +239,12 @@ namespace sat { } - void local_search::flip(int flipvar) + void local_search::flip(bool_var flipvar) { // already changed truth value!!!! cur_solution[flipvar] = !cur_solution[flipvar]; - int v, c; + unsigned v, c; int org_flipvar_score = score[flipvar]; int org_flipvar_sscore = sscore[flipvar]; @@ -346,59 +364,45 @@ namespace sat { } } - bool local_search::tie_breaker_sat(int v, int best_var) - { + bool local_search::tie_breaker_sat(bool_var v, bool_var best_var) { // most improvement on objective value int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint[v] : coefficient_in_ob_constraint[v]; int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint[best_var] : coefficient_in_ob_constraint[best_var]; // break tie 1: max imp - if (v_imp > b_imp) - return true; - else if (v_imp == b_imp) { - // break tie 2: conf_change - if (conf_change[v] && !conf_change[best_var]) - return true; - else if (conf_change[v] == conf_change[best_var]) { - // break tie 3: time_stamp - if (time_stamp[v] < time_stamp[best_var]) - return true; - } - } - return false; + // break tie 2: conf_change + // break tie 3: time_stamp + + return + (v_imp > b_imp) || + ((v_imp == b_imp) && + ((conf_change[v] && !conf_change[best_var]) || + ((conf_change[v] == conf_change[best_var]) && + (time_stamp[v] < time_stamp[best_var])))); } - bool local_search::tie_breaker_ccd(int v, int best_var) - { + bool local_search::tie_breaker_ccd(bool_var v, bool_var best_var) { // break tie 1: max score - if (score[v] > score[best_var]) - return true; - else if (score[v] == score[best_var]) { - // break tie 2: max sscore - if (sscore[v] > sscore[best_var]) - return true; - else if (sscore[v] == sscore[best_var]) { - // break tie 3: cscc - if (cscc[v] > cscc[best_var]) - return true; - else if (cscc[v] == cscc[best_var]) { - // break tie 4: oldest one - if (time_stamp[v] < time_stamp[best_var]) - return true; - } - } - } - return false; + // break tie 2: max sscore + // break tie 3: cscc + // break tie 4: oldest one + return + (score[v] > score[best_var]) || + ((score[v] == score[best_var]) && + (sscore[v] > sscore[best_var]) || + ((sscore[v] == sscore[best_var]) && + (cscc[v] > cscc[best_var]) || + ((cscc[v] == cscc[best_var]) && + (time_stamp[v] < time_stamp[best_var])))); } - int local_search::pick_var() - { + bool_var local_search::pick_var() { int c, v; - int best_var = 0; + bool_var best_var = null_bool_var; // SAT Mode if (m_unsat_stack.empty()) { //++as; - for (int i = 1; i <= ob_num_terms; ++i) { + for (unsigned i = 0; i < ob_constraint.size(); ++i) { v = ob_constraint[i].var_id; if (tie_breaker_sat(v, best_var)) best_var = v; diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 8de3aadaa..565180976 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -43,14 +43,11 @@ namespace sat { }; // parameters of the instance - int num_vars; // var index from 1 to num_vars - int num_constraints; // constraint index from 1 to num_constraint - int max_constraint_len; - int min_constraint_len; + unsigned num_vars; // var index from 1 to num_vars + unsigned num_constraints; // constraint index from 1 to num_constraint // objective function: maximize - int ob_num_terms; // how many terms are in the objective function - ob_term* ob_constraint; // the objective function *constraint*, sorting as decending order + svector ob_constraint; // the objective function *constraint*, sorted in decending order // terms arrays @@ -58,14 +55,14 @@ namespace sat { vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i // information about the variable - int_vector coefficient_in_ob_constraint; // initilized to be 0 + int_vector coefficient_in_ob_constraint; // initialized to be 0 int_vector score; - int_vector sscore; // slack score + int_vector sscore; // slack score - int_vector time_stamp; // the flip time stamp - bool_vector conf_change; // whether its configure changes since its last flip - int_vector cscc; // how many times its constraint state configure changes since its last flip - vector var_neighbor; // all of its neighborhoods variable + int_vector time_stamp; // the flip time stamp + bool_vector conf_change; // whether its configure changes since its last flip + int_vector cscc; // how many times its constraint state configure changes since its last flip + vector var_neighbor; // all of its neighborhoods variable /* TBD: other scores */ // information about the constraints @@ -81,6 +78,7 @@ namespace sat { // configuration changed decreasing variables (score>0 and conf_change==true) int_vector goodvar_stack; bool_vector already_in_goodvar_stack; + // information about solution bool_vector cur_solution; // the current solution int objective_value; // the objective function value corresponds to the current solution @@ -97,13 +95,22 @@ namespace sat { int s_id = 0; // strategy id void init(); + void init_orig(); void init_greedy(); + void init_cur_solution(); - int pick_var(); - void flip(int v); - bool tie_breaker_sat(int, int); - bool tie_breaker_ccd(int, int); + void init_slack(); + void init_scores(); + void init_goodvars(); + + bool_var pick_var(); + + void flip(bool_var v); + + bool tie_breaker_sat(bool_var v1, bool_var v2); + + bool tie_breaker_ccd(bool_var v1, bool_var v2); void set_parameters(); @@ -115,13 +122,13 @@ namespace sat { void unsat(int constraint_id) { m_unsat_stack.push_back(constraint_id); } + // swap the deleted one with the last one and pop void sat(int c) { int last_unsat_constraint = m_unsat_stack.back(); - m_unsat_stack.pop_back(); int index = m_index_in_unsat_stack[c]; - // swap the deleted one with the last one and pop m_unsat_stack[index] = last_unsat_constraint; m_index_in_unsat_stack[last_unsat_constraint] = index; + m_unsat_stack.pop_back(); } public: diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 9393a8e10..bc24f2fde 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -155,6 +155,7 @@ namespace sat { friend class card_extension; friend class parallel; friend class lookahead; + friend class local_search; friend struct mk_stat; public: solver(params_ref const & p, reslimit& l); From 748ada2acc2323296742c8be0e1e2cccda7d0bd5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Feb 2017 11:46:47 -0800 Subject: [PATCH 0053/1283] adding unit test entry point Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/test/CMakeLists.txt | 1 + src/api/api_opt.cpp | 1 - src/sat/card_extension.cpp | 13 ++- src/sat/card_extension.h | 6 ++ src/sat/sat_local_search.cpp | 143 ++++++++++++++++++-------- src/sat/sat_local_search.h | 4 + src/test/main.cpp | 1 + src/test/sat_local_search.cpp | 136 ++++++++++++++++++++++++ 8 files changed, 260 insertions(+), 45 deletions(-) create mode 100644 src/test/sat_local_search.cpp diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index 7ea5f4589..0f756ce2c 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -92,6 +92,7 @@ add_executable(test-z3 rational.cpp rcf.cpp region.cpp + sat_local_search.cpp sat_lookahead.cpp sat_user_scope.cpp simple_parser.cpp diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 6fbc86ab6..32f0d1003 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -129,7 +129,6 @@ extern "C" { cancel_eh eh(mk_c(c)->m().limit()); unsigned timeout = to_optimize_ptr(o)->get_params().get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = mk_c(c)->get_rlimit(); - std::cout << "Timeout: " << timeout << "\n"; api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index fd8986cae..4b46b6da1 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -741,9 +741,16 @@ namespace sat { unsigned index = 2*m_cards.size(); card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, literal(v, false), lits, k); m_cards.push_back(c); - init_watch(v); - m_var_infos[v].m_card = c; - m_var_trail.push_back(v); + if (v == null_bool_var) { + // it is an axiom. + init_watch(*c, true); + m_card_axioms.push_back(c); + } + else { + init_watch(v); + m_var_infos[v].m_card = c; + m_var_trail.push_back(v); + } } void card_extension::add_xor(bool_var v, literal_vector const& lits) { diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 4e0c10cd2..1c4aac29b 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -21,10 +21,14 @@ Revision History: #include"sat_extension.h" #include"sat_solver.h" +#include"scoped_ptr_vector.h" namespace sat { class card_extension : public extension { + + friend class local_search; + struct stats { unsigned m_num_propagations; unsigned m_num_conflicts; @@ -118,6 +122,8 @@ namespace sat { ptr_vector m_cards; ptr_vector m_xors; + scoped_ptr_vector m_card_axioms; + // watch literals svector m_var_infos; unsigned_vector m_var_trail; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 95f021537..87f0c379f 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -19,6 +19,7 @@ #include "sat_local_search.h" #include "sat_solver.h" +#include "card_extension.h" namespace sat { @@ -153,29 +154,32 @@ namespace sat { } + void local_search::add_clause(unsigned sz, literal const* c) { + add_cardinality(sz, c, sz - 1); + } + + void local_search::add_cardinality(unsigned sz, literal const* c, unsigned k) { + unsigned id = constraint_term.size(); + constraint_term.push_back(svector()); + for (unsigned i = 0; i < sz; ++i) { + term t; + t.constraint_id = id; + t.var_id = c[i].var(); + t.sense = c[i].sign(); + var_term[t.var_id].push_back(t); + constraint_term[id].push_back(t); + } + constraint_k.push_back(k); + } + local_search::local_search(solver& s) { - - // TBD: use solver::copy as a guideline for importing state from a solver. - - // TBD initialize variables - s.num_vars(); - // copy units unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { - unsigned id = constraint_term.size(); - term t; - t.constraint_id = id; - t.var_id = s.m_trail[i].var(); - t.sense = s.m_trail[i].sign(); - var_term[t.var_id].push_back(t); - constraint_term.push_back(svector()); - constraint_term[id].push_back(t); - constraint_k.push_back(0); + add_clause(1, s.m_trail.c_ptr() + i); } - // TBD copy binary: - s.m_watches.size(); + // copy binary clauses { unsigned sz = s.m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { @@ -189,45 +193,62 @@ namespace sat { literal l2 = it->get_literal(); if (l.index() > l2.index()) continue; - - unsigned id = constraint_term.size(); - constraint_term.push_back(svector()); - - // TBD: add clause l, l2; - - constraint_k.push_back(1); + literal ls[2] = { l, l2 }; + add_clause(2, ls); } } } - + // copy clauses clause_vector::const_iterator it = s.m_clauses.begin(); clause_vector::const_iterator end = s.m_clauses.end(); for (; it != end; ++it) { - clause const& c = *(*it); - unsigned sz = c.size(); - unsigned id = constraint_term.size(); - constraint_term.push_back(svector()); - for (unsigned i = 0; i < sz; ++i) { - term t; - t.constraint_id = id; - t.var_id = c[i].var(); - t.sense = c[i].sign(); - var_term[t.var_id].push_back(t); - constraint_term[id].push_back(t); - } - constraint_k.push_back(sz-1); + clause& c = *(*it); + add_clause(c.size(), c.begin()); + } + + // copy cardinality clauses + card_extension* ext = dynamic_cast(s.get_extension()); + if (ext) { + literal_vector lits; + unsigned sz = ext->m_cards.size(); + for (unsigned i = 0; i < sz; ++i) { + card_extension::card& c = *ext->m_cards[i]; + unsigned n = c.size(); + unsigned k = c.k(); + + // c.lit() <=> c.lits() >= k + // + // (c.lits() < k) or c.lit() + // = (c.lits() + (n - k - 1)*~c.lit()) <= n + // + // ~c.lit() or (c.lits() >= k) + // = ~c.lit() or (~c.lits() <= n - k) + // = k*c.lit() + ~c.lits() <= n + // + + lits.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]); + for (unsigned j = 0; j < n - k - 1; ++j) lits.push_back(~c.lit()); + add_cardinality(lits.size(), lits.c_ptr(), n); + + lits.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]); + for (unsigned j = 0; j < k; ++j) lits.push_back(c.lit()); + add_cardinality(lits.size(), lits.c_ptr(), n); + } + // + // optionally handle xor constraints. + // + SASSERT(ext->m_xors.empty()); } - // TBD initialize cardinalities from m_ext, retrieve cardinality constraints. - // optionally handle xor constraints. num_vars = s.num_vars(); num_constraints = constraint_term.size(); } local_search::~local_search() { - } void local_search::add_soft(literal l, double weight) { @@ -235,6 +256,46 @@ namespace sat { } lbool local_search::operator()() { + bool reach_cutoff_time = false; + bool reach_known_best_value = false; + bool_var flipvar; + double elapsed_time = 0; + clock_t start = clock(), stop; // TBD, use stopwatch facility + srand(0); // TBD, use random facility and parameters to set random seed. + set_parameters(); + // ################## start ###################### + //cout << "Start initialize and local search, restart in every " << max_steps << " steps" << endl; + for (unsigned tries = 0; ; ++tries) { + init(); + for (int step = 1; step <= max_steps; ++step) { + // feasible + if (m_unsat_stack.empty()) { + calculate_and_update_ob(); + if (best_objective_value >= best_known_value) { + reach_known_best_value = true; + break; + } + } + flipvar = pick_var(); + flip(flipvar); + time_stamp[flipvar] = step; + } + // take a look at watch + stop = clock(); + elapsed_time = (double)(stop - start) / CLOCKS_PER_SEC; + if (elapsed_time > cutoff_time) + reach_cutoff_time = true; + if (reach_known_best_value || reach_cutoff_time) + break; + } + if (reach_known_best_value) { + std::cout << elapsed_time << "\n"; + } + else + std::cout << -1 << "\n"; + //print_solution(); + + // TBD: adjust return status return l_undef; } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 565180976..12f3c3756 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -122,6 +122,10 @@ namespace sat { void unsat(int constraint_id) { m_unsat_stack.push_back(constraint_id); } + void add_clause(unsigned sz, literal const* c); + + void add_cardinality(unsigned sz, literal const* c, unsigned k); + // swap the deleted one with the last one and pop void sat(int c) { int last_unsat_constraint = m_unsat_stack.back(); diff --git a/src/test/main.cpp b/src/test/main.cpp index 18b83e90e..6e7b60152 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -230,6 +230,7 @@ int main(int argc, char ** argv) { TST(get_consequences); TST(pb2bv); TST_ARGV(sat_lookahead); + TST_ARGV(sat_local_search); //TST_ARGV(hs); } diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp new file mode 100644 index 000000000..1d92b37c7 --- /dev/null +++ b/src/test/sat_local_search.cpp @@ -0,0 +1,136 @@ +#include "sat_local_search.h" +#include "sat_solver.h" + +static int build_instance(char *filename, sat::solver& s, sat::local_search& ls) +{ + char line[16383]; + int cur_term; + // for temperally storage + int temp[16383]; + int temp_count; + + std::ifstream infile(filename); + //if (infile == NULL) //linux + if (!infile) + return 0; + infile.getline(line, 16383); + int num_vars, num_constraints; + sscanf_s(line, "%d %d", &num_vars, &num_constraints); + //cout << "number of variables: " << num_vars << endl; + //cout << "number of constraints: " << num_constraints << endl; + + + // write in the objective function + temp_count = 0; + infile >> cur_term; + while (cur_term != 0) { + temp[temp_count++] = cur_term; + infile >> cur_term; + } + int ob_num_terms = temp_count; + +#if 0 + TBD make this compile: + ob_constraint = new ob_term[ob_num_terms + 1]; + // coefficient + ob_constraint[0].coefficient = 0; // virtual var: all variables not in ob are pointed to this var + for (i = 1; i <= ob_num_terms; ++i) { + ob_constraint[i].coefficient = temp[i - 1]; + } + + sat::literal_vector lits; + // ob variable + temp_count = 0; + infile >> cur_term; + while (cur_term != 0) { + temp[temp_count++] = cur_term; + infile >> cur_term; + } + if (temp_count != ob_num_terms) { + cout << "Objective function format error." << endl; + exit(-1); + } + for (i = 1; i <= ob_num_terms; ++i) { + ob_constraint[i].var_id = temp[i - 1]; + coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient; + } + // read the constraints, one at a time + card_extension* ext = 0; + int k; + for (c = 1; c <= num_constraints; ++c) { + lits.reset(); + infile >> cur_term; + while (cur_term != 0) { + lits.push_back(sat::literal(abs(cur_term), cur_term > 0)); + infile >> cur_term; + } + infile >> k; + ext->add_at_least(null_bool_var, lits, lits.size() - k); + } +#endif + + infile.close(); + + +#if 0 + Move all of this to initialization code for local search solver: + + // create var_term array + for (v = 1; v <= num_vars; ++v) { + var_term[v] = new term[var_term_count[v]]; + var_term_count[v] = 0; // reset to 0, for building up the array + } + // scan all constraints to build up var term arrays + for (c = 1; c <= num_constraints; ++c) { + for (i = 0; i < constraint_term_count[c]; ++i) { + v = constraint_term[c][i].var_id; + var_term[v][var_term_count[v]++] = constraint_term[c][i]; + } + } + + + // build neighborhood relationship + bool *is_neighbor; + is_neighbor = new bool[num_vars + 1]; + for (v = 1; v <= num_vars; ++v) { + // init as not neighbor + for (i = 1; i <= num_vars; ++i) { + is_neighbor[i] = false; + } + temp_count = 0; + // for each constraint v appears + for (i = 0; i < var_term_count[v]; ++i) { + c = var_term[v][i].constraint_id; + for (j = 0; j < constraint_term_count[c]; ++j) { + if (constraint_term[c][j].var_id == v) + continue; + // not neighbor yet + if (!is_neighbor[constraint_term[c][j].var_id]) { + is_neighbor[constraint_term[c][j].var_id] = true; + temp[temp_count++] = constraint_term[c][j].var_id; + } + } + } + // create and build neighbor + var_neighbor_count[v] = temp_count; + var_neighbor[v] = new int[var_neighbor_count[v]]; + for (i = 0; i < var_neighbor_count[v]; ++i) { + var_neighbor[v][i] = temp[i]; + } + } + delete[] is_neighbor; + +#endif + return 1; +} + +void tst_sat_local_search(char ** argv, int argc, int& i) { + if (argc != i + 2) { + std::cout << "require dimacs file name\n"; + return; + } + // sat::solver s; + // populate the sat solver with clauses and cardinality consrtaints from the input + // call the lookahead solver. + // TBD +} From 43ddad0ecdb776e80e693765d5f7c4b538f98129 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Feb 2017 14:57:25 -0800 Subject: [PATCH 0054/1283] initial pass Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 3 +- src/sat/sat_local_search.cpp | 130 +++++++++++++++++++++------------- src/sat/sat_local_search.h | 19 +++-- src/sat/tactic/goal2sat.cpp | 5 +- src/test/sat_local_search.cpp | 130 +++++++++++----------------------- 5 files changed, 139 insertions(+), 148 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 4b46b6da1..e0bb04c10 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -739,7 +739,8 @@ namespace sat { void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { unsigned index = 2*m_cards.size(); - card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, literal(v, false), lits, k); + literal lit = v == null_bool_var ? null_literal : literal(v, false); + card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); m_cards.push_back(c); if (v == null_bool_var) { // it is an axiom. diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 87f0c379f..84e1355b1 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -24,21 +24,40 @@ namespace sat { void local_search::init() { - constraint_slack.resize(num_constraints + 1); - cur_solution.resize(num_vars + 1); - // etc. initialize other vectors. - init_greedy(); + constraint_slack.resize(num_constraints(), 0); + cur_solution.resize(num_vars(), false); + m_index_in_unsat_stack.resize(num_constraints(), 0); + coefficient_in_ob_constraint.resize(num_vars(), 0); + var_neighbor.reset(); + for (bool_var v = 0; v < num_vars(); ++v) { + bool_vector is_neighbor(num_vars(), false); + var_neighbor.push_back(bool_var_vector()); + for (unsigned i = 0; i < var_term[v].size(); ++ i) { + unsigned c = var_term[v][i].constraint_id; + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + bool_var w = constraint_term[c][j].var_id; + if (w == v || is_neighbor[w]) continue; + is_neighbor[w] = true; + var_neighbor.back().push_back(w); + } + } + } + } + + void local_search::reinit() { + reinit_greedy(); } void local_search::init_cur_solution() { - for (unsigned v = 1; v <= num_vars; ++v) { + cur_solution.resize(num_vars() + 1, false); + for (unsigned v = 0; v < num_vars(); ++v) { cur_solution[v] = (rand() % 2 == 1); } } // figure out slack, and init unsat stack void local_search::init_slack() { - for (unsigned c = 1; c <= num_constraints; ++c) { + for (unsigned c = 0; c < num_constraints(); ++c) { for (unsigned i = 0; i < constraint_term[c].size(); ++i) { unsigned v = constraint_term[c][i].var_id; if (cur_solution[v] == constraint_term[c][i].sense) @@ -53,7 +72,7 @@ namespace sat { // figure out variables scores, pscores and sscores void local_search::init_scores() { - for (unsigned v = 1; v <= num_vars; ++v) { + for (unsigned v = 0; v < num_vars(); ++v) { for (unsigned i = 0; i < var_term[v].size(); ++i) { int c = var_term[v][i].constraint_id; if (cur_solution[v] != var_term[v][i].sense) { @@ -81,8 +100,8 @@ namespace sat { // init goodvars and okvars stack void local_search::init_goodvars() { goodvar_stack.reset(); - already_in_goodvar_stack.resize(num_vars+1, false); - for (unsigned v = 1; v <= num_vars; ++v) { + already_in_goodvar_stack.resize(num_vars(), false); + for (unsigned v = 0; v < num_vars(); ++v) { if (score[v] > 0) { // && conf_change[v] == true already_in_goodvar_stack[v] = true; goodvar_stack.push_back(v); @@ -90,7 +109,7 @@ namespace sat { } } - void local_search::init_orig() { + void local_search::reinit_orig() { constraint_slack = constraint_k; // init unsat stack @@ -102,18 +121,24 @@ namespace sat { // init varibale information // variable 0 is the virtual variable - score.resize(num_vars+1, 0); score[0] = INT_MIN; - sscore.resize(num_vars+1, 0); sscore[0] = INT_MIN; - time_stamp.resize(num_vars+1, 0); time_stamp[0] = max_steps; - conf_change.resize(num_vars+1, true); conf_change[0] = false; - cscc.resize(num_vars+1, 1); cscc[0] = 0; + score.reset(); + sscore.reset(); + time_stamp.reset(); + conf_change.reset(); + cscc.reset(); + + score.resize(num_vars(), 0); score[0] = INT_MIN; + sscore.resize(num_vars(), 0); sscore[0] = INT_MIN; + time_stamp.resize(num_vars(), 0); time_stamp[0] = max_steps; + conf_change.resize(num_vars(), true); conf_change[0] = false; + cscc.resize(num_vars(), 1); cscc[0] = 0; init_slack(); init_scores(); init_goodvars(); } - void local_search::init_greedy() { + void local_search::reinit_greedy() { constraint_slack = constraint_k; // init unsat stack @@ -125,14 +150,20 @@ namespace sat { // init varibale information // variable 0 is the virtual variable - score.resize(num_vars+1, 0); score[0] = INT_MIN; - sscore.resize(num_vars+1, 0); sscore[0] = INT_MIN; - time_stamp.resize(num_vars+1, 0); time_stamp[0] = max_steps; - conf_change.resize(num_vars+1, true); conf_change[0] = false; - cscc.resize(num_vars+1, 1); cscc[0] = 0; - for (unsigned v = 1; v <= num_vars; ++v) { + score.reset(); + sscore.reset(); + time_stamp.reset(); + conf_change.reset(); + cscc.reset(); + + score.resize(num_vars(), 0); score[0] = INT_MIN; + sscore.resize(num_vars(), 0); sscore[0] = INT_MIN; + time_stamp.resize(num_vars(), 0); time_stamp[0] = max_steps; + conf_change.resize(num_vars(), true); conf_change[0] = false; + cscc.resize(num_vars(), 1); cscc[0] = 0; + for (unsigned v = 0; v < num_vars(); ++v) { // greedy here!! - if (coefficient_in_ob_constraint[v] != 0) + if (coefficient_in_ob_constraint.get(v, 0) != 0) cur_solution[v] = (coefficient_in_ob_constraint[v] > 0); } @@ -162,6 +193,7 @@ namespace sat { unsigned id = constraint_term.size(); constraint_term.push_back(svector()); for (unsigned i = 0; i < sz; ++i) { + var_term.resize(c[i].var() + 1); term t; t.constraint_id = id; t.var_id = c[i].var(); @@ -173,6 +205,7 @@ namespace sat { } local_search::local_search(solver& s) { + // copy units unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { @@ -242,10 +275,6 @@ namespace sat { // SASSERT(ext->m_xors.empty()); } - - - num_vars = s.num_vars(); - num_constraints = constraint_term.size(); } local_search::~local_search() { @@ -256,17 +285,18 @@ namespace sat { } lbool local_search::operator()() { - bool reach_cutoff_time = false; - bool reach_known_best_value = false; - bool_var flipvar; + init(); + bool reach_cutoff_time = false; + bool reach_known_best_value = false; + bool_var flipvar; double elapsed_time = 0; clock_t start = clock(), stop; // TBD, use stopwatch facility - srand(0); // TBD, use random facility and parameters to set random seed. - set_parameters(); - // ################## start ###################### - //cout << "Start initialize and local search, restart in every " << max_steps << " steps" << endl; - for (unsigned tries = 0; ; ++tries) { - init(); + srand(0); // TBD, use random facility and parameters to set random seed. + set_parameters(); + // ################## start ###################### + //cout << "Start initialize and local search, restart in every " << max_steps << " steps" << endl; + for (unsigned tries = 0; ; ++tries) { + reinit(); for (int step = 1; step <= max_steps; ++step) { // feasible if (m_unsat_stack.empty()) { @@ -287,11 +317,11 @@ namespace sat { reach_cutoff_time = true; if (reach_known_best_value || reach_cutoff_time) break; - } - if (reach_known_best_value) { + } + if (reach_known_best_value) { std::cout << elapsed_time << "\n"; - } - else + } + else std::cout << -1 << "\n"; //print_solution(); @@ -311,8 +341,8 @@ namespace sat { // update related clauses and neighbor vars svector const& constraints = var_term[flipvar]; - unsigned num_constraints = constraints.size(); - for (unsigned i = 0; i < num_constraints; ++i) { + unsigned num_cs = constraints.size(); + for (unsigned i = 0; i < num_cs; ++i) { c = constraints[i].constraint_id; if (cur_solution[flipvar] == constraints[i].sense) { //++true_terms_count[c]; @@ -427,8 +457,8 @@ namespace sat { bool local_search::tie_breaker_sat(bool_var v, bool_var best_var) { // most improvement on objective value - int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint[v] : coefficient_in_ob_constraint[v]; - int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint[best_var] : coefficient_in_ob_constraint[best_var]; + int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint.get(v, 0) : coefficient_in_ob_constraint.get(v, 0); + int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint.get(best_var, 0) : coefficient_in_ob_constraint.get(best_var, 0); // break tie 1: max imp // break tie 2: conf_change // break tie 3: time_stamp @@ -458,7 +488,7 @@ namespace sat { bool_var local_search::pick_var() { int c, v; - bool_var best_var = null_bool_var; + bool_var best_var = num_vars()-1; // SAT Mode if (m_unsat_stack.empty()) { @@ -498,15 +528,15 @@ namespace sat { void local_search::set_parameters() { if (s_id == 0) - max_steps = num_vars; + max_steps = num_vars(); else if (s_id == 1) - max_steps = (int) (1.5 * num_vars); + max_steps = (int) (1.5 * num_vars()); else if (s_id == 1) - max_steps = 2 * num_vars; + max_steps = 2 * num_vars(); else if (s_id == 2) - max_steps = (int) (2.5 * num_vars); + max_steps = (int) (2.5 * num_vars()); else if (s_id == 3) - max_steps = 3 * num_vars; + max_steps = 3 * num_vars(); else { std::cout << "Invalid strategy id!" << std::endl; exit(-1); diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 12f3c3756..1d314abf8 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -42,9 +42,6 @@ namespace sat { //int coefficient; // all constraints are cardinality: coefficient=1 }; - // parameters of the instance - unsigned num_vars; // var index from 1 to num_vars - unsigned num_constraints; // constraint index from 1 to num_constraint // objective function: maximize svector ob_constraint; // the objective function *constraint*, sorted in decending order @@ -53,6 +50,11 @@ namespace sat { // terms arrays vector > var_term; // var_term[i][j] means the j'th term of var i vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i + + // parameters of the instance + unsigned num_vars() const { return var_term.size(); } // var index from 1 to num_vars + unsigned num_constraints() const { return constraint_term.size(); } // constraint index from 1 to num_constraint + // information about the variable int_vector coefficient_in_ob_constraint; // initialized to be 0 @@ -62,7 +64,7 @@ namespace sat { int_vector time_stamp; // the flip time stamp bool_vector conf_change; // whether its configure changes since its last flip int_vector cscc; // how many times its constraint state configure changes since its last flip - vector var_neighbor; // all of its neighborhoods variable + vector var_neighbor; // all of its neighborhoods variable /* TBD: other scores */ // information about the constraints @@ -94,10 +96,12 @@ namespace sat { // for tuning int s_id = 0; // strategy id + void init(); - void init_orig(); - void init_greedy(); + void reinit(); + void reinit_orig(); + void reinit_greedy(); void init_cur_solution(); void init_slack(); @@ -124,7 +128,6 @@ namespace sat { void add_clause(unsigned sz, literal const* c); - void add_cardinality(unsigned sz, literal const* c, unsigned k); // swap the deleted one with the last one and pop void sat(int c) { @@ -141,6 +144,8 @@ namespace sat { ~local_search(); void add_soft(literal l, double weight); + + void add_cardinality(unsigned sz, literal const* c, unsigned k); lbool operator()(); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 30a458ece..8530a9d76 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -447,14 +447,15 @@ struct goal2sat::imp { lits[i].neg(); } sat::bool_var v = m_solver.mk_var(true); + sat::literal lit(v, sign); m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); if (root) { m_result_stack.reset(); - mk_clause(sat::literal(v, sign)); + mk_clause(lit); } else { m_result_stack.shrink(sz - t->get_num_args()); - m_result_stack.push_back(sat::literal(v, sign)); + m_result_stack.push_back(lit); } } diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 1d92b37c7..83c8e7b14 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -1,18 +1,18 @@ #include "sat_local_search.h" #include "sat_solver.h" -static int build_instance(char *filename, sat::solver& s, sat::local_search& ls) +static bool build_instance(char const * filename, sat::solver& s, sat::local_search& local_search) { char line[16383]; int cur_term; // for temperally storage - int temp[16383]; - int temp_count; std::ifstream infile(filename); //if (infile == NULL) //linux - if (!infile) - return 0; + if (!infile) { + std::cout << "File not found " << filename << "\n"; + return false; + } infile.getline(line, 16383); int num_vars, num_constraints; sscanf_s(line, "%d %d", &num_vars, &num_constraints); @@ -20,44 +20,36 @@ static int build_instance(char *filename, sat::solver& s, sat::local_search& ls) //cout << "number of constraints: " << num_constraints << endl; - // write in the objective function - temp_count = 0; - infile >> cur_term; - while (cur_term != 0) { - temp[temp_count++] = cur_term; - infile >> cur_term; - } - int ob_num_terms = temp_count; - -#if 0 - TBD make this compile: - ob_constraint = new ob_term[ob_num_terms + 1]; - // coefficient - ob_constraint[0].coefficient = 0; // virtual var: all variables not in ob are pointed to this var - for (i = 1; i <= ob_num_terms; ++i) { - ob_constraint[i].coefficient = temp[i - 1]; - } - + unsigned_vector coefficients; sat::literal_vector lits; - // ob variable - temp_count = 0; + + // process objective function: + // read coefficents infile >> cur_term; while (cur_term != 0) { - temp[temp_count++] = cur_term; + coefficients.push_back(cur_term); infile >> cur_term; } - if (temp_count != ob_num_terms) { - cout << "Objective function format error." << endl; - exit(-1); + + // read variables + infile >> cur_term; + while (cur_term != 0) { + lits.push_back(sat::literal(abs(cur_term), cur_term < 0)); + infile >> cur_term; } - for (i = 1; i <= ob_num_terms; ++i) { - ob_constraint[i].var_id = temp[i - 1]; - coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient; + + if (lits.size() != coefficients.size()) { + std::cout << "Objective function format error. They have different lenghts.\n"; + return false; } + + for (unsigned i = 0; i < lits.size(); ++i) { + local_search.add_soft(lits[i], coefficients[i]); + } + // read the constraints, one at a time - card_extension* ext = 0; int k; - for (c = 1; c <= num_constraints; ++c) { + for (int c = 1; c <= num_constraints; ++c) { lits.reset(); infile >> cur_term; while (cur_term != 0) { @@ -65,63 +57,11 @@ static int build_instance(char *filename, sat::solver& s, sat::local_search& ls) infile >> cur_term; } infile >> k; - ext->add_at_least(null_bool_var, lits, lits.size() - k); + local_search.add_cardinality(lits.size(), lits.c_ptr(), static_cast(lits.size() - k)); } -#endif infile.close(); - - -#if 0 - Move all of this to initialization code for local search solver: - - // create var_term array - for (v = 1; v <= num_vars; ++v) { - var_term[v] = new term[var_term_count[v]]; - var_term_count[v] = 0; // reset to 0, for building up the array - } - // scan all constraints to build up var term arrays - for (c = 1; c <= num_constraints; ++c) { - for (i = 0; i < constraint_term_count[c]; ++i) { - v = constraint_term[c][i].var_id; - var_term[v][var_term_count[v]++] = constraint_term[c][i]; - } - } - - - // build neighborhood relationship - bool *is_neighbor; - is_neighbor = new bool[num_vars + 1]; - for (v = 1; v <= num_vars; ++v) { - // init as not neighbor - for (i = 1; i <= num_vars; ++i) { - is_neighbor[i] = false; - } - temp_count = 0; - // for each constraint v appears - for (i = 0; i < var_term_count[v]; ++i) { - c = var_term[v][i].constraint_id; - for (j = 0; j < constraint_term_count[c]; ++j) { - if (constraint_term[c][j].var_id == v) - continue; - // not neighbor yet - if (!is_neighbor[constraint_term[c][j].var_id]) { - is_neighbor[constraint_term[c][j].var_id] = true; - temp[temp_count++] = constraint_term[c][j].var_id; - } - } - } - // create and build neighbor - var_neighbor_count[v] = temp_count; - var_neighbor[v] = new int[var_neighbor_count[v]]; - for (i = 0; i < var_neighbor_count[v]; ++i) { - var_neighbor[v][i] = temp[i]; - } - } - delete[] is_neighbor; - -#endif - return 1; + return true; } void tst_sat_local_search(char ** argv, int argc, int& i) { @@ -129,6 +69,20 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { std::cout << "require dimacs file name\n"; return; } + reslimit limit; + params_ref params; + sat::solver solver(params, limit); + sat::local_search local_search(solver); + char const* file_name = argv[i + 1]; + ++i; + + if (!build_instance(file_name, solver, local_search)) { + return; + } + + std::cout << "local instance built\n"; + local_search(); + // sat::solver s; // populate the sat solver with clauses and cardinality consrtaints from the input // call the lookahead solver. From 54f145b364df0611a416aaeaa6733f94fe2b090d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Feb 2017 15:11:18 -0800 Subject: [PATCH 0055/1283] initialize Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 6 +++++- src/sat/sat_params.pyg | 1 + src/test/sat_local_search.cpp | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 84e1355b1..e1fad2740 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -20,6 +20,7 @@ #include "sat_local_search.h" #include "sat_solver.h" #include "card_extension.h" +#include "sat_params.hpp" namespace sat { @@ -42,6 +43,7 @@ namespace sat { } } } + set_parameters(); } void local_search::reinit() { @@ -285,6 +287,8 @@ namespace sat { } lbool local_search::operator()() { + sat_params params; + std::cout << "my parameter value: " << params.cliff() << "\n"; init(); bool reach_cutoff_time = false; bool reach_known_best_value = false; @@ -294,7 +298,7 @@ namespace sat { srand(0); // TBD, use random facility and parameters to set random seed. set_parameters(); // ################## start ###################### - //cout << "Start initialize and local search, restart in every " << max_steps << " steps" << endl; + std::cout << "Start initialize and local search, restart in every " << max_steps << " steps\n"; for (unsigned tries = 0; ; ++tries) { reinit(); for (int step = 1; step <= max_steps; ++step) { diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index a51e72e25..5e68d2f42 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -27,4 +27,5 @@ def_module_params('sat', ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), ('cardinality.solver', BOOL, False, 'use cardinality/xor solver'), + ('cliff', UINT, 0, 'my favorite parameter'), )) diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 83c8e7b14..53720d094 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -65,7 +65,7 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea } void tst_sat_local_search(char ** argv, int argc, int& i) { - if (argc != i + 2) { + if (argc < i + 2) { std::cout << "require dimacs file name\n"; return; } @@ -75,6 +75,11 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { sat::local_search local_search(solver); char const* file_name = argv[i + 1]; ++i; + while (i + 1 < argc) { + // set other ad hoc parameters. + std::cout << argv[i + 1] << "\n"; + ++i; + } if (!build_instance(file_name, solver, local_search)) { return; From db9e8d96d43e527f901e646587eafb4cd87a60ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Feb 2017 16:00:20 -0800 Subject: [PATCH 0056/1283] working on lookahead solver Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 476 ++++++++++++++++++++++++++++------------ src/util/uint_set.h | 39 ++++ 2 files changed, 378 insertions(+), 137 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 4872a548a..7be53e2d1 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -27,52 +27,211 @@ namespace sat { double m_dl_success; }; - config m_config; - double m_delta_trigger; - literal_vector m_trail; - literal_vector m_units; - unsigned_vector m_units_lim; - unsigned_vector m_learned_lim; - unsigned_vector m_binary; + struct statistics { + unsigned m_propagations; + statistics() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + config m_config; + double m_delta_trigger; + literal_vector m_trail; + unsigned_vector m_trail_lim; + literal_vector m_units; + unsigned_vector m_units_lim; + vector m_binary; // binary clauses + unsigned_vector m_binary_trail; // trail of added binary clauses + unsigned_vector m_binary_trail_lim; + clause_vector m_clauses; // non-binary clauses + clause_allocator m_cls_allocator; + bool m_inconsistent; + unsigned_vector m_bstamp; // timestamp for binary implication, one for each literal + unsigned m_bstamp_id; // unique id for binary implication. + unsigned m_qhead; + unsigned_vector m_qhead_lim; + char_vector m_assignment; + vector m_watches; + indexed_uint_set m_free_vars; + statistics m_stats; + + void add_binary(literal l1, literal l2) { + SASSERT(l1 != l2); + SASSERT(~l1 != l2); + m_binary[(~l1).index()].push_back(l2); + m_binary[(~l2).index()].push_back(l1); + m_binary_trail.push_back((~l1).index()); + } + + void del_binary(unsigned idx) { + literal_vector & lits = m_binary[idx]; + literal l = lits.back(); + lits.pop_back(); + m_binary[(~l).index()].pop_back(); + } + + // ------------------------------------- + // track consequences of binary clauses + // see also 72 - 77 in sat11.w + + void inc_bstamp() { + ++m_bstamp_id; + if (m_bstamp_id == 0) { + ++m_bstamp_id; + m_bstamp.fill(0); + } + } + void set_bstamp(literal l) { + m_bstamp[l.index()] = m_bstamp_id; + } + void set_bstamps(literal l) { + set_bstamp(l); + literal_vector const& conseq = m_binary[l.index()]; + for (unsigned i = 0; i < conseq.size(); ++i) { + set_bstamp(conseq[i]); + } + } + bool is_stamped(literal l) const { return m_bstamp[l.index()] == m_bstamp_id; } + + /** + \brief add one-step transitive closure of binary implications + return false if we learn a unit literal. + \pre all implicants of ~u are stamped. + u \/ v is true + **/ + + bool add_tc1(literal u, literal v) { + unsigned sz = m_binary[v.index()].size(); + for (unsigned i = 0; i < sz; ++i) { + literal w = m_binary[v.index()][i]; + // ~v \/ w + if (!is_fixed(w)) { + if (is_stamped(~w)) { + // u \/ v, ~v \/ w, u \/ ~w => u is unit + assign(u); + return false; + } + add_binary(u, w); + } + } + return true; + } + + /** + \brief main routine for adding a new binary clause dynamically. + */ + void try_add_binary(literal u, literal v) { + SASSERT(u.var() != v.var()); + inc_bstamp(); + set_bstamps(~u); + if (is_stamped(~v)) { + // u \/ ~v is a binary clause, u \/ v is true => u is a unit literal + assign(u); + } + else if (!is_stamped(v) && add_tc1(u, v)) { + // u \/ v is not in index + // all implicants of ~u are stamped. + inc_bstamp(); + set_bstamps(~v); + if (is_stamped(~u)) { + // v \/ ~u is a binary clause, u \/ v is true => v is a unit + assign(v); + } + else if (add_tc1(v, u)) { + add_binary(u, v); + } + } + } + + void init_var(bool_var v) { + m_assignment.push_back(l_undef); + m_assignment.push_back(l_undef); + m_binary.push_back(literal_vector()); + m_binary.push_back(literal_vector()); + m_watches.push_back(watch_list()); + m_watches.push_back(watch_list()); + m_bstamp.push_back(0); + m_bstamp.push_back(0); + } void init() { m_delta_trigger = s.num_vars()/10; m_config.m_dl_success = 0.8; + m_inconsistent = false; + m_qhead = 0; + m_bstamp_id = 0; + + for (unsigned i = 0; i < s.num_vars(); ++i) { + init_var(i); + } + + // copy binary clauses + unsigned sz = s.m_watches.size(); + for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { + literal l = ~to_literal(l_idx); + watch_list const & wlist = s.m_watches[l_idx]; + watch_list::const_iterator it = wlist.begin(); + watch_list::const_iterator end = wlist.end(); + for (; it != end; ++it) { + if (!it->is_binary_non_learned_clause()) + continue; + literal l2 = it->get_literal(); + if (l.index() < l2.index()) + add_binary(l, l2); + } + } + + // copy clauses + clause_vector::const_iterator it = s.m_clauses.begin(); + clause_vector::const_iterator end = s.m_clauses.end(); + for (; it != end; ++it) { + clause& c = *(*it); + m_clauses.push_back(m_cls_allocator.mk_clause(c.size(), c.begin(), false)); + // TBD: add watch + } + + // copy units + unsigned trail_sz = s.init_trail_size(); + for (unsigned i = 0; i < trail_sz; ++i) { + literal l = s.m_trail[i]; + m_units.push_back(l); + assign(l); + } } void push(literal lit) { - m_learned_lim.push_back(s.m_learned.size()); + m_binary_trail_lim.push_back(m_binary_trail.size()); m_units_lim.push_back(m_units.size()); + m_trail_lim.push_back(m_trail.size()); + m_qhead_lim.push_back(m_qhead); m_trail.push_back(lit); - m_binary.push_back(0); - s.push(); assign(lit); + propagate(); } void pop() { - s.pop(1); - unsigned old_sz = m_learned_lim.back(); - m_learned_lim.pop_back(); - for (unsigned i = old_sz; i < s.m_learned.size(); ++i) { - clause* r = s.m_learned[i]; - s.dettach_clause(*r); - s.m_cls_allocator.del_clause(r); + // remove local binary clauses + unsigned old_sz = m_binary_trail_lim.back(); + m_binary_trail_lim.pop_back(); + for (unsigned i = old_sz; i < m_binary_trail.size(); ++i) { + del_binary(m_binary_trail[i]); } - s.m_learned.shrink(old_sz); + + // add implied binary clauses unsigned new_unit_sz = m_units_lim.back(); for (unsigned i = new_unit_sz; i < m_units.size(); ++i) { - literal lits[2] = { ~m_trail.back(), m_units[i] }; - clause * r = s.m_cls_allocator.mk_clause(2, lits, true); - s.m_learned.push_back(r); + add_binary(~m_trail.back(), m_units[i]); } m_units.shrink(new_unit_sz); m_units_lim.pop_back(); - m_trail.pop_back(); - m_binary.pop_back(); + m_trail.shrink(m_trail_lim.size()); // reset assignment. + m_trail_lim.pop_back(); + m_qhead_lim.pop_back(); + m_qhead = m_qhead_lim.back(); + + m_inconsistent = false; } - unsigned diff() const { return m_binary.back() + m_units.size() - m_units_lim.back(); } + unsigned diff() const { return m_units.size() - m_units_lim.back(); } unsigned mix_diff(unsigned l, unsigned r) const { return l + r + (1 << 10) * l * r; } @@ -82,52 +241,129 @@ namespace sat { } bool is_nary_propagation(clause const& c, literal l) const { - bool r = c.size() > 2 && ((c[0] == l && s.value(c[1]) == l_false) || (c[1] == l && s.value(c[0]) == l_false)); - DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(s.value(c[j]) == l_false);); + bool r = c.size() > 2 && ((c[0] == l && value(c[1]) == l_false) || (c[1] == l && value(c[0]) == l_false)); + DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(value(c[j]) == l_false);); return r; } - void get_resolvent_units(literal lit) { + void propagate_clauses(literal l) { + SASSERT(value(l) == l_true); + SASSERT(value(~l) == l_false); if (inconsistent()) return; - for (unsigned i = s.m_trail.size(); i > 0; ) { - --i; - literal l = s.m_trail[i]; - if (l == lit) break; - SASSERT(s.lvl(l) == s.scope_lvl()); - watch_list& wlist = s.m_watches[(~l).index()]; - watch_list::iterator it = wlist.begin(), end = wlist.end(); - for (; it != end; ++it) { - switch (it->get_kind()) { - case watched::TERNARY: - if (s.value(it->get_literal1()) == l_false && - s.value(it->get_literal2()) == l_false) { - m_units.push_back(l); - goto done_finding_unit; - } - break; - case watched::CLAUSE: { - clause const & c = get_clause(it); - SASSERT(c[0] == l || c[1] == l); - if (is_nary_propagation(c, l)) { - m_units.push_back(l); - goto done_finding_unit; - } - break; + watch_list& wlist = m_watches[l.index()]; + watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); + for (; it != end && !inconsistent(); ++it) { + switch (it->get_kind()) { + case watched::BINARY: + UNREACHABLE(); + break; + case watched::TERNARY: { + literal l1 = it->get_literal1(); + literal l2 = it->get_literal2(); + lbool val1 = value(l1); + lbool val2 = value(l2); + if (val1 == l_false && val2 == l_undef) { + m_stats.m_propagations++; + assign(l2); } - default: - break; + else if (val1 == l_undef && val2 == l_false) { + m_stats.m_propagations++; + assign(l1); } + else if (val1 == l_false && val2 == l_false) { + set_conflict(); + } + else if (val1 == l_undef && val2 == l_undef) { + // TBD: the clause has become binary. + } + *it2 = *it; + it2++; + break; + } + case watched::CLAUSE: { + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";); + if (c[0] == ~l) + std::swap(c[0], c[1]); + if (value(c[0]) == l_true) { + it2->set_clause(c[0], cls_off); + it2++; + break; + } + literal * l_it = c.begin() + 2; + literal * l_end = c.end(); + unsigned found = 0; + for (; l_it != l_end && found < 2; ++l_it) { + if (value(*l_it) != l_false) { + ++found; + if (found == 2) { + break; + } + else { + c[1] = *l_it; + *l_it = ~l; + m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); + } + } + } + if (found == 1) { + // TBD: clause has become binary + break; + } + if (found > 1) { + // not a binary clause + break; + } + else if (value(c[0]) == l_false) { + set_conflict(); + } + else { + SASSERT(value(c[0]) == l_undef); + *it2 = *it; + it2++; + m_stats.m_propagations++; + assign(c[0]); + } + break; + } + case watched::EXT_CONSTRAINT: + UNREACHABLE(); + break; + default: + UNREACHABLE(); + break; } - done_finding_unit: - - // - // TBD: count binary clauses created by propagation. - // They used to be in the watch list of l.index(), - // both new literals in watch list should be unassigned. - // - continue; - } + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + wlist.set_end(it2); + + + // + // TBD: count binary clauses created by propagation. + // They used to be in the watch list of l.index(), + // both new literals in watch list should be unassigned. + // + } + + void propagate_binary(literal l) { + literal_vector const& lits = m_binary[l.index()]; + unsigned sz = lits.size(); + for (unsigned i = 0; !inconsistent() && i < sz; ++i) { + assign(lits[i]); + } + } + + void propagate() { + for (; m_qhead < m_trail.size(); ++m_qhead) { + if (inconsistent()) break; + literal l = m_trail[m_qhead]; + propagate_binary(l); + propagate_clauses(l); + } + TRACE("sat", s.display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } literal choose() { @@ -187,7 +423,7 @@ namespace sat { bool unsat; for (unsigned i = 0; !inconsistent() && i < P.size(); ++i) { literal lit = P[i]; - if (s.value(lit) != l_undef) continue; + if (value(lit) != l_undef) continue; push(lit); unsat = inconsistent(); @@ -205,37 +441,39 @@ namespace sat { TRACE("sat", tout << "unit: " << lit << "\n";); assign(lit); } - } update_delta_trigger(); } + bool is_fixed(literal l) const { return value(l) != l_undef; } + bool is_contrary(literal l) const { return value(l) == l_false; } + void set_conflict() { m_inconsistent = true; } + lbool value(literal l) const { return static_cast(m_assignment[l.index()]); } + unsigned scope_lvl() const { return m_trail_lim.size(); } + void assign(literal l) { - s.assign(l, justification()); - s.propagate(false); - get_resolvent_units(l); - TRACE("sat", s.display(tout << l << " @ " << s.scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); + switch (value(l)) { + case l_true: + break; + case l_false: + set_conflict(); + break; + default: + m_assignment[l.index()] = l.sign() ? l_false : l_true; + m_assignment[(~l).index()] = l.sign() ? l_false : l_true; + m_trail.push_back(l); + break; + } } - bool inconsistent() { return s.inconsistent(); } + void set_inconsistent() { m_inconsistent = true; } + bool inconsistent() { return m_inconsistent; } void pre_select(literal_vector& P) { select_variables(P); order_by_implication_trees(P); } - void check_binary(clause const& c, literal lit1, literal& lit2) { - if (c.size() == 2) { - if (c[0] == lit1) { - lit2 = c[1]; - } - else { - SASSERT(c[1] == lit1); - lit2 = c[0]; - } - } - } - void order_by_implication_trees(literal_vector& P) { literal_set roots; literal_vector nodes, parent; @@ -253,24 +491,11 @@ namespace sat { // make lit1 a root instead of lit2 // - watch_list& wlist = s.m_watches[(~lit1).index()]; - watch_list::iterator it = wlist.begin(), end = wlist.end(); - lit2 = null_literal; - for (; it != end; ++it) { - switch (it->get_kind()) { - case watched::BINARY: - lit2 = it->get_literal(); - break; - case watched::CLAUSE: { - clause const & c = get_clause(it); - check_binary(c, lit1, lit2); - break; - } - default: - break; - } - - if (lit2 != null_literal && roots.contains(~lit2)) { + literal_vector const& lits1 = m_binary[(~lit1).index()]; + unsigned sz = lits1.size(); + for (unsigned i = 0; i < sz; ++i) { + literal lit2 = lits1[i]; + if (roots.contains(~lit2)) { // ~lit2 => lit1 // if lit2 is a root, put it under lit2 parent.setx((~lit2).index(), lit1, null_literal); @@ -285,24 +510,11 @@ namespace sat { // if lit2 is a node, put lit1 above lit2 // - it = s.m_watches[lit1.index()].begin(); - end = s.m_watches[lit1.index()].end(); - for (; it != end; ++it) { - lit2 = null_literal; - switch (it->get_kind()) { - case watched::BINARY: - lit2 = it->get_literal(); - break; - case watched::CLAUSE: { - clause const & c = get_clause(it); - check_binary(c, ~lit1, lit2); - break; - } - default: - break; - } - - if (lit2 != null_literal && nodes.contains(lit2)) { + literal_vector const& lits2 = m_binary[(~lit2).index()]; + sz = lits2.size(); + for (unsigned i = 0; i < sz; ++i) { + literal lit2 = lits2[i]; + if (nodes.contains(lit2)) { // lit1 => lit2 parent.setx(lit1.index(), lit2, null_literal); nodes.insert(lit1); @@ -329,7 +541,7 @@ namespace sat { void select_variables(literal_vector& P) { for (unsigned i = 0; i < s.num_vars(); ++i) { - if (s.value(i) == l_undef) { + if (value(literal(i,false)) == l_undef) { P.push_back(literal(i, false)); } } @@ -351,15 +563,12 @@ namespace sat { } } - lbool backtrack(literal_vector& trail) { - if (inconsistent()) { - if (trail.empty()) return l_false; - pop(); - assign(~trail.back()); - trail.pop_back(); - return l_true; - } - return l_undef; + bool backtrack(literal_vector& trail) { + if (trail.empty()) return false; + pop(); + assign(~trail.back()); + trail.pop_back(); + return true; } lbool search() { @@ -367,17 +576,10 @@ namespace sat { while (true) { s.checkpoint(); - switch (backtrack(trail)) { - case l_true: continue; - case l_false: return l_false; - case l_undef: break; - } - literal l = choose(); - switch (backtrack(trail)) { - case l_true: continue; - case l_false: return l_false; - case l_undef: break; + if (inconsistent()) { + if (!backtrack(trail)) return l_false; + continue; } if (l == null_literal) { return l_true; diff --git a/src/util/uint_set.h b/src/util/uint_set.h index d0cc8a32a..5633b74b2 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -333,6 +333,45 @@ public: } }; +class indexed_uint_set { + unsigned m_size; + unsigned_vector m_elems; + unsigned_vector m_index; +public: + indexed_uint_set(): + m_size(0) + {} + + void insert(unsigned x) { + SASSERT(!contains(x)); + m_index.resize(x + 1, UINT_MAX); + m_elems.resize(m_size + 1); + m_index[x] = m_size; + m_elems[m_size] = x; + m_size++; + } + + void remove(unsigned x) { + SASSERT(contains(x)); + unsigned y = m_elems[--m_size]; + if (x != y) { + unsigned idx = m_index[x]; + m_index[y] = idx; + m_elems[idx] = y; + m_index[x] = m_size; + m_elems[m_size] = x; + } + } + + bool contains(unsigned x) const { return x < m_index.size() && m_index[x] < m_size && m_elems[m_index[x]] == x; } + void reset() { m_size = 0; } + bool empty() const { return m_size == 0; } + unsigned size() const { return m_size; } + typedef unsigned_vector::const_iterator iterator; + iterator begin() const { return m_elems.begin(); } + iterator end() const { return m_elems.begin() + m_size; } + +}; #endif /* UINT_SET_H_ */ From 411dcc89259055cd87623567f605da6693085c98 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Feb 2017 17:05:08 -0800 Subject: [PATCH 0057/1283] working on pre-selection Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 124 ++++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 7be53e2d1..c7acb2bb0 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -25,6 +25,19 @@ namespace sat { struct config { double m_dl_success; + float m_alpha; + float m_max_score; + unsigned m_max_hlevel; + unsigned m_min_cutoff; + unsigned m_level_cand; + + config() { + m_max_hlevel = 50; + m_alpha = 3.5; + m_max_score = 20.0; + m_min_cutoff = 30; + m_level_cand = 600; + } }; struct statistics { @@ -35,23 +48,26 @@ namespace sat { config m_config; double m_delta_trigger; - literal_vector m_trail; + + literal_vector m_trail; // trail of units unsigned_vector m_trail_lim; - literal_vector m_units; + literal_vector m_units; // units learned during lookahead unsigned_vector m_units_lim; - vector m_binary; // binary clauses + vector m_binary; // literal: binary clauses unsigned_vector m_binary_trail; // trail of added binary clauses unsigned_vector m_binary_trail_lim; + unsigned m_qhead; // propagation queue head + unsigned_vector m_qhead_lim; clause_vector m_clauses; // non-binary clauses clause_allocator m_cls_allocator; bool m_inconsistent; - unsigned_vector m_bstamp; // timestamp for binary implication, one for each literal + unsigned_vector m_bstamp; // literal: timestamp for binary implication + vector > m_H; // literal: fitness score + svector m_rating; // var: pre-selection rating unsigned m_bstamp_id; // unique id for binary implication. - unsigned m_qhead; - unsigned_vector m_qhead_lim; - char_vector m_assignment; - vector m_watches; - indexed_uint_set m_free_vars; + char_vector m_assignment; // literal: assignment + vector m_watches; // literal: watch structure + indexed_uint_set m_freevars; statistics m_stats; void add_binary(literal l1, literal l2) { @@ -71,7 +87,7 @@ namespace sat { // ------------------------------------- // track consequences of binary clauses - // see also 72 - 77 in sat11.w + // see also 72 - 79 in sat11.w void inc_bstamp() { ++m_bstamp_id; @@ -84,6 +100,7 @@ namespace sat { m_bstamp[l.index()] = m_bstamp_id; } void set_bstamps(literal l) { + inc_bstamp(); set_bstamp(l); literal_vector const& conseq = m_binary[l.index()]; for (unsigned i = 0; i < conseq.size(); ++i) { @@ -121,26 +138,96 @@ namespace sat { */ void try_add_binary(literal u, literal v) { SASSERT(u.var() != v.var()); - inc_bstamp(); set_bstamps(~u); - if (is_stamped(~v)) { - // u \/ ~v is a binary clause, u \/ v is true => u is a unit literal - assign(u); + if (is_stamped(~v)) { + assign(u); // u \/ ~v, u \/ v => u is a unit literal } else if (!is_stamped(v) && add_tc1(u, v)) { // u \/ v is not in index - // all implicants of ~u are stamped. - inc_bstamp(); set_bstamps(~v); if (is_stamped(~u)) { - // v \/ ~u is a binary clause, u \/ v is true => v is a unit - assign(v); + assign(v); // v \/ ~u, u \/ v => v is a unit literal } else if (add_tc1(v, u)) { add_binary(u, v); } } } + + // ------------------------------------- + // pre-selection + // see also 91 - 102 sat11.w + + void init_pre_selection(unsigned level) { + unsigned max_level = m_config.m_max_hlevel; + if (level <= 1) { + ensure_H(2); + h_scores(m_H[0], m_H[1]); + for (unsigned j = 0; j < 2; ++j) { + for (unsigned i = 0; i < 2; ++i) { + h_scores(m_H[i + 1], m_H[(i + 2) % 3]); + } + } + // heur = m_H[1]; + } + else if (level < max_level) { + ensure_H(level); + h_scores(m_H[level-1], m_H[level]); + // heur = m_H[level]; + } + else { + ensure_H(max_level); + h_scores(m_H[max_level-1], m_H[max_level]); + // heur = m_H[max_level]; + } + } + + void ensure_H(unsigned level) { + while (m_H.size() <= level) { + m_H.push_back(svector()); + m_H.back().resize(s.num_vars() * 2, 0); + } + } + + void h_scores(svector& h, svector& hp) { + float sum = 0; + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + literal l(*it, false); + sum += h[l.index()] + h[(~l).index()]; + } + float factor = 2 * m_freevars.size() / sum; + float sqfactor = factor * factor; + float afactor = factor * m_config.m_alpha; + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + literal l(*it, false); + float pos = l_score(l, h, factor, sqfactor, afactor); + float neg = l_score(~l, h, factor, sqfactor, afactor); + hp[l.index()] = pos; + hp[(~l).index()] = neg; + m_rating[l.var()] = pos * neg; + } + } + + float l_score(literal l, svector const& h, float factor, float sqfactor, float afactor) { + float sum = 0, tsum = 0; + literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); + for (; it != end; ++it) { + if (is_free(*it)) sum += h[it->index()]; + } + // TBD walk ternary clauses. + sum = 0.1 + afactor*sum + sqfactor*tsum; + return std::min(m_config.m_max_score, sum); + } + + bool is_free(literal l) const { + return !is_unit(l); + } + bool is_unit(literal l) const { + return false; // TBD track variables that are units + } + + // ------------------------------------ + // initialization void init_var(bool_var v) { m_assignment.push_back(l_undef); @@ -151,6 +238,7 @@ namespace sat { m_watches.push_back(watch_list()); m_bstamp.push_back(0); m_bstamp.push_back(0); + m_rating.push_back(0); } void init() { From e407b81f703050265a11d0b8fdfe22b4e8d9bbf8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 24 Feb 2017 15:56:04 -0800 Subject: [PATCH 0058/1283] update for layout Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 238 +++++++++++++++++----------------- src/sat/sat_local_search.h | 108 ++++++++++++--- src/test/sat_local_search.cpp | 41 +++++- 3 files changed, 244 insertions(+), 143 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index e1fad2740..6d99ef47d 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -25,15 +25,21 @@ namespace sat { void local_search::init() { + + best_solution.resize(num_vars() + 1, false); constraint_slack.resize(num_constraints(), 0); - cur_solution.resize(num_vars(), false); + cur_solution.resize(num_vars() + 1, false); m_index_in_unsat_stack.resize(num_constraints(), 0); - coefficient_in_ob_constraint.resize(num_vars(), 0); + coefficient_in_ob_constraint.resize(num_vars() + 1, 0); var_neighbor.reset(); - for (bool_var v = 0; v < num_vars(); ++v) { - bool_vector is_neighbor(num_vars(), false); + + // for dummy var 0 + var_neighbor.push_back(bool_var_vector()); + + for (bool_var v = 1; v <= num_vars(); ++v) { + bool_vector is_neighbor(num_vars() + 1, false); var_neighbor.push_back(bool_var_vector()); - for (unsigned i = 0; i < var_term[v].size(); ++ i) { + for (unsigned i = 0; i < var_term[v].size(); ++i) { unsigned c = var_term[v][i].constraint_id; for (unsigned j = 0; j < constraint_term[c].size(); ++j) { bool_var w = constraint_term[c][j].var_id; @@ -42,17 +48,20 @@ namespace sat { var_neighbor.back().push_back(w); } } - } + } + for (unsigned i = 0; i < ob_constraint.size(); ++i) + coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient; + set_parameters(); } void local_search::reinit() { - reinit_greedy(); + reinit_orig(); } void local_search::init_cur_solution() { - cur_solution.resize(num_vars() + 1, false); - for (unsigned v = 0; v < num_vars(); ++v) { + //cur_solution.resize(num_vars() + 1, false); + for (unsigned v = 1; v <= num_vars(); ++v) { cur_solution[v] = (rand() % 2 == 1); } } @@ -72,9 +81,9 @@ namespace sat { } } - // figure out variables scores, pscores and sscores + // figure out variables scores and sscores void local_search::init_scores() { - for (unsigned v = 0; v < num_vars(); ++v) { + for (unsigned v = 1; v <= num_vars(); ++v) { for (unsigned i = 0; i < var_term[v].size(); ++i) { int c = var_term[v][i].constraint_id; if (cur_solution[v] != var_term[v][i].sense) { @@ -83,7 +92,7 @@ namespace sat { if (constraint_slack[c] <= 0) { --sscore[v]; if (constraint_slack[c] == 0) - --score[v]; + --m_var_info[v].m_score; } } else { // if (cur_solution[v] == var_term[v][i].sense) @@ -92,20 +101,19 @@ namespace sat { if (constraint_slack[c] <= -1) { ++sscore[v]; if (constraint_slack[c] == -1) - ++score[v]; + ++m_var_info[v].m_score; } } } } } - // init goodvars and okvars stack + // init goodvars void local_search::init_goodvars() { goodvar_stack.reset(); - already_in_goodvar_stack.resize(num_vars(), false); - for (unsigned v = 0; v < num_vars(); ++v) { - if (score[v] > 0) { // && conf_change[v] == true - already_in_goodvar_stack[v] = true; + for (unsigned v = 1; v <= num_vars(); ++v) { + if (score(v) > 0) { // && conf_change[v] == true + m_var_info[v].m_in_goodvar_stack = true; goodvar_stack.push_back(v); } } @@ -123,60 +131,39 @@ namespace sat { // init varibale information // variable 0 is the virtual variable - score.reset(); + m_var_info.reset(); sscore.reset(); time_stamp.reset(); - conf_change.reset(); cscc.reset(); - score.resize(num_vars(), 0); score[0] = INT_MIN; - sscore.resize(num_vars(), 0); sscore[0] = INT_MIN; - time_stamp.resize(num_vars(), 0); time_stamp[0] = max_steps; - conf_change.resize(num_vars(), true); conf_change[0] = false; - cscc.resize(num_vars(), 1); cscc[0] = 0; + m_var_info.resize(num_vars() + 1, var_info()); + m_var_info[0].m_score = INT_MIN; + m_var_info[0].m_conf_change = false; + sscore.resize(num_vars() + 1, 0); sscore[0] = INT_MIN; + time_stamp.resize(num_vars() + 1, 0); time_stamp[0] = max_steps + 1; + cscc.resize(num_vars() + 1, 1); cscc[0] = 0; + init_slack(); init_scores(); - init_goodvars(); - } + init_goodvars(); - void local_search::reinit_greedy() { - constraint_slack = constraint_k; - - // init unsat stack - m_unsat_stack.reset(); - - // init solution: greedy - init_cur_solution(); - - // init varibale information - // variable 0 is the virtual variable - - score.reset(); - sscore.reset(); - time_stamp.reset(); - conf_change.reset(); - cscc.reset(); - - score.resize(num_vars(), 0); score[0] = INT_MIN; - sscore.resize(num_vars(), 0); sscore[0] = INT_MIN; - time_stamp.resize(num_vars(), 0); time_stamp[0] = max_steps; - conf_change.resize(num_vars(), true); conf_change[0] = false; - cscc.resize(num_vars(), 1); cscc[0] = 0; - for (unsigned v = 0; v < num_vars(); ++v) { - // greedy here!! - if (coefficient_in_ob_constraint.get(v, 0) != 0) - cur_solution[v] = (coefficient_in_ob_constraint[v] > 0); - } - - init_slack(); - init_scores(); - init_goodvars(); } - void local_search::calculate_and_update_ob() { - + unsigned i, v; + objective_value = 0; + for (i = 0; i < ob_constraint.size(); ++i) { + v = ob_constraint[i].var_id; + if (cur_solution[v]) + objective_value += ob_constraint[i].coefficient; + } + if (objective_value > best_objective_value) { + best_solution = cur_solution; + best_objective_value = objective_value; + stop = clock(); + best_time = (double)(stop - start) / CLOCKS_PER_SEC; + } } void local_search::verify_solution() { @@ -195,7 +182,7 @@ namespace sat { unsigned id = constraint_term.size(); constraint_term.push_back(svector()); for (unsigned i = 0; i < sz; ++i) { - var_term.resize(c[i].var() + 1); + var_term.reserve(c[i].var() + 1); term t; t.constraint_id = id; t.var_id = c[i].var(); @@ -282,26 +269,30 @@ namespace sat { local_search::~local_search() { } - void local_search::add_soft(literal l, double weight) { - + void local_search::add_soft(int v, int weight) { + // TBD + ob_term t; + t.var_id = v; + t.coefficient = weight; + ob_constraint.push_back(t); } lbool local_search::operator()() { - sat_params params; - std::cout << "my parameter value: " << params.cliff() << "\n"; + //sat_params params; + //std::cout << "my parameter value: " << params.cliff() << "\n"; init(); bool reach_cutoff_time = false; bool reach_known_best_value = false; bool_var flipvar; double elapsed_time = 0; - clock_t start = clock(), stop; // TBD, use stopwatch facility - srand(0); // TBD, use random facility and parameters to set random seed. - set_parameters(); + //clock_t start = clock(), stop; // TBD, use stopwatch facility + start = clock(); // ################## start ###################### - std::cout << "Start initialize and local search, restart in every " << max_steps << " steps\n"; - for (unsigned tries = 0; ; ++tries) { + //std::cout << "Start initialize and local search, restart in every " << max_steps << " steps\n"; + unsigned tries, step; + for (tries = 0; ; ++tries) { reinit(); - for (int step = 1; step <= max_steps; ++step) { + for (step = 1; step <= max_steps; ++step) { // feasible if (m_unsat_stack.empty()) { calculate_and_update_ob(); @@ -317,30 +308,32 @@ namespace sat { // take a look at watch stop = clock(); elapsed_time = (double)(stop - start) / CLOCKS_PER_SEC; + if (tries % 10 == 0) + std::cout << tries << ": " << elapsed_time << '\n'; if (elapsed_time > cutoff_time) reach_cutoff_time = true; - if (reach_known_best_value || reach_cutoff_time) - break; + //if (reach_known_best_value || reach_cutoff_time) + // break; } if (reach_known_best_value) { std::cout << elapsed_time << "\n"; } - else + else { std::cout << -1 << "\n"; + } //print_solution(); - + std::cout << tries * max_steps + step << '\n'; // TBD: adjust return status return l_undef; } - void local_search::flip(bool_var flipvar) { // already changed truth value!!!! cur_solution[flipvar] = !cur_solution[flipvar]; - + unsigned v, c; - int org_flipvar_score = score[flipvar]; + int org_flipvar_score = score(flipvar); int org_flipvar_sscore = sscore[flipvar]; // update related clauses and neighbor vars @@ -358,7 +351,7 @@ namespace sat { // flipping the slack increasing var will no long sat this constraint if (cur_solution[v] == constraint_term[c][j].sense) //score[v] -= constraint_weight[c]; - --score[v]; + --m_var_info[v].m_score; } break; case -1: // from 0 to -1: sat -> unsat @@ -366,7 +359,7 @@ namespace sat { v = constraint_term[c][j].var_id; ++cscc[v]; //score[v] += constraint_weight[c]; - ++score[v]; + ++m_var_info[v].m_score; // slack increasing var if (cur_solution[v] == constraint_term[c][j].sense) ++sscore[v]; @@ -379,7 +372,7 @@ namespace sat { // flip the slack decreasing var will falsify this constraint if (cur_solution[v] != constraint_term[c][j].sense) { //score[v] -= constraint_weight[c]; - --score[v]; + --m_var_info[v].m_score; --sscore[v]; } } @@ -398,7 +391,7 @@ namespace sat { // flip the slack decreasing var will no long falsify this constraint if (cur_solution[v] != constraint_term[c][j].sense) { //score[v] += constraint_weight[c]; - ++score[v]; + ++m_var_info[v].m_score; ++sscore[v]; } } @@ -408,7 +401,7 @@ namespace sat { v = constraint_term[c][j].var_id; ++cscc[v]; //score[v] -= constraint_weight[c]; - --score[v]; + --m_var_info[v].m_score; // slack increasing var no longer sat this var if (cur_solution[v] == constraint_term[c][j].sense) --sscore[v]; @@ -421,7 +414,7 @@ namespace sat { // flip the slack increasing var will satisfy this constraint if (cur_solution[v] == constraint_term[c][j].sense) //score[v] += constraint_weight[c]; - ++score[v]; + ++m_var_info[v].m_score; } break; default: @@ -430,39 +423,42 @@ namespace sat { } } - score[flipvar] = -org_flipvar_score; + m_var_info[flipvar].m_score = -org_flipvar_score; sscore[flipvar] = -org_flipvar_sscore; - conf_change[flipvar] = false; + m_var_info[flipvar].m_conf_change = false; cscc[flipvar] = 0; /* update CCD */ - // remove the vars no longer okvar in okvar stack // remove the vars no longer goodvar in goodvar stack for (unsigned i = goodvar_stack.size(); i > 0;) { --i; v = goodvar_stack[i]; - if (score[v] <= 0) { + if (score(v) <= 0) { goodvar_stack[i] = goodvar_stack.back(); goodvar_stack.pop_back(); - already_in_goodvar_stack[v] = false; + m_var_info[v].m_in_goodvar_stack = false; } } // update all flipvar's neighbor's conf_change to true, add goodvar/okvar - for (unsigned i = 0; i < var_neighbor[flipvar].size(); ++i) { + + unsigned sz = var_neighbor[flipvar].size(); + for (unsigned i = 0; i < sz; ++i) { v = var_neighbor[flipvar][i]; - conf_change[v] = true; - if (score[v] > 0 && !already_in_goodvar_stack[v]) { + m_var_info[v].m_conf_change = true; + if (score(v) > 0 && !already_in_goodvar_stack(v)) { goodvar_stack.push_back(v); - already_in_goodvar_stack[v] = true; + m_var_info[v].m_in_goodvar_stack = true; } } + } bool local_search::tie_breaker_sat(bool_var v, bool_var best_var) { // most improvement on objective value int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint.get(v, 0) : coefficient_in_ob_constraint.get(v, 0); int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint.get(best_var, 0) : coefficient_in_ob_constraint.get(best_var, 0); + //std::cout << v_imp << "\n"; // break tie 1: max imp // break tie 2: conf_change // break tie 3: time_stamp @@ -470,8 +466,8 @@ namespace sat { return (v_imp > b_imp) || ((v_imp == b_imp) && - ((conf_change[v] && !conf_change[best_var]) || - ((conf_change[v] == conf_change[best_var]) && + ((conf_change(v) && !conf_change(best_var)) || + ((conf_change(v) == conf_change(best_var)) && (time_stamp[v] < time_stamp[best_var])))); } @@ -481,18 +477,18 @@ namespace sat { // break tie 3: cscc // break tie 4: oldest one return - (score[v] > score[best_var]) || - ((score[v] == score[best_var]) && - (sscore[v] > sscore[best_var]) || - ((sscore[v] == sscore[best_var]) && - (cscc[v] > cscc[best_var]) || - ((cscc[v] == cscc[best_var]) && - (time_stamp[v] < time_stamp[best_var])))); + ((score(v) > score(best_var)) || + ((score(v) == score(best_var)) && + ((sscore[v] > sscore[best_var]) || + ((sscore[v] == sscore[best_var]) && + ((cscc[v] > cscc[best_var]) || + ((cscc[v] == cscc[best_var]) && + (time_stamp[v] < time_stamp[best_var]))))))); } bool_var local_search::pick_var() { int c, v; - bool_var best_var = num_vars()-1; + bool_var best_var = 0; // SAT Mode if (m_unsat_stack.empty()) { @@ -521,32 +517,42 @@ namespace sat { // Diversification Mode c = m_unsat_stack[rand() % m_unsat_stack.size()]; // a random unsat constraint // Within c, from all slack increasing var, choose the oldest one - for (unsigned i = 0; i < constraint_term[c].size(); ++i) { + unsigned c_size = constraint_term[c].size(); + for (unsigned i = 0; i < c_size; ++i) { v = constraint_term[c][i].var_id; if (cur_solution[v] == constraint_term[c][i].sense && time_stamp[v] < time_stamp[best_var]) best_var = v; } - //++rd; return best_var; } void local_search::set_parameters() { + + srand(m_config.seed()); + cutoff_time = m_config.cutoff_time(); + s_id = m_config.strategy_id(); + best_known_value = m_config.best_known_value(); + + + if (s_id == 0) - max_steps = num_vars(); - else if (s_id == 1) - max_steps = (int) (1.5 * num_vars()); - else if (s_id == 1) max_steps = 2 * num_vars(); - else if (s_id == 2) - max_steps = (int) (2.5 * num_vars()); - else if (s_id == 3) - max_steps = 3 * num_vars(); else { std::cout << "Invalid strategy id!" << std::endl; exit(-1); } + + /*std::cout << "seed:\t" << m_config.seed() << '\n'; + std::cout << "cutoff time:\t" << m_config.cutoff_time() << '\n'; + std::cout << "strategy id:\t" << m_config.strategy_id() << '\n'; + std::cout << "best_known_value:\t" << m_config.best_known_value() << '\n'; + std::cout << "max_steps:\t" << max_steps << '\n'; + */ } - - + void local_search::print_info() { + for (int v = 1; v <= num_vars(); ++v) { + std::cout << var_neighbor[v].size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << sscore[v] << '\n'; + } + } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 1d314abf8..97e1974f2 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -1,21 +1,21 @@ /*++ -Copyright (c) 2017 Microsoft Corporation + Copyright (c) 2017 Microsoft Corporation -Module Name: + Module Name: - sat_local_search.h + sat_local_search.h -Abstract: + Abstract: - Local search module for cardinality clauses. + Local search module for cardinality clauses. -Author: + Author: - Sixue Liu 2017-2-21 + Sixue Liu 2017-2-21 -Notes: + Notes: ---*/ + --*/ #ifndef _SAT_LOCAL_SEARCH_H_ #define _SAT_LOCAL_SEARCH_H_ @@ -24,8 +24,33 @@ Notes: namespace sat { - class local_search { + class local_search_config { + unsigned m_seed; + unsigned m_cutoff_time; + unsigned m_strategy_id; + unsigned m_best_known_value; + public: + local_search_config() + { + m_seed = 0; + m_cutoff_time = 1; + m_strategy_id = 0; + m_best_known_value = UINT_MAX; + } + unsigned seed() const { return m_seed; } + unsigned cutoff_time() const { return m_cutoff_time; } + unsigned strategy_id() const { return m_strategy_id; } + unsigned best_known_value() const { return m_best_known_value; } + + void set_seed(unsigned s) { m_seed = s; } + void set_cutoff_time(unsigned t) { m_cutoff_time = t; } + void set_strategy_id(unsigned i) { m_strategy_id = i; } + void set_best_known_value(unsigned v) { m_best_known_value = v; } + }; + + class local_search { + typedef svector bool_vector; // data structure for a term in objective function @@ -52,17 +77,33 @@ namespace sat { vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i // parameters of the instance - unsigned num_vars() const { return var_term.size(); } // var index from 1 to num_vars + unsigned num_vars() const { return var_term.size() - 1; } // var index from 1 to num_vars unsigned num_constraints() const { return constraint_term.size(); } // constraint index from 1 to num_constraint // information about the variable int_vector coefficient_in_ob_constraint; // initialized to be 0 - int_vector score; + // int_vector score; int_vector sscore; // slack score + struct var_info { + bool m_conf_change; // whether its configure changes since its last flip + bool m_in_goodvar_stack; + int m_score; + var_info(): + m_conf_change(true), + m_in_goodvar_stack(false), + m_score(0) + {} + }; + svector m_var_info; + + inline int score(unsigned v) const { return m_var_info[v].m_score; } + inline bool already_in_goodvar_stack(unsigned v) const { return m_var_info[v].m_in_goodvar_stack; } + inline bool conf_change(unsigned v) const { return m_var_info[v].m_conf_change; } + int_vector time_stamp; // the flip time stamp - bool_vector conf_change; // whether its configure changes since its last flip + // bool_vector conf_change; int_vector cscc; // how many times its constraint state configure changes since its last flip vector var_neighbor; // all of its neighborhoods variable /* TBD: other scores */ @@ -70,8 +111,8 @@ namespace sat { // information about the constraints int_vector constraint_k; // the right side k of a constraint int_vector constraint_slack; // =constraint_k[i]-true_terms[i], if >=0 then sat - int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing - bool_vector has_true_ob_terms; + //int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing + //bool_vector has_true_ob_terms; // unsat constraint stack int_vector m_unsat_stack; // store all the unsat constraits @@ -79,7 +120,7 @@ namespace sat { // configuration changed decreasing variables (score>0 and conf_change==true) int_vector goodvar_stack; - bool_vector already_in_goodvar_stack; + // bool_vector already_in_goodvar_stack; // information about solution bool_vector cur_solution; // the current solution @@ -92,6 +133,8 @@ namespace sat { // cutoff int cutoff_time = 1; // seconds int max_steps = 2000000000; // < 2147483647 + clock_t start, stop; + double best_time; // for tuning int s_id = 0; // strategy id @@ -101,7 +144,6 @@ namespace sat { void reinit(); void reinit_orig(); - void reinit_greedy(); void init_cur_solution(); void init_slack(); @@ -124,11 +166,35 @@ namespace sat { void display(std::ostream& out); - void unsat(int constraint_id) { m_unsat_stack.push_back(constraint_id); } + void print_info(); + + bool check_goodvar() { + unsigned g = 0; + for (unsigned v = 1; v <= num_vars(); ++v) { + if (conf_change(v) && score(v) > 0) { + ++g; + if (!already_in_goodvar_stack(v)) + std::cout << "3\n"; + } + } + if (g == goodvar_stack.size()) + return true; + else { + if (g < goodvar_stack.size()) + std::cout << "1\n"; + else + std::cout << "2\n"; // delete too many + return false; + } + } void add_clause(unsigned sz, literal const* c); + void unsat(int c) { + m_index_in_unsat_stack[c] = m_unsat_stack.size(); + m_unsat_stack.push_back(c); + } // swap the deleted one with the last one and pop void sat(int c) { int last_unsat_constraint = m_unsat_stack.back(); @@ -143,13 +209,15 @@ namespace sat { ~local_search(); - void add_soft(literal l, double weight); + void add_soft(int l, int weight); void add_cardinality(unsigned sz, literal const* c, unsigned k); lbool operator()(); - + local_search_config& config() { return m_config; } + + local_search_config m_config; }; } diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 53720d094..6128e5e21 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -16,8 +16,8 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea infile.getline(line, 16383); int num_vars, num_constraints; sscanf_s(line, "%d %d", &num_vars, &num_constraints); - //cout << "number of variables: " << num_vars << endl; - //cout << "number of constraints: " << num_constraints << endl; + //std::cout << "number of variables: " << num_vars << '\n'; + //std::cout << "number of constraints: " << num_constraints << '\n'; unsigned_vector coefficients; @@ -44,12 +44,12 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea } for (unsigned i = 0; i < lits.size(); ++i) { - local_search.add_soft(lits[i], coefficients[i]); + local_search.add_soft(lits[i].var(), coefficients[i]); } // read the constraints, one at a time int k; - for (int c = 1; c <= num_constraints; ++c) { + for (int c = 0; c < num_constraints; ++c) { lits.reset(); infile >> cur_term; while (cur_term != 0) { @@ -57,10 +57,12 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea infile >> cur_term; } infile >> k; - local_search.add_cardinality(lits.size(), lits.c_ptr(), static_cast(lits.size() - k)); + //local_search.add_cardinality(lits.size(), lits.c_ptr(), static_cast(lits.size() - k)); + local_search.add_cardinality(lits.size(), lits.c_ptr(), static_cast(k)); } infile.close(); + return true; } @@ -75,9 +77,34 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { sat::local_search local_search(solver); char const* file_name = argv[i + 1]; ++i; + + int v; while (i + 1 < argc) { // set other ad hoc parameters. - std::cout << argv[i + 1] << "\n"; + if (argv[i + 1][0] == '-' && i + 2 < argc) { + switch (argv[i + 1][1]) { + case 's': // seed + v = atoi(argv[i + 2]); + local_search.m_config.set_seed(v); + break; + case 't': // cutoff_time + v = atoi(argv[i + 2]); + local_search.m_config.set_cutoff_time(v); + break; + case 'i': // strategy_id + v = atoi(argv[i + 2]); + local_search.m_config.set_strategy_id(v); + break; + case 'b': // best_known_value + v = atoi(argv[i + 2]); + local_search.m_config.set_best_known_value(v); + break; + default: + ++i; + v = -1; + break; + } + } ++i; } @@ -85,7 +112,7 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { return; } - std::cout << "local instance built\n"; + //std::cout << "local instance built\n"; local_search(); // sat::solver s; From 61920503bd088a94a7802660013c2e907f9b5ab5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 24 Feb 2017 18:13:02 -0800 Subject: [PATCH 0059/1283] hackvector! Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 37 +++++++++++++++++++++++++++++------- src/sat/sat_local_search.h | 20 +++++++++++-------- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 6d99ef47d..b9ae4afdc 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -179,10 +179,12 @@ namespace sat { } void local_search::add_cardinality(unsigned sz, literal const* c, unsigned k) { - unsigned id = constraint_term.size(); - constraint_term.push_back(svector()); + unsigned id = m_num_constraints; + ++m_num_constraints; + // constraint_term.push_back(svector()); for (unsigned i = 0; i < sz; ++i) { - var_term.reserve(c[i].var() + 1); + m_num_vars = std::max(c[i].var() + 1, m_num_vars); + // var_term.reserve(c[i].var() + 1); term t; t.constraint_id = id; t.var_id = c[i].var(); @@ -195,6 +197,9 @@ namespace sat { local_search::local_search(solver& s) { + m_num_vars = 0; + m_num_constraints = 0; + // copy units unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { @@ -329,6 +334,8 @@ namespace sat { void local_search::flip(bool_var flipvar) { + static unsigned_vector hack_vector; + hack_vector.reset(); // already changed truth value!!!! cur_solution[flipvar] = !cur_solution[flipvar]; @@ -360,6 +367,7 @@ namespace sat { ++cscc[v]; //score[v] += constraint_weight[c]; ++m_var_info[v].m_score; + hack_vector.push_back(v); // slack increasing var if (cur_solution[v] == constraint_term[c][j].sense) ++sscore[v]; @@ -392,6 +400,7 @@ namespace sat { if (cur_solution[v] != constraint_term[c][j].sense) { //score[v] += constraint_weight[c]; ++m_var_info[v].m_score; + hack_vector.push_back(v); ++sscore[v]; } } @@ -412,9 +421,11 @@ namespace sat { for (unsigned j = 0; j < constraint_term[c].size(); ++j) { v = constraint_term[c][j].var_id; // flip the slack increasing var will satisfy this constraint - if (cur_solution[v] == constraint_term[c][j].sense) - //score[v] += constraint_weight[c]; - ++m_var_info[v].m_score; + if (cur_solution[v] == constraint_term[c][j].sense) { + //score[v] += constraint_weight[c]; + ++m_var_info[v].m_score; + hack_vector.push_back(v); + } } break; default: @@ -442,6 +453,7 @@ namespace sat { } // update all flipvar's neighbor's conf_change to true, add goodvar/okvar +#if 0 unsigned sz = var_neighbor[flipvar].size(); for (unsigned i = 0; i < sz; ++i) { v = var_neighbor[flipvar][i]; @@ -451,7 +463,18 @@ namespace sat { m_var_info[v].m_in_goodvar_stack = true; } } - +#else + unsigned sz = hack_vector.size(); + for (unsigned i = 0; i < sz; ++i) + { + v = hack_vector[i]; + m_var_info[v].m_conf_change = true; + if (score(v) > 0 && !already_in_goodvar_stack(v)) { + goodvar_stack.push_back(v); + m_var_info[v].m_in_goodvar_stack = true; + } + } +#endif } bool local_search::tie_breaker_sat(bool_var v, bool_var best_var) { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 97e1974f2..2836ac4e3 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -28,14 +28,14 @@ namespace sat { unsigned m_seed; unsigned m_cutoff_time; unsigned m_strategy_id; - unsigned m_best_known_value; + int m_best_known_value; public: local_search_config() { m_seed = 0; m_cutoff_time = 1; m_strategy_id = 0; - m_best_known_value = UINT_MAX; + m_best_known_value = INT_MAX; } unsigned seed() const { return m_seed; } @@ -49,6 +49,9 @@ namespace sat { void set_best_known_value(unsigned v) { m_best_known_value = v; } }; +#define MAX_VARS 5000 +#define MAX_CONSTRAINTS 100 + class local_search { typedef svector bool_vector; @@ -73,12 +76,13 @@ namespace sat { // terms arrays - vector > var_term; // var_term[i][j] means the j'th term of var i - vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i + svector var_term[MAX_VARS]; // var_term[i][j] means the j'th term of var i + svector constraint_term[MAX_CONSTRAINTS]; // constraint_term[i][j] means the j'th term of constraint i + unsigned m_num_vars, m_num_constraints; // parameters of the instance - unsigned num_vars() const { return var_term.size() - 1; } // var index from 1 to num_vars - unsigned num_constraints() const { return constraint_term.size(); } // constraint index from 1 to num_constraint + unsigned num_vars() const { return m_num_vars - 1; } // var index from 1 to num_vars + unsigned num_constraints() const { return m_num_constraints; } // constraint index from 1 to num_constraint // information about the variable @@ -111,7 +115,7 @@ namespace sat { // information about the constraints int_vector constraint_k; // the right side k of a constraint int_vector constraint_slack; // =constraint_k[i]-true_terms[i], if >=0 then sat - //int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing + //int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing //bool_vector has_true_ob_terms; // unsat constraint stack @@ -126,7 +130,7 @@ namespace sat { bool_vector cur_solution; // the current solution int objective_value; // the objective function value corresponds to the current solution bool_vector best_solution; // the best solution so far - int best_objective_value = 0; // the objective value corresponds to the best solution so far + int best_objective_value = -1; // the objective value corresponds to the best solution so far // for non-known instance, set as maximal int best_known_value = INT_MAX; // best known value for this instance From 52d2d63623afef3a774d3d6090e788367bcaa664 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 Feb 2017 16:19:45 -0800 Subject: [PATCH 0060/1283] working on lookahead Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 372 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 371 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index c7acb2bb0..d5f9ce5aa 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -8,6 +8,7 @@ Module Name: Abstract: Lookahead SAT solver in the style of March. + Thanks also to the presentation in sat11.w. Author: @@ -158,6 +159,114 @@ namespace sat { // pre-selection // see also 91 - 102 sat11.w + struct candidate { + bool_var m_var; + float m_rating; + candidate(bool_var v, float r): m_var(v), m_rating(r) {} + }; + svector m_candidates; + + float get_rating(bool_var v) const { return m_rating[v]; } + float get_rating(literal l) const { return get_rating(l.var()); } + + bool_var select(unsigned level) { + init_pre_selection(level); + unsigned max_num_cand = level == 0 ? m_freevars.size() : m_config.m_level_cand / level; + max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand); + + float sum = 0; + for (bool newbies = false; ; newbies = true) { + sum = init_candidates(level, newbies); + if (!m_candidates.empty()) break; + if (is_sat()) { + return null_bool_var; + } + } + SASSERT(!m_candidates.empty()); + // cut number of candidates down to max_num_cand. + // step 1. cut it to at most 2*max_num_cand. + // step 2. use a heap to sift through the rest. + bool progress = true; + while (progress && m_candidates.size() >= max_num_cand * 2) { + progress = false; + float mean = sum / (float)(m_candidates.size() + 0.0001); + sum = 0; + for (unsigned i = 0; i < m_candidates.size(); ++i) { + if (m_candidates[i].m_rating >= mean) { + sum += m_candidates[i].m_rating; + } + else { + m_candidates[i] = m_candidates.back(); + m_candidates.pop_back(); + --i; + progress = true; + } + } + } + SASSERT(!m_candidates.empty()); + if (m_candidates.size() > max_num_cand) { + unsigned j = m_candidates.size()/2; + while (j > 0) { + --j; + sift_up(j); + } + while (true) { + m_candidates[0] = m_candidates.back(); + m_candidates.pop_back(); + if (m_candidates.size() == max_num_cand) break; + sift_up(0); + } + } + SASSERT(!m_candidates.empty() && m_candidates.size() <= max_num_cand); + } + + void sift_up(unsigned j) { + unsigned i = j; + candidate c = m_candidates[j]; + for (unsigned k = 2*j + 1; k < m_candidates.size(); i = k, k = 2*k + 1) { + // pick largest parent + if (k + 1 < m_candidates.size() && m_candidates[k].m_rating < m_candidates[k+1].m_rating) { + ++k; + } + if (c.m_rating <= m_candidates[k].m_rating) break; + m_candidates[i] = m_candidates[k]; + } + if (i > j) m_candidates[i] = c; + } + + float init_candidates(unsigned level, bool newbies) { + m_candidates.reset(); + float sum = 0; + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + bool_var x = *it; + if (!newbies) { + // TBD filter out candidates based on prefix strings or similar method + } + m_candidates.push_back(candidate(x, m_rating[x])); + sum += m_rating[x]; + } + return sum; + } + + bool is_sat() const { + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + literal l(*it, false); + literal_vector const& lits1 = m_binary[l.index()]; + for (unsigned i = 0; i < lits1.size(); ++i) { + if (!is_true(lits1[i])) return false; + } + literal_vector const& lits2 = m_binary[(~l).index()]; + for (unsigned i = 0; i < lits2.size(); ++i) { + if (!is_true(lits2[i])) return false; + } + } + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause& c = *m_clauses[i]; + if (!is_true(c[0]) && !is_true(c[1])) return false; + } + return true; + } + void init_pre_selection(unsigned level) { unsigned max_level = m_config.m_max_hlevel; if (level <= 1) { @@ -215,7 +324,7 @@ namespace sat { if (is_free(*it)) sum += h[it->index()]; } // TBD walk ternary clauses. - sum = 0.1 + afactor*sum + sqfactor*tsum; + sum = (float)(0.1 + afactor*sum + sqfactor*tsum); return std::min(m_config.m_max_score, sum); } @@ -226,6 +335,264 @@ namespace sat { return false; // TBD track variables that are units } + // ------------------------------------ + // Implication graph + // Compute implication ordering and strongly connected components. + // sat11.w 103 - 114. + + struct arcs : public literal_vector {}; + // Knuth uses a shared pool of fixed size for arcs. + // Should it be useful we could use this approach tooo + // by changing the arcs abstraction and associated functions. + + struct dfs_info { + unsigned m_rank; + unsigned m_height; + literal m_parent; + arcs m_next; + unsigned m_nextp; + literal m_link; + literal m_min; + literal m_vcomp; + dfs_info() { reset(); } + void reset() { + m_rank = 0; + m_height = 0; + m_parent = null_literal; + m_next.reset(); + m_link = null_literal; + m_min = null_literal; + m_vcomp = null_literal; + m_nextp = 0; + } + }; + + literal m_active; + unsigned m_rank; + literal m_settled; + vector m_dfs; + + void get_scc() { + init_scc(); + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal lit(m_candidates[i].m_var, false); + if (get_rank(lit) == 0) get_scc(lit); + if (get_rank(~lit) == 0) get_scc(~lit); + } + } + void init_scc() { + inc_bstamp(); + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal lit(m_candidates[i].m_var, false); + init_dfs_info(lit); + init_dfs_info(~lit); + } + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal lit(m_candidates[i].m_var, false); + init_arcs(lit); + init_arcs(~lit); + } + // set nextp = 0? + m_rank = 0; + m_active = null_literal; + } + void init_dfs_info(literal l) { + unsigned idx = l.index(); + m_dfs[idx].reset(); + set_bstamp(l); + } + // arcs are added in the opposite direction of implications. + // So for implications l => u we add arcs u -> l + void init_arcs(literal l) { + literal_vector const& succ = m_binary[l.index()]; + for (unsigned i = 0; i < succ.size(); ++i) { + literal u = succ[i]; + SASSERT(u != l); + if (u.index() > l.index() && is_stamped(u)) { + add_arc(~l, ~u); + add_arc( u, l); + } + } + } + void add_arc(literal u, literal v) { m_dfs[u.index()].m_next.push_back(v); } + bool has_arc(literal v) const { + return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp; + } + literal pop_arc(literal u) { return m_dfs[u.index()].m_next[m_dfs[u.index()].m_nextp++]; } + unsigned num_next(literal u) const { return m_dfs[u.index()].m_next.size(); } + literal get_next(literal u, unsigned i) const { return m_dfs[u.index()].m_next[i]; } + literal get_min(literal v) const { return m_dfs[v.index()].m_min; } + unsigned get_rank(literal v) const { return m_dfs[v.index()].m_rank; } + unsigned get_height(literal v) const { return m_dfs[v.index()].m_height; } + literal get_parent(literal u) const { return m_dfs[u.index()].m_parent; } + literal get_link(literal u) const { return m_dfs[u.index()].m_link; } + literal get_vcomp(literal u) const { return m_dfs[u.index()].m_vcomp; } + void set_link(literal v, literal u) { m_dfs[v.index()].m_link = u; } + void set_min(literal v, literal u) { m_dfs[v.index()].m_min = u; } + void set_rank(literal v, unsigned r) { m_dfs[v.index()].m_rank = r; } + void set_height(literal v, unsigned h) { m_dfs[v.index()].m_height = h; } + void set_parent(literal v, literal p) { m_dfs[v.index()].m_parent = p; } + void set_vcomp(literal v, literal u) { m_dfs[v.index()].m_vcomp = u; } + void get_scc(literal v) { + set_parent(v, null_literal); + activate_scc(v); + literal u; + do { + literal ll = get_min(v); + if (!has_arc(v)) { + u = get_parent(v); + if (v == ll) { + found_scc(v); + } + else if (get_rank(ll) < get_rank(get_min(u))) { + set_min(u, ll); + } + v = u; + } + else { + literal u = pop_arc(v); + unsigned r = get_rank(u); + if (r > 0) { + if (r < get_rank(ll)) set_min(v, u); + } + else { + set_parent(u, v); + v = u; + activate_scc(v); + } + } + } + while (v != null_literal); + } + void activate_scc(literal l) { + SASSERT(get_rank(l) == 0); + set_rank(l, ++m_rank); + set_link(l, m_active); + set_min(l, l); + m_active = l; + } + // make v root of the scc equivalence class + // set vcomp to be the highest rated literal + void found_scc(literal v) { + literal t = m_active; + m_active = get_link(v); + literal best = v; + float best_rating = get_rating(v); + set_rank(v, UINT_MAX); + while (t != v) { + SASSERT(t != ~v); + set_rank(t, UINT_MAX); + set_parent(t, v); + float t_rating = get_rating(t); + if (t_rating > best_rating) { + best = t; + best_rating = t_rating; + } + t = get_link(t); + } + set_parent(v, v); + set_vcomp(v, best); + if (get_rank(~v) == UINT_MAX) { + set_vcomp(v, ~get_vcomp(get_parent(~v))); // TBD check semantics + } + } + + // ------------------------------------ + // lookahead forest + // sat11.w 115-121 + + literal m_root_child; + + literal get_child(literal u) const { + if (u == null_literal) return m_root_child; + return m_dfs[u.index()].m_min; + } + void set_child(literal v, literal u) { + if (v == null_literal) m_root_child = u; + else m_dfs[v.index()].m_min = u; + } + + void construct_forest() { + find_heights(); + construct_lookahead_table(); + } + void find_heights() { + literal pp = null_literal; + set_child(pp, null_literal); + unsigned h = 0; + literal w; + for (literal u = m_settled; u != null_literal; u = get_link(u)) { + literal p = get_parent(u); + if (p != pp) { + h = 0; + w = null_literal; + pp = p; + } + for (unsigned j = 0; j < num_next(~u); ++j) { + literal v = ~get_next(~u, j); + literal pv = get_parent(v); + if (pv == p) continue; + unsigned hh = get_height(pv); + if (hh >= h) { + h = hh + 1; + w = pv; + } + } + if (p == u) { // u is an equivalence class representative + literal v = get_child(w); + set_height(u, h); + set_child(u, null_literal); + set_link(u, v); + set_child(w, u); + } + } + } + struct literal_offset { + literal m_lit; + unsigned m_offset; + literal_offset(literal l): m_lit(l), m_offset(0) {} + }; + svector m_lookahead; + void set_offset(unsigned idx, unsigned offset) { + m_lookahead[idx].m_offset = offset; + } + void set_lookahead(literal l) { + m_lookahead.push_back(literal_offset(l)); + } + void construct_lookahead_table() { + literal u = get_child(null_literal), v = null_literal; + unsigned offset = 0; + m_lookahead.reset(); + while (u != null_literal) { + set_rank(u, m_lookahead.size()); + set_lookahead(get_vcomp(u)); + if (null_literal != get_child(u)) { + set_parent(u, v); + v = u; + u = get_child(u); + } + else { + while (true) { + set_offset(get_rank(u), offset); + offset += 2; + set_parent(u, v == null_literal ? v : get_vcomp(v)); + u = get_link(u); + if (u == null_literal && v != null_literal) { + u = v; + v = get_parent(u); + } + else { + break; + } + } + } + } + SASSERT(2*m_lookahead.size() == offset); + TRACE("sat", for (unsigned i = 0; i < m_lookahead.size(); ++i) + tout << m_lookahead[i].m_lit << " : " << m_lookahead[i].m_offset << "\n";); + } + + // ------------------------------------ // initialization @@ -239,6 +606,8 @@ namespace sat { m_bstamp.push_back(0); m_bstamp.push_back(0); m_rating.push_back(0); + m_dfs.push_back(dfs_info()); + m_dfs.push_back(dfs_info()); } void init() { @@ -535,6 +904,7 @@ namespace sat { bool is_fixed(literal l) const { return value(l) != l_undef; } bool is_contrary(literal l) const { return value(l) == l_false; } + bool is_true(literal l) const { return value(l) == l_true; } void set_conflict() { m_inconsistent = true; } lbool value(literal l) const { return static_cast(m_assignment[l.index()]); } unsigned scope_lvl() const { return m_trail_lim.size(); } From 4e85a6e8fd2a99dfb9413c96cd13eff6cef60fe4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 Feb 2017 16:25:06 -0800 Subject: [PATCH 0061/1283] merge with master Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 90 +++++------------------------------------ 1 file changed, 10 insertions(+), 80 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index d5f9ce5aa..45db956fc 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -830,22 +830,21 @@ namespace sat { } bool choose1(literal& l) { - literal_vector P; - pre_select(P); + l = null_literal; - if (P.empty()) { + if (m_lookahead.empty()) { return true; } unsigned h = 0, count = 1; - for (unsigned i = 0; i < P.size(); ++i) { - literal lit = P[i]; + for (unsigned i = 0; i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; push(lit); - if (do_double()) double_look(P); + if (do_double()) double_look(); if (inconsistent()) { pop(); assign(~lit); - if (do_double()) double_look(P); + if (do_double()) double_look(); if (inconsistent()) return true; continue; } @@ -853,7 +852,7 @@ namespace sat { pop(); push(~lit); - if (do_double()) double_look(P); + if (do_double()) double_look(); bool unsat2 = inconsistent(); unsigned diff2 = diff(); pop(); @@ -876,10 +875,10 @@ namespace sat { return l != null_literal; } - void double_look(literal_vector const& P) { + void double_look() { bool unsat; - for (unsigned i = 0; !inconsistent() && i < P.size(); ++i) { - literal lit = P[i]; + for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; if (value(lit) != l_undef) continue; push(lit); @@ -927,75 +926,6 @@ namespace sat { void set_inconsistent() { m_inconsistent = true; } bool inconsistent() { return m_inconsistent; } - void pre_select(literal_vector& P) { - select_variables(P); - order_by_implication_trees(P); - } - - void order_by_implication_trees(literal_vector& P) { - literal_set roots; - literal_vector nodes, parent; - - // - // Extract binary clauses in watch list. - // Produce implication graph between literals in P. - // - - for (unsigned i = 0; i < P.size(); ++i) { - literal lit1 = P[i], lit2; - - // - // lit2 => lit1, where lit2 is a root. - // make lit1 a root instead of lit2 - // - - literal_vector const& lits1 = m_binary[(~lit1).index()]; - unsigned sz = lits1.size(); - for (unsigned i = 0; i < sz; ++i) { - literal lit2 = lits1[i]; - if (roots.contains(~lit2)) { - // ~lit2 => lit1 - // if lit2 is a root, put it under lit2 - parent.setx((~lit2).index(), lit1, null_literal); - roots.remove(~lit2); - roots.insert(lit1); - goto found; - } - } - - // - // lit1 => lit2.n - // if lit2 is a node, put lit1 above lit2 - // - - literal_vector const& lits2 = m_binary[(~lit2).index()]; - sz = lits2.size(); - for (unsigned i = 0; i < sz; ++i) { - literal lit2 = lits2[i]; - if (nodes.contains(lit2)) { - // lit1 => lit2 - parent.setx(lit1.index(), lit2, null_literal); - nodes.insert(lit1); - goto found; - } - } - nodes.push_back(lit1); - roots.insert(lit1); - found: - ; - } - TRACE("sat", - tout << "implication trees\n"; - for (unsigned i = 0; i < parent.size(); ++i) { - literal p = parent[i]; - if (p != null_literal) { - tout << to_literal(i) << " |-> " << p << "\n"; - } - }); - - // TBD: extract ordering. - - } void select_variables(literal_vector& P) { for (unsigned i = 0; i < s.num_vars(); ++i) { From 388b025d9ed119a15b6c420a2800a30919d45bd8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 Feb 2017 16:29:46 -0800 Subject: [PATCH 0062/1283] expose xor solver separate from cardinality solver Signed-off-by: Nikolaj Bjorner --- src/sat/sat_params.pyg | 4 ++-- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 5e68d2f42..97497a220 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -26,6 +26,6 @@ def_module_params('sat', ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), - ('cardinality.solver', BOOL, False, 'use cardinality/xor solver'), - ('cliff', UINT, 0, 'my favorite parameter'), + ('cardinality.solver', BOOL, False, 'use cardinality solver'), + ('xor.solver', BOOL, False, 'use xor solver'), )) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 83b8362cf..0c0f82537 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -217,7 +217,7 @@ public: sat_params p1(p); m_params.set_bool("elim_vars", false); m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); - m_params.set_bool("cardinality_solver", p1.cardinality_solver()); + m_params.set_bool("xor_solver", p1.xor_solver()); m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 8530a9d76..5e5625049 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -65,7 +65,7 @@ struct goal2sat::imp { expr_ref_vector m_trail; expr_ref_vector m_interpreted_atoms; bool m_default_external; - bool m_cardinality_solver; + bool m_xor_solver; imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external): m(_m), @@ -82,9 +82,9 @@ struct goal2sat::imp { } void updt_params(params_ref const & p) { - m_ite_extra = p.get_bool("ite_extra", true); - m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); - m_cardinality_solver = p.get_bool("cardinality_solver", false); + m_ite_extra = p.get_bool("ite_extra", true); + m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + m_xor_solver = p.get_bool("xor_solver", false); } void throw_op_not_handled(std::string const& s) { @@ -560,7 +560,7 @@ struct goal2sat::imp { unsigned get_num_args(app* t) { - if (m.is_iff(t) && m_cardinality_solver) { + if (m.is_iff(t) && m_xor_solver) { unsigned n = 2; while (m.is_iff(t->get_arg(1))) { ++n; @@ -574,7 +574,7 @@ struct goal2sat::imp { } expr* get_arg(app* t, unsigned idx) { - if (m.is_iff(t) && m_cardinality_solver) { + if (m.is_iff(t) && m_xor_solver) { while (idx >= 1) { SASSERT(m.is_iff(t)); t = to_app(t->get_arg(1)); From 88e7c240b721a552cccb5a40d8f1f55576cc11d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Feb 2017 10:59:59 -0800 Subject: [PATCH 0063/1283] working on lookahead Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.h | 4 + src/sat/sat_lookahead.h | 338 ++++++++++++++++++++++++++++--------- src/sat/sat_solver.cpp | 20 ++- src/sat/sat_solver.h | 5 + 4 files changed, 280 insertions(+), 87 deletions(-) diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 2836ac4e3..65138f68e 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -219,6 +219,10 @@ namespace sat { lbool operator()(); + lbool check(unsigned sz, literal const* assumptions) { return l_undef; } // TBD + + void cancel() {} // TBD + local_search_config& config() { return m_config; } local_search_config m_config; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 45db956fc..5921e4588 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -31,6 +31,7 @@ namespace sat { unsigned m_max_hlevel; unsigned m_min_cutoff; unsigned m_level_cand; + float m_delta_rho; config() { m_max_hlevel = 50; @@ -38,15 +39,39 @@ namespace sat { m_max_score = 20.0; m_min_cutoff = 30; m_level_cand = 600; + m_delta_rho = (float)0.9995; } }; + struct prefix { + unsigned m_prefix; + unsigned m_length; + prefix(): m_prefix(0), m_length(0) {} + }; + + struct lit_info { + float m_wnb; + unsigned m_double_lookahead; + lit_info(): m_wnb(0), m_double_lookahead(0) {} + }; + struct statistics { unsigned m_propagations; statistics() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; + enum search_mode { + searching, // normal search + lookahead1, // lookahead mode + lookahead2 // double lookahead + }; + + struct ternary { + ternary(literal u, literal v, literal w): m_u(u), m_v(v), m_w(w) {} + literal m_u, m_v, m_w; + }; + config m_config; double m_delta_trigger; @@ -60,15 +85,25 @@ namespace sat { unsigned m_qhead; // propagation queue head unsigned_vector m_qhead_lim; clause_vector m_clauses; // non-binary clauses + clause_vector m_retired_clauses; // clauses that were removed during search + svector m_retired_ternary; // + unsigned_vector m_retired_clause_lim; clause_allocator m_cls_allocator; bool m_inconsistent; unsigned_vector m_bstamp; // literal: timestamp for binary implication vector > m_H; // literal: fitness score + svector* m_heur; // current fitness svector m_rating; // var: pre-selection rating unsigned m_bstamp_id; // unique id for binary implication. + unsigned m_istamp_id; // unique id for managing double lookaheads char_vector m_assignment; // literal: assignment vector m_watches; // literal: watch structure + svector m_lits; // literal: attributes. + float m_weighted_new_binaries; // metric associated with current lookahead1 literal. + svector m_prefix; // var: prefix where variable participates in propagation indexed_uint_set m_freevars; + svector m_search_modes; // stack of modes + search_mode m_search_mode; // mode of search statistics m_stats; void add_binary(literal l1, literal l2) { @@ -97,6 +132,15 @@ namespace sat { m_bstamp.fill(0); } } + void inc_istamp() { + ++m_istamp_id; + if (m_istamp_id == 0) { + ++m_istamp_id; + for (unsigned i = 0; i < m_lits.size(); ++i) { + m_lits[i].m_double_lookahead = 0; + } + } + } void set_bstamp(literal l) { m_bstamp[l.index()] = m_bstamp_id; } @@ -159,6 +203,15 @@ namespace sat { // pre-selection // see also 91 - 102 sat11.w + void pre_select() { + m_lookahead.reset(); + if (select(scope_lvl())) { + get_scc(); + find_heights(); + construct_lookahead_table(); + } + } + struct candidate { bool_var m_var; float m_rating; @@ -169,7 +222,7 @@ namespace sat { float get_rating(bool_var v) const { return m_rating[v]; } float get_rating(literal l) const { return get_rating(l.var()); } - bool_var select(unsigned level) { + bool select(unsigned level) { init_pre_selection(level); unsigned max_num_cand = level == 0 ? m_freevars.size() : m_config.m_level_cand / level; max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand); @@ -179,7 +232,7 @@ namespace sat { sum = init_candidates(level, newbies); if (!m_candidates.empty()) break; if (is_sat()) { - return null_bool_var; + return false; } } SASSERT(!m_candidates.empty()); @@ -218,6 +271,7 @@ namespace sat { } } SASSERT(!m_candidates.empty() && m_candidates.size() <= max_num_cand); + return true; } void sift_up(unsigned j) { @@ -238,12 +292,13 @@ namespace sat { m_candidates.reset(); float sum = 0; for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + SASSERT(l_undef == value(*it)); bool_var x = *it; if (!newbies) { // TBD filter out candidates based on prefix strings or similar method } m_candidates.push_back(candidate(x, m_rating[x])); - sum += m_rating[x]; + sum += m_rating[x]; } return sum; } @@ -277,17 +332,17 @@ namespace sat { h_scores(m_H[i + 1], m_H[(i + 2) % 3]); } } - // heur = m_H[1]; + m_heur = &m_H[1]; } else if (level < max_level) { ensure_H(level); h_scores(m_H[level-1], m_H[level]); - // heur = m_H[level]; + m_heur = &m_H[level]; } else { ensure_H(max_level); h_scores(m_H[max_level-1], m_H[max_level]); - // heur = m_H[max_level]; + m_heur = &m_H[max_level]; } } @@ -415,9 +470,7 @@ namespace sat { } } void add_arc(literal u, literal v) { m_dfs[u.index()].m_next.push_back(v); } - bool has_arc(literal v) const { - return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp; - } + bool has_arc(literal v) const { return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp; } literal pop_arc(literal u) { return m_dfs[u.index()].m_next[m_dfs[u.index()].m_nextp++]; } unsigned num_next(literal u) const { return m_dfs[u.index()].m_next.size(); } literal get_next(literal u, unsigned i) const { return m_dfs[u.index()].m_next[i]; } @@ -512,10 +565,6 @@ namespace sat { else m_dfs[v.index()].m_min = u; } - void construct_forest() { - find_heights(); - construct_lookahead_table(); - } void find_heights() { literal pp = null_literal; set_child(pp, null_literal); @@ -562,7 +611,7 @@ namespace sat { void construct_lookahead_table() { literal u = get_child(null_literal), v = null_literal; unsigned offset = 0; - m_lookahead.reset(); + SASSERT(m_lookahead.empty()); while (u != null_literal) { set_rank(u, m_lookahead.size()); set_lookahead(get_vcomp(u)); @@ -591,7 +640,41 @@ namespace sat { TRACE("sat", for (unsigned i = 0; i < m_lookahead.size(); ++i) tout << m_lookahead[i].m_lit << " : " << m_lookahead[i].m_offset << "\n";); } - + + // ------------------------------------ + // clause management + + void attach_clause(clause& c) { + if (false && c.size() == 3) { // disable ternary clauses + m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); + m_watches[(~c[1]).index()].push_back(watched(c[0], c[2])); + m_watches[(~c[2]).index()].push_back(watched(c[0], c[1])); + } + else { + literal block_lit = c[c.size() >> 2]; + clause_offset cls_off = m_cls_allocator.get_offset(&c); + m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); + m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); + SASSERT(value(c[0]) == l_undef); + SASSERT(value(c[1]) == l_undef); + } + } + + void detach_clause(clause& c) { + clause_offset cls_off = m_cls_allocator.get_offset(&c); + m_retired_clauses.push_back(&c); + erase_clause_watch(get_wlist(~c[0]), cls_off); + erase_clause_watch(get_wlist(~c[1]), cls_off); + } + + void detach_ternary(literal l1, literal l2, literal l3) { + m_retired_ternary.push_back(ternary(l1, l2, l3)); + erase_ternary_watch(get_wlist(~l1), l2, l3); + erase_ternary_watch(get_wlist(~l2), l1, l3); + erase_ternary_watch(get_wlist(~l3), l1, l2); + } + + watch_list& get_wlist(literal l) { return m_watches[l.index()]; } // ------------------------------------ // initialization @@ -608,6 +691,10 @@ namespace sat { m_rating.push_back(0); m_dfs.push_back(dfs_info()); m_dfs.push_back(dfs_info()); + m_lits.push_back(lit_info()); + m_lits.push_back(lit_info()); + m_prefix.push_back(prefix()); + m_freevars.insert(v); } void init() { @@ -642,8 +729,9 @@ namespace sat { clause_vector::const_iterator end = s.m_clauses.end(); for (; it != end; ++it) { clause& c = *(*it); - m_clauses.push_back(m_cls_allocator.mk_clause(c.size(), c.begin(), false)); - // TBD: add watch + clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); + m_clauses.push_back(c1); + attach_clause(c); } // copy units @@ -654,18 +742,38 @@ namespace sat { assign(l); } } + + // ------------------------------------ + // search - void push(literal lit) { + void push(literal lit, search_mode mode) { m_binary_trail_lim.push_back(m_binary_trail.size()); m_units_lim.push_back(m_units.size()); m_trail_lim.push_back(m_trail.size()); + m_retired_clause_lim.push_back(m_retired_clauses.size()); m_qhead_lim.push_back(m_qhead); m_trail.push_back(lit); + m_search_modes.push_back(m_search_mode); + m_search_mode = mode; assign(lit); propagate(); } void pop() { + m_inconsistent = false; + + // search mode + m_search_mode = m_search_modes.back(); + m_search_modes.pop_back(); + + // unretire clauses + unsigned rsz = m_retired_clause_lim.back(); + for (unsigned i = rsz; i < m_retired_clauses.size(); ++i) { + attach_clause(*m_retired_clauses[i]); + } + m_retired_clauses.resize(rsz); + m_retired_clause_lim.pop_back(); + // remove local binary clauses unsigned old_sz = m_binary_trail_lim.back(); m_binary_trail_lim.pop_back(); @@ -673,24 +781,31 @@ namespace sat { del_binary(m_binary_trail[i]); } + // undo assignments + for (unsigned i = m_trail.size(); i > m_trail_lim.size(); ) { + --i; + literal l = m_trail[i]; + m_freevars.insert(l.var()); + m_assignment[l.index()] = l_undef; + m_assignment[(~l).index()] = l_undef; + } + m_trail.shrink(m_trail_lim.size()); // reset assignment. + m_trail_lim.pop_back(); + // add implied binary clauses unsigned new_unit_sz = m_units_lim.back(); for (unsigned i = new_unit_sz; i < m_units.size(); ++i) { - add_binary(~m_trail.back(), m_units[i]); + try_add_binary(~m_trail.back(), m_units[i]); } m_units.shrink(new_unit_sz); m_units_lim.pop_back(); - m_trail.shrink(m_trail_lim.size()); // reset assignment. - m_trail_lim.pop_back(); + + // reset propagation queue m_qhead_lim.pop_back(); m_qhead = m_qhead_lim.back(); + } - m_inconsistent = false; - } - - unsigned diff() const { return m_units.size() - m_units_lim.back(); } - - unsigned mix_diff(unsigned l, unsigned r) const { return l + r + (1 << 10) * l * r; } + float mix_diff(float l, float r) const { return l + r + (1 << 10) * l * r; } clause const& get_clause(watch_list::iterator it) const { clause_offset cls_off = it->get_clause_offset(); @@ -715,6 +830,7 @@ namespace sat { UNREACHABLE(); break; case watched::TERNARY: { + UNREACHABLE(); // we avoid adding ternary clauses for now. literal l1 = it->get_literal1(); literal l2 = it->get_literal2(); lbool val1 = value(l1); @@ -731,7 +847,17 @@ namespace sat { set_conflict(); } else if (val1 == l_undef && val2 == l_undef) { - // TBD: the clause has become binary. + switch (m_search_mode) { + case searching: + detach_ternary(l, l1, l2); + try_add_binary(l1, l2); + break; + case lookahead1: + m_weighted_new_binaries += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + break; + case lookahead2: + break; + } } *it2 = *it; it2++; @@ -750,29 +876,37 @@ namespace sat { } literal * l_it = c.begin() + 2; literal * l_end = c.end(); - unsigned found = 0; - for (; l_it != l_end && found < 2; ++l_it) { + bool found = false; + for (; l_it != l_end && !found; ++l_it) { if (value(*l_it) != l_false) { - ++found; - if (found == 2) { - break; - } - else { - c[1] = *l_it; - *l_it = ~l; - m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); - } + found = true; + c[1] = *l_it; + *l_it = ~l; + m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); } } - if (found == 1) { - // TBD: clause has become binary + if (found) { + found = false; + for (; l_it != l_end && !found; ++l_it) { + found = value(*l_it) != l_false; + } + // normal clause was converted to a binary clause. + if (!found && value(c[1]) == l_undef && value(c[0]) == l_undef) { + switch (m_search_mode) { + case searching: + detach_clause(c); + try_add_binary(c[0], c[1]); + break; + case lookahead1: + m_weighted_new_binaries += (*m_heur)[c[0].index()]* (*m_heur)[c[1].index()]; + break; + case lookahead2: + break; + } + } break; } - if (found > 1) { - // not a binary clause - break; - } - else if (value(c[0]) == l_false) { + if (value(c[0]) == l_false) { set_conflict(); } else { @@ -829,41 +963,57 @@ namespace sat { return l; } + // TBD: + // Handle scope properly for nested implications. + // Suppose u -> v, and u -> w and we process v first, then the + // consequences of v should remain when processing u. + // March and sat11.w solve this by introducing timestamps on truth values. + // regular push/pop doesn't really work here: we basically need a traversal of the + // lookahead tree and push/pop according to that (or adapt timestamps) + // bool choose1(literal& l) { - + pre_select(); l = null_literal; if (m_lookahead.empty()) { return true; } - unsigned h = 0, count = 1; - for (unsigned i = 0; i < m_lookahead.size(); ++i) { + float h = 0; + unsigned count = 1; + for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; + if (value(lit) != l_undef) { + continue; + } + SASSERT(value(lit) == l_undef); + SASSERT(!inconsistent()); - push(lit); - if (do_double()) double_look(); + reset_wnb(lit); + push(lit, lookahead1); + do_double(lit); if (inconsistent()) { pop(); assign(~lit); - if (do_double()) double_look(); - if (inconsistent()) return true; + propagate(); continue; } - unsigned diff1 = diff(); + update_wnb(lit); + float diff1 = m_weighted_new_binaries; pop(); - push(~lit); - if (do_double()) double_look(); - bool unsat2 = inconsistent(); - unsigned diff2 = diff(); - pop(); - - if (unsat2) { + reset_wnb(~lit); + push(~lit, lookahead1); + do_double(~lit); + if (inconsistent()) { + pop(); assign(lit); + propagate(); continue; } + update_wnb(~lit); + float diff2 = m_weighted_new_binaries; + pop(); - unsigned mixd = mix_diff(diff1, diff2); - + float mixd = mix_diff(diff1, diff2); if (mixd > h || (mixd == h && s.m_rand(count) == 0)) { CTRACE("sat", l != null_literal, tout << lit << " diff1: " << diff1 << " diff2: " << diff2 << "\n";); @@ -872,7 +1022,30 @@ namespace sat { l = diff1 < diff2 ? lit : ~lit; } } - return l != null_literal; + return l != null_literal || inconsistent(); + } + + void set_wnb(literal l, float f) { m_lits[l.index()].m_wnb = f; } + void inc_wnb(literal l, float f) { m_lits[l.index()].m_wnb += f; } + float get_wnb(literal l) const { return m_lits[l.index()].m_wnb; } + bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; } + void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } + + void reset_wnb(literal l) { + m_weighted_new_binaries = 0; + + // inherit propagation effect from parent. + literal p = get_parent(l); + set_wnb(l, p == null_literal ? 0 : get_wnb(p)); + } + + void update_wnb(literal l) { + if (m_weighted_new_binaries == 0) { + // TBD autarky + } + else { + inc_wnb(l, m_weighted_new_binaries); + } } void double_look() { @@ -881,7 +1054,7 @@ namespace sat { literal lit = m_lookahead[i].m_lit; if (value(lit) != l_undef) continue; - push(lit); + push(lit, lookahead2); unsat = inconsistent(); pop(); if (unsat) { @@ -890,7 +1063,7 @@ namespace sat { continue; } - push(~lit); + push(~lit, lookahead2); unsat = inconsistent(); pop(); if (unsat) { @@ -898,7 +1071,6 @@ namespace sat { assign(lit); } } - update_delta_trigger(); } bool is_fixed(literal l) const { return value(l) != l_undef; } @@ -906,6 +1078,7 @@ namespace sat { bool is_true(literal l) const { return value(l) == l_true; } void set_conflict() { m_inconsistent = true; } lbool value(literal l) const { return static_cast(m_assignment[l.index()]); } + lbool value(bool_var v) const { return value(literal(v, false)); } unsigned scope_lvl() const { return m_trail_lim.size(); } void assign(literal l) { @@ -919,14 +1092,13 @@ namespace sat { m_assignment[l.index()] = l.sign() ? l_false : l_true; m_assignment[(~l).index()] = l.sign() ? l_false : l_true; m_trail.push_back(l); + m_freevars.remove(l.var()); break; } } - void set_inconsistent() { m_inconsistent = true; } bool inconsistent() { return m_inconsistent; } - void select_variables(literal_vector& P) { for (unsigned i = 0; i < s.num_vars(); ++i) { if (value(literal(i,false)) == l_undef) { @@ -935,19 +1107,16 @@ namespace sat { } } - bool do_double() { - return !inconsistent() && diff() > m_delta_trigger; - } - - void update_delta_trigger() { - if (inconsistent()) { - m_delta_trigger -= (1 - m_config.m_dl_success) / m_config.m_dl_success; - } - else { - m_delta_trigger += 1; - } - if (m_delta_trigger >= s.num_vars()) { - // reset it. + void do_double(literal l) { + if (!inconsistent() && scope_lvl() > 0 && dl_enabled(l)) { + if (get_wnb(l) > m_delta_trigger) { + double_look(); + m_delta_trigger = get_wnb(l); + dl_disable(l); + } + else { + m_delta_trigger *= m_config.m_delta_rho; + } } } @@ -961,8 +1130,9 @@ namespace sat { lbool search() { literal_vector trail; - + m_search_mode = searching; while (true) { + inc_istamp(); s.checkpoint(); literal l = choose(); if (inconsistent()) { @@ -973,7 +1143,7 @@ namespace sat { return l_true; } TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); - push(l); + push(l, searching); trail.push_back(l); } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 740eea371..50e046905 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -782,7 +782,7 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); - if (m_config.m_num_threads > 1 && !m_par) { + if ((m_config.m_num_threads > 1 || m_local_search) && !m_par) { return check_par(num_lits, lits); } flet _searching(m_searching, true); @@ -854,9 +854,17 @@ namespace sat { ERROR_EX }; + local_search& solver::init_local_search() { + if (!m_local_search) { + m_local_search = alloc(local_search, *this); + } + return *m_local_search.get(); + } + + lbool solver::check_par(unsigned num_lits, literal const* lits) { int num_threads = static_cast(m_config.m_num_threads); - int num_extra_solvers = num_threads - 1; + int num_extra_solvers = num_threads - 1 + (m_local_search ? 1 : 0); sat::parallel par(*this); par.reserve(num_threads, 1 << 12); par.init_solvers(*this, num_extra_solvers); @@ -870,7 +878,10 @@ namespace sat { for (int i = 0; i < num_threads; ++i) { try { lbool r = l_undef; - if (i < num_extra_solvers) { + if (m_local_search && i + 1 == num_extra_solvers) { + r = m_local_search->check(num_lits, lits); + } + else if (i < num_extra_solvers) { r = par.get_solver(i).check(num_lits, lits); } else { @@ -886,6 +897,9 @@ namespace sat { } } if (first) { + if (m_local_search) { + m_local_search->cancel(); + } for (int j = 0; j < num_extra_solvers; ++j) { if (i != j) { par.cancel_solver(j); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index bc24f2fde..5ca668ff8 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -35,6 +35,7 @@ Revision History: #include"sat_mus.h" #include"sat_drat.h" #include"sat_parallel.h" +#include"sat_local_search.h" #include"params.h" #include"statistics.h" #include"stopwatch.h" @@ -89,6 +90,7 @@ namespace sat { probing m_probing; mus m_mus; // MUS for minimal core extraction drat m_drat; // DRAT for generating proofs + scoped_ptr m_local_search; bool m_inconsistent; bool m_searching; // A conflict is usually a single justification. That is, a justification @@ -460,6 +462,9 @@ namespace sat { lbool get_consequences(literal_vector const& assms, bool_var_vector const& vars, vector& conseq); + // initialize and retrieve local search. + local_search& init_local_search(); + private: typedef hashtable index_set; From c22359820dbf14b20b9a67c5b625f00d8a2332dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Feb 2017 16:37:31 -0800 Subject: [PATCH 0064/1283] latest updates from Cliff Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 281 ++++++++++++++++++---------------- src/sat/sat_local_search.h | 10 +- src/test/sat_local_search.cpp | 49 +++--- 3 files changed, 177 insertions(+), 163 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index b9ae4afdc..cd611176a 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -37,10 +37,11 @@ namespace sat { var_neighbor.push_back(bool_var_vector()); for (bool_var v = 1; v <= num_vars(); ++v) { + //std::cout << pos_var_term[v].size() << '\t' << neg_var_term[v].size() << '\n'; bool_vector is_neighbor(num_vars() + 1, false); var_neighbor.push_back(bool_var_vector()); - for (unsigned i = 0; i < var_term[v].size(); ++i) { - unsigned c = var_term[v][i].constraint_id; + for (unsigned i = 0; i < pos_var_term[v].size(); ++i) { + unsigned c = pos_var_term[v][i]; for (unsigned j = 0; j < constraint_term[c].size(); ++j) { bool_var w = constraint_term[c][j].var_id; if (w == v || is_neighbor[w]) continue; @@ -48,6 +49,15 @@ namespace sat { var_neighbor.back().push_back(w); } } + for (unsigned i = 0; i < neg_var_term[v].size(); ++i) { + unsigned c = neg_var_term[v][i]; + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + bool_var w = constraint_term[c][j].var_id; + if (w == v || is_neighbor[w]) continue; + is_neighbor[w] = true; + var_neighbor.back().push_back(w); + } + } } for (unsigned i = 0; i < ob_constraint.size(); ++i) coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient; @@ -84,25 +94,32 @@ namespace sat { // figure out variables scores and sscores void local_search::init_scores() { for (unsigned v = 1; v <= num_vars(); ++v) { - for (unsigned i = 0; i < var_term[v].size(); ++i) { - int c = var_term[v][i].constraint_id; - if (cur_solution[v] != var_term[v][i].sense) { - // will ++true_terms_count[c] - // will --slack - if (constraint_slack[c] <= 0) { - --sscore[v]; - if (constraint_slack[c] == 0) - --m_var_info[v].m_score; - } - } - else { // if (cur_solution[v] == var_term[v][i].sense) - // will --true_terms_count[c] - // will ++slack - if (constraint_slack[c] <= -1) { - ++sscore[v]; - if (constraint_slack[c] == -1) - ++m_var_info[v].m_score; - } + int_vector truep, falsep; + if (cur_solution[v]) { + truep = pos_var_term[v]; + falsep = neg_var_term[v]; + } + else { + truep = neg_var_term[v]; + falsep = pos_var_term[v]; + } + for (unsigned i = 0; i < falsep.size(); ++i) { + int c = falsep[i]; + // will --slack + if (constraint_slack[c] <= 0) { + --sscore[v]; + if (constraint_slack[c] == 0) + --m_var_info[v].m_score; + } + } + for (unsigned i = 0; i < truep.size(); ++i) { + int c = truep[i]; + // will --true_terms_count[c] + // will ++slack + if (constraint_slack[c] <= -1) { + ++sscore[v]; + if (constraint_slack[c] == -1) + ++m_var_info[v].m_score; } } } @@ -186,10 +203,13 @@ namespace sat { m_num_vars = std::max(c[i].var() + 1, m_num_vars); // var_term.reserve(c[i].var() + 1); term t; - t.constraint_id = id; t.var_id = c[i].var(); t.sense = c[i].sign(); - var_term[t.var_id].push_back(t); + if (t.sense) + pos_var_term[t.var_id].push_back(id); + else + neg_var_term[t.var_id].push_back(id); + //var_term[t.var_id].push_back(t); constraint_term[id].push_back(t); } constraint_k.push_back(k); @@ -305,20 +325,21 @@ namespace sat { reach_known_best_value = true; break; } - } + } flipvar = pick_var(); flip(flipvar); time_stamp[flipvar] = step; } - // take a look at watch - stop = clock(); - elapsed_time = (double)(stop - start) / CLOCKS_PER_SEC; - if (tries % 10 == 0) - std::cout << tries << ": " << elapsed_time << '\n'; + if (tries % 10 == 0) { + // take a look at watch + stop = clock(); + elapsed_time = (double)(stop - start) / CLOCKS_PER_SEC; + std::cout << tries << ": " << elapsed_time << '\n'; + } if (elapsed_time > cutoff_time) reach_cutoff_time = true; - //if (reach_known_best_value || reach_cutoff_time) - // break; + if (reach_known_best_value || reach_cutoff_time) + break; } if (reach_known_best_value) { std::cout << elapsed_time << "\n"; @@ -334,8 +355,6 @@ namespace sat { void local_search::flip(bool_var flipvar) { - static unsigned_vector hack_vector; - hack_vector.reset(); // already changed truth value!!!! cur_solution[flipvar] = !cur_solution[flipvar]; @@ -343,95 +362,99 @@ namespace sat { int org_flipvar_score = score(flipvar); int org_flipvar_sscore = sscore[flipvar]; + int_vector truep, falsep; + if (cur_solution[flipvar]) { + truep = pos_var_term[flipvar]; + falsep = neg_var_term[flipvar]; + } + else { + truep = neg_var_term[flipvar]; + falsep = pos_var_term[flipvar]; + } + // update related clauses and neighbor vars - svector const& constraints = var_term[flipvar]; - unsigned num_cs = constraints.size(); - for (unsigned i = 0; i < num_cs; ++i) { - c = constraints[i].constraint_id; - if (cur_solution[flipvar] == constraints[i].sense) { - //++true_terms_count[c]; - --constraint_slack[c]; - switch (constraint_slack[c]) { - case -2: // from -1 to -2 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flipping the slack increasing var will no long sat this constraint - if (cur_solution[v] == constraint_term[c][j].sense) - //score[v] -= constraint_weight[c]; - --m_var_info[v].m_score; - } - break; - case -1: // from 0 to -1: sat -> unsat - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - ++cscc[v]; - //score[v] += constraint_weight[c]; - ++m_var_info[v].m_score; - hack_vector.push_back(v); - // slack increasing var - if (cur_solution[v] == constraint_term[c][j].sense) - ++sscore[v]; - } - unsat(c); - break; - case 0: // from 1 to 0 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack decreasing var will falsify this constraint - if (cur_solution[v] != constraint_term[c][j].sense) { - //score[v] -= constraint_weight[c]; - --m_var_info[v].m_score; - --sscore[v]; - } - } - break; - default: - break; - } - } - else { // if (cur_solution[flipvar] != var_term[i].sense) - //--true_terms_count[c]; - ++constraint_slack[c]; - switch (constraint_slack[c]) { - case 1: // from 0 to 1 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack decreasing var will no long falsify this constraint - if (cur_solution[v] != constraint_term[c][j].sense) { - //score[v] += constraint_weight[c]; - ++m_var_info[v].m_score; - hack_vector.push_back(v); - ++sscore[v]; - } - } - break; - case 0: // from -1 to 0: unsat -> sat - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - ++cscc[v]; - //score[v] -= constraint_weight[c]; - --m_var_info[v].m_score; - // slack increasing var no longer sat this var - if (cur_solution[v] == constraint_term[c][j].sense) - --sscore[v]; - } - sat(c); - break; - case -1: // from -2 to -1 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack increasing var will satisfy this constraint - if (cur_solution[v] == constraint_term[c][j].sense) { - //score[v] += constraint_weight[c]; - ++m_var_info[v].m_score; - hack_vector.push_back(v); - } - } - break; - default: - break; - } - } + for (unsigned i = 0; i < truep.size(); ++i) { + c = truep[i]; + //++true_terms_count[c]; + --constraint_slack[c]; + switch (constraint_slack[c]) { + case -2: // from -1 to -2 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flipping the slack increasing var will no long sat this constraint + if (cur_solution[v] == constraint_term[c][j].sense) + //score[v] -= constraint_weight[c]; + --m_var_info[v].m_score; + } + break; + case -1: // from 0 to -1: sat -> unsat + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + ++cscc[v]; + //score[v] += constraint_weight[c]; + ++m_var_info[v].m_score; + // slack increasing var + if (cur_solution[v] == constraint_term[c][j].sense) + ++sscore[v]; + } + unsat(c); + break; + case 0: // from 1 to 0 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack decreasing var will falsify this constraint + if (cur_solution[v] != constraint_term[c][j].sense) { + //score[v] -= constraint_weight[c]; + --m_var_info[v].m_score; + --sscore[v]; + } + } + break; + default: + break; + } + } + for (unsigned i = 0; i < falsep.size(); ++i) { + c = falsep[i]; + //--true_terms_count[c]; + ++constraint_slack[c]; + switch (constraint_slack[c]) { + case 1: // from 0 to 1 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack decreasing var will no long falsify this constraint + if (cur_solution[v] != constraint_term[c][j].sense) { + //score[v] += constraint_weight[c]; + ++m_var_info[v].m_score; + ++sscore[v]; + } + } + break; + case 0: // from -1 to 0: unsat -> sat + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + ++cscc[v]; + //score[v] -= constraint_weight[c]; + --m_var_info[v].m_score; + // slack increasing var no longer sat this var + if (cur_solution[v] == constraint_term[c][j].sense) + --sscore[v]; + } + sat(c); + break; + case -1: // from -2 to -1 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack increasing var will satisfy this constraint + if (cur_solution[v] == constraint_term[c][j].sense) { + //score[v] += constraint_weight[c]; + ++m_var_info[v].m_score; + } + } + break; + default: + break; + } } m_var_info[flipvar].m_score = -org_flipvar_score; @@ -453,7 +476,6 @@ namespace sat { } // update all flipvar's neighbor's conf_change to true, add goodvar/okvar -#if 0 unsigned sz = var_neighbor[flipvar].size(); for (unsigned i = 0; i < sz; ++i) { v = var_neighbor[flipvar][i]; @@ -463,18 +485,7 @@ namespace sat { m_var_info[v].m_in_goodvar_stack = true; } } -#else - unsigned sz = hack_vector.size(); - for (unsigned i = 0; i < sz; ++i) - { - v = hack_vector[i]; - m_var_info[v].m_conf_change = true; - if (score(v) > 0 && !already_in_goodvar_stack(v)) { - goodvar_stack.push_back(v); - m_var_info[v].m_in_goodvar_stack = true; - } - } -#endif + } bool local_search::tie_breaker_sat(bool_var v, bool_var best_var) { @@ -574,7 +585,7 @@ namespace sat { } void local_search::print_info() { - for (int v = 1; v <= num_vars(); ++v) { + for (unsigned v = 1; v <= num_vars(); ++v) { std::cout << var_neighbor[v].size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << sscore[v] << '\n'; } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 65138f68e..d1708a105 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -64,7 +64,7 @@ namespace sat { // data structure for a term in constraint struct term { - int constraint_id; // constraint it belongs to + //int constraint_id; // constraint it belongs to int var_id; // variable id, begin with 1 bool sense; // 1 for positive, 0 for negative //int coefficient; // all constraints are cardinality: coefficient=1 @@ -76,8 +76,10 @@ namespace sat { // terms arrays - svector var_term[MAX_VARS]; // var_term[i][j] means the j'th term of var i - svector constraint_term[MAX_CONSTRAINTS]; // constraint_term[i][j] means the j'th term of constraint i + //svector var_term[MAX_VARS]; // var_term[i][j] means the j'th term of var i + int_vector pos_var_term[MAX_VARS]; + int_vector neg_var_term[MAX_VARS]; + svector constraint_term[MAX_CONSTRAINTS]; // constraint_term[i][j] means the j'th term of constraint i unsigned m_num_vars, m_num_constraints; // parameters of the instance @@ -136,7 +138,7 @@ namespace sat { // cutoff int cutoff_time = 1; // seconds - int max_steps = 2000000000; // < 2147483647 + unsigned max_steps = 2000000000; // < 2147483647 clock_t start, stop; double best_time; diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 6128e5e21..a835f6a35 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -80,31 +80,32 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { int v; while (i + 1 < argc) { + std::cout << argv[i + 1] << "\n"; // set other ad hoc parameters. - if (argv[i + 1][0] == '-' && i + 2 < argc) { - switch (argv[i + 1][1]) { - case 's': // seed - v = atoi(argv[i + 2]); - local_search.m_config.set_seed(v); - break; - case 't': // cutoff_time - v = atoi(argv[i + 2]); - local_search.m_config.set_cutoff_time(v); - break; - case 'i': // strategy_id - v = atoi(argv[i + 2]); - local_search.m_config.set_strategy_id(v); - break; - case 'b': // best_known_value - v = atoi(argv[i + 2]); - local_search.m_config.set_best_known_value(v); - break; - default: - ++i; - v = -1; - break; - } - } + if (argv[i + 1][0] == '-' && i + 2 < argc) { + switch (argv[i + 1][1]) { + case 's': // seed + v = atoi(argv[i + 2]); + local_search.m_config.set_seed(v); + break; + case 't': // cutoff_time + v = atoi(argv[i + 2]); + local_search.m_config.set_cutoff_time(v); + break; + case 'i': // strategy_id + v = atoi(argv[i + 2]); + local_search.m_config.set_strategy_id(v); + break; + case 'b': // best_known_value + v = atoi(argv[i + 2]); + local_search.m_config.set_best_known_value(v); + break; + default: + ++i; + v = -1; + break; + } + } ++i; } From ba0ec79375b9aee57cc93aa932807a9b06643a09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Feb 2017 19:03:32 -0800 Subject: [PATCH 0065/1283] adapt to vectors Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 323 +++++++++++++++++------------------ src/sat/sat_local_search.h | 48 +++--- 2 files changed, 176 insertions(+), 195 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index cd611176a..e73b84760 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -37,11 +37,10 @@ namespace sat { var_neighbor.push_back(bool_var_vector()); for (bool_var v = 1; v <= num_vars(); ++v) { - //std::cout << pos_var_term[v].size() << '\t' << neg_var_term[v].size() << '\n'; bool_vector is_neighbor(num_vars() + 1, false); var_neighbor.push_back(bool_var_vector()); - for (unsigned i = 0; i < pos_var_term[v].size(); ++i) { - unsigned c = pos_var_term[v][i]; + for (unsigned i = 0; i < m_vars[v].m_watch[true].size(); ++i) { + unsigned c = m_vars[v].m_watch[true][i]; for (unsigned j = 0; j < constraint_term[c].size(); ++j) { bool_var w = constraint_term[c][j].var_id; if (w == v || is_neighbor[w]) continue; @@ -49,15 +48,15 @@ namespace sat { var_neighbor.back().push_back(w); } } - for (unsigned i = 0; i < neg_var_term[v].size(); ++i) { - unsigned c = neg_var_term[v][i]; - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - bool_var w = constraint_term[c][j].var_id; - if (w == v || is_neighbor[w]) continue; - is_neighbor[w] = true; - var_neighbor.back().push_back(w); - } - } + for (unsigned i = 0; i < m_vars[v].m_watch[false].size(); ++i) { + unsigned c = m_vars[v].m_watch[false][i]; + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + bool_var w = constraint_term[c][j].var_id; + if (w == v || is_neighbor[w]) continue; + is_neighbor[w] = true; + var_neighbor.back().push_back(w); + } + } } for (unsigned i = 0; i < ob_constraint.size(); ++i) coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient; @@ -91,35 +90,30 @@ namespace sat { } } - // figure out variables scores and sscores + // figure out variables scores and slack_scores void local_search::init_scores() { for (unsigned v = 1; v <= num_vars(); ++v) { - int_vector truep, falsep; - if (cur_solution[v]) { - truep = pos_var_term[v]; - falsep = neg_var_term[v]; - } - else { - truep = neg_var_term[v]; - falsep = pos_var_term[v]; - } - for (unsigned i = 0; i < falsep.size(); ++i) { - int c = falsep[i]; - // will --slack - if (constraint_slack[c] <= 0) { - --sscore[v]; - if (constraint_slack[c] == 0) - --m_var_info[v].m_score; - } - } - for (unsigned i = 0; i < truep.size(); ++i) { - int c = truep[i]; + bool is_true = cur_solution[v]; + int_vector& truep = m_vars[v].m_watch[is_true]; + int_vector& falsep = m_vars[v].m_watch[!is_true]; + + for (unsigned i = 0; i < falsep.size(); ++i) { + int c = falsep[i]; + // will --slack + if (constraint_slack[c] <= 0) { + dec_slack_score(v); + if (constraint_slack[c] == 0) + dec_score(v); + } + } + for (unsigned i = 0; i < truep.size(); ++i) { + int c = truep[i]; // will --true_terms_count[c] // will ++slack if (constraint_slack[c] <= -1) { - ++sscore[v]; + inc_slack_score(v); if (constraint_slack[c] == -1) - ++m_var_info[v].m_score; + inc_score(v); } } } @@ -130,7 +124,7 @@ namespace sat { goodvar_stack.reset(); for (unsigned v = 1; v <= num_vars(); ++v) { if (score(v) > 0) { // && conf_change[v] == true - m_var_info[v].m_in_goodvar_stack = true; + m_vars[v].m_in_goodvar_stack = true; goodvar_stack.push_back(v); } } @@ -148,23 +142,24 @@ namespace sat { // init varibale information // variable 0 is the virtual variable - m_var_info.reset(); - sscore.reset(); - time_stamp.reset(); - cscc.reset(); - - m_var_info.resize(num_vars() + 1, var_info()); - m_var_info[0].m_score = INT_MIN; - m_var_info[0].m_conf_change = false; - sscore.resize(num_vars() + 1, 0); sscore[0] = INT_MIN; - time_stamp.resize(num_vars() + 1, 0); time_stamp[0] = max_steps + 1; - cscc.resize(num_vars() + 1, 1); cscc[0] = 0; - - + time_stamp.reserve(m_vars.size()); + cscc.reserve(m_vars.size()); + m_vars[0].m_score = INT_MIN; + m_vars[0].m_conf_change = false; + m_vars[0].m_slack_score = INT_MIN; + cscc[0] = 0; + time_stamp[0] = max_steps + 1; + for (unsigned i = 1; i < m_vars.size(); ++i) { + time_stamp[i] = 0; + cscc[i] = 1; + m_vars[i].m_conf_change = true; + m_vars[i].m_in_goodvar_stack = false; + m_vars[i].m_score = 0; + m_vars[i].m_slack_score = 0; + } init_slack(); init_scores(); init_goodvars(); - } void local_search::calculate_and_update_ob() { @@ -196,20 +191,14 @@ namespace sat { } void local_search::add_cardinality(unsigned sz, literal const* c, unsigned k) { - unsigned id = m_num_constraints; - ++m_num_constraints; - // constraint_term.push_back(svector()); + unsigned id = num_constraints(); + constraint_term.push_back(svector()); for (unsigned i = 0; i < sz; ++i) { - m_num_vars = std::max(c[i].var() + 1, m_num_vars); - // var_term.reserve(c[i].var() + 1); + m_vars.reserve(c[i].var() + 1); term t; t.var_id = c[i].var(); t.sense = c[i].sign(); - if (t.sense) - pos_var_term[t.var_id].push_back(id); - else - neg_var_term[t.var_id].push_back(id); - //var_term[t.var_id].push_back(t); + m_vars[t.var_id].m_watch[t.sense].push_back(id); constraint_term[id].push_back(t); } constraint_k.push_back(k); @@ -217,9 +206,6 @@ namespace sat { local_search::local_search(solver& s) { - m_num_vars = 0; - m_num_constraints = 0; - // copy units unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { @@ -325,17 +311,17 @@ namespace sat { reach_known_best_value = true; break; } - } + } flipvar = pick_var(); flip(flipvar); time_stamp[flipvar] = step; } if (tries % 10 == 0) { - // take a look at watch - stop = clock(); - elapsed_time = (double)(stop - start) / CLOCKS_PER_SEC; - std::cout << tries << ": " << elapsed_time << '\n'; - } + // take a look at watch + stop = clock(); + elapsed_time = (double)(stop - start) / CLOCKS_PER_SEC; + std::cout << tries << ": " << elapsed_time << '\n'; + } if (elapsed_time > cutoff_time) reach_cutoff_time = true; if (reach_known_best_value || reach_cutoff_time) @@ -360,107 +346,102 @@ namespace sat { unsigned v, c; int org_flipvar_score = score(flipvar); - int org_flipvar_sscore = sscore[flipvar]; + int org_flipvar_slack_score = slack_score(flipvar); - int_vector truep, falsep; - if (cur_solution[flipvar]) { - truep = pos_var_term[flipvar]; - falsep = neg_var_term[flipvar]; - } - else { - truep = neg_var_term[flipvar]; - falsep = pos_var_term[flipvar]; - } + bool is_true = cur_solution[flipvar]; + int_vector& truep = m_vars[flipvar].m_watch[is_true]; + int_vector& falsep = m_vars[flipvar].m_watch[!is_true]; // update related clauses and neighbor vars - for (unsigned i = 0; i < truep.size(); ++i) { - c = truep[i]; - //++true_terms_count[c]; - --constraint_slack[c]; - switch (constraint_slack[c]) { - case -2: // from -1 to -2 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flipping the slack increasing var will no long sat this constraint - if (cur_solution[v] == constraint_term[c][j].sense) - //score[v] -= constraint_weight[c]; - --m_var_info[v].m_score; - } - break; - case -1: // from 0 to -1: sat -> unsat - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - ++cscc[v]; - //score[v] += constraint_weight[c]; - ++m_var_info[v].m_score; - // slack increasing var - if (cur_solution[v] == constraint_term[c][j].sense) - ++sscore[v]; - } - unsat(c); - break; - case 0: // from 1 to 0 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack decreasing var will falsify this constraint - if (cur_solution[v] != constraint_term[c][j].sense) { - //score[v] -= constraint_weight[c]; - --m_var_info[v].m_score; - --sscore[v]; - } - } - break; - default: - break; - } - } - for (unsigned i = 0; i < falsep.size(); ++i) { - c = falsep[i]; - //--true_terms_count[c]; - ++constraint_slack[c]; - switch (constraint_slack[c]) { - case 1: // from 0 to 1 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack decreasing var will no long falsify this constraint - if (cur_solution[v] != constraint_term[c][j].sense) { - //score[v] += constraint_weight[c]; - ++m_var_info[v].m_score; - ++sscore[v]; - } - } - break; - case 0: // from -1 to 0: unsat -> sat - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - ++cscc[v]; - //score[v] -= constraint_weight[c]; - --m_var_info[v].m_score; - // slack increasing var no longer sat this var - if (cur_solution[v] == constraint_term[c][j].sense) - --sscore[v]; - } - sat(c); - break; - case -1: // from -2 to -1 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - // flip the slack increasing var will satisfy this constraint - if (cur_solution[v] == constraint_term[c][j].sense) { - //score[v] += constraint_weight[c]; - ++m_var_info[v].m_score; - } - } - break; - default: - break; - } + for (unsigned i = 0; i < truep.size(); ++i) { + c = truep[i]; + //++true_terms_count[c]; + --constraint_slack[c]; + switch (constraint_slack[c]) { + case -2: // from -1 to -2 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flipping the slack increasing var will no long sat this constraint + if (cur_solution[v] == constraint_term[c][j].sense) { + //score[v] -= constraint_weight[c]; + dec_score(v); + } + } + break; + case -1: // from 0 to -1: sat -> unsat + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + ++cscc[v]; + //score[v] += constraint_weight[c]; + inc_score(v); + // slack increasing var + if (cur_solution[v] == constraint_term[c][j].sense) + inc_slack_score(v); + } + unsat(c); + break; + case 0: // from 1 to 0 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack decreasing var will falsify this constraint + if (cur_solution[v] != constraint_term[c][j].sense) { + //score[v] -= constraint_weight[c]; + dec_score(v); + dec_slack_score(v); + } + } + break; + default: + break; + } + } + for (unsigned i = 0; i < falsep.size(); ++i) { + c = falsep[i]; + //--true_terms_count[c]; + ++constraint_slack[c]; + switch (constraint_slack[c]) { + case 1: // from 0 to 1 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack decreasing var will no long falsify this constraint + if (cur_solution[v] != constraint_term[c][j].sense) { + //score[v] += constraint_weight[c]; + inc_score(v); + inc_slack_score(v); + } + } + break; + case 0: // from -1 to 0: unsat -> sat + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + ++cscc[v]; + //score[v] -= constraint_weight[c]; + dec_score(v); + // slack increasing var no longer sat this var + if (cur_solution[v] == constraint_term[c][j].sense) + dec_slack_score(v); + } + sat(c); + break; + case -1: // from -2 to -1 + for (unsigned j = 0; j < constraint_term[c].size(); ++j) { + v = constraint_term[c][j].var_id; + // flip the slack increasing var will satisfy this constraint + if (cur_solution[v] == constraint_term[c][j].sense) { + //score[v] += constraint_weight[c]; + inc_score(v); + } + } + break; + default: + break; + } } - m_var_info[flipvar].m_score = -org_flipvar_score; - sscore[flipvar] = -org_flipvar_sscore; + m_vars[flipvar].m_score = -org_flipvar_score; + m_vars[flipvar].m_slack_score = -org_flipvar_slack_score; - m_var_info[flipvar].m_conf_change = false; + m_vars[flipvar].m_conf_change = false; cscc[flipvar] = 0; /* update CCD */ @@ -471,7 +452,7 @@ namespace sat { if (score(v) <= 0) { goodvar_stack[i] = goodvar_stack.back(); goodvar_stack.pop_back(); - m_var_info[v].m_in_goodvar_stack = false; + m_vars[v].m_in_goodvar_stack = false; } } // update all flipvar's neighbor's conf_change to true, add goodvar/okvar @@ -479,10 +460,10 @@ namespace sat { unsigned sz = var_neighbor[flipvar].size(); for (unsigned i = 0; i < sz; ++i) { v = var_neighbor[flipvar][i]; - m_var_info[v].m_conf_change = true; + m_vars[v].m_conf_change = true; if (score(v) > 0 && !already_in_goodvar_stack(v)) { goodvar_stack.push_back(v); - m_var_info[v].m_in_goodvar_stack = true; + m_vars[v].m_in_goodvar_stack = true; } } @@ -507,14 +488,14 @@ namespace sat { bool local_search::tie_breaker_ccd(bool_var v, bool_var best_var) { // break tie 1: max score - // break tie 2: max sscore + // break tie 2: max slack_score // break tie 3: cscc // break tie 4: oldest one return ((score(v) > score(best_var)) || ((score(v) == score(best_var)) && - ((sscore[v] > sscore[best_var]) || - ((sscore[v] == sscore[best_var]) && + ((slack_score(v) > slack_score(best_var)) || + ((slack_score(v) == slack_score(best_var)) && ((cscc[v] > cscc[best_var]) || ((cscc[v] == cscc[best_var]) && (time_stamp[v] < time_stamp[best_var]))))))); @@ -586,7 +567,7 @@ namespace sat { void local_search::print_info() { for (unsigned v = 1; v <= num_vars(); ++v) { - std::cout << var_neighbor[v].size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << sscore[v] << '\n'; + std::cout << var_neighbor[v].size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; } } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index d1708a105..226e1e984 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -49,8 +49,6 @@ namespace sat { void set_best_known_value(unsigned v) { m_best_known_value = v; } }; -#define MAX_VARS 5000 -#define MAX_CONSTRAINTS 100 class local_search { @@ -58,14 +56,13 @@ namespace sat { // data structure for a term in objective function struct ob_term { - int var_id; // variable id, begin with 1 + bool_var var_id; // variable id, begin with 1 int coefficient; // non-zero integer }; // data structure for a term in constraint struct term { - //int constraint_id; // constraint it belongs to - int var_id; // variable id, begin with 1 + bool_var var_id; // variable id, begin with 1 bool sense; // 1 for positive, 0 for negative //int coefficient; // all constraints are cardinality: coefficient=1 }; @@ -76,42 +73,46 @@ namespace sat { // terms arrays - //svector var_term[MAX_VARS]; // var_term[i][j] means the j'th term of var i - int_vector pos_var_term[MAX_VARS]; - int_vector neg_var_term[MAX_VARS]; - svector constraint_term[MAX_CONSTRAINTS]; // constraint_term[i][j] means the j'th term of constraint i - unsigned m_num_vars, m_num_constraints; + vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i // parameters of the instance - unsigned num_vars() const { return m_num_vars - 1; } // var index from 1 to num_vars - unsigned num_constraints() const { return m_num_constraints; } // constraint index from 1 to num_constraint + unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars + unsigned num_constraints() const { return constraint_term.size(); } // constraint index from 1 to num_constraint // information about the variable int_vector coefficient_in_ob_constraint; // initialized to be 0 - // int_vector score; - int_vector sscore; // slack score + // int_vector sscore; // slack score struct var_info { bool m_conf_change; // whether its configure changes since its last flip bool m_in_goodvar_stack; int m_score; + int m_slack_score; + int_vector m_watch[2]; var_info(): m_conf_change(true), m_in_goodvar_stack(false), - m_score(0) + m_score(0), + m_slack_score(0) {} }; - svector m_var_info; + svector m_vars; - inline int score(unsigned v) const { return m_var_info[v].m_score; } - inline bool already_in_goodvar_stack(unsigned v) const { return m_var_info[v].m_in_goodvar_stack; } - inline bool conf_change(unsigned v) const { return m_var_info[v].m_conf_change; } + inline int score(unsigned v) const { return m_vars[v].m_score; } + inline void inc_score(bool_var v) { m_vars[v].m_score++; } + inline void dec_score(bool_var v) { m_vars[v].m_score--; } - int_vector time_stamp; // the flip time stamp - // bool_vector conf_change; - int_vector cscc; // how many times its constraint state configure changes since its last flip - vector var_neighbor; // all of its neighborhoods variable + inline int slack_score(unsigned v) const { return m_vars[v].m_slack_score; } + inline void inc_slack_score(bool_var v) { m_vars[v].m_slack_score++; } + inline void dec_slack_score(bool_var v) { m_vars[v].m_slack_score--; } + + inline bool already_in_goodvar_stack(unsigned v) const { return m_vars[v].m_in_goodvar_stack; } + inline bool conf_change(unsigned v) const { return m_vars[v].m_conf_change; } + + int_vector time_stamp; // the flip time stamp + int_vector cscc; // how many times its constraint state configure changes since its last flip + vector var_neighbor; // all of its neighborhoods variable /* TBD: other scores */ // information about the constraints @@ -126,7 +127,6 @@ namespace sat { // configuration changed decreasing variables (score>0 and conf_change==true) int_vector goodvar_stack; - // bool_vector already_in_goodvar_stack; // information about solution bool_vector cur_solution; // the current solution From 1c7cb8790014c52d971416abb4a520a5afac3351 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Feb 2017 20:41:47 -0800 Subject: [PATCH 0066/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 159 +++++++++++++++++------------------ src/sat/sat_local_search.h | 71 ++++++++++------ src/sat/sat_lookahead.h | 8 -- 3 files changed, 118 insertions(+), 120 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index e73b84760..f204cdec2 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -27,7 +27,6 @@ namespace sat { void local_search::init() { best_solution.resize(num_vars() + 1, false); - constraint_slack.resize(num_constraints(), 0); cur_solution.resize(num_vars() + 1, false); m_index_in_unsat_stack.resize(num_constraints(), 0); coefficient_in_ob_constraint.resize(num_vars() + 1, 0); @@ -39,22 +38,16 @@ namespace sat { for (bool_var v = 1; v <= num_vars(); ++v) { bool_vector is_neighbor(num_vars() + 1, false); var_neighbor.push_back(bool_var_vector()); - for (unsigned i = 0; i < m_vars[v].m_watch[true].size(); ++i) { - unsigned c = m_vars[v].m_watch[true][i]; - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - bool_var w = constraint_term[c][j].var_id; - if (w == v || is_neighbor[w]) continue; - is_neighbor[w] = true; - var_neighbor.back().push_back(w); - } - } - for (unsigned i = 0; i < m_vars[v].m_watch[false].size(); ++i) { - unsigned c = m_vars[v].m_watch[false][i]; - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - bool_var w = constraint_term[c][j].var_id; - if (w == v || is_neighbor[w]) continue; - is_neighbor[w] = true; - var_neighbor.back().push_back(w); + bool pol = true; + for (unsigned k = 0; k < 2; pol = !pol, k++) { + for (unsigned i = 0; i < m_vars[v].m_watch[pol].size(); ++i) { + constraint const& c = m_constraints[m_vars[v].m_watch[pol][i]]; + for (unsigned j = 0; j < c.size(); ++j) { + bool_var w = c[j].var(); + if (w == v || is_neighbor[w]) continue; + is_neighbor[w] = true; + var_neighbor.back().push_back(w); + } } } } @@ -78,14 +71,15 @@ namespace sat { // figure out slack, and init unsat stack void local_search::init_slack() { for (unsigned c = 0; c < num_constraints(); ++c) { - for (unsigned i = 0; i < constraint_term[c].size(); ++i) { - unsigned v = constraint_term[c][i].var_id; - if (cur_solution[v] == constraint_term[c][i].sense) - --constraint_slack[c]; + constraint & cn = m_constraints[c]; + for (unsigned i = 0; i < cn.size(); ++i) { + bool_var v = cn[i].var(); + if (cur_solution[v] == is_pos(cn[i])) + --cn.m_slack; } // constraint_slack[c] = constraint_k[c] - true_terms_count[c]; // violate the at-most-k constraint - if (constraint_slack[c] < 0) + if (cn.m_slack < 0) unsat(c); } } @@ -98,21 +92,21 @@ namespace sat { int_vector& falsep = m_vars[v].m_watch[!is_true]; for (unsigned i = 0; i < falsep.size(); ++i) { - int c = falsep[i]; + constraint& c = m_constraints[falsep[i]]; // will --slack - if (constraint_slack[c] <= 0) { + if (c.m_slack <= 0) { dec_slack_score(v); - if (constraint_slack[c] == 0) + if (c.m_slack == 0) dec_score(v); } } for (unsigned i = 0; i < truep.size(); ++i) { - int c = truep[i]; + constraint& c = m_constraints[truep[i]]; // will --true_terms_count[c] // will ++slack - if (constraint_slack[c] <= -1) { + if (c.m_slack <= -1) { inc_slack_score(v); - if (constraint_slack[c] == -1) + if (c.m_slack == -1) inc_score(v); } } @@ -131,7 +125,10 @@ namespace sat { } void local_search::reinit_orig() { - constraint_slack = constraint_k; + for (unsigned i = 0; i < m_constraints.size(); ++i) { + constraint& c = m_constraints[i]; + c.m_slack = c.m_k; + } // init unsat stack m_unsat_stack.reset(); @@ -142,16 +139,14 @@ namespace sat { // init varibale information // variable 0 is the virtual variable - time_stamp.reserve(m_vars.size()); - cscc.reserve(m_vars.size()); m_vars[0].m_score = INT_MIN; m_vars[0].m_conf_change = false; m_vars[0].m_slack_score = INT_MIN; - cscc[0] = 0; - time_stamp[0] = max_steps + 1; + m_vars[0].m_cscc = 0; + m_vars[0].m_time_stamp = max_steps + 1; for (unsigned i = 1; i < m_vars.size(); ++i) { - time_stamp[i] = 0; - cscc[i] = 1; + m_vars[i].m_time_stamp = 0; + m_vars[i].m_cscc = 1; m_vars[i].m_conf_change = true; m_vars[i].m_in_goodvar_stack = false; m_vars[i].m_score = 0; @@ -191,17 +186,14 @@ namespace sat { } void local_search::add_cardinality(unsigned sz, literal const* c, unsigned k) { - unsigned id = num_constraints(); - constraint_term.push_back(svector()); + unsigned id = m_constraints.size(); + m_constraints.push_back(constraint(k)); for (unsigned i = 0; i < sz; ++i) { m_vars.reserve(c[i].var() + 1); - term t; - t.var_id = c[i].var(); - t.sense = c[i].sign(); - m_vars[t.var_id].m_watch[t.sense].push_back(id); - constraint_term[id].push_back(t); + literal t(~c[i]); + m_vars[t.var()].m_watch[is_pos(t)].push_back(id); + m_constraints.back().m_literals.push_back(t); } - constraint_k.push_back(k); } local_search::local_search(solver& s) { @@ -314,7 +306,7 @@ namespace sat { } flipvar = pick_var(); flip(flipvar); - time_stamp[flipvar] = step; + m_vars[flipvar].m_time_stamp = step; } if (tries % 10 == 0) { // take a look at watch @@ -344,7 +336,7 @@ namespace sat { // already changed truth value!!!! cur_solution[flipvar] = !cur_solution[flipvar]; - unsigned v, c; + unsigned v; int org_flipvar_score = score(flipvar); int org_flipvar_slack_score = slack_score(flipvar); @@ -354,37 +346,37 @@ namespace sat { // update related clauses and neighbor vars for (unsigned i = 0; i < truep.size(); ++i) { - c = truep[i]; + constraint & c = m_constraints[truep[i]]; //++true_terms_count[c]; - --constraint_slack[c]; - switch (constraint_slack[c]) { + --c.m_slack; + switch (c.m_slack) { case -2: // from -1 to -2 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; + for (unsigned j = 0; j < c.size(); ++j) { + v = c[j].var(); // flipping the slack increasing var will no long sat this constraint - if (cur_solution[v] == constraint_term[c][j].sense) { + if (cur_solution[v] == is_pos(c[j])) { //score[v] -= constraint_weight[c]; dec_score(v); } } break; case -1: // from 0 to -1: sat -> unsat - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - ++cscc[v]; + for (unsigned j = 0; j < c.size(); ++j) { + v = c[j].var(); + inc_cscc(v); //score[v] += constraint_weight[c]; inc_score(v); // slack increasing var - if (cur_solution[v] == constraint_term[c][j].sense) + if (cur_solution[v] == is_pos(c[j])) inc_slack_score(v); } - unsat(c); + unsat(truep[i]); break; case 0: // from 1 to 0 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; + for (unsigned j = 0; j < c.size(); ++j) { + v = c[j].var(); // flip the slack decreasing var will falsify this constraint - if (cur_solution[v] != constraint_term[c][j].sense) { + if (cur_solution[v] != is_pos(c[j])) { //score[v] -= constraint_weight[c]; dec_score(v); dec_slack_score(v); @@ -396,15 +388,15 @@ namespace sat { } } for (unsigned i = 0; i < falsep.size(); ++i) { - c = falsep[i]; + constraint& c = m_constraints[falsep[i]]; //--true_terms_count[c]; - ++constraint_slack[c]; - switch (constraint_slack[c]) { + ++c.m_slack; + switch (c.m_slack) { case 1: // from 0 to 1 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; + for (unsigned j = 0; j < c.size(); ++j) { + v = c[j].var(); // flip the slack decreasing var will no long falsify this constraint - if (cur_solution[v] != constraint_term[c][j].sense) { + if (cur_solution[v] != is_pos(c[j])) { //score[v] += constraint_weight[c]; inc_score(v); inc_slack_score(v); @@ -412,22 +404,22 @@ namespace sat { } break; case 0: // from -1 to 0: unsat -> sat - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; - ++cscc[v]; + for (unsigned j = 0; j < c.size(); ++j) { + v = c[j].var(); + inc_cscc(v); //score[v] -= constraint_weight[c]; dec_score(v); // slack increasing var no longer sat this var - if (cur_solution[v] == constraint_term[c][j].sense) + if (cur_solution[v] == is_pos(c[j])) dec_slack_score(v); } - sat(c); + sat(falsep[i]); break; case -1: // from -2 to -1 - for (unsigned j = 0; j < constraint_term[c].size(); ++j) { - v = constraint_term[c][j].var_id; + for (unsigned j = 0; j < c.size(); ++j) { + v = c[j].var(); // flip the slack increasing var will satisfy this constraint - if (cur_solution[v] == constraint_term[c][j].sense) { + if (cur_solution[v] == is_pos(c[j])) { //score[v] += constraint_weight[c]; inc_score(v); } @@ -440,9 +432,8 @@ namespace sat { m_vars[flipvar].m_score = -org_flipvar_score; m_vars[flipvar].m_slack_score = -org_flipvar_slack_score; - m_vars[flipvar].m_conf_change = false; - cscc[flipvar] = 0; + m_vars[flipvar].m_cscc = 0; /* update CCD */ // remove the vars no longer goodvar in goodvar stack @@ -483,7 +474,7 @@ namespace sat { ((v_imp == b_imp) && ((conf_change(v) && !conf_change(best_var)) || ((conf_change(v) == conf_change(best_var)) && - (time_stamp[v] < time_stamp[best_var])))); + (time_stamp(v) < time_stamp(best_var))))); } bool local_search::tie_breaker_ccd(bool_var v, bool_var best_var) { @@ -496,13 +487,13 @@ namespace sat { ((score(v) == score(best_var)) && ((slack_score(v) > slack_score(best_var)) || ((slack_score(v) == slack_score(best_var)) && - ((cscc[v] > cscc[best_var]) || - ((cscc[v] == cscc[best_var]) && - (time_stamp[v] < time_stamp[best_var]))))))); + ((cscc(v) > cscc(best_var)) || + ((cscc(v) == cscc(best_var)) && + (time_stamp(v) < time_stamp(best_var)))))))); } bool_var local_search::pick_var() { - int c, v; + int v; bool_var best_var = 0; // SAT Mode @@ -530,12 +521,12 @@ namespace sat { } // Diversification Mode - c = m_unsat_stack[rand() % m_unsat_stack.size()]; // a random unsat constraint + constraint const& c = m_constraints[m_unsat_stack[rand() % m_unsat_stack.size()]]; // a random unsat constraint // Within c, from all slack increasing var, choose the oldest one - unsigned c_size = constraint_term[c].size(); + unsigned c_size = c.size(); for (unsigned i = 0; i < c_size; ++i) { - v = constraint_term[c][i].var_id; - if (cur_solution[v] == constraint_term[c][i].sense && time_stamp[v] < time_stamp[best_var]) + v = c[i].var(); + if (cur_solution[v] == is_pos(c[i]) && time_stamp(v) < time_stamp(best_var)) best_var = v; } return best_var; diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 226e1e984..7e366c83a 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -56,13 +56,13 @@ namespace sat { // data structure for a term in objective function struct ob_term { - bool_var var_id; // variable id, begin with 1 + bool_var var_id; // variable id, begin with 1 int coefficient; // non-zero integer }; // data structure for a term in constraint struct term { - bool_var var_id; // variable id, begin with 1 + bool_var var_id; // variable id, begin with 1 bool sense; // 1 for positive, 0 for negative //int coefficient; // all constraints are cardinality: coefficient=1 }; @@ -70,25 +70,17 @@ namespace sat { // objective function: maximize svector ob_constraint; // the objective function *constraint*, sorted in decending order - - - // terms arrays - vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i - - // parameters of the instance - unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars - unsigned num_constraints() const { return constraint_term.size(); } // constraint index from 1 to num_constraint - - + // information about the variable int_vector coefficient_in_ob_constraint; // initialized to be 0 - // int_vector sscore; // slack score struct var_info { bool m_conf_change; // whether its configure changes since its last flip bool m_in_goodvar_stack; int m_score; int m_slack_score; + int m_time_stamp; // the flip time stamp + int m_cscc; // how many times its constraint state configure changes since its last flip int_vector m_watch[2]; var_info(): m_conf_change(true), @@ -109,17 +101,42 @@ namespace sat { inline bool already_in_goodvar_stack(unsigned v) const { return m_vars[v].m_in_goodvar_stack; } inline bool conf_change(unsigned v) const { return m_vars[v].m_conf_change; } + inline int time_stamp(bool_var v) const { return m_vars[v].m_time_stamp; } + inline int cscc(bool_var v) const { return m_vars[v].m_cscc; } + inline void inc_cscc(bool_var v) { m_vars[v].m_cscc++; } + + unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars + - int_vector time_stamp; // the flip time stamp - int_vector cscc; // how many times its constraint state configure changes since its last flip vector var_neighbor; // all of its neighborhoods variable + /* TBD: other scores */ + struct constraint { + unsigned m_k; + int m_slack; + svector m_literals; + constraint(unsigned k) : m_k(k), m_slack(0) {} + unsigned size() const { return m_literals.size(); } + literal const& operator[](unsigned idx) const { return m_literals[idx]; } + }; + + vector m_constraints; + + // terms arrays + // vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i + + inline bool is_pos(literal t) const { return !t.sign(); } + + // parameters of the instance + unsigned num_constraints() const { return m_constraints.size(); } // constraint index from 1 to num_constraint + // information about the constraints - int_vector constraint_k; // the right side k of a constraint - int_vector constraint_slack; // =constraint_k[i]-true_terms[i], if >=0 then sat - //int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing - //bool_vector has_true_ob_terms; + // int_vector constraint_k; // the right side k of a constraint + // int_vector constraint_slack; // =constraint_k[i]-true_terms[i], if >=0 then sat + + // int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing + // bool_vector has_true_ob_terms; // unsat constraint stack int_vector m_unsat_stack; // store all the unsat constraits @@ -129,28 +146,26 @@ namespace sat { int_vector goodvar_stack; // information about solution - bool_vector cur_solution; // the current solution - int objective_value; // the objective function value corresponds to the current solution - bool_vector best_solution; // the best solution so far + bool_vector cur_solution; // the current solution + int objective_value; // the objective function value corresponds to the current solution + bool_vector best_solution; // the best solution so far int best_objective_value = -1; // the objective value corresponds to the best solution so far // for non-known instance, set as maximal - int best_known_value = INT_MAX; // best known value for this instance + int best_known_value = INT_MAX; // best known value for this instance // cutoff - int cutoff_time = 1; // seconds - unsigned max_steps = 2000000000; // < 2147483647 + int cutoff_time = 1; // seconds + unsigned max_steps = 2000000000; // < 2147483647 clock_t start, stop; double best_time; // for tuning - int s_id = 0; // strategy id + int s_id = 0; // strategy id void init(); - void reinit(); void reinit_orig(); - void init_cur_solution(); void init_slack(); void init_scores(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 5921e4588..5504cf6e0 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -1099,14 +1099,6 @@ namespace sat { bool inconsistent() { return m_inconsistent; } - void select_variables(literal_vector& P) { - for (unsigned i = 0; i < s.num_vars(); ++i) { - if (value(literal(i,false)) == l_undef) { - P.push_back(literal(i, false)); - } - } - } - void do_double(literal l) { if (!inconsistent() && scope_lvl() > 0 && dl_enabled(l)) { if (get_wnb(l) > m_delta_trigger) { From 475101e932b9f055421417186c6a0156ea361b42 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Feb 2017 20:49:37 -0800 Subject: [PATCH 0067/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 22 +++++++++++----------- src/sat/sat_local_search.h | 8 +++++--- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index f204cdec2..46657f2f4 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -74,7 +74,7 @@ namespace sat { constraint & cn = m_constraints[c]; for (unsigned i = 0; i < cn.size(); ++i) { bool_var v = cn[i].var(); - if (cur_solution[v] == is_pos(cn[i])) + if (is_true(cn[i])) --cn.m_slack; } // constraint_slack[c] = constraint_k[c] - true_terms_count[c]; @@ -340,9 +340,9 @@ namespace sat { int org_flipvar_score = score(flipvar); int org_flipvar_slack_score = slack_score(flipvar); - bool is_true = cur_solution[flipvar]; - int_vector& truep = m_vars[flipvar].m_watch[is_true]; - int_vector& falsep = m_vars[flipvar].m_watch[!is_true]; + bool flip_is_true = cur_solution[flipvar]; + int_vector& truep = m_vars[flipvar].m_watch[flip_is_true]; + int_vector& falsep = m_vars[flipvar].m_watch[!flip_is_true]; // update related clauses and neighbor vars for (unsigned i = 0; i < truep.size(); ++i) { @@ -354,7 +354,7 @@ namespace sat { for (unsigned j = 0; j < c.size(); ++j) { v = c[j].var(); // flipping the slack increasing var will no long sat this constraint - if (cur_solution[v] == is_pos(c[j])) { + if (is_true(c[j])) { //score[v] -= constraint_weight[c]; dec_score(v); } @@ -367,7 +367,7 @@ namespace sat { //score[v] += constraint_weight[c]; inc_score(v); // slack increasing var - if (cur_solution[v] == is_pos(c[j])) + if (is_true(c[j])) inc_slack_score(v); } unsat(truep[i]); @@ -376,7 +376,7 @@ namespace sat { for (unsigned j = 0; j < c.size(); ++j) { v = c[j].var(); // flip the slack decreasing var will falsify this constraint - if (cur_solution[v] != is_pos(c[j])) { + if (is_false(c[j])) { //score[v] -= constraint_weight[c]; dec_score(v); dec_slack_score(v); @@ -396,7 +396,7 @@ namespace sat { for (unsigned j = 0; j < c.size(); ++j) { v = c[j].var(); // flip the slack decreasing var will no long falsify this constraint - if (cur_solution[v] != is_pos(c[j])) { + if (is_false(c[j])) { //score[v] += constraint_weight[c]; inc_score(v); inc_slack_score(v); @@ -410,7 +410,7 @@ namespace sat { //score[v] -= constraint_weight[c]; dec_score(v); // slack increasing var no longer sat this var - if (cur_solution[v] == is_pos(c[j])) + if (is_true(c[j])) dec_slack_score(v); } sat(falsep[i]); @@ -419,7 +419,7 @@ namespace sat { for (unsigned j = 0; j < c.size(); ++j) { v = c[j].var(); // flip the slack increasing var will satisfy this constraint - if (cur_solution[v] == is_pos(c[j])) { + if (is_true(c[j])) { //score[v] += constraint_weight[c]; inc_score(v); } @@ -526,7 +526,7 @@ namespace sat { unsigned c_size = c.size(); for (unsigned i = 0; i < c_size; ++i) { v = c[i].var(); - if (cur_solution[v] == is_pos(c[i]) && time_stamp(v) < time_stamp(best_var)) + if (is_true(c[i]) && time_stamp(v) < time_stamp(best_var)) best_var = v; } return best_var; diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 7e366c83a..30ee3ce38 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -113,9 +113,9 @@ namespace sat { /* TBD: other scores */ struct constraint { - unsigned m_k; - int m_slack; - svector m_literals; + unsigned m_k; + int m_slack; + literal_vector m_literals; constraint(unsigned k) : m_k(k), m_slack(0) {} unsigned size() const { return m_literals.size(); } literal const& operator[](unsigned idx) const { return m_literals[idx]; } @@ -127,6 +127,8 @@ namespace sat { // vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i inline bool is_pos(literal t) const { return !t.sign(); } + inline bool is_true(literal l) const { return cur_solution[l.var()] != l.sign(); } + inline bool is_false(literal l) const { return cur_solution[l.var()] == l.sign(); } // parameters of the instance unsigned num_constraints() const { return m_constraints.size(); } // constraint index from 1 to num_constraint From c205b59a211f6f411b03dcc2361df46eef06bcac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Feb 2017 21:13:52 -0800 Subject: [PATCH 0068/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 62 ++++++++++++++++++------------------ src/sat/sat_local_search.h | 27 ++++++---------- 2 files changed, 41 insertions(+), 48 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 46657f2f4..4e4db015f 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -26,31 +26,32 @@ namespace sat { void local_search::init() { + // add sentinel variable. + m_vars.push_back(var_info()); + best_solution.resize(num_vars() + 1, false); cur_solution.resize(num_vars() + 1, false); m_index_in_unsat_stack.resize(num_constraints(), 0); coefficient_in_ob_constraint.resize(num_vars() + 1, 0); - var_neighbor.reset(); - // for dummy var 0 - var_neighbor.push_back(bool_var_vector()); - - for (bool_var v = 1; v <= num_vars(); ++v) { - bool_vector is_neighbor(num_vars() + 1, false); - var_neighbor.push_back(bool_var_vector()); + uint_set is_neighbor; + for (bool_var v = 0; v < num_vars(); ++v) { + is_neighbor.reset(); bool pol = true; + var_info& vi = m_vars[v]; for (unsigned k = 0; k < 2; pol = !pol, k++) { for (unsigned i = 0; i < m_vars[v].m_watch[pol].size(); ++i) { constraint const& c = m_constraints[m_vars[v].m_watch[pol][i]]; for (unsigned j = 0; j < c.size(); ++j) { bool_var w = c[j].var(); - if (w == v || is_neighbor[w]) continue; - is_neighbor[w] = true; - var_neighbor.back().push_back(w); + if (w == v || is_neighbor.contains(w)) continue; + is_neighbor.insert(w); + vi.m_neighbors.push_back(w); } } } } + for (unsigned i = 0; i < ob_constraint.size(); ++i) coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient; @@ -63,7 +64,7 @@ namespace sat { void local_search::init_cur_solution() { //cur_solution.resize(num_vars() + 1, false); - for (unsigned v = 1; v <= num_vars(); ++v) { + for (unsigned v = 0; v < num_vars(); ++v) { cur_solution[v] = (rand() % 2 == 1); } } @@ -86,7 +87,7 @@ namespace sat { // figure out variables scores and slack_scores void local_search::init_scores() { - for (unsigned v = 1; v <= num_vars(); ++v) { + for (unsigned v = 0; v < num_vars(); ++v) { bool is_true = cur_solution[v]; int_vector& truep = m_vars[v].m_watch[is_true]; int_vector& falsep = m_vars[v].m_watch[!is_true]; @@ -116,7 +117,7 @@ namespace sat { // init goodvars void local_search::init_goodvars() { goodvar_stack.reset(); - for (unsigned v = 1; v <= num_vars(); ++v) { + for (unsigned v = 0; v < num_vars(); ++v) { if (score(v) > 0) { // && conf_change[v] == true m_vars[v].m_in_goodvar_stack = true; goodvar_stack.push_back(v); @@ -139,12 +140,12 @@ namespace sat { // init varibale information // variable 0 is the virtual variable - m_vars[0].m_score = INT_MIN; - m_vars[0].m_conf_change = false; - m_vars[0].m_slack_score = INT_MIN; - m_vars[0].m_cscc = 0; - m_vars[0].m_time_stamp = max_steps + 1; - for (unsigned i = 1; i < m_vars.size(); ++i) { + m_vars.back().m_score = INT_MIN; + m_vars.back().m_conf_change = false; + m_vars.back().m_slack_score = INT_MIN; + m_vars.back().m_cscc = 0; + m_vars.back().m_time_stamp = max_steps + 1; + for (unsigned i = 0; i < num_vars(); ++i) { m_vars[i].m_time_stamp = 0; m_vars[i].m_cscc = 1; m_vars[i].m_conf_change = true; @@ -448,13 +449,14 @@ namespace sat { } // update all flipvar's neighbor's conf_change to true, add goodvar/okvar - unsigned sz = var_neighbor[flipvar].size(); + var_info& vi = m_vars[flipvar]; + unsigned sz = vi.m_neighbors.size(); for (unsigned i = 0; i < sz; ++i) { - v = var_neighbor[flipvar][i]; - m_vars[v].m_conf_change = true; + v = vi.m_neighbors[i]; + vi.m_conf_change = true; if (score(v) > 0 && !already_in_goodvar_stack(v)) { goodvar_stack.push_back(v); - m_vars[v].m_in_goodvar_stack = true; + vi.m_in_goodvar_stack = true; } } @@ -493,14 +495,12 @@ namespace sat { } bool_var local_search::pick_var() { - int v; - bool_var best_var = 0; - + bool_var best_var = m_vars.size()-1; // sentinel variable // SAT Mode if (m_unsat_stack.empty()) { //++as; for (unsigned i = 0; i < ob_constraint.size(); ++i) { - v = ob_constraint[i].var_id; + bool_var v = ob_constraint[i].var_id; if (tie_breaker_sat(v, best_var)) best_var = v; } @@ -513,7 +513,7 @@ namespace sat { //++ccd; best_var = goodvar_stack[0]; for (unsigned i = 1; i < goodvar_stack.size(); ++i) { - v = goodvar_stack[i]; + bool_var v = goodvar_stack[i]; if (tie_breaker_ccd(v, best_var)) best_var = v; } @@ -525,7 +525,7 @@ namespace sat { // Within c, from all slack increasing var, choose the oldest one unsigned c_size = c.size(); for (unsigned i = 0; i < c_size; ++i) { - v = c[i].var(); + bool_var v = c[i].var(); if (is_true(c[i]) && time_stamp(v) < time_stamp(best_var)) best_var = v; } @@ -557,8 +557,8 @@ namespace sat { } void local_search::print_info() { - for (unsigned v = 1; v <= num_vars(); ++v) { - std::cout << var_neighbor[v].size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; + for (unsigned v = 0; v < num_vars(); ++v) { + std::cout << m_vars[v].m_neighbors.size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; } } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 30ee3ce38..4d51fe519 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -81,35 +81,35 @@ namespace sat { int m_slack_score; int m_time_stamp; // the flip time stamp int m_cscc; // how many times its constraint state configure changes since its last flip + bool_var_vector m_neighbors; // neighborhood variables int_vector m_watch[2]; var_info(): m_conf_change(true), m_in_goodvar_stack(false), m_score(0), - m_slack_score(0) + m_slack_score(0), + m_cscc(0) {} }; - svector m_vars; - inline int score(unsigned v) const { return m_vars[v].m_score; } + vector m_vars; + + inline int score(bool_var v) const { return m_vars[v].m_score; } inline void inc_score(bool_var v) { m_vars[v].m_score++; } inline void dec_score(bool_var v) { m_vars[v].m_score--; } - inline int slack_score(unsigned v) const { return m_vars[v].m_slack_score; } + inline int slack_score(bool_var v) const { return m_vars[v].m_slack_score; } inline void inc_slack_score(bool_var v) { m_vars[v].m_slack_score++; } inline void dec_slack_score(bool_var v) { m_vars[v].m_slack_score--; } - inline bool already_in_goodvar_stack(unsigned v) const { return m_vars[v].m_in_goodvar_stack; } - inline bool conf_change(unsigned v) const { return m_vars[v].m_conf_change; } + inline bool already_in_goodvar_stack(bool_var v) const { return m_vars[v].m_in_goodvar_stack; } + inline bool conf_change(bool_var v) const { return m_vars[v].m_conf_change; } inline int time_stamp(bool_var v) const { return m_vars[v].m_time_stamp; } inline int cscc(bool_var v) const { return m_vars[v].m_cscc; } inline void inc_cscc(bool_var v) { m_vars[v].m_cscc++; } unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars - - - vector var_neighbor; // all of its neighborhoods variable - + /* TBD: other scores */ struct constraint { @@ -123,19 +123,12 @@ namespace sat { vector m_constraints; - // terms arrays - // vector > constraint_term; // constraint_term[i][j] means the j'th term of constraint i - inline bool is_pos(literal t) const { return !t.sign(); } inline bool is_true(literal l) const { return cur_solution[l.var()] != l.sign(); } inline bool is_false(literal l) const { return cur_solution[l.var()] == l.sign(); } - // parameters of the instance unsigned num_constraints() const { return m_constraints.size(); } // constraint index from 1 to num_constraint - // information about the constraints - // int_vector constraint_k; // the right side k of a constraint - // int_vector constraint_slack; // =constraint_k[i]-true_terms[i], if >=0 then sat // int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing // bool_vector has_true_ob_terms; From 31c68b6e239c7ff8d417fb25115060243c9290d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Feb 2017 23:19:58 -0800 Subject: [PATCH 0069/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 82 +++++++++++++++++------------------ src/sat/sat_local_search.h | 79 ++++++++++++++++----------------- src/sat/sat_parallel.cpp | 55 +++++++++++++++++++++++ src/sat/sat_parallel.h | 12 +++++ src/sat/sat_solver.cpp | 6 +-- src/test/sat_local_search.cpp | 33 ++++++++------ 6 files changed, 170 insertions(+), 97 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 4e4db015f..24d4ebbd0 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -21,6 +21,7 @@ #include "sat_solver.h" #include "card_extension.h" #include "sat_params.hpp" +#include "timer.h" namespace sat { @@ -65,7 +66,7 @@ namespace sat { void local_search::init_cur_solution() { //cur_solution.resize(num_vars() + 1, false); for (unsigned v = 0; v < num_vars(); ++v) { - cur_solution[v] = (rand() % 2 == 1); + cur_solution[v] = (m_rand() % 2 == 1); } } @@ -138,7 +139,7 @@ namespace sat { init_cur_solution(); // init varibale information - // variable 0 is the virtual variable + // the last variable is the virtual variable m_vars.back().m_score = INT_MIN; m_vars.back().m_conf_change = false; @@ -169,8 +170,6 @@ namespace sat { if (objective_value > best_objective_value) { best_solution = cur_solution; best_objective_value = objective_value; - stop = clock(); - best_time = (double)(stop - start) / CLOCKS_PER_SEC; } } @@ -197,7 +196,8 @@ namespace sat { } } - local_search::local_search(solver& s) { + local_search::local_search(solver& s) : + m_par(0) { // copy units unsigned trail_sz = s.init_trail_size(); @@ -264,7 +264,7 @@ namespace sat { add_cardinality(lits.size(), lits.c_ptr(), n); } // - // optionally handle xor constraints. + // xor constraints should be disabled. // SASSERT(ext->m_xors.empty()); } @@ -273,24 +273,31 @@ namespace sat { local_search::~local_search() { } - void local_search::add_soft(int v, int weight) { - // TBD - ob_term t; - t.var_id = v; - t.coefficient = weight; - ob_constraint.push_back(t); + void local_search::add_soft(bool_var v, int weight) { + ob_constraint.push_back(ob_term(v, weight)); + } + + lbool local_search::check(parallel& p) { + flet _p(m_par, &p); + return check(); + } + + lbool local_search::check() { + return check(0, 0); } - lbool local_search::operator()() { + lbool local_search::check(unsigned sz, literal const* assumptions) { //sat_params params; //std::cout << "my parameter value: " << params.cliff() << "\n"; + unsigned num_constraints = m_constraints.size(); + for (unsigned i = 0; i < sz; ++i) { + add_clause(1, assumptions + i); + } init(); - bool reach_cutoff_time = false; bool reach_known_best_value = false; bool_var flipvar; - double elapsed_time = 0; - //clock_t start = clock(), stop; // TBD, use stopwatch facility - start = clock(); + timer timer; + timer.start(); // ################## start ###################### //std::cout << "Start initialize and local search, restart in every " << max_steps << " steps\n"; unsigned tries, step; @@ -309,25 +316,20 @@ namespace sat { flip(flipvar); m_vars[flipvar].m_time_stamp = step; } - if (tries % 10 == 0) { - // take a look at watch - stop = clock(); - elapsed_time = (double)(stop - start) / CLOCKS_PER_SEC; - std::cout << tries << ": " << elapsed_time << '\n'; - } - if (elapsed_time > cutoff_time) - reach_cutoff_time = true; - if (reach_known_best_value || reach_cutoff_time) + IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << tries << ": " << timer.get_seconds() << '\n';); + + if (!m_limit.inc()) break; } - if (reach_known_best_value) { - std::cout << elapsed_time << "\n"; - } - else { - std::cout << -1 << "\n"; - } + IF_VERBOSE(1, verbose_stream() << timer.get_seconds() << " " << (reach_known_best_value ? "reached":"not reached") << "\n";); + + // remove unit clauses from assumptions. + m_constraints.shrink(num_constraints); //print_solution(); - std::cout << tries * max_steps + step << '\n'; + IF_VERBOSE(1, verbose_stream() << tries * max_steps + step << '\n';); + if (m_unsat_stack.empty() && ob_constraint.empty()) { // or all variables in ob_constraint are true + return l_true; + } // TBD: adjust return status return l_undef; } @@ -354,7 +356,7 @@ namespace sat { case -2: // from -1 to -2 for (unsigned j = 0; j < c.size(); ++j) { v = c[j].var(); - // flipping the slack increasing var will no long sat this constraint + // flipping the slack increasing var will no longer satisfy this constraint if (is_true(c[j])) { //score[v] -= constraint_weight[c]; dec_score(v); @@ -378,7 +380,7 @@ namespace sat { v = c[j].var(); // flip the slack decreasing var will falsify this constraint if (is_false(c[j])) { - //score[v] -= constraint_weight[c]; + // score[v] -= constraint_weight[c]; dec_score(v); dec_slack_score(v); } @@ -459,14 +461,13 @@ namespace sat { vi.m_in_goodvar_stack = true; } } - } bool local_search::tie_breaker_sat(bool_var v, bool_var best_var) { // most improvement on objective value int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint.get(v, 0) : coefficient_in_ob_constraint.get(v, 0); int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint.get(best_var, 0) : coefficient_in_ob_constraint.get(best_var, 0); - //std::cout << v_imp << "\n"; + // std::cout << v_imp << "\n"; // break tie 1: max imp // break tie 2: conf_change // break tie 3: time_stamp @@ -521,7 +522,7 @@ namespace sat { } // Diversification Mode - constraint const& c = m_constraints[m_unsat_stack[rand() % m_unsat_stack.size()]]; // a random unsat constraint + constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; // a random unsat constraint // Within c, from all slack increasing var, choose the oldest one unsigned c_size = c.size(); for (unsigned i = 0; i < c_size; ++i) { @@ -534,13 +535,10 @@ namespace sat { void local_search::set_parameters() { - srand(m_config.seed()); - cutoff_time = m_config.cutoff_time(); + m_rand.set_seed(m_config.seed()); s_id = m_config.strategy_id(); best_known_value = m_config.best_known_value(); - - if (s_id == 0) max_steps = 2 * num_vars(); else { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 4d51fe519..cba49e8ed 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -21,30 +21,29 @@ #include "vector.h" #include "sat_types.h" +#include "rlimit.h" namespace sat { + class parallel; + class local_search_config { unsigned m_seed; - unsigned m_cutoff_time; unsigned m_strategy_id; int m_best_known_value; public: local_search_config() { m_seed = 0; - m_cutoff_time = 1; m_strategy_id = 0; m_best_known_value = INT_MAX; } unsigned seed() const { return m_seed; } - unsigned cutoff_time() const { return m_cutoff_time; } unsigned strategy_id() const { return m_strategy_id; } unsigned best_known_value() const { return m_best_known_value; } void set_seed(unsigned s) { m_seed = s; } - void set_cutoff_time(unsigned t) { m_cutoff_time = t; } void set_strategy_id(unsigned i) { m_strategy_id = i; } void set_best_known_value(unsigned v) { m_best_known_value = v; } }; @@ -58,21 +57,8 @@ namespace sat { struct ob_term { bool_var var_id; // variable id, begin with 1 int coefficient; // non-zero integer + ob_term(bool_var v, int c): var_id(v), coefficient(c) {} }; - - // data structure for a term in constraint - struct term { - bool_var var_id; // variable id, begin with 1 - bool sense; // 1 for positive, 0 for negative - //int coefficient; // all constraints are cardinality: coefficient=1 - }; - - - // objective function: maximize - svector ob_constraint; // the objective function *constraint*, sorted in decending order - - // information about the variable - int_vector coefficient_in_ob_constraint; // initialized to be 0 struct var_info { bool m_conf_change; // whether its configure changes since its last flip @@ -92,6 +78,24 @@ namespace sat { {} }; + struct constraint { + unsigned m_k; + int m_slack; + literal_vector m_literals; + constraint(unsigned k) : m_k(k), m_slack(0) {} + unsigned size() const { return m_literals.size(); } + literal const& operator[](unsigned idx) const { return m_literals[idx]; } + }; + + local_search_config m_config; + + // objective function: maximize + svector ob_constraint; // the objective function *constraint*, sorted in decending order + + // information about the variable + int_vector coefficient_in_ob_constraint; // var! initialized to be 0 + + vector m_vars; inline int score(bool_var v) const { return m_vars[v].m_score; } @@ -107,23 +111,14 @@ namespace sat { inline int time_stamp(bool_var v) const { return m_vars[v].m_time_stamp; } inline int cscc(bool_var v) const { return m_vars[v].m_cscc; } inline void inc_cscc(bool_var v) { m_vars[v].m_cscc++; } - - unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars /* TBD: other scores */ - struct constraint { - unsigned m_k; - int m_slack; - literal_vector m_literals; - constraint(unsigned k) : m_k(k), m_slack(0) {} - unsigned size() const { return m_literals.size(); } - literal const& operator[](unsigned idx) const { return m_literals[idx]; } - }; vector m_constraints; inline bool is_pos(literal t) const { return !t.sign(); } + inline bool is_true(bool_var v) const { return cur_solution[v]; } inline bool is_true(literal l) const { return cur_solution[l.var()] != l.sign(); } inline bool is_false(literal l) const { return cur_solution[l.var()] == l.sign(); } @@ -141,22 +136,21 @@ namespace sat { int_vector goodvar_stack; // information about solution - bool_vector cur_solution; // the current solution + bool_vector cur_solution; // !var: the current solution int objective_value; // the objective function value corresponds to the current solution - bool_vector best_solution; // the best solution so far + bool_vector best_solution; // !var: the best solution so far int best_objective_value = -1; // the objective value corresponds to the best solution so far // for non-known instance, set as maximal int best_known_value = INT_MAX; // best known value for this instance - // cutoff - int cutoff_time = 1; // seconds unsigned max_steps = 2000000000; // < 2147483647 - clock_t start, stop; - double best_time; // for tuning int s_id = 0; // strategy id + reslimit m_limit; + random_gen m_rand; + parallel* m_par; void init(); void reinit(); @@ -220,24 +214,31 @@ namespace sat { m_unsat_stack.pop_back(); } + public: local_search(solver& s); + reslimit& rlimit() { return m_limit; } + ~local_search(); - void add_soft(int l, int weight); + void add_soft(bool_var v, int weight); void add_cardinality(unsigned sz, literal const* c, unsigned k); - lbool operator()(); + lbool check(); - lbool check(unsigned sz, literal const* assumptions) { return l_undef; } // TBD + lbool check(unsigned sz, literal const* assumptions); - void cancel() {} // TBD + lbool check(parallel& p); local_search_config& config() { return m_config; } - local_search_config m_config; + unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars + + void set_phase(bool_var v, bool f) {} + + bool get_phase(bool_var v) const { return is_true(v); } }; } diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index bc7ac408e..aa9edefe0 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -106,6 +106,7 @@ namespace sat { for (unsigned i = 0; i < num_extra_solvers; ++i) { m_limits.push_back(reslimit()); } + for (unsigned i = 0; i < num_extra_solvers; ++i) { s.m_params.set_uint("random_seed", s.m_rand()); if (i == 1 + num_threads/2) { @@ -204,5 +205,59 @@ namespace sat { return (c.size() <= 40 && c.glue() <= 8) || c.glue() <= 2; } + void parallel::set_phase(solver& s) { + #pragma omp critical (par_solver) + { + m_phase.reserve(s.num_vars(), 0); + for (unsigned i = 0; i < s.num_vars(); ++i) { + if (s.value(i) != l_undef) { + m_phase[i] += (s.value(i) == l_true) ? 1 : -1; + continue; + } + switch (s.m_phase[i]) { + case POS_PHASE: + m_phase[i]++; + break; + case NEG_PHASE: + m_phase[i]--; + break; + default: + break; + } + } + } + } + + void parallel::get_phase(solver& s) { + #pragma omp critical (par_solver) + { + m_phase.reserve(s.num_vars(), 0); + for (unsigned i = 0; i < s.num_vars(); ++i) { + if (m_phase[i] < 0) { + s.m_phase[i] = NEG_PHASE; + } + else if (m_phase[i] > 0) { + s.m_phase[i] = POS_PHASE; + } + } + } + } + + void parallel::get_phase(local_search& s) { + #pragma omp critical (par_solver) + { + m_phase.reserve(s.num_vars(), 0); + for (unsigned i = 0; i < s.num_vars(); ++i) { + if (m_phase[i] < 0) { + s.set_phase(i, false); + } + else if (m_phase[i] > 0) { + s.set_phase(i, true); + } + } + } + } + + }; diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index 56dc83aba..0c2ba4ed9 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -26,6 +26,8 @@ Revision History: namespace sat { + class local_search; + class parallel { // shared pool of learned clauses. @@ -56,6 +58,7 @@ namespace sat { index_set m_unit_set; literal_vector m_lits; vector_pool m_pool; + int_vector m_phase; scoped_limits m_scoped_rlimit; vector m_limits; @@ -86,6 +89,15 @@ namespace sat { // receive clauses from shared clause pool void get_clauses(solver& s); + + // exchange phase of variables. + void set_phase(solver& s); + + void get_phase(solver& s); + + void set_phase(local_search& s); + + void get_phase(local_search& s); }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 50e046905..cac06d52b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -864,7 +864,7 @@ namespace sat { lbool solver::check_par(unsigned num_lits, literal const* lits) { int num_threads = static_cast(m_config.m_num_threads); - int num_extra_solvers = num_threads - 1 + (m_local_search ? 1 : 0); + int num_extra_solvers = num_threads - 1 - (m_local_search ? 1 : 0); sat::parallel par(*this); par.reserve(num_threads, 1 << 12); par.init_solvers(*this, num_extra_solvers); @@ -878,7 +878,7 @@ namespace sat { for (int i = 0; i < num_threads; ++i) { try { lbool r = l_undef; - if (m_local_search && i + 1 == num_extra_solvers) { + if (m_local_search && i == num_extra_solvers) { r = m_local_search->check(num_lits, lits); } else if (i < num_extra_solvers) { @@ -898,7 +898,7 @@ namespace sat { } if (first) { if (m_local_search) { - m_local_search->cancel(); + m_local_search->rlimit().cancel(); } for (int j = 0; j < num_extra_solvers; ++j) { if (i != j) { diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index a835f6a35..f4dee3061 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -1,10 +1,13 @@ #include "sat_local_search.h" #include "sat_solver.h" +#include "cancel_eh.h" +#include "scoped_ctrl_c.h" +#include "scoped_timer.h" static bool build_instance(char const * filename, sat::solver& s, sat::local_search& local_search) { - char line[16383]; - int cur_term; + char line[16383]; + int cur_term; // for temperally storage std::ifstream infile(filename); @@ -62,7 +65,6 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea } infile.close(); - return true; } @@ -78,7 +80,9 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { char const* file_name = argv[i + 1]; ++i; - int v; + int cutoff_time = 1; + + int v; while (i + 1 < argc) { std::cout << argv[i + 1] << "\n"; // set other ad hoc parameters. @@ -86,19 +90,19 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { switch (argv[i + 1][1]) { case 's': // seed v = atoi(argv[i + 2]); - local_search.m_config.set_seed(v); + local_search.config().set_seed(v); break; case 't': // cutoff_time v = atoi(argv[i + 2]); - local_search.m_config.set_cutoff_time(v); + cutoff_time = v; break; case 'i': // strategy_id v = atoi(argv[i + 2]); - local_search.m_config.set_strategy_id(v); + local_search.config().set_strategy_id(v); break; case 'b': // best_known_value v = atoi(argv[i + 2]); - local_search.m_config.set_best_known_value(v); + local_search.config().set_best_known_value(v); break; default: ++i; @@ -114,10 +118,13 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { } //std::cout << "local instance built\n"; - local_search(); - // sat::solver s; - // populate the sat solver with clauses and cardinality consrtaints from the input - // call the lookahead solver. - // TBD + + // set up cancellation/timeout environment. + + cancel_eh eh(local_search.rlimit()); + scoped_ctrl_c ctrlc(eh, false, true); + scoped_timer timer(cutoff_time*1000, &eh); + local_search.check(); + } From fb4f6d654ae25db5a191f2ac2270c8ec7a867ac3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Feb 2017 23:35:50 -0800 Subject: [PATCH 0070/1283] add local search parameters and co-processor mode Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 2 ++ src/sat/sat_config.h | 1 + src/sat/sat_local_search.cpp | 10 ++++++---- src/sat/sat_parallel.cpp | 20 +++++++++++++++++++- src/sat/sat_parallel.h | 1 + src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 3 +++ 7 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index e5fac42ae..190e76ef8 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -36,6 +36,7 @@ namespace sat { m_glue_psm("glue_psm"), m_psm_glue("psm_glue") { m_num_threads = 1; + m_local_search = false; updt_params(p); } @@ -79,6 +80,7 @@ namespace sat { m_max_conflicts = p.max_conflicts(); m_num_threads = p.threads(); + m_local_search = p.local_search(); // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 6f29f485e..38805bc90 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -58,6 +58,7 @@ namespace sat { unsigned m_burst_search; unsigned m_max_conflicts; unsigned m_num_threads; + bool m_local_search; unsigned m_simplify_mult1; double m_simplify_mult2; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 24d4ebbd0..6c210c6c4 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -300,8 +300,8 @@ namespace sat { timer.start(); // ################## start ###################### //std::cout << "Start initialize and local search, restart in every " << max_steps << " steps\n"; - unsigned tries, step; - for (tries = 0; ; ++tries) { + unsigned tries, step = 0; + for (tries = 0; m_limit.inc(); ++tries) { reinit(); for (step = 1; step <= max_steps; ++step) { // feasible @@ -318,8 +318,10 @@ namespace sat { } IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << tries << ": " << timer.get_seconds() << '\n';); - if (!m_limit.inc()) - break; + // tell the SAT solvers about the phase of variables. + if (m_par && tries % 10 == 0) { + m_par->set_phase(*this); + } } IF_VERBOSE(1, verbose_stream() << timer.get_seconds() << " " << (reach_known_best_value ? "reached":"not reached") << "\n";); diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index aa9edefe0..c4bd66a8e 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -139,6 +139,8 @@ namespace sat { } } limit = m_units.size(); + + _get_phase(s); } } @@ -231,6 +233,12 @@ namespace sat { void parallel::get_phase(solver& s) { #pragma omp critical (par_solver) { + _get_phase(s); + } + } + + void parallel::_get_phase(solver& s) { + if (!m_phase.empty()) { m_phase.reserve(s.num_vars(), 0); for (unsigned i = 0; i < s.num_vars(); ++i) { if (m_phase[i] < 0) { @@ -243,7 +251,7 @@ namespace sat { } } - void parallel::get_phase(local_search& s) { + void parallel::set_phase(local_search& s) { #pragma omp critical (par_solver) { m_phase.reserve(s.num_vars(), 0); @@ -258,6 +266,16 @@ namespace sat { } } + void parallel::get_phase(local_search& s) { + #pragma omp critical (par_solver) + { + m_phase.reserve(s.num_vars(), 0); + for (unsigned i = 0; i < s.num_vars(); ++i) { + m_phase[i] += (s.get_phase(i) ? 1 : -1); + } + } + } + }; diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index 0c2ba4ed9..ffbed5c0c 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -52,6 +52,7 @@ namespace sat { bool enable_add(clause const& c) const; void _get_clauses(solver& s); + void _get_phase(solver& s); typedef hashtable index_set; literal_vector m_units; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 97497a220..a8fe3295b 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -28,4 +28,5 @@ def_module_params('sat', ('drat.check', BOOL, False, 'build up internal proof and check'), ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('xor.solver', BOOL, False, 'use xor solver'), + ('local_search', BOOL, False, 'add local search co-processor to find satisfiable solution'), )) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index cac06d52b..cf150217d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -782,6 +782,9 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); + if (m_config.m_local_search && !m_local_search) { + m_local_search = alloc(local_search, *this); + } if ((m_config.m_num_threads > 1 || m_local_search) && !m_par) { return check_par(num_lits, lits); } From 5c11d7f2b30eaf18c05ce2ab098c4745dab200fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Mar 2017 10:22:07 -0800 Subject: [PATCH 0071/1283] Sixue's updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 53 ++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 6c210c6c4..b58a1646c 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -65,8 +65,9 @@ namespace sat { void local_search::init_cur_solution() { //cur_solution.resize(num_vars() + 1, false); - for (unsigned v = 0; v < num_vars(); ++v) { + for (unsigned v = 1; v < num_vars(); ++v) { cur_solution[v] = (m_rand() % 2 == 1); + //std::cout << cur_solution[v] << '\n'; } } @@ -92,7 +93,6 @@ namespace sat { bool is_true = cur_solution[v]; int_vector& truep = m_vars[v].m_watch[is_true]; int_vector& falsep = m_vars[v].m_watch[!is_true]; - for (unsigned i = 0; i < falsep.size(); ++i) { constraint& c = m_constraints[falsep[i]]; // will --slack @@ -298,10 +298,13 @@ namespace sat { bool_var flipvar; timer timer; timer.start(); + bool reach_cutoff_time = false; + double elapsed_time; // ################## start ###################### //std::cout << "Start initialize and local search, restart in every " << max_steps << " steps\n"; + //std::cout << num_vars() << '\n'; unsigned tries, step = 0; - for (tries = 0; m_limit.inc(); ++tries) { + for (tries = 1; ; ++tries) { reinit(); for (step = 1; step <= max_steps; ++step) { // feasible @@ -314,21 +317,36 @@ namespace sat { } flipvar = pick_var(); flip(flipvar); - m_vars[flipvar].m_time_stamp = step; - } - IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << tries << ": " << timer.get_seconds() << '\n';); + //std::cout << flipvar << '\t' << m_unsat_stack.size() << '\n'; + //std::cout << goodvar_stack.size() << '\n'; + m_vars[flipvar].m_time_stamp = step; + //if (!m_limit.inc()) break;pick_flip(); + } + //IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << tries << ": " << timer.get_seconds() << '\n';); + // the following is for tesing + if (tries % 10 == 0) { + elapsed_time = timer.get_seconds(); + //std::cout << tries << '\t' << elapsed_time << '\n'; + if (elapsed_time > 300) { + reach_cutoff_time = true; + break; + } + } // tell the SAT solvers about the phase of variables. - if (m_par && tries % 10 == 0) { - m_par->set_phase(*this); + //if (m_par && tries % 10 == 0) { + //m_par->set_phase(*this); + if (reach_known_best_value || reach_cutoff_time) { + break; } } - IF_VERBOSE(1, verbose_stream() << timer.get_seconds() << " " << (reach_known_best_value ? "reached":"not reached") << "\n";); + std::cout << elapsed_time << '\t' << reach_known_best_value << '\t' << reach_cutoff_time << '\t' << best_objective_value << '\n'; + //IF_VERBOSE(1, verbose_stream() << timer.get_seconds() << " " << (reach_known_best_value ? "reached":"not reached") << "\n";); // remove unit clauses from assumptions. m_constraints.shrink(num_constraints); //print_solution(); - IF_VERBOSE(1, verbose_stream() << tries * max_steps + step << '\n';); + IF_VERBOSE(1, verbose_stream() << (tries - 1) * max_steps + step << '\n';); if (m_unsat_stack.empty() && ob_constraint.empty()) { // or all variables in ob_constraint are true return l_true; } @@ -434,7 +452,6 @@ namespace sat { break; } } - m_vars[flipvar].m_score = -org_flipvar_score; m_vars[flipvar].m_slack_score = -org_flipvar_slack_score; m_vars[flipvar].m_conf_change = false; @@ -457,10 +474,10 @@ namespace sat { unsigned sz = vi.m_neighbors.size(); for (unsigned i = 0; i < sz; ++i) { v = vi.m_neighbors[i]; - vi.m_conf_change = true; + m_vars[v].m_conf_change = true; if (score(v) > 0 && !already_in_goodvar_stack(v)) { goodvar_stack.push_back(v); - vi.m_in_goodvar_stack = true; + m_vars[v].m_in_goodvar_stack = true; } } } @@ -501,7 +518,7 @@ namespace sat { bool_var best_var = m_vars.size()-1; // sentinel variable // SAT Mode if (m_unsat_stack.empty()) { - //++as; + //std::cout << "as\t"; for (unsigned i = 0; i < ob_constraint.size(); ++i) { bool_var v = ob_constraint[i].var_id; if (tie_breaker_sat(v, best_var)) @@ -527,6 +544,7 @@ namespace sat { constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; // a random unsat constraint // Within c, from all slack increasing var, choose the oldest one unsigned c_size = c.size(); + //std::cout << "rd\t"; for (unsigned i = 0; i < c_size; ++i) { bool_var v = c[i].var(); if (is_true(c[i]) && time_stamp(v) < time_stamp(best_var)) @@ -538,11 +556,12 @@ namespace sat { void local_search::set_parameters() { m_rand.set_seed(m_config.seed()); + //srand(m_config.seed()); s_id = m_config.strategy_id(); best_known_value = m_config.best_known_value(); if (s_id == 0) - max_steps = 2 * num_vars(); + max_steps = 2 * (num_vars() - 1); else { std::cout << "Invalid strategy id!" << std::endl; exit(-1); @@ -557,8 +576,8 @@ namespace sat { } void local_search::print_info() { - for (unsigned v = 0; v < num_vars(); ++v) { - std::cout << m_vars[v].m_neighbors.size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; + for (unsigned v = 1; v < num_vars(); ++v) { + std::cout << v << "\t" << m_vars[v].m_neighbors.size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; } } } From 59baaea2191790ff63645c8dc7933eb4fb3be24e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Mar 2017 19:49:59 -0800 Subject: [PATCH 0072/1283] integrating local search, supporting top-level inequalities Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 50 ++++++------ src/sat/sat_local_search.cpp | 149 +++++++++++++++++++++++------------ src/sat/sat_local_search.h | 51 ++++-------- src/sat/sat_solver.cpp | 32 +++++--- src/sat/tactic/goal2sat.cpp | 32 +++----- src/shell/opt_frontend.cpp | 16 +++- 6 files changed, 186 insertions(+), 144 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index e0bb04c10..b98e6b182 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -60,11 +60,11 @@ namespace sat { void card_extension::init_watch(card& c, bool is_true) { clear_watch(c); - if (c.lit().sign() == is_true) { + if (c.lit() != null_literal && c.lit().sign() == is_true) { c.negate(); } TRACE("sat", display(tout << "init watch: ", c, true);); - SASSERT(value(c.lit()) == l_true); + SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); if (bound == sz) { for (unsigned i = 0; i < sz && !s().inconsistent(); ++i) { @@ -153,12 +153,12 @@ namespace sat { if (s().m_config.m_drat) { svector ps; literal_vector lits; - lits.push_back(~c.lit()); + if (c.lit() != null_literal) lits.push_back(~c.lit()); for (unsigned i = c.k(); i < c.size(); ++i) { lits.push_back(c[i]); } lits.push_back(lit); - ps.push_back(drat::premise(drat::s_ext(), c.lit())); + ps.push_back(drat::premise(drat::s_ext(), c.lit())); // null_literal case. s().m_drat.add(lits, ps); } s().assign(lit, justification::mk_ext_justification(c.index())); @@ -220,7 +220,7 @@ namespace sat { void card_extension::init_watch(xor& x, bool is_true) { clear_watch(x); - if (x.lit().sign() == is_true) { + if (x.lit() != null_literal && x.lit().sign() == is_true) { x.negate(); } unsigned sz = x.size(); @@ -261,7 +261,7 @@ namespace sat { if (s().m_config.m_drat) { svector ps; literal_vector lits; - lits.push_back(~x.lit()); + if (x.lit() != null_literal) lits.push_back(~x.lit()); for (unsigned i = 1; i < x.size(); ++i) { lits.push_back(x[i]); } @@ -302,7 +302,7 @@ namespace sat { TRACE("sat", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); SASSERT(value(alit) != l_undef); - SASSERT(value(x.lit()) == l_true); + SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); unsigned index = 0; for (; index <= 2; ++index) { if (x[index].var() == alit.var()) break; @@ -685,7 +685,7 @@ namespace sat { void card_extension::process_card(card& c, int offset) { literal lit = c.lit(); SASSERT(c.k() <= c.size()); - SASSERT(value(lit) == l_true); + SASSERT(lit == null_literal || value(lit) == l_true); SASSERT(0 < offset); for (unsigned i = c.k(); i < c.size(); ++i) { process_antecedent(c[i], offset); @@ -693,7 +693,9 @@ namespace sat { for (unsigned i = 0; i < c.k(); ++i) { inc_coeff(c[i], offset); } - process_antecedent(~lit, c.k() * offset); + if (lit != null_literal) { + process_antecedent(~lit, c.k() * offset); + } } void card_extension::process_antecedent(literal l, int offset) { @@ -742,6 +744,7 @@ namespace sat { literal lit = v == null_bool_var ? null_literal : literal(v, false); card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); m_cards.push_back(c); + std::cout << lit << "\n"; if (v == null_bool_var) { // it is an axiom. init_watch(*c, true); @@ -815,7 +818,7 @@ namespace sat { } else { xor& x = index2xor(idx); - if (lvl(x.lit()) > 0) r.push_back(x.lit()); + if (x.lit() != null_literal && lvl(x.lit()) > 0) r.push_back(x.lit()); if (x[1].var() == l.var()) { x.swap(0, 1); } @@ -885,8 +888,8 @@ namespace sat { } SASSERT(found);); - r.push_back(c.lit()); - SASSERT(value(c.lit()) == l_true); + if (c.lit() != null_literal) r.push_back(c.lit()); + SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); for (unsigned i = c.k(); i < c.size(); ++i) { SASSERT(value(c[i]) == l_false); r.push_back(~c[i]); @@ -894,9 +897,9 @@ namespace sat { } else { xor& x = index2xor(idx); - r.push_back(x.lit()); + if (x.lit() != null_literal) r.push_back(x.lit()); TRACE("sat", display(tout << l << " ", x, true);); - SASSERT(value(x.lit()) == l_true); + SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); SASSERT(x[0].var() == l.var() || x[1].var() == l.var()); if (x[0].var() == l.var()) { SASSERT(value(x[1]) != l_undef); @@ -922,7 +925,7 @@ namespace sat { SASSERT(0 < bound && bound < sz); SASSERT(value(alit) == l_false); - SASSERT(value(c.lit()) == l_true); + SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); unsigned index = 0; for (index = 0; index <= bound; ++index) { if (c[index] == alit) { @@ -985,7 +988,7 @@ namespace sat { ptr_vector::iterator it = begin, it2 = it, end = cards->end(); for (; it != end; ++it) { card& c = *(*it); - if (value(c.lit()) != l_true) { + if (c.lit() != null_literal && value(c.lit()) != l_true) { continue; } switch (add_assign(c, ~l)) { @@ -1028,7 +1031,7 @@ namespace sat { ptr_vector::iterator it = begin, it2 = it, end = xors->end(); for (; it != end; ++it) { xor& c = *(*it); - if (value(c.lit()) != l_true) { + if (c.lit() != null_literal && value(c.lit()) != l_true) { continue; } switch (add_assign(c, ~l)) { @@ -1101,7 +1104,8 @@ namespace sat { for (unsigned i = 0; i < c.size(); ++i) { lits.push_back(c[i]); } - result->add_at_least(c.lit().var(), lits, c.k()); + bool_var v = c.lit() == null_literal ? null_bool_var : c.lit().var(); + result->add_at_least(v, lits, c.k()); } for (unsigned i = 0; i < m_xors.size(); ++i) { literal_vector lits; @@ -1109,7 +1113,8 @@ namespace sat { for (unsigned i = 0; i < x.size(); ++i) { lits.push_back(x[i]); } - result->add_xor(x.lit().var(), lits); + bool_var v = x.lit() == null_literal ? null_bool_var : x.lit().var(); + result->add_xor(v, lits); } return result; } @@ -1285,7 +1290,7 @@ namespace sat { return !parity(x, 0); } bool card_extension::validate_unit_propagation(card const& c) { - if (value(c.lit()) != l_true) return false; + if (c.lit() != null_literal && value(c.lit()) != l_true) return false; for (unsigned i = c.k(); i < c.size(); ++i) { if (value(c[i]) != l_false) return false; } @@ -1353,7 +1358,7 @@ namespace sat { for (unsigned i = 0; i < c.size(); ++i) { p.push(c[i], offset); } - p.push(~c.lit(), offset*c.k()); + if (c.lit() != null_literal) p.push(~c.lit(), offset*c.k()); } else { literal_vector ls; @@ -1362,7 +1367,8 @@ namespace sat { for (unsigned i = 0; i < ls.size(); ++i) { p.push(~ls[i], offset); } - p.push(~index2xor(index).lit(), offset); + literal lxor = index2xor(index).lit(); + if (lxor != null_literal) p.push(~lxor, offset); } break; } diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index b58a1646c..979557d50 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -177,10 +177,6 @@ namespace sat { } - void local_search::display(std::ostream& out) { - - } - void local_search::add_clause(unsigned sz, literal const* c) { add_cardinality(sz, c, sz - 1); } @@ -243,25 +239,38 @@ namespace sat { unsigned n = c.size(); unsigned k = c.k(); - // c.lit() <=> c.lits() >= k - // - // (c.lits() < k) or c.lit() - // = (c.lits() + (n - k - 1)*~c.lit()) <= n - // - // ~c.lit() or (c.lits() >= k) - // = ~c.lit() or (~c.lits() <= n - k) - // = k*c.lit() + ~c.lits() <= n - // - lits.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]); - for (unsigned j = 0; j < n - k - 1; ++j) lits.push_back(~c.lit()); - add_cardinality(lits.size(), lits.c_ptr(), n); - - lits.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]); - for (unsigned j = 0; j < k; ++j) lits.push_back(c.lit()); - add_cardinality(lits.size(), lits.c_ptr(), n); + + if (c.lit() == null_literal) { + // c.lits() >= k + // <=> + // ~c.lits() <= n - k + lits.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]); + add_cardinality(lits.size(), lits.c_ptr(), n - k); + } + else { + // TBD: this doesn't really work + // + // c.lit() <=> c.lits() >= k + // + // (c.lits() < k) or c.lit() + // = (c.lits() + (n - k - 1)*~c.lit()) <= n + // + // ~c.lit() or (c.lits() >= k) + // = ~c.lit() or (~c.lits() <= n - k) + // = k*c.lit() + ~c.lits() <= n + // + lits.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]); + for (unsigned j = 0; j < n - k - 1; ++j) lits.push_back(~c.lit()); + add_cardinality(lits.size(), lits.c_ptr(), n); + + lits.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]); + for (unsigned j = 0; j < k; ++j) lits.push_back(c.lit()); + add_cardinality(lits.size(), lits.c_ptr(), n); + } } // // xor constraints should be disabled. @@ -277,83 +286,79 @@ namespace sat { ob_constraint.push_back(ob_term(v, weight)); } - lbool local_search::check(parallel& p) { - flet _p(m_par, &p); - return check(); - } - lbool local_search::check() { return check(0, 0); } - lbool local_search::check(unsigned sz, literal const* assumptions) { - //sat_params params; - //std::cout << "my parameter value: " << params.cliff() << "\n"; + lbool local_search::check(unsigned sz, literal const* assumptions, parallel* p) { + flet _p(m_par, p); + m_model.reset(); unsigned num_constraints = m_constraints.size(); for (unsigned i = 0; i < sz; ++i) { add_clause(1, assumptions + i); } init(); + reinit(); bool reach_known_best_value = false; bool_var flipvar; timer timer; timer.start(); - bool reach_cutoff_time = false; - double elapsed_time; // ################## start ###################### + IF_VERBOSE(1, verbose_stream() << "Unsat stack size: " << m_unsat_stack.size() << "\n";); //std::cout << "Start initialize and local search, restart in every " << max_steps << " steps\n"; //std::cout << num_vars() << '\n'; unsigned tries, step = 0; - for (tries = 1; ; ++tries) { + for (tries = 1; m_limit.inc() && !m_unsat_stack.empty(); ++tries) { reinit(); for (step = 1; step <= max_steps; ++step) { // feasible if (m_unsat_stack.empty()) { calculate_and_update_ob(); if (best_objective_value >= best_known_value) { - reach_known_best_value = true; break; } } flipvar = pick_var(); flip(flipvar); - //std::cout << flipvar << '\t' << m_unsat_stack.size() << '\n'; - //std::cout << goodvar_stack.size() << '\n'; m_vars[flipvar].m_time_stamp = step; //if (!m_limit.inc()) break;pick_flip(); } - //IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << tries << ": " << timer.get_seconds() << '\n';); + IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << tries << ": " << timer.get_seconds() << '\n';); // the following is for tesing - if (tries % 10 == 0) { - elapsed_time = timer.get_seconds(); - //std::cout << tries << '\t' << elapsed_time << '\n'; - if (elapsed_time > 300) { - reach_cutoff_time = true; - break; - } - } + // tell the SAT solvers about the phase of variables. //if (m_par && tries % 10 == 0) { //m_par->set_phase(*this); - if (reach_known_best_value || reach_cutoff_time) { - break; - } } - std::cout << elapsed_time << '\t' << reach_known_best_value << '\t' << reach_cutoff_time << '\t' << best_objective_value << '\n'; - //IF_VERBOSE(1, verbose_stream() << timer.get_seconds() << " " << (reach_known_best_value ? "reached":"not reached") << "\n";); // remove unit clauses from assumptions. m_constraints.shrink(num_constraints); //print_solution(); - IF_VERBOSE(1, verbose_stream() << (tries - 1) * max_steps + step << '\n';); + IF_VERBOSE(1, verbose_stream() << timer.get_seconds() << " steps: " << (tries - 1) * max_steps + step << " unsat stack: " << m_unsat_stack.size() << '\n';); if (m_unsat_stack.empty() && ob_constraint.empty()) { // or all variables in ob_constraint are true + extract_model(); return l_true; } // TBD: adjust return status return l_undef; } + + void local_search::sat(unsigned c) { + unsigned last_unsat_constraint = m_unsat_stack.back(); + int index = m_index_in_unsat_stack[c]; + m_unsat_stack[index] = last_unsat_constraint; + m_index_in_unsat_stack[last_unsat_constraint] = index; + m_unsat_stack.pop_back(); + } + + // swap the deleted one with the last one and pop + void local_search::unsat(unsigned c) { + m_index_in_unsat_stack[c] = m_unsat_stack.size(); + m_unsat_stack.push_back(c); + } + void local_search::flip(bool_var flipvar) { // already changed truth value!!!! @@ -580,4 +585,46 @@ namespace sat { std::cout << v << "\t" << m_vars[v].m_neighbors.size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; } } + + void local_search::extract_model() { + m_model.reset(); + for (unsigned v = 0; v < num_vars(); ++v) { + m_model.push_back(cur_solution[v] ? l_true : l_false); + } + } + + void local_search::display(std::ostream& out) const { + for (unsigned i = 0; i < m_constraints.size(); ++i) { + constraint const& c = m_constraints[i]; + display(out, c); + } + } + + void local_search::display(std::ostream& out, constraint const& c) const { + out << c.m_literals << " <= " << c.m_k << "\n"; + } + + void local_search::display(std::ostream& out, unsigned v, var_info const& vi) const { + out << "v" << v << "\n"; + } + + bool local_search::check_goodvar() { + unsigned g = 0; + for (unsigned v = 0; v < num_vars(); ++v) { + if (conf_change(v) && score(v) > 0) { + ++g; + if (!already_in_goodvar_stack(v)) + std::cout << "3\n"; + } + } + if (g == goodvar_stack.size()) + return true; + else { + if (g < goodvar_stack.size()) + std::cout << "1\n"; + else + std::cout << "2\n"; // delete too many + return false; + } + } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index cba49e8ed..530e9a67b 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -151,6 +151,7 @@ namespace sat { reslimit m_limit; random_gen m_rand; parallel* m_par; + model m_model; void init(); void reinit(); @@ -164,6 +165,10 @@ namespace sat { void flip(bool_var v); + void unsat(unsigned c); + + void sat(unsigned c); + bool tie_breaker_sat(bool_var v1, bool_var v2); bool tie_breaker_ccd(bool_var v1, bool_var v2); @@ -174,48 +179,22 @@ namespace sat { void verify_solution(); - void display(std::ostream& out); - void print_info(); - bool check_goodvar() { - unsigned g = 0; - for (unsigned v = 1; v <= num_vars(); ++v) { - if (conf_change(v) && score(v) > 0) { - ++g; - if (!already_in_goodvar_stack(v)) - std::cout << "3\n"; - } - } - if (g == goodvar_stack.size()) - return true; - else { - if (g < goodvar_stack.size()) - std::cout << "1\n"; - else - std::cout << "2\n"; // delete too many - return false; - } - } + void extract_model(); + + bool check_goodvar(); void add_clause(unsigned sz, literal const* c); + void display(std::ostream& out) const; - void unsat(int c) { - m_index_in_unsat_stack[c] = m_unsat_stack.size(); - m_unsat_stack.push_back(c); - } - // swap the deleted one with the last one and pop - void sat(int c) { - int last_unsat_constraint = m_unsat_stack.back(); - int index = m_index_in_unsat_stack[c]; - m_unsat_stack[index] = last_unsat_constraint; - m_index_in_unsat_stack[last_unsat_constraint] = index; - m_unsat_stack.pop_back(); - } + void display(std::ostream& out, constraint const& c) const; + void display(std::ostream& out, unsigned v, var_info const& vi) const; public: + local_search(solver& s); reslimit& rlimit() { return m_limit; } @@ -228,9 +207,7 @@ namespace sat { lbool check(); - lbool check(unsigned sz, literal const* assumptions); - - lbool check(parallel& p); + lbool check(unsigned sz, literal const* assumptions, parallel* p = 0); local_search_config& config() { return m_config; } @@ -239,6 +216,8 @@ namespace sat { void set_phase(bool_var v, bool f) {} bool get_phase(bool_var v) const { return is_true(v); } + + model& get_model() { return m_model; } }; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index cf150217d..eea696547 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -782,10 +782,7 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); - if (m_config.m_local_search && !m_local_search) { - m_local_search = alloc(local_search, *this); - } - if ((m_config.m_num_threads > 1 || m_local_search) && !m_par) { + if ((m_config.m_num_threads > 1 || m_config.m_local_search) && !m_par) { return check_par(num_lits, lits); } flet _searching(m_searching, true); @@ -866,8 +863,16 @@ namespace sat { lbool solver::check_par(unsigned num_lits, literal const* lits) { - int num_threads = static_cast(m_config.m_num_threads); - int num_extra_solvers = num_threads - 1 - (m_local_search ? 1 : 0); + bool use_local_search = m_config.m_local_search; + if (use_local_search) { + m_local_search = alloc(local_search, *this); + } + + int num_threads = static_cast(m_config.m_num_threads) + (use_local_search ? 1 : 0); + int num_extra_solvers = num_threads - 1 - (use_local_search ? 1 : 0); + +#define IS_LOCAL_SEARCH(i) i == num_extra_solvers && use_local_search + sat::parallel par(*this); par.reserve(num_threads, 1 << 12); par.init_solvers(*this, num_extra_solvers); @@ -881,12 +886,12 @@ namespace sat { for (int i = 0; i < num_threads; ++i) { try { lbool r = l_undef; - if (m_local_search && i == num_extra_solvers) { - r = m_local_search->check(num_lits, lits); - } - else if (i < num_extra_solvers) { + if (i < num_extra_solvers) { r = par.get_solver(i).check(num_lits, lits); } + else if (IS_LOCAL_SEARCH(i)) { + r = m_local_search->check(num_lits, lits); + } else { r = check(num_lits, lits); } @@ -897,6 +902,7 @@ namespace sat { finished_id = i; first = true; result = r; + std::cout << finished_id << " " << r << "\n"; } } if (first) { @@ -908,7 +914,7 @@ namespace sat { par.cancel_solver(j); } } - if (i != num_extra_solvers) { + if ((0 <= i && i < num_extra_solvers) || IS_LOCAL_SEARCH(i)) { canceled = !rlimit().inc(); if (!canceled) { rlimit().cancel(); @@ -936,10 +942,14 @@ namespace sat { m_core.reset(); m_core.append(par.get_solver(finished_id).get_core()); } + if (result == l_true && finished_id != -1 && IS_LOCAL_SEARCH(finished_id)) { + set_model(m_local_search->get_model()); + } if (!canceled) { rlimit().reset_cancel(); } set_par(0, 0); + m_local_search = 0; if (finished_id == -1) { switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 5e5625049..971843d55 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -424,15 +424,15 @@ struct goal2sat::imp { sat::literal_vector lits; unsigned sz = m_result_stack.size(); convert_pb_args(t->get_num_args(), lits); - sat::bool_var v = m_solver.mk_var(true); - sat::literal lit(v, sign); - m_ext->add_at_least(v, lits, k.get_unsigned()); - TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); if (root) { m_result_stack.reset(); - mk_clause(lit); + m_ext->add_at_least(sat::null_bool_var, lits, k.get_unsigned()); } else { + sat::bool_var v = m_solver.mk_var(true); + sat::literal lit(v, sign); + m_ext->add_at_least(v, lits, k.get_unsigned()); + TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); m_result_stack.shrink(sz - t->get_num_args()); m_result_stack.push_back(lit); } @@ -446,14 +446,14 @@ struct goal2sat::imp { for (unsigned i = 0; i < lits.size(); ++i) { lits[i].neg(); } - sat::bool_var v = m_solver.mk_var(true); - sat::literal lit(v, sign); - m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); if (root) { m_result_stack.reset(); - mk_clause(lit); + m_ext->add_at_least(sat::null_bool_var, lits, lits.size() - k.get_unsigned()); } else { + sat::bool_var v = m_solver.mk_var(true); + sat::literal lit(v, sign); + m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); m_result_stack.shrink(sz - t->get_num_args()); m_result_stack.push_back(lit); } @@ -463,9 +463,8 @@ struct goal2sat::imp { SASSERT(k.is_unsigned()); sat::literal_vector lits; convert_pb_args(t->get_num_args(), lits); - sat::bool_var v1 = m_solver.mk_var(true); - sat::bool_var v2 = m_solver.mk_var(true); - sat::literal l1(v1, false), l2(v2, false); + sat::bool_var v1 = root ? sat::null_bool_var : m_solver.mk_var(true); + sat::bool_var v2 = root ? sat::null_bool_var : m_solver.mk_var(true); m_ext->add_at_least(v1, lits, k.get_unsigned()); for (unsigned i = 0; i < lits.size(); ++i) { lits[i].neg(); @@ -473,16 +472,9 @@ struct goal2sat::imp { m_ext->add_at_least(v2, lits, lits.size() - k.get_unsigned()); if (root) { m_result_stack.reset(); - if (sign) { - mk_clause(~l1, ~l2); - } - else { - mk_clause(l1); - mk_clause(l2); - } - m_result_stack.reset(); } else { + sat::literal l1(v1, false), l2(v2, false); sat::bool_var v = m_solver.mk_var(); sat::literal l(v, false); mk_clause(~l, l1); diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 760fdcf54..c15680f72 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -186,7 +186,7 @@ class opb { app_ref parse_id() { bool negated = in.parse_token("~"); if (!in.parse_token("x")) { - std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\")\n"; + std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\" expected \"x\")\n"; exit(3); } app_ref p(m); @@ -228,10 +228,15 @@ class opb { return app_ref(m.mk_ite(e, c, arith.mk_numeral(rational(0), true)), m); } - void parse_objective() { + void parse_objective(bool is_min) { app_ref t = parse_term(); while (!in.parse_token(";") && !in.eof()) { - t = arith.mk_add(t, parse_term()); + if (is_min) { + t = arith.mk_add(t, parse_term()); + } + else { + t = arith.mk_sub(t, parse_term()); + } } g_handles.push_back(opt.add_objective(t, false)); } @@ -268,7 +273,10 @@ public: in.skip_line(); } else if (in.parse_token("min:")) { - parse_objective(); + parse_objective(true); + } + else if (in.parse_token("max:")) { + parse_objective(false); } else { parse_constraint(); From 2c7a978c161ceaa51e6db8c998810274395816a2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Mar 2017 20:37:07 -0800 Subject: [PATCH 0073/1283] debugging local Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 1 - src/sat/sat_local_search.cpp | 33 +++++++++++++++++++++++++-------- src/sat/sat_local_search.h | 4 +++- src/sat/sat_solver.cpp | 2 ++ 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index b98e6b182..1100428c5 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -744,7 +744,6 @@ namespace sat { literal lit = v == null_bool_var ? null_literal : literal(v, false); card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); m_cards.push_back(c); - std::cout << lit << "\n"; if (v == null_bool_var) { // it is an axiom. init_watch(*c, true); diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 979557d50..1117a9c68 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -173,14 +173,29 @@ namespace sat { } } - void local_search::verify_solution() { + void local_search::verify_solution() const { + for (unsigned i = 0; i < m_constraints.size(); ++i) { + verify_constraint(m_constraints[i]); + } + } + void local_search::verify_constraint(constraint const& c) const { + unsigned value = 0; + for (unsigned i = 0; i < c.size(); ++i) { + value += is_true(c[i]) ? 1 : 0; + } + if (c.m_k < value) { + display(std::cout << "violated constraint: ", c); + std::cout << "value: " << value << "\n"; + UNREACHABLE(); + } } void local_search::add_clause(unsigned sz, literal const* c) { add_cardinality(sz, c, sz - 1); } + // ~c <= k void local_search::add_cardinality(unsigned sz, literal const* c, unsigned k) { unsigned id = m_constraints.size(); m_constraints.push_back(constraint(k)); @@ -195,6 +210,8 @@ namespace sat { local_search::local_search(solver& s) : m_par(0) { + m_vars.reserve(s.num_vars()); + // copy units unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { @@ -205,7 +222,7 @@ namespace sat { { unsigned sz = s.m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { - literal l = ~to_literal(l_idx); + literal l1 = ~to_literal(l_idx); watch_list const & wlist = s.m_watches[l_idx]; watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); @@ -213,9 +230,9 @@ namespace sat { if (!it->is_binary_non_learned_clause()) continue; literal l2 = it->get_literal(); - if (l.index() > l2.index()) + if (l1.index() > l2.index()) continue; - literal ls[2] = { l, l2 }; + literal ls[2] = { l1, l2 }; add_clause(2, ls); } } @@ -239,18 +256,17 @@ namespace sat { unsigned n = c.size(); unsigned k = c.k(); - - if (c.lit() == null_literal) { // c.lits() >= k // <=> // ~c.lits() <= n - k lits.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]); + for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]); add_cardinality(lits.size(), lits.c_ptr(), n - k); } else { - // TBD: this doesn't really work + // TBD: this doesn't really work because scores are not properly updated for general PB constraints. + NOT_IMPLEMENTED_YET(); // // c.lit() <=> c.lits() >= k // @@ -337,6 +353,7 @@ namespace sat { //print_solution(); IF_VERBOSE(1, verbose_stream() << timer.get_seconds() << " steps: " << (tries - 1) * max_steps + step << " unsat stack: " << m_unsat_stack.size() << '\n';); if (m_unsat_stack.empty() && ob_constraint.empty()) { // or all variables in ob_constraint are true + verify_solution(); extract_model(); return l_true; } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 530e9a67b..c0d6f35d8 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -177,7 +177,9 @@ namespace sat { void calculate_and_update_ob(); - void verify_solution(); + void verify_solution() const; + + void verify_constraint(constraint const& c) const; void print_info(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index eea696547..3dbe87206 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -866,6 +866,7 @@ namespace sat { bool use_local_search = m_config.m_local_search; if (use_local_search) { m_local_search = alloc(local_search, *this); + m_local_search->config().set_seed(m_config.m_random_seed); } int num_threads = static_cast(m_config.m_num_threads) + (use_local_search ? 1 : 0); @@ -942,6 +943,7 @@ namespace sat { m_core.reset(); m_core.append(par.get_solver(finished_id).get_core()); } + std::cout << result << " id: " << finished_id << " is-local: " << (IS_LOCAL_SEARCH(finished_id)) << "\n"; if (result == l_true && finished_id != -1 && IS_LOCAL_SEARCH(finished_id)) { set_model(m_local_search->get_model()); } From b0a47ca897b289afd5b3629237020271bcfc707f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Mar 2017 08:11:38 -0800 Subject: [PATCH 0074/1283] disable pb sorting Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index b905ebff0..1afb56c1a 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -112,13 +112,14 @@ struct pb2bv_rewriter::imp { return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m); } +#if 0 expr_ref result(m); switch (is_le) { case l_true: if (mk_le(sz, args, k, result)) return result; else break; case l_false: if (mk_ge(sz, args, k, result)) return result; else break; case l_undef: if (mk_eq(sz, args, k, result)) return result; else break; } - +#endif // fall back to divide and conquer encoding. SASSERT(k.is_pos()); expr_ref zero(m), bound(m); From a37dfd3ab97bc7e3a6d9f2aaf0c13f78b275a91c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Mar 2017 09:25:05 -0800 Subject: [PATCH 0075/1283] refine logging for local search, add handling of <= for opb front-end Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 4 ++-- src/shell/opt_frontend.cpp | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 1117a9c68..0cf509693 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -340,7 +340,8 @@ namespace sat { m_vars[flipvar].m_time_stamp = step; //if (!m_limit.inc()) break;pick_flip(); } - IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << tries << ": " << timer.get_seconds() << '\n';); + IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << "(sat-local :tries " << tries << " :steps " << (tries - 1) * max_steps + step + << " :unsat " << m_unsat_stack.size() << " :time " << timer.get_seconds() << ")\n";); // the following is for tesing // tell the SAT solvers about the phase of variables. @@ -351,7 +352,6 @@ namespace sat { // remove unit clauses from assumptions. m_constraints.shrink(num_constraints); //print_solution(); - IF_VERBOSE(1, verbose_stream() << timer.get_seconds() << " steps: " << (tries - 1) * max_steps + step << " unsat stack: " << m_unsat_stack.size() << '\n';); if (m_unsat_stack.empty() && ob_constraint.empty()) { // or all variables in ob_constraint are true verify_solution(); extract_model(); diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index c15680f72..9c9bc54ab 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -254,6 +254,11 @@ class opb { in.parse_token(";"); break; } + if (in.parse_token("<=")) { + t = arith.mk_le(t, parse_coeff()); + in.parse_token(";"); + break; + } t = arith.mk_add(t, parse_term()); } opt.add_hard_constraint(t); From 40df1949f52d2d9a196aeff0d4839b8d12d62735 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Mar 2017 10:18:12 -0800 Subject: [PATCH 0076/1283] tweaking local search Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 87 ++++++++++++++++++++++-------------- src/sat/sat_local_search.h | 8 +++- src/sat/sat_parallel.cpp | 17 ++++--- src/sat/sat_parallel.h | 1 + src/sat/sat_solver.cpp | 5 +-- 5 files changed, 74 insertions(+), 44 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 0cf509693..b8376a02e 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -64,10 +64,8 @@ namespace sat { } void local_search::init_cur_solution() { - //cur_solution.resize(num_vars() + 1, false); - for (unsigned v = 1; v < num_vars(); ++v) { + for (unsigned v = 0; v < num_vars(); ++v) { cur_solution[v] = (m_rand() % 2 == 1); - //std::cout << cur_solution[v] << '\n'; } } @@ -172,6 +170,14 @@ namespace sat { best_objective_value = objective_value; } } + + bool local_search::all_objectives_are_met() const { + for (unsigned i = 0; i < ob_constraint.size(); ++i) { + bool_var v = ob_constraint[i].var_id; + if (!cur_solution[v]) return false; + } + return true; + } void local_search::verify_solution() const { for (unsigned i = 0; i < m_constraints.size(); ++i) { @@ -179,14 +185,19 @@ namespace sat { } } - void local_search::verify_constraint(constraint const& c) const { + unsigned local_search::constraint_value(constraint const& c) const { unsigned value = 0; for (unsigned i = 0; i < c.size(); ++i) { value += is_true(c[i]) ? 1 : 0; } + return value; + } + + void local_search::verify_constraint(constraint const& c) const { + unsigned value = constraint_value(c); if (c.m_k < value) { - display(std::cout << "violated constraint: ", c); - std::cout << "value: " << value << "\n"; + IF_VERBOSE(0, display(verbose_stream() << "violated constraint: ", c); + verbose_stream() << "value: " << value << "\n";); UNREACHABLE(); } } @@ -319,10 +330,6 @@ namespace sat { bool_var flipvar; timer timer; timer.start(); - // ################## start ###################### - IF_VERBOSE(1, verbose_stream() << "Unsat stack size: " << m_unsat_stack.size() << "\n";); - //std::cout << "Start initialize and local search, restart in every " << max_steps << " steps\n"; - //std::cout << num_vars() << '\n'; unsigned tries, step = 0; for (tries = 1; m_limit.inc() && !m_unsat_stack.empty(); ++tries) { reinit(); @@ -336,29 +343,37 @@ namespace sat { } flipvar = pick_var(); flip(flipvar); - m_vars[flipvar].m_time_stamp = step; - //if (!m_limit.inc()) break;pick_flip(); } - IF_VERBOSE(1, if (tries % 10 == 0) verbose_stream() << "(sat-local :tries " << tries << " :steps " << (tries - 1) * max_steps + step - << " :unsat " << m_unsat_stack.size() << " :time " << timer.get_seconds() << ")\n";); - // the following is for tesing + IF_VERBOSE(1, if (tries % 10 == 0) + verbose_stream() << "(sat-local-search" + << " :tries " << tries + << " :steps " << (tries - 1) * max_steps + step + << " :unsat " << m_unsat_stack.size() + << " :time " << timer.get_seconds() << ")\n";); // tell the SAT solvers about the phase of variables. - //if (m_par && tries % 10 == 0) { - //m_par->set_phase(*this); + if (m_par && tries % 10 == 0) { + m_par->set_phase(*this); + } } // remove unit clauses from assumptions. m_constraints.shrink(num_constraints); - //print_solution(); - if (m_unsat_stack.empty() && ob_constraint.empty()) { // or all variables in ob_constraint are true + + TRACE("sat", display(tout);); + + lbool result; + if (m_unsat_stack.empty() && all_objectives_are_met()) { verify_solution(); extract_model(); - return l_true; + result = l_true; } - // TBD: adjust return status - return l_undef; + else { + result = l_undef; + } + IF_VERBOSE(1, verbose_stream() << "(sat-local-search " << result << ")\n";); + return result; } @@ -589,17 +604,18 @@ namespace sat { exit(-1); } - /*std::cout << "seed:\t" << m_config.seed() << '\n'; - std::cout << "cutoff time:\t" << m_config.cutoff_time() << '\n'; - std::cout << "strategy id:\t" << m_config.strategy_id() << '\n'; - std::cout << "best_known_value:\t" << m_config.best_known_value() << '\n'; - std::cout << "max_steps:\t" << max_steps << '\n'; - */ + TRACE("sat", + tout << "seed:\t" << m_config.seed() << '\n'; + tout << "cutoff time:\t" << m_config.cutoff_time() << '\n'; + tout << "strategy id:\t" << m_config.strategy_id() << '\n'; + tout << "best_known_value:\t" << m_config.best_known_value() << '\n'; + tout << "max_steps:\t" << max_steps << '\n'; + ); } - void local_search::print_info() { - for (unsigned v = 1; v < num_vars(); ++v) { - std::cout << v << "\t" << m_vars[v].m_neighbors.size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; + void local_search::print_info(std::ostream& out) { + for (unsigned v = 0; v < num_vars(); ++v) { + out << "v" << v << "\t" << m_vars[v].m_neighbors.size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; } } @@ -614,11 +630,11 @@ namespace sat { for (unsigned i = 0; i < m_constraints.size(); ++i) { constraint const& c = m_constraints[i]; display(out, c); - } + } } void local_search::display(std::ostream& out, constraint const& c) const { - out << c.m_literals << " <= " << c.m_k << "\n"; + out << c.m_literals << " <= " << c.m_k << " lhs value: " << constraint_value(c) << "\n"; } void local_search::display(std::ostream& out, unsigned v, var_info const& vi) const { @@ -644,4 +660,9 @@ namespace sat { return false; } } + + void local_search::set_phase(bool_var v, bool f) { + std::cout << v << " " << f << "\n"; + } + } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index c0d6f35d8..4f067404d 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -177,11 +177,15 @@ namespace sat { void calculate_and_update_ob(); + bool all_objectives_are_met() const; + void verify_solution() const; void verify_constraint(constraint const& c) const; - void print_info(); + unsigned constraint_value(constraint const& c) const; + + void print_info(std::ostream& out); void extract_model(); @@ -215,7 +219,7 @@ namespace sat { unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars - void set_phase(bool_var v, bool f) {} + void set_phase(bool_var v, bool f); bool get_phase(bool_var v) const { return is_true(v); } diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index c4bd66a8e..8a1127546 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -141,6 +141,7 @@ namespace sat { limit = m_units.size(); _get_phase(s); + _set_phase(s); } } @@ -207,9 +208,8 @@ namespace sat { return (c.size() <= 40 && c.glue() <= 8) || c.glue() <= 2; } - void parallel::set_phase(solver& s) { - #pragma omp critical (par_solver) - { + void parallel::_set_phase(solver& s) { + if (!m_phase.empty()) { m_phase.reserve(s.num_vars(), 0); for (unsigned i = 0; i < s.num_vars(); ++i) { if (s.value(i) != l_undef) { @@ -230,6 +230,13 @@ namespace sat { } } + void parallel::set_phase(solver& s) { + #pragma omp critical (par_solver) + { + _set_phase(s); + } + } + void parallel::get_phase(solver& s) { #pragma omp critical (par_solver) { @@ -254,8 +261,7 @@ namespace sat { void parallel::set_phase(local_search& s) { #pragma omp critical (par_solver) { - m_phase.reserve(s.num_vars(), 0); - for (unsigned i = 0; i < s.num_vars(); ++i) { + for (unsigned i = 0; i < m_phase.size(); ++i) { if (m_phase[i] < 0) { s.set_phase(i, false); } @@ -263,6 +269,7 @@ namespace sat { s.set_phase(i, true); } } + m_phase.reserve(s.num_vars(), 0); } } diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index ffbed5c0c..cb68dd0f9 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -53,6 +53,7 @@ namespace sat { bool enable_add(clause const& c) const; void _get_clauses(solver& s); void _get_phase(solver& s); + void _set_phase(solver& s); typedef hashtable index_set; literal_vector m_units; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3dbe87206..a135ceee3 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -868,7 +868,6 @@ namespace sat { m_local_search = alloc(local_search, *this); m_local_search->config().set_seed(m_config.m_random_seed); } - int num_threads = static_cast(m_config.m_num_threads) + (use_local_search ? 1 : 0); int num_extra_solvers = num_threads - 1 - (use_local_search ? 1 : 0); @@ -891,7 +890,7 @@ namespace sat { r = par.get_solver(i).check(num_lits, lits); } else if (IS_LOCAL_SEARCH(i)) { - r = m_local_search->check(num_lits, lits); + r = m_local_search->check(num_lits, lits, &par); } else { r = check(num_lits, lits); @@ -903,7 +902,6 @@ namespace sat { finished_id = i; first = true; result = r; - std::cout << finished_id << " " << r << "\n"; } } if (first) { @@ -943,7 +941,6 @@ namespace sat { m_core.reset(); m_core.append(par.get_solver(finished_id).get_core()); } - std::cout << result << " id: " << finished_id << " is-local: " << (IS_LOCAL_SEARCH(finished_id)) << "\n"; if (result == l_true && finished_id != -1 && IS_LOCAL_SEARCH(finished_id)) { set_model(m_local_search->get_model()); } From c6f943e4d60337a636b56e2c6cff2a0c887b6e4d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Mar 2017 11:23:06 -0800 Subject: [PATCH 0077/1283] updates to local search integration Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 41 +++++++++++++++++++++++------------- src/sat/sat_local_search.h | 14 ++++++++---- src/sat/sat_parallel.cpp | 4 ++-- src/sat/sat_solver.cpp | 1 + 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index b8376a02e..2fccf4877 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -31,7 +31,6 @@ namespace sat { m_vars.push_back(var_info()); best_solution.resize(num_vars() + 1, false); - cur_solution.resize(num_vars() + 1, false); m_index_in_unsat_stack.resize(num_constraints(), 0); coefficient_in_ob_constraint.resize(num_vars() + 1, 0); @@ -65,7 +64,7 @@ namespace sat { void local_search::init_cur_solution() { for (unsigned v = 0; v < num_vars(); ++v) { - cur_solution[v] = (m_rand() % 2 == 1); + m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); } } @@ -88,7 +87,7 @@ namespace sat { // figure out variables scores and slack_scores void local_search::init_scores() { for (unsigned v = 0; v < num_vars(); ++v) { - bool is_true = cur_solution[v]; + bool is_true = cur_solution(v); int_vector& truep = m_vars[v].m_watch[is_true]; int_vector& falsep = m_vars[v].m_watch[!is_true]; for (unsigned i = 0; i < falsep.size(); ++i) { @@ -162,11 +161,14 @@ namespace sat { objective_value = 0; for (i = 0; i < ob_constraint.size(); ++i) { v = ob_constraint[i].var_id; - if (cur_solution[v]) + if (cur_solution(v)) objective_value += ob_constraint[i].coefficient; } if (objective_value > best_objective_value) { - best_solution = cur_solution; + best_solution.reset(); + for (unsigned v = 0; v < num_vars(); ++v) { + best_solution.push_back(cur_solution(v)); + } best_objective_value = objective_value; } } @@ -174,7 +176,7 @@ namespace sat { bool local_search::all_objectives_are_met() const { for (unsigned i = 0; i < ob_constraint.size(); ++i) { bool_var v = ob_constraint[i].var_id; - if (!cur_solution[v]) return false; + if (!cur_solution(v)) return false; } return true; } @@ -216,6 +218,9 @@ namespace sat { m_vars[t.var()].m_watch[is_pos(t)].push_back(id); m_constraints.back().m_literals.push_back(t); } + if (sz == 1 && k == 0) { + m_vars[c[0].var()].m_bias = c[0].sign() ? 0 : 100; + } } local_search::local_search(solver& s) : @@ -354,7 +359,7 @@ namespace sat { // tell the SAT solvers about the phase of variables. if (m_par && tries % 10 == 0) { - m_par->set_phase(*this); + m_par->get_phase(*this); } } @@ -373,6 +378,7 @@ namespace sat { result = l_undef; } IF_VERBOSE(1, verbose_stream() << "(sat-local-search " << result << ")\n";); + IF_VERBOSE(2, display(verbose_stream());); return result; } @@ -394,13 +400,13 @@ namespace sat { void local_search::flip(bool_var flipvar) { // already changed truth value!!!! - cur_solution[flipvar] = !cur_solution[flipvar]; + m_vars[flipvar].m_value = !cur_solution(flipvar); unsigned v; int org_flipvar_score = score(flipvar); int org_flipvar_slack_score = slack_score(flipvar); - bool flip_is_true = cur_solution[flipvar]; + bool flip_is_true = cur_solution(flipvar); int_vector& truep = m_vars[flipvar].m_watch[flip_is_true]; int_vector& falsep = m_vars[flipvar].m_watch[!flip_is_true]; @@ -521,8 +527,8 @@ namespace sat { bool local_search::tie_breaker_sat(bool_var v, bool_var best_var) { // most improvement on objective value - int v_imp = cur_solution[v] ? -coefficient_in_ob_constraint.get(v, 0) : coefficient_in_ob_constraint.get(v, 0); - int b_imp = cur_solution[best_var] ? -coefficient_in_ob_constraint.get(best_var, 0) : coefficient_in_ob_constraint.get(best_var, 0); + int v_imp = cur_solution(v) ? -coefficient_in_ob_constraint.get(v, 0) : coefficient_in_ob_constraint.get(v, 0); + int b_imp = cur_solution(best_var) ? -coefficient_in_ob_constraint.get(best_var, 0) : coefficient_in_ob_constraint.get(best_var, 0); // std::cout << v_imp << "\n"; // break tie 1: max imp // break tie 2: conf_change @@ -615,14 +621,14 @@ namespace sat { void local_search::print_info(std::ostream& out) { for (unsigned v = 0; v < num_vars(); ++v) { - out << "v" << v << "\t" << m_vars[v].m_neighbors.size() << '\t' << cur_solution[v] << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; + out << "v" << v << "\t" << m_vars[v].m_neighbors.size() << '\t' << cur_solution(v) << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; } } void local_search::extract_model() { m_model.reset(); for (unsigned v = 0; v < num_vars(); ++v) { - m_model.push_back(cur_solution[v] ? l_true : l_false); + m_model.push_back(cur_solution(v) ? l_true : l_false); } } @@ -631,6 +637,9 @@ namespace sat { constraint const& c = m_constraints[i]; display(out, c); } + for (bool_var v = 0; v < num_vars(); ++v) { + display(out, v, m_vars[v]); + } } void local_search::display(std::ostream& out, constraint const& c) const { @@ -638,7 +647,7 @@ namespace sat { } void local_search::display(std::ostream& out, unsigned v, var_info const& vi) const { - out << "v" << v << "\n"; + out << "v" << v << " := " << (vi.m_value?"true":"false") << " bias: " << vi.m_bias << "\n"; } bool local_search::check_goodvar() { @@ -662,7 +671,9 @@ namespace sat { } void local_search::set_phase(bool_var v, bool f) { - std::cout << v << " " << f << "\n"; + unsigned& bias = m_vars[v].m_bias; + if (f && bias < 100) bias++; + if (!f && bias > 0) bias--; } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 4f067404d..75bfdbb54 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -61,6 +61,9 @@ namespace sat { }; struct var_info { + bool m_value; // current solution + unsigned m_bias; // bias for current solution in percentage. + // if bias is 0, then value is always false, if 100, then always true bool m_conf_change; // whether its configure changes since its last flip bool m_in_goodvar_stack; int m_score; @@ -70,6 +73,8 @@ namespace sat { bool_var_vector m_neighbors; // neighborhood variables int_vector m_watch[2]; var_info(): + m_value(true), + m_bias(50), m_conf_change(true), m_in_goodvar_stack(false), m_score(0), @@ -111,6 +116,8 @@ namespace sat { inline int time_stamp(bool_var v) const { return m_vars[v].m_time_stamp; } inline int cscc(bool_var v) const { return m_vars[v].m_cscc; } inline void inc_cscc(bool_var v) { m_vars[v].m_cscc++; } + + inline bool cur_solution(bool_var v) const { return m_vars[v].m_value; } /* TBD: other scores */ @@ -118,9 +125,9 @@ namespace sat { vector m_constraints; inline bool is_pos(literal t) const { return !t.sign(); } - inline bool is_true(bool_var v) const { return cur_solution[v]; } - inline bool is_true(literal l) const { return cur_solution[l.var()] != l.sign(); } - inline bool is_false(literal l) const { return cur_solution[l.var()] == l.sign(); } + inline bool is_true(bool_var v) const { return cur_solution(v); } + inline bool is_true(literal l) const { return cur_solution(l.var()) != l.sign(); } + inline bool is_false(literal l) const { return cur_solution(l.var()) == l.sign(); } unsigned num_constraints() const { return m_constraints.size(); } // constraint index from 1 to num_constraint @@ -136,7 +143,6 @@ namespace sat { int_vector goodvar_stack; // information about solution - bool_vector cur_solution; // !var: the current solution int objective_value; // the objective function value corresponds to the current solution bool_vector best_solution; // !var: the best solution so far int best_objective_value = -1; // the objective value corresponds to the best solution so far diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 8a1127546..55c9d8125 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -258,7 +258,7 @@ namespace sat { } } - void parallel::set_phase(local_search& s) { + void parallel::get_phase(local_search& s) { #pragma omp critical (par_solver) { for (unsigned i = 0; i < m_phase.size(); ++i) { @@ -273,7 +273,7 @@ namespace sat { } } - void parallel::get_phase(local_search& s) { + void parallel::set_phase(local_search& s) { #pragma omp critical (par_solver) { m_phase.reserve(s.num_vars(), 0); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a135ceee3..01657951d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -963,6 +963,7 @@ namespace sat { \brief import lemmas/units from parallel sat solvers. */ void solver::exchange_par() { + if (m_par && at_search_lvl()) m_par->set_phase(*this); if (m_par && at_base_lvl()) m_par->get_clauses(*this); if (m_par && at_base_lvl()) { // SASSERT(scope_lvl() == search_lvl()); From 9777f43e759ea6ebf9b8d90e58f0151081777501 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Mar 2017 13:28:17 -0800 Subject: [PATCH 0078/1283] fiddle with phase Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 7 ++++--- src/sat/sat_local_search.h | 2 +- src/sat/sat_parallel.cpp | 35 +++++++++++++++-------------------- src/sat/sat_parallel.h | 2 +- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 2fccf4877..ace89c04d 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -670,10 +670,11 @@ namespace sat { } } - void local_search::set_phase(bool_var v, bool f) { + void local_search::set_phase(bool_var v, lbool f) { unsigned& bias = m_vars[v].m_bias; - if (f && bias < 100) bias++; - if (!f && bias > 0) bias--; + if (f == l_true && bias < 100) bias++; + if (f == l_false && bias > 0) bias--; + // f == l_undef ? } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 75bfdbb54..03206eb60 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -225,7 +225,7 @@ namespace sat { unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars - void set_phase(bool_var v, bool f); + void set_phase(bool_var v, lbool f); bool get_phase(bool_var v) const { return is_true(v); } diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 55c9d8125..4eb247fc0 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -210,20 +210,21 @@ namespace sat { void parallel::_set_phase(solver& s) { if (!m_phase.empty()) { - m_phase.reserve(s.num_vars(), 0); + m_phase.reserve(s.num_vars(), l_undef); for (unsigned i = 0; i < s.num_vars(); ++i) { if (s.value(i) != l_undef) { - m_phase[i] += (s.value(i) == l_true) ? 1 : -1; + m_phase[i] = s.value(i); continue; } switch (s.m_phase[i]) { case POS_PHASE: - m_phase[i]++; + m_phase[i] = l_true; break; case NEG_PHASE: - m_phase[i]--; + m_phase[i] = l_false; break; default: + m_phase[i] = l_undef; break; } } @@ -246,39 +247,33 @@ namespace sat { void parallel::_get_phase(solver& s) { if (!m_phase.empty()) { - m_phase.reserve(s.num_vars(), 0); + m_phase.reserve(s.num_vars(), l_undef); for (unsigned i = 0; i < s.num_vars(); ++i) { - if (m_phase[i] < 0) { - s.m_phase[i] = NEG_PHASE; - } - else if (m_phase[i] > 0) { - s.m_phase[i] = POS_PHASE; + switch (m_phase[i]) { + case l_false: s.m_phase[i] = NEG_PHASE; break; + case l_true: s.m_phase[i] = POS_PHASE; break; + default: break; } } } } - void parallel::get_phase(local_search& s) { + void parallel::get_phase(local_search& s) { #pragma omp critical (par_solver) { for (unsigned i = 0; i < m_phase.size(); ++i) { - if (m_phase[i] < 0) { - s.set_phase(i, false); - } - else if (m_phase[i] > 0) { - s.set_phase(i, true); - } + s.set_phase(i, m_phase[i]); } - m_phase.reserve(s.num_vars(), 0); + m_phase.reserve(s.num_vars(), l_undef); } } void parallel::set_phase(local_search& s) { #pragma omp critical (par_solver) { - m_phase.reserve(s.num_vars(), 0); + m_phase.reserve(s.num_vars(), l_undef); for (unsigned i = 0; i < s.num_vars(); ++i) { - m_phase[i] += (s.get_phase(i) ? 1 : -1); + m_phase[i] = s.get_phase(i) ? l_true : l_false; } } } diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index cb68dd0f9..4d8e4a82d 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -60,7 +60,7 @@ namespace sat { index_set m_unit_set; literal_vector m_lits; vector_pool m_pool; - int_vector m_phase; + svector m_phase; scoped_limits m_scoped_rlimit; vector m_limits; From 1e32f1fbb57748138dd7b4cf98f3c6236cf717da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Mar 2017 13:36:05 -0800 Subject: [PATCH 0079/1283] parameter example Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 2 ++ src/sat/sat_config.h | 1 + src/sat/sat_local_search.cpp | 1 + src/sat/sat_params.pyg | 1 + 4 files changed, 5 insertions(+) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 190e76ef8..5102511e8 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -37,6 +37,7 @@ namespace sat { m_psm_glue("psm_glue") { m_num_threads = 1; m_local_search = false; + m_local_search_parameter1 = 0; updt_params(p); } @@ -81,6 +82,7 @@ namespace sat { m_max_conflicts = p.max_conflicts(); m_num_threads = p.threads(); m_local_search = p.local_search(); + m_local_search_parameter1 = p.local_search_int(); // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 38805bc90..dd32fc28d 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -59,6 +59,7 @@ namespace sat { unsigned m_max_conflicts; unsigned m_num_threads; bool m_local_search; + unsigned m_local_search_parameter1; unsigned m_simplify_mult1; double m_simplify_mult2; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index ace89c04d..5c8b7f52f 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -226,6 +226,7 @@ namespace sat { local_search::local_search(solver& s) : m_par(0) { + std::cout << "Parameter1: " << s.m_config.m_local_search_parameter1 << "\n"; m_vars.reserve(s.num_vars()); // copy units diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index a8fe3295b..d95e5fc30 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -29,4 +29,5 @@ def_module_params('sat', ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('xor.solver', BOOL, False, 'use xor solver'), ('local_search', BOOL, False, 'add local search co-processor to find satisfiable solution'), + ('local_search.int', UINT, 0, 'arbitrary integer'), )) From d819784500de167a8054397c8471f77af1f273e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Mar 2017 16:10:18 -0800 Subject: [PATCH 0080/1283] walk/gsat Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- src/sat/sat_local_search.cpp | 177 ++++++++++++++++++++++++++++++++--- src/sat/sat_local_search.h | 31 +++++- 3 files changed, 189 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ca94689e..905a229b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ project(Z3 C CXX) set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 5) set(Z3_VERSION_PATCH 1) -set(Z3_VERSION_TWEAK 0) +set(Z3_VERSION_TWEAK 0303) set(Z3_FULL_VERSION 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") message(STATUS "Z3 version ${Z3_VERSION}") diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 5c8b7f52f..066f2457e 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -187,6 +187,13 @@ namespace sat { } } + void local_search::verify_unsat_stack() const { + for (unsigned i = 0; i < m_unsat_stack.size(); ++i) { + constraint const& c = m_constraints[m_unsat_stack[i]]; + SASSERT(c.m_k < constraint_value(c)); + } + } + unsigned local_search::constraint_value(constraint const& c) const { unsigned value = 0; for (unsigned i = 0; i < c.size(); ++i) { @@ -226,7 +233,6 @@ namespace sat { local_search::local_search(solver& s) : m_par(0) { - std::cout << "Parameter1: " << s.m_config.m_local_search_parameter1 << "\n"; m_vars.reserve(s.num_vars()); // copy units @@ -322,15 +328,28 @@ namespace sat { lbool local_search::check() { return check(0, 0); } - - lbool local_search::check(unsigned sz, literal const* assumptions, parallel* p) { - flet _p(m_par, p); - m_model.reset(); - unsigned num_constraints = m_constraints.size(); - for (unsigned i = 0; i < sz; ++i) { - add_clause(1, assumptions + i); + + void local_search::walksat() { + reinit(); + timer timer; + timer.start(); + unsigned step = 0, total_steps = 0, max_steps = (1 << 20); + for (unsigned tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { + for (step = 0; step < max_steps && !m_unsat_stack.empty(); ++step) { + pick_flip_walksat(); + } + total_steps += step; + if (tries % 10 == 0) { + IF_VERBOSE(1, verbose_stream() << "(sat-local-search" + << " :tries " << tries + << " :steps " << total_steps + << " :unsat " << m_unsat_stack.size() + << " :time " << timer.get_seconds() << ")\n";); + } } - init(); + } + + void local_search::gsat() { reinit(); bool reach_known_best_value = false; bool_var flipvar; @@ -347,8 +366,8 @@ namespace sat { break; } } - flipvar = pick_var(); - flip(flipvar); + flipvar = pick_var_gsat(); + flip_gsat(flipvar); m_vars[flipvar].m_time_stamp = step; } IF_VERBOSE(1, if (tries % 10 == 0) @@ -363,6 +382,26 @@ namespace sat { m_par->get_phase(*this); } } + } + + lbool local_search::check(unsigned sz, literal const* assumptions, parallel* p) { + flet _p(m_par, p); + m_model.reset(); + unsigned num_constraints = m_constraints.size(); + for (unsigned i = 0; i < sz; ++i) { + add_clause(1, assumptions + i); + } + init(); + + switch (m_config.mode()) { + case local_search_mode::gsat: + gsat(); + break; + case local_search_mode::wsat: + walksat(); + break; + } + // remove unit clauses from assumptions. m_constraints.shrink(num_constraints); @@ -398,7 +437,111 @@ namespace sat { m_unsat_stack.push_back(c); } - void local_search::flip(bool_var flipvar) + void local_search::pick_flip_walksat() { + m_good_vars.reset(); + bool_var v; + constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; + SASSERT(c.m_k < constraint_value(c)); + if (m_rand() % 100 < 5) { + // display(std::cout, c); + unsigned best_bsb = 0; + // find the first one, to fast break the rest + unsigned i = 0; + while (true) { + v = c[i].var(); + if (is_true(c[i])) { + bool tt = cur_solution(v); + int_vector const& falsep = m_vars[v].m_watch[!tt]; + for (unsigned j = 0; j < falsep.size(); ++j) { + unsigned ci = falsep[j]; + if (constraint_slack(ci) < 0) + ++best_bsb; + else if (constraint_slack(ci) == 0) + // >= unsat_stack_fill_pointer is enough + best_bsb += m_constraints.size(); + } + break; + } + ++i; + } + m_good_vars.push_back(v); + for (++i; i < c.size(); ++i) { + v = c[i].var(); + if (is_true(c[i])) { + bool found = false; + unsigned bsb = 0; + bool tt = cur_solution(v); + int_vector const& falsep = m_vars[v].m_watch[!tt]; + for (unsigned j = 0; j < falsep.size() && !found; ++j) { + unsigned ci = falsep[j]; + if (constraint_slack(ci) < 0) { + if (bsb == best_bsb) { + found = true; + } + else { + ++bsb; + } + } + else if (constraint_slack(ci) == 0) { + // >= unsat_stack_fill_pointer is enough + bsb += m_constraints.size(); + if (bsb > best_bsb) { + found = true; + } + } + } + if (!found) { + if (bsb < best_bsb) { + best_bsb = bsb; + m_good_vars.reset(); + m_good_vars.push_back(v); + } + else {// if (bb == best_bb) + m_good_vars.push_back(v); + } + } + } + } + } + else { + for (unsigned i = 0; i < c.size(); ++i) { + if (is_true(c[i])) + m_good_vars.push_back(c[i].var()); + } + } + SASSERT(!m_good_vars.empty()); + //std::cout << m_good_vars.size() << "\n"; + flip_walksat(m_good_vars[m_rand() % m_good_vars.size()]); + } + + void local_search::flip_walksat(bool_var flipvar) { + m_vars[flipvar].m_value = !cur_solution(flipvar); + + bool flip_is_true = cur_solution(flipvar); + int_vector& truep = m_vars[flipvar].m_watch[flip_is_true]; + int_vector& falsep = m_vars[flipvar].m_watch[!flip_is_true]; + + for (unsigned i = 0; i < truep.size(); ++i) { + unsigned ci = truep[i]; + constraint& c = m_constraints[ci]; + --c.m_slack; + if (c.m_slack == -1) { // from 0 to -1: sat -> unsat + unsat(ci); + } + } + for (unsigned i = 0; i < falsep.size(); ++i) { + unsigned ci = falsep[i]; + constraint& c = m_constraints[ci]; + ++c.m_slack; + if (c.m_slack == 0) { // from -1 to 0: unsat -> sat + sat(ci); + } + } + + // verify_unsat_stack(); + } + + void local_search::flip_gsat(bool_var flipvar) { // already changed truth value!!!! m_vars[flipvar].m_value = !cur_solution(flipvar); @@ -558,7 +701,7 @@ namespace sat { (time_stamp(v) < time_stamp(best_var)))))))); } - bool_var local_search::pick_var() { + bool_var local_search::pick_var_gsat() { bool_var best_var = m_vars.size()-1; // sentinel variable // SAT Mode if (m_unsat_stack.empty()) { @@ -613,7 +756,6 @@ namespace sat { TRACE("sat", tout << "seed:\t" << m_config.seed() << '\n'; - tout << "cutoff time:\t" << m_config.cutoff_time() << '\n'; tout << "strategy id:\t" << m_config.strategy_id() << '\n'; tout << "best_known_value:\t" << m_config.best_known_value() << '\n'; tout << "max_steps:\t" << max_steps << '\n'; @@ -622,7 +764,12 @@ namespace sat { void local_search::print_info(std::ostream& out) { for (unsigned v = 0; v < num_vars(); ++v) { - out << "v" << v << "\t" << m_vars[v].m_neighbors.size() << '\t' << cur_solution(v) << '\t' << conf_change(v) << '\t' << score(v) << '\t' << slack_score(v) << '\n'; + out << "v" << v << "\t" + << m_vars[v].m_neighbors.size() << '\t' + << cur_solution(v) << '\t' + << conf_change(v) << '\t' + << score(v) << '\t' + << slack_score(v) << '\n'; } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 03206eb60..f41dfed03 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -27,25 +27,33 @@ namespace sat { class parallel; + enum local_search_mode { + gsat, + wsat + }; + class local_search_config { unsigned m_seed; unsigned m_strategy_id; int m_best_known_value; + local_search_mode m_mode; public: - local_search_config() - { + local_search_config() { m_seed = 0; m_strategy_id = 0; m_best_known_value = INT_MAX; + m_mode = local_search_mode::wsat; } unsigned seed() const { return m_seed; } unsigned strategy_id() const { return m_strategy_id; } unsigned best_known_value() const { return m_best_known_value; } + local_search_mode mode() const { return m_mode; } void set_seed(unsigned s) { m_seed = s; } void set_strategy_id(unsigned i) { m_strategy_id = i; } void set_best_known_value(unsigned v) { m_best_known_value = v; } + void set_mode(local_search_mode m) { m_mode = m; } }; @@ -131,7 +139,8 @@ namespace sat { unsigned num_constraints() const { return m_constraints.size(); } // constraint index from 1 to num_constraint - + + unsigned constraint_slack(unsigned ci) const { return m_constraints[ci].m_slack; } // int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing // bool_vector has_true_ob_terms; @@ -142,6 +151,8 @@ namespace sat { // configuration changed decreasing variables (score>0 and conf_change==true) int_vector goodvar_stack; + svector m_good_vars; // candidate variables to flip on. + // information about solution int objective_value; // the objective function value corresponds to the current solution bool_vector best_solution; // !var: the best solution so far @@ -167,9 +178,17 @@ namespace sat { void init_scores(); void init_goodvars(); - bool_var pick_var(); + bool_var pick_var_gsat(); - void flip(bool_var v); + void flip_gsat(bool_var v); + + void pick_flip_walksat(); + + void flip_walksat(bool_var v); + + void walksat(); + + void gsat(); void unsat(unsigned c); @@ -187,6 +206,8 @@ namespace sat { void verify_solution() const; + void verify_unsat_stack() const; + void verify_constraint(constraint const& c) const; unsigned constraint_value(constraint const& c) const; From b5ace71bb8e9775f4462c581739f6c330ada003a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Mar 2017 17:37:55 -0800 Subject: [PATCH 0081/1283] current updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 44 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 066f2457e..21555cfcb 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -329,24 +329,30 @@ namespace sat { return check(0, 0); } +#define PROGRESS(tries, total_steps) \ + if (tries % 10 == 0 || m_unsat_stack.empty()) { \ + IF_VERBOSE(1, verbose_stream() << "(sat-local-search" \ + << " :tries " << tries \ + << " :steps " << total_steps \ + << " :unsat " << m_unsat_stack.size() \ + << " :time " << timer.get_seconds() << ")\n";); \ + } + void local_search::walksat() { reinit(); timer timer; timer.start(); - unsigned step = 0, total_steps = 0, max_steps = (1 << 20); - for (unsigned tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { + unsigned step = 0, total_steps = 0, max_steps = (1 << 17), tries = 0; + PROGRESS(tries, total_steps); + + for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { for (step = 0; step < max_steps && !m_unsat_stack.empty(); ++step) { pick_flip_walksat(); } total_steps += step; - if (tries % 10 == 0) { - IF_VERBOSE(1, verbose_stream() << "(sat-local-search" - << " :tries " << tries - << " :steps " << total_steps - << " :unsat " << m_unsat_stack.size() - << " :time " << timer.get_seconds() << ")\n";); - } + PROGRESS(tries, total_steps); } + PROGRESS(tries, total_steps); } void local_search::gsat() { @@ -355,33 +361,30 @@ namespace sat { bool_var flipvar; timer timer; timer.start(); - unsigned tries, step = 0; + unsigned tries, step = 0, total_steps = 0; for (tries = 1; m_limit.inc() && !m_unsat_stack.empty(); ++tries) { reinit(); - for (step = 1; step <= max_steps; ++step) { + for (step = 1; step <= max_steps; ) { // feasible if (m_unsat_stack.empty()) { calculate_and_update_ob(); if (best_objective_value >= best_known_value) { break; } - } + } flipvar = pick_var_gsat(); flip_gsat(flipvar); - m_vars[flipvar].m_time_stamp = step; + m_vars[flipvar].m_time_stamp = step++; } - IF_VERBOSE(1, if (tries % 10 == 0) - verbose_stream() << "(sat-local-search" - << " :tries " << tries - << " :steps " << (tries - 1) * max_steps + step - << " :unsat " << m_unsat_stack.size() - << " :time " << timer.get_seconds() << ")\n";); + total_steps += step; + PROGRESS(tries, total_steps); // tell the SAT solvers about the phase of variables. if (m_par && tries % 10 == 0) { m_par->get_phase(*this); } } + PROGRESS(tries, total_steps); } lbool local_search::check(unsigned sz, literal const* assumptions, parallel* p) { @@ -442,7 +445,8 @@ namespace sat { bool_var v; constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; SASSERT(c.m_k < constraint_value(c)); - if (m_rand() % 100 < 5) { + if (m_rand() % 100 < 98) { + // take this branch with 98% probability. // display(std::cout, c); unsigned best_bsb = 0; // find the first one, to fast break the rest From f16dcef7e2f8a722d59ce6288a9b7e7515410da6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Mar 2017 18:09:41 -0800 Subject: [PATCH 0082/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 34 ++++++++++++++++++++-------------- src/sat/sat_local_search.h | 7 +++++-- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 21555cfcb..557a5a9a2 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -223,8 +223,9 @@ namespace sat { m_vars.reserve(c[i].var() + 1); literal t(~c[i]); m_vars[t.var()].m_watch[is_pos(t)].push_back(id); - m_constraints.back().m_literals.push_back(t); + m_constraints.back().push(t); } + m_constraints.back().seal(); if (sz == 1 && k == 0) { m_vars[c[0].var()].m_bias = c[0].sign() ? 0 : 100; } @@ -447,50 +448,55 @@ namespace sat { SASSERT(c.m_k < constraint_value(c)); if (m_rand() % 100 < 98) { // take this branch with 98% probability. - // display(std::cout, c); unsigned best_bsb = 0; // find the first one, to fast break the rest unsigned i = 0; + literal const* lits = c.m_literals.c_ptr(); + literal l; while (true) { - v = c[i].var(); - if (is_true(c[i])) { + l = *lits; + if (is_true(l)) { + v = l.var(); bool tt = cur_solution(v); int_vector const& falsep = m_vars[v].m_watch[!tt]; - for (unsigned j = 0; j < falsep.size(); ++j) { + unsigned sz = falsep.size(); + for (unsigned j = 0; j < sz; ++j) { unsigned ci = falsep[j]; if (constraint_slack(ci) < 0) ++best_bsb; else if (constraint_slack(ci) == 0) - // >= unsat_stack_fill_pointer is enough - best_bsb += m_constraints.size(); + best_bsb += m_unsat_stack.size(); } break; } - ++i; + ++lits; } + ++lits; m_good_vars.push_back(v); - for (++i; i < c.size(); ++i) { - v = c[i].var(); - if (is_true(c[i])) { + for (; (l = *lits) != null_literal; ++lits) { + if (is_true(l)) { + v = l.var(); bool found = false; unsigned bsb = 0; bool tt = cur_solution(v); int_vector const& falsep = m_vars[v].m_watch[!tt]; - for (unsigned j = 0; j < falsep.size() && !found; ++j) { + unsigned sz = falsep.size(); + for (unsigned j = 0; j < sz; ++j) { unsigned ci = falsep[j]; if (constraint_slack(ci) < 0) { if (bsb == best_bsb) { found = true; + break; } else { ++bsb; } } else if (constraint_slack(ci) == 0) { - // >= unsat_stack_fill_pointer is enough - bsb += m_constraints.size(); + bsb += m_unsat_stack.size(); if (bsb > best_bsb) { found = true; + break; } } } diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index f41dfed03..cbd0d9d30 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -94,9 +94,12 @@ namespace sat { struct constraint { unsigned m_k; int m_slack; + unsigned m_size; literal_vector m_literals; - constraint(unsigned k) : m_k(k), m_slack(0) {} - unsigned size() const { return m_literals.size(); } + constraint(unsigned k) : m_k(k), m_slack(0), m_size(0) {} + void push(literal l) { m_literals.push_back(l); ++m_size; } + void seal() { m_literals.push_back(null_literal); } + unsigned size() const { return m_size; } literal const& operator[](unsigned idx) const { return m_literals[idx]; } }; From a7db118ebc4d508e565c54259b4581cc4fbe7b7b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Mar 2017 19:30:44 -0800 Subject: [PATCH 0083/1283] use iterators Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 63 ++++++++++++++++-------------------- src/sat/sat_local_search.h | 1 - 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 557a5a9a2..e297386e6 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -225,7 +225,6 @@ namespace sat { m_vars[t.var()].m_watch[is_pos(t)].push_back(id); m_constraints.back().push(t); } - m_constraints.back().seal(); if (sz == 1 && k == 0) { m_vars[c[0].var()].m_bias = c[0].sign() ? 0 : 100; } @@ -443,64 +442,56 @@ namespace sat { void local_search::pick_flip_walksat() { m_good_vars.reset(); - bool_var v; + bool_var v = null_bool_var; + unsigned num_unsat = m_unsat_stack.size(); constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; SASSERT(c.m_k < constraint_value(c)); if (m_rand() % 100 < 98) { // take this branch with 98% probability. - unsigned best_bsb = 0; // find the first one, to fast break the rest - unsigned i = 0; - literal const* lits = c.m_literals.c_ptr(); + unsigned best_bsb = 0; + literal_vector::const_iterator cit = c.m_literals.begin(), cend = c.m_literals.end(); literal l; - while (true) { - l = *lits; - if (is_true(l)) { - v = l.var(); - bool tt = cur_solution(v); - int_vector const& falsep = m_vars[v].m_watch[!tt]; - unsigned sz = falsep.size(); - for (unsigned j = 0; j < sz; ++j) { - unsigned ci = falsep[j]; - if (constraint_slack(ci) < 0) - ++best_bsb; - else if (constraint_slack(ci) == 0) - best_bsb += m_unsat_stack.size(); - } - break; - } - ++lits; + for (; !is_true(*cit); ++cit) { SASSERT(cit != cend); } + l = *cit; + v = l.var(); + bool tt = cur_solution(v); + int_vector const& falsep = m_vars[v].m_watch[!tt]; + int_vector::const_iterator it = falsep.begin(), end = falsep.end(); + for (; it != end; ++it) { + int slack = constraint_slack(*it); + if (slack < 0) + ++best_bsb; + else if (slack == 0) + best_bsb += num_unsat; } - ++lits; m_good_vars.push_back(v); - for (; (l = *lits) != null_literal; ++lits) { + ++cit; + for (; cit != cend; ++cit) { + l = *cit; if (is_true(l)) { v = l.var(); - bool found = false; unsigned bsb = 0; - bool tt = cur_solution(v); - int_vector const& falsep = m_vars[v].m_watch[!tt]; - unsigned sz = falsep.size(); - for (unsigned j = 0; j < sz; ++j) { - unsigned ci = falsep[j]; - if (constraint_slack(ci) < 0) { + int_vector const& falsep = m_vars[v].m_watch[!cur_solution(v)]; + int_vector::const_iterator it = falsep.begin(), end = falsep.end(); + for (; it != end; ++it) { + int slack = constraint_slack(*it); + if (slack < 0) { if (bsb == best_bsb) { - found = true; break; } else { ++bsb; } } - else if (constraint_slack(ci) == 0) { - bsb += m_unsat_stack.size(); + else if (slack == 0) { + bsb += num_unsat; if (bsb > best_bsb) { - found = true; break; } } } - if (!found) { + if (it == end) { if (bsb < best_bsb) { best_bsb = bsb; m_good_vars.reset(); diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index cbd0d9d30..5f76f4934 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -98,7 +98,6 @@ namespace sat { literal_vector m_literals; constraint(unsigned k) : m_k(k), m_slack(0), m_size(0) {} void push(literal l) { m_literals.push_back(l); ++m_size; } - void seal() { m_literals.push_back(null_literal); } unsigned size() const { return m_size; } literal const& operator[](unsigned idx) const { return m_literals[idx]; } }; From fda5809c89529a1848d47b5232aee761976627c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Mar 2017 14:40:58 -0800 Subject: [PATCH 0084/1283] local search updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 182 ++++++++++-------- src/sat/sat_local_search.h | 32 ++-- src/sat/sat_lookahead.h | 347 +++++++++++++++++++++-------------- src/sat/sat_parallel.cpp | 16 +- src/sat/sat_parallel.h | 6 +- src/sat/sat_solver.cpp | 29 ++- src/sat/sat_solver.h | 1 - 7 files changed, 364 insertions(+), 249 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index e297386e6..3dc37471e 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -1,21 +1,21 @@ /*++ Copyright (c) 2017 Microsoft Corporation - Module Name: +Module Name: sat_local_search.cpp - Abstract: +Abstract: Local search module for cardinality clauses. - Author: +Author: Sixue Liu 2017-2-21 - Notes: +Notes: - --*/ +--*/ #include "sat_local_search.h" #include "sat_solver.h" @@ -27,10 +27,18 @@ namespace sat { void local_search::init() { + for (unsigned i = 0; i < m_assumptions.size(); ++i) { + add_clause(1, m_assumptions.c_ptr() + i); + } + // add sentinel variable. m_vars.push_back(var_info()); - best_solution.resize(num_vars() + 1, false); + for (unsigned v = 0; v < num_vars(); ++v) { + m_vars[v].m_value = (0 == (m_rand() % 2)); + } + + m_best_solution.resize(num_vars() + 1, false); m_index_in_unsat_stack.resize(num_constraints(), 0); coefficient_in_ob_constraint.resize(num_vars() + 1, 0); @@ -58,13 +66,12 @@ namespace sat { set_parameters(); } - void local_search::reinit() { - reinit_orig(); - } - void local_search::init_cur_solution() { for (unsigned v = 0; v < num_vars(); ++v) { - m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); + // use bias half the time. + if (m_rand() % 100 < 50) { + m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); + } } } @@ -114,16 +121,16 @@ namespace sat { // init goodvars void local_search::init_goodvars() { - goodvar_stack.reset(); + m_goodvar_stack.reset(); for (unsigned v = 0; v < num_vars(); ++v) { if (score(v) > 0) { // && conf_change[v] == true m_vars[v].m_in_goodvar_stack = true; - goodvar_stack.push_back(v); + m_goodvar_stack.push_back(v); } } } - void local_search::reinit_orig() { + void local_search::reinit() { for (unsigned i = 0; i < m_constraints.size(); ++i) { constraint& c = m_constraints[i]; c.m_slack = c.m_k; @@ -132,7 +139,7 @@ namespace sat { // init unsat stack m_unsat_stack.reset(); - // init solution: random now + // init solution using the bias init_cur_solution(); // init varibale information @@ -142,7 +149,7 @@ namespace sat { m_vars.back().m_conf_change = false; m_vars.back().m_slack_score = INT_MIN; m_vars.back().m_cscc = 0; - m_vars.back().m_time_stamp = max_steps + 1; + m_vars.back().m_time_stamp = m_max_steps + 1; for (unsigned i = 0; i < num_vars(); ++i) { m_vars[i].m_time_stamp = 0; m_vars[i].m_cscc = 1; @@ -158,18 +165,18 @@ namespace sat { void local_search::calculate_and_update_ob() { unsigned i, v; - objective_value = 0; + int objective_value = 0; for (i = 0; i < ob_constraint.size(); ++i) { v = ob_constraint[i].var_id; if (cur_solution(v)) objective_value += ob_constraint[i].coefficient; } - if (objective_value > best_objective_value) { - best_solution.reset(); + if (objective_value > m_best_objective_value) { + m_best_solution.reset(); for (unsigned v = 0; v < num_vars(); ++v) { - best_solution.push_back(cur_solution(v)); + m_best_solution.push_back(cur_solution(v)); } - best_objective_value = objective_value; + m_best_objective_value = objective_value; } } @@ -230,8 +237,13 @@ namespace sat { } } - local_search::local_search(solver& s) : + local_search::local_search() : m_par(0) { + } + + void local_search::import(solver& s, bool _init) { + m_vars.reset(); + m_constraints.reset(); m_vars.reserve(s.num_vars()); @@ -268,6 +280,7 @@ namespace sat { clause& c = *(*it); add_clause(c.size(), c.begin()); } + m_num_non_binary_clauses = s.m_clauses.size(); // copy cardinality clauses card_extension* ext = dynamic_cast(s.get_extension()); @@ -316,6 +329,9 @@ namespace sat { // SASSERT(ext->m_xors.empty()); } + if (_init) { + init(); + } } local_search::~local_search() { @@ -329,30 +345,32 @@ namespace sat { return check(0, 0); } -#define PROGRESS(tries, total_steps) \ +#define PROGRESS(tries, flips) \ if (tries % 10 == 0 || m_unsat_stack.empty()) { \ IF_VERBOSE(1, verbose_stream() << "(sat-local-search" \ - << " :tries " << tries \ - << " :steps " << total_steps \ + << " :flips " << flips \ << " :unsat " << m_unsat_stack.size() \ - << " :time " << timer.get_seconds() << ")\n";); \ + << " :time " << (timer.get_seconds() < 0.001 ? 0.0 : timer.get_seconds()) << ")\n";); \ } void local_search::walksat() { reinit(); timer timer; timer.start(); - unsigned step = 0, total_steps = 0, max_steps = (1 << 17), tries = 0; - PROGRESS(tries, total_steps); + unsigned step = 0, total_flips = 0, tries = 0; + PROGRESS(tries, total_flips); for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { - for (step = 0; step < max_steps && !m_unsat_stack.empty(); ++step) { + for (step = 0; step < m_max_steps && !m_unsat_stack.empty(); ++step) { pick_flip_walksat(); } - total_steps += step; - PROGRESS(tries, total_steps); + total_flips += step; + PROGRESS(tries, total_flips); + if (m_par && tries % 30 == 0) { + m_par->get_phase(*this); + reinit(); + } } - PROGRESS(tries, total_steps); } void local_search::gsat() { @@ -361,14 +379,14 @@ namespace sat { bool_var flipvar; timer timer; timer.start(); - unsigned tries, step = 0, total_steps = 0; + unsigned tries, step = 0, total_flips = 0; for (tries = 1; m_limit.inc() && !m_unsat_stack.empty(); ++tries) { reinit(); - for (step = 1; step <= max_steps; ) { + for (step = 1; step <= m_max_steps; ) { // feasible if (m_unsat_stack.empty()) { calculate_and_update_ob(); - if (best_objective_value >= best_known_value) { + if (m_best_objective_value >= m_best_known_value) { break; } } @@ -376,24 +394,21 @@ namespace sat { flip_gsat(flipvar); m_vars[flipvar].m_time_stamp = step++; } - total_steps += step; - PROGRESS(tries, total_steps); + total_flips += step; + PROGRESS(tries, total_flips); // tell the SAT solvers about the phase of variables. if (m_par && tries % 10 == 0) { m_par->get_phase(*this); } } - PROGRESS(tries, total_steps); } lbool local_search::check(unsigned sz, literal const* assumptions, parallel* p) { flet _p(m_par, p); m_model.reset(); - unsigned num_constraints = m_constraints.size(); - for (unsigned i = 0; i < sz; ++i) { - add_clause(1, assumptions + i); - } + m_assumptions.reset(); + m_assumptions.append(sz, assumptions); init(); switch (m_config.mode()) { @@ -407,7 +422,7 @@ namespace sat { // remove unit clauses from assumptions. - m_constraints.shrink(num_constraints); + m_constraints.shrink(num_constraints() - sz); TRACE("sat", display(tout);); @@ -441,7 +456,8 @@ namespace sat { } void local_search::pick_flip_walksat() { - m_good_vars.reset(); + bool_var best_var = null_bool_var; + unsigned n = 1; bool_var v = null_bool_var; unsigned num_unsat = m_unsat_stack.size(); constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; @@ -454,7 +470,7 @@ namespace sat { literal l; for (; !is_true(*cit); ++cit) { SASSERT(cit != cend); } l = *cit; - v = l.var(); + best_var = v = l.var(); bool tt = cur_solution(v); int_vector const& falsep = m_vars[v].m_watch[!tt]; int_vector::const_iterator it = falsep.begin(), end = falsep.end(); @@ -465,7 +481,6 @@ namespace sat { else if (slack == 0) best_bsb += num_unsat; } - m_good_vars.push_back(v); ++cit; for (; cit != cend; ++cit) { l = *cit; @@ -494,11 +509,14 @@ namespace sat { if (it == end) { if (bsb < best_bsb) { best_bsb = bsb; - m_good_vars.reset(); - m_good_vars.push_back(v); + best_var = v; + n = 1; } else {// if (bb == best_bb) - m_good_vars.push_back(v); + ++n; + if (m_rand() % n == 0) { + best_var = v; + } } } } @@ -506,32 +524,36 @@ namespace sat { } else { for (unsigned i = 0; i < c.size(); ++i) { - if (is_true(c[i])) - m_good_vars.push_back(c[i].var()); + if (is_true(c[i])) { + if (m_rand() % n == 0) { + best_var = c[i].var(); + } + ++n; + } } } - SASSERT(!m_good_vars.empty()); - //std::cout << m_good_vars.size() << "\n"; - flip_walksat(m_good_vars[m_rand() % m_good_vars.size()]); + flip_walksat(best_var); } void local_search::flip_walksat(bool_var flipvar) { m_vars[flipvar].m_value = !cur_solution(flipvar); bool flip_is_true = cur_solution(flipvar); - int_vector& truep = m_vars[flipvar].m_watch[flip_is_true]; - int_vector& falsep = m_vars[flipvar].m_watch[!flip_is_true]; + int_vector const& truep = m_vars[flipvar].m_watch[flip_is_true]; + int_vector const& falsep = m_vars[flipvar].m_watch[!flip_is_true]; - for (unsigned i = 0; i < truep.size(); ++i) { - unsigned ci = truep[i]; + int_vector::const_iterator it = truep.begin(), end = truep.end(); + for (; it != end; ++it) { + unsigned ci = *it; constraint& c = m_constraints[ci]; --c.m_slack; if (c.m_slack == -1) { // from 0 to -1: sat -> unsat unsat(ci); } } - for (unsigned i = 0; i < falsep.size(); ++i) { - unsigned ci = falsep[i]; + it = falsep.begin(), end = falsep.end(); + for (; it != end; ++it) { + unsigned ci = *it; constraint& c = m_constraints[ci]; ++c.m_slack; if (c.m_slack == 0) { // from -1 to 0: unsat -> sat @@ -647,12 +669,12 @@ namespace sat { /* update CCD */ // remove the vars no longer goodvar in goodvar stack - for (unsigned i = goodvar_stack.size(); i > 0;) { + for (unsigned i = m_goodvar_stack.size(); i > 0;) { --i; - v = goodvar_stack[i]; + v = m_goodvar_stack[i]; if (score(v) <= 0) { - goodvar_stack[i] = goodvar_stack.back(); - goodvar_stack.pop_back(); + m_goodvar_stack[i] = m_goodvar_stack.back(); + m_goodvar_stack.pop_back(); m_vars[v].m_in_goodvar_stack = false; } } @@ -664,7 +686,7 @@ namespace sat { v = vi.m_neighbors[i]; m_vars[v].m_conf_change = true; if (score(v) > 0 && !already_in_goodvar_stack(v)) { - goodvar_stack.push_back(v); + m_goodvar_stack.push_back(v); m_vars[v].m_in_goodvar_stack = true; } } @@ -717,11 +739,11 @@ namespace sat { // Unsat Mode: CCD > RD // CCD mode - if (!goodvar_stack.empty()) { + if (!m_goodvar_stack.empty()) { //++ccd; - best_var = goodvar_stack[0]; - for (unsigned i = 1; i < goodvar_stack.size(); ++i) { - bool_var v = goodvar_stack[i]; + best_var = m_goodvar_stack[0]; + for (unsigned i = 1; i < m_goodvar_stack.size(); ++i) { + bool_var v = m_goodvar_stack[i]; if (tie_breaker_ccd(v, best_var)) best_var = v; } @@ -742,24 +764,26 @@ namespace sat { } void local_search::set_parameters() { - + SASSERT(s_id == 0); m_rand.set_seed(m_config.seed()); //srand(m_config.seed()); s_id = m_config.strategy_id(); - best_known_value = m_config.best_known_value(); + m_best_known_value = m_config.best_known_value(); - if (s_id == 0) - max_steps = 2 * (num_vars() - 1); - else { - std::cout << "Invalid strategy id!" << std::endl; - exit(-1); + switch (m_config.mode()) { + case local_search_mode::gsat: + m_max_steps = 2 * num_vars(); + break; + case local_search_mode::wsat: + m_max_steps = std::min(static_cast(20 * num_vars()), static_cast(1 << 17)); // cut steps off at 100K + break; } TRACE("sat", tout << "seed:\t" << m_config.seed() << '\n'; tout << "strategy id:\t" << m_config.strategy_id() << '\n'; tout << "best_known_value:\t" << m_config.best_known_value() << '\n'; - tout << "max_steps:\t" << max_steps << '\n'; + tout << "max_steps:\t" << m_max_steps << '\n'; ); } @@ -808,10 +832,10 @@ namespace sat { std::cout << "3\n"; } } - if (g == goodvar_stack.size()) + if (g == m_goodvar_stack.size()) return true; else { - if (g < goodvar_stack.size()) + if (g < m_goodvar_stack.size()) std::cout << "1\n"; else std::cout << "2\n"; // delete too many diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 5f76f4934..76de2d0e7 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -134,6 +134,10 @@ namespace sat { vector m_constraints; + literal_vector m_assumptions; + + unsigned m_num_non_binary_clauses; + inline bool is_pos(literal t) const { return !t.sign(); } inline bool is_true(bool_var v) const { return cur_solution(v); } inline bool is_true(literal l) const { return cur_solution(l.var()) != l.sign(); } @@ -143,26 +147,23 @@ namespace sat { unsigned constraint_slack(unsigned ci) const { return m_constraints[ci].m_slack; } - // int_vector nb_slack; // constraint_k - ob_var(same in ob) - none_ob_true_terms_count. if < 0: some ob var might be flipped to false, result in an ob decreasing - // bool_vector has_true_ob_terms; // unsat constraint stack - int_vector m_unsat_stack; // store all the unsat constraits - int_vector m_index_in_unsat_stack; // which position is a contraint in the unsat_stack + unsigned_vector m_unsat_stack; // store all the unsat constraits + unsigned_vector m_index_in_unsat_stack; // which position is a contraint in the unsat_stack // configuration changed decreasing variables (score>0 and conf_change==true) - int_vector goodvar_stack; + bool_var_vector m_goodvar_stack; - svector m_good_vars; // candidate variables to flip on. // information about solution - int objective_value; // the objective function value corresponds to the current solution - bool_vector best_solution; // !var: the best solution so far - int best_objective_value = -1; // the objective value corresponds to the best solution so far - // for non-known instance, set as maximal - int best_known_value = INT_MAX; // best known value for this instance + int m_objective_value; // the objective function value corresponds to the current solution + bool_vector m_best_solution; // !var: the best solution so far + int m_best_objective_value = -1; // the objective value corresponds to the best solution so far + // for non-known instance, set as maximal + int m_best_known_value = INT_MAX; // best known value for this instance - unsigned max_steps = 2000000000; // < 2147483647 + unsigned m_max_steps = (1 << 30); // for tuning int s_id = 0; // strategy id @@ -228,9 +229,10 @@ namespace sat { void display(std::ostream& out, unsigned v, var_info const& vi) const; + public: - local_search(solver& s); + local_search(); reslimit& rlimit() { return m_limit; } @@ -248,6 +250,10 @@ namespace sat { unsigned num_vars() const { return m_vars.size() - 1; } // var index from 1 to num_vars + unsigned num_non_binary_clauses() const { return m_num_non_binary_clauses; } + + void import(solver& s, bool init); + void set_phase(bool_var v, lbool f); bool get_phase(bool_var v) const { return is_true(v); } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 5504cf6e0..3356763c0 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -77,8 +77,6 @@ namespace sat { literal_vector m_trail; // trail of units unsigned_vector m_trail_lim; - literal_vector m_units; // units learned during lookahead - unsigned_vector m_units_lim; vector m_binary; // literal: binary clauses unsigned_vector m_binary_trail; // trail of added binary clauses unsigned_vector m_binary_trail_lim; @@ -96,7 +94,9 @@ namespace sat { svector m_rating; // var: pre-selection rating unsigned m_bstamp_id; // unique id for binary implication. unsigned m_istamp_id; // unique id for managing double lookaheads - char_vector m_assignment; // literal: assignment + unsigned_vector m_stamp; // var: timestamp with truth value + unsigned m_level; // current level, = 2 * m_trail_lim.size() + const unsigned c_fixed_truth = UINT_MAX - 1; vector m_watches; // literal: watch structure svector m_lits; // literal: attributes. float m_weighted_new_binaries; // metric associated with current lookahead1 literal. @@ -106,6 +106,33 @@ namespace sat { search_mode m_search_mode; // mode of search statistics m_stats; + // --------------------------------------- + // truth values + + inline bool is_fixed(literal l) const { return m_stamp[l.var()] >= m_level; } + inline bool is_undef(literal l) const { return !is_fixed(l); } + inline bool is_undef(bool_var v) const { return m_stamp[v] < m_level; } + inline bool is_false(literal l) const { return is_fixed(l) && (bool)((m_stamp[l.var()] & 0x1) ^ l.sign()); } // even iff l.sign() + inline bool is_true(literal l) const { return is_fixed(l) && !(bool)((m_stamp[l.var()] & 0x1) ^ l.sign()); } + inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } + inline void set_undef(literal l) { m_stamp[l.var()] = 0; } + + // set the level within a scope of the search. + class scoped_level { + lookahead& m_parent; + unsigned m_save; + public: + scoped_level(lookahead& p, unsigned l): + m_parent(p), m_save(p.m_level) { + p.m_level = l; + } + ~scoped_level() { + m_parent.m_level = m_save; + } + }; + + // ---------------------------------------- + void add_binary(literal l1, literal l2) { SASSERT(l1 != l2); SASSERT(~l1 != l2); @@ -182,6 +209,7 @@ namespace sat { \brief main routine for adding a new binary clause dynamically. */ void try_add_binary(literal u, literal v) { + SASSERT(m_search_mode == searching); SASSERT(u.var() != v.var()); set_bstamps(~u); if (is_stamped(~v)) { @@ -292,7 +320,7 @@ namespace sat { m_candidates.reset(); float sum = 0; for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - SASSERT(l_undef == value(*it)); + SASSERT(is_undef(*it)); bool_var x = *it; if (!newbies) { // TBD filter out candidates based on prefix strings or similar method @@ -376,20 +404,13 @@ namespace sat { float sum = 0, tsum = 0; literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); for (; it != end; ++it) { - if (is_free(*it)) sum += h[it->index()]; + if (is_undef(*it)) sum += h[it->index()]; } // TBD walk ternary clauses. sum = (float)(0.1 + afactor*sum + sqfactor*tsum); return std::min(m_config.m_max_score, sum); } - bool is_free(literal l) const { - return !is_unit(l); - } - bool is_unit(literal l) const { - return false; // TBD track variables that are units - } - // ------------------------------------ // Implication graph // Compute implication ordering and strongly connected components. @@ -638,7 +659,7 @@ namespace sat { } SASSERT(2*m_lookahead.size() == offset); TRACE("sat", for (unsigned i = 0; i < m_lookahead.size(); ++i) - tout << m_lookahead[i].m_lit << " : " << m_lookahead[i].m_offset << "\n";); + tout << m_lookahead[i].m_lit << " : " << m_lookahead[i].m_offset << "\n";); } // ------------------------------------ @@ -655,8 +676,8 @@ namespace sat { clause_offset cls_off = m_cls_allocator.get_offset(&c); m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); - SASSERT(value(c[0]) == l_undef); - SASSERT(value(c[1]) == l_undef); + SASSERT(is_undef(c[0])); + SASSERT(is_undef(c[1])); } } @@ -668,6 +689,9 @@ namespace sat { } void detach_ternary(literal l1, literal l2, literal l3) { + NOT_IMPLEMENTED_YET(); + // there is a clause corresponding to a ternary watch group. + // the clause could be retired / detached. m_retired_ternary.push_back(ternary(l1, l2, l3)); erase_ternary_watch(get_wlist(~l1), l2, l3); erase_ternary_watch(get_wlist(~l2), l1, l3); @@ -680,8 +704,6 @@ namespace sat { // initialization void init_var(bool_var v) { - m_assignment.push_back(l_undef); - m_assignment.push_back(l_undef); m_binary.push_back(literal_vector()); m_binary.push_back(literal_vector()); m_watches.push_back(watch_list()); @@ -738,7 +760,6 @@ namespace sat { unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { literal l = s.m_trail[i]; - m_units.push_back(l); assign(l); } } @@ -746,15 +767,15 @@ namespace sat { // ------------------------------------ // search - void push(literal lit, search_mode mode) { + void push(literal lit, unsigned level) { m_binary_trail_lim.push_back(m_binary_trail.size()); - m_units_lim.push_back(m_units.size()); m_trail_lim.push_back(m_trail.size()); m_retired_clause_lim.push_back(m_retired_clauses.size()); m_qhead_lim.push_back(m_qhead); m_trail.push_back(lit); m_search_modes.push_back(m_search_mode); - m_search_mode = mode; + m_search_mode = searching; + scoped_level _sl(*this, level); assign(lit); propagate(); } @@ -766,6 +787,7 @@ namespace sat { m_search_mode = m_search_modes.back(); m_search_modes.pop_back(); + // not for lookahead // unretire clauses unsigned rsz = m_retired_clause_lim.back(); for (unsigned i = rsz; i < m_retired_clauses.size(); ++i) { @@ -774,6 +796,7 @@ namespace sat { m_retired_clauses.resize(rsz); m_retired_clause_lim.pop_back(); + // m_search_mode == searching // remove local binary clauses unsigned old_sz = m_binary_trail_lim.back(); m_binary_trail_lim.pop_back(); @@ -781,30 +804,31 @@ namespace sat { del_binary(m_binary_trail[i]); } + // not for lookahead. + // m_freevars only for main search // undo assignments for (unsigned i = m_trail.size(); i > m_trail_lim.size(); ) { --i; literal l = m_trail[i]; + set_undef(l); m_freevars.insert(l.var()); - m_assignment[l.index()] = l_undef; - m_assignment[(~l).index()] = l_undef; } m_trail.shrink(m_trail_lim.size()); // reset assignment. m_trail_lim.pop_back(); - // add implied binary clauses - unsigned new_unit_sz = m_units_lim.back(); - for (unsigned i = new_unit_sz; i < m_units.size(); ++i) { - try_add_binary(~m_trail.back(), m_units[i]); - } - m_units.shrink(new_unit_sz); - m_units_lim.pop_back(); - // reset propagation queue m_qhead_lim.pop_back(); m_qhead = m_qhead_lim.back(); } + void push_lookahead2(literal lit) { + + } + + void pop_lookahead2() { + + } + float mix_diff(float l, float r) const { return l + r + (1 << 10) * l * r; } clause const& get_clause(watch_list::iterator it) const { @@ -813,14 +837,13 @@ namespace sat { } bool is_nary_propagation(clause const& c, literal l) const { - bool r = c.size() > 2 && ((c[0] == l && value(c[1]) == l_false) || (c[1] == l && value(c[0]) == l_false)); - DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(value(c[j]) == l_false);); + bool r = c.size() > 2 && ((c[0] == l && is_false(c[1])) || (c[1] == l && is_false(c[0]))); + DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(is_false(c[j]));); return r; } void propagate_clauses(literal l) { - SASSERT(value(l) == l_true); - SASSERT(value(~l) == l_false); + SASSERT(is_true(l)); if (inconsistent()) return; watch_list& wlist = m_watches[l.index()]; watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); @@ -833,20 +856,24 @@ namespace sat { UNREACHABLE(); // we avoid adding ternary clauses for now. literal l1 = it->get_literal1(); literal l2 = it->get_literal2(); - lbool val1 = value(l1); - lbool val2 = value(l2); - if (val1 == l_false && val2 == l_undef) { - m_stats.m_propagations++; - assign(l2); + if (is_fixed(l1)) { + if (is_false(l1)) { + if (is_undef(l2)) { + m_stats.m_propagations++; + assign(l2); + } + else if (is_false(l2)) { + set_conflict(); + } + } } - else if (val1 == l_undef && val2 == l_false) { - m_stats.m_propagations++; - assign(l1); + else if (is_fixed(l2)) { + if (is_false(l2)) { + m_stats.m_propagations++; + assign(l1); + } } - else if (val1 == l_false && val2 == l_false) { - set_conflict(); - } - else if (val1 == l_undef && val2 == l_undef) { + else { switch (m_search_mode) { case searching: detach_ternary(l, l1, l2); @@ -866,10 +893,10 @@ namespace sat { case watched::CLAUSE: { clause_offset cls_off = it->get_clause_offset(); clause & c = *(s.m_cls_allocator.get_clause(cls_off)); - TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";); + TRACE("sat", tout << "propagating " << c << "\n";); if (c[0] == ~l) std::swap(c[0], c[1]); - if (value(c[0]) == l_true) { + if (is_true(c[0])) { it2->set_clause(c[0], cls_off); it2++; break; @@ -878,7 +905,7 @@ namespace sat { literal * l_end = c.end(); bool found = false; for (; l_it != l_end && !found; ++l_it) { - if (value(*l_it) != l_false) { + if (!is_false(*l_it)) { found = true; c[1] = *l_it; *l_it = ~l; @@ -888,10 +915,10 @@ namespace sat { if (found) { found = false; for (; l_it != l_end && !found; ++l_it) { - found = value(*l_it) != l_false; + found = !is_false(*l_it); } // normal clause was converted to a binary clause. - if (!found && value(c[1]) == l_undef && value(c[0]) == l_undef) { + if (!found && is_undef(c[1]) && is_undef(c[0])) { switch (m_search_mode) { case searching: detach_clause(c); @@ -906,11 +933,11 @@ namespace sat { } break; } - if (value(c[0]) == l_false) { + if (is_false(c[0])) { set_conflict(); } else { - SASSERT(value(c[0]) == l_undef); + SASSERT(is_undef(c[0])); *it2 = *it; it2++; m_stats.m_propagations++; @@ -929,14 +956,7 @@ namespace sat { for (; it != end; ++it, ++it2) { *it2 = *it; } - wlist.set_end(it2); - - - // - // TBD: count binary clauses created by propagation. - // They used to be in the watch list of l.index(), - // both new literals in watch list should be unassigned. - // + wlist.set_end(it2); } void propagate_binary(literal l) { @@ -958,78 +978,100 @@ namespace sat { } literal choose() { - literal l; - while (!choose1(l)) {}; + literal l = null_literal; + while (l == null_literal) { + pre_select(); + if (m_lookahead.empty()) { + break; + } + compute_wnb(); + if (inconsistent()) { + break; + } + l = select_literal(); + } return l; } - // TBD: - // Handle scope properly for nested implications. - // Suppose u -> v, and u -> w and we process v first, then the - // consequences of v should remain when processing u. - // March and sat11.w solve this by introducing timestamps on truth values. - // regular push/pop doesn't really work here: we basically need a traversal of the - // lookahead tree and push/pop according to that (or adapt timestamps) - // - bool choose1(literal& l) { - pre_select(); - l = null_literal; - if (m_lookahead.empty()) { - return true; - } - float h = 0; - unsigned count = 1; + void compute_wnb() { + init_wnb(); for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; - if (value(lit) != l_undef) { + if (!is_undef(lit)) { continue; } - SASSERT(value(lit) == l_undef); - SASSERT(!inconsistent()); - reset_wnb(lit); - push(lit, lookahead1); - do_double(lit); - if (inconsistent()) { - pop(); + push_lookahead1(lit, 2 + m_lookahead[i].m_offset); + bool unsat = inconsistent(); + // TBD do_double(lit); + pop_lookahead1(); + update_wnb(lit); + if (unsat) { + reset_wnb(); assign(~lit); propagate(); - continue; + init_wnb(); } - update_wnb(lit); - float diff1 = m_weighted_new_binaries; - pop(); - - reset_wnb(~lit); - push(~lit, lookahead1); - do_double(~lit); - if (inconsistent()) { - pop(); - assign(lit); - propagate(); - continue; - } - update_wnb(~lit); - float diff2 = m_weighted_new_binaries; - pop(); + } + reset_wnb(); + } + void init_wnb() { + m_qhead_lim.push_back(m_qhead); + m_trail_lim.push_back(m_trail.size()); + } + + void reset_wnb() { + m_qhead = m_qhead_lim.back(); + unsigned old_sz = m_trail_lim.back(); + for (unsigned i = old_sz; i < m_trail.size(); ++i) { + set_undef(m_trail[i]); + } + m_trail.shrink(old_sz); + m_trail_lim.pop_back(); + m_qhead_lim.pop_back(); + } + + literal select_literal() { + literal l = null_literal; + float h = 0; + unsigned count = 1; + for (unsigned i = 0; i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + if (lit.sign() || !is_undef(lit)) { + continue; + } + float diff1 = get_wnb(lit), diff2 = get_wnb(~lit); float mixd = mix_diff(diff1, diff2); + if (mixd == h) ++count; if (mixd > h || (mixd == h && s.m_rand(count) == 0)) { - CTRACE("sat", l != null_literal, tout << lit << " diff1: " << diff1 << " diff2: " << diff2 << "\n";); - if (mixd > h) count = 1; else ++count; + CTRACE("sat", l != null_literal, tout << lit << " " << mixd << "\n";); + if (mixd > h) count = 1; h = mixd; l = diff1 < diff2 ? lit : ~lit; } } - return l != null_literal || inconsistent(); + return l; + } + + void push_lookahead1(literal lit, unsigned level) { + m_search_modes.push_back(m_search_mode); + m_search_mode = lookahead1; + scoped_level _sl(*this, level); + assign(lit); + propagate(); + } + + void pop_lookahead1() { + SASSERT(!inconsistent()); + m_search_mode = m_search_modes.back(); + m_search_modes.pop_back(); } void set_wnb(literal l, float f) { m_lits[l.index()].m_wnb = f; } void inc_wnb(literal l, float f) { m_lits[l.index()].m_wnb += f; } float get_wnb(literal l) const { return m_lits[l.index()].m_wnb; } - bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; } - void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } void reset_wnb(literal l) { m_weighted_new_binaries = 0; @@ -1048,24 +1090,27 @@ namespace sat { } } + bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; } + void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } + void double_look() { bool unsat; for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; - if (value(lit) != l_undef) continue; + if (!is_undef(lit)) continue; - push(lit, lookahead2); + push_lookahead2(lit); unsat = inconsistent(); - pop(); + pop_lookahead2(); if (unsat) { TRACE("sat", tout << "unit: " << ~lit << "\n";); assign(~lit); continue; } - push(~lit, lookahead2); + push_lookahead2(~lit); unsat = inconsistent(); - pop(); + pop_lookahead2(); if (unsat) { TRACE("sat", tout << "unit: " << lit << "\n";); assign(lit); @@ -1073,31 +1118,25 @@ namespace sat { } } - bool is_fixed(literal l) const { return value(l) != l_undef; } - bool is_contrary(literal l) const { return value(l) == l_false; } - bool is_true(literal l) const { return value(l) == l_true; } + void set_conflict() { m_inconsistent = true; } - lbool value(literal l) const { return static_cast(m_assignment[l.index()]); } - lbool value(bool_var v) const { return value(literal(v, false)); } + bool inconsistent() { return m_inconsistent; } + unsigned scope_lvl() const { return m_trail_lim.size(); } void assign(literal l) { - switch (value(l)) { - case l_true: - break; - case l_false: - set_conflict(); - break; - default: - m_assignment[l.index()] = l.sign() ? l_false : l_true; - m_assignment[(~l).index()] = l.sign() ? l_false : l_true; + if (is_undef(l)) { + set_true(l); m_trail.push_back(l); - m_freevars.remove(l.var()); - break; + if (m_search_mode == searching) { + m_freevars.remove(l.var()); + } + } + else if (is_false(l)) { + set_conflict(); } } - bool inconsistent() { return m_inconsistent; } void do_double(literal l) { if (!inconsistent() && scope_lvl() > 0 && dl_enabled(l)) { @@ -1115,7 +1154,8 @@ namespace sat { bool backtrack(literal_vector& trail) { if (trail.empty()) return false; pop(); - assign(~trail.back()); + assign(~trail.back()); + propagate(); trail.pop_back(); return true; } @@ -1124,6 +1164,7 @@ namespace sat { literal_vector trail; m_search_mode = searching; while (true) { + TRACE("sat", display(tout);); inc_istamp(); s.checkpoint(); literal l = choose(); @@ -1135,19 +1176,55 @@ namespace sat { return l_true; } TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); - push(l, searching); + push(l, c_fixed_truth); trail.push_back(l); } } + std::ostream& display_binary(std::ostream& out) const { + for (unsigned i = 0; i < m_binary.size(); ++i) { + literal_vector const& lits = m_binary[i]; + if (!lits.empty()) { + out << to_literal(i) << " -> " << lits << "\n"; + } + } + return out; + } + + std::ostream& display_clauses(std::ostream& out) const { + for (unsigned i = 0; i < m_clauses.size(); ++i) { + out << *m_clauses[i] << "\n"; + } + return out; + } + + std::ostream& display_values(std::ostream& out) const { + for (unsigned i = 0; i < m_trail.size(); ++i) { + literal l = m_trail[i]; + out << l << " " << m_stamp[l.var()] << "\n"; + } + return out; + } + + public: - lookahead(solver& s) : s(s) { + lookahead(solver& s) : + s(s), + m_level(0) { + scoped_level _sl(*this, c_fixed_truth); init(); } lbool check() { return search(); } + + std::ostream& display(std::ostream& out) const { + display_values(out); + display_binary(out); + display_clauses(out); + return out; + } }; } diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 4eb247fc0..6652bfc3e 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -139,9 +139,6 @@ namespace sat { } } limit = m_units.size(); - - _get_phase(s); - _set_phase(s); } } @@ -228,6 +225,12 @@ namespace sat { break; } } + if (90 * m_num_clauses > 100 * s.m_clauses.size() && !m_solver_copy) { + // time to update local search with new clauses. + IF_VERBOSE(1, verbose_stream() << "(sat-parallel refresh local search " << m_num_clauses << " -> " << s.m_clauses.size() << ")\n";); + m_solver_copy = alloc(solver, s.m_params, s.rlimit()); + m_solver_copy->copy(s); + } } } @@ -261,10 +264,16 @@ namespace sat { void parallel::get_phase(local_search& s) { #pragma omp critical (par_solver) { + if (m_solver_copy) { + s.import(*m_solver_copy.get(), true); + m_solver_copy = 0; + } for (unsigned i = 0; i < m_phase.size(); ++i) { s.set_phase(i, m_phase[i]); + m_phase[i] = l_undef; } m_phase.reserve(s.num_vars(), l_undef); + m_num_clauses = s.num_non_binary_clauses(); } } @@ -275,6 +284,7 @@ namespace sat { for (unsigned i = 0; i < s.num_vars(); ++i) { m_phase[i] = s.get_phase(i) ? l_true : l_false; } + m_num_clauses = s.num_non_binary_clauses(); } } diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index 4d8e4a82d..b93384bd6 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -60,7 +60,11 @@ namespace sat { index_set m_unit_set; literal_vector m_lits; vector_pool m_pool; - svector m_phase; + + // for exchange with local search: + svector m_phase; + unsigned m_num_clauses; + scoped_ptr m_solver_copy; scoped_limits m_scoped_rlimit; vector m_limits; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 01657951d..e6508ea51 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -82,15 +82,15 @@ namespace sat { void solver::copy(solver const & src) { pop_to_base_level(); - SASSERT(m_mc.empty() && src.m_mc.empty()); - SASSERT(at_search_lvl()); // create new vars if (num_vars() < src.num_vars()) { for (bool_var v = num_vars(); v < src.num_vars(); v++) { - SASSERT(!src.was_eliminated(v)); bool ext = src.m_external[v] != 0; bool dvar = src.m_decision[v] != 0; VERIFY(v == mk_var(ext, dvar)); + if (src.was_eliminated(v)) { + m_eliminated[v] = true; + } } } // @@ -854,19 +854,14 @@ namespace sat { ERROR_EX }; - local_search& solver::init_local_search() { - if (!m_local_search) { - m_local_search = alloc(local_search, *this); - } - return *m_local_search.get(); - } - lbool solver::check_par(unsigned num_lits, literal const* lits) { bool use_local_search = m_config.m_local_search; + scoped_ptr ls; if (use_local_search) { - m_local_search = alloc(local_search, *this); - m_local_search->config().set_seed(m_config.m_random_seed); + ls = alloc(local_search); + ls->config().set_seed(m_config.m_random_seed); + ls->import(*this, false); } int num_threads = static_cast(m_config.m_num_threads) + (use_local_search ? 1 : 0); int num_extra_solvers = num_threads - 1 - (use_local_search ? 1 : 0); @@ -890,7 +885,7 @@ namespace sat { r = par.get_solver(i).check(num_lits, lits); } else if (IS_LOCAL_SEARCH(i)) { - r = m_local_search->check(num_lits, lits, &par); + r = ls->check(num_lits, lits, &par); } else { r = check(num_lits, lits); @@ -905,8 +900,8 @@ namespace sat { } } if (first) { - if (m_local_search) { - m_local_search->rlimit().cancel(); + if (ls) { + ls->rlimit().cancel(); } for (int j = 0; j < num_extra_solvers; ++j) { if (i != j) { @@ -942,13 +937,13 @@ namespace sat { m_core.append(par.get_solver(finished_id).get_core()); } if (result == l_true && finished_id != -1 && IS_LOCAL_SEARCH(finished_id)) { - set_model(m_local_search->get_model()); + set_model(ls->get_model()); } if (!canceled) { rlimit().reset_cancel(); } set_par(0, 0); - m_local_search = 0; + ls = 0; if (finished_id == -1) { switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 5ca668ff8..c35a0296c 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -90,7 +90,6 @@ namespace sat { probing m_probing; mus m_mus; // MUS for minimal core extraction drat m_drat; // DRAT for generating proofs - scoped_ptr m_local_search; bool m_inconsistent; bool m_searching; // A conflict is usually a single justification. That is, a justification From cd4a2701db89b5cdc354afb8efaf4af45ab6679d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Mar 2017 10:48:58 -0800 Subject: [PATCH 0085/1283] adding ability to ahve multiple local search threads Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 4 +--- src/sat/sat_config.h | 3 +-- src/sat/sat_params.pyg | 3 +-- src/sat/sat_solver.cpp | 48 +++++++++++++++++++++++------------------- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 5102511e8..4b019c2b7 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -36,8 +36,7 @@ namespace sat { m_glue_psm("glue_psm"), m_psm_glue("psm_glue") { m_num_threads = 1; - m_local_search = false; - m_local_search_parameter1 = 0; + m_local_search = 0; updt_params(p); } @@ -82,7 +81,6 @@ namespace sat { m_max_conflicts = p.max_conflicts(); m_num_threads = p.threads(); m_local_search = p.local_search(); - m_local_search_parameter1 = p.local_search_int(); // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index dd32fc28d..313b4ec49 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -58,8 +58,7 @@ namespace sat { unsigned m_burst_search; unsigned m_max_conflicts; unsigned m_num_threads; - bool m_local_search; - unsigned m_local_search_parameter1; + unsigned m_local_search; unsigned m_simplify_mult1; double m_simplify_mult2; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index d95e5fc30..045fd803a 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -28,6 +28,5 @@ def_module_params('sat', ('drat.check', BOOL, False, 'build up internal proof and check'), ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('xor.solver', BOOL, False, 'use xor solver'), - ('local_search', BOOL, False, 'add local search co-processor to find satisfiable solution'), - ('local_search.int', UINT, 0, 'arbitrary integer'), + ('local_search', UINT, 0, 'number of local search threads to find satisfiable solution'), )) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e6508ea51..539699382 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -21,6 +21,7 @@ Revision History: #include"luby.h" #include"trace.h" #include"max_cliques.h" +#include"scoped_ptr_vector.h" // define to update glue during propagation #define UPDATE_GLUE @@ -782,7 +783,7 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); - if ((m_config.m_num_threads > 1 || m_config.m_local_search) && !m_par) { + if ((m_config.m_num_threads > 1 || m_config.m_local_search > 0) && !m_par) { return check_par(num_lits, lits); } flet _searching(m_searching, true); @@ -856,17 +857,20 @@ namespace sat { lbool solver::check_par(unsigned num_lits, literal const* lits) { - bool use_local_search = m_config.m_local_search; - scoped_ptr ls; - if (use_local_search) { - ls = alloc(local_search); - ls->config().set_seed(m_config.m_random_seed); - ls->import(*this, false); + scoped_ptr_vector ls; + int num_threads = static_cast(m_config.m_num_threads + m_config.m_local_search); + int num_extra_solvers = m_config.m_num_threads - 1; + int num_local_search = static_cast(m_config.m_local_search); + for (int i = 0; i < num_local_search; ++i) { + local_search* l = alloc(local_search); + l->config().set_seed(m_config.m_random_seed); + l->import(*this, false); + ls.push_back(l); } - int num_threads = static_cast(m_config.m_num_threads) + (use_local_search ? 1 : 0); - int num_extra_solvers = num_threads - 1 - (use_local_search ? 1 : 0); -#define IS_LOCAL_SEARCH(i) i == num_extra_solvers && use_local_search +#define IS_AUX_SOLVER(i) (0 <= i && i < num_extra_solvers) +#define IS_LOCAL_SEARCH(i) (num_extra_solvers <= i && i + 1 < num_threads) +#define IS_MAIN_SOLVER(i) (i + 1 == num_threads) sat::parallel par(*this); par.reserve(num_threads, 1 << 12); @@ -881,11 +885,11 @@ namespace sat { for (int i = 0; i < num_threads; ++i) { try { lbool r = l_undef; - if (i < num_extra_solvers) { + if (IS_AUX_SOLVER(i)) { r = par.get_solver(i).check(num_lits, lits); } else if (IS_LOCAL_SEARCH(i)) { - r = ls->check(num_lits, lits, &par); + r = ls[i-num_extra_solvers]->check(num_lits, lits, &par); } else { r = check(num_lits, lits); @@ -900,15 +904,15 @@ namespace sat { } } if (first) { - if (ls) { - ls->rlimit().cancel(); + for (unsigned j = 0; j < ls.size(); ++j) { + ls[j]->rlimit().cancel(); } for (int j = 0; j < num_extra_solvers; ++j) { if (i != j) { par.cancel_solver(j); } } - if ((0 <= i && i < num_extra_solvers) || IS_LOCAL_SEARCH(i)) { + if (!IS_MAIN_SOLVER(i)) { canceled = !rlimit().inc(); if (!canceled) { rlimit().cancel(); @@ -926,24 +930,24 @@ namespace sat { } } - if (finished_id != -1 && finished_id < num_extra_solvers) { + if (IS_AUX_SOLVER(finished_id)) { m_stats = par.get_solver(finished_id).m_stats; } - if (result == l_true && finished_id != -1 && finished_id < num_extra_solvers) { + if (result == l_true && IS_AUX_SOLVER(finished_id)) { set_model(par.get_solver(finished_id).get_model()); } - else if (result == l_false && finished_id != -1 && finished_id < num_extra_solvers) { + else if (result == l_false && IS_AUX_SOLVER(finished_id)) { m_core.reset(); m_core.append(par.get_solver(finished_id).get_core()); } - if (result == l_true && finished_id != -1 && IS_LOCAL_SEARCH(finished_id)) { - set_model(ls->get_model()); + if (result == l_true && IS_LOCAL_SEARCH(finished_id)) { + set_model(ls[finished_id - num_extra_solvers]->get_model()); } if (!canceled) { rlimit().reset_cancel(); } - set_par(0, 0); - ls = 0; + set_par(0, 0); + ls.reset(); if (finished_id == -1) { switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); From ac59e7b6d3d5c6723747704755f1a25acc6e832c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Mar 2017 11:48:23 -0800 Subject: [PATCH 0086/1283] enable multiple local search threads Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.h | 1 + src/sat/sat_lookahead.h | 9 +++++---- src/sat/sat_parallel.cpp | 12 +++++++++--- src/sat/sat_solver.cpp | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 76de2d0e7..8cb5ff480 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -259,6 +259,7 @@ namespace sat { bool get_phase(bool_var v) const { return is_true(v); } model& get_model() { return m_model; } + }; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 3356763c0..77e562384 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -710,11 +710,11 @@ namespace sat { m_watches.push_back(watch_list()); m_bstamp.push_back(0); m_bstamp.push_back(0); + m_dfs.push_back(dfs_info()); + m_dfs.push_back(dfs_info()); + m_lits.push_back(lit_info()); + m_lits.push_back(lit_info()); m_rating.push_back(0); - m_dfs.push_back(dfs_info()); - m_dfs.push_back(dfs_info()); - m_lits.push_back(lit_info()); - m_lits.push_back(lit_info()); m_prefix.push_back(prefix()); m_freevars.insert(v); } @@ -1125,6 +1125,7 @@ namespace sat { unsigned scope_lvl() const { return m_trail_lim.size(); } void assign(literal l) { + SASSERT(m_level > 0); if (is_undef(l)) { set_true(l); m_trail.push_back(l); diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 6652bfc3e..67d446a29 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -91,7 +91,7 @@ namespace sat { return false; } - parallel::parallel(solver& s): m_scoped_rlimit(s.rlimit()) {} + parallel::parallel(solver& s): m_scoped_rlimit(s.rlimit()), m_num_clauses(0) {} parallel::~parallel() { for (unsigned i = 0; i < m_solvers.size(); ++i) { @@ -227,9 +227,11 @@ namespace sat { } if (90 * m_num_clauses > 100 * s.m_clauses.size() && !m_solver_copy) { // time to update local search with new clauses. + // there could be multiple local search engines runing at the same time. IF_VERBOSE(1, verbose_stream() << "(sat-parallel refresh local search " << m_num_clauses << " -> " << s.m_clauses.size() << ")\n";); m_solver_copy = alloc(solver, s.m_params, s.rlimit()); m_solver_copy->copy(s); + m_num_clauses = s.m_clauses.size(); } } } @@ -264,16 +266,20 @@ namespace sat { void parallel::get_phase(local_search& s) { #pragma omp critical (par_solver) { - if (m_solver_copy) { + if (m_solver_copy && s.num_non_binary_clauses() > m_solver_copy->m_clauses.size()) { s.import(*m_solver_copy.get(), true); + m_num_clauses = s.num_non_binary_clauses(); + SASSERT(s.num_non_binary_clauses() == m_solver_copy->m_clauses.size()); m_solver_copy = 0; } + if (m_num_clauses < s.num_non_binary_clauses()) { + m_num_clauses = s.num_non_binary_clauses(); + } for (unsigned i = 0; i < m_phase.size(); ++i) { s.set_phase(i, m_phase[i]); m_phase[i] = l_undef; } m_phase.reserve(s.num_vars(), l_undef); - m_num_clauses = s.num_non_binary_clauses(); } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 539699382..bddf551df 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -863,7 +863,7 @@ namespace sat { int num_local_search = static_cast(m_config.m_local_search); for (int i = 0; i < num_local_search; ++i) { local_search* l = alloc(local_search); - l->config().set_seed(m_config.m_random_seed); + l->config().set_seed(m_config.m_random_seed + i); l->import(*this, false); ls.push_back(l); } From 5f5819f029482eeace9043998c579578f79bf1bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Mar 2017 22:44:41 +0100 Subject: [PATCH 0087/1283] fix xor handling, and defaults for cardinality Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 8 ++-- src/opt/opt_context.cpp | 11 ++++-- src/sat/card_extension.cpp | 57 ++++++++++++++++++++--------- src/sat/card_extension.h | 10 +++-- src/sat/sat_local_search.cpp | 42 +++++++++++---------- src/sat/sat_lookahead.h | 39 ++++++++++++++++++-- src/tactic/arith/card2bv_tactic.cpp | 1 + src/util/memory_manager.cpp | 1 + 8 files changed, 119 insertions(+), 50 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 1afb56c1a..f546ef70b 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -419,8 +419,8 @@ struct pb2bv_rewriter::imp { bv(m), m_trail(m), m_args(m), - m_keep_cardinality_constraints(true), - m_min_arity(8) + m_keep_cardinality_constraints(false), + m_min_arity(2) {} bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { @@ -618,12 +618,12 @@ struct pb2bv_rewriter::imp { m_fresh(m), m_num_translated(0), m_rw(*this, m) { - m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", true)); + m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", false)); } void updt_params(params_ref const & p) { m_params.append(p); - m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", true)); + m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", false)); } 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"); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ebe56381a..da02eba6b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -270,7 +270,6 @@ namespace opt { #endif solver& s = get_solver(); s.assert_expr(m_hard_constraints); - display_benchmark(); IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";); lbool is_sat = s.check_sat(0,0); TRACE("opt", tout << "initial search result: " << is_sat << "\n";); @@ -1002,8 +1001,9 @@ namespace opt { TRACE("opt", tout << "Term does not evaluate " << term << "\n";); return false; } - if (!m_arith.is_numeral(val, r)) { - TRACE("opt", tout << "model does not evaluate objective to a value\n";); + unsigned bv_size; + if (!m_arith.is_numeral(val, r) && !m_bv.is_numeral(val, r, bv_size)) { + TRACE("opt", tout << "model does not evaluate objective to a value, but to " << val << "\n";); return false; } if (r != v) { @@ -1199,6 +1199,9 @@ namespace opt { } void context::display_benchmark() { + display(verbose_stream()); + return; + if (opt_params(m_params).dump_benchmarks() && sat_enabled() && m_objectives.size() == 1 && @@ -1208,6 +1211,8 @@ namespace opt { unsigned sz = o.m_terms.size(); inc_sat_display(verbose_stream(), get_solver(), sz, o.m_terms.c_ptr(), o.m_weights.c_ptr()); } + + } void context::display(std::ostream& out) { diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 1100428c5..cb05e5d61 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -146,7 +146,7 @@ namespace sat { set_conflict(c, lit); break; default: - m_stats.m_num_propagations++; + m_stats.m_num_card_propagations++; m_num_propagations_since_pop++; //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); SASSERT(validate_unit_propagation(c)); @@ -183,8 +183,10 @@ namespace sat { } void card_extension::set_conflict(card& c, literal lit) { + m_stats.m_num_card_conflicts++; TRACE("sat", display(tout, c, true); ); SASSERT(validate_conflict(c)); + SASSERT(value(lit) == l_false); s().set_conflict(justification::mk_ext_justification(c.index()), ~lit); SASSERT(s().inconsistent()); } @@ -223,6 +225,7 @@ namespace sat { if (x.lit() != null_literal && x.lit().sign() == is_true) { x.negate(); } + TRACE("sat", display(tout, x, true);); unsigned sz = x.size(); unsigned j = 0; for (unsigned i = 0; i < sz && j < 2; ++i) { @@ -234,7 +237,16 @@ namespace sat { switch (j) { case 0: if (!parity(x, 0)) { - set_conflict(x, x[0]); + literal_set litset; + for (unsigned i = 0; i < sz; ++i) { + litset.insert(x[i]); + } + literal_vector const& lits = s().m_trail; + unsigned idx = lits.size()-1; + while (!litset.contains(lits[idx])) { + --idx; + } + set_conflict(x, lits[idx]); } break; case 1: @@ -249,14 +261,16 @@ namespace sat { } void card_extension::assign(xor& x, literal lit) { + SASSERT(!s().inconsistent()); switch (value(lit)) { case l_true: break; case l_false: set_conflict(x, lit); + SASSERT(s().inconsistent()); break; default: - m_stats.m_num_propagations++; + m_stats.m_num_xor_propagations++; m_num_propagations_since_pop++; if (s().m_config.m_drat) { svector ps; @@ -269,6 +283,7 @@ namespace sat { ps.push_back(drat::premise(drat::s_ext(), x.lit())); s().m_drat.add(lits, ps); } + TRACE("sat", display(tout << lit << " ", x, true);); s().assign(lit, justification::mk_ext_justification(x.index())); break; } @@ -290,8 +305,11 @@ namespace sat { void card_extension::set_conflict(xor& x, literal lit) { + m_stats.m_num_xor_conflicts++; TRACE("sat", display(tout, x, true); ); + if (value(lit) == l_true) lit.neg(); SASSERT(validate_conflict(x)); + TRACE("sat", display(tout << lit << " ", x, true);); s().set_conflict(justification::mk_ext_justification(x.index()), ~lit); SASSERT(s().inconsistent()); } @@ -332,7 +350,7 @@ namespace sat { assign(x, p ? ~x[0] : x[0]); } else if (!parity(x, 0)) { - set_conflict(x, x[0]); + set_conflict(x, ~x[1]); } return s().inconsistent() ? l_false : l_true; } @@ -410,6 +428,7 @@ namespace sat { m_bound = 0; literal consequent = s().m_not_l; justification js = s().m_conflict; + TRACE("sat", tout << consequent << " " << js << "\n";); m_conflict_lvl = s().get_max_lvl(consequent, js); if (consequent != null_literal) { consequent.neg(); @@ -418,7 +437,6 @@ namespace sat { literal_vector const& lits = s().m_trail; unsigned idx = lits.size()-1; int offset = 1; - DEBUG_CODE(active2pb(m_A);); unsigned init_marks = m_num_marks; @@ -490,17 +508,18 @@ namespace sat { card& c = index2card(index); m_bound += offset * c.k(); process_card(c, offset); + ++m_stats.m_num_card_resolves; } else { // jus.push_back(js); m_lemma.reset(); m_bound += offset; inc_coeff(consequent, offset); - get_xor_antecedents(idx, m_lemma); - // get_antecedents(consequent, index, m_lemma); + get_xor_antecedents(consequent, idx, js, m_lemma); for (unsigned i = 0; i < m_lemma.size(); ++i) { process_antecedent(~m_lemma[i], offset); } + ++m_stats.m_num_xor_resolves; } break; } @@ -666,7 +685,6 @@ namespace sat { CTRACE("sat", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); s().mark(m_lemma[i].var()); } - m_stats.m_num_conflicts++; return true; @@ -797,19 +815,17 @@ namespace sat { The idea is to collect premises based on xor resolvents. Variables that are repeated an even number of times cancel out. */ - void card_extension::get_xor_antecedents(unsigned index, literal_vector& r) { - literal_vector const& lits = s().m_trail; - literal l = lits[index + 1]; + void card_extension::get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r) { unsigned level = lvl(l); bool_var v = l.var(); - SASSERT(s().m_justification[v].get_kind() == justification::EXT_JUSTIFICATION); - SASSERT(!is_card_index(s().m_justification[v].get_ext_justification_idx())); + SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); + SASSERT(!is_card_index(js.get_ext_justification_idx())); + TRACE("sat", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); unsigned num_marks = 0; unsigned count = 0; while (true) { ++count; - justification js = s().m_justification[v]; if (js.get_kind() == justification::EXT_JUSTIFICATION) { unsigned idx = js.get_ext_justification_idx(); if (is_card_index(idx)) { @@ -838,7 +854,7 @@ namespace sat { r.push_back(l); } while (num_marks > 0) { - l = lits[index]; + l = s().m_trail[index]; v = l.var(); unsigned n = get_parity(v); if (n > 0) { @@ -859,6 +875,7 @@ namespace sat { } --index; --num_marks; + js = s().m_justification[v]; } // now walk the defined literals @@ -874,6 +891,7 @@ namespace sat { reset_parity(lit.var()); } m_parity_trail.reset(); + TRACE("sat", tout << r << "\n";); } void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { @@ -1274,8 +1292,12 @@ namespace sat { } void card_extension::collect_statistics(statistics& st) const { - st.update("cardinality propagations", m_stats.m_num_propagations); - st.update("cardinality conflicts", m_stats.m_num_conflicts); + st.update("cardinality propagations", m_stats.m_num_card_propagations); + st.update("cardinality conflicts", m_stats.m_num_card_conflicts); + st.update("cardinality resolves", m_stats.m_num_card_resolves); + st.update("xor propagations", m_stats.m_num_xor_propagations); + st.update("xor conflicts", m_stats.m_num_xor_conflicts); + st.update("xor resolves", m_stats.m_num_xor_resolves); } bool card_extension::validate_conflict(card& c) { @@ -1310,6 +1332,7 @@ namespace sat { val += coeff; } } + CTRACE("sat", val >= 0, active2pb(m_A); display(tout, m_A);); return val < 0; } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 1c4aac29b..0d649a97c 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -30,8 +30,12 @@ namespace sat { friend class local_search; struct stats { - unsigned m_num_propagations; - unsigned m_num_conflicts; + unsigned m_num_card_propagations; + unsigned m_num_card_conflicts; + unsigned m_num_card_resolves; + unsigned m_num_xor_propagations; + unsigned m_num_xor_conflicts; + unsigned m_num_xor_resolves; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -172,7 +176,7 @@ namespace sat { bool is_card_index(unsigned idx) const { return 0 == (idx & 0x1); } card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 1]; } xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 1]; } - void get_xor_antecedents(unsigned index, literal_vector& r); + void get_xor_antecedents(literal l, unsigned inddex, justification js, literal_vector& r); template diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 3dc37471e..a93ad12c1 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -42,19 +42,21 @@ namespace sat { m_index_in_unsat_stack.resize(num_constraints(), 0); coefficient_in_ob_constraint.resize(num_vars() + 1, 0); - uint_set is_neighbor; - for (bool_var v = 0; v < num_vars(); ++v) { - is_neighbor.reset(); - bool pol = true; - var_info& vi = m_vars[v]; - for (unsigned k = 0; k < 2; pol = !pol, k++) { - for (unsigned i = 0; i < m_vars[v].m_watch[pol].size(); ++i) { - constraint const& c = m_constraints[m_vars[v].m_watch[pol][i]]; - for (unsigned j = 0; j < c.size(); ++j) { - bool_var w = c[j].var(); - if (w == v || is_neighbor.contains(w)) continue; - is_neighbor.insert(w); - vi.m_neighbors.push_back(w); + if (m_config.mode() == local_search_mode::gsat) { + uint_set is_neighbor; + for (bool_var v = 0; v < num_vars(); ++v) { + is_neighbor.reset(); + bool pol = true; + var_info& vi = m_vars[v]; + for (unsigned k = 0; k < 2; pol = !pol, k++) { + for (unsigned i = 0; i < m_vars[v].m_watch[pol].size(); ++i) { + constraint const& c = m_constraints[m_vars[v].m_watch[pol][i]]; + for (unsigned j = 0; j < c.size(); ++j) { + bool_var w = c[j].var(); + if (w == v || is_neighbor.contains(w)) continue; + is_neighbor.insert(w); + vi.m_neighbors.push_back(w); + } } } } @@ -69,7 +71,7 @@ namespace sat { void local_search::init_cur_solution() { for (unsigned v = 0; v < num_vars(); ++v) { // use bias half the time. - if (m_rand() % 100 < 50) { + if (m_rand() % 100 < 10) { m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); } } @@ -345,12 +347,12 @@ namespace sat { return check(0, 0); } -#define PROGRESS(tries, flips) \ - if (tries % 10 == 0 || m_unsat_stack.empty()) { \ - IF_VERBOSE(1, verbose_stream() << "(sat-local-search" \ - << " :flips " << flips \ - << " :unsat " << m_unsat_stack.size() \ - << " :time " << (timer.get_seconds() < 0.001 ? 0.0 : timer.get_seconds()) << ")\n";); \ +#define PROGRESS(tries, flips) \ + if (tries % 10 == 0 || m_unsat_stack.empty()) { \ + IF_VERBOSE(1, verbose_stream() << "(sat-local-search" \ + << " :flips " << flips \ + << " :unsat " << m_unsat_stack.size() \ + << " :time " << (timer.get_seconds() < 0.001 ? 0.0 : timer.get_seconds()) << ")\n";); \ } void local_search::walksat() { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 77e562384..420256e59 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -100,7 +100,8 @@ namespace sat { vector m_watches; // literal: watch structure svector m_lits; // literal: attributes. float m_weighted_new_binaries; // metric associated with current lookahead1 literal. - svector m_prefix; // var: prefix where variable participates in propagation + unsigned m_prefix; // where we are in search tree + svector m_vprefix; // var: prefix where variable participates in propagation indexed_uint_set m_freevars; svector m_search_modes; // stack of modes search_mode m_search_mode; // mode of search @@ -131,6 +132,34 @@ namespace sat { } }; + // ---------------------------------------- + // prefix updates. I use low order bits and + // skip bit 0 in a bid to reduce details. + + void flip_prefix() { + if (m_trail_lim.size() < 32) { + unsigned mask = (1 << m_trail_lim.size()); + m_prefix &= mask | (mask - 1); + } + } + + void prune_prefix() { + if (m_trail_lim.size() < 32) { + m_prefix &= (1 << m_trail_lim.size()) - 1; + } + } + + void update_prefix(literal l) { + bool_var x = l.var(); + + unsigned p = m_prefix[x].m_prefix; + if (m_prefix[x].m_length >= m_trail_lim.size() || + ((p | m_prefix) != m_prefix)) { + m_prefix[x].m_length = m_trail_lim.size(); + m_prefix[x].m_prefix = m_prefix; + } + } + // ---------------------------------------- void add_binary(literal l1, literal l2) { @@ -222,6 +251,8 @@ namespace sat { assign(v); // v \/ ~u, u \/ v => v is a unit literal } else if (add_tc1(v, u)) { + update_prefix(u); + update_prefix(v); add_binary(u, v); } } @@ -715,7 +746,7 @@ namespace sat { m_lits.push_back(lit_info()); m_lits.push_back(lit_info()); m_rating.push_back(0); - m_prefix.push_back(prefix()); + m_vprefix.push_back(prefix()); m_freevars.insert(v); } @@ -1154,7 +1185,8 @@ namespace sat { bool backtrack(literal_vector& trail) { if (trail.empty()) return false; - pop(); + pop(); + flip_prefix(); assign(~trail.back()); propagate(); trail.pop_back(); @@ -1221,6 +1253,7 @@ namespace sat { } std::ostream& display(std::ostream& out) const { + out << std::hex << "Prefix: " << m_prefix << std::dec << "\n"; display_values(out); display_binary(out); display_clauses(out); diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 096e52981..e5a3eec80 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -48,6 +48,7 @@ public: } virtual void collect_param_descrs(param_descrs & r) { + r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints for solver"); } diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 76069ce44..6bd4ec64f 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -282,6 +282,7 @@ void * memory::allocate(size_t s) { if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) { synchronize_counters(true); } + return static_cast(r) + 1; // we return a pointer to the location after the extra field } From 0c7603e92536c6a9176acdd7ddbd0a7c5efc83e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Mar 2017 14:39:12 -0700 Subject: [PATCH 0088/1283] fix build of tests Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 8 ++++---- src/test/sat_local_search.cpp | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 420256e59..d2aa164eb 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -152,11 +152,11 @@ namespace sat { void update_prefix(literal l) { bool_var x = l.var(); - unsigned p = m_prefix[x].m_prefix; - if (m_prefix[x].m_length >= m_trail_lim.size() || + unsigned p = m_vprefix[x].m_prefix; + if (m_vprefix[x].m_length >= m_trail_lim.size() || ((p | m_prefix) != m_prefix)) { - m_prefix[x].m_length = m_trail_lim.size(); - m_prefix[x].m_prefix = m_prefix; + m_vprefix[x].m_length = m_trail_lim.size(); + m_vprefix[x].m_prefix = m_prefix; } } diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index f4dee3061..23558ea44 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -76,7 +76,9 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { reslimit limit; params_ref params; sat::solver solver(params, limit); - sat::local_search local_search(solver); + sat::local_search local_search; + + local_search.import(solver, true); char const* file_name = argv[i + 1]; ++i; From 51951a368354d3fb80b5861d9073bd580c8916fd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Mar 2017 16:40:00 -0700 Subject: [PATCH 0089/1283] add logging to lookahead Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 103 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index d2aa164eb..f8ed9f21f 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -160,6 +160,15 @@ namespace sat { } } + bool active_prefix(bool_var x) { + unsigned lvl = m_trail_lim.size(); + unsigned p = m_vprefix[x].m_prefix; + unsigned l = m_vprefix[x].m_length; + if (l > lvl) return false; + if (l == lvl || l >= 32) return m_prefix == p; + return (m_prefix & ((1 << l) - 1)) == p; + } + // ---------------------------------------- void add_binary(literal l1, literal l2) { @@ -315,6 +324,7 @@ namespace sat { } } } + TRACE("sat", display_candidates(tout);); SASSERT(!m_candidates.empty()); if (m_candidates.size() > max_num_cand) { unsigned j = m_candidates.size()/2; @@ -330,6 +340,7 @@ namespace sat { } } SASSERT(!m_candidates.empty() && m_candidates.size() <= max_num_cand); + TRACE("sat", display_candidates(tout);); return true; } @@ -353,15 +364,22 @@ namespace sat { for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { SASSERT(is_undef(*it)); bool_var x = *it; - if (!newbies) { - // TBD filter out candidates based on prefix strings or similar method - } - m_candidates.push_back(candidate(x, m_rating[x])); - sum += m_rating[x]; - } + if (newbies || active_prefix(x)) { + m_candidates.push_back(candidate(x, m_rating[x])); + sum += m_rating[x]; + } + } + TRACE("sat", display_candidates(tout << "sum: " << sum << "\n");); return sum; } + std::ostream& display_candidates(std::ostream& out) const { + for (unsigned i = 0; i < m_candidates.size(); ++i) { + out << "var: " << m_candidates[i].m_var << " rating: " << m_candidates[i].m_rating << "\n"; + } + return out; + } + bool is_sat() const { for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { literal l(*it, false); @@ -437,7 +455,33 @@ namespace sat { for (; it != end; ++it) { if (is_undef(*it)) sum += h[it->index()]; } - // TBD walk ternary clauses. + watch_list& wlist = m_watches[l.index()]; + watch_list::iterator wit = wlist.begin(), wend = wlist.end(); + for (; wit != wend; ++wit) { + switch (wit->get_kind()) { + case watched::BINARY: + UNREACHABLE(); + break; + case watched::TERNARY: + UNREACHABLE(); + tsum += h[wit->get_literal1().index()] * h[wit->get_literal2().index()]; + break; + case watched::CLAUSE: { + clause_offset cls_off = wit->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + // approximation compared to ternary clause case: + // we pick two other literals from the clause. + if (c[0] == ~l) { + tsum += h[c[1].index()] * h[c[2].index()]; + } + else { + SASSERT(c[1] == ~l); + tsum += h[c[0].index()] * h[c[2].index()]; + } + break; + } + } + } sum = (float)(0.1 + afactor*sum + sqfactor*tsum); return std::min(m_config.m_max_score, sum); } @@ -486,6 +530,7 @@ namespace sat { if (get_rank(lit) == 0) get_scc(lit); if (get_rank(~lit) == 0) get_scc(~lit); } + TRACE("sat", display_scc(tout);); } void init_scc() { inc_bstamp(); @@ -502,6 +547,7 @@ namespace sat { // set nextp = 0? m_rank = 0; m_active = null_literal; + TRACE("sat", display_dfs(tout);); } void init_dfs_info(literal l) { unsigned idx = l.index(); @@ -523,6 +569,7 @@ namespace sat { } void add_arc(literal u, literal v) { m_dfs[u.index()].m_next.push_back(v); } bool has_arc(literal v) const { return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp; } + arcs get_arcs(literal v) const { return m_dfs[v.index()].m_next; } literal pop_arc(literal u) { return m_dfs[u.index()].m_next[m_dfs[u.index()].m_nextp++]; } unsigned num_next(literal u) const { return m_dfs[u.index()].m_next.size(); } literal get_next(literal u, unsigned i) const { return m_dfs[u.index()].m_next[i]; } @@ -602,6 +649,30 @@ namespace sat { } } + std::ostream& display_dfs(std::ostream& out) const { + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal l(m_candidates[i].m_var, false); + arcs const& a1 = get_arcs(l); + if (!a1.empty()) { + out << l << " -> " << a1 << "\n"; + } + arcs const& a2 = get_arcs(~l); + if (!a2.empty()) { + out << ~l << " -> " << a2 << "\n"; + } + } + return out; + } + + std::ostream& display_scc(std::ostream& out) const { + display_dfs(out); + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal l(m_candidates[i].m_var, false); + out << l << " := " << get_parent(l) << "\n"; + out << ~l << " := " << get_parent(~l) << "\n"; + } + } + // ------------------------------------ // lookahead forest // sat11.w 115-121 @@ -1026,6 +1097,7 @@ namespace sat { void compute_wnb() { init_wnb(); + TRACE("sat", display_lookahead(tout); ); for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; if (!is_undef(lit)) { @@ -1045,6 +1117,7 @@ namespace sat { } } reset_wnb(); + TRACE("sat", display_lookahead(tout); ); } void init_wnb() { @@ -1083,6 +1156,7 @@ namespace sat { l = diff1 < diff2 ? lit : ~lit; } } + TRACE("sat", tout << l << "\n";); return l; } @@ -1150,12 +1224,13 @@ namespace sat { } - void set_conflict() { m_inconsistent = true; } + void set_conflict() { TRACE("sat", tout << "conflict\n";); m_inconsistent = true; } bool inconsistent() { return m_inconsistent; } unsigned scope_lvl() const { return m_trail_lim.size(); } void assign(literal l) { + TRACE("sat", tout << "assign: " << l << "\n";); SASSERT(m_level > 0); if (is_undef(l)) { set_true(l); @@ -1239,6 +1314,18 @@ namespace sat { return out; } + std::ostream& display_lookahead(std::ostream& out) const { + for (unsigned i = 0; i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + unsigned offset = m_lookahead[i].m_offset; + out << lit << " offset: " << offset; + out << (is_undef(lit)?" undef": (is_true(lit) ? " true": " false")); + out << " wnb: " << get_wnb(lit); + out << "\n"; + } + return out; + } + public: lookahead(solver& s) : From 5c6cef47357951ba9dfbc884cc77fa51054c9698 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Mar 2017 13:47:01 -0700 Subject: [PATCH 0090/1283] fix local search Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 109 +++++++++++++++++++++++++------------ src/test/sat_lookahead.cpp | 3 +- src/util/uint_set.h | 6 +- 3 files changed, 81 insertions(+), 37 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index f8ed9f21f..c8064a1ed 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -67,6 +67,16 @@ namespace sat { lookahead2 // double lookahead }; + std::ostream& display(std::ostream& out, search_mode m) const { + switch (m) { + case search_mode::searching: return out << "searching"; + case search_mode::lookahead1: return out << "lookahead1"; + case search_mode::lookahead2: return out << "lookahead2"; + default: break; + } + return out; + } + struct ternary { ternary(literal u, literal v, literal w): m_u(u), m_v(v), m_w(w) {} literal m_u, m_v, m_w; @@ -117,6 +127,7 @@ namespace sat { inline bool is_true(literal l) const { return is_fixed(l) && !(bool)((m_stamp[l.var()] & 0x1) ^ l.sign()); } inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } inline void set_undef(literal l) { m_stamp[l.var()] = 0; } + lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; } // set the level within a scope of the search. class scoped_level { @@ -172,6 +183,7 @@ namespace sat { // ---------------------------------------- void add_binary(literal l1, literal l2) { + TRACE("sat", tout << "binary: " << l1 << " " << l2 << "\n";); SASSERT(l1 != l2); SASSERT(~l1 != l2); m_binary[(~l1).index()].push_back(l2); @@ -180,6 +192,7 @@ namespace sat { } void del_binary(unsigned idx) { + // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n");); literal_vector & lits = m_binary[idx]; literal l = lits.back(); lits.pop_back(); @@ -520,7 +533,7 @@ namespace sat { literal m_active; unsigned m_rank; - literal m_settled; + literal_vector m_settled; vector m_dfs; void get_scc() { @@ -547,6 +560,7 @@ namespace sat { // set nextp = 0? m_rank = 0; m_active = null_literal; + m_settled.reset(); TRACE("sat", display_dfs(tout);); } void init_dfs_info(literal l) { @@ -631,6 +645,7 @@ namespace sat { literal best = v; float best_rating = get_rating(v); set_rank(v, UINT_MAX); + m_settled.push_back(t); while (t != v) { SASSERT(t != ~v); set_rank(t, UINT_MAX); @@ -671,6 +686,7 @@ namespace sat { out << l << " := " << get_parent(l) << "\n"; out << ~l << " := " << get_parent(~l) << "\n"; } + return out; } // ------------------------------------ @@ -693,7 +709,8 @@ namespace sat { set_child(pp, null_literal); unsigned h = 0; literal w; - for (literal u = m_settled; u != null_literal; u = get_link(u)) { + for (unsigned i = 0; i < m_settled.size(); ++i) { + literal u = m_settled[i]; literal p = get_parent(u); if (p != pp) { h = 0; @@ -790,6 +807,15 @@ namespace sat { erase_clause_watch(get_wlist(~c[1]), cls_off); } + void del_clauses() { + clause * const* end = m_clauses.end(); + clause * const * it = m_clauses.begin(); + for (; it != end; ++it) { + m_cls_allocator.del_clause(*it); + } + } + + void detach_ternary(literal l1, literal l2, literal l3) { NOT_IMPLEMENTED_YET(); // there is a clause corresponding to a ternary watch group. @@ -812,6 +838,7 @@ namespace sat { m_watches.push_back(watch_list()); m_bstamp.push_back(0); m_bstamp.push_back(0); + m_stamp.push_back(0); m_dfs.push_back(dfs_info()); m_dfs.push_back(dfs_info()); m_lits.push_back(lit_info()); @@ -864,6 +891,7 @@ namespace sat { literal l = s.m_trail[i]; assign(l); } + TRACE("sat", s.display(tout); display(tout);); } // ------------------------------------ @@ -874,7 +902,6 @@ namespace sat { m_trail_lim.push_back(m_trail.size()); m_retired_clause_lim.push_back(m_retired_clauses.size()); m_qhead_lim.push_back(m_qhead); - m_trail.push_back(lit); m_search_modes.push_back(m_search_mode); m_search_mode = searching; scoped_level _sl(*this, level); @@ -889,38 +916,42 @@ namespace sat { m_search_mode = m_search_modes.back(); m_search_modes.pop_back(); - // not for lookahead - // unretire clauses - unsigned rsz = m_retired_clause_lim.back(); - for (unsigned i = rsz; i < m_retired_clauses.size(); ++i) { - attach_clause(*m_retired_clauses[i]); - } - m_retired_clauses.resize(rsz); - m_retired_clause_lim.pop_back(); - - // m_search_mode == searching - // remove local binary clauses - unsigned old_sz = m_binary_trail_lim.back(); - m_binary_trail_lim.pop_back(); - for (unsigned i = old_sz; i < m_binary_trail.size(); ++i) { - del_binary(m_binary_trail[i]); - } - // not for lookahead. // m_freevars only for main search // undo assignments - for (unsigned i = m_trail.size(); i > m_trail_lim.size(); ) { + unsigned old_sz = m_trail_lim.back(); + for (unsigned i = m_trail.size(); i > old_sz; ) { --i; literal l = m_trail[i]; set_undef(l); + TRACE("sat", tout << "inserting free var v" << l.var() << "\n";); m_freevars.insert(l.var()); } - m_trail.shrink(m_trail_lim.size()); // reset assignment. + m_trail.shrink(old_sz); // reset assignment. m_trail_lim.pop_back(); + // not for lookahead + // unretire clauses + old_sz = m_retired_clause_lim.back(); + for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { + attach_clause(*m_retired_clauses[i]); + } + m_retired_clauses.resize(old_sz); + m_retired_clause_lim.pop_back(); + + // m_search_mode == searching + // remove local binary clauses + old_sz = m_binary_trail_lim.back(); + + for (unsigned i = m_binary_trail.size(); i > old_sz; ) { + del_binary(m_binary_trail[--i]); + } + m_binary_trail.shrink(old_sz); + m_binary_trail_lim.pop_back(); + // reset propagation queue - m_qhead_lim.pop_back(); m_qhead = m_qhead_lim.back(); + m_qhead_lim.pop_back(); } void push_lookahead2(literal lit) { @@ -995,7 +1026,6 @@ namespace sat { case watched::CLAUSE: { clause_offset cls_off = it->get_clause_offset(); clause & c = *(s.m_cls_allocator.get_clause(cls_off)); - TRACE("sat", tout << "propagating " << c << "\n";); if (c[0] == ~l) std::swap(c[0], c[1]); if (is_true(c[0])) { @@ -1021,6 +1051,7 @@ namespace sat { } // normal clause was converted to a binary clause. if (!found && is_undef(c[1]) && is_undef(c[0])) { + TRACE("sat", tout << "got binary " << l << ": " << c << "\n";); switch (m_search_mode) { case searching: detach_clause(c); @@ -1036,9 +1067,11 @@ namespace sat { break; } if (is_false(c[0])) { + TRACE("sat", tout << "conflict " << l << ": " << c << "\n";); set_conflict(); } else { + TRACE("sat", tout << "propagating " << l << ": " << c << "\n";); SASSERT(is_undef(c[0])); *it2 = *it; it2++; @@ -1076,7 +1109,7 @@ namespace sat { propagate_binary(l); propagate_clauses(l); } - TRACE("sat", s.display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); + TRACE("sat", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } literal choose() { @@ -1100,9 +1133,7 @@ namespace sat { TRACE("sat", display_lookahead(tout); ); for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; - if (!is_undef(lit)) { - continue; - } + TRACE("sat", tout << "lookahead " << lit << "\n";); reset_wnb(lit); push_lookahead1(lit, 2 + m_lookahead[i].m_offset); bool unsat = inconsistent(); @@ -1110,6 +1141,7 @@ namespace sat { pop_lookahead1(); update_wnb(lit); if (unsat) { + TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); reset_wnb(); assign(~lit); propagate(); @@ -1150,13 +1182,13 @@ namespace sat { if (mixd == h) ++count; if (mixd > h || (mixd == h && s.m_rand(count) == 0)) { - CTRACE("sat", l != null_literal, tout << lit << " " << mixd << "\n";); + CTRACE("sat", l != null_literal, tout << lit << " mix diff: " << mixd << "\n";); if (mixd > h) count = 1; h = mixd; l = diff1 < diff2 ? lit : ~lit; } } - TRACE("sat", tout << l << "\n";); + TRACE("sat", tout << "selected: " << l << "\n";); return l; } @@ -1169,7 +1201,7 @@ namespace sat { } void pop_lookahead1() { - SASSERT(!inconsistent()); + m_inconsistent = false; m_search_mode = m_search_modes.back(); m_search_modes.pop_back(); } @@ -1230,16 +1262,18 @@ namespace sat { unsigned scope_lvl() const { return m_trail_lim.size(); } void assign(literal l) { - TRACE("sat", tout << "assign: " << l << "\n";); + TRACE("sat", tout << "assign: " << l << " := " << value(l) << " @ " << m_level << " "; display(tout, m_search_mode) << "\n";); SASSERT(m_level > 0); if (is_undef(l)) { set_true(l); m_trail.push_back(l); if (m_search_mode == searching) { + TRACE("sat", tout << "removing free var v" << l.var() << "\n";); m_freevars.remove(l.var()); } } else if (is_false(l)) { + SASSERT(!is_true(l)); set_conflict(); } } @@ -1269,6 +1303,7 @@ namespace sat { } lbool search() { + scoped_level _sl(*this, c_fixed_truth); literal_vector trail; m_search_mode = searching; while (true) { @@ -1318,7 +1353,7 @@ namespace sat { for (unsigned i = 0; i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; unsigned offset = m_lookahead[i].m_offset; - out << lit << " offset: " << offset; + out << lit << "\toffset: " << offset; out << (is_undef(lit)?" undef": (is_true(lit) ? " true": " false")); out << " wnb: " << get_wnb(lit); out << "\n"; @@ -1330,10 +1365,15 @@ namespace sat { public: lookahead(solver& s) : s(s), - m_level(0) { + m_level(2), + m_prefix(0) { scoped_level _sl(*this, c_fixed_truth); init(); } + + ~lookahead() { + del_clauses(); + } lbool check() { return search(); @@ -1341,6 +1381,7 @@ namespace sat { std::ostream& display(std::ostream& out) const { out << std::hex << "Prefix: " << m_prefix << std::dec << "\n"; + out << "Level: " << m_level << "\n"; display_values(out); display_binary(out); display_clauses(out); diff --git a/src/test/sat_lookahead.cpp b/src/test/sat_lookahead.cpp index d6993421b..dc62d832b 100644 --- a/src/test/sat_lookahead.cpp +++ b/src/test/sat_lookahead.cpp @@ -11,7 +11,6 @@ void tst_sat_lookahead(char ** argv, int argc, int& i) { reslimit limit; params_ref params; sat::solver solver(params, limit); - sat::lookahead lh(solver); char const* file_name = argv[i + 1]; ++i; @@ -24,6 +23,8 @@ void tst_sat_lookahead(char ** argv, int argc, int& i) { parse_dimacs(in, solver); } + sat::lookahead lh(solver); + IF_VERBOSE(20, solver.display_status(verbose_stream());); std::cout << lh.check() << "\n"; diff --git a/src/util/uint_set.h b/src/util/uint_set.h index 5633b74b2..f0990492b 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -344,11 +344,12 @@ public: void insert(unsigned x) { SASSERT(!contains(x)); - m_index.resize(x + 1, UINT_MAX); - m_elems.resize(m_size + 1); + m_index.reserve(x + 1, UINT_MAX); + m_elems.reserve(m_size + 1); m_index[x] = m_size; m_elems[m_size] = x; m_size++; + SASSERT(contains(x)); } void remove(unsigned x) { @@ -361,6 +362,7 @@ public: m_index[x] = m_size; m_elems[m_size] = x; } + SASSERT(!contains(x)); } bool contains(unsigned x) const { return x < m_index.size() && m_index[x] < m_size && m_elems[m_index[x]] == x; } From c1c0f776fbcc7383cb1941e67eae562a795514c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Mar 2017 16:27:22 -0700 Subject: [PATCH 0091/1283] constraint id Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 83 ++++++++++++++++++++++-------------- src/sat/sat_local_search.h | 11 ++++- 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index a93ad12c1..416339e1b 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -50,7 +50,7 @@ namespace sat { var_info& vi = m_vars[v]; for (unsigned k = 0; k < 2; pol = !pol, k++) { for (unsigned i = 0; i < m_vars[v].m_watch[pol].size(); ++i) { - constraint const& c = m_constraints[m_vars[v].m_watch[pol][i]]; + constraint const& c = m_constraints[m_vars[v].m_watch[pol][i].m_constraint_id]; for (unsigned j = 0; j < c.size(); ++j) { bool_var w = c[j].var(); if (w == v || is_neighbor.contains(w)) continue; @@ -97,10 +97,11 @@ namespace sat { void local_search::init_scores() { for (unsigned v = 0; v < num_vars(); ++v) { bool is_true = cur_solution(v); - int_vector& truep = m_vars[v].m_watch[is_true]; - int_vector& falsep = m_vars[v].m_watch[!is_true]; + coeff_vector& truep = m_vars[v].m_watch[is_true]; + coeff_vector& falsep = m_vars[v].m_watch[!is_true]; for (unsigned i = 0; i < falsep.size(); ++i) { - constraint& c = m_constraints[falsep[i]]; + constraint& c = m_constraints[falsep[i].m_constraint_id]; + SASSERT(falsep[i].m_coeff == 1); // will --slack if (c.m_slack <= 0) { dec_slack_score(v); @@ -109,7 +110,8 @@ namespace sat { } } for (unsigned i = 0; i < truep.size(); ++i) { - constraint& c = m_constraints[truep[i]]; + SASSERT(truep[i].m_coeff == 1); + constraint& c = m_constraints[truep[i].m_constraint_id]; // will --true_terms_count[c] // will ++slack if (c.m_slack <= -1) { @@ -230,8 +232,8 @@ namespace sat { m_constraints.push_back(constraint(k)); for (unsigned i = 0; i < sz; ++i) { m_vars.reserve(c[i].var() + 1); - literal t(~c[i]); - m_vars[t.var()].m_watch[is_pos(t)].push_back(id); + literal t(~c[i]); + m_vars[t.var()].m_watch[is_pos(t)].push_back(pbcoeff(id, 1)); m_constraints.back().push(t); } if (sz == 1 && k == 0) { @@ -239,6 +241,20 @@ namespace sat { } } + void local_search::add_pb(unsigned sz, literal const* c, unsigned const* coeffs, unsigned k) { + unsigned id = m_constraints.size(); + m_constraints.push_back(constraint(k)); + for (unsigned i = 0; i < sz; ++i) { + m_vars.reserve(c[i].var() + 1); + literal t(~c[i]); + m_vars[t.var()].m_watch[is_pos(t)].push_back(pbcoeff(id, coeffs[i])); + m_constraints.back().push(t); // add coefficient to constraint? + } + if (sz == 1 && k == 0) { + m_vars[c[0].var()].m_bias = c[0].sign() ? 0 : 100; + } + } + local_search::local_search() : m_par(0) { } @@ -289,6 +305,7 @@ namespace sat { if (ext) { literal_vector lits; unsigned sz = ext->m_cards.size(); + unsigned_vector coeffs; for (unsigned i = 0; i < sz; ++i) { card_extension::card& c = *ext->m_cards[i]; unsigned n = c.size(); @@ -303,27 +320,27 @@ namespace sat { add_cardinality(lits.size(), lits.c_ptr(), n - k); } else { - // TBD: this doesn't really work because scores are not properly updated for general PB constraints. - NOT_IMPLEMENTED_YET(); // // c.lit() <=> c.lits() >= k // // (c.lits() < k) or c.lit() - // = (c.lits() + (n - k - 1)*~c.lit()) <= n + // = (c.lits() + (n - k + 1)*~c.lit()) <= n // // ~c.lit() or (c.lits() >= k) // = ~c.lit() or (~c.lits() <= n - k) // = k*c.lit() + ~c.lits() <= n // lits.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]); - for (unsigned j = 0; j < n - k - 1; ++j) lits.push_back(~c.lit()); - add_cardinality(lits.size(), lits.c_ptr(), n); + coeffs.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]), coeffs.push_back(1); + lits.push_back(~c.lit()); coeffs.push_back(n - k + 1); + add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), n); lits.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]); - for (unsigned j = 0; j < k; ++j) lits.push_back(c.lit()); - add_cardinality(lits.size(), lits.c_ptr(), n); + coeffs.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]), coeffs.push_back(1); + lits.push_back(c.lit()); coeffs.push_back(k); + add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), n); } } // @@ -474,10 +491,10 @@ namespace sat { l = *cit; best_var = v = l.var(); bool tt = cur_solution(v); - int_vector const& falsep = m_vars[v].m_watch[!tt]; - int_vector::const_iterator it = falsep.begin(), end = falsep.end(); + coeff_vector const& falsep = m_vars[v].m_watch[!tt]; + coeff_vector::const_iterator it = falsep.begin(), end = falsep.end(); for (; it != end; ++it) { - int slack = constraint_slack(*it); + int slack = constraint_slack(it->m_constraint_id); if (slack < 0) ++best_bsb; else if (slack == 0) @@ -489,10 +506,10 @@ namespace sat { if (is_true(l)) { v = l.var(); unsigned bsb = 0; - int_vector const& falsep = m_vars[v].m_watch[!cur_solution(v)]; - int_vector::const_iterator it = falsep.begin(), end = falsep.end(); + coeff_vector const& falsep = m_vars[v].m_watch[!cur_solution(v)]; + coeff_vector::const_iterator it = falsep.begin(), end = falsep.end(); for (; it != end; ++it) { - int slack = constraint_slack(*it); + int slack = constraint_slack(it->m_constraint_id); if (slack < 0) { if (bsb == best_bsb) { break; @@ -541,12 +558,12 @@ namespace sat { m_vars[flipvar].m_value = !cur_solution(flipvar); bool flip_is_true = cur_solution(flipvar); - int_vector const& truep = m_vars[flipvar].m_watch[flip_is_true]; - int_vector const& falsep = m_vars[flipvar].m_watch[!flip_is_true]; + coeff_vector const& truep = m_vars[flipvar].m_watch[flip_is_true]; + coeff_vector const& falsep = m_vars[flipvar].m_watch[!flip_is_true]; - int_vector::const_iterator it = truep.begin(), end = truep.end(); + coeff_vector::const_iterator it = truep.begin(), end = truep.end(); for (; it != end; ++it) { - unsigned ci = *it; + unsigned ci = it->m_constraint_id; constraint& c = m_constraints[ci]; --c.m_slack; if (c.m_slack == -1) { // from 0 to -1: sat -> unsat @@ -555,7 +572,7 @@ namespace sat { } it = falsep.begin(), end = falsep.end(); for (; it != end; ++it) { - unsigned ci = *it; + unsigned ci = it->m_constraint_id; constraint& c = m_constraints[ci]; ++c.m_slack; if (c.m_slack == 0) { // from -1 to 0: unsat -> sat @@ -576,12 +593,12 @@ namespace sat { int org_flipvar_slack_score = slack_score(flipvar); bool flip_is_true = cur_solution(flipvar); - int_vector& truep = m_vars[flipvar].m_watch[flip_is_true]; - int_vector& falsep = m_vars[flipvar].m_watch[!flip_is_true]; + coeff_vector& truep = m_vars[flipvar].m_watch[flip_is_true]; + coeff_vector& falsep = m_vars[flipvar].m_watch[!flip_is_true]; // update related clauses and neighbor vars for (unsigned i = 0; i < truep.size(); ++i) { - constraint & c = m_constraints[truep[i]]; + constraint & c = m_constraints[truep[i].m_constraint_id]; //++true_terms_count[c]; --c.m_slack; switch (c.m_slack) { @@ -605,7 +622,7 @@ namespace sat { if (is_true(c[j])) inc_slack_score(v); } - unsat(truep[i]); + unsat(truep[i].m_constraint_id); break; case 0: // from 1 to 0 for (unsigned j = 0; j < c.size(); ++j) { @@ -623,7 +640,7 @@ namespace sat { } } for (unsigned i = 0; i < falsep.size(); ++i) { - constraint& c = m_constraints[falsep[i]]; + constraint& c = m_constraints[falsep[i].m_constraint_id]; //--true_terms_count[c]; ++c.m_slack; switch (c.m_slack) { @@ -648,7 +665,7 @@ namespace sat { if (is_true(c[j])) dec_slack_score(v); } - sat(falsep[i]); + sat(falsep[i].m_constraint_id); break; case -1: // from -2 to -1 for (unsigned j = 0; j < c.size(); ++j) { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 8cb5ff480..108df4e6d 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -59,7 +59,14 @@ namespace sat { class local_search { + struct pbcoeff { + unsigned m_constraint_id; + unsigned m_coeff; + pbcoeff(unsigned id, unsigned coeff): + m_constraint_id(id), m_coeff(coeff) {} + }; typedef svector bool_vector; + typedef svector coeff_vector; // data structure for a term in objective function struct ob_term { @@ -79,7 +86,7 @@ namespace sat { int m_time_stamp; // the flip time stamp int m_cscc; // how many times its constraint state configure changes since its last flip bool_var_vector m_neighbors; // neighborhood variables - int_vector m_watch[2]; + coeff_vector m_watch[2]; var_info(): m_value(true), m_bias(50), @@ -241,6 +248,8 @@ namespace sat { void add_soft(bool_var v, int weight); void add_cardinality(unsigned sz, literal const* c, unsigned k); + + void add_pb(unsigned sz, literal const* c, unsigned const* coeffs, unsigned k); lbool check(); From f9193af85d079adfb3540ea1d43e3b05f8fa4122 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Mar 2017 16:41:12 -0700 Subject: [PATCH 0092/1283] adding pb Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 416339e1b..92173ff4b 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -79,16 +79,18 @@ namespace sat { // figure out slack, and init unsat stack void local_search::init_slack() { + for (unsigned v = 0; v < num_vars(); ++v) { + bool is_true = cur_solution(v); + coeff_vector& truep = m_vars[v].m_watch[is_true]; + for (unsigned i = 0; i < truep.size(); ++i) { + unsigned c = truep[i].m_constraint_id; + constraint& cn = m_constraints[c]; + cn.m_slack -= truep[i].m_coeff; + } + } for (unsigned c = 0; c < num_constraints(); ++c) { - constraint & cn = m_constraints[c]; - for (unsigned i = 0; i < cn.size(); ++i) { - bool_var v = cn[i].var(); - if (is_true(cn[i])) - --cn.m_slack; - } - // constraint_slack[c] = constraint_k[c] - true_terms_count[c]; // violate the at-most-k constraint - if (cn.m_slack < 0) + if (m_constraints[c].m_slack < 0) unsat(c); } } @@ -497,7 +499,7 @@ namespace sat { int slack = constraint_slack(it->m_constraint_id); if (slack < 0) ++best_bsb; - else if (slack == 0) + else if (slack < static_cast(it->m_coeff)) best_bsb += num_unsat; } ++cit; @@ -518,7 +520,7 @@ namespace sat { ++bsb; } } - else if (slack == 0) { + else if (slack < static_cast(it->m_coeff)) { bsb += num_unsat; if (bsb > best_bsb) { break; @@ -565,8 +567,9 @@ namespace sat { for (; it != end; ++it) { unsigned ci = it->m_constraint_id; constraint& c = m_constraints[ci]; - --c.m_slack; - if (c.m_slack == -1) { // from 0 to -1: sat -> unsat + int old_slack = c.m_slack; + c.m_slack -= it->m_coeff; + if (c.m_slack < 0 && old_slack >= 0) { // from non-negative to negative: sat -> unsat unsat(ci); } } @@ -574,8 +577,9 @@ namespace sat { for (; it != end; ++it) { unsigned ci = it->m_constraint_id; constraint& c = m_constraints[ci]; - ++c.m_slack; - if (c.m_slack == 0) { // from -1 to 0: unsat -> sat + int old_slack = c.m_slack; + c.m_slack += it->m_coeff; + if (c.m_slack >= 0 && old_slack < 0) { // from negative to non-negative: unsat -> sat sat(ci); } } From d4977cb2dbd92c420726b8213fa02a8fca77373f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 15 Mar 2017 08:11:13 -0700 Subject: [PATCH 0093/1283] lookeahead updates Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 36 ++++++++++++++++++++++++++++++++++++ src/sat/sat_lookahead.h | 30 +++++++++++++++++++++++------- src/sat/sat_simplifier.cpp | 6 +++++- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 21a3fedf4..b176253fd 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2175,6 +2175,42 @@ namespace z3 { }; inline std::ostream & operator<<(std::ostream & out, optimize const & s) { out << Z3_optimize_to_string(s.ctx(), s.m_opt); return out; } + class fixedpoint : public object { + Z3_fixedpoint m_fp; + public: + fixedpoint(context& c):object(c) { mfp = Z3_mk_fixedpoint(c); Z3_fixedpoint_inc_ref(c, m_fp); } + ~fixedpoint() { Z3_fixedpoint_dec_ref(ctx(), m_fp); } + operator Z3_fixedpoint() const { return m_fp; } + void from_string(char const* s) { Z3_fixedpoint_from_string(ctx(), m_fp, s); check_error(); } + void from_file(char const* s) { Z3_fixedpoint_from_file(ctx(), m_fp, s); check_error(); } + void add_rule(expr& rule, symbol const& name) { Z3_fixedpoint_add_rule(ctx(), m_fp, rule, name); check_error(); } + void add_fact(func_decl& f, unsigned const* args) { Z3_fixedpoint_add_fact(ctx(), m_fp, f, f.num_args(), args); check_error(); } + check_result query(expr& q) { Z3_lbool r = Z3_fixedpoint_query(ctx(), m_fp, q); check_error(); to_check_result(r); } + check_result query(func_decl_vector& relations) { + array rs(relations); + Z3_lbool r = Z3_fixedpoint_query_relations(ctx(), m_fp, rs.size(), rs.ptr()); + check_error(); + return to_check_result(r); + } + expr get_answer() { Z3_ast r = Z3_fixedpoint_get_answer(ctx(), m_fp); check_error(); return expr(ctx(), r); } + std::string reason_unknown() { return Z3_fixedpoint_get_reason_unknown(ctx(), m_fp); } + void update_rule(expr& rule, synbol const& name) { Z3_fixedpoint_update_rule(ctx(), m_fp, rule, name); check_error(); } + unsigned get_num_levels(func_decl& p) { unsigned r = Z3_fixedpoint_get_num_levels(ctx(), m_fp, p); check_error(); return r; } + expr get_cover_delta(int level, func_decl& p) { return Z3_fixedpoint_get_cover_delta(ctx(), m_fp, level, p); check_error(); } + void add_cover(int level, func_decl& p, expr& property) { Z3_fixedpoint_add_cover(ctx(), m_fp, level, p, property); check_error(); } + stats statistics() const { Z3_stats r = Z3_fixedpoint_get_statistics(ctx(), m_fp); check_error(); return stats(ctx(), r); } + void register_relation(func_decl& p) { Z3_fixedpoint_register_relation(ctx(), m_fp, p); } + expr_vector assertions() const { Z3_ast_vector r = Z3_fixedpoint_get_assertions(ctx(), m_fp); check_error(); return expr_vector(ctx(), r); } + expr_vector rules() const { Z3_ast_vector r = Z3_fixedpoint_get_rules(ctx(), m_fp); check_error(); return expr_vector(ctx(), r); } + void set(params const & p) { Z3_fixedpoint_set_params(ctx(), m_fp, p); check_error(); } + std::string help() const { return Z3_fixedpoint_get_help(ctx(), m_fp); } + param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_fixedpoint_get_param_descrs(ctx(), m_fp)); } + std::string to_string() { return Z3_fixedpoint_to_string(ctx(), m_fp); } + void push() { Z3_fixedpoint_push(ctx(), m_fp); check_error(); } + void pop() { Z3_fixedpoint_pop(ctx(), m_fp); check_error(); } + }; + inline std::ostream & operator<<(std::ostream & out, fixedpoint const & f) { return out << Z3_fixedpoint_to_string(f.ctx(), f); } + inline tactic fail_if(probe const & p) { Z3_tactic r = Z3_tactic_fail_if(p.ctx(), p); p.check_error(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index c8064a1ed..3ebb9edd3 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -290,7 +290,7 @@ namespace sat { get_scc(); find_heights(); construct_lookahead_table(); - } + } } struct candidate { @@ -314,7 +314,10 @@ namespace sat { if (!m_candidates.empty()) break; if (is_sat()) { return false; - } + } + if (newbies) { + TRACE("sat", tout << sum << "\n";); + } } SASSERT(!m_candidates.empty()); // cut number of candidates down to max_num_cand. @@ -398,16 +401,27 @@ namespace sat { literal l(*it, false); literal_vector const& lits1 = m_binary[l.index()]; for (unsigned i = 0; i < lits1.size(); ++i) { - if (!is_true(lits1[i])) return false; + if (!is_true(lits1[i])) { + TRACE("sat", tout << l << " " << lits1[i] << "\n";); + return false; + } } - literal_vector const& lits2 = m_binary[(~l).index()]; + l.neg(); + literal_vector const& lits2 = m_binary[l.index()]; for (unsigned i = 0; i < lits2.size(); ++i) { - if (!is_true(lits2[i])) return false; + if (!is_true(lits2[i])) { + TRACE("sat", tout << l << " " << lits2[i] << "\n";); + return false; + } } } for (unsigned i = 0; i < m_clauses.size(); ++i) { clause& c = *m_clauses[i]; - if (!is_true(c[0]) && !is_true(c[1])) return false; + unsigned j = 0; + for (; j < c.size() && !is_true(c[j]); ++j) {} + if (j == c.size()) { + return false; + } } return true; } @@ -645,8 +659,8 @@ namespace sat { literal best = v; float best_rating = get_rating(v); set_rank(v, UINT_MAX); - m_settled.push_back(t); while (t != v) { + m_settled.push_back(t); SASSERT(t != ~v); set_rank(t, UINT_MAX); set_parent(t, v); @@ -657,6 +671,7 @@ namespace sat { } t = get_link(t); } + m_settled.push_back(v); set_parent(v, v); set_vcomp(v, best); if (get_rank(~v) == UINT_MAX) { @@ -705,6 +720,7 @@ namespace sat { } void find_heights() { + TRACE("sat", tout << m_settled << "\n";); literal pp = null_literal; set_child(pp, null_literal); unsigned h = 0; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 03ff7ec98..10f427fa1 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -283,7 +283,11 @@ namespace sat { unsigned sz = c.size(); if (sz == 0) { s.set_conflict(justification()); - return; + for (; it != end; ++it) { + *it2 = *it; + ++it2; + } + break; } if (sz == 1) { s.assign(c[0], justification()); From cdf080061ea21acd701a8de4c95986474bbc1a50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 15 Mar 2017 18:59:19 -0700 Subject: [PATCH 0094/1283] add debugging Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 42 +++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 3ebb9edd3..954897b3d 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -520,7 +520,7 @@ namespace sat { struct arcs : public literal_vector {}; // Knuth uses a shared pool of fixed size for arcs. - // Should it be useful we could use this approach tooo + // Should it be useful we could use this approach too // by changing the arcs abstraction and associated functions. struct dfs_info { @@ -682,14 +682,16 @@ namespace sat { std::ostream& display_dfs(std::ostream& out) const { for (unsigned i = 0; i < m_candidates.size(); ++i) { literal l(m_candidates[i].m_var, false); - arcs const& a1 = get_arcs(l); - if (!a1.empty()) { - out << l << " -> " << a1 << "\n"; - } - arcs const& a2 = get_arcs(~l); - if (!a2.empty()) { - out << ~l << " -> " << a2 << "\n"; - } + display_dfs(out, l); + display_dfs(out, ~l); + } + return out; + } + + std::ostream& display_dfs(std::ostream& out, literal l) const { + arcs const& a1 = get_arcs(l); + if (!a1.empty()) { + out << l << " -> " << a1 << "\n"; } return out; } @@ -698,12 +700,23 @@ namespace sat { display_dfs(out); for (unsigned i = 0; i < m_candidates.size(); ++i) { literal l(m_candidates[i].m_var, false); - out << l << " := " << get_parent(l) << "\n"; - out << ~l << " := " << get_parent(~l) << "\n"; + display_scc(out, l); + display_scc(out, ~l); } return out; } + std::ostream& display_scc(std::ostream& out, literal l) const { + out << l << " := " << get_parent(l) + << " min: " << get_min(l) + << " rank: " << get_rank(l) + << " height: " << get_height(l) + << " link: " << get_link(l) + << " vcomp: " << get_vcomp(l) << "\n"; + return out; + } + + // ------------------------------------ // lookahead forest // sat11.w 115-121 @@ -720,13 +733,13 @@ namespace sat { } void find_heights() { - TRACE("sat", tout << m_settled << "\n";); + TRACE("sat", display_scc(tout << m_settled << "\n");); literal pp = null_literal; set_child(pp, null_literal); unsigned h = 0; literal w; - for (unsigned i = 0; i < m_settled.size(); ++i) { - literal u = m_settled[i]; + for (unsigned i = m_settled.size(); i > 0; ) { + literal u = m_settled[--i]; literal p = get_parent(u); if (p != pp) { h = 0; @@ -751,6 +764,7 @@ namespace sat { set_child(w, u); } } + TRACE("sat", display_scc(tout); ); } struct literal_offset { literal m_lit; From 5ed3200c8823d991eeac6e1f5f5c7672b761ae64 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 Mar 2017 16:39:51 -0700 Subject: [PATCH 0095/1283] diagnosing lookahead solver Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 100 ++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 954897b3d..73e0ea0bd 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -547,7 +547,7 @@ namespace sat { literal m_active; unsigned m_rank; - literal_vector m_settled; + literal m_settled; vector m_dfs; void get_scc() { @@ -574,7 +574,7 @@ namespace sat { // set nextp = 0? m_rank = 0; m_active = null_literal; - m_settled.reset(); + m_settled = null_literal; TRACE("sat", display_dfs(tout);); } void init_dfs_info(literal l) { @@ -616,30 +616,32 @@ namespace sat { void get_scc(literal v) { set_parent(v, null_literal); activate_scc(v); - literal u; do { literal ll = get_min(v); - if (!has_arc(v)) { - u = get_parent(v); - if (v == ll) { + if (has_arc(v)) { + literal u = pop_arc(v); + unsigned r = get_rank(u); + if (r > 0) { + // u was processed before ll + if (r < get_rank(ll)) set_min(v, u); + } + else { + // process u in dfs order, add v to dfs stack for u + set_parent(u, v); + v = u; + activate_scc(v); + } + } + else { + literal u = get_parent(v); + if (v == ll) { found_scc(v); } else if (get_rank(ll) < get_rank(get_min(u))) { set_min(u, ll); } + // walk back in the dfs stack v = u; - } - else { - literal u = pop_arc(v); - unsigned r = get_rank(u); - if (r > 0) { - if (r < get_rank(ll)) set_min(v, u); - } - else { - set_parent(u, v); - v = u; - activate_scc(v); - } } } while (v != null_literal); @@ -659,8 +661,8 @@ namespace sat { literal best = v; float best_rating = get_rating(v); set_rank(v, UINT_MAX); + set_link(v, m_settled); m_settled = t; while (t != v) { - m_settled.push_back(t); SASSERT(t != ~v); set_rank(t, UINT_MAX); set_parent(t, v); @@ -671,11 +673,10 @@ namespace sat { } t = get_link(t); } - m_settled.push_back(v); set_parent(v, v); set_vcomp(v, best); if (get_rank(~v) == UINT_MAX) { - set_vcomp(v, ~get_vcomp(get_parent(~v))); // TBD check semantics + set_vcomp(v, ~get_vcomp(get_parent(~v))); } } @@ -712,6 +713,7 @@ namespace sat { << " rank: " << get_rank(l) << " height: " << get_height(l) << " link: " << get_link(l) + << " child: " << get_child(l) << " vcomp: " << get_vcomp(l) << "\n"; return out; } @@ -732,40 +734,78 @@ namespace sat { else m_dfs[v.index()].m_min = u; } + /* + \brief Assign heights to the nodes. + Nodes within the same strongly connected component are given the same height. + The code assumes that m_settled is topologically sorted such that + 1. nodes in the same equivalence class come together + 2. the equivalence class representative is last + + */ void find_heights() { - TRACE("sat", display_scc(tout << m_settled << "\n");); + m_root_child = null_literal; literal pp = null_literal; - set_child(pp, null_literal); unsigned h = 0; - literal w; - for (unsigned i = m_settled.size(); i > 0; ) { - literal u = m_settled[--i]; + literal w, uu; + TRACE("sat", + for (literal u = m_settled; u != null_literal; u = get_link(u)) { + tout << u << " "; + } + tout << "\n";); + for (literal u = m_settled; u != null_literal; u = uu) { + TRACE("sat", tout << "process: " << u << "\n";); + uu = get_link(u); literal p = get_parent(u); if (p != pp) { + // new equivalence class h = 0; w = null_literal; pp = p; } - for (unsigned j = 0; j < num_next(~u); ++j) { + // traverse nodes in order of implication + unsigned sz = num_next(~u); + for (unsigned j = 0; j < sz; ++j) { literal v = ~get_next(~u, j); + TRACE("sat", tout << "child " << v << " link: " << get_link(v) << "\n";); literal pv = get_parent(v); - if (pv == p) continue; + // skip nodes in same equivalence, they will all be processed + if (pv == p) continue; unsigned hh = get_height(pv); + // update the maximal height descendant if (hh >= h) { h = hh + 1; w = pv; } } - if (p == u) { // u is an equivalence class representative + if (p == u) { + // u is an equivalence class representative + // it is processed last literal v = get_child(w); set_height(u, h); set_child(u, null_literal); set_link(u, v); set_child(w, u); + TRACE("sat", tout << "child(" << w << ") = " << u << " link(" << u << ") = " << v << "\n";); } } - TRACE("sat", display_scc(tout); ); + TRACE("sat", + display_forest(tout, get_child(null_literal)); + tout << "\n"; + display_scc(tout); ); } + std::ostream& display_forest(std::ostream& out, literal l) { + for (literal u = l; u != null_literal; u = get_link(u)) { + out << u << " "; + l = get_child(u); + if (l != null_literal) { + out << "("; + display_forest(out, l); + out << ") "; + } + } + return out; + } + struct literal_offset { literal m_lit; unsigned m_offset; From 2afd45b3c25e6a265f607a43a252bd9940fbc702 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Mar 2017 04:53:27 +0200 Subject: [PATCH 0096/1283] working on lookahead Signed-off-by: Nikolaj Bjorner --- src/sat/sat_iff3_finder.cpp | 4 +- src/sat/sat_integrity_checker.cpp | 6 +- src/sat/sat_lookahead.h | 516 +++++++++++++++++++++--------- src/sat/sat_simplifier.cpp | 4 +- src/sat/sat_solver.cpp | 2 +- src/sat/sat_types.h | 2 +- src/sat/sat_watched.cpp | 2 +- src/sat/sat_watched.h | 2 +- src/test/main.cpp | 10 +- src/test/sat_lookahead.cpp | 8 +- 10 files changed, 388 insertions(+), 168 deletions(-) diff --git a/src/sat/sat_iff3_finder.cpp b/src/sat/sat_iff3_finder.cpp index 789f5dec0..ca47207e5 100644 --- a/src/sat/sat_iff3_finder.cpp +++ b/src/sat/sat_iff3_finder.cpp @@ -136,9 +136,9 @@ namespace sat { TRACE("iff3_finder", tout << "visiting: " << x << "\n"; tout << "pos:\n"; - display(tout, s.m_cls_allocator, pos_wlist); + display_watch_list(tout, s.m_cls_allocator, pos_wlist); tout << "\nneg:\n"; - display(tout, s.m_cls_allocator, neg_wlist); + display_watch_list(tout, s.m_cls_allocator, neg_wlist); tout << "\n--------------\n";); // traverse the ternary clauses x \/ l1 \/ l2 bool_var curr_v1 = null_bool_var; diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index f7cd371f8..27958785d 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -68,7 +68,7 @@ namespace sat { if (c.size() == 3) { CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2]), tout << c << "\n"; tout << "watch_list:\n"; - sat::display(tout, s.m_cls_allocator, s.get_wlist(~c[0])); + sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~c[0])); tout << "\n";); VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2])); VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2])); @@ -176,9 +176,9 @@ namespace sat { tout << "was_eliminated1: " << s.was_eliminated(l.var()); tout << " was_eliminated2: " << s.was_eliminated(it2->get_literal().var()); tout << " learned: " << it2->is_learned() << "\n"; - sat::display(tout, s.m_cls_allocator, wlist); + sat::display_watch_list(tout, s.m_cls_allocator, wlist); tout << "\n"; - sat::display(tout, s.m_cls_allocator, s.get_wlist(~(it2->get_literal()))); + sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~(it2->get_literal()))); tout << "\n";); SASSERT(s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned()))); break; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 73e0ea0bd..167de1bab 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -21,6 +21,38 @@ Notes: #define _SAT_LOOKAHEAD_H_ namespace sat { + + struct pp_prefix { + uint64 m_prefix; + unsigned m_depth; + pp_prefix(uint64 p, unsigned d) : m_prefix(p), m_depth(d) {} + }; + + inline std::ostream& operator<<(std::ostream& out, pp_prefix const& p) { + uint64 q = p.m_prefix; + unsigned d = std::min(63u, p.m_depth); + for (unsigned i = 0; i <= d; ++i) { + if (0 != (p.m_prefix & (1ull << i))) out << "1"; else out << "0"; + } + return out; + } + + enum lookahead_mode { + searching, // normal search + lookahead1, // lookahead mode + lookahead2 // double lookahead + }; + + inline std::ostream& operator<<(std::ostream& out, lookahead_mode m) { + switch (m) { + case lookahead_mode::searching: return out << "searching"; + case lookahead_mode::lookahead1: return out << "lookahead1"; + case lookahead_mode::lookahead2: return out << "lookahead2"; + default: break; + } + return out; + } + class lookahead { solver& s; @@ -32,6 +64,7 @@ namespace sat { unsigned m_min_cutoff; unsigned m_level_cand; float m_delta_rho; + unsigned m_dl_max_iterations; config() { m_max_hlevel = 50; @@ -40,6 +73,7 @@ namespace sat { m_min_cutoff = 30; m_level_cand = 600; m_delta_rho = (float)0.9995; + m_dl_max_iterations = 32; } }; @@ -55,28 +89,17 @@ namespace sat { lit_info(): m_wnb(0), m_double_lookahead(0) {} }; - struct statistics { + struct stats { unsigned m_propagations; - statistics() { reset(); } + unsigned m_add_binary; + unsigned m_del_binary; + unsigned m_add_ternary; + unsigned m_del_ternary; + unsigned m_decisions; + stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; - enum search_mode { - searching, // normal search - lookahead1, // lookahead mode - lookahead2 // double lookahead - }; - - std::ostream& display(std::ostream& out, search_mode m) const { - switch (m) { - case search_mode::searching: return out << "searching"; - case search_mode::lookahead1: return out << "lookahead1"; - case search_mode::lookahead2: return out << "lookahead2"; - default: break; - } - return out; - } - struct ternary { ternary(literal u, literal v, literal w): m_u(u), m_v(v), m_w(w) {} literal m_u, m_v, m_w; @@ -94,8 +117,9 @@ namespace sat { unsigned_vector m_qhead_lim; clause_vector m_clauses; // non-binary clauses clause_vector m_retired_clauses; // clauses that were removed during search - svector m_retired_ternary; // unsigned_vector m_retired_clause_lim; + svector m_retired_ternary; // ternary removed during search + unsigned_vector m_retired_ternary_lim; clause_allocator m_cls_allocator; bool m_inconsistent; unsigned_vector m_bstamp; // literal: timestamp for binary implication @@ -110,12 +134,12 @@ namespace sat { vector m_watches; // literal: watch structure svector m_lits; // literal: attributes. float m_weighted_new_binaries; // metric associated with current lookahead1 literal. - unsigned m_prefix; // where we are in search tree + literal_vector m_wstack; // windofall stack that is populated in lookahead1 mode + uint64 m_prefix; // where we are in search tree svector m_vprefix; // var: prefix where variable participates in propagation indexed_uint_set m_freevars; - svector m_search_modes; // stack of modes - search_mode m_search_mode; // mode of search - statistics m_stats; + lookahead_mode m_search_mode; // mode of search + stats m_stats; // --------------------------------------- // truth values @@ -148,15 +172,15 @@ namespace sat { // skip bit 0 in a bid to reduce details. void flip_prefix() { - if (m_trail_lim.size() < 32) { - unsigned mask = (1 << m_trail_lim.size()); - m_prefix &= mask | (mask - 1); + if (m_trail_lim.size() < 64) { + uint64 mask = (1ull << m_trail_lim.size()); + m_prefix = mask | (m_prefix & (mask - 1)); } } void prune_prefix() { - if (m_trail_lim.size() < 32) { - m_prefix &= (1 << m_trail_lim.size()) - 1; + if (m_trail_lim.size() < 64) { + m_prefix &= (1ull << m_trail_lim.size()) - 1; } } @@ -167,7 +191,7 @@ namespace sat { if (m_vprefix[x].m_length >= m_trail_lim.size() || ((p | m_prefix) != m_prefix)) { m_vprefix[x].m_length = m_trail_lim.size(); - m_vprefix[x].m_prefix = m_prefix; + m_vprefix[x].m_prefix = static_cast(m_prefix); } } @@ -176,19 +200,23 @@ namespace sat { unsigned p = m_vprefix[x].m_prefix; unsigned l = m_vprefix[x].m_length; if (l > lvl) return false; - if (l == lvl || l >= 32) return m_prefix == p; - return (m_prefix & ((1 << l) - 1)) == p; + if (l == lvl || l >= 31) return m_prefix == p; + unsigned mask = ((1 << l) - 1); + return (m_prefix & mask) == (p & mask); } // ---------------------------------------- void add_binary(literal l1, literal l2) { - TRACE("sat", tout << "binary: " << l1 << " " << l2 << "\n";); + TRACE("sat", tout << "binary: " << l1 << " " << l2 << "\n";); SASSERT(l1 != l2); - SASSERT(~l1 != l2); + // don't add tautologies and don't add already added binaries + if (~l1 == l2) return; + if (!m_binary[(~l1).index()].empty() && m_binary[(~l1).index()].back() == l2) return; m_binary[(~l1).index()].push_back(l2); m_binary[(~l2).index()].push_back(l1); m_binary_trail.push_back((~l1).index()); + ++m_stats.m_add_binary; } void del_binary(unsigned idx) { @@ -197,6 +225,7 @@ namespace sat { literal l = lits.back(); lits.pop_back(); m_binary[(~l).index()].pop_back(); + ++m_stats.m_del_binary; } // ------------------------------------- @@ -247,6 +276,7 @@ namespace sat { if (!is_fixed(w)) { if (is_stamped(~w)) { // u \/ v, ~v \/ w, u \/ ~w => u is unit + TRACE("sat", tout << "tc1: " << u << "\n";); assign(u); return false; } @@ -260,16 +290,18 @@ namespace sat { \brief main routine for adding a new binary clause dynamically. */ void try_add_binary(literal u, literal v) { - SASSERT(m_search_mode == searching); + SASSERT(m_search_mode == lookahead_mode::searching); SASSERT(u.var() != v.var()); set_bstamps(~u); - if (is_stamped(~v)) { + if (is_stamped(~v)) { + TRACE("sat", tout << "try_add_binary: " << u << "\n";); assign(u); // u \/ ~v, u \/ v => u is a unit literal } else if (!is_stamped(v) && add_tc1(u, v)) { // u \/ v is not in index set_bstamps(~v); if (is_stamped(~u)) { + TRACE("sat", tout << "try_add_binary: " << v << "\n";); assign(v); // v \/ ~u, u \/ v => v is a unit literal } else if (add_tc1(v, u)) { @@ -288,9 +320,10 @@ namespace sat { m_lookahead.reset(); if (select(scope_lvl())) { get_scc(); + if (inconsistent()) return; find_heights(); construct_lookahead_table(); - } + } } struct candidate { @@ -316,6 +349,8 @@ namespace sat { return false; } if (newbies) { + enable_trace("sat"); + TRACE("sat", display(tout);); TRACE("sat", tout << sum << "\n";); } } @@ -396,6 +431,20 @@ namespace sat { return out; } + bool is_unsat() const { + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause& c = *m_clauses[i]; + unsigned j = 0; + for (; j < c.size() && is_false(c[j]); ++j) {} + if (j == c.size()) { + TRACE("sat", tout << c << "\n";); + TRACE("sat", display(tout);); + return true; + } + } + return false; + } + bool is_sat() const { for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { literal l(*it, false); @@ -489,10 +538,14 @@ namespace sat { case watched::BINARY: UNREACHABLE(); break; - case watched::TERNARY: - UNREACHABLE(); - tsum += h[wit->get_literal1().index()] * h[wit->get_literal2().index()]; + case watched::TERNARY: { + literal l1 = wit->get_literal1(); + literal l2 = wit->get_literal2(); + if (is_undef(l1) && is_undef(l2)) { + tsum += h[l1.index()] * h[l2.index()]; + } break; + } case watched::CLAUSE: { clause_offset cls_off = wit->get_clause_offset(); clause & c = *(s.m_cls_allocator.get_clause(cls_off)); @@ -552,7 +605,7 @@ namespace sat { void get_scc() { init_scc(); - for (unsigned i = 0; i < m_candidates.size(); ++i) { + for (unsigned i = 0; i < m_candidates.size() && !inconsistent(); ++i) { literal lit(m_candidates[i].m_var, false); if (get_rank(lit) == 0) get_scc(lit); if (get_rank(~lit) == 0) get_scc(~lit); @@ -644,7 +697,7 @@ namespace sat { v = u; } } - while (v != null_literal); + while (v != null_literal && !inconsistent()); } void activate_scc(literal l) { SASSERT(get_rank(l) == 0); @@ -663,7 +716,11 @@ namespace sat { set_rank(v, UINT_MAX); set_link(v, m_settled); m_settled = t; while (t != v) { - SASSERT(t != ~v); + if (t == ~v) { + TRACE("sat", display_scc(tout << "found contradiction during scc search\n");); + set_conflict(); + break; + } set_rank(t, UINT_MAX); set_parent(t, v); float t_rating = get_rating(t); @@ -855,10 +912,8 @@ namespace sat { // clause management void attach_clause(clause& c) { - if (false && c.size() == 3) { // disable ternary clauses - m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); - m_watches[(~c[1]).index()].push_back(watched(c[0], c[2])); - m_watches[(~c[2]).index()].push_back(watched(c[0], c[1])); + if (c.size() == 3) { + attach_ternary(c[0], c[1], c[2]); } else { literal block_lit = c[c.size() >> 2]; @@ -885,17 +940,26 @@ namespace sat { } } - void detach_ternary(literal l1, literal l2, literal l3) { - NOT_IMPLEMENTED_YET(); - // there is a clause corresponding to a ternary watch group. - // the clause could be retired / detached. + ++m_stats.m_del_ternary; m_retired_ternary.push_back(ternary(l1, l2, l3)); - erase_ternary_watch(get_wlist(~l1), l2, l3); + // implicitly erased: erase_ternary_watch(get_wlist(~l1), l2, l3); erase_ternary_watch(get_wlist(~l2), l1, l3); erase_ternary_watch(get_wlist(~l3), l1, l2); } + void attach_ternary(ternary const& t) { + attach_ternary(t.m_u, t.m_v, t.m_w); + } + + void attach_ternary(literal l1, literal l2, literal l3) { + ++m_stats.m_add_ternary; + TRACE("sat", tout << l1 << " " << l2 << " " << l3 << "\n";); + m_watches[(~l1).index()].push_back(watched(l2, l3)); + m_watches[(~l2).index()].push_back(watched(l1, l3)); + m_watches[(~l3).index()].push_back(watched(l1, l2)); + } + watch_list& get_wlist(literal l) { return m_watches[l.index()]; } // ------------------------------------ @@ -952,7 +1016,7 @@ namespace sat { clause& c = *(*it); clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); m_clauses.push_back(c1); - attach_clause(c); + attach_clause(*c1); } // copy units @@ -968,12 +1032,12 @@ namespace sat { // search void push(literal lit, unsigned level) { + SASSERT(m_search_mode == lookahead_mode::searching); m_binary_trail_lim.push_back(m_binary_trail.size()); m_trail_lim.push_back(m_trail.size()); m_retired_clause_lim.push_back(m_retired_clauses.size()); + m_retired_ternary_lim.push_back(m_retired_ternary.size()); m_qhead_lim.push_back(m_qhead); - m_search_modes.push_back(m_search_mode); - m_search_mode = searching; scoped_level _sl(*this, level); assign(lit); propagate(); @@ -981,12 +1045,8 @@ namespace sat { void pop() { m_inconsistent = false; + SASSERT(m_search_mode == lookahead_mode::searching); - // search mode - m_search_mode = m_search_modes.back(); - m_search_modes.pop_back(); - - // not for lookahead. // m_freevars only for main search // undo assignments unsigned old_sz = m_trail_lim.back(); @@ -1000,7 +1060,6 @@ namespace sat { m_trail.shrink(old_sz); // reset assignment. m_trail_lim.pop_back(); - // not for lookahead // unretire clauses old_sz = m_retired_clause_lim.back(); for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { @@ -1008,11 +1067,16 @@ namespace sat { } m_retired_clauses.resize(old_sz); m_retired_clause_lim.pop_back(); + + old_sz = m_retired_ternary_lim.back(); + for (unsigned i = old_sz; i < m_retired_ternary.size(); ++i) { + attach_ternary(m_retired_ternary[i]); + } + m_retired_ternary.shrink(old_sz); + m_retired_ternary_lim.pop_back(); - // m_search_mode == searching // remove local binary clauses - old_sz = m_binary_trail_lim.back(); - + old_sz = m_binary_trail_lim.back(); for (unsigned i = m_binary_trail.size(); i > old_sz; ) { del_binary(m_binary_trail[--i]); } @@ -1024,11 +1088,39 @@ namespace sat { m_qhead_lim.pop_back(); } - void push_lookahead2(literal lit) { - + bool push_lookahead2(literal lit, unsigned level) { + scoped_level _sl(*this, level); + SASSERT(m_search_mode == lookahead_mode::lookahead1); + m_search_mode = lookahead_mode::lookahead2; + assign(lit); + propagate(); + bool unsat = inconsistent(); + SASSERT(m_search_mode == lookahead_mode::lookahead2); + m_search_mode = lookahead_mode::lookahead1; + m_inconsistent = false; + return unsat; } - void pop_lookahead2() { + void push_lookahead1(literal lit, unsigned level) { + SASSERT(m_search_mode == lookahead_mode::searching); + m_search_mode = lookahead_mode::lookahead1; + scoped_level _sl(*this, level); + assign(lit); + propagate(); + } + + void pop_lookahead1(literal lit) { + bool unsat = inconsistent(); + SASSERT(m_search_mode == lookahead_mode::lookahead1); + m_inconsistent = false; + m_search_mode = lookahead_mode::searching; + // convert windfalls to binary clauses. + if (!unsat) { + for (unsigned i = 0; i < m_wstack.size(); ++i) { + add_binary(lit, m_wstack[i]); + } + } + m_wstack.reset(); } @@ -1056,50 +1148,64 @@ namespace sat { UNREACHABLE(); break; case watched::TERNARY: { - UNREACHABLE(); // we avoid adding ternary clauses for now. literal l1 = it->get_literal1(); literal l2 = it->get_literal2(); + bool skip = false; if (is_fixed(l1)) { if (is_false(l1)) { if (is_undef(l2)) { - m_stats.m_propagations++; - assign(l2); + propagated(l2); } else if (is_false(l2)) { + TRACE("sat", tout << l1 << " " << l2 << " " << l << "\n";); set_conflict(); } } + else { + // retire this clause + } } else if (is_fixed(l2)) { if (is_false(l2)) { - m_stats.m_propagations++; - assign(l1); + propagated(l1); + } + else { + // retire this clause } } else { switch (m_search_mode) { - case searching: - detach_ternary(l, l1, l2); + case lookahead_mode::searching: + detach_ternary(~l, l1, l2); try_add_binary(l1, l2); + skip = true; break; - case lookahead1: + case lookahead_mode::lookahead1: m_weighted_new_binaries += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; break; case lookahead2: break; } } - *it2 = *it; - it2++; + if (!skip) { + *it2 = *it; + it2++; + } break; } case watched::CLAUSE: { clause_offset cls_off = it->get_clause_offset(); clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + if (is_true(it->get_blocked_literal())) { + *it2 = *it; + ++it2; + break; + } + if (c[0] == ~l) std::swap(c[0], c[1]); if (is_true(c[0])) { - it2->set_clause(c[0], cls_off); + *it2 = *it; it2++; break; } @@ -1112,6 +1218,7 @@ namespace sat { c[1] = *l_it; *l_it = ~l; m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); + TRACE("sat", tout << "move watch from " << l << " to " << c[1] << " for clause " << c << "\n";); } } if (found) { @@ -1123,30 +1230,40 @@ namespace sat { if (!found && is_undef(c[1]) && is_undef(c[0])) { TRACE("sat", tout << "got binary " << l << ": " << c << "\n";); switch (m_search_mode) { - case searching: + case lookahead_mode::searching: detach_clause(c); try_add_binary(c[0], c[1]); break; - case lookahead1: + case lookahead_mode::lookahead1: m_weighted_new_binaries += (*m_heur)[c[0].index()]* (*m_heur)[c[1].index()]; break; - case lookahead2: + case lookahead_mode::lookahead2: break; } } + else if (found && m_search_mode == lookahead_mode::lookahead1 && m_weighted_new_binaries == 0) { + // leave a trail that some clause was reduced but potentially not an autarky + l_it = c.begin() + 2; + found = false; + for (; l_it != l_end && !found; found = is_true(*l_it), ++l_it) ; + if (!found) { + m_weighted_new_binaries = (float)0.001; + } + } break; } if (is_false(c[0])) { TRACE("sat", tout << "conflict " << l << ": " << c << "\n";); set_conflict(); + *it2 = *it; + ++it2; } else { TRACE("sat", tout << "propagating " << l << ": " << c << "\n";); SASSERT(is_undef(c[0])); *it2 = *it; it2++; - m_stats.m_propagations++; - assign(c[0]); + propagated(c[0]); } break; } @@ -1176,10 +1293,11 @@ namespace sat { for (; m_qhead < m_trail.size(); ++m_qhead) { if (inconsistent()) break; literal l = m_trail[m_qhead]; + TRACE("sat", tout << "propagate " << l << "\n";); propagate_binary(l); propagate_clauses(l); } - TRACE("sat", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); + TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } literal choose() { @@ -1195,28 +1313,43 @@ namespace sat { } l = select_literal(); } + SASSERT(inconsistent() || !is_unsat()); return l; } void compute_wnb() { init_wnb(); TRACE("sat", display_lookahead(tout); ); - for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { - literal lit = m_lookahead[i].m_lit; - TRACE("sat", tout << "lookahead " << lit << "\n";); - reset_wnb(lit); - push_lookahead1(lit, 2 + m_lookahead[i].m_offset); - bool unsat = inconsistent(); - // TBD do_double(lit); - pop_lookahead1(); - update_wnb(lit); - if (unsat) { - TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); - reset_wnb(); - assign(~lit); - propagate(); - init_wnb(); + unsigned base = 2; + bool change = true; + while (change && !inconsistent()) { + change = false; + for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + if (is_fixed_at(lit, c_fixed_truth)) continue; + TRACE("sat", tout << "lookahead " << lit << "\n";); + reset_wnb(lit); + push_lookahead1(lit, base + m_lookahead[i].m_offset); + bool unsat = inconsistent(); + // TBD do_double(lit, base); + pop_lookahead1(lit); + if (unsat) { + TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); + reset_wnb(); + assign(~lit); + propagate(); + init_wnb(); + change = true; + } + else { + update_wnb(lit); + } + SASSERT(inconsistent() || !is_unsat()); } + if (c_fixed_truth - 2 * m_lookahead.size() < base) { + break; + } + base += 2 * m_lookahead.size(); } reset_wnb(); TRACE("sat", display_lookahead(tout); ); @@ -1258,23 +1391,11 @@ namespace sat { l = diff1 < diff2 ? lit : ~lit; } } +// if (count > 1) std::cout << count << "\n"; TRACE("sat", tout << "selected: " << l << "\n";); return l; } - void push_lookahead1(literal lit, unsigned level) { - m_search_modes.push_back(m_search_mode); - m_search_mode = lookahead1; - scoped_level _sl(*this, level); - assign(lit); - propagate(); - } - - void pop_lookahead1() { - m_inconsistent = false; - m_search_mode = m_search_modes.back(); - m_search_modes.pop_back(); - } void set_wnb(literal l, float f) { m_lits[l.index()].m_wnb = f; } void inc_wnb(literal l, float f) { m_lits[l.index()].m_wnb += f; } @@ -1289,8 +1410,35 @@ namespace sat { } void update_wnb(literal l) { - if (m_weighted_new_binaries == 0) { - // TBD autarky + if (false && m_weighted_new_binaries == 0) { + return; + // + // all consequences of l can be set to true. + // it is an autarky. + // copy the part of the trail that originates from l + // down to the trail that is associated with the + // current search scope. + // + unsigned index = m_trail.size(); + while (m_trail[--index] != l); + m_qhead = m_qhead_lim.back(); + unsigned old_sz = m_trail_lim.back(); + for (unsigned i = old_sz; i < m_trail.size(); ++i) { + set_undef(m_trail[i]); + } + m_qhead_lim.pop_back(); + for (unsigned i = index; i < m_trail.size(); ++i) { + l = m_trail[i]; + m_trail[old_sz - index + i] = l; + set_true(l); + m_freevars.remove(l.var()); + } + m_trail.shrink(old_sz + m_trail.size() - index); + TRACE("sat", tout << "autarky: " << m_trail << "\n";); + m_trail_lim.pop_back(); + propagate(); + SASSERT(!inconsistent()); + init_wnb(); } else { inc_wnb(l, m_weighted_new_binaries); @@ -1300,27 +1448,51 @@ namespace sat { bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; } void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } - void double_look() { - bool unsat; - for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { - literal lit = m_lookahead[i].m_lit; - if (!is_undef(lit)) continue; + bool is_fixed_at(literal lit, unsigned level) const { + return is_fixed(lit) && (!is_false(lit) || m_stamp[lit.var()] >= level); + } - push_lookahead2(lit); - unsat = inconsistent(); - pop_lookahead2(); - if (unsat) { - TRACE("sat", tout << "unit: " << ~lit << "\n";); - assign(~lit); - continue; + void double_look(literal l, unsigned& base) { + SASSERT(!inconsistent()); + SASSERT(base + 2 * m_lookahead.size() * static_cast(m_config.m_dl_max_iterations + 1) < c_fixed_truth); + unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); + m_level = dl_truth; + assign(l); + propagate(); + bool change = true; + unsigned num_iterations = 0; + while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { + change = false; + num_iterations++; + for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + if (is_fixed_at(lit, dl_truth)) continue; + if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { + TRACE("sat", tout << "unit: " << ~lit << "\n";); + SASSERT(m_level == dl_truth); + assign(~lit); + propagate(); + change = true; + } } + SASSERT(dl_truth - 2 * m_lookahead.size() > base); + base += 2*m_lookahead.size(); + } + SASSERT(m_level == dl_truth); + base = dl_truth; + } - push_lookahead2(~lit); - unsat = inconsistent(); - pop_lookahead2(); - if (unsat) { - TRACE("sat", tout << "unit: " << lit << "\n";); - assign(lit); + void do_double(literal l, unsigned& base) { + if (!inconsistent() && scope_lvl() > 0 && dl_enabled(l)) { + if (get_wnb(l) > m_delta_trigger) { + if (base + 2 * m_lookahead.size() * static_cast(m_config.m_dl_max_iterations + 1) < c_fixed_truth) { + double_look(l, base); + m_delta_trigger = get_wnb(l); + dl_disable(l); + } + } + else { + m_delta_trigger *= m_config.m_delta_rho; } } } @@ -1332,54 +1504,61 @@ namespace sat { unsigned scope_lvl() const { return m_trail_lim.size(); } void assign(literal l) { - TRACE("sat", tout << "assign: " << l << " := " << value(l) << " @ " << m_level << " "; display(tout, m_search_mode) << "\n";); SASSERT(m_level > 0); if (is_undef(l)) { + TRACE("sat", tout << "assign: " << l << " @ " << m_level << " " << m_trail_lim.size() << " " << m_search_mode << "\n";); set_true(l); m_trail.push_back(l); - if (m_search_mode == searching) { + if (m_search_mode == lookahead_mode::searching) { + m_stats.m_propagations++; TRACE("sat", tout << "removing free var v" << l.var() << "\n";); m_freevars.remove(l.var()); } } else if (is_false(l)) { + TRACE("sat", tout << "conflict: " << l << " @ " << m_level << " " << m_search_mode << "\n";); SASSERT(!is_true(l)); set_conflict(); } } - - void do_double(literal l) { - if (!inconsistent() && scope_lvl() > 0 && dl_enabled(l)) { - if (get_wnb(l) > m_delta_trigger) { - double_look(); - m_delta_trigger = get_wnb(l); - dl_disable(l); - } - else { - m_delta_trigger *= m_config.m_delta_rho; - } + void propagated(literal l) { + assign(l); + switch (m_search_mode) { + case lookahead_mode::searching: + break; + case lookahead_mode::lookahead1: + m_wstack.push_back(l); + break; + case lookahead_mode::lookahead2: + break; } } bool backtrack(literal_vector& trail) { - if (trail.empty()) return false; - pop(); - flip_prefix(); - assign(~trail.back()); - propagate(); - trail.pop_back(); + while (inconsistent()) { + if (trail.empty()) return false; + pop(); + flip_prefix(); + assign(~trail.back()); + trail.pop_back(); + propagate(); + } return true; } lbool search() { scoped_level _sl(*this, c_fixed_truth); literal_vector trail; - m_search_mode = searching; + m_search_mode = lookahead_mode::searching; while (true) { TRACE("sat", display(tout);); inc_istamp(); s.checkpoint(); + if (inconsistent()) { + if (!backtrack(trail)) return l_false; + continue; + } literal l = choose(); if (inconsistent()) { if (!backtrack(trail)) return l_false; @@ -1389,8 +1568,11 @@ namespace sat { return l_true; } TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); + ++m_stats.m_decisions; + IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(m_prefix, m_trail_lim.size()) << ": " << l << " " << m_trail.size() << "\n";); push(l, c_fixed_truth); trail.push_back(l); + SASSERT(inconsistent() || !is_unsat()); } } @@ -1414,7 +1596,7 @@ namespace sat { std::ostream& display_values(std::ostream& out) const { for (unsigned i = 0; i < m_trail.size(); ++i) { literal l = m_trail[i]; - out << l << " " << m_stamp[l.var()] << "\n"; + out << l << "\n"; } return out; } @@ -1437,8 +1619,9 @@ namespace sat { s(s), m_level(2), m_prefix(0) { - scoped_level _sl(*this, c_fixed_truth); - init(); + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); } ~lookahead() { @@ -1450,13 +1633,36 @@ namespace sat { } std::ostream& display(std::ostream& out) const { - out << std::hex << "Prefix: " << m_prefix << std::dec << "\n"; + out << "Prefix: " << pp_prefix(m_prefix, m_trail_lim.size()) << "\n"; out << "Level: " << m_level << "\n"; display_values(out); display_binary(out); display_clauses(out); + out << "free vars: "; + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + out << *it << " "; + } + out << "\n"; + for (unsigned i = 0; i < m_watches.size(); ++i) { + watch_list const& wl = m_watches[i]; + if (!wl.empty()) { + sat::display_watch_list(out << to_literal(i) << " -> ", m_cls_allocator, wl); + out << "\n"; + } + } return out; } + + void collect_statistics(statistics& st) const { + st.update("bool var", m_vprefix.size()); + st.update("clauses", m_clauses.size()); + st.update("add binary", m_stats.m_add_binary); + st.update("del binary", m_stats.m_del_binary); + st.update("add ternary", m_stats.m_add_ternary); + st.update("del ternary", m_stats.m_del_ternary); + st.update("propagations", m_stats.m_propagations); + st.update("decisions", m_stats.m_decisions); + } }; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 10f427fa1..fe019427f 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1256,8 +1256,8 @@ namespace sat { } CTRACE("resolve_bug", it2 == end2, tout << ~l1 << " -> "; - display(tout, s.m_cls_allocator, wlist1); tout << "\n" << ~l2 << " -> "; - display(tout, s.m_cls_allocator, wlist2); tout << "\n";); + display_watch_list(tout, s.m_cls_allocator, wlist1); tout << "\n" << ~l2 << " -> "; + display_watch_list(tout, s.m_cls_allocator, wlist2); tout << "\n";); SASSERT(it2 != end2); return; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index bddf551df..66ebb189f 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2998,7 +2998,7 @@ namespace sat { watch_list const & wlist = *it; literal l = to_literal(l_idx); out << l << ": "; - sat::display(out, m_cls_allocator, wlist); + sat::display_watch_list(out, m_cls_allocator, wlist); out << "\n"; } } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 74354a999..d7578ea84 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -104,7 +104,7 @@ namespace sat { inline bool operator==(literal const & l1, literal const & l2) { return l1.m_val == l2.m_val; } inline bool operator!=(literal const & l1, literal const & l2) { return l1.m_val != l2.m_val; } - inline std::ostream & operator<<(std::ostream & out, literal l) { out << (l.sign() ? "-" : "") << l.var(); return out; } + inline std::ostream & operator<<(std::ostream & out, literal l) { if (l == null_literal) out << "null"; else out << (l.sign() ? "-" : "") << l.var(); return out; } typedef svector literal_vector; typedef std::pair literal_pair; diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index cc442571c..b00f17c38 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -39,7 +39,7 @@ namespace sat { return false; } - void display(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) { + void display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) { watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); for (bool first = true; it != end; ++it) { diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 2c48b6c9b..03eaf2798 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -130,7 +130,7 @@ namespace sat { inline void erase_ternary_watch(watch_list & wlist, literal l1, literal l2) { wlist.erase(watched(l1, l2)); } class clause_allocator; - void display(std::ostream & out, clause_allocator const & ca, watch_list const & wlist); + void display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist); }; #endif diff --git a/src/test/main.cpp b/src/test/main.cpp index 6e7b60152..dd705de4b 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -7,7 +7,8 @@ #include"debug.h" #include"timeit.h" #include"warning.h" -#include "memory_manager.h" +#include"memory_manager.h" +#include"gparams.h" // // Unit tests fail by asserting. @@ -81,6 +82,7 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& t char * opt_name = arg + 1; char * opt_arg = 0; char * colon = strchr(arg, ':'); + char * eq_pos = 0; if (colon) { opt_arg = colon + 1; *colon = 0; @@ -117,6 +119,12 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& t enable_debug(opt_arg); } #endif + else if (arg[0] != '"' && (eq_pos = strchr(arg, '='))) { + char * key = arg; + *eq_pos = 0; + char * value = eq_pos+1; + gparams::set(key, value); + } } i++; } diff --git a/src/test/sat_lookahead.cpp b/src/test/sat_lookahead.cpp index dc62d832b..94a02bc7f 100644 --- a/src/test/sat_lookahead.cpp +++ b/src/test/sat_lookahead.cpp @@ -1,4 +1,6 @@ #include "sat_solver.h" +#include "sat_watched.h" +#include "statistics.h" #include "sat_lookahead.h" #include "dimacs.h" @@ -7,7 +9,7 @@ void tst_sat_lookahead(char ** argv, int argc, int& i) { std::cout << "require dimacs file name\n"; return; } - enable_trace("sat"); +// enable_trace("sat"); reslimit limit; params_ref params; sat::solver solver(params, limit); @@ -28,4 +30,8 @@ void tst_sat_lookahead(char ** argv, int argc, int& i) { IF_VERBOSE(20, solver.display_status(verbose_stream());); std::cout << lh.check() << "\n"; + + statistics st; + lh.collect_statistics(st); + st.display(std::cout); } From 6571aad4408c47b657d7f99e343c4d7ab82da771 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Mar 2017 07:21:59 -0700 Subject: [PATCH 0097/1283] debugging double lookahead and autarkies Signed-off-by: Nikolaj Bjorner --- src/sat/sat_integrity_checker.cpp | 2 +- src/sat/sat_lookahead.h | 249 +++++++++++++++++++----------- src/test/sat_lookahead.cpp | 18 ++- 3 files changed, 179 insertions(+), 90 deletions(-) diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index 27958785d..866dcb72d 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -96,7 +96,7 @@ namespace sat { } // the first two literals must be watched. - VERIFY(contains_watched(s.get_wlist(~c[0]), c, s.get_offset(c))); + VERIFY(contains_watched(s.get_wlist(~c[0]), c, s.get_offset(c))); VERIFY(contains_watched(s.get_wlist(~c[1]), c, s.get_offset(c))); } return true; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 167de1bab..ac985c23c 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -96,6 +96,11 @@ namespace sat { unsigned m_add_ternary; unsigned m_del_ternary; unsigned m_decisions; + unsigned m_windfall_binaries; + unsigned m_autarky_propagations; + unsigned m_autarky_equivalences; + unsigned m_double_lookahead_propagations; + unsigned m_double_lookahead_rounds; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -133,6 +138,7 @@ namespace sat { const unsigned c_fixed_truth = UINT_MAX - 1; vector m_watches; // literal: watch structure svector m_lits; // literal: attributes. + vector m_full_watches; // literal: full watch list, used to ensure that autarky reduction is sound float m_weighted_new_binaries; // metric associated with current lookahead1 literal. literal_vector m_wstack; // windofall stack that is populated in lookahead1 mode uint64 m_prefix; // where we are in search tree @@ -140,6 +146,7 @@ namespace sat { indexed_uint_set m_freevars; lookahead_mode m_search_mode; // mode of search stats m_stats; + model m_model; // --------------------------------------- // truth values @@ -151,6 +158,7 @@ namespace sat { inline bool is_true(literal l) const { return is_fixed(l) && !(bool)((m_stamp[l.var()] & 0x1) ^ l.sign()); } inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } inline void set_undef(literal l) { m_stamp[l.var()] = 0; } + void set_level(literal d, literal s) { m_stamp[d.var()] = (m_stamp[s.var()] & ~0x1) + d.sign(); } lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; } // set the level within a scope of the search. @@ -167,9 +175,8 @@ namespace sat { } }; - // ---------------------------------------- - // prefix updates. I use low order bits and - // skip bit 0 in a bid to reduce details. + // ------------------------------------- + // prefix updates. I use low order bits. void flip_prefix() { if (m_trail_lim.size() < 64) { @@ -184,12 +191,17 @@ namespace sat { } } + /** + length < trail_lim.size: + - mask m_prefix and p wrt length + - update if different. + */ void update_prefix(literal l) { bool_var x = l.var(); - - unsigned p = m_vprefix[x].m_prefix; - if (m_vprefix[x].m_length >= m_trail_lim.size() || - ((p | m_prefix) != m_prefix)) { + unsigned p = m_vprefix[x].m_prefix; + unsigned pl = m_vprefix[x].m_length; + unsigned mask = (1 << std::min(31u, pl)) - 1; + if (pl >= m_trail_lim.size() || (p & mask) != (m_prefix & mask)) { m_vprefix[x].m_length = m_trail_lim.size(); m_vprefix[x].m_prefix = static_cast(m_prefix); } @@ -201,7 +213,7 @@ namespace sat { unsigned l = m_vprefix[x].m_length; if (l > lvl) return false; if (l == lvl || l >= 31) return m_prefix == p; - unsigned mask = ((1 << l) - 1); + unsigned mask = ((1 << std::min(l,31u)) - 1); return (m_prefix & mask) == (p & mask); } @@ -604,8 +616,9 @@ namespace sat { vector m_dfs; void get_scc() { + unsigned num_candidates = m_candidates.size(); init_scc(); - for (unsigned i = 0; i < m_candidates.size() && !inconsistent(); ++i) { + for (unsigned i = 0; i < num_candidates && !inconsistent(); ++i) { literal lit(m_candidates[i].m_var, false); if (get_rank(lit) == 0) get_scc(lit); if (get_rank(~lit) == 0) get_scc(~lit); @@ -624,7 +637,6 @@ namespace sat { init_arcs(lit); init_arcs(~lit); } - // set nextp = 0? m_rank = 0; m_active = null_literal; m_settled = null_literal; @@ -664,7 +676,7 @@ namespace sat { void set_min(literal v, literal u) { m_dfs[v.index()].m_min = u; } void set_rank(literal v, unsigned r) { m_dfs[v.index()].m_rank = r; } void set_height(literal v, unsigned h) { m_dfs[v.index()].m_height = h; } - void set_parent(literal v, literal p) { m_dfs[v.index()].m_parent = p; } + void set_parent(literal v, literal p) { TRACE("sat", tout << v << " <- " << p << "\n";); m_dfs[v.index()].m_parent = p; } void set_vcomp(literal v, literal u) { m_dfs[v.index()].m_vcomp = u; } void get_scc(literal v) { set_parent(v, null_literal); @@ -846,7 +858,7 @@ namespace sat { } } TRACE("sat", - display_forest(tout, get_child(null_literal)); + display_forest(tout << "forest: ", get_child(null_literal)); tout << "\n"; display_scc(tout); ); } @@ -879,7 +891,7 @@ namespace sat { literal u = get_child(null_literal), v = null_literal; unsigned offset = 0; SASSERT(m_lookahead.empty()); - while (u != null_literal) { + while (u != null_literal) { set_rank(u, m_lookahead.size()); set_lookahead(get_vcomp(u)); if (null_literal != get_child(u)) { @@ -970,6 +982,8 @@ namespace sat { m_binary.push_back(literal_vector()); m_watches.push_back(watch_list()); m_watches.push_back(watch_list()); + m_full_watches.push_back(clause_vector()); + m_full_watches.push_back(clause_vector()); m_bstamp.push_back(0); m_bstamp.push_back(0); m_stamp.push_back(0); @@ -1017,6 +1031,9 @@ namespace sat { clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); m_clauses.push_back(c1); attach_clause(*c1); + for (unsigned i = 0; i < c.size(); ++i) { + m_full_watches[(~c[i]).index()].push_back(c1); + } } // copy units @@ -1117,11 +1134,13 @@ namespace sat { // convert windfalls to binary clauses. if (!unsat) { for (unsigned i = 0; i < m_wstack.size(); ++i) { - add_binary(lit, m_wstack[i]); + ++m_stats.m_windfall_binaries; + //update_prefix(~lit); + //update_prefix(m_wstack[i]); + add_binary(~lit, m_wstack[i]); } } m_wstack.reset(); - } float mix_diff(float l, float r) const { return l + r + (1 << 10) * l * r; } @@ -1218,7 +1237,7 @@ namespace sat { c[1] = *l_it; *l_it = ~l; m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); - TRACE("sat", tout << "move watch from " << l << " to " << c[1] << " for clause " << c << "\n";); + TRACE("sat_verbose", tout << "move watch from " << l << " to " << c[1] << " for clause " << c << "\n";); } } if (found) { @@ -1283,6 +1302,7 @@ namespace sat { void propagate_binary(literal l) { literal_vector const& lits = m_binary[l.index()]; + TRACE("sat", tout << l << " => " << lits << "\n";); unsigned sz = lits.size(); for (unsigned i = 0; !inconsistent() && i < sz; ++i) { assign(lits[i]); @@ -1327,11 +1347,15 @@ namespace sat { for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; if (is_fixed_at(lit, c_fixed_truth)) continue; - TRACE("sat", tout << "lookahead " << lit << "\n";); + unsigned level = base + m_lookahead[i].m_offset; + if (m_stamp[lit.var()] >= level) { + continue; + } + TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); reset_wnb(lit); - push_lookahead1(lit, base + m_lookahead[i].m_offset); - bool unsat = inconsistent(); - // TBD do_double(lit, base); + push_lookahead1(lit, level); + do_double(lit, base); + bool unsat = inconsistent(); pop_lookahead1(lit); if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); @@ -1342,7 +1366,7 @@ namespace sat { change = true; } else { - update_wnb(lit); + update_wnb(lit, level); } SASSERT(inconsistent() || !is_unsat()); } @@ -1409,36 +1433,48 @@ namespace sat { set_wnb(l, p == null_literal ? 0 : get_wnb(p)); } - void update_wnb(literal l) { - if (false && m_weighted_new_binaries == 0) { - return; - // - // all consequences of l can be set to true. - // it is an autarky. - // copy the part of the trail that originates from l - // down to the trail that is associated with the - // current search scope. - // - unsigned index = m_trail.size(); - while (m_trail[--index] != l); - m_qhead = m_qhead_lim.back(); - unsigned old_sz = m_trail_lim.back(); - for (unsigned i = old_sz; i < m_trail.size(); ++i) { - set_undef(m_trail[i]); + void update_wnb(literal l, unsigned level) { + if (m_weighted_new_binaries == 0) { + { + scoped_level _sl(*this, level); + clause_vector::const_iterator it = m_full_watches[l.index()].begin(), end = m_full_watches[l.index()].end(); + for (; it != end; ++it) { + clause& c = *(*it); + unsigned sz = c.size(); + bool found = false; + + for (unsigned i = 0; !found && i < sz; ++i) { + found = is_true(c[i]); + } + IF_VERBOSE(2, verbose_stream() << "skip autarky\n";); + if (!found) return; + } } - m_qhead_lim.pop_back(); - for (unsigned i = index; i < m_trail.size(); ++i) { - l = m_trail[i]; - m_trail[old_sz - index + i] = l; - set_true(l); - m_freevars.remove(l.var()); + if (get_wnb(l) == 0) { + ++m_stats.m_autarky_propagations; + IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); + TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] << "\n";); + reset_wnb(); + assign(l); + propagate(); + init_wnb(); + } + else { + ++m_stats.m_autarky_equivalences; + // l => p is known, but p => l is possibly not. + // add p => l. + // justification: any consequence of l + // that is not a consequence of p does not + // reduce the clauses. + literal p = get_parent(l); + SASSERT(p != null_literal); + if (m_stamp[p.var()] > m_stamp[l.var()]) { + TRACE("sat", tout << "equivalence " << l << " == " << p << "\n"; display(tout);); + IF_VERBOSE(1, verbose_stream() << "(sat.lookahead equivalence " << l << " == " << p << ")\n";); + add_binary(~l, p); + set_level(l, p); + } } - m_trail.shrink(old_sz + m_trail.size() - index); - TRACE("sat", tout << "autarky: " << m_trail << "\n";); - m_trail_lim.pop_back(); - propagate(); - SASSERT(!inconsistent()); - init_wnb(); } else { inc_wnb(l, m_weighted_new_binaries); @@ -1447,45 +1483,17 @@ namespace sat { bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; } void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } + bool dl_no_overflow(unsigned base) const { return base + 2 * m_lookahead.size() * static_cast(m_config.m_dl_max_iterations + 1) < c_fixed_truth; } bool is_fixed_at(literal lit, unsigned level) const { return is_fixed(lit) && (!is_false(lit) || m_stamp[lit.var()] >= level); } - void double_look(literal l, unsigned& base) { - SASSERT(!inconsistent()); - SASSERT(base + 2 * m_lookahead.size() * static_cast(m_config.m_dl_max_iterations + 1) < c_fixed_truth); - unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); - m_level = dl_truth; - assign(l); - propagate(); - bool change = true; - unsigned num_iterations = 0; - while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { - change = false; - num_iterations++; - for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { - literal lit = m_lookahead[i].m_lit; - if (is_fixed_at(lit, dl_truth)) continue; - if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { - TRACE("sat", tout << "unit: " << ~lit << "\n";); - SASSERT(m_level == dl_truth); - assign(~lit); - propagate(); - change = true; - } - } - SASSERT(dl_truth - 2 * m_lookahead.size() > base); - base += 2*m_lookahead.size(); - } - SASSERT(m_level == dl_truth); - base = dl_truth; - } - void do_double(literal l, unsigned& base) { if (!inconsistent() && scope_lvl() > 0 && dl_enabled(l)) { if (get_wnb(l) > m_delta_trigger) { - if (base + 2 * m_lookahead.size() * static_cast(m_config.m_dl_max_iterations + 1) < c_fixed_truth) { + if (dl_no_overflow(base)) { + ++m_stats.m_double_lookahead_rounds; double_look(l, base); m_delta_trigger = get_wnb(l); dl_disable(l); @@ -1497,6 +1505,40 @@ namespace sat { } } + void double_look(literal l, unsigned& base) { + SASSERT(!inconsistent()); + SASSERT(dl_no_overflow(base)); + unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); + scoped_level _sl(*this, dl_truth); + assign(l); + propagate(); + bool change = true; + unsigned num_iterations = 0; + init_wnb(); + while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { + change = false; + num_iterations++; + for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + if (is_fixed_at(lit, dl_truth)) continue; + if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { + TRACE("sat", tout << "unit: " << ~lit << "\n";); + ++m_stats.m_double_lookahead_propagations; + SASSERT(m_level == dl_truth); + reset_wnb(); + assign(~lit); + propagate(); + change = true; + init_wnb(); + } + } + SASSERT(dl_truth - 2 * m_lookahead.size() > base); + base += 2*m_lookahead.size(); + } + reset_wnb(); + SASSERT(m_level == dl_truth); + base = dl_truth; + } void set_conflict() { TRACE("sat", tout << "conflict\n";); m_inconsistent = true; } bool inconsistent() { return m_inconsistent; } @@ -1548,6 +1590,7 @@ namespace sat { } lbool search() { + m_model.reset(); scoped_level _sl(*this, c_fixed_truth); literal_vector trail; m_search_mode = lookahead_mode::searching; @@ -1576,6 +1619,24 @@ namespace sat { } } + void init_model() { + m_model.reset(); + for (unsigned i = 0; i < s.num_vars(); ++i) { + lbool val; + literal lit(i, false); + if (is_undef(lit)) { + val = l_undef; + } + if (is_true(lit)) { + val = l_true; + } + else { + val = l_false; + } + m_model.push_back(val); + } + } + std::ostream& display_binary(std::ostream& out) const { for (unsigned i = 0; i < m_binary.size(); ++i) { literal_vector const& lits = m_binary[i]; @@ -1653,15 +1714,27 @@ namespace sat { return out; } + model const& get_model() { + if (m_model.empty()) { + init_model(); + } + return m_model; + } + void collect_statistics(statistics& st) const { - st.update("bool var", m_vprefix.size()); - st.update("clauses", m_clauses.size()); - st.update("add binary", m_stats.m_add_binary); - st.update("del binary", m_stats.m_del_binary); - st.update("add ternary", m_stats.m_add_ternary); - st.update("del ternary", m_stats.m_del_ternary); - st.update("propagations", m_stats.m_propagations); - st.update("decisions", m_stats.m_decisions); + st.update("lh bool var", m_vprefix.size()); + st.update("lh clauses", m_clauses.size()); + st.update("lh add binary", m_stats.m_add_binary); + st.update("lh del binary", m_stats.m_del_binary); + st.update("lh add ternary", m_stats.m_add_ternary); + st.update("lh del ternary", m_stats.m_del_ternary); + st.update("lh propagations", m_stats.m_propagations); + st.update("lh decisions", m_stats.m_decisions); + st.update("lh windfalls", m_stats.m_windfall_binaries); + st.update("lh autarky propagations", m_stats.m_autarky_propagations); + st.update("lh autarky equivalences", m_stats.m_autarky_equivalences); + st.update("lh double lookahead propagations", m_stats.m_double_lookahead_propagations); + st.update("lh double lookahead rounds", m_stats.m_double_lookahead_rounds); } }; diff --git a/src/test/sat_lookahead.cpp b/src/test/sat_lookahead.cpp index 94a02bc7f..b02af0b04 100644 --- a/src/test/sat_lookahead.cpp +++ b/src/test/sat_lookahead.cpp @@ -4,6 +4,18 @@ #include "sat_lookahead.h" #include "dimacs.h" +static void display_model(sat::model const & m) { + for (unsigned i = 1; i < m.size(); i++) { + switch (m[i]) { + case l_false: std::cout << "-" << i << " "; break; + case l_undef: break; + case l_true: std::cout << i << " "; break; + } + } + std::cout << "\n"; +} + + void tst_sat_lookahead(char ** argv, int argc, int& i) { if (argc != i + 2) { std::cout << "require dimacs file name\n"; @@ -29,9 +41,13 @@ void tst_sat_lookahead(char ** argv, int argc, int& i) { IF_VERBOSE(20, solver.display_status(verbose_stream());); - std::cout << lh.check() << "\n"; + lbool is_sat = lh.check(); + std::cout << is_sat << "\n"; statistics st; lh.collect_statistics(st); st.display(std::cout); + if (is_sat == l_true) { + display_model(lh.get_model()); + } } From c0188a7ec032c6105ae383c557d85b7d5dc9add9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Mar 2017 13:16:04 -0700 Subject: [PATCH 0098/1283] fix autarky detection Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 31 +++++++++++++-- src/sat/sat_local_search.h | 7 ++++ src/sat/sat_lookahead.h | 75 +++++++++++++++++++++++++----------- 3 files changed, 87 insertions(+), 26 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 92173ff4b..c9a947712 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -137,6 +137,17 @@ namespace sat { } void local_search::reinit() { + // the following methods does NOT converge for pseudo-boolean + // can try other way to define "worse" and "better" + // the current best noise is below 1000 + if (best_unsat_rate >= last_best_unsat_rate) { + // worse + noise = noise - noise * 2 * noise_delta; + } + else { + // better + noise = noise + (10000 - noise) * noise_delta; + } for (unsigned i = 0; i < m_constraints.size(); ++i) { constraint& c = m_constraints[i]; c.m_slack = c.m_k; @@ -370,11 +381,16 @@ namespace sat { if (tries % 10 == 0 || m_unsat_stack.empty()) { \ IF_VERBOSE(1, verbose_stream() << "(sat-local-search" \ << " :flips " << flips \ - << " :unsat " << m_unsat_stack.size() \ + << " :noise " << noise \ + << " :unsat " << /*m_unsat_stack.size()*/ best_unsat \ << " :time " << (timer.get_seconds() < 0.001 ? 0.0 : timer.get_seconds()) << ")\n";); \ } void local_search::walksat() { + best_unsat_rate = 1; + last_best_unsat_rate = 1; + + reinit(); timer timer; timer.start(); @@ -382,12 +398,17 @@ namespace sat { PROGRESS(tries, total_flips); for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { + if (m_unsat_stack.size() < best_unsat) { + best_unsat = m_unsat_stack.size(); + last_best_unsat_rate = best_unsat_rate; + best_unsat_rate = (double)m_unsat_stack.size() / num_constraints(); + } for (step = 0; step < m_max_steps && !m_unsat_stack.empty(); ++step) { pick_flip_walksat(); } total_flips += step; PROGRESS(tries, total_flips); - if (m_par && tries % 30 == 0) { + if (m_par && tries % 20 == 0) { m_par->get_phase(*this); reinit(); } @@ -483,7 +504,9 @@ namespace sat { unsigned num_unsat = m_unsat_stack.size(); constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; SASSERT(c.m_k < constraint_value(c)); - if (m_rand() % 100 < 98) { + // TBD: dynamic noise strategy + //if (m_rand() % 100 < 98) { + if (m_rand() % 10000 >= noise) { // take this branch with 98% probability. // find the first one, to fast break the rest unsigned best_bsb = 0; @@ -533,7 +556,7 @@ namespace sat { best_var = v; n = 1; } - else {// if (bb == best_bb) + else {// if (bsb == best_bb) ++n; if (m_rand() % n == 0) { best_var = v; diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 108df4e6d..7fb5396fe 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -164,6 +164,9 @@ namespace sat { // information about solution + unsigned best_unsat; + double best_unsat_rate; + double last_best_unsat_rate; int m_objective_value; // the objective function value corresponds to the current solution bool_vector m_best_solution; // !var: the best solution so far int m_best_objective_value = -1; // the objective value corresponds to the best solution so far @@ -172,6 +175,10 @@ namespace sat { unsigned m_max_steps = (1 << 30); + // dynamic noise + unsigned noise = 400; // normalized by 10000 + double noise_delta = 0.05; + // for tuning int s_id = 0; // strategy id diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index ac985c23c..fa9fea724 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -220,7 +220,7 @@ namespace sat { // ---------------------------------------- void add_binary(literal l1, literal l2) { - TRACE("sat", tout << "binary: " << l1 << " " << l2 << "\n";); + TRACE("sat", tout << "binary: " << l1 << " " << l2 << "\n";); SASSERT(l1 != l2); // don't add tautologies and don't add already added binaries if (~l1 == l2) return; @@ -375,7 +375,7 @@ namespace sat { progress = false; float mean = sum / (float)(m_candidates.size() + 0.0001); sum = 0; - for (unsigned i = 0; i < m_candidates.size(); ++i) { + for (unsigned i = 0; i < m_candidates.size() && m_candidates.size() >= max_num_cand * 2; ++i) { if (m_candidates[i].m_rating >= mean) { sum += m_candidates[i].m_rating; } @@ -1133,11 +1133,14 @@ namespace sat { m_search_mode = lookahead_mode::searching; // convert windfalls to binary clauses. if (!unsat) { + literal nlit = ~lit; for (unsigned i = 0; i < m_wstack.size(); ++i) { ++m_stats.m_windfall_binaries; + literal l2 = m_wstack[i]; //update_prefix(~lit); //update_prefix(m_wstack[i]); - add_binary(~lit, m_wstack[i]); + TRACE("sat", tout << "windfall: " << nlit << " " << l2 << "\n";); + add_binary(nlit, l2); } } m_wstack.reset(); @@ -1280,6 +1283,9 @@ namespace sat { else { TRACE("sat", tout << "propagating " << l << ": " << c << "\n";); SASSERT(is_undef(c[0])); + DEBUG_CODE(for (unsigned i = 2; i < c.size(); ++i) { + SASSERT(is_false(c[i])); + }); *it2 = *it; it2++; propagated(c[0]); @@ -1354,7 +1360,7 @@ namespace sat { TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); reset_wnb(lit); push_lookahead1(lit, level); - do_double(lit, base); + //do_double(lit, base); bool unsat = inconsistent(); pop_lookahead1(lit); if (unsat) { @@ -1433,30 +1439,55 @@ namespace sat { set_wnb(l, p == null_literal ? 0 : get_wnb(p)); } - void update_wnb(literal l, unsigned level) { - if (m_weighted_new_binaries == 0) { - { - scoped_level _sl(*this, level); - clause_vector::const_iterator it = m_full_watches[l.index()].begin(), end = m_full_watches[l.index()].end(); - for (; it != end; ++it) { - clause& c = *(*it); - unsigned sz = c.size(); - bool found = false; - - for (unsigned i = 0; !found && i < sz; ++i) { - found = is_true(c[i]); - } - IF_VERBOSE(2, verbose_stream() << "skip autarky\n";); - if (!found) return; + bool check_autarky(literal l, unsigned level) { + // no propagations are allowed to reduce clauses. + clause_vector::const_iterator it = m_full_watches[l.index()].begin(); + clause_vector::const_iterator end = m_full_watches[l.index()].end(); + for (; it != end; ++it) { + clause& c = *(*it); + unsigned sz = c.size(); + bool found = false; + for (unsigned i = 0; !found && i < sz; ++i) { + found = is_true(c[i]); + if (found) { + TRACE("sat", tout << c[i] << " is true in " << c << "\n";); } } - if (get_wnb(l) == 0) { + IF_VERBOSE(2, verbose_stream() << "skip autarky " << l << "\n";); + if (!found) return false; + } + // + // bail out if there is a pending binary propagation. + // In general, we would have to check, recursively that + // a binary propagation does not create reduced clauses. + // + literal_vector const& lits = m_binary[l.index()]; + TRACE("sat", tout << l << ": " << lits << "\n";); + for (unsigned i = 0; i < lits.size(); ++i) { + literal l2 = lits[i]; + if (is_true(l2)) continue; + SASSERT(!is_false(l2)); + return false; + } + + return true; + } + + void update_wnb(literal l, unsigned level) { + if (m_weighted_new_binaries == 0) { + if (!check_autarky(l, level)) { + // skip + } + else if (get_wnb(l) == 0) { ++m_stats.m_autarky_propagations; IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); - TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] << "\n";); + + TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] + << " " + << (!m_binary[l.index()].empty() || !m_full_watches[l.index()].empty()) << "\n";); reset_wnb(); assign(l); - propagate(); + propagate(); init_wnb(); } else { From b70096a97f82ad638e25472ea5e7a0d877d639dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Mar 2017 17:22:44 -0700 Subject: [PATCH 0099/1283] testing double lookahead Signed-off-by: Nikolaj Bjorner --- src/sat/sat_drat.cpp | 17 +++++++++++++++ src/sat/sat_drat.h | 2 ++ src/sat/sat_local_search.cpp | 8 +++---- src/sat/sat_local_search.h | 4 ++-- src/sat/sat_lookahead.h | 42 ++++++++++++++++++++++++++++++++---- src/test/main.cpp | 18 ++++++++++------ 6 files changed, 75 insertions(+), 16 deletions(-) diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index ba4173eed..0f1b578f1 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -449,6 +449,23 @@ namespace sat { } } } + void drat::add(literal_vector const& c) { + for (unsigned i = 0; i < c.size(); ++i) declare(c[i]); + if (m_out) dump(c.size(), c.begin(), status::learned); + if (s.m_config.m_drat_check) { + switch (c.size()) { + case 0: add(); break; + case 1: append(c[0], status::learned); break; + default: { + verify(c.size(), c.begin()); + clause* cl = s.m_cls_allocator.mk_clause(c.size(), c.c_ptr(), true); + append(*cl, status::external); + break; + } + } + } + } + void drat::del(literal l) { if (m_out) dump(1, &l, status::deleted); if (s.m_config.m_drat_check) append(l, status::deleted); diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index e9663628b..2765d104c 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -57,6 +57,7 @@ namespace sat { void append(literal l, status st); void append(literal l1, literal l2, status st); void append(clause& c, status st); + friend std::ostream& operator<<(std::ostream & out, status st); status get_status(bool learned) const; @@ -82,6 +83,7 @@ namespace sat { void add(literal l1, literal l2, bool learned); void add(clause& c, bool learned); void add(literal_vector const& c, svector const& premises); + void add(literal_vector const& c); // add learned clause bool is_cleaned(clause& c) const; void del(literal l); diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index c9a947712..6b0205cc2 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -142,11 +142,11 @@ namespace sat { // the current best noise is below 1000 if (best_unsat_rate >= last_best_unsat_rate) { // worse - noise = noise - noise * 2 * noise_delta; + m_noise -= m_noise * 2 * m_noise_delta; } else { // better - noise = noise + (10000 - noise) * noise_delta; + m_noise += (10000 - m_noise) * m_noise_delta; } for (unsigned i = 0; i < m_constraints.size(); ++i) { constraint& c = m_constraints[i]; @@ -381,7 +381,7 @@ namespace sat { if (tries % 10 == 0 || m_unsat_stack.empty()) { \ IF_VERBOSE(1, verbose_stream() << "(sat-local-search" \ << " :flips " << flips \ - << " :noise " << noise \ + << " :noise " << m_noise \ << " :unsat " << /*m_unsat_stack.size()*/ best_unsat \ << " :time " << (timer.get_seconds() < 0.001 ? 0.0 : timer.get_seconds()) << ")\n";); \ } @@ -506,7 +506,7 @@ namespace sat { SASSERT(c.m_k < constraint_value(c)); // TBD: dynamic noise strategy //if (m_rand() % 100 < 98) { - if (m_rand() % 10000 >= noise) { + if (m_rand() % 10000 >= m_noise) { // take this branch with 98% probability. // find the first one, to fast break the rest unsigned best_bsb = 0; diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 7fb5396fe..678eee60a 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -176,8 +176,8 @@ namespace sat { unsigned m_max_steps = (1 << 30); // dynamic noise - unsigned noise = 400; // normalized by 10000 - double noise_delta = 0.05; + double m_noise = 400; // normalized by 10000 + double m_noise_delta = 0.05; // for tuning int s_id = 0; // strategy id diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index fa9fea724..3344e82e1 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -113,6 +113,9 @@ namespace sat { config m_config; double m_delta_trigger; + drat m_drat; + literal_vector m_assumptions; + literal_vector m_trail; // trail of units unsigned_vector m_trail_lim; vector m_binary; // literal: binary clauses @@ -229,6 +232,7 @@ namespace sat { m_binary[(~l2).index()].push_back(l1); m_binary_trail.push_back((~l1).index()); ++m_stats.m_add_binary; + if (s.m_config.m_drat) validate_binary(l1, l2); } void del_binary(unsigned idx) { @@ -240,6 +244,17 @@ namespace sat { ++m_stats.m_del_binary; } + + void validate_binary(literal l1, literal l2) { + if (m_search_mode == lookahead_mode::searching) { + m_assumptions.push_back(l1); + m_assumptions.push_back(l2); + m_drat.add(m_assumptions); + m_assumptions.pop_back(); + m_assumptions.pop_back(); + } + } + // ------------------------------------- // track consequences of binary clauses // see also 72 - 79 in sat11.w @@ -1034,14 +1049,18 @@ namespace sat { for (unsigned i = 0; i < c.size(); ++i) { m_full_watches[(~c[i]).index()].push_back(c1); } + if (s.m_config.m_drat) m_drat.add(c, false); } // copy units unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { literal l = s.m_trail[i]; + if (s.m_config.m_drat) m_drat.add(l, false); assign(l); } + propagate(); + m_qhead = m_trail.size(); TRACE("sat", s.display(tout); display(tout);); } @@ -1056,11 +1075,13 @@ namespace sat { m_retired_ternary_lim.push_back(m_retired_ternary.size()); m_qhead_lim.push_back(m_qhead); scoped_level _sl(*this, level); + m_assumptions.push_back(~lit); assign(lit); propagate(); } void pop() { + m_assumptions.pop_back(); m_inconsistent = false; SASSERT(m_search_mode == lookahead_mode::searching); @@ -1319,7 +1340,7 @@ namespace sat { for (; m_qhead < m_trail.size(); ++m_qhead) { if (inconsistent()) break; literal l = m_trail[m_qhead]; - TRACE("sat", tout << "propagate " << l << "\n";); + TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); propagate_binary(l); propagate_clauses(l); } @@ -1360,7 +1381,7 @@ namespace sat { TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); reset_wnb(lit); push_lookahead1(lit, level); - //do_double(lit, base); + do_double(lit, base); bool unsat = inconsistent(); pop_lookahead1(lit); if (unsat) { @@ -1386,12 +1407,14 @@ namespace sat { } void init_wnb() { + TRACE("sat", tout << "init_wnb: " << m_qhead << "\n";); m_qhead_lim.push_back(m_qhead); m_trail_lim.push_back(m_trail.size()); } void reset_wnb() { m_qhead = m_qhead_lim.back(); + TRACE("sat", tout << "reset_wnb: " << m_qhead << "\n";); unsigned old_sz = m_trail_lim.back(); for (unsigned i = old_sz; i < m_trail.size(); ++i) { set_undef(m_trail[i]); @@ -1541,14 +1564,15 @@ namespace sat { SASSERT(dl_no_overflow(base)); unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); scoped_level _sl(*this, dl_truth); + init_wnb(); assign(l); propagate(); bool change = true; unsigned num_iterations = 0; - init_wnb(); while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { change = false; num_iterations++; + base += 2*m_lookahead.size(); for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; if (is_fixed_at(lit, dl_truth)) continue; @@ -1564,7 +1588,6 @@ namespace sat { } } SASSERT(dl_truth - 2 * m_lookahead.size() > base); - base += 2*m_lookahead.size(); } reset_wnb(); SASSERT(m_level == dl_truth); @@ -1576,6 +1599,14 @@ namespace sat { unsigned scope_lvl() const { return m_trail_lim.size(); } + void validate_assign(literal l) { + if (s.m_config.m_drat && m_search_mode == lookahead_mode::searching) { + m_assumptions.push_back(l); + m_drat.add(m_assumptions); + m_assumptions.pop_back(); + } + } + void assign(literal l) { SASSERT(m_level > 0); if (is_undef(l)) { @@ -1586,11 +1617,13 @@ namespace sat { m_stats.m_propagations++; TRACE("sat", tout << "removing free var v" << l.var() << "\n";); m_freevars.remove(l.var()); + validate_assign(l); } } else if (is_false(l)) { TRACE("sat", tout << "conflict: " << l << " @ " << m_level << " " << m_search_mode << "\n";); SASSERT(!is_true(l)); + validate_assign(l); set_conflict(); } } @@ -1709,6 +1742,7 @@ namespace sat { public: lookahead(solver& s) : s(s), + m_drat(s), m_level(2), m_prefix(0) { m_search_mode = lookahead_mode::searching; diff --git a/src/test/main.cpp b/src/test/main.cpp index dd705de4b..28b1537f9 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -77,12 +77,12 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& t int i = 1; while (i < argc) { char * arg = argv[i]; + char * eq_pos = 0; if (arg[0] == '-' || arg[0] == '/') { char * opt_name = arg + 1; char * opt_arg = 0; char * colon = strchr(arg, ':'); - char * eq_pos = 0; if (colon) { opt_arg = colon + 1; *colon = 0; @@ -119,13 +119,19 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& t enable_debug(opt_arg); } #endif - else if (arg[0] != '"' && (eq_pos = strchr(arg, '='))) { - char * key = arg; - *eq_pos = 0; - char * value = eq_pos+1; + } + else if (arg[0] != '"' && (eq_pos = strchr(arg, '='))) { + char * key = arg; + *eq_pos = 0; + char * value = eq_pos+1; + try { gparams::set(key, value); } - } + catch (z3_exception& ex) { + std::cerr << ex.msg() << "\n"; + } + } + i++; } } From 41e1b9f3fe211361589bac370f12805046d5c3e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Apr 2017 12:07:16 +0900 Subject: [PATCH 0100/1283] gt encoding of pb constraints Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 146 +++++++++++++++++++++++++++- src/sat/sat_lookahead.h | 54 +++++++--- 2 files changed, 183 insertions(+), 17 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index f546ef70b..d85bdec41 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -5,7 +5,7 @@ Module Name: pb2bv_rewriter.cpp -Abstract: +Abstralct: Conversion from pseudo-booleans to bit-vectors. @@ -25,6 +25,7 @@ Notes: #include"ast_util.h" #include"ast_pp.h" #include"lbool.h" +#include"uint_set.h" const unsigned g_primes[7] = { 2, 3, 5, 7, 11, 13, 17}; @@ -111,7 +112,13 @@ struct pb2bv_rewriter::imp { if (k.is_neg()) { return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m); } - + + expr_ref result(m); + switch (is_le) { + case l_true: if (mk_le_tot(sz, args, k, result)) return result; else break; + case l_false: if (mk_ge_tot(sz, args, k, result)) return result; else break; + case l_undef: break; + } #if 0 expr_ref result(m); switch (is_le) { @@ -172,6 +179,141 @@ struct pb2bv_rewriter::imp { } } + /** + \brief Totalizer encoding. Based on a version by Miguel. + */ + + bool mk_le_tot(unsigned sz, expr * const * args, rational const& _k, expr_ref& result) { + SASSERT(sz == m_coeffs.size()); + if (!_k.is_unsigned() || sz == 0) return false; + unsigned k = _k.get_unsigned(); + expr_ref_vector args1(m); + rational bound; + flip(sz, args, args1, _k, bound); + if (bound.get_unsigned() < k) { + return mk_ge_tot(sz, args1.c_ptr(), bound, result); + } + if (k > 20) { + return false; + } + result = m.mk_not(bounded_addition(sz, args, k + 1)); + TRACE("pb", tout << result << "\n";); + return true; + } + + bool mk_ge_tot(unsigned sz, expr * const * args, rational const& _k, expr_ref& result) { + SASSERT(sz == m_coeffs.size()); + if (!_k.is_unsigned() || sz == 0) return false; + unsigned k = _k.get_unsigned(); + expr_ref_vector args1(m); + rational bound; + flip(sz, args, args1, _k, bound); + if (bound.get_unsigned() < k) { + return mk_le_tot(sz, args1.c_ptr(), bound, result); + } + if (k > 20) { + return false; + } + result = bounded_addition(sz, args, k); + TRACE("pb", tout << result << "\n";); + return true; + } + + void flip(unsigned sz, expr* const* args, expr_ref_vector& args1, rational const& k, rational& bound) { + bound = -k; + for (unsigned i = 0; i < sz; ++i) { + args1.push_back(mk_not(args[i])); + bound += m_coeffs[i]; + } + } + + expr_ref bounded_addition(unsigned sz, expr * const * args, unsigned k) { + SASSERT(sz > 0); + expr_ref result(m); + vector es; + vector coeffs; + for (unsigned i = 0; i < m_coeffs.size(); ++i) { + unsigned_vector v; + expr_ref_vector e(m); + unsigned c = m_coeffs[i].get_unsigned(); + v.push_back(c >= k ? k : c); + e.push_back(args[i]); + es.push_back(e); + coeffs.push_back(v); + } + while (es.size() > 1) { + for (unsigned i = 0; i + 1 < es.size(); i += 2) { + expr_ref_vector o(m); + unsigned_vector oc; + tot_adder(es[i], coeffs[i], es[i + 1], coeffs[i + 1], k, o, oc); + es[i / 2].set(o); + coeffs[i / 2] = oc; + } + if ((es.size() % 2) == 1) { + es[es.size() / 2].set(es.back()); + coeffs[es.size() / 2] = coeffs.back(); + } + es.shrink((1 + es.size())/2); + coeffs.shrink((1 + coeffs.size())/2); + } + SASSERT(coeffs.size() == 1); + SASSERT(coeffs[0].back() <= k); + if (coeffs[0].back() == k) { + result = es[0].back(); + } + else { + result = m.mk_false(); + } + return result; + } + + void tot_adder(expr_ref_vector const& l, unsigned_vector const& lc, + expr_ref_vector const& r, unsigned_vector const& rc, + unsigned k, + expr_ref_vector& o, unsigned_vector & oc) { + SASSERT(l.size() == lc.size()); + SASSERT(r.size() == rc.size()); + uint_set sums; + vector trail; + u_map sum2def; + for (unsigned i = 0; i <= l.size(); ++i) { + for (unsigned j = (i == 0) ? 1 : 0; j <= r.size(); ++j) { + unsigned sum = std::min(k, ((i == 0) ? 0 : lc[i - 1]) + ((j == 0) ? 0 : rc[j - 1])); + sums.insert(sum); + } + } + uint_set::iterator it = sums.begin(), end = sums.end(); + for (; it != end; ++it) { + oc.push_back(*it); + } + std::sort(oc.begin(), oc.end()); + DEBUG_CODE( + for (unsigned i = 0; i + 1 < oc.size(); ++i) { + SASSERT(oc[i] < oc[i+1]); + }); + for (unsigned i = 0; i < oc.size(); ++i) { + sum2def.insert(oc[i], i); + trail.push_back(expr_ref_vector(m)); + } + for (unsigned i = 0; i <= l.size(); ++i) { + for (unsigned j = (i == 0) ? 1 : 0; j <= r.size(); ++j) { + if (i != 0 && j != 0 && (lc[i - 1] >= k || rc[j - 1] >= k)) continue; + unsigned sum = std::min(k, ((i == 0) ? 0 : lc[i - 1]) + ((j == 0) ? 0 : rc[j - 1])); + expr_ref_vector ands(m); + if (i != 0) { + ands.push_back(l[i - 1]); + } + if (j != 0) { + ands.push_back(r[j - 1]); + } + trail[sum2def.find(sum)].push_back(::mk_and(ands)); + } + } + for (unsigned i = 0; i < oc.size(); ++i) { + o.push_back(::mk_or(trail[sum2def.find(oc[i])])); + } + } + /** \brief MiniSat+ based encoding of PB constraints. The procedure is described in "Translating Pseudo-Boolean Constraints into SAT " diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 3344e82e1..c4f6a4bba 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -282,8 +282,10 @@ namespace sat { inc_bstamp(); set_bstamp(l); literal_vector const& conseq = m_binary[l.index()]; - for (unsigned i = 0; i < conseq.size(); ++i) { - set_bstamp(conseq[i]); + literal_vector::const_iterator it = conseq.begin(); + literal_vector::const_iterator end = conseq.end(); + for (; it != end; ++it) { + set_bstamp(*it); } } bool is_stamped(literal l) const { return m_bstamp[l.index()] == m_bstamp_id; } @@ -557,6 +559,7 @@ namespace sat { literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); for (; it != end; ++it) { if (is_undef(*it)) sum += h[it->index()]; + // if (m_freevars.contains(it->var())) sum += h[it->index()]; } watch_list& wlist = m_watches[l.index()]; watch_list::iterator wit = wlist.begin(), wend = wlist.end(); @@ -568,9 +571,8 @@ namespace sat { case watched::TERNARY: { literal l1 = wit->get_literal1(); literal l2 = wit->get_literal2(); - if (is_undef(l1) && is_undef(l2)) { - tsum += h[l1.index()] * h[l2.index()]; - } + // if (is_undef(l1) && is_undef(l2)) + tsum += h[l1.index()] * h[l2.index()]; break; } case watched::CLAUSE: { @@ -1155,14 +1157,19 @@ namespace sat { // convert windfalls to binary clauses. if (!unsat) { literal nlit = ~lit; + for (unsigned i = 0; i < m_wstack.size(); ++i) { - ++m_stats.m_windfall_binaries; literal l2 = m_wstack[i]; //update_prefix(~lit); //update_prefix(m_wstack[i]); TRACE("sat", tout << "windfall: " << nlit << " " << l2 << "\n";); + // if we use try_add_binary, then this may produce new assignments + // these assignments get put on m_trail, and they are cleared by + // reset_wnb. We would need to distinguish the trail that comes + // from lookahead levels and the main search level for this to work. add_binary(nlit, l2); } + m_stats.m_windfall_binaries += m_wstack.size(); } m_wstack.reset(); } @@ -1180,6 +1187,15 @@ namespace sat { return r; } + // + // The current version is modeled after CDCL SAT solving data-structures. + // It borrows from the watch list data-structure. The cost tradeoffs are somewhat + // biased towards CDCL search overheads. + // If we walk over the positive occurrences of l, then those clauses can be retired so + // that they don't interfere with calculation of H. Instead of removing clauses from the watch + // list one can swap them to the "back" and adjust a size indicator of the watch list + // Only the size indicator needs to be updated on backtracking. + // void propagate_clauses(literal l) { SASSERT(is_true(l)); if (inconsistent()) return; @@ -1237,17 +1253,17 @@ namespace sat { break; } case watched::CLAUSE: { - clause_offset cls_off = it->get_clause_offset(); - clause & c = *(s.m_cls_allocator.get_clause(cls_off)); if (is_true(it->get_blocked_literal())) { *it2 = *it; ++it2; break; } - + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(s.m_cls_allocator.get_clause(cls_off)); if (c[0] == ~l) std::swap(c[0], c[1]); if (is_true(c[0])) { + it->set_blocked_literal(c[0]); *it2 = *it; it2++; break; @@ -1337,13 +1353,21 @@ namespace sat { } void propagate() { - for (; m_qhead < m_trail.size(); ++m_qhead) { - if (inconsistent()) break; - literal l = m_trail[m_qhead]; - TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); - propagate_binary(l); - propagate_clauses(l); + while (!inconsistent() && m_qhead < m_trail.size()) { + unsigned i = m_qhead; + unsigned sz = m_trail.size(); + for (; i < sz && !inconsistent(); ++i) { + literal l = m_trail[i]; + TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); + propagate_binary(l); + } + i = m_qhead; + for (; i < sz && !inconsistent(); ++i) { + propagate_clauses(m_trail[i]); + } + m_qhead = sz; } + TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } From 352f8b6cb974bb3c6c2edb24ac8dd2883d3e682f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 17 Apr 2017 13:04:57 -0700 Subject: [PATCH 0101/1283] fixing local search Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 30 ++++++++++++++++++------------ src/sat/sat_local_search.h | 8 ++++---- src/sat/sat_parallel.cpp | 12 +++++------- src/sat/sat_parallel.h | 2 ++ src/sat/sat_solver.cpp | 3 +++ 5 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 6b0205cc2..c5e7fcf54 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -70,9 +70,10 @@ namespace sat { void local_search::init_cur_solution() { for (unsigned v = 0; v < num_vars(); ++v) { - // use bias half the time. - if (m_rand() % 100 < 10) { - m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); + // use bias with a small probability + if (m_rand() % 100 < 3) { + //m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); + m_vars[v].m_value = (50 < m_vars[v].m_bias); } } } @@ -140,14 +141,17 @@ namespace sat { // the following methods does NOT converge for pseudo-boolean // can try other way to define "worse" and "better" // the current best noise is below 1000 - if (best_unsat_rate >= last_best_unsat_rate) { +#if 0 + if (m_best_unsat_rate > m_last_best_unsat_rate) { // worse m_noise -= m_noise * 2 * m_noise_delta; + m_best_unsat_rate *= 1000.0; } else { // better m_noise += (10000 - m_noise) * m_noise_delta; } +#endif for (unsigned i = 0; i < m_constraints.size(); ++i) { constraint& c = m_constraints[i]; c.m_slack = c.m_k; @@ -178,6 +182,8 @@ namespace sat { init_slack(); init_scores(); init_goodvars(); + + m_best_unsat = m_unsat_stack.size(); } void local_search::calculate_and_update_ob() { @@ -382,13 +388,13 @@ namespace sat { IF_VERBOSE(1, verbose_stream() << "(sat-local-search" \ << " :flips " << flips \ << " :noise " << m_noise \ - << " :unsat " << /*m_unsat_stack.size()*/ best_unsat \ + << " :unsat " << /*m_unsat_stack.size()*/ m_best_unsat \ << " :time " << (timer.get_seconds() < 0.001 ? 0.0 : timer.get_seconds()) << ")\n";); \ } void local_search::walksat() { - best_unsat_rate = 1; - last_best_unsat_rate = 1; + m_best_unsat_rate = 1; + m_last_best_unsat_rate = 1; reinit(); @@ -398,10 +404,10 @@ namespace sat { PROGRESS(tries, total_flips); for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { - if (m_unsat_stack.size() < best_unsat) { - best_unsat = m_unsat_stack.size(); - last_best_unsat_rate = best_unsat_rate; - best_unsat_rate = (double)m_unsat_stack.size() / num_constraints(); + if (m_unsat_stack.size() < m_best_unsat) { + m_best_unsat = m_unsat_stack.size(); + m_last_best_unsat_rate = m_best_unsat_rate; + m_best_unsat_rate = (double)m_unsat_stack.size() / num_constraints(); } for (step = 0; step < m_max_steps && !m_unsat_stack.empty(); ++step) { pick_flip_walksat(); @@ -506,7 +512,7 @@ namespace sat { SASSERT(c.m_k < constraint_value(c)); // TBD: dynamic noise strategy //if (m_rand() % 100 < 98) { - if (m_rand() % 10000 >= m_noise) { + if (m_rand() % 10000 <= m_noise) { // take this branch with 98% probability. // find the first one, to fast break the rest unsigned best_bsb = 0; diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 678eee60a..918f5328d 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -164,9 +164,9 @@ namespace sat { // information about solution - unsigned best_unsat; - double best_unsat_rate; - double last_best_unsat_rate; + unsigned m_best_unsat; + double m_best_unsat_rate; + double m_last_best_unsat_rate; int m_objective_value; // the objective function value corresponds to the current solution bool_vector m_best_solution; // !var: the best solution so far int m_best_objective_value = -1; // the objective value corresponds to the best solution so far @@ -176,7 +176,7 @@ namespace sat { unsigned m_max_steps = (1 << 30); // dynamic noise - double m_noise = 400; // normalized by 10000 + double m_noise = 9800; // normalized by 10000 double m_noise_delta = 0.05; // for tuning diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 67d446a29..0b9a5bcb3 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -115,12 +115,16 @@ namespace sat { m_solvers[i] = alloc(sat::solver, s.m_params, m_limits[i]); m_solvers[i]->copy(s); m_solvers[i]->set_par(this, i); - m_scoped_rlimit.push_child(&m_solvers[i]->rlimit()); + push_child(m_solvers[i]->rlimit()); } s.set_par(this, num_extra_solvers); s.m_params.set_sym("phase", saved_phase); } + void parallel::push_child(reslimit& rl) { + m_scoped_rlimit.push_child(&rl); + } + void parallel::exchange(solver& s, literal_vector const& in, unsigned& limit, literal_vector& out) { if (s.m_par_syncing_clauses) return; @@ -268,12 +272,6 @@ namespace sat { { if (m_solver_copy && s.num_non_binary_clauses() > m_solver_copy->m_clauses.size()) { s.import(*m_solver_copy.get(), true); - m_num_clauses = s.num_non_binary_clauses(); - SASSERT(s.num_non_binary_clauses() == m_solver_copy->m_clauses.size()); - m_solver_copy = 0; - } - if (m_num_clauses < s.num_non_binary_clauses()) { - m_num_clauses = s.num_non_binary_clauses(); } for (unsigned i = 0; i < m_phase.size(); ++i) { s.set_phase(i, m_phase[i]); diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index b93384bd6..ffdfddf55 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -78,6 +78,8 @@ namespace sat { void init_solvers(solver& s, unsigned num_extra_solvers); + void push_child(reslimit& rl); + // reserve space void reserve(unsigned num_owners, unsigned sz) { m_pool.reserve(num_owners, sz); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 66ebb189f..d25c8bdee 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -875,6 +875,9 @@ namespace sat { sat::parallel par(*this); par.reserve(num_threads, 1 << 12); par.init_solvers(*this, num_extra_solvers); + for (unsigned i = 0; i < ls.size(); ++i) { + par.push_child(ls[i]->rlimit()); + } int finished_id = -1; std::string ex_msg; par_exception_kind ex_kind; From a3f4d58b000f8ef91c5db61f74adf05329686ba3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 18 Apr 2017 16:58:56 -0700 Subject: [PATCH 0102/1283] use lookahead for simplification Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 4 +- src/sat/sat_config.h | 1 + src/sat/sat_local_search.cpp | 42 ++++++----- src/sat/sat_local_search.h | 1 + src/sat/sat_lookahead.h | 135 +++++++++++++++++++++++++++++------ src/sat/sat_params.pyg | 1 + src/sat/sat_scc.cpp | 4 +- src/sat/sat_simplifier.cpp | 8 +++ src/sat/sat_simplifier.h | 6 +- src/sat/sat_solver.cpp | 23 ++++++ src/sat/sat_solver.h | 3 + 11 files changed, 183 insertions(+), 45 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 4b019c2b7..42c185ee1 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -37,6 +37,7 @@ namespace sat { m_psm_glue("psm_glue") { m_num_threads = 1; m_local_search = 0; + m_lookahead_search = false; updt_params(p); } @@ -81,7 +82,8 @@ namespace sat { m_max_conflicts = p.max_conflicts(); m_num_threads = p.threads(); m_local_search = p.local_search(); - + m_lookahead_search = p.lookahead_search(); + // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); m_simplify_mult2 = _p.get_double("simplify_mult2", 1.5); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 313b4ec49..8c10983d2 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -59,6 +59,7 @@ namespace sat { unsigned m_max_conflicts; unsigned m_num_threads; unsigned m_local_search; + bool m_lookahead_search; unsigned m_simplify_mult1; double m_simplify_mult2; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index c5e7fcf54..5372011ed 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -71,9 +71,8 @@ namespace sat { void local_search::init_cur_solution() { for (unsigned v = 0; v < num_vars(); ++v) { // use bias with a small probability - if (m_rand() % 100 < 3) { - //m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); - m_vars[v].m_value = (50 < m_vars[v].m_bias); + if (m_rand() % 100 < 2) { + m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); } } } @@ -138,20 +137,24 @@ namespace sat { } void local_search::reinit() { - // the following methods does NOT converge for pseudo-boolean - // can try other way to define "worse" and "better" - // the current best noise is below 1000 -#if 0 - if (m_best_unsat_rate > m_last_best_unsat_rate) { - // worse - m_noise -= m_noise * 2 * m_noise_delta; - m_best_unsat_rate *= 1000.0; + + if (!m_is_pb) { + // + // the following methods does NOT converge for pseudo-boolean + // can try other way to define "worse" and "better" + // the current best noise is below 1000 + // + if (m_best_unsat_rate > m_last_best_unsat_rate) { + // worse + m_noise -= m_noise * 2 * m_noise_delta; + m_best_unsat_rate *= 1000.0; + } + else { + // better + m_noise += (10000 - m_noise) * m_noise_delta; + } } - else { - // better - m_noise += (10000 - m_noise) * m_noise_delta; - } -#endif + for (unsigned i = 0; i < m_constraints.size(); ++i) { constraint& c = m_constraints[i]; c.m_slack = c.m_k; @@ -264,7 +267,7 @@ namespace sat { unsigned id = m_constraints.size(); m_constraints.push_back(constraint(k)); for (unsigned i = 0; i < sz; ++i) { - m_vars.reserve(c[i].var() + 1); + m_vars.reserve(c[i].var() + 1); literal t(~c[i]); m_vars[t.var()].m_watch[is_pos(t)].push_back(pbcoeff(id, coeffs[i])); m_constraints.back().push(t); // add coefficient to constraint? @@ -279,6 +282,7 @@ namespace sat { } void local_search::import(solver& s, bool _init) { + m_is_pb = false; m_vars.reset(); m_constraints.reset(); @@ -349,6 +353,7 @@ namespace sat { // = ~c.lit() or (~c.lits() <= n - k) // = k*c.lit() + ~c.lits() <= n // + m_is_pb = true; lits.reset(); coeffs.reset(); for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]), coeffs.push_back(1); @@ -616,8 +621,7 @@ namespace sat { // verify_unsat_stack(); } - void local_search::flip_gsat(bool_var flipvar) - { + void local_search::flip_gsat(bool_var flipvar) { // already changed truth value!!!! m_vars[flipvar].m_value = !cur_solution(flipvar); diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 918f5328d..edce6cc9c 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -144,6 +144,7 @@ namespace sat { literal_vector m_assumptions; unsigned m_num_non_binary_clauses; + bool m_is_pb; inline bool is_pos(literal t) const { return !t.sign(); } inline bool is_true(bool_var v) const { return cur_solution(v); } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index c4f6a4bba..6bc528220 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,6 +20,8 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ +#include "sat_elim_eqs.h" + namespace sat { struct pp_prefix { @@ -34,6 +36,9 @@ namespace sat { for (unsigned i = 0; i <= d; ++i) { if (0 != (p.m_prefix & (1ull << i))) out << "1"; else out << "0"; } + if (d < p.m_depth) { + out << " d:" << p.m_depth; + } return out; } @@ -309,6 +314,7 @@ namespace sat { assign(u); return false; } + IF_VERBOSE(3, verbose_stream() << "tc1: " << u << " " << w << "\n";); add_binary(u, w); } } @@ -367,7 +373,8 @@ namespace sat { bool select(unsigned level) { init_pre_selection(level); - unsigned max_num_cand = level == 0 ? m_freevars.size() : m_config.m_level_cand / level; + unsigned level_cand = std::max(m_config.m_level_cand, m_freevars.size() / 50); + unsigned max_num_cand = level == 0 ? m_freevars.size() : level_cand / level; max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand); float sum = 0; @@ -1010,7 +1017,8 @@ namespace sat { m_lits.push_back(lit_info()); m_rating.push_back(0); m_vprefix.push_back(prefix()); - m_freevars.insert(v); + if (!s.was_eliminated(v)) + m_freevars.insert(v); } void init() { @@ -1040,11 +1048,31 @@ namespace sat { } } + copy_clauses(s.m_clauses); + copy_clauses(s.m_learned); + + // copy units + unsigned trail_sz = s.init_trail_size(); + for (unsigned i = 0; i < trail_sz; ++i) { + literal l = s.m_trail[i]; + if (!s.was_eliminated(l.var())) + { + if (s.m_config.m_drat) m_drat.add(l, false); + assign(l); + } + } + propagate(); + m_qhead = m_trail.size(); + TRACE("sat", s.display(tout); display(tout);); + } + + void copy_clauses(clause_vector const& clauses) { // copy clauses - clause_vector::const_iterator it = s.m_clauses.begin(); - clause_vector::const_iterator end = s.m_clauses.end(); - for (; it != end; ++it) { + clause_vector::const_iterator it = clauses.begin(); + clause_vector::const_iterator end = clauses.end(); + for (; it != end; ++it) { clause& c = *(*it); + if (c.was_removed()) continue; clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); m_clauses.push_back(c1); attach_clause(*c1); @@ -1053,17 +1081,6 @@ namespace sat { } if (s.m_config.m_drat) m_drat.add(c, false); } - - // copy units - unsigned trail_sz = s.init_trail_size(); - for (unsigned i = 0; i < trail_sz; ++i) { - literal l = s.m_trail[i]; - if (s.m_config.m_drat) m_drat.add(l, false); - assign(l); - } - propagate(); - m_qhead = m_trail.size(); - TRACE("sat", s.display(tout); display(tout);); } // ------------------------------------ @@ -1393,19 +1410,24 @@ namespace sat { TRACE("sat", display_lookahead(tout); ); unsigned base = 2; bool change = true; + bool first = true; while (change && !inconsistent()) { change = false; for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { + s.checkpoint(); literal lit = m_lookahead[i].m_lit; if (is_fixed_at(lit, c_fixed_truth)) continue; unsigned level = base + m_lookahead[i].m_offset; if (m_stamp[lit.var()] >= level) { continue; } + if (scope_lvl() == 1) { + IF_VERBOSE(3, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); + } TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); reset_wnb(lit); push_lookahead1(lit, level); - do_double(lit, base); + if (!first) do_double(lit, base); bool unsat = inconsistent(); pop_lookahead1(lit); if (unsat) { @@ -1424,7 +1446,13 @@ namespace sat { if (c_fixed_truth - 2 * m_lookahead.size() < base) { break; } - base += 2 * m_lookahead.size(); + if (first && !change) { + first = false; + change = true; + } + reset_wnb(); + init_wnb(); + // base += 2 * m_lookahead.size(); } reset_wnb(); TRACE("sat", display_lookahead(tout); ); @@ -1487,6 +1515,7 @@ namespace sat { } bool check_autarky(literal l, unsigned level) { + return false; // no propagations are allowed to reduce clauses. clause_vector::const_iterator it = m_full_watches[l.index()].begin(); clause_vector::const_iterator end = m_full_watches[l.index()].end(); @@ -1568,7 +1597,7 @@ namespace sat { } void do_double(literal l, unsigned& base) { - if (!inconsistent() && scope_lvl() > 0 && dl_enabled(l)) { + if (!inconsistent() && scope_lvl() > 1 && dl_enabled(l)) { if (get_wnb(l) > m_delta_trigger) { if (dl_no_overflow(base)) { ++m_stats.m_double_lookahead_rounds; @@ -1588,6 +1617,7 @@ namespace sat { SASSERT(dl_no_overflow(base)); unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); scoped_level _sl(*this, dl_truth); + IF_VERBOSE(2, verbose_stream() << "double: " << l << "\n";); init_wnb(); assign(l); propagate(); @@ -1769,9 +1799,6 @@ namespace sat { m_drat(s), m_level(2), m_prefix(0) { - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); } ~lookahead() { @@ -1779,9 +1806,73 @@ namespace sat { } lbool check() { + { + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + } return search(); } + void simplify() { + SASSERT(m_prefix == 0); + SASSERT(m_watches.empty()); + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + if (inconsistent()) return; + inc_istamp(); + literal l = choose(); + if (inconsistent()) return; + SASSERT(m_trail_lim.empty()); + unsigned num_units = 0; + for (unsigned i = 0; i < m_trail.size(); ++i) { + literal lit = m_trail[i]; + if (s.value(lit) == l_undef && !s.was_eliminated(lit.var())) { + s.m_simplifier.propagate_unit(lit); + ++num_units; + } + } + IF_VERBOSE(1, verbose_stream() << "units found: " << num_units << "\n";); + + s.m_simplifier.subsume(); + m_lookahead.reset(); + } + + void scc() { + SASSERT(m_prefix == 0); + SASSERT(m_watches.empty()); + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + if (inconsistent()) return; + inc_istamp(); + m_lookahead.reset(); + if (select(0)) { + // extract equivalences + get_scc(); + if (inconsistent()) return; + literal_vector roots; + bool_var_vector to_elim; + for (unsigned i = 0; i < s.num_vars(); ++i) { + roots.push_back(literal(i, false)); + } + for (unsigned i = 0; i < m_candidates.size(); ++i) { + bool_var v = m_candidates[i].m_var; + literal lit = literal(v, false); + literal p = get_parent(lit); + if (p != null_literal && p.var() != v && !s.is_external(v) && !s.was_eliminated(v) && !s.was_eliminated(p.var())) { + to_elim.push_back(v); + roots[v] = p; + } + } + IF_VERBOSE(1, verbose_stream() << "eliminate " << to_elim.size() << " variables\n";); + elim_eqs elim(s); + elim(roots, to_elim); + } + m_lookahead.reset(); + } + std::ostream& display(std::ostream& out) const { out << "Prefix: " << pp_prefix(m_prefix, m_trail_lim.size()) << "\n"; out << "Level: " << m_level << "\n"; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 045fd803a..ffc699d02 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -29,4 +29,5 @@ def_module_params('sat', ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('xor.solver', BOOL, False, 'use xor solver'), ('local_search', UINT, 0, 'number of local search threads to find satisfiable solution'), + ('lookahead_search', BOOL, False, 'use lookahead solver') )) diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index ffbdb31c6..3dfc42f6a 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -76,7 +76,9 @@ namespace sat { lowlink.resize(num_lits, UINT_MAX); in_s.resize(num_lits, false); literal_vector roots; - roots.resize(m_solver.num_vars(), null_literal); + for (unsigned i = 0; i < m_solver.num_vars(); ++i) { + roots.push_back(literal(i, false)); + } unsigned next_index = 0; svector frames; bool_var_vector to_elim; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index fe019427f..8cbedb86b 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -21,6 +21,7 @@ Revision History: #include"sat_simplifier.h" #include"sat_simplifier_params.hpp" #include"sat_solver.h" +#include"sat_lookahead.h" #include"stopwatch.h" #include"trace.h" @@ -204,6 +205,11 @@ namespace sat { } while (!m_sub_todo.empty()); + if (!learned) { + // perform lookahead simplification + lookahead(s).simplify(); + } + bool vars_eliminated = m_num_elim_vars > old_num_elim_vars; if (m_need_cleanup) { @@ -219,9 +225,11 @@ namespace sat { cleanup_clauses(s.m_learned, true, true, learned_in_use_lists); } } + CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); finalize(); + } /** diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 9ee239083..47648cc10 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -130,13 +130,11 @@ namespace sat { bool cleanup_clause(clause & c, bool in_use_list); bool cleanup_clause(literal_vector & c); - void propagate_unit(literal l); void elim_lit(clause & c, literal l); void elim_dup_bins(); bool subsume_with_binaries(); void mark_as_not_learned_core(watch_list & wlist, literal l2); void mark_as_not_learned(literal l1, literal l2); - void subsume(); void cleanup_watches(); void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists); @@ -191,6 +189,10 @@ namespace sat { void collect_statistics(statistics & st) const; void reset_statistics(); + + void propagate_unit(literal l); + void subsume(); + }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d25c8bdee..5ebd661ee 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -22,6 +22,7 @@ Revision History: #include"trace.h" #include"max_cliques.h" #include"scoped_ptr_vector.h" +#include"sat_lookahead.h" // define to update glue during propagation #define UPDATE_GLUE @@ -783,6 +784,9 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); + if (m_config.m_lookahead_search && num_lits == 0) { + return lookahead_search(); + } if ((m_config.m_num_threads > 1 || m_config.m_local_search > 0) && !m_par) { return check_par(num_lits, lits); } @@ -855,6 +859,20 @@ namespace sat { ERROR_EX }; + lbool solver::lookahead_search() { + lookahead lh(*this); + lbool r = l_undef; + try { + r = lh.check(); + m_model = lh.get_model(); + } + catch (z3_exception&) { + lh.collect_statistics(m_lookahead_stats); + throw; + } + lh.collect_statistics(m_lookahead_stats); + return r; + } lbool solver::check_par(unsigned num_lits, literal const* lits) { scoped_ptr_vector ls; @@ -1295,6 +1313,8 @@ namespace sat { CASSERT("sat_simplify_bug", check_invariant()); } + lookahead(*this).scc(); + sort_watch_lits(); CASSERT("sat_simplify_bug", check_invariant()); @@ -2762,6 +2782,7 @@ namespace sat { m_asymm_branch.collect_statistics(st); m_probing.collect_statistics(st); if (m_ext) m_ext->collect_statistics(st); + st.copy(m_lookahead_stats); } void solver::reset_statistics() { @@ -2770,6 +2791,7 @@ namespace sat { m_simplifier.reset_statistics(); m_asymm_branch.reset_statistics(); m_probing.reset_statistics(); + m_lookahead_stats.reset(); } // ----------------------- @@ -3605,6 +3627,7 @@ namespace sat { if (m_solver.m_num_frozen > 0) out << " :frozen " << m_solver.m_num_frozen; } + out << " :units " << m_solver.init_trail_size(); out << " :gc-clause " << m_solver.m_stats.m_gc_clause; out << mem_stat(); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c35a0296c..1bf393696 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -141,6 +141,8 @@ namespace sat { unsigned m_par_num_vars; bool m_par_syncing_clauses; + statistics m_lookahead_stats; + void del_clauses(clause * const * begin, clause * const * end); friend class integrity_checker; @@ -346,6 +348,7 @@ namespace sat { void sort_watch_lits(); void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); + lbool lookahead_search(); // ----------------------- // From e65f106a83177bb8e2becfb1d2bb41bd6936cb44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 19 Apr 2017 08:59:49 -0700 Subject: [PATCH 0103/1283] ccc Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 1 + src/sat/card_extension.cpp | 90 ++++++++- src/sat/card_extension.h | 45 ++++- src/sat/sat_ccc.cpp | 271 +++++++++++++++++++++++++++ src/sat/sat_ccc.h | 66 +++++++ src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 3 +- src/sat/sat_lookahead.h | 38 ++-- src/sat/sat_params.pyg | 3 +- src/sat/sat_solver.cpp | 21 ++- src/sat/sat_solver.h | 4 +- src/util/memory_manager.cpp | 1 + src/util/queue.h | 61 ++++++ 13 files changed, 573 insertions(+), 32 deletions(-) create mode 100644 src/sat/sat_ccc.cpp create mode 100644 src/sat/sat_ccc.h create mode 100644 src/util/queue.h diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index 5494049d7..fcfe53e02 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(sat card_extension.cpp dimacs.cpp sat_asymm_branch.cpp + sat_ccc.cpp sat_clause.cpp sat_clause_set.cpp sat_clause_use_list.cpp diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index cb05e5d61..7d1c27abb 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -26,8 +26,7 @@ namespace sat { m_index(index), m_lit(lit), m_k(k), - m_size(lits.size()) - { + m_size(lits.size()) { for (unsigned i = 0; i < lits.size(); ++i) { m_lits[i] = lits[i]; } @@ -42,6 +41,27 @@ namespace sat { SASSERT(m_size >= m_k && m_k > 0); } + card_extension::pb::pb(unsigned index, literal lit, svector const& wlits, unsigned k): + m_index(index), + m_lit(lit), + m_k(k), + m_size(wlits.size()) { + for (unsigned i = 0; i < wlits.size(); ++i) { + m_wlits[i] = wlits[i]; + } + } + + void card_extension::pb::negate() { + m_lit.neg(); + unsigned w = 0; + for (unsigned i = 0; i < m_size; ++i) { + m_wlits[i].second.neg(); + w += m_wlits[i].first; + } + m_k = w - m_k + 1; + SASSERT(w >= m_k && m_k > 0); + } + card_extension::xor::xor(unsigned index, literal lit, literal_vector const& lits): m_index(index), m_lit(lit), @@ -191,6 +211,15 @@ namespace sat { SASSERT(s().inconsistent()); } + // pb: + void card_extension::init_watch(pb& p, bool is_true) { + NOT_IMPLEMENTED_YET(); + } + + + + + // xor: void card_extension::clear_watch(xor& x) { unwatch_literal(x[0], &x); unwatch_literal(x[1], &x); @@ -510,7 +539,7 @@ namespace sat { process_card(c, offset); ++m_stats.m_num_card_resolves; } - else { + else if (is_xor_index(index)) { // jus.push_back(js); m_lemma.reset(); m_bound += offset; @@ -521,6 +550,12 @@ namespace sat { } ++m_stats.m_num_xor_resolves; } + else if (is_pb_index(index)) { + NOT_IMPLEMENTED_YET(); + } + else { + UNREACHABLE(); + } break; } default: @@ -758,7 +793,7 @@ namespace sat { } void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { - unsigned index = 2*m_cards.size(); + unsigned index = 4*m_cards.size(); literal lit = v == null_bool_var ? null_literal : literal(v, false); card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); m_cards.push_back(c); @@ -774,9 +809,26 @@ namespace sat { } } + void card_extension::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { + unsigned index = 4*m_pb.size() + 0x11; + literal lit = v == null_bool_var ? null_literal : literal(v, false); + pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(index, lit, wlits, k); + m_pb.push_back(p); + if (v == null_bool_var) { + init_watch(*p, true); + m_pb_axioms.push_back(p); + } + else { + init_watch(v); + m_var_infos[v].m_pb = p; + m_var_trail.push_back(v); + } + } + + void card_extension::add_xor(bool_var v, literal_vector const& lits) { m_has_xor = true; - unsigned index = 2*m_xors.size()+1; + unsigned index = 4*m_xors.size() + 0x01; xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, literal(v, false), lits); m_xors.push_back(x); init_watch(v); @@ -819,7 +871,7 @@ namespace sat { unsigned level = lvl(l); bool_var v = l.var(); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); - SASSERT(!is_card_index(js.get_ext_justification_idx())); + SASSERT(is_xor_index(js.get_ext_justification_idx())); TRACE("sat", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); unsigned num_marks = 0; @@ -828,7 +880,7 @@ namespace sat { ++count; if (js.get_kind() == justification::EXT_JUSTIFICATION) { unsigned idx = js.get_ext_justification_idx(); - if (is_card_index(idx)) { + if (!is_xor_index(idx)) { r.push_back(l); } else { @@ -912,7 +964,7 @@ namespace sat { r.push_back(~c[i]); } } - else { + else if (is_xor_index(idx)) { xor& x = index2xor(idx); if (x.lit() != null_literal) r.push_back(x.lit()); TRACE("sat", display(tout << l << " ", x, true);); @@ -931,6 +983,12 @@ namespace sat { r.push_back(value(x[i]) == l_true ? x[i] : ~x[i]); } } + else if (is_pb_index(idx)) { + NOT_IMPLEMENTED_YET(); + } + else { + UNREACHABLE(); + } } @@ -1281,13 +1339,19 @@ namespace sat { } out << ">= " << c.k(); } - else { + else if (is_xor_index(idx)) { xor& x = index2xor(idx); out << "xor " << x.lit() << ": "; for (unsigned i = 0; i < x.size(); ++i) { out << x[i] << " "; } } + else if (is_pb_index(idx)) { + NOT_IMPLEMENTED_YET(); + } + else { + UNREACHABLE(); + } return out; } @@ -1382,7 +1446,7 @@ namespace sat { } if (c.lit() != null_literal) p.push(~c.lit(), offset*c.k()); } - else { + else if (is_xor_index(index)) { literal_vector ls; get_antecedents(lit, index, ls); p.reset(offset); @@ -1392,6 +1456,12 @@ namespace sat { literal lxor = index2xor(index).lit(); if (lxor != null_literal) p.push(~lxor, offset); } + else if (is_pb_index(index)) { + NOT_IMPLEMENTED_YET(); + } + else { + UNREACHABLE(); + } break; } default: diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 0d649a97c..6f8b6d120 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -58,6 +58,26 @@ namespace sat { void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate(); }; + + typedef std::pair wliteral; + + class pb { + unsigned m_index; + literal m_lit; + unsigned m_k; + unsigned m_size; + wliteral m_wlits[0]; + public: + static size_t get_obj_size(unsigned num_lits) { return sizeof(card) + num_lits * sizeof(wliteral); } + pb(unsigned index, literal lit, svector const& wlits, unsigned k); + unsigned index() const { return m_index; } + literal lit() const { return m_lit; } + wliteral operator[](unsigned i) const { return m_wlits[i]; } + unsigned k() const { return m_k; } + unsigned size() const { return m_size; } + void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } + void negate(); + }; class xor { unsigned m_index; @@ -85,20 +105,28 @@ namespace sat { typedef ptr_vector card_watch; typedef ptr_vector xor_watch; + typedef ptr_vector pb_watch; struct var_info { card_watch* m_card_watch[2]; + pb_watch* m_pb_watch[2]; xor_watch* m_xor_watch; card* m_card; + pb* m_pb; xor* m_xor; - var_info(): m_xor_watch(0), m_card(0), m_xor(0) { + var_info(): m_xor_watch(0), m_card(0), m_xor(0), m_pb(0) { m_card_watch[0] = 0; m_card_watch[1] = 0; + m_pb_watch[0] = 0; + m_pb_watch[1] = 0; } void reset() { dealloc(m_card); dealloc(m_xor); + dealloc(m_pb); dealloc(card_extension::set_tag_non_empty(m_card_watch[0])); dealloc(card_extension::set_tag_non_empty(m_card_watch[1])); + dealloc(card_extension::set_tag_non_empty(m_pb_watch[0])); + dealloc(card_extension::set_tag_non_empty(m_pb_watch[1])); dealloc(card_extension::set_tag_non_empty(m_xor_watch)); } }; @@ -125,8 +153,10 @@ namespace sat { ptr_vector m_cards; ptr_vector m_xors; + ptr_vector m_pb; scoped_ptr_vector m_card_axioms; + scoped_ptr_vector m_pb_axioms; // watch literals svector m_var_infos; @@ -173,11 +203,17 @@ namespace sat { lbool add_assign(xor& x, literal alit); void asserted_xor(literal l, ptr_vector* xors, xor* x); - bool is_card_index(unsigned idx) const { return 0 == (idx & 0x1); } - card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 1]; } - xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 1]; } + bool is_card_index(unsigned idx) const { return 0x00 == (idx & 0x11); } + bool is_xor_index(unsigned idx) const { return 0x01 == (idx & 0x11); } + bool is_pb_index(unsigned idx) const { return 0x11 == (idx & 0x11); } + card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 2]; } + xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 2]; } + pb& index2pb(unsigned idx) const { SASSERT(is_pb_index(idx)); return *m_pb[idx >> 2]; } + void get_xor_antecedents(literal l, unsigned inddex, justification js, literal_vector& r); + void init_watch(pb& p, bool is_true); + template bool remove(ptr_vector& ts, T* t) { @@ -233,6 +269,7 @@ namespace sat { virtual ~card_extension(); virtual void set_solver(solver* s) { m_solver = s; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); + void add_pb_ge(bool_var v, svector const& wlits, unsigned k); void add_xor(bool_var v, literal_vector const& lits); virtual void propagate(literal l, ext_constraint_idx idx, bool & keep); virtual bool resolve_conflict(); diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp new file mode 100644 index 000000000..70defb17d --- /dev/null +++ b/src/sat/sat_ccc.cpp @@ -0,0 +1,271 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_ccc.cpp + +Abstract: + + A variant of Concurrent Cube and Conquer + +Author: + + Nikolaj Bjorner (nbjorner) 2017-4-17 + +Notes: + +--*/ + +#include "sat_solver.h" +#include "sat_lookahead.h" +#include "sat_ccc.h" + +using namespace sat; + +lbool ccc::cube() { + unsigned branch_id = 0; + unsigned_vector id_trail; + + lookahead lh(s); + lh.init_search(); + lh.m_model.reset(); + + lookahead::scoped_level _sl(lh, lh.c_fixed_truth); + literal_vector trail; + lh.m_search_mode = lookahead_mode::searching; + while (!m_cancel) { + // remove old branch ids from id_trail. + while (id_trail.size() > trail.size()) { + id_trail.pop_back(); + } + TRACE("sat", lh.display(tout);); + lh.inc_istamp(); + s.checkpoint(); + if (lh.inconsistent()) { + if (!lh.backtrack(trail)) return l_false; + continue; + } + + // check if CDCL solver got ahead. + bool repeat = false; + #pragma omp critical (ccc_solved) + { + if (!m_solved.empty()) { + unsigned solved_id = m_solved.top(); + if (id_trail.contains(solved_id)) { + lh.set_conflict(); + } + else { + m_solved.pop(); + } + repeat = true; + } + } + if (repeat) continue; + + ++branch_id; + if (!trail.empty()) { + #pragma omp critical (ccc_decisions) + { + m_decisions.push(decision(branch_id, trail.size()-1, trail.back())); + } + } + + literal l = lh.choose(); + if (lh.inconsistent()) { + if (!lh.backtrack(trail)) return l_false; + continue; + } + if (l == null_literal) { + m_model = lh.get_model(); + return l_true; + } + + // update trail and set of ids + id_trail.push_back(branch_id); + trail.push_back(l); + SASSERT(id_trail.size() == trail.size()); + + TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); + ++lh.m_stats.m_decisions; + IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); + lh.push(l, lh.c_fixed_truth); + SASSERT(lh.inconsistent() || !lh.is_unsat()); + } + return l_undef; +} + +lbool ccc::conquer(solver& s) { + try { + if (s.inconsistent()) return l_false; + s.init_search(); + s.propagate(false); + if (s.inconsistent()) return l_false; + s.init_assumptions(0, 0); + s.propagate(false); + if (s.check_inconsistent()) return l_false; + s.cleanup(); + s.simplify_problem(); + if (s.check_inconsistent()) return l_false; + + unsigned_vector ids; + + while (true) { + SASSERT(!s.inconsistent()); + + lbool r = bounded_search(s, ids); + if (r != l_undef) + return r; + + if (s.m_conflicts > s.m_config.m_max_conflicts) { + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << s.m_conflicts << "\")\n";); + return l_undef; + } + + s.restart(); + s.simplify_problem(); + if (s.check_inconsistent()) return l_false; + s.gc(); + } + } + catch (solver::abort_solver) { + return l_undef; + } +} + +lbool ccc::bounded_search(solver& s, unsigned_vector& ids) { + decision d; + + while (true) { + s.checkpoint(); + bool done = false; + while (!done) { + lbool is_sat = s.propagate_and_backjump_step(done); + if (is_sat != l_true) return is_sat; + } + + if (s.m_scope_lvl < ids.size()) { + while (ids.size() > s.m_scope_lvl + 1) ids.pop_back(); + unsigned id = ids.back(); + ids.pop_back(); + #pragma omp critical (ccc_solved) + { + m_solved.push(id); + } + } + + s.gc(); + + bool cube_decision = false; + #pragma omp critical (ccc_decisions) + { + if (!m_decisions.empty()) { + d = m_decisions.pop(); + cube_decision = true; + } + } + if (cube_decision) { + if (d.m_depth > ids.size()) continue; + ids.push_back(d.m_id); + s.pop_reinit(s.m_scope_lvl - d.m_depth); // TBD: check alignment of scopes + s.push(); + s.assign(d.m_last, justification()); + } + else if (!s.decide()) { + lbool is_sat = s.final_check(); + if (is_sat != l_undef) { + return is_sat; + } + } + } +} + + +lbool ccc::search() { + enum par_exception_kind { + DEFAULT_EX, + ERROR_EX + }; + + m_cancel = false; + + scoped_limits scoped_rlimit(s.rlimit()); + vector limits; + ptr_vector solvers; + int finished_id = -1; + std::string ex_msg; + par_exception_kind ex_kind; + unsigned error_code = 0; + lbool result = l_undef; + bool canceled = false; + + int num_threads = s.m_config.m_num_threads + 1; + for (int i = 1; i < num_threads; ++i) { + limits.push_back(reslimit()); + } + + for (int i = 1; i < num_threads; ++i) { + s.m_params.set_uint("random_seed", s.m_rand()); + solvers[i] = alloc(sat::solver, s.m_params, limits[i]); + solvers[i]->copy(s); + scoped_rlimit.push_child(&solvers[i]->rlimit()); + } + + #pragma omp parallel for + for (int i = 0; i < num_threads; ++i) { + try { + lbool r = l_undef; + if (i == 0) { + r = cube(); + } + else { + r = conquer(*solvers[i-1]); + } + bool first = false; + #pragma omp critical (par_solver) + { + if (finished_id == -1) { + finished_id = i; + first = true; + result = r; + } + } + if (first) { + for (unsigned j = 0; j < solvers.size(); ++j) { + solvers[j]->rlimit().cancel(); + } + // cancel lookahead solver: + m_cancel = true; + } + } + catch (z3_error & err) { + error_code = err.error_code(); + ex_kind = ERROR_EX; + } + catch (z3_exception & ex) { + ex_msg = ex.msg(); + ex_kind = DEFAULT_EX; + } + } + + if (finished_id > 0 && result == l_true) { + // set model from auxiliary solver + m_model = solvers[finished_id - 1]->get_model(); + } + + for (unsigned i = 0; i < solvers.size(); ++i) { + dealloc(solvers[i]); + } + + if (finished_id == -1) { + switch (ex_kind) { + case ERROR_EX: throw z3_error(error_code); + default: throw default_exception(ex_msg.c_str()); + } + } + + + return result; +} + diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h new file mode 100644 index 000000000..d5357090a --- /dev/null +++ b/src/sat/sat_ccc.h @@ -0,0 +1,66 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_ccc.h + +Abstract: + + A variant of Concurrent Cube and Conquer + +Author: + + Nikolaj Bjorner (nbjorner) 2017-4-17 + +Notes: + +--*/ +#ifndef _SAT_CCC_H_ +#define _SAT_CCC_H_ + +#include "queue.h" + +namespace sat { + + class ccc { + struct decision { + unsigned m_id; + unsigned m_depth; + literal m_last; + decision(unsigned id, unsigned d, literal last): + m_id(id), m_depth(d), m_last(last) {} + decision(): m_id(0), m_depth(0), m_last(null_literal) {} + }; + + solver& s; + queue m_solved; + queue m_decisions; + model m_model; + volatile bool m_cancel; + + struct config { + config() { + } + }; + + struct stats { + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + lbool conquer(solver& s); + lbool bounded_search(solver& s, unsigned_vector& ids); + + lbool cube(); + + public: + ccc(solver& s): s(s) {} + + lbool search(); + + }; +} + +#endif + diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 42c185ee1..175c34690 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -82,6 +82,7 @@ namespace sat { m_max_conflicts = p.max_conflicts(); m_num_threads = p.threads(); m_local_search = p.local_search(); + m_local_search_threads = p.local_search_threads(); m_lookahead_search = p.lookahead_search(); // These parameters are not exposed diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 8c10983d2..fb125c529 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -58,7 +58,8 @@ namespace sat { unsigned m_burst_search; unsigned m_max_conflicts; unsigned m_num_threads; - unsigned m_local_search; + unsigned m_local_search_threads; + bool m_local_search; bool m_lookahead_search; unsigned m_simplify_mult1; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 6bc528220..a801cdad7 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -61,6 +61,8 @@ namespace sat { class lookahead { solver& s; + friend class ccc; + struct config { double m_dl_success; float m_alpha; @@ -70,6 +72,7 @@ namespace sat { unsigned m_level_cand; float m_delta_rho; unsigned m_dl_max_iterations; + unsigned m_tc1_limit; config() { m_max_hlevel = 50; @@ -79,6 +82,7 @@ namespace sat { m_level_cand = 600; m_delta_rho = (float)0.9995; m_dl_max_iterations = 32; + m_tc1_limit = 10000000; } }; @@ -126,6 +130,8 @@ namespace sat { vector m_binary; // literal: binary clauses unsigned_vector m_binary_trail; // trail of added binary clauses unsigned_vector m_binary_trail_lim; + unsigned m_num_tc1; + unsigned_vector m_num_tc1_lim; unsigned m_qhead; // propagation queue head unsigned_vector m_qhead_lim; clause_vector m_clauses; // non-binary clauses @@ -314,8 +320,11 @@ namespace sat { assign(u); return false; } - IF_VERBOSE(3, verbose_stream() << "tc1: " << u << " " << w << "\n";); - add_binary(u, w); + if (m_num_tc1 < m_config.m_tc1_limit) { + ++m_num_tc1; + IF_VERBOSE(3, verbose_stream() << "tc1: " << u << " " << w << "\n";); + add_binary(u, w); + } } } return true; @@ -1055,11 +1064,10 @@ namespace sat { unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { literal l = s.m_trail[i]; - if (!s.was_eliminated(l.var())) - { - if (s.m_config.m_drat) m_drat.add(l, false); - assign(l); - } + if (!s.was_eliminated(l.var())) { + if (s.m_config.m_drat) m_drat.add(l, false); + assign(l); + } } propagate(); m_qhead = m_trail.size(); @@ -1090,6 +1098,7 @@ namespace sat { SASSERT(m_search_mode == lookahead_mode::searching); m_binary_trail_lim.push_back(m_binary_trail.size()); m_trail_lim.push_back(m_trail.size()); + m_num_tc1_lim.push_back(m_num_tc1); m_retired_clause_lim.push_back(m_retired_clauses.size()); m_retired_ternary_lim.push_back(m_retired_ternary.size()); m_qhead_lim.push_back(m_qhead); @@ -1116,6 +1125,9 @@ namespace sat { } m_trail.shrink(old_sz); // reset assignment. m_trail_lim.pop_back(); + + m_num_tc1 = m_num_tc1_lim.back(); + m_num_tc1_lim.pop_back(); // unretire clauses old_sz = m_retired_clause_lim.back(); @@ -1792,11 +1804,17 @@ namespace sat { return out; } + void init_search() { + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + } public: lookahead(solver& s) : s(s), m_drat(s), + m_num_tc1(0), m_level(2), m_prefix(0) { } @@ -1806,11 +1824,7 @@ namespace sat { } lbool check() { - { - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); - } + init_search(); return search(); } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index ffc699d02..a69de0772 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -28,6 +28,7 @@ def_module_params('sat', ('drat.check', BOOL, False, 'build up internal proof and check'), ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('xor.solver', BOOL, False, 'use xor solver'), - ('local_search', UINT, 0, 'number of local search threads to find satisfiable solution'), + ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), + ('local_search', BOOL, False, 'use local search instead of CDCL'), ('lookahead_search', BOOL, False, 'use lookahead solver') )) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5ebd661ee..8eaba2734 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -787,7 +787,10 @@ namespace sat { if (m_config.m_lookahead_search && num_lits == 0) { return lookahead_search(); } - if ((m_config.m_num_threads > 1 || m_config.m_local_search > 0) && !m_par) { + if (m_config.m_local_search) { + return do_local_search(num_lits, lits); + } + if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0) && !m_par) { return check_par(num_lits, lits); } flet _searching(m_searching, true); @@ -859,6 +862,18 @@ namespace sat { ERROR_EX }; + lbool solver::do_local_search(unsigned num_lits, literal const* lits) { + scoped_limits scoped_rl(rlimit()); + local_search srch; + srch.config().set_seed(m_config.m_random_seed); + srch.import(*this, false); + scoped_rl.push_child(&srch.rlimit()); + lbool r = srch.check(num_lits, lits, 0); + m_model = srch.get_model(); + // srch.collect_statistics(m_lookahead_stats); + return r; + } + lbool solver::lookahead_search() { lookahead lh(*this); lbool r = l_undef; @@ -876,9 +891,9 @@ namespace sat { lbool solver::check_par(unsigned num_lits, literal const* lits) { scoped_ptr_vector ls; - int num_threads = static_cast(m_config.m_num_threads + m_config.m_local_search); + int num_threads = static_cast(m_config.m_num_threads + m_config.m_local_search_threads); int num_extra_solvers = m_config.m_num_threads - 1; - int num_local_search = static_cast(m_config.m_local_search); + int num_local_search = static_cast(m_config.m_local_search_threads); for (int i = 0; i < num_local_search; ++i) { local_search* l = alloc(local_search); l->config().set_seed(m_config.m_random_seed + i); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 1bf393696..b4b7f82fe 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -160,6 +160,7 @@ namespace sat { friend class lookahead; friend class local_search; friend struct mk_stat; + friend class ccc; public: solver(params_ref const & p, reslimit& l); ~solver(); @@ -349,6 +350,7 @@ namespace sat { void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); lbool lookahead_search(); + lbool do_local_search(unsigned num_lits, literal const* lits); // ----------------------- // @@ -465,7 +467,7 @@ namespace sat { lbool get_consequences(literal_vector const& assms, bool_var_vector const& vars, vector& conseq); // initialize and retrieve local search. - local_search& init_local_search(); + // local_search& init_local_search(); private: diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 6bd4ec64f..c727a8af3 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -57,6 +57,7 @@ static void throw_out_of_memory() { { g_memory_out_of_memory = true; } + if (g_exit_when_out_of_memory) { std::cerr << g_out_of_memory_msg << "\n"; exit(ERR_MEMOUT); diff --git a/src/util/queue.h b/src/util/queue.h new file mode 100644 index 000000000..4b85f53f0 --- /dev/null +++ b/src/util/queue.h @@ -0,0 +1,61 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + queue.h + +Abstract: + + Generic queue. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-4-17 + +Notes: + +--*/ +#ifndef _QUEUE_H_ +#define _QUEUE_H_ + +#include "vector.h" + +template +class queue { + vector m_elems; + unsigned m_head; + unsigned m_capacity; + +public: + + queue(): m_head(0), m_capacity(0) {} + + void push(T const& t) { m_elems.push_back(t); } + + bool empty() const { + return m_head == m_elems.size(); + } + + T top() const { + return m_elems[m_head]; + } + + T pop() { + SASSERT(!empty()); + m_capacity = std::max(m_capacity, m_elems.size()); + SASSERT(m_head < m_elems.size()); + if (2 * m_head > m_capacity && m_capacity > 10) { + for (unsigned i = 0; i < m_elems.size() - m_head; ++i) { + m_elems[i] = m_elems[i + m_head]; + } + m_elems.shrink(m_elems.size() - m_head); + m_head = 0; + } + return m_elems[m_head++]; + } + +}; + +#endif + From 86a54dfec8ddc3e558a558319ae3887ca13a5a78 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Apr 2017 08:18:25 -0700 Subject: [PATCH 0104/1283] debugging ccc Signed-off-by: Nikolaj Bjorner --- src/sat/sat_ccc.cpp | 719 ++++++++++++++++++++++++++++++++++++++--- src/sat/sat_ccc.h | 28 +- src/sat/sat_config.cpp | 2 + src/sat/sat_config.h | 1 + src/sat/sat_params.pyg | 3 +- src/sat/sat_scc.cpp | 247 +++++++------- src/sat/sat_solver.cpp | 11 + src/sat/sat_solver.h | 1 + 8 files changed, 832 insertions(+), 180 deletions(-) diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp index 70defb17d..bb60a99e3 100644 --- a/src/sat/sat_ccc.cpp +++ b/src/sat/sat_ccc.cpp @@ -23,6 +23,18 @@ Notes: using namespace sat; + +std::ostream& ccc::decision::pp(std::ostream& out) const { + return out << "(" << m_id << " " << m_last << " d:" << m_depth << ") "; +} + +std::ostream& ccc::pp(std::ostream& out, svector const& v) { + for (unsigned i = 0; i < v.size(); ++i) { + v[i].pp(out); + } + return out; +} + lbool ccc::cube() { unsigned branch_id = 0; unsigned_vector id_trail; @@ -33,20 +45,30 @@ lbool ccc::cube() { lookahead::scoped_level _sl(lh, lh.c_fixed_truth); literal_vector trail; + svector decisions; lh.m_search_mode = lookahead_mode::searching; while (!m_cancel) { - // remove old branch ids from id_trail. - while (id_trail.size() > trail.size()) { + + s.checkpoint(); + + SASSERT(trail.size() <= decisions.size()); + while (trail.size() < decisions.size()) { + check_non_model("lh inconsistent ", decisions); + decisions.pop_back(); id_trail.pop_back(); } + SASSERT(id_trail.size() == trail.size()); + SASSERT(id_trail.size() == decisions.size()); + TRACE("sat", lh.display(tout);); - lh.inc_istamp(); - s.checkpoint(); + if (lh.inconsistent()) { if (!lh.backtrack(trail)) return l_false; continue; } + lh.inc_istamp(); + // check if CDCL solver got ahead. bool repeat = false; #pragma omp critical (ccc_solved) @@ -64,13 +86,6 @@ lbool ccc::cube() { } if (repeat) continue; - ++branch_id; - if (!trail.empty()) { - #pragma omp critical (ccc_decisions) - { - m_decisions.push(decision(branch_id, trail.size()-1, trail.back())); - } - } literal l = lh.choose(); if (lh.inconsistent()) { @@ -83,13 +98,27 @@ lbool ccc::cube() { } // update trail and set of ids + + ++branch_id; + ++lh.m_stats.m_decisions; + unsigned parent_id = id_trail.empty() ? 0 : id_trail.back(); + decision d(branch_id, trail.size() + 1, l, parent_id); id_trail.push_back(branch_id); trail.push_back(l); + decisions.push_back(d); SASSERT(id_trail.size() == trail.size()); - + + #pragma omp critical (ccc_log) + { + IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << " " << trail << "\n"; + pp(verbose_stream(), decisions) << "\n"; + ); + } + #pragma omp critical (ccc_decisions) + { + m_decisions.push(d); + } TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); - ++lh.m_stats.m_decisions; - IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); lh.push(l, lh.c_fixed_truth); SASSERT(lh.inconsistent() || !lh.is_unsat()); } @@ -102,31 +131,24 @@ lbool ccc::conquer(solver& s) { s.init_search(); s.propagate(false); if (s.inconsistent()) return l_false; - s.init_assumptions(0, 0); - s.propagate(false); - if (s.check_inconsistent()) return l_false; s.cleanup(); s.simplify_problem(); - if (s.check_inconsistent()) return l_false; + if (s.inconsistent()) return l_false; - unsigned_vector ids; + svector decisions; while (true) { SASSERT(!s.inconsistent()); - lbool r = bounded_search(s, ids); + lbool r = bounded_search(s, decisions); if (r != l_undef) return r; - - if (s.m_conflicts > s.m_config.m_max_conflicts) { - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << s.m_conflicts << "\")\n";); - return l_undef; - } - - s.restart(); + + s.restart(); s.simplify_problem(); if (s.check_inconsistent()) return l_false; - s.gc(); + s.gc(); + } } catch (solver::abort_solver) { @@ -134,29 +156,54 @@ lbool ccc::conquer(solver& s) { } } -lbool ccc::bounded_search(solver& s, unsigned_vector& ids) { - decision d; +void ccc::replay_decisions(solver& s, svector& decisions) { + // replay decisions + bool shortcut = false; + s.propagate(true); + for (unsigned i = s.scope_lvl(); !shortcut && !s.inconsistent() && i < decisions.size(); ++i) { + decision d = decisions[i]; + literal lit = d.m_last; + lbool val = s.value(lit); + #pragma omp critical (ccc_log) + { + IF_VERBOSE(1, verbose_stream() << "replay " << lit << " " << val << "\n";); + } + switch (val) { + case l_false: + #pragma omp critical (ccc_solved) + { + m_solved.push(d.m_id); + } + check_non_model("replay", decisions); + decisions.resize(i); + shortcut = true; + break; + case l_undef: + s.push(); + s.assign(lit, justification()); + s.propagate(false); + break; + case l_true: + s.push(); + break; + } + } +} +lbool ccc::bounded_search(solver& s, svector& decisions) { + while (true) { s.checkpoint(); bool done = false; while (!done) { + replay_decisions(s, decisions); lbool is_sat = s.propagate_and_backjump_step(done); if (is_sat != l_true) return is_sat; } - if (s.m_scope_lvl < ids.size()) { - while (ids.size() > s.m_scope_lvl + 1) ids.pop_back(); - unsigned id = ids.back(); - ids.pop_back(); - #pragma omp critical (ccc_solved) - { - m_solved.push(id); - } - } - s.gc(); + decision d; bool cube_decision = false; #pragma omp critical (ccc_decisions) { @@ -165,12 +212,38 @@ lbool ccc::bounded_search(solver& s, unsigned_vector& ids) { cube_decision = true; } } + if (cube_decision) { - if (d.m_depth > ids.size()) continue; - ids.push_back(d.m_id); - s.pop_reinit(s.m_scope_lvl - d.m_depth); // TBD: check alignment of scopes - s.push(); - s.assign(d.m_last, justification()); + if (d.m_depth > 1 + decisions.size()) continue; + while (!decisions.empty() && decisions.back().m_depth >= d.m_depth) { + SASSERT(decisions.back().m_depth == decisions.size()); + check_non_model("cube decision", decisions); + decisions.pop_back(); + } + SASSERT(decisions.empty() || decisions.back().m_depth + 1 == d.m_depth); + SASSERT(decisions.empty() || decisions.back().m_id == d.m_parent); + decisions.push_back(d); + s.pop_reinit(s.m_scope_lvl + 1 - d.m_depth); // TBD: check alignment of scopes + literal lit = d.m_last; + #pragma omp critical (ccc_log) + { + IF_VERBOSE(1, pp(verbose_stream() << "push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; + if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); + } + switch (s.value(lit)) { + case l_false: + decisions.pop_back(); + #pragma omp critical (ccc_solved) + { + m_solved.push(d.m_id); + } + break; + case l_true: + case l_undef: + s.push(); + s.assign(lit, justification()); + break; + } } else if (!s.decide()) { lbool is_sat = s.final_check(); @@ -181,6 +254,541 @@ lbool ccc::bounded_search(solver& s, unsigned_vector& ids) { } } +void ccc::set_model() { + push_model(1, false); + push_model(2, false); + push_model(3, false); + push_model(4, false); + push_model(5, false); + push_model(6, false); + push_model(7, false); + push_model(8, false); + push_model(9, true); + push_model(10, true); + push_model(11, true); + push_model(12, true); + push_model(13, true); + push_model(14, true); + push_model(15, true); + push_model(16, true); + push_model(17, true); + push_model(18, true); + push_model(19, true); + push_model(20, true); + push_model(21, true); + push_model(22, true); + push_model(23, true); +push_model(24, true); +push_model(25, true); +push_model(26, true); +push_model(27, true); +push_model(28, true); +push_model(29, true); +push_model(30, true); +push_model(31, true); +push_model(32, true); +push_model(33, true); +push_model(34, true); +push_model(35, true); +push_model(36, true); +push_model(37, true); +push_model(38, true); +push_model(39, true); +push_model(40, true); +push_model(41, false); +push_model(42, true); +push_model(43, true); +push_model(44, true); +push_model(45, true); +push_model(46, true); +push_model(47, true); +push_model(48, false); +push_model(49, true); +push_model(50, true); +push_model(51, true); +push_model(52, true); +push_model(53, true); +push_model(54, false); +push_model(55, true); +push_model(56, true); +push_model(57, true); +push_model(58, true); +push_model(59, true); +push_model(60, true); +push_model(61, true); +push_model(62, true); +push_model(63, true); +push_model(64, true); +push_model(65, true); +push_model(66, true); +push_model(67, true); +push_model(68, false); +push_model(69, true); +push_model(70, true); +push_model(71, false); +push_model(72, true); +push_model(73, true); +push_model(74, true); +push_model(75, true); +push_model(76, true); +push_model(77, true); +push_model(78, true); +push_model(79, true); +push_model(80, true); +push_model(81, true); +push_model(82, false); +push_model(83, true); +push_model(84, true); +push_model(85, true); +push_model(86, true); +push_model(87, true); +push_model(88, true); +push_model(89, true); +push_model(90, true); +push_model(91, false); +push_model(92, true); +push_model(93, true); +push_model(94, true); +push_model(95, true); +push_model(96, true); +push_model(97, true); +push_model(98, true); +push_model(99, false); +push_model(100, true); +push_model(101, true); +push_model(102, true); +push_model(103, true); +push_model(104, true); +push_model(105, true); +push_model(106, true); +push_model(107, true); +push_model(108, true); +push_model(109, true); +push_model(110, true); +push_model(111, true); +push_model(112, true); +push_model(113, false); +push_model(114, true); +push_model(115, true); +push_model(116, true); +push_model(117, true); +push_model(118, true); +push_model(119, true); +push_model(120, false); +push_model(121, true); +push_model(122, true); +push_model(123, true); +push_model(124, true); +push_model(125, true); +push_model(126, false); +push_model(127, true); +push_model(128, true); +push_model(129, true); +push_model(130, true); +push_model(131, true); +push_model(132, true); +push_model(133, true); +push_model(134, true); +push_model(135, true); +push_model(136, true); +push_model(137, true); +push_model(138, true); +push_model(139, false); +push_model(140, true); +push_model(141, true); +push_model(142, true); +push_model(143, false); +push_model(144, true); +push_model(145, true); +push_model(146, true); +push_model(147, true); +push_model(148, false); +push_model(149, true); +push_model(150, true); +push_model(151, true); +push_model(152, true); +push_model(153, true); +push_model(154, true); +push_model(155, true); +push_model(156, true); +push_model(157, true); +push_model(158, true); +push_model(159, true); +push_model(160, false); +push_model(161, true); +push_model(162, true); +push_model(163, true); +push_model(164, false); +push_model(165, true); +push_model(166, true); +push_model(167, true); +push_model(168, true); +push_model(169, true); +push_model(170, true); +push_model(171, true); +push_model(172, true); +push_model(173, true); +push_model(174, true); +push_model(175, true); +push_model(176, true); +push_model(177, true); +push_model(178, true); +push_model(179, true); +push_model(180, true); +push_model(181, true); +push_model(182, true); +push_model(183, true); +push_model(184, true); +push_model(185, false); +push_model(186, true); +push_model(187, true); +push_model(188, true); +push_model(189, true); +push_model(190, true); +push_model(191, true); +push_model(192, false); +push_model(193, true); +push_model(194, true); +push_model(195, true); +push_model(196, true); +push_model(197, true); +push_model(198, false); +push_model(199, true); +push_model(200, true); +push_model(201, true); +push_model(202, true); +push_model(203, true); +push_model(204, true); +push_model(205, true); +push_model(206, true); +push_model(207, true); +push_model(208, true); +push_model(209, true); +push_model(210, false); +push_model(211, false); +push_model(212, true); +push_model(213, true); +push_model(214, true); +push_model(215, true); +push_model(216, true); +push_model(217, true); +push_model(218, true); +push_model(219, true); +push_model(220, true); +push_model(221, true); +push_model(222, true); +push_model(223, true); +push_model(224, true); +push_model(225, false); +push_model(226, true); +push_model(227, true); +push_model(228, true); +push_model(229, true); +push_model(230, true); +push_model(231, false); +push_model(232, true); +push_model(233, true); +push_model(234, true); +push_model(235, false); +push_model(236, true); +push_model(237, true); +push_model(238, true); +push_model(239, true); +push_model(240, true); +push_model(241, true); +push_model(242, true); +push_model(243, true); +push_model(244, true); +push_model(245, true); +push_model(246, true); +push_model(247, true); +push_model(248, true); +push_model(249, false); +push_model(250, true); +push_model(251, true); +push_model(252, true); +push_model(253, true); +push_model(254, true); +push_model(255, true); +push_model(256, true); +push_model(257, true); +push_model(258, true); +push_model(259, true); +push_model(260, true); +push_model(261, true); +push_model(262, true); +push_model(263, false); +push_model(264, true); +push_model(265, true); +push_model(266, true); +push_model(267, true); +push_model(268, true); +push_model(269, false); +push_model(270, true); +push_model(271, true); +push_model(272, true); +push_model(273, false); +push_model(274, true); +push_model(275, true); +push_model(276, true); +push_model(277, true); +push_model(278, true); +push_model(279, true); +push_model(280, true); +push_model(281, true); +push_model(282, true); +push_model(283, true); +push_model(284, false); +push_model(285, true); +push_model(286, true); +push_model(287, true); +push_model(288, true); +push_model(289, true); +push_model(290, true); +push_model(291, true); +push_model(292, true); +push_model(293, true); +push_model(294, false); +push_model(295, true); +push_model(296, true); +push_model(297, true); +push_model(298, true); +push_model(299, true); +push_model(300, true); +push_model(301, false); +push_model(302, true); +push_model(303, true); +push_model(304, true); +push_model(305, false); +push_model(306, true); +push_model(307, true); +push_model(308, true); +push_model(309, true); +push_model(310, true); +push_model(311, true); +push_model(312, true); +push_model(313, true); +push_model(314, true); +push_model(315, true); +push_model(316, true); +push_model(317, true); +push_model(318, true); +push_model(319, false); +push_model(320, true); +push_model(321, true); +push_model(322, true); +push_model(323, true); +push_model(324, true); +push_model(325, true); +push_model(326, false); +push_model(327, true); +push_model(328, true); +push_model(329, true); +push_model(330, true); +push_model(331, true); +push_model(332, true); +push_model(333, true); +push_model(334, false); +push_model(335, true); +push_model(336, true); +push_model(337, true); +push_model(338, true); +push_model(339, true); +push_model(340, false); +push_model(341, true); +push_model(342, true); +push_model(343, true); +push_model(344, true); +push_model(345, true); +push_model(346, true); +push_model(347, true); +push_model(348, true); +push_model(349, true); +push_model(350, true); +push_model(351, true); +push_model(352, true); +push_model(353, false); +push_model(354, true); +push_model(355, true); +push_model(356, true); +push_model(357, true); +push_model(358, true); +push_model(359, true); +push_model(360, true); +push_model(361, true); +push_model(362, false); +push_model(363, false); +push_model(364, true); +push_model(365, true); +push_model(366, true); +push_model(367, true); +push_model(368, true); +push_model(369, true); +push_model(370, true); +push_model(371, true); +push_model(372, true); +push_model(373, true); +push_model(374, false); +push_model(375, true); +push_model(376, true); +push_model(377, true); +push_model(378, true); +push_model(379, true); +push_model(380, true); +push_model(381, true); +push_model(382, true); +push_model(383, true); +push_model(384, true); +push_model(385, true); +push_model(386, true); +push_model(387, true); +push_model(388, false); +push_model(389, true); +push_model(390, true); +push_model(391, true); +push_model(392, true); +push_model(393, true); +push_model(394, false); +push_model(395, true); +push_model(396, true); +push_model(397, true); +push_model(398, true); +push_model(399, true); +push_model(400, true); +push_model(401, false); +push_model(402, true); +push_model(403, true); +push_model(404, true); +push_model(405, true); +push_model(406, true); +push_model(407, true); +push_model(408, false); +push_model(409, true); +push_model(410, true); +push_model(411, true); +push_model(412, true); +push_model(413, true); +push_model(414, false); +push_model(415, true); +push_model(416, true); +push_model(417, true); +push_model(418, true); +push_model(419, true); +push_model(420, true); +push_model(421, true); +push_model(422, true); +push_model(423, true); +push_model(424, true); +push_model(425, true); +push_model(426, true); +push_model(427, true); +push_model(428, true); +push_model(429, false); +push_model(430, true); +push_model(431, false); +push_model(432, true); +push_model(433, true); +push_model(434, true); +push_model(435, true); +push_model(436, true); +push_model(437, true); +push_model(438, true); +push_model(439, true); +push_model(440, true); +push_model(441, true); +push_model(442, false); +push_model(443, true); +push_model(444, true); +push_model(445, true); +push_model(446, true); +push_model(447, true); +push_model(448, true); +push_model(449, true); +push_model(450, true); +push_model(451, true); +push_model(452, true); +push_model(453, false); +push_model(454, true); +push_model(455, true); +push_model(456, true); +push_model(457, true); +push_model(458, false); +push_model(459, true); +push_model(460, true); +push_model(461, true); +push_model(462, true); +push_model(463, true); +push_model(464, true); +push_model(465, true); +push_model(466, true); +push_model(467, false); +push_model(468, true); +push_model(469, true); +push_model(470, true); +push_model(471, true); +push_model(472, true); +push_model(473, true); +push_model(474, true); +push_model(475, true); +push_model(476, false); +push_model(477, true); +push_model(478, true); +push_model(479, true); +push_model(480, true); +push_model(481, true); +push_model(482, true); +push_model(483, true); +push_model(484, true); +push_model(485, false); +push_model(486, true); +push_model(487, true); +push_model(488, true); +push_model(489, true); +push_model(490, true); +push_model(491, true); +push_model(492, true); +push_model(493, true); +push_model(494, false); +push_model(495, true); +push_model(496, false); +push_model(497, true); +push_model(498, true); +push_model(499, true); +push_model(500, true); +push_model(501, true); +push_model(502, true); +push_model(503, true); +push_model(504, true); +push_model(505, false); +push_model(506, true); +push_model(507, true); +push_model(508, true); +push_model(509, true); +push_model(510, true); +push_model(511, true); +push_model(512, true); + +} + +void ccc::push_model(unsigned v, bool sign) { + if (m_values.size() <= v) { + m_values.resize(v + 1); + } + m_values[v] = sign; +} + +void ccc::check_non_model(char const* fn, svector const& decisions) { + for (unsigned i = 0; i < decisions.size(); ++i) { + decision d = decisions[i]; + literal lit = d.m_last; + if (m_values[lit.var()] != lit.sign()) return; + } + + #pragma omp critical (ccc_log) + { + pp(verbose_stream() << "backtracking from model " << fn << " ", decisions) << "\n"; + } +} lbool ccc::search() { enum par_exception_kind { @@ -188,6 +796,8 @@ lbool ccc::search() { ERROR_EX }; + set_model(); + m_cancel = false; scoped_limits scoped_rlimit(s.rlimit()); @@ -200,16 +810,17 @@ lbool ccc::search() { lbool result = l_undef; bool canceled = false; - int num_threads = s.m_config.m_num_threads + 1; + int num_threads = 2; // for ccc-infinity only two threads. s.m_config.m_num_threads + 1; for (int i = 1; i < num_threads; ++i) { limits.push_back(reslimit()); } for (int i = 1; i < num_threads; ++i) { s.m_params.set_uint("random_seed", s.m_rand()); - solvers[i] = alloc(sat::solver, s.m_params, limits[i]); - solvers[i]->copy(s); - scoped_rlimit.push_child(&solvers[i]->rlimit()); + solver* s1 = alloc(sat::solver, s.m_params, limits[i-1]); + solvers.push_back(s1); + s1->copy(s); + scoped_rlimit.push_child(&s1->rlimit()); } #pragma omp parallel for @@ -261,10 +872,18 @@ lbool ccc::search() { if (finished_id == -1) { switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); - default: throw default_exception(ex_msg.c_str()); + default: throw default_exception(ex_msg.c_str()); } } +#if 0 + if (result == l_true) { + for (unsigned i = 1; i < m_model.size(); ++i) { + std::cout << "push_model(" << i << ", " << (m_model[i] > 0 ? "false" : "true") << ");\n"; + } + } +#endif + return result; } diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h index d5357090a..da546bca1 100644 --- a/src/sat/sat_ccc.h +++ b/src/sat/sat_ccc.h @@ -23,14 +23,18 @@ Notes: namespace sat { + class ccc { struct decision { unsigned m_id; unsigned m_depth; literal m_last; - decision(unsigned id, unsigned d, literal last): - m_id(id), m_depth(d), m_last(last) {} - decision(): m_id(0), m_depth(0), m_last(null_literal) {} + unsigned m_parent; + decision(unsigned id, unsigned d, literal last, unsigned parent_id): + m_id(id), m_depth(d), m_last(last), m_parent(parent_id) {} + decision(): m_id(0), m_depth(0), m_last(null_literal), m_parent(0) {} + + std::ostream& pp(std::ostream& out) const; }; solver& s; @@ -39,6 +43,8 @@ namespace sat { model m_model; volatile bool m_cancel; + svector m_values; + struct config { config() { } @@ -50,14 +56,26 @@ namespace sat { }; lbool conquer(solver& s); - lbool bounded_search(solver& s, unsigned_vector& ids); - + lbool bounded_search(solver& s, svector& decisions); lbool cube(); + void replay_decisions(solver& s, svector& decisions); + + static std::ostream& pp(std::ostream& out, svector const& v); + + void push_model(unsigned v, bool sign); + void set_model(); + bool trail_in_model(literal_vector const& trail) const; + + void check_non_model(char const* fn, svector const& decisions); + public: + ccc(solver& s): s(s) {} lbool search(); + + model const& get_model() const { return m_model; } }; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 175c34690..45ce213b0 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -38,6 +38,7 @@ namespace sat { m_num_threads = 1; m_local_search = 0; m_lookahead_search = false; + m_ccc = false; updt_params(p); } @@ -84,6 +85,7 @@ namespace sat { m_local_search = p.local_search(); m_local_search_threads = p.local_search_threads(); m_lookahead_search = p.lookahead_search(); + m_ccc = p.ccc(); // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index fb125c529..2e3d4ec86 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -61,6 +61,7 @@ namespace sat { unsigned m_local_search_threads; bool m_local_search; bool m_lookahead_search; + bool m_ccc; unsigned m_simplify_mult1; double m_simplify_mult2; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index a69de0772..a13a8e8b5 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -30,5 +30,6 @@ def_module_params('sat', ('xor.solver', BOOL, False, 'use xor solver'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), - ('lookahead_search', BOOL, False, 'use lookahead solver') + ('lookahead_search', BOOL, False, 'use lookahead solver'), + ('ccc', BOOL, False, 'use Concurrent Cube and Conquer solver') )) diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 3dfc42f6a..aa35363b6 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -76,20 +76,18 @@ namespace sat { lowlink.resize(num_lits, UINT_MAX); in_s.resize(num_lits, false); literal_vector roots; - for (unsigned i = 0; i < m_solver.num_vars(); ++i) { - roots.push_back(literal(i, false)); - } + roots.resize(m_solver.num_vars(), null_literal); unsigned next_index = 0; svector frames; bool_var_vector to_elim; - for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { - if (index[l_idx] != UINT_MAX) - continue; - if (m_solver.was_eliminated(to_literal(l_idx).var())) - continue; - - m_solver.checkpoint(); + for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { + if (index[l_idx] != UINT_MAX) + continue; + if (m_solver.was_eliminated(to_literal(l_idx).var())) + continue; + + m_solver.checkpoint(); #define NEW_NODE(LIDX) { \ index[LIDX] = next_index; \ @@ -100,121 +98,122 @@ namespace sat { watch_list & wlist = m_solver.get_wlist(LIDX); \ frames.push_back(frame(LIDX, wlist.begin(), wlist.end())); \ } - - NEW_NODE(l_idx); - - while (!frames.empty()) { - loop: - frame & fr = frames.back(); - unsigned l_idx = fr.m_lidx; - if (!fr.m_first) { - // after visiting child - literal l2 = fr.m_it->get_literal(); - unsigned l2_idx = l2.index(); - SASSERT(index[l2_idx] != UINT_MAX); - if (lowlink[l2_idx] < lowlink[l_idx]) - lowlink[l_idx] = lowlink[l2_idx]; - fr.m_it++; - } - fr.m_first = false; - while (fr.m_it != fr.m_end) { - if (!fr.m_it->is_binary_clause()) { - fr.m_it++; - continue; - } - literal l2 = fr.m_it->get_literal(); - unsigned l2_idx = l2.index(); - if (index[l2_idx] == UINT_MAX) { - NEW_NODE(l2_idx); - goto loop; - } - else if (in_s[l2_idx]) { - if (index[l2_idx] < lowlink[l_idx]) - lowlink[l_idx] = index[l2_idx]; - } - fr.m_it++; - } - // visited all successors - if (lowlink[l_idx] == index[l_idx]) { - // found new SCC - CTRACE("scc_cycle", s.back() != l_idx, { - tout << "cycle: "; - unsigned j = s.size() - 1; - unsigned l2_idx; - do { - l2_idx = s[j]; - j--; - tout << to_literal(l2_idx) << " "; - } - while (l2_idx != l_idx); - tout << "\n"; - }); - - SASSERT(!s.empty()); - literal l = to_literal(l_idx); - bool_var v = l.var(); - if (roots[v] != null_literal) { - // variable was already assigned... just consume stack - TRACE("scc_detail", tout << "consuming stack...\n";); - unsigned l2_idx; - do { - l2_idx = s.back(); - s.pop_back(); - in_s[l2_idx] = false; - SASSERT(roots[to_literal(l2_idx).var()].var() == roots[v].var()); - } - while (l2_idx != l_idx); - } - else { - // check if the SCC has an external variable, and check for conflicts - TRACE("scc_detail", tout << "assigning roots...\n";); - literal r = null_literal; - unsigned j = s.size() - 1; - unsigned l2_idx; - do { - l2_idx = s[j]; - j--; - if (to_literal(l2_idx) == ~l) { - m_solver.set_conflict(justification()); - return 0; - } - if (m_solver.is_external(to_literal(l2_idx).var())) { - r = to_literal(l2_idx); - break; - } - } - while (l2_idx != l_idx); - - if (r == null_literal) { - // SCC does not contain external variable - r = to_literal(l_idx); - } - - TRACE("scc_detail", tout << "r: " << r << "\n";); - do { - l2_idx = s.back(); - s.pop_back(); - in_s[l2_idx] = false; - literal l2 = to_literal(l2_idx); - bool_var v2 = l2.var(); - if (roots[v2] == null_literal) { - if (l2.sign()) { - roots[v2] = ~r; - } - else { - roots[v2] = r; - } - if (v2 != r.var()) - to_elim.push_back(v2); - } - } - while (l2_idx != l_idx); - } - } - frames.pop_back(); - } - } + NEW_NODE(l_idx); + + while (!frames.empty()) { + loop: + frame & fr = frames.back(); + unsigned l_idx = fr.m_lidx; + if (!fr.m_first) { + // after visiting child + literal l2 = fr.m_it->get_literal(); + unsigned l2_idx = l2.index(); + SASSERT(index[l2_idx] != UINT_MAX); + if (lowlink[l2_idx] < lowlink[l_idx]) + lowlink[l_idx] = lowlink[l2_idx]; + fr.m_it++; + } + fr.m_first = false; + while (fr.m_it != fr.m_end) { + if (!fr.m_it->is_binary_clause()) { + fr.m_it++; + continue; + } + literal l2 = fr.m_it->get_literal(); + unsigned l2_idx = l2.index(); + if (index[l2_idx] == UINT_MAX) { + NEW_NODE(l2_idx); + goto loop; + } + else if (in_s[l2_idx]) { + if (index[l2_idx] < lowlink[l_idx]) + lowlink[l_idx] = index[l2_idx]; + } + fr.m_it++; + } + // visited all successors + if (lowlink[l_idx] == index[l_idx]) { + // found new SCC + CTRACE("scc_cycle", s.back() != l_idx, { + tout << "cycle: "; + unsigned j = s.size() - 1; + unsigned l2_idx; + do { + l2_idx = s[j]; + j--; + tout << to_literal(l2_idx) << " "; + } while (l2_idx != l_idx); + tout << "\n"; + }); + + SASSERT(!s.empty()); + literal l = to_literal(l_idx); + bool_var v = l.var(); + if (roots[v] != null_literal) { + // variable was already assigned... just consume stack + TRACE("scc_detail", tout << "consuming stack...\n";); + unsigned l2_idx; + do { + l2_idx = s.back(); + s.pop_back(); + in_s[l2_idx] = false; + SASSERT(roots[to_literal(l2_idx).var()].var() == roots[v].var()); + } while (l2_idx != l_idx); + } + else { + // check if the SCC has an external variable, and check for conflicts + TRACE("scc_detail", tout << "assigning roots...\n";); + literal r = null_literal; + unsigned j = s.size() - 1; + unsigned l2_idx; + do { + l2_idx = s[j]; + j--; + if (to_literal(l2_idx) == ~l) { + m_solver.set_conflict(justification()); + return 0; + } + if (m_solver.is_external(to_literal(l2_idx).var())) { + r = to_literal(l2_idx); + break; + } + } while (l2_idx != l_idx); + + if (r == null_literal) { + // SCC does not contain external variable + r = to_literal(l_idx); + } + + TRACE("scc_detail", tout << "r: " << r << "\n";); + + do { + l2_idx = s.back(); + s.pop_back(); + in_s[l2_idx] = false; + literal l2 = to_literal(l2_idx); + bool_var v2 = l2.var(); + if (roots[v2] == null_literal) { + if (l2.sign()) { + roots[v2] = ~r; + } + else { + roots[v2] = r; + } + if (v2 != r.var()) + to_elim.push_back(v2); + } + } while (l2_idx != l_idx); + } + } + frames.pop_back(); + } + } + for (unsigned i = 0; i < m_solver.num_vars(); ++i) { + if (roots[i] == null_literal) { + roots[i] = literal(i, false); + } + } TRACE("scc", for (unsigned i = 0; i < roots.size(); i++) { tout << i << " -> " << roots[i] << "\n"; } tout << "to_elim: "; for (unsigned i = 0; i < to_elim.size(); i++) tout << to_elim[i] << " "; tout << "\n";); m_num_elim += to_elim.size(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8eaba2734..4647ddb36 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -23,6 +23,7 @@ Revision History: #include"max_cliques.h" #include"scoped_ptr_vector.h" #include"sat_lookahead.h" +#include"sat_ccc.h" // define to update glue during propagation #define UPDATE_GLUE @@ -790,6 +791,9 @@ namespace sat { if (m_config.m_local_search) { return do_local_search(num_lits, lits); } + if (m_config.m_ccc && num_lits == 0) { + return do_ccc(); + } if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0) && !m_par) { return check_par(num_lits, lits); } @@ -874,6 +878,13 @@ namespace sat { return r; } + lbool solver::do_ccc() { + ccc c(*this); + lbool r = c.search(); + m_model = c.get_model(); + return r; + } + lbool solver::lookahead_search() { lookahead lh(*this); lbool r = l_undef; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b4b7f82fe..fda8362ca 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -351,6 +351,7 @@ namespace sat { lbool check_par(unsigned num_lits, literal const* lits); lbool lookahead_search(); lbool do_local_search(unsigned num_lits, literal const* lits); + lbool do_ccc(); // ----------------------- // From 07fe45e92330a7d30e3d25def3e696d31f1e377f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 22 Apr 2017 11:40:47 -0700 Subject: [PATCH 0105/1283] ccc Signed-off-by: Nikolaj Bjorner --- src/sat/sat_ccc.cpp | 801 ++++++++++------------------------------ src/sat/sat_ccc.h | 17 +- src/sat/sat_lookahead.h | 4 +- src/sat/sat_scc.cpp | 238 ++++++------ 4 files changed, 340 insertions(+), 720 deletions(-) diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp index bb60a99e3..141869f11 100644 --- a/src/sat/sat_ccc.cpp +++ b/src/sat/sat_ccc.cpp @@ -35,11 +35,11 @@ std::ostream& ccc::pp(std::ostream& out, svector const& v) { return out; } -lbool ccc::cube() { +lbool ccc::cube2() { unsigned branch_id = 0; unsigned_vector id_trail; - lookahead lh(s); + lookahead lh(m_s); lh.init_search(); lh.m_model.reset(); @@ -47,13 +47,115 @@ lbool ccc::cube() { literal_vector trail; svector decisions; lh.m_search_mode = lookahead_mode::searching; + lh.m_blocked_literal = null_literal; + lbool r = cube2(branch_id, decisions, lh); + if (r == l_true) { + m_model = lh.get_model(); + } + return r; +} + +lbool ccc::cube2(unsigned& branch_id, svector& decisions, lookahead& lh) { + m_s.checkpoint(); + + if (lh.inconsistent()) { + return l_false; + } + + lh.inc_istamp(); + + // check if CDCL solver got ahead. + bool repeat = false; + #pragma omp critical (ccc_solved) + { + while (!m_solved.empty()) { + unsigned solved_id = m_solved.top(); + if (contains_branch(decisions, solved_id)) { + IF_VERBOSE(1, verbose_stream() << "conquer " << decisions.size() << "\n";); + repeat = true; + break; + } + else { + m_solved.pop(); + } + } + } + if (repeat) return l_false; + + literal l = lh.choose(); + if (lh.inconsistent()) { + return l_false; + } + + if (l == null_literal) { + return l_true; + } + + if (!decisions.empty()) { + #pragma omp critical (ccc_decisions) + { + m_decisions.push(decisions.back()); + } + } + + // update trail and set of ids + + ++branch_id; + ++lh.m_stats.m_decisions; + unsigned parent_id = decisions.empty() ? 0 : decisions.back().m_id; + decision d(branch_id, decisions.size() + 1, l, null_literal, parent_id); + decisions.push_back(d); + + #pragma omp critical (ccc_log) + { + IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); + IF_VERBOSE(2, pp(verbose_stream(), decisions) << "\n"; ); + } + TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); + lh.push(l, lh.c_fixed_truth); + lbool r = cube2(branch_id, decisions, lh); + if (r == l_false) { + lh.pop(); + lh.flip_prefix(); + lh.push(~l, lh.c_fixed_truth); + decisions.back().m_last = ~l; + r = cube2(branch_id, decisions, lh); + if (r == l_false) { + lh.pop(); + decisions.pop_back(); + } + } + return r; +} + +bool ccc::contains_branch(svector const& decisions, unsigned branch_id) const { + for (unsigned i = 0; i < decisions.size(); ++i) { + if (branch_id == decisions[i].m_id) return true; + } + return false; +} + + +lbool ccc::cube() { + unsigned branch_id = 0; + unsigned_vector id_trail; + + lookahead lh(m_s); + lh.init_search(); + lh.m_model.reset(); + + lookahead::scoped_level _sl(lh, lh.c_fixed_truth); + literal_vector trail; + svector decisions; + lh.m_search_mode = lookahead_mode::searching; + lh.m_blocked_literal = null_literal; while (!m_cancel) { - s.checkpoint(); + m_s.checkpoint(); SASSERT(trail.size() <= decisions.size()); while (trail.size() < decisions.size()) { - check_non_model("lh inconsistent ", decisions); + //check_non_model("lh inconsistent ", decisions); decisions.pop_back(); id_trail.pop_back(); } @@ -76,6 +178,7 @@ lbool ccc::cube() { if (!m_solved.empty()) { unsigned solved_id = m_solved.top(); if (id_trail.contains(solved_id)) { + IF_VERBOSE(1, verbose_stream() << "cconquer " << decisions.size() << "\n";); lh.set_conflict(); } else { @@ -86,7 +189,6 @@ lbool ccc::cube() { } if (repeat) continue; - literal l = lh.choose(); if (lh.inconsistent()) { if (!lh.backtrack(trail)) return l_false; @@ -102,17 +204,17 @@ lbool ccc::cube() { ++branch_id; ++lh.m_stats.m_decisions; unsigned parent_id = id_trail.empty() ? 0 : id_trail.back(); - decision d(branch_id, trail.size() + 1, l, parent_id); + decision d(branch_id, trail.size() + 1, l, lh.m_blocked_literal, parent_id); id_trail.push_back(branch_id); trail.push_back(l); decisions.push_back(d); SASSERT(id_trail.size() == trail.size()); + lh.m_blocked_literal = null_literal; #pragma omp critical (ccc_log) { - IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << " " << trail << "\n"; - pp(verbose_stream(), decisions) << "\n"; - ); + IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); + IF_VERBOSE(2, verbose_stream() << " " << trail << "\n"; pp(verbose_stream(), decisions) << "\n"; ); } #pragma omp critical (ccc_decisions) { @@ -148,7 +250,6 @@ lbool ccc::conquer(solver& s) { s.simplify_problem(); if (s.check_inconsistent()) return l_false; s.gc(); - } } catch (solver::abort_solver) { @@ -157,41 +258,110 @@ lbool ccc::conquer(solver& s) { } void ccc::replay_decisions(solver& s, svector& decisions) { - // replay decisions - bool shortcut = false; s.propagate(true); - for (unsigned i = s.scope_lvl(); !shortcut && !s.inconsistent() && i < decisions.size(); ++i) { + for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < decisions.size(); ++i) { decision d = decisions[i]; literal lit = d.m_last; lbool val = s.value(lit); #pragma omp critical (ccc_log) { - IF_VERBOSE(1, verbose_stream() << "replay " << lit << " " << val << "\n";); + IF_VERBOSE(2, verbose_stream() << "replay " << lit << " " << val << "\n";); } - switch (val) { + if (!push_decision(s, d)) { + // negation of decision is implied. + // check_non_model("replay", decisions); + decisions.resize(i); + return; + } + } +} + +bool ccc::push_decision(solver& s, decision const& d) { + literal lit = d.m_last; + switch (s.value(lit)) { + case l_false: + #pragma omp critical (ccc_solved) + { + m_solved.push(d.m_id); + } + //TBD: + s.m_restart_threshold = s.m_config.m_restart_initial; + //s.m_conflicts_since_last_restart = 0; + return false; + case l_true: + s.push(); + break; + case l_undef: + s.push(); + s.assign(lit, justification()); + s.propagate(true); + break; + } + literal blocked = d.m_blocked; + if (false && blocked != null_literal) { + switch (s.value(blocked)) { case l_false: #pragma omp critical (ccc_solved) { m_solved.push(d.m_id); } - check_non_model("replay", decisions); - decisions.resize(i); - shortcut = true; + return false; + case l_true: break; case l_undef: - s.push(); - s.assign(lit, justification()); - s.propagate(false); + //s.assign(blocked, justification()); + //s.propagate(true); break; - case l_true: - s.push(); - break; } - } + } + return true; } -lbool ccc::bounded_search(solver& s, svector& decisions) { +bool ccc::cube_decision(solver& s, svector& decisions) { + decision d; + bool use_cube_decision = false; + SASSERT(s.m_qhead == s.m_trail.size()); + get_cube: + #pragma omp critical (ccc_decisions) + { + if (!m_decisions.empty()) { + d = m_decisions.pop(); + use_cube_decision = true; + } + } + + if (!use_cube_decision) { + return false; + } + if (!decisions.empty() && decisions.back().m_depth + 1 < d.m_depth) { + goto get_cube; + } + + while (!decisions.empty() && decisions.back().m_depth >= d.m_depth) { + // check_non_model("cube decision", decisions); + decisions.pop_back(); + } + SASSERT(decisions.empty() || decisions.back().m_depth + 1 == d.m_depth); + SASSERT(decisions.empty() || decisions.back().m_id == d.m_parent); + s.pop_reinit(s.scope_lvl() - decisions.size()); + SASSERT(s.m_qhead == s.m_trail.size()); + SASSERT(s.scope_lvl() == decisions.size()); + #pragma omp critical (ccc_log) + { + literal lit = d.m_last; + IF_VERBOSE(1, verbose_stream() << "cube " << decisions.size() << "\n";); + IF_VERBOSE(2, pp(verbose_stream() << "push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; + if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); + } + if (push_decision(s, d)) { + decisions.push_back(d); + } + + return true; +} + +lbool ccc::bounded_search(solver& s, svector& decisions) { while (true) { s.checkpoint(); bool done = false; @@ -202,50 +372,8 @@ lbool ccc::bounded_search(solver& s, svector& decisions) { } s.gc(); - - decision d; - bool cube_decision = false; - #pragma omp critical (ccc_decisions) - { - if (!m_decisions.empty()) { - d = m_decisions.pop(); - cube_decision = true; - } - } - - if (cube_decision) { - if (d.m_depth > 1 + decisions.size()) continue; - while (!decisions.empty() && decisions.back().m_depth >= d.m_depth) { - SASSERT(decisions.back().m_depth == decisions.size()); - check_non_model("cube decision", decisions); - decisions.pop_back(); - } - SASSERT(decisions.empty() || decisions.back().m_depth + 1 == d.m_depth); - SASSERT(decisions.empty() || decisions.back().m_id == d.m_parent); - decisions.push_back(d); - s.pop_reinit(s.m_scope_lvl + 1 - d.m_depth); // TBD: check alignment of scopes - literal lit = d.m_last; - #pragma omp critical (ccc_log) - { - IF_VERBOSE(1, pp(verbose_stream() << "push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; - if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); - } - switch (s.value(lit)) { - case l_false: - decisions.pop_back(); - #pragma omp critical (ccc_solved) - { - m_solved.push(d.m_id); - } - break; - case l_true: - case l_undef: - s.push(); - s.assign(lit, justification()); - break; - } - } - else if (!s.decide()) { + + if (!cube_decision(s, decisions) && !s.decide()) { lbool is_sat = s.final_check(); if (is_sat != l_undef) { return is_sat; @@ -254,521 +382,6 @@ lbool ccc::bounded_search(solver& s, svector& decisions) { } } -void ccc::set_model() { - push_model(1, false); - push_model(2, false); - push_model(3, false); - push_model(4, false); - push_model(5, false); - push_model(6, false); - push_model(7, false); - push_model(8, false); - push_model(9, true); - push_model(10, true); - push_model(11, true); - push_model(12, true); - push_model(13, true); - push_model(14, true); - push_model(15, true); - push_model(16, true); - push_model(17, true); - push_model(18, true); - push_model(19, true); - push_model(20, true); - push_model(21, true); - push_model(22, true); - push_model(23, true); -push_model(24, true); -push_model(25, true); -push_model(26, true); -push_model(27, true); -push_model(28, true); -push_model(29, true); -push_model(30, true); -push_model(31, true); -push_model(32, true); -push_model(33, true); -push_model(34, true); -push_model(35, true); -push_model(36, true); -push_model(37, true); -push_model(38, true); -push_model(39, true); -push_model(40, true); -push_model(41, false); -push_model(42, true); -push_model(43, true); -push_model(44, true); -push_model(45, true); -push_model(46, true); -push_model(47, true); -push_model(48, false); -push_model(49, true); -push_model(50, true); -push_model(51, true); -push_model(52, true); -push_model(53, true); -push_model(54, false); -push_model(55, true); -push_model(56, true); -push_model(57, true); -push_model(58, true); -push_model(59, true); -push_model(60, true); -push_model(61, true); -push_model(62, true); -push_model(63, true); -push_model(64, true); -push_model(65, true); -push_model(66, true); -push_model(67, true); -push_model(68, false); -push_model(69, true); -push_model(70, true); -push_model(71, false); -push_model(72, true); -push_model(73, true); -push_model(74, true); -push_model(75, true); -push_model(76, true); -push_model(77, true); -push_model(78, true); -push_model(79, true); -push_model(80, true); -push_model(81, true); -push_model(82, false); -push_model(83, true); -push_model(84, true); -push_model(85, true); -push_model(86, true); -push_model(87, true); -push_model(88, true); -push_model(89, true); -push_model(90, true); -push_model(91, false); -push_model(92, true); -push_model(93, true); -push_model(94, true); -push_model(95, true); -push_model(96, true); -push_model(97, true); -push_model(98, true); -push_model(99, false); -push_model(100, true); -push_model(101, true); -push_model(102, true); -push_model(103, true); -push_model(104, true); -push_model(105, true); -push_model(106, true); -push_model(107, true); -push_model(108, true); -push_model(109, true); -push_model(110, true); -push_model(111, true); -push_model(112, true); -push_model(113, false); -push_model(114, true); -push_model(115, true); -push_model(116, true); -push_model(117, true); -push_model(118, true); -push_model(119, true); -push_model(120, false); -push_model(121, true); -push_model(122, true); -push_model(123, true); -push_model(124, true); -push_model(125, true); -push_model(126, false); -push_model(127, true); -push_model(128, true); -push_model(129, true); -push_model(130, true); -push_model(131, true); -push_model(132, true); -push_model(133, true); -push_model(134, true); -push_model(135, true); -push_model(136, true); -push_model(137, true); -push_model(138, true); -push_model(139, false); -push_model(140, true); -push_model(141, true); -push_model(142, true); -push_model(143, false); -push_model(144, true); -push_model(145, true); -push_model(146, true); -push_model(147, true); -push_model(148, false); -push_model(149, true); -push_model(150, true); -push_model(151, true); -push_model(152, true); -push_model(153, true); -push_model(154, true); -push_model(155, true); -push_model(156, true); -push_model(157, true); -push_model(158, true); -push_model(159, true); -push_model(160, false); -push_model(161, true); -push_model(162, true); -push_model(163, true); -push_model(164, false); -push_model(165, true); -push_model(166, true); -push_model(167, true); -push_model(168, true); -push_model(169, true); -push_model(170, true); -push_model(171, true); -push_model(172, true); -push_model(173, true); -push_model(174, true); -push_model(175, true); -push_model(176, true); -push_model(177, true); -push_model(178, true); -push_model(179, true); -push_model(180, true); -push_model(181, true); -push_model(182, true); -push_model(183, true); -push_model(184, true); -push_model(185, false); -push_model(186, true); -push_model(187, true); -push_model(188, true); -push_model(189, true); -push_model(190, true); -push_model(191, true); -push_model(192, false); -push_model(193, true); -push_model(194, true); -push_model(195, true); -push_model(196, true); -push_model(197, true); -push_model(198, false); -push_model(199, true); -push_model(200, true); -push_model(201, true); -push_model(202, true); -push_model(203, true); -push_model(204, true); -push_model(205, true); -push_model(206, true); -push_model(207, true); -push_model(208, true); -push_model(209, true); -push_model(210, false); -push_model(211, false); -push_model(212, true); -push_model(213, true); -push_model(214, true); -push_model(215, true); -push_model(216, true); -push_model(217, true); -push_model(218, true); -push_model(219, true); -push_model(220, true); -push_model(221, true); -push_model(222, true); -push_model(223, true); -push_model(224, true); -push_model(225, false); -push_model(226, true); -push_model(227, true); -push_model(228, true); -push_model(229, true); -push_model(230, true); -push_model(231, false); -push_model(232, true); -push_model(233, true); -push_model(234, true); -push_model(235, false); -push_model(236, true); -push_model(237, true); -push_model(238, true); -push_model(239, true); -push_model(240, true); -push_model(241, true); -push_model(242, true); -push_model(243, true); -push_model(244, true); -push_model(245, true); -push_model(246, true); -push_model(247, true); -push_model(248, true); -push_model(249, false); -push_model(250, true); -push_model(251, true); -push_model(252, true); -push_model(253, true); -push_model(254, true); -push_model(255, true); -push_model(256, true); -push_model(257, true); -push_model(258, true); -push_model(259, true); -push_model(260, true); -push_model(261, true); -push_model(262, true); -push_model(263, false); -push_model(264, true); -push_model(265, true); -push_model(266, true); -push_model(267, true); -push_model(268, true); -push_model(269, false); -push_model(270, true); -push_model(271, true); -push_model(272, true); -push_model(273, false); -push_model(274, true); -push_model(275, true); -push_model(276, true); -push_model(277, true); -push_model(278, true); -push_model(279, true); -push_model(280, true); -push_model(281, true); -push_model(282, true); -push_model(283, true); -push_model(284, false); -push_model(285, true); -push_model(286, true); -push_model(287, true); -push_model(288, true); -push_model(289, true); -push_model(290, true); -push_model(291, true); -push_model(292, true); -push_model(293, true); -push_model(294, false); -push_model(295, true); -push_model(296, true); -push_model(297, true); -push_model(298, true); -push_model(299, true); -push_model(300, true); -push_model(301, false); -push_model(302, true); -push_model(303, true); -push_model(304, true); -push_model(305, false); -push_model(306, true); -push_model(307, true); -push_model(308, true); -push_model(309, true); -push_model(310, true); -push_model(311, true); -push_model(312, true); -push_model(313, true); -push_model(314, true); -push_model(315, true); -push_model(316, true); -push_model(317, true); -push_model(318, true); -push_model(319, false); -push_model(320, true); -push_model(321, true); -push_model(322, true); -push_model(323, true); -push_model(324, true); -push_model(325, true); -push_model(326, false); -push_model(327, true); -push_model(328, true); -push_model(329, true); -push_model(330, true); -push_model(331, true); -push_model(332, true); -push_model(333, true); -push_model(334, false); -push_model(335, true); -push_model(336, true); -push_model(337, true); -push_model(338, true); -push_model(339, true); -push_model(340, false); -push_model(341, true); -push_model(342, true); -push_model(343, true); -push_model(344, true); -push_model(345, true); -push_model(346, true); -push_model(347, true); -push_model(348, true); -push_model(349, true); -push_model(350, true); -push_model(351, true); -push_model(352, true); -push_model(353, false); -push_model(354, true); -push_model(355, true); -push_model(356, true); -push_model(357, true); -push_model(358, true); -push_model(359, true); -push_model(360, true); -push_model(361, true); -push_model(362, false); -push_model(363, false); -push_model(364, true); -push_model(365, true); -push_model(366, true); -push_model(367, true); -push_model(368, true); -push_model(369, true); -push_model(370, true); -push_model(371, true); -push_model(372, true); -push_model(373, true); -push_model(374, false); -push_model(375, true); -push_model(376, true); -push_model(377, true); -push_model(378, true); -push_model(379, true); -push_model(380, true); -push_model(381, true); -push_model(382, true); -push_model(383, true); -push_model(384, true); -push_model(385, true); -push_model(386, true); -push_model(387, true); -push_model(388, false); -push_model(389, true); -push_model(390, true); -push_model(391, true); -push_model(392, true); -push_model(393, true); -push_model(394, false); -push_model(395, true); -push_model(396, true); -push_model(397, true); -push_model(398, true); -push_model(399, true); -push_model(400, true); -push_model(401, false); -push_model(402, true); -push_model(403, true); -push_model(404, true); -push_model(405, true); -push_model(406, true); -push_model(407, true); -push_model(408, false); -push_model(409, true); -push_model(410, true); -push_model(411, true); -push_model(412, true); -push_model(413, true); -push_model(414, false); -push_model(415, true); -push_model(416, true); -push_model(417, true); -push_model(418, true); -push_model(419, true); -push_model(420, true); -push_model(421, true); -push_model(422, true); -push_model(423, true); -push_model(424, true); -push_model(425, true); -push_model(426, true); -push_model(427, true); -push_model(428, true); -push_model(429, false); -push_model(430, true); -push_model(431, false); -push_model(432, true); -push_model(433, true); -push_model(434, true); -push_model(435, true); -push_model(436, true); -push_model(437, true); -push_model(438, true); -push_model(439, true); -push_model(440, true); -push_model(441, true); -push_model(442, false); -push_model(443, true); -push_model(444, true); -push_model(445, true); -push_model(446, true); -push_model(447, true); -push_model(448, true); -push_model(449, true); -push_model(450, true); -push_model(451, true); -push_model(452, true); -push_model(453, false); -push_model(454, true); -push_model(455, true); -push_model(456, true); -push_model(457, true); -push_model(458, false); -push_model(459, true); -push_model(460, true); -push_model(461, true); -push_model(462, true); -push_model(463, true); -push_model(464, true); -push_model(465, true); -push_model(466, true); -push_model(467, false); -push_model(468, true); -push_model(469, true); -push_model(470, true); -push_model(471, true); -push_model(472, true); -push_model(473, true); -push_model(474, true); -push_model(475, true); -push_model(476, false); -push_model(477, true); -push_model(478, true); -push_model(479, true); -push_model(480, true); -push_model(481, true); -push_model(482, true); -push_model(483, true); -push_model(484, true); -push_model(485, false); -push_model(486, true); -push_model(487, true); -push_model(488, true); -push_model(489, true); -push_model(490, true); -push_model(491, true); -push_model(492, true); -push_model(493, true); -push_model(494, false); -push_model(495, true); -push_model(496, false); -push_model(497, true); -push_model(498, true); -push_model(499, true); -push_model(500, true); -push_model(501, true); -push_model(502, true); -push_model(503, true); -push_model(504, true); -push_model(505, false); -push_model(506, true); -push_model(507, true); -push_model(508, true); -push_model(509, true); -push_model(510, true); -push_model(511, true); -push_model(512, true); - -} void ccc::push_model(unsigned v, bool sign) { if (m_values.size() <= v) { @@ -796,11 +409,11 @@ lbool ccc::search() { ERROR_EX }; - set_model(); + // set_model(); m_cancel = false; - scoped_limits scoped_rlimit(s.rlimit()); + scoped_limits scoped_rlimit(m_s.rlimit()); vector limits; ptr_vector solvers; int finished_id = -1; @@ -808,18 +421,15 @@ lbool ccc::search() { par_exception_kind ex_kind; unsigned error_code = 0; lbool result = l_undef; - bool canceled = false; int num_threads = 2; // for ccc-infinity only two threads. s.m_config.m_num_threads + 1; - for (int i = 1; i < num_threads; ++i) { - limits.push_back(reslimit()); - } for (int i = 1; i < num_threads; ++i) { - s.m_params.set_uint("random_seed", s.m_rand()); - solver* s1 = alloc(sat::solver, s.m_params, limits[i-1]); + limits.push_back(reslimit()); + m_s.m_params.set_uint("random_seed", m_s.m_rand()); + solver* s1 = alloc(sat::solver, m_s.m_params, limits.back()); solvers.push_back(s1); - s1->copy(s); + s1->copy(m_s); scoped_rlimit.push_child(&s1->rlimit()); } @@ -828,7 +438,7 @@ lbool ccc::search() { try { lbool r = l_undef; if (i == 0) { - r = cube(); + r = cube2(); } else { r = conquer(*solvers[i-1]); @@ -884,7 +494,6 @@ lbool ccc::search() { } #endif - return result; } diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h index da546bca1..7d6000c93 100644 --- a/src/sat/sat_ccc.h +++ b/src/sat/sat_ccc.h @@ -29,15 +29,16 @@ namespace sat { unsigned m_id; unsigned m_depth; literal m_last; + literal m_blocked; unsigned m_parent; - decision(unsigned id, unsigned d, literal last, unsigned parent_id): - m_id(id), m_depth(d), m_last(last), m_parent(parent_id) {} + decision(unsigned id, unsigned d, literal last, literal blocked, unsigned parent_id): + m_id(id), m_depth(d), m_last(last), m_blocked(blocked), m_parent(parent_id) {} decision(): m_id(0), m_depth(0), m_last(null_literal), m_parent(0) {} std::ostream& pp(std::ostream& out) const; }; - solver& s; + solver& m_s; queue m_solved; queue m_decisions; model m_model; @@ -56,8 +57,14 @@ namespace sat { }; lbool conquer(solver& s); + bool cube_decision(solver& s, svector& decisions); + lbool bounded_search(solver& s, svector& decisions); lbool cube(); + bool push_decision(solver& s, decision const& d); + + lbool cube2(); + lbool cube2(unsigned& branch_id, svector& decisions, lookahead& lh); void replay_decisions(solver& s, svector& decisions); @@ -69,9 +76,11 @@ namespace sat { void check_non_model(char const* fn, svector const& decisions); + bool contains_branch(svector const& decisions, unsigned branch_id) const; + public: - ccc(solver& s): s(s) {} + ccc(solver& s): m_s(s) {} lbool search(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index a801cdad7..a0b82cf45 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -161,6 +161,7 @@ namespace sat { lookahead_mode m_search_mode; // mode of search stats m_stats; model m_model; + literal m_blocked_literal; // --------------------------------------- // truth values @@ -1712,7 +1713,8 @@ namespace sat { if (trail.empty()) return false; pop(); flip_prefix(); - assign(~trail.back()); + m_blocked_literal = trail.back(); + assign(~m_blocked_literal); trail.pop_back(); propagate(); } diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index aa35363b6..ec77ebfbd 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -76,18 +76,18 @@ namespace sat { lowlink.resize(num_lits, UINT_MAX); in_s.resize(num_lits, false); literal_vector roots; - roots.resize(m_solver.num_vars(), null_literal); + roots.resize(m_solver.num_vars(), null_literal); unsigned next_index = 0; svector frames; bool_var_vector to_elim; - for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { - if (index[l_idx] != UINT_MAX) - continue; - if (m_solver.was_eliminated(to_literal(l_idx).var())) - continue; - - m_solver.checkpoint(); + for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { + if (index[l_idx] != UINT_MAX) + continue; + if (m_solver.was_eliminated(to_literal(l_idx).var())) + continue; + + m_solver.checkpoint(); #define NEW_NODE(LIDX) { \ index[LIDX] = next_index; \ @@ -99,121 +99,121 @@ namespace sat { frames.push_back(frame(LIDX, wlist.begin(), wlist.end())); \ } - NEW_NODE(l_idx); + NEW_NODE(l_idx); - while (!frames.empty()) { - loop: - frame & fr = frames.back(); - unsigned l_idx = fr.m_lidx; - if (!fr.m_first) { - // after visiting child - literal l2 = fr.m_it->get_literal(); - unsigned l2_idx = l2.index(); - SASSERT(index[l2_idx] != UINT_MAX); - if (lowlink[l2_idx] < lowlink[l_idx]) - lowlink[l_idx] = lowlink[l2_idx]; - fr.m_it++; - } - fr.m_first = false; - while (fr.m_it != fr.m_end) { - if (!fr.m_it->is_binary_clause()) { - fr.m_it++; - continue; - } - literal l2 = fr.m_it->get_literal(); - unsigned l2_idx = l2.index(); - if (index[l2_idx] == UINT_MAX) { - NEW_NODE(l2_idx); - goto loop; - } - else if (in_s[l2_idx]) { - if (index[l2_idx] < lowlink[l_idx]) - lowlink[l_idx] = index[l2_idx]; - } - fr.m_it++; - } - // visited all successors - if (lowlink[l_idx] == index[l_idx]) { - // found new SCC - CTRACE("scc_cycle", s.back() != l_idx, { - tout << "cycle: "; - unsigned j = s.size() - 1; - unsigned l2_idx; - do { - l2_idx = s[j]; - j--; - tout << to_literal(l2_idx) << " "; - } while (l2_idx != l_idx); - tout << "\n"; - }); + while (!frames.empty()) { + loop: + frame & fr = frames.back(); + unsigned l_idx = fr.m_lidx; + if (!fr.m_first) { + // after visiting child + literal l2 = fr.m_it->get_literal(); + unsigned l2_idx = l2.index(); + SASSERT(index[l2_idx] != UINT_MAX); + if (lowlink[l2_idx] < lowlink[l_idx]) + lowlink[l_idx] = lowlink[l2_idx]; + fr.m_it++; + } + fr.m_first = false; + while (fr.m_it != fr.m_end) { + if (!fr.m_it->is_binary_clause()) { + fr.m_it++; + continue; + } + literal l2 = fr.m_it->get_literal(); + unsigned l2_idx = l2.index(); + if (index[l2_idx] == UINT_MAX) { + NEW_NODE(l2_idx); + goto loop; + } + else if (in_s[l2_idx]) { + if (index[l2_idx] < lowlink[l_idx]) + lowlink[l_idx] = index[l2_idx]; + } + fr.m_it++; + } + // visited all successors + if (lowlink[l_idx] == index[l_idx]) { + // found new SCC + CTRACE("scc_cycle", s.back() != l_idx, { + tout << "cycle: "; + unsigned j = s.size() - 1; + unsigned l2_idx; + do { + l2_idx = s[j]; + j--; + tout << to_literal(l2_idx) << " "; + } while (l2_idx != l_idx); + tout << "\n"; + }); + + SASSERT(!s.empty()); + literal l = to_literal(l_idx); + bool_var v = l.var(); + if (roots[v] != null_literal) { + // variable was already assigned... just consume stack + TRACE("scc_detail", tout << "consuming stack...\n";); + unsigned l2_idx; + do { + l2_idx = s.back(); + s.pop_back(); + in_s[l2_idx] = false; + SASSERT(roots[to_literal(l2_idx).var()].var() == roots[v].var()); + } while (l2_idx != l_idx); + } + else { + // check if the SCC has an external variable, and check for conflicts + TRACE("scc_detail", tout << "assigning roots...\n";); + literal r = null_literal; + unsigned j = s.size() - 1; + unsigned l2_idx; + do { + l2_idx = s[j]; + j--; + if (to_literal(l2_idx) == ~l) { + m_solver.set_conflict(justification()); + return 0; + } + if (m_solver.is_external(to_literal(l2_idx).var())) { + r = to_literal(l2_idx); + break; + } + } while (l2_idx != l_idx); - SASSERT(!s.empty()); - literal l = to_literal(l_idx); - bool_var v = l.var(); - if (roots[v] != null_literal) { - // variable was already assigned... just consume stack - TRACE("scc_detail", tout << "consuming stack...\n";); - unsigned l2_idx; - do { - l2_idx = s.back(); - s.pop_back(); - in_s[l2_idx] = false; - SASSERT(roots[to_literal(l2_idx).var()].var() == roots[v].var()); - } while (l2_idx != l_idx); - } - else { - // check if the SCC has an external variable, and check for conflicts - TRACE("scc_detail", tout << "assigning roots...\n";); - literal r = null_literal; - unsigned j = s.size() - 1; - unsigned l2_idx; - do { - l2_idx = s[j]; - j--; - if (to_literal(l2_idx) == ~l) { - m_solver.set_conflict(justification()); - return 0; - } - if (m_solver.is_external(to_literal(l2_idx).var())) { - r = to_literal(l2_idx); - break; - } - } while (l2_idx != l_idx); + if (r == null_literal) { + // SCC does not contain external variable + r = to_literal(l_idx); + } - if (r == null_literal) { - // SCC does not contain external variable - r = to_literal(l_idx); - } + TRACE("scc_detail", tout << "r: " << r << "\n";); - TRACE("scc_detail", tout << "r: " << r << "\n";); - - do { - l2_idx = s.back(); - s.pop_back(); - in_s[l2_idx] = false; - literal l2 = to_literal(l2_idx); - bool_var v2 = l2.var(); - if (roots[v2] == null_literal) { - if (l2.sign()) { - roots[v2] = ~r; - } - else { - roots[v2] = r; - } - if (v2 != r.var()) - to_elim.push_back(v2); - } - } while (l2_idx != l_idx); - } - } - frames.pop_back(); - } - } - for (unsigned i = 0; i < m_solver.num_vars(); ++i) { - if (roots[i] == null_literal) { - roots[i] = literal(i, false); - } - } + do { + l2_idx = s.back(); + s.pop_back(); + in_s[l2_idx] = false; + literal l2 = to_literal(l2_idx); + bool_var v2 = l2.var(); + if (roots[v2] == null_literal) { + if (l2.sign()) { + roots[v2] = ~r; + } + else { + roots[v2] = r; + } + if (v2 != r.var()) + to_elim.push_back(v2); + } + } while (l2_idx != l_idx); + } + } + frames.pop_back(); + } + } + for (unsigned i = 0; i < m_solver.num_vars(); ++i) { + if (roots[i] == null_literal) { + roots[i] = literal(i, false); + } + } TRACE("scc", for (unsigned i = 0; i < roots.size(); i++) { tout << i << " -> " << roots[i] << "\n"; } tout << "to_elim: "; for (unsigned i = 0; i < to_elim.size(); i++) tout << to_elim[i] << " "; tout << "\n";); m_num_elim += to_elim.size(); From d052155f6eb817fbd1e915da001653bcf230b946 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Apr 2017 14:46:46 -0700 Subject: [PATCH 0106/1283] parallelizing ccc Signed-off-by: Nikolaj Bjorner --- src/sat/sat_ccc.cpp | 397 ++++++++++++++++------------------ src/sat/sat_ccc.h | 74 ++++--- src/sat/sat_lookahead.h | 6 +- src/sat/sat_solver.cpp | 11 +- src/sat/sat_solver.h | 2 +- src/smt/asserted_formulas.cpp | 32 +-- src/util/util.cpp | 16 ++ src/util/util.h | 27 ++- 8 files changed, 284 insertions(+), 281 deletions(-) diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp index 141869f11..a282397be 100644 --- a/src/sat/sat_ccc.cpp +++ b/src/sat/sat_ccc.cpp @@ -15,6 +15,16 @@ Author: Notes: + The cube process spawns conquer threads to search parts of the + state space. + The conquer threads have two modes: + - emulation mode - where they try to outpace the cuber on the same search tree + - complement mode - where they solve a sub-branch not yet explored by the cuber. + When the conquer thread returns a solved cube it is processed in the following ways: + - ignore if solved_id \not\in decisions + - mark d as closed if d \in decisions, such that d is marked by solved id + - backjump otherwise, conquer thread has solved a branch attempted by the cuber + --*/ #include "sat_solver.h" @@ -23,9 +33,16 @@ Notes: using namespace sat; - std::ostream& ccc::decision::pp(std::ostream& out) const { - return out << "(" << m_id << " " << m_last << " d:" << m_depth << ") "; + out << "(" + << " id:" << m_id + << " l:" << m_literal + << " d:" << m_depth; + if (m_spawn_id != 0) { + out << " s:" << m_spawn_id; + } + out << ") "; + return out; } std::ostream& ccc::pp(std::ostream& out, svector const& v) { @@ -35,9 +52,9 @@ std::ostream& ccc::pp(std::ostream& out, svector const& v) { return out; } -lbool ccc::cube2() { - unsigned branch_id = 0; - unsigned_vector id_trail; +lbool ccc::cube() { + m_branch_id = 0; + m_last_closure_level = UINT_MAX; lookahead lh(m_s); lh.init_search(); @@ -47,41 +64,26 @@ lbool ccc::cube2() { literal_vector trail; svector decisions; lh.m_search_mode = lookahead_mode::searching; - lh.m_blocked_literal = null_literal; - lbool r = cube2(branch_id, decisions, lh); + lbool r = cube(decisions, lh); if (r == l_true) { m_model = lh.get_model(); } + lh.collect_statistics(m_stats); return r; } -lbool ccc::cube2(unsigned& branch_id, svector& decisions, lookahead& lh) { +lbool ccc::cube(svector& decisions, lookahead& lh) { m_s.checkpoint(); if (lh.inconsistent()) { return l_false; } - lh.inc_istamp(); - - // check if CDCL solver got ahead. - bool repeat = false; - #pragma omp critical (ccc_solved) - { - while (!m_solved.empty()) { - unsigned solved_id = m_solved.top(); - if (contains_branch(decisions, solved_id)) { - IF_VERBOSE(1, verbose_stream() << "conquer " << decisions.size() << "\n";); - repeat = true; - break; - } - else { - m_solved.pop(); - } - } + if (get_solved(decisions)) { + return l_false; } - if (repeat) return l_false; - + + lh.inc_istamp(); literal l = lh.choose(); if (lh.inconsistent()) { return l_false; @@ -92,34 +94,38 @@ lbool ccc::cube2(unsigned& branch_id, svector& decisions, lookahead& l } if (!decisions.empty()) { - #pragma omp critical (ccc_decisions) - { - m_decisions.push(decisions.back()); - } + put_decision(decisions.back()); } - // update trail and set of ids + // update trail and decisions - ++branch_id; ++lh.m_stats.m_decisions; unsigned parent_id = decisions.empty() ? 0 : decisions.back().m_id; - decision d(branch_id, decisions.size() + 1, l, null_literal, parent_id); + unsigned spawn_id = spawn_conquer(decisions); + unsigned branch_id = ++m_branch_id; + decision d(branch_id, decisions.size() + 1, l, parent_id, spawn_id); decisions.push_back(d); - #pragma omp critical (ccc_log) - { - IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); - IF_VERBOSE(2, pp(verbose_stream(), decisions) << "\n"; ); - } - TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); + IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); + IF_VERBOSE(2, pp(verbose_stream(), decisions) << "\n"; ); + + TRACE("sat", tout << "choose: " << l << "\n";); lh.push(l, lh.c_fixed_truth); - lbool r = cube2(branch_id, decisions, lh); + lbool r = cube(decisions, lh); if (r == l_false) { lh.pop(); - lh.flip_prefix(); - lh.push(~l, lh.c_fixed_truth); - decisions.back().m_last = ~l; - r = cube2(branch_id, decisions, lh); + if (decisions.back().is_closed()) { + // branch was solved by a spawned conquer process + IF_VERBOSE(1, verbose_stream() << "closed " << decisions.back().m_id << "\n";); + + r = l_false; + } + else { + lh.flip_prefix(); + lh.push(~l, lh.c_fixed_truth); + decisions.back().negate(); + r = cube(decisions, lh); + } if (r == l_false) { lh.pop(); decisions.pop_back(); @@ -128,106 +134,26 @@ lbool ccc::cube2(unsigned& branch_id, svector& decisions, lookahead& l return r; } -bool ccc::contains_branch(svector const& decisions, unsigned branch_id) const { - for (unsigned i = 0; i < decisions.size(); ++i) { - if (branch_id == decisions[i].m_id) return true; +unsigned ccc::spawn_conquer(svector const& decisions) { + unsigned result = 0; + // + // decisions must have been solved at a higher level by a conquer thread + // + if (!m_free_threads.empty() && m_last_closure_level <= 1 + decisions.size() + m_free_threads.size()) { + result = m_free_threads.back(); + m_free_threads.pop_back(); + IF_VERBOSE(1, verbose_stream() << "spawn " << result << "\n";); } - return false; + return result; +} + +void ccc::free_conquer(unsigned thread_id) { + m_free_threads.push_back(thread_id); } -lbool ccc::cube() { - unsigned branch_id = 0; - unsigned_vector id_trail; - - lookahead lh(m_s); - lh.init_search(); - lh.m_model.reset(); - - lookahead::scoped_level _sl(lh, lh.c_fixed_truth); - literal_vector trail; - svector decisions; - lh.m_search_mode = lookahead_mode::searching; - lh.m_blocked_literal = null_literal; - while (!m_cancel) { - - m_s.checkpoint(); - - SASSERT(trail.size() <= decisions.size()); - while (trail.size() < decisions.size()) { - //check_non_model("lh inconsistent ", decisions); - decisions.pop_back(); - id_trail.pop_back(); - } - SASSERT(id_trail.size() == trail.size()); - SASSERT(id_trail.size() == decisions.size()); - - TRACE("sat", lh.display(tout);); - - if (lh.inconsistent()) { - if (!lh.backtrack(trail)) return l_false; - continue; - } - - lh.inc_istamp(); - - // check if CDCL solver got ahead. - bool repeat = false; - #pragma omp critical (ccc_solved) - { - if (!m_solved.empty()) { - unsigned solved_id = m_solved.top(); - if (id_trail.contains(solved_id)) { - IF_VERBOSE(1, verbose_stream() << "cconquer " << decisions.size() << "\n";); - lh.set_conflict(); - } - else { - m_solved.pop(); - } - repeat = true; - } - } - if (repeat) continue; - - literal l = lh.choose(); - if (lh.inconsistent()) { - if (!lh.backtrack(trail)) return l_false; - continue; - } - if (l == null_literal) { - m_model = lh.get_model(); - return l_true; - } - - // update trail and set of ids - - ++branch_id; - ++lh.m_stats.m_decisions; - unsigned parent_id = id_trail.empty() ? 0 : id_trail.back(); - decision d(branch_id, trail.size() + 1, l, lh.m_blocked_literal, parent_id); - id_trail.push_back(branch_id); - trail.push_back(l); - decisions.push_back(d); - SASSERT(id_trail.size() == trail.size()); - lh.m_blocked_literal = null_literal; - - #pragma omp critical (ccc_log) - { - IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); - IF_VERBOSE(2, verbose_stream() << " " << trail << "\n"; pp(verbose_stream(), decisions) << "\n"; ); - } - #pragma omp critical (ccc_decisions) - { - m_decisions.push(d); - } - TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); - lh.push(l, lh.c_fixed_truth); - SASSERT(lh.inconsistent() || !lh.is_unsat()); - } - return l_undef; -} - -lbool ccc::conquer(solver& s) { +lbool ccc::conquer(solver& s, unsigned thread_id) { + SASSERT(thread_id > 0); try { if (s.inconsistent()) return l_false; s.init_search(); @@ -242,7 +168,7 @@ lbool ccc::conquer(solver& s) { while (true) { SASSERT(!s.inconsistent()); - lbool r = bounded_search(s, decisions); + lbool r = bounded_search(s, decisions, thread_id); if (r != l_undef) return r; @@ -257,17 +183,13 @@ lbool ccc::conquer(solver& s) { } } -void ccc::replay_decisions(solver& s, svector& decisions) { +void ccc::replay_decisions(solver& s, svector& decisions, unsigned thread_id) { s.propagate(true); for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < decisions.size(); ++i) { - decision d = decisions[i]; - literal lit = d.m_last; - lbool val = s.value(lit); - #pragma omp critical (ccc_log) - { - IF_VERBOSE(2, verbose_stream() << "replay " << lit << " " << val << "\n";); - } - if (!push_decision(s, d)) { + decision const& d = decisions[i]; + IF_VERBOSE(2, verbose_stream() << "replay " << d.get_literal(thread_id) << " " << s.value(d.get_literal(thread_id)) << "\n";); + + if (!push_decision(s, d, thread_id)) { // negation of decision is implied. // check_non_model("replay", decisions); decisions.resize(i); @@ -276,13 +198,73 @@ void ccc::replay_decisions(solver& s, svector& decisions) { } } -bool ccc::push_decision(solver& s, decision const& d) { - literal lit = d.m_last; +bool ccc::get_solved(svector& decisions) { + // check if CDCL solver got ahead. + bool found = false; + #pragma omp critical (ccc_solved) + { + while (!m_solved.empty()) { + solution const& sol = m_solved.top(); + unsigned branch_id = sol.m_branch_id; + unsigned thread_id = sol.m_thread_id; + SASSERT(thread_id > 0); + for (unsigned i = decisions.size(); i > 0; ) { + --i; + decision& d = decisions[i]; + if (branch_id == d.m_id) { + if (d.m_spawn_id == thread_id) { + SASSERT(d.m_spawn_id > 0); + free_conquer(thread_id); + IF_VERBOSE(1, verbose_stream() << "close " << i << "\n";); + d.close(); + } + else { + // IF_VERBOSE(1, verbose_stream() << "conquer " << branch_id << " " << i << " " << d.get_literal(thread_id) << "\n";); + found = true; + } + m_last_closure_level = d.m_depth; + break; + } + } + if (found) { + break; + } + // IF_VERBOSE(1, verbose_stream() << "not found: " << branch_id << " " << decisions.size() << "\n";); + m_solved.pop(); + } + } + return found; +} + +void ccc::put_decision(decision const& d) { + #pragma omp critical (ccc_decisions) + { + for (unsigned i = 0; i < m_num_conquer; ++i) { + m_decisions[i].push(d); + } + } +} + +bool ccc::get_decision(unsigned thread_id, decision& d) { + SASSERT(0 < thread_id && thread_id <= m_decisions.size()); + bool result = false; + #pragma omp critical (ccc_decisions) + { + if (!m_decisions[thread_id - 1].empty()) { + d = m_decisions[thread_id - 1].pop(); + result = true; + } + } + return result; +} + +bool ccc::push_decision(solver& s, decision const& d, unsigned thread_id) { + literal lit = d.get_literal(thread_id); switch (s.value(lit)) { case l_false: #pragma omp critical (ccc_solved) { - m_solved.push(d.m_id); + m_solved.push(solution(thread_id, d.m_id)); } //TBD: s.m_restart_threshold = s.m_config.m_restart_initial; @@ -297,40 +279,16 @@ bool ccc::push_decision(solver& s, decision const& d) { s.propagate(true); break; } - literal blocked = d.m_blocked; - if (false && blocked != null_literal) { - switch (s.value(blocked)) { - case l_false: - #pragma omp critical (ccc_solved) - { - m_solved.push(d.m_id); - } - return false; - case l_true: - break; - case l_undef: - //s.assign(blocked, justification()); - //s.propagate(true); - break; - } - } return true; } -bool ccc::cube_decision(solver& s, svector& decisions) { +bool ccc::cube_decision(solver& s, svector& decisions, unsigned thread_id) { decision d; bool use_cube_decision = false; SASSERT(s.m_qhead == s.m_trail.size()); - get_cube: - #pragma omp critical (ccc_decisions) - { - if (!m_decisions.empty()) { - d = m_decisions.pop(); - use_cube_decision = true; - } - } - if (!use_cube_decision) { + get_cube: + if (!get_decision(thread_id, d)) { return false; } @@ -338,42 +296,45 @@ bool ccc::cube_decision(solver& s, svector& decisions) { goto get_cube; } + if (!decisions.empty() && decisions.back().m_spawn_id == thread_id && decisions.back().m_depth < d.m_depth) { + goto get_cube; + } + while (!decisions.empty() && decisions.back().m_depth >= d.m_depth) { // check_non_model("cube decision", decisions); decisions.pop_back(); } + SASSERT(decisions.empty() || decisions.back().m_depth + 1 == d.m_depth); SASSERT(decisions.empty() || decisions.back().m_id == d.m_parent); s.pop_reinit(s.scope_lvl() - decisions.size()); SASSERT(s.m_qhead == s.m_trail.size()); SASSERT(s.scope_lvl() == decisions.size()); - #pragma omp critical (ccc_log) - { - literal lit = d.m_last; - IF_VERBOSE(1, verbose_stream() << "cube " << decisions.size() << "\n";); - IF_VERBOSE(2, pp(verbose_stream() << "push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; - if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); - } - if (push_decision(s, d)) { + literal lit = d.get_literal(thread_id); + IF_VERBOSE(1, verbose_stream() << "cube " << decisions.size() << " " << d.get_literal(thread_id) << "\n";); + IF_VERBOSE(2, pp(verbose_stream() << "push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; + if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); + + if (push_decision(s, d, thread_id)) { decisions.push_back(d); } return true; } -lbool ccc::bounded_search(solver& s, svector& decisions) { +lbool ccc::bounded_search(solver& s, svector& decisions, unsigned thread_id) { while (true) { s.checkpoint(); bool done = false; while (!done) { - replay_decisions(s, decisions); + replay_decisions(s, decisions, thread_id); lbool is_sat = s.propagate_and_backjump_step(done); if (is_sat != l_true) return is_sat; } s.gc(); - if (!cube_decision(s, decisions) && !s.decide()) { + if (!cube_decision(s, decisions, thread_id) && !s.decide()) { lbool is_sat = s.final_check(); if (is_sat != l_undef) { return is_sat; @@ -383,26 +344,6 @@ lbool ccc::bounded_search(solver& s, svector& decisions) { } -void ccc::push_model(unsigned v, bool sign) { - if (m_values.size() <= v) { - m_values.resize(v + 1); - } - m_values[v] = sign; -} - -void ccc::check_non_model(char const* fn, svector const& decisions) { - for (unsigned i = 0; i < decisions.size(); ++i) { - decision d = decisions[i]; - literal lit = d.m_last; - if (m_values[lit.var()] != lit.sign()) return; - } - - #pragma omp critical (ccc_log) - { - pp(verbose_stream() << "backtracking from model " << fn << " ", decisions) << "\n"; - } -} - lbool ccc::search() { enum par_exception_kind { DEFAULT_EX, @@ -421,8 +362,10 @@ lbool ccc::search() { par_exception_kind ex_kind; unsigned error_code = 0; lbool result = l_undef; + m_decisions.reset(); - int num_threads = 2; // for ccc-infinity only two threads. s.m_config.m_num_threads + 1; + m_num_conquer = m_s.m_config.m_num_threads; + int num_threads = 1 + m_num_conquer; // for ccc-infinity only two threads. for (int i = 1; i < num_threads; ++i) { limits.push_back(reslimit()); @@ -431,6 +374,10 @@ lbool ccc::search() { solvers.push_back(s1); s1->copy(m_s); scoped_rlimit.push_child(&s1->rlimit()); + m_decisions.push_back(queue()); + } + for (unsigned i = 1; i < m_num_conquer; ++i) { + m_free_threads.push_back(i); } #pragma omp parallel for @@ -438,10 +385,10 @@ lbool ccc::search() { try { lbool r = l_undef; if (i == 0) { - r = cube2(); + r = cube(); } else { - r = conquer(*solvers[i-1]); + r = conquer(*solvers[i-1], i); } bool first = false; #pragma omp critical (par_solver) @@ -476,6 +423,7 @@ lbool ccc::search() { } for (unsigned i = 0; i < solvers.size(); ++i) { + solvers[i]->collect_statistics(m_stats); dealloc(solvers[i]); } @@ -497,3 +445,22 @@ lbool ccc::search() { return result; } + +#if 0 +void ccc::push_model(unsigned v, bool sign) { + if (m_values.size() <= v) { + m_values.resize(v + 1); + } + m_values[v] = sign; +} + +void ccc::check_non_model(char const* fn, svector const& decisions) { + for (unsigned i = 0; i < decisions.size(); ++i) { + decision d = decisions[i]; + literal lit = d.m_literal; + if (m_values[lit.var()] != lit.sign()) return; + } + + IF_VERBOSE(1, pp(verbose_stream() << "backtracking from model " << fn << " ", decisions) << "\n";); +} +#endif diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h index 7d6000c93..21291c1aa 100644 --- a/src/sat/sat_ccc.h +++ b/src/sat/sat_ccc.h @@ -26,47 +26,55 @@ namespace sat { class ccc { struct decision { - unsigned m_id; - unsigned m_depth; - literal m_last; - literal m_blocked; - unsigned m_parent; - decision(unsigned id, unsigned d, literal last, literal blocked, unsigned parent_id): - m_id(id), m_depth(d), m_last(last), m_blocked(blocked), m_parent(parent_id) {} - decision(): m_id(0), m_depth(0), m_last(null_literal), m_parent(0) {} - + unsigned m_id; // unique identifier for decision + unsigned m_depth; // depth of decision + literal m_literal; // decision literal + unsigned m_parent; // id of parent + int m_spawn_id; // thread id of conquer thread processing complented branch. + // = 0 if not spawned. + // > 0 if active spawn is in progress + // < 0 if thread has closed the branch + decision(unsigned id, unsigned d, literal last, unsigned parent_id, unsigned spawn): + m_id(id), m_depth(d), m_literal(last), m_parent(parent_id), m_spawn_id(spawn) {} + decision(): + m_id(0), m_depth(0), m_literal(null_literal), m_parent(0), m_spawn_id(0) {} + + void close() { SASSERT(m_spawn_id > 0); m_spawn_id = -m_spawn_id; } + bool is_closed() const { return m_spawn_id < 0; } + void negate() { m_literal.neg(); m_spawn_id = 0; } + literal get_literal(unsigned thread_id) const { return thread_id == m_spawn_id ? ~m_literal : m_literal; } std::ostream& pp(std::ostream& out) const; }; + struct solution { + unsigned m_thread_id; + unsigned m_branch_id; + solution(unsigned t, unsigned s): m_thread_id(t), m_branch_id(s) {} + }; + solver& m_s; - queue m_solved; - queue m_decisions; + queue m_solved; + vector > m_decisions; + unsigned m_num_conquer; model m_model; volatile bool m_cancel; + unsigned m_branch_id; + unsigned_vector m_free_threads; + unsigned m_last_closure_level; + ::statistics m_stats; - svector m_values; + lbool conquer(solver& s, unsigned thread_id); + bool cube_decision(solver& s, svector& decisions, unsigned thread_id); - struct config { - config() { - } - }; - - struct stats { - stats() { reset(); } - void reset() { memset(this, 0, sizeof(*this)); } - }; - - lbool conquer(solver& s); - bool cube_decision(solver& s, svector& decisions); - - lbool bounded_search(solver& s, svector& decisions); + lbool bounded_search(solver& s, svector& decisions, unsigned thread_id); + bool push_decision(solver& s, decision const& d, unsigned thread_id); lbool cube(); - bool push_decision(solver& s, decision const& d); + lbool cube(svector& decisions, lookahead& lh); + void put_decision(decision const& d); + bool get_decision(unsigned thread_id, decision& d); + bool get_solved(svector& decisions); - lbool cube2(); - lbool cube2(unsigned& branch_id, svector& decisions, lookahead& lh); - - void replay_decisions(solver& s, svector& decisions); + void replay_decisions(solver& s, svector& decisions, unsigned thread_id); static std::ostream& pp(std::ostream& out, svector const& v); @@ -76,7 +84,8 @@ namespace sat { void check_non_model(char const* fn, svector const& decisions); - bool contains_branch(svector const& decisions, unsigned branch_id) const; + unsigned spawn_conquer(svector const& decisions); + void free_conquer(unsigned thread_id); public: @@ -86,6 +95,7 @@ namespace sat { model const& get_model() const { return m_model; } + void collect_statistics(::statistics& st) { st.copy(m_stats); } }; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index a0b82cf45..0cc4678dd 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -161,8 +161,7 @@ namespace sat { lookahead_mode m_search_mode; // mode of search stats m_stats; model m_model; - literal m_blocked_literal; - + // --------------------------------------- // truth values @@ -1713,8 +1712,7 @@ namespace sat { if (trail.empty()) return false; pop(); flip_prefix(); - m_blocked_literal = trail.back(); - assign(~m_blocked_literal); + assign(~trail.back()); trail.pop_back(); propagate(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4647ddb36..fa8663db8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -874,7 +874,7 @@ namespace sat { scoped_rl.push_child(&srch.rlimit()); lbool r = srch.check(num_lits, lits, 0); m_model = srch.get_model(); - // srch.collect_statistics(m_lookahead_stats); + // srch.collect_statistics(m_aux_stats); return r; } @@ -882,6 +882,7 @@ namespace sat { ccc c(*this); lbool r = c.search(); m_model = c.get_model(); + c.collect_statistics(m_aux_stats); return r; } @@ -893,10 +894,10 @@ namespace sat { m_model = lh.get_model(); } catch (z3_exception&) { - lh.collect_statistics(m_lookahead_stats); + lh.collect_statistics(m_aux_stats); throw; } - lh.collect_statistics(m_lookahead_stats); + lh.collect_statistics(m_aux_stats); return r; } @@ -2808,7 +2809,7 @@ namespace sat { m_asymm_branch.collect_statistics(st); m_probing.collect_statistics(st); if (m_ext) m_ext->collect_statistics(st); - st.copy(m_lookahead_stats); + st.copy(m_aux_stats); } void solver::reset_statistics() { @@ -2817,7 +2818,7 @@ namespace sat { m_simplifier.reset_statistics(); m_asymm_branch.reset_statistics(); m_probing.reset_statistics(); - m_lookahead_stats.reset(); + m_aux_stats.reset(); } // ----------------------- diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index fda8362ca..dec32f11a 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -141,7 +141,7 @@ namespace sat { unsigned m_par_num_vars; bool m_par_syncing_clauses; - statistics m_lookahead_stats; + statistics m_aux_stats; void del_clauses(clause * const * begin, clause * const * end); diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 26395f9ab..6598c3a05 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -288,7 +288,7 @@ void asserted_formulas::reduce() { } void asserted_formulas::eliminate_and() { - IF_IVERBOSE(10, verbose_stream() << "(smt.eliminating-and)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.eliminating-and)\n";); set_eliminate_and(true); reduce_asserted_formulas(); TRACE("after_elim_and", display(tout);); @@ -393,19 +393,19 @@ void asserted_formulas::find_macros_core() { } void asserted_formulas::find_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.find-macros)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.find-macros)\n";); TRACE("before_find_macros", display(tout);); find_macros_core(); TRACE("after_find_macros", display(tout);); } void asserted_formulas::expand_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.expand-macros)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.expand-macros)\n";); find_macros_core(); } void asserted_formulas::apply_quasi_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.find-quasi-macros)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.find-quasi-macros)\n";); TRACE("before_quasi_macros", display(tout);); expr_ref_vector new_exprs(m_manager); proof_ref_vector new_prs(m_manager); @@ -423,7 +423,7 @@ void asserted_formulas::apply_quasi_macros() { } void asserted_formulas::nnf_cnf() { - IF_IVERBOSE(10, verbose_stream() << "(smt.nnf)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.nnf)\n";); nnf apply_nnf(m_manager, m_defined_names); expr_ref_vector new_exprs(m_manager); proof_ref_vector new_prs(m_manager); @@ -473,7 +473,7 @@ void asserted_formulas::nnf_cnf() { #define MK_SIMPLE_SIMPLIFIER(NAME, FUNCTOR_DEF, LABEL, MSG) \ void asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ + IF_VERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ TRACE(LABEL, tout << "before:\n"; display(tout);); \ FUNCTOR_DEF; \ expr_ref_vector new_exprs(m_manager); \ @@ -508,13 +508,13 @@ void asserted_formulas::NAME() { MK_SIMPLE_SIMPLIFIER(apply_distribute_forall, distribute_forall functor(m_manager, *m_bsimp), "distribute_forall", "distribute-forall"); void asserted_formulas::reduce_and_solve() { - IF_IVERBOSE(10, verbose_stream() << "(smt.reducing)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.reducing)\n";); flush_cache(); // collect garbage reduce_asserted_formulas(); } void asserted_formulas::infer_patterns() { - IF_IVERBOSE(10, verbose_stream() << "(smt.pattern-inference)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.pattern-inference)\n";); TRACE("before_pattern_inference", display(tout);); pattern_inference infer(m_manager, m_params); expr_ref_vector new_exprs(m_manager); @@ -552,7 +552,7 @@ void asserted_formulas::commit(unsigned new_qhead) { } void asserted_formulas::eliminate_term_ite() { - IF_IVERBOSE(10, verbose_stream() << "(smt.eliminating-ite-term)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.eliminating-ite-term)\n";); TRACE("before_elim_term_ite", display(tout);); elim_term_ite elim(m_manager, m_defined_names); expr_ref_vector new_exprs(m_manager); @@ -589,7 +589,7 @@ void asserted_formulas::eliminate_term_ite() { } void asserted_formulas::propagate_values() { - IF_IVERBOSE(10, verbose_stream() << "(smt.constant-propagation)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.constant-propagation)\n";); TRACE("propagate_values", tout << "before:\n"; display(tout);); flush_cache(); bool found = false; @@ -673,7 +673,7 @@ void asserted_formulas::propagate_booleans() { flush_cache(); while (cont) { TRACE("propagate_booleans", tout << "before:\n"; display(tout);); - IF_IVERBOSE(10, verbose_stream() << "(smt.propagate-booleans)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.propagate-booleans)\n";); cont = false; unsigned i = m_asserted_qhead; unsigned sz = m_asserted_formulas.size(); @@ -716,7 +716,7 @@ void asserted_formulas::propagate_booleans() { #define MK_SIMPLIFIER(NAME, FUNCTOR, TAG, MSG, REDUCE) \ bool asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ + IF_VERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ TRACE(TAG, ast_mark visited; display_ll(tout, visited);); \ FUNCTOR; \ bool changed = false; \ @@ -773,7 +773,7 @@ proof * asserted_formulas::get_inconsistency_proof() const { } void asserted_formulas::refine_inj_axiom() { - IF_IVERBOSE(10, verbose_stream() << "(smt.refine-injectivity)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.refine-injectivity)\n";); TRACE("inj_axiom", display(tout);); unsigned i = m_asserted_qhead; unsigned sz = m_asserted_formulas.size(); @@ -805,7 +805,7 @@ MK_SIMPLIFIER(elim_bvs_from_quantifiers, bv_elim_star functor(m_manager), "bv_el #define LIFT_ITE(NAME, FUNCTOR, MSG) \ void asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ + IF_VERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ TRACE("lift_ite", display(tout);); \ FUNCTOR; \ unsigned i = m_asserted_qhead; \ @@ -817,7 +817,7 @@ void asserted_formulas::NAME() { proof_ref new_pr(m_manager); \ functor(n, new_n, new_pr); \ TRACE("lift_ite_step", tout << mk_pp(n, m_manager) << "\n";); \ - IF_IVERBOSE(10000, verbose_stream() << "lift before: " << get_num_exprs(n) << ", after: " << get_num_exprs(new_n) << "\n";); \ + IF_VERBOSE(10000, verbose_stream() << "lift before: " << get_num_exprs(n) << ", after: " << get_num_exprs(new_n) << "\n";); \ m_asserted_formulas.set(i, new_n); \ if (m_manager.proofs_enabled()) { \ new_pr = m_manager.mk_modus_ponens(pr, new_pr); \ @@ -841,7 +841,7 @@ unsigned asserted_formulas::get_total_size() const { } void asserted_formulas::max_bv_sharing() { - IF_IVERBOSE(10, verbose_stream() << "(smt.maximizing-bv-sharing)\n";); + IF_VERBOSE(10, verbose_stream() << "(smt.maximizing-bv-sharing)\n";); TRACE("bv_sharing", display(tout);); unsigned i = m_asserted_qhead; unsigned sz = m_asserted_formulas.size(); diff --git a/src/util/util.cpp b/src/util/util.cpp index bfd4923a8..50d93913a 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -17,6 +17,9 @@ Revision History: --*/ +#ifdef _WINDOWS +#include "windows.h" +#endif #include"util.h" static unsigned g_verbosity_level = 0; @@ -35,6 +38,19 @@ void set_verbose_stream(std::ostream& str) { g_verbose_stream = &str; } +static int g_thread_id = 0; +static bool g_is_threaded = false; + +bool is_threaded() { + if (g_is_threaded) return true; +#ifdef _WINDOWS + int thid = GetCurrentThreadId(); + g_is_threaded = g_thread_id != thid && g_thread_id != 0; + g_thread_id = thid; +#endif + return g_is_threaded; +} + std::ostream& verbose_stream() { return *g_verbose_stream; } diff --git a/src/util/util.h b/src/util/util.h index a040a79ae..e62f24e44 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -24,6 +24,7 @@ Revision History: #include #include #include +#include"z3_omp.h" #ifndef SIZE_MAX #define SIZE_MAX std::numeric_limits::max() @@ -182,16 +183,26 @@ void set_verbosity_level(unsigned lvl); unsigned get_verbosity_level(); std::ostream& verbose_stream(); void set_verbose_stream(std::ostream& str); +bool is_threaded(); -#define IF_VERBOSE(LVL, CODE) { if (get_verbosity_level() >= LVL) { CODE } } ((void) 0) - -#ifdef _EXTERNAL_RELEASE -#define IF_IVERBOSE(LVL, CODE) ((void) 0) -#else -#define IF_IVERBOSE(LVL, CODE) { if (get_verbosity_level() >= LVL) { CODE } } ((void) 0) -#endif - + +#define IF_VERBOSE(LVL, CODE) { \ + if (get_verbosity_level() >= LVL) { \ + if (is_threaded()) { \ + LOCK_CODE(CODE); \ + } \ + else { \ + CODE; \ + } \ + } } ((void) 0) +#define LOCK_CODE(CODE) \ + { \ + __pragma(omp critical (verbose_lock)) \ + { \ + CODE; \ + } \ + } template struct default_eq { From 3aaea6b920de7aa2a1c446b04c6aac1d2559be6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 23 Apr 2017 23:10:23 -0700 Subject: [PATCH 0107/1283] parallelizing ccc Signed-off-by: Nikolaj Bjorner --- src/sat/sat_ccc.cpp | 24 +++++++---- src/sat/sat_ccc.h | 2 +- src/sat/sat_lookahead.h | 88 ++++++++++++++++++++++++++--------------- 3 files changed, 73 insertions(+), 41 deletions(-) diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp index a282397be..b0657fd64 100644 --- a/src/sat/sat_ccc.cpp +++ b/src/sat/sat_ccc.cpp @@ -35,7 +35,7 @@ using namespace sat; std::ostream& ccc::decision::pp(std::ostream& out) const { out << "(" - << " id:" << m_id + << "id:" << m_id << " l:" << m_literal << " d:" << m_depth; if (m_spawn_id != 0) { @@ -187,9 +187,9 @@ void ccc::replay_decisions(solver& s, svector& decisions, unsigned thr s.propagate(true); for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < decisions.size(); ++i) { decision const& d = decisions[i]; - IF_VERBOSE(2, verbose_stream() << "replay " << d.get_literal(thread_id) << " " << s.value(d.get_literal(thread_id)) << "\n";); + IF_VERBOSE(2, verbose_stream() << thread_id << ": replay " << d.get_literal(thread_id) << " " << s.value(d.get_literal(thread_id)) << "\n";); - if (!push_decision(s, d, thread_id)) { + if (!push_decision(s, decisions, d, thread_id)) { // negation of decision is implied. // check_non_model("replay", decisions); decisions.resize(i); @@ -214,7 +214,7 @@ bool ccc::get_solved(svector& decisions) { if (branch_id == d.m_id) { if (d.m_spawn_id == thread_id) { SASSERT(d.m_spawn_id > 0); - free_conquer(thread_id); + free_conquer(thread_id); IF_VERBOSE(1, verbose_stream() << "close " << i << "\n";); d.close(); } @@ -258,10 +258,18 @@ bool ccc::get_decision(unsigned thread_id, decision& d) { return result; } -bool ccc::push_decision(solver& s, decision const& d, unsigned thread_id) { +bool ccc::push_decision(solver& s, svector const& decisions, decision const& d, unsigned thread_id) { literal lit = d.get_literal(thread_id); switch (s.value(lit)) { case l_false: + // TBD: we leak conquer threads if they backjump below spawn point. + if (decisions.empty() && decisions.back().m_spawn_id == thread_id && decisions.back().m_id != d.m_id) { + IF_VERBOSE(0, verbose_stream() << "LEAK avoided\n";); + #pragma omp critical (ccc_solved) + { + m_solved.push(solution(thread_id, decisions.back().m_id)); + } + } #pragma omp critical (ccc_solved) { m_solved.push(solution(thread_id, d.m_id)); @@ -311,11 +319,11 @@ bool ccc::cube_decision(solver& s, svector& decisions, unsigned thread SASSERT(s.m_qhead == s.m_trail.size()); SASSERT(s.scope_lvl() == decisions.size()); literal lit = d.get_literal(thread_id); - IF_VERBOSE(1, verbose_stream() << "cube " << decisions.size() << " " << d.get_literal(thread_id) << "\n";); - IF_VERBOSE(2, pp(verbose_stream() << "push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; + IF_VERBOSE(1, verbose_stream() << thread_id << ": cube " << decisions.size() << " " << d.get_literal(thread_id) << "\n";); + IF_VERBOSE(2, pp(verbose_stream() << thread_id << ": push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); - if (push_decision(s, d, thread_id)) { + if (push_decision(s, decisions, d, thread_id)) { decisions.push_back(d); } diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h index 21291c1aa..b4d497fa0 100644 --- a/src/sat/sat_ccc.h +++ b/src/sat/sat_ccc.h @@ -67,7 +67,7 @@ namespace sat { bool cube_decision(solver& s, svector& decisions, unsigned thread_id); lbool bounded_search(solver& s, svector& decisions, unsigned thread_id); - bool push_decision(solver& s, decision const& d, unsigned thread_id); + bool push_decision(solver& s, svector const& decisions, decision const& d, unsigned thread_id); lbool cube(); lbool cube(svector& decisions, lookahead& lh); void put_decision(decision const& d); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 0cc4678dd..c2763b776 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -59,7 +59,9 @@ namespace sat { } class lookahead { - solver& s; + solver& m_s; + unsigned m_num_vars; + reslimit m_rlimit; friend class ccc; @@ -243,14 +245,20 @@ namespace sat { m_binary[(~l2).index()].push_back(l1); m_binary_trail.push_back((~l1).index()); ++m_stats.m_add_binary; - if (s.m_config.m_drat) validate_binary(l1, l2); + if (m_s.m_config.m_drat) validate_binary(l1, l2); } void del_binary(unsigned idx) { // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n");); literal_vector & lits = m_binary[idx]; - literal l = lits.back(); + if (lits.empty()) IF_VERBOSE(0, verbose_stream() << "empty literals\n";); + literal l = lits.back(); lits.pop_back(); + if (m_binary[(~l).index()].back() != ~to_literal(idx)) { + IF_VERBOSE(0, verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); + } + if (m_binary[(~l).index()].empty()) + IF_VERBOSE(0, verbose_stream() << "empty binary\n";); m_binary[(~l).index()].pop_back(); ++m_stats.m_del_binary; } @@ -547,7 +555,7 @@ namespace sat { void ensure_H(unsigned level) { while (m_H.size() <= level) { m_H.push_back(svector()); - m_H.back().resize(s.num_vars() * 2, 0); + m_H.back().resize(m_num_vars * 2, 0); } } @@ -574,6 +582,9 @@ namespace sat { float sum = 0, tsum = 0; literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); for (; it != end; ++it) { + bool_var v = it->var(); + if (it->index() >= h.size()) + IF_VERBOSE(0, verbose_stream() << l << " " << *it << " " << h.size() << "\n";); if (is_undef(*it)) sum += h[it->index()]; // if (m_freevars.contains(it->var())) sum += h[it->index()]; } @@ -593,7 +604,7 @@ namespace sat { } case watched::CLAUSE: { clause_offset cls_off = wit->get_clause_offset(); - clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + clause & c = *(m_cls_allocator.get_clause(cls_off)); // approximation compared to ternary clause case: // we pick two other literals from the clause. if (c[0] == ~l) { @@ -1026,26 +1037,26 @@ namespace sat { m_lits.push_back(lit_info()); m_rating.push_back(0); m_vprefix.push_back(prefix()); - if (!s.was_eliminated(v)) + if (!m_s.was_eliminated(v)) m_freevars.insert(v); } void init() { - m_delta_trigger = s.num_vars()/10; + m_delta_trigger = m_num_vars/10; m_config.m_dl_success = 0.8; m_inconsistent = false; m_qhead = 0; m_bstamp_id = 0; - for (unsigned i = 0; i < s.num_vars(); ++i) { + for (unsigned i = 0; i < m_num_vars; ++i) { init_var(i); } // copy binary clauses - unsigned sz = s.m_watches.size(); + unsigned sz = m_s.m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { literal l = ~to_literal(l_idx); - watch_list const & wlist = s.m_watches[l_idx]; + watch_list const & wlist = m_s.m_watches[l_idx]; watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); for (; it != end; ++it) { @@ -1057,21 +1068,21 @@ namespace sat { } } - copy_clauses(s.m_clauses); - copy_clauses(s.m_learned); + copy_clauses(m_s.m_clauses); + copy_clauses(m_s.m_learned); // copy units - unsigned trail_sz = s.init_trail_size(); + unsigned trail_sz = m_s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { - literal l = s.m_trail[i]; - if (!s.was_eliminated(l.var())) { - if (s.m_config.m_drat) m_drat.add(l, false); + literal l = m_s.m_trail[i]; + if (!m_s.was_eliminated(l.var())) { + if (m_s.m_config.m_drat) m_drat.add(l, false); assign(l); } } propagate(); m_qhead = m_trail.size(); - TRACE("sat", s.display(tout); display(tout);); + TRACE("sat", m_s.display(tout); display(tout);); } void copy_clauses(clause_vector const& clauses) { @@ -1087,7 +1098,7 @@ namespace sat { for (unsigned i = 0; i < c.size(); ++i) { m_full_watches[(~c[i]).index()].push_back(c1); } - if (s.m_config.m_drat) m_drat.add(c, false); + if (m_s.m_config.m_drat) m_drat.add(c, false); } } @@ -1207,7 +1218,7 @@ namespace sat { clause const& get_clause(watch_list::iterator it) const { clause_offset cls_off = it->get_clause_offset(); - return *(s.m_cls_allocator.get_clause(cls_off)); + return *(m_cls_allocator.get_clause(cls_off)); } bool is_nary_propagation(clause const& c, literal l) const { @@ -1288,7 +1299,7 @@ namespace sat { break; } clause_offset cls_off = it->get_clause_offset(); - clause & c = *(s.m_cls_allocator.get_clause(cls_off)); + clause & c = *(m_cls_allocator.get_clause(cls_off)); if (c[0] == ~l) std::swap(c[0], c[1]); if (is_true(c[0])) { @@ -1426,7 +1437,7 @@ namespace sat { while (change && !inconsistent()) { change = false; for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { - s.checkpoint(); + checkpoint(); literal lit = m_lookahead[i].m_lit; if (is_fixed_at(lit, c_fixed_truth)) continue; unsigned level = base + m_lookahead[i].m_offset; @@ -1501,7 +1512,7 @@ namespace sat { float mixd = mix_diff(diff1, diff2); if (mixd == h) ++count; - if (mixd > h || (mixd == h && s.m_rand(count) == 0)) { + if (mixd > h || (mixd == h && m_s.m_rand(count) == 0)) { CTRACE("sat", l != null_literal, tout << lit << " mix diff: " << mixd << "\n";); if (mixd > h) count = 1; h = mixd; @@ -1666,7 +1677,7 @@ namespace sat { unsigned scope_lvl() const { return m_trail_lim.size(); } void validate_assign(literal l) { - if (s.m_config.m_drat && m_search_mode == lookahead_mode::searching) { + if (m_s.m_config.m_drat && m_search_mode == lookahead_mode::searching) { m_assumptions.push_back(l); m_drat.add(m_assumptions); m_assumptions.pop_back(); @@ -1727,7 +1738,7 @@ namespace sat { while (true) { TRACE("sat", display(tout);); inc_istamp(); - s.checkpoint(); + checkpoint(); if (inconsistent()) { if (!backtrack(trail)) return l_false; continue; @@ -1751,7 +1762,7 @@ namespace sat { void init_model() { m_model.reset(); - for (unsigned i = 0; i < s.num_vars(); ++i) { + for (unsigned i = 0; i < m_num_vars; ++i) { lbool val; literal lit(i, false); if (is_undef(lit)) { @@ -1810,17 +1821,30 @@ namespace sat { init(); } + void checkpoint() { + if (!m_rlimit.inc()) { + throw solver_exception(Z3_CANCELED_MSG); + } + if (memory::get_allocation_size() > m_s.m_config.m_max_memory) { + throw solver_exception(Z3_MAX_MEMORY_MSG); + } + } + + public: lookahead(solver& s) : - s(s), + m_s(s), + m_num_vars(s.num_vars()), m_drat(s), m_num_tc1(0), m_level(2), m_prefix(0) { + m_s.rlimit().push_child(&m_rlimit); } ~lookahead() { del_clauses(); + m_s.rlimit().pop_child(); } lbool check() { @@ -1842,14 +1866,14 @@ namespace sat { unsigned num_units = 0; for (unsigned i = 0; i < m_trail.size(); ++i) { literal lit = m_trail[i]; - if (s.value(lit) == l_undef && !s.was_eliminated(lit.var())) { - s.m_simplifier.propagate_unit(lit); + if (m_s.value(lit) == l_undef && !m_s.was_eliminated(lit.var())) { + m_s.m_simplifier.propagate_unit(lit); ++num_units; } } IF_VERBOSE(1, verbose_stream() << "units found: " << num_units << "\n";); - s.m_simplifier.subsume(); + m_s.m_simplifier.subsume(); m_lookahead.reset(); } @@ -1868,20 +1892,20 @@ namespace sat { if (inconsistent()) return; literal_vector roots; bool_var_vector to_elim; - for (unsigned i = 0; i < s.num_vars(); ++i) { + for (unsigned i = 0; i < m_num_vars; ++i) { roots.push_back(literal(i, false)); } for (unsigned i = 0; i < m_candidates.size(); ++i) { bool_var v = m_candidates[i].m_var; literal lit = literal(v, false); literal p = get_parent(lit); - if (p != null_literal && p.var() != v && !s.is_external(v) && !s.was_eliminated(v) && !s.was_eliminated(p.var())) { + if (p != null_literal && p.var() != v && !m_s.is_external(v) && !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { to_elim.push_back(v); roots[v] = p; } } IF_VERBOSE(1, verbose_stream() << "eliminate " << to_elim.size() << " variables\n";); - elim_eqs elim(s); + elim_eqs elim(m_s); elim(roots, to_elim); } m_lookahead.reset(); From 07ef79d66458b758114f0b2777b3e0a0bd134bb2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Apr 2017 08:36:33 -0700 Subject: [PATCH 0108/1283] parallelizing ccc Signed-off-by: Nikolaj Bjorner --- src/sat/sat_ccc.cpp | 71 +++++++++++++++++++++++++---------------- src/sat/sat_ccc.h | 22 +++++++++++-- src/sat/sat_lookahead.h | 4 +++ 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp index b0657fd64..eec7e313e 100644 --- a/src/sat/sat_ccc.cpp +++ b/src/sat/sat_ccc.cpp @@ -54,7 +54,7 @@ std::ostream& ccc::pp(std::ostream& out, svector const& v) { lbool ccc::cube() { m_branch_id = 0; - m_last_closure_level = UINT_MAX; + m_last_closure_level = 1000; lookahead lh(m_s); lh.init_search(); @@ -68,7 +68,7 @@ lbool ccc::cube() { if (r == l_true) { m_model = lh.get_model(); } - lh.collect_statistics(m_stats); + lh.collect_statistics(m_lh_stats); return r; } @@ -102,8 +102,9 @@ lbool ccc::cube(svector& decisions, lookahead& lh) { ++lh.m_stats.m_decisions; unsigned parent_id = decisions.empty() ? 0 : decisions.back().m_id; unsigned spawn_id = spawn_conquer(decisions); - unsigned branch_id = ++m_branch_id; - decision d(branch_id, decisions.size() + 1, l, parent_id, spawn_id); + unsigned branch1 = m_branch_id++; + unsigned branch2 = m_branch_id++; + decision d(branch1, decisions.size() + 1, l, parent_id, spawn_id); decisions.push_back(d); IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); @@ -116,39 +117,50 @@ lbool ccc::cube(svector& decisions, lookahead& lh) { lh.pop(); if (decisions.back().is_closed()) { // branch was solved by a spawned conquer process - IF_VERBOSE(1, verbose_stream() << "closed " << decisions.back().m_id << "\n";); - + IF_VERBOSE(0, verbose_stream() << "closed " << decisions.back().m_id << "\n";); r = l_false; + decisions.pop_back(); } else { + lh.inc_istamp(); lh.flip_prefix(); lh.push(~l, lh.c_fixed_truth); decisions.back().negate(); + decisions.back().m_id = branch2; r = cube(decisions, lh); - } - if (r == l_false) { - lh.pop(); - decisions.pop_back(); + if (r == l_false) { + lh.pop(); + decisions.pop_back(); + } } } return r; } +void ccc::update_closure_level(decision const& d, int offset) { + m_last_closure_level = (d.m_depth + 3*m_last_closure_level) / 4 + offset; +} + unsigned ccc::spawn_conquer(svector const& decisions) { unsigned result = 0; // // decisions must have been solved at a higher level by a conquer thread // - if (!m_free_threads.empty() && m_last_closure_level <= 1 + decisions.size() + m_free_threads.size()) { + if (m_ccc_stats.m_cdcl_closed < 10) { + return 0; + } + if (!m_free_threads.empty() && m_last_closure_level >= decisions.size()) { result = m_free_threads.back(); m_free_threads.pop_back(); - IF_VERBOSE(1, verbose_stream() << "spawn " << result << "\n";); + IF_VERBOSE(0, verbose_stream() << "spawn " << decisions.size() << " " << result << "\n";); } return result; } void ccc::free_conquer(unsigned thread_id) { - m_free_threads.push_back(thread_id); + if (thread_id != 0) { + m_free_threads.push_back(thread_id); + } } @@ -208,21 +220,32 @@ bool ccc::get_solved(svector& decisions) { unsigned branch_id = sol.m_branch_id; unsigned thread_id = sol.m_thread_id; SASSERT(thread_id > 0); + free_conquer(thread_id); for (unsigned i = decisions.size(); i > 0; ) { --i; decision& d = decisions[i]; if (branch_id == d.m_id) { - if (d.m_spawn_id == thread_id) { + if (d.m_spawn_id == thread_id && thread_id != 0) { SASSERT(d.m_spawn_id > 0); - free_conquer(thread_id); - IF_VERBOSE(1, verbose_stream() << "close " << i << "\n";); + IF_VERBOSE(0, verbose_stream() << "spawn close " << branch_id << " " << thread_id << " " << d.m_depth << "\n";); + ++m_ccc_stats.m_spawn_closed; d.close(); + update_closure_level(d, -1); } else { - // IF_VERBOSE(1, verbose_stream() << "conquer " << branch_id << " " << i << " " << d.get_literal(thread_id) << "\n";); + IF_VERBOSE(0, verbose_stream() << "conquer " << branch_id << " " << thread_id << " " << d.m_depth << " " << d.get_literal(thread_id) << "\n";); found = true; + ++m_ccc_stats.m_cdcl_closed; + update_closure_level(d, 1); } - m_last_closure_level = d.m_depth; + break; + } + // branch is even, d has moved to the next branch + if (branch_id == (d.m_id & ~0x1) && d.m_spawn_id == thread_id && thread_id != 0) { + IF_VERBOSE(0, verbose_stream() << "spawn conquer " << branch_id << " " << thread_id << " " << d.m_depth << "\n";); + found = true; + ++m_ccc_stats.m_cdcl_closed; + update_closure_level(d, 1); break; } } @@ -233,6 +256,7 @@ bool ccc::get_solved(svector& decisions) { m_solved.pop(); } } + return found; } @@ -262,14 +286,7 @@ bool ccc::push_decision(solver& s, svector const& decisions, decision literal lit = d.get_literal(thread_id); switch (s.value(lit)) { case l_false: - // TBD: we leak conquer threads if they backjump below spawn point. - if (decisions.empty() && decisions.back().m_spawn_id == thread_id && decisions.back().m_id != d.m_id) { - IF_VERBOSE(0, verbose_stream() << "LEAK avoided\n";); - #pragma omp critical (ccc_solved) - { - m_solved.push(solution(thread_id, decisions.back().m_id)); - } - } + thread_id = (d.m_spawn_id == thread_id || (!decisions.empty() && decisions.back().m_spawn_id == thread_id)) ? thread_id : 0; #pragma omp critical (ccc_solved) { m_solved.push(solution(thread_id, d.m_id)); @@ -431,7 +448,7 @@ lbool ccc::search() { } for (unsigned i = 0; i < solvers.size(); ++i) { - solvers[i]->collect_statistics(m_stats); + solvers[i]->collect_statistics(m_lh_stats); dealloc(solvers[i]); } diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h index b4d497fa0..29bf3c18d 100644 --- a/src/sat/sat_ccc.h +++ b/src/sat/sat_ccc.h @@ -41,7 +41,7 @@ namespace sat { void close() { SASSERT(m_spawn_id > 0); m_spawn_id = -m_spawn_id; } bool is_closed() const { return m_spawn_id < 0; } - void negate() { m_literal.neg(); m_spawn_id = 0; } + void negate() { m_literal.neg(); } literal get_literal(unsigned thread_id) const { return thread_id == m_spawn_id ? ~m_literal : m_literal; } std::ostream& pp(std::ostream& out) const; }; @@ -52,6 +52,15 @@ namespace sat { solution(unsigned t, unsigned s): m_thread_id(t), m_branch_id(s) {} }; + struct stats { + unsigned m_spawn_closed; + unsigned m_cdcl_closed; + stats() { reset(); } + void reset() { + memset(this, 0, sizeof(*this)); + } + }; + solver& m_s; queue m_solved; vector > m_decisions; @@ -61,7 +70,8 @@ namespace sat { unsigned m_branch_id; unsigned_vector m_free_threads; unsigned m_last_closure_level; - ::statistics m_stats; + ::statistics m_lh_stats; + stats m_ccc_stats; lbool conquer(solver& s, unsigned thread_id); bool cube_decision(solver& s, svector& decisions, unsigned thread_id); @@ -74,6 +84,8 @@ namespace sat { bool get_decision(unsigned thread_id, decision& d); bool get_solved(svector& decisions); + void update_closure_level(decision const& d, int offset); + void replay_decisions(solver& s, svector& decisions, unsigned thread_id); static std::ostream& pp(std::ostream& out, svector const& v); @@ -95,7 +107,11 @@ namespace sat { model const& get_model() const { return m_model; } - void collect_statistics(::statistics& st) { st.copy(m_stats); } + void collect_statistics(::statistics& st) { + st.copy(m_lh_stats); + st.update("ccc-spawn-closed", m_ccc_stats.m_spawn_closed); + st.update("ccc-cdcl-closed", m_ccc_stats.m_cdcl_closed); + } }; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index c2763b776..72e64ae1d 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -344,6 +344,9 @@ namespace sat { void try_add_binary(literal u, literal v) { SASSERT(m_search_mode == lookahead_mode::searching); SASSERT(u.var() != v.var()); + if (!is_undef(u) || !is_undef(v)) { + IF_VERBOSE(0, verbose_stream() << "adding assigned binary " << v << " " << u << "\n";); + } set_bstamps(~u); if (is_stamped(~v)) { TRACE("sat", tout << "try_add_binary: " << u << "\n";); @@ -1120,6 +1123,7 @@ namespace sat { } void pop() { + if (m_assumptions.empty()) IF_VERBOSE(0, verbose_stream() << "empty pop\n";); m_assumptions.pop_back(); m_inconsistent = false; SASSERT(m_search_mode == lookahead_mode::searching); From c637240c4030359c5f16f34e5ff61b435bc080da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Apr 2017 16:56:39 -0700 Subject: [PATCH 0109/1283] parallel verison of ccc Signed-off-by: Nikolaj Bjorner --- src/sat/sat_ccc.cpp | 272 ++++++++++++++++++++++++++------------------ src/sat/sat_ccc.h | 36 ++++-- src/util/queue.h | 14 ++- 3 files changed, 204 insertions(+), 118 deletions(-) diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp index eec7e313e..67b7f5e80 100644 --- a/src/sat/sat_ccc.cpp +++ b/src/sat/sat_ccc.cpp @@ -127,6 +127,7 @@ lbool ccc::cube(svector& decisions, lookahead& lh) { lh.push(~l, lh.c_fixed_truth); decisions.back().negate(); decisions.back().m_id = branch2; + decisions.back().m_spawn_id = 0; r = cube(decisions, lh); if (r == l_false) { lh.pop(); @@ -141,6 +142,7 @@ void ccc::update_closure_level(decision const& d, int offset) { m_last_closure_level = (d.m_depth + 3*m_last_closure_level) / 4 + offset; } + unsigned ccc::spawn_conquer(svector const& decisions) { unsigned result = 0; // @@ -152,20 +154,89 @@ unsigned ccc::spawn_conquer(svector const& decisions) { if (!m_free_threads.empty() && m_last_closure_level >= decisions.size()) { result = m_free_threads.back(); m_free_threads.pop_back(); - IF_VERBOSE(0, verbose_stream() << "spawn " << decisions.size() << " " << result << "\n";); + IF_VERBOSE(0, verbose_stream() << "spawn " << result << " with " << decisions.size() << " decisions\n";); } return result; } void ccc::free_conquer(unsigned thread_id) { if (thread_id != 0) { + IF_VERBOSE(0, verbose_stream() << "free conquer " << thread_id << "\n";); m_free_threads.push_back(thread_id); } } +bool ccc::get_solved(svector& decisions) { + // check if CDCL solver got ahead. + bool do_pop = false; + while (true) { + solution sol; + bool is_empty = true; + #pragma omp critical (ccc_solved) + { + if (do_pop) m_solved.pop_front(); + if (!m_solved.empty()) { + sol = m_solved.top(); + is_empty = false; + } + } + if (is_empty) { + return false; + } + do_pop = true; + unsigned branch_id = sol.m_branch_id; + unsigned thread_id = sol.m_thread_id; + free_conquer(thread_id); + for (unsigned i = decisions.size(); i > 0; ) { + --i; + decision& d = decisions[i]; + if (branch_id == d.m_id) { + if (d.m_spawn_id == thread_id && thread_id != 0) { + SASSERT(d.m_spawn_id > 0); + IF_VERBOSE(0, verbose_stream() << thread_id << ": spawn close " << branch_id << " " << " " << d.m_depth << "\n";); + ++m_ccc_stats.m_spawn_closed; + d.close(); + update_closure_level(d, -1); + break; + } + else { + IF_VERBOSE(0, verbose_stream() << thread_id << ": conquer " << branch_id << " " << d.m_depth << " " << decisions.size() << " " << d.get_literal(thread_id) << "\n";); + ++m_ccc_stats.m_cdcl_closed; + update_closure_level(d, 1); + return true; + } + } + // branch is even, d has moved to the next branch + if (branch_id == (d.m_id & ~0x1) && d.m_spawn_id == thread_id && thread_id != 0) { + IF_VERBOSE(0, verbose_stream() << thread_id << ": spawn conquer " << branch_id << " " << " " << d.m_depth << "\n";); + ++m_ccc_stats.m_cdcl_closed; + update_closure_level(d, 1); + return true; + } + } + } +} -lbool ccc::conquer(solver& s, unsigned thread_id) { - SASSERT(thread_id > 0); +void ccc::put_decision(decision const& d) { + for (unsigned i = 0; i < m_num_conquer; ++i) { + #pragma omp critical (ccc_decisions) + { + while (!m_decisions[i].empty()) { + decision d = m_decisions[i].back(); + if (d.m_depth < d.m_depth || d.m_spawn_id != 0) { + break; + } + m_decisions[i].pop_back(); + } + m_decisions[i].push(d); + } + } +} + +// --------------------- +// conquer state machine + +lbool ccc::conquer::search() { try { if (s.inconsistent()) return l_false; s.init_search(); @@ -174,13 +245,11 @@ lbool ccc::conquer(solver& s, unsigned thread_id) { s.cleanup(); s.simplify_problem(); if (s.inconsistent()) return l_false; - - svector decisions; while (true) { SASSERT(!s.inconsistent()); - lbool r = bounded_search(s, decisions, thread_id); + lbool r = bounded_search(); if (r != l_undef) return r; @@ -195,102 +264,47 @@ lbool ccc::conquer(solver& s, unsigned thread_id) { } } -void ccc::replay_decisions(solver& s, svector& decisions, unsigned thread_id) { +void ccc::conquer::replay_decisions() { s.propagate(true); for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < decisions.size(); ++i) { decision const& d = decisions[i]; IF_VERBOSE(2, verbose_stream() << thread_id << ": replay " << d.get_literal(thread_id) << " " << s.value(d.get_literal(thread_id)) << "\n";); - if (!push_decision(s, decisions, d, thread_id)) { + if (!push_decision(d)) { // negation of decision is implied. - // check_non_model("replay", decisions); - decisions.resize(i); - return; + IF_VERBOSE(0, verbose_stream() << thread_id << ": backjump to level " << i << " of " << decisions.size() << "\n";); + while (decisions.size() > i) { + pop_decision(decisions.back()); + decisions.pop_back(); + } + break; + } + + if (d.m_spawn_id == thread_id && d.is_left()) { + // we pushed the right branch on this thread. + IF_VERBOSE(0, verbose_stream() << thread_id << ": skip left branch on level " << i + 1 << " of " << decisions.size() << "\n";); + break; } } } -bool ccc::get_solved(svector& decisions) { - // check if CDCL solver got ahead. - bool found = false; +void ccc::conquer::pop_decision(decision const& d) { + unsigned tid = 0; + if (d.is_spawned(thread_id)) { + tid = thread_id; + m_spawned = false; + IF_VERBOSE(0, verbose_stream() << thread_id << " retire spawn\n";); + } #pragma omp critical (ccc_solved) { - while (!m_solved.empty()) { - solution const& sol = m_solved.top(); - unsigned branch_id = sol.m_branch_id; - unsigned thread_id = sol.m_thread_id; - SASSERT(thread_id > 0); - free_conquer(thread_id); - for (unsigned i = decisions.size(); i > 0; ) { - --i; - decision& d = decisions[i]; - if (branch_id == d.m_id) { - if (d.m_spawn_id == thread_id && thread_id != 0) { - SASSERT(d.m_spawn_id > 0); - IF_VERBOSE(0, verbose_stream() << "spawn close " << branch_id << " " << thread_id << " " << d.m_depth << "\n";); - ++m_ccc_stats.m_spawn_closed; - d.close(); - update_closure_level(d, -1); - } - else { - IF_VERBOSE(0, verbose_stream() << "conquer " << branch_id << " " << thread_id << " " << d.m_depth << " " << d.get_literal(thread_id) << "\n";); - found = true; - ++m_ccc_stats.m_cdcl_closed; - update_closure_level(d, 1); - } - break; - } - // branch is even, d has moved to the next branch - if (branch_id == (d.m_id & ~0x1) && d.m_spawn_id == thread_id && thread_id != 0) { - IF_VERBOSE(0, verbose_stream() << "spawn conquer " << branch_id << " " << thread_id << " " << d.m_depth << "\n";); - found = true; - ++m_ccc_stats.m_cdcl_closed; - update_closure_level(d, 1); - break; - } - } - if (found) { - break; - } - // IF_VERBOSE(1, verbose_stream() << "not found: " << branch_id << " " << decisions.size() << "\n";); - m_solved.pop(); - } - } - - return found; -} - -void ccc::put_decision(decision const& d) { - #pragma omp critical (ccc_decisions) - { - for (unsigned i = 0; i < m_num_conquer; ++i) { - m_decisions[i].push(d); - } + super.m_solved.push(solution(tid, d.m_id)); } } -bool ccc::get_decision(unsigned thread_id, decision& d) { - SASSERT(0 < thread_id && thread_id <= m_decisions.size()); - bool result = false; - #pragma omp critical (ccc_decisions) - { - if (!m_decisions[thread_id - 1].empty()) { - d = m_decisions[thread_id - 1].pop(); - result = true; - } - } - return result; -} - -bool ccc::push_decision(solver& s, svector const& decisions, decision const& d, unsigned thread_id) { +bool ccc::conquer::push_decision(decision const& d) { literal lit = d.get_literal(thread_id); switch (s.value(lit)) { case l_false: - thread_id = (d.m_spawn_id == thread_id || (!decisions.empty() && decisions.back().m_spawn_id == thread_id)) ? thread_id : 0; - #pragma omp critical (ccc_solved) - { - m_solved.push(solution(thread_id, d.m_id)); - } //TBD: s.m_restart_threshold = s.m_config.m_restart_initial; //s.m_conflicts_since_last_restart = 0; @@ -304,62 +318,90 @@ bool ccc::push_decision(solver& s, svector const& decisions, decision s.propagate(true); break; } + m_spawned |= d.is_spawned(thread_id); return true; } -bool ccc::cube_decision(solver& s, svector& decisions, unsigned thread_id) { +bool ccc::conquer::cube_decision() { decision d; bool use_cube_decision = false; SASSERT(s.m_qhead == s.m_trail.size()); - get_cube: - if (!get_decision(thread_id, d)) { - return false; - } - - if (!decisions.empty() && decisions.back().m_depth + 1 < d.m_depth) { - goto get_cube; - } + while (true) { + if (!super.get_decision(thread_id, d)) { + return false; + } - if (!decisions.empty() && decisions.back().m_spawn_id == thread_id && decisions.back().m_depth < d.m_depth) { - goto get_cube; + if (d.is_spawned(thread_id)) IF_VERBOSE(0, verbose_stream() << thread_id << ": spawned d:" << d.m_depth << " decisions: " << decisions.size() << "\n";); + + if (!decisions.empty() && decisions.back().m_depth + 1 < d.m_depth) { + if (d.is_spawned(thread_id)) { + pop_decision(d); + } + } + else { + break; + } + } + SASSERT(decisions.empty() || decisions.back().m_depth + 1 >= d.m_depth); + + if (!decisions.empty() && decisions.back().is_spawned(thread_id) && decisions.back().m_depth == d.m_depth) { + SASSERT(d.m_spawn_id == 0); + SASSERT(decisions.back().is_left()); + SASSERT(!d.is_left()); + IF_VERBOSE(0, verbose_stream() << thread_id << " inherit spawn\n";); + d.m_spawn_id = thread_id; + decisions.back().m_spawn_id = 0; + m_spawned = false; } + SASSERT(decisions.empty() || decisions.back().m_depth + 1 >= d.m_depth); while (!decisions.empty() && decisions.back().m_depth >= d.m_depth) { // check_non_model("cube decision", decisions); + if (decisions.back().is_spawned(thread_id)) { + pop_decision(decisions.back()); + } decisions.pop_back(); } SASSERT(decisions.empty() || decisions.back().m_depth + 1 == d.m_depth); SASSERT(decisions.empty() || decisions.back().m_id == d.m_parent); + if (m_spawned) { + decisions.push_back(d); + return true; + } + s.pop_reinit(s.scope_lvl() - decisions.size()); SASSERT(s.m_qhead == s.m_trail.size()); SASSERT(s.scope_lvl() == decisions.size()); literal lit = d.get_literal(thread_id); - IF_VERBOSE(1, verbose_stream() << thread_id << ": cube " << decisions.size() << " " << d.get_literal(thread_id) << "\n";); + IF_VERBOSE(0, verbose_stream() << thread_id << ": cube " << decisions.size() << " " << d.get_literal(thread_id) << "\n";); IF_VERBOSE(2, pp(verbose_stream() << thread_id << ": push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); - if (push_decision(s, decisions, d, thread_id)) { + if (push_decision(d)) { decisions.push_back(d); } + else { + pop_decision(d); + } return true; } -lbool ccc::bounded_search(solver& s, svector& decisions, unsigned thread_id) { +lbool ccc::conquer::bounded_search() { while (true) { s.checkpoint(); bool done = false; while (!done) { - replay_decisions(s, decisions, thread_id); + replay_decisions(); lbool is_sat = s.propagate_and_backjump_step(done); if (is_sat != l_true) return is_sat; } s.gc(); - if (!cube_decision(s, decisions, thread_id) && !s.decide()) { + if (!cube_decision() && !s.decide()) { lbool is_sat = s.final_check(); if (is_sat != l_undef) { return is_sat; @@ -369,6 +411,20 @@ lbool ccc::bounded_search(solver& s, svector& decisions, unsigned thre } +bool ccc::get_decision(unsigned thread_id, decision& d) { + SASSERT(0 < thread_id && thread_id <= m_decisions.size()); + bool result = false; + #pragma omp critical (ccc_decisions) + { + if (!m_decisions[thread_id - 1].empty()) { + d = m_decisions[thread_id - 1].pop_front(); + result = true; + } + } + return result; +} + + lbool ccc::search() { enum par_exception_kind { DEFAULT_EX, @@ -381,7 +437,7 @@ lbool ccc::search() { scoped_limits scoped_rlimit(m_s.rlimit()); vector limits; - ptr_vector solvers; + ptr_vector solvers; int finished_id = -1; std::string ex_msg; par_exception_kind ex_kind; @@ -395,10 +451,10 @@ lbool ccc::search() { for (int i = 1; i < num_threads; ++i) { limits.push_back(reslimit()); m_s.m_params.set_uint("random_seed", m_s.m_rand()); - solver* s1 = alloc(sat::solver, m_s.m_params, limits.back()); + conquer* s1 = alloc(conquer, *this, m_s.m_params, limits.back(), i); solvers.push_back(s1); - s1->copy(m_s); - scoped_rlimit.push_child(&s1->rlimit()); + s1->s.copy(m_s); + scoped_rlimit.push_child(&(s1->s.rlimit())); m_decisions.push_back(queue()); } for (unsigned i = 1; i < m_num_conquer; ++i) { @@ -413,7 +469,7 @@ lbool ccc::search() { r = cube(); } else { - r = conquer(*solvers[i-1], i); + r = solvers[i-1]->search(); } bool first = false; #pragma omp critical (par_solver) @@ -426,7 +482,7 @@ lbool ccc::search() { } if (first) { for (unsigned j = 0; j < solvers.size(); ++j) { - solvers[j]->rlimit().cancel(); + solvers[j]->s.rlimit().cancel(); } // cancel lookahead solver: m_cancel = true; @@ -444,11 +500,11 @@ lbool ccc::search() { if (finished_id > 0 && result == l_true) { // set model from auxiliary solver - m_model = solvers[finished_id - 1]->get_model(); + m_model = solvers[finished_id - 1]->s.get_model(); } for (unsigned i = 0; i < solvers.size(); ++i) { - solvers[i]->collect_statistics(m_lh_stats); + solvers[i]->s.collect_statistics(m_lh_stats); dealloc(solvers[i]); } diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h index 29bf3c18d..905a64d93 100644 --- a/src/sat/sat_ccc.h +++ b/src/sat/sat_ccc.h @@ -42,7 +42,14 @@ namespace sat { void close() { SASSERT(m_spawn_id > 0); m_spawn_id = -m_spawn_id; } bool is_closed() const { return m_spawn_id < 0; } void negate() { m_literal.neg(); } - literal get_literal(unsigned thread_id) const { return thread_id == m_spawn_id ? ~m_literal : m_literal; } + bool is_left() const { return 0 == (m_id & 0x1); } + bool is_spawned(unsigned thread_id) const { return m_spawn_id == thread_id; } + + // the left branch has an even branch_id. + // the branch is spawned if it is even and the spawn_id is the same as the thread_id, and furthermore it is exploring the left branch. + // it may explore the right branch, but is then not in a spawned mode. + // we retain the spawn id so that the spawned thread can be re-spun. + literal get_literal(unsigned thread_id) const { return ((m_id & 0x1) == 0 && thread_id == m_spawn_id) ? ~m_literal : m_literal; } std::ostream& pp(std::ostream& out) const; }; @@ -50,6 +57,7 @@ namespace sat { unsigned m_thread_id; unsigned m_branch_id; solution(unsigned t, unsigned s): m_thread_id(t), m_branch_id(s) {} + solution(): m_thread_id(0), m_branch_id(0) {} }; struct stats { @@ -61,6 +69,22 @@ namespace sat { } }; + struct conquer { + ccc& super; + solver s; + svector decisions; + unsigned thread_id; + bool m_spawned; + conquer(ccc& super, params_ref const& p, reslimit& l, unsigned tid): super(super), s(p, l), thread_id(tid), m_spawned(false) {} + + lbool search(); + bool cube_decision(); + lbool bounded_search(); + bool push_decision(decision const& d); + void pop_decision(decision const& d); + void replay_decisions(); + }; + solver& m_s; queue m_solved; vector > m_decisions; @@ -72,21 +96,15 @@ namespace sat { unsigned m_last_closure_level; ::statistics m_lh_stats; stats m_ccc_stats; - - lbool conquer(solver& s, unsigned thread_id); - bool cube_decision(solver& s, svector& decisions, unsigned thread_id); - - lbool bounded_search(solver& s, svector& decisions, unsigned thread_id); - bool push_decision(solver& s, svector const& decisions, decision const& d, unsigned thread_id); + lbool cube(); lbool cube(svector& decisions, lookahead& lh); void put_decision(decision const& d); - bool get_decision(unsigned thread_id, decision& d); bool get_solved(svector& decisions); + bool get_decision(unsigned thread_id, decision& d); void update_closure_level(decision const& d, int offset); - void replay_decisions(solver& s, svector& decisions, unsigned thread_id); static std::ostream& pp(std::ostream& out, svector const& v); diff --git a/src/util/queue.h b/src/util/queue.h index 4b85f53f0..a517efc24 100644 --- a/src/util/queue.h +++ b/src/util/queue.h @@ -41,7 +41,7 @@ public: return m_elems[m_head]; } - T pop() { + T pop_front() { SASSERT(!empty()); m_capacity = std::max(m_capacity, m_elems.size()); SASSERT(m_head < m_elems.size()); @@ -55,6 +55,18 @@ public: return m_elems[m_head++]; } + + T back() const { + return m_elems[m_elems.size() - 1]; + } + + T pop_back() { + SASSERT(!empty()); + SASSERT(m_head < m_elems.size()); + T result = back(); + m_elems.shrink(m_elems.size() - 1); + return result; + } }; #endif From 4575b2820d25f6add9d8a159fee2c9dbe9d1ced8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 26 Apr 2017 00:22:59 -0700 Subject: [PATCH 0110/1283] parallelizing lh Signed-off-by: Nikolaj Bjorner --- src/sat/sat_ccc.cpp | 198 ++++++++++++++++++++++++-------------------- src/sat/sat_ccc.h | 35 +++++--- 2 files changed, 128 insertions(+), 105 deletions(-) diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp index 67b7f5e80..025bbafd4 100644 --- a/src/sat/sat_ccc.cpp +++ b/src/sat/sat_ccc.cpp @@ -33,53 +33,36 @@ Notes: using namespace sat; -std::ostream& ccc::decision::pp(std::ostream& out) const { - out << "(" - << "id:" << m_id - << " l:" << m_literal - << " d:" << m_depth; - if (m_spawn_id != 0) { - out << " s:" << m_spawn_id; - } - out << ") "; - return out; -} +// ------------ +// cuber -std::ostream& ccc::pp(std::ostream& out, svector const& v) { - for (unsigned i = 0; i < v.size(); ++i) { - v[i].pp(out); - } - return out; -} +ccc::cuber::cuber(ccc& c): m_ccc(c), lh(c.m_s), m_branch_id(0) {} -lbool ccc::cube() { +lbool ccc::cuber::search() { m_branch_id = 0; m_last_closure_level = 1000; - lookahead lh(m_s); lh.init_search(); lh.m_model.reset(); lookahead::scoped_level _sl(lh, lh.c_fixed_truth); - literal_vector trail; - svector decisions; lh.m_search_mode = lookahead_mode::searching; - lbool r = cube(decisions, lh); + lbool r = research(); if (r == l_true) { - m_model = lh.get_model(); + m_ccc.m_model = lh.get_model(); } - lh.collect_statistics(m_lh_stats); + lh.collect_statistics(m_ccc.m_lh_stats); return r; } -lbool ccc::cube(svector& decisions, lookahead& lh) { - m_s.checkpoint(); +lbool ccc::cuber::research() { + m_ccc.m_s.checkpoint(); if (lh.inconsistent()) { return l_false; } - if (get_solved(decisions)) { + if (get_solved()) { return l_false; } @@ -94,41 +77,47 @@ lbool ccc::cube(svector& decisions, lookahead& lh) { } if (!decisions.empty()) { - put_decision(decisions.back()); + m_ccc.put_decision(decisions.back()); } // update trail and decisions ++lh.m_stats.m_decisions; unsigned parent_id = decisions.empty() ? 0 : decisions.back().m_id; - unsigned spawn_id = spawn_conquer(decisions); + unsigned spawn_id = spawn_conquer(); unsigned branch1 = m_branch_id++; unsigned branch2 = m_branch_id++; decision d(branch1, decisions.size() + 1, l, parent_id, spawn_id); decisions.push_back(d); + IF_VERBOSE(1, d.pp(verbose_stream() << "select " << m_last_closure_level << " ") << "\n";); IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); IF_VERBOSE(2, pp(verbose_stream(), decisions) << "\n"; ); TRACE("sat", tout << "choose: " << l << "\n";); lh.push(l, lh.c_fixed_truth); - lbool r = cube(decisions, lh); + lbool r = research(); if (r == l_false) { lh.pop(); if (decisions.back().is_closed()) { // branch was solved by a spawned conquer process - IF_VERBOSE(0, verbose_stream() << "closed " << decisions.back().m_id << "\n";); + IF_VERBOSE(1, decisions.back().pp(verbose_stream() << "closed ") << "\n";); r = l_false; decisions.pop_back(); } else { + if (spawn_id > 0) { + free_conquer(spawn_id); + m_last_closure_level *= 3; + m_last_closure_level /= 4; + } lh.inc_istamp(); lh.flip_prefix(); lh.push(~l, lh.c_fixed_truth); decisions.back().negate(); decisions.back().m_id = branch2; decisions.back().m_spawn_id = 0; - r = cube(decisions, lh); + r = research(); if (r == l_false) { lh.pop(); decisions.pop_back(); @@ -138,45 +127,50 @@ lbool ccc::cube(svector& decisions, lookahead& lh) { return r; } -void ccc::update_closure_level(decision const& d, int offset) { - m_last_closure_level = (d.m_depth + 3*m_last_closure_level) / 4 + offset; +void ccc::cuber::update_closure_level(decision const& d, int offset) { + m_last_closure_level = (d.m_depth + 3*m_last_closure_level) / 4; + if (m_last_closure_level >= static_cast(abs(offset))) { + m_last_closure_level += offset; + } } - -unsigned ccc::spawn_conquer(svector const& decisions) { +unsigned ccc::cuber::spawn_conquer() { unsigned result = 0; // // decisions must have been solved at a higher level by a conquer thread // - if (m_ccc_stats.m_cdcl_closed < 10) { - return 0; - } - if (!m_free_threads.empty() && m_last_closure_level >= decisions.size()) { - result = m_free_threads.back(); - m_free_threads.pop_back(); - IF_VERBOSE(0, verbose_stream() << "spawn " << result << " with " << decisions.size() << " decisions\n";); + if (!m_free_threads.empty()) { + if (m_last_closure_level <= decisions.size()) { + result = m_free_threads.back(); + ++m_ccc.m_ccc_stats.m_spawn_opened; + m_free_threads.pop_back(); + } + else { + IF_VERBOSE(1, verbose_stream() << m_last_closure_level << " " << decisions.size() << "\n";); + } } return result; } -void ccc::free_conquer(unsigned thread_id) { - if (thread_id != 0) { - IF_VERBOSE(0, verbose_stream() << "free conquer " << thread_id << "\n";); - m_free_threads.push_back(thread_id); + +void ccc::cuber::free_conquer(unsigned id) { + if (id != 0) { + m_free_threads.push_back(id); } } -bool ccc::get_solved(svector& decisions) { + +bool ccc::cuber::get_solved() { // check if CDCL solver got ahead. bool do_pop = false; + solution sol; while (true) { - solution sol; bool is_empty = true; #pragma omp critical (ccc_solved) { - if (do_pop) m_solved.pop_front(); - if (!m_solved.empty()) { - sol = m_solved.top(); + if (do_pop) m_ccc.m_solved.pop_front(); + if (!m_ccc.m_solved.empty()) { + sol = m_ccc.m_solved.top(); is_empty = false; } } @@ -186,30 +180,31 @@ bool ccc::get_solved(svector& decisions) { do_pop = true; unsigned branch_id = sol.m_branch_id; unsigned thread_id = sol.m_thread_id; - free_conquer(thread_id); + bool found = false; for (unsigned i = decisions.size(); i > 0; ) { --i; decision& d = decisions[i]; if (branch_id == d.m_id) { if (d.m_spawn_id == thread_id && thread_id != 0) { SASSERT(d.m_spawn_id > 0); - IF_VERBOSE(0, verbose_stream() << thread_id << ": spawn close " << branch_id << " " << " " << d.m_depth << "\n";); - ++m_ccc_stats.m_spawn_closed; + IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": spawn close ") << "\n";); + ++m_ccc.m_ccc_stats.m_spawn_closed; d.close(); + free_conquer(thread_id); update_closure_level(d, -1); break; } else { - IF_VERBOSE(0, verbose_stream() << thread_id << ": conquer " << branch_id << " " << d.m_depth << " " << decisions.size() << " " << d.get_literal(thread_id) << "\n";); - ++m_ccc_stats.m_cdcl_closed; + IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": conquer ") << "\n";); + ++m_ccc.m_ccc_stats.m_cdcl_closed; update_closure_level(d, 1); return true; - } + } } // branch is even, d has moved to the next branch if (branch_id == (d.m_id & ~0x1) && d.m_spawn_id == thread_id && thread_id != 0) { - IF_VERBOSE(0, verbose_stream() << thread_id << ": spawn conquer " << branch_id << " " << " " << d.m_depth << "\n";); - ++m_ccc_stats.m_cdcl_closed; + IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": spawn conquer ") << "\n";); + ++m_ccc.m_ccc_stats.m_cdcl_closed; update_closure_level(d, 1); return true; } @@ -217,22 +212,6 @@ bool ccc::get_solved(svector& decisions) { } } -void ccc::put_decision(decision const& d) { - for (unsigned i = 0; i < m_num_conquer; ++i) { - #pragma omp critical (ccc_decisions) - { - while (!m_decisions[i].empty()) { - decision d = m_decisions[i].back(); - if (d.m_depth < d.m_depth || d.m_spawn_id != 0) { - break; - } - m_decisions[i].pop_back(); - } - m_decisions[i].push(d); - } - } -} - // --------------------- // conquer state machine @@ -272,7 +251,7 @@ void ccc::conquer::replay_decisions() { if (!push_decision(d)) { // negation of decision is implied. - IF_VERBOSE(0, verbose_stream() << thread_id << ": backjump to level " << i << " of " << decisions.size() << "\n";); + IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": backjump to level " << i << " ") << "\n";); while (decisions.size() > i) { pop_decision(decisions.back()); decisions.pop_back(); @@ -282,7 +261,7 @@ void ccc::conquer::replay_decisions() { if (d.m_spawn_id == thread_id && d.is_left()) { // we pushed the right branch on this thread. - IF_VERBOSE(0, verbose_stream() << thread_id << ": skip left branch on level " << i + 1 << " of " << decisions.size() << "\n";); + IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": skip left branch on level " << i + 1 << " ") << "\n";); break; } } @@ -293,11 +272,11 @@ void ccc::conquer::pop_decision(decision const& d) { if (d.is_spawned(thread_id)) { tid = thread_id; m_spawned = false; - IF_VERBOSE(0, verbose_stream() << thread_id << " retire spawn\n";); + IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": retire spawn ") << "\n";); } #pragma omp critical (ccc_solved) { - super.m_solved.push(solution(tid, d.m_id)); + m_ccc.m_solved.push(solution(tid, d.m_id)); } } @@ -328,11 +307,11 @@ bool ccc::conquer::cube_decision() { SASSERT(s.m_qhead == s.m_trail.size()); while (true) { - if (!super.get_decision(thread_id, d)) { + if (!m_ccc.get_decision(thread_id, d)) { return false; } - if (d.is_spawned(thread_id)) IF_VERBOSE(0, verbose_stream() << thread_id << ": spawned d:" << d.m_depth << " decisions: " << decisions.size() << "\n";); + if (d.is_spawned(thread_id)) IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << " ") << "\n";); if (!decisions.empty() && decisions.back().m_depth + 1 < d.m_depth) { if (d.is_spawned(thread_id)) { @@ -349,8 +328,7 @@ bool ccc::conquer::cube_decision() { SASSERT(d.m_spawn_id == 0); SASSERT(decisions.back().is_left()); SASSERT(!d.is_left()); - IF_VERBOSE(0, verbose_stream() << thread_id << " inherit spawn\n";); - d.m_spawn_id = thread_id; + IF_VERBOSE(1, verbose_stream() << thread_id << " inherit spawn\n";); decisions.back().m_spawn_id = 0; m_spawned = false; } @@ -375,7 +353,7 @@ bool ccc::conquer::cube_decision() { SASSERT(s.m_qhead == s.m_trail.size()); SASSERT(s.scope_lvl() == decisions.size()); literal lit = d.get_literal(thread_id); - IF_VERBOSE(0, verbose_stream() << thread_id << ": cube " << decisions.size() << " " << d.get_literal(thread_id) << "\n";); + IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": cube ") << "\n";); IF_VERBOSE(2, pp(verbose_stream() << thread_id << ": push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); @@ -410,6 +388,27 @@ lbool ccc::conquer::bounded_search() { } } +// -------------- +// shared state + +std::ostream& ccc::decision::pp(std::ostream& out) const { + out << "(" + << "id:" << m_id + << " l:" << m_literal + << " d:" << m_depth; + if (m_spawn_id != 0) { + out << " s:" << m_spawn_id; + } + out << ") "; + return out; +} + +std::ostream& ccc::pp(std::ostream& out, svector const& v) { + for (unsigned i = 0; i < v.size(); ++i) { + v[i].pp(out); + } + return out; +} bool ccc::get_decision(unsigned thread_id, decision& d) { SASSERT(0 < thread_id && thread_id <= m_decisions.size()); @@ -424,6 +423,21 @@ bool ccc::get_decision(unsigned thread_id, decision& d) { return result; } +void ccc::put_decision(decision const& d) { + for (unsigned i = 0; i < m_num_conquer; ++i) { + #pragma omp critical (ccc_decisions) + { + while (false && !m_decisions[i].empty()) { // introduces contention. + decision d = m_decisions[i].back(); + if (d.m_depth < d.m_depth || d.m_spawn_id != 0) { + break; + } + m_decisions[i].pop_back(); + } + m_decisions[i].push(d); + } + } +} lbool ccc::search() { enum par_exception_kind { @@ -436,7 +450,6 @@ lbool ccc::search() { m_cancel = false; scoped_limits scoped_rlimit(m_s.rlimit()); - vector limits; ptr_vector solvers; int finished_id = -1; std::string ex_msg; @@ -445,20 +458,21 @@ lbool ccc::search() { lbool result = l_undef; m_decisions.reset(); + cuber cuber(*this); + m_num_conquer = m_s.m_config.m_num_threads; int num_threads = 1 + m_num_conquer; // for ccc-infinity only two threads. for (int i = 1; i < num_threads; ++i) { - limits.push_back(reslimit()); m_s.m_params.set_uint("random_seed", m_s.m_rand()); - conquer* s1 = alloc(conquer, *this, m_s.m_params, limits.back(), i); + conquer* s1 = alloc(conquer, *this, m_s.m_params, i); solvers.push_back(s1); s1->s.copy(m_s); - scoped_rlimit.push_child(&(s1->s.rlimit())); + scoped_rlimit.push_child(&(s1->m_limit)); m_decisions.push_back(queue()); } for (unsigned i = 1; i < m_num_conquer; ++i) { - m_free_threads.push_back(i); + cuber.m_free_threads.push_back(i); } #pragma omp parallel for @@ -466,7 +480,7 @@ lbool ccc::search() { try { lbool r = l_undef; if (i == 0) { - r = cube(); + r = cuber.search(); } else { r = solvers[i-1]->search(); @@ -482,7 +496,7 @@ lbool ccc::search() { } if (first) { for (unsigned j = 0; j < solvers.size(); ++j) { - solvers[j]->s.rlimit().cancel(); + solvers[j]->m_limit.cancel(); } // cancel lookahead solver: m_cancel = true; diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h index 905a64d93..30c8a3229 100644 --- a/src/sat/sat_ccc.h +++ b/src/sat/sat_ccc.h @@ -62,6 +62,7 @@ namespace sat { struct stats { unsigned m_spawn_closed; + unsigned m_spawn_opened; unsigned m_cdcl_closed; stats() { reset(); } void reset() { @@ -70,12 +71,13 @@ namespace sat { }; struct conquer { - ccc& super; + reslimit m_limit; + ccc& m_ccc; solver s; svector decisions; unsigned thread_id; bool m_spawned; - conquer(ccc& super, params_ref const& p, reslimit& l, unsigned tid): super(super), s(p, l), thread_id(tid), m_spawned(false) {} + conquer(ccc& super, params_ref const& p, unsigned tid): m_ccc(super), s(p, m_limit), thread_id(tid), m_spawned(false) {} lbool search(); bool cube_decision(); @@ -85,27 +87,35 @@ namespace sat { void replay_decisions(); }; + struct cuber { + ccc& m_ccc; + lookahead lh; + unsigned m_branch_id; + unsigned m_last_closure_level; + unsigned_vector m_free_threads; + svector decisions; + + cuber(ccc& c); + lbool search(); + lbool research(); + bool get_solved(); + void update_closure_level(decision const& d, int offset); + unsigned spawn_conquer(); + void free_conquer(unsigned thread_id); + }; + solver& m_s; queue m_solved; vector > m_decisions; unsigned m_num_conquer; model m_model; volatile bool m_cancel; - unsigned m_branch_id; - unsigned_vector m_free_threads; - unsigned m_last_closure_level; ::statistics m_lh_stats; stats m_ccc_stats; - lbool cube(); - lbool cube(svector& decisions, lookahead& lh); void put_decision(decision const& d); - bool get_solved(svector& decisions); bool get_decision(unsigned thread_id, decision& d); - void update_closure_level(decision const& d, int offset); - - static std::ostream& pp(std::ostream& out, svector const& v); void push_model(unsigned v, bool sign); @@ -114,8 +124,6 @@ namespace sat { void check_non_model(char const* fn, svector const& decisions); - unsigned spawn_conquer(svector const& decisions); - void free_conquer(unsigned thread_id); public: @@ -129,6 +137,7 @@ namespace sat { st.copy(m_lh_stats); st.update("ccc-spawn-closed", m_ccc_stats.m_spawn_closed); st.update("ccc-cdcl-closed", m_ccc_stats.m_cdcl_closed); + st.update("ccc-spawn-opened", m_ccc_stats.m_spawn_opened); } }; } From aedabfff7af810e427118e75f3e73dafaef5d014 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Apr 2017 11:24:30 -0700 Subject: [PATCH 0111/1283] disable newer pb encoding Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index d85bdec41..3a134a13c 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -113,12 +113,15 @@ struct pb2bv_rewriter::imp { return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m); } +#if 0 expr_ref result(m); switch (is_le) { case l_true: if (mk_le_tot(sz, args, k, result)) return result; else break; case l_false: if (mk_ge_tot(sz, args, k, result)) return result; else break; case l_undef: break; } +#endif + #if 0 expr_ref result(m); switch (is_le) { From 0ba7c9c39bae4e53ab8b2029be0db88214300b8f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 May 2017 16:53:25 -0700 Subject: [PATCH 0112/1283] adding pb Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 521 ++++++++++++++++++++++++++++++++----- src/sat/card_extension.h | 33 ++- src/sat/sat_simplifier.cpp | 2 +- 3 files changed, 487 insertions(+), 69 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 7d1c27abb..30206a441 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -45,9 +45,11 @@ namespace sat { m_index(index), m_lit(lit), m_k(k), - m_size(wlits.size()) { + m_size(wlits.size()), + m_max_sum(0) { for (unsigned i = 0; i < wlits.size(); ++i) { m_wlits[i] = wlits[i]; + m_max_sum += wlits[i].first; } } @@ -212,14 +214,355 @@ namespace sat { } // pb: - void card_extension::init_watch(pb& p, bool is_true) { - NOT_IMPLEMENTED_YET(); + + void card_extension::copy_pb(card_extension& result) { + for (unsigned i = 0; i < m_pbs.size(); ++i) { + svector wlits; + pb& p = *m_pbs[i]; + for (unsigned i = 0; i < p.size(); ++i) { + wlits.push_back(p[i]); + } + bool_var v = p.lit() == null_literal ? null_bool_var : p.lit().var(); + result.add_pb_ge(v, wlits, p.k()); + } } + // watch a prefix of literals, such that the slack of these is >= k + void card_extension::init_watch(pb& p, bool is_true) { + clear_watch(p); + if (p.lit() != null_literal && p.lit().sign() == is_true) { + p.negate(); + } + + TRACE("sat", display(tout << "init watch: ", p, true);); + SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); + unsigned sz = p.size(), bound = p.k(); + // put the non-false literals into the head. + unsigned slack = 0, num_watch = 0, j = 0; + for (unsigned i = 0; i < sz; ++i) { + if (value(p[i].second) != l_false) { + if (j != i) { + p.swap(i, j); + } + if (slack < bound) { + slack += p[i].first; + ++num_watch; + } + ++j; + } + } + DEBUG_CODE( + bool is_false = false; + for (unsigned k = 0; k < sz; ++k) { + SASSERT(!is_false || value(p[k].second) == l_false); + SASSERT(k < j == (value(p[k].second) != l_false)); + is_false = value(p[k].second) == l_false; + }); + if (slack < bound) { + literal lit = p[j].second; + SASSERT(value(p[j].second) == l_false); + for (unsigned i = j + 1; j < sz; ++i) { + if (lvl(lit) < lvl(p[i].second)) { + lit = p[i].second; + } + } + set_conflict(p, lit); + } + else { + for (unsigned i = 0; i < num_watch; ++i) { + watch_literal(p, p[i]); + } + p.set_slack(slack); + p.set_num_watch(num_watch); + } + } + + /* + Chai Kuhlmann: + Lw - set of watched literals + Lu - set of unwatched literals that are not false + + Lw = Lw \ { alit } + Sw -= value + a_max = max { a | l in Lw u Lu, l = undef } + while (Sw < k + a_max & Lu != 0) { + a_s = max { a | l in Lu } + Sw += a_s + Lw = Lw u {l_s} + Lu = Lu \ {l_s} + } + if (Sw < bound) conflict + while (Sw < k + a_max) { + assign (l_max) + a_max = max { ai | li in Lw, li = undef } + } + ASSERT(Sw >= bound) + return no-conflict + + a_max index: index of non-false literal with maximal weight. + + + */ + lbool card_extension::add_assign(pb& p, literal alit) { + unsigned sz = p.size(); + unsigned bound = p.k(); + unsigned num_watch = p.num_watch(); + unsigned slack = p.slack(); + SASSERT(value(alit) == l_false); + SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); + SASSERT(num_watch <= sz); + unsigned index = 0; + unsigned a_max = 0; + unsigned max_index = 0; + m_pb_undef.reset(); + for (; index < num_watch; ++index) { + literal lit = p[index].second; + if (lit == alit) { + break; + } + if (value(lit) == l_undef) { + m_pb_undef.push_back(index); + if (p[index].first > a_max) { + a_max = p[index].first; + max_index = index; + } + } + } + + for (unsigned j = index + 1; a_max == 0 && j < num_watch; ++j) { + literal lit = p[j].second; + if (value(lit) == l_undef) { + m_pb_undef.push_back(j); + a_max = p[j].first; + max_index = j; + } + } + for (unsigned j = num_watch; a_max == 0 && j < sz; ++j) { + literal lit = p[j].second; + if (value(lit) == l_undef) { + p.swap(j, num_watch); + m_pb_undef.push_back(num_watch); + a_max = p[num_watch].first; + max_index = num_watch; + } + } + + unsigned val = p[index].first; + SASSERT(num_watch > 0); + SASSERT(index < num_watch); + SASSERT(value(p[index].second) == l_false); + SASSERT(val <= slack); + slack -= val; + // find literals to swap with: + for (unsigned j = num_watch; j < sz && slack < bound + a_max; ++j) { + if (value(p[j].second) != l_false) { + slack += p[j].first; + watch_literal(p, p[j]); + p.swap(num_watch, j); + if (value(p[num_watch].second) == l_undef && a_max < p[num_watch].first) { + m_pb_undef.push_back(num_watch); + a_max = p[num_watch].first; + max_index = num_watch; + } + ++num_watch; + } + } + + if (slack < bound) { + // maintain watching the literal + slack += val; + p.set_slack(slack); + p.set_num_watch(num_watch); + SASSERT(bound <= slack); + TRACE("sat", tout << "conflict " << alit << "\n";); + set_conflict(p, alit); + return l_false; + } + + // swap out the watched literal. + p.set_slack(slack); + --num_watch; + SASSERT(num_watch > 0); + p.set_num_watch(num_watch); + p.swap(num_watch, index); + if (num_watch == max_index) { + max_index = index; + } + + SASSERT(max_index < sz); + while (slack < bound + a_max && !s().inconsistent()) { + // variable at max-index must be assigned to true. + assign(p, p[max_index].second); + + a_max = 0; + // find the next a_max among m_pb_undef + while (!m_pb_undef.empty() && l_undef != value(p[m_pb_undef.back()].second)) { + m_pb_undef.pop_back(); + } + if (m_pb_undef.empty()) { + break; + } + max_index = m_pb_undef.back(); + a_max = p[max_index].first; + m_pb_undef.pop_back(); + } + + return s().inconsistent() ? l_false : l_true; + } + + void card_extension::watch_literal(pb& p, wliteral l) { + literal lit = l.second; + init_watch(lit.var()); + ptr_vector* pbs = m_var_infos[lit.var()].m_pb_watch[lit.sign()]; + if (pbs == 0) { + pbs = alloc(ptr_vector); + m_var_infos[lit.var()].m_pb_watch[lit.sign()] = pbs; + } + else if (is_tag_empty(pbs)) { + pbs = set_tag_non_empty(pbs); + m_var_infos[lit.var()].m_pb_watch[lit.sign()] = pbs; + } + TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); + pbs->push_back(&p); + } + + void card_extension::clear_watch(pb& p) { + unsigned sz = p.size(); + for (unsigned i = 0; i < sz; ++i) { + unwatch_literal(p[i].second, &p); + } + } + + void card_extension::unwatch_literal(literal lit, pb* p) { + if (m_var_infos.size() <= static_cast(lit.var())) { + return; + } + pb_watch*& pbs = m_var_infos[lit.var()].m_pb_watch[lit.sign()]; + if (!is_tag_empty(pbs)) { + if (remove(*pbs, p)) { + pbs = set_tag_empty(pbs); + } + } + } + + void card_extension::set_conflict(pb& p, literal lit) { + m_stats.m_num_pb_conflicts++; + TRACE("sat", display(tout, p, true); ); + // SASSERT(validate_conflict(p)); + SASSERT(value(lit) == l_false); + s().set_conflict(justification::mk_ext_justification(p.index()), ~lit); + SASSERT(s().inconsistent()); + } + + void card_extension::assign(pb& p, literal lit) { + switch (value(lit)) { + case l_true: + break; + case l_false: + set_conflict(p, lit); + break; + default: + m_stats.m_num_pb_propagations++; + m_num_propagations_since_pop++; + if (s().m_config.m_drat) { + svector ps; + literal_vector lits; + get_pb_antecedents(lit, p, lits); + lits.push_back(lit); + ps.push_back(drat::premise(drat::s_ext(), p.lit())); + s().m_drat.add(lits, ps); + } + s().assign(lit, justification::mk_ext_justification(p.index())); + break; + } + } + + void card_extension::display(std::ostream& out, pb& p, bool values) const { + out << p.lit() << "[" << p.size() << "]"; + if (p.lit() != null_literal && values) { + out << "@(" << value(p.lit()); + if (value(p.lit()) != l_undef) { + out << ":" << lvl(p.lit()); + } + out << "): "; + } + else { + out << ": "; + } + for (unsigned i = 0; i < p.size(); ++i) { + literal l = p[i].second; + unsigned w = p[i].first; + if (w > 1) out << w << " * "; + out << l; + if (values) { + out << "@(" << value(l); + if (value(l) != l_undef) { + out << ":" << lvl(l); + } + out << ") "; + } + else { + out << " "; + } + } + out << ">= " << p.k() << "\n"; + } + + void card_extension::asserted_pb(literal l, ptr_vector* pbs, pb* p0) { + TRACE("sat", tout << l << " " << !is_tag_empty(pbs) << " " << (p0 != 0) << "\n";); + if (!is_tag_empty(pbs)) { + ptr_vector::iterator begin = pbs->begin(); + ptr_vector::iterator it = begin, it2 = it, end = pbs->end(); + for (; it != end; ++it) { + pb& p = *(*it); + if (p.lit() != null_literal && value(p.lit()) != l_true) { + continue; + } + switch (add_assign(p, ~l)) { + case l_false: // conflict + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + SASSERT(s().inconsistent()); + pbs->set_end(it2); + return; + case l_true: // unit propagation, keep watching the literal + if (it2 != it) { + *it2 = *it; + } + ++it2; + break; + case l_undef: // watch literal was swapped + break; + } + } + pbs->set_end(it2); + if (pbs->empty()) { + m_var_infos[l.var()].m_pb_watch[!l.sign()] = set_tag_empty(pbs); + } + } + + if (p0 != 0 && !s().inconsistent()) { + init_watch(*p0, !l.sign()); + } + } // xor: + + void card_extension::copy_xor(card_extension& result) { + for (unsigned i = 0; i < m_xors.size(); ++i) { + literal_vector lits; + xor& x = *m_xors[i]; + for (unsigned i = 0; i < x.size(); ++i) { + lits.push_back(x[i]); + } + bool_var v = x.lit() == null_literal ? null_bool_var : x.lit().var(); + result.add_xor(v, lits); + } + } + void card_extension::clear_watch(xor& x) { unwatch_literal(x[0], &x); unwatch_literal(x[1], &x); @@ -229,7 +572,7 @@ namespace sat { if (m_var_infos.size() <= static_cast(lit.var())) { return; } - xor_watch* xors = m_var_infos[lit.var()].m_xor_watch; + xor_watch*& xors = m_var_infos[lit.var()].m_xor_watch; if (!is_tag_empty(xors)) { if (remove(*xors, c)) { xors = set_tag_empty(xors); @@ -384,6 +727,45 @@ namespace sat { return s().inconsistent() ? l_false : l_true; } + void card_extension::asserted_xor(literal l, ptr_vector* xors, xor* x) { + TRACE("sat", tout << l << " " << !is_tag_empty(xors) << " " << (x != 0) << "\n";); + if (!is_tag_empty(xors)) { + ptr_vector::iterator begin = xors->begin(); + ptr_vector::iterator it = begin, it2 = it, end = xors->end(); + for (; it != end; ++it) { + xor& c = *(*it); + if (c.lit() != null_literal && value(c.lit()) != l_true) { + continue; + } + switch (add_assign(c, ~l)) { + case l_false: // conflict + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + SASSERT(s().inconsistent()); + xors->set_end(it2); + return; + case l_undef: // watch literal was swapped + break; + case l_true: // unit propagation, keep watching the literal + if (it2 != it) { + *it2 = *it; + } + ++it2; + break; + } + } + xors->set_end(it2); + if (xors->empty()) { + m_var_infos[l.var()].m_xor_watch = set_tag_empty(xors); + } + } + + if (x != 0 && !s().inconsistent()) { + init_watch(*x, !l.sign()); + } + } + void card_extension::normalize_active_coeffs() { while (!m_active_var_set.empty()) m_active_var_set.erase(); @@ -551,7 +933,15 @@ namespace sat { ++m_stats.m_num_xor_resolves; } else if (is_pb_index(index)) { - NOT_IMPLEMENTED_YET(); + pb& p = index2pb(index); + m_lemma.reset(); + m_bound += offset; + inc_coeff(consequent, offset); + get_pb_antecedents(consequent, p, m_lemma); + for (unsigned i = 0; i < m_lemma.size(); ++i) { + process_antecedent(~m_lemma[i], offset); + } + ++m_stats.m_num_pb_resolves; } else { UNREACHABLE(); @@ -810,10 +1200,10 @@ namespace sat { } void card_extension::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { - unsigned index = 4*m_pb.size() + 0x11; + unsigned index = 4*m_pbs.size() + 0x11; literal lit = v == null_bool_var ? null_literal : literal(v, false); pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(index, lit, wlits, k); - m_pb.push_back(p); + m_pbs.push_back(p); if (v == null_bool_var) { init_watch(*p, true); m_pb_axioms.push_back(p); @@ -946,6 +1336,25 @@ namespace sat { TRACE("sat", tout << r << "\n";); } + void card_extension::get_pb_antecedents(literal l, pb const& p, literal_vector& r) { + if (p.lit() != null_literal) r.push_back(p.lit()); + SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); + unsigned k = p.k(); + unsigned max_sum = p.max_sum(); + for (unsigned i = p.size(); i > 0 && max_sum >= k; ) { + --i; + literal lit = p[i].second; + if (lit == l) { + max_sum -= p[i].first; + } + else if (value(lit) == l_false) { + r.push_back(~p[i].second); + max_sum -= p[i].first; + } + } + SASSERT(max_sum < k); + } + void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { if (is_card_index(idx)) { card& c = index2card(idx); @@ -984,7 +1393,8 @@ namespace sat { } } else if (is_pb_index(idx)) { - NOT_IMPLEMENTED_YET(); + pb const& p = index2pb(idx); + get_pb_antecedents(l, p, r); } else { UNREACHABLE(); @@ -1054,9 +1464,11 @@ namespace sat { if (v >= m_var_infos.size()) return; var_info& vinfo = m_var_infos[v]; ptr_vector* cards = vinfo.m_card_watch[!l.sign()]; + ptr_vector* xors = vinfo.m_xor_watch; + ptr_vector* pbs = vinfo.m_pb_watch[!l.sign()]; + pb* p = vinfo.m_pb; card* crd = vinfo.m_card; xor* x = vinfo.m_xor; - ptr_vector* xors = vinfo.m_xor_watch; if (!is_tag_empty(cards)) { ptr_vector::iterator begin = cards->begin(); @@ -1093,51 +1505,17 @@ namespace sat { if (crd != 0 && !s().inconsistent()) { init_watch(*crd, !l.sign()); } + + if ((!is_tag_empty(pbs) || p) && !s().inconsistent()) { + asserted_pb(l, pbs, p); + } + if (m_has_xor && !s().inconsistent()) { asserted_xor(l, xors, x); } } - void card_extension::asserted_xor(literal l, ptr_vector* xors, xor* x) { - TRACE("sat", tout << l << " " << !is_tag_empty(xors) << " " << (x != 0) << "\n";); - if (!is_tag_empty(xors)) { - ptr_vector::iterator begin = xors->begin(); - ptr_vector::iterator it = begin, it2 = it, end = xors->end(); - for (; it != end; ++it) { - xor& c = *(*it); - if (c.lit() != null_literal && value(c.lit()) != l_true) { - continue; - } - switch (add_assign(c, ~l)) { - case l_false: // conflict - for (; it != end; ++it, ++it2) { - *it2 = *it; - } - SASSERT(s().inconsistent()); - xors->set_end(it2); - return; - case l_undef: // watch literal was swapped - break; - case l_true: // unit propagation, keep watching the literal - if (it2 != it) { - *it2 = *it; - } - ++it2; - break; - } - } - xors->set_end(it2); - if (xors->empty()) { - m_var_infos[l.var()].m_xor_watch = set_tag_empty(xors); - } - } - - if (x != 0 && !s().inconsistent()) { - init_watch(*x, !l.sign()); - } - } - check_result card_extension::check() { return CR_DONE; } void card_extension::push() { @@ -1153,13 +1531,17 @@ namespace sat { m_var_trail.pop_back(); if (v != null_bool_var) { card* c = m_var_infos[v].m_card; - clear_watch(*c); - m_var_infos[v].m_card = 0; - dealloc(c); + if (c) { + clear_watch(*c); + m_var_infos[v].m_card = 0; + dealloc(c); + } xor* x = m_var_infos[v].m_xor; - clear_watch(*x); - m_var_infos[v].m_xor = 0; - dealloc(x); + if (x) { + clear_watch(*x); + m_var_infos[v].m_xor = 0; + dealloc(x); + } } } m_var_lim.resize(new_lim); @@ -1182,15 +1564,8 @@ namespace sat { bool_var v = c.lit() == null_literal ? null_bool_var : c.lit().var(); result->add_at_least(v, lits, c.k()); } - for (unsigned i = 0; i < m_xors.size(); ++i) { - literal_vector lits; - xor& x = *m_xors[i]; - for (unsigned i = 0; i < x.size(); ++i) { - lits.push_back(x[i]); - } - bool_var v = x.lit() == null_literal ? null_bool_var : x.lit().var(); - result->add_xor(v, lits); - } + copy_xor(*result); + copy_pb(*result); return result; } @@ -1347,7 +1722,15 @@ namespace sat { } } else if (is_pb_index(idx)) { - NOT_IMPLEMENTED_YET(); + pb& p = index2pb(idx); + out << "pb " << p.lit() << ": "; + for (unsigned i = 0; i < p.size(); ++i) { + if (p[i].first != 1) { + out << p[i].first << " "; + } + out << p[i].second << " "; + } + out << ">= " << p.k(); } else { UNREACHABLE(); @@ -1362,6 +1745,9 @@ namespace sat { st.update("xor propagations", m_stats.m_num_xor_propagations); st.update("xor conflicts", m_stats.m_num_xor_conflicts); st.update("xor resolves", m_stats.m_num_xor_resolves); + st.update("pb propagations", m_stats.m_num_pb_propagations); + st.update("pb conflicts", m_stats.m_num_pb_conflicts); + st.update("pb resolves", m_stats.m_num_pb_resolves); } bool card_extension::validate_conflict(card& c) { @@ -1457,7 +1843,12 @@ namespace sat { if (lxor != null_literal) p.push(~lxor, offset); } else if (is_pb_index(index)) { - NOT_IMPLEMENTED_YET(); + pb& pb = index2pb(index); + p.reset(pb.k()); + for (unsigned i = 0; i < pb.size(); ++i) { + p.push(pb[i].second, pb[i].first); + } + if (pb.lit() != null_literal) p.push(~pb.lit(), pb.k()); } else { UNREACHABLE(); diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 6f8b6d120..0e229a056 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -36,6 +36,9 @@ namespace sat { unsigned m_num_xor_propagations; unsigned m_num_xor_conflicts; unsigned m_num_xor_resolves; + unsigned m_num_pb_propagations; + unsigned m_num_pb_conflicts; + unsigned m_num_pb_resolves; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -66,6 +69,9 @@ namespace sat { literal m_lit; unsigned m_k; unsigned m_size; + unsigned m_slack; + unsigned m_num_watch; + unsigned m_max_sum; wliteral m_wlits[0]; public: static size_t get_obj_size(unsigned num_lits) { return sizeof(card) + num_lits * sizeof(wliteral); } @@ -75,6 +81,11 @@ namespace sat { wliteral operator[](unsigned i) const { return m_wlits[i]; } unsigned k() const { return m_k; } unsigned size() const { return m_size; } + unsigned slack() const { return m_slack; } + void set_slack(unsigned s) { m_slack = s; } + unsigned num_watch() const { return m_num_watch; } + unsigned max_sum() const { return m_max_sum; } + void set_num_watch(unsigned s) { m_num_watch = s; } void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } void negate(); }; @@ -153,7 +164,7 @@ namespace sat { ptr_vector m_cards; ptr_vector m_xors; - ptr_vector m_pb; + ptr_vector m_pbs; scoped_ptr_vector m_card_axioms; scoped_ptr_vector m_pb_axioms; @@ -175,6 +186,9 @@ namespace sat { bool m_has_xor; unsigned_vector m_parity_marks; literal_vector m_parity_trail; + + unsigned_vector m_pb_undef; + void ensure_parity_size(bool_var v); unsigned get_parity(bool_var v); void inc_parity(bool_var v); @@ -193,6 +207,7 @@ namespace sat { void unwatch_literal(literal w, card* c); // xor specific functionality + void copy_xor(card_extension& result); void clear_watch(xor& x); void watch_literal(xor& x, literal lit); void unwatch_literal(literal w, xor* x); @@ -202,17 +217,28 @@ namespace sat { bool parity(xor const& x, unsigned offset) const; lbool add_assign(xor& x, literal alit); void asserted_xor(literal l, ptr_vector* xors, xor* x); + void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); + bool is_card_index(unsigned idx) const { return 0x00 == (idx & 0x11); } bool is_xor_index(unsigned idx) const { return 0x01 == (idx & 0x11); } bool is_pb_index(unsigned idx) const { return 0x11 == (idx & 0x11); } card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 2]; } xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 2]; } - pb& index2pb(unsigned idx) const { SASSERT(is_pb_index(idx)); return *m_pb[idx >> 2]; } + pb& index2pb(unsigned idx) const { SASSERT(is_pb_index(idx)); return *m_pbs[idx >> 2]; } - void get_xor_antecedents(literal l, unsigned inddex, justification js, literal_vector& r); + // pb functionality + void copy_pb(card_extension& result); + void asserted_pb(literal l, ptr_vector* pbs, pb* p); void init_watch(pb& p, bool is_true); + lbool add_assign(pb& p, literal alit); + void watch_literal(pb& p, wliteral lit); + void clear_watch(pb& p); + void set_conflict(pb& p, literal lit); + void assign(pb& p, literal l); + void unwatch_literal(literal w, pb* p); + void get_pb_antecedents(literal l, pb const& p, literal_vector & r); template @@ -260,6 +286,7 @@ namespace sat { void display(std::ostream& out, ineq& p) const; void display(std::ostream& out, card& c, bool values) const; + void display(std::ostream& out, pb& p, bool values) const; void display(std::ostream& out, xor& c, bool values) const; void display_watch(std::ostream& out, bool_var v) const; void display_watch(std::ostream& out, bool_var v, bool sign) const; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 407475280..2687c59e5 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -191,7 +191,7 @@ namespace sat { m_elim_counter = m_res_limit; m_old_num_elim_vars = m_num_elim_vars; - scoped_finalize _scoped_finalize(*this); + // scoped_finalize _scoped_finalize(*this); do { if (m_subsumption) From c49550ff2dcc12f3c4cc4f959af3c1587bbacbae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 May 2017 18:03:38 -0700 Subject: [PATCH 0113/1283] enable pb solver Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 33 +++++++ src/sat/card_extension.cpp | 3 + src/sat/sat_params.pyg | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 3 +- src/sat/tactic/goal2sat.cpp | 121 ++++++++++++++++++++++++-- 5 files changed, 154 insertions(+), 7 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 3a134a13c..5cef19234 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -53,6 +53,7 @@ struct pb2bv_rewriter::imp { rational m_k; vector m_coeffs; bool m_keep_cardinality_constraints; + bool m_keep_pb_constraints; unsigned m_min_arity; template @@ -565,6 +566,7 @@ struct pb2bv_rewriter::imp { m_trail(m), m_args(m), m_keep_cardinality_constraints(false), + m_keep_pb_constraints(false), m_min_arity(2) {} @@ -701,11 +703,33 @@ struct pb2bv_rewriter::imp { if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); } + else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) { + return false; + } + else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) { + return false; + } + else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) { + return false; + } else { result = mk_bv(f, sz, args); } return true; } + + bool has_small_coefficients(func_decl* f) { + unsigned sz = f->get_arity(); + unsigned sum = 0; + for (unsigned i = 0; i < sz; ++i) { + rational c = pb.get_coeff(f, i); + if (!c.is_unsigned()) return false; + unsigned sum1 = sum + c.get_unsigned(); + if (sum1 < sum) return false; + sum = sum1; + } + return true; + } // definitions used for sorting network literal mk_false() { return m.mk_false(); } @@ -733,6 +757,10 @@ struct pb2bv_rewriter::imp { void keep_cardinality_constraints(bool f) { m_keep_cardinality_constraints = f; } + + void keep_pb_constraints(bool f) { + m_keep_pb_constraints = f; + } }; struct card2bv_rewriter_cfg : public default_rewriter_cfg { @@ -745,6 +773,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 keep_pb_constraints(bool f) { m_r.keep_pb_constraints(f); } }; class card_pb_rewriter : public rewriter_tpl { @@ -754,6 +783,7 @@ struct pb2bv_rewriter::imp { rewriter_tpl(m, false, m_cfg), m_cfg(i, m) {} void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); } + void keep_pb_constraints(bool f) { m_cfg.keep_pb_constraints(f); } }; card_pb_rewriter m_rw; @@ -764,14 +794,17 @@ struct pb2bv_rewriter::imp { m_num_translated(0), m_rw(*this, m) { m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", false)); + m_rw.keep_pb_constraints(p.get_bool("keep_pb_constraints", false)); } void updt_params(params_ref const & p) { m_params.append(p); m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", false)); + m_rw.keep_pb_constraints(m_params.get_bool("keep_pb_constraints", false)); } 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_pb_constraints", CPK_BOOL, "(default: true) retain pb constraints (don't bit-blast them) and use built-in pb solver"); } unsigned get_num_steps() const { return m_rw.get_num_steps(); } diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 30206a441..bd32a7c40 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -49,6 +49,9 @@ namespace sat { m_max_sum(0) { for (unsigned i = 0; i < wlits.size(); ++i) { m_wlits[i] = wlits[i]; + if (m_max_sum + wlits[i].first < m_max_sum) { + throw default_exception("addition of pb coefficients overflows"); + } m_max_sum += wlits[i].first; } } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index a13a8e8b5..226c79642 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -27,6 +27,7 @@ def_module_params('sat', ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), ('cardinality.solver', BOOL, False, 'use cardinality solver'), + ('pb.solver', BOOL, False, 'use pb solver'), ('xor.solver', BOOL, False, 'use xor solver'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0c0f82537..0d12c0a94 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -216,7 +216,8 @@ public: m_params.append(p); sat_params p1(p); m_params.set_bool("elim_vars", false); - m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); + m_params.set_bool("keep_cardinality_constraints", p1.pb_solver() || p1.cardinality_solver()); + m_params.set_bool("keep_pb_constraints", p1.pb_solver()); m_params.set_bool("xor_solver", p1.xor_solver()); m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 971843d55..9d07ec3e6 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -419,6 +419,103 @@ struct goal2sat::imp { } } + typedef std::pair wliteral; + + void check_unsigned(rational const& c) { + if (!c.is_unsigned()) { + throw default_exception("unsigned coefficient expected"); + } + } + + void convert_to_wlits(app* t, sat::literal_vector const& lits, svector& wlits) { + for (unsigned i = 0; i < lits.size(); ++i) { + rational c = pb.get_coeff(t, i); + check_unsigned(c); + wlits.push_back(std::make_pair(c.get_unsigned(), lits[i])); + } + } + + void convert_pb_args(app* t, svector& wlits) { + sat::literal_vector lits; + convert_pb_args(t->get_num_args(), lits); + convert_to_wlits(t, lits, wlits); + } + + void convert_pb_ge(app* t, bool root, bool sign) { + rational k = pb.get_k(t); + check_unsigned(k); + svector wlits; + convert_pb_args(t, wlits); + unsigned sz = m_result_stack.size(); + if (root) { + m_result_stack.reset(); + m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); + } + else { + sat::bool_var v = m_solver.mk_var(true); + sat::literal lit(v, sign); + m_ext->add_pb_ge(v, wlits, k.get_unsigned()); + TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); + m_result_stack.shrink(sz - t->get_num_args()); + m_result_stack.push_back(lit); + } + } + + void convert_pb_le(app* t, bool root, bool sign) { + rational k = pb.get_k(t); + k.neg(); + svector wlits; + convert_pb_args(t, wlits); + for (unsigned i = 0; i < wlits.size(); ++i) { + wlits[i].second.neg(); + k += rational(wlits[i].first); + } + check_unsigned(k); + unsigned sz = m_result_stack.size(); + if (root) { + m_result_stack.reset(); + m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); + } + else { + sat::bool_var v = m_solver.mk_var(true); + sat::literal lit(v, sign); + m_ext->add_pb_ge(v, wlits, k.get_unsigned()); + TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); + m_result_stack.shrink(sz - t->get_num_args()); + m_result_stack.push_back(lit); + } + } + + void convert_pb_eq(app* t, bool root, bool sign) { + rational k = pb.get_k(t); + SASSERT(k.is_unsigned()); + svector wlits; + convert_pb_args(t, wlits); + sat::bool_var v1 = root ? sat::null_bool_var : m_solver.mk_var(true); + sat::bool_var v2 = root ? sat::null_bool_var : m_solver.mk_var(true); + m_ext->add_pb_ge(v1, wlits, k.get_unsigned()); + k.neg(); + for (unsigned i = 0; i < wlits.size(); ++i) { + wlits[i].second.neg(); + k += rational(wlits[i].first); + } + check_unsigned(k); + m_ext->add_pb_ge(v2, wlits, k.get_unsigned()); + if (root) { + m_result_stack.reset(); + } + else { + sat::literal l1(v1, false), l2(v2, false); + sat::bool_var v = m_solver.mk_var(); + sat::literal l(v, false); + mk_clause(~l, l1); + mk_clause(~l, l2); + mk_clause(~l1, ~l2, l); + m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); + m_result_stack.push_back(l); + } + } + void convert_at_least_k(app* t, rational k, bool root, bool sign) { SASSERT(k.is_unsigned()); sat::literal_vector lits; @@ -529,16 +626,28 @@ struct goal2sat::imp { convert_at_least_k(t, pb.get_k(t), root, sign); break; case OP_PB_LE: - SASSERT(pb.has_unit_coefficients(t)); - convert_at_most_k(t, pb.get_k(t), root, sign); + if (pb.has_unit_coefficients(t)) { + convert_at_most_k(t, pb.get_k(t), root, sign); + } + else { + convert_pb_le(t, root, sign); + } break; case OP_PB_GE: - SASSERT(pb.has_unit_coefficients(t)); - convert_at_least_k(t, pb.get_k(t), root, sign); + if (pb.has_unit_coefficients(t)) { + convert_at_least_k(t, pb.get_k(t), root, sign); + } + else { + convert_pb_ge(t, root, sign); + } break; case OP_PB_EQ: - SASSERT(pb.has_unit_coefficients(t)); - convert_eq_k(t, pb.get_k(t), root, sign); + if (pb.has_unit_coefficients(t)) { + convert_eq_k(t, pb.get_k(t), root, sign); + } + else { + convert_pb_eq(t, root, sign); + } break; default: UNREACHABLE(); From cfd2292f4e6db66c4cc8bb4528fc57cedec3af45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 8 May 2017 13:50:05 -0700 Subject: [PATCH 0114/1283] local Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b674ed70a..664f05112 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ project(Z3 C CXX) set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 5) set(Z3_VERSION_PATCH 1) -set(Z3_VERSION_TWEAK 0303) +set(Z3_VERSION_TWEAK 0304) set(Z3_FULL_VERSION 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") message(STATUS "Z3 version ${Z3_VERSION}") From 2033e649b52404a0b99f9792f202c6958e1ddc8b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 May 2017 09:33:27 -0700 Subject: [PATCH 0115/1283] fix bugs related to use of lookahead equivalences and encoding of pb constraints Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 94 ++++++++++++++++++++------------------ src/sat/card_extension.h | 19 ++++---- src/sat/sat_config.cpp | 4 +- src/sat/sat_config.h | 1 + src/sat/sat_lookahead.h | 49 +++++++++++++++----- src/sat/sat_params.pyg | 1 + src/sat/sat_simplifier.cpp | 11 +++-- src/sat/sat_solver.cpp | 6 ++- 8 files changed, 115 insertions(+), 70 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index bd32a7c40..df5bb1eed 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -482,7 +482,7 @@ namespace sat { } } - void card_extension::display(std::ostream& out, pb& p, bool values) const { + void card_extension::display(std::ostream& out, pb const& p, bool values) const { out << p.lit() << "[" << p.size() << "]"; if (p.lit() != null_literal && values) { out << "@(" << value(p.lit()); @@ -835,8 +835,9 @@ namespace sat { bool card_extension::resolve_conflict() { - if (0 == m_num_propagations_since_pop) + if (0 == m_num_propagations_since_pop) { return false; + } reset_coeffs(); m_num_marks = 0; m_bound = 0; @@ -941,6 +942,7 @@ namespace sat { m_bound += offset; inc_coeff(consequent, offset); get_pb_antecedents(consequent, p, m_lemma); + TRACE("sat", tout << m_lemma << "\n";); for (unsigned i = 0; i < m_lemma.size(); ++i) { process_antecedent(~m_lemma[i], offset); } @@ -1187,6 +1189,7 @@ namespace sat { void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { unsigned index = 4*m_cards.size(); + SASSERT(is_card_index(index)); literal lit = v == null_bool_var ? null_literal : literal(v, false); card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); m_cards.push_back(c); @@ -1203,7 +1206,8 @@ namespace sat { } void card_extension::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { - unsigned index = 4*m_pbs.size() + 0x11; + unsigned index = 4*m_pbs.size() + 0x3; + SASSERT(is_pb_index(index)); literal lit = v == null_bool_var ? null_literal : literal(v, false); pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(index, lit, wlits, k); m_pbs.push_back(p); @@ -1221,7 +1225,8 @@ namespace sat { void card_extension::add_xor(bool_var v, literal_vector const& lits) { m_has_xor = true; - unsigned index = 4*m_xors.size() + 0x01; + unsigned index = 4*m_xors.size() + 0x1; + SASSERT(is_xor_index(index)); xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, literal(v, false), lits); m_xors.push_back(x); init_watch(v); @@ -1358,46 +1363,50 @@ namespace sat { SASSERT(max_sum < k); } + void card_extension::get_card_antecedents(literal l, card const& c, literal_vector& r) { + DEBUG_CODE( + bool found = false; + for (unsigned i = 0; !found && i < c.k(); ++i) { + found = c[i] == l; + } + SASSERT(found);); + + if (c.lit() != null_literal) r.push_back(c.lit()); + SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); + for (unsigned i = c.k(); i < c.size(); ++i) { + SASSERT(value(c[i]) == l_false); + r.push_back(~c[i]); + } + } + + void card_extension::get_xor_antecedents(literal l, xor const& x, literal_vector& r) { + if (x.lit() != null_literal) r.push_back(x.lit()); + // TRACE("sat", display(tout << l << " ", x, true);); + SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); + SASSERT(x[0].var() == l.var() || x[1].var() == l.var()); + if (x[0].var() == l.var()) { + SASSERT(value(x[1]) != l_undef); + r.push_back(value(x[1]) == l_true ? x[1] : ~x[1]); + } + else { + SASSERT(value(x[0]) != l_undef); + r.push_back(value(x[0]) == l_true ? x[0] : ~x[0]); + } + for (unsigned i = 2; i < x.size(); ++i) { + SASSERT(value(x[i]) != l_undef); + r.push_back(value(x[i]) == l_true ? x[i] : ~x[i]); + } + } + void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { if (is_card_index(idx)) { - card& c = index2card(idx); - - DEBUG_CODE( - bool found = false; - for (unsigned i = 0; !found && i < c.k(); ++i) { - found = c[i] == l; - } - SASSERT(found);); - - if (c.lit() != null_literal) r.push_back(c.lit()); - SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); - for (unsigned i = c.k(); i < c.size(); ++i) { - SASSERT(value(c[i]) == l_false); - r.push_back(~c[i]); - } + get_card_antecedents(l, index2card(idx), r); } else if (is_xor_index(idx)) { - xor& x = index2xor(idx); - if (x.lit() != null_literal) r.push_back(x.lit()); - TRACE("sat", display(tout << l << " ", x, true);); - SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); - SASSERT(x[0].var() == l.var() || x[1].var() == l.var()); - if (x[0].var() == l.var()) { - SASSERT(value(x[1]) != l_undef); - r.push_back(value(x[1]) == l_true ? x[1] : ~x[1]); - } - else { - SASSERT(value(x[0]) != l_undef); - r.push_back(value(x[0]) == l_true ? x[0] : ~x[0]); - } - for (unsigned i = 2; i < x.size(); ++i) { - SASSERT(value(x[i]) != l_undef); - r.push_back(value(x[i]) == l_true ? x[i] : ~x[i]); - } + get_xor_antecedents(l, index2xor(idx), r); } else if (is_pb_index(idx)) { - pb const& p = index2pb(idx); - get_pb_antecedents(l, p, r); + get_pb_antecedents(l, index2pb(idx), r); } else { UNREACHABLE(); @@ -1635,7 +1644,7 @@ namespace sat { out << ">= " << ineq.m_k << "\n"; } - void card_extension::display(std::ostream& out, xor& x, bool values) const { + void card_extension::display(std::ostream& out, xor const& x, bool values) const { out << "xor " << x.lit(); if (x.lit() != null_literal && values) { out << "@(" << value(x.lit()); @@ -1664,7 +1673,7 @@ namespace sat { out << "\n"; } - void card_extension::display(std::ostream& out, card& c, bool values) const { + void card_extension::display(std::ostream& out, card const& c, bool values) const { out << c.lit() << "[" << c.size() << "]"; if (c.lit() != null_literal && values) { out << "@(" << value(c.lit()); @@ -1728,10 +1737,7 @@ namespace sat { pb& p = index2pb(idx); out << "pb " << p.lit() << ": "; for (unsigned i = 0; i < p.size(); ++i) { - if (p[i].first != 1) { - out << p[i].first << " "; - } - out << p[i].second << " "; + out << p[i].first << "*" << p[i].second << " "; } out << ">= " << p.k(); } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 0e229a056..f7e54b843 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -74,7 +74,7 @@ namespace sat { unsigned m_max_sum; wliteral m_wlits[0]; public: - static size_t get_obj_size(unsigned num_lits) { return sizeof(card) + num_lits * sizeof(wliteral); } + static size_t get_obj_size(unsigned num_lits) { return sizeof(pb) + num_lits * sizeof(wliteral); } pb(unsigned index, literal lit, svector const& wlits, unsigned k); unsigned index() const { return m_index; } literal lit() const { return m_lit; } @@ -205,6 +205,8 @@ namespace sat { void reset_coeffs(); void reset_marked_literals(); void unwatch_literal(literal w, card* c); + void get_card_antecedents(literal l, card const& c, literal_vector & r); + // xor specific functionality void copy_xor(card_extension& result); @@ -218,13 +220,14 @@ namespace sat { lbool add_assign(xor& x, literal alit); void asserted_xor(literal l, ptr_vector* xors, xor* x); void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); + void get_xor_antecedents(literal l, xor const& x, literal_vector & r); - bool is_card_index(unsigned idx) const { return 0x00 == (idx & 0x11); } - bool is_xor_index(unsigned idx) const { return 0x01 == (idx & 0x11); } - bool is_pb_index(unsigned idx) const { return 0x11 == (idx & 0x11); } + bool is_card_index(unsigned idx) const { return 0x0 == (idx & 0x3); } + bool is_xor_index(unsigned idx) const { return 0x1 == (idx & 0x3); } + bool is_pb_index(unsigned idx) const { return 0x3 == (idx & 0x3); } card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 2]; } - xor& index2xor(unsigned idx) const { SASSERT(!is_card_index(idx)); return *m_xors[idx >> 2]; } + xor& index2xor(unsigned idx) const { SASSERT(is_xor_index(idx)); return *m_xors[idx >> 2]; } pb& index2pb(unsigned idx) const { SASSERT(is_pb_index(idx)); return *m_pbs[idx >> 2]; } @@ -285,9 +288,9 @@ namespace sat { bool validate_resolvent(); void display(std::ostream& out, ineq& p) const; - void display(std::ostream& out, card& c, bool values) const; - void display(std::ostream& out, pb& p, bool values) const; - void display(std::ostream& out, xor& c, bool values) const; + void display(std::ostream& out, card const& c, bool values) const; + void display(std::ostream& out, pb const& p, bool values) const; + void display(std::ostream& out, xor const& c, bool values) const; void display_watch(std::ostream& out, bool_var v) const; void display_watch(std::ostream& out, bool_var v, bool sign) const; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 45ce213b0..9d81ce886 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -38,6 +38,7 @@ namespace sat { m_num_threads = 1; m_local_search = 0; m_lookahead_search = false; + m_lookahead_simplify = false; m_ccc = false; updt_params(p); } @@ -83,7 +84,8 @@ namespace sat { m_max_conflicts = p.max_conflicts(); m_num_threads = p.threads(); m_local_search = p.local_search(); - m_local_search_threads = p.local_search_threads(); + m_local_search_threads = p.local_search_threads(); + m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_search = p.lookahead_search(); m_ccc = p.ccc(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 2e3d4ec86..a34384e87 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -61,6 +61,7 @@ namespace sat { unsigned m_local_search_threads; bool m_local_search; bool m_lookahead_search; + bool m_lookahead_simplify; bool m_ccc; unsigned m_simplify_mult1; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 72e64ae1d..7f01197f2 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -251,19 +251,16 @@ namespace sat { void del_binary(unsigned idx) { // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n");); literal_vector & lits = m_binary[idx]; - if (lits.empty()) IF_VERBOSE(0, verbose_stream() << "empty literals\n";); + SASSERT(!lits.empty()); literal l = lits.back(); - lits.pop_back(); - if (m_binary[(~l).index()].back() != ~to_literal(idx)) { - IF_VERBOSE(0, verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); - } - if (m_binary[(~l).index()].empty()) - IF_VERBOSE(0, verbose_stream() << "empty binary\n";); + lits.pop_back(); + SASSERT(!m_binary[(~l).index()].empty()); + IF_VERBOSE(0, if (m_binary[(~l).index()].back() != ~to_literal(idx)) verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); + SASSERT(m_binary[(~l).index()].back() == ~to_literal(idx)); m_binary[(~l).index()].pop_back(); ++m_stats.m_del_binary; } - void validate_binary(literal l1, literal l2) { if (m_search_mode == lookahead_mode::searching) { m_assumptions.push_back(l1); @@ -1856,6 +1853,9 @@ namespace sat { return search(); } + /** + \brief simplify set of clauses by extracting units from a lookahead at base level. + */ void simplify() { SASSERT(m_prefix == 0); SASSERT(m_watches.empty()); @@ -1875,12 +1875,38 @@ namespace sat { ++num_units; } } - IF_VERBOSE(1, verbose_stream() << "units found: " << num_units << "\n";); + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << ")\n";); m_s.m_simplifier.subsume(); m_lookahead.reset(); } + // + // there can be two sets of equivalence classes. + // example: + // a -> !b + // b -> !a + // c -> !a + // we pick as root the Boolean variable with the largest value. + // + literal get_root(bool_var v) { + literal lit(v, false); + literal r1 = get_parent(lit); + literal r2 = get_parent(literal(r1.var(), false)); + CTRACE("sat", r1 != get_parent(literal(r2.var(), false)), + tout << r1 << " " << r2 << "\n";); + SASSERT(r1.var() == get_parent(literal(r2.var(), false)).var()); + if (r1.var() >= r2.var()) { + return r1; + } + else { + return r1.sign() ? ~r2 : r2; + } + } + + /** + \brief extract equivalence classes of variables and simplify clauses using these. + */ void scc() { SASSERT(m_prefix == 0); SASSERT(m_watches.empty()); @@ -1901,14 +1927,13 @@ namespace sat { } for (unsigned i = 0; i < m_candidates.size(); ++i) { bool_var v = m_candidates[i].m_var; - literal lit = literal(v, false); - literal p = get_parent(lit); + literal p = get_root(v); if (p != null_literal && p.var() != v && !m_s.is_external(v) && !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { to_elim.push_back(v); roots[v] = p; } } - IF_VERBOSE(1, verbose_stream() << "eliminate " << to_elim.size() << " variables\n";); + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); elim_eqs elim(m_s); elim(roots, to_elim); } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 226c79642..2c09ecdc1 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -32,5 +32,6 @@ def_module_params('sat', ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('lookahead_search', BOOL, False, 'use lookahead solver'), + ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('ccc', BOOL, False, 'use Concurrent Cube and Conquer solver') )) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 2687c59e5..80c82c92d 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -207,10 +207,6 @@ namespace sat { } while (!m_sub_todo.empty()); - if (!learned) { - // perform lookahead simplification - lookahead(s).simplify(); - } bool vars_eliminated = m_num_elim_vars > m_old_num_elim_vars; @@ -228,6 +224,13 @@ namespace sat { } } + if (!learned && s.m_config.m_lookahead_simplify) { + // perform lookahead simplification + lookahead lh(s); + lh.simplify(); + lh.collect_statistics(s.m_aux_stats); + } + CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); finalize(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3df718527..a292ff202 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1341,7 +1341,11 @@ namespace sat { CASSERT("sat_simplify_bug", check_invariant()); } - lookahead(*this).scc(); + if (m_config.m_lookahead_simplify) { + lookahead lh(*this); + lh.scc(); + lh.collect_statistics(m_aux_stats); + } sort_watch_lits(); CASSERT("sat_simplify_bug", check_invariant()); From f253b20820473735f950ea29e2730b9c38113ec1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 May 2017 09:34:11 -0700 Subject: [PATCH 0116/1283] local changes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 9 +++++++-- src/sat/sat_lookahead.h | 14 ++++++++++++-- src/sat/sat_simplifier.cpp | 11 ++++++----- src/sat/sat_solver.cpp | 1 + 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 0001aaf5c..b9b7dbd85 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -78,7 +78,7 @@ namespace sat { clause_vector::iterator end = cs.end(); for (; it != end; ++it) { clause & c = *(*it); - TRACE("elim_eqs", tout << "processing: " << c << "\n";); + TRACE("sats", tout << "processing: " << c << "\n";); unsigned sz = c.size(); unsigned i; for (i = 0; i < sz; i++) { @@ -101,7 +101,12 @@ namespace sat { c[i] = norm(roots, c[i]); } std::sort(c.begin(), c.end()); - TRACE("elim_eqs", tout << "after normalization/sorting: " << c << "\n";); + TRACE("sats", tout << "after normalization/sorting: " << c << "\n"; tout.flush();); + DEBUG_CODE({ + for (unsigned i = 0; i < sz; i++) { + CTRACE("sats", c[i] != norm(roots, c[i]), tout << c[i] << " " << norm(roots, c[i]) << "\n"; tout.flush();); + SASSERT(c[i] == norm(roots, c[i])); + } }); // remove duplicates, and check if it is a tautology literal l_prev = null_literal; unsigned j = 0; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 72e64ae1d..f1d0833c4 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -723,9 +723,10 @@ namespace sat { void set_min(literal v, literal u) { m_dfs[v.index()].m_min = u; } void set_rank(literal v, unsigned r) { m_dfs[v.index()].m_rank = r; } void set_height(literal v, unsigned h) { m_dfs[v.index()].m_height = h; } - void set_parent(literal v, literal p) { TRACE("sat", tout << v << " <- " << p << "\n";); m_dfs[v.index()].m_parent = p; } + void set_parent(literal v, literal p) { TRACE("scc", tout << v << " <- " << p << "\n";); m_dfs[v.index()].m_parent = p; } void set_vcomp(literal v, literal u) { m_dfs[v.index()].m_vcomp = u; } void get_scc(literal v) { + TRACE("scc", tout << v << "\n";); set_parent(v, null_literal); activate_scc(v); do { @@ -1065,7 +1066,9 @@ namespace sat { for (; it != end; ++it) { if (!it->is_binary_non_learned_clause()) continue; - literal l2 = it->get_literal(); + literal l2 = it->get_literal(); + SASSERT(!m_s.was_eliminated(l.var())); + SASSERT(!m_s.was_eliminated(l2.var())); if (l.index() < l2.index()) add_binary(l, l2); } @@ -1100,6 +1103,7 @@ namespace sat { attach_clause(*c1); for (unsigned i = 0; i < c.size(); ++i) { m_full_watches[(~c[i]).index()].push_back(c1); + SASSERT(!m_s.was_eliminated(c[i].var())); } if (m_s.m_config.m_drat) m_drat.add(c, false); } @@ -1906,6 +1910,12 @@ namespace sat { if (p != null_literal && p.var() != v && !m_s.is_external(v) && !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { to_elim.push_back(v); roots[v] = p; + SASSERT(get_parent(p) == p); + set_parent(~p, ~p); + SASSERT(get_parent(~p) == ~p); + if (v == 5904 || v == 5903) { + std::cout << lit << " " << p << "\n"; + } } } IF_VERBOSE(1, verbose_stream() << "eliminate " << to_elim.size() << " variables\n";); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 2687c59e5..efb9f5498 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -207,11 +207,6 @@ namespace sat { } while (!m_sub_todo.empty()); - if (!learned) { - // perform lookahead simplification - lookahead(s).simplify(); - } - bool vars_eliminated = m_num_elim_vars > m_old_num_elim_vars; if (m_need_cleanup) { @@ -230,6 +225,12 @@ namespace sat { CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); + + if (!learned) { + // perform lookahead simplification + lookahead(s).simplify(); + } + finalize(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3df718527..d42f4d41a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -97,6 +97,7 @@ namespace sat { } } } + // // register the extension before performing assignments. // the assignments may call back into the extension. From 4eec8cbadd494472dce45a778781d04f698fefcb Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 15 May 2017 15:32:31 -0700 Subject: [PATCH 0117/1283] introduce int_solver.h Signed-off-by: Lev Nachmanson --- contrib/cmake/src/util/lp/CMakeLists.txt | 1 + src/util/lp/lar_solver.h | 84 +----------------------- 2 files changed, 3 insertions(+), 82 deletions(-) diff --git a/contrib/cmake/src/util/lp/CMakeLists.txt b/contrib/cmake/src/util/lp/CMakeLists.txt index 57ebecc8d..30c4f9d55 100644 --- a/contrib/cmake/src/util/lp/CMakeLists.txt +++ b/contrib/cmake/src/util/lp/CMakeLists.txt @@ -8,6 +8,7 @@ z3_add_component(lp dense_matrix_instances.cpp eta_matrix_instances.cpp indexed_vector_instances.cpp + lar_solver.cpp lar_core_solver_instances.cpp lp_core_solver_base_instances.cpp lp_dual_core_solver_instances.cpp diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index e2b1eb682..5f7ce96a4 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -30,6 +30,8 @@ #include "util/lp/iterator_on_row.h" #include "util/lp/quick_xplain.h" #include "util/lp/conversion_helper.h" +#include "util/lp/int_solver.h" + namespace lean { class lar_solver : public column_namer { @@ -256,88 +258,6 @@ public: } } - /* - void process_new_implied_evidence_for_low_bound( - implied_bound_explanation& implied_evidence, // not pushed yet - vector & bound_evidences, - std::unordered_map & improved_low_bounds) { - - unsigned existing_index; - if (try_get_val(improved_low_bounds, implied_evidence.m_j, existing_index)) { - // we are improving the existent bound - bound_evidences[existing_index] = fill_bound_evidence(implied_evidence); - } else { - improved_low_bounds[implied_evidence.m_j] = bound_evidences.size(); - bound_evidences.push_back(fill_bound_evidence(implied_evidence)); - } - } - - void fill_bound_evidence_on_term(implied_bound & ie, implied_bound& be) { - lean_assert(false); - } - void fill_implied_bound_on_row(implied_bound & ie, implied_bound& be) { - iterator_on_row it(A_r().m_rows[ie.m_row_or_term_index]); - mpq a; unsigned j; - bool toggle = ie.m_coeff_before_j_is_pos; - if (!ie.m_is_low_bound) - toggle = !toggle; - while (it.next(a, j)) { - if (j == ie.m_j) continue; - const ul_pair & ul = m_vars_to_ul_pairs[j]; - - if (is_neg(a)) { // so the monoid has a positive coeff on the right side - constraint_index witness = toggle ? ul.m_low_bound_witness : ul.m_upper_bound_witness; - lean_assert(is_valid(witness)); - be.m_explanation.emplace_back(a, witness); - } - } - } - */ - /* - implied_bound fill_implied_bound_for_low_bound(implied_bound& ie) { - implied_bound be(ie.m_j, ie.m_bound.y.is_zero() ? GE : GT, ie.m_bound.x); - if (is_term(ie.m_row_or_term_index)) { - fill_implied_bound_for_low_bound_on_term(ie, be); - } - else { - fill_implied_bound_for_low_bound_on_row(ie, be); - } - return be; - } - - implied_bound fill_implied_bound_for_upper_bound(implied_bound& implied_evidence) { - lean_assert(false); - - be.m_j = implied_evidence.m_j; - be.m_bound = implied_evidence.m_bound.x; - be.m_kind = implied_evidence.m_bound.y.is_zero() ? LE : LT; - for (auto t : implied_evidence.m_vector_of_bound_signatures) { - const ul_pair & ul = m_vars_to_ul_pairs[t.m_column_index]; - constraint_index witness = t.m_low_bound ? ul.m_low_bound_witness : ul.m_upper_bound_witness; - lean_assert(is_valid(witness)); - be.m_explanation.emplace_back(t.m_coeff, witness); - } - - } - */ - /* - void process_new_implied_evidence_for_upper_bound( - implied_bound& implied_evidence, - vector & implied_bounds, - std::unordered_map & improved_upper_bounds) { - unsigned existing_index; - if (try_get_val(improved_upper_bounds, implied_evidence.m_j, existing_index)) { - implied_bound & be = implied_bounds[existing_index]; - be.m_explanation.clear(); - // we are improving the existent bound improve the existing bound - be = fill_implied_bound_for_upper_bound(implied_evidence); - } else { - improved_upper_bounds[implied_evidence.m_j] = implied_bounds.size(); - implied_bounds.push_back(fill_implied_bound_for_upper_bound(implied_evidence)); - } - } - */ - // implied_bound * get_existing_ linear_combination_iterator * create_new_iter_from_term(unsigned term_index) const { lean_assert(false); // not implemented From 06e1151ca004b7085efb45d1a53b55f8dfa4f340 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 16 May 2017 12:01:16 -0700 Subject: [PATCH 0118/1283] add int_solver class Signed-off-by: Lev Nachmanson --- contrib/cmake/src/util/lp/CMakeLists.txt | 2 +- ...{init_lar_solver.h => init_lar_solver.cpp} | 54 +- src/util/lp/int_solver.cpp | 6 + src/util/lp/int_solver.h | 44 + src/util/lp/lar_solver.cpp | 1396 ++++++++++++++++ src/util/lp/lar_solver.h | 1450 +++-------------- src/util/lp/lar_solver_instances.cpp | 17 + 7 files changed, 1677 insertions(+), 1292 deletions(-) rename src/util/lp/{init_lar_solver.h => init_lar_solver.cpp} (90%) create mode 100644 src/util/lp/int_solver.cpp create mode 100644 src/util/lp/int_solver.h create mode 100644 src/util/lp/lar_solver.cpp create mode 100644 src/util/lp/lar_solver_instances.cpp diff --git a/contrib/cmake/src/util/lp/CMakeLists.txt b/contrib/cmake/src/util/lp/CMakeLists.txt index 30c4f9d55..ec9a2e137 100644 --- a/contrib/cmake/src/util/lp/CMakeLists.txt +++ b/contrib/cmake/src/util/lp/CMakeLists.txt @@ -8,7 +8,7 @@ z3_add_component(lp dense_matrix_instances.cpp eta_matrix_instances.cpp indexed_vector_instances.cpp - lar_solver.cpp + lar_solver_instances.cpp lar_core_solver_instances.cpp lp_core_solver_base_instances.cpp lp_dual_core_solver_instances.cpp diff --git a/src/util/lp/init_lar_solver.h b/src/util/lp/init_lar_solver.cpp similarity index 90% rename from src/util/lp/init_lar_solver.h rename to src/util/lp/init_lar_solver.cpp index 3fc29f25b..97ebbdd5a 100644 --- a/src/util/lp/init_lar_solver.h +++ b/src/util/lp/init_lar_solver.cpp @@ -2,14 +2,15 @@ Copyright (c) 2017 Microsoft Corporation Author: Lev Nachmanson */ +#include "util/lp/lar_solver.h" -// here we are inside lean::lar_solver class +namespace lean { -bool strategy_is_undecided() const { +bool lar_solver::strategy_is_undecided() const { return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; } -var_index add_var(unsigned ext_j) { +var_index lar_solver::add_var(unsigned ext_j) { var_index i; lean_assert (ext_j < m_terms_start_index); @@ -27,7 +28,7 @@ var_index add_var(unsigned ext_j) { return i; } -void register_new_ext_var_index(unsigned ext_v) { +void lar_solver::register_new_ext_var_index(unsigned ext_v) { lean_assert(!contains(m_ext_vars_to_columns, ext_v)); unsigned j = static_cast(m_ext_vars_to_columns.size()); m_ext_vars_to_columns[ext_v] = j; @@ -35,7 +36,7 @@ void register_new_ext_var_index(unsigned ext_v) { m_columns_to_ext_vars_or_term_indices.push_back(ext_v); } -void add_non_basic_var_to_core_fields(unsigned ext_j) { +void lar_solver::add_non_basic_var_to_core_fields(unsigned ext_j) { register_new_ext_var_index(ext_j); m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); m_columns_with_changed_bound.increase_size_by_one(); @@ -44,7 +45,7 @@ void add_non_basic_var_to_core_fields(unsigned ext_j) { add_new_var_to_core_fields_for_doubles(false); } -void add_new_var_to_core_fields_for_doubles(bool register_in_basis) { +void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) { unsigned j = A_d().column_count(); A_d().add_column(); lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); @@ -63,7 +64,7 @@ void add_new_var_to_core_fields_for_doubles(bool register_in_basis) { } } -void add_new_var_to_core_fields_for_mpq(bool register_in_basis) { +void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) { unsigned j = A_r().column_count(); A_r().add_column(); lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j); @@ -88,7 +89,7 @@ void add_new_var_to_core_fields_for_mpq(bool register_in_basis) { } -var_index add_term_undecided(const vector> & coeffs, +var_index lar_solver::add_term_undecided(const vector> & coeffs, const mpq &m_v) { m_terms.push_back(new lar_term(coeffs, m_v)); m_orig_terms.push_back(new lar_term(coeffs, m_v)); @@ -96,7 +97,7 @@ var_index add_term_undecided(const vector> & coeffs, } // terms -var_index add_term(const vector> & coeffs, +var_index lar_solver::add_term(const vector> & coeffs, const mpq &m_v) { if (strategy_is_undecided()) return add_term_undecided(coeffs, m_v); @@ -114,13 +115,13 @@ var_index add_term(const vector> & coeffs, return ret; } -void add_row_for_term(const lar_term * term, unsigned term_ext_index) { +void lar_solver::add_row_for_term(const lar_term * term, unsigned term_ext_index) { lean_assert(sizes_are_correct()); add_row_from_term_no_constraint(term, term_ext_index); lean_assert(sizes_are_correct()); } -void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { +void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { register_new_ext_var_index(term_ext_index); // j will be a new variable unsigned j = A_r().column_count(); @@ -140,7 +141,7 @@ void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_in fill_last_row_of_A_d(A_d(), term); } -void add_basic_var_to_core_fields() { +void lar_solver::add_basic_var_to_core_fields() { bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); lean_assert(!use_lu || A_r().column_count() == A_d().column_count()); m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); @@ -151,7 +152,7 @@ void add_basic_var_to_core_fields() { add_new_var_to_core_fields_for_doubles(true); } -constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { +constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { constraint_index ci = m_constraints.size(); if (!is_term(j)) { // j is a var auto vc = new lar_var_constraint(j, kind, right_side); @@ -164,7 +165,7 @@ constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & r return ci; } -void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { +void lar_solver::update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { switch(m_mpq_lar_core_solver.m_column_types[j]) { case column_type::free_column: update_free_column_type_and_bound(j, kind, right_side, constr_index); @@ -186,7 +187,7 @@ void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq } } -void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { +void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { lean_assert(is_term(j)); unsigned adjusted_term_index = adjust_term_index(j); unsigned term_j; @@ -201,7 +202,7 @@ void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, co } -void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, +void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, lconstraint_kind kind, const mpq & right_side) { add_row_from_term_no_constraint(term, term_j); @@ -211,7 +212,7 @@ void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const l lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); } -void decide_on_strategy_and_adjust_initial_state() { +void lar_solver::decide_on_strategy_and_adjust_initial_state() { lean_assert(strategy_is_undecided()); if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { m_settings.simplex_strategy() = simplex_strategy_enum::lu; @@ -221,7 +222,7 @@ void decide_on_strategy_and_adjust_initial_state() { adjust_initial_state(); } -void adjust_initial_state() { +void lar_solver::adjust_initial_state() { switch (m_settings.simplex_strategy()) { case simplex_strategy_enum::lu: adjust_initial_state_for_lu(); @@ -237,7 +238,7 @@ void adjust_initial_state() { } } -void adjust_initial_state_for_lu() { +void lar_solver::adjust_initial_state_for_lu() { copy_from_mpq_matrix(A_d()); unsigned n = A_d().column_count(); m_mpq_lar_core_solver.m_d_x.resize(n); @@ -265,7 +266,7 @@ void adjust_initial_state_for_lu() { }*/ } -void adjust_initial_state_for_tableau_rows() { +void lar_solver::adjust_initial_state_for_tableau_rows() { for (unsigned j = 0; j < m_terms.size(); j++) { if (contains(m_ext_vars_to_columns, j + m_terms_start_index)) continue; @@ -274,7 +275,7 @@ void adjust_initial_state_for_tableau_rows() { } // this fills the last row of A_d and sets the basis column: -1 in the last column of the row -void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { +void lar_solver::fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { lean_assert(A.row_count() > 0); lean_assert(A.column_count() > 0); unsigned last_row = A.row_count() - 1; @@ -290,7 +291,7 @@ void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) A.set(last_row, basis_j, - 1 ); } -void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { +void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { mpq y_of_bound(0); switch (kind) { case LT: @@ -330,7 +331,7 @@ void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const m_columns_with_changed_bound.insert(j); } -void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { +void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); mpq y_of_bound(0); switch (kind) { @@ -387,7 +388,7 @@ void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind } } -void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { +void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); mpq y_of_bound(0); switch (kind) { @@ -457,7 +458,7 @@ void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, cons } } -void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { +void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); mpq y_of_bound(0); switch (kind) { @@ -513,7 +514,7 @@ void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, } } -void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { +void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); auto v = numeric_pair(right_side, mpq(0)); @@ -574,3 +575,4 @@ void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, cons } } +} diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp new file mode 100644 index 000000000..e7ea24a6f --- /dev/null +++ b/src/util/lp/int_solver.cpp @@ -0,0 +1,6 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#include "util/lp/int_solver.h" diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h new file mode 100644 index 000000000..b74a25855 --- /dev/null +++ b/src/util/lp/int_solver.h @@ -0,0 +1,44 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ +#pragma once +#include "util/lp/lp_settings.h" +class lemma; // forward definition +namespace lean { +class lar_solver; +template +struct lp_constraint; + +class int_solver { +public: + lar_solver *m_solver; + + int_solver(lar_solver* lp); + bool check();// main function to check that solution provided by lar_solver is valid for integral values or can be adjusted. +private: + + // how to tighten bounds for integer variables. + + + // gcd test + // 5*x + 3*y + 6*z = 5 + // suppose x is fixed at 2. + // so we have 10 + 3(y + 2z) = 5 + // 5 = -3(y + 2z) + // this is unsolvable because 5/3 is not an integer. + // so we create a lemma that rules out this condition. + // + bool gcd_test(lemma& lemma); // returns false in case of failure. Creates a theory lemma in case of failure. + + // create goromy cuts + // either creates a conflict or a bound. + + // branch and bound: + // decide what to branch and bound on + // creates a fresh inequality. + + bool branch(const lp_constraint & new_inequality); + +}; +} diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp new file mode 100644 index 000000000..ba0f74201 --- /dev/null +++ b/src/util/lp/lar_solver.cpp @@ -0,0 +1,1396 @@ +#include "util/lp/lar_solver.h" +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +namespace lean { + +unsigned lar_solver::constraint_count() const { + return m_constraints.size(); +} +const lar_base_constraint& lar_solver::get_constraint(unsigned ci) const { + return *(m_constraints[ci]); +} + + ////////////////// methods //////////////////////////////// + static_matrix> & lar_solver::A_r() { return m_mpq_lar_core_solver.m_r_A;} + static_matrix> const & lar_solver::A_r() const { return m_mpq_lar_core_solver.m_r_A;} + static_matrix & lar_solver::A_d() { return m_mpq_lar_core_solver.m_d_A;} + static_matrix const & lar_solver::A_d() const { return m_mpq_lar_core_solver.m_d_A;} + + lp_settings & lar_solver::settings() { return m_settings;} + + lp_settings const & lar_solver::settings() const { return m_settings;} + + void clear() {lean_assert(false); // not implemented + } + + + lar_solver::lar_solver() : m_status(OPTIMAL), + m_infeasible_column_index(-1), + m_terms_start_index(1000000), + m_column_type_function ([this] (unsigned j) {return m_mpq_lar_core_solver.m_column_types()[j];}), + m_mpq_lar_core_solver(m_settings, *this) + {} + + void lar_solver::set_propagate_bounds_on_pivoted_rows_mode(bool v) { + m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; + } + + lar_solver::~lar_solver(){ + for (auto c : m_constraints) + delete c; + for (auto t : m_terms) + delete t; + for (auto t : m_orig_terms) + delete t; + } + + numeric_pair const& lar_solver::get_value(var_index vi) const { return m_mpq_lar_core_solver.m_r_x[vi]; } + + bool lar_solver::is_term(var_index j) const { + return j >= m_terms_start_index && j - m_terms_start_index < m_terms.size(); + } + + unsigned lar_solver::adjust_term_index(unsigned j) const { + lean_assert(is_term(j)); + return j - m_terms_start_index; + } + + + bool lar_solver::use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } + + bool lar_solver::sizes_are_correct() const { + lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); + return true; + } + + + void lar_solver::print_implied_bound(const implied_bound& be, std::ostream & out) const { + out << "implied bound\n"; + unsigned v = be.m_j; + if (is_term(v)) { + out << "it is a term number " << be.m_j << std::endl; + print_term(*m_orig_terms[be.m_j - m_terms_start_index], out); + } + else { + out << get_column_name(v); + } + out << " " << lconstraint_kind_string(be.kind()) << " " << be.m_bound << std::endl; + // for (auto & p : be.m_explanation) { + // out << p.first << " : "; + // print_constraint(p.second, out); + // } + + // m_mpq_lar_core_solver.m_r_solver.print_column_info(be.m_j< m_terms_start_index? be.m_j : adjust_term_index(be.m_j), out); + out << "end of implied bound" << std::endl; + } + + bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { + std::unordered_map coeff_map; + auto rs_of_evidence = zero_of_type(); + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : explanation) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + const auto & constr = *m_constraints[con_ind]; + lconstraint_kind kind = coeff.is_pos() ? constr.m_kind : flip_kind(constr.m_kind); + register_in_map(coeff_map, constr, coeff); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + rs_of_evidence += coeff*constr.m_right_side; + } + lean_assert(n_of_G == 0 || n_of_L == 0); + lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); + if (strict) + kind = static_cast((static_cast(kind) / 2)); + + if (!is_term(be.m_j)) { + if (coeff_map.size() != 1) + return false; + auto it = coeff_map.find(be.m_j); + if (it == coeff_map.end()) return false; + mpq ratio = it->second; + if (ratio < zero_of_type()) { + kind = static_cast(-kind); + } + rs_of_evidence /= ratio; + } else { + const lar_term * t = m_orig_terms[adjust_term_index(be.m_j)]; + const auto first_coeff = *t->m_coeffs.begin(); + unsigned j = first_coeff.first; + auto it = coeff_map.find(j); + if (it == coeff_map.end()) + return false; + mpq ratio = it->second / first_coeff.second; + for (auto & p : t->m_coeffs) { + it = coeff_map.find(p.first); + if (it == coeff_map.end()) + return false; + if (p.second * ratio != it->second) + return false; + } + if (ratio < zero_of_type()) { + kind = static_cast(-kind); + } + rs_of_evidence /= ratio; + rs_of_evidence += t->m_v * ratio; + } + + return kind == be.kind() && rs_of_evidence == be.m_bound; + } + + + void lar_solver::analyze_new_bounds_on_row( + unsigned row_index, + bound_propagator & bp) { + lean_assert(!use_tableau()); + iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); + + bound_analyzer_on_row ra_pos(it, + zero_of_type>(), + row_index, + bp + ); + ra_pos.analyze(); + } + + 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) + return; + iterator_on_row it(A_r().m_rows[row_index]); + lean_assert(use_tableau()); + bound_analyzer_on_row::analyze_row(it, + zero_of_type>(), + row_index, + bp + ); + } + + + void lar_solver::substitute_basis_var_in_terms_for_row(unsigned i) { + // todo : create a map from term basic vars to the rows where they are used + unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; + for (unsigned k = 0; k < m_terms.size(); k++) { + if (term_is_used_as_row(k)) + continue; + if (!m_terms[k]->contains(basis_j)) + continue; + m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); + } + } + + void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { + if(use_tableau()) { + analyze_new_bounds_on_row_tableau(i, bp); + } else { + m_mpq_lar_core_solver.calculate_pivot_row(i); + substitute_basis_var_in_terms_for_row(i); + analyze_new_bounds_on_row(i, bp); + } + } + + + linear_combination_iterator * lar_solver::create_new_iter_from_term(unsigned term_index) const { + lean_assert(false); // not implemented + return nullptr; + // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); + } + + unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const { + unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; + return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; + } + + void lar_solver::propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { + lean_assert(false); // not implemented + } + + + void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp) { + unsigned i = ib.m_row_or_term_index; + int bound_sign = ib.m_is_low_bound? 1: -1; + int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; + unsigned m_j = ib.m_j; + if (is_term(m_j)) { + m_j = m_ext_vars_to_columns[m_j]; + } + for (auto const& r : A_r().m_rows[i]) { + unsigned j = r.m_j; + mpq const& a = r.get_val(); + if (j == m_j) continue; + if (is_term(j)) { + j = m_ext_vars_to_columns[j]; + } + int a_sign = is_pos(a)? 1: -1; + int sign = j_sign * a_sign; + const ul_pair & ul = m_vars_to_ul_pairs[j]; + auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); + lean_assert(is_valid(witness)); + bp.consume(a, witness); + } + // lean_assert(implied_bound_is_correctly_explained(ib, explanation)); + } + + + bool lar_solver::term_is_used_as_row(unsigned term) const { + lean_assert(is_term(term)); + return contains(m_ext_vars_to_columns, term); + } + + void lar_solver::propagate_bounds_on_terms(bound_propagator & bp) { + for (unsigned i = 0; i < m_terms.size(); i++) { + if (term_is_used_as_row(i + m_terms_start_index)) + continue; // this term is used a left side of a constraint, + // it was processed as a touched row if needed + propagate_bounds_on_a_term(*m_terms[i], bp, i); + } + } + + + // goes over touched rows and tries to induce bounds + void lar_solver::propagate_bounds_for_touched_rows(bound_propagator & bp) { + if (!use_tableau()) + return; // ! todo : enable bound propagaion here. The current bug is that after the pop + // the changed terms become incorrect! + + for (unsigned i : m_rows_with_changed_bounds.m_index) { + calculate_implied_bounds_for_row(i, bp); + } + m_rows_with_changed_bounds.clear(); + if (!use_tableau()) { + propagate_bounds_on_terms(bp); + } + } + + lp_status lar_solver::get_status() const { return m_status;} + + void lar_solver::set_status(lp_status s) {m_status = s;} + + lp_status lar_solver::find_feasible_solution() { + if (strategy_is_undecided()) + decide_on_strategy_and_adjust_initial_state(); + + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; + return solve(); + } + + lp_status lar_solver::solve() { + if (m_status == INFEASIBLE) { + return m_status; + } + solve_with_core_solver(); + if (m_status != INFEASIBLE) { + if (m_settings.bound_propagation()) + detect_rows_with_changed_bounds(); + } + + m_columns_with_changed_bound.clear(); + return m_status; + } + + void lar_solver::fill_explanation_from_infeasible_column(vector> & evidence) const{ + + // this is the case when the lower bound is in conflict with the upper one + const ul_pair & ul = m_vars_to_ul_pairs[m_infeasible_column_index]; + evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); + evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); + } + + + unsigned lar_solver::get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } + // see http://research.microsoft.com/projects/z3/smt07.pdf + // This method searches for a feasible solution with as many different values of variables, reverenced in vars, as it can find + // Attention, after a call to this method the non-basic variables don't necesserarly stick to their bounds anymore + vector lar_solver::get_list_of_all_var_indices() const { + vector ret; + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) + ret.push_back(j); + return ret; + } + void lar_solver::push() { + m_simplex_strategy = m_settings.simplex_strategy(); + m_simplex_strategy.push(); + m_status.push(); + m_vars_to_ul_pairs.push(); + m_infeasible_column_index.push(); + m_mpq_lar_core_solver.push(); + m_term_count = m_terms.size(); + m_term_count.push(); + m_constraint_count = m_constraints.size(); + m_constraint_count.push(); + } + + void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { + vector to_remove; + for (unsigned j: set.m_index) + if (j >= n) + to_remove.push_back(j); + for (unsigned j : to_remove) + set.erase(j); + } + + void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { + clean_large_elements_after_pop(n, set); + set.resize(n); + } + + + void lar_solver::pop(unsigned k) { + int n_was = static_cast(m_ext_vars_to_columns.size()); + m_status.pop(k); + m_infeasible_column_index.pop(k); + unsigned n = m_vars_to_ul_pairs.peek_size(k); + for (unsigned j = n_was; j-- > n;) + m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); + m_columns_to_ext_vars_or_term_indices.resize(n); + if (m_settings.use_tableau()) { + pop_tableau(); + } + m_vars_to_ul_pairs.pop(k); + + m_mpq_lar_core_solver.pop(k); + clean_large_elements_after_pop(n, m_columns_with_changed_bound); + unsigned m = A_r().row_count(); + clean_large_elements_after_pop(m, m_rows_with_changed_bounds); + clean_inf_set_of_r_solver_after_pop(); + lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || + (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + + + lean_assert(ax_is_correct()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); + m_constraint_count.pop(k); + for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) + delete m_constraints[i]; + + m_constraints.resize(m_constraint_count); + m_term_count.pop(k); + for (unsigned i = m_term_count; i < m_terms.size(); i++) { + delete m_terms[i]; + delete m_orig_terms[i]; + } + m_terms.resize(m_term_count); + m_orig_terms.resize(m_term_count); + m_simplex_strategy.pop(k); + m_settings.simplex_strategy() = m_simplex_strategy; + lean_assert(sizes_are_correct()); + lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + } + + vector lar_solver::get_all_constraint_indices() const { + vector ret; + constraint_index i = 0; + while ( i < m_constraints.size()) + ret.push_back(i++); + return ret; + } + + bool lar_solver::maximize_term_on_tableau(const vector> & term, + impq &term_max) { + if (settings().simplex_strategy() == simplex_strategy_enum::undecided) + decide_on_strategy_and_adjust_initial_state(); + + m_mpq_lar_core_solver.solve(); + if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED) + return false; + + term_max = 0; + for (auto & p : term) + term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second]; + + return true; + } + + bool lar_solver::costs_are_zeros_for_r_solver() const { + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { + lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); + } + return true; + } + bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const { + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { + lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); + } + return true; + } + + void lar_solver::set_costs_to_zero(const vector> & term) { + auto & rslv = m_mpq_lar_core_solver.m_r_solver; + auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now + lean_assert(jset.m_index.size()==0); + + for (auto & p : term) { + unsigned j = p.second; + rslv.m_costs[j] = zero_of_type(); + int i = rslv.m_basis_heading[j]; + if (i < 0) + jset.insert(j); + else { + for (auto & rc : A_r().m_rows[i]) + jset.insert(rc.m_j); + } + } + + for (unsigned j : jset.m_index) + rslv.m_d[j] = zero_of_type(); + + jset.clear(); + + lean_assert(reduced_costs_are_zeroes_for_r_solver()); + lean_assert(costs_are_zeros_for_r_solver()); + } + + void lar_solver::prepare_costs_for_r_solver(const vector> & term) { + + auto & rslv = m_mpq_lar_core_solver.m_r_solver; + rslv.m_using_infeas_costs = false; + lean_assert(costs_are_zeros_for_r_solver()); + lean_assert(reduced_costs_are_zeroes_for_r_solver()); + rslv.m_costs.resize(A_r().column_count(), zero_of_type()); + for (auto & p : term) { + unsigned j = p.second; + rslv.m_costs[j] = p.first; + if (rslv.m_basis_heading[j] < 0) + rslv.m_d[j] += p.first; + else + rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); + } + lean_assert(rslv.reduced_costs_are_correct_tableau()); + } + + bool lar_solver::maximize_term_on_corrected_r_solver(const vector> & term, + impq &term_max) { + settings().backup_costs = false; + switch (settings().simplex_strategy()) { + case simplex_strategy_enum::tableau_rows: + prepare_costs_for_r_solver(term); + settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; + { + bool ret = maximize_term_on_tableau(term, term_max); + settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); + return ret; + } + case simplex_strategy_enum::tableau_costs: + prepare_costs_for_r_solver(term); + { + bool ret = maximize_term_on_tableau(term, term_max); + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); + return ret; + } + + case simplex_strategy_enum::lu: + lean_assert(false); // not implemented + return false; + default: + lean_unreachable(); // wrong mode + } + return false; + } + // starting from a given feasible state look for the maximum of the term + // return true if found and false if unbounded + bool lar_solver::maximize_term(const vector> & term, + impq &term_max) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; + return maximize_term_on_corrected_r_solver(term, term_max); + } + + + + const lar_term & lar_solver::get_term(unsigned j) const { + lean_assert(j >= m_terms_start_index); + return *m_terms[j - m_terms_start_index]; + } + + void lar_solver::pop_core_solver_params() { + pop_core_solver_params(1); + } + + void lar_solver::pop_core_solver_params(unsigned k) { + A_r().pop(k); + A_d().pop(k); + } + + + void lar_solver::set_upper_bound_witness(var_index j, constraint_index ci) { + ul_pair ul = m_vars_to_ul_pairs[j]; + ul.upper_bound_witness() = ci; + m_vars_to_ul_pairs[j] = ul; + } + + void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) { + ul_pair ul = m_vars_to_ul_pairs[j]; + ul.low_bound_witness() = ci; + m_vars_to_ul_pairs[j] = ul; + } + + + void lar_solver::substitute_terms(const mpq & mult, + const vector>& left_side_with_terms, + vector> &left_side, mpq & right_side) const { + for (auto & t : left_side_with_terms) { + if (t.second < m_terms_start_index) { + lean_assert(t.second < A_r().column_count()); + left_side.push_back(std::pair(mult * t.first, t.second)); + } else { + const lar_term & term = * m_terms[adjust_term_index(t.second)]; + substitute_terms(mult * t.first, left_side_with_terms, left_side, right_side); + right_side -= mult * term.m_v; + } + } + } + + + void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { + if (A_r().row_count() != m_column_buffer.data_size()) + m_column_buffer.resize(A_r().row_count()); + else + m_column_buffer.clear(); + lean_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); + + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + for (unsigned i : m_column_buffer.m_index) + m_rows_with_changed_bounds.insert(i); + } + + + + 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); + } + + bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } + + bool lar_solver::use_tableau_costs() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; + } + + void lar_solver::detect_rows_of_column_with_bound_change(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column + // just mark the row at touched and exit + m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + return; + } + + if (use_tableau()) + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + else + detect_rows_of_bound_change_column_for_nbasic_column(j); + } + + void lar_solver::adjust_x_of_column(unsigned j) { + lean_assert(false); + } + + 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]; + return is_zero(r); + } + + bool lar_solver::ax_is_correct() const { + for (unsigned i = 0; i < A_r().row_count(); i++) { + if (!row_is_correct(i)) + return false; + } + return true; + } + + bool lar_solver::tableau_with_costs() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; + } + + bool lar_solver::costs_are_used() const { + return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; + } + + void lar_solver::change_basic_x_by_delta_on_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]; + m_mpq_lar_core_solver.m_r_x[bj] -= A_r().get_val(c) * delta; + if (tableau_with_costs()) { + m_basic_columns_with_changed_cost.insert(bj); + } + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); + } + } else { + m_column_buffer.clear(); + m_column_buffer.resize(A_r().row_count()); + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + for (unsigned i : m_column_buffer.m_index) { + unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; + m_mpq_lar_core_solver.m_r_x[bj] -= m_column_buffer[i] * delta; + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); + } + } + } + + void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + if (costs_are_used()) { + bool was_infeas = m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j); + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); + if (was_infeas != m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j)) + m_basic_columns_with_changed_cost.insert(j); + } else { + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); + } + } else { + numeric_pair delta; + if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) + change_basic_x_by_delta_on_column(j, delta); + } + } + + + void lar_solver::detect_rows_with_changed_bounds_for_column(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + return; + } + + if (use_tableau()) + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + else + detect_rows_of_bound_change_column_for_nbasic_column(j); + } + + void lar_solver::detect_rows_with_changed_bounds() { + for (auto j : m_columns_with_changed_bound.m_index) + detect_rows_with_changed_bounds_for_column(j); + } + + void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds() { + for (auto j : m_columns_with_changed_bound.m_index) + update_x_and_inf_costs_for_column_with_changed_bounds(j); + } + + void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { + lean_assert(ax_is_correct()); + for (auto j : m_columns_with_changed_bound.m_index) + update_x_and_inf_costs_for_column_with_changed_bounds(j); + + if (tableau_with_costs()) { + for (unsigned j : m_basic_columns_with_changed_cost.m_index) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + } + } + + + void lar_solver::solve_with_core_solver() { + if (!use_tableau()) + add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); + if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { + add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); + } + m_mpq_lar_core_solver.prefix_r(); + if (costs_are_used()) { + m_basic_columns_with_changed_cost.clear(); + m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); + } + if (use_tableau()) + update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); + else + update_x_and_inf_costs_for_columns_with_changed_bounds(); + m_mpq_lar_core_solver.solve(); + set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); + lean_assert(m_status != OPTIMAL || all_constraints_hold()); + } + + + numeric_pair lar_solver::get_basic_var_value_from_row_directly(unsigned i) { + numeric_pair r = zero_of_type>(); + + 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 (!is_zero(x)) + r -= c.m_value * x; + } + return r; + } + + numeric_pair lar_solver::get_basic_var_value_from_row(unsigned i) { + if (settings().use_tableau()) { + return get_basic_var_value_from_row_directly(i); + } + + numeric_pair r = zero_of_type>(); + m_mpq_lar_core_solver.calculate_pivot_row(i); + for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; + } + return r; + } + + template + void lar_solver::add_last_rows_to_lu(lp_primal_core_solver & s) { + auto & f = s.m_factorization; + if (f != nullptr) { + auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); + if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { + delete f; + f = nullptr; + } else { + f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); + } + } + if (f == nullptr) { + init_factorization(f, s.m_A, s.m_basis, m_settings); + if (f->get_status() != LU_status::OK) { + delete f; + f = nullptr; + } + } + + } + + bool lar_solver::x_is_correct() const { + if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { + // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; + return false; + } + for (unsigned i = 0; i < A_r().row_count(); i++) { + numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); + if (!delta.is_zero()) { + // std::cout << "x is off ("; + // std::cout << "m_b[" << i << "] = " << m_b[i] << " "; + // std::cout << "left side = " << A().dot_product_with_row(i, m_r_solver.m_x) << ' '; + // std::cout << "delta = " << delta << ' '; + // std::cout << "iters = " << total_iterations() << ")" << std::endl; + // std::cout << "row " << i << " is off" << std::endl; + return false; + } + } + return true;; + + } + + bool lar_solver::var_is_registered(var_index vj) const { + if (vj >= m_terms_start_index) { + if (vj - m_terms_start_index >= m_terms.size()) + return false; + } else if ( vj >= A_r().column_count()) { + return false; + } + return true; + } + + unsigned lar_solver::constraint_stack_size() const { + return m_constraint_count.stack_size(); + } + + void lar_solver::fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { + lean_assert(A.row_count() > 0); + lean_assert(A.column_count() > 0); + unsigned last_row = A.row_count() - 1; + lean_assert(A.m_rows[last_row].size() == 0); + for (auto & t : ls->m_coeffs) { + lean_assert(!is_zero(t.second)); + var_index j = t.first; + A.set(last_row, j, - t.second); + } + unsigned basis_j = A.column_count() - 1; + A.set(last_row, basis_j, mpq(1)); + } + + template + void lar_solver::create_matrix_A(static_matrix & matr) { + lean_assert(false); // not implemented + /* + unsigned m = number_or_nontrivial_left_sides(); + unsigned n = m_vec_of_canonic_left_sides.size(); + if (matr.row_count() == m && matr.column_count() == n) + return; + matr.init_empty_matrix(m, n); + copy_from_mpq_matrix(matr); + */ + } + + template + void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { + matr.m_rows.resize(A_r().row_count()); + 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())); + } + } + } + + + bool lar_solver::try_to_set_fixed(column_info & ci) { + if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { + ci.set_fixed_value(ci.get_upper_bound()); + return true; + } + return false; + } + + column_type lar_solver::get_column_type(const column_info & ci) { + auto ret = ci.get_column_type_no_flipping(); + if (ret == column_type::boxed) { // changing boxed to fixed because of the no span + if (ci.get_low_bound() == ci.get_upper_bound()) + ret = column_type::fixed; + } + return ret; + } + + std::string lar_solver::get_column_name(unsigned j) const { + if (j >= m_terms_start_index) + return std::string("_t") + T_to_string(j); + if (j >= m_columns_to_ext_vars_or_term_indices.size()) + return std::string("_s") + T_to_string(j); + + return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]); + } + + bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { + for (auto it : left_side) { + if (! var_is_registered(it.second)) + return false; + } + return true; + } + + constraint_index lar_solver::add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { + /* + mpq rs = right_side_parm; + vector> left_side; + substitute_terms(one_of_type(), left_side_with_terms, left_side, rs); + lean_assert(left_side.size() > 0); + lean_assert(all_constrained_variables_are_registered(left_side)); + lar_constraint original_constr(left_side, kind_par, rs); + unsigned j; // j is the index of the basic variables corresponding to the left side + canonic_left_side ls = create_or_fetch_canonic_left_side(left_side, j); + mpq ratio = find_ratio_of_original_constraint_to_normalized(ls, original_constr); + auto kind = ratio.is_neg() ? flip_kind(kind_par) : kind_par; + rs/= ratio; + lar_normalized_constraint normalized_constraint(ls, ratio, kind, rs, original_constr); + m_constraints.push_back(normalized_constraint); + constraint_index constr_ind = m_constraints.size() - 1; + update_column_type_and_bound(j, kind, rs, constr_ind); + return constr_ind; + */ + lean_assert(false); // not implemented + return 0; + } + + bool lar_solver::all_constraints_hold() const { + if (m_settings.get_cancel_flag()) + return true; + std::unordered_map var_map; + get_model(var_map); + + for (unsigned i = 0; i < m_constraints.size(); i++) { + if (!constraint_holds(*m_constraints[i], var_map)) { + print_constraint(i, std::cout); + return false; + } + } + return true; + } + + bool lar_solver::constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { + mpq left_side_val = get_left_side_val(constr, var_map); + switch (constr.m_kind) { + case LE: return left_side_val <= constr.m_right_side; + case LT: return left_side_val < constr.m_right_side; + case GE: return left_side_val >= constr.m_right_side; + case GT: return left_side_val > constr.m_right_side; + case EQ: return left_side_val == constr.m_right_side; + default: + lean_unreachable(); + } + return false; // it is unreachable + } + + bool lar_solver::the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const { + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lconstraint_kind kind = coeff.is_pos() ? + m_constraints[con_ind]->m_kind : + flip_kind(m_constraints[con_ind]->m_kind); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + } + the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); + if (strict) + the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); + + return n_of_G == 0 || n_of_L == 0; + } + +void lar_solver::register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a) { + for (auto & it : cn.get_left_side_coefficients()) { + unsigned j = it.second; + auto p = coeffs.find(j); + if (p == coeffs.end()) + coeffs[j] = it.first * a; + else { + p->second += it.first * a; + if (p->second.is_zero()) + coeffs.erase(p); + } + } + } + + bool lar_solver::the_left_sides_sum_to_zero(const vector> & evidence) const { + std::unordered_map coeff_map; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + register_in_map(coeff_map, *m_constraints[con_ind], coeff); + } + + if (!coeff_map.empty()) { + std::cout << "left side = "; + vector> t; + for (auto & it : coeff_map) { + t.push_back(std::make_pair(it.second, it.first)); + } + print_linear_combination_of_column_indices(t, std::cout); + std::cout << std::endl; + return false; + } + + return true; + } + + bool lar_solver::the_right_sides_do_not_sum_to_zero(const vector> & evidence) { + mpq ret = numeric_traits::zero(); + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + const lar_constraint & constr = *m_constraints[con_ind]; + ret += constr.m_right_side * coeff; + } + return !numeric_traits::is_zero(ret); + } + + bool lar_solver::explanation_is_correct(const vector>& explanation) const { +#ifdef LEAN_DEBUG + lconstraint_kind kind; + lean_assert(the_relations_are_of_same_type(explanation, kind)); + lean_assert(the_left_sides_sum_to_zero(explanation)); + mpq rs = sum_of_right_sides_of_explanation(explanation); + switch (kind) { + case LE: lean_assert(rs < zero_of_type()); + break; + case LT: lean_assert(rs <= zero_of_type()); + break; + case GE: lean_assert(rs > zero_of_type()); + break; + case GT: lean_assert(rs >= zero_of_type()); + break; + case EQ: lean_assert(rs != zero_of_type()); + break; + default: + lean_assert(false); + return false; + } +#endif + return true; + } + + bool lar_solver::inf_explanation_is_correct() const { +#ifdef LEAN_DEBUG + vector> explanation; + get_infeasibility_explanation(explanation); + return explanation_is_correct(explanation); +#endif + return true; + } + + mpq lar_solver::sum_of_right_sides_of_explanation(const vector> & explanation) const { + mpq ret = numeric_traits::zero(); + for (auto & it : explanation) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; + } + return ret; + } + + bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { + + if (var >= m_vars_to_ul_pairs.size()) { + // TBD: bounds on terms could also be used, caller may have to track these. + return false; + } + const ul_pair & ul = m_vars_to_ul_pairs[var]; + ci = ul.low_bound_witness(); + if (ci != static_cast(-1)) { + auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; + value = p.x; + is_strict = p.y.is_pos(); + return true; + } + else { + return false; + } + } + + bool lar_solver::has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { + + if (var >= m_vars_to_ul_pairs.size()) { + // TBD: bounds on terms could also be used, caller may have to track these. + return false; + } + const ul_pair & ul = m_vars_to_ul_pairs[var]; + ci = ul.upper_bound_witness(); + if (ci != static_cast(-1)) { + auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; + value = p.x; + is_strict = p.y.is_neg(); + return true; + } + else { + return false; + } + } + + void lar_solver::get_infeasibility_explanation(vector> & explanation) const { + explanation.clear(); + if (m_infeasible_column_index != -1) { + fill_explanation_from_infeasible_column(explanation); + return; + } + if (m_mpq_lar_core_solver.get_infeasible_sum_sign() == 0) { + return; + } + // the infeasibility sign + int inf_sign; + auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); + get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); + lean_assert(explanation_is_correct(explanation)); + } + + void lar_solver::get_infeasibility_explanation_for_inf_sign( + vector> & explanation, + const vector> & inf_row, + int inf_sign) const { + + for (auto & it : inf_row) { + mpq coeff = it.first; + unsigned j = it.second; + + int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; + const ul_pair & ul = m_vars_to_ul_pairs[j]; + + constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); + lean_assert(bound_constr_i < m_constraints.size()); + explanation.push_back(std::make_pair(coeff, bound_constr_i)); + } + } + + void lar_solver::get_model(std::unordered_map & variable_values) const { + mpq delta = mpq(1, 2); // start from 0.5 to have less clashes + lean_assert(m_status == OPTIMAL); + unsigned i; + do { + + // different pairs have to produce different singleton values + std::unordered_set set_of_different_pairs; + std::unordered_set set_of_different_singles; + delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); + for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { + const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; + set_of_different_pairs.insert(rp); + mpq x = rp.x + delta * rp.y; + set_of_different_singles.insert(x); + if (set_of_different_pairs.size() + != set_of_different_singles.size()) { + delta /= mpq(2); + break; + } + + variable_values[i] = x; + } + } while (i != m_mpq_lar_core_solver.m_r_x.size()); + } + +std::string lar_solver::get_variable_name(var_index vi) const { + return get_column_name(vi); +} + + // ********** print region start + void lar_solver::print_constraint(constraint_index ci, std::ostream & out) const { + if (ci >= m_constraints.size()) { + out << "constraint " << T_to_string(ci) << " is not found"; + out << std::endl; + return; + } + + print_constraint(m_constraints[ci], out); + } + + void lar_solver::print_constraints(std::ostream& out) const { + for (auto c : m_constraints) { + print_constraint(c, out); + } + } + + void lar_solver::print_terms(std::ostream& out) const { + for (auto it : m_terms) { + print_term(*it, out); + out << "\n"; + } + } + + void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const { + print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out); + mpq free_coeff = c->get_free_coeff_of_left_side(); + if (!is_zero(free_coeff)) + out << " + " << free_coeff; + + } + + void lar_solver::print_term(lar_term const& term, std::ostream & out) const { + if (!numeric_traits::is_zero(term.m_v)) { + out << term.m_v << " + "; + } + print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); + } + + mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { + mpq ret = cns.get_free_coeff_of_left_side(); + for (auto & it : cns.get_left_side_coefficients()) { + var_index j = it.second; + auto vi = var_map.find(j); + lean_assert(vi != var_map.end()); + ret += it.first * vi->second; + } + return ret; + } + + void lar_solver::print_constraint(const lar_base_constraint * c, std::ostream & out) const { + print_left_side_of_constraint(c, out); + out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; + } + + void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { + for (unsigned i = 0; i < sz; i++) { + var_index var = vars[i]; + if (var >= m_terms_start_index) { // handle the term + for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { + column_list.push_back(it.first); + } + } else { + column_list.push_back(var); + } + } + } + + void lar_solver::random_update(unsigned sz, var_index const * vars) { + vector column_list; + fill_var_set_for_random_update(sz, vars, column_list); + random_updater ru(m_mpq_lar_core_solver, column_list); + ru.update(); + } + + + void lar_solver::try_pivot_fixed_vars_from_basis() { + m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); + } + + void lar_solver::pop() { + pop(1); + } + + bool lar_solver::column_represents_row_in_tableau(unsigned j) { + return m_vars_to_ul_pairs()[j].m_i != static_cast(-1); + } + + void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { + // i, j - is the indices of the bottom-right element of the tableau + lean_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;){ + auto & cc = last_column[k]; + if (cc.m_i == i) + return; + non_zero_column_cell_index = k; + } + + lean_assert(non_zero_column_cell_index != -1); + lean_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); + } + + void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + auto & slv = m_mpq_lar_core_solver.m_r_solver; + unsigned i = A_r().row_count() - 1; //last row index + make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); + if (slv.m_basis_heading[j] < 0) { + slv.pivot_column_tableau(j, i); + } + + 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;) { + auto &rc = last_row[k]; + if (cost_is_nz) { + m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); + } + + A_r().remove_element(last_row, rc); + } + lean_assert(last_row.size() == 0); + lean_assert(A_r().m_columns[j].size() == 0); + A_r().m_rows.pop_back(); + A_r().m_columns.pop_back(); + slv.m_b.pop_back(); + } + + void lar_solver::remove_last_column_from_tableau(unsigned j) { + lean_assert(j == A_r().column_count() - 1); + // the last column has to be empty + lean_assert(A_r().m_columns[j].size() == 0); + A_r().m_columns.pop_back(); + } + + void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { + auto& rslv = m_mpq_lar_core_solver.m_r_solver; + int i = rslv.m_basis_heading[j]; + if (i >= 0) { // j is a basic var + int last_pos = static_cast(rslv.m_basis.size()) - 1; + lean_assert(last_pos >= 0); + if (i != last_pos) { + unsigned j_at_last_pos = rslv.m_basis[last_pos]; + rslv.m_basis[i] = j_at_last_pos; + rslv.m_basis_heading[j_at_last_pos] = i; + } + rslv.m_basis.pop_back(); // remove j from the basis + } else { + int last_pos = static_cast(rslv.m_nbasis.size()) - 1; + lean_assert(last_pos >= 0); + i = - 1 - i; + if (i != last_pos) { + unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; + rslv.m_nbasis[i] = j_at_last_pos; + rslv.m_basis_heading[j_at_last_pos] = - i - 1; + } + rslv.m_nbasis.pop_back(); // remove j from the basis + } + rslv.m_basis_heading.pop_back(); + lean_assert(rslv.m_basis.size() == A_r().row_count()); + lean_assert(rslv.basis_heading_is_correct()); + } + + void lar_solver::remove_column_from_tableau(unsigned j) { + auto& rslv = m_mpq_lar_core_solver.m_r_solver; + lean_assert(j == A_r().column_count() - 1); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + if (column_represents_row_in_tableau(j)) { + remove_last_row_and_column_from_tableau(j); + if (rslv.m_basis_heading[j] < 0) + rslv.change_basis_unconditionally(j, rslv.m_basis[A_r().row_count()]); // A_r().row_count() is the index of the last row in the basis still + } + else { + remove_last_column_from_tableau(j); + } + rslv.m_x.pop_back(); + rslv.m_d.pop_back(); + rslv.m_costs.pop_back(); + + remove_last_column_from_basis_tableau(j); + lean_assert(m_mpq_lar_core_solver.r_basis_is_OK()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + } + + void lar_solver::pop_tableau() { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). + // At this moment m_column_names is already popped + for (unsigned j = A_r().column_count(); j-- > m_columns_to_ext_vars_or_term_indices.size();) + remove_column_from_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + } + +void lar_solver::clean_inf_set_of_r_solver_after_pop() { + vector became_feas; + clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); + std::unordered_set basic_columns_with_changed_cost; + auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; + for (auto j: inf_index_copy) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + continue; + } + // some basic columns might become non-basic - these columns need to be made feasible + numeric_pair delta; + if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) + change_basic_x_by_delta_on_column(j, delta); + became_feas.push_back(j); + } + + for (unsigned j : became_feas) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; + m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); + m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); + } + became_feas.clear(); + for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { + lean_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); + if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) + became_feas.push_back(j); + } + for (unsigned j : became_feas) + m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); + + + if (use_tableau_costs()) { + for (unsigned j : became_feas) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + for (unsigned j : basic_columns_with_changed_cost) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + } + } + + void lar_solver::shrink_explanation_to_minimum(vector> & explanation) const { + // implementing quickXplain + quick_xplain::run(explanation, *this); + lean_assert(this->explanation_is_correct(explanation)); + } +} // namespace lean + + diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 5f7ce96a4..f752d6734 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -57,1415 +57,335 @@ class lar_solver : public column_namer { std::function m_column_type_function; public: lar_core_solver m_mpq_lar_core_solver; - unsigned constraint_count() const { - return m_constraints.size(); - } - const lar_base_constraint& get_constraint(unsigned ci) const { - return *(m_constraints[ci]); - } + unsigned constraint_count() const; + const lar_base_constraint& get_constraint(unsigned ci) const; ////////////////// methods //////////////////////////////// - static_matrix> & A_r() { return m_mpq_lar_core_solver.m_r_A;} - static_matrix> const & A_r() const { return m_mpq_lar_core_solver.m_r_A;} - static_matrix & A_d() { return m_mpq_lar_core_solver.m_d_A;} - static_matrix const & A_d() const { return m_mpq_lar_core_solver.m_d_A;} + static_matrix> & A_r(); + static_matrix> const & A_r() const; + static_matrix & A_d(); + static_matrix const & A_d() const; static bool valid_index(unsigned j){ return static_cast(j) >= 0;} public: - lp_settings & settings() { return m_settings;} - lp_settings const & settings() const { return m_settings;} + // init region + bool strategy_is_undecided() const; - void clear() {lean_assert(false); // not implemented - } + var_index add_var(unsigned ext_j); + + void register_new_ext_var_index(unsigned ext_v); + + void add_non_basic_var_to_core_fields(unsigned ext_j); + + void add_new_var_to_core_fields_for_doubles(bool register_in_basis); + + void add_new_var_to_core_fields_for_mpq(bool register_in_basis); - lar_solver() : m_status(OPTIMAL), - m_infeasible_column_index(-1), - m_terms_start_index(1000000), - m_column_type_function ([this] (unsigned j) {return m_mpq_lar_core_solver.m_column_types()[j];}), - m_mpq_lar_core_solver(m_settings, *this) - {} + var_index add_term_undecided(const vector> & coeffs, + const mpq &m_v); + + // terms + var_index add_term(const vector> & coeffs, + const mpq &m_v); + + void add_row_for_term(const lar_term * term, unsigned term_ext_index); + + void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index); + + void add_basic_var_to_core_fields(); + + constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) ; + + void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index); + + void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); + + + void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, + lconstraint_kind kind, const mpq & right_side); + + void decide_on_strategy_and_adjust_initial_state(); + + void adjust_initial_state(); + + void adjust_initial_state_for_lu(); + + void adjust_initial_state_for_tableau_rows(); + + // this fills the last row of A_d and sets the basis column: -1 in the last column of the row + void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls); + + void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind); + + void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); - void set_propagate_bounds_on_pivoted_rows_mode(bool v) { - m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; - } + void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); + void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); - virtual ~lar_solver(){ - for (auto c : m_constraints) - delete c; - for (auto t : m_terms) - delete t; - for (auto t : m_orig_terms) - delete t; - } + void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); + //end of init region + lp_settings & settings(); -#include "util/lp/init_lar_solver.h" - - numeric_pair const& get_value(var_index vi) const { return m_mpq_lar_core_solver.m_r_x[vi]; } - - bool is_term(var_index j) const { - return j >= m_terms_start_index && j - m_terms_start_index < m_terms.size(); - } - - unsigned adjust_term_index(unsigned j) const { - lean_assert(is_term(j)); - return j - m_terms_start_index; - } - - - bool use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } - - bool sizes_are_correct() const { - lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); - return true; - } + lp_settings const & settings() const; + + void clear(); + + + lar_solver(); + void set_propagate_bounds_on_pivoted_rows_mode(bool v); + + virtual ~lar_solver(); + + numeric_pair const& get_value(var_index vi) const; + + bool is_term(var_index j) const; + + unsigned adjust_term_index(unsigned j) const; + + + bool use_lu() const; + bool sizes_are_correct() const; - void print_implied_bound(const implied_bound& be, std::ostream & out) const { - out << "implied bound\n"; - unsigned v = be.m_j; - if (is_term(v)) { - out << "it is a term number " << be.m_j << std::endl; - print_term(*m_orig_terms[be.m_j - m_terms_start_index], out); - } - else { - out << get_column_name(v); - } - out << " " << lconstraint_kind_string(be.kind()) << " " << be.m_bound << std::endl; - // for (auto & p : be.m_explanation) { - // out << p.first << " : "; - // print_constraint(p.second, out); - // } - - // m_mpq_lar_core_solver.m_r_solver.print_column_info(be.m_j< m_terms_start_index? be.m_j : adjust_term_index(be.m_j), out); - out << "end of implied bound" << std::endl; - } + void print_implied_bound(const implied_bound& be, std::ostream & out) const; - bool implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { - std::unordered_map coeff_map; - auto rs_of_evidence = zero_of_type(); - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto & it : explanation) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - const auto & constr = *m_constraints[con_ind]; - lconstraint_kind kind = coeff.is_pos() ? constr.m_kind : flip_kind(constr.m_kind); - register_in_map(coeff_map, constr, coeff); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) n_of_G++; - else if (kind == LE || kind == LT) n_of_L++; - rs_of_evidence += coeff*constr.m_right_side; - } - lean_assert(n_of_G == 0 || n_of_L == 0); - lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - kind = static_cast((static_cast(kind) / 2)); - - if (!is_term(be.m_j)) { - if (coeff_map.size() != 1) - return false; - auto it = coeff_map.find(be.m_j); - if (it == coeff_map.end()) return false; - mpq ratio = it->second; - if (ratio < zero_of_type()) { - kind = static_cast(-kind); - } - rs_of_evidence /= ratio; - } else { - const lar_term * t = m_orig_terms[adjust_term_index(be.m_j)]; - const auto first_coeff = *t->m_coeffs.begin(); - unsigned j = first_coeff.first; - auto it = coeff_map.find(j); - if (it == coeff_map.end()) - return false; - mpq ratio = it->second / first_coeff.second; - for (auto & p : t->m_coeffs) { - it = coeff_map.find(p.first); - if (it == coeff_map.end()) - return false; - if (p.second * ratio != it->second) - return false; - } - if (ratio < zero_of_type()) { - kind = static_cast(-kind); - } - rs_of_evidence /= ratio; - rs_of_evidence += t->m_v * ratio; - } - - return kind == be.kind() && rs_of_evidence == be.m_bound; - } - + bool implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const; void analyze_new_bounds_on_row( unsigned row_index, - bound_propagator & bp) { - lean_assert(!use_tableau()); - iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); - - bound_analyzer_on_row ra_pos(it, - zero_of_type>(), - row_index, - bp - ); - ra_pos.analyze(); - } + bound_propagator & bp); void 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) - return; - iterator_on_row it(A_r().m_rows[row_index]); - lean_assert(use_tableau()); - bound_analyzer_on_row::analyze_row(it, - zero_of_type>(), - row_index, - bp ); - } - void substitute_basis_var_in_terms_for_row(unsigned i) { - // todo : create a map from term basic vars to the rows where they are used - unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; - for (unsigned k = 0; k < m_terms.size(); k++) { - if (term_is_used_as_row(k)) - continue; - if (!m_terms[k]->contains(basis_j)) - continue; - m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); - } - } + void substitute_basis_var_in_terms_for_row(unsigned i); - void calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { - if(use_tableau()) { - analyze_new_bounds_on_row_tableau(i, bp); - } else { - m_mpq_lar_core_solver.calculate_pivot_row(i); - substitute_basis_var_in_terms_for_row(i); - analyze_new_bounds_on_row(i, bp); - } - } + void calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp); - linear_combination_iterator * create_new_iter_from_term(unsigned term_index) const { - lean_assert(false); // not implemented - return nullptr; - // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); - } + linear_combination_iterator * create_new_iter_from_term(unsigned term_index) const; - unsigned adjust_column_index_to_term_index(unsigned j) const { - unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; - return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; - } + unsigned adjust_column_index_to_term_index(unsigned j) const; - void propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { - lean_assert(false); // not implemented - } + void propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset); - void explain_implied_bound(implied_bound & ib, bound_propagator & bp) { - unsigned i = ib.m_row_or_term_index; - int bound_sign = ib.m_is_low_bound? 1: -1; - int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; - unsigned m_j = ib.m_j; - if (is_term(m_j)) { - m_j = m_ext_vars_to_columns[m_j]; - } - for (auto const& r : A_r().m_rows[i]) { - unsigned j = r.m_j; - mpq const& a = r.get_val(); - if (j == m_j) continue; - if (is_term(j)) { - j = m_ext_vars_to_columns[j]; - } - int a_sign = is_pos(a)? 1: -1; - int sign = j_sign * a_sign; - const ul_pair & ul = m_vars_to_ul_pairs[j]; - auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); - lean_assert(is_valid(witness)); - bp.consume(a, witness); - } - // lean_assert(implied_bound_is_correctly_explained(ib, explanation)); - } + void explain_implied_bound(implied_bound & ib, bound_propagator & bp); - bool term_is_used_as_row(unsigned term) const { - lean_assert(is_term(term)); - return contains(m_ext_vars_to_columns, term); - } + bool term_is_used_as_row(unsigned term) const; - void propagate_bounds_on_terms(bound_propagator & bp) { - for (unsigned i = 0; i < m_terms.size(); i++) { - if (term_is_used_as_row(i + m_terms_start_index)) - continue; // this term is used a left side of a constraint, - // it was processed as a touched row if needed - propagate_bounds_on_a_term(*m_terms[i], bp, i); - } - } + void propagate_bounds_on_terms(bound_propagator & bp); // goes over touched rows and tries to induce bounds - void propagate_bounds_for_touched_rows(bound_propagator & bp) { - if (!use_tableau()) - return; // ! todo : enable bound propagaion here. The current bug is that after the pop - // the changed terms become incorrect! + void propagate_bounds_for_touched_rows(bound_propagator & bp); - for (unsigned i : m_rows_with_changed_bounds.m_index) { - calculate_implied_bounds_for_row(i, bp); - } - m_rows_with_changed_bounds.clear(); - if (!use_tableau()) { - propagate_bounds_on_terms(bp); - } - } + lp_status get_status() const; - lp_status get_status() const { return m_status;} + void set_status(lp_status s); - void set_status(lp_status s) {m_status = s;} - - lp_status find_feasible_solution() { - if (strategy_is_undecided()) - decide_on_strategy_and_adjust_initial_state(); - - m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; - return solve(); - } + lp_status find_feasible_solution(); - lp_status solve() { - if (m_status == INFEASIBLE) { - return m_status; - } - solve_with_core_solver(); - if (m_status != INFEASIBLE) { - if (m_settings.bound_propagation()) - detect_rows_with_changed_bounds(); - } - - m_columns_with_changed_bound.clear(); - return m_status; - } + lp_status solve(); - void fill_explanation_from_infeasible_column(vector> & evidence) const{ - - // this is the case when the lower bound is in conflict with the upper one - const ul_pair & ul = m_vars_to_ul_pairs[m_infeasible_column_index]; - evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); - evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); - } + void fill_explanation_from_infeasible_column(vector> & evidence) const; - unsigned get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } + unsigned get_total_iterations() const; // see http://research.microsoft.com/projects/z3/smt07.pdf // This method searches for a feasible solution with as many different values of variables, reverenced in vars, as it can find // Attention, after a call to this method the non-basic variables don't necesserarly stick to their bounds anymore - vector get_list_of_all_var_indices() const { - vector ret; - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) - ret.push_back(j); - return ret; - } - void push() { - m_simplex_strategy = m_settings.simplex_strategy(); - m_simplex_strategy.push(); - m_status.push(); - m_vars_to_ul_pairs.push(); - m_infeasible_column_index.push(); - m_mpq_lar_core_solver.push(); - m_term_count = m_terms.size(); - m_term_count.push(); - m_constraint_count = m_constraints.size(); - m_constraint_count.push(); - } + vector get_list_of_all_var_indices() const; + void push(); - static void clean_large_elements_after_pop(unsigned n, int_set& set) { - vector to_remove; - for (unsigned j: set.m_index) - if (j >= n) - to_remove.push_back(j); - for (unsigned j : to_remove) - set.erase(j); - } + static void clean_large_elements_after_pop(unsigned n, int_set& set); - static void shrink_inf_set_after_pop(unsigned n, int_set & set) { - clean_large_elements_after_pop(n, set); - set.resize(n); - } + static void shrink_inf_set_after_pop(unsigned n, int_set & set); - void pop(unsigned k) { - int n_was = static_cast(m_ext_vars_to_columns.size()); - m_status.pop(k); - m_infeasible_column_index.pop(k); - unsigned n = m_vars_to_ul_pairs.peek_size(k); - for (unsigned j = n_was; j-- > n;) - m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); - m_columns_to_ext_vars_or_term_indices.resize(n); - if (m_settings.use_tableau()) { - pop_tableau(); - } - m_vars_to_ul_pairs.pop(k); - - m_mpq_lar_core_solver.pop(k); - clean_large_elements_after_pop(n, m_columns_with_changed_bound); - unsigned m = A_r().row_count(); - clean_large_elements_after_pop(m, m_rows_with_changed_bounds); - clean_inf_set_of_r_solver_after_pop(); - lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || - (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - - - lean_assert(ax_is_correct()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); - m_constraint_count.pop(k); - for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) - delete m_constraints[i]; - - m_constraints.resize(m_constraint_count); - m_term_count.pop(k); - for (unsigned i = m_term_count; i < m_terms.size(); i++) { - delete m_terms[i]; - delete m_orig_terms[i]; - } - m_terms.resize(m_term_count); - m_orig_terms.resize(m_term_count); - m_simplex_strategy.pop(k); - m_settings.simplex_strategy() = m_simplex_strategy; - lean_assert(sizes_are_correct()); - lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } + void pop(unsigned k); - vector get_all_constraint_indices() const { - vector ret; - constraint_index i = 0; - while ( i < m_constraints.size()) - ret.push_back(i++); - return ret; - } + vector get_all_constraint_indices() const; bool maximize_term_on_tableau(const vector> & term, - impq &term_max) { - if (settings().simplex_strategy() == simplex_strategy_enum::undecided) - decide_on_strategy_and_adjust_initial_state(); - - m_mpq_lar_core_solver.solve(); - if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED) - return false; + impq &term_max); - term_max = 0; - for (auto & p : term) - term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second]; - - return true; - } - - bool costs_are_zeros_for_r_solver() const { - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); - } - return true; - } - bool reduced_costs_are_zeroes_for_r_solver() const { - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); - } - return true; - } + bool costs_are_zeros_for_r_solver() const; + bool reduced_costs_are_zeroes_for_r_solver() const; - void set_costs_to_zero(const vector> & term) { - auto & rslv = m_mpq_lar_core_solver.m_r_solver; - auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now - lean_assert(jset.m_index.size()==0); - - for (auto & p : term) { - unsigned j = p.second; - rslv.m_costs[j] = zero_of_type(); - int i = rslv.m_basis_heading[j]; - if (i < 0) - jset.insert(j); - else { - for (auto & rc : A_r().m_rows[i]) - jset.insert(rc.m_j); - } - } + void set_costs_to_zero(const vector> & term); - for (unsigned j : jset.m_index) - rslv.m_d[j] = zero_of_type(); - - jset.clear(); - - lean_assert(reduced_costs_are_zeroes_for_r_solver()); - lean_assert(costs_are_zeros_for_r_solver()); - } - - void prepare_costs_for_r_solver(const vector> & term) { - - auto & rslv = m_mpq_lar_core_solver.m_r_solver; - rslv.m_using_infeas_costs = false; - lean_assert(costs_are_zeros_for_r_solver()); - lean_assert(reduced_costs_are_zeroes_for_r_solver()); - rslv.m_costs.resize(A_r().column_count(), zero_of_type()); - for (auto & p : term) { - unsigned j = p.second; - rslv.m_costs[j] = p.first; - if (rslv.m_basis_heading[j] < 0) - rslv.m_d[j] += p.first; - else - rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); - } - lean_assert(rslv.reduced_costs_are_correct_tableau()); - } + void prepare_costs_for_r_solver(const vector> & term); bool maximize_term_on_corrected_r_solver(const vector> & term, - impq &term_max) { - settings().backup_costs = false; - switch (settings().simplex_strategy()) { - case simplex_strategy_enum::tableau_rows: - prepare_costs_for_r_solver(term); - settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; - { - bool ret = maximize_term_on_tableau(term, term_max); - settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); - return ret; - } - case simplex_strategy_enum::tableau_costs: - prepare_costs_for_r_solver(term); - { - bool ret = maximize_term_on_tableau(term, term_max); - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); - return ret; - } - - case simplex_strategy_enum::lu: - lean_assert(false); // not implemented - return false; - default: - lean_unreachable(); // wrong mode - } - return false; - } + impq &term_max); // starting from a given feasible state look for the maximum of the term // return true if found and false if unbounded bool maximize_term(const vector> & term, - impq &term_max) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); - m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; - return maximize_term_on_corrected_r_solver(term, term_max); - } + impq &term_max); - const lar_term & get_term(unsigned j) const { - lean_assert(j >= m_terms_start_index); - return *m_terms[j - m_terms_start_index]; - } + const lar_term & get_term(unsigned j) const; - void pop_core_solver_params() { - pop_core_solver_params(1); - } + void pop_core_solver_params(); - void pop_core_solver_params(unsigned k) { - A_r().pop(k); - A_d().pop(k); - } + void pop_core_solver_params(unsigned k); - void set_upper_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_vars_to_ul_pairs[j]; - ul.upper_bound_witness() = ci; - m_vars_to_ul_pairs[j] = ul; - } + void set_upper_bound_witness(var_index j, constraint_index ci); - void set_low_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_vars_to_ul_pairs[j]; - ul.low_bound_witness() = ci; - m_vars_to_ul_pairs[j] = ul; - } + void set_low_bound_witness(var_index j, constraint_index ci); void substitute_terms(const mpq & mult, const vector>& left_side_with_terms, - vector> &left_side, mpq & right_side) const { - for (auto & t : left_side_with_terms) { - if (t.second < m_terms_start_index) { - lean_assert(t.second < A_r().column_count()); - left_side.push_back(std::pair(mult * t.first, t.second)); - } else { - const lar_term & term = * m_terms[adjust_term_index(t.second)]; - substitute_terms(mult * t.first, left_side_with_terms, left_side, right_side); - right_side -= mult * term.m_v; - } - } - } + vector> &left_side, mpq & right_side) const; - void detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { - if (A_r().row_count() != m_column_buffer.data_size()) - m_column_buffer.resize(A_r().row_count()); - else - m_column_buffer.clear(); - lean_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); - - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) - m_rows_with_changed_bounds.insert(i); - } + void detect_rows_of_bound_change_column_for_nbasic_column(unsigned j); - void 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); - } + void detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j); - bool use_tableau() const { return m_settings.use_tableau(); } + bool use_tableau() const; - bool use_tableau_costs() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; - } + bool use_tableau_costs() const; - void detect_rows_of_column_with_bound_change(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column - // just mark the row at touched and exit - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); - return; - } + void detect_rows_of_column_with_bound_change(unsigned j); - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); - } + void adjust_x_of_column(unsigned j); - void adjust_x_of_column(unsigned j) { - lean_assert(false); - } - - bool 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]; - return is_zero(r); - } + bool row_is_correct(unsigned i) const; - bool ax_is_correct() const { - for (unsigned i = 0; i < A_r().row_count(); i++) { - if (!row_is_correct(i)) - return false; - } - return true; - } + bool ax_is_correct() const; - bool tableau_with_costs() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; - } + bool tableau_with_costs() const; - bool costs_are_used() const { - return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; - } + bool costs_are_used() const; - void change_basic_x_by_delta_on_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]; - m_mpq_lar_core_solver.m_r_x[bj] -= A_r().get_val(c) * delta; - if (tableau_with_costs()) { - m_basic_columns_with_changed_cost.insert(bj); - } - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); - } - } else { - m_column_buffer.clear(); - m_column_buffer.resize(A_r().row_count()); - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; - m_mpq_lar_core_solver.m_r_x[bj] -= m_column_buffer[i] * delta; - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); - } - } - } + void change_basic_x_by_delta_on_column(unsigned j, const numeric_pair & delta); - void update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - if (costs_are_used()) { - bool was_infeas = m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j); - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); - if (was_infeas != m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j)) - m_basic_columns_with_changed_cost.insert(j); - } else { - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); - } - } else { - numeric_pair delta; - if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) - change_basic_x_by_delta_on_column(j, delta); - } - } + void update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j); - void detect_rows_with_changed_bounds_for_column(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); - return; - } - - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); - } + void detect_rows_with_changed_bounds_for_column(unsigned j); - void detect_rows_with_changed_bounds() { - for (auto j : m_columns_with_changed_bound.m_index) - detect_rows_with_changed_bounds_for_column(j); - } + void detect_rows_with_changed_bounds(); - void update_x_and_inf_costs_for_columns_with_changed_bounds() { - for (auto j : m_columns_with_changed_bound.m_index) - update_x_and_inf_costs_for_column_with_changed_bounds(j); - } + void update_x_and_inf_costs_for_columns_with_changed_bounds(); - void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { - lean_assert(ax_is_correct()); - for (auto j : m_columns_with_changed_bound.m_index) - update_x_and_inf_costs_for_column_with_changed_bounds(j); - - if (tableau_with_costs()) { - for (unsigned j : m_basic_columns_with_changed_cost.m_index) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } - } + void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - void solve_with_core_solver() { - if (!use_tableau()) - add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); - if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { - add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); - } - m_mpq_lar_core_solver.prefix_r(); - if (costs_are_used()) { - m_basic_columns_with_changed_cost.clear(); - m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); - } - if (use_tableau()) - update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - else - update_x_and_inf_costs_for_columns_with_changed_bounds(); - m_mpq_lar_core_solver.solve(); - set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); - lean_assert(m_status != OPTIMAL || all_constraints_hold()); - } + void solve_with_core_solver(); - numeric_pair get_basic_var_value_from_row_directly(unsigned i) { - numeric_pair r = zero_of_type>(); - - 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 (!is_zero(x)) - r -= c.m_value * x; - } - return r; - } + numeric_pair get_basic_var_value_from_row_directly(unsigned i); - numeric_pair get_basic_var_value_from_row(unsigned i) { - if (settings().use_tableau()) { - return get_basic_var_value_from_row_directly(i); - } - - numeric_pair r = zero_of_type>(); - m_mpq_lar_core_solver.calculate_pivot_row(i); - for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); - r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; - } - return r; - } + numeric_pair get_basic_var_value_from_row(unsigned i); template - void add_last_rows_to_lu(lp_primal_core_solver & s) { - auto & f = s.m_factorization; - if (f != nullptr) { - auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); - if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { - delete f; - f = nullptr; - } else { - f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); - } - } - if (f == nullptr) { - init_factorization(f, s.m_A, s.m_basis, m_settings); - if (f->get_status() != LU_status::OK) { - delete f; - f = nullptr; - } - } - - } + void add_last_rows_to_lu(lp_primal_core_solver & s); - bool x_is_correct() const { - if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { - // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; - return false; - } - for (unsigned i = 0; i < A_r().row_count(); i++) { - numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); - if (!delta.is_zero()) { - // std::cout << "x is off ("; - // std::cout << "m_b[" << i << "] = " << m_b[i] << " "; - // std::cout << "left side = " << A().dot_product_with_row(i, m_r_solver.m_x) << ' '; - // std::cout << "delta = " << delta << ' '; - // std::cout << "iters = " << total_iterations() << ")" << std::endl; - // std::cout << "row " << i << " is off" << std::endl; - return false; - } - } - return true;; - - } + bool x_is_correct() const; - bool var_is_registered(var_index vj) const { - if (vj >= m_terms_start_index) { - if (vj - m_terms_start_index >= m_terms.size()) - return false; - } else if ( vj >= A_r().column_count()) { - return false; - } - return true; - } + bool var_is_registered(var_index vj) const; - unsigned constraint_stack_size() const { - return m_constraint_count.stack_size(); - } + unsigned constraint_stack_size() const; - void fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); - unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].size() == 0); - for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); - var_index j = t.first; - A.set(last_row, j, - t.second); - } - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, mpq(1)); - } + void fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls); template - void create_matrix_A(static_matrix & matr) { - lean_assert(false); // not implemented - /* - unsigned m = number_or_nontrivial_left_sides(); - unsigned n = m_vec_of_canonic_left_sides.size(); - if (matr.row_count() == m && matr.column_count() == n) - return; - matr.init_empty_matrix(m, n); - copy_from_mpq_matrix(matr); - */ - } + void create_matrix_A(static_matrix & matr); template - void copy_from_mpq_matrix(static_matrix & matr) { - matr.m_rows.resize(A_r().row_count()); - 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())); - } - } - } + void copy_from_mpq_matrix(static_matrix & matr); - bool try_to_set_fixed(column_info & ci) { - if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { - ci.set_fixed_value(ci.get_upper_bound()); - return true; - } - return false; - } + bool try_to_set_fixed(column_info & ci); - column_type get_column_type(const column_info & ci) { - auto ret = ci.get_column_type_no_flipping(); - if (ret == column_type::boxed) { // changing boxed to fixed because of the no span - if (ci.get_low_bound() == ci.get_upper_bound()) - ret = column_type::fixed; - } - return ret; - } + column_type get_column_type(const column_info & ci); - std::string get_column_name(unsigned j) const { - if (j >= m_terms_start_index) - return std::string("_t") + T_to_string(j); - if (j >= m_columns_to_ext_vars_or_term_indices.size()) - return std::string("_s") + T_to_string(j); + std::string get_column_name(unsigned j) const; - return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]); - } + bool all_constrained_variables_are_registered(const vector>& left_side); - bool all_constrained_variables_are_registered(const vector>& left_side) { - for (auto it : left_side) { - if (! var_is_registered(it.second)) - return false; - } - return true; - } + constraint_index add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm); + bool all_constraints_hold() const; + bool constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const; + bool the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const; - constraint_index add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { - /* - mpq rs = right_side_parm; - vector> left_side; - substitute_terms(one_of_type(), left_side_with_terms, left_side, rs); - lean_assert(left_side.size() > 0); - lean_assert(all_constrained_variables_are_registered(left_side)); - lar_constraint original_constr(left_side, kind_par, rs); - unsigned j; // j is the index of the basic variables corresponding to the left side - canonic_left_side ls = create_or_fetch_canonic_left_side(left_side, j); - mpq ratio = find_ratio_of_original_constraint_to_normalized(ls, original_constr); - auto kind = ratio.is_neg() ? flip_kind(kind_par) : kind_par; - rs/= ratio; - lar_normalized_constraint normalized_constraint(ls, ratio, kind, rs, original_constr); - m_constraints.push_back(normalized_constraint); - constraint_index constr_ind = m_constraints.size() - 1; - update_column_type_and_bound(j, kind, rs, constr_ind); - return constr_ind; - */ - lean_assert(false); // not implemented - return 0; - } + static void register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a); + bool the_left_sides_sum_to_zero(const vector> & evidence) const; - bool all_constraints_hold() const { - if (m_settings.get_cancel_flag()) - return true; - std::unordered_map var_map; - get_model(var_map); + bool the_right_sides_do_not_sum_to_zero(const vector> & evidence); + + bool explanation_is_correct(const vector>& explanation) const; + + bool inf_explanation_is_correct() const; + + mpq sum_of_right_sides_of_explanation(const vector> & explanation) const; + + bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict); - for (unsigned i = 0; i < m_constraints.size(); i++) { - if (!constraint_holds(*m_constraints[i], var_map)) { - print_constraint(i, std::cout); - return false; - } - } - return true; - } - - bool constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { - mpq left_side_val = get_left_side_val(constr, var_map); - switch (constr.m_kind) { - case LE: return left_side_val <= constr.m_right_side; - case LT: return left_side_val < constr.m_right_side; - case GE: return left_side_val >= constr.m_right_side; - case GT: return left_side_val > constr.m_right_side; - case EQ: return left_side_val == constr.m_right_side; - default: - lean_unreachable(); - } - return false; // it is unreachable - } + bool has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict); - - - - - - bool the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const { - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lconstraint_kind kind = coeff.is_pos() ? - m_constraints[con_ind]->m_kind : - flip_kind(m_constraints[con_ind]->m_kind); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) n_of_G++; - else if (kind == LE || kind == LT) n_of_L++; - } - the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); - - return n_of_G == 0 || n_of_L == 0; - } - - static void register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a) { - for (auto & it : cn.get_left_side_coefficients()) { - unsigned j = it.second; - auto p = coeffs.find(j); - if (p == coeffs.end()) - coeffs[j] = it.first * a; - else { - p->second += it.first * a; - if (p->second.is_zero()) - coeffs.erase(p); - } - } - } - bool the_left_sides_sum_to_zero(const vector> & evidence) const { - std::unordered_map coeff_map; - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - register_in_map(coeff_map, *m_constraints[con_ind], coeff); - } - - if (!coeff_map.empty()) { - std::cout << "left side = "; - vector> t; - for (auto & it : coeff_map) { - t.push_back(std::make_pair(it.second, it.first)); - } - print_linear_combination_of_column_indices(t, std::cout); - std::cout << std::endl; - return false; - } - - return true; - } - - bool the_right_sides_do_not_sum_to_zero(const vector> & evidence) { - mpq ret = numeric_traits::zero(); - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - const lar_constraint & constr = *m_constraints[con_ind]; - ret += constr.m_right_side * coeff; - } - return !numeric_traits::is_zero(ret); - } - - bool explanation_is_correct(const vector>& explanation) const { -#ifdef LEAN_DEBUG - lconstraint_kind kind; - lean_assert(the_relations_are_of_same_type(explanation, kind)); - lean_assert(the_left_sides_sum_to_zero(explanation)); - mpq rs = sum_of_right_sides_of_explanation(explanation); - switch (kind) { - case LE: lean_assert(rs < zero_of_type()); - break; - case LT: lean_assert(rs <= zero_of_type()); - break; - case GE: lean_assert(rs > zero_of_type()); - break; - case GT: lean_assert(rs >= zero_of_type()); - break; - case EQ: lean_assert(rs != zero_of_type()); - break; - default: - lean_assert(false); - return false; - } -#endif - return true; - } - - bool inf_explanation_is_correct() const { -#ifdef LEAN_DEBUG - vector> explanation; - get_infeasibility_explanation(explanation); - return explanation_is_correct(explanation); -#endif - return true; - } - - mpq sum_of_right_sides_of_explanation(const vector> & explanation) const { - mpq ret = numeric_traits::zero(); - for (auto & it : explanation) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; - } - return ret; - } - - bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - - if (var >= m_vars_to_ul_pairs.size()) { - // TBD: bounds on terms could also be used, caller may have to track these. - return false; - } - const ul_pair & ul = m_vars_to_ul_pairs[var]; - ci = ul.low_bound_witness(); - if (ci != static_cast(-1)) { - auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; - value = p.x; - is_strict = p.y.is_pos(); - return true; - } - else { - return false; - } - } - - bool has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - - if (var >= m_vars_to_ul_pairs.size()) { - // TBD: bounds on terms could also be used, caller may have to track these. - return false; - } - const ul_pair & ul = m_vars_to_ul_pairs[var]; - ci = ul.upper_bound_witness(); - if (ci != static_cast(-1)) { - auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; - value = p.x; - is_strict = p.y.is_neg(); - return true; - } - else { - return false; - } - } - - - void get_infeasibility_explanation(vector> & explanation) const { - explanation.clear(); - if (m_infeasible_column_index != -1) { - fill_explanation_from_infeasible_column(explanation); - return; - } - if (m_mpq_lar_core_solver.get_infeasible_sum_sign() == 0) { - return; - } - // the infeasibility sign - int inf_sign; - auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); - get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); - lean_assert(explanation_is_correct(explanation)); - } + void get_infeasibility_explanation(vector> & explanation) const; void get_infeasibility_explanation_for_inf_sign( vector> & explanation, const vector> & inf_row, - int inf_sign) const { - - for (auto & it : inf_row) { - mpq coeff = it.first; - unsigned j = it.second; - - int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; - const ul_pair & ul = m_vars_to_ul_pairs[j]; - - constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); - lean_assert(bound_constr_i < m_constraints.size()); - explanation.push_back(std::make_pair(coeff, bound_constr_i)); - } - } + int inf_sign) const; - void get_model(std::unordered_map & variable_values) const { - mpq delta = mpq(1, 2); // start from 0.5 to have less clashes - lean_assert(m_status == OPTIMAL); - unsigned i; - do { - - // different pairs have to produce different singleton values - std::unordered_set set_of_different_pairs; - std::unordered_set set_of_different_singles; - delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); - for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { - const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; - set_of_different_pairs.insert(rp); - mpq x = rp.x + delta * rp.y; - set_of_different_singles.insert(x); - if (set_of_different_pairs.size() - != set_of_different_singles.size()) { - delta /= mpq(2); - break; - } - - variable_values[i] = x; - } - } while (i != m_mpq_lar_core_solver.m_r_x.size()); - } + void get_model(std::unordered_map & variable_values) const; - std::string get_variable_name(var_index vi) const { - return get_column_name(vi); - } + std::string get_variable_name(var_index vi) const; // ********** print region start - void print_constraint(constraint_index ci, std::ostream & out) const { - if (ci >= m_constraints.size()) { - out << "constraint " << T_to_string(ci) << " is not found"; - out << std::endl; - return; - } + void print_constraint(constraint_index ci, std::ostream & out) const; - print_constraint(m_constraints[ci], out); - } + void print_constraints(std::ostream& out) const ; - void print_constraints(std::ostream& out) const { - for (auto c : m_constraints) { - print_constraint(c, out); - } - } + void print_terms(std::ostream& out) const ; - void print_terms(std::ostream& out) const { - for (auto it : m_terms) { - print_term(*it, out); - out << "\n"; - } - } + void print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const; - void print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const { - print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out); - mpq free_coeff = c->get_free_coeff_of_left_side(); - if (!is_zero(free_coeff)) - out << " + " << free_coeff; - - } + void print_term(lar_term const& term, std::ostream & out) const; - void print_term(lar_term const& term, std::ostream & out) const { - if (!numeric_traits::is_zero(term.m_v)) { - out << term.m_v << " + "; - } - print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); - } + mpq get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const; - mpq get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { - mpq ret = cns.get_free_coeff_of_left_side(); - for (auto & it : cns.get_left_side_coefficients()) { - var_index j = it.second; - auto vi = var_map.find(j); - lean_assert(vi != var_map.end()); - ret += it.first * vi->second; - } - return ret; - } + void print_constraint(const lar_base_constraint * c, std::ostream & out) const; - void print_constraint(const lar_base_constraint * c, std::ostream & out) const { - print_left_side_of_constraint(c, out); - out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; - } + void fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list); - void fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { - for (unsigned i = 0; i < sz; i++) { - var_index var = vars[i]; - if (var >= m_terms_start_index) { // handle the term - for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { - column_list.push_back(it.first); - } - } else { - column_list.push_back(var); - } - } - } + void random_update(unsigned sz, var_index const * vars); + void try_pivot_fixed_vars_from_basis(); + void pop(); + bool column_represents_row_in_tableau(unsigned j); + void make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j); + void remove_last_row_and_column_from_tableau(unsigned j); + void remove_last_column_from_tableau(unsigned j); - void random_update(unsigned sz, var_index const * vars) { - vector column_list; - fill_var_set_for_random_update(sz, vars, column_list); - random_updater ru(m_mpq_lar_core_solver, column_list); - ru.update(); - } - - - void try_pivot_fixed_vars_from_basis() { - m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); - } - - void pop() { - pop(1); - } - - - bool column_represents_row_in_tableau(unsigned j) { - return m_vars_to_ul_pairs()[j].m_i != static_cast(-1); - } - - void make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { - // i, j - is the indices of the bottom-right element of the tableau - lean_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;){ - auto & cc = last_column[k]; - if (cc.m_i == i) - return; - non_zero_column_cell_index = k; - } - - lean_assert(non_zero_column_cell_index != -1); - lean_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); - } - - void remove_last_row_and_column_from_tableau(unsigned j) { - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - auto & slv = m_mpq_lar_core_solver.m_r_solver; - unsigned i = A_r().row_count() - 1; //last row index - make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); - if (slv.m_basis_heading[j] < 0) { - slv.pivot_column_tableau(j, i); - } - - 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;) { - auto &rc = last_row[k]; - if (cost_is_nz) { - m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); - } - - A_r().remove_element(last_row, rc); - } - lean_assert(last_row.size() == 0); - lean_assert(A_r().m_columns[j].size() == 0); - A_r().m_rows.pop_back(); - A_r().m_columns.pop_back(); - slv.m_b.pop_back(); - } - - void remove_last_column_from_tableau(unsigned j) { - lean_assert(j == A_r().column_count() - 1); - // the last column has to be empty - lean_assert(A_r().m_columns[j].size() == 0); - A_r().m_columns.pop_back(); - } - - void remove_last_column_from_basis_tableau(unsigned j) { - auto& rslv = m_mpq_lar_core_solver.m_r_solver; - int i = rslv.m_basis_heading[j]; - if (i >= 0) { // j is a basic var - int last_pos = static_cast(rslv.m_basis.size()) - 1; - lean_assert(last_pos >= 0); - if (i != last_pos) { - unsigned j_at_last_pos = rslv.m_basis[last_pos]; - rslv.m_basis[i] = j_at_last_pos; - rslv.m_basis_heading[j_at_last_pos] = i; - } - rslv.m_basis.pop_back(); // remove j from the basis - } else { - int last_pos = static_cast(rslv.m_nbasis.size()) - 1; - lean_assert(last_pos >= 0); - i = - 1 - i; - if (i != last_pos) { - unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; - rslv.m_nbasis[i] = j_at_last_pos; - rslv.m_basis_heading[j_at_last_pos] = - i - 1; - } - rslv.m_nbasis.pop_back(); // remove j from the basis - } - rslv.m_basis_heading.pop_back(); - lean_assert(rslv.m_basis.size() == A_r().row_count()); - lean_assert(rslv.basis_heading_is_correct()); - } - - void remove_column_from_tableau(unsigned j) { - auto& rslv = m_mpq_lar_core_solver.m_r_solver; - lean_assert(j == A_r().column_count() - 1); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - if (column_represents_row_in_tableau(j)) { - remove_last_row_and_column_from_tableau(j); - if (rslv.m_basis_heading[j] < 0) - rslv.change_basis_unconditionally(j, rslv.m_basis[A_r().row_count()]); // A_r().row_count() is the index of the last row in the basis still - } - else { - remove_last_column_from_tableau(j); - } - rslv.m_x.pop_back(); - rslv.m_d.pop_back(); - rslv.m_costs.pop_back(); - - remove_last_column_from_basis_tableau(j); - lean_assert(m_mpq_lar_core_solver.r_basis_is_OK()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - } - - - void pop_tableau() { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); - // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). - // At this moment m_column_names is already popped - for (unsigned j = A_r().column_count(); j-- > m_columns_to_ext_vars_or_term_indices.size();) - remove_column_from_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); - } - - - - - void clean_inf_set_of_r_solver_after_pop() { - vector became_feas; - clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); - std::unordered_set basic_columns_with_changed_cost; - auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; - for (auto j: inf_index_copy) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - continue; - } - // some basic columns might become non-basic - these columns need to be made feasible - numeric_pair delta; - if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) - change_basic_x_by_delta_on_column(j, delta); - became_feas.push_back(j); - } - - for (unsigned j : became_feas) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); - m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; - m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); - m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - } - became_feas.clear(); - for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); - if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) - became_feas.push_back(j); - } - for (unsigned j : became_feas) - m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - - - if (use_tableau_costs()) { - for (unsigned j : became_feas) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - for (unsigned j : basic_columns_with_changed_cost) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } - } - - - void shrink_explanation_to_minimum(vector> & explanation) const { - // implementing quickXplain - quick_xplain::run(explanation, *this); - lean_assert(this->explanation_is_correct(explanation)); - } - - + void remove_last_column_from_basis_tableau(unsigned j); + void remove_column_from_tableau(unsigned j); + void pop_tableau(); + void clean_inf_set_of_r_solver_after_pop(); + void shrink_explanation_to_minimum(vector> & explanation) const; }; } diff --git a/src/util/lp/lar_solver_instances.cpp b/src/util/lp/lar_solver_instances.cpp new file mode 100644 index 000000000..ccde7e574 --- /dev/null +++ b/src/util/lp/lar_solver_instances.cpp @@ -0,0 +1,17 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#include "util/lp/lar_solver.cpp" +#include "util/lp/init_lar_solver.cpp" + + + + +template void lean::lar_solver::copy_from_mpq_matrix(class lean::static_matrix &); + + + + + From 7b433bee2b4774cae125ce09d256f05c84732352 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 16 May 2017 17:36:32 -0700 Subject: [PATCH 0119/1283] track which var is an integer Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 2 +- src/util/lp/init_lar_solver.cpp | 15 ++++++++------- src/util/lp/lar_solver.cpp | 8 ++++++-- src/util/lp/lar_solver.h | 13 +++++++++++-- src/util/lp/quick_xplain.cpp | 4 ++-- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 05aa33d13..0072aea7d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -487,7 +487,7 @@ namespace smt { result = m_theory_var2var_index[v]; } if (result == UINT_MAX) { - result = m_solver->add_var(v); + result = m_solver->add_var(v, false); m_theory_var2var_index.setx(v, result, UINT_MAX); m_var_index2theory_var.setx(result, v, UINT_MAX); m_var_trail.push_back(v); diff --git a/src/util/lp/init_lar_solver.cpp b/src/util/lp/init_lar_solver.cpp index 97ebbdd5a..1f004198d 100644 --- a/src/util/lp/init_lar_solver.cpp +++ b/src/util/lp/init_lar_solver.cpp @@ -10,15 +10,15 @@ bool lar_solver::strategy_is_undecided() const { return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; } -var_index lar_solver::add_var(unsigned ext_j) { +var_index lar_solver::add_var(unsigned ext_j, bool is_integer) { var_index i; lean_assert (ext_j < m_terms_start_index); if (ext_j >= m_terms_start_index) throw 0; // todo : what is the right way to exit? - - if (try_get_val(m_ext_vars_to_columns, ext_j, i)) { - return i; + auto it = m_ext_vars_to_columns.find(ext_j); + if (it != m_ext_vars_to_columns.end()) { + return it->second.ext_j(); } lean_assert(m_vars_to_ul_pairs.size() == A_r().column_count()); i = A_r().column_count(); @@ -31,7 +31,7 @@ var_index lar_solver::add_var(unsigned ext_j) { void lar_solver::register_new_ext_var_index(unsigned ext_v) { lean_assert(!contains(m_ext_vars_to_columns, ext_v)); unsigned j = static_cast(m_ext_vars_to_columns.size()); - m_ext_vars_to_columns[ext_v] = j; + m_ext_vars_to_columns.insert(std::make_pair(ext_v, ext_var_info(j))); lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j); m_columns_to_ext_vars_or_term_indices.push_back(ext_v); } @@ -190,8 +190,9 @@ void lar_solver::update_column_type_and_bound(var_index j, lconstraint_kind kind void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { lean_assert(is_term(j)); unsigned adjusted_term_index = adjust_term_index(j); - unsigned term_j; - if (try_get_val(m_ext_vars_to_columns, j, term_j)) { + auto it = m_ext_vars_to_columns.find(j); + if (it != m_ext_vars_to_columns.end()) { + unsigned term_j = it->second.ext_j(); mpq rs = right_side - m_orig_terms[adjusted_term_index]->m_v; m_constraints.push_back(new lar_term_constraint(m_orig_terms[adjusted_term_index], kind, right_side)); update_column_type_and_bound(term_j, kind, rs, ci); diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index ba0f74201..594abae46 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -224,14 +224,18 @@ const lar_base_constraint& lar_solver::get_constraint(unsigned ci) const { int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; unsigned m_j = ib.m_j; if (is_term(m_j)) { - m_j = m_ext_vars_to_columns[m_j]; + auto it = m_ext_vars_to_columns.find(m_j); + lean_assert(it != m_ext_vars_to_columns.end()); + m_j = it->second.ext_j(); } for (auto const& r : A_r().m_rows[i]) { unsigned j = r.m_j; mpq const& a = r.get_val(); if (j == m_j) continue; if (is_term(j)) { - j = m_ext_vars_to_columns[j]; + auto it = m_ext_vars_to_columns.find(j); + lean_assert(it != m_ext_vars_to_columns.end()); + j = it->second.ext_j(); } int a_sign = is_pos(a)? 1: -1; int sign = j_sign * a_sign; diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index f752d6734..2d2016dbe 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -35,11 +35,20 @@ namespace lean { class lar_solver : public column_namer { + class ext_var_info { + unsigned m_ext_j; // the external index + bool m_is_integer; + public: + ext_var_info(unsigned j): ext_var_info(j, false) {} + ext_var_info(unsigned j , bool is_int) : m_ext_j(j), m_is_integer(is_int) {} + unsigned ext_j() const { return m_ext_j;} + bool is_integer() const {return m_is_integer;} + }; //////////////////// fields ////////////////////////// lp_settings m_settings; stacked_value m_status; stacked_value m_simplex_strategy; - std::unordered_map m_ext_vars_to_columns; + std::unordered_map m_ext_vars_to_columns; vector m_columns_to_ext_vars_or_term_indices; stacked_vector m_vars_to_ul_pairs; vector m_constraints; @@ -74,7 +83,7 @@ public: // init region bool strategy_is_undecided() const; - var_index add_var(unsigned ext_j); + var_index add_var(unsigned ext_j, bool is_integer); void register_new_ext_var_index(unsigned ext_v); diff --git a/src/util/lp/quick_xplain.cpp b/src/util/lp/quick_xplain.cpp index a4b6fb0e6..df409240e 100644 --- a/src/util/lp/quick_xplain.cpp +++ b/src/util/lp/quick_xplain.cpp @@ -20,7 +20,7 @@ void quick_xplain::copy_constraint_and_add_constraint_vars(const lar_constraint& vector < std::pair> ls; for (auto & p : lar_c.get_left_side_coefficients()) { unsigned j = p.second; - unsigned lj = m_qsol.add_var(j); + unsigned lj = m_qsol.add_var(j, false); ls.push_back(std::make_pair(p.first, lj)); } m_constraints_in_local_vars.push_back(lar_constraint(ls, lar_c.m_kind, lar_c.m_right_side)); @@ -94,7 +94,7 @@ bool quick_xplain::is_feasible(const vector & x, unsigned k) const { vector < std::pair> ls; const lar_constraint & c = m_constraints_in_local_vars[i]; for (auto & p : c.get_left_side_coefficients()) { - unsigned lj = l.add_var(p.second); + unsigned lj = l.add_var(p.second, false); ls.push_back(std::make_pair(p.first, lj)); } l.add_constraint(ls, c.m_kind, c.m_right_side); From d5e06303ef21630ab3b6a69c0d1928a9bb8e055d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 16 May 2017 17:54:09 -0700 Subject: [PATCH 0120/1283] add queries for integrality of vars Signed-off-by: Lev Nachmanson --- src/util/lp/init_lar_solver.cpp | 1 + src/util/lp/lar_solver.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/util/lp/init_lar_solver.cpp b/src/util/lp/init_lar_solver.cpp index 1f004198d..a84d791d5 100644 --- a/src/util/lp/init_lar_solver.cpp +++ b/src/util/lp/init_lar_solver.cpp @@ -25,6 +25,7 @@ var_index lar_solver::add_var(unsigned ext_j, bool is_integer) { m_vars_to_ul_pairs.push_back (ul_pair(static_cast(-1))); add_non_basic_var_to_core_fields(ext_j); lean_assert(sizes_are_correct()); + lean_assert(!column_is_integer(i)); return i; } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 2d2016dbe..78795e0e4 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -396,5 +396,11 @@ public: void pop_tableau(); void clean_inf_set_of_r_solver_after_pop(); void shrink_explanation_to_minimum(vector> & explanation) const; + inline + bool column_is_integer(unsigned j) const { + unsigned ext_var = m_columns_to_ext_vars_or_term_indices[j]; + return m_ext_vars_to_columns.find(ext_var)->second.is_integer(); + } + inline bool column_is_real(unsigned j) const { return !column_is_integer(j); } }; } From 9a58eb63cb4fa8a32f8e393e83f9693b2dc1d86e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 17 May 2017 11:01:04 -0700 Subject: [PATCH 0121/1283] resurrect lp_tst in its own director lp Signed-off-by: Lev Nachmanson --- contrib/cmake/src/test/CMakeLists.txt | 3 +- contrib/cmake/src/test/lp/CMakeLists.txt | 6 ++++ src/test/{ => lp}/argument_parser.h | 0 src/test/{ => lp}/lp.cpp | 44 ++++++++++++------------ src/test/{ => lp}/smt_reader.h | 2 +- src/test/{ => lp}/test_file_reader.h | 0 src/util/lp/init_lar_solver.cpp | 4 ++- src/util/lp/mps_reader.h | 10 +++--- 8 files changed, 39 insertions(+), 30 deletions(-) create mode 100644 contrib/cmake/src/test/lp/CMakeLists.txt rename src/test/{ => lp}/argument_parser.h (100%) rename src/test/{ => lp}/lp.cpp (99%) rename src/test/{ => lp}/smt_reader.h (99%) rename src/test/{ => lp}/test_file_reader.h (100%) diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index b395c09e6..f92525069 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(fuzzing) +add_subdirectory(lp) ################################################################################ # z3-test executable ################################################################################ @@ -117,7 +118,7 @@ add_executable(test-z3 upolynomial.cpp var_subst.cpp vector.cpp - lp.cpp + lp/lp.cpp ${z3_test_extra_object_files} ) z3_add_install_tactic_rule(${z3_test_deps}) diff --git a/contrib/cmake/src/test/lp/CMakeLists.txt b/contrib/cmake/src/test/lp/CMakeLists.txt new file mode 100644 index 000000000..99f8747b1 --- /dev/null +++ b/contrib/cmake/src/test/lp/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(lp_tst lp_main.cpp lp.cpp $ $) +target_compile_definitions(lp_tst PRIVATE ${Z3_COMPONENT_CXX_DEFINES}) +target_compile_options(lp_tst PRIVATE ${Z3_COMPONENT_CXX_FLAGS}) +target_include_directories(lp_tst PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS}) +target_link_libraries(lp_tst PRIVATE ${Z3_DEPENDENT_LIBS}) +z3_append_linker_flag_list_to_target(lp_tst ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) diff --git a/src/test/argument_parser.h b/src/test/lp/argument_parser.h similarity index 100% rename from src/test/argument_parser.h rename to src/test/lp/argument_parser.h diff --git a/src/test/lp.cpp b/src/test/lp/lp.cpp similarity index 99% rename from src/test/lp.cpp rename to src/test/lp/lp.cpp index 235dab960..1acf4ba2a 100644 --- a/src/test/lp.cpp +++ b/src/test/lp/lp.cpp @@ -2691,8 +2691,8 @@ void test_term() { lar_solver solver; unsigned _x = 0; unsigned _y = 1; - var_index x = solver.add_var(_x); - var_index y = solver.add_var(_y); + var_index x = solver.add_var(_x, false); + var_index y = solver.add_var(_y, false); vector> term_ls; term_ls.push_back(std::pair((int)1, x)); @@ -2719,8 +2719,8 @@ void test_term() { void test_evidence_for_total_inf_simple(argument_parser & args_parser) { lar_solver solver; - var_index x = solver.add_var(0); - var_index y = solver.add_var(1); + var_index x = solver.add_var(0, false); + var_index y = solver.add_var(1, false); solver.add_var_bound(x, LE, -mpq(1)); solver.add_var_bound(y, GE, mpq(0)); vector> ls; @@ -2754,9 +2754,9 @@ If b becomes basic variable, then it is likely the old solver ends up with a row return true; }; lar_solver ls; - unsigned a = ls.add_var(0); - unsigned b = ls.add_var(1); - unsigned c = ls.add_var(2); + unsigned a = ls.add_var(0, false); + unsigned b = ls.add_var(1, false); + unsigned c = ls.add_var(2, false); vector> coeffs; coeffs.push_back(std::pair(1, a)); coeffs.push_back(std::pair(-1, c)); @@ -2819,8 +2819,8 @@ If x9 becomes basic variable, then it is likely the old solver ends up with a ro } void test_bound_propagation_one_row() { lar_solver ls; - unsigned x0 = ls.add_var(0); - unsigned x1 = ls.add_var(1); + unsigned x0 = ls.add_var(0, false); + unsigned x1 = ls.add_var(1, false); vector> c; c.push_back(std::pair(1, x0)); c.push_back(std::pair(-1, x1)); @@ -2833,8 +2833,8 @@ void test_bound_propagation_one_row() { } void test_bound_propagation_one_row_with_bounded_vars() { lar_solver ls; - unsigned x0 = ls.add_var(0); - unsigned x1 = ls.add_var(1); + unsigned x0 = ls.add_var(0, false); + unsigned x1 = ls.add_var(1, false); vector> c; c.push_back(std::pair(1, x0)); c.push_back(std::pair(-1, x1)); @@ -2849,8 +2849,8 @@ void test_bound_propagation_one_row_with_bounded_vars() { } void test_bound_propagation_one_row_mixed() { lar_solver ls; - unsigned x0 = ls.add_var(0); - unsigned x1 = ls.add_var(1); + unsigned x0 = ls.add_var(0, false); + unsigned x1 = ls.add_var(1, false); vector> c; c.push_back(std::pair(1, x0)); c.push_back(std::pair(-1, x1)); @@ -2864,9 +2864,9 @@ void test_bound_propagation_one_row_mixed() { void test_bound_propagation_two_rows() { lar_solver ls; - unsigned x = ls.add_var(0); - unsigned y = ls.add_var(1); - unsigned z = ls.add_var(2); + unsigned x = ls.add_var(0, false); + unsigned y = ls.add_var(1, false); + unsigned z = ls.add_var(2, false); vector> c; c.push_back(std::pair(1, x)); c.push_back(std::pair(2, y)); @@ -2888,9 +2888,9 @@ void test_bound_propagation_two_rows() { void test_total_case_u() { std::cout << "test_total_case_u\n"; lar_solver ls; - unsigned x = ls.add_var(0); - unsigned y = ls.add_var(1); - unsigned z = ls.add_var(2); + unsigned x = ls.add_var(0, false); + unsigned y = ls.add_var(1, false); + unsigned z = ls.add_var(2, false); vector> c; c.push_back(std::pair(1, x)); c.push_back(std::pair(2, y)); @@ -2914,9 +2914,9 @@ bool contains_j_kind(unsigned j, lconstraint_kind kind, const mpq & rs, const ve void test_total_case_l(){ std::cout << "test_total_case_l\n"; lar_solver ls; - unsigned x = ls.add_var(0); - unsigned y = ls.add_var(1); - unsigned z = ls.add_var(2); + unsigned x = ls.add_var(0, false); + unsigned y = ls.add_var(1, false); + unsigned z = ls.add_var(2, false); vector> c; c.push_back(std::pair(1, x)); c.push_back(std::pair(2, y)); diff --git a/src/test/smt_reader.h b/src/test/lp/smt_reader.h similarity index 99% rename from src/test/smt_reader.h rename to src/test/lp/smt_reader.h index 38e3f4157..dd38c6bcd 100644 --- a/src/test/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -376,7 +376,7 @@ namespace lean { void add_constraint_to_solver(lar_solver * solver, formula_constraint & fc) { vector> ls; for (auto & it : fc.m_coeffs) { - ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second)))); + ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second), false))); } solver->add_constraint(ls, fc.m_kind, fc.m_right_side); } diff --git a/src/test/test_file_reader.h b/src/test/lp/test_file_reader.h similarity index 100% rename from src/test/test_file_reader.h rename to src/test/lp/test_file_reader.h diff --git a/src/util/lp/init_lar_solver.cpp b/src/util/lp/init_lar_solver.cpp index a84d791d5..5efa24a48 100644 --- a/src/util/lp/init_lar_solver.cpp +++ b/src/util/lp/init_lar_solver.cpp @@ -2,8 +2,10 @@ Copyright (c) 2017 Microsoft Corporation Author: Lev Nachmanson */ -#include "util/lp/lar_solver.h" +// this file represents the intiialization functionality of lar_solver + +#include "util/lp/lar_solver.h" namespace lean { bool lar_solver::strategy_is_undecided() const { diff --git a/src/util/lp/mps_reader.h b/src/util/lp/mps_reader.h index 4c08ec8e6..6b80c2257 100644 --- a/src/util/lp/mps_reader.h +++ b/src/util/lp/mps_reader.h @@ -810,7 +810,7 @@ public: auto kind = get_lar_relation_from_row(row->m_type); vector> ls; for (auto s : row->m_row_columns) { - var_index i = solver->add_var(get_var_index(s.first)); + var_index i = solver->add_var(get_var_index(s.first), false); ls.push_back(std::make_pair(s.second, i)); } solver->add_constraint(ls, kind, row->m_right_side); @@ -828,20 +828,20 @@ public: void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) { vector> ls; - var_index i = solver->add_var(col->m_index); + var_index i = solver->add_var(col->m_index, false); ls.push_back(std::make_pair(numeric_traits::one(), i)); solver->add_constraint(ls, GE, b->m_low); } void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) { - var_index i = solver->add_var(col->m_index); + var_index i = solver->add_var(col->m_index, false); vector> ls; ls.push_back(std::make_pair(numeric_traits::one(), i)); solver->add_constraint(ls, LE, b->m_upper); } void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) { - var_index i = solver->add_var(col->m_index); + var_index i = solver->add_var(col->m_index, false); vector> ls; ls.push_back(std::make_pair(numeric_traits::one(), i)); solver->add_constraint(ls, EQ, b->m_fixed_value); @@ -850,7 +850,7 @@ public: void fill_lar_solver_on_columns(lar_solver * solver) { for (auto s : m_columns) { mps_reader::column * col = s.second; - solver->add_var(col->m_index); + solver->add_var(col->m_index, false); auto b = col->m_bound; if (b == nullptr) return; From d28b8b33b40da83f8f3e068cad80a04ccaf960fe Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 17 May 2017 11:04:35 -0700 Subject: [PATCH 0122/1283] add file Signed-off-by: Lev Nachmanson --- src/test/lp/lp_main.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/lp/lp_main.cpp diff --git a/src/test/lp/lp_main.cpp b/src/test/lp/lp_main.cpp new file mode 100644 index 000000000..a301f38c6 --- /dev/null +++ b/src/test/lp/lp_main.cpp @@ -0,0 +1,14 @@ +void gparams_register_modules(){} +void mem_initialize() {} +void mem_finalize() {} +#include "util/rational.h" +namespace lean { +void test_lp_local(int argc, char**argv); +} +int main(int argn, char**argv){ + rational::initialize(); + lean::test_lp_local(argn, argv); + rational::finalize(); + return 0; +} + From e9d9354885dad474066f6ba4bee4614f68ef6da1 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 17 May 2017 19:00:33 -0700 Subject: [PATCH 0123/1283] add_constraint has got a body Signed-off-by: Lev Nachmanson --- src/util/lp/init_lar_solver.cpp | 31 +- src/util/lp/lar_solver.cpp | 2671 +++++++++++++++---------------- src/util/lp/lar_solver.h | 7 +- 3 files changed, 1359 insertions(+), 1350 deletions(-) diff --git a/src/util/lp/init_lar_solver.cpp b/src/util/lp/init_lar_solver.cpp index 5efa24a48..58486e6ba 100644 --- a/src/util/lp/init_lar_solver.cpp +++ b/src/util/lp/init_lar_solver.cpp @@ -95,7 +95,6 @@ void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) { var_index lar_solver::add_term_undecided(const vector> & coeffs, const mpq &m_v) { m_terms.push_back(new lar_term(coeffs, m_v)); - m_orig_terms.push_back(new lar_term(coeffs, m_v)); return m_terms_start_index + m_terms.size() - 1; } @@ -106,11 +105,10 @@ var_index lar_solver::add_term(const vector> & coeffs, return add_term_undecided(coeffs, m_v); m_terms.push_back(new lar_term(coeffs, m_v)); - m_orig_terms.push_back(new lar_term(coeffs, m_v)); unsigned adjusted_term_index = m_terms.size() - 1; var_index ret = m_terms_start_index + adjusted_term_index; if (use_tableau() && !coeffs.empty()) { - add_row_for_term(m_orig_terms.back(), ret); + add_row_for_term(m_terms.back(), ret); if (m_settings.bound_propagation()) m_rows_with_changed_bounds.insert(A_r().row_count() - 1); } @@ -196,15 +194,36 @@ void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_k auto it = m_ext_vars_to_columns.find(j); if (it != m_ext_vars_to_columns.end()) { unsigned term_j = it->second.ext_j(); - mpq rs = right_side - m_orig_terms[adjusted_term_index]->m_v; - m_constraints.push_back(new lar_term_constraint(m_orig_terms[adjusted_term_index], kind, right_side)); + mpq rs = right_side - m_terms[adjusted_term_index]->m_v; + m_constraints.push_back(new lar_term_constraint(m_terms[adjusted_term_index], kind, right_side)); update_column_type_and_bound(term_j, kind, rs, ci); } else { - add_constraint_from_term_and_create_new_column_row(j, m_orig_terms[adjusted_term_index], kind, right_side); + add_constraint_from_term_and_create_new_column_row(j, m_terms[adjusted_term_index], kind, right_side); } } +constraint_index lar_solver::add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { + this->print_linear_combination_of_column_indices(left_side_with_terms, std::cout); + std::cout << std::endl; + vector> left_side; + mpq rs = - right_side_parm; + std::cout << "before rs = " << rs << std::endl; + substitute_terms_in_linear_expression(left_side_with_terms, left_side, rs); + std::cout << "after rs = " << rs << std::endl; + + this->print_linear_combination_of_column_indices(left_side, std::cout); + std::cout << std::endl; + + unsigned term_index = add_term(left_side, zero_of_type()); + constraint_index ci = m_constraints.size(); + add_var_bound_on_constraint_for_term(term_index, kind_par, -rs, ci); + std::cout << "constraint = "; + print_constraint(ci, std::cout); + std::cout << std::endl; + + return ci; +} void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, lconstraint_kind kind, const mpq & right_side) { diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 594abae46..78b71ecfd 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -13,1388 +13,1377 @@ const lar_base_constraint& lar_solver::get_constraint(unsigned ci) const { return *(m_constraints[ci]); } - ////////////////// methods //////////////////////////////// - static_matrix> & lar_solver::A_r() { return m_mpq_lar_core_solver.m_r_A;} - static_matrix> const & lar_solver::A_r() const { return m_mpq_lar_core_solver.m_r_A;} - static_matrix & lar_solver::A_d() { return m_mpq_lar_core_solver.m_d_A;} - static_matrix const & lar_solver::A_d() const { return m_mpq_lar_core_solver.m_d_A;} +////////////////// methods //////////////////////////////// +static_matrix> & lar_solver::A_r() { return m_mpq_lar_core_solver.m_r_A;} +static_matrix> const & lar_solver::A_r() const { return m_mpq_lar_core_solver.m_r_A;} +static_matrix & lar_solver::A_d() { return m_mpq_lar_core_solver.m_d_A;} +static_matrix const & lar_solver::A_d() const { return m_mpq_lar_core_solver.m_d_A;} - lp_settings & lar_solver::settings() { return m_settings;} +lp_settings & lar_solver::settings() { return m_settings;} - lp_settings const & lar_solver::settings() const { return m_settings;} +lp_settings const & lar_solver::settings() const { return m_settings;} - void clear() {lean_assert(false); // not implemented - } - - - lar_solver::lar_solver() : m_status(OPTIMAL), - m_infeasible_column_index(-1), - m_terms_start_index(1000000), - m_column_type_function ([this] (unsigned j) {return m_mpq_lar_core_solver.m_column_types()[j];}), - m_mpq_lar_core_solver(m_settings, *this) - {} - - void lar_solver::set_propagate_bounds_on_pivoted_rows_mode(bool v) { - m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; - } - - lar_solver::~lar_solver(){ - for (auto c : m_constraints) - delete c; - for (auto t : m_terms) - delete t; - for (auto t : m_orig_terms) - delete t; - } - - numeric_pair const& lar_solver::get_value(var_index vi) const { return m_mpq_lar_core_solver.m_r_x[vi]; } - - bool lar_solver::is_term(var_index j) const { - return j >= m_terms_start_index && j - m_terms_start_index < m_terms.size(); - } - - unsigned lar_solver::adjust_term_index(unsigned j) const { - lean_assert(is_term(j)); - return j - m_terms_start_index; - } - - - bool lar_solver::use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } - - bool lar_solver::sizes_are_correct() const { - lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); - return true; - } - - - void lar_solver::print_implied_bound(const implied_bound& be, std::ostream & out) const { - out << "implied bound\n"; - unsigned v = be.m_j; - if (is_term(v)) { - out << "it is a term number " << be.m_j << std::endl; - print_term(*m_orig_terms[be.m_j - m_terms_start_index], out); - } - else { - out << get_column_name(v); - } - out << " " << lconstraint_kind_string(be.kind()) << " " << be.m_bound << std::endl; - // for (auto & p : be.m_explanation) { - // out << p.first << " : "; - // print_constraint(p.second, out); - // } - - // m_mpq_lar_core_solver.m_r_solver.print_column_info(be.m_j< m_terms_start_index? be.m_j : adjust_term_index(be.m_j), out); - out << "end of implied bound" << std::endl; - } - - bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { - std::unordered_map coeff_map; - auto rs_of_evidence = zero_of_type(); - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto & it : explanation) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - const auto & constr = *m_constraints[con_ind]; - lconstraint_kind kind = coeff.is_pos() ? constr.m_kind : flip_kind(constr.m_kind); - register_in_map(coeff_map, constr, coeff); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) n_of_G++; - else if (kind == LE || kind == LT) n_of_L++; - rs_of_evidence += coeff*constr.m_right_side; - } - lean_assert(n_of_G == 0 || n_of_L == 0); - lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - kind = static_cast((static_cast(kind) / 2)); - - if (!is_term(be.m_j)) { - if (coeff_map.size() != 1) - return false; - auto it = coeff_map.find(be.m_j); - if (it == coeff_map.end()) return false; - mpq ratio = it->second; - if (ratio < zero_of_type()) { - kind = static_cast(-kind); - } - rs_of_evidence /= ratio; - } else { - const lar_term * t = m_orig_terms[adjust_term_index(be.m_j)]; - const auto first_coeff = *t->m_coeffs.begin(); - unsigned j = first_coeff.first; - auto it = coeff_map.find(j); - if (it == coeff_map.end()) - return false; - mpq ratio = it->second / first_coeff.second; - for (auto & p : t->m_coeffs) { - it = coeff_map.find(p.first); - if (it == coeff_map.end()) - return false; - if (p.second * ratio != it->second) - return false; - } - if (ratio < zero_of_type()) { - kind = static_cast(-kind); - } - rs_of_evidence /= ratio; - rs_of_evidence += t->m_v * ratio; - } - - return kind == be.kind() && rs_of_evidence == be.m_bound; - } - - - void lar_solver::analyze_new_bounds_on_row( - unsigned row_index, - bound_propagator & bp) { - lean_assert(!use_tableau()); - iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); - - bound_analyzer_on_row ra_pos(it, - zero_of_type>(), - row_index, - bp - ); - ra_pos.analyze(); - } - - 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) - return; - iterator_on_row it(A_r().m_rows[row_index]); - lean_assert(use_tableau()); - bound_analyzer_on_row::analyze_row(it, - zero_of_type>(), - row_index, - bp - ); - } - - - void lar_solver::substitute_basis_var_in_terms_for_row(unsigned i) { - // todo : create a map from term basic vars to the rows where they are used - unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; - for (unsigned k = 0; k < m_terms.size(); k++) { - if (term_is_used_as_row(k)) - continue; - if (!m_terms[k]->contains(basis_j)) - continue; - m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); - } - } - - void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { - if(use_tableau()) { - analyze_new_bounds_on_row_tableau(i, bp); - } else { - m_mpq_lar_core_solver.calculate_pivot_row(i); - substitute_basis_var_in_terms_for_row(i); - analyze_new_bounds_on_row(i, bp); - } - } - - - linear_combination_iterator * lar_solver::create_new_iter_from_term(unsigned term_index) const { - lean_assert(false); // not implemented - return nullptr; - // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); - } - - unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const { - unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; - return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; - } - - void lar_solver::propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { - lean_assert(false); // not implemented - } - - - void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp) { - unsigned i = ib.m_row_or_term_index; - int bound_sign = ib.m_is_low_bound? 1: -1; - int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; - unsigned m_j = ib.m_j; - if (is_term(m_j)) { - auto it = m_ext_vars_to_columns.find(m_j); - lean_assert(it != m_ext_vars_to_columns.end()); - m_j = it->second.ext_j(); - } - for (auto const& r : A_r().m_rows[i]) { - unsigned j = r.m_j; - mpq const& a = r.get_val(); - if (j == m_j) continue; - if (is_term(j)) { - auto it = m_ext_vars_to_columns.find(j); - lean_assert(it != m_ext_vars_to_columns.end()); - j = it->second.ext_j(); - } - int a_sign = is_pos(a)? 1: -1; - int sign = j_sign * a_sign; - const ul_pair & ul = m_vars_to_ul_pairs[j]; - auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); - lean_assert(is_valid(witness)); - bp.consume(a, witness); - } - // lean_assert(implied_bound_is_correctly_explained(ib, explanation)); - } - - - bool lar_solver::term_is_used_as_row(unsigned term) const { - lean_assert(is_term(term)); - return contains(m_ext_vars_to_columns, term); - } - - void lar_solver::propagate_bounds_on_terms(bound_propagator & bp) { - for (unsigned i = 0; i < m_terms.size(); i++) { - if (term_is_used_as_row(i + m_terms_start_index)) - continue; // this term is used a left side of a constraint, - // it was processed as a touched row if needed - propagate_bounds_on_a_term(*m_terms[i], bp, i); - } - } - - - // goes over touched rows and tries to induce bounds - void lar_solver::propagate_bounds_for_touched_rows(bound_propagator & bp) { - if (!use_tableau()) - return; // ! todo : enable bound propagaion here. The current bug is that after the pop - // the changed terms become incorrect! - - for (unsigned i : m_rows_with_changed_bounds.m_index) { - calculate_implied_bounds_for_row(i, bp); - } - m_rows_with_changed_bounds.clear(); - if (!use_tableau()) { - propagate_bounds_on_terms(bp); - } - } - - lp_status lar_solver::get_status() const { return m_status;} - - void lar_solver::set_status(lp_status s) {m_status = s;} - - lp_status lar_solver::find_feasible_solution() { - if (strategy_is_undecided()) - decide_on_strategy_and_adjust_initial_state(); - - m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; - return solve(); - } - - lp_status lar_solver::solve() { - if (m_status == INFEASIBLE) { - return m_status; - } - solve_with_core_solver(); - if (m_status != INFEASIBLE) { - if (m_settings.bound_propagation()) - detect_rows_with_changed_bounds(); - } - - m_columns_with_changed_bound.clear(); - return m_status; - } - - void lar_solver::fill_explanation_from_infeasible_column(vector> & evidence) const{ - - // this is the case when the lower bound is in conflict with the upper one - const ul_pair & ul = m_vars_to_ul_pairs[m_infeasible_column_index]; - evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); - evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); - } - - - unsigned lar_solver::get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } - // see http://research.microsoft.com/projects/z3/smt07.pdf - // This method searches for a feasible solution with as many different values of variables, reverenced in vars, as it can find - // Attention, after a call to this method the non-basic variables don't necesserarly stick to their bounds anymore - vector lar_solver::get_list_of_all_var_indices() const { - vector ret; - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) - ret.push_back(j); - return ret; - } - void lar_solver::push() { - m_simplex_strategy = m_settings.simplex_strategy(); - m_simplex_strategy.push(); - m_status.push(); - m_vars_to_ul_pairs.push(); - m_infeasible_column_index.push(); - m_mpq_lar_core_solver.push(); - m_term_count = m_terms.size(); - m_term_count.push(); - m_constraint_count = m_constraints.size(); - m_constraint_count.push(); - } - - void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { - vector to_remove; - for (unsigned j: set.m_index) - if (j >= n) - to_remove.push_back(j); - for (unsigned j : to_remove) - set.erase(j); - } - - void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { - clean_large_elements_after_pop(n, set); - set.resize(n); - } - - - void lar_solver::pop(unsigned k) { - int n_was = static_cast(m_ext_vars_to_columns.size()); - m_status.pop(k); - m_infeasible_column_index.pop(k); - unsigned n = m_vars_to_ul_pairs.peek_size(k); - for (unsigned j = n_was; j-- > n;) - m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); - m_columns_to_ext_vars_or_term_indices.resize(n); - if (m_settings.use_tableau()) { - pop_tableau(); - } - m_vars_to_ul_pairs.pop(k); - - m_mpq_lar_core_solver.pop(k); - clean_large_elements_after_pop(n, m_columns_with_changed_bound); - unsigned m = A_r().row_count(); - clean_large_elements_after_pop(m, m_rows_with_changed_bounds); - clean_inf_set_of_r_solver_after_pop(); - lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || - (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - - - lean_assert(ax_is_correct()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); - m_constraint_count.pop(k); - for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) - delete m_constraints[i]; - - m_constraints.resize(m_constraint_count); - m_term_count.pop(k); - for (unsigned i = m_term_count; i < m_terms.size(); i++) { - delete m_terms[i]; - delete m_orig_terms[i]; - } - m_terms.resize(m_term_count); - m_orig_terms.resize(m_term_count); - m_simplex_strategy.pop(k); - m_settings.simplex_strategy() = m_simplex_strategy; - lean_assert(sizes_are_correct()); - lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } - - vector lar_solver::get_all_constraint_indices() const { - vector ret; - constraint_index i = 0; - while ( i < m_constraints.size()) - ret.push_back(i++); - return ret; - } - - bool lar_solver::maximize_term_on_tableau(const vector> & term, - impq &term_max) { - if (settings().simplex_strategy() == simplex_strategy_enum::undecided) - decide_on_strategy_and_adjust_initial_state(); - - m_mpq_lar_core_solver.solve(); - if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED) - return false; - - term_max = 0; - for (auto & p : term) - term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second]; - - return true; - } - - bool lar_solver::costs_are_zeros_for_r_solver() const { - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); - } - return true; - } - bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const { - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); - } - return true; - } - - void lar_solver::set_costs_to_zero(const vector> & term) { - auto & rslv = m_mpq_lar_core_solver.m_r_solver; - auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now - lean_assert(jset.m_index.size()==0); - - for (auto & p : term) { - unsigned j = p.second; - rslv.m_costs[j] = zero_of_type(); - int i = rslv.m_basis_heading[j]; - if (i < 0) - jset.insert(j); - else { - for (auto & rc : A_r().m_rows[i]) - jset.insert(rc.m_j); - } - } - - for (unsigned j : jset.m_index) - rslv.m_d[j] = zero_of_type(); - - jset.clear(); - - lean_assert(reduced_costs_are_zeroes_for_r_solver()); - lean_assert(costs_are_zeros_for_r_solver()); - } - - void lar_solver::prepare_costs_for_r_solver(const vector> & term) { - - auto & rslv = m_mpq_lar_core_solver.m_r_solver; - rslv.m_using_infeas_costs = false; - lean_assert(costs_are_zeros_for_r_solver()); - lean_assert(reduced_costs_are_zeroes_for_r_solver()); - rslv.m_costs.resize(A_r().column_count(), zero_of_type()); - for (auto & p : term) { - unsigned j = p.second; - rslv.m_costs[j] = p.first; - if (rslv.m_basis_heading[j] < 0) - rslv.m_d[j] += p.first; - else - rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); - } - lean_assert(rslv.reduced_costs_are_correct_tableau()); - } - - bool lar_solver::maximize_term_on_corrected_r_solver(const vector> & term, - impq &term_max) { - settings().backup_costs = false; - switch (settings().simplex_strategy()) { - case simplex_strategy_enum::tableau_rows: - prepare_costs_for_r_solver(term); - settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; - { - bool ret = maximize_term_on_tableau(term, term_max); - settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); - return ret; - } - case simplex_strategy_enum::tableau_costs: - prepare_costs_for_r_solver(term); - { - bool ret = maximize_term_on_tableau(term, term_max); - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); - return ret; - } - - case simplex_strategy_enum::lu: - lean_assert(false); // not implemented - return false; - default: - lean_unreachable(); // wrong mode - } - return false; - } - // starting from a given feasible state look for the maximum of the term - // return true if found and false if unbounded - bool lar_solver::maximize_term(const vector> & term, - impq &term_max) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); - m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; - return maximize_term_on_corrected_r_solver(term, term_max); - } - - - - const lar_term & lar_solver::get_term(unsigned j) const { - lean_assert(j >= m_terms_start_index); - return *m_terms[j - m_terms_start_index]; - } - - void lar_solver::pop_core_solver_params() { - pop_core_solver_params(1); - } - - void lar_solver::pop_core_solver_params(unsigned k) { - A_r().pop(k); - A_d().pop(k); - } - - - void lar_solver::set_upper_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_vars_to_ul_pairs[j]; - ul.upper_bound_witness() = ci; - m_vars_to_ul_pairs[j] = ul; - } - - void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_vars_to_ul_pairs[j]; - ul.low_bound_witness() = ci; - m_vars_to_ul_pairs[j] = ul; - } - - - void lar_solver::substitute_terms(const mpq & mult, - const vector>& left_side_with_terms, - vector> &left_side, mpq & right_side) const { - for (auto & t : left_side_with_terms) { - if (t.second < m_terms_start_index) { - lean_assert(t.second < A_r().column_count()); - left_side.push_back(std::pair(mult * t.first, t.second)); - } else { - const lar_term & term = * m_terms[adjust_term_index(t.second)]; - substitute_terms(mult * t.first, left_side_with_terms, left_side, right_side); - right_side -= mult * term.m_v; - } - } - } - - - void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { - if (A_r().row_count() != m_column_buffer.data_size()) - m_column_buffer.resize(A_r().row_count()); - else - m_column_buffer.clear(); - lean_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); - - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) - m_rows_with_changed_bounds.insert(i); - } - - - - 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); - } - - bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } - - bool lar_solver::use_tableau_costs() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; - } - - void lar_solver::detect_rows_of_column_with_bound_change(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column - // just mark the row at touched and exit - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); - return; - } - - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); - } - - void lar_solver::adjust_x_of_column(unsigned j) { - lean_assert(false); - } - - 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]; - return is_zero(r); - } - - bool lar_solver::ax_is_correct() const { - for (unsigned i = 0; i < A_r().row_count(); i++) { - if (!row_is_correct(i)) - return false; - } - return true; - } - - bool lar_solver::tableau_with_costs() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; - } - - bool lar_solver::costs_are_used() const { - return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; - } - - void lar_solver::change_basic_x_by_delta_on_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]; - m_mpq_lar_core_solver.m_r_x[bj] -= A_r().get_val(c) * delta; - if (tableau_with_costs()) { - m_basic_columns_with_changed_cost.insert(bj); - } - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); - } - } else { - m_column_buffer.clear(); - m_column_buffer.resize(A_r().row_count()); - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; - m_mpq_lar_core_solver.m_r_x[bj] -= m_column_buffer[i] * delta; - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); - } - } - } - - void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - if (costs_are_used()) { - bool was_infeas = m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j); - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); - if (was_infeas != m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j)) - m_basic_columns_with_changed_cost.insert(j); - } else { - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); - } - } else { - numeric_pair delta; - if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) - change_basic_x_by_delta_on_column(j, delta); - } - } - - - void lar_solver::detect_rows_with_changed_bounds_for_column(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); - return; - } - - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); - } - - void lar_solver::detect_rows_with_changed_bounds() { - for (auto j : m_columns_with_changed_bound.m_index) - detect_rows_with_changed_bounds_for_column(j); - } - - void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds() { - for (auto j : m_columns_with_changed_bound.m_index) - update_x_and_inf_costs_for_column_with_changed_bounds(j); - } - - void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { - lean_assert(ax_is_correct()); - for (auto j : m_columns_with_changed_bound.m_index) - update_x_and_inf_costs_for_column_with_changed_bounds(j); - - if (tableau_with_costs()) { - for (unsigned j : m_basic_columns_with_changed_cost.m_index) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } - } - - - void lar_solver::solve_with_core_solver() { - if (!use_tableau()) - add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); - if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { - add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); - } - m_mpq_lar_core_solver.prefix_r(); - if (costs_are_used()) { - m_basic_columns_with_changed_cost.clear(); - m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); - } - if (use_tableau()) - update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - else - update_x_and_inf_costs_for_columns_with_changed_bounds(); - m_mpq_lar_core_solver.solve(); - set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); - lean_assert(m_status != OPTIMAL || all_constraints_hold()); - } - - - numeric_pair lar_solver::get_basic_var_value_from_row_directly(unsigned i) { - numeric_pair r = zero_of_type>(); - - 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 (!is_zero(x)) - r -= c.m_value * x; - } - return r; - } - - numeric_pair lar_solver::get_basic_var_value_from_row(unsigned i) { - if (settings().use_tableau()) { - return get_basic_var_value_from_row_directly(i); - } - - numeric_pair r = zero_of_type>(); - m_mpq_lar_core_solver.calculate_pivot_row(i); - for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); - r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; - } - return r; - } - - template - void lar_solver::add_last_rows_to_lu(lp_primal_core_solver & s) { - auto & f = s.m_factorization; - if (f != nullptr) { - auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); - if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { - delete f; - f = nullptr; - } else { - f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); - } - } - if (f == nullptr) { - init_factorization(f, s.m_A, s.m_basis, m_settings); - if (f->get_status() != LU_status::OK) { - delete f; - f = nullptr; - } - } - - } - - bool lar_solver::x_is_correct() const { - if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { - // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; - return false; - } - for (unsigned i = 0; i < A_r().row_count(); i++) { - numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); - if (!delta.is_zero()) { - // std::cout << "x is off ("; - // std::cout << "m_b[" << i << "] = " << m_b[i] << " "; - // std::cout << "left side = " << A().dot_product_with_row(i, m_r_solver.m_x) << ' '; - // std::cout << "delta = " << delta << ' '; - // std::cout << "iters = " << total_iterations() << ")" << std::endl; - // std::cout << "row " << i << " is off" << std::endl; - return false; - } - } - return true;; - - } - - bool lar_solver::var_is_registered(var_index vj) const { - if (vj >= m_terms_start_index) { - if (vj - m_terms_start_index >= m_terms.size()) - return false; - } else if ( vj >= A_r().column_count()) { - return false; - } - return true; - } - - unsigned lar_solver::constraint_stack_size() const { - return m_constraint_count.stack_size(); - } - - void lar_solver::fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); - unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].size() == 0); - for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); - var_index j = t.first; - A.set(last_row, j, - t.second); - } - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, mpq(1)); - } - - template - void lar_solver::create_matrix_A(static_matrix & matr) { - lean_assert(false); // not implemented - /* - unsigned m = number_or_nontrivial_left_sides(); - unsigned n = m_vec_of_canonic_left_sides.size(); - if (matr.row_count() == m && matr.column_count() == n) - return; - matr.init_empty_matrix(m, n); - copy_from_mpq_matrix(matr); - */ - } - - template - void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { - matr.m_rows.resize(A_r().row_count()); - 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())); - } - } - } - - - bool lar_solver::try_to_set_fixed(column_info & ci) { - if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { - ci.set_fixed_value(ci.get_upper_bound()); - return true; - } - return false; - } - - column_type lar_solver::get_column_type(const column_info & ci) { - auto ret = ci.get_column_type_no_flipping(); - if (ret == column_type::boxed) { // changing boxed to fixed because of the no span - if (ci.get_low_bound() == ci.get_upper_bound()) - ret = column_type::fixed; - } - return ret; - } - - std::string lar_solver::get_column_name(unsigned j) const { - if (j >= m_terms_start_index) - return std::string("_t") + T_to_string(j); - if (j >= m_columns_to_ext_vars_or_term_indices.size()) - return std::string("_s") + T_to_string(j); - - return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]); - } - - bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { - for (auto it : left_side) { - if (! var_is_registered(it.second)) - return false; - } - return true; - } - - constraint_index lar_solver::add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { - /* - mpq rs = right_side_parm; - vector> left_side; - substitute_terms(one_of_type(), left_side_with_terms, left_side, rs); - lean_assert(left_side.size() > 0); - lean_assert(all_constrained_variables_are_registered(left_side)); - lar_constraint original_constr(left_side, kind_par, rs); - unsigned j; // j is the index of the basic variables corresponding to the left side - canonic_left_side ls = create_or_fetch_canonic_left_side(left_side, j); - mpq ratio = find_ratio_of_original_constraint_to_normalized(ls, original_constr); - auto kind = ratio.is_neg() ? flip_kind(kind_par) : kind_par; - rs/= ratio; - lar_normalized_constraint normalized_constraint(ls, ratio, kind, rs, original_constr); - m_constraints.push_back(normalized_constraint); - constraint_index constr_ind = m_constraints.size() - 1; - update_column_type_and_bound(j, kind, rs, constr_ind); - return constr_ind; - */ - lean_assert(false); // not implemented - return 0; - } - - bool lar_solver::all_constraints_hold() const { - if (m_settings.get_cancel_flag()) - return true; - std::unordered_map var_map; - get_model(var_map); - - for (unsigned i = 0; i < m_constraints.size(); i++) { - if (!constraint_holds(*m_constraints[i], var_map)) { - print_constraint(i, std::cout); - return false; - } - } - return true; - } - - bool lar_solver::constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { - mpq left_side_val = get_left_side_val(constr, var_map); - switch (constr.m_kind) { - case LE: return left_side_val <= constr.m_right_side; - case LT: return left_side_val < constr.m_right_side; - case GE: return left_side_val >= constr.m_right_side; - case GT: return left_side_val > constr.m_right_side; - case EQ: return left_side_val == constr.m_right_side; - default: - lean_unreachable(); - } - return false; // it is unreachable - } - - bool lar_solver::the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const { - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lconstraint_kind kind = coeff.is_pos() ? - m_constraints[con_ind]->m_kind : - flip_kind(m_constraints[con_ind]->m_kind); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) n_of_G++; - else if (kind == LE || kind == LT) n_of_L++; - } - the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); - - return n_of_G == 0 || n_of_L == 0; - } - -void lar_solver::register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a) { - for (auto & it : cn.get_left_side_coefficients()) { - unsigned j = it.second; - auto p = coeffs.find(j); - if (p == coeffs.end()) - coeffs[j] = it.first * a; - else { - p->second += it.first * a; - if (p->second.is_zero()) - coeffs.erase(p); - } - } - } - - bool lar_solver::the_left_sides_sum_to_zero(const vector> & evidence) const { - std::unordered_map coeff_map; - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - register_in_map(coeff_map, *m_constraints[con_ind], coeff); - } - - if (!coeff_map.empty()) { - std::cout << "left side = "; - vector> t; - for (auto & it : coeff_map) { - t.push_back(std::make_pair(it.second, it.first)); - } - print_linear_combination_of_column_indices(t, std::cout); - std::cout << std::endl; - return false; - } - - return true; - } - - bool lar_solver::the_right_sides_do_not_sum_to_zero(const vector> & evidence) { - mpq ret = numeric_traits::zero(); - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - const lar_constraint & constr = *m_constraints[con_ind]; - ret += constr.m_right_side * coeff; - } - return !numeric_traits::is_zero(ret); - } - - bool lar_solver::explanation_is_correct(const vector>& explanation) const { -#ifdef LEAN_DEBUG - lconstraint_kind kind; - lean_assert(the_relations_are_of_same_type(explanation, kind)); - lean_assert(the_left_sides_sum_to_zero(explanation)); - mpq rs = sum_of_right_sides_of_explanation(explanation); - switch (kind) { - case LE: lean_assert(rs < zero_of_type()); - break; - case LT: lean_assert(rs <= zero_of_type()); - break; - case GE: lean_assert(rs > zero_of_type()); - break; - case GT: lean_assert(rs >= zero_of_type()); - break; - case EQ: lean_assert(rs != zero_of_type()); - break; - default: - lean_assert(false); - return false; - } -#endif - return true; - } - - bool lar_solver::inf_explanation_is_correct() const { -#ifdef LEAN_DEBUG - vector> explanation; - get_infeasibility_explanation(explanation); - return explanation_is_correct(explanation); -#endif - return true; - } - - mpq lar_solver::sum_of_right_sides_of_explanation(const vector> & explanation) const { - mpq ret = numeric_traits::zero(); - for (auto & it : explanation) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; - } - return ret; - } - - bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - - if (var >= m_vars_to_ul_pairs.size()) { - // TBD: bounds on terms could also be used, caller may have to track these. - return false; - } - const ul_pair & ul = m_vars_to_ul_pairs[var]; - ci = ul.low_bound_witness(); - if (ci != static_cast(-1)) { - auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; - value = p.x; - is_strict = p.y.is_pos(); - return true; - } - else { - return false; - } - } - - bool lar_solver::has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - - if (var >= m_vars_to_ul_pairs.size()) { - // TBD: bounds on terms could also be used, caller may have to track these. - return false; - } - const ul_pair & ul = m_vars_to_ul_pairs[var]; - ci = ul.upper_bound_witness(); - if (ci != static_cast(-1)) { - auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; - value = p.x; - is_strict = p.y.is_neg(); - return true; - } - else { - return false; - } - } - - void lar_solver::get_infeasibility_explanation(vector> & explanation) const { - explanation.clear(); - if (m_infeasible_column_index != -1) { - fill_explanation_from_infeasible_column(explanation); - return; - } - if (m_mpq_lar_core_solver.get_infeasible_sum_sign() == 0) { - return; - } - // the infeasibility sign - int inf_sign; - auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); - get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); - lean_assert(explanation_is_correct(explanation)); - } - - void lar_solver::get_infeasibility_explanation_for_inf_sign( - vector> & explanation, - const vector> & inf_row, - int inf_sign) const { - - for (auto & it : inf_row) { - mpq coeff = it.first; - unsigned j = it.second; - - int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; - const ul_pair & ul = m_vars_to_ul_pairs[j]; - - constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); - lean_assert(bound_constr_i < m_constraints.size()); - explanation.push_back(std::make_pair(coeff, bound_constr_i)); - } - } - - void lar_solver::get_model(std::unordered_map & variable_values) const { - mpq delta = mpq(1, 2); // start from 0.5 to have less clashes - lean_assert(m_status == OPTIMAL); - unsigned i; - do { - - // different pairs have to produce different singleton values - std::unordered_set set_of_different_pairs; - std::unordered_set set_of_different_singles; - delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); - for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { - const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; - set_of_different_pairs.insert(rp); - mpq x = rp.x + delta * rp.y; - set_of_different_singles.insert(x); - if (set_of_different_pairs.size() - != set_of_different_singles.size()) { - delta /= mpq(2); - break; - } - - variable_values[i] = x; - } - } while (i != m_mpq_lar_core_solver.m_r_x.size()); - } - -std::string lar_solver::get_variable_name(var_index vi) const { - return get_column_name(vi); +void clear() {lean_assert(false); // not implemented } - // ********** print region start - void lar_solver::print_constraint(constraint_index ci, std::ostream & out) const { - if (ci >= m_constraints.size()) { - out << "constraint " << T_to_string(ci) << " is not found"; - out << std::endl; - return; - } - print_constraint(m_constraints[ci], out); +lar_solver::lar_solver() : m_status(OPTIMAL), + m_infeasible_column_index(-1), + m_terms_start_index(1000000), + m_column_type_function ([this] (unsigned j) {return m_mpq_lar_core_solver.m_column_types()[j];}), + m_mpq_lar_core_solver(m_settings, *this) +{} + +void lar_solver::set_propagate_bounds_on_pivoted_rows_mode(bool v) { + m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; +} + +lar_solver::~lar_solver(){ + for (auto c : m_constraints) + delete c; + for (auto t : m_terms) + delete t; +} + +numeric_pair const& lar_solver::get_value(var_index vi) const { return m_mpq_lar_core_solver.m_r_x[vi]; } + +bool lar_solver::is_term(var_index j) const { + return j >= m_terms_start_index && j - m_terms_start_index < m_terms.size(); +} + +unsigned lar_solver::adjust_term_index(unsigned j) const { + lean_assert(is_term(j)); + return j - m_terms_start_index; +} + + +bool lar_solver::use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } + +bool lar_solver::sizes_are_correct() const { + lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); + return true; +} + + +void lar_solver::print_implied_bound(const implied_bound& be, std::ostream & out) const { + out << "implied bound\n"; + unsigned v = be.m_j; + if (is_term(v)) { + out << "it is a term number " << be.m_j << std::endl; + print_term(*m_terms[be.m_j - m_terms_start_index], out); } - - void lar_solver::print_constraints(std::ostream& out) const { - for (auto c : m_constraints) { - print_constraint(c, out); - } + else { + out << get_column_name(v); } - - void lar_solver::print_terms(std::ostream& out) const { - for (auto it : m_terms) { - print_term(*it, out); - out << "\n"; - } - } - - void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const { - print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out); - mpq free_coeff = c->get_free_coeff_of_left_side(); - if (!is_zero(free_coeff)) - out << " + " << free_coeff; + out << " " << lconstraint_kind_string(be.kind()) << " " << be.m_bound << std::endl; + // for (auto & p : be.m_explanation) { + // out << p.first << " : "; + // print_constraint(p.second, out); + // } + // m_mpq_lar_core_solver.m_r_solver.print_column_info(be.m_j< m_terms_start_index? be.m_j : adjust_term_index(be.m_j), out); + out << "end of implied bound" << std::endl; +} + +bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { + std::unordered_map coeff_map; + auto rs_of_evidence = zero_of_type(); + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : explanation) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + const auto & constr = *m_constraints[con_ind]; + lconstraint_kind kind = coeff.is_pos() ? constr.m_kind : flip_kind(constr.m_kind); + register_in_map(coeff_map, constr, coeff); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + rs_of_evidence += coeff*constr.m_right_side; } - - void lar_solver::print_term(lar_term const& term, std::ostream & out) const { - if (!numeric_traits::is_zero(term.m_v)) { - out << term.m_v << " + "; + lean_assert(n_of_G == 0 || n_of_L == 0); + lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); + if (strict) + kind = static_cast((static_cast(kind) / 2)); + + if (!is_term(be.m_j)) { + if (coeff_map.size() != 1) + return false; + auto it = coeff_map.find(be.m_j); + if (it == coeff_map.end()) return false; + mpq ratio = it->second; + if (ratio < zero_of_type()) { + kind = static_cast(-kind); } - print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); - } - - mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { - mpq ret = cns.get_free_coeff_of_left_side(); - for (auto & it : cns.get_left_side_coefficients()) { - var_index j = it.second; - auto vi = var_map.find(j); - lean_assert(vi != var_map.end()); - ret += it.first * vi->second; + rs_of_evidence /= ratio; + } else { + const lar_term * t = m_terms[adjust_term_index(be.m_j)]; + const auto first_coeff = *t->m_coeffs.begin(); + unsigned j = first_coeff.first; + auto it = coeff_map.find(j); + if (it == coeff_map.end()) + return false; + mpq ratio = it->second / first_coeff.second; + for (auto & p : t->m_coeffs) { + it = coeff_map.find(p.first); + if (it == coeff_map.end()) + return false; + if (p.second * ratio != it->second) + return false; } - return ret; - } - - void lar_solver::print_constraint(const lar_base_constraint * c, std::ostream & out) const { - print_left_side_of_constraint(c, out); - out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; - } - - void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { - for (unsigned i = 0; i < sz; i++) { - var_index var = vars[i]; - if (var >= m_terms_start_index) { // handle the term - for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { - column_list.push_back(it.first); - } - } else { - column_list.push_back(var); - } + if (ratio < zero_of_type()) { + kind = static_cast(-kind); } + rs_of_evidence /= ratio; + rs_of_evidence += t->m_v * ratio; } - void lar_solver::random_update(unsigned sz, var_index const * vars) { - vector column_list; - fill_var_set_for_random_update(sz, vars, column_list); - random_updater ru(m_mpq_lar_core_solver, column_list); - ru.update(); + return kind == be.kind() && rs_of_evidence == be.m_bound; +} + + +void lar_solver::analyze_new_bounds_on_row( + unsigned row_index, + bound_propagator & bp) { + lean_assert(!use_tableau()); + iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); + + bound_analyzer_on_row ra_pos(it, + zero_of_type>(), + row_index, + bp + ); + ra_pos.analyze(); +} + +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) + return; + iterator_on_row it(A_r().m_rows[row_index]); + lean_assert(use_tableau()); + bound_analyzer_on_row::analyze_row(it, + zero_of_type>(), + row_index, + bp + ); +} + + +void lar_solver::substitute_basis_var_in_terms_for_row(unsigned i) { + // todo : create a map from term basic vars to the rows where they are used + unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; + for (unsigned k = 0; k < m_terms.size(); k++) { + if (term_is_used_as_row(k)) + continue; + if (!m_terms[k]->contains(basis_j)) + continue; + m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); } - - - void lar_solver::try_pivot_fixed_vars_from_basis() { - m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); +} + +void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { + if(use_tableau()) { + analyze_new_bounds_on_row_tableau(i, bp); + } else { + m_mpq_lar_core_solver.calculate_pivot_row(i); + substitute_basis_var_in_terms_for_row(i); + analyze_new_bounds_on_row(i, bp); } +} - void lar_solver::pop() { - pop(1); + +linear_combination_iterator * lar_solver::create_new_iter_from_term(unsigned term_index) const { + lean_assert(false); // not implemented + return nullptr; + // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); +} + +unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const { + unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; + return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; +} + +void lar_solver::propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { + lean_assert(false); // not implemented +} + + +void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp) { + unsigned i = ib.m_row_or_term_index; + int bound_sign = ib.m_is_low_bound? 1: -1; + int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; + unsigned m_j = ib.m_j; + if (is_term(m_j)) { + auto it = m_ext_vars_to_columns.find(m_j); + lean_assert(it != m_ext_vars_to_columns.end()); + m_j = it->second.ext_j(); } - - bool lar_solver::column_represents_row_in_tableau(unsigned j) { - return m_vars_to_ul_pairs()[j].m_i != static_cast(-1); + for (auto const& r : A_r().m_rows[i]) { + unsigned j = r.m_j; + mpq const& a = r.get_val(); + if (j == m_j) continue; + if (is_term(j)) { + auto it = m_ext_vars_to_columns.find(j); + lean_assert(it != m_ext_vars_to_columns.end()); + j = it->second.ext_j(); + } + int a_sign = is_pos(a)? 1: -1; + int sign = j_sign * a_sign; + const ul_pair & ul = m_vars_to_ul_pairs[j]; + auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); + lean_assert(is_valid(witness)); + bp.consume(a, witness); } + // lean_assert(implied_bound_is_correctly_explained(ib, explanation)); +} - void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { - // i, j - is the indices of the bottom-right element of the tableau - lean_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;){ - auto & cc = last_column[k]; - if (cc.m_i == i) - return; - non_zero_column_cell_index = k; - } - lean_assert(non_zero_column_cell_index != -1); - lean_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); +bool lar_solver::term_is_used_as_row(unsigned term) const { + lean_assert(is_term(term)); + return contains(m_ext_vars_to_columns, term); +} + +void lar_solver::propagate_bounds_on_terms(bound_propagator & bp) { + for (unsigned i = 0; i < m_terms.size(); i++) { + if (term_is_used_as_row(i + m_terms_start_index)) + continue; // this term is used a left side of a constraint, + // it was processed as a touched row if needed + propagate_bounds_on_a_term(*m_terms[i], bp, i); } +} - void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - auto & slv = m_mpq_lar_core_solver.m_r_solver; - unsigned i = A_r().row_count() - 1; //last row index - make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); - if (slv.m_basis_heading[j] < 0) { - slv.pivot_column_tableau(j, i); - } - 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;) { - auto &rc = last_row[k]; - if (cost_is_nz) { - m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); - } - - A_r().remove_element(last_row, rc); - } - lean_assert(last_row.size() == 0); - lean_assert(A_r().m_columns[j].size() == 0); - A_r().m_rows.pop_back(); - A_r().m_columns.pop_back(); - slv.m_b.pop_back(); +// goes over touched rows and tries to induce bounds +void lar_solver::propagate_bounds_for_touched_rows(bound_propagator & bp) { + if (!use_tableau()) + return; // todo: consider to remove the restriction + + for (unsigned i : m_rows_with_changed_bounds.m_index) { + calculate_implied_bounds_for_row(i, bp); } - - void lar_solver::remove_last_column_from_tableau(unsigned j) { - lean_assert(j == A_r().column_count() - 1); - // the last column has to be empty - lean_assert(A_r().m_columns[j].size() == 0); - A_r().m_columns.pop_back(); + m_rows_with_changed_bounds.clear(); + if (!use_tableau()) { + propagate_bounds_on_terms(bp); } +} - void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { - auto& rslv = m_mpq_lar_core_solver.m_r_solver; +lp_status lar_solver::get_status() const { return m_status;} + +void lar_solver::set_status(lp_status s) {m_status = s;} + +lp_status lar_solver::find_feasible_solution() { + if (strategy_is_undecided()) + decide_on_strategy_and_adjust_initial_state(); + + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; + return solve(); +} + +lp_status lar_solver::solve() { + if (m_status == INFEASIBLE) { + return m_status; + } + solve_with_core_solver(); + if (m_status != INFEASIBLE) { + if (m_settings.bound_propagation()) + detect_rows_with_changed_bounds(); + } + + m_columns_with_changed_bound.clear(); + return m_status; +} + +void lar_solver::fill_explanation_from_infeasible_column(vector> & evidence) const{ + + // this is the case when the lower bound is in conflict with the upper one + const ul_pair & ul = m_vars_to_ul_pairs[m_infeasible_column_index]; + evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); + evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); +} + + +unsigned lar_solver::get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } +// see http://research.microsoft.com/projects/z3/smt07.pdf +// This method searches for a feasible solution with as many different values of variables, reverenced in vars, as it can find +// Attention, after a call to this method the non-basic variables don't necesserarly stick to their bounds anymore +vector lar_solver::get_list_of_all_var_indices() const { + vector ret; + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) + ret.push_back(j); + return ret; +} +void lar_solver::push() { + m_simplex_strategy = m_settings.simplex_strategy(); + m_simplex_strategy.push(); + m_status.push(); + m_vars_to_ul_pairs.push(); + m_infeasible_column_index.push(); + m_mpq_lar_core_solver.push(); + m_term_count = m_terms.size(); + m_term_count.push(); + m_constraint_count = m_constraints.size(); + m_constraint_count.push(); +} + +void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { + vector to_remove; + for (unsigned j: set.m_index) + if (j >= n) + to_remove.push_back(j); + for (unsigned j : to_remove) + set.erase(j); +} + +void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { + clean_large_elements_after_pop(n, set); + set.resize(n); +} + + +void lar_solver::pop(unsigned k) { + int n_was = static_cast(m_ext_vars_to_columns.size()); + m_status.pop(k); + m_infeasible_column_index.pop(k); + unsigned n = m_vars_to_ul_pairs.peek_size(k); + for (unsigned j = n_was; j-- > n;) + m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); + m_columns_to_ext_vars_or_term_indices.resize(n); + if (m_settings.use_tableau()) { + pop_tableau(); + } + m_vars_to_ul_pairs.pop(k); + + m_mpq_lar_core_solver.pop(k); + clean_large_elements_after_pop(n, m_columns_with_changed_bound); + unsigned m = A_r().row_count(); + clean_large_elements_after_pop(m, m_rows_with_changed_bounds); + clean_inf_set_of_r_solver_after_pop(); + lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || + (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + + + lean_assert(ax_is_correct()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); + m_constraint_count.pop(k); + for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) + delete m_constraints[i]; + + m_constraints.resize(m_constraint_count); + m_term_count.pop(k); + for (unsigned i = m_term_count; i < m_terms.size(); i++) { + delete m_terms[i]; + } + m_terms.resize(m_term_count); + m_simplex_strategy.pop(k); + m_settings.simplex_strategy() = m_simplex_strategy; + lean_assert(sizes_are_correct()); + lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); +} + +vector lar_solver::get_all_constraint_indices() const { + vector ret; + constraint_index i = 0; + while ( i < m_constraints.size()) + ret.push_back(i++); + return ret; +} + +bool lar_solver::maximize_term_on_tableau(const vector> & term, + impq &term_max) { + if (settings().simplex_strategy() == simplex_strategy_enum::undecided) + decide_on_strategy_and_adjust_initial_state(); + + m_mpq_lar_core_solver.solve(); + if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED) + return false; + + term_max = 0; + for (auto & p : term) + term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second]; + + return true; +} + +bool lar_solver::costs_are_zeros_for_r_solver() const { + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { + lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); + } + return true; +} +bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const { + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { + lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); + } + return true; +} + +void lar_solver::set_costs_to_zero(const vector> & term) { + auto & rslv = m_mpq_lar_core_solver.m_r_solver; + auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now + lean_assert(jset.m_index.size()==0); + + for (auto & p : term) { + unsigned j = p.second; + rslv.m_costs[j] = zero_of_type(); int i = rslv.m_basis_heading[j]; - if (i >= 0) { // j is a basic var - int last_pos = static_cast(rslv.m_basis.size()) - 1; - lean_assert(last_pos >= 0); - if (i != last_pos) { - unsigned j_at_last_pos = rslv.m_basis[last_pos]; - rslv.m_basis[i] = j_at_last_pos; - rslv.m_basis_heading[j_at_last_pos] = i; - } - rslv.m_basis.pop_back(); // remove j from the basis - } else { - int last_pos = static_cast(rslv.m_nbasis.size()) - 1; - lean_assert(last_pos >= 0); - i = - 1 - i; - if (i != last_pos) { - unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; - rslv.m_nbasis[i] = j_at_last_pos; - rslv.m_basis_heading[j_at_last_pos] = - i - 1; - } - rslv.m_nbasis.pop_back(); // remove j from the basis - } - rslv.m_basis_heading.pop_back(); - lean_assert(rslv.m_basis.size() == A_r().row_count()); - lean_assert(rslv.basis_heading_is_correct()); - } - - void lar_solver::remove_column_from_tableau(unsigned j) { - auto& rslv = m_mpq_lar_core_solver.m_r_solver; - lean_assert(j == A_r().column_count() - 1); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - if (column_represents_row_in_tableau(j)) { - remove_last_row_and_column_from_tableau(j); - if (rslv.m_basis_heading[j] < 0) - rslv.change_basis_unconditionally(j, rslv.m_basis[A_r().row_count()]); // A_r().row_count() is the index of the last row in the basis still - } + if (i < 0) + jset.insert(j); else { - remove_last_column_from_tableau(j); + for (auto & rc : A_r().m_rows[i]) + jset.insert(rc.m_j); } - rslv.m_x.pop_back(); - rslv.m_d.pop_back(); - rslv.m_costs.pop_back(); - - remove_last_column_from_basis_tableau(j); - lean_assert(m_mpq_lar_core_solver.r_basis_is_OK()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); } - void lar_solver::pop_tableau() { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + for (unsigned j : jset.m_index) + rslv.m_d[j] = zero_of_type(); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); - // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). - // At this moment m_column_names is already popped - for (unsigned j = A_r().column_count(); j-- > m_columns_to_ext_vars_or_term_indices.size();) - remove_column_from_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + jset.clear(); + + lean_assert(reduced_costs_are_zeroes_for_r_solver()); + lean_assert(costs_are_zeros_for_r_solver()); +} + +void lar_solver::prepare_costs_for_r_solver(const vector> & term) { + + auto & rslv = m_mpq_lar_core_solver.m_r_solver; + rslv.m_using_infeas_costs = false; + lean_assert(costs_are_zeros_for_r_solver()); + lean_assert(reduced_costs_are_zeroes_for_r_solver()); + rslv.m_costs.resize(A_r().column_count(), zero_of_type()); + for (auto & p : term) { + unsigned j = p.second; + rslv.m_costs[j] = p.first; + if (rslv.m_basis_heading[j] < 0) + rslv.m_d[j] += p.first; + else + rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); } + lean_assert(rslv.reduced_costs_are_correct_tableau()); +} + +bool lar_solver::maximize_term_on_corrected_r_solver(const vector> & term, + impq &term_max) { + settings().backup_costs = false; + switch (settings().simplex_strategy()) { + case simplex_strategy_enum::tableau_rows: + prepare_costs_for_r_solver(term); + settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; + { + bool ret = maximize_term_on_tableau(term, term_max); + settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); + return ret; + } + case simplex_strategy_enum::tableau_costs: + prepare_costs_for_r_solver(term); + { + bool ret = maximize_term_on_tableau(term, term_max); + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); + return ret; + } + + case simplex_strategy_enum::lu: + lean_assert(false); // not implemented + return false; + default: + lean_unreachable(); // wrong mode + } + return false; +} +// starting from a given feasible state look for the maximum of the term +// return true if found and false if unbounded +bool lar_solver::maximize_term(const vector> & term, + impq &term_max) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; + return maximize_term_on_corrected_r_solver(term, term_max); +} + + + +const lar_term & lar_solver::get_term(unsigned j) const { + lean_assert(j >= m_terms_start_index); + return *m_terms[j - m_terms_start_index]; +} + +void lar_solver::pop_core_solver_params() { + pop_core_solver_params(1); +} + +void lar_solver::pop_core_solver_params(unsigned k) { + A_r().pop(k); + A_d().pop(k); +} + + +void lar_solver::set_upper_bound_witness(var_index j, constraint_index ci) { + ul_pair ul = m_vars_to_ul_pairs[j]; + ul.upper_bound_witness() = ci; + m_vars_to_ul_pairs[j] = ul; +} + +void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) { + ul_pair ul = m_vars_to_ul_pairs[j]; + ul.low_bound_witness() = ci; + m_vars_to_ul_pairs[j] = ul; +} + +void lar_solver::register_one_coeff_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j) { + auto it = coeffs.find(j); + if (it == coeffs.end()) { + coeffs[j] = a; + } else { + it->second += a; + } +} + + +void lar_solver::substitute_terms_in_linear_expression(const vector>& left_side_with_terms, + vector> &left_side, mpq & right_side) const { + std::unordered_map coeffs; + for (auto & t : left_side_with_terms) { + unsigned j = t.second; + if (!is_term(j)) { + register_one_coeff_in_map(coeffs, t.first, j); + } else { + const lar_term & term = * m_terms[adjust_term_index(t.second)]; + std::cout << "term = "; + print_term(term, std::cout); + std::cout << std::endl; + for (auto & p : term.coeffs()){ + register_one_coeff_in_map(coeffs, t.first * p.second , p.first); + } + right_side += t.first * term.m_v; + } + } + + for (auto & p : coeffs) + left_side.push_back(std::make_pair(p.second, p.first)); +} + + +void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { + if (A_r().row_count() != m_column_buffer.data_size()) + m_column_buffer.resize(A_r().row_count()); + else + m_column_buffer.clear(); + lean_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); + + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + for (unsigned i : m_column_buffer.m_index) + m_rows_with_changed_bounds.insert(i); +} + + + +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); +} + +bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } + +bool lar_solver::use_tableau_costs() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; +} + +void lar_solver::detect_rows_of_column_with_bound_change(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column + // just mark the row at touched and exit + m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + return; + } + + if (use_tableau()) + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + else + detect_rows_of_bound_change_column_for_nbasic_column(j); +} + +void lar_solver::adjust_x_of_column(unsigned j) { + lean_assert(false); +} + +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]; + return is_zero(r); +} + +bool lar_solver::ax_is_correct() const { + for (unsigned i = 0; i < A_r().row_count(); i++) { + if (!row_is_correct(i)) + return false; + } + return true; +} + +bool lar_solver::tableau_with_costs() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; +} + +bool lar_solver::costs_are_used() const { + return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; +} + +void lar_solver::change_basic_x_by_delta_on_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]; + m_mpq_lar_core_solver.m_r_x[bj] -= A_r().get_val(c) * delta; + if (tableau_with_costs()) { + m_basic_columns_with_changed_cost.insert(bj); + } + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); + } + } else { + m_column_buffer.clear(); + m_column_buffer.resize(A_r().row_count()); + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + for (unsigned i : m_column_buffer.m_index) { + unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; + m_mpq_lar_core_solver.m_r_x[bj] -= m_column_buffer[i] * delta; + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); + } + } +} + +void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + if (costs_are_used()) { + bool was_infeas = m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j); + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); + if (was_infeas != m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j)) + m_basic_columns_with_changed_cost.insert(j); + } else { + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); + } + } else { + numeric_pair delta; + if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) + change_basic_x_by_delta_on_column(j, delta); + } +} + + +void lar_solver::detect_rows_with_changed_bounds_for_column(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + return; + } + + if (use_tableau()) + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + else + detect_rows_of_bound_change_column_for_nbasic_column(j); +} + +void lar_solver::detect_rows_with_changed_bounds() { + for (auto j : m_columns_with_changed_bound.m_index) + detect_rows_with_changed_bounds_for_column(j); +} + +void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds() { + for (auto j : m_columns_with_changed_bound.m_index) + update_x_and_inf_costs_for_column_with_changed_bounds(j); +} + +void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { + lean_assert(ax_is_correct()); + for (auto j : m_columns_with_changed_bound.m_index) + update_x_and_inf_costs_for_column_with_changed_bounds(j); + + if (tableau_with_costs()) { + for (unsigned j : m_basic_columns_with_changed_cost.m_index) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + } +} + + +void lar_solver::solve_with_core_solver() { + if (!use_tableau()) + add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); + if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { + add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); + } + m_mpq_lar_core_solver.prefix_r(); + if (costs_are_used()) { + m_basic_columns_with_changed_cost.clear(); + m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); + } + if (use_tableau()) + update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); + else + update_x_and_inf_costs_for_columns_with_changed_bounds(); + m_mpq_lar_core_solver.solve(); + set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); + lean_assert(m_status != OPTIMAL || all_constraints_hold()); +} + + +numeric_pair lar_solver::get_basic_var_value_from_row_directly(unsigned i) { + numeric_pair r = zero_of_type>(); + + 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 (!is_zero(x)) + r -= c.m_value * x; + } + return r; +} + +numeric_pair lar_solver::get_basic_var_value_from_row(unsigned i) { + if (settings().use_tableau()) { + return get_basic_var_value_from_row_directly(i); + } + + numeric_pair r = zero_of_type>(); + m_mpq_lar_core_solver.calculate_pivot_row(i); + for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; + } + return r; +} + +template +void lar_solver::add_last_rows_to_lu(lp_primal_core_solver & s) { + auto & f = s.m_factorization; + if (f != nullptr) { + auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); + if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { + delete f; + f = nullptr; + } else { + f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); + } + } + if (f == nullptr) { + init_factorization(f, s.m_A, s.m_basis, m_settings); + if (f->get_status() != LU_status::OK) { + delete f; + f = nullptr; + } + } + +} + +bool lar_solver::x_is_correct() const { + if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { + // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; + return false; + } + for (unsigned i = 0; i < A_r().row_count(); i++) { + numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); + if (!delta.is_zero()) { + // std::cout << "x is off ("; + // std::cout << "m_b[" << i << "] = " << m_b[i] << " "; + // std::cout << "left side = " << A().dot_product_with_row(i, m_r_solver.m_x) << ' '; + // std::cout << "delta = " << delta << ' '; + // std::cout << "iters = " << total_iterations() << ")" << std::endl; + // std::cout << "row " << i << " is off" << std::endl; + return false; + } + } + return true;; + +} + +bool lar_solver::var_is_registered(var_index vj) const { + if (vj >= m_terms_start_index) { + if (vj - m_terms_start_index >= m_terms.size()) + return false; + } else if ( vj >= A_r().column_count()) { + return false; + } + return true; +} + +unsigned lar_solver::constraint_stack_size() const { + return m_constraint_count.stack_size(); +} + +void lar_solver::fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { + lean_assert(A.row_count() > 0); + lean_assert(A.column_count() > 0); + unsigned last_row = A.row_count() - 1; + lean_assert(A.m_rows[last_row].size() == 0); + for (auto & t : ls->m_coeffs) { + lean_assert(!is_zero(t.second)); + var_index j = t.first; + A.set(last_row, j, - t.second); + } + unsigned basis_j = A.column_count() - 1; + A.set(last_row, basis_j, mpq(1)); +} + +template +void lar_solver::create_matrix_A(static_matrix & matr) { + lean_assert(false); // not implemented + /* + unsigned m = number_or_nontrivial_left_sides(); + unsigned n = m_vec_of_canonic_left_sides.size(); + if (matr.row_count() == m && matr.column_count() == n) + return; + matr.init_empty_matrix(m, n); + copy_from_mpq_matrix(matr); + */ +} + +template +void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { + matr.m_rows.resize(A_r().row_count()); + 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())); + } + } +} + + +bool lar_solver::try_to_set_fixed(column_info & ci) { + if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { + ci.set_fixed_value(ci.get_upper_bound()); + return true; + } + return false; +} + +column_type lar_solver::get_column_type(const column_info & ci) { + auto ret = ci.get_column_type_no_flipping(); + if (ret == column_type::boxed) { // changing boxed to fixed because of the no span + if (ci.get_low_bound() == ci.get_upper_bound()) + ret = column_type::fixed; + } + return ret; +} + +std::string lar_solver::get_column_name(unsigned j) const { + if (j >= m_terms_start_index) + return std::string("_t") + T_to_string(j); + if (j >= m_columns_to_ext_vars_or_term_indices.size()) + return std::string("_s") + T_to_string(j); + + return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]); +} + +bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { + for (auto it : left_side) { + if (! var_is_registered(it.second)) + return false; + } + return true; +} + +bool lar_solver::all_constraints_hold() const { + if (m_settings.get_cancel_flag()) + return true; + std::unordered_map var_map; + get_model(var_map); + + for (unsigned i = 0; i < m_constraints.size(); i++) { + if (!constraint_holds(*m_constraints[i], var_map)) { + print_constraint(i, std::cout); + return false; + } + } + return true; +} + +bool lar_solver::constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { + mpq left_side_val = get_left_side_val(constr, var_map); + switch (constr.m_kind) { + case LE: return left_side_val <= constr.m_right_side; + case LT: return left_side_val < constr.m_right_side; + case GE: return left_side_val >= constr.m_right_side; + case GT: return left_side_val > constr.m_right_side; + case EQ: return left_side_val == constr.m_right_side; + default: + lean_unreachable(); + } + return false; // it is unreachable +} + +bool lar_solver::the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const { + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lconstraint_kind kind = coeff.is_pos() ? + m_constraints[con_ind]->m_kind : + flip_kind(m_constraints[con_ind]->m_kind); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + } + the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); + if (strict) + the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); + + return n_of_G == 0 || n_of_L == 0; +} + +void lar_solver::register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a) { + for (auto & it : cn.get_left_side_coefficients()) { + unsigned j = it.second; + auto p = coeffs.find(j); + if (p == coeffs.end()) + coeffs[j] = it.first * a; + else { + p->second += it.first * a; + if (p->second.is_zero()) + coeffs.erase(p); + } + } +} + +bool lar_solver::the_left_sides_sum_to_zero(const vector> & evidence) const { + std::unordered_map coeff_map; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + register_in_map(coeff_map, *m_constraints[con_ind], coeff); + } + + if (!coeff_map.empty()) { + std::cout << "left side = "; + vector> t; + for (auto & it : coeff_map) { + t.push_back(std::make_pair(it.second, it.first)); + } + print_linear_combination_of_column_indices(t, std::cout); + std::cout << std::endl; + return false; + } + + return true; +} + +bool lar_solver::the_right_sides_do_not_sum_to_zero(const vector> & evidence) { + mpq ret = numeric_traits::zero(); + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + const lar_constraint & constr = *m_constraints[con_ind]; + ret += constr.m_right_side * coeff; + } + return !numeric_traits::is_zero(ret); +} + +bool lar_solver::explanation_is_correct(const vector>& explanation) const { +#ifdef LEAN_DEBUG + lconstraint_kind kind; + lean_assert(the_relations_are_of_same_type(explanation, kind)); + lean_assert(the_left_sides_sum_to_zero(explanation)); + mpq rs = sum_of_right_sides_of_explanation(explanation); + switch (kind) { + case LE: lean_assert(rs < zero_of_type()); + break; + case LT: lean_assert(rs <= zero_of_type()); + break; + case GE: lean_assert(rs > zero_of_type()); + break; + case GT: lean_assert(rs >= zero_of_type()); + break; + case EQ: lean_assert(rs != zero_of_type()); + break; + default: + lean_assert(false); + return false; + } +#endif + return true; +} + +bool lar_solver::inf_explanation_is_correct() const { +#ifdef LEAN_DEBUG + vector> explanation; + get_infeasibility_explanation(explanation); + return explanation_is_correct(explanation); +#endif + return true; +} + +mpq lar_solver::sum_of_right_sides_of_explanation(const vector> & explanation) const { + mpq ret = numeric_traits::zero(); + for (auto & it : explanation) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; + } + return ret; +} + +bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { + + if (var >= m_vars_to_ul_pairs.size()) { + // TBD: bounds on terms could also be used, caller may have to track these. + return false; + } + const ul_pair & ul = m_vars_to_ul_pairs[var]; + ci = ul.low_bound_witness(); + if (ci != static_cast(-1)) { + auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; + value = p.x; + is_strict = p.y.is_pos(); + return true; + } + else { + return false; + } +} + +bool lar_solver::has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { + + if (var >= m_vars_to_ul_pairs.size()) { + // TBD: bounds on terms could also be used, caller may have to track these. + return false; + } + const ul_pair & ul = m_vars_to_ul_pairs[var]; + ci = ul.upper_bound_witness(); + if (ci != static_cast(-1)) { + auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; + value = p.x; + is_strict = p.y.is_neg(); + return true; + } + else { + return false; + } +} + +void lar_solver::get_infeasibility_explanation(vector> & explanation) const { + explanation.clear(); + if (m_infeasible_column_index != -1) { + fill_explanation_from_infeasible_column(explanation); + return; + } + if (m_mpq_lar_core_solver.get_infeasible_sum_sign() == 0) { + return; + } + // the infeasibility sign + int inf_sign; + auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); + get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); + lean_assert(explanation_is_correct(explanation)); +} + +void lar_solver::get_infeasibility_explanation_for_inf_sign( + vector> & explanation, + const vector> & inf_row, + int inf_sign) const { + + for (auto & it : inf_row) { + mpq coeff = it.first; + unsigned j = it.second; + + int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; + const ul_pair & ul = m_vars_to_ul_pairs[j]; + + constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); + lean_assert(bound_constr_i < m_constraints.size()); + explanation.push_back(std::make_pair(coeff, bound_constr_i)); + } +} + +void lar_solver::get_model(std::unordered_map & variable_values) const { + mpq delta = mpq(1, 2); // start from 0.5 to have less clashes + lean_assert(m_status == OPTIMAL); + unsigned i; + do { + + // different pairs have to produce different singleton values + std::unordered_set set_of_different_pairs; + std::unordered_set set_of_different_singles; + delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); + for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { + const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; + set_of_different_pairs.insert(rp); + mpq x = rp.x + delta * rp.y; + set_of_different_singles.insert(x); + if (set_of_different_pairs.size() + != set_of_different_singles.size()) { + delta /= mpq(2); + break; + } + + variable_values[i] = x; + } + } while (i != m_mpq_lar_core_solver.m_r_x.size()); +} + +std::string lar_solver::get_variable_name(var_index vi) const { + return get_column_name(vi); +} + +// ********** print region start +void lar_solver::print_constraint(constraint_index ci, std::ostream & out) const { + if (ci >= m_constraints.size()) { + out << "constraint " << T_to_string(ci) << " is not found"; + out << std::endl; + return; + } + + print_constraint(m_constraints[ci], out); +} + +void lar_solver::print_constraints(std::ostream& out) const { + for (auto c : m_constraints) { + print_constraint(c, out); + } +} + +void lar_solver::print_terms(std::ostream& out) const { + for (auto it : m_terms) { + print_term(*it, out); + out << "\n"; + } +} + +void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const { + print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out); + mpq free_coeff = c->get_free_coeff_of_left_side(); + if (!is_zero(free_coeff)) + out << " + " << free_coeff; + +} + +void lar_solver::print_term(lar_term const& term, std::ostream & out) const { + if (!numeric_traits::is_zero(term.m_v)) { + out << term.m_v << " + "; + } + print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); +} + +mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { + mpq ret = cns.get_free_coeff_of_left_side(); + for (auto & it : cns.get_left_side_coefficients()) { + var_index j = it.second; + auto vi = var_map.find(j); + lean_assert(vi != var_map.end()); + ret += it.first * vi->second; + } + return ret; +} + +void lar_solver::print_constraint(const lar_base_constraint * c, std::ostream & out) const { + print_left_side_of_constraint(c, out); + out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; +} + +void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { + for (unsigned i = 0; i < sz; i++) { + var_index var = vars[i]; + if (var >= m_terms_start_index) { // handle the term + for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { + column_list.push_back(it.first); + } + } else { + column_list.push_back(var); + } + } +} + +void lar_solver::random_update(unsigned sz, var_index const * vars) { + vector column_list; + fill_var_set_for_random_update(sz, vars, column_list); + random_updater ru(m_mpq_lar_core_solver, column_list); + ru.update(); +} + + +void lar_solver::try_pivot_fixed_vars_from_basis() { + m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); +} + +void lar_solver::pop() { + pop(1); +} + +bool lar_solver::column_represents_row_in_tableau(unsigned j) { + return m_vars_to_ul_pairs()[j].m_i != static_cast(-1); +} + +void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { + // i, j - is the indices of the bottom-right element of the tableau + lean_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;){ + auto & cc = last_column[k]; + if (cc.m_i == i) + return; + non_zero_column_cell_index = k; + } + + lean_assert(non_zero_column_cell_index != -1); + lean_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); +} + +void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + auto & slv = m_mpq_lar_core_solver.m_r_solver; + unsigned i = A_r().row_count() - 1; //last row index + make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); + if (slv.m_basis_heading[j] < 0) { + slv.pivot_column_tableau(j, i); + } + + 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;) { + auto &rc = last_row[k]; + if (cost_is_nz) { + m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); + } + + A_r().remove_element(last_row, rc); + } + lean_assert(last_row.size() == 0); + lean_assert(A_r().m_columns[j].size() == 0); + A_r().m_rows.pop_back(); + A_r().m_columns.pop_back(); + slv.m_b.pop_back(); +} + +void lar_solver::remove_last_column_from_tableau(unsigned j) { + lean_assert(j == A_r().column_count() - 1); + // the last column has to be empty + lean_assert(A_r().m_columns[j].size() == 0); + A_r().m_columns.pop_back(); +} + +void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { + auto& rslv = m_mpq_lar_core_solver.m_r_solver; + int i = rslv.m_basis_heading[j]; + if (i >= 0) { // j is a basic var + int last_pos = static_cast(rslv.m_basis.size()) - 1; + lean_assert(last_pos >= 0); + if (i != last_pos) { + unsigned j_at_last_pos = rslv.m_basis[last_pos]; + rslv.m_basis[i] = j_at_last_pos; + rslv.m_basis_heading[j_at_last_pos] = i; + } + rslv.m_basis.pop_back(); // remove j from the basis + } else { + int last_pos = static_cast(rslv.m_nbasis.size()) - 1; + lean_assert(last_pos >= 0); + i = - 1 - i; + if (i != last_pos) { + unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; + rslv.m_nbasis[i] = j_at_last_pos; + rslv.m_basis_heading[j_at_last_pos] = - i - 1; + } + rslv.m_nbasis.pop_back(); // remove j from the basis + } + rslv.m_basis_heading.pop_back(); + lean_assert(rslv.m_basis.size() == A_r().row_count()); + lean_assert(rslv.basis_heading_is_correct()); +} + +void lar_solver::remove_column_from_tableau(unsigned j) { + auto& rslv = m_mpq_lar_core_solver.m_r_solver; + lean_assert(j == A_r().column_count() - 1); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + if (column_represents_row_in_tableau(j)) { + remove_last_row_and_column_from_tableau(j); + if (rslv.m_basis_heading[j] < 0) + rslv.change_basis_unconditionally(j, rslv.m_basis[A_r().row_count()]); // A_r().row_count() is the index of the last row in the basis still + } + else { + remove_last_column_from_tableau(j); + } + rslv.m_x.pop_back(); + rslv.m_d.pop_back(); + rslv.m_costs.pop_back(); + + remove_last_column_from_basis_tableau(j); + lean_assert(m_mpq_lar_core_solver.r_basis_is_OK()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); +} + +void lar_solver::pop_tableau() { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). + // At this moment m_column_names is already popped + for (unsigned j = A_r().column_count(); j-- > m_columns_to_ext_vars_or_term_indices.size();) + remove_column_from_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); +} void lar_solver::clean_inf_set_of_r_solver_after_pop() { - vector became_feas; - clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); - std::unordered_set basic_columns_with_changed_cost; - auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; - for (auto j: inf_index_copy) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - continue; - } - // some basic columns might become non-basic - these columns need to be made feasible - numeric_pair delta; - if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) - change_basic_x_by_delta_on_column(j, delta); + vector became_feas; + clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); + std::unordered_set basic_columns_with_changed_cost; + auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; + for (auto j: inf_index_copy) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + continue; + } + // some basic columns might become non-basic - these columns need to be made feasible + numeric_pair delta; + if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) + change_basic_x_by_delta_on_column(j, delta); + became_feas.push_back(j); + } + + for (unsigned j : became_feas) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; + m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); + m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); + } + became_feas.clear(); + for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { + lean_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); + if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) became_feas.push_back(j); - } - - for (unsigned j : became_feas) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); - m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; - m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); - m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - } - became_feas.clear(); - for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); - if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) - became_feas.push_back(j); - } + } + for (unsigned j : became_feas) + m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); + + + if (use_tableau_costs()) { for (unsigned j : became_feas) - m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - - - if (use_tableau_costs()) { - for (unsigned j : became_feas) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - for (unsigned j : basic_columns_with_changed_cost) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + for (unsigned j : basic_columns_with_changed_cost) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); } +} - void lar_solver::shrink_explanation_to_minimum(vector> & explanation) const { - // implementing quickXplain - quick_xplain::run(explanation, *this); - lean_assert(this->explanation_is_correct(explanation)); - } +void lar_solver::shrink_explanation_to_minimum(vector> & explanation) const { + // implementing quickXplain + quick_xplain::run(explanation, *this); + lean_assert(this->explanation_is_correct(explanation)); +} } // namespace lean diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 78795e0e4..655f307c3 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -60,7 +60,6 @@ class lar_solver : public column_namer { stacked_value m_infeasible_column_index; // such can be found at the initialization step stacked_value m_term_count; vector m_terms; - vector m_orig_terms; const var_index m_terms_start_index; indexed_vector m_column_buffer; std::function m_column_type_function; @@ -255,8 +254,7 @@ public: void set_low_bound_witness(var_index j, constraint_index ci); - void substitute_terms(const mpq & mult, - const vector>& left_side_with_terms, + void substitute_terms_in_linear_expression( const vector>& left_side_with_terms, vector> &left_side, mpq & right_side) const; @@ -337,6 +335,9 @@ public: bool the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const; static void register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a); + static void register_one_coeff_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j); + + bool the_left_sides_sum_to_zero(const vector> & evidence) const; bool the_right_sides_do_not_sum_to_zero(const vector> & evidence); From b92f0acae32e9248a3d240f1e08d9468278284d2 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 18 May 2017 10:56:50 -0700 Subject: [PATCH 0124/1283] fix add_constraint and substitute_terms_in_linear_expression Signed-off-by: Lev Nachmanson --- src/test/lp/lp.cpp | 7 +++++++ src/util/lp/init_lar_solver.cpp | 12 ------------ src/util/lp/lar_solver.cpp | 3 --- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 1acf4ba2a..3f9e2a4ce 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -2705,9 +2705,16 @@ void test_term() { ls.push_back(std::pair((int)1, z)); solver.add_constraint(ls, lconstraint_kind::EQ, mpq(0)); + ls.clear(); + ls.push_back(std::pair((int)1, x)); + solver.add_constraint(ls, lconstraint_kind::LT, mpq(0)); + ls.push_back(std::pair((int)2, y)); + solver.add_constraint(ls, lconstraint_kind::GT, mpq(0)); auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; std::unordered_map model; + if (status != OPTIMAL) + return; solver.get_model(model); for (auto & t : model) { diff --git a/src/util/lp/init_lar_solver.cpp b/src/util/lp/init_lar_solver.cpp index 58486e6ba..a410d04ae 100644 --- a/src/util/lp/init_lar_solver.cpp +++ b/src/util/lp/init_lar_solver.cpp @@ -204,24 +204,12 @@ void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_k } constraint_index lar_solver::add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { - this->print_linear_combination_of_column_indices(left_side_with_terms, std::cout); - std::cout << std::endl; vector> left_side; mpq rs = - right_side_parm; - std::cout << "before rs = " << rs << std::endl; substitute_terms_in_linear_expression(left_side_with_terms, left_side, rs); - std::cout << "after rs = " << rs << std::endl; - - this->print_linear_combination_of_column_indices(left_side, std::cout); - std::cout << std::endl; - unsigned term_index = add_term(left_side, zero_of_type()); constraint_index ci = m_constraints.size(); add_var_bound_on_constraint_for_term(term_index, kind_par, -rs, ci); - std::cout << "constraint = "; - print_constraint(ci, std::cout); - std::cout << std::endl; - return ci; } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 78b71ecfd..32c41b23e 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -557,9 +557,6 @@ void lar_solver::substitute_terms_in_linear_expression(const vector m_a_max) { + m_a_max = p[index].first; + } + } + } + lbool card_extension::add_assign(pb& p, literal alit) { + + TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + SASSERT(!s().inconsistent()); unsigned sz = p.size(); unsigned bound = p.k(); unsigned num_watch = p.num_watch(); @@ -316,63 +330,43 @@ namespace sat { SASSERT(value(alit) == l_false); SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); SASSERT(num_watch <= sz); + SASSERT(num_watch > 0); unsigned index = 0; - unsigned a_max = 0; - unsigned max_index = 0; + m_a_max = 0; m_pb_undef.reset(); for (; index < num_watch; ++index) { literal lit = p[index].second; if (lit == alit) { break; } - if (value(lit) == l_undef) { - m_pb_undef.push_back(index); - if (p[index].first > a_max) { - a_max = p[index].first; - max_index = index; - } - } + add_index(p, index, lit); } - - for (unsigned j = index + 1; a_max == 0 && j < num_watch; ++j) { - literal lit = p[j].second; - if (value(lit) == l_undef) { - m_pb_undef.push_back(j); - a_max = p[j].first; - max_index = j; - } - } - for (unsigned j = num_watch; a_max == 0 && j < sz; ++j) { - literal lit = p[j].second; - if (value(lit) == l_undef) { - p.swap(j, num_watch); - m_pb_undef.push_back(num_watch); - a_max = p[num_watch].first; - max_index = num_watch; - } + SASSERT(index < num_watch); + + unsigned index1 = index + 1; + for (; m_a_max == 0 && index1 < num_watch; ++index1) { + add_index(p, index1, p[index1].second); } unsigned val = p[index].first; - SASSERT(num_watch > 0); - SASSERT(index < num_watch); SASSERT(value(p[index].second) == l_false); SASSERT(val <= slack); slack -= val; // find literals to swap with: - for (unsigned j = num_watch; j < sz && slack < bound + a_max; ++j) { - if (value(p[j].second) != l_false) { + for (unsigned j = num_watch; j < sz && slack < bound + m_a_max; ++j) { + literal lit = p[j].second; + if (value(lit) != l_false) { slack += p[j].first; watch_literal(p, p[j]); p.swap(num_watch, j); - if (value(p[num_watch].second) == l_undef && a_max < p[num_watch].first) { - m_pb_undef.push_back(num_watch); - a_max = p[num_watch].first; - max_index = num_watch; - } + add_index(p, num_watch, lit); ++num_watch; } } + SASSERT(!s().inconsistent()); + DEBUG_CODE(for (auto idx : m_pb_undef) { SASSERT(value(p[idx].second) == l_undef); }); + if (slack < bound) { // maintain watching the literal slack += val; @@ -385,34 +379,30 @@ namespace sat { } // swap out the watched literal. - p.set_slack(slack); --num_watch; SASSERT(num_watch > 0); + p.set_slack(slack); p.set_num_watch(num_watch); p.swap(num_watch, index); - if (num_watch == max_index) { - max_index = index; - } - SASSERT(max_index < sz); - while (slack < bound + a_max && !s().inconsistent()) { - // variable at max-index must be assigned to true. - assign(p, p[max_index].second); - - a_max = 0; - // find the next a_max among m_pb_undef - while (!m_pb_undef.empty() && l_undef != value(p[m_pb_undef.back()].second)) { + if (slack < bound + m_a_max) { + while (!s().inconsistent() && !m_pb_undef.empty()) { + index1 = m_pb_undef.back(); + literal lit = p[index1].second; + if (slack >= bound + p[index1].first) { + break; + } m_pb_undef.pop_back(); + if (value(lit) == l_undef) { + assign(p, lit); + } } - if (m_pb_undef.empty()) { - break; - } - max_index = m_pb_undef.back(); - a_max = p[max_index].first; - m_pb_undef.pop_back(); } - return s().inconsistent() ? l_false : l_true; + + TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + + return l_undef; } void card_extension::watch_literal(pb& p, wliteral l) { @@ -467,6 +457,7 @@ namespace sat { set_conflict(p, lit); break; default: + SASSERT(validate_unit_propagation(p, lit)); m_stats.m_num_pb_propagations++; m_num_propagations_since_pop++; if (s().m_config.m_drat) { @@ -483,7 +474,7 @@ namespace sat { } void card_extension::display(std::ostream& out, pb const& p, bool values) const { - out << p.lit() << "[" << p.size() << "]"; + out << p.lit() << "[ watch: " << p.num_watch() << ", slack: " << p.slack() << "]"; if (p.lit() != null_literal && values) { out << "@(" << value(p.lit()); if (value(p.lit()) != l_undef) { @@ -514,7 +505,7 @@ namespace sat { } void card_extension::asserted_pb(literal l, ptr_vector* pbs, pb* p0) { - TRACE("sat", tout << l << " " << !is_tag_empty(pbs) << " " << (p0 != 0) << "\n";); + TRACE("sat", tout << "literal: " << l << " has pb: " << !is_tag_empty(pbs) << " p0 != 0: " << (p0 != 0) << "\n";); if (!is_tag_empty(pbs)) { ptr_vector::iterator begin = pbs->begin(); ptr_vector::iterator it = begin, it2 = it, end = pbs->end(); @@ -524,20 +515,28 @@ namespace sat { continue; } switch (add_assign(p, ~l)) { - case l_false: // conflict - for (; it != end; ++it, ++it2) { - *it2 = *it; - } - SASSERT(s().inconsistent()); - pbs->set_end(it2); - return; case l_true: // unit propagation, keep watching the literal if (it2 != it) { *it2 = *it; } ++it2; break; + case l_false: // conflict. + SASSERT(s().inconsistent()); + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + pbs->set_end(it2); + return; case l_undef: // watch literal was swapped + if (s().inconsistent()) { + ++it; + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + pbs->set_end(it2); + return; + } break; } } @@ -844,6 +843,7 @@ namespace sat { literal consequent = s().m_not_l; justification js = s().m_conflict; TRACE("sat", tout << consequent << " " << js << "\n";); + TRACE("sat", s().display(tout);); m_conflict_lvl = s().get_max_lvl(consequent, js); if (consequent != null_literal) { consequent.neg(); @@ -942,7 +942,7 @@ namespace sat { m_bound += offset; inc_coeff(consequent, offset); get_pb_antecedents(consequent, p, m_lemma); - TRACE("sat", tout << m_lemma << "\n";); + TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";); for (unsigned i = 0; i < m_lemma.size(); ++i) { process_antecedent(~m_lemma[i], offset); } @@ -989,6 +989,7 @@ namespace sat { SASSERT(lvl(v) == m_conflict_lvl); s().reset_mark(v); --idx; + TRACE("sat", tout << "Unmark: v" << v << "\n";); --m_num_marks; js = s().m_justification[v]; offset = get_abs_coeff(v); @@ -1153,6 +1154,7 @@ namespace sat { if (level > 0 && !s().is_marked(v) && level == m_conflict_lvl) { s().mark(v); + TRACE("sat", tout << "Mark: v" << v << "\n";); ++m_num_marks; } inc_coeff(l, offset); @@ -1347,20 +1349,12 @@ namespace sat { void card_extension::get_pb_antecedents(literal l, pb const& p, literal_vector& r) { if (p.lit() != null_literal) r.push_back(p.lit()); SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); - unsigned k = p.k(); - unsigned max_sum = p.max_sum(); - for (unsigned i = p.size(); i > 0 && max_sum >= k; ) { - --i; + TRACE("sat", display(tout, p, true);); + for (unsigned i = p.num_watch(); i < p.size(); ++i) { literal lit = p[i].second; - if (lit == l) { - max_sum -= p[i].first; - } - else if (value(lit) == l_false) { - r.push_back(~p[i].second); - max_sum -= p[i].first; - } + SASSERT(l_false == value(lit)); + r.push_back(~lit); } - SASSERT(max_sum < k); } void card_extension::get_card_antecedents(literal l, card const& c, literal_vector& r) { @@ -1776,6 +1770,31 @@ namespace sat { } return true; } + bool card_extension::validate_unit_propagation(pb const& p, literal alit) { + if (p.lit() != null_literal && value(p.lit()) != l_true) return false; + + unsigned k = p.k(); + unsigned sum = 0; + unsigned a_min = 0; + TRACE("sat", display(tout << "validate: " << alit << "\n", p, true);); + for (unsigned i = 0; i < p.size(); ++i) { + literal lit = p[i].second; + lbool val = value(lit); + if (val == l_false) { + // no-op + } + else if (lit == alit) { + a_min = p[i].first; + sum += p[i].first; + } + else { + sum += p[i].first; + } + } + return sum < k + a_min; + return true; + } + bool card_extension::validate_lemma() { int val = -m_bound; normalize_active_coeffs(); diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index f7e54b843..41219fae5 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -232,10 +232,12 @@ namespace sat { // pb functionality + unsigned m_a_max; void copy_pb(card_extension& result); void asserted_pb(literal l, ptr_vector* pbs, pb* p); void init_watch(pb& p, bool is_true); lbool add_assign(pb& p, literal alit); + void add_index(pb& p, unsigned index, literal lit); void watch_literal(pb& p, wliteral lit); void clear_watch(pb& p); void set_conflict(pb& p, literal lit); @@ -280,6 +282,7 @@ namespace sat { bool validate_assign(literal_vector const& lits, literal lit); bool validate_lemma(); bool validate_unit_propagation(card const& c); + bool validate_unit_propagation(pb const& p, literal lit); bool validate_conflict(literal_vector const& lits, ineq& p); ineq m_A, m_B, m_C; From d1fec7c029f928d3e270c0f93501607019a16ec0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 21 May 2017 15:39:05 -0700 Subject: [PATCH 0127/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 112 +++++++++++++++++++------- src/sat/card_extension.cpp | 65 ++++++++++----- src/tactic/portfolio/pb2bv_solver.cpp | 8 +- 3 files changed, 135 insertions(+), 50 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 5cef19234..ccf03a943 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -54,6 +54,8 @@ struct pb2bv_rewriter::imp { vector m_coeffs; bool m_keep_cardinality_constraints; bool m_keep_pb_constraints; + bool m_pb_num_system; + bool m_pb_totalizer; unsigned m_min_arity; template @@ -114,23 +116,24 @@ struct pb2bv_rewriter::imp { return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m); } -#if 0 - expr_ref result(m); - switch (is_le) { - case l_true: if (mk_le_tot(sz, args, k, result)) return result; else break; - case l_false: if (mk_ge_tot(sz, args, k, result)) return result; else break; - case l_undef: break; + if (m_pb_totalizer) { + expr_ref result(m); + switch (is_le) { + case l_true: if (mk_le_tot(sz, args, k, result)) return result; else break; + case l_false: if (mk_ge_tot(sz, args, k, result)) return result; else break; + case l_undef: break; + } + } + + if (m_pb_num_system) { + expr_ref result(m); + switch (is_le) { + case l_true: if (mk_le(sz, args, k, result)) return result; else break; + case l_false: if (mk_ge(sz, args, k, result)) return result; else break; + case l_undef: if (mk_eq(sz, args, k, result)) return result; else break; + } } -#endif -#if 0 - expr_ref result(m); - switch (is_le) { - case l_true: if (mk_le(sz, args, k, result)) return result; else break; - case l_false: if (mk_ge(sz, args, k, result)) return result; else break; - case l_undef: if (mk_eq(sz, args, k, result)) return result; else break; - } -#endif // fall back to divide and conquer encoding. SASSERT(k.is_pos()); expr_ref zero(m), bound(m); @@ -397,22 +400,30 @@ struct pb2bv_rewriter::imp { for (unsigned j = 0; j + lim - 1 < out.size(); j += n) { expr_ref tmp(m); tmp = out[j + lim - 1]; - if (j + n < out.size()) { - tmp = m.mk_and(tmp, m.mk_not(out[j + n])); + if (j + n - 1 < out.size()) { + tmp = m.mk_and(tmp, m.mk_not(out[j + n - 1])); } ors.push_back(tmp); } return ::mk_or(ors); } + // x0 + 5x1 + 3x2 >= k + // x0 x1 x1 -> s0 s1 s2 + // s2 x1 x2 -> s3 s4 s5 + // k = 7: s5 or (s4 & not s2 & s0) + // k = 6: s4 + // k = 5: s4 or (s3 & not s2 & s1) + // k = 4: s4 or (s3 & not s2 & s0) + // k = 3: s3 + // bool mk_ge(unsigned sz, expr * const* args, rational bound, expr_ref& result) { if (!create_basis()) return false; if (!bound.is_unsigned()) return false; vector coeffs(m_coeffs); result = m.mk_true(); expr_ref_vector carry(m), new_carry(m); - for (unsigned i = 0; i < m_base.size(); ++i) { - rational b_i = m_base[i]; + for (rational b_i : m_base) { unsigned B = b_i.get_unsigned(); unsigned d_i = (bound % b_i).get_unsigned(); bound = div(bound, b_i); @@ -425,16 +436,16 @@ struct pb2bv_rewriter::imp { coeffs[j] = div(coeffs[j], b_i); } TRACE("pb", tout << "Carry: " << carry << "\n"; - for (unsigned j = 0; j < coeffs.size(); ++j) tout << coeffs[j] << " "; + for (auto c : coeffs) tout << c << " "; tout << "\n"; ); ptr_vector out; m_sort.sorting(carry.size(), carry.c_ptr(), out); - + expr_ref gt = mod_ge(out, B, d_i + 1); expr_ref ge = mod_ge(out, B, d_i); result = mk_or(gt, mk_and(ge, result)); - TRACE("pb", tout << result << "\n";); + TRACE("pb", tout << "b: " << b_i << " d: " << d_i << " gt: " << gt << " ge: " << ge << " " << result << "\n";); new_carry.reset(); for (unsigned j = B - 1; j < out.size(); j += B) { @@ -443,7 +454,10 @@ struct pb2bv_rewriter::imp { carry.reset(); carry.append(new_carry); } - TRACE("pb", tout << result << "\n";); + if (!carry.empty()) { + result = m.mk_or(result, carry[0].get()); + } + TRACE("pb", tout << "Carry: " << carry << " result: " << result << "\n";); return true; } @@ -567,6 +581,8 @@ struct pb2bv_rewriter::imp { m_args(m), m_keep_cardinality_constraints(false), m_keep_pb_constraints(false), + m_pb_num_system(false), + m_pb_totalizer(false), m_min_arity(2) {} @@ -761,6 +777,14 @@ struct pb2bv_rewriter::imp { void keep_pb_constraints(bool f) { m_keep_pb_constraints = f; } + + void pb_num_system(bool f) { + m_pb_num_system = f; + } + + void pb_totalizer(bool f) { + m_pb_totalizer = f; + } }; struct card2bv_rewriter_cfg : public default_rewriter_cfg { @@ -774,6 +798,8 @@ 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 keep_pb_constraints(bool f) { m_r.keep_pb_constraints(f); } + void pb_num_system(bool f) { m_r.pb_num_system(f); } + void pb_totalizer(bool f) { m_r.pb_totalizer(f); } }; class card_pb_rewriter : public rewriter_tpl { @@ -784,27 +810,59 @@ struct pb2bv_rewriter::imp { m_cfg(i, m) {} void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); } void keep_pb_constraints(bool f) { m_cfg.keep_pb_constraints(f); } + void pb_num_system(bool f) { m_cfg.pb_num_system(f); } + void pb_totalizer(bool f) { m_cfg.pb_totalizer(f); } }; card_pb_rewriter m_rw; + bool keep_cardinality() const { + params_ref const& p = m_params; + return + p.get_bool("keep_cardinality_constraints", false) || + p.get_bool("sat.cardinality.solver", false) || + p.get_bool("cardinality.solver", false) || keep_pb(); + } + + bool keep_pb() const { + params_ref const& p = m_params; + return + p.get_bool("keep_pb_constraints", false) || + p.get_bool("sat.pb.solver", false) || + p.get_bool("pb.solver", false); + } + + bool pb_num_system() const { + return m_params.get_bool("pb_num_system", false); + } + + bool pb_totalizer() const { + return m_params.get_bool("pb_totalizer", false); + } + imp(ast_manager& m, params_ref const& p): m(m), m_params(p), m_lemmas(m), m_fresh(m), m_num_translated(0), m_rw(*this, m) { - m_rw.keep_cardinality_constraints(p.get_bool("keep_cardinality_constraints", false)); - m_rw.keep_pb_constraints(p.get_bool("keep_pb_constraints", false)); + m_rw.keep_cardinality_constraints(keep_cardinality()); + m_rw.keep_pb_constraints(keep_pb()); + m_rw.pb_num_system(pb_num_system()); + m_rw.pb_totalizer(pb_totalizer()); } void updt_params(params_ref const & p) { m_params.append(p); - m_rw.keep_cardinality_constraints(m_params.get_bool("keep_cardinality_constraints", false)); - m_rw.keep_pb_constraints(m_params.get_bool("keep_pb_constraints", false)); + m_rw.keep_cardinality_constraints(keep_cardinality()); + m_rw.keep_pb_constraints(keep_pb()); + m_rw.pb_num_system(pb_num_system()); + m_rw.pb_totalizer(pb_totalizer()); } 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_pb_constraints", CPK_BOOL, "(default: true) retain pb constraints (don't bit-blast them) and use built-in pb solver"); + r.insert("pb_num_system", CPK_BOOL, "(default: false) use pb number system encoding"); + r.insert("pb_totalizer", CPK_BOOL, "(default: false) use pb totalizer encoding"); } unsigned get_num_steps() const { return m_rw.get_num_steps(); } diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index b91018217..c328a30cd 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -250,7 +250,7 @@ namespace sat { p.swap(i, j); } if (slack < bound) { - slack += p[i].first; + slack += p[j].first; ++num_watch; } ++j; @@ -267,7 +267,7 @@ namespace sat { if (slack < bound) { literal lit = p[j].second; SASSERT(value(p[j].second) == l_false); - for (unsigned i = j + 1; j < sz; ++i) { + for (unsigned i = j + 1; i < sz; ++i) { if (lvl(lit) < lvl(p[i].second)) { lit = p[i].second; } @@ -386,16 +386,24 @@ namespace sat { p.swap(num_watch, index); if (slack < bound + m_a_max) { - while (!s().inconsistent() && !m_pb_undef.empty()) { + TRACE("sat", display(tout, p, false); for(auto j : m_pb_undef) tout << j << "\n";); + literal_vector to_assign; + while (!m_pb_undef.empty()) { index1 = m_pb_undef.back(); literal lit = p[index1].second; + TRACE("sat", tout << index1 << " " << lit << "\n";); if (slack >= bound + p[index1].first) { break; } m_pb_undef.pop_back(); + to_assign.push_back(lit); + } + + for (literal lit : to_assign) { + if (s().inconsistent()) break; if (value(lit) == l_undef) { assign(p, lit); - } + } } } @@ -474,7 +482,8 @@ namespace sat { } void card_extension::display(std::ostream& out, pb const& p, bool values) const { - out << p.lit() << "[ watch: " << p.num_watch() << ", slack: " << p.slack() << "]"; + if (p.lit() != null_literal) out << p.lit(); + out << "[watch: " << p.num_watch() << ", slack: " << p.slack() << "]"; if (p.lit() != null_literal && values) { out << "@(" << value(p.lit()); if (value(p.lit()) != l_undef) { @@ -1350,7 +1359,25 @@ namespace sat { if (p.lit() != null_literal) r.push_back(p.lit()); SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); TRACE("sat", display(tout, p, true);); - for (unsigned i = p.num_watch(); i < p.size(); ++i) { + + // unsigned coeff = get_coeff(p, l); + unsigned coeff = 0; + for (unsigned j = 0; j < p.num_watch(); ++j) { + if (p[j].second == l) { + coeff = p[j].first; + break; + } + } + unsigned slack = p.slack() - coeff; + unsigned i = p.num_watch(); + + // skip entries that are not required for unit propagation. + // slack - coeff + w_head < k + unsigned h = 0; + for (; i < p.size() && p[i].first + h + slack < p.k(); ++i) { + h += p[i].first; + } + for (; i < p.size(); ++i) { literal lit = p[i].second; SASSERT(l_false == value(lit)); r.push_back(~lit); @@ -1714,7 +1741,9 @@ namespace sat { std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const { if (is_card_index(idx)) { card& c = index2card(idx); - out << "bound " << c.lit() << ": "; + out << "bound "; + if (c.lit() != null_literal) out << c.lit(); + out << ": "; for (unsigned i = 0; i < c.size(); ++i) { out << c[i] << " "; } @@ -1722,14 +1751,18 @@ namespace sat { } else if (is_xor_index(idx)) { xor& x = index2xor(idx); - out << "xor " << x.lit() << ": "; + out << "xor "; + if (x.lit() != null_literal) out << x.lit(); + out << ": "; for (unsigned i = 0; i < x.size(); ++i) { out << x[i] << " "; } } else if (is_pb_index(idx)) { pb& p = index2pb(idx); - out << "pb " << p.lit() << ": "; + out << "pb "; + if (p.lit() != null_literal) out << p.lit(); + out << ": "; for (unsigned i = 0; i < p.size(); ++i) { out << p[i].first << "*" << p[i].second << " "; } @@ -1773,26 +1806,16 @@ namespace sat { bool card_extension::validate_unit_propagation(pb const& p, literal alit) { if (p.lit() != null_literal && value(p.lit()) != l_true) return false; - unsigned k = p.k(); unsigned sum = 0; - unsigned a_min = 0; TRACE("sat", display(tout << "validate: " << alit << "\n", p, true);); for (unsigned i = 0; i < p.size(); ++i) { literal lit = p[i].second; lbool val = value(lit); - if (val == l_false) { - // no-op - } - else if (lit == alit) { - a_min = p[i].first; - sum += p[i].first; - } - else { + if (val != l_false && lit != alit) { sum += p[i].first; } } - return sum < k + a_min; - return true; + return sum < p.k(); } bool card_extension::validate_lemma() { diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 10acc0bb6..c8aa82e97 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -20,6 +20,7 @@ Notes: #include "solver_na2as.h" #include "tactic.h" #include "pb2bv_rewriter.h" +#include "th_rewriter.h" #include "filter_model_converter.h" #include "ast_pp.h" #include "model_smt2_pp.h" @@ -29,6 +30,7 @@ class pb2bv_solver : public solver_na2as { params_ref m_params; mutable expr_ref_vector m_assertions; mutable ref m_solver; + mutable th_rewriter m_th_rewriter; mutable pb2bv_rewriter m_rewriter; public: @@ -39,6 +41,7 @@ public: m_params(p), m_assertions(m), m_solver(s), + m_th_rewriter(m, p), m_rewriter(m, p) { } @@ -121,10 +124,11 @@ public: private: void flush_assertions() const { proof_ref proof(m); - expr_ref fml(m); + expr_ref fml1(m), fml(m); expr_ref_vector fmls(m); for (unsigned i = 0; i < m_assertions.size(); ++i) { - m_rewriter(m_assertions[i].get(), fml, proof); + m_th_rewriter(m_assertions[i].get(), fml1, proof); + m_rewriter(fml1, fml, proof); m_solver->assert_expr(fml); } m_rewriter.flush_side_constraints(fmls); From 71eb7e81b5b6805b891f1c854993da873934bec8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 May 2017 12:52:53 -0700 Subject: [PATCH 0128/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 8 +++----- src/util/sorting_network.h | 30 ++++++++++++++--------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index ccf03a943..b402aeb41 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -423,6 +423,7 @@ struct pb2bv_rewriter::imp { vector coeffs(m_coeffs); result = m.mk_true(); expr_ref_vector carry(m), new_carry(m); + m_base.push_back(bound + rational::one()); for (rational b_i : m_base) { unsigned B = b_i.get_unsigned(); unsigned d_i = (bound % b_i).get_unsigned(); @@ -454,14 +455,11 @@ struct pb2bv_rewriter::imp { carry.reset(); carry.append(new_carry); } - if (!carry.empty()) { - result = m.mk_or(result, carry[0].get()); - } - TRACE("pb", tout << "Carry: " << carry << " result: " << result << "\n";); + TRACE("pb", tout << "bound: " << bound << " Carry: " << carry << " result: " << result << "\n";); return true; } - expr_ref mk_and(expr_ref& a, expr_ref& b) { + expr_ref mk_and(expr_ref& a, expr_ref& b) { if (m.is_true(a)) return b; if (m.is_true(b)) return a; if (m.is_false(a)) return a; diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 33514730f..2a0f8b37d 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -337,7 +337,7 @@ Notes: } literal mk_at_most_1(bool full, unsigned n, literal const* xs, literal_vector& ors, bool use_ors) { - TRACE("pb", tout << (full?"full":"partial") << " "; + TRACE("pb_verbose", tout << (full?"full":"partial") << " "; for (unsigned i = 0; i < n; ++i) tout << xs[i] << " "; tout << "\n";); @@ -513,7 +513,7 @@ Notes: for (unsigned i = 0; i < N; ++i) { in.push_back(ctx.mk_not(xs[i])); } - TRACE("pb", + TRACE("pb_verbose", pp(tout << N << ": ", in); tout << " ~ " << k << "\n";); return true; @@ -595,7 +595,7 @@ Notes: } void card(unsigned k, unsigned n, literal const* xs, literal_vector& out) { - TRACE("pb", tout << "card k: " << k << " n: " << n << "\n";); + TRACE("pb_verbose", tout << "card k: " << k << " n: " << n << "\n";); if (n <= k) { psort_nw::sorting(n, xs, out); } @@ -609,7 +609,7 @@ Notes: card(k, n-l, xs + l, out2); smerge(k, out1.size(), out1.c_ptr(), out2.size(), out2.c_ptr(), out); } - TRACE("pb", tout << "card k: " << k << " n: " << n << "\n"; + TRACE("pb_verbose", tout << "card k: " << k << " n: " << n << "\n"; pp(tout << "in:", n, xs) << "\n"; pp(tout << "out:", out) << "\n";); @@ -637,7 +637,7 @@ Notes: void merge(unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb", tout << "merge a: " << a << " b: " << b << "\n";); + TRACE("pb_verbose", tout << "merge a: " << a << " b: " << b << "\n";); if (a == 1 && b == 1) { literal y1 = mk_max(as[0], bs[0]); literal y2 = mk_min(as[0], bs[0]); @@ -672,7 +672,7 @@ Notes: odd_b.size(), odd_b.c_ptr(), out2); interleave(out1, out2, out); } - TRACE("pb", tout << "merge a: " << a << " b: " << b << "\n"; + 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";); @@ -709,7 +709,7 @@ Notes: void interleave(literal_vector const& as, literal_vector const& bs, literal_vector& out) { - TRACE("pb", tout << "interleave: " << as.size() << " " << bs.size() << "\n";); + TRACE("pb_verbose", tout << "interleave: " << as.size() << " " << bs.size() << "\n";); SASSERT(as.size() >= bs.size()); SASSERT(as.size() <= bs.size() + 2); SASSERT(!as.empty()); @@ -729,7 +729,7 @@ Notes: out.push_back(as[sz+1]); } SASSERT(out.size() == as.size() + bs.size()); - TRACE("pb", tout << "interleave: " << as.size() << " " << bs.size() << "\n"; + 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";); @@ -741,7 +741,7 @@ Notes: public: void sorting(unsigned n, literal const* xs, literal_vector& out) { - TRACE("pb", tout << "sorting: " << n << "\n";); + TRACE("pb_verbose", tout << "sorting: " << n << "\n";); switch(n) { case 0: break; @@ -766,7 +766,7 @@ Notes: } break; } - TRACE("pb", tout << "sorting: " << n << "\n"; + TRACE("pb_verbose", tout << "sorting: " << n << "\n"; pp(tout << "in:", n, xs) << "\n"; pp(tout << "out:", out) << "\n";); } @@ -802,7 +802,7 @@ Notes: unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";); + TRACE("pb_verbose", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";); if (a == 1 && b == 1 && c == 1) { literal y = mk_max(as[0], bs[0]); if (m_t != GE) { @@ -876,7 +876,7 @@ Notes: out.push_back(y); } } - TRACE("pb", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n"; + 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"; @@ -920,7 +920,7 @@ Notes: unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb", tout << "dsmerge: c:" << c << " a:" << a << " b:" << b << "\n";); + TRACE("pb_verbose", tout << "dsmerge: c:" << c << " a:" << a << " b:" << b << "\n";); SASSERT(a <= c); SASSERT(b <= c); SASSERT(a + b >= c); @@ -979,7 +979,7 @@ Notes: void dsorting(unsigned m, unsigned n, literal const* xs, literal_vector& out) { - TRACE("pb", tout << "dsorting m: " << m << " n: " << n << "\n";); + TRACE("pb_verbose", tout << "dsorting m: " << m << " n: " << n << "\n";); SASSERT(m <= n); literal_vector lits; for (unsigned i = 0; i < m; ++i) { @@ -1014,7 +1014,7 @@ Notes: void add_subset(bool polarity, unsigned k, unsigned offset, literal_vector& lits, unsigned n, literal const* xs) { - TRACE("pb", tout << "k:" << k << " offset: " << offset << " n: " << n << " "; + TRACE("pb_verbose", tout << "k:" << k << " offset: " << offset << " n: " << n << " "; pp(tout, lits) << "\n";); SASSERT(k + offset <= n); if (k == 0) { From f9f0b2221d81e1dc950a26ee0d38cc2e992526b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 May 2017 14:27:34 -0700 Subject: [PATCH 0129/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 8 ++++-- src/sat/card_extension.cpp | 38 +++-------------------------- src/sat/sat_solver.cpp | 35 ++++++++++++++------------ 3 files changed, 29 insertions(+), 52 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index b402aeb41..fd9f5e59f 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -26,6 +26,7 @@ Notes: #include"ast_pp.h" #include"lbool.h" #include"uint_set.h" +#include"gparams.h" const unsigned g_primes[7] = { 2, 3, 5, 7, 11, 13, 17}; @@ -819,7 +820,9 @@ struct pb2bv_rewriter::imp { return p.get_bool("keep_cardinality_constraints", false) || p.get_bool("sat.cardinality.solver", false) || - p.get_bool("cardinality.solver", false) || keep_pb(); + p.get_bool("cardinality.solver", false) || + gparams::get_module("sat").get_bool("cardinality.solver", false) || + keep_pb(); } bool keep_pb() const { @@ -827,7 +830,8 @@ struct pb2bv_rewriter::imp { return p.get_bool("keep_pb_constraints", false) || p.get_bool("sat.pb.solver", false) || - p.get_bool("pb.solver", false); + p.get_bool("pb.solver", false) || + gparams::get_module("sat").get_bool("pb.solver", false); } bool pb_num_system() const { diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index c328a30cd..5032da6ff 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -1025,7 +1025,6 @@ namespace sat { m_lemma.reset(); -#if 1 m_lemma.push_back(null_literal); for (unsigned i = 0; 0 <= slack && i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; @@ -1048,6 +1047,7 @@ namespace sat { } } +#if 0 if (jus.size() > 1) { std::cout << jus.size() << "\n"; for (unsigned i = 0; i < jus.size(); ++i) { @@ -1057,6 +1057,7 @@ namespace sat { active2pb(m_A); display(std::cout, m_A); } +#endif if (slack >= 0) { @@ -1067,7 +1068,7 @@ namespace sat { if (m_lemma[0] == null_literal) { m_lemma[0] = m_lemma.back(); m_lemma.pop_back(); - unsigned level = lvl(m_lemma[0]); + unsigned level = m_lemma.empty() ? 0 : lvl(m_lemma[0]); for (unsigned i = 1; i < m_lemma.size(); ++i) { if (lvl(m_lemma[i]) > level) { level = lvl(m_lemma[i]); @@ -1076,37 +1077,6 @@ namespace sat { } IF_VERBOSE(2, verbose_stream() << "(sat.card set level to " << level << " < " << m_conflict_lvl << ")\n";); } -#else - ++idx; - while (0 <= slack) { - literal lit = lits[idx]; - bool_var v = lit.var(); - if (m_active_var_set.contains(v)) { - int coeff = get_coeff(v); - if (coeff < 0 && !lit.sign()) { - slack += coeff; - m_lemma.push_back(~lit); - } - else if (coeff > 0 && lit.sign()) { - slack -= coeff; - m_lemma.push_back(~lit); - } - } - if (idx == 0 && slack >= 0) { - IF_VERBOSE(2, verbose_stream() << "(sat.card non-asserting)\n";); - goto bail_out; - } - SASSERT(idx > 0 || slack < 0); - --idx; - } - if (m_lemma.size() >= 2 && lvl(m_lemma[1]) == m_conflict_lvl) { - // TRACE("sat", tout << "Bail out on no progress " << lit << "\n";); - IF_VERBOSE(2, verbose_stream() << "(sat.card bail non-asserting resolvent)\n";); - goto bail_out; - } - -#endif - SASSERT(slack < 0); @@ -1118,7 +1088,7 @@ namespace sat { svector ps; // TBD fill in s().m_drat.add(m_lemma, ps); } - + s().m_lemma.reset(); s().m_lemma.append(m_lemma); for (unsigned i = 1; i < m_lemma.size(); ++i) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a292ff202..ac491d6c2 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1937,23 +1937,25 @@ namespace sat { void solver::learn_lemma_and_backjump() { TRACE("sat_lemma", tout << "new lemma size: " << m_lemma.size() << "\n" << m_lemma << "\n";); - if (m_config.m_minimize_lemmas) { - minimize_lemma(); - reset_lemma_var_marks(); - if (m_config.m_dyn_sub_res) - dyn_sub_res(); - TRACE("sat_lemma", tout << "new lemma (after minimization) size: " << m_lemma.size() << "\n" << m_lemma << "\n";); - } - else - reset_lemma_var_marks(); - - literal_vector::iterator it = m_lemma.begin(); - literal_vector::iterator end = m_lemma.end(); unsigned new_scope_lvl = 0; - ++it; - for(; it != end; ++it) { - bool_var var = (*it).var(); - new_scope_lvl = std::max(new_scope_lvl, lvl(var)); + if (!m_lemma.empty()) { + if (m_config.m_minimize_lemmas) { + minimize_lemma(); + reset_lemma_var_marks(); + if (m_config.m_dyn_sub_res) + dyn_sub_res(); + TRACE("sat_lemma", tout << "new lemma (after minimization) size: " << m_lemma.size() << "\n" << m_lemma << "\n";); + } + else + reset_lemma_var_marks(); + + literal_vector::iterator it = m_lemma.begin(); + literal_vector::iterator end = m_lemma.end(); + ++it; + for(; it != end; ++it) { + bool_var var = (*it).var(); + new_scope_lvl = std::max(new_scope_lvl, lvl(var)); + } } unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.c_ptr()); @@ -2389,6 +2391,7 @@ namespace sat { assigned at level 0. */ void solver::minimize_lemma() { + SASSERT(!m_lemma.empty()); SASSERT(m_unmark.empty()); //m_unmark.reset(); updt_lemma_lvl_set(); From 77b2a015a275315fd150b2f1767062a3cb2d726a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 May 2017 17:47:46 -0700 Subject: [PATCH 0130/1283] rewrite pb Signed-off-by: Nikolaj Bjorner --- src/ast/ast_pp_util.cpp | 7 +++-- src/ast/rewriter/pb2bv_rewriter.cpp | 1 + src/ast/rewriter/pb_rewriter.cpp | 43 +++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index f953dbf0e..3021b702b 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -44,8 +44,11 @@ void ast_pp_util::display_decls(std::ostream& out) { } n = coll.get_num_decls(); for (unsigned i = 0; i < n; ++i) { - ast_smt2_pp(out, coll.get_func_decls()[i], env); - out << "\n"; + func_decl* f = coll.get_func_decls()[i]; + if (f->get_family_id() == null_family_id) { + ast_smt2_pp(out, f, env); + out << "\n"; + } } } diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index fd9f5e59f..aedd62081 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -504,6 +504,7 @@ struct pb2bv_rewriter::imp { for (unsigned i = 0; i < sz; ++i) { m_coeffs.push_back(pb.get_coeff(f, i)); } + CTRACE("pb", k.is_neg(), tout << expr_ref(m.mk_app(f, sz, args), m) << "\n";); SASSERT(!k.is_neg()); switch (kind) { case OP_PB_GE: diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index b193a8a45..7d1eebb5c 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -232,6 +232,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons } bool is_eq = f->get_decl_kind() == OP_PB_EQ; + br_status st = BR_DONE; pb_ast_rewriter_util pbu(m); pb_rewriter_util util(pbu); @@ -249,11 +250,14 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons default: { bool all_unit = true; unsigned sz = vec.size(); + rational slack(0); m_args.reset(); m_coeffs.reset(); for (unsigned i = 0; i < sz; ++i) { m_args.push_back(vec[i].first); m_coeffs.push_back(vec[i].second); + SASSERT(vec[i].second.is_pos()); + slack += vec[i].second; all_unit &= m_coeffs.back().is_one(); } if (is_eq) { @@ -271,7 +275,42 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons result = mk_and(m, sz, m_args.c_ptr()); } else { - result = m_util.mk_ge(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k); + expr_ref_vector conj(m), disj(m); + for (unsigned i = 0; i < m_args.size(); ++i) { + rational& c = m_coeffs[i]; + if (slack < c + k) { + conj.push_back(m_args[i]); + slack -= c; + k -= c; + } + else if (c >= k) { + slack -= c; + disj.push_back(m_args[i]); + } + else { + continue; + } + m_args[i] = m_args.back(); + m_coeffs[i] = m_coeffs.back(); + --i; + m_args.pop_back(); + m_coeffs.pop_back(); + } + sz = m_coeffs.size(); + if (slack < k) { + conj.push_back(m.mk_false()); + } + else if (k.is_pos() && sz > 0) { + conj.push_back(m_util.mk_ge(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k)); + } + result = mk_and(conj); + if (!disj.empty()) { + disj.push_back(result); + result = mk_or(disj); + } + if (!disj.empty() || conj.size() > 1) { + st = BR_REWRITE3; + } } break; } @@ -286,7 +325,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons TRACE("pb_validate", validate_rewrite(f, num_args, args, result);); - return BR_DONE; + return st; } From 9633c16d753b66f4482acdc3da6efba50e3f1053 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 May 2017 10:52:14 -0700 Subject: [PATCH 0131/1283] local updates Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index d5abfd747..d56d864dd 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -1932,15 +1932,13 @@ namespace sat { for (unsigned i = 0; i < m_candidates.size(); ++i) { bool_var v = m_candidates[i].m_var; literal p = get_root(v); - if (p != null_literal && p.var() != v && !m_s.is_external(v) && !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { + if (p != null_literal && p.var() != v && !m_s.is_external(v) && + !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { to_elim.push_back(v); roots[v] = p; SASSERT(get_parent(p) == p); set_parent(~p, ~p); SASSERT(get_parent(~p) == ~p); - if (v == 5904 || v == 5903) { - std::cout << lit << " " << p << "\n"; - } } } IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); From 1f425824ff78a3595cbef01f9a9cdf9c6a9c8e16 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 23 May 2017 15:46:53 -0700 Subject: [PATCH 0132/1283] adding stub check_int_feasibility() Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 4 ++++ src/util/lp/lar_solver.h | 3 ++- src/util/lp/lp_settings.h | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 18b901104..b6315fe5c 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1380,6 +1380,10 @@ void lar_solver::shrink_explanation_to_minimum(vectorexplanation_is_correct(explanation)); } + +final_check_status check_int_feasibility() { + return final_check_status::GIVEUP; +} } // namespace lean diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index bd0fe8fac..6fba62fe8 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -401,6 +401,7 @@ public: unsigned ext_var = m_columns_to_ext_vars_or_term_indices[j]; return m_ext_vars_to_columns.find(ext_var)->second.is_integer(); } - inline bool column_is_real(unsigned j) const { return !column_is_integer(j); } + inline bool column_is_real(unsigned j) const { return !column_is_integer(j); } + final_check_status check_int_feasibility(); }; } diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index 6b6aba2ad..c081a84ff 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -16,6 +16,13 @@ namespace lean { typedef unsigned var_index; typedef unsigned constraint_index; typedef unsigned row_index; + +enum class final_check_status { + DONE, + CONTINUE, + GIVEUP +}; + enum class column_type { free_column = 0, low_bound = 1, From f1ca1de4084d88d12d17c733fddc84d5e0bb1a74 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 May 2017 16:12:46 -0700 Subject: [PATCH 0133/1283] initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/util/lp/CMakeLists.txt | 3 +- src/util/lp/nra_solver.cpp | 31 ++++++++++++++++ src/util/lp/nra_solver.h | 47 ++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/util/lp/nra_solver.cpp create mode 100644 src/util/lp/nra_solver.h diff --git a/contrib/cmake/src/util/lp/CMakeLists.txt b/contrib/cmake/src/util/lp/CMakeLists.txt index ec9a2e137..75051d68c 100644 --- a/contrib/cmake/src/util/lp/CMakeLists.txt +++ b/contrib/cmake/src/util/lp/CMakeLists.txt @@ -19,8 +19,9 @@ z3_add_component(lp lp_solver_instances.cpp lu_instances.cpp matrix_instances.cpp + nra_solver.cpp permutation_matrix_instances.cpp - quick_xplain.cpp + quick_xplain.cpp row_eta_matrix_instances.cpp scaler_instances.cpp sparse_matrix_instances.cpp diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp new file mode 100644 index 000000000..cb47b36e5 --- /dev/null +++ b/src/util/lp/nra_solver.cpp @@ -0,0 +1,31 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/lp/nra_solver.h" + +namespace lp { + + struct nra_solver::imp { + lean::lar_solver& s; + imp(lean::lar_solver& s): s(s) {} + + lean::final_check_status check_feasible() { + return lean::final_check_status::GIVEUP; + } + }; + + nra_solver::nra_solver(lean::lar_solver& s) { + m_imp = alloc(imp, s); + } + + nra_solver::~nra_solver() { + dealloc(m_imp); + } + + lean::final_check_status nra_solver::check_feasible() { + return m_imp->check_feasible(); + } +} diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h new file mode 100644 index 000000000..bae76b0d1 --- /dev/null +++ b/src/util/lp/nra_solver.h @@ -0,0 +1,47 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/vector.h" +#include "util/lp/lp_settings.h" +#include "util/lp/lar_solver.h" + +namespace lean { + class lar_solver; +} + +namespace lp { + + class nra_solver { + struct imp; + imp* m_imp; + + public: + + nra_solver(lean::lar_solver& s); + + ~nra_solver(); + + /* + \brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1] + The variable v is equal to the product of variables vs. + */ + void add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs); + + /* + \brief Check feasiblity of linear constraints augmented by polynomial definitions + that are added. + */ + lean::final_check_status check_feasible(); + + /* + \brief push and pop scope. + Monomial definitions are retraced when popping scope. + */ + void push(); + + void pop(unsigned n); + }; +} From db54cab8b26d445f23204af9da4a642d4f412f1b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 May 2017 16:26:46 -0700 Subject: [PATCH 0134/1283] initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner --- src/util/lp/nra_solver.cpp | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index cb47b36e5..08b17030c 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -10,11 +10,35 @@ namespace lp { struct nra_solver::imp { lean::lar_solver& s; - imp(lean::lar_solver& s): s(s) {} + + svector m_vars; + vector> m_monomials; + unsigned_vector m_lim; + + imp(lean::lar_solver& s): s(s) { + m_lim.push_back(0); + } lean::final_check_status check_feasible() { return lean::final_check_status::GIVEUP; } + + void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { + m_vars.push_back(v); + m_monomials.push_back(svector(sz, vs)); + } + + void push() { + m_lim.push_back(m_vars.size()); + } + + void pop(unsigned n) { + SASSERT(n < m_lim.size()); + m_lim.shrink(m_lim.size() - n); + m_vars.shrink(m_lim.back()); + m_monomials.shrink(m_lim.back()); + } + }; nra_solver::nra_solver(lean::lar_solver& s) { @@ -25,7 +49,19 @@ namespace lp { dealloc(m_imp); } + void nra_solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) { + m_imp->add(v, sz, vs); + } + lean::final_check_status nra_solver::check_feasible() { return m_imp->check_feasible(); } + + void nra_solver::push() { + m_imp->push(); + } + + void nra_solver::pop(unsigned n) { + m_imp->pop(n); + } } From 8ecd8a2a521d01e3fff9c9789fd3904628b94115 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 May 2017 18:07:58 -0700 Subject: [PATCH 0135/1283] Dev (#50) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/util/lp/CMakeLists.txt | 3 +- src/util/lp/nra_solver.cpp | 67 ++++++++++++++++++++++++ src/util/lp/nra_solver.h | 47 +++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/util/lp/nra_solver.cpp create mode 100644 src/util/lp/nra_solver.h diff --git a/contrib/cmake/src/util/lp/CMakeLists.txt b/contrib/cmake/src/util/lp/CMakeLists.txt index ec9a2e137..75051d68c 100644 --- a/contrib/cmake/src/util/lp/CMakeLists.txt +++ b/contrib/cmake/src/util/lp/CMakeLists.txt @@ -19,8 +19,9 @@ z3_add_component(lp lp_solver_instances.cpp lu_instances.cpp matrix_instances.cpp + nra_solver.cpp permutation_matrix_instances.cpp - quick_xplain.cpp + quick_xplain.cpp row_eta_matrix_instances.cpp scaler_instances.cpp sparse_matrix_instances.cpp diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp new file mode 100644 index 000000000..08b17030c --- /dev/null +++ b/src/util/lp/nra_solver.cpp @@ -0,0 +1,67 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/lp/nra_solver.h" + +namespace lp { + + struct nra_solver::imp { + lean::lar_solver& s; + + svector m_vars; + vector> m_monomials; + unsigned_vector m_lim; + + imp(lean::lar_solver& s): s(s) { + m_lim.push_back(0); + } + + lean::final_check_status check_feasible() { + return lean::final_check_status::GIVEUP; + } + + void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { + m_vars.push_back(v); + m_monomials.push_back(svector(sz, vs)); + } + + void push() { + m_lim.push_back(m_vars.size()); + } + + void pop(unsigned n) { + SASSERT(n < m_lim.size()); + m_lim.shrink(m_lim.size() - n); + m_vars.shrink(m_lim.back()); + m_monomials.shrink(m_lim.back()); + } + + }; + + nra_solver::nra_solver(lean::lar_solver& s) { + m_imp = alloc(imp, s); + } + + nra_solver::~nra_solver() { + dealloc(m_imp); + } + + void nra_solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) { + m_imp->add(v, sz, vs); + } + + lean::final_check_status nra_solver::check_feasible() { + return m_imp->check_feasible(); + } + + void nra_solver::push() { + m_imp->push(); + } + + void nra_solver::pop(unsigned n) { + m_imp->pop(n); + } +} diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h new file mode 100644 index 000000000..bae76b0d1 --- /dev/null +++ b/src/util/lp/nra_solver.h @@ -0,0 +1,47 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/vector.h" +#include "util/lp/lp_settings.h" +#include "util/lp/lar_solver.h" + +namespace lean { + class lar_solver; +} + +namespace lp { + + class nra_solver { + struct imp; + imp* m_imp; + + public: + + nra_solver(lean::lar_solver& s); + + ~nra_solver(); + + /* + \brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1] + The variable v is equal to the product of variables vs. + */ + void add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs); + + /* + \brief Check feasiblity of linear constraints augmented by polynomial definitions + that are added. + */ + lean::final_check_status check_feasible(); + + /* + \brief push and pop scope. + Monomial definitions are retraced when popping scope. + */ + void push(); + + void pop(unsigned n); + }; +} From 93a3c486b00fe566b2ea70b3062e26a117865ce3 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 23 May 2017 18:32:08 -0700 Subject: [PATCH 0136/1283] small fix in lar_solver.cpp Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index b6315fe5c..aed5e32db 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1381,7 +1381,8 @@ void lar_solver::shrink_explanation_to_minimum(vectorexplanation_is_correct(explanation)); } -final_check_status check_int_feasibility() { +final_check_status lar_solver::check_int_feasibility() { + std::cout << "lar_solver::check_int_feasibility()\n"; return final_check_status::GIVEUP; } } // namespace lean From e231f4bc87146cad844a179eeb52b51086932866 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 May 2017 18:50:18 -0700 Subject: [PATCH 0137/1283] adding more nlsat Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.h | 8 ++-- src/nlsat/nlsat_types.h | 8 ++-- src/util/lp/nra_solver.cpp | 77 +++++++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index 3668629cd..08902e709 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -21,10 +21,10 @@ Revision History: #ifndef NLSAT_SOLVER_H_ #define NLSAT_SOLVER_H_ -#include"nlsat_types.h" -#include"params.h" -#include"statistics.h" -#include"rlimit.h" +#include"nlsat/nlsat_types.h" +#include"util/params.h" +#include"util/statistics.h" +#include"util/rlimit.h" namespace nlsat { diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 11e063a17..70da98e32 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -19,10 +19,10 @@ Revision History: #ifndef NLSAT_TYPES_H_ #define NLSAT_TYPES_H_ -#include"polynomial.h" -#include"buffer.h" -#include"sat_types.h" -#include"z3_exception.h" +#include"math/polynomial/polynomial.h" +#include"util/buffer.h" +#include"sat/sat_types.h" +#include"util/z3_exception.h" namespace algebraic_numbers { class anum; diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index 08b17030c..6ccc73633 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -5,18 +5,28 @@ #pragma once #include "util/lp/nra_solver.h" +#include "nlsat/nlsat_solver.h" namespace lp { struct nra_solver::imp { lean::lar_solver& s; + reslimit m_limit; // TBD: extract from lar_solver + params_ref m_params; // TBD: pass from outside - svector m_vars; - vector> m_monomials; + struct mon_eq { + mon_eq(lean::var_index v, svector const& vs): + m_v(v), m_vs(vs) {} + lean::var_index m_v; + svector m_vs; + }; + + vector m_monomials; unsigned_vector m_lim; + mutable std::unordered_map m_variable_values; // current model - imp(lean::lar_solver& s): s(s) { - m_lim.push_back(0); + imp(lean::lar_solver& s): + s(s) { } lean::final_check_status check_feasible() { @@ -24,21 +34,70 @@ namespace lp { } void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { - m_vars.push_back(v); - m_monomials.push_back(svector(sz, vs)); + m_monomials.push_back(mon_eq(v, svector(sz, vs))); } void push() { - m_lim.push_back(m_vars.size()); + m_lim.push_back(m_monomials.size()); } void pop(unsigned n) { + if (n == 0) return; SASSERT(n < m_lim.size()); + m_monomials.shrink(m_lim[m_lim.size() - n]); m_lim.shrink(m_lim.size() - n); - m_vars.shrink(m_lim.back()); - m_monomials.shrink(m_lim.back()); } + /* + \brief Check if polynomials are well defined. + multiply values for vs and check if they are equal to value for v. + epsilon has been computed. + */ + bool check_assignment(mon_eq const& m) const { + rational r1 = m_variable_values[m.m_v]; + rational r2(1); + for (auto w : m.m_vs) { + r2 *= m_variable_values[w]; + } + return r1 == r2; + } + + bool check_assignments() const { + s.get_model(m_variable_values); + for (auto const& m : m_monomials) { + if (!check_assignment(m)) return false; + } + return true; + } + + + /** + \brief one-shot nlsat check. + A one shot checker is the least functionality that can + enable non-linear reasoning. + In addition to checking satisfiability we would also need + to identify equalities in the model that should be assumed + with the remaining solver. + + TBD: use partial model from lra_solver to prime the state of nlsat_solver. + */ + lbool check_nlsat() { + nlsat::solver solver(m_limit, m_params); + // add linear inequalities from lra_solver + // add polynomial definitions. + for (auto const& m : m_monomials) { + add_monomial_eq(solver, m); + } + lbool r = solver.check(); + if (r == l_true) { + // TBD extract model. + } + return r; + } + + void add_monomial_eq(nlsat::solver& solver, mon_eq const& m) { + + } }; nra_solver::nra_solver(lean::lar_solver& s) { From b9ca8b435f85d520f97b0c70d1a0733ff9e24475 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 May 2017 20:45:58 -0700 Subject: [PATCH 0138/1283] nlsat integration Signed-off-by: Nikolaj Bjorner --- src/util/lp/nra_solver.cpp | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index 6ccc73633..3b8aaa34f 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -6,6 +6,8 @@ #pragma once #include "util/lp/nra_solver.h" #include "nlsat/nlsat_solver.h" +#include "math/polynomial/polynomial.h" +#include "util/map.h" namespace lp { @@ -13,6 +15,7 @@ namespace lp { lean::lar_solver& s; reslimit m_limit; // TBD: extract from lar_solver params_ref m_params; // TBD: pass from outside + u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables struct mon_eq { mon_eq(lean::var_index v, svector const& vs): @@ -78,7 +81,7 @@ namespace lp { In addition to checking satisfiability we would also need to identify equalities in the model that should be assumed with the remaining solver. - + TBD: use partial model from lra_solver to prime the state of nlsat_solver. */ lbool check_nlsat() { @@ -88,15 +91,44 @@ namespace lp { for (auto const& m : m_monomials) { add_monomial_eq(solver, m); } - lbool r = solver.check(); + lbool r = solver.check(); // TBD: get assumptions from literals that are asserted above level 0. if (r == l_true) { // TBD extract model. + // check interface equalities } return r; } void add_monomial_eq(nlsat::solver& solver, mon_eq const& m) { - + polynomial::manager& pm = solver.pm(); + svector vars; + for (auto v : m.m_vs) { + vars.push_back(lp2nl(solver, v)); + } + polynomial::monomial_ref m1(pm.mk_monomial(vars.size(), vars.c_ptr()), pm); + polynomial::monomial_ref m2(pm.mk_monomial(lp2nl(solver, m.m_v), 1), pm); + polynomial::monomial* mls[2] = { m1, m2 }; + polynomial::scoped_numeral_vector coeffs(pm.m()); + coeffs.push_back(mpz(1)); + coeffs.push_back(mpz(-1)); + polynomial::polynomial_ref p(pm.mk_polynomial(2, coeffs.c_ptr(), mls), pm); + polynomial::polynomial* ps[1] = { p }; + bool even[1] = { false }; + nlsat::literal lit = solver.mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, even); + solver.mk_clause(1, &lit, 0); + } + + + // translate var_index into polynomial::var that are declared on nlsat::solver. + + + polynomial::var lp2nl(nlsat::solver& solver, lean::var_index v) { + polynomial::var r; + if (!m_lp2nl.find(v, r)) { + r = solver.mk_var(false); // TBD: is it s.column_is_integer(v), if then the function should take a var_index and not unsigned; s.is_int(v); + m_lp2nl.insert(v, r); + } + return r; } }; From dcc62845575f867a9cd6638efb68cec0d5ad21a1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 May 2017 08:57:10 -0700 Subject: [PATCH 0139/1283] adding constraints Signed-off-by: Nikolaj Bjorner --- src/util/lp/nra_solver.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index 3b8aaa34f..70b550733 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -87,6 +87,9 @@ namespace lp { lbool check_nlsat() { nlsat::solver solver(m_limit, m_params); // add linear inequalities from lra_solver + for (unsigned i = 0; i < s.constraint_count(); ++i) { + add_constraint(solver, s.get_constraint(i)); + } // add polynomial definitions. for (auto const& m : m_monomials) { add_monomial_eq(solver, m); @@ -118,6 +121,41 @@ namespace lp { solver.mk_clause(1, &lit, 0); } + void add_constraint(nlsat::solver& solver, lean::lar_base_constraint const& c) { + polynomial::manager& pm = solver.pm(); + auto k = c.m_kind; + auto rhs = c.m_right_side; + auto lhs = c.get_left_side_coefficients(); + unsigned sz = lhs.size(); + svector vars; + rational den = denominator(rhs); + for (auto kv : lhs) { + vars.push_back(lp2nl(solver, kv.second)); + den = lcm(den, denominator(kv.first)); + } + vector coeffs; + for (auto kv : lhs) { + coeffs.push_back(den * kv.first); + } + rhs *= den; + polynomial::polynomial_ref p(pm.mk_linear(sz, coeffs.c_ptr(), vars.c_ptr(), -rhs), pm); + nlsat::literal lit; + switch (k) { + case lean::lconstraint_kind::LE: + // lit = ~solver.mk_ineq_literal(nlsat::atom::kind::GT, ); + break; + case lean::lconstraint_kind::GE: + case lean::lconstraint_kind::LT: + case lean::lconstraint_kind::GT: + case lean::lconstraint_kind::EQ: + break; + } + + // solver.mk_clause(); + + // c.get_free_coeff_of_left_side(); + } + // translate var_index into polynomial::var that are declared on nlsat::solver. From 09530bb6bcb09cba18115124496f30ca667716e6 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 24 May 2017 10:12:42 -0700 Subject: [PATCH 0140/1283] adding some content to the new check_int_feasibility() Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 9 +++++++-- src/util/lp/lar_solver.h | 10 ++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index aed5e32db..14d3535af 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1382,8 +1382,13 @@ void lar_solver::shrink_explanation_to_minimum(vectorsecond.is_integer(); } + + static bool impq_is_int(const impq& v) { + return v.x.is_int() && is_zero(v.y); + } + + inline + bool column_value_is_integer(unsigned j) const { + const impq & v = m_mpq_lar_core_solver.m_r_x[j]; + return impq_is_int(v); + } inline bool column_is_real(unsigned j) const { return !column_is_integer(j); } final_check_status check_int_feasibility(); }; From fc53c5b638984a21fefbe65d3fe618325fdd4935 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 May 2017 14:41:02 -0700 Subject: [PATCH 0141/1283] adding nra solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/CMakeLists.txt | 2 +- contrib/cmake/src/smt/CMakeLists.txt | 1 + contrib/cmake/src/test/lp/CMakeLists.txt | 2 +- contrib/cmake/src/util/lp/CMakeLists.txt | 2 + src/smt/theory_lra.cpp | 57 +++++++++++- src/util/lp/lar_solver.cpp | 6 ++ src/util/lp/lar_solver.h | 9 +- src/util/lp/lp_settings.h | 12 ++- src/util/lp/nra_solver.cpp | 114 +++++++++++++++++------ src/util/lp/nra_solver.h | 12 +-- 10 files changed, 174 insertions(+), 43 deletions(-) diff --git a/contrib/cmake/src/CMakeLists.txt b/contrib/cmake/src/CMakeLists.txt index dd440b34d..a98f92ca3 100644 --- a/contrib/cmake/src/CMakeLists.txt +++ b/contrib/cmake/src/CMakeLists.txt @@ -35,10 +35,10 @@ endforeach() # raised if you try to declare a component is dependent on another component # that has not yet been declared. add_subdirectory(util) -add_subdirectory(util/lp) add_subdirectory(math/polynomial) add_subdirectory(sat) add_subdirectory(nlsat) +add_subdirectory(util/lp) add_subdirectory(math/hilbert) add_subdirectory(math/simplex) add_subdirectory(math/automata) diff --git a/contrib/cmake/src/smt/CMakeLists.txt b/contrib/cmake/src/smt/CMakeLists.txt index 41890dd05..3db66eb3e 100644 --- a/contrib/cmake/src/smt/CMakeLists.txt +++ b/contrib/cmake/src/smt/CMakeLists.txt @@ -70,6 +70,7 @@ z3_add_component(smt euclid fpa grobner + nlsat lp macros normal_forms diff --git a/contrib/cmake/src/test/lp/CMakeLists.txt b/contrib/cmake/src/test/lp/CMakeLists.txt index 99f8747b1..6683a1758 100644 --- a/contrib/cmake/src/test/lp/CMakeLists.txt +++ b/contrib/cmake/src/test/lp/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(lp_tst lp_main.cpp lp.cpp $ $) +add_executable(lp_tst lp_main.cpp lp.cpp $ $ $ $ ) target_compile_definitions(lp_tst PRIVATE ${Z3_COMPONENT_CXX_DEFINES}) target_compile_options(lp_tst PRIVATE ${Z3_COMPONENT_CXX_FLAGS}) target_include_directories(lp_tst PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS}) diff --git a/contrib/cmake/src/util/lp/CMakeLists.txt b/contrib/cmake/src/util/lp/CMakeLists.txt index 75051d68c..e33764f69 100644 --- a/contrib/cmake/src/util/lp/CMakeLists.txt +++ b/contrib/cmake/src/util/lp/CMakeLists.txt @@ -30,6 +30,8 @@ z3_add_component(lp random_updater_instances.cpp COMPONENT_DEPENDENCIES util + polynomial + nlsat PYG_FILES lp_params.pyg ) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 0072aea7d..addf37153 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1166,18 +1166,41 @@ namespace smt { else if (m_solver->get_status() != lean::lp_status::OPTIMAL) { is_sat = make_feasible(); } + final_check_status st = FC_DONE; switch (is_sat) { case l_true: + if (delayed_assume_eqs()) { return FC_CONTINUE; } if (assume_eqs()) { return FC_CONTINUE; } - if (m_not_handled != 0) { - return FC_GIVEUP; + + switch (check_lia()) { + case l_true: + break; + case l_false: + return FC_CONTINUE; + case l_undef: + st = FC_GIVEUP; + break; } - return FC_DONE; + + switch (check_nra()) { + case l_true: + break; + case l_false: + return FC_CONTINUE; + case l_undef: + st = FC_GIVEUP; + break; + } + if (m_not_handled != 0) { + st = FC_GIVEUP; + } + + return st; case l_false: set_conflict(); return FC_CONTINUE; @@ -1190,6 +1213,28 @@ namespace smt { return FC_GIVEUP; } + lbool check_lia() { + if (m.canceled()) return l_undef; + return l_true; + } + + lbool check_nra() { + if (m.canceled()) return l_undef; + return l_true; + // TBD: + switch (m_solver->check_nra(m_variable_values, m_explanation)) { + case lean::final_check_status::DONE: + return l_true; + case lean::final_check_status::CONTINUE: + return l_true; // ?? why have a continue at this level ?? + case lean::final_check_status::UNSAT: + set_conflict1(); + return l_false; + case lean::final_check_status::GIVEUP: + return l_undef; + } + return l_true; + } /** \brief We must redefine this method, because theory of arithmetic contains @@ -2197,11 +2242,15 @@ namespace smt { } void set_conflict() { + m_solver->get_infeasibility_explanation(m_explanation); + set_conflict1(); + } + + void set_conflict1() { m_eqs.reset(); m_core.reset(); m_params.reset(); m_explanation.clear(); - m_solver->get_infeasibility_explanation(m_explanation); // m_solver->shrink_explanation_to_minimum(m_explanation); // todo, enable when perf is fixed /* static unsigned cn = 0; diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index b6315fe5c..5165dba48 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -330,6 +330,7 @@ void lar_solver::push() { m_term_count.push(); m_constraint_count = m_constraints.size(); m_constraint_count.push(); + m_nra->push(); } void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { @@ -385,6 +386,7 @@ void lar_solver::pop(unsigned k) { m_settings.simplex_strategy() = m_simplex_strategy; lean_assert(sizes_are_correct()); lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + m_nra->pop(k); } vector lar_solver::get_all_constraint_indices() const { @@ -1084,6 +1086,10 @@ void lar_solver::get_infeasibility_explanation(vectorcheck(model, explanation); +} + void lar_solver::get_infeasibility_explanation_for_inf_sign( vector> & explanation, const vector> & inf_row, diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 6fba62fe8..1508d9c28 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -31,9 +31,11 @@ #include "util/lp/quick_xplain.h" #include "util/lp/conversion_helper.h" #include "util/lp/int_solver.h" +#include "util/lp/nra_solver.h" namespace lean { + class lar_solver : public column_namer { class ext_var_info { unsigned m_ext_j; // the external index @@ -61,7 +63,8 @@ class lar_solver : public column_namer { stacked_value m_term_count; vector m_terms; const var_index m_terms_start_index; - indexed_vector m_column_buffer; + indexed_vector m_column_buffer; + scoped_ptr m_nra; public: lar_core_solver m_mpq_lar_core_solver; unsigned constraint_count() const; @@ -200,10 +203,12 @@ public: void set_status(lp_status s); lp_status find_feasible_solution(); + + final_check_status check_nra(nra_model_t& model, explanation_t& explanation); lp_status solve(); - void fill_explanation_from_infeasible_column(vector> & evidence) const; + void fill_explanation_from_infeasible_column(explanation_t & evidence) const; unsigned get_total_iterations() const; diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index c081a84ff..f07fbeef7 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -18,11 +18,17 @@ typedef unsigned constraint_index; typedef unsigned row_index; enum class final_check_status { - DONE, - CONTINUE, - GIVEUP + DONE, + CONTINUE, + UNSAT, + GIVEUP }; +typedef vector> explanation_t; + +typedef std::unordered_map nra_model_t; + + enum class column_type { free_column = 0, low_bound = 1, diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index 70b550733..a5d2e671a 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -4,14 +4,17 @@ */ #pragma once +#include "util/lp/lar_solver.h" #include "util/lp/nra_solver.h" #include "nlsat/nlsat_solver.h" #include "math/polynomial/polynomial.h" +#include "math/polynomial/algebraic_numbers.h" #include "util/map.h" -namespace lp { - struct nra_solver::imp { +namespace nra { + + struct solver::imp { lean::lar_solver& s; reslimit m_limit; // TBD: extract from lar_solver params_ref m_params; // TBD: pass from outside @@ -27,13 +30,25 @@ namespace lp { vector m_monomials; unsigned_vector m_lim; mutable std::unordered_map m_variable_values; // current model + vector> m_core; imp(lean::lar_solver& s): s(s) { } - lean::final_check_status check_feasible() { - return lean::final_check_status::GIVEUP; + lean::final_check_status check_feasible(lean::nra_model_t& m, lean::explanation_t& ex) { + if (m_monomials.empty()) { + return lean::final_check_status::DONE; + } + if (check_assignments()) { + return lean::final_check_status::DONE; + } + switch (check_nlsat(m, ex)) { + case l_undef: return lean::final_check_status::GIVEUP; + case l_true: lean::final_check_status::DONE; + case l_false: lean::final_check_status::UNSAT; + } + return lean::final_check_status::DONE; } void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { @@ -84,21 +99,57 @@ namespace lp { TBD: use partial model from lra_solver to prime the state of nlsat_solver. */ - lbool check_nlsat() { + lbool check_nlsat(lean::nra_model_t& model, lean::explanation_t& ex) { nlsat::solver solver(m_limit, m_params); + m_lp2nl.reset(); // add linear inequalities from lra_solver for (unsigned i = 0; i < s.constraint_count(); ++i) { - add_constraint(solver, s.get_constraint(i)); + add_constraint(solver, i); } + // add polynomial definitions. for (auto const& m : m_monomials) { add_monomial_eq(solver, m); } - lbool r = solver.check(); // TBD: get assumptions from literals that are asserted above level 0. - if (r == l_true) { - // TBD extract model. - // check interface equalities + // TBD: add variable bounds? + + lbool r = solver.check(); + switch (r) { + case l_true: { + nlsat::anum_manager& am = solver.am(); + model.clear(); + for (auto kv : m_lp2nl) { + kv.m_key; + nlsat::anum const& v = solver.value(kv.m_value); + if (is_int(kv.m_key) && !am.is_int(v)) { + // the nlsat solver should already have returned unknown. + TRACE("lp", tout << "Value is not integer " << kv.m_key << "\n";); + return l_undef; + } + if (!am.is_rational(v)) { + // TBD extract and convert model. + TRACE("lp", tout << "Cannot handle algebraic numbers\n";); + return l_undef; + } + rational r; + am.to_rational(v, r); + model[kv.m_key] = r; + } + break; } + case l_false: { + ex.reset(); + vector core; + solver.get_core(core); + for (auto c : core) { + unsigned idx = static_cast(static_cast(c) - this); + ex.push_back(std::pair(rational(1), idx)); + } + break; + } + case l_undef: + break; + } return r; } @@ -121,7 +172,8 @@ namespace lp { solver.mk_clause(1, &lit, 0); } - void add_constraint(nlsat::solver& solver, lean::lar_base_constraint const& c) { + void add_constraint(nlsat::solver& solver, unsigned idx) { + lean::lar_base_constraint const& c = s.get_constraint(idx); polynomial::manager& pm = solver.pm(); auto k = c.m_kind; auto rhs = c.m_right_side; @@ -139,58 +191,68 @@ namespace lp { } rhs *= den; polynomial::polynomial_ref p(pm.mk_linear(sz, coeffs.c_ptr(), vars.c_ptr(), -rhs), pm); + polynomial::polynomial* ps[1] = { p }; + bool is_even[1] = { false }; nlsat::literal lit; switch (k) { case lean::lconstraint_kind::LE: - // lit = ~solver.mk_ineq_literal(nlsat::atom::kind::GT, ); + lit = ~solver.mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); break; case lean::lconstraint_kind::GE: + lit = ~solver.mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); + break; case lean::lconstraint_kind::LT: + lit = solver.mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); + break; case lean::lconstraint_kind::GT: + lit = solver.mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); + break; case lean::lconstraint_kind::EQ: + lit = solver.mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); break; } - // solver.mk_clause(); + nlsat::assumption a = this + idx; + solver.mk_clause(1, &lit, a); + } - // c.get_free_coeff_of_left_side(); + bool is_int(lean::var_index v) { + // TBD: is it s.column_is_integer(v), if then the function should take a var_index and not unsigned; s.is_int(v); + return false; } - - // translate var_index into polynomial::var that are declared on nlsat::solver. - - polynomial::var lp2nl(nlsat::solver& solver, lean::var_index v) { polynomial::var r; if (!m_lp2nl.find(v, r)) { - r = solver.mk_var(false); // TBD: is it s.column_is_integer(v), if then the function should take a var_index and not unsigned; s.is_int(v); + r = solver.mk_var(is_int(v)); m_lp2nl.insert(v, r); } return r; } + }; - nra_solver::nra_solver(lean::lar_solver& s) { + solver::solver(lean::lar_solver& s) { m_imp = alloc(imp, s); } - nra_solver::~nra_solver() { + solver::~solver() { dealloc(m_imp); } - void nra_solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) { + void solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) { m_imp->add(v, sz, vs); } - lean::final_check_status nra_solver::check_feasible() { - return m_imp->check_feasible(); + lean::final_check_status solver::check(lean::nra_model_t& m, lean::explanation_t& ex) { + return m_imp->check_feasible(m, ex); } - void nra_solver::push() { + void solver::push() { m_imp->push(); } - void nra_solver::pop(unsigned n) { + void solver::pop(unsigned n) { m_imp->pop(n); } } diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h index bae76b0d1..1383cfbc3 100644 --- a/src/util/lp/nra_solver.h +++ b/src/util/lp/nra_solver.h @@ -6,23 +6,22 @@ #pragma once #include "util/vector.h" #include "util/lp/lp_settings.h" -#include "util/lp/lar_solver.h" namespace lean { class lar_solver; } -namespace lp { +namespace nra { - class nra_solver { + class solver { struct imp; imp* m_imp; public: - nra_solver(lean::lar_solver& s); + solver(lean::lar_solver& s); - ~nra_solver(); + ~solver(); /* \brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1] @@ -34,7 +33,7 @@ namespace lp { \brief Check feasiblity of linear constraints augmented by polynomial definitions that are added. */ - lean::final_check_status check_feasible(); + lean::final_check_status check(lean::nra_model_t& m, lean::explanation_t& ex); /* \brief push and pop scope. @@ -43,5 +42,6 @@ namespace lp { void push(); void pop(unsigned n); + }; } From 80bb084611ecf754a4ebc7fd3aea382f98d4f548 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 May 2017 14:47:09 -0700 Subject: [PATCH 0142/1283] add missing initialization Signed-off-by: Nikolaj Bjorner --- src/util/lp/lar_solver.cpp | 4 +++- src/util/lp/nra_solver.cpp | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index fee17dc77..97e1c102f 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -31,7 +31,9 @@ lar_solver::lar_solver() : m_status(OPTIMAL), m_infeasible_column_index(-1), m_terms_start_index(1000000), m_mpq_lar_core_solver(m_settings, *this) -{} +{ + m_nra = alloc(nra::solver, *this); +} void lar_solver::set_propagate_bounds_on_pivoted_rows_mode(bool v) { m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index a5d2e671a..2308b9c45 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -30,7 +30,6 @@ namespace nra { vector m_monomials; unsigned_vector m_lim; mutable std::unordered_map m_variable_values; // current model - vector> m_core; imp(lean::lar_solver& s): s(s) { From 7a809fe4f0f566e7615f0a0f9605cc7b56b8d85b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 May 2017 14:56:59 -0700 Subject: [PATCH 0143/1283] adding nra solver Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 25 +++++++++++++++++++++++++ src/util/lp/lar_solver.cpp | 5 +++++ src/util/lp/lar_solver.h | 2 ++ 3 files changed, 32 insertions(+) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index addf37153..cd663f354 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -415,6 +415,31 @@ namespace smt { } } + void internalize_mul(app* t) { + SASSERT(a.is_mul(t)); + mk_enode(t); + theory_var v = mk_var(t); + svector vars; + ptr_vector todo; + todo.push_back(t); + while (!todo.empty()) { + expr* n = todo.back(); + todo.pop_back(); + expr* n1, *n2; + if (a.is_mul(n, n1, n2)) { + todo.push_back(n1); + todo.push_back(n2); + } + else { + if (!ctx().e_internalized(n)) { + ctx().internalize(n, false); + } + vars.push_back(get_var_index(mk_var(n))); + } + } + // m_solver->add_monomial(get_var_index(v), vars); + } + enode * mk_enode(app * n) { if (ctx().e_internalized(n)) { return get_enode(n); diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 97e1c102f..b3da4e8ba 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1092,6 +1092,11 @@ final_check_status lar_solver::check_nra(nra_model_t& model, explanation_t& expl return m_nra->check(model, explanation); } +void lar_solver::add_monomial(var_index v, svector const& vars) { + m_nra->add_monomial(v, vars.size(), vars.c_ptr()); +} + + void lar_solver::get_infeasibility_explanation_for_inf_sign( vector> & explanation, const vector> & inf_row, diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 9a80335ac..6937455ae 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -205,6 +205,8 @@ public: lp_status find_feasible_solution(); final_check_status check_nra(nra_model_t& model, explanation_t& explanation); + + void add_monomial(var_index v, svector const& vars); lp_status solve(); From 4726d32e2f5cfb7c2f6cd057f680b049f0a19df0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 May 2017 16:32:14 -0700 Subject: [PATCH 0144/1283] Dev (#51) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/CMakeLists.txt | 2 +- contrib/cmake/src/smt/CMakeLists.txt | 1 + contrib/cmake/src/test/lp/CMakeLists.txt | 2 +- contrib/cmake/src/util/lp/CMakeLists.txt | 2 + src/nlsat/nlsat_solver.h | 8 +- src/nlsat/nlsat_types.h | 8 +- src/smt/theory_lra.cpp | 82 +++++++- src/util/lp/lar_solver.cpp | 15 +- src/util/lp/lar_solver.h | 11 +- src/util/lp/lp_settings.h | 12 +- src/util/lp/nra_solver.cpp | 230 +++++++++++++++++++++-- src/util/lp/nra_solver.h | 11 +- 12 files changed, 338 insertions(+), 46 deletions(-) diff --git a/contrib/cmake/src/CMakeLists.txt b/contrib/cmake/src/CMakeLists.txt index dd440b34d..a98f92ca3 100644 --- a/contrib/cmake/src/CMakeLists.txt +++ b/contrib/cmake/src/CMakeLists.txt @@ -35,10 +35,10 @@ endforeach() # raised if you try to declare a component is dependent on another component # that has not yet been declared. add_subdirectory(util) -add_subdirectory(util/lp) add_subdirectory(math/polynomial) add_subdirectory(sat) add_subdirectory(nlsat) +add_subdirectory(util/lp) add_subdirectory(math/hilbert) add_subdirectory(math/simplex) add_subdirectory(math/automata) diff --git a/contrib/cmake/src/smt/CMakeLists.txt b/contrib/cmake/src/smt/CMakeLists.txt index 41890dd05..3db66eb3e 100644 --- a/contrib/cmake/src/smt/CMakeLists.txt +++ b/contrib/cmake/src/smt/CMakeLists.txt @@ -70,6 +70,7 @@ z3_add_component(smt euclid fpa grobner + nlsat lp macros normal_forms diff --git a/contrib/cmake/src/test/lp/CMakeLists.txt b/contrib/cmake/src/test/lp/CMakeLists.txt index 99f8747b1..6683a1758 100644 --- a/contrib/cmake/src/test/lp/CMakeLists.txt +++ b/contrib/cmake/src/test/lp/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(lp_tst lp_main.cpp lp.cpp $ $) +add_executable(lp_tst lp_main.cpp lp.cpp $ $ $ $ ) target_compile_definitions(lp_tst PRIVATE ${Z3_COMPONENT_CXX_DEFINES}) target_compile_options(lp_tst PRIVATE ${Z3_COMPONENT_CXX_FLAGS}) target_include_directories(lp_tst PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS}) diff --git a/contrib/cmake/src/util/lp/CMakeLists.txt b/contrib/cmake/src/util/lp/CMakeLists.txt index 75051d68c..e33764f69 100644 --- a/contrib/cmake/src/util/lp/CMakeLists.txt +++ b/contrib/cmake/src/util/lp/CMakeLists.txt @@ -30,6 +30,8 @@ z3_add_component(lp random_updater_instances.cpp COMPONENT_DEPENDENCIES util + polynomial + nlsat PYG_FILES lp_params.pyg ) diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index 3668629cd..08902e709 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -21,10 +21,10 @@ Revision History: #ifndef NLSAT_SOLVER_H_ #define NLSAT_SOLVER_H_ -#include"nlsat_types.h" -#include"params.h" -#include"statistics.h" -#include"rlimit.h" +#include"nlsat/nlsat_types.h" +#include"util/params.h" +#include"util/statistics.h" +#include"util/rlimit.h" namespace nlsat { diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 11e063a17..70da98e32 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -19,10 +19,10 @@ Revision History: #ifndef NLSAT_TYPES_H_ #define NLSAT_TYPES_H_ -#include"polynomial.h" -#include"buffer.h" -#include"sat_types.h" -#include"z3_exception.h" +#include"math/polynomial/polynomial.h" +#include"util/buffer.h" +#include"sat/sat_types.h" +#include"util/z3_exception.h" namespace algebraic_numbers { class anum; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 0072aea7d..cd663f354 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -415,6 +415,31 @@ namespace smt { } } + void internalize_mul(app* t) { + SASSERT(a.is_mul(t)); + mk_enode(t); + theory_var v = mk_var(t); + svector vars; + ptr_vector todo; + todo.push_back(t); + while (!todo.empty()) { + expr* n = todo.back(); + todo.pop_back(); + expr* n1, *n2; + if (a.is_mul(n, n1, n2)) { + todo.push_back(n1); + todo.push_back(n2); + } + else { + if (!ctx().e_internalized(n)) { + ctx().internalize(n, false); + } + vars.push_back(get_var_index(mk_var(n))); + } + } + // m_solver->add_monomial(get_var_index(v), vars); + } + enode * mk_enode(app * n) { if (ctx().e_internalized(n)) { return get_enode(n); @@ -1166,18 +1191,41 @@ namespace smt { else if (m_solver->get_status() != lean::lp_status::OPTIMAL) { is_sat = make_feasible(); } + final_check_status st = FC_DONE; switch (is_sat) { case l_true: + if (delayed_assume_eqs()) { return FC_CONTINUE; } if (assume_eqs()) { return FC_CONTINUE; } - if (m_not_handled != 0) { - return FC_GIVEUP; + + switch (check_lia()) { + case l_true: + break; + case l_false: + return FC_CONTINUE; + case l_undef: + st = FC_GIVEUP; + break; } - return FC_DONE; + + switch (check_nra()) { + case l_true: + break; + case l_false: + return FC_CONTINUE; + case l_undef: + st = FC_GIVEUP; + break; + } + if (m_not_handled != 0) { + st = FC_GIVEUP; + } + + return st; case l_false: set_conflict(); return FC_CONTINUE; @@ -1190,6 +1238,28 @@ namespace smt { return FC_GIVEUP; } + lbool check_lia() { + if (m.canceled()) return l_undef; + return l_true; + } + + lbool check_nra() { + if (m.canceled()) return l_undef; + return l_true; + // TBD: + switch (m_solver->check_nra(m_variable_values, m_explanation)) { + case lean::final_check_status::DONE: + return l_true; + case lean::final_check_status::CONTINUE: + return l_true; // ?? why have a continue at this level ?? + case lean::final_check_status::UNSAT: + set_conflict1(); + return l_false; + case lean::final_check_status::GIVEUP: + return l_undef; + } + return l_true; + } /** \brief We must redefine this method, because theory of arithmetic contains @@ -2197,11 +2267,15 @@ namespace smt { } void set_conflict() { + m_solver->get_infeasibility_explanation(m_explanation); + set_conflict1(); + } + + void set_conflict1() { m_eqs.reset(); m_core.reset(); m_params.reset(); m_explanation.clear(); - m_solver->get_infeasibility_explanation(m_explanation); // m_solver->shrink_explanation_to_minimum(m_explanation); // todo, enable when perf is fixed /* static unsigned cn = 0; diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 14d3535af..b3da4e8ba 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -31,7 +31,9 @@ lar_solver::lar_solver() : m_status(OPTIMAL), m_infeasible_column_index(-1), m_terms_start_index(1000000), m_mpq_lar_core_solver(m_settings, *this) -{} +{ + m_nra = alloc(nra::solver, *this); +} void lar_solver::set_propagate_bounds_on_pivoted_rows_mode(bool v) { m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; @@ -330,6 +332,7 @@ void lar_solver::push() { m_term_count.push(); m_constraint_count = m_constraints.size(); m_constraint_count.push(); + m_nra->push(); } void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { @@ -385,6 +388,7 @@ void lar_solver::pop(unsigned k) { m_settings.simplex_strategy() = m_simplex_strategy; lean_assert(sizes_are_correct()); lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + m_nra->pop(k); } vector lar_solver::get_all_constraint_indices() const { @@ -1084,6 +1088,15 @@ void lar_solver::get_infeasibility_explanation(vectorcheck(model, explanation); +} + +void lar_solver::add_monomial(var_index v, svector const& vars) { + m_nra->add_monomial(v, vars.size(), vars.c_ptr()); +} + + void lar_solver::get_infeasibility_explanation_for_inf_sign( vector> & explanation, const vector> & inf_row, diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index a47240fdd..6937455ae 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -31,9 +31,11 @@ #include "util/lp/quick_xplain.h" #include "util/lp/conversion_helper.h" #include "util/lp/int_solver.h" +#include "util/lp/nra_solver.h" namespace lean { + class lar_solver : public column_namer { class ext_var_info { unsigned m_ext_j; // the external index @@ -61,7 +63,8 @@ class lar_solver : public column_namer { stacked_value m_term_count; vector m_terms; const var_index m_terms_start_index; - indexed_vector m_column_buffer; + indexed_vector m_column_buffer; + scoped_ptr m_nra; public: lar_core_solver m_mpq_lar_core_solver; unsigned constraint_count() const; @@ -200,10 +203,14 @@ public: void set_status(lp_status s); lp_status find_feasible_solution(); + + final_check_status check_nra(nra_model_t& model, explanation_t& explanation); + + void add_monomial(var_index v, svector const& vars); lp_status solve(); - void fill_explanation_from_infeasible_column(vector> & evidence) const; + void fill_explanation_from_infeasible_column(explanation_t & evidence) const; unsigned get_total_iterations() const; diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index c081a84ff..f07fbeef7 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -18,11 +18,17 @@ typedef unsigned constraint_index; typedef unsigned row_index; enum class final_check_status { - DONE, - CONTINUE, - GIVEUP + DONE, + CONTINUE, + UNSAT, + GIVEUP }; +typedef vector> explanation_t; + +typedef std::unordered_map nra_model_t; + + enum class column_type { free_column = 0, low_bound = 1, diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index 08b17030c..2308b9c45 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -4,64 +4,254 @@ */ #pragma once +#include "util/lp/lar_solver.h" #include "util/lp/nra_solver.h" +#include "nlsat/nlsat_solver.h" +#include "math/polynomial/polynomial.h" +#include "math/polynomial/algebraic_numbers.h" +#include "util/map.h" -namespace lp { - struct nra_solver::imp { +namespace nra { + + struct solver::imp { lean::lar_solver& s; + reslimit m_limit; // TBD: extract from lar_solver + params_ref m_params; // TBD: pass from outside + u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables - svector m_vars; - vector> m_monomials; + struct mon_eq { + mon_eq(lean::var_index v, svector const& vs): + m_v(v), m_vs(vs) {} + lean::var_index m_v; + svector m_vs; + }; + + vector m_monomials; unsigned_vector m_lim; + mutable std::unordered_map m_variable_values; // current model - imp(lean::lar_solver& s): s(s) { - m_lim.push_back(0); + imp(lean::lar_solver& s): + s(s) { } - lean::final_check_status check_feasible() { - return lean::final_check_status::GIVEUP; + lean::final_check_status check_feasible(lean::nra_model_t& m, lean::explanation_t& ex) { + if (m_monomials.empty()) { + return lean::final_check_status::DONE; + } + if (check_assignments()) { + return lean::final_check_status::DONE; + } + switch (check_nlsat(m, ex)) { + case l_undef: return lean::final_check_status::GIVEUP; + case l_true: lean::final_check_status::DONE; + case l_false: lean::final_check_status::UNSAT; + } + return lean::final_check_status::DONE; } void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { - m_vars.push_back(v); - m_monomials.push_back(svector(sz, vs)); + m_monomials.push_back(mon_eq(v, svector(sz, vs))); } void push() { - m_lim.push_back(m_vars.size()); + m_lim.push_back(m_monomials.size()); } void pop(unsigned n) { + if (n == 0) return; SASSERT(n < m_lim.size()); + m_monomials.shrink(m_lim[m_lim.size() - n]); m_lim.shrink(m_lim.size() - n); - m_vars.shrink(m_lim.back()); - m_monomials.shrink(m_lim.back()); + } + + /* + \brief Check if polynomials are well defined. + multiply values for vs and check if they are equal to value for v. + epsilon has been computed. + */ + bool check_assignment(mon_eq const& m) const { + rational r1 = m_variable_values[m.m_v]; + rational r2(1); + for (auto w : m.m_vs) { + r2 *= m_variable_values[w]; + } + return r1 == r2; + } + + bool check_assignments() const { + s.get_model(m_variable_values); + for (auto const& m : m_monomials) { + if (!check_assignment(m)) return false; + } + return true; + } + + + /** + \brief one-shot nlsat check. + A one shot checker is the least functionality that can + enable non-linear reasoning. + In addition to checking satisfiability we would also need + to identify equalities in the model that should be assumed + with the remaining solver. + + TBD: use partial model from lra_solver to prime the state of nlsat_solver. + */ + lbool check_nlsat(lean::nra_model_t& model, lean::explanation_t& ex) { + nlsat::solver solver(m_limit, m_params); + m_lp2nl.reset(); + // add linear inequalities from lra_solver + for (unsigned i = 0; i < s.constraint_count(); ++i) { + add_constraint(solver, i); + } + + // add polynomial definitions. + for (auto const& m : m_monomials) { + add_monomial_eq(solver, m); + } + // TBD: add variable bounds? + + lbool r = solver.check(); + switch (r) { + case l_true: { + nlsat::anum_manager& am = solver.am(); + model.clear(); + for (auto kv : m_lp2nl) { + kv.m_key; + nlsat::anum const& v = solver.value(kv.m_value); + if (is_int(kv.m_key) && !am.is_int(v)) { + // the nlsat solver should already have returned unknown. + TRACE("lp", tout << "Value is not integer " << kv.m_key << "\n";); + return l_undef; + } + if (!am.is_rational(v)) { + // TBD extract and convert model. + TRACE("lp", tout << "Cannot handle algebraic numbers\n";); + return l_undef; + } + rational r; + am.to_rational(v, r); + model[kv.m_key] = r; + } + break; + } + case l_false: { + ex.reset(); + vector core; + solver.get_core(core); + for (auto c : core) { + unsigned idx = static_cast(static_cast(c) - this); + ex.push_back(std::pair(rational(1), idx)); + } + break; + } + case l_undef: + break; + } + return r; + } + + void add_monomial_eq(nlsat::solver& solver, mon_eq const& m) { + polynomial::manager& pm = solver.pm(); + svector vars; + for (auto v : m.m_vs) { + vars.push_back(lp2nl(solver, v)); + } + polynomial::monomial_ref m1(pm.mk_monomial(vars.size(), vars.c_ptr()), pm); + polynomial::monomial_ref m2(pm.mk_monomial(lp2nl(solver, m.m_v), 1), pm); + polynomial::monomial* mls[2] = { m1, m2 }; + polynomial::scoped_numeral_vector coeffs(pm.m()); + coeffs.push_back(mpz(1)); + coeffs.push_back(mpz(-1)); + polynomial::polynomial_ref p(pm.mk_polynomial(2, coeffs.c_ptr(), mls), pm); + polynomial::polynomial* ps[1] = { p }; + bool even[1] = { false }; + nlsat::literal lit = solver.mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, even); + solver.mk_clause(1, &lit, 0); + } + + void add_constraint(nlsat::solver& solver, unsigned idx) { + lean::lar_base_constraint const& c = s.get_constraint(idx); + polynomial::manager& pm = solver.pm(); + auto k = c.m_kind; + auto rhs = c.m_right_side; + auto lhs = c.get_left_side_coefficients(); + unsigned sz = lhs.size(); + svector vars; + rational den = denominator(rhs); + for (auto kv : lhs) { + vars.push_back(lp2nl(solver, kv.second)); + den = lcm(den, denominator(kv.first)); + } + vector coeffs; + for (auto kv : lhs) { + coeffs.push_back(den * kv.first); + } + rhs *= den; + polynomial::polynomial_ref p(pm.mk_linear(sz, coeffs.c_ptr(), vars.c_ptr(), -rhs), pm); + polynomial::polynomial* ps[1] = { p }; + bool is_even[1] = { false }; + nlsat::literal lit; + switch (k) { + case lean::lconstraint_kind::LE: + lit = ~solver.mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); + break; + case lean::lconstraint_kind::GE: + lit = ~solver.mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); + break; + case lean::lconstraint_kind::LT: + lit = solver.mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); + break; + case lean::lconstraint_kind::GT: + lit = solver.mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); + break; + case lean::lconstraint_kind::EQ: + lit = solver.mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); + break; + } + + nlsat::assumption a = this + idx; + solver.mk_clause(1, &lit, a); + } + + bool is_int(lean::var_index v) { + // TBD: is it s.column_is_integer(v), if then the function should take a var_index and not unsigned; s.is_int(v); + return false; + } + + polynomial::var lp2nl(nlsat::solver& solver, lean::var_index v) { + polynomial::var r; + if (!m_lp2nl.find(v, r)) { + r = solver.mk_var(is_int(v)); + m_lp2nl.insert(v, r); + } + return r; } }; - nra_solver::nra_solver(lean::lar_solver& s) { + solver::solver(lean::lar_solver& s) { m_imp = alloc(imp, s); } - nra_solver::~nra_solver() { + solver::~solver() { dealloc(m_imp); } - void nra_solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) { + void solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) { m_imp->add(v, sz, vs); } - lean::final_check_status nra_solver::check_feasible() { - return m_imp->check_feasible(); + lean::final_check_status solver::check(lean::nra_model_t& m, lean::explanation_t& ex) { + return m_imp->check_feasible(m, ex); } - void nra_solver::push() { + void solver::push() { m_imp->push(); } - void nra_solver::pop(unsigned n) { + void solver::pop(unsigned n) { m_imp->pop(n); } } diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h index bae76b0d1..87820728a 100644 --- a/src/util/lp/nra_solver.h +++ b/src/util/lp/nra_solver.h @@ -6,23 +6,22 @@ #pragma once #include "util/vector.h" #include "util/lp/lp_settings.h" -#include "util/lp/lar_solver.h" namespace lean { class lar_solver; } -namespace lp { +namespace nra { - class nra_solver { + class solver { struct imp; imp* m_imp; public: - nra_solver(lean::lar_solver& s); + solver(lean::lar_solver& s); - ~nra_solver(); + ~solver(); /* \brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1] @@ -34,7 +33,7 @@ namespace lp { \brief Check feasiblity of linear constraints augmented by polynomial definitions that are added. */ - lean::final_check_status check_feasible(); + lean::final_check_status check(lean::nra_model_t& m, lean::explanation_t& ex); /* \brief push and pop scope. From b18dc7d05238ec3afa7d8eac1e7b4691321b09c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 May 2017 17:24:36 -0700 Subject: [PATCH 0145/1283] adding nra Signed-off-by: Nikolaj Bjorner --- src/smt/params/smt_params_helper.pyg | 2 +- src/smt/params/theory_arith_params.h | 13 +++++----- src/smt/smt_setup.cpp | 5 ++-- src/smt/theory_lra.cpp | 22 +++++++++++++---- src/util/lp/nra_solver.cpp | 36 +++++++++++++++++++++------- src/util/lp/nra_solver.h | 5 ++++ 6 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 6c2ff4962..d2addb7dc 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -36,7 +36,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'), + ('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/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 943bd711e..e71c0adad 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -23,12 +23,13 @@ Revision History: #include"params.h" enum arith_solver_id { - AS_NO_ARITH, - AS_DIFF_LOGIC, - AS_ARITH, - AS_DENSE_DIFF_LOGIC, - AS_UTVPI, - AS_OPTINF + AS_NO_ARITH, // 0 + AS_DIFF_LOGIC, // 1 + AS_ARITH, // 2 + AS_DENSE_DIFF_LOGIC, // 3 + AS_UTVPI, // 4 + AS_OPTINF, // 5 + AS_LRA // 6 }; enum bound_prop_mode { diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 4dd1e2510..9646bce2b 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -724,8 +724,6 @@ namespace smt { } void setup::setup_r_arith() { - // to disable theory lra - // m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params)); } @@ -789,6 +787,9 @@ namespace smt { case AS_OPTINF: m_context.register_plugin(alloc(smt::theory_inf_arith, m_manager, m_params)); break; + case AS_LRA: + setup_r_arith(); + break; default: if (m_params.m_arith_int_only && int_only) m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index cd663f354..b0345c52f 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -366,6 +366,14 @@ namespace smt { terms[index] = n1; st.terms_to_internalize().push_back(n2); } + else if (a.is_mul(n)) { + theory_var v; + internalize_mul(to_app(n), v, r); + coeffs[index] *= r; + coeffs[vars.size()] = coeffs[index]; + vars.push_back(v); + ++index; + } else if (a.is_numeral(n, r)) { coeff += coeffs[index]*r; ++index; @@ -415,10 +423,13 @@ namespace smt { } } - void internalize_mul(app* t) { + void internalize_mul(app* t, theory_var& v, rational& r) { SASSERT(a.is_mul(t)); + internalize_args(t); mk_enode(t); - theory_var v = mk_var(t); + r = rational::one(); + rational r1; + v = mk_var(t); svector vars; ptr_vector todo; todo.push_back(t); @@ -430,6 +441,9 @@ namespace smt { todo.push_back(n1); todo.push_back(n2); } + else if (a.is_numeral(n, r1)) { + r *= r1; + } else { if (!ctx().e_internalized(n)) { ctx().internalize(n, false); @@ -437,7 +451,7 @@ namespace smt { vars.push_back(get_var_index(mk_var(n))); } } - // m_solver->add_monomial(get_var_index(v), vars); + m_solver->add_monomial(get_var_index(v), vars); } enode * mk_enode(app * n) { @@ -1245,7 +1259,7 @@ namespace smt { lbool check_nra() { if (m.canceled()) return l_undef; - return l_true; + // return l_true; // TBD: switch (m_solver->check_nra(m_variable_values, m_explanation)) { case lean::final_check_status::DONE: diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index 2308b9c45..5157be92c 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -21,8 +21,8 @@ namespace nra { u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables struct mon_eq { - mon_eq(lean::var_index v, svector const& vs): - m_v(v), m_vs(vs) {} + mon_eq(lean::var_index v, unsigned sz, lean::var_index const* vs): + m_v(v), m_vs(sz, vs) {} lean::var_index m_v; svector m_vs; }; @@ -44,14 +44,14 @@ namespace nra { } switch (check_nlsat(m, ex)) { case l_undef: return lean::final_check_status::GIVEUP; - case l_true: lean::final_check_status::DONE; - case l_false: lean::final_check_status::UNSAT; + case l_true: return lean::final_check_status::DONE; + case l_false: return lean::final_check_status::UNSAT; } return lean::final_check_status::DONE; } void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { - m_monomials.push_back(mon_eq(v, svector(sz, vs))); + m_monomials.push_back(mon_eq(v, sz, vs)); } void push() { @@ -60,7 +60,6 @@ namespace nra { void pop(unsigned n) { if (n == 0) return; - SASSERT(n < m_lim.size()); m_monomials.shrink(m_lim[m_lim.size() - n]); m_lim.shrink(m_lim.size() - n); } @@ -112,7 +111,9 @@ namespace nra { } // TBD: add variable bounds? + lbool r = solver.check(); + TRACE("arith", solver.display(tout << r << "\n");); switch (r) { case l_true: { nlsat::anum_manager& am = solver.am(); @@ -143,6 +144,7 @@ namespace nra { for (auto c : core) { unsigned idx = static_cast(static_cast(c) - this); ex.push_back(std::pair(rational(1), idx)); + TRACE("arith", tout << "ex: " << idx << "\n";); } break; } @@ -172,12 +174,12 @@ namespace nra { } void add_constraint(nlsat::solver& solver, unsigned idx) { - lean::lar_base_constraint const& c = s.get_constraint(idx); - polynomial::manager& pm = solver.pm(); + auto& c = s.get_constraint(idx); + auto& pm = solver.pm(); auto k = c.m_kind; auto rhs = c.m_right_side; auto lhs = c.get_left_side_coefficients(); - unsigned sz = lhs.size(); + auto sz = lhs.size(); svector vars; rational den = denominator(rhs); for (auto kv : lhs) { @@ -229,6 +231,17 @@ namespace nra { return r; } + std::ostream& display(std::ostream& out) const { + for (auto m : m_monomials) { + out << "v" << m.m_v << " = "; + for (auto v : m.m_vs) { + out << "v" << v << " "; + } + out << "\n"; + } + return out; + } + }; solver::solver(lean::lar_solver& s) { @@ -254,4 +267,9 @@ namespace nra { void solver::pop(unsigned n) { m_imp->pop(n); } + + std::ostream& solver::display(std::ostream& out) const { + return m_imp->display(out); + } + } diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h index 87820728a..2fdf91729 100644 --- a/src/util/lp/nra_solver.h +++ b/src/util/lp/nra_solver.h @@ -42,5 +42,10 @@ namespace nra { void push(); void pop(unsigned n); + + /* + \brief display state + */ + std::ostream& display(std::ostream& out) const; }; } From 73e919c002a656739190662ca758f4cfc560df14 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 24 May 2017 17:31:17 -0700 Subject: [PATCH 0146/1283] test Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 6937455ae..e99600340 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -418,6 +418,7 @@ public: const impq & v = m_mpq_lar_core_solver.m_r_x[j]; return impq_is_int(v); } + inline bool column_is_real(unsigned j) const { return !column_is_integer(j); } final_check_status check_int_feasibility(); }; From 1086eaaa1f17fa2228da4e33103c928b2a3a0451 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 May 2017 21:46:19 -0700 Subject: [PATCH 0147/1283] debugging nra Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 - src/ast/rewriter/arith_rewriter.cpp | 45 +++++++++++++++++++ src/ast/rewriter/arith_rewriter.h | 1 + .../simplifier/arith_simplifier_plugin.cpp | 45 +++++++++++++++++++ src/ast/simplifier/arith_simplifier_plugin.h | 1 + src/smt/smt_model_generator.cpp | 1 + src/smt/theory_lra.cpp | 30 ++++++++++--- 7 files changed, 118 insertions(+), 6 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 5f2de5170..109657675 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1727,7 +1727,6 @@ ast * ast_manager::register_node_core(ast * n) { n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); - TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); // increment reference counters diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 2b2087e3b..fa3d69602 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -738,9 +738,54 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu result = m_util.mk_idiv0(arg1); return BR_REWRITE1; } + expr_ref quot(m()); + if (divides(arg1, arg2, quot)) { + result = m_util.mk_mul(quot, m_util.mk_idiv(arg1, arg1)); + return BR_REWRITE2; + } return BR_FAILED; } +bool arith_rewriter::divides(expr* d, expr* n, expr_ref& quot) { + if (d == n) { + quot = m_util.mk_numeral(rational(1), m_util.is_int(d)); + return true; + } + if (m_util.is_mul(n)) { + expr_ref_vector muls(m()); + muls.push_back(n); + expr* n1, *n2; + rational r1, r2; + for (unsigned i = 0; i < muls.size(); ++i) { + if (m_util.is_mul(muls[i].get(), n1, n2)) { + muls[i] = n1; + muls.push_back(n2); + --i; + } + } + if (m_util.is_numeral(d, r1) && !r1.is_zero()) { + for (unsigned i = 0; i < muls.size(); ++i) { + if (m_util.is_numeral(muls[i].get(), r2) && (r2 / r1).is_int()) { + muls[i] = m_util.mk_numeral(r2 / r1, m_util.is_int(d)); + quot = m_util.mk_mul(muls.size(), muls.c_ptr()); + return true; + } + } + } + else { + for (unsigned i = 0; i < muls.size(); ++i) { + if (d == muls[i].get()) { + muls[i] = muls.back(); + muls.pop_back(); + quot = m_util.mk_mul(muls.size(), muls.c_ptr()); + return true; + } + } + } + } + return false; +} + br_status arith_rewriter::mk_mod_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 68a60e1f0..606d73ae1 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -90,6 +90,7 @@ class arith_rewriter : public poly_rewriter { bool is_pi_integer_offset(expr * t, expr * & m); expr * mk_sin_value(rational const & k); app * mk_sqrt(rational const & k); + bool divides(expr* d, expr* n, expr_ref& quot); public: arith_rewriter(ast_manager & m, params_ref const & p = params_ref()): diff --git a/src/ast/simplifier/arith_simplifier_plugin.cpp b/src/ast/simplifier/arith_simplifier_plugin.cpp index ef320578a..52f36ab04 100644 --- a/src/ast/simplifier/arith_simplifier_plugin.cpp +++ b/src/ast/simplifier/arith_simplifier_plugin.cpp @@ -267,10 +267,55 @@ void arith_simplifier_plugin::mk_idiv(expr * arg1, expr * arg2, expr_ref & resul bool is_int; if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) result = m_util.mk_numeral(div(v1, v2), is_int); + else if (divides(arg2, arg1, result)) { + result = m_util.mk_mul(result, m_util.mk_idiv(arg2, arg2)); + } else result = m_util.mk_idiv(arg1, arg2); } +bool arith_simplifier_plugin::divides(expr* d, expr* n, expr_ref& quot) { + ast_manager& m = m_manager; + if (d == n) { + quot = m_util.mk_numeral(rational(1), m_util.is_int(d)); + return true; + } + if (m_util.is_mul(n)) { + expr_ref_vector muls(m); + muls.push_back(n); + expr* n1, *n2; + rational r1, r2; + for (unsigned i = 0; i < muls.size(); ++i) { + if (m_util.is_mul(muls[i].get(), n1, n2)) { + muls[i] = n1; + muls.push_back(n2); + --i; + } + } + if (m_util.is_numeral(d, r1) && !r1.is_zero()) { + for (unsigned i = 0; i < muls.size(); ++i) { + if (m_util.is_numeral(muls[i].get(), r2) && (r2 / r1).is_int()) { + muls[i] = m_util.mk_numeral(r2 / r1, m_util.is_int(d)); + quot = m_util.mk_mul(muls.size(), muls.c_ptr()); + return true; + } + } + } + else { + for (unsigned i = 0; i < muls.size(); ++i) { + if (d == muls[i].get()) { + muls[i] = muls.back(); + muls.pop_back(); + quot = m_util.mk_mul(muls.size(), muls.c_ptr()); + return true; + } + } + } + } + return false; +} + + void arith_simplifier_plugin::prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result) { SASSERT(m_util.is_int(e)); SASSERT(k.is_int() && k.is_pos()); diff --git a/src/ast/simplifier/arith_simplifier_plugin.h b/src/ast/simplifier/arith_simplifier_plugin.h index e6181e211..045ee0e71 100644 --- a/src/ast/simplifier/arith_simplifier_plugin.h +++ b/src/ast/simplifier/arith_simplifier_plugin.h @@ -48,6 +48,7 @@ protected: void div_monomial(expr_ref_vector& monomials, numeral const& g); void get_monomial_gcd(expr_ref_vector& monomials, numeral& g); + bool divides(expr* d, expr* n, expr_ref& quot); public: arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p); diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index b9c1ac453..c319a8d7d 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -388,6 +388,7 @@ namespace smt { enode * n = *it3; if (is_uninterp_const(n->get_owner()) && m_context->is_relevant(n)) { func_decl * d = n->get_owner()->get_decl(); + TRACE("mg_top_sort", tout << d->get_name() << " " << (m_hidden_ufs.contains(d)?"hidden":"visible") << "\n";); if (m_hidden_ufs.contains(d)) continue; expr * val = get_value(n); m_model->register_decl(d, val); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index b0345c52f..dd910446e 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -425,8 +425,11 @@ namespace smt { void internalize_mul(app* t, theory_var& v, rational& r) { SASSERT(a.is_mul(t)); - internalize_args(t); - mk_enode(t); + bool _has_var = has_var(t); + if (!_has_var) { + internalize_args(t); + mk_enode(t); + } r = rational::one(); rational r1; v = mk_var(t); @@ -451,7 +454,10 @@ namespace smt { vars.push_back(get_var_index(mk_var(n))); } } - m_solver->add_monomial(get_var_index(v), vars); + TRACE("arith", tout << mk_pp(t, m) << "\n";); + if (!_has_var) { + m_solver->add_monomial(get_var_index(v), vars); + } } enode * mk_enode(app * n) { @@ -498,6 +504,14 @@ namespace smt { return m_arith_params.m_arith_reflect || is_underspecified(n); } + bool has_var(expr* n) { + if (!ctx().e_internalized(n)) { + return false; + } + enode* e = get_enode(n); + return th.is_attached_to_var(e); + } + theory_var mk_var(expr* n, bool internalize = true) { if (!ctx().e_internalized(n)) { ctx().internalize(n, false); @@ -2281,6 +2295,7 @@ namespace smt { } void set_conflict() { + m_explanation.clear(); m_solver->get_infeasibility_explanation(m_explanation); set_conflict1(); } @@ -2289,7 +2304,6 @@ namespace smt { m_eqs.reset(); m_core.reset(); m_params.reset(); - m_explanation.clear(); // m_solver->shrink_explanation_to_minimum(m_explanation); // todo, enable when perf is fixed /* static unsigned cn = 0; @@ -2340,7 +2354,10 @@ namespace smt { model_value_proc * mk_value(enode * n, model_generator & mg) { theory_var v = n->get_th_var(get_id()); - return alloc(expr_wrapper_proc, m_factory->mk_value(get_value(v), m.get_sort(n->get_owner()))); + expr* o = n->get_owner(); + rational r = get_value(v); + 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))); } bool get_value(enode* n, expr_ref& r) { @@ -2366,6 +2383,7 @@ namespace smt { 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); } + if (m_arith_params.m_arith_mode == AS_LRA) return true; context nctx(m, ctx().get_fparams(), ctx().get_params()); add_background(nctx); bool result = l_true != nctx.check(); @@ -2378,6 +2396,7 @@ namespace smt { if (dump_lemmas()) { ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); } + if (m_arith_params.m_arith_mode == AS_LRA) return true; context nctx(m, ctx().get_fparams(), ctx().get_params()); m_core.push_back(~lit); add_background(nctx); @@ -2389,6 +2408,7 @@ namespace smt { } bool validate_eq(enode* x, enode* y) { + if (m_arith_params.m_arith_mode == AS_LRA) return true; context nctx(m, ctx().get_fparams(), ctx().get_params()); add_background(nctx); nctx.assert_expr(m.mk_not(m.mk_eq(x->get_owner(), y->get_owner()))); From e306287d7ba588638033bdb17db1e4be54c3be22 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 May 2017 14:04:48 -0700 Subject: [PATCH 0148/1283] updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 64 +++++++++++++------ src/util/lp/lar_solver.cpp | 10 --- src/util/lp/lar_solver.h | 4 -- src/util/lp/lp_settings.h | 2 - src/util/lp/nra_solver.cpp | 126 +++++++++++++++++-------------------- src/util/lp/nra_solver.h | 21 ++++++- 6 files changed, 120 insertions(+), 107 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index dd910446e..a075f3072 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -35,6 +35,7 @@ Revision History: #include "smt/smt_model_generator.h" #include "smt/arith_eq_adapter.h" #include "util/nat_set.h" +#include "util/lp/nra_solver.h" #include "tactic/filter_model_converter.h" namespace lp { @@ -144,10 +145,10 @@ namespace smt { ast_manager& m; theory_arith_params& m_arith_params; arith_util a; - arith_eq_adapter m_arith_eq_adapter; + vector m_columns; + - vector m_columns; // temporary values kept during internalization struct internalize_state { expr_ref_vector m_terms; @@ -248,6 +249,8 @@ namespace smt { unsigned m_num_conflicts; + scoped_ptr m_nra; + bool m_use_nra_model; struct var_value_eq { imp & m_th; @@ -291,6 +294,16 @@ namespace smt { //m_solver->settings().set_ostream(0); } + void ensure_nra() { + if (!m_nra) { + m_nra = alloc(nra::solver, *m_solver.get(), m.limit(), ctx().get_params()); + for (unsigned i = 0; i < m_scopes.size(); ++i) { + m_nra->push(); + } + } + } + + void found_not_handled(expr* n) { m_not_handled = n; if (is_app(n) && is_underspecified(to_app(n))) { @@ -456,7 +469,8 @@ namespace smt { } TRACE("arith", tout << mk_pp(t, m) << "\n";); if (!_has_var) { - m_solver->add_monomial(get_var_index(v), vars); + ensure_nra(); + m_nra->add_monomial(get_var_index(v), vars.size(), vars.c_ptr()); } } @@ -711,7 +725,8 @@ namespace smt { m_num_conflicts(0), m_model_eqs(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)), m_solver(0), - m_resource_limit(*this) { + m_resource_limit(*this), + m_use_nra_model(false) { } ~imp() { @@ -868,6 +883,7 @@ namespace smt { s.m_underspecified_lim = m_underspecified.size(); s.m_var_trail_lim = m_var_trail.size(); if (!m_delay_constraints) m_solver->push(); + if (m_nra) m_nra->push(); } void pop_scope_eh(unsigned num_scopes) { @@ -900,6 +916,7 @@ namespace smt { // VERIFY(l_false != make_feasible()); m_new_bounds.reset(); m_to_check.reset(); + if (m_nra) m_nra->pop(num_scopes); TRACE("arith", tout << "num scopes: " << num_scopes << " new scope level: " << m_scopes.size() << "\n";); } @@ -1272,21 +1289,23 @@ namespace smt { } lbool check_nra() { + m_use_nra_model = false; if (m.canceled()) return l_undef; - // return l_true; - // TBD: - switch (m_solver->check_nra(m_variable_values, m_explanation)) { - case lean::final_check_status::DONE: - return l_true; - case lean::final_check_status::CONTINUE: - return l_true; // ?? why have a continue at this level ?? - case lean::final_check_status::UNSAT: + if (!m_nra) return l_true; + if (!m_nra->need_check()) return l_true; + lbool r = m_nra->check(m_explanation); + switch (r) { + case l_false: set_conflict1(); - return l_false; - case lean::final_check_status::GIVEUP: - return l_undef; + break; + case l_true: + m_use_nra_model = true; + // TBD: check equalities + break; + default: + break; } - return l_true; + return r; } /** @@ -2355,9 +2374,16 @@ namespace smt { model_value_proc * mk_value(enode * n, model_generator & mg) { theory_var v = n->get_th_var(get_id()); expr* o = n->get_owner(); - rational r = get_value(v); - 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))); + if (m_use_nra_model) { + SASSERT(m_nra); + app* e = a.mk_numeral(m_nra->value(m_theory_var2var_index[v]), a.is_int(o)); + return alloc(expr_wrapper_proc, e); + } + else { + rational r = get_value(v); + 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))); + } } bool get_value(enode* n, expr_ref& r) { diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index b3da4e8ba..882ce229e 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -32,7 +32,6 @@ lar_solver::lar_solver() : m_status(OPTIMAL), m_terms_start_index(1000000), m_mpq_lar_core_solver(m_settings, *this) { - m_nra = alloc(nra::solver, *this); } void lar_solver::set_propagate_bounds_on_pivoted_rows_mode(bool v) { @@ -332,7 +331,6 @@ void lar_solver::push() { m_term_count.push(); m_constraint_count = m_constraints.size(); m_constraint_count.push(); - m_nra->push(); } void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { @@ -388,7 +386,6 @@ void lar_solver::pop(unsigned k) { m_settings.simplex_strategy() = m_simplex_strategy; lean_assert(sizes_are_correct()); lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - m_nra->pop(k); } vector lar_solver::get_all_constraint_indices() const { @@ -1088,13 +1085,6 @@ void lar_solver::get_infeasibility_explanation(vectorcheck(model, explanation); -} - -void lar_solver::add_monomial(var_index v, svector const& vars) { - m_nra->add_monomial(v, vars.size(), vars.c_ptr()); -} void lar_solver::get_infeasibility_explanation_for_inf_sign( diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 6937455ae..b8c5ce608 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -31,7 +31,6 @@ #include "util/lp/quick_xplain.h" #include "util/lp/conversion_helper.h" #include "util/lp/int_solver.h" -#include "util/lp/nra_solver.h" namespace lean { @@ -64,7 +63,6 @@ class lar_solver : public column_namer { vector m_terms; const var_index m_terms_start_index; indexed_vector m_column_buffer; - scoped_ptr m_nra; public: lar_core_solver m_mpq_lar_core_solver; unsigned constraint_count() const; @@ -204,8 +202,6 @@ public: lp_status find_feasible_solution(); - final_check_status check_nra(nra_model_t& model, explanation_t& explanation); - void add_monomial(var_index v, svector const& vars); lp_status solve(); diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index f07fbeef7..3f082ab10 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -26,8 +26,6 @@ enum class final_check_status { typedef vector> explanation_t; -typedef std::unordered_map nra_model_t; - enum class column_type { free_column = 0, diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index 5157be92c..695066048 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -16,9 +16,10 @@ namespace nra { struct solver::imp { lean::lar_solver& s; - reslimit m_limit; // TBD: extract from lar_solver - params_ref m_params; // TBD: pass from outside + reslimit& m_limit; // TBD: extract from lar_solver + params_ref m_params; // TBD: pass from outside u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables + nlsat::solver m_nlsat; struct mon_eq { mon_eq(lean::var_index v, unsigned sz, lean::var_index const* vs): @@ -31,23 +32,15 @@ namespace nra { unsigned_vector m_lim; mutable std::unordered_map m_variable_values; // current model - imp(lean::lar_solver& s): - s(s) { + imp(lean::lar_solver& s, reslimit& lim, params_ref const& p): + s(s), + m_limit(lim), + m_params(p), + m_nlsat(m_limit, m_params) { } - lean::final_check_status check_feasible(lean::nra_model_t& m, lean::explanation_t& ex) { - if (m_monomials.empty()) { - return lean::final_check_status::DONE; - } - if (check_assignments()) { - return lean::final_check_status::DONE; - } - switch (check_nlsat(m, ex)) { - case l_undef: return lean::final_check_status::GIVEUP; - case l_true: return lean::final_check_status::DONE; - case l_false: return lean::final_check_status::UNSAT; - } - return lean::final_check_status::DONE; + bool need_check() { + return !m_monomials.empty() && !check_assignments(); } void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { @@ -97,71 +90,51 @@ namespace nra { TBD: use partial model from lra_solver to prime the state of nlsat_solver. */ - lbool check_nlsat(lean::nra_model_t& model, lean::explanation_t& ex) { - nlsat::solver solver(m_limit, m_params); + lbool check(lean::explanation_t& ex) { + SASSERT(need_check()); + m_nlsat.reset(); m_lp2nl.reset(); + vector core; + // add linear inequalities from lra_solver for (unsigned i = 0; i < s.constraint_count(); ++i) { - add_constraint(solver, i); + add_constraint(i); } // add polynomial definitions. for (auto const& m : m_monomials) { - add_monomial_eq(solver, m); + add_monomial_eq(m); } // TBD: add variable bounds? - - lbool r = solver.check(); - TRACE("arith", solver.display(tout << r << "\n");); + lbool r = m_nlsat.check(); + TRACE("arith", m_nlsat.display(tout << r << "\n");); switch (r) { - case l_true: { - nlsat::anum_manager& am = solver.am(); - model.clear(); - for (auto kv : m_lp2nl) { - kv.m_key; - nlsat::anum const& v = solver.value(kv.m_value); - if (is_int(kv.m_key) && !am.is_int(v)) { - // the nlsat solver should already have returned unknown. - TRACE("lp", tout << "Value is not integer " << kv.m_key << "\n";); - return l_undef; - } - if (!am.is_rational(v)) { - // TBD extract and convert model. - TRACE("lp", tout << "Cannot handle algebraic numbers\n";); - return l_undef; - } - rational r; - am.to_rational(v, r); - model[kv.m_key] = r; - } + case l_true: break; - } - case l_false: { + case l_false: ex.reset(); - vector core; - solver.get_core(core); + m_nlsat.get_core(core); for (auto c : core) { unsigned idx = static_cast(static_cast(c) - this); ex.push_back(std::pair(rational(1), idx)); TRACE("arith", tout << "ex: " << idx << "\n";); } break; - } case l_undef: break; } return r; } - void add_monomial_eq(nlsat::solver& solver, mon_eq const& m) { - polynomial::manager& pm = solver.pm(); + void add_monomial_eq(mon_eq const& m) { + polynomial::manager& pm = m_nlsat.pm(); svector vars; for (auto v : m.m_vs) { - vars.push_back(lp2nl(solver, v)); + vars.push_back(lp2nl(v)); } polynomial::monomial_ref m1(pm.mk_monomial(vars.size(), vars.c_ptr()), pm); - polynomial::monomial_ref m2(pm.mk_monomial(lp2nl(solver, m.m_v), 1), pm); + polynomial::monomial_ref m2(pm.mk_monomial(lp2nl(m.m_v), 1), pm); polynomial::monomial* mls[2] = { m1, m2 }; polynomial::scoped_numeral_vector coeffs(pm.m()); coeffs.push_back(mpz(1)); @@ -169,13 +142,13 @@ namespace nra { polynomial::polynomial_ref p(pm.mk_polynomial(2, coeffs.c_ptr(), mls), pm); polynomial::polynomial* ps[1] = { p }; bool even[1] = { false }; - nlsat::literal lit = solver.mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, even); - solver.mk_clause(1, &lit, 0); + nlsat::literal lit = m_nlsat.mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, even); + m_nlsat.mk_clause(1, &lit, 0); } - void add_constraint(nlsat::solver& solver, unsigned idx) { + void add_constraint(unsigned idx) { auto& c = s.get_constraint(idx); - auto& pm = solver.pm(); + auto& pm = m_nlsat.pm(); auto k = c.m_kind; auto rhs = c.m_right_side; auto lhs = c.get_left_side_coefficients(); @@ -183,7 +156,7 @@ namespace nra { svector vars; rational den = denominator(rhs); for (auto kv : lhs) { - vars.push_back(lp2nl(solver, kv.second)); + vars.push_back(lp2nl(kv.second)); den = lcm(den, denominator(kv.first)); } vector coeffs; @@ -197,24 +170,24 @@ namespace nra { nlsat::literal lit; switch (k) { case lean::lconstraint_kind::LE: - lit = ~solver.mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); + lit = ~m_nlsat.mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); break; case lean::lconstraint_kind::GE: - lit = ~solver.mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); + lit = ~m_nlsat.mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); break; case lean::lconstraint_kind::LT: - lit = solver.mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); + lit = m_nlsat.mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); break; case lean::lconstraint_kind::GT: - lit = solver.mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); + lit = m_nlsat.mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); break; case lean::lconstraint_kind::EQ: - lit = solver.mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); + lit = m_nlsat.mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); break; } nlsat::assumption a = this + idx; - solver.mk_clause(1, &lit, a); + m_nlsat.mk_clause(1, &lit, a); } bool is_int(lean::var_index v) { @@ -222,15 +195,20 @@ namespace nra { return false; } - polynomial::var lp2nl(nlsat::solver& solver, lean::var_index v) { + + polynomial::var lp2nl(lean::var_index v) { polynomial::var r; if (!m_lp2nl.find(v, r)) { - r = solver.mk_var(is_int(v)); + r = m_nlsat.mk_var(is_int(v)); m_lp2nl.insert(v, r); } return r; } + nlsat::anum const& value(lean::var_index v) const { + return m_nlsat.value(m_lp2nl.find(v)); + } + std::ostream& display(std::ostream& out) const { for (auto m : m_monomials) { out << "v" << m.m_v << " = "; @@ -244,8 +222,8 @@ namespace nra { }; - solver::solver(lean::lar_solver& s) { - m_imp = alloc(imp, s); + solver::solver(lean::lar_solver& s, reslimit& lim, params_ref const& p) { + m_imp = alloc(imp, s, lim, p); } solver::~solver() { @@ -256,8 +234,12 @@ namespace nra { m_imp->add(v, sz, vs); } - lean::final_check_status solver::check(lean::nra_model_t& m, lean::explanation_t& ex) { - return m_imp->check_feasible(m, ex); + lbool solver::check(lean::explanation_t& ex) { + return m_imp->check(ex); + } + + bool solver::need_check() { + return m_imp->need_check(); } void solver::push() { @@ -272,4 +254,8 @@ namespace nra { return m_imp->display(out); } + nlsat::anum const& solver::value(lean::var_index v) const { + return m_imp->value(v); + } + } diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h index 2fdf91729..4bd7a64a0 100644 --- a/src/util/lp/nra_solver.h +++ b/src/util/lp/nra_solver.h @@ -6,20 +6,26 @@ #pragma once #include "util/vector.h" #include "util/lp/lp_settings.h" +#include "util/rlimit.h" +#include "util/params.h" +#include "nlsat/nlsat_solver.h" namespace lean { class lar_solver; } + namespace nra { + typedef std::unordered_map nra_model_t; + class solver { struct imp; imp* m_imp; public: - solver(lean::lar_solver& s); + solver(lean::lar_solver& s, reslimit& lim, params_ref const& p = params_ref()); ~solver(); @@ -33,7 +39,17 @@ namespace nra { \brief Check feasiblity of linear constraints augmented by polynomial definitions that are added. */ - lean::final_check_status check(lean::nra_model_t& m, lean::explanation_t& ex); + lbool check(lean::explanation_t& ex); + + /* + \brief determine whether nra check is needed. + */ + bool need_check(); + + /* + \brief Access model. + */ + nlsat::anum const& value(lean::var_index v) const; /* \brief push and pop scope. @@ -47,5 +63,6 @@ namespace nra { \brief display state */ std::ostream& display(std::ostream& out) const; + }; } From 7d245be4e1b464995443ee475b7600729638a46e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 May 2017 17:33:27 -0700 Subject: [PATCH 0149/1283] enable exposing internal solver state on interrupted solvers Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 3 +- src/ast/rewriter/pb2bv_rewriter.cpp | 3 +- src/sat/card_extension.h | 11 ++- src/sat/sat_extension.h | 2 +- src/sat/sat_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 58 +++++++++++-- src/sat/tactic/goal2sat.cpp | 83 +++++++++++++++++-- src/solver/solver2tactic.cpp | 16 +++- src/tactic/bv/bit_blaster_model_converter.cpp | 43 +++++++++- src/tactic/goal.cpp | 7 ++ src/tactic/goal.h | 1 + src/tactic/portfolio/default_tactic.cpp | 2 - src/tactic/portfolio/fd_solver.cpp | 6 ++ src/tactic/portfolio/fd_solver.h | 1 + src/tactic/portfolio/smt_strategic_solver.cpp | 6 +- 15 files changed, 215 insertions(+), 29 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 67c0f2f08..d867900e8 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -349,10 +349,10 @@ extern "C" { // // ---------------------------- +#if 0 void Z3_API Z3_del_model(Z3_context c, Z3_model m) { Z3_model_dec_ref(c, m); } - unsigned Z3_API Z3_get_model_num_constants(Z3_context c, Z3_model m) { return Z3_model_get_num_consts(c, m); } @@ -368,6 +368,7 @@ extern "C" { Z3_func_decl Z3_API Z3_get_model_func_decl(Z3_context c, Z3_model m, unsigned i) { return Z3_model_get_func_decl(c, m, i); } +#endif unsigned get_model_func_num_entries_core(Z3_context c, Z3_model m, unsigned i) { diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index aedd62081..bcc050048 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -822,8 +822,7 @@ struct pb2bv_rewriter::imp { p.get_bool("keep_cardinality_constraints", false) || p.get_bool("sat.cardinality.solver", false) || p.get_bool("cardinality.solver", false) || - gparams::get_module("sat").get_bool("cardinality.solver", false) || - keep_pb(); + gparams::get_module("sat").get_bool("cardinality.solver", false); } bool keep_pb() const { diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 41219fae5..fbe1141b1 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -42,7 +42,8 @@ namespace sat { stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; - + + public: class card { unsigned m_index; literal m_lit; @@ -105,6 +106,7 @@ namespace sat { void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate() { m_lits[0].neg(); } }; + protected: struct ineq { literal_vector m_lits; @@ -304,6 +306,13 @@ namespace sat { void add_at_least(bool_var v, literal_vector const& lits, unsigned k); void add_pb_ge(bool_var v, svector const& wlits, unsigned k); void add_xor(bool_var v, literal_vector const& lits); + unsigned num_pb() const { return m_pbs.size(); } + pb const& get_pb(unsigned i) const { return *m_pbs[i]; } + unsigned num_card() const { return m_cards.size(); } + card const& get_card(unsigned i) const { return *m_cards[i]; } + unsigned num_xor() const { return m_xors.size(); } + xor const& get_xor(unsigned i) const { return *m_xors[i]; } + virtual void propagate(literal l, ext_constraint_idx idx, bool & keep); virtual bool resolve_conflict(); virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r); diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index aae99c28f..a875bad6c 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -46,7 +46,7 @@ namespace sat { virtual std::ostream& display(std::ostream& out) const = 0; virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; virtual void collect_statistics(statistics& st) const = 0; - virtual extension* copy(solver* s) = 0; + virtual extension* copy(solver* s) = 0; virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; }; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c708823dd..c512597b0 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -309,7 +309,7 @@ namespace sat { } void set_par(parallel* p, unsigned id); bool canceled() { return !m_rlimit.inc(); } - config const& get_config() { return m_config; } + config const& get_config() const { return m_config; } extension* get_extension() const { return m_ext.get(); } void set_extension(extension* e); typedef std::pair bin_clause; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0d12c0a94..5016d20cd 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -66,7 +66,11 @@ class inc_sat_solver : public solver { expr_dependency_ref m_dep_core; svector m_weights; std::string m_unknown; - + // access formulas after they have been pre-processed and handled by the sat solver. + // this allows to access the internal state of the SAT solver and carry on partial results. + bool m_internalized; // are formulas internalized? + bool m_internalized_converted; // have internalized formulas been converted back + expr_ref_vector m_internalized_fmls; // formulas in internalized format typedef obj_map dep2asm_t; public: @@ -81,7 +85,10 @@ public: m_map(m), m_num_scopes(0), m_dep_core(m), - m_unknown("no reason given") { + m_unknown("no reason given"), + m_internalized(false), + m_internalized_converted(false), + m_internalized_fmls(m) { updt_params(p); init_preprocess(); } @@ -141,6 +148,8 @@ public: if (r != l_true) return r; r = internalize_assumptions(sz, assumptions, dep2asm); if (r != l_true) return r; + m_internalized = true; + m_internalized_converted = false; r = m_solver.check(m_asms.size(), m_asms.c_ptr()); @@ -170,8 +179,11 @@ public: m_fmls_head_lim.push_back(m_fmls_head); if (m_bb_rewriter) m_bb_rewriter->push(); m_map.push(); + m_internalized = true; + m_internalized_converted = false; } virtual void pop(unsigned n) { + m_internalized = false; if (n > m_num_scopes) { // allow inc_sat_solver to n = m_num_scopes; // take over for another solver. } @@ -204,6 +216,7 @@ public: } virtual ast_manager& get_manager() const { return m; } virtual void assert_expr(expr * t) { + m_internalized = false; TRACE("goal2sat", tout << mk_pp(t, m) << "\n";); m_fmls.push_back(t); } @@ -320,9 +333,18 @@ public: virtual void get_labels(svector & r) { } virtual unsigned get_num_assertions() const { - return m_fmls.size(); + const_cast(this)->convert_internalized(); + if (m_internalized && m_internalized_converted) { + return m_internalized_fmls.size(); + } + else { + return m_fmls.size(); + } } virtual expr * get_assertion(unsigned idx) const { + if (m_internalized && m_internalized_converted) { + return m_internalized_fmls[idx]; + } return m_fmls[idx]; } virtual unsigned get_num_assumptions() const { @@ -332,6 +354,32 @@ public: return m_asmsf[idx]; } + void convert_internalized() { + if (!m_internalized) return; + sat2goal s2g; + model_converter_ref mc; + goal g(m, false, false, false); + s2g(m_solver, m_map, m_params, g, mc); + extract_model(); + if (!m_model) { + m_model = alloc(model, m); + } + model_ref mdl = m_model; + if (m_mc) (*m_mc)(mdl); + for (unsigned i = 0; i < mdl->get_num_constants(); ++i) { + func_decl* c = mdl->get_constant(i); + expr_ref eq(m.mk_eq(m.mk_const(c), mdl->get_const_interp(c)), m); + g.assert_expr(eq); + } + m_internalized_fmls.reset(); + g.get_formulas(m_internalized_fmls); + // g.display(std::cout); + m_internalized_converted = true; + // if (mc) mc->display(std::cout << "mc"); + // if (m_mc) m_mc->display(std::cout << "m_mc\n"); + // if (m_mc0) m_mc0->display(std::cout << "m_mc0\n"); + } + void init_preprocess() { if (m_preprocess) { m_preprocess->reset(); @@ -374,7 +422,7 @@ private: init_preprocess(); SASSERT(g->models_enabled()); SASSERT(!g->proofs_enabled()); - TRACE("goal2sat", g->display(tout);); + TRACE("sat", g->display(tout);); try { (*m_preprocess)(g, m_subgoals, m_mc, m_pc, m_dep_core); } @@ -391,7 +439,7 @@ private: } g = m_subgoals[0]; expr_ref_vector atoms(m); - TRACE("goal2sat", g->display_with_dependencies(tout);); + TRACE("sat", g->display_with_dependencies(tout);); m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 9d07ec3e6..6604bab89 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -137,7 +137,7 @@ struct goal2sat::imp { sat::bool_var v = m_solver.mk_var(ext); m_map.insert(t, v); l = sat::literal(v, sign); - TRACE("goal2sat", tout << "new_var: " << v << "\n" << mk_ismt2_pp(t, m) << "\n";); + TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";); if (ext && !is_uninterp_const(t)) { m_interpreted_atoms.push_back(t); } @@ -993,6 +993,7 @@ struct sat2goal::imp { expr_ref_vector m_lit2expr; unsigned long long m_max_memory; bool m_learned; + unsigned m_glue; imp(ast_manager & _m, params_ref const & p):m(_m), m_lit2expr(m) { updt_params(p); @@ -1000,6 +1001,7 @@ struct sat2goal::imp { void updt_params(params_ref const & p) { m_learned = p.get_bool("learned", false); + m_glue = p.get_uint("glue", UINT_MAX); m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); } @@ -1042,20 +1044,71 @@ struct sat2goal::imp { return m_lit2expr.get(l.index()); } - void assert_clauses(sat::clause * const * begin, sat::clause * const * end, goal & r) { + void assert_pb(goal& r, sat::card_extension::pb const& p) { + pb_util pb(m); + ptr_buffer lits; + vector coeffs; + for (unsigned i = 0; i < p.size(); ++i) { + lits.push_back(lit2expr(p[i].second)); + coeffs.push_back(rational(p[i].first)); + } + rational k(p.k()); + expr_ref fml(pb.mk_ge(p.size(), coeffs.c_ptr(), lits.c_ptr(), k), m); + + if (p.lit() != sat::null_literal) { + fml = m.mk_eq(lit2expr(p.lit()), fml); + } + r.assert_expr(fml); + } + + void assert_card(goal& r, sat::card_extension::card const& c) { + pb_util pb(m); + ptr_buffer lits; + for (unsigned i = 0; i < c.size(); ++i) { + lits.push_back(lit2expr(c[i])); + } + expr_ref fml(pb.mk_at_most_k(c.size(), lits.c_ptr(), c.k()), m); + + if (c.lit() != sat::null_literal) { + fml = m.mk_eq(lit2expr(c.lit()), fml); + } + r.assert_expr(fml); + } + + void assert_xor(goal & r, sat::card_extension::xor const& x) { + ptr_buffer lits; + for (unsigned i = 0; i < x.size(); ++i) { + lits.push_back(lit2expr(x[i])); + } + expr_ref fml(m.mk_xor(x.size(), lits.c_ptr()), m); + + if (x.lit() != sat::null_literal) { + fml = m.mk_eq(lit2expr(x.lit()), fml); + } + r.assert_expr(fml); + } + + void assert_clauses(sat::solver const & s, sat::clause * const * begin, sat::clause * const * end, goal & r, bool asserted) { ptr_buffer lits; for (sat::clause * const * it = begin; it != end; it++) { checkpoint(); lits.reset(); sat::clause const & c = *(*it); unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - lits.push_back(lit2expr(c[i])); + if (asserted || m_learned || c.glue() <= s.get_config().m_gc_small_lbd) { + for (unsigned i = 0; i < sz; i++) { + lits.push_back(lit2expr(c[i])); + } + r.assert_expr(m.mk_or(lits.size(), lits.c_ptr())); } - r.assert_expr(m.mk_or(lits.size(), lits.c_ptr())); } } + sat::card_extension* get_card_extension(sat::solver const& s) { + sat::extension* ext = s.get_extension(); + return dynamic_cast(ext); + } + void operator()(sat::solver const & s, atom2bool_var const & map, goal & r, model_converter_ref & mc) { if (s.inconsistent()) { r.assert_expr(m.mk_false()); @@ -1087,9 +1140,22 @@ struct sat2goal::imp { r.assert_expr(m.mk_or(lit2expr(it->first), lit2expr(it->second))); } // collect clauses - assert_clauses(s.begin_clauses(), s.end_clauses(), r); - if (m_learned) - assert_clauses(s.begin_learned(), s.end_learned(), r); + assert_clauses(s, s.begin_clauses(), s.end_clauses(), r, true); + assert_clauses(s, s.begin_learned(), s.end_learned(), r, false); + + // TBD: collect assertions from plugin + sat::card_extension* ext = get_card_extension(s); + if (ext) { + for (unsigned i = 0; i < ext->num_pb(); ++i) { + assert_pb(r, ext->get_pb(i)); + } + for (unsigned i = 0; i < ext->num_card(); ++i) { + assert_card(r, ext->get_card(i)); + } + for (unsigned i = 0; i < ext->num_xor(); ++i) { + assert_xor(r, ext->get_xor(i)); + } + } } }; @@ -1100,6 +1166,7 @@ sat2goal::sat2goal():m_imp(0) { void sat2goal::collect_param_descrs(param_descrs & r) { insert_max_memory(r); r.insert("learned", CPK_BOOL, "(default: false) collect also learned clauses."); + r.insert("glue", CPK_UINT, "(default: max-int) collect learned clauses with glue level below parameter."); } struct sat2goal::scoped_set_imp { diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 1a02c97e6..4283da50a 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -150,7 +150,21 @@ public: if (m.canceled()) { throw tactic_exception(Z3_CANCELED_MSG); } - throw tactic_exception(local_solver->reason_unknown().c_str()); + if (in->models_enabled()) { + model_ref mdl; + local_solver->get_model(mdl); + if (mdl) { + mc = model2model_converter(mdl.get()); + mc = concat(fmc.get(), mc.get()); + } + } + in->reset(); + unsigned sz = local_solver->get_num_assertions(); + for (unsigned i = 0; i < sz; ++i) { + in->assert_expr(local_solver->get_assertion(i)); + } + result.push_back(in.get()); + break; } local_solver->collect_statistics(m_st); } diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index a18862ee8..c9ba2f09c 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -117,8 +117,10 @@ struct bit_blaster_model_converter : public model_converter { SASSERT(is_uninterp_const(bit)); func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); - // remark: if old_model does not assign bit_val, then assume it is false. - if (bit_val != 0 && m().is_true(bit_val)) + if (bit_val == 0) { + goto bail; + } + if (m().is_true(bit_val)) val++; } } @@ -133,15 +135,50 @@ struct bit_blaster_model_converter : public model_converter { func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); // remark: if old_model does not assign bit_val, then assume it is false. - if (bit_val != 0 && !util.is_zero(bit_val)) + if (bit_val == 0) { + goto bail; + } + if (!util.is_zero(bit_val)) val++; } } new_val = util.mk_numeral(val, bv_sz); new_model->register_decl(m_vars.get(i), new_val); + continue; + bail: + new_model->register_decl(m_vars.get(i), mk_bv(bs, *old_model)); } } + app_ref mk_bv(expr* bs, model& old_model) { + bv_util util(m()); + unsigned bv_sz = to_app(bs)->get_num_args(); + expr_ref_vector args(m()); + app_ref result(m()); + for (unsigned j = 0; j < bv_sz; ++j) { + expr * bit = to_app(bs)->get_arg(j); + SASSERT(is_uninterp_const(bit)); + func_decl * bit_decl = to_app(bit)->get_decl(); + expr * bit_val = old_model.get_const_interp(bit_decl); + if (bit_val != 0) { + args.push_back(bit_val); + } + else { + args.push_back(bit); + } + } + + if (TO_BOOL) { + SASSERT(is_app_of(bs, m().get_family_id("bv"), OP_MKBV)); + result = util.mk_bv(bv_sz, args.c_ptr()); + } + else { + SASSERT(is_app_of(bs, m().get_family_id("bv"), OP_CONCAT)); + result = util.mk_concat(bv_sz, args.c_ptr()); + } + return result; + } + virtual void operator()(model_ref & md, unsigned goal_idx) { SASSERT(goal_idx == 0); model * new_model = alloc(model, m()); diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index b14d2676c..af58d8331 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -262,6 +262,13 @@ void goal::get_formulas(ptr_vector & result) { } } +void goal::get_formulas(expr_ref_vector & result) { + unsigned sz = size(); + for (unsigned i = 0; i < sz; i++) { + result.push_back(form(i)); + } +} + void goal::update(unsigned i, expr * f, proof * pr, expr_dependency * d) { // KLM: don't know why this assertion is no longer true // SASSERT(proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr))); diff --git a/src/tactic/goal.h b/src/tactic/goal.h index ea02dfa17..5ccbd4529 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -120,6 +120,7 @@ public: void update(unsigned i, expr * f, proof * pr = 0, expr_dependency * dep = 0); void get_formulas(ptr_vector & result); + void get_formulas(expr_ref_vector & result); void elim_true(); void elim_redundancies(); diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 4f5eb5ed0..2052894d2 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -30,7 +30,6 @@ Notes: #include"qffp_tactic.h" #include"qfaufbv_tactic.h" #include"qfauflia_tactic.h" -#include"qfufnra_tactic.h" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), @@ -44,7 +43,6 @@ tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_lira_probe(), mk_lira_tactic(m, p), cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), - //cond(mk_is_qfufnra_probe(), mk_qfufnra_tactic(m, p), mk_smt_tactic()))))))))))), p); return st; diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/portfolio/fd_solver.cpp index a534337bc..12842daac 100644 --- a/src/tactic/portfolio/fd_solver.cpp +++ b/src/tactic/portfolio/fd_solver.cpp @@ -18,11 +18,13 @@ Notes: --*/ #include "fd_solver.h" +#include "fd_tactic.h" #include "tactic.h" #include "inc_sat_solver.h" #include "enum2bv_solver.h" #include "pb2bv_solver.h" #include "bounded_int2bv_solver.h" +#include "solver/solver2tactic.h" solver * mk_fd_solver(ast_manager & m, params_ref const & p) { solver* s = mk_inc_sat_solver(m, p); @@ -31,3 +33,7 @@ solver * mk_fd_solver(ast_manager & m, params_ref const & p) { s = mk_bounded_int2bv_solver(m, p, s); return s; } + +tactic * mk_fd_tactic(ast_manager & m, params_ref const& p) { + return mk_solver2tactic(mk_fd_solver(m, p)); +} diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/portfolio/fd_solver.h index 51abb087f..41605c460 100644 --- a/src/tactic/portfolio/fd_solver.h +++ b/src/tactic/portfolio/fd_solver.h @@ -26,4 +26,5 @@ class solver; solver * mk_fd_solver(ast_manager & m, params_ref const & p); + #endif diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index a4a579ddd..15d2e02c2 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -34,11 +34,11 @@ Notes: #include"default_tactic.h" #include"ufbv_tactic.h" #include"qffp_tactic.h" -#include"qfufnra_tactic.h" #include"horn_tactic.h" #include"smt_solver.h" #include"inc_sat_solver.h" #include"fd_solver.h" +#include"fd_tactic.h" #include"bv_rewriter.h" #include"solver2tactic.h" @@ -91,9 +91,7 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const else if (logic=="HORN") return mk_horn_tactic(m, p); else if (logic == "QF_FD") - return mk_solver2tactic(mk_fd_solver(m, p)); - //else if (logic=="QF_UFNRA") - // return mk_qfufnra_tactic(m, p); + return mk_fd_tactic(m, p); else return mk_default_tactic(m, p); } From 4e65c13726d2fb95e0fb9826a8c200db0e6d4712 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Jun 2017 14:49:54 -0700 Subject: [PATCH 0150/1283] adding lookahead and lemmas Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 56 +++++++++++++++++++ src/api/dotnet/Solver.cs | 23 ++++++++ src/api/python/z3/z3.py | 15 +++++ src/api/z3_api.h | 24 ++++++++ src/sat/sat_lookahead.h | 32 ++++++++++- src/sat/sat_solver.cpp | 10 ++++ src/sat/sat_solver.h | 2 + src/sat/sat_solver/inc_sat_solver.cpp | 22 ++++++++ src/solver/solver.cpp | 6 ++ src/solver/solver.h | 11 ++++ .../portfolio/bounded_int2bv_solver.cpp | 1 + src/tactic/portfolio/enum2bv_solver.cpp | 1 + src/tactic/portfolio/pb2bv_solver.cpp | 1 + 13 files changed, 203 insertions(+), 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 6dc41efb2..c6eae7488 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -477,4 +477,60 @@ extern "C" { Z3_CATCH_RETURN(Z3_L_UNDEF); } + Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, + Z3_solver s, + Z3_ast_vector candidates) { + Z3_TRY; + LOG_Z3_solver_lookahead(c, s, candidates); + ast_manager& m = mk_c(c)->m(); + expr_ref_vector _candidates(m); + ast_ref_vector const& __candidates = to_ast_vector_ref(candidates); + for (auto & e : __candidates) { + if (!is_expr(e)) { + SET_ERROR_CODE(Z3_INVALID_USAGE); + return 0; + } + _candidates.push_back(to_expr(e)); + } + + expr_ref result(m); + unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); + unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); + bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); + cancel_eh eh(mk_c(c)->m().limit()); + api::context::set_interruptable si(*(mk_c(c)), eh); + { + scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); + scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); + try { + result = to_solver_ref(s)->lookahead(_candidates); + } + catch (z3_exception & ex) { + mk_c(c)->handle_exception(ex); + return 0; + } + } + mk_c(c)->save_ast_trail(result); + RETURN_Z3(of_ast(result)); + Z3_CATCH_RETURN(0); + } + + Z3_ast_vector Z3_API Z3_solver_get_lemmas(Z3_context c, Z3_solver s) { + Z3_TRY; + LOG_Z3_solver_get_lemmas(c, s); + RESET_ERROR_CODE(); + ast_manager& m = mk_c(c)->m(); + init_solver(c, s); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + mk_c(c)->save_object(v); + expr_ref_vector lemmas(m); + to_solver_ref(s)->get_lemmas(lemmas); + for (expr* e : lemmas) { + v->m_ast_vector.push_back(e); + } + RETURN_Z3(of_ast_vector(v)); + Z3_CATCH_RETURN(0); + } + }; diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index dff2677df..6dd19cddf 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -252,6 +252,29 @@ namespace Microsoft.Z3 return lboolToStatus(r); } + /// + /// Select a lookahead literal from the set of supplied candidates. + /// + public BoolExpr Lookahead(IEnumerable candidates) + { + ASTVector cands = new ASTVector(Context); + foreach (var c in candidates) cands.Push(c); + return (BoolExpr)Expr.Create(Context, Native.Z3_solver_lookahead(Context.nCtx, NativeObject, cands.NativeObject)); + } + + /// + /// Retrieve set of lemmas that have been inferred by solver. + /// + public BoolExpr[] Lemmas + { + get + { + var r = Native.Z3_solver_get_lemmas(Context.nCtx, NativeObject); + var v = new ASTVector(Context, r); + return v.ToBoolExprArray(); + } + } + /// /// The model of the last Check. /// diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 84a80ddf7..7e93e58ae 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6216,6 +6216,21 @@ class Solver(Z3PPObject): consequences = [ consequences[i] for i in range(sz) ] return CheckSatResult(r), consequences + def lemmas(self): + """Extract auxiliary lemmas produced by solver""" + return AstVector(Z3_solver_get_lemmas(self.ctx.ref(), self.solver), self.ctx) + + def lookahead(self, candidates = None): + """Get lookahead literal""" + if candidates is None: + candidates = AstVector(None, self.ctx) + elif not isinstance(candidates, AstVector): + _cs = AstVector(None, self.ctx) + for c in candidates: + _asms.push(c) + candidates = _cs + return _to_expr_ref(Z3_solver_lookahead(self.ctx.ref(), self.solver, candidates), self.ctx) + def proof(self): """Return a proof for the last `check()`. Proof construction must be enabled.""" return _to_expr_ref(Z3_solver_get_proof(self.ctx.ref(), self.solver), self.ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 45065f856..e3bd942bd 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6023,6 +6023,29 @@ extern "C" { Z3_ast_vector assumptions, Z3_ast_vector variables, Z3_ast_vector consequences); + + /** + \brief select a literal from the list of candidate propositional variables to split on. + If the candidate list is empty, then the solver chooses a formula based on its internal state. + + def_API('Z3_solver_lookahead', AST, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR))) + */ + + Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, Z3_solver s, Z3_ast_vector candidates); + + + /** + \brief retrieve lemmas from solver state. Lemmas are auxiliary unit literals, + binary clauses and other learned clauses that are below a minimal glue level. + Lemmas that have been retrieved in a previous call may be suppressed from subsequent + calls. + + def_API('Z3_solver_get_lemmas', AST_VECTOR, (_in(CONTEXT), _in(SOLVER))) + */ + + Z3_ast_vector Z3_API Z3_solver_get_lemmas(Z3_context c, Z3_solver s); + + /** \brief Retrieve the model for the last #Z3_solver_check or #Z3_solver_check_assumptions @@ -6031,6 +6054,7 @@ extern "C" { def_API('Z3_solver_get_model', MODEL, (_in(CONTEXT), _in(SOLVER))) */ + Z3_model Z3_API Z3_solver_get_model(Z3_context c, Z3_solver s); /** diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 7f01197f2..8f7a7675f 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -384,6 +384,7 @@ namespace sat { candidate(bool_var v, float r): m_var(v), m_rating(r) {} }; svector m_candidates; + uint_set m_select_lookahead_vars; float get_rating(bool_var v) const { return m_rating[v]; } float get_rating(literal l) const { return get_rating(l.var()); } @@ -468,7 +469,11 @@ namespace sat { for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { SASSERT(is_undef(*it)); bool_var x = *it; - if (newbies || active_prefix(x)) { + if (!m_select_lookahead_vars.empty() && m_select_lookahead_vars.contains(x)) { + m_candidates.push_back(candidate(x, m_rating[x])); + sum += m_rating[x]; + } + else if (newbies || active_prefix(x)) { m_candidates.push_back(candidate(x, m_rating[x])); sum += m_rating[x]; } @@ -1853,6 +1858,31 @@ namespace sat { return search(); } + literal select_lookahead(bool_var_vector const& vars) { + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + if (inconsistent()) return null_literal; + inc_istamp(); + for (auto v : vars) { + m_select_lookahead_vars.insert(v); + } + literal l = choose(); + m_select_lookahead_vars.reset(); + if (inconsistent()) return null_literal; + + // assign unit literals that were found during search for lookahead. + unsigned num_assigned = 0; + for (literal lit : m_trail) { + if (!m_s.was_eliminated(lit.var()) && m_s.value(lit) != l_true) { + m_s.assign(lit, justification()); + ++num_assigned; + } + } + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_assigned << ")\n";); + return l; + } + /** \brief simplify set of clauses by extracting units from a lookahead at base level. */ diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8095ee12d..fd26bdd70 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -809,6 +809,16 @@ namespace sat { return r; } + literal solver::select_lookahead(bool_var_vector const& vars) { + lookahead lh(*this); + literal result = lh.select_lookahead(vars); + if (result == null_literal) { + set_conflict(justification()); + } + // extract unit literals from lh + return result; + } + // ----------------------- // // Search diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c512597b0..54ea360e4 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -352,6 +352,8 @@ namespace sat { model_converter const & get_model_converter() const { return m_mc; } void set_model(model const& mdl); + literal select_lookahead(bool_var_vector const& vars); + protected: unsigned m_conflicts; unsigned m_restarts; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 5016d20cd..225fd8d63 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -255,6 +255,28 @@ public: return 0; } + virtual expr_ref lookahead(expr_ref_vector const& candidates) { + sat::bool_var_vector vars; + u_map var2candidate; + for (auto c : candidates) { + // TBD: check membership + sat::bool_var v = m_map.to_bool_var(c); + SASSERT(v != sat::null_bool_var); + vars.push_back(v); + var2candidate.insert(v, c); + } + sat::literal l = m_solver.select_lookahead(vars); + if (l == sat::null_literal) { + return expr_ref(m.mk_true(), m); + } + expr* e; + if (!var2candidate.find(l.var(), e)) { + // TBD: if candidate set is empty, then do something else. + e = m.mk_true(); + } + return expr_ref(l.sign() ? m.mk_not(e) : e, m); + } + virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { init_preprocess(); TRACE("sat", tout << assumptions << "\n" << vars << "\n";); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 9163cfeda..59b950972 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -162,3 +162,9 @@ bool solver::is_literal(ast_manager& m, expr* e) { return is_uninterp_const(e) || (m.is_not(e, e) && is_uninterp_const(e)); } +expr_ref solver::lookahead(expr_ref_vector const& candidates) { + ast_manager& m = candidates.get_manager(); + return expr_ref(m.mk_true(), m); +} + + diff --git a/src/solver/solver.h b/src/solver/solver.h index 6b9d38f29..51bff08ad 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -172,6 +172,17 @@ public: */ virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); + /** + \brief extract a lookahead candidates for branching. + */ + + virtual expr_ref lookahead(expr_ref_vector const& candidates); + + /** + \brief extract learned lemmas. + */ + virtual void get_lemmas(expr_ref_vector& lemmas) {} + /** \brief Display the content of this solver. */ diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 83693abba..cee8688e5 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -149,6 +149,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } + virtual expr_ref lookahead(expr_ref_vector& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 35601f374..ef7ee6cd8 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -97,6 +97,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } + virtual expr_ref lookahead(expr_ref_vector& candidates) { return m_solver->lookahead(candidates); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { datatype_util dt(m); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index c8aa82e97..673db03c0 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -93,6 +93,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } + virtual expr_ref lookahead(expr_ref_vector& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); From 538411c67f26600815d5398d2c02b461055573af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Jun 2017 15:03:34 -0700 Subject: [PATCH 0151/1283] remove dependencies on fd_tactic.h Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/fd_solver.cpp | 1 - src/tactic/portfolio/fd_solver.h | 5 +++++ src/tactic/portfolio/smt_strategic_solver.cpp | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/portfolio/fd_solver.cpp index 12842daac..c56c0359e 100644 --- a/src/tactic/portfolio/fd_solver.cpp +++ b/src/tactic/portfolio/fd_solver.cpp @@ -18,7 +18,6 @@ Notes: --*/ #include "fd_solver.h" -#include "fd_tactic.h" #include "tactic.h" #include "inc_sat_solver.h" #include "enum2bv_solver.h" diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/portfolio/fd_solver.h index 41605c460..a52245e0d 100644 --- a/src/tactic/portfolio/fd_solver.h +++ b/src/tactic/portfolio/fd_solver.h @@ -23,8 +23,13 @@ Notes: #include"params.h" class solver; +class tactic; solver * mk_fd_solver(ast_manager & m, params_ref const & p); +tactic * mk_fd_tactic(ast_manager & m, params_ref const & p); +/* + ADD_TACTIC("qffd", "builtin strategy for solving QF_FD problems.", "mk_fd_tactic(m, p)") +*/ #endif diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 15d2e02c2..188174eca 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -38,7 +38,6 @@ Notes: #include"smt_solver.h" #include"inc_sat_solver.h" #include"fd_solver.h" -#include"fd_tactic.h" #include"bv_rewriter.h" #include"solver2tactic.h" From e37a6dd809060c28d6bdc3c1e8d38e921ef72489 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Jun 2017 17:04:37 -0700 Subject: [PATCH 0152/1283] add tracking for reason unknown Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 5 ----- src/sat/sat_solver.cpp | 6 ++++++ src/sat/sat_solver.h | 4 ++++ src/sat/sat_solver/inc_sat_solver.cpp | 6 +++++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 2e3fbdd77..afeed35be 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -233,11 +233,6 @@ namespace sat { CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); - if (!learned) { - // perform lookahead simplification - lookahead(s).simplify(); - } - finalize(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a3383ed55..6f117de72 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -57,6 +57,7 @@ namespace sat { m_scope_lvl(0), m_search_lvl(0), m_params(p) { + init_reason_unknown(); updt_params(p); m_conflicts_since_gc = 0; m_conflicts = 0; @@ -826,6 +827,7 @@ namespace sat { // // ----------------------- lbool solver::check(unsigned num_lits, literal const* lits) { + init_reason_unknown(); pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); @@ -872,6 +874,7 @@ namespace sat { if (check_inconsistent()) return l_false; if (m_config.m_max_conflicts == 0) { + m_reason_unknown = "sat.max.conflicts"; IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = 0\")\n";); return l_undef; } @@ -884,6 +887,7 @@ namespace sat { return r; if (m_conflicts > m_config.m_max_conflicts) { + m_reason_unknown = "sat.max.conflicts"; IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts << "\")\n";); return l_undef; } @@ -894,6 +898,7 @@ namespace sat { gc(); if (m_config.m_restart_max <= m_restarts) { + m_reason_unknown = "sat.max.restarts"; IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); return l_undef; } @@ -901,6 +906,7 @@ namespace sat { } } catch (abort_solver) { + m_reason_unknown = "sat.giveup"; return l_undef; } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 54ea360e4..ea8246466 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -132,6 +132,8 @@ namespace sat { unsigned m_search_lvl; literal_vector m_trail; clause_wrapper_vector m_clauses_to_reinit; + std::string m_reason_unknown; + struct scope { unsigned m_trail_lim; unsigned m_clauses_to_reinit_lim; @@ -351,6 +353,7 @@ namespace sat { literal_vector const& get_core() const { return m_core; } model_converter const & get_model_converter() const { return m_mc; } void set_model(model const& mdl); + char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } literal select_lookahead(bool_var_vector const& vars); @@ -374,6 +377,7 @@ namespace sat { literal_vector m_min_core; bool m_min_core_valid; + void init_reason_unknown() { m_reason_unknown = "no reason given"; } void init_assumptions(unsigned num_lits, literal const* lits); void reassert_min_core(); void update_min_core(); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 225fd8d63..2f02e14e2 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -151,6 +151,7 @@ public: m_internalized = true; m_internalized_converted = false; + init_reason_unknown(); r = m_solver.check(m_asms.size(), m_asms.c_ptr()); switch (r) { @@ -166,6 +167,7 @@ public: } break; default: + set_reason_unknown(m_solver.get_reason_unknown()); break; } return r; @@ -345,7 +347,9 @@ public: return l_true; } - + void init_reason_unknown() { + m_unknown = "no reason given"; + } virtual std::string reason_unknown() const { return m_unknown; } From 0ac80fc042ba9ff4fed0e7283ed72b9a26b606c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Jun 2017 21:21:05 -0700 Subject: [PATCH 0153/1283] have parser produce ast-vector instead of single ast Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 4 ++-- examples/c/test_capi.c | 7 +++++-- src/api/api_interp.cpp | 11 ++++++----- src/api/api_parsers.cpp | 22 ++++++++++++++-------- src/api/c++/z3++.h | 32 ++++++++++++++++---------------- src/api/dotnet/Context.cs | 10 ++++++---- src/api/java/Context.java | 10 ++++++---- src/api/z3_api.h | 10 ++++------ src/test/smt2print_parse.cpp | 21 ++++++++++++++++----- 9 files changed, 75 insertions(+), 52 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 2d7d051c5..732a89099 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -470,7 +470,7 @@ void unsat_core_example2() { // The solver s already contains p1 => F // To disable F, we add (not p1) as an additional assumption qs.push_back(!p1); - std::cout << s.check(qs.size(), &qs[0]) << "\n"; + std::cout << s.check(static_cast(qs.size()), &qs[0]) << "\n"; expr_vector core2 = s.unsat_core(); std::cout << core2 << "\n"; std::cout << "size: " << core2.size() << "\n"; @@ -1136,7 +1136,7 @@ static void parse_example() { func_decl_vector decls(c); sort B = c.bool_sort(); decls.push_back(c.function("a", 0, 0, B)); - expr a = c.parse_string("(assert a)", sorts, decls); + expr_vector a = c.parse_string("(assert a)", sorts, decls); std::cout << a << "\n"; } diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 88fdaa1cf..56b402ad5 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2632,13 +2632,16 @@ void reference_counter_example() { */ void smt2parser_example() { Z3_context ctx; - Z3_ast fs; + Z3_ast_vector fs; printf("\nsmt2parser_example\n"); LOG_MSG("smt2parser_example"); ctx = mk_context(); fs = Z3_parse_smtlib2_string(ctx, "(declare-fun a () (_ BitVec 8)) (assert (bvuge a #x10)) (assert (bvule a #xf0))", 0, 0, 0, 0, 0, 0); - printf("formulas: %s\n", Z3_ast_to_string(ctx, fs)); + Z3_ast_vector_inc_ref(ctx, fs); + printf("formulas: %s\n", Z3_ast_vector_to_string(ctx, fs)); + Z3_ast_vector_dec_ref(ctx, fs); + Z3_del_context(ctx); } diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index 10aa06568..abfca9827 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -511,12 +511,13 @@ extern "C" { try { std::string foo(filename); if (foo.size() >= 5 && foo.substr(foo.size() - 5) == ".smt2"){ - Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0); - Z3_app app = Z3_to_app(ctx, assrts); - int nconjs = Z3_get_app_num_args(ctx, app); + Z3_ast_vector assrts = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0); + Z3_ast_vector_inc_ref(ctx, assrts); + unsigned nconjs = Z3_ast_vector_size(ctx, assrts); assertions.resize(nconjs); - for (int k = 0; k < nconjs; k++) - assertions[k] = Z3_get_app_arg(ctx, app, k); + for (unsigned k = 0; k < nconjs; k++) + assertions[k] = Z3_ast_vector_get(ctx, assrts, k); + // Z3_ast_vector_dec_ref(ctx, assrts) is unsafe } else { Z3_parse_smtlib_file(ctx, filename, 0, 0, 0, 0, 0, 0); diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 8f6eb1125..29c7fa707 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -24,6 +24,7 @@ Revision History: #include"smt2parser.h" #include"smtparser.h" #include"solver_na2as.h" +#include"api_ast_vector.h" extern "C" { @@ -252,7 +253,7 @@ extern "C" { // --------------- // Support for SMTLIB2 - Z3_ast parse_smtlib2_stream(bool exec, Z3_context c, std::istream& is, + Z3_ast_vector parse_smtlib2_stream(bool exec, Z3_context c, std::istream& is, unsigned num_sorts, Z3_symbol const sort_names[], Z3_sort const sorts[], @@ -262,6 +263,9 @@ extern "C" { Z3_TRY; cmd_context ctx(false, &(mk_c(c)->m())); ctx.set_ignore_check(true); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + mk_c(c)->save_object(v); + for (unsigned i = 0; i < num_decls; ++i) { ctx.insert(to_symbol(decl_names[i]), to_func_decl(decls[i])); } @@ -271,16 +275,18 @@ extern "C" { } if (!parse_smt2_commands(ctx, is)) { SET_ERROR_CODE(Z3_PARSER_ERROR); - return of_ast(mk_c(c)->m().mk_true()); + return of_ast_vector(v); } ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); - unsigned size = static_cast(end - it); - return of_ast(mk_c(c)->mk_and(size, it)); + for (; it != end; ++it) { + v->m_ast_vector.push_back(*it); + } + return of_ast_vector(v); Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_parse_smtlib2_string(Z3_context c, Z3_string str, + Z3_ast_vector Z3_API Z3_parse_smtlib2_string(Z3_context c, Z3_string str, unsigned num_sorts, Z3_symbol const sort_names[], Z3_sort const sorts[], @@ -291,12 +297,12 @@ extern "C" { LOG_Z3_parse_smtlib2_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); std::string s(str); std::istringstream is(s); - Z3_ast r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); + Z3_ast_vector r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); RETURN_Z3(r); Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_parse_smtlib2_file(Z3_context c, Z3_string file_name, + Z3_ast_vector Z3_API Z3_parse_smtlib2_file(Z3_context c, Z3_string file_name, unsigned num_sorts, Z3_symbol const sort_names[], Z3_sort const sorts[], @@ -310,7 +316,7 @@ extern "C" { SET_ERROR_CODE(Z3_PARSER_ERROR); return 0; } - Z3_ast r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); + Z3_ast_vector r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); RETURN_Z3(r); Z3_CATCH_RETURN(0); } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 9d9982523..bd03237be 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -309,11 +309,11 @@ namespace z3 { /** \brief parsing */ - expr parse_string(char const* s); - expr parse_file(char const* file); + expr_vector parse_string(char const* s); + expr_vector parse_file(char const* file); - expr parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls); - expr parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls); + expr_vector parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls); + expr_vector parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls); /** \brief Interpolation support @@ -2701,19 +2701,19 @@ namespace z3 { return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a)); } - inline expr context::parse_string(char const* s) { - Z3_ast r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); + inline expr_vector context::parse_string(char const* s) { + Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); check_error(); - return expr(*this, r); + return expr_vector(*this, r); } - inline expr context::parse_file(char const* s) { - Z3_ast r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); + inline expr_vector context::parse_file(char const* s) { + Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); check_error(); - return expr(*this, r); + return expr_vector(*this, r); } - inline expr context::parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls) { + inline expr_vector context::parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls) { array sort_names(sorts.size()); array decl_names(decls.size()); array sorts1(sorts); @@ -2724,12 +2724,12 @@ namespace z3 { for (unsigned i = 0; i < decls.size(); ++i) { decl_names[i] = decls[i].name(); } - Z3_ast r = Z3_parse_smtlib2_string(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); + Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); check_error(); - return expr(*this, r); + return expr_vector(*this, r); } - inline expr context::parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls) { + inline expr_vector context::parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls) { array sort_names(sorts.size()); array decl_names(decls.size()); array sorts1(sorts); @@ -2740,9 +2740,9 @@ namespace z3 { for (unsigned i = 0; i < decls.size(); ++i) { decl_names[i] = decls[i].name(); } - Z3_ast r = Z3_parse_smtlib2_file(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); + Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); check_error(); - return expr(*this, r); + return expr_vector(*this, r); } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index a656be3eb..a6614a202 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3390,7 +3390,7 @@ namespace Microsoft.Z3 /// /// /// A conjunction of assertions in the scope (up to push/pop) at the end of the string. - public BoolExpr ParseSMTLIB2String(string str, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) + public BoolExpr[] ParseSMTLIB2String(string str, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) { Contract.Ensures(Contract.Result() != null); @@ -3400,16 +3400,17 @@ namespace Microsoft.Z3 uint cd = AST.ArrayLength(decls); if (csn != cs || cdn != cd) throw new Z3Exception("Argument size mismatch"); - return (BoolExpr)Expr.Create(this, Native.Z3_parse_smtlib2_string(nCtx, str, + ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_string(nCtx, str, AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts), AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls))); + return assertions.ToBoolExprArray(); } /// /// Parse the given file using the SMT-LIB2 parser. /// /// - public BoolExpr ParseSMTLIB2File(string fileName, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) + public BoolExpr[] ParseSMTLIB2File(string fileName, Symbol[] sortNames = null, Sort[] sorts = null, Symbol[] declNames = null, FuncDecl[] decls = null) { Contract.Ensures(Contract.Result() != null); @@ -3419,9 +3420,10 @@ namespace Microsoft.Z3 uint cd = AST.ArrayLength(decls); if (csn != cs || cdn != cd) throw new Z3Exception("Argument size mismatch"); - return (BoolExpr)Expr.Create(this, Native.Z3_parse_smtlib2_file(nCtx, fileName, + ASTVector assertions = new ASTVector(this, Native.Z3_parse_smtlib2_file(nCtx, fileName, AST.ArrayLength(sorts), Symbol.ArrayToNative(sortNames), AST.ArrayToNative(sorts), AST.ArrayLength(decls), Symbol.ArrayToNative(declNames), AST.ArrayToNative(decls))); + return assertions.ToBoolExprArray(); } #endregion diff --git a/src/api/java/Context.java b/src/api/java/Context.java index db7a08711..d9e938086 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2621,7 +2621,7 @@ public class Context implements AutoCloseable { * @return A conjunction of assertions in the scope (up to push/pop) at the * end of the string. **/ - public BoolExpr parseSMTLIB2String(String str, Symbol[] sortNames, + public BoolExpr[] parseSMTLIB2String(String str, Symbol[] sortNames, Sort[] sorts, Symbol[] declNames, FuncDecl[] decls) { @@ -2633,17 +2633,18 @@ public class Context implements AutoCloseable { if (csn != cs || cdn != cd) { throw new Z3Exception("Argument size mismatch"); } - return (BoolExpr) Expr.create(this, Native.parseSmtlib2String(nCtx(), + ASTVector v = new ASTVector(this, Native.parseSmtlib2String(nCtx(), str, AST.arrayLength(sorts), Symbol.arrayToNative(sortNames), AST.arrayToNative(sorts), AST.arrayLength(decls), Symbol.arrayToNative(declNames), AST.arrayToNative(decls))); + return v.ToBoolExprArray(); } /** * Parse the given file using the SMT-LIB2 parser. * @see #parseSMTLIB2String **/ - public BoolExpr parseSMTLIB2File(String fileName, Symbol[] sortNames, + public BoolExpr[] parseSMTLIB2File(String fileName, Symbol[] sortNames, Sort[] sorts, Symbol[] declNames, FuncDecl[] decls) { @@ -2653,11 +2654,12 @@ public class Context implements AutoCloseable { int cd = AST.arrayLength(decls); if (csn != cs || cdn != cd) throw new Z3Exception("Argument size mismatch"); - return (BoolExpr) Expr.create(this, Native.parseSmtlib2File(nCtx(), + ASTVector v = new ASTVector(this, Native.parseSmtlib2File(nCtx(), fileName, AST.arrayLength(sorts), Symbol.arrayToNative(sortNames), AST.arrayToNative(sorts), AST.arrayLength(decls), Symbol.arrayToNative(declNames), AST.arrayToNative(decls))); + return v.ToBoolExprArray(); } /** diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e3bd942bd..4ae7c5c22 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5059,9 +5059,9 @@ extern "C" { It returns a formula comprising of the conjunction of assertions in the scope (up to push/pop) at the end of the string. - def_API('Z3_parse_smtlib2_string', AST, (_in(CONTEXT), _in(STRING), _in(UINT), _in_array(2, SYMBOL), _in_array(2, SORT), _in(UINT), _in_array(5, SYMBOL), _in_array(5, FUNC_DECL))) + def_API('Z3_parse_smtlib2_string', AST_VECTOR, (_in(CONTEXT), _in(STRING), _in(UINT), _in_array(2, SYMBOL), _in_array(2, SORT), _in(UINT), _in_array(5, SYMBOL), _in_array(5, FUNC_DECL))) */ - Z3_ast Z3_API Z3_parse_smtlib2_string(Z3_context c, + Z3_ast_vector Z3_API Z3_parse_smtlib2_string(Z3_context c, Z3_string str, unsigned num_sorts, Z3_symbol const sort_names[], @@ -5073,9 +5073,9 @@ extern "C" { /** \brief Similar to #Z3_parse_smtlib2_string, but reads the benchmark from a file. - def_API('Z3_parse_smtlib2_file', AST, (_in(CONTEXT), _in(STRING), _in(UINT), _in_array(2, SYMBOL), _in_array(2, SORT), _in(UINT), _in_array(5, SYMBOL), _in_array(5, FUNC_DECL))) + def_API('Z3_parse_smtlib2_file', AST_VECTOR, (_in(CONTEXT), _in(STRING), _in(UINT), _in_array(2, SYMBOL), _in_array(2, SORT), _in(UINT), _in_array(5, SYMBOL), _in_array(5, FUNC_DECL))) */ - Z3_ast Z3_API Z3_parse_smtlib2_file(Z3_context c, + Z3_ast_vector Z3_API Z3_parse_smtlib2_file(Z3_context c, Z3_string file_name, unsigned num_sorts, Z3_symbol const sort_names[], @@ -6045,7 +6045,6 @@ extern "C" { Z3_ast_vector Z3_API Z3_solver_get_lemmas(Z3_context c, Z3_solver s); - /** \brief Retrieve the model for the last #Z3_solver_check or #Z3_solver_check_assumptions @@ -6054,7 +6053,6 @@ extern "C" { def_API('Z3_solver_get_model', MODEL, (_in(CONTEXT), _in(SOLVER))) */ - Z3_model Z3_API Z3_solver_get_model(Z3_context c, Z3_solver s); /** diff --git a/src/test/smt2print_parse.cpp b/src/test/smt2print_parse.cpp index c79a80ae5..ba497d180 100644 --- a/src/test/smt2print_parse.cpp +++ b/src/test/smt2print_parse.cpp @@ -10,13 +10,21 @@ Copyright (c) 2015 Microsoft Corporation #include "z3.h" #include -void test_print(Z3_context ctx, Z3_ast a) { +void test_print(Z3_context ctx, Z3_ast_vector av) { Z3_set_ast_print_mode(ctx, Z3_PRINT_SMTLIB2_COMPLIANT); + Z3_ast* args = new Z3_ast[Z3_ast_vector_size(ctx, av)]; + for (unsigned i = 0; i < Z3_ast_vector_size(ctx, av); ++i) { + args[i] = Z3_ast_vector_get(ctx, av, i); + } + Z3_ast a = Z3_mk_and(ctx, Z3_ast_vector_size(ctx, av), args); + Z3_inc_ref(ctx, a); + delete[] args; char const* spec1 = Z3_benchmark_to_smtlib_string(ctx, "test", 0, 0, 0, 0, 0, a); + Z3_dec_ref(ctx, a); std::cout << "spec1: benchmark->string\n" << spec1 << "\n"; std::cout << "attempting to parse spec1...\n"; - Z3_ast b = + Z3_ast_vector b = Z3_parse_smtlib2_string(ctx, spec1, 0, @@ -26,15 +34,17 @@ void test_print(Z3_context ctx, Z3_ast a) { 0, 0); std::cout << "parse successful, converting ast->string\n"; - char const* spec2 = Z3_ast_to_string(ctx, b); + Z3_ast_vector_inc_ref(ctx, b); + char const* spec2 = Z3_ast_vector_to_string(ctx, b); std::cout << "spec2: string->ast->string\n" << spec2 << "\n"; + Z3_ast_vector_dec_ref(ctx, b); } void test_parseprint(char const* spec) { Z3_context ctx = Z3_mk_context(0); std::cout << "spec:\n" << spec << "\n"; - Z3_ast a = + Z3_ast_vector a = Z3_parse_smtlib2_string(ctx, spec, 0, @@ -45,11 +55,12 @@ void test_parseprint(char const* spec) { 0); std::cout << "done parsing\n"; - + Z3_ast_vector_inc_ref(ctx, a); test_print(ctx, a); std::cout << "done printing\n"; + Z3_ast_vector_dec_ref(ctx, a); Z3_del_context(ctx); } From 71b6f97fb1783302407d8c5a96787261d0786c1e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Jun 2017 11:55:53 -0700 Subject: [PATCH 0154/1283] fix lookahead code Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver/inc_sat_solver.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6ef6cb9cb..c636c3f2a 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -282,24 +282,25 @@ public: virtual expr_ref lookahead(expr_ref_vector const& candidates) { sat::bool_var_vector vars; - u_map var2candidate; + expr_ref_vector lit2expr(m); + m_map.mk_inv(lit2expr); for (auto c : candidates) { - // TBD: check membership sat::bool_var v = m_map.to_bool_var(c); - SASSERT(v != sat::null_bool_var); - vars.push_back(v); - var2candidate.insert(v, c); + if (v != sat::null_bool_var) { + vars.push_back(v); + } + } + if (vars.empty()) { + return expr_ref(m.mk_true(), m); } sat::literal l = m_solver.select_lookahead(vars); + if (m_solver.inconsistent()) { + return expr_ref(m.mk_false(), m); + } if (l == sat::null_literal) { return expr_ref(m.mk_true(), m); } - expr* e; - if (!var2candidate.find(l.var(), e)) { - // TBD: if candidate set is empty, then do something else. - e = m.mk_true(); - } - return expr_ref(l.sign() ? m.mk_not(e) : e, m); + return expr_ref(lit2expr[l.index()].get(), m); } virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { From c33dce116187bee212bc86a7085639240ac878d6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Jun 2017 14:12:55 -0700 Subject: [PATCH 0155/1283] extract lemmas Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.h | 2 + src/sat/sat_solver.cpp | 6 +- src/sat/sat_solver.h | 3 +- src/sat/sat_solver/inc_sat_solver.cpp | 15 +++- src/sat/tactic/goal2sat.cpp | 75 ++++++++++++++++++- src/sat/tactic/goal2sat.h | 7 ++ .../portfolio/bounded_int2bv_solver.cpp | 1 + src/tactic/portfolio/enum2bv_solver.cpp | 1 + src/tactic/portfolio/pb2bv_solver.cpp | 1 + 9 files changed, 104 insertions(+), 7 deletions(-) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 27a0ed739..11824b247 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -73,6 +73,8 @@ namespace sat { bool check_approx() const; // for debugging literal * begin() { return m_lits; } literal * end() { return m_lits + m_size; } + literal const * begin() const { return m_lits; } + literal const * end() const { return m_lits + m_size; } bool contains(literal l) const; bool contains(bool_var v) const; bool satisfied_by(model const & m) const; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 6f117de72..e45373b5c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3004,7 +3004,8 @@ namespace sat { // Iterators // // ----------------------- - void solver::collect_bin_clauses(svector & r, bool learned) const { + void solver::collect_bin_clauses(svector & r, bool learned, bool learned_only) const { + SASSERT(learned || !learned_only); unsigned sz = m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; l_idx++) { literal l = to_literal(l_idx); @@ -3017,6 +3018,8 @@ namespace sat { continue; if (!learned && it->is_learned()) continue; + else if (learned && learned_only && !it->is_learned()) + continue; literal l2 = it->get_literal(); if (l.index() > l2.index()) continue; @@ -3327,7 +3330,6 @@ namespace sat { m_user_bin_clauses.reset(); m_binary_clause_graph.reset(); collect_bin_clauses(m_user_bin_clauses, true); - collect_bin_clauses(m_user_bin_clauses, false); hashtable, default_eq > seen_bc; for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) { literal l1 = m_user_bin_clauses[i].first; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index ea8246466..348e1cd22 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -586,7 +586,8 @@ namespace sat { clause * const * end_clauses() const { return m_clauses.end(); } clause * const * begin_learned() const { return m_learned.begin(); } clause * const * end_learned() const { return m_learned.end(); } - void collect_bin_clauses(svector & r, bool learned) const; + clause_vector const& learned() const { return m_learned; } + void collect_bin_clauses(svector & r, bool learned, bool learned_only = false) const; // ----------------------- // diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index c636c3f2a..eb931d428 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -302,6 +302,15 @@ public: } return expr_ref(lit2expr[l.index()].get(), m); } + virtual void get_lemmas(expr_ref_vector & lemmas) { + IF_VERBOSE(1, verbose_stream() << "(sat-get-lemmas " << lemmas.size() << ")\n";); + if (!m_internalized) return; + sat2goal s2g; + goal g(m, false, false, false); + s2g.get_learned(m_solver, m_map, m_params, lemmas); + // TBD: handle externals properly. + } + virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { init_preprocess(); @@ -426,9 +435,9 @@ public: g.get_formulas(m_internalized_fmls); // g.display(std::cout); m_internalized_converted = true; - // if (mc) mc->display(std::cout << "mc"); - // if (m_mc) m_mc->display(std::cout << "m_mc\n"); - // if (m_mc0) m_mc0->display(std::cout << "m_mc0\n"); + // if (mc) mc->display(std::cout << "mc"); + // if (m_mc) m_mc->display(std::cout << "m_mc\n"); + // if (m_mc0) m_mc0->display(std::cout << "m_mc0\n"); } void init_preprocess() { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 6604bab89..cb4a19e89 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -36,6 +36,7 @@ Notes: #include"model_v2_pp.h" #include"tactic.h" #include"ast_pp.h" +#include"ast_util.h" #include"pb_decl_plugin.h" #include"card_extension.h" #include @@ -1143,7 +1144,6 @@ struct sat2goal::imp { assert_clauses(s, s.begin_clauses(), s.end_clauses(), r, true); assert_clauses(s, s.begin_learned(), s.end_learned(), r, false); - // TBD: collect assertions from plugin sat::card_extension* ext = get_card_extension(s); if (ext) { for (unsigned i = 0; i < ext->num_pb(); ++i) { @@ -1158,6 +1158,73 @@ struct sat2goal::imp { } } + void add_clause(sat::literal_vector const& lits, expr_ref_vector& lemmas) { + expr_ref_vector lemma(m); + for (sat::literal l : lits) { + expr* e = m_lit2expr.get(l.index(), 0); + if (!e) return; + lemma.push_back(e); + } + lemmas.push_back(mk_or(lemma)); + } + + void add_clause(sat::clause const& c, expr_ref_vector& lemmas) { + expr_ref_vector lemma(m); + for (sat::literal l : c) { + expr* e = m_lit2expr.get(l.index(), 0); + if (!e) return; + lemma.push_back(e); + } + lemmas.push_back(mk_or(lemma)); + } + + void get_learned(sat::solver const& s, atom2bool_var const& map, expr_ref_vector& lemmas) { + if (s.inconsistent()) { + lemmas.push_back(m.mk_false()); + return; + } + + unsigned num_vars = s.num_vars(); + m_lit2expr.resize(num_vars * 2); + map.mk_inv(m_lit2expr); + + sat::literal_vector lits; + // collect units + for (sat::bool_var v = 0; v < num_vars; v++) { + checkpoint(); + lits.reset(); + switch (s.value(v)) { + case l_true: + lits.push_back(sat::literal(v, false)); + add_clause(lits, lemmas); + break; + case l_false: + lits.push_back(sat::literal(v, false)); + add_clause(lits, lemmas); + break; + case l_undef: + break; + } + } + // collect learned binary clauses + svector bin_clauses; + s.collect_bin_clauses(bin_clauses, true, true); + svector::iterator it = bin_clauses.begin(); + svector::iterator end = bin_clauses.end(); + for (; it != end; ++it) { + checkpoint(); + lits.reset(); + lits.push_back(it->first); + lits.push_back(it->second); + add_clause(lits, lemmas); + } + // collect clauses + for (sat::clause const* c : s.learned()) { + add_clause(*c, lemmas); + } + } + + }; sat2goal::sat2goal():m_imp(0) { @@ -1186,3 +1253,9 @@ void sat2goal::operator()(sat::solver const & t, atom2bool_var const & m, params proc(t, m, g, mc); } +void sat2goal::get_learned(sat::solver const & t, atom2bool_var const & m, params_ref const& p, expr_ref_vector& lemmas) { + imp proc(lemmas.get_manager(), p); + scoped_set_imp set(this, &proc); + proc.get_learned(t, m, lemmas); +} + diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index cd63cd497..5bfb28f60 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -85,6 +85,13 @@ public: or memory consumption limit is reached (set with param :max-memory). */ void operator()(sat::solver const & t, atom2bool_var const & m, params_ref const & p, goal & s, model_converter_ref & mc); + + + /** + \brief extract learned clauses only that are in the domain of m. + + */ + void get_learned(sat::solver const& s, atom2bool_var const& m, params_ref const& p, expr_ref_vector& learned); }; diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index cee8688e5..3645ba97a 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -150,6 +150,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual expr_ref lookahead(expr_ref_vector& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } + virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index ef7ee6cd8..a40f2988a 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -98,6 +98,7 @@ public: virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual expr_ref lookahead(expr_ref_vector& candidates) { return m_solver->lookahead(candidates); } + virtual void get_lemmas(expr_ref_vector & lemmas) { m_solver->get_lemmas(lemmas); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { datatype_util dt(m); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 673db03c0..8bf6b7e39 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -94,6 +94,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual expr_ref lookahead(expr_ref_vector& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } + virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); From 83635eb8269390d2eee156fd3a903fc2a2064df4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Jun 2017 16:05:14 -0700 Subject: [PATCH 0156/1283] fix iz3parse for updated API Signed-off-by: Nikolaj Bjorner --- src/api/api_interp.cpp | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index abfca9827..a1fa8f137 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -506,42 +506,39 @@ extern "C" { static std::string read_msg; static std::vector read_theory; - static bool iZ3_parse(Z3_context ctx, const char *filename, const char **error, svector &assertions){ + static Z3_ast_vector iZ3_parse(Z3_context ctx, const char *filename, const char ** error){ read_error.clear(); try { std::string foo(filename); if (foo.size() >= 5 && foo.substr(foo.size() - 5) == ".smt2"){ Z3_ast_vector assrts = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0); Z3_ast_vector_inc_ref(ctx, assrts); - unsigned nconjs = Z3_ast_vector_size(ctx, assrts); - assertions.resize(nconjs); - for (unsigned k = 0; k < nconjs; k++) - assertions[k] = Z3_ast_vector_get(ctx, assrts, k); - // Z3_ast_vector_dec_ref(ctx, assrts) is unsafe + return assrts; } else { Z3_parse_smtlib_file(ctx, filename, 0, 0, 0, 0, 0, 0); int numa = Z3_get_smtlib_num_assumptions(ctx); int numf = Z3_get_smtlib_num_formulas(ctx); - int num = numa + numf; + Z3_ast_vector assrts = Z3_mk_ast_vector(ctx); + Z3_ast_vector_inc_ref(ctx, assrts); - assertions.resize(num); - for (int j = 0; j < num; j++){ - if (j < numa) - assertions[j] = Z3_get_smtlib_assumption(ctx, j); - else - assertions[j] = Z3_get_smtlib_formula(ctx, j - numa); + for (int j = 0; j < numa; j++){ + Z3_ast_vector_push(ctx, assrts, Z3_get_smtlib_assumption(ctx, j)); } + for (int j = 0; j < numf; j++){ + Z3_ast_vector_push(ctx, assrts, Z3_get_smtlib_formula(ctx, j)); + } + return assrts; } } catch (...) { read_error << "SMTLIB parse error: " << Z3_get_smtlib_error(ctx); read_msg = read_error.str(); *error = read_msg.c_str(); - return false; + return 0; } Z3_set_error_handler(ctx, 0); - return true; + return 0; } @@ -554,23 +551,23 @@ extern "C" { if (file_params.find("THEORY") != file_params.end()) num_theory = atoi(file_params["THEORY"].c_str()); - svector assertions; - if (!iZ3_parse(ctx, filename, error, assertions)) + Z3_ast_vector assertions = iZ3_parse(ctx, filename, error); + if (assertions == 0) return false; - if (num_theory > assertions.size()) - num_theory = assertions.size(); - unsigned num = assertions.size() - num_theory; + if (num_theory > Z3_ast_vector_size(ctx, assertions)) + num_theory = Z3_ast_vector_size(ctx, assertions); + unsigned num = Z3_ast_vector_size(ctx, assertions) - num_theory; read_cnsts.resize(num); read_parents.resize(num); read_theory.resize(num_theory); for (unsigned j = 0; j < num_theory; j++) - read_theory[j] = assertions[j]; + read_theory[j] = Z3_ast_vector_get(ctx, assertions, j); for (unsigned j = 0; j < num; j++) - read_cnsts[j] = assertions[j + num_theory]; - + read_cnsts[j] = Z3_ast_vector_get(ctx, assertions, j + num_theory); + if (ret_num_theory) *ret_num_theory = num_theory; if (theory) @@ -579,6 +576,7 @@ extern "C" { if (!parents){ *_num = num; *cnsts = &read_cnsts[0]; + Z3_ast_vector_dec_ref(ctx, assertions); return true; } @@ -650,9 +648,11 @@ extern "C" { *_num = num; *cnsts = &read_cnsts[0]; *parents = &read_parents[0]; + Z3_ast_vector_dec_ref(ctx, assertions); return true; fail: + Z3_ast_vector_dec_ref(ctx, assertions); read_msg = read_error.str(); *error = read_msg.c_str(); return false; From f3b0ede6e833c124034a2b2e43006732f40bc46d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Jun 2017 16:35:35 -0700 Subject: [PATCH 0157/1283] update lookahead to include extensions Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 1 + src/api/api_interp.cpp | 28 +- src/api/dotnet/InterpolationContext.cs | 17 +- src/api/z3_interp.h | 11 +- src/cmd_context/basic_cmds.cpp | 2 +- src/sat/card_extension.cpp | 442 ++----- src/sat/card_extension.h | 89 +- src/sat/sat_extension.h | 1 + src/sat/sat_lookahead.cpp | 1597 +++++++++++++++++++++++ src/sat/sat_lookahead.h | 1600 ++---------------------- src/sat/sat_solver.cpp | 8 +- src/sat/sat_types.h | 1 + src/sat/sat_watched.h | 2 +- 13 files changed, 1855 insertions(+), 1944 deletions(-) create mode 100644 src/sat/sat_lookahead.cpp diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index fcfe53e02..0f9b9c20c 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -14,6 +14,7 @@ z3_add_component(sat sat_iff3_finder.cpp sat_integrity_checker.cpp sat_local_search.cpp + sat_lookahead.cpp sat_model_converter.cpp sat_mus.cpp sat_parallel.cpp diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index a1fa8f137..05921cc91 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -542,14 +542,15 @@ extern "C" { } - int Z3_read_interpolation_problem(Z3_context ctx, unsigned *_num, Z3_ast *cnsts[], unsigned *parents[], const char *filename, Z3_string_ptr error, unsigned *ret_num_theory, Z3_ast *theory[]){ + int Z3_read_interpolation_problem(Z3_context ctx, Z3_ast_vector cnsts, unsigned* _num, unsigned* parents[], const char *filename, Z3_string_ptr error, Z3_ast_vector theory){ hash_map file_params; get_file_params(filename, file_params); unsigned num_theory = 0; - if (file_params.find("THEORY") != file_params.end()) + if (file_params.find("THEORY") != file_params.end()) { num_theory = atoi(file_params["THEORY"].c_str()); + } Z3_ast_vector assertions = iZ3_parse(ctx, filename, error); if (assertions == 0) @@ -559,23 +560,15 @@ extern "C" { num_theory = Z3_ast_vector_size(ctx, assertions); unsigned num = Z3_ast_vector_size(ctx, assertions) - num_theory; - read_cnsts.resize(num); read_parents.resize(num); - read_theory.resize(num_theory); - for (unsigned j = 0; j < num_theory; j++) - read_theory[j] = Z3_ast_vector_get(ctx, assertions, j); - for (unsigned j = 0; j < num; j++) - read_cnsts[j] = Z3_ast_vector_get(ctx, assertions, j + num_theory); + for (unsigned j = 0; theory && j < num_theory; j++) + Z3_ast_vector_push(ctx, theory, Z3_ast_vector_get(ctx, assertions, j)); + + for (unsigned j = 0; j < num; j++) + Z3_ast_vector_push(ctx, cnsts, Z3_ast_vector_get(ctx, assertions, j + num_theory)); - if (ret_num_theory) - *ret_num_theory = num_theory; - if (theory) - *theory = &read_theory[0]; - if (!parents){ - *_num = num; - *cnsts = &read_cnsts[0]; Z3_ast_vector_dec_ref(ctx, assertions); return true; } @@ -586,7 +579,7 @@ extern "C" { hash_map pred_map; for (unsigned j = 0; j < num; j++){ - Z3_ast lhs = 0, rhs = read_cnsts[j]; + Z3_ast lhs = 0, rhs = Z3_ast_vector_get(ctx, cnsts, j); if (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, rhs))) == Z3_OP_IMPLIES){ Z3_app app1 = Z3_to_app(ctx, rhs); @@ -627,7 +620,7 @@ extern "C" { read_error << "formula " << j + 1 << ": should be (implies {children} fmla parent)"; goto fail; } - read_cnsts[j] = lhs; + Z3_ast_vector_set(ctx, cnsts, j, lhs); Z3_ast name = rhs; if (pred_map.find(name) != pred_map.end()){ read_error << "formula " << j + 1 << ": duplicate symbol"; @@ -646,7 +639,6 @@ extern "C" { } *_num = num; - *cnsts = &read_cnsts[0]; *parents = &read_parents[0]; Z3_ast_vector_dec_ref(ctx, assertions); return true; diff --git a/src/api/dotnet/InterpolationContext.cs b/src/api/dotnet/InterpolationContext.cs index 3f2feb5a6..e2b814983 100644 --- a/src/api/dotnet/InterpolationContext.cs +++ b/src/api/dotnet/InterpolationContext.cs @@ -133,19 +133,16 @@ namespace Microsoft.Z3 /// well documented. public int ReadInterpolationProblem(string filename, out Expr[] cnsts, out uint[] parents, out string error, out Expr[] theory) { - uint num = 0, num_theory = 0; - IntPtr[] n_cnsts; - IntPtr[] n_theory; + uint num = 0; IntPtr n_err_str; - int r = Native.Z3_read_interpolation_problem(nCtx, ref num, out n_cnsts, out parents, filename, out n_err_str, ref num_theory, out n_theory); + ASTVector _cnsts = new ASTVector(this); + ASTVector _theory = new ASTVector(this); + + int r = Native.Z3_read_interpolation_problem(nCtx, _cnsts.NativeObject, ref num, out parents, filename, out n_err_str, _theory.NativeObject); error = Marshal.PtrToStringAnsi(n_err_str); - cnsts = new Expr[num]; + cnsts = _cnsts.ToExprArray(); parents = new uint[num]; - theory = new Expr[num_theory]; - for (int i = 0; i < num; i++) - cnsts[i] = Expr.Create(this, n_cnsts[i]); - for (int i = 0; i < num_theory; i++) - theory[i] = Expr.Create(this, n_theory[i]); + theory = _theory.ToExprArray(); return r; } diff --git a/src/api/z3_interp.h b/src/api/z3_interp.h index bcee0e22d..7646695f8 100644 --- a/src/api/z3_interp.h +++ b/src/api/z3_interp.h @@ -207,18 +207,17 @@ extern "C" { where each value is represented using the common symbols between the formulas in the subtree and the remainder of the formulas. - def_API('Z3_read_interpolation_problem', INT, (_in(CONTEXT), _out(UINT), _out_managed_array(1, AST), _out_managed_array(1, UINT), _in(STRING), _out(STRING), _out(UINT), _out_managed_array(6, AST))) + def_API('Z3_read_interpolation_problem', INT, (_in(CONTEXT), _in(AST_VECTOR), _out(UINT), _out_managed_array(2, UINT), _in(STRING), _out(STRING), _in(AST_VECTOR))) */ int Z3_API Z3_read_interpolation_problem(Z3_context ctx, - unsigned *num, - Z3_ast *cnsts[], - unsigned *parents[], + Z3_ast_vector cnsts, + unsigned* num, + unsigned* parents[], Z3_string filename, Z3_string_ptr error, - unsigned *num_theory, - Z3_ast *theory[]); + Z3_ast_vector theory); diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 26cd0628e..6d6217b50 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -266,7 +266,7 @@ UNARY_CMD(pp_cmd, "display", "", "display the given term.", CPK_EXPR, expr ctx.regular_stream() << std::endl; }); -UNARY_CMD(echo_cmd, "echo", "", "display the given string", CPK_STRING, char const *, ctx.regular_stream() << arg << std::endl;); +UNARY_CMD(echo_cmd, "echo", "", "display the given string", CPK_STRING, char const *, ctx.regular_stream() << "\"" << arg << "\"" << std::endl;); class set_get_option_cmd : public cmd { diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 5032da6ff..0e3a24f56 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -79,12 +79,6 @@ namespace sat { } } - void card_extension::init_watch(bool_var v) { - if (m_var_infos.size() <= static_cast(v)) { - m_var_infos.resize(static_cast(v)+100); - } - } - void card_extension::init_watch(card& c, bool is_true) { clear_watch(c); if (c.lit() != null_literal && c.lit().sign() == is_true) { @@ -94,7 +88,7 @@ namespace sat { SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); if (bound == sz) { - for (unsigned i = 0; i < sz && !s().inconsistent(); ++i) { + for (unsigned i = 0; i < sz && !inconsistent(); ++i) { assign(c, c[i]); } return; @@ -135,7 +129,7 @@ namespace sat { set_conflict(c, alit); } else if (j == bound) { - for (unsigned i = 0; i < bound && !s().inconsistent(); ++i) { + for (unsigned i = 0; i < bound && !inconsistent(); ++i) { assign(c, c[i]); } } @@ -149,20 +143,12 @@ namespace sat { void card_extension::clear_watch(card& c) { unsigned sz = std::min(c.k() + 1, c.size()); for (unsigned i = 0; i < sz; ++i) { - unwatch_literal(c[i], &c); + unwatch_literal(c[i], c); } } - void card_extension::unwatch_literal(literal lit, card* c) { - if (m_var_infos.size() <= static_cast(lit.var())) { - return; - } - ptr_vector*& cards = m_var_infos[lit.var()].m_card_watch[lit.sign()]; - if (!is_tag_empty(cards)) { - if (remove(*cards, c)) { - cards = set_tag_empty(cards); - } - } + void card_extension::unwatch_literal(literal lit, card& c) { + get_wlist(~lit).erase(watched(c.index())); } void card_extension::assign(card& c, literal lit) { @@ -177,7 +163,7 @@ namespace sat { m_num_propagations_since_pop++; //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); SASSERT(validate_unit_propagation(c)); - if (s().m_config.m_drat) { + if (get_config().m_drat) { svector ps; literal_vector lits; if (c.lit() != null_literal) lits.push_back(~c.lit()); @@ -186,27 +172,16 @@ namespace sat { } lits.push_back(lit); ps.push_back(drat::premise(drat::s_ext(), c.lit())); // null_literal case. - s().m_drat.add(lits, ps); + drat_add(lits, ps); } - s().assign(lit, justification::mk_ext_justification(c.index())); + assign(lit, justification::mk_ext_justification(c.index())); break; } } void card_extension::watch_literal(card& c, literal lit) { TRACE("sat_verbose", tout << "watch: " << lit << "\n";); - init_watch(lit.var()); - ptr_vector* cards = m_var_infos[lit.var()].m_card_watch[lit.sign()]; - if (cards == 0) { - cards = alloc(ptr_vector); - m_var_infos[lit.var()].m_card_watch[lit.sign()] = cards; - } - else if (is_tag_empty(cards)) { - cards = set_tag_non_empty(cards); - m_var_infos[lit.var()].m_card_watch[lit.sign()] = cards; - } - TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); - cards->push_back(&c); + get_wlist(~lit).push_back(watched(c.index())); } void card_extension::set_conflict(card& c, literal lit) { @@ -214,8 +189,8 @@ namespace sat { TRACE("sat", display(tout, c, true); ); SASSERT(validate_conflict(c)); SASSERT(value(lit) == l_false); - s().set_conflict(justification::mk_ext_justification(c.index()), ~lit); - SASSERT(s().inconsistent()); + set_conflict(justification::mk_ext_justification(c.index()), ~lit); + SASSERT(inconsistent()); } // pb: @@ -322,7 +297,7 @@ namespace sat { lbool card_extension::add_assign(pb& p, literal alit) { TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); - SASSERT(!s().inconsistent()); + SASSERT(!inconsistent()); unsigned sz = p.size(); unsigned bound = p.k(); unsigned num_watch = p.num_watch(); @@ -332,7 +307,7 @@ namespace sat { SASSERT(num_watch <= sz); SASSERT(num_watch > 0); unsigned index = 0; - m_a_max = 0; + m_a_max = 0; m_pb_undef.reset(); for (; index < num_watch; ++index) { literal lit = p[index].second; @@ -364,7 +339,7 @@ namespace sat { } } - SASSERT(!s().inconsistent()); + SASSERT(!inconsistent()); DEBUG_CODE(for (auto idx : m_pb_undef) { SASSERT(value(p[idx].second) == l_undef); }); if (slack < bound) { @@ -400,7 +375,7 @@ namespace sat { } for (literal lit : to_assign) { - if (s().inconsistent()) break; + if (inconsistent()) break; if (value(lit) == l_undef) { assign(p, lit); } @@ -415,37 +390,18 @@ namespace sat { void card_extension::watch_literal(pb& p, wliteral l) { literal lit = l.second; - init_watch(lit.var()); - ptr_vector* pbs = m_var_infos[lit.var()].m_pb_watch[lit.sign()]; - if (pbs == 0) { - pbs = alloc(ptr_vector); - m_var_infos[lit.var()].m_pb_watch[lit.sign()] = pbs; - } - else if (is_tag_empty(pbs)) { - pbs = set_tag_non_empty(pbs); - m_var_infos[lit.var()].m_pb_watch[lit.sign()] = pbs; - } - TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); - pbs->push_back(&p); + get_wlist(~lit).push_back(watched(p.index())); } void card_extension::clear_watch(pb& p) { unsigned sz = p.size(); for (unsigned i = 0; i < sz; ++i) { - unwatch_literal(p[i].second, &p); + unwatch_literal(p[i].second, p); } } - void card_extension::unwatch_literal(literal lit, pb* p) { - if (m_var_infos.size() <= static_cast(lit.var())) { - return; - } - pb_watch*& pbs = m_var_infos[lit.var()].m_pb_watch[lit.sign()]; - if (!is_tag_empty(pbs)) { - if (remove(*pbs, p)) { - pbs = set_tag_empty(pbs); - } - } + void card_extension::unwatch_literal(literal lit, pb& p) { + get_wlist(~lit).erase(watched(p.index())); } void card_extension::set_conflict(pb& p, literal lit) { @@ -453,8 +409,8 @@ namespace sat { TRACE("sat", display(tout, p, true); ); // SASSERT(validate_conflict(p)); SASSERT(value(lit) == l_false); - s().set_conflict(justification::mk_ext_justification(p.index()), ~lit); - SASSERT(s().inconsistent()); + set_conflict(justification::mk_ext_justification(p.index()), ~lit); + SASSERT(inconsistent()); } void card_extension::assign(pb& p, literal lit) { @@ -468,15 +424,15 @@ namespace sat { SASSERT(validate_unit_propagation(p, lit)); m_stats.m_num_pb_propagations++; m_num_propagations_since_pop++; - if (s().m_config.m_drat) { + if (get_config().m_drat) { svector ps; literal_vector lits; get_pb_antecedents(lit, p, lits); lits.push_back(lit); ps.push_back(drat::premise(drat::s_ext(), p.lit())); - s().m_drat.add(lits, ps); + drat_add(lits, ps); } - s().assign(lit, justification::mk_ext_justification(p.index())); + assign(lit, justification::mk_ext_justification(p.index())); break; } } @@ -513,53 +469,6 @@ namespace sat { out << ">= " << p.k() << "\n"; } - void card_extension::asserted_pb(literal l, ptr_vector* pbs, pb* p0) { - TRACE("sat", tout << "literal: " << l << " has pb: " << !is_tag_empty(pbs) << " p0 != 0: " << (p0 != 0) << "\n";); - if (!is_tag_empty(pbs)) { - ptr_vector::iterator begin = pbs->begin(); - ptr_vector::iterator it = begin, it2 = it, end = pbs->end(); - for (; it != end; ++it) { - pb& p = *(*it); - if (p.lit() != null_literal && value(p.lit()) != l_true) { - continue; - } - switch (add_assign(p, ~l)) { - case l_true: // unit propagation, keep watching the literal - if (it2 != it) { - *it2 = *it; - } - ++it2; - break; - case l_false: // conflict. - SASSERT(s().inconsistent()); - for (; it != end; ++it, ++it2) { - *it2 = *it; - } - pbs->set_end(it2); - return; - case l_undef: // watch literal was swapped - if (s().inconsistent()) { - ++it; - for (; it != end; ++it, ++it2) { - *it2 = *it; - } - pbs->set_end(it2); - return; - } - break; - } - } - pbs->set_end(it2); - if (pbs->empty()) { - m_var_infos[l.var()].m_pb_watch[!l.sign()] = set_tag_empty(pbs); - } - } - - if (p0 != 0 && !s().inconsistent()) { - init_watch(*p0, !l.sign()); - } - } - // xor: void card_extension::copy_xor(card_extension& result) { @@ -575,20 +484,12 @@ namespace sat { } void card_extension::clear_watch(xor& x) { - unwatch_literal(x[0], &x); - unwatch_literal(x[1], &x); + unwatch_literal(x[0], x); + unwatch_literal(x[1], x); } - void card_extension::unwatch_literal(literal lit, xor* c) { - if (m_var_infos.size() <= static_cast(lit.var())) { - return; - } - xor_watch*& xors = m_var_infos[lit.var()].m_xor_watch; - if (!is_tag_empty(xors)) { - if (remove(*xors, c)) { - xors = set_tag_empty(xors); - } - } + void card_extension::unwatch_literal(literal lit, xor& c) { + get_wlist(~lit).erase(watched(c.index())); } bool card_extension::parity(xor const& x, unsigned offset) const { @@ -620,16 +521,15 @@ namespace sat { switch (j) { case 0: if (!parity(x, 0)) { - literal_set litset; - for (unsigned i = 0; i < sz; ++i) { - litset.insert(x[i]); + unsigned l = lvl(x[0]); + j = 1; + for (unsigned i = 1; i < sz; ++i) { + if (lvl(x[i]) > l) { + j = i; + l = lvl(x[i]); + } } - literal_vector const& lits = s().m_trail; - unsigned idx = lits.size()-1; - while (!litset.contains(lits[idx])) { - --idx; - } - set_conflict(x, lits[idx]); + set_conflict(x, x[j]); } break; case 1: @@ -644,18 +544,18 @@ namespace sat { } void card_extension::assign(xor& x, literal lit) { - SASSERT(!s().inconsistent()); + SASSERT(!inconsistent()); switch (value(lit)) { case l_true: break; case l_false: set_conflict(x, lit); - SASSERT(s().inconsistent()); + SASSERT(inconsistent()); break; default: m_stats.m_num_xor_propagations++; m_num_propagations_since_pop++; - if (s().m_config.m_drat) { + if (get_config().m_drat) { svector ps; literal_vector lits; if (x.lit() != null_literal) lits.push_back(~x.lit()); @@ -664,25 +564,17 @@ namespace sat { } lits.push_back(lit); ps.push_back(drat::premise(drat::s_ext(), x.lit())); - s().m_drat.add(lits, ps); + drat_add(lits, ps); } TRACE("sat", display(tout << lit << " ", x, true);); - s().assign(lit, justification::mk_ext_justification(x.index())); + assign(lit, justification::mk_ext_justification(x.index())); break; } } void card_extension::watch_literal(xor& x, literal lit) { TRACE("sat_verbose", tout << "watch: " << lit << "\n";); - init_watch(lit.var()); - xor_watch*& xors = m_var_infos[lit.var()].m_xor_watch; - if (xors == 0) { - xors = alloc(ptr_vector); - } - else if (is_tag_empty(xors)) { - xors = set_tag_non_empty(xors); - } - xors->push_back(&x); + get_wlist(~lit).push_back(watched(x.index())); TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); } @@ -693,8 +585,8 @@ namespace sat { if (value(lit) == l_true) lit.neg(); SASSERT(validate_conflict(x)); TRACE("sat", display(tout << lit << " ", x, true);); - s().set_conflict(justification::mk_ext_justification(x.index()), ~lit); - SASSERT(s().inconsistent()); + set_conflict(justification::mk_ext_justification(x.index()), ~lit); + SASSERT(inconsistent()); } lbool card_extension::add_assign(xor& x, literal alit) { @@ -735,48 +627,8 @@ namespace sat { else if (!parity(x, 0)) { set_conflict(x, ~x[1]); } - return s().inconsistent() ? l_false : l_true; + return inconsistent() ? l_false : l_true; } - - void card_extension::asserted_xor(literal l, ptr_vector* xors, xor* x) { - TRACE("sat", tout << l << " " << !is_tag_empty(xors) << " " << (x != 0) << "\n";); - if (!is_tag_empty(xors)) { - ptr_vector::iterator begin = xors->begin(); - ptr_vector::iterator it = begin, it2 = it, end = xors->end(); - for (; it != end; ++it) { - xor& c = *(*it); - if (c.lit() != null_literal && value(c.lit()) != l_true) { - continue; - } - switch (add_assign(c, ~l)) { - case l_false: // conflict - for (; it != end; ++it, ++it2) { - *it2 = *it; - } - SASSERT(s().inconsistent()); - xors->set_end(it2); - return; - case l_undef: // watch literal was swapped - break; - case l_true: // unit propagation, keep watching the literal - if (it2 != it) { - *it2 = *it; - } - ++it2; - break; - } - } - xors->set_end(it2); - if (xors->empty()) { - m_var_infos[l.var()].m_xor_watch = set_tag_empty(xors); - } - } - - if (x != 0 && !s().inconsistent()) { - init_watch(*x, !l.sign()); - } - } - void card_extension::normalize_active_coeffs() { while (!m_active_var_set.empty()) m_active_var_set.erase(); @@ -841,7 +693,6 @@ namespace sat { m_active_vars.reset(); } - bool card_extension::resolve_conflict() { if (0 == m_num_propagations_since_pop) { return false; @@ -1084,9 +935,9 @@ namespace sat { TRACE("sat", tout << m_lemma << "\n";); - if (s().m_config.m_drat) { + if (get_config().m_drat) { svector ps; // TBD fill in - s().m_drat.add(m_lemma, ps); + drat_add(m_lemma, ps); } s().m_lemma.reset(); @@ -1155,16 +1006,11 @@ namespace sat { return p; } - card_extension::card_extension(): m_solver(0), m_has_xor(false) { + card_extension::card_extension(): m_solver(0), m_lookahead(0) { TRACE("sat", tout << this << "\n";); } card_extension::~card_extension() { - for (unsigned i = 0; i < m_var_infos.size(); ++i) { - m_var_infos[i].reset(); - } - m_var_trail.reset(); - m_var_lim.reset(); m_stats.reset(); } @@ -1180,9 +1026,9 @@ namespace sat { m_card_axioms.push_back(c); } else { - init_watch(v); - m_var_infos[v].m_card = c; - m_var_trail.push_back(v); + get_wlist(literal(v, false)).push_back(index); + get_wlist(literal(v, true)).push_back(index); + m_index_trail.push_back(index); } } @@ -1197,27 +1043,57 @@ namespace sat { m_pb_axioms.push_back(p); } else { - init_watch(v); - m_var_infos[v].m_pb = p; - m_var_trail.push_back(v); + get_wlist(literal(v, false)).push_back(index); + get_wlist(literal(v, true)).push_back(index); + m_index_trail.push_back(index); } } void card_extension::add_xor(bool_var v, literal_vector const& lits) { - m_has_xor = true; unsigned index = 4*m_xors.size() + 0x1; SASSERT(is_xor_index(index)); + SASSERT(v != null_bool_var); xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, literal(v, false), lits); m_xors.push_back(x); - init_watch(v); - m_var_infos[v].m_xor = x; - m_var_trail.push_back(v); + get_wlist(literal(v, false)).push_back(index); + get_wlist(literal(v, true)).push_back(index); + m_index_trail.push_back(index); } void card_extension::propagate(literal l, ext_constraint_idx idx, bool & keep) { - UNREACHABLE(); + TRACE("sat", tout << l << " " << idx << "\n";); + if (is_pb_index(idx)) { + pb& p = index2pb(idx); + if (l.var() == p.lit().var()) { + init_watch(p, !l.sign()); + } + else { + keep = l_undef != add_assign(p, ~l); + } + } + else if (is_card_index(idx)) { + card& c = index2card(idx); + if (l.var() == c.lit().var()) { + init_watch(c, !l.sign()); + } + else { + keep = l_undef != add_assign(c, ~l); + } + } + else if (is_xor_index(idx)) { + xor& x = index2xor(idx); + if (l.var() == x.lit().var()) { + init_watch(x, !l.sign()); + } + else { + keep = l_undef != add_assign(x, ~l); + } + } + else { + UNREACHABLE(); + } } @@ -1454,100 +1330,53 @@ namespace sat { } SASSERT(validate_unit_propagation(c)); - for (unsigned i = 0; i < bound && !s().inconsistent(); ++i) { + for (unsigned i = 0; i < bound && !inconsistent(); ++i) { assign(c, c[i]); } - return s().inconsistent() ? l_false : l_true; + return inconsistent() ? l_false : l_true; } void card_extension::asserted(literal l) { - bool_var v = l.var(); - if (s().inconsistent()) return; - if (v >= m_var_infos.size()) return; - var_info& vinfo = m_var_infos[v]; - ptr_vector* cards = vinfo.m_card_watch[!l.sign()]; - ptr_vector* xors = vinfo.m_xor_watch; - ptr_vector* pbs = vinfo.m_pb_watch[!l.sign()]; - pb* p = vinfo.m_pb; - card* crd = vinfo.m_card; - xor* x = vinfo.m_xor; - - if (!is_tag_empty(cards)) { - ptr_vector::iterator begin = cards->begin(); - ptr_vector::iterator it = begin, it2 = it, end = cards->end(); - for (; it != end; ++it) { - card& c = *(*it); - if (c.lit() != null_literal && value(c.lit()) != l_true) { - continue; - } - switch (add_assign(c, ~l)) { - case l_false: // conflict - for (; it != end; ++it, ++it2) { - *it2 = *it; - } - SASSERT(s().inconsistent()); - cards->set_end(it2); - return; - case l_undef: // watch literal was swapped - break; - case l_true: // unit propagation, keep watching the literal - if (it2 != it) { - *it2 = *it; - } - ++it2; - break; - } - } - cards->set_end(it2); - if (cards->empty()) { - m_var_infos[v].m_card_watch[!l.sign()] = set_tag_empty(cards); - } - } - - if (crd != 0 && !s().inconsistent()) { - init_watch(*crd, !l.sign()); - } - - if ((!is_tag_empty(pbs) || p) && !s().inconsistent()) { - asserted_pb(l, pbs, p); - } - - if (m_has_xor && !s().inconsistent()) { - asserted_xor(l, xors, x); - } } check_result card_extension::check() { return CR_DONE; } void card_extension::push() { - m_var_lim.push_back(m_var_trail.size()); + m_index_lim.push_back(m_index_trail.size()); } void card_extension::pop(unsigned n) { TRACE("sat_verbose", tout << "pop:" << n << "\n";); - unsigned new_lim = m_var_lim.size() - n; - unsigned sz = m_var_lim[new_lim]; - while (m_var_trail.size() > sz) { - bool_var v = m_var_trail.back(); - m_var_trail.pop_back(); - if (v != null_bool_var) { - card* c = m_var_infos[v].m_card; - if (c) { - clear_watch(*c); - m_var_infos[v].m_card = 0; - dealloc(c); - } - xor* x = m_var_infos[v].m_xor; - if (x) { - clear_watch(*x); - m_var_infos[v].m_xor = 0; - dealloc(x); - } + unsigned new_lim = m_index_lim.size() - n; + unsigned sz = m_index_lim[new_lim]; + while (m_index_trail.size() > sz) { + unsigned index = m_index_trail.back(); + m_index_trail.pop_back(); + if (is_card_index(index)) { + SASSERT(m_cards.back()->index() == index); + clear_watch(*m_cards.back()); + dealloc(m_cards.back()); + m_cards.pop_back(); + } + else if (is_pb_index(index)) { + SASSERT(m_pbs.back()->index() == index); + clear_watch(*m_pbs.back()); + dealloc(m_pbs.back()); + m_pbs.pop_back(); + } + else if (is_xor_index(index)) { + SASSERT(m_xors.back()->index() == index); + clear_watch(*m_xors.back()); + dealloc(m_xors.back()); + m_xors.pop_back(); + } + else { + UNREACHABLE(); } } - m_var_lim.resize(new_lim); + m_index_lim.resize(new_lim); m_num_propagations_since_pop = 0; } @@ -1604,30 +1433,6 @@ namespace sat { } } - void card_extension::display_watch(std::ostream& out, bool_var v, bool sign) const { - card_watch const* w = m_var_infos[v].m_card_watch[sign]; - if (!is_tag_empty(w)) { - card_watch const& wl = *w; - out << literal(v, sign) << " |-> "; - for (unsigned i = 0; i < wl.size(); ++i) { - out << wl[i]->lit() << " "; - } - out << "\n"; - } - } - - void card_extension::display_watch(std::ostream& out, bool_var v) const { - xor_watch const* w = m_var_infos[v].m_xor_watch; - if (!is_tag_empty(w)) { - xor_watch const& wl = *w; - out << "v" << v << " |-> "; - for (unsigned i = 0; i < wl.size(); ++i) { - out << wl[i]->lit() << " "; - } - out << "\n"; - } - } - void card_extension::display(std::ostream& out, ineq& ineq) const { for (unsigned i = 0; i < ineq.m_lits.size(); ++i) { out << ineq.m_coeffs[i] << "*" << ineq.m_lits[i] << " "; @@ -1694,17 +1499,6 @@ namespace sat { } std::ostream& card_extension::display(std::ostream& out) const { - for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { - display_watch(out, vi, false); - display_watch(out, vi, true); - display_watch(out, vi); - } - for (unsigned vi = 0; vi < m_var_infos.size(); ++vi) { - card* c = m_var_infos[vi].m_card; - if (c) display(out, *c, false); - xor* x = m_var_infos[vi].m_xor; - if (x) display(out, *x, false); - } return out; } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index fbe1141b1..9720bde9c 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -21,8 +21,10 @@ Revision History: #include"sat_extension.h" #include"sat_solver.h" +#include"sat_lookahead.h" #include"scoped_ptr_vector.h" + namespace sat { class card_extension : public extension { @@ -116,52 +118,8 @@ namespace sat { void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } }; - typedef ptr_vector card_watch; - typedef ptr_vector xor_watch; - typedef ptr_vector pb_watch; - struct var_info { - card_watch* m_card_watch[2]; - pb_watch* m_pb_watch[2]; - xor_watch* m_xor_watch; - card* m_card; - pb* m_pb; - xor* m_xor; - var_info(): m_xor_watch(0), m_card(0), m_xor(0), m_pb(0) { - m_card_watch[0] = 0; - m_card_watch[1] = 0; - m_pb_watch[0] = 0; - m_pb_watch[1] = 0; - } - void reset() { - dealloc(m_card); - dealloc(m_xor); - dealloc(m_pb); - dealloc(card_extension::set_tag_non_empty(m_card_watch[0])); - dealloc(card_extension::set_tag_non_empty(m_card_watch[1])); - dealloc(card_extension::set_tag_non_empty(m_pb_watch[0])); - dealloc(card_extension::set_tag_non_empty(m_pb_watch[1])); - dealloc(card_extension::set_tag_non_empty(m_xor_watch)); - } - }; - - template - static ptr_vector* set_tag_empty(ptr_vector* c) { - return TAG(ptr_vector*, c, 1); - } - - template - static bool is_tag_empty(ptr_vector const* c) { - return !c || GET_TAG(c) == 1; - } - - template - static ptr_vector* set_tag_non_empty(ptr_vector* c) { - return UNTAG(ptr_vector*, c); - } - - - solver* m_solver; + lookahead* m_lookahead; stats m_stats; ptr_vector m_cards; @@ -172,9 +130,8 @@ namespace sat { scoped_ptr_vector m_pb_axioms; // watch literals - svector m_var_infos; - unsigned_vector m_var_trail; - unsigned_vector m_var_lim; + unsigned_vector m_index_trail; + unsigned_vector m_index_lim; // conflict resolution unsigned m_num_marks; @@ -185,7 +142,6 @@ namespace sat { tracked_uint_set m_active_var_set; literal_vector m_lemma; unsigned m_num_propagations_since_pop; - bool m_has_xor; unsigned_vector m_parity_marks; literal_vector m_parity_trail; @@ -206,7 +162,7 @@ namespace sat { void clear_watch(card& c); void reset_coeffs(); void reset_marked_literals(); - void unwatch_literal(literal w, card* c); + void unwatch_literal(literal w, card& c); void get_card_antecedents(literal l, card const& c, literal_vector & r); @@ -214,13 +170,12 @@ namespace sat { void copy_xor(card_extension& result); void clear_watch(xor& x); void watch_literal(xor& x, literal lit); - void unwatch_literal(literal w, xor* x); + void unwatch_literal(literal w, xor& x); void init_watch(xor& x, bool is_true); void assign(xor& x, literal lit); void set_conflict(xor& x, literal lit); bool parity(xor const& x, unsigned offset) const; lbool add_assign(xor& x, literal alit); - void asserted_xor(literal l, ptr_vector* xors, xor* x); void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); void get_xor_antecedents(literal l, xor const& x, literal_vector & r); @@ -236,7 +191,6 @@ namespace sat { // pb functionality unsigned m_a_max; void copy_pb(card_extension& result); - void asserted_pb(literal l, ptr_vector* pbs, pb* p); void init_watch(pb& p, bool is_true); lbool add_assign(pb& p, literal alit); void add_index(pb& p, unsigned index, literal lit); @@ -244,28 +198,18 @@ namespace sat { void clear_watch(pb& p); void set_conflict(pb& p, literal lit); void assign(pb& p, literal l); - void unwatch_literal(literal w, pb* p); + void unwatch_literal(literal w, pb& p); void get_pb_antecedents(literal l, pb const& p, literal_vector & r); - - template - bool remove(ptr_vector& ts, T* t) { - unsigned sz = ts.size(); - for (unsigned j = 0; j < sz; ++j) { - if (ts[j] == t) { - std::swap(ts[j], ts[sz-1]); - ts.pop_back(); - return sz == 1; - } - } - return false; - } - - - - inline lbool value(literal lit) const { return m_solver->value(lit); } + inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } inline unsigned lvl(bool_var v) const { return m_solver->lvl(v); } + inline bool inconsistent() const { return m_lookahead ? m_lookahead->inconsistent() : m_solver->inconsistent(); } + inline watch_list& get_wlist(literal l) { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } + inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); } + inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); } + inline config const& get_config() const { return m_solver->get_config(); } + inline void drat_add(literal_vector const& c, svector const& premises) { m_solver->m_drat.add(c, premises); } void normalize_active_coeffs(); @@ -296,13 +240,12 @@ namespace sat { void display(std::ostream& out, card const& c, bool values) const; void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xor const& c, bool values) const; - void display_watch(std::ostream& out, bool_var v) const; - void display_watch(std::ostream& out, bool_var v, bool sign) const; public: card_extension(); virtual ~card_extension(); virtual void set_solver(solver* s) { m_solver = s; } + virtual void set_lookahead(lookahead* l) { m_lookahead = l; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); void add_pb_ge(bool_var v, svector const& wlits, unsigned k); void add_xor(bool_var v, literal_vector const& lits); diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index a875bad6c..44a704f80 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -33,6 +33,7 @@ namespace sat { public: virtual ~extension() {} virtual void set_solver(solver* s) = 0; + virtual void set_lookahead(lookahead* s) = 0; virtual void propagate(literal l, ext_constraint_idx idx, bool & keep) = 0; virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0; virtual void asserted(literal l) = 0; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp new file mode 100644 index 000000000..597efa49a --- /dev/null +++ b/src/sat/sat_lookahead.cpp @@ -0,0 +1,1597 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_lookahead.h + +Abstract: + + Lookahead SAT solver in the style of March. + Thanks also to the presentation in sat11.w. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-2-11 + +Notes: + +--*/ +#include "sat_solver.h" +#include "sat_extension.h" +#include "sat_lookahead.h" + +namespace sat { + lookahead::scoped_ext::scoped_ext(lookahead& p): p(p) { + if (p.m_s.m_ext) p.m_s.m_ext->set_lookahead(&p); + } + + lookahead::scoped_ext::~scoped_ext() { + if (p.m_s.m_ext) p.m_s.m_ext->set_lookahead(0); + } + + void lookahead::flip_prefix() { + if (m_trail_lim.size() < 64) { + uint64 mask = (1ull << m_trail_lim.size()); + m_prefix = mask | (m_prefix & (mask - 1)); + } + } + + void lookahead::prune_prefix() { + if (m_trail_lim.size() < 64) { + m_prefix &= (1ull << m_trail_lim.size()) - 1; + } + } + + void lookahead::update_prefix(literal l) { + bool_var x = l.var(); + unsigned p = m_vprefix[x].m_prefix; + unsigned pl = m_vprefix[x].m_length; + unsigned mask = (1 << std::min(31u, pl)) - 1; + if (pl >= m_trail_lim.size() || (p & mask) != (m_prefix & mask)) { + m_vprefix[x].m_length = m_trail_lim.size(); + m_vprefix[x].m_prefix = static_cast(m_prefix); + } + } + + bool lookahead::active_prefix(bool_var x) { + unsigned lvl = m_trail_lim.size(); + unsigned p = m_vprefix[x].m_prefix; + unsigned l = m_vprefix[x].m_length; + if (l > lvl) return false; + if (l == lvl || l >= 31) return m_prefix == p; + unsigned mask = ((1 << std::min(l,31u)) - 1); + return (m_prefix & mask) == (p & mask); + } + + void lookahead::add_binary(literal l1, literal l2) { + TRACE("sat", tout << "binary: " << l1 << " " << l2 << "\n";); + SASSERT(l1 != l2); + // don't add tautologies and don't add already added binaries + if (~l1 == l2) return; + if (!m_binary[(~l1).index()].empty() && m_binary[(~l1).index()].back() == l2) return; + m_binary[(~l1).index()].push_back(l2); + m_binary[(~l2).index()].push_back(l1); + m_binary_trail.push_back((~l1).index()); + ++m_stats.m_add_binary; + if (m_s.m_config.m_drat) validate_binary(l1, l2); + } + + void lookahead::del_binary(unsigned idx) { + // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n");); + literal_vector & lits = m_binary[idx]; + SASSERT(!lits.empty()); + literal l = lits.back(); + lits.pop_back(); + SASSERT(!m_binary[(~l).index()].empty()); + IF_VERBOSE(0, if (m_binary[(~l).index()].back() != ~to_literal(idx)) verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); + SASSERT(m_binary[(~l).index()].back() == ~to_literal(idx)); + m_binary[(~l).index()].pop_back(); + ++m_stats.m_del_binary; + } + + + void lookahead::validate_binary(literal l1, literal l2) { + if (m_search_mode == lookahead_mode::searching) { + m_assumptions.push_back(l1); + m_assumptions.push_back(l2); + m_drat.add(m_assumptions); + m_assumptions.pop_back(); + m_assumptions.pop_back(); + } + } + + + void lookahead::inc_bstamp() { + ++m_bstamp_id; + if (m_bstamp_id == 0) { + ++m_bstamp_id; + m_bstamp.fill(0); + } + } + void lookahead::inc_istamp() { + ++m_istamp_id; + if (m_istamp_id == 0) { + ++m_istamp_id; + for (unsigned i = 0; i < m_lits.size(); ++i) { + m_lits[i].m_double_lookahead = 0; + } + } + } + + void lookahead::set_bstamps(literal l) { + inc_bstamp(); + set_bstamp(l); + literal_vector const& conseq = m_binary[l.index()]; + literal_vector::const_iterator it = conseq.begin(); + literal_vector::const_iterator end = conseq.end(); + for (; it != end; ++it) { + set_bstamp(*it); + } + } + + /** + \brief add one-step transitive closure of binary implications + return false if we learn a unit literal. + \pre all implicants of ~u are stamped. + u \/ v is true + **/ + + bool lookahead::add_tc1(literal u, literal v) { + unsigned sz = m_binary[v.index()].size(); + for (unsigned i = 0; i < sz; ++i) { + literal w = m_binary[v.index()][i]; + // ~v \/ w + if (!is_fixed(w)) { + if (is_stamped(~w)) { + // u \/ v, ~v \/ w, u \/ ~w => u is unit + TRACE("sat", tout << "tc1: " << u << "\n";); + assign(u); + return false; + } + if (m_num_tc1 < m_config.m_tc1_limit) { + ++m_num_tc1; + IF_VERBOSE(3, verbose_stream() << "tc1: " << u << " " << w << "\n";); + add_binary(u, w); + } + } + } + return true; + } + + + /** + \brief main routine for adding a new binary clause dynamically. + */ + void lookahead::try_add_binary(literal u, literal v) { + SASSERT(m_search_mode == lookahead_mode::searching); + SASSERT(u.var() != v.var()); + if (!is_undef(u) || !is_undef(v)) { + IF_VERBOSE(0, verbose_stream() << "adding assigned binary " << v << " " << u << "\n";); + } + set_bstamps(~u); + if (is_stamped(~v)) { + TRACE("sat", tout << "try_add_binary: " << u << "\n";); + assign(u); // u \/ ~v, u \/ v => u is a unit literal + } + else if (!is_stamped(v) && add_tc1(u, v)) { + // u \/ v is not in index + set_bstamps(~v); + if (is_stamped(~u)) { + TRACE("sat", tout << "try_add_binary: " << v << "\n";); + assign(v); // v \/ ~u, u \/ v => v is a unit literal + } + else if (add_tc1(v, u)) { + update_prefix(u); + update_prefix(v); + add_binary(u, v); + } + } + } + + // ------------------------------------- + // pre-selection + // see also 91 - 102 sat11.w + + + void lookahead::pre_select() { + m_lookahead.reset(); + if (select(scope_lvl())) { + get_scc(); + if (inconsistent()) return; + find_heights(); + construct_lookahead_table(); + } + } + + + bool lookahead::select(unsigned level) { + init_pre_selection(level); + unsigned level_cand = std::max(m_config.m_level_cand, m_freevars.size() / 50); + unsigned max_num_cand = level == 0 ? m_freevars.size() : level_cand / level; + max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand); + + float sum = 0; + for (bool newbies = false; ; newbies = true) { + sum = init_candidates(level, newbies); + if (!m_candidates.empty()) break; + if (is_sat()) { + return false; + } + if (newbies) { + enable_trace("sat"); + TRACE("sat", display(tout);); + TRACE("sat", tout << sum << "\n";); + } + } + SASSERT(!m_candidates.empty()); + // cut number of candidates down to max_num_cand. + // step 1. cut it to at most 2*max_num_cand. + // step 2. use a heap to sift through the rest. + bool progress = true; + while (progress && m_candidates.size() >= max_num_cand * 2) { + progress = false; + float mean = sum / (float)(m_candidates.size() + 0.0001); + sum = 0; + for (unsigned i = 0; i < m_candidates.size() && m_candidates.size() >= max_num_cand * 2; ++i) { + if (m_candidates[i].m_rating >= mean) { + sum += m_candidates[i].m_rating; + } + else { + m_candidates[i] = m_candidates.back(); + m_candidates.pop_back(); + --i; + progress = true; + } + } + } + TRACE("sat", display_candidates(tout);); + SASSERT(!m_candidates.empty()); + if (m_candidates.size() > max_num_cand) { + unsigned j = m_candidates.size()/2; + while (j > 0) { + --j; + sift_up(j); + } + while (true) { + m_candidates[0] = m_candidates.back(); + m_candidates.pop_back(); + if (m_candidates.size() == max_num_cand) break; + sift_up(0); + } + } + SASSERT(!m_candidates.empty() && m_candidates.size() <= max_num_cand); + TRACE("sat", display_candidates(tout);); + return true; + } + + void lookahead::sift_up(unsigned j) { + unsigned i = j; + candidate c = m_candidates[j]; + for (unsigned k = 2*j + 1; k < m_candidates.size(); i = k, k = 2*k + 1) { + // pick largest parent + if (k + 1 < m_candidates.size() && m_candidates[k].m_rating < m_candidates[k+1].m_rating) { + ++k; + } + if (c.m_rating <= m_candidates[k].m_rating) break; + m_candidates[i] = m_candidates[k]; + } + if (i > j) m_candidates[i] = c; + } + + float lookahead::init_candidates(unsigned level, bool newbies) { + m_candidates.reset(); + float sum = 0; + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + SASSERT(is_undef(*it)); + bool_var x = *it; + if (!m_select_lookahead_vars.empty() && m_select_lookahead_vars.contains(x)) { + m_candidates.push_back(candidate(x, m_rating[x])); + sum += m_rating[x]; + } + else if (newbies || active_prefix(x)) { + m_candidates.push_back(candidate(x, m_rating[x])); + sum += m_rating[x]; + } + } + TRACE("sat", display_candidates(tout << "sum: " << sum << "\n");); + return sum; + } + + + std::ostream& lookahead::display_candidates(std::ostream& out) const { + for (unsigned i = 0; i < m_candidates.size(); ++i) { + out << "var: " << m_candidates[i].m_var << " rating: " << m_candidates[i].m_rating << "\n"; + } + return out; + } + + bool lookahead::is_unsat() const { + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause& c = *m_clauses[i]; + unsigned j = 0; + for (; j < c.size() && is_false(c[j]); ++j) {} + if (j == c.size()) { + TRACE("sat", tout << c << "\n";); + TRACE("sat", display(tout);); + return true; + } + } + return false; + } + + bool lookahead::is_sat() const { + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + literal l(*it, false); + literal_vector const& lits1 = m_binary[l.index()]; + for (unsigned i = 0; i < lits1.size(); ++i) { + if (!is_true(lits1[i])) { + TRACE("sat", tout << l << " " << lits1[i] << "\n";); + return false; + } + } + l.neg(); + literal_vector const& lits2 = m_binary[l.index()]; + for (unsigned i = 0; i < lits2.size(); ++i) { + if (!is_true(lits2[i])) { + TRACE("sat", tout << l << " " << lits2[i] << "\n";); + return false; + } + } + } + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause& c = *m_clauses[i]; + unsigned j = 0; + for (; j < c.size() && !is_true(c[j]); ++j) {} + if (j == c.size()) { + return false; + } + } + return true; + } + + void lookahead::init_pre_selection(unsigned level) { + unsigned max_level = m_config.m_max_hlevel; + if (level <= 1) { + ensure_H(2); + h_scores(m_H[0], m_H[1]); + for (unsigned j = 0; j < 2; ++j) { + for (unsigned i = 0; i < 2; ++i) { + h_scores(m_H[i + 1], m_H[(i + 2) % 3]); + } + } + m_heur = &m_H[1]; + } + else if (level < max_level) { + ensure_H(level); + h_scores(m_H[level-1], m_H[level]); + m_heur = &m_H[level]; + } + else { + ensure_H(max_level); + h_scores(m_H[max_level-1], m_H[max_level]); + m_heur = &m_H[max_level]; + } + } + + void lookahead::ensure_H(unsigned level) { + while (m_H.size() <= level) { + m_H.push_back(svector()); + m_H.back().resize(m_num_vars * 2, 0); + } + } + + void lookahead::h_scores(svector& h, svector& hp) { + float sum = 0; + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + literal l(*it, false); + sum += h[l.index()] + h[(~l).index()]; + } + float factor = 2 * m_freevars.size() / sum; + float sqfactor = factor * factor; + float afactor = factor * m_config.m_alpha; + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + literal l(*it, false); + float pos = l_score(l, h, factor, sqfactor, afactor); + float neg = l_score(~l, h, factor, sqfactor, afactor); + hp[l.index()] = pos; + hp[(~l).index()] = neg; + m_rating[l.var()] = pos * neg; + } + } + + float lookahead::l_score(literal l, svector const& h, float factor, float sqfactor, float afactor) { + float sum = 0, tsum = 0; + literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); + for (; it != end; ++it) { + bool_var v = it->var(); + if (it->index() >= h.size()) + IF_VERBOSE(0, verbose_stream() << l << " " << *it << " " << h.size() << "\n";); + if (is_undef(*it)) sum += h[it->index()]; + // if (m_freevars.contains(it->var())) sum += h[it->index()]; + } + watch_list& wlist = m_watches[l.index()]; + watch_list::iterator wit = wlist.begin(), wend = wlist.end(); + for (; wit != wend; ++wit) { + switch (wit->get_kind()) { + case watched::BINARY: + UNREACHABLE(); + break; + case watched::TERNARY: { + literal l1 = wit->get_literal1(); + literal l2 = wit->get_literal2(); + // if (is_undef(l1) && is_undef(l2)) + tsum += h[l1.index()] * h[l2.index()]; + break; + } + case watched::CLAUSE: { + clause_offset cls_off = wit->get_clause_offset(); + clause & c = *(m_cls_allocator.get_clause(cls_off)); + // approximation compared to ternary clause case: + // we pick two other literals from the clause. + if (c[0] == ~l) { + tsum += h[c[1].index()] * h[c[2].index()]; + } + else { + SASSERT(c[1] == ~l); + tsum += h[c[0].index()] * h[c[2].index()]; + } + break; + } + } + } + sum = (float)(0.1 + afactor*sum + sqfactor*tsum); + return std::min(m_config.m_max_score, sum); + } + + // ------------------------------------ + // Implication graph + // Compute implication ordering and strongly connected components. + // sat11.w 103 - 114. + + void lookahead::get_scc() { + unsigned num_candidates = m_candidates.size(); + init_scc(); + for (unsigned i = 0; i < num_candidates && !inconsistent(); ++i) { + literal lit(m_candidates[i].m_var, false); + if (get_rank(lit) == 0) get_scc(lit); + if (get_rank(~lit) == 0) get_scc(~lit); + } + TRACE("sat", display_scc(tout);); + } + void lookahead::init_scc() { + inc_bstamp(); + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal lit(m_candidates[i].m_var, false); + init_dfs_info(lit); + init_dfs_info(~lit); + } + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal lit(m_candidates[i].m_var, false); + init_arcs(lit); + init_arcs(~lit); + } + m_rank = 0; + m_active = null_literal; + m_settled = null_literal; + TRACE("sat", display_dfs(tout);); + } + void lookahead::init_dfs_info(literal l) { + unsigned idx = l.index(); + m_dfs[idx].reset(); + set_bstamp(l); + } + // arcs are added in the opposite direction of implications. + // So for implications l => u we add arcs u -> l + void lookahead::init_arcs(literal l) { + literal_vector const& succ = m_binary[l.index()]; + for (unsigned i = 0; i < succ.size(); ++i) { + literal u = succ[i]; + SASSERT(u != l); + if (u.index() > l.index() && is_stamped(u)) { + add_arc(~l, ~u); + add_arc( u, l); + } + } + } + + void lookahead::get_scc(literal v) { + TRACE("scc", tout << v << "\n";); + set_parent(v, null_literal); + activate_scc(v); + do { + literal ll = get_min(v); + if (has_arc(v)) { + literal u = pop_arc(v); + unsigned r = get_rank(u); + if (r > 0) { + // u was processed before ll + if (r < get_rank(ll)) set_min(v, u); + } + else { + // process u in dfs order, add v to dfs stack for u + set_parent(u, v); + v = u; + activate_scc(v); + } + } + else { + literal u = get_parent(v); + if (v == ll) { + found_scc(v); + } + else if (get_rank(ll) < get_rank(get_min(u))) { + set_min(u, ll); + } + // walk back in the dfs stack + v = u; + } + } + while (v != null_literal && !inconsistent()); + } + + void lookahead::activate_scc(literal l) { + SASSERT(get_rank(l) == 0); + set_rank(l, ++m_rank); + set_link(l, m_active); + set_min(l, l); + m_active = l; + } + // make v root of the scc equivalence class + // set vcomp to be the highest rated literal + void lookahead::found_scc(literal v) { + literal t = m_active; + m_active = get_link(v); + literal best = v; + float best_rating = get_rating(v); + set_rank(v, UINT_MAX); + set_link(v, m_settled); m_settled = t; + while (t != v) { + if (t == ~v) { + TRACE("sat", display_scc(tout << "found contradiction during scc search\n");); + set_conflict(); + break; + } + set_rank(t, UINT_MAX); + set_parent(t, v); + float t_rating = get_rating(t); + if (t_rating > best_rating) { + best = t; + best_rating = t_rating; + } + t = get_link(t); + } + set_parent(v, v); + set_vcomp(v, best); + if (get_rank(~v) == UINT_MAX) { + set_vcomp(v, ~get_vcomp(get_parent(~v))); + } + } + + std::ostream& lookahead::display_dfs(std::ostream& out) const { + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal l(m_candidates[i].m_var, false); + display_dfs(out, l); + display_dfs(out, ~l); + } + return out; + } + + std::ostream& lookahead::display_dfs(std::ostream& out, literal l) const { + arcs const& a1 = get_arcs(l); + if (!a1.empty()) { + out << l << " -> " << a1 << "\n"; + } + return out; + } + + std::ostream& lookahead::display_scc(std::ostream& out) const { + display_dfs(out); + for (unsigned i = 0; i < m_candidates.size(); ++i) { + literal l(m_candidates[i].m_var, false); + display_scc(out, l); + display_scc(out, ~l); + } + return out; + } + + std::ostream& lookahead::display_scc(std::ostream& out, literal l) const { + out << l << " := " << get_parent(l) + << " min: " << get_min(l) + << " rank: " << get_rank(l) + << " height: " << get_height(l) + << " link: " << get_link(l) + << " child: " << get_child(l) + << " vcomp: " << get_vcomp(l) << "\n"; + return out; + } + + + // ------------------------------------ + // lookahead forest + // sat11.w 115-121 + + literal lookahead::get_child(literal u) const { + if (u == null_literal) return m_root_child; + return m_dfs[u.index()].m_min; + } + + void lookahead::set_child(literal v, literal u) { + if (v == null_literal) m_root_child = u; + else m_dfs[v.index()].m_min = u; + } + + /* + \brief Assign heights to the nodes. + Nodes within the same strongly connected component are given the same height. + The code assumes that m_settled is topologically sorted such that + 1. nodes in the same equivalence class come together + 2. the equivalence class representative is last + + */ + void lookahead::find_heights() { + m_root_child = null_literal; + literal pp = null_literal; + unsigned h = 0; + literal w, uu; + TRACE("sat", + for (literal u = m_settled; u != null_literal; u = get_link(u)) { + tout << u << " "; + } + tout << "\n";); + for (literal u = m_settled; u != null_literal; u = uu) { + TRACE("sat", tout << "process: " << u << "\n";); + uu = get_link(u); + literal p = get_parent(u); + if (p != pp) { + // new equivalence class + h = 0; + w = null_literal; + pp = p; + } + // traverse nodes in order of implication + unsigned sz = num_next(~u); + for (unsigned j = 0; j < sz; ++j) { + literal v = ~get_next(~u, j); + TRACE("sat", tout << "child " << v << " link: " << get_link(v) << "\n";); + literal pv = get_parent(v); + // skip nodes in same equivalence, they will all be processed + if (pv == p) continue; + unsigned hh = get_height(pv); + // update the maximal height descendant + if (hh >= h) { + h = hh + 1; + w = pv; + } + } + if (p == u) { + // u is an equivalence class representative + // it is processed last + literal v = get_child(w); + set_height(u, h); + set_child(u, null_literal); + set_link(u, v); + set_child(w, u); + TRACE("sat", tout << "child(" << w << ") = " << u << " link(" << u << ") = " << v << "\n";); + } + } + TRACE("sat", + display_forest(tout << "forest: ", get_child(null_literal)); + tout << "\n"; + display_scc(tout); ); + } + std::ostream& lookahead::display_forest(std::ostream& out, literal l) { + for (literal u = l; u != null_literal; u = get_link(u)) { + out << u << " "; + l = get_child(u); + if (l != null_literal) { + out << "("; + display_forest(out, l); + out << ") "; + } + } + return out; + } + + void lookahead::construct_lookahead_table() { + literal u = get_child(null_literal), v = null_literal; + unsigned offset = 0; + SASSERT(m_lookahead.empty()); + while (u != null_literal) { + set_rank(u, m_lookahead.size()); + set_lookahead(get_vcomp(u)); + if (null_literal != get_child(u)) { + set_parent(u, v); + v = u; + u = get_child(u); + } + else { + while (true) { + set_offset(get_rank(u), offset); + offset += 2; + set_parent(u, v == null_literal ? v : get_vcomp(v)); + u = get_link(u); + if (u == null_literal && v != null_literal) { + u = v; + v = get_parent(u); + } + else { + break; + } + } + } + } + SASSERT(2*m_lookahead.size() == offset); + TRACE("sat", for (unsigned i = 0; i < m_lookahead.size(); ++i) + tout << m_lookahead[i].m_lit << " : " << m_lookahead[i].m_offset << "\n";); + } + + + // ------------------------------------ + // clause management + + void lookahead::attach_clause(clause& c) { + if (c.size() == 3) { + attach_ternary(c[0], c[1], c[2]); + } + else { + literal block_lit = c[c.size() >> 2]; + clause_offset cls_off = m_cls_allocator.get_offset(&c); + m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); + m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); + SASSERT(is_undef(c[0])); + SASSERT(is_undef(c[1])); + } + } + + void lookahead::detach_clause(clause& c) { + clause_offset cls_off = m_cls_allocator.get_offset(&c); + m_retired_clauses.push_back(&c); + erase_clause_watch(get_wlist(~c[0]), cls_off); + erase_clause_watch(get_wlist(~c[1]), cls_off); + } + + void lookahead::del_clauses() { + clause * const* end = m_clauses.end(); + clause * const * it = m_clauses.begin(); + for (; it != end; ++it) { + m_cls_allocator.del_clause(*it); + } + } + + void lookahead::detach_ternary(literal l1, literal l2, literal l3) { + ++m_stats.m_del_ternary; + m_retired_ternary.push_back(ternary(l1, l2, l3)); + // implicitly erased: erase_ternary_watch(get_wlist(~l1), l2, l3); + erase_ternary_watch(get_wlist(~l2), l1, l3); + erase_ternary_watch(get_wlist(~l3), l1, l2); + } + + void lookahead::attach_ternary(ternary const& t) { + attach_ternary(t.m_u, t.m_v, t.m_w); + } + + void lookahead::attach_ternary(literal l1, literal l2, literal l3) { + ++m_stats.m_add_ternary; + TRACE("sat", tout << l1 << " " << l2 << " " << l3 << "\n";); + m_watches[(~l1).index()].push_back(watched(l2, l3)); + m_watches[(~l2).index()].push_back(watched(l1, l3)); + m_watches[(~l3).index()].push_back(watched(l1, l2)); + } + + // ------------------------------------ + // initialization + + void lookahead::init_var(bool_var v) { + m_binary.push_back(literal_vector()); + m_binary.push_back(literal_vector()); + m_watches.push_back(watch_list()); + m_watches.push_back(watch_list()); + m_full_watches.push_back(clause_vector()); + m_full_watches.push_back(clause_vector()); + m_bstamp.push_back(0); + m_bstamp.push_back(0); + m_stamp.push_back(0); + m_dfs.push_back(dfs_info()); + m_dfs.push_back(dfs_info()); + m_lits.push_back(lit_info()); + m_lits.push_back(lit_info()); + m_rating.push_back(0); + m_vprefix.push_back(prefix()); + if (!m_s.was_eliminated(v)) + m_freevars.insert(v); + } + + void lookahead::init() { + m_delta_trigger = m_num_vars/10; + m_config.m_dl_success = 0.8; + m_inconsistent = false; + m_qhead = 0; + m_bstamp_id = 0; + + for (unsigned i = 0; i < m_num_vars; ++i) { + init_var(i); + } + + // copy binary clauses + unsigned sz = m_s.m_watches.size(); + for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { + literal l = ~to_literal(l_idx); + watch_list const & wlist = m_s.m_watches[l_idx]; + watch_list::const_iterator it = wlist.begin(); + watch_list::const_iterator end = wlist.end(); + for (; it != end; ++it) { + if (!it->is_binary_non_learned_clause()) + continue; + literal l2 = it->get_literal(); + SASSERT(!m_s.was_eliminated(l.var())); + SASSERT(!m_s.was_eliminated(l2.var())); + if (l.index() < l2.index()) + add_binary(l, l2); + } + } + + copy_clauses(m_s.m_clauses); + copy_clauses(m_s.m_learned); + + // copy units + unsigned trail_sz = m_s.init_trail_size(); + for (unsigned i = 0; i < trail_sz; ++i) { + literal l = m_s.m_trail[i]; + if (!m_s.was_eliminated(l.var())) { + if (m_s.m_config.m_drat) m_drat.add(l, false); + assign(l); + } + } + propagate(); + m_qhead = m_trail.size(); + TRACE("sat", m_s.display(tout); display(tout);); + } + + void lookahead::copy_clauses(clause_vector const& clauses) { + // copy clauses + clause_vector::const_iterator it = clauses.begin(); + clause_vector::const_iterator end = clauses.end(); + for (; it != end; ++it) { + clause& c = *(*it); + if (c.was_removed()) continue; + clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); + m_clauses.push_back(c1); + attach_clause(*c1); + for (unsigned i = 0; i < c.size(); ++i) { + m_full_watches[(~c[i]).index()].push_back(c1); + SASSERT(!m_s.was_eliminated(c[i].var())); + } + if (m_s.m_config.m_drat) m_drat.add(c, false); + } + } + + // ------------------------------------ + // search + + + void lookahead::push(literal lit, unsigned level) { + SASSERT(m_search_mode == lookahead_mode::searching); + m_binary_trail_lim.push_back(m_binary_trail.size()); + m_trail_lim.push_back(m_trail.size()); + m_num_tc1_lim.push_back(m_num_tc1); + m_retired_clause_lim.push_back(m_retired_clauses.size()); + m_retired_ternary_lim.push_back(m_retired_ternary.size()); + m_qhead_lim.push_back(m_qhead); + scoped_level _sl(*this, level); + m_assumptions.push_back(~lit); + assign(lit); + propagate(); + } + + void lookahead::pop() { + if (m_assumptions.empty()) IF_VERBOSE(0, verbose_stream() << "empty pop\n";); + m_assumptions.pop_back(); + m_inconsistent = false; + SASSERT(m_search_mode == lookahead_mode::searching); + + // m_freevars only for main search + // undo assignments + unsigned old_sz = m_trail_lim.back(); + for (unsigned i = m_trail.size(); i > old_sz; ) { + --i; + literal l = m_trail[i]; + set_undef(l); + TRACE("sat", tout << "inserting free var v" << l.var() << "\n";); + m_freevars.insert(l.var()); + } + m_trail.shrink(old_sz); // reset assignment. + m_trail_lim.pop_back(); + + m_num_tc1 = m_num_tc1_lim.back(); + m_num_tc1_lim.pop_back(); + + // unretire clauses + old_sz = m_retired_clause_lim.back(); + for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { + attach_clause(*m_retired_clauses[i]); + } + m_retired_clauses.resize(old_sz); + m_retired_clause_lim.pop_back(); + + old_sz = m_retired_ternary_lim.back(); + for (unsigned i = old_sz; i < m_retired_ternary.size(); ++i) { + attach_ternary(m_retired_ternary[i]); + } + m_retired_ternary.shrink(old_sz); + m_retired_ternary_lim.pop_back(); + + // remove local binary clauses + old_sz = m_binary_trail_lim.back(); + for (unsigned i = m_binary_trail.size(); i > old_sz; ) { + del_binary(m_binary_trail[--i]); + } + m_binary_trail.shrink(old_sz); + m_binary_trail_lim.pop_back(); + + // reset propagation queue + m_qhead = m_qhead_lim.back(); + m_qhead_lim.pop_back(); + } + + bool lookahead::push_lookahead2(literal lit, unsigned level) { + scoped_level _sl(*this, level); + SASSERT(m_search_mode == lookahead_mode::lookahead1); + m_search_mode = lookahead_mode::lookahead2; + assign(lit); + propagate(); + bool unsat = inconsistent(); + SASSERT(m_search_mode == lookahead_mode::lookahead2); + m_search_mode = lookahead_mode::lookahead1; + m_inconsistent = false; + return unsat; + } + + void lookahead::push_lookahead1(literal lit, unsigned level) { + SASSERT(m_search_mode == lookahead_mode::searching); + m_search_mode = lookahead_mode::lookahead1; + scoped_level _sl(*this, level); + assign(lit); + propagate(); + } + + void lookahead::pop_lookahead1(literal lit) { + bool unsat = inconsistent(); + SASSERT(m_search_mode == lookahead_mode::lookahead1); + m_inconsistent = false; + m_search_mode = lookahead_mode::searching; + // convert windfalls to binary clauses. + if (!unsat) { + literal nlit = ~lit; + + for (unsigned i = 0; i < m_wstack.size(); ++i) { + literal l2 = m_wstack[i]; + //update_prefix(~lit); + //update_prefix(m_wstack[i]); + TRACE("sat", tout << "windfall: " << nlit << " " << l2 << "\n";); + // if we use try_add_binary, then this may produce new assignments + // these assignments get put on m_trail, and they are cleared by + // reset_wnb. We would need to distinguish the trail that comes + // from lookahead levels and the main search level for this to work. + add_binary(nlit, l2); + } + m_stats.m_windfall_binaries += m_wstack.size(); + } + m_wstack.reset(); + } + + clause const& lookahead::get_clause(watch_list::iterator it) const { + clause_offset cls_off = it->get_clause_offset(); + return *(m_cls_allocator.get_clause(cls_off)); + } + + bool lookahead::is_nary_propagation(clause const& c, literal l) const { + bool r = c.size() > 2 && ((c[0] == l && is_false(c[1])) || (c[1] == l && is_false(c[0]))); + DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(is_false(c[j]));); + return r; + } + + + // + // The current version is modeled after CDCL SAT solving data-structures. + // It borrows from the watch list data-structure. The cost tradeoffs are somewhat + // biased towards CDCL search overheads. + // If we walk over the positive occurrences of l, then those clauses can be retired so + // that they don't interfere with calculation of H. Instead of removing clauses from the watch + // list one can swap them to the "back" and adjust a size indicator of the watch list + // Only the size indicator needs to be updated on backtracking. + // + + void lookahead::propagate_clauses(literal l) { + SASSERT(is_true(l)); + if (inconsistent()) return; + watch_list& wlist = m_watches[l.index()]; + watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); + for (; it != end && !inconsistent(); ++it) { + switch (it->get_kind()) { + case watched::BINARY: + UNREACHABLE(); + break; + case watched::TERNARY: { + literal l1 = it->get_literal1(); + literal l2 = it->get_literal2(); + bool skip = false; + if (is_fixed(l1)) { + if (is_false(l1)) { + if (is_undef(l2)) { + propagated(l2); + } + else if (is_false(l2)) { + TRACE("sat", tout << l1 << " " << l2 << " " << l << "\n";); + set_conflict(); + } + } + else { + // retire this clause + } + } + else if (is_fixed(l2)) { + if (is_false(l2)) { + propagated(l1); + } + else { + // retire this clause + } + } + else { + switch (m_search_mode) { + case lookahead_mode::searching: + detach_ternary(~l, l1, l2); + try_add_binary(l1, l2); + skip = true; + break; + case lookahead_mode::lookahead1: + m_weighted_new_binaries += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + break; + case lookahead2: + break; + } + } + if (!skip) { + *it2 = *it; + it2++; + } + break; + } + case watched::CLAUSE: { + if (is_true(it->get_blocked_literal())) { + *it2 = *it; + ++it2; + break; + } + clause_offset cls_off = it->get_clause_offset(); + clause & c = *(m_cls_allocator.get_clause(cls_off)); + if (c[0] == ~l) + std::swap(c[0], c[1]); + if (is_true(c[0])) { + it->set_blocked_literal(c[0]); + *it2 = *it; + it2++; + break; + } + literal * l_it = c.begin() + 2; + literal * l_end = c.end(); + bool found = false; + for (; l_it != l_end && !found; ++l_it) { + if (!is_false(*l_it)) { + found = true; + c[1] = *l_it; + *l_it = ~l; + m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); + TRACE("sat_verbose", tout << "move watch from " << l << " to " << c[1] << " for clause " << c << "\n";); + } + } + if (found) { + found = false; + for (; l_it != l_end && !found; ++l_it) { + found = !is_false(*l_it); + } + // normal clause was converted to a binary clause. + if (!found && is_undef(c[1]) && is_undef(c[0])) { + TRACE("sat", tout << "got binary " << l << ": " << c << "\n";); + switch (m_search_mode) { + case lookahead_mode::searching: + detach_clause(c); + try_add_binary(c[0], c[1]); + break; + case lookahead_mode::lookahead1: + m_weighted_new_binaries += (*m_heur)[c[0].index()]* (*m_heur)[c[1].index()]; + break; + case lookahead_mode::lookahead2: + break; + } + } + else if (found && m_search_mode == lookahead_mode::lookahead1 && m_weighted_new_binaries == 0) { + // leave a trail that some clause was reduced but potentially not an autarky + l_it = c.begin() + 2; + found = false; + for (; l_it != l_end && !found; found = is_true(*l_it), ++l_it) ; + if (!found) { + m_weighted_new_binaries = (float)0.001; + } + } + break; + } + if (is_false(c[0])) { + TRACE("sat", tout << "conflict " << l << ": " << c << "\n";); + set_conflict(); + *it2 = *it; + ++it2; + } + else { + TRACE("sat", tout << "propagating " << l << ": " << c << "\n";); + SASSERT(is_undef(c[0])); + DEBUG_CODE(for (unsigned i = 2; i < c.size(); ++i) { + SASSERT(is_false(c[i])); + }); + *it2 = *it; + it2++; + propagated(c[0]); + } + break; + } + case watched::EXT_CONSTRAINT: { + bool keep = true; + SASSERT(m_s.m_ext); + m_s.m_ext->propagate(l, it->get_ext_constraint_idx(), keep); + if (m_inconsistent) { + set_conflict(); + } + else if (keep) { + *it2 = *it; + it2++; + } + break; + } + default: + UNREACHABLE(); + break; + } + } + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + wlist.set_end(it2); + } + + void lookahead::propagate_binary(literal l) { + literal_vector const& lits = m_binary[l.index()]; + TRACE("sat", tout << l << " => " << lits << "\n";); + unsigned sz = lits.size(); + for (unsigned i = 0; !inconsistent() && i < sz; ++i) { + assign(lits[i]); + } + } + + void lookahead::propagate() { + while (!inconsistent() && m_qhead < m_trail.size()) { + unsigned i = m_qhead; + unsigned sz = m_trail.size(); + for (; i < sz && !inconsistent(); ++i) { + literal l = m_trail[i]; + TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); + propagate_binary(l); + } + i = m_qhead; + for (; i < sz && !inconsistent(); ++i) { + propagate_clauses(m_trail[i]); + } + m_qhead = sz; + } + + TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); + } + + void lookahead::compute_wnb() { + init_wnb(); + TRACE("sat", display_lookahead(tout); ); + unsigned base = 2; + bool change = true; + bool first = true; + while (change && !inconsistent()) { + change = false; + for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { + checkpoint(); + literal lit = m_lookahead[i].m_lit; + if (is_fixed_at(lit, c_fixed_truth)) continue; + unsigned level = base + m_lookahead[i].m_offset; + if (m_stamp[lit.var()] >= level) { + continue; + } + if (scope_lvl() == 1) { + IF_VERBOSE(3, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); + } + TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); + reset_wnb(lit); + push_lookahead1(lit, level); + if (!first) do_double(lit, base); + bool unsat = inconsistent(); + pop_lookahead1(lit); + if (unsat) { + TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); + reset_wnb(); + assign(~lit); + propagate(); + init_wnb(); + change = true; + } + else { + update_wnb(lit, level); + } + SASSERT(inconsistent() || !is_unsat()); + } + if (c_fixed_truth - 2 * m_lookahead.size() < base) { + break; + } + if (first && !change) { + first = false; + change = true; + } + reset_wnb(); + init_wnb(); + // base += 2 * m_lookahead.size(); + } + reset_wnb(); + TRACE("sat", display_lookahead(tout); ); + } + + void lookahead::init_wnb() { + TRACE("sat", tout << "init_wnb: " << m_qhead << "\n";); + m_qhead_lim.push_back(m_qhead); + m_trail_lim.push_back(m_trail.size()); + } + + void lookahead::reset_wnb() { + m_qhead = m_qhead_lim.back(); + TRACE("sat", tout << "reset_wnb: " << m_qhead << "\n";); + unsigned old_sz = m_trail_lim.back(); + for (unsigned i = old_sz; i < m_trail.size(); ++i) { + set_undef(m_trail[i]); + } + m_trail.shrink(old_sz); + m_trail_lim.pop_back(); + m_qhead_lim.pop_back(); + } + + literal lookahead::select_literal() { + literal l = null_literal; + float h = 0; + unsigned count = 1; + for (unsigned i = 0; i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + if (lit.sign() || !is_undef(lit)) { + continue; + } + float diff1 = get_wnb(lit), diff2 = get_wnb(~lit); + float mixd = mix_diff(diff1, diff2); + + if (mixd == h) ++count; + if (mixd > h || (mixd == h && m_s.m_rand(count) == 0)) { + CTRACE("sat", l != null_literal, tout << lit << " mix diff: " << mixd << "\n";); + if (mixd > h) count = 1; + h = mixd; + l = diff1 < diff2 ? lit : ~lit; + } + } + // if (count > 1) std::cout << count << "\n"; + TRACE("sat", tout << "selected: " << l << "\n";); + return l; + } + + + void lookahead::reset_wnb(literal l) { + m_weighted_new_binaries = 0; + + // inherit propagation effect from parent. + literal p = get_parent(l); + set_wnb(l, p == null_literal ? 0 : get_wnb(p)); + } + + bool lookahead::check_autarky(literal l, unsigned level) { + return false; + // no propagations are allowed to reduce clauses. + clause_vector::const_iterator it = m_full_watches[l.index()].begin(); + clause_vector::const_iterator end = m_full_watches[l.index()].end(); + for (; it != end; ++it) { + clause& c = *(*it); + unsigned sz = c.size(); + bool found = false; + for (unsigned i = 0; !found && i < sz; ++i) { + found = is_true(c[i]); + if (found) { + TRACE("sat", tout << c[i] << " is true in " << c << "\n";); + } + } + IF_VERBOSE(2, verbose_stream() << "skip autarky " << l << "\n";); + if (!found) return false; + } + // + // bail out if there is a pending binary propagation. + // In general, we would have to check, recursively that + // a binary propagation does not create reduced clauses. + // + literal_vector const& lits = m_binary[l.index()]; + TRACE("sat", tout << l << ": " << lits << "\n";); + for (unsigned i = 0; i < lits.size(); ++i) { + literal l2 = lits[i]; + if (is_true(l2)) continue; + SASSERT(!is_false(l2)); + return false; + } + + return true; + } + + + void lookahead::update_wnb(literal l, unsigned level) { + if (m_weighted_new_binaries == 0) { + if (!check_autarky(l, level)) { + // skip + } + else if (get_wnb(l) == 0) { + ++m_stats.m_autarky_propagations; + IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); + + TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] + << " " + << (!m_binary[l.index()].empty() || !m_full_watches[l.index()].empty()) << "\n";); + reset_wnb(); + assign(l); + propagate(); + init_wnb(); + } + else { + ++m_stats.m_autarky_equivalences; + // l => p is known, but p => l is possibly not. + // add p => l. + // justification: any consequence of l + // that is not a consequence of p does not + // reduce the clauses. + literal p = get_parent(l); + SASSERT(p != null_literal); + if (m_stamp[p.var()] > m_stamp[l.var()]) { + TRACE("sat", tout << "equivalence " << l << " == " << p << "\n"; display(tout);); + IF_VERBOSE(1, verbose_stream() << "(sat.lookahead equivalence " << l << " == " << p << ")\n";); + add_binary(~l, p); + set_level(l, p); + } + } + } + else { + inc_wnb(l, m_weighted_new_binaries); + } + } + + void lookahead::do_double(literal l, unsigned& base) { + if (!inconsistent() && scope_lvl() > 1 && dl_enabled(l)) { + if (get_wnb(l) > m_delta_trigger) { + if (dl_no_overflow(base)) { + ++m_stats.m_double_lookahead_rounds; + double_look(l, base); + m_delta_trigger = get_wnb(l); + dl_disable(l); + } + } + else { + m_delta_trigger *= m_config.m_delta_rho; + } + } + } + + void lookahead::double_look(literal l, unsigned& base) { + SASSERT(!inconsistent()); + SASSERT(dl_no_overflow(base)); + unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); + scoped_level _sl(*this, dl_truth); + IF_VERBOSE(2, verbose_stream() << "double: " << l << "\n";); + init_wnb(); + assign(l); + propagate(); + bool change = true; + unsigned num_iterations = 0; + while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { + change = false; + num_iterations++; + base += 2*m_lookahead.size(); + for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + if (is_fixed_at(lit, dl_truth)) continue; + if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { + TRACE("sat", tout << "unit: " << ~lit << "\n";); + ++m_stats.m_double_lookahead_propagations; + SASSERT(m_level == dl_truth); + reset_wnb(); + assign(~lit); + propagate(); + change = true; + init_wnb(); + } + } + SASSERT(dl_truth - 2 * m_lookahead.size() > base); + } + reset_wnb(); + SASSERT(m_level == dl_truth); + base = dl_truth; + } + + void lookahead::validate_assign(literal l) { + if (m_s.m_config.m_drat && m_search_mode == lookahead_mode::searching) { + m_assumptions.push_back(l); + m_drat.add(m_assumptions); + m_assumptions.pop_back(); + } + } + + void lookahead::assign(literal l) { + SASSERT(m_level > 0); + if (is_undef(l)) { + TRACE("sat", tout << "assign: " << l << " @ " << m_level << " " << m_trail_lim.size() << " " << m_search_mode << "\n";); + set_true(l); + m_trail.push_back(l); + if (m_search_mode == lookahead_mode::searching) { + m_stats.m_propagations++; + TRACE("sat", tout << "removing free var v" << l.var() << "\n";); + m_freevars.remove(l.var()); + validate_assign(l); + } + } + else if (is_false(l)) { + TRACE("sat", tout << "conflict: " << l << " @ " << m_level << " " << m_search_mode << "\n";); + SASSERT(!is_true(l)); + validate_assign(l); + set_conflict(); + } + } + + void lookahead::propagated(literal l) { + assign(l); + switch (m_search_mode) { + case lookahead_mode::searching: + break; + case lookahead_mode::lookahead1: + m_wstack.push_back(l); + break; + case lookahead_mode::lookahead2: + break; + } + } + + bool lookahead::backtrack(literal_vector& trail) { + while (inconsistent()) { + if (trail.empty()) return false; + pop(); + flip_prefix(); + assign(~trail.back()); + trail.pop_back(); + propagate(); + } + return true; + } + + lbool lookahead::search() { + m_model.reset(); + scoped_level _sl(*this, c_fixed_truth); + literal_vector trail; + m_search_mode = lookahead_mode::searching; + while (true) { + TRACE("sat", display(tout);); + inc_istamp(); + checkpoint(); + if (inconsistent()) { + if (!backtrack(trail)) return l_false; + continue; + } + literal l = choose(); + if (inconsistent()) { + if (!backtrack(trail)) return l_false; + continue; + } + if (l == null_literal) { + return l_true; + } + TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); + ++m_stats.m_decisions; + IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(m_prefix, m_trail_lim.size()) << ": " << l << " " << m_trail.size() << "\n";); + push(l, c_fixed_truth); + trail.push_back(l); + SASSERT(inconsistent() || !is_unsat()); + } + } + + void lookahead::init_model() { + m_model.reset(); + for (unsigned i = 0; i < m_num_vars; ++i) { + lbool val; + literal lit(i, false); + if (is_undef(lit)) { + val = l_undef; + } + if (is_true(lit)) { + val = l_true; + } + else { + val = l_false; + } + m_model.push_back(val); + } + } + + std::ostream& lookahead::display_binary(std::ostream& out) const { + for (unsigned i = 0; i < m_binary.size(); ++i) { + literal_vector const& lits = m_binary[i]; + if (!lits.empty()) { + out << to_literal(i) << " -> " << lits << "\n"; + } + } + return out; + } + + std::ostream& lookahead::display_clauses(std::ostream& out) const { + for (unsigned i = 0; i < m_clauses.size(); ++i) { + out << *m_clauses[i] << "\n"; + } + return out; + } + + std::ostream& lookahead::display_values(std::ostream& out) const { + for (unsigned i = 0; i < m_trail.size(); ++i) { + literal l = m_trail[i]; + out << l << "\n"; + } + return out; + } + + std::ostream& lookahead::display_lookahead(std::ostream& out) const { + for (unsigned i = 0; i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + unsigned offset = m_lookahead[i].m_offset; + out << lit << "\toffset: " << offset; + out << (is_undef(lit)?" undef": (is_true(lit) ? " true": " false")); + out << " wnb: " << get_wnb(lit); + out << "\n"; + } + return out; + } + + void lookahead::init_search() { + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + } + + void lookahead::checkpoint() { + if (!m_rlimit.inc()) { + throw solver_exception(Z3_CANCELED_MSG); + } + if (memory::get_allocation_size() > m_s.m_config.m_max_memory) { + throw solver_exception(Z3_MAX_MEMORY_MSG); + } + } + + + + + literal lookahead::choose() { + literal l = null_literal; + while (l == null_literal) { + pre_select(); + if (m_lookahead.empty()) { + break; + } + compute_wnb(); + if (inconsistent()) { + break; + } + l = select_literal(); + } + SASSERT(inconsistent() || !is_unsat()); + return l; + } + + +} diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 6708e61f5..f1e78bf8f 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -64,6 +64,7 @@ namespace sat { reslimit m_rlimit; friend class ccc; + friend class card_extension; struct config { double m_dl_success; @@ -191,192 +192,55 @@ namespace sat { } }; + class scoped_ext { + lookahead& p; + public: + scoped_ext(lookahead& p); + ~scoped_ext(); + }; + // ------------------------------------- // prefix updates. I use low order bits. - void flip_prefix() { - if (m_trail_lim.size() < 64) { - uint64 mask = (1ull << m_trail_lim.size()); - m_prefix = mask | (m_prefix & (mask - 1)); - } - } - - void prune_prefix() { - if (m_trail_lim.size() < 64) { - m_prefix &= (1ull << m_trail_lim.size()) - 1; - } - } + void flip_prefix(); + void prune_prefix(); /** length < trail_lim.size: - mask m_prefix and p wrt length - update if different. */ - void update_prefix(literal l) { - bool_var x = l.var(); - unsigned p = m_vprefix[x].m_prefix; - unsigned pl = m_vprefix[x].m_length; - unsigned mask = (1 << std::min(31u, pl)) - 1; - if (pl >= m_trail_lim.size() || (p & mask) != (m_prefix & mask)) { - m_vprefix[x].m_length = m_trail_lim.size(); - m_vprefix[x].m_prefix = static_cast(m_prefix); - } - } + void update_prefix(literal l); - bool active_prefix(bool_var x) { - unsigned lvl = m_trail_lim.size(); - unsigned p = m_vprefix[x].m_prefix; - unsigned l = m_vprefix[x].m_length; - if (l > lvl) return false; - if (l == lvl || l >= 31) return m_prefix == p; - unsigned mask = ((1 << std::min(l,31u)) - 1); - return (m_prefix & mask) == (p & mask); - } + bool active_prefix(bool_var x); // ---------------------------------------- - void add_binary(literal l1, literal l2) { - TRACE("sat", tout << "binary: " << l1 << " " << l2 << "\n";); - SASSERT(l1 != l2); - // don't add tautologies and don't add already added binaries - if (~l1 == l2) return; - if (!m_binary[(~l1).index()].empty() && m_binary[(~l1).index()].back() == l2) return; - m_binary[(~l1).index()].push_back(l2); - m_binary[(~l2).index()].push_back(l1); - m_binary_trail.push_back((~l1).index()); - ++m_stats.m_add_binary; - if (m_s.m_config.m_drat) validate_binary(l1, l2); - } - - void del_binary(unsigned idx) { - // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n");); - literal_vector & lits = m_binary[idx]; - SASSERT(!lits.empty()); - literal l = lits.back(); - lits.pop_back(); - SASSERT(!m_binary[(~l).index()].empty()); - IF_VERBOSE(0, if (m_binary[(~l).index()].back() != ~to_literal(idx)) verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); - SASSERT(m_binary[(~l).index()].back() == ~to_literal(idx)); - m_binary[(~l).index()].pop_back(); - ++m_stats.m_del_binary; - } - - void validate_binary(literal l1, literal l2) { - if (m_search_mode == lookahead_mode::searching) { - m_assumptions.push_back(l1); - m_assumptions.push_back(l2); - m_drat.add(m_assumptions); - m_assumptions.pop_back(); - m_assumptions.pop_back(); - } - } + void add_binary(literal l1, literal l2); + void del_binary(unsigned idx); + void validate_binary(literal l1, literal l2); // ------------------------------------- // track consequences of binary clauses // see also 72 - 79 in sat11.w - void inc_bstamp() { - ++m_bstamp_id; - if (m_bstamp_id == 0) { - ++m_bstamp_id; - m_bstamp.fill(0); - } - } - void inc_istamp() { - ++m_istamp_id; - if (m_istamp_id == 0) { - ++m_istamp_id; - for (unsigned i = 0; i < m_lits.size(); ++i) { - m_lits[i].m_double_lookahead = 0; - } - } - } - void set_bstamp(literal l) { - m_bstamp[l.index()] = m_bstamp_id; - } - void set_bstamps(literal l) { - inc_bstamp(); - set_bstamp(l); - literal_vector const& conseq = m_binary[l.index()]; - literal_vector::const_iterator it = conseq.begin(); - literal_vector::const_iterator end = conseq.end(); - for (; it != end; ++it) { - set_bstamp(*it); - } - } + void inc_bstamp(); + void inc_istamp(); + void set_bstamp(literal l) { m_bstamp[l.index()] = m_bstamp_id; } + void set_bstamps(literal l); bool is_stamped(literal l) const { return m_bstamp[l.index()] == m_bstamp_id; } - - /** - \brief add one-step transitive closure of binary implications - return false if we learn a unit literal. - \pre all implicants of ~u are stamped. - u \/ v is true - **/ - - bool add_tc1(literal u, literal v) { - unsigned sz = m_binary[v.index()].size(); - for (unsigned i = 0; i < sz; ++i) { - literal w = m_binary[v.index()][i]; - // ~v \/ w - if (!is_fixed(w)) { - if (is_stamped(~w)) { - // u \/ v, ~v \/ w, u \/ ~w => u is unit - TRACE("sat", tout << "tc1: " << u << "\n";); - assign(u); - return false; - } - if (m_num_tc1 < m_config.m_tc1_limit) { - ++m_num_tc1; - IF_VERBOSE(3, verbose_stream() << "tc1: " << u << " " << w << "\n";); - add_binary(u, w); - } - } - } - return true; - } + bool add_tc1(literal u, literal v); /** \brief main routine for adding a new binary clause dynamically. */ - void try_add_binary(literal u, literal v) { - SASSERT(m_search_mode == lookahead_mode::searching); - SASSERT(u.var() != v.var()); - if (!is_undef(u) || !is_undef(v)) { - IF_VERBOSE(0, verbose_stream() << "adding assigned binary " << v << " " << u << "\n";); - } - set_bstamps(~u); - if (is_stamped(~v)) { - TRACE("sat", tout << "try_add_binary: " << u << "\n";); - assign(u); // u \/ ~v, u \/ v => u is a unit literal - } - else if (!is_stamped(v) && add_tc1(u, v)) { - // u \/ v is not in index - set_bstamps(~v); - if (is_stamped(~u)) { - TRACE("sat", tout << "try_add_binary: " << v << "\n";); - assign(v); // v \/ ~u, u \/ v => v is a unit literal - } - else if (add_tc1(v, u)) { - update_prefix(u); - update_prefix(v); - add_binary(u, v); - } - } - } + void try_add_binary(literal u, literal v); // ------------------------------------- // pre-selection // see also 91 - 102 sat11.w - void pre_select() { - m_lookahead.reset(); - if (select(scope_lvl())) { - get_scc(); - if (inconsistent()) return; - find_heights(); - construct_lookahead_table(); - } - } + void pre_select(); struct candidate { bool_var m_var; @@ -388,244 +252,16 @@ namespace sat { float get_rating(bool_var v) const { return m_rating[v]; } float get_rating(literal l) const { return get_rating(l.var()); } - - bool select(unsigned level) { - init_pre_selection(level); - unsigned level_cand = std::max(m_config.m_level_cand, m_freevars.size() / 50); - unsigned max_num_cand = level == 0 ? m_freevars.size() : level_cand / level; - max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand); - - float sum = 0; - for (bool newbies = false; ; newbies = true) { - sum = init_candidates(level, newbies); - if (!m_candidates.empty()) break; - if (is_sat()) { - return false; - } - if (newbies) { - enable_trace("sat"); - TRACE("sat", display(tout);); - TRACE("sat", tout << sum << "\n";); - } - } - SASSERT(!m_candidates.empty()); - // cut number of candidates down to max_num_cand. - // step 1. cut it to at most 2*max_num_cand. - // step 2. use a heap to sift through the rest. - bool progress = true; - while (progress && m_candidates.size() >= max_num_cand * 2) { - progress = false; - float mean = sum / (float)(m_candidates.size() + 0.0001); - sum = 0; - for (unsigned i = 0; i < m_candidates.size() && m_candidates.size() >= max_num_cand * 2; ++i) { - if (m_candidates[i].m_rating >= mean) { - sum += m_candidates[i].m_rating; - } - else { - m_candidates[i] = m_candidates.back(); - m_candidates.pop_back(); - --i; - progress = true; - } - } - } - TRACE("sat", display_candidates(tout);); - SASSERT(!m_candidates.empty()); - if (m_candidates.size() > max_num_cand) { - unsigned j = m_candidates.size()/2; - while (j > 0) { - --j; - sift_up(j); - } - while (true) { - m_candidates[0] = m_candidates.back(); - m_candidates.pop_back(); - if (m_candidates.size() == max_num_cand) break; - sift_up(0); - } - } - SASSERT(!m_candidates.empty() && m_candidates.size() <= max_num_cand); - TRACE("sat", display_candidates(tout);); - return true; - } - - void sift_up(unsigned j) { - unsigned i = j; - candidate c = m_candidates[j]; - for (unsigned k = 2*j + 1; k < m_candidates.size(); i = k, k = 2*k + 1) { - // pick largest parent - if (k + 1 < m_candidates.size() && m_candidates[k].m_rating < m_candidates[k+1].m_rating) { - ++k; - } - if (c.m_rating <= m_candidates[k].m_rating) break; - m_candidates[i] = m_candidates[k]; - } - if (i > j) m_candidates[i] = c; - } - - float init_candidates(unsigned level, bool newbies) { - m_candidates.reset(); - float sum = 0; - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - SASSERT(is_undef(*it)); - bool_var x = *it; - if (!m_select_lookahead_vars.empty() && m_select_lookahead_vars.contains(x)) { - m_candidates.push_back(candidate(x, m_rating[x])); - sum += m_rating[x]; - } - else if (newbies || active_prefix(x)) { - m_candidates.push_back(candidate(x, m_rating[x])); - sum += m_rating[x]; - } - } - TRACE("sat", display_candidates(tout << "sum: " << sum << "\n");); - return sum; - } - - std::ostream& display_candidates(std::ostream& out) const { - for (unsigned i = 0; i < m_candidates.size(); ++i) { - out << "var: " << m_candidates[i].m_var << " rating: " << m_candidates[i].m_rating << "\n"; - } - return out; - } - - bool is_unsat() const { - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause& c = *m_clauses[i]; - unsigned j = 0; - for (; j < c.size() && is_false(c[j]); ++j) {} - if (j == c.size()) { - TRACE("sat", tout << c << "\n";); - TRACE("sat", display(tout);); - return true; - } - } - return false; - } - - bool is_sat() const { - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - literal l(*it, false); - literal_vector const& lits1 = m_binary[l.index()]; - for (unsigned i = 0; i < lits1.size(); ++i) { - if (!is_true(lits1[i])) { - TRACE("sat", tout << l << " " << lits1[i] << "\n";); - return false; - } - } - l.neg(); - literal_vector const& lits2 = m_binary[l.index()]; - for (unsigned i = 0; i < lits2.size(); ++i) { - if (!is_true(lits2[i])) { - TRACE("sat", tout << l << " " << lits2[i] << "\n";); - return false; - } - } - } - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause& c = *m_clauses[i]; - unsigned j = 0; - for (; j < c.size() && !is_true(c[j]); ++j) {} - if (j == c.size()) { - return false; - } - } - return true; - } - - void init_pre_selection(unsigned level) { - unsigned max_level = m_config.m_max_hlevel; - if (level <= 1) { - ensure_H(2); - h_scores(m_H[0], m_H[1]); - for (unsigned j = 0; j < 2; ++j) { - for (unsigned i = 0; i < 2; ++i) { - h_scores(m_H[i + 1], m_H[(i + 2) % 3]); - } - } - m_heur = &m_H[1]; - } - else if (level < max_level) { - ensure_H(level); - h_scores(m_H[level-1], m_H[level]); - m_heur = &m_H[level]; - } - else { - ensure_H(max_level); - h_scores(m_H[max_level-1], m_H[max_level]); - m_heur = &m_H[max_level]; - } - } - - void ensure_H(unsigned level) { - while (m_H.size() <= level) { - m_H.push_back(svector()); - m_H.back().resize(m_num_vars * 2, 0); - } - } - - void h_scores(svector& h, svector& hp) { - float sum = 0; - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - literal l(*it, false); - sum += h[l.index()] + h[(~l).index()]; - } - float factor = 2 * m_freevars.size() / sum; - float sqfactor = factor * factor; - float afactor = factor * m_config.m_alpha; - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - literal l(*it, false); - float pos = l_score(l, h, factor, sqfactor, afactor); - float neg = l_score(~l, h, factor, sqfactor, afactor); - hp[l.index()] = pos; - hp[(~l).index()] = neg; - m_rating[l.var()] = pos * neg; - } - } - - float l_score(literal l, svector const& h, float factor, float sqfactor, float afactor) { - float sum = 0, tsum = 0; - literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); - for (; it != end; ++it) { - bool_var v = it->var(); - if (it->index() >= h.size()) - IF_VERBOSE(0, verbose_stream() << l << " " << *it << " " << h.size() << "\n";); - if (is_undef(*it)) sum += h[it->index()]; - // if (m_freevars.contains(it->var())) sum += h[it->index()]; - } - watch_list& wlist = m_watches[l.index()]; - watch_list::iterator wit = wlist.begin(), wend = wlist.end(); - for (; wit != wend; ++wit) { - switch (wit->get_kind()) { - case watched::BINARY: - UNREACHABLE(); - break; - case watched::TERNARY: { - literal l1 = wit->get_literal1(); - literal l2 = wit->get_literal2(); - // if (is_undef(l1) && is_undef(l2)) - tsum += h[l1.index()] * h[l2.index()]; - break; - } - case watched::CLAUSE: { - clause_offset cls_off = wit->get_clause_offset(); - clause & c = *(m_cls_allocator.get_clause(cls_off)); - // approximation compared to ternary clause case: - // we pick two other literals from the clause. - if (c[0] == ~l) { - tsum += h[c[1].index()] * h[c[2].index()]; - } - else { - SASSERT(c[1] == ~l); - tsum += h[c[0].index()] * h[c[2].index()]; - } - break; - } - } - } - sum = (float)(0.1 + afactor*sum + sqfactor*tsum); - return std::min(m_config.m_max_score, sum); - } + bool select(unsigned level); + void sift_up(unsigned j); + float init_candidates(unsigned level, bool newbies); + std::ostream& display_candidates(std::ostream& out) const; + bool is_unsat() const; + bool is_sat() const; + void init_pre_selection(unsigned level); + void ensure_H(unsigned level); + void h_scores(svector& h, svector& hp); + float l_score(literal l, svector const& h, float factor, float sqfactor, float afactor); // ------------------------------------ // Implication graph @@ -664,51 +300,10 @@ namespace sat { literal m_settled; vector m_dfs; - void get_scc() { - unsigned num_candidates = m_candidates.size(); - init_scc(); - for (unsigned i = 0; i < num_candidates && !inconsistent(); ++i) { - literal lit(m_candidates[i].m_var, false); - if (get_rank(lit) == 0) get_scc(lit); - if (get_rank(~lit) == 0) get_scc(~lit); - } - TRACE("sat", display_scc(tout);); - } - void init_scc() { - inc_bstamp(); - for (unsigned i = 0; i < m_candidates.size(); ++i) { - literal lit(m_candidates[i].m_var, false); - init_dfs_info(lit); - init_dfs_info(~lit); - } - for (unsigned i = 0; i < m_candidates.size(); ++i) { - literal lit(m_candidates[i].m_var, false); - init_arcs(lit); - init_arcs(~lit); - } - m_rank = 0; - m_active = null_literal; - m_settled = null_literal; - TRACE("sat", display_dfs(tout);); - } - void init_dfs_info(literal l) { - unsigned idx = l.index(); - m_dfs[idx].reset(); - set_bstamp(l); - } - // arcs are added in the opposite direction of implications. - // So for implications l => u we add arcs u -> l - void init_arcs(literal l) { - literal_vector const& succ = m_binary[l.index()]; - for (unsigned i = 0; i < succ.size(); ++i) { - literal u = succ[i]; - SASSERT(u != l); - if (u.index() > l.index() && is_stamped(u)) { - add_arc(~l, ~u); - add_arc( u, l); - } - } - } + void get_scc(); + void init_scc(); + void init_dfs_info(literal l); + void init_arcs(literal l); void add_arc(literal u, literal v) { m_dfs[u.index()].m_next.push_back(v); } bool has_arc(literal v) const { return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp; } arcs get_arcs(literal v) const { return m_dfs[v.index()].m_next; } @@ -727,115 +322,13 @@ namespace sat { void set_height(literal v, unsigned h) { m_dfs[v.index()].m_height = h; } void set_parent(literal v, literal p) { TRACE("scc", tout << v << " <- " << p << "\n";); m_dfs[v.index()].m_parent = p; } void set_vcomp(literal v, literal u) { m_dfs[v.index()].m_vcomp = u; } - void get_scc(literal v) { - TRACE("scc", tout << v << "\n";); - set_parent(v, null_literal); - activate_scc(v); - do { - literal ll = get_min(v); - if (has_arc(v)) { - literal u = pop_arc(v); - unsigned r = get_rank(u); - if (r > 0) { - // u was processed before ll - if (r < get_rank(ll)) set_min(v, u); - } - else { - // process u in dfs order, add v to dfs stack for u - set_parent(u, v); - v = u; - activate_scc(v); - } - } - else { - literal u = get_parent(v); - if (v == ll) { - found_scc(v); - } - else if (get_rank(ll) < get_rank(get_min(u))) { - set_min(u, ll); - } - // walk back in the dfs stack - v = u; - } - } - while (v != null_literal && !inconsistent()); - } - void activate_scc(literal l) { - SASSERT(get_rank(l) == 0); - set_rank(l, ++m_rank); - set_link(l, m_active); - set_min(l, l); - m_active = l; - } - // make v root of the scc equivalence class - // set vcomp to be the highest rated literal - void found_scc(literal v) { - literal t = m_active; - m_active = get_link(v); - literal best = v; - float best_rating = get_rating(v); - set_rank(v, UINT_MAX); - set_link(v, m_settled); m_settled = t; - while (t != v) { - if (t == ~v) { - TRACE("sat", display_scc(tout << "found contradiction during scc search\n");); - set_conflict(); - break; - } - set_rank(t, UINT_MAX); - set_parent(t, v); - float t_rating = get_rating(t); - if (t_rating > best_rating) { - best = t; - best_rating = t_rating; - } - t = get_link(t); - } - set_parent(v, v); - set_vcomp(v, best); - if (get_rank(~v) == UINT_MAX) { - set_vcomp(v, ~get_vcomp(get_parent(~v))); - } - } - - std::ostream& display_dfs(std::ostream& out) const { - for (unsigned i = 0; i < m_candidates.size(); ++i) { - literal l(m_candidates[i].m_var, false); - display_dfs(out, l); - display_dfs(out, ~l); - } - return out; - } - - std::ostream& display_dfs(std::ostream& out, literal l) const { - arcs const& a1 = get_arcs(l); - if (!a1.empty()) { - out << l << " -> " << a1 << "\n"; - } - return out; - } - - std::ostream& display_scc(std::ostream& out) const { - display_dfs(out); - for (unsigned i = 0; i < m_candidates.size(); ++i) { - literal l(m_candidates[i].m_var, false); - display_scc(out, l); - display_scc(out, ~l); - } - return out; - } - - std::ostream& display_scc(std::ostream& out, literal l) const { - out << l << " := " << get_parent(l) - << " min: " << get_min(l) - << " rank: " << get_rank(l) - << " height: " << get_height(l) - << " link: " << get_link(l) - << " child: " << get_child(l) - << " vcomp: " << get_vcomp(l) << "\n"; - return out; - } + void get_scc(literal v); + void activate_scc(literal l); + void found_scc(literal v); + std::ostream& display_dfs(std::ostream& out) const; + std::ostream& display_dfs(std::ostream& out, literal l) const; + std::ostream& display_scc(std::ostream& out) const; + std::ostream& display_scc(std::ostream& out, literal l) const; // ------------------------------------ @@ -844,86 +337,10 @@ namespace sat { literal m_root_child; - literal get_child(literal u) const { - if (u == null_literal) return m_root_child; - return m_dfs[u.index()].m_min; - } - void set_child(literal v, literal u) { - if (v == null_literal) m_root_child = u; - else m_dfs[v.index()].m_min = u; - } - - /* - \brief Assign heights to the nodes. - Nodes within the same strongly connected component are given the same height. - The code assumes that m_settled is topologically sorted such that - 1. nodes in the same equivalence class come together - 2. the equivalence class representative is last - - */ - void find_heights() { - m_root_child = null_literal; - literal pp = null_literal; - unsigned h = 0; - literal w, uu; - TRACE("sat", - for (literal u = m_settled; u != null_literal; u = get_link(u)) { - tout << u << " "; - } - tout << "\n";); - for (literal u = m_settled; u != null_literal; u = uu) { - TRACE("sat", tout << "process: " << u << "\n";); - uu = get_link(u); - literal p = get_parent(u); - if (p != pp) { - // new equivalence class - h = 0; - w = null_literal; - pp = p; - } - // traverse nodes in order of implication - unsigned sz = num_next(~u); - for (unsigned j = 0; j < sz; ++j) { - literal v = ~get_next(~u, j); - TRACE("sat", tout << "child " << v << " link: " << get_link(v) << "\n";); - literal pv = get_parent(v); - // skip nodes in same equivalence, they will all be processed - if (pv == p) continue; - unsigned hh = get_height(pv); - // update the maximal height descendant - if (hh >= h) { - h = hh + 1; - w = pv; - } - } - if (p == u) { - // u is an equivalence class representative - // it is processed last - literal v = get_child(w); - set_height(u, h); - set_child(u, null_literal); - set_link(u, v); - set_child(w, u); - TRACE("sat", tout << "child(" << w << ") = " << u << " link(" << u << ") = " << v << "\n";); - } - } - TRACE("sat", - display_forest(tout << "forest: ", get_child(null_literal)); - tout << "\n"; - display_scc(tout); ); - } - std::ostream& display_forest(std::ostream& out, literal l) { - for (literal u = l; u != null_literal; u = get_link(u)) { - out << u << " "; - l = get_child(u); - if (l != null_literal) { - out << "("; - display_forest(out, l); - out << ") "; - } - } - return out; - } + literal get_child(literal u) const; + void set_child(literal v, literal u); + void find_heights(); + std::ostream& display_forest(std::ostream& out, literal l); struct literal_offset { literal m_lit; @@ -931,696 +348,55 @@ namespace sat { literal_offset(literal l): m_lit(l), m_offset(0) {} }; svector m_lookahead; - void set_offset(unsigned idx, unsigned offset) { - m_lookahead[idx].m_offset = offset; - } - void set_lookahead(literal l) { - m_lookahead.push_back(literal_offset(l)); - } - void construct_lookahead_table() { - literal u = get_child(null_literal), v = null_literal; - unsigned offset = 0; - SASSERT(m_lookahead.empty()); - while (u != null_literal) { - set_rank(u, m_lookahead.size()); - set_lookahead(get_vcomp(u)); - if (null_literal != get_child(u)) { - set_parent(u, v); - v = u; - u = get_child(u); - } - else { - while (true) { - set_offset(get_rank(u), offset); - offset += 2; - set_parent(u, v == null_literal ? v : get_vcomp(v)); - u = get_link(u); - if (u == null_literal && v != null_literal) { - u = v; - v = get_parent(u); - } - else { - break; - } - } - } - } - SASSERT(2*m_lookahead.size() == offset); - TRACE("sat", for (unsigned i = 0; i < m_lookahead.size(); ++i) - tout << m_lookahead[i].m_lit << " : " << m_lookahead[i].m_offset << "\n";); - } + void set_offset(unsigned idx, unsigned offset) { m_lookahead[idx].m_offset = offset; } + void set_lookahead(literal l) { m_lookahead.push_back(literal_offset(l)); } + void construct_lookahead_table(); // ------------------------------------ // clause management - void attach_clause(clause& c) { - if (c.size() == 3) { - attach_ternary(c[0], c[1], c[2]); - } - else { - literal block_lit = c[c.size() >> 2]; - clause_offset cls_off = m_cls_allocator.get_offset(&c); - m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); - m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); - SASSERT(is_undef(c[0])); - SASSERT(is_undef(c[1])); - } - } - - void detach_clause(clause& c) { - clause_offset cls_off = m_cls_allocator.get_offset(&c); - m_retired_clauses.push_back(&c); - erase_clause_watch(get_wlist(~c[0]), cls_off); - erase_clause_watch(get_wlist(~c[1]), cls_off); - } - - void del_clauses() { - clause * const* end = m_clauses.end(); - clause * const * it = m_clauses.begin(); - for (; it != end; ++it) { - m_cls_allocator.del_clause(*it); - } - } - - void detach_ternary(literal l1, literal l2, literal l3) { - ++m_stats.m_del_ternary; - m_retired_ternary.push_back(ternary(l1, l2, l3)); - // implicitly erased: erase_ternary_watch(get_wlist(~l1), l2, l3); - erase_ternary_watch(get_wlist(~l2), l1, l3); - erase_ternary_watch(get_wlist(~l3), l1, l2); - } - - void attach_ternary(ternary const& t) { - attach_ternary(t.m_u, t.m_v, t.m_w); - } - - void attach_ternary(literal l1, literal l2, literal l3) { - ++m_stats.m_add_ternary; - TRACE("sat", tout << l1 << " " << l2 << " " << l3 << "\n";); - m_watches[(~l1).index()].push_back(watched(l2, l3)); - m_watches[(~l2).index()].push_back(watched(l1, l3)); - m_watches[(~l3).index()].push_back(watched(l1, l2)); - } - + void attach_clause(clause& c); + void detach_clause(clause& c); + void del_clauses(); + void detach_ternary(literal l1, literal l2, literal l3); + void attach_ternary(ternary const& t); + void attach_ternary(literal l1, literal l2, literal l3); watch_list& get_wlist(literal l) { return m_watches[l.index()]; } // ------------------------------------ // initialization - void init_var(bool_var v) { - m_binary.push_back(literal_vector()); - m_binary.push_back(literal_vector()); - m_watches.push_back(watch_list()); - m_watches.push_back(watch_list()); - m_full_watches.push_back(clause_vector()); - m_full_watches.push_back(clause_vector()); - m_bstamp.push_back(0); - m_bstamp.push_back(0); - m_stamp.push_back(0); - m_dfs.push_back(dfs_info()); - m_dfs.push_back(dfs_info()); - m_lits.push_back(lit_info()); - m_lits.push_back(lit_info()); - m_rating.push_back(0); - m_vprefix.push_back(prefix()); - if (!m_s.was_eliminated(v)) - m_freevars.insert(v); - } - - void init() { - m_delta_trigger = m_num_vars/10; - m_config.m_dl_success = 0.8; - m_inconsistent = false; - m_qhead = 0; - m_bstamp_id = 0; - - for (unsigned i = 0; i < m_num_vars; ++i) { - init_var(i); - } - - // copy binary clauses - unsigned sz = m_s.m_watches.size(); - for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { - literal l = ~to_literal(l_idx); - watch_list const & wlist = m_s.m_watches[l_idx]; - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_non_learned_clause()) - continue; - literal l2 = it->get_literal(); - SASSERT(!m_s.was_eliminated(l.var())); - SASSERT(!m_s.was_eliminated(l2.var())); - if (l.index() < l2.index()) - add_binary(l, l2); - } - } - - copy_clauses(m_s.m_clauses); - copy_clauses(m_s.m_learned); - - // copy units - unsigned trail_sz = m_s.init_trail_size(); - for (unsigned i = 0; i < trail_sz; ++i) { - literal l = m_s.m_trail[i]; - if (!m_s.was_eliminated(l.var())) { - if (m_s.m_config.m_drat) m_drat.add(l, false); - assign(l); - } - } - propagate(); - m_qhead = m_trail.size(); - TRACE("sat", m_s.display(tout); display(tout);); - } - - void copy_clauses(clause_vector const& clauses) { - // copy clauses - clause_vector::const_iterator it = clauses.begin(); - clause_vector::const_iterator end = clauses.end(); - for (; it != end; ++it) { - clause& c = *(*it); - if (c.was_removed()) continue; - clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); - m_clauses.push_back(c1); - attach_clause(*c1); - for (unsigned i = 0; i < c.size(); ++i) { - m_full_watches[(~c[i]).index()].push_back(c1); - SASSERT(!m_s.was_eliminated(c[i].var())); - } - if (m_s.m_config.m_drat) m_drat.add(c, false); - } - } + void init_var(bool_var v); + void init(); + void copy_clauses(clause_vector const& clauses); // ------------------------------------ // search - void push(literal lit, unsigned level) { - SASSERT(m_search_mode == lookahead_mode::searching); - m_binary_trail_lim.push_back(m_binary_trail.size()); - m_trail_lim.push_back(m_trail.size()); - m_num_tc1_lim.push_back(m_num_tc1); - m_retired_clause_lim.push_back(m_retired_clauses.size()); - m_retired_ternary_lim.push_back(m_retired_ternary.size()); - m_qhead_lim.push_back(m_qhead); - scoped_level _sl(*this, level); - m_assumptions.push_back(~lit); - assign(lit); - propagate(); - } - - void pop() { - if (m_assumptions.empty()) IF_VERBOSE(0, verbose_stream() << "empty pop\n";); - m_assumptions.pop_back(); - m_inconsistent = false; - SASSERT(m_search_mode == lookahead_mode::searching); - - // m_freevars only for main search - // undo assignments - unsigned old_sz = m_trail_lim.back(); - for (unsigned i = m_trail.size(); i > old_sz; ) { - --i; - literal l = m_trail[i]; - set_undef(l); - TRACE("sat", tout << "inserting free var v" << l.var() << "\n";); - m_freevars.insert(l.var()); - } - m_trail.shrink(old_sz); // reset assignment. - m_trail_lim.pop_back(); - - m_num_tc1 = m_num_tc1_lim.back(); - m_num_tc1_lim.pop_back(); - - // unretire clauses - old_sz = m_retired_clause_lim.back(); - for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { - attach_clause(*m_retired_clauses[i]); - } - m_retired_clauses.resize(old_sz); - m_retired_clause_lim.pop_back(); - - old_sz = m_retired_ternary_lim.back(); - for (unsigned i = old_sz; i < m_retired_ternary.size(); ++i) { - attach_ternary(m_retired_ternary[i]); - } - m_retired_ternary.shrink(old_sz); - m_retired_ternary_lim.pop_back(); - - // remove local binary clauses - old_sz = m_binary_trail_lim.back(); - for (unsigned i = m_binary_trail.size(); i > old_sz; ) { - del_binary(m_binary_trail[--i]); - } - m_binary_trail.shrink(old_sz); - m_binary_trail_lim.pop_back(); - - // reset propagation queue - m_qhead = m_qhead_lim.back(); - m_qhead_lim.pop_back(); - } - - bool push_lookahead2(literal lit, unsigned level) { - scoped_level _sl(*this, level); - SASSERT(m_search_mode == lookahead_mode::lookahead1); - m_search_mode = lookahead_mode::lookahead2; - assign(lit); - propagate(); - bool unsat = inconsistent(); - SASSERT(m_search_mode == lookahead_mode::lookahead2); - m_search_mode = lookahead_mode::lookahead1; - m_inconsistent = false; - return unsat; - } - - void push_lookahead1(literal lit, unsigned level) { - SASSERT(m_search_mode == lookahead_mode::searching); - m_search_mode = lookahead_mode::lookahead1; - scoped_level _sl(*this, level); - assign(lit); - propagate(); - } - - void pop_lookahead1(literal lit) { - bool unsat = inconsistent(); - SASSERT(m_search_mode == lookahead_mode::lookahead1); - m_inconsistent = false; - m_search_mode = lookahead_mode::searching; - // convert windfalls to binary clauses. - if (!unsat) { - literal nlit = ~lit; - - for (unsigned i = 0; i < m_wstack.size(); ++i) { - literal l2 = m_wstack[i]; - //update_prefix(~lit); - //update_prefix(m_wstack[i]); - TRACE("sat", tout << "windfall: " << nlit << " " << l2 << "\n";); - // if we use try_add_binary, then this may produce new assignments - // these assignments get put on m_trail, and they are cleared by - // reset_wnb. We would need to distinguish the trail that comes - // from lookahead levels and the main search level for this to work. - add_binary(nlit, l2); - } - m_stats.m_windfall_binaries += m_wstack.size(); - } - m_wstack.reset(); - } - + void push(literal lit, unsigned level); + void pop(); + bool push_lookahead2(literal lit, unsigned level); + void push_lookahead1(literal lit, unsigned level); + void pop_lookahead1(literal lit); float mix_diff(float l, float r) const { return l + r + (1 << 10) * l * r; } - - clause const& get_clause(watch_list::iterator it) const { - clause_offset cls_off = it->get_clause_offset(); - return *(m_cls_allocator.get_clause(cls_off)); - } - - bool is_nary_propagation(clause const& c, literal l) const { - bool r = c.size() > 2 && ((c[0] == l && is_false(c[1])) || (c[1] == l && is_false(c[0]))); - DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(is_false(c[j]));); - return r; - } - - // - // The current version is modeled after CDCL SAT solving data-structures. - // It borrows from the watch list data-structure. The cost tradeoffs are somewhat - // biased towards CDCL search overheads. - // If we walk over the positive occurrences of l, then those clauses can be retired so - // that they don't interfere with calculation of H. Instead of removing clauses from the watch - // list one can swap them to the "back" and adjust a size indicator of the watch list - // Only the size indicator needs to be updated on backtracking. - // - void propagate_clauses(literal l) { - SASSERT(is_true(l)); - if (inconsistent()) return; - watch_list& wlist = m_watches[l.index()]; - watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); - for (; it != end && !inconsistent(); ++it) { - switch (it->get_kind()) { - case watched::BINARY: - UNREACHABLE(); - break; - case watched::TERNARY: { - literal l1 = it->get_literal1(); - literal l2 = it->get_literal2(); - bool skip = false; - if (is_fixed(l1)) { - if (is_false(l1)) { - if (is_undef(l2)) { - propagated(l2); - } - else if (is_false(l2)) { - TRACE("sat", tout << l1 << " " << l2 << " " << l << "\n";); - set_conflict(); - } - } - else { - // retire this clause - } - } - else if (is_fixed(l2)) { - if (is_false(l2)) { - propagated(l1); - } - else { - // retire this clause - } - } - else { - switch (m_search_mode) { - case lookahead_mode::searching: - detach_ternary(~l, l1, l2); - try_add_binary(l1, l2); - skip = true; - break; - case lookahead_mode::lookahead1: - m_weighted_new_binaries += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; - break; - case lookahead2: - break; - } - } - if (!skip) { - *it2 = *it; - it2++; - } - break; - } - case watched::CLAUSE: { - if (is_true(it->get_blocked_literal())) { - *it2 = *it; - ++it2; - break; - } - clause_offset cls_off = it->get_clause_offset(); - clause & c = *(m_cls_allocator.get_clause(cls_off)); - if (c[0] == ~l) - std::swap(c[0], c[1]); - if (is_true(c[0])) { - it->set_blocked_literal(c[0]); - *it2 = *it; - it2++; - break; - } - literal * l_it = c.begin() + 2; - literal * l_end = c.end(); - bool found = false; - for (; l_it != l_end && !found; ++l_it) { - if (!is_false(*l_it)) { - found = true; - c[1] = *l_it; - *l_it = ~l; - m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); - TRACE("sat_verbose", tout << "move watch from " << l << " to " << c[1] << " for clause " << c << "\n";); - } - } - if (found) { - found = false; - for (; l_it != l_end && !found; ++l_it) { - found = !is_false(*l_it); - } - // normal clause was converted to a binary clause. - if (!found && is_undef(c[1]) && is_undef(c[0])) { - TRACE("sat", tout << "got binary " << l << ": " << c << "\n";); - switch (m_search_mode) { - case lookahead_mode::searching: - detach_clause(c); - try_add_binary(c[0], c[1]); - break; - case lookahead_mode::lookahead1: - m_weighted_new_binaries += (*m_heur)[c[0].index()]* (*m_heur)[c[1].index()]; - break; - case lookahead_mode::lookahead2: - break; - } - } - else if (found && m_search_mode == lookahead_mode::lookahead1 && m_weighted_new_binaries == 0) { - // leave a trail that some clause was reduced but potentially not an autarky - l_it = c.begin() + 2; - found = false; - for (; l_it != l_end && !found; found = is_true(*l_it), ++l_it) ; - if (!found) { - m_weighted_new_binaries = (float)0.001; - } - } - break; - } - if (is_false(c[0])) { - TRACE("sat", tout << "conflict " << l << ": " << c << "\n";); - set_conflict(); - *it2 = *it; - ++it2; - } - else { - TRACE("sat", tout << "propagating " << l << ": " << c << "\n";); - SASSERT(is_undef(c[0])); - DEBUG_CODE(for (unsigned i = 2; i < c.size(); ++i) { - SASSERT(is_false(c[i])); - }); - *it2 = *it; - it2++; - propagated(c[0]); - } - break; - } - case watched::EXT_CONSTRAINT: - UNREACHABLE(); - break; - default: - UNREACHABLE(); - break; - } - } - for (; it != end; ++it, ++it2) { - *it2 = *it; - } - wlist.set_end(it2); - } - - void propagate_binary(literal l) { - literal_vector const& lits = m_binary[l.index()]; - TRACE("sat", tout << l << " => " << lits << "\n";); - unsigned sz = lits.size(); - for (unsigned i = 0; !inconsistent() && i < sz; ++i) { - assign(lits[i]); - } - } - - void propagate() { - while (!inconsistent() && m_qhead < m_trail.size()) { - unsigned i = m_qhead; - unsigned sz = m_trail.size(); - for (; i < sz && !inconsistent(); ++i) { - literal l = m_trail[i]; - TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); - propagate_binary(l); - } - i = m_qhead; - for (; i < sz && !inconsistent(); ++i) { - propagate_clauses(m_trail[i]); - } - m_qhead = sz; - } - - TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); - } - - literal choose() { - literal l = null_literal; - while (l == null_literal) { - pre_select(); - if (m_lookahead.empty()) { - break; - } - compute_wnb(); - if (inconsistent()) { - break; - } - l = select_literal(); - } - SASSERT(inconsistent() || !is_unsat()); - return l; - } - - void compute_wnb() { - init_wnb(); - TRACE("sat", display_lookahead(tout); ); - unsigned base = 2; - bool change = true; - bool first = true; - while (change && !inconsistent()) { - change = false; - for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { - checkpoint(); - literal lit = m_lookahead[i].m_lit; - if (is_fixed_at(lit, c_fixed_truth)) continue; - unsigned level = base + m_lookahead[i].m_offset; - if (m_stamp[lit.var()] >= level) { - continue; - } - if (scope_lvl() == 1) { - IF_VERBOSE(3, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); - } - TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); - reset_wnb(lit); - push_lookahead1(lit, level); - if (!first) do_double(lit, base); - bool unsat = inconsistent(); - pop_lookahead1(lit); - if (unsat) { - TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); - reset_wnb(); - assign(~lit); - propagate(); - init_wnb(); - change = true; - } - else { - update_wnb(lit, level); - } - SASSERT(inconsistent() || !is_unsat()); - } - if (c_fixed_truth - 2 * m_lookahead.size() < base) { - break; - } - if (first && !change) { - first = false; - change = true; - } - reset_wnb(); - init_wnb(); - // base += 2 * m_lookahead.size(); - } - reset_wnb(); - TRACE("sat", display_lookahead(tout); ); - } - - void init_wnb() { - TRACE("sat", tout << "init_wnb: " << m_qhead << "\n";); - m_qhead_lim.push_back(m_qhead); - m_trail_lim.push_back(m_trail.size()); - } - - void reset_wnb() { - m_qhead = m_qhead_lim.back(); - TRACE("sat", tout << "reset_wnb: " << m_qhead << "\n";); - unsigned old_sz = m_trail_lim.back(); - for (unsigned i = old_sz; i < m_trail.size(); ++i) { - set_undef(m_trail[i]); - } - m_trail.shrink(old_sz); - m_trail_lim.pop_back(); - m_qhead_lim.pop_back(); - } - - literal select_literal() { - literal l = null_literal; - float h = 0; - unsigned count = 1; - for (unsigned i = 0; i < m_lookahead.size(); ++i) { - literal lit = m_lookahead[i].m_lit; - if (lit.sign() || !is_undef(lit)) { - continue; - } - float diff1 = get_wnb(lit), diff2 = get_wnb(~lit); - float mixd = mix_diff(diff1, diff2); - - if (mixd == h) ++count; - if (mixd > h || (mixd == h && m_s.m_rand(count) == 0)) { - CTRACE("sat", l != null_literal, tout << lit << " mix diff: " << mixd << "\n";); - if (mixd > h) count = 1; - h = mixd; - l = diff1 < diff2 ? lit : ~lit; - } - } -// if (count > 1) std::cout << count << "\n"; - TRACE("sat", tout << "selected: " << l << "\n";); - return l; - } - + clause const& get_clause(watch_list::iterator it) const; + bool is_nary_propagation(clause const& c, literal l) const; + void propagate_clauses(literal l); + void propagate_binary(literal l); + void propagate(); + literal choose(); + void compute_wnb(); + void init_wnb(); + void reset_wnb(); + literal select_literal(); void set_wnb(literal l, float f) { m_lits[l.index()].m_wnb = f; } void inc_wnb(literal l, float f) { m_lits[l.index()].m_wnb += f; } float get_wnb(literal l) const { return m_lits[l.index()].m_wnb; } - void reset_wnb(literal l) { - m_weighted_new_binaries = 0; - - // inherit propagation effect from parent. - literal p = get_parent(l); - set_wnb(l, p == null_literal ? 0 : get_wnb(p)); - } - - bool check_autarky(literal l, unsigned level) { - return false; - // no propagations are allowed to reduce clauses. - clause_vector::const_iterator it = m_full_watches[l.index()].begin(); - clause_vector::const_iterator end = m_full_watches[l.index()].end(); - for (; it != end; ++it) { - clause& c = *(*it); - unsigned sz = c.size(); - bool found = false; - for (unsigned i = 0; !found && i < sz; ++i) { - found = is_true(c[i]); - if (found) { - TRACE("sat", tout << c[i] << " is true in " << c << "\n";); - } - } - IF_VERBOSE(2, verbose_stream() << "skip autarky " << l << "\n";); - if (!found) return false; - } - // - // bail out if there is a pending binary propagation. - // In general, we would have to check, recursively that - // a binary propagation does not create reduced clauses. - // - literal_vector const& lits = m_binary[l.index()]; - TRACE("sat", tout << l << ": " << lits << "\n";); - for (unsigned i = 0; i < lits.size(); ++i) { - literal l2 = lits[i]; - if (is_true(l2)) continue; - SASSERT(!is_false(l2)); - return false; - } - - return true; - } - - void update_wnb(literal l, unsigned level) { - if (m_weighted_new_binaries == 0) { - if (!check_autarky(l, level)) { - // skip - } - else if (get_wnb(l) == 0) { - ++m_stats.m_autarky_propagations; - IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); - - TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] - << " " - << (!m_binary[l.index()].empty() || !m_full_watches[l.index()].empty()) << "\n";); - reset_wnb(); - assign(l); - propagate(); - init_wnb(); - } - else { - ++m_stats.m_autarky_equivalences; - // l => p is known, but p => l is possibly not. - // add p => l. - // justification: any consequence of l - // that is not a consequence of p does not - // reduce the clauses. - literal p = get_parent(l); - SASSERT(p != null_literal); - if (m_stamp[p.var()] > m_stamp[l.var()]) { - TRACE("sat", tout << "equivalence " << l << " == " << p << "\n"; display(tout);); - IF_VERBOSE(1, verbose_stream() << "(sat.lookahead equivalence " << l << " == " << p << ")\n";); - add_binary(~l, p); - set_level(l, p); - } - } - } - else { - inc_wnb(l, m_weighted_new_binaries); - } - } - + void reset_wnb(literal l); + bool check_autarky(literal l, unsigned level); + void update_wnb(literal l, unsigned level); bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; } void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } bool dl_no_overflow(unsigned base) const { return base + 2 * m_lookahead.size() * static_cast(m_config.m_dl_max_iterations + 1) < c_fixed_truth; } @@ -1629,217 +405,25 @@ namespace sat { return is_fixed(lit) && (!is_false(lit) || m_stamp[lit.var()] >= level); } - void do_double(literal l, unsigned& base) { - if (!inconsistent() && scope_lvl() > 1 && dl_enabled(l)) { - if (get_wnb(l) > m_delta_trigger) { - if (dl_no_overflow(base)) { - ++m_stats.m_double_lookahead_rounds; - double_look(l, base); - m_delta_trigger = get_wnb(l); - dl_disable(l); - } - } - else { - m_delta_trigger *= m_config.m_delta_rho; - } - } - } - - void double_look(literal l, unsigned& base) { - SASSERT(!inconsistent()); - SASSERT(dl_no_overflow(base)); - unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); - scoped_level _sl(*this, dl_truth); - IF_VERBOSE(2, verbose_stream() << "double: " << l << "\n";); - init_wnb(); - assign(l); - propagate(); - bool change = true; - unsigned num_iterations = 0; - while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { - change = false; - num_iterations++; - base += 2*m_lookahead.size(); - for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { - literal lit = m_lookahead[i].m_lit; - if (is_fixed_at(lit, dl_truth)) continue; - if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { - TRACE("sat", tout << "unit: " << ~lit << "\n";); - ++m_stats.m_double_lookahead_propagations; - SASSERT(m_level == dl_truth); - reset_wnb(); - assign(~lit); - propagate(); - change = true; - init_wnb(); - } - } - SASSERT(dl_truth - 2 * m_lookahead.size() > base); - } - reset_wnb(); - SASSERT(m_level == dl_truth); - base = dl_truth; - } - + void do_double(literal l, unsigned& base); + void double_look(literal l, unsigned& base); void set_conflict() { TRACE("sat", tout << "conflict\n";); m_inconsistent = true; } bool inconsistent() { return m_inconsistent; } unsigned scope_lvl() const { return m_trail_lim.size(); } - void validate_assign(literal l) { - if (m_s.m_config.m_drat && m_search_mode == lookahead_mode::searching) { - m_assumptions.push_back(l); - m_drat.add(m_assumptions); - m_assumptions.pop_back(); - } - } - - void assign(literal l) { - SASSERT(m_level > 0); - if (is_undef(l)) { - TRACE("sat", tout << "assign: " << l << " @ " << m_level << " " << m_trail_lim.size() << " " << m_search_mode << "\n";); - set_true(l); - m_trail.push_back(l); - if (m_search_mode == lookahead_mode::searching) { - m_stats.m_propagations++; - TRACE("sat", tout << "removing free var v" << l.var() << "\n";); - m_freevars.remove(l.var()); - validate_assign(l); - } - } - else if (is_false(l)) { - TRACE("sat", tout << "conflict: " << l << " @ " << m_level << " " << m_search_mode << "\n";); - SASSERT(!is_true(l)); - validate_assign(l); - set_conflict(); - } - } - - void propagated(literal l) { - assign(l); - switch (m_search_mode) { - case lookahead_mode::searching: - break; - case lookahead_mode::lookahead1: - m_wstack.push_back(l); - break; - case lookahead_mode::lookahead2: - break; - } - } - - bool backtrack(literal_vector& trail) { - while (inconsistent()) { - if (trail.empty()) return false; - pop(); - flip_prefix(); - assign(~trail.back()); - trail.pop_back(); - propagate(); - } - return true; - } - - lbool search() { - m_model.reset(); - scoped_level _sl(*this, c_fixed_truth); - literal_vector trail; - m_search_mode = lookahead_mode::searching; - while (true) { - TRACE("sat", display(tout);); - inc_istamp(); - checkpoint(); - if (inconsistent()) { - if (!backtrack(trail)) return l_false; - continue; - } - literal l = choose(); - if (inconsistent()) { - if (!backtrack(trail)) return l_false; - continue; - } - if (l == null_literal) { - return l_true; - } - TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); - ++m_stats.m_decisions; - IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(m_prefix, m_trail_lim.size()) << ": " << l << " " << m_trail.size() << "\n";); - push(l, c_fixed_truth); - trail.push_back(l); - SASSERT(inconsistent() || !is_unsat()); - } - } - - void init_model() { - m_model.reset(); - for (unsigned i = 0; i < m_num_vars; ++i) { - lbool val; - literal lit(i, false); - if (is_undef(lit)) { - val = l_undef; - } - if (is_true(lit)) { - val = l_true; - } - else { - val = l_false; - } - m_model.push_back(val); - } - } - - std::ostream& display_binary(std::ostream& out) const { - for (unsigned i = 0; i < m_binary.size(); ++i) { - literal_vector const& lits = m_binary[i]; - if (!lits.empty()) { - out << to_literal(i) << " -> " << lits << "\n"; - } - } - return out; - } - - std::ostream& display_clauses(std::ostream& out) const { - for (unsigned i = 0; i < m_clauses.size(); ++i) { - out << *m_clauses[i] << "\n"; - } - return out; - } - - std::ostream& display_values(std::ostream& out) const { - for (unsigned i = 0; i < m_trail.size(); ++i) { - literal l = m_trail[i]; - out << l << "\n"; - } - return out; - } - - std::ostream& display_lookahead(std::ostream& out) const { - for (unsigned i = 0; i < m_lookahead.size(); ++i) { - literal lit = m_lookahead[i].m_lit; - unsigned offset = m_lookahead[i].m_offset; - out << lit << "\toffset: " << offset; - out << (is_undef(lit)?" undef": (is_true(lit) ? " true": " false")); - out << " wnb: " << get_wnb(lit); - out << "\n"; - } - return out; - } - - void init_search() { - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); - } - - void checkpoint() { - if (!m_rlimit.inc()) { - throw solver_exception(Z3_CANCELED_MSG); - } - if (memory::get_allocation_size() > m_s.m_config.m_max_memory) { - throw solver_exception(Z3_MAX_MEMORY_MSG); - } - } - + void validate_assign(literal l); + void assign(literal l); + void propagated(literal l); + bool backtrack(literal_vector& trail); + lbool search(); + void init_model(); + std::ostream& display_binary(std::ostream& out) const; + std::ostream& display_clauses(std::ostream& out) const; + std::ostream& display_values(std::ostream& out) const; + std::ostream& display_lookahead(std::ostream& out) const; + void init_search(); + void checkpoint(); public: lookahead(solver& s) : @@ -1857,12 +441,14 @@ namespace sat { m_s.rlimit().pop_child(); } + lbool check() { init_search(); return search(); } literal select_lookahead(bool_var_vector const& vars) { + scoped_ext _sext(*this); m_search_mode = lookahead_mode::searching; scoped_level _sl(*this, c_fixed_truth); init(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e45373b5c..1f8f3aa19 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -779,14 +779,14 @@ namespace sat { case watched::EXT_CONSTRAINT: SASSERT(m_ext); m_ext->propagate(l, it->get_ext_constraint_idx(), keep); - if (keep) { - *it2 = *it; - it2++; - } if (m_inconsistent) { CONFLICT_CLEANUP(); return false; } + if (keep) { + *it2 = *it; + it2++; + } break; default: UNREACHABLE(); diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 0ea82c6ac..977799366 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -124,6 +124,7 @@ namespace sat { }; class solver; + class lookahead; class clause; class clause_wrapper; class integrity_checker; diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 03eaf2798..254dba5b6 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -103,7 +103,7 @@ namespace sat { } bool is_ext_constraint() const { return get_kind() == EXT_CONSTRAINT; } - ext_constraint_idx get_ext_constraint_idx() const { SASSERT(is_ext_constraint()); return m_val2; } + ext_constraint_idx get_ext_constraint_idx() const { SASSERT(is_ext_constraint()); return m_val1; } bool operator==(watched const & w) const { return m_val1 == w.m_val1 && m_val2 == w.m_val2; } bool operator!=(watched const & w) const { return !operator==(w); } From 964102726d095b9564b43db6cb6f6ebb0d821247 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Jun 2017 18:24:58 -0700 Subject: [PATCH 0158/1283] lookahead on cardinality extension Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 1080 +++++++++++++++++++++---------------- src/sat/sat_lookahead.h | 151 +----- 2 files changed, 632 insertions(+), 599 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 597efa49a..fd6860ff3 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -727,269 +727,279 @@ namespace sat { } - // ------------------------------------ - // clause management + // ------------------------------------ + // clause management void lookahead::attach_clause(clause& c) { - if (c.size() == 3) { - attach_ternary(c[0], c[1], c[2]); - } - else { - literal block_lit = c[c.size() >> 2]; - clause_offset cls_off = m_cls_allocator.get_offset(&c); - m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); - m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); - SASSERT(is_undef(c[0])); - SASSERT(is_undef(c[1])); - } + if (c.size() == 3) { + attach_ternary(c[0], c[1], c[2]); } - - void lookahead::detach_clause(clause& c) { + else { + literal block_lit = c[c.size() >> 2]; clause_offset cls_off = m_cls_allocator.get_offset(&c); - m_retired_clauses.push_back(&c); - erase_clause_watch(get_wlist(~c[0]), cls_off); - erase_clause_watch(get_wlist(~c[1]), cls_off); + m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); + m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); + SASSERT(is_undef(c[0])); + SASSERT(is_undef(c[1])); } + } - void lookahead::del_clauses() { - clause * const* end = m_clauses.end(); - clause * const * it = m_clauses.begin(); - for (; it != end; ++it) { - m_cls_allocator.del_clause(*it); - } - } + void lookahead::detach_clause(clause& c) { + clause_offset cls_off = m_cls_allocator.get_offset(&c); + m_retired_clauses.push_back(&c); + erase_clause_watch(get_wlist(~c[0]), cls_off); + erase_clause_watch(get_wlist(~c[1]), cls_off); + } - void lookahead::detach_ternary(literal l1, literal l2, literal l3) { - ++m_stats.m_del_ternary; - m_retired_ternary.push_back(ternary(l1, l2, l3)); - // implicitly erased: erase_ternary_watch(get_wlist(~l1), l2, l3); - erase_ternary_watch(get_wlist(~l2), l1, l3); - erase_ternary_watch(get_wlist(~l3), l1, l2); + void lookahead::del_clauses() { + clause * const* end = m_clauses.end(); + clause * const * it = m_clauses.begin(); + for (; it != end; ++it) { + m_cls_allocator.del_clause(*it); } + } + + void lookahead::detach_ternary(literal l1, literal l2, literal l3) { + ++m_stats.m_del_ternary; + m_retired_ternary.push_back(ternary(l1, l2, l3)); + // implicitly erased: erase_ternary_watch(get_wlist(~l1), l2, l3); + erase_ternary_watch(get_wlist(~l2), l1, l3); + erase_ternary_watch(get_wlist(~l3), l1, l2); + } void lookahead::attach_ternary(ternary const& t) { - attach_ternary(t.m_u, t.m_v, t.m_w); - } + attach_ternary(t.m_u, t.m_v, t.m_w); + } void lookahead::attach_ternary(literal l1, literal l2, literal l3) { - ++m_stats.m_add_ternary; - TRACE("sat", tout << l1 << " " << l2 << " " << l3 << "\n";); - m_watches[(~l1).index()].push_back(watched(l2, l3)); - m_watches[(~l2).index()].push_back(watched(l1, l3)); - m_watches[(~l3).index()].push_back(watched(l1, l2)); - } + ++m_stats.m_add_ternary; + TRACE("sat", tout << l1 << " " << l2 << " " << l3 << "\n";); + m_watches[(~l1).index()].push_back(watched(l2, l3)); + m_watches[(~l2).index()].push_back(watched(l1, l3)); + m_watches[(~l3).index()].push_back(watched(l1, l2)); + } - // ------------------------------------ - // initialization + // ------------------------------------ + // initialization void lookahead::init_var(bool_var v) { - m_binary.push_back(literal_vector()); - m_binary.push_back(literal_vector()); - m_watches.push_back(watch_list()); - m_watches.push_back(watch_list()); - m_full_watches.push_back(clause_vector()); - m_full_watches.push_back(clause_vector()); - m_bstamp.push_back(0); - m_bstamp.push_back(0); - m_stamp.push_back(0); - m_dfs.push_back(dfs_info()); - m_dfs.push_back(dfs_info()); - m_lits.push_back(lit_info()); - m_lits.push_back(lit_info()); - m_rating.push_back(0); - m_vprefix.push_back(prefix()); - if (!m_s.was_eliminated(v)) - m_freevars.insert(v); - } + m_binary.push_back(literal_vector()); + m_binary.push_back(literal_vector()); + m_watches.push_back(watch_list()); + m_watches.push_back(watch_list()); + m_full_watches.push_back(clause_vector()); + m_full_watches.push_back(clause_vector()); + m_bstamp.push_back(0); + m_bstamp.push_back(0); + m_stamp.push_back(0); + m_dfs.push_back(dfs_info()); + m_dfs.push_back(dfs_info()); + m_lits.push_back(lit_info()); + m_lits.push_back(lit_info()); + m_rating.push_back(0); + m_vprefix.push_back(prefix()); + if (!m_s.was_eliminated(v)) + m_freevars.insert(v); + } void lookahead::init() { - m_delta_trigger = m_num_vars/10; - m_config.m_dl_success = 0.8; - m_inconsistent = false; - m_qhead = 0; - m_bstamp_id = 0; + m_delta_trigger = m_num_vars/10; + m_config.m_dl_success = 0.8; + m_inconsistent = false; + m_qhead = 0; + m_bstamp_id = 0; - for (unsigned i = 0; i < m_num_vars; ++i) { - init_var(i); - } - - // copy binary clauses - unsigned sz = m_s.m_watches.size(); - for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { - literal l = ~to_literal(l_idx); - watch_list const & wlist = m_s.m_watches[l_idx]; - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_non_learned_clause()) - continue; - literal l2 = it->get_literal(); - SASSERT(!m_s.was_eliminated(l.var())); - SASSERT(!m_s.was_eliminated(l2.var())); - if (l.index() < l2.index()) - add_binary(l, l2); - } - } - - copy_clauses(m_s.m_clauses); - copy_clauses(m_s.m_learned); - - // copy units - unsigned trail_sz = m_s.init_trail_size(); - for (unsigned i = 0; i < trail_sz; ++i) { - literal l = m_s.m_trail[i]; - if (!m_s.was_eliminated(l.var())) { - if (m_s.m_config.m_drat) m_drat.add(l, false); - assign(l); - } - } - propagate(); - m_qhead = m_trail.size(); - TRACE("sat", m_s.display(tout); display(tout);); + for (unsigned i = 0; i < m_num_vars; ++i) { + init_var(i); } + // copy binary clauses + unsigned sz = m_s.m_watches.size(); + for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { + literal l = ~to_literal(l_idx); + watch_list const & wlist = m_s.m_watches[l_idx]; + watch_list::const_iterator it = wlist.begin(); + watch_list::const_iterator end = wlist.end(); + for (; it != end; ++it) { + if (!it->is_binary_non_learned_clause()) + continue; + literal l2 = it->get_literal(); + SASSERT(!m_s.was_eliminated(l.var())); + SASSERT(!m_s.was_eliminated(l2.var())); + if (l.index() < l2.index()) + add_binary(l, l2); + } + } + + copy_clauses(m_s.m_clauses); + copy_clauses(m_s.m_learned); + + // copy units + unsigned trail_sz = m_s.init_trail_size(); + for (unsigned i = 0; i < trail_sz; ++i) { + literal l = m_s.m_trail[i]; + if (!m_s.was_eliminated(l.var())) { + if (m_s.m_config.m_drat) m_drat.add(l, false); + assign(l); + } + } + + // copy externals: + for (unsigned idx = 0; idx < m_watches.size(); ++idx) { + watch_list const& wl = m_watches[idx]; + for (watched const& w : wl) { + if (w.is_ext_constraint()) { + m_watches[idx].push_back(w); + } + } + } + propagate(); + m_qhead = m_trail.size(); + TRACE("sat", m_s.display(tout); display(tout);); + } + void lookahead::copy_clauses(clause_vector const& clauses) { - // copy clauses - clause_vector::const_iterator it = clauses.begin(); - clause_vector::const_iterator end = clauses.end(); - for (; it != end; ++it) { - clause& c = *(*it); - if (c.was_removed()) continue; - clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); - m_clauses.push_back(c1); - attach_clause(*c1); - for (unsigned i = 0; i < c.size(); ++i) { - m_full_watches[(~c[i]).index()].push_back(c1); - SASSERT(!m_s.was_eliminated(c[i].var())); - } - if (m_s.m_config.m_drat) m_drat.add(c, false); + // copy clauses + clause_vector::const_iterator it = clauses.begin(); + clause_vector::const_iterator end = clauses.end(); + for (; it != end; ++it) { + clause& c = *(*it); + if (c.was_removed()) continue; + clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); + m_clauses.push_back(c1); + attach_clause(*c1); + for (unsigned i = 0; i < c.size(); ++i) { + m_full_watches[(~c[i]).index()].push_back(c1); + SASSERT(!m_s.was_eliminated(c[i].var())); } + if (m_s.m_config.m_drat) m_drat.add(c, false); } + } // ------------------------------------ // search - void lookahead::push(literal lit, unsigned level) { - SASSERT(m_search_mode == lookahead_mode::searching); - m_binary_trail_lim.push_back(m_binary_trail.size()); - m_trail_lim.push_back(m_trail.size()); - m_num_tc1_lim.push_back(m_num_tc1); - m_retired_clause_lim.push_back(m_retired_clauses.size()); - m_retired_ternary_lim.push_back(m_retired_ternary.size()); - m_qhead_lim.push_back(m_qhead); - scoped_level _sl(*this, level); - m_assumptions.push_back(~lit); - assign(lit); - propagate(); - } + void lookahead::push(literal lit, unsigned level) { + SASSERT(m_search_mode == lookahead_mode::searching); + m_binary_trail_lim.push_back(m_binary_trail.size()); + m_trail_lim.push_back(m_trail.size()); + m_num_tc1_lim.push_back(m_num_tc1); + m_retired_clause_lim.push_back(m_retired_clauses.size()); + m_retired_ternary_lim.push_back(m_retired_ternary.size()); + m_qhead_lim.push_back(m_qhead); + scoped_level _sl(*this, level); + m_assumptions.push_back(~lit); + assign(lit); + propagate(); + } void lookahead::pop() { - if (m_assumptions.empty()) IF_VERBOSE(0, verbose_stream() << "empty pop\n";); - m_assumptions.pop_back(); - m_inconsistent = false; - SASSERT(m_search_mode == lookahead_mode::searching); + if (m_assumptions.empty()) IF_VERBOSE(0, verbose_stream() << "empty pop\n";); + m_assumptions.pop_back(); + m_inconsistent = false; + SASSERT(m_search_mode == lookahead_mode::searching); - // m_freevars only for main search - // undo assignments - unsigned old_sz = m_trail_lim.back(); - for (unsigned i = m_trail.size(); i > old_sz; ) { - --i; - literal l = m_trail[i]; - set_undef(l); - TRACE("sat", tout << "inserting free var v" << l.var() << "\n";); - m_freevars.insert(l.var()); - } - m_trail.shrink(old_sz); // reset assignment. - m_trail_lim.pop_back(); - - m_num_tc1 = m_num_tc1_lim.back(); - m_num_tc1_lim.pop_back(); - - // unretire clauses - old_sz = m_retired_clause_lim.back(); - for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { - attach_clause(*m_retired_clauses[i]); - } - m_retired_clauses.resize(old_sz); - m_retired_clause_lim.pop_back(); - - old_sz = m_retired_ternary_lim.back(); - for (unsigned i = old_sz; i < m_retired_ternary.size(); ++i) { - attach_ternary(m_retired_ternary[i]); - } - m_retired_ternary.shrink(old_sz); - m_retired_ternary_lim.pop_back(); - - // remove local binary clauses - old_sz = m_binary_trail_lim.back(); - for (unsigned i = m_binary_trail.size(); i > old_sz; ) { - del_binary(m_binary_trail[--i]); - } - m_binary_trail.shrink(old_sz); - m_binary_trail_lim.pop_back(); - - // reset propagation queue - m_qhead = m_qhead_lim.back(); - m_qhead_lim.pop_back(); - } - - bool lookahead::push_lookahead2(literal lit, unsigned level) { - scoped_level _sl(*this, level); - SASSERT(m_search_mode == lookahead_mode::lookahead1); - m_search_mode = lookahead_mode::lookahead2; - assign(lit); - propagate(); - bool unsat = inconsistent(); - SASSERT(m_search_mode == lookahead_mode::lookahead2); - m_search_mode = lookahead_mode::lookahead1; - m_inconsistent = false; - return unsat; + // m_freevars only for main search + // undo assignments + unsigned old_sz = m_trail_lim.back(); + for (unsigned i = m_trail.size(); i > old_sz; ) { + --i; + literal l = m_trail[i]; + set_undef(l); + TRACE("sat", tout << "inserting free var v" << l.var() << "\n";); + m_freevars.insert(l.var()); } + m_trail.shrink(old_sz); // reset assignment. + m_trail_lim.pop_back(); + + m_num_tc1 = m_num_tc1_lim.back(); + m_num_tc1_lim.pop_back(); + + // unretire clauses + old_sz = m_retired_clause_lim.back(); + for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { + attach_clause(*m_retired_clauses[i]); + } + m_retired_clauses.resize(old_sz); + m_retired_clause_lim.pop_back(); + + old_sz = m_retired_ternary_lim.back(); + for (unsigned i = old_sz; i < m_retired_ternary.size(); ++i) { + attach_ternary(m_retired_ternary[i]); + } + m_retired_ternary.shrink(old_sz); + m_retired_ternary_lim.pop_back(); + + // remove local binary clauses + old_sz = m_binary_trail_lim.back(); + for (unsigned i = m_binary_trail.size(); i > old_sz; ) { + del_binary(m_binary_trail[--i]); + } + m_binary_trail.shrink(old_sz); + m_binary_trail_lim.pop_back(); + + // reset propagation queue + m_qhead = m_qhead_lim.back(); + m_qhead_lim.pop_back(); + } + + bool lookahead::push_lookahead2(literal lit, unsigned level) { + scoped_level _sl(*this, level); + SASSERT(m_search_mode == lookahead_mode::lookahead1); + m_search_mode = lookahead_mode::lookahead2; + assign(lit); + propagate(); + bool unsat = inconsistent(); + SASSERT(m_search_mode == lookahead_mode::lookahead2); + m_search_mode = lookahead_mode::lookahead1; + m_inconsistent = false; + return unsat; + } void lookahead::push_lookahead1(literal lit, unsigned level) { - SASSERT(m_search_mode == lookahead_mode::searching); - m_search_mode = lookahead_mode::lookahead1; - scoped_level _sl(*this, level); - assign(lit); - propagate(); - } + SASSERT(m_search_mode == lookahead_mode::searching); + m_search_mode = lookahead_mode::lookahead1; + scoped_level _sl(*this, level); + assign(lit); + propagate(); + } void lookahead::pop_lookahead1(literal lit) { - bool unsat = inconsistent(); - SASSERT(m_search_mode == lookahead_mode::lookahead1); - m_inconsistent = false; - m_search_mode = lookahead_mode::searching; - // convert windfalls to binary clauses. - if (!unsat) { - literal nlit = ~lit; + bool unsat = inconsistent(); + SASSERT(m_search_mode == lookahead_mode::lookahead1); + m_inconsistent = false; + m_search_mode = lookahead_mode::searching; + // convert windfalls to binary clauses. + if (!unsat) { + literal nlit = ~lit; - for (unsigned i = 0; i < m_wstack.size(); ++i) { - literal l2 = m_wstack[i]; - //update_prefix(~lit); - //update_prefix(m_wstack[i]); - TRACE("sat", tout << "windfall: " << nlit << " " << l2 << "\n";); - // if we use try_add_binary, then this may produce new assignments - // these assignments get put on m_trail, and they are cleared by - // reset_wnb. We would need to distinguish the trail that comes - // from lookahead levels and the main search level for this to work. - add_binary(nlit, l2); - } - m_stats.m_windfall_binaries += m_wstack.size(); + for (unsigned i = 0; i < m_wstack.size(); ++i) { + literal l2 = m_wstack[i]; + //update_prefix(~lit); + //update_prefix(m_wstack[i]); + TRACE("sat", tout << "windfall: " << nlit << " " << l2 << "\n";); + // if we use try_add_binary, then this may produce new assignments + // these assignments get put on m_trail, and they are cleared by + // reset_wnb. We would need to distinguish the trail that comes + // from lookahead levels and the main search level for this to work. + add_binary(nlit, l2); } - m_wstack.reset(); + m_stats.m_windfall_binaries += m_wstack.size(); } + m_wstack.reset(); + } - clause const& lookahead::get_clause(watch_list::iterator it) const { - clause_offset cls_off = it->get_clause_offset(); - return *(m_cls_allocator.get_clause(cls_off)); - } + clause const& lookahead::get_clause(watch_list::iterator it) const { + clause_offset cls_off = it->get_clause_offset(); + return *(m_cls_allocator.get_clause(cls_off)); + } bool lookahead::is_nary_propagation(clause const& c, literal l) const { - bool r = c.size() > 2 && ((c[0] == l && is_false(c[1])) || (c[1] == l && is_false(c[0]))); - DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(is_false(c[j]));); - return r; - } + bool r = c.size() > 2 && ((c[0] == l && is_false(c[1])) || (c[1] == l && is_false(c[0]))); + DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(is_false(c[j]));); + return r; + } // @@ -1285,296 +1295,293 @@ namespace sat { void lookahead::reset_wnb(literal l) { - m_weighted_new_binaries = 0; + m_weighted_new_binaries = 0; - // inherit propagation effect from parent. - literal p = get_parent(l); - set_wnb(l, p == null_literal ? 0 : get_wnb(p)); - } + // inherit propagation effect from parent. + literal p = get_parent(l); + set_wnb(l, p == null_literal ? 0 : get_wnb(p)); + } bool lookahead::check_autarky(literal l, unsigned level) { - return false; - // no propagations are allowed to reduce clauses. - clause_vector::const_iterator it = m_full_watches[l.index()].begin(); - clause_vector::const_iterator end = m_full_watches[l.index()].end(); - for (; it != end; ++it) { - clause& c = *(*it); - unsigned sz = c.size(); - bool found = false; - for (unsigned i = 0; !found && i < sz; ++i) { - found = is_true(c[i]); - if (found) { - TRACE("sat", tout << c[i] << " is true in " << c << "\n";); - } + return false; + // no propagations are allowed to reduce clauses. + clause_vector::const_iterator it = m_full_watches[l.index()].begin(); + clause_vector::const_iterator end = m_full_watches[l.index()].end(); + for (; it != end; ++it) { + clause& c = *(*it); + unsigned sz = c.size(); + bool found = false; + for (unsigned i = 0; !found && i < sz; ++i) { + found = is_true(c[i]); + if (found) { + TRACE("sat", tout << c[i] << " is true in " << c << "\n";); } - IF_VERBOSE(2, verbose_stream() << "skip autarky " << l << "\n";); - if (!found) return false; } - // - // bail out if there is a pending binary propagation. - // In general, we would have to check, recursively that - // a binary propagation does not create reduced clauses. - // - literal_vector const& lits = m_binary[l.index()]; - TRACE("sat", tout << l << ": " << lits << "\n";); - for (unsigned i = 0; i < lits.size(); ++i) { - literal l2 = lits[i]; - if (is_true(l2)) continue; - SASSERT(!is_false(l2)); - return false; - } - - return true; + IF_VERBOSE(2, verbose_stream() << "skip autarky " << l << "\n";); + if (!found) return false; } + // + // bail out if there is a pending binary propagation. + // In general, we would have to check, recursively that + // a binary propagation does not create reduced clauses. + // + literal_vector const& lits = m_binary[l.index()]; + TRACE("sat", tout << l << ": " << lits << "\n";); + for (unsigned i = 0; i < lits.size(); ++i) { + literal l2 = lits[i]; + if (is_true(l2)) continue; + SASSERT(!is_false(l2)); + return false; + } + + return true; + } void lookahead::update_wnb(literal l, unsigned level) { - if (m_weighted_new_binaries == 0) { - if (!check_autarky(l, level)) { - // skip - } - else if (get_wnb(l) == 0) { - ++m_stats.m_autarky_propagations; - IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); + if (m_weighted_new_binaries == 0) { + if (!check_autarky(l, level)) { + // skip + } + else if (get_wnb(l) == 0) { + ++m_stats.m_autarky_propagations; + IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); - TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] - << " " - << (!m_binary[l.index()].empty() || !m_full_watches[l.index()].empty()) << "\n";); - reset_wnb(); - assign(l); - propagate(); - init_wnb(); + TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] + << " " + << (!m_binary[l.index()].empty() || !m_full_watches[l.index()].empty()) << "\n";); + reset_wnb(); + assign(l); + propagate(); + init_wnb(); + } + else { + ++m_stats.m_autarky_equivalences; + // l => p is known, but p => l is possibly not. + // add p => l. + // justification: any consequence of l + // that is not a consequence of p does not + // reduce the clauses. + literal p = get_parent(l); + SASSERT(p != null_literal); + if (m_stamp[p.var()] > m_stamp[l.var()]) { + TRACE("sat", tout << "equivalence " << l << " == " << p << "\n"; display(tout);); + IF_VERBOSE(1, verbose_stream() << "(sat.lookahead equivalence " << l << " == " << p << ")\n";); + add_binary(~l, p); + set_level(l, p); } - else { - ++m_stats.m_autarky_equivalences; - // l => p is known, but p => l is possibly not. - // add p => l. - // justification: any consequence of l - // that is not a consequence of p does not - // reduce the clauses. - literal p = get_parent(l); - SASSERT(p != null_literal); - if (m_stamp[p.var()] > m_stamp[l.var()]) { - TRACE("sat", tout << "equivalence " << l << " == " << p << "\n"; display(tout);); - IF_VERBOSE(1, verbose_stream() << "(sat.lookahead equivalence " << l << " == " << p << ")\n";); - add_binary(~l, p); - set_level(l, p); - } + } + } + else { + inc_wnb(l, m_weighted_new_binaries); + } + } + + void lookahead::do_double(literal l, unsigned& base) { + if (!inconsistent() && scope_lvl() > 1 && dl_enabled(l)) { + if (get_wnb(l) > m_delta_trigger) { + if (dl_no_overflow(base)) { + ++m_stats.m_double_lookahead_rounds; + double_look(l, base); + m_delta_trigger = get_wnb(l); + dl_disable(l); } } else { - inc_wnb(l, m_weighted_new_binaries); - } - } - - void lookahead::do_double(literal l, unsigned& base) { - if (!inconsistent() && scope_lvl() > 1 && dl_enabled(l)) { - if (get_wnb(l) > m_delta_trigger) { - if (dl_no_overflow(base)) { - ++m_stats.m_double_lookahead_rounds; - double_look(l, base); - m_delta_trigger = get_wnb(l); - dl_disable(l); - } - } - else { - m_delta_trigger *= m_config.m_delta_rho; - } + m_delta_trigger *= m_config.m_delta_rho; } } + } void lookahead::double_look(literal l, unsigned& base) { - SASSERT(!inconsistent()); - SASSERT(dl_no_overflow(base)); - unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); - scoped_level _sl(*this, dl_truth); - IF_VERBOSE(2, verbose_stream() << "double: " << l << "\n";); - init_wnb(); - assign(l); - propagate(); - bool change = true; - unsigned num_iterations = 0; - while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { - change = false; - num_iterations++; - base += 2*m_lookahead.size(); - for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { - literal lit = m_lookahead[i].m_lit; - if (is_fixed_at(lit, dl_truth)) continue; - if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { - TRACE("sat", tout << "unit: " << ~lit << "\n";); - ++m_stats.m_double_lookahead_propagations; - SASSERT(m_level == dl_truth); - reset_wnb(); - assign(~lit); - propagate(); - change = true; - init_wnb(); - } + SASSERT(!inconsistent()); + SASSERT(dl_no_overflow(base)); + unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); + scoped_level _sl(*this, dl_truth); + IF_VERBOSE(2, verbose_stream() << "double: " << l << "\n";); + init_wnb(); + assign(l); + propagate(); + bool change = true; + unsigned num_iterations = 0; + while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { + change = false; + num_iterations++; + base += 2*m_lookahead.size(); + for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + if (is_fixed_at(lit, dl_truth)) continue; + if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { + TRACE("sat", tout << "unit: " << ~lit << "\n";); + ++m_stats.m_double_lookahead_propagations; + SASSERT(m_level == dl_truth); + reset_wnb(); + assign(~lit); + propagate(); + change = true; + init_wnb(); } - SASSERT(dl_truth - 2 * m_lookahead.size() > base); } - reset_wnb(); - SASSERT(m_level == dl_truth); - base = dl_truth; + SASSERT(dl_truth - 2 * m_lookahead.size() > base); } + reset_wnb(); + SASSERT(m_level == dl_truth); + base = dl_truth; + } void lookahead::validate_assign(literal l) { - if (m_s.m_config.m_drat && m_search_mode == lookahead_mode::searching) { - m_assumptions.push_back(l); - m_drat.add(m_assumptions); - m_assumptions.pop_back(); - } + if (m_s.m_config.m_drat && m_search_mode == lookahead_mode::searching) { + m_assumptions.push_back(l); + m_drat.add(m_assumptions); + m_assumptions.pop_back(); } + } void lookahead::assign(literal l) { - SASSERT(m_level > 0); - if (is_undef(l)) { - TRACE("sat", tout << "assign: " << l << " @ " << m_level << " " << m_trail_lim.size() << " " << m_search_mode << "\n";); - set_true(l); - m_trail.push_back(l); - if (m_search_mode == lookahead_mode::searching) { - m_stats.m_propagations++; - TRACE("sat", tout << "removing free var v" << l.var() << "\n";); - m_freevars.remove(l.var()); - validate_assign(l); - } - } - else if (is_false(l)) { - TRACE("sat", tout << "conflict: " << l << " @ " << m_level << " " << m_search_mode << "\n";); - SASSERT(!is_true(l)); - validate_assign(l); - set_conflict(); + SASSERT(m_level > 0); + if (is_undef(l)) { + TRACE("sat", tout << "assign: " << l << " @ " << m_level << " " << m_trail_lim.size() << " " << m_search_mode << "\n";); + set_true(l); + m_trail.push_back(l); + if (m_search_mode == lookahead_mode::searching) { + m_stats.m_propagations++; + TRACE("sat", tout << "removing free var v" << l.var() << "\n";); + m_freevars.remove(l.var()); + validate_assign(l); } } + else if (is_false(l)) { + TRACE("sat", tout << "conflict: " << l << " @ " << m_level << " " << m_search_mode << "\n";); + SASSERT(!is_true(l)); + validate_assign(l); + set_conflict(); + } + } void lookahead::propagated(literal l) { - assign(l); - switch (m_search_mode) { - case lookahead_mode::searching: - break; - case lookahead_mode::lookahead1: - m_wstack.push_back(l); - break; - case lookahead_mode::lookahead2: - break; - } + assign(l); + switch (m_search_mode) { + case lookahead_mode::searching: + break; + case lookahead_mode::lookahead1: + m_wstack.push_back(l); + break; + case lookahead_mode::lookahead2: + break; } + } - bool lookahead::backtrack(literal_vector& trail) { - while (inconsistent()) { - if (trail.empty()) return false; - pop(); - flip_prefix(); - assign(~trail.back()); - trail.pop_back(); - propagate(); - } - return true; + bool lookahead::backtrack(literal_vector& trail) { + while (inconsistent()) { + if (trail.empty()) return false; + pop(); + flip_prefix(); + assign(~trail.back()); + trail.pop_back(); + propagate(); } + return true; + } - lbool lookahead::search() { - m_model.reset(); - scoped_level _sl(*this, c_fixed_truth); - literal_vector trail; - m_search_mode = lookahead_mode::searching; - while (true) { - TRACE("sat", display(tout);); - inc_istamp(); - checkpoint(); - if (inconsistent()) { - if (!backtrack(trail)) return l_false; - continue; - } - literal l = choose(); - if (inconsistent()) { - if (!backtrack(trail)) return l_false; - continue; - } - if (l == null_literal) { - return l_true; - } - TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); - ++m_stats.m_decisions; - IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(m_prefix, m_trail_lim.size()) << ": " << l << " " << m_trail.size() << "\n";); - push(l, c_fixed_truth); - trail.push_back(l); - SASSERT(inconsistent() || !is_unsat()); + lbool lookahead::search() { + m_model.reset(); + scoped_level _sl(*this, c_fixed_truth); + literal_vector trail; + m_search_mode = lookahead_mode::searching; + while (true) { + TRACE("sat", display(tout);); + inc_istamp(); + checkpoint(); + if (inconsistent()) { + if (!backtrack(trail)) return l_false; + continue; } + literal l = choose(); + if (inconsistent()) { + if (!backtrack(trail)) return l_false; + continue; + } + if (l == null_literal) { + return l_true; + } + TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); + ++m_stats.m_decisions; + IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(m_prefix, m_trail_lim.size()) << ": " << l << " " << m_trail.size() << "\n";); + push(l, c_fixed_truth); + trail.push_back(l); + SASSERT(inconsistent() || !is_unsat()); } + } - void lookahead::init_model() { - m_model.reset(); - for (unsigned i = 0; i < m_num_vars; ++i) { - lbool val; - literal lit(i, false); - if (is_undef(lit)) { - val = l_undef; - } - if (is_true(lit)) { - val = l_true; - } - else { - val = l_false; - } - m_model.push_back(val); + void lookahead::init_model() { + m_model.reset(); + for (unsigned i = 0; i < m_num_vars; ++i) { + lbool val; + literal lit(i, false); + if (is_undef(lit)) { + val = l_undef; } + if (is_true(lit)) { + val = l_true; + } + else { + val = l_false; + } + m_model.push_back(val); } + } std::ostream& lookahead::display_binary(std::ostream& out) const { - for (unsigned i = 0; i < m_binary.size(); ++i) { - literal_vector const& lits = m_binary[i]; - if (!lits.empty()) { - out << to_literal(i) << " -> " << lits << "\n"; - } + for (unsigned i = 0; i < m_binary.size(); ++i) { + literal_vector const& lits = m_binary[i]; + if (!lits.empty()) { + out << to_literal(i) << " -> " << lits << "\n"; } - return out; } + return out; + } - std::ostream& lookahead::display_clauses(std::ostream& out) const { - for (unsigned i = 0; i < m_clauses.size(); ++i) { - out << *m_clauses[i] << "\n"; - } - return out; + std::ostream& lookahead::display_clauses(std::ostream& out) const { + for (unsigned i = 0; i < m_clauses.size(); ++i) { + out << *m_clauses[i] << "\n"; } + return out; + } std::ostream& lookahead::display_values(std::ostream& out) const { - for (unsigned i = 0; i < m_trail.size(); ++i) { - literal l = m_trail[i]; - out << l << "\n"; - } - return out; + for (unsigned i = 0; i < m_trail.size(); ++i) { + literal l = m_trail[i]; + out << l << "\n"; } + return out; + } - std::ostream& lookahead::display_lookahead(std::ostream& out) const { - for (unsigned i = 0; i < m_lookahead.size(); ++i) { - literal lit = m_lookahead[i].m_lit; - unsigned offset = m_lookahead[i].m_offset; - out << lit << "\toffset: " << offset; - out << (is_undef(lit)?" undef": (is_true(lit) ? " true": " false")); - out << " wnb: " << get_wnb(lit); - out << "\n"; - } - return out; + std::ostream& lookahead::display_lookahead(std::ostream& out) const { + for (unsigned i = 0; i < m_lookahead.size(); ++i) { + literal lit = m_lookahead[i].m_lit; + unsigned offset = m_lookahead[i].m_offset; + out << lit << "\toffset: " << offset; + out << (is_undef(lit)?" undef": (is_true(lit) ? " true": " false")); + out << " wnb: " << get_wnb(lit); + out << "\n"; } + return out; + } void lookahead::init_search() { - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); - } + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + } void lookahead::checkpoint() { - if (!m_rlimit.inc()) { - throw solver_exception(Z3_CANCELED_MSG); - } - if (memory::get_allocation_size() > m_s.m_config.m_max_memory) { - throw solver_exception(Z3_MAX_MEMORY_MSG); - } + if (!m_rlimit.inc()) { + throw solver_exception(Z3_CANCELED_MSG); } - - - + if (memory::get_allocation_size() > m_s.m_config.m_max_memory) { + throw solver_exception(Z3_MAX_MEMORY_MSG); + } + } literal lookahead::choose() { literal l = null_literal; @@ -1594,4 +1601,165 @@ namespace sat { } + literal lookahead::select_lookahead(bool_var_vector const& vars) { + scoped_ext _sext(*this); + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + if (inconsistent()) return null_literal; + inc_istamp(); + for (auto v : vars) { + m_select_lookahead_vars.insert(v); + } + literal l = choose(); + m_select_lookahead_vars.reset(); + if (inconsistent()) return null_literal; + + // assign unit literals that were found during search for lookahead. + unsigned num_assigned = 0; + for (literal lit : m_trail) { + if (!m_s.was_eliminated(lit.var()) && m_s.value(lit) != l_true) { + m_s.assign(lit, justification()); + ++num_assigned; + } + } + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_assigned << ")\n";); + return l; + } + + /** + \brief simplify set of clauses by extracting units from a lookahead at base level. + */ + void lookahead::simplify() { + SASSERT(m_prefix == 0); + SASSERT(m_watches.empty()); + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + if (inconsistent()) return; + inc_istamp(); + literal l = choose(); + if (inconsistent()) return; + SASSERT(m_trail_lim.empty()); + unsigned num_units = 0; + for (unsigned i = 0; i < m_trail.size(); ++i) { + literal lit = m_trail[i]; + if (m_s.value(lit) == l_undef && !m_s.was_eliminated(lit.var())) { + m_s.m_simplifier.propagate_unit(lit); + ++num_units; + } + } + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << ")\n";); + + m_s.m_simplifier.subsume(); + m_lookahead.reset(); + } + + // + // there can be two sets of equivalence classes. + // example: + // a -> !b + // b -> !a + // c -> !a + // we pick as root the Boolean variable with the largest value. + // + literal lookahead::get_root(bool_var v) { + literal lit(v, false); + literal r1 = get_parent(lit); + literal r2 = get_parent(literal(r1.var(), false)); + CTRACE("sat", r1 != get_parent(literal(r2.var(), false)), + tout << r1 << " " << r2 << "\n";); + SASSERT(r1.var() == get_parent(literal(r2.var(), false)).var()); + if (r1.var() >= r2.var()) { + return r1; + } + else { + return r1.sign() ? ~r2 : r2; + } + } + + /** + \brief extract equivalence classes of variables and simplify clauses using these. + */ + void lookahead::scc() { + SASSERT(m_prefix == 0); + SASSERT(m_watches.empty()); + m_search_mode = lookahead_mode::searching; + scoped_level _sl(*this, c_fixed_truth); + init(); + if (inconsistent()) return; + inc_istamp(); + m_lookahead.reset(); + if (select(0)) { + // extract equivalences + get_scc(); + if (inconsistent()) return; + literal_vector roots; + bool_var_vector to_elim; + for (unsigned i = 0; i < m_num_vars; ++i) { + roots.push_back(literal(i, false)); + } + for (unsigned i = 0; i < m_candidates.size(); ++i) { + bool_var v = m_candidates[i].m_var; + literal p = get_root(v); + if (p != null_literal && p.var() != v && !m_s.is_external(v) && + !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { + to_elim.push_back(v); + roots[v] = p; + SASSERT(get_parent(p) == p); + set_parent(~p, ~p); + SASSERT(get_parent(~p) == ~p); + } + } + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); + elim_eqs elim(m_s); + elim(roots, to_elim); + } + m_lookahead.reset(); + } + + std::ostream& lookahead::display(std::ostream& out) const { + out << "Prefix: " << pp_prefix(m_prefix, m_trail_lim.size()) << "\n"; + out << "Level: " << m_level << "\n"; + display_values(out); + display_binary(out); + display_clauses(out); + out << "free vars: "; + for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { + out << *it << " "; + } + out << "\n"; + for (unsigned i = 0; i < m_watches.size(); ++i) { + watch_list const& wl = m_watches[i]; + if (!wl.empty()) { + sat::display_watch_list(out << to_literal(i) << " -> ", m_cls_allocator, wl); + out << "\n"; + } + } + return out; + } + + model const& lookahead::get_model() { + if (m_model.empty()) { + init_model(); + } + return m_model; + } + + void lookahead::collect_statistics(statistics& st) const { + st.update("lh bool var", m_vprefix.size()); + st.update("lh clauses", m_clauses.size()); + st.update("lh add binary", m_stats.m_add_binary); + st.update("lh del binary", m_stats.m_del_binary); + st.update("lh add ternary", m_stats.m_add_ternary); + st.update("lh del ternary", m_stats.m_del_ternary); + st.update("lh propagations", m_stats.m_propagations); + st.update("lh decisions", m_stats.m_decisions); + st.update("lh windfalls", m_stats.m_windfall_binaries); + st.update("lh autarky propagations", m_stats.m_autarky_propagations); + st.update("lh autarky equivalences", m_stats.m_autarky_equivalences); + st.update("lh double lookahead propagations", m_stats.m_double_lookahead_propagations); + st.update("lh double lookahead rounds", m_stats.m_double_lookahead_rounds); + } + } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index f1e78bf8f..610a1b3a2 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -447,59 +447,11 @@ namespace sat { return search(); } - literal select_lookahead(bool_var_vector const& vars) { - scoped_ext _sext(*this); - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); - if (inconsistent()) return null_literal; - inc_istamp(); - for (auto v : vars) { - m_select_lookahead_vars.insert(v); - } - literal l = choose(); - m_select_lookahead_vars.reset(); - if (inconsistent()) return null_literal; - - // assign unit literals that were found during search for lookahead. - unsigned num_assigned = 0; - for (literal lit : m_trail) { - if (!m_s.was_eliminated(lit.var()) && m_s.value(lit) != l_true) { - m_s.assign(lit, justification()); - ++num_assigned; - } - } - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_assigned << ")\n";); - return l; - } - + literal select_lookahead(bool_var_vector const& vars); /** \brief simplify set of clauses by extracting units from a lookahead at base level. */ - void simplify() { - SASSERT(m_prefix == 0); - SASSERT(m_watches.empty()); - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); - if (inconsistent()) return; - inc_istamp(); - literal l = choose(); - if (inconsistent()) return; - SASSERT(m_trail_lim.empty()); - unsigned num_units = 0; - for (unsigned i = 0; i < m_trail.size(); ++i) { - literal lit = m_trail[i]; - if (m_s.value(lit) == l_undef && !m_s.was_eliminated(lit.var())) { - m_s.m_simplifier.propagate_unit(lit); - ++num_units; - } - } - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << ")\n";); - - m_s.m_simplifier.subsume(); - m_lookahead.reset(); - } + void simplify(); // // there can be two sets of equivalence classes. @@ -509,104 +461,17 @@ namespace sat { // c -> !a // we pick as root the Boolean variable with the largest value. // - literal get_root(bool_var v) { - literal lit(v, false); - literal r1 = get_parent(lit); - literal r2 = get_parent(literal(r1.var(), false)); - CTRACE("sat", r1 != get_parent(literal(r2.var(), false)), - tout << r1 << " " << r2 << "\n";); - SASSERT(r1.var() == get_parent(literal(r2.var(), false)).var()); - if (r1.var() >= r2.var()) { - return r1; - } - else { - return r1.sign() ? ~r2 : r2; - } - } - + literal get_root(bool_var v); + /** \brief extract equivalence classes of variables and simplify clauses using these. */ - void scc() { - SASSERT(m_prefix == 0); - SASSERT(m_watches.empty()); - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); - if (inconsistent()) return; - inc_istamp(); - m_lookahead.reset(); - if (select(0)) { - // extract equivalences - get_scc(); - if (inconsistent()) return; - literal_vector roots; - bool_var_vector to_elim; - for (unsigned i = 0; i < m_num_vars; ++i) { - roots.push_back(literal(i, false)); - } - for (unsigned i = 0; i < m_candidates.size(); ++i) { - bool_var v = m_candidates[i].m_var; - literal p = get_root(v); - if (p != null_literal && p.var() != v && !m_s.is_external(v) && - !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { - to_elim.push_back(v); - roots[v] = p; - SASSERT(get_parent(p) == p); - set_parent(~p, ~p); - SASSERT(get_parent(~p) == ~p); - } - } - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); - elim_eqs elim(m_s); - elim(roots, to_elim); - } - m_lookahead.reset(); - } + void scc(); - std::ostream& display(std::ostream& out) const { - out << "Prefix: " << pp_prefix(m_prefix, m_trail_lim.size()) << "\n"; - out << "Level: " << m_level << "\n"; - display_values(out); - display_binary(out); - display_clauses(out); - out << "free vars: "; - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - out << *it << " "; - } - out << "\n"; - for (unsigned i = 0; i < m_watches.size(); ++i) { - watch_list const& wl = m_watches[i]; - if (!wl.empty()) { - sat::display_watch_list(out << to_literal(i) << " -> ", m_cls_allocator, wl); - out << "\n"; - } - } - return out; - } + std::ostream& display(std::ostream& out) const; + model const& get_model(); - model const& get_model() { - if (m_model.empty()) { - init_model(); - } - return m_model; - } - - void collect_statistics(statistics& st) const { - st.update("lh bool var", m_vprefix.size()); - st.update("lh clauses", m_clauses.size()); - st.update("lh add binary", m_stats.m_add_binary); - st.update("lh del binary", m_stats.m_del_binary); - st.update("lh add ternary", m_stats.m_add_ternary); - st.update("lh del ternary", m_stats.m_del_ternary); - st.update("lh propagations", m_stats.m_propagations); - st.update("lh decisions", m_stats.m_decisions); - st.update("lh windfalls", m_stats.m_windfall_binaries); - st.update("lh autarky propagations", m_stats.m_autarky_propagations); - st.update("lh autarky equivalences", m_stats.m_autarky_equivalences); - st.update("lh double lookahead propagations", m_stats.m_double_lookahead_propagations); - st.update("lh double lookahead rounds", m_stats.m_double_lookahead_rounds); - } + void collect_statistics(statistics& st) const; }; } From c870b77366a141e60e4fe3ecb48156fb49cad6a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Jun 2017 17:25:06 -0700 Subject: [PATCH 0159/1283] fixes to lookahead Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.h | 1 + src/sat/sat_lookahead.cpp | 15 +++++++++------ src/sat/sat_solver/inc_sat_solver.cpp | 8 +++++++- src/smt/smt_solver.cpp | 5 +++++ src/solver/combined_solver.cpp | 4 ++++ src/solver/solver.cpp | 4 ++++ src/solver/solver.h | 2 +- src/solver/tactic2solver.cpp | 6 ++++++ src/tactic/portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 11 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 27168e2ca..24d0408fc 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -107,6 +107,7 @@ namespace opt { virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); + virtual expr_ref lookahead(expr_ref_vector const& candidates) { return expr_ref(m.mk_true(), m); } void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index fd6860ff3..347228b79 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -151,7 +151,7 @@ namespace sat { } if (m_num_tc1 < m_config.m_tc1_limit) { ++m_num_tc1; - IF_VERBOSE(3, verbose_stream() << "tc1: " << u << " " << w << "\n";); + IF_VERBOSE(30, verbose_stream() << "tc1: " << u << " " << w << "\n";); add_binary(u, w); } } @@ -285,9 +285,11 @@ namespace sat { for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { SASSERT(is_undef(*it)); bool_var x = *it; - if (!m_select_lookahead_vars.empty() && m_select_lookahead_vars.contains(x)) { - m_candidates.push_back(candidate(x, m_rating[x])); - sum += m_rating[x]; + if (!m_select_lookahead_vars.empty()) { + if (m_select_lookahead_vars.contains(x)) { + m_candidates.push_back(candidate(x, m_rating[x])); + sum += m_rating[x]; + } } else if (newbies || active_prefix(x)) { m_candidates.push_back(candidate(x, m_rating[x])); @@ -1214,7 +1216,7 @@ namespace sat { continue; } if (scope_lvl() == 1) { - IF_VERBOSE(3, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); + IF_VERBOSE(30, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); } TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); reset_wnb(lit); @@ -1602,12 +1604,13 @@ namespace sat { literal lookahead::select_lookahead(bool_var_vector const& vars) { + IF_VERBOSE(1, verbose_stream() << "(sat-select " << vars.size() << ")\n";); scoped_ext _sext(*this); m_search_mode = lookahead_mode::searching; scoped_level _sl(*this, c_fixed_truth); init(); if (inconsistent()) return null_literal; - inc_istamp(); + inc_istamp(); for (auto v : vars) { m_select_lookahead_vars.insert(v); } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index eb931d428..3fa9f4c81 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -281,8 +281,10 @@ public: } virtual expr_ref lookahead(expr_ref_vector const& candidates) { + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead " << candidates.size() << ")\n";); sat::bool_var_vector vars; expr_ref_vector lit2expr(m); + lit2expr.resize(m_solver.num_vars() * 2); m_map.mk_inv(lit2expr); for (auto c : candidates) { sat::bool_var v = m_map.to_bool_var(c); @@ -290,17 +292,21 @@ public: vars.push_back(v); } } + IF_VERBOSE(1, verbose_stream() << "vars: " << vars.size() << "\n";); if (vars.empty()) { return expr_ref(m.mk_true(), m); } sat::literal l = m_solver.select_lookahead(vars); if (m_solver.inconsistent()) { + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead inconsistent)\n";); return expr_ref(m.mk_false(), m); } if (l == sat::null_literal) { return expr_ref(m.mk_true(), m); } - return expr_ref(lit2expr[l.index()].get(), m); + expr_ref result(lit2expr[l.index()].get(), m); + IF_VERBOSE(1, verbose_stream() << "solution: " << l << " " << result << "\n";); + return result; } virtual void get_lemmas(expr_ref_vector & lemmas) { IF_VERBOSE(1, verbose_stream() << "(sat-get-lemmas " << lemmas.size() << ")\n";); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index cd912b72e..2ca5a11c3 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -219,6 +219,11 @@ namespace smt { return m_context.get_formulas()[idx]; } + virtual expr_ref lookahead(expr_ref_vector const& candidates) { + ast_manager& m = get_manager(); + return expr_ref(m.mk_true(), m); + } + struct collect_fds_proc { ast_manager & m; func_decl_set & m_fds; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index d67643edf..5d6cd232f 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -274,6 +274,10 @@ public: return m_solver1->get_num_assumptions() + m_solver2->get_num_assumptions(); } + virtual expr_ref lookahead(expr_ref_vector const& candidates) { + return m_solver1->lookahead(candidates); + } + virtual expr * get_assumption(unsigned idx) const { unsigned c1 = m_solver1->get_num_assumptions(); if (idx < c1) return m_solver1->get_assumption(idx); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 59b950972..7175eacbf 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -162,9 +162,13 @@ bool solver::is_literal(ast_manager& m, expr* e) { return is_uninterp_const(e) || (m.is_not(e, e) && is_uninterp_const(e)); } +#if 0 expr_ref solver::lookahead(expr_ref_vector const& candidates) { + std::cout << "lookahead: " << candidates.size() << "\n"; + INVOKE_DEBUGGER(); ast_manager& m = candidates.get_manager(); return expr_ref(m.mk_true(), m); } +#endif diff --git a/src/solver/solver.h b/src/solver/solver.h index 51bff08ad..56890f7c0 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -176,7 +176,7 @@ public: \brief extract a lookahead candidates for branching. */ - virtual expr_ref lookahead(expr_ref_vector const& candidates); + virtual expr_ref lookahead(expr_ref_vector const& candidates) = 0; /** \brief extract learned lemmas. diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index e451f57d4..f9d5a4b0f 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -75,6 +75,12 @@ public: virtual expr * get_assertion(unsigned idx) const; virtual ast_manager& get_manager() const; + + virtual expr_ref lookahead(expr_ref_vector const& candidates) { + ast_manager& m = get_manager(); + std::cout << "tactic2solver\n"; + return expr_ref(m.mk_true(), m); + } }; ast_manager& tactic2solver::get_manager() const { return m_assertions.get_manager(); } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 3645ba97a..aeaa88bc2 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -149,7 +149,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref lookahead(expr_ref_vector& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } + virtual expr_ref lookahead(expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index a40f2988a..d50dee57c 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -97,7 +97,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual expr_ref lookahead(expr_ref_vector& candidates) { return m_solver->lookahead(candidates); } + virtual expr_ref lookahead(expr_ref_vector const& candidates) { return m_solver->lookahead(candidates); } virtual void get_lemmas(expr_ref_vector & lemmas) { m_solver->get_lemmas(lemmas); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 8bf6b7e39..46a5912b0 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -93,7 +93,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref lookahead(expr_ref_vector& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } + virtual expr_ref lookahead(expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { From a55416351f811a6e927958e9d73ada70977de874 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Jun 2017 09:17:20 -0700 Subject: [PATCH 0160/1283] lookahead Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 51 +++++++++++++++++++++++---------------- src/sat/sat_lookahead.h | 40 +++++++++++++++--------------- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 347228b79..97b4ef073 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -211,7 +211,7 @@ namespace sat { unsigned max_num_cand = level == 0 ? m_freevars.size() : level_cand / level; max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand); - float sum = 0; + double sum = 0; for (bool newbies = false; ; newbies = true) { sum = init_candidates(level, newbies); if (!m_candidates.empty()) break; @@ -231,7 +231,7 @@ namespace sat { bool progress = true; while (progress && m_candidates.size() >= max_num_cand * 2) { progress = false; - float mean = sum / (float)(m_candidates.size() + 0.0001); + double mean = sum / (double)(m_candidates.size() + 0.0001); sum = 0; for (unsigned i = 0; i < m_candidates.size() && m_candidates.size() >= max_num_cand * 2; ++i) { if (m_candidates[i].m_rating >= mean) { @@ -279,14 +279,15 @@ namespace sat { if (i > j) m_candidates[i] = c; } - float lookahead::init_candidates(unsigned level, bool newbies) { + double lookahead::init_candidates(unsigned level, bool newbies) { m_candidates.reset(); - float sum = 0; + double sum = 0; for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { SASSERT(is_undef(*it)); bool_var x = *it; if (!m_select_lookahead_vars.empty()) { if (m_select_lookahead_vars.contains(x)) { + // IF_VERBOSE(1, verbose_stream() << x << " " << m_rating[x] << "\n";); m_candidates.push_back(candidate(x, m_rating[x])); sum += m_rating[x]; } @@ -296,6 +297,7 @@ namespace sat { sum += m_rating[x]; } } + IF_VERBOSE(1, verbose_stream() << " " << sum << " " << m_candidates.size() << "\n";); TRACE("sat", display_candidates(tout << "sum: " << sum << "\n");); return sum; } @@ -378,32 +380,34 @@ namespace sat { void lookahead::ensure_H(unsigned level) { while (m_H.size() <= level) { - m_H.push_back(svector()); + m_H.push_back(svector()); m_H.back().resize(m_num_vars * 2, 0); } } - void lookahead::h_scores(svector& h, svector& hp) { - float sum = 0; + void lookahead::h_scores(svector& h, svector& hp) { + double sum = 0; for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { literal l(*it, false); sum += h[l.index()] + h[(~l).index()]; } - float factor = 2 * m_freevars.size() / sum; - float sqfactor = factor * factor; - float afactor = factor * m_config.m_alpha; + if (sum == 0) sum = 0.0001; + double factor = 2 * m_freevars.size() / sum; + double sqfactor = factor * factor; + double afactor = factor * m_config.m_alpha; for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { literal l(*it, false); - float pos = l_score(l, h, factor, sqfactor, afactor); - float neg = l_score(~l, h, factor, sqfactor, afactor); + double pos = l_score(l, h, factor, sqfactor, afactor); + double neg = l_score(~l, h, factor, sqfactor, afactor); hp[l.index()] = pos; hp[(~l).index()] = neg; + // std::cout << "h_scores: " << pos << " " << neg << "\n"; m_rating[l.var()] = pos * neg; } } - float lookahead::l_score(literal l, svector const& h, float factor, float sqfactor, float afactor) { - float sum = 0, tsum = 0; + double lookahead::l_score(literal l, svector const& h, double factor, double sqfactor, double afactor) { + double sum = 0, tsum = 0; literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); for (; it != end; ++it) { bool_var v = it->var(); @@ -412,6 +416,7 @@ namespace sat { if (is_undef(*it)) sum += h[it->index()]; // if (m_freevars.contains(it->var())) sum += h[it->index()]; } + // std::cout << "sum: " << sum << "\n"; watch_list& wlist = m_watches[l.index()]; watch_list::iterator wit = wlist.begin(), wend = wlist.end(); for (; wit != wend; ++wit) { @@ -440,9 +445,13 @@ namespace sat { } break; } + // case watched::EXTERNAL: } + // std::cout << "tsum: " << tsum << "\n"; } - sum = (float)(0.1 + afactor*sum + sqfactor*tsum); + // std::cout << "sum: " << sum << " afactor " << afactor << " sqfactor " << sqfactor << " tsum " << tsum << "\n"; + sum = (double)(0.1 + afactor*sum + sqfactor*tsum); + // std::cout << "sum: " << sum << " max score " << m_config.m_max_score << "\n"; return std::min(m_config.m_max_score, sum); } @@ -545,7 +554,7 @@ namespace sat { literal t = m_active; m_active = get_link(v); literal best = v; - float best_rating = get_rating(v); + double best_rating = get_rating(v); set_rank(v, UINT_MAX); set_link(v, m_settled); m_settled = t; while (t != v) { @@ -556,7 +565,7 @@ namespace sat { } set_rank(t, UINT_MAX); set_parent(t, v); - float t_rating = get_rating(t); + double t_rating = get_rating(t); if (t_rating > best_rating) { best = t; best_rating = t_rating; @@ -1124,7 +1133,7 @@ namespace sat { found = false; for (; l_it != l_end && !found; found = is_true(*l_it), ++l_it) ; if (!found) { - m_weighted_new_binaries = (float)0.001; + m_weighted_new_binaries = (double)0.001; } } break; @@ -1272,15 +1281,15 @@ namespace sat { literal lookahead::select_literal() { literal l = null_literal; - float h = 0; + double h = 0; unsigned count = 1; for (unsigned i = 0; i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; if (lit.sign() || !is_undef(lit)) { continue; } - float diff1 = get_wnb(lit), diff2 = get_wnb(~lit); - float mixd = mix_diff(diff1, diff2); + double diff1 = get_wnb(lit), diff2 = get_wnb(~lit); + double mixd = mix_diff(diff1, diff2); if (mixd == h) ++count; if (mixd > h || (mixd == h && m_s.m_rand(count) == 0)) { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 610a1b3a2..028e94786 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -68,12 +68,12 @@ namespace sat { struct config { double m_dl_success; - float m_alpha; - float m_max_score; + double m_alpha; + double m_max_score; unsigned m_max_hlevel; unsigned m_min_cutoff; unsigned m_level_cand; - float m_delta_rho; + double m_delta_rho; unsigned m_dl_max_iterations; unsigned m_tc1_limit; @@ -83,7 +83,7 @@ namespace sat { m_max_score = 20.0; m_min_cutoff = 30; m_level_cand = 600; - m_delta_rho = (float)0.9995; + m_delta_rho = (double)0.9995; m_dl_max_iterations = 32; m_tc1_limit = 10000000; } @@ -96,7 +96,7 @@ namespace sat { }; struct lit_info { - float m_wnb; + double m_wnb; unsigned m_double_lookahead; lit_info(): m_wnb(0), m_double_lookahead(0) {} }; @@ -145,9 +145,9 @@ namespace sat { clause_allocator m_cls_allocator; bool m_inconsistent; unsigned_vector m_bstamp; // literal: timestamp for binary implication - vector > m_H; // literal: fitness score - svector* m_heur; // current fitness - svector m_rating; // var: pre-selection rating + vector > m_H; // literal: fitness score + svector* m_heur; // current fitness + svector m_rating; // var: pre-selection rating unsigned m_bstamp_id; // unique id for binary implication. unsigned m_istamp_id; // unique id for managing double lookaheads unsigned_vector m_stamp; // var: timestamp with truth value @@ -156,7 +156,7 @@ namespace sat { vector m_watches; // literal: watch structure svector m_lits; // literal: attributes. vector m_full_watches; // literal: full watch list, used to ensure that autarky reduction is sound - float m_weighted_new_binaries; // metric associated with current lookahead1 literal. + double m_weighted_new_binaries; // metric associated with current lookahead1 literal. literal_vector m_wstack; // windofall stack that is populated in lookahead1 mode uint64 m_prefix; // where we are in search tree svector m_vprefix; // var: prefix where variable participates in propagation @@ -244,24 +244,24 @@ namespace sat { struct candidate { bool_var m_var; - float m_rating; - candidate(bool_var v, float r): m_var(v), m_rating(r) {} + double m_rating; + candidate(bool_var v, double r): m_var(v), m_rating(r) {} }; svector m_candidates; uint_set m_select_lookahead_vars; - float get_rating(bool_var v) const { return m_rating[v]; } - float get_rating(literal l) const { return get_rating(l.var()); } + double get_rating(bool_var v) const { return m_rating[v]; } + double get_rating(literal l) const { return get_rating(l.var()); } bool select(unsigned level); void sift_up(unsigned j); - float init_candidates(unsigned level, bool newbies); + double init_candidates(unsigned level, bool newbies); std::ostream& display_candidates(std::ostream& out) const; bool is_unsat() const; bool is_sat() const; void init_pre_selection(unsigned level); void ensure_H(unsigned level); - void h_scores(svector& h, svector& hp); - float l_score(literal l, svector const& h, float factor, float sqfactor, float afactor); + void h_scores(svector& h, svector& hp); + double l_score(literal l, svector const& h, double factor, double sqfactor, double afactor); // ------------------------------------ // Implication graph @@ -378,7 +378,7 @@ namespace sat { bool push_lookahead2(literal lit, unsigned level); void push_lookahead1(literal lit, unsigned level); void pop_lookahead1(literal lit); - float mix_diff(float l, float r) const { return l + r + (1 << 10) * l * r; } + double mix_diff(double l, double r) const { return l + r + (1 << 10) * l * r; } clause const& get_clause(watch_list::iterator it) const; bool is_nary_propagation(clause const& c, literal l) const; void propagate_clauses(literal l); @@ -390,9 +390,9 @@ namespace sat { void reset_wnb(); literal select_literal(); - void set_wnb(literal l, float f) { m_lits[l.index()].m_wnb = f; } - void inc_wnb(literal l, float f) { m_lits[l.index()].m_wnb += f; } - float get_wnb(literal l) const { return m_lits[l.index()].m_wnb; } + void set_wnb(literal l, double f) { m_lits[l.index()].m_wnb = f; } + void inc_wnb(literal l, double f) { m_lits[l.index()].m_wnb += f; } + double get_wnb(literal l) const { return m_lits[l.index()].m_wnb; } void reset_wnb(literal l); bool check_autarky(literal l, unsigned level); From bc54197fb36a6048ae616ab26ebd86b3ac608a0c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Jun 2017 10:46:51 -0700 Subject: [PATCH 0161/1283] 64 bit clause offset fix Signed-off-by: Nikolaj Bjorner --- src/cmd_context/basic_cmds.cpp | 35 +++++++++++++------------- src/sat/sat_clause.cpp | 46 ++++++---------------------------- src/sat/sat_clause.h | 10 +++----- 3 files changed, 30 insertions(+), 61 deletions(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 6d6217b50..f46e0d8ff 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -198,28 +198,29 @@ ATOMIC_CMD(get_proof_cmd, "get-proof", "retrieve proof", { } }); -#define PRINT_CORE() \ - ptr_vector core; \ - ctx.get_check_sat_result()->get_unsat_core(core); \ - ctx.regular_stream() << "("; \ - ptr_vector::const_iterator it = core.begin(); \ - ptr_vector::const_iterator end = core.end(); \ - for (bool first = true; it != end; ++it) { \ - if (first) \ - first = false; \ - else \ - ctx.regular_stream() << " "; \ - ctx.regular_stream() << mk_ismt2_pp(*it, ctx.m()); \ - } \ - ctx.regular_stream() << ")" << std::endl; \ +static void print_core(cmd_context& ctx) { + ptr_vector core; + ctx.get_check_sat_result()->get_unsat_core(core); + ctx.regular_stream() << "("; + ptr_vector::const_iterator it = core.begin(); + ptr_vector::const_iterator end = core.end(); + for (bool first = true; it != end; ++it) { + if (first) + first = false; + else + ctx.regular_stream() << " "; + ctx.regular_stream() << mk_ismt2_pp(*it, ctx.m()); + } + ctx.regular_stream() << ")" << std::endl; +} -ATOMIC_CMD(get_unsat_core_cmd, "get-unsat-core", "retrieve unsat core", { +TOMIC_CMD(get_unsat_core_cmd, "get-unsat-core", "retrieve unsat core", { if (!ctx.produce_unsat_cores()) throw cmd_exception("unsat core construction is not enabled, use command (set-option :produce-unsat-cores true)"); if (!ctx.has_manager() || ctx.cs_state() != cmd_context::css_unsat) throw cmd_exception("unsat core is not available"); - PRINT_CORE(); + print_core(ctx); }); ATOMIC_CMD(get_unsat_assumptions_cmd, "get-unsat-assumptions", "retrieve subset of assumptions sufficient for unsatisfiability", { @@ -228,7 +229,7 @@ ATOMIC_CMD(get_unsat_assumptions_cmd, "get-unsat-assumptions", "retrieve subset if (!ctx.has_manager() || ctx.cs_state() != cmd_context::css_unsat) { throw cmd_exception("unsat assumptions is not available"); } - PRINT_CORE(); + print_core(ctx); }); diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 68af09ec7..27c566b69 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -130,23 +130,19 @@ namespace sat { clause * clause_allocator::get_clause(clause_offset cls_off) const { #if defined(_AMD64_) -#if defined (Z3DEBUG) - clause const* result; if (((cls_off & c_alignment_mask) == c_last_segment)) { unsigned id = cls_off >> c_cls_alignment; - bool check = m_last_seg_id2cls.find(id, result); - SASSERT(check); - return const_cast(result); + return const_cast(m_last_seg_id2cls[id]); } -#endif return reinterpret_cast(m_segments[cls_off & c_alignment_mask] + (static_cast(cls_off) & ~c_alignment_mask)); #else return reinterpret_cast(cls_off); #endif } + + clause_offset clause_allocator::get_offset(clause const * cls) const { #if defined(_AMD64_) - unsigned clause_allocator::get_segment(clause const* cls) { size_t ptr = reinterpret_cast(cls); SASSERT((ptr & c_alignment_mask) == 0); @@ -154,41 +150,18 @@ namespace sat { unsigned i = 0; for (i = 0; i < m_num_segments; ++i) if (m_segments[i] == ptr) - return i; - i = m_num_segments; + return static_cast(reinterpret_cast(cls)) + i; + SASSERT(i == m_num_segments); SASSERT(i <= c_last_segment); -#if defined(Z3DEBUG) if (i == c_last_segment) { - if (!m_last_seg_id2cls.contains(cls->id())) - m_last_seg_id2cls.insert(cls->id(), cls); + m_last_seg_id2cls.setx(cls->id(), cls, 0); + return (cls->id() << c_cls_alignment) | c_last_segment; } else { ++m_num_segments; m_segments[i] = ptr; + return static_cast(reinterpret_cast(cls)) + i; } -#else - if (i == c_last_segment) { - throw default_exception("segment out of range"); - } - m_segments[i] = ptr; - ++m_num_segments; -#endif - - return i; - } -#endif - - clause_offset clause_allocator::get_offset(clause const * cls) const { -#if defined(_AMD64_) - unsigned segment = const_cast(this)->get_segment(cls); -#if defined(Z3DEBUG) - SASSERT(segment <= c_last_segment); - if (segment == c_last_segment) { - SASSERT(m_last_seg_id2cls.contains(cls->id())); - return (cls->id() << c_cls_alignment) | c_last_segment; - } -#endif - return static_cast(reinterpret_cast(cls)) + segment; #else return reinterpret_cast(cls); #endif @@ -207,9 +180,6 @@ namespace sat { TRACE("sat_clause", tout << "delete: " << cls->id() << " " << *cls << "\n";); m_id_gen.recycle(cls->id()); #if defined(_AMD64_) -#if defined(Z3DEBUG) - m_last_seg_id2cls.remove(cls->id()); -#endif #endif size_t size = clause::get_obj_size(cls->m_capacity); cls->~clause(); diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 11824b247..beaa97862 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -132,15 +132,13 @@ namespace sat { small_object_allocator m_allocator; id_gen m_id_gen; #if defined(_AMD64_) - unsigned get_segment(clause const* cls); static const unsigned c_cls_alignment = 3; static const unsigned c_last_segment = (1ull << c_cls_alignment) - 1ull; static const size_t c_alignment_mask = (1ull << c_cls_alignment) - 1ull; - unsigned m_num_segments; - size_t m_segments[c_last_segment]; -#if defined(Z3DEBUG) - u_map m_last_seg_id2cls; -#endif + mutable unsigned m_num_segments; + mutable size_t m_segments[c_last_segment]; + mutable svector m_aux_segments; + mutable ptr_vector m_last_seg_id2cls; #endif public: clause_allocator(); From b266af3e08390d1cd3f381adfd35d5966d56337b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Jun 2017 10:51:09 -0700 Subject: [PATCH 0162/1283] atomic Signed-off-by: Nikolaj Bjorner --- src/cmd_context/basic_cmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index f46e0d8ff..9886cc100 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -214,7 +214,7 @@ static void print_core(cmd_context& ctx) { ctx.regular_stream() << ")" << std::endl; } -TOMIC_CMD(get_unsat_core_cmd, "get-unsat-core", "retrieve unsat core", { +ATOMIC_CMD(get_unsat_core_cmd, "get-unsat-core", "retrieve unsat core", { if (!ctx.produce_unsat_cores()) throw cmd_exception("unsat core construction is not enabled, use command (set-option :produce-unsat-cores true)"); if (!ctx.has_manager() || From af6ebbcd92746079c8d3d9c581bb18249e2de5d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Jun 2017 13:08:05 -0700 Subject: [PATCH 0163/1283] init search before returning Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 15 ++++++-- src/api/dotnet/Solver.cs | 6 ++-- src/api/z3_api.h | 4 +-- src/opt/opt_solver.h | 2 +- src/sat/sat_lookahead.cpp | 34 ++++++++++++++----- src/sat/sat_lookahead.h | 10 +++++- src/sat/sat_solver.cpp | 11 ++---- src/sat/sat_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 27 +++++++++++++-- src/smt/smt_solver.cpp | 2 +- src/solver/combined_solver.cpp | 4 +-- src/solver/solver.h | 2 +- src/solver/tactic2solver.cpp | 2 +- .../portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 16 files changed, 90 insertions(+), 37 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index c6eae7488..09e522db2 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -479,12 +479,14 @@ extern "C" { Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, Z3_solver s, + Z3_ast_vector assumptions, Z3_ast_vector candidates) { Z3_TRY; - LOG_Z3_solver_lookahead(c, s, candidates); + LOG_Z3_solver_lookahead(c, s, assumptions, candidates); ast_manager& m = mk_c(c)->m(); - expr_ref_vector _candidates(m); + expr_ref_vector _candidates(m), _assumptions(m); ast_ref_vector const& __candidates = to_ast_vector_ref(candidates); + ast_ref_vector const& __assumptions = to_ast_vector_ref(assumptions); for (auto & e : __candidates) { if (!is_expr(e)) { SET_ERROR_CODE(Z3_INVALID_USAGE); @@ -492,6 +494,13 @@ extern "C" { } _candidates.push_back(to_expr(e)); } + for (auto & e : __assumptions) { + if (!is_expr(e)) { + SET_ERROR_CODE(Z3_INVALID_USAGE); + return 0; + } + _assumptions.push_back(to_expr(e)); + } expr_ref result(m); unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); @@ -504,7 +513,7 @@ extern "C" { scoped_timer timer(timeout, &eh); scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); try { - result = to_solver_ref(s)->lookahead(_candidates); + result = to_solver_ref(s)->lookahead(_assumptions, _candidates); } catch (z3_exception & ex) { mk_c(c)->handle_exception(ex); diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 6dd19cddf..078f5bc7a 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -255,11 +255,13 @@ namespace Microsoft.Z3 /// /// Select a lookahead literal from the set of supplied candidates. /// - public BoolExpr Lookahead(IEnumerable candidates) + public BoolExpr Lookahead(IEnumerable assumptions, IEnumerable candidates) { ASTVector cands = new ASTVector(Context); foreach (var c in candidates) cands.Push(c); - return (BoolExpr)Expr.Create(Context, Native.Z3_solver_lookahead(Context.nCtx, NativeObject, cands.NativeObject)); + ASTVector assums = new ASTVector(Context); + foreach (var c in assumptions) assums.Push(c); + return (BoolExpr)Expr.Create(Context, Native.Z3_solver_lookahead(Context.nCtx, NativeObject, assums.NativeObject, cands.NativeObject)); } /// diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 4ae7c5c22..317b32923 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6028,10 +6028,10 @@ extern "C" { \brief select a literal from the list of candidate propositional variables to split on. If the candidate list is empty, then the solver chooses a formula based on its internal state. - def_API('Z3_solver_lookahead', AST, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR))) + def_API('Z3_solver_lookahead', AST, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(AST_VECTOR))) */ - Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, Z3_solver s, Z3_ast_vector candidates); + Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, Z3_solver s, Z3_ast_vector assumptions, Z3_ast_vector candidates); /** diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 24d0408fc..cef270abc 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -107,7 +107,7 @@ namespace opt { virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); - virtual expr_ref lookahead(expr_ref_vector const& candidates) { return expr_ref(m.mk_true(), m); } + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { return expr_ref(m.mk_true(), m); } void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 97b4ef073..eeeff2c11 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -30,6 +30,18 @@ namespace sat { if (p.m_s.m_ext) p.m_s.m_ext->set_lookahead(0); } + lookahead::scoped_assumptions::scoped_assumptions(lookahead& p, literal_vector const& lits): p(p), lits(lits) { + for (auto l : lits) { + p.push(l, p.c_fixed_truth); + } + } + lookahead::scoped_assumptions::~scoped_assumptions() { + for (auto l : lits) { + p.pop(); + } + } + + void lookahead::flip_prefix() { if (m_trail_lim.size() < 64) { uint64 mask = (1ull << m_trail_lim.size()); @@ -1612,7 +1624,7 @@ namespace sat { } - literal lookahead::select_lookahead(bool_var_vector const& vars) { + literal lookahead::select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars) { IF_VERBOSE(1, verbose_stream() << "(sat-select " << vars.size() << ")\n";); scoped_ext _sext(*this); m_search_mode = lookahead_mode::searching; @@ -1623,19 +1635,25 @@ namespace sat { for (auto v : vars) { m_select_lookahead_vars.insert(v); } + + scoped_assumptions _sa(*this, assumptions); literal l = choose(); m_select_lookahead_vars.reset(); - if (inconsistent()) return null_literal; + if (inconsistent()) l = null_literal; +#if 0 // assign unit literals that were found during search for lookahead. - unsigned num_assigned = 0; - for (literal lit : m_trail) { - if (!m_s.was_eliminated(lit.var()) && m_s.value(lit) != l_true) { - m_s.assign(lit, justification()); - ++num_assigned; + if (assumptions.empty()) { + unsigned num_assigned = 0; + for (literal lit : m_trail) { + if (!m_s.was_eliminated(lit.var()) && m_s.value(lit) != l_true) { + m_s.assign(lit, justification()); + ++num_assigned; + } } + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_assigned << ")\n";); } - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_assigned << ")\n";); +#endif return l; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 028e94786..2b8ddc594 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -199,6 +199,14 @@ namespace sat { ~scoped_ext(); }; + class scoped_assumptions { + lookahead& p; + literal_vector lits; + public: + scoped_assumptions(lookahead& p, literal_vector const& lits); + ~scoped_assumptions(); + }; + // ------------------------------------- // prefix updates. I use low order bits. @@ -447,7 +455,7 @@ namespace sat { return search(); } - literal select_lookahead(bool_var_vector const& vars); + literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** \brief simplify set of clauses by extracting units from a lookahead at base level. */ diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1f8f3aa19..77a816660 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -811,14 +811,9 @@ namespace sat { return r; } - literal solver::select_lookahead(bool_var_vector const& vars) { + literal solver::select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars) { lookahead lh(*this); - literal result = lh.select_lookahead(vars); - if (result == null_literal) { - set_conflict(justification()); - } - // extract unit literals from lh - return result; + return lh.select_lookahead(assumptions, vars); } // ----------------------- @@ -851,8 +846,8 @@ namespace sat { } #endif try { - if (inconsistent()) return l_false; init_search(); + if (inconsistent()) return l_false; propagate(false); if (inconsistent()) return l_false; init_assumptions(num_lits, lits); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 348e1cd22..b6dffe511 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -355,7 +355,7 @@ namespace sat { void set_model(model const& mdl); char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } - literal select_lookahead(bool_var_vector const& vars); + literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); protected: unsigned m_conflicts; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 3fa9f4c81..9d9c24b8f 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -148,6 +148,8 @@ public: virtual lbool check_sat(unsigned sz, expr * const * assumptions) { m_solver.pop_to_base_level(); + m_core.reset(); + if (m_solver.inconsistent()) return l_false; expr_ref_vector _assumptions(m); obj_map asm2fml; for (unsigned i = 0; i < sz; ++i) { @@ -280,9 +282,10 @@ public: return 0; } - virtual expr_ref lookahead(expr_ref_vector const& candidates) { + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { IF_VERBOSE(1, verbose_stream() << "(sat-lookahead " << candidates.size() << ")\n";); sat::bool_var_vector vars; + sat::literal_vector lits; expr_ref_vector lit2expr(m); lit2expr.resize(m_solver.num_vars() * 2); m_map.mk_inv(lit2expr); @@ -292,11 +295,29 @@ public: vars.push_back(v); } } + for (auto c : assumptions) { + SASSERT(is_literal(c)); + sat::bool_var v = sat::null_bool_var; + bool sign = false; + expr* e = c; + while (m.is_not(e, e)) { + sign = !sign; + } + if (is_uninterp_const(e)) { + v = m_map.to_bool_var(e); + } + if (v != sat::null_bool_var) { + lits.push_back(sat::literal(v, sign)); + } + else { + IF_VERBOSE(0, verbose_stream() << "WARNING: could not handle " << mk_pp(c, m) << "\n";); + } + } IF_VERBOSE(1, verbose_stream() << "vars: " << vars.size() << "\n";); if (vars.empty()) { return expr_ref(m.mk_true(), m); } - sat::literal l = m_solver.select_lookahead(vars); + sat::literal l = m_solver.select_lookahead(lits, vars); if (m_solver.inconsistent()) { IF_VERBOSE(1, verbose_stream() << "(sat-lookahead inconsistent)\n";); return expr_ref(m.mk_false(), m); @@ -715,7 +736,7 @@ private: if (asm2fml.contains(e)) { e = asm2fml.find(e); } - m_core.push_back(e); + m_core.push_back(e); } } diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 2ca5a11c3..ef81fbfd2 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -219,7 +219,7 @@ namespace smt { return m_context.get_formulas()[idx]; } - virtual expr_ref lookahead(expr_ref_vector const& candidates) { + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { ast_manager& m = get_manager(); return expr_ref(m.mk_true(), m); } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 5d6cd232f..b23aabc2d 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -274,8 +274,8 @@ public: return m_solver1->get_num_assumptions() + m_solver2->get_num_assumptions(); } - virtual expr_ref lookahead(expr_ref_vector const& candidates) { - return m_solver1->lookahead(candidates); + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { + return m_solver1->lookahead(assumptions, candidates); } virtual expr * get_assumption(unsigned idx) const { diff --git a/src/solver/solver.h b/src/solver/solver.h index 56890f7c0..5346cf4a4 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -176,7 +176,7 @@ public: \brief extract a lookahead candidates for branching. */ - virtual expr_ref lookahead(expr_ref_vector const& candidates) = 0; + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) = 0; /** \brief extract learned lemmas. diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index f9d5a4b0f..d3d8e59ce 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -76,7 +76,7 @@ public: virtual ast_manager& get_manager() const; - virtual expr_ref lookahead(expr_ref_vector const& candidates) { + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { ast_manager& m = get_manager(); std::cout << "tactic2solver\n"; return expr_ref(m.mk_true(), m); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index aeaa88bc2..746856543 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -149,7 +149,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref lookahead(expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(assumptions, candidates); } virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index d50dee57c..67be432c2 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -97,7 +97,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual expr_ref lookahead(expr_ref_vector const& candidates) { return m_solver->lookahead(candidates); } + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { return m_solver->lookahead(assumptions, candidates); } virtual void get_lemmas(expr_ref_vector & lemmas) { m_solver->get_lemmas(lemmas); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 46a5912b0..27e2a5850 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -93,7 +93,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref lookahead(expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(candidates); } + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(assumptions, candidates); } virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { From ce592d77160e956a824ba8d4668b3174203ef96c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Jun 2017 19:44:02 -0700 Subject: [PATCH 0164/1283] add facility to add lemmas Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 10 ++++++++++ src/api/dotnet/Solver.cs | 15 +++++++++++++++ src/api/z3_api.h | 10 ++++++++++ src/opt/opt_solver.h | 1 + src/sat/sat_solver.cpp | 14 +++++++------- src/sat/sat_solver.h | 8 ++++---- src/sat/sat_solver/inc_sat_solver.cpp | 18 ++++++++++++++---- src/sat/tactic/goal2sat.cpp | 15 ++++++++++----- src/sat/tactic/goal2sat.h | 3 ++- src/smt/smt_solver.cpp | 4 ++++ src/solver/combined_solver.cpp | 6 ++++++ src/solver/solver.h | 6 ++++++ src/solver/tactic2solver.cpp | 4 ++++ src/tactic/portfolio/bounded_int2bv_solver.cpp | 4 ++++ src/tactic/portfolio/enum2bv_solver.cpp | 10 ++++++++++ src/tactic/portfolio/pb2bv_solver.cpp | 4 ++++ 16 files changed, 111 insertions(+), 21 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 09e522db2..0d6383970 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -258,6 +258,16 @@ extern "C" { to_solver_ref(s)->assert_expr(to_expr(a), to_expr(p)); Z3_CATCH; } + + void Z3_API Z3_solver_assert_lemma(Z3_context c, Z3_solver s, Z3_ast a) { + Z3_TRY; + LOG_Z3_solver_assert_lemma(c, s, a); + RESET_ERROR_CODE(); + init_solver(c, s); + CHECK_FORMULA(a,); + to_solver_ref(s)->assert_lemma(to_expr(a)); + Z3_CATCH; + } Z3_ast_vector Z3_API Z3_solver_get_assertions(Z3_context c, Z3_solver s) { Z3_TRY; diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 078f5bc7a..d2c63ecce 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -181,6 +181,21 @@ namespace Microsoft.Z3 Native.Z3_solver_assert_and_track(Context.nCtx, NativeObject, constraint.NativeObject, p.NativeObject); } + /// + /// Assert a lemma (or multiple) into the solver. + /// + public void AssertLemma(params BoolExpr[] constraints) + { + Contract.Requires(constraints != null); + Contract.Requires(Contract.ForAll(constraints, c => c != null)); + + Context.CheckContextMatch(constraints); + foreach (BoolExpr a in constraints) + { + Native.Z3_solver_assert_lemma(Context.nCtx, NativeObject, a.NativeObject); + } + } + /// /// The number of assertions in the solver. /// diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 317b32923..85d007e70 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5949,6 +5949,16 @@ extern "C" { */ void Z3_API Z3_solver_assert_and_track(Z3_context c, Z3_solver s, Z3_ast a, Z3_ast p); + /** + \brief add a lemma. A lemma is a assumed to be a consequence of the current assertions. + Adding a lemma should therefore be a logical no-op. Solvers are free to ignore lemmas. + + \pre \c a must be a Boolean expression + + def_API('Z3_solver_assert_lemma', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST))) + */ + void Z3_API Z3_solver_assert_lemma(Z3_context c, Z3_solver s, Z3_ast a); + /** \brief Return the set of asserted formulas on the solver. diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index cef270abc..1f15a44d0 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -92,6 +92,7 @@ namespace opt { virtual void collect_param_descrs(param_descrs & r); virtual void collect_statistics(statistics & st) const; virtual void assert_expr(expr * t); + virtual void assert_lemma(expr* t) {} virtual void push_core(); virtual void pop_core(unsigned n); virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 77a816660..36cf9b526 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -209,7 +209,7 @@ namespace sat { } } - void solver::mk_clause(unsigned num_lits, literal * lits) { + void solver::mk_clause(unsigned num_lits, literal * lits, bool learned) { m_model_is_current = false; DEBUG_CODE({ for (unsigned i = 0; i < num_lits; i++) @@ -217,24 +217,24 @@ namespace sat { }); if (m_user_scope_literals.empty()) { - mk_clause_core(num_lits, lits, false); + mk_clause_core(num_lits, lits, learned); } else { m_aux_literals.reset(); m_aux_literals.append(num_lits, lits); m_aux_literals.append(m_user_scope_literals); - mk_clause_core(m_aux_literals.size(), m_aux_literals.c_ptr(), false); + mk_clause_core(m_aux_literals.size(), m_aux_literals.c_ptr(), learned); } } - void solver::mk_clause(literal l1, literal l2) { + void solver::mk_clause(literal l1, literal l2, bool learned) { literal ls[2] = { l1, l2 }; - mk_clause(2, ls); + mk_clause(2, ls, learned); } - void solver::mk_clause(literal l1, literal l2, literal l3) { + void solver::mk_clause(literal l1, literal l2, literal l3, bool learned) { literal ls[3] = { l1, l2, l3 }; - mk_clause(3, ls); + mk_clause(3, ls, learned); } void solver::del_clause(clause& c) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b6dffe511..9da445cad 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -203,10 +203,10 @@ namespace sat { // // ----------------------- bool_var mk_var(bool ext = false, bool dvar = true); - void mk_clause(literal_vector const& lits) { mk_clause(lits.size(), lits.c_ptr()); } - void mk_clause(unsigned num_lits, literal * lits); - void mk_clause(literal l1, literal l2); - void mk_clause(literal l1, literal l2, literal l3); + void mk_clause(literal_vector const& lits, bool learned = false) { mk_clause(lits.size(), lits.c_ptr(), learned); } + void mk_clause(unsigned num_lits, literal * lits, bool learned = false); + void mk_clause(literal l1, literal l2, bool learned = false); + void mk_clause(literal l1, literal l2, literal l3, bool learned = false); protected: void del_clause(clause & c); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 9d9c24b8f..4cff85510 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -241,6 +241,16 @@ public: assert_expr(t); } } + + virtual void assert_lemma(expr* e) { + dep2asm_t dep2asm; + goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled + for (unsigned i = m_fmls_head ; i < m_fmls.size(); ++i) { + g->assert_expr(m_fmls[i].get()); + } + VERIFY(l_undef != internalize_goal(g, dep2asm, true)); + } + virtual ast_manager& get_manager() const { return m; } virtual void assert_expr(expr * t) { m_internalized = false; @@ -501,7 +511,7 @@ public: private: - lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm) { + lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm, bool is_lemma) { m_mc.reset(); m_pc.reset(); m_dep_core.reset(); @@ -527,7 +537,7 @@ private: g = m_subgoals[0]; expr_ref_vector atoms(m); TRACE("sat", g->display_with_dependencies(tout);); - m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true, is_lemma); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { std::stringstream strm; @@ -552,7 +562,7 @@ private: for (unsigned i = 0; i < get_num_assumptions(); ++i) { g->assert_expr(get_assumption(i), m.mk_leaf(get_assumption(i))); } - lbool res = internalize_goal(g, dep2asm); + lbool res = internalize_goal(g, dep2asm, false); if (res == l_true) { extract_assumptions(sz, asms, dep2asm); } @@ -673,7 +683,7 @@ private: for (unsigned i = m_fmls_head ; i < m_fmls.size(); ++i) { g->assert_expr(m_fmls[i].get()); } - lbool res = internalize_goal(g, dep2asm); + lbool res = internalize_goal(g, dep2asm, false); if (res != l_undef) { m_fmls_head = m_fmls.size(); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index cb4a19e89..eb3bc9d3e 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -67,6 +67,7 @@ struct goal2sat::imp { expr_ref_vector m_interpreted_atoms; bool m_default_external; bool m_xor_solver; + bool m_is_lemma; imp(ast_manager & _m, params_ref const & p, sat::solver & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external): m(_m), @@ -77,7 +78,8 @@ struct goal2sat::imp { m_dep2asm(dep2asm), m_trail(m), m_interpreted_atoms(m), - m_default_external(default_external) { + m_default_external(default_external), + m_is_lemma(false) { updt_params(p); m_true = sat::null_bool_var; } @@ -98,19 +100,21 @@ struct goal2sat::imp { m_solver.mk_clause(1, &l); } + void set_lemma_mode(bool f) { m_is_lemma = f; } + void mk_clause(sat::literal l1, sat::literal l2) { TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << "\n";); - m_solver.mk_clause(l1, l2); + m_solver.mk_clause(l1, l2, m_is_lemma); } void mk_clause(sat::literal l1, sat::literal l2, sat::literal l3) { TRACE("goal2sat", tout << "mk_clause: " << l1 << " " << l2 << " " << l3 << "\n";); - m_solver.mk_clause(l1, l2, l3); + m_solver.mk_clause(l1, l2, l3, m_is_lemma); } void mk_clause(unsigned num, sat::literal * lits) { TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < num; i++) tout << lits[i] << " "; tout << "\n";); - m_solver.mk_clause(num, lits); + m_solver.mk_clause(num, lits, m_is_lemma); } sat::bool_var mk_true() { @@ -863,9 +867,10 @@ struct goal2sat::scoped_set_imp { }; -void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external) { +void goal2sat::operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external, bool is_lemma) { imp proc(g.m(), p, t, m, dep2asm, default_external); scoped_set_imp set(this, &proc); + proc.set_lemma_mode(is_lemma); proc(g); dealloc(m_interpreted_atoms); m_interpreted_atoms = alloc(expr_ref_vector, g.m()); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 5bfb28f60..9dfb5b24f 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -50,6 +50,7 @@ public: static bool has_unsupported_bool(goal const & s); + /** \brief "Compile" the goal into the given sat solver. Store a mapping from atoms to boolean variables into m. @@ -60,7 +61,7 @@ public: \warning conversion throws a tactic_exception, if it is interrupted (by set_cancel), an unsupported operator is found, or memory consumption limit is reached (set with param :max-memory). */ - void operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external = false); + void operator()(goal const & g, params_ref const & p, sat::solver & t, atom2bool_var & m, dep2asm_map& dep2asm, bool default_external = false, bool is_lemma = false); void get_interpreted_atoms(expr_ref_vector& atoms); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index ef81fbfd2..d7ecbfd50 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -116,6 +116,10 @@ namespace smt { m_name2assertion.insert(a, t); } + virtual void assert_lemma(expr* t) { + // no-op + } + virtual void push_core() { m_context.push(); } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index b23aabc2d..c35a794e5 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -179,6 +179,12 @@ public: m_solver2->assert_expr(t, a); } + virtual void assert_lemma(expr* t) { + m_solver1->assert_lemma(t); + if (m_solver2_initialized) + m_solver2->assert_lemma(t); + } + virtual void push() { switch_inc_mode(); m_solver1->push(); diff --git a/src/solver/solver.h b/src/solver/solver.h index 5346cf4a4..f32c10887 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -90,6 +90,12 @@ public: */ virtual void assert_expr(expr * t, expr * a) = 0; + /** + \brief Add a lemma to the assertion stack. A lemma is assumed to be a consequence of already + asserted formulas. The solver is free to ignore lemmas. + */ + virtual void assert_lemma(expr * t) = 0; + /** \brief Create a backtracking point. */ diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index d3d8e59ce..6743eac74 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -55,6 +55,7 @@ public: virtual void set_produce_models(bool f) { m_produce_models = f; } virtual void assert_expr(expr * t); + virtual void assert_lemma(expr * t); virtual void push_core(); virtual void pop_core(unsigned n); @@ -115,6 +116,9 @@ void tactic2solver::assert_expr(expr * t) { m_result = 0; } +void tactic2solver::assert_lemma(expr * t) { +} + void tactic2solver::push_core() { m_scopes.push_back(m_assertions.size()); m_result = 0; diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 746856543..4ef909234 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -93,6 +93,10 @@ public: } } + virtual void assert_lemma(expr * t) { + m_solver->assert_lemma(t); + } + virtual void push_core() { flush_assertions(); m_solver->push(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 67be432c2..39519af4e 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -64,6 +64,16 @@ public: m_solver->assert_expr(bounds); } + virtual void assert_lemma(expr* t) { + expr_ref tmp(t, m); + expr_ref_vector bounds(m); + proof_ref tmp_proof(m); + m_rewriter(t, tmp, tmp_proof); + m_solver->assert_lemma(tmp); + m_rewriter.flush_side_constraints(bounds); + m_solver->assert_expr(bounds); + } + virtual void push_core() { m_rewriter.push(); m_solver->push(); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 27e2a5850..29f3314cb 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -56,6 +56,10 @@ public: m_assertions.push_back(t); } + virtual void assert_lemma(expr * t) { + m_solver->assert_lemma(t); + } + virtual void push_core() { flush_assertions(); m_rewriter.push(); From c6fbe38f780e9b45bcafea816d22bf52dae91b0c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Jun 2017 23:56:50 -0500 Subject: [PATCH 0165/1283] disable anti-exploration by default Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Solver.cs | 8 ++++++++ src/sat/sat_config.cpp | 2 +- src/sat/sat_params.pyg | 3 ++- src/sat/sat_solver.cpp | 4 ++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index d2c63ecce..40da086ce 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -196,6 +196,14 @@ namespace Microsoft.Z3 } } + /// + /// Assert a lemma (or multiple) into the solver. + /// + public void AddLemma(IEnumerable constraints) + { + AssertLemma(constraints.ToArray()); + } + /// /// The number of assertions in the solver. /// diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 3d803d164..559317976 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -141,7 +141,7 @@ namespace sat { else { throw sat_param_exception("invalid branching heuristic: accepted heuristics are 'vsids', 'lrb' or 'chb'"); } - m_anti_exploration = m_branching_heuristic != BH_VSIDS; + m_anti_exploration = p.branching_anti_exploration(); m_step_size_init = 0.40; m_step_size_dec = 0.000001; m_step_size_min = 0.06; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index c60ceee07..211b3b2bd 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -10,6 +10,7 @@ def_module_params('sat', ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), ('branching.heuristic', SYMBOL, 'vsids', 'branching heuristic vsids, lrb or chb'), + ('branching.anti_exploration', BOOL, False, 'apply anti-exploration heuristic for branch selection'), ('random_freq', DOUBLE, 0.01, 'frequency of random case splits'), ('random_seed', UINT, 0, 'random seed'), ('burst_search', UINT, 100, 'number of conflicts before first global simplification'), @@ -22,7 +23,7 @@ def_module_params('sat', ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), - ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('threads', UINT, 1, 'number of parallel threads to use'), + ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 36cf9b526..0341b9269 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1194,9 +1194,9 @@ namespace sat { return l_true; if (!resolve_conflict()) return l_false; - if (m_conflicts > m_config.m_max_conflicts) + if (m_conflicts > m_config.m_max_conflicts) return l_undef; - if (m_conflicts_since_restart > m_restart_threshold) + if (m_conflicts_since_restart > m_restart_threshold) return l_undef; if (at_base_lvl()) { cleanup(); // cleaner may propagate frozen clauses From 5f93b9a081b5bbb12529e7adb87adaaea33b8fab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Jun 2017 10:30:30 -0700 Subject: [PATCH 0166/1283] add N-ary clause reward heuristic based on discussions with Heule Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 134 ++++++++++++++++++++++++++------------ src/sat/sat_lookahead.h | 27 ++++---- 2 files changed, 108 insertions(+), 53 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index eeeff2c11..763126398 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -367,6 +367,7 @@ namespace sat { } void lookahead::init_pre_selection(unsigned level) { + if (!m_config.m_use_ternary_reward) return; unsigned max_level = m_config.m_max_hlevel; if (level <= 1) { ensure_H(2); @@ -888,6 +889,12 @@ namespace sat { for (; it != end; ++it) { clause& c = *(*it); if (c.was_removed()) continue; +#if 0 + // enable when there is a non-ternary reward system. + if (c.size() > 3) { + m_config.m_use_ternary_reward = false; + } +#endif clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); m_clauses.push_back(c1); attach_clause(*c1); @@ -1004,7 +1011,7 @@ namespace sat { TRACE("sat", tout << "windfall: " << nlit << " " << l2 << "\n";); // if we use try_add_binary, then this may produce new assignments // these assignments get put on m_trail, and they are cleared by - // reset_wnb. We would need to distinguish the trail that comes + // reset_lookahead_reward. We would need to distinguish the trail that comes // from lookahead levels and the main search level for this to work. add_binary(nlit, l2); } @@ -1079,7 +1086,7 @@ namespace sat { skip = true; break; case lookahead_mode::lookahead1: - m_weighted_new_binaries += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + update_binary_clause_reward(l1, l2); break; case lookahead2: break; @@ -1133,20 +1140,14 @@ namespace sat { try_add_binary(c[0], c[1]); break; case lookahead_mode::lookahead1: - m_weighted_new_binaries += (*m_heur)[c[0].index()]* (*m_heur)[c[1].index()]; + update_binary_clause_reward(c[0], c[1]); break; case lookahead_mode::lookahead2: break; } } - else if (found && m_search_mode == lookahead_mode::lookahead1 && m_weighted_new_binaries == 0) { - // leave a trail that some clause was reduced but potentially not an autarky - l_it = c.begin() + 2; - found = false; - for (; l_it != l_end && !found; found = is_true(*l_it), ++l_it) ; - if (!found) { - m_weighted_new_binaries = (double)0.001; - } + else if (found && m_search_mode == lookahead_mode::lookahead1) { + update_nary_clause_reward(c); } break; } @@ -1192,6 +1193,53 @@ namespace sat { wlist.set_end(it2); } + void lookahead::update_binary_clause_reward(literal l1, literal l2) { + SASSERT(!is_false(l1)); + SASSERT(!is_false(l2)); + if (m_config.m_use_ternary_reward) { + m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + } + else { + m_lookahead_reward += 0.5 * (literal_occs(l1) + literal_occs(l2)); + } + } + + void lookahead::update_nary_clause_reward(clause const& c) { + if (m_config.m_use_ternary_reward && m_lookahead_reward != 0) { + return; + } + literal const * l_it = c.begin() + 2, *l_end = c.end(); + unsigned sz = 0; + for (; l_it != l_end; ++l_it) { + if (is_true(*l_it)) return; + if (!is_false(*l_it)) ++sz; + } + if (!m_config.m_use_ternary_reward) { + SASSERT(sz > 0); + double to_add = 0; + for (literal l : c) { + if (!is_false(l)) { + to_add += literal_occs(l); + } + } + m_lookahead_reward += pow(sz, -2) * to_add; + } + else { + m_lookahead_reward = (double)0.001; + } + } + + // Sum_{ clause C that contains ~l } 1 / |C| + double lookahead::literal_occs(literal l) { + double result = m_binary[l.index()].size(); + for (clause const* c : m_full_watches[l.index()]) { + if (!is_true((*c)[0]) && !is_true((*c)[1])) { + result += 1.0 / c->size(); + } + } + return result; + } + void lookahead::propagate_binary(literal l) { literal_vector const& lits = m_binary[l.index()]; TRACE("sat", tout << l << " => " << lits << "\n";); @@ -1201,6 +1249,7 @@ namespace sat { } } + void lookahead::propagate() { while (!inconsistent() && m_qhead < m_trail.size()) { unsigned i = m_qhead; @@ -1220,8 +1269,8 @@ namespace sat { TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } - void lookahead::compute_wnb() { - init_wnb(); + void lookahead::compute_lookahead_reward() { + init_lookahead_reward(); TRACE("sat", display_lookahead(tout); ); unsigned base = 2; bool change = true; @@ -1240,21 +1289,21 @@ namespace sat { IF_VERBOSE(30, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); } TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); - reset_wnb(lit); + reset_lookahead_reward(lit); push_lookahead1(lit, level); if (!first) do_double(lit, base); bool unsat = inconsistent(); pop_lookahead1(lit); if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); - reset_wnb(); + reset_lookahead_reward(); assign(~lit); propagate(); - init_wnb(); + init_lookahead_reward(); change = true; } else { - update_wnb(lit, level); + update_lookahead_reward(lit, level); } SASSERT(inconsistent() || !is_unsat()); } @@ -1265,23 +1314,23 @@ namespace sat { first = false; change = true; } - reset_wnb(); - init_wnb(); + reset_lookahead_reward(); + init_lookahead_reward(); // base += 2 * m_lookahead.size(); } - reset_wnb(); + reset_lookahead_reward(); TRACE("sat", display_lookahead(tout); ); } - void lookahead::init_wnb() { - TRACE("sat", tout << "init_wnb: " << m_qhead << "\n";); + void lookahead::init_lookahead_reward() { + TRACE("sat", tout << "init_lookahead_reward: " << m_qhead << "\n";); m_qhead_lim.push_back(m_qhead); m_trail_lim.push_back(m_trail.size()); } - void lookahead::reset_wnb() { + void lookahead::reset_lookahead_reward() { m_qhead = m_qhead_lim.back(); - TRACE("sat", tout << "reset_wnb: " << m_qhead << "\n";); + TRACE("sat", tout << "reset_lookahead_reward: " << m_qhead << "\n";); unsigned old_sz = m_trail_lim.back(); for (unsigned i = old_sz; i < m_trail.size(); ++i) { set_undef(m_trail[i]); @@ -1300,7 +1349,7 @@ namespace sat { if (lit.sign() || !is_undef(lit)) { continue; } - double diff1 = get_wnb(lit), diff2 = get_wnb(~lit); + double diff1 = get_lookahead_reward(lit), diff2 = get_lookahead_reward(~lit); double mixd = mix_diff(diff1, diff2); if (mixd == h) ++count; @@ -1317,12 +1366,13 @@ namespace sat { } - void lookahead::reset_wnb(literal l) { - m_weighted_new_binaries = 0; + void lookahead::reset_lookahead_reward(literal l) { + + m_lookahead_reward = 0; // inherit propagation effect from parent. literal p = get_parent(l); - set_wnb(l, p == null_literal ? 0 : get_wnb(p)); + set_lookahead_reward(l, p == null_literal ? 0 : get_lookahead_reward(p)); } bool lookahead::check_autarky(literal l, unsigned level) { @@ -1361,22 +1411,22 @@ namespace sat { } - void lookahead::update_wnb(literal l, unsigned level) { - if (m_weighted_new_binaries == 0) { + void lookahead::update_lookahead_reward(literal l, unsigned level) { + if (m_lookahead_reward == 0) { if (!check_autarky(l, level)) { // skip } - else if (get_wnb(l) == 0) { + else if (get_lookahead_reward(l) == 0) { ++m_stats.m_autarky_propagations; IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] << " " << (!m_binary[l.index()].empty() || !m_full_watches[l.index()].empty()) << "\n";); - reset_wnb(); + reset_lookahead_reward(); assign(l); propagate(); - init_wnb(); + init_lookahead_reward(); } else { ++m_stats.m_autarky_equivalences; @@ -1396,17 +1446,17 @@ namespace sat { } } else { - inc_wnb(l, m_weighted_new_binaries); + inc_lookahead_reward(l, m_lookahead_reward); } } void lookahead::do_double(literal l, unsigned& base) { if (!inconsistent() && scope_lvl() > 1 && dl_enabled(l)) { - if (get_wnb(l) > m_delta_trigger) { + if (get_lookahead_reward(l) > m_delta_trigger) { if (dl_no_overflow(base)) { ++m_stats.m_double_lookahead_rounds; double_look(l, base); - m_delta_trigger = get_wnb(l); + m_delta_trigger = get_lookahead_reward(l); dl_disable(l); } } @@ -1422,7 +1472,7 @@ namespace sat { unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); scoped_level _sl(*this, dl_truth); IF_VERBOSE(2, verbose_stream() << "double: " << l << "\n";); - init_wnb(); + init_lookahead_reward(); assign(l); propagate(); bool change = true; @@ -1438,16 +1488,16 @@ namespace sat { TRACE("sat", tout << "unit: " << ~lit << "\n";); ++m_stats.m_double_lookahead_propagations; SASSERT(m_level == dl_truth); - reset_wnb(); + reset_lookahead_reward(); assign(~lit); propagate(); change = true; - init_wnb(); + init_lookahead_reward(); } } SASSERT(dl_truth - 2 * m_lookahead.size() > base); } - reset_wnb(); + reset_lookahead_reward(); SASSERT(m_level == dl_truth); base = dl_truth; } @@ -1585,7 +1635,7 @@ namespace sat { unsigned offset = m_lookahead[i].m_offset; out << lit << "\toffset: " << offset; out << (is_undef(lit)?" undef": (is_true(lit) ? " true": " false")); - out << " wnb: " << get_wnb(lit); + out << " lookahead_reward: " << get_lookahead_reward(lit); out << "\n"; } return out; @@ -1613,7 +1663,7 @@ namespace sat { if (m_lookahead.empty()) { break; } - compute_wnb(); + compute_lookahead_reward(); if (inconsistent()) { break; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 2b8ddc594..211fa41dd 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -76,6 +76,7 @@ namespace sat { double m_delta_rho; unsigned m_dl_max_iterations; unsigned m_tc1_limit; + bool m_use_ternary_reward; config() { m_max_hlevel = 50; @@ -86,6 +87,7 @@ namespace sat { m_delta_rho = (double)0.9995; m_dl_max_iterations = 32; m_tc1_limit = 10000000; + m_use_ternary_reward = true; } }; @@ -96,9 +98,9 @@ namespace sat { }; struct lit_info { - double m_wnb; + double m_lookahead_reward; unsigned m_double_lookahead; - lit_info(): m_wnb(0), m_double_lookahead(0) {} + lit_info(): m_lookahead_reward(0), m_double_lookahead(0) {} }; struct stats { @@ -156,7 +158,7 @@ namespace sat { vector m_watches; // literal: watch structure svector m_lits; // literal: attributes. vector m_full_watches; // literal: full watch list, used to ensure that autarky reduction is sound - double m_weighted_new_binaries; // metric associated with current lookahead1 literal. + double m_lookahead_reward; // metric associated with current lookahead1 literal. literal_vector m_wstack; // windofall stack that is populated in lookahead1 mode uint64 m_prefix; // where we are in search tree svector m_vprefix; // var: prefix where variable participates in propagation @@ -393,18 +395,21 @@ namespace sat { void propagate_binary(literal l); void propagate(); literal choose(); - void compute_wnb(); - void init_wnb(); - void reset_wnb(); + void compute_lookahead_reward(); + void init_lookahead_reward(); + void reset_lookahead_reward(); literal select_literal(); + void update_binary_clause_reward(literal l1, literal l2); + void update_nary_clause_reward(clause const& c); + double literal_occs(literal l); - void set_wnb(literal l, double f) { m_lits[l.index()].m_wnb = f; } - void inc_wnb(literal l, double f) { m_lits[l.index()].m_wnb += f; } - double get_wnb(literal l) const { return m_lits[l.index()].m_wnb; } + void set_lookahead_reward(literal l, double f) { m_lits[l.index()].m_lookahead_reward = f; } + void inc_lookahead_reward(literal l, double f) { m_lits[l.index()].m_lookahead_reward += f; } + double get_lookahead_reward(literal l) const { return m_lits[l.index()].m_lookahead_reward; } - void reset_wnb(literal l); + void reset_lookahead_reward(literal l); bool check_autarky(literal l, unsigned level); - void update_wnb(literal l, unsigned level); + void update_lookahead_reward(literal l, unsigned level); bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; } void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } bool dl_no_overflow(unsigned base) const { return base + 2 * m_lookahead.size() * static_cast(m_config.m_dl_max_iterations + 1) < c_fixed_truth; } From 5e2f7f7177bf7f4d5f5b66cd7bd5db0f4e07ffab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Jun 2017 20:22:31 -0700 Subject: [PATCH 0167/1283] fixes top lookahead simplification Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 29 ++++++++++++++++++++--------- src/sat/sat_simplifier.cpp | 10 ---------- src/sat/sat_solver.cpp | 2 ++ src/util/uint_set.h | 1 + 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 763126398..955b3766c 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -841,6 +841,7 @@ namespace sat { unsigned sz = m_s.m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { literal l = ~to_literal(l_idx); + if (m_s.was_eliminated(l.var())) continue; watch_list const & wlist = m_s.m_watches[l_idx]; watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); @@ -848,9 +849,7 @@ namespace sat { if (!it->is_binary_non_learned_clause()) continue; literal l2 = it->get_literal(); - SASSERT(!m_s.was_eliminated(l.var())); - SASSERT(!m_s.was_eliminated(l2.var())); - if (l.index() < l2.index()) + if (l.index() < l2.index() && !m_s.was_eliminated(l2.var())) add_binary(l, l2); } } @@ -895,6 +894,12 @@ namespace sat { m_config.m_use_ternary_reward = false; } #endif + bool was_eliminated = false; + for (unsigned i = 0; !was_eliminated && i < c.size(); ++i) { + was_eliminated = m_s.was_eliminated(c[i].var()); + } + if (was_eliminated) continue; + clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); m_clauses.push_back(c1); attach_clause(*c1); @@ -1519,7 +1524,9 @@ namespace sat { if (m_search_mode == lookahead_mode::searching) { m_stats.m_propagations++; TRACE("sat", tout << "removing free var v" << l.var() << "\n";); - m_freevars.remove(l.var()); + if (l.var() > m_freevars.max_var()) std::cout << "bigger than max-var: " << l << " " << " " << m_freevars.max_var() << "\n"; + if (!m_freevars.contains(l.var())) std::cout << "does not contain: " << l << " eliminated: " << m_s.was_eliminated(l.var()) << "\n"; + if (m_freevars.contains(l.var())) { m_freevars.remove(l.var()); } validate_assign(l); } } @@ -1722,16 +1729,20 @@ namespace sat { if (inconsistent()) return; SASSERT(m_trail_lim.empty()); unsigned num_units = 0; - for (unsigned i = 0; i < m_trail.size(); ++i) { + + for (unsigned i = 0; i < m_trail.size() && !m_s.inconsistent(); ++i) { literal lit = m_trail[i]; if (m_s.value(lit) == l_undef && !m_s.was_eliminated(lit.var())) { - m_s.m_simplifier.propagate_unit(lit); + m_s.assign(lit, justification()); ++num_units; } - } + } IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << ")\n";); - - m_s.m_simplifier.subsume(); + + if (num_units > 0 && !m_s.inconsistent()) { + m_s.propagate_core(false); + m_s.m_simplifier(false); + } m_lookahead.reset(); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index afeed35be..366e994ae 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -166,10 +166,7 @@ namespace sat { CASSERT("sat_solver", s.check_invariant()); TRACE("before_simplifier", s.display(tout);); - m_sub_todo.reset(); - m_sub_bin_todo.reset(); s.m_cleaner(true); - m_last_sub_trail_sz = s.m_trail.size(); TRACE("after_cleanup", s.display(tout);); CASSERT("sat_solver", s.check_invariant()); m_need_cleanup = false; @@ -223,13 +220,6 @@ namespace sat { } } - if (!learned && s.m_config.m_lookahead_simplify) { - // perform lookahead simplification - lookahead lh(s); - lh.simplify(); - lh.collect_statistics(s.m_aux_stats); - } - CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0341b9269..078acfb6e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1355,6 +1355,7 @@ namespace sat { m_luby_idx = 1; m_gc_threshold = m_config.m_gc_initial; m_restarts = 0; + m_conflicts = 0; m_min_d_tk = 1.0; m_search_lvl = 0; m_stopwatch.reset(); @@ -1399,6 +1400,7 @@ namespace sat { if (m_config.m_lookahead_simplify) { lookahead lh(*this); + lh.simplify(); lh.scc(); lh.collect_statistics(m_aux_stats); } diff --git a/src/util/uint_set.h b/src/util/uint_set.h index f0990492b..c345f1092 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -369,6 +369,7 @@ public: void reset() { m_size = 0; } bool empty() const { return m_size == 0; } unsigned size() const { return m_size; } + unsigned max_var() const { return m_index.size(); } typedef unsigned_vector::const_iterator iterator; iterator begin() const { return m_elems.begin(); } iterator end() const { return m_elems.begin() + m_size; } From 9ebe980b440a09fdaa3efea8c25a395d25856c1d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jun 2017 07:42:44 -0700 Subject: [PATCH 0168/1283] cleaning up lookahead Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 7 +------ src/sat/sat_params.pyg | 3 ++- src/sat/sat_simplifier.cpp | 1 - src/sat/sat_solver.cpp | 24 ++++++++++++------------ src/sat/sat_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 4 +--- 6 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 955b3766c..95b11fa15 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -299,7 +299,6 @@ namespace sat { bool_var x = *it; if (!m_select_lookahead_vars.empty()) { if (m_select_lookahead_vars.contains(x)) { - // IF_VERBOSE(1, verbose_stream() << x << " " << m_rating[x] << "\n";); m_candidates.push_back(candidate(x, m_rating[x])); sum += m_rating[x]; } @@ -309,7 +308,6 @@ namespace sat { sum += m_rating[x]; } } - IF_VERBOSE(1, verbose_stream() << " " << sum << " " << m_candidates.size() << "\n";); TRACE("sat", display_candidates(tout << "sum: " << sum << "\n");); return sum; } @@ -424,12 +422,9 @@ namespace sat { literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); for (; it != end; ++it) { bool_var v = it->var(); - if (it->index() >= h.size()) - IF_VERBOSE(0, verbose_stream() << l << " " << *it << " " << h.size() << "\n";); if (is_undef(*it)) sum += h[it->index()]; // if (m_freevars.contains(it->var())) sum += h[it->index()]; } - // std::cout << "sum: " << sum << "\n"; watch_list& wlist = m_watches[l.index()]; watch_list::iterator wit = wlist.begin(), wend = wlist.end(); for (; wit != wend; ++wit) { @@ -930,7 +925,7 @@ namespace sat { } void lookahead::pop() { - if (m_assumptions.empty()) IF_VERBOSE(0, verbose_stream() << "empty pop\n";); + SASSERT(!m_assumptions.empty()); m_assumptions.pop_back(); m_inconsistent = false; SASSERT(m_search_mode == lookahead_mode::searching); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 211b3b2bd..58873f517 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -23,7 +23,8 @@ def_module_params('sat', ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), - ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), ('threads', UINT, 1, 'number of parallel threads to use'), + ('core.minimize_partial', BOOL, False, 'apply partial (cheap) core minimization'), + ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 366e994ae..5e218f278 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -21,7 +21,6 @@ Revision History: #include"sat_simplifier.h" #include"sat_simplifier_params.hpp" #include"sat_solver.h" -#include"sat_lookahead.h" #include"stopwatch.h" #include"trace.h" diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 078acfb6e..c3b464716 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -60,7 +60,7 @@ namespace sat { init_reason_unknown(); updt_params(p); m_conflicts_since_gc = 0; - m_conflicts = 0; + m_conflicts_since_init = 0; m_next_simplify = 0; m_num_checkpoints = 0; } @@ -881,9 +881,9 @@ namespace sat { if (r != l_undef) return r; - if (m_conflicts > m_config.m_max_conflicts) { + if (m_conflicts_since_init > m_config.m_max_conflicts) { m_reason_unknown = "sat.max.conflicts"; - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts << "\")\n";); + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts_since_init << "\")\n";); return l_undef; } @@ -1194,7 +1194,7 @@ namespace sat { return l_true; if (!resolve_conflict()) return l_false; - if (m_conflicts > m_config.m_max_conflicts) + if (m_conflicts_since_init > m_config.m_max_conflicts) return l_undef; if (m_conflicts_since_restart > m_restart_threshold) return l_undef; @@ -1355,7 +1355,7 @@ namespace sat { m_luby_idx = 1; m_gc_threshold = m_config.m_gc_initial; m_restarts = 0; - m_conflicts = 0; + m_conflicts_since_init = 0; m_min_d_tk = 1.0; m_search_lvl = 0; m_stopwatch.reset(); @@ -1371,7 +1371,7 @@ namespace sat { */ void solver::simplify_problem() { - if (m_conflicts < m_next_simplify) { + if (m_conflicts_since_init < m_next_simplify) { return; } IF_VERBOSE(2, verbose_stream() << "(sat.simplify)\n";); @@ -1429,9 +1429,9 @@ namespace sat { m_next_simplify = m_config.m_restart_initial * m_config.m_simplify_mult1; } else { - m_next_simplify = static_cast(m_conflicts * m_config.m_simplify_mult2); - if (m_next_simplify > m_conflicts + m_config.m_simplify_max) - m_next_simplify = m_conflicts + m_config.m_simplify_max; + m_next_simplify = static_cast(m_conflicts_since_init * m_config.m_simplify_mult2); + if (m_next_simplify > m_conflicts_since_init + m_config.m_simplify_max) + m_next_simplify = m_conflicts_since_init + m_config.m_simplify_max; } } @@ -1882,7 +1882,7 @@ namespace sat { bool solver::resolve_conflict_core() { - m_conflicts++; + m_conflicts_since_init++; m_conflicts_since_restart++; m_conflicts_since_gc++; m_stats.m_conflict++; @@ -3551,8 +3551,8 @@ namespace sat { extract_fixed_consequences(num_units, asms, unfixed_vars, conseq); - if (m_conflicts > m_config.m_max_conflicts) { - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts << "\")\n";); + if (m_conflicts_since_init > m_config.m_max_conflicts) { + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts_since_init << "\")\n";); return l_undef; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 9da445cad..0dcd9837f 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -358,7 +358,7 @@ namespace sat { literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); protected: - unsigned m_conflicts; + unsigned m_conflicts_since_init; unsigned m_restarts; unsigned m_conflicts_since_restart; unsigned m_restart_threshold; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 4cff85510..5ba1fa136 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -323,7 +323,6 @@ public: IF_VERBOSE(0, verbose_stream() << "WARNING: could not handle " << mk_pp(c, m) << "\n";); } } - IF_VERBOSE(1, verbose_stream() << "vars: " << vars.size() << "\n";); if (vars.empty()) { return expr_ref(m.mk_true(), m); } @@ -336,15 +335,14 @@ public: return expr_ref(m.mk_true(), m); } expr_ref result(lit2expr[l.index()].get(), m); - IF_VERBOSE(1, verbose_stream() << "solution: " << l << " " << result << "\n";); return result; } virtual void get_lemmas(expr_ref_vector & lemmas) { - IF_VERBOSE(1, verbose_stream() << "(sat-get-lemmas " << lemmas.size() << ")\n";); if (!m_internalized) return; sat2goal s2g; goal g(m, false, false, false); s2g.get_learned(m_solver, m_map, m_params, lemmas); + IF_VERBOSE(1, verbose_stream() << "(sat :lemmas " << lemmas.size() << ")\n";); // TBD: handle externals properly. } From 5752830f7132375c58d86dd16252ce1cc74d80d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jun 2017 15:01:12 -0700 Subject: [PATCH 0169/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 8 +++-- src/sat/card_extension.cpp | 50 +++++++++++++++++++++------ src/sat/card_extension.h | 3 ++ src/sat/sat_config.cpp | 18 ++++++++++ src/sat/sat_config.h | 11 +++++- src/sat/sat_params.pyg | 2 +- src/sat/sat_solver.cpp | 40 ++++++++------------- src/sat/sat_solver/inc_sat_solver.cpp | 6 ++-- src/util/gparams.cpp | 2 ++ src/util/params.cpp | 18 ++++++++-- 10 files changed, 112 insertions(+), 46 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index bcc050048..68f10d10d 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -831,15 +831,17 @@ struct pb2bv_rewriter::imp { p.get_bool("keep_pb_constraints", false) || p.get_bool("sat.pb.solver", false) || p.get_bool("pb.solver", false) || - gparams::get_module("sat").get_bool("pb.solver", false); + gparams::get_module("sat").get_sym("pb.solver", symbol()) == symbol("solver") ; } bool pb_num_system() const { - return m_params.get_bool("pb_num_system", false); + return m_params.get_bool("pb_num_system", false) || + gparams::get_module("sat").get_sym("pb.solver", symbol()) == symbol("sorting"); } bool pb_totalizer() const { - return m_params.get_bool("pb_totalizer", false); + return m_params.get_bool("pb_totalizer", false) || + gparams::get_module("sat").get_sym("pb.solver", symbol()) == symbol("totalizer"); } imp(ast_manager& m, params_ref const& p): diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 0e3a24f56..0d0c148f1 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -241,7 +241,7 @@ namespace sat { if (slack < bound) { literal lit = p[j].second; - SASSERT(value(p[j].second) == l_false); + SASSERT(value(lit) == l_false); for (unsigned i = j + 1; i < sz; ++i) { if (lvl(lit) < lvl(p[i].second)) { lit = p[i].second; @@ -365,7 +365,10 @@ namespace sat { literal_vector to_assign; while (!m_pb_undef.empty()) { index1 = m_pb_undef.back(); + if (index1 == num_watch) index1 = index; // it was swapped with index above. literal lit = p[index1].second; + if (value(lit) != l_undef) std::cout << "not undef: " << index1 << " " << lit << " " << value(lit) << "\n"; + SASSERT(value(lit) == l_undef); TRACE("sat", tout << index1 << " " << lit << "\n";); if (slack >= bound + p[index1].first) { break; @@ -376,9 +379,7 @@ namespace sat { for (literal lit : to_assign) { if (inconsistent()) break; - if (value(lit) == l_undef) { - assign(p, lit); - } + assign(p, lit); } } @@ -594,8 +595,8 @@ namespace sat { unsigned sz = x.size(); TRACE("sat", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); - SASSERT(value(alit) != l_undef); SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); + SASSERT(value(alit) != l_undef); unsigned index = 0; for (; index <= 2; ++index) { if (x[index].var() == alit.var()) break; @@ -791,9 +792,7 @@ namespace sat { m_bound += offset; inc_coeff(consequent, offset); get_xor_antecedents(consequent, idx, js, m_lemma); - for (unsigned i = 0; i < m_lemma.size(); ++i) { - process_antecedent(~m_lemma[i], offset); - } + for (literal l : m_lemma) process_antecedent(~l, offset); ++m_stats.m_num_xor_resolves; } else if (is_pb_index(index)) { @@ -803,9 +802,7 @@ namespace sat { inc_coeff(consequent, offset); get_pb_antecedents(consequent, p, m_lemma); TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";); - for (unsigned i = 0; i < m_lemma.size(); ++i) { - process_antecedent(~m_lemma[i], offset); - } + for (literal l : m_lemma) process_antecedent(~l, offset); ++m_stats.m_num_pb_resolves; } else { @@ -1063,12 +1060,16 @@ namespace sat { void card_extension::propagate(literal l, ext_constraint_idx idx, bool & keep) { + SASSERT(value(l) == l_true); TRACE("sat", tout << l << " " << idx << "\n";); if (is_pb_index(idx)) { pb& p = index2pb(idx); if (l.var() == p.lit().var()) { init_watch(p, !l.sign()); } + else if (p.lit() != null_literal && value(p.lit()) != l_true) { + keep = false; + } else { keep = l_undef != add_assign(p, ~l); } @@ -1078,6 +1079,9 @@ namespace sat { if (l.var() == c.lit().var()) { init_watch(c, !l.sign()); } + else if (c.lit() != null_literal && value(c.lit()) != l_true) { + keep = false; + } else { keep = l_undef != add_assign(c, ~l); } @@ -1087,6 +1091,9 @@ namespace sat { if (l.var() == x.lit().var()) { init_watch(x, !l.sign()); } + else if (x.lit() != null_literal && value(x.lit()) != l_true) { + keep = false; + } else { keep = l_undef != add_assign(x, ~l); } @@ -1206,6 +1213,16 @@ namespace sat { SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); TRACE("sat", display(tout, p, true);); + if (value(l) == l_false) { + for (wliteral wl : p) { + literal lit = wl.second; + if (lit != l && value(lit) == l_false) { + r.push_back(~lit); + } + } + return; + } + // unsigned coeff = get_coeff(p, l); unsigned coeff = 0; for (unsigned j = 0; j < p.num_watch(); ++j) { @@ -1214,6 +1231,13 @@ namespace sat { break; } } + if (coeff == 0) { + + std::cout << l << " coeff: " << coeff << "\n"; + display(std::cout, p, true); + } + + SASSERT(coeff > 0); unsigned slack = p.slack() - coeff; unsigned i = p.num_watch(); @@ -1225,6 +1249,10 @@ namespace sat { } for (; i < p.size(); ++i) { literal lit = p[i].second; + if (l_false != value(lit)) { + std::cout << l << " index: " << i << " slack: " << slack << " h: " << h << " coeff: " << coeff << "\n"; + display(std::cout, p, true); + } SASSERT(l_false == value(lit)); r.push_back(~lit); } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 9720bde9c..3b9bfd5c0 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -82,6 +82,9 @@ namespace sat { unsigned index() const { return m_index; } literal lit() const { return m_lit; } wliteral operator[](unsigned i) const { return m_wlits[i]; } + wliteral const* begin() const { return m_wlits; } + wliteral const* end() const { return (wliteral const*)m_wlits + m_size; } + unsigned k() const { return m_k; } unsigned size() const { return m_size; } unsigned slack() const { return m_slack; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 559317976..2ed175ff3 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -147,6 +147,24 @@ namespace sat { m_step_size_min = 0.06; m_reward_multiplier = 0.9; m_reward_offset = 1000000.0; + + // PB parameters + s = p.pb_solver(); + if (s == symbol("circuit")) { + m_pb_solver = PB_CIRCUIT; + } + else if (s == symbol("sorting")) { + m_pb_solver = PB_SORTING; + } + else if (s == symbol("totalizer")) { + m_pb_solver = PB_TOTALIZER; + } + else if (s == symbol("solver")) { + m_pb_solver = PB_SOLVER; + } + else { + throw sat_param_exception("invalid PB solver"); + } } void config::collect_param_descrs(param_descrs & r) { diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index d8b0bc7d2..802e5e1bb 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -50,6 +50,13 @@ namespace sat { BH_LRB }; + enum pb_solver { + PB_SOLVER, + PB_CIRCUIT, + PB_SORTING, + PB_TOTALIZER + }; + struct config { unsigned long long m_max_memory; phase_selection m_phase; @@ -99,7 +106,9 @@ namespace sat { symbol m_psm; symbol m_glue; symbol m_glue_psm; - symbol m_psm_glue; + symbol m_psm_glue; + + pb_solver m_pb_solver; // branching heuristic settings. branching_heuristic m_branching_heuristic; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 58873f517..06edabc8b 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -29,7 +29,7 @@ def_module_params('sat', ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check', BOOL, False, 'build up internal proof and check'), ('cardinality.solver', BOOL, False, 'use cardinality solver'), - ('pb.solver', BOOL, False, 'use pb solver'), + ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), ('xor.solver', BOOL, False, 'use xor solver'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c3b464716..93021a16e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1961,10 +1961,8 @@ namespace sat { } case justification::EXT_JUSTIFICATION: { fill_ext_antecedents(consequent, js); - literal_vector::iterator it = m_ext_antecedents.begin(); - literal_vector::iterator end = m_ext_antecedents.end(); - for (; it != end; ++it) - process_antecedent(*it, num_marks); + for (literal l : m_ext_antecedents) + process_antecedent(l, num_marks); break; } default: @@ -2082,10 +2080,9 @@ namespace sat { } case justification::EXT_JUSTIFICATION: { fill_ext_antecedents(consequent, js); - literal_vector::iterator it = m_ext_antecedents.begin(); - literal_vector::iterator end = m_ext_antecedents.end(); - for (; it != end; ++it) - process_antecedent_for_unsat_core(*it); + for (literal l : m_ext_antecedents) { + process_antecedent_for_unsat_core(l); + } break; } default: @@ -2199,10 +2196,9 @@ namespace sat { SASSERT(not_l != null_literal); r = lvl(not_l); fill_ext_antecedents(~not_l, js); - literal_vector::iterator it = m_ext_antecedents.begin(); - literal_vector::iterator end = m_ext_antecedents.end(); - for (; it != end; ++it) - r = std::max(r, lvl(*it)); + for (literal l : m_ext_antecedents) { + r = std::max(r, lvl(l)); + } return r; } default: @@ -2414,10 +2410,8 @@ namespace sat { case justification::EXT_JUSTIFICATION: { literal consequent(var, value(var) == l_false); fill_ext_antecedents(consequent, js); - literal_vector::iterator it = m_ext_antecedents.begin(); - literal_vector::iterator end = m_ext_antecedents.end(); - for (; it != end; ++it) { - if (!process_antecedent_for_minimization(*it)) { + for (literal l : m_ext_antecedents) { + if (!process_antecedent_for_minimization(l)) { reset_unmark(old_size); return false; } @@ -2540,10 +2534,8 @@ namespace sat { } case justification::EXT_JUSTIFICATION: { fill_ext_antecedents(m_lemma[i], js); - literal_vector::iterator it = m_ext_antecedents.begin(); - literal_vector::iterator end = m_ext_antecedents.end(); - for (; it != end; ++it) { - update_lrb_reasoned(*it); + for (literal l : m_ext_antecedents) { + update_lrb_reasoned(l); } break; } @@ -3776,11 +3768,9 @@ namespace sat { } case justification::EXT_JUSTIFICATION: { fill_ext_antecedents(lit, js); - literal_vector::iterator it = m_ext_antecedents.begin(); - literal_vector::iterator end = m_ext_antecedents.end(); - for (; it != end; ++it) { - if (check_domain(lit, *it) && all_found) { - s |= m_antecedents.find(it->var()); + for (literal l : m_ext_antecedents) { + if (check_domain(lit, l) && all_found) { + s |= m_antecedents.find(l.var()); } else { all_found = false; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 5ba1fa136..6e124fcf3 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -266,8 +266,10 @@ public: m_params.append(p); sat_params p1(p); m_params.set_bool("elim_vars", false); - m_params.set_bool("keep_cardinality_constraints", p1.pb_solver() || p1.cardinality_solver()); - m_params.set_bool("keep_pb_constraints", p1.pb_solver()); + m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); + m_params.set_bool("keep_pb_constraints", m_solver.get_config().m_pb_solver == sat::PB_SOLVER); + m_params.set_bool("pb_num_system", m_solver.get_config().m_pb_solver == sat::PB_SORTING); + m_params.set_bool("pb_totalizer", m_solver.get_config().m_pb_solver == sat::PB_TOTALIZER); m_params.set_bool("xor_solver", p1.xor_solver()); m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 97f84af6a..0450f3bfd 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -425,6 +425,8 @@ public: return r; } + // unfortunately, params_ref is not thread safe + // so better create a local copy of the parameters. params_ref get_module(symbol const & module_name) { params_ref result; params_ref * ps = 0; diff --git a/src/util/params.cpp b/src/util/params.cpp index b869f8e3d..3024cf5cb 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -333,8 +333,21 @@ public: reset(); } - void inc_ref() { m_ref_count++; } - void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); } + void inc_ref() { + #pragma omp critical (params) + { + m_ref_count++; + } + } + void dec_ref() { + bool is_last; + SASSERT(m_ref_count > 0); + #pragma omp critical (params) + { + is_last = 0 == --m_ref_count; + } + if (is_last) dealloc(this); + } bool empty() const { return m_entries.empty(); } bool contains(symbol const & k) const; @@ -344,7 +357,6 @@ public: void reset(symbol const & k); void reset(char const * k); - void validate(param_descrs const & p) { svector::iterator it = m_entries.begin(); svector::iterator end = m_entries.end(); From 6caef86738bb1a573f1ea3e543ded360b5ee29f0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Jun 2017 21:05:54 -0700 Subject: [PATCH 0170/1283] translate Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/pb2bv_solver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 29f3314cb..d0e5598c7 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -49,6 +49,7 @@ public: virtual ~pb2bv_solver() {} virtual solver* translate(ast_manager& m, params_ref const& p) { + return alloc(pb2bv_solver, m, p, m_solver->translate(m, p)); } From fb84ba8c3464d68798d8b0516d5c083d053e56f9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Jun 2017 14:00:33 -0700 Subject: [PATCH 0171/1283] updates and fixes to copying and cardinalities Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 126 +++++++++++++++----------- src/sat/card_extension.h | 8 +- src/sat/sat_simplifier.cpp | 62 +++++-------- src/sat/sat_solver.cpp | 37 +++++--- src/sat/sat_solver/inc_sat_solver.cpp | 39 ++++---- 5 files changed, 144 insertions(+), 128 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 0d0c148f1..71980eeab 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -202,8 +202,7 @@ namespace sat { for (unsigned i = 0; i < p.size(); ++i) { wlits.push_back(p[i]); } - bool_var v = p.lit() == null_literal ? null_bool_var : p.lit().var(); - result.add_pb_ge(v, wlits, p.k()); + result.add_pb_ge(p.lit(), wlits, p.k()); } } @@ -439,21 +438,18 @@ namespace sat { } void card_extension::display(std::ostream& out, pb const& p, bool values) const { - if (p.lit() != null_literal) out << p.lit(); - out << "[watch: " << p.num_watch() << ", slack: " << p.slack() << "]"; + if (p.lit() != null_literal) out << p.lit() << " == "; if (p.lit() != null_literal && values) { + out << "[watch: " << p.num_watch() << ", slack: " << p.slack() << "]"; out << "@(" << value(p.lit()); if (value(p.lit()) != l_undef) { out << ":" << lvl(p.lit()); } out << "): "; } - else { - out << ": "; - } - for (unsigned i = 0; i < p.size(); ++i) { - literal l = p[i].second; - unsigned w = p[i].first; + for (wliteral wl : p) { + literal l = wl.second; + unsigned w = wl.first; if (w > 1) out << w << " * "; out << l; if (values) { @@ -476,11 +472,10 @@ namespace sat { for (unsigned i = 0; i < m_xors.size(); ++i) { literal_vector lits; xor& x = *m_xors[i]; - for (unsigned i = 0; i < x.size(); ++i) { - lits.push_back(x[i]); + for (literal l : x) { + lits.push_back(l); } - bool_var v = x.lit() == null_literal ? null_bool_var : x.lit().var(); - result.add_xor(v, lits); + result.add_xor(x.lit(), lits); } } @@ -1011,53 +1006,63 @@ namespace sat { m_stats.reset(); } - void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { + void card_extension::add_at_least(literal lit, literal_vector const& lits, unsigned k) { unsigned index = 4*m_cards.size(); SASSERT(is_card_index(index)); - literal lit = v == null_bool_var ? null_literal : literal(v, false); card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); m_cards.push_back(c); - if (v == null_bool_var) { + if (lit == null_literal) { // it is an axiom. init_watch(*c, true); m_card_axioms.push_back(c); } else { - get_wlist(literal(v, false)).push_back(index); - get_wlist(literal(v, true)).push_back(index); + get_wlist(lit).push_back(index); + get_wlist(~lit).push_back(index); + m_index_trail.push_back(index); + } + } + + void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { + literal lit = v == null_bool_var ? null_literal : literal(v, false); + add_at_least(lit, lits, k); + } + + void card_extension::add_pb_ge(literal lit, svector const& wlits, unsigned k) { + unsigned index = 4*m_pbs.size() + 0x3; + SASSERT(is_pb_index(index)); + pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(index, lit, wlits, k); + m_pbs.push_back(p); + if (lit == null_literal) { + init_watch(*p, true); + m_pb_axioms.push_back(p); + } + else { + get_wlist(lit).push_back(index); + get_wlist(~lit).push_back(index); m_index_trail.push_back(index); } } void card_extension::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { - unsigned index = 4*m_pbs.size() + 0x3; - SASSERT(is_pb_index(index)); literal lit = v == null_bool_var ? null_literal : literal(v, false); - pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(index, lit, wlits, k); - m_pbs.push_back(p); - if (v == null_bool_var) { - init_watch(*p, true); - m_pb_axioms.push_back(p); - } - else { - get_wlist(literal(v, false)).push_back(index); - get_wlist(literal(v, true)).push_back(index); - m_index_trail.push_back(index); - } + add_pb_ge(lit, wlits, k); } void card_extension::add_xor(bool_var v, literal_vector const& lits) { - unsigned index = 4*m_xors.size() + 0x1; - SASSERT(is_xor_index(index)); - SASSERT(v != null_bool_var); - xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, literal(v, false), lits); - m_xors.push_back(x); - get_wlist(literal(v, false)).push_back(index); - get_wlist(literal(v, true)).push_back(index); - m_index_trail.push_back(index); + add_xor(literal(v, false), lits); } + void card_extension::add_xor(literal lit, literal_vector const& lits) { + unsigned index = 4*m_xors.size() + 0x1; + SASSERT(is_xor_index(index)); + xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, lit, lits); + m_xors.push_back(x); + get_wlist(lit).push_back(index); + get_wlist(~lit).push_back(index); + m_index_trail.push_back(index); + } void card_extension::propagate(literal l, ext_constraint_idx idx, bool & keep) { SASSERT(value(l) == l_true); @@ -1412,18 +1417,20 @@ namespace sat { void card_extension::clauses_modifed() {} lbool card_extension::get_phase(bool_var v) { return l_undef; } - extension* card_extension::copy(solver* s) { - card_extension* result = alloc(card_extension); - result->set_solver(s); + void card_extension::copy_card(card_extension& result) { for (unsigned i = 0; i < m_cards.size(); ++i) { literal_vector lits; card& c = *m_cards[i]; for (unsigned i = 0; i < c.size(); ++i) { lits.push_back(c[i]); } - bool_var v = c.lit() == null_literal ? null_bool_var : c.lit().var(); - result->add_at_least(v, lits, c.k()); + result.add_at_least(c.lit(), lits, c.k()); } + } + extension* card_extension::copy(solver* s) { + card_extension* result = alloc(card_extension); + result->set_solver(s); + copy_card(*result); copy_xor(*result); copy_pb(*result); return result; @@ -1498,16 +1505,18 @@ namespace sat { } void card_extension::display(std::ostream& out, card const& c, bool values) const { - out << c.lit() << "[" << c.size() << "]"; - if (c.lit() != null_literal && values) { - out << "@(" << value(c.lit()); - if (value(c.lit()) != l_undef) { - out << ":" << lvl(c.lit()); + if (c.lit() != null_literal) { + if (values) { + out << c.lit() << "[" << c.size() << "]"; + out << "@(" << value(c.lit()); + if (value(c.lit()) != l_undef) { + out << ":" << lvl(c.lit()); + } + out << "): "; + } + else { + out << c.lit() << " == "; } - out << "): "; - } - else { - out << ": "; } for (unsigned i = 0; i < c.size(); ++i) { literal l = c[i]; @@ -1527,6 +1536,15 @@ namespace sat { } std::ostream& card_extension::display(std::ostream& out) const { + for (card* c : m_cards) { + display(out, *c, false); + } + for (pb* p : m_pbs) { + display(out, *p, false); + } + for (xor* x : m_xors) { + display(out, *x, false); + } return out; } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 3b9bfd5c0..37b368e70 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -108,6 +108,8 @@ namespace sat { literal lit() const { return m_lit; } literal operator[](unsigned i) const { return m_lits[i]; } unsigned size() const { return m_size; } + literal const* begin() const { return m_lits; } + literal const* end() const { return (literal const*)m_lits + m_size; } void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate() { m_lits[0].neg(); } }; @@ -167,7 +169,7 @@ namespace sat { void reset_marked_literals(); void unwatch_literal(literal w, card& c); void get_card_antecedents(literal l, card const& c, literal_vector & r); - + void copy_card(card_extension& result); // xor specific functionality void copy_xor(card_extension& result); @@ -244,6 +246,10 @@ namespace sat { void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xor const& c, bool values) const; + void add_at_least(literal l, literal_vector const& lits, unsigned k); + void add_pb_ge(literal l, svector const& wlits, unsigned k); + void add_xor(literal l, literal_vector const& lits); + public: card_extension(); virtual ~card_extension(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 5e218f278..b53b920dd 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1102,11 +1102,9 @@ namespace sat { unsigned simplifier::get_num_non_learned_bin(literal l) const { unsigned r = 0; - watch_list const & wlist = get_wlist(~l); - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (it->is_binary_non_learned_clause()) + watch_list const & wlist = get_wlist(~l); + for (auto & w : wlist) { + if (w.is_binary_non_learned_clause()) r++; } return r; @@ -1133,10 +1131,7 @@ namespace sat { void simplifier::order_vars_for_elim(bool_var_vector & r) { svector tmp; - bool_var_set::iterator it = m_elim_todo.begin(); - bool_var_set::iterator end = m_elim_todo.end(); - for (; it != end; ++it) { - bool_var v = *it; + for (bool_var v : m_elim_todo) { if (is_external(v)) continue; if (was_eliminated(v)) @@ -1149,17 +1144,10 @@ namespace sat { m_elim_todo.reset(); std::stable_sort(tmp.begin(), tmp.end(), bool_var_and_cost_lt()); TRACE("elim_vars", - svector::iterator it = tmp.begin(); - svector::iterator end = tmp.end(); - for (; it != end; ++it) { - tout << "(" << it->first << ", " << it->second << ") "; - } + for (auto& p : tmp) tout << "(" << p.first << ", " << p.second << ") "; tout << "\n";); - svector::iterator it2 = tmp.begin(); - svector::iterator end2 = tmp.end(); - for (; it2 != end2; ++it2) { - r.push_back(it2->first); - } + for (auto& p : tmp) + r.push_back(p.first); } /** @@ -1175,11 +1163,9 @@ namespace sat { } watch_list & wlist = get_wlist(~l); - watch_list::iterator it2 = wlist.begin(); - watch_list::iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - if (it2->is_binary_non_learned_clause()) { - r.push_back(clause_wrapper(l, it2->get_literal())); + for (auto & w : wlist) { + if (w.is_binary_non_learned_clause()) { + r.push_back(clause_wrapper(l, w.get_literal())); SASSERT(r.back().size() == 2); } } @@ -1199,7 +1185,7 @@ namespace sat { bool res = true; unsigned sz = c1.size(); m_elim_counter -= sz; - for (unsigned i = 0; i < sz; i++) { + for (unsigned i = 0; i < sz; ++i) { literal l2 = c1[i]; if (l == l2) continue; @@ -1210,7 +1196,7 @@ namespace sat { literal not_l = ~l; sz = c2.size(); m_elim_counter -= sz; - for (unsigned i = 0; i < sz; i++) { + for (unsigned i = 0; i < sz; ++i) { literal l2 = c2[i]; if (not_l == l2) continue; @@ -1223,7 +1209,7 @@ namespace sat { } sz = c1.size(); - for (unsigned i = 0; i < sz; i++) { + for (unsigned i = 0; i < sz; ++i) { literal l2 = c1[i]; if (l == l2) continue; @@ -1234,10 +1220,9 @@ namespace sat { void simplifier::save_clauses(model_converter::entry & mc_entry, clause_wrapper_vector const & cs) { model_converter & mc = s.m_mc; - clause_wrapper_vector::const_iterator it = cs.begin(); - clause_wrapper_vector::const_iterator end = cs.end(); - for (; it != end; ++it) - mc.insert(mc_entry, *it); + for (auto & e : cs) { + mc.insert(mc_entry, e); + } } void simplifier::add_non_learned_binary_clause(literal l1, literal l2) { @@ -1273,11 +1258,9 @@ namespace sat { */ void simplifier::remove_bin_clauses(literal l) { watch_list & wlist = get_wlist(~l); - watch_list::iterator it = wlist.begin(); - watch_list::iterator end = wlist.end(); - for (; it != end; ++it) { - if (it->is_binary_clause()) { - literal l2 = it->get_literal(); + for (auto & w : wlist) { + if (w.is_binary_clause()) { + literal l2 = w.get_literal(); watch_list & wlist2 = get_wlist(~l2); watch_list::iterator it2 = wlist2.begin(); watch_list::iterator itprev = it2; @@ -1292,7 +1275,7 @@ namespace sat { itprev++; } wlist2.set_end(itprev); - m_sub_bin_todo.erase(bin_clause(l, l2, it->is_learned())); + m_sub_bin_todo.erase(bin_clause(l, l2, w.is_learned())); } } TRACE("bin_clause_bug", tout << "collapsing watch_list of: " << l << "\n";); @@ -1484,13 +1467,10 @@ namespace sat { bool_var_vector vars; order_vars_for_elim(vars); - bool_var_vector::iterator it = vars.begin(); - bool_var_vector::iterator end = vars.end(); - for (; it != end; ++it) { + for (bool_var v : vars) { checkpoint(); if (m_elim_counter < 0) return; - bool_var v = *it; if (try_eliminate(v)) { m_num_elim_vars++; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 93021a16e..405b44b21 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -96,6 +96,9 @@ namespace sat { if (src.was_eliminated(v)) { m_eliminated[v] = true; } + m_phase[v] = src.m_phase[v]; + m_prev_phase[v] = src.m_prev_phase[v]; + // m_activity[v] = src.m_activity[v], but then update case_split_queue ? } } @@ -117,14 +120,14 @@ namespace sat { unsigned sz = src.m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { literal l = ~to_literal(l_idx); + if (src.was_eliminated(l.var())) continue; watch_list const & wlist = src.m_watches[l_idx]; - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_non_learned_clause()) + for (auto & wi : wlist) { + if (!wi.is_binary_non_learned_clause()) continue; - literal l2 = it->get_literal(); - if (l.index() > l2.index()) + literal l2 = wi.get_literal(); + if (l.index() > l2.index() || + src.was_eliminated(l2.var())) continue; mk_clause_core(l, l2); } @@ -133,16 +136,24 @@ namespace sat { { literal_vector buffer; - // copy clause - clause_vector::const_iterator it = src.m_clauses.begin(); - clause_vector::const_iterator end = src.m_clauses.end(); - for (; it != end; ++it) { - clause const & c = *(*it); + // copy clauses + for (clause* c : src.m_clauses) { buffer.reset(); - for (unsigned i = 0; i < c.size(); i++) - buffer.push_back(c[i]); + for (literal l : *c) buffer.push_back(l); mk_clause_core(buffer); } + // copy high quality lemmas + for (clause* c : src.m_learned) { + if (c->glue() <= 2 || (c->size() <= 40 && c->glue() <= 8)) { + buffer.reset(); + for (literal l : *c) buffer.push_back(l); + clause* c1 = mk_clause_core(buffer.size(), buffer.c_ptr(), true); + if (c1) { + c1->set_glue(c->glue()); + c1->set_psm(c->psm()); + } + } + } } m_user_scope_literals.reset(); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6e124fcf3..295a04a67 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -45,7 +45,6 @@ class inc_sat_solver : public solver { sat::solver m_solver; goal2sat m_goal2sat; params_ref m_params; - bool m_optimize_model; // parameter expr_ref_vector m_fmls; expr_ref_vector m_asmsf; unsigned_vector m_fmls_lim; @@ -77,7 +76,7 @@ public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), m_solver(p, m.limit()), - m_params(p), m_optimize_model(false), + m_params(p), m_fmls(m), m_asmsf(m), m_fmls_head(0), @@ -96,20 +95,24 @@ public: virtual ~inc_sat_solver() {} virtual solver* translate(ast_manager& dst_m, params_ref const& p) { - ast_translation tr(m, dst_m); if (m_num_scopes > 0) { throw default_exception("Cannot translate sat solver at non-base level"); } + ast_translation tr(m, dst_m); + m_solver.pop_to_base_level(); inc_sat_solver* result = alloc(inc_sat_solver, dst_m, p); - expr_ref fml(dst_m); - for (unsigned i = 0; i < m_fmls.size(); ++i) { - fml = tr(m_fmls[i].get()); - result->m_fmls.push_back(fml); - } - for (unsigned i = 0; i < m_asmsf.size(); ++i) { - fml = tr(m_asmsf[i].get()); - result->m_asmsf.push_back(fml); - } + result->m_solver.copy(m_solver); + result->m_fmls_head = m_fmls_head; + for (expr* f : m_fmls) result->m_fmls.push_back(tr(f)); + for (expr* f : m_asmsf) result->m_asmsf.push_back(tr(f)); + for (auto & kv : m_map) result->m_map.insert(tr(kv.m_key), kv.m_value); + for (unsigned l : m_fmls_lim) result->m_fmls_lim.push_back(l); + for (unsigned a : m_asms_lim) result->m_asms_lim.push_back(a); + for (unsigned h : m_fmls_head_lim) result->m_fmls_head_lim.push_back(h); + for (expr* f : m_internalized_fmls) result->m_internalized_fmls.push_back(tr(f)); + if (m_mc0.get()) result->m_mc0 = m_mc0->translate(tr); + result->m_internalized = m_internalized; + result->m_internalized_converted = m_internalized_converted; return result; } @@ -272,7 +275,6 @@ public: m_params.set_bool("pb_totalizer", m_solver.get_config().m_pb_solver == sat::PB_TOTALIZER); m_params.set_bool("xor_solver", p1.xor_solver()); m_solver.updt_params(m_params); - m_optimize_model = m_params.get_bool("optimize_model", false); } virtual void collect_statistics(statistics & st) const { @@ -383,9 +385,9 @@ public: // extract original fixed variables u_map asm2dep; extract_asm2dep(dep2asm, asm2dep); - for (unsigned i = 0; i < vars.size(); ++i) { + for (auto v : vars) { expr_ref cons(m); - if (extract_fixed_variable(dep2asm, asm2dep, vars[i], bool_var2conseq, lconseq, cons)) { + if (extract_fixed_variable(dep2asm, asm2dep, v, bool_var2conseq, lconseq, cons)) { conseq.push_back(cons); } } @@ -407,11 +409,10 @@ public: } vector ls_mutexes; m_solver.find_mutexes(ls, ls_mutexes); - for (unsigned i = 0; i < ls_mutexes.size(); ++i) { - sat::literal_vector const ls_mutex = ls_mutexes[i]; + for (sat::literal_vector const& ls_mutex : ls_mutexes) { expr_ref_vector mutex(m); - for (unsigned j = 0; j < ls_mutex.size(); ++j) { - mutex.push_back(lit2var.find(ls_mutex[j].index())); + for (sat::literal l : ls_mutex) { + mutex.push_back(lit2var.find(l.index())); } mutexes.push_back(mutex); } From c3d29e75ef205307a16686175942cfe48f429881 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Jun 2017 18:27:32 -0700 Subject: [PATCH 0172/1283] adding in-processing Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 461 ++++++++++++++++++++++---- src/sat/card_extension.h | 40 ++- src/sat/sat_model_converter.cpp | 7 + src/sat/sat_model_converter.h | 1 + src/sat/sat_simplifier.cpp | 45 +-- src/sat/sat_solver.cpp | 20 ++ src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 13 +- src/sat/sat_watched.cpp | 2 +- 9 files changed, 484 insertions(+), 106 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 71980eeab..4f8f2d1d3 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -51,10 +51,17 @@ namespace sat { m_max_sum(0) { for (unsigned i = 0; i < wlits.size(); ++i) { m_wlits[i] = wlits[i]; - if (m_max_sum + wlits[i].first < m_max_sum) { + } + update_max_sum(); + } + + void card_extension::pb::update_max_sum() { + m_max_sum = 0; + for (unsigned i = 0; i < size(); ++i) { + if (m_max_sum + m_wlits[i].first < m_max_sum) { throw default_exception("addition of pb coefficients overflows"); } - m_max_sum += wlits[i].first; + m_max_sum += m_wlits[i].first; } } @@ -196,13 +203,12 @@ namespace sat { // pb: void card_extension::copy_pb(card_extension& result) { - for (unsigned i = 0; i < m_pbs.size(); ++i) { + for (pb* p : m_pbs) { svector wlits; - pb& p = *m_pbs[i]; - for (unsigned i = 0; i < p.size(); ++i) { - wlits.push_back(p[i]); + for (wliteral w : *p) { + wlits.push_back(w); } - result.add_pb_ge(p.lit(), wlits, p.k()); + result.add_pb_ge(p->lit(), wlits, p->k()); } } @@ -437,6 +443,151 @@ namespace sat { } } + void card_extension::unit_propagation_simplification(literal lit, literal_vector const& lits) { + if (lit == null_literal) { + for (literal l : lits) { + if (value(l) == l_undef) { + s().assign(l, justification()); + } + } + } + else { + // add clauses for: p.lit() <=> conjunction of undef literals + SASSERT(value(lit) == l_undef); + literal_vector cl; + cl.push_back(lit); + for (literal l : lits) { + if (value(l) == l_undef) { + s().mk_clause(~lit, l); + cl.push_back(~l); + } + } + s().mk_clause(cl); + } + } + + bool card_extension::is_cardinality(pb const& p) { + if (p.size() == 0) return false; + unsigned w = p[0].first; + for (unsigned i = 1; i < p.size(); ++i) { + if (w != p[i].first) return false; + } + return true; + } + + void card_extension::simplify2(pb& p) { + if (is_cardinality(p)) { + literal_vector lits(p.literals()); + unsigned k = (p.k() + p[0].first - 1) / p[0].first; + add_at_least(p.lit(), lits, k); + remove_constraint(p); + return; + } + if (p.lit() == null_literal) { + unsigned max_sum = p.max_sum(); + unsigned sz = p.size(); + for (unsigned i = 0; i < sz; ++i) { + wliteral wl = p[i]; + if (p.k() > max_sum - wl.first) { + std::cout << "unit literal\n"; + } + } + } + } + + void card_extension::simplify(pb& p) { + s().pop_to_base_level(); + if (p.lit() != null_literal && value(p.lit()) == l_false) { + return; + init_watch(p, !p.lit().sign()); + std::cout << "pb: flip sign\n"; + } + if (p.lit() != null_literal && value(p.lit()) == l_true) { + std::cout << "literal is assigned at base level " << s().at_base_lvl() << "\n"; + SASSERT(lvl(p.lit()) == 0); + nullify_tracking_literal(p); + } + + SASSERT(p.lit() == null_literal || value(p.lit()) == l_undef); + + unsigned true_val = 0, slack = 0, num_false = 0; + for (wliteral wl : p) { + switch (value(wl.second)) { + case l_true: true_val += wl.first; break; + case l_false: ++num_false; break; + default: slack += wl.first; break; + } + } + if (true_val == 0 && num_false == 0) { + // no op + } + else if (true_val >= p.k()) { + std::cout << "tautology\n"; + if (p.lit() != null_literal) { + std::cout << "tautology at level 0\n"; + s().assign(p.lit(), justification()); + } + remove_constraint(p); + } + else if (slack + true_val < p.k()) { + if (p.lit() != null_literal) { + s().assign(~p.lit(), justification()); + } + else { + std::cout << "unsat during simplification\n"; + s().set_conflict(justification()); + } + remove_constraint(p); + } + else if (slack + true_val == p.k()) { + std::cout << "unit propagation\n"; + literal_vector lits(p.literals()); + unit_propagation_simplification(p.lit(), lits); + remove_constraint(p); + } + else { + std::cout << "pb value at base: " << true_val << " false: " << num_false << " size: " << p.size() << " k: " << p.k() << "\n"; + unsigned sz = p.size(); + clear_watch(p); + for (unsigned i = 0; i < sz; ++i) { + if (value(p[i].second) != l_undef) { + --sz; + p.swap(i, sz); + --i; + } + } + std::cout << "new size: " << sz << " old size " << p.size() << "\n"; + p.update_size(sz); + p.update_k(p.k() - true_val); + // display(std::cout, c, true); + if (p.lit() == null_literal) { + init_watch(p, true); + } + else { + SASSERT(value(p.lit()) == l_undef); + // c will be watched once c.lit() is assigned. + } + simplify2(p); + } + } + + void card_extension::nullify_tracking_literal(pb& p) { + if (p.lit() != null_literal) { + get_wlist(p.lit()).erase(watched(p.index())); + get_wlist(~p.lit()).erase(watched(p.index())); + p.nullify_literal(); + } + } + + void card_extension::remove_constraint(pb& p) { + clear_watch(p); + nullify_tracking_literal(p); + m_pbs[index2position(p.index())] = 0; + dealloc(&p); + } + + + void card_extension::display(std::ostream& out, pb const& p, bool values) const { if (p.lit() != null_literal) out << p.lit() << " == "; if (p.lit() != null_literal && values) { @@ -469,13 +620,10 @@ namespace sat { // xor: void card_extension::copy_xor(card_extension& result) { - for (unsigned i = 0; i < m_xors.size(); ++i) { + for (xor* x : m_xors) { literal_vector lits; - xor& x = *m_xors[i]; - for (literal l : x) { - lits.push_back(l); - } - result.add_xor(x.lit(), lits); + for (literal l : *x) lits.push_back(l); + result.add_xor(x->lit(), lits); } } @@ -872,7 +1020,7 @@ namespace sat { for (unsigned i = 0; 0 <= slack && i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; int coeff = get_coeff(v); - lbool val = m_solver->value(v); + lbool val = s().value(v); bool is_true = val == l_true; bool append = coeff != 0 && val != l_undef && (coeff < 0 == is_true); if (append) { @@ -1004,22 +1152,8 @@ namespace sat { card_extension::~card_extension() { m_stats.reset(); - } - - void card_extension::add_at_least(literal lit, literal_vector const& lits, unsigned k) { - unsigned index = 4*m_cards.size(); - SASSERT(is_card_index(index)); - card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); - m_cards.push_back(c); - if (lit == null_literal) { - // it is an axiom. - init_watch(*c, true); - m_card_axioms.push_back(c); - } - else { - get_wlist(lit).push_back(index); - get_wlist(~lit).push_back(index); - m_index_trail.push_back(index); + while (!m_index_trail.empty()) { + clear_index_trail_back(); } } @@ -1028,19 +1162,42 @@ namespace sat { add_at_least(lit, lits, k); } + void card_extension::add_at_least(literal lit, literal_vector const& lits, unsigned k) { + unsigned index = 4*m_cards.size(); + SASSERT(is_card_index(index)); + card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); + if (lit != null_literal) s().set_external(lit.var()); + m_cards.push_back(c); + init_watch(*c); + } + + void card_extension::init_watch(card& c) { + unsigned index = c.index(); + literal lit = c.lit(); + m_index_trail.push_back(index); + if (lit == null_literal) { + // it is an axiom. + init_watch(c, true); + } + else { + get_wlist(lit).push_back(index); + get_wlist(~lit).push_back(index); + } + } + void card_extension::add_pb_ge(literal lit, svector const& wlits, unsigned k) { unsigned index = 4*m_pbs.size() + 0x3; SASSERT(is_pb_index(index)); pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(index, lit, wlits, k); m_pbs.push_back(p); + m_index_trail.push_back(index); if (lit == null_literal) { init_watch(*p, true); - m_pb_axioms.push_back(p); } else { + s().set_external(lit.var()); get_wlist(lit).push_back(index); get_wlist(~lit).push_back(index); - m_index_trail.push_back(index); } } @@ -1059,6 +1216,8 @@ namespace sat { SASSERT(is_xor_index(index)); xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, lit, lits); m_xors.push_back(x); + s().set_external(lit.var()); + for (literal l : lits) s().set_external(l.var()); get_wlist(lit).push_back(index); get_wlist(~lit).push_back(index); m_index_trail.push_back(index); @@ -1069,8 +1228,9 @@ namespace sat { TRACE("sat", tout << l << " " << idx << "\n";); if (is_pb_index(idx)) { pb& p = index2pb(idx); - if (l.var() == p.lit().var()) { + if (p.lit() != null_literal && l.var() == p.lit().var()) { init_watch(p, !l.sign()); + keep = true; } else if (p.lit() != null_literal && value(p.lit()) != l_true) { keep = false; @@ -1081,8 +1241,9 @@ namespace sat { } else if (is_card_index(idx)) { card& c = index2card(idx); - if (l.var() == c.lit().var()) { + if (c.lit() != null_literal && l.var() == c.lit().var()) { init_watch(c, !l.sign()); + keep = true; } else if (c.lit() != null_literal && value(c.lit()) != l_true) { keep = false; @@ -1263,6 +1424,10 @@ namespace sat { } } + void card_extension::simplify(xor& x) { + // no-op + } + void card_extension::get_card_antecedents(literal l, card const& c, literal_vector& r) { DEBUG_CODE( bool found = false; @@ -1313,6 +1478,109 @@ namespace sat { } } + void card_extension::nullify_tracking_literal(card& c) { + if (c.lit() != null_literal) { + get_wlist(c.lit()).erase(watched(c.index())); + get_wlist(~c.lit()).erase(watched(c.index())); + c.nullify_literal(); + } + } + + void card_extension::remove_constraint(card& c) { + clear_watch(c); + nullify_tracking_literal(c); + m_cards[index2position(c.index())] = 0; + dealloc(&c); + } + + void card_extension::simplify(card& c) { + SASSERT(c.lit() == null_literal || value(c.lit()) != l_false); + if (c.lit() != null_literal && value(c.lit()) == l_false) { + std::ofstream ous("unit.txt"); + s().display(ous); + s().display_watches(ous); + display(ous, c, true); + exit(1); + return; + init_watch(c, !c.lit().sign()); + std::cout << "card: flip sign\n"; + } + if (c.lit() != null_literal && value(c.lit()) == l_true) { + std::cout << "literal is assigned at base level " << value(c.lit()) << " " << s().at_base_lvl() << "\n"; + SASSERT(lvl(c.lit()) == 0); + nullify_tracking_literal(c); + } + if (c.lit() == null_literal && c.k() == 1) { + std::cout << "create clause\n"; + literal_vector lits; + for (literal l : c) lits.push_back(l); + s().mk_clause(lits); + remove_constraint(c); + return; + } + + SASSERT(c.lit() == null_literal || value(c.lit()) == l_undef); + + unsigned num_true = 0, num_false = 0; + for (literal l : c) { + switch (value(l)) { + case l_true: ++num_true; break; + case l_false: ++num_false; break; + default: break; + } + } + + if (num_false + num_true == 0) { + // no simplification + return; + } + else if (num_true >= c.k()) { + std::cout << "tautology\n"; + if (c.lit() != null_literal) { + std::cout << "tautology at level 0\n"; + s().assign(c.lit(), justification()); + } + remove_constraint(c); + } + else if (num_false + c.k() > c.size()) { + if (c.lit() != null_literal) { + std::cout << "falsity at level 0\n"; + s().assign(~c.lit(), justification()); + remove_constraint(c); + } + else { + std::cout << "unsat during simplification\n"; + } + } + else if (num_false + c.k() == c.size()) { + std::cout << "unit propagations : " << c.size() - num_false - num_true << "\n"; + literal_vector lits(c.literals()); + unit_propagation_simplification(c.lit(), lits); + remove_constraint(c); + } + else { + std::cout << "literals assigned at base: " << num_true + num_false << " " << c.size() << " k: " << c.k() << "\n"; + unsigned sz = c.size(); + clear_watch(c); + for (unsigned i = 0; i < sz; ++i) { + if (value(c[i]) != l_undef) { + --sz; + c.swap(i, sz); + --i; + } + } + std::cout << "new size: " << sz << " old size " << c.size() << "\n"; + c.update_size(sz); + c.update_k(c.k() - num_true); + if (c.lit() == null_literal) { + init_watch(c, true); + } + else { + SASSERT(value(c.lit()) == l_undef); + // c will be watched once c.lit() is assigned. + } + } + } lbool card_extension::add_assign(card& c, literal alit) { // literal is assigned to false. @@ -1380,51 +1648,110 @@ namespace sat { m_index_lim.push_back(m_index_trail.size()); } + void card_extension::clear_index_trail_back() { + unsigned index = m_index_trail.back(); + m_index_trail.pop_back(); + if (is_card_index(index)) { + card* c = m_cards.back(); + if (c) { + SASSERT(c->index() == index); + clear_watch(*c); // can skip during finalization + dealloc(c); + } + m_cards.pop_back(); + } + else if (is_pb_index(index)) { + pb* p = m_pbs.back(); + if (p) { + SASSERT(p->index() == index); + clear_watch(*p); // can skip during finalization + dealloc(p); + } + m_pbs.pop_back(); + } + else if (is_xor_index(index)) { + xor* x = m_xors.back(); + if (x) { + SASSERT(x->index() == index); + clear_watch(*x); // can skip during finalization + dealloc(x); + } + m_xors.pop_back(); + } + else { + UNREACHABLE(); + } + } + void card_extension::pop(unsigned n) { TRACE("sat_verbose", tout << "pop:" << n << "\n";); unsigned new_lim = m_index_lim.size() - n; unsigned sz = m_index_lim[new_lim]; while (m_index_trail.size() > sz) { - unsigned index = m_index_trail.back(); - m_index_trail.pop_back(); - if (is_card_index(index)) { - SASSERT(m_cards.back()->index() == index); - clear_watch(*m_cards.back()); - dealloc(m_cards.back()); - m_cards.pop_back(); - } - else if (is_pb_index(index)) { - SASSERT(m_pbs.back()->index() == index); - clear_watch(*m_pbs.back()); - dealloc(m_pbs.back()); - m_pbs.pop_back(); - } - else if (is_xor_index(index)) { - SASSERT(m_xors.back()->index() == index); - clear_watch(*m_xors.back()); - dealloc(m_xors.back()); - m_xors.pop_back(); - } - else { - UNREACHABLE(); - } + clear_index_trail_back(); } m_index_lim.resize(new_lim); m_num_propagations_since_pop = 0; } - void card_extension::simplify() {} + void card_extension::simplify() { + s().pop_to_base_level(); + for (card* c : m_cards) { + if (c) simplify(*c); + } + for (pb* p : m_pbs) { + if (p) simplify(*p); + } + for (xor* x : m_xors) { + if (x) simplify(*x); + } + gc(); + } + + void card_extension::gc() { + + // remove constraints where indicator literal isn't used. + sat::use_list use_list; + use_list.init(s().num_vars()); + svector var_used(s().num_vars(), false); + for (clause* c : s().m_clauses) if (!c->frozen()) use_list.insert(*c); + for (card* c : m_cards) if (c) for (literal l : *c) var_used[l.var()] = true; + for (pb* p : m_pbs) if (p) for (wliteral wl : *p) var_used[wl.second.var()] = true; + for (xor* x : m_xors) if (x) for (literal l : *x) var_used[l.var()] = true; + for (card* c : m_cards) { + if (c && c->lit() != null_literal && !var_used[c->lit().var()] && use_list.get(c->lit()).empty() && use_list.get(~c->lit()).empty()) { + remove_constraint(*c); + } + } + for (pb* p : m_pbs) { + if (p && p->lit() != null_literal && !var_used[p->lit().var()] && use_list.get(p->lit()).empty() && use_list.get(~p->lit()).empty()) { + remove_constraint(*p); + } + } + // take ownership of interface variables + for (card* c : m_cards) if (c && c->lit() != null_literal) var_used[c->lit().var()] = true; + for (pb* p : m_pbs) if (p && p->lit() != null_literal) var_used[p->lit().var()] = true; + // set variables to be non-external if they are not used in theory constraints. + unsigned ext = 0; + for (unsigned v = 0; v < s().num_vars(); ++v) { + if (s().is_external(v) && !var_used[v]) { + s().set_non_external(v); + ++ext; + } + } + std::cout << "non-external variables " << ext << "\n"; + + } + void card_extension::clauses_modifed() {} + lbool card_extension::get_phase(bool_var v) { return l_undef; } void card_extension::copy_card(card_extension& result) { - for (unsigned i = 0; i < m_cards.size(); ++i) { + for (card* c : m_cards) { literal_vector lits; - card& c = *m_cards[i]; - for (unsigned i = 0; i < c.size(); ++i) { - lits.push_back(c[i]); - } - result.add_at_least(c.lit(), lits, c.k()); + for (literal l : *c) lits.push_back(l); + result.add_at_least(c->lit(), lits, c->k()); } } extension* card_extension::copy(solver* s) { @@ -1537,13 +1864,13 @@ namespace sat { std::ostream& card_extension::display(std::ostream& out) const { for (card* c : m_cards) { - display(out, *c, false); + if (c) display(out, *c, false); } for (pb* p : m_pbs) { - display(out, *p, false); + if (p) display(out, *p, false); } for (xor* x : m_xors) { - display(out, *x, false); + if (x) display(out, *x, false); } return out; } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 37b368e70..64553795b 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -59,10 +59,16 @@ namespace sat { unsigned index() const { return m_index; } literal lit() const { return m_lit; } literal operator[](unsigned i) const { return m_lits[i]; } + literal const* begin() const { return m_lits; } + literal const* end() const { return static_cast(m_lits) + m_size; } unsigned k() const { return m_k; } unsigned size() const { return m_size; } void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } - void negate(); + void negate(); + void update_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } + void update_k(unsigned k) { m_k = k; } + void nullify_literal() { m_lit = null_literal; } + literal_vector literals() const { return literal_vector(m_size, m_lits); } }; typedef std::pair wliteral; @@ -76,6 +82,7 @@ namespace sat { unsigned m_num_watch; unsigned m_max_sum; wliteral m_wlits[0]; + void update_max_sum(); public: static size_t get_obj_size(unsigned num_lits) { return sizeof(pb) + num_lits * sizeof(wliteral); } pb(unsigned index, literal lit, svector const& wlits, unsigned k); @@ -83,7 +90,7 @@ namespace sat { literal lit() const { return m_lit; } wliteral operator[](unsigned i) const { return m_wlits[i]; } wliteral const* begin() const { return m_wlits; } - wliteral const* end() const { return (wliteral const*)m_wlits + m_size; } + wliteral const* end() const { return static_cast(m_wlits) + m_size; } unsigned k() const { return m_k; } unsigned size() const { return m_size; } @@ -94,6 +101,10 @@ namespace sat { void set_num_watch(unsigned s) { m_num_watch = s; } void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } void negate(); + void update_size(unsigned sz) { m_size = sz; update_max_sum(); } + void update_k(unsigned k) { m_k = k; } + void nullify_literal() { m_lit = null_literal; } + literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } }; class xor { @@ -109,7 +120,7 @@ namespace sat { literal operator[](unsigned i) const { return m_lits[i]; } unsigned size() const { return m_size; } literal const* begin() const { return m_lits; } - literal const* end() const { return (literal const*)m_lits + m_size; } + literal const* end() const { return static_cast(m_lits) + m_size; } void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate() { m_lits[0].neg(); } }; @@ -131,9 +142,6 @@ namespace sat { ptr_vector m_xors; ptr_vector m_pbs; - scoped_ptr_vector m_card_axioms; - scoped_ptr_vector m_pb_axioms; - // watch literals unsigned_vector m_index_trail; unsigned_vector m_index_lim; @@ -157,7 +165,14 @@ namespace sat { void inc_parity(bool_var v); void reset_parity(bool_var v); + void clear_index_trail_back(); + solver& s() const { return *m_solver; } + + void gc(); + + // cardinality + void init_watch(card& c); void init_watch(card& c, bool is_true); void init_watch(bool_var v); void assign(card& c, literal lit); @@ -170,6 +185,10 @@ namespace sat { void unwatch_literal(literal w, card& c); void get_card_antecedents(literal l, card const& c, literal_vector & r); void copy_card(card_extension& result); + void simplify(card& c); + void nullify_tracking_literal(card& c); + void remove_constraint(card& c); + void unit_propagation_simplification(literal lit, literal_vector const& lits); // xor specific functionality void copy_xor(card_extension& result); @@ -177,17 +196,19 @@ namespace sat { void watch_literal(xor& x, literal lit); void unwatch_literal(literal w, xor& x); void init_watch(xor& x, bool is_true); - void assign(xor& x, literal lit); + void assign(xor& x, literal lit); void set_conflict(xor& x, literal lit); bool parity(xor const& x, unsigned offset) const; lbool add_assign(xor& x, literal alit); void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); void get_xor_antecedents(literal l, xor const& x, literal_vector & r); + void simplify(xor& x); bool is_card_index(unsigned idx) const { return 0x0 == (idx & 0x3); } bool is_xor_index(unsigned idx) const { return 0x1 == (idx & 0x3); } bool is_pb_index(unsigned idx) const { return 0x3 == (idx & 0x3); } + unsigned index2position(unsigned idx) const { return idx >> 2; } card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 2]; } xor& index2xor(unsigned idx) const { SASSERT(is_xor_index(idx)); return *m_xors[idx >> 2]; } pb& index2pb(unsigned idx) const { SASSERT(is_pb_index(idx)); return *m_pbs[idx >> 2]; } @@ -205,6 +226,11 @@ namespace sat { void assign(pb& p, literal l); void unwatch_literal(literal w, pb& p); void get_pb_antecedents(literal l, pb const& p, literal_vector & r); + void simplify(pb& p); + void simplify2(pb& p); + bool is_cardinality(pb const& p); + void nullify_tracking_literal(pb& p); + void remove_constraint(pb& p); inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 8901c276f..81de935b1 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -32,6 +32,13 @@ namespace sat { void model_converter::reset() { m_entries.finalize(); } + + model_converter& model_converter::operator=(model_converter const& other) { + reset(); + m_entries.append(other.m_entries); + return *this; + } + void model_converter::operator()(model & m) const { vector::const_iterator begin = m_entries.begin(); diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index b89e6e784..e35f2a0aa 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -59,6 +59,7 @@ namespace sat { model_converter(); ~model_converter(); void operator()(model & m) const; + model_converter& operator=(model_converter const& other); entry & mk(kind k, bool_var v); void insert(entry & e, clause const & c); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b53b920dd..4750f8e76 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -35,10 +35,6 @@ namespace sat { void use_list::insert(clause & c) { unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) { - if (m_use_list.size() <= c[i].index()) { - std::cout << c[i] << "\n"; - std::cout << m_use_list.size() << "\n"; - } m_use_list[c[i].index()].insert(c); } } @@ -86,14 +82,11 @@ namespace sat { void simplifier::register_clauses(clause_vector & cs) { std::stable_sort(cs.begin(), cs.end(), size_lt()); - clause_vector::iterator it = cs.begin(); - clause_vector::iterator end = cs.end(); - for (; it != end; ++it) { - clause & c = *(*it); - if (!c.frozen()) { - m_use_list.insert(c); - if (c.strengthened()) - m_sub_todo.insert(c); + for (clause* c : cs) { + if (!c->frozen()) { + m_use_list.insert(*c); + if (c->strengthened()) + m_sub_todo.insert(*c); } } } @@ -1358,16 +1351,12 @@ namespace sat { TRACE("resolution_detail", tout << "collecting number of after_clauses\n";); unsigned before_clauses = num_pos + num_neg; unsigned after_clauses = 0; - clause_wrapper_vector::iterator it1 = m_pos_cls.begin(); - clause_wrapper_vector::iterator end1 = m_pos_cls.end(); - for (; it1 != end1; ++it1) { - clause_wrapper_vector::iterator it2 = m_neg_cls.begin(); - clause_wrapper_vector::iterator end2 = m_neg_cls.end(); - for (; it2 != end2; ++it2) { + for (clause_wrapper& c1 : m_pos_cls) { + for (clause_wrapper& c2 : m_neg_cls) { m_new_cls.reset(); - if (resolve(*it1, *it2, pos_l, m_new_cls)) { - TRACE("resolution_detail", tout << *it1 << "\n" << *it2 << "\n-->\n"; - for (unsigned i = 0; i < m_new_cls.size(); i++) tout << m_new_cls[i] << " "; tout << "\n";); + if (resolve(c1, c2, pos_l, m_new_cls)) { + TRACE("resolution_detail", tout << c1 << "\n" << c2 << "\n-->\n"; + for (literal l : m_new_cls) tout << l << " "; tout << "\n";); after_clauses++; if (after_clauses > before_clauses) { TRACE("resolution", tout << "too many after clauses: " << after_clauses << "\n";); @@ -1393,16 +1382,12 @@ namespace sat { m_elim_counter -= num_pos * num_neg + before_lits; - it1 = m_pos_cls.begin(); - end1 = m_pos_cls.end(); - for (; it1 != end1; ++it1) { - clause_wrapper_vector::iterator it2 = m_neg_cls.begin(); - clause_wrapper_vector::iterator end2 = m_neg_cls.end(); - for (; it2 != end2; ++it2) { + for (auto & c1 : m_pos_cls) { + for (auto & c2 : m_neg_cls) { m_new_cls.reset(); - if (!resolve(*it1, *it2, pos_l, m_new_cls)) + if (!resolve(c1, c2, pos_l, m_new_cls)) continue; - TRACE("resolution_new_cls", tout << *it1 << "\n" << *it2 << "\n-->\n" << m_new_cls << "\n";); + TRACE("resolution_new_cls", tout << c1 << "\n" << c2 << "\n-->\n" << m_new_cls << "\n";); if (cleanup_clause(m_new_cls)) continue; // clause is already satisfied. switch (m_new_cls.size()) { @@ -1470,7 +1455,7 @@ namespace sat { for (bool_var v : vars) { checkpoint(); if (m_elim_counter < 0) - return; + break; if (try_eliminate(v)) { m_num_elim_vars++; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 405b44b21..2aa944087 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -66,6 +66,7 @@ namespace sat { } solver::~solver() { + m_ext = 0; SASSERT(check_invariant()); TRACE("sat", tout << "Delete clauses\n";); del_clauses(m_clauses.begin(), m_clauses.end()); @@ -159,6 +160,7 @@ namespace sat { m_user_scope_literals.reset(); m_user_scope_literals.append(src.m_user_scope_literals); + m_mc = src.m_mc; } // ----------------------- @@ -198,6 +200,10 @@ namespace sat { return v; } + void solver::set_non_external(bool_var v) { + m_external[v] = false; + } + void solver::set_external(bool_var v) { if (m_external[v]) return; m_external[v] = true; @@ -1444,6 +1450,20 @@ namespace sat { if (m_next_simplify > m_conflicts_since_init + m_config.m_simplify_max) m_next_simplify = m_conflicts_since_init + m_config.m_simplify_max; } + +#if 1 + static unsigned file_no = 0; + #pragma omp critical (print_sat) + { + ++file_no; + std::ostringstream ostrm; + ostrm << "s" << file_no << ".txt"; + std::ofstream ous(ostrm.str()); + display(ous); + } +#endif + + } void solver::sort_watch_lits() { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 0dcd9837f..c534ae828 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -274,6 +274,7 @@ namespace sat { unsigned num_restarts() const { return m_restarts; } bool is_external(bool_var v) const { return m_external[v] != 0; } void set_external(bool_var v); + void set_non_external(bool_var v); bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } unsigned scope_lvl() const { return m_scope_lvl; } unsigned search_lvl() const { return m_search_lvl; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 295a04a67..febe171d1 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -113,6 +113,17 @@ public: if (m_mc0.get()) result->m_mc0 = m_mc0->translate(tr); result->m_internalized = m_internalized; result->m_internalized_converted = m_internalized_converted; +#if 0 + static unsigned file_no = 0; + #pragma omp critical (print_sat) + { + ++file_no; + std::ostringstream ostrm; + ostrm << "s" << file_no << ".txt"; + std::ofstream ous(ostrm.str()); + result->m_solver.display(ous); + } +#endif return result; } @@ -538,7 +549,7 @@ private: g = m_subgoals[0]; expr_ref_vector atoms(m); TRACE("sat", g->display_with_dependencies(tout);); - m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, true, is_lemma); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, false, is_lemma); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { std::stringstream strm; diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index b00f17c38..1b294351f 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -60,7 +60,7 @@ namespace sat { out << "(" << it->get_blocked_literal() << " " << *(ca.get_clause(it->get_clause_offset())) << ")"; break; case watched::EXT_CONSTRAINT: - out << it->get_ext_constraint_idx(); + out << "ext: " << it->get_ext_constraint_idx(); break; default: UNREACHABLE(); From 66f0de6785c07278a852184ed6a1544393bf637f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Jun 2017 16:26:47 -0700 Subject: [PATCH 0173/1283] added in-processing features to card/pb Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 655 ++++++++++++++++++++++++++++---- src/sat/card_extension.h | 37 +- src/sat/sat_elim_eqs.cpp | 4 +- src/sat/sat_extension.h | 3 + src/sat/sat_local_search.cpp | 6 +- src/sat/sat_model_converter.cpp | 59 +-- src/sat/sat_parallel.cpp | 13 +- src/sat/sat_simplifier.cpp | 75 ++-- src/sat/sat_simplifier.h | 1 + src/sat/sat_solver.cpp | 15 +- src/sat/sat_solver.h | 2 + 11 files changed, 706 insertions(+), 164 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 4f8f2d1d3..85d812cc3 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -41,6 +41,28 @@ namespace sat { SASSERT(m_size >= m_k && m_k > 0); } + std::ostream& operator<<(std::ostream& out, card_extension::card const& c) { + if (c.lit() != null_literal) { + out << c.lit() << " == "; + } + for (literal l : c) { + out << l << " "; + } + return out << " >= " << c.k(); + } + + std::ostream& operator<<(std::ostream& out, card_extension::pb const& p) { + if (p.lit() != null_literal) { + out << p.lit() << " == "; + } + for (card_extension::wliteral wl : p) { + if (wl.first != 1) out << wl.first << " * "; + out << wl.second << " "; + } + return out << " >= " << p.k(); + } + + card_extension::pb::pb(unsigned index, literal lit, svector const& wlits, unsigned k): m_index(index), m_lit(lit), @@ -204,6 +226,7 @@ namespace sat { void card_extension::copy_pb(card_extension& result) { for (pb* p : m_pbs) { + if (!p) continue; svector wlits; for (wliteral w : *p) { wlits.push_back(w); @@ -366,13 +389,12 @@ namespace sat { p.swap(num_watch, index); if (slack < bound + m_a_max) { - TRACE("sat", display(tout, p, false); for(auto j : m_pb_undef) tout << j << "\n";); + TRACE("sat", tout << p; for(auto j : m_pb_undef) tout << j << "\n";); literal_vector to_assign; while (!m_pb_undef.empty()) { index1 = m_pb_undef.back(); if (index1 == num_watch) index1 = index; // it was swapped with index above. literal lit = p[index1].second; - if (value(lit) != l_undef) std::cout << "not undef: " << index1 << " " << lit << " " << value(lit) << "\n"; SASSERT(value(lit) == l_undef); TRACE("sat", tout << index1 << " " << lit << "\n";); if (slack >= bound + p[index1].first) { @@ -484,12 +506,12 @@ namespace sat { return; } if (p.lit() == null_literal) { - unsigned max_sum = p.max_sum(); - unsigned sz = p.size(); - for (unsigned i = 0; i < sz; ++i) { - wliteral wl = p[i]; - if (p.k() > max_sum - wl.first) { - std::cout << "unit literal\n"; + for (wliteral wl : p) { + if (p.k() > p.max_sum() - wl.first) { + TRACE("sat", + tout << "unit literal " << wl.second << "\n"; + display(tout, p, true);); + s().assign(wl.second, justification()); } } } @@ -498,12 +520,11 @@ namespace sat { void card_extension::simplify(pb& p) { s().pop_to_base_level(); if (p.lit() != null_literal && value(p.lit()) == l_false) { + TRACE("sat", tout << "pb: flip sign " << p << "\n";); return; init_watch(p, !p.lit().sign()); - std::cout << "pb: flip sign\n"; } if (p.lit() != null_literal && value(p.lit()) == l_true) { - std::cout << "literal is assigned at base level " << s().at_base_lvl() << "\n"; SASSERT(lvl(p.lit()) == 0); nullify_tracking_literal(p); } @@ -522,9 +543,9 @@ namespace sat { // no op } else if (true_val >= p.k()) { - std::cout << "tautology\n"; + // std::cout << "tautology\n"; if (p.lit() != null_literal) { - std::cout << "tautology at level 0\n"; + // std::cout << "tautology at level 0\n"; s().assign(p.lit(), justification()); } remove_constraint(p); @@ -534,19 +555,19 @@ namespace sat { s().assign(~p.lit(), justification()); } else { - std::cout << "unsat during simplification\n"; + IF_VERBOSE(0, verbose_stream() << "unsat during simplification\n";); s().set_conflict(justification()); } remove_constraint(p); } else if (slack + true_val == p.k()) { - std::cout << "unit propagation\n"; + // std::cout << "unit propagation\n"; literal_vector lits(p.literals()); unit_propagation_simplification(p.lit(), lits); remove_constraint(p); } else { - std::cout << "pb value at base: " << true_val << " false: " << num_false << " size: " << p.size() << " k: " << p.k() << "\n"; + // std::cout << "pb value at base: " << true_val << " false: " << num_false << " size: " << p.size() << " k: " << p.k() << "\n"; unsigned sz = p.size(); clear_watch(p); for (unsigned i = 0; i < sz; ++i) { @@ -556,10 +577,10 @@ namespace sat { --i; } } - std::cout << "new size: " << sz << " old size " << p.size() << "\n"; + // std::cout << "new size: " << sz << " old size " << p.size() << "\n"; p.update_size(sz); p.update_k(p.k() - true_val); - // display(std::cout, c, true); + // display(verbose_stream(), c, true); if (p.lit() == null_literal) { init_watch(p, true); } @@ -568,6 +589,7 @@ namespace sat { // c will be watched once c.lit() is assigned. } simplify2(p); + m_simplify_change = true; } } @@ -1397,11 +1419,8 @@ namespace sat { break; } } - if (coeff == 0) { - - std::cout << l << " coeff: " << coeff << "\n"; - display(std::cout, p, true); - } + + CTRACE("sat", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); SASSERT(coeff > 0); unsigned slack = p.slack() - coeff; @@ -1415,10 +1434,9 @@ namespace sat { } for (; i < p.size(); ++i) { literal lit = p[i].second; - if (l_false != value(lit)) { - std::cout << l << " index: " << i << " slack: " << slack << " h: " << h << " coeff: " << coeff << "\n"; - display(std::cout, p, true); - } + CTRACE("sat", l_false != value(lit), + tout << l << " index: " << i << " slack: " << slack << " h: " << h << " coeff: " << coeff << "\n"; + display(tout, p, true);); SASSERT(l_false == value(lit)); r.push_back(~lit); } @@ -1496,6 +1514,8 @@ namespace sat { void card_extension::simplify(card& c) { SASSERT(c.lit() == null_literal || value(c.lit()) != l_false); if (c.lit() != null_literal && value(c.lit()) == l_false) { + return; +#if 0 std::ofstream ous("unit.txt"); s().display(ous); s().display_watches(ous); @@ -1503,15 +1523,13 @@ namespace sat { exit(1); return; init_watch(c, !c.lit().sign()); - std::cout << "card: flip sign\n"; +#endif } if (c.lit() != null_literal && value(c.lit()) == l_true) { - std::cout << "literal is assigned at base level " << value(c.lit()) << " " << s().at_base_lvl() << "\n"; SASSERT(lvl(c.lit()) == 0); nullify_tracking_literal(c); } if (c.lit() == null_literal && c.k() == 1) { - std::cout << "create clause\n"; literal_vector lits; for (literal l : c) lits.push_back(l); s().mk_clause(lits); @@ -1535,31 +1553,29 @@ namespace sat { return; } else if (num_true >= c.k()) { - std::cout << "tautology\n"; if (c.lit() != null_literal) { - std::cout << "tautology at level 0\n"; s().assign(c.lit(), justification()); } remove_constraint(c); } else if (num_false + c.k() > c.size()) { if (c.lit() != null_literal) { - std::cout << "falsity at level 0\n"; s().assign(~c.lit(), justification()); remove_constraint(c); } else { - std::cout << "unsat during simplification\n"; + IF_VERBOSE(1, verbose_stream() << "(sat detected unsat)\n";); } } else if (num_false + c.k() == c.size()) { - std::cout << "unit propagations : " << c.size() - num_false - num_true << "\n"; + TRACE("sat", tout << "unit propagations : " << c.size() - num_false - num_true << "\n";); literal_vector lits(c.literals()); unit_propagation_simplification(c.lit(), lits); remove_constraint(c); } else { - std::cout << "literals assigned at base: " << num_true + num_false << " " << c.size() << " k: " << c.k() << "\n"; + TRACE("sat", tout << "literals assigned at base: " << num_true + num_false << " " << c.size() << " k: " << c.k() << "\n";); + unsigned sz = c.size(); clear_watch(c); for (unsigned i = 0; i < sz; ++i) { @@ -1569,7 +1585,6 @@ namespace sat { --i; } } - std::cout << "new size: " << sz << " old size " << c.size() << "\n"; c.update_size(sz); c.update_k(c.k() - num_true); if (c.lit() == null_literal) { @@ -1579,6 +1594,7 @@ namespace sat { SASSERT(value(c.lit()) == l_undef); // c will be watched once c.lit() is assigned. } + m_simplify_change = true; } } @@ -1696,51 +1712,551 @@ namespace sat { void card_extension::simplify() { s().pop_to_base_level(); - for (card* c : m_cards) { - if (c) simplify(*c); - } - for (pb* p : m_pbs) { - if (p) simplify(*p); - } - for (xor* x : m_xors) { - if (x) simplify(*x); - } - gc(); + unsigned trail_sz; + do { + m_simplify_change = false; + trail_sz = s().init_trail_size(); + for (card* c : m_cards) { + if (c) simplify(*c); + } + for (pb* p : m_pbs) { + if (p) simplify(*p); + } + for (xor* x : m_xors) { + if (x) simplify(*x); + } + gc(); + } + while (m_simplify_change || trail_sz < s().init_trail_size()); + // or could create queue of constraints that are affected } + bool card_extension::set_root(literal l, literal r) { + for (unsigned i = m_roots.size(); i < 2 * s().num_vars(); ++i) { + m_roots.push_back(to_literal(i)); + } + m_roots[l.index()] = r; + m_roots[(~l).index()] = ~r; + return true; + } + + void card_extension::flush_roots() { + if (m_roots.empty()) return; + m_visited.resize(s().num_vars()*2, false); + for (card* c : m_cards) { + if (c) flush_roots(*c); + } + for (pb* p : m_pbs) { + if (p) flush_roots(*p); + } + for (xor* x : m_xors) { + if (x) flush_roots(*x); + } + + // display(std::cout << "flush roots\n"); + } + + void card_extension::flush_roots(card& c) { + bool found = c.lit() != null_literal && m_roots[c.lit().index()] != c.lit(); + for (literal l : c) { + if (found) break; + found = m_roots[l.index()] != l; + } + if (!found) return; + clear_watch(c); + // this could create duplicate literals + for (unsigned i = 0; i < c.size(); ++i) { + c[i] = m_roots[c[i].index()]; + } + bool found_dup = false; + for (literal l : c) { + if (is_marked(l)) { + found_dup = true; + } + else { + mark_visited(l); + mark_visited(~l); + } + } + for (literal l : c) { + unmark_visited(l); + unmark_visited(~l); + } + if (found_dup) { + recompile(c); + return; + } + + if (c.lit() != null_literal && m_roots[c.lit().index()] != c.lit()) { + literal r = m_roots[c.lit().index()]; + nullify_tracking_literal(c); + c.update_literal(r); + get_wlist(r).push_back(c.index()); + get_wlist(~r).push_back(c.index()); + } + + if (c.lit() == null_literal || value(c.lit()) == l_true) { + init_watch(c, true); + } + } + + void card_extension::recompile(card& c) { + m_count.resize(2*s().num_vars(), 0); + for (literal l : c) { + ++m_count[l.index()]; + } + unsigned k = c.k(); + bool is_card = true; + unsigned sz = c.size(); + for (unsigned i = 0; i < sz && 0 < k; ++i) { + literal l = c[i]; + while (k > 0 && + m_count[l.index()] > 0 && + m_count[(~l).index()] > 0) { + --m_count[l.index()]; + --m_count[(~l).index()]; + --k; + } + unsigned w = m_count[l.index()]; + if (w > 0) { + is_card &= w == 1; + } + else { + c.swap(i, sz - 1); + --sz; + --i; + } + } + c.update_size(sz); + c.update_k(k); + + svector wlits; + if (!is_card) { + for (literal l : c) { + unsigned w = m_count[l.index()]; + if (w > 0) { + wlits.push_back(wliteral(w, l)); + } + } + } + + // clear counts: + for (literal l : c) { + m_count[l.index()] = 0; + } + + if (k == 0) { + remove_constraint(c); + return; + } + + literal root = null_literal; + if (c.lit() != null_literal) root = m_roots[c.lit().index()]; + + if (!is_card) { + TRACE("sat", tout << "replacing by pb: " << c << "\n";); + remove_constraint(c); + add_pb_ge(root, wlits, k); + } + else { + if (c.lit() != root) { + nullify_tracking_literal(c); + c.update_literal(root); + get_wlist(root).push_back(c.index()); + get_wlist(~root).push_back(c.index()); + } + if (c.lit() == null_literal || value(c.lit()) == l_true) { + init_watch(c, true); + } + } + + } + + void card_extension::recompile(pb& p) { + m_count.resize(2*s().num_vars(), 0); + for (wliteral wl : p) { + m_count[wl.second.index()] += wl.first; + } + unsigned k = p.k(); + unsigned sz = p.size(); + for (unsigned i = 0; i < sz && 0 < k; ++i) { + wliteral wl = p[i]; + literal l = wl.second; + if (m_count[l.index()] >= m_count[(~l).index()]) { + if (k < m_count[(~l).index()]) { + k = 0; + break; + } + k -= m_count[(~l).index()]; + m_count[l.index()] -= m_count[(~l).index()]; + } + unsigned w = m_count[l.index()]; + if (w == 0) { + p.swap(i, sz - 1); + --sz; + --i; + } + else { + p[i] = wliteral(w, l); + } + } + // clear counts: + for (wliteral wl : p) { + m_count[wl.second.index()] = 0; + } + + if (k == 0) { + remove_constraint(p); + return; + } + + p.update_size(sz); + p.update_k(k); + + literal root = null_literal; + if (p.lit() != null_literal) root = m_roots[p.lit().index()]; + + // std::cout << "simplified " << p << "\n"; + if (p.lit() != root) { + nullify_tracking_literal(p); + p.update_literal(root); + get_wlist(root).push_back(p.index()); + get_wlist(~root).push_back(p.index()); + } + if (p.lit() == null_literal || value(p.lit()) == l_true) { + init_watch(p, true); + } + } + + void card_extension::flush_roots(pb& p) { + bool found = p.lit() != null_literal && m_roots[p.lit().index()] != p.lit(); + for (wliteral wl : p) { + if (found) break; + found = m_roots[wl.second.index()] != wl.second; + } + if (!found) return; + clear_watch(p); + // this could create duplicate literals + for (unsigned i = 0; i < p.size(); ++i) { + p[i].second = m_roots[p[i].second.index()]; + } + if (p.lit() != null_literal && m_roots[p.lit().index()] != p.lit()) { + literal r = m_roots[p.lit().index()]; + nullify_tracking_literal(p); + p.update_literal(r); + get_wlist(r).push_back(p.index()); + get_wlist(~r).push_back(p.index()); + } + + bool found_dup = false; + for (wliteral wl : p) { + if (is_marked(wl.second)) { + found_dup = true; + // std::cout << "Dup: " << wl.second << "\n"; + } + else { + mark_visited(wl.second); + mark_visited(~(wl.second)); + } + } + for (wliteral wl : p) { + unmark_visited(wl.second); + unmark_visited(~(wl.second)); + } + if (found_dup) { + // std::cout << "FOUND DUP " << p << "\n"; + recompile(p); + return; + } + // review for potential incompleteness: if p.lit() == l_false, do propagations happen? + if (p.lit() == null_literal || value(p.lit()) == l_true) { + init_watch(p, true); + } + } + + void card_extension::flush_roots(xor& x) { + NOT_IMPLEMENTED_YET(); + } + + + unsigned card_extension::get_num_non_learned_bin(literal l) { + return s().m_simplifier.get_num_non_learned_bin(l); + } + + /* + \brief garbage collection. + This entails + - finding pure literals, + - setting literals that are not used in the extension to non-external. + - subsumption + - resolution + - blocked literals + */ void card_extension::gc() { // remove constraints where indicator literal isn't used. - sat::use_list use_list; - use_list.init(s().num_vars()); - svector var_used(s().num_vars(), false); - for (clause* c : s().m_clauses) if (!c->frozen()) use_list.insert(*c); - for (card* c : m_cards) if (c) for (literal l : *c) var_used[l.var()] = true; - for (pb* p : m_pbs) if (p) for (wliteral wl : *p) var_used[wl.second.var()] = true; - for (xor* x : m_xors) if (x) for (literal l : *x) var_used[l.var()] = true; + m_visited.resize(s().num_vars()*2, false); + m_clause_use_list.init(s().num_vars()); + m_var_used.reset(); + m_var_used.resize(s().num_vars(), false); + m_card_use_list.reset(); + m_card_use_list.resize(2*s().num_vars(), false); + for (clause* c : s().m_clauses) if (!c->frozen()) m_clause_use_list.insert(*c); + for (card* c : m_cards) { + if (c) { + if (c->lit() != null_literal) { + m_card_use_list[c->lit().index()].push_back(c->index()); + m_card_use_list[(~c->lit()).index()].push_back(c->index()); + for (literal l : *c) m_card_use_list[(~l).index()].push_back(c->index()); + + } + for (literal l : *c) { + m_var_used[l.var()] = true; + m_card_use_list[l.index()].push_back(c->index()); + } + } + } + for (pb* p : m_pbs) { + if (p) { + if (p->lit() != null_literal) { + m_card_use_list[p->lit().index()].push_back(p->index()); + m_card_use_list[(~p->lit()).index()].push_back(p->index()); + for (wliteral wl : *p) m_card_use_list[(~wl.second).index()].push_back(p->index()); + } + for (wliteral wl : *p) { + literal l = wl.second; + m_var_used[l.var()] = true; + m_card_use_list[l.index()].push_back(p->index()); + } + } + } + for (xor* x : m_xors) { + if (x) { + m_card_use_list[x->lit().index()].push_back(x->index()); + m_card_use_list[(~x->lit()).index()].push_back(x->index()); + m_var_used[x->lit().var()] = true; + for (literal l : *x) { + m_var_used[l.var()] = true; + m_card_use_list[l.index()].push_back(x->index()); + m_card_use_list[(~l).index()].push_back(x->index()); + } + } + } for (card* c : m_cards) { - if (c && c->lit() != null_literal && !var_used[c->lit().var()] && use_list.get(c->lit()).empty() && use_list.get(~c->lit()).empty()) { + if (c && c->lit() != null_literal && + !m_var_used[c->lit().var()] && + m_clause_use_list.get(c->lit()).empty() && + m_clause_use_list.get(~c->lit()).empty() && + get_num_non_learned_bin(c->lit()) == 0 && + get_num_non_learned_bin(~c->lit()) == 0) { remove_constraint(*c); } } for (pb* p : m_pbs) { - if (p && p->lit() != null_literal && !var_used[p->lit().var()] && use_list.get(p->lit()).empty() && use_list.get(~p->lit()).empty()) { + if (p && p->lit() != null_literal && + !m_var_used[p->lit().var()] && + m_clause_use_list.get(p->lit()).empty() && + m_clause_use_list.get(~p->lit()).empty() && + get_num_non_learned_bin(p->lit()) == 0 && + get_num_non_learned_bin(~p->lit()) == 0) { remove_constraint(*p); } } // take ownership of interface variables - for (card* c : m_cards) if (c && c->lit() != null_literal) var_used[c->lit().var()] = true; - for (pb* p : m_pbs) if (p && p->lit() != null_literal) var_used[p->lit().var()] = true; + for (card* c : m_cards) if (c && c->lit() != null_literal) m_var_used[c->lit().var()] = true; + for (pb* p : m_pbs) if (p && p->lit() != null_literal) m_var_used[p->lit().var()] = true; + // set variables to be non-external if they are not used in theory constraints. unsigned ext = 0; for (unsigned v = 0; v < s().num_vars(); ++v) { - if (s().is_external(v) && !var_used[v]) { + if (s().is_external(v) && !m_var_used[v]) { s().set_non_external(v); ++ext; } } - std::cout << "non-external variables " << ext << "\n"; + // eliminate pure literals + unsigned pure_literals = 0; + for (unsigned v = 0; v < s().num_vars(); ++v) { + if (!m_var_used[v]) continue; + literal lit(v, false); + if (!m_card_use_list[lit.index()].empty() && m_card_use_list[(~lit).index()].empty() && m_clause_use_list.get(~lit).empty() && + get_num_non_learned_bin(~lit) == 0) { + s().assign(lit, justification()); + ++pure_literals; + continue; + } + lit.neg(); + if (!m_card_use_list[lit.index()].empty() && m_card_use_list[(~lit).index()].empty() && m_clause_use_list.get(~lit).empty() && get_num_non_learned_bin(~lit) == 0) { + s().assign(lit, justification()); + ++pure_literals; + } + } + IF_VERBOSE(10, + verbose_stream() << "non-external variables converted: " << ext << "\n"; + verbose_stream() << "pure literals converted: " << pure_literals << "\n";); + + m_cleanup_clauses = false; + for (card* c : m_cards) { + if (c && c->k() > 1) { + subsumption(*c); + } + } + if (m_cleanup_clauses) { + clause_vector::iterator it = s().m_clauses.begin(); + clause_vector::iterator end = s().m_clauses.end(); + clause_vector::iterator it2 = it; + for (; it != end; ++it) { + clause* c = *it; + if (c->was_removed()) { + s().detach_clause(*c); + s().del_clause(*c); + } + else { + if (it2 != it) { + *it2 = *it; + } + ++it2; + } + } + s().m_clauses.set_end(it2); + } + } + + /* + \brief subsumption between two cardinality constraints + - A >= k subsumes A + B >= k' for k' <= k + - A + A' >= k subsumes A + B >= k' for k' + |A'| <= k + - A + lit >= k self subsumes A + ~lit + B >= k' into A + B >= k' for k' <= k + - TBD: consider version that generalizes self-subsumption to more than one literal + A + ~L + B >= k' => A + B >= k' if A + A' + L >= k and k' + |L| + |A'| <= k + */ + bool card_extension::subsumes(card& c1, card& c2, literal_vector & comp) { + if (c2.lit() != null_literal) return false; // perhaps support this? + + unsigned c2_exclusive = 0; + unsigned common = 0; + comp.empty(); + for (literal l : c2) { + if (is_marked(l)) { + ++common; + } + else if (!is_marked(~l)) { + ++c2_exclusive; + } + else { + comp.push_back(l); + } + } + + unsigned c1_exclusive = c1.size() - common - comp.size(); + + return c1_exclusive + c2.k() + comp.size() <= c1.k(); + } + + bool card_extension::subsumes(card& c1, clause& c2, literal_vector & comp) { + unsigned c2_exclusive = 0; + unsigned common = 0; + comp.reset(); + for (literal l : c2) { + if (is_marked(l)) { + ++common; + } + else if (!is_marked(~l)) { + ++c2_exclusive; + } + else { + comp.push_back(l); + } + } + + if (!comp.empty()) { + // self-subsumption is TBD. + return false; + } + unsigned c1_exclusive = c1.size() - common - comp.size(); + if (c1_exclusive + 1 <= c1.k()) { + return true; + } + + return false; + } + + literal card_extension::get_min_occurrence_literal(card const& c) { + unsigned occ_count = UINT_MAX; + literal lit = null_literal; + for (literal l : c) { + unsigned occ_count1 = m_card_use_list[l.index()].size(); + if (occ_count1 < occ_count) { + lit = l; + occ_count = occ_count1; + } + } + return lit; + } + + void card_extension::subsumption(card& c1) { + if (c1.lit() != null_literal) { + return; + } + literal lit = get_min_occurrence_literal(c1); + literal_vector slit; + // maybe index over (~lit) to catch self-subsumption. + + for (literal l : c1) mark_visited(l); + + for (unsigned index : m_card_use_list[lit.index()]) { + if (!is_card_index(index) || index == c1.index()) { + continue; + } + // c2 could be null + card* c = m_cards[index2position(index)]; + if (!c) continue; + card& c2 = *c; + + SASSERT(c1.index() != c2.index()); + if (subsumes(c1, c2, slit)) { + if (slit.empty()) { + TRACE("sat", tout << "subsume cardinality\n" << c1.index() << ":" << c1 << "\n" << c2.index() << ":" << c2 << "\n";); + remove_constraint(c2); + } + else { + TRACE("sat", tout << "self subsume carinality\n";); +#if 0 + clear_watch(c2); + for (unsigned i = 0; i < c2.size(); ++i) { + if (slit == c2[i]) { + c2.swap(i, c2.size() -1); + break; + } + } + c2.update_size(c2.size() - 1); + init_watch(c2, true); + m_simplify_change = true; +#endif + } + } + } + + // same for clauses... + clause_use_list::iterator it = m_clause_use_list.get(lit).mk_iterator(); + while (!it.at_end()) { + clause& c2 = it.curr(); + if (!c2.was_removed() && subsumes(c1, c2, slit)) { + if (slit.empty()) { + TRACE("sat", tout << "remove\n" << c1 << "\n" << c2 << "\n";); + c2.set_removed(true); + m_cleanup_clauses = true; + } + else { + // remove literal slit from c2. + TRACE("sat", tout << "TBD remove literals " << slit << " from " << c2 << "\n";); + } + } + it.next(); + } + + for (literal l : c1) unmark_visited(l); } void card_extension::clauses_modifed() {} @@ -1749,6 +2265,7 @@ namespace sat { void card_extension::copy_card(card_extension& result) { for (card* c : m_cards) { + if (!c) continue; literal_vector lits; for (literal l : *c) lits.push_back(l); result.add_at_least(c->lit(), lits, c->k()); @@ -1864,10 +2381,10 @@ namespace sat { std::ostream& card_extension::display(std::ostream& out) const { for (card* c : m_cards) { - if (c) display(out, *c, false); + if (c) out << *c << "\n"; } for (pb* p : m_pbs) { - if (p) display(out, *p, false); + if (p) out << *p << "\n"; } for (xor* x : m_xors) { if (x) display(out, *x, false); @@ -2092,7 +2609,7 @@ namespace sat { unsigned coeff; if (coeffs.find(lit.index(), coeff)) { if (coeff > m_C.m_coeffs[i] && m_C.m_coeffs[i] < m_C.m_k) { - std::cout << i << ": " << m_C.m_coeffs[i] << " " << m_C.m_k << "\n"; + IF_VERBOSE(0, verbose_stream() << i << ": " << m_C.m_coeffs[i] << " " << m_C.m_k << "\n";); goto violated; } coeffs.remove(lit.index()); @@ -2105,13 +2622,13 @@ namespace sat { return true; violated: - display(std::cout, m_A); - display(std::cout, m_B); - display(std::cout, m_C); - u_map::iterator it = coeffs.begin(), end = coeffs.end(); - for (; it != end; ++it) { - std::cout << to_literal(it->m_key) << ": " << it->m_value << "\n"; - } + IF_VERBOSE(0, + display(verbose_stream(), m_A); + display(verbose_stream(), m_B); + display(verbose_stream(), m_C); + for (auto& e : coeffs) { + verbose_stream() << to_literal(e.m_key) << ": " << e.m_value << "\n"; + }); return false; } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 64553795b..c3f8e430f 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -59,6 +59,7 @@ namespace sat { unsigned index() const { return m_index; } literal lit() const { return m_lit; } literal operator[](unsigned i) const { return m_lits[i]; } + literal& operator[](unsigned i) { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return static_cast(m_lits) + m_size; } unsigned k() const { return m_k; } @@ -67,9 +68,12 @@ namespace sat { void negate(); void update_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } void update_k(unsigned k) { m_k = k; } + void update_literal(literal l) { m_lit = l; } void nullify_literal() { m_lit = null_literal; } - literal_vector literals() const { return literal_vector(m_size, m_lits); } + literal_vector literals() const { return literal_vector(m_size, m_lits); } }; + + friend std::ostream& operator<<(std::ostream& out, card const& c); typedef std::pair wliteral; @@ -89,6 +93,7 @@ namespace sat { unsigned index() const { return m_index; } literal lit() const { return m_lit; } wliteral operator[](unsigned i) const { return m_wlits[i]; } + wliteral& operator[](unsigned i) { return m_wlits[i]; } wliteral const* begin() const { return m_wlits; } wliteral const* end() const { return static_cast(m_wlits) + m_size; } @@ -102,11 +107,14 @@ namespace sat { void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } void negate(); void update_size(unsigned sz) { m_size = sz; update_max_sum(); } - void update_k(unsigned k) { m_k = k; } + void update_k(unsigned k) { m_k = k; } + void update_literal(literal l) { m_lit = l; } void nullify_literal() { m_lit = null_literal; } literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } }; + friend std::ostream& operator<<(std::ostream& out, pb const& p); + class xor { unsigned m_index; literal m_lit; @@ -168,8 +176,26 @@ namespace sat { void clear_index_trail_back(); solver& s() const { return *m_solver; } + + // simplification routines + svector m_visited; + vector> m_card_use_list; + use_list m_clause_use_list; + svector m_var_used; + bool m_simplify_change; + bool m_cleanup_clauses; + literal_vector m_roots; + unsigned_vector m_count; void gc(); + bool subsumes(card& c1, card& c2, literal_vector& comp); + bool subsumes(card& c1, clause& c2, literal_vector& comp); + void mark_visited(literal l) { m_visited[l.index()] = true; } + void unmark_visited(literal l) { m_visited[l.index()] = false; } + bool is_marked(literal l) const { return m_visited[l.index()] != 0; } + unsigned get_num_non_learned_bin(literal l); + literal get_min_occurrence_literal(card const& c); + void subsumption(card& c1); // cardinality void init_watch(card& c); @@ -189,6 +215,8 @@ namespace sat { void nullify_tracking_literal(card& c); void remove_constraint(card& c); void unit_propagation_simplification(literal lit, literal_vector const& lits); + void flush_roots(card& c); + void recompile(card& c); // xor specific functionality void copy_xor(card_extension& result); @@ -203,6 +231,7 @@ namespace sat { void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); void get_xor_antecedents(literal l, xor const& x, literal_vector & r); void simplify(xor& x); + void flush_roots(xor& x); bool is_card_index(unsigned idx) const { return 0x0 == (idx & 0x3); } @@ -231,6 +260,8 @@ namespace sat { bool is_cardinality(pb const& p); void nullify_tracking_literal(pb& p); void remove_constraint(pb& p); + void flush_roots(pb& p); + void recompile(pb& p); inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } @@ -301,6 +332,8 @@ namespace sat { virtual void simplify(); virtual void clauses_modifed(); virtual lbool get_phase(bool_var v); + virtual bool set_root(literal l, literal r); + virtual void flush_roots(); virtual std::ostream& display(std::ostream& out) const; virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; virtual void collect_statistics(statistics& st) const; diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index b9b7dbd85..f51b8c42d 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -189,7 +189,8 @@ namespace sat { literal l(v, false); literal r = roots[v]; SASSERT(v != r.var()); - if (m_solver.is_external(v)) { + if (m_solver.is_external(v) && !m_solver.set_root(l, r)) { + std::cout << "skip: " << l << " == " << r << "\n"; // cannot really eliminate v, since we have to notify extension of future assignments m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(l, ~r, false); @@ -201,6 +202,7 @@ namespace sat { mc.insert(e, ~l, r); mc.insert(e, l, ~r); } + m_solver.flush_roots(); } } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 44a704f80..d3a58810c 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -42,6 +42,9 @@ namespace sat { virtual void push() = 0; virtual void pop(unsigned n) = 0; virtual void simplify() = 0; + // have a way to replace l by r in all constraints + virtual bool set_root(literal l, literal r) { return false; } + virtual void flush_roots() {} virtual void clauses_modifed() = 0; virtual lbool get_phase(bool_var v) = 0; virtual std::ostream& display(std::ostream& out) const = 0; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 5372011ed..e42076de4 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -394,6 +394,7 @@ namespace sat { << " :flips " << flips \ << " :noise " << m_noise \ << " :unsat " << /*m_unsat_stack.size()*/ m_best_unsat \ + << " :constraints " << m_constraints.size() \ << " :time " << (timer.get_seconds() < 0.001 ? 0.0 : timer.get_seconds()) << ")\n";); \ } @@ -419,7 +420,7 @@ namespace sat { } total_flips += step; PROGRESS(tries, total_flips); - if (m_par && tries % 20 == 0) { + if (m_par && tries % 1 == 0) { m_par->get_phase(*this); reinit(); } @@ -489,7 +490,7 @@ namespace sat { result = l_undef; } IF_VERBOSE(1, verbose_stream() << "(sat-local-search " << result << ")\n";); - IF_VERBOSE(2, display(verbose_stream());); + IF_VERBOSE(20, display(verbose_stream());); return result; } @@ -810,7 +811,6 @@ namespace sat { constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; // a random unsat constraint // Within c, from all slack increasing var, choose the oldest one unsigned c_size = c.size(); - //std::cout << "rd\t"; for (unsigned i = 0; i < c_size; ++i) { bool_var v = c[i].var(); if (is_true(c[i]) && time_stamp(v) < time_stamp(best_var)) diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 81de935b1..c6f340f2e 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -34,8 +34,7 @@ namespace sat { } model_converter& model_converter::operator=(model_converter const& other) { - reset(); - m_entries.append(other.m_entries); + copy(other); return *this; } @@ -50,10 +49,7 @@ namespace sat { // and the following procedure flips its value. bool sat = false; bool var_sign = false; - literal_vector::const_iterator it2 = it->m_clauses.begin(); - literal_vector::const_iterator end2 = it->m_clauses.end(); - for (; it2 != end2; ++it2) { - literal l = *it2; + for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause if (!sat) { @@ -80,9 +76,7 @@ namespace sat { DEBUG_CODE({ // all clauses must be satisfied bool sat = false; - it2 = it->m_clauses.begin(); - for (; it2 != end2; ++it2) { - literal l = *it2; + for (literal l : it->m_clauses) { if (l == null_literal) { SASSERT(sat); sat = false; @@ -145,10 +139,7 @@ namespace sat { SASSERT(c.contains(e.var())); SASSERT(m_entries.begin() <= &e); SASSERT(&e < m_entries.end()); - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - e.m_clauses.push_back(c[i]); - } + for (literal l : c) e.m_clauses.push_back(l); e.m_clauses.push_back(null_literal); TRACE("sat_mc_bug", tout << "adding: " << c << "\n";); } @@ -168,10 +159,10 @@ namespace sat { SASSERT(m_entries.begin() <= &e); SASSERT(&e < m_entries.end()); unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) + for (unsigned i = 0; i < sz; ++i) e.m_clauses.push_back(c[i]); e.m_clauses.push_back(null_literal); - TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (unsigned i = 0; i < c.size(); i++) tout << c[i] << " "; tout << "\n";); + TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (literal l : c) tout << l << " "; tout << "\n";); } bool model_converter::check_invariant(unsigned num_vars) const { @@ -186,12 +177,10 @@ namespace sat { it2++; for (; it2 != end; ++it2) { SASSERT(it2->var() != it->var()); - literal_vector::const_iterator it3 = it2->m_clauses.begin(); - literal_vector::const_iterator end3 = it2->m_clauses.end(); - for (; it3 != end3; ++it3) { - CTRACE("sat_model_converter", it3->var() == it->var(), tout << "var: " << it->var() << "\n"; display(tout);); - SASSERT(it3->var() != it->var()); - SASSERT(*it3 == null_literal || it3->var() < num_vars); + for (literal l : it2->m_clauses) { + CTRACE("sat_model_converter", l.var() == it->var(), tout << "var: " << it->var() << "\n"; display(tout);); + SASSERT(l.var() != it->var()); + SASSERT(l == null_literal || l.var() < num_vars); } } } @@ -201,28 +190,24 @@ namespace sat { void model_converter::display(std::ostream & out) const { out << "(sat::model-converter"; - vector::const_iterator it = m_entries.begin(); - vector::const_iterator end = m_entries.end(); - for (; it != end; ++it) { - out << "\n (" << (it->get_kind() == ELIM_VAR ? "elim" : "blocked") << " " << it->var(); + for (auto & entry : m_entries) { + out << "\n (" << (entry.get_kind() == ELIM_VAR ? "elim" : "blocked") << " " << entry.var(); bool start = true; - literal_vector::const_iterator it2 = it->m_clauses.begin(); - literal_vector::const_iterator end2 = it->m_clauses.end(); - for (; it2 != end2; ++it2) { + for (literal l : entry.m_clauses) { if (start) { out << "\n ("; start = false; } else { - if (*it2 != null_literal) + if (l != null_literal) out << " "; } - if (*it2 == null_literal) { + if (l == null_literal) { out << ")"; start = true; continue; } - out << *it2; + out << l; } out << ")"; } @@ -230,18 +215,12 @@ namespace sat { } void model_converter::copy(model_converter const & src) { - vector::const_iterator it = src.m_entries.begin(); - vector::const_iterator end = src.m_entries.end(); - for (; it != end; ++it) - m_entries.push_back(*it); + reset(); + m_entries.append(src.m_entries); } void model_converter::collect_vars(bool_var_set & s) const { - vector::const_iterator it = m_entries.begin(); - vector::const_iterator end = m_entries.end(); - for (; it != end; ++it) { - s.insert(it->m_var); - } + for (entry const & e : m_entries) s.insert(e.m_var); } }; diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 0b9a5bcb3..21f98cd6a 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -127,7 +127,7 @@ namespace sat { void parallel::exchange(solver& s, literal_vector const& in, unsigned& limit, literal_vector& out) { - if (s.m_par_syncing_clauses) return; + if (s.get_config().m_num_threads == 1 || s.m_par_syncing_clauses) return; flet _disable_sync_clause(s.m_par_syncing_clauses, true); #pragma omp critical (par_solver) { @@ -147,11 +147,11 @@ namespace sat { } void parallel::share_clause(solver& s, literal l1, literal l2) { - if (s.m_par_syncing_clauses) return; + if (s.get_config().m_num_threads == 1 || s.m_par_syncing_clauses) return; flet _disable_sync_clause(s.m_par_syncing_clauses, true); + IF_VERBOSE(3, verbose_stream() << s.m_par_id << ": share " << l1 << " " << l2 << "\n";); #pragma omp critical (par_solver) { - IF_VERBOSE(3, verbose_stream() << s.m_par_id << ": share " << l1 << " " << l2 << "\n";); m_pool.begin_add_vector(s.m_par_id, 2); m_pool.add_vector_elem(l1.index()); m_pool.add_vector_elem(l2.index()); @@ -160,13 +160,13 @@ namespace sat { } void parallel::share_clause(solver& s, clause const& c) { - if (!enable_add(c) || s.m_par_syncing_clauses) return; + if (s.get_config().m_num_threads == 1 || !enable_add(c) || s.m_par_syncing_clauses) return; flet _disable_sync_clause(s.m_par_syncing_clauses, true); unsigned n = c.size(); unsigned owner = s.m_par_id; + IF_VERBOSE(3, verbose_stream() << owner << ": share " << c << "\n";); #pragma omp critical (par_solver) { - IF_VERBOSE(3, verbose_stream() << owner << ": share " << c << "\n";); m_pool.begin_add_vector(owner, n); for (unsigned i = 0; i < n; ++i) { m_pool.add_vector_elem(c[i].index()); @@ -229,7 +229,8 @@ namespace sat { break; } } - if (90 * m_num_clauses > 100 * s.m_clauses.size() && !m_solver_copy) { + IF_VERBOSE(1, verbose_stream() << "set phase: " << m_num_clauses << " " << s.m_clauses.size() << " " << m_solver_copy << "\n";); + if (m_num_clauses == 0 || (m_num_clauses > s.m_clauses.size())) { // time to update local search with new clauses. // there could be multiple local search engines runing at the same time. IF_VERBOSE(1, verbose_stream() << "(sat-parallel refresh local search " << m_num_clauses << " -> " << s.m_clauses.size() << ")\n";); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 4750f8e76..9c31f4005 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -354,17 +354,15 @@ namespace sat { Otherwise return false */ bool simplifier::subsumes1(clause const & c1, clause const & c2, literal & l) { - unsigned sz2 = c2.size(); - for (unsigned i = 0; i < sz2; i++) - mark_visited(c2[i]); + for (literal lit : c2) + mark_visited(lit); bool r = true; l = null_literal; - unsigned sz1 = c1.size(); - for (unsigned i = 0; i < sz1; i++) { - if (!is_marked(c1[i])) { - if (l == null_literal && is_marked(~c1[i])) { - l = ~c1[i]; + for (literal lit : c1) { + if (!is_marked(lit)) { + if (l == null_literal && is_marked(~lit)) { + l = ~lit; } else { l = null_literal; @@ -374,8 +372,8 @@ namespace sat { } } - for (unsigned i = 0; i < sz2; i++) - unmark_visited(c2[i]); + for (literal lit : c2) + unmark_visited(lit); return r; } @@ -964,40 +962,37 @@ namespace sat { if (!process_var(l.var())) { return; } + + m_to_remove.reset(); { - m_to_remove.reset(); - { - clause_use_list & occs = s.m_use_list.get(l); - clause_use_list::iterator it = occs.mk_iterator(); - while (!it.at_end()) { - clause & c = it.curr(); - m_counter -= c.size(); - SASSERT(c.contains(l)); - s.mark_all_but(c, l); - if (all_tautology(l)) { - TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); - if (new_entry == 0) - new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); - m_to_remove.push_back(&c); - s.m_num_blocked_clauses++; - mc.insert(*new_entry, c); - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - literal lit = c[i]; - if (lit != l && process_var(lit.var())) { - m_queue.decreased(~lit); - } + clause_use_list & occs = s.m_use_list.get(l); + clause_use_list::iterator it = occs.mk_iterator(); + while (!it.at_end()) { + clause & c = it.curr(); + m_counter -= c.size(); + SASSERT(c.contains(l)); + s.mark_all_but(c, l); + if (all_tautology(l)) { + TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); + if (new_entry == 0) + new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); + m_to_remove.push_back(&c); + s.m_num_blocked_clauses++; + mc.insert(*new_entry, c); + unsigned sz = c.size(); + for (unsigned i = 0; i < sz; i++) { + literal lit = c[i]; + if (lit != l && process_var(lit.var())) { + m_queue.decreased(~lit); } } - s.unmark_all(c); - it.next(); } - } - clause_vector::iterator it = m_to_remove.begin(); - clause_vector::iterator end = m_to_remove.end(); - for (; it != end; ++it) { - s.remove_clause(*(*it)); - } + s.unmark_all(c); + it.next(); + } + } + for (clause* c : m_to_remove) { + s.remove_clause(*c); } { watch_list & wlist = s.get_wlist(~l); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 0f0b1d71e..6429ce6eb 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -47,6 +47,7 @@ namespace sat { }; class simplifier { + friend class card_extension; solver & s; unsigned m_num_calls; use_list m_use_list; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2aa944087..4e34579a7 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1072,9 +1072,8 @@ namespace sat { \brief import lemmas/units from parallel sat solvers. */ void solver::exchange_par() { - if (m_par && at_search_lvl()) m_par->set_phase(*this); - if (m_par && at_base_lvl()) m_par->get_clauses(*this); - if (m_par && at_base_lvl()) { + if (m_par && at_base_lvl() && m_config.m_num_threads > 1) m_par->get_clauses(*this); + if (m_par && at_base_lvl() && m_config.m_num_threads > 1) { // SASSERT(scope_lvl() == search_lvl()); // TBD: import also dependencies of assumptions. unsigned sz = init_trail_size(); @@ -1463,7 +1462,17 @@ namespace sat { } #endif + if (m_par) m_par->set_phase(*this); + + } + + bool solver::set_root(literal l, literal r) { + return !m_ext || m_ext->set_root(l, r); + } + + void solver::flush_roots() { + if (m_ext) m_ext->flush_roots(); } void solver::sort_watch_lits() { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c534ae828..eb7dd9c70 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -315,6 +315,8 @@ namespace sat { config const& get_config() const { return m_config; } extension* get_extension() const { return m_ext.get(); } void set_extension(extension* e); + bool set_root(literal l, literal r); + void flush_roots(); typedef std::pair bin_clause; protected: watch_list & get_wlist(literal l) { return m_watches[l.index()]; } From 94416bea52ef048b58806a90d6453048fa0c6ff2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Jun 2017 09:07:55 -0700 Subject: [PATCH 0174/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 66 ++++++++++++++++++++++++++++++-------- src/sat/card_extension.h | 7 ++++ 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 85d812cc3..d6f23ad3d 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -2097,11 +2097,17 @@ namespace sat { verbose_stream() << "pure literals converted: " << pure_literals << "\n";); m_cleanup_clauses = false; + unsigned bin_sub = m_stats.m_num_bin_subsumes; + unsigned clause_sub = m_stats.m_num_clause_subsumes; + unsigned card_sub = m_stats.m_num_card_subsumes; for (card* c : m_cards) { if (c && c->k() > 1) { subsumption(*c); } } + IF_VERBOSE(1, verbose_stream() << "binary subsumes: " << m_stats.m_num_bin_subsumes - bin_sub << "\n";); + IF_VERBOSE(1, verbose_stream() << "clause subsumes: " << m_stats.m_num_clause_subsumes - clause_sub << "\n";); + IF_VERBOSE(1, verbose_stream() << "card subsumes: " << m_stats.m_num_card_subsumes - card_sub << "\n";); if (m_cleanup_clauses) { clause_vector::iterator it = s().m_clauses.begin(); clause_vector::iterator end = s().m_clauses.end(); @@ -2195,16 +2201,8 @@ namespace sat { return lit; } - void card_extension::subsumption(card& c1) { - if (c1.lit() != null_literal) { - return; - } - literal lit = get_min_occurrence_literal(c1); + void card_extension::card_subsumption(card& c1, literal lit) { literal_vector slit; - // maybe index over (~lit) to catch self-subsumption. - - for (literal l : c1) mark_visited(l); - for (unsigned index : m_card_use_list[lit.index()]) { if (!is_card_index(index) || index == c1.index()) { continue; @@ -2219,9 +2217,11 @@ namespace sat { if (slit.empty()) { TRACE("sat", tout << "subsume cardinality\n" << c1.index() << ":" << c1 << "\n" << c2.index() << ":" << c2 << "\n";); remove_constraint(c2); + ++m_stats.m_num_card_subsumes; } else { TRACE("sat", tout << "self subsume carinality\n";); + IF_VERBOSE(0, verbose_stream() << "self-subsume cardinality is TBD\n";); #if 0 clear_watch(c2); for (unsigned i = 0; i < c2.size(); ++i) { @@ -2237,25 +2237,65 @@ namespace sat { } } } - - // same for clauses... + } + + void card_extension::clause_subsumption(card& c1, literal lit) { + literal_vector slit; clause_use_list::iterator it = m_clause_use_list.get(lit).mk_iterator(); while (!it.at_end()) { clause& c2 = it.curr(); if (!c2.was_removed() && subsumes(c1, c2, slit)) { if (slit.empty()) { TRACE("sat", tout << "remove\n" << c1 << "\n" << c2 << "\n";); - c2.set_removed(true); - m_cleanup_clauses = true; + //c2.set_removed(true); + //m_cleanup_clauses = true; + ++m_stats.m_num_clause_subsumes; } else { + IF_VERBOSE(0, verbose_stream() << "self-subsume clause is TBD\n";); // remove literal slit from c2. TRACE("sat", tout << "TBD remove literals " << slit << " from " << c2 << "\n";); } } it.next(); } + } + void card_extension::binary_subsumption(card& c1, literal lit) { + SASSERT(is_marked(lit)); + watch_list & wlist = get_wlist(~lit); + watch_list::iterator it = wlist.begin(); + watch_list::iterator it2 = it; + watch_list::iterator end = wlist.end(); + for (; it != end; ++it) { + watched w = *it; + if (w.is_binary_clause() && is_marked(w.get_literal())) { + ++m_stats.m_num_bin_subsumes; + IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); + } + else { + if (it != it2) { + *it2 = *it; + } + ++it2; + } + } + if (it != it2) { + wlist.set_end(it2); + } + } + + void card_extension::subsumption(card& c1) { + if (c1.lit() != null_literal) { + return; + } + for (literal l : c1) mark_visited(l); + for (unsigned i = 0; i < std::min(c1.size(), c1.k() + 1); ++i) { + literal lit = c1[i]; + card_subsumption(c1, lit); + clause_subsumption(c1, lit); + binary_subsumption(c1, lit); + } for (literal l : c1) unmark_visited(l); } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index c3f8e430f..15d4c96b9 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -41,6 +41,9 @@ namespace sat { unsigned m_num_pb_propagations; unsigned m_num_pb_conflicts; unsigned m_num_pb_resolves; + unsigned m_num_bin_subsumes; + unsigned m_num_clause_subsumes; + unsigned m_num_card_subsumes; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -190,6 +193,10 @@ namespace sat { void gc(); bool subsumes(card& c1, card& c2, literal_vector& comp); bool subsumes(card& c1, clause& c2, literal_vector& comp); + bool subsumed(card& c1, literal l1, literal l2); + void binary_subsumption(card& c1, literal lit); + void clause_subsumption(card& c1, literal lit); + void card_subsumption(card& c1, literal lit); void mark_visited(literal l) { m_visited[l.index()] = true; } void unmark_visited(literal l) { m_visited[l.index()] = false; } bool is_marked(literal l) const { return m_visited[l.index()] != 0; } From 6f4c873b296327d12e6c7b0eb126a18a3b569b72 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Jun 2017 13:18:20 -0700 Subject: [PATCH 0175/1283] debugging Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 186 +++++++++--------- src/sat/sat_lookahead.cpp | 5 +- src/sat/sat_model_converter.cpp | 2 +- src/sat/sat_solver.cpp | 16 +- src/tactic/arith/bound_manager.cpp | 13 ++ src/tactic/arith/bound_manager.h | 2 + .../portfolio/bounded_int2bv_solver.cpp | 13 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 9 files changed, 139 insertions(+), 102 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index d6f23ad3d..690ed042d 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -281,106 +281,109 @@ namespace sat { for (unsigned i = 0; i < num_watch; ++i) { watch_literal(p, p[i]); } - p.set_slack(slack); - p.set_num_watch(num_watch); - } - TRACE("sat", display(tout << "init watch: ", p, true);); - } +p.set_slack(slack); +p.set_num_watch(num_watch); + } + TRACE("sat", display(tout << "init watch: ", p, true);); + } - /* - Chai Kuhlmann: - Lw - set of watched literals - Lu - set of unwatched literals that are not false - - Lw = Lw \ { alit } - Sw -= value - a_max = max { a | l in Lw u Lu, l = undef } - while (Sw < k + a_max & Lu != 0) { - a_s = max { a | l in Lu } - Sw += a_s - Lw = Lw u {l_s} - Lu = Lu \ {l_s} - } - if (Sw < k) conflict - while (Sw < k + a_max) { - assign (l_max) - a_max = max { ai | li in Lw, li = undef } - } - ASSERT(Sw >= bound) - return no-conflict + /* + Chai Kuhlmann: + Lw - set of watched literals + Lu - set of unwatched literals that are not false - a_max index: index of non-false literal with maximal weight. - - - */ - void card_extension::add_index(pb& p, unsigned index, literal lit) { - if (value(lit) == l_undef) { - m_pb_undef.push_back(index); - if (p[index].first > m_a_max) { - m_a_max = p[index].first; - } - } - } + Lw = Lw \ { alit } + Sw -= value + a_max = max { a | l in Lw u Lu, l = undef } + while (Sw < k + a_max & Lu != 0) { + a_s = max { a | l in Lu } + Sw += a_s + Lw = Lw u {l_s} + Lu = Lu \ {l_s} + } + if (Sw < k) conflict + while (Sw < k + a_max) { + assign (l_max) + a_max = max { ai | li in Lw, li = undef } + } + ASSERT(Sw >= bound) + return no-conflict - lbool card_extension::add_assign(pb& p, literal alit) { + a_max index: index of non-false literal with maximal weight. - TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); - SASSERT(!inconsistent()); - unsigned sz = p.size(); - unsigned bound = p.k(); - unsigned num_watch = p.num_watch(); - unsigned slack = p.slack(); - SASSERT(value(alit) == l_false); - SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); - SASSERT(num_watch <= sz); - SASSERT(num_watch > 0); - unsigned index = 0; - m_a_max = 0; - m_pb_undef.reset(); - for (; index < num_watch; ++index) { - literal lit = p[index].second; - if (lit == alit) { - break; - } - add_index(p, index, lit); - } - SASSERT(index < num_watch); - unsigned index1 = index + 1; - for (; m_a_max == 0 && index1 < num_watch; ++index1) { - add_index(p, index1, p[index1].second); - } + */ + void card_extension::add_index(pb& p, unsigned index, literal lit) { + if (value(lit) == l_undef) { + m_pb_undef.push_back(index); + if (p[index].first > m_a_max) { + m_a_max = p[index].first; + } + } + } - unsigned val = p[index].first; - SASSERT(value(p[index].second) == l_false); - SASSERT(val <= slack); - slack -= val; - // find literals to swap with: - for (unsigned j = num_watch; j < sz && slack < bound + m_a_max; ++j) { - literal lit = p[j].second; - if (value(lit) != l_false) { - slack += p[j].first; - watch_literal(p, p[j]); - p.swap(num_watch, j); - add_index(p, num_watch, lit); - ++num_watch; - } - } + lbool card_extension::add_assign(pb& p, literal alit) { - SASSERT(!inconsistent()); - DEBUG_CODE(for (auto idx : m_pb_undef) { SASSERT(value(p[idx].second) == l_undef); }); + TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + SASSERT(!inconsistent()); + unsigned sz = p.size(); + unsigned bound = p.k(); + unsigned num_watch = p.num_watch(); + unsigned slack = p.slack(); + SASSERT(value(alit) == l_false); + SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); + SASSERT(num_watch <= sz); + SASSERT(num_watch > 0); + unsigned index = 0; + m_a_max = 0; + m_pb_undef.reset(); + for (; index < num_watch; ++index) { + literal lit = p[index].second; + if (lit == alit) { + break; + } + add_index(p, index, lit); + } + SASSERT(index < num_watch); - if (slack < bound) { - // maintain watching the literal - slack += val; - p.set_slack(slack); - p.set_num_watch(num_watch); - SASSERT(bound <= slack); - TRACE("sat", tout << "conflict " << alit << "\n";); - set_conflict(p, alit); - return l_false; - } + unsigned index1 = index + 1; + for (; m_a_max == 0 && index1 < num_watch; ++index1) { + add_index(p, index1, p[index1].second); + } + unsigned val = p[index].first; + SASSERT(value(p[index].second) == l_false); + SASSERT(val <= slack); + slack -= val; + // find literals to swap with: + for (unsigned j = num_watch; j < sz && slack < bound + m_a_max; ++j) { + literal lit = p[j].second; + if (value(lit) != l_false) { + slack += p[j].first; + watch_literal(p, p[j]); + p.swap(num_watch, j); + add_index(p, num_watch, lit); + ++num_watch; + } + } + + SASSERT(!inconsistent()); + DEBUG_CODE(for (auto idx : m_pb_undef) { SASSERT(value(p[idx].second) == l_undef); }); + + if (slack < bound) { + // maintain watching the literal + slack += val; + p.set_slack(slack); + p.set_num_watch(num_watch); + SASSERT(bound <= slack); + TRACE("sat", tout << "conflict " << alit << "\n";); + set_conflict(p, alit); + return l_false; + } + + if (index > p.size() || num_watch > p.size()) { + std::cout << "size: " << p.size() << "index: " << index << " num watch: " << num_watch << "\n"; + } // swap out the watched literal. --num_watch; SASSERT(num_watch > 0); @@ -1711,6 +1714,7 @@ namespace sat { } void card_extension::simplify() { + return; s().pop_to_base_level(); unsigned trail_sz; do { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 95b11fa15..2a1837e20 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1734,11 +1734,14 @@ namespace sat { } IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << ")\n";); - if (num_units > 0 && !m_s.inconsistent()) { + if (m_s.inconsistent()) return; + + if (num_units > 0) { m_s.propagate_core(false); m_s.m_simplifier(false); } m_lookahead.reset(); + } // diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index c6f340f2e..45429805c 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -162,7 +162,7 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) e.m_clauses.push_back(c[i]); e.m_clauses.push_back(null_literal); - TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (literal l : c) tout << l << " "; tout << "\n";); + // TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (literal l : c) tout << l << " "; tout << "\n";); } bool model_converter::check_invariant(unsigned num_vars) const { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4e34579a7..13f0246af 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1415,10 +1415,16 @@ namespace sat { } if (m_config.m_lookahead_simplify) { - lookahead lh(*this); - lh.simplify(); - lh.scc(); - lh.collect_statistics(m_aux_stats); + { + lookahead lh(*this); + lh.simplify(); + lh.collect_statistics(m_aux_stats); + } + { + lookahead lh(*this); + lh.scc(); + lh.collect_statistics(m_aux_stats); + } } sort_watch_lits(); @@ -1450,7 +1456,7 @@ namespace sat { m_next_simplify = m_conflicts_since_init + m_config.m_simplify_max; } -#if 1 +#if 0 static unsigned file_no = 0; #pragma omp critical (print_sat) { diff --git a/src/tactic/arith/bound_manager.cpp b/src/tactic/arith/bound_manager.cpp index 97d93658c..02671ee15 100644 --- a/src/tactic/arith/bound_manager.cpp +++ b/src/tactic/arith/bound_manager.cpp @@ -28,6 +28,19 @@ bound_manager::~bound_manager() { reset(); } +bound_manager* bound_manager::translate(ast_manager& dst_m) { + bound_manager* result = alloc(bound_manager, dst_m); + ast_translation tr(m(), dst_m); + expr_dependency_translation edtr(tr); + for (auto& kv : m_lowers) result->m_lowers.insert(tr(kv.m_key), kv.m_value); + for (auto& kv : m_uppers) result->m_uppers.insert(tr(kv.m_key), kv.m_value); + for (auto& kv : m_lower_deps) result->m_lower_deps.insert(tr(kv.m_key), edtr(kv.m_value)); + for (auto& kv : m_upper_deps) result->m_upper_deps.insert(tr(kv.m_key), edtr(kv.m_value)); + for (expr* e : m_bounded_vars) result->m_bounded_vars.push_back(tr(e)); + return result; +} + + static decl_kind swap_decl(decl_kind k) { switch (k) { case OP_LE: return OP_GE; diff --git a/src/tactic/arith/bound_manager.h b/src/tactic/arith/bound_manager.h index 6a4dc2c96..4e1922bf5 100644 --- a/src/tactic/arith/bound_manager.h +++ b/src/tactic/arith/bound_manager.h @@ -47,6 +47,8 @@ public: bound_manager(ast_manager & m); ~bound_manager(); + bound_manager* translate(ast_manager& dst_m); + ast_manager & m() const { return m_util.get_manager(); } void operator()(goal const & g); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 4ef909234..c8d5d1eb3 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -73,8 +73,17 @@ public: } } - virtual solver* translate(ast_manager& m, params_ref const& p) { - return alloc(bounded_int2bv_solver, m, p, m_solver->translate(m, p)); + virtual solver* translate(ast_manager& dst_m, params_ref const& p) { + flush_assertions(); + bounded_int2bv_solver* result = alloc(bounded_int2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); + ast_translation tr(m, dst_m); + for (auto& kv : m_int2bv) result->m_int2bv.insert(tr(kv.m_key), tr(kv.m_value)); + for (auto& kv : m_bv2int) result->m_bv2int.insert(tr(kv.m_key), tr(kv.m_value)); + for (auto& kv : m_bv2offset) result->m_bv2offset.insert(tr(kv.m_key), kv.m_value); + for (func_decl* f : m_bv_fns) result->m_bv_fns.push_back(tr(f)); + for (func_decl* f : m_int_fns) result->m_int_fns.push_back(tr(f)); + for (bound_manager* b : m_bounds) result->m_bounds.push_back(b->translate(dst_m)); + return result; } virtual void assert_expr(expr * t) { diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 39519af4e..353ea4441 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -50,7 +50,7 @@ public: virtual ~enum2bv_solver() {} - virtual solver* translate(ast_manager& m, params_ref const& p) { + virtual solver* translate(ast_manager& m, params_ref const& p) { return alloc(enum2bv_solver, m, p, m_solver->translate(m, p)); } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index d0e5598c7..b151b9bb3 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -49,7 +49,7 @@ public: virtual ~pb2bv_solver() {} virtual solver* translate(ast_manager& m, params_ref const& p) { - + flush_assertions(); return alloc(pb2bv_solver, m, p, m_solver->translate(m, p)); } From a28a8304b7c55e6e07dcbf92f8bd044054fce7e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Jun 2017 13:12:12 -0700 Subject: [PATCH 0176/1283] Dev (#56) * introduce int_solver.h Signed-off-by: Lev Nachmanson * add int_solver class Signed-off-by: Lev Nachmanson * track which var is an integer Signed-off-by: Lev Nachmanson * add queries for integrality of vars Signed-off-by: Lev Nachmanson * resurrect lp_tst in its own director lp Signed-off-by: Lev Nachmanson * add file Signed-off-by: Lev Nachmanson * add_constraint has got a body Signed-off-by: Lev Nachmanson * fix add_constraint and substitute_terms_in_linear_expression Signed-off-by: Lev Nachmanson * after merge with Z3Prover Signed-off-by: Lev Nachmanson * adding stub check_int_feasibility() Signed-off-by: Lev Nachmanson * Dev (#50) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * small fix in lar_solver.cpp Signed-off-by: Lev Nachmanson * adding some content to the new check_int_feasibility() Signed-off-by: Lev Nachmanson * Dev (#51) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * test Signed-off-by: Lev Nachmanson * Dev (#53) * change in a comment Signed-off-by: Lev Nachmanson * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * adding nra Signed-off-by: Nikolaj Bjorner * debugging nra Signed-off-by: Nikolaj Bjorner * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner * n/a Signed-off-by: Nikolaj Bjorner * integrate nlsat Signed-off-by: Nikolaj Bjorner * tidy Signed-off-by: Nikolaj Bjorner * preserve is_int flag Signed-off-by: Lev Nachmanson * remove a debug printout Signed-off-by: Lev Nachmanson * Dev (#54) * change in a comment Signed-off-by: Lev Nachmanson * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * adding nra Signed-off-by: Nikolaj Bjorner * debugging nra Signed-off-by: Nikolaj Bjorner * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner * n/a Signed-off-by: Nikolaj Bjorner * integrate nlsat Signed-off-by: Nikolaj Bjorner * tidy Signed-off-by: Nikolaj Bjorner * use integer test from lra solver, updated it to work on term variables Signed-off-by: Nikolaj Bjorner * fix equality check in assume-eq Signed-off-by: Nikolaj Bjorner * fix model_is_int_feasible Signed-off-by: Lev Nachmanson * untested gcd_test() Signed-off-by: Lev Nachmanson * call fill_explanation_from_fixed_columns() Signed-off-by: Lev Nachmanson * add the call to pivot_fixed_vars_from_basis() to int_solver.cpp::check() Signed-off-by: Lev Nachmanson * port more of theory_arith_int.h Signed-off-by: Lev Nachmanson * use statistics of lar_solver by theory_lra.cpp Signed-off-by: Lev Nachmanson * port more code to int_solver.cpp Signed-off-by: Lev Nachmanson * add an assert Signed-off-by: Lev Nachmanson * more int porting Signed-off-by: Lev Nachmanson * fix a bug in pivot_fixed_vars_from_basis Signed-off-by: Lev Nachmanson * small change Signed-off-by: Lev Nachmanson * implement find_inf_int_base_column() Signed-off-by: Lev Nachmanson * catch unregistered vars in add_var_bound Signed-off-by: Lev Nachmanson * add a file Signed-off-by: Lev Nachmanson * compile for vs2012 Signed-off-by: Lev Nachmanson * fix asserts in add_var_bound Signed-off-by: Lev Nachmanson * fix the lp_solver init when workig on an mps file Signed-off-by: Lev Nachmanson * towards int_solver::check() Signed-off-by: Lev Nachmanson * change in int_solver::check() signature Signed-off-by: Lev Nachmanson * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/test/lp/CMakeLists.txt | 6 + src/CMakeLists.txt | 2 +- src/ast/ast.cpp | 1 - src/ast/rewriter/arith_rewriter.cpp | 45 + src/ast/rewriter/arith_rewriter.h | 1 + .../simplifier/arith_simplifier_plugin.cpp | 45 + src/ast/simplifier/arith_simplifier_plugin.h | 1 + src/math/polynomial/polynomial.h | 20 +- src/nlsat/nlsat_solver.cpp | 1 + src/nlsat/nlsat_solver.h | 8 +- src/nlsat/nlsat_types.h | 8 +- src/sat/sat_types.h | 12 +- src/shell/lp_frontend.cpp | 3 +- src/smt/CMakeLists.txt | 1 + src/smt/params/smt_params_helper.pyg | 2 +- src/smt/params/theory_arith_params.h | 13 +- src/smt/smt_model_generator.cpp | 1 + src/smt/smt_setup.cpp | 5 +- src/smt/theory_lra.cpp | 413 ++-- src/test/CMakeLists.txt | 3 +- src/test/lp/CMakeLists.txt | 6 + src/test/{ => lp}/argument_parser.h | 0 src/test/{ => lp}/lp.cpp | 51 +- src/test/lp/lp_main.cpp | 14 + src/test/{ => lp}/smt_reader.h | 2 +- src/test/{ => lp}/test_file_reader.h | 0 src/util/lp/CMakeLists.txt | 7 +- src/util/lp/column_namer.h | 2 +- src/util/lp/indexed_vector.h | 9 - src/util/lp/init_lar_solver.h | 576 ----- src/util/lp/int_solver.cpp | 606 +++++ src/util/lp/int_solver.h | 100 + src/util/lp/lar_core_solver.h | 31 + src/util/lp/lar_solver.cpp | 2040 +++++++++++++++++ src/util/lp/lar_solver.h | 1611 +++---------- src/util/lp/lar_solver_instances.cpp | 13 + src/util/lp/lp_core_solver_base.h | 5 +- src/util/lp/lp_core_solver_base.hpp | 39 +- src/util/lp/lp_settings.h | 30 +- src/util/lp/lp_settings_instances.cpp | 2 +- src/util/lp/mps_reader.h | 10 +- src/util/lp/nra_solver.cpp | 264 +++ src/util/lp/nra_solver.h | 70 + src/util/lp/numeric_pair.h | 27 + src/util/lp/quick_xplain.cpp | 4 +- src/util/lp/stacked_vector.h | 5 +- src/util/lp/static_matrix_instances.cpp | 2 +- 47 files changed, 3926 insertions(+), 2191 deletions(-) create mode 100644 contrib/cmake/src/test/lp/CMakeLists.txt create mode 100644 src/test/lp/CMakeLists.txt rename src/test/{ => lp}/argument_parser.h (100%) rename src/test/{ => lp}/lp.cpp (98%) create mode 100644 src/test/lp/lp_main.cpp rename src/test/{ => lp}/smt_reader.h (99%) rename src/test/{ => lp}/test_file_reader.h (100%) delete mode 100644 src/util/lp/init_lar_solver.h create mode 100644 src/util/lp/int_solver.cpp create mode 100644 src/util/lp/int_solver.h create mode 100644 src/util/lp/lar_solver.cpp create mode 100644 src/util/lp/lar_solver_instances.cpp create mode 100644 src/util/lp/nra_solver.cpp create mode 100644 src/util/lp/nra_solver.h diff --git a/contrib/cmake/src/test/lp/CMakeLists.txt b/contrib/cmake/src/test/lp/CMakeLists.txt new file mode 100644 index 000000000..6683a1758 --- /dev/null +++ b/contrib/cmake/src/test/lp/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(lp_tst lp_main.cpp lp.cpp $ $ $ $ ) +target_compile_definitions(lp_tst PRIVATE ${Z3_COMPONENT_CXX_DEFINES}) +target_compile_options(lp_tst PRIVATE ${Z3_COMPONENT_CXX_FLAGS}) +target_include_directories(lp_tst PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS}) +target_link_libraries(lp_tst PRIVATE ${Z3_DEPENDENT_LIBS}) +z3_append_linker_flag_list_to_target(lp_tst ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dd440b34d..a98f92ca3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,10 +35,10 @@ endforeach() # raised if you try to declare a component is dependent on another component # that has not yet been declared. add_subdirectory(util) -add_subdirectory(util/lp) add_subdirectory(math/polynomial) add_subdirectory(sat) add_subdirectory(nlsat) +add_subdirectory(util/lp) add_subdirectory(math/hilbert) add_subdirectory(math/simplex) add_subdirectory(math/automata) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 5f2de5170..109657675 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1727,7 +1727,6 @@ ast * ast_manager::register_node_core(ast * n) { n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); - TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); // increment reference counters diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 2b2087e3b..fa3d69602 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -738,9 +738,54 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu result = m_util.mk_idiv0(arg1); return BR_REWRITE1; } + expr_ref quot(m()); + if (divides(arg1, arg2, quot)) { + result = m_util.mk_mul(quot, m_util.mk_idiv(arg1, arg1)); + return BR_REWRITE2; + } return BR_FAILED; } +bool arith_rewriter::divides(expr* d, expr* n, expr_ref& quot) { + if (d == n) { + quot = m_util.mk_numeral(rational(1), m_util.is_int(d)); + return true; + } + if (m_util.is_mul(n)) { + expr_ref_vector muls(m()); + muls.push_back(n); + expr* n1, *n2; + rational r1, r2; + for (unsigned i = 0; i < muls.size(); ++i) { + if (m_util.is_mul(muls[i].get(), n1, n2)) { + muls[i] = n1; + muls.push_back(n2); + --i; + } + } + if (m_util.is_numeral(d, r1) && !r1.is_zero()) { + for (unsigned i = 0; i < muls.size(); ++i) { + if (m_util.is_numeral(muls[i].get(), r2) && (r2 / r1).is_int()) { + muls[i] = m_util.mk_numeral(r2 / r1, m_util.is_int(d)); + quot = m_util.mk_mul(muls.size(), muls.c_ptr()); + return true; + } + } + } + else { + for (unsigned i = 0; i < muls.size(); ++i) { + if (d == muls[i].get()) { + muls[i] = muls.back(); + muls.pop_back(); + quot = m_util.mk_mul(muls.size(), muls.c_ptr()); + return true; + } + } + } + } + return false; +} + br_status arith_rewriter::mk_mod_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 68a60e1f0..606d73ae1 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -90,6 +90,7 @@ class arith_rewriter : public poly_rewriter { bool is_pi_integer_offset(expr * t, expr * & m); expr * mk_sin_value(rational const & k); app * mk_sqrt(rational const & k); + bool divides(expr* d, expr* n, expr_ref& quot); public: arith_rewriter(ast_manager & m, params_ref const & p = params_ref()): diff --git a/src/ast/simplifier/arith_simplifier_plugin.cpp b/src/ast/simplifier/arith_simplifier_plugin.cpp index ef320578a..52f36ab04 100644 --- a/src/ast/simplifier/arith_simplifier_plugin.cpp +++ b/src/ast/simplifier/arith_simplifier_plugin.cpp @@ -267,10 +267,55 @@ void arith_simplifier_plugin::mk_idiv(expr * arg1, expr * arg2, expr_ref & resul bool is_int; if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) result = m_util.mk_numeral(div(v1, v2), is_int); + else if (divides(arg2, arg1, result)) { + result = m_util.mk_mul(result, m_util.mk_idiv(arg2, arg2)); + } else result = m_util.mk_idiv(arg1, arg2); } +bool arith_simplifier_plugin::divides(expr* d, expr* n, expr_ref& quot) { + ast_manager& m = m_manager; + if (d == n) { + quot = m_util.mk_numeral(rational(1), m_util.is_int(d)); + return true; + } + if (m_util.is_mul(n)) { + expr_ref_vector muls(m); + muls.push_back(n); + expr* n1, *n2; + rational r1, r2; + for (unsigned i = 0; i < muls.size(); ++i) { + if (m_util.is_mul(muls[i].get(), n1, n2)) { + muls[i] = n1; + muls.push_back(n2); + --i; + } + } + if (m_util.is_numeral(d, r1) && !r1.is_zero()) { + for (unsigned i = 0; i < muls.size(); ++i) { + if (m_util.is_numeral(muls[i].get(), r2) && (r2 / r1).is_int()) { + muls[i] = m_util.mk_numeral(r2 / r1, m_util.is_int(d)); + quot = m_util.mk_mul(muls.size(), muls.c_ptr()); + return true; + } + } + } + else { + for (unsigned i = 0; i < muls.size(); ++i) { + if (d == muls[i].get()) { + muls[i] = muls.back(); + muls.pop_back(); + quot = m_util.mk_mul(muls.size(), muls.c_ptr()); + return true; + } + } + } + } + return false; +} + + void arith_simplifier_plugin::prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result) { SASSERT(m_util.is_int(e)); SASSERT(k.is_int() && k.is_pos()); diff --git a/src/ast/simplifier/arith_simplifier_plugin.h b/src/ast/simplifier/arith_simplifier_plugin.h index e6181e211..045ee0e71 100644 --- a/src/ast/simplifier/arith_simplifier_plugin.h +++ b/src/ast/simplifier/arith_simplifier_plugin.h @@ -48,6 +48,7 @@ protected: void div_monomial(expr_ref_vector& monomials, numeral const& g); void get_monomial_gcd(expr_ref_vector& monomials, numeral& g); + bool divides(expr* d, expr* n, expr_ref& quot); public: arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p); diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index cb1880495..b2b61f079 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -19,16 +19,16 @@ Notes: #ifndef POLYNOMIAL_H_ #define POLYNOMIAL_H_ -#include"mpz.h" -#include"rational.h" -#include"obj_ref.h" -#include"ref_vector.h" -#include"z3_exception.h" -#include"scoped_numeral.h" -#include"scoped_numeral_vector.h" -#include"params.h" -#include"mpbqi.h" -#include"rlimit.h" +#include"util/mpz.h" +#include"util/rational.h" +#include"util/obj_ref.h" +#include"util/ref_vector.h" +#include"util/z3_exception.h" +#include"util/scoped_numeral.h" +#include"util/scoped_numeral_vector.h" +#include"util/params.h" +#include"util/mpbqi.h" +#include"util/rlimit.h" class small_object_allocator; diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 7582c8389..7ffb1b0a5 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -623,6 +623,7 @@ namespace nlsat { unsigned sz = cs.size(); for (unsigned i = 0; i < sz; i++) del_clause(cs[i]); + cs.reset(); } void del_clauses() { diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index 3668629cd..08902e709 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -21,10 +21,10 @@ Revision History: #ifndef NLSAT_SOLVER_H_ #define NLSAT_SOLVER_H_ -#include"nlsat_types.h" -#include"params.h" -#include"statistics.h" -#include"rlimit.h" +#include"nlsat/nlsat_types.h" +#include"util/params.h" +#include"util/statistics.h" +#include"util/rlimit.h" namespace nlsat { diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 11e063a17..70da98e32 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -19,10 +19,10 @@ Revision History: #ifndef NLSAT_TYPES_H_ #define NLSAT_TYPES_H_ -#include"polynomial.h" -#include"buffer.h" -#include"sat_types.h" -#include"z3_exception.h" +#include"math/polynomial/polynomial.h" +#include"util/buffer.h" +#include"sat/sat_types.h" +#include"util/z3_exception.h" namespace algebraic_numbers { class anum; diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 28d8d761a..97c8e0e91 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -19,12 +19,12 @@ Revision History: #ifndef SAT_TYPES_H_ #define SAT_TYPES_H_ -#include"debug.h" -#include"approx_set.h" -#include"lbool.h" -#include"z3_exception.h" -#include"common_msgs.h" -#include"vector.h" +#include"util/debug.h" +#include"util/approx_set.h" +#include"util/lbool.h" +#include"util/z3_exception.h" +#include"util/common_msgs.h" +#include"util/vector.h" #include namespace sat { diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index 8acbd28ff..213f94cb2 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -80,8 +80,7 @@ void run_solver(lp_params & params, char const * mps_file_name) { solver->settings().set_message_ostream(&std::cout); solver->settings().report_frequency = params.rep_freq(); solver->settings().print_statistics = params.print_stats(); - solver->settings().simplex_strategy() = lean:: simplex_strategy_enum::lu; - + solver->settings().simplex_strategy() = lean::simplex_strategy_enum::lu; solver->find_maximal_solution(); *(solver->settings().get_message_ostream()) << "status is " << lp_status_to_string(solver->get_status()) << std::endl; diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 41890dd05..3db66eb3e 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -70,6 +70,7 @@ z3_add_component(smt euclid fpa grobner + nlsat lp macros normal_forms diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index a501f474a..6d67bfd19 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -36,7 +36,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'), + ('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/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 943bd711e..e71c0adad 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -23,12 +23,13 @@ Revision History: #include"params.h" enum arith_solver_id { - AS_NO_ARITH, - AS_DIFF_LOGIC, - AS_ARITH, - AS_DENSE_DIFF_LOGIC, - AS_UTVPI, - AS_OPTINF + AS_NO_ARITH, // 0 + AS_DIFF_LOGIC, // 1 + AS_ARITH, // 2 + AS_DENSE_DIFF_LOGIC, // 3 + AS_UTVPI, // 4 + AS_OPTINF, // 5 + AS_LRA // 6 }; enum bound_prop_mode { diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index b9c1ac453..c319a8d7d 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -388,6 +388,7 @@ namespace smt { enode * n = *it3; if (is_uninterp_const(n->get_owner()) && m_context->is_relevant(n)) { func_decl * d = n->get_owner()->get_decl(); + TRACE("mg_top_sort", tout << d->get_name() << " " << (m_hidden_ufs.contains(d)?"hidden":"visible") << "\n";); if (m_hidden_ufs.contains(d)) continue; expr * val = get_value(n); m_model->register_decl(d, val); diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 4dd1e2510..9646bce2b 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -724,8 +724,6 @@ namespace smt { } void setup::setup_r_arith() { - // to disable theory lra - // m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params)); m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params)); } @@ -789,6 +787,9 @@ namespace smt { case AS_OPTINF: m_context.register_plugin(alloc(smt::theory_inf_arith, m_manager, m_params)); break; + case AS_LRA: + setup_r_arith(); + break; default: if (m_params.m_arith_int_only && int_only) m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 76e721faa..c35dbb94e 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -35,7 +35,10 @@ Revision History: #include "smt/smt_model_generator.h" #include "smt/arith_eq_adapter.h" #include "util/nat_set.h" +#include "util/lp/nra_solver.h" #include "tactic/filter_model_converter.h" +#include "math/polynomial/algebraic_numbers.h" +#include "math/polynomial/polynomial.h" namespace lp { enum bound_kind { lower_t, upper_t }; @@ -87,16 +90,12 @@ namespace lp { unsigned m_bounds_propagations; unsigned m_num_iterations; unsigned m_num_iterations_with_no_progress; - unsigned m_num_factorizations; unsigned m_need_to_solve_inf; unsigned m_fixed_eqs; unsigned m_conflicts; unsigned m_bound_propagations1; unsigned m_bound_propagations2; unsigned m_assert_diseq; - unsigned m_make_feasible; - unsigned m_max_cols; - unsigned m_max_rows; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); @@ -118,9 +117,6 @@ namespace smt { unsigned m_bounds_lim; unsigned m_asserted_qhead; unsigned m_asserted_atoms_lim; - unsigned m_delayed_terms_lim; - unsigned m_delayed_equalities_lim; - unsigned m_delayed_defs_lim; unsigned m_underspecified_lim; unsigned m_var_trail_lim; expr* m_not_handled; @@ -144,10 +140,10 @@ namespace smt { ast_manager& m; theory_arith_params& m_arith_params; arith_util a; - arith_eq_adapter m_arith_eq_adapter; + vector m_columns; + - vector m_columns; // temporary values kept during internalization struct internalize_state { expr_ref_vector m_terms; @@ -198,14 +194,6 @@ namespace smt { }; typedef vector> var_coeffs; - struct delayed_def { - vector m_coeffs; - svector m_vars; - rational m_coeff; - theory_var m_var; - delayed_def(svector const& vars, vector const& coeffs, rational const& r, theory_var v): - m_coeffs(coeffs), m_vars(vars), m_coeff(r), m_var(v) {} - }; svector m_theory_var2var_index; // translate from theory variables to lar vars svector m_var_index2theory_var; // reverse map from lp_solver variables to theory variables @@ -224,11 +212,7 @@ namespace smt { svector m_equalities; // asserted rows corresponding to equalities. svector m_definitions; // asserted rows corresponding to definitions - bool m_delay_constraints; // configuration svector m_asserted_atoms; - app_ref_vector m_delayed_terms; - svector> m_delayed_equalities; - vector m_delayed_defs; expr* m_not_handled; ptr_vector m_underspecified; unsigned_vector m_var_trail; @@ -248,16 +232,36 @@ namespace smt { unsigned m_num_conflicts; + // non-linear arithmetic + scoped_ptr m_nra; + bool m_use_nra_model; + scoped_ptr m_a1, m_a2; + + // integer arithmetic + scoped_ptr m_lia; + struct var_value_eq { imp & m_th; var_value_eq(imp & th):m_th(th) {} - bool operator()(theory_var v1, theory_var v2) const { return m_th.get_ivalue(v1) == m_th.get_ivalue(v2) && m_th.is_int(v1) == m_th.is_int(v2); } + bool operator()(theory_var v1, theory_var v2) const { + if (m_th.is_int(v1) != m_th.is_int(v2)) { + return false; + } + return m_th.is_eq(v1, v2); + } }; struct var_value_hash { imp & m_th; var_value_hash(imp & th):m_th(th) {} - unsigned operator()(theory_var v) const { return (unsigned)std::hash()(m_th.get_ivalue(v)); } + unsigned operator()(theory_var v) const { + if (m_th.m_use_nra_model) { + return m_th.is_int(v); + } + else { + return (unsigned)std::hash()(m_th.get_ivalue(v)); + } + } }; int_hashtable m_model_eqs; @@ -289,14 +293,25 @@ namespace smt { m_solver->settings().bound_propagation() = BP_NONE != propagation_mode(); m_solver->set_propagate_bounds_on_pivoted_rows_mode(lp.bprop_on_pivoted_rows()); //m_solver->settings().set_ostream(0); + m_lia = alloc(lean::int_solver, m_solver.get()); } + void ensure_nra() { + if (!m_nra) { + m_nra = alloc(nra::solver, *m_solver.get(), m.limit(), ctx().get_params()); + for (unsigned i = 0; i < m_scopes.size(); ++i) { + m_nra->push(); + } + } + } + + void found_not_handled(expr* n) { m_not_handled = n; if (is_app(n) && is_underspecified(to_app(n))) { + TRACE("arith", tout << "Unhandled: " << mk_pp(n, m) << "\n";); m_underspecified.push_back(to_app(n)); } - TRACE("arith", tout << "Unhandled: " << mk_pp(n, m) << "\n";); } bool is_numeral(expr* term, rational& r) { @@ -366,6 +381,14 @@ namespace smt { terms[index] = n1; st.terms_to_internalize().push_back(n2); } + else if (a.is_mul(n)) { + theory_var v; + internalize_mul(to_app(n), v, r); + coeffs[index] *= r; + coeffs[vars.size()] = coeffs[index]; + vars.push_back(v); + ++index; + } else if (a.is_numeral(n, r)) { coeff += coeffs[index]*r; ++index; @@ -415,6 +438,44 @@ namespace smt { } } + void internalize_mul(app* t, theory_var& v, rational& r) { + SASSERT(a.is_mul(t)); + bool _has_var = has_var(t); + if (!_has_var) { + internalize_args(t); + mk_enode(t); + } + r = rational::one(); + rational r1; + v = mk_var(t); + svector vars; + ptr_vector todo; + todo.push_back(t); + while (!todo.empty()) { + expr* n = todo.back(); + todo.pop_back(); + expr* n1, *n2; + if (a.is_mul(n, n1, n2)) { + todo.push_back(n1); + todo.push_back(n2); + } + else if (a.is_numeral(n, r1)) { + r *= r1; + } + else { + if (!ctx().e_internalized(n)) { + ctx().internalize(n, false); + } + vars.push_back(get_var_index(mk_var(n))); + } + } + TRACE("arith", tout << mk_pp(t, m) << "\n";); + if (!_has_var) { + ensure_nra(); + m_nra->add_monomial(get_var_index(v), vars.size(), vars.c_ptr()); + } + } + enode * mk_enode(app * n) { if (ctx().e_internalized(n)) { return get_enode(n); @@ -459,6 +520,14 @@ namespace smt { return m_arith_params.m_arith_reflect || is_underspecified(n); } + bool has_var(expr* n) { + if (!ctx().e_internalized(n)) { + return false; + } + enode* e = get_enode(n); + return th.is_attached_to_var(e); + } + theory_var mk_var(expr* n, bool internalize = true) { if (!ctx().e_internalized(n)) { ctx().internalize(n, false); @@ -487,7 +556,7 @@ namespace smt { result = m_theory_var2var_index[v]; } if (result == UINT_MAX) { - result = m_solver->add_var(v); // TBD: is_int(v); + result = m_solver->add_var(v, is_int(v)); m_theory_var2var_index.setx(v, result, UINT_MAX); m_var_index2theory_var.setx(result, v, UINT_MAX); m_var_trail.push_back(v); @@ -549,14 +618,6 @@ namespace smt { m_definitions.setx(index, v, null_theory_var); ++m_stats.m_add_rows; } - - void internalize_eq(delayed_def const& d) { - scoped_internalize_state st(*this); - st.vars().append(d.m_vars); - st.coeffs().append(d.m_coeffs); - init_left_side(st); - add_def_constraint(m_solver->add_constraint(m_left_side, lean::EQ, -d.m_coeff), d.m_var); - } void internalize_eq(theory_var v1, theory_var v2) { enode* n1 = get_enode(v1); @@ -650,15 +711,14 @@ namespace smt { a(m), m_arith_eq_adapter(th, ap, a), m_internalize_head(0), - m_delay_constraints(false), - m_delayed_terms(m), m_not_handled(0), m_asserted_qhead(0), m_assume_eq_head(0), m_num_conflicts(0), m_model_eqs(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)), m_solver(0), - m_resource_limit(*this) { + m_resource_limit(*this), + m_use_nra_model(false) { } ~imp() { @@ -671,12 +731,8 @@ namespace smt { } bool internalize_atom(app * atom, bool gate_ctx) { - if (m_delay_constraints) { - return internalize_atom_lazy(atom, gate_ctx); - } - else { - return internalize_atom_strict(atom, gate_ctx); - } + return internalize_atom_strict(atom, gate_ctx); + } bool internalize_atom_strict(app * atom, bool gate_ctx) { @@ -710,54 +766,11 @@ namespace smt { //add_use_lists(b); return true; } - - bool internalize_atom_lazy(app * atom, bool gate_ctx) { - SASSERT(!ctx().b_internalized(atom)); - bool_var bv = ctx().mk_bool_var(atom); - ctx().set_var_theory(bv, get_id()); - expr* n1, *n2; - rational r; - lp::bound_kind k; - theory_var v = null_theory_var; - scoped_internalize_state st(*this); - if (a.is_le(atom, n1, n2) && is_numeral(n2, r) && is_app(n1)) { - v = internalize_def(to_app(n1), st); - k = lp::upper_t; - } - else if (a.is_ge(atom, n1, n2) && is_numeral(n2, r) && is_app(n1)) { - v = internalize_def(to_app(n1), st); - k = lp::lower_t; - } - else { - TRACE("arith", tout << "Could not internalize " << mk_pp(atom, m) << "\n";); - found_not_handled(atom); - return true; - } - lp::bound* b = alloc(lp::bound, bv, v, r, k); - m_bounds[v].push_back(b); - updt_unassigned_bounds(v, +1); - m_bounds_trail.push_back(v); - m_bool_var2bound.insert(bv, b); - TRACE("arith", tout << "Internalized " << mk_pp(atom, m) << "\n";); - if (!is_unit_var(st) && m_bounds[v].size() == 1) { - m_delayed_defs.push_back(delayed_def(st.vars(), st.coeffs(), st.coeff(), v)); - } - return true; - } bool internalize_term(app * term) { if (ctx().e_internalized(term) && th.is_attached_to_var(ctx().get_enode(term))) { // skip } - else if (m_delay_constraints) { - scoped_internalize_state st(*this); - linearize_term(term, st); // ensure that a theory_var was created. - SASSERT(ctx().e_internalized(term)); - if(!th.is_attached_to_var(ctx().get_enode(term))) { - mk_var(term); - } - m_delayed_terms.push_back(term); - } else { internalize_def(term); } @@ -783,13 +796,8 @@ namespace smt { } void new_eq_eh(theory_var v1, theory_var v2) { - if (m_delay_constraints) { - m_delayed_equalities.push_back(std::make_pair(v1, v2)); - } - else { - // or internalize_eq(v1, v2); - m_arith_eq_adapter.new_eq_eh(v1, v2); - } + // or internalize_eq(v1, v2); + m_arith_eq_adapter.new_eq_eh(v1, v2); } bool use_diseqs() const { @@ -808,13 +816,11 @@ namespace smt { s.m_bounds_lim = m_bounds_trail.size(); s.m_asserted_qhead = m_asserted_qhead; s.m_asserted_atoms_lim = m_asserted_atoms.size(); - s.m_delayed_terms_lim = m_delayed_terms.size(); - s.m_delayed_equalities_lim = m_delayed_equalities.size(); - s.m_delayed_defs_lim = m_delayed_defs.size(); s.m_not_handled = m_not_handled; s.m_underspecified_lim = m_underspecified.size(); s.m_var_trail_lim = m_var_trail.size(); - if (!m_delay_constraints) m_solver->push(); + m_solver->push(); + if (m_nra) m_nra->push(); } void pop_scope_eh(unsigned num_scopes) { @@ -835,18 +841,16 @@ namespace smt { m_theory_var2var_index[m_var_trail[i]] = UINT_MAX; } m_asserted_atoms.shrink(m_scopes[old_size].m_asserted_atoms_lim); - m_delayed_terms.shrink(m_scopes[old_size].m_delayed_terms_lim); - m_delayed_defs.shrink(m_scopes[old_size].m_delayed_defs_lim); - m_delayed_equalities.shrink(m_scopes[old_size].m_delayed_equalities_lim); m_asserted_qhead = m_scopes[old_size].m_asserted_qhead; m_underspecified.shrink(m_scopes[old_size].m_underspecified_lim); m_var_trail.shrink(m_scopes[old_size].m_var_trail_lim); m_not_handled = m_scopes[old_size].m_not_handled; m_scopes.resize(old_size); - if (!m_delay_constraints) m_solver->pop(num_scopes); + m_solver->pop(num_scopes); // VERIFY(l_false != make_feasible()); m_new_bounds.reset(); m_to_check.reset(); + if (m_nra) m_nra->pop(num_scopes); TRACE("arith", tout << "num scopes: " << num_scopes << " new scope level: " << m_scopes.size() << "\n";); } @@ -1080,7 +1084,9 @@ namespace smt { } tout << "\n"; ); - m_solver->random_update(vars.size(), vars.c_ptr()); + if (!m_use_nra_model) { + m_solver->random_update(vars.size(), vars.c_ptr()); + } m_model_eqs.reset(); TRACE("arith", display(tout);); @@ -1130,54 +1136,69 @@ namespace smt { enode* n2 = get_enode(v2); m_assume_eq_head++; CTRACE("arith", - get_ivalue(v1) == get_ivalue(v2) && n1->get_root() != n2->get_root(), + is_eq(v1, v2) && n1->get_root() != n2->get_root(), tout << "assuming eq: v" << v1 << " = v" << v2 << "\n";); - if (get_ivalue(v1) == get_ivalue(v2) && n1->get_root() != n2->get_root() && th.assume_eq(n1, n2)) { + if (is_eq(v1, v2) && n1->get_root() != n2->get_root() && th.assume_eq(n1, n2)) { return true; } } return false; } + bool is_eq(theory_var v1, theory_var v2) { + if (m_use_nra_model) { + return m_nra->am().eq(nl_value(v1, *m_a1), nl_value(v2, *m_a2)); + } + else { + return get_ivalue(v1) == get_ivalue(v2); + } + } + bool has_delayed_constraints() const { - return !(m_asserted_atoms.empty() && m_delayed_terms.empty() && m_delayed_equalities.empty()); + return !m_asserted_atoms.empty(); } final_check_status final_check_eh() { + m_use_nra_model = false; lbool is_sat = l_true; - if (m_delay_constraints) { - init_solver(); - for (unsigned i = 0; i < m_asserted_atoms.size(); ++i) { - bool_var bv = m_asserted_atoms[i].m_bv; - assert_bound(bv, m_asserted_atoms[i].m_is_true, *m_bool_var2bound.find(bv)); - } - for (unsigned i = 0; i < m_delayed_terms.size(); ++i) { - internalize_def(m_delayed_terms[i].get()); - } - for (unsigned i = 0; i < m_delayed_defs.size(); ++i) { - internalize_eq(m_delayed_defs[i]); - } - for (unsigned i = 0; i < m_delayed_equalities.size(); ++i) { - std::pair const& eq = m_delayed_equalities[i]; - internalize_eq(eq.first, eq.second); - } - is_sat = make_feasible(); - } - else if (m_solver->get_status() != lean::lp_status::OPTIMAL) { + if (m_solver->get_status() != lean::lp_status::OPTIMAL) { is_sat = make_feasible(); } + final_check_status st = FC_DONE; switch (is_sat) { case l_true: + if (delayed_assume_eqs()) { return FC_CONTINUE; } if (assume_eqs()) { return FC_CONTINUE; } - if (m_not_handled != 0) { - return FC_GIVEUP; + + switch (check_lia()) { + case l_true: + break; + case l_false: + return FC_CONTINUE; + case l_undef: + st = FC_GIVEUP; + break; } - return FC_DONE; + + switch (check_nra()) { + case l_true: + break; + case l_false: + return FC_CONTINUE; + case l_undef: + st = FC_GIVEUP; + break; + } + if (m_not_handled != 0) { + st = FC_GIVEUP; + } + + return st; case l_false: set_conflict(); return FC_CONTINUE; @@ -1190,6 +1211,70 @@ namespace smt { return FC_GIVEUP; } + // create a bound atom representing term >= k + lp::bound* mk_bound(lean::lar_term const& term, rational const& k) { + NOT_IMPLEMENTED_YET(); + lp::bound_kind bkind = lp::bound_kind::lower_t; + bool_var bv = null_bool_var; + theory_var v = null_theory_var; + lp::bound* result = alloc(lp::bound, bv, v, k, bkind); + return result; + } + + lbool check_lia() { + std::cout << "called check_lia()\n"; + lean::lar_term term; + lean::mpq k; + lean::explanation ex; // TBD, this should be streamlined accross different explanations + switch(m_lia->check(term, k, ex)) { + case lean::lia_move::ok: + return l_true; + case lean::lia_move::branch: + // branch on term <= k + NOT_IMPLEMENTED_YET(); + return l_false; + case lean::lia_move::cut: + // m_explanation implies term <= k + m_explanation = ex.m_explanation; + NOT_IMPLEMENTED_YET(); + return l_false; + case lean::lia_move::conflict: + // ex contains unsat core + m_explanation = ex.m_explanation; + set_conflict1(); + return l_false; + case lean::lia_move::give_up: + return l_undef; + default: + UNREACHABLE(); + } + return l_undef; + } + + lbool check_nra() { + m_use_nra_model = false; + if (m.canceled()) return l_undef; + if (!m_nra) return l_true; + if (!m_nra->need_check()) return l_true; + m_a1 = 0; m_a2 = 0; + lbool r = m_nra->check(m_explanation); + m_a1 = alloc(scoped_anum, m_nra->am()); + m_a2 = alloc(scoped_anum, m_nra->am()); + switch (r) { + case l_false: + set_conflict1(); + break; + case l_true: + m_use_nra_model = true; + if (assume_eqs()) { + return l_false; + } + break; + default: + break; + } + return r; + } /** \brief We must redefine this method, because theory of arithmetic contains @@ -1259,14 +1344,13 @@ namespace smt { #else propagate_bound(bv, is_true, b); #endif - if (!m_delay_constraints) { - lp::bound& b = *m_bool_var2bound.find(bv); - assert_bound(bv, is_true, b); - } + lp::bound& b = *m_bool_var2bound.find(bv); + assert_bound(bv, is_true, b); + ++m_asserted_qhead; } - if (m_delay_constraints || ctx().inconsistent()) { + if (ctx().inconsistent()) { m_to_check.reset(); return; } @@ -2133,18 +2217,8 @@ namespace smt { } lbool make_feasible() { - reset_variable_values(); - ++m_stats.m_make_feasible; - if (m_solver->A_r().column_count() > m_stats.m_max_cols) - m_stats.m_max_cols = m_solver->A_r().column_count(); - if (m_solver->A_r().row_count() > m_stats.m_max_rows) - m_stats.m_max_rows = m_solver->A_r().row_count(); + auto status = m_solver->find_feasible_solution(); TRACE("arith_verbose", display(tout);); - lean::lp_status status = m_solver->find_feasible_solution(); - m_stats.m_num_iterations = m_solver->settings().st().m_total_iterations; - m_stats.m_num_factorizations = m_solver->settings().st().m_num_factorizations; - m_stats.m_need_to_solve_inf = m_solver->settings().st().m_need_to_solve_inf; - switch (status) { case lean::lp_status::INFEASIBLE: return l_false; @@ -2197,11 +2271,15 @@ namespace smt { } void set_conflict() { + m_explanation.clear(); + m_solver->get_infeasibility_explanation(m_explanation); + set_conflict1(); + } + + void set_conflict1() { m_eqs.reset(); m_core.reset(); m_params.reset(); - m_explanation.clear(); - m_solver->get_infeasibility_explanation(m_explanation); // m_solver->shrink_explanation_to_minimum(m_explanation); // todo, enable when perf is fixed /* static unsigned cn = 0; @@ -2250,9 +2328,43 @@ namespace smt { TRACE("arith", display(tout);); } + nlsat::anum const& nl_value(theory_var v, scoped_anum& r) { + SASSERT(m_nra); + SASSERT(m_use_nra_model); + lean::var_index vi = m_theory_var2var_index[v]; + if (m_solver->is_term(vi)) { + lean::lar_term const& term = m_solver->get_term(vi); + scoped_anum r1(m_nra->am()); + m_nra->am().set(r, term.m_v.to_mpq()); + + for (auto const coeff : term.m_coeffs) { + lean::var_index wi = coeff.first; + m_nra->am().set(r1, coeff.second.to_mpq()); + m_nra->am().mul(m_nra->value(wi), r1, r1); + m_nra->am().add(r1, r, r); + } + return r; + } + else { + return m_nra->value(vi); + } + } + model_value_proc * mk_value(enode * n, model_generator & mg) { theory_var v = n->get_th_var(get_id()); - return alloc(expr_wrapper_proc, m_factory->mk_value(get_value(v), m.get_sort(n->get_owner()))); + expr* o = n->get_owner(); + if (m_use_nra_model) { + anum const& an = nl_value(v, *m_a1); + if (a.is_int(o) && !m_nra->am().is_int(an)) { + return alloc(expr_wrapper_proc, a.mk_numeral(rational::zero(), a.is_int(o))); + } + return alloc(expr_wrapper_proc, a.mk_numeral(nl_value(v, *m_a1), a.is_int(o))); + } + else { + rational r = get_value(v); + 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))); + } } bool get_value(enode* n, expr_ref& r) { @@ -2278,6 +2390,7 @@ namespace smt { 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); } + if (m_arith_params.m_arith_mode == AS_LRA) return true; context nctx(m, ctx().get_fparams(), ctx().get_params()); add_background(nctx); bool result = l_true != nctx.check(); @@ -2290,6 +2403,7 @@ namespace smt { if (dump_lemmas()) { ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); } + if (m_arith_params.m_arith_mode == AS_LRA) return true; context nctx(m, ctx().get_fparams(), ctx().get_params()); m_core.push_back(~lit); add_background(nctx); @@ -2301,6 +2415,7 @@ namespace smt { } bool validate_eq(enode* x, enode* y) { + if (m_arith_params.m_arith_mode == AS_LRA) return true; context nctx(m, ctx().get_fparams(), ctx().get_params()); add_background(nctx); nctx.assert_expr(m.mk_not(m.mk_eq(x->get_owner(), y->get_owner()))); @@ -2496,7 +2611,7 @@ namespace smt { st.update("arith-rows", m_stats.m_add_rows); st.update("arith-propagations", m_stats.m_bounds_propagations); st.update("arith-iterations", m_stats.m_num_iterations); - st.update("arith-factorizations", m_stats.m_num_factorizations); + st.update("arith-factorizations", m_solver->settings().st().m_num_factorizations); st.update("arith-pivots", m_stats.m_need_to_solve_inf); st.update("arith-plateau-iterations", m_stats.m_num_iterations_with_no_progress); st.update("arith-fixed-eqs", m_stats.m_fixed_eqs); @@ -2504,9 +2619,9 @@ namespace smt { st.update("arith-bound-propagations-lp", m_stats.m_bound_propagations1); st.update("arith-bound-propagations-cheap", m_stats.m_bound_propagations2); st.update("arith-diseq", m_stats.m_assert_diseq); - st.update("arith-make-feasible", m_stats.m_make_feasible); - st.update("arith-max-columns", m_stats.m_max_cols); - st.update("arith-max-rows", m_stats.m_max_rows); + st.update("arith-make-feasible", m_solver->settings().st().m_make_feasible); + st.update("arith-max-columns", m_solver->settings().st().m_max_cols); + st.update("arith-max-rows", m_solver->settings().st().m_max_rows); } }; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b395c09e6..f92525069 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(fuzzing) +add_subdirectory(lp) ################################################################################ # z3-test executable ################################################################################ @@ -117,7 +118,7 @@ add_executable(test-z3 upolynomial.cpp var_subst.cpp vector.cpp - lp.cpp + lp/lp.cpp ${z3_test_extra_object_files} ) z3_add_install_tactic_rule(${z3_test_deps}) diff --git a/src/test/lp/CMakeLists.txt b/src/test/lp/CMakeLists.txt new file mode 100644 index 000000000..6683a1758 --- /dev/null +++ b/src/test/lp/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(lp_tst lp_main.cpp lp.cpp $ $ $ $ ) +target_compile_definitions(lp_tst PRIVATE ${Z3_COMPONENT_CXX_DEFINES}) +target_compile_options(lp_tst PRIVATE ${Z3_COMPONENT_CXX_FLAGS}) +target_include_directories(lp_tst PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS}) +target_link_libraries(lp_tst PRIVATE ${Z3_DEPENDENT_LIBS}) +z3_append_linker_flag_list_to_target(lp_tst ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) diff --git a/src/test/argument_parser.h b/src/test/lp/argument_parser.h similarity index 100% rename from src/test/argument_parser.h rename to src/test/lp/argument_parser.h diff --git a/src/test/lp.cpp b/src/test/lp/lp.cpp similarity index 98% rename from src/test/lp.cpp rename to src/test/lp/lp.cpp index 9e05112f5..71032d013 100644 --- a/src/test/lp.cpp +++ b/src/test/lp/lp.cpp @@ -2695,8 +2695,8 @@ void test_term() { lar_solver solver; unsigned _x = 0; unsigned _y = 1; - var_index x = solver.add_var(_x); - var_index y = solver.add_var(_y); + var_index x = solver.add_var(_x, false); + var_index y = solver.add_var(_y, false); vector> term_ls; term_ls.push_back(std::pair((int)1, x)); @@ -2709,9 +2709,16 @@ void test_term() { ls.push_back(std::pair((int)1, z)); solver.add_constraint(ls, lconstraint_kind::EQ, mpq(0)); + ls.clear(); + ls.push_back(std::pair((int)1, x)); + solver.add_constraint(ls, lconstraint_kind::LT, mpq(0)); + ls.push_back(std::pair((int)2, y)); + solver.add_constraint(ls, lconstraint_kind::GT, mpq(0)); auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; std::unordered_map model; + if (status != OPTIMAL) + return; solver.get_model(model); for (auto & t : model) { @@ -2723,8 +2730,8 @@ void test_term() { void test_evidence_for_total_inf_simple(argument_parser & args_parser) { lar_solver solver; - var_index x = solver.add_var(0); - var_index y = solver.add_var(1); + var_index x = solver.add_var(0, false); + var_index y = solver.add_var(1, false); solver.add_var_bound(x, LE, -mpq(1)); solver.add_var_bound(y, GE, mpq(0)); vector> ls; @@ -2758,9 +2765,9 @@ If b becomes basic variable, then it is likely the old solver ends up with a row return true; }; lar_solver ls; - unsigned a = ls.add_var(0); - unsigned b = ls.add_var(1); - unsigned c = ls.add_var(2); + unsigned a = ls.add_var(0, false); + unsigned b = ls.add_var(1, false); + unsigned c = ls.add_var(2, false); vector> coeffs; coeffs.push_back(std::pair(1, a)); coeffs.push_back(std::pair(-1, c)); @@ -2823,8 +2830,8 @@ If x9 becomes basic variable, then it is likely the old solver ends up with a ro } void test_bound_propagation_one_row() { lar_solver ls; - unsigned x0 = ls.add_var(0); - unsigned x1 = ls.add_var(1); + unsigned x0 = ls.add_var(0, false); + unsigned x1 = ls.add_var(1, false); vector> c; c.push_back(std::pair(1, x0)); c.push_back(std::pair(-1, x1)); @@ -2837,8 +2844,8 @@ void test_bound_propagation_one_row() { } void test_bound_propagation_one_row_with_bounded_vars() { lar_solver ls; - unsigned x0 = ls.add_var(0); - unsigned x1 = ls.add_var(1); + unsigned x0 = ls.add_var(0, false); + unsigned x1 = ls.add_var(1, false); vector> c; c.push_back(std::pair(1, x0)); c.push_back(std::pair(-1, x1)); @@ -2853,8 +2860,8 @@ void test_bound_propagation_one_row_with_bounded_vars() { } void test_bound_propagation_one_row_mixed() { lar_solver ls; - unsigned x0 = ls.add_var(0); - unsigned x1 = ls.add_var(1); + unsigned x0 = ls.add_var(0, false); + unsigned x1 = ls.add_var(1, false); vector> c; c.push_back(std::pair(1, x0)); c.push_back(std::pair(-1, x1)); @@ -2868,9 +2875,9 @@ void test_bound_propagation_one_row_mixed() { void test_bound_propagation_two_rows() { lar_solver ls; - unsigned x = ls.add_var(0); - unsigned y = ls.add_var(1); - unsigned z = ls.add_var(2); + unsigned x = ls.add_var(0, false); + unsigned y = ls.add_var(1, false); + unsigned z = ls.add_var(2, false); vector> c; c.push_back(std::pair(1, x)); c.push_back(std::pair(2, y)); @@ -2892,9 +2899,9 @@ void test_bound_propagation_two_rows() { void test_total_case_u() { std::cout << "test_total_case_u\n"; lar_solver ls; - unsigned x = ls.add_var(0); - unsigned y = ls.add_var(1); - unsigned z = ls.add_var(2); + unsigned x = ls.add_var(0, false); + unsigned y = ls.add_var(1, false); + unsigned z = ls.add_var(2, false); vector> c; c.push_back(std::pair(1, x)); c.push_back(std::pair(2, y)); @@ -2918,9 +2925,9 @@ bool contains_j_kind(unsigned j, lconstraint_kind kind, const mpq & rs, const ve void test_total_case_l(){ std::cout << "test_total_case_l\n"; lar_solver ls; - unsigned x = ls.add_var(0); - unsigned y = ls.add_var(1); - unsigned z = ls.add_var(2); + unsigned x = ls.add_var(0, false); + unsigned y = ls.add_var(1, false); + unsigned z = ls.add_var(2, false); vector> c; c.push_back(std::pair(1, x)); c.push_back(std::pair(2, y)); diff --git a/src/test/lp/lp_main.cpp b/src/test/lp/lp_main.cpp new file mode 100644 index 000000000..a301f38c6 --- /dev/null +++ b/src/test/lp/lp_main.cpp @@ -0,0 +1,14 @@ +void gparams_register_modules(){} +void mem_initialize() {} +void mem_finalize() {} +#include "util/rational.h" +namespace lean { +void test_lp_local(int argc, char**argv); +} +int main(int argn, char**argv){ + rational::initialize(); + lean::test_lp_local(argn, argv); + rational::finalize(); + return 0; +} + diff --git a/src/test/smt_reader.h b/src/test/lp/smt_reader.h similarity index 99% rename from src/test/smt_reader.h rename to src/test/lp/smt_reader.h index 38e3f4157..dd38c6bcd 100644 --- a/src/test/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -376,7 +376,7 @@ namespace lean { void add_constraint_to_solver(lar_solver * solver, formula_constraint & fc) { vector> ls; for (auto & it : fc.m_coeffs) { - ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second)))); + ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second), false))); } solver->add_constraint(ls, fc.m_kind, fc.m_right_side); } diff --git a/src/test/test_file_reader.h b/src/test/lp/test_file_reader.h similarity index 100% rename from src/test/test_file_reader.h rename to src/test/lp/test_file_reader.h diff --git a/src/util/lp/CMakeLists.txt b/src/util/lp/CMakeLists.txt index 57ebecc8d..72c2482bb 100644 --- a/src/util/lp/CMakeLists.txt +++ b/src/util/lp/CMakeLists.txt @@ -8,6 +8,8 @@ z3_add_component(lp dense_matrix_instances.cpp eta_matrix_instances.cpp indexed_vector_instances.cpp + int_solver.cpp + lar_solver_instances.cpp lar_core_solver_instances.cpp lp_core_solver_base_instances.cpp lp_dual_core_solver_instances.cpp @@ -18,8 +20,9 @@ z3_add_component(lp lp_solver_instances.cpp lu_instances.cpp matrix_instances.cpp + nra_solver.cpp permutation_matrix_instances.cpp - quick_xplain.cpp + quick_xplain.cpp row_eta_matrix_instances.cpp scaler_instances.cpp sparse_matrix_instances.cpp @@ -28,6 +31,8 @@ z3_add_component(lp random_updater_instances.cpp COMPONENT_DEPENDENCIES util + polynomial + nlsat PYG_FILES lp_params.pyg ) diff --git a/src/util/lp/column_namer.h b/src/util/lp/column_namer.h index 1a10a5a23..a3fe05dd0 100644 --- a/src/util/lp/column_namer.h +++ b/src/util/lp/column_namer.h @@ -15,7 +15,7 @@ public: T a; unsigned i; while (it->next(a, i)) { - coeff.emplace_back(a, i); + coeff.push_back(std::make_pair(a, i)); } print_linear_combination_of_column_indices(coeff, out); } diff --git a/src/util/lp/indexed_vector.h b/src/util/lp/indexed_vector.h index 6e6a6009b..4b9a7767d 100644 --- a/src/util/lp/indexed_vector.h +++ b/src/util/lp/indexed_vector.h @@ -75,16 +75,7 @@ public: } void set_value(const T& value, unsigned index); - void set_value_as_in_dictionary(unsigned index) { - lean_assert(index < m_data.size()); - T & loc = m_data[index]; - if (is_zero(loc)) { - m_index.push_back(index); - loc = one_of_type(); // use as a characteristic function - } - } - void clear(); void clear_all(); const T& operator[] (unsigned i) const { diff --git a/src/util/lp/init_lar_solver.h b/src/util/lp/init_lar_solver.h deleted file mode 100644 index 3fc29f25b..000000000 --- a/src/util/lp/init_lar_solver.h +++ /dev/null @@ -1,576 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ - -// here we are inside lean::lar_solver class - -bool strategy_is_undecided() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; -} - -var_index add_var(unsigned ext_j) { - var_index i; - lean_assert (ext_j < m_terms_start_index); - - if (ext_j >= m_terms_start_index) - throw 0; // todo : what is the right way to exit? - - if (try_get_val(m_ext_vars_to_columns, ext_j, i)) { - return i; - } - lean_assert(m_vars_to_ul_pairs.size() == A_r().column_count()); - i = A_r().column_count(); - m_vars_to_ul_pairs.push_back (ul_pair(static_cast(-1))); - add_non_basic_var_to_core_fields(ext_j); - lean_assert(sizes_are_correct()); - return i; -} - -void register_new_ext_var_index(unsigned ext_v) { - lean_assert(!contains(m_ext_vars_to_columns, ext_v)); - unsigned j = static_cast(m_ext_vars_to_columns.size()); - m_ext_vars_to_columns[ext_v] = j; - lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j); - m_columns_to_ext_vars_or_term_indices.push_back(ext_v); -} - -void add_non_basic_var_to_core_fields(unsigned ext_j) { - register_new_ext_var_index(ext_j); - m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); - m_columns_with_changed_bound.increase_size_by_one(); - add_new_var_to_core_fields_for_mpq(false); - if (use_lu()) - add_new_var_to_core_fields_for_doubles(false); -} - -void add_new_var_to_core_fields_for_doubles(bool register_in_basis) { - unsigned j = A_d().column_count(); - A_d().add_column(); - lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); - m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_d().add_row(); - m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); - m_mpq_lar_core_solver.m_d_basis.push_back(j); - }else { - m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_d_nbasis.push_back(j); - } -} - -void add_new_var_to_core_fields_for_mpq(bool register_in_basis) { - unsigned j = A_r().column_count(); - A_r().add_column(); - lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_r_x.resize(j + 1); - m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); - m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_r().add_row(); - m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); - m_mpq_lar_core_solver.m_r_basis.push_back(j); - if (m_settings.bound_propagation()) - m_rows_with_changed_bounds.insert(A_r().row_count() - 1); - } else { - m_mpq_lar_core_solver.m_r_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_r_nbasis.push_back(j); - } -} - - -var_index add_term_undecided(const vector> & coeffs, - const mpq &m_v) { - m_terms.push_back(new lar_term(coeffs, m_v)); - m_orig_terms.push_back(new lar_term(coeffs, m_v)); - return m_terms_start_index + m_terms.size() - 1; -} - -// terms -var_index add_term(const vector> & coeffs, - const mpq &m_v) { - if (strategy_is_undecided()) - return add_term_undecided(coeffs, m_v); - - m_terms.push_back(new lar_term(coeffs, m_v)); - m_orig_terms.push_back(new lar_term(coeffs, m_v)); - unsigned adjusted_term_index = m_terms.size() - 1; - var_index ret = m_terms_start_index + adjusted_term_index; - if (use_tableau() && !coeffs.empty()) { - add_row_for_term(m_orig_terms.back(), ret); - if (m_settings.bound_propagation()) - m_rows_with_changed_bounds.insert(A_r().row_count() - 1); - } - lean_assert(m_ext_vars_to_columns.size() == A_r().column_count()); - return ret; -} - -void add_row_for_term(const lar_term * term, unsigned term_ext_index) { - lean_assert(sizes_are_correct()); - add_row_from_term_no_constraint(term, term_ext_index); - lean_assert(sizes_are_correct()); -} - -void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { - register_new_ext_var_index(term_ext_index); - // j will be a new variable - unsigned j = A_r().column_count(); - ul_pair ul(j); - m_vars_to_ul_pairs.push_back(ul); - add_basic_var_to_core_fields(); - if (use_tableau()) { - auto it = iterator_on_term_with_basis_var(*term, j); - A_r().fill_last_row_with_pivoting(it, - m_mpq_lar_core_solver.m_r_solver.m_basis_heading); - m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type()); - } else { - fill_last_row_of_A_r(A_r(), term); - } - m_mpq_lar_core_solver.m_r_x[j] = get_basic_var_value_from_row_directly(A_r().row_count() - 1); - if (use_lu()) - fill_last_row_of_A_d(A_d(), term); -} - -void add_basic_var_to_core_fields() { - bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); - lean_assert(!use_lu || A_r().column_count() == A_d().column_count()); - m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); - m_columns_with_changed_bound.increase_size_by_one(); - m_rows_with_changed_bounds.increase_size_by_one(); - add_new_var_to_core_fields_for_mpq(true); - if (use_lu) - add_new_var_to_core_fields_for_doubles(true); -} - -constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { - constraint_index ci = m_constraints.size(); - if (!is_term(j)) { // j is a var - auto vc = new lar_var_constraint(j, kind, right_side); - m_constraints.push_back(vc); - update_column_type_and_bound(j, kind, right_side, ci); - } else { - add_var_bound_on_constraint_for_term(j, kind, right_side, ci); - } - lean_assert(sizes_are_correct()); - return ci; -} - -void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { - switch(m_mpq_lar_core_solver.m_column_types[j]) { - case column_type::free_column: - update_free_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::boxed: - update_boxed_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::low_bound: - update_low_bound_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::upper_bound: - update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::fixed: - update_fixed_column_type_and_bound(j, kind, right_side, constr_index); - break; - default: - lean_assert(false); // cannot be here - } -} - -void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(is_term(j)); - unsigned adjusted_term_index = adjust_term_index(j); - unsigned term_j; - if (try_get_val(m_ext_vars_to_columns, j, term_j)) { - mpq rs = right_side - m_orig_terms[adjusted_term_index]->m_v; - m_constraints.push_back(new lar_term_constraint(m_orig_terms[adjusted_term_index], kind, right_side)); - update_column_type_and_bound(term_j, kind, rs, ci); - } - else { - add_constraint_from_term_and_create_new_column_row(j, m_orig_terms[adjusted_term_index], kind, right_side); - } -} - - -void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, - lconstraint_kind kind, const mpq & right_side) { - - add_row_from_term_no_constraint(term, term_j); - unsigned j = A_r().column_count() - 1; - update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size()); - m_constraints.push_back(new lar_term_constraint(term, kind, right_side)); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); -} - -void decide_on_strategy_and_adjust_initial_state() { - lean_assert(strategy_is_undecided()); - if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { - m_settings.simplex_strategy() = simplex_strategy_enum::lu; - } else { - m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs? - } - adjust_initial_state(); -} - -void adjust_initial_state() { - switch (m_settings.simplex_strategy()) { - case simplex_strategy_enum::lu: - adjust_initial_state_for_lu(); - break; - case simplex_strategy_enum::tableau_rows: - adjust_initial_state_for_tableau_rows(); - break; - case simplex_strategy_enum::tableau_costs: - lean_assert(false); // not implemented - case simplex_strategy_enum::undecided: - adjust_initial_state_for_tableau_rows(); - break; - } -} - -void adjust_initial_state_for_lu() { - copy_from_mpq_matrix(A_d()); - unsigned n = A_d().column_count(); - m_mpq_lar_core_solver.m_d_x.resize(n); - m_mpq_lar_core_solver.m_d_low_bounds.resize(n); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); - m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; - m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; - - /* - unsigned j = A_d().column_count(); - A_d().add_column(); - lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); - m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_d().add_row(); - m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); - m_mpq_lar_core_solver.m_d_basis.push_back(j); - }else { - m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_d_nbasis.push_back(j); - }*/ -} - -void adjust_initial_state_for_tableau_rows() { - for (unsigned j = 0; j < m_terms.size(); j++) { - if (contains(m_ext_vars_to_columns, j + m_terms_start_index)) - continue; - add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index); - } -} - -// this fills the last row of A_d and sets the basis column: -1 in the last column of the row -void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); - unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].empty()); - - for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); - var_index j = t.first; - A.set(last_row, j, - t.second.get_double()); - } - - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, - 1 ); -} - -void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); - lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); - { - auto up = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - } - set_upper_bound_witness(j, constr_ind); - break; - case GT: - y_of_bound = 1; - case GE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound; - lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); - { - auto low = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - } - set_low_bound_witness(j, constr_ind); - break; - case EQ: - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair(right_side, zero_of_type()); - set_upper_bound_witness(j, constr_ind); - set_low_bound_witness(j, constr_ind); - break; - - default: - lean_unreachable(); - - } - m_columns_with_changed_bound.insert(j); -} - -void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - if (up < m_mpq_lar_core_solver.m_r_upper_bounds()[j]) { - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - } - } - break; - case GT: - y_of_bound = 1; - case GE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed; - { - auto low = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - set_low_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - } else { - m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed; - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - set_low_bound_witness(j, ci); - m_infeasible_column_index = j; - } else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - break; - } - break; - - default: - lean_unreachable(); - - } -} - -void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - } - - if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - lean_assert(false); - m_infeasible_column_index = j; - } else { - if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]) - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - } - break; - case GT: - y_of_bound = 1; - case GE: - { - auto low = numeric_pair(right_side, y_of_bound); - if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - } - if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - } else if ( low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - m_columns_with_changed_bound.insert(j); - } - - break; - } - - default: - lean_unreachable(); - - } -} -void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - - if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - } else { - m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed; - } - } - break; - case GT: - y_of_bound = 1; - case GE: - { - auto low = numeric_pair(right_side, y_of_bound); - if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - m_columns_with_changed_bound.insert(j); - break; - } - - default: - lean_unreachable(); - - } -} - -void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); - auto v = numeric_pair(right_side, mpq(0)); - - mpq y_of_bound(0); - switch (kind) { - case LT: - if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - break; - case LE: - { - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - } - break; - case GT: - { - if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index =j; - set_low_bound_witness(j, ci); - } - } - break; - case GE: - { - if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } - } - break; - case EQ: - { - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } - break; - } - - default: - lean_unreachable(); - - } -} - diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp new file mode 100644 index 000000000..e617a1e29 --- /dev/null +++ b/src/util/lp/int_solver.cpp @@ -0,0 +1,606 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#include "util/lp/int_solver.h" +#include "util/lp/lar_solver.h" +namespace lean { + +void int_solver::fix_non_base_columns() { + auto & lcs = m_lar_solver->m_mpq_lar_core_solver; + for (unsigned j : lcs.m_r_nbasis) { + if (column_is_int_inf(j)) { + set_value(j, floor(lcs.m_r_x[j].x)); + } + } + if (m_lar_solver->find_feasible_solution() == INFEASIBLE) + failed(); +} + +void int_solver::failed() { + auto & lcs = m_lar_solver->m_mpq_lar_core_solver; + + for (unsigned j : m_old_values_set.m_index) { + lcs.m_r_x[j] = m_old_values_data[j]; + lean_assert(lcs.m_r_solver.column_is_feasible(j)); + lcs.m_r_solver.remove_column_from_inf_set(j); + } + lean_assert(lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis()); + lean_assert(lcs.m_r_solver.current_x_is_feasible()); + m_old_values_set.clear(); +} + +void int_solver::trace_inf_rows() const { + unsigned num = m_lar_solver->A_r().column_count(); + for (unsigned v = 0; v < num; v++) { + if (is_int(v) && !get_value(v).is_int()) { + display_column(tout, v); + } + } + + num = 0; + for (unsigned i = 0; i < m_lar_solver->A_r().row_count(); i++) { + unsigned j = m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i]; + if (column_is_int_inf(j)) { + num++; + iterator_on_row it(m_lar_solver->A_r().m_rows[i]); + m_lar_solver->print_linear_iterator(&it, tout); + tout << "\n"; + } + } + tout << "num of int infeasible: " << num << "\n"; +} + +int int_solver::find_inf_int_base_column() { + if (m_inf_int_set.is_empty()) + return -1; + int j = find_inf_int_boxed_base_column_with_smallest_range(); + if (j != -1) + return j; + unsigned k = settings().random_next() % m_inf_int_set.m_index.size(); + return m_inf_int_set.m_index[k]; +} + +int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { + int result = -1; + mpq range; + mpq new_range; + mpq small_range_thresold(1024); + unsigned n = 0; + lar_core_solver & lcs = m_lar_solver->m_mpq_lar_core_solver; + + for (int j : m_inf_int_set.m_index) { + lean_assert(is_base(j) && column_is_int_inf(j)); + if (!is_boxed(j)) + continue; + new_range = lcs.m_r_upper_bounds()[j].x - lcs.m_r_low_bounds()[j].x; + if (new_range > small_range_thresold) + continue; + if (result == -1) { + result = j; + range = new_range; + n = 1; + continue; + } + if (new_range < range) { + n = 1; + result = j; + range = new_range; + continue; + } + if (new_range == range) { + n++; + if (settings().random_next() % n == 0) { + result = j; + continue; + } + } + } + return result; + +} + +lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { + lean_assert(is_feasible()); + init_inf_int_set(); + lean_assert(inf_int_set_is_correct()); + // currently it is a reimplementation of + // final_check_status theory_arith::check_int_feasibility() + // from theory_arith_int.h + if (m_lar_solver->model_is_int_feasible()) + return lia_move::ok; + if (!gcd_test(ex)) + return lia_move::conflict; + /* + if (m_params.m_arith_euclidean_solver) + apply_euclidean_solver(); + + */ + m_lar_solver->pivot_fixed_vars_from_basis(); + patch_int_infeasible_columns(); + fix_non_base_columns(); + lean_assert(is_feasible()); + TRACE("arith_int_rows", trace_inf_rows();); + + if (find_inf_int_base_column() == -1) + return lia_move::ok; + + + if ((++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) { + move_non_base_vars_to_bounds(); + /* + if (!make_feasible()) { + TRACE("arith_int", tout << "failed to move variables to bounds.\n";); + failed(); + return FC_CONTINUE; + } + int int_var = find_inf_int_base_var(); + if (int_var != null_int) { + TRACE("arith_int", tout << "v" << int_var << " does not have an integer assignment: " << get_value(int_var) << "\n";); + SASSERT(is_base(int_var)); + row const & r = m_rows[get_var_row(int_var)]; + if (!mk_gomory_cut(r)) { + // silent failure + } + return FC_CONTINUE; + }*/ + } + else { + int j = find_inf_int_base_column(); + /* + if (j != -1) { + TRACE("arith_int", tout << "v" << j << " does not have an integer assignment: " << get_value(j) << "\n";); + // apply branching + branch_infeasible_int_var(int_var); + return false; + }*/ + } + // return true; + return lia_move::give_up; +} + +void int_solver::move_non_base_vars_to_bounds() { + auto & lcs = m_lar_solver->m_mpq_lar_core_solver; + for (unsigned j : lcs.m_r_nbasis) { + auto & val = lcs.m_r_x[j]; + switch (lcs.m_column_types()[j]) { + case column_type::boxed: + if (val != lcs.m_r_low_bounds()[j] && val != lcs.m_r_upper_bounds()[j]) + set_value(j, lcs.m_r_low_bounds()[j]); + break; + case column_type::low_bound: + if (val != lcs.m_r_low_bounds()[j]) + set_value(j, lcs.m_r_low_bounds()[j]); + break; + case column_type::upper_bound: + if (val != lcs.m_r_upper_bounds()[j]) + set_value(j, lcs.m_r_upper_bounds()[j]); + break; + default: + if (is_int(j) && !val.is_int()) { + set_value(j, impq(floor(val))); + } + } + } +} + + + +void int_solver::set_value(unsigned j, const impq & new_val) { + auto & x = m_lar_solver->m_mpq_lar_core_solver.m_r_x[j]; + if (!m_old_values_set.contains(j)) { + m_old_values_set.insert(j); + m_old_values_data[j] = x; + } + auto delta = new_val - x; + x = new_val; + m_lar_solver->change_basic_x_by_delta_on_column(j, delta); + update_column_in_inf_set_set(j); +} + +void int_solver::patch_int_infeasible_columns() { + bool inf_l, inf_u; + impq l, u; + mpq m; + auto & lcs = m_lar_solver->m_mpq_lar_core_solver; + for (unsigned j : lcs.m_r_nbasis) { + if (!is_int(j)) + continue; + get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m); + impq & val = lcs.m_r_x[j]; + bool val_is_int = val.is_int(); + bool m_is_one = m.is_one(); + if (m.is_one() && val_is_int) + continue; + // check whether value of j is already a multiple of m. + if (val_is_int && (val.x / m).is_int()) + continue; + TRACE("patch_int", + tout << "TARGET j" << j << " -> ["; + if (inf_l) tout << "-oo"; else tout << l; + tout << ", "; + if (inf_u) tout << "oo"; else tout << u; + tout << "]"; + tout << ", m: " << m << ", val: " << val << ", is_int: " << m_lar_solver->column_is_int(j) << "\n";); + if (!inf_l) { + l = m_is_one? ceil(l) : m * ceil(l / m); + if (inf_u || l <= u) { + TRACE("patch_int", + tout << "patching with l: " << l << '\n';); + + set_value(j, l); + } else { + TRACE("patch_int", + tout << "not patching " << l << "\n";); + } + } else if (!inf_u) { + u = m_is_one? floor(u) : m * floor(u / m); + set_value(j, u); + TRACE("patch_int", + tout << "patching with u: " << u << '\n';); + } else { + set_value(j, impq(0)); + TRACE("patch_int", + tout << "patching with 0\n";); + } + } +} + +mpq get_denominators_lcm(iterator_on_row &it) { + mpq r(1); + mpq a; + unsigned j; + while (it.next(a, j)) { + r = lcm(r, denominator(a)); + } + return r; +} + +bool int_solver::gcd_test_for_row(static_matrix> & A, unsigned i, explanation & ex) { + iterator_on_row it(A.m_rows[i]); + std::cout << "gcd_test_for_row(" << i << ")\n"; + mpq lcm_den = get_denominators_lcm(it); + mpq consts(0); + mpq gcds(0); + mpq least_coeff(0); + bool least_coeff_is_bounded = false; + mpq a; + unsigned j; + while (it.next(a, j)) { + if (m_lar_solver->column_is_fixed(j)) { + mpq aux = lcm_den * a; + consts += aux * m_lar_solver->column_low_bound(j).x; + } + else if (m_lar_solver->column_is_real(j)) { + return true; + } + else if (gcds.is_zero()) { + gcds = abs(lcm_den * a); + least_coeff = gcds; + least_coeff_is_bounded = m_lar_solver->column_is_bounded(j); + } + else { + mpq aux = abs(lcm_den * a); + gcds = gcd(gcds, aux); + if (aux < least_coeff) { + least_coeff = aux; + least_coeff_is_bounded = m_lar_solver->column_is_bounded(j); + } + else if (least_coeff_is_bounded && aux == least_coeff) { + least_coeff_is_bounded = m_lar_solver->column_is_bounded(j); + } + } + SASSERT(gcds.is_int()); + SASSERT(least_coeff.is_int()); + TRACE("gcd_test_bug", tout << "coeff: " << a << ", gcds: " << gcds + << " least_coeff: " << least_coeff << " consts: " << consts << "\n";); + + } + + if (gcds.is_zero()) { + // All variables are fixed. + // This theory guarantees that the assignment satisfies each row, and + // fixed integer variables are assigned to integer values. + return true; + } + + if (!(consts / gcds).is_int()) + fill_explanation_from_fixed_columns(it, ex); + + if (least_coeff.is_one() && !least_coeff_is_bounded) { + SASSERT(gcds.is_one()); + return true; + } + + if (least_coeff_is_bounded) { + return ext_gcd_test(it, least_coeff, lcm_den, consts, ex); + } + return true; +} + +void int_solver::add_to_explanation_from_fixed_or_boxed_column(unsigned j, explanation & ex) { + constraint_index lc, uc; + m_lar_solver->get_bound_constraint_witnesses_for_column(j, lc, uc); + ex.m_explanation.push_back(std::make_pair(mpq(1), lc)); + ex.m_explanation.push_back(std::make_pair(mpq(1), uc)); +} +void int_solver::fill_explanation_from_fixed_columns(iterator_on_row & it, explanation & ex) { + it.reset(); + unsigned j; + while (it.next(j)) { + if (!m_lar_solver->column_is_fixed(j)) + continue; + add_to_explanation_from_fixed_or_boxed_column(j, ex); + } +} + +bool int_solver::gcd_test(explanation & ex) { + auto & A = m_lar_solver->A_r(); // getting the matrix + for (unsigned i = 0; i < A.row_count(); i++) + if (!gcd_test_for_row(A, i, ex)) { + std::cout << "false from gcd_test\n" ; + return false; + } + + return true; +} + +bool int_solver::ext_gcd_test(iterator_on_row & it, + mpq const & least_coeff, + mpq const & lcm_den, + mpq const & consts, explanation& ex) { + + std::cout << "calling ext_gcd_test" << std::endl; + mpq gcds(0); + mpq l(consts); + mpq u(consts); + + it.reset(); + mpq a; + unsigned j; + while (it.next(a, j)) { + if (m_lar_solver->column_is_fixed(j)) + continue; + SASSERT(!m_lar_solver->column_is_real(j)); + mpq ncoeff = lcm_den * a; + SASSERT(ncoeff.is_int()); + mpq abs_ncoeff = abs(ncoeff); + if (abs_ncoeff == least_coeff) { + SASSERT(m_lar_solver->column_is_bounded(j)); + if (ncoeff.is_pos()) { + // l += ncoeff * m_lar_solver->column_low_bound(j).x; + l.addmul(ncoeff, m_lar_solver->column_low_bound(j).x); + // u += ncoeff * m_lar_solver->column_upper_bound(j).x; + u.addmul(ncoeff, m_lar_solver->column_upper_bound(j).x); + } + else { + // l += ncoeff * upper_bound(j).get_rational(); + l.addmul(ncoeff, m_lar_solver->column_upper_bound(j).x); + // u += ncoeff * lower_bound(j).get_rational(); + u.addmul(ncoeff, m_lar_solver->column_low_bound(j).x); + } + add_to_explanation_from_fixed_or_boxed_column(j, ex); + } + else if (gcds.is_zero()) { + gcds = abs_ncoeff; + } + else { + gcds = gcd(gcds, abs_ncoeff); + } + SASSERT(gcds.is_int()); + } + + if (gcds.is_zero()) { + return true; + } + + mpq l1 = ceil(l/gcds); + mpq u1 = floor(u/gcds); + + if (u1 < l1) { + fill_explanation_from_fixed_columns(it, ex); + return false; + } + + return true; + +} + +linear_combination_iterator * int_solver::get_column_iterator(unsigned j) { + if (m_lar_solver->use_tableau()) + return new iterator_on_column(m_lar_solver->A_r().m_columns[j], m_lar_solver->A_r()); + return new iterator_on_indexed_vector(m_lar_solver->get_column_in_lu_mode(j)); +} + + +int_solver::int_solver(lar_solver* lar_slv) : + m_lar_solver(lar_slv), + m_branch_cut_counter(0) { + lean_assert(m_old_values_set.size() == 0); + m_old_values_set.resize(lar_slv->A_r().column_count()); + m_old_values_data.resize(lar_slv->A_r().column_count(), zero_of_type()); +} + +bool int_solver::lower(unsigned j) const { + switch (m_lar_solver->m_mpq_lar_core_solver.m_column_types()[j]) { + case column_type::fixed: + case column_type::boxed: + case column_type::low_bound: + return true; + default: + return false; + } +} + +bool int_solver::upper(unsigned j) const { + switch (m_lar_solver->m_mpq_lar_core_solver.m_column_types()[j]) { + case column_type::fixed: + case column_type::boxed: + case column_type::upper_bound: + return true; + default: + return false; + } +} + +const impq& int_solver::lower_bound(unsigned j) const { + return m_lar_solver->m_mpq_lar_core_solver.m_r_low_bounds()[j]; +} + +const impq& int_solver::upper_bound(unsigned j) const { + return m_lar_solver->m_mpq_lar_core_solver.m_r_upper_bounds()[j]; +} + + +void set_lower(impq & l, + bool & inf_l, + impq const & v ) { + if (inf_l || v > l) { + l = v; + inf_l = false; + } +} + +void set_upper(impq & u, + bool & inf_u, + impq const & v) { + if (inf_u || v < u) { + u = v; + inf_u = false; + } +} + +bool int_solver::get_freedom_interval_for_column(unsigned x_j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m) { + auto & lcs = m_lar_solver->m_mpq_lar_core_solver; + if (lcs.m_r_heading[x_j] >= 0) // the basic var + return false; + + impq const & x_j_val = lcs.m_r_x[x_j]; + linear_combination_iterator *it = get_column_iterator(x_j); + + inf_l = true; + inf_u = true; + l = u = zero_of_type(); + m = mpq(1); + + if (lower(x_j)) { + set_lower(l, inf_l, lower_bound(x_j)); + } + if (upper(x_j)) { + set_upper(u, inf_u, upper_bound(x_j)); + } + + mpq a_ij; unsigned i; + while (it->next(a_ij, i)) { + unsigned x_i = lcs.m_r_basis[i]; + impq const & x_i_val = lcs.m_r_x[x_i]; + if (is_int(x_i) && is_int(x_j) && !a_ij.is_int()) + m = lcm(m, denominator(a_ij)); + bool x_i_lower = lower(x_i); + bool x_i_upper = upper(x_i); + if (a_ij.is_neg()) { + if (x_i_lower) { + impq new_l = x_j_val + ((x_i_val - lcs.m_r_low_bounds()[x_i]) / a_ij); + set_lower(l, inf_l, new_l); + if (!inf_l && !inf_u && l == u) break;; + } + if (x_i_upper) { + impq new_u = x_j_val + ((x_i_val - lcs.m_r_upper_bounds()[x_i]) / a_ij); + set_upper(u, inf_u, new_u); + if (!inf_l && !inf_u && l == u) break;; + } + } + else { + if (x_i_upper) { + impq new_l = x_j_val + ((x_i_val - lcs.m_r_upper_bounds()[x_i]) / a_ij); + set_lower(l, inf_u, new_l); + if (!inf_l && !inf_u && l == u) break;; + } + if (x_i_lower) { + impq new_u = x_j_val + ((x_i_val - lcs.m_r_low_bounds()[x_i]) / a_ij); + set_upper(u, inf_u, new_u); + if (!inf_l && !inf_u && l == u) break;; + } + } + } + + delete it; + TRACE("freedom_interval", + tout << "freedom variable for:\n"; + tout << m_lar_solver->get_column_name(x_j); + tout << "["; + if (inf_l) tout << "-oo"; else tout << l; + tout << "; "; + if (inf_u) tout << "oo"; else tout << u; + tout << "]\n";); + return true; + +} + +bool int_solver::is_int(unsigned j) const { + return m_lar_solver->column_is_int(j); +} + +bool int_solver::value_is_int(unsigned j) const { + return m_lar_solver->m_mpq_lar_core_solver.m_r_x[j].is_int(); +} + + + +bool int_solver::is_feasible() const { + auto & lcs = m_lar_solver->m_mpq_lar_core_solver; + lean_assert( + lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis() == + lcs.m_r_solver.current_x_is_feasible()); + return lcs.m_r_solver.current_x_is_feasible(); +} +const impq & int_solver::get_value(unsigned j) const { + return m_lar_solver->m_mpq_lar_core_solver.m_r_x[j]; +} + +void int_solver::display_column(std::ostream & out, unsigned j) const { + m_lar_solver->m_mpq_lar_core_solver.m_r_solver.print_column_info(j, out); +} + +bool int_solver::inf_int_set_is_correct() const { + for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) { + if (m_inf_int_set.contains(j) != is_int(j) && (!value_is_int(j))) + return false; + } + return true; +} + +bool int_solver::column_is_int_inf(unsigned j) const { + return is_int(j) && (!value_is_int(j)); +} + +void int_solver::init_inf_int_set() { + m_inf_int_set.clear(); + m_inf_int_set.resize(m_lar_solver->A_r().column_count()); + for (unsigned j : m_lar_solver->m_mpq_lar_core_solver.m_r_basis) { + if (column_is_int_inf(j)) + m_inf_int_set.insert(j); + } +} + +void int_solver::update_column_in_inf_set_set(unsigned j) { + if (is_int(j) && (!value_is_int(j))) + m_inf_int_set.insert(j); + else + m_inf_int_set.erase(j); +} + +bool int_solver::is_base(unsigned j) const { + return m_lar_solver->m_mpq_lar_core_solver.m_r_heading[j] >= 0; +} + +bool int_solver::is_boxed(unsigned j) const { + return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed; +} + +lp_settings& int_solver::settings() { + return m_lar_solver->settings(); +} + +} diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h new file mode 100644 index 000000000..981127bc8 --- /dev/null +++ b/src/util/lp/int_solver.h @@ -0,0 +1,100 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ +#pragma once +#include "util/lp/lp_settings.h" +#include "util/lp/static_matrix.h" +#include "util/lp/iterator_on_row.h" +#include "util/lp/int_set.h" +#include "util/lp/lar_term.h" + +namespace lean { +class lar_solver; +template +struct lp_constraint; +enum class lia_move { + ok, + branch, + cut, + conflict, + give_up +}; + +struct explanation { + vector> m_explanation; +}; + +class int_solver { +public: + // fields + lar_solver *m_lar_solver; + int_set m_old_values_set; + vector m_old_values_data; + int_set m_inf_int_set; + unsigned m_branch_cut_counter; + // methods + int_solver(lar_solver* lp); + // main function to check that 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); +private: + + // how to tighten bounds for integer variables. + + bool gcd_test_for_row(static_matrix> & A, unsigned i, explanation &); + + // gcd test + // 5*x + 3*y + 6*z = 5 + // suppose x is fixed at 2. + // so we have 10 + 3(y + 2z) = 5 + // 5 = -3(y + 2z) + // this is unsolvable because 5/3 is not an integer. + // so we create a lemma that rules out this condition. + // + bool gcd_test(explanation & ); // returns false in case of failure. Creates a theory lemma in case of failure. + + // create goromy cuts + // either creates a conflict or a bound. + + // branch and bound: + // decide what to branch and bound on + // creates a fresh inequality. + + bool branch(const lp_constraint & new_inequality); + bool ext_gcd_test(iterator_on_row & it, + mpq const & least_coeff, + mpq const & lcm_den, + mpq const & consts, + explanation & ex); + void fill_explanation_from_fixed_columns(iterator_on_row & it, explanation &); + void add_to_explanation_from_fixed_or_boxed_column(unsigned j, explanation &); + void remove_fixed_vars_from_base(); + void patch_int_infeasible_columns(); + bool get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m); + linear_combination_iterator * get_column_iterator(unsigned j); + bool lower(unsigned j) const; + bool upper(unsigned j) const; + const impq & lower_bound(unsigned j) const; + const impq & upper_bound(unsigned j) const; + bool is_int(unsigned j) const; + bool is_base(unsigned j) const; + bool is_boxed(unsigned j) const; + bool value_is_int(unsigned j) const; + void set_value(unsigned j, const impq & new_val); + void fix_non_base_columns(); + void failed(); + bool is_feasible() const; + const impq & get_value(unsigned j) const; + void display_column(std::ostream & out, unsigned j) const; + bool inf_int_set_is_correct() const; + void init_inf_int_set(); + void update_column_in_inf_set_set(unsigned j); + bool column_is_int_inf(unsigned j) const; + void trace_inf_rows() const; + int find_inf_int_base_column(); + int find_inf_int_boxed_base_column_with_smallest_range(); + lp_settings& settings(); + void move_non_base_vars_to_bounds(); +}; +} diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 71d69c3a4..44a6349a7 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -796,6 +796,37 @@ public: return new iterator_on_indexed_vector(m_r_solver.m_ed); } } + + bool column_is_fixed(unsigned j) const { + return m_column_types()[j] == column_type::fixed || + ( m_column_types()[j] == column_type::boxed && + m_r_solver.m_low_bounds[j] == m_r_solver.m_upper_bounds[j]); + } + + const impq & low_bound(unsigned j) const { + lean_assert(m_column_types()[j] == column_type::fixed || + m_column_types()[j] == column_type::boxed || + m_column_types()[j] == column_type::low_bound); + return m_r_low_bounds[j]; + } + + const impq & upper_bound(unsigned j) const { + lean_assert(m_column_types()[j] == column_type::fixed || + m_column_types()[j] == column_type::boxed || + m_column_types()[j] == column_type::upper_bound); + return m_r_upper_bounds[j]; + } + + const bool column_is_bounded(unsigned j) const { + switch(m_column_types()[j]) { + case column_type::fixed: + case column_type::boxed: + return true; + default: + return false; + } + } + }; } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp new file mode 100644 index 000000000..def72734c --- /dev/null +++ b/src/util/lp/lar_solver.cpp @@ -0,0 +1,2040 @@ +#include "util/lp/lar_solver.h" +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +namespace lean { + +unsigned lar_solver::constraint_count() const { + return m_constraints.size(); +} +const lar_base_constraint& lar_solver::get_constraint(unsigned ci) const { + return *(m_constraints[ci]); +} + +////////////////// methods //////////////////////////////// +static_matrix> & lar_solver::A_r() { return m_mpq_lar_core_solver.m_r_A;} +static_matrix> const & lar_solver::A_r() const { return m_mpq_lar_core_solver.m_r_A;} +static_matrix & lar_solver::A_d() { return m_mpq_lar_core_solver.m_d_A;} +static_matrix const & lar_solver::A_d() const { return m_mpq_lar_core_solver.m_d_A;} + +lp_settings & lar_solver::settings() { return m_settings;} + +lp_settings const & lar_solver::settings() const { return m_settings;} + +void clear() {lean_assert(false); // not implemented +} + + +lar_solver::lar_solver() : m_status(OPTIMAL), + m_infeasible_column_index(-1), + m_terms_start_index(1000000), + m_mpq_lar_core_solver(m_settings, *this) +{ +} + +void lar_solver::set_propagate_bounds_on_pivoted_rows_mode(bool v) { + m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; +} + +lar_solver::~lar_solver(){ + for (auto c : m_constraints) + delete c; + for (auto t : m_terms) + delete t; +} + +numeric_pair const& lar_solver::get_value(var_index vi) const { return m_mpq_lar_core_solver.m_r_x[vi]; } + +bool lar_solver::is_term(var_index j) const { + return j >= m_terms_start_index && j - m_terms_start_index < m_terms.size(); +} + +unsigned lar_solver::adjust_term_index(unsigned j) const { + lean_assert(is_term(j)); + return j - m_terms_start_index; +} + + +bool lar_solver::use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } + +bool lar_solver::sizes_are_correct() const { + lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); + return true; +} + + +void lar_solver::print_implied_bound(const implied_bound& be, std::ostream & out) const { + out << "implied bound\n"; + unsigned v = be.m_j; + if (is_term(v)) { + out << "it is a term number " << be.m_j << std::endl; + print_term(*m_terms[be.m_j - m_terms_start_index], out); + } + else { + out << get_column_name(v); + } + out << " " << lconstraint_kind_string(be.kind()) << " " << be.m_bound << std::endl; + // for (auto & p : be.m_explanation) { + // out << p.first << " : "; + // print_constraint(p.second, out); + // } + + // m_mpq_lar_core_solver.m_r_solver.print_column_info(be.m_j< m_terms_start_index? be.m_j : adjust_term_index(be.m_j), out); + out << "end of implied bound" << std::endl; +} + +bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { + std::unordered_map coeff_map; + auto rs_of_evidence = zero_of_type(); + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : explanation) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + const auto & constr = *m_constraints[con_ind]; + lconstraint_kind kind = coeff.is_pos() ? constr.m_kind : flip_kind(constr.m_kind); + register_in_map(coeff_map, constr, coeff); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + rs_of_evidence += coeff*constr.m_right_side; + } + lean_assert(n_of_G == 0 || n_of_L == 0); + lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); + if (strict) + kind = static_cast((static_cast(kind) / 2)); + + if (!is_term(be.m_j)) { + if (coeff_map.size() != 1) + return false; + auto it = coeff_map.find(be.m_j); + if (it == coeff_map.end()) return false; + mpq ratio = it->second; + if (ratio < zero_of_type()) { + kind = static_cast(-kind); + } + rs_of_evidence /= ratio; + } else { + const lar_term * t = m_terms[adjust_term_index(be.m_j)]; + const auto first_coeff = *t->m_coeffs.begin(); + unsigned j = first_coeff.first; + auto it = coeff_map.find(j); + if (it == coeff_map.end()) + return false; + mpq ratio = it->second / first_coeff.second; + for (auto & p : t->m_coeffs) { + it = coeff_map.find(p.first); + if (it == coeff_map.end()) + return false; + if (p.second * ratio != it->second) + return false; + } + if (ratio < zero_of_type()) { + kind = static_cast(-kind); + } + rs_of_evidence /= ratio; + rs_of_evidence += t->m_v * ratio; + } + + return kind == be.kind() && rs_of_evidence == be.m_bound; +} + + +void lar_solver::analyze_new_bounds_on_row( + unsigned row_index, + bound_propagator & bp) { + lean_assert(!use_tableau()); + iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); + + bound_analyzer_on_row ra_pos(it, + zero_of_type>(), + row_index, + bp + ); + ra_pos.analyze(); +} + +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) + return; + iterator_on_row it(A_r().m_rows[row_index]); + lean_assert(use_tableau()); + bound_analyzer_on_row::analyze_row(it, + zero_of_type>(), + row_index, + bp + ); +} + + +void lar_solver::substitute_basis_var_in_terms_for_row(unsigned i) { + // todo : create a map from term basic vars to the rows where they are used + unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; + for (unsigned k = 0; k < m_terms.size(); k++) { + if (term_is_used_as_row(k)) + continue; + if (!m_terms[k]->contains(basis_j)) + continue; + m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); + } +} + +void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { + if(use_tableau()) { + analyze_new_bounds_on_row_tableau(i, bp); + } else { + m_mpq_lar_core_solver.calculate_pivot_row(i); + substitute_basis_var_in_terms_for_row(i); + analyze_new_bounds_on_row(i, bp); + } +} + + +linear_combination_iterator * lar_solver::create_new_iter_from_term(unsigned term_index) const { + lean_assert(false); // not implemented + return nullptr; + // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); +} + +unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const { + unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; + return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; +} + +void lar_solver::propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { + lean_assert(false); // not implemented +} + + +void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp) { + unsigned i = ib.m_row_or_term_index; + int bound_sign = ib.m_is_low_bound? 1: -1; + int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; + unsigned m_j = ib.m_j; + if (is_term(m_j)) { + auto it = m_ext_vars_to_columns.find(m_j); + lean_assert(it != m_ext_vars_to_columns.end()); + m_j = it->second.ext_j(); + } + for (auto const& r : A_r().m_rows[i]) { + unsigned j = r.m_j; + mpq const& a = r.get_val(); + if (j == m_j) continue; + if (is_term(j)) { + auto it = m_ext_vars_to_columns.find(j); + lean_assert(it != m_ext_vars_to_columns.end()); + j = it->second.ext_j(); + } + int a_sign = is_pos(a)? 1: -1; + int sign = j_sign * a_sign; + const ul_pair & ul = m_vars_to_ul_pairs[j]; + auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); + lean_assert(is_valid(witness)); + bp.consume(a, witness); + } + // lean_assert(implied_bound_is_correctly_explained(ib, explanation)); +} + + +bool lar_solver::term_is_used_as_row(unsigned term) const { + lean_assert(is_term(term)); + return contains(m_ext_vars_to_columns, term); +} + +void lar_solver::propagate_bounds_on_terms(bound_propagator & bp) { + for (unsigned i = 0; i < m_terms.size(); i++) { + if (term_is_used_as_row(i + m_terms_start_index)) + continue; // this term is used a left side of a constraint, + // it was processed as a touched row if needed + propagate_bounds_on_a_term(*m_terms[i], bp, i); + } +} + + +// goes over touched rows and tries to induce bounds +void lar_solver::propagate_bounds_for_touched_rows(bound_propagator & bp) { + if (!use_tableau()) + return; // todo: consider to remove the restriction + + for (unsigned i : m_rows_with_changed_bounds.m_index) { + calculate_implied_bounds_for_row(i, bp); + } + m_rows_with_changed_bounds.clear(); + if (!use_tableau()) { + propagate_bounds_on_terms(bp); + } +} + +lp_status lar_solver::get_status() const { return m_status;} + +void lar_solver::set_status(lp_status s) {m_status = s;} + +lp_status lar_solver::find_feasible_solution() { + m_settings.st().m_make_feasible++; + if (A_r().column_count() > m_settings.st().m_max_cols) + m_settings.st().m_max_cols = A_r().column_count(); + if (A_r().row_count() > m_settings.st().m_max_rows) + m_settings.st().m_max_rows = A_r().row_count(); + if (strategy_is_undecided()) + decide_on_strategy_and_adjust_initial_state(); + + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; + return solve(); +} + +lp_status lar_solver::solve() { + if (m_status == INFEASIBLE) { + return m_status; + } + solve_with_core_solver(); + if (m_status != INFEASIBLE) { + if (m_settings.bound_propagation()) + detect_rows_with_changed_bounds(); + } + + m_columns_with_changed_bound.clear(); + return m_status; +} + +void lar_solver::fill_explanation_from_infeasible_column(vector> & evidence) const{ + + // this is the case when the lower bound is in conflict with the upper one + const ul_pair & ul = m_vars_to_ul_pairs[m_infeasible_column_index]; + evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); + evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); +} + + +unsigned lar_solver::get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } +// see http://research.microsoft.com/projects/z3/smt07.pdf +// This method searches for a feasible solution with as many different values of variables, reverenced in vars, as it can find +// Attention, after a call to this method the non-basic variables don't necesserarly stick to their bounds anymore +vector lar_solver::get_list_of_all_var_indices() const { + vector ret; + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) + ret.push_back(j); + return ret; +} +void lar_solver::push() { + m_simplex_strategy = m_settings.simplex_strategy(); + m_simplex_strategy.push(); + m_status.push(); + m_vars_to_ul_pairs.push(); + m_infeasible_column_index.push(); + m_mpq_lar_core_solver.push(); + m_term_count = m_terms.size(); + m_term_count.push(); + m_constraint_count = m_constraints.size(); + m_constraint_count.push(); +} + +void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { + vector to_remove; + for (unsigned j: set.m_index) + if (j >= n) + to_remove.push_back(j); + for (unsigned j : to_remove) + set.erase(j); +} + +void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { + clean_large_elements_after_pop(n, set); + set.resize(n); +} + + +void lar_solver::pop(unsigned k) { + int n_was = static_cast(m_ext_vars_to_columns.size()); + m_status.pop(k); + m_infeasible_column_index.pop(k); + unsigned n = m_vars_to_ul_pairs.peek_size(k); + for (unsigned j = n_was; j-- > n;) + m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); + m_columns_to_ext_vars_or_term_indices.resize(n); + if (m_settings.use_tableau()) { + pop_tableau(); + } + m_vars_to_ul_pairs.pop(k); + + m_mpq_lar_core_solver.pop(k); + clean_large_elements_after_pop(n, m_columns_with_changed_bound); + unsigned m = A_r().row_count(); + clean_large_elements_after_pop(m, m_rows_with_changed_bounds); + clean_inf_set_of_r_solver_after_pop(); + lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || + (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + + + lean_assert(ax_is_correct()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); + m_constraint_count.pop(k); + for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) + delete m_constraints[i]; + + m_constraints.resize(m_constraint_count); + m_term_count.pop(k); + for (unsigned i = m_term_count; i < m_terms.size(); i++) { + delete m_terms[i]; + } + m_terms.resize(m_term_count); + m_simplex_strategy.pop(k); + m_settings.simplex_strategy() = m_simplex_strategy; + lean_assert(sizes_are_correct()); + lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); +} + +vector lar_solver::get_all_constraint_indices() const { + vector ret; + constraint_index i = 0; + while ( i < m_constraints.size()) + ret.push_back(i++); + return ret; +} + +bool lar_solver::maximize_term_on_tableau(const vector> & term, + impq &term_max) { + if (settings().simplex_strategy() == simplex_strategy_enum::undecided) + decide_on_strategy_and_adjust_initial_state(); + + m_mpq_lar_core_solver.solve(); + if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED) + return false; + + term_max = 0; + for (auto & p : term) + term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second]; + + return true; +} + +bool lar_solver::costs_are_zeros_for_r_solver() const { + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { + lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); + } + return true; +} +bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const { + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { + lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); + } + return true; +} + +void lar_solver::set_costs_to_zero(const vector> & term) { + auto & rslv = m_mpq_lar_core_solver.m_r_solver; + auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now + lean_assert(jset.m_index.size()==0); + + for (auto & p : term) { + unsigned j = p.second; + rslv.m_costs[j] = zero_of_type(); + int i = rslv.m_basis_heading[j]; + if (i < 0) + jset.insert(j); + else { + for (auto & rc : A_r().m_rows[i]) + jset.insert(rc.m_j); + } + } + + for (unsigned j : jset.m_index) + rslv.m_d[j] = zero_of_type(); + + jset.clear(); + + lean_assert(reduced_costs_are_zeroes_for_r_solver()); + lean_assert(costs_are_zeros_for_r_solver()); +} + +void lar_solver::prepare_costs_for_r_solver(const vector> & term) { + + auto & rslv = m_mpq_lar_core_solver.m_r_solver; + rslv.m_using_infeas_costs = false; + lean_assert(costs_are_zeros_for_r_solver()); + lean_assert(reduced_costs_are_zeroes_for_r_solver()); + rslv.m_costs.resize(A_r().column_count(), zero_of_type()); + for (auto & p : term) { + unsigned j = p.second; + rslv.m_costs[j] = p.first; + if (rslv.m_basis_heading[j] < 0) + rslv.m_d[j] += p.first; + else + rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); + } + lean_assert(rslv.reduced_costs_are_correct_tableau()); +} + +bool lar_solver::maximize_term_on_corrected_r_solver(const vector> & term, + impq &term_max) { + settings().backup_costs = false; + switch (settings().simplex_strategy()) { + case simplex_strategy_enum::tableau_rows: + prepare_costs_for_r_solver(term); + settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; + { + bool ret = maximize_term_on_tableau(term, term_max); + settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); + return ret; + } + case simplex_strategy_enum::tableau_costs: + prepare_costs_for_r_solver(term); + { + bool ret = maximize_term_on_tableau(term, term_max); + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); + return ret; + } + + case simplex_strategy_enum::lu: + lean_assert(false); // not implemented + return false; + default: + lean_unreachable(); // wrong mode + } + return false; +} +// starting from a given feasible state look for the maximum of the term +// return true if found and false if unbounded +bool lar_solver::maximize_term(const vector> & term, + impq &term_max) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; + return maximize_term_on_corrected_r_solver(term, term_max); +} + + + +const lar_term & lar_solver::get_term(unsigned j) const { + lean_assert(j >= m_terms_start_index); + return *m_terms[j - m_terms_start_index]; +} + +void lar_solver::pop_core_solver_params() { + pop_core_solver_params(1); +} + +void lar_solver::pop_core_solver_params(unsigned k) { + A_r().pop(k); + A_d().pop(k); +} + + +void lar_solver::set_upper_bound_witness(var_index j, constraint_index ci) { + ul_pair ul = m_vars_to_ul_pairs[j]; + ul.upper_bound_witness() = ci; + m_vars_to_ul_pairs[j] = ul; +} + +void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) { + ul_pair ul = m_vars_to_ul_pairs[j]; + ul.low_bound_witness() = ci; + m_vars_to_ul_pairs[j] = ul; +} + +void lar_solver::register_one_coeff_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j) { + auto it = coeffs.find(j); + if (it == coeffs.end()) { + coeffs[j] = a; + } else { + it->second += a; + } +} + + +void lar_solver::substitute_terms_in_linear_expression(const vector>& left_side_with_terms, + vector> &left_side, mpq & right_side) const { + std::unordered_map coeffs; + for (auto & t : left_side_with_terms) { + unsigned j = t.second; + if (!is_term(j)) { + register_one_coeff_in_map(coeffs, t.first, j); + } else { + const lar_term & term = * m_terms[adjust_term_index(t.second)]; + for (auto & p : term.coeffs()){ + register_one_coeff_in_map(coeffs, t.first * p.second , p.first); + } + right_side += t.first * term.m_v; + } + } + + for (auto & p : coeffs) + left_side.push_back(std::make_pair(p.second, p.first)); +} + + +void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { + if (A_r().row_count() != m_column_buffer.data_size()) + m_column_buffer.resize(A_r().row_count()); + else + m_column_buffer.clear(); + lean_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); + + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + for (unsigned i : m_column_buffer.m_index) + m_rows_with_changed_bounds.insert(i); +} + + + +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); +} + +bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } + +bool lar_solver::use_tableau_costs() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; +} + +void lar_solver::detect_rows_of_column_with_bound_change(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column + // just mark the row at touched and exit + m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + return; + } + + if (use_tableau()) + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + else + detect_rows_of_bound_change_column_for_nbasic_column(j); +} + +void lar_solver::adjust_x_of_column(unsigned j) { + lean_assert(false); +} + +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]; + return is_zero(r); +} + +bool lar_solver::ax_is_correct() const { + for (unsigned i = 0; i < A_r().row_count(); i++) { + if (!row_is_correct(i)) + return false; + } + return true; +} + +bool lar_solver::tableau_with_costs() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; +} + +bool lar_solver::costs_are_used() const { + return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; +} + +void lar_solver::change_basic_x_by_delta_on_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]; + m_mpq_lar_core_solver.m_r_x[bj] -= A_r().get_val(c) * delta; + if (tableau_with_costs()) { + m_basic_columns_with_changed_cost.insert(bj); + } + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); + } + } else { + m_column_buffer.clear(); + m_column_buffer.resize(A_r().row_count()); + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + for (unsigned i : m_column_buffer.m_index) { + unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; + m_mpq_lar_core_solver.m_r_x[bj] -= m_column_buffer[i] * delta; + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); + } + } +} + +void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + if (costs_are_used()) { + bool was_infeas = m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j); + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); + if (was_infeas != m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j)) + m_basic_columns_with_changed_cost.insert(j); + } else { + m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); + } + } else { + numeric_pair delta; + if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) + change_basic_x_by_delta_on_column(j, delta); + } +} + + +void lar_solver::detect_rows_with_changed_bounds_for_column(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + return; + } + + if (use_tableau()) + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + else + detect_rows_of_bound_change_column_for_nbasic_column(j); +} + +void lar_solver::detect_rows_with_changed_bounds() { + for (auto j : m_columns_with_changed_bound.m_index) + detect_rows_with_changed_bounds_for_column(j); +} + +void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds() { + for (auto j : m_columns_with_changed_bound.m_index) + update_x_and_inf_costs_for_column_with_changed_bounds(j); +} + +void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { + lean_assert(ax_is_correct()); + for (auto j : m_columns_with_changed_bound.m_index) + update_x_and_inf_costs_for_column_with_changed_bounds(j); + + if (tableau_with_costs()) { + for (unsigned j : m_basic_columns_with_changed_cost.m_index) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + } +} + + +void lar_solver::solve_with_core_solver() { + if (!use_tableau()) + add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); + if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { + add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); + } + m_mpq_lar_core_solver.prefix_r(); + if (costs_are_used()) { + m_basic_columns_with_changed_cost.clear(); + m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); + } + if (use_tableau()) + update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); + else + update_x_and_inf_costs_for_columns_with_changed_bounds(); + m_mpq_lar_core_solver.solve(); + set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); + lean_assert(m_status != OPTIMAL || all_constraints_hold()); +} + + +numeric_pair lar_solver::get_basic_var_value_from_row_directly(unsigned i) { + numeric_pair r = zero_of_type>(); + + 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 (!is_zero(x)) + r -= c.m_value * x; + } + return r; +} + +numeric_pair lar_solver::get_basic_var_value_from_row(unsigned i) { + if (settings().use_tableau()) { + return get_basic_var_value_from_row_directly(i); + } + + numeric_pair r = zero_of_type>(); + m_mpq_lar_core_solver.calculate_pivot_row(i); + for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; + } + return r; +} + +template +void lar_solver::add_last_rows_to_lu(lp_primal_core_solver & s) { + auto & f = s.m_factorization; + if (f != nullptr) { + auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); + if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { + delete f; + f = nullptr; + } else { + f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); + } + } + if (f == nullptr) { + init_factorization(f, s.m_A, s.m_basis, m_settings); + if (f->get_status() != LU_status::OK) { + delete f; + f = nullptr; + } + } + +} + +bool lar_solver::x_is_correct() const { + if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { + // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; + return false; + } + for (unsigned i = 0; i < A_r().row_count(); i++) { + numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); + if (!delta.is_zero()) { + // std::cout << "x is off ("; + // std::cout << "m_b[" << i << "] = " << m_b[i] << " "; + // std::cout << "left side = " << A().dot_product_with_row(i, m_r_solver.m_x) << ' '; + // std::cout << "delta = " << delta << ' '; + // std::cout << "iters = " << total_iterations() << ")" << std::endl; + // std::cout << "row " << i << " is off" << std::endl; + return false; + } + } + return true;; + +} + +bool lar_solver::var_is_registered(var_index vj) const { + if (vj >= m_terms_start_index) { + if (vj - m_terms_start_index >= m_terms.size()) + return false; + } else if ( vj >= A_r().column_count()) { + return false; + } + return true; +} + +unsigned lar_solver::constraint_stack_size() const { + return m_constraint_count.stack_size(); +} + +void lar_solver::fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { + lean_assert(A.row_count() > 0); + lean_assert(A.column_count() > 0); + unsigned last_row = A.row_count() - 1; + lean_assert(A.m_rows[last_row].size() == 0); + for (auto & t : ls->m_coeffs) { + lean_assert(!is_zero(t.second)); + var_index j = t.first; + A.set(last_row, j, - t.second); + } + unsigned basis_j = A.column_count() - 1; + A.set(last_row, basis_j, mpq(1)); +} + +template +void lar_solver::create_matrix_A(static_matrix & matr) { + lean_assert(false); // not implemented + /* + unsigned m = number_or_nontrivial_left_sides(); + unsigned n = m_vec_of_canonic_left_sides.size(); + if (matr.row_count() == m && matr.column_count() == n) + return; + matr.init_empty_matrix(m, n); + copy_from_mpq_matrix(matr); + */ +} + +template +void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { + matr.m_rows.resize(A_r().row_count()); + 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())); + } + } +} + + +bool lar_solver::try_to_set_fixed(column_info & ci) { + if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { + ci.set_fixed_value(ci.get_upper_bound()); + return true; + } + return false; +} + +column_type lar_solver::get_column_type(const column_info & ci) { + auto ret = ci.get_column_type_no_flipping(); + if (ret == column_type::boxed) { // changing boxed to fixed because of the no span + if (ci.get_low_bound() == ci.get_upper_bound()) + ret = column_type::fixed; + } + return ret; +} + +std::string lar_solver::get_column_name(unsigned j) const { + if (j >= m_terms_start_index) + return std::string("_t") + T_to_string(j); + if (j >= m_columns_to_ext_vars_or_term_indices.size()) + return std::string("_s") + T_to_string(j); + + return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]); +} + +bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { + for (auto it : left_side) { + if (! var_is_registered(it.second)) + return false; + } + return true; +} + +bool lar_solver::all_constraints_hold() const { + if (m_settings.get_cancel_flag()) + return true; + std::unordered_map var_map; + get_model(var_map); + + for (unsigned i = 0; i < m_constraints.size(); i++) { + if (!constraint_holds(*m_constraints[i], var_map)) { + print_constraint(i, std::cout); + return false; + } + } + return true; +} + +bool lar_solver::constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { + mpq left_side_val = get_left_side_val(constr, var_map); + switch (constr.m_kind) { + case LE: return left_side_val <= constr.m_right_side; + case LT: return left_side_val < constr.m_right_side; + case GE: return left_side_val >= constr.m_right_side; + case GT: return left_side_val > constr.m_right_side; + case EQ: return left_side_val == constr.m_right_side; + default: + lean_unreachable(); + } + return false; // it is unreachable +} + +bool lar_solver::the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const { + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lconstraint_kind kind = coeff.is_pos() ? + m_constraints[con_ind]->m_kind : + flip_kind(m_constraints[con_ind]->m_kind); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + } + the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); + if (strict) + the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); + + return n_of_G == 0 || n_of_L == 0; +} + +void lar_solver::register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a) { + for (auto & it : cn.get_left_side_coefficients()) { + unsigned j = it.second; + auto p = coeffs.find(j); + if (p == coeffs.end()) + coeffs[j] = it.first * a; + else { + p->second += it.first * a; + if (p->second.is_zero()) + coeffs.erase(p); + } + } +} + +bool lar_solver::the_left_sides_sum_to_zero(const vector> & evidence) const { + std::unordered_map coeff_map; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + register_in_map(coeff_map, *m_constraints[con_ind], coeff); + } + + if (!coeff_map.empty()) { + std::cout << "left side = "; + vector> t; + for (auto & it : coeff_map) { + t.push_back(std::make_pair(it.second, it.first)); + } + print_linear_combination_of_column_indices(t, std::cout); + std::cout << std::endl; + return false; + } + + return true; +} + +bool lar_solver::the_right_sides_do_not_sum_to_zero(const vector> & evidence) { + mpq ret = numeric_traits::zero(); + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + const lar_constraint & constr = *m_constraints[con_ind]; + ret += constr.m_right_side * coeff; + } + return !numeric_traits::is_zero(ret); +} + +bool lar_solver::explanation_is_correct(const vector>& explanation) const { +#ifdef LEAN_DEBUG + lconstraint_kind kind; + lean_assert(the_relations_are_of_same_type(explanation, kind)); + lean_assert(the_left_sides_sum_to_zero(explanation)); + mpq rs = sum_of_right_sides_of_explanation(explanation); + switch (kind) { + case LE: lean_assert(rs < zero_of_type()); + break; + case LT: lean_assert(rs <= zero_of_type()); + break; + case GE: lean_assert(rs > zero_of_type()); + break; + case GT: lean_assert(rs >= zero_of_type()); + break; + case EQ: lean_assert(rs != zero_of_type()); + break; + default: + lean_assert(false); + return false; + } +#endif + return true; +} + +bool lar_solver::inf_explanation_is_correct() const { +#ifdef LEAN_DEBUG + vector> explanation; + get_infeasibility_explanation(explanation); + return explanation_is_correct(explanation); +#endif + return true; +} + +mpq lar_solver::sum_of_right_sides_of_explanation(const vector> & explanation) const { + mpq ret = numeric_traits::zero(); + for (auto & it : explanation) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lean_assert(con_ind < m_constraints.size()); + ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; + } + return ret; +} + +bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { + + if (var >= m_vars_to_ul_pairs.size()) { + // TBD: bounds on terms could also be used, caller may have to track these. + return false; + } + const ul_pair & ul = m_vars_to_ul_pairs[var]; + ci = ul.low_bound_witness(); + if (ci != static_cast(-1)) { + auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; + value = p.x; + is_strict = p.y.is_pos(); + return true; + } + else { + return false; + } +} + +bool lar_solver::has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { + + if (var >= m_vars_to_ul_pairs.size()) { + // TBD: bounds on terms could also be used, caller may have to track these. + return false; + } + const ul_pair & ul = m_vars_to_ul_pairs[var]; + ci = ul.upper_bound_witness(); + if (ci != static_cast(-1)) { + auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; + value = p.x; + is_strict = p.y.is_neg(); + return true; + } + else { + return false; + } +} + +void lar_solver::get_infeasibility_explanation(vector> & explanation) const { + explanation.clear(); + if (m_infeasible_column_index != -1) { + fill_explanation_from_infeasible_column(explanation); + return; + } + if (m_mpq_lar_core_solver.get_infeasible_sum_sign() == 0) { + return; + } + // the infeasibility sign + int inf_sign; + auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); + get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); + lean_assert(explanation_is_correct(explanation)); +} + + + +void lar_solver::get_infeasibility_explanation_for_inf_sign( + vector> & explanation, + const vector> & inf_row, + int inf_sign) const { + + for (auto & it : inf_row) { + mpq coeff = it.first; + unsigned j = it.second; + + int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; + const ul_pair & ul = m_vars_to_ul_pairs[j]; + + constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); + lean_assert(bound_constr_i < m_constraints.size()); + explanation.push_back(std::make_pair(coeff, bound_constr_i)); + } +} + +void lar_solver::get_model(std::unordered_map & variable_values) const { + mpq delta = mpq(1, 2); // start from 0.5 to have less clashes + lean_assert(m_status == OPTIMAL); + unsigned i; + do { + + // different pairs have to produce different singleton values + std::unordered_set set_of_different_pairs; + std::unordered_set set_of_different_singles; + delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); + for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { + const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; + set_of_different_pairs.insert(rp); + mpq x = rp.x + delta * rp.y; + set_of_different_singles.insert(x); + if (set_of_different_pairs.size() + != set_of_different_singles.size()) { + delta /= mpq(2); + break; + } + + variable_values[i] = x; + } + } while (i != m_mpq_lar_core_solver.m_r_x.size()); +} + +std::string lar_solver::get_variable_name(var_index vi) const { + return get_column_name(vi); +} + +// ********** print region start +void lar_solver::print_constraint(constraint_index ci, std::ostream & out) const { + if (ci >= m_constraints.size()) { + out << "constraint " << T_to_string(ci) << " is not found"; + out << std::endl; + return; + } + + print_constraint(m_constraints[ci], out); +} + +void lar_solver::print_constraints(std::ostream& out) const { + for (auto c : m_constraints) { + print_constraint(c, out); + } +} + +void lar_solver::print_terms(std::ostream& out) const { + for (auto it : m_terms) { + print_term(*it, out); + out << "\n"; + } +} + +void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const { + print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out); + mpq free_coeff = c->get_free_coeff_of_left_side(); + if (!is_zero(free_coeff)) + out << " + " << free_coeff; + +} + +void lar_solver::print_term(lar_term const& term, std::ostream & out) const { + if (!numeric_traits::is_zero(term.m_v)) { + out << term.m_v << " + "; + } + print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); +} + +mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { + mpq ret = cns.get_free_coeff_of_left_side(); + for (auto & it : cns.get_left_side_coefficients()) { + var_index j = it.second; + auto vi = var_map.find(j); + lean_assert(vi != var_map.end()); + ret += it.first * vi->second; + } + return ret; +} + +void lar_solver::print_constraint(const lar_base_constraint * c, std::ostream & out) const { + print_left_side_of_constraint(c, out); + out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; +} + +void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { + for (unsigned i = 0; i < sz; i++) { + var_index var = vars[i]; + if (var >= m_terms_start_index) { // handle the term + for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { + column_list.push_back(it.first); + } + } else { + column_list.push_back(var); + } + } +} + +void lar_solver::random_update(unsigned sz, var_index const * vars) { + vector column_list; + fill_var_set_for_random_update(sz, vars, column_list); + random_updater ru(m_mpq_lar_core_solver, column_list); + ru.update(); +} + + +void lar_solver::pivot_fixed_vars_from_basis() { + m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); +} + +void lar_solver::pop() { + pop(1); +} + +bool lar_solver::column_represents_row_in_tableau(unsigned j) { + return m_vars_to_ul_pairs()[j].m_i != static_cast(-1); +} + +void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { + // i, j - is the indices of the bottom-right element of the tableau + lean_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;){ + auto & cc = last_column[k]; + if (cc.m_i == i) + return; + non_zero_column_cell_index = k; + } + + lean_assert(non_zero_column_cell_index != -1); + lean_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); +} + +void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + auto & slv = m_mpq_lar_core_solver.m_r_solver; + unsigned i = A_r().row_count() - 1; //last row index + make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); + if (slv.m_basis_heading[j] < 0) { + slv.pivot_column_tableau(j, i); + } + + 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;) { + auto &rc = last_row[k]; + if (cost_is_nz) { + m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); + } + + A_r().remove_element(last_row, rc); + } + lean_assert(last_row.size() == 0); + lean_assert(A_r().m_columns[j].size() == 0); + A_r().m_rows.pop_back(); + A_r().m_columns.pop_back(); + slv.m_b.pop_back(); +} + +void lar_solver::remove_last_column_from_tableau(unsigned j) { + lean_assert(j == A_r().column_count() - 1); + // the last column has to be empty + lean_assert(A_r().m_columns[j].size() == 0); + A_r().m_columns.pop_back(); +} + +void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { + auto& rslv = m_mpq_lar_core_solver.m_r_solver; + int i = rslv.m_basis_heading[j]; + if (i >= 0) { // j is a basic var + int last_pos = static_cast(rslv.m_basis.size()) - 1; + lean_assert(last_pos >= 0); + if (i != last_pos) { + unsigned j_at_last_pos = rslv.m_basis[last_pos]; + rslv.m_basis[i] = j_at_last_pos; + rslv.m_basis_heading[j_at_last_pos] = i; + } + rslv.m_basis.pop_back(); // remove j from the basis + } else { + int last_pos = static_cast(rslv.m_nbasis.size()) - 1; + lean_assert(last_pos >= 0); + i = - 1 - i; + if (i != last_pos) { + unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; + rslv.m_nbasis[i] = j_at_last_pos; + rslv.m_basis_heading[j_at_last_pos] = - i - 1; + } + rslv.m_nbasis.pop_back(); // remove j from the basis + } + rslv.m_basis_heading.pop_back(); + lean_assert(rslv.m_basis.size() == A_r().row_count()); + lean_assert(rslv.basis_heading_is_correct()); +} + +void lar_solver::remove_column_from_tableau(unsigned j) { + auto& rslv = m_mpq_lar_core_solver.m_r_solver; + lean_assert(j == A_r().column_count() - 1); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + if (column_represents_row_in_tableau(j)) { + remove_last_row_and_column_from_tableau(j); + if (rslv.m_basis_heading[j] < 0) + rslv.change_basis_unconditionally(j, rslv.m_basis[A_r().row_count()]); // A_r().row_count() is the index of the last row in the basis still + } + else { + remove_last_column_from_tableau(j); + } + rslv.m_x.pop_back(); + rslv.m_d.pop_back(); + rslv.m_costs.pop_back(); + + remove_last_column_from_basis_tableau(j); + lean_assert(m_mpq_lar_core_solver.r_basis_is_OK()); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); +} + +void lar_solver::pop_tableau() { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). + // At this moment m_column_names is already popped + for (unsigned j = A_r().column_count(); j-- > m_columns_to_ext_vars_or_term_indices.size();) + remove_column_from_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); +} + +void lar_solver::clean_inf_set_of_r_solver_after_pop() { + vector became_feas; + clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); + std::unordered_set basic_columns_with_changed_cost; + auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; + for (auto j: inf_index_copy) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + continue; + } + // some basic columns might become non-basic - these columns need to be made feasible + numeric_pair delta; + if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) + change_basic_x_by_delta_on_column(j, delta); + became_feas.push_back(j); + } + + for (unsigned j : became_feas) { + lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; + m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); + m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); + } + became_feas.clear(); + for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { + lean_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); + if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) + became_feas.push_back(j); + } + for (unsigned j : became_feas) + m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); + + + if (use_tableau_costs()) { + for (unsigned j : became_feas) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + for (unsigned j : basic_columns_with_changed_cost) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + } +} + +void lar_solver::shrink_explanation_to_minimum(vector> & explanation) const { + // implementing quickXplain + quick_xplain::run(explanation, *this); + lean_assert(this->explanation_is_correct(explanation)); +} + +bool lar_solver::model_is_int_feasible() const { + unsigned n = A_r().column_count(); + for (unsigned j = 0; j < n; j++) { + if (column_is_int(j) && !column_value_is_integer(j)) + return false; + } + return true; +} + +bool lar_solver::term_is_int(const lar_term * t) const { + for (auto const & p : t->m_coeffs) + if (!column_is_int(p.first) || p.second.is_int()) + return false; + return t->m_v.is_int(); +} + +bool lar_solver::var_is_int(var_index v) const { + if (is_term(v)) { + lar_term const& t = get_term(v); + return term_is_int(&t); + } + else { + return column_is_int(v); + } +} + +bool lar_solver::column_is_int(unsigned j) const { + unsigned ext_var = m_columns_to_ext_vars_or_term_indices[j]; + lean_assert(contains(m_ext_vars_to_columns, ext_var)); + return m_ext_vars_to_columns.find(ext_var)->second.is_integer(); +} + +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 { + auto it = m_ext_vars_to_columns.find(ext_var); + lean_assert(it != m_ext_vars_to_columns.end()); + return it == m_ext_vars_to_columns.end() || it->second.is_integer(); +} + + // below is the initialization functionality of lar_solver + +bool lar_solver::strategy_is_undecided() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; +} + +var_index lar_solver::add_var(unsigned ext_j, bool is_int) { + TRACE("add_var", tout << "adding var " << ext_j << (is_int? " int" : " nonint") << std::endl;); + var_index i; + lean_assert(ext_j < m_terms_start_index); + + if (ext_j >= m_terms_start_index) + throw 0; // todo : what is the right way to exit? + auto it = m_ext_vars_to_columns.find(ext_j); + if (it != m_ext_vars_to_columns.end()) { + return it->second.ext_j(); + } + lean_assert(m_vars_to_ul_pairs.size() == A_r().column_count()); + i = A_r().column_count(); + m_vars_to_ul_pairs.push_back(ul_pair(static_cast(-1))); + add_non_basic_var_to_core_fields(ext_j, is_int); + lean_assert(sizes_are_correct()); + return i; +} + +void lar_solver::register_new_ext_var_index(unsigned ext_v, bool is_int) { + lean_assert(!contains(m_ext_vars_to_columns, ext_v)); + unsigned j = static_cast(m_ext_vars_to_columns.size()); + m_ext_vars_to_columns.insert(std::make_pair(ext_v, ext_var_info(j, is_int))); + lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j); + m_columns_to_ext_vars_or_term_indices.push_back(ext_v); +} + +void lar_solver::add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int) { + register_new_ext_var_index(ext_j, is_int); + m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); + m_columns_with_changed_bound.increase_size_by_one(); + add_new_var_to_core_fields_for_mpq(false); + if (use_lu()) + add_new_var_to_core_fields_for_doubles(false); +} + +void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) { + unsigned j = A_d().column_count(); + A_d().add_column(); + lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); + // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_d_x.resize(j + 1); + m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); + lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_d().add_row(); + m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); + m_mpq_lar_core_solver.m_d_basis.push_back(j); + } + else { + m_mpq_lar_core_solver.m_d_heading.push_back(-static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_d_nbasis.push_back(j); + } +} + +void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) { + unsigned j = A_r().column_count(); + A_r().add_column(); + lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j); + // lean_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_r_x.resize(j + 1); + m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); + m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); + lean_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_r().add_row(); + m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); + m_mpq_lar_core_solver.m_r_basis.push_back(j); + if (m_settings.bound_propagation()) + m_rows_with_changed_bounds.insert(A_r().row_count() - 1); + } + else { + m_mpq_lar_core_solver.m_r_heading.push_back(-static_cast(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_r_nbasis.push_back(j); + } +} + + +var_index lar_solver::add_term_undecided(const vector> & coeffs, + const mpq &m_v) { + m_terms.push_back(new lar_term(coeffs, m_v)); + return m_terms_start_index + m_terms.size() - 1; +} + +// terms +var_index lar_solver::add_term(const vector> & coeffs, + const mpq &m_v) { + if (strategy_is_undecided()) + return add_term_undecided(coeffs, m_v); + + m_terms.push_back(new lar_term(coeffs, m_v)); + unsigned adjusted_term_index = m_terms.size() - 1; + var_index ret = m_terms_start_index + adjusted_term_index; + if (use_tableau() && !coeffs.empty()) { + add_row_for_term(m_terms.back(), ret); + if (m_settings.bound_propagation()) + m_rows_with_changed_bounds.insert(A_r().row_count() - 1); + } + lean_assert(m_ext_vars_to_columns.size() == A_r().column_count()); + return ret; +} + +void lar_solver::add_row_for_term(const lar_term * term, unsigned term_ext_index) { + lean_assert(sizes_are_correct()); + add_row_from_term_no_constraint(term, term_ext_index); + lean_assert(sizes_are_correct()); +} + +void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { + register_new_ext_var_index(term_ext_index, term_is_int(term)); + // j will be a new variable + unsigned j = A_r().column_count(); + ul_pair ul(j); + m_vars_to_ul_pairs.push_back(ul); + add_basic_var_to_core_fields(); + if (use_tableau()) { + auto it = iterator_on_term_with_basis_var(*term, j); + A_r().fill_last_row_with_pivoting(it, + m_mpq_lar_core_solver.m_r_solver.m_basis_heading); + m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type()); + } + else { + fill_last_row_of_A_r(A_r(), term); + } + m_mpq_lar_core_solver.m_r_x[j] = get_basic_var_value_from_row_directly(A_r().row_count() - 1); + if (use_lu()) + fill_last_row_of_A_d(A_d(), term); +} + +void lar_solver::add_basic_var_to_core_fields() { + bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); + lean_assert(!use_lu || A_r().column_count() == A_d().column_count()); + m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); + m_columns_with_changed_bound.increase_size_by_one(); + m_rows_with_changed_bounds.increase_size_by_one(); + add_new_var_to_core_fields_for_mpq(true); + if (use_lu) + add_new_var_to_core_fields_for_doubles(true); +} + +bool lar_solver::bound_is_integer_if_needed(unsigned j, const mpq & right_side) const { + if (!column_is_int(j)) + return true; + return right_side.is_int(); +} + +constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { + constraint_index ci = m_constraints.size(); + if (!is_term(j)) { // j is a var + lean_assert(bound_is_integer_if_needed(j, right_side)); + auto vc = new lar_var_constraint(j, kind, right_side); + m_constraints.push_back(vc); + update_column_type_and_bound(j, kind, right_side, ci); + } + else { + add_var_bound_on_constraint_for_term(j, kind, right_side, ci); + } + lean_assert(sizes_are_correct()); + return ci; +} + +void lar_solver::update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { + switch (m_mpq_lar_core_solver.m_column_types[j]) { + case column_type::free_column: + update_free_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::boxed: + update_boxed_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::low_bound: + update_low_bound_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::upper_bound: + update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::fixed: + update_fixed_column_type_and_bound(j, kind, right_side, constr_index); + break; + default: + lean_assert(false); // cannot be here + } +} + +void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lean_assert(is_term(j)); + unsigned adjusted_term_index = adjust_term_index(j); + lean_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int()); + auto it = m_ext_vars_to_columns.find(j); + if (it != m_ext_vars_to_columns.end()) { + unsigned term_j = it->second.ext_j(); + mpq rs = right_side - m_terms[adjusted_term_index]->m_v; + m_constraints.push_back(new lar_term_constraint(m_terms[adjusted_term_index], kind, right_side)); + update_column_type_and_bound(term_j, kind, rs, ci); + } + else { + add_constraint_from_term_and_create_new_column_row(j, m_terms[adjusted_term_index], kind, right_side); + } +} + +constraint_index lar_solver::add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { + vector> left_side; + mpq rs = -right_side_parm; + substitute_terms_in_linear_expression(left_side_with_terms, left_side, rs); + unsigned term_index = add_term(left_side, zero_of_type()); + constraint_index ci = m_constraints.size(); + add_var_bound_on_constraint_for_term(term_index, kind_par, -rs, ci); + return ci; +} + +void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, + lconstraint_kind kind, const mpq & right_side) { + + add_row_from_term_no_constraint(term, term_j); + unsigned j = A_r().column_count() - 1; + update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size()); + m_constraints.push_back(new lar_term_constraint(term, kind, right_side)); + lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); +} + +void lar_solver::decide_on_strategy_and_adjust_initial_state() { + lean_assert(strategy_is_undecided()); + if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { + m_settings.simplex_strategy() = simplex_strategy_enum::lu; + } + else { + m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs? + } + adjust_initial_state(); +} + +void lar_solver::adjust_initial_state() { + switch (m_settings.simplex_strategy()) { + case simplex_strategy_enum::lu: + adjust_initial_state_for_lu(); + break; + case simplex_strategy_enum::tableau_rows: + adjust_initial_state_for_tableau_rows(); + break; + case simplex_strategy_enum::tableau_costs: + lean_assert(false); // not implemented + case simplex_strategy_enum::undecided: + adjust_initial_state_for_tableau_rows(); + break; + } +} + +void lar_solver::adjust_initial_state_for_lu() { + copy_from_mpq_matrix(A_d()); + unsigned n = A_d().column_count(); + m_mpq_lar_core_solver.m_d_x.resize(n); + m_mpq_lar_core_solver.m_d_low_bounds.resize(n); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); + m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; + m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; + + /* + unsigned j = A_d().column_count(); + A_d().add_column(); + lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); + // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); + m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); + lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_d().add_row(); + m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); + m_mpq_lar_core_solver.m_d_basis.push_back(j); + }else { + m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_d_nbasis.push_back(j); + }*/ +} + +void lar_solver::adjust_initial_state_for_tableau_rows() { + for (unsigned j = 0; j < m_terms.size(); j++) { + if (contains(m_ext_vars_to_columns, j + m_terms_start_index)) + continue; + add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index); + } +} + +// this fills the last row of A_d and sets the basis column: -1 in the last column of the row +void lar_solver::fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { + lean_assert(A.row_count() > 0); + lean_assert(A.column_count() > 0); + unsigned last_row = A.row_count() - 1; + lean_assert(A.m_rows[last_row].empty()); + + for (auto & t : ls->m_coeffs) { + lean_assert(!is_zero(t.second)); + var_index j = t.first; + A.set(last_row, j, -t.second.get_double()); + } + + unsigned basis_j = A.column_count() - 1; + A.set(last_row, basis_j, -1); +} + +void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; + lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + { + auto up = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + } + set_upper_bound_witness(j, constr_ind); + break; + case GT: + y_of_bound = 1; + case GE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound; + lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + { + auto low = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + } + set_low_bound_witness(j, constr_ind); + break; + case EQ: + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair(right_side, zero_of_type()); + set_upper_bound_witness(j, constr_ind); + set_low_bound_witness(j, constr_ind); + break; + + default: + lean_unreachable(); + + } + m_columns_with_changed_bound.insert(j); +} + +void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + if (up < m_mpq_lar_core_solver.m_r_upper_bounds()[j]) { + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + } + } + break; + case GT: + y_of_bound = 1; + case GE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed; + { + auto low = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + set_low_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + } + else { + m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j] ? column_type::boxed : column_type::fixed; + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + set_low_bound_witness(j, ci); + m_infeasible_column_index = j; + } + else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + break; + } + break; + + default: + lean_unreachable(); + + } +} + +void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + } + + if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + lean_assert(false); + m_infeasible_column_index = j; + } + else { + if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]) + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + } + break; + case GT: + y_of_bound = 1; + case GE: + { + auto low = numeric_pair(right_side, y_of_bound); + if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + } + if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + } + else if (low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + m_columns_with_changed_bound.insert(j); + } + + break; + } + + default: + lean_unreachable(); + + } +} +void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + + if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + } + else { + m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j] ? column_type::boxed : column_type::fixed; + } + } + break; + case GT: + y_of_bound = 1; + case GE: + { + auto low = numeric_pair(right_side, y_of_bound); + if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + m_columns_with_changed_bound.insert(j); + break; + } + + default: + lean_unreachable(); + + } +} + +void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); + auto v = numeric_pair(right_side, mpq(0)); + + mpq y_of_bound(0); + switch (kind) { + case LT: + if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + break; + case LE: + { + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + } + break; + case GT: + { + if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + } + break; + case GE: + { + if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + } + break; + case EQ: + { + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + break; + } + + default: + lean_unreachable(); + + } +} + + +} // namespace lean + + diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index b74515566..dbccbc9cf 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -30,1520 +30,421 @@ #include "util/lp/iterator_on_row.h" #include "util/lp/quick_xplain.h" #include "util/lp/conversion_helper.h" +#include "util/lp/int_solver.h" +#include "util/lp/nra_solver.h" + namespace lean { + class lar_solver : public column_namer { + class ext_var_info { + unsigned m_ext_j; // the external index + bool m_is_integer; + public: + ext_var_info(unsigned j): ext_var_info(j, false) {} + ext_var_info(unsigned j , bool is_int) : m_ext_j(j), m_is_integer(is_int) {} + unsigned ext_j() const { return m_ext_j;} + bool is_integer() const {return m_is_integer;} + }; //////////////////// fields ////////////////////////// - lp_settings m_settings; - stacked_value m_status; - stacked_value m_simplex_strategy; - std::unordered_map m_ext_vars_to_columns; - vector m_columns_to_ext_vars_or_term_indices; - stacked_vector m_vars_to_ul_pairs; - vector m_constraints; - stacked_value m_constraint_count; + lp_settings m_settings; + stacked_value m_status; + stacked_value m_simplex_strategy; + std::unordered_map m_ext_vars_to_columns; + vector m_columns_to_ext_vars_or_term_indices; + stacked_vector m_vars_to_ul_pairs; + vector m_constraints; + stacked_value m_constraint_count; // the set of column indices j such that bounds have changed for j - int_set m_columns_with_changed_bound; - int_set m_rows_with_changed_bounds; - int_set m_basic_columns_with_changed_cost; - stacked_value m_infeasible_column_index; // such can be found at the initialization step - stacked_value m_term_count; - vector m_terms; - vector m_orig_terms; - const var_index m_terms_start_index; - indexed_vector m_column_buffer; + int_set m_columns_with_changed_bound; + int_set m_rows_with_changed_bounds; + int_set m_basic_columns_with_changed_cost; + stacked_value m_infeasible_column_index; // such can be found at the initialization step + stacked_value m_term_count; + vector m_terms; + const var_index m_terms_start_index; + indexed_vector m_column_buffer; public: lar_core_solver m_mpq_lar_core_solver; - unsigned constraint_count() const { - return m_constraints.size(); - } - const lar_base_constraint& get_constraint(unsigned ci) const { - return *(m_constraints[ci]); - } + unsigned constraint_count() const; + const lar_base_constraint& get_constraint(unsigned ci) const; ////////////////// methods //////////////////////////////// - static_matrix> & A_r() { return m_mpq_lar_core_solver.m_r_A;} - static_matrix> const & A_r() const { return m_mpq_lar_core_solver.m_r_A;} - static_matrix & A_d() { return m_mpq_lar_core_solver.m_d_A;} - static_matrix const & A_d() const { return m_mpq_lar_core_solver.m_d_A;} + static_matrix> & A_r(); + static_matrix> const & A_r() const; + static_matrix & A_d(); + static_matrix const & A_d() const; static bool valid_index(unsigned j){ return static_cast(j) >= 0;} - + bool column_is_int(unsigned j) const; + bool column_is_fixed(unsigned j) const; public: - lp_settings & settings() { return m_settings;} - lp_settings const & settings() const { return m_settings;} + // init region + bool strategy_is_undecided() const; - void clear() {lean_assert(false); // not implemented - } + var_index add_var(unsigned ext_j, bool is_integer); + void register_new_ext_var_index(unsigned ext_v, bool is_int); - lar_solver() : m_status(OPTIMAL), - m_infeasible_column_index(-1), - m_terms_start_index(1000000), - m_mpq_lar_core_solver(m_settings, *this) - {} + bool term_is_int(const lar_term * t) const; + + bool var_is_int(var_index v) const; + + bool ext_var_is_int(var_index ext_var) const; - void set_propagate_bounds_on_pivoted_rows_mode(bool v) { - m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; - } + void add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int); - virtual ~lar_solver(){ - for (auto c : m_constraints) - delete c; - for (auto t : m_terms) - delete t; - for (auto t : m_orig_terms) - delete t; - } + void add_new_var_to_core_fields_for_doubles(bool register_in_basis); -#include "util/lp/init_lar_solver.h" + void add_new_var_to_core_fields_for_mpq(bool register_in_basis); + + + var_index add_term_undecided(const vector> & coeffs, + const mpq &m_v); + + // terms + var_index add_term(const vector> & coeffs, + const mpq &m_v); + + void add_row_for_term(const lar_term * term, unsigned term_ext_index); + + void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index); + + void add_basic_var_to_core_fields(); + + constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) ; + + void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index); + + void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); + + + void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, + lconstraint_kind kind, const mpq & right_side); + + void decide_on_strategy_and_adjust_initial_state(); + + void adjust_initial_state(); + + void adjust_initial_state_for_lu(); + + void adjust_initial_state_for_tableau_rows(); + + // this fills the last row of A_d and sets the basis column: -1 in the last column of the row + void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls); + + void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind); + + void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); - numeric_pair const& get_value(var_index vi) const { return m_mpq_lar_core_solver.m_r_x[vi]; } + void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); + void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); - bool is_term(var_index j) const { - return j >= m_terms_start_index && j - m_terms_start_index < m_terms.size(); - } + void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci); + //end of init region + lp_settings & settings(); - unsigned adjust_term_index(unsigned j) const { - lean_assert(is_term(j)); - return j - m_terms_start_index; - } + lp_settings const & settings() const; + + void clear(); - bool use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } - - bool sizes_are_correct() const { - lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); - return true; - } + lar_solver(); + void set_propagate_bounds_on_pivoted_rows_mode(bool v); + + virtual ~lar_solver(); + + numeric_pair const& get_value(var_index vi) const; + + bool is_term(var_index j) const; + + unsigned adjust_term_index(unsigned j) const; + + + bool use_lu() const; + bool sizes_are_correct() const; - void print_implied_bound(const implied_bound& be, std::ostream & out) const { - out << "implied bound\n"; - unsigned v = be.m_j; - if (is_term(v)) { - out << "it is a term number " << be.m_j << std::endl; - print_term(*m_orig_terms[be.m_j - m_terms_start_index], out); - } - else { - out << get_column_name(v); - } - out << " " << lconstraint_kind_string(be.kind()) << " " << be.m_bound << std::endl; - // for (auto & p : be.m_explanation) { - // out << p.first << " : "; - // print_constraint(p.second, out); - // } - - // m_mpq_lar_core_solver.m_r_solver.print_column_info(be.m_j< m_terms_start_index? be.m_j : adjust_term_index(be.m_j), out); - out << "end of implied bound" << std::endl; - } + void print_implied_bound(const implied_bound& be, std::ostream & out) const; - bool implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { - std::unordered_map coeff_map; - auto rs_of_evidence = zero_of_type(); - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto & it : explanation) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - const auto & constr = *m_constraints[con_ind]; - lconstraint_kind kind = coeff.is_pos() ? constr.m_kind : flip_kind(constr.m_kind); - register_in_map(coeff_map, constr, coeff); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) n_of_G++; - else if (kind == LE || kind == LT) n_of_L++; - rs_of_evidence += coeff*constr.m_right_side; - } - lean_assert(n_of_G == 0 || n_of_L == 0); - lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - kind = static_cast((static_cast(kind) / 2)); - - if (!is_term(be.m_j)) { - if (coeff_map.size() != 1) - return false; - auto it = coeff_map.find(be.m_j); - if (it == coeff_map.end()) return false; - mpq ratio = it->second; - if (ratio < zero_of_type()) { - kind = static_cast(-kind); - } - rs_of_evidence /= ratio; - } else { - const lar_term * t = m_orig_terms[adjust_term_index(be.m_j)]; - const auto first_coeff = *t->m_coeffs.begin(); - unsigned j = first_coeff.first; - auto it = coeff_map.find(j); - if (it == coeff_map.end()) - return false; - mpq ratio = it->second / first_coeff.second; - for (auto & p : t->m_coeffs) { - it = coeff_map.find(p.first); - if (it == coeff_map.end()) - return false; - if (p.second * ratio != it->second) - return false; - } - if (ratio < zero_of_type()) { - kind = static_cast(-kind); - } - rs_of_evidence /= ratio; - rs_of_evidence += t->m_v * ratio; - } - - return kind == be.kind() && rs_of_evidence == be.m_bound; - } - + bool implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const; void analyze_new_bounds_on_row( unsigned row_index, - bound_propagator & bp) { - lean_assert(!use_tableau()); - iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); - - bound_analyzer_on_row ra_pos(it, - zero_of_type>(), - row_index, - bp - ); - ra_pos.analyze(); - } + bound_propagator & bp); void 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) - return; - iterator_on_row it(A_r().m_rows[row_index]); - lean_assert(use_tableau()); - bound_analyzer_on_row::analyze_row(it, - zero_of_type>(), - row_index, - bp ); - } - void substitute_basis_var_in_terms_for_row(unsigned i) { - // todo : create a map from term basic vars to the rows where they are used - unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; - for (unsigned k = 0; k < m_terms.size(); k++) { - if (term_is_used_as_row(k)) - continue; - if (!m_terms[k]->contains(basis_j)) - continue; - m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); - } - } + void substitute_basis_var_in_terms_for_row(unsigned i); - void calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { - if(use_tableau()) { - analyze_new_bounds_on_row_tableau(i, bp); - } else { - m_mpq_lar_core_solver.calculate_pivot_row(i); - substitute_basis_var_in_terms_for_row(i); - analyze_new_bounds_on_row(i, bp); - } - } + void calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp); - /* - void process_new_implied_evidence_for_low_bound( - implied_bound_explanation& implied_evidence, // not pushed yet - vector & bound_evidences, - std::unordered_map & improved_low_bounds) { - - unsigned existing_index; - if (try_get_val(improved_low_bounds, implied_evidence.m_j, existing_index)) { - // we are improving the existent bound - bound_evidences[existing_index] = fill_bound_evidence(implied_evidence); - } else { - improved_low_bounds[implied_evidence.m_j] = bound_evidences.size(); - bound_evidences.push_back(fill_bound_evidence(implied_evidence)); - } - } - - void fill_bound_evidence_on_term(implied_bound & ie, implied_bound& be) { - lean_assert(false); - } - void fill_implied_bound_on_row(implied_bound & ie, implied_bound& be) { - iterator_on_row it(A_r().m_rows[ie.m_row_or_term_index]); - mpq a; unsigned j; - bool toggle = ie.m_coeff_before_j_is_pos; - if (!ie.m_is_low_bound) - toggle = !toggle; - while (it.next(a, j)) { - if (j == ie.m_j) continue; - const ul_pair & ul = m_vars_to_ul_pairs[j]; - - if (is_neg(a)) { // so the monoid has a positive coeff on the right side - constraint_index witness = toggle ? ul.m_low_bound_witness : ul.m_upper_bound_witness; - lean_assert(is_valid(witness)); - be.m_explanation.emplace_back(a, witness); - } - } - } - */ - /* - implied_bound fill_implied_bound_for_low_bound(implied_bound& ie) { - implied_bound be(ie.m_j, ie.m_bound.y.is_zero() ? GE : GT, ie.m_bound.x); - if (is_term(ie.m_row_or_term_index)) { - fill_implied_bound_for_low_bound_on_term(ie, be); - } - else { - fill_implied_bound_for_low_bound_on_row(ie, be); - } - return be; - } - - implied_bound fill_implied_bound_for_upper_bound(implied_bound& implied_evidence) { - lean_assert(false); - - be.m_j = implied_evidence.m_j; - be.m_bound = implied_evidence.m_bound.x; - be.m_kind = implied_evidence.m_bound.y.is_zero() ? LE : LT; - for (auto t : implied_evidence.m_vector_of_bound_signatures) { - const ul_pair & ul = m_vars_to_ul_pairs[t.m_column_index]; - constraint_index witness = t.m_low_bound ? ul.m_low_bound_witness : ul.m_upper_bound_witness; - lean_assert(is_valid(witness)); - be.m_explanation.emplace_back(t.m_coeff, witness); - } - - } - */ - /* - void process_new_implied_evidence_for_upper_bound( - implied_bound& implied_evidence, - vector & implied_bounds, - std::unordered_map & improved_upper_bounds) { - unsigned existing_index; - if (try_get_val(improved_upper_bounds, implied_evidence.m_j, existing_index)) { - implied_bound & be = implied_bounds[existing_index]; - be.m_explanation.clear(); - // we are improving the existent bound improve the existing bound - be = fill_implied_bound_for_upper_bound(implied_evidence); - } else { - improved_upper_bounds[implied_evidence.m_j] = implied_bounds.size(); - implied_bounds.push_back(fill_implied_bound_for_upper_bound(implied_evidence)); - } - } - */ - // implied_bound * get_existing_ - linear_combination_iterator * create_new_iter_from_term(unsigned term_index) const { - lean_assert(false); // not implemented - return nullptr; - // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); - } + linear_combination_iterator * create_new_iter_from_term(unsigned term_index) const; - unsigned adjust_column_index_to_term_index(unsigned j) const { - unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; - return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; - } + unsigned adjust_column_index_to_term_index(unsigned j) const; - void propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { - lean_assert(false); // not implemented - } + void propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset); - void explain_implied_bound(implied_bound & ib, bound_propagator & bp) { - unsigned i = ib.m_row_or_term_index; - int bound_sign = ib.m_is_low_bound? 1: -1; - int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; - unsigned m_j = ib.m_j; - if (is_term(m_j)) { - m_j = m_ext_vars_to_columns[m_j]; - } - for (auto const& r : A_r().m_rows[i]) { - unsigned j = r.m_j; - mpq const& a = r.get_val(); - if (j == m_j) continue; - if (is_term(j)) { - j = m_ext_vars_to_columns[j]; - } - int a_sign = is_pos(a)? 1: -1; - int sign = j_sign * a_sign; - const ul_pair & ul = m_vars_to_ul_pairs[j]; - auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); - lean_assert(is_valid(witness)); - bp.consume(a, witness); - } - // lean_assert(implied_bound_is_correctly_explained(ib, explanation)); - } + void explain_implied_bound(implied_bound & ib, bound_propagator & bp); - bool term_is_used_as_row(unsigned term) const { - lean_assert(is_term(term)); - return contains(m_ext_vars_to_columns, term); - } + bool term_is_used_as_row(unsigned term) const; - void propagate_bounds_on_terms(bound_propagator & bp) { - for (unsigned i = 0; i < m_terms.size(); i++) { - if (term_is_used_as_row(i + m_terms_start_index)) - continue; // this term is used a left side of a constraint, - // it was processed as a touched row if needed - propagate_bounds_on_a_term(*m_terms[i], bp, i); - } - } + void propagate_bounds_on_terms(bound_propagator & bp); // goes over touched rows and tries to induce bounds - void propagate_bounds_for_touched_rows(bound_propagator & bp) { - if (!use_tableau()) - return; // ! todo : enable bound propagaion here. The current bug is that after the pop - // the changed terms become incorrect! + void propagate_bounds_for_touched_rows(bound_propagator & bp); - for (unsigned i : m_rows_with_changed_bounds.m_index) { - calculate_implied_bounds_for_row(i, bp); - } - m_rows_with_changed_bounds.clear(); - if (!use_tableau()) { - propagate_bounds_on_terms(bp); - } - } + lp_status get_status() const; - lp_status get_status() const { return m_status;} + void set_status(lp_status s); - void set_status(lp_status s) {m_status = s;} - - lp_status find_feasible_solution() { - if (strategy_is_undecided()) - decide_on_strategy_and_adjust_initial_state(); - - m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; - return solve(); - } + lp_status find_feasible_solution(); - lp_status solve() { - if (m_status == INFEASIBLE) { - return m_status; - } - solve_with_core_solver(); - if (m_status != INFEASIBLE) { - if (m_settings.bound_propagation()) - detect_rows_with_changed_bounds(); - } - - m_columns_with_changed_bound.clear(); - return m_status; - } + lp_status solve(); - void fill_explanation_from_infeasible_column(vector> & evidence) const{ - - // this is the case when the lower bound is in conflict with the upper one - const ul_pair & ul = m_vars_to_ul_pairs[m_infeasible_column_index]; - evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); - evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); - } + void fill_explanation_from_infeasible_column(explanation_t & evidence) const; - unsigned get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } + unsigned get_total_iterations() const; // see http://research.microsoft.com/projects/z3/smt07.pdf // This method searches for a feasible solution with as many different values of variables, reverenced in vars, as it can find // Attention, after a call to this method the non-basic variables don't necesserarly stick to their bounds anymore - vector get_list_of_all_var_indices() const { - vector ret; - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) - ret.push_back(j); - return ret; - } - void push() { - m_simplex_strategy = m_settings.simplex_strategy(); - m_simplex_strategy.push(); - m_status.push(); - m_vars_to_ul_pairs.push(); - m_infeasible_column_index.push(); - m_mpq_lar_core_solver.push(); - m_term_count = m_terms.size(); - m_term_count.push(); - m_constraint_count = m_constraints.size(); - m_constraint_count.push(); - } + vector get_list_of_all_var_indices() const; + void push(); - static void clean_large_elements_after_pop(unsigned n, int_set& set) { - vector to_remove; - for (unsigned j: set.m_index) - if (j >= n) - to_remove.push_back(j); - for (unsigned j : to_remove) - set.erase(j); - } + static void clean_large_elements_after_pop(unsigned n, int_set& set); - static void shrink_inf_set_after_pop(unsigned n, int_set & set) { - clean_large_elements_after_pop(n, set); - set.resize(n); - } + static void shrink_inf_set_after_pop(unsigned n, int_set & set); - void pop(unsigned k) { - int n_was = static_cast(m_ext_vars_to_columns.size()); - m_status.pop(k); - m_infeasible_column_index.pop(k); - unsigned n = m_vars_to_ul_pairs.peek_size(k); - for (unsigned j = n_was; j-- > n;) - m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); - m_columns_to_ext_vars_or_term_indices.resize(n); - if (m_settings.use_tableau()) { - pop_tableau(); - } - m_vars_to_ul_pairs.pop(k); - - m_mpq_lar_core_solver.pop(k); - clean_large_elements_after_pop(n, m_columns_with_changed_bound); - unsigned m = A_r().row_count(); - clean_large_elements_after_pop(m, m_rows_with_changed_bounds); - clean_inf_set_of_r_solver_after_pop(); - lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || - (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - - - lean_assert(ax_is_correct()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); - m_constraint_count.pop(k); - for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) - delete m_constraints[i]; - - m_constraints.resize(m_constraint_count); - m_term_count.pop(k); - for (unsigned i = m_term_count; i < m_terms.size(); i++) { - delete m_terms[i]; - delete m_orig_terms[i]; - } - m_terms.resize(m_term_count); - m_orig_terms.resize(m_term_count); - m_simplex_strategy.pop(k); - m_settings.simplex_strategy() = m_simplex_strategy; - lean_assert(sizes_are_correct()); - lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } + void pop(unsigned k); - vector get_all_constraint_indices() const { - vector ret; - constraint_index i = 0; - while ( i < m_constraints.size()) - ret.push_back(i++); - return ret; - } + vector get_all_constraint_indices() const; bool maximize_term_on_tableau(const vector> & term, - impq &term_max) { - if (settings().simplex_strategy() == simplex_strategy_enum::undecided) - decide_on_strategy_and_adjust_initial_state(); - - m_mpq_lar_core_solver.solve(); - if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED) - return false; + impq &term_max); - term_max = 0; - for (auto & p : term) - term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second]; - - return true; - } - - bool costs_are_zeros_for_r_solver() const { - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); - } - return true; - } - bool reduced_costs_are_zeroes_for_r_solver() const { - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); - } - return true; - } + bool costs_are_zeros_for_r_solver() const; + bool reduced_costs_are_zeroes_for_r_solver() const; - void set_costs_to_zero(const vector> & term) { - auto & rslv = m_mpq_lar_core_solver.m_r_solver; - auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now - lean_assert(jset.m_index.size()==0); - - for (auto & p : term) { - unsigned j = p.second; - rslv.m_costs[j] = zero_of_type(); - int i = rslv.m_basis_heading[j]; - if (i < 0) - jset.insert(j); - else { - for (auto & rc : A_r().m_rows[i]) - jset.insert(rc.m_j); - } - } + void set_costs_to_zero(const vector> & term); - for (unsigned j : jset.m_index) - rslv.m_d[j] = zero_of_type(); - - jset.clear(); - - lean_assert(reduced_costs_are_zeroes_for_r_solver()); - lean_assert(costs_are_zeros_for_r_solver()); - } - - void prepare_costs_for_r_solver(const vector> & term) { - - auto & rslv = m_mpq_lar_core_solver.m_r_solver; - rslv.m_using_infeas_costs = false; - lean_assert(costs_are_zeros_for_r_solver()); - lean_assert(reduced_costs_are_zeroes_for_r_solver()); - rslv.m_costs.resize(A_r().column_count(), zero_of_type()); - for (auto & p : term) { - unsigned j = p.second; - rslv.m_costs[j] = p.first; - if (rslv.m_basis_heading[j] < 0) - rslv.m_d[j] += p.first; - else - rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); - } - lean_assert(rslv.reduced_costs_are_correct_tableau()); - } + void prepare_costs_for_r_solver(const vector> & term); bool maximize_term_on_corrected_r_solver(const vector> & term, - impq &term_max) { - settings().backup_costs = false; - switch (settings().simplex_strategy()) { - case simplex_strategy_enum::tableau_rows: - prepare_costs_for_r_solver(term); - settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; - { - bool ret = maximize_term_on_tableau(term, term_max); - settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); - return ret; - } - case simplex_strategy_enum::tableau_costs: - prepare_costs_for_r_solver(term); - { - bool ret = maximize_term_on_tableau(term, term_max); - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL); - return ret; - } - - case simplex_strategy_enum::lu: - lean_assert(false); // not implemented - return false; - default: - lean_unreachable(); // wrong mode - } - return false; - } + impq &term_max); // starting from a given feasible state look for the maximum of the term // return true if found and false if unbounded bool maximize_term(const vector> & term, - impq &term_max) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); - m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; - return maximize_term_on_corrected_r_solver(term, term_max); - } + impq &term_max); - const lar_term & get_term(unsigned j) const { - lean_assert(j >= m_terms_start_index); - return *m_terms[j - m_terms_start_index]; - } + const lar_term & get_term(unsigned j) const; - void pop_core_solver_params() { - pop_core_solver_params(1); - } + void pop_core_solver_params(); - void pop_core_solver_params(unsigned k) { - A_r().pop(k); - A_d().pop(k); - } + void pop_core_solver_params(unsigned k); - void set_upper_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_vars_to_ul_pairs[j]; - ul.upper_bound_witness() = ci; - m_vars_to_ul_pairs[j] = ul; - } + void set_upper_bound_witness(var_index j, constraint_index ci); - void set_low_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_vars_to_ul_pairs[j]; - ul.low_bound_witness() = ci; - m_vars_to_ul_pairs[j] = ul; - } + void set_low_bound_witness(var_index j, constraint_index ci); - void substitute_terms(const mpq & mult, - const vector>& left_side_with_terms, - vector> &left_side, mpq & right_side) const { - for (auto & t : left_side_with_terms) { - if (t.second < m_terms_start_index) { - lean_assert(t.second < A_r().column_count()); - left_side.push_back(std::pair(mult * t.first, t.second)); - } else { - const lar_term & term = * m_terms[adjust_term_index(t.second)]; - substitute_terms(mult * t.first, left_side_with_terms, left_side, right_side); - right_side -= mult * term.m_v; - } - } - } + void substitute_terms_in_linear_expression( const vector>& left_side_with_terms, + vector> &left_side, mpq & right_side) const; - void detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { - if (A_r().row_count() != m_column_buffer.data_size()) - m_column_buffer.resize(A_r().row_count()); - else - m_column_buffer.clear(); - lean_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); - - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) - m_rows_with_changed_bounds.insert(i); - } + void detect_rows_of_bound_change_column_for_nbasic_column(unsigned j); - void 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); - } + void detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j); - bool use_tableau() const { return m_settings.use_tableau(); } + bool use_tableau() const; - bool use_tableau_costs() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; - } + bool use_tableau_costs() const; - void detect_rows_of_column_with_bound_change(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column - // just mark the row at touched and exit - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); - return; - } + void detect_rows_of_column_with_bound_change(unsigned j); - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); - } + void adjust_x_of_column(unsigned j); - void adjust_x_of_column(unsigned j) { - lean_assert(false); - } - - bool 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]; - return is_zero(r); - } + bool row_is_correct(unsigned i) const; - bool ax_is_correct() const { - for (unsigned i = 0; i < A_r().row_count(); i++) { - if (!row_is_correct(i)) - return false; - } - return true; - } + bool ax_is_correct() const; - bool tableau_with_costs() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; - } + bool tableau_with_costs() const; - bool costs_are_used() const { - return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; - } + bool costs_are_used() const; - void change_basic_x_by_delta_on_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]; - m_mpq_lar_core_solver.m_r_x[bj] -= A_r().get_val(c) * delta; - if (tableau_with_costs()) { - m_basic_columns_with_changed_cost.insert(bj); - } - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); - } - } else { - m_column_buffer.clear(); - m_column_buffer.resize(A_r().row_count()); - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; - m_mpq_lar_core_solver.m_r_x[bj] -= m_column_buffer[i] * delta; - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); - } - } - } + void change_basic_x_by_delta_on_column(unsigned j, const numeric_pair & delta); - void update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - if (costs_are_used()) { - bool was_infeas = m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j); - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); - if (was_infeas != m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j)) - m_basic_columns_with_changed_cost.insert(j); - } else { - m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(j); - } - } else { - numeric_pair delta; - if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) - change_basic_x_by_delta_on_column(j, delta); - } - } + void update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j); - void detect_rows_with_changed_bounds_for_column(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); - return; - } - - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); - } + void detect_rows_with_changed_bounds_for_column(unsigned j); - void detect_rows_with_changed_bounds() { - for (auto j : m_columns_with_changed_bound.m_index) - detect_rows_with_changed_bounds_for_column(j); - } + void detect_rows_with_changed_bounds(); - void update_x_and_inf_costs_for_columns_with_changed_bounds() { - for (auto j : m_columns_with_changed_bound.m_index) - update_x_and_inf_costs_for_column_with_changed_bounds(j); - } + void update_x_and_inf_costs_for_columns_with_changed_bounds(); - void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { - lean_assert(ax_is_correct()); - for (auto j : m_columns_with_changed_bound.m_index) - update_x_and_inf_costs_for_column_with_changed_bounds(j); - - if (tableau_with_costs()) { - for (unsigned j : m_basic_columns_with_changed_cost.m_index) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } - } + void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - void solve_with_core_solver() { - if (!use_tableau()) - add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); - if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { - add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); - } - m_mpq_lar_core_solver.prefix_r(); - if (costs_are_used()) { - m_basic_columns_with_changed_cost.clear(); - m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); - } - if (use_tableau()) - update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - else - update_x_and_inf_costs_for_columns_with_changed_bounds(); - m_mpq_lar_core_solver.solve(); - set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); - lean_assert(m_status != OPTIMAL || all_constraints_hold()); - } + void solve_with_core_solver(); - numeric_pair get_basic_var_value_from_row_directly(unsigned i) { - numeric_pair r = zero_of_type>(); - - 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 (!is_zero(x)) - r -= c.m_value * x; - } - return r; - } + numeric_pair get_basic_var_value_from_row_directly(unsigned i); - numeric_pair get_basic_var_value_from_row(unsigned i) { - if (settings().use_tableau()) { - return get_basic_var_value_from_row_directly(i); - } - - numeric_pair r = zero_of_type>(); - m_mpq_lar_core_solver.calculate_pivot_row(i); - for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); - r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; - } - return r; - } + numeric_pair get_basic_var_value_from_row(unsigned i); template - void add_last_rows_to_lu(lp_primal_core_solver & s) { - auto & f = s.m_factorization; - if (f != nullptr) { - auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); - if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { - delete f; - f = nullptr; - } else { - f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); - } - } - if (f == nullptr) { - init_factorization(f, s.m_A, s.m_basis, m_settings); - if (f->get_status() != LU_status::OK) { - delete f; - f = nullptr; - } - } - - } + void add_last_rows_to_lu(lp_primal_core_solver & s); - bool x_is_correct() const { - if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { - // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; - return false; - } - for (unsigned i = 0; i < A_r().row_count(); i++) { - numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); - if (!delta.is_zero()) { - // std::cout << "x is off ("; - // std::cout << "m_b[" << i << "] = " << m_b[i] << " "; - // std::cout << "left side = " << A().dot_product_with_row(i, m_r_solver.m_x) << ' '; - // std::cout << "delta = " << delta << ' '; - // std::cout << "iters = " << total_iterations() << ")" << std::endl; - // std::cout << "row " << i << " is off" << std::endl; - return false; - } - } - return true;; - - } + bool x_is_correct() const; - bool var_is_registered(var_index vj) const { - if (vj >= m_terms_start_index) { - if (vj - m_terms_start_index >= m_terms.size()) - return false; - } else if ( vj >= A_r().column_count()) { - return false; - } - return true; - } + bool var_is_registered(var_index vj) const; - unsigned constraint_stack_size() const { - return m_constraint_count.stack_size(); - } + unsigned constraint_stack_size() const; - void fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); - unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].size() == 0); - for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); - var_index j = t.first; - A.set(last_row, j, - t.second); - } - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, mpq(1)); - } + void fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls); template - void create_matrix_A(static_matrix & matr) { - lean_assert(false); // not implemented - /* - unsigned m = number_or_nontrivial_left_sides(); - unsigned n = m_vec_of_canonic_left_sides.size(); - if (matr.row_count() == m && matr.column_count() == n) - return; - matr.init_empty_matrix(m, n); - copy_from_mpq_matrix(matr); - */ - } + void create_matrix_A(static_matrix & matr); template - void copy_from_mpq_matrix(static_matrix & matr) { - matr.m_rows.resize(A_r().row_count()); - 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())); - } - } - } + void copy_from_mpq_matrix(static_matrix & matr); - bool try_to_set_fixed(column_info & ci) { - if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { - ci.set_fixed_value(ci.get_upper_bound()); - return true; - } - return false; - } + bool try_to_set_fixed(column_info & ci); - column_type get_column_type(const column_info & ci) { - auto ret = ci.get_column_type_no_flipping(); - if (ret == column_type::boxed) { // changing boxed to fixed because of the no span - if (ci.get_low_bound() == ci.get_upper_bound()) - ret = column_type::fixed; - } - return ret; - } + column_type get_column_type(const column_info & ci); - std::string get_column_name(unsigned j) const { - if (j >= m_terms_start_index) - return std::string("_t") + T_to_string(j); - if (j >= m_columns_to_ext_vars_or_term_indices.size()) - return std::string("_s") + T_to_string(j); + std::string get_column_name(unsigned j) const; - return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]); - } + bool all_constrained_variables_are_registered(const vector>& left_side); - bool all_constrained_variables_are_registered(const vector>& left_side) { - for (auto it : left_side) { - if (! var_is_registered(it.second)) - return false; - } - return true; - } + constraint_index add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm); + bool all_constraints_hold() const; + bool constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const; + bool the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const; - constraint_index add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { - /* - mpq rs = right_side_parm; - vector> left_side; - substitute_terms(one_of_type(), left_side_with_terms, left_side, rs); - lean_assert(left_side.size() > 0); - lean_assert(all_constrained_variables_are_registered(left_side)); - lar_constraint original_constr(left_side, kind_par, rs); - unsigned j; // j is the index of the basic variables corresponding to the left side - canonic_left_side ls = create_or_fetch_canonic_left_side(left_side, j); - mpq ratio = find_ratio_of_original_constraint_to_normalized(ls, original_constr); - auto kind = ratio.is_neg() ? flip_kind(kind_par) : kind_par; - rs/= ratio; - lar_normalized_constraint normalized_constraint(ls, ratio, kind, rs, original_constr); - m_constraints.push_back(normalized_constraint); - constraint_index constr_ind = m_constraints.size() - 1; - update_column_type_and_bound(j, kind, rs, constr_ind); - return constr_ind; - */ - lean_assert(false); // not implemented - return 0; - } + static void register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a); + static void register_one_coeff_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j); - bool all_constraints_hold() const { - if (m_settings.get_cancel_flag()) - return true; - std::unordered_map var_map; - get_model(var_map); + + bool the_left_sides_sum_to_zero(const vector> & evidence) const; + + bool the_right_sides_do_not_sum_to_zero(const vector> & evidence); + + bool explanation_is_correct(const vector>& explanation) const; + + bool inf_explanation_is_correct() const; + + mpq sum_of_right_sides_of_explanation(const vector> & explanation) const; + + bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict); - for (unsigned i = 0; i < m_constraints.size(); i++) { - if (!constraint_holds(*m_constraints[i], var_map)) { - print_constraint(i, std::cout); - return false; - } - } - return true; - } - - bool constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { - mpq left_side_val = get_left_side_val(constr, var_map); - switch (constr.m_kind) { - case LE: return left_side_val <= constr.m_right_side; - case LT: return left_side_val < constr.m_right_side; - case GE: return left_side_val >= constr.m_right_side; - case GT: return left_side_val > constr.m_right_side; - case EQ: return left_side_val == constr.m_right_side; - default: - lean_unreachable(); - } - return false; // it is unreachable - } + bool has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict); - - - - - - bool the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const { - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lconstraint_kind kind = coeff.is_pos() ? - m_constraints[con_ind]->m_kind : - flip_kind(m_constraints[con_ind]->m_kind); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) n_of_G++; - else if (kind == LE || kind == LT) n_of_L++; - } - the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); - - return n_of_G == 0 || n_of_L == 0; - } - - static void register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a) { - for (auto & it : cn.get_left_side_coefficients()) { - unsigned j = it.second; - auto p = coeffs.find(j); - if (p == coeffs.end()) - coeffs[j] = it.first * a; - else { - p->second += it.first * a; - if (p->second.is_zero()) - coeffs.erase(p); - } - } - } - bool the_left_sides_sum_to_zero(const vector> & evidence) const { - std::unordered_map coeff_map; - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - register_in_map(coeff_map, *m_constraints[con_ind], coeff); - } - - if (!coeff_map.empty()) { - std::cout << "left side = "; - vector> t; - for (auto & it : coeff_map) { - t.push_back(std::make_pair(it.second, it.first)); - } - print_linear_combination_of_column_indices(t, std::cout); - std::cout << std::endl; - return false; - } - - return true; - } - - bool the_right_sides_do_not_sum_to_zero(const vector> & evidence) { - mpq ret = numeric_traits::zero(); - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - const lar_constraint & constr = *m_constraints[con_ind]; - ret += constr.m_right_side * coeff; - } - return !numeric_traits::is_zero(ret); - } - - bool explanation_is_correct(const vector>& explanation) const { -#ifdef LEAN_DEBUG - lconstraint_kind kind; - lean_assert(the_relations_are_of_same_type(explanation, kind)); - lean_assert(the_left_sides_sum_to_zero(explanation)); - mpq rs = sum_of_right_sides_of_explanation(explanation); - switch (kind) { - case LE: lean_assert(rs < zero_of_type()); - break; - case LT: lean_assert(rs <= zero_of_type()); - break; - case GE: lean_assert(rs > zero_of_type()); - break; - case GT: lean_assert(rs >= zero_of_type()); - break; - case EQ: lean_assert(rs != zero_of_type()); - break; - default: - lean_assert(false); - return false; - } -#endif - return true; - } - - bool inf_explanation_is_correct() const { -#ifdef LEAN_DEBUG - vector> explanation; - get_infeasibility_explanation(explanation); - return explanation_is_correct(explanation); -#endif - return true; - } - - mpq sum_of_right_sides_of_explanation(const vector> & explanation) const { - mpq ret = numeric_traits::zero(); - for (auto & it : explanation) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lean_assert(con_ind < m_constraints.size()); - ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; - } - return ret; - } - - bool has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - - if (var >= m_vars_to_ul_pairs.size()) { - // TBD: bounds on terms could also be used, caller may have to track these. - return false; - } - const ul_pair & ul = m_vars_to_ul_pairs[var]; - ci = ul.low_bound_witness(); - if (ci != static_cast(-1)) { - auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; - value = p.x; - is_strict = p.y.is_pos(); - return true; - } - else { - return false; - } - } - - bool has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - - if (var >= m_vars_to_ul_pairs.size()) { - // TBD: bounds on terms could also be used, caller may have to track these. - return false; - } - const ul_pair & ul = m_vars_to_ul_pairs[var]; - ci = ul.upper_bound_witness(); - if (ci != static_cast(-1)) { - auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; - value = p.x; - is_strict = p.y.is_neg(); - return true; - } - else { - return false; - } - } - - - void get_infeasibility_explanation(vector> & explanation) const { - explanation.clear(); - if (m_infeasible_column_index != -1) { - fill_explanation_from_infeasible_column(explanation); - return; - } - if (m_mpq_lar_core_solver.get_infeasible_sum_sign() == 0) { - return; - } - // the infeasibility sign - int inf_sign; - auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); - get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); - lean_assert(explanation_is_correct(explanation)); - } + void get_infeasibility_explanation(vector> & explanation) const; void get_infeasibility_explanation_for_inf_sign( vector> & explanation, const vector> & inf_row, - int inf_sign) const { - - for (auto & it : inf_row) { - mpq coeff = it.first; - unsigned j = it.second; - - int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; - const ul_pair & ul = m_vars_to_ul_pairs[j]; - - constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); - lean_assert(bound_constr_i < m_constraints.size()); - explanation.push_back(std::make_pair(coeff, bound_constr_i)); - } - } + int inf_sign) const; - void get_model(std::unordered_map & variable_values) const { - mpq delta = mpq(1, 2); // start from 0.5 to have less clashes - lean_assert(m_status == OPTIMAL); - unsigned i; - do { - - // different pairs have to produce different singleton values - std::unordered_set set_of_different_pairs; - std::unordered_set set_of_different_singles; - delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); - for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { - const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; - set_of_different_pairs.insert(rp); - mpq x = rp.x + delta * rp.y; - set_of_different_singles.insert(x); - if (set_of_different_pairs.size() - != set_of_different_singles.size()) { - delta /= mpq(2); - break; - } - - variable_values[i] = x; - } - } while (i != m_mpq_lar_core_solver.m_r_x.size()); - } + void get_model(std::unordered_map & variable_values) const; - std::string get_variable_name(var_index vi) const { - return get_column_name(vi); - } + std::string get_variable_name(var_index vi) const; // ********** print region start - void print_constraint(constraint_index ci, std::ostream & out) const { - if (ci >= m_constraints.size()) { - out << "constraint " << T_to_string(ci) << " is not found"; - out << std::endl; - return; - } + void print_constraint(constraint_index ci, std::ostream & out) const; - print_constraint(m_constraints[ci], out); - } + void print_constraints(std::ostream& out) const ; - void print_constraints(std::ostream& out) const { - for (auto c : m_constraints) { - print_constraint(c, out); - } - } + void print_terms(std::ostream& out) const ; - void print_terms(std::ostream& out) const { - for (auto it : m_terms) { - print_term(*it, out); - out << "\n"; - } - } + void print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const; - void print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const { - print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out); - mpq free_coeff = c->get_free_coeff_of_left_side(); - if (!is_zero(free_coeff)) - out << " + " << free_coeff; - - } + void print_term(lar_term const& term, std::ostream & out) const; - void print_term(lar_term const& term, std::ostream & out) const { - if (!numeric_traits::is_zero(term.m_v)) { - out << term.m_v << " + "; - } - print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); - } + mpq get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const; - mpq get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { - mpq ret = cns.get_free_coeff_of_left_side(); - for (auto & it : cns.get_left_side_coefficients()) { - var_index j = it.second; - auto vi = var_map.find(j); - lean_assert(vi != var_map.end()); - ret += it.first * vi->second; - } - return ret; - } + void print_constraint(const lar_base_constraint * c, std::ostream & out) const; - void print_constraint(const lar_base_constraint * c, std::ostream & out) const { - print_left_side_of_constraint(c, out); - out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; - } + void fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list); - void fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { - for (unsigned i = 0; i < sz; i++) { - var_index var = vars[i]; - if (var >= m_terms_start_index) { // handle the term - for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { - column_list.push_back(it.first); - } - } else { - column_list.push_back(var); - } - } - } + void random_update(unsigned sz, var_index const * vars); + void pivot_fixed_vars_from_basis(); + void pop(); + bool column_represents_row_in_tableau(unsigned j); + void make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j); + void remove_last_row_and_column_from_tableau(unsigned j); + void remove_last_column_from_tableau(unsigned j); - void random_update(unsigned sz, var_index const * vars) { - vector column_list; - fill_var_set_for_random_update(sz, vars, column_list); - random_updater ru(m_mpq_lar_core_solver, column_list); - ru.update(); - } + void remove_last_column_from_basis_tableau(unsigned j); + void remove_column_from_tableau(unsigned j); + void pop_tableau(); + void clean_inf_set_of_r_solver_after_pop(); + void shrink_explanation_to_minimum(vector> & explanation) const; - - void try_pivot_fixed_vars_from_basis() { - m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); - } - - void pop() { - pop(1); - } - - - bool column_represents_row_in_tableau(unsigned j) { - return m_vars_to_ul_pairs()[j].m_i != static_cast(-1); - } - - void make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { - // i, j - is the indices of the bottom-right element of the tableau - lean_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;){ - auto & cc = last_column[k]; - if (cc.m_i == i) - return; - non_zero_column_cell_index = k; - } - - lean_assert(non_zero_column_cell_index != -1); - lean_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); - } - - void remove_last_row_and_column_from_tableau(unsigned j) { - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - auto & slv = m_mpq_lar_core_solver.m_r_solver; - unsigned i = A_r().row_count() - 1; //last row index - make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); - if (slv.m_basis_heading[j] < 0) { - slv.pivot_column_tableau(j, i); - } - - 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;) { - auto &rc = last_row[k]; - if (cost_is_nz) { - m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); - } - - A_r().remove_element(last_row, rc); - } - lean_assert(last_row.size() == 0); - lean_assert(A_r().m_columns[j].size() == 0); - A_r().m_rows.pop_back(); - A_r().m_columns.pop_back(); - slv.m_b.pop_back(); - } - - void remove_last_column_from_tableau(unsigned j) { - lean_assert(j == A_r().column_count() - 1); - // the last column has to be empty - lean_assert(A_r().m_columns[j].size() == 0); - A_r().m_columns.pop_back(); - } - - void remove_last_column_from_basis_tableau(unsigned j) { - auto& rslv = m_mpq_lar_core_solver.m_r_solver; - int i = rslv.m_basis_heading[j]; - if (i >= 0) { // j is a basic var - int last_pos = static_cast(rslv.m_basis.size()) - 1; - lean_assert(last_pos >= 0); - if (i != last_pos) { - unsigned j_at_last_pos = rslv.m_basis[last_pos]; - rslv.m_basis[i] = j_at_last_pos; - rslv.m_basis_heading[j_at_last_pos] = i; - } - rslv.m_basis.pop_back(); // remove j from the basis - } else { - int last_pos = static_cast(rslv.m_nbasis.size()) - 1; - lean_assert(last_pos >= 0); - i = - 1 - i; - if (i != last_pos) { - unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; - rslv.m_nbasis[i] = j_at_last_pos; - rslv.m_basis_heading[j_at_last_pos] = - i - 1; - } - rslv.m_nbasis.pop_back(); // remove j from the basis - } - rslv.m_basis_heading.pop_back(); - lean_assert(rslv.m_basis.size() == A_r().row_count()); - lean_assert(rslv.basis_heading_is_correct()); - } - - void remove_column_from_tableau(unsigned j) { - auto& rslv = m_mpq_lar_core_solver.m_r_solver; - lean_assert(j == A_r().column_count() - 1); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - if (column_represents_row_in_tableau(j)) { - remove_last_row_and_column_from_tableau(j); - if (rslv.m_basis_heading[j] < 0) - rslv.change_basis_unconditionally(j, rslv.m_basis[A_r().row_count()]); // A_r().row_count() is the index of the last row in the basis still - } - else { - remove_last_column_from_tableau(j); - } - rslv.m_x.pop_back(); - rslv.m_d.pop_back(); - rslv.m_costs.pop_back(); - - remove_last_column_from_basis_tableau(j); - lean_assert(m_mpq_lar_core_solver.r_basis_is_OK()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - } - - - void pop_tableau() { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); - // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). - // At this moment m_column_names is already popped - for (unsigned j = A_r().column_count(); j-- > m_columns_to_ext_vars_or_term_indices.size();) - remove_column_from_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); - } - - - - - void clean_inf_set_of_r_solver_after_pop() { - vector became_feas; - clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); - std::unordered_set basic_columns_with_changed_cost; - auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; - for (auto j: inf_index_copy) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - continue; - } - // some basic columns might become non-basic - these columns need to be made feasible - numeric_pair delta; - if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) - change_basic_x_by_delta_on_column(j, delta); - became_feas.push_back(j); - } - - for (unsigned j : became_feas) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); - m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; - m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); - m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - } - became_feas.clear(); - for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); - if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) - became_feas.push_back(j); - } - for (unsigned j : became_feas) - m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - if (use_tableau_costs()) { - for (unsigned j : became_feas) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - for (unsigned j : basic_columns_with_changed_cost) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } - } - - - void shrink_explanation_to_minimum(vector> & explanation) const { - // implementing quickXplain - quick_xplain::run(explanation, *this); - lean_assert(this->explanation_is_correct(explanation)); + bool column_value_is_integer(unsigned j) const { + const impq & v = m_mpq_lar_core_solver.m_r_x[j]; + return v.is_int(); } + + bool column_is_real(unsigned j) const { + return !column_is_int(j); + } + + bool model_is_int_feasible() const; + + const impq & column_low_bound(unsigned j) const { + return m_mpq_lar_core_solver.low_bound(j); + } + + const impq & column_upper_bound(unsigned j) const { + return m_mpq_lar_core_solver.upper_bound(j); + } + + bool column_is_bounded(unsigned j) const { + return m_mpq_lar_core_solver.column_is_bounded(j); + } + + void get_bound_constraint_witnesses_for_column(unsigned j, constraint_index & lc, constraint_index & uc) const { + const ul_pair & ul = m_vars_to_ul_pairs[j]; + lc = ul.low_bound_witness(); + uc = ul.upper_bound_witness(); + } + indexed_vector & get_column_in_lu_mode(unsigned j) { + m_column_buffer.clear(); + m_column_buffer.resize(A_r().row_count()); + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + return m_column_buffer; + } + + bool bound_is_integer_if_needed(unsigned j, const mpq & right_side) const; }; } diff --git a/src/util/lp/lar_solver_instances.cpp b/src/util/lp/lar_solver_instances.cpp new file mode 100644 index 000000000..98f59edb9 --- /dev/null +++ b/src/util/lp/lar_solver_instances.cpp @@ -0,0 +1,13 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#include "util/lp/lar_solver.cpp" + +template void lean::lar_solver::copy_from_mpq_matrix(class lean::static_matrix &); + + + + + diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index a12b7b5d2..925206680 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -429,6 +429,7 @@ public: void init_lu(); int pivots_in_column_and_row_are_different(int entering, int leaving) const; void pivot_fixed_vars_from_basis(); + bool pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w); bool pivot_for_tableau_on_basis(); bool pivot_row_for_tableau_on_basis(unsigned row); void init_basic_part_of_basis_heading() { @@ -568,8 +569,8 @@ public: default: lean_assert(false); } - std::cout << "basis heading = " << m_basis_heading[j] << std::endl; - std::cout << "x = " << m_x[j] << std::endl; + out << "basis heading = " << m_basis_heading[j] << std::endl; + out << "x = " << m_x[j] << std::endl; /* std::cout << "cost = " << m_costs[j] << std::endl; std:: cout << "m_d = " << m_d[j] << std::endl;*/ diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index a0dba9de7..d551daf27 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -923,7 +923,27 @@ template void lp_core_solver_base::transpose_row transpose_basis(i, j); m_A.transpose_rows(i, j); } - +// j is the new basic column, j_basic - the leaving column +template bool lp_core_solver_base::pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w) { + unsigned row_index = m_basis_heading[j_basic]; + change_basis(j, j_basic); + if (m_settings.m_simplex_strategy == simplex_strategy_enum::lu) { + if (m_factorization->need_to_refactor()) { + init_lu(); + } else { + m_factorization->prepare_entering(j, w); // to init vector w + m_factorization->replace_column(zero_of_type(), w, row_index); + } + if (m_factorization->get_status() != LU_status::OK) { + change_basis(j_basic, j); + init_lu(); + return false; + } + } else { // the tableau case + pivot_column_tableau(j, row_index); + } + return true; +} template void lp_core_solver_base::pivot_fixed_vars_from_basis() { // run over basis and non-basis at the same time indexed_vector w(m_basis.size()); // the buffer @@ -943,22 +963,9 @@ template void lp_core_solver_base::pivot_fixed_v if (j >= m_nbasis.size()) break; j++; - if (m_factorization->need_to_refactor()) { - change_basis(jj, ii); - init_lu(); - } else { - m_factorization->prepare_entering(jj, w); // to init vector w - m_factorization->replace_column(zero_of_type(), w, m_basis_heading[ii]); - change_basis(jj, ii); - } - if (m_factorization->get_status() != LU_status::OK) { - change_basis(ii, jj); - init_lu(); - } else { + if (!pivot_column_general(jj, ii, w)) break; - } - } - lean_assert(m_factorization->get_status()== LU_status::OK); + } } } diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index aac3692f9..736e4cda4 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -16,13 +16,16 @@ namespace lean { typedef unsigned var_index; typedef unsigned constraint_index; typedef unsigned row_index; + +typedef vector> explanation_t; + enum class column_type { free_column = 0, - low_bound = 1, - upper_bound = 2, - boxed = 3, - fixed = 4 - }; + low_bound = 1, + upper_bound = 2, + boxed = 3, + fixed = 4 +}; enum class simplex_strategy_enum { undecided = 3, @@ -75,11 +78,14 @@ public: }; struct stats { + unsigned m_make_feasible; unsigned m_total_iterations; unsigned m_iters_with_no_cost_growing; unsigned m_num_factorizations; unsigned m_num_of_implied_bounds; unsigned m_need_to_solve_inf; + unsigned m_max_cols; + unsigned m_max_rows; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -198,7 +204,8 @@ public: use_breakpoints_in_feasibility_search(false), max_row_length_for_bound_propagation(300), backup_costs(true), - column_number_threshold_for_using_lu_in_lar_solver(4000) + column_number_threshold_for_using_lu_in_lar_solver(4000), + m_int_branch_cut_threshold(10000000) {} void set_resource_limit(lp_resource_limit& lim) { m_resource_limit = &lim; } @@ -278,13 +285,13 @@ public: return m_simplex_strategy; } - bool use_lu() const { - return m_simplex_strategy == simplex_strategy_enum::lu; - } + bool use_lu() const { + return m_simplex_strategy == simplex_strategy_enum::lu; + } bool use_tableau() const { - return m_simplex_strategy == simplex_strategy_enum::tableau_rows || - m_simplex_strategy == simplex_strategy_enum::tableau_costs; + return m_simplex_strategy == simplex_strategy_enum::tableau_rows || + m_simplex_strategy == simplex_strategy_enum::tableau_costs; } bool use_tableau_rows() const { @@ -305,6 +312,7 @@ public: unsigned max_row_length_for_bound_propagation; bool backup_costs; unsigned column_number_threshold_for_using_lu_in_lar_solver; + unsigned m_int_branch_cut_threshold; }; // end of lp_settings class diff --git a/src/util/lp/lp_settings_instances.cpp b/src/util/lp/lp_settings_instances.cpp index e9a3888ba..ac2ed4b51 100644 --- a/src/util/lp/lp_settings_instances.cpp +++ b/src/util/lp/lp_settings_instances.cpp @@ -2,8 +2,8 @@ Copyright (c) 2017 Microsoft Corporation Author: Lev Nachmanson */ -#include "util/vector.h" #include +#include "util/vector.h" #include "util/lp/lp_settings.hpp" template bool lean::vectors_are_equal(vector const&, vector const&); template bool lean::vectors_are_equal(vector const&, vector const&); diff --git a/src/util/lp/mps_reader.h b/src/util/lp/mps_reader.h index 4c793d56e..eb83735ca 100644 --- a/src/util/lp/mps_reader.h +++ b/src/util/lp/mps_reader.h @@ -810,7 +810,7 @@ public: auto kind = get_lar_relation_from_row(row->m_type); vector> ls; for (auto s : row->m_row_columns) { - var_index i = solver->add_var(get_var_index(s.first)); + var_index i = solver->add_var(get_var_index(s.first), false); ls.push_back(std::make_pair(s.second, i)); } solver->add_constraint(ls, kind, row->m_right_side); @@ -828,20 +828,20 @@ public: void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) { vector> ls; - var_index i = solver->add_var(col->m_index); + var_index i = solver->add_var(col->m_index, false); ls.push_back(std::make_pair(numeric_traits::one(), i)); solver->add_constraint(ls, GE, b->m_low); } void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) { - var_index i = solver->add_var(col->m_index); + var_index i = solver->add_var(col->m_index, false); vector> ls; ls.push_back(std::make_pair(numeric_traits::one(), i)); solver->add_constraint(ls, LE, b->m_upper); } void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) { - var_index i = solver->add_var(col->m_index); + var_index i = solver->add_var(col->m_index, false); vector> ls; ls.push_back(std::make_pair(numeric_traits::one(), i)); solver->add_constraint(ls, EQ, b->m_fixed_value); @@ -850,7 +850,7 @@ public: void fill_lar_solver_on_columns(lar_solver * solver) { for (auto s : m_columns) { mps_reader::column * col = s.second; - solver->add_var(col->m_index); + solver->add_var(col->m_index, false); auto b = col->m_bound; if (b == nullptr) return; diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp new file mode 100644 index 000000000..81372be32 --- /dev/null +++ b/src/util/lp/nra_solver.cpp @@ -0,0 +1,264 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#include "util/lp/lar_solver.h" +#include "util/lp/nra_solver.h" +#include "nlsat/nlsat_solver.h" +#include "math/polynomial/polynomial.h" +#include "math/polynomial/algebraic_numbers.h" +#include "util/map.h" + + +namespace nra { + + struct mon_eq { + mon_eq(lean::var_index v, unsigned sz, lean::var_index const* vs): + m_v(v), m_vs(sz, vs) {} + lean::var_index m_v; + svector m_vs; + }; + + struct solver::imp { + lean::lar_solver& s; + reslimit& m_limit; + params_ref m_params; + u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables + scoped_ptr m_nlsat; + vector m_monomials; + unsigned_vector m_monomials_lim; + mutable std::unordered_map m_variable_values; // current model + + imp(lean::lar_solver& s, reslimit& lim, params_ref const& p): + s(s), + m_limit(lim), + m_params(p) { + } + + bool need_check() { + return !m_monomials.empty() && !check_assignments(); + } + + void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { + m_monomials.push_back(mon_eq(v, sz, vs)); + } + + void push() { + m_monomials_lim.push_back(m_monomials.size()); + } + + void pop(unsigned n) { + if (n == 0) return; + m_monomials.shrink(m_monomials_lim[m_monomials_lim.size() - n]); + m_monomials_lim.shrink(m_monomials_lim.size() - n); + } + + /* + \brief Check if polynomials are well defined. + multiply values for vs and check if they are equal to value for v. + epsilon has been computed. + */ + bool check_assignment(mon_eq const& m) const { + rational r1 = m_variable_values[m.m_v]; + rational r2(1); + for (auto w : m.m_vs) { + r2 *= m_variable_values[w]; + } + return r1 == r2; + } + + bool check_assignments() const { + s.get_model(m_variable_values); + for (auto const& m : m_monomials) { + if (!check_assignment(m)) return false; + } + return true; + } + + /** + \brief one-shot nlsat check. + A one shot checker is the least functionality that can + enable non-linear reasoning. + In addition to checking satisfiability we would also need + to identify equalities in the model that should be assumed + with the remaining solver. + + TBD: use partial model from lra_solver to prime the state of nlsat_solver. + TBD: explore more incremental ways of applying nlsat (using assumptions) + */ + lbool check(lean::explanation_t& ex) { + SASSERT(need_check()); + m_nlsat = alloc(nlsat::solver, m_limit, m_params); + m_lp2nl.reset(); + vector core; + + // add linear inequalities from lra_solver + for (unsigned i = 0; i < s.constraint_count(); ++i) { + add_constraint(i); + } + + // add polynomial definitions. + for (auto const& m : m_monomials) { + add_monomial_eq(m); + } + // TBD: add variable bounds? + + lbool r = m_nlsat->check(); + TRACE("arith", m_nlsat->display(tout << r << "\n");); + switch (r) { + case l_true: + break; + case l_false: + ex.reset(); + m_nlsat->get_core(core); + for (auto c : core) { + unsigned idx = static_cast(static_cast(c) - this); + ex.push_back(std::pair(rational(1), idx)); + TRACE("arith", tout << "ex: " << idx << "\n";); + } + break; + + case l_undef: + break; + } + return r; + } + + void add_monomial_eq(mon_eq const& m) { + polynomial::manager& pm = m_nlsat->pm(); + svector vars; + for (auto v : m.m_vs) { + vars.push_back(lp2nl(v)); + } + polynomial::monomial_ref m1(pm.mk_monomial(vars.size(), vars.c_ptr()), pm); + polynomial::monomial_ref m2(pm.mk_monomial(lp2nl(m.m_v), 1), pm); + polynomial::monomial* mls[2] = { m1, m2 }; + polynomial::scoped_numeral_vector coeffs(pm.m()); + coeffs.push_back(mpz(1)); + coeffs.push_back(mpz(-1)); + polynomial::polynomial_ref p(pm.mk_polynomial(2, coeffs.c_ptr(), mls), pm); + polynomial::polynomial* ps[1] = { p }; + bool even[1] = { false }; + nlsat::literal lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, even); + m_nlsat->mk_clause(1, &lit, 0); + } + + void add_constraint(unsigned idx) { + auto& c = s.get_constraint(idx); + auto& pm = m_nlsat->pm(); + auto k = c.m_kind; + auto rhs = c.m_right_side; + auto lhs = c.get_left_side_coefficients(); + auto sz = lhs.size(); + svector vars; + rational den = denominator(rhs); + for (auto kv : lhs) { + vars.push_back(lp2nl(kv.second)); + den = lcm(den, denominator(kv.first)); + } + vector coeffs; + for (auto kv : lhs) { + coeffs.push_back(den * kv.first); + } + rhs *= den; + polynomial::polynomial_ref p(pm.mk_linear(sz, coeffs.c_ptr(), vars.c_ptr(), -rhs), pm); + polynomial::polynomial* ps[1] = { p }; + bool is_even[1] = { false }; + nlsat::literal lit; + nlsat::assumption a = this + idx; + switch (k) { + case lean::lconstraint_kind::LE: + lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); + break; + case lean::lconstraint_kind::GE: + lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); + break; + case lean::lconstraint_kind::LT: + lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); + break; + case lean::lconstraint_kind::GT: + lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); + break; + case lean::lconstraint_kind::EQ: + lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); + break; + } + m_nlsat->mk_clause(1, &lit, a); + } + + bool is_int(lean::var_index v) { + return s.var_is_int(v); + } + + + polynomial::var lp2nl(lean::var_index v) { + polynomial::var r; + if (!m_lp2nl.find(v, r)) { + r = m_nlsat->mk_var(is_int(v)); + m_lp2nl.insert(v, r); + } + return r; + } + + nlsat::anum const& value(lean::var_index v) const { + return m_nlsat->value(m_lp2nl.find(v)); + } + + nlsat::anum_manager& am() { + return m_nlsat->am(); + } + + std::ostream& display(std::ostream& out) const { + for (auto m : m_monomials) { + out << "v" << m.m_v << " = "; + for (auto v : m.m_vs) { + out << "v" << v << " "; + } + out << "\n"; + } + return out; + } + }; + + solver::solver(lean::lar_solver& s, reslimit& lim, params_ref const& p) { + m_imp = alloc(imp, s, lim, p); + } + + solver::~solver() { + dealloc(m_imp); + } + + void solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) { + m_imp->add(v, sz, vs); + } + + lbool solver::check(lean::explanation_t& ex) { + return m_imp->check(ex); + } + + bool solver::need_check() { + return m_imp->need_check(); + } + + void solver::push() { + m_imp->push(); + } + + void solver::pop(unsigned n) { + m_imp->pop(n); + } + + std::ostream& solver::display(std::ostream& out) const { + return m_imp->display(out); + } + + nlsat::anum const& solver::value(lean::var_index v) const { + return m_imp->value(v); + } + + nlsat::anum_manager& solver::am() { + return m_imp->am(); + } + +} diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h new file mode 100644 index 000000000..0b02e7136 --- /dev/null +++ b/src/util/lp/nra_solver.h @@ -0,0 +1,70 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ + +#pragma once +#include "util/vector.h" +#include "util/lp/lp_settings.h" +#include "util/rlimit.h" +#include "util/params.h" +#include "nlsat/nlsat_solver.h" + +namespace lean { + class lar_solver; +} + + +namespace nra { + + + + class solver { + struct imp; + imp* m_imp; + + public: + + solver(lean::lar_solver& s, reslimit& lim, params_ref const& p = params_ref()); + + ~solver(); + + /* + \brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1] + The variable v is equal to the product of variables vs. + */ + void add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs); + + /* + \brief Check feasiblity of linear constraints augmented by polynomial definitions + that are added. + */ + lbool check(lean::explanation_t& ex); + + /* + \brief determine whether nra check is needed. + */ + bool need_check(); + + /* + \brief Access model. + */ + nlsat::anum const& value(lean::var_index v) const; + + nlsat::anum_manager& am(); + + /* + \brief push and pop scope. + Monomial definitions are retraced when popping scope. + */ + void push(); + + void pop(unsigned n); + + /* + \brief display state + */ + std::ostream& display(std::ostream& out) const; + + }; +} diff --git a/src/util/lp/numeric_pair.h b/src/util/lp/numeric_pair.h index 84c99b3b1..db7b71119 100644 --- a/src/util/lp/numeric_pair.h +++ b/src/util/lp/numeric_pair.h @@ -199,6 +199,11 @@ struct numeric_pair { std::string to_string() const { return std::string("(") + T_to_string(x) + ", " + T_to_string(y) + ")"; } + + bool is_int() const { + return x.is_int() && y.is_zero(); + } + }; @@ -324,4 +329,26 @@ struct convert_struct { template bool is_epsilon_small(const X & v, const double &eps) { return convert_struct::is_epsilon_small(v, eps);} template bool below_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct::below_bound_numeric(x, bound, eps);} template bool above_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct::above_bound_numeric(x, bound, eps);} +template T floor(const numeric_pair & r) { + if (r.x.is_int()) { + if (r.y.is_nonneg()) { + return r.x; + } + return r.x - mpq::one(); + } + + return floor(r.x); +} + +template T ceil(const numeric_pair & r) { + if (r.x.is_int()) { + if (r.y.is_nonpos()) { + return r.x; + } + return r.x + mpq::one(); + } + + return ceil(r.x); +} + } diff --git a/src/util/lp/quick_xplain.cpp b/src/util/lp/quick_xplain.cpp index a4b6fb0e6..df409240e 100644 --- a/src/util/lp/quick_xplain.cpp +++ b/src/util/lp/quick_xplain.cpp @@ -20,7 +20,7 @@ void quick_xplain::copy_constraint_and_add_constraint_vars(const lar_constraint& vector < std::pair> ls; for (auto & p : lar_c.get_left_side_coefficients()) { unsigned j = p.second; - unsigned lj = m_qsol.add_var(j); + unsigned lj = m_qsol.add_var(j, false); ls.push_back(std::make_pair(p.first, lj)); } m_constraints_in_local_vars.push_back(lar_constraint(ls, lar_c.m_kind, lar_c.m_right_side)); @@ -94,7 +94,7 @@ bool quick_xplain::is_feasible(const vector & x, unsigned k) const { vector < std::pair> ls; const lar_constraint & c = m_constraints_in_local_vars[i]; for (auto & p : c.get_left_side_coefficients()) { - unsigned lj = l.add_var(p.second); + unsigned lj = l.add_var(p.second, false); ls.push_back(std::make_pair(p.first, lj)); } l.add_constraint(ls, c.m_kind, c.m_right_side); diff --git a/src/util/lp/stacked_vector.h b/src/util/lp/stacked_vector.h index 3f39dd346..14b0d0141 100644 --- a/src/util/lp/stacked_vector.h +++ b/src/util/lp/stacked_vector.h @@ -32,7 +32,10 @@ public: operator const B&() const { return m_vec.m_vector[m_i]; } - + + bool operator==(B const& other) const { + return m_vec.m_vector[m_i] == other; + } }; class ref_const { diff --git a/src/util/lp/static_matrix_instances.cpp b/src/util/lp/static_matrix_instances.cpp index d0e2045c0..59905929e 100644 --- a/src/util/lp/static_matrix_instances.cpp +++ b/src/util/lp/static_matrix_instances.cpp @@ -2,8 +2,8 @@ Copyright (c) 2017 Microsoft Corporation Author: Lev Nachmanson */ -#include "util/vector.h" #include +#include "util/vector.h" #include #include #include "util/lp/static_matrix.hpp" From 6fad478a189870bbcffba7b1098a943fe43b283b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Jun 2017 17:46:29 -0700 Subject: [PATCH 0177/1283] reorg Signed-off-by: Nikolaj Bjorner --- src/sat/card_extension.cpp | 1196 ++++++++++++++++++---------------- src/sat/card_extension.h | 150 +++-- src/sat/sat_justification.h | 9 +- src/sat/sat_local_search.cpp | 88 +-- src/sat/sat_local_search.h | 1 - src/sat/sat_solver.cpp | 4 + src/sat/sat_solver.h | 1 + src/sat/sat_types.h | 4 +- src/sat/sat_watched.h | 8 +- src/sat/tactic/goal2sat.cpp | 20 +- 10 files changed, 771 insertions(+), 710 deletions(-) diff --git a/src/sat/card_extension.cpp b/src/sat/card_extension.cpp index 690ed042d..8a590017e 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/card_extension.cpp @@ -22,12 +22,40 @@ Revision History: namespace sat { - card_extension::card::card(unsigned index, literal lit, literal_vector const& lits, unsigned k): - m_index(index), - m_lit(lit), - m_k(k), - m_size(lits.size()) { - for (unsigned i = 0; i < lits.size(); ++i) { + card_extension::card& card_extension::constraint::to_card() { + SASSERT(is_card()); + return static_cast(*this); + } + + card_extension::card const& card_extension::constraint::to_card() const{ + SASSERT(is_card()); + return static_cast(*this); + } + + card_extension::pb& card_extension::constraint::to_pb() { + SASSERT(is_pb()); + return static_cast(*this); + } + + card_extension::pb const& card_extension::constraint::to_pb() const{ + SASSERT(is_pb()); + return static_cast(*this); + } + + card_extension::xor& card_extension::constraint::to_xor() { + SASSERT(is_xor()); + return static_cast(*this); + } + + card_extension::xor const& card_extension::constraint::to_xor() const{ + SASSERT(is_xor()); + return static_cast(*this); + } + + card_extension::card::card(literal lit, literal_vector const& lits, unsigned k): + constraint(card_t, lit, lits.size()), + m_k(k) { + for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; } } @@ -41,37 +69,47 @@ namespace sat { SASSERT(m_size >= m_k && m_k > 0); } - std::ostream& operator<<(std::ostream& out, card_extension::card const& c) { - if (c.lit() != null_literal) { - out << c.lit() << " == "; + std::ostream& operator<<(std::ostream& out, card_extension::constraint const& cnstr) { + if (cnstr.lit() != null_literal) out << cnstr.lit() << " == "; + switch (cnstr.tag()) { + case card_extension::card_t: { + card_extension::card const& c = cnstr.to_card(); + for (literal l : c) { + out << l << " "; + } + out << " >= " << c.k(); + break; } - for (literal l : c) { - out << l << " "; + case card_extension::pb_t: { + card_extension::pb const& p = cnstr.to_pb(); + for (card_extension::wliteral wl : p) { + if (wl.first != 1) out << wl.first << " * "; + out << wl.second << " "; + } + out << " >= " << p.k(); + break; } - return out << " >= " << c.k(); + case card_extension::xor_t: { + card_extension::xor const& x = cnstr.to_xor(); + for (unsigned i = 0; i < x.size(); ++i) { + out << x[i] << " "; + if (i + 1 < x.size()) out << "x "; + } + break; + } + default: + UNREACHABLE(); + } + return out; } - std::ostream& operator<<(std::ostream& out, card_extension::pb const& p) { - if (p.lit() != null_literal) { - out << p.lit() << " == "; - } - for (card_extension::wliteral wl : p) { - if (wl.first != 1) out << wl.first << " * "; - out << wl.second << " "; - } - return out << " >= " << p.k(); - } - - - card_extension::pb::pb(unsigned index, literal lit, svector const& wlits, unsigned k): - m_index(index), - m_lit(lit), + card_extension::pb::pb(literal lit, svector const& wlits, unsigned k): + constraint(pb_t, lit, wlits.size()), m_k(k), - m_size(wlits.size()), m_slack(0), m_num_watch(0), m_max_sum(0) { - for (unsigned i = 0; i < wlits.size(); ++i) { + for (unsigned i = 0; i < size(); ++i) { m_wlits[i] = wlits[i]; } update_max_sum(); @@ -97,13 +135,11 @@ namespace sat { m_k = w - m_k + 1; SASSERT(w >= m_k && m_k > 0); } - - card_extension::xor::xor(unsigned index, literal lit, literal_vector const& lits): - m_index(index), - m_lit(lit), - m_size(lits.size()) + + card_extension::xor::xor(literal lit, literal_vector const& lits): + constraint(xor_t, lit, lits.size()) { - for (unsigned i = 0; i < lits.size(); ++i) { + for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; } } @@ -164,7 +200,7 @@ namespace sat { } else { for (unsigned i = 0; i <= bound; ++i) { - watch_literal(c, c[i]); + watch_literal(c[i], c); } } } @@ -176,10 +212,14 @@ namespace sat { } } - void card_extension::unwatch_literal(literal lit, card& c) { + void card_extension::unwatch_literal(literal lit, constraint& c) { get_wlist(~lit).erase(watched(c.index())); } + void card_extension::watch_literal(literal lit, constraint& c) { + get_wlist(~lit).push_back(watched(c.index())); + } + void card_extension::assign(card& c, literal lit) { switch (value(lit)) { case l_true: @@ -208,11 +248,6 @@ namespace sat { } } - void card_extension::watch_literal(card& c, literal lit) { - TRACE("sat_verbose", tout << "watch: " << lit << "\n";); - get_wlist(~lit).push_back(watched(c.index())); - } - void card_extension::set_conflict(card& c, literal lit) { m_stats.m_num_card_conflicts++; TRACE("sat", display(tout, c, true); ); @@ -224,16 +259,6 @@ namespace sat { // pb: - void card_extension::copy_pb(card_extension& result) { - for (pb* p : m_pbs) { - if (!p) continue; - svector wlits; - for (wliteral w : *p) { - wlits.push_back(w); - } - result.add_pb_ge(p->lit(), wlits, p->k()); - } - } // watch a prefix of literals, such that the slack of these is >= k void card_extension::init_watch(pb& p, bool is_true) { @@ -279,111 +304,112 @@ namespace sat { } else { for (unsigned i = 0; i < num_watch; ++i) { - watch_literal(p, p[i]); + watch_literal(p[i], p); } -p.set_slack(slack); -p.set_num_watch(num_watch); - } - TRACE("sat", display(tout << "init watch: ", p, true);); - } + p.set_slack(slack); + p.set_num_watch(num_watch); + } + TRACE("sat", display(tout << "init watch: ", p, true);); + } - /* - Chai Kuhlmann: - Lw - set of watched literals - Lu - set of unwatched literals that are not false + /* + Chai Kuhlmann: + Lw - set of watched literals + Lu - set of unwatched literals that are not false + + Lw = Lw \ { alit } + Sw -= value + a_max = max { a | l in Lw u Lu, l = undef } + while (Sw < k + a_max & Lu != 0) { + a_s = max { a | l in Lu } + Sw += a_s + Lw = Lw u {l_s} + Lu = Lu \ {l_s} + } + if (Sw < k) conflict + while (Sw < k + a_max) { + assign (l_max) + a_max = max { ai | li in Lw, li = undef } + } + ASSERT(Sw >= bound) + return no-conflict - Lw = Lw \ { alit } - Sw -= value - a_max = max { a | l in Lw u Lu, l = undef } - while (Sw < k + a_max & Lu != 0) { - a_s = max { a | l in Lu } - Sw += a_s - Lw = Lw u {l_s} - Lu = Lu \ {l_s} - } - if (Sw < k) conflict - while (Sw < k + a_max) { - assign (l_max) - a_max = max { ai | li in Lw, li = undef } - } - ASSERT(Sw >= bound) - return no-conflict - - a_max index: index of non-false literal with maximal weight. + a_max index: index of non-false literal with maximal weight. - */ - void card_extension::add_index(pb& p, unsigned index, literal lit) { - if (value(lit) == l_undef) { - m_pb_undef.push_back(index); - if (p[index].first > m_a_max) { - m_a_max = p[index].first; - } - } - } - - lbool card_extension::add_assign(pb& p, literal alit) { - - TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); - SASSERT(!inconsistent()); - unsigned sz = p.size(); - unsigned bound = p.k(); - unsigned num_watch = p.num_watch(); - unsigned slack = p.slack(); - SASSERT(value(alit) == l_false); - SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); - SASSERT(num_watch <= sz); - SASSERT(num_watch > 0); - unsigned index = 0; - m_a_max = 0; - m_pb_undef.reset(); - for (; index < num_watch; ++index) { - literal lit = p[index].second; - if (lit == alit) { - break; - } - add_index(p, index, lit); - } - SASSERT(index < num_watch); - - unsigned index1 = index + 1; - for (; m_a_max == 0 && index1 < num_watch; ++index1) { - add_index(p, index1, p[index1].second); - } - - unsigned val = p[index].first; - SASSERT(value(p[index].second) == l_false); - SASSERT(val <= slack); - slack -= val; - // find literals to swap with: - for (unsigned j = num_watch; j < sz && slack < bound + m_a_max; ++j) { - literal lit = p[j].second; - if (value(lit) != l_false) { - slack += p[j].first; - watch_literal(p, p[j]); - p.swap(num_watch, j); - add_index(p, num_watch, lit); - ++num_watch; - } - } - - SASSERT(!inconsistent()); - DEBUG_CODE(for (auto idx : m_pb_undef) { SASSERT(value(p[idx].second) == l_undef); }); - - if (slack < bound) { - // maintain watching the literal - slack += val; - p.set_slack(slack); - p.set_num_watch(num_watch); - SASSERT(bound <= slack); - TRACE("sat", tout << "conflict " << alit << "\n";); - set_conflict(p, alit); - return l_false; - } - - if (index > p.size() || num_watch > p.size()) { - std::cout << "size: " << p.size() << "index: " << index << " num watch: " << num_watch << "\n"; - } + */ + void card_extension::add_index(pb& p, unsigned index, literal lit) { + if (value(lit) == l_undef) { + m_pb_undef.push_back(index); + if (p[index].first > m_a_max) { + m_a_max = p[index].first; + } + } + } + + lbool card_extension::add_assign(pb& p, literal alit) { + + TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + SASSERT(!inconsistent()); + unsigned sz = p.size(); + unsigned bound = p.k(); + unsigned num_watch = p.num_watch(); + unsigned slack = p.slack(); + SASSERT(value(alit) == l_false); + SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); + SASSERT(num_watch <= sz); + SASSERT(num_watch > 0); + unsigned index = 0; + m_a_max = 0; + m_pb_undef.reset(); + for (; index < num_watch; ++index) { + literal lit = p[index].second; + if (lit == alit) { + break; + } + add_index(p, index, lit); + } + SASSERT(index < num_watch); + + unsigned index1 = index + 1; + for (; m_a_max == 0 && index1 < num_watch; ++index1) { + add_index(p, index1, p[index1].second); + } + + unsigned val = p[index].first; + SASSERT(value(p[index].second) == l_false); + SASSERT(val <= slack); + slack -= val; + // find literals to swap with: + for (unsigned j = num_watch; j < sz && slack < bound + m_a_max; ++j) { + literal lit = p[j].second; + if (value(lit) != l_false) { + slack += p[j].first; + watch_literal(p[j], p); + p.swap(num_watch, j); + add_index(p, num_watch, lit); + ++num_watch; + } + } + + SASSERT(!inconsistent()); + DEBUG_CODE(for (auto idx : m_pb_undef) { SASSERT(value(p[idx].second) == l_undef); }); + + if (slack < bound) { + // maintain watching the literal + slack += val; + p.set_slack(slack); + p.set_num_watch(num_watch); + SASSERT(bound <= slack); + TRACE("sat", tout << "conflict " << alit << "\n";); + set_conflict(p, alit); + return l_false; + } + + if (index > p.size() || num_watch > p.size() || num_watch == 0) { + display(std::cout, p, true); + std::cout << "size: " << p.size() << "index: " << index << " num watch: " << num_watch << "\n"; + } // swap out the watched literal. --num_watch; SASSERT(num_watch > 0); @@ -419,9 +445,8 @@ p.set_num_watch(num_watch); return l_undef; } - void card_extension::watch_literal(pb& p, wliteral l) { - literal lit = l.second; - get_wlist(~lit).push_back(watched(p.index())); + void card_extension::watch_literal(wliteral l, pb& p) { + watch_literal(l.second, p); } void card_extension::clear_watch(pb& p) { @@ -431,10 +456,6 @@ p.set_num_watch(num_watch); } } - void card_extension::unwatch_literal(literal lit, pb& p) { - get_wlist(~lit).erase(watched(p.index())); - } - void card_extension::set_conflict(pb& p, literal lit) { m_stats.m_num_pb_conflicts++; TRACE("sat", display(tout, p, true); ); @@ -596,23 +617,13 @@ p.set_num_watch(num_watch); } } - void card_extension::nullify_tracking_literal(pb& p) { - if (p.lit() != null_literal) { - get_wlist(p.lit()).erase(watched(p.index())); - get_wlist(~p.lit()).erase(watched(p.index())); - p.nullify_literal(); - } - } - void card_extension::remove_constraint(pb& p) { clear_watch(p); nullify_tracking_literal(p); - m_pbs[index2position(p.index())] = 0; - dealloc(&p); + p.remove(); + m_constraint_removed = true; } - - void card_extension::display(std::ostream& out, pb const& p, bool values) const { if (p.lit() != null_literal) out << p.lit() << " == "; if (p.lit() != null_literal && values) { @@ -644,23 +655,11 @@ p.set_num_watch(num_watch); // xor: - void card_extension::copy_xor(card_extension& result) { - for (xor* x : m_xors) { - literal_vector lits; - for (literal l : *x) lits.push_back(l); - result.add_xor(x->lit(), lits); - } - } - void card_extension::clear_watch(xor& x) { unwatch_literal(x[0], x); unwatch_literal(x[1], x); } - void card_extension::unwatch_literal(literal lit, xor& c) { - get_wlist(~lit).erase(watched(c.index())); - } - bool card_extension::parity(xor const& x, unsigned offset) const { bool odd = false; unsigned sz = x.size(); @@ -706,8 +705,8 @@ p.set_num_watch(num_watch); break; default: SASSERT(j == 2); - watch_literal(x, x[0]); - watch_literal(x, x[1]); + watch_literal(x[0], x); + watch_literal(x[1], x); break; } } @@ -741,13 +740,6 @@ p.set_num_watch(num_watch); } } - void card_extension::watch_literal(xor& x, literal lit) { - TRACE("sat_verbose", tout << "watch: " << lit << "\n";); - get_wlist(~lit).push_back(watched(x.index())); - TRACE("sat_verbose", tout << "insert: " << lit.var() << " " << lit.sign() << "\n";); - } - - void card_extension::set_conflict(xor& x, literal lit) { m_stats.m_num_xor_conflicts++; TRACE("sat", display(tout, x, true); ); @@ -780,7 +772,7 @@ p.set_num_watch(num_watch); literal lit2 = x[i]; if (value(lit2) == l_undef) { x.swap(index, i); - watch_literal(x, lit2); + watch_literal(lit2, x); return l_undef; } } @@ -947,24 +939,17 @@ p.set_num_watch(num_watch); break; } case justification::EXT_JUSTIFICATION: { - unsigned index = js.get_ext_justification_idx(); - if (is_card_index(index)) { - card& c = index2card(index); + constraint& cnstr = index2constraint(js.get_ext_justification_idx()); + switch (cnstr.tag()) { + case card_t: { + card& c = cnstr.to_card(); m_bound += offset * c.k(); process_card(c, offset); ++m_stats.m_num_card_resolves; + break; } - else if (is_xor_index(index)) { - // jus.push_back(js); - m_lemma.reset(); - m_bound += offset; - inc_coeff(consequent, offset); - get_xor_antecedents(consequent, idx, js, m_lemma); - for (literal l : m_lemma) process_antecedent(~l, offset); - ++m_stats.m_num_xor_resolves; - } - else if (is_pb_index(index)) { - pb& p = index2pb(index); + case pb_t: { + pb& p = cnstr.to_pb(); m_lemma.reset(); m_bound += offset; inc_coeff(consequent, offset); @@ -972,9 +957,21 @@ p.set_num_watch(num_watch); TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";); for (literal l : m_lemma) process_antecedent(~l, offset); ++m_stats.m_num_pb_resolves; + break; } - else { + case xor_t: { + // jus.push_back(js); + m_lemma.reset(); + m_bound += offset; + inc_coeff(consequent, offset); + get_xor_antecedents(consequent, idx, js, m_lemma); + for (literal l : m_lemma) process_antecedent(~l, offset); + ++m_stats.m_num_xor_resolves; + break; + } + default: UNREACHABLE(); + break; } break; } @@ -1177,8 +1174,8 @@ p.set_num_watch(num_watch); card_extension::~card_extension() { m_stats.reset(); - while (!m_index_trail.empty()) { - clear_index_trail_back(); + while (!m_constraints.empty()) { + pop_constraint(); } } @@ -1188,109 +1185,75 @@ p.set_num_watch(num_watch); } void card_extension::add_at_least(literal lit, literal_vector const& lits, unsigned k) { - unsigned index = 4*m_cards.size(); - SASSERT(is_card_index(index)); - card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(index, lit, lits, k); - if (lit != null_literal) s().set_external(lit.var()); - m_cards.push_back(c); - init_watch(*c); - } - - void card_extension::init_watch(card& c) { - unsigned index = c.index(); - literal lit = c.lit(); - m_index_trail.push_back(index); - if (lit == null_literal) { - // it is an axiom. - init_watch(c, true); - } - else { - get_wlist(lit).push_back(index); - get_wlist(~lit).push_back(index); - } + card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(lit, lits, k); + add_constraint(c); } - void card_extension::add_pb_ge(literal lit, svector const& wlits, unsigned k) { - unsigned index = 4*m_pbs.size() + 0x3; - SASSERT(is_pb_index(index)); - pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(index, lit, wlits, k); - m_pbs.push_back(p); - m_index_trail.push_back(index); + void card_extension::add_constraint(constraint* c) { + m_constraints.push_back(c); + literal lit = c->lit(); if (lit == null_literal) { - init_watch(*p, true); + init_watch(*c, true); } else { s().set_external(lit.var()); - get_wlist(lit).push_back(index); - get_wlist(~lit).push_back(index); + get_wlist(lit).push_back(c->index()); + get_wlist(~lit).push_back(c->index()); } } + + void card_extension::init_watch(constraint& c, bool is_true) { + switch (c.tag()) { + case card_t: init_watch(c.to_card(), is_true); break; + case pb_t: init_watch(c.to_pb(), is_true); break; + case xor_t: init_watch(c.to_xor(), is_true); break; + } + } + + lbool card_extension::add_assign(constraint& c, literal l) { + switch (c.tag()) { + case card_t: return add_assign(c.to_card(), l); + case pb_t: return add_assign(c.to_pb(), l); + case xor_t: return add_assign(c.to_xor(), l); + } + UNREACHABLE(); + return l_undef; + } + + void card_extension::add_pb_ge(literal lit, svector const& wlits, unsigned k) { + pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(lit, wlits, k); + add_constraint(p); + } + void card_extension::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { literal lit = v == null_bool_var ? null_literal : literal(v, false); add_pb_ge(lit, wlits, k); } - void card_extension::add_xor(bool_var v, literal_vector const& lits) { add_xor(literal(v, false), lits); } void card_extension::add_xor(literal lit, literal_vector const& lits) { - unsigned index = 4*m_xors.size() + 0x1; - SASSERT(is_xor_index(index)); - xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(index, lit, lits); - m_xors.push_back(x); - s().set_external(lit.var()); - for (literal l : lits) s().set_external(l.var()); - get_wlist(lit).push_back(index); - get_wlist(~lit).push_back(index); - m_index_trail.push_back(index); + xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(lit, lits); + add_constraint(x); + for (literal l : lits) s().set_external(l.var()); // TBD: determine if goal2sat does this. } void card_extension::propagate(literal l, ext_constraint_idx idx, bool & keep) { SASSERT(value(l) == l_true); TRACE("sat", tout << l << " " << idx << "\n";); - if (is_pb_index(idx)) { - pb& p = index2pb(idx); - if (p.lit() != null_literal && l.var() == p.lit().var()) { - init_watch(p, !l.sign()); - keep = true; - } - else if (p.lit() != null_literal && value(p.lit()) != l_true) { - keep = false; - } - else { - keep = l_undef != add_assign(p, ~l); - } + constraint& c = index2constraint(idx); + if (c.lit() != null_literal && l.var() == c.lit().var()) { + init_watch(c, !l.sign()); + keep = true; } - else if (is_card_index(idx)) { - card& c = index2card(idx); - if (c.lit() != null_literal && l.var() == c.lit().var()) { - init_watch(c, !l.sign()); - keep = true; - } - else if (c.lit() != null_literal && value(c.lit()) != l_true) { - keep = false; - } - else { - keep = l_undef != add_assign(c, ~l); - } - } - else if (is_xor_index(idx)) { - xor& x = index2xor(idx); - if (l.var() == x.lit().var()) { - init_watch(x, !l.sign()); - } - else if (x.lit() != null_literal && value(x.lit()) != l_true) { - keep = false; - } - else { - keep = l_undef != add_assign(x, ~l); - } + else if (c.lit() != null_literal && value(c.lit()) != l_true) { + keep = false; } else { - UNREACHABLE(); + keep = l_undef != add_assign(c, ~l); } } @@ -1324,7 +1287,7 @@ p.set_num_watch(num_watch); unsigned level = lvl(l); bool_var v = l.var(); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); - SASSERT(is_xor_index(js.get_ext_justification_idx())); + SASSERT(index2constraint(index).is_xor()); TRACE("sat", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); unsigned num_marks = 0; @@ -1332,12 +1295,12 @@ p.set_num_watch(num_watch); while (true) { ++count; if (js.get_kind() == justification::EXT_JUSTIFICATION) { - unsigned idx = js.get_ext_justification_idx(); - if (!is_xor_index(idx)) { + constraint& c = index2constraint(js.get_ext_justification_idx()); + if (!c.is_xor()) { r.push_back(l); } else { - xor& x = index2xor(idx); + xor& x = c.to_xor(); if (x.lit() != null_literal && lvl(x.lit()) > 0) r.push_back(x.lit()); if (x[1].var() == l.var()) { x.swap(0, 1); @@ -1485,21 +1448,16 @@ p.set_num_watch(num_watch); } void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { - if (is_card_index(idx)) { - get_card_antecedents(l, index2card(idx), r); - } - else if (is_xor_index(idx)) { - get_xor_antecedents(l, index2xor(idx), r); - } - else if (is_pb_index(idx)) { - get_pb_antecedents(l, index2pb(idx), r); - } - else { - UNREACHABLE(); + constraint& c = index2constraint(idx); + switch (c.tag()) { + case card_t: get_card_antecedents(l, c.to_card(), r); break; + case pb_t: get_pb_antecedents(l, c.to_pb(), r); break; + case xor_t: get_xor_antecedents(l, c.to_xor(), r); break; + default: UNREACHABLE(); break; } } - void card_extension::nullify_tracking_literal(card& c) { + void card_extension::nullify_tracking_literal(constraint& c) { if (c.lit() != null_literal) { get_wlist(c.lit()).erase(watched(c.index())); get_wlist(~c.lit()).erase(watched(c.index())); @@ -1510,8 +1468,8 @@ p.set_num_watch(num_watch); void card_extension::remove_constraint(card& c) { clear_watch(c); nullify_tracking_literal(c); - m_cards[index2position(c.index())] = 0; - dealloc(&c); + c.remove(); + m_constraint_removed = true; } void card_extension::simplify(card& c) { @@ -1628,7 +1586,7 @@ p.set_num_watch(num_watch); literal lit2 = c[i]; if (value(lit2) != l_false) { c.swap(index, i); - watch_literal(c, lit2); + watch_literal(lit2, c); return l_undef; } } @@ -1664,78 +1622,78 @@ p.set_num_watch(num_watch); check_result card_extension::check() { return CR_DONE; } void card_extension::push() { - m_index_lim.push_back(m_index_trail.size()); + m_constraint_lim.push_back(m_constraints.size()); } - void card_extension::clear_index_trail_back() { - unsigned index = m_index_trail.back(); - m_index_trail.pop_back(); - if (is_card_index(index)) { - card* c = m_cards.back(); - if (c) { - SASSERT(c->index() == index); - clear_watch(*c); // can skip during finalization - dealloc(c); - } - m_cards.pop_back(); - } - else if (is_pb_index(index)) { - pb* p = m_pbs.back(); - if (p) { - SASSERT(p->index() == index); - clear_watch(*p); // can skip during finalization - dealloc(p); - } - m_pbs.pop_back(); - } - else if (is_xor_index(index)) { - xor* x = m_xors.back(); - if (x) { - SASSERT(x->index() == index); - clear_watch(*x); // can skip during finalization - dealloc(x); - } - m_xors.pop_back(); - } - else { + void card_extension::pop_constraint() { + constraint* c = m_constraints.back(); + m_constraints.pop_back(); + nullify_tracking_literal(*c); + switch (c->tag()) { + case card_t: + clear_watch(c->to_card()); + break; + case pb_t: + clear_watch(c->to_pb()); + break; + case xor_t: + clear_watch(c->to_xor()); + break; + default: UNREACHABLE(); } + dealloc(c); } void card_extension::pop(unsigned n) { TRACE("sat_verbose", tout << "pop:" << n << "\n";); - unsigned new_lim = m_index_lim.size() - n; - unsigned sz = m_index_lim[new_lim]; - while (m_index_trail.size() > sz) { - clear_index_trail_back(); + unsigned new_lim = m_constraint_lim.size() - n; + unsigned sz = m_constraint_lim[new_lim]; + while (m_constraints.size() > sz) { + pop_constraint(); } - m_index_lim.resize(new_lim); + m_constraint_lim.resize(new_lim); m_num_propagations_since_pop = 0; } + void card_extension::simplify(constraint& c) { + switch (c.tag()) { + case card_t: + simplify(c.to_card()); + break; + case pb_t: + simplify(c.to_pb()); + break; + case xor_t: + simplify(c.to_xor()); + break; + default: + UNREACHABLE(); + } + } + void card_extension::simplify() { return; - s().pop_to_base_level(); + if (!s().at_base_lvl()) s().pop_to_base_level(); unsigned trail_sz; do { m_simplify_change = false; + m_clause_removed = false; + m_constraint_removed = false; trail_sz = s().init_trail_size(); - for (card* c : m_cards) { - if (c) simplify(*c); - } - for (pb* p : m_pbs) { - if (p) simplify(*p); - } - for (xor* x : m_xors) { - if (x) simplify(*x); - } + for (constraint* c : m_constraints) simplify(*c); gc(); + cleanup_clauses(); + cleanup_constraints(); } while (m_simplify_change || trail_sz < s().init_trail_size()); // or could create queue of constraints that are affected } bool card_extension::set_root(literal l, literal r) { + if (s().is_assumption(l.var())) { + return false; + } for (unsigned i = m_roots.size(); i < 2 * s().num_vars(); ++i) { m_roots.push_back(to_literal(i)); } @@ -1747,16 +1705,23 @@ p.set_num_watch(num_watch); void card_extension::flush_roots() { if (m_roots.empty()) return; m_visited.resize(s().num_vars()*2, false); - for (card* c : m_cards) { - if (c) flush_roots(*c); + m_constraint_removed = false; + for (constraint* c : m_constraints) { + switch (c->tag()) { + case card_t: + flush_roots(c->to_card()); + break; + case pb_t: + flush_roots(c->to_pb()); + break; + case xor_t: + flush_roots(c->to_xor()); + break; + default: + UNREACHABLE(); + } } - for (pb* p : m_pbs) { - if (p) flush_roots(*p); - } - for (xor* x : m_xors) { - if (x) flush_roots(*x); - } - + cleanup_constraints(); // display(std::cout << "flush roots\n"); } @@ -1805,49 +1770,53 @@ p.set_num_watch(num_watch); } void card_extension::recompile(card& c) { - m_count.resize(2*s().num_vars(), 0); + IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); + m_weights.resize(2*s().num_vars(), 0); for (literal l : c) { - ++m_count[l.index()]; + ++m_weights[l.index()]; } unsigned k = c.k(); bool is_card = true; unsigned sz = c.size(); + unsigned_vector coeffs; for (unsigned i = 0; i < sz && 0 < k; ++i) { literal l = c[i]; - while (k > 0 && - m_count[l.index()] > 0 && - m_count[(~l).index()] > 0) { - --m_count[l.index()]; - --m_count[(~l).index()]; - --k; - } - unsigned w = m_count[l.index()]; - if (w > 0) { - is_card &= w == 1; - } - else { + unsigned w = m_weights[l.index()]; + unsigned w2 = m_weights[(~l).index()]; + if (w == 0 || w < w2) { c.swap(i, sz - 1); --sz; --i; } + else if (k <= w2) { + k = 0; + break; + } + else { + SASSERT(w2 <= w && w2 < k); + k -= w2; + w -= w2; + m_weights[(~l).index()] = 0; + m_weights[l.index()] = 0; + if (w == 0) { + c.swap(i, sz - 1); + --sz; + --i; + } + else { + is_card &= (w == 1); + coeffs.push_back(w); + } + } } c.update_size(sz); c.update_k(k); - svector wlits; - if (!is_card) { - for (literal l : c) { - unsigned w = m_count[l.index()]; - if (w > 0) { - wlits.push_back(wliteral(w, l)); - } - } - } - - // clear counts: + // clear weights for (literal l : c) { - m_count[l.index()] = 0; - } + m_weights[l.index()] = 0; + m_weights[(~l).index()] = 0; + } if (k == 0) { remove_constraint(c); @@ -1859,10 +1828,15 @@ p.set_num_watch(num_watch); if (!is_card) { TRACE("sat", tout << "replacing by pb: " << c << "\n";); + svector wlits; + for (unsigned i = 0; i < sz; ++i) { + wlits.push_back(wliteral(coeffs[i], c[i])); + } remove_constraint(c); add_pb_ge(root, wlits, k); } else { + IF_VERBOSE(0, verbose_stream() << "new: " << c << "\n";); if (c.lit() != root) { nullify_tracking_literal(c); c.update_literal(root); @@ -1877,36 +1851,47 @@ p.set_num_watch(num_watch); } void card_extension::recompile(pb& p) { - m_count.resize(2*s().num_vars(), 0); + IF_VERBOSE(0, verbose_stream() << "re: " << p << "\n";); + m_weights.resize(2*s().num_vars(), 0); for (wliteral wl : p) { - m_count[wl.second.index()] += wl.first; + m_weights[wl.second.index()] += wl.first; } unsigned k = p.k(); unsigned sz = p.size(); for (unsigned i = 0; i < sz && 0 < k; ++i) { wliteral wl = p[i]; literal l = wl.second; - if (m_count[l.index()] >= m_count[(~l).index()]) { - if (k < m_count[(~l).index()]) { - k = 0; - break; - } - k -= m_count[(~l).index()]; - m_count[l.index()] -= m_count[(~l).index()]; - } - unsigned w = m_count[l.index()]; - if (w == 0) { + unsigned w = m_weights[l.index()]; + unsigned w2 = m_weights[(~l).index()]; + if (w == 0 || w < w2) { p.swap(i, sz - 1); --sz; --i; } + else if (k <= w2) { + k = 0; + break; + } else { - p[i] = wliteral(w, l); + SASSERT(w2 <= w && w2 < k); + k -= w2; + w -= w2; + m_weights[l.index()] = 0; + m_weights[(~l).index()] = 0; + if (w == 0) { + p.swap(i, sz - 1); + --sz; + --i; + } + else { + p[i] = wliteral(w, l); + } } } - // clear counts: + // clear weights for (wliteral wl : p) { - m_count[wl.second.index()] = 0; + m_weights[wl.second.index()] = 0; + m_weights[(~wl.second).index()] = 0; } if (k == 0) { @@ -1917,9 +1902,17 @@ p.set_num_watch(num_watch); p.update_size(sz); p.update_k(k); + for (unsigned i = 0; i < sz; ++i) { + wliteral wl = p[i]; + unsigned w = std::min(k, wl.first); + p[i] = wliteral(w, wl.second); + } + literal root = null_literal; if (p.lit() != null_literal) root = m_roots[p.lit().index()]; + IF_VERBOSE(0, verbose_stream() << "new: " << p << "\n";); + // std::cout << "simplified " << p << "\n"; if (p.lit() != root) { nullify_tracking_literal(p); @@ -2003,77 +1996,90 @@ p.set_num_watch(num_watch); m_clause_use_list.init(s().num_vars()); m_var_used.reset(); m_var_used.resize(s().num_vars(), false); - m_card_use_list.reset(); - m_card_use_list.resize(2*s().num_vars(), false); - for (clause* c : s().m_clauses) if (!c->frozen()) m_clause_use_list.insert(*c); - for (card* c : m_cards) { - if (c) { - if (c->lit() != null_literal) { - m_card_use_list[c->lit().index()].push_back(c->index()); - m_card_use_list[(~c->lit()).index()].push_back(c->index()); - for (literal l : *c) m_card_use_list[(~l).index()].push_back(c->index()); - - } - for (literal l : *c) { - m_var_used[l.var()] = true; - m_card_use_list[l.index()].push_back(c->index()); - } - } + m_cnstr_use_list.reset(); + m_cnstr_use_list.resize(2*s().num_vars()); + for (clause* c : s().m_clauses) { + if (!c->frozen()) + m_clause_use_list.insert(*c); } - for (pb* p : m_pbs) { - if (p) { - if (p->lit() != null_literal) { - m_card_use_list[p->lit().index()].push_back(p->index()); - m_card_use_list[(~p->lit()).index()].push_back(p->index()); - for (wliteral wl : *p) m_card_use_list[(~wl.second).index()].push_back(p->index()); - } - for (wliteral wl : *p) { + for (constraint* cp : m_constraints) { + literal lit = cp->lit(); + if (lit != null_literal) { + m_cnstr_use_list[lit.index()].push_back(cp); + m_cnstr_use_list[(~lit).index()].push_back(cp); + } + switch (cp->tag()) { + case card_t: { + card& c = cp->to_card(); + for (literal l : c) { + m_var_used[l.var()] = true; + m_cnstr_use_list[l.index()].push_back(&c); + if (lit != null_literal) m_cnstr_use_list[(~l).index()].push_back(&c); + } + break; + } + case pb_t: { + pb& p = cp->to_pb(); + for (wliteral wl : p) { literal l = wl.second; m_var_used[l.var()] = true; - m_card_use_list[l.index()].push_back(p->index()); + m_cnstr_use_list[l.index()].push_back(&p); + if (lit != null_literal) m_cnstr_use_list[(~l).index()].push_back(&p); } + break; } - } - for (xor* x : m_xors) { - if (x) { - m_card_use_list[x->lit().index()].push_back(x->index()); - m_card_use_list[(~x->lit()).index()].push_back(x->index()); - m_var_used[x->lit().var()] = true; - for (literal l : *x) { + case xor_t: { + xor& x = cp->to_xor(); + m_var_used[x.lit().var()] = true; + for (literal l : x) { m_var_used[l.var()] = true; - m_card_use_list[l.index()].push_back(x->index()); - m_card_use_list[(~l).index()].push_back(x->index()); + m_cnstr_use_list[l.index()].push_back(&x); + m_cnstr_use_list[(~l).index()].push_back(&x); + } + break; + } + } + } + for (constraint* cp : m_constraints) { + switch (cp->tag()) { + case card_t: { + card& c = cp->to_card(); + if (c.lit() != null_literal && + !m_var_used[c.lit().var()] && + m_clause_use_list.get(c.lit()).empty() && + m_clause_use_list.get(~c.lit()).empty() && + get_num_non_learned_bin(c.lit()) == 0 && + get_num_non_learned_bin(~c.lit()) == 0) { + remove_constraint(c); } + break; + } + case pb_t: { + pb& p = cp->to_pb(); + if (p.lit() != null_literal && + !m_var_used[p.lit().var()] && + m_clause_use_list.get(p.lit()).empty() && + m_clause_use_list.get(~p.lit()).empty() && + get_num_non_learned_bin(p.lit()) == 0 && + get_num_non_learned_bin(~p.lit()) == 0) { + remove_constraint(p); + } + break; + } + default: + break; } } - for (card* c : m_cards) { - if (c && c->lit() != null_literal && - !m_var_used[c->lit().var()] && - m_clause_use_list.get(c->lit()).empty() && - m_clause_use_list.get(~c->lit()).empty() && - get_num_non_learned_bin(c->lit()) == 0 && - get_num_non_learned_bin(~c->lit()) == 0) { - remove_constraint(*c); - } - } - for (pb* p : m_pbs) { - if (p && p->lit() != null_literal && - !m_var_used[p->lit().var()] && - m_clause_use_list.get(p->lit()).empty() && - m_clause_use_list.get(~p->lit()).empty() && - get_num_non_learned_bin(p->lit()) == 0 && - get_num_non_learned_bin(~p->lit()) == 0) { - remove_constraint(*p); - } - } + // take ownership of interface variables - for (card* c : m_cards) if (c && c->lit() != null_literal) m_var_used[c->lit().var()] = true; - for (pb* p : m_pbs) if (p && p->lit() != null_literal) m_var_used[p->lit().var()] = true; + for (constraint* cp : m_constraints) { + if (cp->lit() != null_literal) m_var_used[cp->lit().var()] = true; + } // set variables to be non-external if they are not used in theory constraints. unsigned ext = 0; for (unsigned v = 0; v < s().num_vars(); ++v) { - if (s().is_external(v) && !m_var_used[v]) { + if (s().is_external(v) && !m_var_used[v] && !s().is_assumption(v)) { s().set_non_external(v); ++ext; } @@ -2084,14 +2090,14 @@ p.set_num_watch(num_watch); for (unsigned v = 0; v < s().num_vars(); ++v) { if (!m_var_used[v]) continue; literal lit(v, false); - if (!m_card_use_list[lit.index()].empty() && m_card_use_list[(~lit).index()].empty() && m_clause_use_list.get(~lit).empty() && + if (!m_cnstr_use_list[lit.index()].empty() && m_cnstr_use_list[(~lit).index()].empty() && m_clause_use_list.get(~lit).empty() && get_num_non_learned_bin(~lit) == 0) { s().assign(lit, justification()); ++pure_literals; continue; } lit.neg(); - if (!m_card_use_list[lit.index()].empty() && m_card_use_list[(~lit).index()].empty() && m_clause_use_list.get(~lit).empty() && get_num_non_learned_bin(~lit) == 0) { + if (!m_cnstr_use_list[lit.index()].empty() && m_cnstr_use_list[(~lit).index()].empty() && m_clause_use_list.get(~lit).empty() && get_num_non_learned_bin(~lit) == 0) { s().assign(lit, justification()); ++pure_literals; } @@ -2100,37 +2106,69 @@ p.set_num_watch(num_watch); verbose_stream() << "non-external variables converted: " << ext << "\n"; verbose_stream() << "pure literals converted: " << pure_literals << "\n";); - m_cleanup_clauses = false; unsigned bin_sub = m_stats.m_num_bin_subsumes; unsigned clause_sub = m_stats.m_num_clause_subsumes; unsigned card_sub = m_stats.m_num_card_subsumes; - for (card* c : m_cards) { - if (c && c->k() > 1) { - subsumption(*c); + for (constraint* cp : m_constraints) { + switch (cp->tag()) { + case card_t: { + card& c = cp->to_card(); + if (c.k() > 1) subsumption(c); + break; + } + default: + break; } } IF_VERBOSE(1, verbose_stream() << "binary subsumes: " << m_stats.m_num_bin_subsumes - bin_sub << "\n";); IF_VERBOSE(1, verbose_stream() << "clause subsumes: " << m_stats.m_num_clause_subsumes - clause_sub << "\n";); IF_VERBOSE(1, verbose_stream() << "card subsumes: " << m_stats.m_num_card_subsumes - card_sub << "\n";); - if (m_cleanup_clauses) { - clause_vector::iterator it = s().m_clauses.begin(); - clause_vector::iterator end = s().m_clauses.end(); - clause_vector::iterator it2 = it; - for (; it != end; ++it) { - clause* c = *it; - if (c->was_removed()) { - s().detach_clause(*c); - s().del_clause(*c); - } - else { - if (it2 != it) { - *it2 = *it; - } - ++it2; - } + + } + + void card_extension::cleanup_clauses() { + if (!m_clause_removed) return; + // version in simplify first clears + // all watch literals, then reinserts them. + // this ensures linear time cleanup. + clause_vector::iterator it = s().m_clauses.begin(); + clause_vector::iterator end = s().m_clauses.end(); + clause_vector::iterator it2 = it; + for (; it != end; ++it) { + clause* c = *it; + if (c->was_removed()) { + s().detach_clause(*c); + s().del_clause(*c); + } + else { + if (it2 != it) { + *it2 = *it; + } + ++it2; } - s().m_clauses.set_end(it2); } + s().m_clauses.set_end(it2); + } + + void card_extension::cleanup_constraints() { + if (!m_constraint_removed) return; + ptr_vector::iterator it = m_constraints.begin(); + ptr_vector::iterator it2 = it; + ptr_vector::iterator end = m_constraints.end(); + for (; it != end; ++it) { + constraint& c = *(*it); + if (c.was_removed()) { + dealloc(&c); + } + else { + if (it != it2) { + *it2 = *it; + } + ++it2; + } + } + m_constraints.set_end(it2); + m_constraint_removed = false; } /* @@ -2196,7 +2234,7 @@ p.set_num_watch(num_watch); unsigned occ_count = UINT_MAX; literal lit = null_literal; for (literal l : c) { - unsigned occ_count1 = m_card_use_list[l.index()].size(); + unsigned occ_count1 = m_cnstr_use_list[l.index()].size(); if (occ_count1 < occ_count) { lit = l; occ_count = occ_count1; @@ -2207,14 +2245,11 @@ p.set_num_watch(num_watch); void card_extension::card_subsumption(card& c1, literal lit) { literal_vector slit; - for (unsigned index : m_card_use_list[lit.index()]) { - if (!is_card_index(index) || index == c1.index()) { + for (constraint* c : m_cnstr_use_list[lit.index()]) { + if (!c || c->tag() != card_t || c == &c1) { continue; } - // c2 could be null - card* c = m_cards[index2position(index)]; - if (!c) continue; - card& c2 = *c; + card& c2 = c->to_card(); SASSERT(c1.index() != c2.index()); if (subsumes(c1, c2, slit)) { @@ -2252,7 +2287,7 @@ p.set_num_watch(num_watch); if (slit.empty()) { TRACE("sat", tout << "remove\n" << c1 << "\n" << c2 << "\n";); //c2.set_removed(true); - //m_cleanup_clauses = true; + //m_clause_removed = true; ++m_stats.m_num_clause_subsumes; } else { @@ -2307,28 +2342,51 @@ p.set_num_watch(num_watch); lbool card_extension::get_phase(bool_var v) { return l_undef; } - void card_extension::copy_card(card_extension& result) { - for (card* c : m_cards) { - if (!c) continue; - literal_vector lits; - for (literal l : *c) lits.push_back(l); - result.add_at_least(c->lit(), lits, c->k()); - } - } + extension* card_extension::copy(solver* s) { card_extension* result = alloc(card_extension); result->set_solver(s); - copy_card(*result); - copy_xor(*result); - copy_pb(*result); + literal_vector lits; + svector wlits; + for (constraint* cp : m_constraints) { + switch (cp->tag()) { + case card_t: { + card const& c = cp->to_card(); + lits.reset(); + for (literal l : c) lits.push_back(l); + result->add_at_least(c.lit(), lits, c.k()); + break; + } + case pb_t: { + pb const& p = cp->to_pb(); + wlits.reset(); + for (wliteral w : p) { + wlits.push_back(w); + } + result->add_pb_ge(p.lit(), wlits, p.k()); + break; + } + case xor_t: { + xor const& x = cp->to_xor(); + lits.reset(); + for (literal l : x) lits.push_back(l); + result->add_xor(x.lit(), lits); + break; + } + default: + UNREACHABLE(); + } + } + return result; } void card_extension::find_mutexes(literal_vector& lits, vector & mutexes) { literal_set slits(lits); bool change = false; - for (unsigned i = 0; i < m_cards.size(); ++i) { - card& c = *m_cards[i]; + for (constraint* cp : m_constraints) { + if (!cp->is_card()) continue; + card const& c = cp->to_card(); if (c.size() == c.k() + 1) { literal_vector mux; for (unsigned j = 0; j < c.size(); ++j) { @@ -2424,52 +2482,27 @@ p.set_num_watch(num_watch); } std::ostream& card_extension::display(std::ostream& out) const { - for (card* c : m_cards) { - if (c) out << *c << "\n"; - } - for (pb* p : m_pbs) { - if (p) out << *p << "\n"; - } - for (xor* x : m_xors) { - if (x) display(out, *x, false); + for (constraint const* c : m_constraints) { + switch (c->tag()) { + case card_t: + out << c->to_card() << "\n"; + break; + case pb_t: + out << c->to_pb() << "\n"; + break; + case xor_t: + display(out, c->to_xor(), false); + break; + default: + UNREACHABLE(); + } } return out; } std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const { - if (is_card_index(idx)) { - card& c = index2card(idx); - out << "bound "; - if (c.lit() != null_literal) out << c.lit(); - out << ": "; - for (unsigned i = 0; i < c.size(); ++i) { - out << c[i] << " "; - } - out << ">= " << c.k(); - } - else if (is_xor_index(idx)) { - xor& x = index2xor(idx); - out << "xor "; - if (x.lit() != null_literal) out << x.lit(); - out << ": "; - for (unsigned i = 0; i < x.size(); ++i) { - out << x[i] << " "; - } - } - else if (is_pb_index(idx)) { - pb& p = index2pb(idx); - out << "pb "; - if (p.lit() != null_literal) out << p.lit(); - out << ": "; - for (unsigned i = 0; i < p.size(); ++i) { - out << p[i].first << "*" << p[i].second << " "; - } - out << ">= " << p.k(); - } - else { - UNREACHABLE(); - } - return out; + constraint const& cnstr = index2constraint(idx); + return out << index2constraint(idx); } void card_extension::collect_statistics(statistics& st) const { @@ -2546,61 +2579,68 @@ p.set_num_watch(num_watch); } } - void card_extension::justification2pb(justification const& js, literal lit, unsigned offset, ineq& p) { + void card_extension::justification2pb(justification const& js, literal lit, unsigned offset, ineq& ineq) { switch (js.get_kind()) { case justification::NONE: - p.reset(offset); - p.push(lit, offset); + ineq.reset(offset); + ineq.push(lit, offset); break; case justification::BINARY: - p.reset(offset); - p.push(lit, offset); - p.push(js.get_literal(), offset); + ineq.reset(offset); + ineq.push(lit, offset); + ineq.push(js.get_literal(), offset); break; case justification::TERNARY: - p.reset(offset); - p.push(lit, offset); - p.push(js.get_literal1(), offset); - p.push(js.get_literal2(), offset); + ineq.reset(offset); + ineq.push(lit, offset); + ineq.push(js.get_literal1(), offset); + ineq.push(js.get_literal2(), offset); break; case justification::CLAUSE: { - p.reset(offset); + ineq.reset(offset); clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) - p.push(c[i], offset); + ineq.push(c[i], offset); break; } case justification::EXT_JUSTIFICATION: { - unsigned index = js.get_ext_justification_idx(); - if (is_card_index(index)) { - card& c = index2card(index); - p.reset(offset*c.k()); + ext_justification_idx index = js.get_ext_justification_idx(); + constraint& cnstr = index2constraint(index); + switch (cnstr.tag()) { + case card_t: { + card& c = cnstr.to_card(); + ineq.reset(offset*c.k()); for (unsigned i = 0; i < c.size(); ++i) { - p.push(c[i], offset); + ineq.push(c[i], offset); } - if (c.lit() != null_literal) p.push(~c.lit(), offset*c.k()); + if (c.lit() != null_literal) ineq.push(~c.lit(), offset*c.k()); + break; } - else if (is_xor_index(index)) { + case pb_t: { + pb& p = cnstr.to_pb(); + ineq.reset(p.k()); + for (unsigned i = 0; i < p.size(); ++i) { + ineq.push(p[i].second, p[i].first); + } + if (p.lit() != null_literal) ineq.push(~p.lit(), p.k()); + break; + } + case xor_t: { + xor& x = cnstr.to_xor(); literal_vector ls; - get_antecedents(lit, index, ls); - p.reset(offset); + get_xor_antecedents(lit, x, ls); + ineq.reset(offset); for (unsigned i = 0; i < ls.size(); ++i) { - p.push(~ls[i], offset); + ineq.push(~ls[i], offset); } - literal lxor = index2xor(index).lit(); - if (lxor != null_literal) p.push(~lxor, offset); + literal lxor = x.lit(); + if (lxor != null_literal) ineq.push(~lxor, offset); + break; } - else if (is_pb_index(index)) { - pb& pb = index2pb(index); - p.reset(pb.k()); - for (unsigned i = 0; i < pb.size(); ++i) { - p.push(pb[i].second, pb[i].first); - } - if (pb.lit() != null_literal) p.push(~pb.lit(), pb.k()); - } - else { + default: UNREACHABLE(); + break; } break; } diff --git a/src/sat/card_extension.h b/src/sat/card_extension.h index 15d4c96b9..b748cc69c 100644 --- a/src/sat/card_extension.h +++ b/src/sat/card_extension.h @@ -49,42 +49,70 @@ namespace sat { }; public: - class card { - unsigned m_index; - literal m_lit; - unsigned m_k; - unsigned m_size; - literal m_lits[0]; + enum tag_t { + card_t, + pb_t, + xor_t + }; + class card; + class pb; + class xor; + + class constraint { + protected: + tag_t m_tag; + bool m_removed; + literal m_lit; + unsigned m_size; + public: + constraint(tag_t t, literal l, unsigned sz): m_tag(t), m_removed(false), m_lit(l), m_size(sz) {} + ext_constraint_idx index() const { return reinterpret_cast(this); } + tag_t tag() const { return m_tag; } + literal lit() const { return m_lit; } + unsigned size() const { return m_size; } + void update_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } + void update_literal(literal l) { m_lit = l; } + bool was_removed() const { return m_removed; } + void remove() { m_removed = true; } + void nullify_literal() { m_lit = null_literal; } + + + card& to_card(); + pb& to_pb(); + xor& to_xor(); + card const& to_card() const; + pb const& to_pb() const; + xor const& to_xor() const; + bool is_card() const { return m_tag == card_t; } + bool is_pb() const { return m_tag == pb_t; } + bool is_xor() const { return m_tag == xor_t; } + }; + + friend std::ostream& operator<<(std::ostream& out, constraint const& c); + + class card : public constraint { + unsigned m_k; + literal m_lits[0]; public: static size_t get_obj_size(unsigned num_lits) { return sizeof(card) + num_lits * sizeof(literal); } - card(unsigned index, literal lit, literal_vector const& lits, unsigned k); - unsigned index() const { return m_index; } - literal lit() const { return m_lit; } + card(literal lit, literal_vector const& lits, unsigned k); literal operator[](unsigned i) const { return m_lits[i]; } literal& operator[](unsigned i) { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return static_cast(m_lits) + m_size; } unsigned k() const { return m_k; } - unsigned size() const { return m_size; } void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate(); - void update_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } void update_k(unsigned k) { m_k = k; } - void update_literal(literal l) { m_lit = l; } - void nullify_literal() { m_lit = null_literal; } literal_vector literals() const { return literal_vector(m_size, m_lits); } }; - friend std::ostream& operator<<(std::ostream& out, card const& c); typedef std::pair wliteral; - class pb { - unsigned m_index; - literal m_lit; + class pb : public constraint { unsigned m_k; - unsigned m_size; unsigned m_slack; unsigned m_num_watch; unsigned m_max_sum; @@ -92,8 +120,7 @@ namespace sat { void update_max_sum(); public: static size_t get_obj_size(unsigned num_lits) { return sizeof(pb) + num_lits * sizeof(wliteral); } - pb(unsigned index, literal lit, svector const& wlits, unsigned k); - unsigned index() const { return m_index; } + pb(literal lit, svector const& wlits, unsigned k); literal lit() const { return m_lit; } wliteral operator[](unsigned i) const { return m_wlits[i]; } wliteral& operator[](unsigned i) { return m_wlits[i]; } @@ -101,7 +128,6 @@ namespace sat { wliteral const* end() const { return static_cast(m_wlits) + m_size; } unsigned k() const { return m_k; } - unsigned size() const { return m_size; } unsigned slack() const { return m_slack; } void set_slack(unsigned s) { m_slack = s; } unsigned num_watch() const { return m_num_watch; } @@ -109,32 +135,23 @@ namespace sat { void set_num_watch(unsigned s) { m_num_watch = s; } void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } void negate(); - void update_size(unsigned sz) { m_size = sz; update_max_sum(); } void update_k(unsigned k) { m_k = k; } - void update_literal(literal l) { m_lit = l; } - void nullify_literal() { m_lit = null_literal; } literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } }; - friend std::ostream& operator<<(std::ostream& out, pb const& p); - - class xor { - unsigned m_index; - literal m_lit; - unsigned m_size; + class xor : public constraint { literal m_lits[0]; public: static size_t get_obj_size(unsigned num_lits) { return sizeof(xor) + num_lits * sizeof(literal); } - xor(unsigned index, literal lit, literal_vector const& lits); - unsigned index() const { return m_index; } - literal lit() const { return m_lit; } + xor(literal lit, literal_vector const& lits); literal operator[](unsigned i) const { return m_lits[i]; } - unsigned size() const { return m_size; } literal const* begin() const { return m_lits; } literal const* end() const { return static_cast(m_lits) + m_size; } void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate() { m_lits[0].neg(); } }; + + protected: struct ineq { @@ -149,13 +166,10 @@ namespace sat { lookahead* m_lookahead; stats m_stats; - ptr_vector m_cards; - ptr_vector m_xors; - ptr_vector m_pbs; + ptr_vector m_constraints; // watch literals - unsigned_vector m_index_trail; - unsigned_vector m_index_lim; + unsigned_vector m_constraint_lim; // conflict resolution unsigned m_num_marks; @@ -176,20 +190,22 @@ namespace sat { void inc_parity(bool_var v); void reset_parity(bool_var v); - void clear_index_trail_back(); + void pop_constraint(); solver& s() const { return *m_solver; } - + + // simplification routines svector m_visited; - vector> m_card_use_list; + vector> m_cnstr_use_list; use_list m_clause_use_list; svector m_var_used; bool m_simplify_change; - bool m_cleanup_clauses; + bool m_clause_removed; + bool m_constraint_removed; literal_vector m_roots; - unsigned_vector m_count; + unsigned_vector m_weights; void gc(); bool subsumes(card& c1, card& c2, literal_vector& comp); bool subsumes(card& c1, clause& c2, literal_vector& comp); @@ -203,33 +219,37 @@ namespace sat { unsigned get_num_non_learned_bin(literal l); literal get_min_occurrence_literal(card const& c); void subsumption(card& c1); + void cleanup_clauses(); + void cleanup_constraints(); + + // constraints + void unwatch_literal(literal w, constraint& c); + void watch_literal(literal w, constraint& c); + void watch_literal(wliteral w, pb& p); + void add_constraint(constraint* c); + void init_watch(constraint& c, bool is_true); + void init_watch(bool_var v); + lbool add_assign(constraint& c, literal l); + void simplify(constraint& c); + void nullify_tracking_literal(constraint& c); // cardinality - void init_watch(card& c); void init_watch(card& c, bool is_true); - void init_watch(bool_var v); void assign(card& c, literal lit); lbool add_assign(card& c, literal lit); - void watch_literal(card& c, literal lit); void set_conflict(card& c, literal lit); void clear_watch(card& c); void reset_coeffs(); void reset_marked_literals(); - void unwatch_literal(literal w, card& c); void get_card_antecedents(literal l, card const& c, literal_vector & r); - void copy_card(card_extension& result); void simplify(card& c); - void nullify_tracking_literal(card& c); void remove_constraint(card& c); void unit_propagation_simplification(literal lit, literal_vector const& lits); void flush_roots(card& c); void recompile(card& c); // xor specific functionality - void copy_xor(card_extension& result); void clear_watch(xor& x); - void watch_literal(xor& x, literal lit); - void unwatch_literal(literal w, xor& x); void init_watch(xor& x, bool is_true); void assign(xor& x, literal lit); void set_conflict(xor& x, literal lit); @@ -240,32 +260,21 @@ namespace sat { void simplify(xor& x); void flush_roots(xor& x); - - bool is_card_index(unsigned idx) const { return 0x0 == (idx & 0x3); } - bool is_xor_index(unsigned idx) const { return 0x1 == (idx & 0x3); } - bool is_pb_index(unsigned idx) const { return 0x3 == (idx & 0x3); } - unsigned index2position(unsigned idx) const { return idx >> 2; } - card& index2card(unsigned idx) const { SASSERT(is_card_index(idx)); return *m_cards[idx >> 2]; } - xor& index2xor(unsigned idx) const { SASSERT(is_xor_index(idx)); return *m_xors[idx >> 2]; } - pb& index2pb(unsigned idx) const { SASSERT(is_pb_index(idx)); return *m_pbs[idx >> 2]; } - + + constraint& index2constraint(size_t idx) const { return *reinterpret_cast(idx); } // pb functionality unsigned m_a_max; - void copy_pb(card_extension& result); void init_watch(pb& p, bool is_true); lbool add_assign(pb& p, literal alit); void add_index(pb& p, unsigned index, literal lit); - void watch_literal(pb& p, wliteral lit); void clear_watch(pb& p); void set_conflict(pb& p, literal lit); void assign(pb& p, literal l); - void unwatch_literal(literal w, pb& p); void get_pb_antecedents(literal l, pb const& p, literal_vector & r); void simplify(pb& p); void simplify2(pb& p); bool is_cardinality(pb const& p); - void nullify_tracking_literal(pb& p); void remove_constraint(pb& p); void flush_roots(pb& p); void recompile(pb& p); @@ -322,12 +331,6 @@ namespace sat { void add_at_least(bool_var v, literal_vector const& lits, unsigned k); void add_pb_ge(bool_var v, svector const& wlits, unsigned k); void add_xor(bool_var v, literal_vector const& lits); - unsigned num_pb() const { return m_pbs.size(); } - pb const& get_pb(unsigned i) const { return *m_pbs[i]; } - unsigned num_card() const { return m_cards.size(); } - card const& get_card(unsigned i) const { return *m_cards[i]; } - unsigned num_xor() const { return m_xors.size(); } - xor const& get_xor(unsigned i) const { return *m_xors[i]; } virtual void propagate(literal l, ext_constraint_idx idx, bool & keep); virtual bool resolve_conflict(); @@ -346,6 +349,9 @@ namespace sat { virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); virtual void find_mutexes(literal_vector& lits, vector & mutexes); + + ptr_vector const & constraints() const { return m_constraints; } + }; }; diff --git a/src/sat/sat_justification.h b/src/sat/sat_justification.h index 8c5331d17..b8b3dcbdc 100644 --- a/src/sat/sat_justification.h +++ b/src/sat/sat_justification.h @@ -25,9 +25,10 @@ namespace sat { public: enum kind { NONE, BINARY, TERNARY, CLAUSE, EXT_JUSTIFICATION }; private: - unsigned m_val1; + size_t m_val1; unsigned m_val2; justification(ext_justification_idx idx, kind k):m_val1(idx), m_val2(k) {} + unsigned val1() const { return static_cast(m_val1); } public: justification():m_val1(0), m_val2(NONE) {} explicit justification(literal l):m_val1(l.to_uint()), m_val2(BINARY) {} @@ -40,14 +41,14 @@ namespace sat { bool is_none() const { return m_val2 == NONE; } bool is_binary_clause() const { return m_val2 == BINARY; } - literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(m_val1); } + literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(val1()); } bool is_ternary_clause() const { return get_kind() == TERNARY; } - literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(m_val1); } + literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(val1()); } literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 3); } bool is_clause() const { return m_val2 == CLAUSE; } - clause_offset get_clause_offset() const { return m_val1; } + clause_offset get_clause_offset() const { return val1(); } bool is_ext_justification() const { return m_val2 == EXT_JUSTIFICATION; } ext_justification_idx get_ext_justification_idx() const { return m_val1; } diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index e42076de4..54fe506cf 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -326,51 +326,57 @@ namespace sat { // copy cardinality clauses card_extension* ext = dynamic_cast(s.get_extension()); if (ext) { - literal_vector lits; - unsigned sz = ext->m_cards.size(); unsigned_vector coeffs; - for (unsigned i = 0; i < sz; ++i) { - card_extension::card& c = *ext->m_cards[i]; - unsigned n = c.size(); - unsigned k = c.k(); - - if (c.lit() == null_literal) { - // c.lits() >= k - // <=> - // ~c.lits() <= n - k - lits.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]); - add_cardinality(lits.size(), lits.c_ptr(), n - k); - } - else { - // - // c.lit() <=> c.lits() >= k - // - // (c.lits() < k) or c.lit() - // = (c.lits() + (n - k + 1)*~c.lit()) <= n - // - // ~c.lit() or (c.lits() >= k) - // = ~c.lit() or (~c.lits() <= n - k) - // = k*c.lit() + ~c.lits() <= n - // - m_is_pb = true; - lits.reset(); - coeffs.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]), coeffs.push_back(1); - lits.push_back(~c.lit()); coeffs.push_back(n - k + 1); - add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), n); + literal_vector lits; + for (card_extension::constraint* cp : ext->m_constraints) { + switch (cp->tag()) { + case card_extension::card_t: { + card_extension::card const& c = cp->to_card(); + unsigned n = c.size(); + unsigned k = c.k(); - lits.reset(); - coeffs.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]), coeffs.push_back(1); - lits.push_back(c.lit()); coeffs.push_back(k); - add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), n); + if (c.lit() == null_literal) { + // c.lits() >= k + // <=> + // ~c.lits() <= n - k + lits.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]); + add_cardinality(lits.size(), lits.c_ptr(), n - k); + } + else { + // + // c.lit() <=> c.lits() >= k + // + // (c.lits() < k) or c.lit() + // = (c.lits() + (n - k + 1)*~c.lit()) <= n + // + // ~c.lit() or (c.lits() >= k) + // = ~c.lit() or (~c.lits() <= n - k) + // = k*c.lit() + ~c.lits() <= n + // + m_is_pb = true; + lits.reset(); + coeffs.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]), coeffs.push_back(1); + lits.push_back(~c.lit()); coeffs.push_back(n - k + 1); + add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), n); + + lits.reset(); + coeffs.reset(); + for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]), coeffs.push_back(1); + lits.push_back(c.lit()); coeffs.push_back(k); + add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), n); + } + break; + } + case card_extension::pb_t: + NOT_IMPLEMENTED_YET(); + break; + case card_extension::xor_t: + NOT_IMPLEMENTED_YET(); + break; } } - // - // xor constraints should be disabled. - // - SASSERT(ext->m_xors.empty()); } if (_init) { init(); diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index edce6cc9c..4899fa25a 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -244,7 +244,6 @@ namespace sat { void display(std::ostream& out, unsigned v, var_info const& vi) const; - public: local_search(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 13f0246af..341bcc906 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1362,6 +1362,10 @@ namespace sat { return tracking_assumptions() && m_assumption_set.contains(l); } + bool solver::is_assumption(bool_var v) const { + return is_assumption(literal(v, false)) || is_assumption(literal(v, true)); + } + void solver::init_search() { m_model_is_current = false; m_phase_counter = 0; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index eb7dd9c70..76a0f5721 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -391,6 +391,7 @@ namespace sat { void reinit_assumptions(); bool tracking_assumptions() const; bool is_assumption(literal l) const; + bool is_assumption(bool_var v) const; void simplify_problem(); void mk_model(); bool check_model(model const & m) const; diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 977799366..9e09c68b1 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -110,8 +110,8 @@ namespace sat { typedef std::pair literal_pair; typedef unsigned clause_offset; - typedef unsigned ext_constraint_idx; - typedef unsigned ext_justification_idx; + typedef size_t ext_constraint_idx; + typedef size_t ext_justification_idx; struct literal2unsigned { unsigned operator()(literal l) const { return l.to_uint(); } }; diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 254dba5b6..b9a0962e9 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -41,7 +41,7 @@ namespace sat { BINARY = 0, TERNARY, CLAUSE, EXT_CONSTRAINT }; private: - unsigned m_val1; + size_t m_val1; unsigned m_val2; public: watched(literal l, bool learned): @@ -82,18 +82,18 @@ namespace sat { kind get_kind() const { return static_cast(m_val2 & 3); } bool is_binary_clause() const { return get_kind() == BINARY; } - literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(m_val1); } + literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(static_cast(m_val1)); } void set_literal(literal l) { SASSERT(is_binary_clause()); m_val1 = l.to_uint(); } bool is_learned() const { SASSERT(is_binary_clause()); return (m_val2 >> 2) == 1; } bool is_binary_non_learned_clause() const { return m_val2 == 0; } void mark_not_learned() { SASSERT(is_learned()); m_val2 = static_cast(BINARY); SASSERT(!is_learned()); } bool is_ternary_clause() const { return get_kind() == TERNARY; } - literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(m_val1); } + literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast(m_val1)); } literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 2); } bool is_clause() const { return get_kind() == CLAUSE; } - clause_offset get_clause_offset() const { SASSERT(is_clause()); return m_val1; } + clause_offset get_clause_offset() const { SASSERT(is_clause()); return static_cast(m_val1); } literal get_blocked_literal() const { SASSERT(is_clause()); return to_literal(m_val2 >> 2); } void set_clause_offset(clause_offset c) { SASSERT(is_clause()); m_val1 = c; } void set_blocked_literal(literal l) { SASSERT(is_clause()); m_val2 = static_cast(CLAUSE) + (l.to_uint() << 2); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index eb3bc9d3e..4cc4c76cc 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1151,14 +1151,18 @@ struct sat2goal::imp { sat::card_extension* ext = get_card_extension(s); if (ext) { - for (unsigned i = 0; i < ext->num_pb(); ++i) { - assert_pb(r, ext->get_pb(i)); - } - for (unsigned i = 0; i < ext->num_card(); ++i) { - assert_card(r, ext->get_card(i)); - } - for (unsigned i = 0; i < ext->num_xor(); ++i) { - assert_xor(r, ext->get_xor(i)); + for (auto* c : ext->constraints()) { + switch (c->tag()) { + case sat::card_extension::card_t: + assert_card(r, c->to_card()); + break; + case sat::card_extension::pb_t: + assert_pb(r, c->to_pb()); + break; + case sat::card_extension::xor_t: + assert_xor(r, c->to_xor()); + break; + } } } } From e176c4ba9a44e75eeb28cf1ef3c16d2b91577049 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Jun 2017 17:54:16 -0700 Subject: [PATCH 0178/1283] rename to ba_solver Signed-off-by: Nikolaj Bjorner --- contrib/cmake/src/sat/CMakeLists.txt | 2 +- src/sat/{card_extension.cpp => ba_solver.cpp} | 254 +++++++++--------- src/sat/{card_extension.h => ba_solver.h} | 12 +- src/sat/sat_local_search.cpp | 14 +- src/sat/sat_lookahead.h | 2 +- src/sat/sat_simplifier.h | 2 +- src/sat/sat_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 26 +- 9 files changed, 158 insertions(+), 158 deletions(-) rename src/sat/{card_extension.cpp => ba_solver.cpp} (91%) rename src/sat/{card_extension.h => ba_solver.h} (98%) diff --git a/contrib/cmake/src/sat/CMakeLists.txt b/contrib/cmake/src/sat/CMakeLists.txt index 0f9b9c20c..16d4962d8 100644 --- a/contrib/cmake/src/sat/CMakeLists.txt +++ b/contrib/cmake/src/sat/CMakeLists.txt @@ -1,6 +1,6 @@ z3_add_component(sat SOURCES - card_extension.cpp + ba_solver.cpp dimacs.cpp sat_asymm_branch.cpp sat_ccc.cpp diff --git a/src/sat/card_extension.cpp b/src/sat/ba_solver.cpp similarity index 91% rename from src/sat/card_extension.cpp rename to src/sat/ba_solver.cpp index 8a590017e..2844b3a5e 100644 --- a/src/sat/card_extension.cpp +++ b/src/sat/ba_solver.cpp @@ -3,7 +3,7 @@ Copyright (c) 2017 Microsoft Corporation Module Name: - card_extension.cpp + ba_solver.cpp Abstract: @@ -17,42 +17,42 @@ Revision History: --*/ -#include"card_extension.h" +#include"ba_solver.h" #include"sat_types.h" namespace sat { - card_extension::card& card_extension::constraint::to_card() { + ba_solver::card& ba_solver::constraint::to_card() { SASSERT(is_card()); return static_cast(*this); } - card_extension::card const& card_extension::constraint::to_card() const{ + ba_solver::card const& ba_solver::constraint::to_card() const{ SASSERT(is_card()); return static_cast(*this); } - card_extension::pb& card_extension::constraint::to_pb() { + ba_solver::pb& ba_solver::constraint::to_pb() { SASSERT(is_pb()); return static_cast(*this); } - card_extension::pb const& card_extension::constraint::to_pb() const{ + ba_solver::pb const& ba_solver::constraint::to_pb() const{ SASSERT(is_pb()); return static_cast(*this); } - card_extension::xor& card_extension::constraint::to_xor() { + ba_solver::xor& ba_solver::constraint::to_xor() { SASSERT(is_xor()); return static_cast(*this); } - card_extension::xor const& card_extension::constraint::to_xor() const{ + ba_solver::xor const& ba_solver::constraint::to_xor() const{ SASSERT(is_xor()); return static_cast(*this); } - card_extension::card::card(literal lit, literal_vector const& lits, unsigned k): + ba_solver::card::card(literal lit, literal_vector const& lits, unsigned k): constraint(card_t, lit, lits.size()), m_k(k) { for (unsigned i = 0; i < size(); ++i) { @@ -60,7 +60,7 @@ namespace sat { } } - void card_extension::card::negate() { + void ba_solver::card::negate() { m_lit.neg(); for (unsigned i = 0; i < m_size; ++i) { m_lits[i].neg(); @@ -69,28 +69,28 @@ namespace sat { SASSERT(m_size >= m_k && m_k > 0); } - std::ostream& operator<<(std::ostream& out, card_extension::constraint const& cnstr) { + std::ostream& operator<<(std::ostream& out, ba_solver::constraint const& cnstr) { if (cnstr.lit() != null_literal) out << cnstr.lit() << " == "; switch (cnstr.tag()) { - case card_extension::card_t: { - card_extension::card const& c = cnstr.to_card(); + case ba_solver::card_t: { + ba_solver::card const& c = cnstr.to_card(); for (literal l : c) { out << l << " "; } out << " >= " << c.k(); break; } - case card_extension::pb_t: { - card_extension::pb const& p = cnstr.to_pb(); - for (card_extension::wliteral wl : p) { + case ba_solver::pb_t: { + ba_solver::pb const& p = cnstr.to_pb(); + for (ba_solver::wliteral wl : p) { if (wl.first != 1) out << wl.first << " * "; out << wl.second << " "; } out << " >= " << p.k(); break; } - case card_extension::xor_t: { - card_extension::xor const& x = cnstr.to_xor(); + case ba_solver::xor_t: { + ba_solver::xor const& x = cnstr.to_xor(); for (unsigned i = 0; i < x.size(); ++i) { out << x[i] << " "; if (i + 1 < x.size()) out << "x "; @@ -103,7 +103,7 @@ namespace sat { return out; } - card_extension::pb::pb(literal lit, svector const& wlits, unsigned k): + ba_solver::pb::pb(literal lit, svector const& wlits, unsigned k): constraint(pb_t, lit, wlits.size()), m_k(k), m_slack(0), @@ -115,7 +115,7 @@ namespace sat { update_max_sum(); } - void card_extension::pb::update_max_sum() { + void ba_solver::pb::update_max_sum() { m_max_sum = 0; for (unsigned i = 0; i < size(); ++i) { if (m_max_sum + m_wlits[i].first < m_max_sum) { @@ -125,7 +125,7 @@ namespace sat { } } - void card_extension::pb::negate() { + void ba_solver::pb::negate() { m_lit.neg(); unsigned w = 0; for (unsigned i = 0; i < m_size; ++i) { @@ -136,7 +136,7 @@ namespace sat { SASSERT(w >= m_k && m_k > 0); } - card_extension::xor::xor(literal lit, literal_vector const& lits): + ba_solver::xor::xor(literal lit, literal_vector const& lits): constraint(xor_t, lit, lits.size()) { for (unsigned i = 0; i < size(); ++i) { @@ -144,7 +144,7 @@ namespace sat { } } - void card_extension::init_watch(card& c, bool is_true) { + void ba_solver::init_watch(card& c, bool is_true) { clear_watch(c); if (c.lit() != null_literal && c.lit().sign() == is_true) { c.negate(); @@ -205,22 +205,22 @@ namespace sat { } } - void card_extension::clear_watch(card& c) { + void ba_solver::clear_watch(card& c) { unsigned sz = std::min(c.k() + 1, c.size()); for (unsigned i = 0; i < sz; ++i) { unwatch_literal(c[i], c); } } - void card_extension::unwatch_literal(literal lit, constraint& c) { + void ba_solver::unwatch_literal(literal lit, constraint& c) { get_wlist(~lit).erase(watched(c.index())); } - void card_extension::watch_literal(literal lit, constraint& c) { + void ba_solver::watch_literal(literal lit, constraint& c) { get_wlist(~lit).push_back(watched(c.index())); } - void card_extension::assign(card& c, literal lit) { + void ba_solver::assign(card& c, literal lit) { switch (value(lit)) { case l_true: break; @@ -248,7 +248,7 @@ namespace sat { } } - void card_extension::set_conflict(card& c, literal lit) { + void ba_solver::set_conflict(card& c, literal lit) { m_stats.m_num_card_conflicts++; TRACE("sat", display(tout, c, true); ); SASSERT(validate_conflict(c)); @@ -261,7 +261,7 @@ namespace sat { // watch a prefix of literals, such that the slack of these is >= k - void card_extension::init_watch(pb& p, bool is_true) { + void ba_solver::init_watch(pb& p, bool is_true) { clear_watch(p); if (p.lit() != null_literal && p.lit().sign() == is_true) { p.negate(); @@ -338,7 +338,7 @@ namespace sat { */ - void card_extension::add_index(pb& p, unsigned index, literal lit) { + void ba_solver::add_index(pb& p, unsigned index, literal lit) { if (value(lit) == l_undef) { m_pb_undef.push_back(index); if (p[index].first > m_a_max) { @@ -347,7 +347,7 @@ namespace sat { } } - lbool card_extension::add_assign(pb& p, literal alit) { + lbool ba_solver::add_assign(pb& p, literal alit) { TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); SASSERT(!inconsistent()); @@ -445,18 +445,18 @@ namespace sat { return l_undef; } - void card_extension::watch_literal(wliteral l, pb& p) { + void ba_solver::watch_literal(wliteral l, pb& p) { watch_literal(l.second, p); } - void card_extension::clear_watch(pb& p) { + void ba_solver::clear_watch(pb& p) { unsigned sz = p.size(); for (unsigned i = 0; i < sz; ++i) { unwatch_literal(p[i].second, p); } } - void card_extension::set_conflict(pb& p, literal lit) { + void ba_solver::set_conflict(pb& p, literal lit) { m_stats.m_num_pb_conflicts++; TRACE("sat", display(tout, p, true); ); // SASSERT(validate_conflict(p)); @@ -465,7 +465,7 @@ namespace sat { SASSERT(inconsistent()); } - void card_extension::assign(pb& p, literal lit) { + void ba_solver::assign(pb& p, literal lit) { switch (value(lit)) { case l_true: break; @@ -489,7 +489,7 @@ namespace sat { } } - void card_extension::unit_propagation_simplification(literal lit, literal_vector const& lits) { + void ba_solver::unit_propagation_simplification(literal lit, literal_vector const& lits) { if (lit == null_literal) { for (literal l : lits) { if (value(l) == l_undef) { @@ -512,7 +512,7 @@ namespace sat { } } - bool card_extension::is_cardinality(pb const& p) { + bool ba_solver::is_cardinality(pb const& p) { if (p.size() == 0) return false; unsigned w = p[0].first; for (unsigned i = 1; i < p.size(); ++i) { @@ -521,7 +521,7 @@ namespace sat { return true; } - void card_extension::simplify2(pb& p) { + void ba_solver::simplify2(pb& p) { if (is_cardinality(p)) { literal_vector lits(p.literals()); unsigned k = (p.k() + p[0].first - 1) / p[0].first; @@ -541,7 +541,7 @@ namespace sat { } } - void card_extension::simplify(pb& p) { + void ba_solver::simplify(pb& p) { s().pop_to_base_level(); if (p.lit() != null_literal && value(p.lit()) == l_false) { TRACE("sat", tout << "pb: flip sign " << p << "\n";); @@ -617,14 +617,14 @@ namespace sat { } } - void card_extension::remove_constraint(pb& p) { + void ba_solver::remove_constraint(pb& p) { clear_watch(p); nullify_tracking_literal(p); p.remove(); m_constraint_removed = true; } - void card_extension::display(std::ostream& out, pb const& p, bool values) const { + void ba_solver::display(std::ostream& out, pb const& p, bool values) const { if (p.lit() != null_literal) out << p.lit() << " == "; if (p.lit() != null_literal && values) { out << "[watch: " << p.num_watch() << ", slack: " << p.slack() << "]"; @@ -655,12 +655,12 @@ namespace sat { // xor: - void card_extension::clear_watch(xor& x) { + void ba_solver::clear_watch(xor& x) { unwatch_literal(x[0], x); unwatch_literal(x[1], x); } - bool card_extension::parity(xor const& x, unsigned offset) const { + bool ba_solver::parity(xor const& x, unsigned offset) const { bool odd = false; unsigned sz = x.size(); for (unsigned i = offset; i < sz; ++i) { @@ -672,7 +672,7 @@ namespace sat { return odd; } - void card_extension::init_watch(xor& x, bool is_true) { + void ba_solver::init_watch(xor& x, bool is_true) { clear_watch(x); if (x.lit() != null_literal && x.lit().sign() == is_true) { x.negate(); @@ -711,7 +711,7 @@ namespace sat { } } - void card_extension::assign(xor& x, literal lit) { + void ba_solver::assign(xor& x, literal lit) { SASSERT(!inconsistent()); switch (value(lit)) { case l_true: @@ -740,7 +740,7 @@ namespace sat { } } - void card_extension::set_conflict(xor& x, literal lit) { + void ba_solver::set_conflict(xor& x, literal lit) { m_stats.m_num_xor_conflicts++; TRACE("sat", display(tout, x, true); ); if (value(lit) == l_true) lit.neg(); @@ -750,7 +750,7 @@ namespace sat { SASSERT(inconsistent()); } - lbool card_extension::add_assign(xor& x, literal alit) { + lbool ba_solver::add_assign(xor& x, literal alit) { // literal is assigned unsigned sz = x.size(); TRACE("sat", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); @@ -791,7 +791,7 @@ namespace sat { return inconsistent() ? l_false : l_true; } - void card_extension::normalize_active_coeffs() { + void ba_solver::normalize_active_coeffs() { while (!m_active_var_set.empty()) m_active_var_set.erase(); unsigned i = 0, j = 0, sz = m_active_vars.size(); for (; i < sz; ++i) { @@ -808,7 +808,7 @@ namespace sat { m_active_vars.shrink(sz); } - void card_extension::inc_coeff(literal l, int offset) { + void ba_solver::inc_coeff(literal l, int offset) { SASSERT(offset > 0); bool_var v = l.var(); SASSERT(v != null_bool_var); @@ -839,22 +839,22 @@ namespace sat { } } - int card_extension::get_coeff(bool_var v) const { + int ba_solver::get_coeff(bool_var v) const { return m_coeffs.get(v, 0); } - int card_extension::get_abs_coeff(bool_var v) const { + int ba_solver::get_abs_coeff(bool_var v) const { return abs(get_coeff(v)); } - void card_extension::reset_coeffs() { + void ba_solver::reset_coeffs() { for (unsigned i = 0; i < m_active_vars.size(); ++i) { m_coeffs[m_active_vars[i]] = 0; } m_active_vars.reset(); } - bool card_extension::resolve_conflict() { + bool ba_solver::resolve_conflict() { if (0 == m_num_propagations_since_pop) { return false; } @@ -1123,7 +1123,7 @@ namespace sat { return false; } - void card_extension::process_card(card& c, int offset) { + void ba_solver::process_card(card& c, int offset) { literal lit = c.lit(); SASSERT(c.k() <= c.size()); SASSERT(lit == null_literal || value(lit) == l_true); @@ -1139,7 +1139,7 @@ namespace sat { } } - void card_extension::process_antecedent(literal l, int offset) { + void ba_solver::process_antecedent(literal l, int offset) { SASSERT(value(l) == l_false); bool_var v = l.var(); unsigned level = lvl(v); @@ -1152,7 +1152,7 @@ namespace sat { inc_coeff(l, offset); } - literal card_extension::get_asserting_literal(literal p) { + literal ba_solver::get_asserting_literal(literal p) { if (get_abs_coeff(p.var()) != 0) { return p; } @@ -1168,28 +1168,28 @@ namespace sat { return p; } - card_extension::card_extension(): m_solver(0), m_lookahead(0) { + ba_solver::ba_solver(): m_solver(0), m_lookahead(0) { TRACE("sat", tout << this << "\n";); } - card_extension::~card_extension() { + ba_solver::~ba_solver() { m_stats.reset(); while (!m_constraints.empty()) { pop_constraint(); } } - void card_extension::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { + void ba_solver::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { literal lit = v == null_bool_var ? null_literal : literal(v, false); add_at_least(lit, lits, k); } - void card_extension::add_at_least(literal lit, literal_vector const& lits, unsigned k) { + void ba_solver::add_at_least(literal lit, literal_vector const& lits, unsigned k) { card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(lit, lits, k); add_constraint(c); } - void card_extension::add_constraint(constraint* c) { + void ba_solver::add_constraint(constraint* c) { m_constraints.push_back(c); literal lit = c->lit(); if (lit == null_literal) { @@ -1203,7 +1203,7 @@ namespace sat { } - void card_extension::init_watch(constraint& c, bool is_true) { + void ba_solver::init_watch(constraint& c, bool is_true) { switch (c.tag()) { case card_t: init_watch(c.to_card(), is_true); break; case pb_t: init_watch(c.to_pb(), is_true); break; @@ -1211,7 +1211,7 @@ namespace sat { } } - lbool card_extension::add_assign(constraint& c, literal l) { + lbool ba_solver::add_assign(constraint& c, literal l) { switch (c.tag()) { case card_t: return add_assign(c.to_card(), l); case pb_t: return add_assign(c.to_pb(), l); @@ -1221,27 +1221,27 @@ namespace sat { return l_undef; } - void card_extension::add_pb_ge(literal lit, svector const& wlits, unsigned k) { + void ba_solver::add_pb_ge(literal lit, svector const& wlits, unsigned k) { pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(lit, wlits, k); add_constraint(p); } - void card_extension::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { + void ba_solver::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { literal lit = v == null_bool_var ? null_literal : literal(v, false); add_pb_ge(lit, wlits, k); } - void card_extension::add_xor(bool_var v, literal_vector const& lits) { + void ba_solver::add_xor(bool_var v, literal_vector const& lits) { add_xor(literal(v, false), lits); } - void card_extension::add_xor(literal lit, literal_vector const& lits) { + void ba_solver::add_xor(literal lit, literal_vector const& lits) { xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(lit, lits); add_constraint(x); for (literal l : lits) s().set_external(l.var()); // TBD: determine if goal2sat does this. } - void card_extension::propagate(literal l, ext_constraint_idx idx, bool & keep) { + void ba_solver::propagate(literal l, ext_constraint_idx idx, bool & keep) { SASSERT(value(l) == l_true); TRACE("sat", tout << l << " " << idx << "\n";); constraint& c = index2constraint(idx); @@ -1258,22 +1258,22 @@ namespace sat { } - void card_extension::ensure_parity_size(bool_var v) { + void ba_solver::ensure_parity_size(bool_var v) { if (m_parity_marks.size() <= static_cast(v)) { m_parity_marks.resize(static_cast(v) + 1, 0); } } - unsigned card_extension::get_parity(bool_var v) { + unsigned ba_solver::get_parity(bool_var v) { return m_parity_marks.get(v, 0); } - void card_extension::inc_parity(bool_var v) { + void ba_solver::inc_parity(bool_var v) { ensure_parity_size(v); m_parity_marks[v]++; } - void card_extension::reset_parity(bool_var v) { + void ba_solver::reset_parity(bool_var v) { ensure_parity_size(v); m_parity_marks[v] = 0; } @@ -1283,7 +1283,7 @@ namespace sat { The idea is to collect premises based on xor resolvents. Variables that are repeated an even number of times cancel out. */ - void card_extension::get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r) { + void ba_solver::get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r) { unsigned level = lvl(l); bool_var v = l.var(); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); @@ -1362,7 +1362,7 @@ namespace sat { TRACE("sat", tout << r << "\n";); } - void card_extension::get_pb_antecedents(literal l, pb const& p, literal_vector& r) { + void ba_solver::get_pb_antecedents(literal l, pb const& p, literal_vector& r) { if (p.lit() != null_literal) r.push_back(p.lit()); SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); TRACE("sat", display(tout, p, true);); @@ -1408,11 +1408,11 @@ namespace sat { } } - void card_extension::simplify(xor& x) { + void ba_solver::simplify(xor& x) { // no-op } - void card_extension::get_card_antecedents(literal l, card const& c, literal_vector& r) { + void ba_solver::get_card_antecedents(literal l, card const& c, literal_vector& r) { DEBUG_CODE( bool found = false; for (unsigned i = 0; !found && i < c.k(); ++i) { @@ -1428,7 +1428,7 @@ namespace sat { } } - void card_extension::get_xor_antecedents(literal l, xor const& x, literal_vector& r) { + void ba_solver::get_xor_antecedents(literal l, xor const& x, literal_vector& r) { if (x.lit() != null_literal) r.push_back(x.lit()); // TRACE("sat", display(tout << l << " ", x, true);); SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); @@ -1447,7 +1447,7 @@ namespace sat { } } - void card_extension::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { + void ba_solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { constraint& c = index2constraint(idx); switch (c.tag()) { case card_t: get_card_antecedents(l, c.to_card(), r); break; @@ -1457,7 +1457,7 @@ namespace sat { } } - void card_extension::nullify_tracking_literal(constraint& c) { + void ba_solver::nullify_tracking_literal(constraint& c) { if (c.lit() != null_literal) { get_wlist(c.lit()).erase(watched(c.index())); get_wlist(~c.lit()).erase(watched(c.index())); @@ -1465,14 +1465,14 @@ namespace sat { } } - void card_extension::remove_constraint(card& c) { + void ba_solver::remove_constraint(card& c) { clear_watch(c); nullify_tracking_literal(c); c.remove(); m_constraint_removed = true; } - void card_extension::simplify(card& c) { + void ba_solver::simplify(card& c) { SASSERT(c.lit() == null_literal || value(c.lit()) != l_false); if (c.lit() != null_literal && value(c.lit()) == l_false) { return; @@ -1559,7 +1559,7 @@ namespace sat { } } - lbool card_extension::add_assign(card& c, literal alit) { + lbool ba_solver::add_assign(card& c, literal alit) { // literal is assigned to false. unsigned sz = c.size(); unsigned bound = c.k(); @@ -1615,17 +1615,17 @@ namespace sat { return inconsistent() ? l_false : l_true; } - void card_extension::asserted(literal l) { + void ba_solver::asserted(literal l) { } - check_result card_extension::check() { return CR_DONE; } + check_result ba_solver::check() { return CR_DONE; } - void card_extension::push() { + void ba_solver::push() { m_constraint_lim.push_back(m_constraints.size()); } - void card_extension::pop_constraint() { + void ba_solver::pop_constraint() { constraint* c = m_constraints.back(); m_constraints.pop_back(); nullify_tracking_literal(*c); @@ -1645,7 +1645,7 @@ namespace sat { dealloc(c); } - void card_extension::pop(unsigned n) { + void ba_solver::pop(unsigned n) { TRACE("sat_verbose", tout << "pop:" << n << "\n";); unsigned new_lim = m_constraint_lim.size() - n; unsigned sz = m_constraint_lim[new_lim]; @@ -1656,7 +1656,7 @@ namespace sat { m_num_propagations_since_pop = 0; } - void card_extension::simplify(constraint& c) { + void ba_solver::simplify(constraint& c) { switch (c.tag()) { case card_t: simplify(c.to_card()); @@ -1672,7 +1672,7 @@ namespace sat { } } - void card_extension::simplify() { + void ba_solver::simplify() { return; if (!s().at_base_lvl()) s().pop_to_base_level(); unsigned trail_sz; @@ -1690,7 +1690,7 @@ namespace sat { // or could create queue of constraints that are affected } - bool card_extension::set_root(literal l, literal r) { + bool ba_solver::set_root(literal l, literal r) { if (s().is_assumption(l.var())) { return false; } @@ -1702,7 +1702,7 @@ namespace sat { return true; } - void card_extension::flush_roots() { + void ba_solver::flush_roots() { if (m_roots.empty()) return; m_visited.resize(s().num_vars()*2, false); m_constraint_removed = false; @@ -1725,7 +1725,7 @@ namespace sat { // display(std::cout << "flush roots\n"); } - void card_extension::flush_roots(card& c) { + void ba_solver::flush_roots(card& c) { bool found = c.lit() != null_literal && m_roots[c.lit().index()] != c.lit(); for (literal l : c) { if (found) break; @@ -1769,7 +1769,7 @@ namespace sat { } } - void card_extension::recompile(card& c) { + void ba_solver::recompile(card& c) { IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); m_weights.resize(2*s().num_vars(), 0); for (literal l : c) { @@ -1850,7 +1850,7 @@ namespace sat { } - void card_extension::recompile(pb& p) { + void ba_solver::recompile(pb& p) { IF_VERBOSE(0, verbose_stream() << "re: " << p << "\n";); m_weights.resize(2*s().num_vars(), 0); for (wliteral wl : p) { @@ -1925,7 +1925,7 @@ namespace sat { } } - void card_extension::flush_roots(pb& p) { + void ba_solver::flush_roots(pb& p) { bool found = p.lit() != null_literal && m_roots[p.lit().index()] != p.lit(); for (wliteral wl : p) { if (found) break; @@ -1971,12 +1971,12 @@ namespace sat { } } - void card_extension::flush_roots(xor& x) { + void ba_solver::flush_roots(xor& x) { NOT_IMPLEMENTED_YET(); } - unsigned card_extension::get_num_non_learned_bin(literal l) { + unsigned ba_solver::get_num_non_learned_bin(literal l) { return s().m_simplifier.get_num_non_learned_bin(l); } @@ -1989,7 +1989,7 @@ namespace sat { - resolution - blocked literals */ - void card_extension::gc() { + void ba_solver::gc() { // remove constraints where indicator literal isn't used. m_visited.resize(s().num_vars()*2, false); @@ -2126,7 +2126,7 @@ namespace sat { } - void card_extension::cleanup_clauses() { + void ba_solver::cleanup_clauses() { if (!m_clause_removed) return; // version in simplify first clears // all watch literals, then reinserts them. @@ -2150,7 +2150,7 @@ namespace sat { s().m_clauses.set_end(it2); } - void card_extension::cleanup_constraints() { + void ba_solver::cleanup_constraints() { if (!m_constraint_removed) return; ptr_vector::iterator it = m_constraints.begin(); ptr_vector::iterator it2 = it; @@ -2179,7 +2179,7 @@ namespace sat { - TBD: consider version that generalizes self-subsumption to more than one literal A + ~L + B >= k' => A + B >= k' if A + A' + L >= k and k' + |L| + |A'| <= k */ - bool card_extension::subsumes(card& c1, card& c2, literal_vector & comp) { + bool ba_solver::subsumes(card& c1, card& c2, literal_vector & comp) { if (c2.lit() != null_literal) return false; // perhaps support this? unsigned c2_exclusive = 0; @@ -2202,7 +2202,7 @@ namespace sat { return c1_exclusive + c2.k() + comp.size() <= c1.k(); } - bool card_extension::subsumes(card& c1, clause& c2, literal_vector & comp) { + bool ba_solver::subsumes(card& c1, clause& c2, literal_vector & comp) { unsigned c2_exclusive = 0; unsigned common = 0; comp.reset(); @@ -2230,7 +2230,7 @@ namespace sat { return false; } - literal card_extension::get_min_occurrence_literal(card const& c) { + literal ba_solver::get_min_occurrence_literal(card const& c) { unsigned occ_count = UINT_MAX; literal lit = null_literal; for (literal l : c) { @@ -2243,7 +2243,7 @@ namespace sat { return lit; } - void card_extension::card_subsumption(card& c1, literal lit) { + void ba_solver::card_subsumption(card& c1, literal lit) { literal_vector slit; for (constraint* c : m_cnstr_use_list[lit.index()]) { if (!c || c->tag() != card_t || c == &c1) { @@ -2278,7 +2278,7 @@ namespace sat { } } - void card_extension::clause_subsumption(card& c1, literal lit) { + void ba_solver::clause_subsumption(card& c1, literal lit) { literal_vector slit; clause_use_list::iterator it = m_clause_use_list.get(lit).mk_iterator(); while (!it.at_end()) { @@ -2300,7 +2300,7 @@ namespace sat { } } - void card_extension::binary_subsumption(card& c1, literal lit) { + void ba_solver::binary_subsumption(card& c1, literal lit) { SASSERT(is_marked(lit)); watch_list & wlist = get_wlist(~lit); watch_list::iterator it = wlist.begin(); @@ -2324,7 +2324,7 @@ namespace sat { } } - void card_extension::subsumption(card& c1) { + void ba_solver::subsumption(card& c1) { if (c1.lit() != null_literal) { return; } @@ -2338,13 +2338,13 @@ namespace sat { for (literal l : c1) unmark_visited(l); } - void card_extension::clauses_modifed() {} + void ba_solver::clauses_modifed() {} - lbool card_extension::get_phase(bool_var v) { return l_undef; } + lbool ba_solver::get_phase(bool_var v) { return l_undef; } - extension* card_extension::copy(solver* s) { - card_extension* result = alloc(card_extension); + extension* ba_solver::copy(solver* s) { + ba_solver* result = alloc(ba_solver); result->set_solver(s); literal_vector lits; svector wlits; @@ -2381,7 +2381,7 @@ namespace sat { return result; } - void card_extension::find_mutexes(literal_vector& lits, vector & mutexes) { + void ba_solver::find_mutexes(literal_vector& lits, vector & mutexes) { literal_set slits(lits); bool change = false; for (constraint* cp : m_constraints) { @@ -2414,14 +2414,14 @@ namespace sat { } } - void card_extension::display(std::ostream& out, ineq& ineq) const { + void ba_solver::display(std::ostream& out, ineq& ineq) const { for (unsigned i = 0; i < ineq.m_lits.size(); ++i) { out << ineq.m_coeffs[i] << "*" << ineq.m_lits[i] << " "; } out << ">= " << ineq.m_k << "\n"; } - void card_extension::display(std::ostream& out, xor const& x, bool values) const { + void ba_solver::display(std::ostream& out, xor const& x, bool values) const { out << "xor " << x.lit(); if (x.lit() != null_literal && values) { out << "@(" << value(x.lit()); @@ -2450,7 +2450,7 @@ namespace sat { out << "\n"; } - void card_extension::display(std::ostream& out, card const& c, bool values) const { + void ba_solver::display(std::ostream& out, card const& c, bool values) const { if (c.lit() != null_literal) { if (values) { out << c.lit() << "[" << c.size() << "]"; @@ -2481,7 +2481,7 @@ namespace sat { out << ">= " << c.k() << "\n"; } - std::ostream& card_extension::display(std::ostream& out) const { + std::ostream& ba_solver::display(std::ostream& out) const { for (constraint const* c : m_constraints) { switch (c->tag()) { case card_t: @@ -2500,12 +2500,12 @@ namespace sat { return out; } - std::ostream& card_extension::display_justification(std::ostream& out, ext_justification_idx idx) const { + std::ostream& ba_solver::display_justification(std::ostream& out, ext_justification_idx idx) const { constraint const& cnstr = index2constraint(idx); return out << index2constraint(idx); } - void card_extension::collect_statistics(statistics& st) const { + void ba_solver::collect_statistics(statistics& st) const { st.update("cardinality propagations", m_stats.m_num_card_propagations); st.update("cardinality conflicts", m_stats.m_num_card_conflicts); st.update("cardinality resolves", m_stats.m_num_card_resolves); @@ -2517,24 +2517,24 @@ namespace sat { st.update("pb resolves", m_stats.m_num_pb_resolves); } - bool card_extension::validate_conflict(card& c) { + bool ba_solver::validate_conflict(card& c) { if (!validate_unit_propagation(c)) return false; for (unsigned i = 0; i < c.k(); ++i) { if (value(c[i]) == l_false) return true; } return false; } - bool card_extension::validate_conflict(xor& x) { + bool ba_solver::validate_conflict(xor& x) { return !parity(x, 0); } - bool card_extension::validate_unit_propagation(card const& c) { + bool ba_solver::validate_unit_propagation(card const& c) { if (c.lit() != null_literal && value(c.lit()) != l_true) return false; for (unsigned i = c.k(); i < c.size(); ++i) { if (value(c[i]) != l_false) return false; } return true; } - bool card_extension::validate_unit_propagation(pb const& p, literal alit) { + bool ba_solver::validate_unit_propagation(pb const& p, literal alit) { if (p.lit() != null_literal && value(p.lit()) != l_true) return false; unsigned sum = 0; @@ -2549,7 +2549,7 @@ namespace sat { return sum < p.k(); } - bool card_extension::validate_lemma() { + bool ba_solver::validate_lemma() { int val = -m_bound; normalize_active_coeffs(); for (unsigned i = 0; i < m_active_vars.size(); ++i) { @@ -2568,7 +2568,7 @@ namespace sat { return val < 0; } - void card_extension::active2pb(ineq& p) { + void ba_solver::active2pb(ineq& p) { normalize_active_coeffs(); p.reset(m_bound); for (unsigned i = 0; i < m_active_vars.size(); ++i) { @@ -2579,7 +2579,7 @@ namespace sat { } } - void card_extension::justification2pb(justification const& js, literal lit, unsigned offset, ineq& ineq) { + void ba_solver::justification2pb(justification const& js, literal lit, unsigned offset, ineq& ineq) { switch (js.get_kind()) { case justification::NONE: ineq.reset(offset); @@ -2653,7 +2653,7 @@ namespace sat { // validate that m_A & m_B implies m_C - bool card_extension::validate_resolvent() { + bool ba_solver::validate_resolvent() { u_map coeffs; unsigned k = m_A.m_k + m_B.m_k; for (unsigned i = 0; i < m_A.m_lits.size(); ++i) { @@ -2717,7 +2717,7 @@ namespace sat { return false; } - bool card_extension::validate_conflict(literal_vector const& lits, ineq& p) { + bool ba_solver::validate_conflict(literal_vector const& lits, ineq& p) { for (unsigned i = 0; i < lits.size(); ++i) { if (value(lits[i]) != l_false) { TRACE("sat", tout << "literal " << lits[i] << " is not false\n";); diff --git a/src/sat/card_extension.h b/src/sat/ba_solver.h similarity index 98% rename from src/sat/card_extension.h rename to src/sat/ba_solver.h index b748cc69c..950580b20 100644 --- a/src/sat/card_extension.h +++ b/src/sat/ba_solver.h @@ -3,7 +3,7 @@ Copyright (c) 2017 Microsoft Corporation Module Name: - card_extension.h + ba_solver.h Abstract: @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#ifndef CARD_EXTENSION_H_ -#define CARD_EXTENSION_H_ +#ifndef BA_SOLVER_H_ +#define BA_SOLVER_H_ #include"sat_extension.h" #include"sat_solver.h" @@ -27,7 +27,7 @@ Revision History: namespace sat { - class card_extension : public extension { + class ba_solver : public extension { friend class local_search; @@ -324,8 +324,8 @@ namespace sat { void add_xor(literal l, literal_vector const& lits); public: - card_extension(); - virtual ~card_extension(); + ba_solver(); + virtual ~ba_solver(); virtual void set_solver(solver* s) { m_solver = s; } virtual void set_lookahead(lookahead* l) { m_lookahead = l; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 54fe506cf..683b702e4 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -19,7 +19,7 @@ Notes: #include "sat_local_search.h" #include "sat_solver.h" -#include "card_extension.h" +#include "ba_solver.h" #include "sat_params.hpp" #include "timer.h" @@ -324,14 +324,14 @@ namespace sat { m_num_non_binary_clauses = s.m_clauses.size(); // copy cardinality clauses - card_extension* ext = dynamic_cast(s.get_extension()); + ba_solver* ext = dynamic_cast(s.get_extension()); if (ext) { unsigned_vector coeffs; literal_vector lits; - for (card_extension::constraint* cp : ext->m_constraints) { + for (ba_solver::constraint* cp : ext->m_constraints) { switch (cp->tag()) { - case card_extension::card_t: { - card_extension::card const& c = cp->to_card(); + case ba_solver::card_t: { + ba_solver::card const& c = cp->to_card(); unsigned n = c.size(); unsigned k = c.k(); @@ -369,10 +369,10 @@ namespace sat { } break; } - case card_extension::pb_t: + case ba_solver::pb_t: NOT_IMPLEMENTED_YET(); break; - case card_extension::xor_t: + case ba_solver::xor_t: NOT_IMPLEMENTED_YET(); break; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 211fa41dd..43c2612b8 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -64,7 +64,7 @@ namespace sat { reslimit m_rlimit; friend class ccc; - friend class card_extension; + friend class ba_solver; struct config { double m_dl_success; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 6429ce6eb..626d91ff7 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -47,7 +47,7 @@ namespace sat { }; class simplifier { - friend class card_extension; + friend class ba_solver; solver & s; unsigned m_num_calls; use_list m_use_list; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 76a0f5721..919b0e92a 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -167,7 +167,7 @@ namespace sat { friend class iff3_finder; friend class mus; friend class drat; - friend class card_extension; + friend class ba_solver; friend class parallel; friend class lookahead; friend class local_search; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index febe171d1..07042b682 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -20,7 +20,7 @@ Notes: #include "solver.h" #include "tactical.h" #include "sat_solver.h" -#include "card_extension.h" +#include "ba_solver.h" #include "tactic2solver.h" #include "aig_tactic.h" #include "propagate_values_tactic.h" diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 4cc4c76cc..e72865778 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -38,7 +38,7 @@ Notes: #include"ast_pp.h" #include"ast_util.h" #include"pb_decl_plugin.h" -#include"card_extension.h" +#include"ba_solver.h" #include struct goal2sat::imp { @@ -52,7 +52,7 @@ struct goal2sat::imp { }; ast_manager & m; pb_util pb; - sat::card_extension* m_ext; + sat::ba_solver* m_ext; svector m_frame_stack; svector m_result_stack; obj_map m_cache; @@ -591,11 +591,11 @@ struct goal2sat::imp { if (!m_ext) { sat::extension* ext = m_solver.get_extension(); if (ext) { - m_ext = dynamic_cast(ext); + m_ext = dynamic_cast(ext); SASSERT(m_ext); } if (!m_ext) { - m_ext = alloc(sat::card_extension); + m_ext = alloc(sat::ba_solver); m_solver.set_extension(m_ext); } } @@ -1050,7 +1050,7 @@ struct sat2goal::imp { return m_lit2expr.get(l.index()); } - void assert_pb(goal& r, sat::card_extension::pb const& p) { + void assert_pb(goal& r, sat::ba_solver::pb const& p) { pb_util pb(m); ptr_buffer lits; vector coeffs; @@ -1067,7 +1067,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_card(goal& r, sat::card_extension::card const& c) { + void assert_card(goal& r, sat::ba_solver::card const& c) { pb_util pb(m); ptr_buffer lits; for (unsigned i = 0; i < c.size(); ++i) { @@ -1081,7 +1081,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_xor(goal & r, sat::card_extension::xor const& x) { + void assert_xor(goal & r, sat::ba_solver::xor const& x) { ptr_buffer lits; for (unsigned i = 0; i < x.size(); ++i) { lits.push_back(lit2expr(x[i])); @@ -1110,9 +1110,9 @@ struct sat2goal::imp { } } - sat::card_extension* get_card_extension(sat::solver const& s) { + sat::ba_solver* get_ba_solver(sat::solver const& s) { sat::extension* ext = s.get_extension(); - return dynamic_cast(ext); + return dynamic_cast(ext); } void operator()(sat::solver const & s, atom2bool_var const & map, goal & r, model_converter_ref & mc) { @@ -1149,17 +1149,17 @@ struct sat2goal::imp { assert_clauses(s, s.begin_clauses(), s.end_clauses(), r, true); assert_clauses(s, s.begin_learned(), s.end_learned(), r, false); - sat::card_extension* ext = get_card_extension(s); + sat::ba_solver* ext = get_ba_solver(s); if (ext) { for (auto* c : ext->constraints()) { switch (c->tag()) { - case sat::card_extension::card_t: + case sat::ba_solver::card_t: assert_card(r, c->to_card()); break; - case sat::card_extension::pb_t: + case sat::ba_solver::pb_t: assert_pb(r, c->to_pb()); break; - case sat::card_extension::xor_t: + case sat::ba_solver::xor_t: assert_xor(r, c->to_xor()); break; } From 5c83dfee06ca37711620b9297c4ca014227a8790 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Jun 2017 18:04:08 -0700 Subject: [PATCH 0179/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 2844b3a5e..d29ec509f 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1368,12 +1368,23 @@ namespace sat { TRACE("sat", display(tout, p, true);); if (value(l) == l_false) { + unsigned slack = 0; + unsigned miss = 0; for (wliteral wl : p) { literal lit = wl.second; if (lit != l && value(lit) == l_false) { r.push_back(~lit); + miss += wl.first; } + else { + slack += wl.first; + } } +#if 0 + std::cout << p << "\n"; + std::cout << r << "\n"; + std::cout << "slack:" << slack << " miss: " << miss << "\n"; +#endif return; } @@ -1770,7 +1781,7 @@ namespace sat { } void ba_solver::recompile(card& c) { - IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); + // IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); m_weights.resize(2*s().num_vars(), 0); for (literal l : c) { ++m_weights[l.index()]; @@ -1836,7 +1847,7 @@ namespace sat { add_pb_ge(root, wlits, k); } else { - IF_VERBOSE(0, verbose_stream() << "new: " << c << "\n";); + // IF_VERBOSE(0, verbose_stream() << "new: " << c << "\n";); if (c.lit() != root) { nullify_tracking_literal(c); c.update_literal(root); @@ -1851,7 +1862,7 @@ namespace sat { } void ba_solver::recompile(pb& p) { - IF_VERBOSE(0, verbose_stream() << "re: " << p << "\n";); + // IF_VERBOSE(0, verbose_stream() << "re: " << p << "\n";); m_weights.resize(2*s().num_vars(), 0); for (wliteral wl : p) { m_weights[wl.second.index()] += wl.first; @@ -1911,7 +1922,7 @@ namespace sat { literal root = null_literal; if (p.lit() != null_literal) root = m_roots[p.lit().index()]; - IF_VERBOSE(0, verbose_stream() << "new: " << p << "\n";); + // IF_VERBOSE(0, verbose_stream() << "new: " << p << "\n";); // std::cout << "simplified " << p << "\n"; if (p.lit() != root) { From 085c18a92a947b93868a228af26870de55722341 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Jun 2017 20:29:13 -0700 Subject: [PATCH 0180/1283] add pb to local search Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 111 ++++++++++++++++++++++------------- src/sat/sat_local_search.h | 2 + 2 files changed, 72 insertions(+), 41 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 683b702e4..01076386a 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -62,8 +62,9 @@ namespace sat { } } - for (unsigned i = 0; i < ob_constraint.size(); ++i) - coefficient_in_ob_constraint[ob_constraint[i].var_id] = ob_constraint[i].coefficient; + for (auto const& c : ob_constraint) { + coefficient_in_ob_constraint[c.var_id] = c.coefficient; + } set_parameters(); } @@ -357,7 +358,7 @@ namespace sat { m_is_pb = true; lits.reset(); coeffs.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(c[j]), coeffs.push_back(1); + for (literal l : c) lits.push_back(l), coeffs.push_back(1); lits.push_back(~c.lit()); coeffs.push_back(n - k + 1); add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), n); @@ -369,9 +370,41 @@ namespace sat { } break; } - case ba_solver::pb_t: - NOT_IMPLEMENTED_YET(); + case ba_solver::pb_t: { + ba_solver::pb const& p = cp->to_pb(); + lits.reset(); + coeffs.reset(); + m_is_pb = true; + unsigned sum = 0; + for (ba_solver::wliteral wl : p) sum += wl.first; + + if (p.lit() == null_literal) { + // w1 + .. + w_n >= k + // <=> + // ~wl + ... + ~w_n <= sum_of_weights - k + for (ba_solver::wliteral wl : p) lits.push_back(~(wl.second)), coeffs.push_back(wl.first); + add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), sum - p.k()); + } + else { + // lit <=> w1 + .. + w_n >= k + // <=> + // lit or w1 + .. + w_n <= k - 1 + // ~lit or w1 + .. + w_n >= k + // <=> + // (sum - k + 1)*~lit + w1 + .. + w_n <= sum + // k*lit + ~wl + ... + ~w_n <= sum + lits.push_back(p.lit()), coeffs.push_back(p.k()); + for (ba_solver::wliteral wl : p) lits.push_back(~(wl.second)), coeffs.push_back(wl.first); + add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), sum); + + lits.reset(); + coeffs.reset(); + lits.push_back(~p.lit()), coeffs.push_back(sum + 1 - p.k()); + for (ba_solver::wliteral wl : p) lits.push_back(wl.second), coeffs.push_back(wl.first); + add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), sum); + } break; + } case ba_solver::xor_t: NOT_IMPLEMENTED_YET(); break; @@ -585,10 +618,10 @@ namespace sat { } } else { - for (unsigned i = 0; i < c.size(); ++i) { - if (is_true(c[i])) { + for (literal l : c) { + if (is_true(l)) { if (m_rand() % n == 0) { - best_var = c[i].var(); + best_var = l.var(); } ++n; } @@ -647,32 +680,32 @@ namespace sat { --c.m_slack; switch (c.m_slack) { case -2: // from -1 to -2 - for (unsigned j = 0; j < c.size(); ++j) { - v = c[j].var(); + for (literal l : c) { + v = l.var(); // flipping the slack increasing var will no longer satisfy this constraint - if (is_true(c[j])) { + if (is_true(l)) { //score[v] -= constraint_weight[c]; dec_score(v); } } break; case -1: // from 0 to -1: sat -> unsat - for (unsigned j = 0; j < c.size(); ++j) { - v = c[j].var(); + for (literal l : c) { + v = l.var(); inc_cscc(v); //score[v] += constraint_weight[c]; inc_score(v); // slack increasing var - if (is_true(c[j])) + if (is_true(l)) inc_slack_score(v); } unsat(truep[i].m_constraint_id); break; case 0: // from 1 to 0 - for (unsigned j = 0; j < c.size(); ++j) { - v = c[j].var(); + for (literal l : c) { + v = l.var(); // flip the slack decreasing var will falsify this constraint - if (is_false(c[j])) { + if (is_false(l)) { // score[v] -= constraint_weight[c]; dec_score(v); dec_slack_score(v); @@ -683,16 +716,16 @@ namespace sat { break; } } - for (unsigned i = 0; i < falsep.size(); ++i) { - constraint& c = m_constraints[falsep[i].m_constraint_id]; + for (pbcoeff const& f : falsep) { + constraint& c = m_constraints[f.m_constraint_id]; //--true_terms_count[c]; ++c.m_slack; switch (c.m_slack) { case 1: // from 0 to 1 - for (unsigned j = 0; j < c.size(); ++j) { - v = c[j].var(); + for (literal l : c) { + v = l.var(); // flip the slack decreasing var will no long falsify this constraint - if (is_false(c[j])) { + if (is_false(l)) { //score[v] += constraint_weight[c]; inc_score(v); inc_slack_score(v); @@ -700,22 +733,22 @@ namespace sat { } break; case 0: // from -1 to 0: unsat -> sat - for (unsigned j = 0; j < c.size(); ++j) { - v = c[j].var(); + for (literal l : c) { + v = l.var(); inc_cscc(v); //score[v] -= constraint_weight[c]; dec_score(v); // slack increasing var no longer sat this var - if (is_true(c[j])) + if (is_true(l)) dec_slack_score(v); } - sat(falsep[i].m_constraint_id); + sat(f.m_constraint_id); break; case -1: // from -2 to -1 - for (unsigned j = 0; j < c.size(); ++j) { - v = c[j].var(); + for (literal l : c) { + v = l.var(); // flip the slack increasing var will satisfy this constraint - if (is_true(c[j])) { + if (is_true(l)) { //score[v] += constraint_weight[c]; inc_score(v); } @@ -745,8 +778,7 @@ namespace sat { var_info& vi = m_vars[flipvar]; unsigned sz = vi.m_neighbors.size(); - for (unsigned i = 0; i < sz; ++i) { - v = vi.m_neighbors[i]; + for (auto v : vi.m_neighbors) { m_vars[v].m_conf_change = true; if (score(v) > 0 && !already_in_goodvar_stack(v)) { m_goodvar_stack.push_back(v); @@ -792,8 +824,8 @@ namespace sat { // SAT Mode if (m_unsat_stack.empty()) { //std::cout << "as\t"; - for (unsigned i = 0; i < ob_constraint.size(); ++i) { - bool_var v = ob_constraint[i].var_id; + for (auto const& c : ob_constraint) { + bool_var v = c.var_id; if (tie_breaker_sat(v, best_var)) best_var = v; } @@ -805,8 +837,7 @@ namespace sat { if (!m_goodvar_stack.empty()) { //++ccd; best_var = m_goodvar_stack[0]; - for (unsigned i = 1; i < m_goodvar_stack.size(); ++i) { - bool_var v = m_goodvar_stack[i]; + for (bool_var v : m_goodvar_stack) { if (tie_breaker_ccd(v, best_var)) best_var = v; } @@ -816,10 +847,9 @@ namespace sat { // Diversification Mode constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; // a random unsat constraint // Within c, from all slack increasing var, choose the oldest one - unsigned c_size = c.size(); - for (unsigned i = 0; i < c_size; ++i) { - bool_var v = c[i].var(); - if (is_true(c[i]) && time_stamp(v) < time_stamp(best_var)) + for (literal l : c) { + bool_var v = l.var(); + if (is_true(l) && time_stamp(v) < time_stamp(best_var)) best_var = v; } return best_var; @@ -868,8 +898,7 @@ namespace sat { } void local_search::display(std::ostream& out) const { - for (unsigned i = 0; i < m_constraints.size(); ++i) { - constraint const& c = m_constraints[i]; + for (constraint const& c : m_constraints) { display(out, c); } for (bool_var v = 0; v < num_vars(); ++v) { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 4899fa25a..5e717c5a7 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -107,6 +107,8 @@ namespace sat { void push(literal l) { m_literals.push_back(l); ++m_size; } unsigned size() const { return m_size; } literal const& operator[](unsigned idx) const { return m_literals[idx]; } + literal const* begin() const { return m_literals.begin(); } + literal const* end() const { return m_literals.end(); } }; local_search_config m_config; From 7580644d150d04b15d15ee1875a52b5c8a4fa6c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Jun 2017 08:11:27 -0700 Subject: [PATCH 0181/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 473 +++++++++++++++++++++++----------------- src/sat/ba_solver.h | 84 +++---- src/sat/sat_extension.h | 1 + src/sat/sat_solver.cpp | 57 ++--- 4 files changed, 336 insertions(+), 279 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index d29ec509f..7d9e16df0 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -53,7 +53,7 @@ namespace sat { } ba_solver::card::card(literal lit, literal_vector const& lits, unsigned k): - constraint(card_t, lit, lits.size()), + constraint(card_t, lit, lits.size(), get_obj_size(lits.size())), m_k(k) { for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; @@ -104,7 +104,7 @@ namespace sat { } ba_solver::pb::pb(literal lit, svector const& wlits, unsigned k): - constraint(pb_t, lit, wlits.size()), + constraint(pb_t, lit, wlits.size(), get_obj_size(wlits.size())), m_k(k), m_slack(0), m_num_watch(0), @@ -137,8 +137,7 @@ namespace sat { } ba_solver::xor::xor(literal lit, literal_vector const& lits): - constraint(xor_t, lit, lits.size()) - { + constraint(xor_t, lit, lits.size(), get_obj_size(lits.size())) { for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; } @@ -169,9 +168,9 @@ namespace sat { } DEBUG_CODE( bool is_false = false; - for (unsigned k = 0; k < sz; ++k) { - SASSERT(!is_false || value(c[k]) == l_false); - is_false = value(c[k]) == l_false; + for (literal l : c) { + SASSERT(!is_false || value(l) == l_false); + is_false = value(l) == l_false; }); // j is the number of non-false, sz - j the number of false. @@ -220,7 +219,18 @@ namespace sat { get_wlist(~lit).push_back(watched(c.index())); } - void ba_solver::assign(card& c, literal lit) { + void ba_solver::set_conflict(constraint& c, literal lit) { + m_stats.m_num_conflicts++; + TRACE("sat", display(tout, c, true); ); + SASSERT(validate_conflict(c)); + if (c.is_xor() && value(lit) == l_true) lit.neg(); + SASSERT(value(lit) == l_false); + set_conflict(justification::mk_ext_justification(c.index()), ~lit); + SASSERT(inconsistent()); + } + + + void ba_solver::assign(constraint& c, literal lit) { switch (value(lit)) { case l_true: break; @@ -228,17 +238,14 @@ namespace sat { set_conflict(c, lit); break; default: - m_stats.m_num_card_propagations++; + m_stats.m_num_propagations++; m_num_propagations_since_pop++; //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); - SASSERT(validate_unit_propagation(c)); + SASSERT(validate_unit_propagation(c, lit)); if (get_config().m_drat) { svector ps; literal_vector lits; - if (c.lit() != null_literal) lits.push_back(~c.lit()); - for (unsigned i = c.k(); i < c.size(); ++i) { - lits.push_back(c[i]); - } + get_antecedents(lit, c, lits); lits.push_back(lit); ps.push_back(drat::premise(drat::s_ext(), c.lit())); // null_literal case. drat_add(lits, ps); @@ -248,15 +255,6 @@ namespace sat { } } - void ba_solver::set_conflict(card& c, literal lit) { - m_stats.m_num_card_conflicts++; - TRACE("sat", display(tout, c, true); ); - SASSERT(validate_conflict(c)); - SASSERT(value(lit) == l_false); - set_conflict(justification::mk_ext_justification(c.index()), ~lit); - SASSERT(inconsistent()); - } - // pb: @@ -370,6 +368,10 @@ namespace sat { add_index(p, index, lit); } SASSERT(index < num_watch); + if (index >= num_watch) { + std::cout << "BAD assign. " << alit << " not found within " << num_watch << "\n"; + std::cout << p << "\n"; + } unsigned index1 = index + 1; for (; m_a_max == 0 && index1 < num_watch; ++index1) { @@ -423,6 +425,10 @@ namespace sat { while (!m_pb_undef.empty()) { index1 = m_pb_undef.back(); if (index1 == num_watch) index1 = index; // it was swapped with index above. + if (index1 >= num_watch) { + std::cout << "BAD assignment at position " << index1 << " with " << num_watch << "\n"; + std::cout << p << "\n"; + } literal lit = p[index1].second; SASSERT(value(lit) == l_undef); TRACE("sat", tout << index1 << " " << lit << "\n";); @@ -450,43 +456,7 @@ namespace sat { } void ba_solver::clear_watch(pb& p) { - unsigned sz = p.size(); - for (unsigned i = 0; i < sz; ++i) { - unwatch_literal(p[i].second, p); - } - } - - void ba_solver::set_conflict(pb& p, literal lit) { - m_stats.m_num_pb_conflicts++; - TRACE("sat", display(tout, p, true); ); - // SASSERT(validate_conflict(p)); - SASSERT(value(lit) == l_false); - set_conflict(justification::mk_ext_justification(p.index()), ~lit); - SASSERT(inconsistent()); - } - - void ba_solver::assign(pb& p, literal lit) { - switch (value(lit)) { - case l_true: - break; - case l_false: - set_conflict(p, lit); - break; - default: - SASSERT(validate_unit_propagation(p, lit)); - m_stats.m_num_pb_propagations++; - m_num_propagations_since_pop++; - if (get_config().m_drat) { - svector ps; - literal_vector lits; - get_pb_antecedents(lit, p, lits); - lits.push_back(lit); - ps.push_back(drat::premise(drat::s_ext(), p.lit())); - drat_add(lits, ps); - } - assign(lit, justification::mk_ext_justification(p.index())); - break; - } + for (wliteral wl : p) unwatch_literal(wl.second, p); } void ba_solver::unit_propagation_simplification(literal lit, literal_vector const& lits) { @@ -515,9 +485,7 @@ namespace sat { bool ba_solver::is_cardinality(pb const& p) { if (p.size() == 0) return false; unsigned w = p[0].first; - for (unsigned i = 1; i < p.size(); ++i) { - if (w != p[i].first) return false; - } + for (wliteral wl : p) if (w != wl.first) return false; return true; } @@ -604,6 +572,7 @@ namespace sat { // std::cout << "new size: " << sz << " old size " << p.size() << "\n"; p.update_size(sz); p.update_k(p.k() - true_val); + p.update_max_sum(); // display(verbose_stream(), c, true); if (p.lit() == null_literal) { init_watch(p, true); @@ -617,11 +586,13 @@ namespace sat { } } - void ba_solver::remove_constraint(pb& p) { - clear_watch(p); - nullify_tracking_literal(p); - p.remove(); - m_constraint_removed = true; + void ba_solver::display(std::ostream& out, constraint const& c, bool values) const { + switch (c.tag()) { + case card_t: display(out, c.to_card(), values); break; + case pb_t: display(out, c.to_pb(), values); break; + case xor_t: display(out, c.to_xor(), values); break; + default: UNREACHABLE(); break; + } } void ba_solver::display(std::ostream& out, pb const& p, bool values) const { @@ -711,44 +682,6 @@ namespace sat { } } - void ba_solver::assign(xor& x, literal lit) { - SASSERT(!inconsistent()); - switch (value(lit)) { - case l_true: - break; - case l_false: - set_conflict(x, lit); - SASSERT(inconsistent()); - break; - default: - m_stats.m_num_xor_propagations++; - m_num_propagations_since_pop++; - if (get_config().m_drat) { - svector ps; - literal_vector lits; - if (x.lit() != null_literal) lits.push_back(~x.lit()); - for (unsigned i = 1; i < x.size(); ++i) { - lits.push_back(x[i]); - } - lits.push_back(lit); - ps.push_back(drat::premise(drat::s_ext(), x.lit())); - drat_add(lits, ps); - } - TRACE("sat", display(tout << lit << " ", x, true);); - assign(lit, justification::mk_ext_justification(x.index())); - break; - } - } - - void ba_solver::set_conflict(xor& x, literal lit) { - m_stats.m_num_xor_conflicts++; - TRACE("sat", display(tout, x, true); ); - if (value(lit) == l_true) lit.neg(); - SASSERT(validate_conflict(x)); - TRACE("sat", display(tout << lit << " ", x, true);); - set_conflict(justification::mk_ext_justification(x.index()), ~lit); - SASSERT(inconsistent()); - } lbool ba_solver::add_assign(xor& x, literal alit) { // literal is assigned @@ -854,6 +787,8 @@ namespace sat { m_active_vars.reset(); } + static bool _debug_conflict = false; + bool ba_solver::resolve_conflict() { if (0 == m_num_propagations_since_pop) { return false; @@ -879,6 +814,8 @@ namespace sat { vector jus; + // if (null_literal != consequent) std::cout << "resolve " << consequent << " " << value(consequent) << "\n"; + do { if (offset == 0) { @@ -900,6 +837,11 @@ namespace sat { DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); + if (_debug_conflict) { + std::cout << consequent << "\n"; + s().display_justification(std::cout, js); + std::cout << "\n"; + } switch(js.get_kind()) { case justification::NONE: SASSERT (consequent != null_literal); @@ -940,12 +882,12 @@ namespace sat { } case justification::EXT_JUSTIFICATION: { constraint& cnstr = index2constraint(js.get_ext_justification_idx()); + ++m_stats.m_num_resolves; switch (cnstr.tag()) { case card_t: { card& c = cnstr.to_card(); m_bound += offset * c.k(); process_card(c, offset); - ++m_stats.m_num_card_resolves; break; } case pb_t: { @@ -953,10 +895,13 @@ namespace sat { m_lemma.reset(); m_bound += offset; inc_coeff(consequent, offset); - get_pb_antecedents(consequent, p, m_lemma); + get_antecedents(consequent, p, m_lemma); TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";); + if (_debug_conflict) { + std::cout << consequent << " "; + std::cout << "antecedents: " << m_lemma << "\n"; + } for (literal l : m_lemma) process_antecedent(~l, offset); - ++m_stats.m_num_pb_resolves; break; } case xor_t: { @@ -966,7 +911,6 @@ namespace sat { inc_coeff(consequent, offset); get_xor_antecedents(consequent, idx, js, m_lemma); for (literal l : m_lemma) process_antecedent(~l, offset); - ++m_stats.m_num_xor_resolves; break; } default: @@ -1118,6 +1062,19 @@ namespace sat { s().reset_mark(v); --m_num_marks; } + if (idx == 0 && !_debug_conflict) { + _debug_conflict = true; + // s().display(std::cout); + std::cout << s().m_not_l << "\n"; + for (literal l : lits) { + if (s().is_marked(l.var())) { + std::cout << "missing mark: " << l << "\n"; + s().reset_mark(l.var()); + } + } + m_num_marks = 0; + resolve_conflict(); + } --idx; } return false; @@ -1185,7 +1142,8 @@ namespace sat { } void ba_solver::add_at_least(literal lit, literal_vector const& lits, unsigned k) { - card* c = new (memory::allocate(card::get_obj_size(lits.size()))) card(lit, lits, k); + void * mem = m_allocator.allocate(card::get_obj_size(lits.size())); + card* c = new (mem) card(lit, lits, k); add_constraint(c); } @@ -1222,7 +1180,8 @@ namespace sat { } void ba_solver::add_pb_ge(literal lit, svector const& wlits, unsigned k) { - pb* p = new (memory::allocate(pb::get_obj_size(wlits.size()))) pb(lit, wlits, k); + void * mem = m_allocator.allocate(pb::get_obj_size(wlits.size())); + pb* p = new (mem) pb(lit, wlits, k); add_constraint(p); } @@ -1236,7 +1195,8 @@ namespace sat { } void ba_solver::add_xor(literal lit, literal_vector const& lits) { - xor* x = new (memory::allocate(xor::get_obj_size(lits.size()))) xor(lit, lits); + void * mem = m_allocator.allocate(xor::get_obj_size(lits.size())); + xor* x = new (mem) xor(lit, lits); add_constraint(x); for (literal l : lits) s().set_external(l.var()); // TBD: determine if goal2sat does this. } @@ -1287,7 +1247,6 @@ namespace sat { unsigned level = lvl(l); bool_var v = l.var(); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); - SASSERT(index2constraint(index).is_xor()); TRACE("sat", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); unsigned num_marks = 0; @@ -1362,24 +1321,47 @@ namespace sat { TRACE("sat", tout << r << "\n";); } - void ba_solver::get_pb_antecedents(literal l, pb const& p, literal_vector& r) { + void ba_solver::get_antecedents(literal l, pb const& p, literal_vector& r) { if (p.lit() != null_literal) r.push_back(p.lit()); SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); TRACE("sat", display(tout, p, true);); if (value(l) == l_false) { + // The literal comes from a conflict. + // it is forced true, but assigned to false. unsigned slack = 0; unsigned miss = 0; + unsigned worth = 0; + unsigned k = p.k(); for (wliteral wl : p) { literal lit = wl.second; - if (lit != l && value(lit) == l_false) { - r.push_back(~lit); + if (lit == l) { + worth = wl.first; + } + else if (value(lit) == l_false) { miss += wl.first; - } + } else { slack += wl.first; } } + SASSERT(slack < k); + SASSERT(0 < worth); + + slack += worth; + for (wliteral wl : p) { + literal lit = wl.second; + if (lit != l && value(lit) == l_false) { + unsigned w = wl.first; + if (slack + w >= k) { + r.push_back(~lit); + } + else { + slack += w; + std::cout << "increase slack by " << w << " to " << slack << " worth: " << worth << "\n"; + } + } + } #if 0 std::cout << p << "\n"; std::cout << r << "\n"; @@ -1388,7 +1370,6 @@ namespace sat { return; } - // unsigned coeff = get_coeff(p, l); unsigned coeff = 0; for (unsigned j = 0; j < p.num_watch(); ++j) { if (p[j].second == l) { @@ -1396,6 +1377,11 @@ namespace sat { break; } } + + if (_debug_conflict) { + std::cout << p << "\n"; + std::cout << l << " " << coeff << " num_watch: " << p.num_watch() << "\n"; + } CTRACE("sat", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); @@ -1423,7 +1409,7 @@ namespace sat { // no-op } - void ba_solver::get_card_antecedents(literal l, card const& c, literal_vector& r) { + void ba_solver::get_antecedents(literal l, card const& c, literal_vector& r) { DEBUG_CODE( bool found = false; for (unsigned i = 0; !found && i < c.k(); ++i) { @@ -1439,7 +1425,7 @@ namespace sat { } } - void ba_solver::get_xor_antecedents(literal l, xor const& x, literal_vector& r) { + void ba_solver::get_antecedents(literal l, xor const& x, literal_vector& r) { if (x.lit() != null_literal) r.push_back(x.lit()); // TRACE("sat", display(tout << l << " ", x, true);); SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); @@ -1459,15 +1445,68 @@ namespace sat { } void ba_solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { - constraint& c = index2constraint(idx); + get_antecedents(l, index2constraint(idx), r); + } + + void ba_solver::get_antecedents(literal l, constraint const& c, literal_vector& r) { switch (c.tag()) { - case card_t: get_card_antecedents(l, c.to_card(), r); break; - case pb_t: get_pb_antecedents(l, c.to_pb(), r); break; - case xor_t: get_xor_antecedents(l, c.to_xor(), r); break; + case card_t: get_antecedents(l, c.to_card(), r); break; + case pb_t: get_antecedents(l, c.to_pb(), r); break; + case xor_t: get_antecedents(l, c.to_xor(), r); break; default: UNREACHABLE(); break; } } + bool ba_solver::validate_unit_propagation(constraint const& c, literal l) const { + switch (c.tag()) { + case card_t: return validate_unit_propagation(c.to_card(), l); + case pb_t: return validate_unit_propagation(c.to_pb(), l); + case xor_t: return true; + default: UNREACHABLE(); break; + } + return false; + } + + bool ba_solver::validate_conflict(constraint const& c) const { + switch (c.tag()) { + case card_t: return validate_conflict(c.to_card()); + case pb_t: return validate_conflict(c.to_pb()); + case xor_t: return validate_conflict(c.to_xor()); + default: UNREACHABLE(); break; + } + return false; + } + + /** + \brief Lex on (glue, size) + */ + struct constraint_glue_lt { + bool operator()(ba_solver::constraint const * c1, ba_solver::constraint const * c2) const { + return + (c1->glue() < c2->glue()) || + (c1->glue() == c2->glue() && c1->size() < c2->size()); + } + }; + + void ba_solver::gc() { + std::stable_sort(m_learned.begin(), m_learned.end(), constraint_glue_lt()); + gc_half("glue"); + cleanup_constraints(m_learned); + } + + void ba_solver::gc_half(char const* st_name) { + TRACE("sat", tout << "gc\n";); + unsigned sz = m_learned.size(); + unsigned new_sz = sz/2; + unsigned j = new_sz; + for (unsigned i = new_sz; i < sz; i++) { + remove_constraint(*(m_learned[i])); + } + m_learned.shrink(j); + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :strategy " << st_name << " :deleted " << (sz - j) << ")\n";); + + } + void ba_solver::nullify_tracking_literal(constraint& c) { if (c.lit() != null_literal) { get_wlist(c.lit()).erase(watched(c.index())); @@ -1476,9 +1515,21 @@ namespace sat { } } - void ba_solver::remove_constraint(card& c) { - clear_watch(c); + void ba_solver::remove_constraint(constraint& c) { nullify_tracking_literal(c); + switch (c.tag()) { + case card_t: + clear_watch(c.to_card()); + break; + case pb_t: + clear_watch(c.to_pb()); + break; + case xor_t: + clear_watch(c.to_xor()); + break; + default: + UNREACHABLE(); + } c.remove(); m_constraint_removed = true; } @@ -1616,9 +1667,7 @@ namespace sat { // assigned l_true. if (index != bound) { c.swap(index, bound); - } - SASSERT(validate_unit_propagation(c)); - + } for (unsigned i = 0; i < bound && !inconsistent(); ++i) { assign(c, c[i]); } @@ -1639,23 +1688,11 @@ namespace sat { void ba_solver::pop_constraint() { constraint* c = m_constraints.back(); m_constraints.pop_back(); - nullify_tracking_literal(*c); - switch (c->tag()) { - case card_t: - clear_watch(c->to_card()); - break; - case pb_t: - clear_watch(c->to_pb()); - break; - case xor_t: - clear_watch(c->to_xor()); - break; - default: - UNREACHABLE(); - } - dealloc(c); + remove_constraint(*c); + m_allocator.deallocate(c->obj_size(), c); } + void ba_solver::pop(unsigned n) { TRACE("sat_verbose", tout << "pop:" << n << "\n";); unsigned new_lim = m_constraint_lim.size() - n; @@ -1693,7 +1730,15 @@ namespace sat { m_constraint_removed = false; trail_sz = s().init_trail_size(); for (constraint* c : m_constraints) simplify(*c); - gc(); + init_use_lists(); + remove_unused_defs(); + // take ownership of interface variables + for (constraint* c : m_constraints) { + if (c->lit() != null_literal) m_var_used[c->lit().var()] = true; + } + set_non_external(); + elim_pure(); + subsumption(); cleanup_clauses(); cleanup_constraints(); } @@ -1910,15 +1955,17 @@ namespace sat { return; } - p.update_size(sz); - p.update_k(k); - for (unsigned i = 0; i < sz; ++i) { wliteral wl = p[i]; unsigned w = std::min(k, wl.first); p[i] = wliteral(w, wl.second); } + p.update_size(sz); + p.update_k(k); + p.update_max_sum(); + + literal root = null_literal; if (p.lit() != null_literal) root = m_roots[p.lit().index()]; @@ -2000,9 +2047,7 @@ namespace sat { - resolution - blocked literals */ - void ba_solver::gc() { - - // remove constraints where indicator literal isn't used. + void ba_solver::init_use_lists() { m_visited.resize(s().num_vars()*2, false); m_clause_use_list.init(s().num_vars()); m_var_used.reset(); @@ -2051,6 +2096,10 @@ namespace sat { } } } + } + + void ba_solver::remove_unused_defs() { + // remove constraints where indicator literal isn't used. for (constraint* cp : m_constraints) { switch (cp->tag()) { case card_t: { @@ -2081,12 +2130,9 @@ namespace sat { break; } } + } - // take ownership of interface variables - for (constraint* cp : m_constraints) { - if (cp->lit() != null_literal) m_var_used[cp->lit().var()] = true; - } - + unsigned ba_solver::set_non_external() { // set variables to be non-external if they are not used in theory constraints. unsigned ext = 0; for (unsigned v = 0; v < s().num_vars(); ++v) { @@ -2095,7 +2141,11 @@ namespace sat { ++ext; } } + IF_VERBOSE(10, verbose_stream() << "non-external variables converted: " << ext << "\n";); + return ext; + } + unsigned ba_solver::elim_pure() { // eliminate pure literals unsigned pure_literals = 0; for (unsigned v = 0; v < s().num_vars(); ++v) { @@ -2113,10 +2163,11 @@ namespace sat { ++pure_literals; } } - IF_VERBOSE(10, - verbose_stream() << "non-external variables converted: " << ext << "\n"; - verbose_stream() << "pure literals converted: " << pure_literals << "\n";); + IF_VERBOSE(10, verbose_stream() << "pure literals converted: " << pure_literals << "\n";); + return pure_literals; + } + void ba_solver::subsumption() { unsigned bin_sub = m_stats.m_num_bin_subsumes; unsigned clause_sub = m_stats.m_num_clause_subsumes; unsigned card_sub = m_stats.m_num_card_subsumes; @@ -2163,13 +2214,19 @@ namespace sat { void ba_solver::cleanup_constraints() { if (!m_constraint_removed) return; - ptr_vector::iterator it = m_constraints.begin(); + cleanup_constraints(m_constraints); + cleanup_constraints(m_learned); + m_constraint_removed = false; + } + + void ba_solver::cleanup_constraints(ptr_vector& cs) { + ptr_vector::iterator it = cs.begin(); ptr_vector::iterator it2 = it; - ptr_vector::iterator end = m_constraints.end(); + ptr_vector::iterator end = cs.end(); for (; it != end; ++it) { constraint& c = *(*it); if (c.was_removed()) { - dealloc(&c); + m_allocator.deallocate(c.obj_size(), &c); } else { if (it != it2) { @@ -2178,8 +2235,7 @@ namespace sat { ++it2; } } - m_constraints.set_end(it2); - m_constraint_removed = false; + cs.set_end(it2); } /* @@ -2517,54 +2573,74 @@ namespace sat { } void ba_solver::collect_statistics(statistics& st) const { - st.update("cardinality propagations", m_stats.m_num_card_propagations); - st.update("cardinality conflicts", m_stats.m_num_card_conflicts); - st.update("cardinality resolves", m_stats.m_num_card_resolves); - st.update("xor propagations", m_stats.m_num_xor_propagations); - st.update("xor conflicts", m_stats.m_num_xor_conflicts); - st.update("xor resolves", m_stats.m_num_xor_resolves); - st.update("pb propagations", m_stats.m_num_pb_propagations); - st.update("pb conflicts", m_stats.m_num_pb_conflicts); - st.update("pb resolves", m_stats.m_num_pb_resolves); + st.update("ba propagations", m_stats.m_num_propagations); + st.update("ba conflicts", m_stats.m_num_conflicts); + st.update("ba resolves", m_stats.m_num_resolves); } - bool ba_solver::validate_conflict(card& c) { - if (!validate_unit_propagation(c)) return false; + bool ba_solver::validate_conflict(card const& c) const { + if (c.lit() != null_literal && value(c.lit()) != l_true) { + return false; + } + for (unsigned i = c.k(); i < c.size(); ++i) { + if (value(c[i]) != l_false) return false; + } for (unsigned i = 0; i < c.k(); ++i) { if (value(c[i]) == l_false) return true; } return false; } - bool ba_solver::validate_conflict(xor& x) { + + bool ba_solver::validate_conflict(xor const& x) const { return !parity(x, 0); } - bool ba_solver::validate_unit_propagation(card const& c) { + + bool ba_solver::validate_conflict(pb const& p) const { + unsigned slack = 0; + for (wliteral wl : p) { + if (value(wl.second) != l_false) { + slack += wl.first; + } + } + return slack < p.k(); + } + + bool ba_solver::validate_unit_propagation(card const& c, literal alit) const { + (void) alit; if (c.lit() != null_literal && value(c.lit()) != l_true) return false; for (unsigned i = c.k(); i < c.size(); ++i) { if (value(c[i]) != l_false) return false; } return true; } - bool ba_solver::validate_unit_propagation(pb const& p, literal alit) { + + bool ba_solver::validate_unit_propagation(pb const& p, literal alit) const { if (p.lit() != null_literal && value(p.lit()) != l_true) return false; unsigned sum = 0; TRACE("sat", display(tout << "validate: " << alit << "\n", p, true);); - for (unsigned i = 0; i < p.size(); ++i) { - literal lit = p[i].second; + for (wliteral wl : p) { + literal lit = wl.second; lbool val = value(lit); if (val != l_false && lit != alit) { - sum += p[i].first; + sum += wl.first; } } return sum < p.k(); } + bool ba_solver::validate_unit_propagation(xor const& x, literal alit) const { + if (value(x.lit()) != l_true) return false; + for (unsigned i = 1; i < x.size(); ++i) { + if (value(x[i]) == l_undef) return false; + } + return true; + } + bool ba_solver::validate_lemma() { int val = -m_bound; normalize_active_coeffs(); - for (unsigned i = 0; i < m_active_vars.size(); ++i) { - bool_var v = m_active_vars[i]; + for (bool_var v : m_active_vars) { int coeff = get_coeff(v); literal lit(v, false); SASSERT(coeff != 0); @@ -2582,8 +2658,7 @@ namespace sat { void ba_solver::active2pb(ineq& p) { normalize_active_coeffs(); p.reset(m_bound); - for (unsigned i = 0; i < m_active_vars.size(); ++i) { - bool_var v = m_active_vars[i]; + for (bool_var v : m_active_vars) { literal lit(v, get_coeff(v) < 0); p.m_lits.push_back(lit); p.m_coeffs.push_back(get_abs_coeff(v)); @@ -2610,9 +2685,7 @@ namespace sat { case justification::CLAUSE: { ineq.reset(offset); clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) - ineq.push(c[i], offset); + for (literal l : c) ineq.push(l, offset); break; } case justification::EXT_JUSTIFICATION: { @@ -2622,29 +2695,23 @@ namespace sat { case card_t: { card& c = cnstr.to_card(); ineq.reset(offset*c.k()); - for (unsigned i = 0; i < c.size(); ++i) { - ineq.push(c[i], offset); - } + for (literal l : c) ineq.push(l, offset); if (c.lit() != null_literal) ineq.push(~c.lit(), offset*c.k()); break; } case pb_t: { pb& p = cnstr.to_pb(); ineq.reset(p.k()); - for (unsigned i = 0; i < p.size(); ++i) { - ineq.push(p[i].second, p[i].first); - } + for (wliteral wl : p) ineq.push(wl.second, wl.first); if (p.lit() != null_literal) ineq.push(~p.lit(), p.k()); break; } case xor_t: { xor& x = cnstr.to_xor(); literal_vector ls; - get_xor_antecedents(lit, x, ls); + get_antecedents(lit, x, ls); ineq.reset(offset); - for (unsigned i = 0; i < ls.size(); ++i) { - ineq.push(~ls[i], offset); - } + for (literal l : ls) ineq.push(~l, offset); literal lxor = x.lit(); if (lxor != null_literal) ineq.push(~lxor, offset); break; @@ -2729,13 +2796,13 @@ namespace sat { } bool ba_solver::validate_conflict(literal_vector const& lits, ineq& p) { - for (unsigned i = 0; i < lits.size(); ++i) { - if (value(lits[i]) != l_false) { - TRACE("sat", tout << "literal " << lits[i] << " is not false\n";); + for (literal l : lits) { + if (value(l) != l_false) { + TRACE("sat", tout << "literal " << l << " is not false\n";); return false; } } - unsigned value = 0; + unsigned value = 0; for (unsigned i = 0; i < p.m_lits.size(); ++i) { unsigned coeff = p.m_coeffs[i]; if (!lits.contains(p.m_lits[i])) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 950580b20..ca6b0d093 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -32,15 +32,9 @@ namespace sat { friend class local_search; struct stats { - unsigned m_num_card_propagations; - unsigned m_num_card_conflicts; - unsigned m_num_card_resolves; - unsigned m_num_xor_propagations; - unsigned m_num_xor_conflicts; - unsigned m_num_xor_resolves; - unsigned m_num_pb_propagations; - unsigned m_num_pb_conflicts; - unsigned m_num_pb_resolves; + unsigned m_num_propagations; + unsigned m_num_conflicts; + unsigned m_num_resolves; unsigned m_num_bin_subsumes; unsigned m_num_clause_subsumes; unsigned m_num_card_subsumes; @@ -64,9 +58,11 @@ namespace sat { tag_t m_tag; bool m_removed; literal m_lit; + unsigned m_glue; unsigned m_size; + size_t m_obj_size; public: - constraint(tag_t t, literal l, unsigned sz): m_tag(t), m_removed(false), m_lit(l), m_size(sz) {} + constraint(tag_t t, literal l, unsigned sz, size_t osz): m_tag(t), m_removed(false), m_lit(l), m_glue(0), m_size(sz), m_obj_size(osz) {} ext_constraint_idx index() const { return reinterpret_cast(this); } tag_t tag() const { return m_tag; } literal lit() const { return m_lit; } @@ -76,8 +72,10 @@ namespace sat { bool was_removed() const { return m_removed; } void remove() { m_removed = true; } void nullify_literal() { m_lit = null_literal; } + unsigned glue() const { return m_glue; } + void set_glue(unsigned g) { m_glue = g; } - + size_t obj_size() const { return m_obj_size; } card& to_card(); pb& to_pb(); xor& to_xor(); @@ -117,7 +115,6 @@ namespace sat { unsigned m_num_watch; unsigned m_max_sum; wliteral m_wlits[0]; - void update_max_sum(); public: static size_t get_obj_size(unsigned num_lits) { return sizeof(pb) + num_lits * sizeof(wliteral); } pb(literal lit, svector const& wlits, unsigned k); @@ -136,6 +133,7 @@ namespace sat { void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } void negate(); void update_k(unsigned k) { m_k = k; } + void update_max_sum(); literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } }; @@ -162,14 +160,15 @@ namespace sat { void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } }; - solver* m_solver; - lookahead* m_lookahead; - stats m_stats; + solver* m_solver; + lookahead* m_lookahead; + stats m_stats; + small_object_allocator m_allocator; + ptr_vector m_constraints; - - // watch literals - unsigned_vector m_constraint_lim; + ptr_vector m_learned; + unsigned_vector m_constraint_lim; // conflict resolution unsigned m_num_marks; @@ -190,8 +189,6 @@ namespace sat { void inc_parity(bool_var v); void reset_parity(bool_var v); - void pop_constraint(); - solver& s() const { return *m_solver; } @@ -206,7 +203,6 @@ namespace sat { bool m_constraint_removed; literal_vector m_roots; unsigned_vector m_weights; - void gc(); bool subsumes(card& c1, card& c2, literal_vector& comp); bool subsumes(card& c1, clause& c2, literal_vector& comp); bool subsumed(card& c1, literal l1, literal l2); @@ -218,11 +214,22 @@ namespace sat { bool is_marked(literal l) const { return m_visited[l.index()] != 0; } unsigned get_num_non_learned_bin(literal l); literal get_min_occurrence_literal(card const& c); + void init_use_lists(); + void remove_unused_defs(); + unsigned set_non_external(); + unsigned elim_pure(); + void subsumption(); void subsumption(card& c1); + void gc_half(char const* _method); + void cleanup_clauses(); void cleanup_constraints(); + void cleanup_constraints(ptr_vector& cs); + void remove_constraint(constraint& c); // constraints + constraint& index2constraint(size_t idx) const { return *reinterpret_cast(idx); } + void pop_constraint(); void unwatch_literal(literal w, constraint& c); void watch_literal(literal w, constraint& c); void watch_literal(wliteral w, pb& p); @@ -232,18 +239,20 @@ namespace sat { lbool add_assign(constraint& c, literal l); void simplify(constraint& c); void nullify_tracking_literal(constraint& c); + void set_conflict(constraint& c, literal lit); + void assign(constraint& c, literal lit); + void get_antecedents(literal l, constraint const& c, literal_vector & r); + bool validate_conflict(constraint const& c) const; + bool validate_unit_propagation(constraint const& c, literal alit) const; // cardinality void init_watch(card& c, bool is_true); - void assign(card& c, literal lit); lbool add_assign(card& c, literal lit); - void set_conflict(card& c, literal lit); void clear_watch(card& c); void reset_coeffs(); void reset_marked_literals(); - void get_card_antecedents(literal l, card const& c, literal_vector & r); + void get_antecedents(literal l, card const& c, literal_vector & r); void simplify(card& c); - void remove_constraint(card& c); void unit_propagation_simplification(literal lit, literal_vector const& lits); void flush_roots(card& c); void recompile(card& c); @@ -251,34 +260,27 @@ namespace sat { // xor specific functionality void clear_watch(xor& x); void init_watch(xor& x, bool is_true); - void assign(xor& x, literal lit); - void set_conflict(xor& x, literal lit); bool parity(xor const& x, unsigned offset) const; lbool add_assign(xor& x, literal alit); void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); - void get_xor_antecedents(literal l, xor const& x, literal_vector & r); + void get_antecedents(literal l, xor const& x, literal_vector & r); void simplify(xor& x); void flush_roots(xor& x); - - constraint& index2constraint(size_t idx) const { return *reinterpret_cast(idx); } - // pb functionality unsigned m_a_max; void init_watch(pb& p, bool is_true); lbool add_assign(pb& p, literal alit); void add_index(pb& p, unsigned index, literal lit); void clear_watch(pb& p); - void set_conflict(pb& p, literal lit); - void assign(pb& p, literal l); - void get_pb_antecedents(literal l, pb const& p, literal_vector & r); + void get_antecedents(literal l, pb const& p, literal_vector & r); void simplify(pb& p); void simplify2(pb& p); bool is_cardinality(pb const& p); - void remove_constraint(pb& p); void flush_roots(pb& p); void recompile(pb& p); + // access solver inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } inline unsigned lvl(bool_var v) const { return m_solver->lvl(v); } @@ -301,12 +303,14 @@ namespace sat { void cut(); // validation utilities - bool validate_conflict(card& c); - bool validate_conflict(xor& x); + bool validate_conflict(card const& c) const; + bool validate_conflict(xor const& x) const; + bool validate_conflict(pb const& p) const; bool validate_assign(literal_vector const& lits, literal lit); bool validate_lemma(); - bool validate_unit_propagation(card const& c); - bool validate_unit_propagation(pb const& p, literal lit); + bool validate_unit_propagation(card const& c, literal alit) const; + bool validate_unit_propagation(pb const& p, literal alit) const; + bool validate_unit_propagation(xor const& x, literal alit) const; bool validate_conflict(literal_vector const& lits, ineq& p); ineq m_A, m_B, m_C; @@ -315,6 +319,7 @@ namespace sat { bool validate_resolvent(); void display(std::ostream& out, ineq& p) const; + void display(std::ostream& out, constraint const& c, bool values) const; void display(std::ostream& out, card const& c, bool values) const; void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xor const& c, bool values) const; @@ -349,6 +354,7 @@ namespace sat { virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); virtual void find_mutexes(literal_vector& lits, vector & mutexes); + virtual void gc(); ptr_vector const & constraints() const { return m_constraints; } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index d3a58810c..642171610 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -52,6 +52,7 @@ namespace sat { virtual void collect_statistics(statistics& st) const = 0; virtual extension* copy(solver* s) = 0; virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; + virtual void gc() = 0; }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 341bcc906..7a6955ef8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1641,6 +1641,7 @@ namespace sat { UNREACHABLE(); break; } + if (m_ext) m_ext->gc(); m_conflicts_since_gc = 0; m_gc_threshold += m_config.m_gc_increment; CASSERT("sat_gc_bug", check_invariant()); @@ -3148,26 +3149,16 @@ namespace sat { } unsigned solver::num_clauses() const { - unsigned num_cls = 0; - num_cls += m_trail.size(); // units; - vector::const_iterator it = m_watches.begin(); - vector::const_iterator end = m_watches.end(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - literal l = ~to_literal(l_idx); - watch_list const & wlist = *it; - watch_list::const_iterator it2 = wlist.begin(); - watch_list::const_iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - if (it2->is_binary_clause() && l.index() < it2->get_literal().index()) + unsigned num_cls = m_trail.size(); // units; + unsigned l_idx = 0; + for (auto const& wl : m_watches) { + literal l = ~to_literal(l_idx++); + for (auto const& w : wl) { + if (w.is_binary_clause() && l.index() < w.get_literal().index()) num_cls++; } } - clause_vector const * vs[2] = { &m_clauses, &m_learned }; - for (unsigned i = 0; i < 2; i++) { - clause_vector const & cs = *(vs[i]); - num_cls += cs.size(); - } - return num_cls; + return num_cls + m_clauses.size() + m_learned.size(); } void solver::display_dimacs(std::ostream & out) const { @@ -3175,28 +3166,21 @@ namespace sat { for (unsigned i = 0; i < m_trail.size(); i++) { out << dimacs_lit(m_trail[i]) << " 0\n"; } - vector::const_iterator it = m_watches.begin(); - vector::const_iterator end = m_watches.end(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - literal l = ~to_literal(l_idx); - watch_list const & wlist = *it; - watch_list::const_iterator it2 = wlist.begin(); - watch_list::const_iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - if (it2->is_binary_clause() && l.index() < it2->get_literal().index()) - out << dimacs_lit(l) << " " << dimacs_lit(it2->get_literal()) << " 0\n"; + unsigned l_idx = 0; + for (auto const& wlist : m_watches) { + literal l = ~to_literal(l_idx++); + for (auto const& w : wlist) { + if (w.is_binary_clause() && l.index() < w.get_literal().index()) + out << dimacs_lit(l) << " " << dimacs_lit(w.get_literal()) << " 0\n"; } } clause_vector const * vs[2] = { &m_clauses, &m_learned }; for (unsigned i = 0; i < 2; i++) { clause_vector const & cs = *(vs[i]); - clause_vector::const_iterator it = cs.begin(); - clause_vector::const_iterator end = cs.end(); - for (; it != end; ++it) { - clause const & c = *(*it); - unsigned sz = c.size(); - for (unsigned j = 0; j < sz; j++) - out << dimacs_lit(c[j]) << " "; + for (auto cp : cs) { + for (literal l : *cp) { + out << dimacs_lit(l) << " "; + } out << "0\n"; } } @@ -3269,9 +3253,8 @@ namespace sat { */ bool solver::is_unit(clause const & c) const { bool found_undef = false; - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - switch (value(c[i])) { + for (literal l : c) { + switch (value(l)) { case l_undef: if (found_undef) return false; From bcf0ee77096fd70d3cd60da2097c2562ca6bf249 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Jun 2017 18:53:58 -0700 Subject: [PATCH 0182/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 255 +++++++++++++++++++++++++++++++++------- src/sat/ba_solver.h | 29 ++++- src/sat/sat_extension.h | 1 + src/sat/sat_lookahead.h | 1 + src/sat/sat_solver.cpp | 21 ++-- src/sat/sat_watched.cpp | 3 +- src/sat/sat_watched.h | 2 +- 7 files changed, 252 insertions(+), 60 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 7d9e16df0..22c77f164 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -69,6 +69,14 @@ namespace sat { SASSERT(m_size >= m_k && m_k > 0); } + bool ba_solver::card::is_watching(literal l) const { + unsigned sz = std::min(k() + 1, size()); + for (unsigned i = 0; i < sz; ++i) { + if ((*this)[i] == l) return true; + } + return false; + } + std::ostream& operator<<(std::ostream& out, ba_solver::constraint const& cnstr) { if (cnstr.lit() != null_literal) out << cnstr.lit() << " == "; switch (cnstr.tag()) { @@ -135,6 +143,14 @@ namespace sat { m_k = w - m_k + 1; SASSERT(w >= m_k && m_k > 0); } + + bool ba_solver::pb::is_watching(literal l) const { + for (unsigned i = 0; i < m_num_watch; ++i) { + if ((*this)[i].second == l) return true; + } + return false; + } + ba_solver::xor::xor(literal lit, literal_vector const& lits): constraint(xor_t, lit, lits.size(), get_obj_size(lits.size())) { @@ -143,6 +159,12 @@ namespace sat { } } + bool ba_solver::xor::is_watching(literal l) const { + return + l == (*this)[0] || l == (*this)[1] || + ~l == (*this)[0] || ~l == (*this)[1]; + } + void ba_solver::init_watch(card& c, bool is_true) { clear_watch(c); if (c.lit() != null_literal && c.lit().sign() == is_true) { @@ -211,14 +233,6 @@ namespace sat { } } - void ba_solver::unwatch_literal(literal lit, constraint& c) { - get_wlist(~lit).erase(watched(c.index())); - } - - void ba_solver::watch_literal(literal lit, constraint& c) { - get_wlist(~lit).push_back(watched(c.index())); - } - void ba_solver::set_conflict(constraint& c, literal lit) { m_stats.m_num_conflicts++; TRACE("sat", display(tout, c, true); ); @@ -510,7 +524,6 @@ namespace sat { } void ba_solver::simplify(pb& p) { - s().pop_to_base_level(); if (p.lit() != null_literal && value(p.lit()) == l_false) { TRACE("sat", tout << "pb: flip sign " << p << "\n";); return; @@ -629,6 +642,8 @@ namespace sat { void ba_solver::clear_watch(xor& x) { unwatch_literal(x[0], x); unwatch_literal(x[1], x); + unwatch_literal(~x[0], x); + unwatch_literal(~x[1], x); } bool ba_solver::parity(xor const& x, unsigned offset) const { @@ -678,6 +693,8 @@ namespace sat { SASSERT(j == 2); watch_literal(x[0], x); watch_literal(x[1], x); + watch_literal(~x[0], x); + watch_literal(~x[1], x); break; } } @@ -1157,6 +1174,14 @@ namespace sat { s().set_external(lit.var()); get_wlist(lit).push_back(c->index()); get_wlist(~lit).push_back(c->index()); + if (!validate_watched_constraint(*c)) { + std::cout << "wrong: " << *c << "\n"; + } + } + if (lit.var() == 102770) { + display(std::cout, *c, true); + display_watch_list(std::cout, s().m_cls_allocator, get_wlist(lit)) << "\n"; + display_watch_list(std::cout, s().m_cls_allocator, get_wlist(~lit)) << "\n"; } } @@ -1208,6 +1233,7 @@ namespace sat { if (c.lit() != null_literal && l.var() == c.lit().var()) { init_watch(c, !l.sign()); keep = true; + if (!inconsistent()) validate_watched_constraint(c); } else if (c.lit() != null_literal && value(c.lit()) != l_true) { keep = false; @@ -1215,6 +1241,7 @@ namespace sat { else { keep = l_undef != add_assign(c, ~l); } + std::cout << c.lit() << " " << l << " " << keep << "\n"; } @@ -1444,10 +1471,21 @@ namespace sat { } } + // ---------------------------- + // constraint generic methods + void ba_solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { get_antecedents(l, index2constraint(idx), r); } + void ba_solver::unwatch_literal(literal lit, constraint& c) { + get_wlist(~lit).erase(watched(c.index())); + } + + void ba_solver::watch_literal(literal lit, constraint& c) { + get_wlist(~lit).push_back(watched(c.index())); + } + void ba_solver::get_antecedents(literal l, constraint const& c, literal_vector& r) { switch (c.tag()) { case card_t: get_antecedents(l, c.to_card(), r); break; @@ -1457,7 +1495,38 @@ namespace sat { } } + void ba_solver::nullify_tracking_literal(constraint& c) { + if (c.lit() != null_literal) { + get_wlist(c.lit()).erase(watched(c.index())); + get_wlist(~c.lit()).erase(watched(c.index())); + c.nullify_literal(); + } + } + + void ba_solver::remove_constraint(constraint& c) { + nullify_tracking_literal(c); + switch (c.tag()) { + case card_t: + clear_watch(c.to_card()); + break; + case pb_t: + clear_watch(c.to_pb()); + break; + case xor_t: + clear_watch(c.to_xor()); + break; + default: + UNREACHABLE(); + } + c.remove(); + m_constraint_removed = true; + } + + // -------------------------------- + // validation + bool ba_solver::validate_unit_propagation(constraint const& c, literal l) const { + return true; switch (c.tag()) { case card_t: return validate_unit_propagation(c.to_card(), l); case pb_t: return validate_unit_propagation(c.to_pb(), l); @@ -1468,6 +1537,7 @@ namespace sat { } bool ba_solver::validate_conflict(constraint const& c) const { + return true; switch (c.tag()) { case card_t: return validate_conflict(c.to_card()); case pb_t: return validate_conflict(c.to_pb()); @@ -1477,6 +1547,133 @@ namespace sat { return false; } + bool ba_solver::is_true(constraint const& c) const { + lbool v1 = c.lit() == null_literal ? l_true : value(c.lit()); + if (v1 == l_undef) return false; + switch (c.tag()) { + case card_t: return v1 == value(c.to_card()); + case pb_t: return v1 == value(c.to_pb()); + case xor_t: return v1 == value(c.to_xor()); + default: UNREACHABLE(); break; + } + return false; + } + + lbool ba_solver::value(card const& c) const { + unsigned trues = 0, undefs = 0; + for (literal l : c) { + switch (value(l)) { + case l_true: trues++; break; + case l_undef: undefs++; break; + default: break; + } + } + if (trues + undefs < c.k()) return l_false; + if (trues >= c.k()) return l_true; + return l_undef; + } + + lbool ba_solver::value(pb const& p) const { + unsigned trues = 0, undefs = 0; + for (wliteral wl : p) { + switch (value(wl.second)) { + case l_true: trues += wl.first; break; + case l_undef: undefs += wl.first; break; + default: break; + } + } + if (trues + undefs < p.k()) return l_false; + if (trues >= p.k()) return l_true; + return l_undef; + } + + lbool ba_solver::value(xor const& x) const { + bool odd = false; + + for (auto l : x) { + switch (value(l)) { + case l_true: odd = !odd; break; + case l_false: break; + default: return l_undef; + } + } + return odd ? l_true : l_false; + } + + void ba_solver::validate() { + if (validate_watch_literals()) { + for (constraint* c : m_constraints) { + if (!validate_watched_constraint(*c)) break; + } + } + } + + bool ba_solver::validate_watch_literals() const { + for (unsigned v = 0; v < s().num_vars(); ++v) { + literal lit(v, false); + if (lvl(lit) == 0) continue; + if (!validate_watch_literal(lit)) return false; + if (!validate_watch_literal(~lit)) return false; + } + return true; + } + + bool ba_solver::validate_watch_literal(literal lit) const { + if (lvl(lit) == 0) return true; + for (auto const & w : get_wlist(lit)) { + if (w.get_kind() == watched::EXT_CONSTRAINT) { + constraint const& c = index2constraint(w.get_ext_constraint_idx()); + if (!c.is_watching(~lit)) { + std::cout << lit << " " << lvl(lit) << " is not watched in " << c << "\n"; + display(std::cout, c, true); + UNREACHABLE(); + return false; + } + } + } + return true; + } + + bool ba_solver::validate_watched_constraint(constraint const& c) const { + if (c.lit() != null_literal && value(c.lit()) != l_true) return true; + if (c.lit() != null_literal && lvl(c.lit()) != 0) { + if (!is_watching(c.lit(), c) || !is_watching(~c.lit(), c)) { + std::cout << "Definition literal is not watched " << c.lit() << " " << c << "\n"; + display_watch_list(std::cout, s().m_cls_allocator, get_wlist(c.lit())) << "\n"; + display_watch_list(std::cout, s().m_cls_allocator, get_wlist(~c.lit())) << "\n"; + return false; + } + } + if (is_true(c)) { + return true; + } + literal_vector lits(c.literals()); + for (literal l : lits) { + if (lvl(l) == 0) continue; + bool found = is_watching(l, c); + if (found != c.is_watching(l)) { + std::cout << "Discrepancy of watched literal: " << l << ": " << c.index() << " " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n"; + display_watch_list(std::cout << l << ": ", s().m_cls_allocator, get_wlist(l)) << "\n"; + display_watch_list(std::cout << ~l << ": ", s().m_cls_allocator, get_wlist(~l)) << "\n"; + std::cout << "value: " << value(l) << " level: " << lvl(l) << "\n"; + display(std::cout, c, true); + if (c.lit() != null_literal) std::cout << value(c.lit()) << "\n"; + UNREACHABLE(); + exit(1); + return false; + } + } + return true; + } + + bool ba_solver::is_watching(literal lit, constraint const& c) const { + for (auto w : get_wlist(~lit)) { + if (w.get_kind() == watched::EXT_CONSTRAINT && w.get_ext_constraint_idx() == c.index()) + return true; + } + return false; + } + /** \brief Lex on (glue, size) */ @@ -1507,33 +1704,6 @@ namespace sat { } - void ba_solver::nullify_tracking_literal(constraint& c) { - if (c.lit() != null_literal) { - get_wlist(c.lit()).erase(watched(c.index())); - get_wlist(~c.lit()).erase(watched(c.index())); - c.nullify_literal(); - } - } - - void ba_solver::remove_constraint(constraint& c) { - nullify_tracking_literal(c); - switch (c.tag()) { - case card_t: - clear_watch(c.to_card()); - break; - case pb_t: - clear_watch(c.to_pb()); - break; - case xor_t: - clear_watch(c.to_xor()); - break; - default: - UNREACHABLE(); - } - c.remove(); - m_constraint_removed = true; - } - void ba_solver::simplify(card& c) { SASSERT(c.lit() == null_literal || value(c.lit()) != l_false); if (c.lit() != null_literal && value(c.lit()) == l_false) { @@ -1722,7 +1892,7 @@ namespace sat { void ba_solver::simplify() { return; - if (!s().at_base_lvl()) s().pop_to_base_level(); + SASSERT(s().at_base_lvl()); unsigned trail_sz; do { m_simplify_change = false; @@ -1760,6 +1930,10 @@ namespace sat { void ba_solver::flush_roots() { if (m_roots.empty()) return; + + std::cout << "pre\n"; + validate(); + m_visited.resize(s().num_vars()*2, false); m_constraint_removed = false; for (constraint* c : m_constraints) { @@ -1778,6 +1952,8 @@ namespace sat { } } cleanup_constraints(); + std::cout << "post\n"; + validate(); // display(std::cout << "flush roots\n"); } @@ -1907,7 +2083,7 @@ namespace sat { } void ba_solver::recompile(pb& p) { - // IF_VERBOSE(0, verbose_stream() << "re: " << p << "\n";); + IF_VERBOSE(0, verbose_stream() << "re: " << p << "\n";); m_weights.resize(2*s().num_vars(), 0); for (wliteral wl : p) { m_weights[wl.second.index()] += wl.first; @@ -1965,11 +2141,10 @@ namespace sat { p.update_k(k); p.update_max_sum(); - literal root = null_literal; if (p.lit() != null_literal) root = m_roots[p.lit().index()]; - // IF_VERBOSE(0, verbose_stream() << "new: " << p << "\n";); + IF_VERBOSE(0, verbose_stream() << "new: " << p << "\n";); // std::cout << "simplified " << p << "\n"; if (p.lit() != root) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index ca6b0d093..2c2a5d914 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -74,6 +74,7 @@ namespace sat { void nullify_literal() { m_lit = null_literal; } unsigned glue() const { return m_glue; } void set_glue(unsigned g) { m_glue = g; } + size_t obj_size() const { return m_obj_size; } card& to_card(); @@ -85,6 +86,9 @@ namespace sat { bool is_card() const { return m_tag == card_t; } bool is_pb() const { return m_tag == pb_t; } bool is_xor() const { return m_tag == xor_t; } + + virtual bool is_watching(literal l) const { return false; }; + virtual literal_vector literals() const { return literal_vector(); } }; friend std::ostream& operator<<(std::ostream& out, constraint const& c); @@ -103,7 +107,8 @@ namespace sat { void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate(); void update_k(unsigned k) { m_k = k; } - literal_vector literals() const { return literal_vector(m_size, m_lits); } + virtual literal_vector literals() const { return literal_vector(m_size, m_lits); } + virtual bool is_watching(literal l) const; }; @@ -122,7 +127,7 @@ namespace sat { wliteral operator[](unsigned i) const { return m_wlits[i]; } wliteral& operator[](unsigned i) { return m_wlits[i]; } wliteral const* begin() const { return m_wlits; } - wliteral const* end() const { return static_cast(m_wlits) + m_size; } + wliteral const* end() const { return begin() + m_size; } unsigned k() const { return m_k; } unsigned slack() const { return m_slack; } @@ -134,7 +139,8 @@ namespace sat { void negate(); void update_k(unsigned k) { m_k = k; } void update_max_sum(); - literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } + virtual literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } + virtual bool is_watching(literal l) const; }; class xor : public constraint { @@ -144,9 +150,11 @@ namespace sat { xor(literal lit, literal_vector const& lits); literal operator[](unsigned i) const { return m_lits[i]; } literal const* begin() const { return m_lits; } - literal const* end() const { return static_cast(m_lits) + m_size; } + literal const* end() const { return begin() + m_size; } void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate() { m_lits[0].neg(); } + virtual bool is_watching(literal l) const; + virtual literal_vector literals() const { return literal_vector(size(), begin()); } }; @@ -244,6 +252,9 @@ namespace sat { void get_antecedents(literal l, constraint const& c, literal_vector & r); bool validate_conflict(constraint const& c) const; bool validate_unit_propagation(constraint const& c, literal alit) const; + void attach_constraint(constraint const& c); + void detach_constraint(constraint const& c); + bool is_true(constraint const& c) const; // cardinality void init_watch(card& c, bool is_true); @@ -256,6 +267,7 @@ namespace sat { void unit_propagation_simplification(literal lit, literal_vector const& lits); void flush_roots(card& c); void recompile(card& c); + lbool value(card const& c) const; // xor specific functionality void clear_watch(xor& x); @@ -266,6 +278,7 @@ namespace sat { void get_antecedents(literal l, xor const& x, literal_vector & r); void simplify(xor& x); void flush_roots(xor& x); + lbool value(xor const& x) const; // pb functionality unsigned m_a_max; @@ -279,6 +292,7 @@ namespace sat { bool is_cardinality(pb const& p); void flush_roots(pb& p); void recompile(pb& p); + lbool value(pb const& p) const; // access solver inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } @@ -286,6 +300,7 @@ namespace sat { inline unsigned lvl(bool_var v) const { return m_solver->lvl(v); } inline bool inconsistent() const { return m_lookahead ? m_lookahead->inconsistent() : m_solver->inconsistent(); } inline watch_list& get_wlist(literal l) { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } + inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); } inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); } inline config const& get_config() const { return m_solver->get_config(); } @@ -312,6 +327,10 @@ namespace sat { bool validate_unit_propagation(pb const& p, literal alit) const; bool validate_unit_propagation(xor const& x, literal alit) const; bool validate_conflict(literal_vector const& lits, ineq& p); + bool validate_watch_literals() const; + bool validate_watch_literal(literal lit) const; + bool validate_watched_constraint(constraint const& c) const; + bool is_watching(literal lit, constraint const& c) const; ineq m_A, m_B, m_C; void active2pb(ineq& p); @@ -358,6 +377,8 @@ namespace sat { ptr_vector const & constraints() const { return m_constraints; } + virtual void validate(); + }; }; diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 642171610..f984091e3 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -53,6 +53,7 @@ namespace sat { virtual extension* copy(solver* s) = 0; virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; virtual void gc() = 0; + virtual void validate() = 0; }; }; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 43c2612b8..067a95c55 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -372,6 +372,7 @@ namespace sat { void attach_ternary(ternary const& t); void attach_ternary(literal l1, literal l2, literal l3); watch_list& get_wlist(literal l) { return m_watches[l.index()]; } + watch_list const& get_wlist(literal l) const { return m_watches[l.index()]; } // ------------------------------------ // initialization diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 7a6955ef8..dfa85569c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1391,6 +1391,7 @@ namespace sat { */ void solver::simplify_problem() { + if (m_ext) m_ext->validate(); if (m_conflicts_since_init < m_next_simplify) { return; } @@ -1403,12 +1404,15 @@ namespace sat { SASSERT(at_base_lvl()); m_cleaner(); + if (m_ext) m_ext->validate(); CASSERT("sat_simplify_bug", check_invariant()); m_scc(); + if (m_ext) m_ext->validate(); CASSERT("sat_simplify_bug", check_invariant()); m_simplifier(false); + if (m_ext) m_ext->validate(); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); @@ -1417,6 +1421,7 @@ namespace sat { CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); } + if (m_ext) m_ext->validate(); if (m_config.m_lookahead_simplify) { { @@ -1435,10 +1440,12 @@ namespace sat { CASSERT("sat_simplify_bug", check_invariant()); m_probing(); + if (m_ext) m_ext->validate(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); m_asymm_branch(); + if (m_ext) m_ext->validate(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); @@ -1460,21 +1467,7 @@ namespace sat { m_next_simplify = m_conflicts_since_init + m_config.m_simplify_max; } -#if 0 - static unsigned file_no = 0; - #pragma omp critical (print_sat) - { - ++file_no; - std::ostringstream ostrm; - ostrm << "s" << file_no << ".txt"; - std::ofstream ous(ostrm.str()); - display(ous); - } -#endif - if (m_par) m_par->set_phase(*this); - - } bool solver::set_root(literal l, literal r) { diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index 1b294351f..d1642d50f 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -39,7 +39,7 @@ namespace sat { return false; } - void display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) { + std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) { watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); for (bool first = true; it != end; ++it) { @@ -66,6 +66,7 @@ namespace sat { UNREACHABLE(); } } + return out; } }; diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index b9a0962e9..fa7008818 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -130,7 +130,7 @@ namespace sat { inline void erase_ternary_watch(watch_list & wlist, literal l1, literal l2) { wlist.erase(watched(l1, l2)); } class clause_allocator; - void display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist); + std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist); }; #endif From 9b631f982b13ba73fd55e400ed9339d3bd2ce6ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Jun 2017 17:48:04 -0700 Subject: [PATCH 0183/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 701 +++++++++++++++++------------------------ src/sat/ba_solver.h | 77 +++-- src/sat/sat_solver.cpp | 27 +- src/util/max_cliques.h | 11 +- 4 files changed, 360 insertions(+), 456 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 22c77f164..7884018fc 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -52,31 +52,6 @@ namespace sat { return static_cast(*this); } - ba_solver::card::card(literal lit, literal_vector const& lits, unsigned k): - constraint(card_t, lit, lits.size(), get_obj_size(lits.size())), - m_k(k) { - for (unsigned i = 0; i < size(); ++i) { - m_lits[i] = lits[i]; - } - } - - void ba_solver::card::negate() { - m_lit.neg(); - for (unsigned i = 0; i < m_size; ++i) { - m_lits[i].neg(); - } - m_k = m_size - m_k + 1; - SASSERT(m_size >= m_k && m_k > 0); - } - - bool ba_solver::card::is_watching(literal l) const { - unsigned sz = std::min(k() + 1, size()); - for (unsigned i = 0; i < sz; ++i) { - if ((*this)[i] == l) return true; - } - return false; - } - std::ostream& operator<<(std::ostream& out, ba_solver::constraint const& cnstr) { if (cnstr.lit() != null_literal) out << cnstr.lit() << " == "; switch (cnstr.tag()) { @@ -111,9 +86,53 @@ namespace sat { return out; } + + // ----------------------- + // pb_base + + bool ba_solver::pb_base::well_formed() const { + uint_set vars; + for (unsigned i = 0; i < size(); ++i) { + bool_var v = get_lit(i).var(); + if (vars.contains(v)) return false; + if (get_coeff(i) > k()) return false; + vars.insert(v); + } + return true; + } + + // ---------------------- + // card + + ba_solver::card::card(literal lit, literal_vector const& lits, unsigned k): + pb_base(card_t, lit, lits.size(), get_obj_size(lits.size()), k) { + for (unsigned i = 0; i < size(); ++i) { + m_lits[i] = lits[i]; + } + } + + void ba_solver::card::negate() { + m_lit.neg(); + for (unsigned i = 0; i < m_size; ++i) { + m_lits[i].neg(); + } + m_k = m_size - m_k + 1; + SASSERT(m_size >= m_k && m_k > 0); + } + + bool ba_solver::card::is_watching(literal l) const { + unsigned sz = std::min(k() + 1, size()); + for (unsigned i = 0; i < sz; ++i) { + if ((*this)[i] == l) return true; + } + return false; + } + + // ----------------------------------- + // pb + ba_solver::pb::pb(literal lit, svector const& wlits, unsigned k): - constraint(pb_t, lit, wlits.size(), get_obj_size(wlits.size())), - m_k(k), + pb_base(pb_t, lit, wlits.size(), get_obj_size(wlits.size()), k), m_slack(0), m_num_watch(0), m_max_sum(0) { @@ -126,6 +145,7 @@ namespace sat { void ba_solver::pb::update_max_sum() { m_max_sum = 0; for (unsigned i = 0; i < size(); ++i) { + m_wlits[i].first = std::min(k(), m_wlits[i].first); if (m_max_sum + m_wlits[i].first < m_max_sum) { throw default_exception("addition of pb coefficients overflows"); } @@ -151,6 +171,17 @@ namespace sat { return false; } + + bool ba_solver::pb::is_cardinality() const { + if (size() == 0) return false; + unsigned w = (*this)[0].first; + for (wliteral wl : *this) if (w != wl.first) return false; + return true; + } + + + // ----------------------------------- + // xor ba_solver::xor::xor(literal lit, literal_vector const& lits): constraint(xor_t, lit, lits.size(), get_obj_size(lits.size())) { @@ -165,6 +196,19 @@ namespace sat { ~l == (*this)[0] || ~l == (*this)[1]; } + bool ba_solver::xor::well_formed() const { + uint_set vars; + for (literal l : *this) { + bool_var v = l.var(); + if (vars.contains(v)) return false; + vars.insert(v); + } + return true; + } + + // ---------------------------- + // card + void ba_solver::init_watch(card& c, bool is_true) { clear_watch(c); if (c.lit() != null_literal && c.lit().sign() == is_true) { @@ -233,6 +277,9 @@ namespace sat { } } + // ----------------------- + // constraint + void ba_solver::set_conflict(constraint& c, literal lit) { m_stats.m_num_conflicts++; TRACE("sat", display(tout, c, true); ); @@ -243,7 +290,6 @@ namespace sat { SASSERT(inconsistent()); } - void ba_solver::assign(constraint& c, literal lit) { switch (value(lit)) { case l_true: @@ -269,7 +315,8 @@ namespace sat { } } - // pb: + // ------------------- + // pb // watch a prefix of literals, such that the slack of these is >= k @@ -473,7 +520,10 @@ namespace sat { for (wliteral wl : p) unwatch_literal(wl.second, p); } - void ba_solver::unit_propagation_simplification(literal lit, literal_vector const& lits) { + /* + \brief lit <=> conjunction of unconstrained lits + */ + void ba_solver::assert_unconstrained(literal lit, literal_vector const& lits) { if (lit == null_literal) { for (literal l : lits) { if (value(l) == l_undef) { @@ -482,7 +532,7 @@ namespace sat { } } else { - // add clauses for: p.lit() <=> conjunction of undef literals + // add clauses for: lit <=> conjunction of undef literals SASSERT(value(lit) == l_undef); literal_vector cl; cl.push_back(lit); @@ -496,34 +546,28 @@ namespace sat { } } - bool ba_solver::is_cardinality(pb const& p) { - if (p.size() == 0) return false; - unsigned w = p[0].first; - for (wliteral wl : p) if (w != wl.first) return false; - return true; - } - void ba_solver::simplify2(pb& p) { - if (is_cardinality(p)) { + return; + if (p.is_cardinality()) { literal_vector lits(p.literals()); unsigned k = (p.k() + p[0].first - 1) / p[0].first; add_at_least(p.lit(), lits, k); remove_constraint(p); - return; } - if (p.lit() == null_literal) { + else if (p.lit() == null_literal) { for (wliteral wl : p) { if (p.k() > p.max_sum() - wl.first) { TRACE("sat", tout << "unit literal " << wl.second << "\n"; display(tout, p, true);); + s().assign(wl.second, justification()); } } } } - void ba_solver::simplify(pb& p) { + void ba_solver::simplify(pb_base& p) { if (p.lit() != null_literal && value(p.lit()) == l_false) { TRACE("sat", tout << "pb: flip sign " << p << "\n";); return; @@ -537,20 +581,18 @@ namespace sat { SASSERT(p.lit() == null_literal || value(p.lit()) == l_undef); unsigned true_val = 0, slack = 0, num_false = 0; - for (wliteral wl : p) { - switch (value(wl.second)) { - case l_true: true_val += wl.first; break; + for (unsigned i = 0; i < p.size(); ++i) { + switch (value(p.get_lit(i))) { + case l_true: true_val += p.get_coeff(i); break; case l_false: ++num_false; break; - default: slack += wl.first; break; + default: slack += p.get_coeff(i); break; } } if (true_val == 0 && num_false == 0) { // no op } else if (true_val >= p.k()) { - // std::cout << "tautology\n"; if (p.lit() != null_literal) { - // std::cout << "tautology at level 0\n"; s().assign(p.lit(), justification()); } remove_constraint(p); @@ -566,35 +608,31 @@ namespace sat { remove_constraint(p); } else if (slack + true_val == p.k()) { - // std::cout << "unit propagation\n"; literal_vector lits(p.literals()); - unit_propagation_simplification(p.lit(), lits); + assert_unconstrained(p.lit(), lits); remove_constraint(p); } else { - // std::cout << "pb value at base: " << true_val << " false: " << num_false << " size: " << p.size() << " k: " << p.k() << "\n"; unsigned sz = p.size(); clear_watch(p); for (unsigned i = 0; i < sz; ++i) { - if (value(p[i].second) != l_undef) { + if (value(p.get_lit(i)) != l_undef) { --sz; p.swap(i, sz); --i; } } - // std::cout << "new size: " << sz << " old size " << p.size() << "\n"; - p.update_size(sz); - p.update_k(p.k() - true_val); - p.update_max_sum(); + p.set_size(sz); + p.set_k(p.k() - true_val); // display(verbose_stream(), c, true); if (p.lit() == null_literal) { init_watch(p, true); } else { SASSERT(value(p.lit()) == l_undef); - // c will be watched once c.lit() is assigned. } - simplify2(p); + SASSERT(p.well_formed()); + if (p.is_pb()) simplify2(p.to_pb()); m_simplify_change = true; } } @@ -637,6 +675,7 @@ namespace sat { out << ">= " << p.k() << "\n"; } + // -------------------- // xor: void ba_solver::clear_watch(xor& x) { @@ -740,6 +779,9 @@ namespace sat { } return inconsistent() ? l_false : l_true; } + + // --------------------------- + // conflict resolution void ba_solver::normalize_active_coeffs() { while (!m_active_var_set.empty()) m_active_var_set.erase(); @@ -1003,7 +1045,7 @@ namespace sat { for (unsigned i = 0; 0 <= slack && i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; int coeff = get_coeff(v); - lbool val = s().value(v); + lbool val = value(v); bool is_true = val == l_true; bool append = coeff != 0 && val != l_undef && (coeff < 0 == is_true); if (append) { @@ -1174,15 +1216,8 @@ namespace sat { s().set_external(lit.var()); get_wlist(lit).push_back(c->index()); get_wlist(~lit).push_back(c->index()); - if (!validate_watched_constraint(*c)) { - std::cout << "wrong: " << *c << "\n"; - } } - if (lit.var() == 102770) { - display(std::cout, *c, true); - display_watch_list(std::cout, s().m_cls_allocator, get_wlist(lit)) << "\n"; - display_watch_list(std::cout, s().m_cls_allocator, get_wlist(~lit)) << "\n"; - } + SASSERT(c->well_formed()); } @@ -1204,10 +1239,11 @@ namespace sat { return l_undef; } - void ba_solver::add_pb_ge(literal lit, svector const& wlits, unsigned k) { + ba_solver::pb const& ba_solver::add_pb_ge(literal lit, svector const& wlits, unsigned k) { void * mem = m_allocator.allocate(pb::get_obj_size(wlits.size())); pb* p = new (mem) pb(lit, wlits, k); add_constraint(p); + return *p; } void ba_solver::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { @@ -1233,7 +1269,6 @@ namespace sat { if (c.lit() != null_literal && l.var() == c.lit().var()) { init_watch(c, !l.sign()); keep = true; - if (!inconsistent()) validate_watched_constraint(c); } else if (c.lit() != null_literal && value(c.lit()) != l_true) { keep = false; @@ -1241,7 +1276,6 @@ namespace sat { else { keep = l_undef != add_assign(c, ~l); } - std::cout << c.lit() << " " << l << " " << keep << "\n"; } @@ -1497,14 +1531,13 @@ namespace sat { void ba_solver::nullify_tracking_literal(constraint& c) { if (c.lit() != null_literal) { - get_wlist(c.lit()).erase(watched(c.index())); - get_wlist(~c.lit()).erase(watched(c.index())); + unwatch_literal(c.lit(), c); + unwatch_literal(~c.lit(), c); c.nullify_literal(); } } - void ba_solver::remove_constraint(constraint& c) { - nullify_tracking_literal(c); + void ba_solver::clear_watch(constraint& c) { switch (c.tag()) { case card_t: clear_watch(c.to_card()); @@ -1518,6 +1551,11 @@ namespace sat { default: UNREACHABLE(); } + } + + void ba_solver::remove_constraint(constraint& c) { + nullify_tracking_literal(c); + clear_watch(c); c.remove(); m_constraint_removed = true; } @@ -1537,29 +1575,26 @@ namespace sat { } bool ba_solver::validate_conflict(constraint const& c) const { - return true; - switch (c.tag()) { - case card_t: return validate_conflict(c.to_card()); - case pb_t: return validate_conflict(c.to_pb()); - case xor_t: return validate_conflict(c.to_xor()); - default: UNREACHABLE(); break; - } - return false; + return eval(c) == l_false; } - bool ba_solver::is_true(constraint const& c) const { + lbool ba_solver::eval(constraint const& c) const { lbool v1 = c.lit() == null_literal ? l_true : value(c.lit()); - if (v1 == l_undef) return false; switch (c.tag()) { - case card_t: return v1 == value(c.to_card()); - case pb_t: return v1 == value(c.to_pb()); - case xor_t: return v1 == value(c.to_xor()); + case card_t: return eval(v1, eval(c.to_card())); + case pb_t: return eval(v1, eval(c.to_pb())); + case xor_t: return eval(v1, eval(c.to_xor())); default: UNREACHABLE(); break; } - return false; + return l_undef; } - lbool ba_solver::value(card const& c) const { + lbool ba_solver::eval(lbool a, lbool b) const { + if (a == l_undef || b == l_undef) return l_undef; + return (a == b) ? l_true : l_false; + } + + lbool ba_solver::eval(card const& c) const { unsigned trues = 0, undefs = 0; for (literal l : c) { switch (value(l)) { @@ -1573,7 +1608,7 @@ namespace sat { return l_undef; } - lbool ba_solver::value(pb const& p) const { + lbool ba_solver::eval(pb const& p) const { unsigned trues = 0, undefs = 0; for (wliteral wl : p) { switch (value(wl.second)) { @@ -1587,7 +1622,7 @@ namespace sat { return l_undef; } - lbool ba_solver::value(xor const& x) const { + lbool ba_solver::eval(xor const& x) const { bool odd = false; for (auto l : x) { @@ -1623,7 +1658,7 @@ namespace sat { for (auto const & w : get_wlist(lit)) { if (w.get_kind() == watched::EXT_CONSTRAINT) { constraint const& c = index2constraint(w.get_ext_constraint_idx()); - if (!c.is_watching(~lit)) { + if (!c.is_watching(~lit) && lit.var() != c.lit().var()) { std::cout << lit << " " << lvl(lit) << " is not watched in " << c << "\n"; display(std::cout, c, true); UNREACHABLE(); @@ -1644,7 +1679,7 @@ namespace sat { return false; } } - if (is_true(c)) { + if (eval(c) == l_true) { return true; } literal_vector lits(c.literals()); @@ -1704,93 +1739,6 @@ namespace sat { } - void ba_solver::simplify(card& c) { - SASSERT(c.lit() == null_literal || value(c.lit()) != l_false); - if (c.lit() != null_literal && value(c.lit()) == l_false) { - return; -#if 0 - std::ofstream ous("unit.txt"); - s().display(ous); - s().display_watches(ous); - display(ous, c, true); - exit(1); - return; - init_watch(c, !c.lit().sign()); -#endif - } - if (c.lit() != null_literal && value(c.lit()) == l_true) { - SASSERT(lvl(c.lit()) == 0); - nullify_tracking_literal(c); - } - if (c.lit() == null_literal && c.k() == 1) { - literal_vector lits; - for (literal l : c) lits.push_back(l); - s().mk_clause(lits); - remove_constraint(c); - return; - } - - SASSERT(c.lit() == null_literal || value(c.lit()) == l_undef); - - unsigned num_true = 0, num_false = 0; - for (literal l : c) { - switch (value(l)) { - case l_true: ++num_true; break; - case l_false: ++num_false; break; - default: break; - } - } - - if (num_false + num_true == 0) { - // no simplification - return; - } - else if (num_true >= c.k()) { - if (c.lit() != null_literal) { - s().assign(c.lit(), justification()); - } - remove_constraint(c); - } - else if (num_false + c.k() > c.size()) { - if (c.lit() != null_literal) { - s().assign(~c.lit(), justification()); - remove_constraint(c); - } - else { - IF_VERBOSE(1, verbose_stream() << "(sat detected unsat)\n";); - } - } - else if (num_false + c.k() == c.size()) { - TRACE("sat", tout << "unit propagations : " << c.size() - num_false - num_true << "\n";); - literal_vector lits(c.literals()); - unit_propagation_simplification(c.lit(), lits); - remove_constraint(c); - } - else { - TRACE("sat", tout << "literals assigned at base: " << num_true + num_false << " " << c.size() << " k: " << c.k() << "\n";); - - unsigned sz = c.size(); - clear_watch(c); - for (unsigned i = 0; i < sz; ++i) { - if (value(c[i]) != l_undef) { - --sz; - c.swap(i, sz); - --i; - } - } - c.update_size(sz); - c.update_k(c.k() - num_true); - if (c.lit() == null_literal) { - init_watch(c, true); - } - else { - SASSERT(value(c.lit()) == l_undef); - // c will be watched once c.lit() is assigned. - } - m_simplify_change = true; - } - } - lbool ba_solver::add_assign(card& c, literal alit) { // literal is assigned to false. unsigned sz = c.size(); @@ -1875,6 +1823,7 @@ namespace sat { } void ba_solver::simplify(constraint& c) { + if (!s().at_base_lvl()) s().pop_to_base_level(); switch (c.tag()) { case card_t: simplify(c.to_card()); @@ -1891,31 +1840,51 @@ namespace sat { } void ba_solver::simplify() { - return; - SASSERT(s().at_base_lvl()); + if (!s().at_base_lvl()) s().pop_to_base_level(); unsigned trail_sz; do { + trail_sz = s().init_trail_size(); + IF_VERBOSE(1, verbose_stream() << "(bool-algebra-solver simplify-begin " << trail_sz << ")\n";); m_simplify_change = false; m_clause_removed = false; m_constraint_removed = false; - trail_sz = s().init_trail_size(); - for (constraint* c : m_constraints) simplify(*c); + // for (constraint* c : m_constraints) simplify(*c); init_use_lists(); remove_unused_defs(); - // take ownership of interface variables - for (constraint* c : m_constraints) { - if (c->lit() != null_literal) m_var_used[c->lit().var()] = true; - } set_non_external(); elim_pure(); subsumption(); cleanup_clauses(); cleanup_constraints(); + IF_VERBOSE(1, verbose_stream() << "(bool-algebra-solver simplify-end :trail " << trail_sz << " :vars " << s().num_vars() - trail_sz << ")\n";); } while (m_simplify_change || trail_sz < s().init_trail_size()); + + mutex_reduction(); // or could create queue of constraints that are affected } + void ba_solver::mutex_reduction() { + literal_vector lits; + for (unsigned v = 0; v < s().num_vars(); ++v) { + lits.push_back(literal(v, false)); + lits.push_back(literal(v, true)); + } + vector mutexes; + s().find_mutexes(lits, mutexes); + std::cout << "mutexes: " << mutexes.size() << "\n"; + for (literal_vector& mux : mutexes) { + if (mux.size() > 2) { + std::cout << "mux: " << mux << "\n"; + for (unsigned i = 0; i < mux.size(); ++i) mux[i].neg(); + add_at_least(null_literal, mux, mux.size() - 1); + } + } + } + + // ------------------------------- + // set literals equivalent + bool ba_solver::set_root(literal l, literal r) { if (s().is_assumption(l.var())) { return false; @@ -1931,74 +1900,32 @@ namespace sat { void ba_solver::flush_roots() { if (m_roots.empty()) return; - std::cout << "pre\n"; - validate(); + // validate(); m_visited.resize(s().num_vars()*2, false); m_constraint_removed = false; for (constraint* c : m_constraints) { - switch (c->tag()) { - case card_t: - flush_roots(c->to_card()); - break; - case pb_t: - flush_roots(c->to_pb()); - break; - case xor_t: - flush_roots(c->to_xor()); - break; - default: - UNREACHABLE(); - } + flush_roots(*c); } cleanup_constraints(); - std::cout << "post\n"; - validate(); - // display(std::cout << "flush roots\n"); + + // validate(); } - void ba_solver::flush_roots(card& c) { - bool found = c.lit() != null_literal && m_roots[c.lit().index()] != c.lit(); - for (literal l : c) { - if (found) break; - found = m_roots[l.index()] != l; - } - if (!found) return; - clear_watch(c); - // this could create duplicate literals - for (unsigned i = 0; i < c.size(); ++i) { - c[i] = m_roots[c[i].index()]; - } - bool found_dup = false; - for (literal l : c) { - if (is_marked(l)) { - found_dup = true; - } - else { - mark_visited(l); - mark_visited(~l); - } - } - for (literal l : c) { - unmark_visited(l); - unmark_visited(~l); - } - if (found_dup) { - recompile(c); - return; - } - - if (c.lit() != null_literal && m_roots[c.lit().index()] != c.lit()) { - literal r = m_roots[c.lit().index()]; - nullify_tracking_literal(c); - c.update_literal(r); - get_wlist(r).push_back(c.index()); - get_wlist(~r).push_back(c.index()); - } - - if (c.lit() == null_literal || value(c.lit()) == l_true) { - init_watch(c, true); - } + void ba_solver::recompile(constraint& c) { + switch (c.tag()) { + case card_t: + recompile(c.to_card()); + break; + case pb_t: + recompile(c.to_pb()); + break; + case xor_t: + NOT_IMPLEMENTED_YET(); + break; + default: + UNREACHABLE(); + } } void ba_solver::recompile(card& c) { @@ -2041,9 +1968,6 @@ namespace sat { } } } - c.update_size(sz); - c.update_k(k); - // clear weights for (literal l : c) { m_weights[l.index()] = 0; @@ -2055,8 +1979,8 @@ namespace sat { return; } - literal root = null_literal; - if (c.lit() != null_literal) root = m_roots[c.lit().index()]; + c.set_size(sz); + c.set_k(k); if (!is_card) { TRACE("sat", tout << "replacing by pb: " << c << "\n";); @@ -2064,20 +1988,17 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) { wlits.push_back(wliteral(coeffs[i], c[i])); } + literal root = c.lit(); remove_constraint(c); - add_pb_ge(root, wlits, k); + pb const& p = add_pb_ge(root, wlits, k); + IF_VERBOSE(1, verbose_stream() << p << "\n";); } else { - // IF_VERBOSE(0, verbose_stream() << "new: " << c << "\n";); - if (c.lit() != root) { - nullify_tracking_literal(c); - c.update_literal(root); - get_wlist(root).push_back(c.index()); - get_wlist(~root).push_back(c.index()); - } + // IF_VERBOSE(1, verbose_stream() << "new: " << c << "\n";); if (c.lit() == null_literal || value(c.lit()) == l_true) { init_watch(c, true); } + SASSERT(c.well_formed()); } } @@ -2091,11 +2012,10 @@ namespace sat { unsigned k = p.k(); unsigned sz = p.size(); for (unsigned i = 0; i < sz && 0 < k; ++i) { - wliteral wl = p[i]; - literal l = wl.second; - unsigned w = m_weights[l.index()]; + literal l = p[i].second; + unsigned w1 = m_weights[l.index()]; unsigned w2 = m_weights[(~l).index()]; - if (w == 0 || w < w2) { + if (w1 == 0 || w1 < w2) { p.swap(i, sz - 1); --sz; --i; @@ -2105,18 +2025,18 @@ namespace sat { break; } else { - SASSERT(w2 <= w && w2 < k); + SASSERT(w2 <= w1 && w2 < k); k -= w2; - w -= w2; + w1 -= w2; m_weights[l.index()] = 0; m_weights[(~l).index()] = 0; - if (w == 0) { + if (w1 == 0) { p.swap(i, sz - 1); --sz; --i; } else { - p[i] = wliteral(w, l); + p[i] = wliteral(w1, l); } } } @@ -2131,84 +2051,68 @@ namespace sat { return; } - for (unsigned i = 0; i < sz; ++i) { - wliteral wl = p[i]; - unsigned w = std::min(k, wl.first); - p[i] = wliteral(w, wl.second); - } - - p.update_size(sz); - p.update_k(k); - p.update_max_sum(); - - literal root = null_literal; - if (p.lit() != null_literal) root = m_roots[p.lit().index()]; + p.set_size(sz); + p.set_k(k); + SASSERT(p.well_formed()); IF_VERBOSE(0, verbose_stream() << "new: " << p << "\n";); - // std::cout << "simplified " << p << "\n"; - if (p.lit() != root) { - nullify_tracking_literal(p); - p.update_literal(root); - get_wlist(root).push_back(p.index()); - get_wlist(~root).push_back(p.index()); - } if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p, true); } } - void ba_solver::flush_roots(pb& p) { - bool found = p.lit() != null_literal && m_roots[p.lit().index()] != p.lit(); - for (wliteral wl : p) { - if (found) break; - found = m_roots[wl.second.index()] != wl.second; + void ba_solver::flush_roots(constraint& c) { + bool found = c.lit() != null_literal && m_roots[c.lit().index()] != c.lit(); + for (unsigned i = 0; !found && i < c.size(); ++i) { + found = m_roots[c.get_lit(i).index()] != c.get_lit(i); } if (!found) return; - clear_watch(p); + clear_watch(c); + // this could create duplicate literals - for (unsigned i = 0; i < p.size(); ++i) { - p[i].second = m_roots[p[i].second.index()]; + for (unsigned i = 0; i < c.size(); ++i) { + c.set_lit(i, m_roots[c.get_lit(i).index()]); } - if (p.lit() != null_literal && m_roots[p.lit().index()] != p.lit()) { - literal r = m_roots[p.lit().index()]; - nullify_tracking_literal(p); - p.update_literal(r); - get_wlist(r).push_back(p.index()); - get_wlist(~r).push_back(p.index()); + + if (c.lit() != null_literal && m_roots[c.lit().index()] != c.lit()) { + literal r = m_roots[c.lit().index()]; + nullify_tracking_literal(c); + c.update_literal(r); + get_wlist(r).push_back(c.index()); + get_wlist(~r).push_back(c.index()); } bool found_dup = false; - for (wliteral wl : p) { - if (is_marked(wl.second)) { + for (unsigned i = 0; i < c.size(); ++i) { + literal l = c.get_lit(i); + if (is_marked(l)) { found_dup = true; - // std::cout << "Dup: " << wl.second << "\n"; + break; } else { - mark_visited(wl.second); - mark_visited(~(wl.second)); + mark_visited(l); + mark_visited(~l); } } - for (wliteral wl : p) { - unmark_visited(wl.second); - unmark_visited(~(wl.second)); + for (unsigned i = 0; i < c.size(); ++i) { + literal l = c.get_lit(i); + unmark_visited(l); + unmark_visited(~l); } + if (found_dup) { // std::cout << "FOUND DUP " << p << "\n"; - recompile(p); + recompile(c); return; } - // review for potential incompleteness: if p.lit() == l_false, do propagations happen? - if (p.lit() == null_literal || value(p.lit()) == l_true) { - init_watch(p, true); + // review for potential incompleteness: if c.lit() == l_false, do propagations happen? + if (c.lit() == null_literal || value(c.lit()) == l_true) { + init_watch(c, true); } + SASSERT(c.well_formed()); } - void ba_solver::flush_roots(xor& x) { - NOT_IMPLEMENTED_YET(); - } - - unsigned ba_solver::get_num_non_learned_bin(literal l) { return s().m_simplifier.get_num_non_learned_bin(l); } @@ -2225,8 +2129,6 @@ namespace sat { void ba_solver::init_use_lists() { m_visited.resize(s().num_vars()*2, false); m_clause_use_list.init(s().num_vars()); - m_var_used.reset(); - m_var_used.resize(s().num_vars(), false); m_cnstr_use_list.reset(); m_cnstr_use_list.resize(2*s().num_vars()); for (clause* c : s().m_clauses) { @@ -2243,7 +2145,6 @@ namespace sat { case card_t: { card& c = cp->to_card(); for (literal l : c) { - m_var_used[l.var()] = true; m_cnstr_use_list[l.index()].push_back(&c); if (lit != null_literal) m_cnstr_use_list[(~l).index()].push_back(&c); } @@ -2253,7 +2154,6 @@ namespace sat { pb& p = cp->to_pb(); for (wliteral wl : p) { literal l = wl.second; - m_var_used[l.var()] = true; m_cnstr_use_list[l.index()].push_back(&p); if (lit != null_literal) m_cnstr_use_list[(~l).index()].push_back(&p); } @@ -2261,9 +2161,7 @@ namespace sat { } case xor_t: { xor& x = cp->to_xor(); - m_var_used[x.lit().var()] = true; for (literal l : x) { - m_var_used[l.var()] = true; m_cnstr_use_list[l.index()].push_back(&x); m_cnstr_use_list[(~l).index()].push_back(&x); } @@ -2276,28 +2174,17 @@ namespace sat { void ba_solver::remove_unused_defs() { // remove constraints where indicator literal isn't used. for (constraint* cp : m_constraints) { - switch (cp->tag()) { - case card_t: { - card& c = cp->to_card(); - if (c.lit() != null_literal && - !m_var_used[c.lit().var()] && - m_clause_use_list.get(c.lit()).empty() && - m_clause_use_list.get(~c.lit()).empty() && - get_num_non_learned_bin(c.lit()) == 0 && - get_num_non_learned_bin(~c.lit()) == 0) { - remove_constraint(c); - } - break; - } + constraint& c = *cp; + literal lit = c.lit(); + switch (c.tag()) { + case card_t: case pb_t: { - pb& p = cp->to_pb(); - if (p.lit() != null_literal && - !m_var_used[p.lit().var()] && - m_clause_use_list.get(p.lit()).empty() && - m_clause_use_list.get(~p.lit()).empty() && - get_num_non_learned_bin(p.lit()) == 0 && - get_num_non_learned_bin(~p.lit()) == 0) { - remove_constraint(p); + if (lit != null_literal && + use_count(lit) == 1 && + use_count(~lit) == 1 && + get_num_non_learned_bin(lit) == 0 && + get_num_non_learned_bin(~lit) == 0) { + remove_constraint(c); } break; } @@ -2306,12 +2193,13 @@ namespace sat { } } } - + unsigned ba_solver::set_non_external() { // set variables to be non-external if they are not used in theory constraints. unsigned ext = 0; for (unsigned v = 0; v < s().num_vars(); ++v) { - if (s().is_external(v) && !m_var_used[v] && !s().is_assumption(v)) { + literal lit(v, false); + if (s().is_external(v) && m_cnstr_use_list[lit.index()].size() == 0 && m_cnstr_use_list[(~lit).index()].size() == 0 && !s().is_assumption(v)) { s().set_non_external(v); ++ext; } @@ -2320,25 +2208,30 @@ namespace sat { return ext; } + bool ba_solver::elim_pure(literal lit) { + if (value(lit) != l_undef) return false; + if (!m_cnstr_use_list[lit.index()].empty() && use_count(~lit) == 0 && + get_num_non_learned_bin(~lit) == 0) { + s().assign(lit, justification()); + return true; + } + return false; + } + unsigned ba_solver::elim_pure() { // eliminate pure literals unsigned pure_literals = 0; for (unsigned v = 0; v < s().num_vars(); ++v) { - if (!m_var_used[v]) continue; literal lit(v, false); - if (!m_cnstr_use_list[lit.index()].empty() && m_cnstr_use_list[(~lit).index()].empty() && m_clause_use_list.get(~lit).empty() && - get_num_non_learned_bin(~lit) == 0) { - s().assign(lit, justification()); - ++pure_literals; - continue; - } - lit.neg(); - if (!m_cnstr_use_list[lit.index()].empty() && m_cnstr_use_list[(~lit).index()].empty() && m_clause_use_list.get(~lit).empty() && get_num_non_learned_bin(~lit) == 0) { - s().assign(lit, justification()); + if (value(v) != l_undef) continue; + if (m_cnstr_use_list[lit.index()].empty() && + m_cnstr_use_list[(~lit).index()].empty()) continue; + + if (elim_pure(lit) || elim_pure(~lit)) { ++pure_literals; } - } - IF_VERBOSE(10, verbose_stream() << "pure literals converted: " << pure_literals << "\n";); + } + IF_VERBOSE(10, verbose_stream() << "pure literals converted: " << pure_literals << " " << inconsistent() << "\n";); return pure_literals; } @@ -2347,6 +2240,7 @@ namespace sat { unsigned clause_sub = m_stats.m_num_clause_subsumes; unsigned card_sub = m_stats.m_num_card_subsumes; for (constraint* cp : m_constraints) { + if (cp->was_removed()) continue; switch (cp->tag()) { case card_t: { card& c = cp->to_card(); @@ -2422,25 +2316,24 @@ namespace sat { A + ~L + B >= k' => A + B >= k' if A + A' + L >= k and k' + |L| + |A'| <= k */ bool ba_solver::subsumes(card& c1, card& c2, literal_vector & comp) { - if (c2.lit() != null_literal) return false; // perhaps support this? + if (c2.lit() != null_literal) return false; unsigned c2_exclusive = 0; unsigned common = 0; - comp.empty(); + comp.reset(); for (literal l : c2) { if (is_marked(l)) { ++common; } - else if (!is_marked(~l)) { - ++c2_exclusive; + else if (is_marked(~l)) { + comp.push_back(l); } else { - comp.push_back(l); + ++c2_exclusive; } } unsigned c1_exclusive = c1.size() - common - comp.size(); - return c1_exclusive + c2.k() + comp.size() <= c1.k(); } @@ -2452,11 +2345,11 @@ namespace sat { if (is_marked(l)) { ++common; } - else if (!is_marked(~l)) { - ++c2_exclusive; + else if (is_marked(~l)) { + comp.push_back(l); } else { - comp.push_back(l); + ++c2_exclusive; } } @@ -2465,11 +2358,7 @@ namespace sat { return false; } unsigned c1_exclusive = c1.size() - common - comp.size(); - if (c1_exclusive + 1 <= c1.k()) { - return true; - } - - return false; + return c1_exclusive + 1 <= c1.k(); } literal ba_solver::get_min_occurrence_literal(card const& c) { @@ -2488,7 +2377,7 @@ namespace sat { void ba_solver::card_subsumption(card& c1, literal lit) { literal_vector slit; for (constraint* c : m_cnstr_use_list[lit.index()]) { - if (!c || c->tag() != card_t || c == &c1) { + if (!c || c->tag() != card_t || c == &c1 || c->was_removed()) { continue; } card& c2 = c->to_card(); @@ -2502,7 +2391,10 @@ namespace sat { } else { TRACE("sat", tout << "self subsume carinality\n";); - IF_VERBOSE(0, verbose_stream() << "self-subsume cardinality is TBD\n";); + IF_VERBOSE(0, + verbose_stream() << "self-subsume cardinality is TBD\n"; + verbose_stream() << c1 << "\n"; + verbose_stream() << c2 << "\n";); #if 0 clear_watch(c2); for (unsigned i = 0; i < c2.size(); ++i) { @@ -2511,7 +2403,7 @@ namespace sat { break; } } - c2.update_size(c2.size() - 1); + c2.set_size(c2.size() - 1); init_watch(c2, true); m_simplify_change = true; #endif @@ -2521,6 +2413,7 @@ namespace sat { } void ba_solver::clause_subsumption(card& c1, literal lit) { + SASSERT(!c1.was_removed()); literal_vector slit; clause_use_list::iterator it = m_clause_use_list.get(lit).mk_iterator(); while (!it.at_end()) { @@ -2528,8 +2421,8 @@ namespace sat { if (!c2.was_removed() && subsumes(c1, c2, slit)) { if (slit.empty()) { TRACE("sat", tout << "remove\n" << c1 << "\n" << c2 << "\n";); - //c2.set_removed(true); - //m_clause_removed = true; + c2.set_removed(true); + m_clause_removed = true; ++m_stats.m_num_clause_subsumes; } else { @@ -2543,7 +2436,9 @@ namespace sat { } void ba_solver::binary_subsumption(card& c1, literal lit) { + if (c1.k() + 1 != c1.size()) return; SASSERT(is_marked(lit)); + SASSERT(!c1.was_removed()); watch_list & wlist = get_wlist(~lit); watch_list::iterator it = wlist.begin(); watch_list::iterator it2 = it; @@ -2552,7 +2447,7 @@ namespace sat { watched w = *it; if (w.is_binary_clause() && is_marked(w.get_literal())) { ++m_stats.m_num_bin_subsumes; - IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); + // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); } else { if (it != it2) { @@ -2567,12 +2462,13 @@ namespace sat { } void ba_solver::subsumption(card& c1) { + SASSERT(!c1.was_removed()); if (c1.lit() != null_literal) { return; } for (literal l : c1) mark_visited(l); for (unsigned i = 0; i < std::min(c1.size(), c1.k() + 1); ++i) { - literal lit = c1[i]; + literal lit = c1[i]; card_subsumption(c1, lit); clause_subsumption(c1, lit); binary_subsumption(c1, lit); @@ -2631,28 +2527,26 @@ namespace sat { card const& c = cp->to_card(); if (c.size() == c.k() + 1) { literal_vector mux; - for (unsigned j = 0; j < c.size(); ++j) { - literal lit = ~c[j]; - if (slits.contains(lit)) { - mux.push_back(lit); + for (literal lit : c) { + if (slits.contains(~lit)) { + mux.push_back(~lit); } } if (mux.size() <= 1) { continue; } - for (unsigned j = 0; j < mux.size(); ++j) { - slits.remove(mux[j]); + for (literal m : mux) { + slits.remove(m); } change = true; mutexes.push_back(mux); } } if (!change) return; - literal_set::iterator it = slits.begin(), end = slits.end(); lits.reset(); - for (; it != end; ++it) { - lits.push_back(*it); + for (literal l : slits) { + lits.push_back(l); } } @@ -2753,33 +2647,6 @@ namespace sat { st.update("ba resolves", m_stats.m_num_resolves); } - bool ba_solver::validate_conflict(card const& c) const { - if (c.lit() != null_literal && value(c.lit()) != l_true) { - return false; - } - for (unsigned i = c.k(); i < c.size(); ++i) { - if (value(c[i]) != l_false) return false; - } - for (unsigned i = 0; i < c.k(); ++i) { - if (value(c[i]) == l_false) return true; - } - return false; - } - - bool ba_solver::validate_conflict(xor const& x) const { - return !parity(x, 0); - } - - bool ba_solver::validate_conflict(pb const& p) const { - unsigned slack = 0; - for (wliteral wl : p) { - if (value(wl.second) != l_false) { - slack += wl.first; - } - } - return slack < p.k(); - } - bool ba_solver::validate_unit_propagation(card const& c, literal alit) const { (void) alit; if (c.lit() != null_literal && value(c.lit()) != l_true) return false; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 2c2a5d914..3d52c2ea4 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -67,14 +67,13 @@ namespace sat { tag_t tag() const { return m_tag; } literal lit() const { return m_lit; } unsigned size() const { return m_size; } - void update_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } + void set_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } void update_literal(literal l) { m_lit = l; } bool was_removed() const { return m_removed; } void remove() { m_removed = true; } void nullify_literal() { m_lit = null_literal; } unsigned glue() const { return m_glue; } - void set_glue(unsigned g) { m_glue = g; } - + void set_glue(unsigned g) { m_glue = g; } size_t obj_size() const { return m_obj_size; } card& to_card(); @@ -87,14 +86,29 @@ namespace sat { bool is_pb() const { return m_tag == pb_t; } bool is_xor() const { return m_tag == xor_t; } - virtual bool is_watching(literal l) const { return false; }; - virtual literal_vector literals() const { return literal_vector(); } + virtual bool is_watching(literal l) const { UNREACHABLE(); return false; }; + virtual literal_vector literals() const { UNREACHABLE(); return literal_vector(); } + virtual void swap(unsigned i, unsigned j) { UNREACHABLE(); } + virtual literal get_lit(unsigned i) const { UNREACHABLE(); return null_literal; } + virtual void set_lit(unsigned i, literal l) { UNREACHABLE(); } + virtual bool well_formed() const { return true; } }; friend std::ostream& operator<<(std::ostream& out, constraint const& c); - class card : public constraint { + // base class for pb and cardinality constraints + class pb_base : public constraint { + protected: unsigned m_k; + public: + pb_base(tag_t t, literal l, unsigned sz, size_t osz, unsigned k): constraint(t, l, sz, osz), m_k(k) {} + virtual void set_k(unsigned k) { m_k = k; } + virtual unsigned get_coeff(unsigned i) const { UNREACHABLE(); return 0; } + unsigned k() const { return m_k; } + virtual bool well_formed() const; + }; + + class card : public pb_base { literal m_lits[0]; public: static size_t get_obj_size(unsigned num_lits) { return sizeof(card) + num_lits * sizeof(literal); } @@ -103,23 +117,24 @@ namespace sat { literal& operator[](unsigned i) { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return static_cast(m_lits) + m_size; } - unsigned k() const { return m_k; } - void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate(); - void update_k(unsigned k) { m_k = k; } + virtual void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } virtual literal_vector literals() const { return literal_vector(m_size, m_lits); } virtual bool is_watching(literal l) const; + virtual literal get_lit(unsigned i) const { return m_lits[i]; } + virtual void set_lit(unsigned i, literal l) { m_lits[i] = l; } + virtual unsigned get_coeff(unsigned i) const { return 1; } }; typedef std::pair wliteral; - class pb : public constraint { - unsigned m_k; + class pb : public pb_base { unsigned m_slack; unsigned m_num_watch; unsigned m_max_sum; wliteral m_wlits[0]; + void update_max_sum(); public: static size_t get_obj_size(unsigned num_lits) { return sizeof(pb) + num_lits * sizeof(wliteral); } pb(literal lit, svector const& wlits, unsigned k); @@ -129,18 +144,20 @@ namespace sat { wliteral const* begin() const { return m_wlits; } wliteral const* end() const { return begin() + m_size; } - unsigned k() const { return m_k; } unsigned slack() const { return m_slack; } void set_slack(unsigned s) { m_slack = s; } unsigned num_watch() const { return m_num_watch; } unsigned max_sum() const { return m_max_sum; } void set_num_watch(unsigned s) { m_num_watch = s; } - void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } + bool is_cardinality() const; void negate(); - void update_k(unsigned k) { m_k = k; } - void update_max_sum(); + virtual void set_k(unsigned k) { m_k = k; update_max_sum(); } + virtual void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } virtual literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } virtual bool is_watching(literal l) const; + virtual literal get_lit(unsigned i) const { return m_wlits[i].second; } + virtual void set_lit(unsigned i, literal l) { m_wlits[i].second = l; } + virtual unsigned get_coeff(unsigned i) const { return m_wlits[i].first; } }; class xor : public constraint { @@ -151,10 +168,13 @@ namespace sat { literal operator[](unsigned i) const { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return begin() + m_size; } - void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } void negate() { m_lits[0].neg(); } + virtual void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } virtual bool is_watching(literal l) const; virtual literal_vector literals() const { return literal_vector(size(), begin()); } + virtual literal get_lit(unsigned i) const { return m_lits[i]; } + virtual void set_lit(unsigned i, literal l) { m_lits[i] = l; } + virtual bool well_formed() const; }; @@ -205,7 +225,6 @@ namespace sat { svector m_visited; vector> m_cnstr_use_list; use_list m_clause_use_list; - svector m_var_used; bool m_simplify_change; bool m_clause_removed; bool m_constraint_removed; @@ -226,9 +245,12 @@ namespace sat { void remove_unused_defs(); unsigned set_non_external(); unsigned elim_pure(); + bool elim_pure(literal lit); void subsumption(); void subsumption(card& c1); void gc_half(char const* _method); + void mutex_reduction(); + unsigned use_count(literal lit) const { return m_cnstr_use_list[lit.index()].size() + m_clause_use_list.get(lit).size(); } void cleanup_clauses(); void cleanup_constraints(); @@ -244,6 +266,7 @@ namespace sat { void add_constraint(constraint* c); void init_watch(constraint& c, bool is_true); void init_watch(bool_var v); + void clear_watch(constraint& c); lbool add_assign(constraint& c, literal l); void simplify(constraint& c); void nullify_tracking_literal(constraint& c); @@ -254,7 +277,12 @@ namespace sat { bool validate_unit_propagation(constraint const& c, literal alit) const; void attach_constraint(constraint const& c); void detach_constraint(constraint const& c); - bool is_true(constraint const& c) const; + lbool eval(constraint const& c) const; + lbool eval(lbool a, lbool b) const; + void assert_unconstrained(literal lit, literal_vector const& lits); + void flush_roots(constraint& c); + void recompile(constraint& c); + // cardinality void init_watch(card& c, bool is_true); @@ -263,11 +291,9 @@ namespace sat { void reset_coeffs(); void reset_marked_literals(); void get_antecedents(literal l, card const& c, literal_vector & r); - void simplify(card& c); - void unit_propagation_simplification(literal lit, literal_vector const& lits); void flush_roots(card& c); void recompile(card& c); - lbool value(card const& c) const; + lbool eval(card const& c) const; // xor specific functionality void clear_watch(xor& x); @@ -278,7 +304,7 @@ namespace sat { void get_antecedents(literal l, xor const& x, literal_vector & r); void simplify(xor& x); void flush_roots(xor& x); - lbool value(xor const& x) const; + lbool eval(xor const& x) const; // pb functionality unsigned m_a_max; @@ -287,14 +313,15 @@ namespace sat { void add_index(pb& p, unsigned index, literal lit); void clear_watch(pb& p); void get_antecedents(literal l, pb const& p, literal_vector & r); - void simplify(pb& p); + void simplify(pb_base& p); void simplify2(pb& p); bool is_cardinality(pb const& p); void flush_roots(pb& p); void recompile(pb& p); - lbool value(pb const& p) const; + lbool eval(pb const& p) const; // access solver + inline lbool value(bool_var v) const { return value(literal(v, false)); } inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } inline unsigned lvl(bool_var v) const { return m_solver->lvl(v); } @@ -344,7 +371,7 @@ namespace sat { void display(std::ostream& out, xor const& c, bool values) const; void add_at_least(literal l, literal_vector const& lits, unsigned k); - void add_pb_ge(literal l, svector const& wlits, unsigned k); + pb const& add_pb_ge(literal l, svector const& wlits, unsigned k); void add_xor(literal l, literal_vector const& lits); public: diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index dfa85569c..29c15c2d7 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1391,7 +1391,6 @@ namespace sat { */ void solver::simplify_problem() { - if (m_ext) m_ext->validate(); if (m_conflicts_since_init < m_next_simplify) { return; } @@ -1404,15 +1403,12 @@ namespace sat { SASSERT(at_base_lvl()); m_cleaner(); - if (m_ext) m_ext->validate(); CASSERT("sat_simplify_bug", check_invariant()); m_scc(); - if (m_ext) m_ext->validate(); CASSERT("sat_simplify_bug", check_invariant()); m_simplifier(false); - if (m_ext) m_ext->validate(); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); @@ -1421,7 +1417,6 @@ namespace sat { CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); } - if (m_ext) m_ext->validate(); if (m_config.m_lookahead_simplify) { { @@ -1440,12 +1435,10 @@ namespace sat { CASSERT("sat_simplify_bug", check_invariant()); m_probing(); - if (m_ext) m_ext->validate(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); m_asymm_branch(); - if (m_ext) m_ext->validate(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); @@ -1468,6 +1461,18 @@ namespace sat { } if (m_par) m_par->set_phase(*this); + +#if 0 + static unsigned file_no = 0; + #pragma omp critical (print_sat) + { + ++file_no; + std::ostringstream ostrm; + ostrm << "s" << file_no << ".txt"; + std::ofstream ous(ostrm.str()); + display(ous); + } +#endif } bool solver::set_root(literal l, literal r) { @@ -3358,17 +3363,17 @@ namespace sat { vector _mutexes; literal_vector _lits(lits); if (m_ext) { - m_ext->find_mutexes(_lits, mutexes); + // m_ext->find_mutexes(_lits, mutexes); } unsigned_vector ps; for (unsigned i = 0; i < _lits.size(); ++i) { ps.push_back(_lits[i].index()); } mc.cliques(ps, _mutexes); - for (unsigned i = 0; i < _mutexes.size(); ++i) { + for (auto const& mux : _mutexes) { literal_vector clique; - for (unsigned j = 0; j < _mutexes[i].size(); ++j) { - clique.push_back(to_literal(_mutexes[i][j])); + for (auto const& idx : mux) { + clique.push_back(to_literal(idx)); } mutexes.push_back(clique); } diff --git a/src/util/max_cliques.h b/src/util/max_cliques.h index ec888c84b..df5994990 100644 --- a/src/util/max_cliques.h +++ b/src/util/max_cliques.h @@ -92,7 +92,7 @@ public: m_next.reserve(std::max(src, dst) + 1); m_next.reserve(std::max(negate(src), negate(dst)) + 1); m_next[src].push_back(dst); - m_next[dst].push_back(src); + m_next[dst].push_back(src); } void cliques(unsigned_vector const& ps, vector& cliques) { @@ -104,7 +104,7 @@ public: max = std::max(max, std::max(np, p) + 1); } m_next.reserve(max); - m_tc.reserve(m_next.size()); + m_tc.reserve(m_next.size()); unsigned_vector clique; uint_set vars; for (unsigned i = 0; i < num_ps; ++i) { @@ -128,7 +128,12 @@ public: turn = !turn; } if (clique.size() > 1) { - cliques.push_back(clique); + if (clique.size() == 2 && clique[0] == negate(clique[1])) { + // no op + } + else { + cliques.push_back(clique); + } } } } From 480296ed9676be891f572a1f65f9219f3231468c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jul 2017 11:27:02 -0700 Subject: [PATCH 0184/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 297 ++++++++++++++++++++++++++++++++---------- src/sat/ba_solver.h | 12 +- src/smt/theory_pb.cpp | 2 +- 3 files changed, 240 insertions(+), 71 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 7884018fc..86fc30981 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -17,8 +17,10 @@ Revision History: --*/ -#include"ba_solver.h" -#include"sat_types.h" +#include "sat/ba_solver.h" +#include "sat/sat_types.h" +#include "util/lp/lar_solver.h" + namespace sat { @@ -217,13 +219,13 @@ namespace sat { TRACE("sat", display(tout << "init watch: ", c, true);); SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); + // put the non-false literals into the head. + if (bound == sz) { - for (unsigned i = 0; i < sz && !inconsistent(); ++i) { - assign(c, c[i]); - } + for (literal l : c) assign(c, l); return; } - // put the non-false literals into the head. + for (unsigned i = 0; i < sz; ++i) { if (value(c[i]) != l_false) { if (j != i) { @@ -259,7 +261,7 @@ namespace sat { set_conflict(c, alit); } else if (j == bound) { - for (unsigned i = 0; i < bound && !inconsistent(); ++i) { + for (unsigned i = 0; i < bound; ++i) { assign(c, c[i]); } } @@ -291,6 +293,7 @@ namespace sat { } void ba_solver::assign(constraint& c, literal lit) { + if (inconsistent()) return; switch (value(lit)) { case l_true: break; @@ -330,7 +333,7 @@ namespace sat { unsigned sz = p.size(), bound = p.k(); // put the non-false literals into the head. - unsigned slack = 0, num_watch = 0, j = 0; + unsigned slack = 0, slack1 = 0, num_watch = 0, j = 0; for (unsigned i = 0; i < sz; ++i) { if (value(p[i].second) != l_false) { if (j != i) { @@ -340,6 +343,9 @@ namespace sat { slack += p[j].first; ++num_watch; } + else { + slack1 += p[j].first; + } ++j; } } @@ -367,6 +373,15 @@ namespace sat { } p.set_slack(slack); p.set_num_watch(num_watch); + + // slack is tight: + if (slack + slack1 == bound) { + SASSERT(slack1 == 0); + SASSERT(j == num_watch); + for (unsigned i = 0; i < j; ++i) { + assign(p, p[i].second); + } + } } TRACE("sat", display(tout << "init watch: ", p, true);); } @@ -394,9 +409,8 @@ namespace sat { return no-conflict a_max index: index of non-false literal with maximal weight. - - */ + void ba_solver::add_index(pb& p, unsigned index, literal lit) { if (value(lit) == l_undef) { m_pb_undef.push_back(index); @@ -501,7 +515,6 @@ namespace sat { } for (literal lit : to_assign) { - if (inconsistent()) break; assign(p, lit); } } @@ -570,6 +583,7 @@ namespace sat { void ba_solver::simplify(pb_base& p) { if (p.lit() != null_literal && value(p.lit()) == l_false) { TRACE("sat", tout << "pb: flip sign " << p << "\n";); + IF_VERBOSE(0, verbose_stream() << "signed is flipped " << p << "\n";); return; init_watch(p, !p.lit().sign()); } @@ -722,10 +736,12 @@ namespace sat { l = lvl(x[i]); } } + SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); set_conflict(x, x[j]); } break; case 1: + SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); assign(x, parity(x, 1) ? ~x[0] : x[0]); break; default: @@ -752,6 +768,7 @@ namespace sat { } if (index == 2) { // literal is no longer watched. + UNREACHABLE(); return l_undef; } SASSERT(x[index].var() == alit.var()); @@ -796,8 +813,7 @@ namespace sat { ++j; } } - sz = j; - m_active_vars.shrink(sz); + m_active_vars.shrink(j); } void ba_solver::inc_coeff(literal l, int offset) { @@ -857,24 +873,19 @@ namespace sat { m_bound = 0; literal consequent = s().m_not_l; justification js = s().m_conflict; - TRACE("sat", tout << consequent << " " << js << "\n";); - TRACE("sat", s().display(tout);); + TRACE("sat", tout << consequent << " " << js << "\n"; s().display(tout);); m_conflict_lvl = s().get_max_lvl(consequent, js); if (consequent != null_literal) { consequent.neg(); process_antecedent(consequent, 1); } literal_vector const& lits = s().m_trail; - unsigned idx = lits.size()-1; + unsigned idx = lits.size() - 1; int offset = 1; DEBUG_CODE(active2pb(m_A);); unsigned init_marks = m_num_marks; - vector jus; - - // if (null_literal != consequent) std::cout << "resolve " << consequent << " " << value(consequent) << "\n"; - do { if (offset == 0) { @@ -889,7 +900,7 @@ namespace sat { goto bail_out; } - // TRACE("sat", display(tout, m_A);); + TRACE("sat_verbose", display(tout, m_A);); TRACE("sat", tout << "process consequent: " << consequent << ":\n"; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); SASSERT(m_bound >= 0); @@ -992,7 +1003,8 @@ namespace sat { m_A = m_C;); TRACE("sat", display(tout << "conflict:\n", m_A);); - // cut(); + + cut(); process_next_resolvent: @@ -1040,9 +1052,10 @@ namespace sat { } m_lemma.reset(); - m_lemma.push_back(null_literal); - for (unsigned i = 0; 0 <= slack && i < m_active_vars.size(); ++i) { + unsigned num_skipped = 0; + int asserting_coeff = 0; + for (unsigned i = 0; /* 0 <= slack && */ i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; int coeff = get_coeff(v); lbool val = value(v); @@ -1052,9 +1065,18 @@ namespace sat { literal lit(v, !is_true); if (lvl(lit) == m_conflict_lvl) { if (m_lemma[0] == null_literal) { - slack -= abs(coeff); + asserting_coeff = abs(coeff); + slack -= asserting_coeff; m_lemma[0] = ~lit; } + else { + ++num_skipped; + if (asserting_coeff < abs(coeff)) { + m_lemma[0] = ~lit; + slack -= (abs(coeff) - asserting_coeff); + asserting_coeff = abs(coeff); + } + } } else { slack -= abs(coeff); @@ -1063,21 +1085,9 @@ namespace sat { } } -#if 0 - if (jus.size() > 1) { - std::cout << jus.size() << "\n"; - for (unsigned i = 0; i < jus.size(); ++i) { - s().display_justification(std::cout, jus[i]); std::cout << "\n"; - } - std::cout << m_lemma << "\n"; - active2pb(m_A); - display(std::cout, m_A); - } -#endif - if (slack >= 0) { - IF_VERBOSE(2, verbose_stream() << "(sat.card bail slack objective not met " << slack << ")\n";); + IF_VERBOSE(2, verbose_stream() << "(sat.card slack: " << slack << " skipped: " << num_skipped << ")\n";); goto bail_out; } @@ -1094,6 +1104,7 @@ namespace sat { IF_VERBOSE(2, verbose_stream() << "(sat.card set level to " << level << " < " << m_conflict_lvl << ")\n";); } + if (slack < -1) std::cout << "lemma: " << m_lemma << " >= " << -slack << "\n"; SASSERT(slack < 0); SASSERT(validate_conflict(m_lemma, m_A)); @@ -1139,6 +1150,49 @@ namespace sat { return false; } + void ba_solver::cut() { + unsigned g = 0; + int sum_of_units = 0; + for (bool_var v : m_active_vars) { + if (1 == get_abs_coeff(v) && ++sum_of_units >= m_bound) return; + } + //active2pb(m_A); + //display(std::cout << "units can be removed\n", m_A, true); + + for (unsigned i = 0; g != 1 && i < m_active_vars.size(); ++i) { + bool_var v = m_active_vars[i]; + int coeff = get_abs_coeff(v); + if (coeff == 0) { + continue; + } + if (coeff == 1) return; + if (m_bound < coeff) { + if (get_coeff(v) > 0) { + m_coeffs[v] = m_bound; + } + else { + m_coeffs[v] = -m_bound; + } + coeff = m_bound; + } + SASSERT(0 < coeff && coeff <= m_bound); + if (g == 0) { + g = static_cast(coeff); + } + else { + g = u_gcd(g, static_cast(coeff)); + } + } + if (g >= 2) { + normalize_active_coeffs(); + for (unsigned i = 0; i < m_active_vars.size(); ++i) { + m_coeffs[m_active_vars[i]] /= g; + } + m_bound = (m_bound + g - 1) / g; + std::cout << "CUT " << g << "\n"; + } + } + void ba_solver::process_card(card& c, int offset) { literal lit = c.lit(); SASSERT(c.k() <= c.size()); @@ -1745,7 +1799,11 @@ namespace sat { unsigned bound = c.k(); TRACE("sat", tout << "assign: " << c.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); - SASSERT(0 < bound && bound < sz); + SASSERT(0 < bound && bound <= sz); + if (bound == sz) { + set_conflict(c, alit); + return l_false; + } SASSERT(value(alit) == l_false); SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); unsigned index = 0; @@ -1786,7 +1844,7 @@ namespace sat { if (index != bound) { c.swap(index, bound); } - for (unsigned i = 0; i < bound && !inconsistent(); ++i) { + for (unsigned i = 0; i < bound; ++i) { assign(c, c[i]); } @@ -1823,7 +1881,7 @@ namespace sat { } void ba_solver::simplify(constraint& c) { - if (!s().at_base_lvl()) s().pop_to_base_level(); + SASSERT(s().at_base_lvl()); switch (c.tag()) { case card_t: simplify(c.to_card()); @@ -1844,7 +1902,7 @@ namespace sat { unsigned trail_sz; do { trail_sz = s().init_trail_size(); - IF_VERBOSE(1, verbose_stream() << "(bool-algebra-solver simplify-begin " << trail_sz << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(bool-algebra-solver simplify-begin :trail " << trail_sz << ")\n";); m_simplify_change = false; m_clause_removed = false; m_constraint_removed = false; @@ -1860,8 +1918,8 @@ namespace sat { } while (m_simplify_change || trail_sz < s().init_trail_size()); - mutex_reduction(); - // or could create queue of constraints that are affected + // mutex_reduction(); + // if (s().m_clauses.size() < 80000) lp_lookahead_reduction(); } void ba_solver::mutex_reduction() { @@ -1872,16 +1930,126 @@ namespace sat { } vector mutexes; s().find_mutexes(lits, mutexes); - std::cout << "mutexes: " << mutexes.size() << "\n"; for (literal_vector& mux : mutexes) { if (mux.size() > 2) { - std::cout << "mux: " << mux << "\n"; + IF_VERBOSE(1, verbose_stream() << "mux: " << mux << "\n";); for (unsigned i = 0; i < mux.size(); ++i) mux[i].neg(); add_at_least(null_literal, mux, mux.size() - 1); } } } + // ---------------------------------- + // lp based relaxation + + void ba_solver::lp_add_var(int coeff, lean::var_index v, lhs_t& lhs, rational& rhs) { + if (coeff < 0) { + rhs += rational(coeff); + } + lhs.push_back(std::make_pair(rational(coeff), v)); + } + + void ba_solver::lp_add_clause(lean::lar_solver& s, svector const& vars, clause const& c) { + lhs_t lhs; + rational rhs; + if (c.frozen()) return; + rhs = rational::one(); + for (literal l : c) { + lp_add_var(l.sign() ? -1 : 1, vars[l.var()], lhs, rhs); + } + s.add_constraint(lhs, lean::GE, rhs); + } + + void ba_solver::lp_lookahead_reduction() { + lean::lar_solver solver; + solver.settings().set_message_ostream(&std::cout); + solver.settings().set_debug_ostream(&std::cout); + solver.settings().print_statistics = true; + solver.settings().report_frequency = 1000; + // solver.settings().simplex_strategy() = lean::simplex_strategy_enum::lu; - runs out of memory + // TBD: set rlimit on the solver + svector vars; + for (unsigned i = 0; i < s().num_vars(); ++i) { + lean::var_index v = solver.add_var(i, false); + vars.push_back(v); + solver.add_var_bound(v, lean::GE, rational::zero()); + solver.add_var_bound(v, lean::LE, rational::one()); + switch (value(v)) { + case l_true: solver.add_var_bound(v, lean::GE, rational::one()); break; + case l_false: solver.add_var_bound(v, lean::LE, rational::zero()); break; + default: break; + } + } + lhs_t lhs; + rational rhs; + for (clause* c : s().m_clauses) { + lp_add_clause(solver, vars, *c); + } + for (clause* c : s().m_learned) { + lp_add_clause(solver, vars, *c); + } + for (constraint const* c : m_constraints) { + if (c->lit() != null_literal) continue; // ignore definitions for now. + switch (c->tag()) { + case card_t: + case pb_t: { + pb_base const& p = dynamic_cast(*c); + rhs = rational(p.k()); + lhs.reset(); + for (unsigned i = 0; i < p.size(); ++i) { + literal l = p.get_lit(i); + int co = p.get_coeff(i); + lp_add_var(l.sign() ? -co : co, vars[l.var()], lhs, rhs); + } + solver.add_constraint(lhs, lean::GE, rhs); + break; + } + default: + // ignore xor + break; + } + } + std::cout << "lp solve\n"; + std::cout.flush(); + + lean::lp_status st = solver.solve(); + if (st == lean::INFEASIBLE) { + std::cout << "infeasible\n"; + s().set_conflict(justification()); + return; + } + std::cout << "feasible\n"; + std::cout.flush(); + for (unsigned i = 0; i < s().num_vars(); ++i) { + lean::var_index v = vars[i]; + if (value(v) != l_undef) continue; + // TBD: take initial model into account to limit queries. + std::cout << "solve v" << v << "\n"; + std::cout.flush(); + solver.push(); + solver.add_var_bound(v, lean::GE, rational::one()); + st = solver.solve(); + solver.pop(1); + if (st == lean::INFEASIBLE) { + std::cout << "found unit: " << literal(v, true) << "\n"; + s().assign(literal(v, true), justification()); + solver.add_var_bound(v, lean::LE, rational::zero()); + continue; + } + + solver.push(); + solver.add_var_bound(v, lean::LE, rational::zero()); + st = solver.solve(); + solver.pop(1); + if (st == lean::INFEASIBLE) { + std::cout << "found unit: " << literal(v, false) << "\n"; + s().assign(literal(v, false), justification()); + solver.add_var_bound(v, lean::GE, rational::zero()); + continue; + } + } + } + // ------------------------------- // set literals equivalent @@ -2004,7 +2172,7 @@ namespace sat { } void ba_solver::recompile(pb& p) { - IF_VERBOSE(0, verbose_stream() << "re: " << p << "\n";); + // IF_VERBOSE(2, verbose_stream() << "re: " << p << "\n";); m_weights.resize(2*s().num_vars(), 0); for (wliteral wl : p) { m_weights[wl.second.index()] += wl.first; @@ -2055,7 +2223,7 @@ namespace sat { p.set_k(k); SASSERT(p.well_formed()); - IF_VERBOSE(0, verbose_stream() << "new: " << p << "\n";); + IF_VERBOSE(20, verbose_stream() << "new: " << p << "\n";); if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p, true); @@ -2390,7 +2558,7 @@ namespace sat { ++m_stats.m_num_card_subsumes; } else { - TRACE("sat", tout << "self subsume carinality\n";); + TRACE("sat", tout << "self subsume cardinality\n";); IF_VERBOSE(0, verbose_stream() << "self-subsume cardinality is TBD\n"; verbose_stream() << c1 << "\n"; @@ -2412,7 +2580,7 @@ namespace sat { } } - void ba_solver::clause_subsumption(card& c1, literal lit) { + void ba_solver::clause_subsumption(card& c1, literal lit, clause_vector& removed_clauses) { SASSERT(!c1.was_removed()); literal_vector slit; clause_use_list::iterator it = m_clause_use_list.get(lit).mk_iterator(); @@ -2421,8 +2589,7 @@ namespace sat { if (!c2.was_removed() && subsumes(c1, c2, slit)) { if (slit.empty()) { TRACE("sat", tout << "remove\n" << c1 << "\n" << c2 << "\n";); - c2.set_removed(true); - m_clause_removed = true; + removed_clauses.push_back(&c2); ++m_stats.m_num_clause_subsumes; } else { @@ -2466,14 +2633,20 @@ namespace sat { if (c1.lit() != null_literal) { return; } + clause_vector removed_clauses; for (literal l : c1) mark_visited(l); for (unsigned i = 0; i < std::min(c1.size(), c1.k() + 1); ++i) { literal lit = c1[i]; card_subsumption(c1, lit); - clause_subsumption(c1, lit); + clause_subsumption(c1, lit, removed_clauses); binary_subsumption(c1, lit); } for (literal l : c1) unmark_visited(l); + m_clause_removed |= !removed_clauses.empty(); + for (clause *c : removed_clauses) { + c->set_removed(true); + m_clause_use_list.erase(*c); + } } void ba_solver::clauses_modifed() {} @@ -2550,9 +2723,10 @@ namespace sat { } } - void ba_solver::display(std::ostream& out, ineq& ineq) const { + void ba_solver::display(std::ostream& out, ineq& ineq, bool values) const { for (unsigned i = 0; i < ineq.m_lits.size(); ++i) { out << ineq.m_coeffs[i] << "*" << ineq.m_lits[i] << " "; + if (values) out << value(ineq.m_lits[i]) << " "; } out << ">= " << ineq.m_k << "\n"; } @@ -2619,25 +2793,12 @@ namespace sat { std::ostream& ba_solver::display(std::ostream& out) const { for (constraint const* c : m_constraints) { - switch (c->tag()) { - case card_t: - out << c->to_card() << "\n"; - break; - case pb_t: - out << c->to_pb() << "\n"; - break; - case xor_t: - display(out, c->to_xor(), false); - break; - default: - UNREACHABLE(); - } + out << (*c) << "\n"; } return out; } std::ostream& ba_solver::display_justification(std::ostream& out, ext_justification_idx idx) const { - constraint const& cnstr = index2constraint(idx); return out << index2constraint(idx); } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 3d52c2ea4..0651dd495 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -23,6 +23,7 @@ Revision History: #include"sat_solver.h" #include"sat_lookahead.h" #include"scoped_ptr_vector.h" +#include"util/lp/lar_solver.h" namespace sat { @@ -206,6 +207,7 @@ namespace sat { int m_bound; tracked_uint_set m_active_var_set; literal_vector m_lemma; + literal_vector m_skipped; unsigned m_num_propagations_since_pop; unsigned_vector m_parity_marks; literal_vector m_parity_trail; @@ -234,7 +236,7 @@ namespace sat { bool subsumes(card& c1, clause& c2, literal_vector& comp); bool subsumed(card& c1, literal l1, literal l2); void binary_subsumption(card& c1, literal lit); - void clause_subsumption(card& c1, literal lit); + void clause_subsumption(card& c1, literal lit, clause_vector& removed_clauses); void card_subsumption(card& c1, literal lit); void mark_visited(literal l) { m_visited[l.index()] = true; } void unmark_visited(literal l) { m_visited[l.index()] = false; } @@ -250,6 +252,12 @@ namespace sat { void subsumption(card& c1); void gc_half(char const* _method); void mutex_reduction(); + + typedef vector> lhs_t; + void lp_lookahead_reduction(); + void lp_add_var(int coeff, lean::var_index v, lhs_t& lhs, rational& rhs); + void lp_add_clause(lean::lar_solver& s, svector const& vars, clause const& c); + unsigned use_count(literal lit) const { return m_cnstr_use_list[lit.index()].size() + m_clause_use_list.get(lit).size(); } void cleanup_clauses(); @@ -364,7 +372,7 @@ namespace sat { void justification2pb(justification const& j, literal lit, unsigned offset, ineq& p); bool validate_resolvent(); - void display(std::ostream& out, ineq& p) const; + void display(std::ostream& out, ineq& p, bool values = false) const; void display(std::ostream& out, constraint const& c, bool values) const; void display(std::ostream& out, card const& c, bool values) const; void display(std::ostream& out, pb const& p, bool values) const; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 591577d2a..b7173e802 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -2096,7 +2096,7 @@ namespace smt { for (unsigned i = 0; i < m_active_vars.size(); ++i) { m_coeffs[m_active_vars[i]] /= g; } - m_bound /= g; + m_bound = (m_bound + g - 1) / g; std::cout << "CUT " << g << "\n"; TRACE("pb", display_resolved_lemma(tout << "cut\n");); } From 4132c44f8dc03f54a9ea26316a487fb17f3e5e20 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jul 2017 16:24:59 -0700 Subject: [PATCH 0185/1283] update to avoid difference in debug/release builds Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 86fc30981..ebf6079ea 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2842,11 +2842,13 @@ namespace sat { bool ba_solver::validate_lemma() { int val = -m_bound; - normalize_active_coeffs(); + while (!m_active_var_set.empty()) m_active_var_set.erase(); for (bool_var v : m_active_vars) { + if (m_active_var_set.contains(v)) continue; int coeff = get_coeff(v); + if (coeff == 0) continue; + m_active_var_set.insert(v); literal lit(v, false); - SASSERT(coeff != 0); if (coeff < 0 && value(lit) != l_true) { val -= coeff; } @@ -2859,9 +2861,13 @@ namespace sat { } void ba_solver::active2pb(ineq& p) { - normalize_active_coeffs(); + while (!m_active_var_set.empty()) m_active_var_set.erase(); p.reset(m_bound); for (bool_var v : m_active_vars) { + if (m_active_var_set.contains(v)) continue; + int coeff = get_coeff(v); + if (coeff == 0) continue; + m_active_var_set.insert(v); literal lit(v, get_coeff(v) < 0); p.m_lits.push_back(lit); p.m_coeffs.push_back(get_abs_coeff(v)); From 5262248823e11ffca0fa7971ad9bb61ccb9e1b79 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Jul 2017 11:13:05 -0700 Subject: [PATCH 0186/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 665 +++++++++++++++++++++++++------------- src/sat/ba_solver.h | 45 ++- src/sat/sat_extension.h | 5 +- src/sat/sat_lookahead.cpp | 4 +- src/sat/sat_solver.cpp | 22 +- 5 files changed, 501 insertions(+), 240 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index ebf6079ea..0d4f5b1fe 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -106,8 +106,8 @@ namespace sat { // ---------------------- // card - ba_solver::card::card(literal lit, literal_vector const& lits, unsigned k): - pb_base(card_t, lit, lits.size(), get_obj_size(lits.size()), k) { + ba_solver::card::card(unsigned id, literal lit, literal_vector const& lits, unsigned k): + pb_base(card_t, id, lit, lits.size(), get_obj_size(lits.size()), k) { for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; } @@ -133,8 +133,8 @@ namespace sat { // ----------------------------------- // pb - ba_solver::pb::pb(literal lit, svector const& wlits, unsigned k): - pb_base(pb_t, lit, wlits.size(), get_obj_size(wlits.size()), k), + ba_solver::pb::pb(unsigned id, literal lit, svector const& wlits, unsigned k): + pb_base(pb_t, id, lit, wlits.size(), get_obj_size(wlits.size()), k), m_slack(0), m_num_watch(0), m_max_sum(0) { @@ -185,8 +185,8 @@ namespace sat { // ----------------------------------- // xor - ba_solver::xor::xor(literal lit, literal_vector const& lits): - constraint(xor_t, lit, lits.size(), get_obj_size(lits.size())) { + ba_solver::xor::xor(unsigned id, literal lit, literal_vector const& lits): + constraint(xor_t, id, lit, lits.size(), get_obj_size(lits.size())) { for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; } @@ -211,7 +211,7 @@ namespace sat { // ---------------------------- // card - void ba_solver::init_watch(card& c, bool is_true) { + bool ba_solver::init_watch(card& c, bool is_true) { clear_watch(c); if (c.lit() != null_literal && c.lit().sign() == is_true) { c.negate(); @@ -223,7 +223,7 @@ namespace sat { if (bound == sz) { for (literal l : c) assign(c, l); - return; + return false; } for (unsigned i = 0; i < sz; ++i) { @@ -242,6 +242,7 @@ namespace sat { }); // j is the number of non-false, sz - j the number of false. + if (j < bound) { SASSERT(0 < bound && bound < sz); literal alit = c[j]; @@ -259,16 +260,19 @@ namespace sat { } } set_conflict(c, alit); + return false; } else if (j == bound) { for (unsigned i = 0; i < bound; ++i) { assign(c, c[i]); } + return false; } else { for (unsigned i = 0; i <= bound; ++i) { watch_literal(c[i], c); } + return true; } } @@ -323,7 +327,7 @@ namespace sat { // watch a prefix of literals, such that the slack of these is >= k - void ba_solver::init_watch(pb& p, bool is_true) { + bool ba_solver::init_watch(pb& p, bool is_true) { clear_watch(p); if (p.lit() != null_literal && p.lit().sign() == is_true) { p.negate(); @@ -366,6 +370,7 @@ namespace sat { } } set_conflict(p, lit); + return false; } else { for (unsigned i = 0; i < num_watch; ++i) { @@ -374,6 +379,8 @@ namespace sat { p.set_slack(slack); p.set_num_watch(num_watch); + TRACE("sat", display(tout << "init watch: ", p, true);); + // slack is tight: if (slack + slack1 == bound) { SASSERT(slack1 == 0); @@ -382,8 +389,8 @@ namespace sat { assign(p, p[i].second); } } + return true; } - TRACE("sat", display(tout << "init watch: ", p, true);); } /* @@ -400,12 +407,9 @@ namespace sat { Lw = Lw u {l_s} Lu = Lu \ {l_s} } - if (Sw < k) conflict - while (Sw < k + a_max) { - assign (l_max) - a_max = max { ai | li in Lw, li = undef } - } - ASSERT(Sw >= bound) + if (Sw < k) return conflict + for (li in Lw | Sw < k + ai) + assign li return no-conflict a_max index: index of non-false literal with maximal weight. @@ -420,8 +424,22 @@ namespace sat { } } + static unsigned _bad_id = 62390000; + +#define BADLOG(_cmd_) if (p.id() == _bad_id) { _cmd_; } + + /* + \brief propagate assignment to alit in constraint p. + + TBD: + - consider reordering literals in watch list so that the search for watched literal takes average shorter time. + - combine with caching literals that are assigned to 'true' to a cold store where they are not being revisited. + Since 'true' literals may be unassigned (unless they are assigned at level 0) the cache has to be backtrack + friendly (and the overhead of backtracking has to be taken into account). + */ lbool ba_solver::add_assign(pb& p, literal alit) { + BADLOG(display(std::cout << "assign: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); SASSERT(!inconsistent()); unsigned sz = p.size(); @@ -442,12 +460,16 @@ namespace sat { } add_index(p, index, lit); } - SASSERT(index < num_watch); - if (index >= num_watch) { - std::cout << "BAD assign. " << alit << " not found within " << num_watch << "\n"; - std::cout << p << "\n"; + if (index == num_watch) { + _bad_id = p.id(); + std::cout << p.id() << "\n"; + display(std::cout, p, true); + std::cout << "alit: " << alit << "\n"; + std::cout << "num watch " << num_watch << "\n"; + return l_undef; } - + + SASSERT(index < num_watch); unsigned index1 = index + 1; for (; m_a_max == 0 && index1 < num_watch; ++index1) { add_index(p, index1, p[index1].second); @@ -457,6 +479,7 @@ namespace sat { SASSERT(value(p[index].second) == l_false); SASSERT(val <= slack); slack -= val; + // find literals to swap with: for (unsigned j = num_watch; j < sz && slack < bound + m_a_max; ++j) { literal lit = p[j].second; @@ -465,6 +488,7 @@ namespace sat { watch_literal(p[j], p); p.swap(num_watch, j); add_index(p, num_watch, lit); + BADLOG(std::cout << "add watch: " << lit << " num watch: " << num_watch << "\n"); ++num_watch; } } @@ -477,16 +501,18 @@ namespace sat { slack += val; p.set_slack(slack); p.set_num_watch(num_watch); + BADLOG(display(std::cout << "conflict: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); SASSERT(bound <= slack); TRACE("sat", tout << "conflict " << alit << "\n";); set_conflict(p, alit); return l_false; } - if (index > p.size() || num_watch > p.size() || num_watch == 0) { + if (index > p.size() || num_watch > p.size() || num_watch == 0 || p.id() == _bad_id) { display(std::cout, p, true); - std::cout << "size: " << p.size() << "index: " << index << " num watch: " << num_watch << "\n"; + std::cout << "size: " << p.size() << " index: " << index << " num watch: " << num_watch << "\n"; } + // swap out the watched literal. --num_watch; SASSERT(num_watch > 0); @@ -494,32 +520,28 @@ namespace sat { p.set_num_watch(num_watch); p.swap(num_watch, index); - if (slack < bound + m_a_max) { - TRACE("sat", tout << p; for(auto j : m_pb_undef) tout << j << "\n";); - literal_vector to_assign; - while (!m_pb_undef.empty()) { - index1 = m_pb_undef.back(); - if (index1 == num_watch) index1 = index; // it was swapped with index above. - if (index1 >= num_watch) { - std::cout << "BAD assignment at position " << index1 << " with " << num_watch << "\n"; - std::cout << p << "\n"; - } - literal lit = p[index1].second; - SASSERT(value(lit) == l_undef); - TRACE("sat", tout << index1 << " " << lit << "\n";); - if (slack >= bound + p[index1].first) { - break; - } - m_pb_undef.pop_back(); - to_assign.push_back(lit); - } + BADLOG(std::cout << "swap watched: " << alit << " watch: " << p.num_watch() << " size: " << p.size() << " slack: " << p.slack() << "\n"); - for (literal lit : to_assign) { - assign(p, lit); + // + // slack >= bound, but slack - w(l) < bound + // l must be true. + // + if (slack < bound + m_a_max) { + TRACE("sat", tout << p; for(auto j : m_pb_undef) tout << j << "\n";); + for (unsigned index1 : m_pb_undef) { + if (index1 == num_watch) { + index1 = index; + } + wliteral wl = p[index1]; + literal lit = wl.second; + SASSERT(value(lit) == l_undef); + BADLOG(std::cout << "Assign " << lit << "\n"); + if (slack < bound + wl.first) { + assign(p, lit); + } } } - TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); return l_undef; @@ -564,7 +586,7 @@ namespace sat { if (p.is_cardinality()) { literal_vector lits(p.literals()); unsigned k = (p.k() + p[0].first - 1) / p[0].first; - add_at_least(p.lit(), lits, k); + add_at_least(p.lit(), lits, k, p.learned()); remove_constraint(p); } else if (p.lit() == null_literal) { @@ -711,7 +733,7 @@ namespace sat { return odd; } - void ba_solver::init_watch(xor& x, bool is_true) { + bool ba_solver::init_watch(xor& x, bool is_true) { clear_watch(x); if (x.lit() != null_literal && x.lit().sign() == is_true) { x.negate(); @@ -739,18 +761,18 @@ namespace sat { SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); set_conflict(x, x[j]); } - break; + return false; case 1: SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); assign(x, parity(x, 1) ? ~x[0] : x[0]); - break; + return false; default: SASSERT(j == 2); watch_literal(x[0], x); watch_literal(x[1], x); watch_literal(~x[0], x); watch_literal(~x[1], x); - break; + return true; } } @@ -801,7 +823,7 @@ namespace sat { // conflict resolution void ba_solver::normalize_active_coeffs() { - while (!m_active_var_set.empty()) m_active_var_set.erase(); + reset_active_var_set(); unsigned i = 0, j = 0, sz = m_active_vars.size(); for (; i < sz; ++i) { bool_var v = m_active_vars[i]; @@ -864,9 +886,9 @@ namespace sat { static bool _debug_conflict = false; - bool ba_solver::resolve_conflict() { + lbool ba_solver::resolve_conflict() { if (0 == m_num_propagations_since_pop) { - return false; + return l_undef; } reset_coeffs(); m_num_marks = 0; @@ -1044,10 +1066,62 @@ namespace sat { SASSERT(validate_lemma()); normalize_active_coeffs(); + + if (!create_asserting_lemma()) { + goto bail_out; + } + active2card(); + + SASSERT(validate_conflict(m_lemma, m_A)); + + TRACE("sat", tout << m_lemma << "\n";); + + if (get_config().m_drat) { + svector ps; // TBD fill in + drat_add(m_lemma, ps); + } + + s().m_lemma.reset(); + s().m_lemma.append(m_lemma); + for (unsigned i = 1; i < m_lemma.size(); ++i) { + CTRACE("sat", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); + s().mark(m_lemma[i].var()); + } + + return l_true; + + bail_out: + while (m_num_marks > 0 && idx >= 0) { + bool_var v = lits[idx].var(); + if (s().is_marked(v)) { + s().reset_mark(v); + --m_num_marks; + } + if (idx == 0 && !_debug_conflict) { + _debug_conflict = true; + // s().display(std::cout); + std::cout << s().m_not_l << "\n"; + for (literal l : lits) { + if (s().is_marked(l.var())) { + std::cout << "missing mark: " << l << "\n"; + s().reset_mark(l.var()); + } + } + m_num_marks = 0; + resolve_conflict(); + } + --idx; + } + return l_undef; + } + + bool ba_solver::create_asserting_lemma() { + + adjust_conflict_level: + int slack = -m_bound; - for (unsigned i = 0; i < m_active_vars.size(); ++i) { - bool_var v = m_active_vars[i]; + for (bool_var v : m_active_vars) { slack += get_abs_coeff(v); } @@ -1085,69 +1159,39 @@ namespace sat { } } - if (slack >= 0) { IF_VERBOSE(2, verbose_stream() << "(sat.card slack: " << slack << " skipped: " << num_skipped << ")\n";); - goto bail_out; + return false; } - if (m_lemma[0] == null_literal) { - m_lemma[0] = m_lemma.back(); - m_lemma.pop_back(); - unsigned level = m_lemma.empty() ? 0 : lvl(m_lemma[0]); - for (unsigned i = 1; i < m_lemma.size(); ++i) { - if (lvl(m_lemma[i]) > level) { - level = lvl(m_lemma[i]); - std::swap(m_lemma[0], m_lemma[i]); - } - } - IF_VERBOSE(2, verbose_stream() << "(sat.card set level to " << level << " < " << m_conflict_lvl << ")\n";); - } - - if (slack < -1) std::cout << "lemma: " << m_lemma << " >= " << -slack << "\n"; - SASSERT(slack < 0); - - SASSERT(validate_conflict(m_lemma, m_A)); - TRACE("sat", tout << m_lemma << "\n";); - - if (get_config().m_drat) { - svector ps; // TBD fill in - drat_add(m_lemma, ps); + if (m_lemma[0] == null_literal) { + if (m_lemma.size() == 1) { + s().set_conflict(justification()); + return false; + } + unsigned old_level = m_conflict_lvl; + m_conflict_lvl = 0; + for (unsigned i = 1; i < m_lemma.size(); ++i) { + m_conflict_lvl = std::max(m_conflict_lvl, lvl(m_lemma[i])); + } + IF_VERBOSE(1, verbose_stream() << "(sat-backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); + goto adjust_conflict_level; } - s().m_lemma.reset(); - s().m_lemma.append(m_lemma); - for (unsigned i = 1; i < m_lemma.size(); ++i) { - CTRACE("sat", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); - s().mark(m_lemma[i].var()); + // slack is related to coefficients of m_lemma + // so does not apply to unit coefficients. + // std::cout << "lemma: " << m_lemma << " >= " << 1 << "\n"; + // active2pb(m_A); + // display(std::cout, m_A, true); +#if 0 + constraint* c = active2constraint(); + if (c) { + display(std::cout, *c, true); + std::cout << "Eval: " << eval(*c) << "\n"; } - +#endif return true; - - bail_out: - while (m_num_marks > 0 && idx >= 0) { - bool_var v = lits[idx].var(); - if (s().is_marked(v)) { - s().reset_mark(v); - --m_num_marks; - } - if (idx == 0 && !_debug_conflict) { - _debug_conflict = true; - // s().display(std::cout); - std::cout << s().m_not_l << "\n"; - for (literal l : lits) { - if (s().is_marked(l.var())) { - std::cout << "missing mark: " << l << "\n"; - s().reset_mark(l.var()); - } - } - m_num_marks = 0; - resolve_conflict(); - } - --idx; - } - return false; } void ba_solver::cut() { @@ -1184,12 +1228,17 @@ namespace sat { } } if (g >= 2) { + active2pb(m_A); + display(std::cout, m_A, true); normalize_active_coeffs(); + int ig = static_cast(g); for (unsigned i = 0; i < m_active_vars.size(); ++i) { - m_coeffs[m_active_vars[i]] /= g; + m_coeffs[m_active_vars[i]] /= ig; } m_bound = (m_bound + g - 1) / g; std::cout << "CUT " << g << "\n"; + active2pb(m_A); + display(std::cout, m_A, true); } } @@ -1238,32 +1287,51 @@ namespace sat { return p; } - ba_solver::ba_solver(): m_solver(0), m_lookahead(0) { + ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_constraint_id(0) { TRACE("sat", tout << this << "\n";); } ba_solver::~ba_solver() { m_stats.reset(); - while (!m_constraints.empty()) { - pop_constraint(); + for (constraint* c : m_constraints) { + m_allocator.deallocate(c->obj_size(), c); + } + for (constraint* c : m_learned) { + m_allocator.deallocate(c->obj_size(), c); } } void ba_solver::add_at_least(bool_var v, literal_vector const& lits, unsigned k) { literal lit = v == null_bool_var ? null_literal : literal(v, false); - add_at_least(lit, lits, k); + add_at_least(lit, lits, k, false); } - void ba_solver::add_at_least(literal lit, literal_vector const& lits, unsigned k) { + ba_solver::card& ba_solver::add_at_least(literal lit, literal_vector const& lits, unsigned k, bool learned) { void * mem = m_allocator.allocate(card::get_obj_size(lits.size())); - card* c = new (mem) card(lit, lits, k); + card* c = new (mem) card(next_id(), lit, lits, k); + c->set_learned(learned); add_constraint(c); + return *c; } void ba_solver::add_constraint(constraint* c) { - m_constraints.push_back(c); + if (c->id() == _bad_id) { + display(std::cout, *c, true); + } + if (c->learned()) { + m_learned.push_back(c); + } + else { + SASSERT(s().at_base_lvl()); + m_constraints.push_back(c); + } literal lit = c->lit(); - if (lit == null_literal) { + if (c->learned()) { + SASSERT(lit == null_literal); + // gets initialized after backjump. + m_constraint_to_reinit.push_back(c); + } + else if (lit == null_literal) { init_watch(*c, true); } else { @@ -1275,12 +1343,15 @@ namespace sat { } - void ba_solver::init_watch(constraint& c, bool is_true) { + bool ba_solver::init_watch(constraint& c, bool is_true) { + if (inconsistent()) return false; switch (c.tag()) { - case card_t: init_watch(c.to_card(), is_true); break; - case pb_t: init_watch(c.to_pb(), is_true); break; - case xor_t: init_watch(c.to_xor(), is_true); break; + case card_t: return init_watch(c.to_card(), is_true); + case pb_t: return init_watch(c.to_pb(), is_true); + case xor_t: return init_watch(c.to_xor(), is_true); } + UNREACHABLE(); + return false; } lbool ba_solver::add_assign(constraint& c, literal l) { @@ -1293,42 +1364,48 @@ namespace sat { return l_undef; } - ba_solver::pb const& ba_solver::add_pb_ge(literal lit, svector const& wlits, unsigned k) { + ba_solver::pb& ba_solver::add_pb_ge(literal lit, svector const& wlits, unsigned k, bool learned) { void * mem = m_allocator.allocate(pb::get_obj_size(wlits.size())); - pb* p = new (mem) pb(lit, wlits, k); + pb* p = new (mem) pb(next_id(), lit, wlits, k); + p->set_learned(learned); add_constraint(p); return *p; } void ba_solver::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { literal lit = v == null_bool_var ? null_literal : literal(v, false); - add_pb_ge(lit, wlits, k); + add_pb_ge(lit, wlits, k, false); } void ba_solver::add_xor(bool_var v, literal_vector const& lits) { - add_xor(literal(v, false), lits); + add_xor(literal(v, false), lits, false); } - void ba_solver::add_xor(literal lit, literal_vector const& lits) { + ba_solver::xor& ba_solver::add_xor(literal lit, literal_vector const& lits, bool learned) { void * mem = m_allocator.allocate(xor::get_obj_size(lits.size())); - xor* x = new (mem) xor(lit, lits); + xor* x = new (mem) xor(next_id(), lit, lits); + x->set_learned(learned); add_constraint(x); for (literal l : lits) s().set_external(l.var()); // TBD: determine if goal2sat does this. + return *x; } - void ba_solver::propagate(literal l, ext_constraint_idx idx, bool & keep) { + /* + \brief return true to keep watching literal. + */ + bool ba_solver::propagate(literal l, ext_constraint_idx idx) { SASSERT(value(l) == l_true); TRACE("sat", tout << l << " " << idx << "\n";); constraint& c = index2constraint(idx); if (c.lit() != null_literal && l.var() == c.lit().var()) { init_watch(c, !l.sign()); - keep = true; + return true; } else if (c.lit() != null_literal && value(c.lit()) != l_true) { - keep = false; + return false; } else { - keep = l_undef != add_assign(c, ~l); + return l_undef != add_assign(c, ~l); } } @@ -1436,88 +1513,78 @@ namespace sat { TRACE("sat", tout << r << "\n";); } + /** + \brief retrieve a sufficient set of literals from p that imply l. + + Find partition: + + - Ax + coeff*l + B*y >= k + - all literals in x are false. + - B < k + + Then x is an explanation for l + + */ void ba_solver::get_antecedents(literal l, pb const& p, literal_vector& r) { - if (p.lit() != null_literal) r.push_back(p.lit()); - SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); TRACE("sat", display(tout, p, true);); + SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); + + if (p.lit() != null_literal) { + r.push_back(p.lit()); + } + + unsigned k = p.k(); if (value(l) == l_false) { // The literal comes from a conflict. // it is forced true, but assigned to false. unsigned slack = 0; - unsigned miss = 0; - unsigned worth = 0; - unsigned k = p.k(); for (wliteral wl : p) { - literal lit = wl.second; - if (lit == l) { - worth = wl.first; - } - else if (value(lit) == l_false) { - miss += wl.first; - } - else { + if (value(wl.second) != l_false) { slack += wl.first; } } SASSERT(slack < k); - SASSERT(0 < worth); - - slack += worth; for (wliteral wl : p) { literal lit = wl.second; if (lit != l && value(lit) == l_false) { unsigned w = wl.first; - if (slack + w >= k) { - r.push_back(~lit); + if (slack + w < k) { + slack += w; } else { - slack += w; - std::cout << "increase slack by " << w << " to " << slack << " worth: " << worth << "\n"; + r.push_back(~lit); } } } -#if 0 - std::cout << p << "\n"; - std::cout << r << "\n"; - std::cout << "slack:" << slack << " miss: " << miss << "\n"; -#endif - return; } - - unsigned coeff = 0; - for (unsigned j = 0; j < p.num_watch(); ++j) { - if (p[j].second == l) { - coeff = p[j].first; - break; + else { + unsigned coeff = 0; + for (unsigned j = 0; j < p.num_watch(); ++j) { + if (p[j].second == l) { + coeff = p[j].first; + break; + } + } + + CTRACE("sat", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); + + SASSERT(coeff > 0); + unsigned slack = p.slack() - coeff; + + for (unsigned i = p.num_watch(); i < p.size(); ++i) { + literal lit = p[i].second; + unsigned w = p[i].first; + SASSERT(l_false == value(lit)); + if (slack + w < k) { + slack += w; + } + else { + r.push_back(~lit); + } } } - - if (_debug_conflict) { - std::cout << p << "\n"; - std::cout << l << " " << coeff << " num_watch: " << p.num_watch() << "\n"; - } - - CTRACE("sat", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); - - SASSERT(coeff > 0); - unsigned slack = p.slack() - coeff; - unsigned i = p.num_watch(); - - // skip entries that are not required for unit propagation. - // slack - coeff + w_head < k - unsigned h = 0; - for (; i < p.size() && p[i].first + h + slack < p.k(); ++i) { - h += p[i].first; - } - for (; i < p.size(); ++i) { - literal lit = p[i].second; - CTRACE("sat", l_false != value(lit), - tout << l << " index: " << i << " slack: " << slack << " h: " << h << " coeff: " << coeff << "\n"; - display(tout, p, true);); - SASSERT(l_false == value(lit)); - r.push_back(~lit); - } + SASSERT(validate_unit_propagation(p, r, l)); } void ba_solver::simplify(xor& x) { @@ -1741,7 +1808,7 @@ namespace sat { if (lvl(l) == 0) continue; bool found = is_watching(l, c); if (found != c.is_watching(l)) { - std::cout << "Discrepancy of watched literal: " << l << ": " << c.index() << " " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n"; + std::cout << "Discrepancy of watched literal: " << l << ": " << c.id() << " " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n"; display_watch_list(std::cout << l << ": ", s().m_cls_allocator, get_wlist(l)) << "\n"; display_watch_list(std::cout << ~l << ": ", s().m_cls_allocator, get_wlist(~l)) << "\n"; std::cout << "value: " << value(l) << " level: " << lvl(l) << "\n"; @@ -1858,28 +1925,30 @@ namespace sat { check_result ba_solver::check() { return CR_DONE; } void ba_solver::push() { - m_constraint_lim.push_back(m_constraints.size()); + m_constraint_to_reinit_lim.push_back(m_constraint_to_reinit.size()); } - void ba_solver::pop_constraint() { - constraint* c = m_constraints.back(); - m_constraints.pop_back(); - remove_constraint(*c); - m_allocator.deallocate(c->obj_size(), c); - } - - void ba_solver::pop(unsigned n) { TRACE("sat_verbose", tout << "pop:" << n << "\n";); - unsigned new_lim = m_constraint_lim.size() - n; - unsigned sz = m_constraint_lim[new_lim]; - while (m_constraints.size() > sz) { - pop_constraint(); - } - m_constraint_lim.resize(new_lim); + unsigned new_lim = m_constraint_to_reinit_lim.size() - n; + m_constraint_to_reinit_last_sz = m_constraint_to_reinit_lim[new_lim]; + m_constraint_to_reinit_lim.shrink(new_lim); m_num_propagations_since_pop = 0; } + void ba_solver::pop_reinit() { + // TBD: need a stack to follow backtracking order. + unsigned sz = m_constraint_to_reinit_last_sz; + // if (sz < m_constraint_to_reinit.size()) std::cout << "REINIT " << s().scope_lvl() << " " << m_constraint_to_reinit.size() - sz << "\n"; + for (unsigned i = sz; i < m_constraint_to_reinit.size(); ++i) { + constraint* c = m_constraint_to_reinit[i]; + if (!init_watch(*c, true)) { + m_constraint_to_reinit[sz++] = c; + } + } + m_constraint_to_reinit.shrink(sz); + } + void ba_solver::simplify(constraint& c) { SASSERT(s().at_base_lvl()); switch (c.tag()) { @@ -1902,11 +1971,12 @@ namespace sat { unsigned trail_sz; do { trail_sz = s().init_trail_size(); - IF_VERBOSE(1, verbose_stream() << "(bool-algebra-solver simplify-begin :trail " << trail_sz << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(bool-algebra-solver simplify-begin :trail " << trail_sz << " :learned " << m_learned.size() << ")\n";); m_simplify_change = false; m_clause_removed = false; m_constraint_removed = false; - // for (constraint* c : m_constraints) simplify(*c); + for (constraint* c : m_constraints) simplify(*c); + for (constraint* c : m_learned) simplify(*c); init_use_lists(); remove_unused_defs(); set_non_external(); @@ -1934,7 +2004,7 @@ namespace sat { if (mux.size() > 2) { IF_VERBOSE(1, verbose_stream() << "mux: " << mux << "\n";); for (unsigned i = 0; i < mux.size(); ++i) mux[i].neg(); - add_at_least(null_literal, mux, mux.size() - 1); + add_at_least(null_literal, mux, mux.size() - 1, false); } } } @@ -2081,6 +2151,9 @@ namespace sat { } void ba_solver::recompile(constraint& c) { + if (c.id() == _bad_id) { + display(std::cout << "recompile\n", c, true); + } switch (c.tag()) { case card_t: recompile(c.to_card()); @@ -2158,7 +2231,7 @@ namespace sat { } literal root = c.lit(); remove_constraint(c); - pb const& p = add_pb_ge(root, wlits, k); + pb const& p = add_pb_ge(root, wlits, k, c.learned()); IF_VERBOSE(1, verbose_stream() << p << "\n";); } else { @@ -2665,7 +2738,7 @@ namespace sat { card const& c = cp->to_card(); lits.reset(); for (literal l : c) lits.push_back(l); - result->add_at_least(c.lit(), lits, c.k()); + result->add_at_least(c.lit(), lits, c.k(), c.learned()); break; } case pb_t: { @@ -2674,14 +2747,14 @@ namespace sat { for (wliteral w : p) { wlits.push_back(w); } - result->add_pb_ge(p.lit(), wlits, p.k()); + result->add_pb_ge(p.lit(), wlits, p.k(), p.learned()); break; } case xor_t: { xor const& x = cp->to_xor(); lits.reset(); for (literal l : x) lits.push_back(l); - result->add_xor(x.lit(), lits); + result->add_xor(x.lit(), lits, x.learned()); break; } default: @@ -2832,6 +2905,21 @@ namespace sat { return sum < p.k(); } + bool ba_solver::validate_unit_propagation(pb const& p, literal_vector const& r, literal alit) const { + unsigned sum = 0; + // all elements of r are true, + for (literal l : r) { + if (value(l) != l_true) return false; + } + // the sum of elements not in r or alit add up to less than k. + for (wliteral wl : p) { + if (wl.second != alit && !r.contains(~wl.second)) { + sum += wl.first; + } + } + return sum < p.k(); + } + bool ba_solver::validate_unit_propagation(xor const& x, literal alit) const { if (value(x.lit()) != l_true) return false; for (unsigned i = 1; i < x.size(); ++i) { @@ -2842,7 +2930,7 @@ namespace sat { bool ba_solver::validate_lemma() { int val = -m_bound; - while (!m_active_var_set.empty()) m_active_var_set.erase(); + reset_active_var_set(); for (bool_var v : m_active_vars) { if (m_active_var_set.contains(v)) continue; int coeff = get_coeff(v); @@ -2860,20 +2948,163 @@ namespace sat { return val < 0; } - void ba_solver::active2pb(ineq& p) { + void ba_solver::reset_active_var_set() { while (!m_active_var_set.empty()) m_active_var_set.erase(); + } + + void ba_solver::active2pb(ineq& p) { + reset_active_var_set(); p.reset(m_bound); for (bool_var v : m_active_vars) { if (m_active_var_set.contains(v)) continue; int coeff = get_coeff(v); if (coeff == 0) continue; m_active_var_set.insert(v); - literal lit(v, get_coeff(v) < 0); + literal lit(v, coeff < 0); p.m_lits.push_back(lit); - p.m_coeffs.push_back(get_abs_coeff(v)); + p.m_coeffs.push_back(abs(coeff)); } } + ba_solver::constraint* ba_solver::active2constraint() { + reset_active_var_set(); + literal_vector lits; + unsigned_vector coeffs; + bool all_one = true; + uint64_t sum = 0; + if (m_bound == 1) return 0; + for (bool_var v : m_active_vars) { + int coeff = get_coeff(v); + if (m_active_var_set.contains(v) || coeff == 0) continue; + m_active_var_set.insert(v); + literal lit(v, coeff < 0); + lits.push_back(lit); + coeffs.push_back(abs(coeff)); + all_one &= abs(coeff) == 1; + sum += abs(coeff); + } + if (sum >= UINT_MAX/2) return 0; + if (all_one) { + card& c = add_at_least(null_literal, lits, m_bound, true); + return &c; + } + else { + svector wlits; + for (unsigned i = 0; i < lits.size(); ++i) { + wlits.push_back(wliteral(coeffs[i], lits[i])); + } + pb& p = add_pb_ge(null_literal, wlits, m_bound, true); + return &p; + } + } + + /* + Chai Kuhlmann: + + a1*l1 + ... + a_n*l_n >= k + s.t. + a1 >= a2 >= .. >= a_n + + let m be such that + + sum_{i = 1}^{m-1} a_i < k <= sum_{i = 1}^{m} + + then + + l1 + ... + l_n >= m + + furthermore, for the largest n' <= n, such that + + sum_{i = n'+1}^n a_i + sum_{i = 1}^{m-1} a_i < k + + then + + l1 + ... + l_n' >= m + + */ + struct compare_wlit { + bool operator()(ba_solver::wliteral l1, ba_solver::wliteral l2) const { + return l1.first > l2.first; + } + }; + + + ba_solver::card* ba_solver::active2card() { + normalize_active_coeffs(); + svector wlits; + for (bool_var v : m_active_vars) { + int coeff = get_coeff(v); + wlits.push_back(std::make_pair(abs(coeff), literal(v, coeff < 0))); + } + std::sort(wlits.begin(), wlits.end(), compare_wlit()); + unsigned k = 0; + int sum = 0, sum0 = 0; + for (wliteral wl : wlits) { + if (sum >= m_bound) break; + sum0 = sum; + sum += wl.first; + ++k; + } + if (k == 1) { + return 0; + } + while (!wlits.empty()) { + wliteral wl = wlits.back(); + if (wl.first + sum0 >= static_cast(m_bound)) break; + wlits.pop_back(); + sum0 += wl.first; + } + + unsigned slack = 0; + unsigned max_level = 0; + unsigned num_max_level = 0; + for (wliteral wl : wlits) { + if (value(wl.second) != l_false) ++slack; + unsigned level = lvl(wl.second); + if (level > max_level) { + max_level = level; + num_max_level = 1; + } + else if (max_level == level) { + ++num_max_level; + } + } + + + if (slack >= k) { + return 0; + } + + +#if 0 + std::cout << "card: "; + for (wliteral wl : wlits) std::cout << wl.second << " "; + std::cout << ">= " << k << "\n"; + + if (num_max_level > 1) { + std::cout << "max level " << num_max_level << "\n"; + } + + + if (wlits.size() < m_active_vars.size()) std::cout << "REMOVED " << m_active_vars.size() - wlits.size() << "\n"; +#endif + + // produce asserting cardinality constraint + literal_vector lits; + for (wliteral wl : wlits) lits.push_back(wl.second); + card& c = add_at_least(null_literal, lits, k, true); + + lits.reset(); + for (wliteral wl : wlits) { + if (value(wl.second) == l_false) lits.push_back(wl.second); + } + unsigned glue = s().num_diff_levels(lits.size(), lits.c_ptr()); + + c.set_glue(glue); + return &c; + } + + void ba_solver::justification2pb(justification const& js, literal lit, unsigned offset, ineq& ineq) { switch (js.get_kind()) { case justification::NONE: diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 0651dd495..b8978b254 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -62,9 +62,12 @@ namespace sat { unsigned m_glue; unsigned m_size; size_t m_obj_size; + bool m_learned; + unsigned m_id; public: - constraint(tag_t t, literal l, unsigned sz, size_t osz): m_tag(t), m_removed(false), m_lit(l), m_glue(0), m_size(sz), m_obj_size(osz) {} + constraint(tag_t t, unsigned id, literal l, unsigned sz, size_t osz): m_tag(t), m_removed(false), m_lit(l), m_glue(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id) {} ext_constraint_idx index() const { return reinterpret_cast(this); } + unsigned id() const { return m_id; } tag_t tag() const { return m_tag; } literal lit() const { return m_lit; } unsigned size() const { return m_size; } @@ -75,6 +78,8 @@ namespace sat { void nullify_literal() { m_lit = null_literal; } unsigned glue() const { return m_glue; } void set_glue(unsigned g) { m_glue = g; } + void set_learned(bool f) { m_learned = f; } + bool learned() const { return m_learned; } size_t obj_size() const { return m_obj_size; } card& to_card(); @@ -102,7 +107,7 @@ namespace sat { protected: unsigned m_k; public: - pb_base(tag_t t, literal l, unsigned sz, size_t osz, unsigned k): constraint(t, l, sz, osz), m_k(k) {} + pb_base(tag_t t, unsigned id, literal l, unsigned sz, size_t osz, unsigned k): constraint(t, id, l, sz, osz), m_k(k) {} virtual void set_k(unsigned k) { m_k = k; } virtual unsigned get_coeff(unsigned i) const { UNREACHABLE(); return 0; } unsigned k() const { return m_k; } @@ -113,7 +118,7 @@ namespace sat { literal m_lits[0]; public: static size_t get_obj_size(unsigned num_lits) { return sizeof(card) + num_lits * sizeof(literal); } - card(literal lit, literal_vector const& lits, unsigned k); + card(unsigned id, literal lit, literal_vector const& lits, unsigned k); literal operator[](unsigned i) const { return m_lits[i]; } literal& operator[](unsigned i) { return m_lits[i]; } literal const* begin() const { return m_lits; } @@ -138,7 +143,7 @@ namespace sat { void update_max_sum(); public: static size_t get_obj_size(unsigned num_lits) { return sizeof(pb) + num_lits * sizeof(wliteral); } - pb(literal lit, svector const& wlits, unsigned k); + pb(unsigned id, literal lit, svector const& wlits, unsigned k); literal lit() const { return m_lit; } wliteral operator[](unsigned i) const { return m_wlits[i]; } wliteral& operator[](unsigned i) { return m_wlits[i]; } @@ -165,7 +170,7 @@ namespace sat { literal m_lits[0]; public: static size_t get_obj_size(unsigned num_lits) { return sizeof(xor) + num_lits * sizeof(literal); } - xor(literal lit, literal_vector const& lits); + xor(unsigned id, literal lit, literal_vector const& lits); literal operator[](unsigned i) const { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return begin() + m_size; } @@ -197,7 +202,10 @@ namespace sat { ptr_vector m_constraints; ptr_vector m_learned; - unsigned_vector m_constraint_lim; + ptr_vector m_constraint_to_reinit; + unsigned_vector m_constraint_to_reinit_lim; + unsigned m_constraint_to_reinit_last_sz; + unsigned m_constraint_id; // conflict resolution unsigned m_num_marks; @@ -272,7 +280,7 @@ namespace sat { void watch_literal(literal w, constraint& c); void watch_literal(wliteral w, pb& p); void add_constraint(constraint* c); - void init_watch(constraint& c, bool is_true); + bool init_watch(constraint& c, bool is_true); void init_watch(bool_var v); void clear_watch(constraint& c); lbool add_assign(constraint& c, literal l); @@ -290,10 +298,11 @@ namespace sat { void assert_unconstrained(literal lit, literal_vector const& lits); void flush_roots(constraint& c); void recompile(constraint& c); + unsigned next_id() { return m_constraint_id++; } // cardinality - void init_watch(card& c, bool is_true); + bool init_watch(card& c, bool is_true); lbool add_assign(card& c, literal lit); void clear_watch(card& c); void reset_coeffs(); @@ -305,7 +314,7 @@ namespace sat { // xor specific functionality void clear_watch(xor& x); - void init_watch(xor& x, bool is_true); + bool init_watch(xor& x, bool is_true); bool parity(xor const& x, unsigned offset) const; lbool add_assign(xor& x, literal alit); void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); @@ -316,7 +325,7 @@ namespace sat { // pb functionality unsigned m_a_max; - void init_watch(pb& p, bool is_true); + bool init_watch(pb& p, bool is_true); lbool add_assign(pb& p, literal alit); void add_index(pb& p, unsigned index, literal lit); void clear_watch(pb& p); @@ -342,6 +351,7 @@ namespace sat { inline void drat_add(literal_vector const& c, svector const& premises) { m_solver->m_drat.add(c, premises); } + void reset_active_var_set(); void normalize_active_coeffs(); void inc_coeff(literal l, int offset); int get_coeff(bool_var v) const; @@ -351,6 +361,7 @@ namespace sat { void process_antecedent(literal l, int offset); void process_card(card& c, int offset); void cut(); + bool create_asserting_lemma(); // validation utilities bool validate_conflict(card const& c) const; @@ -360,6 +371,7 @@ namespace sat { bool validate_lemma(); bool validate_unit_propagation(card const& c, literal alit) const; bool validate_unit_propagation(pb const& p, literal alit) const; + bool validate_unit_propagation(pb const& p, literal_vector const& r, literal alit) const; bool validate_unit_propagation(xor const& x, literal alit) const; bool validate_conflict(literal_vector const& lits, ineq& p); bool validate_watch_literals() const; @@ -369,6 +381,8 @@ namespace sat { ineq m_A, m_B, m_C; void active2pb(ineq& p); + constraint* active2constraint(); + card* active2card(); void justification2pb(justification const& j, literal lit, unsigned offset, ineq& p); bool validate_resolvent(); @@ -378,9 +392,9 @@ namespace sat { void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xor const& c, bool values) const; - void add_at_least(literal l, literal_vector const& lits, unsigned k); - pb const& add_pb_ge(literal l, svector const& wlits, unsigned k); - void add_xor(literal l, literal_vector const& lits); + card& add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned); + pb& add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); + xor& add_xor(literal l, literal_vector const& lits, bool learned); public: ba_solver(); @@ -391,8 +405,8 @@ namespace sat { void add_pb_ge(bool_var v, svector const& wlits, unsigned k); void add_xor(bool_var v, literal_vector const& lits); - virtual void propagate(literal l, ext_constraint_idx idx, bool & keep); - virtual bool resolve_conflict(); + virtual bool propagate(literal l, ext_constraint_idx idx); + virtual lbool resolve_conflict(); virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r); virtual void asserted(literal l); virtual check_result check(); @@ -408,6 +422,7 @@ namespace sat { virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); virtual void find_mutexes(literal_vector& lits, vector & mutexes); + virtual void pop_reinit(); virtual void gc(); ptr_vector const & constraints() const { return m_constraints; } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index f984091e3..4c052494a 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -34,11 +34,11 @@ namespace sat { virtual ~extension() {} virtual void set_solver(solver* s) = 0; virtual void set_lookahead(lookahead* s) = 0; - virtual void propagate(literal l, ext_constraint_idx idx, bool & keep) = 0; + virtual bool propagate(literal l, ext_constraint_idx idx) = 0; virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0; virtual void asserted(literal l) = 0; virtual check_result check() = 0; - virtual bool resolve_conflict() { return false; } // stores result in sat::solver::m_lemma + virtual lbool resolve_conflict() { return l_undef; } // stores result in sat::solver::m_lemma virtual void push() = 0; virtual void pop(unsigned n) = 0; virtual void simplify() = 0; @@ -53,6 +53,7 @@ namespace sat { virtual extension* copy(solver* s) = 0; virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; virtual void gc() = 0; + virtual void pop_reinit() = 0; virtual void validate() = 0; }; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 2a1837e20..6c40c93fd 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1170,10 +1170,10 @@ namespace sat { break; } case watched::EXT_CONSTRAINT: { - bool keep = true; SASSERT(m_s.m_ext); - m_s.m_ext->propagate(l, it->get_ext_constraint_idx(), keep); + bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); if (m_inconsistent) { + if (!keep) ++it; set_conflict(); } else if (keep) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 29c15c2d7..15737d65b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -795,8 +795,12 @@ namespace sat { } case watched::EXT_CONSTRAINT: SASSERT(m_ext); - m_ext->propagate(l, it->get_ext_constraint_idx(), keep); + keep = m_ext->propagate(l, it->get_ext_constraint_idx()); if (m_inconsistent) { + if (!keep) { + std::cout << "CONFLICT - but throw away current watch literal\n"; + ++it; + } CONFLICT_CLEANUP(); return false; } @@ -1955,9 +1959,17 @@ namespace sat { forget_phase_of_vars(m_conflict_lvl); - if (m_ext && m_ext->resolve_conflict()) { - learn_lemma_and_backjump(); - return true; + if (m_ext) { + switch (m_ext->resolve_conflict()) { + case l_true: + learn_lemma_and_backjump(); + return true; + case l_undef: + break; + case l_false: + // backjumping was taken care of internally. + return true; + } } m_lemma.reset(); @@ -2770,6 +2782,8 @@ namespace sat { m_scope_lvl -= num_scopes; m_scopes.shrink(new_lvl); reinit_clauses(s.m_clauses_to_reinit_lim); + if (m_ext) + m_ext->pop_reinit(); } void solver::unassign_vars(unsigned old_sz) { From b419a0e4a43a39f90801171b9eaf52ad02cea434 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 5 Jul 2017 14:32:13 -0700 Subject: [PATCH 0187/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 320 +++++++++++++++++++++++++++++++++------- src/sat/ba_solver.h | 14 +- src/sat/sat_probing.cpp | 6 +- src/sat/sat_solver.cpp | 16 +- 4 files changed, 288 insertions(+), 68 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 0d4f5b1fe..465c5c73b 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -325,6 +325,7 @@ namespace sat { // ------------------- // pb + static unsigned _bad_id = 11111111; // 2759; // // watch a prefix of literals, such that the slack of these is >= k bool ba_solver::init_watch(pb& p, bool is_true) { @@ -343,7 +344,7 @@ namespace sat { if (j != i) { p.swap(i, j); } - if (slack < bound) { + if (slack <= bound) { slack += p[j].first; ++num_watch; } @@ -353,6 +354,9 @@ namespace sat { ++j; } } + if (p.id() == _bad_id) { + std::cout << "watch " << num_watch << " out of " << sz << "\n"; + } DEBUG_CODE( bool is_false = false; for (unsigned k = 0; k < sz; ++k) { @@ -379,6 +383,8 @@ namespace sat { p.set_slack(slack); p.set_num_watch(num_watch); + validate_watch(p); + TRACE("sat", display(tout << "init watch: ", p, true);); // slack is tight: @@ -424,7 +430,6 @@ namespace sat { } } - static unsigned _bad_id = 62390000; #define BADLOG(_cmd_) if (p.id() == _bad_id) { _cmd_; } @@ -462,13 +467,17 @@ namespace sat { } if (index == num_watch) { _bad_id = p.id(); - std::cout << p.id() << "\n"; + std::cout << "BAD: " << p.id() << "\n"; display(std::cout, p, true); std::cout << "alit: " << alit << "\n"; std::cout << "num watch " << num_watch << "\n"; + exit(0); return l_undef; } + validate_watch(p); + + SASSERT(index < num_watch); unsigned index1 = index + 1; for (; m_a_max == 0 && index1 < num_watch; ++index1) { @@ -485,6 +494,9 @@ namespace sat { literal lit = p[j].second; if (value(lit) != l_false) { slack += p[j].first; + if (is_watched(p[j].second, p)) { + std::cout << "Swap literal already watched: " << p[j].second << "\n"; + } watch_literal(p[j], p); p.swap(num_watch, j); add_index(p, num_watch, lit); @@ -501,6 +513,7 @@ namespace sat { slack += val; p.set_slack(slack); p.set_num_watch(num_watch); + validate_watch(p); BADLOG(display(std::cout << "conflict: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); SASSERT(bound <= slack); TRACE("sat", tout << "conflict " << alit << "\n";); @@ -520,8 +533,6 @@ namespace sat { p.set_num_watch(num_watch); p.swap(num_watch, index); - BADLOG(std::cout << "swap watched: " << alit << " watch: " << p.num_watch() << " size: " << p.size() << " slack: " << p.slack() << "\n"); - // // slack >= bound, but slack - w(l) < bound // l must be true. @@ -544,6 +555,8 @@ namespace sat { TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + BADLOG(std::cout << "unwatch " << alit << " watch: " << p.num_watch() << " size: " << p.size() << " slack: " << p.slack() << " " << inconsistent() << "\n"); + return l_undef; } @@ -552,7 +565,12 @@ namespace sat { } void ba_solver::clear_watch(pb& p) { - for (wliteral wl : p) unwatch_literal(wl.second, p); + validate_watch(p); + for (unsigned i = 0; i < p.num_watch(); ++i) { + unwatch_literal(p[i].second, p); + } + p.set_num_watch(0); + validate_watch(p); } /* @@ -583,6 +601,7 @@ namespace sat { void ba_solver::simplify2(pb& p) { return; + if (p.is_cardinality()) { literal_vector lits(p.literals()); unsigned k = (p.k() + p[0].first - 1) / p[0].first; @@ -605,11 +624,12 @@ namespace sat { void ba_solver::simplify(pb_base& p) { if (p.lit() != null_literal && value(p.lit()) == l_false) { TRACE("sat", tout << "pb: flip sign " << p << "\n";); - IF_VERBOSE(0, verbose_stream() << "signed is flipped " << p << "\n";); + IF_VERBOSE(0, verbose_stream() << "sign is flipped " << p << "\n";); return; init_watch(p, !p.lit().sign()); } - if (p.lit() != null_literal && value(p.lit()) == l_true) { + bool nullify = p.lit() != null_literal && value(p.lit()) == l_true; + if (nullify) { SASSERT(lvl(p.lit()) == 0); nullify_tracking_literal(p); } @@ -625,7 +645,9 @@ namespace sat { } } if (true_val == 0 && num_false == 0) { - // no op + if (nullify) { + init_watch(p, true); + } } else if (true_val >= p.k()) { if (p.lit() != null_literal) { @@ -658,8 +680,10 @@ namespace sat { --i; } } + if (p.id() == _bad_id) display(std::cout << "simplify ", p, true); p.set_size(sz); p.set_k(p.k() - true_val); + if (p.id() == _bad_id) display(std::cout << "simplified ", p, true); // display(verbose_stream(), c, true); if (p.lit() == null_literal) { init_watch(p, true); @@ -1307,6 +1331,7 @@ namespace sat { } ba_solver::card& ba_solver::add_at_least(literal lit, literal_vector const& lits, unsigned k, bool learned) { + if (k == 1) UNREACHABLE(); void * mem = m_allocator.allocate(card::get_obj_size(lits.size())); card* c = new (mem) card(next_id(), lit, lits, k); c->set_learned(learned); @@ -1326,7 +1351,7 @@ namespace sat { m_constraints.push_back(c); } literal lit = c->lit(); - if (c->learned()) { + if (c->learned() && !s().at_base_lvl()) { SASSERT(lit == null_literal); // gets initialized after backjump. m_constraint_to_reinit.push_back(c); @@ -1402,7 +1427,7 @@ namespace sat { return true; } else if (c.lit() != null_literal && value(c.lit()) != l_true) { - return false; + return true; } else { return l_undef != add_assign(c, ~l); @@ -1632,12 +1657,26 @@ namespace sat { void ba_solver::get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) { get_antecedents(l, index2constraint(idx), r); } + + bool ba_solver::is_watched(literal lit, constraint const& c) const { + return get_wlist(~lit).contains(watched(c.index())); + } void ba_solver::unwatch_literal(literal lit, constraint& c) { + if (c.id() == _bad_id) { std::cout << "unwatch " << lit << "\n"; } get_wlist(~lit).erase(watched(c.index())); + if (is_watched(lit, c)) { + std::cout << "Not deleted " << lit << "\n"; + } } void ba_solver::watch_literal(literal lit, constraint& c) { + if (is_watched(lit, c)) { + std::cout << "Already watched " << lit << "\n"; + UNREACHABLE(); + exit(0); + } + if (c.id() == _bad_id) { std::cout << "watch " << lit << "\n"; } get_wlist(~lit).push_back(watched(c.index())); } @@ -1757,11 +1796,18 @@ namespace sat { } void ba_solver::validate() { - if (validate_watch_literals()) { - for (constraint* c : m_constraints) { - if (!validate_watched_constraint(*c)) break; - } + if (!validate_watch_literals()) { + return; } + for (constraint* c : m_constraints) { + if (!validate_watched_constraint(*c)) + return; + } + for (constraint* c : m_learned) { + if (!validate_watched_constraint(*c)) + return; + } + } bool ba_solver::validate_watch_literals() const { @@ -1791,9 +1837,12 @@ namespace sat { } bool ba_solver::validate_watched_constraint(constraint const& c) const { + if (c.is_pb() && !validate_watch(c.to_pb())) { + return false; + } if (c.lit() != null_literal && value(c.lit()) != l_true) return true; if (c.lit() != null_literal && lvl(c.lit()) != 0) { - if (!is_watching(c.lit(), c) || !is_watching(~c.lit(), c)) { + if (!is_watched(c.lit(), c) || !is_watched(~c.lit(), c)) { std::cout << "Definition literal is not watched " << c.lit() << " " << c << "\n"; display_watch_list(std::cout, s().m_cls_allocator, get_wlist(c.lit())) << "\n"; display_watch_list(std::cout, s().m_cls_allocator, get_wlist(~c.lit())) << "\n"; @@ -1806,9 +1855,10 @@ namespace sat { literal_vector lits(c.literals()); for (literal l : lits) { if (lvl(l) == 0) continue; - bool found = is_watching(l, c); + bool found = is_watched(l, c); if (found != c.is_watching(l)) { - std::cout << "Discrepancy of watched literal: " << l << ": " << c.id() << " " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n"; + + std::cout << "Discrepancy of watched literal: " << l << " id: " << c.id() << " clause: " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n"; display_watch_list(std::cout << l << ": ", s().m_cls_allocator, get_wlist(l)) << "\n"; display_watch_list(std::cout << ~l << ": ", s().m_cls_allocator, get_wlist(~l)) << "\n"; std::cout << "value: " << value(l) << " level: " << lvl(l) << "\n"; @@ -1821,15 +1871,21 @@ namespace sat { } return true; } - - bool ba_solver::is_watching(literal lit, constraint const& c) const { - for (auto w : get_wlist(~lit)) { - if (w.get_kind() == watched::EXT_CONSTRAINT && w.get_ext_constraint_idx() == c.index()) - return true; + + bool ba_solver::validate_watch(pb const& p) const { + for (unsigned i = 0; i < p.size(); ++i) { + literal l = p[i].second; + if (lvl(l) != 0 && is_watched(l, p) != i < p.num_watch()) { + std::cout << "DISCREPANCY: " << l << " at " << i << " for " << p.num_watch() << " index: " << p.id() << "\n"; + display(std::cout, p, true); + UNREACHABLE(); + return false; + } } - return false; + return true; } + /** \brief Lex on (glue, size) */ @@ -1844,7 +1900,7 @@ namespace sat { void ba_solver::gc() { std::stable_sort(m_learned.begin(), m_learned.end(), constraint_glue_lt()); gc_half("glue"); - cleanup_constraints(m_learned); + cleanup_constraints(m_learned, true); } void ba_solver::gc_half(char const* st_name) { @@ -1942,7 +1998,7 @@ namespace sat { // if (sz < m_constraint_to_reinit.size()) std::cout << "REINIT " << s().scope_lvl() << " " << m_constraint_to_reinit.size() - sz << "\n"; for (unsigned i = sz; i < m_constraint_to_reinit.size(); ++i) { constraint* c = m_constraint_to_reinit[i]; - if (!init_watch(*c, true)) { + if (!init_watch(*c, true) && !s().at_base_lvl()) { m_constraint_to_reinit[sz++] = c; } } @@ -2145,6 +2201,9 @@ namespace sat { for (constraint* c : m_constraints) { flush_roots(*c); } + for (constraint* c : m_learned) { + flush_roots(*c); + } cleanup_constraints(); // validate(); @@ -2170,6 +2229,7 @@ namespace sat { } void ba_solver::recompile(card& c) { + if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; // IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); m_weights.resize(2*s().num_vars(), 0); for (literal l : c) { @@ -2220,8 +2280,15 @@ namespace sat { return; } + if (k == 1) { + literal_vector lits(c.size(), c.begin()); + s().mk_clause(lits.size(), lits.c_ptr(), c.learned()); + remove_constraint(c); + return; + } + c.set_size(sz); - c.set_k(k); + c.set_k(k); if (!is_card) { TRACE("sat", tout << "replacing by pb: " << c << "\n";); @@ -2236,16 +2303,125 @@ namespace sat { } else { // IF_VERBOSE(1, verbose_stream() << "new: " << c << "\n";); + if (c.id() == _bad_id) std::cout << "init: " << c << "\n"; if (c.lit() == null_literal || value(c.lit()) == l_true) { init_watch(c, true); } SASSERT(c.well_formed()); + } + } + + + void ba_solver::split_root(constraint& c) { + switch (c.tag()) { + case card_t: split_root(c.to_card()); break; + case pb_t: split_root(c.to_pb()); break; + case xor_t: NOT_IMPLEMENTED_YET(); break; } + } + + /* + \brief slit PB constraint into two because root is reused in arguments. + + x <=> a*x + B*y >= k + + x => a*x + By >= k + ~x => a*x + By < k + + k*~x + a*x + By >= k + (B+a-k + 1)*x + a*~x + B*~y >= B + a - k + 1 + + (k - a) * ~x + By >= k - a + k' * x + B'y >= k' + + */ + + void ba_solver::split_root(pb_base& p) { + SASSERT(p.lit() != null_literal); + SASSERT(!p.learned()); + m_weights.resize(2*s().num_vars(), 0); + unsigned k = p.k(); + unsigned w, w1, w2; + literal root = p.lit(); + m_weights[(~root).index()] = k; + for (unsigned i = 0; i < p.size(); ++i) { + literal l = p.get_lit(i); + m_weights[l.index()] += p.get_coeff(i); + } + for (unsigned i = 0; i < p.size(); ++i) { + literal l = p.get_lit(i); + w1 = m_weights[l.index()]; + w2 = m_weights[(~l).index()]; + if (w1 > w2) { + if (w2 > k) { + // constraint is true + return; + } + k -= w2; + m_weights[(~l).index()] = 0; + m_weights[l.index()] = w1 - w2; + } + } + w1 = m_weights[(~root).index()]; + w2 = m_weights[root.index()]; + if (w1 > w2) { + if (w2 > k) { + return; + } + k -= w2; + m_weights[(~root).index()] = 0; + m_weights[root.index()] = w1 - w2; + } + if (k == 0) { + return; + } + // ~root * (k - a) + p >= k - a + + svector wlits; + bool units = true; + for (unsigned i = 0; i < p.size(); ++i) { + literal l = p.get_lit(i); + w = m_weights[l.index()]; + if (w != 0) { + wlits.push_back(wliteral(w, l)); + units &= w == 1; + } + m_weights[l.index()] = 0; + } + w = m_weights[(~root).index()]; + if (w != 0) { + wlits.push_back(wliteral(w, ~root)); + units &= w == 1; + } + m_weights[(~root).index()] = 0; + + for (wliteral wl : wlits) { + std::cout << wl.first << " * " << wl.second << " "; + } + std::cout << " >= " << k << "\n"; + if (k == 1) { + std::cout << "CLAUSE\n"; + } + if (units) { + literal_vector lits; + for (wliteral wl : wlits) lits.push_back(wl.second); + add_at_least(null_literal, lits, k, false); + } + else { + add_pb_ge(null_literal, wlits, k, false); + } + + DEBUG_CODE( + for (unsigned i = 0; i < p.size(); ++i) { + SASSERT(m_weights[p.get_lit(i).index()] == 0); + }); + SASSERT(m_weights[(~root).index()] == 0); } void ba_solver::recompile(pb& p) { // IF_VERBOSE(2, verbose_stream() << "re: " << p << "\n";); + SASSERT(p.num_watch() == 0); m_weights.resize(2*s().num_vars(), 0); for (wliteral wl : p) { m_weights[wl.second.index()] += wl.first; @@ -2296,8 +2472,13 @@ namespace sat { p.set_k(k); SASSERT(p.well_formed()); + if (p.id() == _bad_id) { + display(std::cout << "recompile: ", p, true); + } + IF_VERBOSE(20, verbose_stream() << "new: " << p << "\n";); + // this could become a cardinality constraint by now. if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p, true); } @@ -2316,15 +2497,17 @@ namespace sat { c.set_lit(i, m_roots[c.get_lit(i).index()]); } + literal root = null_literal; if (c.lit() != null_literal && m_roots[c.lit().index()] != c.lit()) { - literal r = m_roots[c.lit().index()]; + root = m_roots[c.lit().index()]; nullify_tracking_literal(c); - c.update_literal(r); - get_wlist(r).push_back(c.index()); - get_wlist(~r).push_back(c.index()); + c.update_literal(root); + get_wlist(root).push_back(c.index()); + get_wlist(~root).push_back(c.index()); } bool found_dup = false; + bool found_root = false; for (unsigned i = 0; i < c.size(); ++i) { literal l = c.get_lit(i); if (is_marked(l)) { @@ -2340,18 +2523,27 @@ namespace sat { literal l = c.get_lit(i); unmark_visited(l); unmark_visited(~l); + found_root |= l.var() == root.var(); } - if (found_dup) { - // std::cout << "FOUND DUP " << p << "\n"; + if (found_root) { + display(std::cout << "the root was found within the list of literals " << c.id() << "\n", c, true); + split_root(c); + c.negate(); + split_root(c); + remove_constraint(c); + } + else if (found_dup) { + if (c.id() == _bad_id) { std::cout << "FOUND DUP " << c << "\n"; } recompile(c); - return; } - // review for potential incompleteness: if c.lit() == l_false, do propagations happen? - if (c.lit() == null_literal || value(c.lit()) == l_true) { - init_watch(c, true); + else { + // review for potential incompleteness: if c.lit() == l_false, do propagations happen? + if (c.lit() == null_literal || value(c.lit()) == l_true) { + init_watch(c, true); + } + SASSERT(c.well_formed()); } - SASSERT(c.well_formed()); } unsigned ba_solver::get_num_non_learned_bin(literal l) { @@ -2480,22 +2672,24 @@ namespace sat { unsigned bin_sub = m_stats.m_num_bin_subsumes; unsigned clause_sub = m_stats.m_num_clause_subsumes; unsigned card_sub = m_stats.m_num_card_subsumes; - for (constraint* cp : m_constraints) { - if (cp->was_removed()) continue; - switch (cp->tag()) { - case card_t: { - card& c = cp->to_card(); - if (c.k() > 1) subsumption(c); - break; - } - default: - break; - } - } + for (constraint* c : m_constraints) subsumption(*c); + for (constraint* c : m_learned) subsumption(*c); IF_VERBOSE(1, verbose_stream() << "binary subsumes: " << m_stats.m_num_bin_subsumes - bin_sub << "\n";); IF_VERBOSE(1, verbose_stream() << "clause subsumes: " << m_stats.m_num_clause_subsumes - clause_sub << "\n";); IF_VERBOSE(1, verbose_stream() << "card subsumes: " << m_stats.m_num_card_subsumes - card_sub << "\n";); + } + void ba_solver::subsumption(constraint& cnstr) { + if (cnstr.was_removed()) return; + switch (cnstr.tag()) { + case card_t: { + card& c = cnstr.to_card(); + if (c.k() > 1) subsumption(c); + break; + } + default: + break; + } } void ba_solver::cleanup_clauses() { @@ -2524,12 +2718,12 @@ namespace sat { void ba_solver::cleanup_constraints() { if (!m_constraint_removed) return; - cleanup_constraints(m_constraints); - cleanup_constraints(m_learned); + cleanup_constraints(m_constraints, false); + cleanup_constraints(m_learned, true); m_constraint_removed = false; } - void ba_solver::cleanup_constraints(ptr_vector& cs) { + void ba_solver::cleanup_constraints(ptr_vector& cs, bool learned) { ptr_vector::iterator it = cs.begin(); ptr_vector::iterator it2 = it; ptr_vector::iterator end = cs.end(); @@ -2538,6 +2732,9 @@ namespace sat { if (c.was_removed()) { m_allocator.deallocate(c.obj_size(), &c); } + else if (learned && !c.learned()) { + m_constraints.push_back(&c); + } else { if (it != it2) { *it2 = *it; @@ -2629,6 +2826,7 @@ namespace sat { TRACE("sat", tout << "subsume cardinality\n" << c1.index() << ":" << c1 << "\n" << c2.index() << ":" << c2 << "\n";); remove_constraint(c2); ++m_stats.m_num_card_subsumes; + c1.set_learned(false); } else { TRACE("sat", tout << "self subsume cardinality\n";); @@ -2664,6 +2862,7 @@ namespace sat { TRACE("sat", tout << "remove\n" << c1 << "\n" << c2 << "\n";); removed_clauses.push_back(&c2); ++m_stats.m_num_clause_subsumes; + c1.set_learned(false); } else { IF_VERBOSE(0, verbose_stream() << "self-subsume clause is TBD\n";); @@ -2688,6 +2887,9 @@ namespace sat { if (w.is_binary_clause() && is_marked(w.get_literal())) { ++m_stats.m_num_bin_subsumes; // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); + if (!w.is_binary_non_learned_clause()) { + c1.set_learned(false); + } } else { if (it != it2) { @@ -2868,6 +3070,12 @@ namespace sat { for (constraint const* c : m_constraints) { out << (*c) << "\n"; } + if (!m_learned.empty()) { + out << "learned:\n"; + } + for (constraint const* c : m_learned) { + out << (*c) << "\n"; + } return out; } @@ -2985,16 +3193,14 @@ namespace sat { } if (sum >= UINT_MAX/2) return 0; if (all_one) { - card& c = add_at_least(null_literal, lits, m_bound, true); - return &c; + return &add_at_least(null_literal, lits, m_bound, true); } else { svector wlits; for (unsigned i = 0; i < lits.size(); ++i) { wlits.push_back(wliteral(coeffs[i], lits[i])); } - pb& p = add_pb_ge(null_literal, wlits, m_bound, true); - return &p; + return &add_pb_ge(null_literal, wlits, m_bound, true); } } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index b8978b254..faa851865 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -98,6 +98,7 @@ namespace sat { virtual literal get_lit(unsigned i) const { UNREACHABLE(); return null_literal; } virtual void set_lit(unsigned i, literal l) { UNREACHABLE(); } virtual bool well_formed() const { return true; } + virtual void negate() { UNREACHABLE(); } }; friend std::ostream& operator<<(std::ostream& out, constraint const& c); @@ -123,7 +124,7 @@ namespace sat { literal& operator[](unsigned i) { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return static_cast(m_lits) + m_size; } - void negate(); + virtual void negate(); virtual void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } virtual literal_vector literals() const { return literal_vector(m_size, m_lits); } virtual bool is_watching(literal l) const; @@ -156,7 +157,7 @@ namespace sat { unsigned max_sum() const { return m_max_sum; } void set_num_watch(unsigned s) { m_num_watch = s; } bool is_cardinality() const; - void negate(); + virtual void negate(); virtual void set_k(unsigned k) { m_k = k; update_max_sum(); } virtual void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } virtual literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } @@ -174,7 +175,7 @@ namespace sat { literal operator[](unsigned i) const { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return begin() + m_size; } - void negate() { m_lits[0].neg(); } + virtual void negate() { m_lits[0].neg(); } virtual void swap(unsigned i, unsigned j) { std::swap(m_lits[i], m_lits[j]); } virtual bool is_watching(literal l) const; virtual literal_vector literals() const { return literal_vector(size(), begin()); } @@ -257,6 +258,7 @@ namespace sat { unsigned elim_pure(); bool elim_pure(literal lit); void subsumption(); + void subsumption(constraint& c1); void subsumption(card& c1); void gc_half(char const* _method); void mutex_reduction(); @@ -270,7 +272,7 @@ namespace sat { void cleanup_clauses(); void cleanup_constraints(); - void cleanup_constraints(ptr_vector& cs); + void cleanup_constraints(ptr_vector& cs, bool learned); void remove_constraint(constraint& c); // constraints @@ -279,6 +281,7 @@ namespace sat { void unwatch_literal(literal w, constraint& c); void watch_literal(literal w, constraint& c); void watch_literal(wliteral w, pb& p); + bool is_watched(literal l, constraint const& c) const; void add_constraint(constraint* c); bool init_watch(constraint& c, bool is_true); void init_watch(bool_var v); @@ -298,6 +301,7 @@ namespace sat { void assert_unconstrained(literal lit, literal_vector const& lits); void flush_roots(constraint& c); void recompile(constraint& c); + void split_root(constraint& c); unsigned next_id() { return m_constraint_id++; } @@ -330,6 +334,7 @@ namespace sat { void add_index(pb& p, unsigned index, literal lit); void clear_watch(pb& p); void get_antecedents(literal l, pb const& p, literal_vector & r); + void split_root(pb_base& p); void simplify(pb_base& p); void simplify2(pb& p); bool is_cardinality(pb const& p); @@ -377,6 +382,7 @@ namespace sat { bool validate_watch_literals() const; bool validate_watch_literal(literal lit) const; bool validate_watched_constraint(constraint const& c) const; + bool validate_watch(pb const& p) const; bool is_watching(literal lit, constraint const& c) const; ineq m_A, m_B, m_C; diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index f54ee9f89..25d558e68 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -96,10 +96,8 @@ namespace sat { cache_bins(l, old_tr_sz); s.pop(1); - literal_vector::iterator it = m_to_assert.begin(); - literal_vector::iterator end = m_to_assert.end(); - for (; it != end; ++it) { - s.assign(*it, justification()); + for (literal l : m_to_assert) { + s.assign(l, justification()); m_num_assigned++; } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 15737d65b..2f7b6afe6 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1406,22 +1406,29 @@ namespace sat { SASSERT(at_base_lvl()); + m_cleaner(); CASSERT("sat_simplify_bug", check_invariant()); m_scc(); CASSERT("sat_simplify_bug", check_invariant()); + m_ext->validate(); + m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); + m_ext->validate(); + if (!m_learned.empty()) { m_simplifier(true); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); } + m_ext->validate(); + if (m_config.m_lookahead_simplify) { { lookahead lh(*this); @@ -1435,13 +1442,18 @@ namespace sat { } } + sort_watch_lits(); CASSERT("sat_simplify_bug", check_invariant()); + m_ext->validate(); + m_probing(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); + m_ext->validate(); + m_asymm_branch(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); @@ -1900,9 +1912,7 @@ namespace sat { */ unsigned solver::psm(clause const & c) const { unsigned r = 0; - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = c[i]; + for (literal l : c) { if (l.sign()) { if (m_phase[l.var()] == NEG_PHASE) r++; From da263601e646a2b9f9859b8fe761551c3a8ee0d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 5 Jul 2017 19:19:36 -0700 Subject: [PATCH 0188/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 266 +++++++++++++++++++------------------- src/sat/ba_solver.h | 12 +- src/sat/sat_extension.h | 2 +- src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_solver.cpp | 31 +++-- src/sat/sat_solver.h | 1 + 6 files changed, 162 insertions(+), 152 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 465c5c73b..243fe9b10 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -475,9 +475,8 @@ namespace sat { return l_undef; } - validate_watch(p); + SASSERT(validate_watch(p)); - SASSERT(index < num_watch); unsigned index1 = index + 1; for (; m_a_max == 0 && index1 < num_watch; ++index1) { @@ -622,6 +621,7 @@ namespace sat { } void ba_solver::simplify(pb_base& p) { + SASSERT(s().at_base_lvl()); if (p.lit() != null_literal && value(p.lit()) == l_false) { TRACE("sat", tout << "pb: flip sign " << p << "\n";); IF_VERBOSE(0, verbose_stream() << "sign is flipped " << p << "\n";); @@ -638,13 +638,19 @@ namespace sat { unsigned true_val = 0, slack = 0, num_false = 0; for (unsigned i = 0; i < p.size(); ++i) { - switch (value(p.get_lit(i))) { + literal l = p.get_lit(i); + switch (value(l)) { case l_true: true_val += p.get_coeff(i); break; case l_false: ++num_false; break; default: slack += p.get_coeff(i); break; } } - if (true_val == 0 && num_false == 0) { + if (p.k() == 1 && p.lit() == null_literal) { + literal_vector lits(p.literals()); + s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + remove_constraint(p); + } + else if (true_val == 0 && num_false == 0) { if (nullify) { init_watch(p, true); } @@ -674,7 +680,8 @@ namespace sat { unsigned sz = p.size(); clear_watch(p); for (unsigned i = 0; i < sz; ++i) { - if (value(p.get_lit(i)) != l_undef) { + literal l = p.get_lit(i); + if (value(l) != l_undef) { --sz; p.swap(i, sz); --i; @@ -685,7 +692,14 @@ namespace sat { p.set_k(p.k() - true_val); if (p.id() == _bad_id) display(std::cout << "simplified ", p, true); // display(verbose_stream(), c, true); - if (p.lit() == null_literal) { + + if (p.k() == 1 && p.lit() == null_literal) { + literal_vector lits(p.literals()); + s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + remove_constraint(p); + return; + } + else if (p.lit() == null_literal) { init_watch(p, true); } else { @@ -1184,7 +1198,7 @@ namespace sat { } if (slack >= 0) { - IF_VERBOSE(2, verbose_stream() << "(sat.card slack: " << slack << " skipped: " << num_skipped << ")\n";); + IF_VERBOSE(20, verbose_stream() << "(sat.card slack: " << slack << " skipped: " << num_skipped << ")\n";); return false; } @@ -1199,7 +1213,7 @@ namespace sat { for (unsigned i = 1; i < m_lemma.size(); ++i) { m_conflict_lvl = std::max(m_conflict_lvl, lvl(m_lemma[i])); } - IF_VERBOSE(1, verbose_stream() << "(sat-backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); + IF_VERBOSE(10, verbose_stream() << "(sat.backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); goto adjust_conflict_level; } @@ -1253,16 +1267,17 @@ namespace sat { } if (g >= 2) { active2pb(m_A); - display(std::cout, m_A, true); + //display(std::cout, m_A, true); normalize_active_coeffs(); int ig = static_cast(g); for (unsigned i = 0; i < m_active_vars.size(); ++i) { m_coeffs[m_active_vars[i]] /= ig; } m_bound = (m_bound + g - 1) / g; - std::cout << "CUT " << g << "\n"; - active2pb(m_A); - display(std::cout, m_A, true); + ++m_stats.m_num_cut; + //std::cout << "CUT " << g << "\n"; + //active2pb(m_A); + //display(std::cout, m_A, true); } } @@ -1330,13 +1345,17 @@ namespace sat { add_at_least(lit, lits, k, false); } - ba_solver::card& ba_solver::add_at_least(literal lit, literal_vector const& lits, unsigned k, bool learned) { - if (k == 1) UNREACHABLE(); + ba_solver::constraint* ba_solver::add_at_least(literal lit, literal_vector const& lits, unsigned k, bool learned) { + if (k == 1 && lit == null_literal) { + literal_vector _lits(lits); + s().mk_clause(_lits.size(), _lits.c_ptr(), learned); + return 0; + } void * mem = m_allocator.allocate(card::get_obj_size(lits.size())); card* c = new (mem) card(next_id(), lit, lits, k); c->set_learned(learned); add_constraint(c); - return *c; + return c; } void ba_solver::add_constraint(constraint* c) { @@ -1389,12 +1408,22 @@ namespace sat { return l_undef; } - ba_solver::pb& ba_solver::add_pb_ge(literal lit, svector const& wlits, unsigned k, bool learned) { + ba_solver::constraint* ba_solver::add_pb_ge(literal lit, svector const& wlits, unsigned k, bool learned) { + bool units = true; + for (wliteral wl : wlits) units &= wl.first == 1; + if (k == 0 && lit == null_literal) { + return 0; + } + if (units || k == 1) { + literal_vector lits; + for (wliteral wl : wlits) lits.push_back(wl.second); + return add_at_least(lit, lits, k, learned); + } void * mem = m_allocator.allocate(pb::get_obj_size(wlits.size())); pb* p = new (mem) pb(next_id(), lit, wlits, k); p->set_learned(learned); add_constraint(p); - return *p; + return p; } void ba_solver::add_pb_ge(bool_var v, svector const& wlits, unsigned k) { @@ -1406,13 +1435,13 @@ namespace sat { add_xor(literal(v, false), lits, false); } - ba_solver::xor& ba_solver::add_xor(literal lit, literal_vector const& lits, bool learned) { + ba_solver::constraint* ba_solver::add_xor(literal lit, literal_vector const& lits, bool learned) { void * mem = m_allocator.allocate(xor::get_obj_size(lits.size())); xor* x = new (mem) xor(next_id(), lit, lits); x->set_learned(learned); add_constraint(x); for (literal l : lits) s().set_external(l.var()); // TBD: determine if goal2sat does this. - return *x; + return x; } /* @@ -1503,13 +1532,9 @@ namespace sat { unsigned n = get_parity(v); if (n > 0) { reset_parity(v); - if (n > 1) { - IF_VERBOSE(2, verbose_stream() << "parity greater than 1: " << l << " " << n << "\n";); - } if (n % 2 == 1) { break; } - IF_VERBOSE(2, verbose_stream() << "skip even parity: " << l << "\n";); --num_marks; } --index; @@ -1530,7 +1555,7 @@ namespace sat { r.push_back(lit); } else { - IF_VERBOSE(2, verbose_stream() << "skip even parity: " << lit << "\n";); + // IF_VERBOSE(2, verbose_stream() << "skip even parity: " << lit << "\n";); } reset_parity(lit.var()); } @@ -1795,19 +1820,19 @@ namespace sat { return odd ? l_true : l_false; } - void ba_solver::validate() { + bool ba_solver::validate() { if (!validate_watch_literals()) { - return; + return false; } for (constraint* c : m_constraints) { if (!validate_watched_constraint(*c)) - return; + return false; } for (constraint* c : m_learned) { if (!validate_watched_constraint(*c)) - return; + return false; } - + return true; } bool ba_solver::validate_watch_literals() const { @@ -1826,8 +1851,7 @@ namespace sat { if (w.get_kind() == watched::EXT_CONSTRAINT) { constraint const& c = index2constraint(w.get_ext_constraint_idx()); if (!c.is_watching(~lit) && lit.var() != c.lit().var()) { - std::cout << lit << " " << lvl(lit) << " is not watched in " << c << "\n"; - display(std::cout, c, true); + IF_VERBOSE(0, display(verbose_stream() << lit << " " << lvl(lit) << " is not watched in " << c << "\n", c, true);); UNREACHABLE(); return false; } @@ -1907,12 +1931,17 @@ namespace sat { TRACE("sat", tout << "gc\n";); unsigned sz = m_learned.size(); unsigned new_sz = sz/2; - unsigned j = new_sz; + unsigned removed = 0; for (unsigned i = new_sz; i < sz; i++) { - remove_constraint(*(m_learned[i])); + constraint* c = m_learned[i]; + if (!m_constraint_to_reinit.contains(c)) { + remove_constraint(*c); + ++removed; + } } - m_learned.shrink(j); - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat-gc :strategy " << st_name << " :deleted " << (sz - j) << ")\n";); + m_stats.m_num_gc += removed; + m_learned.shrink(new_sz); + IF_VERBOSE(2, verbose_stream() << "(sat-gc :strategy " << st_name << " :deleted " << removed << ")\n";); } @@ -1971,6 +2000,13 @@ namespace sat { assign(c, c[i]); } + if (c.learned() && c.glue() > 2) { + unsigned glue; + if (s().num_diff_false_levels_below(c.size(), c.begin(), c.glue()-1, glue)) { + c.set_glue(glue); + } + } + return inconsistent() ? l_false : l_true; } @@ -2005,6 +2041,7 @@ namespace sat { m_constraint_to_reinit.shrink(sz); } + void ba_solver::simplify(constraint& c) { SASSERT(s().at_base_lvl()); switch (c.tag()) { @@ -2027,7 +2064,6 @@ namespace sat { unsigned trail_sz; do { trail_sz = s().init_trail_size(); - IF_VERBOSE(1, verbose_stream() << "(bool-algebra-solver simplify-begin :trail " << trail_sz << " :learned " << m_learned.size() << ")\n";); m_simplify_change = false; m_clause_removed = false; m_constraint_removed = false; @@ -2040,12 +2076,20 @@ namespace sat { subsumption(); cleanup_clauses(); cleanup_constraints(); - IF_VERBOSE(1, verbose_stream() << "(bool-algebra-solver simplify-end :trail " << trail_sz << " :vars " << s().num_vars() - trail_sz << ")\n";); } while (m_simplify_change || trail_sz < s().init_trail_size()); + IF_VERBOSE(1, verbose_stream() << "(ba.simplify :trail " << trail_sz + << " :vars " << s().num_vars() - trail_sz + << " :bin-subsumes " << m_stats.m_num_bin_subsumes + << " :clause-subsumes " << m_stats.m_num_clause_subsumes + << " :card-subsumes " << m_stats.m_num_card_subsumes + << ")\n";); + // mutex_reduction(); // if (s().m_clauses.size() < 80000) lp_lookahead_reduction(); + + // display(std::cout); } void ba_solver::mutex_reduction() { @@ -2236,7 +2280,7 @@ namespace sat { ++m_weights[l.index()]; } unsigned k = c.k(); - bool is_card = true; + bool all_units = true; unsigned sz = c.size(); unsigned_vector coeffs; for (unsigned i = 0; i < sz && 0 < k; ++i) { @@ -2264,7 +2308,7 @@ namespace sat { --i; } else { - is_card &= (w == 1); + all_units &= (w == 1); coeffs.push_back(w); } } @@ -2290,7 +2334,7 @@ namespace sat { c.set_size(sz); c.set_k(k); - if (!is_card) { + if (!all_units) { TRACE("sat", tout << "replacing by pb: " << c << "\n";); svector wlits; for (unsigned i = 0; i < sz; ++i) { @@ -2298,12 +2342,9 @@ namespace sat { } literal root = c.lit(); remove_constraint(c); - pb const& p = add_pb_ge(root, wlits, k, c.learned()); - IF_VERBOSE(1, verbose_stream() << p << "\n";); + constraint* p = add_pb_ge(root, wlits, k, c.learned()); } else { - // IF_VERBOSE(1, verbose_stream() << "new: " << c << "\n";); - if (c.id() == _bad_id) std::cout << "init: " << c << "\n"; if (c.lit() == null_literal || value(c.lit()) == l_true) { init_watch(c, true); } @@ -2345,15 +2386,16 @@ namespace sat { literal root = p.lit(); m_weights[(~root).index()] = k; for (unsigned i = 0; i < p.size(); ++i) { - literal l = p.get_lit(i); - m_weights[l.index()] += p.get_coeff(i); + m_weights[p.get_lit(i).index()] += p.get_coeff(i); } - for (unsigned i = 0; i < p.size(); ++i) { - literal l = p.get_lit(i); + literal_vector lits(p.literals()); + lits.push_back(~root); + + for (literal l : lits) { w1 = m_weights[l.index()]; w2 = m_weights[(~l).index()]; - if (w1 > w2) { - if (w2 > k) { + if (w1 >= w2) { + if (w2 >= k) { // constraint is true return; } @@ -2362,61 +2404,20 @@ namespace sat { m_weights[l.index()] = w1 - w2; } } - w1 = m_weights[(~root).index()]; - w2 = m_weights[root.index()]; - if (w1 > w2) { - if (w2 > k) { - return; - } - k -= w2; - m_weights[(~root).index()] = 0; - m_weights[root.index()] = w1 - w2; - } - if (k == 0) { - return; - } + SASSERT(k > 0); + // ~root * (k - a) + p >= k - a svector wlits; - bool units = true; - for (unsigned i = 0; i < p.size(); ++i) { - literal l = p.get_lit(i); + for (literal l : lits) { w = m_weights[l.index()]; if (w != 0) { wlits.push_back(wliteral(w, l)); - units &= w == 1; } m_weights[l.index()] = 0; } - w = m_weights[(~root).index()]; - if (w != 0) { - wlits.push_back(wliteral(w, ~root)); - units &= w == 1; - } - m_weights[(~root).index()] = 0; - - for (wliteral wl : wlits) { - std::cout << wl.first << " * " << wl.second << " "; - } - std::cout << " >= " << k << "\n"; - if (k == 1) { - std::cout << "CLAUSE\n"; - } - if (units) { - literal_vector lits; - for (wliteral wl : wlits) lits.push_back(wl.second); - add_at_least(null_literal, lits, k, false); - } - else { - add_pb_ge(null_literal, wlits, k, false); - } - - DEBUG_CODE( - for (unsigned i = 0; i < p.size(); ++i) { - SASSERT(m_weights[p.get_lit(i).index()] == 0); - }); - SASSERT(m_weights[(~root).index()] == 0); + add_pb_ge(null_literal, wlits, k, false); } void ba_solver::recompile(pb& p) { @@ -2428,6 +2429,7 @@ namespace sat { } unsigned k = p.k(); unsigned sz = p.size(); + bool all_units = true; for (unsigned i = 0; i < sz && 0 < k; ++i) { literal l = p[i].second; unsigned w1 = m_weights[l.index()]; @@ -2454,6 +2456,7 @@ namespace sat { } else { p[i] = wliteral(w1, l); + all_units &= w1 == 1; } } } @@ -2464,6 +2467,23 @@ namespace sat { } if (k == 0) { + if (p.lit() != null_literal) { + s().assign(p.lit(), justification()); + } + remove_constraint(p); + return; + } + + if (k == 1 && p.lit() == null_literal) { + literal_vector lits(p.literals()); + s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + remove_constraint(p); + return; + } + + if (all_units) { + literal_vector lits(p.literals()); + add_at_least(p.lit(), lits, k, p.learned()); remove_constraint(p); return; } @@ -2472,12 +2492,6 @@ namespace sat { p.set_k(k); SASSERT(p.well_formed()); - if (p.id() == _bad_id) { - display(std::cout << "recompile: ", p, true); - } - - IF_VERBOSE(20, verbose_stream() << "new: " << p << "\n";); - // this could become a cardinality constraint by now. if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p, true); @@ -2497,7 +2511,7 @@ namespace sat { c.set_lit(i, m_roots[c.get_lit(i).index()]); } - literal root = null_literal; + literal root = c.lit(); if (c.lit() != null_literal && m_roots[c.lit().index()] != c.lit()) { root = m_roots[c.lit().index()]; nullify_tracking_literal(c); @@ -2527,14 +2541,12 @@ namespace sat { } if (found_root) { - display(std::cout << "the root was found within the list of literals " << c.id() << "\n", c, true); split_root(c); c.negate(); split_root(c); remove_constraint(c); } else if (found_dup) { - if (c.id() == _bad_id) { std::cout << "FOUND DUP " << c << "\n"; } recompile(c); } else { @@ -2669,14 +2681,8 @@ namespace sat { } void ba_solver::subsumption() { - unsigned bin_sub = m_stats.m_num_bin_subsumes; - unsigned clause_sub = m_stats.m_num_clause_subsumes; - unsigned card_sub = m_stats.m_num_card_subsumes; for (constraint* c : m_constraints) subsumption(*c); for (constraint* c : m_learned) subsumption(*c); - IF_VERBOSE(1, verbose_stream() << "binary subsumes: " << m_stats.m_num_bin_subsumes - bin_sub << "\n";); - IF_VERBOSE(1, verbose_stream() << "clause subsumes: " << m_stats.m_num_clause_subsumes - clause_sub << "\n";); - IF_VERBOSE(1, verbose_stream() << "card subsumes: " << m_stats.m_num_card_subsumes - card_sub << "\n";); } void ba_solver::subsumption(constraint& cnstr) { @@ -3087,6 +3093,8 @@ namespace sat { st.update("ba propagations", m_stats.m_num_propagations); st.update("ba conflicts", m_stats.m_num_conflicts); st.update("ba resolves", m_stats.m_num_resolves); + st.update("ba cuts", m_stats.m_num_cut); + st.update("ba gc", m_stats.m_num_gc); } bool ba_solver::validate_unit_propagation(card const& c, literal alit) const { @@ -3193,14 +3201,14 @@ namespace sat { } if (sum >= UINT_MAX/2) return 0; if (all_one) { - return &add_at_least(null_literal, lits, m_bound, true); + return add_at_least(null_literal, lits, m_bound, true); } else { svector wlits; for (unsigned i = 0; i < lits.size(); ++i) { wlits.push_back(wliteral(coeffs[i], lits[i])); } - return &add_pb_ge(null_literal, wlits, m_bound, true); + return add_pb_ge(null_literal, wlits, m_bound, true); } } @@ -3235,7 +3243,7 @@ namespace sat { }; - ba_solver::card* ba_solver::active2card() { + ba_solver::constraint* ba_solver::active2card() { normalize_active_coeffs(); svector wlits; for (bool_var v : m_active_vars) { @@ -3281,33 +3289,21 @@ namespace sat { return 0; } - -#if 0 - std::cout << "card: "; - for (wliteral wl : wlits) std::cout << wl.second << " "; - std::cout << ">= " << k << "\n"; - - if (num_max_level > 1) { - std::cout << "max level " << num_max_level << "\n"; - } - - - if (wlits.size() < m_active_vars.size()) std::cout << "REMOVED " << m_active_vars.size() - wlits.size() << "\n"; -#endif - // produce asserting cardinality constraint literal_vector lits; for (wliteral wl : wlits) lits.push_back(wl.second); - card& c = add_at_least(null_literal, lits, k, true); + constraint* c = add_at_least(null_literal, lits, k, true); - lits.reset(); - for (wliteral wl : wlits) { - if (value(wl.second) == l_false) lits.push_back(wl.second); + if (c) { + lits.reset(); + for (wliteral wl : wlits) { + if (value(wl.second) == l_false) lits.push_back(wl.second); + } + unsigned glue = s().num_diff_levels(lits.size(), lits.c_ptr()); + + c->set_glue(glue); } - unsigned glue = s().num_diff_levels(lits.size(), lits.c_ptr()); - - c.set_glue(glue); - return &c; + return c; } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index faa851865..115b57fed 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -39,6 +39,8 @@ namespace sat { unsigned m_num_bin_subsumes; unsigned m_num_clause_subsumes; unsigned m_num_card_subsumes; + unsigned m_num_cut; + unsigned m_num_gc; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -388,7 +390,7 @@ namespace sat { ineq m_A, m_B, m_C; void active2pb(ineq& p); constraint* active2constraint(); - card* active2card(); + constraint* active2card(); void justification2pb(justification const& j, literal lit, unsigned offset, ineq& p); bool validate_resolvent(); @@ -398,9 +400,9 @@ namespace sat { void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xor const& c, bool values) const; - card& add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned); - pb& add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); - xor& add_xor(literal l, literal_vector const& lits, bool learned); + constraint* add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned); + constraint* add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); + constraint* add_xor(literal l, literal_vector const& lits, bool learned); public: ba_solver(); @@ -433,7 +435,7 @@ namespace sat { ptr_vector const & constraints() const { return m_constraints; } - virtual void validate(); + virtual bool validate(); }; diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 4c052494a..a61c330c7 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -54,7 +54,7 @@ namespace sat { virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; virtual void gc() = 0; virtual void pop_reinit() = 0; - virtual void validate() = 0; + virtual bool validate() = 0; }; }; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 6c40c93fd..5dadd0b73 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -887,7 +887,7 @@ namespace sat { // enable when there is a non-ternary reward system. if (c.size() > 3) { m_config.m_use_ternary_reward = false; - } + } #endif bool was_eliminated = false; for (unsigned i = 0; !was_eliminated && i < c.size(); ++i) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2f7b6afe6..85b1d7e50 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1406,28 +1406,22 @@ namespace sat { SASSERT(at_base_lvl()); - m_cleaner(); CASSERT("sat_simplify_bug", check_invariant()); m_scc(); CASSERT("sat_simplify_bug", check_invariant()); - m_ext->validate(); - m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); - m_ext->validate(); - if (!m_learned.empty()) { m_simplifier(true); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); } - m_ext->validate(); if (m_config.m_lookahead_simplify) { { @@ -1446,14 +1440,10 @@ namespace sat { sort_watch_lits(); CASSERT("sat_simplify_bug", check_invariant()); - m_ext->validate(); - m_probing(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); - m_ext->validate(); - m_asymm_branch(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); @@ -2398,6 +2388,26 @@ namespace sat { return glue < max_glue; } + bool solver::num_diff_false_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue) { + m_diff_levels.reserve(scope_lvl() + 1, false); + glue = 0; + unsigned i = 0; + for (; i < num && glue < max_glue; i++) { + if (value(lits[i]) == l_false) { + unsigned lit_lvl = lvl(lits[i]); + if (m_diff_levels[lit_lvl] == false) { + m_diff_levels[lit_lvl] = true; + glue++; + } + } + } + num = i; + // reset m_diff_levels. + for (i = 0; i < num; i++) + m_diff_levels[lvl(lits[i])] = false; + return glue < max_glue; + } + /** \brief Process an antecedent for lemma minimization. @@ -3100,6 +3110,7 @@ namespace sat { if (!m_rlimit.inc()) return true; integrity_checker checker(*this); SASSERT(checker()); + SASSERT(!m_ext || m_ext->validate()); return true; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 919b0e92a..af0029a08 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -455,6 +455,7 @@ namespace sat { svector m_diff_levels; unsigned num_diff_levels(unsigned num, literal const * lits); bool num_diff_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue); + bool num_diff_false_levels_below(unsigned num, literal const* lits, unsigned max_glue, unsigned& glue); // lemma minimization typedef approx_set_tpl level_approx_set; From 4c23527974aa50d37c49725f1581906400612ecf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jul 2017 08:53:08 -0700 Subject: [PATCH 0189/1283] Dev (#63) * introduce int_solver.h Signed-off-by: Lev Nachmanson * add int_solver class Signed-off-by: Lev Nachmanson * track which var is an integer Signed-off-by: Lev Nachmanson * add queries for integrality of vars Signed-off-by: Lev Nachmanson * resurrect lp_tst in its own director lp Signed-off-by: Lev Nachmanson * add file Signed-off-by: Lev Nachmanson * add_constraint has got a body Signed-off-by: Lev Nachmanson * fix add_constraint and substitute_terms_in_linear_expression Signed-off-by: Lev Nachmanson * after merge with Z3Prover Signed-off-by: Lev Nachmanson * adding stub check_int_feasibility() Signed-off-by: Lev Nachmanson * Dev (#50) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * small fix in lar_solver.cpp Signed-off-by: Lev Nachmanson * adding some content to the new check_int_feasibility() Signed-off-by: Lev Nachmanson * Dev (#51) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * test Signed-off-by: Lev Nachmanson * Dev (#53) * change in a comment Signed-off-by: Lev Nachmanson * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * adding nra Signed-off-by: Nikolaj Bjorner * debugging nra Signed-off-by: Nikolaj Bjorner * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner * n/a Signed-off-by: Nikolaj Bjorner * integrate nlsat Signed-off-by: Nikolaj Bjorner * tidy Signed-off-by: Nikolaj Bjorner * preserve is_int flag Signed-off-by: Lev Nachmanson * remove a debug printout Signed-off-by: Lev Nachmanson * Dev (#54) * change in a comment Signed-off-by: Lev Nachmanson * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * adding nra Signed-off-by: Nikolaj Bjorner * debugging nra Signed-off-by: Nikolaj Bjorner * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner * n/a Signed-off-by: Nikolaj Bjorner * integrate nlsat Signed-off-by: Nikolaj Bjorner * tidy Signed-off-by: Nikolaj Bjorner * use integer test from lra solver, updated it to work on term variables Signed-off-by: Nikolaj Bjorner * fix equality check in assume-eq Signed-off-by: Nikolaj Bjorner * fix model_is_int_feasible Signed-off-by: Lev Nachmanson * untested gcd_test() Signed-off-by: Lev Nachmanson * call fill_explanation_from_fixed_columns() Signed-off-by: Lev Nachmanson * add the call to pivot_fixed_vars_from_basis() to int_solver.cpp::check() Signed-off-by: Lev Nachmanson * port more of theory_arith_int.h Signed-off-by: Lev Nachmanson * use statistics of lar_solver by theory_lra.cpp Signed-off-by: Lev Nachmanson * port more code to int_solver.cpp Signed-off-by: Lev Nachmanson * add an assert Signed-off-by: Lev Nachmanson * more int porting Signed-off-by: Lev Nachmanson * fix a bug in pivot_fixed_vars_from_basis Signed-off-by: Lev Nachmanson * small change Signed-off-by: Lev Nachmanson * implement find_inf_int_base_column() Signed-off-by: Lev Nachmanson * catch unregistered vars in add_var_bound Signed-off-by: Lev Nachmanson * add a file Signed-off-by: Lev Nachmanson * compile for vs2012 Signed-off-by: Lev Nachmanson * fix asserts in add_var_bound Signed-off-by: Lev Nachmanson * fix the lp_solver init when workig on an mps file Signed-off-by: Lev Nachmanson * towards int_solver::check() Signed-off-by: Lev Nachmanson * change in int_solver::check() signature Signed-off-by: Lev Nachmanson * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * return branch from int_solver::check() Signed-off-by: Lev Nachmanson * add a stub for mk_gomory_cut Signed-off-by: Lev Nachmanson * Dev (#59) * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * Dev (#60) * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * Dev (#61) * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * more TRACE(arith_int) Signed-off-by: Lev Nachmanson * fix the build Signed-off-by: Lev Nachmanson * loops Signed-off-by: Nikolaj Bjorner * Dev (#62) * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * build fix Signed-off-by: Lev Nachmanson --- src/smt/theory_arith_int.h | 6 +- src/smt/theory_lra.cpp | 112 +++++++++++++------ src/util/lp/int_solver.cpp | 224 +++++++++++++++++++++++++++++++++---- src/util/lp/int_solver.h | 2 + src/util/lp/lar_term.h | 4 + 5 files changed, 291 insertions(+), 57 deletions(-) diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index e6e9e863c..ca3a485c6 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -201,10 +201,12 @@ namespace smt { SASSERT(is_int(v)); SASSERT(!get_value(v).is_int()); m_stats.m_branches++; - TRACE("arith_int", tout << "branching v" << v << " = " << get_value(v) << "\n"; - display_var(tout, v);); numeral k = ceil(get_value(v)); rational _k = k.to_rational(); + TRACE("arith_int", tout << "branching v" << v << " = " << get_value(v) << "\n"; + display_var(tout, v); + tout << "k = " << k << ", _k = "<< _k << std::endl; + ); expr_ref bound(get_manager()); expr* e = get_enode(v)->get_owner(); bound = m_util.mk_ge(e, m_util.mk_numeral(_k, m_util.is_int(e))); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index c35dbb94e..43d3820f3 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -54,13 +54,15 @@ namespace lp { class bound { smt::bool_var m_bv; smt::theory_var m_var; + bool m_is_int; rational m_value; bound_kind m_bound_kind; public: - bound(smt::bool_var bv, smt::theory_var v, rational const & val, bound_kind k): + bound(smt::bool_var bv, smt::theory_var v, bool is_int, rational const & val, bound_kind k): m_bv(bv), m_var(v), + m_is_int(is_int), m_value(val), m_bound_kind(k) { } @@ -68,11 +70,18 @@ namespace lp { smt::theory_var get_var() const { return m_var; } smt::bool_var get_bv() const { return m_bv; } bound_kind get_bound_kind() const { return m_bound_kind; } + bool is_int() const { return m_is_int; } rational const& get_value() const { return m_value; } inf_rational get_value(bool is_true) const { if (is_true) return inf_rational(m_value); // v >= value or v <= value - if (m_bound_kind == lower_t) return inf_rational(m_value, false); // v <= value - epsilon - return inf_rational(m_value, true); // v >= value + epsilon + if (m_is_int) { + if (m_bound_kind == lower_t) return inf_rational(m_value - rational::one()); // v <= value - 1 + return inf_rational(m_value + rational::one()); // v >= value + 1 + } + else { + if (m_bound_kind == lower_t) return inf_rational(m_value, false); // v <= value - epsilon + return inf_rational(m_value, true); // v >= value + epsilon + } } virtual std::ostream& display(std::ostream& out) const { return out << "v" << get_var() << " " << get_bound_kind() << " " << m_value; @@ -305,7 +314,6 @@ namespace smt { } } - void found_not_handled(expr* n) { m_not_handled = n; if (is_app(n) && is_underspecified(to_app(n))) { @@ -756,7 +764,7 @@ namespace smt { found_not_handled(atom); return true; } - lp::bound* b = alloc(lp::bound, bv, v, r, k); + lp::bound* b = alloc(lp::bound, bv, v, is_int(v), r, k); m_bounds[v].push_back(b); updt_unassigned_bounds(v, +1); m_bounds_trail.push_back(v); @@ -1211,33 +1219,49 @@ namespace smt { return FC_GIVEUP; } - // create a bound atom representing term >= k - lp::bound* mk_bound(lean::lar_term const& term, rational const& k) { - NOT_IMPLEMENTED_YET(); - lp::bound_kind bkind = lp::bound_kind::lower_t; - bool_var bv = null_bool_var; - theory_var v = null_theory_var; - lp::bound* result = alloc(lp::bound, bv, v, k, bkind); - return result; + // create a bound atom representing term <= k + app_ref mk_bound(lean::lar_term const& term, rational const& k) { + SASSERT(k.is_int()); + app_ref t = mk_term(term, true); + app_ref atom(a.mk_le(t, a.mk_numeral(k, true)), m); + TRACE("arith", tout << atom << "\n"; + m_solver->print_term(term, tout << "bound atom: "); tout << " <= " << k << "\n"; + display(tout); + ); + ctx().internalize(atom, true); + ctx().mark_as_relevant(atom.get()); + return atom; } lbool check_lia() { - std::cout << "called check_lia()\n"; + if (m.canceled()) return l_undef; lean::lar_term term; lean::mpq k; lean::explanation ex; // TBD, this should be streamlined accross different explanations switch(m_lia->check(term, k, ex)) { case lean::lia_move::ok: return l_true; - case lean::lia_move::branch: + case lean::lia_move::branch: { + (void)mk_bound(term, k); // branch on term <= k - NOT_IMPLEMENTED_YET(); + // at this point we have a new unassigned atom that the + // SAT core assigns a value to return l_false; - case lean::lia_move::cut: + } + case lean::lia_move::cut: { // m_explanation implies term <= k - m_explanation = ex.m_explanation; - NOT_IMPLEMENTED_YET(); + app_ref b = mk_bound(term, k); + m_eqs.reset(); + m_core.reset(); + m_params.reset(); + for (auto const& ev : ex.m_explanation) { + if (!ev.first.is_zero()) { + set_evidence(ev.second); + } + } + assign(literal(ctx().get_bool_var(b), false)); return l_false; + } case lean::lia_move::conflict: // ex contains unsat core m_explanation = ex.m_explanation; @@ -2030,12 +2054,13 @@ namespace smt { st.coeffs().push_back(rational::one()); init_left_side(st); lean::lconstraint_kind k = lean::EQ; + bool is_int = b.is_int(); switch (b.get_bound_kind()) { case lp::lower_t: - k = is_true ? lean::GE : lean::LT; + k = is_true ? lean::GE : (is_int ? lean::LE : lean::LT); break; case lp::upper_t: - k = is_true ? lean::LE : lean::GT; + k = is_true ? lean::LE : (is_int ? lean::GE : lean::GT); break; } if (k == lean::LT || k == lean::LE) { @@ -2045,7 +2070,15 @@ namespace smt { ++m_stats.m_assert_upper; } auto vi = get_var_index(b.get_var()); - auto ci = m_solver->add_var_bound(vi, k, b.get_value()); + rational bound = b.get_value(); + lean::constraint_index ci; + if (is_int && !is_true) { + rational bound = b.get_value(false).get_rational(); + ci = m_solver->add_var_bound(vi, k, bound); + } + else { + ci = m_solver->add_var_bound(vi, k, b.get_value()); + } TRACE("arith", tout << "v" << b.get_var() << "\n";); add_ineq_constraint(ci, literal(bv, !is_true)); @@ -2499,19 +2532,32 @@ namespace smt { return internalize_def(term); } + app_ref mk_term(lean::lar_term const& term, bool is_int) { + expr_ref_vector args(m); + for (auto & ti : term.m_coeffs) { + theory_var w = m_var_index2theory_var[ti.first]; + expr* o = get_enode(w)->get_owner(); + if (ti.second.is_one()) { + args.push_back(o); + } + else { + args.push_back(a.mk_mul(a.mk_numeral(ti.second, is_int), o)); + } + } + if (!term.m_v.is_zero()) { + args.push_back(a.mk_numeral(term.m_v, is_int)); + } + if (args.size() == 1) { + return app_ref(to_app(args[0].get()), m); + } + return app_ref(a.mk_add(args.size(), args.c_ptr()), m); + } + app_ref mk_obj(theory_var v) { lean::var_index vi = m_theory_var2var_index[v]; bool is_int = a.is_int(get_enode(v)->get_owner()); - if (m_solver->is_term(vi)) { - expr_ref_vector args(m); - const lean::lar_term& term = m_solver->get_term(vi); - for (auto & ti : term.m_coeffs) { - theory_var w = m_var_index2theory_var[ti.first]; - expr* o = get_enode(w)->get_owner(); - args.push_back(a.mk_mul(a.mk_numeral(ti.second, is_int), o)); - } - args.push_back(a.mk_numeral(term.m_v, is_int)); - return app_ref(a.mk_add(args.size(), args.c_ptr()), m); + if (m_solver->is_term(vi)) { + return mk_term(m_solver->get_term(vi), is_int); } else { theory_var w = m_var_index2theory_var[vi]; @@ -2537,7 +2583,7 @@ namespace smt { // ctx().set_enode_flag(bv, true); lp::bound_kind bkind = lp::bound_kind::lower_t; if (is_strict) bkind = lp::bound_kind::upper_t; - lp::bound* a = alloc(lp::bound, bv, v, r, bkind); + lp::bound* a = alloc(lp::bound, bv, v, is_int, r, bkind); mk_bound_axioms(*a); updt_unassigned_bounds(v, +1); m_bounds[v].push_back(a); diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index e617a1e29..1a6d6ddae 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -101,6 +101,186 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { } +bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { + lean_assert(false); + return true; + /* + const auto & row = m_lar_solver->A_r().m_rows[row_index]; + // The following assertion is wrong. It may be violated in mixed-integer problems. + // SASSERT(!all_coeff_int(r)); + theory_var x_i = r.get_base_var(); + + SASSERT(is_int(x_i)); + // The following assertion is wrong. It may be violated in mixed-real-interger problems. + // The check is_gomory_cut_target will discard rows where any variable contains infinitesimals. + // SASSERT(m_value[x_i].is_rational()); // infinitesimals are not used for integer variables + SASSERT(!m_value[x_i].is_int()); // the base variable is not assigned to an integer value. + + if (constrain_free_vars(r) || !is_gomory_cut_target(r)) { + TRACE("gomory_cut", tout << "failed to apply gomory cut:\n"; + tout << "constrain_free_vars(r): " << constrain_free_vars(r) << "\n";); + return false; + } + + TRACE("gomory_cut", tout << "applying cut at:\n"; display_row_info(tout, r);); + + antecedents ante(*this); + + m_stats.m_gomory_cuts++; + + // gomory will be pol >= k + numeral k(1); + buffer pol; + + numeral f_0 = Ext::fractional_part(m_value[x_i]); + numeral one_minus_f_0 = numeral(1) - f_0; + SASSERT(!f_0.is_zero()); + SASSERT(!one_minus_f_0.is_zero()); + + numeral lcm_den(1); + unsigned num_ints = 0; + + typename vector::const_iterator it = r.begin_entries(); + typename vector::const_iterator end = r.end_entries(); + for (; it != end; ++it) { + if (!it->is_dead() && it->m_var != x_i) { + theory_var x_j = it->m_var; + numeral a_ij = it->m_coeff; + a_ij.neg(); // make the used format compatible with the format used in: Integrating Simplex with DPLL(T) + if (is_real(x_j)) { + numeral new_a_ij; + if (at_lower(x_j)) { + if (a_ij.is_pos()) { + new_a_ij = a_ij / one_minus_f_0; + } + else { + new_a_ij = a_ij / f_0; + new_a_ij.neg(); + } + k.addmul(new_a_ij, lower_bound(x_j).get_rational()); + lower(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); + } + else { + SASSERT(at_upper(x_j)); + if (a_ij.is_pos()) { + new_a_ij = a_ij / f_0; + new_a_ij.neg(); // the upper terms are inverted. + } + else { + new_a_ij = a_ij / one_minus_f_0; + } + k.addmul(new_a_ij, upper_bound(x_j).get_rational()); + upper(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); + } + TRACE("gomory_cut_detail", tout << a_ij << "*v" << x_j << " k: " << k << "\n";); + pol.push_back(row_entry(new_a_ij, x_j)); + } + else { + ++num_ints; + SASSERT(is_int(x_j)); + numeral f_j = Ext::fractional_part(a_ij); + TRACE("gomory_cut_detail", + tout << a_ij << "*v" << x_j << "\n"; + tout << "fractional_part: " << Ext::fractional_part(a_ij) << "\n"; + tout << "f_j: " << f_j << "\n"; + tout << "f_0: " << f_0 << "\n"; + tout << "one_minus_f_0: " << one_minus_f_0 << "\n";); + if (!f_j.is_zero()) { + numeral new_a_ij; + if (at_lower(x_j)) { + if (f_j <= one_minus_f_0) { + new_a_ij = f_j / one_minus_f_0; + } + else { + new_a_ij = (numeral(1) - f_j) / f_0; + } + k.addmul(new_a_ij, lower_bound(x_j).get_rational()); + lower(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); + } + else { + SASSERT(at_upper(x_j)); + if (f_j <= f_0) { + new_a_ij = f_j / f_0; + } + else { + new_a_ij = (numeral(1) - f_j) / one_minus_f_0; + } + new_a_ij.neg(); // the upper terms are inverted + k.addmul(new_a_ij, upper_bound(x_j).get_rational()); + upper(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); + } + TRACE("gomory_cut_detail", tout << "new_a_ij: " << new_a_ij << " k: " << k << "\n";); + pol.push_back(row_entry(new_a_ij, x_j)); + lcm_den = lcm(lcm_den, denominator(new_a_ij)); + } + } + } + } + + CTRACE("empty_pol", pol.empty(), display_row_info(tout, r);); + + expr_ref bound(get_manager()); + if (pol.empty()) { + SASSERT(k.is_pos()); + // conflict 0 >= k where k is positive + set_conflict(ante, ante, "gomory-cut"); + return true; + } + else if (pol.size() == 1) { + theory_var v = pol[0].m_var; + k /= pol[0].m_coeff; + bool is_lower = pol[0].m_coeff.is_pos(); + if (is_int(v) && !k.is_int()) { + k = is_lower?ceil(k):floor(k); + } + rational _k = k.to_rational(); + if (is_lower) + bound = m_util.mk_ge(get_enode(v)->get_owner(), m_util.mk_numeral(_k, is_int(v))); + else + bound = m_util.mk_le(get_enode(v)->get_owner(), m_util.mk_numeral(_k, is_int(v))); + } + else { + if (num_ints > 0) { + lcm_den = lcm(lcm_den, denominator(k)); + TRACE("gomory_cut_detail", tout << "k: " << k << " lcm_den: " << lcm_den << "\n"; + for (unsigned i = 0; i < pol.size(); i++) { + tout << pol[i].m_coeff << " " << pol[i].m_var << "\n"; + } + tout << "k: " << k << "\n";); + SASSERT(lcm_den.is_pos()); + if (!lcm_den.is_one()) { + // normalize coefficients of integer parameters to be integers. + unsigned n = pol.size(); + for (unsigned i = 0; i < n; i++) { + pol[i].m_coeff *= lcm_den; + SASSERT(!is_int(pol[i].m_var) || pol[i].m_coeff.is_int()); + } + k *= lcm_den; + } + TRACE("gomory_cut_detail", tout << "after *lcm\n"; + for (unsigned i = 0; i < pol.size(); i++) { + tout << pol[i].m_coeff << " * v" << pol[i].m_var << "\n"; + } + tout << "k: " << k << "\n";); + } + mk_polynomial_ge(pol.size(), pol.c_ptr(), k.to_rational(), bound); + } + TRACE("gomory_cut", tout << "new cut:\n" << bound << "\n"; ante.display(tout);); + literal l = null_literal; + context & ctx = get_context(); + ctx.internalize(bound, true); + l = ctx.get_literal(bound); + ctx.mark_as_relevant(l); + dump_lemmas(l, ante); + ctx.assign(l, ctx.mk_justification( + gomory_cut_justification( + get_id(), ctx.get_region(), + ante.lits().size(), ante.lits().c_ptr(), + ante.eqs().size(), ante.eqs().c_ptr(), ante, l))); + return true; + */ + +} lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { lean_assert(is_feasible()); init_inf_int_set(); @@ -129,32 +309,35 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { if ((++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) { move_non_base_vars_to_bounds(); - /* - if (!make_feasible()) { - TRACE("arith_int", tout << "failed to move variables to bounds.\n";); - failed(); - return FC_CONTINUE; + lp_status st = m_lar_solver->find_feasible_solution(); + if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { + return lia_move::give_up; } - int int_var = find_inf_int_base_var(); - if (int_var != null_int) { - TRACE("arith_int", tout << "v" << int_var << " does not have an integer assignment: " << get_value(int_var) << "\n";); - SASSERT(is_base(int_var)); - row const & r = m_rows[get_var_row(int_var)]; - if (!mk_gomory_cut(r)) { + int j = find_inf_int_base_column(); + if (j != -1) { + TRACE("arith_int", tout << "j = " << j << " does not have an integer assignment: " << get_value(j) << "\n";); + unsigned row_index = m_lar_solver->m_mpq_lar_core_solver.m_r_heading[j]; + if (!mk_gomory_cut(row_index, ex)) { + return lia_move::give_up; // silent failure } - return FC_CONTINUE; - }*/ + return lia_move::cut; + } } else { int j = find_inf_int_base_column(); - /* if (j != -1) { - TRACE("arith_int", tout << "v" << j << " does not have an integer assignment: " << get_value(j) << "\n";); - // apply branching - branch_infeasible_int_var(int_var); - return false; - }*/ + TRACE("arith_int", tout << "j" << j << " does not have an integer assignment: " << get_value(j) << "\n";); + + lean_assert(t.is_empty()); + t.add_to_map(j, mpq(1)); + k = floor(get_value(j)); + TRACE("arith_int", tout << "branching v" << j << " = " << get_value(j) << "\n"; + display_column(tout, j); + tout << "k = " << k << std::endl; + ); + return lia_move::branch; + } } // return true; return lia_move::give_up; @@ -259,7 +442,6 @@ mpq get_denominators_lcm(iterator_on_row &it) { bool int_solver::gcd_test_for_row(static_matrix> & A, unsigned i, explanation & ex) { iterator_on_row it(A.m_rows[i]); - std::cout << "gcd_test_for_row(" << i << ")\n"; mpq lcm_den = get_denominators_lcm(it); mpq consts(0); mpq gcds(0); @@ -350,8 +532,6 @@ bool int_solver::ext_gcd_test(iterator_on_row & it, mpq const & least_coeff, mpq const & lcm_den, mpq const & consts, explanation& ex) { - - std::cout << "calling ext_gcd_test" << std::endl; mpq gcds(0); mpq l(consts); mpq u(consts); diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 981127bc8..edfba5e5b 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -96,5 +96,7 @@ private: int find_inf_int_boxed_base_column_with_smallest_range(); lp_settings& settings(); void move_non_base_vars_to_bounds(); + void branch_infeasible_int_var(unsigned); + bool mk_gomory_cut(unsigned row_index, explanation & ex); }; } diff --git a/src/util/lp/lar_term.h b/src/util/lp/lar_term.h index 0e715ad0b..dfdedb571 100644 --- a/src/util/lp/lar_term.h +++ b/src/util/lp/lar_term.h @@ -21,6 +21,10 @@ struct lar_term { } } + bool is_empty() const { + return m_coeffs.size() == 0 && is_zero(m_v); + } + unsigned size() const { return static_cast(m_coeffs.size()); } const std::unordered_map & coeffs() const { From b21741cccdff6d70de0d69e70309522cb26884bd Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 6 Jul 2017 10:53:32 -0700 Subject: [PATCH 0190/1283] fix a bug in pivot_fixed_vars_from_basis Signed-off-by: Lev Nachmanson --- src/util/lp/lp_core_solver_base.h | 1 + src/util/lp/lp_core_solver_base.hpp | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 925206680..7313a46de 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -479,6 +479,7 @@ public: void change_basis(unsigned entering, unsigned leaving) { lean_assert(m_basis_heading[entering] < 0); + lean_assert(m_basis_heading[leaving] >= 0); int place_in_basis = m_basis_heading[leaving]; int place_in_non_basis = - m_basis_heading[entering] - 1; diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index d551daf27..03ae4e184 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -925,7 +925,9 @@ template void lp_core_solver_base::transpose_row } // j is the new basic column, j_basic - the leaving column template bool lp_core_solver_base::pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w) { - unsigned row_index = m_basis_heading[j_basic]; + lean_assert(m_basis_heading[j] < 0); + lean_assert(m_basis_heading[j_basic] >= 0); + unsigned row_index = m_basis_heading[j_basic]; change_basis(j, j_basic); if (m_settings.m_simplex_strategy == simplex_strategy_enum::lu) { if (m_factorization->need_to_refactor()) { @@ -940,15 +942,16 @@ template bool lp_core_solver_base::pivot_column_g return false; } } else { // the tableau case - pivot_column_tableau(j, row_index); + return pivot_column_tableau(j, row_index); } - return true; } + template void lp_core_solver_base::pivot_fixed_vars_from_basis() { // run over basis and non-basis at the same time indexed_vector w(m_basis.size()); // the buffer unsigned i = 0; // points to basis unsigned j = 0; // points to nonbasis + for (; i < m_basis.size() && j < m_nbasis.size(); i++) { unsigned ii = m_basis[i]; unsigned jj; @@ -963,8 +966,9 @@ template void lp_core_solver_base::pivot_fixed_v if (j >= m_nbasis.size()) break; j++; - if (!pivot_column_general(jj, ii, w)) - break; + if (!pivot_column_general(jj, ii, w)) + return; // total failure + break; } } } From 2e95a9d6b254ae1555cd47b9737549d1b031c2d4 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 6 Jul 2017 10:59:20 -0700 Subject: [PATCH 0191/1283] return a value from pivot_column_general Signed-off-by: Lev Nachmanson --- src/util/lp/lp_core_solver_base.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index 03ae4e184..c2adb61c1 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -944,6 +944,7 @@ template bool lp_core_solver_base::pivot_column_g } else { // the tableau case return pivot_column_tableau(j, row_index); } + return true; } template void lp_core_solver_base::pivot_fixed_vars_from_basis() { From 0e0e9c704121874023289ef0ce33a4d21b648408 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 6 Jul 2017 14:06:33 -0700 Subject: [PATCH 0192/1283] correct handling of integer vars by NB Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 43d3820f3..6144447e3 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -314,6 +314,7 @@ namespace smt { } } + void found_not_handled(expr* n) { m_not_handled = n; if (is_app(n) && is_underspecified(to_app(n))) { @@ -419,9 +420,6 @@ namespace smt { if (is_app(n)) { internalize_args(to_app(n)); } - if (a.is_int(n)) { - found_not_handled(n); - } theory_var v = mk_var(n); coeffs[vars.size()] = coeffs[index]; vars.push_back(v); @@ -1189,6 +1187,7 @@ namespace smt { case l_false: return FC_CONTINUE; case l_undef: + TRACE("arith", tout << "check-lia giveup\n";); st = FC_GIVEUP; break; } @@ -1199,23 +1198,27 @@ namespace smt { case l_false: return FC_CONTINUE; case l_undef: + TRACE("arith", tout << "check-nra giveup\n";); st = FC_GIVEUP; break; } - if (m_not_handled != 0) { + if (m_not_handled != 0) { + TRACE("arith", tout << "unhandled operator " << mk_pp(m_not_handled, m) << "\n";); st = FC_GIVEUP; } - + return st; case l_false: set_conflict(); return FC_CONTINUE; case l_undef: + TRACE("arith", tout << "check feasiable is undef\n";); return m.canceled() ? FC_CONTINUE : FC_GIVEUP; default: UNREACHABLE(); break; } + TRACE("arith", tout << "default giveup\n";); return FC_GIVEUP; } @@ -1268,10 +1271,12 @@ namespace smt { set_conflict1(); return l_false; case lean::lia_move::give_up: + TRACE("arith", tout << "lia giveup\n";); return l_undef; default: UNREACHABLE(); } + UNREACHABLE(); return l_undef; } @@ -1294,6 +1299,8 @@ namespace smt { return l_false; } break; + case l_undef: + TRACE("arith", tout << "nra-undef\n";); default: break; } From 9b1b096a1694c097ccbfdd7cf17c8ed30681eb4a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 6 Jul 2017 20:46:17 -0700 Subject: [PATCH 0193/1283] fix in init_int_int_set Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 1a6d6ddae..ded1d94d8 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -745,7 +745,7 @@ void int_solver::display_column(std::ostream & out, unsigned j) const { bool int_solver::inf_int_set_is_correct() const { for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) { - if (m_inf_int_set.contains(j) != is_int(j) && (!value_is_int(j))) + if (m_inf_int_set.contains(j) != (is_int(j) && (!value_is_int(j)))) return false; } return true; @@ -758,7 +758,7 @@ bool int_solver::column_is_int_inf(unsigned j) const { void int_solver::init_inf_int_set() { m_inf_int_set.clear(); m_inf_int_set.resize(m_lar_solver->A_r().column_count()); - for (unsigned j : m_lar_solver->m_mpq_lar_core_solver.m_r_basis) { + for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) { if (column_is_int_inf(j)) m_inf_int_set.insert(j); } From 055593469ab78cd27689737a4f1aea0a5d58e8dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jul 2017 20:47:07 -0700 Subject: [PATCH 0194/1283] Dev (#64) * introduce int_solver.h Signed-off-by: Lev Nachmanson * add int_solver class Signed-off-by: Lev Nachmanson * track which var is an integer Signed-off-by: Lev Nachmanson * add queries for integrality of vars Signed-off-by: Lev Nachmanson * resurrect lp_tst in its own director lp Signed-off-by: Lev Nachmanson * add file Signed-off-by: Lev Nachmanson * add_constraint has got a body Signed-off-by: Lev Nachmanson * fix add_constraint and substitute_terms_in_linear_expression Signed-off-by: Lev Nachmanson * after merge with Z3Prover Signed-off-by: Lev Nachmanson * adding stub check_int_feasibility() Signed-off-by: Lev Nachmanson * Dev (#50) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * small fix in lar_solver.cpp Signed-off-by: Lev Nachmanson * adding some content to the new check_int_feasibility() Signed-off-by: Lev Nachmanson * Dev (#51) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * test Signed-off-by: Lev Nachmanson * Dev (#53) * change in a comment Signed-off-by: Lev Nachmanson * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * adding nra Signed-off-by: Nikolaj Bjorner * debugging nra Signed-off-by: Nikolaj Bjorner * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner * n/a Signed-off-by: Nikolaj Bjorner * integrate nlsat Signed-off-by: Nikolaj Bjorner * tidy Signed-off-by: Nikolaj Bjorner * preserve is_int flag Signed-off-by: Lev Nachmanson * remove a debug printout Signed-off-by: Lev Nachmanson * Dev (#54) * change in a comment Signed-off-by: Lev Nachmanson * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner * adding more nlsat Signed-off-by: Nikolaj Bjorner * nlsat integration Signed-off-by: Nikolaj Bjorner * adding constraints Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * add missing initialization Signed-off-by: Nikolaj Bjorner * adding nra solver Signed-off-by: Nikolaj Bjorner * adding nra Signed-off-by: Nikolaj Bjorner * debugging nra Signed-off-by: Nikolaj Bjorner * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner * n/a Signed-off-by: Nikolaj Bjorner * integrate nlsat Signed-off-by: Nikolaj Bjorner * tidy Signed-off-by: Nikolaj Bjorner * use integer test from lra solver, updated it to work on term variables Signed-off-by: Nikolaj Bjorner * fix equality check in assume-eq Signed-off-by: Nikolaj Bjorner * fix model_is_int_feasible Signed-off-by: Lev Nachmanson * untested gcd_test() Signed-off-by: Lev Nachmanson * call fill_explanation_from_fixed_columns() Signed-off-by: Lev Nachmanson * add the call to pivot_fixed_vars_from_basis() to int_solver.cpp::check() Signed-off-by: Lev Nachmanson * port more of theory_arith_int.h Signed-off-by: Lev Nachmanson * use statistics of lar_solver by theory_lra.cpp Signed-off-by: Lev Nachmanson * port more code to int_solver.cpp Signed-off-by: Lev Nachmanson * add an assert Signed-off-by: Lev Nachmanson * more int porting Signed-off-by: Lev Nachmanson * fix a bug in pivot_fixed_vars_from_basis Signed-off-by: Lev Nachmanson * small change Signed-off-by: Lev Nachmanson * implement find_inf_int_base_column() Signed-off-by: Lev Nachmanson * catch unregistered vars in add_var_bound Signed-off-by: Lev Nachmanson * add a file Signed-off-by: Lev Nachmanson * compile for vs2012 Signed-off-by: Lev Nachmanson * fix asserts in add_var_bound Signed-off-by: Lev Nachmanson * fix the lp_solver init when workig on an mps file Signed-off-by: Lev Nachmanson * towards int_solver::check() Signed-off-by: Lev Nachmanson * change in int_solver::check() signature Signed-off-by: Lev Nachmanson * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * return branch from int_solver::check() Signed-off-by: Lev Nachmanson * add a stub for mk_gomory_cut Signed-off-by: Lev Nachmanson * Dev (#59) * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * Dev (#60) * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * Dev (#61) * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * more TRACE(arith_int) Signed-off-by: Lev Nachmanson * fix the build Signed-off-by: Lev Nachmanson * loops Signed-off-by: Nikolaj Bjorner * Dev (#62) * add handlers for lia moves Signed-off-by: Nikolaj Bjorner * spacing Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * loops Signed-off-by: Nikolaj Bjorner * build fix Signed-off-by: Lev Nachmanson --- src/util/lp/lp_core_solver_base.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index c2adb61c1..f3cee7fa8 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -83,8 +83,8 @@ pivot_for_tableau_on_basis() { // i is the pivot row, and j is the pivot column template void lp_core_solver_base:: pivot_to_reduced_costs_tableau(unsigned i, unsigned j) { - if (j >= m_d.size()) - return; + if (j >= m_d.size()) + return; T &a = m_d[j]; if (is_zero(a)) return; @@ -925,9 +925,9 @@ template void lp_core_solver_base::transpose_row } // j is the new basic column, j_basic - the leaving column template bool lp_core_solver_base::pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w) { - lean_assert(m_basis_heading[j] < 0); - lean_assert(m_basis_heading[j_basic] >= 0); - unsigned row_index = m_basis_heading[j_basic]; + lean_assert(m_basis_heading[j] < 0); + lean_assert(m_basis_heading[j_basic] >= 0); + unsigned row_index = m_basis_heading[j_basic]; change_basis(j, j_basic); if (m_settings.m_simplex_strategy == simplex_strategy_enum::lu) { if (m_factorization->need_to_refactor()) { @@ -952,7 +952,7 @@ template void lp_core_solver_base::pivot_fixed_v indexed_vector w(m_basis.size()); // the buffer unsigned i = 0; // points to basis unsigned j = 0; // points to nonbasis - + for (; i < m_basis.size() && j < m_nbasis.size(); i++) { unsigned ii = m_basis[i]; unsigned jj; @@ -967,9 +967,9 @@ template void lp_core_solver_base::pivot_fixed_v if (j >= m_nbasis.size()) break; j++; - if (!pivot_column_general(jj, ii, w)) - return; // total failure - break; + if (!pivot_column_general(jj, ii, w)) + return; // total failure + break; } } } From 2cd81851e7d1a206abf0121b90dfb1774e4f17d9 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 6 Jul 2017 21:29:09 -0700 Subject: [PATCH 0195/1283] solve more ilp smt Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 23 ++++++++++--- src/util/lp/int_solver.h | 1 + src/util/lp/lp_core_solver_base.hpp | 52 ++++++++++++++++------------- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index ded1d94d8..30bfcae9b 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -281,9 +281,18 @@ bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { */ } + +void int_solver::init_check_data() { + init_inf_int_set(); + unsigned n = m_lar_solver->A_r().column_count(); + m_old_values_set.resize(n); + m_old_values_data.resize(n); +} + lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { - lean_assert(is_feasible()); - init_inf_int_set(); + lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); + lean_assert(is_feasible()); + init_check_data(); lean_assert(inf_int_set_is_correct()); // currently it is a reimplementation of // final_check_status theory_arith::check_int_feasibility() @@ -298,9 +307,12 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { */ m_lar_solver->pivot_fixed_vars_from_basis(); + lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); patch_int_infeasible_columns(); - fix_non_base_columns(); - lean_assert(is_feasible()); + lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); + fix_non_base_columns(); + lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); + lean_assert(is_feasible()); TRACE("arith_int_rows", trace_inf_rows();); if (find_inf_int_base_column() == -1) @@ -339,7 +351,8 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { return lia_move::branch; } } - // return true; + lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); + // return true; return lia_move::give_up; } diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index edfba5e5b..8259ae128 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -98,5 +98,6 @@ private: void move_non_base_vars_to_bounds(); void branch_infeasible_int_var(unsigned); bool mk_gomory_cut(unsigned row_index, explanation & ex); + void init_check_data(); }; } diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index f3cee7fa8..08ba5d251 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -924,27 +924,32 @@ template void lp_core_solver_base::transpose_row m_A.transpose_rows(i, j); } // j is the new basic column, j_basic - the leaving column -template bool lp_core_solver_base::pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w) { - lean_assert(m_basis_heading[j] < 0); - lean_assert(m_basis_heading[j_basic] >= 0); - unsigned row_index = m_basis_heading[j_basic]; - change_basis(j, j_basic); - if (m_settings.m_simplex_strategy == simplex_strategy_enum::lu) { - if (m_factorization->need_to_refactor()) { - init_lu(); - } else { - m_factorization->prepare_entering(j, w); // to init vector w - m_factorization->replace_column(zero_of_type(), w, row_index); - } - if (m_factorization->get_status() != LU_status::OK) { - change_basis(j_basic, j); - init_lu(); - return false; - } - } else { // the tableau case - return pivot_column_tableau(j, row_index); - } - return true; +template bool lp_core_solver_base::pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w) { + lean_assert(m_basis_heading[j] < 0); + lean_assert(m_basis_heading[j_basic] >= 0); + unsigned row_index = m_basis_heading[j_basic]; + if (m_settings.m_simplex_strategy == simplex_strategy_enum::lu) { + if (m_factorization->need_to_refactor()) { + init_lu(); + } + else { + m_factorization->prepare_entering(j, w); // to init vector w + m_factorization->replace_column(zero_of_type(), w, row_index); + } + if (m_factorization->get_status() != LU_status::OK) { + init_lu(); + return false; + } + else { + change_basis(j, j_basic); + } + } + else { // the tableau case + if (pivot_column_tableau(j, row_index)) + change_basis(j, j_basic); + else return false; + } + return true; } template void lp_core_solver_base::pivot_fixed_vars_from_basis() { @@ -967,9 +972,8 @@ template void lp_core_solver_base::pivot_fixed_v if (j >= m_nbasis.size()) break; j++; - if (!pivot_column_general(jj, ii, w)) - return; // total failure - break; + if (pivot_column_general(jj, ii, w)) + break; } } } From 53c38f02d515661155851640df7fb1a9d0d013c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jul 2017 22:12:18 -0700 Subject: [PATCH 0196/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 448 +++++++++++++++++++++++++------------- src/sat/ba_solver.h | 31 ++- src/sat/sat_extension.h | 7 + src/sat/sat_lookahead.cpp | 18 +- src/sat/sat_lookahead.h | 5 +- 5 files changed, 340 insertions(+), 169 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 243fe9b10..eab579ff1 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -94,6 +94,7 @@ namespace sat { bool ba_solver::pb_base::well_formed() const { uint_set vars; + if (lit() != null_literal) vars.insert(lit().var()); for (unsigned i = 0; i < size(); ++i) { bool_var v = get_lit(i).var(); if (vars.contains(v)) return false; @@ -149,6 +150,7 @@ namespace sat { for (unsigned i = 0; i < size(); ++i) { m_wlits[i].first = std::min(k(), m_wlits[i].first); if (m_max_sum + m_wlits[i].first < m_max_sum) { + std::cout << "update-max-sum overflows\n"; throw default_exception("addition of pb coefficients overflows"); } m_max_sum += m_wlits[i].first; @@ -200,10 +202,11 @@ namespace sat { bool ba_solver::xor::well_formed() const { uint_set vars; + if (lit() != null_literal) vars.insert(lit().var()); for (literal l : *this) { bool_var v = l.var(); if (vars.contains(v)) return false; - vars.insert(v); + vars.insert(v); } return true; } @@ -326,6 +329,8 @@ namespace sat { // pb static unsigned _bad_id = 11111111; // 2759; // +#define BADLOG(_cmd_) if (p.id() == _bad_id) { _cmd_; } + // watch a prefix of literals, such that the slack of these is >= k bool ba_solver::init_watch(pb& p, bool is_true) { @@ -354,9 +359,8 @@ namespace sat { ++j; } } - if (p.id() == _bad_id) { - std::cout << "watch " << num_watch << " out of " << sz << "\n"; - } + BADLOG(std::cout << "watch " << num_watch << " out of " << sz << "\n"); + DEBUG_CODE( bool is_false = false; for (unsigned k = 0; k < sz; ++k) { @@ -383,14 +387,14 @@ namespace sat { p.set_slack(slack); p.set_num_watch(num_watch); - validate_watch(p); + SASSERT(validate_watch(p)); TRACE("sat", display(tout << "init watch: ", p, true);); // slack is tight: if (slack + slack1 == bound) { SASSERT(slack1 == 0); - SASSERT(j == num_watch); + SASSERT(j == num_watch); for (unsigned i = 0; i < j; ++i) { assign(p, p[i].second); } @@ -412,11 +416,11 @@ namespace sat { Sw += a_s Lw = Lw u {l_s} Lu = Lu \ {l_s} - } - if (Sw < k) return conflict - for (li in Lw | Sw < k + ai) + } + if (Sw < k) return conflict + for (li in Lw | Sw < k + ai) assign li - return no-conflict + return no-conflict a_max index: index of non-false literal with maximal weight. */ @@ -428,10 +432,7 @@ namespace sat { m_a_max = p[index].first; } } - } - - -#define BADLOG(_cmd_) if (p.id() == _bad_id) { _cmd_; } + } /* \brief propagate assignment to alit in constraint p. @@ -465,7 +466,7 @@ namespace sat { } add_index(p, index, lit); } - if (index == num_watch) { + if (index == num_watch || num_watch == 0) { _bad_id = p.id(); std::cout << "BAD: " << p.id() << "\n"; display(std::cout, p, true); @@ -493,9 +494,7 @@ namespace sat { literal lit = p[j].second; if (value(lit) != l_false) { slack += p[j].first; - if (is_watched(p[j].second, p)) { - std::cout << "Swap literal already watched: " << p[j].second << "\n"; - } + SASSERT(!is_watched(p[j].second, p)); watch_literal(p[j], p); p.swap(num_watch, j); add_index(p, num_watch, lit); @@ -519,11 +518,10 @@ namespace sat { set_conflict(p, alit); return l_false; } - - if (index > p.size() || num_watch > p.size() || num_watch == 0 || p.id() == _bad_id) { - display(std::cout, p, true); - std::cout << "size: " << p.size() << " index: " << index << " num watch: " << num_watch << "\n"; - } + + if (num_watch == 1) { _bad_id = p.id(); } + + BADLOG(std::cout << "size: " << p.size() << " index: " << index << " num watch: " << num_watch << "\n"); // swap out the watched literal. --num_watch; @@ -532,6 +530,7 @@ namespace sat { p.set_num_watch(num_watch); p.swap(num_watch, index); + // // slack >= bound, but slack - w(l) < bound // l must be true. @@ -564,12 +563,10 @@ namespace sat { } void ba_solver::clear_watch(pb& p) { - validate_watch(p); for (unsigned i = 0; i < p.num_watch(); ++i) { unwatch_literal(p[i].second, p); } p.set_num_watch(0); - validate_watch(p); } /* @@ -687,10 +684,10 @@ namespace sat { --i; } } - if (p.id() == _bad_id) display(std::cout << "simplify ", p, true); + BADLOG(display(std::cout << "simplify ", p, true)); p.set_size(sz); p.set_k(p.k() - true_val); - if (p.id() == _bad_id) display(std::cout << "simplified ", p, true); + BADLOG(display(std::cout << "simplified ", p, true)); // display(verbose_stream(), c, true); if (p.k() == 1 && p.lit() == null_literal) { @@ -876,45 +873,69 @@ namespace sat { m_active_vars.shrink(j); } - void ba_solver::inc_coeff(literal l, int offset) { + void ba_solver::inc_coeff(literal l, int64 offset) { SASSERT(offset > 0); bool_var v = l.var(); SASSERT(v != null_bool_var); if (static_cast(m_coeffs.size()) <= v) { m_coeffs.resize(v + 1, 0); } - int coeff0 = m_coeffs[v]; + int64 coeff0 = m_coeffs[v]; if (coeff0 == 0) { m_active_vars.push_back(v); } - int inc = l.sign() ? -offset : offset; - int coeff1 = inc + coeff0; + int64 inc = l.sign() ? -offset : offset; + int64 coeff1 = inc + coeff0; m_coeffs[v] = coeff1; + if (coeff1 > INT_MAX || coeff1 < INT_MIN) { + std::cout << "overflow update coefficient " << coeff1 << "\n"; + m_overflow = true; + return; + } if (coeff0 > 0 && inc < 0) { - m_bound -= coeff0 - std::max(0, coeff1); + m_bound -= coeff0 - std::max(0LL, coeff1); } else if (coeff0 < 0 && inc > 0) { - m_bound -= std::min(0, coeff1) - coeff0; + m_bound -= std::min(0LL, coeff1) - coeff0; } // reduce coefficient to be no larger than bound. if (coeff1 > m_bound) { m_coeffs[v] = m_bound; } else if (coeff1 < 0 && -coeff1 > m_bound) { - m_coeffs[v] = -m_bound; + m_coeffs[v] = m_bound; } } - int ba_solver::get_coeff(bool_var v) const { + int64 ba_solver::get_coeff(bool_var v) const { return m_coeffs.get(v, 0); } - int ba_solver::get_abs_coeff(bool_var v) const { + int64 ba_solver::get_abs_coeff(bool_var v) const { return abs(get_coeff(v)); } + int ba_solver::get_int_coeff(bool_var v) const { + int64 c = m_coeffs.get(v, 0); + if (c < INT_MIN || c > INT_MAX) { + std::cout << "overflow " << c << "\n"; + m_overflow = true; + return 0; + } + return static_cast(c); + } + + unsigned ba_solver::get_bound() const { + if (m_bound < 0 || m_bound > UINT_MAX) { + std::cout << "overflow bound " << m_bound << "\n"; + m_overflow = true; + return 1; + } + return static_cast(m_bound); + } + void ba_solver::reset_coeffs() { for (unsigned i = 0; i < m_active_vars.size(); ++i) { m_coeffs[m_active_vars[i]] = 0; @@ -923,11 +944,14 @@ namespace sat { } static bool _debug_conflict = false; + static literal _debug_consequent = null_literal; + static unsigned_vector _debug_var2position; lbool ba_solver::resolve_conflict() { if (0 == m_num_propagations_since_pop) { return l_undef; } + m_overflow = false; reset_coeffs(); m_num_marks = 0; m_bound = 0; @@ -941,25 +965,25 @@ namespace sat { } literal_vector const& lits = s().m_trail; unsigned idx = lits.size() - 1; - int offset = 1; + int64 offset = 1; DEBUG_CODE(active2pb(m_A);); unsigned init_marks = m_num_marks; do { - if (offset == 0) { - goto process_next_resolvent; - } - // TBD: need proper check for overflow. - if (offset > (1 << 12)) { - IF_VERBOSE(12, verbose_stream() << "offset: " << offset << "\n"; + if (m_overflow || offset > (1 << 12)) { + IF_VERBOSE(20, verbose_stream() << "offset: " << offset << "\n"; active2pb(m_A); display(verbose_stream(), m_A); ); goto bail_out; } + if (offset == 0) { + goto process_next_resolvent; + } + TRACE("sat_verbose", display(tout, m_A);); TRACE("sat", tout << "process consequent: " << consequent << ":\n"; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); @@ -971,6 +995,7 @@ namespace sat { std::cout << consequent << "\n"; s().display_justification(std::cout, js); std::cout << "\n"; + _debug_consequent = consequent; } switch(js.get_kind()) { case justification::NONE: @@ -1056,7 +1081,6 @@ namespace sat { SASSERT(validate_lemma()); - DEBUG_CODE( active2pb(m_C); //SASSERT(validate_resolvent()); @@ -1096,7 +1120,6 @@ namespace sat { DEBUG_CODE(active2pb(m_A);); } SASSERT(value(consequent) == l_true); - } while (m_num_marks > 0); @@ -1111,6 +1134,10 @@ namespace sat { active2card(); + if (m_overflow) { + goto bail_out; + } + SASSERT(validate_conflict(m_lemma, m_A)); TRACE("sat", tout << m_lemma << "\n";); @@ -1130,6 +1157,9 @@ namespace sat { return l_true; bail_out: + + m_overflow = false; + while (m_num_marks > 0 && idx >= 0) { bool_var v = lits[idx].var(); if (s().is_marked(v)) { @@ -1138,11 +1168,20 @@ namespace sat { } if (idx == 0 && !_debug_conflict) { _debug_conflict = true; + _debug_var2position.reserve(s().num_vars()); + for (unsigned i = 0; i < lits.size(); ++i) { + _debug_var2position[lits[i].var()] = i; + } // s().display(std::cout); - std::cout << s().m_not_l << "\n"; + active2pb(m_A); + uint64 c = 0; + for (uint64 c1 : m_A.m_coeffs) c += c1; + std::cout << "sum of coefficients: " << c << "\n"; + display(std::cout, m_A, true); + std::cout << "conflicting literal: " << s().m_not_l << "\n"; for (literal l : lits) { if (s().is_marked(l.var())) { - std::cout << "missing mark: " << l << "\n"; + IF_VERBOSE(0, verbose_stream() << "missing mark: " << l << "\n";); s().reset_mark(l.var()); } } @@ -1158,7 +1197,7 @@ namespace sat { adjust_conflict_level: - int slack = -m_bound; + int64 slack = -m_bound; for (bool_var v : m_active_vars) { slack += get_abs_coeff(v); } @@ -1166,10 +1205,10 @@ namespace sat { m_lemma.reset(); m_lemma.push_back(null_literal); unsigned num_skipped = 0; - int asserting_coeff = 0; - for (unsigned i = 0; /* 0 <= slack && */ i < m_active_vars.size(); ++i) { + int64 asserting_coeff = 0; + for (unsigned i = 0; 0 <= slack && i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; - int coeff = get_coeff(v); + int64 coeff = get_coeff(v); lbool val = value(v); bool is_true = val == l_true; bool append = coeff != 0 && val != l_undef && (coeff < 0 == is_true); @@ -1216,38 +1255,30 @@ namespace sat { IF_VERBOSE(10, verbose_stream() << "(sat.backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); goto adjust_conflict_level; } - - // slack is related to coefficients of m_lemma - // so does not apply to unit coefficients. - // std::cout << "lemma: " << m_lemma << " >= " << 1 << "\n"; - // active2pb(m_A); - // display(std::cout, m_A, true); -#if 0 - constraint* c = active2constraint(); - if (c) { - display(std::cout, *c, true); - std::cout << "Eval: " << eval(*c) << "\n"; - } -#endif return true; } + /* + \brief compute a cut for current resolvent. + */ + void ba_solver::cut() { - unsigned g = 0; - int sum_of_units = 0; + + // bypass cut if there is a unit coefficient for (bool_var v : m_active_vars) { - if (1 == get_abs_coeff(v) && ++sum_of_units >= m_bound) return; + if (1 == get_abs_coeff(v)) return; } - //active2pb(m_A); - //display(std::cout << "units can be removed\n", m_A, true); + + SASSERT(0 <= m_bound && m_bound <= UINT_MAX); + + unsigned g = 0; for (unsigned i = 0; g != 1 && i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; - int coeff = get_abs_coeff(v); + int64 coeff = get_abs_coeff(v); if (coeff == 0) { continue; } - if (coeff == 1) return; if (m_bound < coeff) { if (get_coeff(v) > 0) { m_coeffs[v] = m_bound; @@ -1265,23 +1296,18 @@ namespace sat { g = u_gcd(g, static_cast(coeff)); } } + if (g >= 2) { - active2pb(m_A); - //display(std::cout, m_A, true); normalize_active_coeffs(); - int ig = static_cast(g); - for (unsigned i = 0; i < m_active_vars.size(); ++i) { - m_coeffs[m_active_vars[i]] /= ig; + for (bool_var v : m_active_vars) { + m_coeffs[v] /= static_cast(g); } m_bound = (m_bound + g - 1) / g; ++m_stats.m_num_cut; - //std::cout << "CUT " << g << "\n"; - //active2pb(m_A); - //display(std::cout, m_A, true); } } - void ba_solver::process_card(card& c, int offset) { + void ba_solver::process_card(card& c, int64 offset) { literal lit = c.lit(); SASSERT(c.k() <= c.size()); SASSERT(lit == null_literal || value(lit) == l_true); @@ -1297,7 +1323,7 @@ namespace sat { } } - void ba_solver::process_antecedent(literal l, int offset) { + void ba_solver::process_antecedent(literal l, int64 offset) { SASSERT(value(l) == l_false); bool_var v = l.var(); unsigned level = lvl(v); @@ -1306,6 +1332,9 @@ namespace sat { s().mark(v); TRACE("sat", tout << "Mark: v" << v << "\n";); ++m_num_marks; + if (_debug_conflict && _debug_consequent != null_literal && _debug_var2position[_debug_consequent.var()] < _debug_var2position[l.var()]) { + std::cout << "antecedent " << l << " is above consequent in stack\n"; + } } inc_coeff(l, offset); } @@ -1359,9 +1388,6 @@ namespace sat { } void ba_solver::add_constraint(constraint* c) { - if (c->id() == _bad_id) { - display(std::cout, *c, true); - } if (c->learned()) { m_learned.push_back(c); } @@ -1463,6 +1489,50 @@ namespace sat { } } + double ba_solver::get_reward(card const& c, literal_occs_fun& literal_occs) const { + unsigned k = c.k(), slack = 0; + double to_add = 0; + for (literal l : c) { + switch (value(l)) { + case l_true: --k; if (k == 0) return 0; break; + case l_undef: to_add += literal_occs(l); ++slack; break; + case l_false: break; + } + } + if (k >= slack) return 1; + return pow(0.5, slack - k + 1) * to_add; + } + + double ba_solver::get_reward(pb const& c, literal_occs_fun& occs) const { + unsigned k = c.k(), slack = 0; + double to_add = 0; + double undefs = 0; + for (wliteral wl : c) { + literal l = wl.second; + unsigned w = wl.first; + switch (value(l)) { + case l_true: if (k <= w) return 0; k -= w; break; + case l_undef: to_add += occs(l); ++undefs; slack += w; break; // TBD multiplier factor on this + case l_false: break; + } + } + if (k >= slack || 0 == undefs) return 0; + double avg = slack / undefs; + return pow(0.5, (slack - k + 1)/avg) * to_add; + } + + double ba_solver::get_reward(literal l, ext_justification_idx idx, literal_occs_fun& occs) const { + constraint const& c = index2constraint(idx); + unsigned sz = c.size(); + switch (c.tag()) { + case card_t: return get_reward(c.to_card(), occs); + case pb_t: return get_reward(c.to_pb(), occs); + case xor_t: return 0; + default: UNREACHABLE(); return 0; + } + } + + void ba_solver::ensure_parity_size(bool_var v) { if (m_parity_marks.size() <= static_cast(v)) { @@ -1585,6 +1655,11 @@ namespace sat { unsigned k = p.k(); + if (_debug_conflict) { + display(std::cout, p, true); + std::cout << "literal: " << l << " value: " << value(l) << " num-watch: " << p.num_watch() << " slack: " << p.slack() << "\n"; + } + if (value(l) == l_false) { // The literal comes from a conflict. // it is forced true, but assigned to false. @@ -1619,6 +1694,10 @@ namespace sat { CTRACE("sat", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); + if (_debug_conflict) { + std::cout << "coeff " << coeff << "\n"; + } + SASSERT(coeff > 0); unsigned slack = p.slack() - coeff; @@ -1688,20 +1767,10 @@ namespace sat { } void ba_solver::unwatch_literal(literal lit, constraint& c) { - if (c.id() == _bad_id) { std::cout << "unwatch " << lit << "\n"; } get_wlist(~lit).erase(watched(c.index())); - if (is_watched(lit, c)) { - std::cout << "Not deleted " << lit << "\n"; - } } void ba_solver::watch_literal(literal lit, constraint& c) { - if (is_watched(lit, c)) { - std::cout << "Already watched " << lit << "\n"; - UNREACHABLE(); - exit(0); - } - if (c.id() == _bad_id) { std::cout << "watch " << lit << "\n"; } get_wlist(~lit).push_back(watched(c.index())); } @@ -1867,9 +1936,7 @@ namespace sat { if (c.lit() != null_literal && value(c.lit()) != l_true) return true; if (c.lit() != null_literal && lvl(c.lit()) != 0) { if (!is_watched(c.lit(), c) || !is_watched(~c.lit(), c)) { - std::cout << "Definition literal is not watched " << c.lit() << " " << c << "\n"; - display_watch_list(std::cout, s().m_cls_allocator, get_wlist(c.lit())) << "\n"; - display_watch_list(std::cout, s().m_cls_allocator, get_wlist(~c.lit())) << "\n"; + UNREACHABLE(); return false; } } @@ -1882,12 +1949,15 @@ namespace sat { bool found = is_watched(l, c); if (found != c.is_watching(l)) { - std::cout << "Discrepancy of watched literal: " << l << " id: " << c.id() << " clause: " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n"; - display_watch_list(std::cout << l << ": ", s().m_cls_allocator, get_wlist(l)) << "\n"; - display_watch_list(std::cout << ~l << ": ", s().m_cls_allocator, get_wlist(~l)) << "\n"; - std::cout << "value: " << value(l) << " level: " << lvl(l) << "\n"; - display(std::cout, c, true); - if (c.lit() != null_literal) std::cout << value(c.lit()) << "\n"; + IF_VERBOSE(0, + verbose_stream() << "Discrepancy of watched literal: " << l << " id: " << c.id() + << " clause: " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n"; + display_watch_list(verbose_stream() << l << ": ", s().m_cls_allocator, get_wlist(l)) << "\n"; + display_watch_list(verbose_stream() << ~l << ": ", s().m_cls_allocator, get_wlist(~l)) << "\n"; + verbose_stream() << "value: " << value(l) << " level: " << lvl(l) << "\n"; + display(verbose_stream(), c, true); + if (c.lit() != null_literal) verbose_stream() << value(c.lit()) << "\n";); + UNREACHABLE(); exit(1); return false; @@ -1900,8 +1970,6 @@ namespace sat { for (unsigned i = 0; i < p.size(); ++i) { literal l = p[i].second; if (lvl(l) != 0 && is_watched(l, p) != i < p.num_watch()) { - std::cout << "DISCREPANCY: " << l << " at " << i << " for " << p.num_watch() << " index: " << p.id() << "\n"; - display(std::cout, p, true); UNREACHABLE(); return false; } @@ -2067,13 +2135,14 @@ namespace sat { m_simplify_change = false; m_clause_removed = false; m_constraint_removed = false; - for (constraint* c : m_constraints) simplify(*c); - for (constraint* c : m_learned) simplify(*c); + for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) simplify(*m_constraints[i]); + for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) simplify(*m_learned[i]); init_use_lists(); remove_unused_defs(); set_non_external(); elim_pure(); - subsumption(); + for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) subsumption(*m_constraints[i]); + for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) subsumption(*m_learned[i]); cleanup_clauses(); cleanup_constraints(); } @@ -2242,12 +2311,10 @@ namespace sat { m_visited.resize(s().num_vars()*2, false); m_constraint_removed = false; - for (constraint* c : m_constraints) { - flush_roots(*c); - } - for (constraint* c : m_learned) { - flush_roots(*c); - } + for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) + flush_roots(*m_constraints[i]); + for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) + flush_roots(*m_learned[i]); cleanup_constraints(); // validate(); @@ -2342,7 +2409,7 @@ namespace sat { } literal root = c.lit(); remove_constraint(c); - constraint* p = add_pb_ge(root, wlits, k, c.learned()); + add_pb_ge(root, wlits, k, c.learned()); } else { if (c.lit() == null_literal || value(c.lit()) == l_true) { @@ -2644,11 +2711,29 @@ namespace sat { unsigned ext = 0; for (unsigned v = 0; v < s().num_vars(); ++v) { literal lit(v, false); - if (s().is_external(v) && m_cnstr_use_list[lit.index()].size() == 0 && m_cnstr_use_list[(~lit).index()].size() == 0 && !s().is_assumption(v)) { + if (s().is_external(v) && + m_cnstr_use_list[lit.index()].size() == 0 && + m_cnstr_use_list[(~lit).index()].size() == 0 && !s().is_assumption(v)) { s().set_non_external(v); ++ext; } } + // ensure that lemmas use only external variables. + for (constraint* cp : m_learned) { + constraint& c = *cp; + if (c.was_removed()) continue; + SASSERT(c.lit() == null_literal); + for (unsigned i = 0; i < c.size(); ++i) { + bool_var v = c.get_lit(i).var(); + if (s().was_eliminated(v)) { + remove_constraint(c); + break; + } + if (!s().is_external(v)) { + s().set_external(v); + } + } + } IF_VERBOSE(10, verbose_stream() << "non-external variables converted: " << ext << "\n";); return ext; } @@ -2680,11 +2765,6 @@ namespace sat { return pure_literals; } - void ba_solver::subsumption() { - for (constraint* c : m_constraints) subsumption(*c); - for (constraint* c : m_learned) subsumption(*c); - } - void ba_solver::subsumption(constraint& cnstr) { if (cnstr.was_removed()) return; switch (cnstr.tag()) { @@ -2693,6 +2773,11 @@ namespace sat { if (c.k() > 1) subsumption(c); break; } + case pb_t: { + pb& p = cnstr.to_pb(); + if (p.k() > 1) subsumption(p); + break; + } default: break; } @@ -2805,6 +2890,45 @@ namespace sat { return c1_exclusive + 1 <= c1.k(); } + /* + \brief Ax >= k subsumes By >= k' if + all coefficients in A are <= B and k >= k' + */ + bool ba_solver::subsumes(pb const& p1, pb_base const& p2) { + if (p1.k() < p2.k()) return false; + unsigned num_marked = 0; + for (unsigned i = 0; i < p2.size(); ++i) { + literal l = p2.get_lit(i); + if (is_marked(l)) { + ++num_marked; + if (m_weights[l.index()] > p2.get_coeff(i)) return false; + } + } + return num_marked == p1.size(); + } + + void ba_solver::subsumes(pb& p1, literal lit) { + for (constraint* c : m_cnstr_use_list[lit.index()]) { + if (c == &p1 || c->was_removed()) continue; + bool s = false; + switch (c->tag()) { + case card_t: + s = subsumes(p1, c->to_card()); + break; + case pb_t: + s = subsumes(p1, c->to_pb()); + break; + default: + break; + } + if (s) { + ++m_stats.m_num_card_subsumes; + p1.set_learned(false); + remove_constraint(*c); + } + } + } + literal ba_solver::get_min_occurrence_literal(card const& c) { unsigned occ_count = UINT_MAX; literal lit = null_literal; @@ -2821,7 +2945,7 @@ namespace sat { void ba_solver::card_subsumption(card& c1, literal lit) { literal_vector slit; for (constraint* c : m_cnstr_use_list[lit.index()]) { - if (!c || c->tag() != card_t || c == &c1 || c->was_removed()) { + if (!c->is_card() || c == &c1 || c->was_removed()) { continue; } card& c2 = c->to_card(); @@ -2910,8 +3034,7 @@ namespace sat { } void ba_solver::subsumption(card& c1) { - SASSERT(!c1.was_removed()); - if (c1.lit() != null_literal) { + if (c1.was_removed() || c1.lit() != null_literal) { return; } clause_vector removed_clauses; @@ -2930,6 +3053,24 @@ namespace sat { } } + void ba_solver::subsumption(pb& p1) { + if (p1.was_removed() || p1.lit() != null_literal) { + return; + } + for (wliteral l : p1) { + mark_visited(l.second); + SASSERT(m_weights[l.second.index()] == 0); + m_weights[l.second.index()] = l.first; + } + for (unsigned i = 0; i < p1.num_watch(); ++i) { + subsumes(p1, p1[i].second); + } + for (wliteral l : p1) { + unmark_visited(l.second); + m_weights[l.second.index()] = 0; + } + } + void ba_solver::clauses_modifed() {} lbool ba_solver::get_phase(bool_var v) { return l_undef; } @@ -3145,11 +3286,11 @@ namespace sat { } bool ba_solver::validate_lemma() { - int val = -m_bound; + int64 val = -m_bound; reset_active_var_set(); for (bool_var v : m_active_vars) { if (m_active_var_set.contains(v)) continue; - int coeff = get_coeff(v); + int64 coeff = get_coeff(v); if (coeff == 0) continue; m_active_var_set.insert(v); literal lit(v, false); @@ -3173,7 +3314,7 @@ namespace sat { p.reset(m_bound); for (bool_var v : m_active_vars) { if (m_active_var_set.contains(v)) continue; - int coeff = get_coeff(v); + int64 coeff = get_coeff(v); if (coeff == 0) continue; m_active_var_set.insert(v); literal lit(v, coeff < 0); @@ -3184,32 +3325,27 @@ namespace sat { ba_solver::constraint* ba_solver::active2constraint() { reset_active_var_set(); - literal_vector lits; - unsigned_vector coeffs; - bool all_one = true; + svector wlits; uint64_t sum = 0; if (m_bound == 1) return 0; + if (m_overflow) return 0; + for (bool_var v : m_active_vars) { - int coeff = get_coeff(v); + int coeff = get_int_coeff(v); if (m_active_var_set.contains(v) || coeff == 0) continue; m_active_var_set.insert(v); literal lit(v, coeff < 0); - lits.push_back(lit); - coeffs.push_back(abs(coeff)); - all_one &= abs(coeff) == 1; + wlits.push_back(wliteral(abs(coeff), lit)); sum += abs(coeff); } - if (sum >= UINT_MAX/2) return 0; - if (all_one) { - return add_at_least(null_literal, lits, m_bound, true); + unsigned k = get_bound(); + + if (m_overflow || sum >= UINT_MAX/2) { + return 0; } else { - svector wlits; - for (unsigned i = 0; i < lits.size(); ++i) { - wlits.push_back(wliteral(coeffs[i], lits[i])); - } - return add_pb_ge(null_literal, wlits, m_bound, true); - } + return add_pb_ge(null_literal, wlits, k, true); + } } /* @@ -3247,7 +3383,7 @@ namespace sat { normalize_active_coeffs(); svector wlits; for (bool_var v : m_active_vars) { - int coeff = get_coeff(v); + int coeff = get_int_coeff(v); wlits.push_back(std::make_pair(abs(coeff), literal(v, coeff < 0))); } std::sort(wlits.begin(), wlits.end(), compare_wlit()); @@ -3264,7 +3400,7 @@ namespace sat { } while (!wlits.empty()) { wliteral wl = wlits.back(); - if (wl.first + sum0 >= static_cast(m_bound)) break; + if (wl.first + sum0 >= get_bound()) break; wlits.pop_back(); sum0 += wl.first; } @@ -3283,9 +3419,15 @@ namespace sat { ++num_max_level; } } - + if (m_overflow) return 0; if (slack >= k) { +#if 0 + return active2constraint(); + active2pb(m_A); + std::cout << "not asserting\n"; + display(std::cout, m_A, true); +#endif return 0; } @@ -3374,15 +3516,15 @@ namespace sat { // validate that m_A & m_B implies m_C bool ba_solver::validate_resolvent() { - u_map coeffs; - unsigned k = m_A.m_k + m_B.m_k; + u_map coeffs; + uint64 k = m_A.m_k + m_B.m_k; for (unsigned i = 0; i < m_A.m_lits.size(); ++i) { - unsigned coeff = m_A.m_coeffs[i]; + uint64 coeff = m_A.m_coeffs[i]; SASSERT(!coeffs.contains(m_A.m_lits[i].index())); coeffs.insert(m_A.m_lits[i].index(), coeff); } for (unsigned i = 0; i < m_B.m_lits.size(); ++i) { - unsigned coeff1 = m_B.m_coeffs[i], coeff2; + uint64 coeff1 = m_B.m_coeffs[i], coeff2; literal lit = m_B.m_lits[i]; if (coeffs.find((~lit).index(), coeff2)) { if (coeff1 == coeff2) { @@ -3410,7 +3552,7 @@ namespace sat { // C is above the sum of A and B for (unsigned i = 0; i < m_C.m_lits.size(); ++i) { literal lit = m_C.m_lits[i]; - unsigned coeff; + uint64 coeff; if (coeffs.find(lit.index(), coeff)) { if (coeff > m_C.m_coeffs[i] && m_C.m_coeffs[i] < m_C.m_k) { IF_VERBOSE(0, verbose_stream() << i << ": " << m_C.m_coeffs[i] << " " << m_C.m_k << "\n";); @@ -3444,9 +3586,9 @@ namespace sat { return false; } } - unsigned value = 0; + uint64 value = 0; for (unsigned i = 0; i < p.m_lits.size(); ++i) { - unsigned coeff = p.m_coeffs[i]; + uint64 coeff = p.m_coeffs[i]; if (!lits.contains(p.m_lits[i])) { value += coeff; } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 115b57fed..c30fd25b4 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -191,9 +191,9 @@ namespace sat { struct ineq { literal_vector m_lits; - unsigned_vector m_coeffs; - unsigned m_k; - void reset(unsigned k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } + svector m_coeffs; + uint64 m_k; + void reset(uint64 k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } }; @@ -213,9 +213,9 @@ namespace sat { // conflict resolution unsigned m_num_marks; unsigned m_conflict_lvl; - svector m_coeffs; + svector m_coeffs; svector m_active_vars; - int m_bound; + int64 m_bound; tracked_uint_set m_active_var_set; literal_vector m_lemma; literal_vector m_skipped; @@ -246,6 +246,9 @@ namespace sat { bool subsumes(card& c1, card& c2, literal_vector& comp); bool subsumes(card& c1, clause& c2, literal_vector& comp); bool subsumed(card& c1, literal l1, literal l2); + bool subsumes(pb const& p1, pb_base const& p2); + void subsumes(pb& p1, literal lit); + void subsumption(pb& p1); void binary_subsumption(card& c1, literal lit); void clause_subsumption(card& c1, literal lit, clause_vector& removed_clauses); void card_subsumption(card& c1, literal lit); @@ -259,7 +262,6 @@ namespace sat { unsigned set_non_external(); unsigned elim_pure(); bool elim_pure(literal lit); - void subsumption(); void subsumption(constraint& c1); void subsumption(card& c1); void gc_half(char const* _method); @@ -317,6 +319,8 @@ namespace sat { void flush_roots(card& c); void recompile(card& c); lbool eval(card const& c) const; + double get_reward(card const& c, literal_occs_fun& occs) const; + // xor specific functionality void clear_watch(xor& x); @@ -343,6 +347,7 @@ namespace sat { void flush_roots(pb& p); void recompile(pb& p); lbool eval(pb const& p) const; + double get_reward(pb const& p, literal_occs_fun& occs) const; // access solver inline lbool value(bool_var v) const { return value(literal(v, false)); } @@ -358,15 +363,18 @@ namespace sat { inline void drat_add(literal_vector const& c, svector const& premises) { m_solver->m_drat.add(c, premises); } + mutable bool m_overflow; void reset_active_var_set(); void normalize_active_coeffs(); - void inc_coeff(literal l, int offset); - int get_coeff(bool_var v) const; - int get_abs_coeff(bool_var v) const; + void inc_coeff(literal l, int64 offset); + int64 get_coeff(bool_var v) const; + int64 get_abs_coeff(bool_var v) const; + int get_int_coeff(bool_var v) const; + unsigned get_bound() const; literal get_asserting_literal(literal conseq); - void process_antecedent(literal l, int offset); - void process_card(card& c, int offset); + void process_antecedent(literal l, int64 offset); + void process_card(card& c, int64 offset); void cut(); bool create_asserting_lemma(); @@ -432,6 +440,7 @@ namespace sat { virtual void find_mutexes(literal_vector& lits, vector & mutexes); virtual void pop_reinit(); virtual void gc(); + virtual double get_reward(literal l, ext_justification_idx idx, literal_occs_fun& occs) const; ptr_vector const & constraints() const { return m_constraints; } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index a61c330c7..87f1904ed 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -29,12 +29,19 @@ namespace sat { CR_DONE, CR_CONTINUE, CR_GIVEUP }; + class literal_occs_fun { + public: + virtual double operator()(literal l) = 0; + + }; + class extension { public: virtual ~extension() {} virtual void set_solver(solver* s) = 0; virtual void set_lookahead(lookahead* s) = 0; virtual bool propagate(literal l, ext_constraint_idx idx) = 0; + virtual double get_reward(literal l, ext_constraint_idx idx, literal_occs_fun& occs) const = 0; virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0; virtual void asserted(literal l) = 0; virtual check_result check() = 0; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 5dadd0b73..b5229dc54 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -852,6 +852,8 @@ namespace sat { copy_clauses(m_s.m_clauses); copy_clauses(m_s.m_learned); + m_config.m_use_ternary_reward &= !m_s.m_ext; + // copy units unsigned trail_sz = m_s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { @@ -883,12 +885,10 @@ namespace sat { for (; it != end; ++it) { clause& c = *(*it); if (c.was_removed()) continue; -#if 0 // enable when there is a non-ternary reward system. if (c.size() > 3) { m_config.m_use_ternary_reward = false; } -#endif bool was_eliminated = false; for (unsigned i = 0; !was_eliminated && i < c.size(); ++i) { was_eliminated = m_s.was_eliminated(c[i].var()); @@ -1042,6 +1042,14 @@ namespace sat { // Only the size indicator needs to be updated on backtracking. // + class lookahead_literal_occs_fun : public literal_occs_fun { + lookahead& lh; + public: + lookahead_literal_occs_fun(lookahead& lh): lh(lh) {} + double operator()(literal l) { return lh.literal_occs(l); } + }; + + void lookahead::propagate_clauses(literal l) { SASSERT(is_true(l)); if (inconsistent()) return; @@ -1172,6 +1180,10 @@ namespace sat { case watched::EXT_CONSTRAINT: { SASSERT(m_s.m_ext); bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); + if (m_search_mode == lookahead_mode::lookahead1) { + lookahead_literal_occs_fun literal_occs_fn(*this); + m_lookahead_reward += m_s.m_ext->get_reward(l, it->get_ext_constraint_idx(), literal_occs_fn); + } if (m_inconsistent) { if (!keep) ++it; set_conflict(); @@ -1222,7 +1234,7 @@ namespace sat { to_add += literal_occs(l); } } - m_lookahead_reward += pow(sz, -2) * to_add; + m_lookahead_reward += pow(0.5, sz) * to_add; } else { m_lookahead_reward = (double)0.001; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 067a95c55..38adc4505 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -402,8 +402,7 @@ namespace sat { literal select_literal(); void update_binary_clause_reward(literal l1, literal l2); void update_nary_clause_reward(clause const& c); - double literal_occs(literal l); - + void set_lookahead_reward(literal l, double f) { m_lits[l.index()].m_lookahead_reward = f; } void inc_lookahead_reward(literal l, double f) { m_lits[l.index()].m_lookahead_reward += f; } double get_lookahead_reward(literal l) const { return m_lits[l.index()].m_lookahead_reward; } @@ -486,6 +485,8 @@ namespace sat { model const& get_model(); void collect_statistics(statistics& st) const; + + double literal_occs(literal l); }; } From 3abc7938761f701a3d91b42da6f0509e8430442c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 7 Jul 2017 11:47:52 -0700 Subject: [PATCH 0197/1283] solve more integer smt problems --- src/util/lp/int_solver.cpp | 40 ++++++++++++++++------------- src/util/lp/int_solver.h | 4 +-- src/util/lp/lp_core_solver_base.hpp | 1 + 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 30bfcae9b..0a5ec6b48 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -11,11 +11,12 @@ void int_solver::fix_non_base_columns() { auto & lcs = m_lar_solver->m_mpq_lar_core_solver; for (unsigned j : lcs.m_r_nbasis) { if (column_is_int_inf(j)) { - set_value(j, floor(lcs.m_r_x[j].x)); + set_value_for_nbasic_column(j, floor(lcs.m_r_x[j].x)); } } if (m_lar_solver->find_feasible_solution() == INFEASIBLE) failed(); + lean_assert(is_feasible() && inf_int_set_is_correct()); } void int_solver::failed() { @@ -307,13 +308,9 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { */ m_lar_solver->pivot_fixed_vars_from_basis(); - lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); - patch_int_infeasible_columns(); - lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); + patch_int_infeasible_columns(); fix_non_base_columns(); - lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); - lean_assert(is_feasible()); - TRACE("arith_int_rows", trace_inf_rows();); + TRACE("arith_int_rows", trace_inf_rows();); if (find_inf_int_base_column() == -1) return lia_move::ok; @@ -363,19 +360,19 @@ void int_solver::move_non_base_vars_to_bounds() { switch (lcs.m_column_types()[j]) { case column_type::boxed: if (val != lcs.m_r_low_bounds()[j] && val != lcs.m_r_upper_bounds()[j]) - set_value(j, lcs.m_r_low_bounds()[j]); + set_value_for_nbasic_column(j, lcs.m_r_low_bounds()[j]); break; case column_type::low_bound: if (val != lcs.m_r_low_bounds()[j]) - set_value(j, lcs.m_r_low_bounds()[j]); + set_value_for_nbasic_column(j, lcs.m_r_low_bounds()[j]); break; case column_type::upper_bound: if (val != lcs.m_r_upper_bounds()[j]) - set_value(j, lcs.m_r_upper_bounds()[j]); + set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); break; default: if (is_int(j) && !val.is_int()) { - set_value(j, impq(floor(val))); + set_value_for_nbasic_column(j, impq(floor(val))); } } } @@ -383,7 +380,8 @@ void int_solver::move_non_base_vars_to_bounds() { -void int_solver::set_value(unsigned j, const impq & new_val) { +void int_solver::set_value_for_nbasic_column(unsigned j, const impq & new_val) { + lean_assert(!is_base(j)); auto & x = m_lar_solver->m_mpq_lar_core_solver.m_r_x[j]; if (!m_old_values_set.contains(j)) { m_old_values_set.insert(j); @@ -392,7 +390,12 @@ void int_solver::set_value(unsigned j, const impq & new_val) { auto delta = new_val - x; x = new_val; m_lar_solver->change_basic_x_by_delta_on_column(j, delta); - update_column_in_inf_set_set(j); + update_column_in_int_inf_set(j); + auto * it = get_column_iterator(j); + unsigned i; + while (it->next(i)) + update_column_in_int_inf_set(m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i]); + delete it; } void int_solver::patch_int_infeasible_columns() { @@ -425,22 +428,23 @@ void int_solver::patch_int_infeasible_columns() { TRACE("patch_int", tout << "patching with l: " << l << '\n';); - set_value(j, l); + set_value_for_nbasic_column(j, l); } else { TRACE("patch_int", tout << "not patching " << l << "\n";); } } else if (!inf_u) { u = m_is_one? floor(u) : m * floor(u / m); - set_value(j, u); + set_value_for_nbasic_column(j, u); TRACE("patch_int", tout << "patching with u: " << u << '\n';); } else { - set_value(j, impq(0)); + set_value_for_nbasic_column(j, impq(0)); TRACE("patch_int", tout << "patching with 0\n";); } - } + lean_assert(is_feasible() && inf_int_set_is_correct()); + } } mpq get_denominators_lcm(iterator_on_row &it) { @@ -777,7 +781,7 @@ void int_solver::init_inf_int_set() { } } -void int_solver::update_column_in_inf_set_set(unsigned j) { +void int_solver::update_column_in_int_inf_set(unsigned j) { if (is_int(j) && (!value_is_int(j))) m_inf_int_set.insert(j); else diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 8259ae128..bac99021b 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -81,7 +81,7 @@ private: bool is_base(unsigned j) const; bool is_boxed(unsigned j) const; bool value_is_int(unsigned j) const; - void set_value(unsigned j, const impq & new_val); + void set_value_for_nbasic_column(unsigned j, const impq & new_val); void fix_non_base_columns(); void failed(); bool is_feasible() const; @@ -89,7 +89,7 @@ private: void display_column(std::ostream & out, unsigned j) const; bool inf_int_set_is_correct() const; void init_inf_int_set(); - void update_column_in_inf_set_set(unsigned j); + void update_column_in_int_inf_set(unsigned j); bool column_is_int_inf(unsigned j) const; void trace_inf_rows() const; int find_inf_int_base_column(); diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index 08ba5d251..f4d7c3770 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -963,6 +963,7 @@ template void lp_core_solver_base::pivot_fixed_v unsigned jj; if (get_column_type(ii) != column_type::fixed) continue; + //todo run over the row here!!!!! while (j < m_nbasis.size()) { for (; j < m_nbasis.size(); j++) { jj = m_nbasis[j]; From 55f54b4fdc874c16dc0789f1d8f442bfc302044b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Jul 2017 13:53:26 -0700 Subject: [PATCH 0198/1283] fixing overflow checking Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 125 +++++++++++++++++++++++++----------------- src/sat/ba_solver.h | 11 ++-- 2 files changed, 80 insertions(+), 56 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index eab579ff1..7f2ae5e89 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -873,38 +873,40 @@ namespace sat { m_active_vars.shrink(j); } - void ba_solver::inc_coeff(literal l, int64 offset) { + void ba_solver::inc_coeff(literal l, unsigned offset) { SASSERT(offset > 0); bool_var v = l.var(); SASSERT(v != null_bool_var); - if (static_cast(m_coeffs.size()) <= v) { - m_coeffs.resize(v + 1, 0); - } + m_coeffs.reserve(v + 1, 0); + int64 coeff0 = m_coeffs[v]; if (coeff0 == 0) { m_active_vars.push_back(v); } - int64 inc = l.sign() ? -offset : offset; + int64 loffset = static_cast(offset); + int64 inc = l.sign() ? -loffset : loffset; int64 coeff1 = inc + coeff0; m_coeffs[v] = coeff1; if (coeff1 > INT_MAX || coeff1 < INT_MIN) { - std::cout << "overflow update coefficient " << coeff1 << "\n"; + std::cout << "overflow update coefficient " << coeff1 << " offset: " << offset << " coeff0: " << coeff0 << "\n"; + UNREACHABLE(); m_overflow = true; return; } if (coeff0 > 0 && inc < 0) { - m_bound -= coeff0 - std::max(0LL, coeff1); + inc_bound(std::max(0LL, coeff1) - coeff0); } else if (coeff0 < 0 && inc > 0) { - m_bound -= std::min(0LL, coeff1) - coeff0; + inc_bound(coeff0 - std::min(0LL, coeff1)); } + // reduce coefficient to be no larger than bound. - if (coeff1 > m_bound) { + if (coeff1 > static_cast(m_bound)) { m_coeffs[v] = m_bound; } - else if (coeff1 < 0 && -coeff1 > m_bound) { + else if (coeff1 < 0 && -coeff1 > static_cast(m_bound)) { m_coeffs[v] = m_bound; } } @@ -913,8 +915,13 @@ namespace sat { return m_coeffs.get(v, 0); } - int64 ba_solver::get_abs_coeff(bool_var v) const { - return abs(get_coeff(v)); + unsigned ba_solver::get_abs_coeff(bool_var v) const { + int64 c = get_coeff(v); + if (c < INT_MIN+1 || c > UINT_MAX) { + m_overflow = true; + return UINT_MAX; + } + return static_cast(abs(c)); } int ba_solver::get_int_coeff(bool_var v) const { @@ -927,13 +934,22 @@ namespace sat { return static_cast(c); } - unsigned ba_solver::get_bound() const { - if (m_bound < 0 || m_bound > UINT_MAX) { - std::cout << "overflow bound " << m_bound << "\n"; + void ba_solver::inc_bound(int64 i) { + if (i < INT_MIN || i > INT_MAX) { m_overflow = true; - return 1; + return; + } + int64 new_bound = m_bound; + new_bound += i; + if (new_bound < 0) { + m_bound = 0; + } + else if (new_bound > UINT_MAX) { + m_overflow = true; + } + else { + m_bound = static_cast(new_bound); } - return static_cast(m_bound); } void ba_solver::reset_coeffs() { @@ -965,14 +981,14 @@ namespace sat { } literal_vector const& lits = s().m_trail; unsigned idx = lits.size() - 1; - int64 offset = 1; + unsigned offset = 1; DEBUG_CODE(active2pb(m_A);); unsigned init_marks = m_num_marks; do { - if (m_overflow || offset > (1 << 12)) { + if (m_overflow || offset > (1 << 12) || m_bound == 0) { IF_VERBOSE(20, verbose_stream() << "offset: " << offset << "\n"; active2pb(m_A); display(verbose_stream(), m_A); @@ -987,9 +1003,8 @@ namespace sat { TRACE("sat_verbose", display(tout, m_A);); TRACE("sat", tout << "process consequent: " << consequent << ":\n"; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); - SASSERT(m_bound >= 0); - DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); + // DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); if (_debug_conflict) { std::cout << consequent << "\n"; @@ -1000,23 +1015,23 @@ namespace sat { switch(js.get_kind()) { case justification::NONE: SASSERT (consequent != null_literal); - m_bound += offset; + inc_bound(offset); break; case justification::BINARY: - m_bound += offset; + inc_bound(offset); SASSERT (consequent != null_literal); inc_coeff(consequent, offset); process_antecedent(js.get_literal(), offset); break; case justification::TERNARY: - m_bound += offset; + inc_bound(offset); SASSERT (consequent != null_literal); inc_coeff(consequent, offset); process_antecedent(js.get_literal1(), offset); process_antecedent(js.get_literal2(), offset); break; case justification::CLAUSE: { - m_bound += offset; + inc_bound(offset); clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); unsigned i = 0; if (consequent != null_literal) { @@ -1041,14 +1056,14 @@ namespace sat { switch (cnstr.tag()) { case card_t: { card& c = cnstr.to_card(); - m_bound += offset * c.k(); + inc_bound(static_cast(offset) * c.k()); process_card(c, offset); break; } case pb_t: { pb& p = cnstr.to_pb(); m_lemma.reset(); - m_bound += offset; + inc_bound(offset); inc_coeff(consequent, offset); get_antecedents(consequent, p, m_lemma); TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";); @@ -1062,7 +1077,7 @@ namespace sat { case xor_t: { // jus.push_back(js); m_lemma.reset(); - m_bound += offset; + inc_bound(offset); inc_coeff(consequent, offset); get_xor_antecedents(consequent, idx, js, m_lemma); for (literal l : m_lemma) process_antecedent(~l, offset); @@ -1115,7 +1130,8 @@ namespace sat { js = s().m_justification[v]; offset = get_abs_coeff(v); if (offset > m_bound) { - m_coeffs[v] = (get_coeff(v) < 0) ? -m_bound : m_bound; + int64 bound64 = static_cast(m_bound); + m_coeffs[v] = (get_coeff(v) < 0) ? -bound64 : bound64; offset = m_bound; DEBUG_CODE(active2pb(m_A);); } @@ -1196,8 +1212,8 @@ namespace sat { bool ba_solver::create_asserting_lemma() { adjust_conflict_level: - - int64 slack = -m_bound; + int64 bound64 = m_bound; + int64 slack = -bound64; for (bool_var v : m_active_vars) { slack += get_abs_coeff(v); } @@ -1214,6 +1230,7 @@ namespace sat { bool append = coeff != 0 && val != l_undef && (coeff < 0 == is_true); if (append) { literal lit(v, !is_true); + unsigned acoeff = get_abs_coeff(v); if (lvl(lit) == m_conflict_lvl) { if (m_lemma[0] == null_literal) { asserting_coeff = abs(coeff); @@ -1269,31 +1286,30 @@ namespace sat { if (1 == get_abs_coeff(v)) return; } - SASSERT(0 <= m_bound && m_bound <= UINT_MAX); - unsigned g = 0; for (unsigned i = 0; g != 1 && i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; - int64 coeff = get_abs_coeff(v); + unsigned coeff = get_abs_coeff(v); if (coeff == 0) { continue; } - if (m_bound < coeff) { + if (m_bound < coeff) { + int64 bound64 = m_bound; if (get_coeff(v) > 0) { - m_coeffs[v] = m_bound; + m_coeffs[v] = bound64; } else { - m_coeffs[v] = -m_bound; + m_coeffs[v] = -bound64; } coeff = m_bound; } SASSERT(0 < coeff && coeff <= m_bound); if (g == 0) { - g = static_cast(coeff); + g = coeff; } else { - g = u_gcd(g, static_cast(coeff)); + g = u_gcd(g, coeff); } } @@ -1307,7 +1323,7 @@ namespace sat { } } - void ba_solver::process_card(card& c, int64 offset) { + void ba_solver::process_card(card& c, unsigned offset) { literal lit = c.lit(); SASSERT(c.k() <= c.size()); SASSERT(lit == null_literal || value(lit) == l_true); @@ -1319,11 +1335,18 @@ namespace sat { inc_coeff(c[i], offset); } if (lit != null_literal) { - process_antecedent(~lit, c.k() * offset); + uint64 offset1 = static_cast(offset) * c.k(); + if (offset1 > UINT_MAX) { + m_overflow = true; + std::cout << "cardinality offset overflow\n"; + } + else { + process_antecedent(~lit, static_cast(offset1)); + } } } - void ba_solver::process_antecedent(literal l, int64 offset) { + void ba_solver::process_antecedent(literal l, unsigned offset) { SASSERT(value(l) == l_false); bool_var v = l.var(); unsigned level = lvl(v); @@ -3286,7 +3309,8 @@ namespace sat { } bool ba_solver::validate_lemma() { - int64 val = -m_bound; + int64 bound64 = m_bound; + int64 val = -bound64; reset_active_var_set(); for (bool_var v : m_active_vars) { if (m_active_var_set.contains(v)) continue; @@ -3326,7 +3350,7 @@ namespace sat { ba_solver::constraint* ba_solver::active2constraint() { reset_active_var_set(); svector wlits; - uint64_t sum = 0; + uint64 sum = 0; if (m_bound == 1) return 0; if (m_overflow) return 0; @@ -3335,16 +3359,15 @@ namespace sat { if (m_active_var_set.contains(v) || coeff == 0) continue; m_active_var_set.insert(v); literal lit(v, coeff < 0); - wlits.push_back(wliteral(abs(coeff), lit)); - sum += abs(coeff); + wlits.push_back(wliteral(get_abs_coeff(v), lit)); + sum += get_abs_coeff(v); } - unsigned k = get_bound(); if (m_overflow || sum >= UINT_MAX/2) { return 0; } else { - return add_pb_ge(null_literal, wlits, k, true); + return add_pb_ge(null_literal, wlits, m_bound, true); } } @@ -3384,11 +3407,11 @@ namespace sat { svector wlits; for (bool_var v : m_active_vars) { int coeff = get_int_coeff(v); - wlits.push_back(std::make_pair(abs(coeff), literal(v, coeff < 0))); + wlits.push_back(std::make_pair(get_abs_coeff(v), literal(v, coeff < 0))); } std::sort(wlits.begin(), wlits.end(), compare_wlit()); unsigned k = 0; - int sum = 0, sum0 = 0; + uint64 sum = 0, sum0 = 0; for (wliteral wl : wlits) { if (sum >= m_bound) break; sum0 = sum; @@ -3400,7 +3423,7 @@ namespace sat { } while (!wlits.empty()) { wliteral wl = wlits.back(); - if (wl.first + sum0 >= get_bound()) break; + if (wl.first + sum0 >= m_bound) break; wlits.pop_back(); sum0 += wl.first; } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index c30fd25b4..93c6f14e1 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -215,7 +215,7 @@ namespace sat { unsigned m_conflict_lvl; svector m_coeffs; svector m_active_vars; - int64 m_bound; + unsigned m_bound; tracked_uint_set m_active_var_set; literal_vector m_lemma; literal_vector m_skipped; @@ -366,15 +366,16 @@ namespace sat { mutable bool m_overflow; void reset_active_var_set(); void normalize_active_coeffs(); - void inc_coeff(literal l, int64 offset); + void inc_coeff(literal l, unsigned offset); int64 get_coeff(bool_var v) const; - int64 get_abs_coeff(bool_var v) const; + unsigned get_abs_coeff(bool_var v) const; int get_int_coeff(bool_var v) const; unsigned get_bound() const; + void inc_bound(int64 i); literal get_asserting_literal(literal conseq); - void process_antecedent(literal l, int64 offset); - void process_card(card& c, int64 offset); + void process_antecedent(literal l, unsigned offset); + void process_card(card& c, unsigned offset); void cut(); bool create_asserting_lemma(); From f6a75600c29d5a3e6d545d9db7048ad45ad222ff Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 7 Jul 2017 22:15:47 -0700 Subject: [PATCH 0199/1283] solve all smt2 from QF_LIA/calypto with int_solver Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 19 +++++-- src/util/lp/lar_core_solver.hpp | 18 +------ src/util/lp/lar_solver.cpp | 4 ++ src/util/lp/lp_core_solver_base.h | 12 +++++ src/util/lp/lp_core_solver_base.hpp | 53 +++++++++++++------ src/util/lp/lp_core_solver_base_instances.cpp | 1 + 6 files changed, 69 insertions(+), 38 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 0a5ec6b48..eb31119b9 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -8,15 +8,21 @@ namespace lean { void int_solver::fix_non_base_columns() { + lean_assert(is_feasible() && inf_int_set_is_correct()); auto & lcs = m_lar_solver->m_mpq_lar_core_solver; + bool change = false; for (unsigned j : lcs.m_r_nbasis) { if (column_is_int_inf(j)) { + change = true; set_value_for_nbasic_column(j, floor(lcs.m_r_x[j].x)); } } + if (!change) + return; if (m_lar_solver->find_feasible_solution() == INFEASIBLE) failed(); - lean_assert(is_feasible() && inf_int_set_is_correct()); + init_inf_int_set(); + lean_assert(is_feasible() && inf_int_set_is_correct()); } void int_solver::failed() { @@ -390,8 +396,9 @@ void int_solver::set_value_for_nbasic_column(unsigned j, const impq & new_val) { auto delta = new_val - x; x = new_val; m_lar_solver->change_basic_x_by_delta_on_column(j, delta); - update_column_in_int_inf_set(j); + auto * it = get_column_iterator(j); + update_column_in_int_inf_set(j); unsigned i; while (it->next(i)) update_column_in_int_inf_set(m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i]); @@ -711,7 +718,7 @@ bool int_solver::get_freedom_interval_for_column(unsigned x_j, bool & inf_l, imp else { if (x_i_upper) { impq new_l = x_j_val + ((x_i_val - lcs.m_r_upper_bounds()[x_i]) / a_ij); - set_lower(l, inf_u, new_l); + set_lower(l, inf_l, new_l); if (!inf_l && !inf_u && l == u) break;; } if (x_i_lower) { @@ -730,7 +737,11 @@ bool int_solver::get_freedom_interval_for_column(unsigned x_j, bool & inf_l, imp if (inf_l) tout << "-oo"; else tout << l; tout << "; "; if (inf_u) tout << "oo"; else tout << u; - tout << "]\n";); + tout << "]\n"; + tout << "val = " << get_value(x_j) << "\n"; + ); + lean_assert(inf_l || l <= get_value(x_j)); + lean_assert(inf_u || u >= get_value(x_j)); return true; } diff --git a/src/util/lp/lar_core_solver.hpp b/src/util/lp/lar_core_solver.hpp index a6dd7e3e0..38c522446 100644 --- a/src/util/lp/lar_core_solver.hpp +++ b/src/util/lp/lar_core_solver.hpp @@ -145,23 +145,7 @@ int lar_core_solver::column_is_out_of_bounds(unsigned j) { void lar_core_solver::calculate_pivot_row(unsigned i) { - lean_assert(!m_r_solver.use_tableau()); - lean_assert(m_r_solver.m_pivot_row.is_OK()); - m_r_solver.m_pivot_row_of_B_1.clear(); - m_r_solver.m_pivot_row_of_B_1.resize(m_r_solver.m_m()); - m_r_solver.m_pivot_row.clear(); - m_r_solver.m_pivot_row.resize(m_r_solver.m_n()); - if (m_r_solver.m_settings.use_tableau()) { - unsigned basis_j = m_r_solver.m_basis[i]; - for (auto & c : m_r_solver.m_A.m_rows[i]) { - if (c.m_j != basis_j) - m_r_solver.m_pivot_row.set_value(c.get_val(), c.m_j); - } - return; - } - - m_r_solver.calculate_pivot_row_of_B_1(i); - m_r_solver.calculate_pivot_row_when_pivot_row_of_B1_is_ready(i); + m_r_solver.calculate_pivot_row(i); } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index def72734c..eff44d1cd 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -648,6 +648,10 @@ void lar_solver::change_basic_x_by_delta_on_column(unsigned j, const numeric_pai m_basic_columns_with_changed_cost.insert(bj); } m_mpq_lar_core_solver.m_r_solver.update_column_in_inf_set(bj); + TRACE("change_x_del", + tout << "changed basis column " << bj << ", it is " << + ( m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj)? "feas":"inf") << std::endl;); + } } else { m_column_buffer.clear(); diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 7313a46de..7599a9d2d 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -13,6 +13,9 @@ #include "util/lp/lu.h" #include "util/lp/permutation_matrix.h" #include "util/lp/column_namer.h" +#include "util/lp/iterator_on_row.h" +#include "util/lp/iterator_on_pivot_row.h" + namespace lean { template // X represents the type of the x variable and the bounds @@ -688,5 +691,14 @@ public: const unsigned & iters_with_no_cost_growing() const { return m_iters_with_no_cost_growing; } + + linear_combination_iterator * get_iterator_on_row(unsigned i) { + if (m_settings.use_tableau()) + return new iterator_on_row(m_A.m_rows[i]); + calculate_pivot_row(i); + return new iterator_on_pivot_row(m_pivot_row, m_basis[i]); + } + + void calculate_pivot_row(unsigned i); }; } diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index f4d7c3770..48494d207 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -956,26 +956,23 @@ template void lp_core_solver_base::pivot_fixed_v // run over basis and non-basis at the same time indexed_vector w(m_basis.size()); // the buffer unsigned i = 0; // points to basis - unsigned j = 0; // points to nonbasis - - for (; i < m_basis.size() && j < m_nbasis.size(); i++) { - unsigned ii = m_basis[i]; - unsigned jj; + for (; i < m_basis.size(); i++) { + unsigned basic_j = m_basis[i]; - if (get_column_type(ii) != column_type::fixed) continue; - //todo run over the row here!!!!! - while (j < m_nbasis.size()) { - for (; j < m_nbasis.size(); j++) { - jj = m_nbasis[j]; - if (get_column_type(jj) != column_type::fixed) + if (get_column_type(basic_j) != column_type::fixed) continue; + //todo run over the row here!!!!! call get_iterator_on_row(); + T a; + unsigned j; + auto * it = get_iterator_on_row(i); + while (it->next(a, j)) { + if (j == basic_j) + continue; + if (get_column_type(j) != column_type::fixed) { + if (pivot_column_general(j, basic_j, w)) break; } - if (j >= m_nbasis.size()) - break; - j++; - if (pivot_column_general(jj, ii, w)) - break; - } + } + delete it; } } @@ -1033,4 +1030,26 @@ lp_core_solver_base::infeasibility_cost_is_correct_for_column(unsigned j) } } +template +void lp_core_solver_base::calculate_pivot_row(unsigned i) { + lean_assert(!use_tableau()); + lean_assert(m_pivot_row.is_OK()); + m_pivot_row_of_B_1.clear(); + m_pivot_row_of_B_1.resize(m_m()); + m_pivot_row.clear(); + m_pivot_row.resize(m_n()); + if (m_settings.use_tableau()) { + unsigned basis_j = m_basis[i]; + for (auto & c : m_A.m_rows[i]) { + if (c.m_j != basis_j) + m_pivot_row.set_value(c.get_val(), c.m_j); + } + return; + } + + calculate_pivot_row_of_B_1(i); + calculate_pivot_row_when_pivot_row_of_B1_is_ready(i); +} + + } diff --git a/src/util/lp/lp_core_solver_base_instances.cpp b/src/util/lp/lp_core_solver_base_instances.cpp index 17dcb87db..d473594c8 100644 --- a/src/util/lp/lp_core_solver_base_instances.cpp +++ b/src/util/lp/lp_core_solver_base_instances.cpp @@ -129,3 +129,4 @@ template bool lean::lp_core_solver_base::inf_set_is_correc template bool lean::lp_core_solver_base >::infeasibility_costs_are_correct() const; template bool lean::lp_core_solver_base::infeasibility_costs_are_correct() const; template bool lean::lp_core_solver_base::infeasibility_costs_are_correct() const; +template void lean::lp_core_solver_base >::calculate_pivot_row(unsigned int); From cc32e45471c4564d606e574649eefb89af59946f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 10 Jul 2017 11:06:37 -0700 Subject: [PATCH 0200/1283] replace lean to lp Signed-off-by: Lev Nachmanson --- src/shell/lp_frontend.cpp | 12 +- src/smt/theory_lra.cpp | 336 ++++++------- src/test/lp/argument_parser.h | 2 +- src/test/lp/lp.cpp | 466 +++++++++--------- src/test/lp/lp_main.cpp | 4 +- src/test/lp/smt_reader.h | 30 +- src/test/lp/test_file_reader.h | 2 +- src/util/lp/binary_heap_priority_queue.h | 4 +- src/util/lp/binary_heap_priority_queue.hpp | 18 +- .../binary_heap_priority_queue_instances.cpp | 6 +- src/util/lp/binary_heap_upair_queue.h | 2 +- src/util/lp/binary_heap_upair_queue.hpp | 8 +- .../lp/binary_heap_upair_queue_instances.cpp | 2 +- src/util/lp/bound_analyzer_on_row.h | 12 +- src/util/lp/bound_propagator.cpp | 2 +- src/util/lp/bound_propagator.h | 4 +- src/util/lp/breakpoint.h | 2 +- src/util/lp/column_info.h | 8 +- src/util/lp/column_namer.h | 2 +- src/util/lp/conversion_helper.h | 2 +- src/util/lp/core_solver_pretty_printer.h | 2 +- src/util/lp/core_solver_pretty_printer.hpp | 8 +- .../core_solver_pretty_printer_instances.cpp | 18 +- src/util/lp/dense_matrix.h | 4 +- src/util/lp/dense_matrix.hpp | 4 +- src/util/lp/dense_matrix_instances.cpp | 32 +- src/util/lp/eta_matrix.h | 4 +- src/util/lp/eta_matrix.hpp | 10 +- src/util/lp/eta_matrix_instances.cpp | 36 +- src/util/lp/hash_helper.h | 4 +- src/util/lp/implied_bound.h | 2 +- src/util/lp/indexed_value.h | 2 +- src/util/lp/indexed_vector.h | 6 +- src/util/lp/indexed_vector.hpp | 6 +- src/util/lp/indexed_vector_instances.cpp | 26 +- src/util/lp/int_set.h | 4 +- src/util/lp/int_solver.cpp | 38 +- src/util/lp/int_solver.h | 2 +- src/util/lp/iterator_on_column.h | 2 +- src/util/lp/iterator_on_indexed_vector.h | 2 +- src/util/lp/iterator_on_pivot_row.h | 2 +- src/util/lp/iterator_on_row.h | 2 +- src/util/lp/iterator_on_term_with_basis_var.h | 2 +- src/util/lp/lar_constraints.h | 6 +- src/util/lp/lar_core_solver.h | 88 ++-- src/util/lp/lar_core_solver.hpp | 36 +- src/util/lp/lar_solution_signature.h | 2 +- src/util/lp/lar_solver.cpp | 282 +++++------ src/util/lp/lar_solver.h | 6 +- src/util/lp/lar_solver_instances.cpp | 2 +- src/util/lp/lar_term.h | 2 +- src/util/lp/linear_combination_iterator.h | 2 +- src/util/lp/lp_core_solver_base.h | 32 +- src/util/lp/lp_core_solver_base.hpp | 74 +-- src/util/lp/lp_core_solver_base_instances.cpp | 224 ++++----- src/util/lp/lp_dual_core_solver.h | 2 +- src/util/lp/lp_dual_core_solver.hpp | 62 +-- src/util/lp/lp_dual_core_solver_instances.cpp | 22 +- src/util/lp/lp_dual_simplex.h | 2 +- src/util/lp/lp_dual_simplex.hpp | 32 +- src/util/lp/lp_dual_simplex_instances.cpp | 8 +- src/util/lp/lp_primal_core_solver.h | 78 +-- src/util/lp/lp_primal_core_solver.hpp | 130 ++--- .../lp/lp_primal_core_solver_instances.cpp | 12 +- src/util/lp/lp_primal_core_solver_tableau.hpp | 52 +- src/util/lp/lp_primal_simplex.h | 2 +- src/util/lp/lp_primal_simplex.hpp | 24 +- src/util/lp/lp_primal_simplex_instances.cpp | 20 +- src/util/lp/lp_settings.h | 4 +- src/util/lp/lp_settings.hpp | 8 +- src/util/lp/lp_settings_instances.cpp | 4 +- src/util/lp/lp_solver.h | 4 +- src/util/lp/lp_solver.hpp | 32 +- src/util/lp/lp_solver_instances.cpp | 68 +-- src/util/lp/lp_utils.cpp | 2 +- src/util/lp/lp_utils.h | 24 +- src/util/lp/lu.h | 14 +- src/util/lp/lu.hpp | 96 ++-- src/util/lp/lu_instances.cpp | 98 ++-- src/util/lp/matrix.h | 2 +- src/util/lp/matrix.hpp | 2 +- src/util/lp/matrix_instances.cpp | 12 +- src/util/lp/mps_reader.h | 18 +- src/util/lp/nra_solver.cpp | 40 +- src/util/lp/nra_solver.h | 10 +- src/util/lp/numeric_pair.h | 30 +- src/util/lp/permutation_matrix.h | 4 +- src/util/lp/permutation_matrix.hpp | 40 +- src/util/lp/permutation_matrix_instances.cpp | 92 ++-- src/util/lp/quick_xplain.cpp | 16 +- src/util/lp/quick_xplain.h | 2 +- src/util/lp/random_updater.h | 2 +- src/util/lp/random_updater.hpp | 38 +- src/util/lp/row_eta_matrix.h | 4 +- src/util/lp/row_eta_matrix.hpp | 16 +- src/util/lp/row_eta_matrix_instances.cpp | 2 +- src/util/lp/scaler.h | 4 +- src/util/lp/scaler.hpp | 8 +- src/util/lp/scaler_instances.cpp | 4 +- src/util/lp/signature_bound_evidence.h | 2 +- src/util/lp/sparse_matrix.h | 18 +- src/util/lp/sparse_matrix.hpp | 96 ++-- src/util/lp/sparse_matrix_instances.cpp | 58 +-- src/util/lp/sparse_vector.h | 4 +- src/util/lp/square_dense_submatrix.h | 22 +- src/util/lp/square_dense_submatrix.hpp | 34 +- .../lp/square_dense_submatrix_instances.cpp | 46 +- src/util/lp/stacked_map.h | 14 +- src/util/lp/stacked_unordered_set.h | 4 +- src/util/lp/stacked_value.h | 2 +- src/util/lp/stacked_vector.h | 22 +- src/util/lp/static_matrix.h | 26 +- src/util/lp/static_matrix.hpp | 36 +- src/util/lp/static_matrix_instances.cpp | 14 +- src/util/lp/tail_matrix.h | 2 +- src/util/lp/test_bound_analyzer.h | 6 +- src/util/lp/ul_pair.h | 2 +- 117 files changed, 1726 insertions(+), 1726 deletions(-) diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index 213f94cb2..694205395 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -17,7 +17,7 @@ Author: #include "gparams.h" #include -static lean::lp_solver* g_solver = 0; +static lp::lp_solver* g_solver = 0; static void display_statistics() { if (g_solver && g_solver->settings().print_statistics) { @@ -42,7 +42,7 @@ static void on_timeout() { } } -struct front_end_resource_limit : public lean::lp_resource_limit { +struct front_end_resource_limit : public lp::lp_resource_limit { reslimit& m_reslim; front_end_resource_limit(reslimit& lim): @@ -64,14 +64,14 @@ void run_solver(lp_params & params, char const * mps_file_name) { scoped_timer timer(timeout, &eh); std::string fn(mps_file_name); - lean::mps_reader reader(fn); + lp::mps_reader reader(fn); reader.set_message_stream(&std::cout); // can be redirected reader.read(); if (!reader.is_ok()) { std::cerr << "cannot process " << mps_file_name << std::endl; return; } - lean::lp_solver * solver = reader.create_solver(false); // false - to create the primal solver + lp::lp_solver * solver = reader.create_solver(false); // false - to create the primal solver solver->settings().set_resource_limit(lp_limit); g_solver = solver; if (params.min()) { @@ -80,11 +80,11 @@ void run_solver(lp_params & params, char const * mps_file_name) { solver->settings().set_message_ostream(&std::cout); solver->settings().report_frequency = params.rep_freq(); solver->settings().print_statistics = params.print_stats(); - solver->settings().simplex_strategy() = lean::simplex_strategy_enum::lu; + solver->settings().simplex_strategy() = lp::simplex_strategy_enum::lu; solver->find_maximal_solution(); *(solver->settings().get_message_ostream()) << "status is " << lp_status_to_string(solver->get_status()) << std::endl; - if (solver->get_status() == lean::OPTIMAL) { + if (solver->get_status() == lp::OPTIMAL) { if (params.min()) { solver->flip_costs(); } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 6144447e3..72654de18 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -40,7 +40,7 @@ Revision History: #include "math/polynomial/algebraic_numbers.h" #include "math/polynomial/polynomial.h" -namespace lp { +namespace lp_api { enum bound_kind { lower_t, upper_t }; std::ostream& operator<<(std::ostream& out, bound_kind const& k) { @@ -118,7 +118,7 @@ namespace lp { namespace smt { - typedef ptr_vector lp_bounds; + typedef ptr_vector lp_bounds; class theory_lra::imp { @@ -137,7 +137,7 @@ namespace smt { delayed_atom(unsigned b, bool t): m_bv(b), m_is_true(t) {} }; - class resource_limit : public lean::lp_resource_limit { + class resource_limit : public lp::lp_resource_limit { imp& m_imp; public: resource_limit(imp& i): m_imp(i) { } @@ -202,13 +202,13 @@ namespace smt { } }; - typedef vector> var_coeffs; + typedef vector> var_coeffs; - svector m_theory_var2var_index; // translate from theory variables to lar vars + svector m_theory_var2var_index; // translate from theory variables to lar vars svector m_var_index2theory_var; // reverse map from lp_solver variables to theory variables svector m_term_index2theory_var; // reverse map from lp_solver variables to theory variables var_coeffs m_left_side; // constraint left side - mutable std::unordered_map m_variable_values; // current model + mutable std::unordered_map m_variable_values; // current model enum constraint_source { inequality_source, @@ -225,10 +225,10 @@ namespace smt { expr* m_not_handled; ptr_vector m_underspecified; unsigned_vector m_var_trail; - vector > m_use_list; // bounds where variables are used. + vector > m_use_list; // bounds where variables are used. // attributes for incremental version: - u_map m_bool_var2bound; + u_map m_bool_var2bound; vector m_bounds; unsigned_vector m_unassigned_bounds; unsigned_vector m_bounds_trail; @@ -247,7 +247,7 @@ namespace smt { scoped_ptr m_a1, m_a2; // integer arithmetic - scoped_ptr m_lia; + scoped_ptr m_lia; struct var_value_eq { @@ -268,7 +268,7 @@ namespace smt { return m_th.is_int(v); } else { - return (unsigned)std::hash()(m_th.get_ivalue(v)); + return (unsigned)std::hash()(m_th.get_ivalue(v)); } } }; @@ -276,9 +276,9 @@ namespace smt { svector m_scopes; - lp::stats m_stats; + lp_api::stats m_stats; arith_factory* m_factory; - scoped_ptr m_solver; + scoped_ptr m_solver; resource_limit m_resource_limit; lp_bounds m_new_bounds; @@ -294,15 +294,15 @@ namespace smt { void init_solver() { if (m_solver) return; lp_params lp(ctx().get_params()); - m_solver = alloc(lean::lar_solver); + m_solver = alloc(lp::lar_solver); m_theory_var2var_index.reset(); m_solver->settings().set_resource_limit(m_resource_limit); - m_solver->settings().simplex_strategy() = static_cast(lp.simplex_strategy()); + m_solver->settings().simplex_strategy() = static_cast(lp.simplex_strategy()); reset_variable_values(); m_solver->settings().bound_propagation() = BP_NONE != propagation_mode(); m_solver->set_propagate_bounds_on_pivoted_rows_mode(lp.bprop_on_pivoted_rows()); //m_solver->settings().set_ostream(0); - m_lia = alloc(lean::int_solver, m_solver.get()); + m_lia = alloc(lp::int_solver, m_solver.get()); } void ensure_nra() { @@ -454,7 +454,7 @@ namespace smt { r = rational::one(); rational r1; v = mk_var(t); - svector vars; + svector vars; ptr_vector todo; todo.push_back(t); while (!todo.empty()) { @@ -556,8 +556,8 @@ namespace smt { return v; } - lean::var_index get_var_index(theory_var v) { - lean::var_index result = UINT_MAX; + lp::var_index get_var_index(theory_var v) { + lp::var_index result = UINT_MAX; if (m_theory_var2var_index.size() > static_cast(v)) { result = m_theory_var2var_index[v]; } @@ -606,20 +606,20 @@ namespace smt { return true; } - void add_eq_constraint(lean::constraint_index index, enode* n1, enode* n2) { + void add_eq_constraint(lp::constraint_index index, enode* n1, enode* n2) { m_constraint_sources.setx(index, equality_source, null_source); m_equalities.setx(index, enode_pair(n1, n2), enode_pair(0, 0)); ++m_stats.m_add_rows; } - void add_ineq_constraint(lean::constraint_index index, literal lit) { + void add_ineq_constraint(lp::constraint_index index, literal lit) { m_constraint_sources.setx(index, inequality_source, null_source); m_inequalities.setx(index, lit, null_literal); ++m_stats.m_add_rows; TRACE("arith", m_solver->print_constraint(index, tout); tout << "\n";); } - void add_def_constraint(lean::constraint_index index, theory_var v) { + void add_def_constraint(lp::constraint_index index, theory_var v) { m_constraint_sources.setx(index, definition_source, null_source); m_definitions.setx(index, v, null_theory_var); ++m_stats.m_add_rows; @@ -634,7 +634,7 @@ namespace smt { st.coeffs().push_back(rational::one()); st.coeffs().push_back(rational::minus_one()); init_left_side(st); - add_eq_constraint(m_solver->add_constraint(m_left_side, lean::EQ, rational::zero()), n1, n2); + add_eq_constraint(m_solver->add_constraint(m_left_side, lp::EQ, rational::zero()), n1, n2); TRACE("arith", tout << "v" << v1 << " = " << "v" << v2 << ": " << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << "\n";); @@ -644,7 +644,7 @@ namespace smt { for (unsigned i = m_bounds_trail.size(); i > old_size; ) { --i; unsigned v = m_bounds_trail[i]; - lp::bound* b = m_bounds[v].back(); + lp_api::bound* b = m_bounds[v].back(); // del_use_lists(b); dealloc(b); m_bounds[v].pop_back(); @@ -687,7 +687,7 @@ namespace smt { else { init_left_side(st); theory_var v = mk_var(term); - lean::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); + lp::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); if (vi == UINT_MAX) { vi = m_solver->add_term(m_left_side, st.coeff()); m_theory_var2var_index.setx(v, vi, UINT_MAX); @@ -747,22 +747,22 @@ namespace smt { ctx().set_var_theory(bv, get_id()); expr* n1, *n2; rational r; - lp::bound_kind k; + lp_api::bound_kind k; theory_var v = null_theory_var; if (a.is_le(atom, n1, n2) && is_numeral(n2, r) && is_app(n1)) { v = internalize_def(to_app(n1)); - k = lp::upper_t; + k = lp_api::upper_t; } else if (a.is_ge(atom, n1, n2) && is_numeral(n2, r) && is_app(n1)) { v = internalize_def(to_app(n1)); - k = lp::lower_t; + k = lp_api::lower_t; } else { TRACE("arith", tout << "Could not internalize " << mk_pp(atom, m) << "\n";); found_not_handled(atom); return true; } - lp::bound* b = alloc(lp::bound, bv, v, is_int(v), r, k); + lp_api::bound* b = alloc(lp_api::bound, bv, v, is_int(v), r, k); m_bounds[v].push_back(b); updt_unassigned_bounds(v, +1); m_bounds_trail.push_back(v); @@ -836,7 +836,7 @@ namespace smt { unsigned old_size = m_scopes.size() - num_scopes; del_bounds(m_scopes[old_size].m_bounds_lim); for (unsigned i = m_scopes[old_size].m_var_trail_lim; i < m_var_trail.size(); ++i) { - lean::var_index vi = m_theory_var2var_index[m_var_trail[i]]; + lp::var_index vi = m_theory_var2var_index[m_var_trail[i]]; if (m_solver->is_term(vi)) { unsigned ti = m_solver->adjust_term_index(vi); m_term_index2theory_var[ti] = UINT_MAX; @@ -1027,14 +1027,14 @@ namespace smt { return m_solver->var_is_registered(m_theory_var2var_index[v]); } - lean::impq get_ivalue(theory_var v) const { - lean_assert(can_get_ivalue(v)); - lean::var_index vi = m_theory_var2var_index[v]; + lp::impq get_ivalue(theory_var v) const { + lp_assert(can_get_ivalue(v)); + lp::var_index vi = m_theory_var2var_index[v]; if (!m_solver->is_term(vi)) return m_solver->get_value(vi); - const lean::lar_term& term = m_solver->get_term(vi); - lean::impq result(term.m_v); + const lp::lar_term& term = m_solver->get_term(vi); + lp::impq result(term.m_v); for (const auto & i: term.m_coeffs) { result += m_solver->get_value(i.first) * i.second; } @@ -1044,12 +1044,12 @@ namespace smt { rational get_value(theory_var v) const { if (!can_get_value(v)) return rational::zero(); - lean::var_index vi = m_theory_var2var_index[v]; + 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)) { - const lean::lar_term& term = m_solver->get_term(vi); + const lp::lar_term& term = m_solver->get_term(vi); rational result = term.m_v; for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { result += m_variable_values[i->first] * i->second; @@ -1072,7 +1072,7 @@ namespace smt { } bool assume_eqs() { - svector vars; + svector vars; theory_var sz = static_cast(th.get_num_vars()); for (theory_var v = 0; v < sz; ++v) { if (th.is_relevant_and_shared(get_enode(v))) { @@ -1167,7 +1167,7 @@ namespace smt { final_check_status final_check_eh() { m_use_nra_model = false; lbool is_sat = l_true; - if (m_solver->get_status() != lean::lp_status::OPTIMAL) { + if (m_solver->get_status() != lp::lp_status::OPTIMAL) { is_sat = make_feasible(); } final_check_status st = FC_DONE; @@ -1223,7 +1223,7 @@ namespace smt { } // create a bound atom representing term <= k - app_ref mk_bound(lean::lar_term const& term, rational const& k) { + app_ref mk_bound(lp::lar_term const& term, rational const& k) { SASSERT(k.is_int()); app_ref t = mk_term(term, true); app_ref atom(a.mk_le(t, a.mk_numeral(k, true)), m); @@ -1238,20 +1238,20 @@ namespace smt { lbool check_lia() { if (m.canceled()) return l_undef; - lean::lar_term term; - lean::mpq k; - lean::explanation ex; // TBD, this should be streamlined accross different explanations + lp::lar_term term; + lp::mpq k; + lp::explanation ex; // TBD, this should be streamlined accross different explanations switch(m_lia->check(term, k, ex)) { - case lean::lia_move::ok: + case lp::lia_move::ok: return l_true; - case lean::lia_move::branch: { + case lp::lia_move::branch: { (void)mk_bound(term, k); // branch on term <= k // at this point we have a new unassigned atom that the // SAT core assigns a value to return l_false; } - case lean::lia_move::cut: { + case lp::lia_move::cut: { // m_explanation implies term <= k app_ref b = mk_bound(term, k); m_eqs.reset(); @@ -1265,12 +1265,12 @@ namespace smt { assign(literal(ctx().get_bool_var(b), false)); return l_false; } - case lean::lia_move::conflict: + case lp::lia_move::conflict: // ex contains unsat core m_explanation = ex.m_explanation; set_conflict1(); return l_false; - case lean::lia_move::give_up: + case lp::lia_move::give_up: TRACE("arith", tout << "lia giveup\n";); return l_undef; default: @@ -1375,7 +1375,7 @@ namespace smt { #else propagate_bound(bv, is_true, b); #endif - lp::bound& b = *m_bool_var2bound.find(bv); + lp_api::bound& b = *m_bool_var2bound.find(bv); assert_bound(bv, is_true, b); @@ -1388,7 +1388,7 @@ namespace smt { /*for (; qhead < m_asserted_atoms.size() && !ctx().inconsistent(); ++qhead) { bool_var bv = m_asserted_atoms[qhead].m_bv; bool is_true = m_asserted_atoms[qhead].m_is_true; - lp::bound& b = *m_bool_var2bound.find(bv); + lp_api::bound& b = *m_bool_var2bound.find(bv); propagate_bound_compound(bv, is_true, b); }*/ @@ -1421,7 +1421,7 @@ namespace smt { } int new_num_of_p = m_solver->settings().st().m_num_of_implied_bounds; CTRACE("arith", new_num_of_p > num_of_p, tout << "found " << new_num_of_p << " implied bounds\n";); - if (m_solver->get_status() == lean::lp_status::INFEASIBLE) { + if (m_solver->get_status() == lp::lp_status::INFEASIBLE) { set_conflict(); } else { @@ -1431,7 +1431,7 @@ namespace smt { } } - bool bound_is_interesting(unsigned vi, lean::lconstraint_kind kind, const rational & bval) const { + bool bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational & bval) const { theory_var v; if (m_solver->is_term(vi)) { v = m_term_index2theory_var.get(m_solver->adjust_term_index(vi), null_theory_var); @@ -1448,7 +1448,7 @@ namespace smt { } lp_bounds const& bounds = m_bounds[v]; for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound* b = bounds[i]; + lp_api::bound* b = bounds[i]; if (ctx().get_assignment(b->get_bv()) != l_undef) { continue; } @@ -1461,11 +1461,11 @@ namespace smt { return false; } - struct local_bound_propagator: public lean::bound_propagator { + struct local_bound_propagator: public lp::bound_propagator { imp & m_imp; local_bound_propagator(imp& i) : bound_propagator(*i.m_solver), m_imp(i) {} - bool bound_is_interesting(unsigned j, lean::lconstraint_kind kind, const rational & v) { + bool bound_is_interesting(unsigned j, lp::lconstraint_kind kind, const rational & v) { return m_imp.bound_is_interesting(j, kind, v); } @@ -1475,10 +1475,10 @@ namespace smt { }; - void propagate_lp_solver_bound(lean::implied_bound& be) { + void propagate_lp_solver_bound(lp::implied_bound& be) { theory_var v; - lean::var_index vi = be.m_j; + lp::var_index vi = be.m_j; if (m_solver->is_term(vi)) { v = m_term_index2theory_var.get(m_solver->adjust_term_index(vi), null_theory_var); } @@ -1499,7 +1499,7 @@ namespace smt { lp_bounds const& bounds = m_bounds[v]; bool first = true; for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound* b = bounds[i]; + lp_api::bound* b = bounds[i]; if (ctx().get_assignment(b->get_bv()) != l_undef) { continue; } @@ -1562,28 +1562,28 @@ namespace smt { } } - literal is_bound_implied(lean::lconstraint_kind k, rational const& value, lp::bound const& b) const { - if ((k == lean::LE || k == lean::LT) && b.get_bound_kind() == lp::upper_t && value <= b.get_value()) { + literal is_bound_implied(lp::lconstraint_kind k, rational const& value, lp_api::bound const& b) const { + if ((k == lp::LE || k == lp::LT) && b.get_bound_kind() == lp_api::upper_t && value <= b.get_value()) { // v <= value <= b.get_value() => v <= b.get_value() return literal(b.get_bv(), false); } - if ((k == lean::GE || k == lean::GT) && b.get_bound_kind() == lp::lower_t && b.get_value() <= value) { + if ((k == lp::GE || k == lp::GT) && b.get_bound_kind() == lp_api::lower_t && b.get_value() <= value) { // b.get_value() <= value <= v => b.get_value() <= v return literal(b.get_bv(), false); } - if (k == lean::LE && b.get_bound_kind() == lp::lower_t && value < b.get_value()) { + if (k == lp::LE && b.get_bound_kind() == lp_api::lower_t && value < b.get_value()) { // v <= value < b.get_value() => v < b.get_value() return literal(b.get_bv(), true); } - if (k == lean::LT && b.get_bound_kind() == lp::lower_t && value <= b.get_value()) { + if (k == lp::LT && b.get_bound_kind() == lp_api::lower_t && value <= b.get_value()) { // v < value <= b.get_value() => v < b.get_value() return literal(b.get_bv(), true); } - if (k == lean::GE && b.get_bound_kind() == lp::upper_t && b.get_value() < value) { + if (k == lp::GE && b.get_bound_kind() == lp_api::upper_t && b.get_value() < value) { // b.get_value() < value <= v => b.get_value() < v return literal(b.get_bv(), true); } - if (k == lean::GT && b.get_bound_kind() == lp::upper_t && b.get_value() <= value) { + if (k == lp::GT && b.get_bound_kind() == lp_api::upper_t && b.get_value() <= value) { // b.get_value() <= value < v => b.get_value() < v return literal(b.get_bv(), true); } @@ -1591,7 +1591,7 @@ namespace smt { return null_literal; } - void mk_bound_axioms(lp::bound& b) { + void mk_bound_axioms(lp_api::bound& b) { if (!ctx().is_searching()) { // // NB. We make an assumption that user push calls propagation @@ -1602,19 +1602,19 @@ namespace smt { return; } theory_var v = b.get_var(); - lp::bound_kind kind1 = b.get_bound_kind(); + lp_api::bound_kind kind1 = b.get_bound_kind(); rational const& k1 = b.get_value(); lp_bounds & bounds = m_bounds[v]; - lp::bound* end = 0; - lp::bound* lo_inf = end, *lo_sup = end; - lp::bound* hi_inf = end, *hi_sup = end; + lp_api::bound* end = 0; + 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::bound& other = *bounds[i]; + lp_api::bound& other = *bounds[i]; if (&other == &b) continue; if (b.get_bv() == other.get_bv()) continue; - lp::bound_kind kind2 = other.get_bound_kind(); + lp_api::bound_kind kind2 = other.get_bound_kind(); rational const& k2 = other.get_value(); if (k1 == k2 && kind1 == kind2) { // the bounds are equivalent. @@ -1622,7 +1622,7 @@ namespace smt { } SASSERT(k1 != k2 || kind1 != kind2); - if (kind2 == lp::lower_t) { + if (kind2 == lp_api::lower_t) { if (k2 < k1) { if (lo_inf == end || k2 > lo_inf->get_value()) { lo_inf = &other; @@ -1648,14 +1648,14 @@ namespace smt { } - void mk_bound_axiom(lp::bound& b1, lp::bound& b2) { + void mk_bound_axiom(lp_api::bound& b1, lp_api::bound& b2) { theory_var v = b1.get_var(); literal l1(b1.get_bv()); literal l2(b2.get_bv()); rational const& k1 = b1.get_value(); rational const& k2 = b2.get_value(); - lp::bound_kind kind1 = b1.get_bound_kind(); - lp::bound_kind kind2 = b2.get_bound_kind(); + lp_api::bound_kind kind1 = b1.get_bound_kind(); + lp_api::bound_kind kind2 = b2.get_bound_kind(); bool v_is_int = is_int(v); SASSERT(v == b2.get_var()); if (k1 == k2 && kind1 == kind2) return; @@ -1663,8 +1663,8 @@ namespace smt { parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; - if (kind1 == lp::lower_t) { - if (kind2 == lp::lower_t) { + if (kind1 == lp_api::lower_t) { + if (kind2 == lp_api::lower_t) { if (k2 <= k1) { mk_clause(~l1, l2, 3, coeffs); } @@ -1685,7 +1685,7 @@ namespace smt { } } } - else if (kind2 == lp::lower_t) { + else if (kind2 == lp_api::lower_t) { if (k1 >= k2) { // k1 >= lo_inf, k1 >= x or lo_inf <= x mk_clause(l1, l2, 3, coeffs); @@ -1743,21 +1743,21 @@ namespace smt { iterator begin1 = occs.begin(); iterator begin2 = occs.begin(); iterator end = occs.end(); - begin1 = first(lp::lower_t, begin1, end); - begin2 = first(lp::upper_t, begin2, end); + begin1 = first(lp_api::lower_t, begin1, end); + begin2 = first(lp_api::upper_t, begin2, end); iterator lo_inf = begin1, lo_sup = begin1; iterator hi_inf = begin2, hi_sup = begin2; iterator lo_inf1 = begin1, lo_sup1 = begin1; iterator hi_inf1 = begin2, hi_sup1 = begin2; bool flo_inf, fhi_inf, flo_sup, fhi_sup; - ptr_addr_hashtable visited; + ptr_addr_hashtable visited; for (unsigned i = 0; i < atoms.size(); ++i) { - lp::bound* a1 = atoms[i]; - lo_inf1 = next_inf(a1, lp::lower_t, lo_inf, end, flo_inf); - hi_inf1 = next_inf(a1, lp::upper_t, hi_inf, end, fhi_inf); - lo_sup1 = next_sup(a1, lp::lower_t, lo_sup, end, flo_sup); - hi_sup1 = next_sup(a1, lp::upper_t, hi_sup, end, fhi_sup); + lp_api::bound* a1 = atoms[i]; + lo_inf1 = next_inf(a1, lp_api::lower_t, lo_inf, end, flo_inf); + hi_inf1 = next_inf(a1, lp_api::upper_t, hi_inf, end, fhi_inf); + lo_sup1 = next_sup(a1, lp_api::lower_t, lo_sup, end, flo_sup); + hi_sup1 = next_sup(a1, lp_api::upper_t, hi_sup, end, fhi_sup); if (lo_inf1 != end) lo_inf = lo_inf1; if (lo_sup1 != end) lo_sup = lo_sup1; if (hi_inf1 != end) hi_inf = hi_inf1; @@ -1776,24 +1776,24 @@ namespace smt { } struct compare_bounds { - bool operator()(lp::bound* a1, lp::bound* a2) const { return a1->get_value() < a2->get_value(); } + bool operator()(lp_api::bound* a1, lp_api::bound* a2) const { return a1->get_value() < a2->get_value(); } }; lp_bounds::iterator first( - lp::bound_kind kind, + lp_api::bound_kind kind, iterator it, iterator end) { for (; it != end; ++it) { - lp::bound* a = *it; + lp_api::bound* a = *it; if (a->get_bound_kind() == kind) return it; } return end; } lp_bounds::iterator next_inf( - lp::bound* a1, - lp::bound_kind kind, + lp_api::bound* a1, + lp_api::bound_kind kind, iterator it, iterator end, bool& found_compatible) { @@ -1801,7 +1801,7 @@ namespace smt { iterator result = end; found_compatible = false; for (; it != end; ++it) { - lp::bound * a2 = *it; + lp_api::bound * a2 = *it; if (a1 == a2) continue; if (a2->get_bound_kind() != kind) continue; rational const & k2(a2->get_value()); @@ -1817,15 +1817,15 @@ namespace smt { } lp_bounds::iterator next_sup( - lp::bound* a1, - lp::bound_kind kind, + lp_api::bound* a1, + lp_api::bound_kind kind, iterator it, iterator end, bool& found_compatible) { rational const & k1(a1->get_value()); found_compatible = false; for (; it != end; ++it) { - lp::bound * a2 = *it; + lp_api::bound * a2 = *it; if (a1 == a2) continue; if (a2->get_bound_kind() != kind) continue; rational const & k2(a2->get_value()); @@ -1839,7 +1839,7 @@ namespace smt { void propagate_basic_bounds() { for (auto const& bv : m_to_check) { - lp::bound& b = *m_bool_var2bound.find(bv); + lp_api::bound& b = *m_bool_var2bound.find(bv); propagate_bound(bv, ctx().get_assignment(bv) == l_true, b); if (ctx().inconsistent()) break; @@ -1854,11 +1854,11 @@ namespace smt { // x <= hi -> x <= hi' // x <= hi -> ~(x >= hi') - void propagate_bound(bool_var bv, bool is_true, lp::bound& b) { + void propagate_bound(bool_var bv, bool is_true, lp_api::bound& b) { if (BP_NONE == propagation_mode()) { return; } - lp::bound_kind k = b.get_bound_kind(); + lp_api::bound_kind k = b.get_bound_kind(); theory_var v = b.get_var(); inf_rational val = b.get_value(is_true); lp_bounds const& bounds = m_bounds[v]; @@ -1868,12 +1868,12 @@ namespace smt { literal lit1(bv, !is_true); literal lit2 = null_literal; - bool find_glb = (is_true == (k == lp::lower_t)); + bool find_glb = (is_true == (k == lp_api::lower_t)); if (find_glb) { rational glb; - lp::bound* lb = 0; + lp_api::bound* lb = 0; for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound* b2 = bounds[i]; + lp_api::bound* b2 = bounds[i]; if (b2 == &b) continue; rational const& val2 = b2->get_value(); if ((is_true ? val2 < val : val2 <= val) && (!lb || glb < val2)) { @@ -1882,14 +1882,14 @@ namespace smt { } } if (!lb) return; - bool sign = lb->get_bound_kind() != lp::lower_t; + bool sign = lb->get_bound_kind() != lp_api::lower_t; lit2 = literal(lb->get_bv(), sign); } else { rational lub; - lp::bound* ub = 0; + lp_api::bound* ub = 0; for (unsigned i = 0; i < bounds.size(); ++i) { - lp::bound* b2 = bounds[i]; + lp_api::bound* b2 = bounds[i]; if (b2 == &b) continue; rational const& val2 = b2->get_value(); if ((is_true ? val < val2 : val <= val2) && (!ub || val2 < lub)) { @@ -1898,7 +1898,7 @@ namespace smt { } } if (!ub) return; - bool sign = ub->get_bound_kind() != lp::upper_t; + bool sign = ub->get_bound_kind() != lp_api::upper_t; lit2 = literal(ub->get_bv(), sign); } TRACE("arith", @@ -1918,27 +1918,27 @@ namespace smt { ++m_stats.m_bounds_propagations; } - void add_use_lists(lp::bound* b) { + void add_use_lists(lp_api::bound* b) { theory_var v = b->get_var(); - lean::var_index vi = get_var_index(v); + lp::var_index vi = get_var_index(v); if (m_solver->is_term(vi)) { - lean::lar_term const& term = m_solver->get_term(vi); + lp::lar_term const& term = m_solver->get_term(vi); for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { - lean::var_index wi = i->first; + lp::var_index wi = i->first; unsigned w = m_var_index2theory_var[wi]; - m_use_list.reserve(w + 1, ptr_vector()); + m_use_list.reserve(w + 1, ptr_vector()); m_use_list[w].push_back(b); } } } - void del_use_lists(lp::bound* b) { + void del_use_lists(lp_api::bound* b) { theory_var v = b->get_var(); - lean::var_index vi = m_theory_var2var_index[v]; + lp::var_index vi = m_theory_var2var_index[v]; if (m_solver->is_term(vi)) { - lean::lar_term const& term = m_solver->get_term(vi); + lp::lar_term const& term = m_solver->get_term(vi); for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { - lean::var_index wi = i->first; + lp::var_index wi = i->first; unsigned w = m_var_index2theory_var[wi]; SASSERT(m_use_list[w].back() == b); m_use_list[w].pop_back(); @@ -1952,7 +1952,7 @@ namespace smt { // have been assigned we may know the truth value of the inequality by using simple // bounds propagation. // - void propagate_bound_compound(bool_var bv, bool is_true, lp::bound& b) { + void propagate_bound_compound(bool_var bv, bool is_true, lp_api::bound& b) { theory_var v = b.get_var(); TRACE("arith", tout << mk_pp(get_owner(v), m) << "\n";); if (static_cast(v) >= m_use_list.size()) { @@ -1968,7 +1968,7 @@ namespace smt { // x >= 0, y >= 1 -> x + y >= 1 // x <= 0, y <= 2 -> x + y <= 2 literal lit = null_literal; - if (lp::lower_t == vb->get_bound_kind()) { + if (lp_api::lower_t == vb->get_bound_kind()) { if (get_glb(*vb, r) && r >= vb->get_value()) { // vb is assigned true lit = literal(vb->get_bv(), false); } @@ -2002,30 +2002,30 @@ namespace smt { } } - bool get_lub(lp::bound const& b, inf_rational& lub) { + bool get_lub(lp_api::bound const& b, inf_rational& lub) { return get_bound(b, lub, true); } - bool get_glb(lp::bound const& b, inf_rational& glb) { + bool get_glb(lp_api::bound const& b, inf_rational& glb) { return get_bound(b, glb, false); } - std::ostream& display_bound(std::ostream& out, lp::bound const& b) { + std::ostream& display_bound(std::ostream& out, lp_api::bound const& b) { return out << mk_pp(ctx().bool_var2expr(b.get_bv()), m); } - bool get_bound(lp::bound const& b, inf_rational& r, bool is_lub) { + bool get_bound(lp_api::bound const& b, inf_rational& r, bool is_lub) { m_core.reset(); m_eqs.reset(); m_params.reset(); r.reset(); theory_var v = b.get_var(); - lean::var_index vi = m_theory_var2var_index[v]; + lp::var_index vi = m_theory_var2var_index[v]; SASSERT(m_solver->is_term(vi)); - lean::lar_term const& term = m_solver->get_term(vi); + lp::lar_term const& term = m_solver->get_term(vi); for (auto const coeff : term.m_coeffs) { - lean::var_index wi = coeff.first; - lean::constraint_index ci; + lp::var_index wi = coeff.first; + lp::constraint_index ci; rational value; bool is_strict; if (coeff.second.is_neg() == is_lub) { @@ -2052,25 +2052,25 @@ namespace smt { return true; } - void assert_bound(bool_var bv, bool is_true, lp::bound& b) { - if (m_solver->get_status() == lean::lp_status::INFEASIBLE) { + void assert_bound(bool_var bv, bool is_true, lp_api::bound& b) { + if (m_solver->get_status() == lp::lp_status::INFEASIBLE) { return; } scoped_internalize_state st(*this); st.vars().push_back(b.get_var()); st.coeffs().push_back(rational::one()); init_left_side(st); - lean::lconstraint_kind k = lean::EQ; + lp::lconstraint_kind k = lp::EQ; bool is_int = b.is_int(); switch (b.get_bound_kind()) { - case lp::lower_t: - k = is_true ? lean::GE : (is_int ? lean::LE : lean::LT); + case lp_api::lower_t: + k = is_true ? lp::GE : (is_int ? lp::LE : lp::LT); break; - case lp::upper_t: - k = is_true ? lean::LE : (is_int ? lean::GE : lean::GT); + case lp_api::upper_t: + k = is_true ? lp::LE : (is_int ? lp::GE : lp::GT); break; } - if (k == lean::LT || k == lean::LE) { + if (k == lp::LT || k == lp::LE) { ++m_stats.m_assert_lower; } else { @@ -2078,7 +2078,7 @@ namespace smt { } auto vi = get_var_index(b.get_var()); rational bound = b.get_value(); - lean::constraint_index ci; + lp::constraint_index ci; if (is_int && !is_true) { rational bound = b.get_value(false).get_rational(); ci = m_solver->add_var_bound(vi, k, bound); @@ -2099,7 +2099,7 @@ namespace smt { // Then the equality v1 == v2 is propagated to the core. // - typedef std::pair constraint_bound; + typedef std::pair constraint_bound; vector m_lower_terms; vector m_upper_terms; typedef std::pair value_sort_pair; @@ -2107,16 +2107,16 @@ namespace smt { typedef map > value2var; value2var m_fixed_var_table; - void propagate_eqs(lean::var_index vi, lean::constraint_index ci, lean::lconstraint_kind k, lp::bound& b) { + void propagate_eqs(lp::var_index vi, lp::constraint_index ci, lp::lconstraint_kind k, lp_api::bound& b) { if (propagate_eqs()) { rational const& value = b.get_value(); - if (k == lean::GE) { + if (k == lp::GE) { set_lower_bound(vi, ci, value); if (has_upper_bound(vi, ci, value)) { fixed_var_eh(b.get_var(), value); } } - else if (k == lean::LE) { + else if (k == lp::LE) { set_upper_bound(vi, ci, value); if (has_lower_bound(vi, ci, value)) { fixed_var_eh(b.get_var(), value); @@ -2137,16 +2137,16 @@ namespace smt { bool use_tableau() const { return lp_params(ctx().get_params()).simplex_strategy() < 2; } - void set_upper_bound(lean::var_index vi, lean::constraint_index ci, rational const& v) { set_bound(vi, ci, v, false); } + void set_upper_bound(lp::var_index vi, lp::constraint_index ci, rational const& v) { set_bound(vi, ci, v, false); } - void set_lower_bound(lean::var_index vi, lean::constraint_index ci, rational const& v) { set_bound(vi, ci, v, true); } + void set_lower_bound(lp::var_index vi, lp::constraint_index ci, rational const& v) { set_bound(vi, ci, v, true); } - void set_bound(lean::var_index vi, lean::constraint_index ci, rational const& v, bool is_lower) { + void set_bound(lp::var_index vi, lp::constraint_index ci, rational const& v, bool is_lower) { if (!m_solver->is_term(vi)) { // m_solver already tracks bounds on proper variables, but not on terms. return; } - lean::var_index ti = m_solver->adjust_term_index(vi); + lp::var_index ti = m_solver->adjust_term_index(vi); auto& vec = is_lower ? m_lower_terms : m_upper_terms; if (vec.size() <= ti) { vec.resize(ti + 1, constraint_bound(UINT_MAX, rational())); @@ -2159,15 +2159,15 @@ namespace smt { } } - bool has_upper_bound(lean::var_index vi, lean::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, false); } + bool has_upper_bound(lp::var_index vi, lp::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, false); } - bool has_lower_bound(lean::var_index vi, lean::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, true); } + bool has_lower_bound(lp::var_index vi, lp::constraint_index& ci, rational const& bound) { return has_bound(vi, ci, bound, true); } - bool has_bound(lean::var_index vi, lean::constraint_index& ci, rational const& bound, bool is_lower) { + bool has_bound(lp::var_index vi, lp::constraint_index& ci, rational const& bound, bool is_lower) { if (m_solver->is_term(vi)) { - lean::var_index ti = m_solver->adjust_term_index(vi); + lp::var_index ti = m_solver->adjust_term_index(vi); theory_var v = m_term_index2theory_var.get(ti, null_theory_var); rational val; TRACE("arith", tout << vi << " " << v << "\n";); @@ -2210,7 +2210,7 @@ namespace smt { if (static_cast(v2) < th.get_num_vars() && !is_equal(v1, v2)) { auto vi1 = get_var_index(v1); auto vi2 = get_var_index(v2); - lean::constraint_index ci1, ci2, ci3, ci4; + lp::constraint_index ci1, ci2, ci3, ci4; TRACE("arith", tout << "fixed: " << mk_pp(get_owner(v1), m) << " " << mk_pp(get_owner(v2), m) << " " << bound << " " << has_lower_bound(vi2, ci3, bound) << "\n";); if (has_lower_bound(vi2, ci3, bound) && has_upper_bound(vi2, ci4, bound)) { VERIFY (has_lower_bound(vi1, ci1, bound)); @@ -2260,13 +2260,13 @@ namespace smt { auto status = m_solver->find_feasible_solution(); TRACE("arith_verbose", display(tout);); switch (status) { - case lean::lp_status::INFEASIBLE: + case lp::lp_status::INFEASIBLE: return l_false; - case lean::lp_status::FEASIBLE: - case lean::lp_status::OPTIMAL: + case lp::lp_status::FEASIBLE: + case lp::lp_status::OPTIMAL: // SASSERT(m_solver->all_constraints_hold()); return l_true; - case lean::lp_status::TIME_EXHAUSTED: + case lp::lp_status::TIME_EXHAUSTED: default: TRACE("arith", tout << "status treated as inconclusive: " << status << "\n";); @@ -2276,14 +2276,14 @@ namespace smt { } } - vector> m_explanation; + vector> m_explanation; literal_vector m_core; svector m_eqs; vector m_params; - // lean::constraint_index const null_constraint_index = UINT_MAX; // not sure what a correct fix is + // lp::constraint_index const null_constraint_index = UINT_MAX; // not sure what a correct fix is - void set_evidence(lean::constraint_index idx) { + void set_evidence(lp::constraint_index idx) { if (idx == UINT_MAX) { return; } @@ -2371,14 +2371,14 @@ namespace smt { nlsat::anum const& nl_value(theory_var v, scoped_anum& r) { SASSERT(m_nra); SASSERT(m_use_nra_model); - lean::var_index vi = m_theory_var2var_index[v]; + lp::var_index vi = m_theory_var2var_index[v]; if (m_solver->is_term(vi)) { - lean::lar_term const& term = m_solver->get_term(vi); + lp::lar_term const& term = m_solver->get_term(vi); scoped_anum r1(m_nra->am()); m_nra->am().set(r, term.m_v.to_mpq()); for (auto const coeff : term.m_coeffs) { - lean::var_index wi = coeff.first; + lp::var_index wi = coeff.first; m_nra->am().set(r1, coeff.second.to_mpq()); m_nra->am().mul(m_nra->value(wi), r1, r1); m_nra->am().add(r1, r, r); @@ -2474,16 +2474,16 @@ namespace smt { } theory_lra::inf_eps value(theory_var v) { - lean::impq ival = get_ivalue(v); + lp::impq ival = get_ivalue(v); return inf_eps(0, inf_rational(ival.x, ival.y)); } theory_lra::inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) { - lean::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); - vector > coeffs; + lp::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); + vector > coeffs; rational coeff; if (m_solver->is_term(vi)) { - const lean::lar_term& term = m_solver->get_term(vi); + const lp::lar_term& term = m_solver->get_term(vi); for (auto & ti : term.m_coeffs) { coeffs.push_back(std::make_pair(ti.second, ti.first)); } @@ -2493,7 +2493,7 @@ namespace smt { coeffs.push_back(std::make_pair(rational::one(), vi)); coeff = rational::zero(); } - lean::impq term_max; + lp::impq term_max; if (m_solver->maximize_term(coeffs, term_max)) { blocker = mk_gt(v); inf_rational val(term_max.x + coeff, term_max.y); @@ -2508,7 +2508,7 @@ namespace smt { } expr_ref mk_gt(theory_var v) { - lean::impq val = get_ivalue(v); + lp::impq val = get_ivalue(v); expr* obj = get_enode(v)->get_owner(); rational r = val.x; expr_ref e(m); @@ -2539,7 +2539,7 @@ namespace smt { return internalize_def(term); } - app_ref mk_term(lean::lar_term const& term, bool is_int) { + app_ref mk_term(lp::lar_term const& term, bool is_int) { expr_ref_vector args(m); for (auto & ti : term.m_coeffs) { theory_var w = m_var_index2theory_var[ti.first]; @@ -2561,7 +2561,7 @@ namespace smt { } app_ref mk_obj(theory_var v) { - lean::var_index vi = m_theory_var2var_index[v]; + lp::var_index vi = m_theory_var2var_index[v]; bool is_int = a.is_int(get_enode(v)->get_owner()); if (m_solver->is_term(vi)) { return mk_term(m_solver->get_term(vi), is_int); @@ -2588,9 +2588,9 @@ namespace smt { bool_var bv = ctx().mk_bool_var(b); ctx().set_var_theory(bv, get_id()); // ctx().set_enode_flag(bv, true); - lp::bound_kind bkind = lp::bound_kind::lower_t; - if (is_strict) bkind = lp::bound_kind::upper_t; - lp::bound* a = alloc(lp::bound, bv, v, is_int, r, bkind); + lp_api::bound_kind bkind = lp_api::bound_kind::lower_t; + if (is_strict) bkind = lp_api::bound_kind::upper_t; + lp_api::bound* a = alloc(lp_api::bound, bv, v, is_int, r, bkind); mk_bound_axioms(*a); updt_unassigned_bounds(v, +1); m_bounds[v].push_back(a); @@ -2622,7 +2622,7 @@ namespace smt { } } - void display_evidence(std::ostream& out, vector> const& evidence) { + void display_evidence(std::ostream& out, vector> const& evidence) { for (auto const& ev : evidence) { expr_ref e(m); SASSERT(!ev.first.is_zero()); diff --git a/src/test/lp/argument_parser.h b/src/test/lp/argument_parser.h index 706167f49..9590baf7b 100644 --- a/src/test/lp/argument_parser.h +++ b/src/test/lp/argument_parser.h @@ -11,7 +11,7 @@ Author: Lev Nachmanson #include #include -namespace lean { +namespace lp { class argument_parser { std::unordered_map m_options; std::unordered_map m_options_with_after_string; diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 71032d013..173bc3b12 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -31,7 +31,7 @@ Author: Lev Nachmanson #include "util/lp/stacked_unordered_set.h" #include "util/lp/int_set.h" #include "util/stopwatch.h" -namespace lean { +namespace lp { unsigned seed = 1; random_gen g_rand; @@ -78,7 +78,7 @@ void test_matrix(sparse_matrix & a) { a.set(i, j, t); - lean_assert(a.get(i, j) == t); + lp_assert(a.get(i, j) == t); unsigned j1; if (j < m - 1) { @@ -170,7 +170,7 @@ vector allocate_basis_heading(unsigned count) { // the rest of initilizatio void init_basic_part_of_basis_heading(vector & basis, vector & basis_heading) { - lean_assert(basis_heading.size() >= basis.size()); + lp_assert(basis_heading.size() >= basis.size()); unsigned m = basis.size(); for (unsigned i = 0; i < m; i++) { unsigned column = basis[i]; @@ -225,7 +225,7 @@ void test_small_lu(lp_settings & settings) { vector non_basic_columns; init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); lu l(m, basis, settings); - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); indexed_vector w(m.row_count()); std::cout << "entering 2, leaving 0" << std::endl; l.prepare_entering(2, w); // to init vector w @@ -235,7 +235,7 @@ void test_small_lu(lp_settings & settings) { // std::cout << "we were factoring " << std::endl; // print_matrix(get_B(l)); // #endif - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); std::cout << "entering 4, leaving 3" << std::endl; l.prepare_entering(4, w); // to init vector w l.replace_column(0, w, heading[3]); @@ -247,7 +247,7 @@ void test_small_lu(lp_settings & settings) { print_matrix(&bl, std::cout); } #endif - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); std::cout << "entering 5, leaving 1" << std::endl; l.prepare_entering(5, w); // to init vector w @@ -260,7 +260,7 @@ void test_small_lu(lp_settings & settings) { print_matrix(&bl, std::cout); } #endif - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); std::cout << "entering 3, leaving 2" << std::endl; l.prepare_entering(3, w); // to init vector w l.replace_column(0, w, heading[2]); @@ -272,7 +272,7 @@ void test_small_lu(lp_settings & settings) { print_matrix(&bl, std::cout); } #endif - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); m.add_row(); m.add_column(); @@ -291,7 +291,7 @@ 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; - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); } #endif @@ -373,7 +373,7 @@ void test_larger_lu_exp(lp_settings & settings) { dense_matrix left_side = l.get_left_side(basis); dense_matrix right_side = l.get_right_side(); - lean_assert(left_side == right_side); + lp_assert(left_side == right_side); int leaving = 3; int entering = 8; for (unsigned i = 0; i < m.row_count(); i++) { @@ -385,12 +385,12 @@ void test_larger_lu_exp(lp_settings & settings) { l.prepare_entering(entering, w); l.replace_column(0, w, heading[leaving]); change_basis(entering, leaving, basis, non_basic_columns, heading); - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); l.prepare_entering(11, w); // to init vector w l.replace_column(0, w, heading[0]); change_basis(11, 0, basis, non_basic_columns, heading); - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); } void test_larger_lu_with_holes(lp_settings & settings) { @@ -432,7 +432,7 @@ void test_larger_lu_with_holes(lp_settings & settings) { l.prepare_entering(8, w); // to init vector w l.replace_column(0, w, heading[0]); change_basis(8, 0, basis, non_basic_columns, heading); - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); } @@ -479,7 +479,7 @@ void test_larger_lu(lp_settings& settings) { l.prepare_entering(9, w); // to init vector w l.replace_column(0, w, heading[0]); change_basis(9, 0, basis, non_basic_columns, heading); - lean_assert(l.is_correct(basis)); + lp_assert(l.is_correct(basis)); } @@ -612,7 +612,7 @@ void test_swap_rows_with_permutation(sparse_matrix& m){ dense_matrix original(&m); permutation_matrix q(dim); print_matrix(m, std::cout); - lean_assert(original == q * m); + lp_assert(original == q * m); for (int i = 0; i < 100; i++) { unsigned row1 = my_random() % dim; unsigned row2 = my_random() % dim; @@ -620,7 +620,7 @@ void test_swap_rows_with_permutation(sparse_matrix& m){ std::cout << "swap " << row1 << " " << row2 << std::endl; m.swap_rows(row1, row2); q.transpose_from_left(row1, row2); - lean_assert(original == q * m); + lp_assert(original == q * m); print_matrix(m, std::cout); std::cout << std::endl; } @@ -636,7 +636,7 @@ void test_swap_cols_with_permutation(sparse_matrix& m){ dense_matrix original(&m); permutation_matrix q(dim); print_matrix(m, std::cout); - lean_assert(original == q * m); + lp_assert(original == q * m); for (int i = 0; i < 100; i++) { unsigned row1 = my_random() % dim; unsigned row2 = my_random() % dim; @@ -644,7 +644,7 @@ void test_swap_cols_with_permutation(sparse_matrix& m){ std::cout << "swap " << row1 << " " << row2 << std::endl; m.swap_rows(row1, row2); q.transpose_from_right(row1, row2); - lean_assert(original == q * m); + lp_assert(original == q * m); print_matrix(m, std::cout); std::cout << std::endl; } @@ -663,8 +663,8 @@ void test_swap_rows(sparse_matrix& m, unsigned i0, unsigned i1){ m.swap_rows(i0, i1); for (unsigned j = 0; j < m.dimension(); j++) { - lean_assert(mcopy(i0, j) == m(i1, j)); - lean_assert(mcopy(i1, j) == m(i0, j)); + lp_assert(mcopy(i0, j) == m(i1, j)); + lp_assert(mcopy(i1, j) == m(i0, j)); } } template @@ -678,15 +678,15 @@ void test_swap_columns(sparse_matrix& m, unsigned i0, unsigned i1){ m.swap_columns(i0, i1); for (unsigned j = 0; j < m.dimension(); j++) { - lean_assert(mcopy(j, i0) == m(j, i1)); - lean_assert(mcopy(j, i1) == m(j, i0)); + lp_assert(mcopy(j, i0) == m(j, i1)); + lp_assert(mcopy(j, i1) == m(j, i0)); } for (unsigned i = 0; i < m.dimension(); i++) { if (i == i0 || i == i1) continue; for (unsigned j = 0; j < m.dimension(); j++) { - lean_assert(mcopy(j, i)== m(j, i)); + lp_assert(mcopy(j, i)== m(j, i)); } } } @@ -748,7 +748,7 @@ void test_pivot_like_swaps_and_pivot(){ m.pivot_row_to_row(pivot_row_0, beta, target_row, settings); // print_matrix(m); for (unsigned j = 0; j < m.dimension(); j++) { - lean_assert(abs(row[j] - m(target_row, j)) < 0.00000001); + lp_assert(abs(row[j] - m(target_row, j)) < 0.00000001); } } @@ -853,57 +853,57 @@ void sparse_matrix_with_permutaions_test() { m.multiply_from_left(q0); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[i], j)); + lp_assert(m(i, j) == dm0.get_elem(q0[i], j)); } } auto q0_dm = q0 * dm; - lean_assert(m == q0_dm); + lp_assert(m == q0_dm); m.multiply_from_left(q1); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], j)); + lp_assert(m(i, j) == dm0.get_elem(q0[q1[i]], j)); } } auto q1_q0_dm = q1 * q0_dm; - lean_assert(m == q1_q0_dm); + lp_assert(m == q1_q0_dm); m.multiply_from_right(p0); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p0[j])); + lp_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p0[j])); } } auto q1_q0_dm_p0 = q1_q0_dm * p0; - lean_assert(m == q1_q0_dm_p0); + lp_assert(m == q1_q0_dm_p0); m.multiply_from_right(p1); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p0[j]])); + lp_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p0[j]])); } } auto q1_q0_dm_p0_p1 = q1_q0_dm_p0 * p1; - lean_assert(m == q1_q0_dm_p0_p1); + lp_assert(m == q1_q0_dm_p0_p1); m.multiply_from_right(p1); for (unsigned i = 0; i < dim; i++) { for (unsigned j = 0; j < dim; j++) { - lean_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p1[p0[j]]])); + lp_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p1[p0[j]]])); } } auto q1_q0_dm_p0_p1_p1 = q1_q0_dm_p0_p1 * p1; - lean_assert(m == q1_q0_dm_p0_p1_p1); + lp_assert(m == q1_q0_dm_p0_p1_p1); } void test_swap_columns() { @@ -1024,7 +1024,7 @@ void test_apply_reverse_from_right_to_perm(permutation_matrix & #ifdef LEAN_DEBUG auto rev = l.get_inverse(); auto rs = pclone * rev; - lean_assert(p == rs) + lp_assert(p == rs) #endif } @@ -1051,8 +1051,8 @@ void test_permutations() { p.apply_reverse_from_right_to_T(v); p.apply_reverse_from_right_to_T(vi); - lean_assert(vectors_are_equal(v, vi.m_data)); - lean_assert(vi.is_OK()); + lp_assert(vectors_are_equal(v, vi.m_data)); + lp_assert(vi.is_OK()); } void lp_solver_test() { @@ -1200,7 +1200,7 @@ void solve_mps_double(std::string file_name, bool look_for_min, unsigned max_ite compare_solutions(reader, primal_solver, solver); print_x(reader, primal_solver); std::cout << "dual cost is " << cost << ", but primal cost is " << primal_cost << std::endl; - lean_assert(false); + lp_assert(false); } } } @@ -1210,7 +1210,7 @@ void solve_mps_double(std::string file_name, bool look_for_min, unsigned max_ite } void solve_mps_rational(std::string file_name, bool look_for_min, unsigned max_iterations, unsigned time_limit, bool dual, argument_parser & args_parser) { - mps_reader reader(file_name); + mps_reader reader(file_name); reader.read(); if (reader.is_ok()) { auto * solver = reader.create_solver(dual); @@ -1224,7 +1224,7 @@ void solve_mps_rational(std::string file_name, bool look_for_min, unsigned max_i // for (auto name: reader.column_names()) { // std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; // } - lean::mpq cost = solver->get_current_cost(); + lp::mpq cost = solver->get_current_cost(); if (look_for_min) { cost = -cost; } @@ -1262,7 +1262,7 @@ void solve_mps(std::string file_name, argument_parser & args_parser) { void solve_mps_in_rational(std::string file_name, bool dual, argument_parser & /*args_parser*/) { std::cout << "solving " << file_name << std::endl; - mps_reader reader(file_name); + mps_reader reader(file_name); reader.read(); if (reader.is_ok()) { auto * solver = reader.create_solver(dual); @@ -1274,7 +1274,7 @@ void solve_mps_in_rational(std::string file_name, bool dual, argument_parser & / std::cout << name << "=" << solver->get_column_value_by_name(name).get_double() << ' '; } } - std::cout << std::endl << "cost = " << numeric_traits::get_double(solver->get_current_cost()) << std::endl; + std::cout << std::endl << "cost = " << numeric_traits::get_double(solver->get_current_cost()) << std::endl; } delete solver; } else { @@ -1318,7 +1318,7 @@ void test_binary_priority_queue() { for (unsigned i = 0; i < 10; i++) { unsigned de = q.dequeue(); - lean_assert(i == de); + lp_assert(i == de); std::cout << de << std::endl; } q.enqueue(2, 2); @@ -1341,7 +1341,7 @@ void test_binary_priority_queue() { unsigned t = 0; while (q.size() > 0) { unsigned d =q.dequeue(); - lean_assert(t++ == d); + lp_assert(t++ == d); std::cout << d << std::endl; } #endif @@ -1370,7 +1370,7 @@ void solve_mps_with_known_solution(std::string file_name, std::unordered_mapget_status()) << std::endl; if (status != solver->get_status()){ std::cout << "status should be " << lp_status_to_string(status) << std::endl; - lean_assert(status == solver->get_status()); + lp_assert(status == solver->get_status()); throw "status is wrong"; } if (solver->get_status() == lp_status::OPTIMAL) { @@ -1381,7 +1381,7 @@ void solve_mps_with_known_solution(std::string file_name, std::unordered_mapget_column_value_by_name(it.first) << std::endl; } - lean_assert(fabs(it.second - solver->get_column_value_by_name(it.first)) < 0.000001); + lp_assert(fabs(it.second - solver->get_column_value_by_name(it.first)) < 0.000001); } } if (reader.column_names().size() < 20) { @@ -1466,127 +1466,127 @@ void fill_file_names(vector &file_names, std::set & m return; } std::string home_dir_str(home_dir); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l0redund.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l1.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l2.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l3.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l4.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l4fix.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/plan.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/samp2.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/murtagh.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/l0.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AFIRO.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC50B.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC50A.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/KB2.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC105.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR1.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ADLITTLE.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BLEND.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCAGR7.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SC205.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHARE2B.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/RECIPELP.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/LOTFI.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/VTP-BASE.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHARE1B.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BOEING2.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BORE3D.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCORPION.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CAPRI.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BRANDY.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCAGR25.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP1.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ISRAEL.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM1.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BANDM.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/E226.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW7.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/ETAMACRO.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FINNIS.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD1.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDATA.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDGUB.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BEACONFD.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STAIR.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STANDMPS.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GFRD-PNC.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCRS8.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BOEING1.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MODSZK1.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DEGEN2.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FORPLAN.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG2.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/AGG3.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM2.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHELL.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT4.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD6.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP04S.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SEBA.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW15.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FFFFF800.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BNL1.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PEROLD.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP8.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCFXM3.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP04L.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GANGES.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP2.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GROW22.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08S.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT-WE.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MAROS.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR2.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/25FV47.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP12S.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCSD8.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT1P.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP3.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SIERRA.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOTNOV.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CZPROB.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT1D.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT-JA.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08L.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/BNL2.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/NESM.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/CYCLE.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/acc-tight5.mps"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/SHIP12L.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DEGEN3.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEA.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEB.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/80BAU3B.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/TRUSS.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/D2Q06C.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/WOODW.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP12.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/D6CUBE.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/DFL001.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/WOOD1P.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT2P.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/PILOT87.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/STOCFOR3.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/QAP15.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/FIT2D.SIF"); - file_names.push_back(home_dir_str + "/projects/lean/src/tests/util/lp/test_files/netlib/MAROS-R7.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/FIT2P.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/DFL001.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/D2Q06C.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/80BAU3B.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEB.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/GREENBEA.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/BNL2.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SHIP08L.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/FIT1D.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCTAP3.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCSD8.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/SCSD6.SIF"); - minimums.insert("/projects/lean/src/tests/util/lp/test_files/netlib/MAROS-R7.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/l0redund.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/l1.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/l2.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/l3.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/l4.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/l4fix.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/plan.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/samp2.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/murtagh.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/l0.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/AFIRO.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SC50B.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SC50A.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/KB2.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SC105.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/STOCFOR1.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/ADLITTLE.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BLEND.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCAGR7.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SC205.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHARE2B.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/RECIPELP.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/LOTFI.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/VTP-BASE.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHARE1B.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BOEING2.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BORE3D.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCORPION.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/CAPRI.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BRANDY.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCAGR25.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCTAP1.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/ISRAEL.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCFXM1.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BANDM.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/E226.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/AGG.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/GROW7.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/ETAMACRO.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/FINNIS.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCSD1.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/STANDATA.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/STANDGUB.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BEACONFD.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/STAIR.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/STANDMPS.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/GFRD-PNC.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCRS8.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BOEING1.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/MODSZK1.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/DEGEN2.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/FORPLAN.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/AGG2.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/AGG3.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCFXM2.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHELL.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/PILOT4.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCSD6.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHIP04S.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SEBA.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/GROW15.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/FFFFF800.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BNL1.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/PEROLD.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/QAP8.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCFXM3.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHIP04L.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/GANGES.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCTAP2.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/GROW22.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHIP08S.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/PILOT-WE.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/MAROS.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/STOCFOR2.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/25FV47.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHIP12S.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCSD8.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/FIT1P.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SCTAP3.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SIERRA.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/PILOTNOV.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/CZPROB.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/FIT1D.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/PILOT-JA.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHIP08L.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/BNL2.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/NESM.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/CYCLE.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/acc-tight5.mps"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/SHIP12L.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/DEGEN3.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/GREENBEA.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/GREENBEB.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/80BAU3B.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/TRUSS.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/D2Q06C.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/WOODW.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/QAP12.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/D6CUBE.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/PILOT.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/DFL001.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/WOOD1P.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/FIT2P.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/PILOT87.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/STOCFOR3.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/QAP15.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/FIT2D.SIF"); + file_names.push_back(home_dir_str + "/projects/lp/src/tests/util/lp/test_files/netlib/MAROS-R7.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/FIT2P.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/DFL001.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/D2Q06C.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/80BAU3B.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/GREENBEB.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/GREENBEA.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/BNL2.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/SHIP08L.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/FIT1D.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/SCTAP3.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/SCSD8.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/SCSD6.SIF"); + minimums.insert("/projects/lp/src/tests/util/lp/test_files/netlib/MAROS-R7.SIF"); } void test_out_dir(std::string out_dir) { @@ -1706,48 +1706,48 @@ void solve_some_mps(argument_parser & args_parser) { #endif void solve_rational() { - lp_primal_simplex solver; - solver.add_constraint(lp_relation::Equal, lean::mpq(7), 0); - solver.add_constraint(lp_relation::Equal, lean::mpq(-3), 1); + lp_primal_simplex solver; + solver.add_constraint(lp_relation::Equal, lp::mpq(7), 0); + solver.add_constraint(lp_relation::Equal, lp::mpq(-3), 1); // setting the cost int cost[] = {-3, -1, -1, 2, -1, 1, 1, -4}; std::string var_names[8] = {"x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8"}; for (unsigned i = 0; i < 8; i++) { - solver.set_cost_for_column(i, lean::mpq(cost[i])); + solver.set_cost_for_column(i, lp::mpq(cost[i])); solver.give_symbolic_name_to_column(var_names[i], i); } int row0[] = {1, 0, 3, 1, -5, -2 , 4, -6}; for (unsigned i = 0; i < 8; i++) { - solver.set_row_column_coefficient(0, i, lean::mpq(row0[i])); + solver.set_row_column_coefficient(0, i, lp::mpq(row0[i])); } int row1[] = {0, 1, -2, -1, 4, 1, -3, 5}; for (unsigned i = 0; i < 8; i++) { - solver.set_row_column_coefficient(1, i, lean::mpq(row1[i])); + solver.set_row_column_coefficient(1, i, lp::mpq(row1[i])); } int bounds[] = {8, 6, 4, 15, 2, 10, 10, 3}; for (unsigned i = 0; i < 8; i++) { - solver.set_low_bound(i, lean::mpq(0)); - solver.set_upper_bound(i, lean::mpq(bounds[i])); + solver.set_low_bound(i, lp::mpq(0)); + solver.set_upper_bound(i, lp::mpq(bounds[i])); } - std::unordered_map expected_sol; - expected_sol["x1"] = lean::mpq(0); - expected_sol["x2"] = lean::mpq(6); - expected_sol["x3"] = lean::mpq(0); - expected_sol["x4"] = lean::mpq(15); - expected_sol["x5"] = lean::mpq(2); - expected_sol["x6"] = lean::mpq(1); - expected_sol["x7"] = lean::mpq(1); - expected_sol["x8"] = lean::mpq(0); + std::unordered_map expected_sol; + expected_sol["x1"] = lp::mpq(0); + expected_sol["x2"] = lp::mpq(6); + expected_sol["x3"] = lp::mpq(0); + expected_sol["x4"] = lp::mpq(15); + expected_sol["x5"] = lp::mpq(2); + expected_sol["x6"] = lp::mpq(1); + expected_sol["x7"] = lp::mpq(1); + expected_sol["x8"] = lp::mpq(0); solver.find_maximal_solution(); - lean_assert(solver.get_status() == OPTIMAL); + lp_assert(solver.get_status() == OPTIMAL); for (auto it : expected_sol) { - lean_assert(it.second == solver.get_column_value_by_name(it.first)); + lp_assert(it.second == solver.get_column_value_by_name(it.first)); } } @@ -1805,7 +1805,7 @@ std::unordered_map * get_solution_from_glpsol_output(std::s return ret; } - lean_assert(split.size() > 3); + lp_assert(split.size() > 3); (*ret)[split[1]] = atof(split[3].c_str()); } while (true); } @@ -1829,7 +1829,7 @@ void test_init_U() { for (unsigned i = 0; i < 3; i++) { for (unsigned j = 0; j < 3; j ++) { - lean_assert(m(i, basis[j]) == u(i, j)); + lp_assert(m(i, basis[j]) == u(i, j)); } } @@ -1857,7 +1857,7 @@ void test_replace_column() { for (unsigned column_to_replace = 0; column_to_replace < m.dimension(); column_to_replace ++) { m.replace_column(column_to_replace, w, settings); for (unsigned i = 0; i < m.dimension(); i++) { - lean_assert(abs(w[i] - m(i, column_to_replace)) < 0.00000001); + lp_assert(abs(w[i] - m(i, column_to_replace)) < 0.00000001); } } } @@ -1961,7 +1961,7 @@ void test_stacked_unsigned() { v = 3; v = 4; v.pop(); - lean_assert(v == 2); + lp_assert(v == 2); v ++; v++; std::cout << "before push v=" << v << std::endl; @@ -1971,7 +1971,7 @@ void test_stacked_unsigned() { v+=1; std::cout << "v = " << v << std::endl; v.pop(2); - lean_assert(v == 4); + lp_assert(v == 4); const unsigned & rr = v; std::cout << rr << std:: endl; @@ -2020,7 +2020,7 @@ void test_stacked_set() { s.push(); s.insert(4); s.pop(); - lean_assert(s() == scopy); + lp_assert(s() == scopy); s.push(); s.push(); s.insert(4); @@ -2028,7 +2028,7 @@ void test_stacked_set() { s.push(); s.insert(4); s.pop(3); - lean_assert(s() == scopy); + lp_assert(s() == scopy); #endif } @@ -2397,15 +2397,15 @@ void test_files_from_directory(std::string test_file_dir, argument_parser & args } -std::unordered_map get_solution_map(lp_solver * lps, mps_reader & reader) { - std::unordered_map ret; +std::unordered_map get_solution_map(lp_solver * lps, mps_reader & reader) { + std::unordered_map ret; for (auto it : reader.column_names()) { ret[it] = lps->get_column_value_by_name(it); } return ret; } -void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_reader * reader) { +void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_reader * reader) { std::string maxng = args_parser.get_option_value("--maxng"); if (maxng.size() > 0) { solver->settings().max_number_of_iterations_with_no_improvements = atoi(maxng.c_str()); @@ -2425,7 +2425,7 @@ void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_read } auto * lps = reader->create_solver(false); lps->find_maximal_solution(); - std::unordered_map sol = get_solution_map(lps, *reader); + std::unordered_map sol = get_solution_map(lps, *reader); std::cout << "status = " << lp_status_to_string(solver->get_status()) << std::endl; return; } @@ -2434,7 +2434,7 @@ void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_read lp_status status = solver->solve(); std::cout << "status is " << lp_status_to_string(status) << ", processed for " << sw.get_current_seconds() <<" seconds, and " << solver->get_total_iterations() << " iterations" << std::endl; if (solver->get_status() == INFEASIBLE) { - vector> evidence; + vector> evidence; solver->get_infeasibility_explanation(evidence); } if (args_parser.option_is_used("--randomize_lar")) { @@ -2467,7 +2467,7 @@ lar_solver * create_lar_solver_from_file(std::string file_name, argument_parser } return reader.create_lar_solver(); } - mps_reader reader(file_name); + mps_reader reader(file_name); reader.read(); if (!reader.is_ok()) { std::cout << "cannot process " << file_name << std::endl; @@ -2478,8 +2478,8 @@ lar_solver * create_lar_solver_from_file(std::string file_name, argument_parser void test_lar_on_file(std::string file_name, argument_parser & args_parser) { lar_solver * solver = create_lar_solver_from_file(file_name, args_parser); - mps_reader reader(file_name); - mps_reader * mps_reader = nullptr; + mps_reader reader(file_name); + mps_reader * mps_reader = nullptr; reader.read(); if (reader.is_ok()) { mps_reader = & reader; @@ -2524,28 +2524,28 @@ void test_lar_solver(argument_parser & args_parser) { } void test_numeric_pair() { - numeric_pair a; - numeric_pair b(2, lean::mpq(6, 2)); + numeric_pair a; + numeric_pair b(2, lp::mpq(6, 2)); a = b; - numeric_pair c(0.1, 0.5); + numeric_pair c(0.1, 0.5); a += 2*c; a -= c; - lean_assert (a == b + c); - numeric_pair d = a * 2; + lp_assert (a == b + c); + numeric_pair d = a * 2; std::cout << a << std::endl; - lean_assert(b == b); - lean_assert(b < a); - lean_assert(b <= a); - lean_assert(a > b); - lean_assert(a != b); - lean_assert(a >= b); - lean_assert(-a < b); - lean_assert(a < 2 * b); - lean_assert(b + b > a); - lean_assert(lean::mpq(2.1) * b + b > a); - lean_assert(-b * lean::mpq(2.1) - b < lean::mpq(0.99) * a); - std::cout << - b * lean::mpq(2.1) - b << std::endl; - lean_assert(-b *(lean::mpq(2.1) + 1) == - b * lean::mpq(2.1) - b); + lp_assert(b == b); + lp_assert(b < a); + lp_assert(b <= a); + lp_assert(a > b); + lp_assert(a != b); + lp_assert(a >= b); + lp_assert(-a < b); + lp_assert(a < 2 * b); + lp_assert(b + b > a); + lp_assert(lp::mpq(2.1) * b + b > a); + lp_assert(-b * lp::mpq(2.1) - b < lp::mpq(0.99) * a); + std::cout << - b * lp::mpq(2.1) - b << std::endl; + lp_assert(-b *(lp::mpq(2.1) + 1) == - b * lp::mpq(2.1) - b); } void get_matrix_dimensions(std::ifstream & f, unsigned & m, unsigned & n) { @@ -2566,7 +2566,7 @@ void read_row_cols(unsigned i, static_matrix& A, std::ifstream & if (line== "row_end") break; auto r = split_and_trim(line); - lean_assert(r.size() == 4); + lp_assert(r.size() == 4); unsigned j = atoi(r[1].c_str()); double v = atof(r[3].c_str()); A.set(i, j, v); @@ -2594,7 +2594,7 @@ void read_basis(vector & basis, std::ifstream & f) { std::cout << "reading basis" << std::endl; std::string line; getline(f, line); - lean_assert(line == "basis_start"); + lp_assert(line == "basis_start"); do { getline(f, line); if (line == "basis_end") @@ -2607,7 +2607,7 @@ void read_basis(vector & basis, std::ifstream & f) { void read_indexed_vector(indexed_vector & v, std::ifstream & f) { std::string line; getline(f, line); - lean_assert(line == "vector_start"); + lp_assert(line == "vector_start"); do { getline(f, line); if (line == "vector_end") break; @@ -2647,7 +2647,7 @@ void check_lu_from_file(std::string lufile_name) { A.copy_column_to_vector(entering, a); indexed_vector cd(d); B.apply_from_left(cd.m_data, settings); - lean_assert(vectors_are_equal(cd.m_data , a)); + lp_assert(vectors_are_equal(cd.m_data , a)); #endif } @@ -2745,7 +2745,7 @@ void test_evidence_for_total_inf_simple(argument_parser & args_parser) { auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; std::unordered_map model; - lean_assert(solver.get_status() == INFEASIBLE); + lp_assert(solver.get_status() == INFEASIBLE); } void test_bound_propagation_one_small_sample1() { /* @@ -2941,8 +2941,8 @@ void test_total_case_l(){ ls.solve(); bound_propagator bp(ls); ls.propagate_bounds_for_touched_rows(bp); - lean_assert(ev.size() == 4); - lean_assert(contains_j_kind(x, GE, - one_of_type(), ev)); + lp_assert(ev.size() == 4); + lp_assert(contains_j_kind(x, GE, - one_of_type(), ev)); } void test_bound_propagation() { test_total_case_u(); @@ -2962,17 +2962,17 @@ void test_int_set() { s.insert(1); s.insert(2); s.print(std::cout); - lean_assert(s.contains(2)); - lean_assert(s.size() == 2); + lp_assert(s.contains(2)); + lp_assert(s.size() == 2); s.erase(2); - lean_assert(s.size() == 1); + lp_assert(s.size() == 1); s.erase(2); - lean_assert(s.size() == 1); + lp_assert(s.size() == 1); s.print(std::cout); s.insert(3); s.insert(2); s.clear(); - lean_assert(s.size() == 0); + lp_assert(s.size() == 0); } @@ -3226,7 +3226,7 @@ void test_lp_local(int argn, char**argv) { ret = 0; return finalize(ret); } - // lean::ccc = 0; + // lp::ccc = 0; return finalize(0); test_init_U(); test_replace_column(); @@ -3243,5 +3243,5 @@ void test_lp_local(int argn, char**argv) { } } void tst_lp(char ** argv, int argc, int& i) { - lean::test_lp_local(argc - 2, argv + 2); + lp::test_lp_local(argc - 2, argv + 2); } diff --git a/src/test/lp/lp_main.cpp b/src/test/lp/lp_main.cpp index a301f38c6..450664fd0 100644 --- a/src/test/lp/lp_main.cpp +++ b/src/test/lp/lp_main.cpp @@ -2,12 +2,12 @@ void gparams_register_modules(){} void mem_initialize() {} void mem_finalize() {} #include "util/rational.h" -namespace lean { +namespace lp { void test_lp_local(int argc, char**argv); } int main(int argn, char**argv){ rational::initialize(); - lean::test_lp_local(argn, argv); + lp::test_lp_local(argn, argv); rational::finalize(); return 0; } diff --git a/src/test/lp/smt_reader.h b/src/test/lp/smt_reader.h index dd38c6bcd..a2ee0f271 100644 --- a/src/test/lp/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -23,7 +23,7 @@ #include "util/lp/lar_constraints.h" #include #include -namespace lean { +namespace lp { template T from_string(const std::string& str) { @@ -108,13 +108,13 @@ namespace lean { void fill_simple_elem(lisp_elem & lm) { int separator = first_separator(); - lean_assert(-1 != separator && separator != 0); + lp_assert(-1 != separator && separator != 0); lm.m_head = m_line.substr(0, separator); m_line = m_line.substr(separator); } void fill_nested_elem(lisp_elem & lm) { - lean_assert(m_line[0] == '('); + lp_assert(m_line[0] == '('); m_line = m_line.substr(1); int separator = first_separator(); lm.m_head = m_line.substr(0, separator); @@ -181,11 +181,11 @@ namespace lean { } void adjust_rigth_side(formula_constraint & /* c*/, lisp_elem & /*el*/) { - // lean_assert(el.m_head == "0"); // do nothing for the time being + // lp_assert(el.m_head == "0"); // do nothing for the time being } void set_constraint_coeffs(formula_constraint & c, lisp_elem & el) { - lean_assert(el.m_elems.size() == 2); + lp_assert(el.m_elems.size() == 2); set_constraint_coeffs_on_coeff_element(c, el.m_elems[0]); adjust_rigth_side(c, el.m_elems[1]); } @@ -201,7 +201,7 @@ namespace lean { add_mult_elem(c, el.m_elems); } else if (el.m_head == "~") { lisp_elem & minel = el.m_elems[0]; - lean_assert(minel.is_simple()); + lp_assert(minel.is_simple()); c.m_right_side += mpq(str_to_int(minel.m_head)); } else { std::cout << "unexpected input " << el.m_head << std::endl; @@ -211,14 +211,14 @@ namespace lean { } std::string get_name(lisp_elem & name) { - lean_assert(name.is_simple()); - lean_assert(!is_integer(name.m_head)); + lp_assert(name.is_simple()); + lp_assert(!is_integer(name.m_head)); return name.m_head; } void add_mult_elem(formula_constraint & c, std::vector & els) { - lean_assert(els.size() == 2); + lp_assert(els.size() == 2); mpq coeff = get_coeff(els[0]); std::string col_name = get_name(els[1]); c.add_pair(coeff, col_name); @@ -228,16 +228,16 @@ namespace lean { if (le.is_simple()) { return mpq(str_to_int(le.m_head)); } else { - lean_assert(le.m_head == "~"); - lean_assert(le.size() == 1); + lp_assert(le.m_head == "~"); + lp_assert(le.size() == 1); lisp_elem & el = le.m_elems[0]; - lean_assert(el.is_simple()); + lp_assert(el.is_simple()); return -mpq(str_to_int(el.m_head)); } } int str_to_int(std::string & s) { - lean_assert(is_integer(s)); + lp_assert(is_integer(s)); return atoi(s.c_str()); } @@ -245,7 +245,7 @@ namespace lean { if (el.size()) { add_complex_sum_elem(c, el); } else { - lean_assert(is_integer(el.m_head)); + lp_assert(is_integer(el.m_head)); int v = atoi(el.m_head.c_str()); mpq vr(v); c.m_right_side -= vr; @@ -263,7 +263,7 @@ namespace lean { } else if (el.m_head == "+") { add_sum(c, el.m_elems); } else { - lean_assert(false); // unexpected input + lp_assert(false); // unexpected input } } diff --git a/src/test/lp/test_file_reader.h b/src/test/lp/test_file_reader.h index c7a9e3b8b..5daeb21b6 100644 --- a/src/test/lp/test_file_reader.h +++ b/src/test/lp/test_file_reader.h @@ -15,7 +15,7 @@ Author: Lev Nachmanson #include "util/lp/lp_utils.h" #include "util/lp/lp_solver.h" -namespace lean { +namespace lp { template struct test_result { diff --git a/src/util/lp/binary_heap_priority_queue.h b/src/util/lp/binary_heap_priority_queue.h index a6206948c..04faefd5b 100644 --- a/src/util/lp/binary_heap_priority_queue.h +++ b/src/util/lp/binary_heap_priority_queue.h @@ -7,7 +7,7 @@ #include "util/vector.h" #include "util/debug.h" #include "util/lp/lp_utils.h" -namespace lean { +namespace lp { // the elements with the smallest priority are dequeued first template class binary_heap_priority_queue { @@ -60,7 +60,7 @@ public: /// return the first element of the queue and removes it from the queue unsigned dequeue(); unsigned peek() const { - lean_assert(m_heap_size > 0); + lp_assert(m_heap_size > 0); return m_heap[1]; } #ifdef LEAN_DEBUG diff --git a/src/util/lp/binary_heap_priority_queue.hpp b/src/util/lp/binary_heap_priority_queue.hpp index 440b45b02..d6d9a5358 100644 --- a/src/util/lp/binary_heap_priority_queue.hpp +++ b/src/util/lp/binary_heap_priority_queue.hpp @@ -4,7 +4,7 @@ */ #include "util/vector.h" #include "util/lp/binary_heap_priority_queue.h" -namespace lean { +namespace lp { // is is the child place in heap template void binary_heap_priority_queue::swap_with_parent(unsigned i) { unsigned parent = m_heap[i >> 1]; @@ -33,8 +33,8 @@ template void binary_heap_priority_queue::decrease_priority(unsi template bool binary_heap_priority_queue::is_consistent() const { for (int i = 0; i < m_heap_inverse.size(); i++) { int i_index = m_heap_inverse[i]; - lean_assert(i_index <= static_cast(m_heap_size)); - lean_assert(i_index == -1 || m_heap[i_index] == i); + lp_assert(i_index <= static_cast(m_heap_size)); + lp_assert(i_index == -1 || m_heap[i_index] == i); } for (unsigned i = 1; i < m_heap_size; i++) { unsigned ch = i << 1; @@ -55,7 +55,7 @@ template void binary_heap_priority_queue::remove(unsigned o) { if (o_in_heap == -1) { return; // nothing to do } - lean_assert(static_cast(o_in_heap) <= m_heap_size); + lp_assert(static_cast(o_in_heap) <= m_heap_size); if (static_cast(o_in_heap) < m_heap_size) { put_at(o_in_heap, m_heap[m_heap_size--]); if (m_priorities[m_heap[o_in_heap]] > priority_of_o) { @@ -72,11 +72,11 @@ template void binary_heap_priority_queue::remove(unsigned o) { } } } else { - lean_assert(static_cast(o_in_heap) == m_heap_size); + lp_assert(static_cast(o_in_heap) == m_heap_size); m_heap_size--; } m_heap_inverse[o] = -1; - // lean_assert(is_consistent()); + // lp_assert(is_consistent()); } // n is the initial queue capacity. // The capacity will be enlarged two times automatically if needed @@ -102,7 +102,7 @@ template void binary_heap_priority_queue::put_to_heap(unsigned i template void binary_heap_priority_queue::enqueue_new(unsigned o, const T& priority) { m_heap_size++; int i = m_heap_size; - lean_assert(o < m_priorities.size()); + lp_assert(o < m_priorities.size()); m_priorities[o] = priority; put_at(i, o); while (i > 1 && m_priorities[m_heap[i >> 1]] > priority) { @@ -134,7 +134,7 @@ template void binary_heap_priority_queue::change_priority_for_ex /// return the first element of the queue and removes it from the queue template unsigned binary_heap_priority_queue::dequeue_and_get_priority(T & priority) { - lean_assert(m_heap_size != 0); + lp_assert(m_heap_size != 0); int ret = m_heap[1]; priority = m_priorities[ret]; put_the_last_at_the_top_and_fix_the_heap(); @@ -168,7 +168,7 @@ template void binary_heap_priority_queue::put_the_last_at_the_to } /// return the first element of the queue and removes it from the queue template unsigned binary_heap_priority_queue::dequeue() { - lean_assert(m_heap_size > 0); + lp_assert(m_heap_size > 0); int ret = m_heap[1]; put_the_last_at_the_top_and_fix_the_heap(); m_heap_inverse[ret] = -1; diff --git a/src/util/lp/binary_heap_priority_queue_instances.cpp b/src/util/lp/binary_heap_priority_queue_instances.cpp index 567494d6f..12b853fc8 100644 --- a/src/util/lp/binary_heap_priority_queue_instances.cpp +++ b/src/util/lp/binary_heap_priority_queue_instances.cpp @@ -4,7 +4,7 @@ */ #include "util/lp/numeric_pair.h" #include "util/lp/binary_heap_priority_queue.hpp" -namespace lean { +namespace lp { template binary_heap_priority_queue::binary_heap_priority_queue(unsigned int); template unsigned binary_heap_priority_queue::dequeue(); template void binary_heap_priority_queue::enqueue(unsigned int, int const&); @@ -16,11 +16,11 @@ template unsigned binary_heap_priority_queue::dequeue(); template unsigned binary_heap_priority_queue::dequeue(); template void binary_heap_priority_queue >::enqueue(unsigned int, numeric_pair const&); template void binary_heap_priority_queue >::resize(unsigned int); -template void lean::binary_heap_priority_queue::resize(unsigned int); +template void lp::binary_heap_priority_queue::resize(unsigned int); template binary_heap_priority_queue::binary_heap_priority_queue(unsigned int); template void binary_heap_priority_queue::resize(unsigned int); template unsigned binary_heap_priority_queue::dequeue(); template void binary_heap_priority_queue::enqueue(unsigned int, unsigned int const&); template void binary_heap_priority_queue::remove(unsigned int); -template void lean::binary_heap_priority_queue::resize(unsigned int); +template void lp::binary_heap_priority_queue::resize(unsigned int); } diff --git a/src/util/lp/binary_heap_upair_queue.h b/src/util/lp/binary_heap_upair_queue.h index 26cfd5532..ec7f4e85f 100644 --- a/src/util/lp/binary_heap_upair_queue.h +++ b/src/util/lp/binary_heap_upair_queue.h @@ -15,7 +15,7 @@ typedef std::pair upair; -namespace lean { +namespace lp { template class binary_heap_upair_queue { binary_heap_priority_queue m_q; diff --git a/src/util/lp/binary_heap_upair_queue.hpp b/src/util/lp/binary_heap_upair_queue.hpp index a48bdb5b7..2a162fa06 100644 --- a/src/util/lp/binary_heap_upair_queue.hpp +++ b/src/util/lp/binary_heap_upair_queue.hpp @@ -6,7 +6,7 @@ #include #include "util/lp/lp_utils.h" #include "util/lp/binary_heap_upair_queue.h" -namespace lean { +namespace lp { template binary_heap_upair_queue::binary_heap_upair_queue(unsigned size) : m_q(size), m_pairs(size) { for (unsigned i = 0; i < size; i++) m_available_spots.push_back(i); @@ -14,7 +14,7 @@ template binary_heap_upair_queue::binary_heap_upair_queue(unsign template unsigned binary_heap_upair_queue::dequeue_available_spot() { - lean_assert(m_available_spots.empty() == false); + lp_assert(m_available_spots.empty() == false); unsigned ret = m_available_spots.back(); m_available_spots.pop_back(); return ret; @@ -54,7 +54,7 @@ template void binary_heap_upair_queue::enqueue(unsigned i, unsig m_pairs.resize(new_size); } ij_index = dequeue_available_spot(); - // lean_assert(ij_index void binary_heap_upair_queue::enqueue(unsigned i, unsig } template void binary_heap_upair_queue::dequeue(unsigned & i, unsigned &j) { - lean_assert(!m_q.is_empty()); + lp_assert(!m_q.is_empty()); unsigned ij_index = m_q.dequeue(); upair & p = m_pairs[ij_index]; i = p.first; diff --git a/src/util/lp/binary_heap_upair_queue_instances.cpp b/src/util/lp/binary_heap_upair_queue_instances.cpp index 4c4603110..d315e9bda 100644 --- a/src/util/lp/binary_heap_upair_queue_instances.cpp +++ b/src/util/lp/binary_heap_upair_queue_instances.cpp @@ -3,7 +3,7 @@ Author: Lev Nachmanson */ #include "util/lp/binary_heap_upair_queue.hpp" -namespace lean { +namespace lp { template binary_heap_upair_queue::binary_heap_upair_queue(unsigned int); template binary_heap_upair_queue::binary_heap_upair_queue(unsigned int); template unsigned binary_heap_upair_queue::dequeue_available_spot(); diff --git a/src/util/lp/bound_analyzer_on_row.h b/src/util/lp/bound_analyzer_on_row.h index 508692e5a..45f5288b1 100644 --- a/src/util/lp/bound_analyzer_on_row.h +++ b/src/util/lp/bound_analyzer_on_row.h @@ -13,7 +13,7 @@ // We try to pin a var by pushing the total by using the variable bounds // In a loop we drive the partial sum down, denoting the variables of this process by _u. // In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l -namespace lean { +namespace lp { class bound_analyzer_on_row { @@ -91,11 +91,11 @@ public : } const impq & ub(unsigned j) const { - lean_assert(upper_bound_is_available(j)); + lp_assert(upper_bound_is_available(j)); return m_bp.get_upper_bound(j); } const impq & lb(unsigned j) const { - lean_assert(low_bound_is_available(j)); + lp_assert(low_bound_is_available(j)); return m_bp.get_low_bound(j); } @@ -153,7 +153,7 @@ public : void limit_all_monoids_from_above() { int strict = 0; mpq total; - lean_assert(is_zero(total)); + lp_assert(is_zero(total)); m_it.reset(); mpq a; unsigned j; while (m_it.next(a, j)) { @@ -180,7 +180,7 @@ public : void limit_all_monoids_from_below() { int strict = 0; mpq total; - lean_assert(is_zero(total)); + lp_assert(is_zero(total)); m_it.reset(); mpq a; unsigned j; while (m_it.next(a, j)) { @@ -272,7 +272,7 @@ public : // mpq a; unsigned j; // while (it->next(a, j)) { // if (be.m_j == j) continue; - // lean_assert(bound_is_available(j, is_neg(a) ? low_bound : !low_bound)); + // lp_assert(bound_is_available(j, is_neg(a) ? low_bound : !low_bound)); // be.m_vector_of_bound_signatures.emplace_back(a, j, numeric_traits:: // is_neg(a)? low_bound: !low_bound); // } diff --git a/src/util/lp/bound_propagator.cpp b/src/util/lp/bound_propagator.cpp index 0d58ec2be..cfb3aa68f 100644 --- a/src/util/lp/bound_propagator.cpp +++ b/src/util/lp/bound_propagator.cpp @@ -3,7 +3,7 @@ Author: Lev Nachmanson */ #include "util/lp/lar_solver.h" -namespace lean { +namespace lp { bound_propagator::bound_propagator(lar_solver & ls): m_lar_solver(ls) {} column_type bound_propagator::get_column_type(unsigned j) const { diff --git a/src/util/lp/bound_propagator.h b/src/util/lp/bound_propagator.h index 92523d75f..2ef0856fd 100644 --- a/src/util/lp/bound_propagator.h +++ b/src/util/lp/bound_propagator.h @@ -4,7 +4,7 @@ */ #pragma once #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { class lar_solver; class bound_propagator { std::unordered_map m_improved_low_bounds; // these maps map a column index to the corresponding index in ibounds @@ -19,7 +19,7 @@ public: const impq & get_upper_bound(unsigned) const; void try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict); virtual bool bound_is_interesting(unsigned vi, - lean::lconstraint_kind kind, + lp::lconstraint_kind kind, const rational & bval) {return true;} unsigned number_of_found_bounds() const { return m_ibounds.size(); } virtual void consume(mpq const& v, unsigned j) { std::cout << "doh\n"; } diff --git a/src/util/lp/breakpoint.h b/src/util/lp/breakpoint.h index e5454db0e..ff3a03e94 100644 --- a/src/util/lp/breakpoint.h +++ b/src/util/lp/breakpoint.h @@ -5,7 +5,7 @@ #pragma once -namespace lean { +namespace lp { enum breakpoint_type { low_break, upper_break, fixed_break }; diff --git a/src/util/lp/column_info.h b/src/util/lp/column_info.h index 56e75a1fb..02c2f638b 100644 --- a/src/util/lp/column_info.h +++ b/src/util/lp/column_info.h @@ -9,7 +9,7 @@ #include #include #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { inline bool is_valid(unsigned j) { return static_cast(j) >= 0;} template @@ -100,11 +100,11 @@ public: } T get_low_bound() const { - lean_assert(m_low_bound_is_set); + lp_assert(m_low_bound_is_set); return m_low_bound; } T get_upper_bound() const { - lean_assert(m_upper_bound_is_set); + lp_assert(m_upper_bound_is_set); return m_upper_bound; } @@ -156,7 +156,7 @@ public: } T get_fixed_value() const { - lean_assert(m_is_fixed); + lp_assert(m_is_fixed); return m_fixed_value; } diff --git a/src/util/lp/column_namer.h b/src/util/lp/column_namer.h index a3fe05dd0..66b6a55db 100644 --- a/src/util/lp/column_namer.h +++ b/src/util/lp/column_namer.h @@ -5,7 +5,7 @@ */ #include #include "util/lp/linear_combination_iterator.h" -namespace lean { +namespace lp { class column_namer { public: virtual std::string get_column_name(unsigned j) const = 0; diff --git a/src/util/lp/conversion_helper.h b/src/util/lp/conversion_helper.h index bff2ad563..cd8577483 100644 --- a/src/util/lp/conversion_helper.h +++ b/src/util/lp/conversion_helper.h @@ -4,7 +4,7 @@ Author: Lev Nachmanson */ #pragma once -namespace lean { +namespace lp { template struct conversion_helper { static V get_low_bound(const column_info & ci) { diff --git a/src/util/lp/core_solver_pretty_printer.h b/src/util/lp/core_solver_pretty_printer.h index 2a3a14b31..cf4caf19d 100644 --- a/src/util/lp/core_solver_pretty_printer.h +++ b/src/util/lp/core_solver_pretty_printer.h @@ -10,7 +10,7 @@ #include #include "util/lp/lp_settings.h" #include "util/lp/indexed_vector.h" -namespace lean { +namespace lp { template class lp_core_solver_base; // forward definition template diff --git a/src/util/lp/core_solver_pretty_printer.hpp b/src/util/lp/core_solver_pretty_printer.hpp index 786b8b3a1..8890f8c20 100644 --- a/src/util/lp/core_solver_pretty_printer.hpp +++ b/src/util/lp/core_solver_pretty_printer.hpp @@ -9,7 +9,7 @@ #include "util/lp/lp_core_solver_base.h" #include "util/lp/core_solver_pretty_printer.h" #include "util/lp/numeric_pair.h" -namespace lean { +namespace lp { template @@ -148,7 +148,7 @@ template void core_solver_pretty_printer::adjust_ case column_type::free_column: break; default: - lean_assert(false); + lp_assert(false); break; } } @@ -357,7 +357,7 @@ template void core_solver_pretty_printer::print_g unsigned width = m_column_widths[col]; string s = row[col]; int number_of_blanks = width - static_cast(s.size()); - lean_assert(number_of_blanks >= 0); + lp_assert(number_of_blanks >= 0); print_blanks(number_of_blanks, m_out); m_out << s << ' '; if (col < row.size() - 1) { @@ -368,7 +368,7 @@ template void core_solver_pretty_printer::print_g string rs = T_to_string(rst); int nb = m_rs_width - static_cast(rs.size()); - lean_assert(nb >= 0); + lp_assert(nb >= 0); print_blanks(nb + 1, m_out); m_out << rs << std::endl; } diff --git a/src/util/lp/core_solver_pretty_printer_instances.cpp b/src/util/lp/core_solver_pretty_printer_instances.cpp index cfa72f725..e3801228c 100644 --- a/src/util/lp/core_solver_pretty_printer_instances.cpp +++ b/src/util/lp/core_solver_pretty_printer_instances.cpp @@ -4,12 +4,12 @@ */ #include "util/lp/numeric_pair.h" #include "util/lp/core_solver_pretty_printer.hpp" -template lean::core_solver_pretty_printer::core_solver_pretty_printer(lean::lp_core_solver_base &, std::ostream & out); -template void lean::core_solver_pretty_printer::print(); -template lean::core_solver_pretty_printer::~core_solver_pretty_printer(); -template lean::core_solver_pretty_printer::core_solver_pretty_printer(lean::lp_core_solver_base &, std::ostream & out); -template void lean::core_solver_pretty_printer::print(); -template lean::core_solver_pretty_printer::~core_solver_pretty_printer(); -template lean::core_solver_pretty_printer >::core_solver_pretty_printer(lean::lp_core_solver_base > &, std::ostream & out); -template lean::core_solver_pretty_printer >::~core_solver_pretty_printer(); -template void lean::core_solver_pretty_printer >::print(); +template lp::core_solver_pretty_printer::core_solver_pretty_printer(lp::lp_core_solver_base &, std::ostream & out); +template void lp::core_solver_pretty_printer::print(); +template lp::core_solver_pretty_printer::~core_solver_pretty_printer(); +template lp::core_solver_pretty_printer::core_solver_pretty_printer(lp::lp_core_solver_base &, std::ostream & out); +template void lp::core_solver_pretty_printer::print(); +template lp::core_solver_pretty_printer::~core_solver_pretty_printer(); +template lp::core_solver_pretty_printer >::core_solver_pretty_printer(lp::lp_core_solver_base > &, std::ostream & out); +template lp::core_solver_pretty_printer >::~core_solver_pretty_printer(); +template void lp::core_solver_pretty_printer >::print(); diff --git a/src/util/lp/dense_matrix.h b/src/util/lp/dense_matrix.h index 233f74016..6f2f54338 100644 --- a/src/util/lp/dense_matrix.h +++ b/src/util/lp/dense_matrix.h @@ -6,7 +6,7 @@ #ifdef LEAN_DEBUG #include "util/vector.h" #include "util/lp/matrix.h" -namespace lean { +namespace lp { // used for debugging purposes only template class dense_matrix: public matrix { @@ -31,7 +31,7 @@ public: dense_matrix(unsigned m, unsigned n); dense_matrix operator*=(matrix const & a) { - lean_assert(column_count() == a.row_count()); + lp_assert(column_count() == a.row_count()); dense_matrix c(row_count(), a.column_count()); for (unsigned i = 0; i < row_count(); i++) { for (unsigned j = 0; j < a.column_count(); j++) { diff --git a/src/util/lp/dense_matrix.hpp b/src/util/lp/dense_matrix.hpp index e42d9e3a4..8850d4f74 100644 --- a/src/util/lp/dense_matrix.hpp +++ b/src/util/lp/dense_matrix.hpp @@ -7,7 +7,7 @@ #include "util/vector.h" #include "util/lp/numeric_pair.h" #include "util/lp/dense_matrix.h" -namespace lean { +namespace lp { template void print_vector(const vector & t, std::ostream & out); template dense_matrix::dense_matrix(unsigned m, unsigned n) : m_m(m), m_n(n), m_values(m * n, numeric_traits::zero()) { } @@ -170,7 +170,7 @@ template void dense_matrix::multiply_row_by_const template dense_matrix operator* (matrix & a, matrix & b){ - lean_assert(a.column_count() == b.row_count()); + lp_assert(a.column_count() == b.row_count()); dense_matrix ret(a.row_count(), b.column_count()); for (unsigned i = 0; i < ret.m_m; i++) for (unsigned j = 0; j< ret.m_n; j++) { diff --git a/src/util/lp/dense_matrix_instances.cpp b/src/util/lp/dense_matrix_instances.cpp index 95ba01801..418e2f2e0 100644 --- a/src/util/lp/dense_matrix_instances.cpp +++ b/src/util/lp/dense_matrix_instances.cpp @@ -6,20 +6,20 @@ #include "util/lp/dense_matrix.hpp" #ifdef LEAN_DEBUG #include "util/vector.h" -template lean::dense_matrix lean::operator*(lean::matrix&, lean::matrix&); -template void lean::dense_matrix::apply_from_left(vector &); -template lean::dense_matrix::dense_matrix(lean::matrix const*); -template lean::dense_matrix::dense_matrix(unsigned int, unsigned int); -template lean::dense_matrix& lean::dense_matrix::operator=(lean::dense_matrix const&); -template lean::dense_matrix::dense_matrix(unsigned int, unsigned int); -template lean::dense_matrix >::dense_matrix(lean::matrix > const*); -template void lean::dense_matrix >::apply_from_left(vector&); -template lean::dense_matrix lean::operator*(lean::matrix&, lean::matrix&); -template lean::dense_matrix & lean::dense_matrix::operator=(lean::dense_matrix const&); -template lean::dense_matrix >::dense_matrix(unsigned int, unsigned int); -template lean::dense_matrix >& lean::dense_matrix >::operator=(lean::dense_matrix > const&); -template lean::dense_matrix > lean::operator* >(lean::matrix >&, lean::matrix >&); -template void lean::dense_matrix >::apply_from_right( vector< lean::mpq> &); -template void lean::dense_matrix::apply_from_right(class vector &); -template void lean::dense_matrix::apply_from_left(vector&); +template lp::dense_matrix lp::operator*(lp::matrix&, lp::matrix&); +template void lp::dense_matrix::apply_from_left(vector &); +template lp::dense_matrix::dense_matrix(lp::matrix const*); +template lp::dense_matrix::dense_matrix(unsigned int, unsigned int); +template lp::dense_matrix& lp::dense_matrix::operator=(lp::dense_matrix const&); +template lp::dense_matrix::dense_matrix(unsigned int, unsigned int); +template lp::dense_matrix >::dense_matrix(lp::matrix > const*); +template void lp::dense_matrix >::apply_from_left(vector&); +template lp::dense_matrix lp::operator*(lp::matrix&, lp::matrix&); +template lp::dense_matrix & lp::dense_matrix::operator=(lp::dense_matrix const&); +template lp::dense_matrix >::dense_matrix(unsigned int, unsigned int); +template lp::dense_matrix >& lp::dense_matrix >::operator=(lp::dense_matrix > const&); +template lp::dense_matrix > lp::operator* >(lp::matrix >&, lp::matrix >&); +template void lp::dense_matrix >::apply_from_right( vector< lp::mpq> &); +template void lp::dense_matrix::apply_from_right(class vector &); +template void lp::dense_matrix::apply_from_left(vector&); #endif diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index 51b015066..cfcd11256 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -7,7 +7,7 @@ #include "util/vector.h" #include "util/lp/tail_matrix.h" #include "util/lp/permutation_matrix.h" -namespace lean { +namespace lp { // This is the sum of a unit matrix and a one-column matrix template @@ -61,7 +61,7 @@ public: void push_back(unsigned row_index, T val ) { - lean_assert(row_index != m_column_index); + lp_assert(row_index != m_column_index); m_column_vector.push_back(row_index, val); } diff --git a/src/util/lp/eta_matrix.hpp b/src/util/lp/eta_matrix.hpp index 142a408d1..dc1ba9ce5 100644 --- a/src/util/lp/eta_matrix.hpp +++ b/src/util/lp/eta_matrix.hpp @@ -6,7 +6,7 @@ #pragma once #include "util/vector.h" #include "util/lp/eta_matrix.h" -namespace lean { +namespace lp { // This is the sum of a unit matrix and a one-column matrix template @@ -60,7 +60,7 @@ void eta_matrix::apply_from_right(vector & w) { } w[m_column_index] = t; #ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(clone_w, w, get_number_of_rows())); + // lp_assert(vectors_are_equal(clone_w, w, get_number_of_rows())); // delete clone_w; #endif } @@ -100,8 +100,8 @@ void eta_matrix::apply_from_right(indexed_vector & w) { } #ifdef LEAN_DEBUG - // lean_assert(w.is_OK()); - // lean_assert(vectors_are_equal(wcopy, w.m_data)); + // lp_assert(w.is_OK()); + // lp_assert(vectors_are_equal(wcopy, w.m_data)); #endif } #ifdef LEAN_DEBUG @@ -130,7 +130,7 @@ void eta_matrix::conjugate_by_permutation(permutation_matrix & p) { pair.first = p.get_rev(pair.first); } #ifdef LEAN_DEBUG - // lean_assert(deb == *this); + // lp_assert(deb == *this); #endif } } diff --git a/src/util/lp/eta_matrix_instances.cpp b/src/util/lp/eta_matrix_instances.cpp index d57d43fed..470a16800 100644 --- a/src/util/lp/eta_matrix_instances.cpp +++ b/src/util/lp/eta_matrix_instances.cpp @@ -7,22 +7,22 @@ #include "util/lp/numeric_pair.h" #include "util/lp/eta_matrix.hpp" #ifdef LEAN_DEBUG -template double lean::eta_matrix::get_elem(unsigned int, unsigned int) const; -template lean::mpq lean::eta_matrix::get_elem(unsigned int, unsigned int) const; -template lean::mpq lean::eta_matrix >::get_elem(unsigned int, unsigned int) const; +template double lp::eta_matrix::get_elem(unsigned int, unsigned int) const; +template lp::mpq lp::eta_matrix::get_elem(unsigned int, unsigned int) const; +template lp::mpq lp::eta_matrix >::get_elem(unsigned int, unsigned int) const; #endif -template void lean::eta_matrix::apply_from_left(vector&, lean::lp_settings&); -template void lean::eta_matrix::apply_from_right(vector&); -template void lean::eta_matrix::conjugate_by_permutation(lean::permutation_matrix&); -template void lean::eta_matrix::apply_from_left(vector&, lean::lp_settings&); -template void lean::eta_matrix::apply_from_right(vector&); -template void lean::eta_matrix::conjugate_by_permutation(lean::permutation_matrix&); -template void lean::eta_matrix >::apply_from_left(vector >&, lean::lp_settings&); -template void lean::eta_matrix >::apply_from_right(vector&); -template void lean::eta_matrix >::conjugate_by_permutation(lean::permutation_matrix >&); -template void lean::eta_matrix::apply_from_left_local(lean::indexed_vector&, lean::lp_settings&); -template void lean::eta_matrix::apply_from_left_local(lean::indexed_vector&, lean::lp_settings&); -template void lean::eta_matrix >::apply_from_left_local(lean::indexed_vector&, lean::lp_settings&); -template void lean::eta_matrix >::apply_from_right(lean::indexed_vector&); -template void lean::eta_matrix::apply_from_right(lean::indexed_vector&); -template void lean::eta_matrix::apply_from_right(lean::indexed_vector&); +template void lp::eta_matrix::apply_from_left(vector&, lp::lp_settings&); +template void lp::eta_matrix::apply_from_right(vector&); +template void lp::eta_matrix::conjugate_by_permutation(lp::permutation_matrix&); +template void lp::eta_matrix::apply_from_left(vector&, lp::lp_settings&); +template void lp::eta_matrix::apply_from_right(vector&); +template void lp::eta_matrix::conjugate_by_permutation(lp::permutation_matrix&); +template void lp::eta_matrix >::apply_from_left(vector >&, lp::lp_settings&); +template void lp::eta_matrix >::apply_from_right(vector&); +template void lp::eta_matrix >::conjugate_by_permutation(lp::permutation_matrix >&); +template void lp::eta_matrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); +template void lp::eta_matrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); +template void lp::eta_matrix >::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); +template void lp::eta_matrix >::apply_from_right(lp::indexed_vector&); +template void lp::eta_matrix::apply_from_right(lp::indexed_vector&); +template void lp::eta_matrix::apply_from_right(lp::indexed_vector&); diff --git a/src/util/lp/hash_helper.h b/src/util/lp/hash_helper.h index 6fe31d5cd..3d2457a5c 100644 --- a/src/util/lp/hash_helper.h +++ b/src/util/lp/hash_helper.h @@ -12,8 +12,8 @@ #endif namespace std { template<> -struct hash { - inline size_t operator()(const lean::mpq & v) const { +struct hash { + inline size_t operator()(const lp::mpq & v) const { return v.hash(); } }; diff --git a/src/util/lp/implied_bound.h b/src/util/lp/implied_bound.h index 9583e3cd8..45911476f 100644 --- a/src/util/lp/implied_bound.h +++ b/src/util/lp/implied_bound.h @@ -5,7 +5,7 @@ #pragma once #include "util/lp/lp_settings.h" #include "util/lp/lar_constraints.h" -namespace lean { +namespace lp { struct implied_bound { mpq m_bound; unsigned m_j; // the column for which the bound has been found diff --git a/src/util/lp/indexed_value.h b/src/util/lp/indexed_value.h index 7963dfdf9..08a821d10 100644 --- a/src/util/lp/indexed_value.h +++ b/src/util/lp/indexed_value.h @@ -4,7 +4,7 @@ */ #pragma once -namespace lean { +namespace lp { template class indexed_value { public: diff --git a/src/util/lp/indexed_vector.h b/src/util/lp/indexed_vector.h index 4b9a7767d..0e013f778 100644 --- a/src/util/lp/indexed_vector.h +++ b/src/util/lp/indexed_vector.h @@ -11,7 +11,7 @@ #include "util/lp/lp_utils.h" #include "util/lp/lp_settings.h" #include -namespace lean { +namespace lp { template void print_vector(const vector & t, std::ostream & out); template void print_vector(const buffer & t, std::ostream & out); @@ -86,7 +86,7 @@ public: return m_data[i]; } - void clean_up() { + void clp_up() { #if 0==1 for (unsigned k = 0; k < m_index.size(); k++) { unsigned i = m_index[k]; @@ -140,7 +140,7 @@ public: } } - void restore_index_and_clean_from_data() { + void restore_index_and_clp_from_data() { m_index.resize(0); for (unsigned i = 0; i < m_data.size(); i++) { T & v = m_data[i]; diff --git a/src/util/lp/indexed_vector.hpp b/src/util/lp/indexed_vector.hpp index 64e329adc..ff3effeb5 100644 --- a/src/util/lp/indexed_vector.hpp +++ b/src/util/lp/indexed_vector.hpp @@ -5,7 +5,7 @@ #include "util/vector.h" #include "util/lp/indexed_vector.h" #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { template void print_vector(const vector & t, std::ostream & out) { @@ -41,13 +41,13 @@ template void indexed_vector::resize(unsigned data_size) { clear(); m_data.resize(data_size, numeric_traits::zero()); - lean_assert(is_OK()); + lp_assert(is_OK()); } template void indexed_vector::set_value(const T& value, unsigned index) { m_data[index] = value; - lean_assert(std::find(m_index.begin(), m_index.end(), index) == m_index.end()); + lp_assert(std::find(m_index.begin(), m_index.end(), index) == m_index.end()); m_index.push_back(index); } diff --git a/src/util/lp/indexed_vector_instances.cpp b/src/util/lp/indexed_vector_instances.cpp index 6f17a894f..0d6f8c5d2 100644 --- a/src/util/lp/indexed_vector_instances.cpp +++ b/src/util/lp/indexed_vector_instances.cpp @@ -4,7 +4,7 @@ */ #include "util/vector.h" #include "util/lp/indexed_vector.hpp" -namespace lean { +namespace lp { template void indexed_vector::clear(); template void indexed_vector::clear_all(); template void indexed_vector::erase_from_index(unsigned int); @@ -20,17 +20,17 @@ template void indexed_vector::set_value(const unsigned&, unsigned int) #ifdef LEAN_DEBUG template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; -template bool indexed_vector >::is_OK() const; -template void lean::indexed_vector< lean::mpq>::print(std::basic_ostream > &); -template void lean::indexed_vector::print(std::basic_ostream > &); -template void lean::indexed_vector >::print(std::ostream&); +template bool indexed_vector >::is_OK() const; +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 lean::print_vector(vector const&, std::ostream&); -template void lean::print_vector(vector const&, std::ostream&); -template void lean::print_vector(vector const&, std::ostream&); -template void lean::print_vector >(vector> const&, std::ostream&); -template void lean::indexed_vector::resize(unsigned int); -template void lean::print_vector< lean::mpq>(vector< lean::mpq> const &, std::basic_ostream > &); -template void lean::print_vector >(vector> const&, std::ostream&); -template void lean::indexed_vector >::erase_from_index(unsigned int); +template void lp::print_vector(vector const&, std::ostream&); +template void lp::print_vector(vector const&, std::ostream&); +template void lp::print_vector(vector const&, std::ostream&); +template void lp::print_vector >(vector> const&, std::ostream&); +template void lp::indexed_vector::resize(unsigned int); +template void lp::print_vector< lp::mpq>(vector< lp::mpq> const &, std::basic_ostream > &); +template void lp::print_vector >(vector> const&, std::ostream&); +template void lp::indexed_vector >::erase_from_index(unsigned int); diff --git a/src/util/lp/int_set.h b/src/util/lp/int_set.h index 0619facd8..931125ab5 100644 --- a/src/util/lp/int_set.h +++ b/src/util/lp/int_set.h @@ -6,7 +6,7 @@ #include "util/vector.h" #include "util/lp/indexed_vector.h" #include -namespace lean { +namespace lp { // serves at a set of non-negative integers smaller than the set size class int_set { vector m_data; @@ -20,7 +20,7 @@ public: return m_data[j] >= 0; } void insert(unsigned j) { - lean_assert(j < m_data.size()); + lp_assert(j < m_data.size()); if (contains(j)) return; m_data[j] = m_index.size(); m_index.push_back(j); diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index eb31119b9..f416ad98c 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -5,10 +5,10 @@ #include "util/lp/int_solver.h" #include "util/lp/lar_solver.h" -namespace lean { +namespace lp { void int_solver::fix_non_base_columns() { - lean_assert(is_feasible() && inf_int_set_is_correct()); + lp_assert(is_feasible() && inf_int_set_is_correct()); auto & lcs = m_lar_solver->m_mpq_lar_core_solver; bool change = false; for (unsigned j : lcs.m_r_nbasis) { @@ -22,7 +22,7 @@ void int_solver::fix_non_base_columns() { if (m_lar_solver->find_feasible_solution() == INFEASIBLE) failed(); init_inf_int_set(); - lean_assert(is_feasible() && inf_int_set_is_correct()); + lp_assert(is_feasible() && inf_int_set_is_correct()); } void int_solver::failed() { @@ -30,11 +30,11 @@ void int_solver::failed() { for (unsigned j : m_old_values_set.m_index) { lcs.m_r_x[j] = m_old_values_data[j]; - lean_assert(lcs.m_r_solver.column_is_feasible(j)); + lp_assert(lcs.m_r_solver.column_is_feasible(j)); lcs.m_r_solver.remove_column_from_inf_set(j); } - lean_assert(lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis()); - lean_assert(lcs.m_r_solver.current_x_is_feasible()); + lp_assert(lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis()); + lp_assert(lcs.m_r_solver.current_x_is_feasible()); m_old_values_set.clear(); } @@ -78,7 +78,7 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { lar_core_solver & lcs = m_lar_solver->m_mpq_lar_core_solver; for (int j : m_inf_int_set.m_index) { - lean_assert(is_base(j) && column_is_int_inf(j)); + lp_assert(is_base(j) && column_is_int_inf(j)); if (!is_boxed(j)) continue; new_range = lcs.m_r_upper_bounds()[j].x - lcs.m_r_low_bounds()[j].x; @@ -109,7 +109,7 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { } bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { - lean_assert(false); + lp_assert(false); return true; /* const auto & row = m_lar_solver->A_r().m_rows[row_index]; @@ -297,10 +297,10 @@ void int_solver::init_check_data() { } lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { - lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); - lean_assert(is_feasible()); + lp_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); + lp_assert(is_feasible()); init_check_data(); - lean_assert(inf_int_set_is_correct()); + lp_assert(inf_int_set_is_correct()); // currently it is a reimplementation of // final_check_status theory_arith::check_int_feasibility() // from theory_arith_int.h @@ -344,7 +344,7 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { if (j != -1) { TRACE("arith_int", tout << "j" << j << " does not have an integer assignment: " << get_value(j) << "\n";); - lean_assert(t.is_empty()); + lp_assert(t.is_empty()); t.add_to_map(j, mpq(1)); k = floor(get_value(j)); TRACE("arith_int", tout << "branching v" << j << " = " << get_value(j) << "\n"; @@ -354,7 +354,7 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { return lia_move::branch; } } - lean_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); + lp_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); // return true; return lia_move::give_up; } @@ -387,7 +387,7 @@ void int_solver::move_non_base_vars_to_bounds() { void int_solver::set_value_for_nbasic_column(unsigned j, const impq & new_val) { - lean_assert(!is_base(j)); + lp_assert(!is_base(j)); auto & x = m_lar_solver->m_mpq_lar_core_solver.m_r_x[j]; if (!m_old_values_set.contains(j)) { m_old_values_set.insert(j); @@ -450,7 +450,7 @@ void int_solver::patch_int_infeasible_columns() { TRACE("patch_int", tout << "patching with 0\n";); } - lean_assert(is_feasible() && inf_int_set_is_correct()); + lp_assert(is_feasible() && inf_int_set_is_correct()); } } @@ -621,7 +621,7 @@ linear_combination_iterator * int_solver::get_column_iterator(unsigned j) { int_solver::int_solver(lar_solver* lar_slv) : m_lar_solver(lar_slv), m_branch_cut_counter(0) { - lean_assert(m_old_values_set.size() == 0); + lp_assert(m_old_values_set.size() == 0); m_old_values_set.resize(lar_slv->A_r().column_count()); m_old_values_data.resize(lar_slv->A_r().column_count(), zero_of_type()); } @@ -740,8 +740,8 @@ bool int_solver::get_freedom_interval_for_column(unsigned x_j, bool & inf_l, imp tout << "]\n"; tout << "val = " << get_value(x_j) << "\n"; ); - lean_assert(inf_l || l <= get_value(x_j)); - lean_assert(inf_u || u >= get_value(x_j)); + lp_assert(inf_l || l <= get_value(x_j)); + lp_assert(inf_u || u >= get_value(x_j)); return true; } @@ -758,7 +758,7 @@ bool int_solver::value_is_int(unsigned j) const { bool int_solver::is_feasible() const { auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - lean_assert( + lp_assert( lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis() == lcs.m_r_solver.current_x_is_feasible()); return lcs.m_r_solver.current_x_is_feasible(); diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index bac99021b..1d1a1dc69 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -9,7 +9,7 @@ #include "util/lp/int_set.h" #include "util/lp/lar_term.h" -namespace lean { +namespace lp { class lar_solver; template struct lp_constraint; diff --git a/src/util/lp/iterator_on_column.h b/src/util/lp/iterator_on_column.h index 215514b39..a3875deef 100644 --- a/src/util/lp/iterator_on_column.h +++ b/src/util/lp/iterator_on_column.h @@ -6,7 +6,7 @@ #include "util/lp/linear_combination_iterator.h" #include "util/lp/static_matrix.h" #include "util/lp/lar_term.h" -namespace lean { +namespace lp { template struct iterator_on_column:linear_combination_iterator { const vector& m_column; // the offset in term coeffs diff --git a/src/util/lp/iterator_on_indexed_vector.h b/src/util/lp/iterator_on_indexed_vector.h index 532b62617..253661c38 100644 --- a/src/util/lp/iterator_on_indexed_vector.h +++ b/src/util/lp/iterator_on_indexed_vector.h @@ -4,7 +4,7 @@ */ #pragma once #include "util/lp/linear_combination_iterator.h" -namespace lean { +namespace lp { template struct iterator_on_indexed_vector:linear_combination_iterator { const indexed_vector & m_v; diff --git a/src/util/lp/iterator_on_pivot_row.h b/src/util/lp/iterator_on_pivot_row.h index 1a9381a70..cfd0feba4 100644 --- a/src/util/lp/iterator_on_pivot_row.h +++ b/src/util/lp/iterator_on_pivot_row.h @@ -4,7 +4,7 @@ */ #pragma once #include "util/lp/iterator_on_indexed_vector.h" -namespace lean { +namespace lp { template struct iterator_on_pivot_row:linear_combination_iterator { bool m_basis_returned; diff --git a/src/util/lp/iterator_on_row.h b/src/util/lp/iterator_on_row.h index 96a1a8cf3..d5f42340b 100644 --- a/src/util/lp/iterator_on_row.h +++ b/src/util/lp/iterator_on_row.h @@ -4,7 +4,7 @@ */ #pragma once #include "util/lp/linear_combination_iterator.h" -namespace lean { +namespace lp { template struct iterator_on_row:linear_combination_iterator { const vector> & m_row; diff --git a/src/util/lp/iterator_on_term_with_basis_var.h b/src/util/lp/iterator_on_term_with_basis_var.h index 3dd217103..3210b1c27 100644 --- a/src/util/lp/iterator_on_term_with_basis_var.h +++ b/src/util/lp/iterator_on_term_with_basis_var.h @@ -6,7 +6,7 @@ #include "util/lp/linear_combination_iterator.h" #include "util/lp/numeric_pair.h" #include "util/lp/lar_term.h" -namespace lean { +namespace lp { struct iterator_on_term_with_basis_var:linear_combination_iterator { const lar_term & m_term; std::unordered_map::const_iterator m_i; // the offset in term coeffs diff --git a/src/util/lp/lar_constraints.h b/src/util/lp/lar_constraints.h index ee0864a4e..bd11896fb 100644 --- a/src/util/lp/lar_constraints.h +++ b/src/util/lp/lar_constraints.h @@ -12,7 +12,7 @@ #include "util/lp/lp_utils.h" #include "util/lp/ul_pair.h" #include "util/lp/lar_term.h" -namespace lean { +namespace lp { inline lconstraint_kind flip_kind(lconstraint_kind t) { return static_cast( - static_cast(t)); } @@ -25,7 +25,7 @@ inline std::string lconstraint_kind_string(lconstraint_kind t) { case GT: return std::string(">"); case EQ: return std::string("="); } - lean_unreachable(); + lp_unreachable(); return std::string(); // it is unreachable } @@ -74,7 +74,7 @@ public: : lar_base_constraint(kind, right_side), m_coeffs(left_side) {} lar_constraint(const lar_base_constraint & c) { - lean_assert(false); // should not be called : todo! + lp_assert(false); // should not be called : todo! } unsigned size() const { diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 44a6349a7..01afc866c 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -18,7 +18,7 @@ #include "util/lp/iterator_on_column.h" #include "util/lp/iterator_on_indexed_vector.h" #include "util/lp/stacked_value.h" -namespace lean { +namespace lp { class lar_core_solver { // m_sign_of_entering is set to 1 if the entering variable needs @@ -168,9 +168,9 @@ public: } void push() { - lean_assert(m_r_solver.basis_heading_is_correct()); - lean_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); - lean_assert(m_column_types.size() == m_r_A.column_count()); + lp_assert(m_r_solver.basis_heading_is_correct()); + lp_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); + lp_assert(m_column_types.size() == m_r_A.column_count()); m_stacked_simplex_strategy = settings().simplex_strategy(); m_stacked_simplex_strategy.push(); m_column_types.push(); @@ -192,7 +192,7 @@ public: template void push_vector(stacked_vector & pushed_vector, const vector & vector) { - lean_assert(pushed_vector.size() <= vector.size()); + lp_assert(pushed_vector.size() <= vector.size()); for (unsigned i = 0; i < vector.size();i++) { if (i == pushed_vector.size()) { pushed_vector.push_back(vector[i]); @@ -242,8 +242,8 @@ public: pop_basis(k); m_stacked_simplex_strategy.pop(k); settings().simplex_strategy() = m_stacked_simplex_strategy; - lean_assert(m_r_solver.basis_heading_is_correct()); - lean_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); + lp_assert(m_r_solver.basis_heading_is_correct()); + lp_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); } bool need_to_presolve_with_double_solver() const { @@ -304,11 +304,11 @@ public: break; default: - lean_assert(false); + lp_assert(false); } break; default: - lean_unreachable(); + lp_unreachable(); } m_r_solver.remove_column_from_inf_set(j); return true; @@ -317,7 +317,7 @@ public: void prepare_solver_x_with_signature_tableau(const lar_solution_signature & signature) { - lean_assert(m_r_solver.inf_set_is_correct()); + lp_assert(m_r_solver.inf_set_is_correct()); for (auto &t : signature) { unsigned j = t.first; if (m_r_heading[j] >= 0) @@ -332,9 +332,9 @@ public: m_r_solver.m_x[jb] -= delta * m_r_solver.m_A.get_val(cc); m_r_solver.update_column_in_inf_set(jb); } - lean_assert(m_r_solver.A_mult_x_is_off() == false); + lp_assert(m_r_solver.A_mult_x_is_off() == false); } - lean_assert(m_r_solver.inf_set_is_correct()); + lp_assert(m_r_solver.inf_set_is_correct()); } @@ -342,7 +342,7 @@ public: void prepare_solver_x_with_signature(const lar_solution_signature & signature, lp_primal_core_solver & s) { for (auto &t : signature) { unsigned j = t.first; - lean_assert(m_r_heading[j] < 0); + lp_assert(m_r_heading[j] < 0); auto pos_type = t.second; switch (pos_type) { case at_low_bound: @@ -359,7 +359,7 @@ public: case not_at_bound: switch (m_column_types[j]) { case column_type::free_column: - lean_assert(false); // unreachable + lp_assert(false); // unreachable case column_type::upper_bound: s.m_x[j] = s.m_upper_bounds[j]; break; @@ -377,15 +377,15 @@ public: s.m_x[j] = s.m_low_bounds[j]; break; default: - lean_assert(false); + lp_assert(false); } break; default: - lean_unreachable(); + lp_unreachable(); } } - lean_assert(is_zero_vector(s.m_b)); + lp_assert(is_zero_vector(s.m_b)); s.solve_Ax_eq_b(); } @@ -418,7 +418,7 @@ public: // the queues of delayed indices std::queue entr_q, leav_q; auto * l = cs.m_factorization; - lean_assert(l->get_status() == LU_status::OK); + lp_assert(l->get_status() == LU_status::OK); for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) { unsigned entering = trace_of_basis_change[i]; unsigned leaving = trace_of_basis_change[i+1]; @@ -446,8 +446,8 @@ public: continue; } } - lean_assert(cs.m_basis_heading[entering] < 0); - lean_assert(cs.m_basis_heading[leaving] >= 0); + lp_assert(cs.m_basis_heading[entering] < 0); + lp_assert(cs.m_basis_heading[leaving] >= 0); if (l->get_status() == LU_status::OK) { l->prepare_entering(entering, w); // to init vector w l->replace_column(zero_of_type(), w, cs.m_basis_heading[leaving]); @@ -471,7 +471,7 @@ public: void solve_on_signature_tableau(const lar_solution_signature & signature, const vector & changes_of_basis) { r_basis_is_OK(); - lean_assert(settings().use_tableau()); + lp_assert(settings().use_tableau()); bool r = catch_up_in_lu_tableau(changes_of_basis, m_d_solver.m_basis_heading); if (!r) { // it is the case where m_d_solver gives a degenerated basis @@ -490,10 +490,10 @@ public: return; m_r_solver.stop_tracing_basis_changes(); // and now catch up in the double solver - lean_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); + lp_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); catch_up_in_lu(m_r_solver.m_trace_of_basis_change_vector, m_r_solver.m_basis_heading, m_d_solver); } - lean_assert(r_basis_is_OK()); + lp_assert(r_basis_is_OK()); } bool adjust_x_of_column(unsigned j) { @@ -507,16 +507,16 @@ public: } m_r_solver.snap_column_to_bound_tableau(j); - lean_assert(m_r_solver.column_is_feasible(j)); + lp_assert(m_r_solver.column_is_feasible(j)); m_r_solver.m_inf_set.erase(j); */ - lean_assert(false); + lp_assert(false); return true; } bool catch_up_in_lu_tableau(const vector & trace_of_basis_change, const vector & basis_heading) { - lean_assert(r_basis_is_OK()); + lp_assert(r_basis_is_OK()); // the queues of delayed indices std::queue entr_q, leav_q; for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) { @@ -546,8 +546,8 @@ public: continue; } } - lean_assert(m_r_solver.m_basis_heading[entering] < 0); - lean_assert(m_r_solver.m_basis_heading[leaving] >= 0); + lp_assert(m_r_solver.m_basis_heading[entering] < 0); + lp_assert(m_r_solver.m_basis_heading[leaving] >= 0); m_r_solver.change_basis_unconditionally(entering, leaving); if(!m_r_solver.pivot_column_tableau(entering, m_r_solver.m_basis_heading[entering])) { // unroll the last step @@ -557,12 +557,12 @@ public: #endif m_r_solver.pivot_column_tableau(leaving, m_r_solver.m_basis_heading[leaving]); #ifdef LEAN_DEBUG - lean_assert(t); + lp_assert(t); #endif return false; } } - lean_assert(r_basis_is_OK()); + lp_assert(r_basis_is_OK()); return true; } @@ -572,21 +572,21 @@ public: if (!m_r_solver.m_settings.use_tableau()) return true; for (unsigned j : m_r_solver.m_basis) { - lean_assert(m_r_solver.m_A.m_columns[j].size() == 1); - lean_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].size() == 1); + lp_assert(m_r_solver.m_A.get_val(m_r_solver.m_A.m_columns[j][0]) == one_of_type()); } for (unsigned j =0; j < m_r_solver.m_basis_heading.size(); j++) { if (m_r_solver.m_basis_heading[j] >= 0) continue; if (m_r_solver.m_column_types[j] == column_type::fixed) continue; - lean_assert(static_cast(- m_r_solver.m_basis_heading[j] - 1) < m_r_solver.m_column_types.size()); - lean_assert( m_r_solver.m_basis_heading[j] <= -1); + lp_assert(static_cast(- m_r_solver.m_basis_heading[j] - 1) < m_r_solver.m_column_types.size()); + lp_assert( m_r_solver.m_basis_heading[j] <= -1); } #endif return true; } void solve_on_signature(const lar_solution_signature & signature, const vector & changes_of_basis) { - lean_assert(!settings().use_tableau()); + lp_assert(!settings().use_tableau()); if (m_r_solver.m_factorization == nullptr) { for (unsigned j = 0; j < changes_of_basis.size(); j+=2) { unsigned entering = changes_of_basis[j]; @@ -615,7 +615,7 @@ public: return; m_r_solver.stop_tracing_basis_changes(); // and now catch up in the double solver - lean_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); + lp_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); catch_up_in_lu(m_r_solver.m_trace_of_basis_change_vector, m_r_solver.m_basis_heading, m_d_solver); } } @@ -641,7 +641,7 @@ public: template void extract_signature_from_lp_core_solver(const lp_primal_core_solver & solver, lar_solution_signature & signature) { signature.clear(); - lean_assert(signature.size() == 0); + lp_assert(signature.size() == 0); for (unsigned j = 0; j < solver.m_basis_heading.size(); j++) { if (solver.m_basis_heading[j] < 0) { signature[j] = solver.get_non_basic_column_value_position(j); @@ -664,7 +664,7 @@ public: if (upper_bound_is_set(j)) { const auto & ub = m_r_solver.m_upper_bounds[j]; m_d_upper_bounds[j] = ub.x.get_double() + delta * ub.y.get_double(); - lean_assert(!low_bound_is_set(j) || (m_d_upper_bounds[j] >= m_d_low_bounds[j])); + lp_assert(!low_bound_is_set(j) || (m_d_upper_bounds[j] >= m_d_low_bounds[j])); } } } @@ -729,7 +729,7 @@ public: case column_type::fixed: return true; default: - lean_assert(false); + lp_assert(false); } return false; } @@ -744,20 +744,20 @@ public: case column_type::fixed: return true; default: - lean_assert(false); + lp_assert(false); } return false; } void update_delta(mpq& delta, numeric_pair const& l, numeric_pair const& u) const { - lean_assert(l <= u); + lp_assert(l <= u); if (l.x < u.x && l.y > u.y) { mpq delta1 = (u.x - l.x) / (l.y - u.y); if (delta1 < delta) { delta = delta1; } } - lean_assert(l.x + delta * l.y <= u.x + delta * u.y); + lp_assert(l.x + delta * l.y <= u.x + delta * u.y); } @@ -804,14 +804,14 @@ public: } const impq & low_bound(unsigned j) const { - lean_assert(m_column_types()[j] == column_type::fixed || + lp_assert(m_column_types()[j] == column_type::fixed || m_column_types()[j] == column_type::boxed || m_column_types()[j] == column_type::low_bound); return m_r_low_bounds[j]; } const impq & upper_bound(unsigned j) const { - lean_assert(m_column_types()[j] == column_type::fixed || + lp_assert(m_column_types()[j] == column_type::fixed || m_column_types()[j] == column_type::boxed || m_column_types()[j] == column_type::upper_bound); return m_r_upper_bounds[j]; diff --git a/src/util/lp/lar_core_solver.hpp b/src/util/lp/lar_core_solver.hpp index 38c522446..227d2910f 100644 --- a/src/util/lp/lar_core_solver.hpp +++ b/src/util/lp/lar_core_solver.hpp @@ -10,7 +10,7 @@ #include "util/vector.h" #include "util/lp/lar_core_solver.h" #include "util/lp/lar_solution_signature.h" -namespace lean { +namespace lp { lar_core_solver::lar_core_solver( lp_settings & settings, const column_namer & column_names @@ -42,9 +42,9 @@ lar_core_solver::lar_core_solver( column_names){} void lar_core_solver::init_costs(bool first_time) { - lean_assert(false); // should not be called - // lean_assert(this->m_x.size() >= this->m_n()); - // lean_assert(this->m_column_types.size() >= this->m_n()); + lp_assert(false); // should not be called + // lp_assert(this->m_x.size() >= this->m_n()); + // lp_assert(this->m_column_types.size() >= this->m_n()); // if (first_time) // this->m_costs.resize(this->m_n()); // X inf = this->m_infeasibility; @@ -54,7 +54,7 @@ void lar_core_solver::init_costs(bool first_time) { // if (!(first_time || inf >= this->m_infeasibility)) { // LP_OUT(this->m_settings, "iter = " << this->total_iterations() << std::endl); // LP_OUT(this->m_settings, "inf was " << T_to_string(inf) << " and now " << T_to_string(this->m_infeasibility) << std::endl); - // lean_assert(false); + // lp_assert(false); // } // if (inf == this->m_infeasibility) // this->m_iters_with_no_cost_growing++; @@ -105,7 +105,7 @@ void lar_core_solver::init_cost_for_column(unsigned j) { this->m_costs[j] = numeric_traits::zero(); break; default: - lean_assert(false); + lp_assert(false); break; }*/ } @@ -138,7 +138,7 @@ int lar_core_solver::column_is_out_of_bounds(unsigned j) { return 0; break; }*/ - lean_assert(false); + lp_assert(false); return true; } @@ -192,7 +192,7 @@ void lar_core_solver::calculate_pivot_row(unsigned i) { } void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() { - lean_assert(m_r_solver.A_mult_x_is_off() == false); + lp_assert(m_r_solver.A_mult_x_is_off() == false); 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(); @@ -227,15 +227,15 @@ void lar_core_solver::fill_not_improvable_zero_sum() { void lar_core_solver::solve() { - lean_assert(m_r_solver.non_basic_columns_are_set_correctly()); - lean_assert(m_r_solver.inf_set_is_correct()); + lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); + lp_assert(m_r_solver.inf_set_is_correct()); if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) { m_r_solver.set_status(OPTIMAL); return; } ++settings().st().m_need_to_solve_inf; - lean_assert(!m_r_solver.A_mult_x_is_off()); - lean_assert((!settings().use_tableau()) || r_basis_is_OK()); + lp_assert(!m_r_solver.A_mult_x_is_off()); + lp_assert((!settings().use_tableau()) || r_basis_is_OK()); if (need_to_presolve_with_double_solver()) { prefix_d(); lar_solution_signature solution_signature; @@ -248,11 +248,11 @@ void lar_core_solver::solve() { solve_on_signature_tableau(solution_signature, changes_of_basis); else solve_on_signature(solution_signature, changes_of_basis); - lean_assert(!settings().use_tableau() || r_basis_is_OK()); + lp_assert(!settings().use_tableau() || r_basis_is_OK()); } else { if (!settings().use_tableau()) { bool snapped = m_r_solver.snap_non_basic_x_to_bound(); - lean_assert(m_r_solver.non_basic_columns_are_set_correctly()); + lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); if (snapped) m_r_solver.solve_Ax_eq_b(); } @@ -260,16 +260,16 @@ void lar_core_solver::solve() { m_r_solver.find_feasible_solution(); else m_r_solver.solve(); - lean_assert(!settings().use_tableau() || r_basis_is_OK()); + lp_assert(!settings().use_tableau() || r_basis_is_OK()); } if (m_r_solver.get_status() == INFEASIBLE) { fill_not_improvable_zero_sum(); } else if (m_r_solver.get_status() != UNBOUNDED) { m_r_solver.set_status(OPTIMAL); } - lean_assert(r_basis_is_OK()); - lean_assert(m_r_solver.non_basic_columns_are_set_correctly()); - lean_assert(m_r_solver.inf_set_is_correct()); + lp_assert(r_basis_is_OK()); + lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); + lp_assert(m_r_solver.inf_set_is_correct()); } diff --git a/src/util/lp/lar_solution_signature.h b/src/util/lp/lar_solution_signature.h index 2c4169c81..6c8598a73 100644 --- a/src/util/lp/lar_solution_signature.h +++ b/src/util/lp/lar_solution_signature.h @@ -8,6 +8,6 @@ #include "util/debug.h" #include "util/lp/lp_settings.h" #include -namespace lean { +namespace lp { typedef std::unordered_map lar_solution_signature; } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index eff44d1cd..3e7c994e6 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -4,7 +4,7 @@ Author: Lev Nachmanson */ -namespace lean { +namespace lp { unsigned lar_solver::constraint_count() const { return m_constraints.size(); @@ -23,7 +23,7 @@ lp_settings & lar_solver::settings() { return m_settings;} lp_settings const & lar_solver::settings() const { return m_settings;} -void clear() {lean_assert(false); // not implemented +void clear() {lp_assert(false); // not implemented } @@ -52,7 +52,7 @@ bool lar_solver::is_term(var_index j) const { } unsigned lar_solver::adjust_term_index(unsigned j) const { - lean_assert(is_term(j)); + lp_assert(is_term(j)); return j - m_terms_start_index; } @@ -60,10 +60,10 @@ unsigned lar_solver::adjust_term_index(unsigned j) const { bool lar_solver::use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } bool lar_solver::sizes_are_correct() const { - lean_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); + lp_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); return true; } @@ -105,7 +105,7 @@ bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, else if (kind == LE || kind == LT) n_of_L++; rs_of_evidence += coeff*constr.m_right_side; } - lean_assert(n_of_G == 0 || n_of_L == 0); + lp_assert(n_of_G == 0 || n_of_L == 0); lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); if (strict) kind = static_cast((static_cast(kind) / 2)); @@ -149,7 +149,7 @@ bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, void lar_solver::analyze_new_bounds_on_row( unsigned row_index, bound_propagator & bp) { - lean_assert(!use_tableau()); + lp_assert(!use_tableau()); iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); bound_analyzer_on_row ra_pos(it, @@ -168,7 +168,7 @@ void lar_solver::analyze_new_bounds_on_row_tableau( if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation) return; iterator_on_row it(A_r().m_rows[row_index]); - lean_assert(use_tableau()); + lp_assert(use_tableau()); bound_analyzer_on_row::analyze_row(it, zero_of_type>(), row_index, @@ -201,7 +201,7 @@ void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator & linear_combination_iterator * lar_solver::create_new_iter_from_term(unsigned term_index) const { - lean_assert(false); // not implemented + lp_assert(false); // not implemented return nullptr; // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); } @@ -212,7 +212,7 @@ unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const { } void lar_solver::propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { - lean_assert(false); // not implemented + lp_assert(false); // not implemented } @@ -223,7 +223,7 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp unsigned m_j = ib.m_j; if (is_term(m_j)) { auto it = m_ext_vars_to_columns.find(m_j); - lean_assert(it != m_ext_vars_to_columns.end()); + lp_assert(it != m_ext_vars_to_columns.end()); m_j = it->second.ext_j(); } for (auto const& r : A_r().m_rows[i]) { @@ -232,22 +232,22 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp if (j == m_j) continue; if (is_term(j)) { auto it = m_ext_vars_to_columns.find(j); - lean_assert(it != m_ext_vars_to_columns.end()); + lp_assert(it != m_ext_vars_to_columns.end()); j = it->second.ext_j(); } int a_sign = is_pos(a)? 1: -1; int sign = j_sign * a_sign; const ul_pair & ul = m_vars_to_ul_pairs[j]; auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); - lean_assert(is_valid(witness)); + lp_assert(is_valid(witness)); bp.consume(a, witness); } - // lean_assert(implied_bound_is_correctly_explained(ib, explanation)); + // lp_assert(implied_bound_is_correctly_explained(ib, explanation)); } bool lar_solver::term_is_used_as_row(unsigned term) const { - lean_assert(is_term(term)); + lp_assert(is_term(term)); return contains(m_ext_vars_to_columns, term); } @@ -338,7 +338,7 @@ void lar_solver::push() { m_constraint_count.push(); } -void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { +void lar_solver::clp_large_elements_after_pop(unsigned n, int_set& set) { vector to_remove; for (unsigned j: set.m_index) if (j >= n) @@ -348,7 +348,7 @@ void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { } void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { - clean_large_elements_after_pop(n, set); + clp_large_elements_after_pop(n, set); set.resize(n); } @@ -367,16 +367,16 @@ void lar_solver::pop(unsigned k) { m_vars_to_ul_pairs.pop(k); m_mpq_lar_core_solver.pop(k); - clean_large_elements_after_pop(n, m_columns_with_changed_bound); + clp_large_elements_after_pop(n, m_columns_with_changed_bound); unsigned m = A_r().row_count(); - clean_large_elements_after_pop(m, m_rows_with_changed_bounds); - clean_inf_set_of_r_solver_after_pop(); - lean_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || + clp_large_elements_after_pop(m, m_rows_with_changed_bounds); + clp_inf_set_of_r_solver_after_pop(); + lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - lean_assert(ax_is_correct()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); + lp_assert(ax_is_correct()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); m_constraint_count.pop(k); for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) delete m_constraints[i]; @@ -389,8 +389,8 @@ void lar_solver::pop(unsigned k) { m_terms.resize(m_term_count); m_simplex_strategy.pop(k); m_settings.simplex_strategy() = m_simplex_strategy; - lean_assert(sizes_are_correct()); - lean_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + lp_assert(sizes_are_correct()); + lp_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); } vector lar_solver::get_all_constraint_indices() const { @@ -419,13 +419,13 @@ bool lar_solver::maximize_term_on_tableau(const vector bool lar_solver::costs_are_zeros_for_r_solver() const { for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); + lp_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); } return true; } bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const { for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { - lean_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); + lp_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); } return true; } @@ -433,7 +433,7 @@ bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const { void lar_solver::set_costs_to_zero(const vector> & term) { auto & rslv = m_mpq_lar_core_solver.m_r_solver; auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now - lean_assert(jset.m_index.size()==0); + lp_assert(jset.m_index.size()==0); for (auto & p : term) { unsigned j = p.second; @@ -452,16 +452,16 @@ void lar_solver::set_costs_to_zero(const vector> & ter jset.clear(); - lean_assert(reduced_costs_are_zeroes_for_r_solver()); - lean_assert(costs_are_zeros_for_r_solver()); + lp_assert(reduced_costs_are_zeroes_for_r_solver()); + lp_assert(costs_are_zeros_for_r_solver()); } void lar_solver::prepare_costs_for_r_solver(const vector> & term) { auto & rslv = m_mpq_lar_core_solver.m_r_solver; rslv.m_using_infeas_costs = false; - lean_assert(costs_are_zeros_for_r_solver()); - lean_assert(reduced_costs_are_zeroes_for_r_solver()); + lp_assert(costs_are_zeros_for_r_solver()); + lp_assert(reduced_costs_are_zeroes_for_r_solver()); rslv.m_costs.resize(A_r().column_count(), zero_of_type()); for (auto & p : term) { unsigned j = p.second; @@ -471,7 +471,7 @@ void lar_solver::prepare_costs_for_r_solver(const vector> & term, @@ -498,10 +498,10 @@ bool lar_solver::maximize_term_on_corrected_r_solver(const vector> & term, impq &term_max) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; return maximize_term_on_corrected_r_solver(term, term_max); } @@ -517,7 +517,7 @@ bool lar_solver::maximize_term(const vector> & term, const lar_term & lar_solver::get_term(unsigned j) const { - lean_assert(j >= m_terms_start_index); + lp_assert(j >= m_terms_start_index); return *m_terms[j - m_terms_start_index]; } @@ -579,7 +579,7 @@ void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j m_column_buffer.resize(A_r().row_count()); else m_column_buffer.clear(); - lean_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); + lp_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); for (unsigned i : m_column_buffer.m_index) @@ -613,7 +613,7 @@ void lar_solver::detect_rows_of_column_with_bound_change(unsigned j) { } void lar_solver::adjust_x_of_column(unsigned j) { - lean_assert(false); + lp_assert(false); } bool lar_solver::row_is_correct(unsigned i) const { @@ -706,14 +706,14 @@ void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds() { } void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { - lean_assert(ax_is_correct()); + lp_assert(ax_is_correct()); for (auto j : m_columns_with_changed_bound.m_index) update_x_and_inf_costs_for_column_with_changed_bounds(j); if (tableau_with_costs()) { for (unsigned j : m_basic_columns_with_changed_cost.m_index) m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); } } @@ -735,7 +735,7 @@ void lar_solver::solve_with_core_solver() { update_x_and_inf_costs_for_columns_with_changed_bounds(); m_mpq_lar_core_solver.solve(); set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); - lean_assert(m_status != OPTIMAL || all_constraints_hold()); + lp_assert(m_status != OPTIMAL || all_constraints_hold()); } @@ -760,7 +760,7 @@ numeric_pair lar_solver::get_basic_var_value_from_row(unsigned i) { numeric_pair r = zero_of_type>(); m_mpq_lar_core_solver.calculate_pivot_row(i); for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; } return r; @@ -824,12 +824,12 @@ unsigned lar_solver::constraint_stack_size() const { } void lar_solver::fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); + lp_assert(A.row_count() > 0); + lp_assert(A.column_count() > 0); unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].size() == 0); + lp_assert(A.m_rows[last_row].size() == 0); for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); + lp_assert(!is_zero(t.second)); var_index j = t.first; A.set(last_row, j, - t.second); } @@ -839,7 +839,7 @@ void lar_solver::fill_last_row_of_A_r(static_matrix> & A, template void lar_solver::create_matrix_A(static_matrix & matr) { - lean_assert(false); // not implemented + lp_assert(false); // not implemented /* unsigned m = number_or_nontrivial_left_sides(); unsigned n = m_vec_of_canonic_left_sides.size(); @@ -920,7 +920,7 @@ bool lar_solver::constraint_holds(const lar_base_constraint & constr, std::unord case GT: return left_side_val > constr.m_right_side; case EQ: return left_side_val == constr.m_right_side; default: - lean_unreachable(); + lp_unreachable(); } return false; // it is unreachable } @@ -965,7 +965,7 @@ bool lar_solver::the_left_sides_sum_to_zero(const vector>& explanation) const { #ifdef LEAN_DEBUG lconstraint_kind kind; - lean_assert(the_relations_are_of_same_type(explanation, kind)); - lean_assert(the_left_sides_sum_to_zero(explanation)); + lp_assert(the_relations_are_of_same_type(explanation, kind)); + lp_assert(the_left_sides_sum_to_zero(explanation)); mpq rs = sum_of_right_sides_of_explanation(explanation); switch (kind) { - case LE: lean_assert(rs < zero_of_type()); + case LE: lp_assert(rs < zero_of_type()); break; - case LT: lean_assert(rs <= zero_of_type()); + case LT: lp_assert(rs <= zero_of_type()); break; - case GE: lean_assert(rs > zero_of_type()); + case GE: lp_assert(rs > zero_of_type()); break; - case GT: lean_assert(rs >= zero_of_type()); + case GT: lp_assert(rs >= zero_of_type()); break; - case EQ: lean_assert(rs != zero_of_type()); + case EQ: lp_assert(rs != zero_of_type()); break; default: - lean_assert(false); + lp_assert(false); return false; } #endif @@ -1034,7 +1034,7 @@ mpq lar_solver::sum_of_right_sides_of_explanation(const vectorm_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; } return ret; @@ -1091,7 +1091,7 @@ void lar_solver::get_infeasibility_explanation(vector & variable_values) const { mpq delta = mpq(1, 2); // start from 0.5 to have less clashes - lean_assert(m_status == OPTIMAL); + lp_assert(m_status == OPTIMAL); unsigned i; do { @@ -1188,7 +1188,7 @@ mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::u for (auto & it : cns.get_left_side_coefficients()) { var_index j = it.second; auto vi = var_map.find(j); - lean_assert(vi != var_map.end()); + lp_assert(vi != var_map.end()); ret += it.first * vi->second; } return ret; @@ -1234,7 +1234,7 @@ bool lar_solver::column_represents_row_in_tableau(unsigned j) { void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { // i, j - is the indices of the bottom-right element of the tableau - lean_assert(A_r().row_count() == i + 1 && A_r().column_count() == j + 1); + 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;){ @@ -1244,13 +1244,13 @@ void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsign non_zero_column_cell_index = k; } - lean_assert(non_zero_column_cell_index != -1); - lean_assert(static_cast(non_zero_column_cell_index) != i); + 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); } void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); auto & slv = m_mpq_lar_core_solver.m_r_solver; unsigned i = A_r().row_count() - 1; //last row index make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); @@ -1269,17 +1269,17 @@ void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { A_r().remove_element(last_row, rc); } - lean_assert(last_row.size() == 0); - lean_assert(A_r().m_columns[j].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(); slv.m_b.pop_back(); } void lar_solver::remove_last_column_from_tableau(unsigned j) { - lean_assert(j == A_r().column_count() - 1); + lp_assert(j == A_r().column_count() - 1); // the last column has to be empty - lean_assert(A_r().m_columns[j].size() == 0); + lp_assert(A_r().m_columns[j].size() == 0); A_r().m_columns.pop_back(); } @@ -1288,7 +1288,7 @@ void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { int i = rslv.m_basis_heading[j]; if (i >= 0) { // j is a basic var int last_pos = static_cast(rslv.m_basis.size()) - 1; - lean_assert(last_pos >= 0); + lp_assert(last_pos >= 0); if (i != last_pos) { unsigned j_at_last_pos = rslv.m_basis[last_pos]; rslv.m_basis[i] = j_at_last_pos; @@ -1297,7 +1297,7 @@ void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { rslv.m_basis.pop_back(); // remove j from the basis } else { int last_pos = static_cast(rslv.m_nbasis.size()) - 1; - lean_assert(last_pos >= 0); + lp_assert(last_pos >= 0); i = - 1 - i; if (i != last_pos) { unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; @@ -1307,14 +1307,14 @@ void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { rslv.m_nbasis.pop_back(); // remove j from the basis } rslv.m_basis_heading.pop_back(); - lean_assert(rslv.m_basis.size() == A_r().row_count()); - lean_assert(rslv.basis_heading_is_correct()); + lp_assert(rslv.m_basis.size() == A_r().row_count()); + lp_assert(rslv.basis_heading_is_correct()); } void lar_solver::remove_column_from_tableau(unsigned j) { auto& rslv = m_mpq_lar_core_solver.m_r_solver; - lean_assert(j == A_r().column_count() - 1); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lp_assert(j == A_r().column_count() - 1); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); if (column_represents_row_in_tableau(j)) { remove_last_row_and_column_from_tableau(j); if (rslv.m_basis_heading[j] < 0) @@ -1328,27 +1328,27 @@ void lar_solver::remove_column_from_tableau(unsigned j) { rslv.m_costs.pop_back(); remove_last_column_from_basis_tableau(j); - lean_assert(m_mpq_lar_core_solver.r_basis_is_OK()); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lp_assert(m_mpq_lar_core_solver.r_basis_is_OK()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); } void lar_solver::pop_tableau() { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). // At this moment m_column_names is already popped for (unsigned j = A_r().column_count(); j-- > m_columns_to_ext_vars_or_term_indices.size();) remove_column_from_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lean_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); } -void lar_solver::clean_inf_set_of_r_solver_after_pop() { +void lar_solver::clp_inf_set_of_r_solver_after_pop() { vector became_feas; - clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); + clp_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); std::unordered_set basic_columns_with_changed_cost; auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; for (auto j: inf_index_copy) { @@ -1363,14 +1363,14 @@ void lar_solver::clean_inf_set_of_r_solver_after_pop() { } for (unsigned j : became_feas) { - lean_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); } became_feas.clear(); for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { - lean_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); + lp_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) became_feas.push_back(j); } @@ -1383,14 +1383,14 @@ void lar_solver::clean_inf_set_of_r_solver_after_pop() { m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); for (unsigned j : basic_columns_with_changed_cost) m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lean_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); } } void lar_solver::shrink_explanation_to_minimum(vector> & explanation) const { // implementing quickXplain quick_xplain::run(explanation, *this); - lean_assert(this->explanation_is_correct(explanation)); + lp_assert(this->explanation_is_correct(explanation)); } bool lar_solver::model_is_int_feasible() const { @@ -1421,7 +1421,7 @@ bool lar_solver::var_is_int(var_index v) const { bool lar_solver::column_is_int(unsigned j) const { unsigned ext_var = m_columns_to_ext_vars_or_term_indices[j]; - lean_assert(contains(m_ext_vars_to_columns, ext_var)); + lp_assert(contains(m_ext_vars_to_columns, ext_var)); return m_ext_vars_to_columns.find(ext_var)->second.is_integer(); } @@ -1432,7 +1432,7 @@ bool lar_solver::column_is_fixed(unsigned j) const { bool lar_solver::ext_var_is_int(var_index ext_var) const { auto it = m_ext_vars_to_columns.find(ext_var); - lean_assert(it != m_ext_vars_to_columns.end()); + lp_assert(it != m_ext_vars_to_columns.end()); return it == m_ext_vars_to_columns.end() || it->second.is_integer(); } @@ -1445,7 +1445,7 @@ bool lar_solver::strategy_is_undecided() const { var_index lar_solver::add_var(unsigned ext_j, bool is_int) { TRACE("add_var", tout << "adding var " << ext_j << (is_int? " int" : " nonint") << std::endl;); var_index i; - lean_assert(ext_j < m_terms_start_index); + lp_assert(ext_j < m_terms_start_index); if (ext_j >= m_terms_start_index) throw 0; // todo : what is the right way to exit? @@ -1453,19 +1453,19 @@ var_index lar_solver::add_var(unsigned ext_j, bool is_int) { if (it != m_ext_vars_to_columns.end()) { return it->second.ext_j(); } - lean_assert(m_vars_to_ul_pairs.size() == A_r().column_count()); + lp_assert(m_vars_to_ul_pairs.size() == A_r().column_count()); i = A_r().column_count(); m_vars_to_ul_pairs.push_back(ul_pair(static_cast(-1))); add_non_basic_var_to_core_fields(ext_j, is_int); - lean_assert(sizes_are_correct()); + lp_assert(sizes_are_correct()); return i; } void lar_solver::register_new_ext_var_index(unsigned ext_v, bool is_int) { - lean_assert(!contains(m_ext_vars_to_columns, ext_v)); + lp_assert(!contains(m_ext_vars_to_columns, ext_v)); unsigned j = static_cast(m_ext_vars_to_columns.size()); m_ext_vars_to_columns.insert(std::make_pair(ext_v, ext_var_info(j, is_int))); - lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j); + lp_assert(m_columns_to_ext_vars_or_term_indices.size() == j); m_columns_to_ext_vars_or_term_indices.push_back(ext_v); } @@ -1481,12 +1481,12 @@ void lar_solver::add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int) { void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) { unsigned j = A_d().column_count(); A_d().add_column(); - lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + lp_assert(m_mpq_lar_core_solver.m_d_x.size() == j); + // lp_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later m_mpq_lar_core_solver.m_d_x.resize(j + 1); m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + lp_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method if (register_in_basis) { A_d().add_row(); m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); @@ -1501,15 +1501,15 @@ void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) { unsigned j = A_r().column_count(); A_r().add_column(); - lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later + lp_assert(m_mpq_lar_core_solver.m_r_x.size() == j); + // lp_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later m_mpq_lar_core_solver.m_r_x.resize(j + 1); m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one(); m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one(); m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method + lp_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method if (register_in_basis) { A_r().add_row(); m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); @@ -1544,14 +1544,14 @@ var_index lar_solver::add_term(const vector> & coeffs, if (m_settings.bound_propagation()) m_rows_with_changed_bounds.insert(A_r().row_count() - 1); } - lean_assert(m_ext_vars_to_columns.size() == A_r().column_count()); + lp_assert(m_ext_vars_to_columns.size() == A_r().column_count()); return ret; } void lar_solver::add_row_for_term(const lar_term * term, unsigned term_ext_index) { - lean_assert(sizes_are_correct()); + lp_assert(sizes_are_correct()); add_row_from_term_no_constraint(term, term_ext_index); - lean_assert(sizes_are_correct()); + lp_assert(sizes_are_correct()); } void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { @@ -1577,7 +1577,7 @@ void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned void lar_solver::add_basic_var_to_core_fields() { bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); - lean_assert(!use_lu || A_r().column_count() == A_d().column_count()); + lp_assert(!use_lu || A_r().column_count() == A_d().column_count()); m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); m_columns_with_changed_bound.increase_size_by_one(); m_rows_with_changed_bounds.increase_size_by_one(); @@ -1595,7 +1595,7 @@ bool lar_solver::bound_is_integer_if_needed(unsigned j, const mpq & right_side) constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { constraint_index ci = m_constraints.size(); if (!is_term(j)) { // j is a var - lean_assert(bound_is_integer_if_needed(j, right_side)); + lp_assert(bound_is_integer_if_needed(j, right_side)); auto vc = new lar_var_constraint(j, kind, right_side); m_constraints.push_back(vc); update_column_type_and_bound(j, kind, right_side, ci); @@ -1603,7 +1603,7 @@ constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, c else { add_var_bound_on_constraint_for_term(j, kind, right_side, ci); } - lean_assert(sizes_are_correct()); + lp_assert(sizes_are_correct()); return ci; } @@ -1625,14 +1625,14 @@ void lar_solver::update_column_type_and_bound(var_index j, lconstraint_kind kind update_fixed_column_type_and_bound(j, kind, right_side, constr_index); break; default: - lean_assert(false); // cannot be here + lp_assert(false); // cannot be here } } void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(is_term(j)); + lp_assert(is_term(j)); unsigned adjusted_term_index = adjust_term_index(j); - lean_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int()); + lp_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int()); auto it = m_ext_vars_to_columns.find(j); if (it != m_ext_vars_to_columns.end()) { unsigned term_j = it->second.ext_j(); @@ -1662,11 +1662,11 @@ void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned ter unsigned j = A_r().column_count() - 1; update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size()); m_constraints.push_back(new lar_term_constraint(term, kind, right_side)); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); } void lar_solver::decide_on_strategy_and_adjust_initial_state() { - lean_assert(strategy_is_undecided()); + lp_assert(strategy_is_undecided()); if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { m_settings.simplex_strategy() = simplex_strategy_enum::lu; } @@ -1685,7 +1685,7 @@ void lar_solver::adjust_initial_state() { adjust_initial_state_for_tableau_rows(); break; case simplex_strategy_enum::tableau_costs: - lean_assert(false); // not implemented + lp_assert(false); // not implemented case simplex_strategy_enum::undecided: adjust_initial_state_for_tableau_rows(); break; @@ -1704,12 +1704,12 @@ void lar_solver::adjust_initial_state_for_lu() { /* unsigned j = A_d().column_count(); A_d().add_column(); - lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + lp_assert(m_mpq_lar_core_solver.m_d_x.size() == j); + // lp_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + lp_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method if (register_in_basis) { A_d().add_row(); m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); @@ -1730,13 +1730,13 @@ void lar_solver::adjust_initial_state_for_tableau_rows() { // this fills the last row of A_d and sets the basis column: -1 in the last column of the row void lar_solver::fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); + lp_assert(A.row_count() > 0); + lp_assert(A.column_count() > 0); unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].empty()); + lp_assert(A.m_rows[last_row].empty()); for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); + lp_assert(!is_zero(t.second)); var_index j = t.first; A.set(last_row, j, -t.second.get_double()); } @@ -1752,8 +1752,8 @@ void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind y_of_bound = -1; case LE: m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); - lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + lp_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); { auto up = numeric_pair(right_side, y_of_bound); m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; @@ -1764,7 +1764,7 @@ void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind y_of_bound = 1; case GE: m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound; - lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + lp_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); { auto low = numeric_pair(right_side, y_of_bound); m_mpq_lar_core_solver.m_r_low_bounds[j] = low; @@ -1779,14 +1779,14 @@ void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind break; default: - lean_unreachable(); + lp_unreachable(); } m_columns_with_changed_bound.insert(j); } void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); mpq y_of_bound(0); switch (kind) { case LT: @@ -1839,13 +1839,13 @@ void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstrai break; default: - lean_unreachable(); + lp_unreachable(); } } void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); mpq y_of_bound(0); switch (kind) { case LT: @@ -1861,7 +1861,7 @@ void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kin if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { m_status = INFEASIBLE; - lean_assert(false); + lp_assert(false); m_infeasible_column_index = j; } else { @@ -1914,12 +1914,12 @@ void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kin } default: - lean_unreachable(); + lp_unreachable(); } } void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); + lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); mpq y_of_bound(0); switch (kind) { case LT: @@ -1971,14 +1971,14 @@ void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint } default: - lean_unreachable(); + lp_unreachable(); } } void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); + lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); auto v = numeric_pair(right_side, mpq(0)); mpq y_of_bound(0); @@ -2033,12 +2033,12 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin } default: - lean_unreachable(); + lp_unreachable(); } } -} // namespace lean +} // namespace lp diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index dbccbc9cf..0961d2b8d 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -33,7 +33,7 @@ #include "util/lp/int_solver.h" #include "util/lp/nra_solver.h" -namespace lean { +namespace lp { class lar_solver : public column_namer { @@ -222,7 +222,7 @@ public: vector get_list_of_all_var_indices() const; void push(); - static void clean_large_elements_after_pop(unsigned n, int_set& set); + static void clp_large_elements_after_pop(unsigned n, int_set& set); static void shrink_inf_set_after_pop(unsigned n, int_set & set); @@ -403,7 +403,7 @@ public: void remove_last_column_from_basis_tableau(unsigned j); void remove_column_from_tableau(unsigned j); void pop_tableau(); - void clean_inf_set_of_r_solver_after_pop(); + void clp_inf_set_of_r_solver_after_pop(); void shrink_explanation_to_minimum(vector> & explanation) const; diff --git a/src/util/lp/lar_solver_instances.cpp b/src/util/lp/lar_solver_instances.cpp index 98f59edb9..602df0326 100644 --- a/src/util/lp/lar_solver_instances.cpp +++ b/src/util/lp/lar_solver_instances.cpp @@ -5,7 +5,7 @@ #include "util/lp/lar_solver.cpp" -template void lean::lar_solver::copy_from_mpq_matrix(class lean::static_matrix &); +template void lp::lar_solver::copy_from_mpq_matrix(class lp::static_matrix &); diff --git a/src/util/lp/lar_term.h b/src/util/lp/lar_term.h index dfdedb571..71320b7c3 100644 --- a/src/util/lp/lar_term.h +++ b/src/util/lp/lar_term.h @@ -4,7 +4,7 @@ */ #pragma once #include "util/lp/indexed_vector.h" -namespace lean { +namespace lp { struct lar_term { // the term evaluates to sum of m_coeffs + m_v std::unordered_map m_coeffs; diff --git a/src/util/lp/linear_combination_iterator.h b/src/util/lp/linear_combination_iterator.h index 634accfd4..d8a67f1b8 100644 --- a/src/util/lp/linear_combination_iterator.h +++ b/src/util/lp/linear_combination_iterator.h @@ -3,7 +3,7 @@ Author: Lev Nachmanson */ #pragma once -namespace lean { +namespace lp { template struct linear_combination_iterator { virtual bool next(T & a, unsigned & i) = 0; diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 7599a9d2d..28cb14011 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -16,7 +16,7 @@ #include "util/lp/iterator_on_row.h" #include "util/lp/iterator_on_pivot_row.h" -namespace lean { +namespace lp { template // X represents the type of the x variable and the bounds class lp_core_solver_base { @@ -185,11 +185,11 @@ public: bool need_to_pivot_to_basis_tableau() const { - lean_assert(m_A.is_correct()); + lp_assert(m_A.is_correct()); unsigned m = m_A.row_count(); for (unsigned i = 0; i < m; i++) { unsigned bj = m_basis[i]; - lean_assert(m_A.m_columns[bj].size() > 0); + 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; } return false; @@ -198,7 +198,7 @@ public: bool reduced_costs_are_correct_tableau() const { if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) return true; - lean_assert(m_A.is_correct()); + lp_assert(m_A.is_correct()); if (m_using_infeas_costs) { if (infeasibility_costs_are_correct() == false) { std::cout << "infeasibility_costs_are_correct() does not hold" << std::endl; @@ -373,11 +373,11 @@ public: } bool make_column_feasible(unsigned j, numeric_pair & delta) { - lean_assert(m_basis_heading[j] < 0); + lp_assert(m_basis_heading[j] < 0); auto & x = m_x[j]; switch (m_column_types[j]) { case column_type::fixed: - lean_assert(m_low_bounds[j] == m_upper_bounds[j]); + lp_assert(m_low_bounds[j] == m_upper_bounds[j]); if (x != m_low_bounds[j]) { delta = m_low_bounds[j] - x; x = m_low_bounds[j]; @@ -413,7 +413,7 @@ public: case column_type::free_column: break; default: - lean_assert(false); + lp_assert(false); break; } return false; @@ -462,7 +462,7 @@ public: } void change_basis_unconditionally(unsigned entering, unsigned leaving) { - lean_assert(m_basis_heading[entering] < 0); + lp_assert(m_basis_heading[entering] < 0); int place_in_non_basis = -1 - m_basis_heading[entering]; if (static_cast(place_in_non_basis) >= m_nbasis.size()) { // entering variable in not in m_nbasis, we need to put it back; @@ -481,8 +481,8 @@ public: } void change_basis(unsigned entering, unsigned leaving) { - lean_assert(m_basis_heading[entering] < 0); - lean_assert(m_basis_heading[leaving] >= 0); + lp_assert(m_basis_heading[entering] < 0); + lp_assert(m_basis_heading[leaving] >= 0); int place_in_basis = m_basis_heading[leaving]; int place_in_non_basis = - m_basis_heading[entering] - 1; @@ -523,7 +523,7 @@ public: case column_type::free_column: break; default: - lean_assert(false); + lp_assert(false); break; } return true; @@ -571,7 +571,7 @@ public: case column_type::free_column: break; default: - lean_assert(false); + lp_assert(false); } out << "basis heading = " << m_basis_heading[j] << std::endl; out << "x = " << m_x[j] << std::endl; @@ -670,17 +670,17 @@ public: } void insert_column_into_inf_set(unsigned j) { m_inf_set.insert(j); - lean_assert(!column_is_feasible(j)); + lp_assert(!column_is_feasible(j)); } void remove_column_from_inf_set(unsigned j) { m_inf_set.erase(j); - lean_assert(column_is_feasible(j)); + lp_assert(column_is_feasible(j)); } bool costs_on_nbasis_are_zeros() const { - lean_assert(this->basis_heading_is_correct()); + lp_assert(this->basis_heading_is_correct()); for (unsigned j = 0; j < this->m_n(); j++) { if (this->m_basis_heading[j] < 0) - lean_assert(is_zero(this->m_costs[j])); + lp_assert(is_zero(this->m_costs[j])); } return true; } diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index 48494d207..26d6f49c7 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -7,7 +7,7 @@ #include "util/vector.h" #include "util/lp/lp_utils.h" #include "util/lp/lp_core_solver_base.h" -namespace lean { +namespace lp { template lp_core_solver_base:: lp_core_solver_base(static_matrix & A, @@ -53,7 +53,7 @@ lp_core_solver_base(static_matrix & A, m_tracing_basis_changes(false), m_pivoted_rows(nullptr), m_look_for_feasible_solution_only(false) { - lean_assert(bounds_for_boxed_are_set_correctly()); + lp_assert(bounds_for_boxed_are_set_correctly()); init(); init_basis_heading_and_non_basic_columns_vector(); } @@ -61,7 +61,7 @@ lp_core_solver_base(static_matrix & A, template void lp_core_solver_base:: allocate_basis_heading() { // the rest of initilization will be handled by the factorization class init_basis_heading_and_non_basic_columns_vector(); - lean_assert(basis_heading_is_correct()); + lp_assert(basis_heading_is_correct()); } template void lp_core_solver_base:: init() { @@ -127,7 +127,7 @@ solve_yB(vector & y) { // } // } template void lp_core_solver_base::solve_Bd(unsigned entering, indexed_vector & column) { - lean_assert(!m_settings.use_tableau()); + lp_assert(!m_settings.use_tableau()); if (m_factorization == nullptr) { init_factorization(m_factorization, m_A, m_basis, m_settings); } @@ -137,19 +137,19 @@ template void lp_core_solver_base::solve_Bd(unsig template void lp_core_solver_base:: solve_Bd(unsigned entering) { - lean_assert(m_ed.is_OK()); + lp_assert(m_ed.is_OK()); m_factorization->solve_Bd(entering, m_ed, m_w); if (this->precise()) m_columns_nz[entering] = m_ed.m_index.size(); - lean_assert(m_ed.is_OK()); - lean_assert(m_w.is_OK()); + lp_assert(m_ed.is_OK()); + lp_assert(m_w.is_OK()); #ifdef LEAN_DEBUG // auto B = get_B(*m_factorization, m_basis); // vector a(m_m()); // m_A.copy_column_to_vector(entering, a); // vector cd(m_ed.m_data); // B.apply_from_left(cd, m_settings); - // lean_assert(vectors_are_equal(cd , a)); + // lp_assert(vectors_are_equal(cd , a)); #endif } @@ -208,7 +208,7 @@ restore_m_ed(T * buffer) { template bool lp_core_solver_base:: A_mult_x_is_off() const { - lean_assert(m_x.size() == m_A.column_count()); + lp_assert(m_x.size() == m_A.column_count()); if (numeric_traits::precise()) { for (unsigned i = 0; i < m_m(); i++) { X delta = m_b[i] - m_A.dot_product_with_row(i, m_x); @@ -244,7 +244,7 @@ A_mult_x_is_off() const { } template bool lp_core_solver_base:: A_mult_x_is_off_on_index(const vector & index) const { - lean_assert(m_x.size() == m_A.column_count()); + lp_assert(m_x.size() == m_A.column_count()); if (numeric_traits::precise()) return false; #if RUN_A_MULT_X_IS_OFF_FOR_PRECESE for (unsigned i : index) { @@ -284,13 +284,13 @@ A_mult_x_is_off_on_index(const vector & index) const { // from page 182 of Istvan Maros's book template void lp_core_solver_base:: calculate_pivot_row_of_B_1(unsigned pivot_row) { - lean_assert(! use_tableau()); - lean_assert(m_pivot_row_of_B_1.is_OK()); + lp_assert(! use_tableau()); + lp_assert(m_pivot_row_of_B_1.is_OK()); m_pivot_row_of_B_1.clear(); m_pivot_row_of_B_1.set_value(numeric_traits::one(), pivot_row); - lean_assert(m_pivot_row_of_B_1.is_OK()); + lp_assert(m_pivot_row_of_B_1.is_OK()); m_factorization->solve_yB_with_error_check_indexed(m_pivot_row_of_B_1, m_basis_heading, m_basis, m_settings); - lean_assert(m_pivot_row_of_B_1.is_OK()); + lp_assert(m_pivot_row_of_B_1.is_OK()); } @@ -380,11 +380,11 @@ set_non_basic_x_to_correct_bounds() { break; case column_type::low_bound: m_x[j] = m_low_bounds[j]; - lean_assert(column_is_dual_feasible(j)); + lp_assert(column_is_dual_feasible(j)); break; case column_type::upper_bound: m_x[j] = m_upper_bounds[j]; - lean_assert(column_is_dual_feasible(j)); + lp_assert(column_is_dual_feasible(j)); break; default: break; @@ -402,15 +402,15 @@ column_is_dual_feasible(unsigned j) const { return x_is_at_low_bound(j) && d_is_not_negative(j); case column_type::upper_bound: LP_OUT(m_settings, "upper_bound type should be switched to low_bound" << std::endl); - lean_assert(false); // impossible case + lp_assert(false); // impossible case case column_type::free_column: return numeric_traits::is_zero(m_d[j]); default: LP_OUT(m_settings, "column = " << j << std::endl); LP_OUT(m_settings, "unexpected column type = " << column_type_to_string(m_column_types[j]) << std::endl); - lean_unreachable(); + lp_unreachable(); } - lean_unreachable(); + lp_unreachable(); return false; } template bool lp_core_solver_base:: @@ -493,7 +493,7 @@ template bool lp_core_solver_base::column_is_feas return true; break; default: - lean_unreachable(); + lp_unreachable(); } return false; // it is unreachable } @@ -575,7 +575,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) { restore_x_and_refactor(entering, leaving, tt); if (m_status == FLOATING_POINT_ERROR) return false; - lean_assert(!A_mult_x_is_off()); + lp_assert(!A_mult_x_is_off()); m_iters_with_no_cost_growing++; // LP_OUT(m_settings, "rolled back after failing of init_factorization()" << std::endl); m_status = UNSTABLE; @@ -587,7 +587,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) { template bool lp_core_solver_base:: divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { - lean_assert(numeric_traits::precise()); + lp_assert(numeric_traits::precise()); int pivot_index = -1; auto & row = m_A.m_rows[pivot_row]; unsigned size = row.size(); @@ -628,7 +628,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { return false; if (pivot_col_cell_index != 0) { - lean_assert(column.size() > 1); + 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]; @@ -639,7 +639,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { } while (column.size() > 1) { auto & c = column.back(); - lean_assert(c.m_i != piv_row_index); + lp_assert(c.m_i != piv_row_index); if(! m_A.pivot_row_to_row_given_cell(piv_row_index, c, j)) { return false; } @@ -687,7 +687,7 @@ non_basis_is_correctly_represented_in_heading() const { } for (unsigned j = 0; j < m_A.column_count(); j++) { if (m_basis_heading[j] >= 0) { - lean_assert(static_cast(m_basis_heading[j]) < m_A.row_count() && m_basis[m_basis_heading[j]] == j); + lp_assert(static_cast(m_basis_heading[j]) < m_A.row_count() && m_basis[m_basis_heading[j]] == j); } } return true; @@ -695,9 +695,9 @@ non_basis_is_correctly_represented_in_heading() const { template bool lp_core_solver_base:: basis_heading_is_correct() const { - lean_assert(m_basis_heading.size() == m_A.column_count()); - lean_assert(m_basis.size() == m_A.row_count()); - lean_assert(m_nbasis.size() <= m_A.column_count() - m_A.row_count()); // for the dual the size of non basis can be smaller + lp_assert(m_basis_heading.size() == m_A.column_count()); + lp_assert(m_basis.size() == m_A.row_count()); + lp_assert(m_nbasis.size() <= m_A.column_count() - m_A.row_count()); // for the dual the size of non basis can be smaller if (!basis_has_no_doubles()) { // std::cout << "basis_has_no_doubles" << std::endl; return false; @@ -841,7 +841,7 @@ solve_Ax_eq_b() { template void lp_core_solver_base:: snap_non_basic_x_to_bound_and_free_to_zeroes() { for (unsigned j : non_basis()) { - lean_assert(j < m_x.size()); + lp_assert(j < m_x.size()); switch (m_column_types[j]) { case column_type::fixed: case column_type::boxed: @@ -892,9 +892,9 @@ get_non_basic_column_value_position(unsigned j) const { case column_type::upper_bound: return x_is_at_upper_bound(j)? at_upper_bound : not_at_bound; default: - lean_unreachable(); + lp_unreachable(); } - lean_unreachable(); + lp_unreachable(); return at_low_bound; } @@ -925,8 +925,8 @@ template void lp_core_solver_base::transpose_row } // j is the new basic column, j_basic - the leaving column template bool lp_core_solver_base::pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w) { - lean_assert(m_basis_heading[j] < 0); - lean_assert(m_basis_heading[j_basic] >= 0); + lp_assert(m_basis_heading[j] < 0); + lp_assert(m_basis_heading[j_basic] >= 0); unsigned row_index = m_basis_heading[j_basic]; if (m_settings.m_simplex_strategy == simplex_strategy_enum::lu) { if (m_factorization->need_to_refactor()) { @@ -980,7 +980,7 @@ template bool lp_core_solver_base::infeasibility_costs_are_correct() const { if (! this->m_using_infeas_costs) return true; - lean_assert(costs_on_nbasis_are_zeros()); + lp_assert(costs_on_nbasis_are_zeros()); for (unsigned j :this->m_basis) { if (!infeasibility_cost_is_correct_for_column(j)) { std::cout << "infeasibility_cost_is_correct_for_column does not hold\n"; @@ -1025,15 +1025,15 @@ lp_core_solver_base::infeasibility_cost_is_correct_for_column(unsigned j) case column_type::free_column: return is_zero(this->m_costs[j]); default: - lean_assert(false); + lp_assert(false); return true; } } template void lp_core_solver_base::calculate_pivot_row(unsigned i) { - lean_assert(!use_tableau()); - lean_assert(m_pivot_row.is_OK()); + lp_assert(!use_tableau()); + lp_assert(m_pivot_row.is_OK()); m_pivot_row_of_B_1.clear(); m_pivot_row_of_B_1.resize(m_m()); m_pivot_row.clear(); diff --git a/src/util/lp/lp_core_solver_base_instances.cpp b/src/util/lp/lp_core_solver_base_instances.cpp index d473594c8..1f9d459bf 100644 --- a/src/util/lp/lp_core_solver_base_instances.cpp +++ b/src/util/lp/lp_core_solver_base_instances.cpp @@ -8,125 +8,125 @@ #include "util/vector.h" #include #include "util/lp/lp_core_solver_base.hpp" -template bool lean::lp_core_solver_base::A_mult_x_is_off() const; -template bool lean::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; -template bool lean::lp_core_solver_base::basis_heading_is_correct() const; -template void lean::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); -template void lean::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); -template bool lean::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; -template void lean::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); -template bool lean::lp_core_solver_base::find_x_by_solving(); -template lean::non_basic_column_value_position lean::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; -template lean::non_basic_column_value_position lean::lp_core_solver_base >::get_non_basic_column_value_position(unsigned int) const; -template lean::non_basic_column_value_position lean::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; -template void lean::lp_core_solver_base::init_reduced_costs_for_one_iteration(); -template lean::lp_core_solver_base::lp_core_solver_base( - lean::static_matrix&, vector&, +template bool lp::lp_core_solver_base::A_mult_x_is_off() const; +template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; +template bool lp::lp_core_solver_base::basis_heading_is_correct() const; +template void lp::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); +template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); +template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; +template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); +template bool lp::lp_core_solver_base::find_x_by_solving(); +template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; +template lp::non_basic_column_value_position lp::lp_core_solver_base >::get_non_basic_column_value_position(unsigned int) const; +template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; +template void lp::lp_core_solver_base::init_reduced_costs_for_one_iteration(); +template lp::lp_core_solver_base::lp_core_solver_base( + lp::static_matrix&, vector&, vector&, vector &, vector &, vector&, vector&, - lean::lp_settings&, const column_namer&, const vector&, + lp::lp_settings&, const column_namer&, const vector&, const vector&, const vector&); -template bool lean::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template bool lean::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template void lean::lp_core_solver_base::restore_x(unsigned int, double const&); -template void lean::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); -template void lean::lp_core_solver_base::snap_xN_to_bounds_and_free_columns_to_zeroes(); -template void lean::lp_core_solver_base >::snap_xN_to_bounds_and_free_columns_to_zeroes(); -template void lean::lp_core_solver_base::solve_Ax_eq_b(); -template void lean::lp_core_solver_base::solve_Bd(unsigned int); -template void lean::lp_core_solver_base>::solve_Bd(unsigned int, indexed_vector&); -template void lean::lp_core_solver_base::solve_yB(vector&); -template bool lean::lp_core_solver_base::update_basis_and_x(int, int, double const&); -template void lean::lp_core_solver_base::update_x(unsigned int, const double&); -template bool lean::lp_core_solver_base::A_mult_x_is_off() const; -template bool lean::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; -template bool lean::lp_core_solver_base::basis_heading_is_correct() const ; -template void lean::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); -template void lean::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); -template bool lean::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; -template void lean::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); -template bool lean::lp_core_solver_base::find_x_by_solving(); -template void lean::lp_core_solver_base::init_reduced_costs_for_one_iteration(); -template bool lean::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template void lean::lp_core_solver_base::restore_x(unsigned int, lean::mpq const&); -template void lean::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); -template void lean::lp_core_solver_base::solve_Ax_eq_b(); -template void lean::lp_core_solver_base::solve_Bd(unsigned int); -template void lean::lp_core_solver_base::solve_yB(vector&); -template bool lean::lp_core_solver_base::update_basis_and_x(int, int, lean::mpq const&); -template void lean::lp_core_solver_base::update_x(unsigned int, const lean::mpq&); -template void lean::lp_core_solver_base >::calculate_pivot_row_of_B_1(unsigned int); -template void lean::lp_core_solver_base >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); -template void lean::lp_core_solver_base >::init(); -template void lean::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); -template void lean::lp_core_solver_base >::init_reduced_costs_for_one_iteration(); -template lean::lp_core_solver_base >::lp_core_solver_base(lean::static_matrix >&, vector >&, vector&, vector &, vector &, vector >&, vector&, lean::lp_settings&, const column_namer&, const vector&, - const vector >&, - const vector >&); -template bool lean::lp_core_solver_base >::print_statistics_with_cost_and_check_that_the_time_is_over(lean::numeric_pair, std::ostream&); -template void lean::lp_core_solver_base >::snap_xN_to_bounds_and_fill_xB(); -template void lean::lp_core_solver_base >::solve_Bd(unsigned int); -template bool lean::lp_core_solver_base >::update_basis_and_x(int, int, lean::numeric_pair const&); -template void lean::lp_core_solver_base >::update_x(unsigned int, const lean::numeric_pair&); -template lean::lp_core_solver_base::lp_core_solver_base( - lean::static_matrix&, - vector&, +template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); +template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); +template void lp::lp_core_solver_base::restore_x(unsigned int, double const&); +template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); +template void lp::lp_core_solver_base::snap_xN_to_bounds_and_free_columns_to_zeroes(); +template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_free_columns_to_zeroes(); +template void lp::lp_core_solver_base::solve_Ax_eq_b(); +template void lp::lp_core_solver_base::solve_Bd(unsigned int); +template void lp::lp_core_solver_base>::solve_Bd(unsigned int, indexed_vector&); +template void lp::lp_core_solver_base::solve_yB(vector&); +template bool lp::lp_core_solver_base::update_basis_and_x(int, int, double const&); +template void lp::lp_core_solver_base::update_x(unsigned int, const double&); +template bool lp::lp_core_solver_base::A_mult_x_is_off() const; +template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; +template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; +template void lp::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); +template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); +template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; +template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); +template bool lp::lp_core_solver_base::find_x_by_solving(); +template void lp::lp_core_solver_base::init_reduced_costs_for_one_iteration(); +template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); +template void lp::lp_core_solver_base::restore_x(unsigned int, lp::mpq const&); +template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); +template void lp::lp_core_solver_base::solve_Ax_eq_b(); +template void lp::lp_core_solver_base::solve_Bd(unsigned int); +template void lp::lp_core_solver_base::solve_yB(vector&); +template bool lp::lp_core_solver_base::update_basis_and_x(int, int, lp::mpq const&); +template void lp::lp_core_solver_base::update_x(unsigned int, const lp::mpq&); +template void lp::lp_core_solver_base >::calculate_pivot_row_of_B_1(unsigned int); +template void lp::lp_core_solver_base >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); +template void lp::lp_core_solver_base >::init(); +template void lp::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); +template void lp::lp_core_solver_base >::init_reduced_costs_for_one_iteration(); +template lp::lp_core_solver_base >::lp_core_solver_base(lp::static_matrix >&, vector >&, vector&, vector &, vector &, vector >&, vector&, lp::lp_settings&, const column_namer&, const vector&, + const vector >&, + const vector >&); +template bool lp::lp_core_solver_base >::print_statistics_with_cost_and_check_that_the_time_is_over(lp::numeric_pair, std::ostream&); +template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_fill_xB(); +template void lp::lp_core_solver_base >::solve_Bd(unsigned int); +template bool lp::lp_core_solver_base >::update_basis_and_x(int, int, lp::numeric_pair const&); +template void lp::lp_core_solver_base >::update_x(unsigned int, const lp::numeric_pair&); +template lp::lp_core_solver_base::lp_core_solver_base( + lp::static_matrix&, + vector&, vector&, vector &, vector &, - vector&, - vector&, - lean::lp_settings&, + vector&, + vector&, + lp::lp_settings&, const column_namer&, - const vector&, - const vector&, - const vector&); -template bool lean::lp_core_solver_base >::print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream &); -template std::string lean::lp_core_solver_base::column_name(unsigned int) const; -template void lean::lp_core_solver_base::pretty_print(std::ostream & out); -template void lean::lp_core_solver_base::restore_state(double*, double*); -template void lean::lp_core_solver_base::save_state(double*, double*); -template std::string lean::lp_core_solver_base::column_name(unsigned int) const; -template void lean::lp_core_solver_base::pretty_print(std::ostream & out); -template void lean::lp_core_solver_base::restore_state(lean::mpq*, lean::mpq*); -template void lean::lp_core_solver_base::save_state(lean::mpq*, lean::mpq*); -template std::string lean::lp_core_solver_base >::column_name(unsigned int) const; -template void lean::lp_core_solver_base >::pretty_print(std::ostream & out); -template void lean::lp_core_solver_base >::restore_state(lean::mpq*, lean::mpq*); -template void lean::lp_core_solver_base >::save_state(lean::mpq*, lean::mpq*); -template void lean::lp_core_solver_base >::solve_yB(vector&); -template void lean::lp_core_solver_base::init_lu(); -template void lean::lp_core_solver_base::init_lu(); -template int lean::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; -template int lean::lp_core_solver_base >::pivots_in_column_and_row_are_different(int, int) const; -template int lean::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; -template bool lean::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; -template bool lean::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; -template bool lean::lp_core_solver_base >::calc_current_x_is_feasible_include_non_basis() const; -template void lean::lp_core_solver_base >::pivot_fixed_vars_from_basis(); -template bool lean::lp_core_solver_base::column_is_feasible(unsigned int) const; -template bool lean::lp_core_solver_base::column_is_feasible(unsigned int) const; -// template void lean::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; -template bool lean::lp_core_solver_base >::column_is_feasible(unsigned int) const; -template bool lean::lp_core_solver_base >::snap_non_basic_x_to_bound(); -template void lean::lp_core_solver_base >::init_lu(); -template bool lean::lp_core_solver_base >::A_mult_x_is_off_on_index(vector const&) const; -template bool lean::lp_core_solver_base >::find_x_by_solving(); -template void lean::lp_core_solver_base >::restore_x(unsigned int, lean::numeric_pair const&); -template bool lean::lp_core_solver_base::pivot_for_tableau_on_basis(); -template bool lean::lp_core_solver_base::pivot_for_tableau_on_basis(); -template bool lean::lp_core_solver_base>::pivot_for_tableau_on_basis(); -template bool lean::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); -template bool lean::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); -template bool lean::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); -template void lean::lp_core_solver_base >::transpose_rows_tableau(unsigned int, unsigned int); -template bool lean::lp_core_solver_base >::inf_set_is_correct() const; -template bool lean::lp_core_solver_base::inf_set_is_correct() const; -template bool lean::lp_core_solver_base::inf_set_is_correct() const; -template bool lean::lp_core_solver_base >::infeasibility_costs_are_correct() const; -template bool lean::lp_core_solver_base::infeasibility_costs_are_correct() const; -template bool lean::lp_core_solver_base::infeasibility_costs_are_correct() const; -template void lean::lp_core_solver_base >::calculate_pivot_row(unsigned int); + const vector&, + const vector&, + const vector&); +template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream &); +template std::string lp::lp_core_solver_base::column_name(unsigned int) const; +template void lp::lp_core_solver_base::pretty_print(std::ostream & out); +template void lp::lp_core_solver_base::restore_state(double*, double*); +template void lp::lp_core_solver_base::save_state(double*, double*); +template std::string lp::lp_core_solver_base::column_name(unsigned int) const; +template void lp::lp_core_solver_base::pretty_print(std::ostream & out); +template void lp::lp_core_solver_base::restore_state(lp::mpq*, lp::mpq*); +template void lp::lp_core_solver_base::save_state(lp::mpq*, lp::mpq*); +template std::string lp::lp_core_solver_base >::column_name(unsigned int) const; +template void lp::lp_core_solver_base >::pretty_print(std::ostream & out); +template void lp::lp_core_solver_base >::restore_state(lp::mpq*, lp::mpq*); +template void lp::lp_core_solver_base >::save_state(lp::mpq*, lp::mpq*); +template void lp::lp_core_solver_base >::solve_yB(vector&); +template void lp::lp_core_solver_base::init_lu(); +template void lp::lp_core_solver_base::init_lu(); +template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; +template int lp::lp_core_solver_base >::pivots_in_column_and_row_are_different(int, int) const; +template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; +template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; +template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; +template bool lp::lp_core_solver_base >::calc_current_x_is_feasible_include_non_basis() const; +template void lp::lp_core_solver_base >::pivot_fixed_vars_from_basis(); +template bool lp::lp_core_solver_base::column_is_feasible(unsigned int) const; +template bool lp::lp_core_solver_base::column_is_feasible(unsigned int) const; +// template void lp::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; +template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; +template bool lp::lp_core_solver_base >::snap_non_basic_x_to_bound(); +template void lp::lp_core_solver_base >::init_lu(); +template bool lp::lp_core_solver_base >::A_mult_x_is_off_on_index(vector const&) const; +template bool lp::lp_core_solver_base >::find_x_by_solving(); +template void lp::lp_core_solver_base >::restore_x(unsigned int, lp::numeric_pair const&); +template bool lp::lp_core_solver_base::pivot_for_tableau_on_basis(); +template bool lp::lp_core_solver_base::pivot_for_tableau_on_basis(); +template bool lp::lp_core_solver_base>::pivot_for_tableau_on_basis(); +template bool lp::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); +template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); +template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); +template void lp::lp_core_solver_base >::transpose_rows_tableau(unsigned int, unsigned int); +template bool lp::lp_core_solver_base >::inf_set_is_correct() const; +template bool lp::lp_core_solver_base::inf_set_is_correct() const; +template bool lp::lp_core_solver_base::inf_set_is_correct() const; +template bool lp::lp_core_solver_base >::infeasibility_costs_are_correct() const; +template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; +template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; +template void lp::lp_core_solver_base >::calculate_pivot_row(unsigned int); diff --git a/src/util/lp/lp_dual_core_solver.h b/src/util/lp/lp_dual_core_solver.h index b873cb711..71a00c268 100644 --- a/src/util/lp/lp_dual_core_solver.h +++ b/src/util/lp/lp_dual_core_solver.h @@ -11,7 +11,7 @@ #include #include "util/vector.h" -namespace lean { +namespace lp { template class lp_dual_core_solver:public lp_core_solver_base { public: diff --git a/src/util/lp/lp_dual_core_solver.hpp b/src/util/lp/lp_dual_core_solver.hpp index 6565331b3..5038fc4ea 100644 --- a/src/util/lp/lp_dual_core_solver.hpp +++ b/src/util/lp/lp_dual_core_solver.hpp @@ -7,7 +7,7 @@ #include "util/vector.h" #include "util/lp/lp_dual_core_solver.h" -namespace lean { +namespace lp { template void lp_dual_core_solver::init_a_wave_by_zeros() { unsigned j = this->m_m(); @@ -23,7 +23,7 @@ template void lp_dual_core_solver::restore_non_ba while (j--) { if (this->m_basis_heading[j] >= 0 ) continue; if (m_can_enter_basis[j]) { - lean_assert(std::find(nb.begin(), nb.end(), j) == nb.end()); + lp_assert(std::find(nb.begin(), nb.end(), j) == nb.end()); nb.push_back(j); this->m_basis_heading[j] = - static_cast(nb.size()); } @@ -93,14 +93,14 @@ template bool lp_dual_core_solver::done() { } template T lp_dual_core_solver::get_edge_steepness_for_low_bound(unsigned p) { - lean_assert(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); + lp_assert(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); T del = this->m_x[p] - this->m_low_bounds[p]; del *= del; return del / this->m_betas[this->m_basis_heading[p]]; } template T lp_dual_core_solver::get_edge_steepness_for_upper_bound(unsigned p) { - lean_assert(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); + lp_assert(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); T del = this->m_x[p] - this->m_upper_bounds[p]; del *= del; return del / this->m_betas[this->m_basis_heading[p]]; @@ -135,12 +135,12 @@ template T lp_dual_core_solver::pricing_for_row(u return numeric_traits::zero(); break; case column_type::free_column: - lean_assert(numeric_traits::is_zero(this->m_d[p])); + lp_assert(numeric_traits::is_zero(this->m_d[p])); return numeric_traits::zero(); default: - lean_unreachable(); + lp_unreachable(); } - lean_unreachable(); + lp_unreachable(); return numeric_traits::zero(); } @@ -209,9 +209,9 @@ template bool lp_dual_core_solver::advance_on_kno int pivot_compare_result = this->pivots_in_column_and_row_are_different(m_q, m_p); if (!pivot_compare_result){;} else if (pivot_compare_result == 2) { // the sign is changed, cannot continue - lean_unreachable(); // not implemented yet + lp_unreachable(); // not implemented yet } else { - lean_assert(pivot_compare_result == 1); + lp_assert(pivot_compare_result == 1); this->init_lu(); } DSE_FTran(); @@ -228,21 +228,21 @@ template int lp_dual_core_solver::define_sign_of_ if (this->x_above_upper_bound(m_p)) { return 1; } - lean_unreachable(); + lp_unreachable(); case column_type::low_bound: if (this->x_below_low_bound(m_p)) { return -1; } - lean_unreachable(); + lp_unreachable(); case column_type::upper_bound: if (this->x_above_upper_bound(m_p)) { return 1; } - lean_unreachable(); + lp_unreachable(); default: - lean_unreachable(); + lp_unreachable(); } - lean_unreachable(); + lp_unreachable(); return 0; } @@ -250,10 +250,10 @@ template bool lp_dual_core_solver::can_be_breakpo if (this->pivot_row_element_is_too_small_for_ratio_test(j)) return false; switch (this->m_column_types[j]) { case column_type::low_bound: - lean_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_low_bounds[j])); + lp_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_low_bounds[j])); return m_sign_of_alpha_r * this->m_pivot_row[j] > 0; case column_type::upper_bound: - lean_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_upper_bounds[j])); + lp_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_upper_bounds[j])); return m_sign_of_alpha_r * this->m_pivot_row[j] < 0; case column_type::boxed: { @@ -292,23 +292,23 @@ template T lp_dual_core_solver::get_delta() { if (this->x_above_upper_bound(m_p)) { return this->m_x[m_p] - this->m_upper_bounds[m_p]; } - lean_unreachable(); + lp_unreachable(); case column_type::low_bound: if (this->x_below_low_bound(m_p)) { return this->m_x[m_p] - this->m_low_bounds[m_p]; } - lean_unreachable(); + lp_unreachable(); case column_type::upper_bound: if (this->x_above_upper_bound(m_p)) { return get_edge_steepness_for_upper_bound(m_p); } - lean_unreachable(); + lp_unreachable(); case column_type::fixed: return this->m_x[m_p] - this->m_upper_bounds[m_p]; default: - lean_unreachable(); + lp_unreachable(); } - lean_unreachable(); + lp_unreachable(); return zero_of_type(); } @@ -355,7 +355,7 @@ template void lp_dual_core_solver::update_betas() template void lp_dual_core_solver::apply_flips() { for (unsigned j : m_flipped_boxed) { - lean_assert(this->x_is_at_bound(j)); + lp_assert(this->x_is_at_bound(j)); if (this->x_is_at_low_bound(j)) { this->m_x[j] = this->m_upper_bounds[j]; } else { @@ -385,7 +385,7 @@ template void lp_dual_core_solver::snap_xN_column case column_type::free_column: break; default: - lean_unreachable(); + lp_unreachable(); } } @@ -441,7 +441,7 @@ template bool lp_dual_core_solver::basis_change_a return false; } - lean_assert(d_is_correct()); + lp_assert(d_is_correct()); return true; } @@ -457,7 +457,7 @@ template void lp_dual_core_solver::recover_leavin case free_of_bounds: this->m_x[m_q] = zero_of_type(); default: - lean_unreachable(); + lp_unreachable(); } } @@ -584,7 +584,7 @@ template bool lp_dual_core_solver::tight_breakpoi template T lp_dual_core_solver::calculate_harris_delta_on_breakpoint_set() { bool first_time = true; T ret = zero_of_type(); - lean_assert(m_breakpoint_set.size() > 0); + lp_assert(m_breakpoint_set.size() > 0); for (auto j : m_breakpoint_set) { T t; if (this->x_is_at_low_bound(j)) { @@ -633,7 +633,7 @@ template void lp_dual_core_solver::find_q_on_tigh } } m_tight_set.erase(m_q); - lean_assert(m_q != -1); + lp_assert(m_q != -1); } template void lp_dual_core_solver::find_q_and_tight_set() { @@ -722,13 +722,13 @@ template void lp_dual_core_solver::one_iteration( this->set_status(FEASIBLE); } pricing_loop(number_of_rows_to_try, offset_in_rows); - lean_assert(problem_is_dual_feasible()); + lp_assert(problem_is_dual_feasible()); } template void lp_dual_core_solver::solve() { // see the page 35 - lean_assert(d_is_correct()); - lean_assert(problem_is_dual_feasible()); - lean_assert(this->basis_heading_is_correct()); + lp_assert(d_is_correct()); + lp_assert(problem_is_dual_feasible()); + lp_assert(this->basis_heading_is_correct()); this->set_total_iterations(0); this->iters_with_no_cost_growing() = 0; do { diff --git a/src/util/lp/lp_dual_core_solver_instances.cpp b/src/util/lp/lp_dual_core_solver_instances.cpp index 8016088f8..9484d34a3 100644 --- a/src/util/lp/lp_dual_core_solver_instances.cpp +++ b/src/util/lp/lp_dual_core_solver_instances.cpp @@ -8,22 +8,22 @@ #include "util/vector.h" #include #include "util/lp/lp_dual_core_solver.hpp" -template void lean::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); -template void lean::lp_dual_core_solver::solve(); -template lean::lp_dual_core_solver::lp_dual_core_solver(lean::static_matrix&, vector&, +template void lp::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); +template void lp::lp_dual_core_solver::solve(); +template lp::lp_dual_core_solver::lp_dual_core_solver(lp::static_matrix&, vector&, vector&, vector&, vector&, vector &, vector &, vector&, - vector&, + vector&, vector&, vector&, - lean::lp_settings&, const lean::column_namer&); -template void lean::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); -template void lean::lp_dual_core_solver::solve(); -template void lean::lp_dual_core_solver::restore_non_basis(); -template void lean::lp_dual_core_solver::restore_non_basis(); -template void lean::lp_dual_core_solver::revert_to_previous_basis(); -template void lean::lp_dual_core_solver::revert_to_previous_basis(); + lp::lp_settings&, const lp::column_namer&); +template void lp::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); +template void lp::lp_dual_core_solver::solve(); +template void lp::lp_dual_core_solver::restore_non_basis(); +template void lp::lp_dual_core_solver::restore_non_basis(); +template void lp::lp_dual_core_solver::revert_to_previous_basis(); +template void lp::lp_dual_core_solver::revert_to_previous_basis(); diff --git a/src/util/lp/lp_dual_simplex.h b/src/util/lp/lp_dual_simplex.h index 4dff2a4f1..58d9b7240 100644 --- a/src/util/lp/lp_dual_simplex.h +++ b/src/util/lp/lp_dual_simplex.h @@ -7,7 +7,7 @@ #include "util/lp/lp_utils.h" #include "util/lp/lp_solver.h" #include "util/lp/lp_dual_core_solver.h" -namespace lean { +namespace lp { template class lp_dual_simplex: public lp_solver { diff --git a/src/util/lp/lp_dual_simplex.hpp b/src/util/lp/lp_dual_simplex.hpp index 5047e117f..8e16853a8 100644 --- a/src/util/lp/lp_dual_simplex.hpp +++ b/src/util/lp/lp_dual_simplex.hpp @@ -3,7 +3,7 @@ Author: Lev Nachmanson */ #include "util/lp/lp_dual_simplex.h" -namespace lean{ +namespace lp{ template void lp_dual_simplex::decide_on_status_after_stage1() { switch (m_core_solver->get_status()) { @@ -15,7 +15,7 @@ template void lp_dual_simplex::decide_on_status_a } break; case DUAL_UNBOUNDED: - lean_unreachable(); + lp_unreachable(); case ITERATIONS_EXHAUSTED: this->m_status = ITERATIONS_EXHAUSTED; break; @@ -26,12 +26,12 @@ template void lp_dual_simplex::decide_on_status_a this->m_status = FLOATING_POINT_ERROR; break; default: - lean_unreachable(); + lp_unreachable(); } } template void lp_dual_simplex::fix_logical_for_stage2(unsigned j) { - lean_assert(j >= this->number_of_core_structurals()); + lp_assert(j >= this->number_of_core_structurals()); switch (m_column_types_of_logicals[j - this->number_of_core_structurals()]) { case column_type::low_bound: m_low_bounds[j] = numeric_traits::zero(); @@ -44,7 +44,7 @@ template void lp_dual_simplex::fix_logical_for_st m_can_enter_basis[j] = false; break; default: - lean_unreachable(); + lp_unreachable(); } } @@ -58,7 +58,7 @@ template void lp_dual_simplex::fix_structural_for break; case column_type::fixed: case column_type::upper_bound: - lean_unreachable(); + lp_unreachable(); case column_type::boxed: this->m_upper_bounds[j] = ci->get_adjusted_upper_bound() / this->m_column_scale[j]; m_low_bounds[j] = numeric_traits::zero(); @@ -70,7 +70,7 @@ template void lp_dual_simplex::fix_structural_for m_column_types_of_core_solver[j] = column_type::free_column; break; default: - lean_unreachable(); + lp_unreachable(); } // T cost_was = this->m_costs[j]; this->set_scaled_cost(j); @@ -115,7 +115,7 @@ template void lp_dual_simplex::solve_for_stage2() this->m_status = FLOATING_POINT_ERROR; break; default: - lean_unreachable(); + lp_unreachable(); } this->m_second_stage_iterations = m_core_solver->total_iterations(); this->m_total_iterations = (this->m_first_stage_iterations + this->m_second_stage_iterations); @@ -129,7 +129,7 @@ template void lp_dual_simplex::fill_x_with_zeros( } template void lp_dual_simplex::stage1() { - lean_assert(m_core_solver == nullptr); + lp_assert(m_core_solver == nullptr); this->m_x.resize(this->m_A->column_count(), numeric_traits::zero()); if (this->m_settings.get_message_ostream() != nullptr) this->print_statistics_on_A(*this->m_settings.get_message_ostream()); @@ -177,7 +177,7 @@ template void lp_dual_simplex::fill_first_stage_s } template column_type lp_dual_simplex::get_column_type(unsigned j) { - lean_assert(j < this->m_A->column_count()); + lp_assert(j < this->m_A->column_count()); if (j >= this->number_of_core_structurals()) { return m_column_types_of_logicals[j - this->number_of_core_structurals()]; } @@ -186,12 +186,12 @@ template column_type lp_dual_simplex::get_column_ template void lp_dual_simplex::fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_structural_column(unsigned j) { // see 4.7 in the dissertation of Achim Koberstein - lean_assert(this->m_core_solver_columns_to_external_columns.find(j) != + lp_assert(this->m_core_solver_columns_to_external_columns.find(j) != this->m_core_solver_columns_to_external_columns.end()); T free_bound = T(1e4); // see 4.8 unsigned jj = this->m_core_solver_columns_to_external_columns[j]; - lean_assert(this->m_map_from_var_index_to_column_info.find(jj) != this->m_map_from_var_index_to_column_info.end()); + lp_assert(this->m_map_from_var_index_to_column_info.find(jj) != this->m_map_from_var_index_to_column_info.end()); column_info * ci = this->m_map_from_var_index_to_column_info[jj]; switch (ci->get_column_type()) { case column_type::upper_bound: { @@ -221,14 +221,14 @@ template void lp_dual_simplex::fill_costs_bounds_ this->m_upper_bounds[j] = this->m_low_bounds[j] = numeric_traits::zero(); // is it needed? break; default: - lean_unreachable(); + lp_unreachable(); } m_column_types_of_core_solver[j] = column_type::boxed; } template void lp_dual_simplex::fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_logical_column(unsigned j) { this->m_costs[j] = 0; - lean_assert(get_column_type(j) != column_type::upper_bound); + lp_assert(get_column_type(j) != column_type::upper_bound); if ((m_can_enter_basis[j] = (get_column_type(j) == column_type::low_bound))) { m_column_types_of_core_solver[j] = column_type::boxed; this->m_low_bounds[j] = numeric_traits::zero(); @@ -254,7 +254,7 @@ template void lp_dual_simplex::fill_costs_and_bou template void lp_dual_simplex::fill_first_stage_solver_fields_for_row_slack_and_artificial(unsigned row, unsigned & slack_var, unsigned & artificial) { - lean_assert(row < this->row_count()); + lp_assert(row < this->row_count()); auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[row]]; // we need to bring the program to the form Ax = b T rs = this->m_b[row]; @@ -335,7 +335,7 @@ template void lp_dual_simplex::find_maximal_solut this->flip_costs(); // do it for now, todo ( remove the flipping) - this->cleanup(); + this->clpup(); if (this->m_status == INFEASIBLE) { return; } diff --git a/src/util/lp/lp_dual_simplex_instances.cpp b/src/util/lp/lp_dual_simplex_instances.cpp index 6610814d8..a79a93748 100644 --- a/src/util/lp/lp_dual_simplex_instances.cpp +++ b/src/util/lp/lp_dual_simplex_instances.cpp @@ -3,7 +3,7 @@ Author: Lev Nachmanson */ #include "util/lp/lp_dual_simplex.hpp" -template lean::mpq lean::lp_dual_simplex::get_current_cost() const; -template void lean::lp_dual_simplex::find_maximal_solution(); -template double lean::lp_dual_simplex::get_current_cost() const; -template void lean::lp_dual_simplex::find_maximal_solution(); +template lp::mpq lp::lp_dual_simplex::get_current_cost() const; +template void lp::lp_dual_simplex::find_maximal_solution(); +template double lp::lp_dual_simplex::get_current_cost() const; +template void lp::lp_dual_simplex::find_maximal_solution(); diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index f77aae6eb..498288726 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -23,7 +23,7 @@ #include "util/lp/binary_heap_priority_queue.h" #include "util/lp/int_set.h" #include "util/lp/iterator_on_row.h" -namespace lean { +namespace lp { // This core solver solves (Ax=b, low_bound_values \leq x \leq upper_bound_values, maximize costs*x ) // The right side b is given implicitly by x and the basis @@ -70,7 +70,7 @@ public: // unsigned len = 100000000; // for (unsigned j : this->m_inf_set.m_index) { // int i = this->m_basis_heading[j]; - // lean_assert(i >= 0); + // lp_assert(i >= 0); // unsigned row_len = this->m_A.m_rows[i].size(); // if (row_len < len) { // choices.clear(); @@ -98,8 +98,8 @@ public: bool column_is_benefitial_for_entering_basis_on_sign_row_strategy(unsigned j, int sign) const { // sign = 1 means the x of the basis column of the row has to grow to become feasible, when the coeff before j is neg, or x - has to diminish when the coeff is pos // we have xbj = -aj * xj - lean_assert(this->m_basis_heading[j] < 0); - lean_assert(this->column_is_feasible(j)); + lp_assert(this->m_basis_heading[j] < 0); + lp_assert(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: return true; case column_type::fixed: return false; @@ -117,13 +117,13 @@ public: return !this->x_is_at_upper_bound(j); } - lean_assert(false); // cannot be here + lp_assert(false); // cannot be here return false; } bool needs_to_grow(unsigned bj) const { - lean_assert(!this->column_is_feasible(bj)); + lp_assert(!this->column_is_feasible(bj)); switch(this->m_column_types[bj]) { case column_type::free_column: return false; @@ -134,12 +134,12 @@ public: default: return false; } - lean_assert(false); // unreachable + lp_assert(false); // unreachable return false; } int inf_sign_of_column(unsigned bj) const { - lean_assert(!this->column_is_feasible(bj)); + lp_assert(!this->column_is_feasible(bj)); switch(this->m_column_types[bj]) { case column_type::free_column: return 0; @@ -151,7 +151,7 @@ public: default: return -1; } - lean_assert(false); // unreachable + lp_assert(false); // unreachable return 0; } @@ -159,7 +159,7 @@ public: bool monoid_can_decrease(const row_cell & rc) const { unsigned j = rc.m_j; - lean_assert(this->column_is_feasible(j)); + lp_assert(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: return true; @@ -186,13 +186,13 @@ public: default: return false; } - lean_assert(false); // unreachable + lp_assert(false); // unreachable return false; } bool monoid_can_increase(const row_cell & rc) const { unsigned j = rc.m_j; - lean_assert(this->column_is_feasible(j)); + lp_assert(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: return true; @@ -219,7 +219,7 @@ public: default: return false; } - lean_assert(false); // unreachable + lp_assert(false); // unreachable return false; } @@ -329,24 +329,24 @@ public: } void limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m < 0 && this->m_column_types[j] == column_type::upper_bound); + lp_assert(m < 0 && this->m_column_types[j] == column_type::upper_bound); limit_inf_on_upper_bound_m_neg(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); } void limit_theta_on_basis_column_for_inf_case_m_neg_low_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m < 0 && this->m_column_types[j] == column_type::low_bound); + lp_assert(m < 0 && this->m_column_types[j] == column_type::low_bound); limit_inf_on_bound_m_neg(m, this->m_x[j], this->m_low_bounds[j], theta, unlimited); } void limit_theta_on_basis_column_for_inf_case_m_pos_low_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m > 0 && this->m_column_types[j] == column_type::low_bound); + lp_assert(m > 0 && this->m_column_types[j] == column_type::low_bound); limit_inf_on_low_bound_m_pos(m, this->m_x[j], this->m_low_bounds[j], theta, unlimited); } void limit_theta_on_basis_column_for_inf_case_m_pos_upper_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m > 0 && this->m_column_types[j] == column_type::upper_bound); + lp_assert(m > 0 && this->m_column_types[j] == column_type::upper_bound); limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); }; @@ -388,7 +388,7 @@ public: bool need_to_switch_costs() const { if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) return false; - // lean_assert(calc_current_x_is_feasible() == current_x_is_feasible()); + // lp_assert(calc_current_x_is_feasible() == current_x_is_feasible()); return this->current_x_is_feasible() == this->m_using_infeas_costs; } @@ -443,7 +443,7 @@ public: if (j == -1) return -1; - lean_assert(!this->column_is_feasible(j)); + lp_assert(!this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::fixed: case column_type::upper_bound: @@ -459,7 +459,7 @@ public: new_val_for_leaving = this->m_low_bounds[j]; break; default: - lean_assert(false); + lp_assert(false); new_val_for_leaving = numeric_traits::zero(); // does not matter } return j; @@ -490,7 +490,7 @@ public: } X theta = (this->m_x[leaving] - new_val_for_leaving) / a_ent; advance_on_entering_and_leaving_tableau_rows(entering, leaving, theta ); - lean_assert(this->m_x[leaving] == new_val_for_leaving); + lp_assert(this->m_x[leaving] == new_val_for_leaving); if (this->current_x_is_feasible()) this->set_status(OPTIMAL); } @@ -507,13 +507,13 @@ public: void update_basis_and_x_with_comparison(unsigned entering, unsigned leaving, X delta); void decide_on_status_when_cannot_find_entering() { - lean_assert(!need_to_switch_costs()); + lp_assert(!need_to_switch_costs()); this->set_status(this->current_x_is_feasible()? OPTIMAL: INFEASIBLE); } // void limit_theta_on_basis_column_for_feas_case_m_neg(unsigned j, const T & m, X & theta) { - // lean_assert(m < 0); - // lean_assert(this->m_column_type[j] == low_bound || this->m_column_type[j] == boxed); + // lp_assert(m < 0); + // lp_assert(this->m_column_type[j] == low_bound || this->m_column_type[j] == boxed); // const X & eps = harris_eps_for_bound(this->m_low_bounds[j]); // if (this->above_bound(this->m_x[j], this->m_low_bounds[j])) { // theta = std::min((this->m_low_bounds[j] -this->m_x[j] - eps) / m, theta); @@ -522,7 +522,7 @@ public: // } void limit_theta_on_basis_column_for_feas_case_m_neg_no_check(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m < 0); + lp_assert(m < 0); const X& eps = harris_eps_for_bound(this->m_low_bounds[j]); limit_theta((this->m_low_bounds[j] - this->m_x[j] - eps) / m, theta, unlimited); if (theta < zero_of_type()) theta = zero_of_type(); @@ -530,7 +530,7 @@ public: bool limit_inf_on_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets smaller - lean_assert(m < 0); + lp_assert(m < 0); if (numeric_traits::precise()) { if (this->below_bound(x, bound)) return false; if (this->above_bound(x, bound)) { @@ -554,7 +554,7 @@ public: bool limit_inf_on_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets larger - lean_assert(m > 0); + lp_assert(m > 0); if (numeric_traits::precise()) { if (this->above_bound(x, bound)) return false; if (this->below_bound(x, bound)) { @@ -579,14 +579,14 @@ public: void limit_inf_on_low_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { if (numeric_traits::precise()) { // x gets larger - lean_assert(m > 0); + lp_assert(m > 0); if (this->below_bound(x, bound)) { limit_theta((bound - x) / m, theta, unlimited); } } else { // x gets larger - lean_assert(m > 0); + lp_assert(m > 0); const X& eps = harris_eps_for_bound(bound); if (this->below_bound(x, bound)) { limit_theta((bound - x + eps) / m, theta, unlimited); @@ -596,7 +596,7 @@ public: void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets smaller - lean_assert(m < 0); + lp_assert(m < 0); const X& eps = harris_eps_for_bound(bound); if (this->above_bound(x, bound)) { limit_theta((bound - x - eps) / m, theta, unlimited); @@ -604,7 +604,7 @@ public: } void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - // lean_assert(m > 0 && this->m_column_type[j] == column_type::boxed); + // lp_assert(m > 0 && this->m_column_type[j] == column_type::boxed); const X & x = this->m_x[j]; const X & lbound = this->m_low_bounds[j]; @@ -624,7 +624,7 @@ public: } void limit_theta_on_basis_column_for_inf_case_m_neg_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - // lean_assert(m < 0 && this->m_column_type[j] == column_type::boxed); + // lp_assert(m < 0 && this->m_column_type[j] == column_type::boxed); const X & x = this->m_x[j]; const X & ubound = this->m_upper_bounds[j]; if (this->above_bound(x, ubound)) { @@ -642,7 +642,7 @@ public: } } void limit_theta_on_basis_column_for_feas_case_m_pos(unsigned j, const T & m, X & theta, bool & unlimited) { - lean_assert(m > 0); + lp_assert(m > 0); const T& eps = harris_eps_for_bound(this->m_upper_bounds[j]); if (this->below_bound(this->m_x[j], this->m_upper_bounds[j])) { limit_theta((this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); @@ -654,7 +654,7 @@ public: } void limit_theta_on_basis_column_for_feas_case_m_pos_no_check(unsigned j, const T & m, X & theta, bool & unlimited ) { - lean_assert(m > 0); + lp_assert(m > 0); const X& eps = harris_eps_for_bound(this->m_upper_bounds[j]); limit_theta( (this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); if (theta < zero_of_type()) { @@ -720,7 +720,7 @@ public: break; default: - lean_unreachable(); + lp_unreachable(); } if (!unlimited && theta < zero_of_type()) { theta = zero_of_type(); @@ -803,7 +803,7 @@ public: case column_type::free_column: return 0; default: - lean_assert(false); + lp_assert(false); } return 0; } @@ -838,7 +838,7 @@ public: return -1; break; default: - lean_assert(false); + lp_assert(false); } return 0; @@ -864,7 +864,7 @@ public: // the delta is between the old and the new cost (old - new) void update_reduced_cost_for_basic_column_cost_change(const T & delta, unsigned j) { - lean_assert(this->m_basis_heading[j] >= 0); + 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; @@ -943,7 +943,7 @@ public: upper_bound_values), m_beta(A.row_count()), m_converted_harris_eps(convert_struct::convert(this->m_settings.harris_feasibility_tolerance)) { - lean_assert(initial_x_is_correct()); + lp_assert(initial_x_is_correct()); m_low_bounds_dummy.resize(A.column_count(), zero_of_type()); m_enter_price_eps = numeric_traits::precise() ? numeric_traits::zero() : T(1e-5); #ifdef LEAN_DEBUG diff --git a/src/util/lp/lp_primal_core_solver.hpp b/src/util/lp/lp_primal_core_solver.hpp index 969d56812..d8d01f4b9 100644 --- a/src/util/lp/lp_primal_core_solver.hpp +++ b/src/util/lp/lp_primal_core_solver.hpp @@ -9,13 +9,13 @@ #include #include #include "util/lp/lp_primal_core_solver.h" -namespace lean { +namespace lp { // This core solver solves (Ax=b, low_bound_values \leq x \leq upper_bound_values, maximize costs*x ) // The right side b is given implicitly by x and the basis template void lp_primal_core_solver::sort_non_basis_rational() { - lean_assert(numeric_traits::precise()); + lp_assert(numeric_traits::precise()); if (this->m_settings.use_tableau()) { std::sort(this->m_nbasis.begin(), this->m_nbasis.end(), [this](unsigned a, unsigned b) { unsigned ca = this->m_A.number_of_non_zeroes_in_column(a); @@ -70,11 +70,11 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_on_breakpoin const T & d = this->m_d[j]; switch (this->m_column_types[j]) { case column_type::low_bound: - lean_assert(this->x_is_at_low_bound(j)); + lp_assert(this->x_is_at_low_bound(j)); ret = d < -m_epsilon_of_reduced_cost; break; case column_type::upper_bound: - lean_assert(this->x_is_at_upper_bound(j)); + lp_assert(this->x_is_at_upper_bound(j)); ret = d > m_epsilon_of_reduced_cost; break; case column_type::fixed: @@ -83,7 +83,7 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_on_breakpoin case column_type::boxed: { bool low_bound = this->x_is_at_low_bound(j); - lean_assert(low_bound || this->x_is_at_upper_bound(j)); + lp_assert(low_bound || this->x_is_at_upper_bound(j)); ret = (low_bound && d < -m_epsilon_of_reduced_cost) || ((!low_bound) && d > m_epsilon_of_reduced_cost); } break; @@ -91,7 +91,7 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_on_breakpoin ret = d > m_epsilon_of_reduced_cost || d < - m_epsilon_of_reduced_cost; break; default: - lean_unreachable(); + lp_unreachable(); ret = false; break; } @@ -127,14 +127,14 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis(unsign } break; default: - lean_unreachable(); + lp_unreachable(); break; } return false; } template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precise(unsigned j) const { - lean_assert (numeric_traits::precise()); + lp_assert (numeric_traits::precise()); if (this->m_using_infeas_costs && this->m_settings.use_breakpoints_in_feasibility_search) return column_is_benefitial_for_entering_on_breakpoints(j); const T& dj = this->m_d[j]; @@ -167,7 +167,7 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precis } break; default: - lean_unreachable(); + lp_unreachable(); break; } return false; @@ -175,7 +175,7 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precis template int lp_primal_core_solver::choose_entering_column_presize(unsigned number_of_benefitial_columns_to_go_over) { // at this moment m_y = cB * B(-1) - lean_assert(numeric_traits::precise()); + lp_assert(numeric_traits::precise()); if (number_of_benefitial_columns_to_go_over == 0) return -1; if (this->m_basis_sort_counter == 0) { @@ -259,7 +259,7 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef template int lp_primal_core_solver::advance_on_sorted_breakpoints(unsigned entering, X &t) { T slope_at_entering = this->m_d[entering]; breakpoint * last_bp = nullptr; - lean_assert(m_breakpoint_indices_queue.is_empty()==false); + lp_assert(m_breakpoint_indices_queue.is_empty()==false); while (m_breakpoint_indices_queue.is_empty() == false) { unsigned bi = m_breakpoint_indices_queue.dequeue(); breakpoint *b = &m_breakpoints[bi]; @@ -274,7 +274,7 @@ template int lp_primal_core_solver::advance_on_so } } } - lean_assert (last_bp != nullptr); + lp_assert (last_bp != nullptr); t = last_bp->m_delta; return last_bp->m_j; } @@ -282,13 +282,13 @@ template int lp_primal_core_solver::advance_on_so template int lp_primal_core_solver::find_leaving_and_t_with_breakpoints(unsigned entering, X & t){ - lean_assert(this->precise() == false); + lp_assert(this->precise() == false); fill_breakpoints_array(entering); return advance_on_sorted_breakpoints(entering, t); } template bool lp_primal_core_solver::get_harris_theta(X & theta) { - lean_assert(this->m_ed.is_OK()); + lp_assert(this->m_ed.is_OK()); bool unlimited = true; for (unsigned i : this->m_ed.m_index) { if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(this->m_ed[i])) continue; @@ -345,13 +345,13 @@ template bool lp_primal_core_solver::try_jump_to_ if (m_sign_of_entering_delta > 0) { t = this->m_upper_bounds[entering] - this->m_x[entering]; if (unlimited || t <= theta){ - lean_assert(t >= zero_of_type()); + lp_assert(t >= zero_of_type()); return true; } } else { // m_sign_of_entering_delta == -1 t = this->m_x[entering] - this->m_low_bounds[entering]; if (unlimited || t <= theta) { - lean_assert(t >= zero_of_type()); + lp_assert(t >= zero_of_type()); return true; } } @@ -360,7 +360,7 @@ template bool lp_primal_core_solver::try_jump_to_ if (m_sign_of_entering_delta > 0) { t = this->m_upper_bounds[entering] - this->m_x[entering]; if (unlimited || t <= theta){ - lean_assert(t >= zero_of_type()); + lp_assert(t >= zero_of_type()); return true; } } @@ -369,7 +369,7 @@ template bool lp_primal_core_solver::try_jump_to_ if (m_sign_of_entering_delta < 0) { t = this->m_x[entering] - this->m_low_bounds[entering]; if (unlimited || t <= theta) { - lean_assert(t >= zero_of_type()); + lp_assert(t >= zero_of_type()); return true; } } @@ -405,7 +405,7 @@ template int lp_primal_core_solver::find_leaving_ do { unsigned i = this->m_ed.m_index[k]; const T & ed = this->m_ed[i]; - lean_assert(!numeric_traits::is_zero(ed)); + 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) { @@ -424,7 +424,7 @@ template int lp_primal_core_solver::find_leaving_ while (k != initial_k) { unsigned i = this->m_ed.m_index[k]; const T & ed = this->m_ed[i]; - lean_assert(!numeric_traits::is_zero(ed)); + 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); @@ -464,7 +464,7 @@ template int lp_primal_core_solver::find_leavi return find_leaving_and_t_with_breakpoints(entering, t); X theta; bool unlimited = get_harris_theta(theta); - lean_assert(unlimited || theta >= zero_of_type()); + lp_assert(unlimited || theta >= zero_of_type()); if (try_jump_to_another_bound_on_entering(entering, theta, t, unlimited)) return entering; if (unlimited) return -1; @@ -533,7 +533,7 @@ template X lp_primal_core_solver::get_max_boun template void lp_primal_core_solver::check_Ax_equal_b() { dense_matrix d(this->m_A); T * ls = d.apply_from_left_with_different_dims(this->m_x); - lean_assert(vectors_are_equal(ls, this->m_b, this->m_m())); + lp_assert(vectors_are_equal(ls, this->m_b, this->m_m())); delete [] ls; } template void lp_primal_core_solver::check_the_bounds() { @@ -543,8 +543,8 @@ template void lp_primal_core_solver::check_the } template void lp_primal_core_solver::check_bound(unsigned i) { - lean_assert (!(this->column_has_low_bound(i) && (numeric_traits::zero() > this->m_x[i]))); - lean_assert (!(this->column_has_upper_bound(i) && (this->m_upper_bounds[i] < this->m_x[i]))); + lp_assert (!(this->column_has_low_bound(i) && (numeric_traits::zero() > this->m_x[i]))); + lp_assert (!(this->column_has_upper_bound(i) && (this->m_upper_bounds[i] < this->m_x[i]))); } template void lp_primal_core_solver::check_correctness() { @@ -560,8 +560,8 @@ void lp_primal_core_solver::update_reduced_costs_from_pivot_row(unsigned e // the basis heading has changed already #ifdef LEAN_DEBUG auto & basis_heading = this->m_basis_heading; - lean_assert(basis_heading[entering] >= 0 && static_cast(basis_heading[entering]) < this->m_m()); - lean_assert(basis_heading[leaving] < 0); + lp_assert(basis_heading[entering] >= 0 && static_cast(basis_heading[entering]) < this->m_m()); + lp_assert(basis_heading[leaving] < 0); #endif T pivot = this->m_pivot_row[entering]; T dq = this->m_d[entering]/pivot; @@ -584,7 +584,7 @@ void lp_primal_core_solver::update_reduced_costs_from_pivot_row(unsigned e template int lp_primal_core_solver::refresh_reduced_cost_at_entering_and_check_that_it_is_off(unsigned entering) { if (numeric_traits::precise()) return 0; T reduced_at_entering_was = this->m_d[entering]; // can benefit from going over non-zeros of m_ed - lean_assert(abs(reduced_at_entering_was) > m_epsilon_of_reduced_cost); + lp_assert(abs(reduced_at_entering_was) > m_epsilon_of_reduced_cost); T refreshed_cost = this->m_costs[entering]; unsigned i = this->m_m(); while (i--) refreshed_cost -= this->m_costs[this->m_basis[i]] * this->m_ed[i]; @@ -619,7 +619,7 @@ template void lp_primal_core_solver::backup_an m_costs_backup = this->m_costs; } else { T cost_max = std::max(max_abs_in_vector(this->m_costs), T(1)); - lean_assert(m_costs_backup.size() == 0); + lp_assert(m_costs_backup.size() == 0); for (unsigned j = 0; j < this->m_costs.size(); j++) m_costs_backup.push_back(this->m_costs[j] /= cost_max); } @@ -649,16 +649,16 @@ template void lp_primal_core_solver::init_run( template void lp_primal_core_solver::calc_working_vector_beta_for_column_norms(){ - lean_assert(numeric_traits::precise() == false); - lean_assert(this->m_ed.is_OK()); - lean_assert(m_beta.is_OK()); + lp_assert(numeric_traits::precise() == false); + lp_assert(this->m_ed.is_OK()); + lp_assert(m_beta.is_OK()); m_beta = this->m_ed; this->m_factorization->solve_yB_with_error_check_indexed(m_beta, this->m_basis_heading, this->m_basis, this->m_settings); } template void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering, X & t) { - lean_assert(!this->A_mult_x_is_off() ); + lp_assert(!this->A_mult_x_is_off() ); this->update_x(entering, t * m_sign_of_entering_delta); if (this->A_mult_x_is_off_on_index(this->m_ed.m_index) && !this->find_x_by_solving()) { this->init_lu(); @@ -670,7 +670,7 @@ void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering } } if (this->m_using_infeas_costs) { - lean_assert(is_zero(this->m_costs[entering])); + lp_assert(is_zero(this->m_costs[entering])); init_infeasibility_costs_for_changed_basis_only(); } if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) @@ -683,10 +683,10 @@ void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering } template void lp_primal_core_solver::advance_on_entering_and_leaving(int entering, int leaving, X & t) { - lean_assert(entering >= 0 && m_non_basis_list.back() == static_cast(entering)); - lean_assert(this->m_using_infeas_costs || t >= zero_of_type()); - lean_assert(leaving >= 0 && entering >= 0); - lean_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes + lp_assert(entering >= 0 && m_non_basis_list.back() == static_cast(entering)); + lp_assert(this->m_using_infeas_costs || t >= zero_of_type()); + lp_assert(leaving >= 0 && entering >= 0); + lp_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes if (entering == leaving) { advance_on_entering_equal_leaving(entering, t); return; @@ -702,7 +702,7 @@ template void lp_primal_core_solver::advance_on_en this->iters_with_no_cost_growing()++; return; } else { - lean_assert(pivot_compare_result == 1); + lp_assert(pivot_compare_result == 1); this->init_lu(); if (this->m_factorization == nullptr || this->m_factorization->get_status() != LU_status::OK) { this->set_status(UNSTABLE); @@ -746,7 +746,7 @@ template void lp_primal_core_solver::advance_on_en } else { update_reduced_costs_from_pivot_row(entering, leaving); } - lean_assert(!need_to_switch_costs()); + lp_assert(!need_to_switch_costs()); std::list::iterator it = m_non_basis_list.end(); it--; * it = static_cast(leaving); @@ -754,8 +754,8 @@ template void lp_primal_core_solver::advance_on_en template void lp_primal_core_solver::advance_on_entering_precise(int entering) { - lean_assert(numeric_traits::precise()); - lean_assert(entering > -1); + lp_assert(numeric_traits::precise()); + lp_assert(entering > -1); this->solve_Bd(entering); X t; int leaving = find_leaving_and_t_precise(entering, t); @@ -771,7 +771,7 @@ template void lp_primal_core_solver::advance_on_e advance_on_entering_precise(entering); return; } - lean_assert(entering > -1); + lp_assert(entering > -1); this->solve_Bd(entering); int refresh_result = refresh_reduced_cost_at_entering_and_check_that_it_is_off(entering); if (refresh_result) { @@ -791,7 +791,7 @@ template void lp_primal_core_solver::advance_on_e int leaving = find_leaving_and_t(entering, t); if (leaving == -1){ if (!this->current_x_is_feasible()) { - lean_assert(!numeric_traits::precise()); // we cannot have unbounded with inf costs + lp_assert(!numeric_traits::precise()); // we cannot have unbounded with inf costs // if (m_look_for_feasible_solution_only) { // this->m_status = INFEASIBLE; @@ -865,7 +865,7 @@ template unsigned lp_primal_core_solver::solve() return this->total_iterations(); } one_iteration(); - lean_assert(!this->m_using_infeas_costs || this->costs_on_nbasis_are_zeros()); + lp_assert(!this->m_using_infeas_costs || this->costs_on_nbasis_are_zeros()); switch (this->get_status()) { case OPTIMAL: // double check that we are at optimum case INFEASIBLE: @@ -914,7 +914,7 @@ template unsigned lp_primal_core_solver::solve() break; case UNSTABLE: - lean_assert(! (numeric_traits::precise())); + lp_assert(! (numeric_traits::precise())); this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { this->set_status(FLOATING_POINT_ERROR); @@ -940,7 +940,7 @@ template unsigned lp_primal_core_solver::solve() && !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); - lean_assert(this->get_status() == FLOATING_POINT_ERROR + lp_assert(this->get_status() == FLOATING_POINT_ERROR || this->current_x_is_feasible() == false || @@ -957,7 +957,7 @@ template void lp_primal_core_solver::delete_fa // according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming" template void lp_primal_core_solver::init_column_norms() { - lean_assert(numeric_traits::precise() == false); + 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)) @@ -967,7 +967,7 @@ template void lp_primal_core_solver::init_column_ // debug only template T lp_primal_core_solver::calculate_column_norm_exactly(unsigned j) { - lean_assert(numeric_traits::precise() == false); + lp_assert(numeric_traits::precise() == false); indexed_vector w(this->m_m()); this->m_A.copy_column_to_vector(j, w); vector d(this->m_m()); @@ -979,8 +979,8 @@ template T lp_primal_core_solver::calculate_colum } template void lp_primal_core_solver::update_or_init_column_norms(unsigned entering, unsigned leaving) { - lean_assert(numeric_traits::precise() == false); - lean_assert(m_column_norm_update_counter <= this->m_settings.column_norms_update_frequency); + lp_assert(numeric_traits::precise() == false); + lp_assert(m_column_norm_update_counter <= this->m_settings.column_norms_update_frequency); if (m_column_norm_update_counter == this->m_settings.column_norms_update_frequency) { m_column_norm_update_counter = 0; init_column_norms(); @@ -992,7 +992,7 @@ template void lp_primal_core_solver::update_or // following Swietanowski - A new steepest ... template void lp_primal_core_solver::update_column_norms(unsigned entering, unsigned leaving) { - lean_assert(numeric_traits::precise() == false); + lp_assert(numeric_traits::precise() == false); T pivot = this->m_pivot_row[entering]; T g_ent = calculate_norm_of_entering_exactly() / pivot / pivot; if (!numeric_traits::precise()) { @@ -1027,7 +1027,7 @@ template T lp_primal_core_solver::calculate_no // calling it stage1 is too cryptic template void lp_primal_core_solver::find_feasible_solution() { this->m_look_for_feasible_solution_only = true; - lean_assert(this->non_basic_columns_are_set_correctly()); + lp_assert(this->non_basic_columns_are_set_correctly()); this->set_status(UNKNOWN); solve(); } @@ -1095,8 +1095,8 @@ void lp_primal_core_solver::init_infeasibility_costs_for_changed_basis_onl template void lp_primal_core_solver::init_infeasibility_costs() { - lean_assert(this->m_x.size() >= this->m_n()); - lean_assert(this->m_column_types.size() >= this->m_n()); + lp_assert(this->m_x.size() >= this->m_n()); + lp_assert(this->m_column_types.size() >= this->m_n()); for (unsigned j = this->m_n(); j--;) init_infeasibility_cost_for_column(j); this->m_using_infeas_costs = true; @@ -1138,7 +1138,7 @@ lp_primal_core_solver::get_infeasibility_cost_for_column(unsigned j) const ret = numeric_traits::zero(); break; default: - lean_assert(false); + lp_assert(false); ret = numeric_traits::zero(); // does not matter break; } @@ -1192,7 +1192,7 @@ lp_primal_core_solver::init_infeasibility_cost_for_column(unsigned j) { this->m_costs[j] = numeric_traits::zero(); break; default: - lean_assert(false); + lp_assert(false); break; } @@ -1223,7 +1223,7 @@ template void lp_primal_core_solver::print_column case column_type::free_column: out << "( _" << this->m_x[j] << "_)" << std::endl; default: - lean_unreachable(); + lp_unreachable(); } } @@ -1262,7 +1262,7 @@ template std::string lp_primal_core_solver::break case upper_break: return "upper_break"; case fixed_break: return "fixed_break"; default: - lean_assert(false); + lp_assert(false); break; } return "type is not found"; @@ -1275,7 +1275,7 @@ template void lp_primal_core_solver::print_breakp template void lp_primal_core_solver::init_reduced_costs() { - lean_assert(!this->use_tableau()); + lp_assert(!this->use_tableau()); if (this->current_x_is_infeasible() && !this->m_using_infeas_costs) { init_infeasibility_costs(); } else if (this->current_x_is_feasible() && this->m_using_infeas_costs) { @@ -1290,12 +1290,12 @@ void lp_primal_core_solver::init_reduced_costs() { template void lp_primal_core_solver::change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering) { if (b->m_j == entering) { - lean_assert(b->m_type != fixed_break && (!is_zero(b->m_delta))); + lp_assert(b->m_type != fixed_break && (!is_zero(b->m_delta))); slope_at_entering += m_sign_of_entering_delta; return; } - lean_assert(this->m_basis_heading[b->m_j] >= 0); + lp_assert(this->m_basis_heading[b->m_j] >= 0); unsigned i_row = this->m_basis_heading[b->m_j]; const T & d = - this->m_ed[i_row]; if (numeric_traits::is_zero(d)) return; @@ -1314,13 +1314,13 @@ template void lp_primal_core_solver::change_sl slope_at_entering += delta; break; default: - lean_assert(false); + lp_assert(false); } } template void lp_primal_core_solver::try_add_breakpoint_in_row(unsigned i) { - lean_assert(i < this->m_m()); + lp_assert(i < this->m_m()); const T & d = this->m_ed[i]; // the coefficient before m_entering in the i-th row if (d == 0) return; // the change of x[m_entering] will not change the corresponding basis x unsigned j = this->m_basis[i]; @@ -1342,7 +1342,7 @@ template void lp_primal_core_solver::try_add_b case column_type::free_column: break; default: - lean_assert(false); + lp_assert(false); break; } } @@ -1366,7 +1366,7 @@ template void lp_primal_core_solver::print_bound_ out << "inf, inf" << std::endl; break; default: - lean_assert(false); + lp_assert(false); break; } } diff --git a/src/util/lp/lp_primal_core_solver_instances.cpp b/src/util/lp/lp_primal_core_solver_instances.cpp index ca231fd34..8e5890bf5 100644 --- a/src/util/lp/lp_primal_core_solver_instances.cpp +++ b/src/util/lp/lp_primal_core_solver_instances.cpp @@ -10,18 +10,18 @@ #include "util/lp/lar_solver.h" #include "util/lp/lp_primal_core_solver.hpp" #include "util/lp/lp_primal_core_solver_tableau.hpp" -namespace lean { +namespace lp { template void lp_primal_core_solver::find_feasible_solution(); -template void lean::lp_primal_core_solver >::find_feasible_solution(); +template void lp::lp_primal_core_solver >::find_feasible_solution(); template unsigned lp_primal_core_solver::solve(); template unsigned lp_primal_core_solver::solve_with_tableau(); template unsigned lp_primal_core_solver::solve(); template unsigned lp_primal_core_solver >::solve(); -template void lean::lp_primal_core_solver::clear_breakpoints(); -template bool lean::lp_primal_core_solver::update_basis_and_x_tableau(int, int, lean::mpq const&); -template bool lean::lp_primal_core_solver::update_basis_and_x_tableau(int, int, double const&); -template bool lean::lp_primal_core_solver >::update_basis_and_x_tableau(int, int, lean::numeric_pair const&); +template void lp::lp_primal_core_solver::clear_breakpoints(); +template bool lp::lp_primal_core_solver::update_basis_and_x_tableau(int, int, lp::mpq const&); +template bool lp::lp_primal_core_solver::update_basis_and_x_tableau(int, int, double const&); +template bool lp::lp_primal_core_solver >::update_basis_and_x_tableau(int, int, lp::numeric_pair const&); } diff --git a/src/util/lp/lp_primal_core_solver_tableau.hpp b/src/util/lp/lp_primal_core_solver_tableau.hpp index 0c09c22c9..d2ce78472 100644 --- a/src/util/lp/lp_primal_core_solver_tableau.hpp +++ b/src/util/lp/lp_primal_core_solver_tableau.hpp @@ -4,7 +4,7 @@ */ // this is a part of lp_primal_core_solver that deals with the tableau #include "util/lp/lp_primal_core_solver.h" -namespace lean { +namespace lp { template void lp_primal_core_solver::one_iteration_tableau() { int entering = choose_entering_column_tableau(); if (entering == -1) { @@ -13,7 +13,7 @@ template void lp_primal_core_solver::one_iteratio else { advance_on_entering_tableau(entering); } - lean_assert(this->inf_set_is_correct()); + lp_assert(this->inf_set_is_correct()); } template void lp_primal_core_solver::advance_on_entering_tableau(int entering) { @@ -37,7 +37,7 @@ template int lp_primal_core_solver::choose_enteri //this moment m_y = cB * B(-1) unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter(); - lean_assert(numeric_traits::precise()); + lp_assert(numeric_traits::precise()); if (number_of_benefitial_columns_to_go_over == 0) return -1; if (this->m_basis_sort_counter == 0) { @@ -149,7 +149,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { break; case UNSTABLE: - lean_assert(! (numeric_traits::precise())); + lp_assert(! (numeric_traits::precise())); this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { this->set_status(FLOATING_POINT_ERROR); @@ -175,7 +175,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { && !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); - lean_assert(this->get_status() == FLOATING_POINT_ERROR + lp_assert(this->get_status() == FLOATING_POINT_ERROR || this->current_x_is_feasible() == false || @@ -184,13 +184,13 @@ unsigned lp_primal_core_solver::solve_with_tableau() { } template void lp_primal_core_solver::advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t) { - lean_assert(this->A_mult_x_is_off() == false); - lean_assert(leaving >= 0 && entering >= 0); - lean_assert((this->m_settings.simplex_strategy() == + lp_assert(this->A_mult_x_is_off() == false); + lp_assert(leaving >= 0 && entering >= 0); + lp_assert((this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) || m_non_basis_list.back() == static_cast(entering)); - lean_assert(this->m_using_infeas_costs || !is_neg(t)); - lean_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes + lp_assert(this->m_using_infeas_costs || !is_neg(t)); + lp_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes if (entering == leaving) { advance_on_entering_equal_leaving_tableau(entering, t); return; @@ -201,7 +201,7 @@ template void lp_primal_core_solver::advance_on_en t = -t; } this->update_basis_and_x_tableau(entering, leaving, t); - lean_assert(this->A_mult_x_is_off() == false); + lp_assert(this->A_mult_x_is_off() == false); this->iters_with_no_cost_growing() = 0; } else { this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); @@ -216,7 +216,7 @@ template void lp_primal_core_solver::advance_on_en this->init_reduced_costs_tableau(); } - lean_assert(!need_to_switch_costs()); + lp_assert(!need_to_switch_costs()); std::list::iterator it = m_non_basis_list.end(); it--; * it = static_cast(leaving); @@ -225,7 +225,7 @@ template void lp_primal_core_solver::advance_on_en template void lp_primal_core_solver::advance_on_entering_equal_leaving_tableau(int entering, X & t) { - lean_assert(!this->A_mult_x_is_off() ); + lp_assert(!this->A_mult_x_is_off() ); this->update_x_tableau(entering, t * m_sign_of_entering_delta); if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) return; @@ -246,7 +246,7 @@ template int lp_primal_core_solver::find_leaving_ const column_cell & c = col[k]; unsigned i = c.m_i; const T & ed = this->m_A.get_val(c); - lean_assert(!numeric_traits::is_zero(ed)); + 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) { @@ -265,7 +265,7 @@ template int lp_primal_core_solver::find_leaving_ const column_cell & c = col[k]; unsigned i = c.m_i; const T & ed = this->m_A.get_val(c); - lean_assert(!numeric_traits::is_zero(ed)); + 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); @@ -298,12 +298,12 @@ template int lp_primal_core_solver::find_leaving_ } template void lp_primal_core_solver::init_run_tableau() { // print_matrix(&(this->m_A), std::cout); - lean_assert(this->A_mult_x_is_off() == false); - lean_assert(basis_columns_are_set_correctly()); + lp_assert(this->A_mult_x_is_off() == false); + lp_assert(basis_columns_are_set_correctly()); this->m_basis_sort_counter = 0; // to initiate the sort of the basis this->set_total_iterations(0); this->iters_with_no_cost_growing() = 0; - lean_assert(this->inf_set_is_correct()); + lp_assert(this->inf_set_is_correct()); if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) return; if (this->m_settings.backup_costs) @@ -317,13 +317,13 @@ template void lp_primal_core_solver::init_run_tab } if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) init_tableau_rows(); - lean_assert(this->reduced_costs_are_correct_tableau()); - lean_assert(!this->need_to_pivot_to_basis_tableau()); + lp_assert(this->reduced_costs_are_correct_tableau()); + lp_assert(!this->need_to_pivot_to_basis_tableau()); } template bool lp_primal_core_solver:: update_basis_and_x_tableau(int entering, int leaving, X const & tt) { - lean_assert(this->use_tableau()); + lp_assert(this->use_tableau()); update_x_tableau(entering, tt); this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); this->change_basis(entering, leaving); @@ -340,8 +340,8 @@ update_x_tableau(unsigned entering, const X& delta) { } } else { // m_using_infeas_costs == true this->m_x[entering] += delta; - lean_assert(this->column_is_feasible(entering)); - lean_assert(this->m_costs[entering] == zero_of_type()); + lp_assert(this->column_is_feasible(entering)); + 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; @@ -354,13 +354,13 @@ update_x_tableau(unsigned entering, const X& delta) { this->m_inf_set.insert(j); } } - lean_assert(this->A_mult_x_is_off() == false); + lp_assert(this->A_mult_x_is_off() == false); } template void lp_primal_core_solver:: update_inf_cost_for_column_tableau(unsigned j) { - lean_assert(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows); - lean_assert(this->m_using_infeas_costs); + lp_assert(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows); + lp_assert(this->m_using_infeas_costs); T new_cost = get_infeasibility_cost_for_column(j); T delta = this->m_costs[j] - new_cost; if (is_zero(delta)) diff --git a/src/util/lp/lp_primal_simplex.h b/src/util/lp/lp_primal_simplex.h index 715d76408..b55fecdcd 100644 --- a/src/util/lp/lp_primal_simplex.h +++ b/src/util/lp/lp_primal_simplex.h @@ -12,7 +12,7 @@ #include "util/lp/lp_primal_core_solver.h" #include "util/lp/lp_solver.h" #include "util/lp/iterator_on_row.h" -namespace lean { +namespace lp { template class lp_primal_simplex: public lp_solver { lp_primal_core_solver * m_core_solver; diff --git a/src/util/lp/lp_primal_simplex.hpp b/src/util/lp/lp_primal_simplex.hpp index b6b6006e5..76ed5684c 100644 --- a/src/util/lp/lp_primal_simplex.hpp +++ b/src/util/lp/lp_primal_simplex.hpp @@ -6,7 +6,7 @@ #include "util/vector.h" #include "util/lp/lp_primal_simplex.h" -namespace lean { +namespace lp { template void lp_primal_simplex::fill_costs_and_x_for_first_stage_solver(unsigned original_number_of_columns) { unsigned slack_var = original_number_of_columns; unsigned artificial = original_number_of_columns + this->m_slacks; @@ -61,7 +61,7 @@ template void lp_primal_simplex::fill_costs_and_x int row, unsigned & slack_var, unsigned & artificial) { - lean_assert(row >= 0 && row < this->row_count()); + lp_assert(row >= 0 && row < this->row_count()); auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[row]]; // we need to bring the program to the form Ax = b T rs = this->m_b[row]; @@ -86,7 +86,7 @@ template void lp_primal_simplex::fill_costs_and_x (*this->m_A)(row, slack_var) = - numeric_traits::one(); if (rs > 0) { - lean_assert(numeric_traits::is_zero(this->m_x[slack_var])); + lp_assert(numeric_traits::is_zero(this->m_x[slack_var])); // adding one artificial this->m_column_types[artificial] = column_type::low_bound; (*this->m_A)(row, artificial) = numeric_traits::one(); @@ -108,7 +108,7 @@ template void lp_primal_simplex::fill_costs_and_x if (rs < 0) { // adding one artificial - lean_assert(numeric_traits::is_zero(this->m_x[slack_var])); + lp_assert(numeric_traits::is_zero(this->m_x[slack_var])); this->m_column_types[artificial] = column_type::low_bound; (*this->m_A)(row, artificial) = - numeric_traits::one(); this->m_costs[artificial] = artificial_cost; @@ -157,7 +157,7 @@ template void lp_primal_simplex::find_maximal_sol return; } - this->cleanup(); + this->clpup(); this->fill_matrix_A_and_init_right_side(); if (this->m_status == lp_status::INFEASIBLE) { return; @@ -177,12 +177,12 @@ template void lp_primal_simplex::fill_A_x_and_bas } template void lp_primal_simplex::fill_A_x_and_basis_for_stage_one_total_inf_for_row(unsigned row) { - lean_assert(row < this->row_count()); + lp_assert(row < this->row_count()); auto ext_row_it = this->m_core_solver_rows_to_external_rows.find(row); - lean_assert(ext_row_it != this->m_core_solver_rows_to_external_rows.end()); + lp_assert(ext_row_it != this->m_core_solver_rows_to_external_rows.end()); unsigned ext_row = ext_row_it->second; auto constr_it = this->m_constraints.find(ext_row); - lean_assert(constr_it != this->m_constraints.end()); + lp_assert(constr_it != this->m_constraints.end()); auto & constraint = constr_it->second; unsigned j = this->m_A->column_count(); // j is a slack variable this->m_A->add_column(); @@ -209,7 +209,7 @@ template void lp_primal_simplex::fill_A_x_and_bas this->m_upper_bounds[j] = m_low_bounds[j] = zero_of_type(); break; default: - lean_unreachable(); + lp_unreachable(); } } @@ -281,10 +281,10 @@ template T lp_primal_simplex::get_row_value(unsig T ret = numeric_traits::zero(); for (auto & pair : it->second) { auto cit = this->m_map_from_var_index_to_column_info.find(pair.first); - lean_assert(cit != this->m_map_from_var_index_to_column_info.end()); + lp_assert(cit != this->m_map_from_var_index_to_column_info.end()); column_info * ci = cit->second; auto sol_it = solution.find(ci->get_name()); - lean_assert(sol_it != solution.end()); + lp_assert(sol_it != solution.end()); T column_val = sol_it->second; if (out != nullptr) { (*out) << pair.second << "(" << ci->get_name() << "=" << column_val << ") "; @@ -329,7 +329,7 @@ template bool lp_primal_simplex::row_constraint_h } return true;; } - lean_unreachable(); + lp_unreachable(); return false; // it is unreachable } diff --git a/src/util/lp/lp_primal_simplex_instances.cpp b/src/util/lp/lp_primal_simplex_instances.cpp index 37b639489..249be218c 100644 --- a/src/util/lp/lp_primal_simplex_instances.cpp +++ b/src/util/lp/lp_primal_simplex_instances.cpp @@ -8,13 +8,13 @@ #include "util/vector.h" #include #include "util/lp/lp_primal_simplex.hpp" -template bool lean::lp_primal_simplex::bounds_hold(std::unordered_map, std::equal_to, std::allocator > > const&); -template bool lean::lp_primal_simplex::row_constraints_hold(std::unordered_map, std::equal_to, std::allocator > > const&); -template double lean::lp_primal_simplex::get_current_cost() const; -template double lean::lp_primal_simplex::get_column_value(unsigned int) const; -template lean::lp_primal_simplex::~lp_primal_simplex(); -template lean::lp_primal_simplex::~lp_primal_simplex(); -template lean::mpq lean::lp_primal_simplex::get_current_cost() const; -template lean::mpq lean::lp_primal_simplex::get_column_value(unsigned int) const; -template void lean::lp_primal_simplex::find_maximal_solution(); -template void lean::lp_primal_simplex::find_maximal_solution(); +template bool lp::lp_primal_simplex::bounds_hold(std::unordered_map, std::equal_to, std::allocator > > const&); +template bool lp::lp_primal_simplex::row_constraints_hold(std::unordered_map, std::equal_to, std::allocator > > const&); +template double lp::lp_primal_simplex::get_current_cost() const; +template double lp::lp_primal_simplex::get_column_value(unsigned int) const; +template lp::lp_primal_simplex::~lp_primal_simplex(); +template lp::lp_primal_simplex::~lp_primal_simplex(); +template lp::mpq lp::lp_primal_simplex::get_current_cost() const; +template lp::mpq lp::lp_primal_simplex::get_column_value(unsigned int) const; +template void lp::lp_primal_simplex::find_maximal_solution(); +template void lp::lp_primal_simplex::find_maximal_solution(); diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index 736e4cda4..3b6b44614 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -12,7 +12,7 @@ #include "util/lp/lp_utils.h" #include "util/stopwatch.h" -namespace lean { +namespace lp { typedef unsigned var_index; typedef unsigned constraint_index; typedef unsigned row_index; @@ -374,7 +374,7 @@ inline void print_blanks(int n, std::ostream & out) { // after a push of the last element we ensure that the vector increases // we also suppose that before the last push the vector was increasing inline void ensure_increasing(vector & v) { - lean_assert(v.size() > 0); + lp_assert(v.size() > 0); unsigned j = v.size() - 1; for (; j > 0; j-- ) if (v[j] <= v[j - 1]) { diff --git a/src/util/lp/lp_settings.hpp b/src/util/lp/lp_settings.hpp index b27d837e0..b07395222 100644 --- a/src/util/lp/lp_settings.hpp +++ b/src/util/lp/lp_settings.hpp @@ -6,7 +6,7 @@ #include #include "util/vector.h" #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { std::string column_type_to_string(column_type t) { switch (t) { case column_type::fixed: return "fixed"; @@ -14,7 +14,7 @@ std::string column_type_to_string(column_type t) { case column_type::low_bound: return "low_bound"; case column_type::upper_bound: return "upper_bound"; case column_type::free_column: return "free_column"; - default: lean_unreachable(); + default: lp_unreachable(); } return "unknown"; // it is unreachable } @@ -34,7 +34,7 @@ const char* lp_status_to_string(lp_status status) { case EMPTY: return "EMPTY"; case UNSTABLE: return "UNSTABLE"; default: - lean_unreachable(); + lp_unreachable(); } return "UNKNOWN"; // it is unreachable } @@ -49,7 +49,7 @@ lp_status lp_status_from_string(std::string status) { if (status == "TIME_EXHAUSTED") return lp_status::TIME_EXHAUSTED; if (status == "ITERATIONS_EXHAUSTED") return lp_status::ITERATIONS_EXHAUSTED; if (status == "EMPTY") return lp_status::EMPTY; - lean_unreachable(); + lp_unreachable(); return lp_status::UNKNOWN; // it is unreachable } diff --git a/src/util/lp/lp_settings_instances.cpp b/src/util/lp/lp_settings_instances.cpp index ac2ed4b51..9e809e7c6 100644 --- a/src/util/lp/lp_settings_instances.cpp +++ b/src/util/lp/lp_settings_instances.cpp @@ -5,6 +5,6 @@ #include #include "util/vector.h" #include "util/lp/lp_settings.hpp" -template bool lean::vectors_are_equal(vector const&, vector const&); -template bool lean::vectors_are_equal(vector const&, vector const&); +template bool lp::vectors_are_equal(vector const&, vector const&); +template bool lp::vectors_are_equal(vector const&, vector const&); diff --git a/src/util/lp/lp_solver.h b/src/util/lp/lp_solver.h index 1bfe7dcdc..984e818e1 100644 --- a/src/util/lp/lp_solver.h +++ b/src/util/lp/lp_solver.h @@ -15,7 +15,7 @@ #include "util/lp/scaler.h" #include "util/lp/linear_combination_iterator.h" #include "util/lp/bound_analyzer_on_row.h" -namespace lean { +namespace lp { enum lp_relation { Less_or_equal, Equal, @@ -205,7 +205,7 @@ protected: unsigned try_to_remove_some_rows(); - void cleanup(); + void clpup(); void map_external_rows_to_core_solver_rows(); diff --git a/src/util/lp/lp_solver.hpp b/src/util/lp/lp_solver.hpp index 135616a69..46674cf5e 100644 --- a/src/util/lp/lp_solver.hpp +++ b/src/util/lp/lp_solver.hpp @@ -6,7 +6,7 @@ #include #include "util/vector.h" #include "util/lp/lp_solver.h" -namespace lean { +namespace lp { template column_info * lp_solver::get_or_create_column_info(unsigned column) { auto it = m_map_from_var_index_to_column_info.find(column); return (it == m_map_from_var_index_to_column_info.end())? (m_map_from_var_index_to_column_info[column] = new column_info(static_cast(-1))) : it->second; @@ -32,7 +32,7 @@ template T lp_solver::get_column_cost_value(unsig return ci->get_cost() * get_column_value(j); } template void lp_solver::add_constraint(lp_relation relation, T right_side, unsigned row_index) { - lean_assert(m_constraints.find(row_index) == m_constraints.end()); + lp_assert(m_constraints.find(row_index) == m_constraints.end()); lp_constraint cs(right_side, relation); m_constraints[row_index] = cs; } @@ -158,10 +158,10 @@ template void lp_solver::pin_vars_on_row_with_sig column_info * ci = m_map_from_var_index_to_column_info[j]; T a = t.second; if (a * sign > numeric_traits::zero()) { - lean_assert(ci->upper_bound_is_set()); + lp_assert(ci->upper_bound_is_set()); ci->set_fixed_value(ci->get_upper_bound()); } else { - lean_assert(ci->low_bound_is_set()); + lp_assert(ci->low_bound_is_set()); ci->set_fixed_value(ci->get_low_bound()); } } @@ -328,7 +328,7 @@ template bool lp_solver::row_is_obsolete(std:: case lp_relation::Less_or_equal: return row_le_is_obsolete(row, row_index); } - lean_unreachable(); + lp_unreachable(); return false; // it is unreachable } @@ -343,7 +343,7 @@ template void lp_solver::remove_fixed_or_zero_col vector removed; for (auto & col : row) { unsigned j = col.first; - lean_assert(m_map_from_var_index_to_column_info.find(j) != m_map_from_var_index_to_column_info.end()); + lp_assert(m_map_from_var_index_to_column_info.find(j) != m_map_from_var_index_to_column_info.end()); column_info * ci = m_map_from_var_index_to_column_info[j]; if (ci->is_fixed()) { removed.push_back(j); @@ -381,7 +381,7 @@ template unsigned lp_solver::try_to_remove_some_r return static_cast(rows_to_delete.size()); } -template void lp_solver::cleanup() { +template void lp_solver::clpup() { int n = 0; // number of deleted rows int d; while ((d = try_to_remove_some_rows() > 0)) @@ -412,7 +412,7 @@ template void lp_solver::map_external_columns_to_ } unsigned j = col.first; auto column_info_it = m_map_from_var_index_to_column_info.find(j); - lean_assert(column_info_it != m_map_from_var_index_to_column_info.end()); + lp_assert(column_info_it != m_map_from_var_index_to_column_info.end()); auto j_column = column_info_it->second->get_column_index(); if (!is_valid(j_column)) { // j is a newcomer @@ -435,14 +435,14 @@ template void lp_solver::fill_A_from_A_values() { m_A = new static_matrix(static_cast(m_A_values.size()), number_of_core_structurals()); for (auto & t : m_A_values) { auto row_it = m_external_rows_to_core_solver_rows.find(t.first); - lean_assert(row_it != m_external_rows_to_core_solver_rows.end()); + lp_assert(row_it != m_external_rows_to_core_solver_rows.end()); unsigned row = row_it->second; for (auto k : t.second) { auto column_info_it = m_map_from_var_index_to_column_info.find(k.first); - lean_assert(column_info_it != m_map_from_var_index_to_column_info.end()); + lp_assert(column_info_it != m_map_from_var_index_to_column_info.end()); column_info *ci = column_info_it->second; unsigned col = ci->get_column_index(); - lean_assert(is_valid(col)); + lp_assert(is_valid(col)); bool col_is_flipped = m_map_from_var_index_to_column_info[k.first]->is_flipped(); if (!col_is_flipped) { (*m_A)(row, col) = k.second; @@ -456,7 +456,7 @@ template void lp_solver::fill_A_from_A_values() { template void lp_solver::fill_matrix_A_and_init_right_side() { map_external_rows_to_core_solver_rows(); map_external_columns_to_core_solver_columns(); - lean_assert(m_A == nullptr); + lp_assert(m_A == nullptr); fill_A_from_A_values(); m_b.resize(m_A->row_count()); } @@ -468,7 +468,7 @@ template void lp_solver::count_slacks_and_artific } template void lp_solver::count_slacks_and_artificials_for_row(unsigned i) { - lean_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); + lp_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[i]]; switch (constraint.m_relation) { case Equal: @@ -504,7 +504,7 @@ template T lp_solver::low_bound_shift_for_row( template void lp_solver::fill_m_b() { for (int i = this->row_count() - 1; i >= 0; i--) { - lean_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); + lp_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); unsigned external_i = this->m_core_solver_rows_to_external_rows[i]; auto & constraint = this->m_constraints[external_i]; this->m_b[i] = constraint.m_rs - low_bound_shift_for_row(external_i); @@ -542,13 +542,13 @@ template T lp_solver::get_column_value_with_core_ template void lp_solver::set_scaled_cost(unsigned j) { // grab original costs but modify it with the column scales - lean_assert(j < this->m_column_scale.size()); + lp_assert(j < this->m_column_scale.size()); column_info * ci = this->m_map_from_var_index_to_column_info[this->m_core_solver_columns_to_external_columns[j]]; T cost = ci->get_cost(); if (ci->is_flipped()){ cost *= -1; } - lean_assert(ci->is_fixed() == false); + lp_assert(ci->is_fixed() == false); this->m_costs[j] = cost * this->m_column_scale[j]; } } diff --git a/src/util/lp/lp_solver_instances.cpp b/src/util/lp/lp_solver_instances.cpp index 5df490cae..6e62ba7d3 100644 --- a/src/util/lp/lp_solver_instances.cpp +++ b/src/util/lp/lp_solver_instances.cpp @@ -4,37 +4,37 @@ */ #include #include "util/lp/lp_solver.hpp" -template void lean::lp_solver::add_constraint(lean::lp_relation, double, unsigned int); -template void lean::lp_solver::cleanup(); -template void lean::lp_solver::count_slacks_and_artificials(); -template void lean::lp_solver::fill_m_b(); -template void lean::lp_solver::fill_matrix_A_and_init_right_side(); -template void lean::lp_solver::flip_costs(); -template double lean::lp_solver::get_column_cost_value(unsigned int, lean::column_info*) const; -template int lean::lp_solver::get_column_index_by_name(std::string) const; -template double lean::lp_solver::get_column_value_with_core_solver(unsigned int, lean::lp_core_solver_base*) const; -template lean::column_info* lean::lp_solver::get_or_create_column_info(unsigned int); -template void lean::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); -template void lean::lp_solver::print_statistics_on_A(std::ostream & out); -template bool lean::lp_solver::problem_is_empty(); -template void lean::lp_solver::scale(); -template void lean::lp_solver::set_scaled_cost(unsigned int); -template lean::lp_solver::~lp_solver(); -template void lean::lp_solver::add_constraint(lean::lp_relation, lean::mpq, unsigned int); -template void lean::lp_solver::cleanup(); -template void lean::lp_solver::count_slacks_and_artificials(); -template void lean::lp_solver::fill_m_b(); -template void lean::lp_solver::fill_matrix_A_and_init_right_side(); -template void lean::lp_solver::flip_costs(); -template lean::mpq lean::lp_solver::get_column_cost_value(unsigned int, lean::column_info*) const; -template int lean::lp_solver::get_column_index_by_name(std::string) const; -template lean::mpq lean::lp_solver::get_column_value_by_name(std::string) const; -template lean::mpq lean::lp_solver::get_column_value_with_core_solver(unsigned int, lean::lp_core_solver_base*) const; -template lean::column_info* lean::lp_solver::get_or_create_column_info(unsigned int); -template void lean::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); -template void lean::lp_solver::print_statistics_on_A(std::ostream & out); -template bool lean::lp_solver::problem_is_empty(); -template void lean::lp_solver::scale(); -template void lean::lp_solver::set_scaled_cost(unsigned int); -template lean::lp_solver::~lp_solver(); -template double lean::lp_solver::get_column_value_by_name(std::string) const; +template void lp::lp_solver::add_constraint(lp::lp_relation, double, unsigned int); +template void lp::lp_solver::clpup(); +template void lp::lp_solver::count_slacks_and_artificials(); +template void lp::lp_solver::fill_m_b(); +template void lp::lp_solver::fill_matrix_A_and_init_right_side(); +template void lp::lp_solver::flip_costs(); +template double lp::lp_solver::get_column_cost_value(unsigned int, lp::column_info*) const; +template int lp::lp_solver::get_column_index_by_name(std::string) const; +template double lp::lp_solver::get_column_value_with_core_solver(unsigned int, lp::lp_core_solver_base*) const; +template lp::column_info* lp::lp_solver::get_or_create_column_info(unsigned int); +template void lp::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); +template void lp::lp_solver::print_statistics_on_A(std::ostream & out); +template bool lp::lp_solver::problem_is_empty(); +template void lp::lp_solver::scale(); +template void lp::lp_solver::set_scaled_cost(unsigned int); +template lp::lp_solver::~lp_solver(); +template void lp::lp_solver::add_constraint(lp::lp_relation, lp::mpq, unsigned int); +template void lp::lp_solver::clpup(); +template void lp::lp_solver::count_slacks_and_artificials(); +template void lp::lp_solver::fill_m_b(); +template void lp::lp_solver::fill_matrix_A_and_init_right_side(); +template void lp::lp_solver::flip_costs(); +template lp::mpq lp::lp_solver::get_column_cost_value(unsigned int, lp::column_info*) const; +template int lp::lp_solver::get_column_index_by_name(std::string) const; +template lp::mpq lp::lp_solver::get_column_value_by_name(std::string) const; +template lp::mpq lp::lp_solver::get_column_value_with_core_solver(unsigned int, lp::lp_core_solver_base*) const; +template lp::column_info* lp::lp_solver::get_or_create_column_info(unsigned int); +template void lp::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); +template void lp::lp_solver::print_statistics_on_A(std::ostream & out); +template bool lp::lp_solver::problem_is_empty(); +template void lp::lp_solver::scale(); +template void lp::lp_solver::set_scaled_cost(unsigned int); +template lp::lp_solver::~lp_solver(); +template double lp::lp_solver::get_column_value_by_name(std::string) const; diff --git a/src/util/lp/lp_utils.cpp b/src/util/lp/lp_utils.cpp index 8cb98974e..7d5f46f2d 100644 --- a/src/util/lp/lp_utils.cpp +++ b/src/util/lp/lp_utils.cpp @@ -4,7 +4,7 @@ */ #include "util/lp/lp_utils.h" #ifdef lp_for_z3 -namespace lean { +namespace lp { double numeric_traits::g_zero = 0.0; double numeric_traits::g_one = 1.0; } diff --git a/src/util/lp/lp_utils.h b/src/util/lp/lp_utils.h index 2be15d79a..e1d5c5b8a 100644 --- a/src/util/lp/lp_utils.h +++ b/src/util/lp/lp_utils.h @@ -27,14 +27,14 @@ bool contains(const std::unordered_map & map, const A& key) { #define LEAN_DEBUG 1 #endif -namespace lean { +namespace lp { inline void throw_exception(const std::string & str) { throw default_exception(str); } typedef z3_exception exception; -#define lean_assert(_x_) { SASSERT(_x_); } - inline void lean_unreachable() { lean_assert(false); } +#define lp_assert(_x_) { SASSERT(_x_); } + inline void lp_unreachable() { lp_assert(false); } template inline X zero_of_type() { return numeric_traits::zero(); } template inline X one_of_type() { return numeric_traits::one(); } template inline bool is_zero(const X & v) { return numeric_traits::is_zero(v); } @@ -68,8 +68,8 @@ template struct hash> { }; template<> -struct hash> { - inline size_t operator()(const lean::numeric_pair & v) const { +struct hash> { + inline size_t operator()(const lp::numeric_pair & v) const { size_t seed = 0; hash_combine(seed, v.x); hash_combine(seed, v.y); @@ -91,26 +91,26 @@ struct hash> { #endif namespace std { template<> -struct hash { - inline size_t operator()(const lean::mpq & v) const { +struct hash { + inline size_t operator()(const lp::mpq & v) const { return v.hash(); } }; } -namespace lean { +namespace lp { template inline bool precise() { return numeric_traits::precise();} template inline X one_of_type() { return numeric_traits::one(); } template inline bool is_zero(const X & v) { return numeric_traits::is_zero(v); } template inline double get_double(const X & v) { return numeric_traits::get_double(v); } template inline T zero_of_type() {return numeric_traits::zero();} inline void throw_exception(std::string str) { throw exception(str); } -template inline T from_string(std::string const & ) { lean_unreachable();} +template inline T from_string(std::string const & ) { lp_unreachable();} template <> double inline from_string(std::string const & str) { return atof(str.c_str());} template <> mpq inline from_string(std::string const & str) { return mpq(atof(str.c_str())); } -} // closing lean +} // closing lp template inline void hash_combine(std::size_t & seed, const T & v) { seed ^= std::hash()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); @@ -126,8 +126,8 @@ template struct hash> { } }; template<> -struct hash> { - inline size_t operator()(const lean::numeric_pair & v) const { +struct hash> { + inline size_t operator()(const lp::numeric_pair & v) const { size_t seed = 0; hash_combine(seed, v.x); hash_combine(seed, v.y); diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h index 0d8163a14..ff95fe258 100644 --- a/src/util/lp/lu.h +++ b/src/util/lp/lu.h @@ -18,7 +18,7 @@ #include "util/lp/row_eta_matrix.h" #include "util/lp/square_dense_submatrix.h" #include "util/lp/dense_matrix.h" -namespace lean { +namespace lp { #ifdef LEAN_DEBUG template // print the nr x nc submatrix at the top left corner void print_submatrix(sparse_matrix & m, unsigned mr, unsigned nc); @@ -32,7 +32,7 @@ void print_matrix(sparse_matrix& m, std::ostream & out); template X dot_product(const vector & a, const vector & b) { - lean_assert(a.size() == b.size()); + lp_assert(a.size() == b.size()); auto r = zero_of_type(); for (unsigned i = 0; i < a.size(); i++) { r += a[i] * b[i]; @@ -99,7 +99,7 @@ public: m_i = p.apply_reverse(m_i); #ifdef LEAN_DEBUG - // lean_assert(*this == deb); + // lp_assert(*this == deb); #endif } }; // end of one_elem_on_diag @@ -291,7 +291,7 @@ public: bool need_to_refactor() { return m_refactor_counter >= 200; } void adjust_dimension_with_matrix_A() { - lean_assert(m_A.row_count() >= m_dim); + lp_assert(m_A.row_count() >= m_dim); m_dim = m_A.row_count(); m_U.resize(m_dim); m_Q.resize(m_dim); @@ -305,7 +305,7 @@ public: unsigned m = m_A.row_count(); unsigned m_prev = m_U.dimension(); - lean_assert(m_A.column_count() == heading.size()); + lp_assert(m_A.column_count() == heading.size()); for (unsigned i = m_prev; i < m; i++) { for (const row_cell & c : m_A.m_rows[i]) { @@ -321,14 +321,14 @@ public: void add_last_rows_to_B(const vector & heading, const std::unordered_set & columns_to_replace) { unsigned m = m_A.row_count(); - lean_assert(m_A.column_count() == heading.size()); + lp_assert(m_A.column_count() == heading.size()); adjust_dimension_with_matrix_A(); m_w_for_extension.resize(m); // At this moment the LU is correct // for B extended by only by ones at the diagonal in the lower right corner for (unsigned j :columns_to_replace) { - lean_assert(heading[j] >= 0); + lp_assert(heading[j] >= 0); replace_column_with_only_change_at_last_rows(j, heading[j]); if (get_status() == LU_status::Degenerated) break; diff --git a/src/util/lp/lu.hpp b/src/util/lp/lu.hpp index 2d2c7c7c4..c602892ac 100644 --- a/src/util/lp/lu.hpp +++ b/src/util/lp/lu.hpp @@ -9,7 +9,7 @@ #include #include "util/debug.h" #include "util/lp/lu.h" -namespace lean { +namespace lp { #ifdef LEAN_DEBUG template // print the nr x nc submatrix at the top left corner void print_submatrix(sparse_matrix & m, unsigned mr, unsigned nc, std::ostream & out) { @@ -122,29 +122,29 @@ lu::lu(static_matrix const & A, m_failure(false), m_row_eta_work_vector(A.row_count()), m_refactor_counter(0) { - lean_assert(!(numeric_traits::precise() && settings.use_tableau())); + lp_assert(!(numeric_traits::precise() && settings.use_tableau())); #ifdef LEAN_DEBUG debug_test_of_basis(A, basis); #endif ++m_settings.st().m_num_factorizations; create_initial_factorization(); #ifdef LEAN_DEBUG - // lean_assert(check_correctness()); + // lp_assert(check_correctness()); #endif } template void lu::debug_test_of_basis(static_matrix const & A, vector & basis) { std::set set; for (unsigned i = 0; i < A.row_count(); i++) { - lean_assert(basis[i]< A.column_count()); + lp_assert(basis[i]< A.column_count()); set.insert(basis[i]); } - lean_assert(set.size() == A.row_count()); + lp_assert(set.size() == A.row_count()); } template void lu::solve_By(indexed_vector & y) { - lean_assert(false); // not implemented + lp_assert(false); // not implemented // init_vector_y(y); // solve_By_when_y_is_ready(y); } @@ -277,20 +277,20 @@ void lu::solve_yB(vector& y) { template void lu::solve_yB_indexed(indexed_vector& y) { - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); // first solve yU = cb*R(-1) m_R.apply_reverse_from_right_to_T(y); // got y = cb*R(-1) - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); m_U.solve_y_U_indexed(y, m_settings); // got y*U=cb*R(-1) - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); m_Q.apply_reverse_from_right_to_T(y); - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); for (auto e = m_tail.rbegin(); e != m_tail.rend(); ++e) { #ifdef LEAN_DEBUG (*e)->set_number_of_columns(m_dim); #endif (*e)->apply_from_right(y); - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); } } @@ -304,8 +304,8 @@ void lu::add_delta_to_solution(const vector& yc, vector& y){ template void lu::add_delta_to_solution_indexed(indexed_vector& y) { // the delta sits in m_y_copy, put result into y - lean_assert(y.is_OK()); - lean_assert(m_y_copy.is_OK()); + lp_assert(y.is_OK()); + lp_assert(m_y_copy.is_OK()); m_ii.clear(); m_ii.resize(y.data_size()); for (unsigned i : y.m_index) @@ -315,7 +315,7 @@ void lu::add_delta_to_solution_indexed(indexed_vector& y) { if (m_ii[i] == 0) m_ii.set_value(1, i); } - lean_assert(m_ii.is_OK()); + lp_assert(m_ii.is_OK()); y.m_index.clear(); for (unsigned i : m_ii.m_index) { @@ -326,7 +326,7 @@ void lu::add_delta_to_solution_indexed(indexed_vector& y) { v = zero_of_type(); } - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); } template @@ -343,7 +343,7 @@ void lu::find_error_of_yB_indexed(const indexed_vector& y, const vector // it is a non efficient version indexed_vector yc = m_y_copy; yc.m_index.clear(); - lean_assert(!numeric_traits::precise()); + lp_assert(!numeric_traits::precise()); { vector d_basis(y.m_data.size()); @@ -364,10 +364,10 @@ void lu::find_error_of_yB_indexed(const indexed_vector& y, const vector } } #endif - lean_assert(m_ii.is_OK()); + lp_assert(m_ii.is_OK()); m_ii.clear(); m_ii.resize(y.data_size()); - lean_assert(m_y_copy.is_OK()); + lp_assert(m_y_copy.is_OK()); // put the error into m_y_copy for (auto k : y.m_index) { auto & row = m_A.m_rows[k]; @@ -399,7 +399,7 @@ void lu::find_error_of_yB_indexed(const indexed_vector& y, const vector m_y_copy.set_value(v, k); } } - lean_assert(m_y_copy.is_OK()); + lp_assert(m_y_copy.is_OK()); } @@ -415,31 +415,31 @@ void lu::solve_yB_with_error_check_indexed(indexed_vector & y, const ve solve_yB_indexed(y); } else { solve_yB(y.m_data); - y.restore_index_and_clean_from_data(); + y.restore_index_and_clp_from_data(); } return; } - lean_assert(m_y_copy.is_OK()); - lean_assert(y.is_OK()); + lp_assert(m_y_copy.is_OK()); + lp_assert(y.is_OK()); if (y.m_index.size() * ratio_of_index_size_to_all_size() < m_A.column_count()) { m_y_copy = y; solve_yB_indexed(y); - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); if (y.m_index.size() * ratio_of_index_size_to_all_size() >= m_A.column_count()) { find_error_of_yB(m_y_copy.m_data, y.m_data, basis); solve_yB(m_y_copy.m_data); add_delta_to_solution(m_y_copy.m_data, y.m_data); - y.restore_index_and_clean_from_data(); + y.restore_index_and_clp_from_data(); m_y_copy.clear_all(); } else { find_error_of_yB_indexed(y, heading, settings); // this works with m_y_copy solve_yB_indexed(m_y_copy); add_delta_to_solution_indexed(y); } - lean_assert(m_y_copy.is_OK()); + lp_assert(m_y_copy.is_OK()); } else { solve_yB_with_error_check(y.m_data, basis); - y.restore_index_and_clean_from_data(); + y.restore_index_and_clp_from_data(); } } @@ -489,7 +489,7 @@ template void lu::perform_transformations_on_w(indexed_vector& w) { apply_lp_list_to_w(w); m_Q.apply_reverse_from_left(w); - // TBD does not compile: lean_assert(numeric_traits::precise() || check_vector_for_small_values(w, m_settings)); + // TBD does not compile: lp_assert(numeric_traits::precise() || check_vector_for_small_values(w, m_settings)); } // see Chvatal 24.3 @@ -503,7 +503,7 @@ template void lu::apply_lp_list_to_w(indexed_vector & w) { for (unsigned i = 0; i < m_tail.size(); i++) { m_tail[i]->apply_from_left_to_T(w, m_settings); - // TBD does not compile: lean_assert(check_vector_for_small_values(w, m_settings)); + // TBD does not compile: lp_assert(check_vector_for_small_values(w, m_settings)); } } template @@ -595,7 +595,7 @@ void lu::check_apply_lp_lists_to_w(T * w) { permutation_matrix qr = m_Q.get_reverse(); apply_to_vector(qr, w); for (int i = m_dim - 1; i >= 0; i--) { - lean_assert(abs(w[i] - w[i]) < 0.0000001); + lp_assert(abs(w[i] - w[i]) < 0.0000001); } } @@ -640,7 +640,7 @@ bool lu::is_correct(const vector& basis) { #ifdef LEAN_DEBUG template dense_matrix lu::tail_product() { - lean_assert(tail_size() > 0); + lp_assert(tail_size() > 0); dense_matrix left_side = permutation_matrix(m_dim); for (unsigned i = 0; i < tail_size(); i++) { matrix* lp = get_lp_matrix(i); @@ -690,8 +690,8 @@ template bool lu::all_columns_and_rows_are_active() { unsigned i = m_dim; while (i--) { - lean_assert(m_U.col_is_active(i)); - lean_assert(m_U.row_is_active(i)); + lp_assert(m_U.col_is_active(i)); + lp_assert(m_U.row_is_active(i)); } return true; } @@ -733,9 +733,9 @@ void lu::create_initial_factorization(){ } } if (j == m_dim) { - // TBD does not compile: lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); - // lean_assert(is_correct()); - // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // TBD does not compile: lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // lp_assert(is_correct()); + // lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); return; } j++; @@ -748,12 +748,12 @@ void lu::create_initial_factorization(){ } } m_dense_LU->update_parent_matrix(m_settings); - lean_assert(m_dense_LU->is_L_matrix()); + lp_assert(m_dense_LU->is_L_matrix()); m_dense_LU->conjugate_by_permutation(m_Q); push_matrix_to_tail(m_dense_LU); m_refactor_counter = 0; - // lean_assert(is_correct()); - // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // lp_assert(is_correct()); + // lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); } template @@ -780,7 +780,7 @@ void lu::scan_last_row_to_work_vector(unsigned lowest_row_of_the_bump) { vector> & last_row_vec = m_U.get_row_values(m_U.adjust_row(lowest_row_of_the_bump)); for (auto & iv : last_row_vec) { if (is_zero(iv.m_value)) continue; - lean_assert(!m_settings.abs_val_is_smaller_than_drop_tolerance(iv.m_value)); + lp_assert(!m_settings.abs_val_is_smaller_than_drop_tolerance(iv.m_value)); unsigned adjusted_col = m_U.adjust_column_inverse(iv.m_index); if (adjusted_col < lowest_row_of_the_bump) { m_row_eta_work_vector.set_value(-iv.m_value, adjusted_col); @@ -801,14 +801,14 @@ void lu::pivot_and_solve_the_system(unsigned replaced_column, unsigned low vector> & row = m_U.get_row_values(aj); for (auto & iv : row) { unsigned col = m_U.adjust_column_inverse(iv.m_index); - lean_assert(col >= j || numeric_traits::is_zero(iv.m_value)); + lp_assert(col >= j || numeric_traits::is_zero(iv.m_value)); if (col == j) continue; if (numeric_traits::is_zero(iv.m_value)) { continue; } // the -v is for solving the system ( to zero the last row), and +v is for pivoting T delta = col < lowest_row_of_the_bump? -v * iv.m_value: v * iv.m_value; - lean_assert(numeric_traits::is_zero(delta) == false); + lp_assert(numeric_traits::is_zero(delta) == false); @@ -885,16 +885,16 @@ void lu::replace_column(T pivot_elem_for_checking, indexed_vector & w, push_matrix_to_tail(row_eta); } calculate_Lwave_Pwave_for_bump(replaced_column, lowest_row_of_the_bump); - // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); - // lean_assert(w.is_OK() && m_row_eta_work_vector.is_OK()); + // lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // lp_assert(w.is_OK() && m_row_eta_work_vector.is_OK()); } template void lu::calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned lowest_row_of_the_bump){ T diagonal_elem; if (replaced_column < lowest_row_of_the_bump) { diagonal_elem = m_row_eta_work_vector[lowest_row_of_the_bump]; - // lean_assert(m_row_eta_work_vector.is_OK()); - m_U.set_row_from_work_vector_and_clean_work_vector_not_adjusted(m_U.adjust_row(lowest_row_of_the_bump), m_row_eta_work_vector, m_settings); + // lp_assert(m_row_eta_work_vector.is_OK()); + m_U.set_row_from_work_vector_and_clp_work_vector_not_adjusted(m_U.adjust_row(lowest_row_of_the_bump), m_row_eta_work_vector, m_settings); } else { diagonal_elem = m_U(lowest_row_of_the_bump, lowest_row_of_the_bump); // todo - get it more efficiently } @@ -904,7 +904,7 @@ void lu::calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned } calculate_Lwave_Pwave_for_last_row(lowest_row_of_the_bump, diagonal_elem); - // lean_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + // lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); } template @@ -930,8 +930,8 @@ void init_factorization(lu* & factorization, static_matrix & m_A, ve #ifdef LEAN_DEBUG template dense_matrix get_B(lu& f, const vector& basis) { - lean_assert(basis.size() == f.dimension()); - lean_assert(basis.size() == f.m_U.dimension()); + lp_assert(basis.size() == f.dimension()); + lp_assert(basis.size() == f.m_U.dimension()); dense_matrix B(f.dimension(), f.dimension()); for (unsigned i = 0; i < f.dimension(); i++) for (unsigned j = 0; j < f.dimension(); j++) diff --git a/src/util/lp/lu_instances.cpp b/src/util/lp/lu_instances.cpp index c8ff7b2f4..97fa3eed9 100644 --- a/src/util/lp/lu_instances.cpp +++ b/src/util/lp/lu_instances.cpp @@ -8,56 +8,56 @@ #include "util/vector.h" #include "util/debug.h" #include "util/lp/lu.hpp" -template double lean::dot_product(vector const&, vector const&); -template lean::lu::lu(lean::static_matrix const&, vector&, lean::lp_settings&); -template void lean::lu::push_matrix_to_tail(lean::tail_matrix*); -template void lean::lu::replace_column(double, lean::indexed_vector&, unsigned); -template void lean::lu::solve_Bd(unsigned int, lean::indexed_vector&, lean::indexed_vector&); -template lean::lu::~lu(); -template void lean::lu::push_matrix_to_tail(lean::tail_matrix*); -template void lean::lu::solve_Bd(unsigned int, lean::indexed_vector&, lean::indexed_vector&); -template lean::lu::~lu(); -template void lean::lu >::push_matrix_to_tail(lean::tail_matrix >*); -template void lean::lu >::solve_Bd(unsigned int, lean::indexed_vector&, lean::indexed_vector&); -template lean::lu >::~lu(); -template lean::mpq lean::dot_product(vector const&, vector const&); -template void lean::init_factorization(lean::lu*&, lean::static_matrix&, vector&, lean::lp_settings&); -template void lean::init_factorization(lean::lu*&, lean::static_matrix&, vector&, lean::lp_settings&); -template void lean::init_factorization >(lean::lu >*&, lean::static_matrix >&, vector&, lean::lp_settings&); +template double lp::dot_product(vector const&, vector const&); +template lp::lu::lu(lp::static_matrix const&, vector&, lp::lp_settings&); +template void lp::lu::push_matrix_to_tail(lp::tail_matrix*); +template void lp::lu::replace_column(double, lp::indexed_vector&, unsigned); +template void lp::lu::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&); +template lp::lu::~lu(); +template void lp::lu::push_matrix_to_tail(lp::tail_matrix*); +template void lp::lu::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&); +template lp::lu::~lu(); +template void lp::lu >::push_matrix_to_tail(lp::tail_matrix >*); +template void lp::lu >::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&); +template lp::lu >::~lu(); +template lp::mpq lp::dot_product(vector const&, vector const&); +template void lp::init_factorization(lp::lu*&, lp::static_matrix&, vector&, lp::lp_settings&); +template void lp::init_factorization(lp::lu*&, lp::static_matrix&, vector&, lp::lp_settings&); +template void lp::init_factorization >(lp::lu >*&, lp::static_matrix >&, vector&, lp::lp_settings&); #ifdef LEAN_DEBUG -template void lean::print_matrix(lean::sparse_matrix&, std::ostream & out); -template void lean::print_matrix(lean::static_matrix&, std::ostream&); -template void lean::print_matrix >(lean::static_matrix >&, std::ostream&); -template void lean::print_matrix(lean::static_matrix&, std::ostream & out); -template bool lean::lu::is_correct(const vector& basis); -template bool lean::lu >::is_correct( vector const &); -template lean::dense_matrix lean::get_B(lean::lu&, const vector& basis); -template lean::dense_matrix lean::get_B(lean::lu&, vector const&); +template void lp::print_matrix(lp::sparse_matrix&, std::ostream & out); +template void lp::print_matrix(lp::static_matrix&, std::ostream&); +template void lp::print_matrix >(lp::static_matrix >&, std::ostream&); +template void lp::print_matrix(lp::static_matrix&, std::ostream & out); +template bool lp::lu::is_correct(const vector& basis); +template bool lp::lu >::is_correct( vector const &); +template lp::dense_matrix lp::get_B(lp::lu&, const vector& basis); +template lp::dense_matrix lp::get_B(lp::lu&, vector const&); #endif -template bool lean::lu::pivot_the_row(int); // NOLINT -template void lean::lu::init_vector_w(unsigned int, lean::indexed_vector&); -template void lean::lu::solve_By(vector&); -template void lean::lu::solve_By_when_y_is_ready_for_X(vector&); -template void lean::lu::solve_yB_with_error_check(vector&, const vector& basis); -template void lean::lu::solve_yB_with_error_check_indexed(lean::indexed_vector&, vector const&, const vector & basis, const lp_settings&); -template void lean::lu::replace_column(lean::mpq, lean::indexed_vector&, unsigned); -template void lean::lu::solve_By(vector&); -template void lean::lu::solve_By_when_y_is_ready_for_X(vector&); -template void lean::lu::solve_yB_with_error_check(vector&, const vector& basis); -template void lean::lu::solve_yB_with_error_check_indexed(lean::indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); -template void lean::lu >::solve_yB_with_error_check_indexed(lean::indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); -template void lean::lu >::init_vector_w(unsigned int, lean::indexed_vector&); -template void lean::lu >::replace_column(lean::mpq, lean::indexed_vector&, unsigned); -template void lean::lu >::solve_Bd_faster(unsigned int, lean::indexed_vector&); -template void lean::lu >::solve_By(vector >&); -template void lean::lu >::solve_By_when_y_is_ready_for_X(vector >&); -template void lean::lu >::solve_yB_with_error_check(vector&, const vector& basis); -template void lean::lu::solve_By(lean::indexed_vector&); -template void lean::lu::solve_By(lean::indexed_vector&); -template void lean::lu::solve_yB_indexed(lean::indexed_vector&); -template void lean::lu::solve_yB_indexed(lean::indexed_vector&); -template void lean::lu >::solve_yB_indexed(lean::indexed_vector&); -template void lean::lu::solve_By_for_T_indexed_only(lean::indexed_vector&, lean::lp_settings const&); -template void lean::lu::solve_By_for_T_indexed_only(lean::indexed_vector&, lean::lp_settings const&); +template bool lp::lu::pivot_the_row(int); // NOLINT +template void lp::lu::init_vector_w(unsigned int, lp::indexed_vector&); +template void lp::lu::solve_By(vector&); +template void lp::lu::solve_By_when_y_is_ready_for_X(vector&); +template void lp::lu::solve_yB_with_error_check(vector&, const vector& basis); +template void lp::lu::solve_yB_with_error_check_indexed(lp::indexed_vector&, vector const&, const vector & basis, const lp_settings&); +template void lp::lu::replace_column(lp::mpq, lp::indexed_vector&, unsigned); +template void lp::lu::solve_By(vector&); +template void lp::lu::solve_By_when_y_is_ready_for_X(vector&); +template void lp::lu::solve_yB_with_error_check(vector&, const vector& basis); +template void lp::lu::solve_yB_with_error_check_indexed(lp::indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); +template void lp::lu >::solve_yB_with_error_check_indexed(lp::indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); +template void lp::lu >::init_vector_w(unsigned int, lp::indexed_vector&); +template void lp::lu >::replace_column(lp::mpq, lp::indexed_vector&, unsigned); +template void lp::lu >::solve_Bd_faster(unsigned int, lp::indexed_vector&); +template void lp::lu >::solve_By(vector >&); +template void lp::lu >::solve_By_when_y_is_ready_for_X(vector >&); +template void lp::lu >::solve_yB_with_error_check(vector&, const vector& basis); +template void lp::lu::solve_By(lp::indexed_vector&); +template void lp::lu::solve_By(lp::indexed_vector&); +template void lp::lu::solve_yB_indexed(lp::indexed_vector&); +template void lp::lu::solve_yB_indexed(lp::indexed_vector&); +template void lp::lu >::solve_yB_indexed(lp::indexed_vector&); +template void lp::lu::solve_By_for_T_indexed_only(lp::indexed_vector&, lp::lp_settings const&); +template void lp::lu::solve_By_for_T_indexed_only(lp::indexed_vector&, lp::lp_settings const&); diff --git a/src/util/lp/matrix.h b/src/util/lp/matrix.h index 63fd5c01e..fb177551e 100644 --- a/src/util/lp/matrix.h +++ b/src/util/lp/matrix.h @@ -8,7 +8,7 @@ #include "util/vector.h" #include #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { // used for debugging purposes only template class matrix { diff --git a/src/util/lp/matrix.hpp b/src/util/lp/matrix.hpp index d032cab8c..45e4c3da2 100644 --- a/src/util/lp/matrix.hpp +++ b/src/util/lp/matrix.hpp @@ -7,7 +7,7 @@ #include #include #include "util/lp/matrix.h" -namespace lean { +namespace lp { template bool matrix::is_equal(const matrix& other) { if (other.row_count() != row_count() || other.column_count() != column_count()) diff --git a/src/util/lp/matrix_instances.cpp b/src/util/lp/matrix_instances.cpp index aeee62786..ae37a2e69 100644 --- a/src/util/lp/matrix_instances.cpp +++ b/src/util/lp/matrix_instances.cpp @@ -7,10 +7,10 @@ #include "util/lp/matrix.hpp" #include "util/lp/static_matrix.h" #include -template void lean::print_matrix(lean::matrix const*, std::ostream & out); -template bool lean::matrix::is_equal(lean::matrix const&); -template void lean::print_matrix >(lean::matrix > const *, std::basic_ostream > &); -template void lean::print_matrix(lean::matrix const*, std::ostream&); -template bool lean::matrix >::is_equal(lean::matrix > const&); -template bool lean::matrix::is_equal(lean::matrix const&); +template void lp::print_matrix(lp::matrix const*, std::ostream & out); +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 diff --git a/src/util/lp/mps_reader.h b/src/util/lp/mps_reader.h index eb83735ca..257cf63e2 100644 --- a/src/util/lp/mps_reader.h +++ b/src/util/lp/mps_reader.h @@ -19,7 +19,7 @@ #include "util/lp/lar_solver.h" #include "util/lp/lp_utils.h" #include "util/lp/lp_solver.h" -namespace lean { +namespace lp { inline bool my_white_space(const char & a) { return a == ' ' || a == '\t'; } @@ -160,9 +160,9 @@ class mps_reader { if (m_line[i] == ' ') break; } - lean_assert(m_line.size() >= offset); - lean_assert(m_line.size() >> i); - lean_assert(i >= offset); + lp_assert(m_line.size() >= offset); + lp_assert(m_line.size() >> i); + lp_assert(i >= offset); return m_line.substr(offset, i - offset); } @@ -497,7 +497,7 @@ class mps_reader { void create_or_update_bound() { const unsigned name_offset = 14; - lean_assert(m_line.size() >= 14); + lp_assert(m_line.size() >= 14); vector bound_string = split_and_trim(m_line.substr(name_offset, m_line.size())); if (bound_string.size() == 0) { @@ -603,7 +603,7 @@ class mps_reader { } for (auto s : row_with_range->m_row_columns) { - lean_assert(m_columns.find(s.first) != m_columns.end()); + lp_assert(m_columns.find(s.first) != m_columns.end()); other_bound_range_row->m_row_columns[s.first] = s.second; } } @@ -679,7 +679,7 @@ class mps_reader { if (row->m_name != m_cost_row_name) { solver->add_constraint(get_relation_from_row(row->m_type), row->m_right_side, row->m_index); for (auto s : row->m_row_columns) { - lean_assert(m_columns.find(s.first) != m_columns.end()); + lp_assert(m_columns.find(s.first) != m_columns.end()); solver->set_row_column_coefficient(row->m_index, m_columns[s.first]->m_index, s.second); } } else { @@ -714,7 +714,7 @@ class mps_reader { void set_solver_cost(row * row, lp_solver *solver) { for (auto s : row->m_row_columns) { std::string name = s.first; - lean_assert(m_columns.find(name) != m_columns.end()); + lp_assert(m_columns.find(name) != m_columns.end()); mps_reader::column * col = m_columns[name]; solver->set_cost_for_column(col->m_index, s.second); } @@ -723,7 +723,7 @@ class mps_reader { public: void set_message_stream(std::ostream * o) { - lean_assert(o != nullptr); + lp_assert(o != nullptr); m_message_stream = o; } vector column_names() { diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index 81372be32..efa003b37 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -14,23 +14,23 @@ namespace nra { struct mon_eq { - mon_eq(lean::var_index v, unsigned sz, lean::var_index const* vs): + mon_eq(lp::var_index v, unsigned sz, lp::var_index const* vs): m_v(v), m_vs(sz, vs) {} - lean::var_index m_v; - svector m_vs; + lp::var_index m_v; + svector m_vs; }; struct solver::imp { - lean::lar_solver& s; + lp::lar_solver& s; reslimit& m_limit; params_ref m_params; u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables scoped_ptr m_nlsat; vector m_monomials; unsigned_vector m_monomials_lim; - mutable std::unordered_map m_variable_values; // current model + mutable std::unordered_map m_variable_values; // current model - imp(lean::lar_solver& s, reslimit& lim, params_ref const& p): + imp(lp::lar_solver& s, reslimit& lim, params_ref const& p): s(s), m_limit(lim), m_params(p) { @@ -40,7 +40,7 @@ namespace nra { return !m_monomials.empty() && !check_assignments(); } - void add(lean::var_index v, unsigned sz, lean::var_index const* vs) { + void add(lp::var_index v, unsigned sz, lp::var_index const* vs) { m_monomials.push_back(mon_eq(v, sz, vs)); } @@ -87,7 +87,7 @@ namespace nra { TBD: use partial model from lra_solver to prime the state of nlsat_solver. TBD: explore more incremental ways of applying nlsat (using assumptions) */ - lbool check(lean::explanation_t& ex) { + lbool check(lp::explanation_t& ex) { SASSERT(need_check()); m_nlsat = alloc(nlsat::solver, m_limit, m_params); m_lp2nl.reset(); @@ -168,31 +168,31 @@ namespace nra { nlsat::literal lit; nlsat::assumption a = this + idx; switch (k) { - case lean::lconstraint_kind::LE: + case lp::lconstraint_kind::LE: lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); break; - case lean::lconstraint_kind::GE: + case lp::lconstraint_kind::GE: lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); break; - case lean::lconstraint_kind::LT: + case lp::lconstraint_kind::LT: lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); break; - case lean::lconstraint_kind::GT: + case lp::lconstraint_kind::GT: lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); break; - case lean::lconstraint_kind::EQ: + case lp::lconstraint_kind::EQ: lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); break; } m_nlsat->mk_clause(1, &lit, a); } - bool is_int(lean::var_index v) { + bool is_int(lp::var_index v) { return s.var_is_int(v); } - polynomial::var lp2nl(lean::var_index v) { + polynomial::var lp2nl(lp::var_index v) { polynomial::var r; if (!m_lp2nl.find(v, r)) { r = m_nlsat->mk_var(is_int(v)); @@ -201,7 +201,7 @@ namespace nra { return r; } - nlsat::anum const& value(lean::var_index v) const { + nlsat::anum const& value(lp::var_index v) const { return m_nlsat->value(m_lp2nl.find(v)); } @@ -221,7 +221,7 @@ namespace nra { } }; - solver::solver(lean::lar_solver& s, reslimit& lim, params_ref const& p) { + solver::solver(lp::lar_solver& s, reslimit& lim, params_ref const& p) { m_imp = alloc(imp, s, lim, p); } @@ -229,11 +229,11 @@ namespace nra { dealloc(m_imp); } - void solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) { + void solver::add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs) { m_imp->add(v, sz, vs); } - lbool solver::check(lean::explanation_t& ex) { + lbool solver::check(lp::explanation_t& ex) { return m_imp->check(ex); } @@ -253,7 +253,7 @@ namespace nra { return m_imp->display(out); } - nlsat::anum const& solver::value(lean::var_index v) const { + nlsat::anum const& solver::value(lp::var_index v) const { return m_imp->value(v); } diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h index 0b02e7136..68c9e98e5 100644 --- a/src/util/lp/nra_solver.h +++ b/src/util/lp/nra_solver.h @@ -10,7 +10,7 @@ #include "util/params.h" #include "nlsat/nlsat_solver.h" -namespace lean { +namespace lp { class lar_solver; } @@ -25,7 +25,7 @@ namespace nra { public: - solver(lean::lar_solver& s, reslimit& lim, params_ref const& p = params_ref()); + solver(lp::lar_solver& s, reslimit& lim, params_ref const& p = params_ref()); ~solver(); @@ -33,13 +33,13 @@ namespace nra { \brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1] The variable v is equal to the product of variables vs. */ - void add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs); + void add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs); /* \brief Check feasiblity of linear constraints augmented by polynomial definitions that are added. */ - lbool check(lean::explanation_t& ex); + lbool check(lp::explanation_t& ex); /* \brief determine whether nra check is needed. @@ -49,7 +49,7 @@ namespace nra { /* \brief Access model. */ - nlsat::anum const& value(lean::var_index v) const; + nlsat::anum const& value(lp::var_index v) const; nlsat::anum_manager& am(); diff --git a/src/util/lp/numeric_pair.h b/src/util/lp/numeric_pair.h index db7b71119..b41f6b565 100644 --- a/src/util/lp/numeric_pair.h +++ b/src/util/lp/numeric_pair.h @@ -17,11 +17,11 @@ // include "util/numerics/mpq.h" // include "util/numerics/numeric_traits.h" #endif -namespace lean { +namespace lp { #ifdef lp_for_z3 // rename rationals typedef rational mpq; #else - typedef lean::mpq mpq; + typedef lp::mpq mpq; #endif @@ -73,8 +73,8 @@ template struct convert_struct { static X convert(const Y & y){ return X(y);} static bool is_epsilon_small(const X & x, const double & y) { return std::abs(numeric_traits::get_double(x)) < y; } - static bool below_bound_numeric(const X &, const X &, const Y &) { /*lean_unreachable();*/ return false;} - static bool above_bound_numeric(const X &, const X &, const Y &) { /*lean_unreachable();*/ return false; } + static bool below_bound_numeric(const X &, const X &, const Y &) { /*lp_unreachable();*/ return false;} + static bool above_bound_numeric(const X &, const X &, const Y &) { /*lp_unreachable();*/ return false; } }; @@ -144,7 +144,7 @@ struct numeric_pair { } numeric_pair operator/(const numeric_pair &) const { - // lean_unreachable(); + // lp_unreachable(); } @@ -153,7 +153,7 @@ struct numeric_pair { } numeric_pair operator*(const numeric_pair & /*a*/) const { - // lean_unreachable(); + // lp_unreachable(); } numeric_pair& operator+=(const numeric_pair & a) { @@ -188,7 +188,7 @@ struct numeric_pair { return numeric_pair(-x, -y); } - static bool precize() { return lean::numeric_traits::precize();} + static bool precize() { return lp::numeric_traits::precize();} bool is_zero() const { return x.is_zero() && y.is_zero(); } @@ -230,15 +230,15 @@ numeric_pair operator/(const numeric_pair & r, const X & a) { } // template bool precise() { return numeric_traits::precise();} -template double get_double(const lean::numeric_pair & ) { /* lean_unreachable(); */ return 0;} +template double get_double(const lp::numeric_pair & ) { /* lp_unreachable(); */ return 0;} template -class numeric_traits> { +class numeric_traits> { public: static bool precise() { return numeric_traits::precise();} - static lean::numeric_pair zero() { return lean::numeric_pair(numeric_traits::zero(), numeric_traits::zero()); } - static bool is_zero(const lean::numeric_pair & v) { return numeric_traits::is_zero(v.x) && numeric_traits::is_zero(v.y); } - static double get_double(const lean::numeric_pair & v){ return numeric_traits::get_double(v.x); } // just return the double of the first coordinate - static double one() { /*lean_unreachable();*/ return 0;} + static lp::numeric_pair zero() { return lp::numeric_pair(numeric_traits::zero(), numeric_traits::zero()); } + static bool is_zero(const lp::numeric_pair & v) { return numeric_traits::is_zero(v.x) && numeric_traits::is_zero(v.y); } + static double get_double(const lp::numeric_pair & v){ return numeric_traits::get_double(v.x); } // just return the double of the first coordinate + static double one() { /*lp_unreachable();*/ return 0;} static bool is_pos(const numeric_pair &p) { return numeric_traits::is_pos(p.x) || (numeric_traits::is_zero(p.x) && numeric_traits::is_pos(p.y)); @@ -268,11 +268,11 @@ struct convert_struct, double> { return convert_struct::is_epsilon_small(p.x, eps) && convert_struct::is_epsilon_small(p.y, eps); } static bool below_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { - // lean_unreachable(); + // lp_unreachable(); return false; } static bool above_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { - // lean_unreachable(); + // lp_unreachable(); return false; } }; diff --git a/src/util/lp/permutation_matrix.h b/src/util/lp/permutation_matrix.h index 4bdd57f25..e0a3ac4c1 100644 --- a/src/util/lp/permutation_matrix.h +++ b/src/util/lp/permutation_matrix.h @@ -12,7 +12,7 @@ #include "util/lp/lp_settings.h" #include "util/lp/matrix.h" #include "util/lp/tail_matrix.h" -namespace lean { +namespace lp { #ifdef LEAN_DEBUG inline bool is_even(int k) { return (k/2)*2 == k; } #endif @@ -86,7 +86,7 @@ class permutation_matrix : public tail_matrix { void apply_reverse_from_right_to_X(vector & w); void set_val(unsigned i, unsigned pi) { - lean_assert(i < size() && pi < size()); m_permutation[i] = pi; m_rev[pi] = i; } + lp_assert(i < size() && pi < size()); m_permutation[i] = pi; m_rev[pi] = i; } void transpose_from_left(unsigned i, unsigned j); diff --git a/src/util/lp/permutation_matrix.hpp b/src/util/lp/permutation_matrix.hpp index ec9af5a50..a379e1ab2 100644 --- a/src/util/lp/permutation_matrix.hpp +++ b/src/util/lp/permutation_matrix.hpp @@ -4,7 +4,7 @@ */ #include "util/vector.h" #include "util/lp/permutation_matrix.h" -namespace lean { +namespace lp { template permutation_matrix::permutation_matrix(unsigned length): m_permutation(length), m_rev(length), m_T_buffer(length), m_X_buffer(length) { for (unsigned i = 0; i < length; i++) { // do not change the direction of the loop because of the vectorization bug in clang3.3 m_permutation[i] = m_rev[i] = i; @@ -50,7 +50,7 @@ void permutation_matrix::apply_from_left(vector & w, lp_settings & ) { // deb.apply_from_left(deb_w); #endif // std::cout << " apply_from_left " << std::endl; - lean_assert(m_X_buffer.size() == w.size()); + lp_assert(m_X_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_X_buffer[i] = w[m_permutation[i]]; @@ -60,7 +60,7 @@ void permutation_matrix::apply_from_left(vector & w, lp_settings & ) { w[i] = m_X_buffer[i]; } #ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(deb_w, w, row_count())); + // lp_assert(vectors_are_equal(deb_w, w, row_count())); // delete [] deb_w; #endif } @@ -86,7 +86,7 @@ template void permutation_matrix::apply_from_righ // T * deb_w = clone_vector(w, row_count()); // deb.apply_from_right(deb_w); #endif - lean_assert(m_T_buffer.size() == w.size()); + lp_assert(m_T_buffer.size() == w.size()); for (unsigned i = 0; i < size(); i++) { m_T_buffer[i] = w[m_rev[i]]; } @@ -95,7 +95,7 @@ template void permutation_matrix::apply_from_righ w[i] = m_T_buffer[i]; } #ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(deb_w, w, row_count())); + // lp_assert(vectors_are_equal(deb_w, w, row_count())); // delete [] deb_w; #endif } @@ -117,9 +117,9 @@ template void permutation_matrix::apply_from_righ unsigned pj = m_permutation[j]; w.set_value(buffer[i], pj); } - lean_assert(w.is_OK()); + lp_assert(w.is_OK()); #ifdef LEAN_DEBUG - lean_assert(vectors_are_equal(wcopy, w.m_data)); + lp_assert(vectors_are_equal(wcopy, w.m_data)); #endif } @@ -166,7 +166,7 @@ void permutation_matrix::apply_reverse_from_left(indexed_vector & w) { w.m_index[i] = j; } #ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(deb_w, w.m_data, row_count())); + // lp_assert(vectors_are_equal(deb_w, w.m_data, row_count())); // delete [] deb_w; #endif } @@ -174,7 +174,7 @@ void permutation_matrix::apply_reverse_from_left(indexed_vector & w) { template void permutation_matrix::apply_reverse_from_left_to_T(vector & w) { // the result will be w = p(-1) * w - lean_assert(m_T_buffer.size() == w.size()); + lp_assert(m_T_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_T_buffer[m_permutation[i]] = w[i]; @@ -187,7 +187,7 @@ void permutation_matrix::apply_reverse_from_left_to_T(vector & w) { template void permutation_matrix::apply_reverse_from_left_to_X(vector & w) { // the result will be w = p(-1) * w - lean_assert(m_X_buffer.size() == w.size()); + lp_assert(m_X_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_X_buffer[m_permutation[i]] = w[i]; @@ -201,7 +201,7 @@ void permutation_matrix::apply_reverse_from_left_to_X(vector & w) { template void permutation_matrix::apply_reverse_from_right_to_T(vector & w) { // the result will be w = w * p(-1) - lean_assert(m_T_buffer.size() == w.size()); + lp_assert(m_T_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_T_buffer[i] = w[m_permutation[i]]; @@ -219,7 +219,7 @@ void permutation_matrix::apply_reverse_from_right_to_T(indexed_vector & // vector wcopy(w.m_data); // apply_reverse_from_right_to_T(wcopy); #endif - lean_assert(w.is_OK()); + lp_assert(w.is_OK()); vector tmp; vector tmp_index(w.m_index); for (auto i : w.m_index) { @@ -232,15 +232,15 @@ void permutation_matrix::apply_reverse_from_right_to_T(indexed_vector & w.set_value(tmp[k], m_rev[j]); } - // lean_assert(w.is_OK()); - // lean_assert(vectors_are_equal(w.m_data, wcopy)); + // lp_assert(w.is_OK()); + // lp_assert(vectors_are_equal(w.m_data, wcopy)); } template void permutation_matrix::apply_reverse_from_right_to_X(vector & w) { // the result will be w = w * p(-1) - lean_assert(m_X_buffer.size() == w.size()); + lp_assert(m_X_buffer.size() == w.size()); unsigned i = size(); while (i-- > 0) { m_X_buffer[i] = w[m_permutation[i]]; @@ -253,7 +253,7 @@ void permutation_matrix::apply_reverse_from_right_to_X(vector & w) { template void permutation_matrix::transpose_from_left(unsigned i, unsigned j) { // the result will be this = (i,j)*this - lean_assert(i < size() && j < size() && i != j); + lp_assert(i < size() && j < size() && i != j); auto pi = m_rev[i]; auto pj = m_rev[j]; set_val(pi, j); @@ -262,7 +262,7 @@ template void permutation_matrix::transpose_from_ template void permutation_matrix::transpose_from_right(unsigned i, unsigned j) { // the result will be this = this * (i,j) - lean_assert(i < size() && j < size() && i != j); + lp_assert(i < size() && j < size() && i != j); auto pi = m_permutation[i]; auto pj = m_permutation[j]; set_val(i, pj); @@ -271,7 +271,7 @@ template void permutation_matrix::transpose_from_ template void permutation_matrix::multiply_by_permutation_from_left(permutation_matrix & p) { m_work_array = m_permutation; - lean_assert(p.size() == size()); + lp_assert(p.size() == size()); unsigned i = size(); while (i-- > 0) { set_val(i, m_work_array[p[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation @@ -281,7 +281,7 @@ template void permutation_matrix::multiply_by_per // this is multiplication in the matrix sense template void permutation_matrix::multiply_by_permutation_from_right(permutation_matrix & p) { m_work_array = m_permutation; - lean_assert(p.size() == size()); + lp_assert(p.size() == size()); unsigned i = size(); while (i-- > 0) set_val(i, p[m_work_array[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation @@ -289,7 +289,7 @@ template void permutation_matrix::multiply_by_per } template void permutation_matrix::multiply_by_reverse_from_right(permutation_matrix & q){ // todo : condensed permutations ? - lean_assert(q.size() == size()); + lp_assert(q.size() == size()); m_work_array = m_permutation; // the result is this = this*q(-1) unsigned i = size(); diff --git a/src/util/lp/permutation_matrix_instances.cpp b/src/util/lp/permutation_matrix_instances.cpp index 91473fabc..756ce4325 100644 --- a/src/util/lp/permutation_matrix_instances.cpp +++ b/src/util/lp/permutation_matrix_instances.cpp @@ -6,50 +6,50 @@ #include "util/vector.h" #include "util/lp/permutation_matrix.hpp" #include "util/lp/numeric_pair.h" -template void lean::permutation_matrix::apply_from_right(vector&); -template void lean::permutation_matrix::init(unsigned int); -template void lean::permutation_matrix::init(unsigned int); -template void lean::permutation_matrix>::init(unsigned int); -template bool lean::permutation_matrix::is_identity() const; -template void lean::permutation_matrix::multiply_by_permutation_from_left(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_permutation_reverse_from_left(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_reverse_from_right(lean::permutation_matrix&); -template lean::permutation_matrix::permutation_matrix(unsigned int, vector const&); -template void lean::permutation_matrix::transpose_from_left(unsigned int, unsigned int); +template void lp::permutation_matrix::apply_from_right(vector&); +template void lp::permutation_matrix::init(unsigned int); +template void lp::permutation_matrix::init(unsigned int); +template void lp::permutation_matrix>::init(unsigned int); +template bool lp::permutation_matrix::is_identity() const; +template void lp::permutation_matrix::multiply_by_permutation_from_left(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_permutation_reverse_from_left(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_reverse_from_right(lp::permutation_matrix&); +template lp::permutation_matrix::permutation_matrix(unsigned int, vector const&); +template void lp::permutation_matrix::transpose_from_left(unsigned int, unsigned int); -template void lean::permutation_matrix::apply_from_right(vector&); -template bool lean::permutation_matrix::is_identity() const; -template void lean::permutation_matrix::multiply_by_permutation_from_left(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_permutation_from_right(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_permutation_reverse_from_left(lean::permutation_matrix&); -template void lean::permutation_matrix::multiply_by_reverse_from_right(lean::permutation_matrix&); -template lean::permutation_matrix::permutation_matrix(unsigned int); -template void lean::permutation_matrix::transpose_from_left(unsigned int, unsigned int); -template void lean::permutation_matrix::transpose_from_right(unsigned int, unsigned int); -template void lean::permutation_matrix >::apply_from_right(vector&); -template bool lean::permutation_matrix >::is_identity() const; -template void lean::permutation_matrix >::multiply_by_permutation_from_left(lean::permutation_matrix >&); -template void lean::permutation_matrix >::multiply_by_permutation_from_right(lean::permutation_matrix >&); -template void lean::permutation_matrix >::multiply_by_permutation_reverse_from_left(lean::permutation_matrix >&); -template void lean::permutation_matrix >::multiply_by_reverse_from_right(lean::permutation_matrix >&); -template lean::permutation_matrix >::permutation_matrix(unsigned int); -template void lean::permutation_matrix >::transpose_from_left(unsigned int, unsigned int); -template void lean::permutation_matrix >::transpose_from_right(unsigned int, unsigned int); -template void lean::permutation_matrix::apply_reverse_from_left(lean::indexed_vector&); -template void lean::permutation_matrix::apply_reverse_from_left_to_T(vector&); -template void lean::permutation_matrix::apply_reverse_from_right_to_T(vector&); -template void lean::permutation_matrix::transpose_from_right(unsigned int, unsigned int); -template void lean::permutation_matrix::apply_reverse_from_left(lean::indexed_vector&); -template void lean::permutation_matrix::apply_reverse_from_left_to_T(vector&); -template void lean::permutation_matrix::apply_reverse_from_right_to_T(vector&); -template void lean::permutation_matrix >::apply_reverse_from_left(lean::indexed_vector&); -template void lean::permutation_matrix >::apply_reverse_from_left_to_T(vector&); -template void lean::permutation_matrix >::apply_reverse_from_right_to_T(vector&); -template void lean::permutation_matrix::multiply_by_permutation_from_right(lean::permutation_matrix&); -template lean::permutation_matrix::permutation_matrix(unsigned int); -template void lean::permutation_matrix::apply_reverse_from_left_to_X(vector &); -template void lean::permutation_matrix< lean::mpq, lean::mpq>::apply_reverse_from_left_to_X(vector &); -template void lean::permutation_matrix< lean::mpq, lean::numeric_pair< lean::mpq> >::apply_reverse_from_left_to_X(vector> &); -template void lean::permutation_matrix::apply_reverse_from_right_to_T(lean::indexed_vector&); -template void lean::permutation_matrix::apply_reverse_from_right_to_T(lean::indexed_vector&); -template void lean::permutation_matrix >::apply_reverse_from_right_to_T(lean::indexed_vector&); +template void lp::permutation_matrix::apply_from_right(vector&); +template bool lp::permutation_matrix::is_identity() const; +template void lp::permutation_matrix::multiply_by_permutation_from_left(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_permutation_from_right(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_permutation_reverse_from_left(lp::permutation_matrix&); +template void lp::permutation_matrix::multiply_by_reverse_from_right(lp::permutation_matrix&); +template lp::permutation_matrix::permutation_matrix(unsigned int); +template void lp::permutation_matrix::transpose_from_left(unsigned int, unsigned int); +template void lp::permutation_matrix::transpose_from_right(unsigned int, unsigned int); +template void lp::permutation_matrix >::apply_from_right(vector&); +template bool lp::permutation_matrix >::is_identity() const; +template void lp::permutation_matrix >::multiply_by_permutation_from_left(lp::permutation_matrix >&); +template void lp::permutation_matrix >::multiply_by_permutation_from_right(lp::permutation_matrix >&); +template void lp::permutation_matrix >::multiply_by_permutation_reverse_from_left(lp::permutation_matrix >&); +template void lp::permutation_matrix >::multiply_by_reverse_from_right(lp::permutation_matrix >&); +template lp::permutation_matrix >::permutation_matrix(unsigned int); +template void lp::permutation_matrix >::transpose_from_left(unsigned int, unsigned int); +template void lp::permutation_matrix >::transpose_from_right(unsigned int, unsigned int); +template void lp::permutation_matrix::apply_reverse_from_left(lp::indexed_vector&); +template void lp::permutation_matrix::apply_reverse_from_left_to_T(vector&); +template void lp::permutation_matrix::apply_reverse_from_right_to_T(vector&); +template void lp::permutation_matrix::transpose_from_right(unsigned int, unsigned int); +template void lp::permutation_matrix::apply_reverse_from_left(lp::indexed_vector&); +template void lp::permutation_matrix::apply_reverse_from_left_to_T(vector&); +template void lp::permutation_matrix::apply_reverse_from_right_to_T(vector&); +template void lp::permutation_matrix >::apply_reverse_from_left(lp::indexed_vector&); +template void lp::permutation_matrix >::apply_reverse_from_left_to_T(vector&); +template void lp::permutation_matrix >::apply_reverse_from_right_to_T(vector&); +template void lp::permutation_matrix::multiply_by_permutation_from_right(lp::permutation_matrix&); +template lp::permutation_matrix::permutation_matrix(unsigned int); +template void lp::permutation_matrix::apply_reverse_from_left_to_X(vector &); +template void lp::permutation_matrix< lp::mpq, lp::mpq>::apply_reverse_from_left_to_X(vector &); +template void lp::permutation_matrix< lp::mpq, lp::numeric_pair< lp::mpq> >::apply_reverse_from_left_to_X(vector> &); +template void lp::permutation_matrix::apply_reverse_from_right_to_T(lp::indexed_vector&); +template void lp::permutation_matrix::apply_reverse_from_right_to_T(lp::indexed_vector&); +template void lp::permutation_matrix >::apply_reverse_from_right_to_T(lp::indexed_vector&); diff --git a/src/util/lp/quick_xplain.cpp b/src/util/lp/quick_xplain.cpp index df409240e..93e40ea71 100644 --- a/src/util/lp/quick_xplain.cpp +++ b/src/util/lp/quick_xplain.cpp @@ -3,7 +3,7 @@ Author: Lev Nachmanson */ #include "util/lp/lar_solver.h" -namespace lean { +namespace lp { quick_xplain::quick_xplain(vector> & explanation, const lar_solver & ls, lar_solver & qsol) : m_explanation(explanation), m_parent_solver(ls), @@ -56,7 +56,7 @@ void quick_xplain::minimize(const vector& u) { } } if (m > 0) { - lean_assert(m_qsol.constraint_stack_size() >= initial_stack_size); + lp_assert(m_qsol.constraint_stack_size() >= initial_stack_size); m_qsol.pop(m_qsol.constraint_stack_size() - initial_stack_size); for (auto j : m_x) add_constraint_to_qsol(j); @@ -73,7 +73,7 @@ void quick_xplain::minimize(const vector& u) { void quick_xplain::run(vector> & explanation, const lar_solver & ls){ if (explanation.size() <= 2) return; lar_solver qsol; - lean_assert(ls.explanation_is_correct(explanation)); + lp_assert(ls.explanation_is_correct(explanation)); quick_xplain q(explanation, ls, qsol); q.solve(); } @@ -109,7 +109,7 @@ bool quick_xplain::x_is_minimal() const { x.push_back(j); for (unsigned k = 0; k < x.size(); k++) { - lean_assert(is_feasible(x, x[k])); + lp_assert(is_feasible(x, x[k])); } return true; } @@ -117,7 +117,7 @@ bool quick_xplain::x_is_minimal() const { void quick_xplain::solve() { copy_constraints_to_local_constraints(); m_qsol.push(); - lean_assert(m_qsol.constraint_count() == 0) + lp_assert(m_qsol.constraint_count() == 0) vector u; for (unsigned k = 0; k < m_constraints_in_local_vars.size(); k++) u.push_back(k); @@ -127,10 +127,10 @@ void quick_xplain::solve() { for (unsigned i : m_x) add_constraint_to_qsol(i); m_qsol.solve(); - lean_assert(m_qsol.get_status() == INFEASIBLE); + lp_assert(m_qsol.get_status() == INFEASIBLE); m_qsol.get_infeasibility_explanation(m_explanation); - lean_assert(m_qsol.explanation_is_correct(m_explanation)); - lean_assert(x_is_minimal()); + lp_assert(m_qsol.explanation_is_correct(m_explanation)); + lp_assert(x_is_minimal()); for (auto & p : m_explanation) { p.second = this->m_local_constraint_offset_to_external_ci[m_local_ci_to_constraint_offsets[p.second]]; } diff --git a/src/util/lp/quick_xplain.h b/src/util/lp/quick_xplain.h index 9faa5f41c..952199f85 100644 --- a/src/util/lp/quick_xplain.h +++ b/src/util/lp/quick_xplain.h @@ -7,7 +7,7 @@ Author: Lev Nachmanson #include "util/vector.h" #include -namespace lean { +namespace lp { class lar_solver; // forward definition class quick_xplain { diff --git a/src/util/lp/random_updater.h b/src/util/lp/random_updater.h index 8cb9740ea..68b14c971 100644 --- a/src/util/lp/random_updater.h +++ b/src/util/lp/random_updater.h @@ -12,7 +12,7 @@ Author: Lev Nachmanson #include "util/lp/linear_combination_iterator.h" // see http://research.microsoft.com/projects/z3/smt07.pdf // The class searches for a feasible solution with as many different values of variables as it can find -namespace lean { +namespace lp { template struct numeric_pair; // forward definition class lar_core_solver; // forward definition class random_updater { diff --git a/src/util/lp/random_updater.hpp b/src/util/lp/random_updater.hpp index 7c6a0539f..ced6a3767 100644 --- a/src/util/lp/random_updater.hpp +++ b/src/util/lp/random_updater.hpp @@ -6,7 +6,7 @@ #include "util/lp/static_matrix.h" #include "util/lp/lar_solver.h" #include "util/vector.h" -namespace lean { +namespace lp { @@ -36,7 +36,7 @@ random_updater::interval random_updater::get_interval_of_non_basic_var(unsigned ret.set_upper_bound(m_core_solver.m_r_upper_bounds[j]); break; default: - lean_assert(false); + lp_assert(false); } return ret; } @@ -44,15 +44,15 @@ random_updater::interval random_updater::get_interval_of_non_basic_var(unsigned void random_updater::diminish_interval_for_basic_var(numeric_pair& nb_x, unsigned j, mpq & a, interval & r) { - lean_assert(m_core_solver.m_r_heading[j] >= 0); + lp_assert(m_core_solver.m_r_heading[j] >= 0); numeric_pair delta; - lean_assert(a != zero_of_type()); + lp_assert(a != zero_of_type()); switch (m_core_solver.get_column_type(j)) { case column_type::free_column: break; case column_type::low_bound: delta = m_core_solver.m_r_x[j] - m_core_solver.m_r_low_bounds[j]; - lean_assert(delta >= zero_of_type>()); + lp_assert(delta >= zero_of_type>()); if (a > 0) { r.set_upper_bound(nb_x + delta / a); } else { @@ -61,7 +61,7 @@ void random_updater::diminish_interval_for_basic_var(numeric_pair& nb_x, un break; case column_type::upper_bound: delta = m_core_solver.m_r_upper_bounds()[j] - m_core_solver.m_r_x[j]; - lean_assert(delta >= zero_of_type>()); + lp_assert(delta >= zero_of_type>()); if (a > 0) { r.set_low_bound(nb_x - delta / a); } else { @@ -71,17 +71,17 @@ void random_updater::diminish_interval_for_basic_var(numeric_pair& nb_x, un case column_type::boxed: if (a > 0) { delta = m_core_solver.m_r_x[j] - m_core_solver.m_r_low_bounds[j]; - lean_assert(delta >= zero_of_type>()); + lp_assert(delta >= zero_of_type>()); r.set_upper_bound(nb_x + delta / a); delta = m_core_solver.m_r_upper_bounds()[j] - m_core_solver.m_r_x[j]; - lean_assert(delta >= zero_of_type>()); + lp_assert(delta >= zero_of_type>()); r.set_low_bound(nb_x - delta / a); } else { // a < 0 delta = m_core_solver.m_r_upper_bounds()[j] - m_core_solver.m_r_x[j]; - lean_assert(delta >= zero_of_type>()); + lp_assert(delta >= zero_of_type>()); r.set_upper_bound(nb_x - delta / a); delta = m_core_solver.m_r_x[j] - m_core_solver.m_r_low_bounds[j]; - lean_assert(delta >= zero_of_type>()); + lp_assert(delta >= zero_of_type>()); r.set_low_bound(nb_x + delta / a); } break; @@ -90,7 +90,7 @@ void random_updater::diminish_interval_for_basic_var(numeric_pair& nb_x, un r.set_upper_bound(nb_x); break; default: - lean_assert(false); + lp_assert(false); } } @@ -113,15 +113,15 @@ random_updater::interval random_updater::find_shift_interval(unsigned j) { } void random_updater::shift_var(unsigned j, interval & r) { - lean_assert(r.contains(m_core_solver.m_r_x[j])); - lean_assert(m_core_solver.m_r_solver.column_is_feasible(j)); + lp_assert(r.contains(m_core_solver.m_r_x[j])); + lp_assert(m_core_solver.m_r_solver.column_is_feasible(j)); auto old_x = m_core_solver.m_r_x[j]; remove_value(old_x); auto new_val = m_core_solver.m_r_x[j] = get_random_from_interval(r); add_value(new_val); - lean_assert(r.contains(m_core_solver.m_r_x[j])); - lean_assert(m_core_solver.m_r_solver.column_is_feasible(j)); + lp_assert(r.contains(m_core_solver.m_r_x[j])); + lp_assert(m_core_solver.m_r_solver.column_is_feasible(j)); auto delta = m_core_solver.m_r_x[j] - old_x; unsigned i; @@ -130,9 +130,9 @@ void random_updater::shift_var(unsigned j, interval & r) { while(m_column_j->next(a, i)) { unsigned bj = m_core_solver.m_r_basis[i]; m_core_solver.m_r_x[bj] -= a * delta; - lean_assert(m_core_solver.m_r_solver.column_is_feasible(bj)); + lp_assert(m_core_solver.m_r_solver.column_is_feasible(bj)); } - lean_assert(m_core_solver.m_r_solver.A_mult_x_is_off() == false); + lp_assert(m_core_solver.m_r_solver.A_mult_x_is_off() == false); } numeric_pair random_updater::get_random_from_interval(interval & r) { @@ -143,7 +143,7 @@ numeric_pair random_updater::get_random_from_interval(interval & r) { return r.low_bound + numeric_pair(rand % range, 0); if ((!r.low_bound_is_set) && r.upper_bound_is_set) return r.upper_bound - numeric_pair(rand % range, 0); - lean_assert(r.low_bound_is_set && r.upper_bound_is_set); + lp_assert(r.low_bound_is_set && r.upper_bound_is_set); return r.low_bound + (rand % range) * (r.upper_bound - r.low_bound)/ range; } @@ -183,7 +183,7 @@ void random_updater::add_value(numeric_pair& v) { void random_updater::remove_value(numeric_pair& v) { std::unordered_map, unsigned>::iterator it = m_values.find(v); - lean_assert(it != m_values.end()); + lp_assert(it != m_values.end()); it->second--; if (it->second == 0) m_values.erase((std::unordered_map, unsigned>::const_iterator)it); diff --git a/src/util/lp/row_eta_matrix.h b/src/util/lp/row_eta_matrix.h index 90acb89f3..60adb23ae 100644 --- a/src/util/lp/row_eta_matrix.h +++ b/src/util/lp/row_eta_matrix.h @@ -10,7 +10,7 @@ #include "util/lp/sparse_vector.h" #include "util/lp/indexed_vector.h" #include "util/lp/permutation_matrix.h" -namespace lean { +namespace lp { // This is the sum of a unit matrix and a lower triangular matrix // with non-zero elements only in one row template @@ -55,7 +55,7 @@ public: } void push_back(unsigned row_index, T val ) { - lean_assert(row_index != m_row); + lp_assert(row_index != m_row); m_row_vector.push_back(row_index, val); } diff --git a/src/util/lp/row_eta_matrix.hpp b/src/util/lp/row_eta_matrix.hpp index 5758abeb8..11f8f4913 100644 --- a/src/util/lp/row_eta_matrix.hpp +++ b/src/util/lp/row_eta_matrix.hpp @@ -4,7 +4,7 @@ */ #include "util/vector.h" #include "util/lp/row_eta_matrix.h" -namespace lean { +namespace lp { template void row_eta_matrix::apply_from_left(vector & w, lp_settings &) { // #ifdef LEAN_DEBUG @@ -19,7 +19,7 @@ void row_eta_matrix::apply_from_left(vector & w, lp_settings &) { } // w[m_row] = w_at_row; // #ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(clone_w, w, m_dimension)); + // lp_assert(vectors_are_equal(clone_w, w, m_dimension)); // delete [] clone_w; // #endif } @@ -43,7 +43,7 @@ void row_eta_matrix::apply_from_left_local_to_T(indexed_vector & w, lp_ auto it = std::find(w.m_index.begin(), w.m_index.end(), m_row); w.m_index.erase(it); } - // TBD: lean_assert(check_vector_for_small_values(w, settings)); + // TBD: lp_assert(check_vector_for_small_values(w, settings)); } template @@ -65,7 +65,7 @@ void row_eta_matrix::apply_from_left_local_to_X(indexed_vector & w, lp_ auto it = std::find(w.m_index.begin(), w.m_index.end(), m_row); w.m_index.erase(it); } - // TBD: does not compile lean_assert(check_vector_for_small_values(w, settings)); + // TBD: does not compile lp_assert(check_vector_for_small_values(w, settings)); } template @@ -81,14 +81,14 @@ void row_eta_matrix::apply_from_right(vector & w) { w[it.first] += w_row * it.second; } #ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(clone_w, w, m_dimension)); + // lp_assert(vectors_are_equal(clone_w, w, m_dimension)); // delete clone_w; #endif } template void row_eta_matrix::apply_from_right(indexed_vector & w) { - lean_assert(w.is_OK()); + lp_assert(w.is_OK()); const T & w_row = w[m_row]; if (numeric_traits::is_zero(w_row)) return; #ifdef LEAN_DEBUG @@ -130,7 +130,7 @@ void row_eta_matrix::apply_from_right(indexed_vector & w) { } } #ifdef LEAN_DEBUG - // lean_assert(vectors_are_equal(wcopy, w.m_data)); + // lp_assert(vectors_are_equal(wcopy, w.m_data)); #endif } @@ -151,7 +151,7 @@ void row_eta_matrix::conjugate_by_permutation(permutation_matrix & p for (unsigned i = static_cast(columns.size()); i-- > 0;) m_row_vector.m_data[i].first = p.get_rev(columns[i]); #ifdef LEAN_DEBUG - // lean_assert(deb == *this); + // lp_assert(deb == *this); #endif } #ifdef LEAN_DEBUG diff --git a/src/util/lp/row_eta_matrix_instances.cpp b/src/util/lp/row_eta_matrix_instances.cpp index c32023164..7ccedf844 100644 --- a/src/util/lp/row_eta_matrix_instances.cpp +++ b/src/util/lp/row_eta_matrix_instances.cpp @@ -6,7 +6,7 @@ #include #include "util/lp/row_eta_matrix.hpp" #include "util/lp/lu.h" -namespace lean { +namespace lp { template void row_eta_matrix::conjugate_by_permutation(permutation_matrix&); template void row_eta_matrix >::conjugate_by_permutation(permutation_matrix >&); template void row_eta_matrix::conjugate_by_permutation(permutation_matrix&); diff --git a/src/util/lp/scaler.h b/src/util/lp/scaler.h index 33c5a6cc4..61869f082 100644 --- a/src/util/lp/scaler.h +++ b/src/util/lp/scaler.h @@ -11,7 +11,7 @@ #include /* exit, EXIT_FAILURE */ #include "util/lp/lp_utils.h" #include "util/lp/static_matrix.h" -namespace lean { +namespace lp { // for scaling an LP template class scaler { @@ -31,7 +31,7 @@ public: m_scaling_maximum(scaling_maximum), m_column_scale(column_scale), m_settings(settings) { - lean_assert(m_column_scale.size() == 0); + lp_assert(m_column_scale.size() == 0); m_column_scale.resize(m_A.column_count(), numeric_traits::one()); } diff --git a/src/util/lp/scaler.hpp b/src/util/lp/scaler.hpp index 69427eea0..482441d7f 100644 --- a/src/util/lp/scaler.hpp +++ b/src/util/lp/scaler.hpp @@ -5,7 +5,7 @@ #include #include "util/lp/scaler.h" #include "util/lp/numeric_pair.h" -namespace lean { +namespace lp { // for scaling an LP template T scaler::right_side_balance() { T ret = zero_of_type(); @@ -41,7 +41,7 @@ template T scaler::A_max() const { template T scaler::get_A_ratio() const { T min = A_min(); T max = A_max(); - lean_assert(!m_settings.abs_val_is_smaller_than_zero_tolerance(min)); + lp_assert(!m_settings.abs_val_is_smaller_than_zero_tolerance(min)); T ratio = max / min; return ratio; } @@ -51,7 +51,7 @@ template T scaler::get_max_ratio_on_rows() con unsigned i = m_A.row_count(); while (i--) { T den = m_A.get_min_abs_in_row(i); - lean_assert(!m_settings.abs_val_is_smaller_than_zero_tolerance(den)); + lp_assert(!m_settings.abs_val_is_smaller_than_zero_tolerance(den)); T t = m_A.get_max_abs_in_row(i)/ den; if (t > ret) ret = t; @@ -78,7 +78,7 @@ template void scaler::scale_rows_with_geometri while (i--) { T max = m_A.get_max_abs_in_row(i); T min = m_A.get_min_abs_in_row(i); - lean_assert(max > zero_of_type() && min > zero_of_type()); + lp_assert(max > zero_of_type() && min > zero_of_type()); if (is_zero(max) || is_zero(min)) continue; T gm = T(sqrt(numeric_traits::get_double(max*min))); diff --git a/src/util/lp/scaler_instances.cpp b/src/util/lp/scaler_instances.cpp index f97e8098f..de1c2b7aa 100644 --- a/src/util/lp/scaler_instances.cpp +++ b/src/util/lp/scaler_instances.cpp @@ -3,5 +3,5 @@ Author: Lev Nachmanson */ #include "util/lp/scaler.hpp" -template bool lean::scaler::scale(); -template bool lean::scaler::scale(); +template bool lp::scaler::scale(); +template bool lp::scaler::scale(); diff --git a/src/util/lp/signature_bound_evidence.h b/src/util/lp/signature_bound_evidence.h index a22c188b4..6a0b4115f 100644 --- a/src/util/lp/signature_bound_evidence.h +++ b/src/util/lp/signature_bound_evidence.h @@ -5,7 +5,7 @@ #pragma once #include "util/lp/lp_settings.h" #include "util/lp/lar_constraints.h" -namespace lean { +namespace lp { struct bound_signature { unsigned m_i; bool m_at_low; diff --git a/src/util/lp/sparse_matrix.h b/src/util/lp/sparse_matrix.h index 7256004da..0fc84f8f5 100644 --- a/src/util/lp/sparse_matrix.h +++ b/src/util/lp/sparse_matrix.h @@ -21,7 +21,7 @@ #include "util/lp/binary_heap_upair_queue.h" #include "util/lp/numeric_pair.h" #include "util/lp/int_set.h" -namespace lean { +namespace lp { // it is a square matrix template class sparse_matrix @@ -190,13 +190,13 @@ public: // set the max val as well // returns false if the resulting row is all zeroes, and true otherwise - bool set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, + bool set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, lp_settings & settings); // set the max val as well // returns false if the resulting row is all zeroes, and true otherwise - bool set_row_from_work_vector_and_clean_work_vector(unsigned i0); + bool set_row_from_work_vector_and_clp_work_vector(unsigned i0); void remove_zero_elements_and_set_data_on_existing_elements(unsigned row); @@ -206,19 +206,19 @@ public: void multiply_from_right(permutation_matrix& p) { // m_dense = m_dense * p; m_column_permutation.multiply_by_permutation_from_right(p); - // lean_assert(*this == m_dense); + // lp_assert(*this == m_dense); } void multiply_from_left(permutation_matrix& p) { // m_dense = p * m_dense; m_row_permutation.multiply_by_permutation_from_left(p); - // lean_assert(*this == m_dense); + // lp_assert(*this == m_dense); } void multiply_from_left_with_reverse(permutation_matrix& p) { // m_dense = p * m_dense; m_row_permutation.multiply_by_permutation_reverse_from_left(p); - // lean_assert(*this == m_dense); + // lp_assert(*this == m_dense); } // adding delta columns at the end of the matrix @@ -231,13 +231,13 @@ public: // dense_matrix d(*this); m_column_permutation.transpose_from_left(a, b); // d.swap_columns(a, b); - // lean_assert(*this == d); + // lp_assert(*this == d); } void swap_rows(unsigned a, unsigned b) { m_row_permutation.transpose_from_right(a, b); // m_dense.swap_rows(a, b); - // lean_assert(*this == m_dense); + // lp_assert(*this == m_dense); } void divide_row_by_constant(unsigned i, const T & t, lp_settings & settings); @@ -393,7 +393,7 @@ public: void process_index_recursively_for_y_U(unsigned j, vector & sorted_rows); void resize(unsigned new_dim) { unsigned old_dim = dimension(); - lean_assert(new_dim >= old_dim); + lp_assert(new_dim >= old_dim); for (unsigned j = old_dim; j < new_dim; j++) { m_rows.push_back(vector>()); m_columns.push_back(col_header()); diff --git a/src/util/lp/sparse_matrix.hpp b/src/util/lp/sparse_matrix.hpp index 32bb8ed4e..175633eda 100644 --- a/src/util/lp/sparse_matrix.hpp +++ b/src/util/lp/sparse_matrix.hpp @@ -7,7 +7,7 @@ #include "util/lp/sparse_matrix.h" #include #include -namespace lean { +namespace lp { template void sparse_matrix::copy_column_from_static_matrix(unsigned col, static_matrix const &A, unsigned col_index_in_the_new_matrix) { vector const & A_col_vector = A.m_columns[col]; @@ -82,12 +82,12 @@ void sparse_matrix::set_with_no_adjusting(unsigned row, unsigned col, T va template void sparse_matrix::set(unsigned row, unsigned col, T val) { // should not be used in efficient code - lean_assert(row < dimension() && col < dimension()); + lp_assert(row < dimension() && col < dimension()); // m_dense.set_elem(row, col, val); row = adjust_row(row); col = adjust_column(col); set_with_no_adjusting(row, col, val); - // lean_assert(*this == m_dense); + // lp_assert(*this == m_dense); } template @@ -261,8 +261,8 @@ vector sparse_matrix::get_full_row(unsigned i) const { // Returns false if the resulting row is all zeroes, and true otherwise template bool sparse_matrix::pivot_row_to_row(unsigned i, const T& alpha, unsigned i0, lp_settings & settings ) { - lean_assert(i < dimension() && i0 < dimension()); - lean_assert(i != i0); + lp_assert(i < dimension() && i0 < dimension()); + lp_assert(i != i0); unsigned pivot_col = adjust_column(i); i = adjust_row(i); i0 = adjust_row(i0); @@ -296,7 +296,7 @@ bool sparse_matrix::pivot_row_to_row(unsigned i, const T& alpha, unsigned } - // clean the work vector + // clp the work vector for (unsigned k = 0; k < prev_size_i0; k++) { m_work_pivot_vector[i0_row_vals[k].m_index] = -1; } @@ -319,7 +319,7 @@ bool sparse_matrix::pivot_row_to_row(unsigned i, const T& alpha, unsigned // set the max val as well // returns false if the resulting row is all zeroes, and true otherwise template -bool sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, +bool sparse_matrix::set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, lp_settings & settings) { remove_zero_elements_and_set_data_on_existing_elements_not_adjusted(i0, work_vec, settings); // all non-zero elements in m_work_pivot_vector are new @@ -327,7 +327,7 @@ bool sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adj if (numeric_traits::is_zero(work_vec[j])) { continue; } - lean_assert(!settings.abs_val_is_smaller_than_drop_tolerance(work_vec[j])); + lp_assert(!settings.abs_val_is_smaller_than_drop_tolerance(work_vec[j])); add_new_element(i0, adjust_column(j), work_vec[j]); work_vec[j] = numeric_traits::zero(); } @@ -372,7 +372,7 @@ void sparse_matrix::remove_zero_elements_and_set_data_on_existing_elements T val = work_vec[rj]; if (settings.abs_val_is_smaller_than_drop_tolerance(val)) { remove_element(row_vals, row_el_iv); - lean_assert(numeric_traits::is_zero(val)); + lp_assert(numeric_traits::is_zero(val)); } else { m_columns[j].m_values[row_el_iv.m_other].set_value(row_el_iv.m_value = val); work_vec[rj] = numeric_traits::zero(); @@ -393,7 +393,7 @@ void sparse_matrix::add_columns_at_the_end(unsigned delta) { template void sparse_matrix::delete_column(int i) { - lean_assert(i < dimension()); + lp_assert(i < dimension()); for (auto cell = m_columns[i].m_head; cell != nullptr;) { auto next_cell = cell->m_down; kill_cell(cell); @@ -403,7 +403,7 @@ void sparse_matrix::delete_column(int i) { template void sparse_matrix::divide_row_by_constant(unsigned i, const T & t, lp_settings & settings) { - lean_assert(!settings.abs_val_is_smaller_than_zero_tolerance(t)); + lp_assert(!settings.abs_val_is_smaller_than_zero_tolerance(t)); i = adjust_row(i); for (auto & iv : m_rows[i]) { T &v = iv.m_value; @@ -440,7 +440,7 @@ void sparse_matrix::solve_y_U(vector & y) const { // works by rows // dense_matrix deb(*this); // T * clone_y = clone_vector(y, dimension()); // deb.apply_from_right(clone_y); - // lean_assert(vectors_are_equal(rs, clone_y, dimension())); + // lp_assert(vectors_are_equal(rs, clone_y, dimension())); // delete [] clone_y; // delete [] rs; #endif @@ -474,10 +474,10 @@ void sparse_matrix::solve_y_U_indexed(indexed_vector & y, const lp_sett y.m_data[j] = zero_of_type(); } - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); #if 0 && LEAN_DEBUG if (numeric_traits::precise() == false) - lean_assert(vectors_are_equal(ycopy, y.m_data)); + lp_assert(vectors_are_equal(ycopy, y.m_data)); #endif } @@ -537,8 +537,8 @@ void sparse_matrix::add_delta_to_solution(const vector& del, vector template template void sparse_matrix::add_delta_to_solution(const indexed_vector& del, indexed_vector & y) { -// lean_assert(del.is_OK()); - // lean_assert(y.is_OK()); +// lp_assert(del.is_OK()); + // lp_assert(y.is_OK()); for (auto i : del.m_index) { y.add_value_at_index(i, del[i]); } @@ -546,24 +546,24 @@ void sparse_matrix::add_delta_to_solution(const indexed_vector& del, in template template void sparse_matrix::double_solve_U_y(indexed_vector& y, const lp_settings & settings){ - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); indexed_vector y_orig(y); // copy y aside vector active_rows; solve_U_y_indexed_only(y, settings, active_rows); - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); find_error_in_solution_U_y_indexed(y_orig, y, active_rows); // y_orig contains the error now if (y_orig.m_index.size() * ratio_of_index_size_to_all_size() < 32 * dimension()) { active_rows.clear(); solve_U_y_indexed_only(y_orig, settings, active_rows); add_delta_to_solution(y_orig, y); - y.clean_up(); + y.clp_up(); } else { // the dense version solve_U_y(y_orig.m_data); add_delta_to_solution(y_orig.m_data, y.m_data); - y.restore_index_and_clean_from_data(); + y.restore_index_and_clp_from_data(); } - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); } template template @@ -599,12 +599,12 @@ void sparse_matrix::solve_U_y(vector & y) { // it is a column wise vers // dense_matrix deb(*this); // T * clone_y = clone_vector(y, dimension()); // deb.apply_from_left(clone_y); - // lean_assert(vectors_are_equal(rs, clone_y, dimension())); + // lp_assert(vectors_are_equal(rs, clone_y, dimension())); #endif } template void sparse_matrix::process_index_recursively_for_y_U(unsigned j, vector & sorted_active_rows) { - lean_assert(m_processed[j] == false); + lp_assert(m_processed[j] == false); m_processed[j]=true; auto & row = m_rows[adjust_row(j)]; for (auto & c : row) { @@ -619,7 +619,7 @@ void sparse_matrix::process_index_recursively_for_y_U(unsigned j, vector void sparse_matrix::process_column_recursively(unsigned j, vector & sorted_active_rows) { - lean_assert(m_processed[j] == false); + lp_assert(m_processed[j] == false); auto & mc = m_columns[adjust_column(j)].m_values; for (auto & iv : mc) { unsigned i = adjust_row_inverse(iv.m_index); @@ -684,12 +684,12 @@ void sparse_matrix::solve_U_y_indexed_only(indexed_vector & y, const lp y[j] = zero_of_type(); } - lean_assert(y.is_OK()); + lp_assert(y.is_OK()); #ifdef LEAN_DEBUG // dense_matrix deb(this); // vector clone_y(y.m_data); // deb.apply_from_left(clone_y); - // lean_assert(vectors_are_equal(rs, clone_y)); + // lp_assert(vectors_are_equal(rs, clone_y)); #endif } @@ -802,7 +802,7 @@ void sparse_matrix::add_new_elements_of_w_and_clear_w(unsigned column_to_r unsigned ai = adjust_row(i); add_new_element(ai, column_to_replace, w_at_i); auto & row_chunk = m_rows[ai]; - lean_assert(row_chunk.size() > 0); + lp_assert(row_chunk.size() > 0); if (abs(w_at_i) > abs(row_chunk[0].m_value)) put_max_index_to_0(row_chunk, static_cast(row_chunk.size()) - 1); } @@ -833,7 +833,7 @@ unsigned sparse_matrix::pivot_score(unsigned i, unsigned j) { template void sparse_matrix::enqueue_domain_into_pivot_queue() { - lean_assert(m_pivot_queue.size() == 0); + lp_assert(m_pivot_queue.size() == 0); for (unsigned i = 0; i < dimension(); i++) { auto & rh = m_rows[i]; unsigned rnz = static_cast(rh.size()); @@ -919,7 +919,7 @@ void sparse_matrix::update_active_pivots(unsigned row) { for (const auto & iv : m_rows[arow]) { col_header & ch = m_columns[iv.m_index]; int cols = static_cast(ch.m_values.size()) - ch.m_shortened_markovitz - 1; - lean_assert(cols >= 0); + lp_assert(cols >= 0); for (const auto &ivc : ch.m_values) { unsigned i = ivc.m_index; if (adjust_row_inverse(i) <= row) continue; // the i is not an active row @@ -945,7 +945,7 @@ bool sparse_matrix::shorten_active_matrix(unsigned row, eta_matrix * for (auto & iv : row_values) { const col_header& ch = m_columns[iv.m_index]; int cnz = static_cast(ch.m_values.size()) - ch.m_shortened_markovitz - 1; - lean_assert(cnz >= 0); + lp_assert(cnz >= 0); m_pivot_queue.enqueue(row, iv.m_index, rnz * cnz); } } @@ -961,7 +961,7 @@ unsigned sparse_matrix::pivot_score_without_shortened_counters(unsigned i, if (adjust_row_inverse(iv.m_index) < k) cnz--; } - lean_assert(cnz > 0); + lp_assert(cnz > 0); return m_rows[i].m_values.size() * (cnz - 1); } #ifdef LEAN_DEBUG @@ -971,15 +971,15 @@ bool sparse_matrix::can_improve_score_for_row(unsigned row, unsigned score auto & row_vals = m_rows[arow].m_values; auto & begin_iv = row_vals[0]; T row_max = abs(begin_iv.m_value); - lean_assert(adjust_column_inverse(begin_iv.m_index) >= k); + lp_assert(adjust_column_inverse(begin_iv.m_index) >= k); if (pivot_score_without_shortened_counters(arow, begin_iv.m_index, k) < score) { print_active_matrix(k); return true; } for (unsigned jj = 1; jj < row_vals.size(); jj++) { auto & iv = row_vals[jj]; - lean_assert(adjust_column_inverse(iv.m_index) >= k); - lean_assert(abs(iv.m_value) <= row_max); + lp_assert(adjust_column_inverse(iv.m_index) >= k); + lp_assert(abs(iv.m_value) <= row_max); if (c_partial_pivoting * abs(iv.m_value) < row_max) continue; if (pivot_score_without_shortened_counters(arow, iv.m_index, k) < score) { print_active_matrix(k); @@ -993,7 +993,7 @@ template bool sparse_matrix::really_best_pivot(unsigned i, unsigned j, T const & c_partial_pivoting, unsigned k) { unsigned queue_pivot_score = pivot_score_without_shortened_counters(i, j, k); for (unsigned ii = k; ii < dimension(); ii++) { - lean_assert(!can_improve_score_for_row(ii, queue_pivot_score, c_partial_pivoting, k)); + lp_assert(!can_improve_score_for_row(ii, queue_pivot_score, c_partial_pivoting, k)); } return true; } @@ -1026,7 +1026,7 @@ template bool sparse_matrix::pivot_queue_is_correct_for_row(unsigned i, unsigned k) { unsigned arow = adjust_row(i); for (auto & iv : m_rows[arow].m_values) { - lean_assert(pivot_score_without_shortened_counters(arow, iv.m_index, k + 1) == + lp_assert(pivot_score_without_shortened_counters(arow, iv.m_index, k + 1) == m_pivot_queue.get_priority(arow, iv.m_index)); } return true; @@ -1035,8 +1035,8 @@ bool sparse_matrix::pivot_queue_is_correct_for_row(unsigned i, unsigned k) template bool sparse_matrix::pivot_queue_is_correct_after_pivoting(int k) { for (unsigned i = k + 1; i < dimension(); i++ ) - lean_assert(pivot_queue_is_correct_for_row(i, k)); - lean_assert(m_pivot_queue.is_correct()); + lp_assert(pivot_queue_is_correct_for_row(i, k)); + lp_assert(m_pivot_queue.is_correct()); return true; } #endif @@ -1055,7 +1055,7 @@ bool sparse_matrix::get_pivot_for_column(unsigned &i, unsigned &j, int c_p #ifdef LEAN_DEBUG // if (!really_best_pivot(i, j, c_partial_pivoting, k)) { // print_active_matrix(k); - // lean_assert(false); + // lp_assert(false); // } #endif recover_pivot_queue(pivots_candidates_that_are_too_small); @@ -1088,7 +1088,7 @@ bool sparse_matrix::shorten_columns_by_pivot_row(unsigned i, unsigned pivo for (indexed_value & iv : row_chunk) { unsigned j = iv.m_index; if (j == pivot_column) { - lean_assert(!col_is_active(j)); + lp_assert(!col_is_active(j)); continue; } m_columns[j].shorten_markovich_by_one(); @@ -1151,11 +1151,11 @@ template bool sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings & settings) const { for (unsigned i = 0; i < dimension(); i++) { vector> const & row_chunk = get_row_values(i); - lean_assert(row_chunk.size()); + lp_assert(row_chunk.size()); T const & max = abs(row_chunk[0].m_value); unsigned ai = adjust_row_inverse(i); for (auto & iv : row_chunk) { - lean_assert(abs(iv.m_value) <= max); + lp_assert(abs(iv.m_value) <= max); unsigned aj = adjust_column_inverse(iv.m_index); if (!(ai <= aj || numeric_traits::is_zero(iv.m_value))) return false; @@ -1193,18 +1193,18 @@ void sparse_matrix::check_column_vs_rows(unsigned col) { indexed_value & row_iv = column_iv_other(column_iv); if (row_iv.m_index != col) { // std::cout << "m_other in row does not belong to column " << col << ", but to column " << row_iv.m_index << std::endl; - lean_assert(false); + lp_assert(false); } if (& row_iv_other(row_iv) != &column_iv) { // std::cout << "row and col do not point to each other" << std::endl; - lean_assert(false); + lp_assert(false); } if (row_iv.m_value != column_iv.m_value) { // std::cout << "the data from col " << col << " for row " << column_iv.m_index << " is different in the column " << std::endl; // std::cout << "in the col it is " << column_iv.m_value << ", but in the row it is " << row_iv.m_value << std::endl; - lean_assert(false); + lp_assert(false); } } } @@ -1217,18 +1217,18 @@ void sparse_matrix::check_row_vs_columns(unsigned row) { if (column_iv.m_index != row) { // std::cout << "col_iv does not point to correct row " << row << " but to " << column_iv.m_index << std::endl; - lean_assert(false); + lp_assert(false); } if (& row_iv != & column_iv_other(column_iv)) { // std::cout << "row and col do not point to each other" << std::endl; - lean_assert(false); + lp_assert(false); } if (row_iv.m_value != column_iv.m_value) { // std::cout << "the data from col " << column_iv.m_index << " for row " << row << " is different in the column " << std::endl; // std::cout << "in the col it is " << column_iv.m_value << ", but in the row it is " << row_iv.m_value << std::endl; - lean_assert(false); + lp_assert(false); } } } diff --git a/src/util/lp/sparse_matrix_instances.cpp b/src/util/lp/sparse_matrix_instances.cpp index c06fcbf05..cf859a6a2 100644 --- a/src/util/lp/sparse_matrix_instances.cpp +++ b/src/util/lp/sparse_matrix_instances.cpp @@ -8,7 +8,7 @@ #include "util/lp/lu.h" #include "util/lp/sparse_matrix.hpp" #include "util/lp/dense_matrix.h" -namespace lean { +namespace lp { template double sparse_matrix::dot_product_with_row(unsigned int, vector const&) const; template void sparse_matrix::add_new_element(unsigned int, unsigned int, const double&); template void sparse_matrix::divide_row_by_constant(unsigned int, const double&, lp_settings&); @@ -24,7 +24,7 @@ template void sparse_matrix::remove_element(vector::replace_column(unsigned int, indexed_vector&, lp_settings&); template void sparse_matrix::set(unsigned int, unsigned int, double); template void sparse_matrix::set_max_in_row(vector >&); -template bool sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); +template bool sparse_matrix::set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); template bool sparse_matrix::shorten_active_matrix(unsigned int, eta_matrix*); template void sparse_matrix::solve_y_U(vector&) const; template sparse_matrix::sparse_matrix(static_matrix const&, vector&); @@ -41,7 +41,7 @@ template void sparse_matrix::prepare_for_factorization(); template void sparse_matrix::remove_element(vector> &, indexed_value&); template void sparse_matrix::replace_column(unsigned int, indexed_vector&, lp_settings&); template void sparse_matrix::set_max_in_row(vector>&); -template bool sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); +template bool sparse_matrix::set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); template bool sparse_matrix::shorten_active_matrix(unsigned int, eta_matrix*); template void sparse_matrix::solve_y_U(vector&) const; template sparse_matrix::sparse_matrix(static_matrix const&, vector&); @@ -57,7 +57,7 @@ template void sparse_matrix>::prepare_for_factorizati template void sparse_matrix>::remove_element(vector>&, indexed_value&); template void sparse_matrix>::replace_column(unsigned int, indexed_vector&, lp_settings&); template void sparse_matrix>::set_max_in_row(vector>&); -template bool sparse_matrix>::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); +template bool sparse_matrix>::set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); template bool sparse_matrix>::shorten_active_matrix(unsigned int, eta_matrix >*); template void sparse_matrix>::solve_y_U(vector&) const; template sparse_matrix>::sparse_matrix(static_matrix > const&, vector&); @@ -65,37 +65,37 @@ template void sparse_matrix::double_solve_U_y(indexed_ve template void sparse_matrix::double_solve_U_y(indexed_vector&, const lp_settings&); template void sparse_matrix>::double_solve_U_y(indexed_vector&, const lp_settings&); template void sparse_matrix >::double_solve_U_y >(indexed_vector>&, const lp_settings&); -template void lean::sparse_matrix::solve_U_y_indexed_only(lean::indexed_vector&, const lp_settings&, vector &); -template void lean::sparse_matrix::solve_U_y_indexed_only(lean::indexed_vector&, const lp_settings &, vector &); +template void lp::sparse_matrix::solve_U_y_indexed_only(lp::indexed_vector&, const lp_settings&, vector &); +template void lp::sparse_matrix::solve_U_y_indexed_only(lp::indexed_vector&, const lp_settings &, vector &); #ifdef LEAN_DEBUG template bool sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; template bool sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; template bool sparse_matrix >::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; #endif } -template void lean::sparse_matrix >::solve_U_y_indexed_only(lean::indexed_vector&, const lp_settings &, vector &); -template void lean::sparse_matrix::solve_U_y(vector&); -template void lean::sparse_matrix::double_solve_U_y(vector&); -template void lean::sparse_matrix::solve_U_y(vector&); -template void lean::sparse_matrix::double_solve_U_y(vector&); -template void lean::sparse_matrix >::solve_U_y >(vector >&); -template void lean::sparse_matrix >::double_solve_U_y >(vector >&); -template void lean::sparse_matrix::find_error_in_solution_U_y_indexed(lean::indexed_vector&, lean::indexed_vector&, const vector &); -template double lean::sparse_matrix::dot_product_with_row(unsigned int, lean::indexed_vector const&) const; -template void lean::sparse_matrix::find_error_in_solution_U_y_indexed(lean::indexed_vector&, lean::indexed_vector&, const vector &); -template lean::mpq lean::sparse_matrix::dot_product_with_row(unsigned int, lean::indexed_vector const&) const; -template void lean::sparse_matrix >::find_error_in_solution_U_y_indexed(lean::indexed_vector&, lean::indexed_vector&, const vector &); -template lean::mpq lean::sparse_matrix >::dot_product_with_row(unsigned int, lean::indexed_vector const&) const; -template void lean::sparse_matrix >::find_error_in_solution_U_y_indexed >(lean::indexed_vector >&, lean::indexed_vector >&, const vector &); -template lean::numeric_pair lean::sparse_matrix >::dot_product_with_row >(unsigned int, lean::indexed_vector > const&) const; -template void lean::sparse_matrix::extend_and_sort_active_rows(vector const&, vector&); +template void lp::sparse_matrix >::solve_U_y_indexed_only(lp::indexed_vector&, const lp_settings &, vector &); +template void lp::sparse_matrix::solve_U_y(vector&); +template void lp::sparse_matrix::double_solve_U_y(vector&); +template void lp::sparse_matrix::solve_U_y(vector&); +template void lp::sparse_matrix::double_solve_U_y(vector&); +template void lp::sparse_matrix >::solve_U_y >(vector >&); +template void lp::sparse_matrix >::double_solve_U_y >(vector >&); +template void lp::sparse_matrix::find_error_in_solution_U_y_indexed(lp::indexed_vector&, lp::indexed_vector&, const vector &); +template double lp::sparse_matrix::dot_product_with_row(unsigned int, lp::indexed_vector const&) const; +template void lp::sparse_matrix::find_error_in_solution_U_y_indexed(lp::indexed_vector&, lp::indexed_vector&, const vector &); +template lp::mpq lp::sparse_matrix::dot_product_with_row(unsigned int, lp::indexed_vector const&) const; +template void lp::sparse_matrix >::find_error_in_solution_U_y_indexed(lp::indexed_vector&, lp::indexed_vector&, const vector &); +template lp::mpq lp::sparse_matrix >::dot_product_with_row(unsigned int, lp::indexed_vector const&) const; +template void lp::sparse_matrix >::find_error_in_solution_U_y_indexed >(lp::indexed_vector >&, lp::indexed_vector >&, const vector &); +template lp::numeric_pair lp::sparse_matrix >::dot_product_with_row >(unsigned int, lp::indexed_vector > const&) const; +template void lp::sparse_matrix::extend_and_sort_active_rows(vector const&, vector&); -template void lean::sparse_matrix >::extend_and_sort_active_rows(vector const&, vector&); +template void lp::sparse_matrix >::extend_and_sort_active_rows(vector const&, vector&); -template void lean::sparse_matrix >::solve_U_y(vector&); -template void lean::sparse_matrix >::double_solve_U_y(vector&); -template void lean::sparse_matrix< lean::mpq,lean::numeric_pair< lean::mpq> >::set(unsigned int,unsigned int, lean::mpq); -template void lean::sparse_matrix::solve_y_U_indexed(lean::indexed_vector&, const lp_settings & ); -template void lean::sparse_matrix::solve_y_U_indexed(lean::indexed_vector&, const lp_settings &); -template void lean::sparse_matrix >::solve_y_U_indexed(lean::indexed_vector&, const lp_settings &); +template void lp::sparse_matrix >::solve_U_y(vector&); +template void lp::sparse_matrix >::double_solve_U_y(vector&); +template void lp::sparse_matrix< lp::mpq,lp::numeric_pair< lp::mpq> >::set(unsigned int,unsigned int, lp::mpq); +template void lp::sparse_matrix::solve_y_U_indexed(lp::indexed_vector&, const lp_settings & ); +template void lp::sparse_matrix::solve_y_U_indexed(lp::indexed_vector&, const lp_settings &); +template void lp::sparse_matrix >::solve_y_U_indexed(lp::indexed_vector&, const lp_settings &); diff --git a/src/util/lp/sparse_vector.h b/src/util/lp/sparse_vector.h index 975cb7f28..65bd6d3f3 100644 --- a/src/util/lp/sparse_vector.h +++ b/src/util/lp/sparse_vector.h @@ -9,7 +9,7 @@ #include "util/debug.h" #include "util/lp/lp_utils.h" #include "util/lp/lp_settings.h" -namespace lean { +namespace lp { template class sparse_vector { @@ -27,7 +27,7 @@ public: } #endif void divide(T const & a) { - lean_assert(!lp_settings::is_eps_small_general(a, 1e-12)); + lp_assert(!lp_settings::is_eps_small_general(a, 1e-12)); for (auto & t : m_data) { t.second /= a; } } diff --git a/src/util/lp/square_dense_submatrix.h b/src/util/lp/square_dense_submatrix.h index 019497aa5..5ffed7818 100644 --- a/src/util/lp/square_dense_submatrix.h +++ b/src/util/lp/square_dense_submatrix.h @@ -20,7 +20,7 @@ #include "util/lp/eta_matrix.h" #include "util/lp/binary_heap_upair_queue.h" #include "util/lp/sparse_matrix.h" -namespace lean { +namespace lp { template class square_dense_submatrix : public tail_matrix { // the submatrix uses the permutations of the parent matrix to access the elements @@ -30,11 +30,11 @@ class square_dense_submatrix : public tail_matrix { ref(unsigned i, square_dense_submatrix & s) : m_i_offset((i - s.m_index_start) * s.m_dim), m_s(s){} T & operator[] (unsigned j) { - lean_assert(j >= m_s.m_index_start); + lp_assert(j >= m_s.m_index_start); return m_s.m_v[m_i_offset + m_s.adjust_column(j) - m_s.m_index_start]; } const T & operator[] (unsigned j) const { - lean_assert(j >= m_s.m_index_start); + lp_assert(j >= m_s.m_index_start); return m_s.m_v[m_i_offset + m_s.adjust_column(j) - m_s.m_index_start]; } }; @@ -58,8 +58,8 @@ public: bool is_dense() const { return true; } ref operator[] (unsigned i) { - lean_assert(i >= m_index_start); - lean_assert(i < m_parent->dimension()); + lp_assert(i >= m_index_start); + lp_assert(i < m_parent->dimension()); return ref(i, *this); } @@ -148,7 +148,7 @@ public: } } } - lean_assert(wcopy.is_OK()); + lp_assert(wcopy.is_OK()); apply_from_right(w.m_data); w.m_index.clear(); if (numeric_traits::precise()) { @@ -167,11 +167,11 @@ public: } } #else - lean_assert(w.is_OK()); - lean_assert(m_work_vector.is_OK()); + lp_assert(w.is_OK()); + lp_assert(m_work_vector.is_OK()); m_work_vector.resize(w.data_size()); m_work_vector.clear(); - lean_assert(m_work_vector.is_OK()); + lp_assert(m_work_vector.is_OK()); unsigned end = m_index_start + m_dim; for (unsigned k : w.m_index) { // find j such that k = adjust_row_inverse(j) @@ -187,8 +187,8 @@ public: } } } - m_work_vector.clean_up(); - lean_assert(m_work_vector.is_OK()); + m_work_vector.clp_up(); + lp_assert(m_work_vector.is_OK()); w = m_work_vector; #endif } diff --git a/src/util/lp/square_dense_submatrix.hpp b/src/util/lp/square_dense_submatrix.hpp index 365c9d7f0..809d5c5a6 100644 --- a/src/util/lp/square_dense_submatrix.hpp +++ b/src/util/lp/square_dense_submatrix.hpp @@ -4,7 +4,7 @@ */ #include "util/vector.h" #include "util/lp/square_dense_submatrix.h" -namespace lean { +namespace lp { template square_dense_submatrix::square_dense_submatrix (sparse_matrix *parent_matrix, unsigned index_start) : m_index_start(index_start), @@ -18,7 +18,7 @@ square_dense_submatrix::square_dense_submatrix (sparse_matrix *paren unsigned row = parent_matrix->adjust_row(i); for (auto & iv : parent_matrix->get_row_values(row)) { unsigned j = parent_matrix->adjust_column_inverse(iv.m_index); - lean_assert(j>= m_index_start); + lp_assert(j>= m_index_start); m_v[row_offset + j] = iv.m_value; } row_offset += m_dim; @@ -43,7 +43,7 @@ template void square_dense_submatrix::init(sparse template int square_dense_submatrix::find_pivot_column_in_row(unsigned i) const { int j = -1; T max = zero_of_type(); - lean_assert(i >= m_index_start); + lp_assert(i >= m_index_start); unsigned row_start = (i - m_index_start) * m_dim; for (unsigned k = i; k < m_parent->dimension(); k++) { unsigned col = adjust_column(k); // this is where the column is in the row @@ -64,14 +64,14 @@ template void square_dense_submatrix::pivot(un } template void square_dense_submatrix::pivot_row_to_row(unsigned i, unsigned row, lp_settings & settings) { - lean_assert(i < row); + lp_assert(i < row); unsigned pj = adjust_column(i); // the pivot column unsigned pjd = pj - m_index_start; unsigned pivot_row_offset = (i-m_index_start)*m_dim; T pivot = m_v[pivot_row_offset + pjd]; unsigned row_offset= (row-m_index_start)*m_dim; T m = m_v[row_offset + pjd]; - lean_assert(!is_zero(pivot)); + lp_assert(!is_zero(pivot)); m_v[row_offset + pjd] = -m * pivot; // creating L matrix for (unsigned j = m_index_start; j < m_parent->dimension(); j++) { if (j == pj) { @@ -94,7 +94,7 @@ template void square_dense_submatrix::divide_r unsigned pj = adjust_column(i); // the pivot column unsigned irow_offset = (i - m_index_start) * m_dim; T pivot = m_v[irow_offset + pj - m_index_start]; - lean_assert(!is_zero(pivot)); + lp_assert(!is_zero(pivot)); for (unsigned k = m_index_start; k < m_parent->dimension(); k++) { if (k == pj){ m_v[irow_offset++] = one_of_type() / pivot; // creating the L matrix diagonal @@ -158,7 +158,7 @@ template void square_dense_submatrix::push_new template template L square_dense_submatrix::row_by_vector_product(unsigned i, const vector & v) { - lean_assert(i >= m_index_start); + lp_assert(i >= m_index_start); unsigned row_in_subm = i - m_index_start; unsigned row_offset = row_in_subm * m_dim; @@ -171,7 +171,7 @@ L square_dense_submatrix::row_by_vector_product(unsigned i, const vector template L square_dense_submatrix::column_by_vector_product(unsigned j, const vector & v) { - lean_assert(j >= m_index_start); + lp_assert(j >= m_index_start); unsigned offset = j - m_index_start; L r = zero_of_type(); @@ -182,7 +182,7 @@ L square_dense_submatrix::column_by_vector_product(unsigned j, const vecto template template L square_dense_submatrix::row_by_indexed_vector_product(unsigned i, const indexed_vector & v) { - lean_assert(i >= m_index_start); + lp_assert(i >= m_index_start); unsigned row_in_subm = i - m_index_start; unsigned row_offset = row_in_subm * m_dim; @@ -249,8 +249,8 @@ void square_dense_submatrix::apply_from_left_local(indexed_vector & w, #ifdef LEAN_DEBUG // cout << "w final" << endl; // print_vector(w.m_data); - // lean_assert(vectors_are_equal(deb_w, w.m_data)); - // lean_assert(w.is_OK()); + // lp_assert(vectors_are_equal(deb_w, w.m_data)); + // lp_assert(w.is_OK()); #endif } @@ -280,16 +280,16 @@ void square_dense_submatrix::apply_from_left_to_vector(vector & w) { #ifdef LEAN_DEBUG // cout << "w final" << endl; // print_vector(w.m_data); - // lean_assert(vectors_are_equal(deb_w, w)); + // lp_assert(vectors_are_equal(deb_w, w)); #endif } template bool square_dense_submatrix::is_L_matrix() const { #ifdef LEAN_DEBUG - lean_assert(m_row_permutation.is_identity()); + lp_assert(m_row_permutation.is_identity()); for (unsigned i = 0; i < m_parent->dimension(); i++) { if (i < m_index_start) { - lean_assert(m_column_permutation[i] == i); + lp_assert(m_column_permutation[i] == i); continue; } unsigned row_offs = (i-m_index_start)*m_dim; @@ -297,9 +297,9 @@ template bool square_dense_submatrix::is_L_mat unsigned j = m_index_start + k; unsigned jex = adjust_column_inverse(j); if (jex > i) { - lean_assert(is_zero(m_v[row_offs + k])); + lp_assert(is_zero(m_v[row_offs + k])); } else if (jex == i) { - lean_assert(!is_zero(m_v[row_offs + k])); + lp_assert(!is_zero(m_v[row_offs + k])); } } } @@ -327,7 +327,7 @@ template void square_dense_submatrix::apply_from_ } w = t; #ifdef LEAN_DEBUG - // lean_assert(vector_are_equal(deb_w, w)); + // lp_assert(vector_are_equal(deb_w, w)); #endif } diff --git a/src/util/lp/square_dense_submatrix_instances.cpp b/src/util/lp/square_dense_submatrix_instances.cpp index 7d45aaaa1..7283bb3da 100644 --- a/src/util/lp/square_dense_submatrix_instances.cpp +++ b/src/util/lp/square_dense_submatrix_instances.cpp @@ -5,29 +5,29 @@ #include #include "util/vector.h" #include "util/lp/square_dense_submatrix.hpp" -template void lean::square_dense_submatrix::init(lean::sparse_matrix*, unsigned int); -template lean::square_dense_submatrix::square_dense_submatrix(lean::sparse_matrix*, unsigned int); -template void lean::square_dense_submatrix::update_parent_matrix(lean::lp_settings&); -template bool lean::square_dense_submatrix::is_L_matrix() const; -template void lean::square_dense_submatrix::conjugate_by_permutation(lean::permutation_matrix&); -template int lean::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; -template void lean::square_dense_submatrix::pivot(unsigned int, lean::lp_settings&); -template lean::square_dense_submatrix >::square_dense_submatrix(lean::sparse_matrix >*, unsigned int); -template void lean::square_dense_submatrix >::update_parent_matrix(lean::lp_settings&); -template bool lean::square_dense_submatrix >::is_L_matrix() const; -template void lean::square_dense_submatrix >::conjugate_by_permutation(lean::permutation_matrix >&); -template int lean::square_dense_submatrix >::find_pivot_column_in_row(unsigned int) const; -template void lean::square_dense_submatrix >::pivot(unsigned int, lean::lp_settings&); +template void lp::square_dense_submatrix::init(lp::sparse_matrix*, unsigned int); +template lp::square_dense_submatrix::square_dense_submatrix(lp::sparse_matrix*, unsigned int); +template void lp::square_dense_submatrix::update_parent_matrix(lp::lp_settings&); +template bool lp::square_dense_submatrix::is_L_matrix() const; +template void lp::square_dense_submatrix::conjugate_by_permutation(lp::permutation_matrix&); +template int lp::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; +template void lp::square_dense_submatrix::pivot(unsigned int, lp::lp_settings&); +template lp::square_dense_submatrix >::square_dense_submatrix(lp::sparse_matrix >*, unsigned int); +template void lp::square_dense_submatrix >::update_parent_matrix(lp::lp_settings&); +template bool lp::square_dense_submatrix >::is_L_matrix() const; +template void lp::square_dense_submatrix >::conjugate_by_permutation(lp::permutation_matrix >&); +template int lp::square_dense_submatrix >::find_pivot_column_in_row(unsigned int) const; +template void lp::square_dense_submatrix >::pivot(unsigned int, lp::lp_settings&); #ifdef LEAN_DEBUG -template double lean::square_dense_submatrix::get_elem(unsigned int, unsigned int) const; +template double lp::square_dense_submatrix::get_elem(unsigned int, unsigned int) const; #endif -template void lean::square_dense_submatrix::apply_from_right(vector&); +template void lp::square_dense_submatrix::apply_from_right(vector&); -template void lean::square_dense_submatrix::apply_from_left_local(lean::indexed_vector&, lean::lp_settings&); -template void lean::square_dense_submatrix::apply_from_left_to_vector(vector&); -template lean::square_dense_submatrix::square_dense_submatrix(lean::sparse_matrix*, unsigned int); -template void lean::square_dense_submatrix::update_parent_matrix(lean::lp_settings&); -template bool lean::square_dense_submatrix::is_L_matrix() const; -template void lean::square_dense_submatrix::conjugate_by_permutation(lean::permutation_matrix&); -template int lean::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; -template void lean::square_dense_submatrix::pivot(unsigned int, lean::lp_settings&); +template void lp::square_dense_submatrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); +template void lp::square_dense_submatrix::apply_from_left_to_vector(vector&); +template lp::square_dense_submatrix::square_dense_submatrix(lp::sparse_matrix*, unsigned int); +template void lp::square_dense_submatrix::update_parent_matrix(lp::lp_settings&); +template bool lp::square_dense_submatrix::is_L_matrix() const; +template void lp::square_dense_submatrix::conjugate_by_permutation(lp::permutation_matrix&); +template int lp::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; +template void lp::square_dense_submatrix::pivot(unsigned int, lp::lp_settings&); diff --git a/src/util/lp/stacked_map.h b/src/util/lp/stacked_map.h index 4692540dd..1c55b9f9f 100644 --- a/src/util/lp/stacked_map.h +++ b/src/util/lp/stacked_map.h @@ -8,7 +8,7 @@ #include #include #include -namespace lean { +namespace lp { template second; } }; @@ -73,7 +73,7 @@ public: const B & operator[]( const A & a) const { auto it = m_map.find(a); if (it == m_map.end()) { - lean_assert(false); + lp_assert(false); } return it->second; @@ -128,7 +128,7 @@ public: for (auto & t: d.m_original_changed) { m_map[t.first] = t.second; } - // lean_assert(d.m_deb_copy == m_map); + // lp_assert(d.m_deb_copy == m_map); m_stack.pop(); } } @@ -142,7 +142,7 @@ public: delta & d = m_stack.top(); auto it = m_map.find(key); if (it == m_map.end()) { - lean_assert(d.m_new.find(key) == d.m_new.end()); + lp_assert(d.m_new.find(key) == d.m_new.end()); return; } auto &orig_changed = d.m_original_changed; @@ -151,7 +151,7 @@ public: if (orig_changed.find(key) == orig_changed.end()) orig_changed.emplace(it->first, it->second); // need to restore } else { // k is new - lean_assert(orig_changed.find(key) == orig_changed.end()); + lp_assert(orig_changed.find(key) == orig_changed.end()); d.m_new.erase(nit); } diff --git a/src/util/lp/stacked_unordered_set.h b/src/util/lp/stacked_unordered_set.h index 69c4cf03b..88bb3160c 100644 --- a/src/util/lp/stacked_unordered_set.h +++ b/src/util/lp/stacked_unordered_set.h @@ -8,7 +8,7 @@ #include #include #include -namespace lean { +namespace lp { template , @@ -81,7 +81,7 @@ public: for (auto & t : d.m_erased) { m_set.insert(t); } - lean_assert(d.m_deb_copy == m_set); + lp_assert(d.m_deb_copy == m_set); m_stack.pop(); } } diff --git a/src/util/lp/stacked_value.h b/src/util/lp/stacked_value.h index 2a1e85be7..8cd43afce 100644 --- a/src/util/lp/stacked_value.h +++ b/src/util/lp/stacked_value.h @@ -6,7 +6,7 @@ #pragma once // add to value the stack semantics #include -namespace lean { +namespace lp { template class stacked_value { T m_value; std::stack m_stack; diff --git a/src/util/lp/stacked_vector.h b/src/util/lp/stacked_vector.h index 14b0d0141..4ed6f44d9 100644 --- a/src/util/lp/stacked_vector.h +++ b/src/util/lp/stacked_vector.h @@ -7,7 +7,7 @@ Author: Lev Nachmanson #include #include #include "util/vector.h" -namespace lean { +namespace lp { template < typename B> class stacked_vector { vector m_stack_of_vector_sizes; vector m_stack_of_change_sizes; @@ -19,7 +19,7 @@ public: unsigned m_i; public: ref(stacked_vector &m, unsigned key) :m_vec(m), m_i(key) { - lean_assert(key < m.size()); + lp_assert(key < m.size()); } ref & operator=(const B & b) { m_vec.emplace_replace(m_i, b); @@ -43,7 +43,7 @@ public: unsigned m_i; public: ref_const(const stacked_vector &m, unsigned key) :m_vec(m), m_i(key) { - lean_assert(key < m.size()); + lp_assert(key < m.size()); } operator const B&() const { @@ -71,7 +71,7 @@ public: /* const B & operator[](unsigned a) const { - lean_assert(a < m_vector.size()); + lp_assert(a < m_vector.size()); return m_vector[a]; } */ @@ -91,7 +91,7 @@ public: template void pop_tail(vector & v, unsigned k) { - lean_assert(v.size() >= k); + lp_assert(v.size() >= k); v.resize(v.size() - k); } @@ -101,8 +101,8 @@ public: } void pop(unsigned k) { - lean_assert(m_stack_of_vector_sizes.size() >= k); - lean_assert(k > 0); + lp_assert(m_stack_of_vector_sizes.size() >= k); + lp_assert(k > 0); resize(m_vector, m_stack_of_vector_sizes[m_stack_of_vector_sizes.size() - k]); pop_tail(m_stack_of_vector_sizes, k); unsigned first_change = m_stack_of_change_sizes[m_stack_of_change_sizes.size() - k]; @@ -122,15 +122,15 @@ public: return; delta & d = m_stack.back(); - lean_assert(m_vector.size() >= d.m_size); + lp_assert(m_vector.size() >= d.m_size); while (m_vector.size() > d.m_size) m_vector.pop_back(); for (auto & t : d.m_original_changed) { - lean_assert(t.first < m_vector.size()); + lp_assert(t.first < m_vector.size()); m_vector[t.first] = t.second; } - // lean_assert(d.m_deb_copy == m_vector); + // lp_assert(d.m_deb_copy == m_vector); m_stack.pop_back();*/ } @@ -160,7 +160,7 @@ public: } unsigned peek_size(unsigned k) const { - lean_assert(k > 0 && k <= m_stack_of_vector_sizes.size()); + lp_assert(k > 0 && k <= m_stack_of_vector_sizes.size()); return m_stack_of_vector_sizes[m_stack_of_vector_sizes.size() - k]; } diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index 5ef4b449f..f1d7f064b 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -13,7 +13,7 @@ #include "util/lp/permutation_matrix.h" #include "util/lp/linear_combination_iterator.h" #include -namespace lean { +namespace lp { struct column_cell { unsigned m_i; // points to the row @@ -193,7 +193,7 @@ public: void scan_row_to_work_vector(unsigned i); - void clean_row_work_vector(unsigned i); + void clp_row_work_vector(unsigned i); #ifdef LEAN_DEBUG @@ -203,7 +203,7 @@ public: virtual void set_number_of_columns(unsigned /*n*/) { } #endif - T get_max_val_in_row(unsigned /* i */) const { lean_unreachable(); } + T get_max_val_in_row(unsigned /* i */) const { lp_unreachable(); } T get_balance() const; @@ -219,7 +219,7 @@ public: for (auto & c : row) { unsigned j = c.m_j; auto & col = m_columns[j]; - lean_assert(col[col.size() - 1].m_i == m_rows.size() -1 ); // todo : start here!!!! + lp_assert(col[col.size() - 1].m_i == m_rows.size() -1 ); // todo : start here!!!! col.pop_back(); } } @@ -246,7 +246,7 @@ public: m_columns.pop_back(); // delete the last column m_stack.pop(); } - lean_assert(is_correct()); + lp_assert(is_correct()); } void multiply_row(unsigned row, T const & alpha) { @@ -262,7 +262,7 @@ public: } T dot_product_with_column(const vector & y, unsigned j) const { - lean_assert(j < column_count()); + 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); @@ -281,20 +281,20 @@ public: // now fix the columns for (auto & rc : m_rows[i]) { column_cell & cc = m_columns[rc.m_j][rc.m_offset]; - lean_assert(cc.m_i == ii); + lp_assert(cc.m_i == ii); cc.m_i = i; } for (auto & rc : m_rows[ii]) { column_cell & cc = m_columns[rc.m_j][rc.m_offset]; - lean_assert(cc.m_i == i); + lp_assert(cc.m_i == i); cc.m_i = ii; } } void fill_last_row_with_pivoting(linear_combination_iterator & it, const vector & basis_heading) { - lean_assert(numeric_traits::precise()); - lean_assert(row_count() > 0); + lp_assert(numeric_traits::precise()); + lp_assert(row_count() > 0); m_work_vector.resize(column_count()); T a; unsigned j; @@ -332,13 +332,13 @@ public: alpha = zero_of_type(); m_work_vector.erase_from_index(j); } - lean_assert(m_work_vector.is_OK()); + lp_assert(m_work_vector.is_OK()); unsigned last_row = row_count() - 1; for (unsigned j : m_work_vector.m_index) { set (last_row, j, m_work_vector.m_data[j]); } - lean_assert(column_count() > 0); + lp_assert(column_count() > 0); set(last_row, column_count() - 1, one_of_type()); } @@ -354,7 +354,7 @@ public: template L dot_product_with_row(unsigned row, const vector & w) const { L ret = zero_of_type(); - lean_assert(row < m_rows.size()); + lp_assert(row < m_rows.size()); for (auto & it : m_rows[row]) { ret += w[it.m_j] * it.get_val(); } diff --git a/src/util/lp/static_matrix.hpp b/src/util/lp/static_matrix.hpp index fb12da8c4..a3f69c9bf 100644 --- a/src/util/lp/static_matrix.hpp +++ b/src/util/lp/static_matrix.hpp @@ -6,11 +6,11 @@ #include #include #include "util/lp/static_matrix.h" -namespace lean { +namespace lp { // each assignment for this matrix should be issued only once!!! template void static_matrix::init_row_columns(unsigned m, unsigned n) { - lean_assert(m_rows.size() == 0 && m_columns.size() == 0); + lp_assert(m_rows.size() == 0 && m_columns.size() == 0); for (unsigned i = 0; i < m; i++){ m_rows.push_back(row_strip()); } @@ -30,23 +30,23 @@ 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) { unsigned ii = c.m_i; - lean_assert(i < row_count() && ii < column_count()); - lean_assert(i != ii); + lp_assert(i < row_count() && ii < column_count()); + lp_assert(i != ii); m_became_zeros.reset(); T alpha = -get_val(c); - lean_assert(!is_zero(alpha)); + lp_assert(!is_zero(alpha)); auto & ii_row_vals = m_rows[ii]; remove_element(ii_row_vals, ii_row_vals[c.m_offset]); scan_row_ii_to_offset_vector(ii); - lean_assert(!is_zero(alpha)); + lp_assert(!is_zero(alpha)); unsigned prev_size_ii = ii_row_vals.size(); // run over the pivot row and update row ii for (const auto & iv : m_rows[i]) { unsigned j = iv.m_j; if (j == pivot_col) continue; T alv = alpha * iv.m_value; - lean_assert(!is_zero(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); @@ -61,7 +61,7 @@ template bool static_matrix::pivot_row_to_row_giv } } - // clean the work vector + // clp the work vector for (unsigned k = 0; k < prev_size_ii; k++) { m_vector_of_row_offsets[ii_row_vals[k].m_j] = -1; } @@ -104,9 +104,9 @@ template void static_matrix::init_empty_matrix } template unsigned static_matrix::lowest_row_in_column(unsigned col) { - lean_assert(col < column_count()); + lp_assert(col < column_count()); column_strip & colstrip = m_columns[col]; - lean_assert(colstrip.size() > 0); + lp_assert(colstrip.size() > 0); unsigned ret = 0; for (auto & t : colstrip) { if (t.m_i > ret) { @@ -122,7 +122,7 @@ template void static_matrix::add_columns_at_th } template void static_matrix::forget_last_columns(unsigned how_many_to_forget) { - lean_assert(m_columns.size() >= how_many_to_forget); + lp_assert(m_columns.size() >= how_many_to_forget); unsigned j = column_count() - 1; for (; how_many_to_forget > 0; how_many_to_forget--) { remove_last_column(j --); @@ -151,7 +151,7 @@ template void static_matrix::remove_last_column(u template void static_matrix::set(unsigned row, unsigned col, T const & val) { if (numeric_traits::is_zero(val)) return; - lean_assert(row < row_count() && col < column_count()); + 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()))); @@ -171,7 +171,7 @@ std::set> static_matrix::get_domain() { template void static_matrix::copy_column_to_indexed_vector (unsigned j, indexed_vector & v) const { - lean_assert(j < m_columns.size()); + lp_assert(j < m_columns.size()); for (auto & it : m_columns[j]) { const T& val = get_val(it); if (!is_zero(val)) @@ -240,7 +240,7 @@ template void static_matrix::check_consistency for (int i = 0; i < m_rows.size(); i++){ for (auto & t : m_rows[i]) { std::pair p(i, t.m_j); - lean_assert(by_rows.find(p) == by_rows.end()); + lp_assert(by_rows.find(p) == by_rows.end()); by_rows[p] = t.get_val(); } } @@ -248,11 +248,11 @@ template void static_matrix::check_consistency for (int i = 0; i < m_columns.size(); i++){ for (auto & t : m_columns[i]) { std::pair p(t.m_i, i); - lean_assert(by_cols.find(p) == by_cols.end()); + lp_assert(by_cols.find(p) == by_cols.end()); by_cols[p] = get_val(t); } } - lean_assert(by_rows.size() == by_cols.size()); + lp_assert(by_rows.size() == by_cols.size()); for (auto & t : by_rows) { auto ic = by_cols.find(t.first); @@ -260,8 +260,8 @@ template void static_matrix::check_consistency //std::cout << "rows have pair (" << t.first.first <<"," << t.first.second // << "), but columns don't " << std::endl; } - lean_assert(ic != by_cols.end()); - lean_assert(t.second == ic->second); + lp_assert(ic != by_cols.end()); + lp_assert(t.second == ic->second); } } #endif diff --git a/src/util/lp/static_matrix_instances.cpp b/src/util/lp/static_matrix_instances.cpp index 59905929e..263021239 100644 --- a/src/util/lp/static_matrix_instances.cpp +++ b/src/util/lp/static_matrix_instances.cpp @@ -13,7 +13,7 @@ #include "util/lp/lp_primal_core_solver.h" #include "util/lp/scaler.h" #include "util/lp/lar_solver.h" -namespace lean { +namespace lp { template void static_matrix::add_columns_at_the_end(unsigned int); template void static_matrix::clear(); #ifdef LEAN_DEBUG @@ -23,8 +23,8 @@ template void static_matrix::copy_column_to_indexed_vector(unsig template double static_matrix::get_balance() const; template std::set> static_matrix::get_domain(); -template std::set> lean::static_matrix::get_domain(); -template std::set> lean::static_matrix >::get_domain(); +template std::set> lp::static_matrix::get_domain(); +template std::set> lp::static_matrix >::get_domain(); template double static_matrix::get_elem(unsigned int, unsigned int) const; template double static_matrix::get_max_abs_in_column(unsigned int) const; template double static_matrix::get_min_abs_in_column(unsigned int) const; @@ -60,10 +60,10 @@ template void static_matrix >::init_empty_matrix(unsigned template void static_matrix >::set(unsigned int, unsigned int, mpq const&); -template bool lean::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell &, unsigned int); -template bool lean::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell& , unsigned int); -template bool lean::static_matrix >::pivot_row_to_row_given_cell(unsigned int, column_cell&, unsigned int); -template void lean::static_matrix >::remove_element(vector, true, unsigned int>&, lean::row_cell&); +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&); } diff --git a/src/util/lp/tail_matrix.h b/src/util/lp/tail_matrix.h index c337b0933..0e9c6320a 100644 --- a/src/util/lp/tail_matrix.h +++ b/src/util/lp/tail_matrix.h @@ -10,7 +10,7 @@ #include "util/lp/lp_settings.h" // These matrices appear at the end of the list -namespace lean { +namespace lp { template class tail_matrix #ifdef LEAN_DEBUG diff --git a/src/util/lp/test_bound_analyzer.h b/src/util/lp/test_bound_analyzer.h index 262c610c7..43ba244dc 100644 --- a/src/util/lp/test_bound_analyzer.h +++ b/src/util/lp/test_bound_analyzer.h @@ -16,7 +16,7 @@ // In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l // here in addition we assume that all coefficient in the row are positive -namespace lean { +namespace lp { class test_bound_analyzer { linear_combination_iterator & m_it; @@ -74,7 +74,7 @@ public : void analyze_i_for_upper(unsigned i) { mpq l; bool strict = false; - lean_assert(is_zero(l)); + lp_assert(is_zero(l)); for (unsigned k = 0; k < m_index.size(); k++) { if (k == i) continue; @@ -165,7 +165,7 @@ public : void analyze_i_for_lower(unsigned i) { mpq l; - lean_assert(is_zero(l)); + lp_assert(is_zero(l)); bool strict = false; for (unsigned k = 0; k < m_index.size(); k++) { if (k == i) diff --git a/src/util/lp/ul_pair.h b/src/util/lp/ul_pair.h index 2e77a7db0..1df20aa56 100644 --- a/src/util/lp/ul_pair.h +++ b/src/util/lp/ul_pair.h @@ -10,7 +10,7 @@ #include #include "util/lp/column_info.h" -namespace lean { +namespace lp { enum lconstraint_kind { LE = -2, LT = -1 , GE = 2, GT = 1, EQ = 0 From 86ed01a63b416d74e101ecab781bbedc0d80356c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 10 Jul 2017 11:30:08 -0700 Subject: [PATCH 0201/1283] replace clp to clean Signed-off-by: Lev Nachmanson --- src/util/lp/indexed_vector.h | 4 ++-- src/util/lp/lar_solver.cpp | 17 +++++++---------- src/util/lp/lar_solver.h | 4 ++-- src/util/lp/lp_dual_simplex.hpp | 2 +- src/util/lp/lp_primal_simplex.hpp | 2 +- src/util/lp/lp_solver.h | 2 +- src/util/lp/lp_solver.hpp | 2 +- src/util/lp/lp_solver_instances.cpp | 4 ++-- src/util/lp/lu.hpp | 8 ++++---- src/util/lp/sparse_matrix.h | 4 ++-- src/util/lp/sparse_matrix.hpp | 8 ++++---- src/util/lp/sparse_matrix_instances.cpp | 6 +++--- src/util/lp/square_dense_submatrix.h | 2 +- src/util/lp/static_matrix.h | 2 +- src/util/lp/static_matrix.hpp | 2 +- 15 files changed, 33 insertions(+), 36 deletions(-) diff --git a/src/util/lp/indexed_vector.h b/src/util/lp/indexed_vector.h index 0e013f778..6c0c32414 100644 --- a/src/util/lp/indexed_vector.h +++ b/src/util/lp/indexed_vector.h @@ -86,7 +86,7 @@ public: return m_data[i]; } - void clp_up() { + void clean_up() { #if 0==1 for (unsigned k = 0; k < m_index.size(); k++) { unsigned i = m_index[k]; @@ -140,7 +140,7 @@ public: } } - void restore_index_and_clp_from_data() { + void restore_index_and_clean_from_data() { m_index.resize(0); for (unsigned i = 0; i < m_data.size(); i++) { T & v = m_data[i]; diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 3e7c994e6..93cd6a118 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -316,9 +316,6 @@ void lar_solver::fill_explanation_from_infeasible_column(vector lar_solver::get_list_of_all_var_indices() const { vector ret; for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) @@ -338,7 +335,7 @@ void lar_solver::push() { m_constraint_count.push(); } -void lar_solver::clp_large_elements_after_pop(unsigned n, int_set& set) { +void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { vector to_remove; for (unsigned j: set.m_index) if (j >= n) @@ -348,7 +345,7 @@ void lar_solver::clp_large_elements_after_pop(unsigned n, int_set& set) { } void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { - clp_large_elements_after_pop(n, set); + clean_large_elements_after_pop(n, set); set.resize(n); } @@ -367,10 +364,10 @@ void lar_solver::pop(unsigned k) { m_vars_to_ul_pairs.pop(k); m_mpq_lar_core_solver.pop(k); - clp_large_elements_after_pop(n, m_columns_with_changed_bound); + clean_large_elements_after_pop(n, m_columns_with_changed_bound); unsigned m = A_r().row_count(); - clp_large_elements_after_pop(m, m_rows_with_changed_bounds); - clp_inf_set_of_r_solver_after_pop(); + clean_large_elements_after_pop(m, m_rows_with_changed_bounds); + clean_inf_set_of_r_solver_after_pop(); lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); @@ -1346,9 +1343,9 @@ void lar_solver::pop_tableau() { lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); } -void lar_solver::clp_inf_set_of_r_solver_after_pop() { +void lar_solver::clean_inf_set_of_r_solver_after_pop() { vector became_feas; - clp_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); + clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); std::unordered_set basic_columns_with_changed_cost; auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; for (auto j: inf_index_copy) { diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 0961d2b8d..1a12a5953 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -222,7 +222,7 @@ public: vector get_list_of_all_var_indices() const; void push(); - static void clp_large_elements_after_pop(unsigned n, int_set& set); + static void clean_large_elements_after_pop(unsigned n, int_set& set); static void shrink_inf_set_after_pop(unsigned n, int_set & set); @@ -403,7 +403,7 @@ public: void remove_last_column_from_basis_tableau(unsigned j); void remove_column_from_tableau(unsigned j); void pop_tableau(); - void clp_inf_set_of_r_solver_after_pop(); + void clean_inf_set_of_r_solver_after_pop(); void shrink_explanation_to_minimum(vector> & explanation) const; diff --git a/src/util/lp/lp_dual_simplex.hpp b/src/util/lp/lp_dual_simplex.hpp index 8e16853a8..5a585c68e 100644 --- a/src/util/lp/lp_dual_simplex.hpp +++ b/src/util/lp/lp_dual_simplex.hpp @@ -335,7 +335,7 @@ template void lp_dual_simplex::find_maximal_solut this->flip_costs(); // do it for now, todo ( remove the flipping) - this->clpup(); + this->cleanup(); if (this->m_status == INFEASIBLE) { return; } diff --git a/src/util/lp/lp_primal_simplex.hpp b/src/util/lp/lp_primal_simplex.hpp index 76ed5684c..a09cd714f 100644 --- a/src/util/lp/lp_primal_simplex.hpp +++ b/src/util/lp/lp_primal_simplex.hpp @@ -157,7 +157,7 @@ template void lp_primal_simplex::find_maximal_sol return; } - this->clpup(); + this->cleanup(); this->fill_matrix_A_and_init_right_side(); if (this->m_status == lp_status::INFEASIBLE) { return; diff --git a/src/util/lp/lp_solver.h b/src/util/lp/lp_solver.h index 984e818e1..6c878c687 100644 --- a/src/util/lp/lp_solver.h +++ b/src/util/lp/lp_solver.h @@ -205,7 +205,7 @@ protected: unsigned try_to_remove_some_rows(); - void clpup(); + void cleanup(); void map_external_rows_to_core_solver_rows(); diff --git a/src/util/lp/lp_solver.hpp b/src/util/lp/lp_solver.hpp index 46674cf5e..a903421fd 100644 --- a/src/util/lp/lp_solver.hpp +++ b/src/util/lp/lp_solver.hpp @@ -381,7 +381,7 @@ template unsigned lp_solver::try_to_remove_some_r return static_cast(rows_to_delete.size()); } -template void lp_solver::clpup() { +template void lp_solver::cleanup() { int n = 0; // number of deleted rows int d; while ((d = try_to_remove_some_rows() > 0)) diff --git a/src/util/lp/lp_solver_instances.cpp b/src/util/lp/lp_solver_instances.cpp index 6e62ba7d3..dce86914c 100644 --- a/src/util/lp/lp_solver_instances.cpp +++ b/src/util/lp/lp_solver_instances.cpp @@ -5,7 +5,7 @@ #include #include "util/lp/lp_solver.hpp" template void lp::lp_solver::add_constraint(lp::lp_relation, double, unsigned int); -template void lp::lp_solver::clpup(); +template void lp::lp_solver::cleanup(); template void lp::lp_solver::count_slacks_and_artificials(); template void lp::lp_solver::fill_m_b(); template void lp::lp_solver::fill_matrix_A_and_init_right_side(); @@ -21,7 +21,7 @@ template void lp::lp_solver::scale(); template void lp::lp_solver::set_scaled_cost(unsigned int); template lp::lp_solver::~lp_solver(); template void lp::lp_solver::add_constraint(lp::lp_relation, lp::mpq, unsigned int); -template void lp::lp_solver::clpup(); +template void lp::lp_solver::cleanup(); template void lp::lp_solver::count_slacks_and_artificials(); template void lp::lp_solver::fill_m_b(); template void lp::lp_solver::fill_matrix_A_and_init_right_side(); diff --git a/src/util/lp/lu.hpp b/src/util/lp/lu.hpp index c602892ac..64ac8efe2 100644 --- a/src/util/lp/lu.hpp +++ b/src/util/lp/lu.hpp @@ -415,7 +415,7 @@ void lu::solve_yB_with_error_check_indexed(indexed_vector & y, const ve solve_yB_indexed(y); } else { solve_yB(y.m_data); - y.restore_index_and_clp_from_data(); + y.restore_index_and_clean_from_data(); } return; } @@ -429,7 +429,7 @@ void lu::solve_yB_with_error_check_indexed(indexed_vector & y, const ve find_error_of_yB(m_y_copy.m_data, y.m_data, basis); solve_yB(m_y_copy.m_data); add_delta_to_solution(m_y_copy.m_data, y.m_data); - y.restore_index_and_clp_from_data(); + y.restore_index_and_clean_from_data(); m_y_copy.clear_all(); } else { find_error_of_yB_indexed(y, heading, settings); // this works with m_y_copy @@ -439,7 +439,7 @@ void lu::solve_yB_with_error_check_indexed(indexed_vector & y, const ve lp_assert(m_y_copy.is_OK()); } else { solve_yB_with_error_check(y.m_data, basis); - y.restore_index_and_clp_from_data(); + y.restore_index_and_clean_from_data(); } } @@ -894,7 +894,7 @@ void lu::calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned if (replaced_column < lowest_row_of_the_bump) { diagonal_elem = m_row_eta_work_vector[lowest_row_of_the_bump]; // lp_assert(m_row_eta_work_vector.is_OK()); - m_U.set_row_from_work_vector_and_clp_work_vector_not_adjusted(m_U.adjust_row(lowest_row_of_the_bump), m_row_eta_work_vector, m_settings); + m_U.set_row_from_work_vector_and_clean_work_vector_not_adjusted(m_U.adjust_row(lowest_row_of_the_bump), m_row_eta_work_vector, m_settings); } else { diagonal_elem = m_U(lowest_row_of_the_bump, lowest_row_of_the_bump); // todo - get it more efficiently } diff --git a/src/util/lp/sparse_matrix.h b/src/util/lp/sparse_matrix.h index 0fc84f8f5..17f9ed7e0 100644 --- a/src/util/lp/sparse_matrix.h +++ b/src/util/lp/sparse_matrix.h @@ -190,13 +190,13 @@ public: // set the max val as well // returns false if the resulting row is all zeroes, and true otherwise - bool set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, + bool set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, lp_settings & settings); // set the max val as well // returns false if the resulting row is all zeroes, and true otherwise - bool set_row_from_work_vector_and_clp_work_vector(unsigned i0); + bool set_row_from_work_vector_and_clean_work_vector(unsigned i0); void remove_zero_elements_and_set_data_on_existing_elements(unsigned row); diff --git a/src/util/lp/sparse_matrix.hpp b/src/util/lp/sparse_matrix.hpp index 175633eda..a26f36ae9 100644 --- a/src/util/lp/sparse_matrix.hpp +++ b/src/util/lp/sparse_matrix.hpp @@ -296,7 +296,7 @@ bool sparse_matrix::pivot_row_to_row(unsigned i, const T& alpha, unsigned } - // clp the work vector + // clean the work vector for (unsigned k = 0; k < prev_size_i0; k++) { m_work_pivot_vector[i0_row_vals[k].m_index] = -1; } @@ -319,7 +319,7 @@ bool sparse_matrix::pivot_row_to_row(unsigned i, const T& alpha, unsigned // set the max val as well // returns false if the resulting row is all zeroes, and true otherwise template -bool sparse_matrix::set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, +bool sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, lp_settings & settings) { remove_zero_elements_and_set_data_on_existing_elements_not_adjusted(i0, work_vec, settings); // all non-zero elements in m_work_pivot_vector are new @@ -557,11 +557,11 @@ void sparse_matrix::double_solve_U_y(indexed_vector& y, const lp_settin active_rows.clear(); solve_U_y_indexed_only(y_orig, settings, active_rows); add_delta_to_solution(y_orig, y); - y.clp_up(); + y.clean_up(); } else { // the dense version solve_U_y(y_orig.m_data); add_delta_to_solution(y_orig.m_data, y.m_data); - y.restore_index_and_clp_from_data(); + y.restore_index_and_clean_from_data(); } lp_assert(y.is_OK()); } diff --git a/src/util/lp/sparse_matrix_instances.cpp b/src/util/lp/sparse_matrix_instances.cpp index cf859a6a2..80a9b8ef5 100644 --- a/src/util/lp/sparse_matrix_instances.cpp +++ b/src/util/lp/sparse_matrix_instances.cpp @@ -24,7 +24,7 @@ template void sparse_matrix::remove_element(vector::replace_column(unsigned int, indexed_vector&, lp_settings&); template void sparse_matrix::set(unsigned int, unsigned int, double); template void sparse_matrix::set_max_in_row(vector >&); -template bool sparse_matrix::set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); +template bool sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); template bool sparse_matrix::shorten_active_matrix(unsigned int, eta_matrix*); template void sparse_matrix::solve_y_U(vector&) const; template sparse_matrix::sparse_matrix(static_matrix const&, vector&); @@ -41,7 +41,7 @@ template void sparse_matrix::prepare_for_factorization(); template void sparse_matrix::remove_element(vector> &, indexed_value&); template void sparse_matrix::replace_column(unsigned int, indexed_vector&, lp_settings&); template void sparse_matrix::set_max_in_row(vector>&); -template bool sparse_matrix::set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); +template bool sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); template bool sparse_matrix::shorten_active_matrix(unsigned int, eta_matrix*); template void sparse_matrix::solve_y_U(vector&) const; template sparse_matrix::sparse_matrix(static_matrix const&, vector&); @@ -57,7 +57,7 @@ template void sparse_matrix>::prepare_for_factorizati template void sparse_matrix>::remove_element(vector>&, indexed_value&); template void sparse_matrix>::replace_column(unsigned int, indexed_vector&, lp_settings&); template void sparse_matrix>::set_max_in_row(vector>&); -template bool sparse_matrix>::set_row_from_work_vector_and_clp_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); +template bool sparse_matrix>::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); template bool sparse_matrix>::shorten_active_matrix(unsigned int, eta_matrix >*); template void sparse_matrix>::solve_y_U(vector&) const; template sparse_matrix>::sparse_matrix(static_matrix > const&, vector&); diff --git a/src/util/lp/square_dense_submatrix.h b/src/util/lp/square_dense_submatrix.h index 5ffed7818..c5aa1fa97 100644 --- a/src/util/lp/square_dense_submatrix.h +++ b/src/util/lp/square_dense_submatrix.h @@ -187,7 +187,7 @@ public: } } } - m_work_vector.clp_up(); + m_work_vector.clean_up(); lp_assert(m_work_vector.is_OK()); w = m_work_vector; #endif diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index f1d7f064b..74bcf17cf 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -193,7 +193,7 @@ public: void scan_row_to_work_vector(unsigned i); - void clp_row_work_vector(unsigned i); + void clean_row_work_vector(unsigned i); #ifdef LEAN_DEBUG diff --git a/src/util/lp/static_matrix.hpp b/src/util/lp/static_matrix.hpp index a3f69c9bf..1a88b567d 100644 --- a/src/util/lp/static_matrix.hpp +++ b/src/util/lp/static_matrix.hpp @@ -61,7 +61,7 @@ template bool static_matrix::pivot_row_to_row_giv } } - // clp the work vector + // clean the work vector for (unsigned k = 0; k < prev_size_ii; k++) { m_vector_of_row_offsets[ii_row_vals[k].m_j] = -1; } From 9dc7ba73eb13a42f24ca77471290a22aaf26dc94 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 10 Jul 2017 11:57:33 -0700 Subject: [PATCH 0202/1283] use a faster version of get_model in debug checks Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 10 +++++++++- src/util/lp/lar_solver.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 93cd6a118..0f9fa938a 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -897,7 +897,7 @@ bool lar_solver::all_constraints_hold() const { if (m_settings.get_cancel_flag()) return true; std::unordered_map var_map; - get_model(var_map); + get_model_do_not_care_about_diff_vars(var_map); for (unsigned i = 0; i < m_constraints.size(); i++) { if (!constraint_holds(*m_constraints[i], var_map)) { @@ -1137,6 +1137,14 @@ void lar_solver::get_model(std::unordered_map & variable_values) } while (i != m_mpq_lar_core_solver.m_r_x.size()); } +void lar_solver::get_model_do_not_care_about_diff_vars(std::unordered_map & variable_values) const { + for (unsigned i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { + const impq & rp = m_mpq_lar_core_solver.m_r_x[i]; + variable_values[i] = rp.x + rp.y; + } +} + + std::string lar_solver::get_variable_name(var_index vi) const { return get_column_name(vi); } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 1a12a5953..e155d31a1 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -372,6 +372,7 @@ public: void get_model(std::unordered_map & variable_values) const; + void get_model_do_not_care_about_diff_vars(std::unordered_map & variable_values) const; std::string get_variable_name(var_index vi) const; From 581098299be0c3f8893d24f4260d9dc44b88dac4 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 10 Jul 2017 12:04:58 -0700 Subject: [PATCH 0203/1283] change the order of initializations in the constructor of imp in theory_lra Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 4 ++-- src/util/lp/lar_solver.cpp | 2 +- src/util/lp/lar_solver.h | 2 +- src/util/lp/nra_solver.cpp | 2 +- src/util/lp/nra_solver.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 72654de18..c6fe07c4d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -721,10 +721,10 @@ namespace smt { m_asserted_qhead(0), m_assume_eq_head(0), m_num_conflicts(0), + m_use_nra_model(false), m_model_eqs(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)), m_solver(0), - m_resource_limit(*this), - m_use_nra_model(false) { + m_resource_limit(*this) { } ~imp() { diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 0f9fa938a..0b5508ec9 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1,7 +1,7 @@ #include "util/lp/lar_solver.h" /* Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson + Author: Nikolaj Bjorner, Lev Nachmanson */ namespace lp { diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index e155d31a1..e1b6973e8 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -1,6 +1,6 @@ /* Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson + Author: Nikolaj Bjorner, Lev Nachmanson */ #pragma once #include "util/vector.h" diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index efa003b37..327d2b70f 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -1,6 +1,6 @@ /* Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson + Author: Nikolaj Bjorner */ #include "util/lp/lar_solver.h" diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h index 68c9e98e5..70e614e91 100644 --- a/src/util/lp/nra_solver.h +++ b/src/util/lp/nra_solver.h @@ -1,6 +1,6 @@ /* Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson + Author: Nikolaj Bjorner */ #pragma once From 2fe846d9fcadff7242991d7ab3e27b1aa80dc069 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 10 Jul 2017 16:34:23 -0700 Subject: [PATCH 0204/1283] fix a bug in the lar_solver::m_status update during push/pop Signed-off-by: Lev Nachmanson --- src/shell/lp_frontend.cpp | 2 +- src/smt/theory_lra.cpp | 1 + src/test/lp/lp.cpp | 24 +++--- src/util/lp/int_solver.cpp | 17 +++-- src/util/lp/lar_core_solver.hpp | 12 +-- src/util/lp/lar_solver.cpp | 66 +++++++++-------- src/util/lp/lar_solver.h | 13 +++- src/util/lp/lp_core_solver_base.h | 12 ++- src/util/lp/lp_core_solver_base.hpp | 13 ++-- src/util/lp/lp_dual_core_solver.hpp | 30 ++++---- src/util/lp/lp_dual_simplex.hpp | 44 +++++------ src/util/lp/lp_primal_core_solver.h | 10 +-- src/util/lp/lp_primal_core_solver.hpp | 74 +++++++++---------- src/util/lp/lp_primal_core_solver_tableau.hpp | 38 +++++----- src/util/lp/lp_primal_simplex.hpp | 2 +- src/util/lp/lp_settings.h | 2 +- src/util/lp/lp_settings.hpp | 24 +++--- src/util/lp/lp_solver.hpp | 12 +-- src/util/lp/quick_xplain.cpp | 6 +- 19 files changed, 212 insertions(+), 190 deletions(-) diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index 694205395..83f5e9e2e 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -84,7 +84,7 @@ void run_solver(lp_params & params, char const * mps_file_name) { solver->find_maximal_solution(); *(solver->settings().get_message_ostream()) << "status is " << lp_status_to_string(solver->get_status()) << std::endl; - if (solver->get_status() == lp::OPTIMAL) { + if (solver->get_status() == lp::lp_status::OPTIMAL) { if (params.min()) { solver->flip_costs(); } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index c6fe07c4d..e2b4ea944 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1165,6 +1165,7 @@ namespace smt { } final_check_status final_check_eh() { + TRACE("lar_solver", tout << "ddd=" <<++lp::lp_settings::ddd << std::endl;); m_use_nra_model = false; lbool is_sat = l_true; if (m_solver->get_status() != lp::lp_status::OPTIMAL) { diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 173bc3b12..d402d4ff7 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -1656,7 +1656,7 @@ void solve_some_mps(argument_parser & args_parser) { } if (!solve_for_rational) { solve_mps(file_names[6], false, 0, time_limit, false, dual, compare_with_primal, args_parser); - solve_mps_with_known_solution(file_names[3], nullptr, INFEASIBLE, dual); // chvatal: 135(d) + solve_mps_with_known_solution(file_names[3], nullptr, lp_status::INFEASIBLE, dual); // chvatal: 135(d) std::unordered_map sol; sol["X1"] = 0; sol["X2"] = 6; @@ -1666,8 +1666,8 @@ void solve_some_mps(argument_parser & args_parser) { sol["X6"] = 1; sol["X7"] = 1; sol["X8"] = 0; - solve_mps_with_known_solution(file_names[9], &sol, OPTIMAL, dual); - solve_mps_with_known_solution(file_names[0], &sol, OPTIMAL, dual); + solve_mps_with_known_solution(file_names[9], &sol, lp_status::OPTIMAL, dual); + solve_mps_with_known_solution(file_names[0], &sol, lp_status::OPTIMAL, dual); sol.clear(); sol["X1"] = 25.0/14.0; // sol["X2"] = 0; @@ -1676,10 +1676,10 @@ void solve_some_mps(argument_parser & args_parser) { // sol["X5"] = 0; // sol["X6"] = 0; // sol["X7"] = 9.0/14.0; - solve_mps_with_known_solution(file_names[5], &sol, OPTIMAL, dual); // chvatal: 135(e) - solve_mps_with_known_solution(file_names[4], &sol, OPTIMAL, dual); // chvatal: 135(e) - solve_mps_with_known_solution(file_names[2], nullptr, UNBOUNDED, dual); // chvatal: 135(c) - solve_mps_with_known_solution(file_names[1], nullptr, UNBOUNDED, dual); // chvatal: 135(b) + solve_mps_with_known_solution(file_names[5], &sol, lp_status::OPTIMAL, dual); // chvatal: 135(e) + solve_mps_with_known_solution(file_names[4], &sol, lp_status::OPTIMAL, dual); // chvatal: 135(e) + solve_mps_with_known_solution(file_names[2], nullptr, lp_status::UNBOUNDED, dual); // chvatal: 135(c) + solve_mps_with_known_solution(file_names[1], nullptr, lp_status::UNBOUNDED, dual); // chvatal: 135(b) solve_mps(file_names[8], false, 0, time_limit, false, dual, compare_with_primal, args_parser); // return; for (auto& s : file_names) { @@ -1745,7 +1745,7 @@ void solve_rational() { expected_sol["x7"] = lp::mpq(1); expected_sol["x8"] = lp::mpq(0); solver.find_maximal_solution(); - lp_assert(solver.get_status() == OPTIMAL); + lp_assert(solver.get_status() == lp_status::OPTIMAL); for (auto it : expected_sol) { lp_assert(it.second == solver.get_column_value_by_name(it.first)); } @@ -2433,12 +2433,12 @@ void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_read sw.start(); lp_status status = solver->solve(); std::cout << "status is " << lp_status_to_string(status) << ", processed for " << sw.get_current_seconds() <<" seconds, and " << solver->get_total_iterations() << " iterations" << std::endl; - if (solver->get_status() == INFEASIBLE) { + if (solver->get_status() == lp_status::INFEASIBLE) { vector> evidence; solver->get_infeasibility_explanation(evidence); } if (args_parser.option_is_used("--randomize_lar")) { - if (solver->get_status() != OPTIMAL) { + if (solver->get_status() != lp_status::OPTIMAL) { std::cout << "cannot check randomize on an infeazible problem" << std::endl; return; } @@ -2717,7 +2717,7 @@ void test_term() { auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; std::unordered_map model; - if (status != OPTIMAL) + if (status != lp_status::OPTIMAL) return; solver.get_model(model); @@ -2745,7 +2745,7 @@ void test_evidence_for_total_inf_simple(argument_parser & args_parser) { auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; std::unordered_map model; - lp_assert(solver.get_status() == INFEASIBLE); + lp_assert(solver.get_status() == lp_status::INFEASIBLE); } void test_bound_propagation_one_small_sample1() { /* diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index f416ad98c..46d46e981 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -19,7 +19,7 @@ void int_solver::fix_non_base_columns() { } if (!change) return; - if (m_lar_solver->find_feasible_solution() == INFEASIBLE) + if (m_lar_solver->find_feasible_solution() == lp_status::INFEASIBLE) failed(); init_inf_int_set(); lp_assert(is_feasible() && inf_int_set_is_correct()); @@ -109,14 +109,13 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { } bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { - lp_assert(false); - return true; + + auto row_it = m_lar_solver->get_iterator_on_row(row_index); + + unsigned x_i = m_lar_solver->get_base_column_in_row(row_index); + + lp_assert(column_is_int_inf(x_i)); /* - const auto & row = m_lar_solver->A_r().m_rows[row_index]; - // The following assertion is wrong. It may be violated in mixed-integer problems. - // SASSERT(!all_coeff_int(r)); - theory_var x_i = r.get_base_var(); - SASSERT(is_int(x_i)); // The following assertion is wrong. It may be violated in mixed-real-interger problems. // The check is_gomory_cut_target will discard rows where any variable contains infinitesimals. @@ -286,6 +285,8 @@ bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { ante.eqs().size(), ante.eqs().c_ptr(), ante, l))); return true; */ + delete row_it; + return true; } diff --git a/src/util/lp/lar_core_solver.hpp b/src/util/lp/lar_core_solver.hpp index 227d2910f..6f7f7e720 100644 --- a/src/util/lp/lar_core_solver.hpp +++ b/src/util/lp/lar_core_solver.hpp @@ -230,7 +230,7 @@ void lar_core_solver::solve() { lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); lp_assert(m_r_solver.inf_set_is_correct()); if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) { - m_r_solver.set_status(OPTIMAL); + m_r_solver.set_status(lp_status::OPTIMAL); return; } ++settings().st().m_need_to_solve_inf; @@ -240,8 +240,8 @@ void lar_core_solver::solve() { prefix_d(); lar_solution_signature solution_signature; vector changes_of_basis = find_solution_signature_with_doubles(solution_signature); - if (m_d_solver.get_status() == TIME_EXHAUSTED) { - m_r_solver.set_status(TIME_EXHAUSTED); + if (m_d_solver.get_status() == lp_status::TIME_EXHAUSTED) { + m_r_solver.set_status(lp_status::TIME_EXHAUSTED); return; } if (settings().use_tableau()) @@ -262,10 +262,10 @@ void lar_core_solver::solve() { m_r_solver.solve(); lp_assert(!settings().use_tableau() || r_basis_is_OK()); } - if (m_r_solver.get_status() == INFEASIBLE) { + if (m_r_solver.get_status() == lp_status::INFEASIBLE) { fill_not_improvable_zero_sum(); - } else if (m_r_solver.get_status() != UNBOUNDED) { - m_r_solver.set_status(OPTIMAL); + } else if (m_r_solver.get_status() != lp_status::UNBOUNDED) { + m_r_solver.set_status(lp_status::OPTIMAL); } lp_assert(r_basis_is_OK()); lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 0b5508ec9..8dcd5a327 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -27,7 +27,7 @@ void clear() {lp_assert(false); // not implemented } -lar_solver::lar_solver() : m_status(OPTIMAL), +lar_solver::lar_solver() : m_status(lp_status::OPTIMAL), m_infeasible_column_index(-1), m_terms_start_index(1000000), m_mpq_lar_core_solver(m_settings, *this) @@ -293,11 +293,11 @@ lp_status lar_solver::find_feasible_solution() { } lp_status lar_solver::solve() { - if (m_status == INFEASIBLE) { + if (m_status == lp_status::INFEASIBLE) { return m_status; } solve_with_core_solver(); - if (m_status != INFEASIBLE) { + if (m_status != lp_status::INFEASIBLE) { if (m_settings.bound_propagation()) detect_rows_with_changed_bounds(); } @@ -325,7 +325,6 @@ vector lar_solver::get_list_of_all_var_indices() const { void lar_solver::push() { m_simplex_strategy = m_settings.simplex_strategy(); m_simplex_strategy.push(); - m_status.push(); m_vars_to_ul_pairs.push(); m_infeasible_column_index.push(); m_mpq_lar_core_solver.push(); @@ -335,7 +334,7 @@ void lar_solver::push() { m_constraint_count.push(); } -void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { +void lar_solver::clean_popped_elements(unsigned n, int_set& set) { vector to_remove; for (unsigned j: set.m_index) if (j >= n) @@ -345,14 +344,15 @@ void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) { } void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { - clean_large_elements_after_pop(n, set); + clean_popped_elements(n, set); set.resize(n); } void lar_solver::pop(unsigned k) { + TRACE("lar_solver", tout << "k = " << k << std::endl;); + int n_was = static_cast(m_ext_vars_to_columns.size()); - m_status.pop(k); m_infeasible_column_index.pop(k); unsigned n = m_vars_to_ul_pairs.peek_size(k); for (unsigned j = n_was; j-- > n;) @@ -364,10 +364,11 @@ void lar_solver::pop(unsigned k) { m_vars_to_ul_pairs.pop(k); m_mpq_lar_core_solver.pop(k); - clean_large_elements_after_pop(n, m_columns_with_changed_bound); + clean_popped_elements(n, m_columns_with_changed_bound); unsigned m = A_r().row_count(); - clean_large_elements_after_pop(m, m_rows_with_changed_bounds); + clean_popped_elements(m, m_rows_with_changed_bounds); clean_inf_set_of_r_solver_after_pop(); + m_status = m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()? lp_status::OPTIMAL: lp_status::UNKNOWN; lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); @@ -404,7 +405,7 @@ bool lar_solver::maximize_term_on_tableau(const vector decide_on_strategy_and_adjust_initial_state(); m_mpq_lar_core_solver.solve(); - if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED) + if (m_mpq_lar_core_solver.m_r_solver.get_status() == lp_status::UNBOUNDED) return false; term_max = 0; @@ -482,7 +483,7 @@ bool lar_solver::maximize_term_on_corrected_r_solver(const vector & variable_values) const { mpq delta = mpq(1, 2); // start from 0.5 to have less clashes - lp_assert(m_status == OPTIMAL); + lp_assert(m_status == lp_status::OPTIMAL); unsigned i; do { @@ -1353,7 +1354,7 @@ void lar_solver::pop_tableau() { void lar_solver::clean_inf_set_of_r_solver_after_pop() { vector became_feas; - clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); + clean_popped_elements(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); std::unordered_set basic_columns_with_changed_cost; auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; for (auto j: inf_index_copy) { @@ -1598,6 +1599,7 @@ bool lar_solver::bound_is_integer_if_needed(unsigned j, const mpq & right_side) } constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { + TRACE("lar_solver", tout << "j = " << j << std::endl;); constraint_index ci = m_constraints.size(); if (!is_term(j)) { // j is a var lp_assert(bound_is_integer_if_needed(j, right_side)); @@ -1816,7 +1818,7 @@ void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstrai set_low_bound_witness(j, ci); m_columns_with_changed_bound.insert(j); if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; } else { @@ -1828,7 +1830,7 @@ void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstrai { auto v = numeric_pair(right_side, zero_of_type()); if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; set_low_bound_witness(j, ci); m_infeasible_column_index = j; } @@ -1850,7 +1852,7 @@ void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstrai } void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); mpq y_of_bound(0); switch (kind) { case LT: @@ -1865,7 +1867,7 @@ void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kin } if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; lp_assert(false); m_infeasible_column_index = j; } @@ -1886,7 +1888,7 @@ void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kin set_low_bound_witness(j, ci); } if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; } else if (low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) { @@ -1898,12 +1900,12 @@ void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kin { auto v = numeric_pair(right_side, zero_of_type()); if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_upper_bound_witness(j, ci); } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_low_bound_witness(j, ci); } @@ -1937,7 +1939,7 @@ void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint m_columns_with_changed_bound.insert(j); if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; } else { @@ -1961,7 +1963,7 @@ void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint { auto v = numeric_pair(right_side, zero_of_type()); if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_upper_bound_witness(j, ci); } @@ -1982,15 +1984,15 @@ void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint } void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); + lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); auto v = numeric_pair(right_side, mpq(0)); mpq y_of_bound(0); switch (kind) { case LT: if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_upper_bound_witness(j, ci); } @@ -1998,7 +2000,7 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin case LE: { if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_upper_bound_witness(j, ci); } @@ -2007,7 +2009,7 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin case GT: { if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_low_bound_witness(j, ci); } @@ -2016,7 +2018,7 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin case GE: { if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_low_bound_witness(j, ci); } @@ -2025,12 +2027,12 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin case EQ: { if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_upper_bound_witness(j, ci); } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; m_infeasible_column_index = j; set_low_bound_witness(j, ci); } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index e1b6973e8..2249beaa1 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -48,7 +48,7 @@ class lar_solver : public column_namer { }; //////////////////// fields ////////////////////////// lp_settings m_settings; - stacked_value m_status; + lp_status m_status; stacked_value m_simplex_strategy; std::unordered_map m_ext_vars_to_columns; vector m_columns_to_ext_vars_or_term_indices; @@ -222,7 +222,7 @@ public: vector get_list_of_all_var_indices() const; void push(); - static void clean_large_elements_after_pop(unsigned n, int_set& set); + static void clean_popped_elements(unsigned n, int_set& set); static void shrink_inf_set_after_pop(unsigned n, int_set & set); @@ -447,5 +447,14 @@ public: } bool bound_is_integer_if_needed(unsigned j, const mpq & right_side) const; + linear_combination_iterator * get_iterator_on_row(unsigned i) { + return m_mpq_lar_core_solver.m_r_solver.get_iterator_on_row(i); + } + + unsigned get_base_column_in_row(unsigned row_index) const { + return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index); + } + + }; } diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 28cb14011..12c93ec93 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -26,7 +26,14 @@ class lp_core_solver_base { private: lp_status m_status; public: - bool current_x_is_feasible() const { return m_inf_set.size() == 0; } + bool current_x_is_feasible() const { + TRACE("feas", + if (m_inf_set.size()) { + tout << "column " << m_inf_set.m_index[0] << " is infeasible" << std::endl; + } + ); + return m_inf_set.size() == 0; + } bool current_x_is_infeasible() const { return m_inf_set.size() != 0; } int_set m_inf_set; bool m_using_infeas_costs; @@ -700,5 +707,8 @@ public: } void calculate_pivot_row(unsigned i); + unsigned get_base_column_in_row(unsigned row_index) const { + return m_basis[row_index]; + } }; } diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index 26d6f49c7..bd3410b45 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -24,7 +24,7 @@ lp_core_solver_base(static_matrix & A, const vector & upper_bound_values): m_total_iterations(0), m_iters_with_no_cost_growing(0), - m_status(FEASIBLE), + m_status(lp_status::FEASIBLE), m_inf_set(A.column_count()), m_using_infeas_costs(false), m_pivot_row_of_B_1(A.row_count()), @@ -534,7 +534,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) { if (!find_x_by_solving()) { restore_x(entering, tt); if(A_mult_x_is_off()) { - m_status = FLOATING_POINT_ERROR; + m_status = lp_status::FLOATING_POINT_ERROR; m_iters_with_no_cost_growing++; return false; } @@ -544,7 +544,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) { if (m_factorization->get_status() != LU_status::OK) { std::stringstream s; // s << "failing refactor on off_result for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << total_iterations(); - m_status = FLOATING_POINT_ERROR; + m_status = lp_status::FLOATING_POINT_ERROR; return false; } return false; @@ -566,19 +566,19 @@ update_basis_and_x(int entering, int leaving, X const & tt) { init_lu(); if (m_factorization->get_status() != LU_status::OK) { if (m_look_for_feasible_solution_only && !precise()) { - m_status = UNSTABLE; + m_status = lp_status::UNSTABLE; delete m_factorization; m_factorization = nullptr; return false; } // LP_OUT(m_settings, "failing refactor for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << total_iterations() << std::endl); restore_x_and_refactor(entering, leaving, tt); - if (m_status == FLOATING_POINT_ERROR) + if (m_status == lp_status::FLOATING_POINT_ERROR) return false; lp_assert(!A_mult_x_is_off()); m_iters_with_no_cost_growing++; // LP_OUT(m_settings, "rolled back after failing of init_factorization()" << std::endl); - m_status = UNSTABLE; + m_status = lp_status::UNSTABLE; return false; } return true; @@ -960,7 +960,6 @@ template void lp_core_solver_base::pivot_fixed_v unsigned basic_j = m_basis[i]; if (get_column_type(basic_j) != column_type::fixed) continue; - //todo run over the row here!!!!! call get_iterator_on_row(); T a; unsigned j; auto * it = get_iterator_on_row(i); diff --git a/src/util/lp/lp_dual_core_solver.hpp b/src/util/lp/lp_dual_core_solver.hpp index 5038fc4ea..1b6e696d7 100644 --- a/src/util/lp/lp_dual_core_solver.hpp +++ b/src/util/lp/lp_dual_core_solver.hpp @@ -82,11 +82,11 @@ template void lp_dual_core_solver::start_with_ini } template bool lp_dual_core_solver::done() { - if (this->get_status() == OPTIMAL) { + if (this->get_status() == lp_status::OPTIMAL) { return true; } if (this->total_iterations() > this->m_settings.max_total_number_of_iterations) { // debug !!!! - this->set_status(ITERATIONS_EXHAUSTED); + this->set_status(lp_status::ITERATIONS_EXHAUSTED); return true; } return false; // todo, need to be more cases @@ -170,8 +170,8 @@ template void lp_dual_core_solver::pricing_loop(u } } while (i != initial_offset_in_rows && rows_left); if (m_r == -1) { - if (this->get_status() != UNSTABLE) { - this->set_status(OPTIMAL); + if (this->get_status() != lp_status::UNSTABLE) { + this->set_status(lp_status::OPTIMAL); } } else { m_p = this->m_basis[m_r]; @@ -181,10 +181,10 @@ template void lp_dual_core_solver::pricing_loop(u return; } // failure in advance_on_known_p - if (this->get_status() == FLOATING_POINT_ERROR) { + if (this->get_status() == lp_status::FLOATING_POINT_ERROR) { return; } - this->set_status(UNSTABLE); + this->set_status(lp_status::UNSTABLE); m_forbidden_rows.insert(m_r); } } @@ -466,12 +466,12 @@ template void lp_dual_core_solver::revert_to_prev this->change_basis_unconditionally(m_p, m_q); init_factorization(this->m_factorization, this->m_A, this->m_basis, this->m_settings); if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(FLOATING_POINT_ERROR); // complete failure + this->set_status(lp_status::FLOATING_POINT_ERROR); // complete failure return; } recover_leaving(); if (!this->find_x_by_solving()) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); return; } recalculate_xB_and_d(); @@ -551,10 +551,10 @@ template bool lp_dual_core_solver::delta_keeps_th } template void lp_dual_core_solver::set_status_to_tentative_dual_unbounded_or_dual_unbounded() { - if (this->get_status() == TENTATIVE_DUAL_UNBOUNDED) { - this->set_status(DUAL_UNBOUNDED); + if (this->get_status() == lp_status::TENTATIVE_DUAL_UNBOUNDED) { + this->set_status(lp_status::DUAL_UNBOUNDED); } else { - this->set_status(TENTATIVE_DUAL_UNBOUNDED); + this->set_status(lp_status::TENTATIVE_DUAL_UNBOUNDED); } } @@ -660,7 +660,7 @@ template bool lp_dual_core_solver::ratio_test() { set_status_to_tentative_dual_unbounded_or_dual_unbounded(); return false; } - this->set_status(FEASIBLE); + this->set_status(lp_status::FEASIBLE); find_q_and_tight_set(); if (!tight_breakpoinst_are_all_boxed()) break; T del = m_delta - delta_lost_on_flips_of_tight_breakpoints() * initial_delta_sign; @@ -716,10 +716,10 @@ template void lp_dual_core_solver::update_xb_afte template void lp_dual_core_solver::one_iteration() { unsigned number_of_rows_to_try = get_number_of_rows_to_try_for_leaving(); unsigned offset_in_rows = this->m_settings.random_next() % this->m_m(); - if (this->get_status() == TENTATIVE_DUAL_UNBOUNDED) { + if (this->get_status() == lp_status::TENTATIVE_DUAL_UNBOUNDED) { number_of_rows_to_try = this->m_m(); } else { - this->set_status(FEASIBLE); + this->set_status(lp_status::FEASIBLE); } pricing_loop(number_of_rows_to_try, offset_in_rows); lp_assert(problem_is_dual_feasible()); @@ -736,7 +736,7 @@ template void lp_dual_core_solver::solve() { // s return; } one_iteration(); - } while (this->get_status() != FLOATING_POINT_ERROR && this->get_status() != DUAL_UNBOUNDED && this->get_status() != OPTIMAL && + } while (this->get_status() != lp_status::FLOATING_POINT_ERROR && this->get_status() != lp_status::DUAL_UNBOUNDED && this->get_status() != lp_status::OPTIMAL && this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements && this->total_iterations() <= this->m_settings.max_total_number_of_iterations); } diff --git a/src/util/lp/lp_dual_simplex.hpp b/src/util/lp/lp_dual_simplex.hpp index 5a585c68e..7f6f686ca 100644 --- a/src/util/lp/lp_dual_simplex.hpp +++ b/src/util/lp/lp_dual_simplex.hpp @@ -7,23 +7,23 @@ namespace lp{ template void lp_dual_simplex::decide_on_status_after_stage1() { switch (m_core_solver->get_status()) { - case OPTIMAL: + case lp_status::OPTIMAL: if (this->m_settings.abs_val_is_smaller_than_artificial_tolerance(m_core_solver->get_cost())) { - this->m_status = FEASIBLE; + this->m_status = lp_status::FEASIBLE; } else { - this->m_status = UNBOUNDED; + this->m_status = lp_status::UNBOUNDED; } break; - case DUAL_UNBOUNDED: + case lp_status::DUAL_UNBOUNDED: lp_unreachable(); - case ITERATIONS_EXHAUSTED: - this->m_status = ITERATIONS_EXHAUSTED; + case lp_status::ITERATIONS_EXHAUSTED: + this->m_status = lp_status::ITERATIONS_EXHAUSTED; break; - case TIME_EXHAUSTED: - this->m_status = TIME_EXHAUSTED; + case lp_status::TIME_EXHAUSTED: + this->m_status = lp_status::TIME_EXHAUSTED; break; - case FLOATING_POINT_ERROR: - this->m_status = FLOATING_POINT_ERROR; + case lp_status::FLOATING_POINT_ERROR: + this->m_status = lp_status::FLOATING_POINT_ERROR; break; default: lp_unreachable(); @@ -99,20 +99,20 @@ template void lp_dual_simplex::solve_for_stage2() m_core_solver->solve_yB(m_core_solver->m_y); m_core_solver->fill_reduced_costs_from_m_y_by_rows(); m_core_solver->start_with_initial_basis_and_make_it_dual_feasible(); - m_core_solver->set_status(FEASIBLE); + m_core_solver->set_status(lp_status::FEASIBLE); m_core_solver->solve(); switch (m_core_solver->get_status()) { - case OPTIMAL: - this->m_status = OPTIMAL; + case lp_status::OPTIMAL: + this->m_status = lp_status::OPTIMAL; break; - case DUAL_UNBOUNDED: - this->m_status = INFEASIBLE; + case lp_status::DUAL_UNBOUNDED: + this->m_status = lp_status::INFEASIBLE; break; - case TIME_EXHAUSTED: - this->m_status = TIME_EXHAUSTED; + case lp_status::TIME_EXHAUSTED: + this->m_status = lp_status::TIME_EXHAUSTED; break; - case FLOATING_POINT_ERROR: - this->m_status = FLOATING_POINT_ERROR; + case lp_status::FLOATING_POINT_ERROR: + this->m_status = lp_status::FLOATING_POINT_ERROR; break; default: lp_unreachable(); @@ -151,7 +151,7 @@ template void lp_dual_simplex::stage1() { m_core_solver->start_with_initial_basis_and_make_it_dual_feasible(); if (this->m_settings.abs_val_is_smaller_than_artificial_tolerance(m_core_solver->get_cost())) { // skipping stage 1 - m_core_solver->set_status(OPTIMAL); + m_core_solver->set_status(lp_status::OPTIMAL); m_core_solver->set_total_iterations(0); } else { m_core_solver->solve(); @@ -336,7 +336,7 @@ template void lp_dual_simplex::find_maximal_solut this->flip_costs(); // do it for now, todo ( remove the flipping) this->cleanup(); - if (this->m_status == INFEASIBLE) { + if (this->m_status == lp_status::INFEASIBLE) { return; } this->fill_matrix_A_and_init_right_side(); @@ -346,7 +346,7 @@ template void lp_dual_simplex::find_maximal_solut fill_first_stage_solver_fields(); copy_m_b_aside_and_set_it_to_zeros(); stage1(); - if (this->m_status == FEASIBLE) { + if (this->m_status == lp_status::FEASIBLE) { stage2(); } } diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index 498288726..77784746a 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -469,7 +469,7 @@ public: X new_val_for_leaving; int leaving = find_leaving_tableau_rows(new_val_for_leaving); if (leaving == -1) { - this->set_status(OPTIMAL); + this->set_status(lp_status::OPTIMAL); return; } @@ -485,14 +485,14 @@ public: T a_ent; int entering = find_beneficial_column_in_row_tableau_rows(this->m_basis_heading[leaving], a_ent); if (entering == -1) { - this->set_status(INFEASIBLE); + this->set_status(lp_status::INFEASIBLE); return; } X theta = (this->m_x[leaving] - new_val_for_leaving) / a_ent; advance_on_entering_and_leaving_tableau_rows(entering, leaving, theta ); lp_assert(this->m_x[leaving] == new_val_for_leaving); if (this->current_x_is_feasible()) - this->set_status(OPTIMAL); + this->set_status(lp_status::OPTIMAL); } void fill_breakpoints_array(unsigned entering); @@ -508,7 +508,7 @@ public: void decide_on_status_when_cannot_find_entering() { lp_assert(!need_to_switch_costs()); - this->set_status(this->current_x_is_feasible()? OPTIMAL: INFEASIBLE); + this->set_status(this->current_x_is_feasible()? lp_status::OPTIMAL: lp_status::INFEASIBLE); } // void limit_theta_on_basis_column_for_feas_case_m_neg(unsigned j, const T & m, X & theta) { @@ -915,7 +915,7 @@ public: } else { m_converted_harris_eps = zero_of_type(); } - this->set_status(UNKNOWN); + this->set_status(lp_status::UNKNOWN); } // constructor diff --git a/src/util/lp/lp_primal_core_solver.hpp b/src/util/lp/lp_primal_core_solver.hpp index d8d01f4b9..b3d6921d9 100644 --- a/src/util/lp/lp_primal_core_solver.hpp +++ b/src/util/lp/lp_primal_core_solver.hpp @@ -698,14 +698,14 @@ template void lp_primal_core_solver::advance_on_en int pivot_compare_result = this->pivots_in_column_and_row_are_different(entering, leaving); if (!pivot_compare_result){;} else if (pivot_compare_result == 2) { // the sign is changed, cannot continue - this->set_status(UNSTABLE); + this->set_status(lp_status::UNSTABLE); this->iters_with_no_cost_growing()++; return; } else { lp_assert(pivot_compare_result == 1); this->init_lu(); if (this->m_factorization == nullptr || this->m_factorization->get_status() != LU_status::OK) { - this->set_status(UNSTABLE); + this->set_status(lp_status::UNSTABLE); this->iters_with_no_cost_growing()++; return; } @@ -717,10 +717,10 @@ template void lp_primal_core_solver::advance_on_en t = -t; } if (!this->update_basis_and_x(entering, leaving, t)) { - if (this->get_status() == FLOATING_POINT_ERROR) + if (this->get_status() == lp_status::FLOATING_POINT_ERROR) return; if (this->m_look_for_feasible_solution_only) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); return; } init_reduced_costs(); @@ -733,7 +733,7 @@ template void lp_primal_core_solver::advance_on_en } if (this->current_x_is_feasible()) { - this->set_status(FEASIBLE); + this->set_status(lp_status::FEASIBLE); if (this->m_look_for_feasible_solution_only) return; } @@ -760,7 +760,7 @@ template void lp_primal_core_solver::advance_on_e X t; int leaving = find_leaving_and_t_precise(entering, t); if (leaving == -1) { - this->set_status(UNBOUNDED); + this->set_status(lp_status::UNBOUNDED); return; } advance_on_entering_and_leaving(entering, leaving, t); @@ -776,7 +776,7 @@ template void lp_primal_core_solver::advance_on_e int refresh_result = refresh_reduced_cost_at_entering_and_check_that_it_is_off(entering); if (refresh_result) { if (this->m_look_for_feasible_solution_only) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); return; } @@ -799,19 +799,19 @@ template void lp_primal_core_solver::advance_on_e // } - if (this->get_status() == UNSTABLE) { - this->set_status(FLOATING_POINT_ERROR); + if (this->get_status() == lp_status::UNSTABLE) { + this->set_status(lp_status::FLOATING_POINT_ERROR); return; } init_infeasibility_costs(); - this->set_status(UNSTABLE); + this->set_status(lp_status::UNSTABLE); return; } - if (this->get_status() == TENTATIVE_UNBOUNDED) { - this->set_status(UNBOUNDED); + if (this->get_status() == lp_status::TENTATIVE_UNBOUNDED) { + this->set_status(lp_status::UNBOUNDED); } else { - this->set_status(TENTATIVE_UNBOUNDED); + this->set_status(lp_status::TENTATIVE_UNBOUNDED); } return; } @@ -825,7 +825,7 @@ template void lp_primal_core_solver::push_forw template unsigned lp_primal_core_solver::get_number_of_non_basic_column_to_try_for_enter() { unsigned ret = static_cast(this->m_nbasis.size()); - if (this->get_status() == TENTATIVE_UNBOUNDED) + if (this->get_status() == lp_status::TENTATIVE_UNBOUNDED) return ret; // we really need to find entering with a large reduced cost if (ret > 300) { ret = (unsigned)(ret * this->m_settings.percent_of_entering_to_check / 100); @@ -852,12 +852,12 @@ template unsigned lp_primal_core_solver::solve() init_run(); if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) { - this->set_status(FEASIBLE); + this->set_status(lp_status::FEASIBLE); return 0; } if ((!numeric_traits::precise()) && this->A_mult_x_is_off()) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); return 0; } do { @@ -867,8 +867,8 @@ template unsigned lp_primal_core_solver::solve() one_iteration(); lp_assert(!this->m_using_infeas_costs || this->costs_on_nbasis_are_zeros()); switch (this->get_status()) { - case OPTIMAL: // double check that we are at optimum - case INFEASIBLE: + case lp_status::OPTIMAL: // double check that we are at optimum + case lp_status::INFEASIBLE: if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) break; if (!numeric_traits::precise()) { @@ -877,7 +877,7 @@ template unsigned lp_primal_core_solver::solve() this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status (FLOATING_POINT_ERROR); + this->set_status (lp_status::FLOATING_POINT_ERROR); break; } init_reduced_costs(); @@ -885,7 +885,7 @@ template unsigned lp_primal_core_solver::solve() decide_on_status_when_cannot_find_entering(); break; } - this->set_status(UNKNOWN); + this->set_status(lp_status::UNKNOWN); } else { // precise case if (this->m_look_for_feasible_solution_only) { // todo: keep the reduced costs correct all the time! init_reduced_costs(); @@ -893,31 +893,31 @@ template unsigned lp_primal_core_solver::solve() decide_on_status_when_cannot_find_entering(); break; } - this->set_status(UNKNOWN); + this->set_status(lp_status::UNKNOWN); } } break; - case TENTATIVE_UNBOUNDED: + case lp_status::TENTATIVE_UNBOUNDED: this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); break; } init_reduced_costs(); break; - case UNBOUNDED: + case lp_status::UNBOUNDED: if (this->current_x_is_infeasible()) { init_reduced_costs(); - this->set_status(UNKNOWN); + this->set_status(lp_status::UNKNOWN); } break; - case UNSTABLE: + case lp_status::UNSTABLE: lp_assert(! (numeric_traits::precise())); this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); break; } init_reduced_costs(); @@ -926,13 +926,13 @@ template unsigned lp_primal_core_solver::solve() default: break; // do nothing } - } while (this->get_status() != FLOATING_POINT_ERROR + } while (this->get_status() != lp_status::FLOATING_POINT_ERROR && - this->get_status() != UNBOUNDED + this->get_status() != lp_status::UNBOUNDED && - this->get_status() != OPTIMAL + this->get_status() != lp_status::OPTIMAL && - this->get_status() != INFEASIBLE + this->get_status() != lp_status::INFEASIBLE && this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements && @@ -940,7 +940,7 @@ template unsigned lp_primal_core_solver::solve() && !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); - lp_assert(this->get_status() == FLOATING_POINT_ERROR + lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR || this->current_x_is_feasible() == false || @@ -1028,7 +1028,7 @@ template T lp_primal_core_solver::calculate_no template void lp_primal_core_solver::find_feasible_solution() { this->m_look_for_feasible_solution_only = true; lp_assert(this->non_basic_columns_are_set_correctly()); - this->set_status(UNKNOWN); + this->set_status(lp_status::UNKNOWN); solve(); } @@ -1072,15 +1072,15 @@ template void lp_primal_core_solver::fill_breakpo template bool lp_primal_core_solver::done() { - if (this->get_status() == OPTIMAL || this->get_status() == FLOATING_POINT_ERROR) return true; - if (this->get_status() == INFEASIBLE) { + if (this->get_status() == lp_status::OPTIMAL || this->get_status() == lp_status::FLOATING_POINT_ERROR) return true; + if (this->get_status() == lp_status::INFEASIBLE) { return true; } if (this->m_iters_with_no_cost_growing >= this->m_settings.max_number_of_iterations_with_no_improvements) { - this->get_status() = ITERATIONS_EXHAUSTED; return true; + this->get_status() = lp_status::ITERATIONS_EXHAUSTED; return true; } if (this->total_iterations() >= this->m_settings.max_total_number_of_iterations) { - this->get_status() = ITERATIONS_EXHAUSTED; return true; + this->get_status() = lp_status::ITERATIONS_EXHAUSTED; return true; } return false; } diff --git a/src/util/lp/lp_primal_core_solver_tableau.hpp b/src/util/lp/lp_primal_core_solver_tableau.hpp index d2ce78472..3cacd2dbb 100644 --- a/src/util/lp/lp_primal_core_solver_tableau.hpp +++ b/src/util/lp/lp_primal_core_solver_tableau.hpp @@ -20,7 +20,7 @@ template void lp_primal_core_solver::advance_on_e X t; int leaving = find_leaving_and_t_tableau(entering, t); if (leaving == -1) { - this->set_status(UNBOUNDED); + this->set_status(lp_status::UNBOUNDED); return; } advance_on_entering_and_leaving_tableau(entering, leaving, t); @@ -85,12 +85,12 @@ template unsigned lp_primal_core_solver::solve_with_tableau() { init_run_tableau(); if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) { - this->set_status(FEASIBLE); + this->set_status(lp_status::FEASIBLE); return 0; } if ((!numeric_traits::precise()) && this->A_mult_x_is_off()) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); return 0; } do { @@ -102,8 +102,8 @@ unsigned lp_primal_core_solver::solve_with_tableau() { else one_iteration_tableau(); switch (this->get_status()) { - case OPTIMAL: // double check that we are at optimum - case INFEASIBLE: + case lp_status::OPTIMAL: // double check that we are at optimum + case lp_status::INFEASIBLE: if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) break; if (!numeric_traits::precise()) { @@ -112,7 +112,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); break; } init_reduced_costs(); @@ -120,7 +120,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { decide_on_status_when_cannot_find_entering(); break; } - this->set_status(UNKNOWN); + this->set_status(lp_status::UNKNOWN); } else { // precise case if ((!this->infeasibility_costs_are_correct())) { init_reduced_costs_tableau(); // forcing recalc @@ -128,31 +128,31 @@ unsigned lp_primal_core_solver::solve_with_tableau() { decide_on_status_when_cannot_find_entering(); break; } - this->set_status(UNKNOWN); + this->set_status(lp_status::UNKNOWN); } } break; - case TENTATIVE_UNBOUNDED: + case lp_status::TENTATIVE_UNBOUNDED: this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); break; } init_reduced_costs(); break; - case UNBOUNDED: + case lp_status::UNBOUNDED: if (this->current_x_is_infeasible()) { init_reduced_costs(); - this->set_status(UNKNOWN); + this->set_status(lp_status::UNKNOWN); } break; - case UNSTABLE: + case lp_status::UNSTABLE: lp_assert(! (numeric_traits::precise())); this->init_lu(); if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(FLOATING_POINT_ERROR); + this->set_status(lp_status::FLOATING_POINT_ERROR); break; } init_reduced_costs(); @@ -161,13 +161,13 @@ unsigned lp_primal_core_solver::solve_with_tableau() { default: break; // do nothing } - } while (this->get_status() != FLOATING_POINT_ERROR + } while (this->get_status() != lp_status::FLOATING_POINT_ERROR && - this->get_status() != UNBOUNDED + this->get_status() != lp_status::UNBOUNDED && - this->get_status() != OPTIMAL + this->get_status() != lp_status::OPTIMAL && - this->get_status() != INFEASIBLE + this->get_status() != lp_status::INFEASIBLE && this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements && @@ -175,7 +175,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { && !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); - lp_assert(this->get_status() == FLOATING_POINT_ERROR + lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR || this->current_x_is_feasible() == false || diff --git a/src/util/lp/lp_primal_simplex.hpp b/src/util/lp/lp_primal_simplex.hpp index a09cd714f..759095355 100644 --- a/src/util/lp/lp_primal_simplex.hpp +++ b/src/util/lp/lp_primal_simplex.hpp @@ -216,7 +216,7 @@ template void lp_primal_simplex::fill_A_x_and_bas template void lp_primal_simplex::solve_with_total_inf() { int total_vars = this->m_A->column_count() + this->row_count(); if (total_vars == 0) { - this->m_status = OPTIMAL; + this->m_status = lp_status::OPTIMAL; return; } m_low_bounds.clear(); diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index 3b6b44614..3530a13f5 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -36,7 +36,7 @@ enum class simplex_strategy_enum { std::string column_type_to_string(column_type t); -enum lp_status { +enum class lp_status { UNKNOWN, INFEASIBLE, TENTATIVE_UNBOUNDED, diff --git a/src/util/lp/lp_settings.hpp b/src/util/lp/lp_settings.hpp index b07395222..fd5d8d8ea 100644 --- a/src/util/lp/lp_settings.hpp +++ b/src/util/lp/lp_settings.hpp @@ -21,18 +21,18 @@ std::string column_type_to_string(column_type t) { const char* lp_status_to_string(lp_status status) { switch (status) { - case UNKNOWN: return "UNKNOWN"; - case INFEASIBLE: return "INFEASIBLE"; - case UNBOUNDED: return "UNBOUNDED"; - case TENTATIVE_DUAL_UNBOUNDED: return "TENTATIVE_DUAL_UNBOUNDED"; - case DUAL_UNBOUNDED: return "DUAL_UNBOUNDED"; - case OPTIMAL: return "OPTIMAL"; - case FEASIBLE: return "FEASIBLE"; - case FLOATING_POINT_ERROR: return "FLOATING_POINT_ERROR"; - case TIME_EXHAUSTED: return "TIME_EXHAUSTED"; - case ITERATIONS_EXHAUSTED: return "ITERATIONS_EXHAUSTED"; - case EMPTY: return "EMPTY"; - case UNSTABLE: return "UNSTABLE"; + case lp_status::UNKNOWN: return "UNKNOWN"; + case lp_status::INFEASIBLE: return "INFEASIBLE"; + case lp_status::UNBOUNDED: return "UNBOUNDED"; + case lp_status::TENTATIVE_DUAL_UNBOUNDED: return "TENTATIVE_DUAL_UNBOUNDED"; + case lp_status::DUAL_UNBOUNDED: return "DUAL_UNBOUNDED"; + case lp_status::OPTIMAL: return "OPTIMAL"; + case lp_status::FEASIBLE: return "FEASIBLE"; + case lp_status::FLOATING_POINT_ERROR: return "FLOATING_POINT_ERROR"; + case lp_status::TIME_EXHAUSTED: return "TIME_EXHAUSTED"; + case lp_status::ITERATIONS_EXHAUSTED: return "ITERATIONS_EXHAUSTED"; + case lp_status::EMPTY: return "EMPTY"; + case lp_status::UNSTABLE: return "UNSTABLE"; default: lp_unreachable(); } diff --git a/src/util/lp/lp_solver.hpp b/src/util/lp/lp_solver.hpp index a903421fd..3c7f35587 100644 --- a/src/util/lp/lp_solver.hpp +++ b/src/util/lp/lp_solver.hpp @@ -223,7 +223,7 @@ template bool lp_solver::row_e_is_obsolete(std T rs = m_constraints[row_index].m_rs; if (row_is_zero(row)) { if (!is_zero(rs)) - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; return true; } @@ -233,7 +233,7 @@ template bool lp_solver::row_e_is_obsolete(std T diff = low_bound - rs; if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)){ // low_bound > rs + m_settings.refactor_epsilon - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; return true; } if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ @@ -248,7 +248,7 @@ template bool lp_solver::row_e_is_obsolete(std T diff = rs - upper_bound; if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)) { // upper_bound < rs - m_settings.refactor_tolerance - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; return true; } if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ @@ -264,7 +264,7 @@ template bool lp_solver::row_ge_is_obsolete(std: T rs = m_constraints[row_index].m_rs; if (row_is_zero(row)) { if (rs > zero_of_type()) - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; return true; } @@ -273,7 +273,7 @@ template bool lp_solver::row_ge_is_obsolete(std: T diff = rs - upper_bound; if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)) { // upper_bound < rs - m_settings.refactor_tolerance - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; return true; } if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ @@ -290,7 +290,7 @@ template bool lp_solver::row_le_is_obsolete(std:: T rs = m_constraints[row_index].m_rs; if (row_is_zero(row)) { if (rs < zero_of_type()) - m_status = INFEASIBLE; + m_status = lp_status::INFEASIBLE; return true; } diff --git a/src/util/lp/quick_xplain.cpp b/src/util/lp/quick_xplain.cpp index 93e40ea71..53c7ecfca 100644 --- a/src/util/lp/quick_xplain.cpp +++ b/src/util/lp/quick_xplain.cpp @@ -29,7 +29,7 @@ void quick_xplain::copy_constraint_and_add_constraint_vars(const lar_constraint& bool quick_xplain::infeasible() { m_qsol.solve(); - return m_qsol.get_status() == INFEASIBLE; + return m_qsol.get_status() == lp_status::INFEASIBLE; } // u - unexplored constraints @@ -100,7 +100,7 @@ bool quick_xplain::is_feasible(const vector & x, unsigned k) const { l.add_constraint(ls, c.m_kind, c.m_right_side); } l.solve(); - return l.get_status() != INFEASIBLE; + return l.get_status() != lp_status::INFEASIBLE; } bool quick_xplain::x_is_minimal() const { @@ -127,7 +127,7 @@ void quick_xplain::solve() { for (unsigned i : m_x) add_constraint_to_qsol(i); m_qsol.solve(); - lp_assert(m_qsol.get_status() == INFEASIBLE); + lp_assert(m_qsol.get_status() == lp_status::INFEASIBLE); m_qsol.get_infeasibility_explanation(m_explanation); lp_assert(m_qsol.explanation_is_correct(m_explanation)); lp_assert(x_is_minimal()); From 69d6b022b8535fce5b48234326fcbba073e0fbb4 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 10 Jul 2017 22:14:56 -0700 Subject: [PATCH 0205/1283] speed up in get_model and fix in git_model_do_not_care_... Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 36 +++++++++++++++++++----------------- src/util/lp/lar_solver.cpp | 7 +++++-- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 46d46e981..176d67733 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -39,24 +39,26 @@ void int_solver::failed() { } void int_solver::trace_inf_rows() const { - unsigned num = m_lar_solver->A_r().column_count(); - for (unsigned v = 0; v < num; v++) { - if (is_int(v) && !get_value(v).is_int()) { - display_column(tout, v); - } - } + TRACE("arith_int_rows", + unsigned num = m_lar_solver->A_r().column_count(); + for (unsigned v = 0; v < num; v++) { + if (is_int(v) && !get_value(v).is_int()) { + display_column(tout, v); + } + } - num = 0; - for (unsigned i = 0; i < m_lar_solver->A_r().row_count(); i++) { - unsigned j = m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i]; - if (column_is_int_inf(j)) { - num++; - iterator_on_row it(m_lar_solver->A_r().m_rows[i]); - m_lar_solver->print_linear_iterator(&it, tout); - tout << "\n"; - } - } - tout << "num of int infeasible: " << num << "\n"; + num = 0; + for (unsigned i = 0; i < m_lar_solver->A_r().row_count(); i++) { + unsigned j = m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i]; + if (column_is_int_inf(j)) { + num++; + iterator_on_row it(m_lar_solver->A_r().m_rows[i]); + m_lar_solver->print_linear_iterator(&it, tout); + tout << "\n"; + } + } + tout << "num of int infeasible: " << num << "\n"; + ); } int int_solver::find_inf_int_base_column() { diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 8dcd5a327..3cef85ce2 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -368,7 +368,6 @@ void lar_solver::pop(unsigned k) { unsigned m = A_r().row_count(); clean_popped_elements(m, m_rows_with_changed_bounds); clean_inf_set_of_r_solver_after_pop(); - m_status = m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()? lp_status::OPTIMAL: lp_status::UNKNOWN; lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); @@ -389,6 +388,8 @@ void lar_solver::pop(unsigned k) { m_settings.simplex_strategy() = m_simplex_strategy; lp_assert(sizes_are_correct()); lp_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + m_status = m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()? lp_status::OPTIMAL: lp_status::UNKNOWN; + } vector lar_solver::get_all_constraint_indices() const { @@ -1139,9 +1140,11 @@ void lar_solver::get_model(std::unordered_map & variable_values) } void lar_solver::get_model_do_not_care_about_diff_vars(std::unordered_map & variable_values) const { + mpq delta = mpq(1); + delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); for (unsigned i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { const impq & rp = m_mpq_lar_core_solver.m_r_x[i]; - variable_values[i] = rp.x + rp.y; + variable_values[i] = rp.x + delta * rp.y; } } From fc6a876845a414e8591919ea18ad81304703ab2c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 11 Jul 2017 13:38:59 -0700 Subject: [PATCH 0206/1283] start gomory cut Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 5 +++ src/util/lp/int_solver.cpp | 79 ++++++++++++++++++++++++-------------- src/util/lp/int_solver.h | 9 ++++- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index e2b4ea944..b0404e126 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1252,6 +1252,11 @@ namespace smt { // SAT core assigns a value to return l_false; } + case lp::lia_move::bound: { + // todo nikolaj + // Need to set a bound >= k on the only var from the term + return l_false; + } case lp::lia_move::cut: { // m_explanation implies term <= k app_ref b = mk_bound(term, k); diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 176d67733..c4c477dfb 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -110,26 +110,21 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { } -bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { + /** + \brief Create bounds for (non base) free vars in the given row. + Return true if at least one variable was constrained. + This method is used to enable the application of gomory cuts. + */ - auto row_it = m_lar_solver->get_iterator_on_row(row_index); + + +lia_move int_solver::mk_gomory_cut(explanation & ex) { + + lp_assert(column_is_int_inf(m_gomory_cut_inf_column)); + + return lia_move::give_up; - unsigned x_i = m_lar_solver->get_base_column_in_row(row_index); - - lp_assert(column_is_int_inf(x_i)); /* - SASSERT(is_int(x_i)); - // The following assertion is wrong. It may be violated in mixed-real-interger problems. - // The check is_gomory_cut_target will discard rows where any variable contains infinitesimals. - // SASSERT(m_value[x_i].is_rational()); // infinitesimals are not used for integer variables - SASSERT(!m_value[x_i].is_int()); // the base variable is not assigned to an integer value. - - if (constrain_free_vars(r) || !is_gomory_cut_target(r)) { - TRACE("gomory_cut", tout << "failed to apply gomory cut:\n"; - tout << "constrain_free_vars(r): " << constrain_free_vars(r) << "\n";); - return false; - } - TRACE("gomory_cut", tout << "applying cut at:\n"; display_row_info(tout, r);); antecedents ante(*this); @@ -287,9 +282,6 @@ bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { ante.eqs().size(), ante.eqs().c_ptr(), ante, l))); return true; */ - delete row_it; - return true; - } void int_solver::init_check_data() { @@ -299,9 +291,35 @@ void int_solver::init_check_data() { m_old_values_data.resize(n); } +int int_solver::find_next_free_var_in_gomory_row() { + lp_assert(m_iter_on_gomory_row != nullptr); + unsigned j; + while(m_iter_on_gomory_row->next(j)) { + if (is_free(j)) + return static_cast(j); + } + return -1; +} + +lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex) { + int j = find_next_free_var_in_gomory_row(); + if (j != -1) { + lp_assert(t.is_empty()); + t.add_to_map(j, mpq(1)); + k = zero_of_type(); + return lia_move::bound; + } + delete m_iter_on_gomory_row; + m_iter_on_gomory_row = nullptr; + return mk_gomory_cut(ex); + } + + lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { - lp_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); - lp_assert(is_feasible()); + if (m_iter_on_gomory_row != nullptr) { + return proceed_with_gomory_cut(t, k, ex); + } + init_check_data(); lp_assert(inf_int_set_is_correct()); // currently it is a reimplementation of @@ -333,13 +351,12 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { } int j = find_inf_int_base_column(); if (j != -1) { + // setup the call for gomory cut TRACE("arith_int", tout << "j = " << j << " does not have an integer assignment: " << get_value(j) << "\n";); unsigned row_index = m_lar_solver->m_mpq_lar_core_solver.m_r_heading[j]; - if (!mk_gomory_cut(row_index, ex)) { - return lia_move::give_up; - // silent failure - } - return lia_move::cut; + m_iter_on_gomory_row = m_lar_solver->get_iterator_on_row(row_index); + m_gomory_cut_inf_column = j; + return check(t, k, ex); } } else { @@ -623,7 +640,8 @@ linear_combination_iterator * int_solver::get_column_iterator(unsigned j) { int_solver::int_solver(lar_solver* lar_slv) : m_lar_solver(lar_slv), - m_branch_cut_counter(0) { + m_branch_cut_counter(0), + m_iter_on_gomory_row(nullptr) { lp_assert(m_old_values_set.size() == 0); m_old_values_set.resize(lar_slv->A_r().column_count()); m_old_values_data.resize(lar_slv->A_r().column_count(), zero_of_type()); @@ -810,6 +828,11 @@ bool int_solver::is_boxed(unsigned j) const { return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed; } +bool int_solver::is_free(unsigned j) const { + return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::free_column; +} + + lp_settings& int_solver::settings() { return m_lar_solver->settings(); } diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 1d1a1dc69..1ae0ecbd8 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -18,6 +18,7 @@ enum class lia_move { branch, cut, conflict, + bound, give_up }; @@ -33,6 +34,8 @@ public: vector m_old_values_data; int_set m_inf_int_set; unsigned m_branch_cut_counter; + linear_combination_iterator* m_iter_on_gomory_row; + unsigned m_gomory_cut_inf_column; // methods int_solver(lar_solver* lp); // main function to check that solution provided by lar_solver is valid for integral values, @@ -80,6 +83,7 @@ private: bool is_int(unsigned j) const; bool is_base(unsigned j) const; bool is_boxed(unsigned j) const; + bool is_free(unsigned j) const; bool value_is_int(unsigned j) const; void set_value_for_nbasic_column(unsigned j, const impq & new_val); void fix_non_base_columns(); @@ -97,7 +101,10 @@ private: lp_settings& settings(); void move_non_base_vars_to_bounds(); void branch_infeasible_int_var(unsigned); - bool mk_gomory_cut(unsigned row_index, explanation & ex); + lia_move mk_gomory_cut(explanation & ex); void init_check_data(); + bool constrain_free_vars(linear_combination_iterator * r); + lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex); + int find_next_free_var_in_gomory_row(); }; } From bac16bac85e07567b2126e7d03c53bd462532d3b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 11 Jul 2017 13:46:46 -0700 Subject: [PATCH 0207/1283] start gomory cut Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index b0404e126..e02554a3d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1254,7 +1254,7 @@ namespace smt { } case lp::lia_move::bound: { // todo nikolaj - // Need to set a bound >= k on the only var from the term + // Need to set a bound x[j] >= k where j is the only var from the term return l_false; } case lp::lia_move::cut: { From 2056404ed488b0ffd1994a22558b2eaf21493eb5 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 11 Jul 2017 16:44:04 -0700 Subject: [PATCH 0208/1283] branch on a free variable before trying Gomory cuts Signed-off-by: Lev Nachmanson --- src/smt/theory_arith_int.h | 2 +- src/smt/theory_lra.cpp | 5 ---- src/util/lp/int_solver.cpp | 60 +++++++++++++++++++++++++++++++------- src/util/lp/int_solver.h | 5 +++- 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index ca3a485c6..7be5650c6 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -1387,7 +1387,7 @@ namespace smt { m_branch_cut_counter++; // TODO: add giveup code - if (m_branch_cut_counter % m_params.m_arith_branch_cut_ratio == 0) { + if (true || m_branch_cut_counter % m_params.m_arith_branch_cut_ratio == 0) { // remove true :todo TRACE("opt_verbose", display(tout);); move_non_base_vars_to_bounds(); if (!make_feasible()) { diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index e02554a3d..e2b4ea944 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1252,11 +1252,6 @@ namespace smt { // SAT core assigns a value to return l_false; } - case lp::lia_move::bound: { - // todo nikolaj - // Need to set a bound x[j] >= k where j is the only var from the term - return l_false; - } case lp::lia_move::cut: { // m_explanation implies term <= k app_ref b = mk_bound(term, k); diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index c4c477dfb..62bdc0e32 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -110,13 +110,23 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { } - /** - \brief Create bounds for (non base) free vars in the given row. - Return true if at least one variable was constrained. - This method is used to enable the application of gomory cuts. - */ +bool int_solver::is_gomory_cut_target() { + m_iter_on_gomory_row->reset(); + unsigned j; + TRACE("gomory_cut", m_lar_solver->print_linear_iterator(m_iter_on_gomory_row, tout);); - + while (m_iter_on_gomory_row->next(j)) { + // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). + if (j != m_gomory_cut_inf_column && (!at_bound(j) || !is_zero(get_value(j).y))) { + TRACE("gomory_cut", tout << "row is not gomory cut target:\n"; + display_column(tout, j); + tout << "at_bound: " << at_bound(j) << "\n"; + tout << "infinitesimal: " << !is_zero(get_value(j).y) << "\n";); + return false; + } + } + return true; +} lia_move int_solver::mk_gomory_cut(explanation & ex) { @@ -295,7 +305,7 @@ int int_solver::find_next_free_var_in_gomory_row() { lp_assert(m_iter_on_gomory_row != nullptr); unsigned j; while(m_iter_on_gomory_row->next(j)) { - if (is_free(j)) + if (j != m_gomory_cut_inf_column && is_free(j)) return static_cast(j); } return -1; @@ -304,11 +314,19 @@ int int_solver::find_next_free_var_in_gomory_row() { lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex) { int j = find_next_free_var_in_gomory_row(); if (j != -1) { + m_found_free_var_in_gomory_row = true; lp_assert(t.is_empty()); t.add_to_map(j, mpq(1)); k = zero_of_type(); - return lia_move::bound; + return lia_move::branch; // branch on a free column } + if (m_found_free_var_in_gomory_row || !is_gomory_cut_target()) { + m_found_free_var_in_gomory_row = false; + delete m_iter_on_gomory_row; + m_iter_on_gomory_row = nullptr; + return lia_move::continue_with_check; + } + delete m_iter_on_gomory_row; m_iter_on_gomory_row = nullptr; return mk_gomory_cut(ex); @@ -317,7 +335,9 @@ lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& e lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { if (m_iter_on_gomory_row != nullptr) { - return proceed_with_gomory_cut(t, k, ex); + auto ret = proceed_with_gomory_cut(t, k, ex); + if (ret != lia_move::continue_with_check) + return ret; } init_check_data(); @@ -343,7 +363,7 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { return lia_move::ok; - if ((++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) { + if (true || (++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) { move_non_base_vars_to_bounds(); lp_status st = m_lar_solver->find_feasible_solution(); if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { @@ -641,7 +661,8 @@ linear_combination_iterator * int_solver::get_column_iterator(unsigned j) { int_solver::int_solver(lar_solver* lar_slv) : m_lar_solver(lar_slv), m_branch_cut_counter(0), - m_iter_on_gomory_row(nullptr) { + m_iter_on_gomory_row(nullptr), + m_found_free_var_in_gomory_row(false) { lp_assert(m_old_values_set.size() == 0); m_old_values_set.resize(lar_slv->A_r().column_count()); m_old_values_data.resize(lar_slv->A_r().column_count(), zero_of_type()); @@ -832,6 +853,23 @@ bool int_solver::is_free(unsigned j) const { return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::free_column; } +bool int_solver::at_bound(unsigned j) const { + auto & mpq_solver = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; + switch (mpq_solver.m_column_types[j] ) { + case column_type::boxed: + return + mpq_solver.m_low_bounds[j] == get_value(j) || + mpq_solver.m_upper_bounds[j] == get_value(j); + case column_type::low_bound: + return mpq_solver.m_low_bounds[j] == get_value(j); + case column_type::upper_bound: + return mpq_solver.m_upper_bounds[j] == get_value(j); + default: + return false; + } +} + + lp_settings& int_solver::settings() { return m_lar_solver->settings(); diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 1ae0ecbd8..b4179fe9a 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -18,7 +18,7 @@ enum class lia_move { branch, cut, conflict, - bound, + continue_with_check, give_up }; @@ -36,6 +36,7 @@ public: unsigned m_branch_cut_counter; linear_combination_iterator* m_iter_on_gomory_row; unsigned m_gomory_cut_inf_column; + bool m_found_free_var_in_gomory_row; // methods int_solver(lar_solver* lp); // main function to check that solution provided by lar_solver is valid for integral values, @@ -106,5 +107,7 @@ private: bool constrain_free_vars(linear_combination_iterator * r); lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex); int find_next_free_var_in_gomory_row(); + bool is_gomory_cut_target(); + bool at_bound(unsigned j) const; }; } From 8750da1da7f04f17be650cd440a594f6f93da02c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 12 Jul 2017 16:43:10 -0700 Subject: [PATCH 0209/1283] progress in gomory cut Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 2 + src/util/lp/int_solver.cpp | 221 +++++++++++++++++++++---------------- src/util/lp/int_solver.h | 20 ++++ src/util/lp/lar_solver.h | 4 +- 4 files changed, 149 insertions(+), 98 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index e2b4ea944..c5da28df2 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -105,6 +105,7 @@ namespace lp_api { unsigned m_bound_propagations1; unsigned m_bound_propagations2; unsigned m_assert_diseq; + unsigned m_gomory_cuts; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); @@ -1253,6 +1254,7 @@ namespace smt { return l_false; } case lp::lia_move::cut: { + ++m_stats.m_gomory_cuts; // m_explanation implies term <= k app_ref b = mk_bound(term, k); m_eqs.reset(); diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 62bdc0e32..56037c841 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -5,6 +5,7 @@ #include "util/lp/int_solver.h" #include "util/lp/lar_solver.h" +#include "util/lp/antecedents.h" namespace lp { void int_solver::fix_non_base_columns() { @@ -128,108 +129,107 @@ bool int_solver::is_gomory_cut_target() { return true; } + +void int_solver::is_real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, buffer & pol) { + mpq f_0 = fractional_part(get_value(m_gomory_cut_inf_column)); + mpq new_a; + if (at_lower(x_j)) { + if (a.is_pos()) { + new_a = a / (mpq(1) - f_0); + } + else { + new_a = a / f_0; + new_a.neg(); + } + k += lower_bound(x_j).x * k; // k.addmul(new_a, lower_bound(x_j).x); // is it a faster operation + // lower(x_j)->push_justification(ante, new_a, coeffs_enabled());*/ + } + else { + lp_assert(at_upper(x_j)); + if (a.is_pos()) { + new_a = a / f_0; + new_a.neg(); // the upper terms are inverted. + } + else { + new_a = a / (mpq(1) - f_0); + } + k += upper_bound(x_j).x * k; // k.addmul(new_a, upper_bound(x_j).get_rational()); + // upper(x_j)->push_justification(ante, new_a, coeffs_enabled());*/ + } + TRACE("gomory_cut_detail", tout << a << "*v" << x_j << " k: " << k << "\n";); + pol.push_back(row_entry(new_a, x_j)); +} +void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, buffer & pol) { + /* + ++num_ints; + SASSERT(is_int(x_j)); + mpq f_j = Ext::fractional_part(a); + TRACE("gomory_cut_detail", + tout << a << "*v" << x_j << "\n"; + tout << "fractional_part: " << Ext::fractional_part(a) << "\n"; + tout << "f_j: " << f_j << "\n"; + tout << "f_0: " << f_0 << "\n"; + tout << "one_minus_f_0: " << one_minus_f_0 << "\n";); + if (!f_j.is_zero()) { + mpq new_a; + if (at_lower(x_j)) { + if (f_j <= one_minus_f_0) { + new_a = f_j / one_minus_f_0; + } + else { + new_a = (mpq(1) - f_j) / f_0; + } + k.addmul(new_a, lower_bound(x_j).get_rational()); + lower(x_j)->push_justification(ante, new_a, coeffs_enabled()); + } + else { + SASSERT(at_upper(x_j)); + if (f_j <= f_0) { + new_a = f_j / f_0; + } + else { + new_a = (mpq(1) - f_j) / one_minus_f_0; + } + new_a.neg(); // the upper terms are inverted + k.addmul(new_a, upper_bound(x_j).get_rational()); + upper(x_j)->push_justification(ante, new_a, coeffs_enabled()); + } + TRACE("gomory_cut_detail", tout << "new_a: " << new_a << " k: " << k << "\n";); + pol.push_back(row_entry(new_a, x_j)); + lcm_den = lcm(lcm_den, denominator(new_a)); + }*/ +} + lia_move int_solver::mk_gomory_cut(explanation & ex) { lp_assert(column_is_int_inf(m_gomory_cut_inf_column)); - return lia_move::give_up; - - /* - TRACE("gomory_cut", tout << "applying cut at:\n"; display_row_info(tout, r);); + TRACE("gomory_cut", tout << "applying cut at:\n"; m_lar_solver->print_linear_iterator(m_iter_on_gomory_row, tout); tout << "\n";); - antecedents ante(*this); - - m_stats.m_gomory_cuts++; - + antecedents ante(); // gomory will be pol >= k - numeral k(1); + mpq k(1); buffer pol; - - numeral f_0 = Ext::fractional_part(m_value[x_i]); - numeral one_minus_f_0 = numeral(1) - f_0; - SASSERT(!f_0.is_zero()); - SASSERT(!one_minus_f_0.is_zero()); - - numeral lcm_den(1); + + mpq f_0 = fractional_part(get_value(m_gomory_cut_inf_column)); + mpq one_minus_f_0 = mpq(1) - f_0; + lp_assert(!is_zero(f_0) && !is_zero(one_minus_f_0)); + mpq lcm_den(1); unsigned num_ints = 0; + unsigned x_j; + mpq a; - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) { - if (!it->is_dead() && it->m_var != x_i) { - theory_var x_j = it->m_var; - numeral a_ij = it->m_coeff; - a_ij.neg(); // make the used format compatible with the format used in: Integrating Simplex with DPLL(T) - if (is_real(x_j)) { - numeral new_a_ij; - if (at_lower(x_j)) { - if (a_ij.is_pos()) { - new_a_ij = a_ij / one_minus_f_0; - } - else { - new_a_ij = a_ij / f_0; - new_a_ij.neg(); - } - k.addmul(new_a_ij, lower_bound(x_j).get_rational()); - lower(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); - } - else { - SASSERT(at_upper(x_j)); - if (a_ij.is_pos()) { - new_a_ij = a_ij / f_0; - new_a_ij.neg(); // the upper terms are inverted. - } - else { - new_a_ij = a_ij / one_minus_f_0; - } - k.addmul(new_a_ij, upper_bound(x_j).get_rational()); - upper(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); - } - TRACE("gomory_cut_detail", tout << a_ij << "*v" << x_j << " k: " << k << "\n";); - pol.push_back(row_entry(new_a_ij, x_j)); - } - else { - ++num_ints; - SASSERT(is_int(x_j)); - numeral f_j = Ext::fractional_part(a_ij); - TRACE("gomory_cut_detail", - tout << a_ij << "*v" << x_j << "\n"; - tout << "fractional_part: " << Ext::fractional_part(a_ij) << "\n"; - tout << "f_j: " << f_j << "\n"; - tout << "f_0: " << f_0 << "\n"; - tout << "one_minus_f_0: " << one_minus_f_0 << "\n";); - if (!f_j.is_zero()) { - numeral new_a_ij; - if (at_lower(x_j)) { - if (f_j <= one_minus_f_0) { - new_a_ij = f_j / one_minus_f_0; - } - else { - new_a_ij = (numeral(1) - f_j) / f_0; - } - k.addmul(new_a_ij, lower_bound(x_j).get_rational()); - lower(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); - } - else { - SASSERT(at_upper(x_j)); - if (f_j <= f_0) { - new_a_ij = f_j / f_0; - } - else { - new_a_ij = (numeral(1) - f_j) / one_minus_f_0; - } - new_a_ij.neg(); // the upper terms are inverted - k.addmul(new_a_ij, upper_bound(x_j).get_rational()); - upper(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); - } - TRACE("gomory_cut_detail", tout << "new_a_ij: " << new_a_ij << " k: " << k << "\n";); - pol.push_back(row_entry(new_a_ij, x_j)); - lcm_den = lcm(lcm_den, denominator(new_a_ij)); - } - } - } + while (m_iter_on_gomory_row->next(a, x_j)) { + if (x_j == m_gomory_cut_inf_column) + continue; + // make the format compatible with the format used in: Integrating Simplex with DPLL(T) + a.neg(); + if (is_real(x_j)) + is_real_case_in_gomory_cut(a, x_j, k, pol); + else + int_case_in_gomory_cut(a, x_j, k, pol); } - + /* CTRACE("empty_pol", pol.empty(), display_row_info(tout, r);); expr_ref bound(get_manager()); @@ -276,8 +276,8 @@ lia_move int_solver::mk_gomory_cut(explanation & ex) { } tout << "k: " << k << "\n";); } - mk_polynomial_ge(pol.size(), pol.c_ptr(), k.to_rational(), bound); - } + mk_polynomial_ge(pol.size(), pol.c_ptr(), k.to_rational(), bound); */ + /* TRACE("gomory_cut", tout << "new cut:\n" << bound << "\n"; ante.display(tout);); literal l = null_literal; context & ctx = get_context(); @@ -292,6 +292,7 @@ lia_move int_solver::mk_gomory_cut(explanation & ex) { ante.eqs().size(), ante.eqs().c_ptr(), ante, l))); return true; */ + return lia_move::give_up; } void int_solver::init_check_data() { @@ -327,9 +328,10 @@ lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& e return lia_move::continue_with_check; } + lia_move ret = mk_gomory_cut(ex); delete m_iter_on_gomory_row; m_iter_on_gomory_row = nullptr; - return mk_gomory_cut(ex); + return ret; } @@ -792,6 +794,10 @@ bool int_solver::is_int(unsigned j) const { return m_lar_solver->column_is_int(j); } +bool int_solver::is_real(unsigned j) const { + return !is_int(j); +} + bool int_solver::value_is_int(unsigned j) const { return m_lar_solver->m_mpq_lar_core_solver.m_r_x[j].is_int(); } @@ -856,6 +862,7 @@ bool int_solver::is_free(unsigned j) const { bool int_solver::at_bound(unsigned j) const { auto & mpq_solver = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; switch (mpq_solver.m_column_types[j] ) { + case column_type::fixed: case column_type::boxed: return mpq_solver.m_low_bounds[j] == get_value(j) || @@ -869,6 +876,30 @@ bool int_solver::at_bound(unsigned j) const { } } +bool int_solver::at_lower(unsigned j) const { + auto & mpq_solver = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; + switch (mpq_solver.m_column_types[j] ) { + case column_type::fixed: + case column_type::boxed: + case column_type::low_bound: + return mpq_solver.m_low_bounds[j] == get_value(j); + default: + return false; + } +} + +bool int_solver::at_upper(unsigned j) const { + auto & mpq_solver = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; + switch (mpq_solver.m_column_types[j] ) { + case column_type::fixed: + case column_type::boxed: + case column_type::upper_bound: + return mpq_solver.m_upper_bounds[j] == get_value(j); + default: + return false; + } +} + lp_settings& int_solver::settings() { diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index b4179fe9a..22d37d9a6 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -27,6 +27,11 @@ struct explanation { }; class int_solver { + struct row_entry { + mpq m_coeff; + unsigned m_var; + row_entry(const mpq & coeff, unsigned var) : m_coeff(coeff), m_var(var) {} + }; public: // fields lar_solver *m_lar_solver; @@ -82,6 +87,7 @@ private: const impq & lower_bound(unsigned j) const; const impq & upper_bound(unsigned j) const; bool is_int(unsigned j) const; + bool is_real(unsigned j) const; bool is_base(unsigned j) const; bool is_boxed(unsigned j) const; bool is_free(unsigned j) const; @@ -109,5 +115,19 @@ private: int find_next_free_var_in_gomory_row(); bool is_gomory_cut_target(); bool at_bound(unsigned j) const; + bool at_lower(unsigned j) const; + bool at_upper(unsigned j) const; + + inline static bool is_rational(const impq & n) { + return is_zero(n.y); + } + + inline static + mpq fractional_part(const impq & n) { + lp_assert(is_rational); + return n.x - floor(n.x); + } + void is_real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, buffer & pol); + void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, buffer & pol); }; } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 2249beaa1..491bc0167 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -414,9 +414,7 @@ public: return v.is_int(); } - - - bool column_is_real(unsigned j) const { + bool column_is_real(unsigned j) const { return !column_is_int(j); } From 1931adcb74ee559cedd94fa6b68f106664e5ce90 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 13 Jul 2017 09:48:29 -0700 Subject: [PATCH 0210/1283] add a file Signed-off-by: Lev Nachmanson --- src/util/lp/antecedents.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/util/lp/antecedents.h diff --git a/src/util/lp/antecedents.h b/src/util/lp/antecedents.h new file mode 100644 index 000000000..e96c92614 --- /dev/null +++ b/src/util/lp/antecedents.h @@ -0,0 +1,10 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ +#pragma once + +namespace lp { +class antecedents { +}; +} From 8c67e958fff788b3234b1f4c50f1a2b4e743ec0a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 16 Jul 2017 18:51:01 +0200 Subject: [PATCH 0211/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 655 +++++++++++++++++++------------------ src/sat/ba_solver.h | 4 +- src/sat/sat_asymm_branch.h | 2 +- 3 files changed, 335 insertions(+), 326 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 7f2ae5e89..242ecb590 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -24,6 +24,9 @@ Revision History: namespace sat { + static unsigned _bad_id = 11111111; // 2759; // +#define BADLOG(_cmd_) if (p.id() == _bad_id) { _cmd_; } + ba_solver::card& ba_solver::constraint::to_card() { SASSERT(is_card()); return static_cast(*this); @@ -150,7 +153,6 @@ namespace sat { for (unsigned i = 0; i < size(); ++i) { m_wlits[i].first = std::min(k(), m_wlits[i].first); if (m_max_sum + m_wlits[i].first < m_max_sum) { - std::cout << "update-max-sum overflows\n"; throw default_exception("addition of pb coefficients overflows"); } m_max_sum += m_wlits[i].first; @@ -326,10 +328,161 @@ namespace sat { } // ------------------- - // pb + // pb_base - static unsigned _bad_id = 11111111; // 2759; // -#define BADLOG(_cmd_) if (p.id() == _bad_id) { _cmd_; } + void ba_solver::simplify(pb_base& p) { + SASSERT(s().at_base_lvl()); + if (p.lit() != null_literal && value(p.lit()) == l_false) { + TRACE("sat", tout << "pb: flip sign " << p << "\n";); + IF_VERBOSE(0, verbose_stream() << "sign is flipped " << p << "\n";); + return; + init_watch(p, !p.lit().sign()); + } + bool nullify = p.lit() != null_literal && value(p.lit()) == l_true; + if (nullify) { + SASSERT(lvl(p.lit()) == 0); + nullify_tracking_literal(p); + } + + SASSERT(p.lit() == null_literal || value(p.lit()) == l_undef); + + unsigned true_val = 0, slack = 0, num_false = 0; + for (unsigned i = 0; i < p.size(); ++i) { + literal l = p.get_lit(i); + switch (value(l)) { + case l_true: true_val += p.get_coeff(i); break; + case l_false: ++num_false; break; + default: slack += p.get_coeff(i); break; + } + } + if (p.k() == 1 && p.lit() == null_literal) { + literal_vector lits(p.literals()); + s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + remove_constraint(p); + } + else if (true_val == 0 && num_false == 0) { + if (nullify) { + init_watch(p, true); + } + } + else if (true_val >= p.k()) { + if (p.lit() != null_literal) { + s().assign(p.lit(), justification()); + } + remove_constraint(p); + } + else if (slack + true_val < p.k()) { + if (p.lit() != null_literal) { + s().assign(~p.lit(), justification()); + } + else { + IF_VERBOSE(0, verbose_stream() << "unsat during simplification\n";); + s().set_conflict(justification()); + } + remove_constraint(p); + } + else if (slack + true_val == p.k()) { + literal_vector lits(p.literals()); + assert_unconstrained(p.lit(), lits); + remove_constraint(p); + } + else { + unsigned sz = p.size(); + clear_watch(p); + for (unsigned i = 0; i < sz; ++i) { + literal l = p.get_lit(i); + if (value(l) != l_undef) { + --sz; + p.swap(i, sz); + --i; + } + } + BADLOG(display(verbose_stream() << "simplify ", p, true)); + p.set_size(sz); + p.set_k(p.k() - true_val); + BADLOG(display(verbose_stream() << "simplified ", p, true)); + // display(verbose_stream(), c, true); + + if (p.k() == 1 && p.lit() == null_literal) { + literal_vector lits(p.literals()); + s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + remove_constraint(p); + return; + } + else if (p.lit() == null_literal) { + init_watch(p, true); + } + else { + SASSERT(value(p.lit()) == l_undef); + } + SASSERT(p.well_formed()); + if (p.is_pb()) simplify2(p.to_pb()); + m_simplify_change = true; + } + } + + /* + \brief slit PB constraint into two because root is reused in arguments. + + x <=> a*x + B*y >= k + + x => a*x + By >= k + ~x => a*x + By < k + + k*~x + a*x + By >= k + (B+a-k + 1)*x + a*~x + B*~y >= B + a - k + 1 + + (k - a) * ~x + By >= k - a + k' * x + B'y >= k' + + */ + + void ba_solver::split_root(pb_base& p) { + SASSERT(p.lit() != null_literal); + SASSERT(!p.learned()); + m_weights.resize(2*s().num_vars(), 0); + unsigned k = p.k(); + unsigned w, w1, w2; + literal root = p.lit(); + m_weights[(~root).index()] = k; + for (unsigned i = 0; i < p.size(); ++i) { + m_weights[p.get_lit(i).index()] += p.get_coeff(i); + } + literal_vector lits(p.literals()); + lits.push_back(~root); + + for (literal l : lits) { + w1 = m_weights[l.index()]; + w2 = m_weights[(~l).index()]; + if (w1 >= w2) { + if (w2 >= k) { + // constraint is true + return; + } + k -= w2; + m_weights[(~l).index()] = 0; + m_weights[l.index()] = w1 - w2; + } + } + SASSERT(k > 0); + + // ~root * (k - a) + p >= k - a + + m_wlits.reset(); + for (literal l : lits) { + w = m_weights[l.index()]; + if (w != 0) { + m_wlits.push_back(wliteral(w, l)); + } + m_weights[l.index()] = 0; + } + + add_pb_ge(null_literal, m_wlits, k, false); + } + + + // ------------------- + // pb // watch a prefix of literals, such that the slack of these is >= k @@ -359,7 +512,7 @@ namespace sat { ++j; } } - BADLOG(std::cout << "watch " << num_watch << " out of " << sz << "\n"); + BADLOG(verbose_stream() << "watch " << num_watch << " out of " << sz << "\n"); DEBUG_CODE( bool is_false = false; @@ -445,7 +598,7 @@ namespace sat { */ lbool ba_solver::add_assign(pb& p, literal alit) { - BADLOG(display(std::cout << "assign: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); + BADLOG(display(verbose_stream() << "assign: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); SASSERT(!inconsistent()); unsigned sz = p.size(); @@ -468,10 +621,11 @@ namespace sat { } if (index == num_watch || num_watch == 0) { _bad_id = p.id(); - std::cout << "BAD: " << p.id() << "\n"; - display(std::cout, p, true); - std::cout << "alit: " << alit << "\n"; - std::cout << "num watch " << num_watch << "\n"; + BADLOG( + verbose_stream() << "BAD: " << p.id() << "\n"; + display(verbose_stream(), p, true); + verbose_stream() << "alit: " << alit << "\n"; + verbose_stream() << "num watch " << num_watch << "\n"); exit(0); return l_undef; } @@ -498,7 +652,7 @@ namespace sat { watch_literal(p[j], p); p.swap(num_watch, j); add_index(p, num_watch, lit); - BADLOG(std::cout << "add watch: " << lit << " num watch: " << num_watch << "\n"); + BADLOG(verbose_stream() << "add watch: " << lit << " num watch: " << num_watch << "\n"); ++num_watch; } } @@ -512,7 +666,7 @@ namespace sat { p.set_slack(slack); p.set_num_watch(num_watch); validate_watch(p); - BADLOG(display(std::cout << "conflict: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); + BADLOG(display(verbose_stream() << "conflict: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); SASSERT(bound <= slack); TRACE("sat", tout << "conflict " << alit << "\n";); set_conflict(p, alit); @@ -521,7 +675,7 @@ namespace sat { if (num_watch == 1) { _bad_id = p.id(); } - BADLOG(std::cout << "size: " << p.size() << " index: " << index << " num watch: " << num_watch << "\n"); + BADLOG(verbose_stream() << "size: " << p.size() << " index: " << index << " num watch: " << num_watch << "\n"); // swap out the watched literal. --num_watch; @@ -544,7 +698,7 @@ namespace sat { wliteral wl = p[index1]; literal lit = wl.second; SASSERT(value(lit) == l_undef); - BADLOG(std::cout << "Assign " << lit << "\n"); + BADLOG(verbose_stream() << "Assign " << lit << "\n"); if (slack < bound + wl.first) { assign(p, lit); } @@ -553,7 +707,7 @@ namespace sat { TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); - BADLOG(std::cout << "unwatch " << alit << " watch: " << p.num_watch() << " size: " << p.size() << " slack: " << p.slack() << " " << inconsistent() << "\n"); + BADLOG(verbose_stream() << "unwatch " << alit << " watch: " << p.num_watch() << " size: " << p.size() << " slack: " << p.slack() << " " << inconsistent() << "\n"); return l_undef; } @@ -569,29 +723,81 @@ namespace sat { p.set_num_watch(0); } - /* - \brief lit <=> conjunction of unconstrained lits - */ - void ba_solver::assert_unconstrained(literal lit, literal_vector const& lits) { - if (lit == null_literal) { - for (literal l : lits) { - if (value(l) == l_undef) { - s().assign(l, justification()); + void ba_solver::recompile(pb& p) { + // IF_VERBOSE(2, verbose_stream() << "re: " << p << "\n";); + SASSERT(p.num_watch() == 0); + m_weights.resize(2*s().num_vars(), 0); + for (wliteral wl : p) { + m_weights[wl.second.index()] += wl.first; + } + unsigned k = p.k(); + unsigned sz = p.size(); + bool all_units = true; + for (unsigned i = 0; i < sz && 0 < k; ++i) { + literal l = p[i].second; + unsigned w1 = m_weights[l.index()]; + unsigned w2 = m_weights[(~l).index()]; + if (w1 == 0 || w1 < w2) { + p.swap(i, sz - 1); + --sz; + --i; + } + else if (k <= w2) { + k = 0; + break; + } + else { + SASSERT(w2 <= w1 && w2 < k); + k -= w2; + w1 -= w2; + m_weights[l.index()] = 0; + m_weights[(~l).index()] = 0; + if (w1 == 0) { + p.swap(i, sz - 1); + --sz; + --i; + } + else { + p[i] = wliteral(w1, l); + all_units &= w1 == 1; } } } - else { - // add clauses for: lit <=> conjunction of undef literals - SASSERT(value(lit) == l_undef); - literal_vector cl; - cl.push_back(lit); - for (literal l : lits) { - if (value(l) == l_undef) { - s().mk_clause(~lit, l); - cl.push_back(~l); - } - } - s().mk_clause(cl); + // clear weights + for (wliteral wl : p) { + m_weights[wl.second.index()] = 0; + m_weights[(~wl.second).index()] = 0; + } + + if (k == 0) { + if (p.lit() != null_literal) { + s().assign(p.lit(), justification()); + } + remove_constraint(p); + return; + } + + if (k == 1 && p.lit() == null_literal) { + literal_vector lits(p.literals()); + s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + remove_constraint(p); + return; + } + + if (all_units) { + literal_vector lits(p.literals()); + add_at_least(p.lit(), lits, k, p.learned()); + remove_constraint(p); + return; + } + + p.set_size(sz); + p.set_k(k); + SASSERT(p.well_formed()); + + // this could become a cardinality constraint by now. + if (p.lit() == null_literal || value(p.lit()) == l_true) { + init_watch(p, true); } } @@ -617,106 +823,6 @@ namespace sat { } } - void ba_solver::simplify(pb_base& p) { - SASSERT(s().at_base_lvl()); - if (p.lit() != null_literal && value(p.lit()) == l_false) { - TRACE("sat", tout << "pb: flip sign " << p << "\n";); - IF_VERBOSE(0, verbose_stream() << "sign is flipped " << p << "\n";); - return; - init_watch(p, !p.lit().sign()); - } - bool nullify = p.lit() != null_literal && value(p.lit()) == l_true; - if (nullify) { - SASSERT(lvl(p.lit()) == 0); - nullify_tracking_literal(p); - } - - SASSERT(p.lit() == null_literal || value(p.lit()) == l_undef); - - unsigned true_val = 0, slack = 0, num_false = 0; - for (unsigned i = 0; i < p.size(); ++i) { - literal l = p.get_lit(i); - switch (value(l)) { - case l_true: true_val += p.get_coeff(i); break; - case l_false: ++num_false; break; - default: slack += p.get_coeff(i); break; - } - } - if (p.k() == 1 && p.lit() == null_literal) { - literal_vector lits(p.literals()); - s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - remove_constraint(p); - } - else if (true_val == 0 && num_false == 0) { - if (nullify) { - init_watch(p, true); - } - } - else if (true_val >= p.k()) { - if (p.lit() != null_literal) { - s().assign(p.lit(), justification()); - } - remove_constraint(p); - } - else if (slack + true_val < p.k()) { - if (p.lit() != null_literal) { - s().assign(~p.lit(), justification()); - } - else { - IF_VERBOSE(0, verbose_stream() << "unsat during simplification\n";); - s().set_conflict(justification()); - } - remove_constraint(p); - } - else if (slack + true_val == p.k()) { - literal_vector lits(p.literals()); - assert_unconstrained(p.lit(), lits); - remove_constraint(p); - } - else { - unsigned sz = p.size(); - clear_watch(p); - for (unsigned i = 0; i < sz; ++i) { - literal l = p.get_lit(i); - if (value(l) != l_undef) { - --sz; - p.swap(i, sz); - --i; - } - } - BADLOG(display(std::cout << "simplify ", p, true)); - p.set_size(sz); - p.set_k(p.k() - true_val); - BADLOG(display(std::cout << "simplified ", p, true)); - // display(verbose_stream(), c, true); - - if (p.k() == 1 && p.lit() == null_literal) { - literal_vector lits(p.literals()); - s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - remove_constraint(p); - return; - } - else if (p.lit() == null_literal) { - init_watch(p, true); - } - else { - SASSERT(value(p.lit()) == l_undef); - } - SASSERT(p.well_formed()); - if (p.is_pb()) simplify2(p.to_pb()); - m_simplify_change = true; - } - } - - void ba_solver::display(std::ostream& out, constraint const& c, bool values) const { - switch (c.tag()) { - case card_t: display(out, c.to_card(), values); break; - case pb_t: display(out, c.to_pb(), values); break; - case xor_t: display(out, c.to_xor(), values); break; - default: UNREACHABLE(); break; - } - } - void ba_solver::display(std::ostream& out, pb const& p, bool values) const { if (p.lit() != null_literal) out << p.lit() << " == "; if (p.lit() != null_literal && values) { @@ -746,6 +852,7 @@ namespace sat { out << ">= " << p.k() << "\n"; } + // -------------------- // xor: @@ -889,8 +996,6 @@ namespace sat { int64 coeff1 = inc + coeff0; m_coeffs[v] = coeff1; if (coeff1 > INT_MAX || coeff1 < INT_MIN) { - std::cout << "overflow update coefficient " << coeff1 << " offset: " << offset << " coeff0: " << coeff0 << "\n"; - UNREACHABLE(); m_overflow = true; return; } @@ -927,7 +1032,6 @@ namespace sat { int ba_solver::get_int_coeff(bool_var v) const { int64 c = m_coeffs.get(v, 0); if (c < INT_MIN || c > INT_MAX) { - std::cout << "overflow " << c << "\n"; m_overflow = true; return 0; } @@ -942,7 +1046,8 @@ namespace sat { int64 new_bound = m_bound; new_bound += i; if (new_bound < 0) { - m_bound = 0; + // std::cout << "new negative bound " << new_bound << "\n"; + m_overflow = true; } else if (new_bound > UINT_MAX) { m_overflow = true; @@ -988,11 +1093,10 @@ namespace sat { do { - if (m_overflow || offset > (1 << 12) || m_bound == 0) { + if (m_overflow || offset > (1 << 12)) { IF_VERBOSE(20, verbose_stream() << "offset: " << offset << "\n"; active2pb(m_A); - display(verbose_stream(), m_A); - ); + display(verbose_stream(), m_A);); goto bail_out; } @@ -1007,9 +1111,10 @@ namespace sat { // DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); if (_debug_conflict) { - std::cout << consequent << "\n"; - s().display_justification(std::cout, js); - std::cout << "\n"; + IF_VERBOSE(0, + verbose_stream() << consequent << "\n"; + s().display_justification(verbose_stream(), js); + verbose_stream() << "\n";); _debug_consequent = consequent; } switch(js.get_kind()) { @@ -1068,8 +1173,8 @@ namespace sat { get_antecedents(consequent, p, m_lemma); TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";); if (_debug_conflict) { - std::cout << consequent << " "; - std::cout << "antecedents: " << m_lemma << "\n"; + verbose_stream() << consequent << " "; + verbose_stream() << "antecedents: " << m_lemma << "\n"; } for (literal l : m_lemma) process_antecedent(~l, offset); break; @@ -1188,13 +1293,14 @@ namespace sat { for (unsigned i = 0; i < lits.size(); ++i) { _debug_var2position[lits[i].var()] = i; } - // s().display(std::cout); - active2pb(m_A); - uint64 c = 0; - for (uint64 c1 : m_A.m_coeffs) c += c1; - std::cout << "sum of coefficients: " << c << "\n"; - display(std::cout, m_A, true); - std::cout << "conflicting literal: " << s().m_not_l << "\n"; + IF_VERBOSE(0, + active2pb(m_A); + uint64 c = 0; + for (uint64 c1 : m_A.m_coeffs) c += c1; + std::cout << "sum of coefficients: " << c << "\n"; + display(std::cout, m_A, true); + std::cout << "conflicting literal: " << s().m_not_l << "\n";); + for (literal l : lits) { if (s().is_marked(l.var())) { IF_VERBOSE(0, verbose_stream() << "missing mark: " << l << "\n";); @@ -1338,7 +1444,6 @@ namespace sat { uint64 offset1 = static_cast(offset) * c.k(); if (offset1 > UINT_MAX) { m_overflow = true; - std::cout << "cardinality offset overflow\n"; } else { process_antecedent(~lit, static_cast(offset1)); @@ -2120,9 +2225,7 @@ namespace sat { } void ba_solver::pop_reinit() { - // TBD: need a stack to follow backtracking order. unsigned sz = m_constraint_to_reinit_last_sz; - // if (sz < m_constraint_to_reinit.size()) std::cout << "REINIT " << s().scope_lvl() << " " << m_constraint_to_reinit.size() - sz << "\n"; for (unsigned i = sz; i < m_constraint_to_reinit.size(); ++i) { constraint* c = m_constraint_to_reinit[i]; if (!init_watch(*c, true) && !s().at_base_lvl()) { @@ -2173,15 +2276,17 @@ namespace sat { IF_VERBOSE(1, verbose_stream() << "(ba.simplify :trail " << trail_sz << " :vars " << s().num_vars() - trail_sz - << " :bin-subsumes " << m_stats.m_num_bin_subsumes - << " :clause-subsumes " << m_stats.m_num_clause_subsumes - << " :card-subsumes " << m_stats.m_num_card_subsumes + << " :constraints " << m_constraints.size() + << " :lemmas " << m_learned.size() + << " :subsumes " << m_stats.m_num_bin_subsumes + + m_stats.m_num_clause_subsumes + + m_stats.m_num_pb_subsumes + << " :gc " << m_stats.m_num_gc << ")\n";); // mutex_reduction(); // if (s().m_clauses.size() < 80000) lp_lookahead_reduction(); - // display(std::cout); } void ba_solver::mutex_reduction() { @@ -2319,11 +2424,13 @@ namespace sat { if (s().is_assumption(l.var())) { return false; } + m_root_vars.reserve(s().num_vars(), false); for (unsigned i = m_roots.size(); i < 2 * s().num_vars(); ++i) { m_roots.push_back(to_literal(i)); } m_roots[l.index()] = r; m_roots[(~l).index()] = ~r; + m_root_vars[l.var()] = true; return true; } @@ -2426,13 +2533,13 @@ namespace sat { if (!all_units) { TRACE("sat", tout << "replacing by pb: " << c << "\n";); - svector wlits; + m_wlits.reset(); for (unsigned i = 0; i < sz; ++i) { - wlits.push_back(wliteral(coeffs[i], c[i])); + m_wlits.push_back(wliteral(coeffs[i], c[i])); } literal root = c.lit(); remove_constraint(c); - add_pb_ge(root, wlits, k, c.learned()); + add_pb_ge(root, m_wlits, k, c.learned()); } else { if (c.lit() == null_literal || value(c.lit()) == l_true) { @@ -2451,147 +2558,12 @@ namespace sat { } } - /* - \brief slit PB constraint into two because root is reused in arguments. - - x <=> a*x + B*y >= k - - x => a*x + By >= k - ~x => a*x + By < k - - k*~x + a*x + By >= k - (B+a-k + 1)*x + a*~x + B*~y >= B + a - k + 1 - (k - a) * ~x + By >= k - a - k' * x + B'y >= k' - - */ - - void ba_solver::split_root(pb_base& p) { - SASSERT(p.lit() != null_literal); - SASSERT(!p.learned()); - m_weights.resize(2*s().num_vars(), 0); - unsigned k = p.k(); - unsigned w, w1, w2; - literal root = p.lit(); - m_weights[(~root).index()] = k; - for (unsigned i = 0; i < p.size(); ++i) { - m_weights[p.get_lit(i).index()] += p.get_coeff(i); - } - literal_vector lits(p.literals()); - lits.push_back(~root); - - for (literal l : lits) { - w1 = m_weights[l.index()]; - w2 = m_weights[(~l).index()]; - if (w1 >= w2) { - if (w2 >= k) { - // constraint is true - return; - } - k -= w2; - m_weights[(~l).index()] = 0; - m_weights[l.index()] = w1 - w2; - } - } - SASSERT(k > 0); - - // ~root * (k - a) + p >= k - a - - svector wlits; - for (literal l : lits) { - w = m_weights[l.index()]; - if (w != 0) { - wlits.push_back(wliteral(w, l)); - } - m_weights[l.index()] = 0; - } - - add_pb_ge(null_literal, wlits, k, false); - } - - void ba_solver::recompile(pb& p) { - // IF_VERBOSE(2, verbose_stream() << "re: " << p << "\n";); - SASSERT(p.num_watch() == 0); - m_weights.resize(2*s().num_vars(), 0); - for (wliteral wl : p) { - m_weights[wl.second.index()] += wl.first; - } - unsigned k = p.k(); - unsigned sz = p.size(); - bool all_units = true; - for (unsigned i = 0; i < sz && 0 < k; ++i) { - literal l = p[i].second; - unsigned w1 = m_weights[l.index()]; - unsigned w2 = m_weights[(~l).index()]; - if (w1 == 0 || w1 < w2) { - p.swap(i, sz - 1); - --sz; - --i; - } - else if (k <= w2) { - k = 0; - break; - } - else { - SASSERT(w2 <= w1 && w2 < k); - k -= w2; - w1 -= w2; - m_weights[l.index()] = 0; - m_weights[(~l).index()] = 0; - if (w1 == 0) { - p.swap(i, sz - 1); - --sz; - --i; - } - else { - p[i] = wliteral(w1, l); - all_units &= w1 == 1; - } - } - } - // clear weights - for (wliteral wl : p) { - m_weights[wl.second.index()] = 0; - m_weights[(~wl.second).index()] = 0; - } - - if (k == 0) { - if (p.lit() != null_literal) { - s().assign(p.lit(), justification()); - } - remove_constraint(p); - return; - } - - if (k == 1 && p.lit() == null_literal) { - literal_vector lits(p.literals()); - s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - remove_constraint(p); - return; - } - - if (all_units) { - literal_vector lits(p.literals()); - add_at_least(p.lit(), lits, k, p.learned()); - remove_constraint(p); - return; - } - - p.set_size(sz); - p.set_k(k); - SASSERT(p.well_formed()); - - // this could become a cardinality constraint by now. - if (p.lit() == null_literal || value(p.lit()) == l_true) { - init_watch(p, true); - } - } void ba_solver::flush_roots(constraint& c) { - bool found = c.lit() != null_literal && m_roots[c.lit().index()] != c.lit(); + bool found = c.lit() != null_literal && m_root_vars[c.lit().var()]; for (unsigned i = 0; !found && i < c.size(); ++i) { - found = m_roots[c.get_lit(i).index()] != c.get_lit(i); + found = m_root_vars[c.get_lit(i).var()]; } if (!found) return; clear_watch(c); @@ -2918,16 +2890,15 @@ namespace sat { all coefficients in A are <= B and k >= k' */ bool ba_solver::subsumes(pb const& p1, pb_base const& p2) { - if (p1.k() < p2.k()) return false; - unsigned num_marked = 0; + if (p1.k() < p2.k() || p1.size() > p2.size()) return false; + unsigned num_sub = 0; for (unsigned i = 0; i < p2.size(); ++i) { literal l = p2.get_lit(i); - if (is_marked(l)) { - ++num_marked; - if (m_weights[l.index()] > p2.get_coeff(i)) return false; + if (is_marked(l) && m_weights[l.index()] <= p2.get_coeff(i)) { + ++num_sub; } } - return num_marked == p1.size(); + return num_sub == p1.size(); } void ba_solver::subsumes(pb& p1, literal lit) { @@ -2945,7 +2916,7 @@ namespace sat { break; } if (s) { - ++m_stats.m_num_card_subsumes; + ++m_stats.m_num_pb_subsumes; p1.set_learned(false); remove_constraint(*c); } @@ -2978,7 +2949,7 @@ namespace sat { if (slit.empty()) { TRACE("sat", tout << "subsume cardinality\n" << c1.index() << ":" << c1 << "\n" << c2.index() << ":" << c2 << "\n";); remove_constraint(c2); - ++m_stats.m_num_card_subsumes; + ++m_stats.m_num_pb_subsumes; c1.set_learned(false); } else { @@ -3081,16 +3052,16 @@ namespace sat { return; } for (wliteral l : p1) { - mark_visited(l.second); SASSERT(m_weights[l.second.index()] == 0); m_weights[l.second.index()] = l.first; + mark_visited(l.second); } for (unsigned i = 0; i < p1.num_watch(); ++i) { subsumes(p1, p1[i].second); } for (wliteral l : p1) { - unmark_visited(l.second); m_weights[l.second.index()] = 0; + unmark_visited(l.second); } } @@ -3098,6 +3069,31 @@ namespace sat { lbool ba_solver::get_phase(bool_var v) { return l_undef; } + /* + \brief lit <=> conjunction of unconstrained lits + */ + void ba_solver::assert_unconstrained(literal lit, literal_vector const& lits) { + if (lit == null_literal) { + for (literal l : lits) { + if (value(l) == l_undef) { + s().assign(l, justification()); + } + } + } + else { + // add clauses for: lit <=> conjunction of undef literals + SASSERT(value(lit) == l_undef); + literal_vector cl; + cl.push_back(lit); + for (literal l : lits) { + if (value(l) == l_undef) { + s().mk_clause(~lit, l); + cl.push_back(~l); + } + } + s().mk_clause(cl); + } + } extension* ba_solver::copy(solver* s) { ba_solver* result = alloc(ba_solver); @@ -3253,6 +3249,15 @@ namespace sat { return out << index2constraint(idx); } + void ba_solver::display(std::ostream& out, constraint const& c, bool values) const { + switch (c.tag()) { + case card_t: display(out, c.to_card(), values); break; + case pb_t: display(out, c.to_pb(), values); break; + case xor_t: display(out, c.to_xor(), values); break; + default: UNREACHABLE(); break; + } + } + void ba_solver::collect_statistics(statistics& st) const { st.update("ba propagations", m_stats.m_num_propagations); st.update("ba conflicts", m_stats.m_num_conflicts); @@ -3349,7 +3354,7 @@ namespace sat { ba_solver::constraint* ba_solver::active2constraint() { reset_active_var_set(); - svector wlits; + m_wlits.reset(); uint64 sum = 0; if (m_bound == 1) return 0; if (m_overflow) return 0; @@ -3359,7 +3364,7 @@ namespace sat { if (m_active_var_set.contains(v) || coeff == 0) continue; m_active_var_set.insert(v); literal lit(v, coeff < 0); - wlits.push_back(wliteral(get_abs_coeff(v), lit)); + m_wlits.push_back(wliteral(get_abs_coeff(v), lit)); sum += get_abs_coeff(v); } @@ -3367,7 +3372,7 @@ namespace sat { return 0; } else { - return add_pb_ge(null_literal, wlits, m_bound, true); + return add_pb_ge(null_literal, m_wlits, m_bound, true); } } @@ -3404,15 +3409,15 @@ namespace sat { ba_solver::constraint* ba_solver::active2card() { normalize_active_coeffs(); - svector wlits; + m_wlits.reset(); for (bool_var v : m_active_vars) { int coeff = get_int_coeff(v); - wlits.push_back(std::make_pair(get_abs_coeff(v), literal(v, coeff < 0))); + m_wlits.push_back(std::make_pair(get_abs_coeff(v), literal(v, coeff < 0))); } - std::sort(wlits.begin(), wlits.end(), compare_wlit()); + std::sort(m_wlits.begin(), m_wlits.end(), compare_wlit()); unsigned k = 0; uint64 sum = 0, sum0 = 0; - for (wliteral wl : wlits) { + for (wliteral wl : m_wlits) { if (sum >= m_bound) break; sum0 = sum; sum += wl.first; @@ -3421,17 +3426,17 @@ namespace sat { if (k == 1) { return 0; } - while (!wlits.empty()) { - wliteral wl = wlits.back(); + while (!m_wlits.empty()) { + wliteral wl = m_wlits.back(); if (wl.first + sum0 >= m_bound) break; - wlits.pop_back(); + m_wlits.pop_back(); sum0 += wl.first; } unsigned slack = 0; unsigned max_level = 0; unsigned num_max_level = 0; - for (wliteral wl : wlits) { + for (wliteral wl : m_wlits) { if (value(wl.second) != l_false) ++slack; unsigned level = lvl(wl.second); if (level > max_level) { @@ -3456,12 +3461,12 @@ namespace sat { // produce asserting cardinality constraint literal_vector lits; - for (wliteral wl : wlits) lits.push_back(wl.second); + for (wliteral wl : m_wlits) lits.push_back(wl.second); constraint* c = add_at_least(null_literal, lits, k, true); if (c) { lits.reset(); - for (wliteral wl : wlits) { + for (wliteral wl : m_wlits) { if (value(wl.second) == l_false) lits.push_back(wl.second); } unsigned glue = s().num_diff_levels(lits.size(), lits.c_ptr()); @@ -3621,6 +3626,8 @@ namespace sat { tout << lits << "\n";); return value < p.m_k; } + + }; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 93c6f14e1..2496de593 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -38,7 +38,7 @@ namespace sat { unsigned m_num_resolves; unsigned m_num_bin_subsumes; unsigned m_num_clause_subsumes; - unsigned m_num_card_subsumes; + unsigned m_num_pb_subsumes; unsigned m_num_cut; unsigned m_num_gc; stats() { reset(); } @@ -242,7 +242,9 @@ namespace sat { bool m_clause_removed; bool m_constraint_removed; literal_vector m_roots; + svector m_root_vars; unsigned_vector m_weights; + svector m_wlits; bool subsumes(card& c1, card& c2, literal_vector& comp); bool subsumes(card& c1, clause& c2, literal_vector& comp); bool subsumed(card& c1, literal l1, literal l2); diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 4ad702c5c..0d4998107 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -52,7 +52,7 @@ namespace sat { void collect_statistics(statistics & st) const; void reset_statistics(); - void dec(unsigned c) { m_counter -= c; } + inline void dec(unsigned c) { m_counter -= c; } }; }; From 77171f4af8a995a775a6fb9fb1c6270991462442 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 17 Jul 2017 15:17:46 -0700 Subject: [PATCH 0212/1283] the first version of Gomory cut, probably broken Signed-off-by: Lev Nachmanson --- src/util/lp/antecedents.h | 10 -- src/util/lp/int_solver.cpp | 184 ++++++++++++++++++++----------------- src/util/lp/int_solver.h | 18 ++-- src/util/lp/lar_solver.cpp | 38 ++++---- src/util/lp/lar_solver.h | 13 ++- src/util/lp/lar_term.h | 17 +++- 6 files changed, 152 insertions(+), 128 deletions(-) delete mode 100644 src/util/lp/antecedents.h diff --git a/src/util/lp/antecedents.h b/src/util/lp/antecedents.h deleted file mode 100644 index e96c92614..000000000 --- a/src/util/lp/antecedents.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -#pragma once - -namespace lp { -class antecedents { -}; -} diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 56037c841..a6eea6021 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -5,7 +5,6 @@ #include "util/lp/int_solver.h" #include "util/lp/lar_solver.h" -#include "util/lp/antecedents.h" namespace lp { void int_solver::fix_non_base_columns() { @@ -114,7 +113,9 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { bool int_solver::is_gomory_cut_target() { m_iter_on_gomory_row->reset(); unsigned j; - TRACE("gomory_cut", m_lar_solver->print_linear_iterator(m_iter_on_gomory_row, tout);); + TRACE("gomory_cut", m_lar_solver->print_linear_iterator(m_iter_on_gomory_row, tout); + m_iter_on_gomory_row->reset(); + ); while (m_iter_on_gomory_row->next(j)) { // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). @@ -126,23 +127,25 @@ bool int_solver::is_gomory_cut_target() { return false; } } + m_iter_on_gomory_row->reset(); return true; } -void int_solver::is_real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, buffer & pol) { +void int_solver::real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& pol, explanation & expl) { mpq f_0 = fractional_part(get_value(m_gomory_cut_inf_column)); mpq new_a; if (at_lower(x_j)) { if (a.is_pos()) { - new_a = a / (mpq(1) - f_0); + new_a = a / (1 - f_0); } else { new_a = a / f_0; new_a.neg(); } k += lower_bound(x_j).x * k; // k.addmul(new_a, lower_bound(x_j).x); // is it a faster operation - // lower(x_j)->push_justification(ante, new_a, coeffs_enabled());*/ + + expl.push_justification(column_low_bound_constraint(x_j), new_a); } else { lp_assert(at_upper(x_j)); @@ -154,33 +157,43 @@ void int_solver::is_real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k new_a = a / (mpq(1) - f_0); } k += upper_bound(x_j).x * k; // k.addmul(new_a, upper_bound(x_j).get_rational()); - // upper(x_j)->push_justification(ante, new_a, coeffs_enabled());*/ + expl.push_justification(column_upper_bound_constraint(x_j), new_a); } TRACE("gomory_cut_detail", tout << a << "*v" << x_j << " k: " << k << "\n";); - pol.push_back(row_entry(new_a, x_j)); + pol.add_monoid(new_a, x_j); } -void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, buffer & pol) { - /* - ++num_ints; - SASSERT(is_int(x_j)); - mpq f_j = Ext::fractional_part(a); + +constraint_index int_solver::column_upper_bound_constraint(unsigned j) const { + return m_lar_solver->get_column_upper_bound_witness(j); +} + +constraint_index int_solver::column_low_bound_constraint(unsigned j) const { + return m_lar_solver->get_column_low_bound_witness(j); +} + + +void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term & pol, explanation& expl, mpq & lcm_den) { + mpq f_0 = fractional_part(get_value(m_gomory_cut_inf_column)); + lp_assert(is_int(x_j)); + mpq f_j = fractional_part(a); TRACE("gomory_cut_detail", tout << a << "*v" << x_j << "\n"; - tout << "fractional_part: " << Ext::fractional_part(a) << "\n"; + tout << "fractional_part: " << fractional_part(a) << "\n"; tout << "f_j: " << f_j << "\n"; tout << "f_0: " << f_0 << "\n"; - tout << "one_minus_f_0: " << one_minus_f_0 << "\n";); + tout << "one_minus_f_0: " << 1 - f_0 << "\n";); if (!f_j.is_zero()) { mpq new_a; if (at_lower(x_j)) { + auto one_minus_f_0 = 1 - f_0; if (f_j <= one_minus_f_0) { new_a = f_j / one_minus_f_0; } else { - new_a = (mpq(1) - f_j) / f_0; + new_a = (1 - f_j) / f_0; } - k.addmul(new_a, lower_bound(x_j).get_rational()); - lower(x_j)->push_justification(ante, new_a, coeffs_enabled()); + k.addmul(new_a, lower_bound(x_j).x); + expl.push_justification(column_low_bound_constraint(x_j), new_a); } else { SASSERT(at_upper(x_j)); @@ -188,111 +201,96 @@ void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, bu new_a = f_j / f_0; } else { - new_a = (mpq(1) - f_j) / one_minus_f_0; + new_a = (mpq(1) - f_j) / 1 - f_0; } new_a.neg(); // the upper terms are inverted - k.addmul(new_a, upper_bound(x_j).get_rational()); - upper(x_j)->push_justification(ante, new_a, coeffs_enabled()); + k.addmul(new_a, upper_bound(x_j).x); + expl.push_justification(column_upper_bound_constraint(x_j), new_a); } TRACE("gomory_cut_detail", tout << "new_a: " << new_a << " k: " << k << "\n";); - pol.push_back(row_entry(new_a, x_j)); + pol.add_monoid(new_a, x_j); lcm_den = lcm(lcm_den, denominator(new_a)); - }*/ + } } -lia_move int_solver::mk_gomory_cut(explanation & ex) { +lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl ) { lp_assert(column_is_int_inf(m_gomory_cut_inf_column)); - TRACE("gomory_cut", tout << "applying cut at:\n"; m_lar_solver->print_linear_iterator(m_iter_on_gomory_row, tout); tout << "\n";); + TRACE("gomory_cut", tout << "applying cut at:\n"; m_lar_solver->print_linear_iterator(m_iter_on_gomory_row, tout); tout << std::endl; m_iter_on_gomory_row->reset();); - antecedents ante(); - // gomory will be pol >= k - mpq k(1); - buffer pol; - - mpq f_0 = fractional_part(get_value(m_gomory_cut_inf_column)); - mpq one_minus_f_0 = mpq(1) - f_0; - lp_assert(!is_zero(f_0) && !is_zero(one_minus_f_0)); + // gomory will be t >= k + k = 1; mpq lcm_den(1); unsigned num_ints = 0; unsigned x_j; mpq a; - while (m_iter_on_gomory_row->next(a, x_j)) { if (x_j == m_gomory_cut_inf_column) continue; // make the format compatible with the format used in: Integrating Simplex with DPLL(T) a.neg(); if (is_real(x_j)) - is_real_case_in_gomory_cut(a, x_j, k, pol); - else - int_case_in_gomory_cut(a, x_j, k, pol); + real_case_in_gomory_cut(a, x_j, k, t, expl); + else { + num_ints++; + int_case_in_gomory_cut(a, x_j, k, t, expl, lcm_den); + } } - /* - CTRACE("empty_pol", pol.empty(), display_row_info(tout, r);); - expr_ref bound(get_manager()); - if (pol.empty()) { - SASSERT(k.is_pos()); + if (t.is_empty()) { + TRACE("empty_pol", + display_row_info(tout, + m_lar_solver->m_mpq_lar_core_solver.m_r_heading[m_gomory_cut_inf_column]);); + lp_assert(k.is_pos()); // conflict 0 >= k where k is positive - set_conflict(ante, ante, "gomory-cut"); - return true; + k.neg(); // returning 0 <= -k + return lia_move::conflict; } - else if (pol.size() == 1) { - theory_var v = pol[0].m_var; - k /= pol[0].m_coeff; - bool is_lower = pol[0].m_coeff.is_pos(); - if (is_int(v) && !k.is_int()) { + + auto pol = t.coeffs_as_vector(); + if (pol.size() == 1) { + unsigned j = pol[0].second; + k /= pol[0].first; + bool is_lower = pol[0].first.is_pos(); + if (is_int(j) && !k.is_int()) { k = is_lower?ceil(k):floor(k); } - rational _k = k.to_rational(); - if (is_lower) - bound = m_util.mk_ge(get_enode(v)->get_owner(), m_util.mk_numeral(_k, is_int(v))); - else - bound = m_util.mk_le(get_enode(v)->get_owner(), m_util.mk_numeral(_k, is_int(v))); - } - else { + if (is_lower) { // returning -t <= -k which is equivalent to t >= k + k.neg(); + t.negate(); + } + } else { if (num_ints > 0) { lcm_den = lcm(lcm_den, denominator(k)); TRACE("gomory_cut_detail", tout << "k: " << k << " lcm_den: " << lcm_den << "\n"; - for (unsigned i = 0; i < pol.size(); i++) { - tout << pol[i].m_coeff << " " << pol[i].m_var << "\n"; - } - tout << "k: " << k << "\n";); + linear_combination_iterator_on_vector pi(pol); + m_lar_solver->print_linear_iterator(&pi, tout); + tout << "\nk: " << k << "\n";); SASSERT(lcm_den.is_pos()); if (!lcm_den.is_one()) { // normalize coefficients of integer parameters to be integers. - unsigned n = pol.size(); - for (unsigned i = 0; i < n; i++) { - pol[i].m_coeff *= lcm_den; - SASSERT(!is_int(pol[i].m_var) || pol[i].m_coeff.is_int()); + for (auto & pi: pol) { + pi.first *= lcm_den; + SASSERT(!is_int(pi.second) || pi.first.is_int()); } k *= lcm_den; } TRACE("gomory_cut_detail", tout << "after *lcm\n"; for (unsigned i = 0; i < pol.size(); i++) { - tout << pol[i].m_coeff << " * v" << pol[i].m_var << "\n"; + tout << pol[i].first << " * v" << pol[i].second << "\n"; } tout << "k: " << k << "\n";); + t.clear(); + // negate everything to return -pol <= -k + for (const auto & pi: pol) + t.add_monoid(-pi.first, pi.second); + k.neg(); + } else { + lp_assert(false); // not sure what happens here } - mk_polynomial_ge(pol.size(), pol.c_ptr(), k.to_rational(), bound); */ - /* - TRACE("gomory_cut", tout << "new cut:\n" << bound << "\n"; ante.display(tout);); - literal l = null_literal; - context & ctx = get_context(); - ctx.internalize(bound, true); - l = ctx.get_literal(bound); - ctx.mark_as_relevant(l); - dump_lemmas(l, ante); - ctx.assign(l, ctx.mk_justification( - gomory_cut_justification( - get_id(), ctx.get_region(), - ante.lits().size(), ante.lits().c_ptr(), - ante.eqs().size(), ante.eqs().c_ptr(), ante, l))); - return true; - */ - return lia_move::give_up; + } + return lia_move::cut; } void int_solver::init_check_data() { @@ -317,7 +315,7 @@ lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& e if (j != -1) { m_found_free_var_in_gomory_row = true; lp_assert(t.is_empty()); - t.add_to_map(j, mpq(1)); + t.add_monoid(mpq(1), j); k = zero_of_type(); return lia_move::branch; // branch on a free column } @@ -328,7 +326,7 @@ lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& e return lia_move::continue_with_check; } - lia_move ret = mk_gomory_cut(ex); + lia_move ret = mk_gomory_cut(t, k, ex); delete m_iter_on_gomory_row; m_iter_on_gomory_row = nullptr; return ret; @@ -387,7 +385,7 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { TRACE("arith_int", tout << "j" << j << " does not have an integer assignment: " << get_value(j) << "\n";); lp_assert(t.is_empty()); - t.add_to_map(j, mpq(1)); + t.add_monoid(1, j); k = floor(get_value(j)); TRACE("arith_int", tout << "branching v" << j << " = " << get_value(j) << "\n"; display_column(tout, j); @@ -906,4 +904,22 @@ lp_settings& int_solver::settings() { return m_lar_solver->settings(); } +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; + auto it = m_lar_solver->get_iterator_on_row(row_index); + mpq a; + unsigned j; + while (it->next(a, j)) { + if (numeric_traits::is_pos(a)) + out << "+"; + out << a << rslv.column_name(j) << " "; + } + + it->reset(); + while(it->next(j)) { + rslv.print_column_bound_info(j, out); + } + rslv.print_column_bound_info(rslv.m_basis[row_index], out); + delete it; +} } diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 22d37d9a6..18b44dccb 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -8,7 +8,6 @@ #include "util/lp/iterator_on_row.h" #include "util/lp/int_set.h" #include "util/lp/lar_term.h" - namespace lp { class lar_solver; template @@ -24,14 +23,12 @@ enum class lia_move { struct explanation { vector> m_explanation; + void push_justification(constraint_index j, const mpq& v) { + m_explanation.push_back(std::make_pair(v, j)); + } }; class int_solver { - struct row_entry { - mpq m_coeff; - unsigned m_var; - row_entry(const mpq & coeff, unsigned var) : m_coeff(coeff), m_var(var) {} - }; public: // fields lar_solver *m_lar_solver; @@ -108,7 +105,7 @@ private: lp_settings& settings(); void move_non_base_vars_to_bounds(); void branch_infeasible_int_var(unsigned); - lia_move mk_gomory_cut(explanation & ex); + lia_move mk_gomory_cut(lar_term& t, mpq& k,explanation & ex); void init_check_data(); bool constrain_free_vars(linear_combination_iterator * r); lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex); @@ -127,7 +124,10 @@ private: lp_assert(is_rational); return n.x - floor(n.x); } - void is_real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, buffer & pol); - void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, buffer & pol); + void real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation & ex); + void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation& ex, mpq & lcm_den); + constraint_index column_upper_bound_constraint(unsigned j) const; + constraint_index column_low_bound_constraint(unsigned j) const; + void display_row_info(std::ostream & out, unsigned row_index) const; }; } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 3cef85ce2..451be98fe 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -237,7 +237,7 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp } int a_sign = is_pos(a)? 1: -1; int sign = j_sign * a_sign; - const ul_pair & ul = m_vars_to_ul_pairs[j]; + const ul_pair & ul = m_columns_to_ul_pairs[j]; auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); lp_assert(is_valid(witness)); bp.consume(a, witness); @@ -309,7 +309,7 @@ lp_status lar_solver::solve() { void lar_solver::fill_explanation_from_infeasible_column(vector> & evidence) const{ // this is the case when the lower bound is in conflict with the upper one - const ul_pair & ul = m_vars_to_ul_pairs[m_infeasible_column_index]; + const ul_pair & ul = m_columns_to_ul_pairs[m_infeasible_column_index]; evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); } @@ -325,7 +325,7 @@ vector lar_solver::get_list_of_all_var_indices() const { void lar_solver::push() { m_simplex_strategy = m_settings.simplex_strategy(); m_simplex_strategy.push(); - m_vars_to_ul_pairs.push(); + m_columns_to_ul_pairs.push(); m_infeasible_column_index.push(); m_mpq_lar_core_solver.push(); m_term_count = m_terms.size(); @@ -354,14 +354,14 @@ void lar_solver::pop(unsigned k) { int n_was = static_cast(m_ext_vars_to_columns.size()); m_infeasible_column_index.pop(k); - unsigned n = m_vars_to_ul_pairs.peek_size(k); + unsigned n = m_columns_to_ul_pairs.peek_size(k); for (unsigned j = n_was; j-- > n;) m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); m_columns_to_ext_vars_or_term_indices.resize(n); if (m_settings.use_tableau()) { pop_tableau(); } - m_vars_to_ul_pairs.pop(k); + m_columns_to_ul_pairs.pop(k); m_mpq_lar_core_solver.pop(k); clean_popped_elements(n, m_columns_with_changed_bound); @@ -531,15 +531,15 @@ void lar_solver::pop_core_solver_params(unsigned k) { void lar_solver::set_upper_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_vars_to_ul_pairs[j]; + ul_pair ul = m_columns_to_ul_pairs[j]; ul.upper_bound_witness() = ci; - m_vars_to_ul_pairs[j] = ul; + m_columns_to_ul_pairs[j] = ul; } void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_vars_to_ul_pairs[j]; + ul_pair ul = m_columns_to_ul_pairs[j]; ul.low_bound_witness() = ci; - m_vars_to_ul_pairs[j] = ul; + m_columns_to_ul_pairs[j] = ul; } void lar_solver::register_one_coeff_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j) { @@ -1041,11 +1041,11 @@ mpq lar_solver::sum_of_right_sides_of_explanation(const vector= m_vars_to_ul_pairs.size()) { + if (var >= m_columns_to_ul_pairs.size()) { // TBD: bounds on terms could also be used, caller may have to track these. return false; } - const ul_pair & ul = m_vars_to_ul_pairs[var]; + const ul_pair & ul = m_columns_to_ul_pairs[var]; ci = ul.low_bound_witness(); if (ci != static_cast(-1)) { auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; @@ -1060,11 +1060,11 @@ bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value bool lar_solver::has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - if (var >= m_vars_to_ul_pairs.size()) { + if (var >= m_columns_to_ul_pairs.size()) { // TBD: bounds on terms could also be used, caller may have to track these. return false; } - const ul_pair & ul = m_vars_to_ul_pairs[var]; + const ul_pair & ul = m_columns_to_ul_pairs[var]; ci = ul.upper_bound_witness(); if (ci != static_cast(-1)) { auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; @@ -1105,7 +1105,7 @@ void lar_solver::get_infeasibility_explanation_for_inf_sign( unsigned j = it.second; int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; - const ul_pair & ul = m_vars_to_ul_pairs[j]; + const ul_pair & ul = m_columns_to_ul_pairs[j]; constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); lp_assert(bound_constr_i < m_constraints.size()); @@ -1238,7 +1238,7 @@ void lar_solver::pop() { } bool lar_solver::column_represents_row_in_tableau(unsigned j) { - return m_vars_to_ul_pairs()[j].m_i != static_cast(-1); + return m_columns_to_ul_pairs()[j].m_i != static_cast(-1); } void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { @@ -1462,9 +1462,9 @@ var_index lar_solver::add_var(unsigned ext_j, bool is_int) { if (it != m_ext_vars_to_columns.end()) { return it->second.ext_j(); } - lp_assert(m_vars_to_ul_pairs.size() == A_r().column_count()); + lp_assert(m_columns_to_ul_pairs.size() == A_r().column_count()); i = A_r().column_count(); - m_vars_to_ul_pairs.push_back(ul_pair(static_cast(-1))); + m_columns_to_ul_pairs.push_back(ul_pair(static_cast(-1))); add_non_basic_var_to_core_fields(ext_j, is_int); lp_assert(sizes_are_correct()); return i; @@ -1568,7 +1568,7 @@ void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned // j will be a new variable unsigned j = A_r().column_count(); ul_pair ul(j); - m_vars_to_ul_pairs.push_back(ul); + m_columns_to_ul_pairs.push_back(ul); add_basic_var_to_core_fields(); if (use_tableau()) { auto it = iterator_on_term_with_basis_var(*term, j); @@ -1677,7 +1677,7 @@ void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned ter void lar_solver::decide_on_strategy_and_adjust_initial_state() { lp_assert(strategy_is_undecided()); - if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { + if (m_columns_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { m_settings.simplex_strategy() = simplex_strategy_enum::lu; } else { diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 491bc0167..9afb4180b 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -52,7 +52,7 @@ class lar_solver : public column_namer { stacked_value m_simplex_strategy; std::unordered_map m_ext_vars_to_columns; vector m_columns_to_ext_vars_or_term_indices; - stacked_vector m_vars_to_ul_pairs; + stacked_vector m_columns_to_ul_pairs; vector m_constraints; stacked_value m_constraint_count; // the set of column indices j such that bounds have changed for j @@ -433,7 +433,7 @@ public: } void get_bound_constraint_witnesses_for_column(unsigned j, constraint_index & lc, constraint_index & uc) const { - const ul_pair & ul = m_vars_to_ul_pairs[j]; + const ul_pair & ul = m_columns_to_ul_pairs[j]; lc = ul.low_bound_witness(); uc = ul.upper_bound_witness(); } @@ -453,6 +453,13 @@ public: return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index); } - + constraint_index get_column_upper_bound_witness(unsigned j) const { + return m_columns_to_ul_pairs()[j].upper_bound_witness(); + } + + constraint_index get_column_low_bound_witness(unsigned j) const { + return m_columns_to_ul_pairs()[j].low_bound_witness(); + } + }; } diff --git a/src/util/lp/lar_term.h b/src/util/lp/lar_term.h index 71320b7c3..dc3921767 100644 --- a/src/util/lp/lar_term.h +++ b/src/util/lp/lar_term.h @@ -10,7 +10,7 @@ struct lar_term { std::unordered_map m_coeffs; mpq m_v; lar_term() {} - void add_to_map(unsigned j, const mpq& c) { + void add_monoid(const mpq& c, unsigned j) { auto it = m_coeffs.find(j); if (it == m_coeffs.end()) { m_coeffs.emplace(j, c); @@ -34,7 +34,7 @@ struct lar_term { lar_term(const vector>& coeffs, const mpq & v) : m_v(v) { for (const auto & p : coeffs) { - add_to_map(p.second, p.first); + add_monoid(p.first, p.second); } } bool operator==(const lar_term & a) const { return false; } // take care not to create identical terms @@ -56,7 +56,7 @@ struct lar_term { if (it == m_coeffs.end()) return; const mpq & b = it->second; for (unsigned it_j :li.m_index) { - add_to_map(it_j, - b * li.m_data[it_j]); + add_monoid(- b * li.m_data[it_j], it_j); } m_coeffs.erase(it); } @@ -64,5 +64,16 @@ struct lar_term { bool contains(unsigned j) const { return m_coeffs.find(j) != m_coeffs.end(); } + + void negate() { + for (auto & t : m_coeffs) + t.second.neg(); + } + + void clear() { + m_coeffs.clear(); + m_v = zero_of_type(); + } + }; } From 729644a2b64a38d580f684d1cb4b53847cb56d0f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 17 Jul 2017 16:08:20 -0700 Subject: [PATCH 0213/1283] fix term_is_int 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 451be98fe..96313703a 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1413,7 +1413,7 @@ bool lar_solver::model_is_int_feasible() const { bool lar_solver::term_is_int(const lar_term * t) const { for (auto const & p : t->m_coeffs) - if (!column_is_int(p.first) || p.second.is_int()) + if (! (column_is_int(p.first) && p.second.is_int())) return false; return t->m_v.is_int(); } From 94b3fee6ac297e73a9185b5f52fd0e9717cd6954 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 17 Jul 2017 16:41:02 -0700 Subject: [PATCH 0214/1283] rename a function Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 1 + src/util/lp/lar_solver.cpp | 7 +++++++ src/util/lp/lar_solver.h | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index a6eea6021..9de63a6fc 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -336,6 +336,7 @@ lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& e lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { if (m_iter_on_gomory_row != nullptr) { auto ret = proceed_with_gomory_cut(t, k, ex); + TRACE("gomory_cut", tout << "term t = "; m_lar_solver->print_term_as_indices(t, tout);); if (ret != lia_move::continue_with_check) return ret; } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 96313703a..2e8631445 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1192,6 +1192,13 @@ void lar_solver::print_term(lar_term const& term, std::ostream & out) const { print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); } +void lar_solver::print_term_as_indices(lar_term const& term, std::ostream & out) const { + if (!numeric_traits::is_zero(term.m_v)) { + out << term.m_v << " + "; + } + print_linear_combination_of_column_indices_only(term.coeffs_as_vector(), out); +} + mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { mpq ret = cns.get_free_coeff_of_left_side(); for (auto & it : cns.get_left_side_coefficients()) { diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 9afb4180b..46af1ae63 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -381,12 +381,14 @@ public: void print_constraints(std::ostream& out) const ; - void print_terms(std::ostream& out) const ; + void print_terms(std::ostream& out) const; void print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const; void print_term(lar_term const& term, std::ostream & out) const; + void print_term_as_indices(lar_term const& term, std::ostream & out) const; + mpq get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const; void print_constraint(const lar_base_constraint * c, std::ostream & out) const; From 4d1b0d8026f6ea5b53bec45013167403e0dbad07 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 19 Jul 2017 16:50:23 -0700 Subject: [PATCH 0215/1283] gomory cut worked on a toy example Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 134 ++++++++++++++++++++++--------------- src/util/lp/int_solver.h | 4 ++ src/util/lp/lar_solver.cpp | 10 +-- src/util/lp/lar_solver.h | 18 +++-- 4 files changed, 104 insertions(+), 62 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 9de63a6fc..349393cc3 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -213,7 +213,82 @@ void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, la } } -lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl ) { +lia_move int_solver::report_conflict_from_gomory_cut(mpq & k) { + TRACE("empty_pol", + display_row_info(tout, + m_lar_solver->m_mpq_lar_core_solver.m_r_heading[m_gomory_cut_inf_column]);); + lp_assert(k.is_pos()); + // conflict 0 >= k where k is positive + k.neg(); // returning 0 <= -k + return lia_move::conflict; +} + +void int_solver::gomory_cut_adjust_t_and_k_for_size_gt_1( + vector> & pol, + lar_term & t, + mpq &k, + unsigned num_ints, + mpq & lcm_den) { + if (num_ints > 0) { + lcm_den = lcm(lcm_den, denominator(k)); + TRACE("gomory_cut_detail", tout << "k: " << k << " lcm_den: " << lcm_den << "\n"; + linear_combination_iterator_on_vector pi(pol); + m_lar_solver->print_linear_iterator(&pi, tout); + tout << "\nk: " << k << "\n";); + lp_assert(lcm_den.is_pos()); + if (!lcm_den.is_one()) { + // normalize coefficients of integer parameters to be integers. + for (auto & pi: pol) { + pi.first *= lcm_den; + SASSERT(!is_int(pi.second) || pi.first.is_int()); + } + k *= lcm_den; + } + TRACE("gomory_cut_detail", tout << "after *lcm_den\n"; + for (unsigned i = 0; i < pol.size(); i++) { + tout << pol[i].first << " * v" << pol[i].second << "\n"; + } + tout << "k: " << k << "\n";); + } + t.clear(); + // negate everything to return -pol <= -k + for (const auto & pi: pol) + t.add_monoid(-pi.first, pi.second); + k.neg(); +} + + +void int_solver::gomory_cut_adjust_t_and_k_for_size_1(const vector> & pol, lar_term& t, mpq &k) { + lp_assert(pol.size() == 1); + unsigned j = pol[0].second; + k /= pol[0].first; + bool is_lower = pol[0].first.is_pos(); + if (is_int(j) && !k.is_int()) { + k = is_lower?ceil(k):floor(k); + } + if (is_lower) { // returning -t <= -k which is equivalent to t >= k + k.neg(); + t.negate(); + } +} + + + +lia_move int_solver::report_gomory_cut(lar_term& t, mpq& k, mpq &lcm_den, unsigned num_ints) { + lp_assert(!t.is_empty()); + auto pol = t.coeffs_as_vector(); + if (pol.size() == 1) + gomory_cut_adjust_t_and_k_for_size_1(pol, t, k); + else + gomory_cut_adjust_t_and_k_for_size_gt_1(pol, t, k, num_ints, lcm_den); + m_lar_solver->subs_terms_for_debugging(t); // todo: remove later + return lia_move::cut; +} + + + + +lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl) { lp_assert(column_is_int_inf(m_gomory_cut_inf_column)); @@ -238,59 +313,11 @@ lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl ) { } } - if (t.is_empty()) { - TRACE("empty_pol", - display_row_info(tout, - m_lar_solver->m_mpq_lar_core_solver.m_r_heading[m_gomory_cut_inf_column]);); - lp_assert(k.is_pos()); - // conflict 0 >= k where k is positive - k.neg(); // returning 0 <= -k - return lia_move::conflict; - } + if (t.is_empty()) + return report_conflict_from_gomory_cut(k); - auto pol = t.coeffs_as_vector(); - if (pol.size() == 1) { - unsigned j = pol[0].second; - k /= pol[0].first; - bool is_lower = pol[0].first.is_pos(); - if (is_int(j) && !k.is_int()) { - k = is_lower?ceil(k):floor(k); - } - if (is_lower) { // returning -t <= -k which is equivalent to t >= k - k.neg(); - t.negate(); - } - } else { - if (num_ints > 0) { - lcm_den = lcm(lcm_den, denominator(k)); - TRACE("gomory_cut_detail", tout << "k: " << k << " lcm_den: " << lcm_den << "\n"; - linear_combination_iterator_on_vector pi(pol); - m_lar_solver->print_linear_iterator(&pi, tout); - tout << "\nk: " << k << "\n";); - SASSERT(lcm_den.is_pos()); - if (!lcm_den.is_one()) { - // normalize coefficients of integer parameters to be integers. - for (auto & pi: pol) { - pi.first *= lcm_den; - SASSERT(!is_int(pi.second) || pi.first.is_int()); - } - k *= lcm_den; - } - TRACE("gomory_cut_detail", tout << "after *lcm\n"; - for (unsigned i = 0; i < pol.size(); i++) { - tout << pol[i].first << " * v" << pol[i].second << "\n"; - } - tout << "k: " << k << "\n";); - t.clear(); - // negate everything to return -pol <= -k - for (const auto & pi: pol) - t.add_monoid(-pi.first, pi.second); - k.neg(); - } else { - lp_assert(false); // not sure what happens here - } - } - return lia_move::cut; + return report_gomory_cut(t, k, lcm_den, num_ints); + } void int_solver::init_check_data() { @@ -370,6 +397,7 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { return lia_move::give_up; } + init_inf_int_set(); // todo - can we avoid this call? int j = find_inf_int_base_column(); if (j != -1) { // setup the call for gomory cut diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 18b44dccb..53ae94ff8 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -106,6 +106,8 @@ private: void move_non_base_vars_to_bounds(); void branch_infeasible_int_var(unsigned); lia_move mk_gomory_cut(lar_term& t, mpq& k,explanation & ex); + lia_move report_conflict_from_gomory_cut(mpq & k); + lia_move report_gomory_cut(lar_term& t, mpq& k, mpq& lcm_den, unsigned num_ints); void init_check_data(); bool constrain_free_vars(linear_combination_iterator * r); lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex); @@ -129,5 +131,7 @@ private: constraint_index column_upper_bound_constraint(unsigned j) const; constraint_index column_low_bound_constraint(unsigned j) const; void display_row_info(std::ostream & out, unsigned row_index) const; + void gomory_cut_adjust_t_and_k_for_size_1(const vector> & pol, lar_term & t, mpq &k); + void gomory_cut_adjust_t_and_k_for_size_gt_1(vector> & pol, lar_term & t, mpq &k, unsigned num_ints, mpq &lcm_den); }; } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 2e8631445..e8235c839 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -542,7 +542,7 @@ void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) { m_columns_to_ul_pairs[j] = ul; } -void lar_solver::register_one_coeff_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j) { +void lar_solver::register_monoid_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j) { auto it = coeffs.find(j); if (it == coeffs.end()) { coeffs[j] = a; @@ -553,18 +553,18 @@ void lar_solver::register_one_coeff_in_map(std::unordered_map & void lar_solver::substitute_terms_in_linear_expression(const vector>& left_side_with_terms, - vector> &left_side, mpq & right_side) const { + vector> &left_side, mpq & free_coeff) const { std::unordered_map coeffs; for (auto & t : left_side_with_terms) { unsigned j = t.second; if (!is_term(j)) { - register_one_coeff_in_map(coeffs, t.first, j); + register_monoid_in_map(coeffs, t.first, j); } else { const lar_term & term = * m_terms[adjust_term_index(t.second)]; for (auto & p : term.coeffs()){ - register_one_coeff_in_map(coeffs, t.first * p.second , p.first); + register_monoid_in_map(coeffs, t.first * p.second , p.first); } - right_side += t.first * term.m_v; + free_coeff += t.first * term.m_v; } } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 46af1ae63..d6f55c612 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -149,8 +149,6 @@ public: lp_settings const & settings() const; void clear(); - - lar_solver(); void set_propagate_bounds_on_pivoted_rows_mode(bool v); @@ -263,7 +261,7 @@ public: void substitute_terms_in_linear_expression( const vector>& left_side_with_terms, - vector> &left_side, mpq & right_side) const; + vector> &left_side, mpq & free_coeff) const; void detect_rows_of_bound_change_column_for_nbasic_column(unsigned j); @@ -343,7 +341,7 @@ public: bool the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const; static void register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a); - static void register_one_coeff_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j); + static void register_monoid_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j); bool the_left_sides_sum_to_zero(const vector> & evidence) const; @@ -463,5 +461,17 @@ public: return m_columns_to_ul_pairs()[j].low_bound_witness(); } + void subs_terms_for_debugging(lar_term& t) { + vector> pol; + for (const auto & m : t.m_coeffs) { + pol.push_back(std::make_pair(m.second, adjust_column_index_to_term_index(m.first))); + } + mpq v = t.m_v; + + vector> pol_after_subs; + substitute_terms_in_linear_expression(pol, pol_after_subs, v); + t.clear(); + t = lar_term(pol_after_subs, v); + } }; } From 1490b7a15fc7a292d7774ce99c7874322e4f36f9 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 19 Jul 2017 22:14:05 -0700 Subject: [PATCH 0216/1283] a cleaner version of subs_term_columns Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 2 +- src/util/lp/lar_solver.h | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 349393cc3..793663bf1 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -281,7 +281,7 @@ lia_move int_solver::report_gomory_cut(lar_term& t, mpq& k, mpq &lcm_den, unsign gomory_cut_adjust_t_and_k_for_size_1(pol, t, k); else gomory_cut_adjust_t_and_k_for_size_gt_1(pol, t, k, num_ints, lcm_den); - m_lar_solver->subs_terms_for_debugging(t); // todo: remove later + m_lar_solver->subs_term_columns(t); return lia_move::cut; } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index d6f55c612..3a48c4d79 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -461,14 +461,16 @@ public: return m_columns_to_ul_pairs()[j].low_bound_witness(); } - void subs_terms_for_debugging(lar_term& t) { - vector> pol; + void subs_term_columns(lar_term& t) { + vector > pol; for (const auto & m : t.m_coeffs) { pol.push_back(std::make_pair(m.second, adjust_column_index_to_term_index(m.first))); } + + mpq v = t.m_v; - vector> pol_after_subs; + // todo : remove the call to substitute_terms_in_linear_expression substitute_terms_in_linear_expression(pol, pol_after_subs, v); t.clear(); t = lar_term(pol_after_subs, v); From 04824e737284670b424c84b978b0db6eee732dc6 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 20 Jul 2017 18:12:16 -0700 Subject: [PATCH 0217/1283] add a check in gomory cut Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 7 +++++++ src/util/lp/int_solver.h | 1 + src/util/lp/lar_solver.h | 2 -- src/util/lp/lar_term.h | 10 ++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 793663bf1..7753dd600 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -273,6 +273,12 @@ void int_solver::gomory_cut_adjust_t_and_k_for_size_1(const vectorm_mpq_lar_core_solver.m_r_x; + impq v = t.apply(x); + TRACE("gomory_cut", tout << "v = " << v << " k = " << k << std::endl;); + return v > k; +} lia_move int_solver::report_gomory_cut(lar_term& t, mpq& k, mpq &lcm_den, unsigned num_ints) { lp_assert(!t.is_empty()); @@ -282,6 +288,7 @@ lia_move int_solver::report_gomory_cut(lar_term& t, mpq& k, mpq &lcm_den, unsign else gomory_cut_adjust_t_and_k_for_size_gt_1(pol, t, k, num_ints, lcm_den); m_lar_solver->subs_term_columns(t); + lp_assert(current_solution_is_inf_on_cut(t, k)); return lia_move::cut; } diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 53ae94ff8..b5a7e74f5 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -133,5 +133,6 @@ private: void display_row_info(std::ostream & out, unsigned row_index) const; void gomory_cut_adjust_t_and_k_for_size_1(const vector> & pol, lar_term & t, mpq &k); void gomory_cut_adjust_t_and_k_for_size_gt_1(vector> & pol, lar_term & t, mpq &k, unsigned num_ints, mpq &lcm_den); + bool current_solution_is_inf_on_cut(const lar_term& t, const mpq& k) const; }; } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 3a48c4d79..31a33d9d3 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -466,8 +466,6 @@ public: for (const auto & m : t.m_coeffs) { pol.push_back(std::make_pair(m.second, adjust_column_index_to_term_index(m.first))); } - - mpq v = t.m_v; vector> pol_after_subs; // todo : remove the call to substitute_terms_in_linear_expression diff --git a/src/util/lp/lar_term.h b/src/util/lp/lar_term.h index dc3921767..10e58dafa 100644 --- a/src/util/lp/lar_term.h +++ b/src/util/lp/lar_term.h @@ -70,6 +70,16 @@ struct lar_term { t.second.neg(); } + template + T apply(const vector& x) const { + T ret = T(m_v); + for (const auto & t : m_coeffs) { + ret += t.second * x[t.first]; + } + return ret; + } + + void clear() { m_coeffs.clear(); m_v = zero_of_type(); From 64e542bd70e0254a4a24648ca8ad96421445ad66 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 20 Jul 2017 19:13:13 -0700 Subject: [PATCH 0218/1283] fix term indices for the time being when exiting from check() Signed-off-by: Lev Nachmanson --- src/smt/theory_arith_int.h | 2 +- src/util/lp/int_solver.cpp | 17 ++++++++++++----- src/util/lp/lar_solver.h | 2 +- src/util/lp/lp_settings.h | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 7be5650c6..ca3a485c6 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -1387,7 +1387,7 @@ namespace smt { m_branch_cut_counter++; // TODO: add giveup code - if (true || m_branch_cut_counter % m_params.m_arith_branch_cut_ratio == 0) { // remove true :todo + if (m_branch_cut_counter % m_params.m_arith_branch_cut_ratio == 0) { TRACE("opt_verbose", display(tout);); move_non_base_vars_to_bounds(); if (!make_feasible()) { diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 7753dd600..f40fbfb42 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -287,8 +287,6 @@ lia_move int_solver::report_gomory_cut(lar_term& t, mpq& k, mpq &lcm_den, unsign gomory_cut_adjust_t_and_k_for_size_1(pol, t, k); else gomory_cut_adjust_t_and_k_for_size_gt_1(pol, t, k, num_ints, lcm_den); - m_lar_solver->subs_term_columns(t); - lp_assert(current_solution_is_inf_on_cut(t, k)); return lia_move::cut; } @@ -323,7 +321,12 @@ lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl) { if (t.is_empty()) return report_conflict_from_gomory_cut(k); - return report_gomory_cut(t, k, lcm_den, num_ints); + auto ret = report_gomory_cut(t, k, lcm_den, num_ints); + + // remove this call later :todo + m_lar_solver->subs_term_columns(t); + lp_assert(current_solution_is_inf_on_cut(t, k)); + return ret; } @@ -398,7 +401,7 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { return lia_move::ok; - if (true || (++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) { + if ((++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) { move_non_base_vars_to_bounds(); lp_status st = m_lar_solver->find_feasible_solution(); if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { @@ -421,15 +424,19 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { TRACE("arith_int", tout << "j" << j << " does not have an integer assignment: " << get_value(j) << "\n";); lp_assert(t.is_empty()); - t.add_monoid(1, j); + t.add_monoid(mpq(1), j); k = floor(get_value(j)); TRACE("arith_int", tout << "branching v" << j << " = " << get_value(j) << "\n"; display_column(tout, j); tout << "k = " << k << std::endl; ); + // todo: remove this call later when theory_lra handles term indices + m_lar_solver->subs_term_columns(t); + lp_assert(current_solution_is_inf_on_cut(t, k)); return lia_move::branch; } } + lp_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); // return true; return lia_move::give_up; diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 31a33d9d3..8189fb4b8 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -468,7 +468,7 @@ public: } mpq v = t.m_v; vector> pol_after_subs; - // todo : remove the call to substitute_terms_in_linear_expression + // todo : remove the call to substitute_terms_in_linear_expression, when theory_lra handles the terms indices substitute_terms_in_linear_expression(pol, pol_after_subs, v); t.clear(); t = lar_term(pol_after_subs, v); diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index 3530a13f5..d5c3b5f0e 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -205,7 +205,7 @@ public: max_row_length_for_bound_propagation(300), backup_costs(true), column_number_threshold_for_using_lu_in_lar_solver(4000), - m_int_branch_cut_threshold(10000000) + m_int_branch_cut_threshold(100) {} void set_resource_limit(lp_resource_limit& lim) { m_resource_limit = &lim; } From bd4fb22665bd7d2d4843080c7a425044394cda68 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 21 Jul 2017 21:09:51 -0700 Subject: [PATCH 0219/1283] track the set of integer variables that are not set to integer values Signed-off-by: Lev Nachmanson --- src/util/lp/int_solver.cpp | 38 +++++++++---------- src/util/lp/int_solver.h | 5 ++- src/util/lp/lar_solver.cpp | 23 ++++++++++- src/util/lp/lar_solver.h | 5 ++- src/util/lp/lp_core_solver_base.h | 14 ++++++- src/util/lp/lp_core_solver_base.hpp | 3 +- src/util/lp/lp_primal_core_solver.h | 2 +- src/util/lp/lp_primal_core_solver.hpp | 4 +- src/util/lp/lp_primal_core_solver_tableau.hpp | 4 +- 9 files changed, 66 insertions(+), 32 deletions(-) diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index f40fbfb42..90dfef767 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -21,7 +21,6 @@ void int_solver::fix_non_base_columns() { return; if (m_lar_solver->find_feasible_solution() == lp_status::INFEASIBLE) failed(); - init_inf_int_set(); lp_assert(is_feasible() && inf_int_set_is_correct()); } @@ -61,14 +60,22 @@ void int_solver::trace_inf_rows() const { ); } +int_set& int_solver::inf_int_set() { + return m_lar_solver->m_inf_int_set; +} + +const int_set& int_solver::inf_int_set() const { + return m_lar_solver->m_inf_int_set; +} + int int_solver::find_inf_int_base_column() { - if (m_inf_int_set.is_empty()) + if (inf_int_set().is_empty()) return -1; int j = find_inf_int_boxed_base_column_with_smallest_range(); if (j != -1) return j; - unsigned k = settings().random_next() % m_inf_int_set.m_index.size(); - return m_inf_int_set.m_index[k]; + unsigned k = settings().random_next() % inf_int_set().m_index.size(); + return inf_int_set().m_index[k]; } int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { @@ -79,7 +86,7 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { unsigned n = 0; lar_core_solver & lcs = m_lar_solver->m_mpq_lar_core_solver; - for (int j : m_inf_int_set.m_index) { + for (int j : inf_int_set().m_index) { lp_assert(is_base(j) && column_is_int_inf(j)); if (!is_boxed(j)) continue; @@ -331,7 +338,6 @@ lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl) { } void int_solver::init_check_data() { - init_inf_int_set(); unsigned n = m_lar_solver->A_r().column_count(); m_old_values_set.resize(n); m_old_values_data.resize(n); @@ -402,12 +408,13 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { if ((++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) { - move_non_base_vars_to_bounds(); + move_non_base_vars_to_bounds(); // todo track changed variables lp_status st = m_lar_solver->find_feasible_solution(); if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { return lia_move::give_up; } - init_inf_int_set(); // todo - can we avoid this call? + lp_assert(inf_int_set_is_correct()); + // init_inf_int_set(); // todo - can we avoid this call? int j = find_inf_int_base_column(); if (j != -1) { // setup the call for gomory cut @@ -862,7 +869,7 @@ void int_solver::display_column(std::ostream & out, unsigned j) const { bool int_solver::inf_int_set_is_correct() const { for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) { - if (m_inf_int_set.contains(j) != (is_int(j) && (!value_is_int(j)))) + if (inf_int_set().contains(j) != (is_int(j) && (!value_is_int(j)))) return false; } return true; @@ -872,20 +879,11 @@ bool int_solver::column_is_int_inf(unsigned j) const { return is_int(j) && (!value_is_int(j)); } -void int_solver::init_inf_int_set() { - m_inf_int_set.clear(); - m_inf_int_set.resize(m_lar_solver->A_r().column_count()); - for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) { - if (column_is_int_inf(j)) - m_inf_int_set.insert(j); - } -} - void int_solver::update_column_in_int_inf_set(unsigned j) { if (is_int(j) && (!value_is_int(j))) - m_inf_int_set.insert(j); + inf_int_set().insert(j); else - m_inf_int_set.erase(j); + inf_int_set().erase(j); } bool int_solver::is_base(unsigned j) const { diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index b5a7e74f5..104e9b321 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -34,13 +34,15 @@ public: lar_solver *m_lar_solver; int_set m_old_values_set; vector m_old_values_data; - int_set m_inf_int_set; unsigned m_branch_cut_counter; linear_combination_iterator* m_iter_on_gomory_row; unsigned m_gomory_cut_inf_column; bool m_found_free_var_in_gomory_row; + // methods int_solver(lar_solver* lp); + int_set& inf_int_set(); + const int_set& inf_int_set() const; // main function to check that 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); @@ -96,7 +98,6 @@ private: const impq & get_value(unsigned j) const; void display_column(std::ostream & out, unsigned j) const; bool inf_int_set_is_correct() const; - void init_inf_int_set(); void update_column_in_int_inf_set(unsigned j); bool column_is_int_inf(unsigned j) const; void trace_inf_rows() const; diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index e8235c839..e7ef4f748 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -30,7 +30,17 @@ void clear() {lp_assert(false); // not implemented lar_solver::lar_solver() : m_status(lp_status::OPTIMAL), m_infeasible_column_index(-1), m_terms_start_index(1000000), - m_mpq_lar_core_solver(m_settings, *this) + m_mpq_lar_core_solver(m_settings, *this), + m_tracker_of_x_change([&](unsigned j, const impq & x){ + if (!var_is_int(j)) { + lp_assert(m_inf_int_set.contains(j) == false); + return; + } + if (m_mpq_lar_core_solver.m_r_x[j].is_int()) + m_inf_int_set.erase(j); + else + m_inf_int_set.insert(j); + }) { } @@ -279,6 +289,10 @@ lp_status lar_solver::get_status() const { return m_status;} void lar_solver::set_status(lp_status s) {m_status = s;} +bool lar_solver::has_int_var() const { + return m_mpq_lar_core_solver.m_r_solver.m_tracker_of_x_change != nullptr; +} + lp_status lar_solver::find_feasible_solution() { m_settings.st().m_make_feasible++; if (A_r().column_count() > m_settings.st().m_max_cols) @@ -288,6 +302,10 @@ lp_status lar_solver::find_feasible_solution() { if (strategy_is_undecided()) decide_on_strategy_and_adjust_initial_state(); + if (has_int_var()) { + m_inf_int_set.resize(A_r().column_count()); + } + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; return solve(); } @@ -1474,6 +1492,9 @@ var_index lar_solver::add_var(unsigned ext_j, bool is_int) { m_columns_to_ul_pairs.push_back(ul_pair(static_cast(-1))); add_non_basic_var_to_core_fields(ext_j, is_int); lp_assert(sizes_are_correct()); + if (is_int) { + m_mpq_lar_core_solver.m_r_solver.set_tracker_of_x(& m_tracker_of_x_change); + } return i; } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 8189fb4b8..df4df5ca1 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -68,7 +68,8 @@ public: lar_core_solver m_mpq_lar_core_solver; unsigned constraint_count() const; const lar_base_constraint& get_constraint(unsigned ci) const; - + std::function m_tracker_of_x_change; + int_set m_inf_int_set; ////////////////// methods //////////////////////////////// static_matrix> & A_r(); static_matrix> const & A_r() const; @@ -473,5 +474,7 @@ public: t.clear(); t = lar_term(pol_after_subs, v); } + + bool has_int_var() const; }; } diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 12c93ec93..0a07055a4 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -69,6 +69,12 @@ public: bool m_tracing_basis_changes; int_set* m_pivoted_rows; bool m_look_for_feasible_solution_only; + std::function * m_tracker_of_x_change; + + void set_tracker_of_x(std::function* tracker) { + m_tracker_of_x_change = tracker; + } + void start_tracing_basis_changes() { m_trace_of_basis_change_vector.resize(0); m_tracing_basis_changes = true; @@ -670,16 +676,20 @@ public: void update_column_in_inf_set(unsigned j) { if (column_is_feasible(j)) { - m_inf_set.erase(j); + remove_column_from_inf_set(j); } else { - m_inf_set.insert(j); + insert_column_into_inf_set(j); } } void insert_column_into_inf_set(unsigned j) { + if (m_tracker_of_x_change != nullptr) + (*m_tracker_of_x_change)(j, m_x[j]); m_inf_set.insert(j); lp_assert(!column_is_feasible(j)); } void remove_column_from_inf_set(unsigned j) { + if (m_tracker_of_x_change != nullptr) + (*m_tracker_of_x_change)(j, m_x[j]); m_inf_set.erase(j); lp_assert(column_is_feasible(j)); } diff --git a/src/util/lp/lp_core_solver_base.hpp b/src/util/lp/lp_core_solver_base.hpp index bd3410b45..5ac6c4c22 100644 --- a/src/util/lp/lp_core_solver_base.hpp +++ b/src/util/lp/lp_core_solver_base.hpp @@ -52,7 +52,8 @@ lp_core_solver_base(static_matrix & A, m_steepest_edge_coefficients(A.column_count()), m_tracing_basis_changes(false), m_pivoted_rows(nullptr), - m_look_for_feasible_solution_only(false) { + m_look_for_feasible_solution_only(false), + m_tracker_of_x_change(nullptr) { lp_assert(bounds_for_boxed_are_set_correctly()); init(); init_basis_heading_and_non_basic_columns_vector(); diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index 77784746a..7577516d2 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -779,7 +779,7 @@ public: if (this->m_basis_heading[j] < 0) continue; if (!this->column_is_feasible(j)) - this->m_inf_set.insert(j); + this->insert_column_into_inf_set(j); } } diff --git a/src/util/lp/lp_primal_core_solver.hpp b/src/util/lp/lp_primal_core_solver.hpp index b3d6921d9..27c92e5e0 100644 --- a/src/util/lp/lp_primal_core_solver.hpp +++ b/src/util/lp/lp_primal_core_solver.hpp @@ -1197,9 +1197,9 @@ lp_primal_core_solver::init_infeasibility_cost_for_column(unsigned j) { } if (numeric_traits::is_zero(this->m_costs[j])) { - this->m_inf_set.erase(j); + this->remove_column_from_inf_set(j); } else { - this->m_inf_set.insert(j); + this->insert_column_into_inf_set(j); } if (!this->m_settings.use_breakpoints_in_feasibility_search) { this->m_costs[j] = - this->m_costs[j]; diff --git a/src/util/lp/lp_primal_core_solver_tableau.hpp b/src/util/lp/lp_primal_core_solver_tableau.hpp index 3cacd2dbb..867c321ba 100644 --- a/src/util/lp/lp_primal_core_solver_tableau.hpp +++ b/src/util/lp/lp_primal_core_solver_tableau.hpp @@ -349,9 +349,9 @@ update_x_tableau(unsigned entering, const X& delta) { this->m_x[j] -= delta * this->m_A.get_val(c); update_inf_cost_for_column_tableau(j); if (is_zero(this->m_costs[j])) - this->m_inf_set.erase(j); + this->remove_column_from_inf_set(j); else - this->m_inf_set.insert(j); + this->insert_column_into_inf_set(j); } } lp_assert(this->A_mult_x_is_off() == false); From c8fe91d8c5cda754f9e560caee07f0491a1c92b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 24 Jul 2017 16:12:46 -0700 Subject: [PATCH 0220/1283] add handling for nested terms Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 149 ++++++++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 38 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 0813e1dcd..e9bb13b8e 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -602,8 +602,8 @@ namespace smt { } bool all_zeros(vector const& v) const { - for (unsigned i = 0; i < v.size(); ++i) { - if (!v[i].is_zero()) { + for (rational const& r : v) { + if (!r.is_zero()) { return false; } } @@ -1031,20 +1031,32 @@ namespace smt { return m_solver->var_is_registered(m_theory_var2var_index[v]); } + mutable vector> m_todo_terms; + lp::impq get_ivalue(theory_var v) const { lp_assert(can_get_ivalue(v)); lp::var_index vi = m_theory_var2var_index[v]; if (!m_solver->is_term(vi)) return m_solver->get_value(vi); - - const lp::lar_term& term = m_solver->get_term(vi); - lp::impq result(term.m_v); - for (const auto & i: term.m_coeffs) { - result += m_solver->get_value(i.first) * i.second; + m_todo_terms.push_back(std::make_pair(vi, rational::one())); + lp::impq result(0); + while (!m_todo_terms.empty()) { + vi = m_todo_terms.back().first; + rational coeff = m_todo_terms.back().second; + m_todo_terms.pop_back(); + if (m_solver->is_term(vi)) { + const lp::lar_term& term = m_solver->get_term(vi); + result += term.m_v * coeff; + for (const auto & i: term.m_coeffs) { + m_todo_terms.push_back(std::make_pair(i.first, coeff * i.second)); + } + } + else { + result += m_solver->get_value(vi) * coeff; + } } return result; } - rational get_value(theory_var v) const { if (!can_get_value(v)) return rational::zero(); @@ -1052,17 +1064,25 @@ namespace smt { if (m_variable_values.count(vi) > 0) { return m_variable_values[vi]; } - if (m_solver->is_term(vi)) { - const lp::lar_term& term = m_solver->get_term(vi); - rational result = term.m_v; - for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { - result += m_variable_values[i->first] * i->second; + m_todo_terms.push_back(std::make_pair(vi, rational::one())); + rational result(0); + while (!m_todo_terms.empty()) { + lp::var_index wi = m_todo_terms.back().first; + rational coeff = m_todo_terms.back().second; + m_todo_terms.pop_back(); + if (m_solver->is_term(wi)) { + const lp::lar_term& term = m_solver->get_term(wi); + result += term.m_v * coeff; + for (auto const& i : term.m_coeffs) { + m_todo_terms.push_back(std::make_pair(i.first, i.second * coeff)); + } + } + else { + result += m_variable_values[wi] * coeff; } - m_variable_values[vi] = result; - return result; } - UNREACHABLE(); - return m_variable_values[vi]; + m_variable_values[vi] = result; + return result; } void init_variable_values() { @@ -1550,8 +1570,8 @@ namespace smt { SASSERT(validate_assign(lit)); if (m_core.size() < small_lemma_size() && m_eqs.empty()) { m_core2.reset(); - for (unsigned i = 0; i < m_core.size(); ++i) { - m_core2.push_back(~m_core[i]); + for (auto const& c : m_core) { + m_core2.push_back(~c); } m_core2.push_back(lit); justification * js = 0; @@ -1926,16 +1946,29 @@ namespace smt { ++m_stats.m_bounds_propagations; } + svector m_todo_vars; + void add_use_lists(lp_api::bound* b) { theory_var v = b->get_var(); lp::var_index vi = get_var_index(v); - if (m_solver->is_term(vi)) { + if (!m_solver->is_term(vi)) { + return; + } + m_todo_vars.push_back(vi); + while (!m_todo_vars.empty()) { + vi = m_todo_vars.back(); + m_todo_vars.pop_back(); lp::lar_term const& term = m_solver->get_term(vi); for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { lp::var_index wi = i->first; - unsigned w = m_var_index2theory_var[wi]; - m_use_list.reserve(w + 1, ptr_vector()); - m_use_list[w].push_back(b); + if (m_solver->is_term(wi)) { + m_todo_vars.push_back(wi); + } + else { + unsigned w = m_var_index2theory_var[wi]; + m_use_list.reserve(w + 1, ptr_vector()); + m_use_list[w].push_back(b); + } } } } @@ -1943,13 +1976,24 @@ namespace smt { void del_use_lists(lp_api::bound* b) { theory_var v = b->get_var(); lp::var_index vi = m_theory_var2var_index[v]; - if (m_solver->is_term(vi)) { + if (!m_solver->is_term(vi)) { + return; + } + m_todo_vars.push_back(vi); + while (!m_todo_vars.empty()) { + vi = m_todo_vars.back(); + m_todo_vars.pop_back(); lp::lar_term const& term = m_solver->get_term(vi); for (auto i = term.m_coeffs.begin(); i != term.m_coeffs.end(); ++i) { lp::var_index wi = i->first; - unsigned w = m_var_index2theory_var[wi]; - SASSERT(m_use_list[w].back() == b); - m_use_list[w].pop_back(); + if (m_solver->is_term(wi)) { + m_todo_vars.push_back(wi); + } + else { + unsigned w = m_var_index2theory_var[wi]; + SASSERT(m_use_list[w].back() == b); + m_use_list[w].pop_back(); + } } } } @@ -2036,6 +2080,9 @@ namespace smt { lp::constraint_index ci; rational value; bool is_strict; + if (m_solver->is_term(wi)) { + return false; + } if (coeff.second.is_neg() == is_lub) { // -3*x ... <= lub based on lower bound for x. if (!m_solver->has_lower_bound(wi, ci, value, is_strict)) { @@ -2381,15 +2428,31 @@ namespace smt { SASSERT(m_use_nra_model); lp::var_index vi = m_theory_var2var_index[v]; if (m_solver->is_term(vi)) { - lp::lar_term const& term = m_solver->get_term(vi); - scoped_anum r1(m_nra->am()); - m_nra->am().set(r, term.m_v.to_mpq()); - - for (auto const coeff : term.m_coeffs) { - lp::var_index wi = coeff.first; - m_nra->am().set(r1, coeff.second.to_mpq()); - m_nra->am().mul(m_nra->value(wi), r1, r1); - m_nra->am().add(r1, r, r); + + m_todo_terms.push_back(std::make_pair(vi, rational::one())); + + m_nra->am().set(r, 0); + while (!m_todo_terms.empty()) { + rational wcoeff = m_todo_terms.back().second; + lp::var_index wi = m_todo_terms.back().first; + m_todo_terms.pop_back(); + lp::lar_term const& term = m_solver->get_term(vi); + scoped_anum r1(m_nra->am()); + rational c1 = term.m_v * wcoeff; + m_nra->am().set(r1, c1.to_mpq()); + m_nra->am().add(r, r1, r); + for (auto const coeff : term.m_coeffs) { + lp::var_index wi = coeff.first; + c1 = coeff.second * wcoeff; + if (m_solver->is_term(wi)) { + m_todo_terms.push_back(std::make_pair(wi, c1)); + } + else { + m_nra->am().set(r1, c1.to_mpq()); + m_nra->am().mul(m_nra->value(wi), r1, r1); + m_nra->am().add(r1, r, r); + } + } } return r; } @@ -2489,10 +2552,14 @@ namespace smt { theory_lra::inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) { lp::var_index vi = m_theory_var2var_index.get(v, UINT_MAX); vector > coeffs; - rational coeff; + rational coeff(0); + // + // TBD: change API for maximize_term to take a proper term as input. + // if (m_solver->is_term(vi)) { const lp::lar_term& term = m_solver->get_term(vi); for (auto & ti : term.m_coeffs) { + SASSERT(!m_solver->is_term(ti.first)); coeffs.push_back(std::make_pair(ti.second, ti.first)); } coeff = term.m_v; @@ -2550,7 +2617,13 @@ namespace smt { app_ref mk_term(lp::lar_term const& term, bool is_int) { expr_ref_vector args(m); for (auto & ti : term.m_coeffs) { - theory_var w = m_var_index2theory_var[ti.first]; + theory_var w; + if (m_solver->is_term(ti.first)) { + w = m_term_index2theory_var[m_solver->adjust_term_index(ti.first)]; + } + else { + w = m_var_index2theory_var[ti.first]; + } expr* o = get_enode(w)->get_owner(); if (ti.second.is_one()) { args.push_back(o); From b2b2c636f855db70ececfd4e15522e74eeaa30ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 28 Jul 2017 10:30:23 -0700 Subject: [PATCH 0221/1283] update for equivalences Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 49 +++++++++++++++++++++++++++++++++++---- src/sat/ba_solver.h | 9 +++++-- src/sat/sat_extension.h | 1 + src/sat/sat_lookahead.cpp | 11 +++++++++ src/sat/sat_scc.cpp | 6 +++-- 5 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index eedca9ce9..e77e1172d 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1739,6 +1739,25 @@ namespace sat { SASSERT(validate_unit_propagation(p, r, l)); } + bool ba_solver::is_extended_binary(ext_justification_idx idx, literal_vector & r) { + constraint const& c = index2constraint(idx); + switch (c.tag()) { + case card_t: { + card const& ca = c.to_card(); + if (ca.size() == ca.k() + 1 && ca.lit() == null_literal) { + r.reset(); + for (literal l : ca) r.push_back(l); + return true; + } + else { + return false; + } + } + default: + return false; + } + } + void ba_solver::simplify(xor& x) { // no-op } @@ -2004,17 +2023,39 @@ namespace sat { /** \brief Lex on (glue, size) */ - struct constraint_glue_lt { + struct constraint_glue_psm_lt { bool operator()(ba_solver::constraint const * c1, ba_solver::constraint const * c2) const { return (c1->glue() < c2->glue()) || - (c1->glue() == c2->glue() && c1->size() < c2->size()); + (c1->glue() == c2->glue() && + (c1->psm() < c2->psm() || + (c1->psm() == c2->psm() && c1->size() < c2->size()))); } }; + void ba_solver::update_psm(constraint& c) const { + unsigned r = 0; + switch (c.tag()) { + case card_t: + for (literal l : c.to_card()) { + if (s().m_phase[l.var()] == (l.sign() ? NEG_PHASE : POS_PHASE)) ++r; + } + break; + case pb_t: + for (wliteral l : c.to_pb()) { + if (s().m_phase[l.second.var()] == (l.second.sign() ? NEG_PHASE : POS_PHASE)) ++r; + } + break; + default: + break; + } + c.set_psm(r); + } + void ba_solver::gc() { - std::stable_sort(m_learned.begin(), m_learned.end(), constraint_glue_lt()); - gc_half("glue"); + for (auto & c : m_learned) update_psm(*c); + std::stable_sort(m_learned.begin(), m_learned.end(), constraint_glue_psm_lt()); + gc_half("glue-psm"); cleanup_constraints(m_learned, true); } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 2169f5845..5347cac22 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -62,12 +62,13 @@ namespace sat { bool m_removed; literal m_lit; unsigned m_glue; + unsigned m_psm; unsigned m_size; size_t m_obj_size; bool m_learned; unsigned m_id; public: - constraint(tag_t t, unsigned id, literal l, unsigned sz, size_t osz): m_tag(t), m_removed(false), m_lit(l), m_glue(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id) {} + constraint(tag_t t, unsigned id, literal l, unsigned sz, size_t osz): m_tag(t), m_removed(false), m_lit(l), m_glue(0), m_psm(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id) {} ext_constraint_idx index() const { return reinterpret_cast(this); } unsigned id() const { return m_id; } tag_t tag() const { return m_tag; } @@ -79,7 +80,9 @@ namespace sat { void remove() { m_removed = true; } void nullify_literal() { m_lit = null_literal; } unsigned glue() const { return m_glue; } - void set_glue(unsigned g) { m_glue = g; } + void set_glue(unsigned g) { m_glue = g; } + unsigned psm() const { return m_psm; } + void set_psm(unsigned p) { m_psm = p; } void set_learned(bool f) { m_learned = f; } bool learned() const { return m_learned; } @@ -265,6 +268,7 @@ namespace sat { void subsumption(constraint& c1); void subsumption(card& c1); void gc_half(char const* _method); + void update_psm(constraint& c) const; void mutex_reduction(); typedef vector> lhs_t; @@ -442,6 +446,7 @@ namespace sat { virtual void pop_reinit(); virtual void gc(); virtual double get_reward(literal l, ext_justification_idx idx, literal_occs_fun& occs) const; + virtual bool is_extended_binary(ext_justification_idx idx, literal_vector & r); ptr_vector const & constraints() const { return m_constraints; } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 87f1904ed..406cc6421 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -43,6 +43,7 @@ namespace sat { virtual bool propagate(literal l, ext_constraint_idx idx) = 0; virtual double get_reward(literal l, ext_constraint_idx idx, literal_occs_fun& occs) const = 0; virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0; + virtual bool is_extended_binary(ext_justification_idx idx, literal_vector & r) = 0; virtual void asserted(literal l) = 0; virtual check_result check() = 0; virtual lbool resolve_conflict() { return l_undef; } // stores result in sat::solver::m_lemma diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index b5229dc54..aaf392ae3 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -503,6 +503,7 @@ namespace sat { // arcs are added in the opposite direction of implications. // So for implications l => u we add arcs u -> l void lookahead::init_arcs(literal l) { + literal_vector lits; literal_vector const& succ = m_binary[l.index()]; for (unsigned i = 0; i < succ.size(); ++i) { literal u = succ[i]; @@ -512,6 +513,16 @@ namespace sat { add_arc( u, l); } } + for (auto w : m_watches[l.index()]) { + if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { + for (literal u : lits) { + if (u.index() > l.index() && is_stamped(u)) { + add_arc(~l, ~u); + add_arc( u, l); + } + } + } + } } void lookahead::get_scc(literal v) { diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index ec77ebfbd..15108c7fd 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -33,10 +33,11 @@ namespace sat { struct frame { unsigned m_lidx; + unsigned m_succ_idx; bool m_first; watched * m_it; watched * m_end; - frame(unsigned lidx, watched * it, watched * end):m_lidx(lidx), m_first(true), m_it(it), m_end(end) {} + frame(unsigned lidx, watched * it, watched * end, unsigned sidx = 0):m_lidx(lidx), m_succ_idx(sidx), m_first(true), m_it(it), m_end(end) {} }; typedef svector frames; @@ -75,7 +76,7 @@ namespace sat { index.resize(num_lits, UINT_MAX); lowlink.resize(num_lits, UINT_MAX); in_s.resize(num_lits, false); - literal_vector roots; + literal_vector roots, lits; roots.resize(m_solver.num_vars(), null_literal); unsigned next_index = 0; svector frames; @@ -106,6 +107,7 @@ namespace sat { frame & fr = frames.back(); unsigned l_idx = fr.m_lidx; if (!fr.m_first) { + SASSERT(fr.m_it->is_binary_clause()); // after visiting child literal l2 = fr.m_it->get_literal(); unsigned l2_idx = l2.index(); From b1090f43994577b9156a23d85786c2942e035875 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 31 Jul 2017 09:49:11 -0700 Subject: [PATCH 0222/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 100 +++++++++++++++++++++++++++++++++---- src/sat/ba_solver.h | 2 + src/sat/sat_extension.h | 18 ++++++- src/sat/sat_simplifier.cpp | 74 ++++++++++++++------------- src/sat/sat_simplifier.h | 2 + 5 files changed, 151 insertions(+), 45 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 0b28c21a7..1f236a9c7 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1812,8 +1812,8 @@ namespace sat { } } else { - unsigned coeff = 0; - for (unsigned j = 0; j < p.num_watch(); ++j) { + unsigned coeff = 0, j = 0; + for (; j < p.size(); ++j) { if (p[j].second == l) { coeff = p[j].first; break; @@ -1828,10 +1828,11 @@ namespace sat { SASSERT(coeff > 0); unsigned slack = p.slack() - coeff; + j = std::max(j + 1, p.num_watch()); - for (unsigned i = p.num_watch(); i < p.size(); ++i) { - literal lit = p[i].second; - unsigned w = p[i].first; + for (; j < p.size(); ++j) { + literal lit = p[j].second; + unsigned w = p[j].first; SASSERT(l_false == value(lit)); if (slack + w < k) { slack += w; @@ -2118,9 +2119,11 @@ namespace sat { }; void ba_solver::gc() { - std::stable_sort(m_learned.begin(), m_learned.end(), constraint_glue_lt()); - gc_half("glue"); - cleanup_constraints(m_learned, true); + if (m_learned.size() >= 2 * m_constraints.size()) { + std::stable_sort(m_learned.begin(), m_learned.end(), constraint_glue_lt()); + gc_half("glue"); + cleanup_constraints(m_learned, true); + } } void ba_solver::gc_half(char const* st_name) { @@ -2274,7 +2277,7 @@ namespace sat { } while (m_simplify_change || trail_sz < s().init_trail_size()); - IF_VERBOSE(1, verbose_stream() << "(ba.simplify :trail " << trail_sz + IF_VERBOSE(1, verbose_stream() << "(ba.simplify " << " :vars " << s().num_vars() - trail_sz << " :constraints " << m_constraints.size() << " :lemmas " << m_learned.size() @@ -3133,6 +3136,85 @@ namespace sat { return result; } + void ba_solver::init_use_list(ext_use_list& ul) { + ul.init(s().num_vars()); + for (constraint const* cp : m_constraints) { + ext_constraint_idx idx = cp->index(); + if (cp->lit() != null_literal) { + ul.insert(cp->lit(), idx); + ul.insert(~cp->lit(), idx); + } + switch (cp->tag()) { + case card_t: { + card const& c = cp->to_card(); + for (literal l : c) { + ul.insert(l, idx); + } + break; + } + case pb_t: { + pb const& p = cp->to_pb(); + for (wliteral w : p) { + ul.insert(w.second, idx); + } + break; + } + case xor_t: { + xor const& x = cp->to_xor(); + for (literal l : x) { + ul.insert(l, idx); + ul.insert(~l, idx); + } + break; + } + default: + UNREACHABLE(); + } + } + } + + // + // literal is used in a clause (C or l), it + // it occurs negatively in constraint c. + // all literals in C are marked + // + bool ba_solver::is_blocked(literal l, ext_constraint_idx idx) { + constraint const& c = index2constraint(idx); + simplifier& sim = s().m_simplifier; + if (c.lit() != null_literal) return false; + switch (c.tag()) { + case card_t: { + card const& ca = c.to_card(); + unsigned weight = 0; + for (literal l2 : ca) { + if (sim.is_marked(~l2)) ++weight; + } + return weight >= ca.k(); + } + case pb_t: { + pb const& p = c.to_pb(); + unsigned weight = 0, offset = 0; + for (wliteral l2 : p) { + if (~l2.second == l) { + offset = l2.first; + break; + } + } + SASSERT(offset != 0); + for (wliteral l2 : p) { + if (sim.is_marked(~l2.second)) { + weight += std::min(offset, l2.first); + } + } + return weight >= p.k(); + } + default: + break; + } + return false; + } + + void ba_solver::find_mutexes(literal_vector& lits, vector & mutexes) { literal_set slits(lits); bool change = false; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index d40611dfe..4433017dc 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -444,6 +444,8 @@ namespace sat { virtual void pop_reinit(); virtual void gc(); virtual double get_reward(literal l, ext_justification_idx idx, literal_occs_fun& occs) const; + virtual void init_use_list(ext_use_list& ul); + virtual bool is_blocked(literal l, ext_constraint_idx idx); ptr_vector const & constraints() const { return m_constraints; } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 87f1904ed..0278bdb61 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -31,8 +31,20 @@ namespace sat { class literal_occs_fun { public: - virtual double operator()(literal l) = 0; - + virtual double operator()(literal l) = 0; + }; + + + typedef svector ext_constraint_list; + + class ext_use_list { + vector m_use_list; + public: + void init(unsigned num_vars) { m_use_list.reset(); m_use_list.resize(num_vars*2); } + void insert(literal l, ext_constraint_idx idx) { get(l).push_back(idx); } + ext_constraint_list & get(literal l) { return m_use_list[l.index()]; } + ext_constraint_list const & get(literal l) const { return m_use_list[l.index()]; } + void finalize() { m_use_list.finalize(); } }; class extension { @@ -62,6 +74,8 @@ namespace sat { virtual void gc() = 0; virtual void pop_reinit() = 0; virtual bool validate() = 0; + virtual void init_use_list(ext_use_list& ul) = 0; + virtual bool is_blocked(literal l, ext_constraint_idx) = 0; }; }; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 9c31f4005..37a7a8cd7 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -70,7 +70,13 @@ namespace sat { inline watch_list const & simplifier::get_wlist(literal l) const { return s.get_wlist(l); } - inline bool simplifier::is_external(bool_var v) const { return s.is_external(v); } + inline bool simplifier::is_external(bool_var v) const { + return + s.is_assumption(v) || + (s.is_external(v) && + (!m_ext_use_list.get(literal(v, false)).empty() || + !m_ext_use_list.get(literal(v, true)).empty())); + } inline bool simplifier::was_eliminated(bool_var v) const { return s.was_eliminated(v); } @@ -130,6 +136,7 @@ namespace sat { m_visited.finalize(); m_bs_cs.finalize(); m_bs_ls.finalize(); + m_ext_use_list.finalize(); } void simplifier::initialize() { @@ -137,6 +144,7 @@ namespace sat { s.m_cleaner(true); m_last_sub_trail_sz = s.m_trail.size(); m_use_list.init(s.num_vars()); + if (s.m_ext) s.m_ext->init_use_list(m_ext_use_list); m_sub_todo.reset(); m_sub_bin_todo.reset(); m_elim_todo.reset(); @@ -187,7 +195,7 @@ namespace sat { subsume(); if (s.inconsistent()) return; - if (!learned && m_resolution) + if (!learned && m_resolution && s.m_config.m_num_threads == 1) elim_vars(); if (s.inconsistent()) return; @@ -937,7 +945,7 @@ namespace sat { } bool process_var(bool_var v) { - return !s.is_external(v) && !s.was_eliminated(v); + return !s.s.is_assumption(v) && !s.was_eliminated(v); } void operator()(unsigned num_vars) { @@ -989,7 +997,7 @@ namespace sat { } s.unmark_all(c); it.next(); - } + } } for (clause* c : m_to_remove) { s.remove_clause(*c); @@ -1028,33 +1036,34 @@ namespace sat { } bool all_tautology(literal l) { - { - watch_list & wlist = s.get_wlist(l); - m_counter -= wlist.size(); - watch_list::iterator it = wlist.begin(); - watch_list::iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_non_learned_clause()) - continue; - if (!s.is_marked(~it->get_literal())) - return false; - } + watch_list & wlist = s.get_wlist(l); + m_counter -= wlist.size(); + for (auto const& w : wlist) { + if (w.is_binary_non_learned_clause() && + !s.is_marked(~w.get_literal())) + return false; } - { - clause_use_list & neg_occs = s.m_use_list.get(~l); - clause_use_list::iterator it = neg_occs.mk_iterator(); - while (!it.at_end()) { - clause & c = it.curr(); - m_counter -= c.size(); - unsigned sz = c.size(); - unsigned i; - for (i = 0; i < sz; i++) { - if (s.is_marked(~c[i])) - break; - } - if (i == sz) - return false; - it.next(); + + clause_use_list & neg_occs = s.m_use_list.get(~l); + clause_use_list::iterator it = neg_occs.mk_iterator(); + while (!it.at_end()) { + clause & c = it.curr(); + m_counter -= c.size(); + unsigned sz = c.size(); + unsigned i; + for (i = 0; i < sz; i++) { + if (s.is_marked(~c[i])) + break; + } + if (i == sz) + return false; + it.next(); + } + + ext_constraint_list const& ext_list = s.m_ext_use_list.get(~l); + for (ext_constraint_idx idx : ext_list) { + if (!s.s.m_ext->is_blocked(l, idx)) { + return false; } } return true; @@ -1171,8 +1180,8 @@ namespace sat { SASSERT(c1.contains(l)); SASSERT(c2.contains(~l)); bool res = true; + m_elim_counter -= c1.size() + c2.size(); unsigned sz = c1.size(); - m_elim_counter -= sz; for (unsigned i = 0; i < sz; ++i) { literal l2 = c1[i]; if (l == l2) @@ -1183,7 +1192,6 @@ namespace sat { literal not_l = ~l; sz = c2.size(); - m_elim_counter -= sz; for (unsigned i = 0; i < sz; ++i) { literal l2 = c2[i]; if (not_l == l2) @@ -1199,8 +1207,6 @@ namespace sat { sz = c1.size(); for (unsigned i = 0; i < sz; ++i) { literal l2 = c1[i]; - if (l == l2) - continue; m_visited[l2.index()] = false; } return res; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 626d91ff7..5e4dc9de3 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -26,6 +26,7 @@ Revision History: #include"sat_clause_set.h" #include"sat_clause_use_list.h" #include"sat_watched.h" +#include"sat_extension.h" #include"sat_model_converter.h" #include"heap.h" #include"statistics.h" @@ -51,6 +52,7 @@ namespace sat { solver & s; unsigned m_num_calls; use_list m_use_list; + ext_use_list m_ext_use_list; clause_set m_sub_todo; svector m_sub_bin_todo; unsigned m_last_sub_trail_sz; // size of the trail since last cleanup From 431d318958359142b5aaba6089cfa59ea7594097 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Sep 2017 08:19:08 -0700 Subject: [PATCH 0223/1283] experiments with ccc Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 16 ++-- src/sat/sat_ccc.cpp | 185 +++++++++++++++++++++++--------------- src/sat/sat_ccc.h | 20 +++-- src/sat/sat_lookahead.cpp | 11 ++- src/sat/sat_solver.cpp | 7 ++ 5 files changed, 151 insertions(+), 88 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 0309d390f..0e9b98f44 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1812,14 +1812,18 @@ namespace sat { } } else { - unsigned coeff = 0; - for (unsigned j = 0; j < p.num_watch(); ++j) { + unsigned coeff = 0, j = 0; + for (; j < p.size(); ++j) { if (p[j].second == l) { coeff = p[j].first; break; } } + ++j; + if (j < p.num_watch()) { + j = p.num_watch(); + } CTRACE("sat", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); if (_debug_conflict) { @@ -1829,9 +1833,9 @@ namespace sat { SASSERT(coeff > 0); unsigned slack = p.slack() - coeff; - for (unsigned i = p.num_watch(); i < p.size(); ++i) { - literal lit = p[i].second; - unsigned w = p[i].first; + for (; j < p.size(); ++j) { + literal lit = p[j].second; + unsigned w = p[j].first; SASSERT(l_false == value(lit)); if (slack + w < k) { slack += w; @@ -3094,7 +3098,7 @@ namespace sat { } for (wliteral l : p1) { SASSERT(m_weights[l.second.index()] == 0); - m_weights[l.second.index()] = l.first; + m_weights.setx(l.second.index(), l.first, 0); mark_visited(l.second); } for (unsigned i = 0; i < p1.num_watch(); ++i) { diff --git a/src/sat/sat_ccc.cpp b/src/sat/sat_ccc.cpp index 025bbafd4..ee087a60f 100644 --- a/src/sat/sat_ccc.cpp +++ b/src/sat/sat_ccc.cpp @@ -36,39 +36,48 @@ using namespace sat; // ------------ // cuber -ccc::cuber::cuber(ccc& c): m_ccc(c), lh(c.m_s), m_branch_id(0) {} +ccc::cuber::cuber(ccc& c): m_ccc(c), m_lh(alloc(lookahead, c.m_s)), m_branch_id(0) {} lbool ccc::cuber::search() { - m_branch_id = 0; - m_last_closure_level = 1000; - - lh.init_search(); - lh.m_model.reset(); - - lookahead::scoped_level _sl(lh, lh.c_fixed_truth); - lh.m_search_mode = lookahead_mode::searching; - lbool r = research(); - if (r == l_true) { - m_ccc.m_model = lh.get_model(); + while (true) { + m_branch_id = 0; + m_last_closure_level = 1000; + + m_lh->init_search(); + m_lh->m_model.reset(); + + lookahead::scoped_level _sl(*m_lh.get(), m_lh->c_fixed_truth); + m_lh->m_search_mode = lookahead_mode::searching; + lbool r = research(); + if (r == l_true) { + m_ccc.m_model = m_lh->get_model(); + } + if (false && r == l_undef) { + continue; + } + m_lh->collect_statistics(m_ccc.m_lh_stats); + return r; } - lh.collect_statistics(m_ccc.m_lh_stats); - return r; } lbool ccc::cuber::research() { m_ccc.m_s.checkpoint(); - if (lh.inconsistent()) { + if (m_lh->inconsistent()) { return l_false; } + if (pop_lookahead()) { + return l_undef; + } + if (get_solved()) { return l_false; } - lh.inc_istamp(); - literal l = lh.choose(); - if (lh.inconsistent()) { + m_lh->inc_istamp(); + literal l = m_lh->choose(); + if (m_lh->inconsistent()) { return l_false; } @@ -76,34 +85,35 @@ lbool ccc::cuber::research() { return l_true; } - if (!decisions.empty()) { - m_ccc.put_decision(decisions.back()); + if (!m_decisions.empty()) { + m_ccc.put_decision(m_decisions.back()); } - // update trail and decisions + + // update trail and m_decisions - ++lh.m_stats.m_decisions; - unsigned parent_id = decisions.empty() ? 0 : decisions.back().m_id; + ++m_lh->m_stats.m_decisions; + unsigned parent_id = m_decisions.empty() ? 0 : m_decisions.back().m_id; unsigned spawn_id = spawn_conquer(); unsigned branch1 = m_branch_id++; unsigned branch2 = m_branch_id++; - decision d(branch1, decisions.size() + 1, l, parent_id, spawn_id); - decisions.push_back(d); + decision d(branch1, m_decisions.size() + 1, l, parent_id, spawn_id); + m_decisions.push_back(d); - IF_VERBOSE(1, d.pp(verbose_stream() << "select " << m_last_closure_level << " ") << "\n";); - IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(lh.m_prefix, lh.m_trail_lim.size()) << ": " << l << " " << lh.m_trail.size() << "\n";); - IF_VERBOSE(2, pp(verbose_stream(), decisions) << "\n"; ); + IF_VERBOSE(2, d.pp(verbose_stream() << "select " << m_last_closure_level << " ") << "\n";); + IF_VERBOSE(2, verbose_stream() << "select " << pp_prefix(m_lh->m_prefix, m_lh->m_trail_lim.size()) << ": " << l << " " << m_lh->m_trail.size() << "\n";); + IF_VERBOSE(3, pp(verbose_stream(), m_decisions) << "\n"; ); TRACE("sat", tout << "choose: " << l << "\n";); - lh.push(l, lh.c_fixed_truth); + m_lh->push(l, m_lh->c_fixed_truth); lbool r = research(); if (r == l_false) { - lh.pop(); - if (decisions.back().is_closed()) { + m_lh->pop(); + if (m_decisions.back().is_closed()) { // branch was solved by a spawned conquer process - IF_VERBOSE(1, decisions.back().pp(verbose_stream() << "closed ") << "\n";); + IF_VERBOSE(1, m_decisions.back().pp(verbose_stream() << "closed ") << "\n";); r = l_false; - decisions.pop_back(); + m_decisions.pop_back(); } else { if (spawn_id > 0) { @@ -111,22 +121,41 @@ lbool ccc::cuber::research() { m_last_closure_level *= 3; m_last_closure_level /= 4; } - lh.inc_istamp(); - lh.flip_prefix(); - lh.push(~l, lh.c_fixed_truth); - decisions.back().negate(); - decisions.back().m_id = branch2; - decisions.back().m_spawn_id = 0; + m_lh->inc_istamp(); + m_lh->flip_prefix(); + m_lh->push(~l, m_lh->c_fixed_truth); + m_decisions.back().negate(); + m_decisions.back().m_id = branch2; + m_decisions.back().m_spawn_id = 0; r = research(); if (r == l_false) { - lh.pop(); - decisions.pop_back(); + m_lh->pop(); + m_decisions.pop_back(); } } } return r; } +bool ccc::cuber::pop_lookahead() { + return false; + + scoped_ptr new_lh; + bool result = false; + #pragma omp critical (ccc_new_lh) + { + if (m_ccc.m_new_lh) { + new_lh = m_ccc.m_new_lh.detach(); + result = true; + } + } + if (new_lh) { + m_lh->collect_statistics(m_ccc.m_lh_stats); + m_lh = new_lh.detach(); + } + return result; +} + void ccc::cuber::update_closure_level(decision const& d, int offset) { m_last_closure_level = (d.m_depth + 3*m_last_closure_level) / 4; if (m_last_closure_level >= static_cast(abs(offset))) { @@ -140,13 +169,13 @@ unsigned ccc::cuber::spawn_conquer() { // decisions must have been solved at a higher level by a conquer thread // if (!m_free_threads.empty()) { - if (m_last_closure_level <= decisions.size()) { + if (m_last_closure_level <= m_decisions.size()) { result = m_free_threads.back(); ++m_ccc.m_ccc_stats.m_spawn_opened; m_free_threads.pop_back(); } else { - IF_VERBOSE(1, verbose_stream() << m_last_closure_level << " " << decisions.size() << "\n";); + IF_VERBOSE(1, verbose_stream() << m_last_closure_level << " " << m_decisions.size() << "\n";); } } return result; @@ -181,13 +210,13 @@ bool ccc::cuber::get_solved() { unsigned branch_id = sol.m_branch_id; unsigned thread_id = sol.m_thread_id; bool found = false; - for (unsigned i = decisions.size(); i > 0; ) { + for (unsigned i = m_decisions.size(); i > 0; ) { --i; - decision& d = decisions[i]; + decision& d = m_decisions[i]; if (branch_id == d.m_id) { if (d.m_spawn_id == thread_id && thread_id != 0) { SASSERT(d.m_spawn_id > 0); - IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": spawn close ") << "\n";); + IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": spawn close ") << "\n";); ++m_ccc.m_ccc_stats.m_spawn_closed; d.close(); free_conquer(thread_id); @@ -195,7 +224,7 @@ bool ccc::cuber::get_solved() { break; } else { - IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": conquer ") << "\n";); + IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": conquer ") << "\n";); ++m_ccc.m_ccc_stats.m_cdcl_closed; update_closure_level(d, 1); return true; @@ -236,6 +265,7 @@ lbool ccc::conquer::search() { s.simplify_problem(); if (s.check_inconsistent()) return l_false; s.gc(); + push_lookahead(); } } catch (solver::abort_solver) { @@ -245,16 +275,16 @@ lbool ccc::conquer::search() { void ccc::conquer::replay_decisions() { s.propagate(true); - for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < decisions.size(); ++i) { - decision const& d = decisions[i]; + for (unsigned i = s.scope_lvl(); !s.inconsistent() && i < m_decisions.size(); ++i) { + decision const& d = m_decisions[i]; IF_VERBOSE(2, verbose_stream() << thread_id << ": replay " << d.get_literal(thread_id) << " " << s.value(d.get_literal(thread_id)) << "\n";); if (!push_decision(d)) { // negation of decision is implied. IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": backjump to level " << i << " ") << "\n";); - while (decisions.size() > i) { - pop_decision(decisions.back()); - decisions.pop_back(); + while (m_decisions.size() > i) { + pop_decision(m_decisions.back()); + m_decisions.pop_back(); } break; } @@ -280,6 +310,19 @@ void ccc::conquer::pop_decision(decision const& d) { } } +void ccc::conquer::push_lookahead() { + return; + + #pragma omp critical (ccc_new_lh) + { + if (!m_ccc.m_new_lh && m_ccc.m_num_clauses > s.num_clauses()) { + std::cout << "push " << s.num_clauses() << "\n"; + m_ccc.m_new_lh = alloc(lookahead, s); + m_ccc.m_num_clauses = s.num_clauses(); + } + } +} + bool ccc::conquer::push_decision(decision const& d) { literal lit = d.get_literal(thread_id); switch (s.value(lit)) { @@ -313,7 +356,7 @@ bool ccc::conquer::cube_decision() { if (d.is_spawned(thread_id)) IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << " ") << "\n";); - if (!decisions.empty() && decisions.back().m_depth + 1 < d.m_depth) { + if (!m_decisions.empty() && m_decisions.back().m_depth + 1 < d.m_depth) { if (d.is_spawned(thread_id)) { pop_decision(d); } @@ -322,43 +365,43 @@ bool ccc::conquer::cube_decision() { break; } } - SASSERT(decisions.empty() || decisions.back().m_depth + 1 >= d.m_depth); + SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 >= d.m_depth); - if (!decisions.empty() && decisions.back().is_spawned(thread_id) && decisions.back().m_depth == d.m_depth) { + if (!m_decisions.empty() && m_decisions.back().is_spawned(thread_id) && m_decisions.back().m_depth == d.m_depth) { SASSERT(d.m_spawn_id == 0); - SASSERT(decisions.back().is_left()); + SASSERT(m_decisions.back().is_left()); SASSERT(!d.is_left()); IF_VERBOSE(1, verbose_stream() << thread_id << " inherit spawn\n";); - decisions.back().m_spawn_id = 0; + m_decisions.back().m_spawn_id = 0; m_spawned = false; } - SASSERT(decisions.empty() || decisions.back().m_depth + 1 >= d.m_depth); + SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 >= d.m_depth); - while (!decisions.empty() && decisions.back().m_depth >= d.m_depth) { - // check_non_model("cube decision", decisions); - if (decisions.back().is_spawned(thread_id)) { - pop_decision(decisions.back()); + while (!m_decisions.empty() && m_decisions.back().m_depth >= d.m_depth) { + // check_non_model("cube decision", m_decisions); + if (m_decisions.back().is_spawned(thread_id)) { + pop_decision(m_decisions.back()); } - decisions.pop_back(); + m_decisions.pop_back(); } - SASSERT(decisions.empty() || decisions.back().m_depth + 1 == d.m_depth); - SASSERT(decisions.empty() || decisions.back().m_id == d.m_parent); + SASSERT(m_decisions.empty() || m_decisions.back().m_depth + 1 == d.m_depth); + SASSERT(m_decisions.empty() || m_decisions.back().m_id == d.m_parent); if (m_spawned) { - decisions.push_back(d); + m_decisions.push_back(d); return true; } - s.pop_reinit(s.scope_lvl() - decisions.size()); + s.pop_reinit(s.scope_lvl() - m_decisions.size()); SASSERT(s.m_qhead == s.m_trail.size()); - SASSERT(s.scope_lvl() == decisions.size()); + SASSERT(s.scope_lvl() == m_decisions.size()); literal lit = d.get_literal(thread_id); - IF_VERBOSE(1, d.pp(verbose_stream() << thread_id << ": cube ") << "\n";); - IF_VERBOSE(2, pp(verbose_stream() << thread_id << ": push ", decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; + IF_VERBOSE(2, d.pp(verbose_stream() << thread_id << ": cube ") << "\n";); + IF_VERBOSE(3, pp(verbose_stream() << thread_id << ": push ", m_decisions) << " @ " << s.scope_lvl() << " " << s.value(lit) << "\n"; if (s.value(lit) == l_false) verbose_stream() << "level: " << s.lvl(lit) << "\n";); if (push_decision(d)) { - decisions.push_back(d); + m_decisions.push_back(d); } else { pop_decision(d); diff --git a/src/sat/sat_ccc.h b/src/sat/sat_ccc.h index 30c8a3229..348f99b9e 100644 --- a/src/sat/sat_ccc.h +++ b/src/sat/sat_ccc.h @@ -74,7 +74,7 @@ namespace sat { reslimit m_limit; ccc& m_ccc; solver s; - svector decisions; + svector m_decisions; unsigned thread_id; bool m_spawned; conquer(ccc& super, params_ref const& p, unsigned tid): m_ccc(super), s(p, m_limit), thread_id(tid), m_spawned(false) {} @@ -84,16 +84,17 @@ namespace sat { lbool bounded_search(); bool push_decision(decision const& d); void pop_decision(decision const& d); + void push_lookahead(); void replay_decisions(); }; struct cuber { - ccc& m_ccc; - lookahead lh; - unsigned m_branch_id; - unsigned m_last_closure_level; - unsigned_vector m_free_threads; - svector decisions; + ccc& m_ccc; + scoped_ptr m_lh; + unsigned m_branch_id; + unsigned m_last_closure_level; + unsigned_vector m_free_threads; + svector m_decisions; cuber(ccc& c); lbool search(); @@ -102,11 +103,14 @@ namespace sat { void update_closure_level(decision const& d, int offset); unsigned spawn_conquer(); void free_conquer(unsigned thread_id); + bool pop_lookahead(); }; solver& m_s; queue m_solved; vector > m_decisions; + scoped_ptr m_new_lh; + unsigned m_num_clauses; unsigned m_num_conquer; model m_model; volatile bool m_cancel; @@ -127,7 +131,7 @@ namespace sat { public: - ccc(solver& s): m_s(s) {} + ccc(solver& s): m_s(s), m_num_clauses(s.num_clauses()) {} lbool search(); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index aaf392ae3..bfe5ec686 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -863,7 +863,7 @@ namespace sat { copy_clauses(m_s.m_clauses); copy_clauses(m_s.m_learned); - m_config.m_use_ternary_reward &= !m_s.m_ext; + // m_config.m_use_ternary_reward &= !m_s.m_ext; // copy units unsigned trail_sz = m_s.init_trail_size(); @@ -898,7 +898,7 @@ namespace sat { if (c.was_removed()) continue; // enable when there is a non-ternary reward system. if (c.size() > 3) { - m_config.m_use_ternary_reward = false; + // m_config.m_use_ternary_reward = false; } bool was_eliminated = false; for (unsigned i = 0; !was_eliminated && i < c.size(); ++i) { @@ -1256,7 +1256,12 @@ namespace sat { double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); for (clause const* c : m_full_watches[l.index()]) { - if (!is_true((*c)[0]) && !is_true((*c)[1])) { + bool has_true = false; + for (literal l : *c) { + has_true = is_true(l); + if (has_true) break; + } + if (!has_true) { result += 1.0 / c->size(); } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f98175823..183a306aa 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -913,6 +913,13 @@ namespace sat { if (check_inconsistent()) return l_false; gc(); +#if 0 + if (m_clauses.size() < 65000) { + return do_ccc(); + return lookahead_search(); + } +#endif + if (m_config.m_restart_max <= m_restarts) { m_reason_unknown = "sat.max.restarts"; IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); From d1a227493a2f22b8bf87eb0d077c46621919fbed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Sep 2017 08:31:31 -0700 Subject: [PATCH 0224/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 4433017dc..46e6b15e8 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -7,7 +7,9 @@ Module Name: Abstract: - Cardinality extensions. + Cardinality extensions, + Pseudo Booleans, + Xors Author: From 3c4ac9aee5ec26830549c3b1bf750d38ef0fddc0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Sep 2017 12:02:50 -0700 Subject: [PATCH 0225/1283] add HS and unit literal reward schemes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 120 +++++++++++++++++++++----------------- src/sat/sat_lookahead.h | 12 +++- 2 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index bfe5ec686..4e2d77f67 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -135,10 +135,8 @@ namespace sat { inc_bstamp(); set_bstamp(l); literal_vector const& conseq = m_binary[l.index()]; - literal_vector::const_iterator it = conseq.begin(); - literal_vector::const_iterator end = conseq.end(); - for (; it != end; ++it) { - set_bstamp(*it); + for (literal l : conseq) { + set_bstamp(l); } } @@ -365,27 +363,35 @@ namespace sat { } void lookahead::init_pre_selection(unsigned level) { - if (!m_config.m_use_ternary_reward) return; - unsigned max_level = m_config.m_max_hlevel; - if (level <= 1) { - ensure_H(2); - h_scores(m_H[0], m_H[1]); - for (unsigned j = 0; j < 2; ++j) { - for (unsigned i = 0; i < 2; ++i) { - h_scores(m_H[i + 1], m_H[(i + 2) % 3]); + switch (m_config.m_reward_type) { + case ternary_reward: { + unsigned max_level = m_config.m_max_hlevel; + if (level <= 1) { + ensure_H(2); + h_scores(m_H[0], m_H[1]); + for (unsigned j = 0; j < 2; ++j) { + for (unsigned i = 0; i < 2; ++i) { + h_scores(m_H[i + 1], m_H[(i + 2) % 3]); + } } + m_heur = &m_H[1]; } - m_heur = &m_H[1]; + else if (level < max_level) { + ensure_H(level); + h_scores(m_H[level-1], m_H[level]); + m_heur = &m_H[level]; + } + else { + ensure_H(max_level); + h_scores(m_H[max_level-1], m_H[max_level]); + m_heur = &m_H[max_level]; + } + break; } - else if (level < max_level) { - ensure_H(level); - h_scores(m_H[level-1], m_H[level]); - m_heur = &m_H[level]; - } - else { - ensure_H(max_level); - h_scores(m_H[max_level-1], m_H[max_level]); - m_heur = &m_H[max_level]; + case heule_schur_reward: + break; + case unit_literal_reward: + break; } } @@ -782,10 +788,8 @@ namespace sat { } void lookahead::del_clauses() { - clause * const* end = m_clauses.end(); - clause * const * it = m_clauses.begin(); - for (; it != end; ++it) { - m_cls_allocator.del_clause(*it); + for (clause * c : m_clauses) { + m_cls_allocator.del_clause(c); } } @@ -849,12 +853,10 @@ namespace sat { literal l = ~to_literal(l_idx); if (m_s.was_eliminated(l.var())) continue; watch_list const & wlist = m_s.m_watches[l_idx]; - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_non_learned_clause()) + for (auto& w : wlist) { + if (!w.is_binary_non_learned_clause()) continue; - literal l2 = it->get_literal(); + literal l2 = w.get_literal(); if (l.index() < l2.index() && !m_s.was_eliminated(l2.var())) add_binary(l, l2); } @@ -891,15 +893,10 @@ namespace sat { void lookahead::copy_clauses(clause_vector const& clauses) { // copy clauses - clause_vector::const_iterator it = clauses.begin(); - clause_vector::const_iterator end = clauses.end(); - for (; it != end; ++it) { - clause& c = *(*it); + for (clause* cp : clauses) { + clause& c = *cp; if (c.was_removed()) continue; // enable when there is a non-ternary reward system. - if (c.size() > 3) { - // m_config.m_use_ternary_reward = false; - } bool was_eliminated = false; for (unsigned i = 0; !was_eliminated && i < c.size(); ++i) { was_eliminated = m_s.was_eliminated(c[i].var()); @@ -1028,6 +1025,9 @@ namespace sat { } m_stats.m_windfall_binaries += m_wstack.size(); } + if (m_config.m_reward_type == unit_literal_reward) { + m_lookahead_reward += m_wstack.size(); + } m_wstack.reset(); } @@ -1219,16 +1219,20 @@ namespace sat { void lookahead::update_binary_clause_reward(literal l1, literal l2) { SASSERT(!is_false(l1)); SASSERT(!is_false(l2)); - if (m_config.m_use_ternary_reward) { + switch (m_config.m_reward_type) { + case ternary_reward: m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; - } - else { - m_lookahead_reward += 0.5 * (literal_occs(l1) + literal_occs(l2)); + break; + case heule_schur_reward: + m_lookahead_reward += (literal_occs(l1) + literal_occs(l2)) / 8.0; + break; + case unit_literal_reward: + break; } } void lookahead::update_nary_clause_reward(clause const& c) { - if (m_config.m_use_ternary_reward && m_lookahead_reward != 0) { + if (m_config.m_reward_type == ternary_reward && m_lookahead_reward != 0) { return; } literal const * l_it = c.begin() + 2, *l_end = c.end(); @@ -1237,7 +1241,8 @@ namespace sat { if (is_true(*l_it)) return; if (!is_false(*l_it)) ++sz; } - if (!m_config.m_use_ternary_reward) { + switch (m_config.m_reward_type) { + case heule_schur_reward: { SASSERT(sz > 0); double to_add = 0; for (literal l : c) { @@ -1245,14 +1250,18 @@ namespace sat { to_add += literal_occs(l); } } - m_lookahead_reward += pow(0.5, sz) * to_add; + m_lookahead_reward += pow(0.5, sz) * to_add / sz; + break; } - else { + case ternary_reward: m_lookahead_reward = (double)0.001; + break; + case unit_literal_reward: + break; } } - // Sum_{ clause C that contains ~l } 1 / |C| + // Sum_{ clause C that contains ~l } 1 double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); for (clause const* c : m_full_watches[l.index()]) { @@ -1262,7 +1271,7 @@ namespace sat { if (has_true) break; } if (!has_true) { - result += 1.0 / c->size(); + result += 1.0; } } return result; @@ -1394,6 +1403,15 @@ namespace sat { } + double lookahead::mix_diff(double l, double r) const { + switch (m_config.m_reward_type) { + case ternary_reward: return l + r + (1 << 10) * l * r; + case heule_schur_reward: return l * r; + case unit_literal_reward: return l * r; + default: UNREACHABLE(); return l * r; + } + } + void lookahead::reset_lookahead_reward(literal l) { m_lookahead_reward = 0; @@ -1406,10 +1424,8 @@ namespace sat { bool lookahead::check_autarky(literal l, unsigned level) { return false; // no propagations are allowed to reduce clauses. - clause_vector::const_iterator it = m_full_watches[l.index()].begin(); - clause_vector::const_iterator end = m_full_watches[l.index()].end(); - for (; it != end; ++it) { - clause& c = *(*it); + for (clause * cp : m_full_watches[l.index()]) { + clause& c = *cp; unsigned sz = c.size(); bool found = false; for (unsigned i = 0; !found && i < sz; ++i) { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 38adc4505..7d4d7a39d 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -66,6 +66,12 @@ namespace sat { friend class ccc; friend class ba_solver; + enum reward_t { + ternary_reward, + unit_literal_reward, + heule_schur_reward + }; + struct config { double m_dl_success; double m_alpha; @@ -76,7 +82,7 @@ namespace sat { double m_delta_rho; unsigned m_dl_max_iterations; unsigned m_tc1_limit; - bool m_use_ternary_reward; + reward_t m_reward_type; config() { m_max_hlevel = 50; @@ -87,7 +93,7 @@ namespace sat { m_delta_rho = (double)0.9995; m_dl_max_iterations = 32; m_tc1_limit = 10000000; - m_use_ternary_reward = true; + m_reward_type = ternary_reward; } }; @@ -389,7 +395,7 @@ namespace sat { bool push_lookahead2(literal lit, unsigned level); void push_lookahead1(literal lit, unsigned level); void pop_lookahead1(literal lit); - double mix_diff(double l, double r) const { return l + r + (1 << 10) * l * r; } + double mix_diff(double l, double r) const; clause const& get_clause(watch_list::iterator it) const; bool is_nary_propagation(clause const& c, literal l) const; void propagate_clauses(literal l); From edb3569599eb9172ae63db15e0469cdd81824bc4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Sep 2017 22:36:19 -0500 Subject: [PATCH 0226/1283] updates to sorting networks Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 35 +- src/opt/sortmax.cpp | 7 +- src/sat/sat_config.cpp | 3 +- src/sat/sat_config.h | 1 + src/sat/sat_lookahead.cpp | 228 ++++++-- src/sat/sat_lookahead.h | 15 +- src/sat/sat_params.pyg | 2 + src/smt/theory_pb.cpp | 8 +- src/test/main.cpp | 1 - src/test/sat_local_search.cpp | 10 +- src/test/sat_lookahead.cpp | 10 +- src/test/sorting_network.cpp | 157 ++++-- src/util/lp/bound_propagator.h | 27 + src/util/lp/cut_solver.h | 201 +++++++ src/util/lp/disjoint_intervals.h | 334 +++++++++++ src/util/lp/init_lar_solver.h | 591 ++++++++++++++++++++ src/util/lp/lp_primal_core_solver_tableau.h | 408 ++++++++++++++ src/util/sorting_network.h | 202 +++++-- 18 files changed, 2070 insertions(+), 170 deletions(-) create mode 100644 src/util/lp/bound_propagator.h create mode 100644 src/util/lp/cut_solver.h create mode 100644 src/util/lp/disjoint_intervals.h create mode 100644 src/util/lp/init_lar_solver.h create mode 100644 src/util/lp/lp_primal_core_solver_tableau.h diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index a60849c4b..fcabdd596 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -43,6 +43,7 @@ struct pb2bv_rewriter::imp { struct card2bv_rewriter { typedef expr* literal; typedef ptr_vector literal_vector; + sorting_network_config m_cfg; psort_nw m_sort; ast_manager& m; imp& m_imp; @@ -570,8 +571,8 @@ struct pb2bv_rewriter::imp { public: - card2bv_rewriter(imp& i, ast_manager& m): - m_sort(*this), + card2bv_rewriter(imp& i, ast_manager& m): + m_sort(*this, m_cfg), m(m), m_imp(i), au(m), @@ -760,8 +761,8 @@ struct pb2bv_rewriter::imp { m_trail.push_back(l); return l; } - literal fresh() { - expr_ref fr(m.mk_fresh_const("sn", m.mk_bool_sort()), m); + literal fresh(char const* n) { + expr_ref fr(m.mk_fresh_const(n, m.mk_bool_sort()), m); m_imp.m_fresh.push_back(to_app(fr)->get_decl()); return trail(fr); } @@ -785,6 +786,8 @@ struct pb2bv_rewriter::imp { void pb_totalizer(bool f) { m_pb_totalizer = f; } + void set_at_most1(sorting_network_encoding enc) { m_cfg.m_encoding = enc; } + }; struct card2bv_rewriter_cfg : public default_rewriter_cfg { @@ -800,6 +803,8 @@ struct pb2bv_rewriter::imp { void keep_pb_constraints(bool f) { m_r.keep_pb_constraints(f); } void pb_num_system(bool f) { m_r.pb_num_system(f); } void pb_totalizer(bool f) { m_r.pb_totalizer(f); } + void set_at_most1(sorting_network_encoding enc) { m_r.set_at_most1(enc); } + }; class card_pb_rewriter : public rewriter_tpl { @@ -812,6 +817,7 @@ struct pb2bv_rewriter::imp { void keep_pb_constraints(bool f) { m_cfg.keep_pb_constraints(f); } void pb_num_system(bool f) { m_cfg.pb_num_system(f); } void pb_totalizer(bool f) { m_cfg.pb_totalizer(f); } + void set_at_most1(sorting_network_encoding e) { m_cfg.set_at_most1(e); } }; card_pb_rewriter m_rw; @@ -844,15 +850,25 @@ struct pb2bv_rewriter::imp { gparams::get_module("sat").get_sym("pb.solver", symbol()) == symbol("totalizer"); } + + sorting_network_encoding atmost1_encoding() const { + symbol enc = m_params.get_sym("atmost1_encoding", enc); + if (enc == symbol()) { + enc = gparams::get_module("sat").get_sym("atmost1_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; + } + + imp(ast_manager& m, params_ref const& p): m(m), m_params(p), m_lemmas(m), m_fresh(m), m_num_translated(0), m_rw(*this, m) { - m_rw.keep_cardinality_constraints(keep_cardinality()); - m_rw.keep_pb_constraints(keep_pb()); - m_rw.pb_num_system(pb_num_system()); - m_rw.pb_totalizer(pb_totalizer()); + updt_params(p); } void updt_params(params_ref const & p) { @@ -860,7 +876,8 @@ struct pb2bv_rewriter::imp { m_rw.keep_cardinality_constraints(keep_cardinality()); m_rw.keep_pb_constraints(keep_pb()); m_rw.pb_num_system(pb_num_system()); - m_rw.pb_totalizer(pb_totalizer()); + m_rw.pb_totalizer(pb_totalizer()); + m_rw.set_at_most1(atmost1_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"); diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 00cab488c..01d8db22d 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -32,12 +32,13 @@ namespace opt { public: typedef expr* literal; typedef ptr_vector literal_vector; + sorting_network_config m_cfg; psort_nw m_sort; expr_ref_vector m_trail; func_decl_ref_vector m_fresh; ref m_filter; sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), m_sort(*this), m_trail(m), m_fresh(m) {} + maxsmt_solver_base(c, ws, soft), m_sort(*this, m_cfg), m_trail(m), m_fresh(m) {} virtual ~sortmax() {} @@ -138,8 +139,8 @@ namespace opt { m_trail.push_back(l); return l; } - literal fresh() { - expr_ref fr(m.mk_fresh_const("sn", m.mk_bool_sort()), m); + literal fresh(char const* n) { + expr_ref fr(m.mk_fresh_const(n, m.mk_bool_sort()), m); func_decl* f = to_app(fr)->get_decl(); m_fresh.push_back(f); m_filter->insert(f); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index ae3161a1a..b2ef3760c 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -87,6 +87,7 @@ namespace sat { m_local_search_threads = p.local_search_threads(); m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_search = p.lookahead_search(); + m_lookahead_reward = p.lookahead_reward(); m_ccc = p.ccc(); // These parameters are not exposed @@ -163,7 +164,7 @@ namespace sat { m_pb_solver = PB_SOLVER; } else { - throw sat_param_exception("invalid PB solver"); + throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); } } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 7595d62fd..71d5e2c9f 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -75,6 +75,7 @@ namespace sat { bool m_local_search; bool m_lookahead_search; bool m_lookahead_simplify; + symbol m_lookahead_reward; bool m_ccc; unsigned m_simplify_mult1; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 4e2d77f67..50cb68431 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -41,7 +41,6 @@ namespace sat { } } - void lookahead::flip_prefix() { if (m_trail_lim.size() < 64) { uint64 mask = (1ull << m_trail_lim.size()); @@ -228,11 +227,6 @@ namespace sat { if (is_sat()) { return false; } - if (newbies) { - enable_trace("sat"); - TRACE("sat", display(tout);); - TRACE("sat", tout << sum << "\n";); - } } SASSERT(!m_candidates.empty()); // cut number of candidates down to max_num_cand. @@ -292,9 +286,8 @@ namespace sat { double lookahead::init_candidates(unsigned level, bool newbies) { m_candidates.reset(); double sum = 0; - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - SASSERT(is_undef(*it)); - bool_var x = *it; + for (bool_var x : m_freevars) { + SASSERT(is_undef(x)); if (!m_select_lookahead_vars.empty()) { if (m_select_lookahead_vars.contains(x)) { m_candidates.push_back(candidate(x, m_rating[x])); @@ -333,20 +326,20 @@ namespace sat { } bool lookahead::is_sat() const { - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - literal l(*it, false); + for (bool_var x : m_freevars) { + literal l(x, false); literal_vector const& lits1 = m_binary[l.index()]; - for (unsigned i = 0; i < lits1.size(); ++i) { - if (!is_true(lits1[i])) { - TRACE("sat", tout << l << " " << lits1[i] << "\n";); + for (literal lit1 : lits1) { + if (!is_true(lit1)) { + TRACE("sat", tout << l << " " << lit1 << "\n";); return false; } } l.neg(); literal_vector const& lits2 = m_binary[l.index()]; - for (unsigned i = 0; i < lits2.size(); ++i) { - if (!is_true(lits2[i])) { - TRACE("sat", tout << l << " " << lits2[i] << "\n";); + for (literal lit2 : lits2) { + if (!is_true(lit2)) { + TRACE("sat", tout << l << " " << lit2 << "\n";); return false; } } @@ -389,12 +382,114 @@ namespace sat { break; } case heule_schur_reward: + heule_schur_scores(); + break; + case heule_unit_reward: + heule_unit_scores(); break; case unit_literal_reward: + heule_schur_scores(); break; } } + static unsigned counter = 0; + void lookahead::heule_schur_scores() { + if (counter % 10 != 0) return; + ++counter; + for (bool_var x : m_freevars) { + literal l(x, false); + m_rating[l.var()] = heule_schur_score(l) * heule_schur_score(~l); + } + } + + double lookahead::heule_schur_score(literal l) { + double sum = 0; + for (literal lit : m_binary[l.index()]) { + if (is_undef(lit)) sum += literal_occs(lit) / 4.0; + } + watch_list& wlist = m_watches[l.index()]; + for (auto & w : wlist) { + switch (w.get_kind()) { + case watched::BINARY: + UNREACHABLE(); + break; + case watched::TERNARY: { + literal l1 = w.get_literal1(); + literal l2 = w.get_literal2(); + if (is_undef(l1) && is_undef(l2)) { + sum += (literal_occs(l1) + literal_occs(l2)) / 8.0; + } + break; + } + case watched::CLAUSE: { + clause_offset cls_off = w.get_clause_offset(); + clause & c = *(m_cls_allocator.get_clause(cls_off)); + unsigned sz = 0; + double to_add = 0; + for (literal lit : c) { + if (is_undef(lit) && lit != ~l) { + to_add += literal_occs(lit); + ++sz; + } + } + sum += pow(0.5, sz) * to_add / sz; + break; + } + default: + break; + } + } + return sum; + } + + void lookahead::heule_unit_scores() { + if (counter % 10 != 0) return; + ++counter; + for (bool_var x : m_freevars) { + literal l(x, false); + m_rating[l.var()] = heule_unit_score(l) * heule_unit_score(~l); + } + } + + double lookahead::heule_unit_score(literal l) { + double sum = 0; + for (literal lit : m_binary[l.index()]) { + if (is_undef(lit)) sum += 0.25; + } + watch_list& wlist = m_watches[l.index()]; + for (auto & w : wlist) { + switch (w.get_kind()) { + case watched::BINARY: + UNREACHABLE(); + break; + case watched::TERNARY: { + literal l1 = w.get_literal1(); + literal l2 = w.get_literal2(); + if (is_undef(l1) && is_undef(l2)) { + sum += 0.25; + } + break; + } + case watched::CLAUSE: { + clause_offset cls_off = w.get_clause_offset(); + clause & c = *(m_cls_allocator.get_clause(cls_off)); + unsigned sz = 0; + for (literal lit : c) { + if (is_undef(lit) && lit != ~l) { + ++sz; + } + } + sum += pow(0.5, sz); + break; + } + default: + break; + } + } + return sum; + } + void lookahead::ensure_H(unsigned level) { while (m_H.size() <= level) { m_H.push_back(svector()); @@ -404,16 +499,16 @@ namespace sat { void lookahead::h_scores(svector& h, svector& hp) { double sum = 0; - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - literal l(*it, false); + for (bool_var x : m_freevars) { + literal l(x, false); sum += h[l.index()] + h[(~l).index()]; } if (sum == 0) sum = 0.0001; double factor = 2 * m_freevars.size() / sum; double sqfactor = factor * factor; double afactor = factor * m_config.m_alpha; - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - literal l(*it, false); + for (bool_var x : m_freevars) { + literal l(x, false); double pos = l_score(l, h, factor, sqfactor, afactor); double neg = l_score(~l, h, factor, sqfactor, afactor); hp[l.index()] = pos; @@ -425,28 +520,25 @@ namespace sat { double lookahead::l_score(literal l, svector const& h, double factor, double sqfactor, double afactor) { double sum = 0, tsum = 0; - literal_vector::iterator it = m_binary[l.index()].begin(), end = m_binary[l.index()].end(); - for (; it != end; ++it) { - bool_var v = it->var(); - if (is_undef(*it)) sum += h[it->index()]; - // if (m_freevars.contains(it->var())) sum += h[it->index()]; + for (literal lit : m_binary[l.index()]) { + if (is_undef(lit)) sum += h[lit.index()]; + // if (m_freevars.contains(lit.var())) sum += h[lit.index()]; } watch_list& wlist = m_watches[l.index()]; - watch_list::iterator wit = wlist.begin(), wend = wlist.end(); - for (; wit != wend; ++wit) { - switch (wit->get_kind()) { + for (auto & w : wlist) { + switch (w.get_kind()) { case watched::BINARY: UNREACHABLE(); break; case watched::TERNARY: { - literal l1 = wit->get_literal1(); - literal l2 = wit->get_literal2(); + literal l1 = w.get_literal1(); + literal l2 = w.get_literal2(); // if (is_undef(l1) && is_undef(l2)) tsum += h[l1.index()] * h[l2.index()]; break; } case watched::CLAUSE: { - clause_offset cls_off = wit->get_clause_offset(); + clause_offset cls_off = w.get_clause_offset(); clause & c = *(m_cls_allocator.get_clause(cls_off)); // approximation compared to ternary clause case: // we pick two other literals from the clause. @@ -865,8 +957,6 @@ namespace sat { copy_clauses(m_s.m_clauses); copy_clauses(m_s.m_learned); - // m_config.m_use_ternary_reward &= !m_s.m_ext; - // copy units unsigned trail_sz = m_s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { @@ -995,15 +1085,17 @@ namespace sat { return unsat; } - void lookahead::push_lookahead1(literal lit, unsigned level) { + unsigned lookahead::push_lookahead1(literal lit, unsigned level) { SASSERT(m_search_mode == lookahead_mode::searching); m_search_mode = lookahead_mode::lookahead1; scoped_level _sl(*this, level); + unsigned old_sz = m_trail.size(); assign(lit); propagate(); + return m_trail.size() - old_sz; } - void lookahead::pop_lookahead1(literal lit) { + void lookahead::pop_lookahead1(literal lit, unsigned num_units) { bool unsat = inconsistent(); SASSERT(m_search_mode == lookahead_mode::lookahead1); m_inconsistent = false; @@ -1025,8 +1117,15 @@ namespace sat { } m_stats.m_windfall_binaries += m_wstack.size(); } - if (m_config.m_reward_type == unit_literal_reward) { - m_lookahead_reward += m_wstack.size(); + switch (m_config.m_reward_type) { + case unit_literal_reward: + m_lookahead_reward += num_units; + break; + case heule_unit_reward: + case heule_schur_reward: + break; + default: + break; } m_wstack.reset(); } @@ -1226,6 +1325,9 @@ namespace sat { case heule_schur_reward: m_lookahead_reward += (literal_occs(l1) + literal_occs(l2)) / 8.0; break; + case heule_unit_reward: + m_lookahead_reward += 0.25; + break; case unit_literal_reward: break; } @@ -1253,6 +1355,9 @@ namespace sat { m_lookahead_reward += pow(0.5, sz) * to_add / sz; break; } + case heule_unit_reward: + m_lookahead_reward += pow(0.5, sz); + break; case ternary_reward: m_lookahead_reward = (double)0.001; break; @@ -1326,11 +1431,13 @@ namespace sat { IF_VERBOSE(30, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); } TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); + unsigned old_trail_sz = m_trail.size(); reset_lookahead_reward(lit); push_lookahead1(lit, level); if (!first) do_double(lit, base); - bool unsat = inconsistent(); - pop_lookahead1(lit); + bool unsat = inconsistent(); + unsigned num_units = m_trail.size() - old_trail_sz; + pop_lookahead1(lit, num_units); if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); reset_lookahead_reward(); @@ -1407,6 +1514,7 @@ namespace sat { switch (m_config.m_reward_type) { case ternary_reward: return l + r + (1 << 10) * l * r; case heule_schur_reward: return l * r; + case heule_unit_reward: return l * r; case unit_literal_reward: return l * r; default: UNREACHABLE(); return l * r; } @@ -1489,7 +1597,7 @@ namespace sat { } } } - else { + else { inc_lookahead_reward(l, m_lookahead_reward); } } @@ -1625,7 +1733,13 @@ namespace sat { } TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); ++m_stats.m_decisions; - IF_VERBOSE(1, verbose_stream() << "select " << pp_prefix(m_prefix, m_trail_lim.size()) << ": " << l << " " << m_trail.size() << "\n";); + IF_VERBOSE(1, printf("\r"); + std::stringstream strm; + strm << pp_prefix(m_prefix, m_trail_lim.size()); + for (unsigned i = 0; i < 50; ++i) strm << " "; + printf(strm.str().c_str()); + fflush(stdout); + ); push(l, c_fixed_truth); trail.push_back(l); SASSERT(inconsistent() || !is_unsat()); @@ -1851,16 +1965,20 @@ namespace sat { m_lookahead.reset(); } - std::ostream& lookahead::display(std::ostream& out) const { + std::ostream& lookahead::display_summary(std::ostream& out) const { out << "Prefix: " << pp_prefix(m_prefix, m_trail_lim.size()) << "\n"; out << "Level: " << m_level << "\n"; + out << "Free vars: " << m_freevars.size() << "\n"; + return out; + } + + std::ostream& lookahead::display(std::ostream& out) const { + display_summary(out); display_values(out); display_binary(out); display_clauses(out); out << "free vars: "; - for (bool_var const* it = m_freevars.begin(), * end = m_freevars.end(); it != end; ++it) { - out << *it << " "; - } + for (bool_var b : m_freevars) out << b << " "; out << "\n"; for (unsigned i = 0; i < m_watches.size(); ++i) { watch_list const& wl = m_watches[i]; @@ -1879,6 +1997,24 @@ namespace sat { return m_model; } + void lookahead::init_config() { + if (m_s.m_config.m_lookahead_reward == symbol("hs")) { + m_config.m_reward_type = heule_schur_reward; + } + else if (m_s.m_config.m_lookahead_reward == symbol("heuleu")) { + m_config.m_reward_type = heule_unit_reward; + } + else if (m_s.m_config.m_lookahead_reward == symbol("ternary")) { + m_config.m_reward_type = ternary_reward; + } + else if (m_s.m_config.m_lookahead_reward == symbol("unit")) { + m_config.m_reward_type = unit_literal_reward; + } + else { + warning_msg("Reward type not recognized"); + } + } + void lookahead::collect_statistics(statistics& st) const { st.update("lh bool var", m_vprefix.size()); st.update("lh clauses", m_clauses.size()); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 7d4d7a39d..8ec44abcf 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -69,7 +69,8 @@ namespace sat { enum reward_t { ternary_reward, unit_literal_reward, - heule_schur_reward + heule_schur_reward, + heule_unit_reward }; struct config { @@ -277,6 +278,10 @@ namespace sat { void init_pre_selection(unsigned level); void ensure_H(unsigned level); void h_scores(svector& h, svector& hp); + void heule_schur_scores(); + double heule_schur_score(literal l); + void heule_unit_scores(); + double heule_unit_score(literal l); double l_score(literal l, svector const& h, double factor, double sqfactor, double afactor); // ------------------------------------ @@ -393,8 +398,8 @@ namespace sat { void push(literal lit, unsigned level); void pop(); bool push_lookahead2(literal lit, unsigned level); - void push_lookahead1(literal lit, unsigned level); - void pop_lookahead1(literal lit); + unsigned push_lookahead1(literal lit, unsigned level); + void pop_lookahead1(literal lit, unsigned num_units); double mix_diff(double l, double r) const; clause const& get_clause(watch_list::iterator it) const; bool is_nary_propagation(clause const& c, literal l) const; @@ -444,6 +449,8 @@ namespace sat { void init_search(); void checkpoint(); + void init_config(); + public: lookahead(solver& s) : m_s(s), @@ -453,6 +460,7 @@ namespace sat { m_level(2), m_prefix(0) { m_s.rlimit().push_child(&m_rlimit); + init_config(); } ~lookahead() { @@ -488,6 +496,7 @@ namespace sat { void scc(); std::ostream& display(std::ostream& out) const; + std::ostream& display_summary(std::ostream& out) const; model const& get_model(); void collect_statistics(statistics& st) const; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 06edabc8b..b856921b2 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -31,9 +31,11 @@ def_module_params('sat', ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), ('xor.solver', BOOL, False, 'use xor solver'), + ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), + ('lookahead.reward', SYMBOL, 'heuleu', 'select lookahead heuristic: ternary, hs (Heule Schur), heuleu (Heule Unit), or unit'), ('ccc', BOOL, False, 'use Concurrent Cube and Conquer solver') )) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 19feb3551..153d31b05 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1396,7 +1396,7 @@ namespace smt { th(th), pb(m) {} - literal fresh() { + literal fresh(char const* ) { app_ref y(m); y = pb.mk_fresh_bool(); return literal(ctx.mk_bool_var(y)); @@ -1441,7 +1441,8 @@ namespace smt { theory_pb_params p; theory_pb th(ctx.get_manager(), p); psort_expr ps(ctx, th); - psort_nw sort(ps); + sorting_network_config cfg; + psort_nw sort(ps, cfg); return sort.ge(false, k, n, xs); } @@ -1577,7 +1578,8 @@ namespace smt { psort_expr ps(ctx, *this); - psort_nw sortnw(ps); + sorting_network_config cfg; + psort_nw sortnw(ps, cfg); sortnw.m_stats.reset(); if (ctx.get_assignment(thl) == l_true && diff --git a/src/test/main.cpp b/src/test/main.cpp index fd72138c7..613c11532 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -239,7 +239,6 @@ int main(int argc, char ** argv) { TST(pdr); TST_ARGV(ddnf); TST(model_evaluator); - TST_ARGV(lp); TST(get_consequences); TST(pb2bv); TST_ARGV(sat_lookahead); diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 23558ea44..fc1445e34 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -1,8 +1,8 @@ -#include "sat_local_search.h" -#include "sat_solver.h" -#include "cancel_eh.h" -#include "scoped_ctrl_c.h" -#include "scoped_timer.h" +#include "sat/sat_local_search.h" +#include "sat/sat_solver.h" +#include "util/cancel_eh.h" +#include "util/scoped_ctrl_c.h" +#include "util/scoped_timer.h" static bool build_instance(char const * filename, sat::solver& s, sat::local_search& local_search) { diff --git a/src/test/sat_lookahead.cpp b/src/test/sat_lookahead.cpp index b02af0b04..fccbe8eed 100644 --- a/src/test/sat_lookahead.cpp +++ b/src/test/sat_lookahead.cpp @@ -1,8 +1,8 @@ -#include "sat_solver.h" -#include "sat_watched.h" -#include "statistics.h" -#include "sat_lookahead.h" -#include "dimacs.h" +#include "sat/sat_solver.h" +#include "sat/sat_watched.h" +#include "util/statistics.h" +#include "sat/sat_lookahead.h" +#include "sat/dimacs.h" static void display_model(sat::model const & m) { for (unsigned i = 1; i < m.size(); i++) { diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 2984e94e2..7cc046304 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -6,14 +6,14 @@ Copyright (c) 2015 Microsoft Corporation #include "util/trace.h" #include "util/vector.h" +#include "util/sorting_network.h" #include "ast/ast.h" #include "ast/ast_pp.h" #include "ast/reg_decl_plugins.h" -#include "util/sorting_network.h" -#include "smt/smt_kernel.h" -#include "model/model_smt2_pp.h" -#include "smt/params/smt_params.h" #include "ast/ast_util.h" +#include "model/model_smt2_pp.h" +#include "smt/smt_kernel.h" +#include "smt/params/smt_params.h" @@ -174,16 +174,61 @@ struct ast_ext2 { std::ostream& pp(std::ostream& out, literal lit) { return out << mk_pp(lit, m); } - literal fresh() { - return trail(m.mk_fresh_const("x", m.mk_bool_sort())); + literal fresh(char const* n) { + return trail(m.mk_fresh_const(n, m.mk_bool_sort())); } void mk_clause(unsigned n, literal const* lits) { m_clauses.push_back(mk_or(m, n, lits)); } }; +static void test_eq1(unsigned n, sorting_network_encoding enc) { + //std::cout << "test eq1 " << n << " for encoding: " << enc << "\n"; + ast_manager m; + reg_decl_plugins(m); + ast_ext2 ext(m); + expr_ref_vector in(m), out(m); + for (unsigned i = 0; i < n; ++i) { + in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); + } + smt_params fp; + smt::kernel solver(m, fp); + sorting_network_config cfg; + cfg.m_encoding = enc; + psort_nw sn(ext, cfg); + expr_ref result1(m), result2(m); -static void test_sorting_eq(unsigned n, unsigned k) { + // equality: + solver.push(); + result1 = sn.eq(true, 1, in.size(), in.c_ptr()); + for (expr* cl : ext.m_clauses) { + solver.assert_expr(cl); + } + expr_ref_vector ors(m); + for (unsigned i = 0; i < n; ++i) { + expr_ref_vector ands(m); + for (unsigned j = 0; j < n; ++j) { + ands.push_back(j == i ? in[j].get() : m.mk_not(in[j].get())); + } + ors.push_back(mk_and(ands)); + } + result2 = mk_or(ors); + solver.assert_expr(m.mk_not(m.mk_eq(result1, result2))); + //std::cout << ext.m_clauses << "\n"; + //std::cout << result1 << "\n"; + //std::cout << result2 << "\n"; + lbool res = solver.check(); + if (res == l_true) { + model_ref model; + solver.get_model(model); + model_smt2_pp(std::cout, m, *model, 0); + TRACE("pb", model_smt2_pp(tout, m, *model, 0);); + } + ENSURE(l_false == res); + ext.m_clauses.reset(); +} + +static void test_sorting_eq(unsigned n, unsigned k, sorting_network_encoding enc) { ENSURE(k < n); ast_manager m; reg_decl_plugins(m); @@ -194,16 +239,19 @@ static void test_sorting_eq(unsigned n, unsigned k) { } smt_params fp; smt::kernel solver(m, fp); - psort_nw sn(ext); + sorting_network_config cfg; + cfg.m_encoding = enc; + psort_nw sn(ext, cfg); expr_ref result(m); // equality: - std::cout << "eq " << k << "\n"; + std::cout << "eq " << k << " out of " << n << " for encoding " << enc << "\n"; solver.push(); - result = sn.eq(true, k, in.size(), in.c_ptr()); + result = sn.eq(false, k, in.size(), in.c_ptr()); + std::cout << result << "\n" << ext.m_clauses << "\n"; solver.assert_expr(result); - for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { - solver.assert_expr(ext.m_clauses[i].get()); + for (expr* cl : ext.m_clauses) { + solver.assert_expr(cl); } lbool res = solver.check(); ENSURE(res == l_true); @@ -232,7 +280,7 @@ static void test_sorting_eq(unsigned n, unsigned k) { ext.m_clauses.reset(); } -static void test_sorting_le(unsigned n, unsigned k) { +static void test_sorting_le(unsigned n, unsigned k, sorting_network_encoding enc) { ast_manager m; reg_decl_plugins(m); ast_ext2 ext(m); @@ -242,7 +290,9 @@ static void test_sorting_le(unsigned n, unsigned k) { } smt_params fp; smt::kernel solver(m, fp); - psort_nw sn(ext); + sorting_network_config cfg; + cfg.m_encoding = enc; + psort_nw sn(ext, cfg); expr_ref result(m); // B <= k std::cout << "le " << k << "\n"; @@ -279,7 +329,7 @@ static void test_sorting_le(unsigned n, unsigned k) { } -void test_sorting_ge(unsigned n, unsigned k) { +void test_sorting_ge(unsigned n, unsigned k, sorting_network_encoding enc) { ast_manager m; reg_decl_plugins(m); ast_ext2 ext(m); @@ -289,7 +339,9 @@ void test_sorting_ge(unsigned n, unsigned k) { } smt_params fp; smt::kernel solver(m, fp); - psort_nw sn(ext); + sorting_network_config cfg; + cfg.m_encoding = enc; + psort_nw sn(ext, cfg); expr_ref result(m); // k <= B std::cout << "ge " << k << "\n"; @@ -325,11 +377,11 @@ void test_sorting_ge(unsigned n, unsigned k) { solver.pop(1); } -void test_sorting5(unsigned n, unsigned k) { +void test_sorting5(unsigned n, unsigned k, sorting_network_encoding enc) { std::cout << "n: " << n << " k: " << k << "\n"; - test_sorting_le(n, k); - test_sorting_eq(n, k); - test_sorting_ge(n, k); + test_sorting_le(n, k, enc); + test_sorting_eq(n, k, enc); + test_sorting_ge(n, k, enc); } expr_ref naive_at_most1(expr_ref_vector const& xs) { @@ -343,7 +395,7 @@ expr_ref naive_at_most1(expr_ref_vector const& xs) { return mk_and(clauses); } -void test_at_most_1(unsigned n, bool full) { +void test_at_most_1(unsigned n, bool full, sorting_network_encoding enc) { ast_manager m; reg_decl_plugins(m); expr_ref_vector in(m), out(m); @@ -352,12 +404,17 @@ void test_at_most_1(unsigned n, bool full) { } ast_ext2 ext(m); - psort_nw sn(ext); + sorting_network_config cfg; + cfg.m_encoding = enc; + psort_nw sn(ext, cfg); expr_ref result1(m), result2(m); result1 = sn.le(full, 1, in.size(), in.c_ptr()); result2 = naive_at_most1(in); + std::cout << "clauses: " << ext.m_clauses << "\n-----\n"; + std::cout << "encoded: " << result1 << "\n"; + std::cout << "naive: " << result2 << "\n"; smt_params fp; smt::kernel solver(m, fp); @@ -369,15 +426,27 @@ void test_at_most_1(unsigned n, bool full) { solver.assert_expr(m.mk_not(m.mk_eq(result1, result2))); std::cout << result1 << "\n"; + lbool res = solver.check(); + if (res == l_true) { + model_ref model; + solver.get_model(model); + model_smt2_pp(std::cout, m, *model, 0); + } - VERIFY(l_false == solver.check()); + VERIFY(l_false == res); solver.pop(1); } if (n >= 9) return; + if (n <= 1) return; for (unsigned i = 0; i < static_cast(1 << n); ++i) { - std::cout << "checking: " << n << ": " << i << "\n"; + std::cout << "checking n: " << n << " bits: "; + for (unsigned j = 0; j < n; ++j) { + bool is_true = (i & (1 << j)) != 0; + std::cout << (is_true?"1":"0"); + } + std::cout << "\n"; solver.push(); unsigned k = 0; for (unsigned j = 0; j < n; ++j) { @@ -388,7 +457,6 @@ void test_at_most_1(unsigned n, bool full) { std::cout << atom << "\n"; if (is_true) ++k; } - VERIFY(l_false == solver.check()); if (k > 1) { solver.assert_expr(result1); } @@ -405,7 +473,7 @@ void test_at_most_1(unsigned n, bool full) { } -static void test_at_most1() { +static void test_at_most1(sorting_network_encoding enc) { ast_manager m; reg_decl_plugins(m); expr_ref_vector in(m), out(m); @@ -415,28 +483,45 @@ static void test_at_most1() { in[4] = in[3].get(); ast_ext2 ext(m); - psort_nw sn(ext); + sorting_network_config cfg; + cfg.m_encoding = enc; + psort_nw sn(ext, cfg); expr_ref result(m); result = sn.le(true, 1, in.size(), in.c_ptr()); std::cout << result << "\n"; std::cout << ext.m_clauses << "\n"; } -void tst_sorting_network() { - for (unsigned i = 1; i < 17; ++i) { - test_at_most_1(i, true); - test_at_most_1(i, false); - } - test_at_most1(); - - test_sorting_eq(11,7); +static void test_sorting5(sorting_network_encoding enc) { + test_sorting_eq(11,7, enc); for (unsigned n = 3; n < 20; n += 2) { for (unsigned k = 1; k < n; ++k) { - test_sorting5(n, k); + test_sorting5(n, k, enc); } } +} + +static void tst_sorting_network(sorting_network_encoding enc) { + for (unsigned i = 1; i < 17; ++i) { + test_at_most_1(i, true, enc); + test_at_most_1(i, false, enc); + } + for (unsigned n = 2; n < 20; ++n) { + std::cout << "verify eq-1 out of " << n << "\n"; + test_sorting_eq(n, 1, enc); + test_eq1(n, enc); + } + test_at_most1(enc); + test_sorting5(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); test_sorting1(); test_sorting2(); test_sorting3(); test_sorting4(); } + diff --git a/src/util/lp/bound_propagator.h b/src/util/lp/bound_propagator.h new file mode 100644 index 000000000..128973c12 --- /dev/null +++ b/src/util/lp/bound_propagator.h @@ -0,0 +1,27 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ +#pragma once +#include "util/lp/lp_settings.h" +namespace lp { +class lar_solver; +class bound_propagator { + std::unordered_map m_improved_low_bounds; // these maps map a column index to the corresponding index in ibounds + std::unordered_map m_improved_upper_bounds; + lar_solver & m_lar_solver; +public: + vector m_ibounds; +public: + bound_propagator(lar_solver & ls); + column_type get_column_type(unsigned) const; + const impq & get_low_bound(unsigned) const; + const impq & get_upper_bound(unsigned) const; + void try_add_bound(mpq v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict); + virtual bool bound_is_interesting(unsigned vi, + lp::lconstraint_kind kind, + const rational & bval) {return true;} + unsigned number_of_found_bounds() const { return m_ibounds.size(); } + virtual void consume(mpq const& v, unsigned j) { std::cout << "doh\n"; } +}; +} diff --git a/src/util/lp/cut_solver.h b/src/util/lp/cut_solver.h new file mode 100644 index 000000000..18da0b88b --- /dev/null +++ b/src/util/lp/cut_solver.h @@ -0,0 +1,201 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Nikolaj Bjorner, Lev Nachmanson +*/ +#pragma once +#include "util/vector.h" +#include "util/trace.h" +#include "util/lp/lp_settings.h" +namespace lp { +template +class cut_solver { + + struct ineq { // we only have less or equal, which is enough for integral variables + mpq m_bound; + vector> m_term; + ineq(vector>& term, mpq bound):m_bound(bound),m_term(term) { + } + }; + + vector m_ineqs; + + enum class lbool { + l_false, // false + l_true, // true + l_undef // undef + }; + + enum class literal_type { + BOOL, + INEQ, + BOUND + }; + + struct literal { + literal_type m_tag; + bool m_sign; // true means the pointed inequality is negated, or bound is negated, or boolean value is negated + + unsigned m_id; + unsigned m_index_of_ineq; // index into m_ineqs + bool m_bool_val; // used if m_tag is equal to BOOL + mpq m_bound; // used if m_tag is BOUND + literal(bool sign, bool val): m_tag(literal_type::BOOL), + m_bool_val(val){ + } + literal(bool sign, unsigned index_of_ineq) : m_tag(literal_type::INEQ), m_index_of_ineq(index_of_ineq) {} + }; + + bool lhs_is_int(const vector> & lhs) const { + for (auto & p : lhs) + if (p.first.is_int() == false) return false; + return true; + } + + public: + void add_ineq(vector> & lhs, mpq rhs) { + lp_assert(lhs_is_int(lhs)); + lp_assert(rhs.is_int()); + m_ineqs.push_back(ineq(lhs, rhs)); + } + + + bool m_inconsistent; // tracks if state is consistent + unsigned m_scope_lvl; // tracks the number of case splits + + svector m_trail; + // backtracking state from the SAT solver: + struct scope { + unsigned m_trail_lim; // pointer into assignment stack + unsigned m_clauses_to_reinit_lim; // ignore for now + bool m_inconsistent; // really needed? + }; + + svector m_scopes; + + bool at_base_lvl() const { return m_scope_lvl == 0; } + + lbool check() { + init_search(); + propagate(); + while (true) { + lbool r = bounded_search(); + if (r != lbool::l_undef) + return r; + + restart(); + simplify_problem(); + if (check_inconsistent()) return lbool::l_false; + gc(); + } + } + + cut_solver() { + } + + void init_search() { + // TBD + // initialize data-structures + } + + void simplify_problem() { + // no-op + } + + void gc() { + // no-op + } + + void restart() { + // no-op for now + } + + bool check_inconsistent() { + // TBD + return false; + } + + lbool bounded_search() { + while (true) { + checkpoint(); + bool done = false; + while (!done) { + lbool is_sat = propagate_and_backjump_step(done); + if (is_sat != lbool::l_true) return is_sat; + } + + gc(); + + if (!decide()) { + lbool is_sat = final_check(); + if (is_sat != lbool::l_undef) { + return is_sat; + } + } + } + } + + void checkpoint() { + // check for cancelation + } + + void cleanup() { + } + + lbool propagate_and_backjump_step(bool& done) { + done = true; + propagate(); + if (!inconsistent()) + return lbool::l_true; + if (!resolve_conflict()) + return lbool::l_false; + if (at_base_lvl()) { + cleanup(); // cleaner may propagate frozen clauses + if (inconsistent()) { + TRACE("sat", tout << "conflict at level 0\n";); + return lbool::l_false; + } + gc(); + } + done = false; + return lbool::l_true; + } + + lbool final_check() { + // there are no more case splits, and all clauses are satisfied. + // prepare the model for external consumption. + return lbool::l_true; + } + + + bool resolve_conflict() { + while (true) { + bool r = resolve_conflict_core(); + // after pop, clauses are reinitialized, + // this may trigger another conflict. + if (!r) + return false; + if (!inconsistent()) + return true; + } + } + + bool resolve_conflict_core() { + // this is where the main action is. + return true; + } + + void propagate() { + // this is where the main action is. + } + + bool decide() { + // this is where the main action is. + // pick the next variable and bound or value on the variable. + // return false if all variables have been assigned. + return false; + } + + bool inconsistent() const { return m_inconsistent; } + +}; +} diff --git a/src/util/lp/disjoint_intervals.h b/src/util/lp/disjoint_intervals.h new file mode 100644 index 000000000..5f4f31af6 --- /dev/null +++ b/src/util/lp/disjoint_intervals.h @@ -0,0 +1,334 @@ +/* + Copyright (c) 2017 Microsoft Corporation + Author: Lev Nachmanson +*/ +#pragma once +#include +namespace lp { +// represents the set of disjoint intervals of integer number +struct disjoint_intervals { + std::map m_endpoints; // 0 means start, 1 means end, 2 means both - for a point interval + bool m_empty; + // constructors create an interval containing all integer numbers or an empty interval + disjoint_intervals() : m_empty(false) {} + disjoint_intervals(bool is_empty) : m_empty(is_empty) {} + + bool is_start(short x) const { return x == 0 || x == 2; } + bool is_start(const std::map::iterator & it) const { + return is_start(it->second); + } + bool is_start(const std::map::reverse_iterator & it) const { + return is_start(it->second); + } + bool is_end(short x) const { return x == 1 || x == 2; } + bool is_end(const std::map::iterator & it) const { + return is_end(it->second); + } + bool is_end(const std::map::reverse_iterator & it) const { + return is_end(it->second); + } + + int pos(const std::map::iterator & it) const { + return it->first; + } + int pos(const std::map::reverse_iterator & it) const { + return it->first; + } + + int bound_kind(const std::map::iterator & it) const { + return it->second; + } + + int bound_kind(const std::map::reverse_iterator & it) const { + return it->second; + } + + bool is_proper_start(short x) const { return x == 0; } + bool is_proper_end(short x) const { return x == 1; } + bool is_proper_end(const std::map::iterator & it) const { + return is_proper_end(it->second); + } + bool is_proper_end(const std::map::reverse_iterator & it) const { + return is_proper_end(it->second); + } + + bool is_one_point_interval(short x) const { return x == 2; } + bool is_one_point_interval(const std::map::iterator & it) const { + return is_one_point_interval(it->second); + } + bool is_one_point_interval(const std::map::reverse_iterator & it) const { + return is_one_point_interval(it->second); + } + + + void erase(int x) { + m_endpoints.erase(x); + } + + void set_one_point_segment(int x) { + m_endpoints[x] = 2; + } + + void set_start(int x) { + m_endpoints[x] = 0; + } + + void set_end(int x) { + m_endpoints[x] = 1; + } + + void remove_all_endpoints_below(int x) { + while (m_endpoints.begin() != m_endpoints.end() && m_endpoints.begin()->first < x) + m_endpoints.erase(m_endpoints.begin()); + } + // we intersect the existing set with the half open to the right interval + void intersect_with_lower_bound(int x) { + if (m_empty) + return; + if (m_endpoints.empty()) { + set_start(x); + return; + } + bool pos_inf = has_pos_inf(); + auto it = m_endpoints.begin(); + while (it != m_endpoints.end() && pos(it) < x) { + m_endpoints.erase(it); + it = m_endpoints.begin(); + } + if (m_endpoints.empty()) { + if (!pos_inf) { + m_empty = true; + return; + } + set_start(x); + return; + } + lp_assert(pos(it) >= x); + if (pos(it) == x) { + if (is_proper_end(it)) + set_one_point_segment(x); + } + else { // x(it) > x + if (is_proper_end(it)) { + set_start(x); + } + } + + lp_assert(is_correct()); + } + + // we intersect the existing set with the half open interval + void intersect_with_upper_bound(int x) { + if (m_empty) + return; + if (m_endpoints.empty()) { + set_end(x); + return; + } + bool neg_inf = has_neg_inf(); + auto it = m_endpoints.rbegin(); + + while (!m_endpoints.empty() && pos(it) > x) { + m_endpoints.erase(std::prev(m_endpoints.end())); + it = m_endpoints.rbegin(); + } + if (m_endpoints.empty()) { + if (!neg_inf) { + m_empty = true; + return; + } + set_end(x); + } + lp_assert(pos(it) <= x); + if (pos(it) == x) { + if (is_one_point_interval(it)) {} + else if (is_proper_end(it)) {} + else {// is_proper_start(it->second) + set_one_point_segment(x); + } + } + else { // pos(it) < x} + if (is_start(it)) + set_end(x); + } + lp_assert(is_correct()); + } + + bool has_pos_inf() const { + if (m_empty) + return false; + + if (m_endpoints.empty()) + return true; + + lp_assert(m_endpoints.rbegin() != m_endpoints.rend()); + return m_endpoints.rbegin()->second == 0; + } + + bool has_neg_inf() const { + if (m_empty) + return false; + + if (m_endpoints.empty()) + return true; + auto it = m_endpoints.begin(); + return is_proper_end(it->second);//m_endpoints.begin()); + } + + // we are intersecting + void intersect_with_interval(int x, int y) { + if (m_empty) + return; + lp_assert(x <= y); + intersect_with_lower_bound(x); + intersect_with_upper_bound(y); + } + + // add an intervar [x, inf] + void unite_with_interval_x_pos_inf(int x) { + if (m_empty) { + set_start(x); + m_empty = false; + return; + } + + while (!m_endpoints.empty() && pos(m_endpoints.rbegin()) > x) { + m_endpoints.erase(std::prev(m_endpoints.end())); + } + + if (m_endpoints.empty()) { + set_start(x); + return; + } + auto it = m_endpoints.rbegin(); + lp_assert(pos(it) <= x); + if (pos(it) == x) { + if (is_end(it)) { + m_endpoints.erase(x); + } else { + set_start(x); + } + } else if (pos(it) == x - 1 && is_end(it)) { + m_endpoints.erase(x - 1); // closing the gap + } else { + if (!has_pos_inf()) + set_start(x); + } + } + + // add an interval [-inf, x] + void unite_with_interval_neg_inf_x(int x) { + if (m_empty) { + set_end(x); + m_empty = false; + return; + } + auto it = m_endpoints.upper_bound(x); + + if (it == m_endpoints.end()) { + bool pos_inf = has_pos_inf(); + m_endpoints.clear(); + // it could be the case where x is inside of the last infinite interval with pos inf + if (!pos_inf) + set_end(x); + return; + } + lp_assert(pos(it) > x); + if (is_one_point_interval(pos(it))) { + set_end(it->second); + } else { + if (is_start(it->second)) { + set_end(x); + } + } + + while (!m_endpoints.empty() && m_endpoints.begin()->first < x) { + m_endpoints.erase(m_endpoints.begin()); + } + lp_assert(is_correct()); + } + + void unite_with_interval(int x, int y) { + lp_assert(false); // not implemented + } + + bool is_correct() const { + if (m_empty) { + if (m_endpoints.size() > 0) { + std::cout << "is empty is true but m_endpoints.size() = " << m_endpoints.size() << std::endl; + return false; + } + return true; + } + bool expect_end; + bool prev = false; + int prev_x; + for (auto t : m_endpoints) { + if (prev && (expect_end != t.second > 0)) { + std::cout << "x = " << t.first << "\n"; + if (expect_end) { + std::cout << "expecting an interval end\n"; + } else { + std::cout << "expecting an interval start\n"; + } + return false; + } + + if (t.second == 2) { + expect_end = false; // swallow a point interval + } else { + if (prev) + expect_end = !expect_end; + else + expect_end = is_start(t.second); + } + if (prev) { + if (t.first - prev_x <= 1) { + std::cout << "the sequence is not increasing or the gap is too small: " << prev_x << ", " << t.first << std::endl; + return false; + } + } + prev = true; + prev_x = t.first; + } + + return true; + } + + void print(std::ostream & out) const { + if (m_empty) { + out << "empty\n"; + return; + } + if (m_endpoints.empty()){ + out << "[-oo,oo]\n"; + return; + } + bool first = true; + for (auto t : m_endpoints) { + if (first) { + if (t.second == 1) { + out << "[-oo," << t.first << "]"; + } + else if (t.second == 0) + out << "[" << t.first << ","; + else if (t.second == 2) + out << "[" << t.first << "]"; + first = false; + } else { + if (t.second==0) + out << "[" << t.first << ","; + else if (t.second == 1) + out << t.first << "]"; + else if (t.second == 2) + out << "[" << t.first << "]"; + } + } + if (has_pos_inf()) + out << "oo]"; + out << "\n"; + } + + +}; +} diff --git a/src/util/lp/init_lar_solver.h b/src/util/lp/init_lar_solver.h new file mode 100644 index 000000000..5d78c3ba7 --- /dev/null +++ b/src/util/lp/init_lar_solver.h @@ -0,0 +1,591 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ + +// here we are inside lp::lar_solver class + +bool strategy_is_undecided() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; +} + +var_index add_var(unsigned ext_j) { + var_index i; + SASSERT (ext_j < m_terms_start_index); + + if (ext_j >= m_terms_start_index) + throw 0; // todo : what is the right way to exit? + + if (try_get_val(m_ext_vars_to_columns, ext_j, i)) { + return i; + } + SASSERT(m_vars_to_ul_pairs.size() == A_r().column_count()); + i = A_r().column_count(); + m_vars_to_ul_pairs.push_back (ul_pair(static_cast(-1))); + add_non_basic_var_to_core_fields(ext_j); + SASSERT(sizes_are_correct()); + return i; +} + +void register_new_ext_var_index(unsigned ext_v) { + SASSERT(!contains(m_ext_vars_to_columns, ext_v)); + unsigned j = static_cast(m_ext_vars_to_columns.size()); + m_ext_vars_to_columns[ext_v] = j; + SASSERT(m_columns_to_ext_vars_or_term_indices.size() == j); + m_columns_to_ext_vars_or_term_indices.push_back(ext_v); +} + +void add_non_basic_var_to_core_fields(unsigned ext_j) { + register_new_ext_var_index(ext_j); + m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); + m_columns_with_changed_bound.increase_size_by_one(); + add_new_var_to_core_fields_for_mpq(false); + if (use_lu()) + add_new_var_to_core_fields_for_doubles(false); +} + +void add_new_var_to_core_fields_for_doubles(bool register_in_basis) { + unsigned j = A_d().column_count(); + A_d().add_column(); + SASSERT(m_mpq_lar_core_solver.m_d_x.size() == j); + // SASSERT(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); + m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); + SASSERT(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_d().add_row(); + m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); + m_mpq_lar_core_solver.m_d_basis.push_back(j); + }else { + m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_d_nbasis.push_back(j); + } +} + +void add_new_var_to_core_fields_for_mpq(bool register_in_basis) { + unsigned j = A_r().column_count(); + A_r().add_column(); + SASSERT(m_mpq_lar_core_solver.m_r_x.size() == j); + // SASSERT(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_r_x.resize(j + 1); + m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); + m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); + SASSERT(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_r().add_row(); + m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); + m_mpq_lar_core_solver.m_r_basis.push_back(j); + if (m_settings.bound_propagation()) + m_rows_with_changed_bounds.insert(A_r().row_count() - 1); + } else { + m_mpq_lar_core_solver.m_r_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_r_nbasis.push_back(j); + } +} + + +var_index add_term_undecided(const vector> & coeffs, + const mpq &m_v) { + m_terms.push_back(new lar_term(coeffs, m_v)); + m_orig_terms.push_back(new lar_term(coeffs, m_v)); + return m_terms_start_index + m_terms.size() - 1; +} + +// terms +var_index add_term(const vector> & coeffs, + const mpq &m_v) { + if (strategy_is_undecided()) + return add_term_undecided(coeffs, m_v); + + m_terms.push_back(new lar_term(coeffs, m_v)); + m_orig_terms.push_back(new lar_term(coeffs, m_v)); + unsigned adjusted_term_index = m_terms.size() - 1; + var_index ret = m_terms_start_index + adjusted_term_index; + if (use_tableau() && !coeffs.empty()) { + add_row_for_term(m_orig_terms.back(), ret); + if (m_settings.bound_propagation()) + m_rows_with_changed_bounds.insert(A_r().row_count() - 1); + } + SASSERT(m_ext_vars_to_columns.size() == A_r().column_count()); + return ret; +} + +void add_row_for_term(const lar_term * term, unsigned term_ext_index) { + SASSERT(sizes_are_correct()); + add_row_from_term_no_constraint(term, term_ext_index); + SASSERT(sizes_are_correct()); +} + +void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { + register_new_ext_var_index(term_ext_index); + // j will be a new variable + unsigned j = A_r().column_count(); + ul_pair ul(j); + m_vars_to_ul_pairs.push_back(ul); + add_basic_var_to_core_fields(); + if (use_tableau()) { + auto it = iterator_on_term_with_basis_var(*term, j); + A_r().fill_last_row_with_pivoting(it, + m_mpq_lar_core_solver.m_r_solver.m_basis_heading); + m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type()); + } else { + fill_last_row_of_A_r(A_r(), term); + } + m_mpq_lar_core_solver.m_r_x[j] = get_basic_var_value_from_row_directly(A_r().row_count() - 1); + if (use_lu()) + fill_last_row_of_A_d(A_d(), term); +} + +void add_basic_var_to_core_fields() { + bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); + SASSERT(!use_lu || A_r().column_count() == A_d().column_count()); + m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); + m_columns_with_changed_bound.increase_size_by_one(); + m_rows_with_changed_bounds.increase_size_by_one(); + add_new_var_to_core_fields_for_mpq(true); + if (use_lu) + add_new_var_to_core_fields_for_doubles(true); +} + +constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { + constraint_index ci = m_constraints.size(); + if (!is_term(j)) { // j is a var + auto vc = new lar_var_constraint(j, kind, right_side); + m_constraints.push_back(vc); + update_column_type_and_bound(j, kind, right_side, ci); + } else { + add_var_bound_on_constraint_for_term(j, kind, right_side, ci); + } + SASSERT(sizes_are_correct()); + return ci; +} + +void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { + switch(m_mpq_lar_core_solver.m_column_types[j]) { + case column_type::free_column: + update_free_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::boxed: + update_boxed_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::low_bound: + update_low_bound_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::upper_bound: + update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::fixed: + update_fixed_column_type_and_bound(j, kind, right_side, constr_index); + break; + default: + SASSERT(false); // cannot be here + } +} + +void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + SASSERT(is_term(j)); + unsigned adjusted_term_index = adjust_term_index(j); + unsigned term_j; + if (try_get_val(m_ext_vars_to_columns, j, term_j)) { + mpq rs = right_side - m_orig_terms[adjusted_term_index]->m_v; + m_constraints.push_back(new lar_term_constraint(m_orig_terms[adjusted_term_index], kind, right_side)); + update_column_type_and_bound(term_j, kind, rs, ci); + } + else { + add_constraint_from_term_and_create_new_column_row(j, m_orig_terms[adjusted_term_index], kind, right_side); + } +} + + +void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, + lconstraint_kind kind, const mpq & right_side) { + + add_row_from_term_no_constraint(term, term_j); + unsigned j = A_r().column_count() - 1; + update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size()); + m_constraints.push_back(new lar_term_constraint(term, kind, right_side)); + SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); +} + +void decide_on_strategy_and_adjust_initial_state() { + SASSERT(strategy_is_undecided()); + if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { + m_settings.simplex_strategy() = simplex_strategy_enum::lu; + } else { + m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs? + } + adjust_initial_state(); +} + +void adjust_initial_state() { + switch (m_settings.simplex_strategy()) { + case simplex_strategy_enum::lu: + adjust_initial_state_for_lu(); + break; + case simplex_strategy_enum::tableau_rows: + adjust_initial_state_for_tableau_rows(); + break; + case simplex_strategy_enum::tableau_costs: + SASSERT(false); // not implemented + case simplex_strategy_enum::undecided: + adjust_initial_state_for_tableau_rows(); + break; + } +} + +void adjust_initial_state_for_lu() { + copy_from_mpq_matrix(A_d()); + unsigned n = A_d().column_count(); + m_mpq_lar_core_solver.m_d_x.resize(n); + m_mpq_lar_core_solver.m_d_low_bounds.resize(n); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); + m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; + m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; + + /* + unsigned j = A_d().column_count(); + A_d().add_column(); + SASSERT(m_mpq_lar_core_solver.m_d_x.size() == j); + // SASSERT(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); + m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); + SASSERT(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_d().add_row(); + m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); + m_mpq_lar_core_solver.m_d_basis.push_back(j); + }else { + m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_d_nbasis.push_back(j); + }*/ +} + +void adjust_initial_state_for_tableau_rows() { + for (unsigned j = 0; j < m_terms.size(); j++) { + if (contains(m_ext_vars_to_columns, j + m_terms_start_index)) + continue; + add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index); + } +} + +// this fills the last row of A_d and sets the basis column: -1 in the last column of the row +void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { + SASSERT(A.row_count() > 0); + SASSERT(A.column_count() > 0); + unsigned last_row = A.row_count() - 1; + SASSERT(A.m_rows[last_row].empty()); + + for (auto & t : ls->m_coeffs) { + SASSERT(!is_zero(t.second)); + var_index j = t.first; + A.set(last_row, j, - t.second.get_double()); + } + + unsigned basis_j = A.column_count() - 1; + A.set(last_row, basis_j, - 1 ); +} + +void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; + SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + SASSERT(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + { + auto up = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + } + set_upper_bound_witness(j, constr_ind); + break; + case GT: + y_of_bound = 1; + case GE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound; + SASSERT(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + { + auto low = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + } + set_low_bound_witness(j, constr_ind); + break; + case EQ: + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair(right_side, zero_of_type()); + set_upper_bound_witness(j, constr_ind); + set_low_bound_witness(j, constr_ind); + break; + + default: + SASSERT(false); + + } + m_columns_with_changed_bound.insert(j); +} + +void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + if (up < m_mpq_lar_core_solver.m_r_upper_bounds()[j]) { + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + } + } + break; + case GT: + y_of_bound = 1; + case GE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed; + { + auto low = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + set_low_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + } else { + m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed; + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + set_low_bound_witness(j, ci); + m_infeasible_column_index = j; + } else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + break; + } + break; + + default: + SASSERT(false); + + } +} + +void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + } + + if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + SASSERT(false); + m_infeasible_column_index = j; + } else { + if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]) + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + } + break; + case GT: + y_of_bound = 1; + case GE: + { + auto low = numeric_pair(right_side, y_of_bound); + if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + } + if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + } else if ( low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + m_columns_with_changed_bound.insert(j); + } + + break; + } + + default: + SASSERT(false); + + } +} +void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + + if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + } else { + m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed; + } + } + break; + case GT: + y_of_bound = 1; + case GE: + { + auto low = numeric_pair(right_side, y_of_bound); + if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + m_columns_with_changed_bound.insert(j); + break; + } + + default: + SASSERT(false); + + } +} + +void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); + auto v = numeric_pair(right_side, mpq(0)); + + mpq y_of_bound(0); + switch (kind) { + case LT: + if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + break; + case LE: + { + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + } + break; + case GT: + { + if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index =j; + set_low_bound_witness(j, ci); + } + } + break; + case GE: + { + if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + } + break; + case EQ: + { + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + break; + } + + default: + SASSERT(false); + + } +} + diff --git a/src/util/lp/lp_primal_core_solver_tableau.h b/src/util/lp/lp_primal_core_solver_tableau.h new file mode 100644 index 000000000..5c7d4d2c2 --- /dev/null +++ b/src/util/lp/lp_primal_core_solver_tableau.h @@ -0,0 +1,408 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + + +Abstract: + + + +Author: + + Lev Nachmanson (levnach) + +Revision History: + + +--*/ +// this is a part of lp_primal_core_solver that deals with the tableau +#include "util/lp/lp_primal_core_solver.h" +namespace lp { +template void lp_primal_core_solver::one_iteration_tableau() { + int entering = choose_entering_column_tableau(); + if (entering == -1) { + decide_on_status_when_cannot_find_entering(); + } + else { + advance_on_entering_tableau(entering); + } + SASSERT(this->inf_set_is_correct()); +} + +template void lp_primal_core_solver::advance_on_entering_tableau(int entering) { + X t; + int leaving = find_leaving_and_t_tableau(entering, t); + if (leaving == -1) { + this->set_status(UNBOUNDED); + return; + } + advance_on_entering_and_leaving_tableau(entering, leaving, t); +} +/* +template int lp_primal_core_solver::choose_entering_column_tableau_rows() { + int i = find_inf_row(); + if (i == -1) + return -1; + return find_shortest_beneficial_column_in_row(i); + } +*/ + template int lp_primal_core_solver::choose_entering_column_tableau() { + //this moment m_y = cB * B(-1) + unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter(); + + SASSERT(numeric_traits::precise()); + if (number_of_benefitial_columns_to_go_over == 0) + return -1; + if (this->m_basis_sort_counter == 0) { + sort_non_basis(); + this->m_basis_sort_counter = 20; + } + else { + this->m_basis_sort_counter--; + } + unsigned j_nz = this->m_m() + 1; // this number is greater than the max column size + std::list::iterator entering_iter = m_non_basis_list.end(); + for (auto non_basis_iter = m_non_basis_list.begin(); number_of_benefitial_columns_to_go_over && non_basis_iter != m_non_basis_list.end(); ++non_basis_iter) { + unsigned j = *non_basis_iter; + if (!column_is_benefitial_for_entering_basis(j)) + continue; + + // if we are here then j is a candidate to enter the basis + unsigned t = this->m_A.number_of_non_zeroes_in_column(j); + if (t < j_nz) { + j_nz = t; + entering_iter = non_basis_iter; + if (number_of_benefitial_columns_to_go_over) + number_of_benefitial_columns_to_go_over--; + } + else if (t == j_nz && this->m_settings.random_next() % 2 == 0) { + entering_iter = non_basis_iter; + } + }// while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb); + if (entering_iter == m_non_basis_list.end()) + return -1; + unsigned entering = *entering_iter; + m_sign_of_entering_delta = this->m_d[entering] > 0 ? 1 : -1; + if (this->m_using_infeas_costs && this->m_settings.use_breakpoints_in_feasibility_search) + m_sign_of_entering_delta = -m_sign_of_entering_delta; + m_non_basis_list.erase(entering_iter); + m_non_basis_list.push_back(entering); + return entering; + +} + + + + +template +unsigned lp_primal_core_solver::solve_with_tableau() { + init_run_tableau(); + if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) { + this->set_status(FEASIBLE); + return 0; + } + + if ((!numeric_traits::precise()) && this->A_mult_x_is_off()) { + this->set_status(FLOATING_POINT_ERROR); + return 0; + } + do { + if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over((this->m_using_infeas_costs? "inf t" : "feas t"), * this->m_settings.get_message_ostream())) { + return this->total_iterations(); + } + if (this->m_settings.use_tableau_rows()) + one_iteration_tableau_rows(); + else + one_iteration_tableau(); + switch (this->get_status()) { + case OPTIMAL: // double check that we are at optimum + case INFEASIBLE: + if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) + break; + if (!numeric_traits::precise()) { + if(this->m_look_for_feasible_solution_only) + break; + this->init_lu(); + + if (this->m_factorization->get_status() != LU_status::OK) { + this->set_status(FLOATING_POINT_ERROR); + break; + } + init_reduced_costs(); + if (choose_entering_column(1) == -1) { + decide_on_status_when_cannot_find_entering(); + break; + } + this->set_status(UNKNOWN); + } else { // precise case + if ((!this->infeasibility_costs_are_correct())) { + init_reduced_costs_tableau(); // forcing recalc + if (choose_entering_column_tableau() == -1) { + decide_on_status_when_cannot_find_entering(); + break; + } + this->set_status(UNKNOWN); + } + } + break; + case TENTATIVE_UNBOUNDED: + this->init_lu(); + if (this->m_factorization->get_status() != LU_status::OK) { + this->set_status(FLOATING_POINT_ERROR); + break; + } + + init_reduced_costs(); + break; + case UNBOUNDED: + if (this->current_x_is_infeasible()) { + init_reduced_costs(); + this->set_status(UNKNOWN); + } + break; + + case UNSTABLE: + SASSERT(! (numeric_traits::precise())); + this->init_lu(); + if (this->m_factorization->get_status() != LU_status::OK) { + this->set_status(FLOATING_POINT_ERROR); + break; + } + init_reduced_costs(); + break; + + default: + break; // do nothing + } + } while (this->get_status() != FLOATING_POINT_ERROR + && + this->get_status() != UNBOUNDED + && + this->get_status() != OPTIMAL + && + this->get_status() != INFEASIBLE + && + this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements + && + this->total_iterations() <= this->m_settings.max_total_number_of_iterations + && + !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); + + SASSERT(this->get_status() == FLOATING_POINT_ERROR + || + this->current_x_is_feasible() == false + || + this->calc_current_x_is_feasible_include_non_basis()); + return this->total_iterations(); + +} +template void lp_primal_core_solver::advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t) { + SASSERT(this->A_mult_x_is_off() == false); + SASSERT(leaving >= 0 && entering >= 0); + SASSERT((this->m_settings.simplex_strategy() == + simplex_strategy_enum::tableau_rows) || + m_non_basis_list.back() == static_cast(entering)); + SASSERT(this->m_using_infeas_costs || !is_neg(t)); + SASSERT(entering != leaving || !is_zero(t)); // otherwise nothing changes + if (entering == leaving) { + advance_on_entering_equal_leaving_tableau(entering, t); + return; + } + if (!is_zero(t)) { + if (this->current_x_is_feasible() || !this->m_settings.use_breakpoints_in_feasibility_search ) { + if (m_sign_of_entering_delta == -1) + t = -t; + } + this->update_basis_and_x_tableau(entering, leaving, t); + SASSERT(this->A_mult_x_is_off() == false); + this->iters_with_no_cost_growing() = 0; + } else { + this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); + this->change_basis(entering, leaving); + } + + if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) + return; + + if (this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows) { + if (need_to_switch_costs()) { + this->init_reduced_costs_tableau(); + } + + SASSERT(!need_to_switch_costs()); + std::list::iterator it = m_non_basis_list.end(); + it--; + * it = static_cast(leaving); + } +} + +template +void lp_primal_core_solver::advance_on_entering_equal_leaving_tableau(int entering, X & t) { + SASSERT(!this->A_mult_x_is_off() ); + this->update_x_tableau(entering, t * m_sign_of_entering_delta); + if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) + return; + + if (need_to_switch_costs()) { + init_reduced_costs_tableau(); + } + this->iters_with_no_cost_growing() = 0; +} +template int lp_primal_core_solver::find_leaving_and_t_tableau(unsigned entering, X & t) { + unsigned k = 0; + bool unlimited = true; + 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(); + for (;k < col_size && unlimited; k++) { + const column_cell & c = col[k]; + unsigned i = c.m_i; + const T & ed = this->m_A.get_val(c); + SASSERT(!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(); + } + } + if (unlimited) { + if (try_jump_to_another_bound_on_entering_unlimited(entering, t)) + return entering; + return -1; + } + + X ratio; + for (;k < col_size; k++) { + const column_cell & c = col[k]; + unsigned i = c.m_i; + const T & ed = this->m_A.get_val(c); + SASSERT(!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(); + if (ratio < t) { + t = ratio; + m_leaving_candidates.clear(); + m_leaving_candidates.push_back(j); + row_min_nz = i_nz; + } 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(); + } else if (ratio == t && i_nz == row_min_nz) { + m_leaving_candidates.push_back(j); + } + } + + ratio = t; + unlimited = false; + if (try_jump_to_another_bound_on_entering(entering, t, ratio, unlimited)) { + t = ratio; + return entering; + } + if (m_leaving_candidates.size() == 1) + return m_leaving_candidates[0]; + k = this->m_settings.random_next() % m_leaving_candidates.size(); + return m_leaving_candidates[k]; +} +template void lp_primal_core_solver::init_run_tableau() { + // print_matrix(&(this->m_A), std::cout); + SASSERT(this->A_mult_x_is_off() == false); + SASSERT(basis_columns_are_set_correctly()); + this->m_basis_sort_counter = 0; // to initiate the sort of the basis + this->set_total_iterations(0); + this->iters_with_no_cost_growing() = 0; + SASSERT(this->inf_set_is_correct()); + if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) + return; + if (this->m_settings.backup_costs) + backup_and_normalize_costs(); + m_epsilon_of_reduced_cost = numeric_traits::precise() ? zero_of_type() : T(1) / T(10000000); + if (this->m_settings.use_breakpoints_in_feasibility_search) + m_breakpoint_indices_queue.resize(this->m_n()); + if (!numeric_traits::precise()) { + this->m_column_norm_update_counter = 0; + init_column_norms(); + } + if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) + init_tableau_rows(); + SASSERT(this->reduced_costs_are_correct_tableau()); + SASSERT(!this->need_to_pivot_to_basis_tableau()); +} + +template bool lp_primal_core_solver:: +update_basis_and_x_tableau(int entering, int leaving, X const & tt) { + SASSERT(this->use_tableau()); + update_x_tableau(entering, tt); + this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); + this->change_basis(entering, leaving); + return true; +} +template void lp_primal_core_solver:: +update_x_tableau(unsigned entering, const X& delta) { + if (!this->m_using_infeas_costs) { + this->m_x[entering] += delta; + for (const auto & c : this->m_A.m_columns[entering]) { + unsigned i = c.m_i; + this->m_x[this->m_basis[i]] -= delta * this->m_A.get_val(c); + this->update_column_in_inf_set(this->m_basis[i]); + } + } else { // m_using_infeas_costs == true + this->m_x[entering] += delta; + SASSERT(this->column_is_feasible(entering)); + SASSERT(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 j = this->m_basis[i]; + this->m_x[j] -= delta * this->m_A.get_val(c); + update_inf_cost_for_column_tableau(j); + if (is_zero(this->m_costs[j])) + this->m_inf_set.erase(j); + else + this->m_inf_set.insert(j); + } + } + SASSERT(this->A_mult_x_is_off() == false); +} + +template void lp_primal_core_solver:: +update_inf_cost_for_column_tableau(unsigned j) { + SASSERT(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows); + SASSERT(this->m_using_infeas_costs); + T new_cost = get_infeasibility_cost_for_column(j); + T delta = this->m_costs[j] - new_cost; + if (is_zero(delta)) + return; + this->m_costs[j] = new_cost; + update_reduced_cost_for_basic_column_cost_change(delta, j); +} + +template void lp_primal_core_solver::init_reduced_costs_tableau() { + if (this->current_x_is_infeasible() && !this->m_using_infeas_costs) { + init_infeasibility_costs(); + } else if (this->current_x_is_feasible() && this->m_using_infeas_costs) { + if (this->m_look_for_feasible_solution_only) + return; + this->m_costs = m_costs_backup; + this->m_using_infeas_costs = false; + } + unsigned size = this->m_basis_heading.size(); + for (unsigned j = 0; j < size; j++) { + if (this->m_basis_heading[j] >= 0) + this->m_d[j] = zero_of_type(); + 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); + } + } + } +} +} diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 955af56aa..6207a0d94 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -24,6 +24,28 @@ Notes: #ifndef SORTING_NETWORK_H_ #define SORTING_NETWORK_H_ + enum sorting_network_encoding { + grouped_at_most_1, + bimander_at_most_1, + ordered_at_most_1 + }; + + 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"; + } + return out << "???"; + } + + struct sorting_network_config { + sorting_network_encoding m_encoding; + sorting_network_config() { + m_encoding = grouped_at_most_1; + } + }; + template class sorting_network { typedef typename Ext::vector vect; @@ -88,7 +110,7 @@ Notes: } public: - sorting_network(Ext& ext): + sorting_network(Ext& ext): m_ext(ext), m_current(&m_currentv), m_next(&m_nextv) @@ -121,6 +143,7 @@ Notes: class psort_nw { typedef typename psort_expr::literal literal; typedef typename psort_expr::literal_vector literal_vector; + sorting_network_config m_cfg; class vc { unsigned v; // number of vertices @@ -185,7 +208,7 @@ Notes: } }; - psort_nw(psort_expr& c): ctx(c) {} + psort_nw(psort_expr& c, sorting_network_config const& cfg): ctx(c), m_cfg(cfg) {} literal ge(bool full, unsigned k, unsigned n, literal const* xs) { if (k > n) { @@ -220,7 +243,17 @@ Notes: else if (k == 1) { literal_vector ors; // scoped_stats _ss(m_stats, k, n); - return mk_at_most_1(full, n, xs, ors, false); + switch (m_cfg.m_encoding) { + case grouped_at_most_1: + return mk_at_most_1(full, n, xs, ors, false); + case bimander_at_most_1: + return mk_at_most_1_bimander(full, n, xs, ors); + case ordered_at_most_1: + return mk_ordered_atmost_1(full, n, xs); + default: + UNREACHABLE(); + return xs[0]; + } } else { SASSERT(2*k <= n); @@ -278,7 +311,7 @@ Notes: if (n == 1) { return ors[0]; } - literal result = fresh(); + literal result = fresh("or"); add_implies_or(result, n, ors); add_or_implies(result, n, ors); return result; @@ -317,15 +350,26 @@ Notes: if (ands.size() == 1) { return ands[0]; } - literal result = fresh(); + 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) { + TRACE("pb", tout << "exactly 1 with " << n << " arguments " << (full?"full":"not full") << "\n";); literal_vector ors; - literal r1 = mk_at_most_1(full, n, xs, ors, true); + literal r1; + switch (m_cfg.m_encoding) { + case grouped_at_most_1: + r1 = mk_at_most_1(full, n, xs, ors, true); + break; + case bimander_at_most_1: + r1 = mk_at_most_1_bimander(full, n, xs, ors); + break; + case ordered_at_most_1: + return mk_ordered_exactly_1(full, n, xs); + } if (full) { r1 = mk_and(r1, mk_or(ors)); @@ -340,12 +384,8 @@ Notes: TRACE("pb_verbose", tout << (full?"full":"partial") << " "; for (unsigned i = 0; i < n; ++i) tout << xs[i] << " "; tout << "\n";); - - if (n >= 4 && false) { - return mk_at_most_1_bimander(full, n, xs, ors); - } literal_vector in(n, xs); - literal result = fresh(); + literal result = fresh("at-most-1"); unsigned inc_size = 4; literal_vector ands; ands.push_back(result); @@ -387,7 +427,7 @@ Notes: // xs[0] + ... + xs[n-1] <= 1 => and_x if (full) { - literal and_i = fresh(); + literal and_i = fresh("and"); for (unsigned i = 0; i < n; ++i) { literal_vector lits; lits.push_back(and_i); @@ -407,29 +447,6 @@ Notes: } -#if 0 - literal result = fresh(); - - // 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])); - } - } - - // xs[0] + ... + xs[n-1] <= 1 => result - for (unsigned i = 0; i < n; ++i) { - literal_vector lits; - lits.push_back(result); - for (unsigned j = 0; j < n; ++j) { - if (j != i) lits.push_back(xs[j]); - } - add_clause(lits); - } - - return result; -#endif -#if 1 // r <=> and( or(!xi,!xj)) // literal_vector ands; @@ -439,30 +456,100 @@ Notes: } } return mk_and(ands); -#else - // r <=> or (and !x_{j != i}) - - literal_vector ors; - for (unsigned i = 0; i < n; ++i) { - literal_vector ands; - for (unsigned j = 0; j < n; ++j) { - if (j != i) { - ands.push_back(ctx.mk_not(xs[j])); - } - } - ors.push_back(mk_and(ands)); - } - return mk_or(ors); - -#endif } + literal mk_ordered_exactly_1(bool full, unsigned n, literal const* xs) { + return mk_ordered_1(full, true, n, xs); + } + + literal mk_ordered_atmost_1(bool full, unsigned n, literal const* xs) { + return mk_ordered_1(full, false, n, xs); + } + + literal mk_ordered_1(bool full, bool is_eq, unsigned n, literal const* xs) { + if (n <= 1 && !is_eq) return ctx.mk_true(); + if (n == 0) { + return ctx.mk_false(); + } + if (n == 1) { + return xs[0]; + } + + // y0 -> y1 + // x0 -> y0 + // x1 -> y1 + // r, y0 -> ~x1 + // r, y1 -> ~x2 + // r -> x3 | y1 + // r -> ~x3 | ~y1 + + // x0,x1,x2, .., x_{n-1}, x_n + // y0,y1,y2, .., y_{n-1} + // y_i -> y_{i+1} i = 0, ..., n - 2 + // x_i -> y_i i = 0, ..., n - 1 + // r, y_i -> ~x_{i+1} i = 0, ..., n - 1 + // exactly 1: + // r -> x_n | y_{n-1} + // full (exactly 1): + // two_i -> y_i & x_{i+1} + // zero -> ~x_n + // zero -> ~y_{n-1} + // r | zero | two_0 | ... | two_{n-1} + // full atmost 1: + // r | two | two_0 | ... | two_{n-1} + + literal r = fresh("ordered"); + literal_vector ys; + for (unsigned i = 0; i + 1 < n; ++i) { + ys.push_back(fresh("y")); + } + for (unsigned i = 0; i + 2 < n; ++i) { + add_clause(ctx.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(ctx.mk_not(r), ys[n-2], xs[n-1]); + add_clause(ctx.mk_not(r), ctx.mk_not(ys[n-2]), ctx.mk_not(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(ctx.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]); + 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]); + } + 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(r, zero, twos.back()); + } + else { + add_clause(r, twos.back()); + } + } + return r; + } // literal mk_at_most_1_bimander(bool full, unsigned n, literal const* xs, literal_vector& ors) { + if (full) { + return mk_at_most_1(full, n, xs, ors, true); + } literal_vector in(n, xs); - literal result = fresh(); + literal result = fresh("bimander"); unsigned inc_size = 2; literal_vector ands; for (unsigned i = 0; i < n; i += inc_size) { @@ -477,7 +564,7 @@ Notes: } literal_vector bits; for (unsigned k = 0; k < nbits; ++k) { - bits.push_back(fresh()); + bits.push_back(fresh("bit")); } for (unsigned i = 0; i < ors.size(); ++i) { for (unsigned k = 0; k < nbits; ++k) { @@ -539,9 +626,9 @@ Notes: return ctx.mk_min(a, b); } - literal fresh() { + literal fresh(char const* n) { m_stats.m_num_compiled_vars++; - return ctx.fresh(); + return ctx.fresh(n); } void add_clause(literal l1, literal l2, literal l3) { literal lits[3] = { l1, l2, l3 }; @@ -558,7 +645,6 @@ Notes: m_stats.m_num_compiled_clauses++; m_stats.m_num_clause_vars += n; literal_vector tmp(n, ls); - TRACE("pb_verbose", for (unsigned i = 0; i < n; ++i) tout << ls[i] << " "; tout << "\n";); ctx.mk_clause(n, tmp.c_ptr()); } @@ -925,7 +1011,7 @@ Notes: SASSERT(b <= c); SASSERT(a + b >= c); for (unsigned i = 0; i < c; ++i) { - out.push_back(fresh()); + out.push_back(fresh("dsmerge")); } if (m_t != GE) { for (unsigned i = 0; i < a; ++i) { @@ -983,7 +1069,7 @@ Notes: SASSERT(m <= n); literal_vector lits; for (unsigned i = 0; i < m; ++i) { - out.push_back(fresh()); + out.push_back(fresh("dsort")); } if (m_t != GE) { for (unsigned k = 1; k <= m; ++k) { From 82922d92f7527c5b4060fbedcc376865d473e6ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Sep 2017 13:29:46 -0700 Subject: [PATCH 0227/1283] add cube functionality Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 124 ++++++++++++++++++++++---------------- src/sat/sat_lookahead.h | 6 +- src/sat/sat_solver.cpp | 9 +-- src/sat/sat_solver.h | 2 +- 4 files changed, 83 insertions(+), 58 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 7205b9ac3..6b55802d0 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -820,6 +820,15 @@ namespace sat { } return out; } + + void lookahead::display_search_string() { + printf("\r"); + std::stringstream strm; + strm << pp_prefix(m_prefix, m_trail_lim.size()); + for (unsigned i = 0; i < 50; ++i) strm << " "; + printf(strm.str().c_str()); + fflush(stdout); + } void lookahead::construct_lookahead_table() { literal u = get_child(null_literal), v = null_literal; @@ -1710,47 +1719,6 @@ namespace sat { return true; } - void lookahead::cube() { - m_model.reset(); - scoped_level _sl(*this, c_fixed_truth); - literal_vector trail; - m_search_mode = lookahead_mode::searching; - double freevars_threshold = 0; - while (true) { - TRACE("sat", display(tout);); - inc_istamp(); - checkpoint(); - literal l = choose(); - if (inconsistent()) { - freevars_threshold = m_freevars.size(); - if (!backtrack(trail)) return; - continue; - } - unsigned depth = m_trail_lim.size(); - if (l == null_literal || - (m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || - (m_config.m_cube_cutoff == 0 && m_freevars.size() < freevars_threshold)) { - display_cube(std::cout); - set_conflict(); - if (!backtrack(trail)) return; - freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); - continue; - } - TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); - ++m_stats.m_decisions; - IF_VERBOSE(1, printf("\r"); - std::stringstream strm; - strm << pp_prefix(m_prefix, m_trail_lim.size()); - for (unsigned i = 0; i < 50; ++i) strm << " "; - printf(strm.str().c_str()); - fflush(stdout); - ); - push(l, c_fixed_truth); - trail.push_back(l); - SASSERT(inconsistent() || !is_unsat()); - } - } - lbool lookahead::search() { m_model.reset(); scoped_level _sl(*this, c_fixed_truth); @@ -1770,19 +1738,73 @@ namespace sat { } TRACE("sat", tout << "choose: " << l << " " << trail << "\n";); ++m_stats.m_decisions; - IF_VERBOSE(1, printf("\r"); - std::stringstream strm; - strm << pp_prefix(m_prefix, m_trail_lim.size()); - for (unsigned i = 0; i < 50; ++i) strm << " "; - printf(strm.str().c_str()); - fflush(stdout); - ); + IF_VERBOSE(1, display_search_string();); push(l, c_fixed_truth); trail.push_back(l); SASSERT(inconsistent() || !is_unsat()); } } + bool lookahead::backtrack(literal_vector& trail, svector & is_decision) { + while (inconsistent()) { + if (trail.empty()) return false; + if (is_decision.back()) { + pop(); + trail.back().neg(); + assign(trail.back()); + is_decision.back() = false; + propagate(); + } + else { + trail.pop_back(); + is_decision.pop_back(); + } + } + return true; + } + + lbool lookahead::cube() { + lbool result = l_false; + init_search(); + m_model.reset(); + scoped_level _sl(*this, c_fixed_truth); + literal_vector cube; + svector is_decision; + m_search_mode = lookahead_mode::searching; + double freevars_threshold = 0; + while (true) { + TRACE("sat", display(tout);); + inc_istamp(); + checkpoint(); + literal l = choose(); + if (inconsistent()) { + TRACE("sat", tout << "inconsistent: " << cube << "\n";); + freevars_threshold = m_freevars.size(); + if (!backtrack(cube, is_decision)) return result; + continue; + } + if (l == null_literal) { + return l_true; + } + unsigned depth = cube.size(); + if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || + (m_config.m_cube_cutoff == 0 && m_freevars.size() < freevars_threshold)) { + display_cube(std::cout, cube); + freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); + result = l_undef; + set_conflict(); + if (!backtrack(cube, is_decision)) return result; + continue; + } + TRACE("sat", tout << "choose: " << l << " cube: " << cube << "\n";); + ++m_stats.m_decisions; + push(l, c_fixed_truth); + cube.push_back(l); + is_decision.push_back(true); + SASSERT(inconsistent() || !is_unsat()); + } + } + void lookahead::init_model() { m_model.reset(); for (unsigned i = 0; i < m_num_vars; ++i) { @@ -1801,12 +1823,12 @@ namespace sat { } } - std::ostream& lookahead::display_cube(std::ostream& out) const { + std::ostream& lookahead::display_cube(std::ostream& out, literal_vector const& cube) const { out << "c"; - for (literal l : m_assumptions) { + for (literal l : cube) { out << " " << ~l; } - return out << "\n"; + return out << " 0\n"; } std::ostream& lookahead::display_binary(std::ostream& out) const { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 0bd6e39d4..609f72a51 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -444,13 +444,15 @@ namespace sat { void assign(literal l); void propagated(literal l); bool backtrack(literal_vector& trail); + bool backtrack(literal_vector& trail, svector & is_decision); lbool search(); void init_model(); std::ostream& display_binary(std::ostream& out) const; std::ostream& display_clauses(std::ostream& out) const; std::ostream& display_values(std::ostream& out) const; std::ostream& display_lookahead(std::ostream& out) const; - std::ostream& display_cube(std::ostream& out) const; + std::ostream& display_cube(std::ostream& out, literal_vector const& cube) const; + void display_search_string(); void init_search(); void checkpoint(); @@ -486,7 +488,7 @@ namespace sat { If cut-depth != 0, then it is used to control the depth of cuts. Otherwise, cut-fraction gives an adaptive threshold for creating cuts. */ - void cube(); + lbool cube(); literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5e054bdaf..f0a423491 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -857,8 +857,7 @@ namespace sat { return lookahead_search(); } if (m_config.m_lookahead_cube && num_lits == 0) { - lookahead_cube(); - return l_undef; + return lookahead_cube(); } if (m_config.m_local_search) { return do_local_search(num_lits, lits); @@ -952,16 +951,18 @@ namespace sat { return r; } - void solver::lookahead_cube() { + lbool solver::lookahead_cube() { lookahead lh(*this); + lbool r = l_undef; try { - lh.cube(); + r = lh.cube(); } catch (z3_exception&) { lh.collect_statistics(m_aux_stats); throw; } lh.collect_statistics(m_aux_stats); + return r; } lbool solver::lookahead_search() { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index ab2dd7a1f..581f557a7 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -403,7 +403,7 @@ namespace sat { void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); lbool lookahead_search(); - void lookahead_cube(); + lbool lookahead_cube(); lbool do_local_search(unsigned num_lits, literal const* lits); lbool do_ccc(); From ced2029ae9797a16f594dee4d0d88c3183d7ee1c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Sep 2017 16:37:15 -0700 Subject: [PATCH 0228/1283] local changes Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 7 +++--- src/opt/sortmax.cpp | 3 +-- src/sat/ba_solver.cpp | 20 +++++++++++----- src/sat/sat_config.cpp | 17 +++++++++++++- src/sat/sat_config.h | 9 ++++++- src/sat/sat_lookahead.cpp | 18 ++------------ src/sat/sat_lookahead.h | 7 ------ src/sat/sat_simplifier.cpp | 10 ++++---- src/smt/theory_pb.cpp | 6 ++--- src/tactic/portfolio/enum2bv_solver.cpp | 1 + src/test/sorting_network.cpp | 31 +++++++++++-------------- src/util/sorting_network.h | 4 +++- 12 files changed, 69 insertions(+), 64 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index fcabdd596..000257f61 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -43,7 +43,6 @@ struct pb2bv_rewriter::imp { struct card2bv_rewriter { typedef expr* literal; typedef ptr_vector literal_vector; - sorting_network_config m_cfg; psort_nw m_sort; ast_manager& m; imp& m_imp; @@ -572,7 +571,7 @@ struct pb2bv_rewriter::imp { public: card2bv_rewriter(imp& i, ast_manager& m): - m_sort(*this, m_cfg), + m_sort(*this), m(m), m_imp(i), au(m), @@ -786,7 +785,7 @@ struct pb2bv_rewriter::imp { void pb_totalizer(bool f) { m_pb_totalizer = f; } - void set_at_most1(sorting_network_encoding enc) { m_cfg.m_encoding = enc; } + void set_at_most1(sorting_network_encoding enc) { m_sort.cfg().m_encoding = enc; } }; @@ -852,7 +851,7 @@ struct pb2bv_rewriter::imp { sorting_network_encoding atmost1_encoding() const { - symbol enc = m_params.get_sym("atmost1_encoding", enc); + symbol enc = m_params.get_sym("atmost1_encoding", symbol()); if (enc == symbol()) { enc = gparams::get_module("sat").get_sym("atmost1_encoding", symbol()); } diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 01d8db22d..f832d5564 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -32,13 +32,12 @@ namespace opt { public: typedef expr* literal; typedef ptr_vector literal_vector; - sorting_network_config m_cfg; psort_nw m_sort; expr_ref_vector m_trail; func_decl_ref_vector m_fresh; ref m_filter; sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), m_sort(*this, m_cfg), m_trail(m), m_fresh(m) {} + maxsmt_solver_base(c, ws, soft), m_sort(*this), m_trail(m), m_fresh(m) {} virtual ~sortmax() {} diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index c90a0c022..cdbbee96b 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1619,11 +1619,14 @@ namespace sat { double ba_solver::get_reward(card const& c, literal_occs_fun& literal_occs) const { unsigned k = c.k(), slack = 0; - double to_add = 0; + bool do_add = get_config().m_lookahead_reward == heule_schur_reward; + double to_add = do_add ? 0: 1; for (literal l : c) { switch (value(l)) { - case l_true: --k; if (k == 0) return 0; break; - case l_undef: to_add += literal_occs(l); ++slack; break; + case l_true: --k; if (k == 0) return 0; + case l_undef: + if (do_add) to_add += literal_occs(l); + ++slack; break; case l_false: break; } } @@ -1633,14 +1636,19 @@ namespace sat { double ba_solver::get_reward(pb const& c, literal_occs_fun& occs) const { unsigned k = c.k(), slack = 0; - double to_add = 0; + bool do_add = get_config().m_lookahead_reward == heule_schur_reward; + double to_add = do_add ? 0 : 1; double undefs = 0; for (wliteral wl : c) { literal l = wl.second; unsigned w = wl.first; switch (value(l)) { - case l_true: if (k <= w) return 0; k -= w; break; - case l_undef: to_add += occs(l); ++undefs; slack += w; break; // TBD multiplier factor on this + case l_true: if (k <= w) return 0; + case l_undef: + if (do_add) to_add += occs(l); + ++undefs; + slack += w; + break; // TBD multiplier factor on this case l_false: break; } } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index dd6cea3f8..2ba7cec57 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -87,7 +87,22 @@ namespace sat { m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_cube = p.lookahead_cube(); m_lookahead_search = p.lookahead_search(); - m_lookahead_reward = p.lookahead_reward(); + if (p.lookahead_reward() == symbol("hs")) { + m_lookahead_reward = heule_schur_reward; + } + else if (p.lookahead_reward() == symbol("heuleu")) { + m_lookahead_reward = heule_unit_reward; + } + else if (p.lookahead_reward() == symbol("ternary")) { + m_lookahead_reward = ternary_reward; + } + else if (p.lookahead_reward() == symbol("unit")) { + m_lookahead_reward = unit_literal_reward; + } + else { + throw sat_param_exception("invalid reward type supplied: accepted heuristics are 'ternary', 'heuleu', 'unit' or 'heule_schur'"); + } + m_lookahead_cube_fraction = p.lookahead_cube_fraction(); m_lookahead_cube_cutoff = p.lookahead_cube_cutoff(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index fc93e50ea..ba68b7901 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -57,6 +57,13 @@ namespace sat { PB_TOTALIZER }; + enum reward_t { + ternary_reward, + unit_literal_reward, + heule_schur_reward, + heule_unit_reward + }; + struct config { unsigned long long m_max_memory; phase_selection m_phase; @@ -78,7 +85,7 @@ namespace sat { bool m_lookahead_cube; unsigned m_lookahead_cube_cutoff; double m_lookahead_cube_fraction; - symbol m_lookahead_reward; + reward_t m_lookahead_reward; unsigned m_simplify_mult1; double m_simplify_mult2; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 6b55802d0..8b5316986 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1299,7 +1299,7 @@ namespace sat { case watched::EXT_CONSTRAINT: { SASSERT(m_s.m_ext); bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); - if (m_search_mode == lookahead_mode::lookahead1) { + if (m_search_mode == lookahead_mode::lookahead1 && !m_inconsistent) { lookahead_literal_occs_fun literal_occs_fn(*this); m_lookahead_reward += m_s.m_ext->get_reward(l, it->get_ext_constraint_idx(), literal_occs_fn); } @@ -2065,21 +2065,7 @@ namespace sat { } void lookahead::init_config() { - if (m_s.m_config.m_lookahead_reward == symbol("hs")) { - m_config.m_reward_type = heule_schur_reward; - } - else if (m_s.m_config.m_lookahead_reward == symbol("heuleu")) { - m_config.m_reward_type = heule_unit_reward; - } - else if (m_s.m_config.m_lookahead_reward == symbol("ternary")) { - m_config.m_reward_type = ternary_reward; - } - else if (m_s.m_config.m_lookahead_reward == symbol("unit")) { - m_config.m_reward_type = unit_literal_reward; - } - else { - warning_msg("Reward type not recognized"); - } + m_config.m_reward_type = m_s.m_config.m_lookahead_reward; m_config.m_cube_cutoff = m_s.m_config.m_lookahead_cube_cutoff; m_config.m_cube_fraction = m_s.m_config.m_lookahead_cube_fraction; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 609f72a51..1f1c12fef 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -66,13 +66,6 @@ namespace sat { friend class ccc; friend class ba_solver; - enum reward_t { - ternary_reward, - unit_literal_reward, - heule_schur_reward, - heule_unit_reward - }; - struct config { double m_dl_success; double m_alpha; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 945a824ab..7ef9a7338 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1060,10 +1060,12 @@ namespace sat { it.next(); } - ext_constraint_list const& ext_list = s.m_ext_use_list.get(~l); - for (ext_constraint_idx idx : ext_list) { - if (!s.s.m_ext->is_blocked(l, idx)) { - return false; + if (s.s.m_ext) { + ext_constraint_list const& ext_list = s.m_ext_use_list.get(~l); + for (ext_constraint_idx idx : ext_list) { + if (!s.s.m_ext->is_blocked(l, idx)) { + return false; + } } } return true; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 153d31b05..12fddee13 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1441,8 +1441,7 @@ namespace smt { theory_pb_params p; theory_pb th(ctx.get_manager(), p); psort_expr ps(ctx, th); - sorting_network_config cfg; - psort_nw sort(ps, cfg); + psort_nw sort(ps); return sort.ge(false, k, n, xs); } @@ -1578,8 +1577,7 @@ namespace smt { psort_expr ps(ctx, *this); - sorting_network_config cfg; - psort_nw sortnw(ps, cfg); + psort_nw sortnw(ps); sortnw.m_stats.reset(); if (ctx.get_assignment(thl) == l_true && diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index bdabf784e..a9e91bfe6 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -85,6 +85,7 @@ public: } virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + m_solver->updt_params(m_params); return m_solver->check_sat(num_assumptions, assumptions); } diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index b5c8dc165..94e2c332e 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -191,9 +191,9 @@ static void test_eq1(unsigned n, sorting_network_encoding enc) { } smt_params fp; smt::kernel solver(m, fp); - sorting_network_config cfg; - cfg.m_encoding = enc; - psort_nw sn(ext, cfg); + psort_nw sn(ext); + sn.cfg().m_encoding = enc; + expr_ref result1(m), result2(m); // equality: @@ -237,9 +237,8 @@ static void test_sorting_eq(unsigned n, unsigned k, sorting_network_encoding enc } smt_params fp; smt::kernel solver(m, fp); - sorting_network_config cfg; - cfg.m_encoding = enc; - psort_nw sn(ext, cfg); + psort_nw sn(ext); + sn.cfg().m_encoding = enc; expr_ref result(m); // equality: @@ -288,9 +287,8 @@ static void test_sorting_le(unsigned n, unsigned k, sorting_network_encoding enc } smt_params fp; smt::kernel solver(m, fp); - sorting_network_config cfg; - cfg.m_encoding = enc; - psort_nw sn(ext, cfg); + psort_nw sn(ext); + sn.cfg().m_encoding = enc; expr_ref result(m); // B <= k std::cout << "le " << k << "\n"; @@ -337,9 +335,8 @@ void test_sorting_ge(unsigned n, unsigned k, sorting_network_encoding enc) { } smt_params fp; smt::kernel solver(m, fp); - sorting_network_config cfg; - cfg.m_encoding = enc; - psort_nw sn(ext, cfg); + psort_nw sn(ext); + sn.cfg().m_encoding = enc; expr_ref result(m); // k <= B std::cout << "ge " << k << "\n"; @@ -402,9 +399,8 @@ void test_at_most_1(unsigned n, bool full, sorting_network_encoding enc) { } ast_ext2 ext(m); - sorting_network_config cfg; - cfg.m_encoding = enc; - psort_nw sn(ext, cfg); + psort_nw sn(ext); + sn.cfg().m_encoding = enc; expr_ref result1(m), result2(m); result1 = sn.le(full, 1, in.size(), in.c_ptr()); result2 = naive_at_most1(in); @@ -481,9 +477,8 @@ static void test_at_most1(sorting_network_encoding enc) { in[4] = in[3].get(); ast_ext2 ext(m); - sorting_network_config cfg; - cfg.m_encoding = enc; - psort_nw sn(ext, cfg); + psort_nw sn(ext); + sn.cfg().m_encoding = enc; expr_ref result(m); result = sn.le(true, 1, in.size(), in.c_ptr()); std::cout << result << "\n"; diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 6207a0d94..9a1d064d4 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -208,7 +208,9 @@ Notes: } }; - psort_nw(psort_expr& c, sorting_network_config const& cfg): ctx(c), m_cfg(cfg) {} + psort_nw(psort_expr& c): ctx(c) {} + + sorting_network_config& cfg() { return m_cfg; } literal ge(bool full, unsigned k, unsigned n, literal const* xs) { if (k > n) { From d41696b91ec353b607cc787292fdd20be4bb6e0c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Sep 2017 20:29:53 -0700 Subject: [PATCH 0229/1283] adding new clause management Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 208 ++++++++++++++++++++++++++++++++++++++ src/sat/sat_lookahead.h | 37 +++++++ 2 files changed, 245 insertions(+) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 8b5316986..1e71555d7 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1168,7 +1168,215 @@ namespace sat { double operator()(literal l) { return lh.literal_occs(l); } }; +#ifdef NEW_CLAUSE + // Ternary clause managagement: + void lookahead::add_ternary(literal u, literal v, literal w) { + SASSERT(u != w && u != v && v != w && ~u != w && ~u != v && ~w != v); + m_ternary[u.index()].push_back(binary(v, w)); + m_ternary[v.index()].push_back(binary(w, u)); + m_ternary[w.index()].push_back(binary(u, v)); + m_ternary_size[u.index()]++; + m_ternary_size[v.index()]++; + m_ternary_size[w.index()]++; + } + + lbool lookahead::propagate_ternary(literal l1, literal l2) { + if (is_fixed(l1)) { + if (is_false(l1)) { + if (is_undef(l2)) { + propagated(l2); + } + else if (is_false(l2)) { + TRACE("sat", tout << l1 << " " << l2 << " " << "\n";); + set_conflict(); + } + return l_false; + } + else { + return l_true; + } + } + + if (is_fixed(l2)) { + if (is_false(l2)) { + propagated(l1); + return l_false; + } + else { + return l_true; + } + } + return l_undef; + } + + void lookahead::propagate_ternary(literal l) { + unsigned sz = m_ternary_size[(~l).index()]; + svector const& negs = m_ternary[(~l).index()]; + + switch (m_search_mode) { + case lookahead_mode::searching: { + + // ternary clauses where l is negative become binary + + for (unsigned i = 0; i < sz; ++i) { + binary const& b = negs[i]; + // this could create a conflict from propagation, but we complete the transaction. + literal l1 = b.m_u; + literal l2 = b.m_v; + switch (propagate_ternary(l1, l2)) { + case l_undef: + try_add_binary(l1, l2); + remove_ternary(l1, l2, l); + remove_ternary(l2, l, l1); + break; + default: + break; + // propagated or + // is tautology, someone else will remove it. + break; + } + } + sz = m_ternary_size[l.index()]; + svector const& poss = m_ternary[l.index()]; + + // ternary clauses where l is positive are tautologies + for (unsigned i = 0; i < sz; ++i) { + binary const& b = poss[i]; + remove_ternary(b.m_u, b.m_v, l); + remove_ternary(b.m_v, l, b.m_u); + } + break; + } + case lookahead_mode::lookahead1: + // this could create a conflict from propagation, but we complete the loop. + for (unsigned i = 0; i < sz; ++i) { + binary const& b = negs[i]; + literal l1 = b.m_u; + literal l2 = b.m_v; + switch (propagate_ternary(l1, l2)) { + case l_undef: + update_binary_clause_reward(l1, l2); + break; + default: + break; + } + } + break; + case lookahead2: + // this could create a conflict from propagation, but we complete the loop. + for (unsigned i = 0; i < sz; ++i) { + binary const& b = negs[i]; + propagate_ternary(b.m_u, b.m_v); + } + break; + } + } + + void lookahead::remove_ternary(literal l, literal u, literal v) { + unsigned idx = l.index(); + unsigned sz = m_ternary_size[idx]--; + auto& tv = m_ternary[idx]; + for (unsigned i = sz; i > 0; ) { + --i; + binary const& b = tv[i]; + if (b.m_u == u && b.m_v == v) { + std::swap(tv[i], tv[sz-1]); + return; + } + } + UNREACHABLE(); + } + + void lookahead::restore_ternary(literal l) { + for (binary const& b : m_ternary[(~l).index()]) { + m_ternary_size[b.m_u.index()]++; + m_ternary_size[b.m_v.index()]++; + } + for (binary const& b : m_ternary[l.index()]) { + m_ternary_size[b.m_u.index()]++; + m_ternary_size[b.m_v.index()]++; + } + } + + // new n-ary clause managment + void lookahead::propagate_clauses2(literal l) { + // clauses where l is negative + unsigned_vector const& nclauses = m_clauses2[(~l).index()]; + unsigned sz = m_clause_count[(~l).index()]; + for (unsigned i = 0; i < sz; ++i) { + unsigned idx = nclauses[i]; + unsigned len = --m_clause_len[idx]; // TBD: only decrement for search_mode == searching + if (len <= 1) { + // propagate or detect conflict. + unsigned end = idx + m_clause_size[idx]; + for (unsigned j = idx; j < end; ++j) { + literal lit = m_clause_literals[j]; + NOT_IMPLEMENTED_YET(); + // TBD + } + } + // TBD for binary case + if (len == 2) { +#if 0 + switch (m_search_mode) { + case lookahead_mode::searching: + detach_clause(c); + try_add_binary(c[0], c[1]); + break; + case lookahead_mode::lookahead1: + update_binary_clause_reward(c[0], c[1]); + // update_nary_clause_reward... + break; + case lookahead_mode::lookahead2: + break; + } +#endif + } + + } + // clauses where l is positive: + unsigned_vector const& pclauses = m_clauses2[l.index()]; + sz = m_clause_count[l.index()]; + for (unsigned i = 0; i < sz; ++i) { + unsigned idx = pclauses[i]; + unsigned end = idx + m_clause_size[idx]; + for (unsigned j = idx; j < end; ++j) { + literal lit = m_clause_literals[j]; + if (lit != l) { + remove_clause(lit, idx); + } + } + } + } + + void lookahead::remove_clause(literal l, unsigned clause_idx) { + unsigned_vector& pclauses = m_clauses2[l.index()]; + unsigned sz = m_clause_count[l.index()]--; + for (unsigned i = sz; i > 0; ) { + --i; + if (clause_idx == pclauses[i]) { + std::swap(pclauses[i], pclauses[sz-1]); + } + } + } + + void lookahead::restore_clauses2(literal l) { + unsigned_vector const& pclauses = m_clauses2[l.index()]; + unsigned sz = m_clause_count[l.index()]; + for (unsigned i = 0; i < sz; ++i) { + unsigned idx = pclauses[i]; + unsigned end = idx + m_clause_size[idx]; + for (unsigned j = idx; j < end; ++j) { + literal lit = m_clause_literals[j]; + if (lit != l) { + m_clause_count[lit.index()]++; + } + } + } + } + +#endif void lookahead::propagate_clauses(literal l) { SASSERT(is_true(l)); if (inconsistent()) return; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 1f1c12fef..55fdb0211 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,6 +20,8 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ +#define NEW_CLAUSE + #include "sat_elim_eqs.h" namespace sat { @@ -128,6 +130,13 @@ namespace sat { literal m_u, m_v, m_w; }; +#ifdef NEW_CLAUSE + struct binary { + binary(literal u, literal v): m_u(u), m_v(v) {} + literal m_u, m_v; + }; +#endif + config m_config; double m_delta_trigger; @@ -139,6 +148,22 @@ namespace sat { vector m_binary; // literal: binary clauses unsigned_vector m_binary_trail; // trail of added binary clauses unsigned_vector m_binary_trail_lim; + +#ifdef NEW_CLAUSE + // specialized clause managemet uses ternary clauses and dedicated clause data-structure. + // this will replace m_clauses below + vector> m_ternary; // lit |-> vector of ternary clauses + unsigned_vector m_ternary_size; // lit |-> current number of active ternary clauses for lit + unsigned_vector m_ternary_trail_lim; // limit for ternary vectors. + + vector m_clauses2; // lit |-> vector of clause_id + unsigned_vector m_clause_count; // lit |-> number of valid clause_id in m_clauses2[lit] + unsigned_vector m_clause_len; // clause_id |-> current clause length + unsigned_vector m_clause_size; // clause_id |-> size of clause >= m_clause_len[clause_id] + literal_vector m_clause_literals; // the actual literals + // TBD trail.. for clause updates? +#endif + unsigned m_num_tc1; unsigned_vector m_num_tc1_lim; unsigned m_qhead; // propagation queue head @@ -382,6 +407,18 @@ namespace sat { watch_list& get_wlist(literal l) { return m_watches[l.index()]; } watch_list const& get_wlist(literal l) const { return m_watches[l.index()]; } +#ifdef NEW_CLAUSE + // new clause managment: + void add_ternary(literal u, literal v, literal w); + void propagate_ternary(literal l); + lbool propagate_ternary(literal l1, literal l2); + void remove_ternary(literal l, literal u, literal v); + void restore_ternary(literal l); + + void propagate_clauses2(literal l); + void restore_clauses2(literal l); + void remove_clause(literal l, unsigned clause_idx); +#endif // ------------------------------------ // initialization From e7449f38117138904a7d83f62f7574c548fd353a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Sep 2017 00:05:53 -0700 Subject: [PATCH 0230/1283] working on new clause management Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 146 ++++++++++++++++++++++++++++++-------- src/sat/sat_lookahead.h | 9 ++- 2 files changed, 123 insertions(+), 32 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 1e71555d7..f9b6df9a2 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1227,15 +1227,13 @@ namespace sat { switch (propagate_ternary(l1, l2)) { case l_undef: try_add_binary(l1, l2); - remove_ternary(l1, l2, l); - remove_ternary(l2, l, l1); break; default: - break; - // propagated or - // is tautology, someone else will remove it. + // propagated or tautology. break; } + remove_ternary(l1, l2, l); + remove_ternary(l2, l, l1); } sz = m_ternary_size[l.index()]; svector const& poss = m_ternary[l.index()]; @@ -1304,20 +1302,79 @@ namespace sat { // clauses where l is negative unsigned_vector const& nclauses = m_clauses2[(~l).index()]; unsigned sz = m_clause_count[(~l).index()]; + literal lit; for (unsigned i = 0; i < sz; ++i) { unsigned idx = nclauses[i]; - unsigned len = --m_clause_len[idx]; // TBD: only decrement for search_mode == searching - if (len <= 1) { - // propagate or detect conflict. - unsigned end = idx + m_clause_size[idx]; - for (unsigned j = idx; j < end; ++j) { - literal lit = m_clause_literals[j]; - NOT_IMPLEMENTED_YET(); - // TBD + unsigned len = --m_clause_len[idx]; // TBD: only safe to decrement for search_mode == searching + SASSERT(len >= 2); +#if 0 + if (len == 1) { + while ((lit = m_clause_literals[idx++]) != null_literal) { + if (is_fixed(lit)) { + if (is_true(lit)) { + break; + } + } + else { + propagated(lit); + break; + } + } + if (lit == null_literal) { + // it is a conflict + set_conflict(); + for (++i; i < sz; ++i) { + --m_clause_len[nclauses[i]]; + } } } - // TBD for binary case +#endif + // find the two unassigned literals, if any if (len == 2) { + literal l1 = null_literal; + literal l2 = null_literal; + unsigned j = idx; + bool found_true = false; + while ((lit = m_clause_literals[j++]) != null_literal) { + if (!is_fixed(lit)) { + if (l1 == null_literal) { + l1 = lit; + } + else { + SASSERT(l2 == null_literal); + l2 = lit; + break; + } + } + else if (is_true(lit)) { + found_true = true; + break; + } + } + if (found_true) { + // skip, the clause will be removed when propagating on 'lit' + } + else if (l1 == null_literal) { + set_conflict(); + for (++i; i < sz; ++i) { + --m_clause_len[nclauses[i]]; + } + } + else if (l2 == null_literal) { + // clause gets revisited during propagation, when l2 is true in this clause. + // prevent removing the clause at that point by removing it already now. + m_removed_clauses.push_back(std::make_pair(l, idx)); + remove_clause_at(l, idx); + propagated(l1); + } + else { + // extract binary clause. + // we should never get a unary or empty clause after this. + m_removed_clauses.push_back(std::make_pair(l, idx)); // need to restore this clause. + remove_clause_at(l, idx); + try_add_binary(l1, l2); + } + #if 0 switch (m_search_mode) { case lookahead_mode::searching: @@ -1339,13 +1396,16 @@ namespace sat { unsigned_vector const& pclauses = m_clauses2[l.index()]; sz = m_clause_count[l.index()]; for (unsigned i = 0; i < sz; ++i) { - unsigned idx = pclauses[i]; - unsigned end = idx + m_clause_size[idx]; - for (unsigned j = idx; j < end; ++j) { - literal lit = m_clause_literals[j]; - if (lit != l) { - remove_clause(lit, idx); - } + remove_clause_at(l, pclauses[i]); + } + } + + void lookahead::remove_clause_at(literal l, unsigned clause_idx) { + unsigned j = clause_idx; + literal lit; + while ((lit = m_clause_literals[j++]) != null_literal) { + if (lit != l) { + remove_clause(lit, clause_idx); } } } @@ -1357,18 +1417,46 @@ namespace sat { --i; if (clause_idx == pclauses[i]) { std::swap(pclauses[i], pclauses[sz-1]); + return; + } + } + UNREACHABLE(); + } + + void lookahead::restore_clauses2(literal l) { + SASSERT(m_search_mode == lookahead_mode::searching); + + // increase the length of clauses where l is negative + unsigned_vector const& nclauses = m_clauses2[(~l).index()]; + unsigned sz = m_clause_count[(~l).index()]; + for (unsigned i = 0; i < sz; ++i) { + ++m_clause_len[nclauses[i]]; + } + + // add idx back to clause list where l is positive + unsigned_vector const& pclauses = m_clauses2[l.index()]; + sz = m_clause_count[l.index()]; + for (unsigned i = 0; i < sz; ++i) { + unsigned idx = pclauses[i]; + unsigned j = idx; + literal lit; + while ((lit = m_clause_literals[j++]) != null_literal) { + if (lit != l) { + m_clause_count[lit.index()]++; + } } } } - void lookahead::restore_clauses2(literal l) { - unsigned_vector const& pclauses = m_clauses2[l.index()]; - unsigned sz = m_clause_count[l.index()]; - for (unsigned i = 0; i < sz; ++i) { - unsigned idx = pclauses[i]; - unsigned end = idx + m_clause_size[idx]; - for (unsigned j = idx; j < end; ++j) { - literal lit = m_clause_literals[j]; + void lookahead::restore_clauses2() { + // restore clauses that were reduced to binary. + unsigned old_sz = m_removed_clauses_lim.back(); + for (unsigned i = m_removed_clauses.size(); i > old_sz; ) { + --i; + std::pair const& p = m_removed_clauses[i]; + literal l = p.first, lit; + unsigned j = p.second; + while ((lit = m_clause_literals[j++]) != null_literal) { if (lit != l) { m_clause_count[lit.index()]++; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 55fdb0211..8a8c3ea9c 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -158,9 +158,10 @@ namespace sat { vector m_clauses2; // lit |-> vector of clause_id unsigned_vector m_clause_count; // lit |-> number of valid clause_id in m_clauses2[lit] - unsigned_vector m_clause_len; // clause_id |-> current clause length - unsigned_vector m_clause_size; // clause_id |-> size of clause >= m_clause_len[clause_id] - literal_vector m_clause_literals; // the actual literals + unsigned_vector m_clause_len; // clause_id |-> current clause length, clauses are terminated using null_literal + literal_vector m_clause_literals; // the actual literals, clauses are separated by a null_literal + svector > m_removed_clauses; + unsigned_vector m_removed_clauses_lim; // TBD trail.. for clause updates? #endif @@ -417,7 +418,9 @@ namespace sat { void propagate_clauses2(literal l); void restore_clauses2(literal l); + void restore_clauses2(); void remove_clause(literal l, unsigned clause_idx); + void remove_clause_at(literal l, unsigned clause_idx); #endif // ------------------------------------ // initialization From e2ed658c6c09c78d0be5760daab469d5b8bef94e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Sep 2017 08:31:10 -0700 Subject: [PATCH 0231/1283] working on new clause management Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 141 ++++++++++++++++++++++++-------------- src/sat/sat_lookahead.h | 2 + 2 files changed, 93 insertions(+), 50 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index f9b6df9a2..0bbf77c3f 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1298,37 +1298,17 @@ namespace sat { } // new n-ary clause managment - void lookahead::propagate_clauses2(literal l) { + void lookahead::propagate_clauses2_searching(literal l) { // clauses where l is negative unsigned_vector const& nclauses = m_clauses2[(~l).index()]; unsigned sz = m_clause_count[(~l).index()]; literal lit; + SASSERT(m_search_mode == lookahead_mode::searching); + for (unsigned i = 0; i < sz; ++i) { unsigned idx = nclauses[i]; - unsigned len = --m_clause_len[idx]; // TBD: only safe to decrement for search_mode == searching - SASSERT(len >= 2); -#if 0 - if (len == 1) { - while ((lit = m_clause_literals[idx++]) != null_literal) { - if (is_fixed(lit)) { - if (is_true(lit)) { - break; - } - } - else { - propagated(lit); - break; - } - } - if (lit == null_literal) { - // it is a conflict - set_conflict(); - for (++i; i < sz; ++i) { - --m_clause_len[nclauses[i]]; - } - } - } -#endif + unsigned len = --m_clause_len[idx]; + if (len <= 1) continue; // already processed // find the two unassigned literals, if any if (len == 2) { literal l1 = null_literal; @@ -1347,6 +1327,7 @@ namespace sat { } } else if (is_true(lit)) { + std::swap(m_clause_literals[j], m_clause_literals[idx]); found_true = true; break; } @@ -1361,36 +1342,19 @@ namespace sat { } } else if (l2 == null_literal) { - // clause gets revisited during propagation, when l2 is true in this clause. - // prevent removing the clause at that point by removing it already now. - m_removed_clauses.push_back(std::make_pair(l, idx)); - remove_clause_at(l, idx); + // clause may get revisited during propagation, when l2 is true in this clause. + // m_removed_clauses.push_back(std::make_pair(~l, idx)); + // remove_clause_at(~l, idx); propagated(l1); } else { - // extract binary clause. - // we should never get a unary or empty clause after this. - m_removed_clauses.push_back(std::make_pair(l, idx)); // need to restore this clause. - remove_clause_at(l, idx); + // extract binary clause. A unary or empty clause may get revisited, + // but we skip it then because it is already handled as a binary clause. + // m_removed_clauses.push_back(std::make_pair(~l, idx)); // need to restore this clause. + // remove_clause_at(~l, idx); try_add_binary(l1, l2); - } - -#if 0 - switch (m_search_mode) { - case lookahead_mode::searching: - detach_clause(c); - try_add_binary(c[0], c[1]); - break; - case lookahead_mode::lookahead1: - update_binary_clause_reward(c[0], c[1]); - // update_nary_clause_reward... - break; - case lookahead_mode::lookahead2: - break; - } -#endif + } } - } // clauses where l is positive: unsigned_vector const& pclauses = m_clauses2[l.index()]; @@ -1400,6 +1364,82 @@ namespace sat { } } + void lookahead::propagate_clauses2_lookahead(literal l) { + // clauses where l is negative + unsigned_vector const& nclauses = m_clauses2[(~l).index()]; + unsigned sz = m_clause_count[(~l).index()]; + literal lit; + SASSERT(m_search_mode == lookahead_mode::lookahead1 || + m_search_mode == lookahead_mode::lookahead2); + + for (unsigned i = 0; i < sz; ++i) { + unsigned idx = nclauses[i]; + literal l1 = null_literal; + literal l2 = null_literal; + unsigned j = idx; + bool found_true = false; + unsigned nonfixed = 0; + while ((lit = m_clause_literals[j++]) != null_literal) { + if (!is_fixed(lit)) { + ++nonfixed; + if (l1 == null_literal) { + l1 = lit; + } + else if (l2 == null_literal) { + l2 = lit; + } + } + else if (is_true(lit)) { + found_true = true; + break; + } + } + if (found_true) { + // skip, the clause will be removed when propagating on 'lit' + } + else if (l1 == null_literal) { + set_conflict(); + return; + } + else if (l2 == null_literal) { + propagated(l1); + } + else if (m_search_mode == lookahead_mode::lookahead2) { + continue; + } + else { + SASSERT (m_search_mode == lookahead_mode::lookahead1); + switch (m_config.m_reward_type) { + case heule_schur_reward: { + j = idx; + double to_add = 0; + while ((lit = m_clause_literals[j++]) != null_literal) { + if (!is_fixed(lit)) { + to_add += literal_occs(lit); + } + } + m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed; + break; + } + case heule_unit_reward: + m_lookahead_reward += pow(0.5, nonfixed); + break; + case ternary_reward: + if (nonfixed == 2) { + m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + } + else { + m_lookahead_reward += (double)0.001; + } + break; + case unit_literal_reward: + break; + } + } + } + } + + void lookahead::remove_clause_at(literal l, unsigned clause_idx) { unsigned j = clause_idx; literal lit; @@ -1448,6 +1488,7 @@ namespace sat { } } + // TBD: this should not be necessary void lookahead::restore_clauses2() { // restore clauses that were reduced to binary. unsigned old_sz = m_removed_clauses_lim.back(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 8a8c3ea9c..27cd3ca06 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -417,6 +417,8 @@ namespace sat { void restore_ternary(literal l); void propagate_clauses2(literal l); + void propagate_clauses2_searching(literal l); + void propagate_clauses2_lookahead(literal l); void restore_clauses2(literal l); void restore_clauses2(); void remove_clause(literal l, unsigned clause_idx); From 7b9156dd5b570216159ccb8e3fa10f2b2a038b65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Sep 2017 10:17:57 -0700 Subject: [PATCH 0232/1283] adding new clause management Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 8 +- src/sat/sat_lookahead.cpp | 271 +++++++++++++++++++++++++++++++------- src/sat/sat_lookahead.h | 33 +++-- src/sat/sat_watched.h | 2 +- 4 files changed, 247 insertions(+), 67 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index cdbbee96b..ffc431d0d 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1534,8 +1534,8 @@ namespace sat { } else { s().set_external(lit.var()); - get_wlist(lit).push_back(c->index()); - get_wlist(~lit).push_back(c->index()); + get_wlist(lit).push_back(watched(c->index())); + get_wlist(~lit).push_back(watched(c->index())); } SASSERT(c->well_formed()); } @@ -2636,8 +2636,8 @@ namespace sat { root = m_roots[c.lit().index()]; nullify_tracking_literal(c); c.update_literal(root); - get_wlist(root).push_back(c.index()); - get_wlist(~root).push_back(c.index()); + get_wlist(root).push_back(watched(c.index())); + get_wlist(~root).push_back(watched(c.index())); } bool found_dup = false; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 0bbf77c3f..be85764b2 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -312,6 +312,39 @@ namespace sat { } bool lookahead::is_unsat() const { +#ifdef NEW_CLAUSE + bool all_false = true; + bool first = true; + // check if there is a clause whose literals are false. + // every clause is terminated by a null-literal. + for (unsigned l_idx : m_clause_literals) { + literal l = to_literal(l_idx); + if (first) { + // skip the first entry, the length indicator. + first = false; + } + else if (l == null_literal) { + // when reaching the end of a clause check if all entries are false + if (all_false) return true; + all_false = true; + first = true; + } + else { + all_false &= is_false(l); + } + } + // check if there is a ternary whose literals are false. + for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { + literal lit = to_literal(idx); + if (is_false(lit)) { + for (binary const& b : m_ternary[lit.index()]) { + if (is_false(b.m_u) && is_false(b.m_v)) + return true; + } + } + } + +#else for (unsigned i = 0; i < m_clauses.size(); ++i) { clause& c = *m_clauses[i]; unsigned j = 0; @@ -322,6 +355,7 @@ namespace sat { return true; } } +#endif return false; } @@ -344,6 +378,37 @@ namespace sat { } } } +#ifdef NEW_CLAUSE + bool no_true = true; + bool first = true; + // check if there is a clause whose literals are false. + // every clause is terminated by a null-literal. + for (unsigned l_idx : m_clause_literals) { + literal l = to_literal(l_idx); + if (first) { + // skip the first entry, the length indicator. + first = false; + } + else if (l == null_literal) { + if (no_true) return false; + no_true = true; + first = true; + } + else { + no_true &= !is_true(l); + } + } + // check if there is a ternary whose literals are false. + for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { + literal lit = to_literal(idx); + if (!is_true(lit)) { + for (binary const& b : m_ternary[lit.index()]) { + if (!is_true(b.m_u) && !is_true(b.m_v)) + return false; + } + } + } +#else for (unsigned i = 0; i < m_clauses.size(); ++i) { clause& c = *m_clauses[i]; unsigned j = 0; @@ -352,6 +417,7 @@ namespace sat { return false; } } +#endif return true; } @@ -867,6 +933,7 @@ namespace sat { // ------------------------------------ // clause management +#ifndef NEW_CLAUSE void lookahead::attach_clause(clause& c) { if (c.size() == 3) { attach_ternary(c[0], c[1], c[2]); @@ -913,6 +980,7 @@ namespace sat { m_watches[(~l2).index()].push_back(watched(l1, l3)); m_watches[(~l3).index()].push_back(watched(l1, l2)); } +#endif // ------------------------------------ // initialization @@ -992,6 +1060,26 @@ namespace sat { void lookahead::copy_clauses(clause_vector const& clauses) { // copy clauses +#ifdef NEW_CLAUSE + for (clause* cp : clauses) { + clause& c = *cp; + if (c.was_removed()) continue; + // enable when there is a non-ternary reward system. + bool was_eliminated = false; + for (unsigned i = 0; !was_eliminated && i < c.size(); ++i) { + was_eliminated = m_s.was_eliminated(c[i].var()); + } + if (was_eliminated) continue; + + switch (c.size()) { + case 1: assign(c[0]); break; + case 2: add_binary(c[0],c[1]); break; + case 3: add_ternary(c[0],c[1],c[2]); break; + default: add_clause(c); break; + } + if (m_s.m_config.m_drat) m_drat.add(c, false); + } +#else for (clause* cp : clauses) { clause& c = *cp; if (c.was_removed()) continue; @@ -1011,6 +1099,7 @@ namespace sat { } if (m_s.m_config.m_drat) m_drat.add(c, false); } +#endif } // ------------------------------------ @@ -1022,8 +1111,10 @@ namespace sat { m_binary_trail_lim.push_back(m_binary_trail.size()); m_trail_lim.push_back(m_trail.size()); m_num_tc1_lim.push_back(m_num_tc1); +#ifndef NEW_CLAUSE m_retired_clause_lim.push_back(m_retired_clauses.size()); m_retired_ternary_lim.push_back(m_retired_ternary.size()); +#endif m_qhead_lim.push_back(m_qhead); scoped_level _sl(*this, level); m_assumptions.push_back(~lit); @@ -1053,6 +1144,7 @@ namespace sat { m_num_tc1 = m_num_tc1_lim.back(); m_num_tc1_lim.pop_back(); +#ifndef NEW_CLAUSE // unretire clauses old_sz = m_retired_clause_lim.back(); for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { @@ -1067,7 +1159,14 @@ namespace sat { } m_retired_ternary.shrink(old_sz); m_retired_ternary_lim.pop_back(); - +#else + for (unsigned i = m_qhead; i > m_qhead_lim.back(); ) { + --i; + restore_ternary(m_trail[i]); + restore_clauses(m_trail[i]); + } +#endif + // remove local binary clauses old_sz = m_binary_trail_lim.back(); for (unsigned i = m_binary_trail.size(); i > old_sz; ) { @@ -1176,9 +1275,9 @@ namespace sat { m_ternary[u.index()].push_back(binary(v, w)); m_ternary[v.index()].push_back(binary(w, u)); m_ternary[w.index()].push_back(binary(u, v)); - m_ternary_size[u.index()]++; - m_ternary_size[v.index()]++; - m_ternary_size[w.index()]++; + m_ternary_count[u.index()]++; + m_ternary_count[v.index()]++; + m_ternary_count[w.index()]++; } lbool lookahead::propagate_ternary(literal l1, literal l2) { @@ -1211,7 +1310,7 @@ namespace sat { } void lookahead::propagate_ternary(literal l) { - unsigned sz = m_ternary_size[(~l).index()]; + unsigned sz = m_ternary_count[(~l).index()]; svector const& negs = m_ternary[(~l).index()]; switch (m_search_mode) { @@ -1235,7 +1334,7 @@ namespace sat { remove_ternary(l1, l2, l); remove_ternary(l2, l, l1); } - sz = m_ternary_size[l.index()]; + sz = m_ternary_count[l.index()]; svector const& poss = m_ternary[l.index()]; // ternary clauses where l is positive are tautologies @@ -1273,7 +1372,7 @@ namespace sat { void lookahead::remove_ternary(literal l, literal u, literal v) { unsigned idx = l.index(); - unsigned sz = m_ternary_size[idx]--; + unsigned sz = m_ternary_count[idx]--; auto& tv = m_ternary[idx]; for (unsigned i = sz; i > 0; ) { --i; @@ -1288,26 +1387,67 @@ namespace sat { void lookahead::restore_ternary(literal l) { for (binary const& b : m_ternary[(~l).index()]) { - m_ternary_size[b.m_u.index()]++; - m_ternary_size[b.m_v.index()]++; + m_ternary_count[b.m_u.index()]++; + m_ternary_count[b.m_v.index()]++; } for (binary const& b : m_ternary[l.index()]) { - m_ternary_size[b.m_u.index()]++; - m_ternary_size[b.m_v.index()]++; + m_ternary_count[b.m_u.index()]++; + m_ternary_count[b.m_v.index()]++; } } + void lookahead::propagate_external(literal l) { + SASSERT(is_true(l)); + if (!m_s.m_ext || inconsistent()) return; + watch_list& wlist = m_watches[l.index()]; + watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); + for (; it != end && !inconsistent(); ++it) { + SASSERT(it->get_kind() == watched::EXT_CONSTRAINT); + bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); + if (m_search_mode == lookahead_mode::lookahead1 && !m_inconsistent) { + lookahead_literal_occs_fun literal_occs_fn(*this); + m_lookahead_reward += m_s.m_ext->get_reward(l, it->get_ext_constraint_idx(), literal_occs_fn); + } + if (m_inconsistent) { + if (!keep) ++it; + } + else if (keep) { + *it2 = *it; + it2++; + } + } + for (; it != end; ++it, ++it2) { + *it2 = *it; + } + wlist.set_end(it2); + } + + // new n-ary clause managment - void lookahead::propagate_clauses2_searching(literal l) { + + void lookahead::add_clause(clause const& c) { + unsigned sz = c.size(); + SASSERT(sz > 3); + unsigned idx = m_clause_literals.size(); + m_clause_literals.push_back(sz); + for (literal l : c) { + m_clause_literals.push_back(l.index()); + m_clause_count[l.index()]++; + m_clauses[l.index()].push_back(idx); + } + m_clause_literals.push_back(null_literal.index()); + } + + void lookahead::propagate_clauses_searching(literal l) { // clauses where l is negative - unsigned_vector const& nclauses = m_clauses2[(~l).index()]; + unsigned_vector const& nclauses = m_clauses[(~l).index()]; unsigned sz = m_clause_count[(~l).index()]; literal lit; SASSERT(m_search_mode == lookahead_mode::searching); for (unsigned i = 0; i < sz; ++i) { unsigned idx = nclauses[i]; - unsigned len = --m_clause_len[idx]; + unsigned len = --m_clause_literals[idx]; if (len <= 1) continue; // already processed // find the two unassigned literals, if any if (len == 2) { @@ -1315,7 +1455,7 @@ namespace sat { literal l2 = null_literal; unsigned j = idx; bool found_true = false; - while ((lit = m_clause_literals[j++]) != null_literal) { + while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { if (!is_fixed(lit)) { if (l1 == null_literal) { l1 = lit; @@ -1327,7 +1467,7 @@ namespace sat { } } else if (is_true(lit)) { - std::swap(m_clause_literals[j], m_clause_literals[idx]); + // can't swap with idx. std::swap(m_clause_literals[j], m_clause_literals[idx]); found_true = true; break; } @@ -1338,7 +1478,7 @@ namespace sat { else if (l1 == null_literal) { set_conflict(); for (++i; i < sz; ++i) { - --m_clause_len[nclauses[i]]; + --m_clause_literals[nclauses[i]]; } } else if (l2 == null_literal) { @@ -1357,16 +1497,16 @@ namespace sat { } } // clauses where l is positive: - unsigned_vector const& pclauses = m_clauses2[l.index()]; + unsigned_vector const& pclauses = m_clauses[l.index()]; sz = m_clause_count[l.index()]; for (unsigned i = 0; i < sz; ++i) { remove_clause_at(l, pclauses[i]); } } - void lookahead::propagate_clauses2_lookahead(literal l) { + void lookahead::propagate_clauses_lookahead(literal l) { // clauses where l is negative - unsigned_vector const& nclauses = m_clauses2[(~l).index()]; + unsigned_vector const& nclauses = m_clauses[(~l).index()]; unsigned sz = m_clause_count[(~l).index()]; literal lit; SASSERT(m_search_mode == lookahead_mode::lookahead1 || @@ -1379,7 +1519,7 @@ namespace sat { unsigned j = idx; bool found_true = false; unsigned nonfixed = 0; - while ((lit = m_clause_literals[j++]) != null_literal) { + while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { if (!is_fixed(lit)) { ++nonfixed; if (l1 == null_literal) { @@ -1413,7 +1553,7 @@ namespace sat { case heule_schur_reward: { j = idx; double to_add = 0; - while ((lit = m_clause_literals[j++]) != null_literal) { + while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { if (!is_fixed(lit)) { to_add += literal_occs(lit); } @@ -1443,7 +1583,7 @@ namespace sat { void lookahead::remove_clause_at(literal l, unsigned clause_idx) { unsigned j = clause_idx; literal lit; - while ((lit = m_clause_literals[j++]) != null_literal) { + while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { if (lit != l) { remove_clause(lit, clause_idx); } @@ -1451,7 +1591,7 @@ namespace sat { } void lookahead::remove_clause(literal l, unsigned clause_idx) { - unsigned_vector& pclauses = m_clauses2[l.index()]; + unsigned_vector& pclauses = m_clauses[l.index()]; unsigned sz = m_clause_count[l.index()]--; for (unsigned i = sz; i > 0; ) { --i; @@ -1463,24 +1603,24 @@ namespace sat { UNREACHABLE(); } - void lookahead::restore_clauses2(literal l) { + void lookahead::restore_clauses(literal l) { SASSERT(m_search_mode == lookahead_mode::searching); // increase the length of clauses where l is negative - unsigned_vector const& nclauses = m_clauses2[(~l).index()]; + unsigned_vector const& nclauses = m_clauses[(~l).index()]; unsigned sz = m_clause_count[(~l).index()]; for (unsigned i = 0; i < sz; ++i) { - ++m_clause_len[nclauses[i]]; + ++m_clause_literals[nclauses[i]]; } // add idx back to clause list where l is positive - unsigned_vector const& pclauses = m_clauses2[l.index()]; + unsigned_vector const& pclauses = m_clauses[l.index()]; sz = m_clause_count[l.index()]; for (unsigned i = 0; i < sz; ++i) { unsigned idx = pclauses[i]; unsigned j = idx; literal lit; - while ((lit = m_clause_literals[j++]) != null_literal) { + while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { if (lit != l) { m_clause_count[lit.index()]++; } @@ -1488,24 +1628,21 @@ namespace sat { } } - // TBD: this should not be necessary - void lookahead::restore_clauses2() { - // restore clauses that were reduced to binary. - unsigned old_sz = m_removed_clauses_lim.back(); - for (unsigned i = m_removed_clauses.size(); i > old_sz; ) { - --i; - std::pair const& p = m_removed_clauses[i]; - literal l = p.first, lit; - unsigned j = p.second; - while ((lit = m_clause_literals[j++]) != null_literal) { - if (lit != l) { - m_clause_count[lit.index()]++; - } - } + void lookahead::propagate_clauses(literal l) { + propagate_ternary(l); + switch (m_search_mode) { + case lookahead_mode::searching: + propagate_clauses_searching(l); + break; + default: + propagate_clauses_lookahead(l); + break; } + propagate_external(l); } + -#endif +#else void lookahead::propagate_clauses(literal l) { SASSERT(is_true(l)); if (inconsistent()) return; @@ -1660,6 +1797,7 @@ namespace sat { } wlist.set_end(it2); } +#endif void lookahead::update_binary_clause_reward(literal l1, literal l2) { SASSERT(!is_false(l1)); @@ -1715,6 +1853,11 @@ namespace sat { // Sum_{ clause C that contains ~l } 1 double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); +#ifdef NEW_CLAUSE + unsigned_vector const& nclauses = m_clauses[(~l).index()]; + result += m_clause_count[(~l).index()]; + result += m_ternary_count[(~l).index()]; +#else for (clause const* c : m_full_watches[l.index()]) { bool has_true = false; for (literal l : *c) { @@ -1725,6 +1868,7 @@ namespace sat { result += 1.0; } } +#endif return result; } @@ -1747,11 +1891,10 @@ namespace sat { TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); propagate_binary(l); } - i = m_qhead; - for (; i < sz && !inconsistent(); ++i) { - propagate_clauses(m_trail[i]); + while (m_qhead < sz && !inconsistent()) { + propagate_clauses(m_trail[m_qhead++]); } - m_qhead = sz; + SASSERT(m_qhead == sz || (inconsistent() && m_qhead < sz)); } TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); @@ -2179,9 +2322,37 @@ namespace sat { } std::ostream& lookahead::display_clauses(std::ostream& out) const { +#ifdef NEW_CLAUSE + bool first = true; + for (unsigned l_idx : m_clause_literals) { + literal l = to_literal(l_idx); + if (first) { + // skip the first entry, the length indicator. + first = false; + } + else if (l == null_literal) { + first = true; + out << "\n"; + } + else { + out << l << " "; + } + } + + for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { + literal lit = to_literal(idx); + for (binary const& b : m_ternary[idx]) { + if (idx < b.m_u.index() && idx << b.m_v.index()) { + out << lit << " " << b.m_u << " " << b.m_v << "\n"; + } + } + } + +#else for (unsigned i = 0; i < m_clauses.size(); ++i) { out << *m_clauses[i] << "\n"; } +#endif return out; } @@ -2409,7 +2580,11 @@ namespace sat { void lookahead::collect_statistics(statistics& st) const { st.update("lh bool var", m_vprefix.size()); +#ifndef NEW_CLAUSE st.update("lh clauses", m_clauses.size()); +#else + // TBD: keep count of ternary and >3-ary clauses. +#endif st.update("lh add binary", m_stats.m_add_binary); st.update("lh del binary", m_stats.m_del_binary); st.update("lh add ternary", m_stats.m_add_ternary); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 27cd3ca06..7296e4282 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,7 +20,7 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ -#define NEW_CLAUSE +// #define NEW_CLAUSE #include "sat_elim_eqs.h" @@ -153,25 +153,26 @@ namespace sat { // specialized clause managemet uses ternary clauses and dedicated clause data-structure. // this will replace m_clauses below vector> m_ternary; // lit |-> vector of ternary clauses - unsigned_vector m_ternary_size; // lit |-> current number of active ternary clauses for lit + unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit unsigned_vector m_ternary_trail_lim; // limit for ternary vectors. - vector m_clauses2; // lit |-> vector of clause_id - unsigned_vector m_clause_count; // lit |-> number of valid clause_id in m_clauses2[lit] - unsigned_vector m_clause_len; // clause_id |-> current clause length, clauses are terminated using null_literal - literal_vector m_clause_literals; // the actual literals, clauses are separated by a null_literal - svector > m_removed_clauses; - unsigned_vector m_removed_clauses_lim; - // TBD trail.. for clause updates? + vector m_clauses; // lit |-> vector of clause_id + unsigned_vector m_clause_count; // lit |-> number of valid clause_id in m_clauses2[lit] + unsigned_vector m_clause_literals; // the actual literals, clauses start at offset clause_id, + // the first entry is the current length, clauses are separated by a null_literal + + #endif unsigned m_num_tc1; unsigned_vector m_num_tc1_lim; unsigned m_qhead; // propagation queue head unsigned_vector m_qhead_lim; +#ifndef NEW_CLAUSE clause_vector m_clauses; // non-binary clauses clause_vector m_retired_clauses; // clauses that were removed during search unsigned_vector m_retired_clause_lim; +#endif svector m_retired_ternary; // ternary removed during search unsigned_vector m_retired_ternary_lim; clause_allocator m_cls_allocator; @@ -399,12 +400,14 @@ namespace sat { // ------------------------------------ // clause management +#ifndef NEW_CLAUSE void attach_clause(clause& c); void detach_clause(clause& c); void del_clauses(); void detach_ternary(literal l1, literal l2, literal l3); void attach_ternary(ternary const& t); void attach_ternary(literal l1, literal l2, literal l3); +#endif watch_list& get_wlist(literal l) { return m_watches[l.index()]; } watch_list const& get_wlist(literal l) const { return m_watches[l.index()]; } @@ -416,11 +419,11 @@ namespace sat { void remove_ternary(literal l, literal u, literal v); void restore_ternary(literal l); - void propagate_clauses2(literal l); - void propagate_clauses2_searching(literal l); - void propagate_clauses2_lookahead(literal l); - void restore_clauses2(literal l); - void restore_clauses2(); + void propagate_external(literal l); + void add_clause(clause const& c); + void propagate_clauses_searching(literal l); + void propagate_clauses_lookahead(literal l); + void restore_clauses(literal l); void remove_clause(literal l, unsigned clause_idx); void remove_clause_at(literal l, unsigned clause_idx); #endif @@ -507,7 +510,9 @@ namespace sat { } ~lookahead() { +#ifndef NEW_CLAUSE del_clauses(); +#endif m_s.rlimit().pop_child(); } diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index ce7b68756..2bbf8aa77 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -72,7 +72,7 @@ namespace sat { SASSERT(get_clause_offset() == cls_off); } - watched(ext_constraint_idx cnstr_idx): + explicit watched(ext_constraint_idx cnstr_idx): m_val1(cnstr_idx), m_val2(static_cast(EXT_CONSTRAINT)) { SASSERT(is_ext_constraint()); From 11499558939cf9fc5b40bc4ac519bb3db2212605 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Sep 2017 14:39:33 -0700 Subject: [PATCH 0233/1283] working on new clause organization Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 65 ++++++++++++++++++++++++++++++++++++--- src/sat/sat_lookahead.h | 8 +++-- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index be85764b2..8579e1c03 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -337,7 +337,9 @@ namespace sat { for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); if (is_false(lit)) { + unsigned sz = m_ternary_count[lit.index()]; for (binary const& b : m_ternary[lit.index()]) { + if (sz-- == 0) break; if (is_false(b.m_u) && is_false(b.m_v)) return true; } @@ -402,7 +404,9 @@ namespace sat { for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); if (!is_true(lit)) { + unsigned sz = m_ternary_count[lit.index()]; for (binary const& b : m_ternary[lit.index()]) { + if (sz-- == 0) break; if (!is_true(b.m_u) && !is_true(b.m_v)) return false; } @@ -474,6 +478,27 @@ namespace sat { for (literal lit : m_binary[l.index()]) { if (is_undef(lit)) sum += literal_occs(lit) / 4.0; } +#ifdef NEW_CLAUSE + unsigned sz = m_ternary_count[(~l).index()]; + for (binary const& b : m_ternary[(~l).index()]) { + if (sz-- == 0) break; + sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0; + } + sz = m_clause_count[(~l).index()]; + for (unsigned idx : m_clauses[(~l).index()]) { + if (sz-- == 0) break; + literal lit; + unsigned j = idx; + double to_add = 0; + while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { + if (!is_fixed(lit) && lit != ~l) { + to_add += literal_occs(lit); + } + } + unsigned len = m_clause_literals[idx]; + sum += pow(0.5, len) * to_add / len; + } +#else watch_list& wlist = m_watches[l.index()]; for (auto & w : wlist) { switch (w.get_kind()) { @@ -506,6 +531,7 @@ namespace sat { break; } } +#endif return sum; } @@ -521,8 +547,16 @@ namespace sat { double lookahead::heule_unit_score(literal l) { double sum = 0; for (literal lit : m_binary[l.index()]) { - if (is_undef(lit)) sum += 0.25; + if (is_undef(lit)) sum += 0.5; } +#ifdef NEW_CLAUSE + sum += 0.25 * m_ternary_count[(~l).index()]; + unsigned sz = m_clause_count[(~l).index()]; + for (unsigned cls_idx : m_clauses[(~l).index()]) { + if (sz-- == 0) break; + sum += pow(0.5, m_clause_literals[cls_idx]); + } +#else watch_list& wlist = m_watches[l.index()]; for (auto & w : wlist) { switch (w.get_kind()) { @@ -553,6 +587,7 @@ namespace sat { break; } } +#endif return sum; } @@ -590,6 +625,13 @@ namespace sat { if (is_undef(lit)) sum += h[lit.index()]; // if (m_freevars.contains(lit.var())) sum += h[lit.index()]; } +#ifdef NEW_CLAUSE + unsigned sz = m_ternary_count[(~l).index()]; + for (binary const& b : m_ternary[(~l).index()]) { + if (sz-- == 0) break; + tsum += h[b.m_u.index()] * h[b.m_v.index()]; + } +#else watch_list& wlist = m_watches[l.index()]; for (auto & w : wlist) { switch (w.get_kind()) { @@ -621,6 +663,7 @@ namespace sat { } // std::cout << "tsum: " << tsum << "\n"; } +#endif // std::cout << "sum: " << sum << " afactor " << afactor << " sqfactor " << sqfactor << " tsum " << tsum << "\n"; sum = (double)(0.1 + afactor*sum + sqfactor*tsum); // std::cout << "sum: " << sum << " max score " << m_config.m_max_score << "\n"; @@ -990,8 +1033,10 @@ namespace sat { m_binary.push_back(literal_vector()); m_watches.push_back(watch_list()); m_watches.push_back(watch_list()); +#ifndef NEW_CLAUSE m_full_watches.push_back(clause_vector()); m_full_watches.push_back(clause_vector()); +#endif m_bstamp.push_back(0); m_bstamp.push_back(0); m_stamp.push_back(0); @@ -1238,6 +1283,7 @@ namespace sat { m_wstack.reset(); } +#ifndef NEW_CLAUSE clause const& lookahead::get_clause(watch_list::iterator it) const { clause_offset cls_off = it->get_clause_offset(); return *(m_cls_allocator.get_clause(cls_off)); @@ -1248,7 +1294,7 @@ namespace sat { DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(is_false(c[j]));); return r; } - +#endif // // The current version is modeled after CDCL SAT solving data-structures. @@ -1386,11 +1432,15 @@ namespace sat { } void lookahead::restore_ternary(literal l) { + unsigned sz = m_ternary_count[(~l).index()]; for (binary const& b : m_ternary[(~l).index()]) { + if (sz-- == 0) break; m_ternary_count[b.m_u.index()]++; m_ternary_count[b.m_v.index()]++; } + sz = m_ternary_count[l.index()]; for (binary const& b : m_ternary[l.index()]) { + if (sz-- == 0) break; m_ternary_count[b.m_u.index()]++; m_ternary_count[b.m_v.index()]++; } @@ -2020,6 +2070,7 @@ namespace sat { bool lookahead::check_autarky(literal l, unsigned level) { return false; +#if 0 // no propagations are allowed to reduce clauses. for (clause * cp : m_full_watches[l.index()]) { clause& c = *cp; @@ -2049,6 +2100,7 @@ namespace sat { } return true; +#endif } @@ -2061,9 +2113,11 @@ namespace sat { ++m_stats.m_autarky_propagations; IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); +#ifdef NEW_CLAUSE TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] << " " - << (!m_binary[l.index()].empty() || !m_full_watches[l.index()].empty()) << "\n";); + << (!m_binary[l.index()].empty() || m_clause_count[l.index()] != 0) << "\n";); +#endif reset_lookahead_reward(); assign(l); propagate(); @@ -2341,7 +2395,9 @@ namespace sat { for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); + unsigned sz = m_ternary_count[idx]; for (binary const& b : m_ternary[idx]) { + if (sz-- == 0) break; if (idx < b.m_u.index() && idx << b.m_v.index()) { out << lit << " " << b.m_u << " " << b.m_v << "\n"; } @@ -2555,10 +2611,11 @@ namespace sat { out << "free vars: "; for (bool_var b : m_freevars) out << b << " "; out << "\n"; + clause_allocator dummy_allocator; for (unsigned i = 0; i < m_watches.size(); ++i) { watch_list const& wl = m_watches[i]; if (!wl.empty()) { - sat::display_watch_list(out << to_literal(i) << " -> ", m_cls_allocator, wl); + sat::display_watch_list(out << to_literal(i) << " -> ", dummy_allocator, wl); out << "\n"; } } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 7296e4282..efd650e59 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -125,10 +125,12 @@ namespace sat { void reset() { memset(this, 0, sizeof(*this)); } }; +#ifndef NEW_CLAUSE struct ternary { ternary(literal u, literal v, literal w): m_u(u), m_v(v), m_w(w) {} literal m_u, m_v, m_w; }; +#endif #ifdef NEW_CLAUSE struct binary { @@ -172,10 +174,10 @@ namespace sat { clause_vector m_clauses; // non-binary clauses clause_vector m_retired_clauses; // clauses that were removed during search unsigned_vector m_retired_clause_lim; -#endif svector m_retired_ternary; // ternary removed during search unsigned_vector m_retired_ternary_lim; - clause_allocator m_cls_allocator; + clause_allocator m_cls_allocator; +#endif bool m_inconsistent; unsigned_vector m_bstamp; // literal: timestamp for binary implication vector > m_H; // literal: fitness score @@ -188,7 +190,9 @@ namespace sat { const unsigned c_fixed_truth = UINT_MAX - 1; vector m_watches; // literal: watch structure svector m_lits; // literal: attributes. +#ifndef NEW_CLAUSE vector m_full_watches; // literal: full watch list, used to ensure that autarky reduction is sound +#endif double m_lookahead_reward; // metric associated with current lookahead1 literal. literal_vector m_wstack; // windofall stack that is populated in lookahead1 mode uint64 m_prefix; // where we are in search tree From 3a832e5b24742937b16ec3a5ad5ac8ebe752da17 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Sep 2017 20:14:49 -0700 Subject: [PATCH 0234/1283] tidy Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 186 ++++++++++++++++++++------------------ src/sat/sat_lookahead.h | 13 ++- 2 files changed, 105 insertions(+), 94 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 8579e1c03..66ad2afd7 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -317,7 +317,7 @@ namespace sat { bool first = true; // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. - for (unsigned l_idx : m_clause_literals) { + for (unsigned l_idx : m_nary_literals) { literal l = to_literal(l_idx); if (first) { // skip the first entry, the length indicator. @@ -385,7 +385,7 @@ namespace sat { bool first = true; // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. - for (unsigned l_idx : m_clause_literals) { + for (unsigned l_idx : m_nary_literals) { literal l = to_literal(l_idx); if (first) { // skip the first entry, the length indicator. @@ -484,18 +484,18 @@ namespace sat { if (sz-- == 0) break; sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0; } - sz = m_clause_count[(~l).index()]; - for (unsigned idx : m_clauses[(~l).index()]) { + sz = m_nary_count[(~l).index()]; + for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; literal lit; unsigned j = idx; double to_add = 0; - while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { + while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { if (!is_fixed(lit) && lit != ~l) { to_add += literal_occs(lit); } } - unsigned len = m_clause_literals[idx]; + unsigned len = m_nary_literals[idx]; sum += pow(0.5, len) * to_add / len; } #else @@ -551,10 +551,10 @@ namespace sat { } #ifdef NEW_CLAUSE sum += 0.25 * m_ternary_count[(~l).index()]; - unsigned sz = m_clause_count[(~l).index()]; - for (unsigned cls_idx : m_clauses[(~l).index()]) { + unsigned sz = m_nary_count[(~l).index()]; + for (unsigned cls_idx : m_nary[(~l).index()]) { if (sz-- == 0) break; - sum += pow(0.5, m_clause_literals[cls_idx]); + sum += pow(0.5, m_nary_literals[cls_idx]); } #else watch_list& wlist = m_watches[l.index()]; @@ -973,10 +973,11 @@ namespace sat { } +#ifndef NEW_CLAUSE + // ------------------------------------ // clause management -#ifndef NEW_CLAUSE void lookahead::attach_clause(clause& c) { if (c.size() == 3) { attach_ternary(c[0], c[1], c[2]); @@ -1036,6 +1037,15 @@ namespace sat { #ifndef NEW_CLAUSE m_full_watches.push_back(clause_vector()); m_full_watches.push_back(clause_vector()); +#else + m_ternary.push_back(svector); + m_ternary.push_back(svector); + m_ternary_count.push_back(0); + m_ternary_count.push_back(0); + m_nary.push_back(unsigned_vector()); + m_nary.push_back(unsigned_vector()); + m_nary_count.push_back(0); + m_nary_count.push_back(0); #endif m_bstamp.push_back(0); m_bstamp.push_back(0); @@ -1183,8 +1193,6 @@ namespace sat { TRACE("sat", tout << "inserting free var v" << l.var() << "\n";); m_freevars.insert(l.var()); } - m_trail.shrink(old_sz); // reset assignment. - m_trail_lim.pop_back(); m_num_tc1 = m_num_tc1_lim.back(); m_num_tc1_lim.pop_back(); @@ -1212,6 +1220,9 @@ namespace sat { } #endif + m_trail.shrink(old_sz); // reset assignment. + m_trail_lim.pop_back(); + // remove local binary clauses old_sz = m_binary_trail_lim.back(); for (unsigned i = m_binary_trail.size(); i > old_sz; ) { @@ -1357,15 +1368,13 @@ namespace sat { void lookahead::propagate_ternary(literal l) { unsigned sz = m_ternary_count[(~l).index()]; - svector const& negs = m_ternary[(~l).index()]; switch (m_search_mode) { case lookahead_mode::searching: { // ternary clauses where l is negative become binary - - for (unsigned i = 0; i < sz; ++i) { - binary const& b = negs[i]; + for (binary const& b : m_ternary[(~l).index()]) { + if (sz-- == 0) break; // this could create a conflict from propagation, but we complete the transaction. literal l1 = b.m_u; literal l2 = b.m_v; @@ -1374,18 +1383,17 @@ namespace sat { try_add_binary(l1, l2); break; default: - // propagated or tautology. + // propagated or tautology or conflict break; } remove_ternary(l1, l2, l); remove_ternary(l2, l, l1); } - sz = m_ternary_count[l.index()]; - svector const& poss = m_ternary[l.index()]; - + + sz = m_ternary_count[l.index()]; // ternary clauses where l is positive are tautologies - for (unsigned i = 0; i < sz; ++i) { - binary const& b = poss[i]; + for (binary const& b : m_ternary[l.index()]) { + if (sz-- == 0) break; remove_ternary(b.m_u, b.m_v, l); remove_ternary(b.m_v, l, b.m_u); } @@ -1393,8 +1401,8 @@ namespace sat { } case lookahead_mode::lookahead1: // this could create a conflict from propagation, but we complete the loop. - for (unsigned i = 0; i < sz; ++i) { - binary const& b = negs[i]; + for (binary const& b : m_ternary[(~l).index()]) { + if (sz-- == 0) break; literal l1 = b.m_u; literal l2 = b.m_v; switch (propagate_ternary(l1, l2)) { @@ -1408,8 +1416,8 @@ namespace sat { break; case lookahead2: // this could create a conflict from propagation, but we complete the loop. - for (unsigned i = 0; i < sz; ++i) { - binary const& b = negs[i]; + for (binary const& b : m_ternary[(~l).index()]) { + if (sz-- == 0) break; propagate_ternary(b.m_u, b.m_v); } break; @@ -1434,7 +1442,7 @@ namespace sat { void lookahead::restore_ternary(literal l) { unsigned sz = m_ternary_count[(~l).index()]; for (binary const& b : m_ternary[(~l).index()]) { - if (sz-- == 0) break; + if (sz-- == 0) break; m_ternary_count[b.m_u.index()]++; m_ternary_count[b.m_v.index()]++; } @@ -1458,7 +1466,7 @@ namespace sat { lookahead_literal_occs_fun literal_occs_fn(*this); m_lookahead_reward += m_s.m_ext->get_reward(l, it->get_ext_constraint_idx(), literal_occs_fn); } - if (m_inconsistent) { + if (inconsistent()) { if (!keep) ++it; } else if (keep) { @@ -1478,26 +1486,26 @@ namespace sat { void lookahead::add_clause(clause const& c) { unsigned sz = c.size(); SASSERT(sz > 3); - unsigned idx = m_clause_literals.size(); - m_clause_literals.push_back(sz); + unsigned idx = m_nary_literals.size(); + m_nary_literals.push_back(sz); for (literal l : c) { - m_clause_literals.push_back(l.index()); - m_clause_count[l.index()]++; - m_clauses[l.index()].push_back(idx); + m_nary_literals.push_back(l.index()); + m_nary_count[l.index()]++; + m_nary[l.index()].push_back(idx); + SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size()); } - m_clause_literals.push_back(null_literal.index()); + m_nary_literals.push_back(null_literal.index()); } void lookahead::propagate_clauses_searching(literal l) { // clauses where l is negative - unsigned_vector const& nclauses = m_clauses[(~l).index()]; - unsigned sz = m_clause_count[(~l).index()]; + unsigned sz = m_nary_count[(~l).index()]; literal lit; SASSERT(m_search_mode == lookahead_mode::searching); - for (unsigned i = 0; i < sz; ++i) { - unsigned idx = nclauses[i]; - unsigned len = --m_clause_literals[idx]; + for (unsigned idx : m_nary[(~l).index()]) { + if (sz-- == 0) break; + unsigned len = --m_nary_literals[idx]; if (len <= 1) continue; // already processed // find the two unassigned literals, if any if (len == 2) { @@ -1505,7 +1513,7 @@ namespace sat { literal l2 = null_literal; unsigned j = idx; bool found_true = false; - while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { + while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { if (!is_fixed(lit)) { if (l1 == null_literal) { l1 = lit; @@ -1517,7 +1525,7 @@ namespace sat { } } else if (is_true(lit)) { - // can't swap with idx. std::swap(m_clause_literals[j], m_clause_literals[idx]); + // can't swap with idx. std::swap(m_nary_literals[j], m_nary_literals[idx]); found_true = true; break; } @@ -1528,7 +1536,7 @@ namespace sat { else if (l1 == null_literal) { set_conflict(); for (++i; i < sz; ++i) { - --m_clause_literals[nclauses[i]]; + --m_nary_literals[nclauses[i]]; } } else if (l2 == null_literal) { @@ -1547,29 +1555,28 @@ namespace sat { } } // clauses where l is positive: - unsigned_vector const& pclauses = m_clauses[l.index()]; - sz = m_clause_count[l.index()]; - for (unsigned i = 0; i < sz; ++i) { - remove_clause_at(l, pclauses[i]); + sz = m_nary_count[l.index()]; + for (unsigned idx : m_nary[l.index())) { + if (sz-- == 0) break; + remove_clause_at(l, idx); } } void lookahead::propagate_clauses_lookahead(literal l) { // clauses where l is negative - unsigned_vector const& nclauses = m_clauses[(~l).index()]; - unsigned sz = m_clause_count[(~l).index()]; + unsigned sz = m_nary_count[(~l).index()]; literal lit; SASSERT(m_search_mode == lookahead_mode::lookahead1 || m_search_mode == lookahead_mode::lookahead2); - - for (unsigned i = 0; i < sz; ++i) { - unsigned idx = nclauses[i]; + + for (unsigned idx : m_nary[(~l).index()]) { + if (sz-- == 0) break; literal l1 = null_literal; literal l2 = null_literal; unsigned j = idx; bool found_true = false; unsigned nonfixed = 0; - while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { + while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { if (!is_fixed(lit)) { ++nonfixed; if (l1 == null_literal) { @@ -1598,12 +1605,13 @@ namespace sat { continue; } else { - SASSERT (m_search_mode == lookahead_mode::lookahead1); + SASSERT(nonfixed >= 2); + SASSERT(m_search_mode == lookahead_mode::lookahead1); switch (m_config.m_reward_type) { case heule_schur_reward: { j = idx; double to_add = 0; - while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { + while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { if (!is_fixed(lit)) { to_add += literal_occs(lit); } @@ -1633,7 +1641,7 @@ namespace sat { void lookahead::remove_clause_at(literal l, unsigned clause_idx) { unsigned j = clause_idx; literal lit; - while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { + while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { if (lit != l) { remove_clause(lit, clause_idx); } @@ -1641,8 +1649,8 @@ namespace sat { } void lookahead::remove_clause(literal l, unsigned clause_idx) { - unsigned_vector& pclauses = m_clauses[l.index()]; - unsigned sz = m_clause_count[l.index()]--; + unsigned_vector& pclauses = m_nary[l.index()]; + unsigned sz = m_nary_count[l.index()]--; for (unsigned i = sz; i > 0; ) { --i; if (clause_idx == pclauses[i]) { @@ -1657,22 +1665,25 @@ namespace sat { SASSERT(m_search_mode == lookahead_mode::searching); // increase the length of clauses where l is negative - unsigned_vector const& nclauses = m_clauses[(~l).index()]; - unsigned sz = m_clause_count[(~l).index()]; - for (unsigned i = 0; i < sz; ++i) { - ++m_clause_literals[nclauses[i]]; + unsigned sz = m_nary_count[(~l).index()]; + for (unsigned idx : m_nary[(~l).index()]) { + if (sz-- == 0) break; + ++m_nary_literals[idx]; } // add idx back to clause list where l is positive - unsigned_vector const& pclauses = m_clauses[l.index()]; - sz = m_clause_count[l.index()]; - for (unsigned i = 0; i < sz; ++i) { - unsigned idx = pclauses[i]; - unsigned j = idx; + // add them back in the same order as they were inserted + // in this way we can check that the clauses are the same. + sz = m_nary_count[l.index()]; + unsigned_vector const& pclauses = m_nary[l.index()]; + for (unsigned i = sz; i > 0; ) { + --i; + unsigned j = pclauses[i]; literal lit; - while ((lit = to_literal(m_clause_literals[++j])) != null_literal) { + while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { if (lit != l) { - m_clause_count[lit.index()]++; + SASSERT(m_nary[lit.index()] == pclauses[i]); + m_nary_count[lit.index()]++; } } } @@ -1904,8 +1915,8 @@ namespace sat { double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); #ifdef NEW_CLAUSE - unsigned_vector const& nclauses = m_clauses[(~l).index()]; - result += m_clause_count[(~l).index()]; + unsigned_vector const& nclauses = m_nary[(~l).index()]; + result += m_nary_count[(~l).index()]; result += m_ternary_count[(~l).index()]; #else for (clause const* c : m_full_watches[l.index()]) { @@ -2116,7 +2127,7 @@ namespace sat { #ifdef NEW_CLAUSE TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] << " " - << (!m_binary[l.index()].empty() || m_clause_count[l.index()] != 0) << "\n";); + << (!m_binary[l.index()].empty() || m_nary_count[l.index()] != 0) << "\n";); #endif reset_lookahead_reward(); assign(l); @@ -2378,20 +2389,6 @@ namespace sat { std::ostream& lookahead::display_clauses(std::ostream& out) const { #ifdef NEW_CLAUSE bool first = true; - for (unsigned l_idx : m_clause_literals) { - literal l = to_literal(l_idx); - if (first) { - // skip the first entry, the length indicator. - first = false; - } - else if (l == null_literal) { - first = true; - out << "\n"; - } - else { - out << l << " "; - } - } for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -2404,6 +2401,22 @@ namespace sat { } } + for (unsigned l_idx : m_nary_literals) { + literal l = to_literal(l_idx); + if (first) { + // the first entry is a length indicator of non-false literals. + out << l_idx << ": "; + first = false; + } + else if (l == null_literal) { + first = true; + out << "\n"; + } + else { + out << l << " "; + } + } + #else for (unsigned i = 0; i < m_clauses.size(); ++i) { out << *m_clauses[i] << "\n"; @@ -2413,8 +2426,7 @@ namespace sat { } std::ostream& lookahead::display_values(std::ostream& out) const { - for (unsigned i = 0; i < m_trail.size(); ++i) { - literal l = m_trail[i]; + for (literal l : m_trail) { out << l << "\n"; } return out; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index efd650e59..78ec590b5 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -153,15 +153,14 @@ namespace sat { #ifdef NEW_CLAUSE // specialized clause managemet uses ternary clauses and dedicated clause data-structure. - // this will replace m_clauses below + // this replaces m_clauses below vector> m_ternary; // lit |-> vector of ternary clauses - unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit - unsigned_vector m_ternary_trail_lim; // limit for ternary vectors. + unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit - vector m_clauses; // lit |-> vector of clause_id - unsigned_vector m_clause_count; // lit |-> number of valid clause_id in m_clauses2[lit] - unsigned_vector m_clause_literals; // the actual literals, clauses start at offset clause_id, - // the first entry is the current length, clauses are separated by a null_literal + vector m_nary; // lit |-> vector of clause_id + unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_clauses2[lit] + unsigned_vector m_nary_literals; // the actual literals, clauses start at offset clause_id, + // the first entry is the current length, clauses are separated by a null_literal #endif From 0833a9ee14d8a3ec665b28918084c30392552992 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Sep 2017 07:15:06 -0700 Subject: [PATCH 0235/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 41 +++++++++++++++++++++++++++++++++++---- src/sat/sat_lookahead.h | 2 +- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 66ad2afd7..ce205cc2f 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1086,8 +1086,8 @@ namespace sat { } } - copy_clauses(m_s.m_clauses); - copy_clauses(m_s.m_learned); + copy_clauses(m_s.m_clauses, false); + copy_clauses(m_s.m_learned, true); // copy units unsigned trail_sz = m_s.init_trail_size(); @@ -1113,7 +1113,7 @@ namespace sat { TRACE("sat", m_s.display(tout); display(tout);); } - void lookahead::copy_clauses(clause_vector const& clauses) { + void lookahead::copy_clauses(clause_vector const& clauses, bool learned) { // copy clauses #ifdef NEW_CLAUSE for (clause* cp : clauses) { @@ -1130,7 +1130,7 @@ namespace sat { case 1: assign(c[0]); break; case 2: add_binary(c[0],c[1]); break; case 3: add_ternary(c[0],c[1],c[2]); break; - default: add_clause(c); break; + default: if (!learned) add_clause(c); break; } if (m_s.m_config.m_drat) m_drat.add(c, false); } @@ -1497,6 +1497,39 @@ namespace sat { m_nary_literals.push_back(null_literal.index()); } +#if 0 + // split large clauses into smaller ones to avoid overhead during propagation. + + void lookahead::add_clause(unsigned sz, literal const * lits) { + if (sz > 6) { + bool_var v = m_s.mk_var(false); + ++m_num_vars; + init_var(v); + literal lit(v, false); + unsigned mid = sz / 2; + literal_vector lits1(mid, lits); + lits1.push_back(lit); + add_clause(lits1.size(), lits1.c_ptr()); + lit.neg(); + literal_vector lits2(sz - mid, lits + mid); + lits2.push_back(lit); + add_clause(lits2.size(), lits2.c_ptr()); + } + else { + unsigned idx = m_nary_literals.size(); + m_nary_literals.push_back(sz); + for (unsigned i = 0; i < sz; ++i) { + literal l = lits[i]; + m_nary_literals.push_back(l.index()); + m_nary_count[l.index()]++; + m_nary[l.index()].push_back(idx); + SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size()); + } + m_nary_literals.push_back(null_literal.index()); + } + } +#endif + void lookahead::propagate_clauses_searching(literal l) { // clauses where l is negative unsigned sz = m_nary_count[(~l).index()]; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 78ec590b5..a3777ea44 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -435,7 +435,7 @@ namespace sat { void init_var(bool_var v); void init(); - void copy_clauses(clause_vector const& clauses); + void copy_clauses(clause_vector const& clauses, bool learned); // ------------------------------------ // search From 340b460f74d03da899608c9433e5be99a938b6aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Sep 2017 07:20:34 -0700 Subject: [PATCH 0236/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 8579e1c03..a289a3814 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1117,6 +1117,7 @@ namespace sat { if (was_eliminated) continue; switch (c.size()) { + case 0: set_conflict(); break; case 1: assign(c[0]); break; case 2: add_binary(c[0],c[1]); break; case 3: add_ternary(c[0],c[1],c[2]); break; From a1e4fc3e98869243894b1477e6fdae966acb53d7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Sep 2017 11:13:35 -0700 Subject: [PATCH 0237/1283] fix new clause encoding Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 2 +- src/sat/sat_lookahead.cpp | 49 ++++++++++++++++++++++++++------------- src/sat/sat_lookahead.h | 2 +- src/sat/sat_solver.cpp | 2 +- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 2ba7cec57..0248b5b0b 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -87,7 +87,7 @@ namespace sat { m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_cube = p.lookahead_cube(); m_lookahead_search = p.lookahead_search(); - if (p.lookahead_reward() == symbol("hs")) { + if (p.lookahead_reward() == symbol("heule_schur")) { m_lookahead_reward = heule_schur_reward; } else if (p.lookahead_reward() == symbol("heuleu")) { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 12018f083..13506529a 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -930,12 +930,25 @@ namespace sat { return out; } + static unsigned last_prefix_length = 0; + void lookahead::display_search_string() { printf("\r"); - std::stringstream strm; - strm << pp_prefix(m_prefix, m_trail_lim.size()); - for (unsigned i = 0; i < 50; ++i) strm << " "; - printf(strm.str().c_str()); + uint64 q = m_prefix; + unsigned depth = m_trail_lim.size(); + unsigned d = std::min(63u, depth); + unsigned new_prefix_length = d; + for (unsigned i = 0; i <= d; ++i) { + printf((0 != (q & (1ull << i)))? "1" : "0"); + } + if (d < depth) { + printf(" d: %d", depth); + new_prefix_length += 10; + } + for (unsigned i = new_prefix_length; i < last_prefix_length; ++i) { + printf(" "); + } + last_prefix_length = new_prefix_length; fflush(stdout); } @@ -1038,8 +1051,8 @@ namespace sat { m_full_watches.push_back(clause_vector()); m_full_watches.push_back(clause_vector()); #else - m_ternary.push_back(svector); - m_ternary.push_back(svector); + m_ternary.push_back(svector()); + m_ternary.push_back(svector()); m_ternary_count.push_back(0); m_ternary_count.push_back(0); m_nary.push_back(unsigned_vector()); @@ -1100,8 +1113,8 @@ namespace sat { } // copy externals: - for (unsigned idx = 0; idx < m_watches.size(); ++idx) { - watch_list const& wl = m_watches[idx]; + for (unsigned idx = 0; idx < m_s.m_watches.size(); ++idx) { + watch_list const& wl = m_s.m_watches[idx]; for (watched const& w : wl) { if (w.is_ext_constraint()) { m_watches[idx].push_back(w); @@ -1199,6 +1212,9 @@ namespace sat { m_num_tc1_lim.pop_back(); #ifndef NEW_CLAUSE + m_trail.shrink(old_sz); // reset assignment. + m_trail_lim.pop_back(); + // unretire clauses old_sz = m_retired_clause_lim.back(); for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { @@ -1219,11 +1235,13 @@ namespace sat { restore_ternary(m_trail[i]); restore_clauses(m_trail[i]); } -#endif m_trail.shrink(old_sz); // reset assignment. m_trail_lim.pop_back(); +#endif + + // remove local binary clauses old_sz = m_binary_trail_lim.back(); for (unsigned i = m_binary_trail.size(); i > old_sz; ) { @@ -1377,6 +1395,7 @@ namespace sat { for (binary const& b : m_ternary[(~l).index()]) { if (sz-- == 0) break; // this could create a conflict from propagation, but we complete the transaction. + TRACE("sat", display(tout);); literal l1 = b.m_u; literal l2 = b.m_v; switch (propagate_ternary(l1, l2)) { @@ -1387,8 +1406,8 @@ namespace sat { // propagated or tautology or conflict break; } - remove_ternary(l1, l2, l); - remove_ternary(l2, l, l1); + remove_ternary(l1, l2, ~l); + remove_ternary(l2, ~l, l1); } sz = m_ternary_count[l.index()]; @@ -1540,6 +1559,7 @@ namespace sat { for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; unsigned len = --m_nary_literals[idx]; + if (m_inconsistent) continue; if (len <= 1) continue; // already processed // find the two unassigned literals, if any if (len == 2) { @@ -1569,9 +1589,6 @@ namespace sat { } else if (l1 == null_literal) { set_conflict(); - for (++i; i < sz; ++i) { - --m_nary_literals[nclauses[i]]; - } } else if (l2 == null_literal) { // clause may get revisited during propagation, when l2 is true in this clause. @@ -1590,7 +1607,7 @@ namespace sat { } // clauses where l is positive: sz = m_nary_count[l.index()]; - for (unsigned idx : m_nary[l.index())) { + for (unsigned idx : m_nary[l.index()]) { if (sz-- == 0) break; remove_clause_at(l, idx); } @@ -1716,7 +1733,7 @@ namespace sat { literal lit; while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { if (lit != l) { - SASSERT(m_nary[lit.index()] == pclauses[i]); + // SASSERT(m_nary[lit.index()] == pclauses[i]); m_nary_count[lit.index()]++; } } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index a3777ea44..c64f265c0 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,7 +20,7 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ -// #define NEW_CLAUSE +#define NEW_CLAUSE #include "sat_elim_eqs.h" diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f0a423491..d42243a06 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -65,7 +65,7 @@ namespace sat { } solver::~solver() { - m_ext = 0; + m_ext = 0; SASSERT(check_invariant()); TRACE("sat", tout << "Delete clauses\n";); del_clauses(m_clauses.begin(), m_clauses.end()); From 7db1132c33fe38642e876bbe8fa83a2252475195 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Sep 2017 14:54:24 -0700 Subject: [PATCH 0238/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 13506529a..74b54e283 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1987,9 +1987,9 @@ namespace sat { void lookahead::propagate_binary(literal l) { literal_vector const& lits = m_binary[l.index()]; TRACE("sat", tout << l << " => " << lits << "\n";); - unsigned sz = lits.size(); - for (unsigned i = 0; !inconsistent() && i < sz; ++i) { - assign(lits[i]); + for (literal l : lits) { + if (inconsistent()) break; + assign(l); } } From ff2cdc0e3f75bcecd549a27db1cd451c1aa9fee3 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Wed, 27 Sep 2017 17:18:28 -0700 Subject: [PATCH 0239/1283] local updates Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_config.cpp | 2 ++ src/sat/sat_config.h | 2 ++ src/sat/sat_params.pyg | 4 +++- src/sat/sat_simplifier.cpp | 2 +- src/sat/sat_solver.cpp | 20 ++++++++++++++++---- src/sat/sat_solver.h | 1 + 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 0248b5b0b..49a146489 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -72,6 +72,7 @@ namespace sat { m_restart_initial = p.restart_initial(); m_restart_factor = p.restart_factor(); m_restart_max = p.restart_max(); + m_inprocess_max = p.inprocess_max(); m_random_freq = p.random_freq(); m_random_seed = p.random_seed(); @@ -183,6 +184,7 @@ namespace sat { throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); } m_dimacs_display = p.dimacs_display(); + m_dimacs_inprocess_display = p.dimacs_inprocess_display(); } void config::collect_param_descrs(param_descrs & r) { diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index ba68b7901..a7c8590fb 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -73,6 +73,7 @@ namespace sat { unsigned m_restart_initial; double m_restart_factor; // for geometric case unsigned m_restart_max; + unsigned m_inprocess_max; double m_random_freq; unsigned m_random_seed; unsigned m_burst_search; @@ -106,6 +107,7 @@ namespace sat { bool m_drat_check; bool m_dimacs_display; + bool m_dimacs_inprocess_display; symbol m_always_true; symbol m_always_false; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index ab35b3c56..67659aa24 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -9,6 +9,7 @@ def_module_params('sat', ('restart.initial', UINT, 100, 'initial restart (number of conflicts)'), ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), + ('inprocess.max', UINT, UINT_MAX, 'maximal number of inprocessing passes'), ('branching.heuristic', SYMBOL, 'vsids', 'branching heuristic vsids, lrb or chb'), ('branching.anti_exploration', BOOL, False, 'apply anti-exploration heuristic for branch selection'), ('random_freq', DOUBLE, 0.01, 'frequency of random case splits'), @@ -40,5 +41,6 @@ def_module_params('sat', ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead.reward', SYMBOL, 'heuleu', 'select lookahead heuristic: ternary, hs (Heule Schur), heuleu (Heule Unit), or unit'), - ('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving'))) + ('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving'), + ('dimacs.inprocess.display', BOOL, False, 'display SAT instance in DIMACS format if unsolved after inprocess.max inprocessing passes'))) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 7ef9a7338..4d5946795 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -73,7 +73,7 @@ namespace sat { inline bool simplifier::is_external(bool_var v) const { return s.is_assumption(v) || - (s.is_external(v) && + (s.is_external(v) && s.m_ext && (!m_ext_use_list.get(literal(v, false)).empty() || !m_ext_use_list.get(literal(v, true)).empty())); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d42243a06..e15cddbd6 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -62,6 +62,7 @@ namespace sat { m_conflicts_since_init = 0; m_next_simplify = 0; m_num_checkpoints = 0; + m_simplifications = 0; } solver::~solver() { @@ -797,7 +798,6 @@ namespace sat { keep = m_ext->propagate(l, it->get_ext_constraint_idx()); if (m_inconsistent) { if (!keep) { - std::cout << "CONFLICT - but throw away current watch literal\n"; ++it; } CONFLICT_CLEANUP(); @@ -925,6 +925,17 @@ namespace sat { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-restarts\")\n";); return l_undef; } + if (m_config.m_inprocess_max <= m_simplifications) { + m_reason_unknown = "sat.max.inprocess"; + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-inprocess\")\n";); + if (m_config.m_dimacs_inprocess_display) { + display_dimacs(std::cout); + for (unsigned i = 0; i < num_lits; ++lits) { + std::cout << dimacs_lit(lits[i]) << " 0\n"; + } + } + return l_undef; + } } } @@ -1411,7 +1422,8 @@ namespace sat { if (m_conflicts_since_init < m_next_simplify) { return; } - IF_VERBOSE(2, verbose_stream() << "(sat.simplify)\n";); + m_simplifications++; + IF_VERBOSE(2, verbose_stream() << "(sat.simplify :simplifications " << m_simplifications << ")\n";); TRACE("sat", tout << "simplify\n";); @@ -1424,11 +1436,11 @@ namespace sat { m_scc(); CASSERT("sat_simplify_bug", check_invariant()); - + m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); - + if (!m_learned.empty()) { m_simplifier(true); CASSERT("sat_missed_prop", check_missed_propagation()); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 581f557a7..fd8de1ad3 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -367,6 +367,7 @@ namespace sat { unsigned m_conflicts_since_init; unsigned m_restarts; unsigned m_conflicts_since_restart; + unsigned m_simplifications; unsigned m_restart_threshold; unsigned m_luby_idx; unsigned m_conflicts_since_gc; From 6c4cadd22384985ce8e429e7dafef8ecd4ccf364 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Sep 2017 00:33:56 -0700 Subject: [PATCH 0240/1283] tidy Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 19 ++--- src/sat/sat_lookahead.h | 6 +- src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 53 +++----------- src/sat/tactic/atom2bool_var.cpp | 15 ++-- src/sat/tactic/goal2sat.cpp | 100 +++++++++++--------------- 6 files changed, 70 insertions(+), 124 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 74b54e283..f3a0c9d9c 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -463,10 +463,8 @@ namespace sat { } } - static unsigned counter = 0; void lookahead::heule_schur_scores() { - if (counter % 10 != 0) return; - ++counter; + if (m_rating_throttle++ % 10 != 0) return; for (bool_var x : m_freevars) { literal l(x, false); m_rating[l.var()] = heule_schur_score(l) * heule_schur_score(~l); @@ -536,8 +534,7 @@ namespace sat { } void lookahead::heule_unit_scores() { - if (counter % 10 != 0) return; - ++counter; + if (m_rating_throttle++ % 10 != 0) return; for (bool_var x : m_freevars) { literal l(x, false); m_rating[l.var()] = heule_unit_score(l) * heule_unit_score(~l); @@ -614,7 +611,6 @@ namespace sat { double neg = l_score(~l, h, factor, sqfactor, afactor); hp[l.index()] = pos; hp[(~l).index()] = neg; - // std::cout << "h_scores: " << pos << " " << neg << "\n"; m_rating[l.var()] = pos * neg; } } @@ -930,8 +926,6 @@ namespace sat { return out; } - static unsigned last_prefix_length = 0; - void lookahead::display_search_string() { printf("\r"); uint64 q = m_prefix; @@ -945,10 +939,10 @@ namespace sat { printf(" d: %d", depth); new_prefix_length += 10; } - for (unsigned i = new_prefix_length; i < last_prefix_length; ++i) { + for (unsigned i = new_prefix_length; i < m_last_prefix_length; ++i) { printf(" "); } - last_prefix_length = new_prefix_length; + m_last_prefix_length = new_prefix_length; fflush(stdout); } @@ -2105,7 +2099,6 @@ namespace sat { l = diff1 < diff2 ? lit : ~lit; } } - // if (count > 1) std::cout << count << "\n"; TRACE("sat", tout << "selected: " << l << "\n";); return l; } @@ -2276,8 +2269,8 @@ namespace sat { if (m_search_mode == lookahead_mode::searching) { m_stats.m_propagations++; TRACE("sat", tout << "removing free var v" << l.var() << "\n";); - if (l.var() > m_freevars.max_var()) std::cout << "bigger than max-var: " << l << " " << " " << m_freevars.max_var() << "\n"; - if (!m_freevars.contains(l.var())) std::cout << "does not contain: " << l << " eliminated: " << m_s.was_eliminated(l.var()) << "\n"; + if (l.var() > m_freevars.max_var()) IF_VERBOSE(0, verbose_stream() << "bigger than max-var: " << l << " " << " " << m_freevars.max_var() << "\n";); + if (!m_freevars.contains(l.var())) IF_VERBOSE(0, verbose_stream() << "does not contain: " << l << " eliminated: " << m_s.was_eliminated(l.var()) << "\n";); if (m_freevars.contains(l.var())) { m_freevars.remove(l.var()); } validate_assign(l); } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index c64f265c0..be6070014 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -194,8 +194,10 @@ namespace sat { #endif double m_lookahead_reward; // metric associated with current lookahead1 literal. literal_vector m_wstack; // windofall stack that is populated in lookahead1 mode + unsigned m_last_prefix_length; uint64 m_prefix; // where we are in search tree svector m_vprefix; // var: prefix where variable participates in propagation + unsigned m_rating_throttle; // throttle to recompute rating indexed_uint_set m_freevars; lookahead_mode m_search_mode; // mode of search stats m_stats; @@ -507,7 +509,9 @@ namespace sat { m_drat(s), m_num_tc1(0), m_level(2), - m_prefix(0) { + m_last_prefix_length(0), + m_prefix(0), + m_rating_throttle(0) { m_s.rlimit().push_child(&m_rlimit); init_config(); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index fd8de1ad3..53e8e12dc 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -597,6 +597,7 @@ namespace sat { clause * const * begin_learned() const { return m_learned.begin(); } clause * const * end_learned() const { return m_learned.end(); } clause_vector const& learned() const { return m_learned; } + clause_vector const& clauses() const { return m_clauses; } void collect_bin_clauses(svector & r, bool learned, bool learned_only = false) const; // ----------------------- diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 1fbabcf13..7c3c9643e 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -17,27 +17,6 @@ Notes: --*/ -/* -#include "solver.h" -#include "tactical.h" -#include "sat_solver.h" -#include "ba_solver.h" -#include "tactic2solver.h" -#include "aig_tactic.h" -#include "propagate_values_tactic.h" -#include "max_bv_sharing_tactic.h" -#include "card2bv_tactic.h" -#include "bit_blaster_tactic.h" -#include "simplify_tactic.h" -#include "goal2sat.h" -#include "ast_pp.h" -#include "model_smt2_pp.h" -#include "filter_model_converter.h" -#include "bit_blaster_model_converter.h" -#include "ast_translation.h" -#include "ast_util.h" -#include "propagate_values_tactic.h" -*/ #include "solver/solver.h" #include "tactic/tactical.h" @@ -133,17 +112,6 @@ public: if (m_mc0.get()) result->m_mc0 = m_mc0->translate(tr); result->m_internalized = m_internalized; result->m_internalized_converted = m_internalized_converted; -#if 0 - static unsigned file_no = 0; - #pragma omp critical (print_sat) - { - ++file_no; - std::ostringstream ostrm; - ostrm << "s" << file_no << ".txt"; - std::ofstream ous(ostrm.str()); - result->m_solver.display(ous); - } -#endif return result; } @@ -660,9 +628,9 @@ private: } sat::literal_vector value; sat::literal_set premises; - for (unsigned i = 0; i < bvars.size(); ++i) { + for (sat::bool_var bv : bvars) { unsigned index; - if (bool_var2conseq.find(bvars[i], index)) { + if (bool_var2conseq.find(bv, index)) { value.push_back(lconseq[index][0]); for (unsigned j = 1; j < lconseq[index].size(); ++j) { premises.insert(lconseq[index][j]); @@ -754,10 +722,8 @@ private: } void extract_asm2dep(dep2asm_t const& dep2asm, u_map& asm2dep) { - dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); - for (; it != end; ++it) { - expr* e = it->m_key; - asm2dep.insert(it->m_value.index(), e); + for (auto const& kv : dep2asm) { + asm2dep.insert(kv.m_value.index(), kv.m_key); } } @@ -777,9 +743,9 @@ private: ); m_core.reset(); - for (unsigned i = 0; i < core.size(); ++i) { + for (sat::literal c : core) { expr* e = 0; - VERIFY(asm2dep.find(core[i].index(), e)); + VERIFY(asm2dep.find(c.index(), e)); if (asm2fml.contains(e)) { e = asm2fml.find(e); } @@ -789,11 +755,10 @@ private: void check_assumptions(dep2asm_t& dep2asm) { sat::model const & ll_m = m_solver.get_model(); - dep2asm_t::iterator it = dep2asm.begin(), end = dep2asm.end(); - for (; it != end; ++it) { - sat::literal lit = it->m_value; + for (auto const& kv : dep2asm) { + sat::literal lit = kv.m_value; if (sat::value_at(lit, ll_m) != l_true) { - IF_VERBOSE(0, verbose_stream() << mk_pp(it->m_key, m) << " does not evaluate to true\n"; + IF_VERBOSE(0, verbose_stream() << mk_pp(kv.m_key, m) << " does not evaluate to true\n"; verbose_stream() << m_asms << "\n"; m_solver.display_assignment(verbose_stream()); m_solver.display(verbose_stream());); diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp index 26f3448d3..d8827fe66 100644 --- a/src/sat/tactic/atom2bool_var.cpp +++ b/src/sat/tactic/atom2bool_var.cpp @@ -16,19 +16,18 @@ Author: Notes: --*/ -#include "sat/tactic/atom2bool_var.h" -#include "ast/ast_smt2_pp.h" + #include "util/ref_util.h" +#include "ast/ast_smt2_pp.h" #include "tactic/goal.h" +#include "sat/tactic/atom2bool_var.h" void atom2bool_var::mk_inv(expr_ref_vector & lit2expr) const { - obj_map::iterator it = m_mapping.begin(); - obj_map::iterator end = m_mapping.end(); - for (; it != end; ++it) { - sat::literal l(static_cast(it->m_value), false); - lit2expr.set(l.index(), it->m_key); + for (auto const& kv : m_mapping) { + sat::literal l(static_cast(kv.m_value), false); + lit2expr.set(l.index(), kv.m_key); l.neg(); - lit2expr.set(l.index(), m().mk_not(it->m_key)); + lit2expr.set(l.index(), m().mk_not(kv.m_key)); } } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index fc061a2e7..75561ed86 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -26,19 +26,19 @@ Author: Notes: --*/ -#include "sat/tactic/goal2sat.h" -#include "ast/ast_smt2_pp.h" #include "util/ref_util.h" #include "util/cooperate.h" -#include "tactic/filter_model_converter.h" -#include "model/model_evaluator.h" -#include "ast/for_each_expr.h" -#include "model/model_v2_pp.h" -#include "tactic/tactic.h" +#include "ast/ast_smt2_pp.h" #include "ast/ast_pp.h" -#include "sat/ba_solver.h" #include "ast/pb_decl_plugin.h" #include "ast/ast_util.h" +#include "ast/for_each_expr.h" +#include "sat/tactic/goal2sat.h" +#include "sat/ba_solver.h" +#include "model/model_evaluator.h" +#include "model/model_v2_pp.h" +#include "tactic/tactic.h" +#include "tactic/filter_model_converter.h" #include struct goal2sat::imp { @@ -412,15 +412,7 @@ struct goal2sat::imp { for (unsigned i = 0; i < num_args; ++i) { sat::literal lit(m_result_stack[sz - num_args + i]); if (!m_solver.is_external(lit.var())) { -#if 1 m_solver.set_external(lit.var()); -#else - sat::bool_var w = m_solver.mk_var(true); - sat::literal lit2(w, false); - mk_clause(lit, ~lit2); - mk_clause(~lit, lit2); - lit = lit2; -#endif } lits.push_back(lit); } @@ -473,9 +465,9 @@ struct goal2sat::imp { k.neg(); svector wlits; convert_pb_args(t, wlits); - for (unsigned i = 0; i < wlits.size(); ++i) { - wlits[i].second.neg(); - k += rational(wlits[i].first); + for (wliteral& wl : wlits) { + wl.second.neg(); + k += rational(wl.first); } check_unsigned(k); unsigned sz = m_result_stack.size(); @@ -502,9 +494,9 @@ struct goal2sat::imp { sat::bool_var v2 = root ? sat::null_bool_var : m_solver.mk_var(true); m_ext->add_pb_ge(v1, wlits, k.get_unsigned()); k.neg(); - for (unsigned i = 0; i < wlits.size(); ++i) { - wlits[i].second.neg(); - k += rational(wlits[i].first); + for (wliteral& wl : wlits) { + wl.second.neg(); + k += rational(wl.first); } check_unsigned(k); m_ext->add_pb_ge(v2, wlits, k.get_unsigned()); @@ -547,8 +539,8 @@ struct goal2sat::imp { sat::literal_vector lits; unsigned sz = m_result_stack.size(); convert_pb_args(t->get_num_args(), lits); - for (unsigned i = 0; i < lits.size(); ++i) { - lits[i].neg(); + for (sat::literal& l : lits) { + l.neg(); } if (root) { m_result_stack.reset(); @@ -570,8 +562,8 @@ struct goal2sat::imp { sat::bool_var v1 = root ? sat::null_bool_var : m_solver.mk_var(true); sat::bool_var v2 = root ? sat::null_bool_var : m_solver.mk_var(true); m_ext->add_at_least(v1, lits, k.get_unsigned()); - for (unsigned i = 0; i < lits.size(); ++i) { - lits[i].neg(); + for (sat::literal& l : lits) { + l.neg(); } m_ext->add_at_least(v2, lits, lits.size() - k.get_unsigned()); if (root) { @@ -782,8 +774,7 @@ struct goal2sat::imp { fmls.reset(); m.linearize(g.dep(idx), deps); fmls.push_back(f); - for (unsigned i = 0; i < deps.size(); ++i) { - expr * d = deps[i]; + for (expr * d : deps) { expr * d1 = d; SASSERT(m.is_bool(d)); bool sign = m.is_not(d, d1); @@ -935,10 +926,8 @@ struct sat2goal::imp { // create a SAT model using md sat::model sat_md; - unsigned sz = m_var2expr.size(); expr_ref val(m()); - for (sat::bool_var v = 0; v < sz; v++) { - expr * atom = m_var2expr.get(v); + for (expr * atom : m_var2expr) { ev(atom, val); if (m().is_true(val)) sat_md.push_back(l_true); @@ -952,7 +941,7 @@ struct sat2goal::imp { m_mc(sat_md); // register value of non-auxiliary boolean variables back into md - sz = m_var2expr.size(); + unsigned sz = m_var2expr.size(); for (sat::bool_var v = 0; v < sz; v++) { expr * atom = m_var2expr.get(v); if (is_uninterp_const(atom)) { @@ -973,9 +962,8 @@ struct sat2goal::imp { virtual model_converter * translate(ast_translation & translator) { sat_model_converter * res = alloc(sat_model_converter, translator.to()); res->m_fmc = static_cast(m_fmc->translate(translator)); - unsigned sz = m_var2expr.size(); - for (unsigned i = 0; i < sz; i++) - res->m_var2expr.push_back(translator(m_var2expr.get(i))); + for (expr* e : m_var2expr) + res->m_var2expr.push_back(translator(e)); return res; } @@ -1056,9 +1044,9 @@ struct sat2goal::imp { pb_util pb(m); ptr_buffer lits; vector coeffs; - for (unsigned i = 0; i < p.size(); ++i) { - lits.push_back(lit2expr(p[i].second)); - coeffs.push_back(rational(p[i].first)); + for (auto const& wl : p) { + lits.push_back(lit2expr(wl.second)); + coeffs.push_back(rational(wl.first)); } rational k(p.k()); expr_ref fml(pb.mk_ge(p.size(), coeffs.c_ptr(), lits.c_ptr(), k), m); @@ -1072,8 +1060,8 @@ struct sat2goal::imp { void assert_card(goal& r, sat::ba_solver::card const& c) { pb_util pb(m); ptr_buffer lits; - for (unsigned i = 0; i < c.size(); ++i) { - lits.push_back(lit2expr(c[i])); + for (sat::literal l : c) { + lits.push_back(lit2expr(l)); } expr_ref fml(pb.mk_at_most_k(c.size(), lits.c_ptr(), c.k()), m); @@ -1085,8 +1073,8 @@ struct sat2goal::imp { void assert_xor(goal & r, sat::ba_solver::xor const& x) { ptr_buffer lits; - for (unsigned i = 0; i < x.size(); ++i) { - lits.push_back(lit2expr(x[i])); + for (sat::literal l : x) { + lits.push_back(lit2expr(l)); } expr_ref fml(m.mk_xor(x.size(), lits.c_ptr()), m); @@ -1096,16 +1084,16 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_clauses(sat::solver const & s, sat::clause * const * begin, sat::clause * const * end, goal & r, bool asserted) { + void assert_clauses(sat::solver const & s, sat::clause_vector const& clauses, goal & r, bool asserted) { ptr_buffer lits; - for (sat::clause * const * it = begin; it != end; it++) { + for (sat::clause* cp : clauses) { checkpoint(); lits.reset(); - sat::clause const & c = *(*it); + sat::clause const & c = *cp; unsigned sz = c.size(); if (asserted || m_learned || c.glue() <= s.get_config().m_gc_small_lbd) { - for (unsigned i = 0; i < sz; i++) { - lits.push_back(lit2expr(c[i])); + for (sat::literal l : c) { + lits.push_back(lit2expr(l)); } r.assert_expr(m.mk_or(lits.size(), lits.c_ptr())); } @@ -1141,15 +1129,13 @@ struct sat2goal::imp { // collect binary clauses svector bin_clauses; s.collect_bin_clauses(bin_clauses, m_learned); - svector::iterator it = bin_clauses.begin(); - svector::iterator end = bin_clauses.end(); - for (; it != end; ++it) { + for (sat::solver::bin_clause const& bc : bin_clauses) { checkpoint(); - r.assert_expr(m.mk_or(lit2expr(it->first), lit2expr(it->second))); + r.assert_expr(m.mk_or(lit2expr(bc.first), lit2expr(bc.second))); } // collect clauses - assert_clauses(s, s.begin_clauses(), s.end_clauses(), r, true); - assert_clauses(s, s.begin_learned(), s.end_learned(), r, false); + assert_clauses(s, s.clauses(), r, true); + assert_clauses(s, s.learned(), r, false); sat::ba_solver* ext = get_ba_solver(s); if (ext) { @@ -1220,13 +1206,11 @@ struct sat2goal::imp { // collect learned binary clauses svector bin_clauses; s.collect_bin_clauses(bin_clauses, true, true); - svector::iterator it = bin_clauses.begin(); - svector::iterator end = bin_clauses.end(); - for (; it != end; ++it) { + for (sat::solver::bin_clause const& bc : bin_clauses) { checkpoint(); lits.reset(); - lits.push_back(it->first); - lits.push_back(it->second); + lits.push_back(bc.first); + lits.push_back(bc.second); add_clause(lits, lemmas); } // collect clauses From 260c27d58a856d8ab794f393022576e43f40fa4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Sep 2017 01:56:12 -0700 Subject: [PATCH 0241/1283] fix python parsing API Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index b99a78c71..9e03c5f99 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8058,7 +8058,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) - return _to_expr_ref(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), 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. @@ -8068,7 +8068,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) - return _to_expr_ref(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + return AstVector(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) def Interpolant(a,ctx=None): """Create an interpolation operator. From e507a6ccd1113067366d9fd2726ba3bcef80e3f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Sep 2017 09:06:17 -0700 Subject: [PATCH 0242/1283] adding incremental cubing from API Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 27 ++++++++ src/api/z3_api.h | 10 +++ src/muz/spacer/spacer_itp_solver.h | 2 + src/muz/spacer/spacer_virtual_solver.h | 4 +- src/opt/maxres.cpp | 16 +++-- src/opt/opt_solver.h | 1 + src/sat/sat_lookahead.cpp | 62 +++++++++++++++++++ src/sat/sat_lookahead.h | 19 ++++++ src/sat/sat_solver.cpp | 14 +++++ src/sat/sat_solver.h | 5 +- src/sat/sat_solver/inc_sat_solver.cpp | 19 ++++++ src/smt/smt_solver.cpp | 5 ++ src/solver/combined_solver.cpp | 4 ++ src/solver/solver.h | 6 ++ src/solver/tactic2solver.cpp | 6 +- .../portfolio/bounded_int2bv_solver.cpp | 1 + src/tactic/portfolio/enum2bv_solver.cpp | 1 + src/tactic/portfolio/pb2bv_solver.cpp | 1 + 18 files changed, 194 insertions(+), 9 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index e7c5c979d..73ba5e082 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -495,6 +495,33 @@ extern "C" { Z3_CATCH_RETURN(Z3_L_UNDEF); } + Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s) { + Z3_TRY; + LOG_Z3_solver_cube(c, s); + ast_manager& m = mk_c(c)->m(); + expr_ref result(m); + unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); + unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); + bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); + cancel_eh eh(mk_c(c)->m().limit()); + api::context::set_interruptable si(*(mk_c(c)), eh); + { + scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); + scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); + try { + result = to_solver_ref(s)->cube(); + } + catch (z3_exception & ex) { + mk_c(c)->handle_exception(ex); + return 0; + } + } + mk_c(c)->save_ast_trail(result); + RETURN_Z3(of_ast(result)); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, Z3_solver s, Z3_ast_vector assumptions, diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 77ea9bed0..8615cd7cb 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6183,6 +6183,16 @@ extern "C" { Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, Z3_solver s, Z3_ast_vector assumptions, Z3_ast_vector candidates); + /** + \brief extract a next cube for a solver. The last cube is the constant \c true or \c false. + The number of (non-constant) cubes is by default 1. For the sat solver cubing is controlled + using parameters sat.lookahead.cube.cutoff and sat.lookahead.cube.fraction. + + def_API('Z3_solver_cube', AST, (_in(CONTEXT), _in(SOLVER))) + */ + + Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s); + /** \brief retrieve lemmas from solver state. Lemmas are auxiliary unit literals, diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 07764745f..ec878af00 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -119,6 +119,8 @@ public: {NOT_IMPLEMENTED_YET();} virtual void assert_lemma(expr* e) { NOT_IMPLEMENTED_YET(); } virtual expr_ref lookahead(const expr_ref_vector &,const expr_ref_vector &) { return expr_ref(m.mk_true(), m); } + virtual expr_ref cube() { return expr_ref(m.mk_true(), m); } + virtual void push(); virtual void pop(unsigned n); diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 2c338ad2e..fafaf2020 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -93,10 +93,10 @@ public: virtual smt_params &fparams(); virtual void reset(); - virtual void set_progress_callback(progress_callback *callback) - {UNREACHABLE();} + virtual void set_progress_callback(progress_callback *callback) {UNREACHABLE();} virtual void assert_lemma(expr* e) { NOT_IMPLEMENTED_YET(); } virtual expr_ref lookahead(const expr_ref_vector &,const expr_ref_vector &) { return expr_ref(m.mk_true(), m); } + virtual expr_ref cube() { return expr_ref(m.mk_true(), m); } virtual solver *translate(ast_manager &m, params_ref const &p); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d77eff902..52972fef1 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -368,6 +368,7 @@ public: m_lower = m_upper; return l_true; } + split_core(core); cores.push_back(core); if (core.size() >= m_max_core_size) { break; @@ -493,7 +494,7 @@ public: expr_ref fml(m); remove_core(core); SASSERT(!core.empty()); - rational w = split_core(core); + rational w = core_weight(core); TRACE("opt", display_vec(tout << "minimized core: ", core);); IF_VERBOSE(10, display_vec(verbose_stream() << "core: ", core);); max_resolve(core, w); @@ -558,19 +559,24 @@ public: return m_asm2weight.find(e); } - rational split_core(exprs const& core) { + rational core_weight(exprs const& core) { if (core.empty()) return rational(0); // find the minimal weight: rational w = get_weight(core[0]); for (unsigned i = 1; i < core.size(); ++i) { w = std::min(w, get_weight(core[i])); } + return w; + } + + rational split_core(exprs const& core) { + rational w = core_weight(core); // add fresh soft clauses for weights that are above w. - for (unsigned i = 0; i < core.size(); ++i) { - rational w2 = get_weight(core[i]); + for (expr* e : core) { + rational w2 = get_weight(e); if (w2 > w) { rational w3 = w2 - w; - new_assumption(core[i], w3); + new_assumption(e, w3); } } return w; diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 5455e2b11..a3107057a 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -109,6 +109,7 @@ namespace opt { virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { return expr_ref(m.mk_true(), m); } + virtual expr_ref cube() { return expr_ref(m.mk_true(), m); } void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index f3a0c9d9c..f4bfb14e2 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2353,6 +2353,16 @@ namespace sat { } lbool lookahead::cube() { +#if 0 + literal_vector lits; + while (true) { + lbool result = cube(lits); + if (lits.empty() || result != l_undef) { + return result; + } + display_cube(std::cout, cube); + } +#endif lbool result = l_false; init_search(); m_model.reset(); @@ -2394,6 +2404,58 @@ namespace sat { } } + lbool lookahead::cube(literal_vector& lits) { + lits.reset(); + bool is_first = (m_cube_state.m_lit == null_literal); + if (is_first) { + init_search(); + m_model.reset(); + } + scoped_level _sl(*this, c_fixed_truth); + m_search_mode = lookahead_mode::searching; + unsigned depth = 0; + + if (!is_first) { + goto pick_up_work; + } + + while (true) { + TRACE("sat", display(tout);); + inc_istamp(); + checkpoint(); + m_cube_state.m_lit = choose(); + if (inconsistent()) { + TRACE("sat", tout << "inconsistent: " << cube << "\n";); + m_cube_state.m_freevars_threshold = m_freevars.size(); + if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return m_cube_state.m_result; + continue; + } + if (m_cube_state.m_lit == null_literal) { + return l_true; + } + depth = m_cube_state.m_cube.size(); + if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || + (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) { + m_cube_state.m_freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); + m_cube_state.m_result = l_undef; + set_conflict(); + if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return m_cube_state.m_result; + lits.append(m_cube_state.m_cube); + return l_undef; + } + pick_up_work: + TRACE("sat", tout << "choose: " << m_cube_state.m_lit << " cube: " << m_cube_state.m_cube << "\n";); + ++m_stats.m_decisions; + push(m_cube_state.m_lit, c_fixed_truth); + m_cube_state.m_cube.push_back(m_cube_state.m_lit); + m_cube_state.m_is_decision.push_back(true); + SASSERT(inconsistent() || !is_unsat()); + } + lbool result = m_cube_state.m_result; + m_cube_state.reset(); + return result; + } + void lookahead::init_model() { m_model.reset(); for (unsigned i = 0; i < m_num_vars; ++i) { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index be6070014..3fcf3e18b 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -139,6 +139,22 @@ namespace sat { }; #endif + struct cube_state { + svector m_is_decision; + literal_vector m_cube; + literal m_lit; + lbool m_result; + double m_freevars_threshold; + cube_state() { reset(); } + void reset() { + m_is_decision.reset(); + m_cube.reset(); + m_lit = null_literal; + m_result = l_false; + m_freevars_threshold = 0; + } + }; + config m_config; double m_delta_trigger; @@ -202,6 +218,7 @@ namespace sat { lookahead_mode m_search_mode; // mode of search stats m_stats; model m_model; + cube_state m_cube_state; // --------------------------------------- // truth values @@ -537,6 +554,8 @@ namespace sat { */ lbool cube(); + lbool cube(literal_vector& lits); + literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** \brief simplify set of clauses by extracting units from a lookahead at base level. diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e15cddbd6..cbbb6b13d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -63,6 +63,7 @@ namespace sat { m_next_simplify = 0; m_num_checkpoints = 0; m_simplifications = 0; + m_cuber = nullptr; } solver::~solver() { @@ -836,6 +837,19 @@ namespace sat { return lh.select_lookahead(assumptions, vars); } + lbool solver::cube(literal_vector& lits) { + if (!m_cuber) { + m_cuber = alloc(lookahead, *this); + } + lbool result = m_cuber->cube(lits); + if (result == l_false) { + dealloc(m_cuber); + m_cuber = nullptr; + } + return result; + } + + // ----------------------- // // Search diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 53e8e12dc..c115b71bb 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -156,6 +156,8 @@ namespace sat { unsigned m_par_num_vars; bool m_par_syncing_clauses; + class lookahead* m_cuber; + statistics m_aux_stats; void del_clauses(clause * const * begin, clause * const * end); @@ -362,6 +364,7 @@ namespace sat { char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); + lbool cube(literal_vector& lits); protected: unsigned m_conflicts_since_init; @@ -404,7 +407,7 @@ namespace sat { void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); lbool lookahead_search(); - lbool lookahead_cube(); + lbool lookahead_cube(); lbool do_local_search(unsigned num_lits, literal const* lits); lbool do_ccc(); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 7c3c9643e..da8f22e86 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -344,6 +344,25 @@ public: expr_ref result(lit2expr[l.index()].get(), m); return result; } + virtual expr_ref cube() { + sat::literal_vector lits; + lbool result = m_solver.cube(lits); + if (result == l_false || lits.empty()) { + return expr_ref(m.mk_false(), m); + } + if (result == l_true) { + return expr_ref(m.mk_true(), m); + } + expr_ref_vector fmls(m); + expr_ref_vector lit2expr(m); + lit2expr.resize(m_solver.num_vars() * 2); + m_map.mk_inv(lit2expr); + for (sat::literal l : lits) { + fmls.push_back(lit2expr[l.index()].get()); + } + return mk_and(fmls); + } + virtual void get_lemmas(expr_ref_vector & lemmas) { if (!m_internalized) return; sat2goal s2g; diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index ae7bd95fd..9f411b0e6 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -229,6 +229,11 @@ namespace smt { return expr_ref(m.mk_true(), m); } + virtual expr_ref cube() { + ast_manager& m = get_manager(); + return expr_ref(m.mk_true(), m); + } + struct collect_fds_proc { ast_manager & m; func_decl_set & m_fds; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index a556570f8..a67fd724d 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -284,6 +284,10 @@ public: return m_solver1->lookahead(assumptions, candidates); } + virtual expr_ref cube() { + return m_solver1->cube(); + } + virtual expr * get_assumption(unsigned idx) const { unsigned c1 = m_solver1->get_num_assumptions(); if (idx < c1) return m_solver1->get_assumption(idx); diff --git a/src/solver/solver.h b/src/solver/solver.h index c44b049b1..abd9b01f2 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -184,6 +184,12 @@ public: virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) = 0; + /** + \brief extract a lookahead candidates for branching. + */ + + virtual expr_ref cube() = 0; + /** \brief extract learned lemmas. */ diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 722326dfe..b165304bf 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -79,9 +79,13 @@ public: virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { ast_manager& m = get_manager(); - std::cout << "tactic2solver\n"; return expr_ref(m.mk_true(), m); } + virtual expr_ref cube() { + ast_manager& m = get_manager(); + return expr_ref(m.mk_true(), m); + } + }; ast_manager& tactic2solver::get_manager() const { return m_assertions.get_manager(); } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 9fcce9360..09791f7c9 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -163,6 +163,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(assumptions, candidates); } + virtual expr_ref cube() { return m_solver->cube(); } virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index a9e91bfe6..6288223fa 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -109,6 +109,7 @@ public: virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { return m_solver->lookahead(assumptions, candidates); } + virtual expr_ref cube() { return m_solver->cube(); } virtual void get_lemmas(expr_ref_vector & lemmas) { m_solver->get_lemmas(lemmas); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 80e135ca7..d76260e0d 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -99,6 +99,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(assumptions, candidates); } + virtual expr_ref cube() { return m_solver->cube(); } virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { From a625301a4175abb521ef46ff125efb208a943c98 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Sep 2017 15:05:10 -0700 Subject: [PATCH 0243/1283] expose incremental cubing over API Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 1 + src/api/python/z3/z3.py | 23 +++++ src/sat/sat_lookahead.cpp | 84 ++++++------------- src/sat/sat_lookahead.h | 6 +- src/sat/sat_params.pyg | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 8 ++ src/tactic/portfolio/CMakeLists.txt | 1 + .../portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/fd_solver.h | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 10 files changed, 63 insertions(+), 68 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 24f22d8ee..520ba3d91 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2735,6 +2735,7 @@ def get_header_files_for_components(component_src_dirs): def mk_install_tactic_cpp(cnames, path): component_src_dirs = [] for cname in cnames: + print("Component %s" % cname) c = get_component(cname) component_src_dirs.append(c.src_dir) h_files_full_path = get_header_files_for_components(component_src_dirs) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 9e03c5f99..94221b3db 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6294,10 +6294,33 @@ class Solver(Z3PPObject): candidates = _cs return _to_expr_ref(Z3_solver_lookahead(self.ctx.ref(), self.solver, candidates), self.ctx) + def cube(self): + """Get set of cubes""" + rounds = 0 + while True: + r = _to_expr_ref(Z3_solver_cube(self.ctx.ref(), self.solver), self.ctx) + if (is_false(r)): + if (rounds == 0): + yield r + return + if (is_true(r)): + yield r + return + rounds += 1 + yield r + def proof(self): """Return a proof for the last `check()`. Proof construction must be enabled.""" return _to_expr_ref(Z3_solver_get_proof(self.ctx.ref(), self.solver), self.ctx) + def from_file(self, filename): + """Parse assertions from a file""" + self.add([f for f in parse_smt2_file(filename)]) + + def from_string(self, s): + """Parse assertions from a string""" + self.add([f for f in parse_smt2_string(s)]) + def assertions(self): """Return an AST vector containing all added constraints. diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index f4bfb14e2..a68367f6b 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -657,7 +657,6 @@ namespace sat { } // case watched::EXTERNAL: } - // std::cout << "tsum: " << tsum << "\n"; } #endif // std::cout << "sum: " << sum << " afactor " << afactor << " sqfactor " << sqfactor << " tsum " << tsum << "\n"; @@ -2221,7 +2220,7 @@ namespace sat { SASSERT(dl_no_overflow(base)); unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); scoped_level _sl(*this, dl_truth); - IF_VERBOSE(2, verbose_stream() << "double: " << l << "\n";); + IF_VERBOSE(2, verbose_stream() << "double: " << l << " depth: " << m_trail_lim.size() << "\n";); init_lookahead_reward(); assign(l); propagate(); @@ -2353,63 +2352,24 @@ namespace sat { } lbool lookahead::cube() { -#if 0 literal_vector lits; while (true) { lbool result = cube(lits); if (lits.empty() || result != l_undef) { return result; } - display_cube(std::cout, cube); - } -#endif - lbool result = l_false; - init_search(); - m_model.reset(); - scoped_level _sl(*this, c_fixed_truth); - literal_vector cube; - svector is_decision; - m_search_mode = lookahead_mode::searching; - double freevars_threshold = 0; - while (true) { - TRACE("sat", display(tout);); - inc_istamp(); - checkpoint(); - literal l = choose(); - if (inconsistent()) { - TRACE("sat", tout << "inconsistent: " << cube << "\n";); - freevars_threshold = m_freevars.size(); - if (!backtrack(cube, is_decision)) return result; - continue; - } - if (l == null_literal) { - return l_true; - } - unsigned depth = cube.size(); - if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || - (m_config.m_cube_cutoff == 0 && m_freevars.size() < freevars_threshold)) { - display_cube(std::cout, cube); - freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); - result = l_undef; - set_conflict(); - if (!backtrack(cube, is_decision)) return result; - continue; - } - TRACE("sat", tout << "choose: " << l << " cube: " << cube << "\n";); - ++m_stats.m_decisions; - push(l, c_fixed_truth); - cube.push_back(l); - is_decision.push_back(true); - SASSERT(inconsistent() || !is_unsat()); + display_cube(std::cout, lits); } + return l_undef; } lbool lookahead::cube(literal_vector& lits) { lits.reset(); - bool is_first = (m_cube_state.m_lit == null_literal); + bool is_first = m_cube_state.m_first; if (is_first) { init_search(); m_model.reset(); + m_cube_state.m_first = false; } scoped_level _sl(*this, c_fixed_truth); m_search_mode = lookahead_mode::searching; @@ -2421,39 +2381,43 @@ namespace sat { while (true) { TRACE("sat", display(tout);); - inc_istamp(); checkpoint(); - m_cube_state.m_lit = choose(); + inc_istamp(); if (inconsistent()) { - TRACE("sat", tout << "inconsistent: " << cube << "\n";); + TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); m_cube_state.m_freevars_threshold = m_freevars.size(); - if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return m_cube_state.m_result; + if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; continue; } - if (m_cube_state.m_lit == null_literal) { - return l_true; - } + pick_up_work: depth = m_cube_state.m_cube.size(); if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) { m_cube_state.m_freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); - m_cube_state.m_result = l_undef; set_conflict(); - if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return m_cube_state.m_result; lits.append(m_cube_state.m_cube); + backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision); return l_undef; } - pick_up_work: - TRACE("sat", tout << "choose: " << m_cube_state.m_lit << " cube: " << m_cube_state.m_cube << "\n";); + literal lit = choose(); + if (inconsistent()) { + TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); + m_cube_state.m_freevars_threshold = m_freevars.size(); + if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; + continue; + } + if (lit == null_literal) { + return l_true; + } + TRACE("sat", tout << "choose: " << lit << " cube: " << m_cube_state.m_cube << "\n";); ++m_stats.m_decisions; - push(m_cube_state.m_lit, c_fixed_truth); - m_cube_state.m_cube.push_back(m_cube_state.m_lit); + push(lit, c_fixed_truth); + m_cube_state.m_cube.push_back(lit); m_cube_state.m_is_decision.push_back(true); SASSERT(inconsistent() || !is_unsat()); } - lbool result = m_cube_state.m_result; m_cube_state.reset(); - return result; + return l_undef; } void lookahead::init_model() { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 3fcf3e18b..87247611c 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -140,17 +140,15 @@ namespace sat { #endif struct cube_state { + bool m_first; svector m_is_decision; literal_vector m_cube; - literal m_lit; - lbool m_result; double m_freevars_threshold; cube_state() { reset(); } void reset() { + m_first = true; m_is_decision.reset(); m_cube.reset(); - m_lit = null_literal; - m_result = l_false; m_freevars_threshold = 0; } }; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 67659aa24..01708b775 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -40,7 +40,7 @@ def_module_params('sat', ('lookahead.cube.cutoff', UINT, 0, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), - ('lookahead.reward', SYMBOL, 'heuleu', 'select lookahead heuristic: ternary, hs (Heule Schur), heuleu (Heule Unit), or unit'), + ('lookahead.reward', SYMBOL, 'heuleu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), or unit'), ('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving'), ('dimacs.inprocess.display', BOOL, False, 'display SAT instance in DIMACS format if unsolved after inprocess.max inprocessing passes'))) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index da8f22e86..908e56da8 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -345,6 +345,14 @@ public: return result; } virtual expr_ref cube() { + if (!m_internalized) { + dep2asm_t dep2asm; + m_model = 0; + lbool r = internalize_formulas(); + if (r != l_true) return expr_ref(m.mk_true(), m); + m_internalized = true; + } + convert_internalized(); sat::literal_vector lits; lbool result = m_solver.cube(lits); if (result == l_false || lits.empty()) { diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index a8a9b2bba..570db8f6a 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -18,4 +18,5 @@ z3_add_component(portfolio ufbv_tactic TACTIC_HEADERS default_tactic.h + fd_solver.h ) diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 09791f7c9..ec83766a0 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -163,7 +163,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(assumptions, candidates); } - virtual expr_ref cube() { return m_solver->cube(); } + virtual expr_ref cube() { flush_assertions(); return m_solver->cube(); } virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/portfolio/fd_solver.h index 6726f42aa..b54ba74f4 100644 --- a/src/tactic/portfolio/fd_solver.h +++ b/src/tactic/portfolio/fd_solver.h @@ -29,7 +29,7 @@ solver * mk_fd_solver(ast_manager & m, params_ref const & p); tactic * mk_fd_tactic(ast_manager & m, params_ref const & p); /* - ADD_TACTIC("qffd", "builtin strategy for solving QF_FD problems.", "mk_fd_tactic(m, p)") + ADD_TACTIC("qffd", "builtin strategy for solving QF_FD problems.", "mk_fd_tactic(m, p)") */ #endif diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index d76260e0d..ee4b14178 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -99,7 +99,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(assumptions, candidates); } - virtual expr_ref cube() { return m_solver->cube(); } + virtual expr_ref cube() { flush_assertions(); return m_solver->cube(); } virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { From 01879ed1ed9ce1ae88b7fd77f10470b736bf6ebe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Sep 2017 15:25:36 -0700 Subject: [PATCH 0244/1283] remove NEW_CLAUSE variant Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 458 +------------------------------------- src/sat/sat_lookahead.h | 39 +--- 2 files changed, 2 insertions(+), 495 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index a68367f6b..92ba7b808 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -312,7 +312,6 @@ namespace sat { } bool lookahead::is_unsat() const { -#ifdef NEW_CLAUSE bool all_false = true; bool first = true; // check if there is a clause whose literals are false. @@ -344,20 +343,7 @@ namespace sat { return true; } } - } - -#else - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause& c = *m_clauses[i]; - unsigned j = 0; - for (; j < c.size() && is_false(c[j]); ++j) {} - if (j == c.size()) { - TRACE("sat", tout << c << "\n";); - TRACE("sat", display(tout);); - return true; - } - } -#endif + } return false; } @@ -380,7 +366,6 @@ namespace sat { } } } -#ifdef NEW_CLAUSE bool no_true = true; bool first = true; // check if there is a clause whose literals are false. @@ -412,16 +397,6 @@ namespace sat { } } } -#else - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause& c = *m_clauses[i]; - unsigned j = 0; - for (; j < c.size() && !is_true(c[j]); ++j) {} - if (j == c.size()) { - return false; - } - } -#endif return true; } @@ -476,7 +451,6 @@ namespace sat { for (literal lit : m_binary[l.index()]) { if (is_undef(lit)) sum += literal_occs(lit) / 4.0; } -#ifdef NEW_CLAUSE unsigned sz = m_ternary_count[(~l).index()]; for (binary const& b : m_ternary[(~l).index()]) { if (sz-- == 0) break; @@ -496,40 +470,6 @@ namespace sat { unsigned len = m_nary_literals[idx]; sum += pow(0.5, len) * to_add / len; } -#else - watch_list& wlist = m_watches[l.index()]; - for (auto & w : wlist) { - switch (w.get_kind()) { - case watched::BINARY: - UNREACHABLE(); - break; - case watched::TERNARY: { - literal l1 = w.get_literal1(); - literal l2 = w.get_literal2(); - if (is_undef(l1) && is_undef(l2)) { - sum += (literal_occs(l1) + literal_occs(l2)) / 8.0; - } - break; - } - case watched::CLAUSE: { - clause_offset cls_off = w.get_clause_offset(); - clause & c = *(m_cls_allocator.get_clause(cls_off)); - unsigned sz = 0; - double to_add = 0; - for (literal lit : c) { - if (is_undef(lit) && lit != ~l) { - to_add += literal_occs(lit); - ++sz; - } - } - sum += pow(0.5, sz) * to_add / sz; - break; - } - default: - break; - } - } -#endif return sum; } @@ -546,45 +486,12 @@ namespace sat { for (literal lit : m_binary[l.index()]) { if (is_undef(lit)) sum += 0.5; } -#ifdef NEW_CLAUSE sum += 0.25 * m_ternary_count[(~l).index()]; unsigned sz = m_nary_count[(~l).index()]; for (unsigned cls_idx : m_nary[(~l).index()]) { if (sz-- == 0) break; sum += pow(0.5, m_nary_literals[cls_idx]); } -#else - watch_list& wlist = m_watches[l.index()]; - for (auto & w : wlist) { - switch (w.get_kind()) { - case watched::BINARY: - UNREACHABLE(); - break; - case watched::TERNARY: { - literal l1 = w.get_literal1(); - literal l2 = w.get_literal2(); - if (is_undef(l1) && is_undef(l2)) { - sum += 0.25; - } - break; - } - case watched::CLAUSE: { - clause_offset cls_off = w.get_clause_offset(); - clause & c = *(m_cls_allocator.get_clause(cls_off)); - unsigned sz = 0; - for (literal lit : c) { - if (is_undef(lit) && lit != ~l) { - ++sz; - } - } - sum += pow(0.5, sz); - break; - } - default: - break; - } - } -#endif return sum; } @@ -621,44 +528,11 @@ namespace sat { if (is_undef(lit)) sum += h[lit.index()]; // if (m_freevars.contains(lit.var())) sum += h[lit.index()]; } -#ifdef NEW_CLAUSE unsigned sz = m_ternary_count[(~l).index()]; for (binary const& b : m_ternary[(~l).index()]) { if (sz-- == 0) break; tsum += h[b.m_u.index()] * h[b.m_v.index()]; } -#else - watch_list& wlist = m_watches[l.index()]; - for (auto & w : wlist) { - switch (w.get_kind()) { - case watched::BINARY: - UNREACHABLE(); - break; - case watched::TERNARY: { - literal l1 = w.get_literal1(); - literal l2 = w.get_literal2(); - // if (is_undef(l1) && is_undef(l2)) - tsum += h[l1.index()] * h[l2.index()]; - break; - } - case watched::CLAUSE: { - clause_offset cls_off = w.get_clause_offset(); - clause & c = *(m_cls_allocator.get_clause(cls_off)); - // approximation compared to ternary clause case: - // we pick two other literals from the clause. - if (c[0] == ~l) { - tsum += h[c[1].index()] * h[c[2].index()]; - } - else { - SASSERT(c[1] == ~l); - tsum += h[c[0].index()] * h[c[2].index()]; - } - break; - } - // case watched::EXTERNAL: - } - } -#endif // std::cout << "sum: " << sum << " afactor " << afactor << " sqfactor " << sqfactor << " tsum " << tsum << "\n"; sum = (double)(0.1 + afactor*sum + sqfactor*tsum); // std::cout << "sum: " << sum << " max score " << m_config.m_max_score << "\n"; @@ -979,58 +853,6 @@ namespace sat { } -#ifndef NEW_CLAUSE - - // ------------------------------------ - // clause management - - void lookahead::attach_clause(clause& c) { - if (c.size() == 3) { - attach_ternary(c[0], c[1], c[2]); - } - else { - literal block_lit = c[c.size() >> 2]; - clause_offset cls_off = m_cls_allocator.get_offset(&c); - m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); - m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); - SASSERT(is_undef(c[0])); - SASSERT(is_undef(c[1])); - } - } - - void lookahead::detach_clause(clause& c) { - clause_offset cls_off = m_cls_allocator.get_offset(&c); - m_retired_clauses.push_back(&c); - erase_clause_watch(get_wlist(~c[0]), cls_off); - erase_clause_watch(get_wlist(~c[1]), cls_off); - } - - void lookahead::del_clauses() { - for (clause * c : m_clauses) { - m_cls_allocator.del_clause(c); - } - } - - void lookahead::detach_ternary(literal l1, literal l2, literal l3) { - ++m_stats.m_del_ternary; - m_retired_ternary.push_back(ternary(l1, l2, l3)); - // implicitly erased: erase_ternary_watch(get_wlist(~l1), l2, l3); - erase_ternary_watch(get_wlist(~l2), l1, l3); - erase_ternary_watch(get_wlist(~l3), l1, l2); - } - - void lookahead::attach_ternary(ternary const& t) { - attach_ternary(t.m_u, t.m_v, t.m_w); - } - - void lookahead::attach_ternary(literal l1, literal l2, literal l3) { - ++m_stats.m_add_ternary; - TRACE("sat", tout << l1 << " " << l2 << " " << l3 << "\n";); - m_watches[(~l1).index()].push_back(watched(l2, l3)); - m_watches[(~l2).index()].push_back(watched(l1, l3)); - m_watches[(~l3).index()].push_back(watched(l1, l2)); - } -#endif // ------------------------------------ // initialization @@ -1040,10 +862,6 @@ namespace sat { m_binary.push_back(literal_vector()); m_watches.push_back(watch_list()); m_watches.push_back(watch_list()); -#ifndef NEW_CLAUSE - m_full_watches.push_back(clause_vector()); - m_full_watches.push_back(clause_vector()); -#else m_ternary.push_back(svector()); m_ternary.push_back(svector()); m_ternary_count.push_back(0); @@ -1052,7 +870,6 @@ namespace sat { m_nary.push_back(unsigned_vector()); m_nary_count.push_back(0); m_nary_count.push_back(0); -#endif m_bstamp.push_back(0); m_bstamp.push_back(0); m_stamp.push_back(0); @@ -1121,7 +938,6 @@ namespace sat { void lookahead::copy_clauses(clause_vector const& clauses, bool learned) { // copy clauses -#ifdef NEW_CLAUSE for (clause* cp : clauses) { clause& c = *cp; if (c.was_removed()) continue; @@ -1141,27 +957,6 @@ namespace sat { } if (m_s.m_config.m_drat) m_drat.add(c, false); } -#else - for (clause* cp : clauses) { - clause& c = *cp; - if (c.was_removed()) continue; - // enable when there is a non-ternary reward system. - bool was_eliminated = false; - for (unsigned i = 0; !was_eliminated && i < c.size(); ++i) { - was_eliminated = m_s.was_eliminated(c[i].var()); - } - if (was_eliminated) continue; - - clause* c1 = m_cls_allocator.mk_clause(c.size(), c.begin(), false); - m_clauses.push_back(c1); - attach_clause(*c1); - for (unsigned i = 0; i < c.size(); ++i) { - m_full_watches[(~c[i]).index()].push_back(c1); - SASSERT(!m_s.was_eliminated(c[i].var())); - } - if (m_s.m_config.m_drat) m_drat.add(c, false); - } -#endif } // ------------------------------------ @@ -1173,10 +968,6 @@ namespace sat { m_binary_trail_lim.push_back(m_binary_trail.size()); m_trail_lim.push_back(m_trail.size()); m_num_tc1_lim.push_back(m_num_tc1); -#ifndef NEW_CLAUSE - m_retired_clause_lim.push_back(m_retired_clauses.size()); - m_retired_ternary_lim.push_back(m_retired_ternary.size()); -#endif m_qhead_lim.push_back(m_qhead); scoped_level _sl(*this, level); m_assumptions.push_back(~lit); @@ -1204,25 +995,6 @@ namespace sat { m_num_tc1 = m_num_tc1_lim.back(); m_num_tc1_lim.pop_back(); -#ifndef NEW_CLAUSE - m_trail.shrink(old_sz); // reset assignment. - m_trail_lim.pop_back(); - - // unretire clauses - old_sz = m_retired_clause_lim.back(); - for (unsigned i = old_sz; i < m_retired_clauses.size(); ++i) { - attach_clause(*m_retired_clauses[i]); - } - m_retired_clauses.resize(old_sz); - m_retired_clause_lim.pop_back(); - - old_sz = m_retired_ternary_lim.back(); - for (unsigned i = old_sz; i < m_retired_ternary.size(); ++i) { - attach_ternary(m_retired_ternary[i]); - } - m_retired_ternary.shrink(old_sz); - m_retired_ternary_lim.pop_back(); -#else for (unsigned i = m_qhead; i > m_qhead_lim.back(); ) { --i; restore_ternary(m_trail[i]); @@ -1232,8 +1004,6 @@ namespace sat { m_trail.shrink(old_sz); // reset assignment. m_trail_lim.pop_back(); -#endif - // remove local binary clauses old_sz = m_binary_trail_lim.back(); @@ -1306,18 +1076,6 @@ namespace sat { m_wstack.reset(); } -#ifndef NEW_CLAUSE - clause const& lookahead::get_clause(watch_list::iterator it) const { - clause_offset cls_off = it->get_clause_offset(); - return *(m_cls_allocator.get_clause(cls_off)); - } - - bool lookahead::is_nary_propagation(clause const& c, literal l) const { - bool r = c.size() > 2 && ((c[0] == l && is_false(c[1])) || (c[1] == l && is_false(c[0]))); - DEBUG_CODE(if (r) for (unsigned j = 2; j < c.size(); ++j) SASSERT(is_false(c[j]));); - return r; - } -#endif // // The current version is modeled after CDCL SAT solving data-structures. @@ -1336,7 +1094,6 @@ namespace sat { double operator()(literal l) { return lh.literal_occs(l); } }; -#ifdef NEW_CLAUSE // Ternary clause managagement: void lookahead::add_ternary(literal u, literal v, literal w) { @@ -1510,38 +1267,6 @@ namespace sat { m_nary_literals.push_back(null_literal.index()); } -#if 0 - // split large clauses into smaller ones to avoid overhead during propagation. - - void lookahead::add_clause(unsigned sz, literal const * lits) { - if (sz > 6) { - bool_var v = m_s.mk_var(false); - ++m_num_vars; - init_var(v); - literal lit(v, false); - unsigned mid = sz / 2; - literal_vector lits1(mid, lits); - lits1.push_back(lit); - add_clause(lits1.size(), lits1.c_ptr()); - lit.neg(); - literal_vector lits2(sz - mid, lits + mid); - lits2.push_back(lit); - add_clause(lits2.size(), lits2.c_ptr()); - } - else { - unsigned idx = m_nary_literals.size(); - m_nary_literals.push_back(sz); - for (unsigned i = 0; i < sz; ++i) { - literal l = lits[i]; - m_nary_literals.push_back(l.index()); - m_nary_count[l.index()]++; - m_nary[l.index()].push_back(idx); - SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size()); - } - m_nary_literals.push_back(null_literal.index()); - } - } -#endif void lookahead::propagate_clauses_searching(literal l) { // clauses where l is negative @@ -1747,162 +1472,6 @@ namespace sat { } -#else - void lookahead::propagate_clauses(literal l) { - SASSERT(is_true(l)); - if (inconsistent()) return; - watch_list& wlist = m_watches[l.index()]; - watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); - for (; it != end && !inconsistent(); ++it) { - switch (it->get_kind()) { - case watched::BINARY: - UNREACHABLE(); - break; - case watched::TERNARY: { - literal l1 = it->get_literal1(); - literal l2 = it->get_literal2(); - bool skip = false; - if (is_fixed(l1)) { - if (is_false(l1)) { - if (is_undef(l2)) { - propagated(l2); - } - else if (is_false(l2)) { - TRACE("sat", tout << l1 << " " << l2 << " " << l << "\n";); - set_conflict(); - } - } - else { - // retire this clause - } - } - else if (is_fixed(l2)) { - if (is_false(l2)) { - propagated(l1); - } - else { - // retire this clause - } - } - else { - switch (m_search_mode) { - case lookahead_mode::searching: - detach_ternary(~l, l1, l2); - try_add_binary(l1, l2); - skip = true; - break; - case lookahead_mode::lookahead1: - update_binary_clause_reward(l1, l2); - break; - case lookahead2: - break; - } - } - if (!skip) { - *it2 = *it; - it2++; - } - break; - } - case watched::CLAUSE: { - if (is_true(it->get_blocked_literal())) { - *it2 = *it; - ++it2; - break; - } - clause_offset cls_off = it->get_clause_offset(); - clause & c = *(m_cls_allocator.get_clause(cls_off)); - if (c[0] == ~l) - std::swap(c[0], c[1]); - if (is_true(c[0])) { - it->set_blocked_literal(c[0]); - *it2 = *it; - it2++; - break; - } - literal * l_it = c.begin() + 2; - literal * l_end = c.end(); - bool found = false; - for (; l_it != l_end && !found; ++l_it) { - if (!is_false(*l_it)) { - found = true; - c[1] = *l_it; - *l_it = ~l; - m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); - TRACE("sat_verbose", tout << "move watch from " << l << " to " << c[1] << " for clause " << c << "\n";); - } - } - if (found) { - found = false; - for (; l_it != l_end && !found; ++l_it) { - found = !is_false(*l_it); - } - // normal clause was converted to a binary clause. - if (!found && is_undef(c[1]) && is_undef(c[0])) { - TRACE("sat", tout << "got binary " << l << ": " << c << "\n";); - switch (m_search_mode) { - case lookahead_mode::searching: - detach_clause(c); - try_add_binary(c[0], c[1]); - break; - case lookahead_mode::lookahead1: - update_binary_clause_reward(c[0], c[1]); - break; - case lookahead_mode::lookahead2: - break; - } - } - else if (found && m_search_mode == lookahead_mode::lookahead1) { - update_nary_clause_reward(c); - } - break; - } - if (is_false(c[0])) { - TRACE("sat", tout << "conflict " << l << ": " << c << "\n";); - set_conflict(); - *it2 = *it; - ++it2; - } - else { - TRACE("sat", tout << "propagating " << l << ": " << c << "\n";); - SASSERT(is_undef(c[0])); - DEBUG_CODE(for (unsigned i = 2; i < c.size(); ++i) { - SASSERT(is_false(c[i])); - }); - *it2 = *it; - it2++; - propagated(c[0]); - } - break; - } - case watched::EXT_CONSTRAINT: { - SASSERT(m_s.m_ext); - bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); - if (m_search_mode == lookahead_mode::lookahead1 && !m_inconsistent) { - lookahead_literal_occs_fun literal_occs_fn(*this); - m_lookahead_reward += m_s.m_ext->get_reward(l, it->get_ext_constraint_idx(), literal_occs_fn); - } - if (m_inconsistent) { - if (!keep) ++it; - set_conflict(); - } - else if (keep) { - *it2 = *it; - it2++; - } - break; - } - default: - UNREACHABLE(); - break; - } - } - for (; it != end; ++it, ++it2) { - *it2 = *it; - } - wlist.set_end(it2); - } -#endif void lookahead::update_binary_clause_reward(literal l1, literal l2) { SASSERT(!is_false(l1)); @@ -1958,22 +1527,9 @@ namespace sat { // Sum_{ clause C that contains ~l } 1 double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); -#ifdef NEW_CLAUSE unsigned_vector const& nclauses = m_nary[(~l).index()]; result += m_nary_count[(~l).index()]; result += m_ternary_count[(~l).index()]; -#else - for (clause const* c : m_full_watches[l.index()]) { - bool has_true = false; - for (literal l : *c) { - has_true = is_true(l); - if (has_true) break; - } - if (!has_true) { - result += 1.0; - } - } -#endif return result; } @@ -2167,11 +1723,9 @@ namespace sat { ++m_stats.m_autarky_propagations; IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); -#ifdef NEW_CLAUSE TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] << " " << (!m_binary[l.index()].empty() || m_nary_count[l.index()] != 0) << "\n";); -#endif reset_lookahead_reward(); assign(l); propagate(); @@ -2457,7 +2011,6 @@ namespace sat { } std::ostream& lookahead::display_clauses(std::ostream& out) const { -#ifdef NEW_CLAUSE bool first = true; for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { @@ -2487,11 +2040,6 @@ namespace sat { } } -#else - for (unsigned i = 0; i < m_clauses.size(); ++i) { - out << *m_clauses[i] << "\n"; - } -#endif return out; } @@ -2719,11 +2267,7 @@ namespace sat { void lookahead::collect_statistics(statistics& st) const { st.update("lh bool var", m_vprefix.size()); -#ifndef NEW_CLAUSE - st.update("lh clauses", m_clauses.size()); -#else // TBD: keep count of ternary and >3-ary clauses. -#endif st.update("lh add binary", m_stats.m_add_binary); st.update("lh del binary", m_stats.m_del_binary); st.update("lh add ternary", m_stats.m_add_ternary); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 87247611c..9a50dceed 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,7 +20,6 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ -#define NEW_CLAUSE #include "sat_elim_eqs.h" @@ -125,19 +124,10 @@ namespace sat { void reset() { memset(this, 0, sizeof(*this)); } }; -#ifndef NEW_CLAUSE - struct ternary { - ternary(literal u, literal v, literal w): m_u(u), m_v(v), m_w(w) {} - literal m_u, m_v, m_w; - }; -#endif - -#ifdef NEW_CLAUSE struct binary { binary(literal u, literal v): m_u(u), m_v(v) {} literal m_u, m_v; }; -#endif struct cube_state { bool m_first; @@ -165,7 +155,6 @@ namespace sat { unsigned_vector m_binary_trail; // trail of added binary clauses unsigned_vector m_binary_trail_lim; -#ifdef NEW_CLAUSE // specialized clause managemet uses ternary clauses and dedicated clause data-structure. // this replaces m_clauses below vector> m_ternary; // lit |-> vector of ternary clauses @@ -176,21 +165,10 @@ namespace sat { unsigned_vector m_nary_literals; // the actual literals, clauses start at offset clause_id, // the first entry is the current length, clauses are separated by a null_literal - -#endif - unsigned m_num_tc1; unsigned_vector m_num_tc1_lim; unsigned m_qhead; // propagation queue head unsigned_vector m_qhead_lim; -#ifndef NEW_CLAUSE - clause_vector m_clauses; // non-binary clauses - clause_vector m_retired_clauses; // clauses that were removed during search - unsigned_vector m_retired_clause_lim; - svector m_retired_ternary; // ternary removed during search - unsigned_vector m_retired_ternary_lim; - clause_allocator m_cls_allocator; -#endif bool m_inconsistent; unsigned_vector m_bstamp; // literal: timestamp for binary implication vector > m_H; // literal: fitness score @@ -203,9 +181,6 @@ namespace sat { const unsigned c_fixed_truth = UINT_MAX - 1; vector m_watches; // literal: watch structure svector m_lits; // literal: attributes. -#ifndef NEW_CLAUSE - vector m_full_watches; // literal: full watch list, used to ensure that autarky reduction is sound -#endif double m_lookahead_reward; // metric associated with current lookahead1 literal. literal_vector m_wstack; // windofall stack that is populated in lookahead1 mode unsigned m_last_prefix_length; @@ -420,18 +395,9 @@ namespace sat { // ------------------------------------ // clause management -#ifndef NEW_CLAUSE - void attach_clause(clause& c); - void detach_clause(clause& c); - void del_clauses(); - void detach_ternary(literal l1, literal l2, literal l3); - void attach_ternary(ternary const& t); - void attach_ternary(literal l1, literal l2, literal l3); -#endif watch_list& get_wlist(literal l) { return m_watches[l.index()]; } watch_list const& get_wlist(literal l) const { return m_watches[l.index()]; } -#ifdef NEW_CLAUSE // new clause managment: void add_ternary(literal u, literal v, literal w); void propagate_ternary(literal l); @@ -446,7 +412,7 @@ namespace sat { void restore_clauses(literal l); void remove_clause(literal l, unsigned clause_idx); void remove_clause_at(literal l, unsigned clause_idx); -#endif + // ------------------------------------ // initialization @@ -532,9 +498,6 @@ namespace sat { } ~lookahead() { -#ifndef NEW_CLAUSE - del_clauses(); -#endif m_s.rlimit().pop_child(); } From 705b1078461b4d4680ab4080fda9221a92b4846a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Sep 2017 20:05:46 -0700 Subject: [PATCH 0245/1283] fixed encoding for order constraints Signed-off-by: Nikolaj Bjorner --- src/sat/dimacs.cpp | 9 +++++++-- src/util/sorting_network.h | 15 ++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/sat/dimacs.cpp b/src/sat/dimacs.cpp index 512be5f4b..463418b23 100644 --- a/src/sat/dimacs.cpp +++ b/src/sat/dimacs.cpp @@ -24,10 +24,12 @@ Revision History: class stream_buffer { std::istream & m_stream; int m_val; + unsigned m_line; public: stream_buffer(std::istream & s): - m_stream(s) { + m_stream(s), + m_line(0) { m_val = m_stream.get(); } @@ -37,7 +39,10 @@ public: void operator ++() { m_val = m_stream.get(); + if (m_val == '\n') ++m_line; } + + unsigned line() const { return m_line; } }; template @@ -76,7 +81,7 @@ int parse_int(Buffer & in) { } if (*in < '0' || *in > '9') { - std::cerr << "(error, \"unexpected char: " << *in << "\")\n"; + std::cerr << "(error, \"unexpected char: " << *in << " line: " << in.line() << "\")\n"; exit(3); exit(ERR_PARSER); } diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 9a1d064d4..ade66403d 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -328,15 +328,15 @@ Notes: } void add_implies_and(literal l, literal_vector const& xs) { - for (unsigned j = 0; j < xs.size(); ++j) { - add_clause(ctx.mk_not(l), xs[j]); + 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 (unsigned j = 0; j < xs.size(); ++j) { - lits.push_back(ctx.mk_not(xs[j])); + for (literal const& x : xs) { + lits.push_back(ctx.mk_not(x)); } lits.push_back(l); add_clause(lits); @@ -513,8 +513,9 @@ Notes: add_clause(ctx.mk_not(r), ctx.mk_not(ys[i]), ctx.mk_not(xs[i + 1])); } - add_clause(ctx.mk_not(r), ys[n-2], xs[n-1]); - add_clause(ctx.mk_not(r), ctx.mk_not(ys[n-2]), ctx.mk_not(xs[n-1])); + if (is_eq) { + add_clause(ctx.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]); } @@ -583,7 +584,7 @@ Notes: } std::ostream& pp(std::ostream& out, literal_vector const& lits) { - for (unsigned i = 0; i < lits.size(); ++i) ctx.pp(out, lits[i]) << " "; + for (literal const& l : lits) ctx.pp(out, l) << " "; return out; } From da5c8c0667db1837cde48519098e1ec6779c78cd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Sep 2017 08:00:01 -0700 Subject: [PATCH 0246/1283] update pb rewriter to be non-full on assertions Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 000257f61..0fdee0700 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -623,6 +623,11 @@ struct pb2bv_rewriter::imp { } } + bool mk_app(expr* e, expr_ref& r) { + app* a; + return (is_app(e) && (a = to_app(e), mk_app(false, a->get_decl(), a->get_num_args(), a->get_args(), r))); + } + bool is_pb(expr* x, expr* y) { m_args.reset(); m_coeffs.reset(); @@ -817,6 +822,14 @@ struct pb2bv_rewriter::imp { void pb_num_system(bool f) { m_cfg.pb_num_system(f); } void pb_totalizer(bool f) { m_cfg.pb_totalizer(f); } void set_at_most1(sorting_network_encoding e) { m_cfg.set_at_most1(e); } + void rewrite(expr* e, expr_ref& r, proof_ref& p) { + expr_ref ee(e, m()); + if (m_cfg.m_r.mk_app(e, r)) { + ee = r; + // mp proof? + } + (*this)(ee, r, p); + } }; card_pb_rewriter m_rw; @@ -888,7 +901,8 @@ struct pb2bv_rewriter::imp { unsigned get_num_steps() const { return m_rw.get_num_steps(); } void cleanup() { m_rw.cleanup(); } void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { - m_rw(e, result, result_proof); + // m_rw(e, result, result_proof); + m_rw.rewrite(e, result, result_proof); } void push() { m_fresh_lim.push_back(m_fresh.size()); From d6327d69d2995eba70a47880517a6eb580836256 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Sep 2017 15:35:11 -0700 Subject: [PATCH 0247/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 55 ++++++++++++++++++++++++++-------------- src/sat/ba_solver.h | 1 + src/sat/sat_elim_eqs.cpp | 5 +--- src/sat/sat_solver.cpp | 6 ++--- 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index ffc431d0d..e8f97ce5e 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -349,6 +349,11 @@ namespace sat { unsigned true_val = 0, slack = 0, num_false = 0; for (unsigned i = 0; i < p.size(); ++i) { literal l = p.get_lit(i); + if (s().was_eliminated(l.var())) { + SASSERT(p.learned()); + remove_constraint(p); + return; + } switch (value(l)) { case l_true: true_val += p.get_coeff(i); break; case l_false: ++num_false; break; @@ -779,13 +784,13 @@ namespace sat { if (k == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); - s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + s().mk_clause(sz, lits.c_ptr(), p.learned()); remove_constraint(p); return; } if (all_units) { - literal_vector lits(p.literals()); + literal_vector lits(sz, p.literals().c_ptr()); add_at_least(p.lit(), lits, k, p.learned()); remove_constraint(p); return; @@ -1006,14 +1011,15 @@ namespace sat { else if (coeff0 < 0 && inc > 0) { inc_bound(coeff0 - std::min(0LL, coeff1)); } + int64 lbound = static_cast(m_bound); // reduce coefficient to be no larger than bound. - if (coeff1 > static_cast(m_bound)) { - m_coeffs[v] = m_bound; - } - else if (coeff1 < 0 && -coeff1 > static_cast(m_bound)) { - m_coeffs[v] = m_bound; + if (coeff1 > lbound) { + m_coeffs[v] = lbound; } + else if (coeff1 < 0 && -coeff1 > lbound) { + m_coeffs[v] = -lbound; + } } int64 ba_solver::get_coeff(bool_var v) const { @@ -1105,7 +1111,7 @@ namespace sat { } TRACE("sat_verbose", display(tout, m_A);); - TRACE("sat", tout << "process consequent: " << consequent << ":\n"; s().display_justification(tout, js) << "\n";); + TRACE("sat", tout << "process consequent: " << consequent << " : "; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); // DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); @@ -1206,7 +1212,7 @@ namespace sat { //SASSERT(validate_resolvent()); m_A = m_C;); - TRACE("sat", display(tout << "conflict:\n", m_A);); + TRACE("sat", display(tout << "conflict: ", m_A);); cut(); @@ -1230,7 +1236,7 @@ namespace sat { SASSERT(lvl(v) == m_conflict_lvl); s().reset_mark(v); --idx; - TRACE("sat", tout << "Unmark: v" << v << "\n";); + TRACE("sat_verbose", tout << "Unmark: v" << v << "\n";); --m_num_marks; js = s().m_justification[v]; offset = get_abs_coeff(v); @@ -1297,9 +1303,9 @@ namespace sat { active2pb(m_A); uint64 c = 0; for (uint64 c1 : m_A.m_coeffs) c += c1; - std::cout << "sum of coefficients: " << c << "\n"; - display(std::cout, m_A, true); - std::cout << "conflicting literal: " << s().m_not_l << "\n";); + verbose_stream() << "sum of coefficients: " << c << "\n"; + display(verbose_stream(), m_A, true); + verbose_stream() << "conflicting literal: " << s().m_not_l << "\n";); for (literal l : lits) { if (s().is_marked(l.var())) { @@ -1458,7 +1464,7 @@ namespace sat { if (level > 0 && !s().is_marked(v) && level == m_conflict_lvl) { s().mark(v); - TRACE("sat", tout << "Mark: v" << v << "\n";); + TRACE("sat_verbose", tout << "Mark: v" << v << "\n";); ++m_num_marks; if (_debug_conflict && _debug_consequent != null_literal && _debug_var2position[_debug_consequent.var()] < _debug_var2position[l.var()]) { std::cout << "antecedent " << l << " is above consequent in stack\n"; @@ -1516,6 +1522,7 @@ namespace sat { } void ba_solver::add_constraint(constraint* c) { + literal_vector lits(c->literals()); if (c->learned()) { m_learned.push_back(c); } @@ -2628,7 +2635,8 @@ namespace sat { // this could create duplicate literals for (unsigned i = 0; i < c.size(); ++i) { - c.set_lit(i, m_roots[c.get_lit(i).index()]); + literal lit = m_roots[c.get_lit(i).index()]; + c.set_lit(i, lit); } literal root = c.lit(); @@ -2782,9 +2790,7 @@ namespace sat { remove_constraint(c); break; } - if (!s().is_external(v)) { - s().set_external(v); - } + s().set_external(v); } } IF_VERBOSE(10, verbose_stream() << "non-external variables converted: " << ext << "\n";); @@ -2867,6 +2873,14 @@ namespace sat { m_constraint_removed = false; } + void ba_solver::ensure_external(constraint const& c) { + literal_vector lits(c.literals()); + for (literal l : lits) { + s().set_external(l.var()); + } + } + + void ba_solver::cleanup_constraints(ptr_vector& cs, bool learned) { ptr_vector::iterator it = cs.begin(); ptr_vector::iterator it2 = it; @@ -2877,6 +2891,7 @@ namespace sat { m_allocator.deallocate(c.obj_size(), &c); } else if (learned && !c.learned()) { + ensure_external(c); m_constraints.push_back(&c); } else { @@ -3598,7 +3613,9 @@ namespace sat { // produce asserting cardinality constraint literal_vector lits; - for (wliteral wl : m_wlits) lits.push_back(wl.second); + for (wliteral wl : m_wlits) { + lits.push_back(wl.second); + } constraint* c = add_at_least(null_literal, lits, k, true); if (c) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 9f9dded3d..88a81701a 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -285,6 +285,7 @@ namespace sat { void cleanup_clauses(); void cleanup_constraints(); void cleanup_constraints(ptr_vector& cs, bool learned); + void ensure_external(constraint const& c); void remove_constraint(constraint& c); // constraints diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index a71a7184a..8666218c6 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -182,10 +182,7 @@ namespace sat { void elim_eqs::save_elim(literal_vector const & roots, bool_var_vector const & to_elim) { model_converter & mc = m_solver.m_mc; - bool_var_vector::const_iterator it = to_elim.begin(); - bool_var_vector::const_iterator end = to_elim.end(); - for (; it != end; ++it) { - bool_var v = *it; + for (bool_var v : to_elim) { literal l(v, false); literal r = roots[v]; SASSERT(v != r.var()); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index cbbb6b13d..cc79e75ff 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -202,12 +202,12 @@ namespace sat { } void solver::set_non_external(bool_var v) { - m_external[v] = false; + m_external[v] = 0; } void solver::set_external(bool_var v) { - if (m_external[v]) return; - m_external[v] = true; + if (m_external[v] != 0) return; + m_external[v] = 1; if (!m_ext) return; From 133f3761727f7791a4aea3f46b9488d85036338a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Sep 2017 19:53:22 -0700 Subject: [PATCH 0248/1283] assertion fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 18 +++++++++++++----- src/sat/sat_lookahead.cpp | 2 +- src/util/memory_manager.cpp | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index e8f97ce5e..a4275f804 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -634,8 +634,9 @@ namespace sat { exit(0); return l_undef; } - - SASSERT(validate_watch(p)); + + validate_watch(p); + // SASSERT(validate_watch(p)); SASSERT(index < num_watch); unsigned index1 = index + 1; @@ -710,6 +711,8 @@ namespace sat { } } + validate_watch(p); + TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); BADLOG(verbose_stream() << "unwatch " << alit << " watch: " << p.num_watch() << " size: " << p.size() << " slack: " << p.slack() << " " << inconsistent() << "\n"); @@ -3428,7 +3431,9 @@ namespace sat { } bool ba_solver::validate_unit_propagation(pb const& p, literal alit) const { - if (p.lit() != null_literal && value(p.lit()) != l_true) return false; + if (p.lit() != null_literal && value(p.lit()) != l_true) { + return false; + } unsigned sum = 0; TRACE("sat", display(tout << "validate: " << alit << "\n", p, true);); @@ -3446,11 +3451,14 @@ namespace sat { unsigned sum = 0; // all elements of r are true, for (literal l : r) { - if (value(l) != l_true) return false; + if (value(l) != l_true) { + return false; + } } // the sum of elements not in r or alit add up to less than k. for (wliteral wl : p) { - if (wl.second != alit && !r.contains(~wl.second)) { + literal lit = wl.second; + if (lit != alit && value(lit) != l_false && !r.contains(~lit)) { sum += wl.first; } } diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 92ba7b808..596b9abe7 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1910,7 +1910,7 @@ namespace sat { while (true) { lbool result = cube(lits); if (lits.empty() || result != l_undef) { - return result; + return l_undef; } display_cube(std::cout, lits); } diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 08fada396..0b394b450 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -60,6 +60,7 @@ static void throw_out_of_memory() { if (g_exit_when_out_of_memory) { std::cerr << g_out_of_memory_msg << "\n"; + __assume(0); exit(ERR_MEMOUT); } else { From 4d911691181e5ccb236d14db879d6412e256a9d6 Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Fri, 6 Oct 2017 16:10:05 -0700 Subject: [PATCH 0249/1283] Cuber fixes. Added March_CU heuristics --- src/api/python/z3/z3.py | 2 +- src/sat/sat_config.cpp | 3 + src/sat/sat_config.h | 3 +- src/sat/sat_lookahead.cpp | 160 ++++++++++++++++++++++++++------------ src/sat/sat_lookahead.h | 17 +++- src/sat/sat_params.pyg | 4 +- 6 files changed, 130 insertions(+), 59 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 94221b3db..4379e3fe1 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -120,7 +120,7 @@ def _get_args(args): try: if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)): return args[0] - elif len(args) == 1 and isinstance(args[0], set): + elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)): return [arg for arg in args[0]] else: return args diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 49a146489..c77774283 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -100,6 +100,9 @@ namespace sat { else if (p.lookahead_reward() == symbol("unit")) { m_lookahead_reward = unit_literal_reward; } + else if (p.lookahead_reward() == symbol("march_cu")) { + m_lookahead_reward = march_cu_reward; + } else { throw sat_param_exception("invalid reward type supplied: accepted heuristics are 'ternary', 'heuleu', 'unit' or 'heule_schur'"); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index a7c8590fb..214a93f5d 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -61,7 +61,8 @@ namespace sat { ternary_reward, unit_literal_reward, heule_schur_reward, - heule_unit_reward + heule_unit_reward, + march_cu_reward }; struct config { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 596b9abe7..59149ec0f 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -217,7 +217,7 @@ namespace sat { bool lookahead::select(unsigned level) { init_pre_selection(level); unsigned level_cand = std::max(m_config.m_level_cand, m_freevars.size() / 50); - unsigned max_num_cand = level == 0 ? m_freevars.size() : level_cand / level; + unsigned max_num_cand = (level > 0 && m_config.m_preselect) ? level_cand / level : m_freevars.size(); max_num_cand = std::max(m_config.m_min_cutoff, max_num_cand); double sum = 0; @@ -251,30 +251,40 @@ namespace sat { } TRACE("sat", display_candidates(tout);); SASSERT(!m_candidates.empty()); - if (m_candidates.size() > max_num_cand) { - unsigned j = m_candidates.size()/2; - while (j > 0) { - --j; - sift_up(j); - } - while (true) { - m_candidates[0] = m_candidates.back(); - m_candidates.pop_back(); - if (m_candidates.size() == max_num_cand) break; - sift_up(0); - } + heap_sort(); + while (m_candidates.size() > max_num_cand) { + m_candidates.pop_back(); } SASSERT(!m_candidates.empty() && m_candidates.size() <= max_num_cand); TRACE("sat", display_candidates(tout);); return true; } - void lookahead::sift_up(unsigned j) { + void lookahead::heap_sort() { + if (m_candidates.size() > 1) { + heapify(); + for (unsigned i = m_candidates.size() - 1; i > 0; --i) { + candidate c = m_candidates[i]; + m_candidates[i] = m_candidates[0]; + m_candidates[0] = c; + sift_down(0, i); + } + } + } + + void lookahead::heapify() { + unsigned i = 1 + (m_candidates.size() - 2) / 2; + while(i > 0) { + sift_down(--i, m_candidates.size()); + } + } + + void lookahead::sift_down(unsigned j, unsigned sz) { unsigned i = j; candidate c = m_candidates[j]; - for (unsigned k = 2*j + 1; k < m_candidates.size(); i = k, k = 2*k + 1) { - // pick largest parent - if (k + 1 < m_candidates.size() && m_candidates[k].m_rating < m_candidates[k+1].m_rating) { + for (unsigned k = 2 * j + 1; k < sz; i = k, k = 2 * k + 1) { + // pick smallest child + if (k + 1 < sz && m_candidates[k].m_rating > m_candidates[k + 1].m_rating) { ++k; } if (c.m_rating <= m_candidates[k].m_rating) break; @@ -432,6 +442,9 @@ namespace sat { case heule_unit_reward: heule_unit_scores(); break; + case march_cu_reward: + march_cu_scores(); + break; case unit_literal_reward: heule_schur_scores(); break; @@ -478,7 +491,7 @@ namespace sat { for (bool_var x : m_freevars) { literal l(x, false); m_rating[l.var()] = heule_unit_score(l) * heule_unit_score(~l); - } + } } double lookahead::heule_unit_score(literal l) { @@ -493,7 +506,23 @@ namespace sat { sum += pow(0.5, m_nary_literals[cls_idx]); } return sum; - } + } + + void lookahead::march_cu_scores() { + for (bool_var x : m_freevars) { + literal l(x, false); + double pos = march_cu_score(l), neg = march_cu_score(~l); + m_rating[l.var()] = 1024 * pos * neg + pos + neg + 1; + } + } + + double lookahead::march_cu_score(literal l) { + double sum = 1.0 + literal_big_occs(~l); + for (literal lit : m_binary[l.index()]) { + if (is_undef(lit)) sum += literal_big_occs(lit); + } + return sum; + } void lookahead::ensure_H(unsigned level) { while (m_H.size() <= level) { @@ -884,7 +913,7 @@ namespace sat { } void lookahead::init() { - m_delta_trigger = m_num_vars/10; + m_delta_trigger = 0.0; m_config.m_dl_success = 0.8; m_inconsistent = false; m_qhead = 0; @@ -1068,6 +1097,7 @@ namespace sat { m_lookahead_reward += num_units; break; case heule_unit_reward: + case march_cu_reward: case heule_schur_reward: break; default: @@ -1391,6 +1421,9 @@ namespace sat { case heule_unit_reward: m_lookahead_reward += pow(0.5, nonfixed); break; + case march_cu_reward: + m_lookahead_reward += 3.3 * pow(0.5, nonfixed - 2); + break; case ternary_reward: if (nonfixed == 2) { m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; @@ -1486,6 +1519,9 @@ namespace sat { case heule_unit_reward: m_lookahead_reward += 0.25; break; + case march_cu_reward: + m_lookahead_reward += 3.3; + break; case unit_literal_reward: break; } @@ -1516,6 +1552,9 @@ namespace sat { case heule_unit_reward: m_lookahead_reward += pow(0.5, sz); break; + case march_cu_reward: + m_lookahead_reward += 3.3 * pow(0.5, sz - 2); + break; case ternary_reward: m_lookahead_reward = (double)0.001; break; @@ -1525,10 +1564,18 @@ namespace sat { } // Sum_{ clause C that contains ~l } 1 + // FIXME: counts occurences of ~l; misleading double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); - unsigned_vector const& nclauses = m_nary[(~l).index()]; - result += m_nary_count[(~l).index()]; + //unsigned_vector const& nclauses = m_nary[(~l).index()]; + result += literal_big_occs(l); + return result; + } + + // Sum_{ clause C that contains ~l such that |C| > 2} 1 + // FIXME: counts occurences of ~l; misleading + double lookahead::literal_big_occs(literal l) { + double result = m_nary_count[(~l).index()]; result += m_ternary_count[(~l).index()]; return result; } @@ -1542,22 +1589,19 @@ namespace sat { } } - void lookahead::propagate() { while (!inconsistent() && m_qhead < m_trail.size()) { unsigned i = m_qhead; - unsigned sz = m_trail.size(); - for (; i < sz && !inconsistent(); ++i) { + for (; i < m_trail.size() && !inconsistent(); ++i) { literal l = m_trail[i]; TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); propagate_binary(l); } - while (m_qhead < sz && !inconsistent()) { + while (m_qhead < m_trail.size() && !inconsistent()) { propagate_clauses(m_trail[m_qhead++]); } - SASSERT(m_qhead == sz || (inconsistent() && m_qhead < sz)); + SASSERT(m_qhead == m_trail.size() || (inconsistent() && m_qhead < m_trail.size())); } - TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } @@ -1566,12 +1610,15 @@ namespace sat { TRACE("sat", display_lookahead(tout); ); unsigned base = 2; bool change = true; - bool first = true; + literal last_changed = null_literal; while (change && !inconsistent()) { change = false; for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { checkpoint(); literal lit = m_lookahead[i].m_lit; + if (lit == last_changed) { + break; + } if (is_fixed_at(lit, c_fixed_truth)) continue; unsigned level = base + m_lookahead[i].m_offset; if (m_stamp[lit.var()] >= level) { @@ -1584,7 +1631,7 @@ namespace sat { unsigned old_trail_sz = m_trail.size(); reset_lookahead_reward(lit); push_lookahead1(lit, level); - if (!first) do_double(lit, base); + do_double(lit, base); bool unsat = inconsistent(); unsigned num_units = m_trail.size() - old_trail_sz; pop_lookahead1(lit, num_units); @@ -1595,6 +1642,7 @@ namespace sat { propagate(); init_lookahead_reward(); change = true; + last_changed = lit; } else { update_lookahead_reward(lit, level); @@ -1604,13 +1652,9 @@ namespace sat { if (c_fixed_truth - 2 * m_lookahead.size() < base) { break; } - if (first && !change) { - first = false; - change = true; - } reset_lookahead_reward(); init_lookahead_reward(); - // base += 2 * m_lookahead.size(); + base += 2 * m_lookahead.size(); } reset_lookahead_reward(); TRACE("sat", display_lookahead(tout); ); @@ -1664,6 +1708,7 @@ namespace sat { case ternary_reward: return l + r + (1 << 10) * l * r; case heule_schur_reward: return l * r; case heule_unit_reward: return l * r; + case march_cu_reward: return 1024 * (1024 * l * r + l + r); case unit_literal_reward: return l * r; default: UNREACHABLE(); return l * r; } @@ -1753,14 +1798,16 @@ namespace sat { } } - void lookahead::do_double(literal l, unsigned& base) { - if (!inconsistent() && scope_lvl() > 1 && dl_enabled(l)) { + void lookahead::do_double(literal l, unsigned& base) { + if (!inconsistent() && dl_enabled(l)) { if (get_lookahead_reward(l) > m_delta_trigger) { if (dl_no_overflow(base)) { ++m_stats.m_double_lookahead_rounds; double_look(l, base); - m_delta_trigger = get_lookahead_reward(l); - dl_disable(l); + if (!inconsistent()) { + m_delta_trigger = get_lookahead_reward(l); + dl_disable(l); + } } } else { @@ -1772,21 +1819,30 @@ namespace sat { void lookahead::double_look(literal l, unsigned& base) { SASSERT(!inconsistent()); SASSERT(dl_no_overflow(base)); - unsigned dl_truth = base + 2 * m_lookahead.size() * (m_config.m_dl_max_iterations + 1); + base += m_lookahead.size(); + unsigned dl_truth = base + m_lookahead.size() * m_config.m_dl_max_iterations; scoped_level _sl(*this, dl_truth); IF_VERBOSE(2, verbose_stream() << "double: " << l << " depth: " << m_trail_lim.size() << "\n";); init_lookahead_reward(); assign(l); propagate(); bool change = true; + literal last_changed = null_literal; unsigned num_iterations = 0; while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { change = false; num_iterations++; - base += 2*m_lookahead.size(); for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; - if (is_fixed_at(lit, dl_truth)) continue; + if (lit == last_changed) { + SASSERT(change == false); + break; + } + if (is_fixed_at(lit, dl_truth)) continue; + if (base + m_lookahead.size() + m_lookahead[i].m_offset >= dl_truth) { + change = false; + break; + } if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { TRACE("sat", tout << "unit: " << ~lit << "\n";); ++m_stats.m_double_lookahead_propagations; @@ -1795,10 +1851,12 @@ namespace sat { assign(~lit); propagate(); change = true; + last_changed = lit; init_lookahead_reward(); } } - SASSERT(dl_truth - 2 * m_lookahead.size() > base); + base += 2 * m_lookahead.size(); + SASSERT(dl_truth >= base); } reset_lookahead_reward(); SASSERT(m_level == dl_truth); @@ -1838,14 +1896,13 @@ namespace sat { void lookahead::propagated(literal l) { assign(l); - switch (m_search_mode) { - case lookahead_mode::searching: - break; - case lookahead_mode::lookahead1: + for (unsigned i = m_trail.size() - 1; i < m_trail.size() && !inconsistent(); ++i) { + literal l = m_trail[i]; + TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); + propagate_binary(l); + } + if (m_search_mode == lookahead_mode::lookahead1) { m_wstack.push_back(l); - break; - case lookahead_mode::lookahead2: - break; } } @@ -1953,10 +2010,11 @@ namespace sat { backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision); return l_undef; } + int prev_nfreevars = m_freevars.size(); literal lit = choose(); if (inconsistent()) { TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); - m_cube_state.m_freevars_threshold = m_freevars.size(); + m_cube_state.m_freevars_threshold = prev_nfreevars; if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; continue; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 9a50dceed..4011996bb 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -73,6 +73,7 @@ namespace sat { double m_max_score; unsigned m_max_hlevel; unsigned m_min_cutoff; + bool m_preselect; unsigned m_level_cand; double m_delta_rho; unsigned m_dl_max_iterations; @@ -86,9 +87,10 @@ namespace sat { m_alpha = 3.5; m_max_score = 20.0; m_min_cutoff = 30; + m_preselect = false; m_level_cand = 600; - m_delta_rho = (double)0.9995; - m_dl_max_iterations = 32; + m_delta_rho = (double)0.99995; + m_dl_max_iterations = 2; m_tc1_limit = 10000000; m_reward_type = ternary_reward; m_cube_cutoff = 0; @@ -289,7 +291,10 @@ namespace sat { double get_rating(bool_var v) const { return m_rating[v]; } double get_rating(literal l) const { return get_rating(l.var()); } bool select(unsigned level); - void sift_up(unsigned j); + //void sift_up(unsigned j); + void heap_sort(); + void heapify(); + void sift_down(unsigned j, unsigned sz); double init_candidates(unsigned level, bool newbies); std::ostream& display_candidates(std::ostream& out) const; bool is_unsat() const; @@ -301,6 +306,8 @@ namespace sat { double heule_schur_score(literal l); void heule_unit_scores(); double heule_unit_score(literal l); + void march_cu_scores(); + double march_cu_score(literal l); double l_score(literal l, svector const& h, double factor, double sqfactor, double afactor); // ------------------------------------ @@ -460,6 +467,7 @@ namespace sat { void do_double(literal l, unsigned& base); void double_look(literal l, unsigned& base); void set_conflict() { TRACE("sat", tout << "conflict\n";); m_inconsistent = true; } + //void set_conflict() { TRACE("sat", tout << "conflict\n";); printf("CONFLICT\n"); m_inconsistent = true; } bool inconsistent() { return m_inconsistent; } unsigned scope_lvl() const { return m_trail_lim.size(); } @@ -544,7 +552,8 @@ namespace sat { void collect_statistics(statistics& st) const; - double literal_occs(literal l); + double literal_occs(literal l); + double literal_big_occs(literal l); }; } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 01708b775..296c75180 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -31,7 +31,7 @@ def_module_params('sat', ('drat.check', BOOL, False, 'build up internal proof and check'), ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), - ('xor.solver', BOOL, False, 'use xor solver'), + ('xor.solver', BOOL, False, 'use xor solver'), ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), @@ -40,7 +40,7 @@ def_module_params('sat', ('lookahead.cube.cutoff', UINT, 0, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), - ('lookahead.reward', SYMBOL, 'heuleu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), or unit'), + ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'), ('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving'), ('dimacs.inprocess.display', BOOL, False, 'display SAT instance in DIMACS format if unsolved after inprocess.max inprocessing passes'))) From 6b88446ee804c8336aa11026344d46f2e0aee87e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Oct 2017 19:02:06 +0100 Subject: [PATCH 0250/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 448 +++++++++++++++++++++++++++---------- src/sat/ba_solver.h | 14 +- src/sat/sat_drat.cpp | 3 +- src/util/sorting_network.h | 6 +- 4 files changed, 349 insertions(+), 122 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index a4275f804..0de5af885 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -221,7 +221,7 @@ namespace sat { if (c.lit() != null_literal && c.lit().sign() == is_true) { c.negate(); } - TRACE("sat", display(tout << "init watch: ", c, true);); + TRACE("ba", display(tout << "init watch: ", c, true);); SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); // put the non-false literals into the head. @@ -293,7 +293,7 @@ namespace sat { void ba_solver::set_conflict(constraint& c, literal lit) { m_stats.m_num_conflicts++; - TRACE("sat", display(tout, c, true); ); + TRACE("ba", display(tout, c, true); ); SASSERT(validate_conflict(c)); if (c.is_xor() && value(lit) == l_true) lit.neg(); SASSERT(value(lit) == l_false); @@ -312,7 +312,7 @@ namespace sat { default: m_stats.m_num_propagations++; m_num_propagations_since_pop++; - //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); + //TRACE("ba", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); SASSERT(validate_unit_propagation(c, lit)); if (get_config().m_drat) { svector ps; @@ -333,25 +333,26 @@ namespace sat { void ba_solver::simplify(pb_base& p) { SASSERT(s().at_base_lvl()); if (p.lit() != null_literal && value(p.lit()) == l_false) { - TRACE("sat", tout << "pb: flip sign " << p << "\n";); + TRACE("ba", tout << "pb: flip sign " << p << "\n";); IF_VERBOSE(0, verbose_stream() << "sign is flipped " << p << "\n";); return; - init_watch(p, !p.lit().sign()); } bool nullify = p.lit() != null_literal && value(p.lit()) == l_true; if (nullify) { + IF_VERBOSE(10, display(verbose_stream() << "nullify tracking literal\n", p, true);); SASSERT(lvl(p.lit()) == 0); nullify_tracking_literal(p); + init_watch(p, true); } - SASSERT(p.lit() == null_literal || value(p.lit()) == l_undef); + SASSERT(p.lit() == null_literal || value(p.lit()) != l_false); unsigned true_val = 0, slack = 0, num_false = 0; for (unsigned i = 0; i < p.size(); ++i) { literal l = p.get_lit(i); if (s().was_eliminated(l.var())) { SASSERT(p.learned()); - remove_constraint(p); + remove_constraint(p, "contains eliminated"); return; } switch (value(l)) { @@ -362,64 +363,73 @@ namespace sat { } if (p.k() == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); + IF_VERBOSE(10, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - remove_constraint(p); + remove_constraint(p, "implies clause"); } else if (true_val == 0 && num_false == 0) { - if (nullify) { + if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p, true); } } else if (true_val >= p.k()) { if (p.lit() != null_literal) { + IF_VERBOSE(10, display(verbose_stream() << "assign true literal ", p, true);); s().assign(p.lit(), justification()); } - remove_constraint(p); + remove_constraint(p, "is true"); } else if (slack + true_val < p.k()) { if (p.lit() != null_literal) { + display(std::cout << "assign false literal ", p, true); s().assign(~p.lit(), justification()); } else { IF_VERBOSE(0, verbose_stream() << "unsat during simplification\n";); s().set_conflict(justification()); } - remove_constraint(p); + remove_constraint(p, "is false"); } else if (slack + true_val == p.k()) { - literal_vector lits(p.literals()); + literal_vector lits(p.literals()); + display(std::cout << "replace", p, true); assert_unconstrained(p.lit(), lits); - remove_constraint(p); + remove_constraint(p, "is tight"); } else { + unsigned sz = p.size(); clear_watch(p); + unsigned j = 0; for (unsigned i = 0; i < sz; ++i) { literal l = p.get_lit(i); - if (value(l) != l_undef) { - --sz; - p.swap(i, sz); - --i; + if (value(l) == l_undef) { + if (i != j) p.swap(i, j); + ++j; } } + sz = j; + // _bad_id = p.id(); BADLOG(display(verbose_stream() << "simplify ", p, true)); + p.set_size(sz); p.set_k(p.k() - true_val); - BADLOG(display(verbose_stream() << "simplified ", p, true)); - // display(verbose_stream(), c, true); if (p.k() == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - remove_constraint(p); + remove_constraint(p, "is clause"); return; } - else if (p.lit() == null_literal) { + else if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p, true); } else { SASSERT(value(p.lit()) == l_undef); } + BADLOG(display(verbose_stream() << "simplified ", p, true); verbose_stream() << "\n"); + // display(verbose_stream(), c, true); + _bad_id = 11111111; SASSERT(p.well_formed()); if (p.is_pb()) simplify2(p.to_pb()); m_simplify_change = true; @@ -545,9 +555,10 @@ namespace sat { p.set_slack(slack); p.set_num_watch(num_watch); - SASSERT(validate_watch(p)); + VERIFY(validate_watch(p, null_literal)); + // SASSERT(validate_watch(p, null_literal)); - TRACE("sat", display(tout << "init watch: ", p, true);); + TRACE("ba", display(tout << "init watch: ", p, true);); // slack is tight: if (slack + slack1 == bound) { @@ -602,9 +613,8 @@ namespace sat { friendly (and the overhead of backtracking has to be taken into account). */ lbool ba_solver::add_assign(pb& p, literal alit) { - BADLOG(display(verbose_stream() << "assign: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); - TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + TRACE("ba", display(tout << "assign: " << alit << "\n", p, true);); SASSERT(!inconsistent()); unsigned sz = p.size(); unsigned bound = p.k(); @@ -635,8 +645,8 @@ namespace sat { return l_undef; } - validate_watch(p); - // SASSERT(validate_watch(p)); + VERIFY(validate_watch(p, null_literal)); + // SASSERT(validate_watch(p, null_literal)); SASSERT(index < num_watch); unsigned index1 = index + 1; @@ -658,7 +668,7 @@ namespace sat { watch_literal(p[j], p); p.swap(num_watch, j); add_index(p, num_watch, lit); - BADLOG(verbose_stream() << "add watch: " << lit << " num watch: " << num_watch << "\n"); + BADLOG(verbose_stream() << "add watch: " << lit << " num watch: " << num_watch << " max: " << m_a_max << " slack " << slack << "\n"); ++num_watch; } } @@ -671,10 +681,10 @@ namespace sat { slack += val; p.set_slack(slack); p.set_num_watch(num_watch); - validate_watch(p); + VERIFY(validate_watch(p, null_literal)); BADLOG(display(verbose_stream() << "conflict: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); SASSERT(bound <= slack); - TRACE("sat", tout << "conflict " << alit << "\n";); + TRACE("ba", tout << "conflict " << alit << "\n";); set_conflict(p, alit); return l_false; } @@ -696,7 +706,8 @@ namespace sat { // l must be true. // if (slack < bound + m_a_max) { - TRACE("sat", tout << p; for(auto j : m_pb_undef) tout << j << "\n";); + BADLOG(verbose_stream() << "slack " << slack << " " << bound << " " << m_a_max << "\n";); + TRACE("ba", tout << p << "\n"; for(auto j : m_pb_undef) tout << j << " "; tout << "\n";); for (unsigned index1 : m_pb_undef) { if (index1 == num_watch) { index1 = index; @@ -704,16 +715,16 @@ namespace sat { wliteral wl = p[index1]; literal lit = wl.second; SASSERT(value(lit) == l_undef); - BADLOG(verbose_stream() << "Assign " << lit << "\n"); if (slack < bound + wl.first) { + BADLOG(verbose_stream() << "Assign " << lit << " " << wl.first << "\n"); assign(p, lit); } } } - validate_watch(p); + VERIFY(validate_watch(p, alit)); // except that alit is still watched. - TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + TRACE("ba", display(tout << "assign: " << alit << "\n", p, true);); BADLOG(verbose_stream() << "unwatch " << alit << " watch: " << p.num_watch() << " size: " << p.size() << " slack: " << p.slack() << " " << inconsistent() << "\n"); @@ -729,6 +740,11 @@ namespace sat { unwatch_literal(p[i].second, p); } p.set_num_watch(0); + // debug code: + DEBUG_CODE( + for (wliteral wl : p) { + VERIFY(!is_watched(wl.second, p)); + }); } void ba_solver::recompile(pb& p) { @@ -781,21 +797,21 @@ namespace sat { if (p.lit() != null_literal) { s().assign(p.lit(), justification()); } - remove_constraint(p); + remove_constraint(p, "recompiled to true"); return; } if (k == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); s().mk_clause(sz, lits.c_ptr(), p.learned()); - remove_constraint(p); + remove_constraint(p, "recompiled to clause"); return; } if (all_units) { literal_vector lits(sz, p.literals().c_ptr()); add_at_least(p.lit(), lits, k, p.learned()); - remove_constraint(p); + remove_constraint(p, "recompiled to cardinality"); return; } @@ -816,12 +832,12 @@ namespace sat { literal_vector lits(p.literals()); unsigned k = (p.k() + p[0].first - 1) / p[0].first; add_at_least(p.lit(), lits, k, p.learned()); - remove_constraint(p); + remove_constraint(p, "simplified to cardinality"); } else if (p.lit() == null_literal) { for (wliteral wl : p) { if (p.k() > p.max_sum() - wl.first) { - TRACE("sat", + TRACE("ba", tout << "unit literal " << wl.second << "\n"; display(tout, p, true);); @@ -833,17 +849,21 @@ namespace sat { void ba_solver::display(std::ostream& out, pb const& p, bool values) const { if (p.lit() != null_literal) out << p.lit() << " == "; - if (p.lit() != null_literal && values) { + if (values) { out << "[watch: " << p.num_watch() << ", slack: " << p.slack() << "]"; + } + if (p.lit() != null_literal && values) { out << "@(" << value(p.lit()); if (value(p.lit()) != l_undef) { out << ":" << lvl(p.lit()); } out << "): "; } + unsigned i = 0; for (wliteral wl : p) { literal l = wl.second; unsigned w = wl.first; + if (i++ == p.num_watch()) out << " | "; if (w > 1) out << w << " * "; out << l; if (values) { @@ -888,7 +908,7 @@ namespace sat { if (x.lit() != null_literal && x.lit().sign() == is_true) { x.negate(); } - TRACE("sat", display(tout, x, true);); + TRACE("ba", display(tout, x, true);); unsigned sz = x.size(); unsigned j = 0; for (unsigned i = 0; i < sz && j < 2; ++i) { @@ -930,7 +950,7 @@ namespace sat { lbool ba_solver::add_assign(xor& x, literal alit) { // literal is assigned unsigned sz = x.size(); - TRACE("sat", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); + TRACE("ba", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); SASSERT(value(alit) != l_undef); @@ -1077,6 +1097,8 @@ namespace sat { static literal _debug_consequent = null_literal; static unsigned_vector _debug_var2position; +// #define DEBUG_CODE(_x_) _x_ + lbool ba_solver::resolve_conflict() { if (0 == m_num_propagations_since_pop) { return l_undef; @@ -1087,7 +1109,7 @@ namespace sat { m_bound = 0; literal consequent = s().m_not_l; justification js = s().m_conflict; - TRACE("sat", tout << consequent << " " << js << "\n"; s().display(tout);); + TRACE("ba", tout << consequent << " " << js << "\n";); m_conflict_lvl = s().get_max_lvl(consequent, js); if (consequent != null_literal) { consequent.neg(); @@ -1114,10 +1136,10 @@ namespace sat { } TRACE("sat_verbose", display(tout, m_A);); - TRACE("sat", tout << "process consequent: " << consequent << " : "; s().display_justification(tout, js) << "\n";); + TRACE("ba", tout << "process consequent: " << consequent << " : "; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); - // DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); + DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); if (_debug_conflict) { IF_VERBOSE(0, @@ -1180,7 +1202,7 @@ namespace sat { inc_bound(offset); inc_coeff(consequent, offset); get_antecedents(consequent, p, m_lemma); - TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";); + TRACE("ba", display(tout, p, true); tout << m_lemma << "\n";); if (_debug_conflict) { verbose_stream() << consequent << " "; verbose_stream() << "antecedents: " << m_lemma << "\n"; @@ -1212,10 +1234,10 @@ namespace sat { DEBUG_CODE( active2pb(m_C); - //SASSERT(validate_resolvent()); + VERIFY(validate_resolvent()); m_A = m_C;); - TRACE("sat", display(tout << "conflict: ", m_A);); + TRACE("ba", display(tout << "conflict: ", m_A);); cut(); @@ -1268,9 +1290,9 @@ namespace sat { goto bail_out; } - SASSERT(validate_conflict(m_lemma, m_A)); + DEBUG_CODE(VERIFY(validate_conflict(m_lemma, m_A));); - TRACE("sat", tout << m_lemma << "\n";); + TRACE("ba", tout << m_lemma << "\n";); if (get_config().m_drat) { svector ps; // TBD fill in @@ -1280,7 +1302,7 @@ namespace sat { s().m_lemma.reset(); s().m_lemma.append(m_lemma); for (unsigned i = 1; i < m_lemma.size(); ++i) { - CTRACE("sat", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); + CTRACE("ba", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); s().mark(m_lemma[i].var()); } @@ -1470,7 +1492,7 @@ namespace sat { TRACE("sat_verbose", tout << "Mark: v" << v << "\n";); ++m_num_marks; if (_debug_conflict && _debug_consequent != null_literal && _debug_var2position[_debug_consequent.var()] < _debug_var2position[l.var()]) { - std::cout << "antecedent " << l << " is above consequent in stack\n"; + IF_VERBOSE(0, verbose_stream() << "antecedent " << l << " is above consequent in stack\n";); } } inc_coeff(l, offset); @@ -1493,7 +1515,7 @@ namespace sat { } ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_constraint_id(0) { - TRACE("sat", tout << this << "\n";); + TRACE("ba", tout << this << "\n";); } ba_solver::~ba_solver() { @@ -1525,6 +1547,7 @@ namespace sat { } void ba_solver::add_constraint(constraint* c) { + // display(std::cout << "add " << c->learned() << " " << c->id() << "\n", *c, true); literal_vector lits(c->literals()); if (c->learned()) { m_learned.push_back(c); @@ -1613,8 +1636,8 @@ namespace sat { */ bool ba_solver::propagate(literal l, ext_constraint_idx idx) { SASSERT(value(l) == l_true); - TRACE("sat", tout << l << " " << idx << "\n";); constraint& c = index2constraint(idx); + TRACE("ba", tout << l << "\n";); if (c.lit() != null_literal && l.var() == c.lit().var()) { init_watch(c, !l.sign()); return true; @@ -1709,7 +1732,7 @@ namespace sat { unsigned level = lvl(l); bool_var v = l.var(); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); - TRACE("sat", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); + TRACE("ba", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); unsigned num_marks = 0; unsigned count = 0; @@ -1776,7 +1799,7 @@ namespace sat { reset_parity(lit.var()); } m_parity_trail.reset(); - TRACE("sat", tout << r << "\n";); + TRACE("ba", tout << r << "\n";); } /** @@ -1791,8 +1814,29 @@ namespace sat { Then x is an explanation for l */ + + bool ba_solver::assigned_above(literal above, literal below) { + unsigned l = lvl(above); + SASSERT(l == lvl(below)); + if (l == 0) return false; + unsigned start = s().m_scopes[l-1].m_trail_lim; + literal_vector const& lits = s().m_trail; + +#if 0 + IF_VERBOSE(10, verbose_stream() << "level " << l << " scope level " << s().scope_lvl() << " tail lim start: " + << start << " size of lits: " << lits.size() << " num scopes " << s().m_scopes.size() << "\n";); +#endif + + for (unsigned sz = lits.size(); sz-- > start; ) { + if (lits[sz] == above) return true; + if (lits[sz] == below) return false; + } + UNREACHABLE(); + return false; + } + void ba_solver::get_antecedents(literal l, pb const& p, literal_vector& r) { - TRACE("sat", display(tout, p, true);); + TRACE("ba", display(tout << l << " level: " << s().scope_lvl() << " ", p, true);); SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); if (p.lit() != null_literal) { @@ -1802,8 +1846,8 @@ namespace sat { unsigned k = p.k(); if (_debug_conflict) { - display(std::cout, p, true); - std::cout << "literal: " << l << " value: " << value(l) << " num-watch: " << p.num_watch() << " slack: " << p.slack() << "\n"; + IF_VERBOSE(0, display(verbose_stream(), p, true); + verbose_stream() << "literal: " << l << " value: " << value(l) << " num-watch: " << p.num_watch() << " slack: " << p.slack() << "\n";); } if (value(l) == l_false) { @@ -1830,6 +1874,8 @@ namespace sat { } } else { + // comes from a unit propagation + SASSERT(value(l) == l_true); unsigned coeff = 0, j = 0; for (; j < p.size(); ++j) { if (p[j].second == l) { @@ -1842,21 +1888,29 @@ namespace sat { if (j < p.num_watch()) { j = p.num_watch(); } - CTRACE("sat", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); + CTRACE("ba", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); if (_debug_conflict) { std::cout << "coeff " << coeff << "\n"; } SASSERT(coeff > 0); - unsigned slack = p.slack() - coeff; - j = std::max(j + 1, p.num_watch()); + unsigned slack = p.max_sum() - coeff; + // we need antecedents to be deeper than alit. for (; j < p.size(); ++j) { literal lit = p[j].second; unsigned w = p[j].first; - SASSERT(l_false == value(lit)); - if (slack + w < k) { + if (l_false != value(lit)) { + // skip + } + else if (lvl(lit) > lvl(l)) { + // skip + } + else if (lvl(lit) == lvl(l) && assigned_above(~lit, l)) { + // skip + } + else if (slack + w < k) { slack += w; } else { @@ -1908,7 +1962,7 @@ namespace sat { void ba_solver::get_antecedents(literal l, xor const& x, literal_vector& r) { if (x.lit() != null_literal) r.push_back(x.lit()); - // TRACE("sat", display(tout << l << " ", x, true);); + // TRACE("ba", display(tout << l << " ", x, true);); SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); SASSERT(x[0].var() == l.var() || x[1].var() == l.var()); if (x[0].var() == l.var()) { @@ -1977,10 +2031,11 @@ namespace sat { } } - void ba_solver::remove_constraint(constraint& c) { + void ba_solver::remove_constraint(constraint& c, char const* reason) { + IF_VERBOSE(21, display(verbose_stream() << "remove " << reason << " ", c, true);); nullify_tracking_literal(c); clear_watch(c); - c.remove(); + c.set_removed(); m_constraint_removed = true; } @@ -2100,16 +2155,11 @@ namespace sat { } bool ba_solver::validate_watched_constraint(constraint const& c) const { - if (c.is_pb() && !validate_watch(c.to_pb())) { + if (c.is_pb() && !validate_watch(c.to_pb(), null_literal)) { return false; } if (c.lit() != null_literal && value(c.lit()) != l_true) return true; - if (c.lit() != null_literal && lvl(c.lit()) != 0) { - if (!is_watched(c.lit(), c) || !is_watched(~c.lit(), c)) { - UNREACHABLE(); - return false; - } - } + SASSERT(c.lit() == null_literal || lvl(c.lit()) == 0 || (is_watched(c.lit(), c) && is_watched(~c.lit(), c))); if (eval(c) == l_true) { return true; } @@ -2136,14 +2186,25 @@ namespace sat { return true; } - bool ba_solver::validate_watch(pb const& p) const { + bool ba_solver::validate_watch(pb const& p, literal alit) const { for (unsigned i = 0; i < p.size(); ++i) { literal l = p[i].second; - if (lvl(l) != 0 && is_watched(l, p) != i < p.num_watch()) { + if (l != alit && lvl(l) != 0 && is_watched(l, p) != i < p.num_watch()) { + IF_VERBOSE(0, display(verbose_stream(), p, true); + verbose_stream() << "literal " << l << " at position " << i << " " << is_watched(l, p) << "\n";); UNREACHABLE(); return false; } } + unsigned slack = 0; + for (unsigned i = 0; i < p.num_watch(); ++i) { + slack += p[i].first; + } + if (slack != p.slack()) { + IF_VERBOSE(0, display(verbose_stream(), p, true);); + UNREACHABLE(); + return false; + } return true; } @@ -2190,14 +2251,14 @@ namespace sat { } void ba_solver::gc_half(char const* st_name) { - TRACE("sat", tout << "gc\n";); + TRACE("ba", tout << "gc\n";); unsigned sz = m_learned.size(); unsigned new_sz = sz/2; unsigned removed = 0; for (unsigned i = new_sz; i < sz; i++) { constraint* c = m_learned[i]; if (!m_constraint_to_reinit.contains(c)) { - remove_constraint(*c); + remove_constraint(*c, "gc"); ++removed; } } @@ -2211,7 +2272,7 @@ namespace sat { // literal is assigned to false. unsigned sz = c.size(); unsigned bound = c.k(); - TRACE("sat", tout << "assign: " << c.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); + TRACE("ba", tout << "assign: " << c.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); SASSERT(0 < bound && bound <= sz); if (bound == sz) { @@ -2245,12 +2306,12 @@ namespace sat { // conflict if (bound != index && value(c[bound]) == l_false) { - TRACE("sat", tout << "conflict " << c[bound] << " " << alit << "\n";); + TRACE("ba", tout << "conflict " << c[bound] << " " << alit << "\n";); set_conflict(c, alit); return l_false; } - // TRACE("sat", tout << "no swap " << index << " " << alit << "\n";); + // TRACE("ba", tout << "no swap " << index << " " << alit << "\n";); // there are no literals to swap with, // prepare for unit propagation by swapping the false literal into // position bound. Then literals in positions 0..bound-1 have to be @@ -2319,7 +2380,7 @@ namespace sat { } } - void ba_solver::simplify() { + void ba_solver::simplify() { if (!s().at_base_lvl()) s().pop_to_base_level(); unsigned trail_sz; do { @@ -2340,7 +2401,7 @@ namespace sat { } while (m_simplify_change || trail_sz < s().init_trail_size()); - IF_VERBOSE(1, verbose_stream() << "(ba.simplify " + IF_VERBOSE(1, verbose_stream() << "(ba.simplify" << " :vars " << s().num_vars() - trail_sz << " :constraints " << m_constraints.size() << " :lemmas " << m_learned.size() @@ -2520,7 +2581,7 @@ namespace sat { void ba_solver::recompile(constraint& c) { if (c.id() == _bad_id) { - display(std::cout << "recompile\n", c, true); + IF_VERBOSE(0, display(verbose_stream() << "recompile\n", c, true);); } switch (c.tag()) { case card_t: @@ -2585,14 +2646,14 @@ namespace sat { } if (k == 0) { - remove_constraint(c); + remove_constraint(c, "recompiled to true"); return; } if (k == 1) { literal_vector lits(c.size(), c.begin()); s().mk_clause(lits.size(), lits.c_ptr(), c.learned()); - remove_constraint(c); + remove_constraint(c, "recompiled to clause"); return; } @@ -2600,13 +2661,13 @@ namespace sat { c.set_k(k); if (!all_units) { - TRACE("sat", tout << "replacing by pb: " << c << "\n";); + TRACE("ba", tout << "replacing by pb: " << c << "\n";); m_wlits.reset(); for (unsigned i = 0; i < sz; ++i) { m_wlits.push_back(wliteral(coeffs[i], c[i])); } literal root = c.lit(); - remove_constraint(c); + remove_constraint(c, "recompiled to pb"); add_pb_ge(root, m_wlits, k, c.learned()); } else { @@ -2634,6 +2695,7 @@ namespace sat { found = m_root_vars[c.get_lit(i).var()]; } if (!found) return; + //std::cout << "reroot " << c << "\n"; clear_watch(c); // this could create duplicate literals @@ -2671,11 +2733,12 @@ namespace sat { found_root |= l.var() == root.var(); } + //std::cout << "reroot " << c << "\n"; if (found_root) { split_root(c); c.negate(); split_root(c); - remove_constraint(c); + remove_constraint(c, "flush roots"); } else if (found_dup) { recompile(c); @@ -2755,12 +2818,13 @@ namespace sat { switch (c.tag()) { case card_t: case pb_t: { - if (lit != null_literal && + if (lit != null_literal && + value(lit) == l_undef && use_count(lit) == 1 && use_count(~lit) == 1 && get_num_non_learned_bin(lit) == 0 && get_num_non_learned_bin(~lit) == 0) { - remove_constraint(c); + remove_constraint(c, "unused def"); } break; } @@ -2790,7 +2854,7 @@ namespace sat { for (unsigned i = 0; i < c.size(); ++i) { bool_var v = c.get_lit(i).var(); if (s().was_eliminated(v)) { - remove_constraint(c); + remove_constraint(c, "contains eliminated var"); break; } s().set_external(v); @@ -2801,9 +2865,9 @@ namespace sat { } bool ba_solver::elim_pure(literal lit) { - if (value(lit) != l_undef) return false; - if (!m_cnstr_use_list[lit.index()].empty() && use_count(~lit) == 0 && - get_num_non_learned_bin(~lit) == 0) { + if (value(lit) == l_undef && !m_cnstr_use_list[lit.index()].empty() && + use_count(~lit) == 0 && get_num_non_learned_bin(~lit) == 0) { + IF_VERBOSE(10, verbose_stream() << "pure literal: " << lit << "\n";); s().assign(lit, justification()); return true; } @@ -2855,7 +2919,7 @@ namespace sat { clause_vector::iterator it2 = it; for (; it != end; ++it) { clause* c = *it; - if (c->was_removed()) { + if (c->was_removed() && s().can_delete(*c)) { s().detach_clause(*c); s().del_clause(*c); } @@ -2891,6 +2955,8 @@ namespace sat { for (; it != end; ++it) { constraint& c = *(*it); if (c.was_removed()) { + clear_watch(c); + nullify_tracking_literal(c); m_allocator.deallocate(c.obj_size(), &c); } else if (learned && !c.learned()) { @@ -2994,7 +3060,7 @@ namespace sat { if (s) { ++m_stats.m_num_pb_subsumes; p1.set_learned(false); - remove_constraint(*c); + remove_constraint(*c, "subsumed"); } } } @@ -3023,13 +3089,14 @@ namespace sat { SASSERT(c1.index() != c2.index()); if (subsumes(c1, c2, slit)) { if (slit.empty()) { - TRACE("sat", tout << "subsume cardinality\n" << c1.index() << ":" << c1 << "\n" << c2.index() << ":" << c2 << "\n";); - remove_constraint(c2); + TRACE("ba", tout << "subsume cardinality\n" << c1.index() << ":" << c1 << "\n" << c2.index() << ":" << c2 << "\n";); + remove_constraint(c2, "subsumed"); ++m_stats.m_num_pb_subsumes; c1.set_learned(false); + std::cout << c1 << " subsumes " << c2 << "\n"; } else { - TRACE("sat", tout << "self subsume cardinality\n";); + TRACE("ba", tout << "self subsume cardinality\n";); IF_VERBOSE(0, verbose_stream() << "self-subsume cardinality is TBD\n"; verbose_stream() << c1 << "\n"; @@ -3059,15 +3126,16 @@ namespace sat { clause& c2 = it.curr(); if (!c2.was_removed() && subsumes(c1, c2, slit)) { if (slit.empty()) { - TRACE("sat", tout << "remove\n" << c1 << "\n" << c2 << "\n";); + TRACE("ba", tout << "remove\n" << c1 << "\n" << c2 << "\n";); removed_clauses.push_back(&c2); ++m_stats.m_num_clause_subsumes; c1.set_learned(false); + std::cout << c1 << " subsumes " << c2 << "\n"; } else { IF_VERBOSE(0, verbose_stream() << "self-subsume clause is TBD\n";); // remove literal slit from c2. - TRACE("sat", tout << "TBD remove literals " << slit << " from " << c2 << "\n";); + TRACE("ba", tout << "TBD remove literals " << slit << " from " << c2 << "\n";); } } it.next(); @@ -3089,6 +3157,7 @@ namespace sat { // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); if (!w.is_binary_non_learned_clause()) { c1.set_learned(false); + std::cout << c1 << " subsumes " << lit << " " << w.get_literal() << "\n"; } } else { @@ -3098,9 +3167,7 @@ namespace sat { ++it2; } } - if (it != it2) { - wlist.set_end(it2); - } + wlist.set_end(it2); } void ba_solver::subsumption(card& c1) { @@ -3138,7 +3205,7 @@ namespace sat { for (wliteral l : p1) { m_weights[l.second.index()] = 0; unmark_visited(l.second); - } + } } void ba_solver::clauses_modifed() {} @@ -3149,6 +3216,7 @@ namespace sat { \brief lit <=> conjunction of unconstrained lits */ void ba_solver::assert_unconstrained(literal lit, literal_vector const& lits) { + std::cout << "assert unconstrained\n"; if (lit == null_literal) { for (literal l : lits) { if (value(l) == l_undef) { @@ -3431,12 +3499,12 @@ namespace sat { } bool ba_solver::validate_unit_propagation(pb const& p, literal alit) const { - if (p.lit() != null_literal && value(p.lit()) != l_true) { + if (p.lit() != null_literal && value(p.lit()) != l_true) { return false; } unsigned sum = 0; - TRACE("sat", display(tout << "validate: " << alit << "\n", p, true);); + TRACE("ba", display(tout << "validate: " << alit << "\n", p, true);); for (wliteral wl : p) { literal lit = wl.second; lbool val = value(lit); @@ -3448,21 +3516,54 @@ namespace sat { } bool ba_solver::validate_unit_propagation(pb const& p, literal_vector const& r, literal alit) const { - unsigned sum = 0; // all elements of r are true, for (literal l : r) { if (value(l) != l_true) { + std::cout << "value of " << l << " is " << value(l) << "\n"; + display(std::cout, p, true); return false; } + if (value(alit) == l_true && lvl(l) > lvl(alit)) { + std::cout << "level of premise " << l << " is " << lvl(l) << "\n"; + std::cout << "level of asserting literal " << alit << " is " << lvl(alit) << "\n"; + display(std::cout, p, true); + return false; + } + // if (value(alit) == l_true && lvl(l) == lvl(alit)) { + // std::cout << "same level " << alit << " " << l << "\n"; + // } } // the sum of elements not in r or alit add up to less than k. + unsigned sum = 0; + // + // a*x + b*alit + c*r >= k + // sum a < k + // val(r) = false + // hence alit has to be true. for (wliteral wl : p) { literal lit = wl.second; - if (lit != alit && value(lit) != l_false && !r.contains(~lit)) { + if (lit != alit && !r.contains(~lit)) { sum += wl.first; } } - return sum < p.k(); + if (sum >= p.k()) { + std::cout << "sum is " << sum << " >= " << p.k() << "\n"; + display(std::cout, p, true); + std::cout << "id: " << p.id() << "\n"; + sum = 0; + for (wliteral wl : p) sum += wl.first; + std::cout << "overall sum " << sum << "\n"; + std::cout << "asserting literal: " << alit << "\n"; + std::cout << "reason: " << r << "\n"; + return false; + } + for (wliteral wl : p) { + if (alit == wl.second) { + return true; + } + } + std::cout << alit << " not found among literals\n"; + return false; } bool ba_solver::validate_unit_propagation(xor const& x, literal alit) const { @@ -3490,7 +3591,7 @@ namespace sat { val += coeff; } } - CTRACE("sat", val >= 0, active2pb(m_A); display(tout, m_A);); + CTRACE("ba", val >= 0, active2pb(m_A); display(tout, m_A);); return val < 0; } @@ -3627,12 +3728,12 @@ namespace sat { constraint* c = add_at_least(null_literal, lits, k, true); if (c) { + std::cout << *c << "\n"; lits.reset(); for (wliteral wl : m_wlits) { if (value(wl.second) == l_false) lits.push_back(wl.second); } unsigned glue = s().num_diff_levels(lits.size(), lits.c_ptr()); - c->set_glue(glue); } return c; @@ -3706,6 +3807,7 @@ namespace sat { // validate that m_A & m_B implies m_C bool ba_solver::validate_resolvent() { + return true; u_map coeffs; uint64 k = m_A.m_k + m_B.m_k; for (unsigned i = 0; i < m_A.m_lits.size(); ++i) { @@ -3745,7 +3847,6 @@ namespace sat { uint64 coeff; if (coeffs.find(lit.index(), coeff)) { if (coeff > m_C.m_coeffs[i] && m_C.m_coeffs[i] < m_C.m_k) { - IF_VERBOSE(0, verbose_stream() << i << ": " << m_C.m_coeffs[i] << " " << m_C.m_k << "\n";); goto violated; } coeffs.remove(lit.index()); @@ -3758,6 +3859,23 @@ namespace sat { return true; violated: + // last ditch effort by translating to SAT. + solver s0(s().m_params, s().rlimit()); + u_map translation; + literal l1 = translate_to_sat(s0, translation, m_A); + if (l1 == null_literal) return true; + literal l2 = translate_to_sat(s0, translation, m_B); + if (l2 == null_literal) return true; + ineq notC = negate(m_B); + literal l3 = translate_to_sat(s0, translation, notC); + if (l3 == null_literal) return true; + s0.assign(l1, justification()); + s0.assign(l2, justification()); + s0.assign(l3, justification()); + lbool is_sat = s0.check(); + TRACE("ba", s0.display(tout << "trying sat encoding");); + if (is_sat == l_false) return true; + IF_VERBOSE(0, display(verbose_stream(), m_A); display(verbose_stream(), m_B); @@ -3766,13 +3884,111 @@ namespace sat { verbose_stream() << to_literal(e.m_key) << ": " << e.m_value << "\n"; }); + UNREACHABLE(); return false; } + /** + \brief translate PB inequality to SAT formula. + */ + literal ba_solver::translate_to_sat(solver& s, u_map& translation, ineq const& pb) { + SASSERT(pb.m_k > 0); + if (pb.m_lits.size() > 1) { + ineq a, b; + a.reset(pb.m_k); + b.reset(pb.m_k); + for (unsigned i = 0; i < pb.m_lits.size()/2; ++i) { + a.push(pb.m_lits[i], pb.m_coeffs[i]); + } + for (unsigned i = pb.m_lits.size()/2; i < pb.m_lits.size(); ++i) { + b.push(pb.m_lits[i], pb.m_coeffs[i]); + } + bool_var v = s.mk_var(); + literal lit(v, false); + literal_vector lits; + lits.push_back(~lit); + push_lit(lits, translate_to_sat(s, translation, a)); + push_lit(lits, translate_to_sat(s, translation, b)); + push_lit(lits, translate_to_sat(s, translation, a, b)); + s.mk_clause(lits); + return lit; + } + if (pb.m_coeffs[0] >= pb.m_k) { + return translate_to_sat(s, translation, pb.m_lits[0]); + } + else { + return null_literal; + } + } + + /* + \brief encode the case where Sum(a) >= k-1 & Sum(b) >= 1 \/ ... \/ Sum(a) >= 1 & Sum(b) >= k-1 + */ + literal ba_solver::translate_to_sat(solver& s, u_map& translation, ineq& a, ineq& b) { + uint64 k0 = a.m_k; + literal_vector lits; + for (unsigned k = 1; k < a.m_k - 1; ++k) { + a.m_k = k; b.m_k = k0 - k; + literal lit1 = translate_to_sat(s, translation, a); + literal lit2 = translate_to_sat(s, translation, b); + if (lit1 != null_literal && lit2 != null_literal) { + bool_var v = s.mk_var(); + literal lit(v, false); + s.mk_clause(~lit, lit1); + s.mk_clause(~lit, lit2); + lits.push_back(lit); + } + } + a.m_k = k0; + b.m_k = k0; + switch (lits.size()) { + case 0: return null_literal; + case 1: return lits[0]; + default: { + bool_var v = s.mk_var(); + literal lit(v, false); + lits.push_back(~lit); + s.mk_clause(lits); + return lit; + } + } + } + + literal ba_solver::translate_to_sat(solver& s, u_map& translation, literal lit) { + bool_var v; + if (!translation.find(lit.var(), v)) { + v = s.mk_var(); + translation.insert(lit.var(), v); + } + return literal(v, lit.sign()); + } + + ba_solver::ineq ba_solver::negate(ineq const& a) const { + ineq result; + uint64 sum = 0; + for (unsigned i = 0; i < a.m_lits.size(); ++i) { + result.push(~a.m_lits[i], a.m_coeffs[i]); + sum += a.m_coeffs[i]; + } + SASSERT(sum >= a.m_k + 1); + result.m_k = sum + 1 - a.m_k; + return result; + } + + void ba_solver::push_lit(literal_vector& lits, literal lit) { + if (lit != null_literal) { + lits.push_back(lit); + } + } + bool ba_solver::validate_conflict(literal_vector const& lits, ineq& p) { for (literal l : lits) { if (value(l) != l_false) { - TRACE("sat", tout << "literal " << l << " is not false\n";); + TRACE("ba", tout << "literal " << l << " is not false\n";); + return false; + } + if (!p.m_lits.contains(l)) { + TRACE("ba", tout << "lemma contains literal " << l << " not in inequality\n";); return false; } } @@ -3783,7 +3999,7 @@ namespace sat { value += coeff; } } - CTRACE("sat", value >= p.m_k, tout << "slack: " << value << " bound " << p.m_k << "\n"; + CTRACE("ba", value >= p.m_k, tout << "slack: " << value << " bound " << p.m_k << "\n"; display(tout, p); tout << lits << "\n";); return value < p.m_k; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 88a81701a..360f276f2 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -79,7 +79,7 @@ namespace sat { void set_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } void update_literal(literal l) { m_lit = l; } bool was_removed() const { return m_removed; } - void remove() { m_removed = true; } + void set_removed() { m_removed = true; } void nullify_literal() { m_lit = null_literal; } unsigned glue() const { return m_glue; } void set_glue(unsigned g) { m_glue = g; } @@ -199,7 +199,7 @@ namespace sat { svector m_coeffs; uint64 m_k; void reset(uint64 k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } - void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } + void push(literal l, uint64 c) { m_lits.push_back(l); m_coeffs.push_back(c); } }; solver* m_solver; @@ -286,7 +286,7 @@ namespace sat { void cleanup_constraints(); void cleanup_constraints(ptr_vector& cs, bool learned); void ensure_external(constraint const& c); - void remove_constraint(constraint& c); + void remove_constraint(constraint& c, char const* reason); // constraints constraint& index2constraint(size_t idx) const { return *reinterpret_cast(idx); } @@ -304,6 +304,7 @@ namespace sat { void nullify_tracking_literal(constraint& c); void set_conflict(constraint& c, literal lit); void assign(constraint& c, literal lit); + bool assigned_above(literal above, literal below); void get_antecedents(literal l, constraint const& c, literal_vector & r); bool validate_conflict(constraint const& c) const; bool validate_unit_propagation(constraint const& c, literal alit) const; @@ -402,8 +403,13 @@ namespace sat { bool validate_watch_literals() const; bool validate_watch_literal(literal lit) const; bool validate_watched_constraint(constraint const& c) const; - bool validate_watch(pb const& p) const; + bool validate_watch(pb const& p, literal alit) const; bool is_watching(literal lit, constraint const& c) const; + literal translate_to_sat(solver& s, u_map& translation, ineq const& pb); + literal translate_to_sat(solver& s, u_map& translation, ineq& a, ineq& b); + literal translate_to_sat(solver& s, u_map& translation, literal lit); + ineq negate(ineq const& a) const; + void push_lit(literal_vector& lits, literal lit); ineq m_A, m_B, m_C; void active2pb(ineq& p); diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 0f1b578f1..d3864fd8b 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -272,7 +272,8 @@ namespace sat { void drat::verify(unsigned n, literal const* c) { if (!is_drup(n, c) && !is_drat(n, c)) { std::cout << "Verification failed\n"; - display(std::cout); + UNREACHABLE(); + //display(std::cout); TRACE("sat", tout << literal_vector(n, c) << "\n"; display(tout); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index ade66403d..ab0d69791 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -469,7 +469,9 @@ Notes: } literal mk_ordered_1(bool full, bool is_eq, unsigned n, literal const* xs) { - if (n <= 1 && !is_eq) return ctx.mk_true(); + if (n <= 1 && !is_eq) { + return ctx.mk_true(); + } if (n == 0) { return ctx.mk_false(); } @@ -477,6 +479,8 @@ Notes: return xs[0]; } + SASSERT(n > 1); + // y0 -> y1 // x0 -> y0 // x1 -> y1 From 356835533a8df3f6c995da2ac2b96c8d5079ed77 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 10:47:15 -0700 Subject: [PATCH 0251/1283] clean up debug output Signed-off-by: Nikolaj Bjorner --- src/model/model_core.cpp | 8 ++++---- src/sat/ba_solver.cpp | 40 +++++++++++++++++----------------------- src/smt/theory_pb.cpp | 1 - 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index f94558097..4290700d4 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -86,18 +86,18 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { void model_core::unregister_decl(func_decl * d) { decl2expr::obj_map_entry * ec = m_interp.find_core(d); if (ec && ec->get_data().m_value != 0) { - m_manager.dec_ref(ec->get_data().m_key); - m_manager.dec_ref(ec->get_data().m_value); m_interp.remove(d); m_const_decls.erase(d); + m_manager.dec_ref(ec->get_data().m_key); + m_manager.dec_ref(ec->get_data().m_value); return; } decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); if (ef && ef->get_data().m_value != 0) { - m_manager.dec_ref(ef->get_data().m_key); - dealloc(ef->get_data().m_value); m_finterp.remove(d); m_func_decls.erase(d); + m_manager.dec_ref(ef->get_data().m_key); + dealloc(ef->get_data().m_value); } } diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 0de5af885..668044e66 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -381,7 +381,7 @@ namespace sat { } else if (slack + true_val < p.k()) { if (p.lit() != null_literal) { - display(std::cout << "assign false literal ", p, true); + IF_VERBOSE(10, display(verbose_stream() << "assign false literal ", p, true);); s().assign(~p.lit(), justification()); } else { @@ -392,7 +392,6 @@ namespace sat { } else if (slack + true_val == p.k()) { literal_vector lits(p.literals()); - display(std::cout << "replace", p, true); assert_unconstrained(p.lit(), lits); remove_constraint(p, "is tight"); } @@ -1075,7 +1074,6 @@ namespace sat { int64 new_bound = m_bound; new_bound += i; if (new_bound < 0) { - // std::cout << "new negative bound " << new_bound << "\n"; m_overflow = true; } else if (new_bound > UINT_MAX) { @@ -1547,7 +1545,6 @@ namespace sat { } void ba_solver::add_constraint(constraint* c) { - // display(std::cout << "add " << c->learned() << " " << c->id() << "\n", *c, true); literal_vector lits(c->literals()); if (c->learned()) { m_learned.push_back(c); @@ -3093,7 +3090,6 @@ namespace sat { remove_constraint(c2, "subsumed"); ++m_stats.m_num_pb_subsumes; c1.set_learned(false); - std::cout << c1 << " subsumes " << c2 << "\n"; } else { TRACE("ba", tout << "self subsume cardinality\n";); @@ -3130,7 +3126,6 @@ namespace sat { removed_clauses.push_back(&c2); ++m_stats.m_num_clause_subsumes; c1.set_learned(false); - std::cout << c1 << " subsumes " << c2 << "\n"; } else { IF_VERBOSE(0, verbose_stream() << "self-subsume clause is TBD\n";); @@ -3157,7 +3152,6 @@ namespace sat { // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); if (!w.is_binary_non_learned_clause()) { c1.set_learned(false); - std::cout << c1 << " subsumes " << lit << " " << w.get_literal() << "\n"; } } else { @@ -3216,7 +3210,6 @@ namespace sat { \brief lit <=> conjunction of unconstrained lits */ void ba_solver::assert_unconstrained(literal lit, literal_vector const& lits) { - std::cout << "assert unconstrained\n"; if (lit == null_literal) { for (literal l : lits) { if (value(l) == l_undef) { @@ -3519,14 +3512,15 @@ namespace sat { // all elements of r are true, for (literal l : r) { if (value(l) != l_true) { - std::cout << "value of " << l << " is " << value(l) << "\n"; - display(std::cout, p, true); + IF_VERBOSE(0, verbose_stream() << "value of " << l << " is " << value(l) << "\n"; + display(verbose_stream(), p, true);); return false; } if (value(alit) == l_true && lvl(l) > lvl(alit)) { - std::cout << "level of premise " << l << " is " << lvl(l) << "\n"; - std::cout << "level of asserting literal " << alit << " is " << lvl(alit) << "\n"; - display(std::cout, p, true); + IF_VERBOSE(0, + verbose_stream() << "level of premise " << l << " is " << lvl(l) << "\n"; + verbose_stream() << "level of asserting literal " << alit << " is " << lvl(alit) << "\n"; + display(verbose_stream(), p, true);); return false; } // if (value(alit) == l_true && lvl(l) == lvl(alit)) { @@ -3547,14 +3541,15 @@ namespace sat { } } if (sum >= p.k()) { - std::cout << "sum is " << sum << " >= " << p.k() << "\n"; - display(std::cout, p, true); - std::cout << "id: " << p.id() << "\n"; - sum = 0; - for (wliteral wl : p) sum += wl.first; - std::cout << "overall sum " << sum << "\n"; - std::cout << "asserting literal: " << alit << "\n"; - std::cout << "reason: " << r << "\n"; + IF_VERBOSE(0, + verbose_stream() << "sum is " << sum << " >= " << p.k() << "\n"; + display(verbose_stream(), p, true); + verbose_stream() << "id: " << p.id() << "\n"; + sum = 0; + for (wliteral wl : p) sum += wl.first; + verbose_stream() << "overall sum " << sum << "\n"; + verbose_stream() << "asserting literal: " << alit << "\n"; + verbose_stream() << "reason: " << r << "\n";); return false; } for (wliteral wl : p) { @@ -3562,7 +3557,7 @@ namespace sat { return true; } } - std::cout << alit << " not found among literals\n"; + IF_VERBOSE(0, verbose_stream() << alit << " not found among literals\n";); return false; } @@ -3728,7 +3723,6 @@ namespace sat { constraint* c = add_at_least(null_literal, lits, k, true); if (c) { - std::cout << *c << "\n"; lits.reset(); for (wliteral wl : m_wlits) { if (value(wl.second) == l_false) lits.push_back(wl.second); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 12fddee13..92f66f4b6 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -474,7 +474,6 @@ namespace smt { if (pb.is_aux_bool(atom)) { bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); - std::cout << "aux bool " << ctx.get_scope_level() << " " << mk_pp(atom, get_manager()) << " " << literal(abv) << "\n"; return true; } From 10e4235b4c9495be46ca6c11786b445c94a668f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 14:35:31 -0700 Subject: [PATCH 0252/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 84 +++++++++++++++++++--------------------- src/sat/sat_elim_eqs.cpp | 56 +++++++++++++-------------- src/sat/sat_elim_eqs.h | 1 + src/sat/sat_solver.cpp | 3 ++ 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 668044e66..6f3d0da2f 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -363,8 +363,8 @@ namespace sat { } if (p.k() == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); - IF_VERBOSE(10, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + IF_VERBOSE(10, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); remove_constraint(p, "implies clause"); } else if (true_val == 0 && num_false == 0) { @@ -415,8 +415,8 @@ namespace sat { p.set_k(p.k() - true_val); if (p.k() == 1 && p.lit() == null_literal) { - literal_vector lits(p.literals()); - s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + literal_vector lits(sz, p.literals().c_ptr()); + s().mk_clause(sz, lits.c_ptr(), p.learned()); remove_constraint(p, "is clause"); return; } @@ -501,7 +501,7 @@ namespace sat { // watch a prefix of literals, such that the slack of these is >= k bool ba_solver::init_watch(pb& p, bool is_true) { - clear_watch(p); + clear_watch(p); if (p.lit() != null_literal && p.lit().sign() == is_true) { p.negate(); } @@ -756,14 +756,13 @@ namespace sat { unsigned k = p.k(); unsigned sz = p.size(); bool all_units = true; + unsigned j = 0; for (unsigned i = 0; i < sz && 0 < k; ++i) { literal l = p[i].second; unsigned w1 = m_weights[l.index()]; unsigned w2 = m_weights[(~l).index()]; if (w1 == 0 || w1 < w2) { - p.swap(i, sz - 1); - --sz; - --i; + continue; } else if (k <= w2) { k = 0; @@ -776,16 +775,16 @@ namespace sat { m_weights[l.index()] = 0; m_weights[(~l).index()] = 0; if (w1 == 0) { - p.swap(i, sz - 1); - --sz; - --i; + continue; } else { - p[i] = wliteral(w1, l); + p[j] = wliteral(w1, l); all_units &= w1 == 1; + ++j; } } } + sz = j; // clear weights for (wliteral wl : p) { m_weights[wl.second.index()] = 0; @@ -800,27 +799,28 @@ namespace sat { return; } - if (k == 1 && p.lit() == null_literal) { - literal_vector lits(p.literals()); + else if (k == 1 && p.lit() == null_literal) { + literal_vector lits(sz, p.literals().c_ptr()); s().mk_clause(sz, lits.c_ptr(), p.learned()); remove_constraint(p, "recompiled to clause"); return; } - if (all_units) { + else if (all_units) { literal_vector lits(sz, p.literals().c_ptr()); add_at_least(p.lit(), lits, k, p.learned()); remove_constraint(p, "recompiled to cardinality"); return; } - p.set_size(sz); - p.set_k(k); - SASSERT(p.well_formed()); - - // this could become a cardinality constraint by now. - if (p.lit() == null_literal || value(p.lit()) == l_true) { - init_watch(p, true); + else { + p.set_size(sz); + p.set_k(k); + SASSERT(p.well_formed()); + + if (p.lit() == null_literal || value(p.lit()) == l_true) { + init_watch(p, true); + } } } @@ -1281,13 +1281,8 @@ namespace sat { if (!create_asserting_lemma()) { goto bail_out; } - active2card(); - if (m_overflow) { - goto bail_out; - } - DEBUG_CODE(VERIFY(validate_conflict(m_lemma, m_A));); TRACE("ba", tout << m_lemma << "\n";); @@ -1407,7 +1402,7 @@ namespace sat { IF_VERBOSE(10, verbose_stream() << "(sat.backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); goto adjust_conflict_level; } - return true; + return !m_overflow; } /* @@ -2564,7 +2559,6 @@ namespace sat { if (m_roots.empty()) return; // validate(); - m_visited.resize(s().num_vars()*2, false); m_constraint_removed = false; for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) @@ -2572,7 +2566,6 @@ namespace sat { for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) flush_roots(*m_learned[i]); cleanup_constraints(); - // validate(); } @@ -2596,6 +2589,7 @@ namespace sat { } void ba_solver::recompile(card& c) { + // pre-condition is that the literals, except c.lit(), in c are watched. if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; // IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); m_weights.resize(2*s().num_vars(), 0); @@ -2606,14 +2600,14 @@ namespace sat { bool all_units = true; unsigned sz = c.size(); unsigned_vector coeffs; + literal_vector lits; + unsigned j = 0; for (unsigned i = 0; i < sz && 0 < k; ++i) { literal l = c[i]; unsigned w = m_weights[l.index()]; unsigned w2 = m_weights[(~l).index()]; if (w == 0 || w < w2) { - c.swap(i, sz - 1); - --sz; - --i; + continue; } else if (k <= w2) { k = 0; @@ -2626,36 +2620,37 @@ namespace sat { m_weights[(~l).index()] = 0; m_weights[l.index()] = 0; if (w == 0) { - c.swap(i, sz - 1); - --sz; - --i; + continue; } else { all_units &= (w == 1); coeffs.push_back(w); + c[j++] = l; } } } + sz = j; + // clear weights for (literal l : c) { m_weights[l.index()] = 0; m_weights[(~l).index()] = 0; } - if (k == 0) { + if (k == 0 && c.lit() == null_literal) { remove_constraint(c, "recompiled to true"); return; } - if (k == 1) { - literal_vector lits(c.size(), c.begin()); - s().mk_clause(lits.size(), lits.c_ptr(), c.learned()); + if (k == 1 && c.lit() == null_literal) { + literal_vector lits(sz, c.literals().c_ptr()); + s().mk_clause(sz, lits.c_ptr(), c.learned()); remove_constraint(c, "recompiled to clause"); return; } c.set_size(sz); - c.set_k(k); + c.set_k(k); if (!all_units) { TRACE("ba", tout << "replacing by pb: " << c << "\n";); @@ -2671,6 +2666,7 @@ namespace sat { if (c.lit() == null_literal || value(c.lit()) == l_true) { init_watch(c, true); } + SASSERT(c.lit() == null_literal || is_watched(c.lit(), c)); SASSERT(c.well_formed()); } } @@ -2692,7 +2688,6 @@ namespace sat { found = m_root_vars[c.get_lit(i).var()]; } if (!found) return; - //std::cout << "reroot " << c << "\n"; clear_watch(c); // this could create duplicate literals @@ -2730,7 +2725,6 @@ namespace sat { found_root |= l.var() == root.var(); } - //std::cout << "reroot " << c << "\n"; if (found_root) { split_root(c); c.negate(); @@ -2837,8 +2831,9 @@ namespace sat { for (unsigned v = 0; v < s().num_vars(); ++v) { literal lit(v, false); if (s().is_external(v) && - m_cnstr_use_list[lit.index()].size() == 0 && - m_cnstr_use_list[(~lit).index()].size() == 0 && !s().is_assumption(v)) { + m_cnstr_use_list[lit.index()].empty() && + m_cnstr_use_list[(~lit).index()].empty() && + !s().is_assumption(v)) { s().set_non_external(v); ++ext; } @@ -3723,6 +3718,7 @@ namespace sat { constraint* c = add_at_least(null_literal, lits, k, true); if (c) { + // IF_VERBOSE(0, verbose_stream() << *c << "\n";); lits.reset(); for (wliteral wl : m_wlits) { if (value(wl.second) == l_false) lits.push_back(wl.second); diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 8666218c6..7580ebba5 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -101,12 +101,13 @@ namespace sat { c[i] = norm(roots, c[i]); } std::sort(c.begin(), c.end()); + for (literal l : c) VERIFY(l == norm(roots, l)); TRACE("sats", tout << "after normalization/sorting: " << c << "\n"; tout.flush();); DEBUG_CODE({ - for (unsigned i = 0; i < sz; i++) { - CTRACE("sats", c[i] != norm(roots, c[i]), tout << c[i] << " " << norm(roots, c[i]) << "\n"; tout.flush();); - SASSERT(c[i] == norm(roots, c[i])); - } }); + for (literal l : c) { + CTRACE("sat", l != norm(roots, l), tout << l << " " << norm(roots, l) << "\n"; tout.flush();); + SASSERT(l == norm(roots, l)); + } }); // remove duplicates, and check if it is a tautology literal l_prev = null_literal; unsigned j = 0; @@ -122,13 +123,11 @@ namespace sat { break; // clause was satisfied if (val == l_false) continue; // skip - if (i != j) { - std::swap(c[i], c[j]); - } + c[j] = l; j++; } if (i < sz) { - // clause is a tautology or was simplified + // clause is a tautology or was simplified to true m_solver.del_clause(c); continue; } @@ -164,10 +163,7 @@ namespace sat { else c.update_approx(); - DEBUG_CODE({ - for (unsigned i = 0; i < j; i++) { - SASSERT(c[i] == norm(roots, c[i])); - } }); + DEBUG_CODE(for (literal l : c) VERIFY(l == norm(roots, l));); *it2 = *it; it2++; @@ -187,7 +183,6 @@ namespace sat { literal r = roots[v]; SASSERT(v != r.var()); if (m_solver.is_external(v) && !m_solver.set_root(l, r)) { - std::cout << "skip: " << l << " == " << r << "\n"; // cannot really eliminate v, since we have to notify extension of future assignments m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(l, ~r, false); @@ -199,29 +194,33 @@ namespace sat { mc.insert(e, ~l, r); mc.insert(e, l, ~r); } - m_solver.flush_roots(); } + m_solver.flush_roots(); } - bool elim_eqs::check_clauses(literal_vector const & roots) const { - clause_vector * vs[2] = { &m_solver.m_clauses, &m_solver.m_learned }; - for (unsigned i = 0; i < 2; i++) { - clause_vector & cs = *(vs[i]); - clause_vector::iterator it = cs.begin(); - clause_vector::iterator end = cs.end(); - for (; it != end; ++it) { - clause & c = *(*it); - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - CTRACE("elim_eqs_bug", m_solver.was_eliminated(c[i].var()), tout << "lit: " << c[i] << " " << norm(roots, c[i]) << "\n"; - tout << c << "\n";); - SASSERT(!m_solver.was_eliminated(c[i].var())); - } + bool elim_eqs::check_clause(clause const& c, literal_vector const& roots) const { + for (literal l : c) { + CTRACE("elim_eqs_bug", m_solver.was_eliminated(l.var()), tout << "lit: " << l << " " << norm(roots, l) << "\n"; + tout << c << "\n";); + if (m_solver.was_eliminated(l.var())) { + IF_VERBOSE(0, verbose_stream() << c << " contains eliminated literal " << l << " " << norm(roots, l) << "\n";); + UNREACHABLE(); } } return true; } + + bool elim_eqs::check_clauses(literal_vector const & roots) const { + for (clause * cp : m_solver.m_clauses) + if (!check_clause(*cp, roots)) + return false; + for (clause * cp : m_solver.m_learned) + if (!check_clause(*cp, roots)) + return false; + return true; + } + void elim_eqs::operator()(literal_vector const & roots, bool_var_vector const & to_elim) { cleanup_bin_watches(roots); TRACE("elim_eqs", tout << "after bin cleanup\n"; m_solver.display(tout);); @@ -230,6 +229,7 @@ namespace sat { cleanup_clauses(roots, m_solver.m_learned); if (m_solver.inconsistent()) return; save_elim(roots, to_elim); + VERIFY(check_clauses(roots)); m_solver.propagate(false); SASSERT(check_clauses(roots)); } diff --git a/src/sat/sat_elim_eqs.h b/src/sat/sat_elim_eqs.h index 0422b60df..15c50097d 100644 --- a/src/sat/sat_elim_eqs.h +++ b/src/sat/sat_elim_eqs.h @@ -30,6 +30,7 @@ namespace sat { void cleanup_clauses(literal_vector const & roots, clause_vector & cs); void cleanup_bin_watches(literal_vector const & roots); bool check_clauses(literal_vector const & roots) const; + bool check_clause(clause const& c, literal_vector const& roots) const; public: elim_eqs(solver & s); void operator()(literal_vector const & roots, bool_var_vector const & to_elim); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index cc79e75ff..8011837dd 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -372,6 +372,9 @@ namespace sat { clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, bool learned) { m_stats.m_mk_clause++; + for (unsigned i = 0; i + 1 < num_lits; ++i) { + VERIFY (lits[i] != ~lits[i + 1]); + } clause * r = m_cls_allocator.mk_clause(num_lits, lits, learned); SASSERT(!learned || r->is_learned()); bool reinit = attach_nary_clause(*r); From f85c02600f19d6c5e7a7a67aaa2d53a8002ce71a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 16:07:58 -0700 Subject: [PATCH 0253/1283] remove verificaiton code Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 1 - src/sat/sat_elim_eqs.cpp | 1 - src/sat/sat_solver.cpp | 3 --- 3 files changed, 5 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 6f3d0da2f..f1f32eef5 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1387,7 +1387,6 @@ namespace sat { IF_VERBOSE(20, verbose_stream() << "(sat.card slack: " << slack << " skipped: " << num_skipped << ")\n";); return false; } - if (m_lemma[0] == null_literal) { if (m_lemma.size() == 1) { diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 7580ebba5..d10bea7bb 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -229,7 +229,6 @@ namespace sat { cleanup_clauses(roots, m_solver.m_learned); if (m_solver.inconsistent()) return; save_elim(roots, to_elim); - VERIFY(check_clauses(roots)); m_solver.propagate(false); SASSERT(check_clauses(roots)); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8011837dd..cc79e75ff 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -372,9 +372,6 @@ namespace sat { clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, bool learned) { m_stats.m_mk_clause++; - for (unsigned i = 0; i + 1 < num_lits; ++i) { - VERIFY (lits[i] != ~lits[i + 1]); - } clause * r = m_cls_allocator.mk_clause(num_lits, lits, learned); SASSERT(!learned || r->is_learned()); bool reinit = attach_nary_clause(*r); From 79b2a4f605cf1acd7dd8608a1df09b4ab2a359cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Oct 2017 07:22:02 -0700 Subject: [PATCH 0254/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 57 ++++++++++++++++++++++++------------- src/util/memory_manager.cpp | 3 +- src/util/vector.h | 1 + 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index f1f32eef5..1dbaefbce 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -218,11 +218,16 @@ namespace sat { bool ba_solver::init_watch(card& c, bool is_true) { clear_watch(c); - if (c.lit() != null_literal && c.lit().sign() == is_true) { + literal root = c.lit(); + if (root != null_literal && root.sign() == is_true) { c.negate(); } + if (root != null_literal) { + if (!is_watched(root, c)) watch_literal(root, c); + if (!is_watched(~root, c)) watch_literal(~root, c); + } TRACE("ba", display(tout << "init watch: ", c, true);); - SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); + SASSERT(root == null_literal || value(root) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); // put the non-false literals into the head. @@ -554,8 +559,7 @@ namespace sat { p.set_slack(slack); p.set_num_watch(num_watch); - VERIFY(validate_watch(p, null_literal)); - // SASSERT(validate_watch(p, null_literal)); + SASSERT(validate_watch(p, null_literal)); TRACE("ba", display(tout << "init watch: ", p, true);); @@ -644,7 +648,7 @@ namespace sat { return l_undef; } - VERIFY(validate_watch(p, null_literal)); + SASSERT(validate_watch(p, null_literal)); // SASSERT(validate_watch(p, null_literal)); SASSERT(index < num_watch); @@ -680,7 +684,7 @@ namespace sat { slack += val; p.set_slack(slack); p.set_num_watch(num_watch); - VERIFY(validate_watch(p, null_literal)); + SASSERT(validate_watch(p, null_literal)); BADLOG(display(verbose_stream() << "conflict: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); SASSERT(bound <= slack); TRACE("ba", tout << "conflict " << alit << "\n";); @@ -721,7 +725,7 @@ namespace sat { } } - VERIFY(validate_watch(p, alit)); // except that alit is still watched. + SASSERT(validate_watch(p, alit)); // except that alit is still watched. TRACE("ba", display(tout << "assign: " << alit << "\n", p, true);); @@ -739,11 +743,8 @@ namespace sat { unwatch_literal(p[i].second, p); } p.set_num_watch(0); - // debug code: - DEBUG_CODE( - for (wliteral wl : p) { - VERIFY(!is_watched(wl.second, p)); - }); + + DEBUG_CODE(for (wliteral wl : p) VERIFY(!is_watched(wl.second, p));); } void ba_solver::recompile(pb& p) { @@ -1558,10 +1559,14 @@ namespace sat { } else { s().set_external(lit.var()); - get_wlist(lit).push_back(watched(c->index())); - get_wlist(~lit).push_back(watched(c->index())); + watch_literal(lit, *c); + watch_literal(~lit, *c); } SASSERT(c->well_formed()); + if (c->id() == 1344) { + std::cout << "is watched: " << lit << " " << is_watched(lit, *c) << "\n"; + std::cout << "is watched: " << ~lit << " " << is_watched(~lit, *c) << "\n"; + } } @@ -1982,10 +1987,17 @@ namespace sat { } void ba_solver::unwatch_literal(literal lit, constraint& c) { + if (c.index() == 1344) { + std::cout << "unwatch: " << lit << "\n"; + } get_wlist(~lit).erase(watched(c.index())); } void ba_solver::watch_literal(literal lit, constraint& c) { + if (c.index() == 1344) { + std::cout << "watch: " << lit << "\n"; + } + get_wlist(~lit).push_back(watched(c.index())); } @@ -2588,7 +2600,9 @@ namespace sat { } void ba_solver::recompile(card& c) { - // pre-condition is that the literals, except c.lit(), in c are watched. + SASSERT(c.lit() == null_literal || is_watched(c.lit(), c)); + + // pre-condition is that the literals, except c.lit(), in c are unwatched. if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; // IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); m_weights.resize(2*s().num_vars(), 0); @@ -2682,6 +2696,11 @@ namespace sat { void ba_solver::flush_roots(constraint& c) { + if (c.lit() != null_literal && !is_watched(c.lit(), c)) { + watch_literal(c.lit(), c); + watch_literal(~c.lit(), c); + } + SASSERT(c.lit() == null_literal || is_watched(c.lit(), c)); bool found = c.lit() != null_literal && m_root_vars[c.lit().var()]; for (unsigned i = 0; !found && i < c.size(); ++i) { found = m_root_vars[c.get_lit(i).var()]; @@ -2696,12 +2715,12 @@ namespace sat { } literal root = c.lit(); - if (c.lit() != null_literal && m_roots[c.lit().index()] != c.lit()) { - root = m_roots[c.lit().index()]; + if (root != null_literal && m_roots[root.index()] != root) { + root = m_roots[root.index()]; nullify_tracking_literal(c); c.update_literal(root); - get_wlist(root).push_back(watched(c.index())); - get_wlist(~root).push_back(watched(c.index())); + watch_literal(root, c); + watch_literal(~root, c); } bool found_dup = false; diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 0b394b450..d2e25294d 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -58,9 +58,10 @@ static void throw_out_of_memory() { g_memory_out_of_memory = true; } + __assume(0); + if (g_exit_when_out_of_memory) { std::cerr << g_out_of_memory_msg << "\n"; - __assume(0); exit(ERR_MEMOUT); } else { diff --git a/src/util/vector.h b/src/util/vector.h index 2d499a900..2e2640de3 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -72,6 +72,7 @@ class vector { SZ new_capacity = (3 * old_capacity + 1) >> 1; SZ new_capacity_T = sizeof(T) * new_capacity + sizeof(SZ) * 2; if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) { + UNREACHABLE(); throw default_exception("Overflow encountered when expanding vector"); } SZ *mem = (SZ*)memory::reallocate(reinterpret_cast(m_data)-2, new_capacity_T); From 42de2743076723171b91d9ec17cbd8468398a88a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Oct 2017 07:49:20 -0700 Subject: [PATCH 0255/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 1dbaefbce..6a68c30c9 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -221,6 +221,7 @@ namespace sat { literal root = c.lit(); if (root != null_literal && root.sign() == is_true) { c.negate(); + root.neg(); } if (root != null_literal) { if (!is_watched(root, c)) watch_literal(root, c); @@ -1563,10 +1564,6 @@ namespace sat { watch_literal(~lit, *c); } SASSERT(c->well_formed()); - if (c->id() == 1344) { - std::cout << "is watched: " << lit << " " << is_watched(lit, *c) << "\n"; - std::cout << "is watched: " << ~lit << " " << is_watched(~lit, *c) << "\n"; - } } @@ -1987,17 +1984,10 @@ namespace sat { } void ba_solver::unwatch_literal(literal lit, constraint& c) { - if (c.index() == 1344) { - std::cout << "unwatch: " << lit << "\n"; - } get_wlist(~lit).erase(watched(c.index())); } void ba_solver::watch_literal(literal lit, constraint& c) { - if (c.index() == 1344) { - std::cout << "watch: " << lit << "\n"; - } - get_wlist(~lit).push_back(watched(c.index())); } From a0cd6e0fca14003795f5651002232645544a17cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Oct 2017 16:47:23 -0700 Subject: [PATCH 0256/1283] adding outline for parallel tactic Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 4 +- src/sat/sat_lookahead.cpp | 2 + src/tactic/portfolio/CMakeLists.txt | 6 ++- src/tactic/portfolio/parallel_tactic.cpp | 48 +++++++++++++++++++++++ src/tactic/portfolio/parallel_tactic.h | 27 +++++++++++++ src/tactic/portfolio/solver2lookahead.cpp | 24 ++++++++++++ src/tactic/portfolio/solver2lookahead.h | 26 ++++++++++++ 7 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 src/tactic/portfolio/parallel_tactic.cpp create mode 100644 src/tactic/portfolio/parallel_tactic.h create mode 100644 src/tactic/portfolio/solver2lookahead.cpp create mode 100644 src/tactic/portfolio/solver2lookahead.h diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index d10bea7bb..424de0e7c 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -96,9 +96,9 @@ namespace sat { if (!c.frozen()) m_solver.detach_clause(c); // apply substitution - for (i = 0; i < sz; i++) { - SASSERT(!m_solver.was_eliminated(c[i].var())); + for (i = 0; i < sz; i++) { c[i] = norm(roots, c[i]); + SASSERT(!m_solver.was_eliminated(c[i].var())); } std::sort(c.begin(), c.end()); for (literal l : c) VERIFY(l == norm(roots, l)); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 596b9abe7..11fb7f008 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1623,6 +1623,8 @@ namespace sat { } void lookahead::reset_lookahead_reward() { + SASSERT(m_search_mode == lookahead_mode::lookahead1 || + m_search_mode == lookahead_mode::lookahead2); m_qhead = m_qhead_lim.back(); TRACE("sat", tout << "reset_lookahead_reward: " << m_qhead << "\n";); unsigned old_sz = m_trail_lim.back(); diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index 570db8f6a..c4ae795c6 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -1,11 +1,13 @@ z3_add_component(portfolio SOURCES + bounded_int2bv_solver.cpp default_tactic.cpp enum2bv_solver.cpp - pb2bv_solver.cpp - bounded_int2bv_solver.cpp fd_solver.cpp + parallel_tactic.cpp + pb2bv_solver.cpp smt_strategic_solver.cpp + solver2lookahead.cpp COMPONENT_DEPENDENCIES aig_tactic fp diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp new file mode 100644 index 000000000..497587cd3 --- /dev/null +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -0,0 +1,48 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + parallel_solver.cpp + +Abstract: + + Parallel solver in the style of Treengeling. + + It assumes a solver that supports good lookaheads. + + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ + +#include "solver/solver.h" +#include "tactic/tactic.h" + +class parallel_tactic : public tactic { + ref m_solver; +public: + parallel_tactic(solver* s) : m_solver(s) {} + + void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { + NOT_IMPLEMENTED_YET(); + } + + void cleanup() { + NOT_IMPLEMENTED_YET(); + } + + tactic* translate(ast_manager& m) { + NOT_IMPLEMENTED_YET(); + return 0; + } +}; + +tactic * mk_parallel_tactic(solver* s) { + return alloc(parallel_tactic, s); +} + diff --git a/src/tactic/portfolio/parallel_tactic.h b/src/tactic/portfolio/parallel_tactic.h new file mode 100644 index 000000000..a84c7be4d --- /dev/null +++ b/src/tactic/portfolio/parallel_tactic.h @@ -0,0 +1,27 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + parallel_tactic.h + +Abstract: + + Parallel tactic in the style of Treengeling. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ +#ifndef PARALLEL_TACTIC_H_ +#define PARALLEL_TACTIC_H_ + +class solver; +class tactic; + +tactic * mk_parallel_tactic(solver* s); + +#endif diff --git a/src/tactic/portfolio/solver2lookahead.cpp b/src/tactic/portfolio/solver2lookahead.cpp new file mode 100644 index 000000000..0c18ab079 --- /dev/null +++ b/src/tactic/portfolio/solver2lookahead.cpp @@ -0,0 +1,24 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + solver2lookahead.cpp + +Abstract: + + Lookahead wrapper for arbitrary solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ +#include "sat/sat_solver/inc_sat_solver.h" +#include "solver/solver.h" + +solver * mk_solver2lookahead(solver* s) { + return 0; +} diff --git a/src/tactic/portfolio/solver2lookahead.h b/src/tactic/portfolio/solver2lookahead.h new file mode 100644 index 000000000..80d73ddf3 --- /dev/null +++ b/src/tactic/portfolio/solver2lookahead.h @@ -0,0 +1,26 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + solver2lookahead.h + +Abstract: + + Lookahead wrapper for arbitrary solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ +#ifndef SOLVER2LOOKAHEAD_H_ +#define SOLVER2LOOKAHEAD_H_ + +class solver; + +solver * mk_solver2lookahead(solver* s); + +#endif From 8b32c15ac9483c26d3ae74023c9072c8629b0dd0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Oct 2017 11:49:31 -0700 Subject: [PATCH 0257/1283] use clause structure for nary Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 2 +- src/sat/sat_lookahead.cpp | 240 +++++++++++++++++++++-- src/sat/sat_lookahead.h | 53 ++++- src/tactic/portfolio/parallel_tactic.cpp | 178 ++++++++++++++++- 4 files changed, 455 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 424de0e7c..7eb307f85 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -98,7 +98,7 @@ namespace sat { // apply substitution for (i = 0; i < sz; i++) { c[i] = norm(roots, c[i]); - SASSERT(!m_solver.was_eliminated(c[i].var())); + VERIFY(!m_solver.was_eliminated(c[i].var())); } std::sort(c.begin(), c.end()); for (literal l : c) VERIFY(l == norm(roots, l)); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 11fb7f008..7ce2b53b9 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -312,10 +312,11 @@ namespace sat { } bool lookahead::is_unsat() const { - bool all_false = true; - bool first = true; // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. +#if OLD_NARY + bool all_false = true; + bool first = true; for (unsigned l_idx : m_nary_literals) { literal l = to_literal(l_idx); if (first) { @@ -332,6 +333,15 @@ namespace sat { all_false &= is_false(l); } } +#else + for (nary* n : m_nary_clauses) { + bool all_false = true; + for (literal l : *n) { + all_false &= is_false(l); + } + if (all_false) return true; + } +#endif // check if there is a ternary whose literals are false. for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -366,10 +376,11 @@ namespace sat { } } } - bool no_true = true; - bool first = true; // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. +#if OLD_NARY + bool no_true = true; + bool first = true; for (unsigned l_idx : m_nary_literals) { literal l = to_literal(l_idx); if (first) { @@ -385,6 +396,15 @@ namespace sat { no_true &= !is_true(l); } } +#else + for (nary * n : m_nary_clauses) { + bool no_true = true; + for (literal l : *n) { + no_true &= !is_true(l); + } + if (no_true) return false; + } +#endif // check if there is a ternary whose literals are false. for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -457,6 +477,7 @@ namespace sat { sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0; } sz = m_nary_count[(~l).index()]; +#if OLD_NARY for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; literal lit; @@ -470,6 +491,9 @@ namespace sat { unsigned len = m_nary_literals[idx]; sum += pow(0.5, len) * to_add / len; } +#else + +#endif return sum; } @@ -488,10 +512,17 @@ namespace sat { } sum += 0.25 * m_ternary_count[(~l).index()]; unsigned sz = m_nary_count[(~l).index()]; +#if OLD_NARY for (unsigned cls_idx : m_nary[(~l).index()]) { if (sz-- == 0) break; sum += pow(0.5, m_nary_literals[cls_idx]); } +#else + for (nary * n : m_nary[(~l).index()]) { + if (sz-- == 0) break; + sum += pow(0.5, n->size()); + } +#endif return sum; } @@ -866,8 +897,13 @@ namespace sat { m_ternary.push_back(svector()); m_ternary_count.push_back(0); m_ternary_count.push_back(0); +#if OLD_NARY m_nary.push_back(unsigned_vector()); m_nary.push_back(unsigned_vector()); +#else + m_nary.push_back(ptr_vector()); + m_nary.push_back(ptr_vector()); +#endif m_nary_count.push_back(0); m_nary_count.push_back(0); m_bstamp.push_back(0); @@ -1254,8 +1290,10 @@ namespace sat { // new n-ary clause managment void lookahead::add_clause(clause const& c) { + SASSERT(c.size() > 3); + +#if OLD_NARY unsigned sz = c.size(); - SASSERT(sz > 3); unsigned idx = m_nary_literals.size(); m_nary_literals.push_back(sz); for (literal l : c) { @@ -1264,7 +1302,15 @@ namespace sat { m_nary[l.index()].push_back(idx); SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size()); } - m_nary_literals.push_back(null_literal.index()); + m_nary_literals.push_back(null_literal.index()); +#else + void * mem = m_allocator.allocate(nary::get_obj_size(c.size())); + nary * n = new (mem) nary(c.size(), c.begin()); + m_nary_clauses.push_back(n); + for (literal l : c) { + m_nary[l.index()].push_back(n); + } +#endif } @@ -1274,6 +1320,7 @@ namespace sat { literal lit; SASSERT(m_search_mode == lookahead_mode::searching); +#if OLD_NARY for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; unsigned len = --m_nary_literals[idx]; @@ -1323,12 +1370,69 @@ namespace sat { } } } +#else + for (nary * n : m_nary[(~l).index()]) { + if (sz-- == 0) break; + unsigned len = n->dec_size(); + if (m_inconsistent) continue; + if (len <= 1) continue; // already processed + // find the two unassigned literals, if any + if (len == 2) { + literal l1 = null_literal; + literal l2 = null_literal; + bool found_true = false; + for (literal lit : *n) { + if (!is_fixed(lit)) { + if (l1 == null_literal) { + l1 = lit; + } + else { + SASSERT(l2 == null_literal); + l2 = lit; + break; + } + } + else if (is_true(lit)) { + n->set_head(lit); + found_true = true; + break; + } + } + if (found_true) { + // skip, the clause will be removed when propagating on 'lit' + } + else if (l1 == null_literal) { + set_conflict(); + } + else if (l2 == null_literal) { + // clause may get revisited during propagation, when l2 is true in this clause. + // m_removed_clauses.push_back(std::make_pair(~l, idx)); + // remove_clause_at(~l, idx); + propagated(l1); + } + else { + // extract binary clause. A unary or empty clause may get revisited, + // but we skip it then because it is already handled as a binary clause. + // m_removed_clauses.push_back(std::make_pair(~l, idx)); // need to restore this clause. + // remove_clause_at(~l, idx); + try_add_binary(l1, l2); + } + } + } +#endif // clauses where l is positive: sz = m_nary_count[l.index()]; +#if OLD_NARY for (unsigned idx : m_nary[l.index()]) { if (sz-- == 0) break; remove_clause_at(l, idx); } +#else + for (nary* n : m_nary[l.index()]) { + if (sz-- == 0) break; + remove_clause_at(l, *n); + } +#endif } void lookahead::propagate_clauses_lookahead(literal l) { @@ -1338,6 +1442,7 @@ namespace sat { SASSERT(m_search_mode == lookahead_mode::lookahead1 || m_search_mode == lookahead_mode::lookahead2); +#if OLD_NARY for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; literal l1 = null_literal; @@ -1404,9 +1509,75 @@ namespace sat { } } } +#else + for (nary* n : m_nary[(~l).index()]) { + if (sz-- == 0) break; + literal l1 = null_literal; + literal l2 = null_literal; + bool found_true = false; + unsigned nonfixed = 0; + for (literal lit : *n) { + if (!is_fixed(lit)) { + ++nonfixed; + if (l1 == null_literal) { + l1 = lit; + } + else if (l2 == null_literal) { + l2 = lit; + } + } + else if (is_true(lit)) { + found_true = true; + break; + } + } + if (found_true) { + // skip, the clause will be removed when propagating on 'lit' + } + else if (l1 == null_literal) { + set_conflict(); + return; + } + else if (l2 == null_literal) { + propagated(l1); + } + else if (m_search_mode == lookahead_mode::lookahead2) { + continue; + } + else { + SASSERT(nonfixed >= 2); + SASSERT(m_search_mode == lookahead_mode::lookahead1); + switch (m_config.m_reward_type) { + case heule_schur_reward: { + double to_add = 0; + for (literal lit : *n) { + if (!is_fixed(lit)) { + to_add += literal_occs(lit); + } + } + m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed; + break; + } + case heule_unit_reward: + m_lookahead_reward += pow(0.5, nonfixed); + break; + case ternary_reward: + if (nonfixed == 2) { + m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + } + else { + m_lookahead_reward += (double)0.001; + } + break; + case unit_literal_reward: + break; + } + } + } +#endif } - +#if OLD_NARY void lookahead::remove_clause_at(literal l, unsigned clause_idx) { unsigned j = clause_idx; literal lit; @@ -1429,21 +1600,50 @@ namespace sat { } UNREACHABLE(); } +#else + + void lookahead::remove_clause_at(literal l, nary& n) { + for (literal lit : n) { + if (lit != l) { + remove_clause(lit, n); + } + } + } + + void lookahead::remove_clause(literal l, nary& n) { + ptr_vector& pclauses = m_nary[l.index()]; + unsigned sz = m_nary_count[l.index()]--; + for (unsigned i = sz; i > 0; ) { + --i; + if (&n == pclauses[i]) { + std::swap(pclauses[i], pclauses[sz-1]); + return; + } + } + UNREACHABLE(); + } +#endif void lookahead::restore_clauses(literal l) { SASSERT(m_search_mode == lookahead_mode::searching); - // increase the length of clauses where l is negative unsigned sz = m_nary_count[(~l).index()]; +#if OLD_NARY for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; ++m_nary_literals[idx]; } - +#else + for (nary* n : m_nary[(~l).index()]) { + if (sz-- == 0) break; + n->inc_size(); + } +#endif // add idx back to clause list where l is positive // add them back in the same order as they were inserted // in this way we can check that the clauses are the same. sz = m_nary_count[l.index()]; +#if OLD_NARY unsigned_vector const& pclauses = m_nary[l.index()]; for (unsigned i = sz; i > 0; ) { --i; @@ -1456,6 +1656,17 @@ namespace sat { } } } +#else + ptr_vector& pclauses = m_nary[l.index()]; + for (unsigned i = sz; i-- > 0; ) { + for (literal lit : *pclauses[i]) { + if (lit != l) { + // SASSERT(m_nary[lit.index()] == pclauses[i]); + m_nary_count[lit.index()]++; + } + } + } +#endif } void lookahead::propagate_clauses(literal l) { @@ -1527,7 +1738,7 @@ namespace sat { // Sum_{ clause C that contains ~l } 1 double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); - unsigned_vector const& nclauses = m_nary[(~l).index()]; + // unsigned_vector const& nclauses = m_nary[(~l).index()]; result += m_nary_count[(~l).index()]; result += m_ternary_count[(~l).index()]; return result; @@ -1684,7 +1895,7 @@ namespace sat { return false; #if 0 // no propagations are allowed to reduce clauses. - for (clause * cp : m_full_watches[l.index()]) { + for (nary * cp : m_nary[(~l).index()]) { clause& c = *cp; unsigned sz = c.size(); bool found = false; @@ -2026,6 +2237,7 @@ namespace sat { } } +#if OLD_NARY for (unsigned l_idx : m_nary_literals) { literal l = to_literal(l_idx); if (first) { @@ -2041,6 +2253,12 @@ namespace sat { out << l << " "; } } +#else + for (nary * n : m_nary_clauses) { + for (literal l : *n) out << l << " "; + out << "\n"; + } +#endif return out; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 9a50dceed..2972bc167 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,6 +20,7 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ +#define OLD_NARY 0 #include "sat_elim_eqs.h" @@ -129,6 +130,36 @@ namespace sat { literal m_u, m_v; }; + class nary { + unsigned m_size; // number of non-false literals + size_t m_obj_size; // object size (counting all literals) + literal m_head; // head literal + literal m_literals[0]; // list of literals, put any true literal in head. + size_t num_lits() const { + return (m_obj_size - sizeof(nary)) / sizeof(literal); + } + public: + static size_t get_obj_size(unsigned sz) { return sizeof(nary) + sz * sizeof(literal); } + size_t obj_size() const { return m_obj_size; } + nary(unsigned sz, literal const* lits): + m_size(sz), + m_obj_size(get_obj_size(sz)) { + for (unsigned i = 0; i < sz; ++i) m_literals[i] = lits[i]; + m_head = lits[0]; + } + unsigned size() const { return m_size; } + unsigned dec_size() { SASSERT(m_size > 0); return --m_size; } + void inc_size() { SASSERT(m_size < num_lits()); ++m_size; } + literal get_head() const { return m_head; } + void set_head(literal l) { m_head = l; } + + literal operator[](unsigned i) { SASSERT(i < num_lits()); return m_literals[i]; } + literal const* begin() const { return m_literals; } + literal const* end() const { return m_literals + num_lits(); } + // swap the true literal to the head. + // void swap(unsigned i, unsigned j) { SASSERT(i < num_lits() && j < num_lits()); std::swap(m_literals[i], m_literals[j]); } + }; + struct cube_state { bool m_first; svector m_is_decision; @@ -160,11 +191,18 @@ namespace sat { vector> m_ternary; // lit |-> vector of ternary clauses unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit +#if OLD_NARY vector m_nary; // lit |-> vector of clause_id - unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_clauses2[lit] unsigned_vector m_nary_literals; // the actual literals, clauses start at offset clause_id, // the first entry is the current length, clauses are separated by a null_literal +#else + small_object_allocator m_allocator; + vector> m_nary; // lit |-> vector of nary clauses + ptr_vector m_nary_clauses; // vector of all nary clauses +#endif + unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_nary[lit] + unsigned m_num_tc1; unsigned_vector m_num_tc1_lim; unsigned m_qhead; // propagation queue head @@ -410,15 +448,20 @@ namespace sat { void propagate_clauses_searching(literal l); void propagate_clauses_lookahead(literal l); void restore_clauses(literal l); +#if OLD_NARY void remove_clause(literal l, unsigned clause_idx); void remove_clause_at(literal l, unsigned clause_idx); - +#else + void remove_clause(literal l, nary& n); + void remove_clause_at(literal l, nary& n); +#endif // ------------------------------------ // initialization void init_var(bool_var v); void init(); void copy_clauses(clause_vector const& clauses, bool learned); + nary * copy_clause(clause const& c); // ------------------------------------ // search @@ -499,6 +542,12 @@ namespace sat { ~lookahead() { m_s.rlimit().pop_child(); +#if OLD_NARY +#else + for (nary* n : m_nary_clauses) { + m_allocator.deallocate(n->obj_size(), n); + } +#endif } diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 497587cd3..c8cb7e2ee 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -3,11 +3,11 @@ Copyright (c) 2017 Microsoft Corporation Module Name: - parallel_solver.cpp + parallel_tactic.cpp Abstract: - Parallel solver in the style of Treengeling. + Parallel tactic in the style of Treengeling. It assumes a solver that supports good lookaheads. @@ -20,13 +20,183 @@ Notes: --*/ +#include "util/scoped_ptr_vector.h" #include "solver/solver.h" #include "tactic/tactic.h" class parallel_tactic : public tactic { - ref m_solver; + + // parameters + unsigned m_conflicts_lower_bound; + unsigned m_conflicts_upper_bound; + unsigned m_conflicts_growth_rate; + unsigned m_conflicts_decay_rate; + unsigned m_num_threads; + + unsigned m_max_conflicts; + + sref_vector m_solvers; + scoped_ptr_vector m_managers; + + void init() { + m_conflicts_lower_bound = 1000; + m_conflicts_upper_bound = 10000; + m_conflicts_growth_rate = 150; + m_conflicts_decay_rate = 75; + m_max_conflicts = m_conflicts_lower_bound; + m_num_threads = omp_get_num_threads(); + } + + unsigned get_max_conflicts() { + return m_max_conflicts; + } + + void set_max_conflicts(unsigned c) { + m_max_conflicts = c; + } + + bool should_increase_conflicts() { + NOT_IMPLEMENTED_YET(); + return false; + } + + int pick_solvers() { + NOT_IMPLEMENTED_YET(); + return 1; + } + + void update_max_conflicts() { + if (should_increase_conflicts()) { + set_max_conflicts(std::min(m_conflicts_upper_bound, m_conflicts_growth_rate * get_max_conflicts() / 100)); + } + else { + set_max_conflicts(std::max(m_conflicts_lower_bound, m_conflicts_decay_rate * get_max_conflicts() / 100)); + } + } + + lbool simplify(solver& s) { + params_ref p; + p.set_uint("sat.max_conflicts", 10); + p.set_bool("sat.lookahead_simplify", true); + s.updt_params(p); + lbool is_sat = s.check_sat(0,0); + p.set_uint("sat.max_conflicts", get_max_conflicts()); + p.set_bool("sat.lookahead_simplify", false); + s.updt_params(p); + return is_sat; + } + + lbool lookahead(solver& s) { + ast_manager& m = s.get_manager(); + params_ref p; + p.set_uint("sat.lookahead.cube.cutoff", 1); + expr_ref_vector cubes(m); + while (true) { + expr_ref c = s.cube(); + if (m.is_false(c)) { + break; + } + cubes.push_back(c); + } + if (cubes.empty()) { + return l_false; + } + for (unsigned i = 1; i < cubes.size(); ++i) { + ast_manager * new_m = alloc(ast_manager, m, !m.proof_mode()); + solver* s1 = s.translate(*new_m, params_ref()); + ast_translation translate(m, *new_m); + expr_ref cube(translate(cubes[i].get()), *new_m); + s1->assert_expr(cube); + + #pragma omp critical (_solvers) + { + m_managers.push_back(new_m); + m_solvers.push_back(s1); + } + } + s.assert_expr(cubes[0].get()); + return l_true; + } + + lbool solve(solver& s) { + params_ref p; + p.set_uint("sat.max_conflicts", get_max_conflicts()); + s.updt_params(p); + lbool is_sat = s.check_sat(0, 0); + return is_sat; + } + + void remove_unsat(svector& unsat) { + std::sort(unsat.begin(), unsat.end()); + unsat.reverse(); + DEBUG_CODE(for (unsigned i = 0; i + 1 < unsat.size(); ++i) SASSERT(unsat[i] > unsat[i+1]);); + for (int i : unsat) { + m_solvers.erase(i); + } + unsat.reset(); + } + + lbool solve() { + while (true) { + int sz = pick_solvers(); + + if (sz == 0) { + return l_false; + } + svector unsat; + int sat_index = -1; + + // Simplify phase. + #pragma omp parallel for + for (int i = 0; i < sz; ++i) { + lbool is_sat = simplify(*m_solvers[i]); + switch (is_sat) { + case l_false: unsat.push_back(i); break; + case l_true: sat_index = i; break; + case l_undef: break; + } + } + if (sat_index != -1) return l_true; // TBD: extact model + sz -= unsat.size(); + remove_unsat(unsat); + if (sz == 0) continue; + + // Solve phase. + #pragma omp parallel for + for (int i = 0; i < sz; ++i) { + lbool is_sat = solve(*m_solvers[i]); + switch (is_sat) { + case l_false: unsat.push_back(i); break; + case l_true: sat_index = i; break; + case l_undef: break; + } + } + if (sat_index != -1) return l_true; // TBD: extact model + sz -= unsat.size(); + remove_unsat(unsat); + if (sz == 0) continue; + + // Split phase. + #pragma omp parallel for + for (int i = 0; i < sz; ++i) { + lbool is_sat = lookahead(*m_solvers[i]); + switch (is_sat) { + case l_false: unsat.push_back(i); break; + case l_true: break; + case l_undef: break; + } + } + remove_unsat(unsat); + + update_max_conflicts(); + } + return l_undef; + } + public: - parallel_tactic(solver* s) : m_solver(s) {} + parallel_tactic(solver* s) { + m_solvers.push_back(s); // clone it? + } void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { NOT_IMPLEMENTED_YET(); From 01897831fb58de35c0202a1fbdfb71f0fa5f64b4 Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Tue, 10 Oct 2017 15:59:53 -0700 Subject: [PATCH 0258/1283] Dynamic delta trigger decrease --- src/sat/sat_lookahead.cpp | 5 ++++- src/sat/sat_lookahead.h | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 59149ec0f..63b013ca0 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -914,6 +914,7 @@ namespace sat { void lookahead::init() { m_delta_trigger = 0.0; + m_delta_decrease = 0.0; m_config.m_dl_success = 0.8; m_inconsistent = false; m_qhead = 0; @@ -1608,6 +1609,7 @@ namespace sat { void lookahead::compute_lookahead_reward() { init_lookahead_reward(); TRACE("sat", display_lookahead(tout); ); + m_delta_decrease = pow(m_config.m_delta_rho, 1.0 / (double)m_lookahead.size()); unsigned base = 2; bool change = true; literal last_changed = null_literal; @@ -1811,7 +1813,8 @@ namespace sat { } } else { - m_delta_trigger *= m_config.m_delta_rho; + SASSERT(m_delta_decrease > 0.0); + m_delta_trigger *= m_delta_decrease; } } } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 4011996bb..76f5437b5 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -89,7 +89,7 @@ namespace sat { m_min_cutoff = 30; m_preselect = false; m_level_cand = 600; - m_delta_rho = (double)0.99995; + m_delta_rho = (double)0.25; m_dl_max_iterations = 2; m_tc1_limit = 10000000; m_reward_type = ternary_reward; @@ -146,7 +146,8 @@ namespace sat { }; config m_config; - double m_delta_trigger; + double m_delta_trigger; + double m_delta_decrease; drat m_drat; literal_vector m_assumptions; From 97f37613c2915f6270fd5d6f82057e1382a5a1cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Oct 2017 07:50:04 -0700 Subject: [PATCH 0259/1283] parallel Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/parallel_tactic.cpp | 116 +++++++++++++++-------- src/tactic/portfolio/parallel_tactic.h | 6 +- 2 files changed, 82 insertions(+), 40 deletions(-) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 5cd508042..1ee6cbfef 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -30,19 +30,16 @@ Notes: class parallel_tactic : public tactic { class solver_state { + scoped_ptr m_manager; ref m_solver; expr_ref_vector m_cube; unsigned m_units; public: - solver_state(solver* s): m_solver(s), m_cube(s->get_manager()), m_units(0) {} - - solver_state& operator=(solver_state& other) { - m_solver = other.m_solver; - m_cube.reset(); - m_cube.append(other.m_cube); - m_units = other.m_units; - return *this; - } + solver_state(ast_manager* m, solver* s): + m_manager(m), + m_solver(s), + m_cube(s->get_manager()), + m_units(0) {} void update_units() { m_units = 0; @@ -66,6 +63,21 @@ class parallel_tactic : public tactic { solver& get_solver() { return *m_solver; } solver const& get_solver() const { return *m_solver; } + + solver_state* clone(params_ref& p, expr* cube) { + ast_manager& m = m_solver->get_manager(); + ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); + solver* s = m_solver->translate(*new_m, p); + solver_state* st = alloc(solver_state, new_m, s); + ast_translation translate(m, *new_m); + for (expr* c : m_cube) { + st->m_cube.push_back(translate(c)); + } + expr_ref cube1(translate(cube), *new_m); + st->m_cube.push_back(cube1); + s->assert_expr(cube1); + return st; + } }; public: @@ -74,7 +86,8 @@ public: } private: - ast_manager* m_manager; + ast_manager& m_manager; + params_ref m_params; // parameters unsigned m_conflicts_lower_bound; @@ -84,11 +97,10 @@ private: unsigned m_num_threads; double m_progress; - unsigned m_max_conflicts; + unsigned m_max_conflicts; statistics m_stats; vector m_solvers; - scoped_ptr_vector m_managers; void init() { m_conflicts_lower_bound = 1000; @@ -114,6 +126,9 @@ private: void update_progress(bool b) { m_progress = 0.9 * m_progress + (b ? 1 : -1); + if (b) { + m_stats.update("closed", 1u); + } } int pick_solvers() { @@ -157,6 +172,7 @@ private: lbool simplify(solver& s) { params_ref p; + p.copy(m_params); p.set_uint("sat.max_conflicts", 10); p.set_bool("sat.lookahead_simplify", true); s.updt_params(p); @@ -170,6 +186,7 @@ private: void cube(solver& s, expr_ref_vector& cubes) { ast_manager& m = s.get_manager(); params_ref p; + p.copy(m_params); p.set_uint("sat.lookahead.cube.cutoff", 1); s.updt_params(p); while (true) { @@ -177,12 +194,18 @@ private: if (m.is_false(c)) { break; } + if (m.is_true(c)) { + cubes.reset(); + cubes.push_back(c); + break; + } cubes.push_back(c); } } lbool solve(solver& s) { params_ref p; + p.copy(m_params); p.set_uint("sat.max_conflicts", get_max_conflicts()); s.updt_params(p); return s.check_sat(0, 0); @@ -199,6 +222,7 @@ private: m_solvers[j - 1] = m_solvers[j]; } m_solvers.shrink(m_solvers.size() - 1); + update_progress(true); } unsat.reset(); } @@ -206,7 +230,7 @@ private: void get_model(model_ref& mdl, int sat_index) { SASSERT(sat_index != -1); m_solvers[sat_index]->get_solver().get_model(mdl); - ast_translation translate(m_solvers[sat_index]->get_solver().get_manager(), *m_manager); + ast_translation translate(m_solvers[sat_index]->get_solver().get_manager(), m_manager); mdl = mdl->translate(translate); } @@ -226,9 +250,17 @@ private: for (int i = 0; i < sz; ++i) { lbool is_sat = simplify(m_solvers[i]->get_solver()); switch (is_sat) { - case l_false: unsat.push_back(i); break; - case l_true: sat_index = i; break; - case l_undef: break; + case l_false: + #pragma omp critical (parallel_tactic) + { + unsat.push_back(i); + } + break; + case l_true: + sat_index = i; + break; + case l_undef: + break; } } if (sat_index != -1) { @@ -245,9 +277,21 @@ private: for (int i = 0; i < sz; ++i) { lbool is_sat = solve(m_solvers[i]->get_solver()); switch (is_sat) { - case l_false: update_progress(true); unsat.push_back(i); break; - case l_true: sat_index = i; break; - case l_undef: update_progress(false); break; + case l_false: + #pragma omp critical (parallel_tactic) + { + unsat.push_back(i); + } + break; + case l_true: + sat_index = i; + break; + case l_undef: + #pragma omp critical (parallel_tactic) + { + update_progress(false); + } + break; } } if (sat_index != -1) { @@ -279,16 +323,11 @@ private: } solver& s = m_solvers[i]->get_solver(); ast_manager& m = s.get_manager(); + if (cubes[i].size() == 1 && m.is_true(cubes[i][0].get())) { + continue; + } for (unsigned j = 1; j < cubes[i].size(); ++j) { - ast_manager * new_m = alloc(ast_manager, m, !m.proof_mode()); - solver* s1 = s.translate(*new_m, params_ref()); - ast_translation translate(m, *new_m); - expr_ref cube(translate(cubes[i][j].get()), *new_m); - s1->assert_expr(cube); - m_managers.push_back(new_m); - solver_state* st = alloc(solver_state, s1); - st->add_cube(cube); - m_solvers.push_back(st); + m_solvers.push_back(m_solvers[i]->clone(m_params, cubes[i][j].get())); } expr* cube0 = cubes[i][0].get(); m_solvers[i]->add_cube(cube0); @@ -305,22 +344,22 @@ private: out << "solver units" << s->num_units() << "\n"; out << "cube " << s->cube() << "\n"; } + m_stats.display(out); return out; } public: - parallel_tactic() : - m_manager(0) { + parallel_tactic(ast_manager& m, params_ref const& p) : + m_manager(m), + m_params(p) { init(); } void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { ast_manager& m = g->m(); - m_manager = &m; - params_ref p; - solver* s = mk_fd_solver(m, p); - m_solvers.push_back(alloc(solver_state, s)); + solver* s = mk_fd_solver(m, m_params); + m_solvers.push_back(alloc(solver_state, 0, s)); expr_ref_vector clauses(m); ptr_vector assumptions; obj_map bool2dep; @@ -359,15 +398,14 @@ public: for (solver_state * s : m_solvers) dealloc(s); m_solvers.reset(); init(); - m_manager = nullptr; } tactic* translate(ast_manager& m) { - return alloc(parallel_tactic); + return alloc(parallel_tactic, m, m_params); } virtual void updt_params(params_ref const & p) { - // TBD + m_params.copy(p); } virtual void collect_param_descrs(param_descrs & r) { // TBD @@ -385,7 +423,7 @@ public: }; -tactic * mk_parallel_tactic() { - return alloc(parallel_tactic); +tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p) { + return alloc(parallel_tactic, m, p); } diff --git a/src/tactic/portfolio/parallel_tactic.h b/src/tactic/portfolio/parallel_tactic.h index 063d1480f..8fd9a29fa 100644 --- a/src/tactic/portfolio/parallel_tactic.h +++ b/src/tactic/portfolio/parallel_tactic.h @@ -22,6 +22,10 @@ Notes: class solver; class tactic; -tactic * mk_parallel_tactic(); +tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p); + +/* + ADD_TACTIC("qffdp", "builtin strategy for solving QF_FD problems in parallel.", "mk_parallel_tactic(m, p)") +*/ #endif From 79ceaa1d1394d7b51e5c1b90c98c64188776509e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Oct 2017 13:17:57 -0700 Subject: [PATCH 0260/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 4 +- src/sat/tactic/goal2sat.cpp | 29 +++--- src/tactic/portfolio/CMakeLists.txt | 1 + src/tactic/portfolio/parallel_tactic.cpp | 116 +++++++++++++---------- 4 files changed, 89 insertions(+), 61 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4447b399c..3812eff56 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1468,11 +1468,14 @@ namespace sat { lh.simplify(); lh.collect_statistics(m_aux_stats); } +#if 0 + // Buggy { lookahead lh(*this); lh.scc(); lh.collect_statistics(m_aux_stats); } +#endif } @@ -3049,7 +3052,6 @@ namespace sat { m_probing.updt_params(p); m_scc.updt_params(p); m_rand.set_seed(m_config.m_random_seed); - m_step_size = m_config.m_step_size_init; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 75561ed86..81302764a 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -94,6 +94,12 @@ struct goal2sat::imp { std::string s0 = "operator " + s + " not supported, apply simplifier before invoking translator"; throw tactic_exception(s0.c_str()); } + + sat::bool_var mk_var(expr* t, bool ext) { + sat::bool_var v = m_solver.mk_var(ext); + m_map.insert(t, v); + return v; + } void mk_clause(sat::literal l) { TRACE("goal2sat", tout << "mk_clause: " << l << "\n";); @@ -120,7 +126,7 @@ struct goal2sat::imp { sat::bool_var mk_true() { if (m_true == sat::null_bool_var) { // create fake variable to represent true; - m_true = m_solver.mk_var(); + m_true = mk_var(m.mk_true(), false); mk_clause(sat::literal(m_true, false)); // v is true } return m_true; @@ -139,8 +145,7 @@ struct goal2sat::imp { } else { bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t); - sat::bool_var v = m_solver.mk_var(ext); - m_map.insert(t, v); + sat::bool_var v = mk_var(t, ext); l = sat::literal(v, sign); TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";); if (ext && !is_uninterp_const(t)) { @@ -247,7 +252,7 @@ struct goal2sat::imp { } else { SASSERT(num <= m_result_stack.size()); - sat::bool_var k = m_solver.mk_var(); + sat::bool_var k = mk_var(t, false); sat::literal l(k, false); m_cache.insert(t, l); sat::literal * lits = m_result_stack.end() - num; @@ -286,7 +291,7 @@ struct goal2sat::imp { } else { SASSERT(num <= m_result_stack.size()); - sat::bool_var k = m_solver.mk_var(); + sat::bool_var k = mk_var(t, false); sat::literal l(k, false); m_cache.insert(t, l); // l => /\ lits @@ -330,7 +335,7 @@ struct goal2sat::imp { m_result_stack.reset(); } else { - sat::bool_var k = m_solver.mk_var(); + sat::bool_var k = mk_var(n, false); sat::literal l(k, false); m_cache.insert(n, l); mk_clause(~l, ~c, t); @@ -367,7 +372,7 @@ struct goal2sat::imp { m_result_stack.reset(); } else { - sat::bool_var k = m_solver.mk_var(); + sat::bool_var k = mk_var(t, false); sat::literal l(k, false); m_cache.insert(t, l); mk_clause(~l, l1, ~l2); @@ -392,7 +397,7 @@ struct goal2sat::imp { } sat::literal_vector lits; convert_pb_args(num, lits); - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); ensure_extension(); if (lits.size() % 2 == 0) lits[0].neg(); m_ext->add_xor(v, lits); @@ -451,7 +456,7 @@ struct goal2sat::imp { m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); } else { - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -476,7 +481,7 @@ struct goal2sat::imp { m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); } else { - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -525,7 +530,7 @@ struct goal2sat::imp { m_ext->add_at_least(sat::null_bool_var, lits, k.get_unsigned()); } else { - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -547,7 +552,7 @@ struct goal2sat::imp { m_ext->add_at_least(sat::null_bool_var, lits, lits.size() - k.get_unsigned()); } else { - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); m_result_stack.shrink(sz - t->get_num_args()); diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index c4ae795c6..055251467 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -21,4 +21,5 @@ z3_add_component(portfolio TACTIC_HEADERS default_tactic.h fd_solver.h + parallel_tactic.h ) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 1ee6cbfef..524754613 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -30,12 +30,14 @@ Notes: class parallel_tactic : public tactic { class solver_state { + params_ref m_params; scoped_ptr m_manager; ref m_solver; expr_ref_vector m_cube; unsigned m_units; public: - solver_state(ast_manager* m, solver* s): + solver_state(ast_manager* m, solver* s, params_ref const& p): + m_params(p), m_manager(m), m_solver(s), m_cube(s->get_manager()), @@ -49,6 +51,7 @@ class parallel_tactic : public tactic { for (unsigned i = st.size(); i-- > 0; ) { if (st.get_key(i) == units) { m_units = st.get_uint_value(i); + std::cout << "value for " << i << " is " << m_units << "\n"; break; } } @@ -64,15 +67,17 @@ class parallel_tactic : public tactic { solver const& get_solver() const { return *m_solver; } - solver_state* clone(params_ref& p, expr* cube) { + params_ref const& params() const { return m_params; } + + solver_state* clone(params_ref const& p, expr* cube) { ast_manager& m = m_solver->get_manager(); ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); solver* s = m_solver->translate(*new_m, p); - solver_state* st = alloc(solver_state, new_m, s); + solver_state* st = alloc(solver_state, new_m, s, m_params); ast_translation translate(m, *new_m); for (expr* c : m_cube) { st->m_cube.push_back(translate(c)); - } + } expr_ref cube1(translate(cube), *new_m); st->m_cube.push_back(cube1); s->assert_expr(cube1); @@ -109,7 +114,7 @@ private: m_conflicts_decay_rate = 75; m_max_conflicts = m_conflicts_lower_bound; m_progress = 0; - m_num_threads = omp_get_num_threads(); // TBD adjust by possible threads used inside each solver. + m_num_threads = omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. } unsigned get_max_conflicts() { @@ -173,40 +178,60 @@ private: lbool simplify(solver& s) { params_ref p; p.copy(m_params); - p.set_uint("sat.max_conflicts", 10); - p.set_bool("sat.lookahead_simplify", true); + p.set_uint("max_conflicts", 10); + p.set_bool("lookahead_simplify", true); s.updt_params(p); lbool is_sat = s.check_sat(0,0); - p.set_uint("sat.max_conflicts", get_max_conflicts()); - p.set_bool("sat.lookahead_simplify", false); + p.set_uint("max_conflicts", get_max_conflicts()); + p.set_bool("lookahead_simplify", false); s.updt_params(p); return is_sat; } - void cube(solver& s, expr_ref_vector& cubes) { - ast_manager& m = s.get_manager(); - params_ref p; - p.copy(m_params); - p.set_uint("sat.lookahead.cube.cutoff", 1); - s.updt_params(p); + lbool cube(solver_state& s) { + ast_manager& m = s.get_solver().get_manager(); + expr_ref_vector cubes(m); + params_ref p; + p.copy(s.params()); + p.set_uint("lookahead.cube.cutoff", 1); + s.get_solver().updt_params(p); + SASSERT(&m == &cubes.get_manager()); while (true) { - expr_ref c = s.cube(); - if (m.is_false(c)) { + expr_ref c = s.get_solver().cube(); + VERIFY(c); + if (m.is_false(c)) { break; } if (m.is_true(c)) { cubes.reset(); - cubes.push_back(c); - break; + return l_undef; } cubes.push_back(c); } + + IF_VERBOSE(1, verbose_stream() << "cubes: " << cubes << "\n";); + + if (cubes.empty()) { + return l_false; + } + for (unsigned j = 1; j < cubes.size(); ++j) { + solver_state* s1 = s.clone(s.params(), cubes[j].get()); + #pragma omp critical (parallel_tactic) + { + m_solvers.push_back(s1); + } + } + + expr* cube0 = cubes[0].get(); + s.add_cube(cube0); + s.get_solver().assert_expr(cube0); + return l_undef; } lbool solve(solver& s) { params_ref p; p.copy(m_params); - p.set_uint("sat.max_conflicts", get_max_conflicts()); + p.set_uint("max_conflicts", get_max_conflicts()); s.updt_params(p); return s.check_sat(0, 0); } @@ -238,6 +263,7 @@ private: while (true) { int sz = pick_solvers(); + if (sz == 0) { return l_false; } @@ -246,6 +272,8 @@ private: // Simplify phase. IF_VERBOSE(1, verbose_stream() << "(solver.parallel :simplify " << sz << ")\n";); + IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); + #pragma omp parallel for for (int i = 0; i < sz; ++i) { lbool is_sat = simplify(m_solvers[i]->get_solver()); @@ -273,6 +301,8 @@ private: // Solve phase. IF_VERBOSE(1, verbose_stream() << "(solver.parallel :solve " << sz << ")\n";); + IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); + #pragma omp parallel for for (int i = 0; i < sz; ++i) { lbool is_sat = solve(m_solvers[i]->get_solver()); @@ -287,10 +317,6 @@ private: sat_index = i; break; case l_undef: - #pragma omp critical (parallel_tactic) - { - update_progress(false); - } break; } } @@ -304,35 +330,29 @@ private: sz = std::min(max_num_splits(), sz); if (sz == 0) continue; - vector cubes; - for (int i = 0; i < sz; ++i) { - cubes.push_back(expr_ref_vector(m_solvers[i]->get_solver().get_manager())); - } // Split phase. IF_VERBOSE(1, verbose_stream() << "(solver.parallel :split " << sz << ")\n";); + IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); + #pragma omp parallel for for (int i = 0; i < sz; ++i) { - cube(m_solvers[i]->get_solver(), cubes[i]); + switch (cube(*m_solvers[i])) { + case l_false: + #pragma omp critical (parallel_tactic) + { + unsat.push_back(i); + } + break; + default: + #pragma omp critical (parallel_tactic) + { + update_progress(false); + } + break; + } } - for (int i = 0; i < sz; ++i) { - if (cubes[i].empty()) { - unsat.push_back(i); - continue; - } - solver& s = m_solvers[i]->get_solver(); - ast_manager& m = s.get_manager(); - if (cubes[i].size() == 1 && m.is_true(cubes[i][0].get())) { - continue; - } - for (unsigned j = 1; j < cubes[i].size(); ++j) { - m_solvers.push_back(m_solvers[i]->clone(m_params, cubes[i][j].get())); - } - expr* cube0 = cubes[i][0].get(); - m_solvers[i]->add_cube(cube0); - s.assert_expr(cube0); - } remove_unsat(unsat); update_max_conflicts(); } @@ -341,7 +361,7 @@ private: std::ostream& display(std::ostream& out) { for (solver_state* s : m_solvers) { - out << "solver units" << s->num_units() << "\n"; + out << "solver units " << s->num_units() << "\n"; out << "cube " << s->cube() << "\n"; } m_stats.display(out); @@ -359,7 +379,7 @@ public: void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { ast_manager& m = g->m(); solver* s = mk_fd_solver(m, m_params); - m_solvers.push_back(alloc(solver_state, 0, s)); + m_solvers.push_back(alloc(solver_state, 0, s, m_params)); expr_ref_vector clauses(m); ptr_vector assumptions; obj_map bool2dep; From 81ad69214c15831076beaa6839546ebbe099e698 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Oct 2017 17:06:28 -0700 Subject: [PATCH 0261/1283] fixing lookahead/ba + parallel Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 5 ++++ src/sat/sat_lookahead.cpp | 29 ++++++++++++++++++------ src/sat/sat_lookahead.h | 3 ++- src/sat/sat_solver.cpp | 8 ++++--- src/sat/sat_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 6 ++++- src/sat/tactic/goal2sat.cpp | 29 ++++++++++-------------- src/tactic/portfolio/parallel_tactic.cpp | 3 +-- 8 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 6a68c30c9..a2058512b 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -300,6 +300,10 @@ namespace sat { void ba_solver::set_conflict(constraint& c, literal lit) { m_stats.m_num_conflicts++; TRACE("ba", display(tout, c, true); ); + if (!validate_conflict(c)) { + display(std::cout, c, true); + UNREACHABLE(); + } SASSERT(validate_conflict(c)); if (c.is_xor() && value(lit) == l_true) lit.neg(); SASSERT(value(lit) == l_false); @@ -645,6 +649,7 @@ namespace sat { display(verbose_stream(), p, true); verbose_stream() << "alit: " << alit << "\n"; verbose_stream() << "num watch " << num_watch << "\n"); + UNREACHABLE(); exit(0); return l_undef; } diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 0374aca9c..d0f4bc7f6 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -92,7 +92,7 @@ namespace sat { // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n");); literal_vector & lits = m_binary[idx]; SASSERT(!lits.empty()); - literal l = lits.back(); + literal l = lits.back(); lits.pop_back(); SASSERT(!m_binary[(~l).index()].empty()); IF_VERBOSE(0, if (m_binary[(~l).index()].back() != ~to_literal(idx)) verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); @@ -641,18 +641,18 @@ namespace sat { void lookahead::init_arcs(literal l) { literal_vector lits; literal_vector const& succ = m_binary[l.index()]; - for (unsigned i = 0; i < succ.size(); ++i) { - literal u = succ[i]; + for (literal u : succ) { SASSERT(u != l); + // l => u if (u.index() > l.index() && is_stamped(u)) { add_arc(~l, ~u); add_arc( u, l); } } for (auto w : m_watches[l.index()]) { - if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { + if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { for (literal u : lits) { - if (u.index() > l.index() && is_stamped(u)) { + if (u.index() > (~l).index() && is_stamped(u)) { add_arc(~l, ~u); add_arc( u, l); } @@ -1298,6 +1298,8 @@ namespace sat { watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); for (; it != end && !inconsistent(); ++it) { SASSERT(it->get_kind() == watched::EXT_CONSTRAINT); + VERIFY(is_true(l)); + VERIFY(!is_undef(l)); bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); if (m_search_mode == lookahead_mode::lookahead1 && !m_inconsistent) { lookahead_literal_occs_fun literal_occs_fn(*this); @@ -1704,6 +1706,8 @@ namespace sat { } void lookahead::propagate_clauses(literal l) { + VERIFY(is_true(l)); + VERIFY(value(l) == l_true); propagate_ternary(l); switch (m_search_mode) { case lookahead_mode::searching: @@ -1713,6 +1717,9 @@ namespace sat { propagate_clauses_lookahead(l); break; } + VERIFY(!is_undef(l)); + VERIFY(is_true(l)); + VERIFY(value(l) == l_true); propagate_external(l); } @@ -2179,8 +2186,10 @@ namespace sat { lbool lookahead::cube() { literal_vector lits; + bool_var_vector vars; + for (bool_var v : m_freevars) vars.push_back(v); while (true) { - lbool result = cube(lits); + lbool result = cube(vars, lits); if (lits.empty() || result != l_undef) { return l_undef; } @@ -2189,8 +2198,13 @@ namespace sat { return l_undef; } - lbool lookahead::cube(literal_vector& lits) { + lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits) { + scoped_ext _scoped_ext(*this); lits.reset(); + m_select_lookahead_vars.reset(); + for (auto v : vars) { + m_select_lookahead_vars.insert(v); + } bool is_first = m_cube_state.m_first; if (is_first) { init_search(); @@ -2412,6 +2426,7 @@ namespace sat { \brief simplify set of clauses by extracting units from a lookahead at base level. */ void lookahead::simplify() { + scoped_ext _scoped_ext(*this); SASSERT(m_prefix == 0); SASSERT(m_watches.empty()); m_search_mode = lookahead_mode::searching; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 38f9b0481..6ff228427 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -571,9 +571,10 @@ namespace sat { If cut-depth != 0, then it is used to control the depth of cuts. Otherwise, cut-fraction gives an adaptive threshold for creating cuts. */ + lbool cube(); - lbool cube(literal_vector& lits); + lbool cube(bool_var_vector const& vars, literal_vector& lits); literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3812eff56..8004c9635 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -162,6 +162,7 @@ namespace sat { m_user_scope_literals.append(src.m_user_scope_literals); m_mc = src.m_mc; + m_stats.m_units = init_trail_size(); } // ----------------------- @@ -837,11 +838,11 @@ namespace sat { return lh.select_lookahead(assumptions, vars); } - lbool solver::cube(literal_vector& lits) { + lbool solver::cube(bool_var_vector const& vars, literal_vector& lits) { if (!m_cuber) { m_cuber = alloc(lookahead, *this); } - lbool result = m_cuber->cube(lits); + lbool result = m_cuber->cube(vars, lits); if (result == l_false) { dealloc(m_cuber); m_cuber = nullptr; @@ -858,6 +859,7 @@ namespace sat { lbool solver::check(unsigned num_lits, literal const* lits) { init_reason_unknown(); pop_to_base_level(); + m_stats.m_units = init_trail_size(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); if (m_config.m_dimacs_display) { @@ -4039,7 +4041,7 @@ namespace sat { } void stats::reset() { - memset(this, sizeof(*this), 0); + memset(this, 0, sizeof(*this)); } void mk_stat::display(std::ostream & out) const { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index fa095623f..020c1dc42 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -365,7 +365,7 @@ namespace sat { char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); - lbool cube(literal_vector& lits); + lbool cube(bool_var_vector const& vars, literal_vector& lits); protected: unsigned m_conflicts_since_init; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 908e56da8..53383a7c2 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -353,8 +353,12 @@ public: m_internalized = true; } convert_internalized(); + sat::bool_var_vector vars; + for (auto& kv : m_map) { + vars.push_back(kv.m_value); + } sat::literal_vector lits; - lbool result = m_solver.cube(lits); + lbool result = m_solver.cube(vars, lits); if (result == l_false || lits.empty()) { return expr_ref(m.mk_false(), m); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 81302764a..3db2908ed 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -94,12 +94,6 @@ struct goal2sat::imp { std::string s0 = "operator " + s + " not supported, apply simplifier before invoking translator"; throw tactic_exception(s0.c_str()); } - - sat::bool_var mk_var(expr* t, bool ext) { - sat::bool_var v = m_solver.mk_var(ext); - m_map.insert(t, v); - return v; - } void mk_clause(sat::literal l) { TRACE("goal2sat", tout << "mk_clause: " << l << "\n";); @@ -126,7 +120,7 @@ struct goal2sat::imp { sat::bool_var mk_true() { if (m_true == sat::null_bool_var) { // create fake variable to represent true; - m_true = mk_var(m.mk_true(), false); + m_true = m_solver.mk_var(false); mk_clause(sat::literal(m_true, false)); // v is true } return m_true; @@ -145,7 +139,8 @@ struct goal2sat::imp { } else { bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t); - sat::bool_var v = mk_var(t, ext); + sat::bool_var v = m_solver.mk_var(ext); + m_map.insert(t, v); l = sat::literal(v, sign); TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";); if (ext && !is_uninterp_const(t)) { @@ -252,7 +247,7 @@ struct goal2sat::imp { } else { SASSERT(num <= m_result_stack.size()); - sat::bool_var k = mk_var(t, false); + sat::bool_var k = m_solver.mk_var(); sat::literal l(k, false); m_cache.insert(t, l); sat::literal * lits = m_result_stack.end() - num; @@ -291,7 +286,7 @@ struct goal2sat::imp { } else { SASSERT(num <= m_result_stack.size()); - sat::bool_var k = mk_var(t, false); + sat::bool_var k = m_solver.mk_var(); sat::literal l(k, false); m_cache.insert(t, l); // l => /\ lits @@ -335,7 +330,7 @@ struct goal2sat::imp { m_result_stack.reset(); } else { - sat::bool_var k = mk_var(n, false); + sat::bool_var k = m_solver.mk_var(); sat::literal l(k, false); m_cache.insert(n, l); mk_clause(~l, ~c, t); @@ -372,7 +367,7 @@ struct goal2sat::imp { m_result_stack.reset(); } else { - sat::bool_var k = mk_var(t, false); + sat::bool_var k = m_solver.mk_var(); sat::literal l(k, false); m_cache.insert(t, l); mk_clause(~l, l1, ~l2); @@ -397,7 +392,7 @@ struct goal2sat::imp { } sat::literal_vector lits; convert_pb_args(num, lits); - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); ensure_extension(); if (lits.size() % 2 == 0) lits[0].neg(); m_ext->add_xor(v, lits); @@ -456,7 +451,7 @@ struct goal2sat::imp { m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); } else { - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -481,7 +476,7 @@ struct goal2sat::imp { m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); } else { - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -530,7 +525,7 @@ struct goal2sat::imp { m_ext->add_at_least(sat::null_bool_var, lits, k.get_unsigned()); } else { - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -552,7 +547,7 @@ struct goal2sat::imp { m_ext->add_at_least(sat::null_bool_var, lits, lits.size() - k.get_unsigned()); } else { - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); m_result_stack.shrink(sz - t->get_num_args()); diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 524754613..9bacbe6a0 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -398,7 +398,6 @@ public: mc = concat(fmc.get(), mc.get()); } g->reset(); - result.push_back(g.get()); break; case l_false: SASSERT(!g->proofs_enabled()); @@ -409,9 +408,9 @@ public: if (m.canceled()) { throw tactic_exception(Z3_CANCELED_MSG); } - result.push_back(g.get()); break; } + result.push_back(g.get()); } void cleanup() { From 99b232a4c54b93da68a39f2a17a12fd0c6410505 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Oct 2017 17:30:21 -0700 Subject: [PATCH 0262/1283] fix lookahead with ba extension Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 16 +++++++++++++--- src/sat/ba_solver.h | 4 +++- src/sat/sat_extension.h | 1 + src/sat/sat_lookahead.cpp | 6 ++++++ src/sat/sat_lookahead.h | 3 +++ 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index a2058512b..e0c1b1696 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1564,7 +1564,7 @@ namespace sat { init_watch(*c, true); } else { - s().set_external(lit.var()); + if (m_solver) m_solver->set_external(lit.var()); watch_literal(lit, *c); watch_literal(~lit, *c); } @@ -3243,6 +3243,18 @@ namespace sat { extension* ba_solver::copy(solver* s) { ba_solver* result = alloc(ba_solver); result->set_solver(s); + copy_core(result); + return result; + } + + extension* ba_solver::copy(lookahead* s) { + ba_solver* result = alloc(ba_solver); + result->set_lookahead(s); + copy_core(result); + return result; + } + + void ba_solver::copy_core(ba_solver* result) { literal_vector lits; svector wlits; for (constraint* cp : m_constraints) { @@ -3274,8 +3286,6 @@ namespace sat { UNREACHABLE(); } } - - return result; } void ba_solver::init_use_list(ext_use_list& ul) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 360f276f2..3e02d49dc 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -369,7 +369,7 @@ namespace sat { inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); } inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); } - inline config const& get_config() const { return m_solver->get_config(); } + inline config const& get_config() const { return m_lookahead ? m_lookahead->get_config() : m_solver->get_config(); } inline void drat_add(literal_vector const& c, svector const& premises) { m_solver->m_drat.add(c, premises); } @@ -428,6 +428,7 @@ namespace sat { constraint* add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); constraint* add_xor(literal l, literal_vector const& lits, bool learned); + void copy_core(ba_solver* result); public: ba_solver(); virtual ~ba_solver(); @@ -453,6 +454,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); + virtual extension* copy(lookahead* s); virtual void find_mutexes(literal_vector& lits, vector & mutexes); virtual void pop_reinit(); virtual void gc(); diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 1f747ae50..c2a9197c1 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -71,6 +71,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; virtual void collect_statistics(statistics& st) const = 0; virtual extension* copy(solver* s) = 0; + virtual extension* copy(lookahead* s) = 0; virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; virtual void gc() = 0; virtual void pop_reinit() = 0; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index d0f4bc7f6..11c946fba 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -988,6 +988,7 @@ namespace sat { } } +#if 0 // copy externals: for (unsigned idx = 0; idx < m_s.m_watches.size(); ++idx) { watch_list const& wl = m_s.m_watches[idx]; @@ -997,6 +998,11 @@ namespace sat { } } } +#else + if (m_s.m_ext) { + m_ext = m_s.m_ext->copy(this); + } +#endif propagate(); m_qhead = m_trail.size(); TRACE("sat", m_s.display(tout); display(tout);); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 6ff228427..ce98bcce3 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -233,6 +233,7 @@ namespace sat { stats m_stats; model m_model; cube_state m_cube_state; + scoped_ptr m_ext; // --------------------------------------- // truth values @@ -605,6 +606,8 @@ namespace sat { double literal_occs(literal l); double literal_big_occs(literal l); + + sat::config const& get_config() const { return m_s.get_config(); } }; } From 5afef07f40cf80fb617aaab3bcf9215decd8e935 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Oct 2017 08:37:49 -0700 Subject: [PATCH 0263/1283] remove traces of old n-ary representation, add checks Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 333 ++++---------------------------------- src/sat/sat_lookahead.h | 21 +-- 2 files changed, 38 insertions(+), 316 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 11c946fba..1c3e9931c 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -270,6 +270,7 @@ namespace sat { sift_down(0, i); } } + SASSERT(validate_heap_sort()); } void lookahead::heapify() { @@ -293,6 +294,17 @@ namespace sat { if (i > j) m_candidates[i] = c; } + /** + * \brief validate that the result of heap sort sorts the candidates + * in descending order of their rating. + */ + bool lookahead::validate_heap_sort() { + for (unsigned i = 0; i + 1 < m_candidates.size(); ++i) + if (m_candidates[i].m_rating < m_candidates[i + 1].m_rating) + return false; + return true; + } + double lookahead::init_candidates(unsigned level, bool newbies) { m_candidates.reset(); double sum = 0; @@ -324,26 +336,6 @@ namespace sat { bool lookahead::is_unsat() const { // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. -#if OLD_NARY - bool all_false = true; - bool first = true; - for (unsigned l_idx : m_nary_literals) { - literal l = to_literal(l_idx); - if (first) { - // skip the first entry, the length indicator. - first = false; - } - else if (l == null_literal) { - // when reaching the end of a clause check if all entries are false - if (all_false) return true; - all_false = true; - first = true; - } - else { - all_false &= is_false(l); - } - } -#else for (nary* n : m_nary_clauses) { bool all_false = true; for (literal l : *n) { @@ -351,7 +343,6 @@ namespace sat { } if (all_false) return true; } -#endif // check if there is a ternary whose literals are false. for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -388,25 +379,6 @@ namespace sat { } // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. -#if OLD_NARY - bool no_true = true; - bool first = true; - for (unsigned l_idx : m_nary_literals) { - literal l = to_literal(l_idx); - if (first) { - // skip the first entry, the length indicator. - first = false; - } - else if (l == null_literal) { - if (no_true) return false; - no_true = true; - first = true; - } - else { - no_true &= !is_true(l); - } - } -#else for (nary * n : m_nary_clauses) { bool no_true = true; for (literal l : *n) { @@ -414,7 +386,6 @@ namespace sat { } if (no_true) return false; } -#endif // check if there is a ternary whose literals are false. for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -490,23 +461,17 @@ namespace sat { sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0; } sz = m_nary_count[(~l).index()]; -#if OLD_NARY - for (unsigned idx : m_nary[(~l).index()]) { + for (nary * n : m_nary[(~l).index()]) { if (sz-- == 0) break; - literal lit; - unsigned j = idx; double to_add = 0; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { + for (literal lit : *n) { if (!is_fixed(lit) && lit != ~l) { to_add += literal_occs(lit); } } - unsigned len = m_nary_literals[idx]; + unsigned len = n->size(); sum += pow(0.5, len) * to_add / len; } -#else - -#endif return sum; } @@ -525,17 +490,10 @@ namespace sat { } sum += 0.25 * m_ternary_count[(~l).index()]; unsigned sz = m_nary_count[(~l).index()]; -#if OLD_NARY - for (unsigned cls_idx : m_nary[(~l).index()]) { - if (sz-- == 0) break; - sum += pow(0.5, m_nary_literals[cls_idx]); - } -#else for (nary * n : m_nary[(~l).index()]) { if (sz-- == 0) break; sum += pow(0.5, n->size()); } -#endif return sum; } @@ -926,13 +884,8 @@ namespace sat { m_ternary.push_back(svector()); m_ternary_count.push_back(0); m_ternary_count.push_back(0); -#if OLD_NARY - m_nary.push_back(unsigned_vector()); - m_nary.push_back(unsigned_vector()); -#else m_nary.push_back(ptr_vector()); m_nary.push_back(ptr_vector()); -#endif m_nary_count.push_back(0); m_nary_count.push_back(0); m_bstamp.push_back(0); @@ -988,21 +941,9 @@ namespace sat { } } -#if 0 - // copy externals: - for (unsigned idx = 0; idx < m_s.m_watches.size(); ++idx) { - watch_list const& wl = m_s.m_watches[idx]; - for (watched const& w : wl) { - if (w.is_ext_constraint()) { - m_watches[idx].push_back(w); - } - } - } -#else if (m_s.m_ext) { m_ext = m_s.m_ext->copy(this); } -#endif propagate(); m_qhead = m_trail.size(); TRACE("sat", m_s.display(tout); display(tout);); @@ -1304,8 +1245,6 @@ namespace sat { watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); for (; it != end && !inconsistent(); ++it) { SASSERT(it->get_kind() == watched::EXT_CONSTRAINT); - VERIFY(is_true(l)); - VERIFY(!is_undef(l)); bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); if (m_search_mode == lookahead_mode::lookahead1 && !m_inconsistent) { lookahead_literal_occs_fun literal_occs_fn(*this); @@ -1330,26 +1269,13 @@ namespace sat { void lookahead::add_clause(clause const& c) { SASSERT(c.size() > 3); - -#if OLD_NARY - unsigned sz = c.size(); - unsigned idx = m_nary_literals.size(); - m_nary_literals.push_back(sz); - for (literal l : c) { - m_nary_literals.push_back(l.index()); - m_nary_count[l.index()]++; - m_nary[l.index()].push_back(idx); - SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size()); - } - m_nary_literals.push_back(null_literal.index()); -#else void * mem = m_allocator.allocate(nary::get_obj_size(c.size())); nary * n = new (mem) nary(c.size(), c.begin()); m_nary_clauses.push_back(n); for (literal l : c) { m_nary[l.index()].push_back(n); + m_nary_count[l.index()]++; } -#endif } @@ -1359,57 +1285,6 @@ namespace sat { literal lit; SASSERT(m_search_mode == lookahead_mode::searching); -#if OLD_NARY - for (unsigned idx : m_nary[(~l).index()]) { - if (sz-- == 0) break; - unsigned len = --m_nary_literals[idx]; - if (m_inconsistent) continue; - if (len <= 1) continue; // already processed - // find the two unassigned literals, if any - if (len == 2) { - literal l1 = null_literal; - literal l2 = null_literal; - unsigned j = idx; - bool found_true = false; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (!is_fixed(lit)) { - if (l1 == null_literal) { - l1 = lit; - } - else { - SASSERT(l2 == null_literal); - l2 = lit; - break; - } - } - else if (is_true(lit)) { - // can't swap with idx. std::swap(m_nary_literals[j], m_nary_literals[idx]); - found_true = true; - break; - } - } - if (found_true) { - // skip, the clause will be removed when propagating on 'lit' - } - else if (l1 == null_literal) { - set_conflict(); - } - else if (l2 == null_literal) { - // clause may get revisited during propagation, when l2 is true in this clause. - // m_removed_clauses.push_back(std::make_pair(~l, idx)); - // remove_clause_at(~l, idx); - propagated(l1); - } - else { - // extract binary clause. A unary or empty clause may get revisited, - // but we skip it then because it is already handled as a binary clause. - // m_removed_clauses.push_back(std::make_pair(~l, idx)); // need to restore this clause. - // remove_clause_at(~l, idx); - try_add_binary(l1, l2); - } - } - } -#else for (nary * n : m_nary[(~l).index()]) { if (sz-- == 0) break; unsigned len = n->dec_size(); @@ -1458,20 +1333,12 @@ namespace sat { } } } -#endif // clauses where l is positive: sz = m_nary_count[l.index()]; -#if OLD_NARY - for (unsigned idx : m_nary[l.index()]) { - if (sz-- == 0) break; - remove_clause_at(l, idx); - } -#else for (nary* n : m_nary[l.index()]) { if (sz-- == 0) break; remove_clause_at(l, *n); } -#endif } void lookahead::propagate_clauses_lookahead(literal l) { @@ -1481,77 +1348,6 @@ namespace sat { SASSERT(m_search_mode == lookahead_mode::lookahead1 || m_search_mode == lookahead_mode::lookahead2); -#if OLD_NARY - for (unsigned idx : m_nary[(~l).index()]) { - if (sz-- == 0) break; - literal l1 = null_literal; - literal l2 = null_literal; - unsigned j = idx; - bool found_true = false; - unsigned nonfixed = 0; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (!is_fixed(lit)) { - ++nonfixed; - if (l1 == null_literal) { - l1 = lit; - } - else if (l2 == null_literal) { - l2 = lit; - } - } - else if (is_true(lit)) { - found_true = true; - break; - } - } - if (found_true) { - // skip, the clause will be removed when propagating on 'lit' - } - else if (l1 == null_literal) { - set_conflict(); - return; - } - else if (l2 == null_literal) { - propagated(l1); - } - else if (m_search_mode == lookahead_mode::lookahead2) { - continue; - } - else { - SASSERT(nonfixed >= 2); - SASSERT(m_search_mode == lookahead_mode::lookahead1); - switch (m_config.m_reward_type) { - case heule_schur_reward: { - j = idx; - double to_add = 0; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (!is_fixed(lit)) { - to_add += literal_occs(lit); - } - } - m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed; - break; - } - case heule_unit_reward: - m_lookahead_reward += pow(0.5, nonfixed); - break; - case march_cu_reward: - m_lookahead_reward += 3.3 * pow(0.5, nonfixed - 2); - break; - case ternary_reward: - if (nonfixed == 2) { - m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; - } - else { - m_lookahead_reward += (double)0.001; - } - break; - case unit_literal_reward: - break; - } - } - } -#else for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; literal l1 = null_literal; @@ -1616,34 +1412,8 @@ namespace sat { } } } -#endif } -#if OLD_NARY - void lookahead::remove_clause_at(literal l, unsigned clause_idx) { - unsigned j = clause_idx; - literal lit; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (lit != l) { - remove_clause(lit, clause_idx); - } - } - } - - void lookahead::remove_clause(literal l, unsigned clause_idx) { - unsigned_vector& pclauses = m_nary[l.index()]; - unsigned sz = m_nary_count[l.index()]--; - for (unsigned i = sz; i > 0; ) { - --i; - if (clause_idx == pclauses[i]) { - std::swap(pclauses[i], pclauses[sz-1]); - return; - } - } - UNREACHABLE(); - } -#else - void lookahead::remove_clause_at(literal l, nary& n) { for (literal lit : n) { if (lit != l) { @@ -1664,41 +1434,19 @@ namespace sat { } UNREACHABLE(); } -#endif void lookahead::restore_clauses(literal l) { SASSERT(m_search_mode == lookahead_mode::searching); // increase the length of clauses where l is negative unsigned sz = m_nary_count[(~l).index()]; -#if OLD_NARY - for (unsigned idx : m_nary[(~l).index()]) { - if (sz-- == 0) break; - ++m_nary_literals[idx]; - } -#else for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; n->inc_size(); } -#endif // add idx back to clause list where l is positive // add them back in the same order as they were inserted // in this way we can check that the clauses are the same. sz = m_nary_count[l.index()]; -#if OLD_NARY - unsigned_vector const& pclauses = m_nary[l.index()]; - for (unsigned i = sz; i > 0; ) { - --i; - unsigned j = pclauses[i]; - literal lit; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (lit != l) { - // SASSERT(m_nary[lit.index()] == pclauses[i]); - m_nary_count[lit.index()]++; - } - } - } -#else ptr_vector& pclauses = m_nary[l.index()]; for (unsigned i = sz; i-- > 0; ) { for (literal lit : *pclauses[i]) { @@ -1708,12 +1456,10 @@ namespace sat { } } } -#endif } void lookahead::propagate_clauses(literal l) { - VERIFY(is_true(l)); - VERIFY(value(l) == l_true); + SASSERT(is_true(l)); propagate_ternary(l); switch (m_search_mode) { case lookahead_mode::searching: @@ -1723,13 +1469,8 @@ namespace sat { propagate_clauses_lookahead(l); break; } - VERIFY(!is_undef(l)); - VERIFY(is_true(l)); - VERIFY(value(l) == l_true); propagate_external(l); - } - - + } void lookahead::update_binary_clause_reward(literal l1, literal l2) { SASSERT(!is_false(l1)); @@ -1829,6 +1570,8 @@ namespace sat { TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } +#define CHECK_FAILED_LITERAL 0 + void lookahead::compute_lookahead_reward() { init_lookahead_reward(); TRACE("sat", display_lookahead(tout); ); @@ -1836,6 +1579,10 @@ namespace sat { unsigned base = 2; bool change = true; literal last_changed = null_literal; +#if CHECK_FAILED_LITERAL + unsigned_vector assigns; + literal_vector assigns_lits; +#endif while (change && !inconsistent()) { change = false; for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { @@ -1863,6 +1610,10 @@ namespace sat { if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); reset_lookahead_reward(); +#if CHECK_FAILED_LITERAL + assigns.push_back(m_trail.size()); + assigns_lits.push_back(~lit); +#endif assign(~lit); propagate(); init_lookahead_reward(); @@ -1882,6 +1633,12 @@ namespace sat { base += 2 * m_lookahead.size(); } reset_lookahead_reward(); +#if CHECK_FAILED_LITERAL + for (unsigned i = 0; i < assigns.size(); ++i) { + std::cout << "check trail: " << m_trail[assigns[i]] << " " << assigns_lits[i] << "\n"; + VERIFY(m_trail[assigns[i]] == assigns_lits[i]); + } +#endif TRACE("sat", display_lookahead(tout); ); } @@ -1892,8 +1649,6 @@ namespace sat { } void lookahead::reset_lookahead_reward() { - SASSERT(m_search_mode == lookahead_mode::lookahead1 || - m_search_mode == lookahead_mode::lookahead2); m_qhead = m_qhead_lim.back(); TRACE("sat", tout << "reset_lookahead_reward: " << m_qhead << "\n";); unsigned old_sz = m_trail_lim.back(); @@ -2317,28 +2072,10 @@ namespace sat { } } -#if OLD_NARY - for (unsigned l_idx : m_nary_literals) { - literal l = to_literal(l_idx); - if (first) { - // the first entry is a length indicator of non-false literals. - out << l_idx << ": "; - first = false; - } - else if (l == null_literal) { - first = true; - out << "\n"; - } - else { - out << l << " "; - } - } -#else for (nary * n : m_nary_clauses) { for (literal l : *n) out << l << " "; out << "\n"; } -#endif return out; } @@ -2432,7 +2169,7 @@ namespace sat { \brief simplify set of clauses by extracting units from a lookahead at base level. */ void lookahead::simplify() { - scoped_ext _scoped_ext(*this); + scoped_ext _scoped_ext(*this); SASSERT(m_prefix == 0); SASSERT(m_watches.empty()); m_search_mode = lookahead_mode::searching; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index ce98bcce3..e60924425 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,7 +20,7 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ -#define OLD_NARY 0 +// #define OLD_NARY 0 #include "sat_elim_eqs.h" @@ -194,16 +194,9 @@ namespace sat { vector> m_ternary; // lit |-> vector of ternary clauses unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit -#if OLD_NARY - vector m_nary; // lit |-> vector of clause_id - unsigned_vector m_nary_literals; // the actual literals, clauses start at offset clause_id, - // the first entry is the current length, clauses are separated by a null_literal - -#else small_object_allocator m_allocator; vector> m_nary; // lit |-> vector of nary clauses ptr_vector m_nary_clauses; // vector of all nary clauses -#endif unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_nary[lit] unsigned m_num_tc1; @@ -331,10 +324,10 @@ namespace sat { double get_rating(bool_var v) const { return m_rating[v]; } double get_rating(literal l) const { return get_rating(l.var()); } bool select(unsigned level); - //void sift_up(unsigned j); void heap_sort(); - void heapify(); + void heapify(); void sift_down(unsigned j, unsigned sz); + bool validate_heap_sort(); double init_candidates(unsigned level, bool newbies); std::ostream& display_candidates(std::ostream& out) const; bool is_unsat() const; @@ -457,13 +450,8 @@ namespace sat { void propagate_clauses_searching(literal l); void propagate_clauses_lookahead(literal l); void restore_clauses(literal l); -#if OLD_NARY - void remove_clause(literal l, unsigned clause_idx); - void remove_clause_at(literal l, unsigned clause_idx); -#else void remove_clause(literal l, nary& n); void remove_clause_at(literal l, nary& n); -#endif // ------------------------------------ // initialization @@ -552,12 +540,9 @@ namespace sat { ~lookahead() { m_s.rlimit().pop_child(); -#if OLD_NARY -#else for (nary* n : m_nary_clauses) { m_allocator.deallocate(n->obj_size(), n); } -#endif } From 4adf4d4ac2238ac2dbd9a69547c2979f6b8ce9c8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Oct 2017 12:08:54 -0700 Subject: [PATCH 0264/1283] micro opt Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 1c3e9931c..ed5976838 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -112,7 +112,6 @@ namespace sat { } } - void lookahead::inc_bstamp() { ++m_bstamp_id; if (m_bstamp_id == 0) { @@ -120,6 +119,7 @@ namespace sat { m_bstamp.fill(0); } } + void lookahead::inc_istamp() { ++m_istamp_id; if (m_istamp_id == 0) { @@ -1350,9 +1350,13 @@ namespace sat { for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; + + if (is_true(n->get_head())) { + continue; + } literal l1 = null_literal; literal l2 = null_literal; - bool found_true = false; + bool skip_clause = false; unsigned nonfixed = 0; for (literal lit : *n) { if (!is_fixed(lit)) { @@ -1363,14 +1367,19 @@ namespace sat { else if (l2 == null_literal) { l2 = lit; } + else if (m_search_mode == lookahead_mode::lookahead2) { + skip_clause = true; + break; + } } else if (is_true(lit)) { - found_true = true; + n->set_head(lit); + skip_clause = true; break; } } - if (found_true) { - // skip, the clause will be removed when propagating on 'lit' + if (skip_clause) { + // skip, the clause } else if (l1 == null_literal) { set_conflict(); @@ -1379,9 +1388,6 @@ namespace sat { else if (l2 == null_literal) { propagated(l1); } - else if (m_search_mode == lookahead_mode::lookahead2) { - continue; - } else { SASSERT(nonfixed >= 2); SASSERT(m_search_mode == lookahead_mode::lookahead1); From 611a13e8b31bad12c6a7e81ee17b77b31f4ec180 Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Thu, 12 Oct 2017 14:34:42 -0700 Subject: [PATCH 0265/1283] Changed lookahead backtrack. Parent lookahead re-use fix --- src/sat/sat_lookahead.cpp | 132 +++++++++++++++++++++++--------------- src/sat/sat_lookahead.h | 8 ++- 2 files changed, 84 insertions(+), 56 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 63b013ca0..8f6cba598 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -205,6 +205,12 @@ namespace sat { void lookahead::pre_select() { m_lookahead.reset(); + for (bool_var x : m_freevars) { // tree lookahead may leave some literals fixed in lower truth levels + literal l(x, false); + set_undef(l); + set_undef(~l); + } +//printf("m_freevars.size() = %d\n", m_freevars.size()); if (select(scope_lvl())) { get_scc(); if (inconsistent()) return; @@ -1052,6 +1058,7 @@ namespace sat { scoped_level _sl(*this, level); SASSERT(m_search_mode == lookahead_mode::lookahead1); m_search_mode = lookahead_mode::lookahead2; + lookahead_backtrack(); assign(lit); propagate(); bool unsat = inconsistent(); @@ -1065,6 +1072,7 @@ namespace sat { SASSERT(m_search_mode == lookahead_mode::searching); m_search_mode = lookahead_mode::lookahead1; scoped_level _sl(*this, level); + lookahead_backtrack(); unsigned old_sz = m_trail.size(); assign(lit); propagate(); @@ -1107,6 +1115,41 @@ namespace sat { m_wstack.reset(); } + void lookahead::lookahead_backtrack() { + //printf("before: m_trail.size() = %d\n", m_trail.size()); + while (!m_trail.empty() && is_undef(m_trail.back())) { + m_trail.pop_back(); + } + SASSERT(m_trail_lim.empty() || m_trail.size() >= m_trail_lim.back()); + m_qhead = std::min(m_qhead, m_trail.size()); + //printf("after: m_trail.size() = %d\n", m_trail.size()); + } + /*void lookahead::lookahead_backtrack() { + //return; + if (m_trail_lim.empty()) return; + unsigned old_sz = m_trail_lim.back(); + unsigned j = m_trail.size(); + while (j > old_sz) { + //while (m_qhead > old_sz) { + literal l = m_trail[j - 1]; + //literal l = m_trail[m_qhead - 1]; + if (is_fixed(l)) { + break; + } + else { + --j; + //--m_qhead; + SASSERT(is_undef(l)); + //set_undef(l); + //for (unsigned idx : m_nary[(~l).index()]) { + // ++m_nary_len[idx]; + //} + } + } + //m_trail.shrink(m_qhead); + m_trail.shrink(j); + m_qhead = std::min(m_qhead, j); + }*/ // // The current version is modeled after CDCL SAT solving data-structures. @@ -1304,7 +1347,6 @@ namespace sat { unsigned sz = m_nary_count[(~l).index()]; literal lit; SASSERT(m_search_mode == lookahead_mode::searching); - for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; unsigned len = --m_nary_literals[idx]; @@ -1485,7 +1527,7 @@ namespace sat { literal lit; while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { if (lit != l) { - // SASSERT(m_nary[lit.index()] == pclauses[i]); + SASSERT(m_nary[lit.index()][m_nary_count[lit.index()]] == pclauses[i]); m_nary_count[lit.index()]++; } } @@ -1593,12 +1635,15 @@ namespace sat { void lookahead::propagate() { while (!inconsistent() && m_qhead < m_trail.size()) { unsigned i = m_qhead; - for (; i < m_trail.size() && !inconsistent(); ++i) { + unsigned sz = m_trail.size(); + //for (; i < m_trail.size() && !inconsistent(); ++i) { + for (; i < sz && !inconsistent(); ++i) { literal l = m_trail[i]; TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); propagate_binary(l); } - while (m_qhead < m_trail.size() && !inconsistent()) { + //while (m_qhead < m_trail.size() && !inconsistent()) { + while (m_qhead < sz && !inconsistent()) { propagate_clauses(m_trail[m_qhead++]); } SASSERT(m_qhead == m_trail.size() || (inconsistent() && m_qhead < m_trail.size())); @@ -1607,7 +1652,6 @@ namespace sat { } void lookahead::compute_lookahead_reward() { - init_lookahead_reward(); TRACE("sat", display_lookahead(tout); ); m_delta_decrease = pow(m_config.m_delta_rho, 1.0 / (double)m_lookahead.size()); unsigned base = 2; @@ -1630,56 +1674,36 @@ namespace sat { IF_VERBOSE(30, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); } TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); - unsigned old_trail_sz = m_trail.size(); reset_lookahead_reward(lit); - push_lookahead1(lit, level); - do_double(lit, base); - bool unsat = inconsistent(); - unsigned num_units = m_trail.size() - old_trail_sz; + unsigned num_units = push_lookahead1(lit, level); + update_lookahead_reward(lit, level); + unsigned old_trail_sz = m_trail.size(); + unsigned dl_lvl = level; + num_units += do_double(lit, dl_lvl); + if (dl_lvl > level) { + base = dl_lvl; + } + bool unsat = inconsistent(); pop_lookahead1(lit, num_units); if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); - reset_lookahead_reward(); + lookahead_backtrack(); assign(~lit); propagate(); - init_lookahead_reward(); change = true; last_changed = lit; } - else { - update_lookahead_reward(lit, level); - } SASSERT(inconsistent() || !is_unsat()); } if (c_fixed_truth - 2 * m_lookahead.size() < base) { break; } - reset_lookahead_reward(); - init_lookahead_reward(); base += 2 * m_lookahead.size(); } - reset_lookahead_reward(); + lookahead_backtrack(); TRACE("sat", display_lookahead(tout); ); } - void lookahead::init_lookahead_reward() { - TRACE("sat", tout << "init_lookahead_reward: " << m_qhead << "\n";); - m_qhead_lim.push_back(m_qhead); - m_trail_lim.push_back(m_trail.size()); - } - - void lookahead::reset_lookahead_reward() { - m_qhead = m_qhead_lim.back(); - TRACE("sat", tout << "reset_lookahead_reward: " << m_qhead << "\n";); - unsigned old_sz = m_trail_lim.back(); - for (unsigned i = old_sz; i < m_trail.size(); ++i) { - set_undef(m_trail[i]); - } - m_trail.shrink(old_sz); - m_trail_lim.pop_back(); - m_qhead_lim.pop_back(); - } - literal lookahead::select_literal() { literal l = null_literal; double h = 0; @@ -1722,7 +1746,8 @@ namespace sat { // inherit propagation effect from parent. literal p = get_parent(l); - set_lookahead_reward(l, p == null_literal ? 0 : get_lookahead_reward(p)); + set_lookahead_reward(l, (p == null_literal || is_undef(p) || is_fixed_at(p, c_fixed_truth)) ? + 0 : get_lookahead_reward(p)); } bool lookahead::check_autarky(literal l, unsigned level) { @@ -1773,10 +1798,9 @@ namespace sat { TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] << " " << (!m_binary[l.index()].empty() || m_nary_count[l.index()] != 0) << "\n";); - reset_lookahead_reward(); + lookahead_backtrack(); assign(l); - propagate(); - init_lookahead_reward(); + propagate(); } else { ++m_stats.m_autarky_equivalences; @@ -1800,12 +1824,13 @@ namespace sat { } } - void lookahead::do_double(literal l, unsigned& base) { + unsigned lookahead::do_double(literal l, unsigned& base) { + unsigned num_units = 0; if (!inconsistent() && dl_enabled(l)) { if (get_lookahead_reward(l) > m_delta_trigger) { if (dl_no_overflow(base)) { ++m_stats.m_double_lookahead_rounds; - double_look(l, base); + num_units = double_look(l, base); if (!inconsistent()) { m_delta_trigger = get_lookahead_reward(l); dl_disable(l); @@ -1817,18 +1842,20 @@ namespace sat { m_delta_trigger *= m_delta_decrease; } } + return num_units; } - void lookahead::double_look(literal l, unsigned& base) { + unsigned lookahead::double_look(literal l, unsigned& base) { SASSERT(!inconsistent()); SASSERT(dl_no_overflow(base)); base += m_lookahead.size(); unsigned dl_truth = base + m_lookahead.size() * m_config.m_dl_max_iterations; scoped_level _sl(*this, dl_truth); IF_VERBOSE(2, verbose_stream() << "double: " << l << " depth: " << m_trail_lim.size() << "\n";); - init_lookahead_reward(); + lookahead_backtrack(); assign(l); propagate(); + unsigned old_sz = m_trail.size(); bool change = true; literal last_changed = null_literal; unsigned num_iterations = 0; @@ -1841,7 +1868,7 @@ namespace sat { SASSERT(change == false); break; } - if (is_fixed_at(lit, dl_truth)) continue; + if (is_fixed_at(lit, dl_truth)) continue; if (base + m_lookahead.size() + m_lookahead[i].m_offset >= dl_truth) { change = false; break; @@ -1850,20 +1877,19 @@ namespace sat { TRACE("sat", tout << "unit: " << ~lit << "\n";); ++m_stats.m_double_lookahead_propagations; SASSERT(m_level == dl_truth); - reset_lookahead_reward(); + lookahead_backtrack(); assign(~lit); propagate(); change = true; last_changed = lit; - init_lookahead_reward(); } } base += 2 * m_lookahead.size(); SASSERT(dl_truth >= base); } - reset_lookahead_reward(); - SASSERT(m_level == dl_truth); + SASSERT(m_level == dl_truth); base = dl_truth; + return m_trail.size() - old_sz; } void lookahead::validate_assign(literal l) { @@ -1899,11 +1925,11 @@ namespace sat { void lookahead::propagated(literal l) { assign(l); - for (unsigned i = m_trail.size() - 1; i < m_trail.size() && !inconsistent(); ++i) { + /*for (unsigned i = m_trail.size() - 1; i < m_trail.size() && !inconsistent(); ++i) { literal l = m_trail[i]; TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); propagate_binary(l); - } + }*/ if (m_search_mode == lookahead_mode::lookahead1) { m_wstack.push_back(l); } @@ -1949,9 +1975,9 @@ namespace sat { bool lookahead::backtrack(literal_vector& trail, svector & is_decision) { while (inconsistent()) { - if (trail.empty()) return false; + if (trail.empty()) return false; if (is_decision.back()) { - pop(); + pop(); trail.back().neg(); assign(trail.back()); is_decision.back() = false; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 76f5437b5..56015571d 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -89,7 +89,8 @@ namespace sat { m_min_cutoff = 30; m_preselect = false; m_level_cand = 600; - m_delta_rho = (double)0.25; + //m_delta_rho = (double)0.25; + m_delta_rho = (double)0.5; m_dl_max_iterations = 2; m_tc1_limit = 10000000; m_reward_type = ternary_reward; @@ -436,6 +437,7 @@ namespace sat { bool push_lookahead2(literal lit, unsigned level); unsigned push_lookahead1(literal lit, unsigned level); void pop_lookahead1(literal lit, unsigned num_units); + void lookahead_backtrack(); double mix_diff(double l, double r) const; clause const& get_clause(watch_list::iterator it) const; bool is_nary_propagation(clause const& c, literal l) const; @@ -465,8 +467,8 @@ namespace sat { return is_fixed(lit) && (!is_false(lit) || m_stamp[lit.var()] >= level); } - void do_double(literal l, unsigned& base); - void double_look(literal l, unsigned& base); + unsigned do_double(literal l, unsigned& base); + unsigned double_look(literal l, unsigned& base); void set_conflict() { TRACE("sat", tout << "conflict\n";); m_inconsistent = true; } //void set_conflict() { TRACE("sat", tout << "conflict\n";); printf("CONFLICT\n"); m_inconsistent = true; } bool inconsistent() { return m_inconsistent; } From a658e46b1f68255d785abed12b7d6bd8b62266f9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Oct 2017 15:46:25 -0700 Subject: [PATCH 0266/1283] removing failed literal macro Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index ed5976838..00a469a0a 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1576,7 +1576,6 @@ namespace sat { TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } -#define CHECK_FAILED_LITERAL 0 void lookahead::compute_lookahead_reward() { init_lookahead_reward(); @@ -1585,10 +1584,6 @@ namespace sat { unsigned base = 2; bool change = true; literal last_changed = null_literal; -#if CHECK_FAILED_LITERAL - unsigned_vector assigns; - literal_vector assigns_lits; -#endif while (change && !inconsistent()) { change = false; for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { @@ -1616,10 +1611,6 @@ namespace sat { if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); reset_lookahead_reward(); -#if CHECK_FAILED_LITERAL - assigns.push_back(m_trail.size()); - assigns_lits.push_back(~lit); -#endif assign(~lit); propagate(); init_lookahead_reward(); @@ -1639,12 +1630,6 @@ namespace sat { base += 2 * m_lookahead.size(); } reset_lookahead_reward(); -#if CHECK_FAILED_LITERAL - for (unsigned i = 0; i < assigns.size(); ++i) { - std::cout << "check trail: " << m_trail[assigns[i]] << " " << assigns_lits[i] << "\n"; - VERIFY(m_trail[assigns[i]] == assigns_lits[i]); - } -#endif TRACE("sat", display_lookahead(tout); ); } From 25c1b41c516ceb886ece86e726e8268d442ad9b9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Oct 2017 15:56:09 -0700 Subject: [PATCH 0267/1283] tidy Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index c468ebbc1..9a0740cb5 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1078,8 +1078,7 @@ namespace sat { TRACE("sat", tout << "windfall: " << nlit << " " << l2 << "\n";); // if we use try_add_binary, then this may produce new assignments // these assignments get put on m_trail, and they are cleared by - // reset_lookahead_reward. We would need to distinguish the trail that comes - // from lookahead levels and the main search level for this to work. + // lookahead_backtrack. add_binary(nlit, l2); } m_stats.m_windfall_binaries += m_wstack.size(); @@ -1578,13 +1577,11 @@ namespace sat { while (!inconsistent() && m_qhead < m_trail.size()) { unsigned i = m_qhead; unsigned sz = m_trail.size(); - //for (; i < m_trail.size() && !inconsistent(); ++i) { for (; i < sz && !inconsistent(); ++i) { literal l = m_trail[i]; TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); propagate_binary(l); } - //while (m_qhead < m_trail.size() && !inconsistent()) { while (m_qhead < sz && !inconsistent()) { propagate_clauses(m_trail[m_qhead++]); } @@ -1629,7 +1626,6 @@ namespace sat { pop_lookahead1(lit, num_units); if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); - //reset_lookahead_reward(); assign(~lit); propagate(); change = true; From 56496ead2fdc8bf1b62825979c3d295119a5c17d Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Thu, 12 Oct 2017 16:14:56 -0700 Subject: [PATCH 0268/1283] Commit --- src/sat/sat_lookahead.cpp | 11 +++++++++++ src/sat/sat_lookahead.h | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index cdbbb365b..d7df0a85b 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1672,6 +1672,17 @@ namespace sat { change = true; last_changed = lit; } + { + // if l was derived from lit and ~lit -> l, then l is a necessary assignment + scoped_level _sl(*this, dl_lvl); + literal_vector const& lits = m_binary[(~l).index()]; + for (literal l : lits) { + if (inconsistent()) break; + if (is_true(l) && !is_fixed_at(l, cl_fixed_truth)) { + assign(l); + } + } + } SASSERT(inconsistent() || !is_unsat()); } if (c_fixed_truth - 2 * m_lookahead.size() < base) { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index fce4fd636..14bfbb582 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -501,7 +501,6 @@ namespace sat { unsigned do_double(literal l, unsigned& base); unsigned double_look(literal l, unsigned& base); void set_conflict() { TRACE("sat", tout << "conflict\n";); m_inconsistent = true; } - //void set_conflict() { TRACE("sat", tout << "conflict\n";); printf("CONFLICT\n"); m_inconsistent = true; } bool inconsistent() { return m_inconsistent; } unsigned scope_lvl() const { return m_trail_lim.size(); } From 708e8669fa3e522f5bbe383e06ea1323b77b32d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Oct 2017 07:41:31 -0700 Subject: [PATCH 0269/1283] fix faulty merge Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 9a0740cb5..c9552d5d2 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1626,6 +1626,7 @@ namespace sat { pop_lookahead1(lit, num_units); if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); + lookahead_backtrack(); assign(~lit); propagate(); change = true; From 4394ce96aecc83bd2d23c8a2ef21d54ea4445d25 Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Fri, 13 Oct 2017 09:15:28 -0700 Subject: [PATCH 0270/1283] More failed literals --- src/sat/sat_lookahead.cpp | 95 ++++++++++++++++++++++++--------------- src/sat/sat_lookahead.h | 18 +++++--- 2 files changed, 69 insertions(+), 44 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index f70650ab6..f5d0910ab 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1574,19 +1574,16 @@ namespace sat { } void lookahead::propagate() { - while (!inconsistent() && m_qhead < m_trail.size()) { - unsigned i = m_qhead; - unsigned sz = m_trail.size(); - for (; i < sz && !inconsistent(); ++i) { - literal l = m_trail[i]; - TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); - propagate_binary(l); - } - while (m_qhead < sz && !inconsistent()) { - propagate_clauses(m_trail[m_qhead++]); - } - SASSERT(m_qhead == m_trail.size() || (inconsistent() && m_qhead < m_trail.size())); + unsigned i = m_qhead; + for (; i < m_trail.size() && !inconsistent(); ++i) { + literal l = m_trail[i]; + TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); + propagate_binary(l); } + while (m_qhead < m_trail.size() && !inconsistent()) { + propagate_clauses(m_trail[m_qhead++]); + } + SASSERT(m_qhead == m_trail.size() || (inconsistent() && m_qhead < m_trail.size())); TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } @@ -1605,41 +1602,52 @@ namespace sat { if (lit == last_changed) { break; } - if (is_fixed_at(lit, c_fixed_truth)) continue; - unsigned level = base + m_lookahead[i].m_offset; - if (m_stamp[lit.var()] >= level) { - continue; - } if (scope_lvl() == 1) { IF_VERBOSE(30, verbose_stream() << scope_lvl() << " " << lit << " binary: " << m_binary_trail.size() << " trail: " << m_trail_lim.back() << "\n";); } - TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); - reset_lookahead_reward(lit); - unsigned num_units = push_lookahead1(lit, level); - update_lookahead_reward(lit, level); + unsigned level = base + m_lookahead[i].m_offset; unsigned dl_lvl = level; - num_units += do_double(lit, dl_lvl); - if (dl_lvl > level) { - base = dl_lvl; + if (is_fixed_at(lit, c_fixed_truth) || is_true_at(lit, level)) continue; + bool unsat = false; + if (is_false_at(lit, level)) { + unsat = true; + } + else { + TRACE("sat", tout << "lookahead: " << lit << " @ " << m_lookahead[i].m_offset << "\n";); + reset_lookahead_reward(lit); + unsigned num_units = push_lookahead1(lit, level); + update_lookahead_reward(lit, level); + num_units += do_double(lit, dl_lvl); + if (dl_lvl > level) { + base = dl_lvl; + } + unsat = inconsistent(); + pop_lookahead1(lit, num_units); } - bool unsat = inconsistent(); - pop_lookahead1(lit, num_units); if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); + lookahead_backtrack(); assign(~lit); propagate(); change = true; last_changed = lit; + continue; } - { - // if l was derived from lit and ~lit -> l, then l is a necessary assignment - scoped_level _sl(*this, dl_lvl); - literal_vector const& lits = m_binary[(~l).index()]; - for (literal l : lits) { + // if l was derived from lit and ~lit -> l, then l is a necessary assignment + literal_vector necessary_lits; + for (literal l : m_binary[(~lit).index()]) { + if (is_true_at(l, dl_lvl) && !is_fixed_at(l, c_fixed_truth)) { + necessary_lits.push_back(l); + } + } + if (!necessary_lits.empty()) { + change = true; + last_changed = lit; + lookahead_backtrack(); + for (literal l : necessary_lits) { if (inconsistent()) break; - if (is_true(l) && !is_fixed_at(l, cl_fixed_truth)) { - assign(l); - } + assign(l); + propagate(); } } SASSERT(inconsistent() || !is_unsat()); @@ -1817,12 +1825,20 @@ namespace sat { SASSERT(change == false); break; } - if (is_fixed_at(lit, dl_truth)) continue; - if (base + m_lookahead.size() + m_lookahead[i].m_offset >= dl_truth) { + unsigned level = base + m_lookahead[i].m_offset; + if (level + m_lookahead.size() >= dl_truth) { change = false; break; } - if (push_lookahead2(lit, base + m_lookahead[i].m_offset)) { + bool unsat = false; + if (is_false_at(lit, level) && !is_fixed_at(lit, dl_truth)) { + unsat = true; + } + else { + if (is_fixed_at(lit, level)) continue; + unsat = push_lookahead2(lit, level); + } + if (unsat) { TRACE("sat", tout << "unit: " << ~lit << "\n";); ++m_stats.m_double_lookahead_propagations; SASSERT(m_level == dl_truth); @@ -1874,6 +1890,11 @@ namespace sat { void lookahead::propagated(literal l) { assign(l); + for (unsigned i = m_trail.size()-1; i < m_trail.size() && !inconsistent(); ++i) { + literal l = m_trail[i]; + TRACE("sat", tout << "propagate " << l << " @ " << m_level << "\n";); + propagate_binary(l); + } if (m_search_mode == lookahead_mode::lookahead1) { m_wstack.push_back(l); } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 1dba66976..c9ce7d946 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -231,11 +231,19 @@ namespace sat { // --------------------------------------- // truth values - inline bool is_fixed(literal l) const { return m_stamp[l.var()] >= m_level; } + + inline bool is_fixed_at(literal l, unsigned level) const { return m_stamp[l.var()] >= level; } + inline bool is_fixed(literal l) const { return is_fixed_at(l, m_level); } inline bool is_undef(literal l) const { return !is_fixed(l); } inline bool is_undef(bool_var v) const { return m_stamp[v] < m_level; } - inline bool is_false(literal l) const { return is_fixed(l) && (bool)((m_stamp[l.var()] & 0x1) ^ l.sign()); } // even iff l.sign() - inline bool is_true(literal l) const { return is_fixed(l) && !(bool)((m_stamp[l.var()] & 0x1) ^ l.sign()); } + inline bool is_false_at(literal l, unsigned level) const { + return is_fixed_at(l, level) && (bool)((m_stamp[l.var()] & 0x1) ^ l.sign()); + } // even iff l.sign() + inline bool is_false(literal l) const { return is_false_at(l, m_level); } + inline bool is_true_at(literal l, unsigned level) const { + return is_fixed_at(l, level) && !(bool)((m_stamp[l.var()] & 0x1) ^ l.sign()); + } + inline bool is_true(literal l) const { return is_true_at(l, m_level); } inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } inline void set_undef(literal l) { m_stamp[l.var()] = 0; } void set_level(literal d, literal s) { m_stamp[d.var()] = (m_stamp[s.var()] & ~0x1) + d.sign(); } @@ -492,10 +500,6 @@ namespace sat { void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } bool dl_no_overflow(unsigned base) const { return base + 2 * m_lookahead.size() * static_cast(m_config.m_dl_max_iterations + 1) < c_fixed_truth; } - bool is_fixed_at(literal lit, unsigned level) const { - return is_fixed(lit) && (!is_false(lit) || m_stamp[lit.var()] >= level); - } - unsigned do_double(literal l, unsigned& base); unsigned double_look(literal l, unsigned& base); void set_conflict() { TRACE("sat", tout << "conflict\n";); m_inconsistent = true; } From 4d48811efddaf583ff3112f0174b9ae7cc62c5b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Oct 2017 11:22:47 -0700 Subject: [PATCH 0271/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 17 ++++--- src/sat/tactic/goal2sat.cpp | 2 + src/tactic/portfolio/parallel_tactic.cpp | 62 ++++++++++++++++-------- 3 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index e0c1b1696..faa9b639e 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1288,7 +1288,6 @@ namespace sat { if (!create_asserting_lemma()) { goto bail_out; } - active2card(); DEBUG_CODE(VERIFY(validate_conflict(m_lemma, m_A));); @@ -1347,6 +1346,7 @@ namespace sat { } bool ba_solver::create_asserting_lemma() { + bool adjusted = false; adjust_conflict_level: int64 bound64 = m_bound; @@ -1354,7 +1354,6 @@ namespace sat { for (bool_var v : m_active_vars) { slack += get_abs_coeff(v); } - m_lemma.reset(); m_lemma.push_back(null_literal); unsigned num_skipped = 0; @@ -1389,26 +1388,32 @@ namespace sat { } } } - if (slack >= 0) { IF_VERBOSE(20, verbose_stream() << "(sat.card slack: " << slack << " skipped: " << num_skipped << ")\n";); return false; } - + if (m_overflow) { + return false; + } if (m_lemma[0] == null_literal) { if (m_lemma.size() == 1) { s().set_conflict(justification()); return false; } + return false; unsigned old_level = m_conflict_lvl; m_conflict_lvl = 0; for (unsigned i = 1; i < m_lemma.size(); ++i) { m_conflict_lvl = std::max(m_conflict_lvl, lvl(m_lemma[i])); } - IF_VERBOSE(10, verbose_stream() << "(sat.backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(sat.backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); + adjusted = true; goto adjust_conflict_level; } - return !m_overflow; + if (!adjusted) { + active2card(); + } + return true; } /* diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 3db2908ed..d7b0e0892 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1153,6 +1153,8 @@ struct sat2goal::imp { } } } + //s.display(std::cout); + //r.display(std::cout); } void add_clause(sat::literal_vector const& lits, expr_ref_vector& lemmas) { diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 9bacbe6a0..4eb2fbbe9 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -63,12 +63,16 @@ class parallel_tactic : public tactic { unsigned num_units() const { return m_units; } + unsigned cube_size() const { return m_cube.size(); } + solver& get_solver() { return *m_solver; } solver const& get_solver() const { return *m_solver; } params_ref const& params() const { return m_params; } + params_ref& params() { return m_params; } + solver_state* clone(params_ref const& p, expr* cube) { ast_manager& m = m_solver->get_manager(); ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); @@ -114,7 +118,7 @@ private: m_conflicts_decay_rate = 75; m_max_conflicts = m_conflicts_lower_bound; m_progress = 0; - m_num_threads = omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. + m_num_threads = 2 * omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. } unsigned get_max_conflicts() { @@ -175,16 +179,14 @@ private: } } - lbool simplify(solver& s) { - params_ref p; - p.copy(m_params); - p.set_uint("max_conflicts", 10); - p.set_bool("lookahead_simplify", true); - s.updt_params(p); - lbool is_sat = s.check_sat(0,0); - p.set_uint("max_conflicts", get_max_conflicts()); - p.set_bool("lookahead_simplify", false); - s.updt_params(p); + lbool simplify(solver_state& s) { + s.params().set_uint("max_conflicts", 10); + s.params().set_bool("lookahead_simplify", true); + s.get_solver().updt_params(s.params()); + lbool is_sat = s.get_solver().check_sat(0,0); + s.params().set_uint("max_conflicts", get_max_conflicts()); + s.params().set_bool("lookahead_simplify", false); + s.get_solver().updt_params(s.params()); return is_sat; } @@ -228,12 +230,10 @@ private: return l_undef; } - lbool solve(solver& s) { - params_ref p; - p.copy(m_params); - p.set_uint("max_conflicts", get_max_conflicts()); - s.updt_params(p); - return s.check_sat(0, 0); + lbool solve(solver_state& s) { + s.params().set_uint("max_conflicts", get_max_conflicts()); + s.get_solver().updt_params(s.params()); + return s.get_solver().check_sat(0, 0); } void remove_unsat(svector& unsat) { @@ -260,6 +260,25 @@ private: } lbool solve(model_ref& mdl) { + + { + solver_state& st = *m_solvers[0]; + st.params().set_uint("restart.max", 200); + st.get_solver().updt_params(st.params()); + lbool is_sat = st.get_solver().check_sat(0, 0); + st.params().set_uint("restart.max", UINT_MAX); + st.get_solver().updt_params(st.params()); + switch (is_sat) { + case l_true: + get_model(mdl, 0); + return l_true; + case l_false: + return l_false; + default: + break; + } + } + while (true) { int sz = pick_solvers(); @@ -276,7 +295,7 @@ private: #pragma omp parallel for for (int i = 0; i < sz; ++i) { - lbool is_sat = simplify(m_solvers[i]->get_solver()); + lbool is_sat = simplify(*m_solvers[i]); switch (is_sat) { case l_false: #pragma omp critical (parallel_tactic) @@ -305,7 +324,7 @@ private: #pragma omp parallel for for (int i = 0; i < sz; ++i) { - lbool is_sat = solve(m_solvers[i]->get_solver()); + lbool is_sat = solve(*m_solvers[i]); switch (is_sat) { case l_false: #pragma omp critical (parallel_tactic) @@ -328,6 +347,7 @@ private: remove_unsat(unsat); sz = std::min(max_num_splits(), sz); + sz = std::min(static_cast(m_num_threads/2), sz); if (sz == 0) continue; @@ -360,9 +380,9 @@ private: } std::ostream& display(std::ostream& out) { + out << "branches: " << m_solvers.size() << "\n"; for (solver_state* s : m_solvers) { - out << "solver units " << s->num_units() << "\n"; - out << "cube " << s->cube() << "\n"; + out << "cube " << s->cube_size() << " units " << s->num_units() << "\n"; } m_stats.display(out); return out; From 64ea473bc7425f62a0064711a446890a84faeb0e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Oct 2017 18:03:35 -0700 Subject: [PATCH 0272/1283] adding bdd Signed-off-by: Nikolaj Bjorner --- src/sat/CMakeLists.txt | 1 + src/sat/sat_bdd.cpp | 260 +++++++++++++++++++++++++++++++++++++++++ src/sat/sat_bdd.h | 170 +++++++++++++++++++++++++++ src/sat/sat_params.pyg | 1 + 4 files changed, 432 insertions(+) create mode 100644 src/sat/sat_bdd.cpp create mode 100644 src/sat/sat_bdd.h diff --git a/src/sat/CMakeLists.txt b/src/sat/CMakeLists.txt index c506c04e0..7be6ffb45 100644 --- a/src/sat/CMakeLists.txt +++ b/src/sat/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(sat ba_solver.cpp dimacs.cpp sat_asymm_branch.cpp + sat_bdd.cpp sat_clause.cpp sat_clause_set.cpp sat_clause_use_list.cpp diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp new file mode 100644 index 000000000..fc3f94a25 --- /dev/null +++ b/src/sat/sat_bdd.cpp @@ -0,0 +1,260 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_bdd.cpp + +Abstract: + + Simple BDD package modeled after BuDDy, which is modeled after CUDD. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-13 + +Revision History: + +--*/ + +#include "sat/sat_bdd.h" + +namespace sat { + + bdd_manager::bdd_manager(unsigned num_vars, unsigned cache_size) { + for (BDD a = 0; a < 2; ++a) { + for (BDD b = 0; b < 2; ++b) { + for (unsigned op = bdd_and_op; op < bdd_no_op; ++op) { + unsigned index = a + 2*b + 4*op; + m_apply_const.reserve(index+1); + m_apply_const[index] = apply_const(a, b, static_cast(op)); + } + } + } + // add two dummy nodes for true_bdd and false_bdd + m_nodes.push_back(bdd_node(0,0,0)); + m_nodes.push_back(bdd_node(0,0,0)); + m_nodes[0].m_refcount = max_rc; + m_nodes[1].m_refcount = max_rc; + + // add variables + for (unsigned i = 0; i < num_vars; ++i) { + m_var2bdd.push_back(make_node(i, false_bdd, true_bdd)); + m_var2bdd.push_back(make_node(i, true_bdd, false_bdd)); + m_nodes[m_var2bdd[2*i]].m_refcount = max_rc; + m_nodes[m_var2bdd[2*i+1]].m_refcount = max_rc; + m_var2level.push_back(i); + m_level2var.push_back(i); + } + + m_spare_entry = nullptr; + } + + bdd_manager::BDD bdd_manager::apply_const(BDD a, BDD b, bdd_op op) { + switch (op) { + case bdd_and_op: + return (a == 1 && b == 1) ? 1 : 0; + case bdd_or_op: + return (a == 1 || b == 1) ? 1 : 0; + case bdd_iff_op: + return (a == b) ? 1 : 0; + default: + UNREACHABLE(); + return 0; + } + } + + + bdd_manager::BDD bdd_manager::apply(BDD arg1, BDD arg2, bdd_op op) { + return apply_rec(arg1, arg2, op); + } + + bdd_manager::BDD bdd_manager::apply_rec(BDD a, BDD b, bdd_op op) { + switch (op) { + case bdd_and_op: + if (a == b) return a; + if (is_false(a) || is_false(b)) return false_bdd; + if (is_true(a)) return b; + if (is_true(b)) return a; + break; + case bdd_or_op: + if (a == b) return a; + if (is_false(a)) return b; + if (is_false(b)) return a; + if (is_true(a) || is_true(b)) return true_bdd; + break; + case bdd_iff_op: + if (a == b) return true_bdd; + if (is_true(a)) return b; + if (is_true(b)) return a; + break; + default: + UNREACHABLE(); + break; + } + if (is_const(a) && is_const(b)) { + return m_apply_const[a + 2*b + 4*op]; + } + cache_entry * e1 = pop_entry(hash2(a, b, op)); + cache_entry const* e2 = m_cache.insert_if_not_there(e1); + if (e2->m_op == op && e2->m_bdd1 == a && e2->m_bdd2 == b) { + push_entry(e1); + return e2->m_result; + } + BDD r; + if (level(a) == level(b)) { + push(apply_rec(lo(a), lo(b), op)); + push(apply_rec(hi(a), hi(b), op)); + r = make_node(level(a), read(2), read(1)); + } + else if (level(a) < level(b)) { + push(apply_rec(lo(a), b, op)); + push(apply_rec(hi(a), b, op)); + r = make_node(level(a), read(2), read(1)); + } + else { + push(apply_rec(a, lo(b), op)); + push(apply_rec(a, hi(b), op)); + r = make_node(level(b), read(2), read(1)); + } + e1->m_result = r; + e1->m_bdd1 = a; + e1->m_bdd2 = b; + e1->m_op = op; + return r; + } + + void bdd_manager::push(BDD b) { + m_bdd_stack.push_back(b); + } + + void bdd_manager::pop(unsigned num_scopes) { + m_bdd_stack.shrink(m_bdd_stack.size() - num_scopes); + } + + bdd_manager::BDD bdd_manager::read(unsigned index) { + return m_bdd_stack[m_bdd_stack.size() - index]; + } + + + bdd_manager::cache_entry* bdd_manager::pop_entry(unsigned hash) { + cache_entry* result = 0; + if (m_spare_entry) { + result = m_spare_entry; + m_spare_entry = 0; + result->m_hash = hash; + } + else { + void * mem = m_alloc.allocate(sizeof(cache_entry)); + result = new (mem) cache_entry(hash); + } + return result; + } + + void bdd_manager::push_entry(cache_entry* e) { + SASSERT(!m_spare_entry); + m_spare_entry = e; + } + + + bdd_manager::BDD bdd_manager::make_node(unsigned level, BDD l, BDD r) { + if (l == r) { + return l; + } +#if 0 + // TBD + unsigned hash = node_hash(level, l, r); + bdd result = m_ +#endif + int sz = m_nodes.size(); + m_nodes.push_back(bdd_node(level, l, r)); + return sz; + } + +#if 0 + void bdd_manager::bdd_reorder(int) { + + } +#endif + + bdd bdd_manager::mk_var(unsigned i) { + return bdd(m_var2bdd[2*i+1], this); + } + + bdd bdd_manager::mk_nvar(unsigned i) { + return bdd(m_var2bdd[2*i+1], this); + } + + unsigned bdd_manager::hash2(BDD a, BDD b, bdd_op op) const { + return mk_mix(a, b, op); + } + + bdd bdd_manager::mk_not(bdd b) { + return bdd(mk_not_rec(b.root), this); + } + + bdd_manager::BDD bdd_manager::mk_not_rec(BDD b) { + if (is_true(b)) return false_bdd; + if (is_false(b)) return true_bdd; + cache_entry* e1 = pop_entry(hash1(b, bdd_not_op)); + cache_entry const* e2 = m_cache.insert_if_not_there(e1); + if (e2->m_bdd1 == b && e2->m_op == bdd_not_op) { + push_entry(e1); + return e2->m_result; + } + push(mk_not_rec(lo(b))); + push(mk_not_rec(hi(b))); + BDD r = make_node(level(b), read(2), read(1)); + pop(2); + e1->m_bdd1 = b; + e1->m_bdd2 = b; + e1->m_op = bdd_not_op; + e1->m_result = r; + return r; + } + +#if 0 + bdd bdd_manager::mk_exists(bdd vars, bdd b) { + + } + + bdd bdd_manager::mk_forall(bdd vars, bdd b) { + + } + + bdd bdd_manager::mk_ite(bdd c, bdd t, bdd e) { + + } + + double bdd_manager::path_count(bdd b) { + + } + +#endif + + std::ostream& bdd_manager::display(std::ostream& out, bdd b) { + + return out; + } + + std::ostream& bdd_manager::display(std::ostream& out) { + + return out; + } + + bdd::bdd(int root, bdd_manager* m): + root(root), m(m) { + m->inc_ref(root); + } + + bdd::bdd(bdd & other): root(other.root), m(other.m) { m->inc_ref(root); } + + + bdd::~bdd() { + m->dec_ref(root); + } + +#if 0 +#endif + +} diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h new file mode 100644 index 000000000..4df0433fd --- /dev/null +++ b/src/sat/sat_bdd.h @@ -0,0 +1,170 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_bdd + +Abstract: + + Simple BDD package modeled after BuDDy, which is modeled after CUDD. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-13 + +Revision History: + +--*/ +#ifndef SAT_BDD_H_ +#define SAT_BDD_H_ + +#include "util/vector.h" +#include "util/map.h" +#include "util/small_object_allocator.h" + +namespace sat { + + struct bdd_pair { + int* m_bdd; + int m_last; + int m_id; + bdd_pair* m_next; + }; + + class bdd_manager; + + class bdd { + friend class bdd_manager; + int root; + bdd_manager* m; + bdd(int root, bdd_manager* m); + public: + bdd(bdd & other); + ~bdd(); + // bdd operator!() { return m->mk_not(*this); } + }; + + class bdd_manager { + friend bdd; + + typedef int BDD; + + enum bdd_op { + bdd_and_op = 0, + bdd_or_op, + bdd_iff_op, + bdd_not_op, + bdd_no_op + }; + + struct bdd_node { + bdd_node(unsigned level, int lo, int hi): + m_refcount(0), + m_level(level), + m_lo(lo), + m_hi(hi) + {} + unsigned m_refcount : 10; + unsigned m_level : 22; + int m_lo; + int m_hi; + //unsigned m_hash; + //unsigned m_next; + }; + + struct cache_entry { + cache_entry(unsigned hash): + m_bdd1(0), + m_bdd2(0), + m_op(bdd_no_op), + m_result(0), + m_hash(hash) + {} + + BDD m_bdd1; + BDD m_bdd2; + bdd_op m_op; + BDD m_result; + unsigned m_hash; + }; + + struct hash_entry { + unsigned operator()(cache_entry* e) const { return e->m_hash; } + }; + + struct eq_entry { + bool operator()(cache_entry * a, cache_entry * b) const { + return a->m_hash == b->m_hash; + } + }; + + svector m_nodes; + ptr_hashtable m_cache; + unsigned_vector m_apply_const; + svector m_bdd_stack; + cache_entry* m_spare_entry; + svector m_var2bdd; + unsigned_vector m_var2level, m_level2var; + small_object_allocator m_alloc; + + BDD make_node(unsigned level, BDD l, BDD r); + + BDD apply_const(BDD a, BDD b, bdd_op op); + BDD apply(BDD arg1, BDD arg2, bdd_op op); + BDD apply_rec(BDD arg1, BDD arg2, bdd_op op); + + void push(BDD b); + void pop(unsigned num_scopes); + BDD read(unsigned index); + + cache_entry* pop_entry(unsigned hash); + void push_entry(cache_entry* e); + + // void bdd_reorder(int); + + BDD mk_not_rec(BDD b); + + unsigned hash1(BDD b, bdd_op op) const { return hash2(b, b, op); } + unsigned hash2(BDD a, BDD b, bdd_op op) const; + unsigned hash3(BDD a, BDD b, BDD c, bdd_op op) const; + + static const BDD false_bdd = 0; + static const BDD true_bdd = 1; + static const unsigned max_rc = (1 << 10) - 1; + + inline bool is_true(BDD b) const { return b == true_bdd; } + inline bool is_false(BDD b) const { return b == false_bdd; } + inline bool is_const(BDD b) const { return 0 <= b && b <= 1; } + + unsigned level(BDD b) const { return m_nodes[b].m_level; } + BDD lo(BDD b) const { return m_nodes[b].m_lo; } + BDD hi(BDD b) const { return m_nodes[b].m_hi; } + void inc_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount++; } + void dec_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc && m_nodes[b].m_refcount > 0) m_nodes[b].m_refcount--; } + + BDD mk_true() { return 1; } + BDD mk_false() { return 0; } + + public: + bdd_manager(unsigned nodes, unsigned cache_size); + + bdd mk_var(unsigned i); + bdd mk_nvar(unsigned i); + + bdd mk_not(bdd b); + bdd mk_exist(bdd vars, bdd b); + bdd mk_forall(bdd vars, bdd b); + bdd mk_and(bdd a, bdd b) { return bdd(apply(a.root, b.root, bdd_and_op), this); } + bdd mk_or(bdd a, bdd b) { return bdd(apply(a.root, b.root, bdd_or_op), this); } + bdd mk_iff(bdd a, bdd b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); } + bdd mk_ite(bdd c, bdd t, bdd e); + + double path_count(bdd b); + + std::ostream& display(std::ostream& out, bdd b); + std::ostream& display(std::ostream& out); + }; +} + +#endif diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 296c75180..d803617f5 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -39,6 +39,7 @@ def_module_params('sat', ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'), ('lookahead.cube.cutoff', UINT, 0, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), ('lookahead_search', BOOL, False, 'use lookahead solver'), + ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'), ('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving'), From d7b6373601c46ba3dc928c59280298b6e18be2e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Oct 2017 10:41:17 -0700 Subject: [PATCH 0273/1283] adding bdd package Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 428 ++++++++++++++++++++++++++++++++-------- src/sat/sat_bdd.h | 135 ++++++++----- src/test/CMakeLists.txt | 1 + src/test/bdd.cpp | 40 ++++ src/test/main.cpp | 1 + 5 files changed, 476 insertions(+), 129 deletions(-) create mode 100644 src/test/bdd.cpp diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index fc3f94a25..50fc3f1d9 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -32,10 +32,16 @@ namespace sat { } } // add two dummy nodes for true_bdd and false_bdd - m_nodes.push_back(bdd_node(0,0,0)); - m_nodes.push_back(bdd_node(0,0,0)); - m_nodes[0].m_refcount = max_rc; - m_nodes[1].m_refcount = max_rc; + for (unsigned i = 0; i <= bdd_no_op; ++i) { + m_nodes.push_back(bdd_node(0,0,0)); + m_nodes.back().m_refcount = max_rc; + m_nodes.back().m_index = m_nodes.size()-1; + } + + m_spare_entry = nullptr; + m_max_num_bdd_nodes = 1 << 24; // up to 16M nodes + m_mark_level = 0; + alloc_free_nodes(1024); // add variables for (unsigned i = 0; i < num_vars; ++i) { @@ -45,28 +51,44 @@ namespace sat { m_nodes[m_var2bdd[2*i+1]].m_refcount = max_rc; m_var2level.push_back(i); m_level2var.push_back(i); - } - - m_spare_entry = nullptr; + } + } + + bdd_manager::~bdd_manager() { + if (m_spare_entry) { + m_alloc.deallocate(sizeof(*m_spare_entry), m_spare_entry); + } + for (auto* e : m_op_cache) { + m_alloc.deallocate(sizeof(*e), e); + } } bdd_manager::BDD bdd_manager::apply_const(BDD a, BDD b, bdd_op op) { + SASSERT(is_const(a) && is_const(b)); switch (op) { case bdd_and_op: - return (a == 1 && b == 1) ? 1 : 0; + return (a == true_bdd && b == true_bdd) ? true_bdd : false_bdd; case bdd_or_op: - return (a == 1 || b == 1) ? 1 : 0; + return (a == true_bdd || b == true_bdd) ? true_bdd : false_bdd; case bdd_iff_op: - return (a == b) ? 1 : 0; + return (a == b) ? true_bdd : false_bdd; default: - UNREACHABLE(); - return 0; + return false_bdd; } } - bdd_manager::BDD bdd_manager::apply(BDD arg1, BDD arg2, bdd_op op) { - return apply_rec(arg1, arg2, op); + bool first = true; + while (true) { + try { + return apply_rec(arg1, arg2, op); + } + catch (bdd_exception) { + try_reorder(); + if (!first) throw; + first = false; + } + } } bdd_manager::BDD bdd_manager::apply_rec(BDD a, BDD b, bdd_op op) { @@ -95,11 +117,17 @@ namespace sat { if (is_const(a) && is_const(b)) { return m_apply_const[a + 2*b + 4*op]; } - cache_entry * e1 = pop_entry(hash2(a, b, op)); - cache_entry const* e2 = m_cache.insert_if_not_there(e1); - if (e2->m_op == op && e2->m_bdd1 == a && e2->m_bdd2 == b) { - push_entry(e1); - return e2->m_result; + op_entry * e1 = pop_entry(a, b, op); + op_entry const* e2 = m_op_cache.insert_if_not_there(e1); + if (e2 != e1) { + if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == op) { + push_entry(e1); + return e2->m_result; + } + e1 = const_cast(e2); + e1->m_bdd1 = a; + e1->m_bdd2 = b; + e1->m_op = op; } BDD r; if (level(a) == level(b)) { @@ -107,7 +135,7 @@ namespace sat { push(apply_rec(hi(a), hi(b), op)); r = make_node(level(a), read(2), read(1)); } - else if (level(a) < level(b)) { + else if (level(a) > level(b)) { push(apply_rec(lo(a), b, op)); push(apply_rec(hi(a), b, op)); r = make_node(level(a), read(2), read(1)); @@ -117,10 +145,8 @@ namespace sat { push(apply_rec(a, hi(b), op)); r = make_node(level(b), read(2), read(1)); } + pop(2); e1->m_result = r; - e1->m_bdd1 = a; - e1->m_bdd2 = b; - e1->m_op = op; return r; } @@ -136,46 +162,63 @@ namespace sat { return m_bdd_stack[m_bdd_stack.size() - index]; } - - bdd_manager::cache_entry* bdd_manager::pop_entry(unsigned hash) { - cache_entry* result = 0; + bdd_manager::op_entry* bdd_manager::pop_entry(BDD l, BDD r, BDD op) { + op_entry* result = nullptr; if (m_spare_entry) { result = m_spare_entry; - m_spare_entry = 0; - result->m_hash = hash; + m_spare_entry = nullptr; + result->m_bdd1 = l; + result->m_bdd2 = r; + result->m_op = op; } else { - void * mem = m_alloc.allocate(sizeof(cache_entry)); - result = new (mem) cache_entry(hash); + void * mem = m_alloc.allocate(sizeof(op_entry)); + result = new (mem) op_entry(l, r, op); } + result->m_result = -1; return result; } - void bdd_manager::push_entry(cache_entry* e) { + void bdd_manager::push_entry(op_entry* e) { SASSERT(!m_spare_entry); m_spare_entry = e; } - bdd_manager::BDD bdd_manager::make_node(unsigned level, BDD l, BDD r) { if (l == r) { return l; } -#if 0 - // TBD - unsigned hash = node_hash(level, l, r); - bdd result = m_ -#endif - int sz = m_nodes.size(); - m_nodes.push_back(bdd_node(level, l, r)); - return sz; + + bdd_node n(level, l, r); + node_table::entry* e = m_node_table.insert_if_not_there2(n); + if (e->get_data().m_index != 0) { + return e->get_data().m_index; + } + e->get_data().m_refcount = 0; + if (m_free_nodes.empty()) { + gc(); + e = m_node_table.insert_if_not_there2(n); + e->get_data().m_refcount = 0; + } + if (m_free_nodes.empty()) { + if (m_nodes.size() > m_max_num_bdd_nodes) { + throw bdd_exception(); + } + e->get_data().m_index = m_nodes.size(); + m_nodes.push_back(e->get_data()); + alloc_free_nodes(m_nodes.size()/2); + } + else { + e->get_data().m_index = m_free_nodes.back(); + m_nodes[e->get_data().m_index] = e->get_data(); + m_free_nodes.pop_back(); + } + return e->get_data().m_index; } -#if 0 - void bdd_manager::bdd_reorder(int) { - + void bdd_manager::try_reorder() { + // TBD } -#endif bdd bdd_manager::mk_var(unsigned i) { return bdd(m_var2bdd[2*i+1], this); @@ -185,76 +228,301 @@ namespace sat { return bdd(m_var2bdd[2*i+1], this); } - unsigned bdd_manager::hash2(BDD a, BDD b, bdd_op op) const { - return mk_mix(a, b, op); - } - bdd bdd_manager::mk_not(bdd b) { - return bdd(mk_not_rec(b.root), this); + bool first = true; + while (true) { + try { + return bdd(mk_not_rec(b.root), this); + } + catch (bdd_exception) { + try_reorder(); + if (!first) throw; + first = false; + } + } } bdd_manager::BDD bdd_manager::mk_not_rec(BDD b) { if (is_true(b)) return false_bdd; if (is_false(b)) return true_bdd; - cache_entry* e1 = pop_entry(hash1(b, bdd_not_op)); - cache_entry const* e2 = m_cache.insert_if_not_there(e1); - if (e2->m_bdd1 == b && e2->m_op == bdd_not_op) { - push_entry(e1); - return e2->m_result; + op_entry* e1 = pop_entry(b, b, bdd_not_op); + op_entry const* e2 = m_op_cache.insert_if_not_there(e1); + if (e2 != e1) { + if (e2->m_bdd1 == b && e2->m_bdd2 == b && e2->m_op == bdd_not_op) { + push_entry(e1); + return e2->m_result; + } + e1 = const_cast(e2); + e1->m_bdd1 = b; + e1->m_bdd2 = b; + e1->m_op = bdd_not_op; } push(mk_not_rec(lo(b))); push(mk_not_rec(hi(b))); BDD r = make_node(level(b), read(2), read(1)); pop(2); - e1->m_bdd1 = b; - e1->m_bdd2 = b; - e1->m_op = bdd_not_op; e1->m_result = r; return r; } -#if 0 - bdd bdd_manager::mk_exists(bdd vars, bdd b) { + bdd bdd_manager::mk_ite(bdd const& c, bdd const& t, bdd const& e) { + bool first = true; + while (true) { + try { + return bdd(mk_ite_rec(c.root, t.root, e.root), this); + } + catch (bdd_exception) { + try_reorder(); + if (!first) throw; + first = false; + } + } + } + + bdd_manager::BDD bdd_manager::mk_ite_rec(BDD a, BDD b, BDD c) { + if (is_true(a)) return b; + if (is_false(a)) return c; + if (b == c) return b; + if (is_true(b)) return apply(a, c, bdd_or_op); + if (is_false(c)) return apply(a, b, bdd_and_op); + if (is_false(b)) return apply(mk_not_rec(a), c, bdd_and_op); + if (is_true(c)) return apply(mk_not_rec(a), b, bdd_or_op); + SASSERT(!is_const(a) && !is_const(b) && !is_const(c)); + op_entry * e1 = pop_entry(a, b, c); + op_entry const* e2 = m_op_cache.insert_if_not_there(e1); + if (e2 != e1) { + if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == c) { + push_entry(e1); + return e2->m_result; + } + e1 = const_cast(e2); + e1->m_bdd1 = a; + e1->m_bdd2 = b; + e1->m_op = c; + } + unsigned la = level(a), lb = level(b), lc = level(c); + BDD r; + BDD a1, b1, c1, a2, b2, c2; + unsigned lvl = la; + if (la >= lb && la >= lc) { + a1 = lo(a), a2 = hi(a); + lvl = la; + } + else { + a1 = a, a2 = a; + } + if (lb >= la && lb >= lc) { + b1 = lo(b), b2 = hi(b); + lvl = lb; + } + else { + b1 = b, b2 = b; + } + if (lc >= la && lc >= lb) { + c1 = lo(c), c2 = hi(c); + lvl = lc; + } + else { + c1 = c, c2 = c; + } + push(mk_ite_rec(a1, b1, c1)); + push(mk_ite_rec(a2, b2, c2)); + r = make_node(lvl, read(2), read(1)); + pop(2); + e1->m_result = r; + return r; + } + + bdd bdd_manager::mk_exists(unsigned n, unsigned const* vars, bdd const& b) { + return bdd(mk_quant(n, vars, b.root, bdd_or_op), this); + } + + bdd bdd_manager::mk_forall(unsigned n, unsigned const* vars, bdd const& b) { + return bdd(mk_quant(n, vars, b.root, bdd_and_op), this); + } + + bdd_manager::BDD bdd_manager::mk_quant(unsigned n, unsigned const* vars, BDD b, bdd_op op) { + BDD result = b; + for (unsigned i = 0; i < n; ++i) { + result = mk_quant_rec(m_var2level[vars[i]], result, op); + } + return result; + } + + bdd_manager::BDD bdd_manager::mk_quant_rec(unsigned l, BDD b, bdd_op op) { + unsigned lvl = level(b); + + if (lvl == l) { + return apply(lo(b), hi(b), op); + } + else if (lvl < l) { + return b; + } + else { + BDD a = level2bdd(l); + bdd_op q_op = op == bdd_and_op ? bdd_and_proj_op : bdd_or_proj_op; + op_entry * e1 = pop_entry(a, b, q_op); + op_entry const* e2 = m_op_cache.insert_if_not_there(e1); + if (e1 != e2) { + if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == q_op) { + push_entry(e1); + return e2->m_result; + } + e1 = const_cast(e2); + e1->m_bdd1 = a; + e1->m_bdd2 = b; + e1->m_op = q_op; + } + push(mk_quant_rec(l, lo(b), op)); + push(mk_quant_rec(l, hi(b), op)); + BDD r = make_node(lvl, read(2), read(1)); + pop(2); + e1->m_result = r; + return r; + } + } + + double bdd_manager::path_count(bdd const& b) { + init_mark(); + m_path_count.resize(m_nodes.size()); + m_path_count[0] = 0; + m_path_count[1] = 1; + set_mark(0); + set_mark(1); + m_todo.push_back(b.root); + while (!m_todo.empty()) { + BDD r = m_todo.back(); + if (is_marked(r)) { + m_todo.pop_back(); + } + else if (!is_marked(lo(r))) { + m_todo.push_back(lo(r)); + } + else if (!is_marked(hi(r))) { + m_todo.push_back(hi(r)); + } + else { + m_path_count[r] = m_path_count[lo(r)] + m_path_count[hi(r)]; + set_mark(r); + m_todo.pop_back(); + } + } + return m_path_count[b.root]; } - bdd bdd_manager::mk_forall(bdd vars, bdd b) { - + void bdd_manager::alloc_free_nodes(unsigned n) { + for (unsigned i = 0; i < n; ++i) { + m_free_nodes.push_back(m_nodes.size()); + m_nodes.push_back(bdd_node()); + m_nodes.back().m_index = m_nodes.size() - 1; + } + m_free_nodes.reverse(); } - bdd bdd_manager::mk_ite(bdd c, bdd t, bdd e) { - + void bdd_manager::gc() { + IF_VERBOSE(1, verbose_stream() << "(bdd :gc " << m_nodes.size() << ")\n";); + SASSERT(m_free_nodes.empty()); + svector reachable(m_nodes.size(), false); + for (unsigned i = m_bdd_stack.size(); i-- > 0; ) { + reachable[m_bdd_stack[i]] = true; + m_todo.push_back(m_bdd_stack[i]); + } + for (unsigned i = m_nodes.size(); i-- > 2; ) { + if (m_nodes[i].m_refcount > 0) { + reachable[i] = true; + m_todo.push_back(i); + } + } + while (!m_todo.empty()) { + BDD b = m_todo.back(); + m_todo.pop_back(); + SASSERT(reachable[b]); + if (is_const(b)) continue; + if (!reachable[lo(b)]) { + reachable[lo(b)] = true; + m_todo.push_back(lo(b)); + } + if (!reachable[hi(b)]) { + reachable[hi(b)] = true; + m_todo.push_back(hi(b)); + } + } + for (unsigned i = m_nodes.size(); i-- > 2; ) { + if (!reachable[i]) { + m_free_nodes.push_back(i); + } + } + for (auto* e : m_op_cache) { + m_alloc.deallocate(sizeof(*e), e); + } + m_op_cache.reset(); + m_node_table.reset(); + // re-populate node cache + for (unsigned i = m_nodes.size(); i-- > 2; ) { + if (reachable[i]) { + SASSERT(m_nodes[i].m_index == i); + m_node_table.insert(m_nodes[i]); + } + } } - double bdd_manager::path_count(bdd b) { - + void bdd_manager::init_mark() { + m_mark.resize(m_nodes.size()); + ++m_mark_level; + if (m_mark_level == 0) { + m_mark.fill(0); + } } -#endif - - std::ostream& bdd_manager::display(std::ostream& out, bdd b) { - + std::ostream& bdd_manager::display(std::ostream& out, bdd const& b) { + init_mark(); + m_todo.push_back(b.root); + while (!m_todo.empty()) { + BDD r = m_todo.back(); + if (is_marked(r)) { + m_todo.pop_back(); + } + else if (lo(r) == 0 && hi(r) == 0) { + set_mark(r); + m_todo.pop_back(); + } + else if (!is_marked(lo(r))) { + m_todo.push_back(lo(r)); + } + else if (!is_marked(hi(r))) { + m_todo.push_back(hi(r)); + } + else { + out << r << " : " << var(r) << " " << lo(r) << " " << hi(r) << "\n"; + set_mark(r); + m_todo.pop_back(); + } + } return out; } std::ostream& bdd_manager::display(std::ostream& out) { - + for (unsigned i = 0; i < m_nodes.size(); ++i) { + bdd_node const& n = m_nodes[i]; + if (n.m_lo == 0 && n.m_hi == 0) continue; + out << i << " : " << m_level2var[n.m_level] << " " << n.m_lo << " " << n.m_hi << "\n"; + } return out; } - bdd::bdd(int root, bdd_manager* m): - root(root), m(m) { - m->inc_ref(root); - } - + bdd::bdd(int root, bdd_manager* m): root(root), m(m) { m->inc_ref(root); } bdd::bdd(bdd & other): root(other.root), m(other.m) { m->inc_ref(root); } + bdd::~bdd() { m->dec_ref(root); } + bdd bdd::operator!() { return m->mk_not(*this); } + bdd bdd::operator&&(bdd const& other) { return m->mk_and(*this, other); } + bdd bdd::operator||(bdd const& other) { return m->mk_or(*this, other); } + std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); } - - bdd::~bdd() { - m->dec_ref(root); + std::ostream& operator<<(std::ostream& out, bdd const& b) { + return b.display(out); } -#if 0 -#endif + } diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index 4df0433fd..767fd5111 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -42,20 +42,29 @@ namespace sat { public: bdd(bdd & other); ~bdd(); - // bdd operator!() { return m->mk_not(*this); } + bdd operator!(); + bdd operator&&(bdd const& other); + bdd operator||(bdd const& other); + std::ostream& display(std::ostream& out) const; + bool operator==(bdd const& other) const { return root == other.root; } + bool operator!=(bdd const& other) const { return root != other.root; } }; + std::ostream& operator<<(std::ostream& out, bdd const& b); + class bdd_manager { friend bdd; typedef int BDD; enum bdd_op { - bdd_and_op = 0, - bdd_or_op, - bdd_iff_op, - bdd_not_op, - bdd_no_op + bdd_and_op = 2, + bdd_or_op = 3, + bdd_iff_op = 4, + bdd_not_op = 5, + bdd_and_proj_op = 6, + bdd_or_proj_op = 7, + bdd_no_op = 8, }; struct bdd_node { @@ -63,71 +72,99 @@ namespace sat { m_refcount(0), m_level(level), m_lo(lo), - m_hi(hi) + m_hi(hi), + m_index(0) {} + bdd_node(): m_level(0), m_lo(0), m_hi(0), m_index(0) {} unsigned m_refcount : 10; unsigned m_level : 22; int m_lo; int m_hi; - //unsigned m_hash; - //unsigned m_next; + unsigned m_index; + unsigned hash() const { return mk_mix(m_level, m_lo, m_hi); } + }; + + struct hash_node { + unsigned operator()(bdd_node const& n) const { return n.hash(); } + }; + + struct eq_node { + bool operator()(bdd_node const& a, bdd_node const& b) const { + return a.m_lo == b.m_lo && a.m_hi == b.m_hi && a.m_level == b.m_level; + } }; - struct cache_entry { - cache_entry(unsigned hash): - m_bdd1(0), - m_bdd2(0), - m_op(bdd_no_op), - m_result(0), - m_hash(hash) + typedef hashtable node_table; + + struct op_entry { + op_entry(BDD l, BDD r, BDD op): + m_bdd1(l), + m_bdd2(r), + m_op(op), + m_result(0) {} BDD m_bdd1; BDD m_bdd2; - bdd_op m_op; + BDD m_op; BDD m_result; - unsigned m_hash; + unsigned hash() const { return mk_mix(m_bdd1, m_bdd2, m_op); } }; struct hash_entry { - unsigned operator()(cache_entry* e) const { return e->m_hash; } + unsigned operator()(op_entry* e) const { return e->hash(); } }; struct eq_entry { - bool operator()(cache_entry * a, cache_entry * b) const { - return a->m_hash == b->m_hash; + bool operator()(op_entry * a, op_entry * b) const { + return a->hash() == b->hash(); } }; - svector m_nodes; - ptr_hashtable m_cache; + typedef ptr_hashtable op_table; + + svector m_nodes; + op_table m_op_cache; + node_table m_node_table; unsigned_vector m_apply_const; svector m_bdd_stack; - cache_entry* m_spare_entry; + op_entry* m_spare_entry; svector m_var2bdd; unsigned_vector m_var2level, m_level2var; + unsigned_vector m_free_nodes; small_object_allocator m_alloc; + mutable svector m_mark; + mutable unsigned m_mark_level; + mutable svector m_path_count; + mutable svector m_todo; + + unsigned m_max_num_bdd_nodes; BDD make_node(unsigned level, BDD l, BDD r); BDD apply_const(BDD a, BDD b, bdd_op op); BDD apply(BDD arg1, BDD arg2, bdd_op op); + BDD mk_quant(unsigned n, unsigned const* vars, BDD b, bdd_op op); + BDD apply_rec(BDD arg1, BDD arg2, bdd_op op); + BDD mk_not_rec(BDD b); + BDD mk_ite_rec(BDD a, BDD b, BDD c); + BDD mk_quant_rec(unsigned lvl, BDD b, bdd_op op); void push(BDD b); void pop(unsigned num_scopes); BDD read(unsigned index); - cache_entry* pop_entry(unsigned hash); - void push_entry(cache_entry* e); + op_entry* pop_entry(BDD l, BDD r, BDD op); + void push_entry(op_entry* e); - // void bdd_reorder(int); + void gc(); + void alloc_free_nodes(unsigned n); + void init_mark(); + void set_mark(unsigned i) { m_mark[i] = m_mark_level; } + bool is_marked(unsigned i) { return m_mark[i] == m_mark_level; } - BDD mk_not_rec(BDD b); - - unsigned hash1(BDD b, bdd_op op) const { return hash2(b, b, op); } - unsigned hash2(BDD a, BDD b, bdd_op op) const; - unsigned hash3(BDD a, BDD b, BDD c, bdd_op op) const; + void try_reorder(); static const BDD false_bdd = 0; static const BDD true_bdd = 1; @@ -136,33 +173,33 @@ namespace sat { inline bool is_true(BDD b) const { return b == true_bdd; } inline bool is_false(BDD b) const { return b == false_bdd; } inline bool is_const(BDD b) const { return 0 <= b && b <= 1; } + inline unsigned level(BDD b) const { return m_nodes[b].m_level; } + inline unsigned var(BDD b) const { return m_level2var[level(b)]; } + inline BDD lo(BDD b) const { return m_nodes[b].m_lo; } + inline BDD hi(BDD b) const { return m_nodes[b].m_hi; } + inline void inc_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount++; } + inline void dec_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount--; } + inline BDD level2bdd(unsigned l) const { return m_var2bdd[m_level2var[l]]; } - unsigned level(BDD b) const { return m_nodes[b].m_level; } - BDD lo(BDD b) const { return m_nodes[b].m_lo; } - BDD hi(BDD b) const { return m_nodes[b].m_hi; } - void inc_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount++; } - void dec_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc && m_nodes[b].m_refcount > 0) m_nodes[b].m_refcount--; } - - BDD mk_true() { return 1; } - BDD mk_false() { return 0; } - + struct bdd_exception {}; public: bdd_manager(unsigned nodes, unsigned cache_size); + ~bdd_manager(); bdd mk_var(unsigned i); bdd mk_nvar(unsigned i); bdd mk_not(bdd b); - bdd mk_exist(bdd vars, bdd b); - bdd mk_forall(bdd vars, bdd b); - bdd mk_and(bdd a, bdd b) { return bdd(apply(a.root, b.root, bdd_and_op), this); } - bdd mk_or(bdd a, bdd b) { return bdd(apply(a.root, b.root, bdd_or_op), this); } - bdd mk_iff(bdd a, bdd b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); } - bdd mk_ite(bdd c, bdd t, bdd e); + bdd mk_exists(unsigned n, unsigned const* vars, bdd const & b); + bdd mk_forall(unsigned n, unsigned const* vars, bdd const & b); + bdd mk_and(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_and_op), this); } + bdd mk_or(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_or_op), this); } + bdd mk_iff(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); } + bdd mk_ite(bdd const& c, bdd const& t, bdd const& e); - double path_count(bdd b); + double path_count(bdd const& b); - std::ostream& display(std::ostream& out, bdd b); + std::ostream& display(std::ostream& out, bdd const& b); std::ostream& display(std::ostream& out); }; } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 1c1665363..b487fe9ba 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -16,6 +16,7 @@ add_executable(test-z3 arith_rewriter.cpp arith_simplifier_plugin.cpp ast.cpp + bdd.cpp bit_blaster.cpp bits.cpp bit_vector.cpp diff --git a/src/test/bdd.cpp b/src/test/bdd.cpp new file mode 100644 index 000000000..91d837f08 --- /dev/null +++ b/src/test/bdd.cpp @@ -0,0 +1,40 @@ +#include "sat/sat_bdd.h" + +namespace sat { + static void test1() { + bdd_manager m(20, 1000); + bdd v0 = m.mk_var(0); + bdd v1 = m.mk_var(1); + bdd v2 = m.mk_var(2); + bdd c1 = v0 && v1 && v2; + bdd c2 = v2 && v0 && v1; + std::cout << c1 << "\n"; + SASSERT(c1 == c2); + + c1 = v0 || v1 || v2; + c2 = v2 || v1 || v0; + std::cout << c1 << "\n"; + std::cout << c2 << "\n"; + SASSERT(c1 == c2); + } + + static void test2() { + bdd_manager m(20, 1000); + bdd v0 = m.mk_var(0); + bdd v1 = m.mk_var(1); + bdd v2 = m.mk_var(2); + SASSERT(m.mk_ite(v0,v0,v1) == (v0 || v1)); + SASSERT(m.mk_ite(v0,v1,v1) == v1); + SASSERT(m.mk_ite(v1,v0,v1) == (v0 && v1)); + SASSERT(m.mk_ite(v1,v0,v0) == v0); + SASSERT(m.mk_ite(v0,!v0,v1) == (!v0 && v1)); + SASSERT(m.mk_ite(v0,v1,!v0) == (!v0 || v1)); + SASSERT(!(v0 && v1) == (!v0 || !v1)); + SASSERT(!(v0 || v1) == (!v0 && !v1)); + } +} + +void tst_bdd() { + sat::test1(); + sat::test2(); +} diff --git a/src/test/main.cpp b/src/test/main.cpp index 4aeba26c5..33d0abae5 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -245,6 +245,7 @@ int main(int argc, char ** argv) { TST_ARGV(sat_lookahead); TST_ARGV(sat_local_search); TST_ARGV(cnf_backbones); + TST(bdd); //TST_ARGV(hs); } From 09fdfcc963c4171e9003ca025078a3b675a00dca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Oct 2017 11:40:20 -0700 Subject: [PATCH 0274/1283] adding bdd package Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 104 +++++++++++++++++++------------------------- src/sat/sat_bdd.h | 44 ++++++++++--------- src/test/bdd.cpp | 3 +- 3 files changed, 69 insertions(+), 82 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 50fc3f1d9..216eec32f 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -24,15 +24,16 @@ namespace sat { bdd_manager::bdd_manager(unsigned num_vars, unsigned cache_size) { for (BDD a = 0; a < 2; ++a) { for (BDD b = 0; b < 2; ++b) { - for (unsigned op = bdd_and_op; op < bdd_no_op; ++op) { + for (unsigned op = bdd_and_op; op < bdd_not_op; ++op) { unsigned index = a + 2*b + 4*op; m_apply_const.reserve(index+1); m_apply_const[index] = apply_const(a, b, static_cast(op)); } } } - // add two dummy nodes for true_bdd and false_bdd - for (unsigned i = 0; i <= bdd_no_op; ++i) { + + // add dummy nodes for operations, and true, false bdds. + for (unsigned i = 0; i <= bdd_no_op + 2; ++i) { m_nodes.push_back(bdd_node(0,0,0)); m_nodes.back().m_refcount = max_rc; m_nodes.back().m_index = m_nodes.size()-1; @@ -41,7 +42,7 @@ namespace sat { m_spare_entry = nullptr; m_max_num_bdd_nodes = 1 << 24; // up to 16M nodes m_mark_level = 0; - alloc_free_nodes(1024); + alloc_free_nodes(1024 + num_vars); // add variables for (unsigned i = 0; i < num_vars; ++i) { @@ -91,6 +92,20 @@ namespace sat { } } + bool bdd_manager::check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c) { + if (e1 != e2) { + if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == c) { + push_entry(e1); + return true; + } + e1 = const_cast(e2); + } + e1->m_bdd1 = a; + e1->m_bdd2 = b; + e1->m_op = c; + return false; + } + bdd_manager::BDD bdd_manager::apply_rec(BDD a, BDD b, bdd_op op) { switch (op) { case bdd_and_op: @@ -119,15 +134,8 @@ namespace sat { } op_entry * e1 = pop_entry(a, b, op); op_entry const* e2 = m_op_cache.insert_if_not_there(e1); - if (e2 != e1) { - if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == op) { - push_entry(e1); - return e2->m_result; - } - e1 = const_cast(e2); - e1->m_bdd1 = a; - e1->m_bdd2 = b; - e1->m_op = op; + if (check_result(e1, e2, a, b, op)) { + return e2->m_result; } BDD r; if (level(a) == level(b)) { @@ -221,7 +229,7 @@ namespace sat { } bdd bdd_manager::mk_var(unsigned i) { - return bdd(m_var2bdd[2*i+1], this); + return bdd(m_var2bdd[2*i], this); } bdd bdd_manager::mk_nvar(unsigned i) { @@ -247,16 +255,8 @@ namespace sat { if (is_false(b)) return true_bdd; op_entry* e1 = pop_entry(b, b, bdd_not_op); op_entry const* e2 = m_op_cache.insert_if_not_there(e1); - if (e2 != e1) { - if (e2->m_bdd1 == b && e2->m_bdd2 == b && e2->m_op == bdd_not_op) { - push_entry(e1); - return e2->m_result; - } - e1 = const_cast(e2); - e1->m_bdd1 = b; - e1->m_bdd2 = b; - e1->m_op = bdd_not_op; - } + if (check_result(e1, e2, b, b, bdd_not_op)) + return e2->m_result; push(mk_not_rec(lo(b))); push(mk_not_rec(hi(b))); BDD r = make_node(level(b), read(2), read(1)); @@ -264,8 +264,8 @@ namespace sat { e1->m_result = r; return r; } - - bdd bdd_manager::mk_ite(bdd const& c, bdd const& t, bdd const& e) { + + bdd bdd_manager::mk_ite(bdd const& c, bdd const& t, bdd const& e) { bool first = true; while (true) { try { @@ -290,16 +290,8 @@ namespace sat { SASSERT(!is_const(a) && !is_const(b) && !is_const(c)); op_entry * e1 = pop_entry(a, b, c); op_entry const* e2 = m_op_cache.insert_if_not_there(e1); - if (e2 != e1) { - if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == c) { - push_entry(e1); - return e2->m_result; - } - e1 = const_cast(e2); - e1->m_bdd1 = a; - e1->m_bdd2 = b; - e1->m_op = c; - } + if (check_result(e1, e2, a, b, c)) + return e2->m_result; unsigned la = level(a), lb = level(b), lc = level(c); BDD r; BDD a1, b1, c1, a2, b2, c2; @@ -363,16 +355,8 @@ namespace sat { bdd_op q_op = op == bdd_and_op ? bdd_and_proj_op : bdd_or_proj_op; op_entry * e1 = pop_entry(a, b, q_op); op_entry const* e2 = m_op_cache.insert_if_not_there(e1); - if (e1 != e2) { - if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == q_op) { - push_entry(e1); - return e2->m_result; - } - e1 = const_cast(e2); - e1->m_bdd1 = a; - e1->m_bdd2 = b; - e1->m_op = q_op; - } + if (check_result(e1, e2, a, b, q_op)) + return e2->m_result; push(mk_quant_rec(l, lo(b), op)); push(mk_quant_rec(l, hi(b), op)); BDD r = make_node(lvl, read(2), read(1)); @@ -382,11 +366,11 @@ namespace sat { } } - double bdd_manager::path_count(bdd const& b) { + double bdd_manager::count(bdd const& b, unsigned z) { init_mark(); - m_path_count.resize(m_nodes.size()); - m_path_count[0] = 0; - m_path_count[1] = 1; + m_count.resize(m_nodes.size()); + m_count[0] = z; + m_count[1] = 1-z; set_mark(0); set_mark(1); m_todo.push_back(b.root); @@ -402,13 +386,12 @@ namespace sat { m_todo.push_back(hi(r)); } else { - m_path_count[r] = m_path_count[lo(r)] + m_path_count[hi(r)]; + m_count[r] = m_count[lo(r)] + m_count[hi(r)]; set_mark(r); m_todo.pop_back(); } } - return m_path_count[b.root]; - + return m_count[b.root]; } void bdd_manager::alloc_free_nodes(unsigned n) { @@ -472,6 +455,7 @@ namespace sat { ++m_mark_level; if (m_mark_level == 0) { m_mark.fill(0); + ++m_mark_level; } } @@ -514,15 +498,15 @@ namespace sat { bdd::bdd(int root, bdd_manager* m): root(root), m(m) { m->inc_ref(root); } bdd::bdd(bdd & other): root(other.root), m(other.m) { m->inc_ref(root); } bdd::~bdd() { m->dec_ref(root); } + bdd bdd::lo() const { return bdd(m->lo(root), m); } + bdd bdd::hi() const { return bdd(m->hi(root), m); } + unsigned bdd::var() const { return m->var(root); } + bool bdd::is_true() const { return root == bdd_manager::true_bdd; } + bool bdd::is_false() const { return root == bdd_manager::false_bdd; } bdd bdd::operator!() { return m->mk_not(*this); } bdd bdd::operator&&(bdd const& other) { return m->mk_and(*this, other); } bdd bdd::operator||(bdd const& other) { return m->mk_or(*this, other); } - std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); } - - std::ostream& operator<<(std::ostream& out, bdd const& b) { - return b.display(out); - } - - + std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); } + std::ostream& operator<<(std::ostream& out, bdd const& b) { return b.display(out); } } diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index 767fd5111..04aa1e8d7 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -25,13 +25,6 @@ Revision History: namespace sat { - struct bdd_pair { - int* m_bdd; - int m_last; - int m_id; - bdd_pair* m_next; - }; - class bdd_manager; class bdd { @@ -42,6 +35,12 @@ namespace sat { public: bdd(bdd & other); ~bdd(); + bdd lo() const; + bdd hi() const; + unsigned var() const; + bool is_true() const; + bool is_false() const; + bdd operator!(); bdd operator&&(bdd const& other); bdd operator||(bdd const& other); @@ -123,22 +122,21 @@ namespace sat { typedef ptr_hashtable op_table; - svector m_nodes; - op_table m_op_cache; - node_table m_node_table; - unsigned_vector m_apply_const; - svector m_bdd_stack; - op_entry* m_spare_entry; - svector m_var2bdd; - unsigned_vector m_var2level, m_level2var; - unsigned_vector m_free_nodes; - small_object_allocator m_alloc; + svector m_nodes; + op_table m_op_cache; + node_table m_node_table; + unsigned_vector m_apply_const; + svector m_bdd_stack; + op_entry* m_spare_entry; + svector m_var2bdd; + unsigned_vector m_var2level, m_level2var; + unsigned_vector m_free_nodes; + small_object_allocator m_alloc; mutable svector m_mark; mutable unsigned m_mark_level; - mutable svector m_path_count; + mutable svector m_count; mutable svector m_todo; - - unsigned m_max_num_bdd_nodes; + unsigned m_max_num_bdd_nodes; BDD make_node(unsigned level, BDD l, BDD r); @@ -157,7 +155,10 @@ namespace sat { op_entry* pop_entry(BDD l, BDD r, BDD op); void push_entry(op_entry* e); + bool check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c); + double count(bdd const& b, unsigned z); + void gc(); void alloc_free_nodes(unsigned n); void init_mark(); @@ -197,7 +198,8 @@ namespace sat { bdd mk_iff(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); } bdd mk_ite(bdd const& c, bdd const& t, bdd const& e); - double path_count(bdd const& b); + double dnf_size(bdd const& b) { return count(b, 0); } + double cnf_size(bdd const& b) { return count(b, 1); } std::ostream& display(std::ostream& out, bdd const& b); std::ostream& display(std::ostream& out); diff --git a/src/test/bdd.cpp b/src/test/bdd.cpp index 91d837f08..319f05bf8 100644 --- a/src/test/bdd.cpp +++ b/src/test/bdd.cpp @@ -10,12 +10,13 @@ namespace sat { bdd c2 = v2 && v0 && v1; std::cout << c1 << "\n"; SASSERT(c1 == c2); + std::cout << "cnf size: " << m.cnf_size(c1) << "\n"; c1 = v0 || v1 || v2; c2 = v2 || v1 || v0; std::cout << c1 << "\n"; - std::cout << c2 << "\n"; SASSERT(c1 == c2); + std::cout << "cnf size: " << m.cnf_size(c1) << "\n"; } static void test2() { From d36406f845cc761edd81f2628a21bdf602a8b509 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Oct 2017 15:12:02 -0700 Subject: [PATCH 0275/1283] adding BDD-based variable elimination routine Signed-off-by: Nikolaj Bjorner --- src/sat/CMakeLists.txt | 1 + src/sat/sat_bdd.cpp | 1 + src/sat/sat_bdd.h | 7 + src/sat/sat_elim_vars.cpp | 289 +++++++++++++++++++++++++++++++++++++ src/sat/sat_elim_vars.h | 61 ++++++++ src/sat/sat_simplifier.cpp | 14 +- src/sat/sat_simplifier.h | 1 + src/sat/sat_solver.h | 1 + 8 files changed, 372 insertions(+), 3 deletions(-) create mode 100644 src/sat/sat_elim_vars.cpp create mode 100644 src/sat/sat_elim_vars.h diff --git a/src/sat/CMakeLists.txt b/src/sat/CMakeLists.txt index 7be6ffb45..88f4f3dd6 100644 --- a/src/sat/CMakeLists.txt +++ b/src/sat/CMakeLists.txt @@ -11,6 +11,7 @@ z3_add_component(sat sat_config.cpp sat_drat.cpp sat_elim_eqs.cpp + sat_elim_vars.cpp sat_iff3_finder.cpp sat_integrity_checker.cpp sat_local_search.cpp diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 216eec32f..4835b8580 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -506,6 +506,7 @@ namespace sat { bdd bdd::operator!() { return m->mk_not(*this); } bdd bdd::operator&&(bdd const& other) { return m->mk_and(*this, other); } bdd bdd::operator||(bdd const& other) { return m->mk_or(*this, other); } + bdd& bdd::operator=(bdd const& other) { int r1 = root; root = other.root; m->inc_ref(root); m->dec_ref(r1); return *this; } std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); } std::ostream& operator<<(std::ostream& out, bdd const& b) { return b.display(out); } diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index 04aa1e8d7..da26c0b36 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -34,6 +34,7 @@ namespace sat { bdd(int root, bdd_manager* m); public: bdd(bdd & other); + bdd& operator=(bdd const& other); ~bdd(); bdd lo() const; bdd hi() const; @@ -44,6 +45,8 @@ namespace sat { bdd operator!(); bdd operator&&(bdd const& other); bdd operator||(bdd const& other); + bdd operator|=(bdd const& other) { return *this = *this || other; } + bdd operator&=(bdd const& other) { return *this = *this && other; } std::ostream& display(std::ostream& out) const; bool operator==(bdd const& other) const { return root == other.root; } bool operator!=(bdd const& other) const { return root != other.root; } @@ -190,9 +193,13 @@ namespace sat { bdd mk_var(unsigned i); bdd mk_nvar(unsigned i); + bdd mk_true() { return bdd(true_bdd, this); } + bdd mk_false() { return bdd(false_bdd, this); } bdd mk_not(bdd b); bdd mk_exists(unsigned n, unsigned const* vars, bdd const & b); bdd mk_forall(unsigned n, unsigned const* vars, bdd const & b); + bdd mk_exists(unsigned v, bdd const& b) { return mk_exists(1, &v, b); } + bdd mk_forall(unsigned v, bdd const& b) { return mk_forall(1, &v, b); } bdd mk_and(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_and_op), this); } bdd mk_or(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_or_op), this); } bdd mk_iff(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); } diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp new file mode 100644 index 000000000..4fb92c261 --- /dev/null +++ b/src/sat/sat_elim_vars.cpp @@ -0,0 +1,289 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_elim_vars.cpp + +Abstract: + + Helper class for eliminating variables + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-14 + +Revision History: + +--*/ + +#include "sat/sat_simplifier.h" +#include "sat/sat_elim_vars.h" +#include "sat/sat_solver.h" + +namespace sat{ + + elim_vars::elim_vars(simplifier& s) : simp(s), s(s.s), m(20,10000) { + m_mark_lim = 0; + m_max_literals = 11; // p.resolution_occ_cutoff(); + } + + bool elim_vars::operator()(bool_var v) { + if (s.value(v) != l_undef) + return false; + + literal pos_l(v, false); + literal neg_l(v, true); + unsigned num_bin_pos = simp.get_num_non_learned_bin(pos_l); + if (num_bin_pos > m_max_literals) return false; + unsigned num_bin_neg = simp.get_num_non_learned_bin(neg_l); + if (num_bin_neg > m_max_literals) return false; + clause_use_list & pos_occs = simp.m_use_list.get(pos_l); + clause_use_list & neg_occs = simp.m_use_list.get(neg_l); + unsigned clause_size = num_bin_pos + num_bin_neg + pos_occs.size() + neg_occs.size(); + reset_mark(); + mark_var(v); + if (!mark_literals(pos_occs)) return false; + if (!mark_literals(neg_occs)) return false; + if (!mark_literals(pos_l)) return false; + if (!mark_literals(neg_l)) return false; + + // associate index with each variable. + unsigned index = 0; + for (bool_var w : m_vars) { + m_var2index[w] = index++; + } + bdd b1 = make_clauses(pos_l); + bdd b2 = make_clauses(neg_l); + bdd b3 = make_clauses(pos_occs); + bdd b4 = make_clauses(neg_occs); + bdd b0 = b1 && b2 && b3 && b4; + bdd b = m.mk_exists(m_var2index[v], b0); + TRACE("elim_vars", + tout << "eliminate " << v << "\n"; + tout << "clauses : " << clause_size << "\n"; + for (watched const& w : simp.get_wlist(~pos_l)) { + if (w.is_binary_non_learned_clause()) { + tout << pos_l << " " << w.get_literal() << "\n"; + } + } + m.display(tout, b1); + for (watched const& w : simp.get_wlist(~neg_l)) { + if (w.is_binary_non_learned_clause()) { + tout << neg_l << " " << w.get_literal() << "\n"; + } + } + m.display(tout, b2); + clause_use_list::iterator itp = pos_occs.mk_iterator(); + while (!itp.at_end()) { + clause const& c = itp.curr(); + tout << c << "\n"; + itp.next(); + } + m.display(tout, b3); + clause_use_list::iterator itn = neg_occs.mk_iterator(); + while (!itn.at_end()) { + clause const& c = itn.curr(); + tout << c << "\n"; + itn.next(); + } + m.display(tout, b4); + tout << "eliminated:\n"; + tout << b << "\n"; + tout << m.cnf_size(b) << "\n"; + ); + std::cout << "num clauses: " << clause_size << " cnf size: " << m.cnf_size(b) << "\n"; + if (clause_size < m.cnf_size(b)) + return false; + + + literal_vector lits; + TRACE("elim_vars", + clause_vector clauses; + literal_vector units; + get_clauses(b0, lits, clauses, units); + for (clause* c : clauses) + tout << *c << "\n"; + for (literal l : units) + tout << l << "\n"; + for (clause* c : clauses) + s.m_cls_allocator.del_clause(c); + SASSERT(lits.empty()); + clauses.reset(); + units.reset(); + tout << "after elim:\n"; + get_clauses(b, lits, clauses, units); + for (clause* c : clauses) + tout << *c << "\n"; + for (literal l : units) + tout << l << "\n"; + for (clause* c : clauses) + s.m_cls_allocator.del_clause(c); + SASSERT(lits.empty()); + clauses.reset(); + ); + + return false; + + // eliminate variable + simp.m_pos_cls.reset(); + simp.m_neg_cls.reset(); + simp.collect_clauses(pos_l, simp.m_pos_cls); + simp.collect_clauses(neg_l, simp.m_neg_cls); + model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); + simp.save_clauses(mc_entry, simp.m_pos_cls); + simp.save_clauses(mc_entry, simp.m_neg_cls); + s.m_eliminated[v] = true; + simp.remove_bin_clauses(pos_l); + simp.remove_bin_clauses(neg_l); + simp.remove_clauses(pos_occs, pos_l); + simp.remove_clauses(neg_occs, neg_l); + pos_occs.reset(); + neg_occs.reset(); + add_clauses(b, lits); + return true; + } + + void elim_vars::add_clauses(bdd const& b, literal_vector& lits) { + if (b.is_true()) { + // no-op + } + else if (b.is_false()) { + SASSERT(lits.size() > 0); + std::cout << lits << "\n"; + literal_vector c(lits); + if (simp.cleanup_clause(c)) + return; + + std::cout << c << "\n"; + + switch (c.size()) { + case 0: + UNREACHABLE(); + break; + case 1: + simp.propagate_unit(c[0]); + break; + case 2: + simp.add_non_learned_binary_clause(c[0],c[1]); + break; + default: { + clause* cp = s.m_cls_allocator.mk_clause(c.size(), c.c_ptr(), false); + s.m_clauses.push_back(cp); + simp.m_use_list.insert(*cp); + break; + } + } + } + else { + unsigned v = m_vars[b.var()]; + lits.push_back(literal(v, false)); + add_clauses(b.lo(), lits); + lits.pop_back(); + lits.push_back(literal(v, true)); + add_clauses(b.hi(), lits); + lits.pop_back(); + } + } + + + void elim_vars::get_clauses(bdd const& b, literal_vector & lits, clause_vector& clauses, literal_vector& units) { + if (b.is_true()) { + return; + } + if (b.is_false()) { + if (lits.size() > 1) { + clause* c = s.m_cls_allocator.mk_clause(lits.size(), lits.c_ptr(), false); + clauses.push_back(c); + } + else { + units.push_back(lits.back()); + } + return; + } + + // if (v hi lo) + // (v | lo) & (!v | hi) + // if (v T lo) -> (v | lo) + unsigned v = m_vars[b.var()]; + lits.push_back(literal(v, false)); + get_clauses(b.lo(), lits, clauses, units); + lits.pop_back(); + lits.push_back(literal(v, true)); + get_clauses(b.hi(), lits, clauses, units); + lits.pop_back(); + } + + void elim_vars::reset_mark() { + m_vars.reset(); + m_mark.resize(s.num_vars()); + m_var2index.resize(s.num_vars()); + ++m_mark_lim; + if (m_mark_lim == 0) { + ++m_mark_lim; + m_mark.fill(0); + } + } + + void elim_vars::mark_var(bool_var v) { + if (m_mark[v] != m_mark_lim) { + m_mark[v] = m_mark_lim; + m_vars.push_back(v); + } + } + + bool elim_vars::mark_literals(clause_use_list & occs) { + clause_use_list::iterator it = occs.mk_iterator(); + while (!it.at_end()) { + clause const& c = it.curr(); + for (literal l : c) { + mark_var(l.var()); + } + if (num_vars() > m_max_literals) return false; + it.next(); + } + return true; + } + + bool elim_vars::mark_literals(literal lit) { + watch_list& wl = simp.get_wlist(lit); + for (watched const& w : wl) { + if (w.is_binary_non_learned_clause()) { + mark_var(w.get_literal().var()); + } + } + return num_vars() <= m_max_literals; + } + + bdd elim_vars::make_clauses(clause_use_list & occs) { + bdd result = m.mk_true(); + clause_use_list::iterator it = occs.mk_iterator(); + while (!it.at_end()) { + clause const& c = it.curr(); + bdd cl = m.mk_false(); + for (literal l : c) { + cl |= mk_literal(l); + } + it.next(); + result &= cl; + } + return result; + } + + bdd elim_vars::make_clauses(literal lit) { + bdd result = m.mk_true(); + watch_list& wl = simp.get_wlist(~lit); + for (watched const& w : wl) { + if (w.is_binary_non_learned_clause()) { + result &= (mk_literal(lit) || mk_literal(w.get_literal())); + } + } + return result; + } + + bdd elim_vars::mk_literal(literal l) { + return l.sign() ? m.mk_nvar(m_var2index[l.var()]) : m.mk_var(m_var2index[l.var()]); + } + +}; + diff --git a/src/sat/sat_elim_vars.h b/src/sat/sat_elim_vars.h new file mode 100644 index 000000000..f9d3b374c --- /dev/null +++ b/src/sat/sat_elim_vars.h @@ -0,0 +1,61 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_elim_vars.h + +Abstract: + + Helper class for eliminating variables + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-14 + +Revision History: + +--*/ +#ifndef SAT_ELIM_VARS_H_ +#define SAT_ELIM_VARS_H_ + +#include "sat/sat_types.h" +#include "sat/sat_bdd.h" + +namespace sat { + class solver; + class simplifier; + + class elim_vars { + friend class simplifier; + + simplifier& simp; + solver& s; + bdd_manager m; + + svector m_vars; + unsigned_vector m_mark; + unsigned m_mark_lim; + unsigned_vector m_var2index; + + unsigned m_max_literals; + + unsigned num_vars() const { return m_vars.size(); } + void reset_mark(); + void mark_var(bool_var v); + bool mark_literals(clause_use_list & occs); + bool mark_literals(literal lit); + bdd make_clauses(clause_use_list & occs); + bdd make_clauses(literal lit); + bdd mk_literal(literal l); + void get_clauses(bdd const& b, literal_vector& lits, clause_vector& clauses, literal_vector& units); + void add_clauses(bdd const& b, literal_vector& lits); + + public: + elim_vars(simplifier& s); + bool operator()(bool_var v); + }; + +}; + +#endif diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 4d5946795..12923e0d0 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -21,6 +21,7 @@ Revision History: #include "sat/sat_simplifier.h" #include "sat/sat_simplifier_params.hpp" #include "sat/sat_solver.h" +#include "sat/sat_elim_vars.h" #include "util/stopwatch.h" #include "util/trace.h" @@ -1308,7 +1309,6 @@ namespace sat { clause_use_list & neg_occs = m_use_list.get(neg_l); unsigned num_pos = pos_occs.size() + num_bin_pos; unsigned num_neg = neg_occs.size() + num_bin_neg; - m_elim_counter -= num_pos + num_neg; TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";); @@ -1349,7 +1349,6 @@ namespace sat { collect_clauses(pos_l, m_pos_cls); collect_clauses(neg_l, m_neg_cls); - m_elim_counter -= num_pos * num_neg + before_lits; TRACE("resolution_detail", tout << "collecting number of after_clauses\n";); unsigned before_clauses = num_pos + num_neg; @@ -1371,6 +1370,8 @@ namespace sat { TRACE("resolution", tout << "found var to eliminate, before: " << before_clauses << " after: " << after_clauses << "\n";); + m_elim_counter -= num_pos * num_neg + before_lits; + // eliminate variable model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); save_clauses(mc_entry, m_pos_cls); @@ -1454,14 +1455,21 @@ namespace sat { elim_var_report rpt(*this); bool_var_vector vars; order_vars_for_elim(vars); + // sat::elim_vars elim_bdd(*this); + std::cout << "vars to elim: " << vars.size() << "\n"; for (bool_var v : vars) { checkpoint(); - if (m_elim_counter < 0) + if (m_elim_counter < 0) break; if (try_eliminate(v)) { m_num_elim_vars++; } +#if 0 + else if (elim_bdd(v)) { + m_num_elim_vars++; + } +#endif } m_pos_cls.finalize(); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index a38df3d3c..6ef0f8f18 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -49,6 +49,7 @@ namespace sat { class simplifier { friend class ba_solver; + friend class elim_vars; solver & s; unsigned m_num_calls; use_list m_use_list; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 020c1dc42..56071182b 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -179,6 +179,7 @@ namespace sat { friend class local_search; friend struct mk_stat; friend class ccc; + friend class elim_vars; public: solver(params_ref const & p, reslimit& l); ~solver(); From 11093166215845bf870cbd1f62a1d9f18b9f0504 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Oct 2017 15:53:25 -0700 Subject: [PATCH 0276/1283] fixing projection Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 33 +++++++++++++++++++-------------- src/sat/sat_bdd.h | 14 +++++++------- src/test/bdd.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 4835b8580..36900760e 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -94,8 +94,8 @@ namespace sat { bool bdd_manager::check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c) { if (e1 != e2) { + push_entry(e1); if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == c) { - push_entry(e1); return true; } e1 = const_cast(e2); @@ -343,12 +343,15 @@ namespace sat { bdd_manager::BDD bdd_manager::mk_quant_rec(unsigned l, BDD b, bdd_op op) { unsigned lvl = level(b); - - if (lvl == l) { - return apply(lo(b), hi(b), op); + BDD r; + if (is_const(b)) { + r = b; + } + else if (lvl == l) { + r = apply(lo(b), hi(b), op); } else if (lvl < l) { - return b; + r = b; } else { BDD a = level2bdd(l); @@ -356,14 +359,16 @@ namespace sat { op_entry * e1 = pop_entry(a, b, q_op); op_entry const* e2 = m_op_cache.insert_if_not_there(e1); if (check_result(e1, e2, a, b, q_op)) - return e2->m_result; - push(mk_quant_rec(l, lo(b), op)); - push(mk_quant_rec(l, hi(b), op)); - BDD r = make_node(lvl, read(2), read(1)); - pop(2); - e1->m_result = r; - return r; + r = e2->m_result; + else { + push(mk_quant_rec(l, lo(b), op)); + push(mk_quant_rec(l, hi(b), op)); + r = make_node(lvl, read(2), read(1)); + pop(2); + e1->m_result = r; + } } + return r; } double bdd_manager::count(bdd const& b, unsigned z) { @@ -495,7 +500,7 @@ namespace sat { return out; } - bdd::bdd(int root, bdd_manager* m): root(root), m(m) { m->inc_ref(root); } + bdd::bdd(unsigned root, bdd_manager* m): root(root), m(m) { m->inc_ref(root); } bdd::bdd(bdd & other): root(other.root), m(other.m) { m->inc_ref(root); } bdd::~bdd() { m->dec_ref(root); } bdd bdd::lo() const { return bdd(m->lo(root), m); } @@ -506,7 +511,7 @@ namespace sat { bdd bdd::operator!() { return m->mk_not(*this); } bdd bdd::operator&&(bdd const& other) { return m->mk_and(*this, other); } bdd bdd::operator||(bdd const& other) { return m->mk_or(*this, other); } - bdd& bdd::operator=(bdd const& other) { int r1 = root; root = other.root; m->inc_ref(root); m->dec_ref(r1); return *this; } + bdd& bdd::operator=(bdd const& other) { unsigned r1 = root; root = other.root; m->inc_ref(root); m->dec_ref(r1); return *this; } std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); } std::ostream& operator<<(std::ostream& out, bdd const& b) { return b.display(out); } diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index da26c0b36..29d91446e 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -29,9 +29,9 @@ namespace sat { class bdd { friend class bdd_manager; - int root; + unsigned root; bdd_manager* m; - bdd(int root, bdd_manager* m); + bdd(unsigned root, bdd_manager* m); public: bdd(bdd & other); bdd& operator=(bdd const& other); @@ -57,7 +57,7 @@ namespace sat { class bdd_manager { friend bdd; - typedef int BDD; + typedef unsigned BDD; enum bdd_op { bdd_and_op = 2, @@ -70,7 +70,7 @@ namespace sat { }; struct bdd_node { - bdd_node(unsigned level, int lo, int hi): + bdd_node(unsigned level, BDD lo, BDD hi): m_refcount(0), m_level(level), m_lo(lo), @@ -80,8 +80,8 @@ namespace sat { bdd_node(): m_level(0), m_lo(0), m_hi(0), m_index(0) {} unsigned m_refcount : 10; unsigned m_level : 22; - int m_lo; - int m_hi; + BDD m_lo; + BDD m_hi; unsigned m_index; unsigned hash() const { return mk_mix(m_level, m_lo, m_hi); } }; @@ -176,7 +176,7 @@ namespace sat { inline bool is_true(BDD b) const { return b == true_bdd; } inline bool is_false(BDD b) const { return b == false_bdd; } - inline bool is_const(BDD b) const { return 0 <= b && b <= 1; } + inline bool is_const(BDD b) const { return b <= 1; } inline unsigned level(BDD b) const { return m_nodes[b].m_level; } inline unsigned var(BDD b) const { return m_level2var[level(b)]; } inline BDD lo(BDD b) const { return m_nodes[b].m_lo; } diff --git a/src/test/bdd.cpp b/src/test/bdd.cpp index 319f05bf8..f3f6e6b8d 100644 --- a/src/test/bdd.cpp +++ b/src/test/bdd.cpp @@ -33,9 +33,34 @@ namespace sat { SASSERT(!(v0 && v1) == (!v0 || !v1)); SASSERT(!(v0 || v1) == (!v0 && !v1)); } + + static void test3() { + bdd_manager m(20, 1000); + bdd v0 = m.mk_var(0); + bdd v1 = m.mk_var(1); + bdd v2 = m.mk_var(2); + bdd c1 = (v0 && v1) || v2; + bdd c2 = m.mk_exists(0, c1); + std::cout << c1 << "\n"; + std::cout << c2 << "\n"; + SASSERT(c2 == (v1 || v2)); + c2 = m.mk_exists(1, c1); + SASSERT(c2 == (v0 || v2)); + c2 = m.mk_exists(2, c1); + SASSERT(c2.is_true()); + SASSERT(m.mk_exists(3, c1) == c1); + c1 = (v0 && v1) || (v1 && v2) || (!v0 && !v2); + c2 = m.mk_exists(0, c1); + SASSERT(c2 == (v1 || (v1 && v2) || !v2)); + c2 = m.mk_exists(1, c1); + SASSERT(c2 == (v0 || v2 || (!v0 && !v2))); + c2 = m.mk_exists(2, c1); + SASSERT(c2 == ((v0 && v1) || v1 || !v0)); + } } void tst_bdd() { sat::test1(); sat::test2(); + sat::test3(); } From 46fa24532439afcb38f26561c066ff4da9e4a5c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Oct 2017 18:33:38 -0700 Subject: [PATCH 0277/1283] more agressive variable elimination Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_vars.cpp | 131 +++++++++++++++++++++++++++++-------- src/sat/sat_elim_vars.h | 8 +++ src/sat/sat_simplifier.cpp | 10 ++- 3 files changed, 118 insertions(+), 31 deletions(-) diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 4fb92c261..764c193b3 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -25,7 +25,7 @@ namespace sat{ elim_vars::elim_vars(simplifier& s) : simp(s), s(s.s), m(20,10000) { m_mark_lim = 0; - m_max_literals = 11; // p.resolution_occ_cutoff(); + m_max_literals = 13; // p.resolution_occ_cutoff(); } bool elim_vars::operator()(bool_var v) { @@ -41,6 +41,9 @@ namespace sat{ clause_use_list & pos_occs = simp.m_use_list.get(pos_l); clause_use_list & neg_occs = simp.m_use_list.get(neg_l); unsigned clause_size = num_bin_pos + num_bin_neg + pos_occs.size() + neg_occs.size(); + if (clause_size == 0) { + return false; + } reset_mark(); mark_var(v); if (!mark_literals(pos_occs)) return false; @@ -49,16 +52,72 @@ namespace sat{ if (!mark_literals(neg_l)) return false; // associate index with each variable. + sort_marked(); + bdd b1 = elim_var(v); + double sz1 = m.cnf_size(b1); + if (sz1 > 2*clause_size) { + return false; + } + if (sz1 <= clause_size) { + return elim_var(v, b1); + } + m_vars.reverse(); + bdd b2 = elim_var(v); + double sz2 = m.cnf_size(b2); + if (sz2 <= clause_size) { + return elim_var(v, b2); + } + shuffle_vars(); + bdd b3 = elim_var(v); + double sz3 = m.cnf_size(b3); + if (sz3 <= clause_size) { + return elim_var(v, b3); + } + return false; + } + + bool elim_vars::elim_var(bool_var v, bdd const& b) { + literal pos_l(v, false); + literal neg_l(v, true); + clause_use_list & pos_occs = simp.m_use_list.get(pos_l); + clause_use_list & neg_occs = simp.m_use_list.get(neg_l); + + // eliminate variable + simp.m_pos_cls.reset(); + simp.m_neg_cls.reset(); + simp.collect_clauses(pos_l, simp.m_pos_cls); + simp.collect_clauses(neg_l, simp.m_neg_cls); + model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); + simp.save_clauses(mc_entry, simp.m_pos_cls); + simp.save_clauses(mc_entry, simp.m_neg_cls); + s.m_eliminated[v] = true; + simp.remove_bin_clauses(pos_l); + simp.remove_bin_clauses(neg_l); + simp.remove_clauses(pos_occs, pos_l); + simp.remove_clauses(neg_occs, neg_l); + pos_occs.reset(); + neg_occs.reset(); + literal_vector lits; + add_clauses(b, lits); + return true; + } + + bdd elim_vars::elim_var(bool_var v) { unsigned index = 0; for (bool_var w : m_vars) { m_var2index[w] = index++; } + literal pos_l(v, false); + literal neg_l(v, true); + clause_use_list & pos_occs = simp.m_use_list.get(pos_l); + clause_use_list & neg_occs = simp.m_use_list.get(neg_l); + bdd b1 = make_clauses(pos_l); bdd b2 = make_clauses(neg_l); bdd b3 = make_clauses(pos_occs); bdd b4 = make_clauses(neg_occs); bdd b0 = b1 && b2 && b3 && b4; - bdd b = m.mk_exists(m_var2index[v], b0); + bdd b = m.mk_exists(m_var2index[v], b0); TRACE("elim_vars", tout << "eliminate " << v << "\n"; tout << "clauses : " << clause_size << "\n"; @@ -92,12 +151,8 @@ namespace sat{ tout << b << "\n"; tout << m.cnf_size(b) << "\n"; ); - std::cout << "num clauses: " << clause_size << " cnf size: " << m.cnf_size(b) << "\n"; - if (clause_size < m.cnf_size(b)) - return false; - - literal_vector lits; +#if 0 TRACE("elim_vars", clause_vector clauses; literal_vector units; @@ -122,26 +177,9 @@ namespace sat{ SASSERT(lits.empty()); clauses.reset(); ); +#endif - return false; - - // eliminate variable - simp.m_pos_cls.reset(); - simp.m_neg_cls.reset(); - simp.collect_clauses(pos_l, simp.m_pos_cls); - simp.collect_clauses(neg_l, simp.m_neg_cls); - model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); - simp.save_clauses(mc_entry, simp.m_pos_cls); - simp.save_clauses(mc_entry, simp.m_neg_cls); - s.m_eliminated[v] = true; - simp.remove_bin_clauses(pos_l); - simp.remove_bin_clauses(neg_l); - simp.remove_clauses(pos_occs, pos_l); - simp.remove_clauses(neg_occs, neg_l); - pos_occs.reset(); - neg_occs.reset(); - add_clauses(b, lits); - return true; + return b; } void elim_vars::add_clauses(bdd const& b, literal_vector& lits) { @@ -150,12 +188,9 @@ namespace sat{ } else if (b.is_false()) { SASSERT(lits.size() > 0); - std::cout << lits << "\n"; literal_vector c(lits); if (simp.cleanup_clause(c)) return; - - std::cout << c << "\n"; switch (c.size()) { case 0: @@ -165,12 +200,22 @@ namespace sat{ simp.propagate_unit(c[0]); break; case 2: + s.m_stats.m_mk_bin_clause++; simp.add_non_learned_binary_clause(c[0],c[1]); + simp.back_subsumption1(c[0],c[1], false); break; default: { + if (c.size() == 3) + s.m_stats.m_mk_ter_clause++; + else + s.m_stats.m_mk_clause++; clause* cp = s.m_cls_allocator.mk_clause(c.size(), c.c_ptr(), false); s.m_clauses.push_back(cp); simp.m_use_list.insert(*cp); + if (simp.m_sub_counter > 0) + simp.back_subsumption1(*cp); + else + simp.back_subsumption0(*cp); break; } } @@ -218,6 +263,7 @@ namespace sat{ m_vars.reset(); m_mark.resize(s.num_vars()); m_var2index.resize(s.num_vars()); + m_occ.resize(s.num_vars()); ++m_mark_lim; if (m_mark_lim == 0) { ++m_mark_lim; @@ -225,10 +271,37 @@ namespace sat{ } } + class elim_vars::compare_occ { + elim_vars& ev; + public: + compare_occ(elim_vars& ev):ev(ev) {} + + bool operator()(bool_var v1, bool_var v2) const { + return ev.m_occ[v1] < ev.m_occ[v2]; + } + }; + + void elim_vars::sort_marked() { + std::sort(m_vars.begin(), m_vars.end(), compare_occ(*this)); + } + + void elim_vars::shuffle_vars() { + unsigned sz = m_vars.size(); + for (unsigned i = 0; i < sz; ++i) { + unsigned x = m_rand(sz); + unsigned y = m_rand(sz); + std::swap(m_vars[x], m_vars[y]); + } + } + void elim_vars::mark_var(bool_var v) { if (m_mark[v] != m_mark_lim) { m_mark[v] = m_mark_lim; m_vars.push_back(v); + m_occ[v] = 1; + } + else { + ++m_occ[v]; } } diff --git a/src/sat/sat_elim_vars.h b/src/sat/sat_elim_vars.h index f9d3b374c..8f7ec1bb4 100644 --- a/src/sat/sat_elim_vars.h +++ b/src/sat/sat_elim_vars.h @@ -28,21 +28,27 @@ namespace sat { class elim_vars { friend class simplifier; + class compare_occ; simplifier& simp; solver& s; bdd_manager m; + random_gen m_rand; + svector m_vars; unsigned_vector m_mark; unsigned m_mark_lim; unsigned_vector m_var2index; + unsigned_vector m_occ; unsigned m_max_literals; unsigned num_vars() const { return m_vars.size(); } void reset_mark(); void mark_var(bool_var v); + void sort_marked(); + void shuffle_vars(); bool mark_literals(clause_use_list & occs); bool mark_literals(literal lit); bdd make_clauses(clause_use_list & occs); @@ -50,6 +56,8 @@ namespace sat { bdd mk_literal(literal l); void get_clauses(bdd const& b, literal_vector& lits, clause_vector& clauses, literal_vector& units); void add_clauses(bdd const& b, literal_vector& lits); + bool elim_var(bool_var v, bdd const& b); + bdd elim_var(bool_var v); public: elim_vars(simplifier& s); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 12923e0d0..688510153 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -191,6 +191,12 @@ namespace sat { // scoped_finalize _scoped_finalize(*this); + for (bool_var v = 0; v < s.num_vars(); ++v) { + if (!s.m_eliminated[v] && !is_external(v)) { + insert_elim_todo(v); + } + } + do { if (m_subsumption) subsume(); @@ -1455,7 +1461,7 @@ namespace sat { elim_var_report rpt(*this); bool_var_vector vars; order_vars_for_elim(vars); - // sat::elim_vars elim_bdd(*this); + sat::elim_vars elim_bdd(*this); std::cout << "vars to elim: " << vars.size() << "\n"; for (bool_var v : vars) { @@ -1465,7 +1471,7 @@ namespace sat { if (try_eliminate(v)) { m_num_elim_vars++; } -#if 0 +#if 1 else if (elim_bdd(v)) { m_num_elim_vars++; } From 9f9ae4427de529643b9f18d2c0e77040a02c01fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Oct 2017 15:13:43 -0700 Subject: [PATCH 0278/1283] add cce Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 35 ++++-- src/sat/sat_bdd.h | 108 ++++++++++--------- src/sat/sat_elim_vars.cpp | 44 ++------ src/sat/sat_elim_vars.h | 1 - src/sat/sat_model_converter.cpp | 9 +- src/sat/sat_simplifier.cpp | 186 ++++++++++++++++++++++++++------ src/sat/sat_simplifier.h | 1 + src/sat/sat_solver.cpp | 2 + src/sat/sat_solver.h | 2 + src/test/bdd.cpp | 10 +- 10 files changed, 259 insertions(+), 139 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 36900760e..edc8ad2a8 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -21,7 +21,7 @@ Revision History: namespace sat { - bdd_manager::bdd_manager(unsigned num_vars, unsigned cache_size) { + bdd_manager::bdd_manager(unsigned num_vars) { for (BDD a = 0; a < 2; ++a) { for (BDD b = 0; b < 2; ++b) { for (unsigned op = bdd_and_op; op < bdd_not_op; ++op) { @@ -84,7 +84,7 @@ namespace sat { try { return apply_rec(arg1, arg2, op); } - catch (bdd_exception) { + catch (mem_out) { try_reorder(); if (!first) throw; first = false; @@ -92,6 +92,16 @@ namespace sat { } } + + bdd bdd_manager::mk_true() { return bdd(true_bdd, this); } + bdd bdd_manager::mk_false() { return bdd(false_bdd, this); } + bdd bdd_manager::mk_and(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_and_op), this); } + bdd bdd_manager::mk_or(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_or_op), this); } + bdd bdd_manager::mk_iff(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); } + bdd bdd_manager::mk_exists(unsigned v, bdd const& b) { return mk_exists(1, &v, b); } + bdd bdd_manager::mk_forall(unsigned v, bdd const& b) { return mk_forall(1, &v, b); } + + bool bdd_manager::check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c) { if (e1 != e2) { push_entry(e1); @@ -203,14 +213,15 @@ namespace sat { return e->get_data().m_index; } e->get_data().m_refcount = 0; - if (m_free_nodes.empty()) { + bool do_gc = m_free_nodes.empty(); + if (do_gc) { gc(); e = m_node_table.insert_if_not_there2(n); e->get_data().m_refcount = 0; } - if (m_free_nodes.empty()) { + if (do_gc && m_free_nodes.size()*3 < m_nodes.size()) { if (m_nodes.size() > m_max_num_bdd_nodes) { - throw bdd_exception(); + throw mem_out(); } e->get_data().m_index = m_nodes.size(); m_nodes.push_back(e->get_data()); @@ -228,6 +239,11 @@ namespace sat { // TBD } + void bdd_manager::sift_up(unsigned level) { + // exchange level and level + 1. + + } + bdd bdd_manager::mk_var(unsigned i) { return bdd(m_var2bdd[2*i], this); } @@ -242,7 +258,7 @@ namespace sat { try { return bdd(mk_not_rec(b.root), this); } - catch (bdd_exception) { + catch (mem_out) { try_reorder(); if (!first) throw; first = false; @@ -271,7 +287,7 @@ namespace sat { try { return bdd(mk_ite_rec(c.root, t.root, e.root), this); } - catch (bdd_exception) { + catch (mem_out) { try_reorder(); if (!first) throw; first = false; @@ -409,7 +425,7 @@ namespace sat { } void bdd_manager::gc() { - IF_VERBOSE(1, verbose_stream() << "(bdd :gc " << m_nodes.size() << ")\n";); + IF_VERBOSE(3, verbose_stream() << "(bdd :gc " << m_nodes.size() << ")\n";); SASSERT(m_free_nodes.empty()); svector reachable(m_nodes.size(), false); for (unsigned i = m_bdd_stack.size(); i-- > 0; ) { @@ -502,6 +518,7 @@ namespace sat { bdd::bdd(unsigned root, bdd_manager* m): root(root), m(m) { m->inc_ref(root); } bdd::bdd(bdd & other): root(other.root), m(other.m) { m->inc_ref(root); } + bdd::bdd(bdd && other): root(0), m(other.m) { std::swap(root, other.root); } bdd::~bdd() { m->dec_ref(root); } bdd bdd::lo() const { return bdd(m->lo(root), m); } bdd bdd::hi() const { return bdd(m->hi(root), m); } @@ -514,5 +531,7 @@ namespace sat { bdd& bdd::operator=(bdd const& other) { unsigned r1 = root; root = other.root; m->inc_ref(root); m->dec_ref(r1); return *this; } std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); } std::ostream& operator<<(std::ostream& out, bdd const& b) { return b.display(out); } + double bdd::cnf_size() const { return m->cnf_size(*this); } + double bdd::dnf_size() const { return m->dnf_size(*this); } } diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index 29d91446e..c0f1fc9b2 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -25,34 +25,7 @@ Revision History: namespace sat { - class bdd_manager; - - class bdd { - friend class bdd_manager; - unsigned root; - bdd_manager* m; - bdd(unsigned root, bdd_manager* m); - public: - bdd(bdd & other); - bdd& operator=(bdd const& other); - ~bdd(); - bdd lo() const; - bdd hi() const; - unsigned var() const; - bool is_true() const; - bool is_false() const; - - bdd operator!(); - bdd operator&&(bdd const& other); - bdd operator||(bdd const& other); - bdd operator|=(bdd const& other) { return *this = *this || other; } - bdd operator&=(bdd const& other) { return *this = *this && other; } - std::ostream& display(std::ostream& out) const; - bool operator==(bdd const& other) const { return root == other.root; } - bool operator!=(bdd const& other) const { return root != other.root; } - }; - - std::ostream& operator<<(std::ostream& out, bdd const& b); + class bdd; class bdd_manager { friend bdd; @@ -169,6 +142,7 @@ namespace sat { bool is_marked(unsigned i) { return m_mark[i] == m_mark_level; } void try_reorder(); + void sift_up(unsigned level); static const BDD false_bdd = 0; static const BDD true_bdd = 1; @@ -185,32 +159,70 @@ namespace sat { inline void dec_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount--; } inline BDD level2bdd(unsigned l) const { return m_var2bdd[m_level2var[l]]; } - struct bdd_exception {}; - public: - bdd_manager(unsigned nodes, unsigned cache_size); - ~bdd_manager(); - - bdd mk_var(unsigned i); - bdd mk_nvar(unsigned i); - - bdd mk_true() { return bdd(true_bdd, this); } - bdd mk_false() { return bdd(false_bdd, this); } - bdd mk_not(bdd b); - bdd mk_exists(unsigned n, unsigned const* vars, bdd const & b); - bdd mk_forall(unsigned n, unsigned const* vars, bdd const & b); - bdd mk_exists(unsigned v, bdd const& b) { return mk_exists(1, &v, b); } - bdd mk_forall(unsigned v, bdd const& b) { return mk_forall(1, &v, b); } - bdd mk_and(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_and_op), this); } - bdd mk_or(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_or_op), this); } - bdd mk_iff(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); } - bdd mk_ite(bdd const& c, bdd const& t, bdd const& e); - double dnf_size(bdd const& b) { return count(b, 0); } double cnf_size(bdd const& b) { return count(b, 1); } + bdd mk_not(bdd b); + bdd mk_and(bdd const& a, bdd const& b); + bdd mk_or(bdd const& a, bdd const& b); + std::ostream& display(std::ostream& out, bdd const& b); + + public: + struct mem_out {}; + + bdd_manager(unsigned nodes); + ~bdd_manager(); + + void set_max_num_nodes(unsigned n) { m_max_num_bdd_nodes = n; } + + bdd mk_var(unsigned i); + bdd mk_nvar(unsigned i); + + bdd mk_true(); + bdd mk_false(); + + bdd mk_exists(unsigned n, unsigned const* vars, bdd const & b); + bdd mk_forall(unsigned n, unsigned const* vars, bdd const & b); + bdd mk_exists(unsigned v, bdd const& b); + bdd mk_forall(unsigned v, bdd const& b); + bdd mk_iff(bdd const& a, bdd const& b); + bdd mk_ite(bdd const& c, bdd const& t, bdd const& e); + std::ostream& display(std::ostream& out); }; + + class bdd { + friend class bdd_manager; + unsigned root; + bdd_manager* m; + bdd(unsigned root, bdd_manager* m); + public: + bdd(bdd & other); + bdd(bdd && other); + bdd& operator=(bdd const& other); + ~bdd(); + bdd lo() const; + bdd hi() const; + unsigned var() const; + bool is_true() const; + bool is_false() const; + + bdd operator!(); + bdd operator&&(bdd const& other); + bdd operator||(bdd const& other); + bdd operator|=(bdd const& other) { return *this = *this || other; } + bdd operator&=(bdd const& other) { return *this = *this && other; } + std::ostream& display(std::ostream& out) const; + bool operator==(bdd const& other) const { return root == other.root; } + bool operator!=(bdd const& other) const { return root != other.root; } + double cnf_size() const; + double dnf_size() const; + }; + + std::ostream& operator<<(std::ostream& out, bdd const& b); + } + #endif diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 764c193b3..a5ca80a32 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -23,9 +23,9 @@ Revision History: namespace sat{ - elim_vars::elim_vars(simplifier& s) : simp(s), s(s.s), m(20,10000) { + elim_vars::elim_vars(simplifier& s) : simp(s), s(s.s), m(20) { m_mark_lim = 0; - m_max_literals = 13; // p.resolution_occ_cutoff(); + m_max_literals = 11; } bool elim_vars::operator()(bool_var v) { @@ -54,7 +54,7 @@ namespace sat{ // associate index with each variable. sort_marked(); bdd b1 = elim_var(v); - double sz1 = m.cnf_size(b1); + double sz1 = b1.cnf_size(); if (sz1 > 2*clause_size) { return false; } @@ -63,13 +63,13 @@ namespace sat{ } m_vars.reverse(); bdd b2 = elim_var(v); - double sz2 = m.cnf_size(b2); + double sz2 = b2.cnf_size(); if (sz2 <= clause_size) { return elim_var(v, b2); } shuffle_vars(); bdd b3 = elim_var(v); - double sz3 = m.cnf_size(b3); + double sz3 = b3.cnf_size(); if (sz3 <= clause_size) { return elim_var(v, b3); } @@ -91,6 +91,7 @@ namespace sat{ simp.save_clauses(mc_entry, simp.m_pos_cls); simp.save_clauses(mc_entry, simp.m_neg_cls); s.m_eliminated[v] = true; + ++s.m_stats.m_elim_var_bdd; simp.remove_bin_clauses(pos_l); simp.remove_bin_clauses(neg_l); simp.remove_clauses(pos_occs, pos_l); @@ -152,33 +153,6 @@ namespace sat{ tout << m.cnf_size(b) << "\n"; ); -#if 0 - TRACE("elim_vars", - clause_vector clauses; - literal_vector units; - get_clauses(b0, lits, clauses, units); - for (clause* c : clauses) - tout << *c << "\n"; - for (literal l : units) - tout << l << "\n"; - for (clause* c : clauses) - s.m_cls_allocator.del_clause(c); - SASSERT(lits.empty()); - clauses.reset(); - units.reset(); - tout << "after elim:\n"; - get_clauses(b, lits, clauses, units); - for (clause* c : clauses) - tout << *c << "\n"; - for (literal l : units) - tout << l << "\n"; - for (clause* c : clauses) - s.m_cls_allocator.del_clause(c); - SASSERT(lits.empty()); - clauses.reset(); - ); -#endif - return b; } @@ -194,15 +168,15 @@ namespace sat{ switch (c.size()) { case 0: - UNREACHABLE(); + s.set_conflict(justification()); break; case 1: simp.propagate_unit(c[0]); break; case 2: s.m_stats.m_mk_bin_clause++; - simp.add_non_learned_binary_clause(c[0],c[1]); - simp.back_subsumption1(c[0],c[1], false); + simp.add_non_learned_binary_clause(c[0], c[1]); + simp.back_subsumption1(c[0], c[1], false); break; default: { if (c.size() == 3) diff --git a/src/sat/sat_elim_vars.h b/src/sat/sat_elim_vars.h index 8f7ec1bb4..8893bbc40 100644 --- a/src/sat/sat_elim_vars.h +++ b/src/sat/sat_elim_vars.h @@ -27,7 +27,6 @@ namespace sat { class simplifier; class elim_vars { - friend class simplifier; class compare_occ; simplifier& simp; diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index e9d047086..d4a994d0f 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -226,13 +226,8 @@ namespace sat { unsigned model_converter::max_var(unsigned min) const { unsigned result = min; - vector::const_iterator it = m_entries.begin(); - vector::const_iterator end = m_entries.end(); - for (; it != end; ++it) { - literal_vector::const_iterator lvit = it->m_clauses.begin(); - literal_vector::const_iterator lvend = it->m_clauses.end(); - for (; lvit != lvend; ++lvit) { - literal l = *lvit; + for (entry const& e : m_entries) { + for (literal l : e.m_clauses) { if (l != null_literal) { if (l.var() > result) result = l.var(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 688510153..6ad88a31b 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -330,19 +330,15 @@ namespace sat { cs.set_end(it2); } - void simplifier::mark_all_but(clause const & c, literal l) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - if (c[i] == l) - continue; - mark_visited(c[i]); - } + void simplifier::mark_all_but(clause const & c, literal l1) { + for (literal l2 : c) + if (l2 != l1) + mark_visited(l2); } void simplifier::unmark_all(clause const & c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) - unmark_visited(c[i]); + for (literal l : c) + unmark_visited(l); } /** @@ -952,7 +948,7 @@ namespace sat { } bool process_var(bool_var v) { - return !s.s.is_assumption(v) && !s.was_eliminated(v); + return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v); } void operator()(unsigned num_vars) { @@ -971,6 +967,108 @@ namespace sat { } } + // + // Resolve intersection + // Find literals that are in the intersection of all resolvents with l. + // + void ri(literal l, literal_vector& inter) { + if (!process_var(l.var())) return; + bool first = true; + for (watched & w : s.get_wlist(~l)) { + if (w.is_binary_non_learned_clause()) { + literal lit = w.get_literal(); + if (s.is_marked(~lit)) continue; + if (!first) { + inter.reset(); + return; + } + first = false; + inter.push_back(lit); + } + } + clause_use_list & neg_occs = s.m_use_list.get(~l); + clause_use_list::iterator it = neg_occs.mk_iterator(); + while (!it.at_end()) { + bool tautology = false; + clause & c = it.curr(); + for (literal lit : c) { + if (s.is_marked(~lit)) { + tautology = true; + break; + } + } + if (!tautology) { + if (first) { + for (literal lit : c) { + if (lit != ~l) inter.push_back(lit); + } + first = false; + } + else { + unsigned j = 0; + unsigned sz = inter.size(); + for (unsigned i = 0; i < sz; ++i) { + literal lit1 = inter[i]; + for (literal lit2 : c) { + if (lit1 == lit2) { + inter[j++] = lit1; + break; + } + } + } + inter.shrink(j); + if (j == 0) return; + } + } + it.next(); + } + } + + // perform covered clause elimination. + // first extract the covered literal addition (CLA). + // then check whether the CLA is blocked. + bool cce(clause& c, literal lit) { + for (literal l : c) s.mark_visited(l); + literal_vector added, lits; + for (literal l : c) added.push_back(l); + for (unsigned i = 0; i < added.size(); ++i) { + ri(added[i], lits); + for (literal l : lits) { + if (!s.is_marked(l)) { + s.mark_visited(l); + added.push_back(l); + } + } + lits.reset(); + } + s.unmark_visited(lit); + bool is_tautology = (added.size() > c.size()) && all_tautology(lit); + for (literal l : added) s.unmark_visited(l); + return is_tautology; + } + + bool cce(literal lit, literal l2) { + literal_vector added, lits; + s.mark_visited(lit); + s.mark_visited(l2); + added.push_back(lit); + added.push_back(l2); + for (unsigned i = 0; i < added.size(); ++i) { + ri(added[i], lits); + for (literal l : lits) { + if (!s.is_marked(l)) { + s.mark_visited(l); + added.push_back(l); + } + } + lits.reset(); + } + s.unmark_visited(lit); + bool is_tautology = added.size() > 2 && all_tautology(lit); + for (literal l : added) s.unmark_visited(l); + return is_tautology; + } + void process(literal l) { TRACE("blocked_clause", tout << "processing: " << l << "\n";); model_converter::entry * new_entry = 0; @@ -988,21 +1086,14 @@ namespace sat { SASSERT(c.contains(l)); s.mark_all_but(c, l); if (all_tautology(l)) { - TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); - if (new_entry == 0) - new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); - m_to_remove.push_back(&c); + block_clause(c, l, new_entry); s.m_num_blocked_clauses++; - mc.insert(*new_entry, c); - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - literal lit = c[i]; - if (lit != l && process_var(lit.var())) { - m_queue.decreased(~lit); - } - } + s.unmark_all(c); + } + else if (cce(c, l)) { + block_clause(c, l, new_entry); + s.m_num_covered_clauses++; } - s.unmark_all(c); it.next(); } } @@ -1024,13 +1115,12 @@ namespace sat { literal l2 = it->get_literal(); s.mark_visited(l2); if (all_tautology(l)) { - if (new_entry == 0) - new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); - TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l << "\n";); - s.remove_bin_clause_half(l2, l, it->is_learned()); + block_binary(it, l, new_entry); s.m_num_blocked_clauses++; - m_queue.decreased(~l2); - mc.insert(*new_entry, l, l2); + } + else if (cce(l, l2)) { + block_binary(it, l, new_entry); + s.m_num_covered_clauses++; } else { *it2 = *it; @@ -1042,6 +1132,29 @@ namespace sat { } } + void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { + TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); + if (new_entry == 0) + new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); + m_to_remove.push_back(&c); + mc.insert(*new_entry, c); + for (literal lit : c) { + if (lit != l && process_var(lit.var())) { + m_queue.decreased(~lit); + } + } + } + + void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { + if (new_entry == 0) + new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); + TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l << "\n";); + literal l2 = it->get_literal(); + s.remove_bin_clause_half(l2, l, it->is_learned()); + m_queue.decreased(~l2); + mc.insert(*new_entry, l, l2); + } + bool all_tautology(literal l) { watch_list & wlist = s.get_wlist(l); m_counter -= wlist.size(); @@ -1083,9 +1196,11 @@ namespace sat { simplifier & m_simplifier; stopwatch m_watch; unsigned m_num_blocked_clauses; + unsigned m_num_covered_clauses; blocked_cls_report(simplifier & s): m_simplifier(s), - m_num_blocked_clauses(s.m_num_blocked_clauses) { + m_num_blocked_clauses(s.m_num_blocked_clauses), + m_num_covered_clauses(s.m_num_covered_clauses) { m_watch.start(); } @@ -1094,6 +1209,8 @@ namespace sat { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << " (sat-blocked-clauses :elim-blocked-clauses " << (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses) + << " :elim-covered-clauses " + << (m_simplifier.m_num_covered_clauses - m_num_covered_clauses) << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } @@ -1379,6 +1496,7 @@ namespace sat { m_elim_counter -= num_pos * num_neg + before_lits; // eliminate variable + ++s.m_stats.m_elim_var_res; model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); save_clauses(mc_entry, m_pos_cls); save_clauses(mc_entry, m_neg_cls); @@ -1463,7 +1581,6 @@ namespace sat { order_vars_for_elim(vars); sat::elim_vars elim_bdd(*this); - std::cout << "vars to elim: " << vars.size() << "\n"; for (bool_var v : vars) { checkpoint(); if (m_elim_counter < 0) @@ -1471,11 +1588,9 @@ namespace sat { if (try_eliminate(v)) { m_num_elim_vars++; } -#if 1 else if (elim_bdd(v)) { m_num_elim_vars++; } -#endif } m_pos_cls.finalize(); @@ -1512,12 +1627,13 @@ namespace sat { st.update("subsumed", m_num_subsumed); st.update("subsumption resolution", m_num_sub_res); st.update("elim literals", m_num_elim_lits); - st.update("elim bool vars", m_num_elim_vars); st.update("elim blocked clauses", m_num_blocked_clauses); + st.update("elim covered clauses", m_num_covered_clauses); } void simplifier::reset_statistics() { m_num_blocked_clauses = 0; + m_num_covered_clauses = 0; m_num_subsumed = 0; m_num_sub_res = 0; m_num_elim_lits = 0; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 6ef0f8f18..fdfabb513 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -90,6 +90,7 @@ namespace sat { // stats unsigned m_num_blocked_clauses; + unsigned m_num_covered_clauses; unsigned m_num_subsumed; unsigned m_num_elim_vars; unsigned m_num_sub_res; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8004c9635..ca1fc7801 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -4038,6 +4038,8 @@ namespace sat { st.update("dyn subsumption resolution", m_dyn_sub_res); st.update("blocked correction sets", m_blocked_corr_sets); st.update("units", m_units); + st.update("elim bool vars", m_elim_var_res); + st.update("elim bool vars bdd", m_elim_var_bdd); } void stats::reset() { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 56071182b..58d2824c7 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -67,6 +67,8 @@ namespace sat { unsigned m_dyn_sub_res; unsigned m_non_learned_generation; unsigned m_blocked_corr_sets; + unsigned m_elim_var_res; + unsigned m_elim_var_bdd; unsigned m_units; stats() { reset(); } void reset(); diff --git a/src/test/bdd.cpp b/src/test/bdd.cpp index f3f6e6b8d..6826df35e 100644 --- a/src/test/bdd.cpp +++ b/src/test/bdd.cpp @@ -2,7 +2,7 @@ namespace sat { static void test1() { - bdd_manager m(20, 1000); + bdd_manager m(20); bdd v0 = m.mk_var(0); bdd v1 = m.mk_var(1); bdd v2 = m.mk_var(2); @@ -10,17 +10,17 @@ namespace sat { bdd c2 = v2 && v0 && v1; std::cout << c1 << "\n"; SASSERT(c1 == c2); - std::cout << "cnf size: " << m.cnf_size(c1) << "\n"; + std::cout << "cnf size: " << c1.cnf_size() << "\n"; c1 = v0 || v1 || v2; c2 = v2 || v1 || v0; std::cout << c1 << "\n"; SASSERT(c1 == c2); - std::cout << "cnf size: " << m.cnf_size(c1) << "\n"; + std::cout << "cnf size: " << c1.cnf_size() << "\n"; } static void test2() { - bdd_manager m(20, 1000); + bdd_manager m(20); bdd v0 = m.mk_var(0); bdd v1 = m.mk_var(1); bdd v2 = m.mk_var(2); @@ -35,7 +35,7 @@ namespace sat { } static void test3() { - bdd_manager m(20, 1000); + bdd_manager m(20); bdd v0 = m.mk_var(0); bdd v1 = m.mk_var(1); bdd v2 = m.mk_var(2); From 00a401260e65557ceb7c6b410963a49c4365e376 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Oct 2017 21:19:02 -0700 Subject: [PATCH 0279/1283] fixing cce Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 90 +++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 6ad88a31b..4bc42e76c 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -971,16 +971,16 @@ namespace sat { // Resolve intersection // Find literals that are in the intersection of all resolvents with l. // - void ri(literal l, literal_vector& inter) { - if (!process_var(l.var())) return; + bool ri(literal l, literal_vector& inter) { + if (!process_var(l.var())) return false; bool first = true; - for (watched & w : s.get_wlist(~l)) { + for (watched & w : s.get_wlist(l)) { if (w.is_binary_non_learned_clause()) { literal lit = w.get_literal(); - if (s.is_marked(~lit)) continue; + if (s.is_marked(~lit) && lit != ~l) continue; if (!first) { inter.reset(); - return; + return false; } first = false; inter.push_back(lit); @@ -992,7 +992,7 @@ namespace sat { bool tautology = false; clause & c = it.curr(); for (literal lit : c) { - if (s.is_marked(~lit)) { + if (s.is_marked(~lit) && lit != ~l) { tautology = true; break; } @@ -1017,56 +1017,58 @@ namespace sat { } } inter.shrink(j); - if (j == 0) return; + if (j == 0) return false; } } it.next(); } + return first; + } + + literal_vector m_added; + literal_vector m_intersection; + + bool cla(literal lit) { + bool is_tautology = false; + for (literal l : m_added) s.mark_visited(l); + unsigned num_iterations = 0, sz; + do { + ++num_iterations; + sz = m_added.size(); + for (unsigned i = 0; i < m_added.size(); ++i) { + if (ri(m_added[i], m_intersection) && m_added[i] == lit) { + is_tautology = true; + break; + } + for (literal l : m_intersection) { + if (!s.is_marked(l)) { + s.mark_visited(l); + m_added.push_back(l); + } + } + m_intersection.reset(); + } + } + while (m_added.size() > sz && !is_tautology); + for (literal l : m_added) s.unmark_visited(l); + m_intersection.reset(); + m_added.reset(); + if (is_tautology) std::cout << "taut: " << num_iterations << "\n"; + return is_tautology; } // perform covered clause elimination. // first extract the covered literal addition (CLA). // then check whether the CLA is blocked. bool cce(clause& c, literal lit) { - for (literal l : c) s.mark_visited(l); - literal_vector added, lits; - for (literal l : c) added.push_back(l); - for (unsigned i = 0; i < added.size(); ++i) { - ri(added[i], lits); - for (literal l : lits) { - if (!s.is_marked(l)) { - s.mark_visited(l); - added.push_back(l); - } - } - lits.reset(); - } - s.unmark_visited(lit); - bool is_tautology = (added.size() > c.size()) && all_tautology(lit); - for (literal l : added) s.unmark_visited(l); - return is_tautology; + for (literal l : c) m_added.push_back(l); + return cla(lit); } bool cce(literal lit, literal l2) { - literal_vector added, lits; - s.mark_visited(lit); - s.mark_visited(l2); - added.push_back(lit); - added.push_back(l2); - for (unsigned i = 0; i < added.size(); ++i) { - ri(added[i], lits); - for (literal l : lits) { - if (!s.is_marked(l)) { - s.mark_visited(l); - added.push_back(l); - } - } - lits.reset(); - } - s.unmark_visited(lit); - bool is_tautology = added.size() > 2 && all_tautology(lit); - for (literal l : added) s.unmark_visited(l); - return is_tautology; + m_added.push_back(lit); + m_added.push_back(l2); + return cla(lit); } void process(literal l) { @@ -1086,9 +1088,9 @@ namespace sat { SASSERT(c.contains(l)); s.mark_all_but(c, l); if (all_tautology(l)) { + s.unmark_all(c); block_clause(c, l, new_entry); s.m_num_blocked_clauses++; - s.unmark_all(c); } else if (cce(c, l)) { block_clause(c, l, new_entry); From d9ccb3928ec67b4d0bca29847053d822173172b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Oct 2017 09:05:25 -0700 Subject: [PATCH 0280/1283] fix debug build Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.h | 3 +-- src/sat/sat_elim_vars.cpp | 3 +-- src/sat/sat_simplifier.cpp | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index c0f1fc9b2..10caa0125 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -166,8 +166,6 @@ namespace sat { bdd mk_and(bdd const& a, bdd const& b); bdd mk_or(bdd const& a, bdd const& b); - std::ostream& display(std::ostream& out, bdd const& b); - public: struct mem_out {}; @@ -190,6 +188,7 @@ namespace sat { bdd mk_ite(bdd const& c, bdd const& t, bdd const& e); std::ostream& display(std::ostream& out); + std::ostream& display(std::ostream& out, bdd const& b); }; class bdd { diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index a5ca80a32..6edc125ea 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -121,7 +121,6 @@ namespace sat{ bdd b = m.mk_exists(m_var2index[v], b0); TRACE("elim_vars", tout << "eliminate " << v << "\n"; - tout << "clauses : " << clause_size << "\n"; for (watched const& w : simp.get_wlist(~pos_l)) { if (w.is_binary_non_learned_clause()) { tout << pos_l << " " << w.get_literal() << "\n"; @@ -150,7 +149,7 @@ namespace sat{ m.display(tout, b4); tout << "eliminated:\n"; tout << b << "\n"; - tout << m.cnf_size(b) << "\n"; + tout << b.cnf_size() << "\n"; ); return b; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 4bc42e76c..3bd5cefb9 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1150,8 +1150,8 @@ namespace sat { void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { if (new_entry == 0) new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); - TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l << "\n";); literal l2 = it->get_literal(); + TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l << "\n";); s.remove_bin_clause_half(l2, l, it->is_learned()); m_queue.decreased(~l2); mc.insert(*new_entry, l, l2); From da4e8118b2220d81662116d182c2cb11846f5fc6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Oct 2017 17:58:56 -0700 Subject: [PATCH 0281/1283] adding elim sequences Signed-off-by: Nikolaj Bjorner --- src/sat/sat_model_converter.cpp | 25 ++++++++++++++++++++++++- src/sat/sat_model_converter.h | 26 ++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index d4a994d0f..471d314c1 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -49,16 +49,35 @@ namespace sat { // and the following procedure flips its value. bool sat = false; bool var_sign = false; + unsigned index = 0; + literal prev = null_literal; for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause + if (!sat && it->m_elim_sequence[index]) { + SASSERT(prev != null_literal); + m[prev.var()] = prev.sign() ? l_false : l_true; + elim_sequence* s = it->m_elim_sequence[index]; +#if 0 + while (!sat) { + SASSERT(s); + for (literal l2 : s->clause()) { + sat = value_at(l2, m) == l_true; + } + s->clause(); + } +#endif + NOT_IMPLEMENTED_YET(); + } if (!sat) { m[it->var()] = var_sign ? l_false : l_true; break; } sat = false; + ++index; continue; } + prev = l; if (sat) continue; @@ -136,15 +155,17 @@ namespace sat { return e; } - void model_converter::insert(entry & e, clause const & c) { + void model_converter::insert(entry & e, clause const & c, elim_sequence* s) { SASSERT(c.contains(e.var())); SASSERT(m_entries.begin() <= &e); SASSERT(&e < m_entries.end()); for (literal l : c) e.m_clauses.push_back(l); e.m_clauses.push_back(null_literal); + e.m_elim_sequence.push_back(s); TRACE("sat_mc_bug", tout << "adding: " << c << "\n";); } + void model_converter::insert(entry & e, literal l1, literal l2) { SASSERT(l1.var() == e.var() || l2.var() == e.var()); SASSERT(m_entries.begin() <= &e); @@ -152,6 +173,7 @@ namespace sat { e.m_clauses.push_back(l1); e.m_clauses.push_back(l2); e.m_clauses.push_back(null_literal); + e.m_elim_sequence.push_back(nullptr); TRACE("sat_mc_bug", tout << "adding (binary): " << l1 << " " << l2 << "\n";); } @@ -163,6 +185,7 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) e.m_clauses.push_back(c[i]); e.m_clauses.push_back(null_literal); + e.m_elim_sequence.push_back(nullptr); // TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (literal l : c) tout << l << " "; tout << "\n";); } diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index aae3ad479..c5cefe84e 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -20,6 +20,7 @@ Revision History: #define SAT_MODEL_CONVERTER_H_ #include "sat/sat_types.h" +#include "util/ref_vector.h" namespace sat { /** @@ -36,19 +37,40 @@ namespace sat { it can be converted into a general Z3 model_converter */ class model_converter { + public: + class elim_sequence { + unsigned m_refcount; + elim_sequence* m_next; + literal m_literal; + literal_vector m_clause; + public: + elim_sequence(literal l, literal_vector const& clause, elim_sequence* next): + m_refcount(0), + m_next(next), + m_literal(l), + m_clause(clause) { + if (m_next) m_next->inc_ref(); + } + ~elim_sequence() { if (m_next) m_next->dec_ref(); } + void inc_ref() { ++m_refcount; } + void dec_ref() { if (0 == --m_refcount) dealloc(this); } + }; + enum kind { ELIM_VAR = 0, BLOCK_LIT }; class entry { friend class model_converter; unsigned m_var:31; unsigned m_kind:1; literal_vector m_clauses; // the different clauses are separated by null_literal + sref_vector m_elim_sequence; entry(kind k, bool_var v):m_var(v), m_kind(k) {} public: entry(entry const & src): m_var(src.m_var), m_kind(src.m_kind), - m_clauses(src.m_clauses) { + m_clauses(src.m_clauses), + m_elim_sequence(src.m_elim_sequence) { } bool_var var() const { return m_var; } kind get_kind() const { return static_cast(m_kind); } @@ -62,7 +84,7 @@ namespace sat { model_converter& operator=(model_converter const& other); entry & mk(kind k, bool_var v); - void insert(entry & e, clause const & c); + void insert(entry & e, clause const & c, elim_sequence* s = nullptr); void insert(entry & e, literal l1, literal l2); void insert(entry & e, clause_wrapper const & c); From 42e9a0156b6a383f6ec5c9161026f38be6d0a18e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Oct 2017 04:52:06 -0700 Subject: [PATCH 0282/1283] add elimination stack for model reconstruction Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 53 ++++++++++++++++++++++++++- src/sat/sat_model_converter.cpp | 60 ++++++++++++++++++------------ src/sat/sat_model_converter.h | 26 ++++++------- src/sat/sat_simplifier.cpp | 65 +++++++++++++++++++++++---------- 4 files changed, 145 insertions(+), 59 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index edc8ad2a8..d88b28e74 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -239,9 +239,53 @@ namespace sat { // TBD } - void bdd_manager::sift_up(unsigned level) { + void bdd_manager::sift_up(unsigned lvl) { // exchange level and level + 1. - +#if 0 + m_relevel.reset(); // nodes to be re-leveled. + + for (unsigned n : m_level2nodes[lvl + 1]) { + BDD l = lo(n); + BDD h = hi(n); + if (l == 0 && h == 0) continue; + BDD a, b, c, d; + if (level(l) == lvl) { + a = lo(l); + b = hi(l); + } + else { + a = b = l; + } + if (level(h) == lvl) { + c = lo(h); + d = hi(h); + } + else { + c = d = h; + } + + push(make_node(lvl, a, c)); + push(make_node(lvl, b, d)); + m_node_table.remove(m_nodes[n]); + m_nodes[n].m_lo = read(2); + m_nodes[n].m_hi = read(1); + m_relevel.push_back(l); + m_relevel.push_back(r); + // TBD: read(2); read(1); should be inserted into m_level2nodes[lvl]; + pop(2); + m_node_table.insert(m_nodes[n]); + } + unsigned v = m_level2var[lvl]; + unsigned w = m_level2var[lvl+1]; + std::swap(m_level2var[lvl], m_level2var[lvl+1]); + std::swap(m_var2level[v], m_var2level[w]); + for (unsigned n : m_relevel) { + if (level(n) == lvl) { + // whoever points to n uses it as if it is level lvl + 1. + m_level2nodes[m_node2levelpos[n]]; + } + } +#endif } bdd bdd_manager::mk_var(unsigned i) { @@ -454,9 +498,14 @@ namespace sat { } for (unsigned i = m_nodes.size(); i-- > 2; ) { if (!reachable[i]) { + m_nodes[i].m_lo = m_nodes[i].m_hi = 0; m_free_nodes.push_back(i); } } + // sort free nodes so that adjacent nodes are picked in order of use + std::sort(m_free_nodes.begin(), m_free_nodes.end()); + m_free_nodes.reverse(); + for (auto* e : m_op_cache) { m_alloc.deallocate(sizeof(*e), e); } diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 471d314c1..c79cd2944 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -38,6 +38,22 @@ namespace sat { return *this; } + void model_converter::process_stack(model & m, literal_vector const& stack) const { + SASSERT(!stack.empty()); + unsigned sz = stack.size(); + SASSERT(stack[sz - 1] == null_literal); + for (unsigned i = sz - 1; i-- > 0; ) { + literal lit = stack[i]; // this is the literal that is pivoted on. It is repeated + bool sat = false; + for (; i > 0 && stack[--i] != null_literal;) { + if (sat) continue; + sat = value_at(stack[i], m) == l_true; + } + if (!sat) { + m[lit.var()] = lit.sign() ? l_false : l_true; + } + } + } void model_converter::operator()(model & m) const { vector::const_iterator begin = m_entries.begin(); @@ -50,34 +66,20 @@ namespace sat { bool sat = false; bool var_sign = false; unsigned index = 0; - literal prev = null_literal; for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause - if (!sat && it->m_elim_sequence[index]) { - SASSERT(prev != null_literal); - m[prev.var()] = prev.sign() ? l_false : l_true; - elim_sequence* s = it->m_elim_sequence[index]; -#if 0 - while (!sat) { - SASSERT(s); - for (literal l2 : s->clause()) { - sat = value_at(l2, m) == l_true; - } - s->clause(); - } -#endif - NOT_IMPLEMENTED_YET(); - } if (!sat) { m[it->var()] = var_sign ? l_false : l_true; - break; + } + elim_stack* s = it->m_elim_stack[index]; + if (s) { + process_stack(m, s->stack()); } sat = false; ++index; - continue; + continue; } - prev = l; if (sat) continue; @@ -155,17 +157,16 @@ namespace sat { return e; } - void model_converter::insert(entry & e, clause const & c, elim_sequence* s) { + void model_converter::insert(entry & e, clause const & c) { SASSERT(c.contains(e.var())); SASSERT(m_entries.begin() <= &e); SASSERT(&e < m_entries.end()); for (literal l : c) e.m_clauses.push_back(l); e.m_clauses.push_back(null_literal); - e.m_elim_sequence.push_back(s); + e.m_elim_stack.push_back(nullptr); TRACE("sat_mc_bug", tout << "adding: " << c << "\n";); } - void model_converter::insert(entry & e, literal l1, literal l2) { SASSERT(l1.var() == e.var() || l2.var() == e.var()); SASSERT(m_entries.begin() <= &e); @@ -173,7 +174,7 @@ namespace sat { e.m_clauses.push_back(l1); e.m_clauses.push_back(l2); e.m_clauses.push_back(null_literal); - e.m_elim_sequence.push_back(nullptr); + e.m_elim_stack.push_back(nullptr); TRACE("sat_mc_bug", tout << "adding (binary): " << l1 << " " << l2 << "\n";); } @@ -185,10 +186,21 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) e.m_clauses.push_back(c[i]); e.m_clauses.push_back(null_literal); - e.m_elim_sequence.push_back(nullptr); + e.m_elim_stack.push_back(nullptr); // TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (literal l : c) tout << l << " "; tout << "\n";); } + void model_converter::insert(entry & e, literal_vector const& c, literal_vector const& elims) { + SASSERT(c.contains(literal(e.var(), false)) || c.contains(literal(e.var(), true))); + SASSERT(m_entries.begin() <= &e); + SASSERT(&e < m_entries.end()); + for (literal l : c) e.m_clauses.push_back(l); + e.m_clauses.push_back(null_literal); + e.m_elim_stack.push_back(alloc(elim_stack, elims)); + TRACE("sat_mc_bug", tout << "adding: " << c << "\n";); + } + + bool model_converter::check_invariant(unsigned num_vars) const { // After a variable v occurs in an entry n and the entry has kind ELIM_VAR, // then the variable must not occur in any other entry occurring after it. diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index c5cefe84e..00fd637b7 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -39,22 +39,18 @@ namespace sat { class model_converter { public: - class elim_sequence { + class elim_stack { unsigned m_refcount; - elim_sequence* m_next; - literal m_literal; - literal_vector m_clause; + literal_vector m_stack; public: - elim_sequence(literal l, literal_vector const& clause, elim_sequence* next): + elim_stack(literal_vector const& stack): m_refcount(0), - m_next(next), - m_literal(l), - m_clause(clause) { - if (m_next) m_next->inc_ref(); + m_stack(stack) { } - ~elim_sequence() { if (m_next) m_next->dec_ref(); } + ~elim_stack() { } void inc_ref() { ++m_refcount; } void dec_ref() { if (0 == --m_refcount) dealloc(this); } + literal_vector const& stack() const { return m_stack; } }; enum kind { ELIM_VAR = 0, BLOCK_LIT }; @@ -63,20 +59,23 @@ namespace sat { unsigned m_var:31; unsigned m_kind:1; literal_vector m_clauses; // the different clauses are separated by null_literal - sref_vector m_elim_sequence; + sref_vector m_elim_stack; entry(kind k, bool_var v):m_var(v), m_kind(k) {} public: entry(entry const & src): m_var(src.m_var), m_kind(src.m_kind), m_clauses(src.m_clauses), - m_elim_sequence(src.m_elim_sequence) { + m_elim_stack(src.m_elim_stack) { } bool_var var() const { return m_var; } kind get_kind() const { return static_cast(m_kind); } }; private: vector m_entries; + + void process_stack(model & m, literal_vector const& stack) const; + public: model_converter(); ~model_converter(); @@ -84,9 +83,10 @@ namespace sat { model_converter& operator=(model_converter const& other); entry & mk(kind k, bool_var v); - void insert(entry & e, clause const & c, elim_sequence* s = nullptr); + void insert(entry & e, clause const & c); void insert(entry & e, literal l1, literal l2); void insert(entry & e, clause_wrapper const & c); + void insert(entry & c, literal_vector const& covered_clause, literal_vector const& elim_stack); bool empty() const { return m_entries.empty(); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3bd5cefb9..b09d180c0 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1025,34 +1025,39 @@ namespace sat { return first; } - literal_vector m_added; + literal_vector m_covered_clause; literal_vector m_intersection; + literal_vector m_elim_stack; bool cla(literal lit) { bool is_tautology = false; - for (literal l : m_added) s.mark_visited(l); + for (literal l : m_covered_clause) s.mark_visited(l); unsigned num_iterations = 0, sz; + m_elim_stack.reset(); do { ++num_iterations; - sz = m_added.size(); - for (unsigned i = 0; i < m_added.size(); ++i) { - if (ri(m_added[i], m_intersection) && m_added[i] == lit) { + sz = m_covered_clause.size(); + for (unsigned i = 0; i < m_covered_clause.size(); ++i) { + m_intersection.reset(); + if (ri(m_covered_clause[i], m_intersection) && m_covered_clause[i] == lit) { is_tautology = true; break; } for (literal l : m_intersection) { if (!s.is_marked(l)) { s.mark_visited(l); - m_added.push_back(l); + m_covered_clause.push_back(l); } } - m_intersection.reset(); + if (!m_intersection.empty()) { + m_elim_stack.append(m_covered_clause); // the current clause + m_elim_stack.push_back(m_covered_clause[i]); // the pivot literal + m_elim_stack.push_back(null_literal); // null demarcation + } } } - while (m_added.size() > sz && !is_tautology); - for (literal l : m_added) s.unmark_visited(l); - m_intersection.reset(); - m_added.reset(); + while (m_covered_clause.size() > sz && !is_tautology); + for (literal l : m_covered_clause) s.unmark_visited(l); if (is_tautology) std::cout << "taut: " << num_iterations << "\n"; return is_tautology; } @@ -1061,13 +1066,15 @@ namespace sat { // first extract the covered literal addition (CLA). // then check whether the CLA is blocked. bool cce(clause& c, literal lit) { - for (literal l : c) m_added.push_back(l); + m_covered_clause.reset(); + for (literal l : c) m_covered_clause.push_back(l); return cla(lit); } bool cce(literal lit, literal l2) { - m_added.push_back(lit); - m_added.push_back(l2); + m_covered_clause.reset(); + m_covered_clause.push_back(lit); + m_covered_clause.push_back(l2); return cla(lit); } @@ -1093,7 +1100,7 @@ namespace sat { s.m_num_blocked_clauses++; } else if (cce(c, l)) { - block_clause(c, l, new_entry); + block_covered_clause(c, l, new_entry); s.m_num_covered_clauses++; } it.next(); @@ -1121,7 +1128,7 @@ namespace sat { s.m_num_blocked_clauses++; } else if (cce(l, l2)) { - block_binary(it, l, new_entry); + block_covered_binary(it, l, new_entry); s.m_num_covered_clauses++; } else { @@ -1134,12 +1141,11 @@ namespace sat { } } - void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { + void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); if (new_entry == 0) new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); m_to_remove.push_back(&c); - mc.insert(*new_entry, c); for (literal lit : c) { if (lit != l && process_var(lit.var())) { m_queue.decreased(~lit); @@ -1147,14 +1153,33 @@ namespace sat { } } - void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { + void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { + prepare_block_clause(c, l, new_entry); + mc.insert(*new_entry, c); + } + + void block_covered_clause(clause& c, literal l, model_converter::entry *& new_entry) { + prepare_block_clause(c, l, new_entry); + mc.insert(*new_entry, m_covered_clause, m_elim_stack); + } + + void prepare_block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { if (new_entry == 0) new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); literal l2 = it->get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l << "\n";); s.remove_bin_clause_half(l2, l, it->is_learned()); m_queue.decreased(~l2); - mc.insert(*new_entry, l, l2); + } + + void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { + prepare_block_binary(it, l, new_entry); + mc.insert(*new_entry, l, it->get_literal()); + } + + void block_covered_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { + prepare_block_binary(it, l, new_entry); + mc.insert(*new_entry, m_covered_clause, m_elim_stack); } bool all_tautology(literal l) { From 806690571e06f12f21239dd8d68d1786ec9cec4e Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Tue, 17 Oct 2017 13:15:34 -0700 Subject: [PATCH 0283/1283] Lookahead clause size optimization. Fixed some missing propagations --- src/sat/sat_lookahead.cpp | 164 ++++++++++++++++++++++++++------------ src/sat/sat_lookahead.h | 6 +- 2 files changed, 117 insertions(+), 53 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index f5d0910ab..edb881aa4 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -155,7 +155,7 @@ namespace sat { if (is_stamped(~w)) { // u \/ v, ~v \/ w, u \/ ~w => u is unit TRACE("sat", tout << "tc1: " << u << "\n";); - assign(u); + propagated(u); return false; } if (m_num_tc1 < m_config.m_tc1_limit) { @@ -181,14 +181,14 @@ namespace sat { set_bstamps(~u); if (is_stamped(~v)) { TRACE("sat", tout << "try_add_binary: " << u << "\n";); - assign(u); // u \/ ~v, u \/ v => u is a unit literal + propagated(u); // u \/ ~v, u \/ v => u is a unit literal } else if (!is_stamped(v) && add_tc1(u, v)) { // u \/ v is not in index set_bstamps(~v); if (is_stamped(~u)) { - TRACE("sat", tout << "try_add_binary: " << v << "\n";); - assign(v); // v \/ ~u, u \/ v => v is a unit literal + TRACE("sat", tout << "try_add_binary: " << v << "\n";); + propagated(v); // v \/ ~u, u \/ v => v is a unit literal } else if (add_tc1(v, u)) { update_prefix(u); @@ -407,6 +407,37 @@ namespace sat { return true; } + bool lookahead::missed_propagation() const { + for (literal l1 : m_trail) { + SASSERT(is_true(l1)); + for (literal l2 : m_binary[l1.index()]) { + if (is_undef(l2)) return true; + } + unsigned sz = m_ternary_count[(~l1).index()]; + for (binary b : m_ternary[(~l1).index()]) { + if (sz-- == 0) break; + if ((is_false(b.m_u) && is_undef(b.m_v)) || (is_false(b.m_v) && is_undef(b.m_u))) + return true; + } + } + for (nary * n : m_nary_clauses) { + if (n->size() == 1 && !is_true(n->get_head())) { + for (literal lit : *n) { + if (is_undef(lit)) return true; + } + } + } + return false; + } + + bool lookahead::missed_conflict() const { + if (inconsistent()) return false; + for (nary * n : m_nary_clauses) { + if (n->size() == 0) return true; + } + return false; + } + void lookahead::init_pre_selection(unsigned level) { switch (m_config.m_reward_type) { case ternary_reward: { @@ -1098,11 +1129,19 @@ namespace sat { } void lookahead::lookahead_backtrack() { - while (!m_trail.empty() && is_undef(m_trail.back())) { + literal lit = null_literal; + while (!m_trail.empty() && is_undef((lit = m_trail.back()))) { + if (m_qhead == m_trail.size()) { + unsigned sz = m_nary_count[(~lit).index()]; + for (nary* n : m_nary[(~lit).index()]) { + if (sz-- == 0) break; + n->inc_size(); + } + --m_qhead; + } m_trail.pop_back(); } SASSERT(m_trail_lim.empty() || m_trail.size() >= m_trail_lim.back()); - m_qhead = std::min(m_qhead, m_trail.size()); } // @@ -1137,14 +1176,15 @@ namespace sat { lbool lookahead::propagate_ternary(literal l1, literal l2) { if (is_fixed(l1)) { if (is_false(l1)) { - if (is_undef(l2)) { - propagated(l2); - } - else if (is_false(l2)) { + if (is_false(l2)) { TRACE("sat", tout << l1 << " " << l2 << " " << "\n";); set_conflict(); + return l_false; } - return l_false; + else if (is_undef(l2)) { + propagated(l2); + } + return l_true; } else { return l_true; @@ -1298,10 +1338,11 @@ namespace sat { unsigned sz = m_nary_count[(~l).index()]; literal lit; SASSERT(m_search_mode == lookahead_mode::searching); - for (nary * n : m_nary[(~l).index()]) { + for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; unsigned len = n->dec_size(); - if (m_inconsistent) continue; + if (is_true(n->get_head())) continue; + if (inconsistent()) continue; if (len <= 1) continue; // already processed // find the two unassigned literals, if any if (len == 2) { @@ -1357,53 +1398,35 @@ namespace sat { void lookahead::propagate_clauses_lookahead(literal l) { // clauses where l is negative unsigned sz = m_nary_count[(~l).index()]; - literal lit; SASSERT(m_search_mode == lookahead_mode::lookahead1 || m_search_mode == lookahead_mode::lookahead2); for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; - - if (is_true(n->get_head())) { - continue; - } - literal l1 = null_literal; - literal l2 = null_literal; - bool skip_clause = false; - unsigned nonfixed = 0; - for (literal lit : *n) { - if (!is_fixed(lit)) { - ++nonfixed; - if (l1 == null_literal) { - l1 = lit; - } - else if (l2 == null_literal) { - l2 = lit; + unsigned nonfixed = n->dec_size(); + if (is_true(n->get_head())) continue; + if (inconsistent()) continue; + if (nonfixed <= 1) { + bool found_conflict = true; + for (literal lit : *n) { + if (!is_fixed(lit)) { + propagated(lit); + found_conflict = false; + break; } - else if (m_search_mode == lookahead_mode::lookahead2) { - skip_clause = true; + else if (is_true(lit)) { + n->set_head(lit); + found_conflict = false; break; } } - else if (is_true(lit)) { - n->set_head(lit); - skip_clause = true; - break; + if (found_conflict) { + set_conflict(); + continue; } } - if (skip_clause) { - // skip, the clause - } - else if (l1 == null_literal) { - set_conflict(); - return; - } - else if (l2 == null_literal) { - propagated(l1); - } - else { + else if (m_search_mode == lookahead_mode::lookahead1) { SASSERT(nonfixed >= 2); - SASSERT(m_search_mode == lookahead_mode::lookahead1); switch (m_config.m_reward_type) { case heule_schur_reward: { double to_add = 0; @@ -1418,9 +1441,35 @@ namespace sat { case heule_unit_reward: m_lookahead_reward += pow(0.5, nonfixed); break; + case march_cu_reward: + m_lookahead_reward += 3.3 * pow(0.5, nonfixed - 2); + break; case ternary_reward: if (nonfixed == 2) { - m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + literal l1 = null_literal; + literal l2 = null_literal; + for (literal lit : *n) { + if (!is_fixed(lit)) { + if (l1 == null_literal) { + l1 = lit; + } + else { + SASSERT(l2 != null_literal); + l2 = lit; + break; + } + } + } + if (l1 == null_literal) { + set_conflict(); + continue; + } + else if (l2 == null_literal) { + propagated(l1); + } + else { + m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + } } else { m_lookahead_reward += (double)0.001; @@ -1431,6 +1480,14 @@ namespace sat { } } } + // clauses where l is positive: + sz = m_nary_count[l.index()]; + for (nary* n : m_nary[l.index()]) { + if (sz-- == 0) break; + if (m_stamp[l.var()] > m_stamp[n->get_head().var()]) { + n->set_head(l); + } + } } void lookahead::remove_clause_at(literal l, nary& n) { @@ -1567,9 +1624,9 @@ namespace sat { void lookahead::propagate_binary(literal l) { literal_vector const& lits = m_binary[l.index()]; TRACE("sat", tout << l << " => " << lits << "\n";); - for (literal l : lits) { + for (literal lit : lits) { if (inconsistent()) break; - assign(l); + assign(lit); } } @@ -1584,6 +1641,8 @@ namespace sat { propagate_clauses(m_trail[m_qhead++]); } SASSERT(m_qhead == m_trail.size() || (inconsistent() && m_qhead < m_trail.size())); + //SASSERT(!missed_conflict()); + //SASSERT(inconsistent() || !missed_propagation()); TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } @@ -1600,6 +1659,7 @@ namespace sat { checkpoint(); literal lit = m_lookahead[i].m_lit; if (lit == last_changed) { + SASSERT(!change); break; } if (scope_lvl() == 1) { @@ -1812,6 +1872,7 @@ namespace sat { lookahead_backtrack(); assign(l); propagate(); + //SASSERT(!inconsistent()); unsigned old_sz = m_trail.size(); bool change = true; literal last_changed = null_literal; @@ -1847,6 +1908,7 @@ namespace sat { propagate(); change = true; last_changed = lit; + m_wstack.push_back(~lit); } } base += 2 * m_lookahead.size(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index c9ce7d946..d30485254 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -90,7 +90,7 @@ namespace sat { m_min_cutoff = 30; m_preselect = false; m_level_cand = 600; - m_delta_rho = (double)0.25; + m_delta_rho = (double)0.85; m_dl_max_iterations = 2; m_tc1_limit = 10000000; m_reward_type = ternary_reward; @@ -340,6 +340,8 @@ namespace sat { std::ostream& display_candidates(std::ostream& out) const; bool is_unsat() const; bool is_sat() const; + bool missed_propagation() const; + bool missed_conflict() const; void init_pre_selection(unsigned level); void ensure_H(unsigned level); void h_scores(svector& h, svector& hp); @@ -503,7 +505,7 @@ namespace sat { unsigned do_double(literal l, unsigned& base); unsigned double_look(literal l, unsigned& base); void set_conflict() { TRACE("sat", tout << "conflict\n";); m_inconsistent = true; } - bool inconsistent() { return m_inconsistent; } + bool inconsistent() const { return m_inconsistent; } unsigned scope_lvl() const { return m_trail_lim.size(); } From 43f82144536ed14f362b8daa7dd46f73938316a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Oct 2017 13:25:08 -0700 Subject: [PATCH 0284/1283] local Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 105 ++++++++++++++++++++++++++++++++------------ src/sat/sat_bdd.h | 9 ++++ src/util/vector.h | 2 +- 3 files changed, 88 insertions(+), 28 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index d88b28e74..52a362728 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -43,6 +43,8 @@ namespace sat { m_max_num_bdd_nodes = 1 << 24; // up to 16M nodes m_mark_level = 0; alloc_free_nodes(1024 + num_vars); + m_disable_gc = false; + m_is_new_node = false; // add variables for (unsigned i = 0; i < num_vars; ++i) { @@ -203,6 +205,7 @@ namespace sat { } bdd_manager::BDD bdd_manager::make_node(unsigned level, BDD l, BDD r) { + m_is_new_node = false; if (l == r) { return l; } @@ -214,7 +217,7 @@ namespace sat { } e->get_data().m_refcount = 0; bool do_gc = m_free_nodes.empty(); - if (do_gc) { + if (do_gc && !m_disable_gc) { gc(); e = m_node_table.insert_if_not_there2(n); e->get_data().m_refcount = 0; @@ -223,15 +226,14 @@ namespace sat { if (m_nodes.size() > m_max_num_bdd_nodes) { throw mem_out(); } - e->get_data().m_index = m_nodes.size(); - m_nodes.push_back(e->get_data()); alloc_free_nodes(m_nodes.size()/2); } - else { - e->get_data().m_index = m_free_nodes.back(); - m_nodes[e->get_data().m_index] = e->get_data(); - m_free_nodes.pop_back(); - } + + SASSERT(!m_free_nodes.empty()); + e->get_data().m_index = m_free_nodes.back(); + m_nodes[e->get_data().m_index] = e->get_data(); + m_free_nodes.pop_back(); + m_is_new_node = true; return e->get_data().m_index; } @@ -241,10 +243,45 @@ namespace sat { void bdd_manager::sift_up(unsigned lvl) { // exchange level and level + 1. -#if 0 - m_relevel.reset(); // nodes to be re-leveled. + m_S.reset(); + m_T.reset(); + m_disable_gc = true; for (unsigned n : m_level2nodes[lvl + 1]) { + BDD l = lo(n); + BDD h = hi(n); + if (l == 0 && h == 0) continue; + if ((is_const(l) || level(l) != lvl) && + (is_const(h) || level(h) != lvl)) { + m_S.push_back(n); + } + else { + m_T.push_back(n); + } + m_node_table.remove(m_nodes[n]); + } + + for (unsigned n : m_level2nodes[lvl]) { + bdd_node& node = m_nodes[n]; + m_node_table.remove(node); + if (m_max_parent[n] == lvl + 1 && node.m_refcount == 0) { + node.set_internal(); + m_free_nodes.push_back(n); + } + else { + node.m_level = lvl + 1; + m_node_table.insert(node); + } + } + + for (unsigned n : m_S) { + m_nodes[n].m_level = lvl; + m_node_table.insert(m_nodes[n]); + } + + std::swap(m_level2nodes[lvl], m_level2nodes[lvl + 1]); + + for (unsigned n : m_T) { BDD l = lo(n); BDD h = hi(n); if (l == 0 && h == 0) continue; @@ -264,28 +301,42 @@ namespace sat { c = d = h; } - push(make_node(lvl, a, c)); - push(make_node(lvl, b, d)); - m_node_table.remove(m_nodes[n]); - m_nodes[n].m_lo = read(2); - m_nodes[n].m_hi = read(1); - m_relevel.push_back(l); - m_relevel.push_back(r); - // TBD: read(2); read(1); should be inserted into m_level2nodes[lvl]; - pop(2); + unsigned ac = make_node(lvl, a, c); + if (is_new_node()) { + m_level2nodes[lvl].push_back(ac); + m_max_parent.setx(ac, lvl + 1, 0); + } + unsigned bd = make_node(lvl, b, d); + if (is_new_node()) { + m_level2nodes[lvl].push_back(bd); + m_max_parent.setx(bd, lvl + 1, 0); + } + m_nodes[n].m_lo = ac; + m_nodes[n].m_hi = bd; m_node_table.insert(m_nodes[n]); } unsigned v = m_level2var[lvl]; unsigned w = m_level2var[lvl+1]; std::swap(m_level2var[lvl], m_level2var[lvl+1]); std::swap(m_var2level[v], m_var2level[w]); - for (unsigned n : m_relevel) { - if (level(n) == lvl) { - // whoever points to n uses it as if it is level lvl + 1. - m_level2nodes[m_node2levelpos[n]]; - } + m_disable_gc = false; + } + + void bdd_manager::init_reorder() { + m_level2nodes.reset(); + unsigned sz = m_nodes.size(); + m_max_parent.fill(sz, 0); + for (unsigned i = 0; i < m_level2var.size(); ++i) { + m_level2nodes.push_back(unsigned_vector()); + } + for (unsigned i = 0; i < sz; ++i) { + bdd_node const& n = m_nodes[i]; + if (n.is_internal()) continue; + SASSERT(i == m_nodes[i].m_index); + m_level2nodes[n.m_level].push_back(i); + m_max_parent[n.m_lo] = std::max(m_max_parent[n.m_lo], n.m_level); + m_max_parent[n.m_hi] = std::max(m_max_parent[n.m_hi], n.m_level); } -#endif } bdd bdd_manager::mk_var(unsigned i) { @@ -498,7 +549,7 @@ namespace sat { } for (unsigned i = m_nodes.size(); i-- > 2; ) { if (!reachable[i]) { - m_nodes[i].m_lo = m_nodes[i].m_hi = 0; + m_nodes[i].set_internal(); m_free_nodes.push_back(i); } } @@ -559,7 +610,7 @@ namespace sat { std::ostream& bdd_manager::display(std::ostream& out) { for (unsigned i = 0; i < m_nodes.size(); ++i) { bdd_node const& n = m_nodes[i]; - if (n.m_lo == 0 && n.m_hi == 0) continue; + if (n.is_internal()) continue; out << i << " : " << m_level2var[n.m_level] << " " << n.m_lo << " " << n.m_hi << "\n"; } return out; diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index 10caa0125..f38c26d21 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -57,6 +57,8 @@ namespace sat { BDD m_hi; unsigned m_index; unsigned hash() const { return mk_mix(m_level, m_lo, m_hi); } + bool is_internal() const { return m_lo == 0 && m_hi == 0; } + void set_internal() { m_lo = m_hi = 0; } }; struct hash_node { @@ -112,9 +114,15 @@ namespace sat { mutable unsigned m_mark_level; mutable svector m_count; mutable svector m_todo; + bool m_disable_gc; + bool m_is_new_node; unsigned m_max_num_bdd_nodes; + unsigned_vector m_S, m_T; // used for reordering + vector m_level2nodes; + unsigned_vector m_max_parent; BDD make_node(unsigned level, BDD l, BDD r); + bool is_new_node() const { return m_is_new_node; } BDD apply_const(BDD a, BDD b, bdd_op op); BDD apply(BDD arg1, BDD arg2, bdd_op op); @@ -142,6 +150,7 @@ namespace sat { bool is_marked(unsigned i) { return m_mark[i] == m_mark_level; } void try_reorder(); + void init_reorder(); void sift_up(unsigned level); static const BDD false_bdd = 0; diff --git a/src/util/vector.h b/src/util/vector.h index 2e2640de3..c60585512 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -410,7 +410,7 @@ public: void fill(unsigned sz, T const & elem) { resize(sz); - fill(sz, elem); + fill(elem); } bool contains(T const & elem) const { From e0e7836c121c3daa587d716767cc4bff575a4abc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Oct 2017 14:20:49 -0700 Subject: [PATCH 0285/1283] working on BDD reordering Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 85 +++++++++++++++++++++++++++++++++++---- src/sat/sat_bdd.h | 3 ++ src/sat/sat_lookahead.cpp | 30 +------------- 3 files changed, 82 insertions(+), 36 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 52a362728..1073f482e 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -238,10 +238,82 @@ namespace sat { } void bdd_manager::try_reorder() { - // TBD + init_reorder(); + for (unsigned i = 0; i < m_var2level.size(); ++i) { + sift_var(i); + } + } + + double bdd_manager::current_cost() { +#if 0 + +#endif + return m_nodes.size() - m_free_nodes.size(); + } + + bool bdd_manager::is_bad_cost(double current_cost, double best_cost) const { + return current_cost > 1.1 * best_cost; + } + + void bdd_manager::sift_var(unsigned v) { + unsigned lvl = m_var2level[v]; + unsigned start = lvl; + double best_cost = current_cost(); + bool first = true; + unsigned max_lvl = m_level2nodes.size()-1; + if (lvl*2 < max_lvl) { + goto go_down; + } + go_up: + while (lvl < max_lvl) { + sift_up(lvl); + ++lvl; + double cost = current_cost(); + if (is_bad_cost(cost, best_cost)) break; + best_cost = std::min(cost, best_cost); + } + if (first) { + first = false; + while (lvl != start) { + sift_up(lvl-1); + --lvl; + } + goto go_down; + } + else { + while (current_cost() != best_cost) { + sift_up(lvl-1); + --lvl; + } + return; + } + go_down: + while (lvl > 0) { + sift_up(lvl-1); + --lvl; + double cost = current_cost(); + if (is_bad_cost(cost, best_cost)) break; + best_cost = std::min(cost, best_cost); + } + if (first) { + first = false; + while (lvl != start) { + sift_up(lvl); + ++lvl; + } + goto go_up; + } + else { + while (current_cost() != best_cost) { + sift_up(lvl); + ++lvl; + } + return; + } } void bdd_manager::sift_up(unsigned lvl) { + if (m_level2nodes[lvl].empty()) return; // exchange level and level + 1. m_S.reset(); m_T.reset(); @@ -326,16 +398,15 @@ namespace sat { m_level2nodes.reset(); unsigned sz = m_nodes.size(); m_max_parent.fill(sz, 0); - for (unsigned i = 0; i < m_level2var.size(); ++i) { - m_level2nodes.push_back(unsigned_vector()); - } for (unsigned i = 0; i < sz; ++i) { bdd_node const& n = m_nodes[i]; if (n.is_internal()) continue; + unsigned lvl = n.m_level; SASSERT(i == m_nodes[i].m_index); - m_level2nodes[n.m_level].push_back(i); - m_max_parent[n.m_lo] = std::max(m_max_parent[n.m_lo], n.m_level); - m_max_parent[n.m_hi] = std::max(m_max_parent[n.m_hi], n.m_level); + while (m_level2nodes.size() <= lvl) m_level2nodes.push_back(unsigned_vector()); + m_level2nodes[lvl].push_back(i); + m_max_parent[n.m_lo] = std::max(m_max_parent[n.m_lo], lvl); + m_max_parent[n.m_hi] = std::max(m_max_parent[n.m_hi], lvl); } } diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index f38c26d21..dbd19ec61 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -152,6 +152,9 @@ namespace sat { void try_reorder(); void init_reorder(); void sift_up(unsigned level); + void sift_var(unsigned v); + double current_cost(); + bool is_bad_cost(double new_cost, double best_cost) const; static const BDD false_bdd = 0; static const BDD true_bdd = 1; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index edb881aa4..f607d53ad 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1445,35 +1445,7 @@ namespace sat { m_lookahead_reward += 3.3 * pow(0.5, nonfixed - 2); break; case ternary_reward: - if (nonfixed == 2) { - literal l1 = null_literal; - literal l2 = null_literal; - for (literal lit : *n) { - if (!is_fixed(lit)) { - if (l1 == null_literal) { - l1 = lit; - } - else { - SASSERT(l2 != null_literal); - l2 = lit; - break; - } - } - } - if (l1 == null_literal) { - set_conflict(); - continue; - } - else if (l2 == null_literal) { - propagated(l1); - } - else { - m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; - } - } - else { - m_lookahead_reward += (double)0.001; - } + UNREACHABLE(); break; case unit_literal_reward: break; From cf2512ce90ddaf482f317258b9e227d8b04f1a43 Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Tue, 17 Oct 2017 16:03:58 -0700 Subject: [PATCH 0286/1283] Added literal promotion --- src/sat/sat_lookahead.cpp | 26 +++++++++++++++++++++++--- src/sat/sat_lookahead.h | 2 ++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index edb881aa4..bdc856fb3 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1144,6 +1144,18 @@ namespace sat { SASSERT(m_trail_lim.empty() || m_trail.size() >= m_trail_lim.back()); } + void lookahead::promote(unsigned base) { + if (m_trail.empty()) return; + unsigned last_lvl = get_level(m_trail.back()); + base -= last_lvl; + for (unsigned i = m_trail.size(); i > 0; ) { + literal lit = m_trail[--i]; + if (is_fixed_at(lit, c_fixed_truth)) break; + SASSERT(is_fixed_at(lit, last_lvl)); + m_stamp[lit.var()] += base; + } + } + // // The current version is modeled after CDCL SAT solving data-structures. // It borrows from the watch list data-structure. The cost tradeoffs are somewhat @@ -1680,6 +1692,8 @@ namespace sat { num_units += do_double(lit, dl_lvl); if (dl_lvl > level) { base = dl_lvl; + promote(base + m_lookahead[i].m_offset); + SASSERT(get_level(m_trail.back()) == base + m_lookahead[i].m_offset); } unsat = inconsistent(); pop_lookahead1(lit, num_units); @@ -1867,11 +1881,14 @@ namespace sat { SASSERT(dl_no_overflow(base)); base += m_lookahead.size(); unsigned dl_truth = base + m_lookahead.size() * m_config.m_dl_max_iterations; + promote(dl_truth); scoped_level _sl(*this, dl_truth); + SASSERT(get_level(m_trail.back()) == dl_truth); + SASSERT(is_fixed(l)); IF_VERBOSE(2, verbose_stream() << "double: " << l << " depth: " << m_trail_lim.size() << "\n";); - lookahead_backtrack(); - assign(l); - propagate(); + //lookahead_backtrack(); + //assign(l); + //propagate(); //SASSERT(!inconsistent()); unsigned old_sz = m_trail.size(); bool change = true; @@ -1914,6 +1931,8 @@ namespace sat { base += 2 * m_lookahead.size(); SASSERT(dl_truth >= base); } + lookahead_backtrack(); + SASSERT(get_level(m_trail.back()) == dl_truth); SASSERT(m_level == dl_truth); base = dl_truth; return m_trail.size() - old_sz; @@ -1932,6 +1951,7 @@ namespace sat { if (is_undef(l)) { TRACE("sat", tout << "assign: " << l << " @ " << m_level << " " << m_trail_lim.size() << " " << m_search_mode << "\n";); set_true(l); + SASSERT(m_trail.empty() || get_level(m_trail.back()) >= get_level(l)); m_trail.push_back(l); if (m_search_mode == lookahead_mode::searching) { m_stats.m_propagations++; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index d30485254..8420ae1f5 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -246,6 +246,7 @@ namespace sat { inline bool is_true(literal l) const { return is_true_at(l, m_level); } inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } inline void set_undef(literal l) { m_stamp[l.var()] = 0; } + inline unsigned get_level(literal l) { return m_stamp[l.var()] & UINT_MAX - 1; } void set_level(literal d, literal s) { m_stamp[d.var()] = (m_stamp[s.var()] & ~0x1) + d.sign(); } lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; } @@ -479,6 +480,7 @@ namespace sat { unsigned push_lookahead1(literal lit, unsigned level); void pop_lookahead1(literal lit, unsigned num_units); void lookahead_backtrack(); + void promote(unsigned base); double mix_diff(double l, double r) const; clause const& get_clause(watch_list::iterator it) const; bool is_nary_propagation(clause const& c, literal l) const; From 8811d784154b0eaf64aa72137d097d66123df4ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 17 Oct 2017 21:28:48 -0700 Subject: [PATCH 0287/1283] compress elimination stack representation Signed-off-by: Nikolaj Bjorner --- src/sat/sat_model_converter.cpp | 22 +++--- src/sat/sat_model_converter.h | 12 +-- src/sat/sat_simplifier.cpp | 128 ++++++++++++++++++++++---------- 3 files changed, 108 insertions(+), 54 deletions(-) diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index c79cd2944..14443a2f7 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -38,16 +38,15 @@ namespace sat { return *this; } - void model_converter::process_stack(model & m, literal_vector const& stack) const { + void model_converter::process_stack(model & m, literal_vector const& c, elim_stackv const& stack) const { SASSERT(!stack.empty()); unsigned sz = stack.size(); - SASSERT(stack[sz - 1] == null_literal); - for (unsigned i = sz - 1; i-- > 0; ) { - literal lit = stack[i]; // this is the literal that is pivoted on. It is repeated + for (unsigned i = sz; i-- > 0; ) { + unsigned csz = stack[i].first; + literal lit = stack[i].second; bool sat = false; - for (; i > 0 && stack[--i] != null_literal;) { - if (sat) continue; - sat = value_at(stack[i], m) == l_true; + for (unsigned j = 0; !sat && j < csz; ++j) { + sat = value_at(c[j], m) == l_true; } if (!sat) { m[lit.var()] = lit.sign() ? l_false : l_true; @@ -66,6 +65,7 @@ namespace sat { bool sat = false; bool var_sign = false; unsigned index = 0; + literal_vector clause; for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause @@ -74,13 +74,15 @@ namespace sat { } elim_stack* s = it->m_elim_stack[index]; if (s) { - process_stack(m, s->stack()); + process_stack(m, clause, s->stack()); } sat = false; ++index; + clause.reset(); continue; } + clause.push_back(l); if (sat) continue; bool sign = l.sign(); @@ -190,13 +192,13 @@ namespace sat { // TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (literal l : c) tout << l << " "; tout << "\n";); } - void model_converter::insert(entry & e, literal_vector const& c, literal_vector const& elims) { + void model_converter::insert(entry & e, literal_vector const& c, elim_stackv const& elims) { SASSERT(c.contains(literal(e.var(), false)) || c.contains(literal(e.var(), true))); SASSERT(m_entries.begin() <= &e); SASSERT(&e < m_entries.end()); for (literal l : c) e.m_clauses.push_back(l); e.m_clauses.push_back(null_literal); - e.m_elim_stack.push_back(alloc(elim_stack, elims)); + e.m_elim_stack.push_back(elims.empty() ? nullptr : alloc(elim_stack, elims)); TRACE("sat_mc_bug", tout << "adding: " << c << "\n";); } diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index 00fd637b7..dcbe450a8 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -39,18 +39,20 @@ namespace sat { class model_converter { public: + typedef svector> elim_stackv; + class elim_stack { unsigned m_refcount; - literal_vector m_stack; + elim_stackv m_stack; public: - elim_stack(literal_vector const& stack): + elim_stack(elim_stackv const& stack): m_refcount(0), m_stack(stack) { } ~elim_stack() { } void inc_ref() { ++m_refcount; } void dec_ref() { if (0 == --m_refcount) dealloc(this); } - literal_vector const& stack() const { return m_stack; } + elim_stackv const& stack() const { return m_stack; } }; enum kind { ELIM_VAR = 0, BLOCK_LIT }; @@ -74,7 +76,7 @@ namespace sat { private: vector m_entries; - void process_stack(model & m, literal_vector const& stack) const; + void process_stack(model & m, literal_vector const& clause, elim_stackv const& stack) const; public: model_converter(); @@ -86,7 +88,7 @@ namespace sat { void insert(entry & e, clause const & c); void insert(entry & e, literal l1, literal l2); void insert(entry & e, clause_wrapper const & c); - void insert(entry & c, literal_vector const& covered_clause, literal_vector const& elim_stack); + void insert(entry & c, literal_vector const& covered_clause, elim_stackv const& elim_stack); bool empty() const { return m_entries.empty(); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b09d180c0..b967ade06 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -965,6 +965,7 @@ namespace sat { literal l = m_queue.next(); process(l); } + cce(); } // @@ -1027,55 +1028,106 @@ namespace sat { literal_vector m_covered_clause; literal_vector m_intersection; - literal_vector m_elim_stack; + sat::model_converter::elim_stackv m_elim_stack; + unsigned m_ala_qhead; - bool cla(literal lit) { + /* + * C \/ l l \/ lit + * ------------------- + * C \/ l \/ ~lit + */ + void add_ala() { + for (; m_ala_qhead < m_covered_clause.size(); ++m_ala_qhead) { + literal l = m_covered_clause[m_ala_qhead]; + for (watched & w : s.get_wlist(~l)) { + if (w.is_binary_clause()) { + literal lit = w.get_literal(); + if (!s.is_marked(lit) && !s.is_marked(~lit)) { + //std::cout << "ALA " << ~lit << "\n"; + m_covered_clause.push_back(~lit); + s.mark_visited(~lit); + } + } + } + } + } + + bool add_cla(literal& blocked) { + for (unsigned i = 0; i < m_covered_clause.size(); ++i) { + m_intersection.reset(); + if (ri(m_covered_clause[i], m_intersection)) { + blocked = m_covered_clause[i]; + return true; + } + for (literal l : m_intersection) { + if (!s.is_marked(l)) { + s.mark_visited(l); + m_covered_clause.push_back(l); + } + } + if (!m_intersection.empty()) { + m_elim_stack.push_back(std::make_pair(m_covered_clause.size(), m_covered_clause[i])); + } + } + return false; + } + + bool cla(literal& blocked) { bool is_tautology = false; for (literal l : m_covered_clause) s.mark_visited(l); unsigned num_iterations = 0, sz; m_elim_stack.reset(); + m_ala_qhead = 0; do { - ++num_iterations; - sz = m_covered_clause.size(); - for (unsigned i = 0; i < m_covered_clause.size(); ++i) { - m_intersection.reset(); - if (ri(m_covered_clause[i], m_intersection) && m_covered_clause[i] == lit) { - is_tautology = true; - break; - } - for (literal l : m_intersection) { - if (!s.is_marked(l)) { - s.mark_visited(l); - m_covered_clause.push_back(l); - } - } - if (!m_intersection.empty()) { - m_elim_stack.append(m_covered_clause); // the current clause - m_elim_stack.push_back(m_covered_clause[i]); // the pivot literal - m_elim_stack.push_back(null_literal); // null demarcation - } + do { + ++num_iterations; + sz = m_covered_clause.size(); + is_tautology = add_cla(blocked); } + while (m_covered_clause.size() > sz && !is_tautology); + break; + //if (is_tautology) break; + //sz = m_covered_clause.size(); + // unsound? add_ala(); } - while (m_covered_clause.size() > sz && !is_tautology); + while (m_covered_clause.size() > sz); for (literal l : m_covered_clause) s.unmark_visited(l); - if (is_tautology) std::cout << "taut: " << num_iterations << "\n"; + // if (is_tautology) std::cout << "taut: " << num_iterations << " " << m_covered_clause.size() << " " << m_elim_stack.size() << "\n"; return is_tautology; } // perform covered clause elimination. // first extract the covered literal addition (CLA). // then check whether the CLA is blocked. - bool cce(clause& c, literal lit) { + bool cce(clause& c, literal& blocked) { m_covered_clause.reset(); for (literal l : c) m_covered_clause.push_back(l); - return cla(lit); + return cla(blocked); } - bool cce(literal lit, literal l2) { + bool cce(literal lit, literal l2, literal& blocked) { m_covered_clause.reset(); m_covered_clause.push_back(lit); m_covered_clause.push_back(l2); - return cla(lit); + return cla(blocked); + } + + void cce() { + m_to_remove.reset(); + literal blocked; + for (clause* cp : s.s.m_clauses) { + clause& c = *cp; + if (c.was_removed()) continue; + if (cce(c, blocked)) { + model_converter::entry * new_entry = 0; + block_covered_clause(c, blocked, new_entry); + s.m_num_covered_clauses++; + } + } + for (clause* c : m_to_remove) { + s.remove_clause(*c); + } + m_to_remove.reset(); } void process(literal l) { @@ -1085,6 +1137,7 @@ namespace sat { return; } + literal blocked = null_literal; m_to_remove.reset(); { clause_use_list & occs = s.m_use_list.get(l); @@ -1095,14 +1148,10 @@ namespace sat { SASSERT(c.contains(l)); s.mark_all_but(c, l); if (all_tautology(l)) { - s.unmark_all(c); block_clause(c, l, new_entry); s.m_num_blocked_clauses++; } - else if (cce(c, l)) { - block_covered_clause(c, l, new_entry); - s.m_num_covered_clauses++; - } + s.unmark_all(c); it.next(); } } @@ -1127,8 +1176,9 @@ namespace sat { block_binary(it, l, new_entry); s.m_num_blocked_clauses++; } - else if (cce(l, l2)) { - block_covered_binary(it, l, new_entry); + else if (cce(l, l2, blocked)) { + model_converter::entry * blocked_entry = 0; + block_covered_binary(it, l, blocked, blocked_entry); s.m_num_covered_clauses++; } else { @@ -1163,9 +1213,9 @@ namespace sat { mc.insert(*new_entry, m_covered_clause, m_elim_stack); } - void prepare_block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { + void prepare_block_binary(watch_list::iterator it, literal l, literal blocked, model_converter::entry *& new_entry) { if (new_entry == 0) - new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); + new_entry = &(mc.mk(model_converter::BLOCK_LIT, blocked.var())); literal l2 = it->get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l << "\n";); s.remove_bin_clause_half(l2, l, it->is_learned()); @@ -1173,12 +1223,12 @@ namespace sat { } void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { - prepare_block_binary(it, l, new_entry); + prepare_block_binary(it, l, l, new_entry); mc.insert(*new_entry, l, it->get_literal()); } - void block_covered_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { - prepare_block_binary(it, l, new_entry); + void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::entry *& new_entry) { + prepare_block_binary(it, l, blocked, new_entry); mc.insert(*new_entry, m_covered_clause, m_elim_stack); } From 80f24c29ab2831576b18d8bea4ac75f03b808ad9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Oct 2017 08:52:03 -0700 Subject: [PATCH 0288/1283] debugging reordering Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 145 ++++++++++++++++++++++++++++++-------------- src/sat/sat_bdd.h | 46 ++++++++------ src/test/bdd.cpp | 16 +++++ 3 files changed, 144 insertions(+), 63 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 1073f482e..3125b2a3a 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include "sat/sat_bdd.h" +#include "util/trace.h" namespace sat { @@ -48,12 +49,7 @@ namespace sat { // add variables for (unsigned i = 0; i < num_vars; ++i) { - m_var2bdd.push_back(make_node(i, false_bdd, true_bdd)); - m_var2bdd.push_back(make_node(i, true_bdd, false_bdd)); - m_nodes[m_var2bdd[2*i]].m_refcount = max_rc; - m_nodes[m_var2bdd[2*i+1]].m_refcount = max_rc; - m_var2level.push_back(i); - m_level2var.push_back(i); + reserve_var(i); } } @@ -73,8 +69,8 @@ namespace sat { return (a == true_bdd && b == true_bdd) ? true_bdd : false_bdd; case bdd_or_op: return (a == true_bdd || b == true_bdd) ? true_bdd : false_bdd; - case bdd_iff_op: - return (a == b) ? true_bdd : false_bdd; + case bdd_xor_op: + return (a == b) ? false_bdd : true_bdd; default: return false_bdd; } @@ -99,7 +95,7 @@ namespace sat { bdd bdd_manager::mk_false() { return bdd(false_bdd, this); } bdd bdd_manager::mk_and(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_and_op), this); } bdd bdd_manager::mk_or(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_or_op), this); } - bdd bdd_manager::mk_iff(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); } + bdd bdd_manager::mk_xor(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_xor_op), this); } bdd bdd_manager::mk_exists(unsigned v, bdd const& b) { return mk_exists(1, &v, b); } bdd bdd_manager::mk_forall(unsigned v, bdd const& b) { return mk_forall(1, &v, b); } @@ -132,10 +128,10 @@ namespace sat { if (is_false(b)) return a; if (is_true(a) || is_true(b)) return true_bdd; break; - case bdd_iff_op: - if (a == b) return true_bdd; - if (is_true(a)) return b; - if (is_true(b)) return a; + case bdd_xor_op: + if (a == b) return false_bdd; + if (is_false(a)) return b; + if (is_false(b)) return a; break; default: UNREACHABLE(); @@ -265,9 +261,9 @@ namespace sat { goto go_down; } go_up: + TRACE("bdd", tout << "sift up " << lvl << "\n";); while (lvl < max_lvl) { - sift_up(lvl); - ++lvl; + sift_up(lvl++); double cost = current_cost(); if (is_bad_cost(cost, best_cost)) break; best_cost = std::min(cost, best_cost); @@ -275,22 +271,20 @@ namespace sat { if (first) { first = false; while (lvl != start) { - sift_up(lvl-1); - --lvl; + sift_up(--lvl); } goto go_down; } else { while (current_cost() != best_cost) { - sift_up(lvl-1); - --lvl; + sift_up(--lvl); } return; } go_down: + TRACE("bdd", tout << "sift down " << lvl << "\n";); while (lvl > 0) { - sift_up(lvl-1); - --lvl; + sift_up(--lvl); double cost = current_cost(); if (is_bad_cost(cost, best_cost)) break; best_cost = std::min(cost, best_cost); @@ -298,15 +292,13 @@ namespace sat { if (first) { first = false; while (lvl != start) { - sift_up(lvl); - ++lvl; + sift_up(lvl++); } goto go_up; } else { while (current_cost() != best_cost) { - sift_up(lvl); - ++lvl; + sift_up(lvl++); } return; } @@ -330,30 +322,37 @@ namespace sat { else { m_T.push_back(n); } + TRACE("bdd", tout << "remove " << n << "\n";); m_node_table.remove(m_nodes[n]); } + m_level2nodes[lvl + 1].reset(); + m_level2nodes[lvl + 1].append(m_T); for (unsigned n : m_level2nodes[lvl]) { bdd_node& node = m_nodes[n]; m_node_table.remove(node); if (m_max_parent[n] == lvl + 1 && node.m_refcount == 0) { + TRACE("bdd", tout << "free " << n << "\n";); node.set_internal(); m_free_nodes.push_back(n); } else { + TRACE("bdd", tout << "set level " << n << " to " << lvl + 1 << "\n";); node.m_level = lvl + 1; m_node_table.insert(node); + m_level2nodes[lvl + 1].push_back(n); } } - + m_level2nodes[lvl].reset(); + m_level2nodes[lvl].append(m_S); + for (unsigned n : m_S) { m_nodes[n].m_level = lvl; m_node_table.insert(m_nodes[n]); } - std::swap(m_level2nodes[lvl], m_level2nodes[lvl + 1]); - for (unsigned n : m_T) { + TRACE("bdd", tout << "transform " << n << "\n";); BDD l = lo(n); BDD h = hi(n); if (l == 0 && h == 0) continue; @@ -392,6 +391,14 @@ namespace sat { std::swap(m_level2var[lvl], m_level2var[lvl+1]); std::swap(m_var2level[v], m_var2level[w]); m_disable_gc = false; + TRACE("bdd", tout << "sift " << lvl << "\n"; display(tout); ); + DEBUG_CODE( + for (unsigned i = 0; i < m_level2nodes.size(); ++i) { + for (unsigned n : m_level2nodes[i]) { + bdd_node const& node = m_nodes[n]; + SASSERT(node.m_level == i); + } + }); } void bdd_manager::init_reorder() { @@ -403,18 +410,41 @@ namespace sat { if (n.is_internal()) continue; unsigned lvl = n.m_level; SASSERT(i == m_nodes[i].m_index); - while (m_level2nodes.size() <= lvl) m_level2nodes.push_back(unsigned_vector()); + m_level2nodes.reserve(lvl + 1); m_level2nodes[lvl].push_back(i); m_max_parent[n.m_lo] = std::max(m_max_parent[n.m_lo], lvl); m_max_parent[n.m_hi] = std::max(m_max_parent[n.m_hi], lvl); } + TRACE("bdd", + display(tout); + for (unsigned i = 0; i < sz; ++i) { + bdd_node const& n = m_nodes[i]; + if (n.is_internal()) continue; + unsigned lvl = n.m_level; + tout << "lvl: " << lvl << " parent: " << m_max_parent[i] << " lo " << n.m_lo << " hi " << n.m_hi << "\n"; + } + ); + } + + void bdd_manager::reserve_var(unsigned i) { + while (m_var2level.size() <= i) { + unsigned v = m_var2level.size(); + m_var2bdd.push_back(make_node(v, false_bdd, true_bdd)); + m_var2bdd.push_back(make_node(v, true_bdd, false_bdd)); + m_nodes[m_var2bdd[2*v]].m_refcount = max_rc; + m_nodes[m_var2bdd[2*v+1]].m_refcount = max_rc; + m_var2level.push_back(v); + m_level2var.push_back(v); + } } bdd bdd_manager::mk_var(unsigned i) { + reserve_var(i); return bdd(m_var2bdd[2*i], this); } bdd bdd_manager::mk_nvar(unsigned i) { + reserve_var(i); return bdd(m_var2bdd[2*i+1], this); } @@ -581,6 +611,29 @@ namespace sat { return m_count[b.root]; } + unsigned bdd_manager::bdd_size(bdd const& b) { + init_mark(); + set_mark(0); + set_mark(1); + unsigned sz = 0; + m_todo.push_back(b.root); + while (!m_todo.empty()) { + BDD r = m_todo.back(); + m_todo.pop_back(); + if (!is_marked(r)) { + ++sz; + set_mark(r); + if (!is_marked(lo(r))) { + m_todo.push_back(lo(r)); + } + if (!is_marked(hi(r))) { + m_todo.push_back(hi(r)); + } + } + } + return sz; + } + void bdd_manager::alloc_free_nodes(unsigned n) { for (unsigned i = 0; i < n; ++i) { m_free_nodes.push_back(m_nodes.size()); @@ -678,31 +731,35 @@ namespace sat { return out; } + void bdd_manager::well_formed() { + for (unsigned n : m_free_nodes) { + VERIFY(lo(n) == 0 && hi(n) == 0 && m_nodes[n].m_refcount == 0); + } + for (bdd_node const& n : m_nodes) { + if (n.is_internal()) continue; + unsigned lvl = n.m_level; + BDD lo = n.m_lo; + BDD hi = n.m_hi; + VERIFY(is_const(lo) || level(lo) < lvl); + VERIFY(is_const(hi) || level(hi) < lvl); + } + } + std::ostream& bdd_manager::display(std::ostream& out) { for (unsigned i = 0; i < m_nodes.size(); ++i) { bdd_node const& n = m_nodes[i]; if (n.is_internal()) continue; out << i << " : " << m_level2var[n.m_level] << " " << n.m_lo << " " << n.m_hi << "\n"; } + for (unsigned i = 0; i < m_level2nodes.size(); ++i) { + out << i << " : "; + for (unsigned l : m_level2nodes[i]) out << l << " "; + out << "\n"; + } return out; } - bdd::bdd(unsigned root, bdd_manager* m): root(root), m(m) { m->inc_ref(root); } - bdd::bdd(bdd & other): root(other.root), m(other.m) { m->inc_ref(root); } - bdd::bdd(bdd && other): root(0), m(other.m) { std::swap(root, other.root); } - bdd::~bdd() { m->dec_ref(root); } - bdd bdd::lo() const { return bdd(m->lo(root), m); } - bdd bdd::hi() const { return bdd(m->hi(root), m); } - unsigned bdd::var() const { return m->var(root); } - bool bdd::is_true() const { return root == bdd_manager::true_bdd; } - bool bdd::is_false() const { return root == bdd_manager::false_bdd; } - bdd bdd::operator!() { return m->mk_not(*this); } - bdd bdd::operator&&(bdd const& other) { return m->mk_and(*this, other); } - bdd bdd::operator||(bdd const& other) { return m->mk_or(*this, other); } bdd& bdd::operator=(bdd const& other) { unsigned r1 = root; root = other.root; m->inc_ref(root); m->dec_ref(r1); return *this; } - std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); } std::ostream& operator<<(std::ostream& out, bdd const& b) { return b.display(out); } - double bdd::cnf_size() const { return m->cnf_size(*this); } - double bdd::dnf_size() const { return m->dnf_size(*this); } } diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index dbd19ec61..41e45c822 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -35,7 +35,7 @@ namespace sat { enum bdd_op { bdd_and_op = 2, bdd_or_op = 3, - bdd_iff_op = 4, + bdd_xor_op = 4, bdd_not_op = 5, bdd_and_proj_op = 6, bdd_or_proj_op = 7, @@ -149,7 +149,6 @@ namespace sat { void set_mark(unsigned i) { m_mark[i] = m_mark_level; } bool is_marked(unsigned i) { return m_mark[i] == m_mark_level; } - void try_reorder(); void init_reorder(); void sift_up(unsigned level); void sift_var(unsigned v); @@ -173,10 +172,15 @@ namespace sat { double dnf_size(bdd const& b) { return count(b, 0); } double cnf_size(bdd const& b) { return count(b, 1); } + unsigned bdd_size(bdd const& b); bdd mk_not(bdd b); bdd mk_and(bdd const& a, bdd const& b); bdd mk_or(bdd const& a, bdd const& b); + bdd mk_xor(bdd const& a, bdd const& b); + + void reserve_var(unsigned v); + void well_formed(); public: struct mem_out {}; @@ -196,39 +200,43 @@ namespace sat { bdd mk_forall(unsigned n, unsigned const* vars, bdd const & b); bdd mk_exists(unsigned v, bdd const& b); bdd mk_forall(unsigned v, bdd const& b); - bdd mk_iff(bdd const& a, bdd const& b); bdd mk_ite(bdd const& c, bdd const& t, bdd const& e); std::ostream& display(std::ostream& out); std::ostream& display(std::ostream& out, bdd const& b); + + void try_reorder(); }; class bdd { friend class bdd_manager; unsigned root; bdd_manager* m; - bdd(unsigned root, bdd_manager* m); + bdd(unsigned root, bdd_manager* m): root(root), m(m) { m->inc_ref(root); } public: - bdd(bdd & other); - bdd(bdd && other); + bdd(bdd & other): root(other.root), m(other.m) { m->inc_ref(root); } + bdd(bdd && other): root(0), m(other.m) { std::swap(root, other.root); } bdd& operator=(bdd const& other); - ~bdd(); - bdd lo() const; - bdd hi() const; - unsigned var() const; - bool is_true() const; - bool is_false() const; - - bdd operator!(); - bdd operator&&(bdd const& other); - bdd operator||(bdd const& other); + ~bdd() { m->dec_ref(root); } + bdd lo() const { return bdd(m->lo(root), m); } + bdd hi() const { return bdd(m->hi(root), m); } + unsigned var() const { return m->var(root); } + + bool is_true() const { return root == bdd_manager::true_bdd; } + bool is_false() const { return root == bdd_manager::false_bdd; } + + bdd operator!() { return m->mk_not(*this); } + bdd operator&&(bdd const& other) { return m->mk_and(*this, other); } + bdd operator||(bdd const& other) { return m->mk_or(*this, other); } + bdd operator^(bdd const& other) { return m->mk_xor(*this, other); } bdd operator|=(bdd const& other) { return *this = *this || other; } bdd operator&=(bdd const& other) { return *this = *this && other; } - std::ostream& display(std::ostream& out) const; + std::ostream& display(std::ostream& out) const { return m->display(out, *this); } bool operator==(bdd const& other) const { return root == other.root; } bool operator!=(bdd const& other) const { return root != other.root; } - double cnf_size() const; - double dnf_size() const; + double cnf_size() const { return m->cnf_size(*this); } + double dnf_size() const { return m->dnf_size(*this); } + unsigned bdd_size() const { return m->bdd_size(*this); } }; std::ostream& operator<<(std::ostream& out, bdd const& b); diff --git a/src/test/bdd.cpp b/src/test/bdd.cpp index 6826df35e..b60522740 100644 --- a/src/test/bdd.cpp +++ b/src/test/bdd.cpp @@ -57,10 +57,26 @@ namespace sat { c2 = m.mk_exists(2, c1); SASSERT(c2 == ((v0 && v1) || v1 || !v0)); } + + void test4() { + bdd_manager m(3); + bdd v0 = m.mk_var(0); + bdd v1 = m.mk_var(1); + bdd v2 = m.mk_var(2); + bdd c1 = (v0 && v2) || v1; + std::cout << "before reorder:\n"; + std::cout << c1 << "\n"; + std::cout << c1.bdd_size() << "\n"; + m.try_reorder(); + std::cout << "after reorder:\n"; + std::cout << c1 << "\n"; + std::cout << c1.bdd_size() << "\n"; + } } void tst_bdd() { sat::test1(); sat::test2(); sat::test3(); + sat::test4(); } From edea8798641477e3de17863179c9a80be136915d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Oct 2017 08:57:32 -0700 Subject: [PATCH 0289/1283] expose missed propagations Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 +- src/sat/ba_solver.h | 4 ++-- src/sat/sat_lookahead.cpp | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index faa9b639e..ab2352253 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1556,7 +1556,7 @@ namespace sat { m_learned.push_back(c); } else { - SASSERT(s().at_base_lvl()); + SASSERT(!m_solver || s().at_base_lvl()); m_constraints.push_back(c); } literal lit = c->lit(); diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 3e02d49dc..09903f889 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -362,8 +362,8 @@ namespace sat { // access solver inline lbool value(bool_var v) const { return value(literal(v, false)); } inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } - inline unsigned lvl(literal lit) const { return m_solver->lvl(lit); } - inline unsigned lvl(bool_var v) const { return m_solver->lvl(v); } + inline unsigned lvl(literal lit) const { return m_lookahead ? 0 : m_solver->lvl(lit); } + inline unsigned lvl(bool_var v) const { return m_lookahead ? 0 : m_solver->lvl(v); } inline bool inconsistent() const { return m_lookahead ? m_lookahead->inconsistent() : m_solver->inconsistent(); } inline watch_list& get_wlist(literal l) { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index f607d53ad..5c039f664 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -408,6 +408,7 @@ namespace sat { } bool lookahead::missed_propagation() const { + if (inconsistent()) return false; for (literal l1 : m_trail) { SASSERT(is_true(l1)); for (literal l2 : m_binary[l1.index()]) { @@ -1614,7 +1615,7 @@ namespace sat { } SASSERT(m_qhead == m_trail.size() || (inconsistent() && m_qhead < m_trail.size())); //SASSERT(!missed_conflict()); - //SASSERT(inconsistent() || !missed_propagation()); + VERIFY(!missed_propagation()); TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } @@ -1656,6 +1657,7 @@ namespace sat { unsat = inconsistent(); pop_lookahead1(lit, num_units); } + // VERIFY(!missed_propagation()); if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); lookahead_backtrack(); From dc6ed64da1a534fae2cd83a96a63be9776a890f5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Oct 2017 17:37:38 -0700 Subject: [PATCH 0290/1283] testing bdd for elim-vars Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 248 +++++++++++++++++++++++++++++-------- src/sat/sat_bdd.h | 39 +++--- src/sat/sat_elim_vars.cpp | 9 +- src/sat/sat_elim_vars.h | 2 + src/sat/sat_lookahead.cpp | 76 ++---------- src/sat/sat_lookahead.h | 1 + src/sat/sat_simplifier.cpp | 6 +- src/test/bdd.cpp | 1 + src/util/vector.h | 5 + 9 files changed, 254 insertions(+), 133 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 3125b2a3a..e44bf7944 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -23,6 +23,8 @@ Revision History: namespace sat { bdd_manager::bdd_manager(unsigned num_vars) { + m_cost_metric = bdd_cost; + m_cost_bdd = 0; for (BDD a = 0; a < 2; ++a) { for (BDD b = 0; b < 2; ++b) { for (unsigned op = bdd_and_op; op < bdd_not_op; ++op) { @@ -58,6 +60,7 @@ namespace sat { m_alloc.deallocate(sizeof(*m_spare_entry), m_spare_entry); } for (auto* e : m_op_cache) { + VERIFY(e != m_spare_entry); m_alloc.deallocate(sizeof(*e), e); } } @@ -78,16 +81,21 @@ namespace sat { bdd_manager::BDD bdd_manager::apply(BDD arg1, BDD arg2, bdd_op op) { bool first = true; + SASSERT(well_formed()); while (true) { try { return apply_rec(arg1, arg2, op); } catch (mem_out) { + throw; +#if 0 try_reorder(); if (!first) throw; first = false; +#endif } } + SASSERT(well_formed()); } @@ -101,17 +109,20 @@ namespace sat { bool bdd_manager::check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c) { + // std::cout << a << " " << b << " " << c << " " << e1 << " " << e2 << "\n"; if (e1 != e2) { + VERIFY(e2->m_result != -1); push_entry(e1); - if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == c) { - return true; - } - e1 = const_cast(e2); + e1 = nullptr; + return true; + } + else { + e1->m_bdd1 = a; + e1->m_bdd2 = b; + e1->m_op = c; + VERIFY(e1->m_result == -1); + return false; } - e1->m_bdd1 = a; - e1->m_bdd2 = b; - e1->m_op = c; - return false; } bdd_manager::BDD bdd_manager::apply_rec(BDD a, BDD b, bdd_op op) { @@ -143,8 +154,10 @@ namespace sat { op_entry * e1 = pop_entry(a, b, op); op_entry const* e2 = m_op_cache.insert_if_not_there(e1); if (check_result(e1, e2, a, b, op)) { + SASSERT(!m_free_nodes.contains(e2->m_result)); return e2->m_result; } + // VERIFY(well_formed()); BDD r; if (level(a) == level(b)) { push(apply_rec(lo(a), lo(b), op)); @@ -163,6 +176,8 @@ namespace sat { } pop(2); e1->m_result = r; + // VERIFY(well_formed()); + SASSERT(!m_free_nodes.contains(r)); return r; } @@ -190,6 +205,7 @@ namespace sat { else { void * mem = m_alloc.allocate(sizeof(op_entry)); result = new (mem) op_entry(l, r, op); + // std::cout << "alloc: " << result << "\n"; } result->m_result = -1; return result; @@ -200,16 +216,22 @@ namespace sat { m_spare_entry = e; } - bdd_manager::BDD bdd_manager::make_node(unsigned level, BDD l, BDD r) { + bdd_manager::BDD bdd_manager::make_node(unsigned lvl, BDD l, BDD h) { m_is_new_node = false; - if (l == r) { + if (l == h) { return l; } + if (!is_const(l) && level(l) >= lvl) { + display(std::cout << l << " level: " << level(l) << " lvl: " << lvl << "\n"); + } + VERIFY(is_const(l) || level(l) < lvl); + VERIFY(is_const(h) || level(h) < lvl); - bdd_node n(level, l, r); + bdd_node n(lvl, l, h); node_table::entry* e = m_node_table.insert_if_not_there2(n); if (e->get_data().m_index != 0) { - return e->get_data().m_index; + unsigned result = e->get_data().m_index; + return result; } e->get_data().m_refcount = 0; bool do_gc = m_free_nodes.empty(); @@ -226,25 +248,50 @@ namespace sat { } SASSERT(!m_free_nodes.empty()); - e->get_data().m_index = m_free_nodes.back(); - m_nodes[e->get_data().m_index] = e->get_data(); - m_free_nodes.pop_back(); - m_is_new_node = true; - return e->get_data().m_index; + unsigned result = m_free_nodes.back(); + m_free_nodes.pop_back(); + e->get_data().m_index = result; + m_nodes[result] = e->get_data(); + m_is_new_node = true; + SASSERT(!m_free_nodes.contains(result)); + SASSERT(m_nodes[result].m_index == result); + return result; } + void bdd_manager::try_cnf_reorder(bdd const& b) { + m_cost_bdd = b.root; + m_cost_metric = cnf_cost; + try_reorder(); + m_cost_metric = bdd_cost; + m_cost_bdd = 0; + } + void bdd_manager::try_reorder() { + gc(); + for (auto* e : m_op_cache) { + m_alloc.deallocate(sizeof(*e), e); + } + m_op_cache.reset(); init_reorder(); for (unsigned i = 0; i < m_var2level.size(); ++i) { sift_var(i); } + SASSERT(m_op_cache.empty()); + SASSERT(well_formed()); } double bdd_manager::current_cost() { -#if 0 - -#endif - return m_nodes.size() - m_free_nodes.size(); + switch (m_cost_metric) { + case bdd_cost: + return m_nodes.size() - m_free_nodes.size(); + case cnf_cost: + return cnf_size(m_cost_bdd); + case dnf_cost: + return dnf_size(m_cost_bdd); + default: + UNREACHABLE(); + return 0; + } } bool bdd_manager::is_bad_cost(double current_cost, double best_cost) const { @@ -306,9 +353,11 @@ namespace sat { void bdd_manager::sift_up(unsigned lvl) { if (m_level2nodes[lvl].empty()) return; + // VERIFY(well_formed()); // exchange level and level + 1. m_S.reset(); m_T.reset(); + m_to_free.reset(); m_disable_gc = true; for (unsigned n : m_level2nodes[lvl + 1]) { @@ -320,6 +369,8 @@ namespace sat { m_S.push_back(n); } else { + reorder_decref(l); + reorder_decref(h); m_T.push_back(n); } TRACE("bdd", tout << "remove " << n << "\n";); @@ -331,14 +382,12 @@ namespace sat { for (unsigned n : m_level2nodes[lvl]) { bdd_node& node = m_nodes[n]; m_node_table.remove(node); - if (m_max_parent[n] == lvl + 1 && node.m_refcount == 0) { - TRACE("bdd", tout << "free " << n << "\n";); - node.set_internal(); - m_free_nodes.push_back(n); + node.m_level = lvl + 1; + if (m_reorder_rc[n] == 0) { + m_to_free.push_back(n); } else { TRACE("bdd", tout << "set level " << n << " to " << lvl + 1 << "\n";); - node.m_level = lvl + 1; m_node_table.insert(node); m_level2nodes[lvl + 1].push_back(n); } @@ -352,19 +401,18 @@ namespace sat { } for (unsigned n : m_T) { - TRACE("bdd", tout << "transform " << n << "\n";); BDD l = lo(n); BDD h = hi(n); if (l == 0 && h == 0) continue; BDD a, b, c, d; - if (level(l) == lvl) { + if (level(l) == lvl + 1) { a = lo(l); b = hi(l); } else { a = b = l; } - if (level(h) == lvl) { + if (level(h) == lvl + 1) { c = lo(h); d = hi(h); } @@ -375,15 +423,22 @@ namespace sat { unsigned ac = make_node(lvl, a, c); if (is_new_node()) { m_level2nodes[lvl].push_back(ac); - m_max_parent.setx(ac, lvl + 1, 0); + m_reorder_rc.reserve(ac+1); + reorder_incref(a); + reorder_incref(c); } unsigned bd = make_node(lvl, b, d); if (is_new_node()) { m_level2nodes[lvl].push_back(bd); - m_max_parent.setx(bd, lvl + 1, 0); + m_reorder_rc.reserve(bd+1); + reorder_incref(b); + reorder_incref(d); } m_nodes[n].m_lo = ac; m_nodes[n].m_hi = bd; + reorder_incref(ac); + reorder_incref(bd); + TRACE("bdd", tout << "transform " << n << " " << " " << a << " " << b << " " << c << " " << d << " " << ac << " " << bd << "\n";); m_node_table.insert(m_nodes[n]); } unsigned v = m_level2var[lvl]; @@ -391,6 +446,30 @@ namespace sat { std::swap(m_level2var[lvl], m_level2var[lvl+1]); std::swap(m_var2level[v], m_var2level[w]); m_disable_gc = false; + + // add orphaned nodes to free-list + for (unsigned i = 0; i < m_to_free.size(); ++i) { + unsigned n = m_to_free[i]; + bdd_node& node = m_nodes[n]; + if (!node.is_internal()) { + VERIFY(!m_free_nodes.contains(n)); + VERIFY(node.m_refcount == 0); + m_free_nodes.push_back(n); + m_node_table.remove(node); + BDD l = lo(n); + BDD h = hi(n); + node.set_internal(); + + reorder_decref(l); + if (!m_nodes[l].is_internal() && m_reorder_rc[l] == 0) { + m_to_free.push_back(l); + } + reorder_decref(h); + if (!m_nodes[h].is_internal() && m_reorder_rc[h] == 0) { + m_to_free.push_back(h); + } + } + } TRACE("bdd", tout << "sift " << lvl << "\n"; display(tout); ); DEBUG_CODE( for (unsigned i = 0; i < m_level2nodes.size(); ++i) { @@ -399,12 +478,24 @@ namespace sat { SASSERT(node.m_level == i); } }); + + TRACE("bdd", + for (unsigned i = 0; i < m_nodes.size(); ++i) { + if (m_reorder_rc[i] != 0) { + tout << i << " " << m_reorder_rc[i] << "\n"; + }}); + + // VERIFY(well_formed()); } void bdd_manager::init_reorder() { m_level2nodes.reset(); unsigned sz = m_nodes.size(); - m_max_parent.fill(sz, 0); + m_reorder_rc.fill(sz, 0); + for (unsigned i = 0; i < sz; ++i) { + if (m_nodes[i].m_refcount > 0) + m_reorder_rc[i] = UINT_MAX; + } for (unsigned i = 0; i < sz; ++i) { bdd_node const& n = m_nodes[i]; if (n.is_internal()) continue; @@ -412,8 +503,8 @@ namespace sat { SASSERT(i == m_nodes[i].m_index); m_level2nodes.reserve(lvl + 1); m_level2nodes[lvl].push_back(i); - m_max_parent[n.m_lo] = std::max(m_max_parent[n.m_lo], lvl); - m_max_parent[n.m_hi] = std::max(m_max_parent[n.m_hi], lvl); + reorder_incref(n.m_lo); + reorder_incref(n.m_hi); } TRACE("bdd", display(tout); @@ -421,11 +512,19 @@ namespace sat { bdd_node const& n = m_nodes[i]; if (n.is_internal()) continue; unsigned lvl = n.m_level; - tout << "lvl: " << lvl << " parent: " << m_max_parent[i] << " lo " << n.m_lo << " hi " << n.m_hi << "\n"; + tout << i << " lvl: " << lvl << " rc: " << m_reorder_rc[i] << " lo " << n.m_lo << " hi " << n.m_hi << "\n"; } ); } + void bdd_manager::reorder_incref(unsigned n) { + if (m_reorder_rc[n] != UINT_MAX) m_reorder_rc[n]++; + } + + void bdd_manager::reorder_decref(unsigned n) { + if (m_reorder_rc[n] != UINT_MAX) m_reorder_rc[n]--; + } + void bdd_manager::reserve_var(unsigned i) { while (m_var2level.size() <= i) { unsigned v = m_var2level.size(); @@ -455,9 +554,12 @@ namespace sat { return bdd(mk_not_rec(b.root), this); } catch (mem_out) { + throw; +#if 0 try_reorder(); if (!first) throw; first = false; +#endif } } } @@ -532,12 +634,13 @@ namespace sat { push(mk_ite_rec(a1, b1, c1)); push(mk_ite_rec(a2, b2, c2)); r = make_node(lvl, read(2), read(1)); - pop(2); + pop(2); e1->m_result = r; return r; } bdd bdd_manager::mk_exists(unsigned n, unsigned const* vars, bdd const& b) { + // VERIFY(well_formed()); return bdd(mk_quant(n, vars, b.root, bdd_or_op), this); } @@ -570,9 +673,11 @@ namespace sat { bdd_op q_op = op == bdd_and_op ? bdd_and_proj_op : bdd_or_proj_op; op_entry * e1 = pop_entry(a, b, q_op); op_entry const* e2 = m_op_cache.insert_if_not_there(e1); - if (check_result(e1, e2, a, b, q_op)) + if (check_result(e1, e2, a, b, q_op)) { r = e2->m_result; + } else { + VERIFY(e1->m_result == -1); push(mk_quant_rec(l, lo(b), op)); push(mk_quant_rec(l, hi(b), op)); r = make_node(lvl, read(2), read(1)); @@ -580,26 +685,29 @@ namespace sat { e1->m_result = r; } } + VERIFY(r != UINT_MAX); return r; } - double bdd_manager::count(bdd const& b, unsigned z) { + double bdd_manager::count(BDD b, unsigned z) { init_mark(); m_count.resize(m_nodes.size()); m_count[0] = z; m_count[1] = 1-z; set_mark(0); set_mark(1); - m_todo.push_back(b.root); + m_todo.push_back(b); while (!m_todo.empty()) { BDD r = m_todo.back(); if (is_marked(r)) { m_todo.pop_back(); } else if (!is_marked(lo(r))) { + VERIFY (is_const(r) || r != lo(r)); m_todo.push_back(lo(r)); } else if (!is_marked(hi(r))) { + VERIFY (is_const(r) || r != hi(r)); m_todo.push_back(hi(r)); } else { @@ -608,7 +716,7 @@ namespace sat { m_todo.pop_back(); } } - return m_count[b.root]; + return m_count[b]; } unsigned bdd_manager::bdd_size(bdd const& b) { @@ -644,8 +752,8 @@ namespace sat { } void bdd_manager::gc() { + m_free_nodes.reset(); IF_VERBOSE(3, verbose_stream() << "(bdd :gc " << m_nodes.size() << ")\n";); - SASSERT(m_free_nodes.empty()); svector reachable(m_nodes.size(), false); for (unsigned i = m_bdd_stack.size(); i-- > 0; ) { reachable[m_bdd_stack[i]] = true; @@ -674,6 +782,7 @@ namespace sat { for (unsigned i = m_nodes.size(); i-- > 2; ) { if (!reachable[i]) { m_nodes[i].set_internal(); + VERIFY(m_nodes[i].m_refcount == 0); m_free_nodes.push_back(i); } } @@ -681,10 +790,25 @@ namespace sat { std::sort(m_free_nodes.begin(), m_free_nodes.end()); m_free_nodes.reverse(); - for (auto* e : m_op_cache) { - m_alloc.deallocate(sizeof(*e), e); + ptr_vector to_delete, to_keep; + for (auto* e : m_op_cache) { + // std::cout << "check: " << e << "\n"; + if (!reachable[e->m_bdd1] || !reachable[e->m_bdd2] || !reachable[e->m_op] || (e->m_result != -1 && !reachable[e->m_result])) { + to_delete.push_back(e); + } + else { + to_keep.push_back(e); + } } m_op_cache.reset(); + for (op_entry* e : to_delete) { + // std::cout << "erase: " << e << "\n"; + m_alloc.deallocate(sizeof(*e), e); + } + for (op_entry* e : to_keep) { + m_op_cache.insert(e); + } + m_node_table.reset(); // re-populate node cache for (unsigned i = m_nodes.size(); i-- > 2; ) { @@ -693,6 +817,7 @@ namespace sat { m_node_table.insert(m_nodes[i]); } } + SASSERT(well_formed()); } void bdd_manager::init_mark() { @@ -707,6 +832,7 @@ namespace sat { std::ostream& bdd_manager::display(std::ostream& out, bdd const& b) { init_mark(); m_todo.push_back(b.root); + m_reorder_rc.reserve(m_nodes.size()); while (!m_todo.empty()) { BDD r = m_todo.back(); if (is_marked(r)) { @@ -723,7 +849,7 @@ namespace sat { m_todo.push_back(hi(r)); } else { - out << r << " : " << var(r) << " " << lo(r) << " " << hi(r) << "\n"; + out << r << " : " << var(r) << " @ " << level(r) << " " << lo(r) << " " << hi(r) << " " << m_reorder_rc[r] << "\n"; set_mark(r); m_todo.pop_back(); } @@ -731,30 +857,52 @@ namespace sat { return out; } - void bdd_manager::well_formed() { + bool bdd_manager::well_formed() { for (unsigned n : m_free_nodes) { - VERIFY(lo(n) == 0 && hi(n) == 0 && m_nodes[n].m_refcount == 0); + if (!(lo(n) == 0 && hi(n) == 0 && m_nodes[n].m_refcount == 0)) { + std::cout << "free node is not internal " << n << " " << lo(n) << " " << hi(n) << " " << m_nodes[n].m_refcount << "\n"; + display(std::cout); + UNREACHABLE(); + } } for (bdd_node const& n : m_nodes) { if (n.is_internal()) continue; unsigned lvl = n.m_level; BDD lo = n.m_lo; BDD hi = n.m_hi; + if (!is_const(lo) && level(lo) >= lvl) { + std::cout << n.m_index << " lo: " << lo << "\n"; + display(std::cout); + } VERIFY(is_const(lo) || level(lo) < lvl); + if (!is_const(hi) && level(hi) >= lvl) { + std::cout << n.m_index << " hi: " << hi << "\n"; + display(std::cout); + } VERIFY(is_const(hi) || level(hi) < lvl); + if (!is_const(lo) && m_nodes[lo].is_internal()) { + std::cout << n.m_index << " lo: " << lo << "\n"; + display(std::cout); + } + if (!is_const(hi) && m_nodes[hi].is_internal()) { + std::cout << n.m_index << " hi: " << hi << "\n"; + display(std::cout); + } + VERIFY(is_const(lo) || !m_nodes[lo].is_internal()); + VERIFY(is_const(hi) || !m_nodes[hi].is_internal()); } + return true; } std::ostream& bdd_manager::display(std::ostream& out) { + m_reorder_rc.reserve(m_nodes.size()); for (unsigned i = 0; i < m_nodes.size(); ++i) { bdd_node const& n = m_nodes[i]; if (n.is_internal()) continue; - out << i << " : " << m_level2var[n.m_level] << " " << n.m_lo << " " << n.m_hi << "\n"; + out << i << " : v" << m_level2var[n.m_level] << " " << n.m_lo << " " << n.m_hi << " rc " << m_reorder_rc[i] << "\n"; } for (unsigned i = 0; i < m_level2nodes.size(); ++i) { - out << i << " : "; - for (unsigned l : m_level2nodes[i]) out << l << " "; - out << "\n"; + out << "level: " << i << " : " << m_level2nodes[i] << "\n"; } return out; } diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index 41e45c822..41d1115b9 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -50,7 +50,7 @@ namespace sat { m_hi(hi), m_index(0) {} - bdd_node(): m_level(0), m_lo(0), m_hi(0), m_index(0) {} + bdd_node(): m_refcount(0), m_level(0), m_lo(0), m_hi(0), m_index(0) {} unsigned m_refcount : 10; unsigned m_level : 22; BDD m_lo; @@ -58,7 +58,13 @@ namespace sat { unsigned m_index; unsigned hash() const { return mk_mix(m_level, m_lo, m_hi); } bool is_internal() const { return m_lo == 0 && m_hi == 0; } - void set_internal() { m_lo = m_hi = 0; } + void set_internal() { m_lo = 0; m_hi = 0; } + }; + + enum cost_metric { + cnf_cost, + dnf_cost, + bdd_cost }; struct hash_node { @@ -94,7 +100,7 @@ namespace sat { struct eq_entry { bool operator()(op_entry * a, op_entry * b) const { - return a->hash() == b->hash(); + return a->m_bdd1 == b->m_bdd2 && a->m_bdd2 == b->m_bdd2 && a->m_op == b->m_op; } }; @@ -117,9 +123,11 @@ namespace sat { bool m_disable_gc; bool m_is_new_node; unsigned m_max_num_bdd_nodes; - unsigned_vector m_S, m_T; // used for reordering + unsigned_vector m_S, m_T, m_to_free; // used for reordering vector m_level2nodes; - unsigned_vector m_max_parent; + unsigned_vector m_reorder_rc; + cost_metric m_cost_metric; + BDD m_cost_bdd; BDD make_node(unsigned level, BDD l, BDD r); bool is_new_node() const { return m_is_new_node; } @@ -141,15 +149,16 @@ namespace sat { void push_entry(op_entry* e); bool check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c); - double count(bdd const& b, unsigned z); + double count(BDD b, unsigned z); - void gc(); void alloc_free_nodes(unsigned n); void init_mark(); void set_mark(unsigned i) { m_mark[i] = m_mark_level; } bool is_marked(unsigned i) { return m_mark[i] == m_mark_level; } void init_reorder(); + void reorder_incref(unsigned n); + void reorder_decref(unsigned n); void sift_up(unsigned level); void sift_var(unsigned v); double current_cost(); @@ -166,12 +175,12 @@ namespace sat { inline unsigned var(BDD b) const { return m_level2var[level(b)]; } inline BDD lo(BDD b) const { return m_nodes[b].m_lo; } inline BDD hi(BDD b) const { return m_nodes[b].m_hi; } - inline void inc_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount++; } - inline void dec_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount--; } + inline void inc_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount++; VERIFY(!m_free_nodes.contains(b)); } + inline void dec_ref(BDD b) { if (m_nodes[b].m_refcount != max_rc) m_nodes[b].m_refcount--; VERIFY(!m_free_nodes.contains(b)); } inline BDD level2bdd(unsigned l) const { return m_var2bdd[m_level2var[l]]; } - double dnf_size(bdd const& b) { return count(b, 0); } - double cnf_size(bdd const& b) { return count(b, 1); } + double dnf_size(BDD b) { return count(b, 0); } + double cnf_size(BDD b) { return count(b, 1); } unsigned bdd_size(bdd const& b); bdd mk_not(bdd b); @@ -180,7 +189,7 @@ namespace sat { bdd mk_xor(bdd const& a, bdd const& b); void reserve_var(unsigned v); - void well_formed(); + bool well_formed(); public: struct mem_out {}; @@ -205,7 +214,9 @@ namespace sat { std::ostream& display(std::ostream& out); std::ostream& display(std::ostream& out, bdd const& b); + void gc(); void try_reorder(); + void try_cnf_reorder(bdd const& b); }; class bdd { @@ -234,8 +245,8 @@ namespace sat { std::ostream& display(std::ostream& out) const { return m->display(out, *this); } bool operator==(bdd const& other) const { return root == other.root; } bool operator!=(bdd const& other) const { return root != other.root; } - double cnf_size() const { return m->cnf_size(*this); } - double dnf_size() const { return m->dnf_size(*this); } + double cnf_size() const { return m->cnf_size(root); } + double dnf_size() const { return m->dnf_size(root); } unsigned bdd_size() const { return m->bdd_size(*this); } }; diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 6edc125ea..99c15c247 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -26,6 +26,7 @@ namespace sat{ elim_vars::elim_vars(simplifier& s) : simp(s), s(s.s), m(20) { m_mark_lim = 0; m_max_literals = 11; + m_miss = 0; } bool elim_vars::operator()(bool_var v) { @@ -57,10 +58,11 @@ namespace sat{ double sz1 = b1.cnf_size(); if (sz1 > 2*clause_size) { return false; - } + } if (sz1 <= clause_size) { return elim_var(v, b1); } + m_vars.reverse(); bdd b2 = elim_var(v); double sz2 = b2.cnf_size(); @@ -73,6 +75,11 @@ namespace sat{ if (sz3 <= clause_size) { return elim_var(v, b3); } +#if 0 + m.try_cnf_reorder(b3); + sz3 = b3.cnf_size(); + if (sz3 <= clause_size) ++m_miss; +#endif return false; } diff --git a/src/sat/sat_elim_vars.h b/src/sat/sat_elim_vars.h index 8893bbc40..e4843c41c 100644 --- a/src/sat/sat_elim_vars.h +++ b/src/sat/sat_elim_vars.h @@ -40,6 +40,7 @@ namespace sat { unsigned m_mark_lim; unsigned_vector m_var2index; unsigned_vector m_occ; + unsigned m_miss; unsigned m_max_literals; @@ -61,6 +62,7 @@ namespace sat { public: elim_vars(simplifier& s); bool operator()(bool_var v); + unsigned miss() const { return m_miss; } }; }; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 5c039f664..be698fc46 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -412,11 +412,17 @@ namespace sat { for (literal l1 : m_trail) { SASSERT(is_true(l1)); for (literal l2 : m_binary[l1.index()]) { + VERIFY(is_true(l2)); if (is_undef(l2)) return true; } unsigned sz = m_ternary_count[(~l1).index()]; for (binary b : m_ternary[(~l1).index()]) { if (sz-- == 0) break; + if (!(is_true(b.m_u) || is_true(b.m_v) || (is_undef(b.m_v) && is_undef(b.m_u)))) { + std::cout << b.m_u << " " << b.m_v << "\n"; + std::cout << get_level(b.m_u) << " " << get_level(b.m_v) << " level: " << m_level << "\n"; + UNREACHABLE(); + } if ((is_false(b.m_u) && is_undef(b.m_v)) || (is_false(b.m_v) && is_undef(b.m_u))) return true; } @@ -424,6 +430,7 @@ namespace sat { for (nary * n : m_nary_clauses) { if (n->size() == 1 && !is_true(n->get_head())) { for (literal lit : *n) { + VERIFY(!is_undef(lit)); if (is_undef(lit)) return true; } } @@ -1743,74 +1750,10 @@ namespace sat { bool lookahead::check_autarky(literal l, unsigned level) { return false; -#if 0 - // no propagations are allowed to reduce clauses. - for (nary * cp : m_nary[(~l).index()]) { - clause& c = *cp; - unsigned sz = c.size(); - bool found = false; - for (unsigned i = 0; !found && i < sz; ++i) { - found = is_true(c[i]); - if (found) { - TRACE("sat", tout << c[i] << " is true in " << c << "\n";); - } - } - IF_VERBOSE(2, verbose_stream() << "skip autarky " << l << "\n";); - if (!found) return false; - } - // - // bail out if there is a pending binary propagation. - // In general, we would have to check, recursively that - // a binary propagation does not create reduced clauses. - // - literal_vector const& lits = m_binary[l.index()]; - TRACE("sat", tout << l << ": " << lits << "\n";); - for (unsigned i = 0; i < lits.size(); ++i) { - literal l2 = lits[i]; - if (is_true(l2)) continue; - SASSERT(!is_false(l2)); - return false; - } - - return true; -#endif } - - void lookahead::update_lookahead_reward(literal l, unsigned level) { - if (m_lookahead_reward == 0) { - if (!check_autarky(l, level)) { - // skip - } - else if (get_lookahead_reward(l) == 0) { - ++m_stats.m_autarky_propagations; - IF_VERBOSE(1, verbose_stream() << "(sat.lookahead autarky " << l << ")\n";); - - TRACE("sat", tout << "autarky: " << l << " @ " << m_stamp[l.var()] - << " " - << (!m_binary[l.index()].empty() || m_nary_count[l.index()] != 0) << "\n";); - lookahead_backtrack(); - assign(l); - propagate(); - } - else { - ++m_stats.m_autarky_equivalences; - // l => p is known, but p => l is possibly not. - // add p => l. - // justification: any consequence of l - // that is not a consequence of p does not - // reduce the clauses. - literal p = get_parent(l); - SASSERT(p != null_literal); - if (m_stamp[p.var()] > m_stamp[l.var()]) { - TRACE("sat", tout << "equivalence " << l << " == " << p << "\n"; display(tout);); - IF_VERBOSE(1, verbose_stream() << "(sat.lookahead equivalence " << l << " == " << p << ")\n";); - add_binary(~l, p); - set_level(l, p); - } - } - } - else { + void lookahead::update_lookahead_reward(literal l, unsigned level) { + if (m_lookahead_reward != 0) { inc_lookahead_reward(l, m_lookahead_reward); } } @@ -1852,7 +1795,6 @@ namespace sat { literal last_changed = null_literal; unsigned num_iterations = 0; while (change && num_iterations < m_config.m_dl_max_iterations && !inconsistent()) { - change = false; num_iterations++; for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { literal lit = m_lookahead[i].m_lit; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index d30485254..64a4ef63e 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -247,6 +247,7 @@ namespace sat { inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } inline void set_undef(literal l) { m_stamp[l.var()] = 0; } void set_level(literal d, literal s) { m_stamp[d.var()] = (m_stamp[s.var()] & ~0x1) + d.sign(); } + unsigned get_level(literal d) const { return m_stamp[d.var()]; } lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; } // set the level within a scope of the search. diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b967ade06..b1f0431cc 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1657,6 +1657,7 @@ namespace sat { bool_var_vector vars; order_vars_for_elim(vars); sat::elim_vars elim_bdd(*this); + unsigned bdd_vars = 0; for (bool_var v : vars) { checkpoint(); @@ -1665,10 +1666,13 @@ namespace sat { if (try_eliminate(v)) { m_num_elim_vars++; } - else if (elim_bdd(v)) { + else if (false && elim_bdd(v)) { m_num_elim_vars++; + ++bdd_vars; } } + std::cout << "bdd elim: " << bdd_vars << "\n"; + std::cout << "bdd miss: " << elim_bdd.miss() << "\n"; m_pos_cls.finalize(); m_neg_cls.finalize(); diff --git a/src/test/bdd.cpp b/src/test/bdd.cpp index b60522740..ea5a0bc34 100644 --- a/src/test/bdd.cpp +++ b/src/test/bdd.cpp @@ -67,6 +67,7 @@ namespace sat { std::cout << "before reorder:\n"; std::cout << c1 << "\n"; std::cout << c1.bdd_size() << "\n"; + m.gc(); m.try_reorder(); std::cout << "after reorder:\n"; std::cout << c1 << "\n"; diff --git a/src/util/vector.h b/src/util/vector.h index c60585512..f068481db 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -472,6 +472,11 @@ typedef svector char_vector; typedef svector signed_char_vector; typedef svector double_vector; +inline std::ostream& operator<<(std::ostream& out, unsigned_vector const& v) { + for (unsigned u : v) out << u << " "; + return out; +} + template struct vector_hash_tpl { Hash m_hash; From 553bf74f47f04fab0c55b97e1d64ab1626c29763 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Oct 2017 17:38:39 -0700 Subject: [PATCH 0291/1283] testing bdd for elim-vars Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index be698fc46..4bb7ba180 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1622,7 +1622,7 @@ namespace sat { } SASSERT(m_qhead == m_trail.size() || (inconsistent() && m_qhead < m_trail.size())); //SASSERT(!missed_conflict()); - VERIFY(!missed_propagation()); + //VERIFY(!missed_propagation()); TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } From 636f740b1afcaa4fcb2c8af91784d4fe0948b852 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Oct 2017 19:32:49 -0700 Subject: [PATCH 0292/1283] fixup bdd reordering, assertions and perf Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 89 +++++++++++++++----------------------- src/sat/sat_elim_vars.cpp | 29 +++++-------- src/sat/sat_elim_vars.h | 6 ++- src/sat/sat_simplifier.cpp | 7 +-- 4 files changed, 52 insertions(+), 79 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index e44bf7944..52714eae6 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -19,6 +19,7 @@ Revision History: #include "sat/sat_bdd.h" #include "util/trace.h" +#include "util/stopwatch.h" namespace sat { @@ -60,7 +61,7 @@ namespace sat { m_alloc.deallocate(sizeof(*m_spare_entry), m_spare_entry); } for (auto* e : m_op_cache) { - VERIFY(e != m_spare_entry); + SASSERT(e != m_spare_entry); m_alloc.deallocate(sizeof(*e), e); } } @@ -87,12 +88,9 @@ namespace sat { return apply_rec(arg1, arg2, op); } catch (mem_out) { - throw; -#if 0 try_reorder(); if (!first) throw; first = false; -#endif } } SASSERT(well_formed()); @@ -109,9 +107,8 @@ namespace sat { bool bdd_manager::check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c) { - // std::cout << a << " " << b << " " << c << " " << e1 << " " << e2 << "\n"; if (e1 != e2) { - VERIFY(e2->m_result != -1); + SASSERT(e2->m_result != -1); push_entry(e1); e1 = nullptr; return true; @@ -120,7 +117,7 @@ namespace sat { e1->m_bdd1 = a; e1->m_bdd2 = b; e1->m_op = c; - VERIFY(e1->m_result == -1); + SASSERT(e1->m_result == -1); return false; } } @@ -157,7 +154,7 @@ namespace sat { SASSERT(!m_free_nodes.contains(e2->m_result)); return e2->m_result; } - // VERIFY(well_formed()); + // SASSERT(well_formed()); BDD r; if (level(a) == level(b)) { push(apply_rec(lo(a), lo(b), op)); @@ -176,7 +173,7 @@ namespace sat { } pop(2); e1->m_result = r; - // VERIFY(well_formed()); + // SASSERT(well_formed()); SASSERT(!m_free_nodes.contains(r)); return r; } @@ -205,7 +202,6 @@ namespace sat { else { void * mem = m_alloc.allocate(sizeof(op_entry)); result = new (mem) op_entry(l, r, op); - // std::cout << "alloc: " << result << "\n"; } result->m_result = -1; return result; @@ -221,11 +217,8 @@ namespace sat { if (l == h) { return l; } - if (!is_const(l) && level(l) >= lvl) { - display(std::cout << l << " level: " << level(l) << " lvl: " << lvl << "\n"); - } - VERIFY(is_const(l) || level(l) < lvl); - VERIFY(is_const(h) || level(h) < lvl); + SASSERT(is_const(l) || level(l) < lvl); + SASSERT(is_const(h) || level(h) < lvl); bdd_node n(lvl, l, h); node_table::entry* e = m_node_table.insert_if_not_there2(n); @@ -353,7 +346,7 @@ namespace sat { void bdd_manager::sift_up(unsigned lvl) { if (m_level2nodes[lvl].empty()) return; - // VERIFY(well_formed()); + // SASSERT(well_formed()); // exchange level and level + 1. m_S.reset(); m_T.reset(); @@ -452,8 +445,8 @@ namespace sat { unsigned n = m_to_free[i]; bdd_node& node = m_nodes[n]; if (!node.is_internal()) { - VERIFY(!m_free_nodes.contains(n)); - VERIFY(node.m_refcount == 0); + SASSERT(!m_free_nodes.contains(n)); + SASSERT(node.m_refcount == 0); m_free_nodes.push_back(n); m_node_table.remove(node); BDD l = lo(n); @@ -485,7 +478,7 @@ namespace sat { tout << i << " " << m_reorder_rc[i] << "\n"; }}); - // VERIFY(well_formed()); + // SASSERT(well_formed()); } void bdd_manager::init_reorder() { @@ -554,12 +547,9 @@ namespace sat { return bdd(mk_not_rec(b.root), this); } catch (mem_out) { - throw; -#if 0 try_reorder(); if (!first) throw; first = false; -#endif } } } @@ -640,7 +630,7 @@ namespace sat { } bdd bdd_manager::mk_exists(unsigned n, unsigned const* vars, bdd const& b) { - // VERIFY(well_formed()); + // SASSERT(well_formed()); return bdd(mk_quant(n, vars, b.root, bdd_or_op), this); } @@ -677,7 +667,7 @@ namespace sat { r = e2->m_result; } else { - VERIFY(e1->m_result == -1); + SASSERT(e1->m_result == -1); push(mk_quant_rec(l, lo(b), op)); push(mk_quant_rec(l, hi(b), op)); r = make_node(lvl, read(2), read(1)); @@ -685,7 +675,7 @@ namespace sat { e1->m_result = r; } } - VERIFY(r != UINT_MAX); + SASSERT(r != UINT_MAX); return r; } @@ -703,11 +693,11 @@ namespace sat { m_todo.pop_back(); } else if (!is_marked(lo(r))) { - VERIFY (is_const(r) || r != lo(r)); + SASSERT (is_const(r) || r != lo(r)); m_todo.push_back(lo(r)); } else if (!is_marked(hi(r))) { - VERIFY (is_const(r) || r != hi(r)); + SASSERT (is_const(r) || r != hi(r)); m_todo.push_back(hi(r)); } else { @@ -782,7 +772,7 @@ namespace sat { for (unsigned i = m_nodes.size(); i-- > 2; ) { if (!reachable[i]) { m_nodes[i].set_internal(); - VERIFY(m_nodes[i].m_refcount == 0); + SASSERT(m_nodes[i].m_refcount == 0); m_free_nodes.push_back(i); } } @@ -792,8 +782,7 @@ namespace sat { ptr_vector to_delete, to_keep; for (auto* e : m_op_cache) { - // std::cout << "check: " << e << "\n"; - if (!reachable[e->m_bdd1] || !reachable[e->m_bdd2] || !reachable[e->m_op] || (e->m_result != -1 && !reachable[e->m_result])) { + if (e->m_result != -1) { to_delete.push_back(e); } else { @@ -802,7 +791,6 @@ namespace sat { } m_op_cache.reset(); for (op_entry* e : to_delete) { - // std::cout << "erase: " << e << "\n"; m_alloc.deallocate(sizeof(*e), e); } for (op_entry* e : to_keep) { @@ -858,11 +846,15 @@ namespace sat { } bool bdd_manager::well_formed() { + bool ok = true; for (unsigned n : m_free_nodes) { - if (!(lo(n) == 0 && hi(n) == 0 && m_nodes[n].m_refcount == 0)) { - std::cout << "free node is not internal " << n << " " << lo(n) << " " << hi(n) << " " << m_nodes[n].m_refcount << "\n"; - display(std::cout); + ok &= (lo(n) == 0 && hi(n) == 0 && m_nodes[n].m_refcount == 0); + if (!ok) { + IF_VERBOSE(0, + verbose_stream() << "free node is not internal " << n << " " << lo(n) << " " << hi(n) << " " << m_nodes[n].m_refcount << "\n"; + display(verbose_stream());); UNREACHABLE(); + return false; } } for (bdd_node const& n : m_nodes) { @@ -870,28 +862,17 @@ namespace sat { unsigned lvl = n.m_level; BDD lo = n.m_lo; BDD hi = n.m_hi; - if (!is_const(lo) && level(lo) >= lvl) { - std::cout << n.m_index << " lo: " << lo << "\n"; - display(std::cout); + ok &= is_const(lo) || level(lo) < lvl; + ok &= is_const(hi) || level(hi) < lvl; + ok &= is_const(lo) || !m_nodes[lo].is_internal(); + ok &= is_const(hi) || !m_nodes[hi].is_internal(); + if (!ok) { + IF_VERBOSE(0, display(verbose_stream() << n.m_index << " lo " << lo << " hi " << hi << "\n");); + UNREACHABLE(); + return false; } - VERIFY(is_const(lo) || level(lo) < lvl); - if (!is_const(hi) && level(hi) >= lvl) { - std::cout << n.m_index << " hi: " << hi << "\n"; - display(std::cout); - } - VERIFY(is_const(hi) || level(hi) < lvl); - if (!is_const(lo) && m_nodes[lo].is_internal()) { - std::cout << n.m_index << " lo: " << lo << "\n"; - display(std::cout); - } - if (!is_const(hi) && m_nodes[hi].is_internal()) { - std::cout << n.m_index << " hi: " << hi << "\n"; - display(std::cout); - } - VERIFY(is_const(lo) || !m_nodes[lo].is_internal()); - VERIFY(is_const(hi) || !m_nodes[hi].is_internal()); } - return true; + return ok; } std::ostream& bdd_manager::display(std::ostream& out) { diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 99c15c247..86954d037 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -27,6 +27,8 @@ namespace sat{ m_mark_lim = 0; m_max_literals = 11; m_miss = 0; + m_hit1 = 0; + m_hit2 = 0; } bool elim_vars::operator()(bool_var v) { @@ -57,29 +59,20 @@ namespace sat{ bdd b1 = elim_var(v); double sz1 = b1.cnf_size(); if (sz1 > 2*clause_size) { + ++m_miss; return false; } if (sz1 <= clause_size) { + ++m_hit1; return elim_var(v, b1); } - - m_vars.reverse(); - bdd b2 = elim_var(v); - double sz2 = b2.cnf_size(); - if (sz2 <= clause_size) { - return elim_var(v, b2); - } - shuffle_vars(); - bdd b3 = elim_var(v); - double sz3 = b3.cnf_size(); - if (sz3 <= clause_size) { - return elim_var(v, b3); - } -#if 0 - m.try_cnf_reorder(b3); - sz3 = b3.cnf_size(); - if (sz3 <= clause_size) ++m_miss; -#endif + m.try_cnf_reorder(b1); + sz1 = b1.cnf_size(); + if (sz1 <= clause_size) { + ++m_hit2; + return elim_var(v, b1); + } + ++m_miss; return false; } diff --git a/src/sat/sat_elim_vars.h b/src/sat/sat_elim_vars.h index e4843c41c..ba5a02d67 100644 --- a/src/sat/sat_elim_vars.h +++ b/src/sat/sat_elim_vars.h @@ -41,6 +41,8 @@ namespace sat { unsigned_vector m_var2index; unsigned_vector m_occ; unsigned m_miss; + unsigned m_hit1; + unsigned m_hit2; unsigned m_max_literals; @@ -62,7 +64,9 @@ namespace sat { public: elim_vars(simplifier& s); bool operator()(bool_var v); - unsigned miss() const { return m_miss; } + unsigned hit2() const { return m_hit1; } // first round bdd construction is minimal + unsigned hit1() const { return m_hit2; } // minimal after reshufling + unsigned miss() const { return m_miss; } // not-minimal }; }; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b1f0431cc..cd46f1916 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1657,8 +1657,6 @@ namespace sat { bool_var_vector vars; order_vars_for_elim(vars); sat::elim_vars elim_bdd(*this); - unsigned bdd_vars = 0; - for (bool_var v : vars) { checkpoint(); if (m_elim_counter < 0) @@ -1666,13 +1664,10 @@ namespace sat { if (try_eliminate(v)) { m_num_elim_vars++; } - else if (false && elim_bdd(v)) { + else if (elim_bdd(v)) { m_num_elim_vars++; - ++bdd_vars; } } - std::cout << "bdd elim: " << bdd_vars << "\n"; - std::cout << "bdd miss: " << elim_bdd.miss() << "\n"; m_pos_cls.finalize(); m_neg_cls.finalize(); From ba6b024ac4d1d54574b5e92450dea4f29598a004 Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Thu, 19 Oct 2017 19:52:56 -0700 Subject: [PATCH 0293/1283] Reverted to March_CU like lookahead --- src/sat/sat_lookahead.cpp | 45 ++++++++++++++++++++++----------------- src/sat/sat_lookahead.h | 5 ++--- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index bdc856fb3..7e9e2d230 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -340,6 +340,13 @@ namespace sat { } bool lookahead::is_unsat() const { + for (unsigned idx = 0; idx < m_binary.size(); ++idx) { + literal l = to_literal(idx); + for (literal lit : m_binary[idx]) { + if (is_true(l) && is_false(lit)) + return true; + } + } // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. for (nary* n : m_nary_clauses) { @@ -432,8 +439,21 @@ namespace sat { bool lookahead::missed_conflict() const { if (inconsistent()) return false; + for (literal l1 : m_trail) { + for (literal l2 : m_binary[l1.index()]) { + if (is_false(l2)) + return true; + } + unsigned sz = m_ternary_count[(~l1).index()]; + for (binary b : m_ternary[(~l1).index()]) { + if (sz-- == 0) break; + if ((is_false(b.m_u) && is_false(b.m_v))) + return true; + } + } for (nary * n : m_nary_clauses) { - if (n->size() == 0) return true; + if (n->size() == 0) + return true; } return false; } @@ -1144,18 +1164,6 @@ namespace sat { SASSERT(m_trail_lim.empty() || m_trail.size() >= m_trail_lim.back()); } - void lookahead::promote(unsigned base) { - if (m_trail.empty()) return; - unsigned last_lvl = get_level(m_trail.back()); - base -= last_lvl; - for (unsigned i = m_trail.size(); i > 0; ) { - literal lit = m_trail[--i]; - if (is_fixed_at(lit, c_fixed_truth)) break; - SASSERT(is_fixed_at(lit, last_lvl)); - m_stamp[lit.var()] += base; - } - } - // // The current version is modeled after CDCL SAT solving data-structures. // It borrows from the watch list data-structure. The cost tradeoffs are somewhat @@ -1496,7 +1504,7 @@ namespace sat { sz = m_nary_count[l.index()]; for (nary* n : m_nary[l.index()]) { if (sz-- == 0) break; - if (m_stamp[l.var()] > m_stamp[n->get_head().var()]) { + if (get_level(l) > get_level(n->get_head())) { n->set_head(l); } } @@ -1692,7 +1700,6 @@ namespace sat { num_units += do_double(lit, dl_lvl); if (dl_lvl > level) { base = dl_lvl; - promote(base + m_lookahead[i].m_offset); SASSERT(get_level(m_trail.back()) == base + m_lookahead[i].m_offset); } unsat = inconsistent(); @@ -1881,15 +1888,13 @@ namespace sat { SASSERT(dl_no_overflow(base)); base += m_lookahead.size(); unsigned dl_truth = base + m_lookahead.size() * m_config.m_dl_max_iterations; - promote(dl_truth); scoped_level _sl(*this, dl_truth); SASSERT(get_level(m_trail.back()) == dl_truth); SASSERT(is_fixed(l)); IF_VERBOSE(2, verbose_stream() << "double: " << l << " depth: " << m_trail_lim.size() << "\n";); - //lookahead_backtrack(); - //assign(l); - //propagate(); - //SASSERT(!inconsistent()); + lookahead_backtrack(); + assign(l); + propagate(); unsigned old_sz = m_trail.size(); bool change = true; literal last_changed = null_literal; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 8420ae1f5..e84213cfe 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -90,7 +90,7 @@ namespace sat { m_min_cutoff = 30; m_preselect = false; m_level_cand = 600; - m_delta_rho = (double)0.85; + m_delta_rho = (double)0.7; m_dl_max_iterations = 2; m_tc1_limit = 10000000; m_reward_type = ternary_reward; @@ -246,7 +246,7 @@ namespace sat { inline bool is_true(literal l) const { return is_true_at(l, m_level); } inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } inline void set_undef(literal l) { m_stamp[l.var()] = 0; } - inline unsigned get_level(literal l) { return m_stamp[l.var()] & UINT_MAX - 1; } + inline unsigned get_level(literal l) const { return m_stamp[l.var()] & UINT_MAX - 1; } void set_level(literal d, literal s) { m_stamp[d.var()] = (m_stamp[s.var()] & ~0x1) + d.sign(); } lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; } @@ -480,7 +480,6 @@ namespace sat { unsigned push_lookahead1(literal lit, unsigned level); void pop_lookahead1(literal lit, unsigned num_units); void lookahead_backtrack(); - void promote(unsigned base); double mix_diff(double l, double r) const; clause const& get_clause(watch_list::iterator it) const; bool is_nary_propagation(clause const& c, literal l) const; From d58f42c821181ffe8e6798c1de4fe9ce87219b30 Mon Sep 17 00:00:00 2001 From: Miguel Neves Date: Thu, 19 Oct 2017 20:02:05 -0700 Subject: [PATCH 0294/1283] Merge --- src/sat/sat_lookahead.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index f98a117c8..e84213cfe 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -248,7 +248,6 @@ namespace sat { inline void set_undef(literal l) { m_stamp[l.var()] = 0; } inline unsigned get_level(literal l) const { return m_stamp[l.var()] & UINT_MAX - 1; } void set_level(literal d, literal s) { m_stamp[d.var()] = (m_stamp[s.var()] & ~0x1) + d.sign(); } - unsigned get_level(literal d) const { return m_stamp[d.var()]; } lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; } // set the level within a scope of the search. From 76eed064ebca58884d57c3b28404537cee265949 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 19 Oct 2017 22:19:05 -0700 Subject: [PATCH 0295/1283] bug fixes, prepare for retaining blocked clauses Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 15 +- src/sat/ba_solver.h | 2 +- src/sat/sat_clause.cpp | 1 + src/sat/sat_clause.h | 4 + src/sat/sat_clause_use_list.cpp | 16 +- src/sat/sat_clause_use_list.h | 57 +++-- src/sat/sat_elim_vars.cpp | 19 +- src/sat/sat_local_search.cpp | 2 +- src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_simplifier.cpp | 346 +++++++++++++++++------------- src/sat/sat_simplifier.h | 10 +- src/sat/sat_simplifier_params.pyg | 2 + src/sat/sat_solver.cpp | 37 ++-- src/sat/sat_solver.h | 4 +- src/sat/sat_watched.h | 11 +- src/shell/dimacs_frontend.cpp | 39 +++- 16 files changed, 333 insertions(+), 234 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index ab2352253..a8a09d3ff 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2761,8 +2761,8 @@ namespace sat { } } - unsigned ba_solver::get_num_non_learned_bin(literal l) { - return s().m_simplifier.get_num_non_learned_bin(l); + unsigned ba_solver::get_num_unblocked_bin(literal l) { + return s().m_simplifier.get_num_unblocked_bin(l); } /* @@ -2831,8 +2831,8 @@ namespace sat { value(lit) == l_undef && use_count(lit) == 1 && use_count(~lit) == 1 && - get_num_non_learned_bin(lit) == 0 && - get_num_non_learned_bin(~lit) == 0) { + get_num_unblocked_bin(lit) == 0 && + get_num_unblocked_bin(~lit) == 0) { remove_constraint(c, "unused def"); } break; @@ -2876,7 +2876,7 @@ namespace sat { bool ba_solver::elim_pure(literal lit) { if (value(lit) == l_undef && !m_cnstr_use_list[lit.index()].empty() && - use_count(~lit) == 0 && get_num_non_learned_bin(~lit) == 0) { + use_count(~lit) == 0 && get_num_unblocked_bin(~lit) == 0) { IF_VERBOSE(10, verbose_stream() << "pure literal: " << lit << "\n";); s().assign(lit, justification()); return true; @@ -3163,9 +3163,12 @@ namespace sat { if (w.is_binary_clause() && is_marked(w.get_literal())) { ++m_stats.m_num_bin_subsumes; // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); - if (!w.is_binary_non_learned_clause()) { + if (w.is_learned()) { c1.set_learned(false); } + else if (w.is_blocked()) { + w.set_unblocked(); + } } else { if (it != it2) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 09903f889..16c853423 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -262,7 +262,7 @@ namespace sat { void mark_visited(literal l) { m_visited[l.index()] = true; } void unmark_visited(literal l) { m_visited[l.index()] = false; } bool is_marked(literal l) const { return m_visited[l.index()] != 0; } - unsigned get_num_non_learned_bin(literal l); + unsigned get_num_unblocked_bin(literal l); literal get_min_occurrence_literal(card const& c); void init_use_lists(); void remove_unused_defs(); diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 15c97b509..206dfcf40 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -29,6 +29,7 @@ namespace sat { m_capacity(sz), m_removed(false), m_learned(learned), + m_blocked(false), m_used(false), m_frozen(false), m_reinit_stack(false), diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 556385696..8fd7b52cf 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -46,6 +46,7 @@ namespace sat { unsigned m_used:1; unsigned m_frozen:1; unsigned m_reinit_stack:1; + unsigned m_blocked; unsigned m_inact_rounds:8; unsigned m_glue:8; unsigned m_psm:8; // transient field used during gc @@ -86,6 +87,9 @@ namespace sat { unsigned inact_rounds() const { return m_inact_rounds; } bool frozen() const { return m_frozen; } void freeze() { SASSERT(is_learned()); SASSERT(!frozen()); m_frozen = true; } + bool is_blocked() const { return m_blocked; } + void block() { SASSERT(!m_blocked); SASSERT(!is_learned()); m_blocked = true; } + void unblock() { SASSERT(m_blocked); SASSERT(!is_learned()); m_blocked = false; } void unfreeze() { SASSERT(is_learned()); SASSERT(frozen()); m_frozen = false; } static var_approx_set approx(unsigned num, literal const * lits); void set_glue(unsigned glue) { m_glue = glue > 255 ? 255 : glue; } diff --git a/src/sat/sat_clause_use_list.cpp b/src/sat/sat_clause_use_list.cpp index 5ee5b4cda..363ef784e 100644 --- a/src/sat/sat_clause_use_list.cpp +++ b/src/sat/sat_clause_use_list.cpp @@ -22,17 +22,20 @@ Revision History: namespace sat { bool clause_use_list::check_invariant() const { -#ifdef LAZY_USE_LIST unsigned sz = 0; - for (unsigned i = 0; i < m_clauses.size(); i++) - if (!m_clauses[i]->was_removed()) + for (clause* c : m_clauses) + if (!c->was_removed()) sz++; SASSERT(sz == m_size); -#endif + unsigned blocked = 0; + for (clause* c : m_clauses) + if (c->is_blocked()) + blocked++; + SASSERT(blocked == m_num_blocked); + return true; } -#ifdef LAZY_USE_LIST void clause_use_list::iterator::consume() { while (true) { if (m_i == m_size) @@ -44,14 +47,11 @@ namespace sat { m_i++; } } -#endif clause_use_list::iterator::~iterator() { -#ifdef LAZY_USE_LIST while (m_i < m_size) next(); m_clauses.shrink(m_j); -#endif } }; diff --git a/src/sat/sat_clause_use_list.h b/src/sat/sat_clause_use_list.h index 121345f21..08b50086a 100644 --- a/src/sat/sat_clause_use_list.h +++ b/src/sat/sat_clause_use_list.h @@ -24,30 +24,30 @@ Revision History: namespace sat { -#define LAZY_USE_LIST - /** \brief Clause use list with delayed deletion. */ class clause_use_list { clause_vector m_clauses; -#ifdef LAZY_USE_LIST unsigned m_size; -#endif + unsigned m_num_blocked; public: clause_use_list() { STRACE("clause_use_list_bug", tout << "[cul_created] " << this << "\n";); -#ifdef LAZY_USE_LIST m_size = 0; -#endif + m_num_blocked = 0; } unsigned size() const { -#ifdef LAZY_USE_LIST return m_size; -#else - return m_clauses.size(); -#endif + } + + unsigned num_blocked() const { + return m_num_blocked; + } + + unsigned non_blocked_size() const { + return m_size - m_num_blocked; } bool empty() const { return size() == 0; } @@ -57,58 +57,59 @@ namespace sat { SASSERT(!m_clauses.contains(&c)); SASSERT(!c.was_removed()); m_clauses.push_back(&c); -#ifdef LAZY_USE_LIST m_size++; -#endif + if (c.is_blocked()) ++m_num_blocked; } void erase_not_removed(clause & c) { STRACE("clause_use_list_bug", tout << "[cul_erase_not_removed] " << this << " " << &c << "\n";); -#ifdef LAZY_USE_LIST SASSERT(m_clauses.contains(&c)); SASSERT(!c.was_removed()); m_clauses.erase(&c); m_size--; -#else - m_clauses.erase(&c); -#endif + if (c.is_blocked()) --m_num_blocked; } void erase(clause & c) { STRACE("clause_use_list_bug", tout << "[cul_erase] " << this << " " << &c << "\n";); -#ifdef LAZY_USE_LIST SASSERT(m_clauses.contains(&c)); SASSERT(c.was_removed()); m_size--; -#else - m_clauses.erase(&c); -#endif + if (c.is_blocked()) --m_num_blocked; + } + + void block(clause const& c) { + SASSERT(c.is_blocked()); + ++m_num_blocked; + SASSERT(check_invariant()); + } + + void unblock(clause const& c) { + SASSERT(!c.is_blocked()); + --m_num_blocked; + SASSERT(check_invariant()); } void reset() { m_clauses.finalize(); -#ifdef LAZY_USE_LIST m_size = 0; -#endif + m_num_blocked = 0; } bool check_invariant() const; // iterate & compress - class iterator { + class iterator { clause_vector & m_clauses; unsigned m_size; unsigned m_i; -#ifdef LAZY_USE_LIST unsigned m_j; void consume(); -#endif + public: iterator(clause_vector & v):m_clauses(v), m_size(v.size()), m_i(0) { -#ifdef LAZY_USE_LIST m_j = 0; consume(); -#endif } ~iterator(); bool at_end() const { return m_i == m_size; } @@ -117,10 +118,8 @@ namespace sat { SASSERT(!at_end()); SASSERT(!m_clauses[m_i]->was_removed()); m_i++; -#ifdef LAZY_USE_LIST m_j++; consume(); -#endif } }; diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 86954d037..59210a266 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -37,13 +37,13 @@ namespace sat{ literal pos_l(v, false); literal neg_l(v, true); - unsigned num_bin_pos = simp.get_num_non_learned_bin(pos_l); + unsigned num_bin_pos = simp.get_num_unblocked_bin(pos_l); if (num_bin_pos > m_max_literals) return false; - unsigned num_bin_neg = simp.get_num_non_learned_bin(neg_l); + unsigned num_bin_neg = simp.get_num_unblocked_bin(neg_l); if (num_bin_neg > m_max_literals) return false; clause_use_list & pos_occs = simp.m_use_list.get(pos_l); clause_use_list & neg_occs = simp.m_use_list.get(neg_l); - unsigned clause_size = num_bin_pos + num_bin_neg + pos_occs.size() + neg_occs.size(); + unsigned clause_size = num_bin_pos + num_bin_neg + pos_occs.non_blocked_size() + neg_occs.non_blocked_size(); if (clause_size == 0) { return false; } @@ -85,8 +85,8 @@ namespace sat{ // eliminate variable simp.m_pos_cls.reset(); simp.m_neg_cls.reset(); - simp.collect_clauses(pos_l, simp.m_pos_cls); - simp.collect_clauses(neg_l, simp.m_neg_cls); + simp.collect_clauses(pos_l, simp.m_pos_cls, false); + simp.collect_clauses(neg_l, simp.m_neg_cls, false); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); simp.save_clauses(mc_entry, simp.m_pos_cls); simp.save_clauses(mc_entry, simp.m_neg_cls); @@ -122,13 +122,13 @@ namespace sat{ TRACE("elim_vars", tout << "eliminate " << v << "\n"; for (watched const& w : simp.get_wlist(~pos_l)) { - if (w.is_binary_non_learned_clause()) { + if (w.is_binary_unblocked_clause()) { tout << pos_l << " " << w.get_literal() << "\n"; } } m.display(tout, b1); for (watched const& w : simp.get_wlist(~neg_l)) { - if (w.is_binary_non_learned_clause()) { + if (w.is_binary_unblocked_clause()) { tout << neg_l << " " << w.get_literal() << "\n"; } } @@ -294,7 +294,7 @@ namespace sat{ bool elim_vars::mark_literals(literal lit) { watch_list& wl = simp.get_wlist(lit); for (watched const& w : wl) { - if (w.is_binary_non_learned_clause()) { + if (w.is_binary_unblocked_clause()) { mark_var(w.get_literal().var()); } } @@ -306,6 +306,7 @@ namespace sat{ clause_use_list::iterator it = occs.mk_iterator(); while (!it.at_end()) { clause const& c = it.curr(); + if (c.is_blocked()) continue; bdd cl = m.mk_false(); for (literal l : c) { cl |= mk_literal(l); @@ -320,7 +321,7 @@ namespace sat{ bdd result = m.mk_true(); watch_list& wl = simp.get_wlist(~lit); for (watched const& w : wl) { - if (w.is_binary_non_learned_clause()) { + if (w.is_binary_unblocked_clause()) { result &= (mk_literal(lit) || mk_literal(w.get_literal())); } } diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 5cc19a174..3a9e48182 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -304,7 +304,7 @@ namespace sat { watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); for (; it != end; ++it) { - if (!it->is_binary_non_learned_clause()) + if (!it->is_binary_unblocked_clause()) continue; literal l2 = it->get_literal(); if (l1.index() > l2.index()) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 4bb7ba180..ff2bac39f 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -965,7 +965,7 @@ namespace sat { if (m_s.was_eliminated(l.var())) continue; watch_list const & wlist = m_s.m_watches[l_idx]; for (auto& w : wlist) { - if (!w.is_binary_non_learned_clause()) + if (!w.is_binary_clause()) continue; literal l2 = w.get_literal(); if (l.index() < l2.index() && !m_s.was_eliminated(l2.var())) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index cd46f1916..b0ef9e3e9 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -34,26 +34,29 @@ namespace sat { } void use_list::insert(clause & c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - m_use_list[c[i].index()].insert(c); - } + for (literal l : c) + m_use_list[l.index()].insert(c); } void use_list::erase(clause & c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - m_use_list[c[i].index()].erase(c); - } + for (literal l : c) + m_use_list[l.index()].erase(c); } void use_list::erase(clause & c, literal l) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - literal l2 = c[i]; + for (literal l2 : c) if (l2 != l) m_use_list[l2.index()].erase(c); - } + } + + void use_list::block(clause& c) { + for (literal l : c) + m_use_list[l.index()].block(c); + } + + void use_list::unblock(clause& c) { + for (literal l : c) + m_use_list[l.index()].unblock(c); } simplifier::simplifier(solver & _s, params_ref const & p): @@ -99,9 +102,8 @@ namespace sat { } inline void simplifier::remove_clause_core(clause & c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) - insert_elim_todo(c[i].var()); + for (literal l : c) + insert_elim_todo(l.var()); m_sub_todo.erase(c); c.set_removed(true); TRACE("resolution_bug", tout << "del_clause: " << c << "\n";); @@ -118,6 +120,20 @@ namespace sat { m_use_list.erase(c, l); } + inline void simplifier::block_clause(clause & c) { +#if 1 + remove_clause(c); +#else + c.block(); + m_use_list.block(c); +#endif + } + + inline void simplifier::unblock_clause(clause & c) { + c.unblock(); + m_use_list.unblock(c); + } + inline void simplifier::remove_bin_clause_half(literal l1, literal l2, bool learned) { SASSERT(s.get_wlist(~l1).contains(watched(l2, learned))); s.get_wlist(~l1).erase(watched(l2, learned)); @@ -238,10 +254,7 @@ namespace sat { \brief Eliminate all ternary and clause watches. */ void simplifier::cleanup_watches() { - vector::iterator it = s.m_watches.begin(); - vector::iterator end = s.m_watches.end(); - for (; it != end; ++it) { - watch_list & wlist = *it; + for (watch_list& wlist : s.m_watches) { watch_list::iterator it2 = wlist.begin(); watch_list::iterator itprev = it2; watch_list::iterator end2 = wlist.end(); @@ -345,11 +358,9 @@ namespace sat { \brief Return the variable in c with the minimal number positive+negative occurrences. */ bool_var simplifier::get_min_occ_var(clause const & c) const { - literal l_best = c[0]; - unsigned best = m_use_list.get(l_best).size() + m_use_list.get(~l_best).size(); - unsigned sz = c.size(); - for (unsigned i = 1; i < sz; i++) { - literal l = c[i]; + literal l_best = null_literal; + unsigned best = UINT_MAX; + for (literal l : c) { unsigned num = m_use_list.get(l).size() + m_use_list.get(~l).size(); if (num < best) { l_best = l; @@ -394,6 +405,7 @@ namespace sat { */ void simplifier::collect_subsumed1_core(clause const & c1, clause_vector & out, literal_vector & out_lits, literal target) { + if (c1.is_blocked()) return; clause_use_list const & cs = m_use_list.get(target); clause_use_list::iterator it = cs.mk_iterator(); while (!it.at_end()) { @@ -424,7 +436,7 @@ namespace sat { } /** - \brief Perform backward subsumption and self-subsumption resolution using c. + \brief Perform backward subsumption and self-subsumption resolution using c1. */ void simplifier::back_subsumption1(clause & c1) { m_bs_cs.reset(); @@ -440,11 +452,13 @@ namespace sat { // c2 was subsumed if (c1.is_learned() && !c2.is_learned()) c1.unset_learned(); + else if (c1.is_blocked() && !c2.is_learned() && !c2.is_blocked()) + unblock_clause(c1); TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";); remove_clause(c2); m_num_subsumed++; } - else if (!c2.was_removed()) { + else if (!c2.was_removed() && !c1.is_blocked()) { // subsumption resolution TRACE("subsumption_resolution", tout << c1 << " sub-ref(" << *l_it << ") " << c2 << "\n";); elim_lit(c2, *l_it); @@ -466,11 +480,9 @@ namespace sat { \brief Return the literal in c with the minimal number of occurrences. */ literal simplifier::get_min_occ_var0(clause const & c) const { - literal l_best = c[0]; - unsigned best = m_use_list.get(l_best).size(); - unsigned sz = c.size(); - for (unsigned i = 1; i < sz; i++) { - literal l = c[i]; + literal l_best = null_literal; + unsigned best = UINT_MAX; + for (literal l : c) { unsigned num = m_use_list.get(l).size(); if (num < best) { l_best = l; @@ -485,21 +497,19 @@ namespace sat { Otherwise return false */ bool simplifier::subsumes0(clause const & c1, clause const & c2) { - unsigned sz2 = c2.size(); - for (unsigned i = 0; i < sz2; i++) - mark_visited(c2[i]); + for (literal l : c2) + mark_visited(l); bool r = true; - unsigned sz1 = c1.size(); - for (unsigned i = 0; i < sz1; i++) { - if (!is_marked(c1[i])) { + for (literal l : c1) { + if (!is_marked(l)) { r = false; break; } } - for (unsigned i = 0; i < sz2; i++) - unmark_visited(c2[i]); + for (literal l : c2) + unmark_visited(l); return r; } @@ -508,6 +518,7 @@ namespace sat { \brief Collect the clauses subsumed by c1 (using the occurrence list of target). */ void simplifier::collect_subsumed0_core(clause const & c1, clause_vector & out, literal target) { + if (c1.is_blocked()) return; clause_use_list const & cs = m_use_list.get(target); clause_use_list::iterator it = cs.mk_iterator(); while (!it.at_end()) { @@ -540,10 +551,8 @@ namespace sat { void simplifier::back_subsumption0(clause & c1) { m_bs_cs.reset(); collect_subsumed0(c1, m_bs_cs); - clause_vector::iterator it = m_bs_cs.begin(); - clause_vector::iterator end = m_bs_cs.end(); - for (; it != end; ++it) { - clause & c2 = *(*it); + for (clause* cp : m_bs_cs) { + clause & c2 = *cp; // c2 was subsumed if (c1.is_learned() && !c2.is_learned()) c1.unset_learned(); @@ -951,13 +960,17 @@ namespace sat { return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v); } - void operator()(unsigned num_vars) { + void insert_queue(unsigned num_vars) { for (bool_var v = 0; v < num_vars; v++) { if (process_var(v)) { insert(literal(v, false)); insert(literal(v, true)); } } + } + + void block_clauses(unsigned num_vars) { + insert_queue(num_vars); while (!m_queue.empty()) { s.checkpoint(); if (m_counter < 0) @@ -965,7 +978,73 @@ namespace sat { literal l = m_queue.next(); process(l); } - cce(); + } + + void operator()(unsigned num_vars) { + block_clauses(num_vars); + if (s.m_elim_covered_clauses) + cce(); + } + + void process(literal l) { + TRACE("blocked_clause", tout << "processing: " << l << "\n";); + model_converter::entry * new_entry = 0; + if (!process_var(l.var())) { + return; + } + + literal blocked = null_literal; + m_to_remove.reset(); + { + clause_use_list & occs = s.m_use_list.get(l); + clause_use_list::iterator it = occs.mk_iterator(); + while (!it.at_end()) { + clause & c = it.curr(); + if (c.is_blocked()) continue; + m_counter -= c.size(); + SASSERT(c.contains(l)); + s.mark_all_but(c, l); + if (all_tautology(l)) { + block_clause(c, l, new_entry); + s.m_num_blocked_clauses++; + } + s.unmark_all(c); + it.next(); + } + } + for (clause* c : m_to_remove) + s.block_clause(*c); + + { + watch_list & wlist = s.get_wlist(~l); + m_counter -= wlist.size(); + watch_list::iterator it = wlist.begin(); + watch_list::iterator it2 = it; + watch_list::iterator end = wlist.end(); + for (; it != end; ++it) { + if (!it->is_binary_clause() || it->is_blocked()) { + *it2 = *it; + it2++; + continue; + } + literal l2 = it->get_literal(); + s.mark_visited(l2); + if (all_tautology(l)) { + block_binary(it, l, new_entry); + s.m_num_blocked_clauses++; + } + else if (s.m_elim_covered_clauses && cce(l, l2, blocked)) { + block_covered_binary(it, l, blocked); + s.m_num_covered_clauses++; + } + else { + *it2 = *it; + it2++; + } + s.unmark_visited(l2); + } + wlist.set_end(it2); + } } // @@ -976,7 +1055,7 @@ namespace sat { if (!process_var(l.var())) return false; bool first = true; for (watched & w : s.get_wlist(l)) { - if (w.is_binary_non_learned_clause()) { + if (w.is_binary_unblocked_clause()) { literal lit = w.get_literal(); if (s.is_marked(~lit) && lit != ~l) continue; if (!first) { @@ -992,6 +1071,7 @@ namespace sat { while (!it.at_end()) { bool tautology = false; clause & c = it.curr(); + if (c.is_blocked()) continue; for (literal lit : c) { if (s.is_marked(~lit) && lit != ~l) { tautology = true; @@ -1007,16 +1087,9 @@ namespace sat { } else { unsigned j = 0; - unsigned sz = inter.size(); - for (unsigned i = 0; i < sz; ++i) { - literal lit1 = inter[i]; - for (literal lit2 : c) { - if (lit1 == lit2) { - inter[j++] = lit1; - break; - } - } - } + for (literal lit : inter) + if (c.contains(lit)) + inter[j++] = lit; inter.shrink(j); if (j == 0) return false; } @@ -1052,6 +1125,14 @@ namespace sat { } } + + /* + * C \/ l ~l \/ lit \/ D_i for i = 1...N all the clauses that have ~l + * ------------------------- + * C \/ l \/ lit + * + * + */ bool add_cla(literal& blocked) { for (unsigned i = 0; i < m_covered_clause.size(); ++i) { m_intersection.reset(); @@ -1059,15 +1140,15 @@ namespace sat { blocked = m_covered_clause[i]; return true; } + if (!m_intersection.empty()) { + m_elim_stack.push_back(std::make_pair(m_covered_clause.size(), m_covered_clause[i])); + } for (literal l : m_intersection) { if (!s.is_marked(l)) { s.mark_visited(l); m_covered_clause.push_back(l); } } - if (!m_intersection.empty()) { - m_elim_stack.push_back(std::make_pair(m_covered_clause.size(), m_covered_clause[i])); - } } return false; } @@ -1085,14 +1166,18 @@ namespace sat { is_tautology = add_cla(blocked); } while (m_covered_clause.size() > sz && !is_tautology); +#if 1 break; - //if (is_tautology) break; - //sz = m_covered_clause.size(); - // unsound? add_ala(); +#else + // check for soundness? + if (is_tautology) break; + sz = m_covered_clause.size(); + add_ala(); +#endif } while (m_covered_clause.size() > sz); for (literal l : m_covered_clause) s.unmark_visited(l); - // if (is_tautology) std::cout << "taut: " << num_iterations << " " << m_covered_clause.size() << " " << m_elim_stack.size() << "\n"; + if (is_tautology) std::cout << "taut: " << num_iterations << " " << m_covered_clause.size() << " " << m_elim_stack.size() << "\n"; return is_tautology; } @@ -1105,9 +1190,9 @@ namespace sat { return cla(blocked); } - bool cce(literal lit, literal l2, literal& blocked) { + bool cce(literal l1, literal l2, literal& blocked) { m_covered_clause.reset(); - m_covered_clause.push_back(lit); + m_covered_clause.push_back(l1); m_covered_clause.push_back(l2); return cla(blocked); } @@ -1117,79 +1202,17 @@ namespace sat { literal blocked; for (clause* cp : s.s.m_clauses) { clause& c = *cp; - if (c.was_removed()) continue; - if (cce(c, blocked)) { - model_converter::entry * new_entry = 0; - block_covered_clause(c, blocked, new_entry); + if (!c.was_removed() && !c.is_blocked() && cce(c, blocked)) { + block_covered_clause(c, blocked); s.m_num_covered_clauses++; } } for (clause* c : m_to_remove) { - s.remove_clause(*c); + s.block_clause(*c); } m_to_remove.reset(); } - void process(literal l) { - TRACE("blocked_clause", tout << "processing: " << l << "\n";); - model_converter::entry * new_entry = 0; - if (!process_var(l.var())) { - return; - } - - literal blocked = null_literal; - m_to_remove.reset(); - { - clause_use_list & occs = s.m_use_list.get(l); - clause_use_list::iterator it = occs.mk_iterator(); - while (!it.at_end()) { - clause & c = it.curr(); - m_counter -= c.size(); - SASSERT(c.contains(l)); - s.mark_all_but(c, l); - if (all_tautology(l)) { - block_clause(c, l, new_entry); - s.m_num_blocked_clauses++; - } - s.unmark_all(c); - it.next(); - } - } - for (clause* c : m_to_remove) { - s.remove_clause(*c); - } - { - watch_list & wlist = s.get_wlist(~l); - m_counter -= wlist.size(); - watch_list::iterator it = wlist.begin(); - watch_list::iterator it2 = it; - watch_list::iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_clause()) { - *it2 = *it; - it2++; - continue; - } - literal l2 = it->get_literal(); - s.mark_visited(l2); - if (all_tautology(l)) { - block_binary(it, l, new_entry); - s.m_num_blocked_clauses++; - } - else if (cce(l, l2, blocked)) { - model_converter::entry * blocked_entry = 0; - block_covered_binary(it, l, blocked, blocked_entry); - s.m_num_covered_clauses++; - } - else { - *it2 = *it; - it2++; - } - s.unmark_visited(l2); - } - wlist.set_end(it2); - } - } void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); @@ -1208,7 +1231,8 @@ namespace sat { mc.insert(*new_entry, c); } - void block_covered_clause(clause& c, literal l, model_converter::entry *& new_entry) { + void block_covered_clause(clause& c, literal l) { + model_converter::entry * new_entry = 0; prepare_block_clause(c, l, new_entry); mc.insert(*new_entry, m_covered_clause, m_elim_stack); } @@ -1227,7 +1251,8 @@ namespace sat { mc.insert(*new_entry, l, it->get_literal()); } - void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::entry *& new_entry) { + void block_covered_binary(watch_list::iterator it, literal l, literal blocked) { + model_converter::entry * new_entry = 0; prepare_block_binary(it, l, blocked, new_entry); mc.insert(*new_entry, m_covered_clause, m_elim_stack); } @@ -1236,7 +1261,7 @@ namespace sat { watch_list & wlist = s.get_wlist(l); m_counter -= wlist.size(); for (auto const& w : wlist) { - if (w.is_binary_non_learned_clause() && + if (w.is_binary_unblocked_clause() && !s.is_marked(~w.get_literal())) return false; } @@ -1245,6 +1270,7 @@ namespace sat { clause_use_list::iterator it = neg_occs.mk_iterator(); while (!it.at_end()) { clause & c = it.curr(); + if (c.is_blocked()) continue; m_counter -= c.size(); unsigned sz = c.size(); unsigned i; @@ -1300,11 +1326,11 @@ namespace sat { elim(s.num_vars()); } - unsigned simplifier::get_num_non_learned_bin(literal l) const { + unsigned simplifier::get_num_unblocked_bin(literal l) const { unsigned r = 0; watch_list const & wlist = get_wlist(~l); for (auto & w : wlist) { - if (w.is_binary_non_learned_clause()) + if (w.is_binary_unblocked_clause()) r++; } return r; @@ -1315,8 +1341,8 @@ namespace sat { literal neg_l(v, true); unsigned num_pos = m_use_list.get(pos_l).size(); unsigned num_neg = m_use_list.get(neg_l).size(); - unsigned num_bin_pos = get_num_non_learned_bin(pos_l); - unsigned num_bin_neg = get_num_non_learned_bin(neg_l); + unsigned num_bin_pos = get_num_unblocked_bin(pos_l); + unsigned num_bin_neg = get_num_unblocked_bin(neg_l); unsigned cost = 2 * num_pos * num_neg + num_pos * num_bin_neg + num_neg * num_bin_pos; CTRACE("elim_vars_detail", cost == 0, tout << v << " num_pos: " << num_pos << " num_neg: " << num_neg << " num_bin_pos: " << num_bin_pos << " num_bin_neg: " << num_bin_neg << " cost: " << cost << "\n";); @@ -1353,20 +1379,32 @@ namespace sat { /** \brief Collect clauses and binary clauses containing l. */ - void simplifier::collect_clauses(literal l, clause_wrapper_vector & r) { + void simplifier::collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked) { clause_use_list const & cs = m_use_list.get(l); clause_use_list::iterator it = cs.mk_iterator(); while (!it.at_end()) { - r.push_back(clause_wrapper(it.curr())); - SASSERT(r.back().size() == it.curr().size()); + if (!it.curr().is_blocked() || include_blocked) { + r.push_back(clause_wrapper(it.curr())); + SASSERT(r.back().size() == it.curr().size()); + } it.next(); } watch_list & wlist = get_wlist(~l); - for (auto & w : wlist) { - if (w.is_binary_non_learned_clause()) { - r.push_back(clause_wrapper(l, w.get_literal())); - SASSERT(r.back().size() == 2); + if (include_blocked) { + for (auto & w : wlist) { + if (w.is_binary_non_learned_clause2()) { + r.push_back(clause_wrapper(l, w.get_literal())); + SASSERT(r.back().size() == 2); + } + } + } + else { + for (auto & w : wlist) { + if (w.is_binary_unblocked_clause()) { + r.push_back(clause_wrapper(l, w.get_literal())); + SASSERT(r.back().size() == 2); + } } } } @@ -1503,12 +1541,12 @@ namespace sat { literal pos_l(v, false); literal neg_l(v, true); - unsigned num_bin_pos = get_num_non_learned_bin(pos_l); - unsigned num_bin_neg = get_num_non_learned_bin(neg_l); + unsigned num_bin_pos = get_num_unblocked_bin(pos_l); + unsigned num_bin_neg = get_num_unblocked_bin(neg_l); clause_use_list & pos_occs = m_use_list.get(pos_l); clause_use_list & neg_occs = m_use_list.get(neg_l); - unsigned num_pos = pos_occs.size() + num_bin_pos; - unsigned num_neg = neg_occs.size() + num_bin_neg; + unsigned num_pos = pos_occs.non_blocked_size() + num_bin_pos; + unsigned num_neg = neg_occs.non_blocked_size() + num_bin_neg; TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";); @@ -1520,7 +1558,8 @@ namespace sat { { clause_use_list::iterator it = pos_occs.mk_iterator(); while (!it.at_end()) { - before_lits += it.curr().size(); + if (!it.curr().is_blocked()) + before_lits += it.curr().size(); it.next(); } } @@ -1528,7 +1567,8 @@ namespace sat { { clause_use_list::iterator it2 = neg_occs.mk_iterator(); while (!it2.at_end()) { - before_lits += it2.curr().size(); + if (!it2.curr().is_blocked()) + before_lits += it2.curr().size(); it2.next(); } } @@ -1546,8 +1586,8 @@ namespace sat { m_pos_cls.reset(); m_neg_cls.reset(); - collect_clauses(pos_l, m_pos_cls); - collect_clauses(neg_l, m_neg_cls); + collect_clauses(pos_l, m_pos_cls, false); + collect_clauses(neg_l, m_neg_cls, false); TRACE("resolution_detail", tout << "collecting number of after_clauses\n";); @@ -1676,6 +1716,7 @@ namespace sat { void simplifier::updt_params(params_ref const & _p) { sat_simplifier_params p(_p); + m_elim_covered_clauses = p.elim_covered_clauses(); m_elim_blocked_clauses = p.elim_blocked_clauses(); m_elim_blocked_clauses_at = p.elim_blocked_clauses_at(); m_blocked_clause_limit = p.blocked_clause_limit(); @@ -1693,6 +1734,7 @@ namespace sat { m_subsumption = p.subsumption(); m_subsumption_limit = p.subsumption_limit(); m_elim_vars = p.elim_vars(); + m_elim_vars_bdd = p.elim_vars_bdd(); } void simplifier::collect_param_descrs(param_descrs & r) { diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index fdfabb513..d58babfef 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -40,6 +40,8 @@ namespace sat { public: void init(unsigned num_vars); void insert(clause & c); + void block(clause & c); + void unblock(clause & c); void erase(clause & c); void erase(clause & c, literal l); clause_use_list & get(literal l) { return m_use_list[l.index()]; } @@ -69,6 +71,7 @@ namespace sat { int m_elim_counter; // config + bool m_elim_covered_clauses; bool m_elim_blocked_clauses; unsigned m_elim_blocked_clauses_at; unsigned m_blocked_clause_limit; @@ -87,6 +90,7 @@ namespace sat { bool m_subsumption; unsigned m_subsumption_limit; bool m_elim_vars; + bool m_elim_vars_bdd; // stats unsigned m_num_blocked_clauses; @@ -119,6 +123,8 @@ namespace sat { void remove_clause_core(clause & c); void remove_clause(clause & c); void remove_clause(clause & c, literal l); + void block_clause(clause & c); + void unblock_clause(clause & c); void remove_bin_clause_half(literal l1, literal l2, bool learned); bool_var get_min_occ_var(clause const & c) const; @@ -157,10 +163,10 @@ namespace sat { struct blocked_clause_elim; void elim_blocked_clauses(); - unsigned get_num_non_learned_bin(literal l) const; + unsigned get_num_unblocked_bin(literal l) const; unsigned get_to_elim_cost(bool_var v) const; void order_vars_for_elim(bool_var_vector & r); - void collect_clauses(literal l, clause_wrapper_vector & r); + void collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked); clause_wrapper_vector m_pos_cls; clause_wrapper_vector m_neg_cls; literal_vector m_new_cls; diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index ff2944987..9a7812586 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -2,6 +2,7 @@ def_module_params(module_name='sat', class_name='sat_simplifier_params', export=True, params=(('elim_blocked_clauses', BOOL, False, 'eliminate blocked clauses'), + ('elim_covered_clauses', BOOL, False, 'eliminate covered clauses'), ('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), ('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'), ('resolution', BOOL, True, 'eliminate boolean variables using resolution'), @@ -16,5 +17,6 @@ def_module_params(module_name='sat', ('resolution.cls_cutoff1', UINT, 100000000, 'limit1 - total number of problems clauses for the second cutoff of Boolean variable elimination'), ('resolution.cls_cutoff2', UINT, 700000000, 'limit2 - total number of problems clauses for the second cutoff of Boolean variable elimination'), ('elim_vars', BOOL, True, 'enable variable elimination during simplification'), + ('elim_vars_bdd', BOOL, True, 'enable variable elimination using BDD recompilation during simplification'), ('subsumption', BOOL, True, 'eliminate subsumed clauses'), ('subsumption.limit', UINT, 100000000, 'approx. maximum number of literals visited during subsumption (and subsumption resolution)'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index ca1fc7801..1b117b0a7 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -117,7 +117,7 @@ namespace sat { assign(src.m_trail[i], justification()); } - // copy binary clauses + // copy binary clauses that are unblocked. { unsigned sz = src.m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { @@ -125,7 +125,7 @@ namespace sat { if (src.was_eliminated(l.var())) continue; watch_list const & wlist = src.m_watches[l_idx]; for (auto & wi : wlist) { - if (!wi.is_binary_non_learned_clause()) + if (!wi.is_binary_unblocked_clause()) continue; literal l2 = wi.get_literal(); if (l.index() > l2.index() || @@ -142,7 +142,10 @@ namespace sat { for (clause* c : src.m_clauses) { buffer.reset(); for (literal l : *c) buffer.push_back(l); - mk_clause_core(buffer); + clause* c1 = mk_clause_core(buffer); + if (c1 && c->is_blocked()) { + c1->block(); + } } // copy high quality lemmas for (clause* c : src.m_learned) { @@ -1558,8 +1561,8 @@ namespace sat { m_mc(m_model); TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); -#ifndef _EXTERNAL_RELEASE - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model\"\n";); +// #ifndef _EXTERNAL_RELEASE + IF_VERBOSE(1, verbose_stream() << "\"checking model\"\n";); if (!check_model(m_model)) throw solver_exception("check model failed"); @@ -1568,7 +1571,7 @@ namespace sat { if (!m_clone->check_model(m_model)) throw solver_exception("check model failed (for cloned solver)"); } -#endif +// #endif } bool solver::check_model(model const & m) const { @@ -3124,17 +3127,14 @@ namespace sat { for (unsigned l_idx = 0; l_idx < sz; l_idx++) { literal l = to_literal(l_idx); l.neg(); - watch_list const & wlist = m_watches[l_idx]; - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_clause()) + for (watched const& w : m_watches[l_idx]) { + if (!w.is_binary_clause()) continue; - if (!learned && it->is_learned()) + if (!learned && w.is_learned()) continue; - else if (learned && learned_only && !it->is_learned()) + else if (learned && learned_only && !w.is_learned()) continue; - literal l2 = it->get_literal(); + literal l2 = w.get_literal(); if (l.index() > l2.index()) continue; TRACE("cleanup_bug", tout << "collected: " << l << " " << l2 << "\n";); @@ -3168,13 +3168,10 @@ namespace sat { for (unsigned l_idx = 0; l_idx < sz; l_idx++) { literal l = to_literal(l_idx); l.neg(); - watch_list const & wlist = m_watches[l_idx]; - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_clause()) + for (watched const& w : m_watches[l_idx]) { + if (!w.is_binary_clause()) continue; - literal l2 = it->get_literal(); + literal l2 = w.get_literal(); if (l.index() > l2.index()) continue; out << "(" << l << " " << l2 << ")\n"; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 58d2824c7..2c5a04104 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -220,8 +220,8 @@ namespace sat { protected: void del_clause(clause & c); clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned); - void mk_clause_core(literal_vector const& lits) { mk_clause_core(lits.size(), lits.c_ptr()); } - void mk_clause_core(unsigned num_lits, literal * lits) { mk_clause_core(num_lits, lits, false); } + clause * mk_clause_core(literal_vector const& lits) { return mk_clause_core(lits.size(), lits.c_ptr()); } + clause * mk_clause_core(unsigned num_lits, literal * lits) { return mk_clause_core(num_lits, lits, false); } void mk_clause_core(literal l1, literal l2) { literal lits[2] = { l1, l2 }; mk_clause_core(2, lits); } void mk_bin_clause(literal l1, literal l2, bool learned); bool propagate_bin_clause(literal l1, literal l2); diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index d1333c314..f18e08999 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -50,7 +50,7 @@ namespace sat { SASSERT(is_binary_clause()); SASSERT(get_literal() == l); SASSERT(is_learned() == learned); - SASSERT(learned || is_binary_non_learned_clause()); + SASSERT(learned || is_binary_unblocked_clause()); } watched(literal l1, literal l2) { @@ -85,8 +85,15 @@ namespace sat { literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(static_cast(m_val1)); } void set_literal(literal l) { SASSERT(is_binary_clause()); m_val1 = l.to_uint(); } bool is_learned() const { SASSERT(is_binary_clause()); return (m_val2 >> 2) == 1; } - bool is_binary_non_learned_clause() const { return m_val2 == 0; } + + bool is_binary_unblocked_clause() const { return m_val2 == 0; } + bool is_binary_learned_clause() const { return is_binary_clause() && is_learned(); } + bool is_binary_non_learned_clause2() const { return is_binary_clause() && !is_learned(); } + void mark_not_learned() { SASSERT(is_learned()); m_val2 = static_cast(BINARY); SASSERT(!is_learned()); } + void set_blocked() { SASSERT(is_binary_clause()); SASSERT(!is_learned()); m_val2 |= (1 << 3); } + bool is_blocked() const { SASSERT(is_binary_clause()); return 0 != (m_val2 & (1 << 3)); } + void set_unblocked() { SASSERT(is_binary_clause()); SASSERT(is_blocked()); m_val2 &= ~(1u << 3u); } bool is_ternary_clause() const { return get_kind() == TERNARY; } literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast(m_val1)); } diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index c47da9b1f..50c542043 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -21,9 +21,9 @@ Revision History: #include #include "util/timeout.h" #include "util/rlimit.h" +#include "util/gparams.h" #include "sat/dimacs.h" #include "sat/sat_solver.h" -#include "util/gparams.h" extern bool g_display_statistics; static sat::solver * g_solver = 0; @@ -126,6 +126,42 @@ static void track_clauses(sat::solver const& src, } } +void verify_solution(char const * file_name) { + params_ref p = gparams::get_module("sat"); + p.set_bool("produce_models", true); + reslimit limit; + sat::solver solver(p, limit); + std::ifstream in(file_name); + if (in.bad() || in.fail()) { + std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; + exit(ERR_OPEN_FILE); + } + parse_dimacs(in, solver); + + sat::model const & m = g_solver->get_model(); + for (unsigned i = 1; i < m.size(); i++) { + sat::literal lit(i, false); + switch (m[i]) { + case l_false: lit.neg(); break; + case l_undef: break; + case l_true: break; + } + solver.mk_clause(1, &lit); + } + lbool r = solver.check(); + switch (r) { + case l_false: + std::cout << "model checking failed\n"; + break; + case l_true: + std::cout << "model validated\n"; + break; + default: + std::cout << "inconclusive model\n"; + break; + } +} + unsigned read_dimacs(char const * file_name) { g_start_time = clock(); register_on_timeout_proc(on_timeout); @@ -164,6 +200,7 @@ unsigned read_dimacs(char const * file_name) { switch (r) { case l_true: std::cout << "sat\n"; + if (file_name) verify_solution(file_name); display_model(*g_solver); break; case l_undef: From ee6cfb8eef7da46bcc1a2a8550bcdf7ec9b20f9a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Oct 2017 01:00:06 -0400 Subject: [PATCH 0296/1283] updates to simplifier Signed-off-by: Nikolaj Bjorner --- src/sat/sat_bdd.cpp | 2 +- src/sat/sat_elim_eqs.cpp | 1 + src/sat/sat_lookahead.cpp | 112 ++++---- src/sat/sat_lookahead.h | 17 +- src/sat/sat_model_converter.cpp | 6 +- src/sat/sat_simplifier.cpp | 424 ++++++++++++++++++------------ src/sat/sat_simplifier.h | 15 +- src/sat/sat_simplifier_params.pyg | 9 +- src/sat/sat_solver.cpp | 70 ++--- 9 files changed, 365 insertions(+), 291 deletions(-) diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 52714eae6..74af4bf5e 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -743,7 +743,7 @@ namespace sat { void bdd_manager::gc() { m_free_nodes.reset(); - IF_VERBOSE(3, verbose_stream() << "(bdd :gc " << m_nodes.size() << ")\n";); + IF_VERBOSE(13, verbose_stream() << "(bdd :gc " << m_nodes.size() << ")\n";); svector reachable(m_nodes.size(), false); for (unsigned i = m_bdd_stack.size(); i-- > 0; ) { reachable[m_bdd_stack[i]] = true; diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 7eb307f85..49b371104 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -98,6 +98,7 @@ namespace sat { // apply substitution for (i = 0; i < sz; i++) { c[i] = norm(roots, c[i]); + VERIFY(c[i] == norm(roots, c[i])); VERIFY(!m_solver.was_eliminated(c[i].var())); } std::sort(c.begin(), c.end()); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 4efbfd162..60594c0d4 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -204,7 +204,7 @@ namespace sat { void lookahead::pre_select() { - IF_VERBOSE(10, verbose_stream() << "freevars: " << m_freevars.size() << "\n";); + IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :freevars " << m_freevars.size() << ")\n";); m_lookahead.reset(); for (bool_var x : m_freevars) { // tree lookahead leaves literals fixed in lower truth levels literal l(x, false); @@ -1808,7 +1808,7 @@ namespace sat { scoped_level _sl(*this, dl_truth); SASSERT(get_level(m_trail.back()) == dl_truth); SASSERT(is_fixed(l)); - IF_VERBOSE(2, verbose_stream() << "double: " << l << " depth: " << m_trail_lim.size() << "\n";); + IF_VERBOSE(2, verbose_stream() << "(sat-lookahead :double " << l << " :depth " << m_trail_lim.size() << ")\n";); lookahead_backtrack(); assign(l); propagate(); @@ -2211,71 +2211,65 @@ namespace sat { m_s.propagate_core(false); m_s.m_simplifier(false); } + + if (select(0)) { + get_scc(); + if (!inconsistent()) { + normalize_parents(); + literal_vector roots; + bool_var_vector to_elim; + for (unsigned i = 0; i < m_num_vars; ++i) { + roots.push_back(literal(i, false)); + } + for (auto const& c : m_candidates) { + bool_var v = c.m_var; + literal q(v, false); + literal p = get_parent(q); + if (p != null_literal && p.var() != v && !m_s.is_external(v) && + !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { + to_elim.push_back(v); + roots[v] = p; + VERIFY(get_parent(p) == p); + VERIFY(get_parent(~p) == ~p); + } + } + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); + elim_eqs elim(m_s); + elim(roots, to_elim); + } + } m_lookahead.reset(); } - // - // there can be two sets of equivalence classes. - // example: - // a -> !b - // b -> !a - // c -> !a - // we pick as root the Boolean variable with the largest value. - // - literal lookahead::get_root(bool_var v) { - literal lit(v, false); - literal r1 = get_parent(lit); - literal r2 = get_parent(literal(r1.var(), false)); - CTRACE("sat", r1 != get_parent(literal(r2.var(), false)), - tout << r1 << " " << r2 << "\n";); - SASSERT(r1.var() == get_parent(literal(r2.var(), false)).var()); - if (r1.var() >= r2.var()) { - return r1; + void lookahead::normalize_parents() { + literal_vector roots; + for (unsigned i = 0; i < m_num_vars; ++i) { + literal lit(i, false); + roots.push_back(lit); + roots.push_back(~lit); + SASSERT(roots[lit.index()] == lit); } - else { - return r1.sign() ? ~r2 : r2; - } - } - - /** - \brief extract equivalence classes of variables and simplify clauses using these. - */ - void lookahead::scc() { - SASSERT(m_prefix == 0); - SASSERT(m_watches.empty()); - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); - if (inconsistent()) return; - inc_istamp(); - m_lookahead.reset(); - if (select(0)) { - // extract equivalences - get_scc(); - if (inconsistent()) return; - literal_vector roots; - bool_var_vector to_elim; - for (unsigned i = 0; i < m_num_vars; ++i) { - roots.push_back(literal(i, false)); - } - for (unsigned i = 0; i < m_candidates.size(); ++i) { - bool_var v = m_candidates[i].m_var; - literal p = get_root(v); - if (p != null_literal && p.var() != v && !m_s.is_external(v) && - !m_s.was_eliminated(v) && !m_s.was_eliminated(p.var())) { - to_elim.push_back(v); - roots[v] = p; - SASSERT(get_parent(p) == p); - set_parent(~p, ~p); - SASSERT(get_parent(~p) == ~p); + for (auto const& c : m_candidates) { + bool_var v = c.m_var; + literal p(v, false); + literal q = get_parent(p); + literal r = ~get_parent(~p); + if (q != r) { + if (q.var() < r.var()) { + roots[q.index()] = r; + } + else { + roots[r.index()] = q; } } - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); - elim_eqs elim(m_s); - elim(roots, to_elim); } - m_lookahead.reset(); + for (auto const& c : m_candidates) { + literal p(c.m_var, false); + literal q = roots[get_parent(p).index()]; + set_parent(p, q); + set_parent(~p, ~q); + } } std::ostream& lookahead::display_summary(std::ostream& out) const { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index e84213cfe..56d2e94a1 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -529,6 +529,8 @@ namespace sat { void init_config(); + void normalize_parents(); + public: lookahead(solver& s) : m_s(s), @@ -573,21 +575,6 @@ namespace sat { */ void simplify(); - // - // there can be two sets of equivalence classes. - // example: - // a -> !b - // b -> !a - // c -> !a - // we pick as root the Boolean variable with the largest value. - // - literal get_root(bool_var v); - - /** - \brief extract equivalence classes of variables and simplify clauses using these. - */ - void scc(); - std::ostream& display(std::ostream& out) const; std::ostream& display_summary(std::ostream& out) const; model const& get_model(); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 14443a2f7..eb60e209a 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -50,6 +50,7 @@ namespace sat { } if (!sat) { m[lit.var()] = lit.sign() ? l_false : l_true; + // if (lit.var() == 258007) std::cout << "flip " << lit << " " << m[lit.var()] << " @ " << i << " of " << c << " from overall size " << sz << "\n"; } } } @@ -69,10 +70,10 @@ namespace sat { for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause - if (!sat) { + elim_stack* s = it->m_elim_stack[index]; + if (!sat) { m[it->var()] = var_sign ? l_false : l_true; } - elim_stack* s = it->m_elim_stack[index]; if (s) { process_stack(m, clause, s->stack()); } @@ -94,6 +95,7 @@ namespace sat { else if (!sat && v != it->var() && m[v] == l_undef) { // clause can be satisfied by assigning v. m[v] = sign ? l_false : l_true; + // if (v == 258007) std::cout << "set undef " << v << " to " << m[v] << " in " << clause << "\n"; sat = true; } } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b0ef9e3e9..3ccd183c2 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -121,12 +121,13 @@ namespace sat { } inline void simplifier::block_clause(clause & c) { -#if 1 - remove_clause(c); -#else - c.block(); - m_use_list.block(c); -#endif + if (m_retain_blocked_clauses) { + c.block(); + m_use_list.block(c); + } + else { + remove_clause(c); + } } inline void simplifier::unblock_clause(clause & c) { @@ -135,9 +136,21 @@ namespace sat { } inline void simplifier::remove_bin_clause_half(literal l1, literal l2, bool learned) { - SASSERT(s.get_wlist(~l1).contains(watched(l2, learned))); - s.get_wlist(~l1).erase(watched(l2, learned)); + SASSERT(get_wlist(~l1).contains(watched(l2, learned))); + get_wlist(~l1).erase(watched(l2, learned)); m_sub_bin_todo.erase(bin_clause(l1, l2, learned)); + m_sub_bin_todo.erase(bin_clause(l2, l1, learned)); + } + + inline void simplifier::block_bin_clause_half(literal l1, literal l2) { + SASSERT(get_wlist(~l1).contains(watched(l2, false))); + for (watched & w : get_wlist(~l1)) { + if (w.get_literal() == l2) { + w.set_blocked(); + break; + } + } + m_sub_bin_todo.erase(bin_clause(l1, l2, false)); } void simplifier::init_visited() { @@ -173,7 +186,7 @@ namespace sat { void simplifier::operator()(bool learned) { if (s.inconsistent()) return; - if (!m_subsumption && !m_elim_blocked_clauses && !m_resolution) + if (!m_subsumption && !bce_enabled() && !bca_enabled() && !elim_vars_enabled()) return; // solver::scoped_disable_checkpoint _scoped_disable_checkpoint(s); @@ -195,7 +208,7 @@ namespace sat { } register_clauses(s.m_clauses); - if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) + if (!learned && (bce_enabled() || bca_enabled())) elim_blocked_clauses(); if (!learned) @@ -205,8 +218,6 @@ namespace sat { m_elim_counter = m_res_limit; m_old_num_elim_vars = m_num_elim_vars; - // scoped_finalize _scoped_finalize(*this); - for (bool_var v = 0; v < s.num_vars(); ++v) { if (!s.m_eliminated[v] && !is_external(v)) { insert_elim_todo(v); @@ -218,7 +229,7 @@ namespace sat { subsume(); if (s.inconsistent()) return; - if (!learned && m_resolution && s.m_config.m_num_threads == 1) + if (!learned && elim_vars_enabled() && s.m_config.m_num_threads == 1) elim_vars(); if (s.inconsistent()) return; @@ -743,11 +754,9 @@ namespace sat { } void simplifier::mark_as_not_learned_core(watch_list & wlist, literal l2) { - watch_list::iterator it = wlist.begin(); - watch_list::iterator end = wlist.end(); - for (; it != end; ++it) { - if (it->is_binary_clause() && it->get_literal() == l2 && it->is_learned()) { - it->mark_not_learned(); + for (watched & w : wlist) { + if (w.is_binary_clause() && w.get_literal() == l2 && w.is_learned()) { + w.mark_not_learned(); return; } } @@ -774,34 +783,31 @@ namespace sat { \brief Eliminate duplicated binary clauses. */ void simplifier::elim_dup_bins() { - vector::iterator it = s.m_watches.begin(); - vector::iterator end = s.m_watches.end(); #ifdef _TRACE unsigned l_idx = 0; #endif unsigned elim = 0; - for (; it != end; ++it) { + for (watch_list & wlist : s.m_watches) { checkpoint(); - watch_list & wlist = *it; std::stable_sort(wlist.begin(), wlist.end(), bin_lt()); literal last_lit = null_literal; - watch_list::iterator it2 = wlist.begin(); - watch_list::iterator itprev = it2; - watch_list::iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - if (!it2->is_binary_clause()) { - *itprev = *it2; + watch_list::iterator it = wlist.begin(); + watch_list::iterator itprev = it; + watch_list::iterator end = wlist.end(); + for (; it != end; ++it) { + if (!it->is_binary_clause()) { + *itprev = *it; itprev++; continue; } - if (it2->get_literal() == last_lit) { + if (it->get_literal() == last_lit) { TRACE("subsumption", tout << "eliminating: " << ~to_literal(l_idx) - << " " << it2->get_literal() << "\n";); + << " " << it->get_literal() << "\n";); elim++; } else { - last_lit = it2->get_literal(); - *itprev = *it2; + last_lit = it->get_literal(); + *itprev = *it; itprev++; } } @@ -944,6 +950,11 @@ namespace sat { queue m_queue; clause_vector m_to_remove; + literal_vector m_covered_clause; + literal_vector m_intersection; + sat::model_converter::elim_stackv m_elim_stack; + unsigned m_ala_qhead; + blocked_clause_elim(simplifier & _s, unsigned limit, model_converter & _mc, use_list & l, vector & wlist): s(_s), @@ -960,7 +971,25 @@ namespace sat { return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v); } - void insert_queue(unsigned num_vars) { + void operator()() { + if (s.bce_enabled()) + block_clauses(); + if (s.m_cce) + cce(); + if (s.m_bca) + bca(); + } + + void block_clauses() { + insert_queue(); + while (!m_queue.empty() && m_counter >= 0) { + s.checkpoint(); + process(m_queue.next()); + } + } + + void insert_queue() { + unsigned num_vars = s.s.num_vars(); for (bool_var v = 0; v < num_vars; v++) { if (process_var(v)) { insert(literal(v, false)); @@ -969,96 +998,82 @@ namespace sat { } } - void block_clauses(unsigned num_vars) { - insert_queue(num_vars); - while (!m_queue.empty()) { - s.checkpoint(); - if (m_counter < 0) - return; - literal l = m_queue.next(); - process(l); - } - } - - void operator()(unsigned num_vars) { - block_clauses(num_vars); - if (s.m_elim_covered_clauses) - cce(); - } - void process(literal l) { TRACE("blocked_clause", tout << "processing: " << l << "\n";); model_converter::entry * new_entry = 0; if (!process_var(l.var())) { return; } + process_clauses(l); + process_binary(l); + } - literal blocked = null_literal; - m_to_remove.reset(); - { - clause_use_list & occs = s.m_use_list.get(l); - clause_use_list::iterator it = occs.mk_iterator(); - while (!it.at_end()) { - clause & c = it.curr(); - if (c.is_blocked()) continue; - m_counter -= c.size(); - SASSERT(c.contains(l)); - s.mark_all_but(c, l); - if (all_tautology(l)) { - block_clause(c, l, new_entry); - s.m_num_blocked_clauses++; - } - s.unmark_all(c); - it.next(); + void process_binary(literal l) { + model_converter::entry* new_entry = 0; + watch_list & wlist = s.get_wlist(~l); + m_counter -= wlist.size(); + watch_list::iterator it = wlist.begin(); + watch_list::iterator it2 = it; + watch_list::iterator end = wlist.end(); + +#define INC() if (!s.m_retain_blocked_clauses) { *it2 = *it; it2++; } + + for (; it != end; ++it) { + if (!it->is_binary_clause() || it->is_blocked()) { + INC(); + continue; } + literal l2 = it->get_literal(); + s.mark_visited(l2); + if (all_tautology(l)) { + block_binary(it, l, new_entry); + s.m_num_blocked_clauses++; + } + else { + INC(); + } + s.unmark_visited(l2); + } + if (!s.m_retain_blocked_clauses) wlist.set_end(it2); + } + + void process_clauses(literal l) { + model_converter::entry* new_entry = 0; + m_to_remove.reset(); + clause_use_list & occs = s.m_use_list.get(l); + clause_use_list::iterator it = occs.mk_iterator(); + while (!it.at_end()) { + clause & c = it.curr(); + if (c.is_blocked()) continue; + m_counter -= c.size(); + SASSERT(c.contains(l)); + s.mark_all_but(c, l); + if (all_tautology(l)) { + block_clause(c, l, new_entry); + s.m_num_blocked_clauses++; + } + s.unmark_all(c); + it.next(); } for (clause* c : m_to_remove) s.block_clause(*c); - - { - watch_list & wlist = s.get_wlist(~l); - m_counter -= wlist.size(); - watch_list::iterator it = wlist.begin(); - watch_list::iterator it2 = it; - watch_list::iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_clause() || it->is_blocked()) { - *it2 = *it; - it2++; - continue; - } - literal l2 = it->get_literal(); - s.mark_visited(l2); - if (all_tautology(l)) { - block_binary(it, l, new_entry); - s.m_num_blocked_clauses++; - } - else if (s.m_elim_covered_clauses && cce(l, l2, blocked)) { - block_covered_binary(it, l, blocked); - s.m_num_covered_clauses++; - } - else { - *it2 = *it; - it2++; - } - s.unmark_visited(l2); - } - wlist.set_end(it2); - } } // // Resolve intersection // Find literals that are in the intersection of all resolvents with l. // - bool ri(literal l, literal_vector& inter) { + bool resolution_intersection(literal l, literal_vector& inter, bool adding) { if (!process_var(l.var())) return false; bool first = true; for (watched & w : s.get_wlist(l)) { - if (w.is_binary_unblocked_clause()) { + // when adding a blocked clause, then all non-learned clauses have to be considered for the + // resolution intersection. + bool process_bin = adding ? (w.is_binary_clause() && !w.is_learned()) : w.is_binary_unblocked_clause(); + if (process_bin) { literal lit = w.get_literal(); if (s.is_marked(~lit) && lit != ~l) continue; - if (!first) { + if (!first || s.is_marked(lit)) { inter.reset(); return false; } @@ -1081,9 +1096,10 @@ namespace sat { if (!tautology) { if (first) { for (literal lit : c) { - if (lit != ~l) inter.push_back(lit); + if (lit != ~l && !s.is_marked(lit)) inter.push_back(lit); } first = false; + if (inter.empty()) return false; } else { unsigned j = 0; @@ -1099,11 +1115,6 @@ namespace sat { return first; } - literal_vector m_covered_clause; - literal_vector m_intersection; - sat::model_converter::elim_stackv m_elim_stack; - unsigned m_ala_qhead; - /* * C \/ l l \/ lit * ------------------- @@ -1113,10 +1124,9 @@ namespace sat { for (; m_ala_qhead < m_covered_clause.size(); ++m_ala_qhead) { literal l = m_covered_clause[m_ala_qhead]; for (watched & w : s.get_wlist(~l)) { - if (w.is_binary_clause()) { + if (w.is_binary_unblocked_clause()) { literal lit = w.get_literal(); if (!s.is_marked(lit) && !s.is_marked(~lit)) { - //std::cout << "ALA " << ~lit << "\n"; m_covered_clause.push_back(~lit); s.mark_visited(~lit); } @@ -1136,7 +1146,7 @@ namespace sat { bool add_cla(literal& blocked) { for (unsigned i = 0; i < m_covered_clause.size(); ++i) { m_intersection.reset(); - if (ri(m_covered_clause[i], m_intersection)) { + if (resolution_intersection(m_covered_clause[i], m_intersection, false)) { blocked = m_covered_clause[i]; return true; } @@ -1166,18 +1176,14 @@ namespace sat { is_tautology = add_cla(blocked); } while (m_covered_clause.size() > sz && !is_tautology); -#if 1 - break; -#else - // check for soundness? - if (is_tautology) break; - sz = m_covered_clause.size(); - add_ala(); -#endif + if (s.m_acce && !is_tautology) { + sz = m_covered_clause.size(); + add_ala(); + } } - while (m_covered_clause.size() > sz); + while (m_covered_clause.size() > sz && !is_tautology); for (literal l : m_covered_clause) s.unmark_visited(l); - if (is_tautology) std::cout << "taut: " << num_iterations << " " << m_covered_clause.size() << " " << m_elim_stack.size() << "\n"; + // if (is_tautology) std::cout << "taut: " << num_iterations << " " << m_covered_clause.size() << " " << m_elim_stack.size() << "\n"; return is_tautology; } @@ -1196,8 +1202,47 @@ namespace sat { m_covered_clause.push_back(l2); return cla(blocked); } - + void cce() { + cce_clauses(); + cce_binary(); + } + + void cce_binary() { + insert_queue(); + while (!m_queue.empty() && m_counter >= 0) { + s.checkpoint(); + process_cce_binary(m_queue.next()); + } + } + + void process_cce_binary(literal l) { + literal blocked = null_literal; + watch_list & wlist = s.get_wlist(~l); + m_counter -= wlist.size(); + watch_list::iterator it = wlist.begin(); + watch_list::iterator it2 = it; + watch_list::iterator end = wlist.end(); + + for (; it != end; ++it) { + if (!it->is_binary_clause() || it->is_blocked()) { + INC(); + continue; + } + literal l2 = it->get_literal(); + if (cce(l, l2, blocked)) { + block_covered_binary(it, l, blocked); + s.m_num_covered_clauses++; + } + else { + INC(); + } + } + if (!s.m_retain_blocked_clauses) wlist.set_end(it2); + } + + + void cce_clauses() { m_to_remove.reset(); literal blocked; for (clause* cp : s.s.m_clauses) { @@ -1237,15 +1282,21 @@ namespace sat { mc.insert(*new_entry, m_covered_clause, m_elim_stack); } - void prepare_block_binary(watch_list::iterator it, literal l, literal blocked, model_converter::entry *& new_entry) { - if (new_entry == 0) + void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry) { + if (new_entry == 0) new_entry = &(mc.mk(model_converter::BLOCK_LIT, blocked.var())); literal l2 = it->get_literal(); - TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l << "\n";); - s.remove_bin_clause_half(l2, l, it->is_learned()); + TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); + if (s.m_retain_blocked_clauses && !it->is_learned()) { + s.block_bin_clause_half(l2, l1); + s.block_bin_clause_half(l1, l2); + } + else { + s.remove_bin_clause_half(l2, l1, it->is_learned()); + } m_queue.decreased(~l2); } - + void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { prepare_block_binary(it, l, l, new_entry); mc.insert(*new_entry, l, it->get_literal()); @@ -1257,6 +1308,47 @@ namespace sat { mc.insert(*new_entry, m_covered_clause, m_elim_stack); } + void bca() { + insert_queue(); + while (!m_queue.empty() && m_counter >= 0) { + s.checkpoint(); + bca(m_queue.next()); + } + } + + /* + \brief blocked binary clause addition for literal l + Let RI be the resolution intersection with l, e.g, RI are the literals + that are in all clauses of the form ~l \/ C. + If RI is non-empty, then let l' be a literal in RI. + Then the following binary clause is blocked: l \/ ~l' + */ + void bca(literal l) { + m_intersection.reset(); + if (resolution_intersection(l, m_intersection, true)) { + // this literal is pure. + return; + } + for (literal l2 : m_intersection) { + l2.neg(); + bool found = false; + for (watched w : s.get_wlist(~l)) { + found = w.is_binary_clause() && l2 == w.get_literal(); + if (found) break; + } + if (!found) { + IF_VERBOSE(100, verbose_stream() << "bca " << l << " " << l2 << "\n";); + watched w(l2, false); + w.set_blocked(); + s.get_wlist(~l).push_back(w); + w = watched(l, false); + w.set_blocked(); + s.get_wlist(~l2).push_back(w); + ++s.m_num_bca; + } + } + } + bool all_tautology(literal l) { watch_list & wlist = s.get_wlist(l); m_counter -= wlist.size(); @@ -1323,7 +1415,7 @@ namespace sat { TRACE("blocked_clause_bug", tout << "trail: " << s.m_trail.size() << "\n"; s.display_watches(tout); s.display(tout);); blocked_cls_report rpt(*this); blocked_clause_elim elim(*this, m_blocked_clause_limit, s.m_mc, m_use_list, s.m_watches); - elim(s.num_vars()); + elim(); } unsigned simplifier::get_num_unblocked_bin(literal l) const { @@ -1422,18 +1514,18 @@ namespace sat { SASSERT(c2.contains(~l)); bool res = true; m_elim_counter -= c1.size() + c2.size(); - unsigned sz = c1.size(); - for (unsigned i = 0; i < sz; ++i) { - literal l2 = c1[i]; - if (l == l2) + unsigned sz1 = c1.size(); + for (unsigned i = 0; i < sz1; ++i) { + literal l1 = c1[i]; + if (l == l1) continue; - m_visited[l2.index()] = true; - r.push_back(l2); + m_visited[l1.index()] = true; + r.push_back(l1); } literal not_l = ~l; - sz = c2.size(); - for (unsigned i = 0; i < sz; ++i) { + unsigned sz2 = c2.size(); + for (unsigned i = 0; i < sz2; ++i) { literal l2 = c2[i]; if (not_l == l2) continue; @@ -1445,10 +1537,9 @@ namespace sat { r.push_back(l2); } - sz = c1.size(); - for (unsigned i = 0; i < sz; ++i) { - literal l2 = c1[i]; - m_visited[l2.index()] = false; + for (unsigned i = 0; i < sz1; ++i) { + literal l1 = c1[i]; + m_visited[l1.index()] = false; } return res; } @@ -1461,31 +1552,27 @@ namespace sat { } void simplifier::add_non_learned_binary_clause(literal l1, literal l2) { - watch_list & wlist1 = s.m_watches[(~l1).index()]; - watch_list & wlist2 = s.m_watches[(~l2).index()]; - watch_list::iterator it1 = wlist1.begin(); - watch_list::iterator end1 = wlist1.end(); - for (; it1 != end1; ++it1) { - if (it1->is_binary_clause() && it1->get_literal() == l2) { - *it1 = watched(l2, false); - watch_list::iterator it2 = wlist2.begin(); - watch_list::iterator end2 = wlist2.end(); - for (; it2 != end2; ++it2) { - if (it2->is_binary_clause() && it2->get_literal() == l1) { - *it2 = watched(l1, false); - break; - } - } - CTRACE("resolve_bug", it2 == end2, - tout << ~l1 << " -> "; - display_watch_list(tout, s.m_cls_allocator, wlist1); tout << "\n" << ~l2 << " -> "; - display_watch_list(tout, s.m_cls_allocator, wlist2); tout << "\n";); - SASSERT(it2 != end2); - return; + watch_list & wlist1 = get_wlist(~l1); + watch_list & wlist2 = get_wlist(~l2); + bool found = false; + for (watched& w : wlist1) { + if (w.is_binary_clause() && w.get_literal() == l2) { + if (w.is_learned()) w.mark_not_learned(); + found = true; + break; } } - wlist1.push_back(watched(l2, false)); - wlist2.push_back(watched(l1, false)); + if (!found) wlist1.push_back(watched(l2, false)); + + found = false; + for (watched& w : wlist2) { + if (w.is_binary_clause() && w.get_literal() == l1) { + if (w.is_learned()) w.mark_not_learned(); + found = true; + break; + } + } + if (!found) wlist2.push_back(watched(l1, false)); } /** @@ -1692,7 +1779,7 @@ namespace sat { }; void simplifier::elim_vars() { - if (!m_elim_vars) return; + if (!elim_vars_enabled()) return; elim_var_report rpt(*this); bool_var_vector vars; order_vars_for_elim(vars); @@ -1704,7 +1791,7 @@ namespace sat { if (try_eliminate(v)) { m_num_elim_vars++; } - else if (elim_bdd(v)) { + else if (elim_vars_bdd_enabled() && elim_bdd(v)) { m_num_elim_vars++; } } @@ -1716,11 +1803,13 @@ namespace sat { void simplifier::updt_params(params_ref const & _p) { sat_simplifier_params p(_p); - m_elim_covered_clauses = p.elim_covered_clauses(); + m_cce = p.cce(); + m_acce = p.acce(); + m_bca = p.bca(); m_elim_blocked_clauses = p.elim_blocked_clauses(); m_elim_blocked_clauses_at = p.elim_blocked_clauses_at(); + m_retain_blocked_clauses = p.retain_blocked_clauses(); m_blocked_clause_limit = p.blocked_clause_limit(); - m_resolution = p.resolution(); m_res_limit = p.resolution_limit(); m_res_occ_cutoff = p.resolution_occ_cutoff(); m_res_occ_cutoff1 = p.resolution_occ_cutoff_range1(); @@ -1735,6 +1824,7 @@ namespace sat { m_subsumption_limit = p.subsumption_limit(); m_elim_vars = p.elim_vars(); m_elim_vars_bdd = p.elim_vars_bdd(); + m_elim_vars_bdd_delay = p.elim_vars_bdd_delay(); } void simplifier::collect_param_descrs(param_descrs & r) { @@ -1747,6 +1837,7 @@ namespace sat { st.update("elim literals", m_num_elim_lits); st.update("elim blocked clauses", m_num_blocked_clauses); st.update("elim covered clauses", m_num_covered_clauses); + st.update("blocked clauses added", m_num_bca); } void simplifier::reset_statistics() { @@ -1756,5 +1847,6 @@ namespace sat { m_num_sub_res = 0; m_num_elim_lits = 0; m_num_elim_vars = 0; + m_num_bca = 0; } }; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index d58babfef..c75e45d79 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -71,9 +71,12 @@ namespace sat { int m_elim_counter; // config - bool m_elim_covered_clauses; + bool m_cce; // covered clause elimination + bool m_acce; // cce with asymetric literal addition + bool m_bca; // blocked (binary) clause addition. bool m_elim_blocked_clauses; unsigned m_elim_blocked_clauses_at; + bool m_retain_blocked_clauses; unsigned m_blocked_clause_limit; bool m_resolution; unsigned m_res_limit; @@ -91,6 +94,7 @@ namespace sat { unsigned m_subsumption_limit; bool m_elim_vars; bool m_elim_vars_bdd; + unsigned m_elim_vars_bdd_delay; // stats unsigned m_num_blocked_clauses; @@ -99,6 +103,7 @@ namespace sat { unsigned m_num_elim_vars; unsigned m_num_sub_res; unsigned m_num_elim_lits; + unsigned m_num_bca; bool m_learned_in_use_lists; unsigned m_old_num_elim_vars; @@ -124,6 +129,7 @@ namespace sat { void remove_clause(clause & c); void remove_clause(clause & c, literal l); void block_clause(clause & c); + void block_bin_clause_half(literal l1, literal l2); void unblock_clause(clause & c); void remove_bin_clause_half(literal l1, literal l2, bool learned); @@ -163,6 +169,13 @@ namespace sat { struct blocked_clause_elim; void elim_blocked_clauses(); + bool bce_enabled() const { return m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled(); } + bool acce_enabled() const { return m_acce; } + bool cce_enabled() const { return m_cce || acce_enabled(); } + bool bca_enabled() const { return m_bca; } + bool elim_vars_bdd_enabled() const { return m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay; } + bool elim_vars_enabled() const { return m_elim_vars; } + unsigned get_num_unblocked_bin(literal l) const; unsigned get_to_elim_cost(bool_var v) const; void order_vars_for_elim(bool_var_vector & r); diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index 9a7812586..6528e6699 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -2,10 +2,12 @@ def_module_params(module_name='sat', class_name='sat_simplifier_params', export=True, params=(('elim_blocked_clauses', BOOL, False, 'eliminate blocked clauses'), - ('elim_covered_clauses', BOOL, False, 'eliminate covered clauses'), + ('cce', BOOL, False, 'eliminate covered clauses'), + ('acce', BOOL, False, 'eliminate covered clauses using asymmetric added literals'), ('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), + ('bca', BOOL, False, 'blocked clause addition - add blocked binary clauses'), + ('retain_blocked_clauses', BOOL, False, 'retain blocked clauses for propagation, hide them from variable elimination'), ('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'), - ('resolution', BOOL, True, 'eliminate boolean variables using resolution'), ('resolution.limit', UINT, 500000000, 'approx. maximum number of literals visited during variable elimination'), ('resolution.occ_cutoff', UINT, 10, 'first cutoff (on number of positive/negative occurrences) for Boolean variable elimination'), ('resolution.occ_cutoff_range1', UINT, 8, 'second cutoff (number of positive/negative occurrences) for Boolean variable elimination, for problems containing less than res_cls_cutoff1 clauses'), @@ -16,7 +18,8 @@ def_module_params(module_name='sat', ('resolution.lit_cutoff_range3', UINT, 300, 'second cutoff (total number of literals) for Boolean variable elimination, for problems containing more than res_cls_cutoff2'), ('resolution.cls_cutoff1', UINT, 100000000, 'limit1 - total number of problems clauses for the second cutoff of Boolean variable elimination'), ('resolution.cls_cutoff2', UINT, 700000000, 'limit2 - total number of problems clauses for the second cutoff of Boolean variable elimination'), - ('elim_vars', BOOL, True, 'enable variable elimination during simplification'), + ('elim_vars', BOOL, True, 'enable variable elimination using resolution during simplification'), ('elim_vars_bdd', BOOL, True, 'enable variable elimination using BDD recompilation during simplification'), + ('elim_vars_bdd_delay', UINT, 3, 'delay elimination of variables using BDDs until after simplification round'), ('subsumption', BOOL, True, 'eliminate subsumed clauses'), ('subsumption.limit', UINT, 100000000, 'approx. maximum number of literals visited during subsumption (and subsumption resolution)'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1b117b0a7..5db9d44c6 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1468,19 +1468,9 @@ namespace sat { if (m_config.m_lookahead_simplify) { - { - lookahead lh(*this); - lh.simplify(); - lh.collect_statistics(m_aux_stats); - } -#if 0 - // Buggy - { - lookahead lh(*this); - lh.scc(); - lh.collect_statistics(m_aux_stats); - } -#endif + lookahead lh(*this); + lh.simplify(); + lh.collect_statistics(m_aux_stats); } @@ -1562,7 +1552,7 @@ namespace sat { TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); // #ifndef _EXTERNAL_RELEASE - IF_VERBOSE(1, verbose_stream() << "\"checking model\"\n";); + IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";); if (!check_model(m_model)) throw solver_exception("check model failed"); @@ -1576,48 +1566,40 @@ namespace sat { bool solver::check_model(model const & m) const { bool ok = true; - clause_vector const * vs[2] = { &m_clauses, &m_learned }; - for (unsigned i = 0; i < 2; i++) { - clause_vector const & cs = *(vs[i]); - clause_vector::const_iterator it = cs.begin(); - clause_vector::const_iterator end = cs.end(); - for (; it != end; ++it) { - clause const & c = *(*it); - if (!c.satisfied_by(m)) { - TRACE("sat", tout << "failed: " << c << "\n"; - tout << "assumptions: " << m_assumptions << "\n"; - tout << "trail: " << m_trail << "\n"; - tout << "model: " << m << "\n"; - m_mc.display(tout); - ); - ok = false; - } + for (clause const* cp : m_clauses) { + clause const & c = *cp; + if (!c.satisfied_by(m) && !c.is_blocked()) { + IF_VERBOSE(0, verbose_stream() << "model check failed: " << c << "\n";); + TRACE("sat", tout << "failed: " << c << "\n"; + tout << "assumptions: " << m_assumptions << "\n"; + tout << "trail: " << m_trail << "\n"; + tout << "model: " << m << "\n"; + m_mc.display(tout); + ); + ok = false; } } - vector::const_iterator it = m_watches.begin(); - vector::const_iterator end = m_watches.end(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { + unsigned l_idx = 0; + for (watch_list const& wlist : m_watches) { literal l = ~to_literal(l_idx); if (value_at(l, m) != l_true) { - watch_list const & wlist = *it; - watch_list::const_iterator it2 = wlist.begin(); - watch_list::const_iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - if (!it2->is_binary_clause()) + for (watched const& w : wlist) { + if (!w.is_binary_unblocked_clause()) continue; - literal l2 = it2->get_literal(); + literal l2 = w.get_literal(); if (value_at(l2, m) != l_true) { - TRACE("sat", tout << "failed binary: " << l << " " << l2 << " learned: " << it2->is_learned() << "\n"; - m_mc.display(tout);); + IF_VERBOSE(0, verbose_stream() << "failed binary: " << l << " " << l2 << " " << "\n";); + TRACE("sat", m_mc.display(tout << "failed binary: " << l << " " << l2 << "\n");); ok = false; } } } + ++l_idx; } - for (unsigned i = 0; i < m_assumptions.size(); ++i) { - if (value_at(m_assumptions[i], m) != l_true) { + for (literal l : m_assumptions) { + if (value_at(l, m) != l_true) { TRACE("sat", - tout << m_assumptions[i] << " does not model check\n"; + tout << l << " does not model check\n"; tout << "trail: " << m_trail << "\n"; tout << "model: " << m << "\n"; m_mc.display(tout); From 63545c1e7b668220796c02c22da93fd67a3ef83b Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Mon, 23 Oct 2017 12:51:19 -0700 Subject: [PATCH 0297/1283] Fixes --- src/sat/sat_simplifier.cpp | 12 +++++------- src/sat/sat_simplifier_params.pyg | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3ccd183c2..a5f66dfd9 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -974,9 +974,9 @@ namespace sat { void operator()() { if (s.bce_enabled()) block_clauses(); - if (s.m_cce) + if (s.cce_enabled()) cce(); - if (s.m_bca) + if (s.bca_enabled()) bca(); } @@ -1176,7 +1176,7 @@ namespace sat { is_tautology = add_cla(blocked); } while (m_covered_clause.size() > sz && !is_tautology); - if (s.m_acce && !is_tautology) { + if (s.acce_enabled() && !is_tautology) { sz = m_covered_clause.size(); add_ala(); } @@ -1338,11 +1338,9 @@ namespace sat { } if (!found) { IF_VERBOSE(100, verbose_stream() << "bca " << l << " " << l2 << "\n";); - watched w(l2, false); - w.set_blocked(); + watched w(l2, true); s.get_wlist(~l).push_back(w); - w = watched(l, false); - w.set_blocked(); + w = watched(l, true); s.get_wlist(~l2).push_back(w); ++s.m_num_bca; } diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index 6528e6699..07088a60b 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -20,6 +20,6 @@ def_module_params(module_name='sat', ('resolution.cls_cutoff2', UINT, 700000000, 'limit2 - total number of problems clauses for the second cutoff of Boolean variable elimination'), ('elim_vars', BOOL, True, 'enable variable elimination using resolution during simplification'), ('elim_vars_bdd', BOOL, True, 'enable variable elimination using BDD recompilation during simplification'), - ('elim_vars_bdd_delay', UINT, 3, 'delay elimination of variables using BDDs until after simplification round'), + ('elim_vars_bdd_delay', UINT, 3, 'delay elimination of variables using BDDs until after simplification round'), ('subsumption', BOOL, True, 'eliminate subsumed clauses'), ('subsumption.limit', UINT, 100000000, 'approx. maximum number of literals visited during subsumption (and subsumption resolution)'))) From f6ee6894c7a11af4136aa1e9768d35727dd395c3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 09:59:23 -0700 Subject: [PATCH 0298/1283] fix bugs related to reading configuration flags Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3ccd183c2..369b3c7dd 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -974,9 +974,9 @@ namespace sat { void operator()() { if (s.bce_enabled()) block_clauses(); - if (s.m_cce) + if (s.cce_enabled()) cce(); - if (s.m_bca) + if (s.bca_enabled()) bca(); } @@ -1176,7 +1176,7 @@ namespace sat { is_tautology = add_cla(blocked); } while (m_covered_clause.size() > sz && !is_tautology); - if (s.m_acce && !is_tautology) { + if (s.acce_enabled() && !is_tautology) { sz = m_covered_clause.size(); add_ala(); } From 80041d7131cb61843cebe4045c2314a7e7eef55f Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Tue, 24 Oct 2017 13:51:27 -0700 Subject: [PATCH 0299/1283] Fixed infinite loop bugs in blocked clause retention. Added option to disable incremental sat solver --- src/sat/sat_params.pyg | 1 + src/sat/sat_simplifier.cpp | 6 +++--- src/sat/sat_solver/inc_sat_solver.cpp | 10 ++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index d803617f5..ada6f910b 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -32,6 +32,7 @@ def_module_params('sat', ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), ('xor.solver', BOOL, False, 'use xor solver'), + ('disable_incremental', BOOL, False, 'disable incremental solving. Allows stronger simplification, but solver cannot be re-used.'), ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index a5f66dfd9..9042587b7 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1044,6 +1044,7 @@ namespace sat { clause_use_list::iterator it = occs.mk_iterator(); while (!it.at_end()) { clause & c = it.curr(); + it.next(); if (c.is_blocked()) continue; m_counter -= c.size(); SASSERT(c.contains(l)); @@ -1053,7 +1054,6 @@ namespace sat { s.m_num_blocked_clauses++; } s.unmark_all(c); - it.next(); } for (clause* c : m_to_remove) s.block_clause(*c); @@ -1086,6 +1086,7 @@ namespace sat { while (!it.at_end()) { bool tautology = false; clause & c = it.curr(); + it.next(); if (c.is_blocked()) continue; for (literal lit : c) { if (s.is_marked(~lit) && lit != ~l) { @@ -1110,7 +1111,6 @@ namespace sat { if (j == 0) return false; } } - it.next(); } return first; } @@ -1360,6 +1360,7 @@ namespace sat { clause_use_list::iterator it = neg_occs.mk_iterator(); while (!it.at_end()) { clause & c = it.curr(); + it.next(); if (c.is_blocked()) continue; m_counter -= c.size(); unsigned sz = c.size(); @@ -1370,7 +1371,6 @@ namespace sat { } if (i == sz) return false; - it.next(); } if (s.s.m_ext) { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 53383a7c2..099dc701b 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -29,6 +29,7 @@ Notes: #include "tactic/bv/bit_blaster_tactic.h" #include "tactic/core/simplify_tactic.h" #include "sat/tactic/goal2sat.h" +#include "sat/tactic/sat_tactic.h" #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" #include "tactic/filter_model_converter.h" @@ -848,8 +849,13 @@ private: }; -solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p) { - return alloc(inc_sat_solver, m, p); +solver* mk_inc_sat_solver(ast_manager& m, params_ref const& _p) { + sat_params p(_p); + if (p.disable_incremental()) { + tactic_ref t = mk_sat_tactic(m, _p); + return mk_tactic2solver(m, t.get(), _p); + } + return alloc(inc_sat_solver, m, _p); } From 8915d0a21f60a46ad82092e5a9689cf15ab88460 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Tue, 24 Oct 2017 14:08:44 -0700 Subject: [PATCH 0300/1283] Tidy --- src/sat/sat_simplifier.cpp | 83 ++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 9042587b7..11ad8a85c 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1044,16 +1044,17 @@ namespace sat { clause_use_list::iterator it = occs.mk_iterator(); while (!it.at_end()) { clause & c = it.curr(); - it.next(); - if (c.is_blocked()) continue; - m_counter -= c.size(); - SASSERT(c.contains(l)); - s.mark_all_but(c, l); - if (all_tautology(l)) { - block_clause(c, l, new_entry); - s.m_num_blocked_clauses++; + if (!c.is_blocked()) { + m_counter -= c.size(); + SASSERT(c.contains(l)); + s.mark_all_but(c, l); + if (all_tautology(l)) { + block_clause(c, l, new_entry); + s.m_num_blocked_clauses++; + } + s.unmark_all(c); } - s.unmark_all(c); + it.next(); } for (clause* c : m_to_remove) s.block_clause(*c); @@ -1086,31 +1087,32 @@ namespace sat { while (!it.at_end()) { bool tautology = false; clause & c = it.curr(); - it.next(); - if (c.is_blocked()) continue; - for (literal lit : c) { - if (s.is_marked(~lit) && lit != ~l) { - tautology = true; - break; - } - } - if (!tautology) { - if (first) { - for (literal lit : c) { - if (lit != ~l && !s.is_marked(lit)) inter.push_back(lit); + if (!c.is_blocked()) { + for (literal lit : c) { + if (s.is_marked(~lit) && lit != ~l) { + tautology = true; + break; } - first = false; - if (inter.empty()) return false; } - else { - unsigned j = 0; - for (literal lit : inter) - if (c.contains(lit)) - inter[j++] = lit; - inter.shrink(j); - if (j == 0) return false; + if (!tautology) { + if (first) { + for (literal lit : c) { + if (lit != ~l && !s.is_marked(lit)) inter.push_back(lit); + } + first = false; + if (inter.empty()) return false; + } + else { + unsigned j = 0; + for (literal lit : inter) + if (c.contains(lit)) + inter[j++] = lit; + inter.shrink(j); + if (j == 0) return false; + } } } + it.next(); } return first; } @@ -1360,17 +1362,18 @@ namespace sat { clause_use_list::iterator it = neg_occs.mk_iterator(); while (!it.at_end()) { clause & c = it.curr(); - it.next(); - if (c.is_blocked()) continue; - m_counter -= c.size(); - unsigned sz = c.size(); - unsigned i; - for (i = 0; i < sz; i++) { - if (s.is_marked(~c[i])) - break; + if (!c.is_blocked()) { + m_counter -= c.size(); + unsigned sz = c.size(); + unsigned i; + for (i = 0; i < sz; i++) { + if (s.is_marked(~c[i])) + break; + } + if (i == sz) + return false; } - if (i == sz) - return false; + it.next(); } if (s.s.m_ext) { From b72225d7d0592e837e119e50ce9addfb7608ca70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 15:16:59 -0700 Subject: [PATCH 0301/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 15 +++++++-------- src/sat/sat_solver/inc_sat_solver.cpp | 17 +++++++++++------ src/sat/sat_solver/inc_sat_solver.h | 2 +- src/tactic/portfolio/fd_solver.cpp | 6 +++--- src/tactic/portfolio/fd_solver.h | 2 +- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 369b3c7dd..347800d19 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -942,6 +942,7 @@ namespace sat { } literal next() { SASSERT(!empty()); return to_literal(m_queue.erase_min()); } bool empty() const { return m_queue.empty(); } + void reset() { m_queue.reset(); } }; simplifier & s; @@ -1042,7 +1043,7 @@ namespace sat { m_to_remove.reset(); clause_use_list & occs = s.m_use_list.get(l); clause_use_list::iterator it = occs.mk_iterator(); - while (!it.at_end()) { + for (; !it.at_end(); it.next()) { clause & c = it.curr(); if (c.is_blocked()) continue; m_counter -= c.size(); @@ -1052,8 +1053,7 @@ namespace sat { block_clause(c, l, new_entry); s.m_num_blocked_clauses++; } - s.unmark_all(c); - it.next(); + s.unmark_all(c); } for (clause* c : m_to_remove) s.block_clause(*c); @@ -1083,7 +1083,7 @@ namespace sat { } clause_use_list & neg_occs = s.m_use_list.get(~l); clause_use_list::iterator it = neg_occs.mk_iterator(); - while (!it.at_end()) { + for (; !it.at_end(); it.next()) { bool tautology = false; clause & c = it.curr(); if (c.is_blocked()) continue; @@ -1110,7 +1110,6 @@ namespace sat { if (j == 0) return false; } } - it.next(); } return first; } @@ -1204,12 +1203,12 @@ namespace sat { } void cce() { + insert_queue(); cce_clauses(); cce_binary(); } void cce_binary() { - insert_queue(); while (!m_queue.empty() && m_counter >= 0) { s.checkpoint(); process_cce_binary(m_queue.next()); @@ -1309,6 +1308,7 @@ namespace sat { } void bca() { + m_queue.reset(); insert_queue(); while (!m_queue.empty() && m_counter >= 0) { s.checkpoint(); @@ -1360,7 +1360,7 @@ namespace sat { clause_use_list & neg_occs = s.m_use_list.get(~l); clause_use_list::iterator it = neg_occs.mk_iterator(); - while (!it.at_end()) { + for (; !it.at_end(); it.next()) { clause & c = it.curr(); if (c.is_blocked()) continue; m_counter -= c.size(); @@ -1372,7 +1372,6 @@ namespace sat { } if (i == sz) return false; - it.next(); } if (s.s.m_ext) { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 53383a7c2..144b6b86c 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -69,10 +69,11 @@ class inc_sat_solver : public solver { bool m_internalized; // are formulas internalized? bool m_internalized_converted; // have internalized formulas been converted back expr_ref_vector m_internalized_fmls; // formulas in internalized format + bool m_incremental_mode; typedef obj_map dep2asm_t; public: - inc_sat_solver(ast_manager& m, params_ref const& p): + inc_sat_solver(ast_manager& m, params_ref const& p, bool incremental_mode): m(m), m_solver(p, m.limit()), m_params(p), @@ -86,7 +87,8 @@ public: m_unknown("no reason given"), m_internalized(false), m_internalized_converted(false), - m_internalized_fmls(m) { + m_internalized_fmls(m), + m_incremental_mode(incremental_mode) { updt_params(p); init_preprocess(); } @@ -99,7 +101,7 @@ public: } ast_translation tr(m, dst_m); m_solver.pop_to_base_level(); - inc_sat_solver* result = alloc(inc_sat_solver, dst_m, p); + inc_sat_solver* result = alloc(inc_sat_solver, dst_m, p, m_incremental_mode); result->m_solver.copy(m_solver); result->m_fmls_head = m_fmls_head; for (expr* f : m_fmls) result->m_fmls.push_back(tr(f)); @@ -271,7 +273,10 @@ public: virtual void updt_params(params_ref const & p) { m_params.append(p); sat_params p1(p); - m_params.set_bool("elim_vars", false); + if (m_incremental_mode) { + m_params.set_bool("elim_vars", false); + m_params.set_uint("elim_blocked_clauses_at", UINT_MAX); + } m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); m_params.set_bool("keep_pb_constraints", m_solver.get_config().m_pb_solver == sat::PB_SOLVER); m_params.set_bool("pb_num_system", m_solver.get_config().m_pb_solver == sat::PB_SORTING); @@ -848,8 +853,8 @@ private: }; -solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p) { - return alloc(inc_sat_solver, m, p); +solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p, bool incremental_mode) { + return alloc(inc_sat_solver, m, p, incremental_mode); } diff --git a/src/sat/sat_solver/inc_sat_solver.h b/src/sat/sat_solver/inc_sat_solver.h index 658c0583d..fb4b05b91 100644 --- a/src/sat/sat_solver/inc_sat_solver.h +++ b/src/sat/sat_solver/inc_sat_solver.h @@ -22,7 +22,7 @@ Notes: #include "solver/solver.h" -solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p); +solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p, bool incremental_mode = true); void inc_sat_display(std::ostream& out, solver& s, unsigned sz, expr*const* soft, rational const* _weights); diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/portfolio/fd_solver.cpp index daecb6c9c..946b3b30c 100644 --- a/src/tactic/portfolio/fd_solver.cpp +++ b/src/tactic/portfolio/fd_solver.cpp @@ -25,8 +25,8 @@ Notes: #include "tactic/portfolio/bounded_int2bv_solver.h" #include "solver/solver2tactic.h" -solver * mk_fd_solver(ast_manager & m, params_ref const & p) { - solver* s = mk_inc_sat_solver(m, p); +solver * mk_fd_solver(ast_manager & m, params_ref const & p, bool incremental_mode) { + solver* s = mk_inc_sat_solver(m, p, incremental_mode); s = mk_enum2bv_solver(m, p, s); s = mk_pb2bv_solver(m, p, s); s = mk_bounded_int2bv_solver(m, p, s); @@ -34,5 +34,5 @@ solver * mk_fd_solver(ast_manager & m, params_ref const & p) { } tactic * mk_fd_tactic(ast_manager & m, params_ref const& p) { - return mk_solver2tactic(mk_fd_solver(m, p)); + return mk_solver2tactic(mk_fd_solver(m, p, false)); } diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/portfolio/fd_solver.h index b54ba74f4..1e107ac20 100644 --- a/src/tactic/portfolio/fd_solver.h +++ b/src/tactic/portfolio/fd_solver.h @@ -25,7 +25,7 @@ Notes: class solver; class tactic; -solver * mk_fd_solver(ast_manager & m, params_ref const & p); +solver * mk_fd_solver(ast_manager & m, params_ref const & p, bool incremental_mode = true); tactic * mk_fd_tactic(ast_manager & m, params_ref const & p); /* From 4d9492176e8905a0ed06b5d82d29130623f7b6be Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Tue, 24 Oct 2017 15:19:45 -0700 Subject: [PATCH 0302/1283] Removed incremental disabling --- src/sat/sat_params.pyg | 1 - src/sat/sat_solver/inc_sat_solver.cpp | 5 ----- 2 files changed, 6 deletions(-) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index ada6f910b..d803617f5 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -32,7 +32,6 @@ def_module_params('sat', ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), ('xor.solver', BOOL, False, 'use xor solver'), - ('disable_incremental', BOOL, False, 'disable incremental solving. Allows stronger simplification, but solver cannot be re-used.'), ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 099dc701b..15c1cb240 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -850,11 +850,6 @@ private: solver* mk_inc_sat_solver(ast_manager& m, params_ref const& _p) { - sat_params p(_p); - if (p.disable_incremental()) { - tactic_ref t = mk_sat_tactic(m, _p); - return mk_tactic2solver(m, t.get(), _p); - } return alloc(inc_sat_solver, m, _p); } From 32711790e87cba5e97d862e7d2fe9564910525af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 13:36:48 -0700 Subject: [PATCH 0303/1283] bug fixes reported by Miguel Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 +- src/sat/sat_config.cpp | 6 ++++++ src/sat/sat_config.h | 4 ++++ src/sat/sat_solver/inc_sat_solver.cpp | 1 - src/sat/tactic/goal2sat.cpp | 4 ++-- src/solver/tactic2solver.cpp | 4 ++++ 6 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index a8a09d3ff..f963ce620 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2396,7 +2396,7 @@ namespace sat { init_use_lists(); remove_unused_defs(); set_non_external(); - elim_pure(); + if (get_config().m_elim_vars) elim_pure(); for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) subsumption(*m_constraints[i]); for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) subsumption(*m_learned[i]); cleanup_clauses(); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index c77774283..08f1b86b2 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -19,6 +19,8 @@ Revision History: #include "sat/sat_config.h" #include "sat/sat_types.h" #include "sat/sat_params.hpp" +#include "sat/sat_simplifier_params.hpp" + namespace sat { @@ -39,6 +41,7 @@ namespace sat { m_local_search = 0; m_lookahead_search = false; m_lookahead_simplify = false; + m_elim_vars = false; updt_params(p); } @@ -188,6 +191,9 @@ namespace sat { } m_dimacs_display = p.dimacs_display(); m_dimacs_inprocess_display = p.dimacs_inprocess_display(); + + sat_simplifier_params sp(_p); + m_elim_vars = sp.elim_vars(); } void config::collect_param_descrs(param_descrs & r) { diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 214a93f5d..a6db0cddc 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -133,6 +133,10 @@ namespace sat { double m_step_size_min; double m_reward_multiplier; double m_reward_offset; + + // simplifier configurations used outside of sat_simplifier + bool m_elim_vars; + config(params_ref const & p); void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 144b6b86c..742f9e103 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -510,7 +510,6 @@ public: } m_internalized_fmls.reset(); g.get_formulas(m_internalized_fmls); - // g.display(std::cout); m_internalized_converted = true; // if (mc) mc->display(std::cout << "mc"); // if (m_mc) m_mc->display(std::cout << "m_mc\n"); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index d7b0e0892..fe8135368 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1063,7 +1063,7 @@ struct sat2goal::imp { for (sat::literal l : c) { lits.push_back(lit2expr(l)); } - expr_ref fml(pb.mk_at_most_k(c.size(), lits.c_ptr(), c.k()), m); + expr_ref fml(pb.mk_at_least_k(c.size(), lits.c_ptr(), c.k()), m); if (c.lit() != sat::null_literal) { fml = m.mk_eq(lit2expr(c.lit()), fml); @@ -1110,6 +1110,7 @@ struct sat2goal::imp { r.assert_expr(m.mk_false()); return; } + IF_VERBOSE(1, verbose_stream() << "solver2goal " << s.num_vars() << " " << s.clauses().size() << "\n";); init_lit2expr(s, map, mc, r.models_enabled()); // collect units unsigned num_vars = s.num_vars(); @@ -1135,7 +1136,6 @@ struct sat2goal::imp { } // collect clauses assert_clauses(s, s.clauses(), r, true); - assert_clauses(s, s.learned(), r, false); sat::ba_solver* ext = get_ba_solver(s); if (ext) { diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index b165304bf..7d9388f50 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -173,6 +173,10 @@ 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) { + m_assertions.reset(); + g->get_formulas(m_assertions); + } break; } } From ac0202630ee945d8c006671d7364ed6b028e0c4c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 15:40:11 -0700 Subject: [PATCH 0304/1283] fix non-termination bug with retained clauses Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 3 +- src/ast/bv_decl_plugin.cpp | 2 +- src/sat/sat_elim_vars.cpp | 17 ++++--- src/sat/sat_simplifier.cpp | 88 ++++++++++--------------------------- src/sat/sat_watched.h | 2 +- src/sat/tactic/goal2sat.cpp | 1 - 6 files changed, 36 insertions(+), 77 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index cac12413e..232e7b6d0 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2254,9 +2254,10 @@ func_decl * ast_manager::mk_fresh_func_decl(symbol const & prefix, symbol const } else { string_buffer<64> buffer; - buffer << prefix; if (prefix == symbol::null) buffer << "sk"; + else + buffer << prefix; buffer << "!"; if (suffix != symbol::null) buffer << suffix << "!"; diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index fcf9a9f8f..fd176c1e0 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -717,7 +717,7 @@ void bv_decl_plugin::get_op_names(svector & op_names, symbol const op_names.push_back(builtin_name("rotate_left",OP_ROTATE_LEFT)); op_names.push_back(builtin_name("rotate_right",OP_ROTATE_RIGHT)); - if (logic == symbol::null) { + if (logic == symbol::null || logic == "QF_FD") { op_names.push_back(builtin_name("bvumul_noovfl",OP_BUMUL_NO_OVFL)); op_names.push_back(builtin_name("bvsmul_noovfl",OP_BSMUL_NO_OVFL)); op_names.push_back(builtin_name("bvsmul_noudfl",OP_BSMUL_NO_UDFL)); diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 59210a266..5dd3ed1f7 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -302,17 +302,16 @@ namespace sat{ } bdd elim_vars::make_clauses(clause_use_list & occs) { - bdd result = m.mk_true(); - clause_use_list::iterator it = occs.mk_iterator(); - while (!it.at_end()) { + bdd result = m.mk_true(); + for (auto it = occs.mk_iterator(); !it.at_end(); it.next()) { clause const& c = it.curr(); - if (c.is_blocked()) continue; - bdd cl = m.mk_false(); - for (literal l : c) { - cl |= mk_literal(l); + if (!c.is_blocked()) { + bdd cl = m.mk_false(); + for (literal l : c) { + cl |= mk_literal(l); + } + result &= cl; } - it.next(); - result &= cl; } return result; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 347800d19..2cc1a7f09 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -418,8 +418,7 @@ namespace sat { literal target) { if (c1.is_blocked()) return; clause_use_list const & cs = m_use_list.get(target); - clause_use_list::iterator it = cs.mk_iterator(); - while (!it.at_end()) { + for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) { clause & c2 = it.curr(); CTRACE("resolution_bug", c2.was_removed(), tout << "clause has been removed:\n" << c2 << "\n";); SASSERT(!c2.was_removed()); @@ -433,7 +432,6 @@ namespace sat { out_lits.push_back(l); } } - it.next(); } } @@ -532,7 +530,7 @@ namespace sat { if (c1.is_blocked()) return; clause_use_list const & cs = m_use_list.get(target); clause_use_list::iterator it = cs.mk_iterator(); - while (!it.at_end()) { + for (; !it.at_end(); it.next()) { clause & c2 = it.curr(); SASSERT(!c2.was_removed()); if (&c2 != &c1 && @@ -543,7 +541,6 @@ namespace sat { out.push_back(&c2); } } - it.next(); } } @@ -652,29 +649,16 @@ namespace sat { unsigned new_trail_sz = s.m_trail.size(); for (unsigned i = old_trail_sz; i < new_trail_sz; i++) { literal l = s.m_trail[i]; - { - // put clauses with literals assigned to false back into todo-list - clause_use_list & cs = m_use_list.get(~l); - clause_use_list::iterator it = cs.mk_iterator(); - while (!it.at_end()) { - clause & c = it.curr(); - it.next(); - m_sub_todo.insert(c); - } + // put clauses with literals assigned to false back into todo-list + for (auto it = m_use_list.get(~l).mk_iterator(); !it.at_end(); it.next()) { + m_sub_todo.insert(it.curr()); } - { - // erase satisfied clauses - clause_use_list & cs = m_use_list.get(l); - { - clause_use_list::iterator it = cs.mk_iterator(); - while (!it.at_end()) { - clause & c = it.curr(); - it.next(); - remove_clause(c, l); - } - } - cs.reset(); + clause_use_list& cs = m_use_list.get(l); + for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) { + clause & c = it.curr(); + remove_clause(c, l); } + cs.reset(); } } @@ -1338,12 +1322,8 @@ namespace sat { } if (!found) { IF_VERBOSE(100, verbose_stream() << "bca " << l << " " << l2 << "\n";); - watched w(l2, false); - w.set_blocked(); - s.get_wlist(~l).push_back(w); - w = watched(l, false); - w.set_blocked(); - s.get_wlist(~l2).push_back(w); + s.get_wlist(~l).push_back(watched(l2, true)); + s.get_wlist(~l2).push_back(watched(l, true)); ++s.m_num_bca; } } @@ -1473,29 +1453,18 @@ namespace sat { void simplifier::collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked) { clause_use_list const & cs = m_use_list.get(l); clause_use_list::iterator it = cs.mk_iterator(); - while (!it.at_end()) { + for (; !it.at_end(); it.next()) { if (!it.curr().is_blocked() || include_blocked) { r.push_back(clause_wrapper(it.curr())); SASSERT(r.back().size() == it.curr().size()); } - it.next(); } watch_list & wlist = get_wlist(~l); - if (include_blocked) { - for (auto & w : wlist) { - if (w.is_binary_non_learned_clause2()) { - r.push_back(clause_wrapper(l, w.get_literal())); - SASSERT(r.back().size() == 2); - } - } - } - else { - for (auto & w : wlist) { - if (w.is_binary_unblocked_clause()) { - r.push_back(clause_wrapper(l, w.get_literal())); - SASSERT(r.back().size() == 2); - } + for (auto & w : wlist) { + if (include_blocked ? w.is_binary_non_learned_clause() : w.is_binary_unblocked_clause()) { + r.push_back(clause_wrapper(l, w.get_literal())); + SASSERT(r.back().size() == 2); } } } @@ -1607,8 +1576,7 @@ namespace sat { \brief Eliminate the clauses where the variable being eliminated occur. */ void simplifier::remove_clauses(clause_use_list const & cs, literal l) { - clause_use_list::iterator it = cs.mk_iterator(); - while (!it.at_end()) { + for (auto it = cs.mk_iterator(); !it.at_end(); ) { clause & c = it.curr(); it.next(); SASSERT(c.contains(l)); @@ -1641,22 +1609,14 @@ namespace sat { unsigned before_lits = num_bin_pos*2 + num_bin_neg*2; - { - clause_use_list::iterator it = pos_occs.mk_iterator(); - while (!it.at_end()) { - if (!it.curr().is_blocked()) - before_lits += it.curr().size(); - it.next(); - } + for (auto it = pos_occs.mk_iterator(); !it.at_end(); it.next()) { + if (!it.curr().is_blocked()) + before_lits += it.curr().size(); } - { - clause_use_list::iterator it2 = neg_occs.mk_iterator(); - while (!it2.at_end()) { - if (!it2.curr().is_blocked()) - before_lits += it2.curr().size(); - it2.next(); - } + for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) { + if (!it.curr().is_blocked()) + before_lits += it.curr().size(); } TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << " before_lits: " << before_lits << "\n";); diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index f18e08999..8d7924c6f 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -88,7 +88,7 @@ namespace sat { bool is_binary_unblocked_clause() const { return m_val2 == 0; } bool is_binary_learned_clause() const { return is_binary_clause() && is_learned(); } - bool is_binary_non_learned_clause2() const { return is_binary_clause() && !is_learned(); } + bool is_binary_non_learned_clause() const { return is_binary_clause() && !is_learned(); } void mark_not_learned() { SASSERT(is_learned()); m_val2 = static_cast(BINARY); SASSERT(!is_learned()); } void set_blocked() { SASSERT(is_binary_clause()); SASSERT(!is_learned()); m_val2 |= (1 << 3); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index fe8135368..208d60386 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1110,7 +1110,6 @@ struct sat2goal::imp { r.assert_expr(m.mk_false()); return; } - IF_VERBOSE(1, verbose_stream() << "solver2goal " << s.num_vars() << " " << s.clauses().size() << "\n";); init_lit2expr(s, map, mc, r.models_enabled()); // collect units unsigned num_vars = s.num_vars(); From 0919fd4075899c10304469965d28a594b32ffb85 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 16:46:22 -0700 Subject: [PATCH 0305/1283] fix bca condition for tautology check Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 10 +++++++--- src/sat/sat_solver.cpp | 9 +++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 2cc1a7f09..09cb063f5 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1070,7 +1070,7 @@ namespace sat { for (; !it.at_end(); it.next()) { bool tautology = false; clause & c = it.curr(); - if (c.is_blocked()) continue; + if (c.is_blocked() && !adding) continue; for (literal lit : c) { if (s.is_marked(~lit) && lit != ~l) { tautology = true; @@ -1322,8 +1322,12 @@ namespace sat { } if (!found) { IF_VERBOSE(100, verbose_stream() << "bca " << l << " " << l2 << "\n";); - s.get_wlist(~l).push_back(watched(l2, true)); - s.get_wlist(~l2).push_back(watched(l, true)); + watched w1(l2, false); + w1.set_blocked(); + watched w2(l, false); + w2.set_blocked(); + s.get_wlist(~l).push_back(w1); + s.get_wlist(~l2).push_back(w2); ++s.m_num_bca; } } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5db9d44c6..1f0015476 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1553,8 +1553,10 @@ namespace sat { // #ifndef _EXTERNAL_RELEASE IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";); - if (!check_model(m_model)) + if (!check_model(m_model)) { + UNREACHABLE(); throw solver_exception("check model failed"); + } if (m_clone) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model (on original set of clauses)\"\n";); @@ -1576,6 +1578,9 @@ namespace sat { tout << "model: " << m << "\n"; m_mc.display(tout); ); + for (literal l : c) { + if (was_eliminated(l.var())) IF_VERBOSE(0, verbose_stream() << "eliminated: " << l << "\n";); + } ok = false; } } @@ -1588,7 +1593,7 @@ namespace sat { continue; literal l2 = w.get_literal(); if (value_at(l2, m) != l_true) { - IF_VERBOSE(0, verbose_stream() << "failed binary: " << l << " " << l2 << " " << "\n";); + IF_VERBOSE(0, verbose_stream() << "failed binary: " << l << " " << l2 << "\n";); TRACE("sat", m_mc.display(tout << "failed binary: " << l << " " << l2 << "\n");); ok = false; } From 3a05313c6795b831f27f88c6a925af0773e7a258 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Fri, 27 Oct 2017 12:36:09 -0700 Subject: [PATCH 0306/1283] Python API context fix --- src/api/python/z3/z3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4379e3fe1..ab6249ff6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6315,11 +6315,11 @@ class Solver(Z3PPObject): def from_file(self, filename): """Parse assertions from a file""" - self.add([f for f in parse_smt2_file(filename)]) + self.add([f for f in parse_smt2_file(filename, ctx=self.ctx)]) def from_string(self, s): """Parse assertions from a string""" - self.add([f for f in parse_smt2_string(s)]) + self.add([f for f in parse_smt2_string(s, ctx=self.ctx)]) def assertions(self): """Return an AST vector containing all added constraints. From f1bad9160979ed010a585f784b57d6abc8857ae3 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Fri, 27 Oct 2017 12:39:36 -0700 Subject: [PATCH 0307/1283] Clean-up --- src/sat/sat_solver/inc_sat_solver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index dcfec489d..742f9e103 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -29,7 +29,6 @@ Notes: #include "tactic/bv/bit_blaster_tactic.h" #include "tactic/core/simplify_tactic.h" #include "sat/tactic/goal2sat.h" -#include "sat/tactic/sat_tactic.h" #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" #include "tactic/filter_model_converter.h" From 829c1400870f45dc46535a3b34b0fa1aa7163e3d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Oct 2017 15:40:25 -0700 Subject: [PATCH 0308/1283] ensure that bca takes also lemmas into account Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 1 + src/sat/sat_asymm_branch.cpp | 1 + src/sat/sat_clause.cpp | 28 +++-- src/sat/sat_clause.h | 10 +- src/sat/sat_cleaner.cpp | 3 +- src/sat/sat_config.cpp | 5 +- src/sat/sat_config.h | 3 +- src/sat/sat_drat.cpp | 42 ++++--- src/sat/sat_drat.h | 5 + src/sat/sat_lookahead.h | 4 +- src/sat/sat_model_converter.cpp | 138 +++++++++++++++++----- src/sat/sat_model_converter.h | 15 ++- src/sat/sat_params.pyg | 3 +- src/sat/sat_scc.cpp | 4 +- src/sat/sat_simplifier.cpp | 157 +++++++++++++++++++------- src/sat/sat_simplifier.h | 11 +- src/sat/sat_simplifier_params.pyg | 2 + src/sat/sat_solver.cpp | 77 +++++++------ src/sat/sat_solver.h | 15 +++ src/sat/sat_solver/inc_sat_solver.cpp | 8 +- src/sat/tactic/goal2sat.cpp | 1 + 21 files changed, 384 insertions(+), 149 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 95c030687..25cb2a541 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1776,6 +1776,7 @@ void cmd_context::validate_model() { continue; } TRACE("model_validate", model_smt2_pp(tout, *this, *(md.get()), 0);); + IF_VERBOSE(10, verbose_stream() << "model check failed on: " << mk_pp(a, m()) << "\n";); invalid_model = true; } } diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 14969adb8..03d121599 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -115,6 +115,7 @@ namespace sat { } bool asymm_branch::process(clause & c) { + if (c.is_blocked()) return true; TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";); SASSERT(s.scope_lvl() == 0); SASSERT(s.m_qhead == s.m_trail.size()); diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 206dfcf40..43d614e38 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -60,15 +60,15 @@ namespace sat { } bool clause::contains(literal l) const { - for (unsigned i = 0; i < m_size; i++) - if (m_lits[i] == l) + for (literal l2 : *this) + if (l2 == l) return true; return false; } bool clause::contains(bool_var v) const { - for (unsigned i = 0; i < m_size; i++) - if (m_lits[i].var() == v) + for (literal l : *this) + if (l.var() == v) return true; return false; } @@ -87,8 +87,7 @@ namespace sat { } bool clause::satisfied_by(model const & m) const { - for (unsigned i = 0; i < m_size; i++) { - literal l = m_lits[i]; + for (literal l : *this) { if (l.sign()) { if (m[l.var()] == l_false) return true; @@ -197,14 +196,13 @@ namespace sat { if (c.was_removed()) out << "x"; if (c.strengthened()) out << "+"; if (c.is_learned()) out << "*"; + if (c.is_blocked()) out << "b"; return out; } std::ostream & operator<<(std::ostream & out, clause_vector const & cs) { - clause_vector::const_iterator it = cs.begin(); - clause_vector::const_iterator end = cs.end(); - for (; it != end; ++it) { - out << *(*it) << "\n"; + for (clause *cp : cs) { + out << *cp << "\n"; } return out; } @@ -226,12 +224,12 @@ namespace sat { } std::ostream & operator<<(std::ostream & out, clause_wrapper const & c) { - out << "("; - for (unsigned i = 0; i < c.size(); i++) { - if (i > 0) out << " "; - out << c[i]; + if (c.is_binary()) { + out << "(" << c[0] << " " << c[1] << ")"; + } + else { + out << c.get_clause()->id() << ": " << *c.get_clause(); } - out << ")"; return out; } diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 8fd7b52cf..dd8028ec2 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -33,6 +33,10 @@ namespace sat { class clause_allocator; + class clause; + + std::ostream & operator<<(std::ostream & out, clause const & c); + class clause { friend class clause_allocator; friend class tmp_clause; @@ -61,8 +65,8 @@ namespace sat { literal & operator[](unsigned idx) { SASSERT(idx < m_size); return m_lits[idx]; } literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; } bool is_learned() const { return m_learned; } - void unset_learned() { SASSERT(is_learned()); m_learned = false; } - void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); } } + void unset_learned() { if (id() == 642277) std::cout << "unlearn " << *this << "\n"; SASSERT(is_learned()); m_learned = false; } + void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); if (id() == 642277) std::cout << "shrink " << *this << "\n"; } } bool strengthened() const { return m_strengthened; } void mark_strengthened() { m_strengthened = true; update_approx(); } void unmark_strengthened() { m_strengthened = false; } @@ -101,7 +105,6 @@ namespace sat { void set_reinit_stack(bool f) { m_reinit_stack = f; } }; - std::ostream & operator<<(std::ostream & out, clause const & c); std::ostream & operator<<(std::ostream & out, clause_vector const & cs); class bin_clause { @@ -180,6 +183,7 @@ namespace sat { bool contains(literal l) const; bool contains(bool_var v) const; clause * get_clause() const { SASSERT(!is_binary()); return m_cls; } + bool was_removed() const { return !is_binary() && get_clause()->was_removed(); } }; typedef svector clause_wrapper_vector; diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 286cc1661..e52cf139f 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -137,7 +137,8 @@ namespace sat { SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); if (new_sz == 2) { TRACE("cleanup_bug", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";); - s.mk_bin_clause(c[0], c[1], c.is_learned()); + if (!c.is_blocked()) + s.mk_bin_clause(c[0], c[1], c.is_learned()); s.del_clause(c); } else { diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 08f1b86b2..d0618d265 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -146,9 +146,10 @@ namespace sat { m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); - m_drat_check = p.drat_check(); + m_drat_check_unsat = p.drat_check_unsat(); + m_drat_check_sat = p.drat_check_sat(); m_drat_file = p.drat_file(); - m_drat = (m_drat_check || m_drat_file != symbol("")) && p.threads() == 1; + m_drat = (m_drat_check_unsat || m_drat_file != symbol("") || m_drat_check_sat) && p.threads() == 1; m_dyn_sub_res = p.dyn_sub_res(); // Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016. diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index a6db0cddc..17ce7a569 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -105,7 +105,8 @@ namespace sat { bool m_core_minimize_partial; bool m_drat; symbol m_drat_file; - bool m_drat_check; + bool m_drat_check_unsat; + bool m_drat_check_sat; bool m_dimacs_display; bool m_dimacs_inprocess_display; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index d3864fd8b..fd2b6fa79 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -27,7 +27,10 @@ namespace sat { drat::drat(solver& s): s(s), m_out(0), - m_inconsistent(false) + m_inconsistent(false), + m_check_unsat(false), + m_check_sat(false), + m_check(false) { if (s.m_config.m_drat && s.m_config.m_drat_file != symbol()) { m_out = alloc(std::ofstream, s.m_config.m_drat_file.str().c_str()); @@ -44,6 +47,12 @@ namespace sat { } } + void drat::updt_config() { + m_check_unsat = s.m_config.m_drat_check_unsat; + m_check_sat = s.m_config.m_drat_check_sat; + m_check = m_check_unsat || m_check_sat; + } + std::ostream& operator<<(std::ostream& out, drat::status st) { switch (st) { case drat::status::learned: return out << "l"; @@ -88,7 +97,7 @@ namespace sat { } void drat::append(literal l, status st) { - IF_VERBOSE(10, trace(verbose_stream(), 1, &l, st);); + IF_VERBOSE(20, trace(verbose_stream(), 1, &l, st);); if (st == status::learned) { verify(1, &l); } @@ -100,7 +109,7 @@ namespace sat { void drat::append(literal l1, literal l2, status st) { literal lits[2] = { l1, l2 }; - IF_VERBOSE(10, trace(verbose_stream(), 2, lits, st);); + IF_VERBOSE(20, trace(verbose_stream(), 2, lits, st);); if (st == status::deleted) { // noop // don't record binary as deleted. @@ -131,7 +140,7 @@ namespace sat { void drat::append(clause& c, status st) { unsigned n = c.size(); - IF_VERBOSE(10, trace(verbose_stream(), n, c.begin(), st);); + IF_VERBOSE(20, trace(verbose_stream(), n, c.begin(), st);); if (st == status::learned) { verify(n, c.begin()); @@ -270,7 +279,7 @@ namespace sat { } void drat::verify(unsigned n, literal const* c) { - if (!is_drup(n, c) && !is_drat(n, c)) { + if (m_check_unsat && !is_drup(n, c) && !is_drat(n, c)) { std::cout << "Verification failed\n"; UNREACHABLE(); //display(std::cout); @@ -412,7 +421,7 @@ namespace sat { void drat::add() { if (m_out) (*m_out) << "0\n"; - if (s.m_config.m_drat_check) { + if (m_check_unsat) { SASSERT(m_inconsistent); } } @@ -420,7 +429,7 @@ namespace sat { declare(l); status st = get_status(learned); if (m_out) dump(1, &l, st); - if (s.m_config.m_drat_check) append(l, st); + if (m_check) append(l, st); } void drat::add(literal l1, literal l2, bool learned) { declare(l1); @@ -428,17 +437,17 @@ namespace sat { literal ls[2] = {l1, l2}; status st = get_status(learned); if (m_out) dump(2, ls, st); - if (s.m_config.m_drat_check) append(l1, l2, st); + if (m_check) append(l1, l2, st); } void drat::add(clause& c, bool learned) { TRACE("sat", tout << "add: " << c << "\n";); for (unsigned i = 0; i < c.size(); ++i) declare(c[i]); status st = get_status(learned); if (m_out) dump(c.size(), c.begin(), st); - if (s.m_config.m_drat_check) append(c, get_status(learned)); + if (m_check_unsat) append(c, get_status(learned)); } void drat::add(literal_vector const& lits, svector const& premises) { - if (s.m_config.m_drat_check) { + if (m_check) { switch (lits.size()) { case 0: add(); break; case 1: append(lits[0], status::external); break; @@ -453,7 +462,7 @@ namespace sat { void drat::add(literal_vector const& c) { for (unsigned i = 0; i < c.size(); ++i) declare(c[i]); if (m_out) dump(c.size(), c.begin(), status::learned); - if (s.m_config.m_drat_check) { + if (m_check) { switch (c.size()) { case 0: add(); break; case 1: append(c[0], status::learned); break; @@ -469,20 +478,25 @@ namespace sat { void drat::del(literal l) { if (m_out) dump(1, &l, status::deleted); - if (s.m_config.m_drat_check) append(l, status::deleted); + if (m_check_unsat) append(l, status::deleted); } void drat::del(literal l1, literal l2) { literal ls[2] = {l1, l2}; if (m_out) dump(2, ls, status::deleted); - if (s.m_config.m_drat_check) + if (m_check) append(l1, l2, status::deleted); } void drat::del(clause& c) { TRACE("sat", tout << "del: " << c << "\n";); if (m_out) dump(c.size(), c.begin(), status::deleted); - if (s.m_config.m_drat_check) { + if (m_check) { clause* c1 = s.m_cls_allocator.mk_clause(c.size(), c.begin(), c.is_learned()); append(*c1, status::deleted); } } + + void drat::check_model(model const& m) { + std::cout << "check model on " << m_proof.size() << "\n"; + } + } diff --git a/src/sat/sat_drat.h b/src/sat/sat_drat.h index 2765d104c..64d796839 100644 --- a/src/sat/sat_drat.h +++ b/src/sat/sat_drat.h @@ -52,6 +52,7 @@ namespace sat { vector m_watches; svector m_assignment; bool m_inconsistent; + bool m_check_unsat, m_check_sat, m_check; void dump(unsigned n, literal const* c, status st); void append(literal l, status st); @@ -78,6 +79,8 @@ namespace sat { public: drat(solver& s); ~drat(); + + void updt_config(); void add(); void add(literal l, bool learned); void add(literal l1, literal l2, bool learned); @@ -89,6 +92,8 @@ namespace sat { void del(literal l); void del(literal l1, literal l2); void del(clause& c); + + void check_model(model const& m); }; }; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 56d2e94a1..baf3ed660 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -246,8 +246,8 @@ namespace sat { inline bool is_true(literal l) const { return is_true_at(l, m_level); } inline void set_true(literal l) { m_stamp[l.var()] = m_level + l.sign(); } inline void set_undef(literal l) { m_stamp[l.var()] = 0; } - inline unsigned get_level(literal l) const { return m_stamp[l.var()] & UINT_MAX - 1; } - void set_level(literal d, literal s) { m_stamp[d.var()] = (m_stamp[s.var()] & ~0x1) + d.sign(); } + inline unsigned get_level(literal l) const { return m_stamp[l.var()] & ~0x1; } + void set_level(literal d, literal s) { m_stamp[d.var()] = get_level(s) + d.sign(); } lbool value(literal l) const { return is_undef(l) ? l_undef : is_true(l) ? l_true : l_false; } // set the level within a scope of the search. diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index eb60e209a..2cc9ceffc 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -18,11 +18,12 @@ Revision History: --*/ #include "sat/sat_model_converter.h" #include "sat/sat_clause.h" +#include "sat/sat_solver.h" #include "util/trace.h" namespace sat { - model_converter::model_converter() { + model_converter::model_converter(): m_solver(nullptr) { } model_converter::~model_converter() { @@ -50,7 +51,6 @@ namespace sat { } if (!sat) { m[lit.var()] = lit.sign() ? l_false : l_true; - // if (lit.var() == 258007) std::cout << "flip " << lit << " " << m[lit.var()] << " @ " << i << " of " << c << " from overall size " << sz << "\n"; } } } @@ -58,6 +58,8 @@ namespace sat { void model_converter::operator()(model & m) const { vector::const_iterator begin = m_entries.begin(); vector::const_iterator it = m_entries.end(); + bool first = true; + VERIFY(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; SASSERT(it->get_kind() != ELIM_VAR || m[it->var()] == l_undef); @@ -70,14 +72,18 @@ namespace sat { for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause - elim_stack* s = it->m_elim_stack[index]; + elim_stack* st = it->m_elim_stack[index]; if (!sat) { m[it->var()] = var_sign ? l_false : l_true; } - if (s) { - process_stack(m, clause, s->stack()); + if (st) { + process_stack(m, clause, st->stack()); } sat = false; + if (first && m_solver && !m_solver->check_clauses(m)) { + display(std::cout, *it) << "\n"; + first = false; + } ++index; clause.reset(); continue; @@ -95,8 +101,12 @@ namespace sat { else if (!sat && v != it->var() && m[v] == l_undef) { // clause can be satisfied by assigning v. m[v] = sign ? l_false : l_true; - // if (v == 258007) std::cout << "set undef " << v << " to " << m[v] << " in " << clause << "\n"; + // if (first) std::cout << "set: " << l << "\n"; sat = true; + if (first && m_solver && !m_solver->check_clauses(m)) { + display(std::cout, *it) << "\n";; + first = false; + } } } DEBUG_CODE({ @@ -217,10 +227,12 @@ namespace sat { it2++; for (; it2 != end; ++it2) { SASSERT(it2->var() != it->var()); + if (it2->var() == it->var()) return false; for (literal l : it2->m_clauses) { CTRACE("sat_model_converter", l.var() == it->var(), tout << "var: " << it->var() << "\n"; display(tout);); SASSERT(l.var() != it->var()); SASSERT(l == null_literal || l.var() < num_vars); + if (it2->var() == it->var()) return false; } } } @@ -229,31 +241,105 @@ namespace sat { } void model_converter::display(std::ostream & out) const { - out << "(sat::model-converter"; + out << "(sat::model-converter\n"; + bool first = true; for (auto & entry : m_entries) { - out << "\n (" << (entry.get_kind() == ELIM_VAR ? "elim" : "blocked") << " " << entry.var(); - bool start = true; - for (literal l : entry.m_clauses) { - if (start) { - out << "\n ("; - start = false; - } - else { - if (l != null_literal) - out << " "; - } - if (l == null_literal) { - out << ")"; - start = true; - continue; - } - out << l; - } - out << ")"; + if (first) first = false; else out << "\n"; + display(out, entry); } out << ")\n"; } + std::ostream& model_converter::display(std::ostream& out, entry const& entry) const { + out << " ("; + switch (entry.get_kind()) { + case ELIM_VAR: out << "elim"; break; + case BLOCK_LIT: out << "blocked"; break; + case CCE: out << "cce"; break; + case ACCE: out << "acce"; break; + } + out << " " << entry.var(); + bool start = true; + unsigned index = 0; + for (literal l : entry.m_clauses) { + if (start) { + out << "\n ("; + start = false; + } + else { + if (l != null_literal) + out << " "; + } + if (l == null_literal) { + out << ")"; + start = true; + elim_stack* st = entry.m_elim_stack[index]; + if (st) { + elim_stackv const& stack = st->stack(); + unsigned sz = stack.size(); + for (unsigned i = sz; i-- > 0; ) { + out << "\n " << stack[i].first << " " << stack[i].second; + } + } + ++index; + continue; + } + out << l; + } + out << ")"; + for (literal l : entry.m_clauses) { + if (l != null_literal) { + if (m_solver && m_solver->was_eliminated(l.var())) out << "\neliminated: " << l; + } + } + return out; + } + + void model_converter::validate_is_blocked(entry const& e, clause const& c) { + if (c.is_blocked() || c.is_learned()) return; + unsigned index = 0; + literal lit = null_literal; + bool_var v = e.var(); + for (literal l : c) { + if (l.var() == v) { + lit = l; + break; + } + } + if (lit == null_literal) return; + + bool sat = false; + for (literal l : e.m_clauses) { + if (l == null_literal) { + if (!sat) { + display(std::cout << "clause is not blocked\n", e) << "\n"; + std::cout << c << "\n"; + } + sat = false; + elim_stack* st = e.m_elim_stack[index]; + if (st) { + elim_stackv const& stack = st->stack(); + unsigned sz = stack.size(); + for (unsigned i = sz; i-- > 0; ) { + // verify ... + } + + } + ++index; + continue; + } + if (sat) { + continue; + } + if (l.var() == v) { + sat = l == lit; + } + else { + sat = c.contains(~l); + } + } + } + void model_converter::copy(model_converter const & src) { reset(); m_entries.append(src.m_entries); diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index dcbe450a8..cdd8c60ed 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -36,6 +36,9 @@ namespace sat { This is a low-level model_converter. Given a mapping from bool_var to expr, it can be converted into a general Z3 model_converter */ + + class solver; + class model_converter { public: @@ -55,11 +58,11 @@ namespace sat { elim_stackv const& stack() const { return m_stack; } }; - enum kind { ELIM_VAR = 0, BLOCK_LIT }; + enum kind { ELIM_VAR = 0, BLOCK_LIT, CCE, ACCE }; class entry { friend class model_converter; - unsigned m_var:31; - unsigned m_kind:1; + unsigned m_var:30; + unsigned m_kind:2; literal_vector m_clauses; // the different clauses are separated by null_literal sref_vector m_elim_stack; entry(kind k, bool_var v):m_var(v), m_kind(k) {} @@ -75,12 +78,18 @@ namespace sat { }; private: vector m_entries; + solver const* m_solver; void process_stack(model & m, literal_vector const& clause, elim_stackv const& stack) const; + std::ostream& display(std::ostream & out, entry const& entry) const; + + void validate_is_blocked(entry const& e, clause const& c); + public: model_converter(); ~model_converter(); + void set_solver(solver const* s) { m_solver = s; } void operator()(model & m) const; model_converter& operator=(model_converter const& other); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index d803617f5..6be3b35ba 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -28,7 +28,8 @@ def_module_params('sat', ('threads', UINT, 1, 'number of parallel threads to use'), ('dimacs.core', BOOL, False, 'extract core from DIMACS benchmarks'), ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), - ('drat.check', BOOL, False, 'build up internal proof and check'), + ('drat.check_unsat', BOOL, False, 'build up internal proof and check'), + ('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'), ('cardinality.solver', BOOL, False, 'use cardinality solver'), ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), ('xor.solver', BOOL, False, 'use xor solver'), diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 544ef1f66..089c5c55f 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -107,7 +107,7 @@ namespace sat { frame & fr = frames.back(); unsigned l_idx = fr.m_lidx; if (!fr.m_first) { - SASSERT(fr.m_it->is_binary_clause()); + SASSERT(fr.m_it->is_binary_unblocked_clause()); // after visiting child literal l2 = fr.m_it->get_literal(); unsigned l2_idx = l2.index(); @@ -118,7 +118,7 @@ namespace sat { } fr.m_first = false; while (fr.m_it != fr.m_end) { - if (!fr.m_it->is_binary_clause()) { + if (!fr.m_it->is_binary_unblocked_clause()) { fr.m_it++; continue; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 09cb063f5..57ecc5bac 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -201,18 +201,19 @@ namespace sat { CASSERT("sat_solver", s.check_invariant()); m_need_cleanup = false; m_use_list.init(s.num_vars()); - m_learned_in_use_lists = false; + m_learned_in_use_lists = learned; if (learned) { register_clauses(s.m_learned); - m_learned_in_use_lists = true; } register_clauses(s.m_clauses); - if (!learned && (bce_enabled() || bca_enabled())) + if (bce_enabled() || abce_enabled() || bca_enabled()) { elim_blocked_clauses(); + } - if (!learned) + if (!learned) { m_num_calls++; + } m_sub_counter = m_subsumption_limit; m_elim_counter = m_res_limit; @@ -457,7 +458,7 @@ namespace sat { literal_vector::iterator l_it = m_bs_ls.begin(); for (; it != end; ++it, ++l_it) { clause & c2 = *(*it); - if (!c2.was_removed() && *l_it == null_literal) { + if (!c2.was_removed() && !c1.is_blocked() && *l_it == null_literal) { // c2 was subsumed if (c1.is_learned() && !c2.is_learned()) c1.unset_learned(); @@ -713,7 +714,7 @@ namespace sat { // should not traverse wlist using iterators, since back_subsumption1 may add new binary clauses there for (unsigned j = 0; j < wlist.size(); j++) { watched w = wlist[j]; - if (w.is_binary_clause()) { + if (w.is_binary_unblocked_clause()) { literal l2 = w.get_literal(); if (l.index() < l2.index()) { m_dummy.set(l, l2, w.is_learned()); @@ -959,8 +960,10 @@ namespace sat { void operator()() { if (s.bce_enabled()) block_clauses(); + if (s.abce_enabled()) + cce(); if (s.cce_enabled()) - cce(); + cce(); if (s.bca_enabled()) bca(); } @@ -1053,21 +1056,22 @@ namespace sat { for (watched & w : s.get_wlist(l)) { // when adding a blocked clause, then all non-learned clauses have to be considered for the // resolution intersection. - bool process_bin = adding ? (w.is_binary_clause() && !w.is_learned()) : w.is_binary_unblocked_clause(); + bool process_bin = adding ? w.is_binary_clause() : w.is_binary_unblocked_clause(); if (process_bin) { literal lit = w.get_literal(); - if (s.is_marked(~lit) && lit != ~l) continue; + if (s.is_marked(~lit) && lit != ~l) { + continue; // tautology + } if (!first || s.is_marked(lit)) { inter.reset(); - return false; + return false; // intersection is empty or does not add anything new. } first = false; inter.push_back(lit); } } clause_use_list & neg_occs = s.m_use_list.get(~l); - clause_use_list::iterator it = neg_occs.mk_iterator(); - for (; !it.at_end(); it.next()) { + for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) { bool tautology = false; clause & c = it.curr(); if (c.is_blocked() && !adding) continue; @@ -1098,6 +1102,30 @@ namespace sat { return first; } + bool check_abce_tautology(literal l) { + if (!process_var(l.var())) return false; + for (watched & w : s.get_wlist(l)) { + if (w.is_binary_unblocked_clause()) { + literal lit = w.get_literal(); + if (!s.is_marked(~lit) || lit == ~l) return false; + } + } + clause_use_list & neg_occs = s.m_use_list.get(~l); + for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) { + clause & c = it.curr(); + if (c.is_blocked()) continue; + bool tautology = false; + for (literal lit : c) { + if (s.is_marked(~lit) && lit != ~l) { + tautology = true; + break; + } + } + if (!tautology) return false; + } + return true; + } + /* * C \/ l l \/ lit * ------------------- @@ -1146,59 +1174,101 @@ namespace sat { return false; } - bool cla(literal& blocked) { + bool above_threshold(unsigned sz0) const { + return sz0 * 10 < m_covered_clause.size(); + } + + template + bool cla(literal& blocked, model_converter::kind& k) { bool is_tautology = false; for (literal l : m_covered_clause) s.mark_visited(l); unsigned num_iterations = 0, sz; m_elim_stack.reset(); m_ala_qhead = 0; + k = model_converter::CCE; + unsigned sz0 = m_covered_clause.size(); + + /* + * For blocked clause elimination with asymmetric literal addition (ABCE) + * it suffices to check if one of the original + * literals in the clause is blocked modulo the additional literals added to the clause. + * So we record sz0, the original set of literals in the clause, mark additional literals, + * and then check if any of the first sz0 literals are blocked. + */ + if (s.abce_enabled() && !use_ri) { + add_ala(); + for (unsigned i = 0; i < sz0; ++i) { + if (check_abce_tautology(m_covered_clause[i])) { + blocked = m_covered_clause[i]; + is_tautology = true; + break; + } + } + k = model_converter::BLOCK_LIT; // actually ABCE + for (literal l : m_covered_clause) s.unmark_visited(l); + m_covered_clause.shrink(sz0); + return is_tautology; + } + + /* + * For CCE we add the resolution intersection while checking if the clause becomes a tautology. + * For ACCE, in addition, we add literals. + */ do { do { + if (above_threshold(sz0)) break; ++num_iterations; sz = m_covered_clause.size(); is_tautology = add_cla(blocked); } while (m_covered_clause.size() > sz && !is_tautology); + if (above_threshold(sz0)) break; if (s.acce_enabled() && !is_tautology) { sz = m_covered_clause.size(); add_ala(); + k = model_converter::ACCE; } } while (m_covered_clause.size() > sz && !is_tautology); + // if (is_tautology) std::cout << num_iterations << " " << m_covered_clause.size() << " " << sz0 << " " << is_tautology << " " << m_elim_stack.size() << "\n"; for (literal l : m_covered_clause) s.unmark_visited(l); - // if (is_tautology) std::cout << "taut: " << num_iterations << " " << m_covered_clause.size() << " " << m_elim_stack.size() << "\n"; - return is_tautology; + return is_tautology && !above_threshold(sz0); } // perform covered clause elimination. // first extract the covered literal addition (CLA). // then check whether the CLA is blocked. - bool cce(clause& c, literal& blocked) { + template + bool cce(clause& c, literal& blocked, model_converter::kind& k) { m_covered_clause.reset(); for (literal l : c) m_covered_clause.push_back(l); - return cla(blocked); + return cla(blocked, k); } - bool cce(literal l1, literal l2, literal& blocked) { + template + bool cce(literal l1, literal l2, literal& blocked, model_converter::kind& k) { m_covered_clause.reset(); m_covered_clause.push_back(l1); m_covered_clause.push_back(l2); - return cla(blocked); + return cla(blocked, k); } + template void cce() { insert_queue(); - cce_clauses(); - cce_binary(); + cce_clauses(); + cce_binary(); } + template void cce_binary() { while (!m_queue.empty() && m_counter >= 0) { s.checkpoint(); - process_cce_binary(m_queue.next()); + process_cce_binary(m_queue.next()); } } + template void process_cce_binary(literal l) { literal blocked = null_literal; watch_list & wlist = s.get_wlist(~l); @@ -1206,15 +1276,15 @@ namespace sat { watch_list::iterator it = wlist.begin(); watch_list::iterator it2 = it; watch_list::iterator end = wlist.end(); - + model_converter::kind k; for (; it != end; ++it) { if (!it->is_binary_clause() || it->is_blocked()) { INC(); continue; } literal l2 = it->get_literal(); - if (cce(l, l2, blocked)) { - block_covered_binary(it, l, blocked); + if (cce(l, l2, blocked, k)) { + block_covered_binary(it, l, blocked, k); s.m_num_covered_clauses++; } else { @@ -1225,13 +1295,15 @@ namespace sat { } + template void cce_clauses() { m_to_remove.reset(); literal blocked; + model_converter::kind k; for (clause* cp : s.s.m_clauses) { clause& c = *cp; - if (!c.was_removed() && !c.is_blocked() && cce(c, blocked)) { - block_covered_clause(c, blocked); + if (!c.was_removed() && !c.is_blocked() && cce(c, blocked, k)) { + block_covered_clause(c, blocked, k); s.m_num_covered_clauses++; } } @@ -1242,10 +1314,10 @@ namespace sat { } - void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry) { + void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); if (new_entry == 0) - new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); + new_entry = &(mc.mk(k, l.var())); m_to_remove.push_back(&c); for (literal lit : c) { if (lit != l && process_var(lit.var())) { @@ -1255,19 +1327,19 @@ namespace sat { } void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { - prepare_block_clause(c, l, new_entry); + prepare_block_clause(c, l, new_entry, model_converter::BLOCK_LIT); mc.insert(*new_entry, c); } - void block_covered_clause(clause& c, literal l) { + void block_covered_clause(clause& c, literal l, model_converter::kind k) { model_converter::entry * new_entry = 0; - prepare_block_clause(c, l, new_entry); + prepare_block_clause(c, l, new_entry, k); mc.insert(*new_entry, m_covered_clause, m_elim_stack); } - void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry) { + void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) { if (new_entry == 0) - new_entry = &(mc.mk(model_converter::BLOCK_LIT, blocked.var())); + new_entry = &(mc.mk(k, blocked.var())); literal l2 = it->get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); if (s.m_retain_blocked_clauses && !it->is_learned()) { @@ -1281,13 +1353,13 @@ namespace sat { } void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { - prepare_block_binary(it, l, l, new_entry); + prepare_block_binary(it, l, l, new_entry, model_converter::BLOCK_LIT); mc.insert(*new_entry, l, it->get_literal()); } - void block_covered_binary(watch_list::iterator it, literal l, literal blocked) { + void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::kind k) { model_converter::entry * new_entry = 0; - prepare_block_binary(it, l, blocked, new_entry); + prepare_block_binary(it, l, blocked, new_entry, k); mc.insert(*new_entry, m_covered_clause, m_elim_stack); } @@ -1375,10 +1447,12 @@ namespace sat { stopwatch m_watch; unsigned m_num_blocked_clauses; unsigned m_num_covered_clauses; + unsigned m_num_added_clauses; blocked_cls_report(simplifier & s): m_simplifier(s), m_num_blocked_clauses(s.m_num_blocked_clauses), - m_num_covered_clauses(s.m_num_covered_clauses) { + m_num_covered_clauses(s.m_num_covered_clauses), + m_num_added_clauses(s.m_num_bca) { m_watch.start(); } @@ -1389,6 +1463,8 @@ namespace sat { << (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses) << " :elim-covered-clauses " << (m_simplifier.m_num_covered_clauses - m_num_covered_clauses) + << " :added-clauses " + << (m_simplifier.m_num_bca - m_num_added_clauses) << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } @@ -1456,8 +1532,7 @@ namespace sat { */ void simplifier::collect_clauses(literal l, clause_wrapper_vector & r, bool include_blocked) { clause_use_list const & cs = m_use_list.get(l); - clause_use_list::iterator it = cs.mk_iterator(); - for (; !it.at_end(); it.next()) { + for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) { if (!it.curr().is_blocked() || include_blocked) { r.push_back(clause_wrapper(it.curr())); SASSERT(r.back().size() == it.curr().size()); @@ -1703,6 +1778,7 @@ namespace sat { else s.m_stats.m_mk_clause++; clause * new_c = s.m_cls_allocator.mk_clause(m_new_cls.size(), m_new_cls.c_ptr(), false); + if (s.m_config.m_drat) s.m_drat.add(*new_c, true); s.m_clauses.push_back(new_c); m_use_list.insert(*new_c); @@ -1769,6 +1845,7 @@ namespace sat { m_cce = p.cce(); m_acce = p.acce(); m_bca = p.bca(); + m_bce_delay = p.bce_delay(); m_elim_blocked_clauses = p.elim_blocked_clauses(); m_elim_blocked_clauses_at = p.elim_blocked_clauses_at(); m_retain_blocked_clauses = p.retain_blocked_clauses(); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index c75e45d79..6e120796f 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -71,9 +71,11 @@ namespace sat { int m_elim_counter; // config + bool m_abce; // block clauses using asymmetric added literals bool m_cce; // covered clause elimination bool m_acce; // cce with asymetric literal addition bool m_bca; // blocked (binary) clause addition. + unsigned m_bce_delay; bool m_elim_blocked_clauses; unsigned m_elim_blocked_clauses_at; bool m_retain_blocked_clauses; @@ -169,10 +171,11 @@ namespace sat { struct blocked_clause_elim; void elim_blocked_clauses(); - bool bce_enabled() const { return m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled(); } - bool acce_enabled() const { return m_acce; } - bool cce_enabled() const { return m_cce || acce_enabled(); } - bool bca_enabled() const { return m_bca; } + bool bce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled()); } + bool acce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce; } + bool cce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); } + bool abce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; } + bool bca_enabled() const { return m_bca && m_learned_in_use_lists; } bool elim_vars_bdd_enabled() const { return m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay; } bool elim_vars_enabled() const { return m_elim_vars; } diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index 6528e6699..4cbd80788 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -2,10 +2,12 @@ def_module_params(module_name='sat', class_name='sat_simplifier_params', export=True, params=(('elim_blocked_clauses', BOOL, False, 'eliminate blocked clauses'), + ('abce', BOOL, BOOL, False, 'eliminate blocked clauses using asymmmetric literals'), ('cce', BOOL, False, 'eliminate covered clauses'), ('acce', BOOL, False, 'eliminate covered clauses using asymmetric added literals'), ('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), ('bca', BOOL, False, 'blocked clause addition - add blocked binary clauses'), + ('bce_delay', UINT, 0, 'delay eliminate blocked clauses until simplification round'), ('retain_blocked_clauses', BOOL, False, 'retain blocked clauses for propagation, hide them from variable elimination'), ('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'), ('resolution.limit', UINT, 500000000, 'approx. maximum number of literals visited during variable elimination'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1f0015476..0fb4dce93 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -23,14 +23,11 @@ Revision History: #include "util/luby.h" #include "util/trace.h" #include "util/max_cliques.h" +#include "util/gparams.h" // define to update glue during propagation #define UPDATE_GLUE -// define to create a copy of the solver before starting the search -// useful for checking models -// #define CLONE_BEFORE_SOLVING - namespace sat { solver::solver(params_ref const & p, reslimit& l): @@ -734,15 +731,13 @@ namespace sat { case watched::CLAUSE: { if (value(it->get_blocked_literal()) == l_true) { TRACE("propagate_clause_bug", tout << "blocked literal " << it->get_blocked_literal() << "\n"; - clause_offset cls_off = it->get_clause_offset(); - clause & c = *(m_cls_allocator.get_clause(cls_off)); - tout << c << "\n";); + tout << get_clause(it) << "\n";); *it2 = *it; it2++; break; } clause_offset cls_off = it->get_clause_offset(); - clause & c = *(m_cls_allocator.get_clause(cls_off)); + clause & c = get_clause(cls_off); TRACE("propagate_clause_bug", tout << "processing... " << c << "\nwas_removed: " << c.was_removed() << "\n";); if (c[0] == not_l) std::swap(c[0], c[1]); @@ -886,12 +881,10 @@ namespace sat { return check_par(num_lits, lits); } flet _searching(m_searching, true); -#ifdef CLONE_BEFORE_SOLVING - if (m_mc.empty()) { - m_clone = alloc(solver, m_params); - SASSERT(m_clone); + if (m_mc.empty() && gparams::get().get_bool("model_validate", false)) { + m_clone = alloc(solver, m_params, m_rlimit); + m_clone->copy(*this); } -#endif try { init_search(); if (inconsistent()) return l_false; @@ -1548,30 +1541,40 @@ namespace sat { m_model[v] = value(v); } TRACE("sat_mc_bug", m_mc.display(tout);); - m_mc(m_model); - TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); -// #ifndef _EXTERNAL_RELEASE IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";); - if (!check_model(m_model)) { + if (!check_clauses(m_model)) { UNREACHABLE(); throw solver_exception("check model failed"); } + + if (m_config.m_drat) m_drat.check_model(m_model); + + // m_mc.set_solver(this); + m_mc(m_model); + + + if (!check_clauses(m_model)) { + std::cout << "failure checking clauses on transformed model\n"; + UNREACHABLE(); + throw solver_exception("check model failed"); + } + + TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); if (m_clone) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model (on original set of clauses)\"\n";); if (!m_clone->check_model(m_model)) throw solver_exception("check model failed (for cloned solver)"); } -// #endif } - bool solver::check_model(model const & m) const { + bool solver::check_clauses(model const& m) const { bool ok = true; for (clause const* cp : m_clauses) { clause const & c = *cp; if (!c.satisfied_by(m) && !c.is_blocked()) { - IF_VERBOSE(0, verbose_stream() << "model check failed: " << c << "\n";); + IF_VERBOSE(0, verbose_stream() << "failed clause " << c.id() << ": " << c << "\n";); TRACE("sat", tout << "failed: " << c << "\n"; tout << "assumptions: " << m_assumptions << "\n"; tout << "trail: " << m_trail << "\n"; @@ -1612,10 +1615,16 @@ namespace sat { ok = false; } } + return ok; + } + + bool solver::check_model(model const & m) const { + bool ok = check_clauses(m); if (ok && !m_mc.check_model(m)) { ok = false; TRACE("sat", tout << "model: " << m << "\n"; m_mc.display(tout);); } + IF_VERBOSE(1, verbose_stream() << "model check " << (ok?"OK":"failed") << "\n";); return ok; } @@ -2034,7 +2043,7 @@ namespace sat { process_antecedent(~(js.get_literal2()), num_marks); break; case justification::CLAUSE: { - clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); + clause & c = get_clause(js); unsigned i = 0; if (consequent != null_literal) { SASSERT(c[0] == consequent || c[1] == consequent); @@ -2153,7 +2162,7 @@ namespace sat { process_antecedent_for_unsat_core(~(js.get_literal2())); break; case justification::CLAUSE: { - clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); + clause & c = get_clause(js); unsigned i = 0; if (consequent != null_literal) { SASSERT(c[0] == consequent || c[1] == consequent); @@ -2497,7 +2506,7 @@ namespace sat { } break; case justification::CLAUSE: { - clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); + clause & c = get_clause(js); unsigned i = 0; if (c[0].var() == var) { i = 1; @@ -2624,8 +2633,7 @@ namespace sat { unsigned sz = m_lemma.size(); SASSERT(!is_marked(m_lemma[0].var())); mark(m_lemma[0].var()); - for (unsigned i = m_lemma.size(); i > 0; ) { - --i; + for (unsigned i = m_lemma.size(); i-- > 0; ) { justification js = m_justification[m_lemma[i].var()]; switch (js.get_kind()) { case justification::NONE: @@ -2638,9 +2646,9 @@ namespace sat { update_lrb_reasoned(js.get_literal2()); break; case justification::CLAUSE: { - clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); - for (unsigned i = 0; i < c.size(); ++i) { - update_lrb_reasoned(c[i]); + clause & c = get_clause(js); + for (literal l : c) { + update_lrb_reasoned(l); } break; } @@ -3045,6 +3053,7 @@ namespace sat { m_scc.updt_params(p); m_rand.set_seed(m_config.m_random_seed); m_step_size = m_config.m_step_size_init; + m_drat.updt_config(); } void solver::collect_param_descrs(param_descrs & d) { @@ -3199,7 +3208,7 @@ namespace sat { std::ostream& solver::display_justification(std::ostream & out, justification const& js) const { out << js; if (js.is_clause()) { - out << *(m_cls_allocator.get_clause(js.get_clause_offset())); + out << get_clause(js); } else if (js.is_ext_justification() && m_ext) { m_ext->display_justification(out << " ", js.get_ext_justification_idx()); @@ -3845,11 +3854,11 @@ namespace sat { s |= m_antecedents.find(js.get_literal2().var()); break; case justification::CLAUSE: { - clause & c = *(m_cls_allocator.get_clause(js.get_clause_offset())); - for (unsigned i = 0; i < c.size(); ++i) { - if (c[i] != lit) { - if (check_domain(lit, ~c[i]) && all_found) { - s |= m_antecedents.find(c[i].var()); + clause & c = get_clause(js); + for (literal l : c) { + if (l != lit) { + if (check_domain(lit, ~l) && all_found) { + s |= m_antecedents.find(l.var()); } else { all_found = false; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 2c5a04104..e7dae93a2 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -366,6 +366,7 @@ namespace sat { model_converter const & get_model_converter() const { return m_mc; } void set_model(model const& mdl); char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } + bool check_clauses(model const& m) const; literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); lbool cube(bool_var_vector const& vars, literal_vector& lits); @@ -442,6 +443,20 @@ namespace sat { justification const & jst = m_justification[l0.var()]; return !jst.is_clause() || m_cls_allocator.get_clause(jst.get_clause_offset()) != &c; } + + clause& get_clause(watch_list::iterator it) const { + SASSERT(it->get_kind() == watched::CLAUSE); + return get_clause(it->get_clause_offset()); + } + + clause& get_clause(justification const& j) const { + SASSERT(j.is_clause()); + return get_clause(j.get_clause_offset()); + } + + clause& get_clause(clause_offset cls_off) const { + return *(m_cls_allocator.get_clause(cls_off)); + } // ----------------------- // diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 742f9e103..5cf16ccc7 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -180,7 +180,13 @@ public: m_internalized_converted = false; init_reason_unknown(); - r = m_solver.check(m_asms.size(), m_asms.c_ptr()); + try { + r = m_solver.check(m_asms.size(), m_asms.c_ptr()); + } + catch (z3_exception& ex) { + IF_VERBOSE(10, verbose_stream() << "exception: " << ex.msg() << "\n";); + r = l_undef; + } if (r == l_undef && m_solver.get_config().m_dimacs_display) { for (auto const& kv : m_map) { std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, m) << "\n"; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 208d60386..1270b67c2 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -896,6 +896,7 @@ struct sat2goal::imp { public: sat_model_converter(ast_manager & m, sat::solver const & s):m_var2expr(m) { m_mc.copy(s.get_model_converter()); + m_mc.set_solver(&s); m_fmc = alloc(filter_model_converter, m); } From ba53fc12304fe936c338591bcb143286903cfc2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Oct 2017 17:29:26 -0700 Subject: [PATCH 0309/1283] fix scc omitting blocked clauses Signed-off-by: Nikolaj Bjorner --- src/ast/ast_pp_util.cpp | 8 ++++---- src/ast/ast_smt_pp.cpp | 37 ++++++++++++++++++++----------------- src/ast/ast_smt_pp.h | 8 +++++--- src/ast/ast_translation.cpp | 2 +- src/sat/sat_clause.h | 4 ++-- src/sat/sat_scc.cpp | 4 ++-- 6 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 677422b8a..455addf73 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -55,17 +55,17 @@ void ast_pp_util::display_decls(std::ostream& out) { void ast_pp_util::display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat) { if (neat) { smt2_pp_environment_dbg env(m); - for (unsigned i = 0; i < fmls.size(); ++i) { + for (expr* f : fmls) { out << "(assert "; - ast_smt2_pp(out, fmls[i], env); + ast_smt2_pp(out, f, env); out << ")\n"; } } else { ast_smt_pp ll_smt2_pp(m); - for (unsigned i = 0; i < fmls.size(); ++i) { + for (expr* f : fmls) { out << "(assert "; - ll_smt2_pp.display_expr_smt2(out, fmls[i]); + ll_smt2_pp.display_expr_smt2(out, f); out << ")\n"; } } diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 906fd054b..189d305fc 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -124,16 +124,19 @@ bool smt_renaming::all_is_legal(char const* s) { smt_renaming::smt_renaming() { for (unsigned i = 0; i < ARRAYSIZE(m_predef_names); ++i) { symbol s(m_predef_names[i]); - m_translate.insert(s, s); + m_translate.insert(s, sym_b(s, false)); m_rev_translate.insert(s, s); } } -symbol smt_renaming::get_symbol(symbol s0) { +symbol smt_renaming::get_symbol(symbol s0, bool is_skolem) { + sym_b sb; symbol s; - if (m_translate.find(s0, s)) { - return s; + if (m_translate.find(s0, sb)) { + if (is_skolem == sb.is_skolem) + return sb.name; + NOT_IMPLEMENTED_YET(); } int k = 0; @@ -141,7 +144,7 @@ symbol smt_renaming::get_symbol(symbol s0) { s = fix_symbol(s0, k++); } while (m_rev_translate.contains(s)); - m_translate.insert(s0, s); + m_translate.insert(s0, sym_b(s, is_skolem)); m_rev_translate.insert(s, s0); return s; } @@ -202,7 +205,7 @@ class smt_printer { } void pp_decl(func_decl* d) { - symbol sym = m_renaming.get_symbol(d->get_name()); + symbol sym = m_renaming.get_symbol(d->get_name(), d->is_skolem()); if (d->get_family_id() == m_dt_fid) { datatype_util util(m_manager); if (util.is_recognizer(d)) { @@ -313,7 +316,7 @@ class smt_printer { if (num_sorts > 0) { m_out << "("; } - m_out << m_renaming.get_symbol(s->get_name()); + m_out << m_renaming.get_symbol(s->get_name(), false); if (num_sorts > 0) { for (unsigned i = 0; i < num_sorts; ++i) { m_out << " "; @@ -324,7 +327,7 @@ class smt_printer { return; } else { - sym = m_renaming.get_symbol(s->get_name()); + sym = m_renaming.get_symbol(s->get_name(), false); } visit_params(true, sym, s->get_num_parameters(), s->get_parameters()); } @@ -396,17 +399,17 @@ class smt_printer { else if (m_manager.is_label(n, pos, names) && names.size() >= 1) { m_out << "(! "; pp_marked_expr(n->get_arg(0)); - m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")"; + m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0], false) << ")"; } else if (m_manager.is_label_lit(n, names) && names.size() >= 1) { - m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0]) << ")"; + m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0], false) << ")"; } else if (num_args == 0) { if (decl->private_parameters()) { - m_out << m_renaming.get_symbol(decl->get_name()); + m_out << m_renaming.get_symbol(decl->get_name(), decl->is_skolem()); } else { - symbol sym = m_renaming.get_symbol(decl->get_name()); + symbol sym = m_renaming.get_symbol(decl->get_name(), decl->is_skolem()); visit_params(false, sym, decl->get_num_parameters(), decl->get_parameters()); } } @@ -500,7 +503,7 @@ class smt_printer { for (unsigned i = 0; i < q->get_num_decls(); ++i) { sort* s = q->get_decl_sort(i); m_out << "("; - print_bound(m_renaming.get_symbol(q->get_decl_name(i))); + print_bound(m_renaming.get_symbol(q->get_decl_name(i), false)); m_out << " "; visit_sort(s, true); m_out << ") "; @@ -565,7 +568,7 @@ class smt_printer { unsigned num_decls = q->get_num_decls(); if (idx < num_decls) { unsigned offs = num_decls-idx-1; - symbol name = m_renaming.get_symbol(q->get_decl_name(offs)); + symbol name = m_renaming.get_symbol(q->get_decl_name(offs), false); print_bound(name); return; } @@ -807,15 +810,15 @@ public: m_out << ")"; } m_out << "("; - m_out << m_renaming.get_symbol(d->name()); + m_out << m_renaming.get_symbol(d->name(), false); m_out << " "; bool first_constr = true; for (datatype::constructor* f : *d) { if (!first_constr) m_out << " "; else first_constr = false; m_out << "("; - m_out << m_renaming.get_symbol(f->name()); + m_out << m_renaming.get_symbol(f->name(), false); for (datatype::accessor* a : *f) { - m_out << " (" << m_renaming.get_symbol(a->name()) << " "; + m_out << " (" << m_renaming.get_symbol(a->name(), false) << " "; visit_sort(a->range()); m_out << ")"; } diff --git a/src/ast/ast_smt_pp.h b/src/ast/ast_smt_pp.h index dd2a6d753..766c8530c 100644 --- a/src/ast/ast_smt_pp.h +++ b/src/ast/ast_smt_pp.h @@ -24,8 +24,10 @@ Revision History: #include "util/map.h" class smt_renaming { + struct sym_b { symbol name; bool is_skolem; sym_b(symbol n, bool s): name(n), is_skolem(s) {} sym_b():name(),is_skolem(false) {}}; typedef map symbol2symbol; - symbol2symbol m_translate; + typedef map symbol2sym_b; + symbol2sym_b m_translate; symbol2symbol m_rev_translate; symbol fix_symbol(symbol s, int k); @@ -35,8 +37,8 @@ class smt_renaming { bool all_is_legal(char const* s); public: smt_renaming(); - symbol get_symbol(symbol s0); - symbol operator()(symbol const & s) { return get_symbol(s); } + symbol get_symbol(symbol s0, bool is_skolem = false); + symbol operator()(symbol const & s, bool is_skolem = false) { return get_symbol(s, is_skolem); } }; class ast_smt_pp { diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index 1bce4bcbe..0599ec91d 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -160,7 +160,7 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) { new_fi.set_chainable(fi->is_chainable()); new_fi.set_pairwise(fi->is_pairwise()); new_fi.set_injective(fi->is_injective()); - new_fi.set_skolem(fi->is_skolem()); +/// TBD new_fi.set_skolem(fi->is_skolem()); new_fi.set_idempotent(fi->is_idempotent()); new_f = m_to_manager.mk_func_decl(f->get_name(), diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index dd8028ec2..dd7af64eb 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -65,8 +65,8 @@ namespace sat { literal & operator[](unsigned idx) { SASSERT(idx < m_size); return m_lits[idx]; } literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; } bool is_learned() const { return m_learned; } - void unset_learned() { if (id() == 642277) std::cout << "unlearn " << *this << "\n"; SASSERT(is_learned()); m_learned = false; } - void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); if (id() == 642277) std::cout << "shrink " << *this << "\n"; } } + void unset_learned() { SASSERT(is_learned()); m_learned = false; } + void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); } } bool strengthened() const { return m_strengthened; } void mark_strengthened() { m_strengthened = true; update_approx(); } void unmark_strengthened() { m_strengthened = false; } diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 089c5c55f..544ef1f66 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -107,7 +107,7 @@ namespace sat { frame & fr = frames.back(); unsigned l_idx = fr.m_lidx; if (!fr.m_first) { - SASSERT(fr.m_it->is_binary_unblocked_clause()); + SASSERT(fr.m_it->is_binary_clause()); // after visiting child literal l2 = fr.m_it->get_literal(); unsigned l2_idx = l2.index(); @@ -118,7 +118,7 @@ namespace sat { } fr.m_first = false; while (fr.m_it != fr.m_end) { - if (!fr.m_it->is_binary_unblocked_clause()) { + if (!fr.m_it->is_binary_clause()) { fr.m_it++; continue; } From 2774d6896b6766f34507eb2b3e6ab1ab9fce24f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 Oct 2017 16:11:29 -0700 Subject: [PATCH 0310/1283] fix variable naming bug for internal (fresh) constants clashing with external names Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 24 +++++------------------- src/ast/ast_smt2_pp.h | 4 +++- src/ast/ast_smt_pp.cpp | 16 +++++++++++++--- src/cmd_context/cmd_context.cpp | 4 ++-- src/sat/ba_solver.cpp | 4 ++-- 5 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index e4a875005..e093dc2ff 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -31,25 +31,11 @@ using namespace format_ns; #define MAX_INDENT 16 #define SMALL_INDENT 2 -format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len) const { +format * smt2_pp_environment::pp_fdecl_name(symbol const & s0, unsigned & len, bool is_skolem) const { ast_manager & m = get_manager(); - if (is_smt2_quoted_symbol(s)) { - std::string str = mk_smt2_quoted_symbol(s); - len = static_cast(str.length()); - return mk_string(m, str.c_str()); - } - else if (s.is_numerical()) { - std::string str = s.str(); - len = static_cast(str.length()); - return mk_string(m, str.c_str()); - } - else if (!s.bare_str()) { - return mk_string(m, "null"); - } - else { - len = static_cast(strlen(s.bare_str())); - return mk_string(m, s.bare_str()); - } + symbol s = m_renaming.get_symbol(s0, is_skolem); + len = static_cast(strlen(s.bare_str())); + return mk_string(m, s.bare_str()); } format * smt2_pp_environment::pp_fdecl_name(func_decl * f, unsigned & len) const { @@ -68,7 +54,7 @@ format * smt2_pp_environment::pp_fdecl_name(func_decl * f, unsigned & len) const } else { symbol s = f->get_name(); - return pp_fdecl_name(s, len); + return pp_fdecl_name(s, len, f->is_skolem()); } } diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 3e8b1aa39..7a0267960 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -31,10 +31,12 @@ Revision History: #include "ast/dl_decl_plugin.h" #include "ast/seq_decl_plugin.h" #include "ast/datatype_decl_plugin.h" +#include "ast/ast_smt_pp.h" #include "util/smt2_util.h" class smt2_pp_environment { protected: + mutable smt_renaming m_renaming; format_ns::format * mk_neg(format_ns::format * f) const; format_ns::format * mk_float(rational const & val) const; bool is_indexed_fdecl(func_decl * f) const; @@ -61,7 +63,7 @@ public: virtual format_ns::format * pp_string_literal(app * t); virtual format_ns::format * pp_sort(sort * s); virtual format_ns::format * pp_fdecl_ref(func_decl * f); - format_ns::format * pp_fdecl_name(symbol const & fname, unsigned & len) const; + format_ns::format * pp_fdecl_name(symbol const & fname, unsigned & len, bool is_skolem) const; format_ns::format * pp_fdecl_name(func_decl * f, unsigned & len) const; }; diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 189d305fc..f8501824a 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -70,7 +70,10 @@ symbol smt_renaming::fix_symbol(symbol s, int k) { return symbol(buffer.str().c_str()); } - if (is_smt2_quoted_symbol(s)) { + if (!s.bare_str()) { + buffer << "null"; + } + else if (is_smt2_quoted_symbol(s)) { buffer << mk_smt2_quoted_symbol(s); } else { @@ -129,14 +132,21 @@ smt_renaming::smt_renaming() { } } - +// Ensure that symbols that are used both with skolems and non-skolems are named apart. symbol smt_renaming::get_symbol(symbol s0, bool is_skolem) { sym_b sb; symbol s; if (m_translate.find(s0, sb)) { if (is_skolem == sb.is_skolem) return sb.name; - NOT_IMPLEMENTED_YET(); + int k = 0; + symbol s1; + do { + s = fix_symbol(s0, k++); + } + while (s == s0 || (m_rev_translate.find(s, s1) && s1 != s0)); + m_rev_translate.insert(s, s0); + return s; } int k = 0; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 25cb2a541..ce6c4a65a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -389,7 +389,7 @@ protected: datalog::dl_decl_util m_dlutil; format_ns::format * pp_fdecl_name(symbol const & s, func_decls const & fs, func_decl * f, unsigned & len) { - format_ns::format * f_name = smt2_pp_environment::pp_fdecl_name(s, len); + format_ns::format * f_name = smt2_pp_environment::pp_fdecl_name(s, len, f->is_skolem()); if (!fs.more_than_one()) return f_name; if (!fs.clash(f)) @@ -399,7 +399,7 @@ protected: format_ns::format * pp_fdecl_ref_core(symbol const & s, func_decls const & fs, func_decl * f) { unsigned len; - format_ns::format * f_name = smt2_pp_environment::pp_fdecl_name(s, len); + format_ns::format * f_name = smt2_pp_environment::pp_fdecl_name(s, len, f->is_skolem()); if (!fs.more_than_one()) return f_name; return pp_signature(f_name, f); diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index f963ce620..2a880f918 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1173,7 +1173,7 @@ namespace sat { break; case justification::CLAUSE: { inc_bound(offset); - clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); + clause & c = s().get_clause(js); unsigned i = 0; if (consequent != null_literal) { inc_coeff(consequent, offset); @@ -3780,7 +3780,7 @@ namespace sat { break; case justification::CLAUSE: { ineq.reset(offset); - clause & c = *(s().m_cls_allocator.get_clause(js.get_clause_offset())); + clause & c = s().get_clause(js); for (literal l : c) ineq.push(l, offset); break; } From 92b5301b7ffebccdf3a9097d9c1062dec2eae8ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 Oct 2017 08:57:24 -0700 Subject: [PATCH 0311/1283] adding Cube method to .NET API, removing lookahead and get-lemmas Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 64 ------------------- src/api/dotnet/Solver.cs | 47 +++++++------- src/api/z3_api.h | 20 ------ src/opt/opt_solver.h | 1 - src/sat/sat_simplifier.cpp | 4 +- src/sat/sat_simplifier.h | 11 ++-- src/sat/sat_solver/inc_sat_solver.cpp | 55 ---------------- src/solver/combined_solver.cpp | 4 -- src/solver/solver.h | 9 ++- src/solver/tactic2solver.cpp | 4 -- .../portfolio/bounded_int2bv_solver.cpp | 2 - src/tactic/portfolio/enum2bv_solver.cpp | 2 - src/tactic/portfolio/pb2bv_solver.cpp | 2 - 13 files changed, 38 insertions(+), 187 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 73ba5e082..f0a8c47f6 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -522,69 +522,5 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, - Z3_solver s, - Z3_ast_vector assumptions, - Z3_ast_vector candidates) { - Z3_TRY; - LOG_Z3_solver_lookahead(c, s, assumptions, candidates); - ast_manager& m = mk_c(c)->m(); - expr_ref_vector _candidates(m), _assumptions(m); - ast_ref_vector const& __candidates = to_ast_vector_ref(candidates); - ast_ref_vector const& __assumptions = to_ast_vector_ref(assumptions); - for (auto & e : __candidates) { - if (!is_expr(e)) { - SET_ERROR_CODE(Z3_INVALID_USAGE); - return 0; - } - _candidates.push_back(to_expr(e)); - } - for (auto & e : __assumptions) { - if (!is_expr(e)) { - SET_ERROR_CODE(Z3_INVALID_USAGE); - return 0; - } - _assumptions.push_back(to_expr(e)); - } - - expr_ref result(m); - unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); - unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); - bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); - cancel_eh eh(mk_c(c)->m().limit()); - api::context::set_interruptable si(*(mk_c(c)), eh); - { - scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); - scoped_timer timer(timeout, &eh); - scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); - try { - result = to_solver_ref(s)->lookahead(_assumptions, _candidates); - } - catch (z3_exception & ex) { - mk_c(c)->handle_exception(ex); - return 0; - } - } - mk_c(c)->save_ast_trail(result); - RETURN_Z3(of_ast(result)); - Z3_CATCH_RETURN(0); - } - - Z3_ast_vector Z3_API Z3_solver_get_lemmas(Z3_context c, Z3_solver s) { - Z3_TRY; - LOG_Z3_solver_get_lemmas(c, s); - RESET_ERROR_CODE(); - ast_manager& m = mk_c(c)->m(); - init_solver(c, s); - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); - mk_c(c)->save_object(v); - expr_ref_vector lemmas(m); - to_solver_ref(s)->get_lemmas(lemmas); - for (expr* e : lemmas) { - v->m_ast_vector.push_back(e); - } - RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); - } }; diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 40da086ce..c18556d0c 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -275,31 +275,6 @@ namespace Microsoft.Z3 return lboolToStatus(r); } - /// - /// Select a lookahead literal from the set of supplied candidates. - /// - public BoolExpr Lookahead(IEnumerable assumptions, IEnumerable candidates) - { - ASTVector cands = new ASTVector(Context); - foreach (var c in candidates) cands.Push(c); - ASTVector assums = new ASTVector(Context); - foreach (var c in assumptions) assums.Push(c); - return (BoolExpr)Expr.Create(Context, Native.Z3_solver_lookahead(Context.nCtx, NativeObject, assums.NativeObject, cands.NativeObject)); - } - - /// - /// Retrieve set of lemmas that have been inferred by solver. - /// - public BoolExpr[] Lemmas - { - get - { - var r = Native.Z3_solver_get_lemmas(Context.nCtx, NativeObject); - var v = new ASTVector(Context, r); - return v.ToBoolExprArray(); - } - } - /// /// The model of the last Check. /// @@ -370,6 +345,28 @@ namespace Microsoft.Z3 } } + /// + /// Return a set of cubes. + /// + public IEnumerable Cube() + { + int rounds = 0; + while (true) { + BoolExpr r = (BoolExpr)Expr.Create(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject)); + if (r.IsFalse) { + if (rounds == 0) + yield return r; + break; + } + if (r.IsTrue) { + yield return r; + break; + } + ++rounds; + yield return r; + } + } + /// /// Create a clone of the current solver with respect to ctx. /// diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 8615cd7cb..f0085f2ed 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6174,14 +6174,6 @@ extern "C" { Z3_ast_vector variables, Z3_ast_vector consequences); - /** - \brief select a literal from the list of candidate propositional variables to split on. - If the candidate list is empty, then the solver chooses a formula based on its internal state. - - def_API('Z3_solver_lookahead', AST, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(AST_VECTOR))) - */ - - Z3_ast Z3_API Z3_solver_lookahead(Z3_context c, Z3_solver s, Z3_ast_vector assumptions, Z3_ast_vector candidates); /** \brief extract a next cube for a solver. The last cube is the constant \c true or \c false. @@ -6193,18 +6185,6 @@ extern "C" { Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s); - - /** - \brief retrieve lemmas from solver state. Lemmas are auxiliary unit literals, - binary clauses and other learned clauses that are below a minimal glue level. - Lemmas that have been retrieved in a previous call may be suppressed from subsequent - calls. - - def_API('Z3_solver_get_lemmas', AST_VECTOR, (_in(CONTEXT), _in(SOLVER))) - */ - - Z3_ast_vector Z3_API Z3_solver_get_lemmas(Z3_context c, Z3_solver s); - /** \brief Retrieve the model for the last #Z3_solver_check or #Z3_solver_check_assumptions diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index a3107057a..46b52e387 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -108,7 +108,6 @@ namespace opt { virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { return expr_ref(m.mk_true(), m); } virtual expr_ref cube() { return expr_ref(m.mk_true(), m); } void set_logic(symbol const& logic); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3942f96db..820000b4c 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -90,6 +90,8 @@ namespace sat { inline void simplifier::checkpoint() { s.checkpoint(); } + bool simplifier::single_threaded() const { return s.m_config.m_num_threads == 1; } + void simplifier::register_clauses(clause_vector & cs) { std::stable_sort(cs.begin(), cs.end(), size_lt()); for (clause* c : cs) { @@ -230,7 +232,7 @@ namespace sat { subsume(); if (s.inconsistent()) return; - if (!learned && elim_vars_enabled() && s.m_config.m_num_threads == 1) + if (!learned && elim_vars_enabled()) elim_vars(); if (s.inconsistent()) return; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 6e120796f..54f8c59dd 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -75,7 +75,7 @@ namespace sat { bool m_cce; // covered clause elimination bool m_acce; // cce with asymetric literal addition bool m_bca; // blocked (binary) clause addition. - unsigned m_bce_delay; + unsigned m_bce_delay; bool m_elim_blocked_clauses; unsigned m_elim_blocked_clauses_at; bool m_retain_blocked_clauses; @@ -171,13 +171,14 @@ namespace sat { struct blocked_clause_elim; void elim_blocked_clauses(); + bool single_threaded() const; // { return s.m_config.m_num_threads == 1; } bool bce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled()); } bool acce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce; } - bool cce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); } + bool cce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); } bool abce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; } - bool bca_enabled() const { return m_bca && m_learned_in_use_lists; } - bool elim_vars_bdd_enabled() const { return m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay; } - bool elim_vars_enabled() const { return m_elim_vars; } + bool bca_enabled() const { return m_bca && m_learned_in_use_lists && single_threaded(); } + bool elim_vars_bdd_enabled() const { return m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay && single_threaded(); } + bool elim_vars_enabled() const { return m_elim_vars && single_threaded(); } unsigned get_num_unblocked_bin(literal l) const; unsigned get_to_elim_cost(bool_var v) const; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 5cf16ccc7..44dc414af 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -310,51 +310,6 @@ public: return 0; } - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead " << candidates.size() << ")\n";); - sat::bool_var_vector vars; - sat::literal_vector lits; - expr_ref_vector lit2expr(m); - lit2expr.resize(m_solver.num_vars() * 2); - m_map.mk_inv(lit2expr); - for (auto c : candidates) { - sat::bool_var v = m_map.to_bool_var(c); - if (v != sat::null_bool_var) { - vars.push_back(v); - } - } - for (auto c : assumptions) { - SASSERT(is_literal(c)); - sat::bool_var v = sat::null_bool_var; - bool sign = false; - expr* e = c; - while (m.is_not(e, e)) { - sign = !sign; - } - if (is_uninterp_const(e)) { - v = m_map.to_bool_var(e); - } - if (v != sat::null_bool_var) { - lits.push_back(sat::literal(v, sign)); - } - else { - IF_VERBOSE(0, verbose_stream() << "WARNING: could not handle " << mk_pp(c, m) << "\n";); - } - } - if (vars.empty()) { - return expr_ref(m.mk_true(), m); - } - sat::literal l = m_solver.select_lookahead(lits, vars); - if (m_solver.inconsistent()) { - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead inconsistent)\n";); - return expr_ref(m.mk_false(), m); - } - if (l == sat::null_literal) { - return expr_ref(m.mk_true(), m); - } - expr_ref result(lit2expr[l.index()].get(), m); - return result; - } virtual expr_ref cube() { if (!m_internalized) { dep2asm_t dep2asm; @@ -386,16 +341,6 @@ public: return mk_and(fmls); } - virtual void get_lemmas(expr_ref_vector & lemmas) { - if (!m_internalized) return; - sat2goal s2g; - goal g(m, false, false, false); - s2g.get_learned(m_solver, m_map, m_params, lemmas); - IF_VERBOSE(1, verbose_stream() << "(sat :lemmas " << lemmas.size() << ")\n";); - // TBD: handle externals properly. - } - - virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { init_preprocess(); TRACE("sat", tout << assumptions << "\n" << vars << "\n";); diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index a67fd724d..9a685d5b3 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -280,10 +280,6 @@ public: return m_solver1->get_num_assumptions() + m_solver2->get_num_assumptions(); } - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { - return m_solver1->lookahead(assumptions, candidates); - } - virtual expr_ref cube() { return m_solver1->cube(); } diff --git a/src/solver/solver.h b/src/solver/solver.h index abd9b01f2..6171f111f 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -182,18 +182,21 @@ public: \brief extract a lookahead candidates for branching. */ - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) = 0; + virtual expr_ref cube() = 0; +#if 0 /** \brief extract a lookahead candidates for branching. */ - virtual expr_ref cube() = 0; + virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) = 0; + /** \brief extract learned lemmas. */ virtual void get_lemmas(expr_ref_vector& lemmas) {} +#endif /** \brief Display the content of this solver. @@ -217,4 +220,6 @@ protected: }; +typedef ref solver_ref; + #endif diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 7d9388f50..0286197fa 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -77,10 +77,6 @@ public: virtual ast_manager& get_manager() const; - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { - ast_manager& m = get_manager(); - return expr_ref(m.mk_true(), m); - } virtual expr_ref cube() { ast_manager& m = get_manager(); return expr_ref(m.mk_true(), m); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index ec83766a0..db8a1fe53 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -162,9 +162,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(assumptions, candidates); } virtual expr_ref cube() { flush_assertions(); return m_solver->cube(); } - virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 6288223fa..c5c7e3028 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -108,9 +108,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { return m_solver->lookahead(assumptions, candidates); } virtual expr_ref cube() { return m_solver->cube(); } - virtual void get_lemmas(expr_ref_vector & lemmas) { m_solver->get_lemmas(lemmas); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { datatype_util dt(m); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index ee4b14178..4ff7251be 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -98,9 +98,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { flush_assertions(); return m_solver->lookahead(assumptions, candidates); } virtual expr_ref cube() { flush_assertions(); return m_solver->cube(); } - virtual void get_lemmas(expr_ref_vector & lemmas) { flush_assertions(); m_solver->get_lemmas(lemmas); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); From 3de8c193eaac44c8b5c6ce4e04af6efe19bb00de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Oct 2017 16:11:51 -0500 Subject: [PATCH 0312/1283] implementing model updates Signed-off-by: Nikolaj Bjorner --- src/ackermannization/ackr_model_converter.cpp | 5 ++ .../lackr_model_converter_lazy.cpp | 5 ++ src/api/python/z3/z3.py | 15 ---- src/ast/ast.cpp | 4 + src/ast/ast.h | 2 + src/ast/ast_pp_util.cpp | 6 +- src/ast/ast_pp_util.h | 6 +- src/ast/ast_printer.cpp | 2 +- src/ast/ast_smt2_pp.cpp | 73 +++++++++++++--- src/ast/ast_smt2_pp.h | 5 +- src/ast/ast_translation.h | 1 + src/cmd_context/cmd_context.cpp | 15 +++- src/cmd_context/cmd_context.h | 20 +++-- src/cmd_context/tactic_cmds.cpp | 3 +- src/muz/base/dl_util.cpp | 15 ++-- src/muz/spacer/spacer_itp_solver.h | 2 +- src/muz/spacer/spacer_virtual_solver.h | 2 +- src/muz/transforms/dl_mk_bit_blast.cpp | 2 + src/muz/transforms/dl_mk_karr_invariants.cpp | 2 + .../dl_mk_quantifier_abstraction.cpp | 8 +- src/muz/transforms/dl_mk_scale.cpp | 3 + src/muz/transforms/dl_mk_slice.cpp | 4 + src/opt/opt_context.cpp | 2 +- src/opt/opt_context.h | 2 +- src/opt/opt_solver.cpp | 2 +- src/opt/opt_solver.h | 2 +- src/parsers/smt2/smt2parser.cpp | 37 +++++++- src/sat/sat_model_converter.cpp | 86 +++++++++---------- src/sat/sat_model_converter.h | 11 ++- src/sat/sat_simplifier.cpp | 16 ++-- src/sat/sat_solver/inc_sat_solver.cpp | 15 +++- src/sat/tactic/goal2sat.cpp | 36 +++++--- src/smt/smt_solver.cpp | 4 +- src/solver/check_sat_result.cpp | 2 +- src/solver/check_sat_result.h | 12 ++- src/solver/combined_solver.cpp | 2 +- src/solver/solver.cpp | 6 ++ src/solver/solver.h | 21 ++--- src/solver/solver2tactic.cpp | 11 +-- src/solver/tactic2solver.cpp | 13 +-- src/tactic/CMakeLists.txt | 1 + src/tactic/arith/degree_shift_tactic.cpp | 66 ++++++-------- src/tactic/arith/elim01_tactic.cpp | 5 ++ src/tactic/arith/eq2bv_tactic.cpp | 12 ++- src/tactic/bv/dt2bv_tactic.cpp | 27 ++---- src/tactic/converter.h | 36 +++----- src/tactic/core/elim_uncnstr_tactic.cpp | 6 +- src/tactic/core/pb_preprocess_tactic.cpp | 14 ++- src/tactic/core/split_clause_tactic.cpp | 2 + src/tactic/equiv_proof_converter.h | 1 + src/tactic/extension_model_converter.cpp | 25 +++--- src/tactic/extension_model_converter.h | 5 +- src/tactic/filter_model_converter.cpp | 6 +- src/tactic/filter_model_converter.h | 2 +- src/tactic/horn_subsume_model_converter.h | 1 + src/tactic/model_converter.cpp | 54 ++++++++++-- src/tactic/model_converter.h | 14 ++- .../portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- src/tactic/replace_proof_converter.h | 2 + src/tactic/tactic.cpp | 9 +- src/tactic/tactic.h | 2 +- 63 files changed, 482 insertions(+), 294 deletions(-) diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index a7c021913..3cd86d2f1 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -62,6 +62,10 @@ public: } } + virtual void display(std::ostream & out) { + out << "(ackr-model-converter)\n"; + } + protected: ast_manager & m; const ackr_info_ref info; @@ -144,6 +148,7 @@ void ackr_model_converter::add_entry(model_evaluator & evaluator, else { TRACE("ackr_model", tout << "entry already present\n";); } + } model_converter * mk_ackr_model_converter(ast_manager & m, const ackr_info_ref& info) { diff --git a/src/ackermannization/lackr_model_converter_lazy.cpp b/src/ackermannization/lackr_model_converter_lazy.cpp index 2a7adb839..ffb4cae9d 100644 --- a/src/ackermannization/lackr_model_converter_lazy.cpp +++ b/src/ackermannization/lackr_model_converter_lazy.cpp @@ -48,6 +48,11 @@ public: virtual model_converter * translate(ast_translation & translator) { NOT_IMPLEMENTED_YET(); } + + virtual void display(std::ostream & out) { + out << "(lackr-model-converter)\n"; + } + protected: ast_manager& m; const lackr_model_constructor_ref model_constructor; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index ab6249ff6..b47873398 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6279,21 +6279,6 @@ class Solver(Z3PPObject): consequences = [ consequences[i] for i in range(sz) ] return CheckSatResult(r), consequences - def lemmas(self): - """Extract auxiliary lemmas produced by solver""" - return AstVector(Z3_solver_get_lemmas(self.ctx.ref(), self.solver), self.ctx) - - def lookahead(self, candidates = None): - """Get lookahead literal""" - if candidates is None: - candidates = AstVector(None, self.ctx) - elif not isinstance(candidates, AstVector): - _cs = AstVector(None, self.ctx) - for c in candidates: - _asms.push(c) - candidates = _cs - return _to_expr_ref(Z3_solver_lookahead(self.ctx.ref(), self.solver, candidates), self.ctx) - def cube(self): """Get set of cubes""" rounds = 0 diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 232e7b6d0..c8de22899 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1356,6 +1356,10 @@ ast_manager::ast_manager(ast_manager const & src, bool disable_proofs): copy_families_plugins(src); } +void ast_manager::update_fresh_id(ast_manager const& m) { + m_fresh_id = std::max(m_fresh_id, m.m_fresh_id); +} + void ast_manager::init() { m_int_real_coercions = true; m_debug_ref_count = false; diff --git a/src/ast/ast.h b/src/ast/ast.h index 4eb43d30b..d1466e569 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1435,6 +1435,8 @@ public: void show_id_gen(); + void update_fresh_id(ast_manager const& other); + protected: reslimit m_limit; small_object_allocator m_alloc; diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 455addf73..bbd1d0f41 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -36,7 +36,6 @@ void ast_pp_util::collect(expr_ref_vector const& es) { } void ast_pp_util::display_decls(std::ostream& out) { - smt2_pp_environment_dbg env(m); ast_smt_pp pp(m); unsigned n = coll.get_num_sorts(); for (unsigned i = 0; i < n; ++i) { @@ -46,7 +45,7 @@ void ast_pp_util::display_decls(std::ostream& out) { for (unsigned i = 0; i < n; ++i) { func_decl* f = coll.get_func_decls()[i]; if (f->get_family_id() == null_family_id) { - ast_smt2_pp(out, f, env); + ast_smt2_pp(out, f, m_env); out << "\n"; } } @@ -54,10 +53,9 @@ void ast_pp_util::display_decls(std::ostream& out) { void ast_pp_util::display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat) { if (neat) { - smt2_pp_environment_dbg env(m); for (expr* f : fmls) { out << "(assert "; - ast_smt2_pp(out, f, env); + ast_smt2_pp(out, f, m_env); out << ")\n"; } } diff --git a/src/ast/ast_pp_util.h b/src/ast/ast_pp_util.h index 964a862a2..ead31a475 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -20,14 +20,16 @@ Revision History: #define AST_PP_UTIL_H_ #include "ast/decl_collector.h" +#include "ast/ast_smt2_pp.h" class ast_pp_util { ast_manager& m; + smt2_pp_environment_dbg m_env; public: decl_collector coll; - ast_pp_util(ast_manager& m): m(m), coll(m, false) {} + ast_pp_util(ast_manager& m): m(m), m_env(m), coll(m, false) {} void collect(expr* e); @@ -38,6 +40,8 @@ class ast_pp_util { void display_decls(std::ostream& out); void display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat = true); + + smt2_pp_environment& env() { return m_env; } }; #endif /* AST_PP_UTIL_H_ */ diff --git a/src/ast/ast_printer.cpp b/src/ast/ast_printer.cpp index b5cf60ee9..9e19e4bfe 100644 --- a/src/ast/ast_printer.cpp +++ b/src/ast/ast_printer.cpp @@ -34,7 +34,7 @@ public: out << f->get_name(); } virtual void pp(sort * s, format_ns::format_ref & r) const { mk_smt2_format(s, env(), params_ref(), r); } - virtual void pp(func_decl * f, format_ns::format_ref & r) const { mk_smt2_format(f, env(), params_ref(), r); } + virtual void pp(func_decl * f, format_ns::format_ref & r) const { mk_smt2_format(f, env(), params_ref(), r, "declare-fun"); } virtual void pp(expr * n, format_ns::format_ref & r) const { sbuffer buf; mk_smt2_format(n, env(), params_ref(), 0, 0, r, buf); diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index e093dc2ff..db66d9097 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -876,8 +876,21 @@ class smt2_printer { } } + void register_var_names(unsigned n) { + unsigned idx = 1; + for (unsigned i = 0; i < n; i++) { + symbol name = next_name("x", idx); + SASSERT(!m_var_names_set.contains(name)); + m_var_names.push_back(name); + m_var_names_set.insert(name); + } + } + void unregister_var_names(quantifier * q) { - unsigned num_decls = q->get_num_decls(); + unregister_var_names(q->get_num_decls()); + } + + void unregister_var_names(unsigned num_decls) { for (unsigned i = 0; i < num_decls; i++) { symbol s = m_var_names.back(); m_var_names.pop_back(); @@ -885,25 +898,28 @@ class smt2_printer { } } - format * pp_var_decls(quantifier * q) { + format * pp_var_args(unsigned num_decls, sort* const* srts) { ptr_buffer buf; - unsigned num_decls = q->get_num_decls(); SASSERT(num_decls <= m_var_names.size()); symbol * it = m_var_names.end() - num_decls; for (unsigned i = 0; i < num_decls; i++, it++) { - format * fs[1] = { m_env.pp_sort(q->get_decl_sort(i)) }; + format * fs[1] = { m_env.pp_sort(srts[i]) }; std::string var_name; if (is_smt2_quoted_symbol (*it)) { var_name = mk_smt2_quoted_symbol (*it); } else { - var_name = it->str ();\ + var_name = it->str (); } buf.push_back(mk_seq1(m(), fs, fs+1, f2f(), var_name.c_str ())); } return mk_seq5(m(), buf.begin(), buf.end(), f2f()); } + format * pp_var_decls(quantifier * q) { + return pp_var_args(q->get_num_decls(), q->get_decl_sorts()); + } + void process_quantifier(quantifier * q, frame & fr) { if (fr.m_idx == 0) { begin_scope(); @@ -1098,7 +1114,7 @@ public: r = m_env.pp_sort(s); } - void operator()(func_decl * f, format_ref & r) { + void operator()(func_decl * f, format_ref & r, char const* cmd) { unsigned arity = f->get_arity(); unsigned len; format * fname = m_env.pp_fdecl_name(f, len); @@ -1110,9 +1126,27 @@ public: } args[1] = mk_seq5(m(), buf.begin(), buf.end(), f2f()); args[2] = m_env.pp_sort(f->get_range()); - r = mk_seq1(m(), args, args+3, f2f(), "declare-fun"); + r = mk_seq1(m(), args, args+3, f2f(), cmd); } + + void operator()(func_decl * f, expr * e, format_ref & r, char const* cmd) { + unsigned arity = f->get_arity(); + unsigned len; + format * fname = m_env.pp_fdecl_name(f, len); + register_var_names(f->get_arity()); + format * args[4]; + args[0] = fname; + args[1] = pp_var_args(f->get_arity(), f->get_domain()); + args[2] = m_env.pp_sort(f->get_range()); + process(e, r); + args[3] = r; + r = mk_seq1(m(), args, args+4, f2f(), cmd); + unregister_var_names(f->get_arity()); + } + + + }; void mk_smt2_format(expr * n, smt2_pp_environment & env, params_ref const & p, @@ -1127,9 +1161,14 @@ void mk_smt2_format(sort * s, smt2_pp_environment & env, params_ref const & p, f pr(s, r); } -void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const & p, format_ref & r) { +void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const & p, format_ref & r, char const* cmd) { smt2_printer pr(env, p); - pr(f, r); + pr(f, r, cmd); +} + +void mk_smt2_format(func_decl * f, expr * e, smt2_pp_environment & env, params_ref const & p, format_ref & r, char const* cmd) { + smt2_printer pr(env, p); + pr(f, e, r, cmd); } void mk_smt2_format(unsigned sz, expr * const* es, smt2_pp_environment & env, params_ref const & p, @@ -1170,17 +1209,29 @@ std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & e return out; } -std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, params_ref const & p, unsigned indent) { +std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, params_ref const & p, unsigned indent, char const* cmd) { ast_manager & m = env.get_manager(); format_ref r(fm(m)); sbuffer var_names; - mk_smt2_format(f, env, p, r); + mk_smt2_format(f, env, p, r, cmd); if (indent > 0) r = mk_indent(m, indent, r.get()); pp(out, r.get(), m, p); return out; } +std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, expr* e, smt2_pp_environment & env, params_ref const & p, unsigned indent, char const* cmd) { + ast_manager & m = env.get_manager(); + format_ref r(fm(m)); + sbuffer var_names; + mk_smt2_format(f, e, env, p, r, cmd); + if (indent > 0) + r = mk_indent(m, indent, r.get()); + pp(out, r.get(), m, p); + return out; +} + + std::ostream & ast_smt2_pp(std::ostream & out, unsigned sz, expr * const* es, smt2_pp_environment & env, params_ref const & p, unsigned indent, unsigned num_vars, char const * var_prefix) { ast_manager & m = env.get_manager(); diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 7a0267960..8a4b3d80a 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -97,12 +97,13 @@ void mk_smt2_format(expr * n, smt2_pp_environment & env, params_ref const & p, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer & var_names); void mk_smt2_format(sort * s, smt2_pp_environment & env, params_ref const & p, format_ns::format_ref & r); -void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const & p, format_ns::format_ref & r); +void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const & p, format_ns::format_ref & r, char const* cmd); std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0); std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0); -std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0); +std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "declare-fun"); +std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, expr* e, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "define-fun"); /** \brief Internal wrapper (for debugging purposes only) diff --git a/src/ast/ast_translation.h b/src/ast/ast_translation.h index b278791d7..886aaf417 100644 --- a/src/ast/ast_translation.h +++ b/src/ast/ast_translation.h @@ -52,6 +52,7 @@ public: ast_translation(ast_manager & from, ast_manager & to, bool copy_plugins = true) : m_from_manager(from), m_to_manager(to) { if (copy_plugins) m_to_manager.copy_families_plugins(m_from_manager); + m_to_manager.update_fresh_id(m_from_manager); } ~ast_translation(); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index ce6c4a65a..97c53d423 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -43,6 +43,7 @@ Notes: #include "model/model_v2_pp.h" #include "model/model_params.hpp" #include "tactic/tactic_exception.h" +#include "tactic/generic_model_converter.h" #include "solver/smt_logics.h" #include "cmd_context/basic_cmds.h" #include "cmd_context/interpolant_cmds.h" @@ -864,6 +865,17 @@ void cmd_context::insert(symbol const & s, object_ref * r) { m_object_refs.insert(s, r); } +void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domain, expr * t) { + if (!m_mc0) m_mc0 = alloc(generic_model_converter, m()); + func_decl_ref fn(m().mk_func_decl(s, arity, domain, m().get_sort(t)), m()); + m_mc0->add(fn, t); +} + +void cmd_context::model_del(func_decl* f) { + if (!m_mc0) m_mc0 = alloc(generic_model_converter, m()); + m_mc0->hide(f); +} + void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* e) { expr_ref eq(m()); app_ref lhs(m()); @@ -1573,6 +1585,7 @@ void cmd_context::display_dimacs() { void cmd_context::display_model(model_ref& mdl) { if (mdl) { + if (m_mc0) (*m_mc0)(mdl); model_params p; if (p.v1() || p.v2()) { std::ostringstream buffer; @@ -1895,7 +1908,7 @@ void cmd_context::pp(expr * n, format_ns::format_ref & r) const { } void cmd_context::pp(func_decl * f, format_ns::format_ref & r) const { - mk_smt2_format(f, get_pp_env(), params_ref(), r); + mk_smt2_format(f, get_pp_env(), params_ref(), r, "declare-fun"); } void cmd_context::display(std::ostream & out, sort * s, unsigned indent) const { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index b60f590a9..48dd17cb0 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -23,20 +23,21 @@ Notes: #include #include -#include "ast/ast.h" -#include "ast/ast_printer.h" -#include "cmd_context/pdecl.h" -#include "util/dictionary.h" -#include "solver/solver.h" -#include "ast/datatype_decl_plugin.h" #include "util/stopwatch.h" #include "util/cmd_context_types.h" #include "util/event_handler.h" #include "util/sexpr.h" +#include "util/dictionary.h" +#include "util/scoped_ptr_vector.h" +#include "ast/ast.h" +#include "ast/ast_printer.h" +#include "ast/datatype_decl_plugin.h" +#include "tactic/generic_model_converter.h" +#include "solver/solver.h" +#include "solver/progress_callback.h" +#include "cmd_context/pdecl.h" #include "cmd_context/tactic_manager.h" #include "cmd_context/check_logic.h" -#include "solver/progress_callback.h" -#include "util/scoped_ptr_vector.h" #include "cmd_context/context_params.h" @@ -303,6 +304,7 @@ protected: void erase_macro(symbol const& s); bool macros_find(symbol const& s, unsigned n, expr*const* args, expr*& t) const; + ref m_mc0; public: cmd_context(bool main_ctx = true, ast_manager * m = 0, symbol const & l = symbol::null); @@ -381,6 +383,8 @@ public: void insert_user_tactic(symbol const & s, sexpr * d); void insert_aux_pdecl(pdecl * p); void insert_rec_fun(func_decl* f, expr_ref_vector const& binding, svector const& ids, expr* e); + void model_add(symbol const & s, unsigned arity, sort *const* domain, expr * t); + void model_del(func_decl* f); func_decl * find_func_decl(symbol const & s) const; func_decl * find_func_decl(symbol const & s, unsigned num_indices, unsigned const * indices, unsigned arity, sort * const * domain, sort * range) const; diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index cbc90c62c..20a2b1c11 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -211,6 +211,7 @@ public: assert_exprs_from(ctx, *g); TRACE("check_sat_using", g->display(tout);); model_ref md; + model_converter_ref mc; proof_ref pr(m); expr_dependency_ref core(m); std::string reason_unknown; @@ -226,7 +227,7 @@ public: cmd_context::scoped_watch sw(ctx); lbool r = l_undef; try { - r = check_sat(t, g, md, result->labels, pr, core, reason_unknown); + r = check_sat(t, g, md, mc, result->labels, pr, core, reason_unknown); ctx.display_sat_result(r); result->set_status(r); if (r == l_undef) { diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index f0439a55c..463b78c4a 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -384,6 +384,7 @@ namespace datalog { return alloc(skip_model_converter); } + virtual void display(std::ostream & out) { } }; model_converter* mk_skip_model_converter() { return alloc(skip_model_converter); } @@ -398,6 +399,7 @@ namespace datalog { return alloc(skip_proof_converter); } + virtual void display(std::ostream & out) { out << "(skip-proof-converter)\n"; } }; proof_converter* mk_skip_proof_converter() { return alloc(skip_proof_converter); } @@ -508,10 +510,9 @@ namespace datalog { } void collect_and_transform(const unsigned_vector & src, const unsigned_vector & translation, - unsigned_vector & res) { - unsigned n = src.size(); - for(unsigned i=0; i &r); - virtual void get_model(model_ref &m) {m_solver.get_model(m);} + virtual void get_model_core(model_ref &m) {m_solver.get_model(m);} virtual proof *get_proof() {return m_solver.get_proof();} virtual std::string reason_unknown() const {return m_solver.reason_unknown();} diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index fafaf2020..613f85169 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -80,7 +80,7 @@ public: virtual void get_unsat_core(ptr_vector &r); virtual void assert_expr(expr *e); virtual void collect_statistics(statistics &st) const {} - virtual void get_model(model_ref &m) {m_context.get_model(m);} + virtual void get_model_core(model_ref &m) {m_context.get_model(m);} virtual proof* get_proof(); virtual std::string reason_unknown() const {return m_context.last_failure_as_string();} diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 3c8045e34..924b12eda 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -63,6 +63,8 @@ namespace datalog { return alloc(bit_blast_model_converter, m); } + virtual void display(std::ostream& out) { out << "(bit-blast-model-converter)\n"; } + virtual void operator()(model_ref & model) { for (unsigned i = 0; i < m_new_funcs.size(); ++i) { func_decl* p = m_new_funcs[i].get(); diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 48219eeb9..678c673a8 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -150,6 +150,8 @@ namespace datalog { return mc; } + virtual void display(std::ostream& out) { out << "(add-invariant-model-converter)\n"; } + private: void mk_body(matrix const& M, expr_ref& body) { expr_ref_vector conj(m); diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index b171aaa7c..888e1ebb5 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -53,6 +53,8 @@ namespace datalog { return alloc(qa_model_converter, m); } + virtual void display(std::ostream& out) { display_add(out, m); } + void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector const& bound) { m_old_funcs.push_back(old_p); m_new_funcs.push_back(new_p); @@ -81,7 +83,11 @@ namespace datalog { SASSERT(body); } else { - body = m.mk_false(); + expr_ref_vector args(m); + for (unsigned i = 0; i < p->get_arity(); ++i) { + args.push_back(m.mk_var(i, p->get_domain(i))); + } + body = m.mk_app(p, args.size(), args.c_ptr()); } // Create quantifier wrapper around body. diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index 5bc10b957..5eeaaaeca 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -99,6 +99,9 @@ namespace datalog { UNREACHABLE(); return 0; } + + virtual void display(std::ostream& out) { out << "(scale-model-converter)\n"; } + }; diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index c094e5520..8b38335e0 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -283,6 +283,8 @@ namespace datalog { // this would require implementing translation for the dl_context. return 0; } + + virtual void display(std::ostream& out) { out << "(slice-proof-converter)\n"; } }; class mk_slice::slice_model_converter : public model_converter { @@ -396,6 +398,8 @@ namespace datalog { return 0; } + virtual void display(std::ostream& out) { out << "(slice-model-converter)\n"; } + }; mk_slice::mk_slice(context & ctx): diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 29470ba18..9c861eb49 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -331,7 +331,7 @@ namespace opt { } } - void context::get_model(model_ref& mdl) { + void context::get_model_core(model_ref& mdl) { mdl = m_model; fix_model(mdl); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index ad40db074..4fec5d452 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -184,7 +184,7 @@ namespace opt { virtual void set_hard_constraints(ptr_vector & hard); virtual lbool optimize(); virtual void set_model(model_ref& _m) { m_model = _m; } - virtual void get_model(model_ref& _m); + virtual void get_model_core(model_ref& _m); virtual void get_box_model(model_ref& _m, unsigned index); virtual void fix_model(model_ref& _m); virtual void collect_statistics(statistics& stats) const; diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 69b62083f..78ae2bbbb 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -296,7 +296,7 @@ namespace opt { } } - void opt_solver::get_model(model_ref & m) { + void opt_solver::get_model_core(model_ref & m) { m_context.get_model(m); } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 46b52e387..1f0a518b2 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -97,7 +97,7 @@ namespace opt { virtual void pop_core(unsigned n); virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & _m); + virtual void get_model_core(model_ref & _m); virtual proof * get_proof(); virtual std::string reason_unknown() const; virtual void set_reason_unknown(char const* msg); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index b8ad7e610..446059227 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -96,6 +96,8 @@ namespace smt2 { symbol m_check_sat; symbol m_define_fun; symbol m_define_const; + symbol m_model_add; + symbol m_model_del; symbol m_declare_fun; symbol m_declare_const; symbol m_define_sort; @@ -2179,9 +2181,9 @@ namespace smt2 { next(); } - void parse_define_fun() { + void parse_define(bool is_fun) { SASSERT(curr_is_identifier()); - SASSERT(curr_id() == m_define_fun); + SASSERT(curr_id() == (is_fun ? m_define_fun : m_model_add)); SASSERT(m_num_bindings == 0); next(); check_identifier("invalid function/constant definition, symbol expected"); @@ -2195,7 +2197,10 @@ namespace smt2 { parse_expr(); if (m().get_sort(expr_stack().back()) != sort_stack().back()) throw parser_exception("invalid function/constant definition, sort mismatch"); - m_ctx.insert(id, num_vars, sort_stack().c_ptr() + sort_spos, expr_stack().back()); + if (is_fun) + m_ctx.insert(id, num_vars, sort_stack().c_ptr() + sort_spos, expr_stack().back()); + else + m_ctx.model_add(id, num_vars, sort_stack().c_ptr() + sort_spos, expr_stack().back()); check_rparen("invalid function/constant definition, ')' expected"); // restore stacks & env symbol_stack().shrink(sym_spos); @@ -2208,6 +2213,22 @@ namespace smt2 { next(); } + void parse_define_fun() { + parse_define(true); + } + + void parse_model_add() { + parse_define(false); + } + + void parse_model_del() { + func_decl* f = parse_func_decl_ref(); + check_rparen("invalid model-del, ')' expected"); + m_ctx.model_del(f); + m_ctx.print_success(); + next(); + } + void parse_define_fun_rec() { // ( define-fun-rec hfun_defi ) SASSERT(curr_is_identifier()); @@ -2910,6 +2931,14 @@ namespace smt2 { parse_define_funs_rec(); return; } + if (s == m_model_add) { + parse_model_add(); + return; + } + if (s == m_model_del) { + parse_model_del(); + return; + } parse_ext_cmd(line, pos); } @@ -2941,6 +2970,8 @@ namespace smt2 { m_check_sat("check-sat"), m_define_fun("define-fun"), m_define_const("define-const"), + m_model_add("model-add"), + m_model_del("model-del"), m_declare_fun("declare-fun"), m_declare_const("declare-const"), m_define_sort("define-sort"), diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 2cc9ceffc..7339f966d 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -295,51 +295,6 @@ namespace sat { return out; } - void model_converter::validate_is_blocked(entry const& e, clause const& c) { - if (c.is_blocked() || c.is_learned()) return; - unsigned index = 0; - literal lit = null_literal; - bool_var v = e.var(); - for (literal l : c) { - if (l.var() == v) { - lit = l; - break; - } - } - if (lit == null_literal) return; - - bool sat = false; - for (literal l : e.m_clauses) { - if (l == null_literal) { - if (!sat) { - display(std::cout << "clause is not blocked\n", e) << "\n"; - std::cout << c << "\n"; - } - sat = false; - elim_stack* st = e.m_elim_stack[index]; - if (st) { - elim_stackv const& stack = st->stack(); - unsigned sz = stack.size(); - for (unsigned i = sz; i-- > 0; ) { - // verify ... - } - - } - ++index; - continue; - } - if (sat) { - continue; - } - if (l.var() == v) { - sat = l == lit; - } - else { - sat = c.contains(~l); - } - } - } - void model_converter::copy(model_converter const & src) { reset(); m_entries.append(src.m_entries); @@ -362,4 +317,45 @@ namespace sat { return result; } + void model_converter::expand(vector& update_stack) { + literal_vector clause; + for (entry const& e : m_entries) { + clause.reset(); + unsigned index = 0; + bool var_sign = false; + for (literal l : e.m_clauses) { + if (l == null_literal) { + elim_stack* st = e.m_elim_stack[index]; + if (st) { + // clause sizes increase + elim_stackv const& stack = st->stack(); + unsigned sz = stack.size(); + for (unsigned i = 0; i < sz; ++i) { + unsigned csz = stack[i].first; + literal lit = stack[i].second; + BOOL found = false; + unsigned j = 0; + for (j = 0; j < csz; ++j) { + if (clause[j] == lit) { + std::swap(clause[j], clause[0]); + found = true; + break; + } + } + SASSERT(found); + update_stack.push_back(literal_vector(csz, clause.c_ptr())); + } + } + update_stack.push_back(clause); + clause.reset(); + continue; + } + clause.push_back(l); + if (l.var() == e.var()) { + std::swap(clause[0], clause.back()); + } + } + } + } + }; diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index cdd8c60ed..a6f1f0bbe 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -84,8 +84,6 @@ namespace sat { std::ostream& display(std::ostream & out, entry const& entry) const; - void validate_is_blocked(entry const& e, clause const& c); - public: model_converter(); ~model_converter(); @@ -109,6 +107,15 @@ namespace sat { void copy(model_converter const & src); void collect_vars(bool_var_set & s) const; unsigned max_var(unsigned min) const; + /* + * \brief expand entries to a list of clauses, such that + * the first literal in each clause is the literal whose + * truth value is updated as follows: + * + * lit0 := lit0 or (~lit1 & ~lit2 & ... & ~lit_k) + * + */ + void expand(vector& update_stack); }; }; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 820000b4c..e2e035dfb 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1318,7 +1318,7 @@ namespace sat { void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); - if (new_entry == 0) + if (new_entry == 0 && !s.m_retain_blocked_clauses) new_entry = &(mc.mk(k, l.var())); m_to_remove.push_back(&c); for (literal lit : c) { @@ -1330,17 +1330,19 @@ namespace sat { void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { prepare_block_clause(c, l, new_entry, model_converter::BLOCK_LIT); - mc.insert(*new_entry, c); + if (!s.m_retain_blocked_clauses) + mc.insert(*new_entry, c); } void block_covered_clause(clause& c, literal l, model_converter::kind k) { model_converter::entry * new_entry = 0; prepare_block_clause(c, l, new_entry, k); - mc.insert(*new_entry, m_covered_clause, m_elim_stack); + if (!s.m_retain_blocked_clauses) + mc.insert(*new_entry, m_covered_clause, m_elim_stack); } void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) { - if (new_entry == 0) + if (new_entry == 0 && !s.m_retain_blocked_clauses) new_entry = &(mc.mk(k, blocked.var())); literal l2 = it->get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); @@ -1356,13 +1358,15 @@ namespace sat { void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { prepare_block_binary(it, l, l, new_entry, model_converter::BLOCK_LIT); - mc.insert(*new_entry, l, it->get_literal()); + if (!s.m_retain_blocked_clauses) + mc.insert(*new_entry, l, it->get_literal()); } void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::kind k) { model_converter::entry * new_entry = 0; prepare_block_binary(it, l, blocked, new_entry, k); - mc.insert(*new_entry, m_covered_clause, m_elim_stack); + if (!s.m_retain_blocked_clauses) + mc.insert(*new_entry, m_covered_clause, m_elim_stack); } void bca() { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 44dc414af..218646de3 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -114,6 +114,7 @@ public: if (m_mc0.get()) result->m_mc0 = m_mc0->translate(tr); result->m_internalized = m_internalized; result->m_internalized_converted = m_internalized_converted; + if (mc0()) result->set_model_converter(mc0()->translate(tr)); return result; } @@ -299,7 +300,7 @@ public: r.reset(); r.append(m_core.size(), m_core.c_ptr()); } - virtual void get_model(model_ref & mdl) { + virtual void get_model_core(model_ref & mdl) { if (!m_model.get()) { extract_model(); } @@ -442,6 +443,18 @@ public: return m_asmsf[idx]; } + virtual model_converter_ref get_model_converter() const { + if (m_internalized && m_internalized_converted) { + NOT_IMPLEMENTED_YET(); + model_converter_ref mc = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); + mc = concat(solver::get_model_converter().get(), mc.get()); + return mc; + } + else { + return solver::get_model_converter(); + } + } + void convert_internalized() { if (!m_internalized) return; sat2goal s2g; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 1270b67c2..8daeb7ec0 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -968,21 +968,31 @@ struct sat2goal::imp { return res; } - void display(std::ostream & out) { - out << "(sat-model-converter\n"; - m_mc.display(out); - sat::bool_var_set vars; - m_mc.collect_vars(vars); - out << "(atoms"; - unsigned sz = m_var2expr.size(); - for (unsigned i = 0; i < sz; i++) { - if (vars.contains(i)) { - out << "\n (" << i << "\n " << mk_ismt2_pp(m_var2expr.get(i), m(), 2) << ")"; - } + expr_ref lit2expr(sat::literal l) { + expr_ref result(m_var2expr.get(l.var()), m()); + if (l.sign()) { + result = m().mk_not(result); + } + return result; + } + + void display(std::ostream & out) { + vector updates; + m_mc.expand(updates); + for (sat::literal_vector const& clause : updates) { + expr_ref_vector tail(m()); + sat::literal lit0 = clause[0]; + for (unsigned i = 1; i < clause.size(); ++i) { + tail.push_back(lit2expr(~clause[i])); + } + expr_ref def(m().mk_or(lit2expr(lit0), mk_and(tail)), m()); + if (lit0.sign()) { + lit0.neg(); + def = m().mk_not(def); + } + display_add(out, m(), to_app(lit2expr(lit0))->get_decl(), def); } - out << ")\n"; m_fmc->display(out); - out << ")\n"; } }; diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 9f411b0e6..b7a686a71 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -70,6 +70,8 @@ namespace smt { result->m_name2assertion.insert(translator(kv.m_key), translator(kv.m_value)); + if (mc0()) + result->set_model_converter(mc0()->translate(translator)); return result; } @@ -186,7 +188,7 @@ namespace smt { add_nonlocal_pattern_literals_to_core(r); } - virtual void get_model(model_ref & m) { + virtual void get_model_core(model_ref & m) { m_context.get_model(m); } diff --git a/src/solver/check_sat_result.cpp b/src/solver/check_sat_result.cpp index f1bedfc08..1308c52de 100644 --- a/src/solver/check_sat_result.cpp +++ b/src/solver/check_sat_result.cpp @@ -53,7 +53,7 @@ void simple_check_sat_result::get_unsat_core(ptr_vector & r) { r.append(m_core.size(), m_core.c_ptr()); } -void simple_check_sat_result::get_model(model_ref & m) { +void simple_check_sat_result::get_model_core(model_ref & m) { if (m_status != l_false) m = m_model; else diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 38720a5e9..572c4d88d 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -23,6 +23,7 @@ Notes: #include "util/lbool.h" #include "util/statistics.h" #include "util/event_handler.h" +#include "tactic/model_converter.h" /** \brief Abstract interface for the result of a (check-sat) like command. @@ -40,6 +41,7 @@ class check_sat_result { protected: unsigned m_ref_count; lbool m_status; + model_converter_ref m_mc0; public: check_sat_result():m_ref_count(0), m_status(l_undef) {} virtual ~check_sat_result() {} @@ -54,7 +56,13 @@ public: get_unsat_core(core); r.append(core.size(), core.c_ptr()); } - virtual void get_model(model_ref & m) = 0; + void set_model_converter(model_converter* mc) { m_mc0 = mc; } + model_converter* mc0() { return m_mc0.get(); } + virtual void get_model_core(model_ref & m) = 0; + void get_model(model_ref & m) { + get_model_core(m); + if (m && mc0()) (*mc0())(m); + } virtual proof * get_proof() = 0; virtual std::string reason_unknown() const = 0; virtual void set_reason_unknown(char const* msg) = 0; @@ -80,7 +88,7 @@ struct simple_check_sat_result : public check_sat_result { virtual ast_manager& get_manager() const { return m_proof.get_manager(); } virtual void collect_statistics(statistics & st) const; virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & m); + virtual void get_model_core(model_ref & m); virtual proof * get_proof(); virtual std::string reason_unknown() const; virtual void get_labels(svector & r); diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 9a685d5b3..6888dd406 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -307,7 +307,7 @@ public: m_solver2->get_unsat_core(r); } - virtual void get_model(model_ref & m) { + virtual void get_model_core(model_ref & m) { if (m_use_solver1_results) m_solver1->get_model(m); else diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 0f5a72831..122bb2933 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -22,6 +22,7 @@ Notes: #include "ast/ast_pp.h" #include "ast/ast_pp_util.h" #include "util/common_msgs.h" +#include "tactic/model_converter.h" unsigned solver::get_num_assertions() const { @@ -41,6 +42,11 @@ std::ostream& solver::display(std::ostream & out) const { visitor.collect(fmls); visitor.display_decls(out); visitor.display_asserts(out, fmls, true); + model_converter_ref mc = get_model_converter(); + if (mc.get()) { + mc->set_pp_env(&visitor.env()); + mc->display(out); + } return out; } diff --git a/src/solver/solver.h b/src/solver/solver.h index 6171f111f..0f64c943d 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -24,6 +24,7 @@ Notes: #include "util/params.h" class solver; +class model_converter; class solver_factory { public: @@ -184,25 +185,17 @@ public: virtual expr_ref cube() = 0; -#if 0 - /** - \brief extract a lookahead candidates for branching. - */ - - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) = 0; - - - /** - \brief extract learned lemmas. - */ - virtual void get_lemmas(expr_ref_vector& lemmas) {} -#endif - /** \brief Display the content of this solver. */ virtual std::ostream& display(std::ostream & out) const; + /** + \brief expose model converter when solver produces partially reduced set of assertions. + */ + + virtual model_converter_ref get_model_converter() const { return m_mc0; } + class scoped_push { solver& s; bool m_nopop; diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 4f7b750f8..eea3aa9c5 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -122,6 +122,7 @@ public: local_solver->get_model(mdl); mc = model2model_converter(mdl.get()); mc = concat(fmc.get(), mc.get()); + mc = concat(local_solver->mc0(), mc.get()); } in->reset(); result.push_back(in.get()); @@ -150,14 +151,8 @@ public: if (m.canceled()) { throw tactic_exception(Z3_CANCELED_MSG); } - if (in->models_enabled()) { - model_ref mdl; - local_solver->get_model(mdl); - if (mdl) { - mc = model2model_converter(mdl.get()); - mc = concat(fmc.get(), mc.get()); - } - } + mc = local_solver->get_model_converter(); + mc = concat(fmc.get(), mc.get()); in->reset(); unsigned sz = local_solver->get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 0286197fa..1dd48fb9c 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -36,6 +36,7 @@ class tactic2solver : public solver_na2as { unsigned_vector m_scopes; ref m_result; tactic_ref m_tactic; + ref m_mc; symbol m_logic; params_ref m_params; bool m_produce_models; @@ -64,7 +65,7 @@ public: virtual void collect_statistics(statistics & st) const; virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & m); + virtual void get_model_core(model_ref & m); virtual proof * get_proof(); virtual std::string reason_unknown() const; virtual void set_reason_unknown(char const* msg); @@ -82,6 +83,8 @@ public: return expr_ref(m.mk_true(), m); } + virtual model_converter* get_model_converter() { return m_mc.get(); } + }; ast_manager& tactic2solver::get_manager() const { return m_assertions.get_manager(); } @@ -153,12 +156,12 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass } model_ref md; - proof_ref pr(m); + proof_ref pr(m); expr_dependency_ref core(m); std::string reason_unknown = "unknown"; labels_vec labels; try { - switch (::check_sat(*m_tactic, g, md, labels, pr, core, reason_unknown)) { + switch (::check_sat(*m_tactic, g, md, m_mc, labels, pr, core, reason_unknown)) { case l_true: m_result->set_status(l_true); break; @@ -226,9 +229,9 @@ void tactic2solver::get_unsat_core(ptr_vector & r) { } } -void tactic2solver::get_model(model_ref & m) { +void tactic2solver::get_model_core(model_ref & m) { if (m_result.get()) - m_result->get_model(m); + m_result->get_model_core(m); } proof * tactic2solver::get_proof() { diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index e7cfdb644..74379b30f 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(tactic equiv_proof_converter.cpp extension_model_converter.cpp filter_model_converter.cpp + generic_model_converter.cpp goal.cpp goal_num_occurs.cpp goal_shared_occs.cpp diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 6344c4c51..80b7a416c 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -21,7 +21,7 @@ Revision History: --*/ #include "tactic/tactical.h" #include "tactic/filter_model_converter.h" -#include "tactic/extension_model_converter.h" +#include "tactic/generic_model_converter.h" #include "util/cooperate.h" #include "ast/arith_decl_plugin.h" #include "tactic/core/simplify_tactic.h" @@ -127,9 +127,7 @@ class degree_shift_tactic : public tactic { void visit_args(expr * t, expr_fast_mark1 & visited) { if (is_app(t)) { - unsigned num_args = to_app(t)->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(t)->get_arg(i); + for (expr * arg : *to_app(t)) { save_degree(arg, m_one); visit(arg, visited); } @@ -166,11 +164,9 @@ class degree_shift_tactic : public tactic { void display_candidates(std::ostream & out) { out << "candidates:\n"; - obj_map::iterator it = m_var2degree.begin(); - obj_map::iterator end = m_var2degree.end(); - for (; it != end; ++it) { - if (!it->m_value.is_one()) { - out << "POWER: " << it->m_value << "\n" << mk_ismt2_pp(it->m_key, m) << "\n"; + for (auto const& kv : m_var2degree) { + if (!kv.m_value.is_one()) { + out << "POWER: " << kv.m_value << "\n" << mk_ismt2_pp(kv.m_key, m) << "\n"; } } } @@ -189,48 +185,42 @@ class degree_shift_tactic : public tactic { void discard_non_candidates() { m_pinned.reset(); ptr_vector to_delete; - obj_map::iterator it = m_var2degree.begin(); - obj_map::iterator end = m_var2degree.end(); - for (; it != end; ++it) { - if (it->m_value.is_one()) - to_delete.push_back(it->m_key); + for (auto const& kv : m_var2degree) { + if (kv.m_value.is_one()) + to_delete.push_back(kv.m_key); else - m_pinned.push_back(it->m_key); // make sure it is not deleted during simplifications + m_pinned.push_back(kv.m_key); // make sure it is not deleted during simplifications } - ptr_vector::iterator it2 = to_delete.begin(); - ptr_vector::iterator end2 = to_delete.end(); - for (; it2 != end2; ++it2) - m_var2degree.erase(*it2); + for (app* a : to_delete) + m_var2degree.erase(a); } void prepare_substitution(model_converter_ref & mc) { SASSERT(!m_var2degree.empty()); filter_model_converter * fmc = 0; - extension_model_converter * xmc = 0; + generic_model_converter * xmc = 0; if (m_produce_models) { fmc = alloc(filter_model_converter, m); - xmc = alloc(extension_model_converter, m); + xmc = alloc(generic_model_converter, m); mc = concat(fmc, xmc); } - obj_map::iterator it = m_var2degree.begin(); - obj_map::iterator end = m_var2degree.end(); - for (; it != end; ++it) { - SASSERT(it->m_value.is_int()); - SASSERT(it->m_value >= rational(2)); - app * fresh = m.mk_fresh_const(0, it->m_key->get_decl()->get_range()); + for (auto const& kv : m_var2degree) { + SASSERT(kv.m_value.is_int()); + SASSERT(kv.m_value >= rational(2)); + app * fresh = m.mk_fresh_const(0, kv.m_key->get_decl()->get_range()); m_pinned.push_back(fresh); - m_var2var.insert(it->m_key, fresh); + m_var2var.insert(kv.m_key, fresh); if (m_produce_models) { fmc->insert(fresh->get_decl()); - xmc->insert(it->m_key->get_decl(), mk_power(fresh, rational(1)/it->m_value)); + xmc->add(kv.m_key->get_decl(), mk_power(fresh, rational(1)/kv.m_value)); } if (m_produce_proofs) { - expr * s = mk_power(it->m_key, it->m_value); + expr * s = mk_power(kv.m_key, kv.m_value); expr * eq = m.mk_eq(fresh, s); proof * pr1 = m.mk_def_intro(eq); proof * result_pr = m.mk_apply_def(fresh, s, pr1); m_pinned.push_back(result_pr); - m_var2pr.insert(it->m_key, result_pr); + m_var2pr.insert(kv.m_key, result_pr); } } } @@ -267,17 +257,15 @@ class degree_shift_tactic : public tactic { } // add >= 0 constraints for variables with even degree - obj_map::iterator it = m_var2degree.begin(); - obj_map::iterator end = m_var2degree.end(); - for (; it != end; ++it) { - SASSERT(it->m_value.is_int()); - SASSERT(it->m_value >= rational(2)); - if (it->m_value.is_even()) { - app * new_var = m_var2var.find(it->m_key); + for (auto const& kv : m_var2degree) { + SASSERT(kv.m_value.is_int()); + SASSERT(kv.m_value >= rational(2)); + if (kv.m_value.is_even()) { + app * new_var = m_var2var.find(kv.m_key); app * new_c = m_autil.mk_ge(new_var, m_autil.mk_numeral(rational(0), false)); proof * new_pr = 0; if (m_produce_proofs) { - proof * pr = m_var2pr.find(it->m_key); + proof * pr = m_var2pr.find(kv.m_key); new_pr = m.mk_th_lemma(m_autil.get_family_id(), new_c, 1, &pr); } g->assert_expr(new_c, new_pr, 0); diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index b6fd5eee7..68534c60b 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -113,6 +113,11 @@ public: } return mc; } + + virtual void display(std::ostream & out) { + out << "(elim01-model-converter)\n"; + } + }; diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 255665b56..492b12fcf 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -107,12 +107,18 @@ class eq2bv_tactic : public tactic { virtual model_converter* translate(ast_translation & translator) { bvmc* v = alloc(bvmc); - obj_map::iterator it = m_map.begin(), end = m_map.end(); - for (; it != end; ++it) { - v->m_map.insert(translator(it->m_key), translator(it->m_value)); + for (auto const& kv : m_map) { + v->m_map.insert(translator(kv.m_key), translator(kv.m_value)); } return v; } + + virtual void display(std::ostream & out) { + for (auto const& kv : m_map) { + out << "(model-set " << kv.m_key->get_name() << " " << kv.m_value->get_name() << ")\n"; + } + } + }; public: diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index fe59480e7..2b1aa0fdd 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -131,10 +131,8 @@ public: for (unsigned i = 0; i < size; ++i) { quick_for_each_expr(proc, visited, g->form(i)); } - obj_hashtable::iterator it = m_non_fd_sorts.begin(), end = m_non_fd_sorts.end(); - for (; it != end; ++it) { - m_fd_sorts.remove(*it); - } + for (sort* s : m_non_fd_sorts) + m_fd_sorts.remove(s); if (!m_fd_sorts.empty()) { ref ext = alloc(extension_model_converter, m); ref filter = alloc(filter_model_converter, m); @@ -152,21 +150,12 @@ public: } expr_ref_vector bounds(m); rw.flush_side_constraints(bounds); - for (unsigned i = 0; i < bounds.size(); ++i) { - g->assert_expr(bounds[i].get()); - } - { - obj_map::iterator it = rw.enum2bv().begin(), end = rw.enum2bv().end(); - for (; it != end; ++it) { - filter->insert(it->m_value); - } - } - { - obj_map::iterator it = rw.enum2def().begin(), end = rw.enum2def().end(); - for (; it != end; ++it) { - ext->insert(it->m_key, it->m_value); - } - } + for (expr* b : bounds) + g->assert_expr(b); + for (auto const& kv : rw.enum2bv()) + filter->insert(kv.m_value); + for (auto const& kv : rw.enum2def()) + ext->insert(kv.m_key, kv.m_value); mc = concat(filter.get(), ext.get()); report_tactic_progress(":fd-num-translated", rw.num_translated()); diff --git a/src/tactic/converter.h b/src/tactic/converter.h index 9de8218c3..84df02c94 100644 --- a/src/tactic/converter.h +++ b/src/tactic/converter.h @@ -38,8 +38,7 @@ public: virtual void cancel() {} - // for debugging purposes - virtual void display(std::ostream & out) {} + virtual void display(std::ostream & out) = 0; }; template @@ -68,10 +67,8 @@ public: virtual char const * get_name() const = 0; virtual void display(std::ostream & out) { - out << "(" << get_name() << "\n"; m_c1->display(out); m_c2->display(out); - out << ")\n"; } }; @@ -86,10 +83,9 @@ protected: T * translate_core(ast_translation & translator) { T * t1 = m_c1 ? m_c1->translate(translator) : 0; ptr_buffer t2s; - unsigned num = m_c2s.size(); - for (unsigned i = 0; i < num; i++) - t2s.push_back(m_c2s[i] ? m_c2s[i]->translate(translator) : 0); - return alloc(T2, t1, num, t2s.c_ptr(), m_szs.c_ptr()); + for (T* c : m_c2s) + t2s.push_back(c ? c->translate(translator) : 0); + return alloc(T2, t1, m_c2s.size(), t2s.c_ptr(), m_szs.c_ptr()); } public: @@ -105,36 +101,24 @@ public: } virtual ~concat_star_converter() { - unsigned sz = m_c2s.size(); - for (unsigned i = 0; i < sz; i++) { - T * c2 = m_c2s[i]; - if (c2) - c2->dec_ref(); - } + for (T* c : m_c2s) + if (c) c->dec_ref(); } virtual void cancel() { if (m_c1) m_c1->cancel(); - unsigned num = m_c2s.size(); - for (unsigned i = 0; i < num; i++) { - if (m_c2s[i]) - m_c2s[i]->cancel(); - } + for (T* c : m_c2s) + if (c) c->cancel(); } virtual char const * get_name() const = 0; virtual void display(std::ostream & out) { - out << "(" << get_name() << "\n"; if (m_c1) m_c1->display(out); - out << "(\n"; - unsigned num = m_c2s.size(); - for (unsigned i = 0; i < num; i++) - if (m_c2s[i]) - m_c2s[i]->display(out); - out << "))\n"; + for (T* c : m_c2s) + if (c) c->display(out); } }; diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 6a38f787e..614b20a10 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -17,7 +17,7 @@ Notes: --*/ #include "tactic/tactical.h" -#include "tactic/extension_model_converter.h" +#include "tactic/generic_model_converter.h" #include "tactic/filter_model_converter.h" #include "ast/rewriter/rewriter_def.h" #include "ast/arith_decl_plugin.h" @@ -34,7 +34,7 @@ class elim_uncnstr_tactic : public tactic { struct imp { // unconstrained vars collector - typedef extension_model_converter mc; + typedef generic_model_converter mc; struct rw_cfg : public default_rewriter_cfg { bool m_produce_proofs; @@ -120,7 +120,7 @@ class elim_uncnstr_tactic : public tactic { SASSERT(uncnstr(v)); SASSERT(to_app(v)->get_num_args() == 0); if (m_mc) - m_mc->insert(to_app(v)->get_decl(), def); + m_mc->add(to_app(v)->get_decl(), def); } void add_defs(unsigned num, expr * const * args, expr * u, expr * identity) { diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 6a0d7205b..c52f0526b 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -50,8 +50,8 @@ public: virtual void operator()(model_ref & mdl, unsigned goal_idx) { SASSERT(goal_idx == 0); - for (unsigned i = 0; i < m_const.size(); ++i) { - mdl->register_decl(m_const[i].first->get_decl(), m_const[i].second); + for (auto const& kv : m_const) { + mdl->register_decl(kv.first->get_decl(), kv.second); } } @@ -65,12 +65,18 @@ public: virtual model_converter * translate(ast_translation & translator) { pb_preproc_model_converter* mc = alloc(pb_preproc_model_converter, translator.to()); - for (unsigned i = 0; i < m_const.size(); ++i) { - mc->set_value_p(translator(m_const[i].first), translator(m_const[i].second)); + for (auto const& kv : m_const) { + mc->set_value_p(translator(kv.first), translator(kv.second)); } return mc; } + virtual void display(std::ostream & out) { + for (auto const& kv : m_const) { + out << "(model-set " << mk_pp(kv.first, m) << " " << mk_pp(kv.second, m) << ")\n"; + } + } + private: void set_value_p(app* e, expr* v) { SASSERT(e->get_num_args() == 0); diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index 7a2df81b5..a120f2910 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -79,6 +79,8 @@ class split_clause_tactic : public tactic { virtual proof_converter * translate(ast_translation & translator) { return alloc(split_pc, translator.to(), translator(m_clause), translator(m_clause_pr)); } + + virtual void display(std::ostream & out) { out << "(split-clause-pc)\n"; } }; public: diff --git a/src/tactic/equiv_proof_converter.h b/src/tactic/equiv_proof_converter.h index 79f5142b2..0ee44aec2 100644 --- a/src/tactic/equiv_proof_converter.h +++ b/src/tactic/equiv_proof_converter.h @@ -47,6 +47,7 @@ public: ast_manager& get_manager() { return m; } + virtual void display(std::ostream & out) {} }; #endif diff --git a/src/tactic/extension_model_converter.cpp b/src/tactic/extension_model_converter.cpp index 38f0100ee..0ae4e1323 100644 --- a/src/tactic/extension_model_converter.cpp +++ b/src/tactic/extension_model_converter.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Model converter that introduces eliminated variables in a model. +Model converter that introduces eliminated variables in a model. Author: @@ -16,11 +16,11 @@ Author: Notes: --*/ -#include "tactic/extension_model_converter.h" -#include "model/model_evaluator.h" -#include "ast/ast_smt2_pp.h" -#include "model/model_v2_pp.h" #include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" +#include "model/model_evaluator.h" +#include "model/model_v2_pp.h" +#include "tactic/extension_model_converter.h" extension_model_converter::~extension_model_converter() { } @@ -78,20 +78,17 @@ void extension_model_converter::insert(func_decl * v, expr * def) { void extension_model_converter::display(std::ostream & out) { - out << "(extension-model-converter"; for (unsigned i = 0; i < m_vars.size(); i++) { - out << "\n (" << m_vars.get(i)->get_name() << " "; - unsigned indent = m_vars.get(i)->get_name().size() + 4; - out << mk_ismt2_pp(m_defs.get(i), m(), indent) << ")"; + display_add(out, m(), m_vars.get(i), m_defs.get(i)); } - out << ")" << std::endl; } model_converter * extension_model_converter::translate(ast_translation & translator) { extension_model_converter * res = alloc(extension_model_converter, translator.to()); - for (unsigned i = 0; i < m_vars.size(); i++) - res->m_vars.push_back(translator(m_vars[i].get())); - for (unsigned i = 0; i < m_defs.size(); i++) - res->m_defs.push_back(translator(m_defs[i].get())); + for (func_decl* v : m_vars) + res->m_vars.push_back(translator(v)); + for (expr* d : m_defs) + res->m_defs.push_back(translator(d)); return res; } + diff --git a/src/tactic/extension_model_converter.h b/src/tactic/extension_model_converter.h index dbd7a7e3b..7ee6c68f5 100644 --- a/src/tactic/extension_model_converter.h +++ b/src/tactic/extension_model_converter.h @@ -23,12 +23,11 @@ Notes: #include "ast/ast.h" #include "tactic/model_converter.h" - class extension_model_converter : public model_converter { func_decl_ref_vector m_vars; expr_ref_vector m_defs; public: - extension_model_converter(ast_manager & m):m_vars(m), m_defs(m) { + extension_model_converter(ast_manager & m): m_vars(m), m_defs(m) { } virtual ~extension_model_converter(); @@ -44,6 +43,4 @@ public: virtual model_converter * translate(ast_translation & translator); }; - - #endif diff --git a/src/tactic/filter_model_converter.cpp b/src/tactic/filter_model_converter.cpp index 46328186d..40de848be 100644 --- a/src/tactic/filter_model_converter.cpp +++ b/src/tactic/filter_model_converter.cpp @@ -55,11 +55,9 @@ void filter_model_converter::operator()(svector & labels, unsigned goal_ } void filter_model_converter::display(std::ostream & out) { - out << "(filter-model-converter"; - for (unsigned i = 0; i < m_decls.size(); i++) { - out << " " << m_decls.get(i)->get_name(); + for (func_decl* f : m_decls) { + display_del(out, f); } - out << ")" << std::endl; } model_converter * filter_model_converter::translate(ast_translation & translator) { diff --git a/src/tactic/filter_model_converter.h b/src/tactic/filter_model_converter.h index b5d6b86f4..1cb6ec056 100644 --- a/src/tactic/filter_model_converter.h +++ b/src/tactic/filter_model_converter.h @@ -24,7 +24,7 @@ Notes: class filter_model_converter : public model_converter { func_decl_ref_vector m_decls; public: - filter_model_converter(ast_manager & m):m_decls(m) {} + filter_model_converter(ast_manager & m): m_decls(m) {} virtual ~filter_model_converter(); diff --git a/src/tactic/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h index 1c1ae9feb..74d5882a5 100644 --- a/src/tactic/horn_subsume_model_converter.h +++ b/src/tactic/horn_subsume_model_converter.h @@ -78,6 +78,7 @@ public: ast_manager& get_manager() { return m; } + virtual void display(std::ostream & out) {} }; #endif diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 4269946a1..6984c0536 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -18,10 +18,53 @@ Notes: --*/ #include "tactic/model_converter.h" #include "model/model_v2_pp.h" +#include "ast/ast_smt2_pp.h" + +/* + * Add or overwrite value in model. + */ +void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { + // TBD: for arity > 0, requires signature of arguments. + if (m_env) { + ast_smt2_pp(out, f, e, *m_env, params_ref(), 0, "model-add"); + } + else { + unsigned indent = f->get_name().size() + 4; + out << "(model-add " << f->get_name() << " " << mk_ismt2_pp(e, m, indent) << ")\n"; + } +} + +/* + * A value is removed from the model. + */ +void model_converter::display_del(std::ostream& out, func_decl* f) const { + if (m_env) { + ast_smt2_pp(out, f, *m_env, params_ref(), 0, "model-del"); + } + else { + out << "(model-del " << f->get_name() << ")\n"; + } +} + +void model_converter::display_add(std::ostream& out, ast_manager& m) { + // default printer for converter that adds entries + model_ref mdl = alloc(model, m); + (*this)(mdl); + for (unsigned i = 0, sz = mdl->get_num_constants(); i < sz; ++i) { + func_decl* f = mdl->get_constant(i); + display_add(out, m, f, mdl->get_const_interp(f)); + } + for (unsigned i = 0, sz = mdl->get_num_functions(); i < sz; ++i) { + func_decl* f = mdl->get_function(i); + func_interp* fi = mdl->get_func_interp(f); + display_add(out, m, f, fi->get_interp()); + } +} + class concat_model_converter : public concat_converter { public: - concat_model_converter(model_converter * mc1, model_converter * mc2):concat_converter(mc1, mc2) {} + concat_model_converter(model_converter * mc1, model_converter * mc2): concat_converter(mc1, mc2) {} virtual void operator()(model_ref & m) { this->m_c2->operator()(m); @@ -37,7 +80,6 @@ public: this->m_c2->operator()(r, goal_idx); this->m_c1->operator()(r, 0); } - virtual char const * get_name() const { return "concat-model-converter"; } @@ -90,9 +132,9 @@ public: // found the model converter that should be used model_converter * c2 = this->m_c2s[i]; if (c2) - c2->operator()(r, goal_idx); + c2->operator()(r, goal_idx); if (m_c1) - this->m_c1->operator()(r, i); + this->m_c1->operator()(r, i); return; } // invalid goal @@ -143,10 +185,10 @@ public: } virtual void operator()(labels_vec & r, unsigned goal_idx) { - r.append(m_labels.size(), m_labels.c_ptr()); + r.append(m_labels.size(), m_labels.c_ptr()); } - virtual void cancel() { + virtual void cancel() { } virtual void display(std::ostream & out) { diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 5e549344e..02e59f6d5 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -24,9 +24,19 @@ Notes: #include "util/ref.h" class labels_vec : public svector {}; +class smt2_pp_environment; class model_converter : public converter { +protected: + smt2_pp_environment* m_env; + void display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const; + void display_del(std::ostream& out, func_decl* f) const; + void display_add(std::ostream& out, ast_manager& m); + public: + + model_converter(): m_env(0) {} + virtual void operator()(model_ref & m) {} // TODO: delete virtual void operator()(model_ref & m, unsigned goal_idx) { @@ -34,10 +44,12 @@ public: SASSERT(goal_idx == 0); operator()(m); } - virtual void operator()(labels_vec & r, unsigned goal_idx) {} + virtual model_converter * translate(ast_translation & translator) = 0; + + void set_pp_env(smt2_pp_environment* env) { m_env = env; } }; typedef ref model_converter_ref; diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index db8a1fe53..9e4a0c547 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -150,7 +150,7 @@ public: virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model(model_ref & mdl) { + virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { extend_model(mdl); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index c5c7e3028..1df7a000c 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -95,7 +95,7 @@ public: virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model(model_ref & mdl) { + virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { extend_model(mdl); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 4ff7251be..44898a578 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -87,7 +87,7 @@ public: m_solver->collect_statistics(st); } virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model(model_ref & mdl) { + virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { filter_model(mdl); diff --git a/src/tactic/replace_proof_converter.h b/src/tactic/replace_proof_converter.h index b768a18a0..d5cf7dc31 100644 --- a/src/tactic/replace_proof_converter.h +++ b/src/tactic/replace_proof_converter.h @@ -45,6 +45,8 @@ public: // run the replacements the inverse direction. void invert() { m_proofs.reverse(); } + virtual void display(std::ostream & out) {} + }; #endif diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 6c4ca7476..7610c420a 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -175,7 +175,7 @@ void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_conve } -lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { +lbool check_sat(tactic & t, goal_ref & g, model_ref & md, model_converter_ref& mc, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { bool models_enabled = g->models_enabled(); bool proofs_enabled = g->proofs_enabled(); bool cores_enabled = g->unsat_core_enabled(); @@ -184,7 +184,6 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p core = 0; ast_manager & m = g->m(); goal_ref_buffer r; - model_converter_ref mc; proof_converter_ref pc; try { exec(t, g, r, mc, pc, core); @@ -219,9 +218,9 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p } else { if (models_enabled) { - model_converter2model(m, mc.get(), md); - if (mc) - (*mc)(labels, 0); + model_converter2model(m, mc.get(), md); + if (mc) + (*mc)(labels, 0); } reason_unknown = "incomplete"; return l_undef; diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 0e4c61611..93da52366 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -153,7 +153,7 @@ public: #define MK_SIMPLE_TACTIC_FACTORY(NAME, ST) MK_TACTIC_FACTORY(NAME, return ST;) void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); -lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); +lbool check_sat(tactic & t, goal_ref & g, model_ref & md, model_converter_ref& mc, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); // Throws an exception if goal \c in requires proof generation. void fail_if_proof_generation(char const * tactic_name, goal_ref const & in); From caaf0ba33cd51ff740d508e2bc0a5abe69bd9965 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Nov 2017 22:32:22 -0500 Subject: [PATCH 0313/1283] model-add/del Signed-off-by: Nikolaj Bjorner --- src/ast/ast_pp_util.cpp | 4 +- src/ast/ast_smt2_pp.cpp | 25 +- src/ast/ast_smt2_pp.h | 1 + src/ast/ast_smt_pp.cpp | 15 +- src/ast/ast_smt_pp.h | 2 +- src/ast/decl_collector.cpp | 39 ++-- src/ast/decl_collector.h | 3 +- src/cmd_context/cmd_context.cpp | 3 + src/cmd_context/cmd_context.h | 3 +- src/cmd_context/tactic_cmds.cpp | 2 + src/parsers/smt2/smt2parser.cpp | 10 +- src/sat/sat_model_converter.cpp | 22 +- src/sat/sat_model_converter.h | 28 ++- src/sat/sat_solver.cpp | 3 +- src/sat/sat_solver/inc_sat_solver.cpp | 28 +-- src/sat/tactic/goal2sat.cpp | 218 +++++++++--------- src/solver/solver.cpp | 18 +- src/solver/tactic2solver.cpp | 2 +- src/tactic/bv/bit_blaster_model_converter.cpp | 34 +-- src/tactic/bv/bit_blaster_tactic.cpp | 2 +- src/tactic/converter.h | 8 +- src/tactic/filter_model_converter.cpp | 11 +- src/tactic/filter_model_converter.h | 6 +- src/tactic/model_converter.cpp | 27 +-- src/tactic/model_converter.h | 5 +- .../portfolio/bounded_int2bv_solver.cpp | 1 + src/tactic/portfolio/enum2bv_solver.cpp | 1 + src/tactic/portfolio/pb2bv_solver.cpp | 1 + 28 files changed, 271 insertions(+), 251 deletions(-) diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index bbd1d0f41..43dccac02 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -45,10 +45,10 @@ void ast_pp_util::display_decls(std::ostream& out) { for (unsigned i = 0; i < n; ++i) { func_decl* f = coll.get_func_decls()[i]; if (f->get_family_id() == null_family_id) { - ast_smt2_pp(out, f, m_env); - out << "\n"; + ast_smt2_pp(out, f, m_env) << "\n"; } } + SASSERT(coll.get_num_preds() == 0); } void ast_pp_util::display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat) { diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index db66d9097..87ca5652a 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -599,9 +599,9 @@ class smt2_printer { return f; ptr_buffer buf; buf.push_back(f); - for (unsigned i = 0; i < names.size(); i++) { - buf.push_back(pp_simple_attribute(is_pos ? ":lblpos " : ":lblneg ", names[i])); - } + for (symbol const& n : names) + buf.push_back(pp_simple_attribute(is_pos ? ":lblpos " : ":lblneg ", n)); + return mk_seq1(m(), buf.begin(), buf.end(), f2f(), "!"); } @@ -1244,6 +1244,15 @@ std::ostream & ast_smt2_pp(std::ostream & out, unsigned sz, expr * const* es, sm return out; } +std::ostream & ast_smt2_pp(std::ostream & out, symbol const& s, bool is_skolem, smt2_pp_environment & env, params_ref const& p) { + unsigned len; + ast_manager & m = env.get_manager(); + format_ref r(fm(m)); + r = env.pp_fdecl_name(s, len, is_skolem); + pp(out, r.get(), m, p); + return out; +} + mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent, unsigned num_vars, char const * var_prefix): m_ast(t), m_manager(m), @@ -1262,6 +1271,8 @@ mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent, unsigned num m_var_prefix(var_prefix) { } + + std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) { smt2_pp_environment_dbg env(p.m_manager); if (p.m_ast == 0) { @@ -1309,14 +1320,14 @@ std::ostream& operator<<(std::ostream& out, app_ref_vector const& e) { } std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e) { - for (unsigned i = 0; i < e.size(); ++i) - out << mk_ismt2_pp(e[i], e.get_manager()) << "\n"; + for (func_decl* f : e) + out << mk_ismt2_pp(f, e.get_manager()) << "\n"; return out; } std::ostream& operator<<(std::ostream& out, sort_ref_vector const& e) { - for (unsigned i = 0; i < e.size(); ++i) - out << mk_ismt2_pp(e[i], e.get_manager()) << "\n"; + for (sort* s : e) + out << mk_ismt2_pp(s, e.get_manager()) << "\n"; return out; } diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 8a4b3d80a..a1a457916 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -104,6 +104,7 @@ std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & e std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0); std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "declare-fun"); std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, expr* e, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, char const* cmd = "define-fun"); +std::ostream & ast_smt2_pp(std::ostream & out, symbol const& s, bool is_skolem, smt2_pp_environment & env, params_ref const& p = params_ref()); /** \brief Internal wrapper (for debugging purposes only) diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index f8501824a..59b66d082 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -45,14 +45,6 @@ symbol smt_renaming::fix_symbol(symbol s, int k) { std::ostringstream buffer; char const * data = s.is_numerical() ? "" : s.bare_str(); - if (data[0] && !data[1]) { - switch (data[0]) { - case '/': data = "op_div"; break; - case '%': data = "op_mod"; break; - default: break; - } - } - if (k == 0 && *data) { if (s.is_numerical()) { return s; @@ -80,7 +72,7 @@ symbol smt_renaming::fix_symbol(symbol s, int k) { buffer << s; } if (k > 0) { - buffer << k; + buffer << "!" << k; } return symbol(buffer.str().c_str()); @@ -139,6 +131,9 @@ symbol smt_renaming::get_symbol(symbol s0, bool is_skolem) { if (m_translate.find(s0, sb)) { if (is_skolem == sb.is_skolem) return sb.name; + if (sb.name_aux != symbol::null) { + return sb.name_aux; + } int k = 0; symbol s1; do { @@ -146,6 +141,8 @@ symbol smt_renaming::get_symbol(symbol s0, bool is_skolem) { } while (s == s0 || (m_rev_translate.find(s, s1) && s1 != s0)); m_rev_translate.insert(s, s0); + sb.name_aux = s; + m_translate.insert(s, sb); return s; } diff --git a/src/ast/ast_smt_pp.h b/src/ast/ast_smt_pp.h index 766c8530c..fd2cd186b 100644 --- a/src/ast/ast_smt_pp.h +++ b/src/ast/ast_smt_pp.h @@ -24,7 +24,7 @@ Revision History: #include "util/map.h" class smt_renaming { - struct sym_b { symbol name; bool is_skolem; sym_b(symbol n, bool s): name(n), is_skolem(s) {} sym_b():name(),is_skolem(false) {}}; + struct sym_b { symbol name; bool is_skolem; symbol name_aux; sym_b(symbol n, bool s): name(n), is_skolem(s) {} sym_b():name(),is_skolem(false) {}}; typedef map symbol2symbol; typedef map symbol2sym_b; symbol2sym_b m_translate; diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index e000f43df..0df4b0fc5 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -45,12 +45,14 @@ bool decl_collector::is_bool(sort * s) { } void decl_collector::visit_func(func_decl * n) { - family_id fid = n->get_family_id(); - if (fid == null_family_id) { - if (m_sep_preds && is_bool(n->get_range())) - m_preds.push_back(n); - else - m_decls.push_back(n); + if (!m_visited.is_marked(n)) { + family_id fid = n->get_family_id(); + if (fid == null_family_id) { + if (m_sep_preds && is_bool(n->get_range())) + m_preds.push_back(n); + else + m_decls.push_back(n); + } } } @@ -63,31 +65,29 @@ decl_collector::decl_collector(ast_manager & m, bool preds): } void decl_collector::visit(ast* n) { - ptr_vector todo; - todo.push_back(n); - while (!todo.empty()) { - n = todo.back(); - todo.pop_back(); + m_todo.push_back(n); + while (!m_todo.empty()) { + n = m_todo.back(); + m_todo.pop_back(); if (!m_visited.is_marked(n)) { - m_visited.mark(n, true); switch(n->get_kind()) { case AST_APP: { app * a = to_app(n); for (unsigned i = 0; i < a->get_num_args(); ++i) { - todo.push_back(a->get_arg(i)); + m_todo.push_back(a->get_arg(i)); } - todo.push_back(a->get_decl()); + m_todo.push_back(a->get_decl()); break; } case AST_QUANTIFIER: { quantifier * q = to_quantifier(n); unsigned num_decls = q->get_num_decls(); for (unsigned i = 0; i < num_decls; ++i) { - todo.push_back(q->get_decl_sort(i)); + m_todo.push_back(q->get_decl_sort(i)); } - todo.push_back(q->get_expr()); + m_todo.push_back(q->get_expr()); for (unsigned i = 0; i < q->get_num_patterns(); ++i) { - todo.push_back(q->get_pattern(i)); + m_todo.push_back(q->get_pattern(i)); } break; } @@ -97,9 +97,9 @@ void decl_collector::visit(ast* n) { case AST_FUNC_DECL: { func_decl * d = to_func_decl(n); for (unsigned i = 0; i < d->get_arity(); ++i) { - todo.push_back(d->get_domain(i)); + m_todo.push_back(d->get_domain(i)); } - todo.push_back(d->get_range()); + m_todo.push_back(d->get_range()); visit_func(d); break; } @@ -108,6 +108,7 @@ void decl_collector::visit(ast* n) { default: UNREACHABLE(); } + m_visited.mark(n, true); } } } diff --git a/src/ast/decl_collector.h b/src/ast/decl_collector.h index 053d6df41..0a812bb2c 100644 --- a/src/ast/decl_collector.h +++ b/src/ast/decl_collector.h @@ -36,7 +36,7 @@ class decl_collector { void visit_sort(sort* n); bool is_bool(sort* s); - void visit_func(func_decl* n); + ptr_vector m_todo; public: @@ -44,6 +44,7 @@ public: decl_collector(ast_manager & m, bool preds=true); ast_manager & m() { return m_manager; } + void visit_func(func_decl* n); void visit(ast * n); void visit(unsigned n, expr* const* es); void visit(expr_ref_vector const& es); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 97c53d423..ee36468a5 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -868,6 +868,9 @@ void cmd_context::insert(symbol const & s, object_ref * r) { void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domain, expr * t) { if (!m_mc0) m_mc0 = alloc(generic_model_converter, m()); func_decl_ref fn(m().mk_func_decl(s, arity, domain, m().get_sort(t)), m()); + dictionary::entry * e = m_func_decls.insert_if_not_there2(s, func_decls()); + func_decls & fs = e->get_data().m_value; + fs.insert(m(), fn); m_mc0->add(fn, t); } diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 48dd17cb0..abf19a487 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -304,7 +304,7 @@ protected: void erase_macro(symbol const& s); bool macros_find(symbol const& s, unsigned n, expr*const* args, expr*& t) const; - ref m_mc0; + generic_model_converter_ref m_mc0; public: cmd_context(bool main_ctx = true, ast_manager * m = 0, symbol const & l = symbol::null); @@ -324,6 +324,7 @@ public: void set_numeral_as_real(bool f) { m_numeral_as_real = f; } void set_interactive_mode(bool flag) { m_interactive_mode = flag; } void set_ignore_check(bool flag) { m_ignore_check = flag; } + bool ignore_check() const { return m_ignore_check; } void set_exit_on_error(bool flag) { m_exit_on_error = flag; } bool exit_on_error() const { return m_exit_on_error; } bool interactive_mode() const { return m_interactive_mode; } diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 20a2b1c11..cd5eff9a6 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -200,6 +200,8 @@ public: if (!m_tactic) { throw cmd_exception("check-sat-using needs a tactic argument"); } + if (ctx.ignore_check()) + return; params_ref p = ctx.params().merge_default_params(ps()); tactic_ref tref = using_params(sexpr2tactic(ctx, m_tactic), p); tref->set_logic(ctx.get_logic()); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 446059227..d73580323 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -2222,11 +2222,13 @@ namespace smt2 { } void parse_model_del() { - func_decl* f = parse_func_decl_ref(); - check_rparen("invalid model-del, ')' expected"); - m_ctx.model_del(f); - m_ctx.print_success(); next(); + symbol id = curr_id(); + func_decl * f = m_ctx.find_func_decl(id); + m_ctx.model_del(f); + next(); + check_rparen_next("invalid model-del, ')' expected"); + m_ctx.print_success(); } void parse_define_fun_rec() { diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 7339f966d..d46063455 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -59,7 +59,7 @@ namespace sat { vector::const_iterator begin = m_entries.begin(); vector::const_iterator it = m_entries.end(); bool first = true; - VERIFY(!m_solver || m_solver->check_clauses(m)); + //VERIFY(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; SASSERT(it->get_kind() != ELIM_VAR || m[it->var()] == l_undef); @@ -80,7 +80,7 @@ namespace sat { process_stack(m, clause, st->stack()); } sat = false; - if (first && m_solver && !m_solver->check_clauses(m)) { + if (false && first && m_solver && !m_solver->check_clauses(m)) { display(std::cout, *it) << "\n"; first = false; } @@ -94,6 +94,8 @@ namespace sat { continue; bool sign = l.sign(); bool_var v = l.var(); + if (v >= m.size()) std::cout << v << " model size: " << m.size() << "\n"; + VERIFY(v < m.size()); if (v == it->var()) var_sign = sign; if (value_at(l, m) == l_true) @@ -103,7 +105,7 @@ namespace sat { m[v] = sign ? l_false : l_true; // if (first) std::cout << "set: " << l << "\n"; sat = true; - if (first && m_solver && !m_solver->check_clauses(m)) { + if (false && first && m_solver && !m_solver->check_clauses(m)) { display(std::cout, *it) << "\n";; first = false; } @@ -289,7 +291,7 @@ namespace sat { out << ")"; for (literal l : entry.m_clauses) { if (l != null_literal) { - if (m_solver && m_solver->was_eliminated(l.var())) out << "\neliminated: " << l; + if (false && m_solver && m_solver->was_eliminated(l.var())) out << "\neliminated: " << l; } } return out; @@ -317,12 +319,12 @@ namespace sat { return result; } - void model_converter::expand(vector& update_stack) { - literal_vector clause; + void model_converter::expand(literal_vector& update_stack) { + sat::literal_vector clause; for (entry const& e : m_entries) { - clause.reset(); unsigned index = 0; bool var_sign = false; + clause.reset(); for (literal l : e.m_clauses) { if (l == null_literal) { elim_stack* st = e.m_elim_stack[index]; @@ -343,10 +345,12 @@ namespace sat { } } SASSERT(found); - update_stack.push_back(literal_vector(csz, clause.c_ptr())); + update_stack.append(csz, clause.c_ptr()); + update_stack.push_back(null_literal); } } - update_stack.push_back(clause); + update_stack.append(clause); + update_stack.push_back(null_literal); clause.reset(); continue; } diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index a6f1f0bbe..8f8b1a41b 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -39,39 +39,47 @@ namespace sat { class solver; + static unsigned counter = 0; + class model_converter { public: typedef svector> elim_stackv; + class elim_stack { - unsigned m_refcount; + unsigned m_counter; + unsigned m_refcount; elim_stackv m_stack; + elim_stack(elim_stack const& ); public: elim_stack(elim_stackv const& stack): + m_counter(0), m_refcount(0), m_stack(stack) { + m_counter = ++counter; } ~elim_stack() { } void inc_ref() { ++m_refcount; } - void dec_ref() { if (0 == --m_refcount) dealloc(this); } + void dec_ref() { if (0 == --m_refcount) { dealloc(this); } } elim_stackv const& stack() const { return m_stack; } + unsigned ref_count() const { return m_refcount; } }; enum kind { ELIM_VAR = 0, BLOCK_LIT, CCE, ACCE }; class entry { friend class model_converter; - unsigned m_var:30; - unsigned m_kind:2; - literal_vector m_clauses; // the different clauses are separated by null_literal - sref_vector m_elim_stack; - entry(kind k, bool_var v):m_var(v), m_kind(k) {} + unsigned m_var:30; + unsigned m_kind:2; + literal_vector m_clauses; // the different clauses are separated by null_literal + sref_vector m_elim_stack; + entry(kind k, bool_var v): m_var(v), m_kind(k) {} public: entry(entry const & src): m_var(src.m_var), m_kind(src.m_kind), - m_clauses(src.m_clauses), - m_elim_stack(src.m_elim_stack) { + m_clauses(src.m_clauses) { + m_elim_stack.append(src.m_elim_stack); } bool_var var() const { return m_var; } kind get_kind() const { return static_cast(m_kind); } @@ -115,7 +123,7 @@ namespace sat { * lit0 := lit0 or (~lit1 & ~lit2 & ... & ~lit_k) * */ - void expand(vector& update_stack); + void expand(literal_vector& update_stack); }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0fb4dce93..6a9d1d5bb 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -61,6 +61,7 @@ namespace sat { m_num_checkpoints = 0; m_simplifications = 0; m_cuber = nullptr; + m_mc.set_solver(nullptr); } solver::~solver() { @@ -1550,7 +1551,7 @@ namespace sat { if (m_config.m_drat) m_drat.check_model(m_model); - // m_mc.set_solver(this); + m_mc.set_solver(nullptr); m_mc(m_model); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 218646de3..59f1a4a71 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -61,6 +61,7 @@ class inc_sat_solver : public solver { proof_converter_ref m_pc; model_converter_ref m_mc; model_converter_ref m_mc0; + model_converter_ref m_sat_mc; expr_dependency_ref m_dep_core; svector m_weights; std::string m_unknown; @@ -444,10 +445,11 @@ public: } virtual model_converter_ref get_model_converter() const { - if (m_internalized && m_internalized_converted) { - NOT_IMPLEMENTED_YET(); + const_cast(this)->convert_internalized(); + if (m_internalized && m_internalized_converted) { model_converter_ref mc = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); mc = concat(solver::get_model_converter().get(), mc.get()); + mc = concat(mc.get(), m_sat_mc.get()); return mc; } else { @@ -456,28 +458,14 @@ public: } void convert_internalized() { - if (!m_internalized) return; + if (!m_internalized || m_internalized_converted) return; sat2goal s2g; - model_converter_ref mc; - goal g(m, false, false, false); - s2g(m_solver, m_map, m_params, g, mc); - extract_model(); - if (!m_model) { - m_model = alloc(model, m); - } - model_ref mdl = m_model; - if (m_mc) (*m_mc)(mdl); - for (unsigned i = 0; i < mdl->get_num_constants(); ++i) { - func_decl* c = mdl->get_constant(i); - expr_ref eq(m.mk_eq(m.mk_const(c), mdl->get_const_interp(c)), m); - g.assert_expr(eq); - } + m_sat_mc = nullptr; + goal g(m, false, true, false); + s2g(m_solver, m_map, m_params, g, m_sat_mc); m_internalized_fmls.reset(); g.get_formulas(m_internalized_fmls); m_internalized_converted = true; - // if (mc) mc->display(std::cout << "mc"); - // if (m_mc) m_mc->display(std::cout << "m_mc\n"); - // if (m_mc0) m_mc0->display(std::cout << "m_mc0\n"); } void init_preprocess() { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 8daeb7ec0..48de6d600 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -52,7 +52,7 @@ struct goal2sat::imp { }; ast_manager & m; pb_util pb; - sat::ba_solver* m_ext; + sat::ba_solver* m_ext; svector m_frame_stack; svector m_result_stack; obj_map m_cache; @@ -896,20 +896,34 @@ struct sat2goal::imp { public: sat_model_converter(ast_manager & m, sat::solver const & s):m_var2expr(m) { m_mc.copy(s.get_model_converter()); - m_mc.set_solver(&s); m_fmc = alloc(filter_model_converter, m); } ast_manager & m() { return m_var2expr.get_manager(); } - - void insert(expr * atom, bool aux) { - m_var2expr.push_back(atom); + + void init(unsigned num_vars) { + m_var2expr.resize(num_vars); + } + + void insert(unsigned v, expr * atom, bool aux) { + VERIFY(!m_var2expr.get(v)); + m_var2expr[v] = atom; if (aux) { SASSERT(is_uninterp_const(atom)); SASSERT(m().is_bool(atom)); m_fmc->insert(to_app(atom)->get_decl()); } } + + void finish() { + sat::literal_vector updates; + m_mc.expand(updates); + for (sat::literal l : updates) { + if (l != sat::null_literal && !m_var2expr.get(l.var())) { + insert(l.var(), m().mk_fresh_const(0, m().mk_bool_sort()), true); + } + } + } virtual void operator()(model_ref & md, unsigned goal_idx) { SASSERT(goal_idx == 0); @@ -929,6 +943,10 @@ struct sat2goal::imp { sat::model sat_md; expr_ref val(m()); for (expr * atom : m_var2expr) { + if (!atom) { + sat_md.push_back(l_undef); + continue; + } ev(atom, val); if (m().is_true(val)) sat_md.push_back(l_true); @@ -945,7 +963,7 @@ struct sat2goal::imp { unsigned sz = m_var2expr.size(); for (sat::bool_var v = 0; v < sz; v++) { expr * atom = m_var2expr.get(v); - if (is_uninterp_const(atom)) { + if (atom && is_uninterp_const(atom)) { func_decl * d = to_app(atom)->get_decl(); lbool new_val = sat_md[v]; if (new_val == l_true) @@ -964,11 +982,12 @@ struct sat2goal::imp { sat_model_converter * res = alloc(sat_model_converter, translator.to()); res->m_fmc = static_cast(m_fmc->translate(translator)); for (expr* e : m_var2expr) - res->m_var2expr.push_back(translator(e)); + res->m_var2expr.push_back(e ? translator(e) : nullptr); return res; } expr_ref lit2expr(sat::literal l) { + VERIFY(m_var2expr.get(l.var())); expr_ref result(m_var2expr.get(l.var()), m()); if (l.sign()) { result = m().mk_not(result); @@ -977,25 +996,43 @@ struct sat2goal::imp { } void display(std::ostream & out) { - vector updates; + sat::literal_vector updates; m_mc.expand(updates); - for (sat::literal_vector const& clause : updates) { - expr_ref_vector tail(m()); - sat::literal lit0 = clause[0]; - for (unsigned i = 1; i < clause.size(); ++i) { - tail.push_back(lit2expr(~clause[i])); + sat::literal_vector clause; + expr_ref_vector tail(m()); + expr_ref def(m()); + for (sat::literal l : updates) { + if (l == sat::null_literal) { + sat::literal lit0 = clause[0]; + for (unsigned i = 1; i < clause.size(); ++i) { + tail.push_back(lit2expr(~clause[i])); + } + def = m().mk_or(lit2expr(lit0), mk_and(tail)); + if (lit0.sign()) { + lit0.neg(); + def = m().mk_not(def); + } + display_add(out, m(), to_app(lit2expr(lit0))->get_decl(), def); + clause.reset(); + tail.reset(); } - expr_ref def(m().mk_or(lit2expr(lit0), mk_and(tail)), m()); - if (lit0.sign()) { - lit0.neg(); - def = m().mk_not(def); + else { + clause.push_back(l); } - display_add(out, m(), to_app(lit2expr(lit0))->get_decl(), def); } m_fmc->display(out); } + + virtual void collect(ast_pp_util& visitor) { + m_env = &visitor.env(); + for (expr* e : m_var2expr) if (e) visitor.coll.visit(e); + if (m_fmc) m_fmc->collect(visitor); + } + }; + typedef ref sat_model_converter_ref; + ast_manager & m; expr_ref_vector m_lit2expr; unsigned long long m_max_memory; @@ -1019,83 +1056,80 @@ struct sat2goal::imp { throw tactic_exception(TACTIC_MAX_MEMORY_MSG); } - void init_lit2expr(sat::solver const & s, atom2bool_var const & map, model_converter_ref & mc, bool produce_models) { - ref _mc; - if (produce_models) - _mc = alloc(sat_model_converter, m, s); + void init_lit2expr(sat::solver const & s, atom2bool_var const & map, sat_model_converter_ref & mc) { unsigned num_vars = s.num_vars(); m_lit2expr.resize(num_vars * 2); map.mk_inv(m_lit2expr); - sort * b = m.mk_bool_sort(); - for (sat::bool_var v = 0; v < num_vars; v++) { - checkpoint(); - sat::literal l(v, false); - if (m_lit2expr.get(l.index()) == 0) { - SASSERT(m_lit2expr.get((~l).index()) == 0); - app * aux = m.mk_fresh_const(0, b); - if (_mc) - _mc->insert(aux, true); - m_lit2expr.set(l.index(), aux); - m_lit2expr.set((~l).index(), m.mk_not(aux)); - } - else { - if (_mc) - _mc->insert(m_lit2expr.get(l.index()), false); - SASSERT(m_lit2expr.get((~l).index()) != 0); + if (mc) { + mc->init(num_vars); + for (sat::bool_var v = 0; v < num_vars; v++) { + checkpoint(); + sat::literal l(v, false); + if (m_lit2expr.get(l.index())) { + mc->insert(v, m_lit2expr.get(l.index()), false); + SASSERT(m_lit2expr[(~l).index()]); + } } } - mc = _mc.get(); } - expr * lit2expr(sat::literal l) { + expr * lit2expr(sat_model_converter_ref& mc, sat::literal l) { + if (!m_lit2expr.get(l.index())) { + SASSERT(m_lit2expr.get((~l).index()) == 0); + app * aux = m.mk_fresh_const(0, m.mk_bool_sort()); + if (mc) + mc->insert(l.var(), aux, true); + m_lit2expr.set(l.index(), aux); + m_lit2expr.set((~l).index(), m.mk_not(aux)); + } return m_lit2expr.get(l.index()); } - void assert_pb(goal& r, sat::ba_solver::pb const& p) { + void assert_pb(sat_model_converter_ref& mc, goal& r, sat::ba_solver::pb const& p) { pb_util pb(m); ptr_buffer lits; vector coeffs; for (auto const& wl : p) { - lits.push_back(lit2expr(wl.second)); + lits.push_back(lit2expr(mc, wl.second)); coeffs.push_back(rational(wl.first)); } rational k(p.k()); expr_ref fml(pb.mk_ge(p.size(), coeffs.c_ptr(), lits.c_ptr(), k), m); if (p.lit() != sat::null_literal) { - fml = m.mk_eq(lit2expr(p.lit()), fml); + fml = m.mk_eq(lit2expr(mc, p.lit()), fml); } r.assert_expr(fml); } - void assert_card(goal& r, sat::ba_solver::card const& c) { + void assert_card(sat_model_converter_ref& mc, goal& r, sat::ba_solver::card const& c) { pb_util pb(m); ptr_buffer lits; for (sat::literal l : c) { - lits.push_back(lit2expr(l)); + lits.push_back(lit2expr(mc, l)); } expr_ref fml(pb.mk_at_least_k(c.size(), lits.c_ptr(), c.k()), m); if (c.lit() != sat::null_literal) { - fml = m.mk_eq(lit2expr(c.lit()), fml); + fml = m.mk_eq(lit2expr(mc, c.lit()), fml); } r.assert_expr(fml); } - void assert_xor(goal & r, sat::ba_solver::xor const& x) { + void assert_xor(sat_model_converter_ref& mc, goal & r, sat::ba_solver::xor const& x) { ptr_buffer lits; for (sat::literal l : x) { - lits.push_back(lit2expr(l)); + lits.push_back(lit2expr(mc, l)); } expr_ref fml(m.mk_xor(x.size(), lits.c_ptr()), m); if (x.lit() != sat::null_literal) { - fml = m.mk_eq(lit2expr(x.lit()), fml); + fml = m.mk_eq(lit2expr(mc, x.lit()), fml); } r.assert_expr(fml); } - void assert_clauses(sat::solver const & s, sat::clause_vector const& clauses, goal & r, bool asserted) { + void assert_clauses(sat_model_converter_ref& mc, sat::solver const & s, sat::clause_vector const& clauses, goal & r, bool asserted) { ptr_buffer lits; for (sat::clause* cp : clauses) { checkpoint(); @@ -1104,7 +1138,7 @@ struct sat2goal::imp { unsigned sz = c.size(); if (asserted || m_learned || c.glue() <= s.get_config().m_gc_small_lbd) { for (sat::literal l : c) { - lits.push_back(lit2expr(l)); + lits.push_back(lit2expr(mc, l)); } r.assert_expr(m.mk_or(lits.size(), lits.c_ptr())); } @@ -1121,17 +1155,22 @@ struct sat2goal::imp { r.assert_expr(m.mk_false()); return; } - init_lit2expr(s, map, mc, r.models_enabled()); + ref _mc; + if (r.models_enabled()) { + _mc = alloc(sat_model_converter, m, s); + } + mc = _mc.get(); + init_lit2expr(s, map, _mc); // collect units unsigned num_vars = s.num_vars(); for (sat::bool_var v = 0; v < num_vars; v++) { checkpoint(); switch (s.value(v)) { case l_true: - r.assert_expr(lit2expr(sat::literal(v, false))); + r.assert_expr(lit2expr(_mc, sat::literal(v, false))); break; case l_false: - r.assert_expr(lit2expr(sat::literal(v, true))); + r.assert_expr(lit2expr(_mc, sat::literal(v, true))); break; case l_undef: break; @@ -1142,96 +1181,50 @@ struct sat2goal::imp { s.collect_bin_clauses(bin_clauses, m_learned); for (sat::solver::bin_clause const& bc : bin_clauses) { checkpoint(); - r.assert_expr(m.mk_or(lit2expr(bc.first), lit2expr(bc.second))); + r.assert_expr(m.mk_or(lit2expr(_mc, bc.first), lit2expr(_mc, bc.second))); } // collect clauses - assert_clauses(s, s.clauses(), r, true); + assert_clauses(_mc, s, s.clauses(), r, true); sat::ba_solver* ext = get_ba_solver(s); if (ext) { for (auto* c : ext->constraints()) { switch (c->tag()) { case sat::ba_solver::card_t: - assert_card(r, c->to_card()); + assert_card(_mc, r, c->to_card()); break; case sat::ba_solver::pb_t: - assert_pb(r, c->to_pb()); + assert_pb(_mc, r, c->to_pb()); break; case sat::ba_solver::xor_t: - assert_xor(r, c->to_xor()); + assert_xor(_mc, r, c->to_xor()); break; } } } - //s.display(std::cout); - //r.display(std::cout); + if (_mc) _mc->finish(); } - void add_clause(sat::literal_vector const& lits, expr_ref_vector& lemmas) { + void add_clause(sat_model_converter_ref& mc, sat::literal_vector const& lits, expr_ref_vector& lemmas) { expr_ref_vector lemma(m); for (sat::literal l : lits) { - expr* e = m_lit2expr.get(l.index(), 0); + expr* e = lit2expr(mc, l); if (!e) return; lemma.push_back(e); } lemmas.push_back(mk_or(lemma)); } - void add_clause(sat::clause const& c, expr_ref_vector& lemmas) { + void add_clause(sat_model_converter_ref& mc, sat::clause const& c, expr_ref_vector& lemmas) { expr_ref_vector lemma(m); for (sat::literal l : c) { - expr* e = m_lit2expr.get(l.index(), 0); + expr* e = lit2expr(mc, l); if (!e) return; lemma.push_back(e); } lemmas.push_back(mk_or(lemma)); } - void get_learned(sat::solver const& s, atom2bool_var const& map, expr_ref_vector& lemmas) { - if (s.inconsistent()) { - lemmas.push_back(m.mk_false()); - return; - } - - unsigned num_vars = s.num_vars(); - m_lit2expr.resize(num_vars * 2); - map.mk_inv(m_lit2expr); - - sat::literal_vector lits; - // collect units - for (sat::bool_var v = 0; v < num_vars; v++) { - checkpoint(); - lits.reset(); - switch (s.value(v)) { - case l_true: - lits.push_back(sat::literal(v, false)); - add_clause(lits, lemmas); - break; - case l_false: - lits.push_back(sat::literal(v, false)); - add_clause(lits, lemmas); - break; - case l_undef: - break; - } - } - // collect learned binary clauses - svector bin_clauses; - s.collect_bin_clauses(bin_clauses, true, true); - for (sat::solver::bin_clause const& bc : bin_clauses) { - checkpoint(); - lits.reset(); - lits.push_back(bc.first); - lits.push_back(bc.second); - add_clause(lits, lemmas); - } - // collect clauses - for (sat::clause const* c : s.learned()) { - add_clause(*c, lemmas); - } - } - - }; sat2goal::sat2goal():m_imp(0) { @@ -1260,9 +1253,4 @@ void sat2goal::operator()(sat::solver const & t, atom2bool_var const & m, params proc(t, m, g, mc); } -void sat2goal::get_learned(sat::solver const & t, atom2bool_var const & m, params_ref const& p, expr_ref_vector& lemmas) { - imp proc(lemmas.get_manager(), p); - scoped_set_imp set(this, &proc); - proc.get_learned(t, m, lemmas); -} diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 122bb2933..c7f385416 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -37,16 +37,26 @@ expr * solver::get_assertion(unsigned idx) const { std::ostream& solver::display(std::ostream & out) const { expr_ref_vector fmls(get_manager()); + std::cout << "display 1\n"; get_assertions(fmls); + std::cout << "display 2\n"; ast_pp_util visitor(get_manager()); - visitor.collect(fmls); - visitor.display_decls(out); - visitor.display_asserts(out, fmls, true); model_converter_ref mc = get_model_converter(); + std::cout << "display 3\n"; + if (mc.get()) { + mc->collect(visitor); + } + std::cout << "display 4\n"; + visitor.collect(fmls); + std::cout << "display 5\n"; + visitor.display_decls(out); + std::cout << "display 6\n"; + visitor.display_asserts(out, fmls, true); + std::cout << "display 7\n"; if (mc.get()) { - mc->set_pp_env(&visitor.env()); mc->display(out); } + std::cout << "display 8\n"; return out; } diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 1dd48fb9c..b9f269b6d 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -83,7 +83,7 @@ public: return expr_ref(m.mk_true(), m); } - virtual model_converter* get_model_converter() { return m_mc.get(); } + virtual model_converter_ref get_model_converter() const { return m_mc; } }; diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index b21defd44..d8dbb77a4 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -34,11 +34,9 @@ struct bit_blaster_model_converter : public model_converter { ast_manager & m() const { return m_vars.get_manager(); } bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits):m_vars(m), m_bits(m) { - obj_map::iterator it = const2bits.begin(); - obj_map::iterator end = const2bits.end(); - for (; it != end; ++it) { - func_decl * v = it->m_key; - expr * bits = it->m_value; + for (auto const& kv : const2bits) { + func_decl * v = kv.m_key; + expr * bits = kv.m_value; SASSERT(!TO_BOOL || is_app_of(bits, m.get_family_id("bv"), OP_MKBV)); SASSERT(TO_BOOL || is_app_of(bits, m.get_family_id("bv"), OP_CONCAT)); m_vars.push_back(v); @@ -155,17 +153,11 @@ struct bit_blaster_model_converter : public model_converter { unsigned bv_sz = to_app(bs)->get_num_args(); expr_ref_vector args(m()); app_ref result(m()); - for (unsigned j = 0; j < bv_sz; ++j) { - expr * bit = to_app(bs)->get_arg(j); + for (expr * bit : *to_app(bs)) { SASSERT(is_uninterp_const(bit)); func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model.get_const_interp(bit_decl); - if (bit_val != 0) { - args.push_back(bit_val); - } - else { - args.push_back(bit); - } + args.push_back(bit_val ? bit_val : bit); } if (TO_BOOL) { @@ -194,14 +186,10 @@ struct bit_blaster_model_converter : public model_converter { } virtual void display(std::ostream & out) { - out << "(bit-blaster-model-converter"; unsigned sz = m_vars.size(); for (unsigned i = 0; i < sz; i++) { - out << "\n (" << m_vars.get(i)->get_name() << " "; - unsigned indent = m_vars.get(i)->get_name().size() + 4; - out << mk_ismt2_pp(m_bits.get(i), m(), indent) << ")"; - } - out << ")" << std::endl; + display_add(out, m(), m_vars.get(i), m_bits.get(i)); + } } protected: @@ -210,10 +198,10 @@ public: virtual model_converter * translate(ast_translation & translator) { bit_blaster_model_converter * res = alloc(bit_blaster_model_converter, translator.to()); - for (unsigned i = 0; i < m_vars.size(); i++) - res->m_vars.push_back(translator(m_vars[i].get())); - for (unsigned i = 0; i < m_bits.size(); i++) - res->m_bits.push_back(translator(m_bits[i].get())); + for (func_decl * v : m_vars) + res->m_vars.push_back(translator(v)); + for (expr* b : m_bits) + res->m_bits.push_back(translator(b)); return res; } }; diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 5c6c43778..308b775a4 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -81,7 +81,7 @@ class bit_blaster_tactic : public tactic { new_pr = m().mk_modus_ponens(pr, new_pr); } if (curr != new_curr) { - change = true; + change = true; TRACE("bit_blaster", tout << mk_pp(curr, m()) << " -> " << mk_pp(new_curr, m()) << "\n";); g->update(idx, new_curr, new_pr, g->dep(idx)); } diff --git a/src/tactic/converter.h b/src/tactic/converter.h index 84df02c94..7fa118e4b 100644 --- a/src/tactic/converter.h +++ b/src/tactic/converter.h @@ -29,11 +29,13 @@ public: converter():m_ref_count(0) {} virtual ~converter() {} - void inc_ref() { ++m_ref_count; } + void inc_ref() { ++m_ref_count; std::cout << "inc_ref " << m_ref_count << " " << this << "\n"; } void dec_ref() { --m_ref_count; - if (m_ref_count == 0) - dealloc(this); + if (m_ref_count == 0) { + std::cout << "dec_ref " << this << "\n"; + dealloc(this); + } } virtual void cancel() {} diff --git a/src/tactic/filter_model_converter.cpp b/src/tactic/filter_model_converter.cpp index 40de848be..4041e9275 100644 --- a/src/tactic/filter_model_converter.cpp +++ b/src/tactic/filter_model_converter.cpp @@ -62,7 +62,14 @@ void filter_model_converter::display(std::ostream & out) { model_converter * filter_model_converter::translate(ast_translation & translator) { filter_model_converter * res = alloc(filter_model_converter, translator.to()); - for (unsigned i = 0; i < m_decls.size(); i++) - res->m_decls.push_back(translator(m_decls[i].get())); + for (func_decl* f : m_decls) + res->m_decls.push_back(translator(f)); return res; } + +void filter_model_converter::collect(ast_pp_util& visitor) { + m_env = &visitor.env(); + std::cout << "collect filter: " << m_decls.size() << "\n"; + for (func_decl* f : m_decls) visitor.coll.visit_func(f); +} + diff --git a/src/tactic/filter_model_converter.h b/src/tactic/filter_model_converter.h index 1cb6ec056..2c3361808 100644 --- a/src/tactic/filter_model_converter.h +++ b/src/tactic/filter_model_converter.h @@ -20,6 +20,7 @@ Notes: #define FILTER_MODEL_CONVERTER_H_ #include "tactic/model_converter.h" +#include "ast/ast_pp_util.h" class filter_model_converter : public model_converter { func_decl_ref_vector m_decls; @@ -37,7 +38,7 @@ public: virtual void operator()(model_ref & md) { operator()(md, 0); } // TODO: delete virtual void cancel() {} - + virtual void display(std::ostream & out); void insert(func_decl * d) { @@ -45,6 +46,9 @@ public: } virtual model_converter * translate(ast_translation & translator); + + virtual void collect(ast_pp_util& visitor); + }; typedef ref filter_model_converter_ref; diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 6984c0536..01c7a16bb 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -24,26 +24,16 @@ Notes: * Add or overwrite value in model. */ void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { - // TBD: for arity > 0, requires signature of arguments. - if (m_env) { - ast_smt2_pp(out, f, e, *m_env, params_ref(), 0, "model-add"); - } - else { - unsigned indent = f->get_name().size() + 4; - out << "(model-add " << f->get_name() << " " << mk_ismt2_pp(e, m, indent) << ")\n"; - } + VERIFY(m_env); + ast_smt2_pp(out, f, e, *m_env, params_ref(), 0, "model-add") << "\n"; } /* * A value is removed from the model. */ void model_converter::display_del(std::ostream& out, func_decl* f) const { - if (m_env) { - ast_smt2_pp(out, f, *m_env, params_ref(), 0, "model-del"); - } - else { - out << "(model-del " << f->get_name() << ")\n"; - } + VERIFY(m_env); + ast_smt2_pp(out << "(model-del ", f->get_name(), f->is_skolem(), *m_env) << ")\n"; } void model_converter::display_add(std::ostream& out, ast_manager& m) { @@ -64,7 +54,9 @@ void model_converter::display_add(std::ostream& out, ast_manager& m) { class concat_model_converter : public concat_converter { public: - concat_model_converter(model_converter * mc1, model_converter * mc2): concat_converter(mc1, mc2) {} + concat_model_converter(model_converter * mc1, model_converter * mc2): concat_converter(mc1, mc2) { + VERIFY(m_c1 && m_c2); + } virtual void operator()(model_ref & m) { this->m_c2->operator()(m); @@ -86,6 +78,11 @@ public: virtual model_converter * translate(ast_translation & translator) { return this->translate_core(translator); } + + virtual void collect(ast_pp_util& visitor) { + this->m_c1->collect(visitor); + this->m_c2->collect(visitor); + } }; model_converter * concat(model_converter * mc1, model_converter * mc2) { diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 02e59f6d5..f7597be07 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -19,6 +19,7 @@ Notes: #ifndef MODEL_CONVERTER_H_ #define MODEL_CONVERTER_H_ +#include "ast/ast_pp_util.h" #include "model/model.h" #include "tactic/converter.h" #include "util/ref.h" @@ -48,8 +49,8 @@ public: virtual model_converter * translate(ast_translation & translator) = 0; - - void set_pp_env(smt2_pp_environment* env) { m_env = env; } + + virtual void collect(ast_pp_util& visitor) { m_env = &visitor.env(); } }; typedef ref model_converter_ref; diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 9e4a0c547..bb8bb463b 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -157,6 +157,7 @@ public: filter_model(mdl); } } + virtual model_converter_ref get_model_converter() const { return m_solver->get_model_converter(); } virtual proof * get_proof() { return m_solver->get_proof(); } virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 1df7a000c..c74d729b5 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -102,6 +102,7 @@ public: filter_model(mdl); } } + virtual model_converter_ref get_model_converter() const { return m_solver->get_model_converter(); } virtual proof * get_proof() { return m_solver->get_proof(); } virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 44898a578..4998cdecf 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -93,6 +93,7 @@ public: filter_model(mdl); } } + virtual model_converter_ref get_model_converter() const { return m_solver->get_model_converter(); } virtual proof * get_proof() { return m_solver->get_proof(); } virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } From 7c743b3d1664c28d5e342d8fe31a2109ed62f42c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Nov 2017 09:25:18 -0500 Subject: [PATCH 0314/1283] add direct FromFile method to solvers so that model transformations are loaded along with assertions. Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 27 +++++++++++++++++++++++++++ src/api/dotnet/Solver.cs | 8 ++++++++ src/api/python/z3/z3.py | 2 +- src/api/z3_api.h | 7 +++++++ src/cmd_context/cmd_context.h | 2 ++ src/sat/tactic/goal2sat.cpp | 4 ---- 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 9c80a6622..ad8a3cc29 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -33,6 +33,9 @@ Revision History: #include "smt/smt_solver.h" #include "smt/smt_implied_equalities.h" #include "solver/smt_logics.h" +#include "cmd_context/cmd_context.h" +#include "parsers/smt2/smt2parser.h" + extern "C" { @@ -121,6 +124,30 @@ extern "C" { Z3_CATCH_RETURN(0); } + void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name) { + Z3_TRY; + LOG_Z3_solver_from_file(c, s, file_name); + scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); + ctx->set_ignore_check(true); + std::ifstream is(file_name); + if (!is) { + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); + return; + } + if (!parse_smt2_commands(*ctx.get(), is)) { + ctx = nullptr; + SET_ERROR_CODE(Z3_PARSER_ERROR); + return; + } + ptr_vector::const_iterator it = ctx->begin_assertions(); + ptr_vector::const_iterator end = ctx->end_assertions(); + for (; it != end; ++it) { + to_solver_ref(s)->assert_expr(*it); + } + to_solver_ref(s)->set_model_converter(ctx->get_model_converter()); + Z3_CATCH; + } + Z3_string Z3_API Z3_solver_get_help(Z3_context c, Z3_solver s) { Z3_TRY; LOG_Z3_solver_get_help(c, s); diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index c18556d0c..9154117ce 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -181,6 +181,14 @@ namespace Microsoft.Z3 Native.Z3_solver_assert_and_track(Context.nCtx, NativeObject, constraint.NativeObject, p.NativeObject); } + /// + /// Load solver assertions from a file. + /// + public void FromFile(string file) + { + Native.Z3_solver_from_file(Context.nCtx, NativeObject, file); + } + /// /// Assert a lemma (or multiple) into the solver. /// diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index b47873398..d0273cc24 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6300,7 +6300,7 @@ class Solver(Z3PPObject): def from_file(self, filename): """Parse assertions from a file""" - self.add([f for f in parse_smt2_file(filename, ctx=self.ctx)]) + Z3_solver_from_file(self.ctx.ref(), self.solver) def from_string(self, s): """Parse assertions from a string""" diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 541a29b60..5548f6796 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6137,6 +6137,13 @@ extern "C" { */ void Z3_API Z3_solver_assert_lemma(Z3_context c, Z3_solver s, Z3_ast a); + /** + \brief load solver assertions from a file. + + def_API('Z3_solver_from_file', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING))) + */ + void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name); + /** \brief Return the set of asserted formulas on the solver. diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 7a3805762..440c17285 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -443,6 +443,8 @@ public: dictionary const & get_macros() const { return m_macros; } + model_converter* get_model_converter() { return m_mc0.get(); } + bool is_model_available() const; double get_seconds() const { return m_watch.get_seconds(); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 12a3cbf1d..c70077dc5 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -882,10 +882,6 @@ struct sat2goal::imp { // Wrapper for sat::model_converter: converts it into an "AST level" model_converter. class sat_model_converter : public model_converter { sat::model_converter m_mc; - // TODO: the following mapping is storing a lot of useless information, and may be a performance bottleneck. - // We need to save only the expressions associated with variables that occur in m_mc. - // This information may be stored as a vector of pairs. - // The mapping is only created during the model conversion. expr_ref_vector m_var2expr; filter_model_converter_ref m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion From 6df3e47b0763e7e206be64e48aedf6582bfb363d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Nov 2017 09:53:47 -0500 Subject: [PATCH 0315/1283] disable symbol fixing in pretty printer Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 9 +++++---- src/solver/solver.cpp | 25 ++++++++++++++----------- src/tactic/filter_model_converter.cpp | 1 - 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index c1130f7c2..bb5359c19 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -31,12 +31,13 @@ using namespace format_ns; #define MAX_INDENT 16 #define SMALL_INDENT 2 -format * smt2_pp_environment::pp_fdecl_name(symbol const & s0, unsigned & len, bool is_skolem) const { +format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len, bool is_skolem) const { ast_manager & m = get_manager(); - symbol s = m_renaming.get_symbol(s0, is_skolem); - len = static_cast(strlen(s.bare_str())); - return mk_string(m, s.bare_str()); #if 0 + symbol s1 = m_renaming.get_symbol(s, is_skolem); + len = static_cast(strlen(s1.bare_str())); + return mk_string(m, s1.bare_str()); +#else if (is_smt2_quoted_symbol(s)) { std::string str = mk_smt2_quoted_symbol(s); len = static_cast(str.length()); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 89625b20c..83982e290 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -16,13 +16,14 @@ Author: Notes: --*/ -#include "solver/solver.h" -#include "model/model_evaluator.h" +#include "util/common_msgs.h" +#include "util/stopwatch.h" #include "ast/ast_util.h" #include "ast/ast_pp.h" #include "ast/ast_pp_util.h" -#include "util/common_msgs.h" #include "tactic/model_converter.h" +#include "solver/solver.h" +#include "model/model_evaluator.h" unsigned solver::get_num_assertions() const { @@ -37,27 +38,29 @@ expr * solver::get_assertion(unsigned idx) const { std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assumptions) const { expr_ref_vector fmls(get_manager()); - //std::cout << "display 1\n"; + stopwatch sw; + sw.start(); + std::cout << "display 1\n"; get_assertions(fmls); - //std::cout << "display 2\n"; + std::cout << "display 2 " << sw.get_current_seconds() << "\n"; ast_pp_util visitor(get_manager()); model_converter_ref mc = get_model_converter(); - //std::cout << "display 3\n"; + std::cout << "display 3 " << sw.get_current_seconds() << "\n"; if (mc.get()) { mc->collect(visitor); } - //std::cout << "display 4\n"; + std::cout << "display 4 " << sw.get_current_seconds() << "\n"; visitor.collect(fmls); - //std::cout << "display 5\n"; + std::cout << "display 5 " << sw.get_current_seconds() << "\n"; visitor.collect(n, assumptions); visitor.display_decls(out); - //std::cout << "display 6\n"; + std::cout << "display 6 " << sw.get_current_seconds() << "\n"; visitor.display_asserts(out, fmls, true); - //std::cout << "display 7\n"; + std::cout << "display 7 " << sw.get_current_seconds() << "\n"; if (mc.get()) { mc->display(out); } - //std::cout << "display 8\n"; + std::cout << "display 8 " << sw.get_current_seconds() << "\n"; return out; } diff --git a/src/tactic/filter_model_converter.cpp b/src/tactic/filter_model_converter.cpp index 4041e9275..7400063e1 100644 --- a/src/tactic/filter_model_converter.cpp +++ b/src/tactic/filter_model_converter.cpp @@ -69,7 +69,6 @@ model_converter * filter_model_converter::translate(ast_translation & translator void filter_model_converter::collect(ast_pp_util& visitor) { m_env = &visitor.env(); - std::cout << "collect filter: " << m_decls.size() << "\n"; for (func_decl* f : m_decls) visitor.coll.visit_func(f); } From 59ea11b1a3676bd6e46b5c558a9225b3b42cadf7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Nov 2017 13:40:31 -0500 Subject: [PATCH 0316/1283] cube and conquer parallel tactic Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 13 + src/sat/sat_simplifier.h | 14 +- src/solver/solver.cpp | 16 +- .../portfolio/bounded_int2bv_solver.cpp | 1 + src/tactic/portfolio/enum2bv_solver.cpp | 9 +- src/tactic/portfolio/parallel_tactic.cpp | 708 ++++++++++-------- src/tactic/portfolio/pb2bv_solver.cpp | 9 +- 7 files changed, 449 insertions(+), 321 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index f091a3f93..5dccdd379 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -92,6 +92,19 @@ namespace sat { bool simplifier::single_threaded() const { return s.m_config.m_num_threads == 1; } + bool simplifier::bce_enabled() const { + return !s.tracking_assumptions() && + !m_learned_in_use_lists && + m_num_calls >= m_bce_delay && + (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled()); + } + bool simplifier::acce_enabled() const { return !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce; } + bool simplifier::cce_enabled() const { return !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); } + bool simplifier::abce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; } + bool simplifier::bca_enabled() const { return !s.tracking_assumptions() && m_bca && m_learned_in_use_lists && single_threaded(); } + bool simplifier::elim_vars_bdd_enabled() const { return !s.tracking_assumptions() && m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay && single_threaded(); } + bool simplifier::elim_vars_enabled() const { return !s.tracking_assumptions() && m_elim_vars && single_threaded(); } + void simplifier::register_clauses(clause_vector & cs) { std::stable_sort(cs.begin(), cs.end(), size_lt()); for (clause* c : cs) { diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 54f8c59dd..98cae5398 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -172,13 +172,13 @@ namespace sat { void elim_blocked_clauses(); bool single_threaded() const; // { return s.m_config.m_num_threads == 1; } - bool bce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled()); } - bool acce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce; } - bool cce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); } - bool abce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; } - bool bca_enabled() const { return m_bca && m_learned_in_use_lists && single_threaded(); } - bool elim_vars_bdd_enabled() const { return m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay && single_threaded(); } - bool elim_vars_enabled() const { return m_elim_vars && single_threaded(); } + bool bce_enabled() const; + bool acce_enabled() const; + bool cce_enabled() const; + bool abce_enabled() const; + bool bca_enabled() const; + bool elim_vars_bdd_enabled() const; + bool elim_vars_enabled() const; unsigned get_num_unblocked_bin(literal l) const; unsigned get_to_elim_cost(bool_var v) const; diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 83982e290..de0834b9d 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -40,27 +40,27 @@ std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assum expr_ref_vector fmls(get_manager()); stopwatch sw; sw.start(); - std::cout << "display 1\n"; + // std::cout << "display 1\n"; get_assertions(fmls); - std::cout << "display 2 " << sw.get_current_seconds() << "\n"; + // std::cout << "display 2 " << sw.get_current_seconds() << "\n"; ast_pp_util visitor(get_manager()); model_converter_ref mc = get_model_converter(); - std::cout << "display 3 " << sw.get_current_seconds() << "\n"; + // std::cout << "display 3 " << sw.get_current_seconds() << "\n"; if (mc.get()) { mc->collect(visitor); } - std::cout << "display 4 " << sw.get_current_seconds() << "\n"; + // std::cout << "display 4 " << sw.get_current_seconds() << "\n"; visitor.collect(fmls); - std::cout << "display 5 " << sw.get_current_seconds() << "\n"; + // std::cout << "display 5 " << sw.get_current_seconds() << "\n"; visitor.collect(n, assumptions); visitor.display_decls(out); - std::cout << "display 6 " << sw.get_current_seconds() << "\n"; + // std::cout << "display 6 " << sw.get_current_seconds() << "\n"; visitor.display_asserts(out, fmls, true); - std::cout << "display 7 " << sw.get_current_seconds() << "\n"; + // std::cout << "display 7 " << sw.get_current_seconds() << "\n"; if (mc.get()) { mc->display(out); } - std::cout << "display 8 " << sw.get_current_seconds() << "\n"; + // std::cout << "display 8 " << sw.get_current_seconds() << "\n"; return out; } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index b78728abe..195a16fbf 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -82,6 +82,7 @@ public: for (func_decl* f : m_bv_fns) result->m_bv_fns.push_back(tr(f)); for (func_decl* f : m_int_fns) result->m_int_fns.push_back(tr(f)); for (bound_manager* b : m_bounds) result->m_bounds.push_back(b->translate(dst_m)); + if (mc0()) result->set_model_converter(mc0()->translate(tr)); return result; } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 57078807d..b16ba2443 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -49,8 +49,13 @@ public: virtual ~enum2bv_solver() {} - virtual solver* translate(ast_manager& m, params_ref const& p) { - return alloc(enum2bv_solver, m, p, m_solver->translate(m, p)); + virtual solver* translate(ast_manager& dst_m, params_ref const& p) { + solver* result = alloc(enum2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); + if (mc0()) { + ast_translation tr(m, dst_m); + result->set_model_converter(mc0()->translate(tr)); + } + return result; } virtual void assert_expr(expr * t) { diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 4eb2fbbe9..8f17048e3 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -7,21 +7,37 @@ Module Name: Abstract: - Parallel tactic in the style of Treengeling. - - It assumes a solver that supports good lookaheads. + Parallel tactic based on cubing. Author: Nikolaj Bjorner (nbjorner) 2017-10-9 + Miguel Neves Notes: - + + + A task comprises of a non-empty sequence of cubes, a type and parameters + + If in the cube state, the solver performs the following: + 1. Clone the state with the remaining cubes if there is more than one cube. Re-enqueue the remaining cubes. + 2. Apply simplifications and pre-processing according to configuration. + 3. Cube using the parameter settings prescribed in m_params. + 4. Create a conquer state with the produced cubes. + If in the conquer state, the solver performs the following + 1. Pass the cubes as assumptions and solve each sub-cube with a prescribed resource bound. + 2. Assemble cubes that could not be solved and create a cube state. + + --*/ +#include +#include +#include #include "util/scoped_ptr_vector.h" #include "ast/ast_util.h" +#include "ast/ast_translation.h" #include "solver/solver.h" #include "solver/solver2tactic.h" #include "tactic/tactic.h" @@ -29,41 +45,140 @@ Notes: class parallel_tactic : public tactic { + + enum task_type { cube_task, conquer_task }; + + class solver_state; + + class task_queue { + std::mutex m_mutex; + std::condition_variable m_cond; + std::unique_lock m_lock; + ptr_vector m_tasks; + ptr_vector m_active; + unsigned m_num_waiters; + volatile bool m_shutdown; + + void inc_wait() { + std::lock_guard lock(m_mutex); + ++m_num_waiters; + } + + void dec_wait() { + std::lock_guard lock(m_mutex); + --m_num_waiters; + } + + solver_state* try_get_task() { + solver_state* st = nullptr; + std::lock_guard lock(m_mutex); + if (!m_tasks.empty()) { + st = m_tasks.back(); + m_tasks.pop_back(); + m_active.push_back(st); + } + return st; + } + + public: + + task_queue(): + m_num_waiters(0), + m_shutdown(false), + m_lock(m_mutex, std::adopt_lock_t()) {} + + ~task_queue() { reset(); } + + void shutdown() { + if (!m_shutdown) { + m_shutdown = true; + m_cond.notify_all(); + std::lock_guard lock(m_mutex); + for (solver_state* st : m_active) { + st->m().limit().cancel(); + } + } + } + + void add_task(solver_state* task) { + std::lock_guard lock(m_mutex); + m_tasks.push_back(task); + if (m_num_waiters > 0) { + m_cond.notify_one(); + } + } + + solver_state* get_task() { + while (!m_shutdown) { + solver_state* st = try_get_task(); + if (st) return st; + inc_wait(); + m_cond.wait(m_lock); + dec_wait(); + } + return nullptr; + } + + void task_done(solver_state* st) { + std::lock_guard lock(m_mutex); + m_active.erase(st); + } + + void reset() { + for (auto* t : m_tasks) dealloc(t); + m_tasks.reset(); + m_active.reset(); + } + + std::ostream& display(std::ostream& out) { + std::lock_guard lock(m_mutex); + out << "num_tasks " << m_tasks.size() << " active: " << m_active.size() << "\n"; + for (solver_state* st : m_tasks) { + st->display(out); + } + return out; + } + + }; + class solver_state { + task_type m_type; + expr_ref_vector m_cubes, m_asserted_cubes; params_ref m_params; scoped_ptr m_manager; ref m_solver; - expr_ref_vector m_cube; - unsigned m_units; - public: - solver_state(ast_manager* m, solver* s, params_ref const& p): - m_params(p), - m_manager(m), - m_solver(s), - m_cube(s->get_manager()), - m_units(0) {} + unsigned m_depth; + unsigned m_width; + unsigned m_cube_cutoff; + double m_cube_fraction; - void update_units() { - m_units = 0; - statistics st; - m_solver->collect_statistics(st); - std::string units("units"); - for (unsigned i = st.size(); i-- > 0; ) { - if (st.get_key(i) == units) { - m_units = st.get_uint_value(i); - std::cout << "value for " << i << " is " << m_units << "\n"; - break; - } + expr_ref_vector cube_literals(expr* cube) { + expr_ref_vector literals(m()); + if (m().is_and(cube)) { + literals.append(to_app(cube)->get_num_args(), to_app(cube)->get_args()); } - } + else { + literals.push_back(cube); + } + return literals; + } - expr_ref cube() { return mk_and(m_cube); } + public: + solver_state(ast_manager* m, solver* s, params_ref const& p, task_type t): + m_type(t), + m_cubes(s->get_manager()), + m_asserted_cubes(s->get_manager()), + m_params(p), + m_manager(m), + m_solver(s), + m_depth(0), + m_width(1) + { + m_cube_cutoff = p.get_uint("sat.lookahead.cube.cutoff", 8); + m_cube_fraction = p.get_double("sat.lookahead.cube.fraction", 0.4); + } - void add_cube(expr* c) { m_cube.push_back(c); } - - unsigned num_units() const { return m_units; } - - unsigned cube_size() const { return m_cube.size(); } + ast_manager& m() { return m_solver->get_manager(); } solver& get_solver() { return *m_solver; } @@ -71,133 +186,212 @@ class parallel_tactic : public tactic { params_ref const& params() const { return m_params; } - params_ref& params() { return m_params; } - - solver_state* clone(params_ref const& p, expr* cube) { + params_ref& params() { return m_params; } + + solver_state* clone() { + SASSERT(!m_cubes.empty()); ast_manager& m = m_solver->get_manager(); ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); - solver* s = m_solver->translate(*new_m, p); - solver_state* st = alloc(solver_state, new_m, s, m_params); - ast_translation translate(m, *new_m); - for (expr* c : m_cube) { - st->m_cube.push_back(translate(c)); - } - expr_ref cube1(translate(cube), *new_m); - st->m_cube.push_back(cube1); - s->assert_expr(cube1); + ast_translation tr(m, *new_m); + solver* s = m_solver->translate(*new_m, m_params); + solver_state* st = alloc(solver_state, new_m, s, m_params, m_type); + for (expr* c : m_cubes) st->m_cubes.push_back(tr(c)); + for (expr* c : m_asserted_cubes) st->m_asserted_cubes.push_back(tr(c)); + st->m_depth = m_depth; return st; } - }; -public: - bool operator()(solver_state* s1, solver_state* s2) const { - return s1->num_units() > s2->num_units(); - } + task_type type() const { return m_type; } + + void set_type(task_type t) { m_type = t; } + + expr_ref_vector const& cubes() const { SASSERT(m_type == conquer); return m_cubes; } + + // remove up to n cubes from list of cubes. + expr_ref_vector split_cubes(unsigned n) { + expr_ref_vector result(m()); + while (n-- > 0 && !m_cubes.empty()) { + result.push_back(m_cubes.back()); + m_cubes.pop_back(); + } + return result; + } + + void set_cubes(expr_ref_vector const& c) { + m_cubes.reset(); + m_cubes.append(c); + } + + void inc_depth(unsigned inc) { m_depth += inc; } + + void inc_width(unsigned w) { m_width *= w; } + + unsigned get_width() const { return m_width; } + + unsigned get_depth() const { return m_depth; } + + lbool simplify() { + lbool r = l_undef; + if (m_depth == 1) { + set_simplify_params(true, true); // retain PB, retain blocked + r = get_solver().check_sat(0,0); + if (r != l_undef) return r; + + // copy over the resulting clauses with a configuration that blasts PB constraints + set_simplify_params(false, true); + m_solver = get_solver().translate(m(), m_params); + } + set_simplify_params(false, true); // remove PB, retain blocked (TBD, sat solver does not blast PB constraints on its own) + r = get_solver().check_sat(0,0); + if (r != l_undef) return r; + set_simplify_params(false, false); // remove any PB, remove blocked + r = get_solver().check_sat(0,0); + return r; + } + + void assert_cube(expr* cube) { + get_solver().assert_expr(cube); + m_asserted_cubes.append(cube_literals(cube)); + } + + lbool solve(expr* cube) { + set_conquer_params(); + expr_ref_vector literals = cube_literals(cube); + return get_solver().check_sat(literals); + } + + void set_cube_params() { + unsigned depth = m_cube_cutoff; + double fraction = m_cube_fraction; + if (m_depth == 1) { + fraction = 0; // use fixed cubing at depth 1. + } + else { + depth = 0; // use dynamic cubing beyond depth 1 + } + m_params.set_uint ("sat.lookahead.cube.cutoff", depth); + m_params.set_double("sat.lookahead.cube.fraction", fraction); + } + + void set_conquer_params() { + m_params.set_bool("sat.lookahead_simplify", false); + m_params.set_uint("sat.restart.max", 10); + } + + void set_simplify_params(bool pb_simp, bool retain_blocked) { + m_params.set_bool("sat.bca", true); + m_params.set_bool("sat.cardinality.solver", pb_simp); + m_params.set_bool("sat.cce", true); + m_params.set_bool("sat.elim_blocked_clauses", true); + m_params.set_uint("sat.inprocess.max", 8); + m_params.set_bool("sat.lookahead_simplify", true); + m_params.set_sym ("sat.pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); + m_params.set_uint("sat.restart.max", UINT_MAX); + m_params.set_bool("sat.retain_blocked_clauses", retain_blocked); + } + + bool canceled() { + return m().canceled(); + } + + std::ostream& display(std::ostream& out) { + out << ":depth " << m_depth << " :width " << m_width << "\n"; + out << ":asserted cubes " << m_asserted_cubes << "\n"; + return out; + } + }; + private: ast_manager& m_manager; params_ref m_params; - - // parameters - unsigned m_conflicts_lower_bound; - unsigned m_conflicts_upper_bound; - unsigned m_conflicts_growth_rate; - unsigned m_conflicts_decay_rate; - unsigned m_num_threads; - - double m_progress; - unsigned m_max_conflicts; - statistics m_stats; - - vector m_solvers; + sref_vector m_models; + unsigned m_num_threads; + statistics m_stats; + task_queue m_queue; + std::mutex m_mutex; + double m_progress; + bool m_has_undef; + bool m_allsat; void init() { - m_conflicts_lower_bound = 1000; - m_conflicts_upper_bound = 10000; - m_conflicts_growth_rate = 150; - m_conflicts_decay_rate = 75; - m_max_conflicts = m_conflicts_lower_bound; - m_progress = 0; m_num_threads = 2 * omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. + m_progress = 0; + m_has_undef = false; + m_allsat = false; } - unsigned get_max_conflicts() { - return m_max_conflicts; + void close_branch(solver_state& s, lbool status) { + double f = 1.0 / s.get_width(); + std::lock_guard lock(m_mutex); + m_progress += f; + char const* st = status == l_true ? "sat" : (status == l_false ? "unsat" : "undef"); + IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :progress " << m_progress << " " << st << ")\n";); } - void set_max_conflicts(unsigned c) { - m_max_conflicts = c; - } - bool should_increase_conflicts() { - return m_progress < 0; - } - - void update_progress(bool b) { - m_progress = 0.9 * m_progress + (b ? 1 : -1); - if (b) { - m_stats.update("closed", 1u); + void report_sat(solver_state& s) { + close_branch(s, l_true); + model_ref mdl; + s.get_solver().get_model(mdl); + if (mdl) { + std::lock_guard lock(m_mutex); + if (&s.m() != &m_manager) { + ast_translation tr(s.m(), m_manager); + mdl = mdl->translate(tr); + } + m_models.push_back(mdl.get()); + } + if (!m_allsat) { + m_queue.shutdown(); } } - int pick_solvers() { - // order solvers by number of units in descending order - for (solver_state* s : m_solvers) s->update_units(); - std::sort(m_solvers.c_ptr(), m_solvers.c_ptr() + m_solvers.size(), *this); - TRACE("parallel_tactic", display(tout);); - return std::min(m_num_threads, m_solvers.size()); + void report_unsat(solver_state& s) { + close_branch(s, l_false); + } + + void report_undef(solver_state& s) { + m_has_undef = true; + close_branch(s, l_undef); } - int max_num_splits() { - if (m_solvers.empty()) { - return m_num_threads; - } - uint64 max_mem = memory::get_max_memory_size(); - uint64 cur_mem = memory::get_allocation_size(); - uint64 sol_sz = cur_mem / m_solvers.size(); - - TRACE("parallel_tactic", tout << "max mem: " << max_mem << " cur mem: " << cur_mem << " num solvers: " << m_solvers.size() << "\n";); - if (max_mem <= cur_mem) { - return 0; - } - if (cur_mem == 0) { - return m_num_threads; - } - uint64 extra_solvers = (max_mem - cur_mem) / (2 * sol_sz); - if (extra_solvers > m_num_threads) { - return m_num_threads; - } - return static_cast(extra_solvers); - } - - void update_max_conflicts() { - if (should_increase_conflicts()) { - set_max_conflicts(std::min(m_conflicts_upper_bound, m_conflicts_growth_rate * get_max_conflicts() / 100)); - } - else { - set_max_conflicts(std::max(m_conflicts_lower_bound, m_conflicts_decay_rate * get_max_conflicts() / 100)); - } - } - - lbool simplify(solver_state& s) { - s.params().set_uint("max_conflicts", 10); - s.params().set_bool("lookahead_simplify", true); - s.get_solver().updt_params(s.params()); - lbool is_sat = s.get_solver().check_sat(0,0); - s.params().set_uint("max_conflicts", get_max_conflicts()); - s.params().set_bool("lookahead_simplify", false); - s.get_solver().updt_params(s.params()); - return is_sat; - } - - lbool cube(solver_state& s) { + void cube_and_conquer(solver_state& s) { ast_manager& m = s.get_solver().get_manager(); - expr_ref_vector cubes(m); - params_ref p; - p.copy(s.params()); - p.set_uint("lookahead.cube.cutoff", 1); - s.get_solver().updt_params(p); - SASSERT(&m == &cubes.get_manager()); + expr_ref_vector cubes(m), cube(m), hard_cubes(m); + + switch (s.type()) { + case cube_task: goto cube; + case conquer_task: goto conquer; + } + + + cube: + SASSERT(s.type() == cube_task); + + s.inc_depth(1); + // extract up to one cube and add it. + cube.reset(); + cube.append(s.split_cubes(1)); + SASSERT(cube.size() <= 1); + + if (!s.cubes().empty()) { + m_queue.add_task(s.clone()); + } + if (!cube.empty()) s.assert_cube(cube.get(0)); + + switch (s.simplify()) { + case l_undef: break; + case l_true: report_sat(s); return; + case l_false: report_unsat(s); return; + } + + if (s.canceled()) return; + + // extract cubes. + + cubes.reset(); + s.set_cube_params(); while (true) { expr_ref c = s.get_solver().cube(); VERIFY(c); @@ -205,8 +399,8 @@ private: break; } if (m.is_true(c)) { - cubes.reset(); - return l_undef; + report_undef(s); + return; } cubes.push_back(c); } @@ -214,182 +408,87 @@ private: IF_VERBOSE(1, verbose_stream() << "cubes: " << cubes << "\n";); if (cubes.empty()) { - return l_false; + report_unsat(s); + return; } - for (unsigned j = 1; j < cubes.size(); ++j) { - solver_state* s1 = s.clone(s.params(), cubes[j].get()); - #pragma omp critical (parallel_tactic) + else { + s.inc_width(cubes.size()); + s.set_cubes(cubes); + s.set_type(conquer_task); + goto conquer; + } + + conquer: + + SASSERT(s.type() == conquer_task); + + // extract a batch of cubes + cubes.reset(); + cubes.append(s.split_cubes(conquer_batch_size())); + if (!s.cubes().empty()) { + m_queue.add_task(s.clone()); + } + + s.set_conquer_params(); + hard_cubes.reset(); + for (expr * c : cubes) { + switch (s.solve(c)) { + case l_undef: hard_cubes.push_back(c); break; + case l_true: report_sat(s); break; + case l_false: report_unsat(s); break; + } + if (s.canceled()) return; + } + IF_VERBOSE(1, verbose_stream() << "(parallel_tactic :cubes " << cubes.size() << " :hard-cubes" << hard_cubes.size() << ")";); + if (!hard_cubes.empty()) { + s.set_cubes(hard_cubes); + s.set_type(cube_task); + goto cube; + } + else { + return; + } + } + + void run_solver() { + while (solver_state* st = m_queue.get_task()) { + cube_and_conquer(*st); { - m_solvers.push_back(s1); + std::lock_guard lock(m_mutex); + st->get_solver().collect_statistics(m_stats); } - } - - expr* cube0 = cubes[0].get(); - s.add_cube(cube0); - s.get_solver().assert_expr(cube0); - return l_undef; - } - - lbool solve(solver_state& s) { - s.params().set_uint("max_conflicts", get_max_conflicts()); - s.get_solver().updt_params(s.params()); - return s.get_solver().check_sat(0, 0); - } - - void remove_unsat(svector& unsat) { - std::sort(unsat.begin(), unsat.end()); - unsat.reverse(); - DEBUG_CODE(for (unsigned i = 0; i + 1 < unsat.size(); ++i) SASSERT(unsat[i] > unsat[i+1]);); - for (int i : unsat) { - m_solvers[i]->get_solver().collect_statistics(m_stats); - dealloc(m_solvers[i]); - for (unsigned j = i + 1; j < m_solvers.size(); ++j) { - m_solvers[j - 1] = m_solvers[j]; + m_queue.task_done(st); + if (st->m().canceled()) { + m_queue.shutdown(); } - m_solvers.shrink(m_solvers.size() - 1); - update_progress(true); + dealloc(st); } - unsat.reset(); - } - - void get_model(model_ref& mdl, int sat_index) { - SASSERT(sat_index != -1); - m_solvers[sat_index]->get_solver().get_model(mdl); - ast_translation translate(m_solvers[sat_index]->get_solver().get_manager(), m_manager); - mdl = mdl->translate(translate); } lbool solve(model_ref& mdl) { - - { - solver_state& st = *m_solvers[0]; - st.params().set_uint("restart.max", 200); - st.get_solver().updt_params(st.params()); - lbool is_sat = st.get_solver().check_sat(0, 0); - st.params().set_uint("restart.max", UINT_MAX); - st.get_solver().updt_params(st.params()); - switch (is_sat) { - case l_true: - get_model(mdl, 0); - return l_true; - case l_false: - return l_false; - default: - break; - } + vector threads; + for (unsigned i = 0; i < m_num_threads; ++i) { + threads.push_back(std::thread([this]() { run_solver(); })); } - - while (true) { - int sz = pick_solvers(); - - - if (sz == 0) { - return l_false; - } - svector unsat; - int sat_index = -1; - - // Simplify phase. - IF_VERBOSE(1, verbose_stream() << "(solver.parallel :simplify " << sz << ")\n";); - IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); - - #pragma omp parallel for - for (int i = 0; i < sz; ++i) { - lbool is_sat = simplify(*m_solvers[i]); - switch (is_sat) { - case l_false: - #pragma omp critical (parallel_tactic) - { - unsat.push_back(i); - } - break; - case l_true: - sat_index = i; - break; - case l_undef: - break; - } - } - if (sat_index != -1) { - get_model(mdl, sat_index); - return l_true; - } - sz -= unsat.size(); - remove_unsat(unsat); - if (sz == 0) continue; - - // Solve phase. - IF_VERBOSE(1, verbose_stream() << "(solver.parallel :solve " << sz << ")\n";); - IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); - - #pragma omp parallel for - for (int i = 0; i < sz; ++i) { - lbool is_sat = solve(*m_solvers[i]); - switch (is_sat) { - case l_false: - #pragma omp critical (parallel_tactic) - { - unsat.push_back(i); - } - break; - case l_true: - sat_index = i; - break; - case l_undef: - break; - } - } - if (sat_index != -1) { - get_model(mdl, sat_index); - return l_true; - } - sz -= unsat.size(); - remove_unsat(unsat); - - sz = std::min(max_num_splits(), sz); - sz = std::min(static_cast(m_num_threads/2), sz); - if (sz == 0) continue; - - - // Split phase. - IF_VERBOSE(1, verbose_stream() << "(solver.parallel :split " << sz << ")\n";); - IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); - - #pragma omp parallel for - for (int i = 0; i < sz; ++i) { - switch (cube(*m_solvers[i])) { - case l_false: - #pragma omp critical (parallel_tactic) - { - unsat.push_back(i); - } - break; - default: - #pragma omp critical (parallel_tactic) - { - update_progress(false); - } - break; - } - } - - remove_unsat(unsat); - update_max_conflicts(); + for (std::thread& t : threads) { + t.join(); } - return l_undef; + if (!m_models.empty()) { + mdl = m_models.back(); + return l_true; + } + if (m_has_undef) return l_undef; + return l_false; } std::ostream& display(std::ostream& out) { - out << "branches: " << m_solvers.size() << "\n"; - for (solver_state* s : m_solvers) { - out << "cube " << s->cube_size() << " units " << s->num_units() << "\n"; - } m_stats.display(out); + m_queue.display(out); return out; } - public: + parallel_tactic(ast_manager& m, params_ref const& p) : m_manager(m), m_params(p) { @@ -399,7 +498,8 @@ public: void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { ast_manager& m = g->m(); solver* s = mk_fd_solver(m, m_params); - m_solvers.push_back(alloc(solver_state, 0, s, m_params)); + solver_state* st = alloc(solver_state, 0, s, m_params, cube_task); + m_queue.add_task(st); expr_ref_vector clauses(m); ptr_vector assumptions; obj_map bool2dep; @@ -434,8 +534,7 @@ public: } void cleanup() { - for (solver_state * s : m_solvers) dealloc(s); - m_solvers.reset(); + m_queue.reset(); init(); } @@ -446,14 +545,17 @@ public: virtual void updt_params(params_ref const & p) { m_params.copy(p); } + virtual void collect_param_descrs(param_descrs & r) { - // TBD + r.insert("conquer_batch_size", CPK_UINT, "(default: 1000) batch size of cubes to conquer"); + } + + unsigned conquer_batch_size() const { + return m_params.get_uint("conquer_batch_size", 1000); } virtual void collect_statistics(statistics & st) const { - for (solver_state const * s : m_solvers) { - s->get_solver().collect_statistics(st); - } + // m_queue.collect_statistics(st); st.copy(m_stats); } virtual void reset_statistics() { @@ -462,6 +564,8 @@ public: }; + + tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p) { return alloc(parallel_tactic, m, p); } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 74ea9f94f..33a8fcd46 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -47,9 +47,14 @@ public: virtual ~pb2bv_solver() {} - virtual solver* translate(ast_manager& m, params_ref const& p) { + virtual solver* translate(ast_manager& dst_m, params_ref const& p) { flush_assertions(); - return alloc(pb2bv_solver, m, p, m_solver->translate(m, p)); + solver* result = alloc(pb2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); + if (mc0()) { + ast_translation tr(m, dst_m); + result->set_model_converter(mc0()->translate(tr)); + } + return result; } virtual void assert_expr(expr * t) { From e46e9cf86d1ab38285fd1177975d846ebb18debc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 4 Nov 2017 15:56:05 -0500 Subject: [PATCH 0317/1283] work on parallel-tactic Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/parallel_tactic.cpp | 112 ++++++++++++----------- 1 file changed, 59 insertions(+), 53 deletions(-) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 8f17048e3..f6f03add8 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -142,15 +142,16 @@ class parallel_tactic : public tactic { }; class solver_state { - task_type m_type; - expr_ref_vector m_cubes, m_asserted_cubes; - params_ref m_params; - scoped_ptr m_manager; - ref m_solver; - unsigned m_depth; - unsigned m_width; - unsigned m_cube_cutoff; - double m_cube_fraction; + task_type m_type; // current work role of the task + expr_ref_vector m_cubes; // set of cubes to process by task + expr_ref_vector m_asserted_cubes; // set of cubes asserted on the current solver + params_ref m_params; // configuration parameters + scoped_ptr m_manager; // ownership handle to ast_manager + ref m_solver; // solver state + unsigned m_depth; // number of nested calls to cubing + unsigned m_width; // estimate of fraction of problem handled by state + unsigned m_cube_cutoff; // saved configuration value + double m_cube_fraction; // saved configuration value expr_ref_vector cube_literals(expr* cube) { expr_ref_vector literals(m()); @@ -184,10 +185,6 @@ class parallel_tactic : public tactic { solver const& get_solver() const { return *m_solver; } - params_ref const& params() const { return m_params; } - - params_ref& params() { return m_params; } - solver_state* clone() { SASSERT(!m_cubes.empty()); ast_manager& m = m_solver->get_manager(); @@ -238,8 +235,13 @@ class parallel_tactic : public tactic { if (r != l_undef) return r; // copy over the resulting clauses with a configuration that blasts PB constraints - set_simplify_params(false, true); - m_solver = get_solver().translate(m(), m_params); + set_simplify_params(false, true); + expr_ref_vector fmls(m()); + get_solver().get_assertions(fmls); + model_converter_ref mc = get_solver().get_model_converter(); + m_solver = mk_fd_solver(m(), m_params); + m_solver->set_model_converter(mc.get()); + m_solver->assert_expr(fmls); } set_simplify_params(false, true); // remove PB, retain blocked (TBD, sat solver does not blast PB constraints on its own) r = get_solver().check_sat(0,0); @@ -271,11 +273,13 @@ class parallel_tactic : public tactic { } m_params.set_uint ("sat.lookahead.cube.cutoff", depth); m_params.set_double("sat.lookahead.cube.fraction", fraction); + get_solver().updt_params(m_params); } void set_conquer_params() { m_params.set_bool("sat.lookahead_simplify", false); m_params.set_uint("sat.restart.max", 10); + get_solver().updt_params(m_params); } void set_simplify_params(bool pb_simp, bool retain_blocked) { @@ -288,6 +292,7 @@ class parallel_tactic : public tactic { m_params.set_sym ("sat.pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); m_params.set_uint("sat.restart.max", UINT_MAX); m_params.set_bool("sat.retain_blocked_clauses", retain_blocked); + get_solver().updt_params(m_params); } bool canceled() { @@ -296,7 +301,7 @@ class parallel_tactic : public tactic { std::ostream& display(std::ostream& out) { out << ":depth " << m_depth << " :width " << m_width << "\n"; - out << ":asserted cubes " << m_asserted_cubes << "\n"; + out << ":asserted " << m_asserted_cubes.size() << "\n"; return out; } }; @@ -313,12 +318,14 @@ private: double m_progress; bool m_has_undef; bool m_allsat; + unsigned m_num_unsat; void init() { m_num_threads = 2 * omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. m_progress = 0; m_has_undef = false; m_allsat = false; + m_num_unsat = 0; } void close_branch(solver_state& s, lbool status) { @@ -329,7 +336,6 @@ private: IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :progress " << m_progress << " " << st << ")\n";); } - void report_sat(solver_state& s) { close_branch(s, l_true); model_ref mdl; @@ -347,8 +353,10 @@ private: } } - void report_unsat(solver_state& s) { + void report_unsat(solver_state& s) { close_branch(s, l_false); + std::lock_guard lock(m_mutex); + ++m_num_unsat; } void report_undef(solver_state& s) { @@ -357,7 +365,7 @@ private: } void cube_and_conquer(solver_state& s) { - ast_manager& m = s.get_solver().get_manager(); + ast_manager& m = s.m(); expr_ref_vector cubes(m), cube(m), hard_cubes(m); switch (s.type()) { @@ -365,7 +373,6 @@ private: case conquer_task: goto conquer; } - cube: SASSERT(s.type() == cube_task); @@ -374,22 +381,18 @@ private: cube.reset(); cube.append(s.split_cubes(1)); SASSERT(cube.size() <= 1); - - if (!s.cubes().empty()) { - m_queue.add_task(s.clone()); - } + if (!s.cubes().empty()) m_queue.add_task(s.clone()); if (!cube.empty()) s.assert_cube(cube.get(0)); - + + // simplify switch (s.simplify()) { case l_undef: break; case l_true: report_sat(s); return; case l_false: report_unsat(s); return; } - if (s.canceled()) return; // extract cubes. - cubes.reset(); s.set_cube_params(); while (true) { @@ -418,16 +421,13 @@ private: goto conquer; } - conquer: - + conquer: SASSERT(s.type() == conquer_task); // extract a batch of cubes cubes.reset(); cubes.append(s.split_cubes(conquer_batch_size())); - if (!s.cubes().empty()) { - m_queue.add_task(s.clone()); - } + if (!s.cubes().empty()) m_queue.add_task(s.clone()); s.set_conquer_params(); hard_cubes.reset(); @@ -440,29 +440,33 @@ private: if (s.canceled()) return; } IF_VERBOSE(1, verbose_stream() << "(parallel_tactic :cubes " << cubes.size() << " :hard-cubes" << hard_cubes.size() << ")";); - if (!hard_cubes.empty()) { - s.set_cubes(hard_cubes); - s.set_type(cube_task); - goto cube; - } - else { - return; - } + if (hard_cubes.empty()) return; + + s.set_cubes(hard_cubes); + s.set_type(cube_task); + goto cube; } void run_solver() { - while (solver_state* st = m_queue.get_task()) { - cube_and_conquer(*st); - { - std::lock_guard lock(m_mutex); - st->get_solver().collect_statistics(m_stats); + try { + while (solver_state* st = m_queue.get_task()) { + cube_and_conquer(*st); + collect_statistics(*st); + m_queue.task_done(st); + if (st->m().canceled()) m_queue.shutdown(); + IF_VERBOSE(1, display(verbose_stream());); + dealloc(st); } - m_queue.task_done(st); - if (st->m().canceled()) { - m_queue.shutdown(); - } - dealloc(st); } + catch (z3_exception& ex) { + std::cout << ex.msg() << "\n"; + m_queue.shutdown(); + } + } + + void collect_statistics(solver_state& s) { + std::lock_guard lock(m_mutex); + s.get_solver().collect_statistics(m_stats); } lbool solve(model_ref& mdl) { @@ -474,16 +478,19 @@ private: t.join(); } if (!m_models.empty()) { - mdl = m_models.back(); + mdl = m_models.back(); return l_true; } - if (m_has_undef) return l_undef; + if (m_has_undef || m_manager.canceled()) + return l_undef; return l_false; } std::ostream& display(std::ostream& out) { m_stats.display(out); m_queue.display(out); + std::lock_guard lock(m_mutex); + out << "(parallel_tactic :unsat " << m_num_unsat << " :progress " << m_progress << " :models " << m_models.size() << ")\n"; return out; } @@ -555,7 +562,6 @@ public: } virtual void collect_statistics(statistics & st) const { - // m_queue.collect_statistics(st); st.copy(m_stats); } virtual void reset_statistics() { From 70ee030228fb75cae3a792607ba67b09eda5c8de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Nov 2017 10:53:25 -0800 Subject: [PATCH 0318/1283] updates to parallel tactic Signed-off-by: Nikolaj Bjorner --- src/sat/sat_params.pyg | 2 +- src/sat/sat_solver.cpp | 1 + src/tactic/portfolio/parallel_tactic.cpp | 83 ++++++++++++++---------- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 6be3b35ba..5880f8bfc 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -38,7 +38,7 @@ def_module_params('sat', ('local_search', BOOL, False, 'use local search instead of CDCL'), ('lookahead_cube', BOOL, False, 'use lookahead solver to create cubes'), ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'), - ('lookahead.cube.cutoff', UINT, 0, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), + ('lookahead.cube.cutoff', UINT, 10, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3471346ef..d6ec47f36 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1416,6 +1416,7 @@ namespace sat { m_luby_idx = 1; m_gc_threshold = m_config.m_gc_initial; m_restarts = 0; + m_simplifications = 0; m_conflicts_since_init = 0; m_min_d_tk = 1.0; m_search_lvl = 0; diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index f6f03add8..e3d2ee8b3 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -53,7 +53,6 @@ class parallel_tactic : public tactic { class task_queue { std::mutex m_mutex; std::condition_variable m_cond; - std::unique_lock m_lock; ptr_vector m_tasks; ptr_vector m_active; unsigned m_num_waiters; @@ -84,8 +83,7 @@ class parallel_tactic : public tactic { task_queue(): m_num_waiters(0), - m_shutdown(false), - m_lock(m_mutex, std::adopt_lock_t()) {} + m_shutdown(false) {} ~task_queue() { reset(); } @@ -113,8 +111,9 @@ class parallel_tactic : public tactic { solver_state* st = try_get_task(); if (st) return st; inc_wait(); - m_cond.wait(m_lock); - dec_wait(); + + std::unique_lock lock(m_mutex); + m_cond.wait(lock, [this] { --m_num_waiters; return true; }); } return nullptr; } @@ -122,6 +121,10 @@ class parallel_tactic : public tactic { void task_done(solver_state* st) { std::lock_guard lock(m_mutex); m_active.erase(st); + if (m_tasks.empty() && m_active.empty()) { + m_shutdown = true; + m_cond.notify_all(); + } } void reset() { @@ -143,15 +146,16 @@ class parallel_tactic : public tactic { class solver_state { task_type m_type; // current work role of the task + scoped_ptr m_manager; // ownership handle to ast_manager expr_ref_vector m_cubes; // set of cubes to process by task expr_ref_vector m_asserted_cubes; // set of cubes asserted on the current solver params_ref m_params; // configuration parameters - scoped_ptr m_manager; // ownership handle to ast_manager ref m_solver; // solver state unsigned m_depth; // number of nested calls to cubing - unsigned m_width; // estimate of fraction of problem handled by state + double m_width; // estimate of fraction of problem handled by state unsigned m_cube_cutoff; // saved configuration value double m_cube_fraction; // saved configuration value + unsigned m_restart_max; // saved configuration value expr_ref_vector cube_literals(expr* cube) { expr_ref_vector literals(m()); @@ -167,16 +171,17 @@ class parallel_tactic : public tactic { public: solver_state(ast_manager* m, solver* s, params_ref const& p, task_type t): m_type(t), + m_manager(m), m_cubes(s->get_manager()), m_asserted_cubes(s->get_manager()), m_params(p), - m_manager(m), m_solver(s), m_depth(0), - m_width(1) + m_width(1.0) { m_cube_cutoff = p.get_uint("sat.lookahead.cube.cutoff", 8); m_cube_fraction = p.get_double("sat.lookahead.cube.fraction", 0.4); + m_restart_max = p.get_uint("sat.restart.max", 10); } ast_manager& m() { return m_solver->get_manager(); } @@ -195,6 +200,7 @@ class parallel_tactic : public tactic { for (expr* c : m_cubes) st->m_cubes.push_back(tr(c)); for (expr* c : m_asserted_cubes) st->m_asserted_cubes.push_back(tr(c)); st->m_depth = m_depth; + st->m_width = m_width; return st; } @@ -222,8 +228,8 @@ class parallel_tactic : public tactic { void inc_depth(unsigned inc) { m_depth += inc; } void inc_width(unsigned w) { m_width *= w; } - - unsigned get_width() const { return m_width; } + + double get_width() const { return m_width; } unsigned get_depth() const { return m_depth; } @@ -243,7 +249,7 @@ class parallel_tactic : public tactic { m_solver->set_model_converter(mc.get()); m_solver->assert_expr(fmls); } - set_simplify_params(false, true); // remove PB, retain blocked (TBD, sat solver does not blast PB constraints on its own) + set_simplify_params(false, true); // remove PB, retain blocked r = get_solver().check_sat(0,0); if (r != l_undef) return r; set_simplify_params(false, false); // remove any PB, remove blocked @@ -263,35 +269,36 @@ class parallel_tactic : public tactic { } void set_cube_params() { - unsigned depth = m_cube_cutoff; + unsigned cutoff = m_cube_cutoff; double fraction = m_cube_fraction; - if (m_depth == 1) { + if (m_depth == 1 && cutoff > 0) { fraction = 0; // use fixed cubing at depth 1. } else { - depth = 0; // use dynamic cubing beyond depth 1 + cutoff = 0; // use dynamic cubing beyond depth 1 } - m_params.set_uint ("sat.lookahead.cube.cutoff", depth); - m_params.set_double("sat.lookahead.cube.fraction", fraction); + m_params.set_uint ("lookahead.cube.cutoff", cutoff); + m_params.set_double("lookahead.cube.fraction", fraction); get_solver().updt_params(m_params); } void set_conquer_params() { - m_params.set_bool("sat.lookahead_simplify", false); - m_params.set_uint("sat.restart.max", 10); + m_params.set_bool("lookahead_simplify", false); + m_params.set_uint("restart.max", m_restart_max); get_solver().updt_params(m_params); } void set_simplify_params(bool pb_simp, bool retain_blocked) { - m_params.set_bool("sat.bca", true); - m_params.set_bool("sat.cardinality.solver", pb_simp); - m_params.set_bool("sat.cce", true); - m_params.set_bool("sat.elim_blocked_clauses", true); - m_params.set_uint("sat.inprocess.max", 8); - m_params.set_bool("sat.lookahead_simplify", true); - m_params.set_sym ("sat.pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); - m_params.set_uint("sat.restart.max", UINT_MAX); - m_params.set_bool("sat.retain_blocked_clauses", retain_blocked); + m_params.set_bool("bca", true); + m_params.set_bool("cardinality.solver", pb_simp); + m_params.set_bool("cce", true); +// m_params.set_bool("elim_blocked_clauses", true); + if (m_params.get_uint("inprocess.max", UINT_MAX) == UINT_MAX) + m_params.set_uint("inprocess.max", 2); + m_params.set_bool("lookahead_simplify", true); + m_params.set_sym ("pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); + m_params.set_uint("restart.max", UINT_MAX); + m_params.set_bool("retain_blocked_clauses", retain_blocked); get_solver().updt_params(m_params); } @@ -321,7 +328,7 @@ private: unsigned m_num_unsat; void init() { - m_num_threads = 2 * omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. + m_num_threads = omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. m_progress = 0; m_has_undef = false; m_allsat = false; @@ -329,11 +336,15 @@ private: } void close_branch(solver_state& s, lbool status) { - double f = 1.0 / s.get_width(); - std::lock_guard lock(m_mutex); - m_progress += f; - char const* st = status == l_true ? "sat" : (status == l_false ? "unsat" : "undef"); - IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :progress " << m_progress << " " << st << ")\n";); + double f = 100.0 / s.get_width(); + { + std::lock_guard lock(m_mutex); + m_progress += f; + } + IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; + if (status == l_true) verbose_stream() << ":status sat "; + if (status == l_undef) verbose_stream() << ":status unknown "; + verbose_stream() < lock(m_mutex); - out << "(parallel_tactic :unsat " << m_num_unsat << " :progress " << m_progress << " :models " << m_models.size() << ")\n"; + out << "(parallel_tactic :unsat " << m_num_unsat << " :progress " << m_progress << "% :models " << m_models.size() << ")\n"; return out; } From 9a4fb4ff7641b9585605567e11a6f7e683aa63bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Nov 2017 14:08:55 -0800 Subject: [PATCH 0319/1283] remove ad-hoc parameters, deprecating dimacs cube mode Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 1 - src/sat/sat_config.h | 1 - src/sat/sat_params.pyg | 1 - src/sat/sat_solver.cpp | 4 +++ src/tactic/portfolio/parallel_tactic.cpp | 31 +++++++++++++++--------- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index d0618d265..31304bab5 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -89,7 +89,6 @@ namespace sat { m_local_search = p.local_search(); m_local_search_threads = p.local_search_threads(); m_lookahead_simplify = p.lookahead_simplify(); - m_lookahead_cube = p.lookahead_cube(); m_lookahead_search = p.lookahead_search(); if (p.lookahead_reward() == symbol("heule_schur")) { m_lookahead_reward = heule_schur_reward; diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 17ce7a569..2e1d8a145 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -84,7 +84,6 @@ namespace sat { bool m_local_search; bool m_lookahead_search; bool m_lookahead_simplify; - bool m_lookahead_cube; unsigned m_lookahead_cube_cutoff; double m_lookahead_cube_fraction; reward_t m_lookahead_reward; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 5880f8bfc..229bd8a4b 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -36,7 +36,6 @@ def_module_params('sat', ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), - ('lookahead_cube', BOOL, False, 'use lookahead solver to create cubes'), ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'), ('lookahead.cube.cutoff', UINT, 10, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), ('lookahead_search', BOOL, False, 'use lookahead solver'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d6ec47f36..f5b04e646 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -871,9 +871,13 @@ namespace sat { if (m_config.m_lookahead_search && num_lits == 0) { return lookahead_search(); } +#if 0 + // deprecated if (m_config.m_lookahead_cube && num_lits == 0) { return lookahead_cube(); } +#endif + if (m_config.m_local_search) { return do_local_search(num_lits, lits); } diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index e3d2ee8b3..82fc0fb39 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -111,7 +111,6 @@ class parallel_tactic : public tactic { solver_state* st = try_get_task(); if (st) return st; inc_wait(); - std::unique_lock lock(m_mutex); m_cond.wait(lock, [this] { --m_num_waiters; return true; }); } @@ -289,14 +288,11 @@ class parallel_tactic : public tactic { } void set_simplify_params(bool pb_simp, bool retain_blocked) { - m_params.set_bool("bca", true); m_params.set_bool("cardinality.solver", pb_simp); - m_params.set_bool("cce", true); -// m_params.set_bool("elim_blocked_clauses", true); + m_params.set_sym ("pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); if (m_params.get_uint("inprocess.max", UINT_MAX) == UINT_MAX) m_params.set_uint("inprocess.max", 2); m_params.set_bool("lookahead_simplify", true); - m_params.set_sym ("pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); m_params.set_uint("restart.max", UINT_MAX); m_params.set_bool("retain_blocked_clauses", retain_blocked); get_solver().updt_params(m_params); @@ -344,7 +340,7 @@ private: IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; if (status == l_true) verbose_stream() << ":status sat "; if (status == l_undef) verbose_stream() << ":status unknown "; - verbose_stream() < Date: Sun, 5 Nov 2017 18:24:15 -0800 Subject: [PATCH 0320/1283] fix race condition, exception handling/throwing Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/parallel_tactic.cpp | 46 +++++++++++++++++------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 82fc0fb39..5762271ba 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -108,11 +108,17 @@ class parallel_tactic : public tactic { solver_state* get_task() { while (!m_shutdown) { - solver_state* st = try_get_task(); - if (st) return st; inc_wait(); - std::unique_lock lock(m_mutex); - m_cond.wait(lock, [this] { --m_num_waiters; return true; }); + solver_state* st = try_get_task(); + if (st) { + dec_wait(); + return st; + } + { + std::unique_lock lock(m_mutex); + m_cond.wait(lock); + } + dec_wait(); } return nullptr; } @@ -128,6 +134,7 @@ class parallel_tactic : public tactic { void reset() { for (auto* t : m_tasks) dealloc(t); + for (auto* t : m_active) dealloc(t); m_tasks.reset(); m_active.reset(); } @@ -322,6 +329,8 @@ private: bool m_has_undef; bool m_allsat; unsigned m_num_unsat; + int m_exn_code; + std::string m_exn_msg; void init() { m_num_threads = omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. @@ -329,6 +338,7 @@ private: m_has_undef = false; m_allsat = false; m_num_unsat = 0; + m_exn_code = 0; } void close_branch(solver_state& s, lbool status) { @@ -476,9 +486,17 @@ private: dealloc(st); } } - catch (z3_exception& ex) { - std::cout << ex.msg() << "\n"; + catch (z3_exception& ex) { + IF_VERBOSE(1, verbose_stream() << ex.msg() << "\n";); m_queue.shutdown(); + std::lock_guard lock(m_mutex); + if (ex.has_error_code()) { + m_exn_code = ex.error_code(); + } + else { + m_exn_msg = ex.msg(); + m_exn_code = -1; + } } } @@ -489,20 +507,21 @@ private: lbool solve(model_ref& mdl) { vector threads; - for (unsigned i = 0; i < m_num_threads; ++i) { + for (unsigned i = 0; i < m_num_threads; ++i) threads.push_back(std::thread([this]() { run_solver(); })); - } - for (std::thread& t : threads) { + for (std::thread& t : threads) t.join(); - } + m_manager.limit().reset_cancel(); + if (m_exn_code == -1) + throw default_exception(m_exn_msg); + if (m_exn_code != 0) + throw z3_error(m_exn_code); if (!m_models.empty()) { mdl = m_models.back(); - m_manager.limit().reset_cancel(); return l_true; } if (m_has_undef) return l_undef; - m_manager.limit().reset_cancel(); return l_false; } @@ -583,6 +602,9 @@ public: virtual void collect_statistics(statistics & st) const { st.copy(m_stats); + st.update("par unsat", m_num_unsat); + st.update("par models", m_models.size()); + st.update("par progress", m_progress); } virtual void reset_statistics() { m_stats.reset(); From d97f800390ac7e8030713ded2eec16a484bdef9e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Nov 2017 10:02:59 -0800 Subject: [PATCH 0321/1283] update error code Signed-off-by: Nikolaj Bjorner --- src/api/api_parsers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 7641bd7c6..8613d07e7 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -315,7 +315,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_PARSER_ERROR); + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); return 0; } Z3_ast_vector r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); From 303157d3b725048d01bd9f2d6fec2bf37bd50495 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Nov 2017 15:00:52 -0800 Subject: [PATCH 0322/1283] allow incremental mode override Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.h | 2 +- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_simplifier.cpp | 31 +++++++++++++++++------- src/sat/sat_simplifier.h | 1 + src/sat/sat_simplifier_params.pyg | 1 + src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 12 +++------ src/tactic/portfolio/parallel_tactic.cpp | 3 ++- 9 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 16c853423..4eb46609f 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -370,7 +370,7 @@ namespace sat { inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); } inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); } inline config const& get_config() const { return m_lookahead ? m_lookahead->get_config() : m_solver->get_config(); } - inline void drat_add(literal_vector const& c, svector const& premises) { m_solver->m_drat.add(c, premises); } + inline void drat_add(literal_vector const& c, svector const& premises) { if (m_solver) m_solver->m_drat.add(c, premises); } mutable bool m_overflow; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 31304bab5..c1c4ff5f8 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -42,6 +42,7 @@ namespace sat { m_lookahead_search = false; m_lookahead_simplify = false; m_elim_vars = false; + m_incremental = false; updt_params(p); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 2e1d8a145..e1e40e100 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -88,6 +88,7 @@ namespace sat { double m_lookahead_cube_fraction; reward_t m_lookahead_reward; + bool m_incremental; unsigned m_simplify_mult1; double m_simplify_mult2; unsigned m_simplify_max; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 5dccdd379..2cc5758d3 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -93,17 +93,28 @@ namespace sat { bool simplifier::single_threaded() const { return s.m_config.m_num_threads == 1; } bool simplifier::bce_enabled() const { - return !s.tracking_assumptions() && - !m_learned_in_use_lists && - m_num_calls >= m_bce_delay && + return + !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled()); } - bool simplifier::acce_enabled() const { return !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce; } - bool simplifier::cce_enabled() const { return !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); } - bool simplifier::abce_enabled() const { return !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; } - bool simplifier::bca_enabled() const { return !s.tracking_assumptions() && m_bca && m_learned_in_use_lists && single_threaded(); } - bool simplifier::elim_vars_bdd_enabled() const { return !s.tracking_assumptions() && m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay && single_threaded(); } - bool simplifier::elim_vars_enabled() const { return !s.tracking_assumptions() && m_elim_vars && single_threaded(); } + bool simplifier::acce_enabled() const { + return !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce; + } + bool simplifier::cce_enabled() const { + return !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); + } + bool simplifier::abce_enabled() const { + return !m_incremental_mode && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; + } + bool simplifier::bca_enabled() const { + return !m_incremental_mode && !s.tracking_assumptions() && m_bca && m_learned_in_use_lists && single_threaded(); + } + bool simplifier::elim_vars_bdd_enabled() const { + return !m_incremental_mode && !s.tracking_assumptions() && m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay && single_threaded(); + } + bool simplifier::elim_vars_enabled() const { + return !m_incremental_mode && !s.tracking_assumptions() && m_elim_vars && single_threaded(); + } void simplifier::register_clauses(clause_vector & cs) { std::stable_sort(cs.begin(), cs.end(), size_lt()); @@ -199,6 +210,7 @@ namespace sat { } void simplifier::operator()(bool learned) { + if (s.inconsistent()) return; if (!m_subsumption && !bce_enabled() && !bca_enabled() && !elim_vars_enabled()) @@ -1883,6 +1895,7 @@ namespace sat { m_elim_vars = p.elim_vars(); m_elim_vars_bdd = p.elim_vars_bdd(); m_elim_vars_bdd_delay = p.elim_vars_bdd_delay(); + m_incremental_mode = s.get_config().m_incremental && !p.override_incremental(); } void simplifier::collect_param_descrs(param_descrs & r) { diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 98cae5398..0acb78ce1 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -80,6 +80,7 @@ namespace sat { unsigned m_elim_blocked_clauses_at; bool m_retain_blocked_clauses; unsigned m_blocked_clause_limit; + bool m_incremental_mode; bool m_resolution; unsigned m_res_limit; unsigned m_res_occ_cutoff; diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index 6dd00ec83..a8f0db724 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -10,6 +10,7 @@ def_module_params(module_name='sat', ('bce_delay', UINT, 0, 'delay eliminate blocked clauses until simplification round'), ('retain_blocked_clauses', BOOL, False, 'retain blocked clauses for propagation, hide them from variable elimination'), ('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'), + ('override_incremental', BOOL, False, 'override incemental safety gaps. Enable elimination of blocked clauses and variables even if solver is reused'), ('resolution.limit', UINT, 500000000, 'approx. maximum number of literals visited during variable elimination'), ('resolution.occ_cutoff', UINT, 10, 'first cutoff (on number of positive/negative occurrences) for Boolean variable elimination'), ('resolution.occ_cutoff_range1', UINT, 8, 'second cutoff (number of positive/negative occurrences) for Boolean variable elimination, for problems containing less than res_cls_cutoff1 clauses'), diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index e7dae93a2..43e36de46 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -322,6 +322,7 @@ namespace sat { void set_par(parallel* p, unsigned id); bool canceled() { return !m_rlimit.inc(); } config const& get_config() const { return m_config; } + void set_incremental(bool b) { m_config.m_incremental = b; } extension* get_extension() const { return m_ext.get(); } void set_extension(extension* e); bool set_root(literal l, literal r); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 3f97025e9..f922be580 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -70,7 +70,7 @@ class inc_sat_solver : public solver { bool m_internalized; // are formulas internalized? bool m_internalized_converted; // have internalized formulas been converted back expr_ref_vector m_internalized_fmls; // formulas in internalized format - bool m_incremental_mode; + typedef obj_map dep2asm_t; public: @@ -87,10 +87,10 @@ public: m_unknown("no reason given"), m_internalized(false), m_internalized_converted(false), - m_internalized_fmls(m), - m_incremental_mode(incremental_mode) { + m_internalized_fmls(m) { updt_params(p); init_preprocess(); + m_solver.set_incremental(incremental_mode); } virtual ~inc_sat_solver() {} @@ -101,7 +101,7 @@ public: } ast_translation tr(m, dst_m); m_solver.pop_to_base_level(); - inc_sat_solver* result = alloc(inc_sat_solver, dst_m, p, m_incremental_mode); + inc_sat_solver* result = alloc(inc_sat_solver, dst_m, p, m_solver.get_config().m_incremental); result->m_solver.copy(m_solver); result->m_fmls_head = m_fmls_head; for (expr* f : m_fmls) result->m_fmls.push_back(tr(f)); @@ -280,10 +280,6 @@ public: virtual void updt_params(params_ref const & p) { m_params.append(p); sat_params p1(p); - if (m_incremental_mode) { - m_params.set_bool("elim_vars", false); - m_params.set_uint("elim_blocked_clauses_at", UINT_MAX); - } m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); m_params.set_bool("keep_pb_constraints", m_solver.get_config().m_pb_solver == sat::PB_SOLVER); m_params.set_bool("pb_num_system", m_solver.get_config().m_pb_solver == sat::PB_SORTING); diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 5762271ba..381a13a48 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -339,6 +339,7 @@ private: m_allsat = false; m_num_unsat = 0; m_exn_code = 0; + m_params.set_bool("override_incremental", true); } void close_branch(solver_state& s, lbool status) { @@ -538,7 +539,7 @@ public: parallel_tactic(ast_manager& m, params_ref const& p) : m_manager(m), m_params(p) { - init(); + init(); } void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { From 1a687a31b6c560641b48da9905e68b262f90dae2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Nov 2017 11:29:51 -0800 Subject: [PATCH 0323/1283] missing files Signed-off-by: Nikolaj Bjorner --- src/tactic/generic_model_converter.cpp | 87 ++++++++++++++++++++++++++ src/tactic/generic_model_converter.h | 62 ++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 src/tactic/generic_model_converter.cpp create mode 100644 src/tactic/generic_model_converter.h diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp new file mode 100644 index 000000000..f8a701003 --- /dev/null +++ b/src/tactic/generic_model_converter.cpp @@ -0,0 +1,87 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + generic_model_converter.cpp + +Abstract: + + Generic model converter that hides and adds entries. + It subsumes filter_model_converter and extension_model_converter. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-29 + +Notes: + +--*/ +#include "ast/ast_pp.h" +#include "tactic/generic_model_converter.h" +#include "model/model_v2_pp.h" +#include "model/model_evaluator.h" + + +void generic_model_converter::operator()(model_ref & md, unsigned goal_idx) { + std::cout << "model converter\n"; + TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout);); + model_evaluator ev(*(md.get())); + ev.set_model_completion(false); + ev.set_expand_array_equalities(false); + expr_ref val(m); + unsigned arity; + for (unsigned i = m_entries.size(); i-- > 0; ) { + entry const& e = m_entries[i]; + switch (e.m_instruction) { + case HIDE: + std::cout << "hide " << e.m_f << "\n"; + md->unregister_decl(e.m_f); + break; + case ADD: + ev(e.m_def, val); + std::cout << e.m_f << " " << e.m_def << " " << val << "\n"; + TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";); + arity = e.m_f->get_arity(); + if (arity == 0) { + md->register_decl(e.m_f, val); + } + else { + func_interp * new_fi = alloc(func_interp, m, arity); + new_fi->set_else(val); + md->register_decl(e.m_f, new_fi); + } + break; + } + } + TRACE("model_converter", tout << "after generic_model_converter\n"; model_v2_pp(tout, *md);); +} + +void generic_model_converter::display(std::ostream & out) { + for (entry const& e : m_entries) { + switch (e.m_instruction) { + case HIDE: + display_del(out, e.m_f); + break; + case ADD: + display_add(out, m, e.m_f, e.m_def); + break; + } + } +} + +model_converter * generic_model_converter::translate(ast_translation & translator) { + ast_manager& to = translator.to(); + generic_model_converter * res = alloc(generic_model_converter, to); + for (entry const& e : m_entries) + res->m_entries.push_back(entry(translator(e.m_f.get()), translator(e.m_def.get()), to, e.m_instruction)); + return res; +} + +void generic_model_converter::collect(ast_pp_util& visitor) { + m_env = &visitor.env(); + for (entry const& e : m_entries) { + visitor.coll.visit_func(e.m_f); + if (e.m_def) visitor.coll.visit(e.m_def); + } +} diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h new file mode 100644 index 000000000..434514ce6 --- /dev/null +++ b/src/tactic/generic_model_converter.h @@ -0,0 +1,62 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + generic_model_converter.h + +Abstract: + + Generic model converter that hides and adds entries. + It subsumes filter_model_converter and extension_model_converter. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-29 + +Notes: + +--*/ +#ifndef GENERIC_MODEL_CONVERTER_H_ +#define GENERIC_MODEL_CONVERTER_H_ + +#include "tactic/model_converter.h" + +class generic_model_converter : public model_converter { + enum instruction { HIDE, ADD }; + struct entry { + func_decl_ref m_f; + expr_ref m_def; + instruction m_instruction; + entry(func_decl* f, expr* d, ast_manager& m, instruction i): + m_f(f, m), m_def(d, m), m_instruction(i) {} + }; + ast_manager& m; + vector m_entries; +public: + generic_model_converter(ast_manager & m): m(m) {} + + virtual ~generic_model_converter() { } + + void hide(func_decl * f) { m_entries.push_back(entry(f, 0, m, HIDE)); } + + void add(func_decl * d, expr* e) { m_entries.push_back(entry(d, e, m, ADD)); } + + virtual void operator()(model_ref & md, unsigned goal_idx); + + virtual void operator()(svector & labels, unsigned goal_idx) {} + + virtual void operator()(model_ref & md) { operator()(md, 0); } + + virtual void cancel() {} + + virtual void display(std::ostream & out); + + virtual model_converter * translate(ast_translation & translator); + + virtual void collect(ast_pp_util& visitor); +}; + +typedef ref generic_model_converter_ref; + +#endif From 2746528aab9e92e31bf22e1d8d7f0a4aa6516683 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 7 Nov 2017 17:16:36 -0800 Subject: [PATCH 0324/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/api/api_goal.cpp | 14 +++ src/api/api_solver.cpp | 4 + src/api/dotnet/Goal.cs | 9 ++ src/api/python/z3/z3.py | 6 +- src/api/z3_api.h | 7 ++ src/sat/sat_asymm_branch.cpp | 141 +++++++++++++++-------- src/sat/sat_asymm_branch.h | 11 ++ src/sat/sat_asymm_branch_params.pyg | 3 +- src/sat/sat_config.cpp | 1 - src/sat/sat_config.h | 1 - src/sat/sat_lookahead.cpp | 6 + src/sat/sat_params.pyg | 1 - src/sat/sat_probing.cpp | 13 +-- src/sat/sat_solver.cpp | 16 +-- src/sat/sat_solver.h | 41 ++++--- src/sat/sat_solver/inc_sat_solver.cpp | 6 - src/sat/tactic/sat_tactic.cpp | 5 - src/tactic/goal.cpp | 5 + src/tactic/portfolio/parallel_tactic.cpp | 2 +- 19 files changed, 186 insertions(+), 106 deletions(-) diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 0f1b9056b..cf248c10e 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -178,4 +178,18 @@ extern "C" { Z3_CATCH_RETURN(""); } + Z3_string Z3_API Z3_goal_to_dimacs_string(Z3_context c, Z3_goal g) { + Z3_TRY; + LOG_Z3_goal_to_dimacs_string(c, g); + RESET_ERROR_CODE(); + std::ostringstream buffer; + to_goal_ref(g)->display_dimacs(buffer); + // Hack for removing the trailing '\n' + std::string result = buffer.str(); + SASSERT(result.size() > 0); + result.resize(result.size()-1); + return mk_c(c)->mk_external_string(result); + Z3_CATCH_RETURN(""); + } + }; diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index ad8a3cc29..53ce36720 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -139,6 +139,10 @@ extern "C" { SET_ERROR_CODE(Z3_PARSER_ERROR); return; } + + bool initialized = to_solver(s)->m_solver.get() != 0; + if (!initialized) + init_solver(c, s); ptr_vector::const_iterator it = ctx->begin_assertions(); ptr_vector::const_iterator end = ctx->end_assertions(); for (; it != end; ++it) { diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs index 521b453f8..25aeba741 100644 --- a/src/api/dotnet/Goal.cs +++ b/src/api/dotnet/Goal.cs @@ -208,6 +208,15 @@ namespace Microsoft.Z3 return Native.Z3_goal_to_string(Context.nCtx, NativeObject); } + /// + /// Goal to DIMACS formatted string conversion. + /// + /// A string representation of the Goal. + public string ToDimacs() + { + return Native.Z3_goal_to_dimacs_string(Context.nCtx, NativeObject); + } + /// /// Goal to BoolExpr conversion. /// diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index d0273cc24..6b6c90019 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -4971,6 +4971,10 @@ class Goal(Z3PPObject): """Return a textual representation of the s-expression representing the goal.""" return Z3_goal_to_string(self.ctx.ref(), self.goal) + def dimacs(self): + """Return a textual representation of the goal in DIMACS format.""" + return Z3_goal_to_dimacs_string(self.ctx.ref(), self.goal) + def translate(self, target): """Copy goal `self` to context `target`. @@ -6300,7 +6304,7 @@ class Solver(Z3PPObject): def from_file(self, filename): """Parse assertions from a file""" - Z3_solver_from_file(self.ctx.ref(), self.solver) + Z3_solver_from_file(self.ctx.ref(), self.solver, filename) def from_string(self, s): """Parse assertions from a string""" diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 5548f6796..ffda1ecbd 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5568,6 +5568,13 @@ extern "C" { */ Z3_string Z3_API Z3_goal_to_string(Z3_context c, Z3_goal g); + /** + \brief Convert a goal into a DIMACS formatted string. + + def_API('Z3_goal_to_dimacs_string', STRING, (_in(CONTEXT), _in(GOAL))) + */ + Z3_string Z3_API Z3_goal_to_dimacs_string(Z3_context c, Z3_goal g); + /*@}*/ /** @name Tactics and Probes */ diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 03d121599..c11ae7e20 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -57,7 +57,7 @@ namespace sat { }; void asymm_branch::operator()(bool force) { - if (!m_asymm_branch) + if (!m_asymm_branch && !m_asymm_branch_all) return; s.propagate(false); // must propagate, since it uses s.push() if (s.m_inconsistent) @@ -92,7 +92,6 @@ namespace sat { } s.checkpoint(); clause & c = *(*it); - m_counter -= c.size(); if (!process(c)) continue; // clause was removed *it2 = *it; @@ -114,57 +113,52 @@ namespace sat { CASSERT("asymm_branch", s.check_invariant()); } - bool asymm_branch::process(clause & c) { - if (c.is_blocked()) return true; - TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";); - SASSERT(s.scope_lvl() == 0); - SASSERT(s.m_qhead == s.m_trail.size()); -#ifdef Z3DEBUG - unsigned trail_sz = s.m_trail.size(); -#endif - SASSERT(!s.inconsistent()); + bool asymm_branch::process_all(clause & c) { + // try asymmetric branching on all literals in clause. + + // clause must not be used for propagation + scoped_detach scoped_d(s, c); unsigned sz = c.size(); SASSERT(sz > 0); - unsigned i; - // check if the clause is already satisfied - for (i = 0; i < sz; i++) { - if (s.value(c[i]) == l_true) { - s.detach_clause(c); - s.del_clause(c); - return false; - } + unsigned i = 0, new_sz = sz; + bool found = false; + for (; i < sz; i++) { + found = flip_literal_at(c, i, new_sz); + if (found) break; } - // try asymmetric branching - // clause must not be used for propagation - solver::scoped_detach scoped_d(s, c); + return !found || cleanup(scoped_d, c, i, new_sz); + } + + bool asymm_branch::propagate_literal(clause const& c, literal l) { + m_counter -= c.size(); + SASSERT(!s.inconsistent()); + TRACE("asymm_branch_detail", tout << "assigning: " << l << "\n";); + s.assign(l, justification()); + s.propagate_core(false); // must not use propagate(), since check_missed_propagation may fail for c + return s.inconsistent(); + } + + bool asymm_branch::flip_literal_at(clause const& c, unsigned flip_index, unsigned& new_sz) { + bool found_conflict = false; + unsigned i = 0, sz = c.size(); s.push(); - for (i = 0; i < sz - 1; i++) { - literal l = c[i]; - SASSERT(!s.inconsistent()); - TRACE("asymm_branch_detail", tout << "assigning: " << ~l << "\n";); - s.assign(~l, justification()); - s.propagate_core(false); // must not use propagate(), since check_missed_propagation may fail for c - if (s.inconsistent()) - break; + for (i = 0; !found_conflict && i < sz; i++) { + if (i == flip_index) continue; + found_conflict = propagate_literal(c, ~c[i]); + } + if (!found_conflict) { + SASSERT(sz == i); + found_conflict = propagate_literal(c, c[flip_index]); } s.pop(1); - SASSERT(!s.inconsistent()); - SASSERT(s.scope_lvl() == 0); - SASSERT(trail_sz == s.m_trail.size()); - SASSERT(s.m_qhead == s.m_trail.size()); - if (i == sz - 1) { - // clause size can't be reduced. - return true; - } - // clause can be reduced - unsigned new_sz = i+1; - SASSERT(new_sz >= 1); - SASSERT(new_sz < sz); - TRACE("asymm_branch", tout << c << "\nnew_size: " << new_sz << "\n"; - for (unsigned i = 0; i < c.size(); i++) tout << static_cast(s.value(c[i])) << " "; tout << "\n";); - // cleanup reduced clause + new_sz = i; + return found_conflict; + } + + bool asymm_branch::cleanup(scoped_detach& scoped_d, clause& c, unsigned skip_idx, unsigned new_sz) { unsigned j = 0; - for (i = 0; i < new_sz; i++) { + for (unsigned i = 0; i < new_sz; i++) { + if (skip_idx == i) continue; literal l = c[i]; switch (s.value(l)) { case l_undef: @@ -181,7 +175,7 @@ namespace sat { } } new_sz = j; - m_elim_literals += sz - new_sz; + m_elim_literals += c.size() - new_sz; switch(new_sz) { case 0: s.set_conflict(justification()); @@ -208,12 +202,65 @@ namespace sat { return true; } } + + bool asymm_branch::process(clause & c) { + if (c.is_blocked()) return true; + TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";); + SASSERT(s.scope_lvl() == 0); + SASSERT(s.m_qhead == s.m_trail.size()); + SASSERT(!s.inconsistent()); + +#ifdef Z3DEBUG + unsigned trail_sz = s.m_trail.size(); +#endif + unsigned sz = c.size(); + SASSERT(sz > 0); + unsigned i; + // check if the clause is already satisfied + for (i = 0; i < sz; i++) { + if (s.value(c[i]) == l_true) { + s.detach_clause(c); + s.del_clause(c); + return false; + } + } + if (m_asymm_branch_all) return process_all(c); + + m_counter -= c.size(); + // try asymmetric branching + // clause must not be used for propagation + scoped_detach scoped_d(s, c); + s.push(); + bool found_conflict = false; + for (i = 0; i < sz - 1 && !found_conflict; i++) { + found_conflict = propagate_literal(c, ~c[i]); + } + s.pop(1); + SASSERT(!s.inconsistent()); + SASSERT(s.scope_lvl() == 0); + SASSERT(trail_sz == s.m_trail.size()); + SASSERT(s.m_qhead == s.m_trail.size()); + SASSERT(found_conflict == (i != sz - 1)); + if (!found_conflict) { + // clause size can't be reduced. + return true; + } + // clause can be reduced + unsigned new_sz = i+1; + SASSERT(new_sz >= 1); + SASSERT(new_sz < sz); + TRACE("asymm_branch", tout << c << "\nnew_size: " << new_sz << "\n"; + for (unsigned i = 0; i < c.size(); i++) tout << static_cast(s.value(c[i])) << " "; tout << "\n";); + // cleanup and attach reduced clause + return cleanup(scoped_d, c, sz, new_sz); + } void asymm_branch::updt_params(params_ref const & _p) { sat_asymm_branch_params p(_p); m_asymm_branch = p.asymm_branch(); m_asymm_branch_rounds = p.asymm_branch_rounds(); m_asymm_branch_limit = p.asymm_branch_limit(); + m_asymm_branch_all = p.asymm_branch_all(); if (m_asymm_branch_limit > INT_MAX) m_asymm_branch_limit = INT_MAX; } diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index f2d064da6..fe5f04845 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -25,6 +25,7 @@ Revision History: namespace sat { class solver; + class scoped_detach; class asymm_branch { struct report; @@ -34,6 +35,7 @@ namespace sat { // config bool m_asymm_branch; + bool m_asymm_branch_all; unsigned m_asymm_branch_rounds; unsigned m_asymm_branch_limit; @@ -41,6 +43,15 @@ namespace sat { unsigned m_elim_literals; bool process(clause & c); + + bool process_all(clause & c); + + bool flip_literal_at(clause const& c, unsigned flip_index, unsigned& new_sz); + + bool cleanup(scoped_detach& scoped_d, clause& c, unsigned skip_index, unsigned new_sz); + + bool propagate_literal(clause const& c, literal l); + public: asymm_branch(solver & s, params_ref const & p); diff --git a/src/sat/sat_asymm_branch_params.pyg b/src/sat/sat_asymm_branch_params.pyg index 8940c64a6..d564c3fb0 100644 --- a/src/sat/sat_asymm_branch_params.pyg +++ b/src/sat/sat_asymm_branch_params.pyg @@ -3,4 +3,5 @@ def_module_params(module_name='sat', export=True, params=(('asymm_branch', BOOL, True, 'asymmetric branching'), ('asymm_branch.rounds', UINT, 32, 'maximum number of rounds of asymmetric branching'), - ('asymm_branch.limit', UINT, 100000000, 'approx. maximum number of literals visited during asymmetric branching'))) + ('asymm_branch.limit', UINT, 100000000, 'approx. maximum number of literals visited during asymmetric branching'), + ('asymm_branch.all', BOOL, False, 'asymmetric branching on all literals per clause'))) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index c1c4ff5f8..4dce25b99 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -190,7 +190,6 @@ namespace sat { else { throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); } - m_dimacs_display = p.dimacs_display(); m_dimacs_inprocess_display = p.dimacs_inprocess_display(); sat_simplifier_params sp(_p); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index e1e40e100..6de1261ad 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -108,7 +108,6 @@ namespace sat { bool m_drat_check_unsat; bool m_drat_check_sat; - bool m_dimacs_display; bool m_dimacs_inprocess_display; symbol m_always_true; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 60594c0d4..a41468936 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1989,6 +1989,7 @@ namespace sat { scoped_level _sl(*this, c_fixed_truth); m_search_mode = lookahead_mode::searching; unsigned depth = 0; + unsigned init_trail = m_trail.size(); if (!is_first) { goto pick_up_work; @@ -2010,7 +2011,12 @@ namespace sat { (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) { m_cube_state.m_freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); set_conflict(); +#if 0 + // return cube of all literals, not just the ones in the main cube + lits.append(m_trail.size() - init_trail, m_trail.c_ptr() + init_trail); +#else lits.append(m_cube_state.m_cube); +#endif backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision); return l_undef; } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 229bd8a4b..7b33ee8e7 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -42,6 +42,5 @@ def_module_params('sat', ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'), - ('dimacs.display', BOOL, False, 'display SAT instance in DIMACS format and return unknown instead of solving'), ('dimacs.inprocess.display', BOOL, False, 'display SAT instance in DIMACS format if unsolved after inprocess.max inprocessing passes'))) diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index ff599c9b2..cafc5e3bb 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -62,11 +62,9 @@ namespace sat { SASSERT(s.value(l.var()) == l_undef); literal_vector * implied_lits = updt_cache ? 0 : cached_implied_lits(l); if (implied_lits) { - literal_vector::iterator it = implied_lits->begin(); - literal_vector::iterator end = implied_lits->end(); - for (; it != end; ++it) { - if (m_assigned.contains(*it)) { - s.assign(*it, justification()); + for (literal lit : *implied_lits) { + if (m_assigned.contains(lit)) { + s.assign(lit, justification()); m_num_assigned++; } } @@ -137,10 +135,9 @@ namespace sat { if (m_probing_binary) { watch_list & wlist = s.get_wlist(~l); - for (unsigned i = 0; i < wlist.size(); i++) { - watched & w = wlist[i]; + for (watched & w : wlist) { if (!w.is_binary_clause()) - break; + continue; literal l2 = w.get_literal(); if (l.index() > l2.index()) continue; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f5b04e646..ba6e63680 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -861,13 +861,6 @@ namespace sat { m_stats.m_units = init_trail_size(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); - if (m_config.m_dimacs_display) { - display_dimacs(std::cout); - for (unsigned i = 0; i < num_lits; ++i) { - std::cout << dimacs_lit(lits[i]) << " 0\n"; - } - return l_undef; - } if (m_config.m_lookahead_search && num_lits == 0) { return lookahead_search(); } @@ -1422,6 +1415,7 @@ namespace sat { m_restarts = 0; m_simplifications = 0; m_conflicts_since_init = 0; + m_next_simplify = 0; m_min_d_tk = 1.0; m_search_lvl = 0; m_stopwatch.reset(); @@ -3942,14 +3936,6 @@ namespace sat { } } - void solver::asymmetric_branching() { - if (!at_base_lvl() || inconsistent()) - return; - m_asymm_branch(); - if (m_ext) - m_ext->clauses_modifed(); - } - // ----------------------- // // Statistics diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 43e36de46..bf5f0975b 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -182,6 +182,7 @@ namespace sat { friend struct mk_stat; friend class ccc; friend class elim_vars; + friend class scoped_detach; public: solver(params_ref const & p, reslimit& l); ~solver(); @@ -231,25 +232,6 @@ namespace sat { bool attach_nary_clause(clause & c); void attach_clause(clause & c, bool & reinit); void attach_clause(clause & c) { bool reinit; attach_clause(c, reinit); } - class scoped_detach { - solver& s; - clause& c; - bool m_deleted; - public: - scoped_detach(solver& s, clause& c): s(s), c(c), m_deleted(false) { - s.detach_clause(c); - } - ~scoped_detach() { - if (!m_deleted) s.attach_clause(c); - } - - void del_clause() { - if (!m_deleted) { - s.del_clause(c); - m_deleted = true; - } - } - }; class scoped_disable_checkpoint { solver& s; public: @@ -653,6 +635,27 @@ namespace sat { void display(std::ostream & out) const; }; + class scoped_detach { + solver& s; + clause& c; + bool m_deleted; + public: + scoped_detach(solver& s, clause& c): s(s), c(c), m_deleted(false) { + s.detach_clause(c); + } + ~scoped_detach() { + if (!m_deleted) s.attach_clause(c); + } + + void del_clause() { + if (!m_deleted) { + s.del_clause(c); + m_deleted = true; + } + } + }; + + std::ostream & operator<<(std::ostream & out, mk_stat const & stat); }; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index f922be580..b9bc81e3d 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -188,12 +188,6 @@ public: IF_VERBOSE(10, verbose_stream() << "exception: " << ex.msg() << "\n";); r = l_undef; } - if (r == l_undef && m_solver.get_config().m_dimacs_display) { - for (auto const& kv : m_map) { - std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, m) << "\n"; - } - } - switch (r) { case l_true: if (sz > 0) { diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index e049df8a7..3a5c414ef 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -68,11 +68,6 @@ class sat_tactic : public tactic { TRACE("sat_dimacs", m_solver.display_dimacs(tout);); dep2assumptions(dep2asm, assumptions); lbool r = m_solver.check(assumptions.size(), assumptions.c_ptr()); - if (r == l_undef && m_solver.get_config().m_dimacs_display) { - for (auto const& kv : map) { - std::cout << "c " << kv.m_value << " " << mk_pp(kv.m_key, g->m()) << "\n"; - } - } if (r == l_false) { expr_dependency * lcore = 0; if (produce_core) { diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 1b2a70f47..311c9838b 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -488,6 +488,11 @@ void goal::display_dimacs(std::ostream & out) const { } out << "0\n"; } + for (auto const& kv : expr2var) { + expr* key = kv.m_key; + if (is_app(key)) + out << "c " << kv.m_value << " " << to_app(key)->get_decl()->get_name() << "\n"; + } } unsigned goal::num_exprs() const { diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 381a13a48..7651ace16 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -214,7 +214,7 @@ class parallel_tactic : public tactic { void set_type(task_type t) { m_type = t; } - expr_ref_vector const& cubes() const { SASSERT(m_type == conquer); return m_cubes; } + expr_ref_vector const& cubes() const { SASSERT(m_type == conquer_task); return m_cubes; } // remove up to n cubes from list of cubes. expr_ref_vector split_cubes(unsigned n) { From b099449ce16e3f3642609630d9a9ccd78a2be60c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Nov 2017 07:21:49 -0800 Subject: [PATCH 0325/1283] asymm branch Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index c11ae7e20..a3aad27e0 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -110,7 +110,13 @@ namespace sat { } m_counter = -m_counter; s.m_phase = saved_phase; + m_asymm_branch_limit *= 2; + if (m_asymm_branch_limit > INT_MAX) + m_asymm_branch_limit = INT_MAX; + CASSERT("asymm_branch", s.check_invariant()); + + } bool asymm_branch::process_all(clause & c) { @@ -121,16 +127,14 @@ namespace sat { unsigned sz = c.size(); SASSERT(sz > 0); unsigned i = 0, new_sz = sz; - bool found = false; - for (; i < sz; i++) { - found = flip_literal_at(c, i, new_sz); - if (found) break; + for (i = sz; i-- > 0; ) { + if (flip_literal_at(c, i, new_sz)) + return cleanup(scoped_d, c, i, new_sz); } - return !found || cleanup(scoped_d, c, i, new_sz); + return true; } bool asymm_branch::propagate_literal(clause const& c, literal l) { - m_counter -= c.size(); SASSERT(!s.inconsistent()); TRACE("asymm_branch_detail", tout << "assigning: " << l << "\n";); s.assign(l, justification()); @@ -224,9 +228,10 @@ namespace sat { return false; } } + m_counter -= c.size(); + if (m_asymm_branch_all) return process_all(c); - m_counter -= c.size(); // try asymmetric branching // clause must not be used for propagation scoped_detach scoped_d(s, c); From 0a9946578b9615a887e8e94b8d22844de375def8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Nov 2017 09:14:21 -0800 Subject: [PATCH 0326/1283] use failed literal to asym branching Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 51 +++++++++++++---------------- src/sat/sat_asymm_branch.h | 6 ++-- src/sat/sat_asymm_branch_params.pyg | 1 - 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index a3aad27e0..029274c97 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -62,14 +62,16 @@ namespace sat { s.propagate(false); // must propagate, since it uses s.push() if (s.m_inconsistent) return; - if (!force && m_counter > 0) + if (!force && m_counter > 0) { + m_counter /= 100; return; + } CASSERT("asymm_branch", s.check_invariant()); TRACE("asymm_branch_detail", s.display(tout);); report rpt(*this); svector saved_phase(s.m_phase); - m_counter = 0; // counter is moving down to capture propagate cost. - int limit = -static_cast(m_asymm_branch_limit); + m_counter = 0; + int64 limit = -m_asymm_branch_limit; std::stable_sort(s.m_clauses.begin(), s.m_clauses.end(), clause_size_lt()); m_counter -= s.m_clauses.size(); SASSERT(s.m_qhead == s.m_trail.size()); @@ -111,19 +113,18 @@ namespace sat { m_counter = -m_counter; s.m_phase = saved_phase; m_asymm_branch_limit *= 2; - if (m_asymm_branch_limit > INT_MAX) - m_asymm_branch_limit = INT_MAX; + if (m_asymm_branch_limit > UINT_MAX) + m_asymm_branch_limit = UINT_MAX; CASSERT("asymm_branch", s.check_invariant()); - - } + /** + \brief try asymmetric branching on all literals in clause. + */ + bool asymm_branch::process_all(clause & c) { - // try asymmetric branching on all literals in clause. - - // clause must not be used for propagation - scoped_detach scoped_d(s, c); + scoped_detach scoped_d(s, c); // clause must not be used for propagation unsigned sz = c.size(); SASSERT(sz > 0); unsigned i = 0, new_sz = sz; @@ -180,6 +181,7 @@ namespace sat { } new_sz = j; m_elim_literals += c.size() - new_sz; + // std::cout << "cleanup: " << c.id() << ": " << literal_vector(new_sz, c.begin()) << " delta: " << (c.size() - new_sz) << " " << skip_idx << " " << new_sz << "\n"; switch(new_sz) { case 0: s.set_conflict(justification()); @@ -235,39 +237,30 @@ namespace sat { // try asymmetric branching // clause must not be used for propagation scoped_detach scoped_d(s, c); - s.push(); - bool found_conflict = false; - for (i = 0; i < sz - 1 && !found_conflict; i++) { - found_conflict = propagate_literal(c, ~c[i]); - } - s.pop(1); + unsigned new_sz = c.size(); + unsigned flip_position = 2 + m_rand(c.size() - 2); // don't flip on the watch literals. + bool found_conflict = flip_literal_at(c, flip_position, new_sz); SASSERT(!s.inconsistent()); SASSERT(s.scope_lvl() == 0); SASSERT(trail_sz == s.m_trail.size()); SASSERT(s.m_qhead == s.m_trail.size()); - SASSERT(found_conflict == (i != sz - 1)); if (!found_conflict) { // clause size can't be reduced. return true; } - // clause can be reduced - unsigned new_sz = i+1; - SASSERT(new_sz >= 1); - SASSERT(new_sz < sz); - TRACE("asymm_branch", tout << c << "\nnew_size: " << new_sz << "\n"; - for (unsigned i = 0; i < c.size(); i++) tout << static_cast(s.value(c[i])) << " "; tout << "\n";); - // cleanup and attach reduced clause - return cleanup(scoped_d, c, sz, new_sz); + else { + // clause can be reduced + return cleanup(scoped_d, c, flip_position, new_sz); + } } void asymm_branch::updt_params(params_ref const & _p) { sat_asymm_branch_params p(_p); m_asymm_branch = p.asymm_branch(); - m_asymm_branch_rounds = p.asymm_branch_rounds(); m_asymm_branch_limit = p.asymm_branch_limit(); m_asymm_branch_all = p.asymm_branch_all(); - if (m_asymm_branch_limit > INT_MAX) - m_asymm_branch_limit = INT_MAX; + if (m_asymm_branch_limit > UINT_MAX) + m_asymm_branch_limit = UINT_MAX; } void asymm_branch::collect_param_descrs(param_descrs & d) { diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index fe5f04845..a11692a82 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -31,13 +31,13 @@ namespace sat { struct report; solver & s; - int m_counter; + int64 m_counter; + random_gen m_rand; // config bool m_asymm_branch; bool m_asymm_branch_all; - unsigned m_asymm_branch_rounds; - unsigned m_asymm_branch_limit; + int64 m_asymm_branch_limit; // stats unsigned m_elim_literals; diff --git a/src/sat/sat_asymm_branch_params.pyg b/src/sat/sat_asymm_branch_params.pyg index d564c3fb0..bc50804ba 100644 --- a/src/sat/sat_asymm_branch_params.pyg +++ b/src/sat/sat_asymm_branch_params.pyg @@ -2,6 +2,5 @@ def_module_params(module_name='sat', class_name='sat_asymm_branch_params', export=True, params=(('asymm_branch', BOOL, True, 'asymmetric branching'), - ('asymm_branch.rounds', UINT, 32, 'maximum number of rounds of asymmetric branching'), ('asymm_branch.limit', UINT, 100000000, 'approx. maximum number of literals visited during asymmetric branching'), ('asymm_branch.all', BOOL, False, 'asymmetric branching on all literals per clause'))) From 75b8d10f48ce59b6770e24f223eaf522565c7f54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Nov 2017 21:44:21 -0800 Subject: [PATCH 0327/1283] add backtrack level to cuber interface Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 6 +++--- src/api/dotnet/Solver.cs | 11 ++++++++--- src/api/python/z3/z3.py | 9 +++------ src/api/z3_api.h | 7 +++++-- src/muz/spacer/spacer_itp_solver.h | 2 +- src/muz/spacer/spacer_virtual_solver.h | 2 +- src/opt/opt_solver.h | 2 +- src/sat/ba_solver.cpp | 10 +++++----- src/sat/sat_lookahead.cpp | 12 ++++++++++-- src/sat/sat_lookahead.h | 2 +- src/sat/sat_solver.cpp | 4 ++-- src/sat/sat_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 4 ++-- src/smt/smt_solver.cpp | 2 +- src/solver/combined_solver.cpp | 4 ++-- src/solver/solver.h | 2 +- src/solver/solver_pool.cpp | 2 +- src/solver/tactic2solver.cpp | 2 +- src/tactic/portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/tactic/portfolio/parallel_tactic.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 22 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 53ce36720..0c94c0b4e 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -529,9 +529,9 @@ extern "C" { Z3_CATCH_RETURN(Z3_L_UNDEF); } - Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s) { + Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, unsigned cutoff) { Z3_TRY; - LOG_Z3_solver_cube(c, s); + LOG_Z3_solver_cube(c, s, cutoff); ast_manager& m = mk_c(c)->m(); expr_ref result(m); unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); @@ -544,7 +544,7 @@ extern "C" { scoped_timer timer(timeout, &eh); scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); try { - result = to_solver_ref(s)->cube(); + result = to_solver_ref(s)->cube(cutoff); } catch (z3_exception & ex) { mk_c(c)->handle_exception(ex); diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 9154117ce..4a779e91b 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -353,6 +353,12 @@ namespace Microsoft.Z3 } } + /// + /// Backtrack level that can be adjusted by conquer process + /// + public uint BacktrackLevel { get; set; } + + /// /// Return a set of cubes. /// @@ -360,10 +366,8 @@ namespace Microsoft.Z3 { int rounds = 0; while (true) { - BoolExpr r = (BoolExpr)Expr.Create(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject)); + BoolExpr r = (BoolExpr)Expr.Create(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, BacktrackLevel)); if (r.IsFalse) { - if (rounds == 0) - yield return r; break; } if (r.IsTrue) { @@ -412,6 +416,7 @@ namespace Microsoft.Z3 : base(ctx, obj) { Contract.Requires(ctx != null); + this.BacktrackLevel = uint.MaxValue; } internal class DecRefQueue : IDecRefQueue diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 6b6c90019..45fedc674 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6283,19 +6283,16 @@ class Solver(Z3PPObject): consequences = [ consequences[i] for i in range(sz) ] return CheckSatResult(r), consequences - def cube(self): + def cube(self, level_ref): """Get set of cubes""" - rounds = 0 while True: - r = _to_expr_ref(Z3_solver_cube(self.ctx.ref(), self.solver), self.ctx) + backtrack_level = level_ref.backtrack_level + r = _to_expr_ref(Z3_solver_cube(self.ctx.ref(), self.solver, backtrack_level), self.ctx) if (is_false(r)): - if (rounds == 0): - yield r return if (is_true(r)): yield r return - rounds += 1 yield r def proof(self): diff --git a/src/api/z3_api.h b/src/api/z3_api.h index ffda1ecbd..b17e2a531 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6232,10 +6232,13 @@ extern "C" { The number of (non-constant) cubes is by default 1. For the sat solver cubing is controlled using parameters sat.lookahead.cube.cutoff and sat.lookahead.cube.fraction. - def_API('Z3_solver_cube', AST, (_in(CONTEXT), _in(SOLVER))) + The last argument is a backtracking level. It instructs the cube process to backtrack below + the indicated level for the next cube. + + def_API('Z3_solver_cube', AST, (_in(CONTEXT), _in(SOLVER), _in(UINT))) */ - Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s); + Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, unsigned backtrack_level); /** \brief Retrieve the model for the last #Z3_solver_check or #Z3_solver_check_assumptions diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 6fc67a243..c61dba13c 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -119,7 +119,7 @@ public: {NOT_IMPLEMENTED_YET();} virtual void assert_lemma(expr* e) { NOT_IMPLEMENTED_YET(); } virtual expr_ref lookahead(const expr_ref_vector &,const expr_ref_vector &) { return expr_ref(m.mk_true(), m); } - virtual expr_ref cube() { return expr_ref(m.mk_true(), m); } + virtual expr_ref cube(unsigned) { return expr_ref(m.mk_true(), m); } virtual void push(); diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 4e1f43bfc..4818600a9 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -94,7 +94,7 @@ public: virtual void reset(); virtual void set_progress_callback(progress_callback *callback) {UNREACHABLE();} - virtual expr_ref cube() { return expr_ref(m.mk_true(), m); } + virtual expr_ref cube(unsigned) { return expr_ref(m.mk_true(), m); } virtual solver *translate(ast_manager &m, params_ref const &p); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 1f0a518b2..f695bae28 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -108,7 +108,7 @@ namespace opt { virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); - virtual expr_ref cube() { return expr_ref(m.mk_true(), m); } + virtual expr_ref cube(unsigned) { return expr_ref(m.mk_true(), m); } void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 2a880f918..a1a80df97 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -349,7 +349,7 @@ namespace sat { } bool nullify = p.lit() != null_literal && value(p.lit()) == l_true; if (nullify) { - IF_VERBOSE(10, display(verbose_stream() << "nullify tracking literal\n", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "nullify tracking literal\n", p, true);); SASSERT(lvl(p.lit()) == 0); nullify_tracking_literal(p); init_watch(p, true); @@ -374,7 +374,7 @@ namespace sat { if (p.k() == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - IF_VERBOSE(10, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); remove_constraint(p, "implies clause"); } else if (true_val == 0 && num_false == 0) { @@ -384,14 +384,14 @@ namespace sat { } else if (true_val >= p.k()) { if (p.lit() != null_literal) { - IF_VERBOSE(10, display(verbose_stream() << "assign true literal ", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "assign true literal ", p, true);); s().assign(p.lit(), justification()); } remove_constraint(p, "is true"); } else if (slack + true_val < p.k()) { if (p.lit() != null_literal) { - IF_VERBOSE(10, display(verbose_stream() << "assign false literal ", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "assign false literal ", p, true);); s().assign(~p.lit(), justification()); } else { @@ -2877,7 +2877,7 @@ namespace sat { bool ba_solver::elim_pure(literal lit) { if (value(lit) == l_undef && !m_cnstr_use_list[lit.index()].empty() && use_count(~lit) == 0 && get_num_unblocked_bin(~lit) == 0) { - IF_VERBOSE(10, verbose_stream() << "pure literal: " << lit << "\n";); + IF_VERBOSE(100, verbose_stream() << "pure literal: " << lit << "\n";); s().assign(lit, justification()); return true; } diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index a41468936..e4878df42 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1964,7 +1964,7 @@ namespace sat { bool_var_vector vars; for (bool_var v : m_freevars) vars.push_back(v); while (true) { - lbool result = cube(vars, lits); + lbool result = cube(vars, lits, UINT_MAX); if (lits.empty() || result != l_undef) { return l_undef; } @@ -1973,7 +1973,7 @@ namespace sat { return l_undef; } - lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits) { + lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level) { scoped_ext _scoped_ext(*this); lits.reset(); m_select_lookahead_vars.reset(); @@ -2006,6 +2006,14 @@ namespace sat { continue; } pick_up_work: + if (m_cube_state.m_cube.size() >= backtrack_level) { + IF_VERBOSE(10, verbose_stream() << "(sat-cube :cube: " << m_cube_state.m_cube.size() << " :backtrack_level " << backtrack_level << ")\n";); + while (m_cube_state.m_cube.size() >= backtrack_level) { + set_conflict(); + backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision); + } + backtrack_level = UINT_MAX; + } depth = m_cube_state.m_cube.size(); if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index baf3ed660..6cf75937f 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -567,7 +567,7 @@ namespace sat { lbool cube(); - lbool cube(bool_var_vector const& vars, literal_vector& lits); + lbool cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level); literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index ba6e63680..61dc1f6c2 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -837,11 +837,11 @@ namespace sat { return lh.select_lookahead(assumptions, vars); } - lbool solver::cube(bool_var_vector const& vars, literal_vector& lits) { + lbool solver::cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level) { if (!m_cuber) { m_cuber = alloc(lookahead, *this); } - lbool result = m_cuber->cube(vars, lits); + lbool result = m_cuber->cube(vars, lits, backtrack_level); if (result == l_false) { dealloc(m_cuber); m_cuber = nullptr; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index bf5f0975b..cb8c2b763 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -352,7 +352,7 @@ namespace sat { bool check_clauses(model const& m) const; literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); - lbool cube(bool_var_vector const& vars, literal_vector& lits); + lbool cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level); protected: unsigned m_conflicts_since_init; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index b9bc81e3d..98c42ed19 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -301,7 +301,7 @@ public: return 0; } - virtual expr_ref cube() { + virtual expr_ref cube(unsigned backtrack_level) { if (!m_internalized) { dep2asm_t dep2asm; m_model = 0; @@ -315,7 +315,7 @@ public: vars.push_back(kv.m_value); } sat::literal_vector lits; - lbool result = m_solver.cube(vars, lits); + lbool result = m_solver.cube(vars, lits, backtrack_level); if (result == l_false || lits.empty()) { return expr_ref(m.mk_false(), m); } diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index b37d004f4..1a0e6facd 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -226,7 +226,7 @@ namespace smt { return expr_ref(m.mk_true(), m); } - virtual expr_ref cube() { + virtual expr_ref cube(unsigned) { ast_manager& m = get_manager(); return expr_ref(m.mk_true(), m); } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 05e75a9a4..7d41a8685 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -281,8 +281,8 @@ public: return m_solver1->get_num_assumptions() + m_solver2->get_num_assumptions(); } - virtual expr_ref cube() { - return m_solver1->cube(); + virtual expr_ref cube(unsigned backtrack_level) { + return m_solver1->cube(backtrack_level); } virtual expr * get_assumption(unsigned idx) const { diff --git a/src/solver/solver.h b/src/solver/solver.h index 3719b5a6a..8d9488c48 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -189,7 +189,7 @@ public: \brief extract a lookahead candidates for branching. */ - virtual expr_ref cube() = 0; + virtual expr_ref cube(unsigned backtrack_level) = 0; /** \brief Display the content of this solver. diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index b2da00bfa..afefd8433 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -223,7 +223,7 @@ public: virtual void get_labels(svector & r) { return m_base->get_labels(r); } virtual void set_progress_callback(progress_callback * callback) { m_base->set_progress_callback(callback); } - virtual expr_ref cube() { return expr_ref(m.mk_true(), m); } + virtual expr_ref cube(unsigned ) { return expr_ref(m.mk_true(), m); } virtual ast_manager& get_manager() const { return m_base->get_manager(); } diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index dc9f1b25f..607f0994f 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -77,7 +77,7 @@ public: virtual ast_manager& get_manager() const; - virtual expr_ref cube() { + virtual expr_ref cube(unsigned ) { ast_manager& m = get_manager(); return expr_ref(m.mk_true(), m); } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 195a16fbf..da031171d 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -163,7 +163,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref cube() { flush_assertions(); return m_solver->cube(); } + virtual expr_ref cube(unsigned backtrack_level) { flush_assertions(); return m_solver->cube(backtrack_level); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index b16ba2443..474084650 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -113,7 +113,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual expr_ref cube() { return m_solver->cube(); } + virtual expr_ref cube(unsigned backtrack_level) { return m_solver->cube(backtrack_level); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { datatype_util dt(m); diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 7651ace16..7d25f0f7e 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -414,7 +414,7 @@ private: cubes.reset(); s.set_cube_params(); while (true) { - expr_ref c = s.get_solver().cube(); + expr_ref c = s.get_solver().cube(UINT_MAX); // TBD tune this VERIFY(c); if (m.is_false(c)) { break; diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 33a8fcd46..7d2e1f322 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -103,7 +103,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref cube() { flush_assertions(); return m_solver->cube(); } + virtual expr_ref cube(unsigned backtrack_level) { flush_assertions(); return m_solver->cube(backtrack_level); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); From bc8681a0ea5441a7741b29380b118e59ad656d28 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 8 Nov 2017 22:14:59 -0800 Subject: [PATCH 0328/1283] reset backtrack level after first backtrack Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 6 +++--- src/sat/sat_lookahead.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 45fedc674..2ae7e6ced 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5988,6 +5988,7 @@ class Solver(Z3PPObject): def __init__(self, solver=None, ctx=None): assert solver is None or ctx is not None self.ctx = _get_ctx(ctx) + self.backtrack_level = 4000000000 self.solver = None if solver is None: self.solver = Z3_mk_solver(self.ctx.ref()) @@ -6283,11 +6284,10 @@ class Solver(Z3PPObject): consequences = [ consequences[i] for i in range(sz) ] return CheckSatResult(r), consequences - def cube(self, level_ref): + def cube(self): """Get set of cubes""" while True: - backtrack_level = level_ref.backtrack_level - r = _to_expr_ref(Z3_solver_cube(self.ctx.ref(), self.solver, backtrack_level), self.ctx) + r = _to_expr_ref(Z3_solver_cube(self.ctx.ref(), self.solver, self.backtrack_level), self.ctx) if (is_false(r)): return if (is_true(r)): diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index e4878df42..27d174653 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2012,8 +2012,8 @@ namespace sat { set_conflict(); backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision); } - backtrack_level = UINT_MAX; } + backtrack_level = UINT_MAX; depth = m_cube_state.m_cube.size(); if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) { From 700f413e269cd1846df551da2c39de4beb064e40 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Nov 2017 09:55:37 -0800 Subject: [PATCH 0329/1283] updates Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 10 +++++----- src/solver/solver.h | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 2a880f918..a1a80df97 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -349,7 +349,7 @@ namespace sat { } bool nullify = p.lit() != null_literal && value(p.lit()) == l_true; if (nullify) { - IF_VERBOSE(10, display(verbose_stream() << "nullify tracking literal\n", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "nullify tracking literal\n", p, true);); SASSERT(lvl(p.lit()) == 0); nullify_tracking_literal(p); init_watch(p, true); @@ -374,7 +374,7 @@ namespace sat { if (p.k() == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - IF_VERBOSE(10, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); remove_constraint(p, "implies clause"); } else if (true_val == 0 && num_false == 0) { @@ -384,14 +384,14 @@ namespace sat { } else if (true_val >= p.k()) { if (p.lit() != null_literal) { - IF_VERBOSE(10, display(verbose_stream() << "assign true literal ", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "assign true literal ", p, true);); s().assign(p.lit(), justification()); } remove_constraint(p, "is true"); } else if (slack + true_val < p.k()) { if (p.lit() != null_literal) { - IF_VERBOSE(10, display(verbose_stream() << "assign false literal ", p, true);); + IF_VERBOSE(100, display(verbose_stream() << "assign false literal ", p, true);); s().assign(~p.lit(), justification()); } else { @@ -2877,7 +2877,7 @@ namespace sat { bool ba_solver::elim_pure(literal lit) { if (value(lit) == l_undef && !m_cnstr_use_list[lit.index()].empty() && use_count(~lit) == 0 && get_num_unblocked_bin(~lit) == 0) { - IF_VERBOSE(10, verbose_stream() << "pure literal: " << lit << "\n";); + IF_VERBOSE(100, verbose_stream() << "pure literal: " << lit << "\n";); s().assign(lit, justification()); return true; } diff --git a/src/solver/solver.h b/src/solver/solver.h index 3719b5a6a..d0e70546b 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -61,7 +61,7 @@ public: /** \brief Retrieve set of parameters set on solver. */ - virtual params_ref const& get_params() { return m_params; } + virtual params_ref const& get_params() const { return m_params; } /** \brief Store in \c r a description of the configuration diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 33a8fcd46..22303f62a 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -134,6 +134,7 @@ public: private: void flush_assertions() const { + m_rewriter.updt_params(get_params()); proof_ref proof(m); expr_ref fml1(m), fml(m); expr_ref_vector fmls(m); From cb7e53aae4f32ff9090b87eb148f6477cf137195 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 9 Nov 2017 10:04:32 -0800 Subject: [PATCH 0330/1283] reset backtrack level at each cube Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Solver.cs | 6 +++--- src/api/python/z3/z3.py | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 4a779e91b..24a0bbc61 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -364,9 +364,10 @@ namespace Microsoft.Z3 /// public IEnumerable Cube() { - int rounds = 0; while (true) { - BoolExpr r = (BoolExpr)Expr.Create(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, BacktrackLevel)); + var lvl = BacktrackLevel; + BacktrackLevel = uint.MaxValue; + BoolExpr r = (BoolExpr)Expr.Create(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, lvl)); if (r.IsFalse) { break; } @@ -374,7 +375,6 @@ namespace Microsoft.Z3 yield return r; break; } - ++rounds; yield return r; } } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 2ae7e6ced..1402d1ce7 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6287,7 +6287,9 @@ class Solver(Z3PPObject): def cube(self): """Get set of cubes""" while True: - r = _to_expr_ref(Z3_solver_cube(self.ctx.ref(), self.solver, self.backtrack_level), self.ctx) + lvl = self.backtrack_level + self.backtrack_level = 4000000000 + r = _to_expr_ref(Z3_solver_cube(self.ctx.ref(), self.solver, lvl), self.ctx) if (is_false(r)): return if (is_true(r)): From 454e12fc49bbd44919722b9ce68fee7e505e1d26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Nov 2017 15:28:16 -0800 Subject: [PATCH 0331/1283] update to vector format Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 14 +++++++++----- src/api/dotnet/Solver.cs | 13 ++++++------- src/api/python/z3/z3.py | 9 ++++----- src/api/z3_api.h | 4 ++-- src/muz/spacer/spacer_itp_solver.h | 2 +- src/muz/spacer/spacer_virtual_solver.h | 2 +- src/opt/opt_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 12 +++++++----- src/smt/smt_solver.cpp | 5 ++--- src/solver/combined_solver.cpp | 2 +- src/solver/solver.h | 2 +- src/solver/solver_pool.cpp | 2 +- src/solver/tactic2solver.cpp | 5 ++--- src/tactic/portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/tactic/portfolio/parallel_tactic.cpp | 13 ++++++------- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 17 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 0c94c0b4e..9f13ce3c1 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -529,11 +529,11 @@ extern "C" { Z3_CATCH_RETURN(Z3_L_UNDEF); } - Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, unsigned cutoff) { + Z3_ast_vector Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, unsigned cutoff) { Z3_TRY; LOG_Z3_solver_cube(c, s, cutoff); ast_manager& m = mk_c(c)->m(); - expr_ref result(m); + expr_ref_vector result(m); unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); @@ -544,15 +544,19 @@ extern "C" { scoped_timer timer(timeout, &eh); scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); try { - result = to_solver_ref(s)->cube(cutoff); + result.append(to_solver_ref(s)->cube(cutoff)); } catch (z3_exception & ex) { mk_c(c)->handle_exception(ex); return 0; } } - mk_c(c)->save_ast_trail(result); - RETURN_Z3(of_ast(result)); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + mk_c(c)->save_object(v); + for (expr* e : result) { + v->m_ast_vector.push_back(e); + } + RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 24a0bbc61..4b8ff4cf6 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -362,20 +362,19 @@ namespace Microsoft.Z3 /// /// Return a set of cubes. /// - public IEnumerable Cube() + public IEnumerable Cube() { while (true) { var lvl = BacktrackLevel; BacktrackLevel = uint.MaxValue; - BoolExpr r = (BoolExpr)Expr.Create(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, lvl)); - if (r.IsFalse) { + ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, lvl)); + if (r.Size == 1 && ((Expr)r[0]).IsFalse) { break; } - if (r.IsTrue) { - yield return r; - break; + yield return r.ToBoolExprArray(); + if (r.Size == 0) { + break; } - yield return r; } } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1402d1ce7..e281a1273 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6289,13 +6289,12 @@ class Solver(Z3PPObject): while True: lvl = self.backtrack_level self.backtrack_level = 4000000000 - r = _to_expr_ref(Z3_solver_cube(self.ctx.ref(), self.solver, lvl), self.ctx) - if (is_false(r)): + r = AstVector(Z3_solver_cube(self.ctx.ref(), self.solver, lvl), self.ctx) + if (len(r) == 1 and is_false(r[0])): return - if (is_true(r)): - yield r + yield r + if (len(r) == 0): return - yield r def proof(self): """Return a proof for the last `check()`. Proof construction must be enabled.""" diff --git a/src/api/z3_api.h b/src/api/z3_api.h index b17e2a531..67fc0c903 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6235,10 +6235,10 @@ extern "C" { The last argument is a backtracking level. It instructs the cube process to backtrack below the indicated level for the next cube. - def_API('Z3_solver_cube', AST, (_in(CONTEXT), _in(SOLVER), _in(UINT))) + def_API('Z3_solver_cube', AST_VECTOR, (_in(CONTEXT), _in(SOLVER), _in(UINT))) */ - Z3_ast Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, unsigned backtrack_level); + Z3_ast_vector Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, unsigned backtrack_level); /** \brief Retrieve the model for the last #Z3_solver_check or #Z3_solver_check_assumptions diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index c61dba13c..ab3b94894 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -119,7 +119,7 @@ public: {NOT_IMPLEMENTED_YET();} virtual void assert_lemma(expr* e) { NOT_IMPLEMENTED_YET(); } virtual expr_ref lookahead(const expr_ref_vector &,const expr_ref_vector &) { return expr_ref(m.mk_true(), m); } - virtual expr_ref cube(unsigned) { return expr_ref(m.mk_true(), m); } + virtual expr_ref_vector cube(unsigned) { return expr_ref_vector(m); } virtual void push(); diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 4818600a9..3b256f297 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -94,7 +94,7 @@ public: virtual void reset(); virtual void set_progress_callback(progress_callback *callback) {UNREACHABLE();} - virtual expr_ref cube(unsigned) { return expr_ref(m.mk_true(), m); } + virtual expr_ref_vector cube(unsigned) { return expr_ref_vector(m); } virtual solver *translate(ast_manager &m, params_ref const &p); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index f695bae28..61947e768 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -108,7 +108,7 @@ namespace opt { virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); - virtual expr_ref cube(unsigned) { return expr_ref(m.mk_true(), m); } + virtual expr_ref_vector cube(unsigned) { return expr_ref_vector(m); } void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 98c42ed19..b5efe57da 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -301,12 +301,12 @@ public: return 0; } - virtual expr_ref cube(unsigned backtrack_level) { + virtual expr_ref_vector cube(unsigned backtrack_level) { if (!m_internalized) { dep2asm_t dep2asm; m_model = 0; lbool r = internalize_formulas(); - if (r != l_true) return expr_ref(m.mk_true(), m); + if (r != l_true) return expr_ref_vector(m); m_internalized = true; } convert_internalized(); @@ -317,10 +317,12 @@ public: sat::literal_vector lits; lbool result = m_solver.cube(vars, lits, backtrack_level); if (result == l_false || lits.empty()) { - return expr_ref(m.mk_false(), m); + expr_ref_vector result(m); + result.push_back(m.mk_false()); + return result; } if (result == l_true) { - return expr_ref(m.mk_true(), m); + return expr_ref_vector(m); } expr_ref_vector fmls(m); expr_ref_vector lit2expr(m); @@ -329,7 +331,7 @@ public: for (sat::literal l : lits) { fmls.push_back(lit2expr[l.index()].get()); } - return mk_and(fmls); + return fmls; } virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 1a0e6facd..850621e67 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -226,9 +226,8 @@ namespace smt { return expr_ref(m.mk_true(), m); } - virtual expr_ref cube(unsigned) { - ast_manager& m = get_manager(); - return expr_ref(m.mk_true(), m); + virtual expr_ref_vector cube(unsigned) { + return expr_ref_vector(get_manager()); } struct collect_fds_proc { diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 7d41a8685..cc52c90cb 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -281,7 +281,7 @@ public: return m_solver1->get_num_assumptions() + m_solver2->get_num_assumptions(); } - virtual expr_ref cube(unsigned backtrack_level) { + virtual expr_ref_vector cube(unsigned backtrack_level) { return m_solver1->cube(backtrack_level); } diff --git a/src/solver/solver.h b/src/solver/solver.h index a3454a798..713434d7c 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -189,7 +189,7 @@ public: \brief extract a lookahead candidates for branching. */ - virtual expr_ref cube(unsigned backtrack_level) = 0; + virtual expr_ref_vector cube(unsigned backtrack_level) = 0; /** \brief Display the content of this solver. diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index afefd8433..3c7837ad5 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -223,7 +223,7 @@ public: virtual void get_labels(svector & r) { return m_base->get_labels(r); } virtual void set_progress_callback(progress_callback * callback) { m_base->set_progress_callback(callback); } - virtual expr_ref cube(unsigned ) { return expr_ref(m.mk_true(), m); } + virtual expr_ref_vector cube(unsigned ) { return expr_ref_vector(m); } virtual ast_manager& get_manager() const { return m_base->get_manager(); } diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 607f0994f..dd2f42e7a 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -77,9 +77,8 @@ public: virtual ast_manager& get_manager() const; - virtual expr_ref cube(unsigned ) { - ast_manager& m = get_manager(); - return expr_ref(m.mk_true(), m); + virtual expr_ref_vector cube(unsigned ) { + return expr_ref_vector(get_manager()); } virtual model_converter_ref get_model_converter() const { return m_mc; } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index da031171d..c0e5e0a46 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -163,7 +163,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref cube(unsigned backtrack_level) { flush_assertions(); return m_solver->cube(backtrack_level); } + virtual expr_ref_vector cube(unsigned backtrack_level) { flush_assertions(); return m_solver->cube(backtrack_level); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 474084650..4722f9289 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -113,7 +113,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual expr_ref cube(unsigned backtrack_level) { return m_solver->cube(backtrack_level); } + virtual expr_ref_vector cube(unsigned backtrack_level) { return m_solver->cube(backtrack_level); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { datatype_util dt(m); diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 7d25f0f7e..8a6c6fa15 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -414,16 +414,15 @@ private: cubes.reset(); s.set_cube_params(); while (true) { - expr_ref c = s.get_solver().cube(UINT_MAX); // TBD tune this - VERIFY(c); - if (m.is_false(c)) { - break; - } - if (m.is_true(c)) { + expr_ref_vector c = s.get_solver().cube(UINT_MAX); // TBD tune this + if (c.empty()) { report_undef(s); return; } - cubes.push_back(c); + if (m.is_false(c.back())) { + break; + } + cubes.push_back(mk_and(c)); } IF_VERBOSE(1, verbose_stream() << "(parallel_tactic :cubes " << cubes.size() << ")\n";); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 4f4c044b8..f6a7b1622 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -103,7 +103,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref cube(unsigned backtrack_level) { flush_assertions(); return m_solver->cube(backtrack_level); } + virtual expr_ref_vector cube(unsigned backtrack_level) { flush_assertions(); return m_solver->cube(backtrack_level); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); From c522487a86be7a7918c78a0fca0c99cc004340e1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 10 Nov 2017 16:59:35 -0800 Subject: [PATCH 0332/1283] add iterators to C++ vectors Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 7015f6c08..c397271e3 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1508,6 +1508,30 @@ namespace z3 { m_vector = s.m_vector; return *this; } + class iterator { + ast_vector_tpl const* m_vector; + unsigned m_index; + public: + iterator(ast_vector_tpl const* v, unsigned i): m_vector(v), m_index(i) {} + iterator(iterator& other): m_vector(other.m_vector), m_index(other.m_index) {} + iterator operator=(iterator const& other) { m_vector = other.m_vector; m_index = other.m_index; return *this; } + + bool operator==(iterator const& other) { + return other.m_index == m_index; + }; + bool operator!=(iterator const& other) { + return other.m_index != m_index; + }; + iterator& operator++() { + ++m_index; + return *this; + } + iterator operator++(int) { iterator tmp = *this; ++m_index; return tmp; } + T * operator->() const { return &(operator*()); } + T operator*() const { return (*m_vector)[m_index]; } + }; + iterator begin() const { return iterator(this, 0); } + iterator end() const { return iterator(this, size()); } friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; } }; @@ -1975,6 +1999,7 @@ namespace z3 { return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } + void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(v); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } From a6da207b652384d3a0328846140aa169b54c2252 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Nov 2017 11:25:43 -0800 Subject: [PATCH 0333/1283] fix crash bugs in sat solver Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 87 +++++++++++++++++++++++++++++++++++- src/sat/sat_asymm_branch.cpp | 1 - src/sat/sat_clause.cpp | 16 +++++-- src/sat/sat_clause.h | 1 + src/sat/sat_justification.h | 2 +- src/sat/sat_simplifier.cpp | 9 +--- src/sat/sat_solver.cpp | 36 ++++++++------- src/sat/sat_types.h | 2 +- src/sat/sat_watched.cpp | 20 ++++----- src/sat/sat_watched.h | 2 + 10 files changed, 133 insertions(+), 43 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index c397271e3..52671a073 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -421,6 +421,7 @@ namespace z3 { void set(char const * k, unsigned n) { Z3_params_set_uint(ctx(), m_params, ctx().str_symbol(k), n); } void set(char const * k, double n) { Z3_params_set_double(ctx(), m_params, ctx().str_symbol(k), n); } void set(char const * k, symbol const & s) { Z3_params_set_symbol(ctx(), m_params, ctx().str_symbol(k), s); } + void set(char const * k, char const* s) { Z3_params_set_symbol(ctx(), m_params, ctx().str_symbol(k), ctx().str_symbol(s)); } friend std::ostream & operator<<(std::ostream & out, params const & p); }; @@ -1508,6 +1509,11 @@ namespace z3 { m_vector = s.m_vector; return *this; } + bool contains(T const& x) const { + for (auto y : *this) if (x == y) return true; + return false; + } + class iterator { ast_vector_tpl const* m_vector; unsigned m_index; @@ -1907,6 +1913,11 @@ namespace z3 { return *this; } void set(params const & p) { Z3_solver_set_params(ctx(), m_solver, p); check_error(); } + void set(char const * k, bool v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, unsigned v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, double v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, symbol const & v) { params p(ctx()); p.set(k, v); set(p); } + void set(char const * k, char const* v) { params p(ctx()); p.set(k, v); set(p); } void push() { Z3_solver_push(ctx(), m_solver); check_error(); } void pop(unsigned n = 1) { Z3_solver_pop(ctx(), m_solver, n); check_error(); } void reset() { Z3_solver_reset(ctx(), m_solver); check_error(); } @@ -1919,6 +1930,8 @@ namespace z3 { void add(expr const & e, char const * p) { add(e, ctx().bool_const(p)); } + void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } + void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); check_error(); } check_result check() { Z3_lbool r = Z3_solver_check(ctx(), m_solver); check_error(); return to_check_result(r); } check_result check(unsigned n, expr * const assumptions) { array _assumptions(n); @@ -1976,6 +1989,78 @@ namespace z3 { param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_solver_get_param_descrs(ctx(), m_solver)); } + + expr_vector cube(unsigned cutoff) { Z3_ast_vector r = Z3_solver_cube(ctx(), m_solver, cutoff); check_error(); return expr_vector(ctx(), r); } + + class cube_iterator { + solver& m_solver; + unsigned& m_cutoff; + expr_vector m_cube; + bool m_end; + + bool is_false() const { return m_cube.size() == 1 && Z3_OP_FALSE == m_cube[0].decl().decl_kind(); } + + void check_end() { + if (is_false()) { + m_cube = z3::expr_vector(m_solver.ctx()); + m_end = true; + } + else if (m_cube.empty()) { + m_end = true; + } + } + + void inc() { + assert(!m_end); + m_cube = m_solver.cube(m_cutoff); + m_cutoff = 0xFFFFFFFF; + check_end(); + } + public: + cube_iterator(solver& s, unsigned& cutoff, bool end): + m_solver(s), + m_cutoff(cutoff), + m_cube(s.ctx()), + m_end(end) { + if (!m_end) { + inc(); + } + } + + cube_iterator& operator++() { + assert(!m_end); + inc(); + return *this; + } + cube_iterator operator++(int) { assert(false); return *this; } + expr_vector const * operator->() const { return &(operator*()); } + expr_vector const& operator*() const { return m_cube; } + + bool operator==(cube_iterator const& other) { + return other.m_end == m_end; + }; + bool operator!=(cube_iterator const& other) { + return other.m_end != m_end; + }; + + }; + + class cube_generator { + solver& m_solver; + unsigned m_cutoff; + public: + cube_generator(solver& s): + m_solver(s), + m_cutoff(0xFFFFFFFF) + {} + + cube_iterator begin() { return cube_iterator(m_solver, m_cutoff, false); } + cube_iterator end() { return cube_iterator(m_solver, m_cutoff, true); } + void set_cutoff(unsigned c) { m_cutoff = c; } + }; + + cube_generator cubes() { return cube_generator(*this); } + }; inline std::ostream & operator<<(std::ostream & out, solver const & s) { out << Z3_solver_to_string(s.ctx(), s); return out; } @@ -1999,7 +2084,7 @@ namespace z3 { return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } - void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(v); } + void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 029274c97..83574749e 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -201,7 +201,6 @@ namespace sat { return false; default: c.shrink(new_sz); - s.attach_clause(c); if (s.m_config.m_drat) s.m_drat.add(c, true); // if (s.m_config.m_drat) s.m_drat.del(c0); // TBD SASSERT(s.m_qhead == s.m_trail.size()); diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 43d614e38..9bfd1d38d 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -129,20 +129,23 @@ namespace sat { } clause * clause_allocator::get_clause(clause_offset cls_off) const { -#if defined(_AMD64_) +#if 0 +// defined(_AMD64_) if (((cls_off & c_alignment_mask) == c_last_segment)) { unsigned id = cls_off >> c_cls_alignment; return const_cast(m_last_seg_id2cls[id]); } return reinterpret_cast(m_segments[cls_off & c_alignment_mask] + (static_cast(cls_off) & ~c_alignment_mask)); #else + VERIFY(cls_off == reinterpret_cast(reinterpret_cast(cls_off))); return reinterpret_cast(cls_off); #endif } clause_offset clause_allocator::get_offset(clause const * cls) const { -#if defined(_AMD64_) +#if 0 +// defined(_AMD64_) size_t ptr = reinterpret_cast(cls); SASSERT((ptr & c_alignment_mask) == 0); @@ -163,6 +166,7 @@ namespace sat { return static_cast(reinterpret_cast(cls)) + i; } #else + VERIFY(cls == reinterpret_cast(reinterpret_cast(cls))); return reinterpret_cast(cls); #endif } @@ -178,9 +182,13 @@ namespace sat { void clause_allocator::del_clause(clause * cls) { TRACE("sat_clause", tout << "delete: " << cls->id() << " " << *cls << "\n";); + if (cls->id() == 62805 && cls->capacity() == 29) { + std::cout << "delete 62805\n"; + for (literal l : *cls) { + std::cout << l << "\n"; + } + } m_id_gen.recycle(cls->id()); -#if defined(_AMD64_) -#endif size_t size = clause::get_obj_size(cls->m_capacity); cls->~clause(); m_allocator.deallocate(size, cls); diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index dd7af64eb..08fff7adb 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -62,6 +62,7 @@ namespace sat { public: unsigned id() const { return m_id; } unsigned size() const { return m_size; } + unsigned capacity() const { return m_capacity; } literal & operator[](unsigned idx) { SASSERT(idx < m_size); return m_lits[idx]; } literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; } bool is_learned() const { return m_learned; } diff --git a/src/sat/sat_justification.h b/src/sat/sat_justification.h index b8b3dcbdc..497d636c8 100644 --- a/src/sat/sat_justification.h +++ b/src/sat/sat_justification.h @@ -48,7 +48,7 @@ namespace sat { literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 3); } bool is_clause() const { return m_val2 == CLAUSE; } - clause_offset get_clause_offset() const { return val1(); } + clause_offset get_clause_offset() const { return m_val1; } bool is_ext_justification() const { return m_val2 == EXT_JUSTIFICATION; } ext_justification_idx get_ext_justification_idx() const { return m_val1; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 2cc5758d3..89b07ddd4 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -268,19 +268,12 @@ namespace sat { bool vars_eliminated = m_num_elim_vars > m_old_num_elim_vars; - if (m_need_cleanup) { + if (m_need_cleanup || vars_eliminated) { TRACE("after_simplifier", tout << "cleanning watches...\n";); cleanup_watches(); cleanup_clauses(s.m_learned, true, vars_eliminated, m_learned_in_use_lists); cleanup_clauses(s.m_clauses, false, vars_eliminated, true); } - else { - TRACE("after_simplifier", tout << "skipping cleanup...\n";); - if (vars_eliminated) { - // must remove learned clauses with eliminated variables - cleanup_clauses(s.m_learned, true, true, m_learned_in_use_lists); - } - } CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 61dc1f6c2..d2a1b8b16 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -417,6 +417,9 @@ 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]); 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; @@ -563,6 +566,9 @@ namespace sat { void solver::detach_nary_clause(clause & c) { clause_offset cls_off = get_offset(c); + if (c.id() == 62805 && c.capacity() == 29) { + std::cout << "detach: " << c[0] << " " << c[1] << " size: " << c.size() << " cap: " << c.capacity() << " id: " << c.id() << "\n"; + } erase_clause_watch(get_wlist(~c[0]), cls_off); erase_clause_watch(get_wlist(~c[1]), cls_off); } @@ -753,18 +759,19 @@ namespace sat { it2++; break; } - SASSERT(c[1] == not_l); if (value(c[0]) == l_true) { it2->set_clause(c[0], cls_off); it2++; break; } + VERIFY(c[1] == not_l); literal * l_it = c.begin() + 2; literal * l_end = c.end(); for (; l_it != l_end; ++l_it) { if (value(*l_it) != l_false) { c[1] = *l_it; *l_it = not_l; + DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off);); m_watches[(~c[1]).index()].push_back(watched(c[0], cls_off)); goto end_clause_case; } @@ -1555,7 +1562,7 @@ namespace sat { if (!check_clauses(m_model)) { - std::cout << "failure checking clauses on transformed model\n"; + IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";); UNREACHABLE(); throw solver_exception("check model failed"); } @@ -3267,29 +3274,24 @@ namespace sat { for (unsigned i = 0; i < m_trail.size(); i++) { out << max_weight << " " << dimacs_lit(m_trail[i]) << " 0\n"; } - vector::const_iterator it = m_watches.begin(); - vector::const_iterator end = m_watches.end(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { + unsigned l_idx = 0; + for (watch_list const& wlist : m_watches) { literal l = ~to_literal(l_idx); - watch_list const & wlist = *it; - watch_list::const_iterator it2 = wlist.begin(); - watch_list::const_iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - if (it2->is_binary_clause() && l.index() < it2->get_literal().index()) - out << max_weight << " " << dimacs_lit(l) << " " << dimacs_lit(it2->get_literal()) << " 0\n"; + for (watched const& w : wlist) { + if (w.is_binary_clause() && l.index() < w.get_literal().index()) + out << max_weight << " " << dimacs_lit(l) << " " << dimacs_lit(w.get_literal()) << " 0\n"; } + ++l_idx; } clause_vector const * vs[2] = { &m_clauses, &m_learned }; for (unsigned i = 0; i < 2; i++) { clause_vector const & cs = *(vs[i]); - clause_vector::const_iterator it = cs.begin(); - clause_vector::const_iterator end = cs.end(); - for (; it != end; ++it) { - clause const & c = *(*it); + for (clause const* cp : cs) { + clause const & c = *cp; unsigned clsz = c.size(); out << max_weight << " "; - for (unsigned j = 0; j < clsz; j++) - out << dimacs_lit(c[j]) << " "; + for (literal l : c) + out << dimacs_lit(l) << " "; out << "0\n"; } } diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index b2d29495c..5eded92ec 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -109,7 +109,7 @@ namespace sat { typedef svector literal_vector; typedef std::pair literal_pair; - typedef unsigned clause_offset; + typedef size_t clause_offset; typedef size_t ext_constraint_idx; typedef size_t ext_justification_idx; diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index d890a8ff7..af4fd598e 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -27,8 +27,9 @@ namespace sat { for (; it != end; ++it) { if (it->is_clause() && it->get_clause_offset() == c) { watch_list::iterator it2 = it; - ++it; + ++it; for (; it != end; ++it) { + SASSERT(!((it->is_clause() && it->get_clause_offset() == c))); *it2 = *it; ++it2; } @@ -40,27 +41,26 @@ namespace sat { } std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) { - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (bool first = true; it != end; ++it) { + bool first = true; + for (watched const& w : wlist) { if (first) first = false; else out << " "; - switch (it->get_kind()) { + switch (w.get_kind()) { case watched::BINARY: - out << it->get_literal(); - if (it->is_learned()) + out << w.get_literal(); + if (w.is_learned()) out << "*"; break; case watched::TERNARY: - out << "(" << it->get_literal1() << " " << it->get_literal2() << ")"; + out << "(" << w.get_literal1() << " " << w.get_literal2() << ")"; break; case watched::CLAUSE: - out << "(" << it->get_blocked_literal() << " " << *(ca.get_clause(it->get_clause_offset())) << ")"; + out << "(" << w.get_blocked_literal() << " " << *(ca.get_clause(w.get_clause_offset())) << ")"; break; case watched::EXT_CONSTRAINT: - out << "ext: " << it->get_ext_constraint_idx(); + out << "ext: " << w.get_ext_constraint_idx(); break; default: UNREACHABLE(); diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 8d7924c6f..e2d814f5b 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -64,6 +64,8 @@ namespace sat { SASSERT(get_literal2() == l2); } + unsigned val2() const { return m_val2; } + watched(literal blocked_lit, clause_offset cls_off): m_val1(cls_off), m_val2(static_cast(CLAUSE) + (blocked_lit.to_uint() << 2)) { From d7f9a3b37d1ac7b4fdccf1e317119cadbbf769ca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Nov 2017 11:27:10 -0800 Subject: [PATCH 0334/1283] fix crash bugs in sat solver Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d2a1b8b16..149d6feea 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -566,9 +566,6 @@ namespace sat { void solver::detach_nary_clause(clause & c) { clause_offset cls_off = get_offset(c); - if (c.id() == 62805 && c.capacity() == 29) { - std::cout << "detach: " << c[0] << " " << c[1] << " size: " << c.size() << " cap: " << c.capacity() << " id: " << c.id() << "\n"; - } erase_clause_watch(get_wlist(~c[0]), cls_off); erase_clause_watch(get_wlist(~c[1]), cls_off); } From 6f273e7b8f8f595dea418cfe221e2a73e4cd582f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Nov 2017 12:09:33 -0800 Subject: [PATCH 0335/1283] bug fixes in uninitialized variables Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 4 ++++ src/sat/sat_asymm_branch.h | 5 ++++- src/sat/sat_simplifier.cpp | 3 ++- src/sat/sat_solver.cpp | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 83574749e..abf1d95be 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -29,6 +29,7 @@ namespace sat { m_counter(0) { updt_params(p); reset_statistics(); + m_calls = 0; } struct clause_size_lt { @@ -57,6 +58,9 @@ namespace sat { }; void asymm_branch::operator()(bool force) { + ++m_calls; + if (m_calls <= 1) + return; if (!m_asymm_branch && !m_asymm_branch_all) return; s.propagate(false); // must propagate, since it uses s.push() diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index a11692a82..a6e44a4e2 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -33,7 +33,8 @@ namespace sat { solver & s; int64 m_counter; random_gen m_rand; - + unsigned m_calls; + // config bool m_asymm_branch; bool m_asymm_branch_all; @@ -63,6 +64,8 @@ namespace sat { void collect_statistics(statistics & st) const; void reset_statistics(); + void init_search() { m_calls = 0; } + inline void dec(unsigned c) { m_counter -= c; } }; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 89b07ddd4..656bff104 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -104,7 +104,7 @@ namespace sat { return !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); } bool simplifier::abce_enabled() const { - return !m_incremental_mode && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; + return !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; } bool simplifier::bca_enabled() const { return !m_incremental_mode && !s.tracking_assumptions() && m_bca && m_learned_in_use_lists && single_threaded(); @@ -1868,6 +1868,7 @@ namespace sat { m_cce = p.cce(); m_acce = p.acce(); m_bca = p.bca(); + m_abce = p.abce(); m_bce_delay = p.bce_delay(); m_elim_blocked_clauses = p.elim_blocked_clauses(); m_elim_blocked_clauses_at = p.elim_blocked_clauses_at(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 149d6feea..b0b5d8495 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1422,6 +1422,7 @@ namespace sat { m_next_simplify = 0; m_min_d_tk = 1.0; m_search_lvl = 0; + m_asymm_branch.init_search(); m_stopwatch.reset(); m_stopwatch.start(); m_core.reset(); From 37b94f1f909e35b7eaf3dcba0d1430ea7ad691e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 11 Nov 2017 17:22:33 -0800 Subject: [PATCH 0336/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 40 +++++++++++++++++++++++-------------- src/sat/sat_clause.cpp | 45 ++---------------------------------------- src/sat/sat_clause.h | 9 --------- 3 files changed, 27 insertions(+), 67 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 52671a073..417a86458 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -826,7 +826,6 @@ namespace z3 { */ friend expr operator!(expr const & a); - /** \brief Return an expression representing a and b. @@ -883,6 +882,16 @@ namespace z3 { friend expr ite(expr const & c, expr const & t, expr const & e); + bool is_true() const { return is_app() && Z3_OP_TRUE == decl().decl_kind(); } + bool is_false() const { return is_app() && Z3_OP_FALSE == decl().decl_kind(); } + bool is_not() const { return is_app() && Z3_OP_NOT == decl().decl_kind(); } + bool is_and() const { return is_app() && Z3_OP_AND == decl().decl_kind(); } + bool is_or() const { return is_app() && Z3_OP_OR == decl().decl_kind(); } + bool is_xor() const { return is_app() && Z3_OP_XOR == decl().decl_kind(); } + bool is_implies() const { return is_app() && Z3_OP_IMPLIES == decl().decl_kind(); } + bool is_eq() const { return is_app() && Z3_OP_EQ == decl().decl_kind(); } + bool is_ite() const { return is_app() && Z3_OP_ITE == decl().decl_kind(); } + friend expr distinct(expr_vector const& args); friend expr concat(expr const& a, expr const& b); friend expr concat(expr_vector const& args); @@ -1997,31 +2006,27 @@ namespace z3 { unsigned& m_cutoff; expr_vector m_cube; bool m_end; + bool m_empty; - bool is_false() const { return m_cube.size() == 1 && Z3_OP_FALSE == m_cube[0].decl().decl_kind(); } - - void check_end() { - if (is_false()) { + void inc() { + assert(!m_end && !m_empty); + m_cube = m_solver.cube(m_cutoff); + m_cutoff = 0xFFFFFFFF; + if (m_cube.size() == 1 && m_cube[0].is_false()) { m_cube = z3::expr_vector(m_solver.ctx()); m_end = true; } else if (m_cube.empty()) { - m_end = true; + m_empty = true; } } - - void inc() { - assert(!m_end); - m_cube = m_solver.cube(m_cutoff); - m_cutoff = 0xFFFFFFFF; - check_end(); - } public: cube_iterator(solver& s, unsigned& cutoff, bool end): m_solver(s), m_cutoff(cutoff), m_cube(s.ctx()), - m_end(end) { + m_end(end), + m_empty(false) { if (!m_end) { inc(); } @@ -2029,7 +2034,12 @@ namespace z3 { cube_iterator& operator++() { assert(!m_end); - inc(); + if (m_empty) { + m_end = true; + } + else { + inc(); + } return *this; } cube_iterator operator++(int) { assert(false); return *this; } diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 9bfd1d38d..90d542a14 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -123,52 +123,17 @@ namespace sat { clause_allocator::clause_allocator(): m_allocator("clause-allocator") { -#if defined(_AMD64_) - m_num_segments = 0; -#endif } clause * clause_allocator::get_clause(clause_offset cls_off) const { -#if 0 -// defined(_AMD64_) - if (((cls_off & c_alignment_mask) == c_last_segment)) { - unsigned id = cls_off >> c_cls_alignment; - return const_cast(m_last_seg_id2cls[id]); - } - return reinterpret_cast(m_segments[cls_off & c_alignment_mask] + (static_cast(cls_off) & ~c_alignment_mask)); -#else - VERIFY(cls_off == reinterpret_cast(reinterpret_cast(cls_off))); + SASSERT(cls_off == reinterpret_cast(reinterpret_cast(cls_off))); return reinterpret_cast(cls_off); -#endif } clause_offset clause_allocator::get_offset(clause const * cls) const { -#if 0 -// defined(_AMD64_) - size_t ptr = reinterpret_cast(cls); - - SASSERT((ptr & c_alignment_mask) == 0); - ptr &= 0xFFFFFFFF00000000ull; // Keep only high part - unsigned i = 0; - for (i = 0; i < m_num_segments; ++i) - if (m_segments[i] == ptr) - return static_cast(reinterpret_cast(cls)) + i; - SASSERT(i == m_num_segments); - SASSERT(i <= c_last_segment); - if (i == c_last_segment) { - m_last_seg_id2cls.setx(cls->id(), cls, 0); - return (cls->id() << c_cls_alignment) | c_last_segment; - } - else { - ++m_num_segments; - m_segments[i] = ptr; - return static_cast(reinterpret_cast(cls)) + i; - } -#else - VERIFY(cls == reinterpret_cast(reinterpret_cast(cls))); + SASSERT(cls == reinterpret_cast(reinterpret_cast(cls))); return reinterpret_cast(cls); -#endif } clause * clause_allocator::mk_clause(unsigned num_lits, literal const * lits, bool learned) { @@ -182,12 +147,6 @@ namespace sat { void clause_allocator::del_clause(clause * cls) { TRACE("sat_clause", tout << "delete: " << cls->id() << " " << *cls << "\n";); - if (cls->id() == 62805 && cls->capacity() == 29) { - std::cout << "delete 62805\n"; - for (literal l : *cls) { - std::cout << l << "\n"; - } - } m_id_gen.recycle(cls->id()); size_t size = clause::get_obj_size(cls->m_capacity); cls->~clause(); diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 08fff7adb..76f1a9ad3 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -139,15 +139,6 @@ namespace sat { class clause_allocator { small_object_allocator m_allocator; id_gen m_id_gen; -#if defined(_AMD64_) - static const unsigned c_cls_alignment = 3; - static const unsigned c_last_segment = (1ull << c_cls_alignment) - 1ull; - static const size_t c_alignment_mask = (1ull << c_cls_alignment) - 1ull; - mutable unsigned m_num_segments; - mutable size_t m_segments[c_last_segment]; - mutable svector m_aux_segments; - mutable ptr_vector m_last_seg_id2cls; -#endif public: clause_allocator(); clause * get_clause(clause_offset cls_off) const; From 0f4afc4536b09d4474d4e0b7b38e910233965005 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 Nov 2017 13:45:27 -0800 Subject: [PATCH 0337/1283] fix bug in contains function Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 417a86458..558151b61 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1519,7 +1519,7 @@ namespace z3 { return *this; } bool contains(T const& x) const { - for (auto y : *this) if (x == y) return true; + for (auto y : *this) if (eq(x, y)) return true; return false; } From 38e4fb307ce1527bb1732e386684ac24f7b600f9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 Nov 2017 00:00:06 -0800 Subject: [PATCH 0338/1283] add useful shorthands to Solver interface Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Params.cs | 30 ++++++++++------ src/api/dotnet/Solver.cs | 77 +++++++++++++++++++++++++++++++++++----- 2 files changed, 89 insertions(+), 18 deletions(-) diff --git a/src/api/dotnet/Params.cs b/src/api/dotnet/Params.cs index 23b037c78..8268fa69f 100644 --- a/src/api/dotnet/Params.cs +++ b/src/api/dotnet/Params.cs @@ -31,98 +31,108 @@ namespace Microsoft.Z3 /// /// Adds a parameter setting. /// - public void Add(Symbol name, bool value) + public Params Add(Symbol name, bool value) { Contract.Requires(name != null); Native.Z3_params_set_bool(Context.nCtx, NativeObject, name.NativeObject, (value) ? 1 : 0); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, uint value) + public Params Add(Symbol name, uint value) { Contract.Requires(name != null); Native.Z3_params_set_uint(Context.nCtx, NativeObject, name.NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, double value) + public Params Add(Symbol name, double value) { Contract.Requires(name != null); Native.Z3_params_set_double(Context.nCtx, NativeObject, name.NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, string value) + public Params Add(Symbol name, string value) { Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, Context.MkSymbol(value).NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(Symbol name, Symbol value) + public Params Add(Symbol name, Symbol value) { Contract.Requires(name != null); Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, name.NativeObject, value.NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, bool value) + public Params Add(string name, bool value) { Native.Z3_params_set_bool(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, (value) ? 1 : 0); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, uint value) + public Params Add(string name, uint value) { Native.Z3_params_set_uint(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, double value) + public Params Add(string name, double value) { Native.Z3_params_set_double(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, Symbol value) + public Params Add(string name, Symbol value) { Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value.NativeObject); + return this; } /// /// Adds a parameter setting. /// - public void Add(string name, string value) + public Params Add(string name, string value) { Contract.Requires(name != null); Contract.Requires(value != null); Native.Z3_params_set_symbol(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, Context.MkSymbol(value).NativeObject); + return this; } /// diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 4b8ff4cf6..568ac79bf 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -57,6 +57,48 @@ namespace Microsoft.Z3 } } + /// + /// Sets parameter on the solver + /// + public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } + /// + /// Sets parameter on the solver + /// + public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } + + /// /// Retrieves parameter descriptions for solver. /// @@ -140,11 +182,11 @@ namespace Microsoft.Z3 /// using the Boolean constants in ps. /// /// - /// This API is an alternative to with assumptions for extracting unsat cores. + /// This API is an alternative to with assumptions for extracting unsat cores. /// Both APIs can be used in the same solver. The unsat core will contain a combination /// of the Boolean variables provided using /// and the Boolean literals - /// provided using with assumptions. + /// provided using with assumptions. /// public void AssertAndTrack(BoolExpr[] constraints, BoolExpr[] ps) { @@ -165,11 +207,11 @@ namespace Microsoft.Z3 /// using the Boolean constant p. /// /// - /// This API is an alternative to with assumptions for extracting unsat cores. + /// This API is an alternative to with assumptions for extracting unsat cores. /// Both APIs can be used in the same solver. The unsat core will contain a combination /// of the Boolean variables provided using /// and the Boolean literals - /// provided using with assumptions. + /// provided using with assumptions. /// public void AssertAndTrack(BoolExpr constraint, BoolExpr p) { @@ -256,6 +298,25 @@ namespace Microsoft.Z3 return lboolToStatus(r); } + /// + /// Checks whether the assertions in the solver are consistent or not. + /// + /// + /// + /// + /// + /// + public Status Check(IEnumerable assumptions) + { + Z3_lbool r; + BoolExpr[] asms = assumptions.ToArray(); + if (asms.Length == 0) + r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); + else + r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)asms.Length, AST.ArrayToNative(asms)); + return lboolToStatus(r); + } + /// /// Retrieve fixed assignments to the set of variables in the form of consequences. /// Each consequence is an implication of the form @@ -284,10 +345,10 @@ namespace Microsoft.Z3 } /// - /// The model of the last Check. + /// The model of the last Check(params Expr[] assumptions). /// /// - /// The result is null if Check was not invoked before, + /// The result is null if Check(params Expr[] assumptions) was not invoked before, /// if its results was not SATISFIABLE, or if model production is not enabled. /// public Model Model @@ -303,10 +364,10 @@ namespace Microsoft.Z3 } /// - /// The proof of the last Check. + /// The proof of the last Check(params Expr[] assumptions). /// /// - /// The result is null if Check was not invoked before, + /// The result is null if Check(params Expr[] assumptions) was not invoked before, /// if its results was not UNSATISFIABLE, or if proof production is disabled. /// public Expr Proof From f7e14b32839bf76e470bcc775d36bc8fc121c134 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 14 Nov 2017 18:19:21 -0800 Subject: [PATCH 0339/1283] add global autarky option, update translation of solvers to retain vsids, remove stale code Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 1 + src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_lookahead.cpp | 77 ++++++++++++++++++++++++++------------- src/sat/sat_lookahead.h | 12 ++---- src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 41 +++++++++------------ src/sat/sat_solver.h | 3 -- 8 files changed, 76 insertions(+), 61 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 558151b61..06c12741c 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2117,6 +2117,7 @@ namespace z3 { return expr(ctx(), Z3_mk_and(ctx(), n, args.ptr())); } } + std::string dimacs() const { return std::string(Z3_goal_to_dimacs_string(ctx(), m_goal)); } friend std::ostream & operator<<(std::ostream & out, goal const & g); }; inline std::ostream & operator<<(std::ostream & out, goal const & g) { out << Z3_goal_to_string(g.ctx(), g); return out; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 4dce25b99..e062841b7 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -112,6 +112,7 @@ namespace sat { m_lookahead_cube_fraction = p.lookahead_cube_fraction(); m_lookahead_cube_cutoff = p.lookahead_cube_cutoff(); + m_lookahead_global_autarky = p.lookahead_global_autarky(); // These parameters are not exposed m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 6de1261ad..4fc1f4e7e 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -87,6 +87,7 @@ namespace sat { unsigned m_lookahead_cube_cutoff; double m_lookahead_cube_fraction; reward_t m_lookahead_reward; + bool m_lookahead_global_autarky; bool m_incremental; unsigned m_simplify_mult1; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 27d174653..d79aeffde 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -233,6 +233,7 @@ namespace sat { if (is_sat()) { return false; } + std::cout << "include newbies\n"; } SASSERT(!m_candidates.empty()); // cut number of candidates down to max_num_cand. @@ -314,12 +315,19 @@ namespace sat { double lookahead::init_candidates(unsigned level, bool newbies) { m_candidates.reset(); double sum = 0; + unsigned skip_candidates = 0; + bool autarky = get_config().m_lookahead_global_autarky; for (bool_var x : m_freevars) { SASSERT(is_undef(x)); if (!m_select_lookahead_vars.empty()) { if (m_select_lookahead_vars.contains(x)) { - m_candidates.push_back(candidate(x, m_rating[x])); - sum += m_rating[x]; + if (!autarky || newbies || in_reduced_clause(x)) { + m_candidates.push_back(candidate(x, m_rating[x])); + sum += m_rating[x]; + } + else { + skip_candidates++; + } } } else if (newbies || active_prefix(x)) { @@ -328,6 +336,9 @@ namespace sat { } } TRACE("sat", display_candidates(tout << "sum: " << sum << "\n");); + if (skip_candidates > 0) { + IF_VERBOSE(0, verbose_stream() << "candidates: " << m_candidates.size() << " skip: " << skip_candidates << "\n";); + } return sum; } @@ -1294,8 +1305,7 @@ namespace sat { unsigned idx = l.index(); unsigned sz = m_ternary_count[idx]--; auto& tv = m_ternary[idx]; - for (unsigned i = sz; i > 0; ) { - --i; + for (unsigned i = sz; i-- > 0; ) { binary const& b = tv[i]; if (b.m_u == u && b.m_v == v) { std::swap(tv[i], tv[sz-1]); @@ -1769,10 +1779,6 @@ namespace sat { 0 : get_lookahead_reward(p)); } - bool lookahead::check_autarky(literal l, unsigned level) { - return false; - } - void lookahead::update_lookahead_reward(literal l, unsigned level) { if (m_lookahead_reward != 0) { inc_lookahead_reward(l, m_lookahead_reward); @@ -1859,6 +1865,43 @@ namespace sat { return m_trail.size() - old_sz; } + /** + \brief check if literal occurs in a non-tautological reduced clause. + */ + bool lookahead::in_reduced_clause(bool_var v) { + return + in_reduced_clause(literal(v, false)) || + in_reduced_clause(literal(v, true)); + } + + bool lookahead::in_reduced_clause(literal lit) { + if (lit == null_literal) return true; + if (m_trail_lim.empty()) return true; + unsigned sz = m_nary_count[lit.index()]; + for (nary* n : m_nary[lit.index()]) { + if (sz-- == 0) break; + if (!n->is_reduced()) continue; + bool has_true = false; + for (literal l : *n) { + if (is_true(l)) { + has_true = true; + break; + } + } + if (!has_true) return true; + } + + auto const& tv = m_ternary[lit.index()]; + sz = tv.size(); + unsigned i = m_ternary_count[lit.index()]; + for (; i < sz; ++i) { + binary const& b = tv[i]; + if (!is_true(b.m_u) && !is_true(b.m_v)) + return true; + } + return false; + } + void lookahead::validate_assign(literal l) { if (m_s.m_config.m_drat && m_search_mode == lookahead_mode::searching) { m_assumptions.push_back(l); @@ -1959,20 +2002,6 @@ namespace sat { return true; } - lbool lookahead::cube() { - literal_vector lits; - bool_var_vector vars; - for (bool_var v : m_freevars) vars.push_back(v); - while (true) { - lbool result = cube(vars, lits, UINT_MAX); - if (lits.empty() || result != l_undef) { - return l_undef; - } - display_cube(std::cout, lits); - } - return l_undef; - } - lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level) { scoped_ext _scoped_ext(*this); lits.reset(); @@ -2330,13 +2359,9 @@ namespace sat { // TBD: keep count of ternary and >3-ary clauses. st.update("lh add binary", m_stats.m_add_binary); st.update("lh del binary", m_stats.m_del_binary); - st.update("lh add ternary", m_stats.m_add_ternary); - st.update("lh del ternary", m_stats.m_del_ternary); st.update("lh propagations", m_stats.m_propagations); st.update("lh decisions", m_stats.m_decisions); st.update("lh windfalls", m_stats.m_windfall_binaries); - st.update("lh autarky propagations", m_stats.m_autarky_propagations); - st.update("lh autarky equivalences", m_stats.m_autarky_equivalences); st.update("lh double lookahead propagations", m_stats.m_double_lookahead_propagations); st.update("lh double lookahead rounds", m_stats.m_double_lookahead_rounds); } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 6cf75937f..9f110b1a0 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -115,12 +115,8 @@ namespace sat { unsigned m_propagations; unsigned m_add_binary; unsigned m_del_binary; - unsigned m_add_ternary; - unsigned m_del_ternary; unsigned m_decisions; unsigned m_windfall_binaries; - unsigned m_autarky_propagations; - unsigned m_autarky_equivalences; unsigned m_double_lookahead_propagations; unsigned m_double_lookahead_rounds; stats() { reset(); } @@ -151,9 +147,10 @@ namespace sat { } unsigned size() const { return m_size; } unsigned dec_size() { SASSERT(m_size > 0); return --m_size; } - void inc_size() { SASSERT(m_size < num_lits()); ++m_size; } + void inc_size() { SASSERT(is_reduced()); ++m_size; } literal get_head() const { return m_head; } void set_head(literal l) { m_head = l; } + bool is_reduced() const { return m_size < num_lits(); } literal operator[](unsigned i) { SASSERT(i < num_lits()); return m_literals[i]; } literal const* begin() const { return m_literals; } @@ -497,7 +494,6 @@ namespace sat { double get_lookahead_reward(literal l) const { return m_lits[l.index()].m_lookahead_reward; } void reset_lookahead_reward(literal l); - bool check_autarky(literal l, unsigned level); void update_lookahead_reward(literal l, unsigned level); bool dl_enabled(literal l) const { return m_lits[l.index()].m_double_lookahead != m_istamp_id; } void dl_disable(literal l) { m_lits[l.index()].m_double_lookahead = m_istamp_id; } @@ -510,6 +506,8 @@ namespace sat { unsigned scope_lvl() const { return m_trail_lim.size(); } + bool in_reduced_clause(literal l); + bool in_reduced_clause(bool_var v); void validate_assign(literal l); void assign(literal l); void propagated(literal l); @@ -565,8 +563,6 @@ namespace sat { Otherwise, cut-fraction gives an adaptive threshold for creating cuts. */ - lbool cube(); - lbool cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level); literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 7b33ee8e7..bae1d0c11 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -41,6 +41,7 @@ def_module_params('sat', ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), + ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'), ('dimacs.inprocess.display', BOOL, False, 'display SAT instance in DIMACS format if unsolved after inprocess.max inprocessing passes'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index b0b5d8495..42b10d5c8 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -98,7 +98,12 @@ namespace sat { } m_phase[v] = src.m_phase[v]; m_prev_phase[v] = src.m_prev_phase[v]; - // m_activity[v] = src.m_activity[v], but then update case_split_queue ? + +#if 1 + // inherit activity: + m_activity[v] = src.m_activity[v]; + m_case_split_queue.activity_changed_eh(v, false); +#endif } } @@ -115,7 +120,7 @@ namespace sat { assign(src.m_trail[i], justification()); } - // copy binary clauses that are unblocked. + // copy binary clauses { unsigned sz = src.m_watches.size(); for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { @@ -123,13 +128,21 @@ namespace sat { if (src.was_eliminated(l.var())) continue; watch_list const & wlist = src.m_watches[l_idx]; for (auto & wi : wlist) { - if (!wi.is_binary_unblocked_clause()) + if (!wi.is_binary_clause()) continue; literal l2 = wi.get_literal(); if (l.index() > l2.index() || src.was_eliminated(l2.var())) continue; - mk_clause_core(l, l2); + + watched w1(l2, wi.is_learned()); + watched w2(l, wi.is_learned()); + if (wi.is_blocked()) { + w1.set_blocked(); + w2.set_blocked(); + } + m_watches[(~l).index()].push_back(w1); + m_watches[(~l2).index()].push_back(w2); } } } @@ -868,12 +881,6 @@ namespace sat { if (m_config.m_lookahead_search && num_lits == 0) { return lookahead_search(); } -#if 0 - // deprecated - if (m_config.m_lookahead_cube && num_lits == 0) { - return lookahead_cube(); - } -#endif if (m_config.m_local_search) { return do_local_search(num_lits, lits); @@ -976,20 +983,6 @@ namespace sat { return r; } - lbool solver::lookahead_cube() { - lookahead lh(*this); - lbool r = l_undef; - try { - r = lh.cube(); - } - catch (z3_exception&) { - lh.collect_statistics(m_aux_stats); - throw; - } - lh.collect_statistics(m_aux_stats); - return r; - } - lbool solver::lookahead_search() { lookahead lh(*this); lbool r = l_undef; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index cb8c2b763..45f91e7a8 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -180,7 +180,6 @@ namespace sat { friend class lookahead; friend class local_search; friend struct mk_stat; - friend class ccc; friend class elim_vars; friend class scoped_detach; public: @@ -395,9 +394,7 @@ namespace sat { void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); lbool lookahead_search(); - lbool lookahead_cube(); lbool do_local_search(unsigned num_lits, literal const* lits); - lbool do_ccc(); // ----------------------- // From d8a2e9d008791cab0e903ee62009e4f658316e8b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 15 Nov 2017 15:57:07 -0800 Subject: [PATCH 0340/1283] initialize glue in constructor to ensure it gets set Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 13 ++++--------- src/sat/sat_clause.cpp | 4 +++- src/sat/sat_lookahead.h | 4 +++- src/sat/sat_solver.cpp | 7 ++----- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index a6c4ab8fc..ba591083f 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1514,21 +1514,16 @@ void ast_manager::compress_ids() { ptr_vector asts; m_expr_id_gen.cleanup(); m_decl_id_gen.cleanup(c_first_decl_id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * n = *it; + for (ast* n : m_ast_table) { if (is_decl(n)) n->m_id = m_decl_id_gen.mk(); else n->m_id = m_expr_id_gen.mk(); asts.push_back(n); - } + } m_ast_table.finalize(); - ptr_vector::iterator it2 = asts.begin(); - ptr_vector::iterator end2 = asts.end(); - for (; it2 != end2; ++it2) - m_ast_table.insert(*it2); + for (ast* a : asts) + m_ast_table.insert(a); } void ast_manager::raise_exception(char const * msg) { diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 90d542a14..8b7a4ca46 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -33,7 +33,9 @@ namespace sat { m_used(false), m_frozen(false), m_reinit_stack(false), - m_inact_rounds(0) { + m_inact_rounds(0), + m_glue(255), + m_psm(255) { memcpy(m_lits, lits, sizeof(literal) * sz); mark_strengthened(); SASSERT(check_approx()); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 9f110b1a0..e65e7021a 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -84,9 +84,11 @@ namespace sat { double m_cube_fraction; config() { - m_max_hlevel = 50; + memset(this, sizeof(*this), 0); + m_dl_success = 0.8; m_alpha = 3.5; m_max_score = 20.0; + m_max_hlevel = 50; m_min_cutoff = 30; m_preselect = false; m_level_cand = 600; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 42b10d5c8..2980fffeb 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1762,11 +1762,8 @@ namespace sat { \brief Compute the psm of all learned clauses. */ void solver::save_psm() { - clause_vector::iterator it = m_learned.begin(); - clause_vector::iterator end = m_learned.end(); - for (; it != end; ++it) { - clause & c = *(*it); - c.set_psm(psm(c)); + for (clause* cp : m_learned) { + cp->set_psm(psm(*cp)); } } From 53e36c9cf90cdca8ab9d8e1ac9c726975aa7871b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 Nov 2017 09:29:44 -0800 Subject: [PATCH 0341/1283] re-organize iterators Signed-off-by: Nikolaj Bjorner --- src/ast/ast_translation.cpp | 2 +- src/sat/sat_solver.cpp | 154 +++++++++++++----------------------- 2 files changed, 57 insertions(+), 99 deletions(-) diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index 0599ec91d..e6be3da98 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -227,7 +227,7 @@ ast * ast_translation::process(ast const * _n) { while (fr.m_idx <= num) { expr * arg = to_app(n)->get_arg(fr.m_idx - 1); fr.m_idx++; - if (!visit(arg)) + if (!visit(arg)) goto loop; } func_decl * new_f = to_func_decl(m_result_stack[fr.m_rpos]); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2980fffeb..e4d239605 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2559,10 +2559,8 @@ namespace sat { */ void solver::updt_lemma_lvl_set() { m_lvl_set.reset(); - literal_vector::const_iterator it = m_lemma.begin(); - literal_vector::const_iterator end = m_lemma.end(); - for(; it != end; ++it) - m_lvl_set.insert(lvl(*it)); + for (literal l : m_lemma) + m_lvl_set.insert(lvl(l)); } /** @@ -2695,25 +2693,23 @@ namespace sat { continue; // literal was eliminated // first use watch lists watch_list const & wlist = get_wlist(~l); - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { + for (watched const& w : wlist) { // In this for-loop, the conditions l0 != ~l2 and l0 != ~l3 // are not really needed if the solver does not miss unit propagations. // However, we add them anyway because we don't want to rely on this // property of the propagator. // For example, if this property is relaxed in the future, then the code // without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP - if (it->is_binary_clause()) { - literal l2 = it->get_literal(); + if (w.is_binary_clause()) { + literal l2 = w.get_literal(); if (is_marked_lit(~l2) && l0 != ~l2) { // eliminate ~l2 from lemma because we have the clause l \/ l2 unmark_lit(~l2); } } - else if (it->is_ternary_clause()) { - literal l2 = it->get_literal1(); - literal l3 = it->get_literal2(); + else if (w.is_ternary_clause()) { + literal l2 = w.get_literal1(); + literal l3 = w.get_literal2(); if (is_marked_lit(l2) && is_marked_lit(~l3) && l0 != ~l3) { // eliminate ~l3 from lemma because we have the clause l \/ l2 \/ l3 unmark_lit(~l3); @@ -2956,16 +2952,10 @@ namespace sat { } bool_var solver::max_var(clause_vector& clauses, bool_var v) { - for (unsigned i = 0; i < clauses.size(); ++i) { - clause & c = *(clauses[i]); - literal* it = c.begin(); - literal * end = c.end(); - for (; it != end; ++it) { - if (it->var() > v) { - v = it->var(); - } - } - } + for (clause* cp : clauses) + for (literal l : *cp) + if (l.var() > v) + v = l.var(); return v; } @@ -2976,8 +2966,8 @@ namespace sat { w = max_var(true, w); w = max_var(false, w); v = m_mc.max_var(w); - for (unsigned i = 0; i < m_trail.size(); ++i) { - if (m_trail[i].var() > w) w = m_trail[i].var(); + for (literal lit : m_trail) { + if (lit.var() > w) w = lit.var(); } v = std::max(v, w + 1); } @@ -3087,10 +3077,8 @@ namespace sat { void solver::rescale_activity() { SASSERT(m_config.m_branching_heuristic == BH_VSIDS); - svector::iterator it = m_activity.begin(); - svector::iterator end = m_activity.end(); - for (; it != end; ++it) { - *it >>= 14; + for (unsigned& act : m_activity) { + act >>= 14; } m_activity_inc >>= 14; } @@ -3171,10 +3159,8 @@ namespace sat { } void solver::display_units(std::ostream & out) const { - unsigned end = m_trail.size(); // init_trail_size(); unsigned level = 0; - for (unsigned i = 0; i < end; i++) { - literal lit = m_trail[i]; + for (literal lit : m_trail) { if (lvl(lit) > level) { level = lvl(lit); out << level << ": "; @@ -3185,8 +3171,6 @@ namespace sat { out << lit << " "; display_justification(out, m_justification[lit.var()]) << "\n"; } - //if (end != 0) - // out << "\n"; } void solver::display(std::ostream & out) const { @@ -3226,8 +3210,8 @@ namespace sat { void solver::display_dimacs(std::ostream & out) const { out << "p cnf " << num_vars() << " " << num_clauses() << "\n"; - for (unsigned i = 0; i < m_trail.size(); i++) { - out << dimacs_lit(m_trail[i]) << " 0\n"; + for (literal lit : m_trail) { + out << dimacs_lit(lit) << " 0\n"; } unsigned l_idx = 0; for (auto const& wlist : m_watches) { @@ -3259,8 +3243,8 @@ namespace sat { out << "p wcnf " << num_vars() << " " << num_clauses() + sz << " " << max_weight << "\n"; out << "c soft " << sz << "\n"; - for (unsigned i = 0; i < m_trail.size(); i++) { - out << max_weight << " " << dimacs_lit(m_trail[i]) << " 0\n"; + for (literal lit : m_trail) { + out << max_weight << " " << dimacs_lit(lit) << " 0\n"; } unsigned l_idx = 0; for (watch_list const& wlist : m_watches) { @@ -3276,7 +3260,6 @@ namespace sat { clause_vector const & cs = *(vs[i]); for (clause const* cp : cs) { clause const & c = *cp; - unsigned clsz = c.size(); out << max_weight << " "; for (literal l : c) out << dimacs_lit(l) << " "; @@ -3291,11 +3274,9 @@ namespace sat { void solver::display_watches(std::ostream & out) const { - vector::const_iterator it = m_watches.begin(); - vector::const_iterator end = m_watches.end(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - watch_list const & wlist = *it; - literal l = to_literal(l_idx); + unsigned l_idx = 0; + for (watch_list const& wlist : m_watches) { + literal l = to_literal(l_idx++); out << l << ": "; sat::display_watch_list(out, m_cls_allocator, wlist); out << "\n"; @@ -3331,24 +3312,20 @@ namespace sat { \brief Return true, if all literals in c are assigned to false. */ bool solver::is_empty(clause const & c) const { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - if (value(c[i]) != l_false) + for (literal lit : c) + if (value(lit) != l_false) return false; - } return true; } bool solver::check_missed_propagation(clause_vector const & cs) const { - clause_vector::const_iterator it = cs.begin(); - clause_vector::const_iterator end = cs.end(); - for (; it != end; ++it) { - clause const & c = *(*it); + for (clause* cp : cs) { + clause const & c = *cp; if (c.frozen()) continue; if (is_empty(c) || is_unit(c)) { TRACE("sat_missed_prop", tout << "missed_propagation: " << c << "\n"; - for (unsigned i = 0; i < c.size(); i++) tout << c[i] << ": " << value(c[i]) << "\n";); + for (literal l : c) tout << l << ": " << value(l) << "\n";); UNREACHABLE(); } SASSERT(!is_empty(c)); @@ -3411,9 +3388,9 @@ namespace sat { m_binary_clause_graph.reset(); collect_bin_clauses(m_user_bin_clauses, true); hashtable, default_eq > seen_bc; - for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) { - literal l1 = m_user_bin_clauses[i].first; - literal l2 = m_user_bin_clauses[i].second; + for (auto const& b : m_user_bin_clauses) { + literal l1 = b.first; + literal l2 = b.second; literal_pair p(l1, l2); if (!seen_bc.contains(p)) { seen_bc.insert(p); @@ -3426,8 +3403,8 @@ namespace sat { // m_ext->find_mutexes(_lits, mutexes); } unsigned_vector ps; - for (unsigned i = 0; i < _lits.size(); ++i) { - ps.push_back(_lits[i].index()); + for (literal lit : _lits) { + ps.push_back(lit.index()); } mc.cliques(ps, _mutexes); for (auto const& mux : _mutexes) { @@ -3471,10 +3448,9 @@ namespace sat { } static void brute_force_consequences(sat::solver& s, sat::literal_vector const& asms, sat::literal_vector const& gamma, vector& conseq) { - for (unsigned i = 0; i < gamma.size(); ++i) { - sat::literal nlit = ~gamma[i]; + for (literal lit : gamma) { sat::literal_vector asms1(asms); - asms1.push_back(nlit); + asms1.push_back(~lit); lbool r = s.check(asms1.size(), asms1.c_ptr()); if (r == l_false) { conseq.push_back(s.get_core()); @@ -3484,8 +3460,8 @@ namespace sat { static lbool core_chunking(sat::solver& s, model const& m, sat::bool_var_vector const& vars, sat::literal_vector const& asms, vector& conseq, unsigned K) { sat::literal_vector lambda; - for (unsigned i = 0; i < vars.size(); i++) { - lambda.push_back(sat::literal(vars[i], m[vars[i]] == l_false)); + for (bool_var v : vars) { + lambda.push_back(sat::literal(v, m[v] == l_false)); } while (!lambda.empty()) { IF_VERBOSE(1, verbose_stream() << "(sat-backbone-core " << lambda.size() << " " << conseq.size() << ")\n";); @@ -3582,9 +3558,8 @@ namespace sat { s |= m_antecedents.find(m_core[i].var()); } m_core.reset(); - index_set::iterator it = s.begin(), end = s.end(); - for (; it != end; ++it) { - m_core.push_back(to_literal(*it)); + for (unsigned idx : s) { + m_core.push_back(to_literal(idx)); } TRACE("sat", tout << m_core << "\n";); } @@ -3690,13 +3665,11 @@ namespace sat { propagate(false); ++num_iterations; checkpoint(); - literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); unsigned num_resolves = 0; unsigned num_fixed = 0; unsigned num_assigned = 0; lbool is_sat = l_true; - for (; it != end; ++it) { - literal lit = *it; + for (literal lit : unfixed_lits) { if (value(lit) != l_undef) { ++num_fixed; if (lvl(lit) <= 1 && value(lit) == l_true) { @@ -3765,9 +3738,7 @@ namespace sat { void solver::delete_unfixed(literal_set& unfixed_lits, bool_var_set& unfixed_vars) { literal_set to_keep; - literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); - for (; it != end; ++it) { - literal lit = *it; + for (literal lit : unfixed_lits) { if (value(lit) == l_true) { to_keep.insert(lit); } @@ -3780,9 +3751,7 @@ namespace sat { void solver::update_unfixed_literals(literal_set& unfixed_lits, bool_var_set& unfixed_vars) { literal_vector to_delete; - literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); - for (; it != end; ++it) { - literal lit = *it; + for (literal lit : unfixed_lits) { if (!unfixed_vars.contains(lit.var())) { to_delete.push_back(lit); } @@ -3803,9 +3772,7 @@ namespace sat { } void solver::extract_fixed_consequences(literal_set const& unfixed_lits, literal_set const& assumptions, bool_var_set& unfixed_vars, vector& conseq) { - literal_set::iterator it = unfixed_lits.begin(), end = unfixed_lits.end(); - for (; it != end; ++it) { - literal lit = *it; + for (literal lit: unfixed_lits) { TRACE("sat", tout << "extract: " << lit << " " << value(lit) << " " << lvl(lit) << "\n";); if (lvl(lit) <= 1 && value(lit) == l_true) { @@ -3878,10 +3845,8 @@ namespace sat { } std::ostream& solver::display_index_set(std::ostream& out, index_set const& s) const { - index_set::iterator it = s.begin(); - index_set::iterator end = s.end(); - for (; it != end; ++it) { - out << to_literal(*it) << " "; + for (unsigned idx : s) { + out << to_literal(idx) << " "; } return out; } @@ -3906,9 +3871,8 @@ namespace sat { if (unfixed.contains(lit.var())) { literal_vector cons; cons.push_back(lit); - index_set::iterator it = s.begin(), end = s.end(); - for (; it != end; ++it) { - cons.push_back(to_literal(*it)); + for (unsigned idx : s) { + cons.push_back(to_literal(idx)); } unfixed.remove(lit.var()); conseq.push_back(cons); @@ -3936,17 +3900,13 @@ namespace sat { unsigned num_bin = 0; unsigned num_ext = 0; unsigned num_lits = 0; - vector::const_iterator it = m_watches.begin(); - vector::const_iterator end = m_watches.end(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - literal l = ~to_literal(l_idx); - watch_list const & wlist = *it; - watch_list::const_iterator it2 = wlist.begin(); - watch_list::const_iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - switch (it2->get_kind()) { + unsigned l_idx = 0; + for (watch_list const& wlist : m_watches) { + literal l = ~to_literal(l_idx++); + for (watched const& w : wlist) { + switch (w.get_kind()) { case watched::BINARY: - if (l.index() < it2->get_literal().index()) { + if (l.index() < w.get_literal().index()) { num_lits += 2; num_bin++; } @@ -3969,10 +3929,8 @@ namespace sat { clause_vector const * vs[2] = { &m_clauses, &m_learned }; for (unsigned i = 0; i < 2; i++) { clause_vector const & cs = *(vs[i]); - clause_vector::const_iterator it = cs.begin(); - clause_vector::const_iterator end = cs.end(); - for (; it != end; ++it) { - clause & c = *(*it); + for (clause* cp : cs) { + clause & c = *cp; if (c.size() == 3) num_ter++; else From 0d15b6abb70e8440e14f2e251dfc69f2d5c1d840 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 17 Nov 2017 14:51:13 -0800 Subject: [PATCH 0342/1283] add stubs for converting assertions, consolidate filter_model_converter Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 2 +- src/muz/base/dl_rule.cpp | 6 +- src/muz/fp/horn_tactic.cpp | 6 +- src/muz/spacer/spacer_itp_solver.h | 4 +- src/muz/spacer/spacer_virtual_solver.cpp | 4 +- src/muz/spacer/spacer_virtual_solver.h | 2 +- src/muz/transforms/dl_mk_bit_blast.cpp | 6 +- src/opt/maxsmt.cpp | 2 +- src/opt/maxsmt.h | 1 - src/opt/opt_context.cpp | 12 +-- src/opt/opt_context.h | 8 +- src/opt/opt_solver.cpp | 4 +- src/opt/opt_solver.h | 8 +- src/opt/sortmax.cpp | 8 +- src/qe/qe_tactic.cpp | 1 - src/qe/qsat.cpp | 10 +-- src/qe/qsat.h | 6 +- src/sat/sat_solver/inc_sat_solver.cpp | 9 +-- src/sat/tactic/goal2sat.cpp | 10 +-- src/sat/tactic/sat_tactic.cpp | 1 - src/smt/smt_solver.cpp | 4 +- src/smt/tactic/smt_tactic.cpp | 4 +- src/smt/theory_arith.h | 2 +- src/smt/theory_arith_aux.h | 6 +- src/smt/theory_dense_diff_logic.h | 2 +- src/smt/theory_dense_diff_logic_def.h | 2 +- src/smt/theory_diff_logic.h | 2 +- src/smt/theory_diff_logic_def.h | 2 +- src/smt/theory_lra.cpp | 8 +- src/smt/theory_lra.h | 2 +- src/smt/theory_opt.h | 2 +- src/smt/theory_wmaxsat.cpp | 4 +- src/smt/theory_wmaxsat.h | 6 +- src/solver/combined_solver.cpp | 4 +- src/solver/solver.cpp | 27 +++++-- src/solver/solver.h | 15 +++- src/solver/solver2tactic.cpp | 10 +-- src/solver/solver2tactic.h | 4 +- src/solver/solver_na2as.cpp | 6 +- src/solver/solver_na2as.h | 4 +- src/solver/solver_pool.cpp | 4 +- src/solver/tactic2solver.cpp | 4 +- src/tactic/CMakeLists.txt | 1 - src/tactic/arith/card2bv_tactic.cpp | 6 +- src/tactic/arith/degree_shift_tactic.cpp | 7 +- src/tactic/arith/lia2pb_tactic.cpp | 8 +- src/tactic/arith/nla2bv_tactic.cpp | 14 ++-- src/tactic/arith/normalize_bounds_tactic.cpp | 8 +- src/tactic/arith/pb2bv_tactic.cpp | 12 ++- src/tactic/arith/purify_arith_tactic.cpp | 14 ++-- src/tactic/arith/recover_01_tactic.cpp | 8 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 12 +-- src/tactic/bv/bvarray2uf_rewriter.cpp | 6 +- src/tactic/bv/bvarray2uf_rewriter.h | 8 +- src/tactic/bv/bvarray2uf_tactic.cpp | 4 +- src/tactic/bv/dt2bv_tactic.cpp | 8 +- src/tactic/bv/elim_small_bv_tactic.cpp | 4 +- src/tactic/core/blast_term_ite_tactic.cpp | 1 - src/tactic/core/elim_term_ite_tactic.cpp | 8 +- src/tactic/core/elim_uncnstr_tactic.cpp | 9 +-- src/tactic/core/nnf_tactic.cpp | 6 +- src/tactic/core/occf_tactic.cpp | 8 +- src/tactic/core/reduce_args_tactic.cpp | 6 +- src/tactic/core/tseitin_cnf_tactic.cpp | 8 +- src/tactic/extension_model_converter.h | 2 + src/tactic/filter_model_converter.cpp | 74 ------------------- src/tactic/filter_model_converter.h | 56 -------------- src/tactic/generic_model_converter.cpp | 4 + src/tactic/generic_model_converter.h | 4 + src/tactic/model_converter.h | 9 ++- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 12 +-- .../portfolio/bounded_int2bv_solver.cpp | 10 +-- src/tactic/portfolio/enum2bv_solver.cpp | 8 +- src/tactic/portfolio/parallel_tactic.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 14 ++-- src/tactic/sine_filter.cpp | 5 +- 76 files changed, 244 insertions(+), 356 deletions(-) delete mode 100644 src/tactic/filter_model_converter.cpp delete mode 100644 src/tactic/filter_model_converter.h diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 06c12741c..a2937cb8e 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1883,7 +1883,7 @@ namespace z3 { bool is_uint(unsigned i) const { Z3_bool r = Z3_stats_is_uint(ctx(), m_stats, i); check_error(); return r != 0; } bool is_double(unsigned i) const { Z3_bool r = Z3_stats_is_double(ctx(), m_stats, i); check_error(); return r != 0; } unsigned uint_value(unsigned i) const { unsigned r = Z3_stats_get_uint_value(ctx(), m_stats, i); check_error(); return r; } - double double_value(unsigned i) const { double r = Z3_stats_get_double_value(ctx(), m_stats, i); check_error(); return r; } + double double_value(unsigned i) const { double r = Z3_stats_get_double_value(ctx(), m_stats, i); check_error(); return r; } friend std::ostream & operator<<(std::ostream & out, stats const & s); }; inline std::ostream & operator<<(std::ostream & out, stats const & s) { out << Z3_stats_to_string(s.ctx(), s); return out; } diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 4f832c4c9..c188426f0 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -41,7 +41,7 @@ Revision History: #include "ast/rewriter/expr_replacer.h" #include "ast/rewriter/bool_rewriter.h" #include "ast/rewriter/expr_safe_replace.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/scoped_proof.h" #include "ast/datatype_decl_plugin.h" #include "ast/ast_util.h" @@ -326,8 +326,8 @@ namespace datalog { rules.set_output_predicate(qpred); if (m_ctx.get_model_converter()) { - filter_model_converter* mc = alloc(filter_model_converter, m); - mc->insert(qpred); + generic_model_converter* mc = alloc(generic_model_converter, m); + mc->hide(qpred); m_ctx.add_model_converter(mc); } diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 5db57a12c..ded33bb0d 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -25,7 +25,7 @@ Revision History: #include "ast/rewriter/expr_replacer.h" #include "muz/base/dl_rule_transformer.h" #include "muz/transforms/dl_mk_slice.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "muz/transforms/dl_transforms.h" #include "muz/base/fixedpoint_params.hpp" #include "ast/ast_util.h" @@ -229,8 +229,8 @@ class horn_tactic : public tactic { } queries.reset(); queries.push_back(q); - filter_model_converter* mc1 = alloc(filter_model_converter, m); - mc1->insert(to_app(q)->get_decl()); + generic_model_converter* mc1 = alloc(generic_model_converter, m); + mc1->hide(q); mc = mc1; } SASSERT(queries.size() == 1); diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index ab3b94894..84469f490 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -112,10 +112,10 @@ public: {m_solver.collect_param_descrs(r);} virtual void set_produce_models(bool f) {m_solver.set_produce_models(f);} - virtual void assert_expr(expr *t) + virtual void assert_expr_core(expr *t) {m_solver.assert_expr(t);} - virtual void assert_expr(expr *t, expr *a) + virtual void assert_expr_core(expr *t, expr *a) {NOT_IMPLEMENTED_YET();} virtual void assert_lemma(expr* e) { NOT_IMPLEMENTED_YET(); } virtual expr_ref lookahead(const expr_ref_vector &,const expr_ref_vector &) { return expr_ref(m.mk_true(), m); } diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 938e8cb94..0c3adbbbd 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -50,7 +50,7 @@ virtual_solver::virtual_solver(virtual_solver_factory &factory, // -- change m_context, but will add m_pred to // -- the private field solver_na2as::m_assumptions if (m_virtual) - { solver_na2as::assert_expr(m.mk_true(), m_pred); } + { solver_na2as::assert_expr_core(m.mk_true(), m_pred); } } virtual_solver::~virtual_solver() @@ -210,7 +210,7 @@ void virtual_solver::get_unsat_core(ptr_vector &r) } } -void virtual_solver::assert_expr(expr *e) +void virtual_solver::assert_expr_core(expr *e) { SASSERT(!m_pushed || get_scope_level() > 0); if (m.is_true(e)) { return; } diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 3b256f297..946df95ad 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -78,7 +78,7 @@ public: } virtual void get_unsat_core(ptr_vector &r); - virtual void assert_expr(expr *e); + virtual void assert_expr_core(expr *e); virtual void collect_statistics(statistics &st) const {} virtual void get_model_core(model_ref &m) {m_context.get_model(m);} virtual proof* get_proof(); diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 924b12eda..7f3ae43f3 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -22,7 +22,7 @@ Revision History: #include "ast/rewriter/rewriter_def.h" #include "ast/ast_pp.h" #include "ast/rewriter/expr_safe_replace.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "muz/transforms/dl_mk_interp_tail_simplifier.h" #include "muz/base/fixedpoint_params.hpp" #include "ast/scoped_proof.h" @@ -299,12 +299,12 @@ namespace datalog { } if (m_context.get_model_converter()) { - filter_model_converter* fmc = alloc(filter_model_converter, m); + generic_model_converter* fmc = alloc(generic_model_converter, m); bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); func_decl_ref_vector const& old_funcs = m_rewriter.m_cfg.old_funcs(); func_decl_ref_vector const& new_funcs = m_rewriter.m_cfg.new_funcs(); for (unsigned i = 0; i < old_funcs.size(); ++i) { - fmc->insert(new_funcs[i]); + fmc->hide(new_funcs[i]); bvmc->insert(old_funcs[i], new_funcs[i]); } m_context.add_model_converter(concat(bvmc, fmc)); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 8df6c04a6..25616b00f 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -105,7 +105,7 @@ namespace opt { app* maxsmt_solver_base::mk_fresh_bool(char const* name) { app* result = m.mk_fresh_const(name, m.mk_bool_sort()); - m_c.fm().insert(result->get_decl()); + m_c.fm().hide(result); return result; } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 0541a9a88..636afcddd 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -22,7 +22,6 @@ Notes: #include "ast/ast.h" #include "util/params.h" #include "solver/solver.h" -#include "tactic/filter_model_converter.h" #include "util/statistics.h" #include "smt/smt_context.h" #include "smt/smt_theory.h" diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 045dcafd4..2ab6abd79 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -40,7 +40,7 @@ Notes: #include "ast/bv_decl_plugin.h" #include "ast/pb_decl_plugin.h" #include "ast/ast_smt_pp.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/ast_pp_util.h" #include "qe/qsat.h" @@ -1021,7 +1021,7 @@ namespace opt { } void context::purify(app_ref& term) { - filter_model_converter_ref fm; + generic_model_converter_ref fm; if (m_arith.is_add(term)) { expr_ref_vector args(m); unsigned sz = term->get_num_args(); @@ -1058,13 +1058,13 @@ namespace opt { (m_arith.is_mul(e, e2, e1) && m_arith.is_numeral(e1) && is_uninterp_const(e2)); } - app* context::purify(filter_model_converter_ref& fm, expr* term) { + app* context::purify(generic_model_converter_ref& fm, expr* term) { std::ostringstream out; out << mk_pp(term, m); app* q = m.mk_fresh_const(out.str().c_str(), m.get_sort(term)); - if (!fm) fm = alloc(filter_model_converter, m); + if (!fm) fm = alloc(generic_model_converter, m); m_hard_constraints.push_back(m.mk_eq(q, term)); - fm->insert(q->get_decl()); + fm->hide(q); return q; } @@ -1075,7 +1075,7 @@ namespace opt { - filter "obj" from generated model. */ void context::mk_atomic(expr_ref_vector& terms) { - filter_model_converter_ref fm; + generic_model_converter_ref fm; for (unsigned i = 0; i < terms.size(); ++i) { expr_ref p(terms[i].get(), m); app_ref q(m); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 4fec5d452..be0ef873c 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -45,7 +45,7 @@ namespace opt { class maxsat_context { public: - virtual filter_model_converter& fm() = 0; // converter that removes fresh names introduced by simplification. + virtual generic_model_converter& fm() = 0; // converter that removes fresh names introduced by simplification. virtual bool sat_enabled() const = 0; // is using th SAT solver core enabled? virtual solver& get_solver() = 0; // retrieve solver object (SAT or SMT solver) virtual ast_manager& get_manager() const = 0; @@ -155,7 +155,7 @@ namespace opt { vector m_objectives; model_ref m_model; model_converter_ref m_model_converter; - filter_model_converter m_fm; + generic_model_converter m_fm; obj_map m_objective_fns; obj_map m_objective_orig; func_decl_ref_vector m_objective_refs; @@ -219,7 +219,7 @@ namespace opt { virtual expr_ref mk_le(unsigned i, model_ref& model); virtual smt::context& smt_context() { return m_opt_solver->get_context(); } - virtual filter_model_converter& fm() { return m_fm; } + virtual generic_model_converter& fm() { return m_fm; } virtual bool sat_enabled() const { return 0 != m_sat_solver.get(); } virtual solver& get_solver(); virtual ast_manager& get_manager() const { return this->m; } @@ -253,7 +253,7 @@ namespace opt { vector& weights, rational& offset, bool& neg, symbol& id, expr_ref& orig_term, unsigned& index); void purify(app_ref& term); - app* purify(filter_model_converter_ref& fm, expr* e); + app* purify(generic_model_converter_ref& fm, expr* e); bool is_mul_const(expr* e); expr* mk_maximize(unsigned index, app* t); expr* mk_minimize(unsigned index, app* t); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 3eb435fd7..b14e99c48 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -37,7 +37,7 @@ Notes: namespace opt { opt_solver::opt_solver(ast_manager & mgr, params_ref const & p, - filter_model_converter& fm): + generic_model_converter& fm): solver_na2as(mgr), m_params(p), m_context(mgr, m_params), @@ -80,7 +80,7 @@ namespace opt { m_context.collect_statistics(st); } - void opt_solver::assert_expr(expr * t) { + void opt_solver::assert_expr_core(expr * t) { if (has_quantifiers(t)) { m_params.m_relevancy_lvl = 2; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 61947e768..9d1eccb38 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -30,7 +30,7 @@ Notes: #include "smt/params/smt_params.h" #include "smt/smt_types.h" #include "smt/theory_opt.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" namespace opt { @@ -70,7 +70,7 @@ namespace opt { smt_params m_params; smt::kernel m_context; ast_manager& m; - filter_model_converter& m_fm; + generic_model_converter& m_fm; progress_callback * m_callback; symbol m_logic; svector m_objective_vars; @@ -84,14 +84,14 @@ namespace opt { bool m_first; bool m_was_unknown; public: - opt_solver(ast_manager & m, params_ref const & p, filter_model_converter& fm); + opt_solver(ast_manager & m, params_ref const & p, generic_model_converter& fm); virtual ~opt_solver(); virtual solver* translate(ast_manager& m, params_ref const& p); virtual void updt_params(params_ref const& p); virtual void collect_param_descrs(param_descrs & r); virtual void collect_statistics(statistics & st) const; - virtual void assert_expr(expr * t); + virtual void assert_expr_core(expr * t); virtual void assert_lemma(expr* t) {} virtual void push_core(); virtual void pop_core(unsigned n); diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index f832d5564..18c3edc76 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -24,7 +24,7 @@ Notes: #include "smt/smt_context.h" #include "opt/opt_context.h" #include "util/sorting_network.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" namespace opt { @@ -35,7 +35,7 @@ namespace opt { psort_nw m_sort; expr_ref_vector m_trail; func_decl_ref_vector m_fresh; - ref m_filter; + ref m_filter; sortmax(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft), m_sort(*this), m_trail(m), m_fresh(m) {} @@ -50,7 +50,7 @@ namespace opt { if (is_sat != l_true) { return is_sat; } - m_filter = alloc(filter_model_converter, m); + m_filter = alloc(generic_model_converter, m); rational offset = m_lower; m_upper = offset; expr_ref_vector in(m); @@ -142,7 +142,7 @@ namespace opt { expr_ref fr(m.mk_fresh_const(n, m.mk_bool_sort()), m); func_decl* f = to_app(fr)->get_decl(); m_fresh.push_back(f); - m_filter->insert(f); + m_filter->hide(f); return trail(fr); } diff --git a/src/qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp index 5d1a74813..e198542c1 100644 --- a/src/qe/qe_tactic.cpp +++ b/src/qe/qe_tactic.cpp @@ -17,7 +17,6 @@ Revision History: --*/ #include "tactic/tactical.h" -#include "tactic/filter_model_converter.h" #include "util/cooperate.h" #include "qe/qe.h" diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 713ecfe77..56f2ff985 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -44,11 +44,11 @@ namespace qe { m(m), m_asms(m), m_trail(m), - m_fmc(alloc(filter_model_converter, m)) + m_fmc(alloc(generic_model_converter, m)) { } - filter_model_converter* pred_abs::fmc() { + generic_model_converter* pred_abs::fmc() { return m_fmc.get(); } @@ -282,7 +282,7 @@ namespace qe { app_ref pred_abs::fresh_bool(char const* name) { app_ref r(m.mk_fresh_const(name, m.mk_bool_sort()), m); - m_fmc->insert(r->get_decl()); + m_fmc->hide(r); return r; } @@ -747,9 +747,7 @@ namespace qe { } void filter_vars(app_ref_vector const& vars) { - for (unsigned i = 0; i < vars.size(); ++i) { - m_pred_abs.fmc()->insert(vars[i]->get_decl()); - } + for (app* v : vars) m_pred_abs.fmc()->hide(v); } void initialize_levels() { diff --git a/src/qe/qsat.h b/src/qe/qsat.h index 85a8181d6..dca7cc00b 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -22,7 +22,7 @@ Revision History: #define QE_QSAT_H__ #include "tactic/tactic.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "qe/qe_mbp.h" namespace qe { @@ -72,7 +72,7 @@ namespace qe { obj_map m_asm2pred; // maintain map from assumptions to predicates obj_map m_pred2asm; // predicates |-> assumptions expr_ref_vector m_trail; - filter_model_converter_ref m_fmc; + generic_model_converter_ref m_fmc; ptr_vector todo; obj_map m_elevel; obj_map m_flevel; @@ -91,7 +91,7 @@ namespace qe { public: pred_abs(ast_manager& m); - filter_model_converter* fmc(); + generic_model_converter* fmc(); void reset(); max_level compute_level(app* e); void push(); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index b5efe57da..37f8b5d16 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -31,7 +31,6 @@ Notes: #include "sat/tactic/goal2sat.h" #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" -#include "tactic/filter_model_converter.h" #include "tactic/bv/bit_blaster_model_converter.h" #include "ast/ast_translation.h" #include "ast/ast_util.h" @@ -241,13 +240,13 @@ public: virtual unsigned get_scope_level() const { return m_num_scopes; } - virtual void assert_expr(expr * t, expr * a) { + virtual void assert_expr_core(expr * t, expr * a) { if (a) { m_asmsf.push_back(a); - assert_expr(m.mk_implies(a, t)); + assert_expr_core(m.mk_implies(a, t)); } else { - assert_expr(t); + assert_expr_core(t); } } @@ -261,7 +260,7 @@ public: } virtual ast_manager& get_manager() const { return m; } - virtual void assert_expr(expr * t) { + virtual void assert_expr_core(expr * t) { m_internalized = false; TRACE("goal2sat", tout << mk_pp(t, m) << "\n";); m_fmls.push_back(t); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index c70077dc5..f037a0e26 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -38,7 +38,7 @@ Notes: #include "model/model_evaluator.h" #include "model/model_v2_pp.h" #include "tactic/tactic.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include struct goal2sat::imp { @@ -883,7 +883,7 @@ struct sat2goal::imp { class sat_model_converter : public model_converter { sat::model_converter m_mc; expr_ref_vector m_var2expr; - filter_model_converter_ref m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion + generic_model_converter_ref m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion sat_model_converter(ast_manager & m): m_var2expr(m) { @@ -892,7 +892,7 @@ struct sat2goal::imp { public: sat_model_converter(ast_manager & m, sat::solver const & s):m_var2expr(m) { m_mc.copy(s.get_model_converter()); - m_fmc = alloc(filter_model_converter, m); + m_fmc = alloc(generic_model_converter, m); } ast_manager & m() { return m_var2expr.get_manager(); } @@ -907,7 +907,7 @@ struct sat2goal::imp { if (aux) { SASSERT(is_uninterp_const(atom)); SASSERT(m().is_bool(atom)); - m_fmc->insert(to_app(atom)->get_decl()); + m_fmc->hide(to_app(atom)->get_decl()); } } @@ -976,7 +976,7 @@ struct sat2goal::imp { virtual model_converter * translate(ast_translation & translator) { sat_model_converter * res = alloc(sat_model_converter, translator.to()); - res->m_fmc = static_cast(m_fmc->translate(translator)); + res->m_fmc = static_cast(m_fmc->translate(translator)); for (expr* e : m_var2expr) res->m_var2expr.push_back(e ? translator(e) : nullptr); return res; diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 3a5c414ef..7b48986c5 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -18,7 +18,6 @@ Notes: --*/ #include "ast/ast_pp.h" #include "tactic/tactical.h" -#include "tactic/filter_model_converter.h" #include "sat/tactic/goal2sat.h" #include "sat/sat_solver.h" #include "model/model_v2_pp.h" diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 850621e67..7866f15e9 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -101,11 +101,11 @@ namespace smt { return m_context.find_mutexes(vars, mutexes); } - virtual void assert_expr(expr * t) { + virtual void assert_expr_core(expr * t) { m_context.assert_expr(t); } - virtual void assert_expr(expr * t, expr * a) { + virtual void assert_expr_core(expr * t, expr * a) { if (m_name2assertion.contains(a)) { throw default_exception("named assertion defined twice"); } diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 57ac7b34b..77024dba6 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -23,7 +23,7 @@ Notes: #include "smt/params/smt_params_helper.hpp" #include "util/lp/lp_params.hpp" #include "ast/rewriter/rewriter_types.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/ast_util.h" #include "solver/solver2tactic.h" #include "smt/smt_solver.h" @@ -169,7 +169,7 @@ public: expr_ref_vector clauses(m); expr2expr_map bool2dep; ptr_vector assumptions; - ref fmc; + ref fmc; if (in->unsat_core_enabled()) { extract_clauses_and_dependencies(in, clauses, assumptions, bool2dep, fmc); TRACE("mus", in->display_with_dependencies(tout); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 5f4e58a1b..ba08c82e2 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1081,7 +1081,7 @@ namespace smt { virtual inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared); virtual inf_eps_rational value(theory_var v); virtual theory_var add_objective(app* term); - expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); + expr_ref mk_ge(generic_model_converter& fm, theory_var v, inf_numeral const& val); void enable_record_conflict(expr* bound); void record_conflict(unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index a1558e5e5..1d4c65f2d 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -23,7 +23,7 @@ Revision History: #include "smt/theory_arith.h" #include "smt/smt_farkas_util.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" namespace smt { @@ -1117,14 +1117,14 @@ namespace smt { This allows to handle inequalities with non-standard numbers. */ template - expr_ref theory_arith::mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val) { + expr_ref theory_arith::mk_ge(generic_model_converter& fm, theory_var v, inf_numeral const& val) { ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; strm << val << " <= " << mk_pp(get_enode(v)->get_owner(), get_manager()); app* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); if (!ctx.b_internalized(b)) { - fm.insert(b->get_decl()); + fm.hide(b->get_decl()); bool_var bv = ctx.mk_bool_var(b); ctx.set_var_theory(bv, get_id()); // ctx.set_enode_flag(bv, true); diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index 980830447..e0de1ebd9 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -271,7 +271,7 @@ namespace smt { virtual inf_eps_rational value(theory_var v); virtual theory_var add_objective(app* term); virtual expr_ref mk_gt(theory_var v, inf_eps const& val); - expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val); + expr_ref mk_ge(generic_model_converter& fm, theory_var v, inf_eps const& val); // ----------------------------------- // diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 78fb4d03d..eef3cd068 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -1055,7 +1055,7 @@ namespace smt { template expr_ref theory_dense_diff_logic::mk_ge( - filter_model_converter& fm, theory_var v, inf_eps const& val) { + generic_model_converter& fm, theory_var v, inf_eps const& val) { return mk_ineq(v, val, false); } diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 1ad239e58..6cd5ce872 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -324,7 +324,7 @@ namespace smt { virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared); virtual inf_eps value(theory_var v); virtual theory_var add_objective(app* term); - expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val); + expr_ref mk_ge(generic_model_converter& fm, theory_var v, inf_eps const& val); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 203dd24d2..0633b500f 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -1336,7 +1336,7 @@ expr_ref theory_diff_logic::mk_gt(theory_var v, inf_eps const& val) { } template -expr_ref theory_diff_logic::mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { +expr_ref theory_diff_logic::mk_ge(generic_model_converter& fm, theory_var v, inf_eps const& val) { return mk_ineq(v, val, false); } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 292d2ab0d..0cc25541b 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -36,7 +36,7 @@ Revision History: #include "smt/smt_model_generator.h" #include "smt/arith_eq_adapter.h" #include "util/nat_set.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" namespace lra_lp { enum bound_kind { lower_t, upper_t }; @@ -2417,7 +2417,7 @@ namespace smt { } } - expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val) { + expr_ref mk_ge(generic_model_converter& fm, theory_var v, inf_rational const& val) { rational r = val.get_rational(); bool is_strict = val.get_infinitesimal().is_pos(); app_ref b(m); @@ -2429,7 +2429,7 @@ namespace smt { b = a.mk_ge(mk_obj(v), a.mk_numeral(r, is_int)); } if (!ctx().b_internalized(b)) { - fm.insert(b->get_decl()); + fm.hide(b); bool_var bv = ctx().mk_bool_var(b); ctx().set_var_theory(bv, get_id()); // ctx().set_enode_flag(bv, true); @@ -2620,7 +2620,7 @@ namespace smt { theory_var theory_lra::add_objective(app* term) { return m_imp->add_objective(term); } - expr_ref theory_lra::mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val) { + expr_ref theory_lra::mk_ge(generic_model_converter& fm, theory_var v, inf_rational const& val) { return m_imp->mk_ge(fm, v, val); } diff --git a/src/smt/theory_lra.h b/src/smt/theory_lra.h index 774ec15ad..d8cc655e9 100644 --- a/src/smt/theory_lra.h +++ b/src/smt/theory_lra.h @@ -89,7 +89,7 @@ namespace smt { virtual inf_eps value(theory_var); virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared); virtual theory_var add_objective(app* term); - virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val); + virtual expr_ref mk_ge(generic_model_converter& fm, theory_var v, inf_rational const& val); }; diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 49f436ea5..2947d86c1 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -25,7 +25,7 @@ Notes: #ifndef THEORY_OPT_H_ #define THEORY_OPT_H_ -class filter_model_converter; +class generic_model_converter; namespace smt { class theory_opt { public: diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 88ba89610..99715cbca 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -25,7 +25,7 @@ Notes: namespace smt { - theory_wmaxsat::theory_wmaxsat(ast_manager& m, filter_model_converter& mc): + theory_wmaxsat::theory_wmaxsat(ast_manager& m, generic_model_converter& mc): theory(m.mk_family_id("weighted_maxsat")), m_mc(mc), m_vars(m), @@ -92,7 +92,7 @@ namespace smt { ast_manager& m = get_manager(); app_ref var(m), wfml(m); var = m.mk_fresh_const("w", m.mk_bool_sort()); - m_mc.insert(var->get_decl()); + m_mc.hide(var); wfml = m.mk_or(var, fml); ctx.assert_expr(wfml); m_rweights.push_back(w); diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 739a22c71..ff3006e11 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -22,7 +22,7 @@ Notes: #include "smt/smt_theory.h" #include "smt/smt_clause.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" namespace smt { class theory_wmaxsat : public theory { @@ -32,7 +32,7 @@ namespace smt { void reset() { memset(this, 0, sizeof(*this)); } stats() { reset(); } }; - filter_model_converter& m_mc; + generic_model_converter& m_mc; mutable unsynch_mpz_manager m_mpz; app_ref_vector m_vars; // Auxiliary variables per soft clause expr_ref_vector m_fmls; // Formulas per soft clause @@ -56,7 +56,7 @@ namespace smt { svector m_assigned, m_enabled; stats m_stats; public: - theory_wmaxsat(ast_manager& m, filter_model_converter& mc); + theory_wmaxsat(ast_manager& m, generic_model_converter& mc); virtual ~theory_wmaxsat(); void get_assignment(svector& result); expr* assert_weighted(expr* fml, rational const& w); diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index cc52c90cb..90a6cb7c8 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -164,7 +164,7 @@ public: m_solver2->set_produce_models(f); } - virtual void assert_expr(expr * t) { + virtual void assert_expr_core(expr * t) { if (m_check_sat_executed) switch_inc_mode(); m_solver1->assert_expr(t); @@ -172,7 +172,7 @@ public: m_solver2->assert_expr(t); } - virtual void assert_expr(expr * t, expr * a) { + virtual void assert_expr_core(expr * t, expr * a) { if (m_check_sat_executed) switch_inc_mode(); m_solver1->assert_expr(t, a); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index de0834b9d..8f1287dab 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -182,13 +182,26 @@ bool solver::is_literal(ast_manager& m, expr* e) { return is_uninterp_const(e) || (m.is_not(e, e) && is_uninterp_const(e)); } -#if 0 -expr_ref solver::lookahead(expr_ref_vector const& candidates) { - std::cout << "lookahead: " << candidates.size() << "\n"; - INVOKE_DEBUGGER(); - ast_manager& m = candidates.get_manager(); - return expr_ref(m.mk_true(), m); + +void solver::assert_expr(expr* f) { + expr_ref fml(f, get_manager()); + if (mc0()) { + (*mc0())(fml); + } + assert_expr_core(fml); } -#endif +void solver::assert_expr(expr* f, expr* t) { + // let mc0 be the model converter associated with the solver + // that converts models to their "real state". + ast_manager& m = get_manager(); + expr_ref fml(f, m); + expr_ref a(t, m); + + if (mc0()) { + (*mc0())(fml); + // (*mc0())(a); + } + assert_expr_core(fml, a); +} diff --git a/src/solver/solver.h b/src/solver/solver.h index 713434d7c..780a55cf5 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -80,14 +80,16 @@ public: /** \brief Add a new formula to the assertion stack. */ - virtual void assert_expr(expr * t) = 0; + void assert_expr(expr* f); + + virtual void assert_expr_core(expr * t) = 0; void assert_expr(expr_ref_vector const& ts) { - for (unsigned i = 0; i < ts.size(); ++i) assert_expr(ts[i]); + for (expr* e : ts) assert_expr(e); } void assert_expr(ptr_vector const& ts) { - for (unsigned i = 0; i < ts.size(); ++i) assert_expr(ts[i]); + for (expr* e : ts) assert_expr(e); } /** @@ -95,7 +97,10 @@ public: The propositional variable \c a is used to track the use of \c t in a proof of unsatisfiability. */ - virtual void assert_expr(expr * t, expr * a) = 0; + + void assert_expr(expr * t, expr* a); + + virtual void assert_expr_core(expr * t, expr * a) = 0; /** \brief Add a lemma to the assertion stack. A lemma is assumed to be a consequence of already @@ -210,11 +215,13 @@ public: ~scoped_push() { if (!m_nopop) s.pop(1); } void disable_pop() { m_nopop = true; } }; + protected: virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); + bool is_literal(ast_manager& m, expr* e); }; diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index eea3aa9c5..a44463a75 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -19,13 +19,13 @@ Notes: #include "solver/solver.h" #include "tactic/tactic.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "solver/solver2tactic.h" #include "ast/ast_util.h" typedef obj_map expr2expr_map; -void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector& assumptions, expr2expr_map& bool2dep, ref& fmc) { +void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector& assumptions, expr2expr_map& bool2dep, ref& fmc) { expr2expr_map dep2bool; ptr_vector deps; ast_manager& m = g->m(); @@ -65,9 +65,9 @@ void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clause bool2dep.insert(b, d); assumptions.push_back(b); if (!fmc) { - fmc = alloc(filter_model_converter, m); + fmc = alloc(generic_model_converter, m); } - fmc->insert(to_app(b)->get_decl()); + fmc->hide(to_app(b)->get_decl()); } clause.push_back(m.mk_not(b)); } @@ -110,7 +110,7 @@ public: expr_ref_vector clauses(m); expr2expr_map bool2dep; ptr_vector assumptions; - ref fmc; + ref fmc; extract_clauses_and_dependencies(in, clauses, assumptions, bool2dep, fmc); ref local_solver = m_solver->translate(m, m_params); local_solver->assert_expr(clauses); diff --git a/src/solver/solver2tactic.h b/src/solver/solver2tactic.h index 647a1cee4..8c6466ddb 100644 --- a/src/solver/solver2tactic.h +++ b/src/solver/solver2tactic.h @@ -20,11 +20,11 @@ Notes: #define SOLVER2TACTIC_H_ #include "tactic/tactic.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" class solver; tactic * mk_solver2tactic(solver* s); -void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector& assumptions, obj_map& bool2dep, ref& fmc); +void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clauses, ptr_vector& assumptions, obj_map& bool2dep, ref& fmc); #endif diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 2628380c5..ae4014c7f 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -30,9 +30,9 @@ solver_na2as::solver_na2as(ast_manager & m): solver_na2as::~solver_na2as() {} -void solver_na2as::assert_expr(expr * t, expr * a) { +void solver_na2as::assert_expr_core(expr * t, expr * a) { if (a == 0) { - assert_expr(t); + assert_expr_core(t); } else { SASSERT(is_uninterp_const(a)); @@ -41,7 +41,7 @@ void solver_na2as::assert_expr(expr * t, expr * a) { m_assumptions.push_back(a); expr_ref new_t(m); new_t = m.mk_implies(a, t); - assert_expr(new_t); + assert_expr_core(new_t); } } diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 3e726be12..061d62aee 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -34,8 +34,8 @@ public: solver_na2as(ast_manager & m); virtual ~solver_na2as(); - virtual void assert_expr(expr * t, expr * a); - virtual void assert_expr(expr * t) = 0; + void assert_expr_core(expr * t, expr * a) override; + virtual void assert_expr_core(expr * t) = 0; // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions); diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 3c7837ad5..1b7203351 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -49,7 +49,7 @@ public: m_in_delayed_scope(false), m_dump_counter(0) { if (is_virtual()) { - solver_na2as::assert_expr(m.mk_true(), pred); + solver_na2as::assert_expr_core(m.mk_true(), pred); } } @@ -191,7 +191,7 @@ public: } } - virtual void assert_expr(expr * e) { + virtual void assert_expr_core(expr * e) { SASSERT(!m_pushed || get_scope_level() > 0); if (m.is_true(e)) return; if (m_in_delayed_scope) { diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index dd2f42e7a..35fe9cf8e 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -54,7 +54,7 @@ public: virtual void set_produce_models(bool f) { m_produce_models = f; } - virtual void assert_expr(expr * t); + virtual void assert_expr_core(expr * t); virtual void assert_lemma(expr * t); virtual void push_core(); @@ -112,7 +112,7 @@ void tactic2solver::collect_param_descrs(param_descrs & r) { m_tactic->collect_param_descrs(r); } -void tactic2solver::assert_expr(expr * t) { +void tactic2solver::assert_expr_core(expr * t) { m_assertions.push_back(t); m_result = 0; } diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index 74379b30f..04900fcbe 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -2,7 +2,6 @@ z3_add_component(tactic SOURCES equiv_proof_converter.cpp extension_model_converter.cpp - filter_model_converter.cpp generic_model_converter.cpp goal.cpp goal_num_occurs.cpp diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 932898bd1..2e4782b2c 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -23,7 +23,7 @@ Notes: #include "ast/rewriter/pb2bv_rewriter.h" #include "ast/ast_util.h" #include "ast/ast_pp.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" class card2bv_tactic : public tactic { ast_manager & m; @@ -89,9 +89,9 @@ public: func_decl_ref_vector const& fns = rw2.fresh_constants(); if (!fns.empty()) { - filter_model_converter* filter = alloc(filter_model_converter, m); + generic_model_converter* filter = alloc(generic_model_converter, m); for (unsigned i = 0; i < fns.size(); ++i) { - filter->insert(fns[i]); + filter->hide(fns[i]); } mc = filter; } diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 80b7a416c..519fec742 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -20,7 +20,6 @@ Revision History: --*/ #include "tactic/tactical.h" -#include "tactic/filter_model_converter.h" #include "tactic/generic_model_converter.h" #include "util/cooperate.h" #include "ast/arith_decl_plugin.h" @@ -197,12 +196,10 @@ class degree_shift_tactic : public tactic { void prepare_substitution(model_converter_ref & mc) { SASSERT(!m_var2degree.empty()); - filter_model_converter * fmc = 0; generic_model_converter * xmc = 0; if (m_produce_models) { - fmc = alloc(filter_model_converter, m); xmc = alloc(generic_model_converter, m); - mc = concat(fmc, xmc); + mc = xmc; } for (auto const& kv : m_var2degree) { SASSERT(kv.m_value.is_int()); @@ -211,7 +208,7 @@ class degree_shift_tactic : public tactic { m_pinned.push_back(fresh); m_var2var.insert(kv.m_key, fresh); if (m_produce_models) { - fmc->insert(fresh->get_decl()); + xmc->hide(fresh->get_decl()); xmc->add(kv.m_key->get_decl(), mk_power(fresh, rational(1)/kv.m_value)); } if (m_produce_proofs) { diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index d303463db..a339db51b 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -21,7 +21,7 @@ Revision History: #include "ast/rewriter/th_rewriter.h" #include "ast/for_each_expr.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" #include "ast/ast_smt2_pp.h" @@ -225,10 +225,10 @@ class lia2pb_tactic : public tactic { throw tactic_exception("lia2pb failed, number of necessary bits exceeds specified threshold (use option :lia2pb-total-bits to increase threshold)"); extension_model_converter * mc1 = 0; - filter_model_converter * mc2 = 0; + generic_model_converter * mc2 = 0; if (m_produce_models) { mc1 = alloc(extension_model_converter, m); - mc2 = alloc(filter_model_converter, m); + mc2 = alloc(generic_model_converter, m); mc = concat(mc2, mc1); } @@ -259,7 +259,7 @@ class lia2pb_tactic : public tactic { else def_args.push_back(m_util.mk_mul(m_util.mk_numeral(a, true), x_prime)); if (m_produce_models) - mc2->insert(x_prime->get_decl()); + mc2->hide(x_prime->get_decl()); a *= rational(2); } SASSERT(def_args.size() > 1); diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 6f5f49aee..00cb02cf6 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -27,7 +27,7 @@ Notes: #include "tactic/arith/bv2int_rewriter.h" #include "tactic/arith/bv2real_rewriter.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "tactic/arith/bound_manager.h" #include "util/obj_pair_hashtable.h" #include "ast/ast_smt2_pp.h" @@ -60,7 +60,7 @@ class nla2bv_tactic : public tactic { expr_ref_vector m_trail; unsigned m_num_bits; unsigned m_default_bv_size; - filter_model_converter_ref m_fmc; + generic_model_converter_ref m_fmc; public: imp(ast_manager & m, params_ref const& p): @@ -86,7 +86,7 @@ class nla2bv_tactic : public tactic { TRACE("nla2bv", g.display(tout); tout << "Muls: " << count_mul(g) << "\n"; ); - m_fmc = alloc(filter_model_converter, m_manager); + m_fmc = alloc(generic_model_converter, m_manager); m_bounds(g); collect_power2(g); if(!collect_vars(g)) { @@ -104,7 +104,7 @@ class nla2bv_tactic : public tactic { evc->insert(m_vars[i].get(), m_defs[i].get()); } for (unsigned i = 0; i < m_bv2real.num_aux_decls(); ++i) { - m_fmc->insert(m_bv2real.get_aux_decl(i)); + m_fmc->hide(m_bv2real.get_aux_decl(i)); } IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(nla->bv :sat-preserving " << m_is_sat_preserving << ")\n";); TRACE("nla2bv_verbose", g.display(tout);); @@ -233,7 +233,7 @@ class nla2bv_tactic : public tactic { bv_sort = m_bv.mk_sort(num_bits); std::string name = n->get_decl()->get_name().str(); s_bv = m_manager.mk_fresh_const(name.c_str(), bv_sort); - m_fmc->insert(to_app(s_bv)->get_decl()); + m_fmc->hide(s_bv); s_bv = m_bv.mk_bv2int(s_bv); if (low) { if (!(*low).is_zero()) { @@ -271,8 +271,8 @@ class nla2bv_tactic : public tactic { s = m_manager.mk_fresh_const(name.c_str(), bv_sort); name += "_r"; t = m_manager.mk_fresh_const(name.c_str(), bv_sort); - m_fmc->insert(to_app(s)->get_decl()); - m_fmc->insert(to_app(t)->get_decl()); + m_fmc->hide(s); + m_fmc->hide(t); s_bv = m_bv2real.mk_bv2real(s, t); m_trail.push_back(s_bv); m_subst.insert(n, s_bv); diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index 2b3ff5ab0..90f92f3f7 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -22,7 +22,7 @@ Revision History: #include "tactic/arith/bound_manager.h" #include "ast/rewriter/th_rewriter.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" #include "ast/ast_smt2_pp.h" @@ -99,10 +99,10 @@ class normalize_bounds_tactic : public tactic { } extension_model_converter * mc1 = 0; - filter_model_converter * mc2 = 0; + generic_model_converter * mc2 = 0; if (produce_models) { mc1 = alloc(extension_model_converter, m); - mc2 = alloc(filter_model_converter, m); + mc2 = alloc(generic_model_converter, m); mc = concat(mc2, mc1); } @@ -121,7 +121,7 @@ class normalize_bounds_tactic : public tactic { subst.insert(x, def); if (produce_models) { mc1->insert(to_app(x)->get_decl(), def); - mc2->insert(x_prime->get_decl()); + mc2->hide(x_prime->get_decl()); } } } diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 259cbc0c8..f391e2a17 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -26,7 +26,7 @@ Notes: #include "util/trace.h" #include "ast/ast_smt2_pp.h" #include "ast/expr_substitution.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "tactic/arith/pb2bv_model_converter.h" #include "tactic/arith/pb2bv_tactic.h" #include "ast/ast_pp.h" @@ -949,15 +949,13 @@ private: g->update(idx, new_exprs[idx].get(), 0, (m_produce_unsat_cores) ? new_deps[idx].get() : g->dep(idx)); if (m_produce_models) { - filter_model_converter * mc1 = alloc(filter_model_converter, m); - obj_map::iterator it = m_const2bit.begin(); - obj_map::iterator end = m_const2bit.end(); - for (; it != end; ++it) - mc1->insert(to_app(it->m_value)->get_decl()); + generic_model_converter * mc1 = alloc(generic_model_converter, m); + for (auto const& kv : m_const2bit) + mc1->hide(kv.m_value); // store temp int constants in the filter unsigned num_temps = m_temporary_ints.size(); for (unsigned i = 0; i < num_temps; i++) - mc1->insert(to_app(m_temporary_ints.get(i))->get_decl()); + mc1->hide(m_temporary_ints.get(i)); pb2bv_model_converter * mc2 = alloc(pb2bv_model_converter, m, m_const2bit, m_bm); mc = concat(mc1, mc2); } diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 7e89794ce..144a13bcd 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -27,7 +27,7 @@ Revision History: #include "tactic/core/nnf_tactic.h" #include "tactic/core/simplify_tactic.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "tactic/extension_model_converter.h" #include "ast/ast_smt2_pp.h" #include "ast/rewriter/expr_replacer.h" @@ -764,17 +764,15 @@ struct purify_arith_proc { m_goal.assert_expr(r.cfg().m_new_cnstrs.get(i), m_produce_proofs ? r.cfg().m_new_cnstr_prs.get(i) : 0, 0); } - // add filter_model_converter to eliminate auxiliary variables from model + // add generic_model_converter to eliminate auxiliary variables from model if (produce_models) { - filter_model_converter * fmc = alloc(filter_model_converter, m()); + generic_model_converter * fmc = alloc(generic_model_converter, m()); mc = fmc; obj_map & f2v = r.cfg().m_app2fresh; - obj_map::iterator it = f2v.begin(); - obj_map::iterator end = f2v.end(); - for (; it != end; ++it) { - app * v = to_app(it->m_value); + for (auto const& kv : f2v) { + app * v = to_app(kv.m_value); SASSERT(is_uninterp_const(v)); - fmc->insert(v->get_decl()); + fmc->hide(v->get_decl()); } } if (produce_models && !m_sin_cos.empty()) { diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index d3b9ecc3e..bd03f6901 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -33,7 +33,7 @@ Revision History: #include "tactic/tactical.h" #include "ast/rewriter/th_rewriter.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" #include "util/dec_ref_util.h" @@ -113,7 +113,7 @@ class recover_01_tactic : public tactic { // temporary fields used by operator() and process extension_model_converter * mc1; - filter_model_converter * mc2; + generic_model_converter * mc2; expr_substitution * subst; goal_ref new_goal; obj_map bool2int; @@ -205,7 +205,7 @@ class recover_01_tactic : public tactic { expr * bool_def = m.mk_eq(var, m_util.mk_numeral(rational(1), true)); subst->insert(atom, bool_def); if (m_produce_models) { - mc2->insert(to_app(var)->get_decl()); + mc2->hide(to_app(var)->get_decl()); mc1->insert(to_app(atom)->get_decl(), bool_def); } m.inc_ref(atom); @@ -329,7 +329,7 @@ class recover_01_tactic : public tactic { if (m_produce_models) { mc1 = alloc(extension_model_converter, m); - mc2 = alloc(filter_model_converter, m); + mc2 = alloc(generic_model_converter, m); mc = concat(mc2, mc1); } diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index 9401f74c1..c62e1177d 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -25,7 +25,7 @@ Notes: #include "ast/bv_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/ast_smt2_pp.h" class bv_size_reduction_tactic : public tactic { @@ -60,7 +60,7 @@ struct bv_size_reduction_tactic::imp { obj_map m_unsigned_lowers; obj_map m_unsigned_uppers; ref m_mc; - filter_model_converter_ref m_fmc; + generic_model_converter_ref m_fmc; scoped_ptr m_replacer; bool m_produce_models; @@ -269,9 +269,9 @@ struct bv_size_reduction_tactic::imp { m_mc = alloc(bv_size_reduction_mc, m); m_mc->insert(v->get_decl(), new_def); if (!m_fmc && new_const) - m_fmc = alloc(filter_model_converter, m); + m_fmc = alloc(generic_model_converter, m); if (new_const) - m_fmc->insert(new_const->get_decl()); + m_fmc->hide(new_const); } num_reduced++; } @@ -335,9 +335,9 @@ struct bv_size_reduction_tactic::imp { m_mc = alloc(bv_size_reduction_mc, m); m_mc->insert(v->get_decl(), new_def); if (!m_fmc && new_const) - m_fmc = alloc(filter_model_converter, m); + m_fmc = alloc(generic_model_converter, m); if (new_const) - m_fmc->insert(new_const->get_decl()); + m_fmc->hide(new_const); } num_reduced++; TRACE("bv_size_reduction", tout << "New definition = " << mk_ismt2_pp(new_def, m) << "\n";); diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp index b92092739..1d96ffc35 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.cpp +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -120,7 +120,7 @@ func_decl_ref bvarray2uf_rewriter_cfg::mk_uf_for_array(expr * e) { m_array_util.mk_as_array(bv_f)); } else if (m_fmc) - m_fmc->insert(bv_f); + m_fmc->hide(bv_f); m_arrays_fs.insert(e, bv_f); m_manager.inc_ref(e); m_manager.inc_ref(bv_f); @@ -193,10 +193,10 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr if (is_uninterp_const(e)) { if (m_emc) m_emc->insert(e->get_decl(), - m_array_util.mk_as_array(bv_f)); + m_array_util.mk_as_array(bv_f)); } else if (m_fmc) - m_fmc->insert(bv_f); + m_fmc->hide(bv_f); m_arrays_fs.insert(e, bv_f); m_manager.inc_ref(e); m_manager.inc_ref(bv_f); diff --git a/src/tactic/bv/bvarray2uf_rewriter.h b/src/tactic/bv/bvarray2uf_rewriter.h index bc4014b5b..0fe5762ae 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.h +++ b/src/tactic/bv/bvarray2uf_rewriter.h @@ -22,7 +22,7 @@ Notes: #include "ast/rewriter/rewriter.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" class bvarray2uf_rewriter_cfg : public default_rewriter_cfg { ast_manager & m_manager; @@ -31,7 +31,7 @@ class bvarray2uf_rewriter_cfg : public default_rewriter_cfg { bv_util m_bv_util; array_util m_array_util; extension_model_converter * m_emc; - filter_model_converter * m_fmc; + generic_model_converter * m_fmc; obj_map m_arrays_fs; @@ -59,7 +59,7 @@ public: expr_ref_vector extra_assertions; - void set_mcs(extension_model_converter * emc, filter_model_converter * fmc) { m_emc = emc; m_fmc = fmc; } + void set_mcs(extension_model_converter * emc, generic_model_converter * fmc) { m_emc = emc; m_fmc = fmc; } protected: sort * get_index_sort(expr * e); @@ -79,7 +79,7 @@ struct bvarray2uf_rewriter : public rewriter_tpl { m_cfg(m, p) { } - void set_mcs(extension_model_converter * emc, filter_model_converter * fmc) { m_cfg.set_mcs(emc, fmc); } + void set_mcs(extension_model_converter * emc, generic_model_converter * fmc) { m_cfg.set_mcs(emc, fmc); } }; #endif diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index 87f43ae8d..af74a2d8f 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -21,7 +21,7 @@ Notes: #include "ast/bv_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/ast_smt2_pp.h" #include "tactic/bv/bvarray2uf_tactic.h" @@ -69,7 +69,7 @@ class bvarray2uf_tactic : public tactic { if (m_produce_models) { extension_model_converter * emc = alloc(extension_model_converter, m_manager); - filter_model_converter * fmc = alloc(filter_model_converter, m_manager); + generic_model_converter * fmc = alloc(generic_model_converter, m_manager); mc = concat(emc, fmc); m_rw.set_mcs(emc, fmc); } diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 2b1aa0fdd..6a1de26fe 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -21,11 +21,11 @@ Revision History: #include "tactic/bv/dt2bv_tactic.h" #include "tactic/tactical.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/datatype_decl_plugin.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "tactic/extension_model_converter.h" #include "ast/rewriter/var_subst.h" #include "ast/ast_util.h" @@ -135,7 +135,7 @@ public: m_fd_sorts.remove(s); if (!m_fd_sorts.empty()) { ref ext = alloc(extension_model_converter, m); - ref filter = alloc(filter_model_converter, m); + ref filter = alloc(generic_model_converter, m); enum2bv_rewriter rw(m, m_params); rw.set_is_fd(&m_is_fd); expr_ref new_curr(m); @@ -153,7 +153,7 @@ public: for (expr* b : bounds) g->assert_expr(b); for (auto const& kv : rw.enum2bv()) - filter->insert(kv.m_value); + filter->hide(kv.m_value); for (auto const& kv : rw.enum2def()) ext->insert(kv.m_key, kv.m_value); diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index ab4b3920d..a0f78154f 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include "tactic/tactical.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "util/cooperate.h" #include "ast/bv_decl_plugin.h" #include "ast/used_vars.h" @@ -35,7 +35,7 @@ class elim_small_bv_tactic : public tactic { params_ref m_params; bv_util m_util; th_rewriter m_simp; - ref m_mc; + ref m_mc; goal * m_goal; unsigned m_max_bits; unsigned long long m_max_steps; diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index ae0ea019b..698da8498 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -19,7 +19,6 @@ Notes: #include "tactic/tactical.h" #include "ast/normal_forms/defined_names.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/filter_model_converter.h" #include "util/cooperate.h" #include "ast/scoped_proof.h" diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 79526a101..d6fb8a091 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -20,7 +20,7 @@ Notes: #include "tactic/tactical.h" #include "ast/normal_forms/defined_names.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "util/cooperate.h" class elim_term_ite_tactic : public tactic { @@ -28,7 +28,7 @@ class elim_term_ite_tactic : public tactic { struct rw_cfg : public default_rewriter_cfg { ast_manager & m; defined_names m_defined_names; - ref m_mc; + ref m_mc; goal * m_goal; unsigned long long m_max_memory; // in bytes bool m_produce_models; @@ -55,8 +55,8 @@ class elim_term_ite_tactic : public tactic { m_num_fresh++; if (m_produce_models) { if (!m_mc) - m_mc = alloc(filter_model_converter, m); - m_mc->insert(_result->get_decl()); + m_mc = alloc(generic_model_converter, m); + m_mc->hide(_result->get_decl()); } } result = _result.get(); diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 614b20a10..aa5d55a8c 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -18,7 +18,6 @@ Notes: --*/ #include "tactic/tactical.h" #include "tactic/generic_model_converter.h" -#include "tactic/filter_model_converter.h" #include "ast/rewriter/rewriter_def.h" #include "ast/arith_decl_plugin.h" #include "ast/bv_decl_plugin.h" @@ -873,9 +872,9 @@ class elim_uncnstr_tactic : public tactic { app_ref_vector & fresh_vars = m_rw->cfg().m_fresh_vars; m_num_elim_apps = fresh_vars.size(); if (produce_models && !fresh_vars.empty()) { - filter_model_converter * fmc = alloc(filter_model_converter, m()); - for (unsigned i = 0; i < fresh_vars.size(); i++) - fmc->insert(fresh_vars.get(i)->get_decl()); + generic_model_converter * fmc = alloc(generic_model_converter, m()); + for (app * f : fresh_vars) + fmc->hide(f); mc = concat(fmc, m_mc.get()); } else { @@ -910,7 +909,7 @@ class elim_uncnstr_tactic : public tactic { imp * m_imp; params_ref m_params; public: - elim_uncnstr_tactic(ast_manager & m, params_ref const & p): + elim_uncnstr_tactic(ast_manager & m, params_ref const & p): m_params(p) { m_imp = alloc(imp, m, p); } diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index 6b360e711..9750ad29c 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include "ast/normal_forms/nnf.h" #include "tactic/tactical.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" class nnf_tactic : public tactic { params_ref m_params; @@ -97,10 +97,10 @@ public: result.push_back(g.get()); unsigned num_extra_names = dnames.get_num_names(); if (num_extra_names > 0) { - filter_model_converter * fmc = alloc(filter_model_converter, m); + generic_model_converter * fmc = alloc(generic_model_converter, m); mc = fmc; for (unsigned i = 0; i < num_extra_names; i++) - fmc->insert(dnames.get_name_decl(i)); + fmc->hide(dnames.get_name_decl(i)); } TRACE("nnf", g->display(tout);); SASSERT(g->is_well_sorted()); diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index 6d9d63971..66143b6b5 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -23,13 +23,13 @@ Revision History: --*/ #include "tactic/tactical.h" #include "tactic/core/occf_tactic.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "util/cooperate.h" class occf_tactic : public tactic { struct imp { ast_manager & m; - filter_model_converter * m_mc; + generic_model_converter * m_mc; imp(ast_manager & _m): m(_m) { @@ -115,7 +115,7 @@ class occf_tactic : public tactic { SASSERT(!c2b.contains(cnstr)); expr * bvar = m.mk_fresh_const(0, m.mk_bool_sort()); if (produce_models) - m_mc->insert(to_app(bvar)->get_decl()); + m_mc->hide(to_app(bvar)->get_decl()); c2b.insert(cnstr, bvar_info(bvar, sign)); if (sign) { g->assert_expr(m.mk_or(bvar, m.mk_not(cnstr)), 0, 0); @@ -157,7 +157,7 @@ class occf_tactic : public tactic { if (!is_target(cls)) continue; if (produce_models && !m_mc) { - m_mc = alloc(filter_model_converter, m); + m_mc = alloc(generic_model_converter, m); mc = m_mc; } expr * keep = 0; diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index 476c21232..aaf85eacd 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -23,7 +23,7 @@ Notes: #include "util/map.h" #include "ast/rewriter/rewriter_def.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" /** \brief Reduce the number of arguments in function applications. @@ -395,7 +395,7 @@ struct reduce_args_tactic::imp { var_ref_vector new_vars(m_manager); ptr_buffer new_eqs; extension_model_converter * e_mc = alloc(extension_model_converter, m_manager); - filter_model_converter * f_mc = alloc(filter_model_converter, m_manager); + generic_model_converter * f_mc = alloc(generic_model_converter, m_manager); decl2arg2func_map::iterator it = decl2arg2funcs.begin(); decl2arg2func_map::iterator end = decl2arg2funcs.end(); for (; it != end; ++it) { @@ -416,7 +416,7 @@ struct reduce_args_tactic::imp { for (; it2 != end2; ++it2) { app * t = it2->m_key; func_decl * new_def = it2->m_value; - f_mc->insert(new_def); + f_mc->hide(new_def); SASSERT(new_def->get_arity() == new_args.size()); app * new_t = m_manager.mk_app(new_def, new_args.size(), new_args.c_ptr()); if (def == 0) { diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index dbfc748b0..4791b5ce6 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -51,7 +51,7 @@ Notes: --*/ #include "tactic/tactical.h" #include "tactic/goal_shared_occs.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/rewriter/bool_rewriter.h" #include "tactic/core/simplify_tactic.h" #include "util/cooperate.h" @@ -80,7 +80,7 @@ class tseitin_cnf_tactic : public tactic { frame(app * n):m_t(n), m_first(true) {} }; - typedef filter_model_converter mc; + typedef generic_model_converter mc; ast_manager & m; svector m_frame_stack; @@ -344,7 +344,7 @@ class tseitin_cnf_tactic : public tactic { app * v = m.mk_fresh_const(0, m.mk_bool_sort()); m_fresh_vars.push_back(v); if (m_mc) - m_mc->insert(v->get_decl()); + m_mc->hide(v->get_decl()); return v; } @@ -817,7 +817,7 @@ class tseitin_cnf_tactic : public tactic { m_frame_stack.reset(); m_clauses.reset(); if (m_produce_models) - m_mc = alloc(filter_model_converter, m); + m_mc = alloc(generic_model_converter, m); else m_mc = 0; diff --git a/src/tactic/extension_model_converter.h b/src/tactic/extension_model_converter.h index 7ee6c68f5..26f1611ef 100644 --- a/src/tactic/extension_model_converter.h +++ b/src/tactic/extension_model_converter.h @@ -10,6 +10,8 @@ Abstract: Model converter that introduces new interpretations into a model. It used to be called elim_var_model_converter + TBD: special case of generic_model_converter + Author: Leonardo (leonardo) 2011-10-21 diff --git a/src/tactic/filter_model_converter.cpp b/src/tactic/filter_model_converter.cpp deleted file mode 100644 index 7400063e1..000000000 --- a/src/tactic/filter_model_converter.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - filter_model_converter.cpp - -Abstract: - - Filter decls from a model - -Author: - - Leonardo (leonardo) 2011-05-06 - -Notes: - ---*/ -#include "tactic/filter_model_converter.h" -#include "model/model_v2_pp.h" - -filter_model_converter::~filter_model_converter() { -} - -void filter_model_converter::operator()(model_ref & old_model, unsigned goal_idx) { - TRACE("filter_mc", tout << "before filter_model_converter\n"; model_v2_pp(tout, *old_model); display(tout);); - ast_fast_mark1 fs; - unsigned num = m_decls.size(); - for (unsigned i = 0; i < num; i++) - fs.mark(m_decls.get(i)); - model * new_model = alloc(model, m()); - num = old_model->get_num_constants(); - for (unsigned i = 0; i < num; i++) { - func_decl * f = old_model->get_constant(i); - if (fs.is_marked(f)) - continue; - expr * fi = old_model->get_const_interp(f); - new_model->register_decl(f, fi); - } - num = old_model->get_num_functions(); - for (unsigned i = 0; i < num; i++) { - func_decl * f = old_model->get_function(i); - if (fs.is_marked(f)) - continue; - func_interp * fi = old_model->get_func_interp(f); - SASSERT(fi); - new_model->register_decl(f, fi->copy()); - } - new_model->copy_usort_interps(*old_model); - old_model = new_model; - TRACE("filter_mc", tout << "after filter_model_converter\n"; model_v2_pp(tout, *old_model);); -} - -void filter_model_converter::operator()(svector & labels, unsigned goal_idx) { -} - -void filter_model_converter::display(std::ostream & out) { - for (func_decl* f : m_decls) { - display_del(out, f); - } -} - -model_converter * filter_model_converter::translate(ast_translation & translator) { - filter_model_converter * res = alloc(filter_model_converter, translator.to()); - for (func_decl* f : m_decls) - res->m_decls.push_back(translator(f)); - return res; -} - -void filter_model_converter::collect(ast_pp_util& visitor) { - m_env = &visitor.env(); - for (func_decl* f : m_decls) visitor.coll.visit_func(f); -} - diff --git a/src/tactic/filter_model_converter.h b/src/tactic/filter_model_converter.h deleted file mode 100644 index 2c3361808..000000000 --- a/src/tactic/filter_model_converter.h +++ /dev/null @@ -1,56 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - filter_model_converter.h - -Abstract: - - Filter decls from a model - -Author: - - Leonardo (leonardo) 2011-05-06 - -Notes: - ---*/ -#ifndef FILTER_MODEL_CONVERTER_H_ -#define FILTER_MODEL_CONVERTER_H_ - -#include "tactic/model_converter.h" -#include "ast/ast_pp_util.h" - -class filter_model_converter : public model_converter { - func_decl_ref_vector m_decls; -public: - filter_model_converter(ast_manager & m): m_decls(m) {} - - virtual ~filter_model_converter(); - - ast_manager & m() const { return m_decls.get_manager(); } - - virtual void operator()(model_ref & md, unsigned goal_idx); - - virtual void operator()(svector & labels, unsigned goal_idx); - - virtual void operator()(model_ref & md) { operator()(md, 0); } // TODO: delete - - virtual void cancel() {} - - virtual void display(std::ostream & out); - - void insert(func_decl * d) { - m_decls.push_back(d); - } - - virtual model_converter * translate(ast_translation & translator); - - virtual void collect(ast_pp_util& visitor); - -}; - -typedef ref filter_model_converter_ref; - -#endif diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index f8a701003..629004869 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -85,3 +85,7 @@ void generic_model_converter::collect(ast_pp_util& visitor) { if (e.m_def) visitor.coll.visit(e.m_def); } } + +void generic_model_converter::operator()(expr_ref& fml) { + NOT_IMPLEMENTED_YET(); +} diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index 434514ce6..c58d0d029 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -38,6 +38,8 @@ public: virtual ~generic_model_converter() { } + void hide(expr* e) { SASSERT(is_app(e) && to_app(e)->get_num_args() == 0); hide(to_app(e)->get_decl()); } + void hide(func_decl * f) { m_entries.push_back(entry(f, 0, m, HIDE)); } void add(func_decl * d, expr* e) { m_entries.push_back(entry(d, e, m, ADD)); } @@ -55,6 +57,8 @@ public: virtual model_converter * translate(ast_translation & translator); virtual void collect(ast_pp_util& visitor); + + void operator()(expr_ref& fml) override; }; typedef ref generic_model_converter_ref; diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index f7597be07..720ae1916 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -45,12 +45,19 @@ public: SASSERT(goal_idx == 0); operator()(m); } - virtual void operator()(labels_vec & r, unsigned goal_idx) {} + virtual void operator()(labels_vec & r, unsigned goal_idx) {} virtual model_converter * translate(ast_translation & translator) = 0; virtual void collect(ast_pp_util& visitor) { m_env = &visitor.env(); } + + /** + \brief we are adding a formula to the context of the model converter. + The operator has as side effect of adding definitions as assertions to the + formula and removing these definitions from the model converter. + */ + virtual void operator()(expr_ref& formula) { UNREACHABLE(); } }; typedef ref model_converter_ref; diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index c99ea545a..e389c960c 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -49,7 +49,7 @@ Revision History: #include "smt/tactic/smt_tactic.h" #include "ast/rewriter/rewriter.h" #include "nlsat/tactic/nlsat_tactic.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "util/obj_pair_hashtable.h" #include "ast/rewriter/rewriter_def.h" #include "ast/ast_pp.h" @@ -73,7 +73,7 @@ class nl_purify_tactic : public tactic { arith_util m_util; params_ref m_params; bool m_produce_proofs; - ref m_fmc; + ref m_fmc; tactic_ref m_nl_tac; // nlsat tactic goal_ref m_nl_g; // nlsat goal ref m_solver; // SMT solver @@ -133,7 +133,7 @@ public: } r = m.mk_fresh_const(0, u().mk_real()); m_new_reals.push_back(to_app(r)); - m_owner.m_fmc->insert(to_app(r)->get_decl()); + m_owner.m_fmc->hide(r); m_interface_cache.insert(arg, r); expr_ref eq(m); eq = m.mk_eq(r, arg); @@ -159,7 +159,7 @@ public: result = m.mk_fresh_const(0, m.mk_bool_sort()); m_polarities.insert(result, pol); m_new_preds.push_back(to_app(result)); - m_owner.m_fmc->insert(to_app(result)->get_decl()); + m_owner.m_fmc->hide(result); if (pol != pol_neg) { m_owner.m_nl_g->assert_expr(m.mk_or(m.mk_not(result), old_pred)); } @@ -491,7 +491,7 @@ private: pred = m.mk_fresh_const(0, m.mk_bool_sort()); m_eq_preds.push_back(pred); m_eq_values.push_back(l_true); - m_fmc->insert(to_app(pred)->get_decl()); + m_fmc->hide(pred); nl_g->assert_expr(m.mk_or(m.mk_not(pred), m.mk_eq(w, v))); nl_g->assert_expr(m.mk_or(pred, m.mk_not(m.mk_eq(w, v)))); m_solver->assert_expr(m.mk_iff(pred, m.mk_eq(w, v))); @@ -761,7 +761,7 @@ public: rw r(*this); expr_ref_vector clauses(m); m_nl_g = alloc(goal, m, true, false); - m_fmc = alloc(filter_model_converter, m); + m_fmc = alloc(generic_model_converter, m); // first hoist interface variables, // then annotate subformulas by polarities, diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index c0e5e0a46..ef8012dd9 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -21,7 +21,7 @@ Notes: #include "solver/solver_na2as.h" #include "tactic/tactic.h" #include "ast/rewriter/pb2bv_rewriter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "tactic/extension_model_converter.h" #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" @@ -86,7 +86,7 @@ public: return result; } - virtual void assert_expr(expr * t) { + virtual void assert_expr_core(expr * t) { unsigned i = m_assertions.size(); m_assertions.push_back(t); while (i < m_assertions.size()) { @@ -209,10 +209,8 @@ private: if (m_bv_fns.empty()) { return; } - filter_model_converter filter(m); - for (unsigned i = 0; i < m_bv_fns.size(); ++i) { - filter.insert(m_bv_fns[i].get()); - } + generic_model_converter filter(m); + for (func_decl* f : m_bv_fns) filter.hide(f); filter(mdl, 0); } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 4722f9289..19b5374ac 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -26,7 +26,7 @@ Notes: #include "model/model_smt2_pp.h" #include "tactic/tactic.h" #include "tactic/extension_model_converter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "tactic/portfolio/enum2bv_solver.h" #include "solver/solver_na2as.h" #include "ast/rewriter/enum2bv_rewriter.h" @@ -58,7 +58,7 @@ public: return result; } - virtual void assert_expr(expr * t) { + virtual void assert_expr_core(expr * t) { expr_ref tmp(t, m); expr_ref_vector bounds(m); proof_ref tmp_proof(m); @@ -164,9 +164,9 @@ public: } void filter_model(model_ref& mdl) { - filter_model_converter filter(m); + generic_model_converter filter(m); for (auto const& kv : m_rewriter.enum2bv()) { - filter.insert(kv.m_value); + filter.hide(kv.m_value); } filter(mdl, 0); } diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 8a6c6fa15..e9c6d76aa 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -549,7 +549,7 @@ public: expr_ref_vector clauses(m); ptr_vector assumptions; obj_map bool2dep; - ref fmc; + ref fmc; extract_clauses_and_dependencies(g, clauses, assumptions, bool2dep, fmc); for (expr * clause : clauses) { s->assert_expr(clause); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index f6a7b1622..334d14d86 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -21,7 +21,7 @@ Notes: #include "tactic/tactic.h" #include "ast/rewriter/pb2bv_rewriter.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" @@ -57,7 +57,7 @@ public: return result; } - virtual void assert_expr(expr * t) { + virtual void assert_expr_core(expr * t) { m_assertions.push_back(t); } @@ -113,10 +113,10 @@ public: if (m_rewriter.fresh_constants().empty()) { return; } - filter_model_converter filter(m); + generic_model_converter filter(m); func_decl_ref_vector const& fns = m_rewriter.fresh_constants(); - for (unsigned i = 0; i < fns.size(); ++i) { - filter.insert(fns[i]); + for (func_decl* f : fns) { + filter.hide(f); } filter(mdl, 0); } @@ -138,8 +138,8 @@ private: proof_ref proof(m); expr_ref fml1(m), fml(m); expr_ref_vector fmls(m); - for (unsigned i = 0; i < m_assertions.size(); ++i) { - m_th_rewriter(m_assertions[i].get(), fml1, proof); + for (expr* a : m_assertions) { + m_th_rewriter(a, fml1, proof); m_rewriter(fml1, fml, proof); m_solver->assert_expr(fml); } diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index ba35bac84..1e0eabac6 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -18,10 +18,9 @@ Revision History: #include "tactic/sine_filter.h" #include "tactic/tactical.h" -#include "tactic/filter_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/datatype_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/filter_model_converter.h" #include "tactic/extension_model_converter.h" #include "ast/rewriter/var_subst.h" #include "ast/ast_util.h" @@ -69,7 +68,7 @@ public: result.push_back(g.get()); TRACE("sine", result[0]->display(tout);); SASSERT(g->is_well_sorted()); - filter_model_converter * fmc = alloc(filter_model_converter, m); + generic_model_converter * fmc = alloc(generic_model_converter, m); mc = fmc; } From dc0b2a8acfd91e77d8b7bb9a6bc49263a0dd7125 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 17 Nov 2017 17:25:35 -0800 Subject: [PATCH 0343/1283] remove extension model converter Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_coi_filter.cpp | 14 +++--- src/tactic/CMakeLists.txt | 1 - src/tactic/arith/fix_dl_var_tactic.cpp | 6 +-- src/tactic/arith/lia2pb_tactic.cpp | 13 ++--- src/tactic/arith/nla2bv_tactic.cpp | 6 +-- src/tactic/arith/normalize_bounds_tactic.cpp | 13 ++--- src/tactic/arith/purify_arith_tactic.cpp | 5 +- src/tactic/arith/recover_01_tactic.cpp | 15 +++--- src/tactic/bv/bv_size_reduction_tactic.cpp | 5 +- src/tactic/bv/bvarray2uf_rewriter.cpp | 11 ++--- src/tactic/bv/bvarray2uf_rewriter.h | 6 +-- src/tactic/bv/bvarray2uf_tactic.cpp | 6 +-- src/tactic/bv/dt2bv_tactic.cpp | 6 +-- src/tactic/core/reduce_args_tactic.cpp | 14 ++---- src/tactic/core/solve_eqs_tactic.cpp | 15 ++---- src/tactic/extension_model_converter.h | 48 ------------------- src/tactic/generic_model_converter.cpp | 2 +- src/tactic/generic_model_converter.h | 2 + .../portfolio/bounded_int2bv_solver.cpp | 14 +++--- src/tactic/portfolio/enum2bv_solver.cpp | 5 +- src/tactic/sine_filter.cpp | 1 - src/tactic/ufbv/macro_finder_tactic.cpp | 6 +-- src/tactic/ufbv/quasi_macros_tactic.cpp | 6 +-- 23 files changed, 69 insertions(+), 151 deletions(-) delete mode 100644 src/tactic/extension_model_converter.h diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 31188bf43..a75c08ec4 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -21,7 +21,7 @@ Author: #include "muz/dataflow/dataflow.h" #include "muz/dataflow/reachability.h" #include "ast/ast_pp.h" -#include "tactic/extension_model_converter.h" +#include "tactic/generic_model_converter.h" namespace datalog { rule_set * mk_coi_filter::operator()(rule_set const & source) { @@ -90,10 +90,10 @@ namespace datalog { // set to false each unreached predicate if (m_context.get_model_converter()) { - extension_model_converter* mc0 = alloc(extension_model_converter, m); - for (dataflow_engine::iterator it = engine.begin(); it != engine.end(); it++) { - if (!it->m_value.is_reachable()) { - mc0->insert(it->m_key, m.mk_false()); + generic_model_converter* mc0 = alloc(generic_model_converter, m); + for (auto const& kv : engine) { + if (!kv.m_value.is_reachable()) { + mc0->add(kv.m_key, m.mk_false()); } } m_context.add_model_converter(mc0); @@ -127,7 +127,7 @@ namespace datalog { if (res && m_context.get_model_converter()) { func_decl_set::iterator end = pruned_preds.end(); func_decl_set::iterator it = pruned_preds.begin(); - extension_model_converter* mc0 = alloc(extension_model_converter, m); + generic_model_converter* mc0 = alloc(generic_model_converter, m); for (; it != end; ++it) { const rule_vector& rules = source.get_predicate_rules(*it); expr_ref_vector fmls(m); @@ -144,7 +144,7 @@ namespace datalog { } expr_ref fml(m); fml = m.mk_or(fmls.size(), fmls.c_ptr()); - mc0->insert(*it, fml); + mc0->add(*it, fml); } m_context.add_model_converter(mc0); } diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index 04900fcbe..8e1ae8cd5 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -1,7 +1,6 @@ z3_add_component(tactic SOURCES equiv_proof_converter.cpp - extension_model_converter.cpp generic_model_converter.cpp goal.cpp goal_num_occurs.cpp diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 7ff7bd835..2abfc32ea 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -23,7 +23,7 @@ Revision History: --*/ #include "tactic/tactical.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/extension_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" #include "ast/ast_smt2_pp.h" @@ -270,8 +270,8 @@ class fix_dl_var_tactic : public tactic { m_rw.set_substitution(&subst); if (m_produce_models) { - extension_model_converter * _mc = alloc(extension_model_converter, m); - _mc->insert(var->get_decl(), zero); + generic_model_converter * _mc = alloc(generic_model_converter, m); + _mc->add(var, zero); mc = _mc; } diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index a339db51b..89c43e647 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -20,7 +20,6 @@ Revision History: #include "tactic/arith/bound_manager.h" #include "ast/rewriter/th_rewriter.h" #include "ast/for_each_expr.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" @@ -224,12 +223,10 @@ class lia2pb_tactic : public tactic { if (!check_num_bits()) throw tactic_exception("lia2pb failed, number of necessary bits exceeds specified threshold (use option :lia2pb-total-bits to increase threshold)"); - extension_model_converter * mc1 = 0; - generic_model_converter * mc2 = 0; + generic_model_converter * gmc = 0; if (m_produce_models) { - mc1 = alloc(extension_model_converter, m); - mc2 = alloc(generic_model_converter, m); - mc = concat(mc2, mc1); + gmc = alloc(generic_model_converter, m); + mc = gmc; } expr_ref zero(m); @@ -259,7 +256,7 @@ class lia2pb_tactic : public tactic { else def_args.push_back(m_util.mk_mul(m_util.mk_numeral(a, true), x_prime)); if (m_produce_models) - mc2->hide(x_prime->get_decl()); + gmc->hide(x_prime->get_decl()); a *= rational(2); } SASSERT(def_args.size() > 1); @@ -273,7 +270,7 @@ class lia2pb_tactic : public tactic { TRACE("lia2pb", tout << mk_ismt2_pp(x, m) << " -> " << dep << "\n";); subst.insert(x, def, 0, dep); if (m_produce_models) { - mc1->insert(to_app(x)->get_decl(), def); + gmc->add(x, def); } } } diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 00cb02cf6..547af63bf 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -26,7 +26,6 @@ Notes: #include "util/optional.h" #include "tactic/arith/bv2int_rewriter.h" #include "tactic/arith/bv2real_rewriter.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" #include "tactic/arith/bound_manager.h" #include "util/obj_pair_hashtable.h" @@ -98,10 +97,9 @@ class nla2bv_tactic : public tactic { reduce_bv2int(g); reduce_bv2real(g); TRACE("nla2bv", g.display(tout << "after reduce\n");); - extension_model_converter * evc = alloc(extension_model_converter, m_manager); - mc = concat(m_fmc.get(), evc); + mc = m_fmc.get(); for (unsigned i = 0; i < m_vars.size(); ++i) { - evc->insert(m_vars[i].get(), m_defs[i].get()); + m_fmc->add(m_vars[i].get(), m_defs[i].get()); } for (unsigned i = 0; i < m_bv2real.num_aux_decls(); ++i) { m_fmc->hide(m_bv2real.get_aux_decl(i)); diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index 90f92f3f7..8f95dac8a 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -21,7 +21,6 @@ Revision History: #include "tactic/tactical.h" #include "tactic/arith/bound_manager.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" @@ -98,12 +97,10 @@ class normalize_bounds_tactic : public tactic { return; } - extension_model_converter * mc1 = 0; - generic_model_converter * mc2 = 0; + generic_model_converter * gmc = 0; if (produce_models) { - mc1 = alloc(extension_model_converter, m); - mc2 = alloc(generic_model_converter, m); - mc = concat(mc2, mc1); + gmc = alloc(generic_model_converter, m); + mc = gmc; } unsigned num_norm_bounds = 0; @@ -120,8 +117,8 @@ class normalize_bounds_tactic : public tactic { expr * def = m_util.mk_add(x_prime, m_util.mk_numeral(val, s)); subst.insert(x, def); if (produce_models) { - mc1->insert(to_app(x)->get_decl(), def); - mc2->hide(x_prime->get_decl()); + gmc->add(to_app(x)->get_decl(), def); + gmc->hide(x_prime->get_decl()); } } } diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 144a13bcd..af2b3581f 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -28,7 +28,6 @@ Revision History: #include "tactic/core/simplify_tactic.h" #include "ast/rewriter/th_rewriter.h" #include "tactic/generic_model_converter.h" -#include "tactic/extension_model_converter.h" #include "ast/ast_smt2_pp.h" #include "ast/rewriter/expr_replacer.h" @@ -776,11 +775,11 @@ struct purify_arith_proc { } } if (produce_models && !m_sin_cos.empty()) { - extension_model_converter* emc = alloc(extension_model_converter, m()); + generic_model_converter* emc = alloc(generic_model_converter, m()); mc = concat(mc.get(), emc); obj_map >::iterator it = m_sin_cos.begin(), end = m_sin_cos.end(); for (; it != end; ++it) { - emc->insert(it->m_key->get_decl(), + emc->add(it->m_key->get_decl(), m().mk_ite(u().mk_ge(it->m_value.first, mk_real_zero()), u().mk_acos(it->m_value.second), u().mk_add(u().mk_acos(u().mk_uminus(it->m_value.second)), u().mk_pi()))); } diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index bd03f6901..9425b90ef 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -32,7 +32,6 @@ Revision History: --*/ #include "tactic/tactical.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" #include "ast/arith_decl_plugin.h" #include "ast/expr_substitution.h" @@ -112,8 +111,7 @@ class recover_01_tactic : public tactic { } // temporary fields used by operator() and process - extension_model_converter * mc1; - generic_model_converter * mc2; + generic_model_converter * gmc; expr_substitution * subst; goal_ref new_goal; obj_map bool2int; @@ -205,8 +203,8 @@ class recover_01_tactic : public tactic { expr * bool_def = m.mk_eq(var, m_util.mk_numeral(rational(1), true)); subst->insert(atom, bool_def); if (m_produce_models) { - mc2->hide(to_app(var)->get_decl()); - mc1->insert(to_app(atom)->get_decl(), bool_def); + gmc->hide(var); + gmc->add(to_app(atom)->get_decl(), bool_def); } m.inc_ref(atom); m.inc_ref(var); @@ -288,7 +286,7 @@ class recover_01_tactic : public tactic { TRACE("recover_01", tout << x->get_name() << " --> " << mk_ismt2_pp(x_def, m) << "\n";); subst->insert(m.mk_const(x), x_def); if (m_produce_models) { - mc1->insert(x, x_def); + gmc->add(x, x_def); } return true; } @@ -328,9 +326,8 @@ class recover_01_tactic : public tactic { } if (m_produce_models) { - mc1 = alloc(extension_model_converter, m); - mc2 = alloc(generic_model_converter, m); - mc = concat(mc2, mc1); + gmc = alloc(generic_model_converter, m); + mc = gmc; } dec_ref_key_values(m, bool2int); diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index c62e1177d..4435bf6a3 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -24,7 +24,6 @@ Notes: #include "tactic/tactical.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" #include "ast/ast_smt2_pp.h" @@ -51,7 +50,7 @@ tactic * mk_bv_size_reduction_tactic(ast_manager & m, params_ref const & p) { struct bv_size_reduction_tactic::imp { typedef rational numeral; - typedef extension_model_converter bv_size_reduction_mc; + typedef generic_model_converter bv_size_reduction_mc; ast_manager & m; bv_util m_util; @@ -267,7 +266,7 @@ struct bv_size_reduction_tactic::imp { if (m_produce_models) { if (!m_mc) m_mc = alloc(bv_size_reduction_mc, m); - m_mc->insert(v->get_decl(), new_def); + m_mc->add(v, new_def); if (!m_fmc && new_const) m_fmc = alloc(generic_model_converter, m); if (new_const) diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp index 1d96ffc35..c9efc16d6 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.cpp +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -37,7 +37,6 @@ bvarray2uf_rewriter_cfg::bvarray2uf_rewriter_cfg(ast_manager & m, params_ref con m_bindings(m), m_bv_util(m), m_array_util(m), - m_emc(0), m_fmc(0), extra_assertions(m) { updt_params(p); @@ -115,9 +114,8 @@ func_decl_ref bvarray2uf_rewriter_cfg::mk_uf_for_array(expr * e) { bv_f = m_manager.mk_fresh_func_decl("f_t", "", 1, &domain, range); TRACE("bvarray2uf_rw", tout << "for " << mk_ismt2_pp(e, m_manager) << " new func_decl is " << mk_ismt2_pp(bv_f, m_manager) << std::endl; ); if (is_uninterp_const(e)) { - if (m_emc) - m_emc->insert(to_app(e)->get_decl(), - m_array_util.mk_as_array(bv_f)); + if (m_fmc) + m_fmc->add(e, m_array_util.mk_as_array(bv_f)); } else if (m_fmc) m_fmc->hide(bv_f); @@ -191,9 +189,8 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr bv_f = m_manager.mk_fresh_func_decl("f_t", "", 1, &domain, range); TRACE("bvarray2uf_rw", tout << mk_ismt2_pp(e, m_manager) << " -> " << bv_f->get_name() << std::endl; ); if (is_uninterp_const(e)) { - if (m_emc) - m_emc->insert(e->get_decl(), - m_array_util.mk_as_array(bv_f)); + if (m_fmc) + m_fmc->add(e, m_array_util.mk_as_array(bv_f)); } else if (m_fmc) m_fmc->hide(bv_f); diff --git a/src/tactic/bv/bvarray2uf_rewriter.h b/src/tactic/bv/bvarray2uf_rewriter.h index 0fe5762ae..9984d3469 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.h +++ b/src/tactic/bv/bvarray2uf_rewriter.h @@ -21,7 +21,6 @@ Notes: #define BVARRAY2UF_REWRITER_H_ #include "ast/rewriter/rewriter.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" class bvarray2uf_rewriter_cfg : public default_rewriter_cfg { @@ -30,7 +29,6 @@ class bvarray2uf_rewriter_cfg : public default_rewriter_cfg { sort_ref_vector m_bindings; bv_util m_bv_util; array_util m_array_util; - extension_model_converter * m_emc; generic_model_converter * m_fmc; obj_map m_arrays_fs; @@ -59,7 +57,7 @@ public: expr_ref_vector extra_assertions; - void set_mcs(extension_model_converter * emc, generic_model_converter * fmc) { m_emc = emc; m_fmc = fmc; } + void set_mcs(generic_model_converter * fmc) { m_fmc = fmc; } protected: sort * get_index_sort(expr * e); @@ -79,7 +77,7 @@ struct bvarray2uf_rewriter : public rewriter_tpl { m_cfg(m, p) { } - void set_mcs(extension_model_converter * emc, generic_model_converter * fmc) { m_cfg.set_mcs(emc, fmc); } + void set_mcs(generic_model_converter * fmc) { m_cfg.set_mcs(fmc); } }; #endif diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index af74a2d8f..3598a767c 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -20,7 +20,6 @@ Notes: #include "tactic/tactical.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" #include "ast/ast_smt2_pp.h" @@ -68,10 +67,9 @@ class bvarray2uf_tactic : public tactic { m_produce_models = g->models_enabled(); if (m_produce_models) { - extension_model_converter * emc = alloc(extension_model_converter, m_manager); generic_model_converter * fmc = alloc(generic_model_converter, m_manager); - mc = concat(emc, fmc); - m_rw.set_mcs(emc, fmc); + mc = fmc; + m_rw.set_mcs(fmc); } diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 6a1de26fe..0d83e313a 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -26,7 +26,6 @@ Revision History: #include "ast/bv_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" #include "tactic/generic_model_converter.h" -#include "tactic/extension_model_converter.h" #include "ast/rewriter/var_subst.h" #include "ast/ast_util.h" #include "ast/rewriter/enum2bv_rewriter.h" @@ -134,7 +133,6 @@ public: for (sort* s : m_non_fd_sorts) m_fd_sorts.remove(s); if (!m_fd_sorts.empty()) { - ref ext = alloc(extension_model_converter, m); ref filter = alloc(generic_model_converter, m); enum2bv_rewriter rw(m, m_params); rw.set_is_fd(&m_is_fd); @@ -155,9 +153,9 @@ public: for (auto const& kv : rw.enum2bv()) filter->hide(kv.m_value); for (auto const& kv : rw.enum2def()) - ext->insert(kv.m_key, kv.m_value); + filter->add(kv.m_key, kv.m_value); - mc = concat(filter.get(), ext.get()); + mc = filter.get(); report_tactic_progress(":fd-num-translated", rw.num_translated()); } g->inc_depth(); diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index aaf85eacd..a7a73ae61 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -22,7 +22,6 @@ Notes: #include "ast/has_free_vars.h" #include "util/map.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" /** @@ -394,13 +393,10 @@ struct reduce_args_tactic::imp { ptr_buffer new_args; var_ref_vector new_vars(m_manager); ptr_buffer new_eqs; - extension_model_converter * e_mc = alloc(extension_model_converter, m_manager); generic_model_converter * f_mc = alloc(generic_model_converter, m_manager); - decl2arg2func_map::iterator it = decl2arg2funcs.begin(); - decl2arg2func_map::iterator end = decl2arg2funcs.end(); - for (; it != end; ++it) { - func_decl * f = it->m_key; - arg2func * map = it->m_value; + for (auto const& kv : decl2arg2funcs) { + func_decl * f = kv.m_key; + arg2func * map = kv.m_value; expr * def = 0; SASSERT(decl2args.contains(f)); bit_vector & bv = decl2args.find(f); @@ -438,9 +434,9 @@ struct reduce_args_tactic::imp { } } SASSERT(def); - e_mc->insert(f, def); + f_mc->add(f, def); } - return concat(f_mc, e_mc); + return f_mc; } void operator()(goal & g, model_converter_ref & mc) { diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 65d474182..c4f315985 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include "tactic/tactical.h" #include "ast/rewriter/expr_replacer.h" -#include "tactic/extension_model_converter.h" +#include "tactic/generic_model_converter.h" #include "ast/occurs.h" #include "util/cooperate.h" #include "tactic/goal_shared_occs.h" @@ -26,7 +26,7 @@ Revision History: class solve_eqs_tactic : public tactic { struct imp { - typedef extension_model_converter gmc; + typedef generic_model_converter gmc; ast_manager & m_manager; expr_replacer * m_r; @@ -509,10 +509,8 @@ class solve_eqs_tactic : public tactic { expr_ref new_def(m()); proof_ref new_pr(m()); expr_dependency_ref new_dep(m()); - unsigned size = m_ordered_vars.size(); - for (unsigned idx = 0; idx < size; idx++) { + for (app * v : m_ordered_vars) { checkpoint(); - expr * v = m_ordered_vars[idx]; expr * def = 0; proof * pr = 0; expr_dependency * dep = 0; @@ -609,16 +607,13 @@ class solve_eqs_tactic : public tactic { if (m_produce_models) { if (mc.get() == 0) mc = alloc(gmc, m()); - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - app * v = *it; + for (app * v : m_ordered_vars) { expr * def = 0; proof * pr; expr_dependency * dep; m_norm_subst->find(v, def, pr, dep); SASSERT(def != 0); - static_cast(mc.get())->insert(v->get_decl(), def); + static_cast(mc.get())->add(v, def); } } } diff --git a/src/tactic/extension_model_converter.h b/src/tactic/extension_model_converter.h deleted file mode 100644 index 26f1611ef..000000000 --- a/src/tactic/extension_model_converter.h +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - extension_model_converter.h - -Abstract: - - Model converter that introduces new interpretations into a model. - It used to be called elim_var_model_converter - - TBD: special case of generic_model_converter - -Author: - - Leonardo (leonardo) 2011-10-21 - -Notes: - ---*/ -#ifndef EXTENSION_MODEL_CONVERTER_H_ -#define EXTENSION_MODEL_CONVERTER_H_ - -#include "ast/ast.h" -#include "tactic/model_converter.h" - -class extension_model_converter : public model_converter { - func_decl_ref_vector m_vars; - expr_ref_vector m_defs; -public: - extension_model_converter(ast_manager & m): m_vars(m), m_defs(m) { - } - - virtual ~extension_model_converter(); - - ast_manager & m() const { return m_vars.get_manager(); } - - virtual void operator()(model_ref & md, unsigned goal_idx); - - virtual void display(std::ostream & out); - - // register a variable that was eliminated - void insert(func_decl * v, expr * def); - - virtual model_converter * translate(ast_translation & translator); -}; -#endif diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 629004869..03361cac1 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -27,7 +27,7 @@ void generic_model_converter::operator()(model_ref & md, unsigned goal_idx) { std::cout << "model converter\n"; TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout);); model_evaluator ev(*(md.get())); - ev.set_model_completion(false); + ev.set_model_completion(true); ev.set_expand_array_equalities(false); expr_ref val(m); unsigned arity; diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index c58d0d029..014725bb0 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -43,6 +43,8 @@ public: void hide(func_decl * f) { m_entries.push_back(entry(f, 0, m, HIDE)); } void add(func_decl * d, expr* e) { m_entries.push_back(entry(d, e, m, ADD)); } + + void add(expr * d, expr* e) { SASSERT(is_app(d) && to_app(d)->get_num_args() == 0); m_entries.push_back(entry(to_app(d)->get_decl(), e, m, ADD)); } virtual void operator()(model_ref & md, unsigned goal_idx); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index ef8012dd9..bc7c5d49c 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -22,7 +22,6 @@ Notes: #include "tactic/tactic.h" #include "ast/rewriter/pb2bv_rewriter.h" #include "tactic/generic_model_converter.h" -#include "tactic/extension_model_converter.h" #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" #include "tactic/arith/bound_manager.h" @@ -215,17 +214,16 @@ private: } void extend_model(model_ref& mdl) { - extension_model_converter ext(m); - obj_map::iterator it = m_int2bv.begin(), end = m_int2bv.end(); - for (; it != end; ++it) { + generic_model_converter ext(m); + for (auto const& kv : m_int2bv) { rational offset; - VERIFY (m_bv2offset.find(it->m_value, offset)); - expr_ref value(m_bv.mk_bv2int(m.mk_const(it->m_value)), m); + VERIFY (m_bv2offset.find(kv.m_value, offset)); + expr_ref value(m_bv.mk_bv2int(m.mk_const(kv.m_value)), m); if (!offset.is_zero()) { value = m_arith.mk_add(value, m_arith.mk_numeral(offset, true)); } - TRACE("int2bv", tout << mk_pp(it->m_key, m) << " " << value << "\n";); - ext.insert(it->m_key, value); + TRACE("int2bv", tout << mk_pp(kv.m_key, m) << " " << value << "\n";); + ext.add(kv.m_key, value); } ext(mdl, 0); } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 19b5374ac..50fb7d925 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -25,7 +25,6 @@ Notes: #include "ast/ast_pp.h" #include "model/model_smt2_pp.h" #include "tactic/tactic.h" -#include "tactic/extension_model_converter.h" #include "tactic/generic_model_converter.h" #include "tactic/portfolio/enum2bv_solver.h" #include "solver/solver_na2as.h" @@ -172,9 +171,9 @@ public: } void extend_model(model_ref& mdl) { - extension_model_converter ext(m); + generic_model_converter ext(m); for (auto const& kv : m_rewriter.enum2def()) - ext.insert(kv.m_key, kv.m_value); + ext.add(kv.m_key, kv.m_value); ext(mdl, 0); } diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 1e0eabac6..64689602c 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -21,7 +21,6 @@ Revision History: #include "tactic/generic_model_converter.h" #include "ast/datatype_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/extension_model_converter.h" #include "ast/rewriter/var_subst.h" #include "ast/ast_util.h" #include "util/obj_pair_hashtable.h" diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index 3a482f37c..7a1838452 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -19,7 +19,7 @@ Notes: #include "tactic/tactical.h" #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" -#include "tactic/extension_model_converter.h" +#include "tactic/generic_model_converter.h" #include "tactic/ufbv/macro_finder_tactic.h" class macro_finder_tactic : public tactic { @@ -69,12 +69,12 @@ class macro_finder_tactic : public tactic { produce_proofs ? new_proofs.get(i) : 0, unsat_core_enabled ? new_deps.get(i) : 0); - extension_model_converter * evmc = alloc(extension_model_converter, mm.get_manager()); + generic_model_converter * evmc = alloc(generic_model_converter, mm.get_manager()); unsigned num = mm.get_num_macros(); for (unsigned i = 0; i < num; i++) { expr_ref f_interp(mm.get_manager()); func_decl * f = mm.get_macro_interpretation(i, f_interp); - evmc->insert(f, f_interp); + evmc->add(f, f_interp); } mc = evmc; diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index 925b5a5e3..ee3cd14ec 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -17,9 +17,9 @@ Notes: --*/ #include "tactic/tactical.h" +#include "tactic/generic_model_converter.h" #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" -#include "tactic/extension_model_converter.h" #include "ast/macros/quasi_macros.h" #include "tactic/ufbv/quasi_macros_tactic.h" @@ -81,12 +81,12 @@ class quasi_macros_tactic : public tactic { produce_proofs ? proofs.get(i) : 0, produce_unsat_cores ? deps.get(i) : 0); - extension_model_converter * evmc = alloc(extension_model_converter, mm.get_manager()); + generic_model_converter * evmc = alloc(generic_model_converter, mm.get_manager()); unsigned num = mm.get_num_macros(); for (unsigned i = 0; i < num; i++) { expr_ref f_interp(mm.get_manager()); func_decl * f = mm.get_macro_interpretation(i, f_interp); - evmc->insert(f, f_interp); + evmc->add(f, f_interp); } mc = evmc; From b3bd9b89b541bff02bdad7db735394cdf71cc53d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 17 Nov 2017 19:55:23 -0800 Subject: [PATCH 0344/1283] prepare for inverse model conversion for formulas Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 15 ++- src/solver/solver.cpp | 13 ++- src/tactic/bv/bit_blaster_model_converter.cpp | 31 ++++-- src/tactic/extension_model_converter.cpp | 94 ------------------- src/tactic/horn_subsume_model_converter.cpp | 8 +- src/tactic/horn_subsume_model_converter.h | 13 +-- src/tactic/model_converter.cpp | 44 +++++---- 7 files changed, 79 insertions(+), 139 deletions(-) delete mode 100644 src/tactic/extension_model_converter.cpp diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index f037a0e26..d730ea0ee 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -881,8 +881,9 @@ struct sat2goal::imp { // Wrapper for sat::model_converter: converts it into an "AST level" model_converter. class sat_model_converter : public model_converter { - sat::model_converter m_mc; - expr_ref_vector m_var2expr; + model_converter_ref m_cached_mc; + sat::model_converter m_mc; + expr_ref_vector m_var2expr; generic_model_converter_ref m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion sat_model_converter(ast_manager & m): @@ -1025,6 +1026,9 @@ struct sat2goal::imp { if (m_fmc) m_fmc->collect(visitor); } + void operator()(expr_ref& formula) override { + NOT_IMPLEMENTED_YET(); + } }; typedef ref sat_model_converter_ref; @@ -1033,7 +1037,6 @@ struct sat2goal::imp { expr_ref_vector m_lit2expr; unsigned long long m_max_memory; bool m_learned; - unsigned m_glue; imp(ast_manager & _m, params_ref const & p):m(_m), m_lit2expr(m) { updt_params(p); @@ -1041,7 +1044,6 @@ struct sat2goal::imp { void updt_params(params_ref const & p) { m_learned = p.get_bool("learned", false); - m_glue = p.get_uint("glue", UINT_MAX); m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); } @@ -1131,7 +1133,6 @@ struct sat2goal::imp { checkpoint(); lits.reset(); sat::clause const & c = *cp; - unsigned sz = c.size(); if (asserted || m_learned || c.glue() <= s.get_config().m_gc_small_lbd) { for (sat::literal l : c) { lits.push_back(lit2expr(mc, l)); @@ -1142,8 +1143,7 @@ struct sat2goal::imp { } sat::ba_solver* get_ba_solver(sat::solver const& s) { - sat::extension* ext = s.get_extension(); - return dynamic_cast(ext); + return dynamic_cast(s.get_extension()); } void operator()(sat::solver const & s, atom2bool_var const & map, goal & r, model_converter_ref & mc) { @@ -1229,7 +1229,6 @@ sat2goal::sat2goal():m_imp(0) { void sat2goal::collect_param_descrs(param_descrs & r) { insert_max_memory(r); r.insert("learned", CPK_BOOL, "(default: false) collect also learned clauses."); - r.insert("glue", CPK_UINT, "(default: max-int) collect learned clauses with glue level below parameter."); } struct sat2goal::scoped_set_imp { diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 8f1287dab..f14467337 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -185,21 +185,20 @@ bool solver::is_literal(ast_manager& m, expr* e) { void solver::assert_expr(expr* f) { expr_ref fml(f, get_manager()); - if (mc0()) { - (*mc0())(fml); + model_converter_ref mc = get_model_converter(); + if (mc) { + (*mc)(fml); } assert_expr_core(fml); } void solver::assert_expr(expr* f, expr* t) { - // let mc0 be the model converter associated with the solver - // that converts models to their "real state". ast_manager& m = get_manager(); expr_ref fml(f, m); expr_ref a(t, m); - - if (mc0()) { - (*mc0())(fml); + model_converter_ref mc = get_model_converter(); + if (mc) { + (*mc)(fml); // (*mc0())(a); } assert_expr_core(fml, a); diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index d8dbb77a4..cdcc486a6 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -21,6 +21,7 @@ Notes: #include "tactic/model_converter.h" #include "ast/bv_decl_plugin.h" #include "ast/ast_smt2_pp.h" +#include "ast/ast_util.h" /** If TO_BOOL == true, then bit-vectors of size n were blasted into n-tuples of Booleans. @@ -171,7 +172,7 @@ struct bit_blaster_model_converter : public model_converter { return result; } - virtual void operator()(model_ref & md, unsigned goal_idx) { + void operator()(model_ref & md, unsigned goal_idx) override { SASSERT(goal_idx == 0); model * new_model = alloc(model, m()); obj_hashtable bits; @@ -181,11 +182,29 @@ struct bit_blaster_model_converter : public model_converter { md = new_model; } - virtual void operator()(model_ref & md) { + void operator()(model_ref & md) override { operator()(md, 0); } + + /** + \brief simplisic expansion operator for formulas. + It just adds back bit-vector definitions to the formula whether they are used or not. + + */ + void operator()(expr_ref& fml) override { + unsigned sz = m_vars.size(); + if (sz == 0) return; + expr_ref_vector fmls(m()); + fmls.push_back(fml); + for (unsigned i = 0; i < sz; i++) { + fmls.push_back(m().mk_eq(m().mk_const(m_vars.get(i)), m_bits.get(i))); + } + m_vars.reset(); + m_bits.reset(); + fml = mk_and(fmls); + } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { unsigned sz = m_vars.size(); for (unsigned i = 0; i < sz; i++) { display_add(out, m(), m_vars.get(i), m_bits.get(i)); @@ -196,7 +215,7 @@ protected: bit_blaster_model_converter(ast_manager & m):m_vars(m), m_bits(m) { } public: - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { bit_blaster_model_converter * res = alloc(bit_blaster_model_converter, translator.to()); for (func_decl * v : m_vars) res->m_vars.push_back(translator(v)); @@ -207,11 +226,11 @@ public: }; model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits) { - return alloc(bit_blaster_model_converter, m, const2bits); + return const2bits.empty() ? nullptr : alloc(bit_blaster_model_converter, m, const2bits); } model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map const & const2bits) { - return alloc(bit_blaster_model_converter, m, const2bits); + return const2bits.empty() ? nullptr : alloc(bit_blaster_model_converter, m, const2bits); } diff --git a/src/tactic/extension_model_converter.cpp b/src/tactic/extension_model_converter.cpp deleted file mode 100644 index 0ae4e1323..000000000 --- a/src/tactic/extension_model_converter.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - extension_model_converter.cpp - -Abstract: - -Model converter that introduces eliminated variables in a model. - -Author: - - Leonardo (leonardo) 2011-10-21 - -Notes: - ---*/ -#include "ast/ast_pp.h" -#include "ast/ast_smt2_pp.h" -#include "model/model_evaluator.h" -#include "model/model_v2_pp.h" -#include "tactic/extension_model_converter.h" - -extension_model_converter::~extension_model_converter() { -} - -#ifdef _TRACE -static void display_decls_info(std::ostream & out, model_ref & md) { - ast_manager & m = md->get_manager(); - unsigned sz = md->get_num_decls(); - for (unsigned i = 0; i < sz; i++) { - func_decl * d = md->get_decl(i); - out << d->get_name(); - out << " ("; - for (unsigned j = 0; j < d->get_arity(); j++) - out << mk_pp(d->get_domain(j), m); - out << mk_pp(d->get_range(), m); - out << ") "; - if (d->get_info()) - out << *(d->get_info()); - out << " :id " << d->get_id() << "\n"; - } -} -#endif - -void extension_model_converter::operator()(model_ref & md, unsigned goal_idx) { - SASSERT(goal_idx == 0); - TRACE("extension_mc", model_v2_pp(tout, *md); display_decls_info(tout, md);); - model_evaluator ev(*(md.get())); - ev.set_model_completion(true); - ev.set_expand_array_equalities(false); - expr_ref val(m()); - unsigned i = m_vars.size(); - while (i > 0) { - --i; - expr * def = m_defs.get(i); - ev(def, val); - TRACE("extension_mc", tout << m_vars.get(i)->get_name() << " ->\n" << mk_ismt2_pp(def, m()) << "\n==>\n" << mk_ismt2_pp(val, m()) << "\n";); - func_decl * f = m_vars.get(i); - unsigned arity = f->get_arity(); - if (arity == 0) { - md->register_decl(f, val); - } - else { - func_interp * new_fi = alloc(func_interp, m(), arity); - new_fi->set_else(val); - md->register_decl(f, new_fi); - } - } - TRACE("extension_mc", model_v2_pp(tout, *md); display_decls_info(tout, md);); -} - -void extension_model_converter::insert(func_decl * v, expr * def) { - m_vars.push_back(v); - m_defs.push_back(def); -} - - -void extension_model_converter::display(std::ostream & out) { - for (unsigned i = 0; i < m_vars.size(); i++) { - display_add(out, m(), m_vars.get(i), m_defs.get(i)); - } -} - -model_converter * extension_model_converter::translate(ast_translation & translator) { - extension_model_converter * res = alloc(extension_model_converter, translator.to()); - for (func_decl* v : m_vars) - res->m_vars.push_back(translator(v)); - for (expr* d : m_defs) - res->m_defs.push_back(translator(d)); - return res; -} - diff --git a/src/tactic/horn_subsume_model_converter.cpp b/src/tactic/horn_subsume_model_converter.cpp index cb56f9b7b..0d49a769e 100644 --- a/src/tactic/horn_subsume_model_converter.cpp +++ b/src/tactic/horn_subsume_model_converter.cpp @@ -170,6 +170,10 @@ void horn_subsume_model_converter::add_default_false_interpretation(expr* e, mod } +void horn_subsume_model_converter::operator()(expr_ref& fml) { + NOT_IMPLEMENTED_YET(); +} + void horn_subsume_model_converter::operator()(model_ref& mr) { func_decl_ref pred(m); @@ -190,11 +194,11 @@ void horn_subsume_model_converter::operator()(model_ref& mr) { add_default_false_interpretation(body, mr); SASSERT(m.is_bool(body)); - TRACE("mc", tout << "eval: " << h->get_name() << "\n" << mk_pp(body, m) << "\n";); + TRACE("mc", tout << "eval: " << h->get_name() << "\n" << body << "\n";); expr_ref tmp(body); mr->eval(tmp, body); - TRACE("mc", tout << "to:\n" << mk_pp(body, m) << "\n";); + TRACE("mc", tout << "to:\n" << body << "\n";); if (arity == 0) { expr* e = mr->get_const_interp(h); diff --git a/src/tactic/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h index 74d5882a5..9b094e575 100644 --- a/src/tactic/horn_subsume_model_converter.h +++ b/src/tactic/horn_subsume_model_converter.h @@ -58,9 +58,8 @@ class horn_subsume_model_converter : public model_converter { public: - horn_subsume_model_converter(ast_manager& m): - m(m), m_funcs(m), m_bodies(m), m_rewrite(m), - m_delay_head(m), m_delay_body(m) {} + horn_subsume_model_converter(ast_manager& m): + m(m), m_funcs(m), m_bodies(m), m_rewrite(m), m_delay_head(m), m_delay_body(m) {} bool mk_horn(expr* clause, func_decl_ref& pred, expr_ref& body); @@ -72,13 +71,15 @@ public: void insert(func_decl* p, expr* body) { m_funcs.push_back(p); m_bodies.push_back(body); } - virtual void operator()(model_ref& _m); + void operator()(model_ref& _m) override; - virtual model_converter * translate(ast_translation & translator); + void operator()(expr_ref& fml) override; + + model_converter * translate(ast_translation & translator) override; ast_manager& get_manager() { return m; } - virtual void display(std::ostream & out) {} + void display(std::ostream & out) override {} }; #endif diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 01c7a16bb..ab1e2a9bc 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -58,28 +58,33 @@ public: VERIFY(m_c1 && m_c2); } - virtual void operator()(model_ref & m) { + void operator()(model_ref & m) override { this->m_c2->operator()(m); this->m_c1->operator()(m); } - virtual void operator()(model_ref & m, unsigned goal_idx) { + void operator()(expr_ref & fml) override { + this->m_c1->operator()(fml); + this->m_c2->operator()(fml); + } + + void operator()(model_ref & m, unsigned goal_idx) override { this->m_c2->operator()(m, goal_idx); this->m_c1->operator()(m, 0); } - virtual void operator()(labels_vec & r, unsigned goal_idx) { + void operator()(labels_vec & r, unsigned goal_idx) override { this->m_c2->operator()(r, goal_idx); this->m_c1->operator()(r, 0); } - virtual char const * get_name() const { return "concat-model-converter"; } + char const * get_name() const override { return "concat-model-converter"; } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { return this->translate_core(translator); } - virtual void collect(ast_pp_util& visitor) { + void collect(ast_pp_util& visitor) override { this->m_c1->collect(visitor); this->m_c2->collect(visitor); } @@ -99,12 +104,12 @@ public: concat_star_converter(mc1, num, mc2s, szs) { } - virtual void operator()(model_ref & m) { + void operator()(model_ref & m) override { // TODO: delete method after conversion is complete UNREACHABLE(); } - virtual void operator()(model_ref & m, unsigned goal_idx) { + void operator()(model_ref & m, unsigned goal_idx) override { unsigned num = this->m_c2s.size(); for (unsigned i = 0; i < num; i++) { if (goal_idx < this->m_szs[i]) { @@ -122,7 +127,7 @@ public: UNREACHABLE(); } - virtual void operator()(labels_vec & r, unsigned goal_idx) { + void operator()(labels_vec & r, unsigned goal_idx) override { unsigned num = this->m_c2s.size(); for (unsigned i = 0; i < num; i++) { if (goal_idx < this->m_szs[i]) { @@ -140,9 +145,9 @@ public: UNREACHABLE(); } - virtual char const * get_name() const { return "concat-star-model-converter"; } + char const * get_name() const override { return "concat-star-model-converter"; } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { return this->translate_core(translator); } }; @@ -173,22 +178,28 @@ public: virtual ~model2mc() {} - virtual void operator()(model_ref & m) { + void operator()(model_ref & m) override { m = m_model; } - virtual void operator()(model_ref & m, unsigned goal_idx) { + void operator()(model_ref & m, unsigned goal_idx) override { m = m_model; } - virtual void operator()(labels_vec & r, unsigned goal_idx) { + void operator()(labels_vec & r, unsigned goal_idx) { r.append(m_labels.size(), m_labels.c_ptr()); } - virtual void cancel() { + void operator()(expr_ref& fml) override { + expr_ref r(m_model->get_manager()); + m_model->eval(fml, r, false); + fml = r; + } + + void cancel() override { } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(model->model-converter-wrapper\n"; model_v2_pp(out, *m_model); out << ")\n"; @@ -198,6 +209,7 @@ public: model * m = m_model->translate(translator); return alloc(model2mc, m); } + }; model_converter * model2model_converter(model * m) { From df6b1a707ebc406bf47bc9ed1bdbeb98248ca39c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 17 Nov 2017 23:32:29 -0800 Subject: [PATCH 0345/1283] remove proof_converter from tactic application, removing nlsat_tactic Signed-off-by: Nikolaj Bjorner --- src/CMakeLists.txt | 1 - .../ackermannize_bv_tactic.cpp | 4 +- src/api/api_tactic.cpp | 3 +- src/cmd_context/echo_tactic.cpp | 6 +- src/cmd_context/tactic_cmds.cpp | 3 +- .../subpaving/tactic/subpaving_tactic.cpp | 2 - src/muz/fp/horn_tactic.cpp | 8 +- src/muz/pdr/pdr_context.cpp | 3 +- src/muz/pdr/pdr_farkas_learner.cpp | 3 +- src/muz/spacer/spacer_context.cpp | 3 +- src/muz/spacer/spacer_legacy_frames.cpp | 3 +- src/muz/spacer/spacer_util.cpp | 6 +- src/nlsat/tactic/nlsat_tactic.cpp | 6 +- src/opt/opt_context.cpp | 3 +- src/qe/nlqsat.cpp | 6 +- src/qe/qe_lite.cpp | 6 +- src/qe/qe_sat_tactic.cpp | 1 - src/qe/qe_tactic.cpp | 6 +- src/qe/qsat.cpp | 3 +- src/sat/sat_solver/inc_sat_solver.cpp | 3 +- src/sat/tactic/sat_tactic.cpp | 6 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 3 +- src/smt/tactic/smt_tactic.cpp | 3 +- src/smt/tactic/unit_subsumption_tactic.cpp | 5 +- src/solver/solver2tactic.cpp | 5 +- src/tactic/aig/aig_tactic.cpp | 3 +- src/tactic/arith/add_bounds_tactic.cpp | 8 +- src/tactic/arith/arith_bounds_tactic.cpp | 1 - src/tactic/arith/card2bv_tactic.cpp | 3 +- src/tactic/arith/degree_shift_tactic.cpp | 6 +- src/tactic/arith/diff_neq_tactic.cpp | 6 +- src/tactic/arith/elim01_tactic.cpp | 3 +- src/tactic/arith/eq2bv_tactic.cpp | 3 +- src/tactic/arith/factor_tactic.cpp | 6 +- src/tactic/arith/fix_dl_var_tactic.cpp | 6 +- src/tactic/arith/fm_tactic.cpp | 6 +- src/tactic/arith/lia2card_tactic.cpp | 3 +- src/tactic/arith/lia2pb_tactic.cpp | 6 +- src/tactic/arith/nla2bv_tactic.cpp | 5 +- src/tactic/arith/normalize_bounds_tactic.cpp | 6 +- src/tactic/arith/pb2bv_tactic.cpp | 6 +- src/tactic/arith/propagate_ineqs_tactic.cpp | 5 +- src/tactic/arith/purify_arith_tactic.cpp | 3 +- src/tactic/arith/recover_01_tactic.cpp | 6 +- src/tactic/bv/bit_blaster_tactic.cpp | 6 +- src/tactic/bv/bv1_blaster_tactic.cpp | 6 +- src/tactic/bv/bv_bound_chk_tactic.cpp | 4 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 5 +- src/tactic/bv/bvarray2uf_tactic.cpp | 6 +- src/tactic/bv/dt2bv_tactic.cpp | 3 +- src/tactic/bv/elim_small_bv_tactic.cpp | 6 +- src/tactic/bv/max_bv_sharing_tactic.cpp | 6 +- src/tactic/core/blast_term_ite_tactic.cpp | 6 +- src/tactic/core/cofactor_term_ite_tactic.cpp | 3 +- src/tactic/core/collect_statistics_tactic.cpp | 2 +- src/tactic/core/ctx_simplify_tactic.cpp | 3 +- src/tactic/core/ctx_simplify_tactic.h | 1 - src/tactic/core/der_tactic.cpp | 3 +- src/tactic/core/distribute_forall_tactic.cpp | 3 +- src/tactic/core/dom_simplify_tactic.cpp | 3 +- src/tactic/core/dom_simplify_tactic.h | 1 - src/tactic/core/elim_term_ite_tactic.cpp | 6 +- src/tactic/core/elim_uncnstr_tactic.cpp | 8 +- src/tactic/core/injectivity_tactic.cpp | 6 +- src/tactic/core/nnf_tactic.cpp | 3 +- src/tactic/core/occf_tactic.cpp | 8 +- src/tactic/core/pb_preprocess_tactic.cpp | 3 +- src/tactic/core/propagate_values_tactic.cpp | 6 +- src/tactic/core/reduce_args_tactic.cpp | 5 +- src/tactic/core/simplify_tactic.cpp | 3 +- src/tactic/core/simplify_tactic.h | 1 - src/tactic/core/solve_eqs_tactic.cpp | 6 +- src/tactic/core/split_clause_tactic.cpp | 5 +- src/tactic/core/symmetry_reduce_tactic.cpp | 4 +- src/tactic/core/tseitin_cnf_tactic.cpp | 6 +- src/tactic/fpa/fpa2bv_tactic.cpp | 6 +- src/tactic/goal.cpp | 25 +- src/tactic/goal.h | 11 + src/tactic/nlsat_smt/CMakeLists.txt | 9 - src/tactic/nlsat_smt/nl_purify_tactic.cpp | 799 ------------------ src/tactic/nlsat_smt/nl_purify_tactic.h | 35 - src/tactic/portfolio/parallel_tactic.cpp | 2 +- src/tactic/sine_filter.cpp | 3 +- src/tactic/sls/sls_tactic.cpp | 3 +- src/tactic/smtlogics/CMakeLists.txt | 3 - src/tactic/smtlogics/qfufbv_tactic.cpp | 1 - src/tactic/tactic.cpp | 19 +- src/tactic/tactic.h | 5 +- src/tactic/tactical.cpp | 181 ++-- src/tactic/ufbv/macro_finder_tactic.cpp | 6 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 6 +- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 6 +- src/util/ref_buffer.h | 3 + 93 files changed, 236 insertions(+), 1216 deletions(-) delete mode 100644 src/tactic/nlsat_smt/CMakeLists.txt delete mode 100644 src/tactic/nlsat_smt/nl_purify_tactic.cpp delete mode 100644 src/tactic/nlsat_smt/nl_purify_tactic.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5961b2a65..484d3e9f5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,7 +92,6 @@ add_subdirectory(muz/ddnf) add_subdirectory(muz/duality) add_subdirectory(muz/spacer) add_subdirectory(muz/fp) -add_subdirectory(tactic/nlsat_smt) add_subdirectory(tactic/ufbv) add_subdirectory(sat/sat_solver) add_subdirectory(tactic/smtlogics) diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index 82ef19274..b9cdc706c 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -32,7 +32,6 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { mc = 0; tactic_report report("ackermannize", *g); @@ -53,7 +52,6 @@ public: result.reset(); result.push_back(g.get()); mc = 0; - pc = 0; core = 0; return; } @@ -62,7 +60,7 @@ public: if (g->models_enabled()) { mc = mk_ackermannize_bv_model_converter(m, lackr.get_info()); } - + resg->inc_depth(); TRACE("ackermannize", resg->display(tout << "out\n");); SASSERT(resg->is_well_sorted()); diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index ccb1ce597..3ee65ba36 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -418,7 +418,8 @@ extern "C" { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); scoped_timer timer(timeout, &eh); try { - exec(*to_tactic_ref(t), new_goal, ref->m_subgoals, ref->m_mc, ref->m_pc, ref->m_core); + exec(*to_tactic_ref(t), new_goal, ref->m_subgoals, ref->m_mc, ref->m_core); + ref->m_pc = new_goal->pc(); return of_apply_result(ref); } catch (z3_exception & ex) { diff --git a/src/cmd_context/echo_tactic.cpp b/src/cmd_context/echo_tactic.cpp index 848ae5429..3b4f8962f 100644 --- a/src/cmd_context/echo_tactic.cpp +++ b/src/cmd_context/echo_tactic.cpp @@ -30,7 +30,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { #pragma omp critical (echo_tactic) { @@ -38,7 +37,7 @@ public: if (m_newline) m_ctx.regular_stream() << std::endl; } - skip_tactic::operator()(in, result, mc, pc, core); + skip_tactic::operator()(in, result, mc, core); } }; @@ -64,7 +63,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { double val = (*m_p)(*(in.get())).get_value(); #pragma omp critical (probe_value_tactic) @@ -75,7 +73,7 @@ public: if (m_newline) m_ctx.diagnostic_stream() << std::endl; } - skip_tactic::operator()(in, result, mc, pc, core); + skip_tactic::operator()(in, result, mc, core); } }; diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index cd5eff9a6..1cdde738e 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -328,7 +328,6 @@ public: goal_ref_buffer result_goals; model_converter_ref mc; - proof_converter_ref pc; expr_dependency_ref core(m); std::string reason_unknown; @@ -340,7 +339,7 @@ public: scoped_timer timer(timeout, &eh); cmd_context::scoped_watch sw(ctx); try { - exec(t, g, result_goals, mc, pc, core); + exec(t, g, result_goals, mc, core); } catch (tactic_exception & ex) { ctx.regular_stream() << "(error \"tactic failed: " << ex.msg() << "\")" << std::endl; diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index 6a7bc11e8..cb5cf9703 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -244,7 +244,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { m_imp->process(*in); @@ -252,7 +251,6 @@ public: result.reset(); result.push_back(in.get()); mc = 0; - pc = 0; core = 0; } catch (z3_exception & ex) { diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index ded33bb0d..5fd41facc 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -179,10 +179,9 @@ class horn_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("horn", *g); bool produce_proofs = g->proofs_enabled(); @@ -235,12 +234,14 @@ class horn_tactic : public tactic { } SASSERT(queries.size() == 1); q = queries[0].get(); + proof_converter_ref pc = g->pc(); if (m_is_simplify) { simplify(q, g, result, mc, pc); } else { verify(q, g, result, mc, pc); } + g->set(pc.get()); } void verify(expr* q, @@ -386,9 +387,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void collect_statistics(statistics & st) const { diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 37d80e2d6..e3681d366 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -203,10 +203,9 @@ namespace pdr { goal_ref g(alloc(goal, m, false, false, false)); for (unsigned j = 0; j < v.size(); ++j) g->assert_expr(v[j].get()); model_converter_ref mc; - proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; - tac(g, result, mc, pc, core); + tac(g, result, mc, core); SASSERT(result.size() == 1); goal* r = result[0]; v.reset(); diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 4a77d2f5f..83b0d2c00 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -521,11 +521,10 @@ namespace pdr { } expr_ref tmp(m); model_converter_ref mc; - proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result, mc, pc, core); + (*simplifier)(g, result, mc, core); lemmas.reset(); SASSERT(result.size() == 1); goal* r = result[0]; diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index b057730d8..484456640 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1368,7 +1368,6 @@ void pred_transformer::frames::simplify_formulas () unsigned level = i < m_size ? i : infty_level (); model_converter_ref mc; - proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; @@ -1395,7 +1394,7 @@ void pred_transformer::frames::simplify_formulas () } // more than one lemma at current level. simplify. - (*simplifier)(g, result, mc, pc, core); + (*simplifier)(g, result, mc, core); SASSERT(result.size () == 1); goal *r = result[0]; diff --git a/src/muz/spacer/spacer_legacy_frames.cpp b/src/muz/spacer/spacer_legacy_frames.cpp index 679736add..5c7fae9ac 100644 --- a/src/muz/spacer/spacer_legacy_frames.cpp +++ b/src/muz/spacer/spacer_legacy_frames.cpp @@ -47,10 +47,9 @@ void pred_transformer::legacy_frames::simplify_formulas(tactic& tac, goal_ref g(alloc(goal, m, false, false, false)); for (unsigned j = 0; j < v.size(); ++j) { g->assert_expr(v[j].get()); } model_converter_ref mc; - proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; - tac(g, result, mc, pc, core); + tac(g, result, mc, core); SASSERT(result.size() == 1); goal* r = result[0]; v.reset(); diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 83042cd6d..05c26b923 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -930,11 +930,10 @@ void simplify_bounds_old(expr_ref_vector& cube) { expr_ref tmp(m); model_converter_ref mc; - proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result, mc, pc, core); + (*simplifier)(g, result, mc, core); SASSERT(result.size() == 1); goal* r = result[0]; @@ -956,14 +955,13 @@ void simplify_bounds_new (expr_ref_vector &cube) { } model_converter_ref mc; - proof_converter_ref pc; expr_dependency_ref dep(m); goal_ref_buffer goals; tactic_ref prop_values = mk_propagate_values_tactic(m); tactic_ref prop_bounds = mk_propagate_ineqs_tactic(m); tactic_ref t = and_then(prop_values.get(), prop_bounds.get()); - (*t)(g, goals, mc, pc, dep); + (*t)(g, goals, mc, dep); SASSERT(goals.size() == 1); g = goals[0]; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 510f503e7..5757220b4 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -131,10 +131,9 @@ class nlsat_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("nlsat", *g); if (g->is_decided()) { @@ -235,12 +234,11 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { imp local_imp(in->m(), m_params); scoped_set_imp setter(*this, local_imp); - local_imp(in, result, mc, pc, core); + local_imp(in, result, mc, core); } catch (z3_error & ex) { throw ex; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2ab6abd79..19cfc4b9c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -747,10 +747,9 @@ namespace opt { else { set_simplify(tac0.get()); } - proof_converter_ref pc; expr_dependency_ref core(m); goal_ref_buffer result; - (*m_simplify)(g, result, m_model_converter, pc, core); + (*m_simplify)(g, result, m_model_converter, core); SASSERT(result.size() == 1); goal* r = result[0]; fmls.reset(); diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 1f9c89f89..e593e6627 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -658,11 +658,10 @@ namespace qe { fml = m.mk_iff(is_true, fml); goal_ref g = alloc(goal, m); g->assert_expr(fml); - proof_converter_ref pc; expr_dependency_ref core(m); model_converter_ref mc; goal_ref_buffer result; - (*m_nftactic)(g, result, mc, pc, core); + (*m_nftactic)(g, result, mc, core); SASSERT(result.size() == 1); TRACE("qe", result[0]->display(tout);); g2s(*result[0], m_params, m_solver, m_a2b, m_t2x); @@ -814,14 +813,13 @@ namespace qe { void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, /* out */ expr_dependency_ref & core) { tactic_report report("nlqsat-tactic", *in); ptr_vector fmls; expr_ref fml(m); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; in->get_formulas(fmls); fml = mk_and(m, fmls.size(), fmls.c_ptr()); if (m_mode == elim_t) { diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 257331161..c7b16417c 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -2534,10 +2534,9 @@ class qe_lite_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("qe-lite", *g); proof_ref new_pr(m); expr_ref new_f(m); @@ -2605,9 +2604,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 69ebc1a42..6f09df5b6 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -235,7 +235,6 @@ namespace qe { goal_ref const& goal, goal_ref_buffer& result, model_converter_ref& mc, - proof_converter_ref & pc, expr_dependency_ref& core) { try { diff --git a/src/qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp index e198542c1..ce1b3003a 100644 --- a/src/qe/qe_tactic.cpp +++ b/src/qe/qe_tactic.cpp @@ -52,10 +52,9 @@ class qe_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("qe", *g); m_fparams.m_model = g->models_enabled(); proof_ref new_pr(m); @@ -123,9 +122,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); m_st.reset(); m_imp->collect_statistics(m_st); diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 56f2ff985..3040a68fe 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -1213,13 +1213,12 @@ namespace qe { void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, /* out */ expr_dependency_ref & core) { tactic_report report("qsat-tactic", *in); ptr_vector fmls; expr_ref_vector defs(m); expr_ref fml(m); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; in->get_formulas(fmls); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 37f8b5d16..29de5f107 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -505,7 +505,7 @@ private: SASSERT(!g->proofs_enabled()); TRACE("sat", g->display(tout);); try { - (*m_preprocess)(g, m_subgoals, m_mc, m_pc, m_dep_core); + (*m_preprocess)(g, m_subgoals, m_mc, m_dep_core); } catch (tactic_exception & ex) { IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); @@ -520,6 +520,7 @@ private: } g = m_subgoals[0]; expr_ref_vector atoms(m); + m_pc = g->pc(); TRACE("sat", g->display_with_dependencies(tout);); m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, false, is_lemma); m_goal2sat.get_interpreted_atoms(atoms); diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 7b48986c5..ba6b53e17 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -41,9 +41,8 @@ class sat_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; fail_if_proof_generation("sat", g); bool produce_models = g->models_enabled(); bool produce_core = g->unsat_core_enabled(); @@ -177,12 +176,11 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { imp proc(g->m(), m_params); scoped_set_imp set(this, &proc); try { - proc(g, result, mc, pc, core); + proc(g, result, mc, core); proc.m_solver.collect_statistics(m_stats); } catch (sat::solver_exception & ex) { diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index edc4b4ff5..5b2537b9b 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -72,10 +72,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; reduce(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 77024dba6..08ce9bded 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -147,11 +147,10 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { IF_VERBOSE(10, verbose_stream() << "(smt.tactic start)\n";); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " " diff --git a/src/smt/tactic/unit_subsumption_tactic.cpp b/src/smt/tactic/unit_subsumption_tactic.cpp index 68a34cea8..f02829af0 100644 --- a/src/smt/tactic/unit_subsumption_tactic.cpp +++ b/src/smt/tactic/unit_subsumption_tactic.cpp @@ -42,7 +42,6 @@ struct unit_subsumption_tactic : public tactic { virtual void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, /* out */ expr_dependency_ref & core) { reduce_core(in, result); } @@ -109,9 +108,7 @@ struct unit_subsumption_tactic : public tactic { } void insert_result(goal_ref& result) { - for (unsigned i = 0; i < m_deleted.size(); ++i) { - result->update(m_deleted[i], m.mk_true()); // TBD proof? - } + for (auto d : m_deleted) result->update(d, m.mk_true()); // TBD proof? } void init(goal_ref const& g) { diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index a44463a75..7d3076643 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -104,9 +104,8 @@ public: virtual void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, /* out */ expr_dependency_ref & core) { - pc = 0; mc = 0; core = 0; + mc = 0; core = 0; expr_ref_vector clauses(m); expr2expr_map bool2dep; ptr_vector assumptions; @@ -133,7 +132,7 @@ public: expr_dependency* lcore = 0; if (in->proofs_enabled()) { pr = local_solver->get_proof(); - pc = proof2proof_converter(m, pr); + in->set(proof2proof_converter(m, pr)); } if (in->unsat_core_enabled()) { ptr_vector core; diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index 37ffc6124..e51dc527c 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -93,10 +93,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { fail_if_proof_generation("aig", g); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; operator()(g); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index ac105eb06..50a30b0ef 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -113,9 +113,8 @@ class add_bounds_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("add-bounds", *g); bound_manager bm(m); expr_fast_mark1 visited; @@ -162,10 +161,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, + model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(g, result, mc, pc, core); + (*m_imp)(g, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index b750689b1..bc7d4b51f 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -26,7 +26,6 @@ struct arith_bounds_tactic : public tactic { virtual void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, /* out */ expr_dependency_ref & core) { bounds_arith_subsumption(in, result); } diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 2e4782b2c..c2715da7a 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -55,11 +55,10 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { TRACE("card2bv-before", g->display(tout);); SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); tactic_report report("card2bv", *g); th_rewriter rw1(m, m_params); pb2bv_rewriter rw2(m, m_params); diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 519fec742..06e81bc68 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -225,10 +225,9 @@ class degree_shift_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; m_produce_proofs = g->proofs_enabled(); m_produce_models = g->models_enabled(); tactic_report report("degree_shift", *g); @@ -293,9 +292,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index 651000297..1bc1c4b73 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -315,11 +315,10 @@ class diff_neq_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); m_produce_models = g->models_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); tactic_report report("diff-neq", *g); fail_if_proof_generation("diff-neq", g); fail_if_unsat_core_generation("diff-neq", g); @@ -386,9 +385,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index 68534c60b..dd1dfbd7e 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -155,10 +155,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("elim01", *g); diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 492b12fcf..819b8cb94 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -153,10 +153,9 @@ public: goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; m_trail.reset(); m_fd.reset(); m_max.reset(); diff --git a/src/tactic/arith/factor_tactic.cpp b/src/tactic/arith/factor_tactic.cpp index d187c0078..e4ab1ca05 100644 --- a/src/tactic/arith/factor_tactic.cpp +++ b/src/tactic/arith/factor_tactic.cpp @@ -259,10 +259,9 @@ class factor_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("factor", *g); bool produce_proofs = g->proofs_enabled(); @@ -315,10 +314,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } catch (z3_error & ex) { throw ex; diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 2abfc32ea..68d31621f 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -251,10 +251,9 @@ class fix_dl_var_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("fix-dl-var", *g); bool produce_proofs = g->proofs_enabled(); m_produce_models = g->models_enabled(); @@ -323,10 +322,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 48f584169..c53ef7274 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -1552,10 +1552,9 @@ class fm_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("fm", *g); fail_if_proof_generation("fm", g); m_produce_models = g->models_enabled(); @@ -1677,9 +1676,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } }; diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index ec41f5845..dfe7037f4 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -161,10 +161,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; m_01s->reset(); tactic_report report("cardinality-intro", *g); diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index 89c43e647..a1834a73a 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -190,13 +190,12 @@ class lia2pb_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("lia2pb", g); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); tactic_report report("lia2pb", *g); m_bm.reset(); m_rw.reset(); m_new_deps.reset(); @@ -332,10 +331,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 547af63bf..65ed8ffbe 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -442,13 +442,12 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("nla2bv", g); fail_if_unsat_core_generation("nla2bv", g); - mc = 0; pc = 0; core = 0; result.reset(); - + mc = 0; core = 0; result.reset(); + imp proc(g->m(), m_params); scoped_set_imp setter(*this, proc); proc(*(g.get()), mc); diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index 8f95dac8a..afc165866 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -82,9 +82,8 @@ class normalize_bounds_tactic : public tactic { void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; bool produce_models = in->models_enabled(); bool produce_proofs = in->proofs_enabled(); tactic_report report("normalize-bounds", *in); @@ -173,10 +172,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index f391e2a17..76f003737 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -888,14 +888,13 @@ private: void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { TRACE("pb2bv", g->display(tout);); SASSERT(g->is_well_sorted()); fail_if_proof_generation("pb2bv", g); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); tactic_report report("pb2bv", *g); m_bm.reset(); m_rw.reset(); m_new_deps.reset(); @@ -1001,9 +1000,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/arith/propagate_ineqs_tactic.cpp b/src/tactic/arith/propagate_ineqs_tactic.cpp index d7209740f..e52668f33 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.cpp +++ b/src/tactic/arith/propagate_ineqs_tactic.cpp @@ -52,7 +52,7 @@ public: virtual void updt_params(params_ref const & p); virtual void collect_param_descrs(param_descrs & r) {} - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); + virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); virtual void cleanup(); }; @@ -529,12 +529,11 @@ void propagate_ineqs_tactic::updt_params(params_ref const & p) { void propagate_ineqs_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("propagate-ineqs", g); fail_if_unsat_core_generation("propagate-ineqs", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); goal_ref r; (*m_imp)(g.get(), r); result.push_back(r.get()); diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index af2b3581f..2affd8012 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -823,11 +823,10 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("purify-arith", *g); TRACE("purify_arith", g->display(tout);); bool produce_proofs = g->proofs_enabled(); diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index 9425b90ef..11144c89b 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -294,13 +294,12 @@ class recover_01_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("recover-01", g); fail_if_unsat_core_generation("recover-01", g); m_produce_models = g->models_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); tactic_report report("recover-01", *g); bool saved = false; @@ -408,10 +407,9 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { - (*m_imp)(g, result, mc, pc, core); + (*m_imp)(g, result, mc, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 308b775a4..d7df2e1c4 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -53,9 +53,8 @@ class bit_blaster_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; bool proofs_enabled = g->proofs_enabled(); if (proofs_enabled && m_blast_quant) @@ -137,10 +136,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { - (*m_imp)(g, result, mc, pc, core); + (*m_imp)(g, result, mc, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index e7e374184..9dc247455 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -381,9 +381,8 @@ class bv1_blaster_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; if (!is_target(*g)) throw tactic_exception("bv1 blaster cannot be applied to goal"); @@ -457,9 +456,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(g, result, mc, pc, core); + (*m_imp)(g, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index b71b44bd0..487bbb762 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -139,7 +139,6 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core); virtual tactic * translate(ast_manager & m); virtual void updt_params(params_ref const & p); @@ -200,13 +199,12 @@ bv_bound_chk_tactic::~bv_bound_chk_tactic() { void bv_bound_chk_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("bv-bound-chk", g); fail_if_unsat_core_generation("bv-bound-chk", g); TRACE("bv-bound-chk", g->display(tout << "before:"); tout << std::endl;); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); m_imp->operator()(g); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index 4435bf6a3..e3a5edd84 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -39,7 +39,7 @@ public: virtual ~bv_size_reduction_tactic(); - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); + virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); virtual void cleanup(); }; @@ -384,12 +384,11 @@ bv_size_reduction_tactic::~bv_size_reduction_tactic() { void bv_size_reduction_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("bv-size-reduction", g); fail_if_unsat_core_generation("bv-size-reduction", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); m_imp->operator()(*(g.get()), mc); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index 3598a767c..3aba9a073 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -55,12 +55,11 @@ class bvarray2uf_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); tactic_report report("bvarray2uf", *g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); fail_if_unsat_core_generation("bvarray2uf", g); TRACE("bvarray2uf", tout << "Before: " << std::endl; g->display(tout); ); @@ -131,9 +130,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 0d83e313a..722d2d359 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -119,9 +119,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; bool produce_proofs = g->proofs_enabled(); tactic_report report("dt2bv", *g); unsigned size = g->size(); diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index a0f78154f..a86b41dcc 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -227,10 +227,9 @@ class elim_small_bv_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("elim-small-bv", *g); bool produce_proofs = g->proofs_enabled(); fail_if_proof_generation("elim-small-bv", g); @@ -290,9 +289,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index b0affeb4b..8a6090ca3 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -239,10 +239,9 @@ class max_bv_sharing_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("max-bv-sharing", *g); bool produce_proofs = g->proofs_enabled(); @@ -301,9 +300,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index 698da8498..7a6643568 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -116,10 +116,9 @@ class blast_term_ite_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("blast-term-ite", *g); bool produce_proofs = g->proofs_enabled(); @@ -174,9 +173,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index 65cdef147..d139d60e9 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -57,13 +57,12 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("cofactor-term-ite", g); fail_if_unsat_core_generation("cofactor-term-ite", g); tactic_report report("cofactor-term-ite", *g); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; process(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 26f6842e3..b71c566d6 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -64,7 +64,7 @@ public: virtual void collect_param_descrs(param_descrs & r) {} virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, proof_converter_ref & pc, + model_converter_ref & mc, expr_dependency_ref & core) { mc = 0; tactic_report report("collect-statistics", *g); diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 5bb54073d..43371235c 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -623,9 +623,8 @@ void ctx_simplify_tactic::get_param_descrs(param_descrs & r) { void ctx_simplify_tactic::operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index 9efa7e7db..2ad6e9243 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -57,7 +57,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core); virtual void cleanup(); diff --git a/src/tactic/core/der_tactic.cpp b/src/tactic/core/der_tactic.cpp index 5df009969..1151d6770 100644 --- a/src/tactic/core/der_tactic.cpp +++ b/src/tactic/core/der_tactic.cpp @@ -76,9 +76,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp index 3ee2697c4..16e2c5f78 100644 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ b/src/tactic/core/distribute_forall_tactic.cpp @@ -102,14 +102,13 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); ast_manager & m = g->m(); bool produce_proofs = g->proofs_enabled(); rw r(m, produce_proofs); m_rw = &r; - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); tactic_report report("distribute-forall", *g); expr_ref new_curr(m); diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 2099eebf0..d175ba0c4 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -187,9 +187,8 @@ void dom_simplify_tactic::operator()( goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("dom-simplify", *in.get()); simplify_goal(*(in.get())); diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 56eea8d9a..fd4e9e49b 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -140,7 +140,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core); virtual void cleanup(); diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index d6fb8a091..3f65f4b9d 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -102,10 +102,9 @@ class elim_term_ite_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("elim-term-ite", *g); bool produce_proofs = g->proofs_enabled(); m_rw.cfg().m_produce_models = g->models_enabled(); @@ -164,9 +163,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index aa5d55a8c..3660fdccb 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -818,9 +818,8 @@ class elim_uncnstr_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); @@ -934,10 +933,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, + model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(g, result, mc, pc, core); + (*m_imp)(g, result, mc, core); report_tactic_progress(":num-elim-apps", get_num_elim_apps()); } diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp index 7d90a2155..4c03254c4 100644 --- a/src/tactic/core/injectivity_tactic.cpp +++ b/src/tactic/core/injectivity_tactic.cpp @@ -146,10 +146,9 @@ class injectivity_tactic : public tactic { void operator()(goal_ref const & goal, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(goal->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("injectivity", *goal); fail_if_unsat_core_generation("injectivity", goal); // TODO: Support UNSAT cores fail_if_proof_generation("injectivity", goal); @@ -273,9 +272,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_finder)(g, result, mc, pc, core); + (*m_finder)(g, result, mc, core); for (unsigned i = 0; i < g->size(); ++i) { expr* curr = g->form(i); diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index 9750ad29c..080fc0bec 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -56,11 +56,10 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { TRACE("nnf", tout << "params: " << m_params << "\n"; g->display(tout);); SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("nnf", *g); bool produce_proofs = g->proofs_enabled(); diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index 66143b6b5..8ce514401 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -130,11 +130,10 @@ class occf_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; - + mc = 0; core = 0; + fail_if_proof_generation("occf", g); bool produce_models = g->models_enabled(); @@ -213,9 +212,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index c52f0526b..897d560cf 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -152,10 +152,9 @@ public: goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - pc = 0; core = 0; + core = 0; if (g->proofs_enabled()) { throw tactic_exception("pb-preprocess does not support proofs"); diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 7baac0b99..61804d336 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -138,10 +138,9 @@ class propagate_values_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("propagate-values", *g); m_goal = g.get(); @@ -243,10 +242,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index a7a73ae61..aa53cd9cc 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -73,7 +73,7 @@ public: virtual ~reduce_args_tactic(); - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); + virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); virtual void cleanup(); }; @@ -485,12 +485,11 @@ reduce_args_tactic::~reduce_args_tactic() { void reduce_args_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("reduce-args", g); fail_if_unsat_core_generation("reduce-args", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); m_imp->operator()(*(g.get()), mc); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/simplify_tactic.cpp b/src/tactic/core/simplify_tactic.cpp index 9deff968e..84ade7ba3 100644 --- a/src/tactic/core/simplify_tactic.cpp +++ b/src/tactic/core/simplify_tactic.cpp @@ -95,13 +95,12 @@ void simplify_tactic::get_param_descrs(param_descrs & r) { void simplify_tactic::operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/core/simplify_tactic.h b/src/tactic/core/simplify_tactic.h index 1e8420c62..f14f219d4 100644 --- a/src/tactic/core/simplify_tactic.h +++ b/src/tactic/core/simplify_tactic.h @@ -37,7 +37,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core); virtual void cleanup(); diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index c4f315985..6fbefcba3 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -669,10 +669,9 @@ class solve_eqs_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("solve_eqs", *g); m_produce_models = g->models_enabled(); m_produce_proofs = g->proofs_enabled(); @@ -736,9 +735,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); report_tactic_progress(":num-elim-vars", m_imp->get_num_eliminated_vars()); } diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index a120f2910..f383036f7 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -108,12 +108,11 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(in->is_well_sorted()); tactic_report report("split-clause", *in); TRACE("before_split_clause", in->display(tout);); - pc = 0; mc = 0; core = 0; + mc = 0; core = 0; ast_manager & m = in->m(); unsigned cls_pos = select_clause(m, in); if (cls_pos == UINT_MAX) { @@ -123,7 +122,7 @@ public: app * cls = to_app(in->form(cls_pos)); expr_dependency * cls_dep = in->dep(cls_pos); if (produce_proofs) - pc = alloc(split_pc, m, cls, in->pr(cls_pos)); + in->set(alloc(split_pc, m, cls, in->pr(cls_pos))); unsigned cls_sz = cls->get_num_args(); report_tactic_progress(":num-new-branches", cls_sz); for (unsigned i = 0; i < cls_sz; i++) { diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index 8e87a6741..89013a6da 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -41,7 +41,6 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core); virtual void cleanup(); }; @@ -637,11 +636,10 @@ symmetry_reduce_tactic::~symmetry_reduce_tactic() { void symmetry_reduce_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { fail_if_proof_generation("symmetry_reduce", g); fail_if_unsat_core_generation("symmetry_reduce", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); (*m_imp)(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index 4791b5ce6..22a2dc500 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -801,10 +801,9 @@ class tseitin_cnf_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("tseitin-cnf", *g); fail_if_proof_generation("tseitin-cnf", g); m_produce_models = g->models_enabled(); @@ -886,9 +885,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); report_tactic_progress(":cnf-aux-vars", m_imp->m_num_aux_vars); } diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 6d90b46ea..99b50429c 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -49,14 +49,13 @@ class fpa2bv_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); m_proofs_enabled = g->proofs_enabled(); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); tactic_report report("fpa2bv", *g); m_rw.reset(); @@ -142,10 +141,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 311c9838b..7a98be3f1 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include "tactic/goal.h" #include "ast/ast_ll_pp.h" #include "ast/ast_smt2_pp.h" #include "ast/for_each_expr.h" #include "ast/well_sorted.h" +#include "tactic/goal.h" goal::precision goal::mk_union(precision p1, precision p2) { if (p1 == PRECISE) return p2; @@ -344,10 +344,7 @@ void goal::display_with_dependencies(ast_printer & prn, std::ostream & out) cons out << "\n |-"; deps.reset(); m().linearize(dep(i), deps); - ptr_vector::iterator it = deps.begin(); - ptr_vector::iterator end = deps.end(); - for (; it != end; ++it) { - expr * d = *it; + for (expr * d : deps) { if (is_uninterp_const(d)) { out << " " << mk_ismt2_pp(d, m()); } @@ -361,10 +358,7 @@ void goal::display_with_dependencies(ast_printer & prn, std::ostream & out) cons } if (!to_pp.empty()) { out << "\n :dependencies-definitions ("; - obj_hashtable::iterator it = to_pp.begin(); - obj_hashtable::iterator end = to_pp.end(); - for (; it != end; ++it) { - expr * d = *it; + for (expr* d : to_pp) { out << "\n (#" << d->get_id() << "\n "; prn.display(out, d, 2); out << ")"; @@ -382,10 +376,7 @@ void goal::display_with_dependencies(std::ostream & out) const { out << "\n |-"; deps.reset(); m().linearize(dep(i), deps); - ptr_vector::iterator it = deps.begin(); - ptr_vector::iterator end = deps.end(); - for (; it != end; ++it) { - expr * d = *it; + for (expr * d : deps) { if (is_uninterp_const(d)) { out << " " << mk_ismt2_pp(d, m()); } @@ -510,14 +501,12 @@ void goal::shrink(unsigned j) { unsigned sz = size(); for (unsigned i = j; i < sz; i++) m().pop_back(m_forms); - if (proofs_enabled()) { + if (proofs_enabled()) for (unsigned i = j; i < sz; i++) m().pop_back(m_proofs); - } - if (unsat_core_enabled()) { + if (unsat_core_enabled()) for (unsigned i = j; i < sz; i++) m().pop_back(m_dependencies); - } } /** @@ -662,6 +651,8 @@ goal * goal::translate(ast_translation & translator) const { res->m_inconsistent = m_inconsistent; res->m_depth = m_depth; res->m_precision = m_precision; + res->m_pc = m_pc ? m_pc->translate(translator) : nullptr; + res->m_mc = m_mc ? m_mc->translate(translator) : nullptr; return res; } diff --git a/src/tactic/goal.h b/src/tactic/goal.h index 599fae14f..275c80060 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -35,6 +35,8 @@ Revision History: #include "util/ref.h" #include "util/ref_vector.h" #include "util/ref_buffer.h" +#include "tactic/model_converter.h" +#include "tactic/proof_converter.h" class goal { public: @@ -49,6 +51,8 @@ public: protected: ast_manager & m_manager; + model_converter_ref m_mc; + proof_converter_ref m_pc; unsigned m_ref_count; expr_array m_forms; expr_array m_proofs; @@ -142,6 +146,13 @@ public: bool is_decided() const; bool is_well_sorted() const; + model_converter* mc() { return m_mc.get(); } + proof_converter* pc() { return inconsistent() ? proof2proof_converter(m(), pr(0)) : m_pc.get(); } + void add(model_converter* m) { m_mc = concat(m_mc.get(), m); } + void add(proof_converter* p) { m_pc = concat(m_pc.get(), p); } + void set(model_converter* m) { m_mc = m; } + void set(proof_converter* p) { m_pc = p; } + goal * translate(ast_translation & translator) const; }; diff --git a/src/tactic/nlsat_smt/CMakeLists.txt b/src/tactic/nlsat_smt/CMakeLists.txt deleted file mode 100644 index ccfc0e3ef..000000000 --- a/src/tactic/nlsat_smt/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -z3_add_component(nlsat_smt_tactic - SOURCES - nl_purify_tactic.cpp - COMPONENT_DEPENDENCIES - nlsat_tactic - smt_tactic - TACTIC_HEADERS - nl_purify_tactic.h -) diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp deleted file mode 100644 index e389c960c..000000000 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ /dev/null @@ -1,799 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - nl_purify_tactic.cpp - -Abstract: - - Tactic for purifying quantifier-free formulas that mix QF_NRA and other theories. - It is designed to allow cooprating between the nlsat solver and other theories - in a decoupled way. - - Let goal be formula F. - Let NL goal be formula G. - Assume F is in NNF. - Assume F does not contain mix of real/integers. - Assume F is quantifier-free (please, otherwise we need to reprocess from instantiated satisfiable formula) - - For each atomic nl formula f, - - introduce a propositional variable p - - replace f by p - - add clauses p => f to G - - For each interface term t, - - introduce interface variable v (or use t if it is already a variable) - - replace t by v - - Check satisfiability of G. - If satisfiable, then check assignment to p and interface equalities on F - If unsat: - Retrieve core and add core to G. - else: - For interface equalities from model of F that are not equal in G, add - For interface variables that are equal under one model, but not the other model, - create interface predicate p_vw => v = w, add to both F, G. - Add interface equations to assumptions, recheck F. - If unsat retrieve core add to G. - -Author: - - Nikolaj Bjorner (nbjorner) 2015-5-5. - -Revision History: - ---*/ -#include "tactic/tactical.h" -#include "tactic/nlsat_smt/nl_purify_tactic.h" -#include "smt/tactic/smt_tactic.h" -#include "ast/rewriter/rewriter.h" -#include "nlsat/tactic/nlsat_tactic.h" -#include "tactic/generic_model_converter.h" -#include "util/obj_pair_hashtable.h" -#include "ast/rewriter/rewriter_def.h" -#include "ast/ast_pp.h" -#include "util/trace.h" -#include "smt/smt_solver.h" -#include "solver/solver.h" -#include "model/model_smt2_pp.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/ast_util.h" -#include "solver/solver2tactic.h" - -class nl_purify_tactic : public tactic { - - enum polarity_t { - pol_pos, - pol_neg, - pol_dual - }; - - ast_manager & m; - arith_util m_util; - params_ref m_params; - bool m_produce_proofs; - ref m_fmc; - tactic_ref m_nl_tac; // nlsat tactic - goal_ref m_nl_g; // nlsat goal - ref m_solver; // SMT solver - expr_ref_vector m_eq_preds; // predicates for equality between pairs of interface variables - svector m_eq_values; // truth value of the equality predicates in nlsat - app_ref_vector m_new_reals; // interface real variables - app_ref_vector m_new_preds; // abstraction predicates for smt_solver (hide real constraints) - expr_ref_vector m_asms; // assumptions to pass to SMT solver - ptr_vector m_ctx_asms; // assumptions passed by context - obj_hashtable m_ctx_asms_set; // assumptions passed by context - obj_hashtable m_used_asms; - obj_map m_bool2dep; - obj_pair_map m_eq_pairs; // map pairs of interface variables to auxiliary predicates - obj_map m_interface_cache; // map of compound real expression to interface variable. - obj_map m_polarities; // polarities of sub-expressions - -public: - struct rw_cfg : public default_rewriter_cfg { - enum mode_t { - mode_interface_var, - mode_bool_preds - }; - ast_manager& m; - nl_purify_tactic & m_owner; - app_ref_vector& m_new_reals; - app_ref_vector& m_new_preds; - obj_map& m_polarities; - obj_map& m_interface_cache; - expr_ref_vector m_args; - proof_ref_vector m_proofs; - mode_t m_mode; - - rw_cfg(nl_purify_tactic & o): - m(o.m), - m_owner(o), - m_new_reals(o.m_new_reals), - m_new_preds(o.m_new_preds), - m_polarities(o.m_polarities), - m_interface_cache(o.m_interface_cache), - m_args(m), - m_proofs(m), - m_mode(mode_interface_var) { - } - - virtual ~rw_cfg() {} - - arith_util & u() { return m_owner.m_util; } - - expr * mk_interface_var(expr* arg, proof_ref& arg_pr) { - expr* r; - if (m_interface_cache.find(arg, r)) { - return r; - } - if (is_uninterp_const(arg)) { - m_interface_cache.insert(arg, arg); - return arg; - } - r = m.mk_fresh_const(0, u().mk_real()); - m_new_reals.push_back(to_app(r)); - m_owner.m_fmc->hide(r); - m_interface_cache.insert(arg, r); - expr_ref eq(m); - eq = m.mk_eq(r, arg); - if (is_real_expression(arg)) { - m_owner.m_nl_g->assert_expr(eq); // m.mk_oeq(r, arg) - } - else { - m_owner.m_solver->assert_expr(eq); - } - if (m_owner.m_produce_proofs) { - arg_pr = m.mk_oeq(arg, r); - } - return r; - } - - bool is_real_expression(expr* e) { - return is_app(e) && (to_app(e)->get_family_id() == u().get_family_id()); - } - - void mk_interface_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref& pr) { - expr_ref old_pred(m.mk_app(f, num, args), m); - polarity_t pol = m_polarities.find(old_pred); - result = m.mk_fresh_const(0, m.mk_bool_sort()); - m_polarities.insert(result, pol); - m_new_preds.push_back(to_app(result)); - m_owner.m_fmc->hide(result); - if (pol != pol_neg) { - m_owner.m_nl_g->assert_expr(m.mk_or(m.mk_not(result), old_pred)); - } - if (pol != pol_pos) { - m_owner.m_nl_g->assert_expr(m.mk_or(result, m.mk_not(old_pred))); - } - if (m_owner.m_produce_proofs) { - pr = m.mk_oeq(old_pred, result); - } - TRACE("nlsat_smt", tout << old_pred << " : " << result << "\n";); - } - - bool reduce_quantifier(quantifier * old_q, - expr * new_body, - expr * const * new_patterns, - expr * const * new_no_patterns, - expr_ref & result, - proof_ref & result_pr) { - throw tactic_exception("quantifiers are not supported in mixed-mode nlsat engine"); - } - - br_status reduce_app(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - if (m_mode == mode_bool_preds) { - return reduce_app_bool(f, num, args, result, pr); - } - else { - return reduce_app_real(f, num, args, result, pr); - } - } - - br_status reduce_app_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - if (f->get_family_id() == m.get_basic_family_id()) { - if (f->get_decl_kind() == OP_EQ && u().is_real(args[0])) { - mk_interface_bool(f, num, args, result, pr); - return BR_DONE; - } - else { - return BR_FAILED; - } - } - if (f->get_family_id() == u().get_family_id()) { - switch (f->get_decl_kind()) { - case OP_LE: case OP_GE: case OP_LT: case OP_GT: - // these are the only real cases of non-linear atomic formulas besides equality. - mk_interface_bool(f, num, args, result, pr); - return BR_DONE; - default: - return BR_FAILED; - } - } - return BR_FAILED; - } - - // (+ (f x) y) - // (f (+ x y)) - // - bool is_arith_op(expr* e) { - return is_app(e) && to_app(e)->get_family_id() == u().get_family_id(); - } - - br_status reduce_app_real(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref & pr) { - bool has_interface = false; - bool is_arith = false; - if (f->get_family_id() == u().get_family_id()) { - switch (f->get_decl_kind()) { - case OP_NUM: - case OP_IRRATIONAL_ALGEBRAIC_NUM: - return BR_FAILED; - default: - is_arith = true; - break; - } - } - m_args.reset(); - m_proofs.reset(); - for (unsigned i = 0; i < num; ++i) { - expr* arg = args[i]; - proof_ref arg_pr(m); - if (is_arith && !is_arith_op(arg)) { - has_interface = true; - m_args.push_back(mk_interface_var(arg, arg_pr)); - } - else if (!is_arith && u().is_real(arg)) { - has_interface = true; - m_args.push_back(mk_interface_var(arg, arg_pr)); - } - else { - m_args.push_back(arg); - } - if (arg_pr) { - m_proofs.push_back(arg_pr); - } - } - if (has_interface) { - result = m.mk_app(f, num, m_args.c_ptr()); - if (m_owner.m_produce_proofs) { - pr = m.mk_oeq_congruence(m.mk_app(f, num, args), to_app(result), m_proofs.size(), m_proofs.c_ptr()); - } - TRACE("nlsat_smt", tout << result << "\n";); - return BR_DONE; - } - else { - return BR_FAILED; - } - } - }; - -private: - - class rw : public rewriter_tpl { - rw_cfg m_cfg; - public: - rw(nl_purify_tactic & o): - rewriter_tpl(o.m, o.m_produce_proofs, m_cfg), - m_cfg(o) { - } - void set_bool_mode() { - m_cfg.m_mode = rw_cfg::mode_bool_preds; - } - void set_interface_var_mode() { - m_cfg.m_mode = rw_cfg::mode_interface_var; - } - }; - - - arith_util & u() { return m_util; } - - void check_point() { - if (m.canceled()) { - throw tactic_exception(Z3_CANCELED_MSG); - } - } - - void display_result(std::ostream& out, goal_ref_buffer const& result) { - for (unsigned i = 0; i < result.size(); ++i) { - result[i]->display_with_dependencies(out << "goal\n"); - } - } - - void update_eq_values(model_ref& mdl) { - expr_ref tmp(m); - for (unsigned i = 0; i < m_eq_preds.size(); ++i) { - expr* pred = m_eq_preds[i].get(); - m_eq_values[i] = l_undef; - if (mdl->eval(pred, tmp)) { - if (m.is_true(tmp)) { - m_eq_values[i] = l_true; - } - else if (m.is_false(tmp)) { - m_eq_values[i] = l_false; - } - } - } - } - - void solve( - goal_ref const& g, - goal_ref_buffer& result, - expr_dependency_ref& core, - model_converter_ref& mc) { - - while (true) { - check_point(); - TRACE("nlsat_smt", m_solver->display(tout << "SMT:\n"); m_nl_g->display(tout << "\nNL:\n"); ); - goal_ref tmp_nl = alloc(goal, m, true, false); - model_converter_ref nl_mc; - proof_converter_ref nl_pc; - expr_dependency_ref nl_core(m); - result.reset(); - tmp_nl->copy_from(*m_nl_g.get()); - (*m_nl_tac)(tmp_nl, result, nl_mc, nl_pc, nl_core); - - if (is_decided_unsat(result)) { - core2result(core, g, result); - TRACE("nlsat_smt", tout << "unsat\n";); - break; - } - if (!is_decided_sat(result)) { - TRACE("nlsat_smt", tout << "not a unit\n";); - break; - } - // extract evaluation on interface variables. - // assert booleans that evaluate to true. - // assert equalities between equal interface real variables. - - model_ref mdl_nl, mdl_smt; - if (nl_mc.get()) { - model_converter2model(m, nl_mc.get(), mdl_nl); - update_eq_values(mdl_nl); - enforce_equalities(mdl_nl, m_nl_g); - - setup_assumptions(mdl_nl); - - TRACE("nlsat_smt", - model_smt2_pp(tout << "nl model\n", m, *mdl_nl.get(), 0); - m_solver->display(tout << "smt goal:\n"); tout << "\n";); - } - result.reset(); - lbool r = m_solver->check_sat(m_asms.size(), m_asms.c_ptr()); - if (r == l_false) { - // extract the core from the result - ptr_vector ecore, asms; - expr_ref_vector clause(m); - expr_ref fml(m); - get_unsat_core(ecore, asms); - - // - // assumptions should also be used for the nlsat tactic, - // but since it does not support assumptions at this time - // we overapproximate the necessary core and accumulate - // all assumptions that are ever used. - // - for (unsigned i = 0; i < asms.size(); ++i) { - m_used_asms.insert(asms[i]); - } - if (ecore.empty()) { - core2result(core, g, result); - break; - } - for (unsigned i = 0; i < ecore.size(); ++i) { - clause.push_back(mk_not(m, ecore[i])); - } - fml = mk_or(m, clause.size(), clause.c_ptr()); - m_nl_g->assert_expr(fml); - continue; - } - else if (r == l_true) { - m_solver->get_model(mdl_smt); - if (enforce_equalities(mdl_smt, m_nl_g)) { - // SMT enforced a new equality that wasn't true for nlsat. - continue; - } - TRACE("nlsat_smt", - m_fmc->display(tout << "joint state is sat\n"); - nl_mc->display(tout << "nl\n");); - if (mdl_nl.get()) { - merge_models(*mdl_nl.get(), mdl_smt); - } - mc = m_fmc.get(); - apply(mc, mdl_smt, 0); - mc = model2model_converter(mdl_smt.get()); - result.push_back(alloc(goal, m)); - } - else { - TRACE("nlsat_smt", tout << "unknown\n";); - } - break; - } - TRACE("nlsat_smt", display_result(tout, result);); - } - - void get_unsat_core(ptr_vector& core, ptr_vector& asms) { - m_solver->get_unsat_core(core); - for (unsigned i = 0; i < core.size(); ++i) { - if (m_ctx_asms_set.contains(core[i])) { - asms.push_back(core[i]); - core[i] = core.back(); - core.pop_back(); - --i; - } - } - } - - void core2result(expr_dependency_ref & lcore, goal_ref const& g, goal_ref_buffer& result) { - result.reset(); - proof * pr = 0; - lcore = 0; - g->reset(); - obj_hashtable::iterator it = m_used_asms.begin(), end = m_used_asms.end(); - for (; it != end; ++it) { - lcore = m.mk_join(lcore, m.mk_leaf(m_bool2dep.find(*it))); - } - g->assert_expr(m.mk_false(), pr, lcore); - TRACE("nlsat_smt", g->display_with_dependencies(tout);); - result.push_back(g.get()); - } - - void setup_assumptions(model_ref& mdl) { - m_asms.reset(); - m_asms.append(m_ctx_asms.size(), m_ctx_asms.c_ptr()); - app_ref_vector const& fresh_preds = m_new_preds; - expr_ref tmp(m); - for (unsigned i = 0; i < fresh_preds.size(); ++i) { - expr* pred = fresh_preds[i]; - if (mdl->eval(pred, tmp)) { - polarity_t pol = m_polarities.find(pred); - // if assumptinon literals are used to satisfy NL state, - // we have to assume them when satisfying SMT state - if (pol != pol_neg && m.is_false(tmp)) { - m_asms.push_back(m.mk_not(pred)); - } - else if (pol != pol_pos && m.is_true(tmp)) { - m_asms.push_back(pred); - } - } - } - for (unsigned i = 0; i < m_eq_preds.size(); ++i) { - expr* pred = m_eq_preds[i].get(); - switch (m_eq_values[i]) { - case l_true: - m_asms.push_back(pred); - break; - case l_false: - m_asms.push_back(m.mk_not(pred)); - break; - default: - break; - } - } - TRACE("nlsat_smt", - tout << "assumptions:\n" << m_asms << "\n";); - } - - bool enforce_equalities(model_ref& mdl, goal_ref const& nl_g) { - TRACE("nlsat_smt", tout << "Enforce equalities " << m_interface_cache.size() << "\n";); - bool new_equality = false; - expr_ref_vector nums(m); - obj_map num2var; - obj_map::iterator it = m_interface_cache.begin(), end = m_interface_cache.end(); - for (; it != end; ++it) { - expr_ref r(m); - expr* v, *w, *pred; - w = it->m_value; - VERIFY(mdl->eval(w, r)); - TRACE("nlsat_smt", tout << mk_pp(w, m) << " |-> " << r << "\n";); - nums.push_back(r); - if (num2var.find(r, v)) { - if (!m_eq_pairs.find(v, w, pred)) { - pred = m.mk_fresh_const(0, m.mk_bool_sort()); - m_eq_preds.push_back(pred); - m_eq_values.push_back(l_true); - m_fmc->hide(pred); - nl_g->assert_expr(m.mk_or(m.mk_not(pred), m.mk_eq(w, v))); - nl_g->assert_expr(m.mk_or(pred, m.mk_not(m.mk_eq(w, v)))); - m_solver->assert_expr(m.mk_iff(pred, m.mk_eq(w, v))); - new_equality = true; - m_eq_pairs.insert(v, w, pred); - } - else { - // interface equality is already enforced. - } - } - else { - num2var.insert(r, w); - } - } - return new_equality; - } - - void merge_models(model const& mdl_nl, model_ref& mdl_smt) { - expr_safe_replace num2num(m); - expr_ref result(m), val2(m); - expr_ref_vector args(m); - unsigned sz = mdl_nl.get_num_constants(); - for (unsigned i = 0; i < sz; ++i) { - func_decl* v = mdl_nl.get_constant(i); - if (u().is_real(v->get_range())) { - expr* val = mdl_nl.get_const_interp(v); - if (mdl_smt->eval(v, val2)) { - if (val != val2) { - num2num.insert(val2, val); - } - } - } - } - sz = mdl_smt->get_num_functions(); - for (unsigned i = 0; i < sz; ++i) { - func_decl* f = mdl_smt->get_function(i); - if (has_real(f)) { - unsigned arity = f->get_arity(); - func_interp* f1 = mdl_smt->get_func_interp(f); - func_interp* f2 = alloc(func_interp, m, f->get_arity()); - for (unsigned j = 0; j < f1->num_entries(); ++j) { - args.reset(); - func_entry const* entry = f1->get_entry(j); - for (unsigned k = 0; k < arity; ++k) { - translate(num2num, entry->get_arg(k), result); - args.push_back(result); - } - translate(num2num, entry->get_result(), result); - f2->insert_entry(args.c_ptr(), result); - } - translate(num2num, f1->get_else(), result); - f2->set_else(result); - mdl_smt->register_decl(f, f2); - } - } - mdl_smt->copy_const_interps(mdl_nl); - } - - bool has_real(func_decl* f) { - for (unsigned i = 0; i < f->get_arity(); ++i) { - if (u().is_real(f->get_domain(i))) return true; - } - return u().is_real(f->get_range()); - } - - void translate(expr_safe_replace& num2num, expr* e, expr_ref& result) { - result = 0; - if (e) { - num2num(e, result); - } - } - - void get_polarities(goal const& g) { - ptr_vector forms; - svector pols; - unsigned sz = g.size(); - for (unsigned i = 0; i < sz; ++i) { - forms.push_back(g.form(i)); - pols.push_back(pol_pos); - } - polarity_t p, q; - while (!forms.empty()) { - expr* e = forms.back(); - p = pols.back(); - forms.pop_back(); - pols.pop_back(); - if (m_polarities.find(e, q)) { - if (p == q || q == pol_dual) continue; - p = pol_dual; - } - TRACE("nlsat_smt_verbose", tout << mk_pp(e, m) << "\n";); - m_polarities.insert(e, p); - if (is_quantifier(e) || is_var(e)) { - throw tactic_exception("nl-purify tactic does not support quantifiers"); - } - SASSERT(is_app(e)); - app* a = to_app(e); - func_decl* f = a->get_decl(); - if (f->get_family_id() == m.get_basic_family_id() && p != pol_dual) { - switch(f->get_decl_kind()) { - case OP_NOT: - p = neg(p); - break; - case OP_AND: - case OP_OR: - break; - default: - p = pol_dual; - break; - } - } - else { - p = pol_dual; - } - for (unsigned i = 0; i < a->get_num_args(); ++i) { - forms.push_back(a->get_arg(i)); - pols.push_back(p); - } - } - } - - polarity_t neg(polarity_t p) { - switch (p) { - case pol_pos: return pol_neg; - case pol_neg: return pol_pos; - case pol_dual: return pol_dual; - } - return pol_dual; - } - - polarity_t join(polarity_t p, polarity_t q) { - if (p == q) return p; - return pol_dual; - } - - void rewrite_goal(rw& r, goal_ref const& g) { - r.reset(); - expr_ref new_curr(m); - proof_ref new_pr(m); - unsigned sz = g->size(); - for (unsigned i = 0; i < sz; i++) { - expr * curr = g->form(i); - r(curr, new_curr, new_pr); - if (m_produce_proofs) { - proof * pr = g->pr(i); - new_pr = m.mk_modus_ponens(pr, new_pr); - } - g->update(i, new_curr, new_pr, g->dep(i)); - } - } - - void remove_pure_arith(goal_ref const& g) { - obj_map is_pure; - unsigned sz = g->size(); - for (unsigned i = 0; i < sz; i++) { - expr * curr = g->form(i); - if (is_pure_arithmetic(is_pure, curr)) { - m_nl_g->assert_expr(curr, g->pr(i), g->dep(i)); - g->update(i, m.mk_true(), g->pr(i), g->dep(i)); - } - } - } - - bool is_pure_arithmetic(obj_map& is_pure, expr* e0) { - ptr_vector todo; - todo.push_back(e0); - while (!todo.empty()) { - expr* e = todo.back(); - if (is_pure.contains(e)) { - todo.pop_back(); - continue; - } - if (!is_app(e)) { - todo.pop_back(); - is_pure.insert(e, false); - continue; - } - app* a = to_app(e); - bool pure = false, all_found = true, p; - pure |= (a->get_family_id() == u().get_family_id()) && u().is_real(a); - pure |= (m.is_eq(e) && u().is_real(a->get_arg(0))); - pure |= (a->get_family_id() == u().get_family_id()) && m.is_bool(a) && u().is_real(a->get_arg(0)); - pure |= (a->get_family_id() == m.get_basic_family_id()); - pure |= is_uninterp_const(a) && u().is_real(a); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - if (!is_pure.find(a->get_arg(i), p)) { - todo.push_back(a->get_arg(i)); - all_found = false; - } - else { - pure &= p; - } - } - if (all_found) { - is_pure.insert(e, pure); - todo.pop_back(); - } - } - return is_pure.find(e0); - } - -public: - - nl_purify_tactic(ast_manager & m, params_ref const& p): - m(m), - m_util(m), - m_params(p), - m_fmc(0), - m_nl_tac(mk_nlsat_tactic(m, p)), - m_nl_g(0), - m_solver(mk_smt_solver(m, p, symbol::null)), - m_eq_preds(m), - m_new_reals(m), - m_new_preds(m), - m_asms(m) - {} - - virtual ~nl_purify_tactic() {} - - virtual void updt_params(params_ref const & p) { - m_params = p; - } - - virtual tactic * translate(ast_manager& m) { - return alloc(nl_purify_tactic, m, m_params); - } - - virtual void collect_statistics(statistics & st) const { - m_nl_tac->collect_statistics(st); - m_solver->collect_statistics(st); - } - - virtual void reset_statistics() { - m_nl_tac->reset_statistics(); - } - - - virtual void cleanup() { - m_solver = mk_smt_solver(m, m_params, symbol::null); - m_nl_tac->cleanup(); - m_eq_preds.reset(); - m_eq_values.reset(); - m_new_reals.reset(); - m_new_preds.reset(); - m_eq_pairs.reset(); - m_polarities.reset(); - m_ctx_asms.reset(); - m_ctx_asms_set.reset(); - m_used_asms.reset(); - m_bool2dep.reset(); - } - - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { - - tactic_report report("qfufnl-purify", *g); - TRACE("nlsat_smt", g->display(tout);); - - m_produce_proofs = g->proofs_enabled(); - mc = 0; pc = 0; core = 0; - - fail_if_proof_generation("qfufnra-purify", g); - // fail_if_unsat_core_generation("qfufnra-purify", g); - rw r(*this); - expr_ref_vector clauses(m); - m_nl_g = alloc(goal, m, true, false); - m_fmc = alloc(generic_model_converter, m); - - // first hoist interface variables, - // then annotate subformulas by polarities, - // finally extract polynomial inequalities by - // creating a place-holder predicate inside the - // original goal and extracing pure nlsat clauses. - r.set_interface_var_mode(); - rewrite_goal(r, g); - if (!g->unsat_core_enabled()) { - remove_pure_arith(g); - } - get_polarities(*g.get()); - r.set_bool_mode(); - rewrite_goal(r, g); - - extract_clauses_and_dependencies(g, clauses, m_ctx_asms, m_bool2dep, m_fmc); - - TRACE("nlsat_smt", tout << clauses << "\n";); - - for (unsigned i = 0; i < m_ctx_asms.size(); ++i) { - m_ctx_asms_set.insert(m_ctx_asms[i]); - } - - for (unsigned i = 0; i < clauses.size(); ++i) { - m_solver->assert_expr(clauses[i].get()); - } - g->inc_depth(); - solve(g, result, core, mc); - } -}; - - -tactic * mk_nl_purify_tactic(ast_manager& m, params_ref const& p) { - return alloc(nl_purify_tactic, m, p); -} diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.h b/src/tactic/nlsat_smt/nl_purify_tactic.h deleted file mode 100644 index 85d033921..000000000 --- a/src/tactic/nlsat_smt/nl_purify_tactic.h +++ /dev/null @@ -1,35 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - nl_purify_tactic.h - -Abstract: - - Tactic for purifying quantifier-free formulas that mix QF_NRA and other theories. - It is designed to allow cooprating between the nlsat solver and other theories - in a decoubled way. - -Author: - - Nikolaj Bjorner (nbjorner) 2015-5-5. - -Revision History: - ---*/ -#ifndef NL_PURIFY_TACTIC_H_ -#define NL_PURIFY_TACTIC_H_ - -#include "util/params.h" -class ast_manager; -class tactic; - -tactic * mk_nl_purify_tactic(ast_manager & m, params_ref const & p = params_ref()); - -/* - ADD_TACTIC("nl-purify", "Decompose goal into pure NL-sat formula and formula over other theories.", "mk_nl_purify_tactic(m, p)") -*/ - -#endif - diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index e9c6d76aa..16eb2b4a7 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -541,7 +541,7 @@ public: init(); } - void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { + void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc, expr_dependency_ref & dep) { ast_manager& m = g->m(); solver* s = mk_fd_solver(m, m_params); solver_state* st = alloc(solver_state, 0, s, m_params, cube_task); diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 64689602c..4e4efeb8f 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -49,9 +49,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; TRACE("sine", g->display(tout);); TRACE("sine", tout << g->size();); diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index 19937e8b0..a96cf117a 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -62,10 +62,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; result.reset(); + mc = 0; core = 0; result.reset(); TRACE("sls", g->display(tout);); tactic_report report("sls", *g); diff --git a/src/tactic/smtlogics/CMakeLists.txt b/src/tactic/smtlogics/CMakeLists.txt index c90fd7468..2741334b4 100644 --- a/src/tactic/smtlogics/CMakeLists.txt +++ b/src/tactic/smtlogics/CMakeLists.txt @@ -11,7 +11,6 @@ z3_add_component(smtlogic_tactics qfnra_tactic.cpp qfufbv_ackr_model_converter.cpp qfufbv_tactic.cpp - qfufnra_tactic.cpp qfuf_tactic.cpp quant_tactics.cpp COMPONENT_DEPENDENCIES @@ -22,7 +21,6 @@ z3_add_component(smtlogic_tactics fp muz nlsat_tactic - nlsat_smt_tactic qe sat_solver smt_tactic @@ -40,6 +38,5 @@ z3_add_component(smtlogic_tactics qfnra_tactic.h qfuf_tactic.h qfufbv_tactic.h - qfufnra_tactic.h quant_tactics.h ) diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index e89da3631..a4995535e 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -56,7 +56,6 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { mc = 0; ast_manager& m(g->m()); diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 7610c420a..3a8e128ec 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -70,12 +70,10 @@ void report_tactic_progress(char const * id, unsigned val) { void skip_tactic::operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { result.reset(); result.push_back(in.get()); mc = 0; - pc = 0; core = 0; } @@ -88,7 +86,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { throw tactic_exception("fail tactic"); } @@ -111,10 +108,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { IF_VERBOSE(m_lvl, verbose_stream() << m_msg << "\n";); - skip_tactic::operator()(in, result, mc, pc, core); + skip_tactic::operator()(in, result, mc, core); } }; @@ -130,11 +126,10 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { TRACE(m_tag, in->display(tout);); (void)m_tag; - skip_tactic::operator()(in, result, mc, pc, core); + skip_tactic::operator()(in, result, mc, core); } }; @@ -149,11 +144,10 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { if (!in->is_decided()) throw tactic_exception("undecided"); - skip_tactic::operator()(in, result, mc, pc, core); + skip_tactic::operator()(in, result, mc, core); } }; @@ -161,10 +155,10 @@ tactic * mk_fail_if_undecided_tactic() { return alloc(fail_if_undecided_tactic); } -void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { +void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core) { t.reset_statistics(); try { - t(in, result, mc, pc, core); + t(in, result, mc, core); t.cleanup(); } catch (tactic_exception & ex) { @@ -184,9 +178,8 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, model_converter_ref& m core = 0; ast_manager & m = g->m(); goal_ref_buffer r; - proof_converter_ref pc; try { - exec(t, g, r, mc, pc, core); + exec(t, g, r, mc, core); } catch (tactic_exception & ex) { reason_unknown = ex.msg(); diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 93da52366..3b8110fd2 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -78,7 +78,6 @@ public: virtual void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, /* out */ expr_dependency_ref & core) = 0; virtual void collect_statistics(statistics & st) const {} @@ -119,7 +118,7 @@ void report_tactic_progress(char const * id, unsigned val); class skip_tactic : public tactic { public: - virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); + virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); virtual void cleanup() {} virtual tactic * translate(ast_manager & m) { return this; } }; @@ -152,7 +151,7 @@ public: #define MK_SIMPLE_TACTIC_FACTORY(NAME, ST) MK_TACTIC_FACTORY(NAME, return ST;) -void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); +void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); lbool check_sat(tactic & t, goal_ref & g, model_ref & md, model_converter_ref& mc, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); // Throws an exception if goal \c in requires proof generation. diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index c5a70c0db..3f94908b3 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -109,7 +109,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { bool models_enabled = in->models_enabled(); @@ -119,14 +118,12 @@ public: ast_manager & m = in->m(); goal_ref_buffer r1; model_converter_ref mc1; - proof_converter_ref pc1; expr_dependency_ref core1(m); result.reset(); - mc = 0; - pc = 0; + mc = 0; core = 0; - m_t1->operator()(in, r1, mc1, pc1, core1); - SASSERT(!is_decided(r1) || (!pc1 && !core1)); // the pc and core of decided goals is 0 + m_t1->operator()(in, r1, mc1, core1); + SASSERT(!is_decided(r1) || !core1); // the pc and core of decided goals is 0 unsigned r1_size = r1.size(); SASSERT(r1_size > 0); if (r1_size == 1) { @@ -136,24 +133,21 @@ public: return; } goal_ref r1_0 = r1[0]; - m_t2->operator()(r1_0, result, mc, pc, core); + m_t2->operator()(r1_0, result, mc, core); if (models_enabled) mc = concat(mc1.get(), mc.get()); - if (proofs_enabled) pc = concat(pc1.get(), pc.get()); if (cores_enabled) core = m.mk_join(core1.get(), core); } else { if (cores_enabled) core = core1; - proof_converter_ref_buffer pc_buffer; model_converter_ref_buffer mc_buffer; sbuffer sz_buffer; goal_ref_buffer r2; for (unsigned i = 0; i < r1_size; i++) { goal_ref g = r1[i]; r2.reset(); - model_converter_ref mc2; - proof_converter_ref pc2; - expr_dependency_ref core2(m); - m_t2->operator()(g, r2, mc2, pc2, core2); + model_converter_ref mc2; + expr_dependency_ref core2(m); + m_t2->operator()(g, r2, mc2, core2); if (is_decided(r2)) { SASSERT(r2.size() == 1); if (is_decided_sat(r2)) { @@ -167,17 +161,15 @@ public: apply(mc1, md, i); mc = model2model_converter(md.get()); } - SASSERT(!pc); SASSERT(!core); + SASSERT(!core); return; } else { SASSERT(is_decided_unsat(r2)); // the proof and unsat core of a decided_unsat goal are stored in the node itself. - // pc2 and core2 must be 0. - SASSERT(!pc2); + // core2 must be 0. SASSERT(!core2); if (models_enabled) mc_buffer.push_back(0); - if (proofs_enabled) pc_buffer.push_back(proof2proof_converter(m, r2[0]->pr(0))); if (models_enabled || proofs_enabled) sz_buffer.push_back(0); if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); } @@ -185,28 +177,37 @@ public: else { result.append(r2.size(), r2.c_ptr()); if (models_enabled) mc_buffer.push_back(mc2.get()); - if (proofs_enabled) pc_buffer.push_back(pc2.get()); if (models_enabled || proofs_enabled) sz_buffer.push_back(r2.size()); if (cores_enabled) core = m.mk_join(core.get(), core2.get()); } } + proof_converter_ref_buffer pc_buffer; + proof_converter_ref pc(in->pc()); + if (proofs_enabled) { + for (goal* g : r1) { + pc_buffer.push_back(g->pc()); + } + } + if (result.empty()) { // all subgoals were shown to be unsat. // create an decided_unsat goal with the proof in->reset_all(); proof_ref pr(m); - if (proofs_enabled) - apply(m, pc1, pc_buffer, pr); + if (proofs_enabled) { + apply(m, pc, pc_buffer, pr); + in->set(proof2proof_converter(m, pr)); + } SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); core = 0; result.push_back(in.get()); - SASSERT(!mc); SASSERT(!pc); SASSERT(!core); + SASSERT(!mc); SASSERT(!core); } else { if (models_enabled) mc = concat(mc1.get(), mc_buffer.size(), mc_buffer.c_ptr(), sz_buffer.c_ptr()); - if (proofs_enabled) pc = concat(pc1.get(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr()); + if (proofs_enabled) in->set(concat(pc.get(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr())); SASSERT(cores_enabled || core == 0); } } @@ -372,9 +373,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { goal orig(*(in.get())); + proof_converter_ref pc = in->pc(); unsigned sz = m_ts.size(); unsigned i; for (i = 0; i < sz; i++) { @@ -386,14 +387,15 @@ public: SASSERT(sz > 0); if (i < sz - 1) { try { - t->operator()(in, result, mc, pc, core); + t->operator()(in, result, mc, core); return; } catch (tactic_exception &) { + in->set(pc.get()); } } else { - t->operator()(in, result, mc, pc, core); + t->operator()(in, result, mc, core); return; } in->reset_all(); @@ -471,7 +473,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { bool use_seq; #ifdef _NO_OMP_ @@ -481,7 +482,7 @@ public: #endif if (use_seq) { // execute tasks sequentially - or_else_tactical::operator()(in, result, mc, pc, core); + or_else_tactical::operator()(in, result, mc, core); return; } @@ -510,14 +511,13 @@ public: for (int i = 0; i < static_cast(sz); i++) { goal_ref_buffer _result; model_converter_ref _mc; - proof_converter_ref _pc; expr_dependency_ref _core(*(managers[i])); goal_ref in_copy = in_copies[i]; tactic & t = *(ts.get(i)); try { - t(in_copy, _result, _mc, _pc, _core); + t(in_copy, _result, _mc, _core); bool first = false; #pragma omp critical (par_tactical) { @@ -537,7 +537,6 @@ public: result.push_back(_result[k]->translate(translator)); } mc = _mc ? _mc->translate(translator) : 0; - pc = _pc ? _pc->translate(translator) : 0; expr_dependency_translation td(translator); core = td(_core); } @@ -602,7 +601,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { bool use_seq; #ifdef _NO_OMP_ @@ -612,7 +610,7 @@ public: #endif if (use_seq) { // execute tasks sequentially - and_then_tactical::operator()(in, result, mc, pc, core); + and_then_tactical::operator()(in, result, mc, core); return; } @@ -623,14 +621,12 @@ public: ast_manager & m = in->m(); goal_ref_buffer r1; model_converter_ref mc1; - proof_converter_ref pc1; expr_dependency_ref core1(m); result.reset(); mc = 0; - pc = 0; core = 0; - m_t1->operator()(in, r1, mc1, pc1, core1); - SASSERT(!is_decided(r1) || (!pc1 && !core1)); // the pc and core of decided goals is 0 + m_t1->operator()(in, r1, mc1, core1); + SASSERT(!is_decided(r1) || !core1); // the core of decided goals is 0 unsigned r1_size = r1.size(); SASSERT(r1_size > 0); if (r1_size == 1) { @@ -638,13 +634,12 @@ public: if (r1[0]->is_decided()) { result.push_back(r1[0]); if (models_enabled) mc = mc1; - SASSERT(!pc); SASSERT(!core); + SASSERT(!core); return; } goal_ref r1_0 = r1[0]; - m_t2->operator()(r1_0, result, mc, pc, core); + m_t2->operator()(r1_0, result, mc, core); if (models_enabled) mc = concat(mc1.get(), mc.get()); - if (proofs_enabled) pc = concat(pc1.get(), pc.get()); if (cores_enabled) core = m.mk_join(core1.get(), core); } else { @@ -662,15 +657,15 @@ public: ts2.push_back(m_t2->translate(*new_m)); } - proof_converter_ref_buffer pc_buffer; model_converter_ref_buffer mc_buffer; + proof_converter_ref_buffer pc_buffer; scoped_ptr_vector core_buffer; scoped_ptr_vector goals_vect; - pc_buffer.resize(r1_size); mc_buffer.resize(r1_size); core_buffer.resize(r1_size); goals_vect.resize(r1_size); + pc_buffer.resize(r1_size); bool found_solution = false; bool failed = false; @@ -685,13 +680,12 @@ public: goal_ref_buffer r2; model_converter_ref mc2; - proof_converter_ref pc2; expr_dependency_ref core2(new_m); bool curr_failed = false; try { - ts2[i]->operator()(new_g, r2, mc2, pc2, core2); + ts2[i]->operator()(new_g, r2, mc2, core2); } catch (tactic_exception & ex) { #pragma omp critical (par_and_then_tactical) @@ -766,14 +760,13 @@ public: apply(mc1, md, i); mc = model2model_converter(md.get()); } - SASSERT(!pc); SASSERT(!core); + SASSERT(!core); } } else { SASSERT(is_decided_unsat(r2)); // the proof and unsat core of a decided_unsat goal are stored in the node itself. // pc2 and core2 must be 0. - SASSERT(!pc2); SASSERT(!core2); if (models_enabled) mc_buffer.set(i, 0); @@ -793,7 +786,7 @@ public: goals_vect.set(i, new_r2); new_r2->append(r2.size(), r2.c_ptr()); mc_buffer.set(i, mc2.get()); - pc_buffer.set(i, pc2.get()); + pc_buffer.set(i, new_g->pc()); if (cores_enabled && core2 != 0) { expr_dependency_ref * new_dep = alloc(expr_dependency_ref, new_m); *new_dep = core2; @@ -841,22 +834,30 @@ public: } } + if (result.empty()) { // all subgoals were shown to be unsat. // create an decided_unsat goal with the proof in->reset_all(); proof_ref pr(m); - if (proofs_enabled) - apply(m, pc1, pc_buffer, pr); + if (proofs_enabled) { + proof_converter_ref_buffer pc_buffer; + for (goal_ref g : r1) { + pc_buffer.push_back(g->pc()); + } + proof_converter_ref pc = in->pc(); + apply(m, pc, pc_buffer, pr); + in->set(proof2proof_converter(m, pr)); + } SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); core = 0; result.push_back(in.get()); - SASSERT(!mc); SASSERT(!pc); SASSERT(!core); + SASSERT(!mc); SASSERT(!core); } else { if (models_enabled) mc = concat(mc1.get(), mc_buffer.size(), mc_buffer.c_ptr(), sz_buffer.c_ptr()); - if (proofs_enabled) pc = concat(pc1.get(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr()); + if (proofs_enabled) in->set(concat(in->pc(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr())); SASSERT(cores_enabled || core == 0); } } @@ -902,9 +903,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - m_t->operator()(in, result, mc, pc, core); + m_t->operator()(in, result, mc, core); } virtual void cleanup(void) { m_t->cleanup(); } @@ -931,13 +931,11 @@ class repeat_tactical : public unary_tactical { goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { // TODO: implement a non-recursive version. if (depth > m_max_depth) { result.push_back(in.get()); mc = 0; - pc = 0; core = 0; return; } @@ -949,20 +947,17 @@ class repeat_tactical : public unary_tactical { ast_manager & m = in->m(); goal_ref_buffer r1; model_converter_ref mc1; - proof_converter_ref pc1; expr_dependency_ref core1(m); result.reset(); mc = 0; - pc = 0; core = 0; { goal orig_in(in->m(), proofs_enabled, models_enabled, cores_enabled); orig_in.copy_from(*(in.get())); - m_t->operator()(in, r1, mc1, pc1, core1); + m_t->operator()(in, r1, mc1, core1); if (is_equal(orig_in, *(in.get()))) { result.push_back(r1[0]); if (models_enabled) mc = mc1; - if (proofs_enabled) pc = pc1; if (cores_enabled) core = core1; return; } @@ -973,28 +968,25 @@ class repeat_tactical : public unary_tactical { if (r1[0]->is_decided()) { result.push_back(r1[0]); if (models_enabled) mc = mc1; - SASSERT(!pc); SASSERT(!core); + SASSERT(!core); return; } goal_ref r1_0 = r1[0]; - operator()(depth+1, r1_0, result, mc, pc, core); + operator()(depth+1, r1_0, result, mc, core); if (models_enabled) mc = concat(mc.get(), mc1.get()); - if (proofs_enabled) pc = concat(pc.get(), pc1.get()); if (cores_enabled) core = m.mk_join(core1.get(), core); } else { if (cores_enabled) core = core1; - proof_converter_ref_buffer pc_buffer; model_converter_ref_buffer mc_buffer; sbuffer sz_buffer; goal_ref_buffer r2; for (unsigned i = 0; i < r1_size; i++) { goal_ref g = r1[i]; r2.reset(); - model_converter_ref mc2; - proof_converter_ref pc2; + model_converter_ref mc2; expr_dependency_ref core2(m); - operator()(depth+1, g, r2, mc2, pc2, core2); + operator()(depth+1, g, r2, mc2, core2); if (is_decided(r2)) { SASSERT(r2.size() == 1); if (is_decided_sat(r2)) { @@ -1007,15 +999,13 @@ class repeat_tactical : public unary_tactical { if (mc1) (*mc1)(md, i); mc = model2model_converter(md.get()); } - SASSERT(!pc); SASSERT(!core); + SASSERT(!core); return; } else { SASSERT(is_decided_unsat(r2)); - SASSERT(!pc2); SASSERT(!core2); if (models_enabled) mc_buffer.push_back(0); - if (proofs_enabled) pc_buffer.push_back(proof2proof_converter(m, r2[0]->pr(0))); if (models_enabled || proofs_enabled) sz_buffer.push_back(0); if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); } @@ -1023,28 +1013,35 @@ class repeat_tactical : public unary_tactical { else { result.append(r2.size(), r2.c_ptr()); if (models_enabled) mc_buffer.push_back(mc2.get()); - if (proofs_enabled) pc_buffer.push_back(pc2.get()); if (models_enabled || proofs_enabled) sz_buffer.push_back(r2.size()); if (cores_enabled) core = m.mk_join(core.get(), core2.get()); } } + + proof_converter_ref_buffer pc_buffer; + if (proofs_enabled) { + for (goal_ref g : r1) pc_buffer.push_back(g->pc()); + } if (result.empty()) { // all subgoals were shown to be unsat. // create an decided_unsat goal with the proof in->reset_all(); proof_ref pr(m); - if (proofs_enabled) - apply(m, pc1, pc_buffer, pr); + if (proofs_enabled) { + proof_converter_ref pc = in->pc(); + apply(m, pc, pc_buffer, pr); + in->set(proof2proof_converter(m, pr)); + } SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); core = 0; result.push_back(in.get()); - SASSERT(!mc); SASSERT(!pc); SASSERT(!core); + SASSERT(!mc); SASSERT(!core); } else { if (models_enabled) mc = concat(mc1.get(), mc_buffer.size(), mc_buffer.c_ptr(), sz_buffer.c_ptr()); - if (proofs_enabled) pc = concat(pc1.get(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr()); + if (proofs_enabled) in->set(concat(in->pc(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr())); SASSERT(cores_enabled || core == 0); } } @@ -1059,9 +1056,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - operator()(0, in, result, mc, pc, core); + operator()(0, in, result, mc, core); } virtual tactic * translate(ast_manager & m) { @@ -1082,13 +1078,11 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - m_t->operator()(in, result, mc, pc, core); + m_t->operator()(in, result, mc, core); if (result.size() > m_threshold) { result.reset(); mc = 0; - pc = 0; core = 0; throw tactic_exception("failed-if-branching tactical"); } @@ -1111,9 +1105,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - m_t->operator()(in, result, mc, pc, core); + m_t->operator()(in, result, mc, core); m_t->cleanup(); } @@ -1135,13 +1128,12 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { cancel_eh eh(in->m().limit()); { // Warning: scoped_timer is not thread safe in Linux. scoped_timer timer(m_timeout, &eh); - m_t->operator()(in, result, mc, pc, core); + m_t->operator()(in, result, mc, core); } } @@ -1205,10 +1197,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { scope _scope(m_name); - m_t->operator()(in, result, mc, pc, core); + m_t->operator()(in, result, mc, core); } virtual tactic * translate(ast_manager & m) { @@ -1239,12 +1230,11 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { if (m_p->operator()(*(in.get())).is_true()) - m_t1->operator()(in, result, mc, pc, core); + m_t1->operator()(in, result, mc, core); else - m_t2->operator()(in, result, mc, pc, core); + m_t2->operator()(in, result, mc, core); } virtual tactic * translate(ast_manager & m) { @@ -1280,10 +1270,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { mc = 0; - pc = 0; core = 0; if (m_p->operator()(*(in.get())).is_true()) { throw tactic_exception("fail-if tactic"); @@ -1311,15 +1299,14 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { if (in->proofs_enabled()) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, mc, pc, core); + m_t->operator()(in, result, mc, core); } } @@ -1333,15 +1320,14 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { if (in->unsat_core_enabled()) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, mc, pc, core); + m_t->operator()(in, result, mc, core); } } @@ -1355,15 +1341,14 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { if (in->models_enabled()) { - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, mc, pc, core); + m_t->operator()(in, result, mc, core); } } diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index 7a1838452..71034b2b1 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -40,10 +40,9 @@ class macro_finder_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("macro-finder", *g); bool produce_proofs = g->proofs_enabled(); @@ -120,9 +119,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index ee3cd14ec..c8c1f2b0f 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -38,10 +38,9 @@ class quasi_macros_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("quasi-macros", *g); bool produce_proofs = g->proofs_enabled(); @@ -131,9 +130,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index 615593317..e4ba71ad7 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -34,10 +34,9 @@ class ufbv_rewriter_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = 0; core = 0; tactic_report report("ufbv-rewriter", *g); fail_if_unsat_core_generation("ufbv-rewriter", g); @@ -103,9 +102,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, - proof_converter_ref & pc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, pc, core); + (*m_imp)(in, result, mc, core); } virtual void cleanup() { diff --git a/src/util/ref_buffer.h b/src/util/ref_buffer.h index 612dde2da..4768c3f28 100644 --- a/src/util/ref_buffer.h +++ b/src/util/ref_buffer.h @@ -82,6 +82,9 @@ public: return m_buffer[idx]; } + T* const* begin() const { return c_ptr(); } + T* const* end() const { return c_ptr() + size(); } + void set(unsigned idx, T * n) { inc_ref(n); dec_ref(m_buffer[idx]); From 00f5308a0e515fa375f0ac41beab41dea292c1e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 17 Nov 2017 23:50:48 -0800 Subject: [PATCH 0346/1283] fix copy function Signed-off-by: Nikolaj Bjorner --- src/tactic/goal.cpp | 2 ++ src/tactic/goal.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 7a98be3f1..778c3804b 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -105,6 +105,8 @@ void goal::copy_to(goal & target) const { SASSERT(target.m_core_enabled == m_core_enabled); target.m_inconsistent = m_inconsistent; target.m_precision = mk_union(prec(), target.prec()); + target.m_mc = m_mc.get(); + target.m_pc = m_pc.get(); } void goal::push_back(expr * f, proof * pr, expr_dependency * d) { diff --git a/src/tactic/goal.h b/src/tactic/goal.h index 275c80060..73fbb6f17 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -75,6 +75,7 @@ protected: unsigned get_not_idx(expr * f) const; void shrink(unsigned j); void reset_core(); + public: goal(ast_manager & m, bool models_enabled = true, bool core_enabled = false); @@ -107,7 +108,7 @@ public: void copy_to(goal & target) const; void copy_from(goal const & src) { src.copy_to(*this); } - + void assert_expr(expr * f, proof * pr, expr_dependency * d); void assert_expr(expr * f, expr_dependency * d); void assert_expr(expr * f, expr * d) { assert_expr(f, m().mk_leaf(d)); } From f476f949543b376ebd3ff46b7074561642c240ae Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Sat, 18 Nov 2017 15:07:18 -0800 Subject: [PATCH 0347/1283] merge commit Signed-off-by: Miguel Angelo Da Terra Neves --- src/api/dotnet/Solver.cs | 7 ++++--- src/tactic/generic_model_converter.cpp | 2 ++ src/tactic/generic_model_converter.h | 8 +++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 568ac79bf..e310f938c 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -429,11 +429,12 @@ namespace Microsoft.Z3 var lvl = BacktrackLevel; BacktrackLevel = uint.MaxValue; ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, lvl)); - if (r.Size == 1 && ((Expr)r[0]).IsFalse) { + var v = r.ToBoolExprArray(); + if (v.Length == 1 && v[0].IsFalse) { break; } - yield return r.ToBoolExprArray(); - if (r.Size == 0) { + yield return v; + if (v.Length == 0) { break; } } diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 629004869..7dec2f73b 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -87,5 +87,7 @@ void generic_model_converter::collect(ast_pp_util& visitor) { } void generic_model_converter::operator()(expr_ref& fml) { + // TODO: traverse expression and retrieve minimum trail index + // TODO: add func = expr starting at that index, removing from table if index is the same NOT_IMPLEMENTED_YET(); } diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index c58d0d029..1862efb8b 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -32,7 +32,9 @@ class generic_model_converter : public model_converter { m_f(f, m), m_def(d, m), m_instruction(i) {} }; ast_manager& m; - vector m_entries; + vector m_add_entries; + vector m_hide_entries; + obj_map m_first_idx; public: generic_model_converter(ast_manager & m): m(m) {} @@ -40,9 +42,9 @@ public: void hide(expr* e) { SASSERT(is_app(e) && to_app(e)->get_num_args() == 0); hide(to_app(e)->get_decl()); } - void hide(func_decl * f) { m_entries.push_back(entry(f, 0, m, HIDE)); } + void hide(func_decl * f) { m_hide_entries.push_back(entry(f, 0, m, HIDE)); } - void add(func_decl * d, expr* e) { m_entries.push_back(entry(d, e, m, ADD)); } + void add(func_decl * d, expr* e) { m_add_entries.push_back(entry(d, e, m, ADD)); } virtual void operator()(model_ref & md, unsigned goal_idx); From 4bbece661600c891672d3b2d8197db8368588bc0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 18 Nov 2017 16:33:54 -0800 Subject: [PATCH 0348/1283] re-organize proof and model converters to be associated with goals instead of external Signed-off-by: Nikolaj Bjorner --- .../ackermannize_bv_tactic.cpp | 5 +- src/api/api_goal.cpp | 15 + src/api/api_tactic.cpp | 41 +-- src/api/c++/z3++.h | 17 +- src/api/dotnet/ApplyResult.cs | 13 - src/api/dotnet/Goal.cs | 15 + src/api/java/ApplyResult.java | 13 - src/api/java/Goal.java | 15 + src/api/python/z3/z3.py | 65 ++-- src/api/z3_api.h | 17 +- src/cmd_context/echo_tactic.cpp | 6 +- src/cmd_context/tactic_cmds.cpp | 10 +- .../subpaving/tactic/subpaving_tactic.cpp | 2 - src/muz/base/dl_util.cpp | 15 +- src/muz/fp/horn_tactic.cpp | 10 +- src/muz/pdr/pdr_context.cpp | 5 +- src/muz/pdr/pdr_farkas_learner.cpp | 3 +- src/muz/pdr/pdr_manager.cpp | 2 +- src/muz/spacer/spacer_context.cpp | 7 +- src/muz/spacer/spacer_legacy_frames.cpp | 3 +- src/muz/spacer/spacer_manager.cpp | 2 +- src/muz/spacer/spacer_util.cpp | 6 +- src/muz/tab/tab_context.cpp | 2 +- src/muz/transforms/dl_mk_slice.cpp | 15 +- src/nlsat/tactic/nlsat_tactic.cpp | 12 +- src/opt/opt_context.cpp | 9 +- src/qe/nlqsat.cpp | 8 +- src/qe/qe_lite.cpp | 6 +- src/qe/qe_sat_tactic.cpp | 11 +- src/qe/qe_tactic.cpp | 6 +- src/qe/qsat.cpp | 5 +- src/sat/sat_solver/inc_sat_solver.cpp | 3 +- src/sat/tactic/goal2sat.cpp | 3 +- src/sat/tactic/sat_tactic.cpp | 10 +- src/smt/smt_solver.cpp | 2 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 3 +- src/smt/tactic/smt_tactic.cpp | 7 +- src/smt/tactic/unit_subsumption_tactic.cpp | 1 - src/solver/solver2tactic.cpp | 7 +- src/solver/tactic2solver.cpp | 3 +- src/tactic/aig/aig_tactic.cpp | 3 +- src/tactic/arith/add_bounds_tactic.cpp | 6 +- src/tactic/arith/arith_bounds_tactic.cpp | 1 - src/tactic/arith/card2bv_tactic.cpp | 9 +- src/tactic/arith/degree_shift_tactic.cpp | 8 +- src/tactic/arith/diff_neq_tactic.cpp | 11 +- src/tactic/arith/elim01_tactic.cpp | 17 +- src/tactic/arith/eq2bv_tactic.cpp | 5 +- src/tactic/arith/factor_tactic.cpp | 6 +- src/tactic/arith/fix_dl_var_tactic.cpp | 12 +- src/tactic/arith/fm_tactic.cpp | 10 +- src/tactic/arith/lia2card_tactic.cpp | 11 +- src/tactic/arith/lia2pb_tactic.cpp | 10 +- src/tactic/arith/nla2bv_tactic.cpp | 6 +- src/tactic/arith/normalize_bounds_tactic.cpp | 13 +- src/tactic/arith/pb2bv_model_converter.cpp | 63 ++-- src/tactic/arith/pb2bv_model_converter.h | 7 +- src/tactic/arith/pb2bv_tactic.cpp | 10 +- src/tactic/arith/propagate_ineqs_tactic.cpp | 5 +- src/tactic/arith/purify_arith_tactic.cpp | 9 +- src/tactic/arith/recover_01_tactic.cpp | 25 +- src/tactic/bv/bit_blaster_model_converter.cpp | 7 +- src/tactic/bv/bit_blaster_tactic.cpp | 12 +- src/tactic/bv/bv1_blaster_tactic.cpp | 8 +- src/tactic/bv/bv_bound_chk_tactic.cpp | 4 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 7 +- src/tactic/bv/bvarray2uf_tactic.cpp | 8 +- src/tactic/bv/dt2bv_tactic.cpp | 5 +- src/tactic/bv/elim_small_bv_tactic.cpp | 8 +- src/tactic/bv/max_bv_sharing_tactic.cpp | 6 +- src/tactic/core/blast_term_ite_tactic.cpp | 6 +- src/tactic/core/cofactor_term_ite_tactic.cpp | 3 +- src/tactic/core/collect_statistics_tactic.cpp | 8 +- src/tactic/core/ctx_simplify_tactic.cpp | 3 +- src/tactic/core/ctx_simplify_tactic.h | 1 - src/tactic/core/der_tactic.cpp | 3 +- src/tactic/core/distribute_forall_tactic.cpp | 3 +- src/tactic/core/dom_simplify_tactic.cpp | 3 +- src/tactic/core/dom_simplify_tactic.h | 1 - src/tactic/core/elim_term_ite_tactic.cpp | 8 +- src/tactic/core/elim_uncnstr_tactic.cpp | 18 +- src/tactic/core/injectivity_tactic.cpp | 6 +- src/tactic/core/nnf_tactic.cpp | 5 +- src/tactic/core/occf_tactic.cpp | 8 +- src/tactic/core/pb_preprocess_tactic.cpp | 6 +- src/tactic/core/propagate_values_tactic.cpp | 6 +- src/tactic/core/reduce_args_tactic.cpp | 13 +- src/tactic/core/simplify_tactic.cpp | 3 +- src/tactic/core/simplify_tactic.h | 1 - src/tactic/core/solve_eqs_tactic.cpp | 9 +- src/tactic/core/split_clause_tactic.cpp | 52 ++- src/tactic/core/symmetry_reduce_tactic.cpp | 4 +- src/tactic/core/tseitin_cnf_tactic.cpp | 10 +- src/tactic/equiv_proof_converter.h | 8 +- src/tactic/fpa/fpa2bv_model_converter.h | 10 +- src/tactic/fpa/fpa2bv_tactic.cpp | 10 +- src/tactic/generic_model_converter.cpp | 5 +- src/tactic/generic_model_converter.h | 14 +- src/tactic/model_converter.cpp | 92 +---- src/tactic/model_converter.h | 27 +- .../portfolio/bounded_int2bv_solver.cpp | 4 +- src/tactic/portfolio/enum2bv_solver.cpp | 4 +- src/tactic/portfolio/parallel_tactic.cpp | 5 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- src/tactic/proof_converter.cpp | 100 ++--- src/tactic/proof_converter.h | 23 +- src/tactic/replace_proof_converter.cpp | 9 +- src/tactic/replace_proof_converter.h | 6 +- src/tactic/sine_filter.cpp | 5 +- src/tactic/sls/sls_tactic.cpp | 6 +- src/tactic/smtlogics/qfufbv_tactic.cpp | 4 +- src/tactic/tactic.cpp | 54 ++- src/tactic/tactic.h | 27 +- src/tactic/tactical.cpp | 343 +++++------------- src/tactic/ufbv/macro_finder_tactic.cpp | 9 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 9 +- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 9 +- src/test/horn_subsume_model_converter.cpp | 10 +- 118 files changed, 617 insertions(+), 1070 deletions(-) diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index b9cdc706c..a38b19c7d 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -31,9 +31,7 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; tactic_report report("ackermannize", *g); fail_if_unsat_core_generation("ackermannize", g); fail_if_proof_generation("ackermannize", g); @@ -51,14 +49,13 @@ public: TRACE("ackermannize", tout << "ackermannize not run due to limit" << std::endl;); result.reset(); result.push_back(g.get()); - mc = 0; core = 0; return; } result.push_back(resg.get()); // report model if (g->models_enabled()) { - mc = mk_ackermannize_bv_model_converter(m, lackr.get_info()); + g->add(mk_ackermannize_bv_model_converter(m, lackr.get_info())); } resg->inc_depth(); diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index cf248c10e..cfda3e87c 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -21,6 +21,7 @@ Revision History: #include "api/api_context.h" #include "api/api_goal.h" #include "ast/ast_translation.h" +#include "api/api_model.h" extern "C" { @@ -151,6 +152,20 @@ extern "C" { Z3_CATCH_RETURN(Z3_FALSE); } + Z3_model Z3_API Z3_goal_convert_model(Z3_context c, Z3_goal g, Z3_model m) { + Z3_TRY; + LOG_Z3_goal_convert_model(c, g, m); + RESET_ERROR_CODE(); + model_ref new_m; + Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); + mk_c(c)->save_object(m_ref); + if (m) m_ref->m_model = to_model_ref(m)->copy(); + if (to_goal_ref(g)->mc()) + (*to_goal_ref(g)->mc())(m_ref->m_model); + RETURN_Z3(of_model(m_ref)); + Z3_CATCH_RETURN(0); + } + Z3_goal Z3_API Z3_goal_translate(Z3_context c, Z3_goal g, Z3_context target) { Z3_TRY; LOG_Z3_goal_translate(c, g, target); diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 3ee65ba36..2d9a47863 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -30,20 +30,20 @@ Z3_apply_result_ref::Z3_apply_result_ref(api::context& c, ast_manager & m): api: extern "C" { -#define RETURN_TACTIC(_t_) { \ +#define RETURN_TACTIC(_t_) { \ Z3_tactic_ref * _ref_ = alloc(Z3_tactic_ref, *mk_c(c)); \ - _ref_->m_tactic = _t_; \ - mk_c(c)->save_object(_ref_); \ - Z3_tactic _result_ = of_tactic(_ref_); \ - RETURN_Z3(_result_); \ + _ref_->m_tactic = _t_; \ + mk_c(c)->save_object(_ref_); \ + Z3_tactic _result_ = of_tactic(_ref_); \ + RETURN_Z3(_result_); \ } -#define RETURN_PROBE(_t_) { \ +#define RETURN_PROBE(_t_) { \ Z3_probe_ref * _ref_ = alloc(Z3_probe_ref, *mk_c(c)); \ - _ref_->m_probe = _t_; \ - mk_c(c)->save_object(_ref_); \ - Z3_probe _result_ = of_probe(_ref_); \ - RETURN_Z3(_result_); \ + _ref_->m_probe = _t_; \ + mk_c(c)->save_object(_ref_); \ + Z3_probe _result_ = of_probe(_ref_); \ + RETURN_Z3(_result_); \ } Z3_tactic Z3_API Z3_mk_tactic(Z3_context c, Z3_string name) { @@ -418,8 +418,9 @@ extern "C" { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); scoped_timer timer(timeout, &eh); try { - exec(*to_tactic_ref(t), new_goal, ref->m_subgoals, ref->m_mc, ref->m_core); + exec(*to_tactic_ref(t), new_goal, ref->m_subgoals, ref->m_core); ref->m_pc = new_goal->pc(); + ref->m_mc = new_goal->mc(); return of_apply_result(ref); } catch (z3_exception & ex) { @@ -514,22 +515,4 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_model Z3_API Z3_apply_result_convert_model(Z3_context c, Z3_apply_result r, unsigned i, Z3_model m) { - Z3_TRY; - LOG_Z3_apply_result_convert_model(c, r, i, m); - RESET_ERROR_CODE(); - if (i > to_apply_result(r)->m_subgoals.size()) { - SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); - } - model_ref new_m = to_model_ref(m)->copy(); - if (to_apply_result(r)->m_mc) - to_apply_result(r)->m_mc->operator()(new_m, i); - Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); - m_ref->m_model = new_m; - mk_c(c)->save_object(m_ref); - RETURN_Z3(of_model(m_ref)); - Z3_CATCH_RETURN(0); - } - }; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index a2937cb8e..428f210ee 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2104,6 +2104,17 @@ namespace z3 { unsigned num_exprs() const { return Z3_goal_num_exprs(ctx(), m_goal); } bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; } bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; } + model convert_model(model const & m) const { + check_context(*this, m); + Z3_model new_m = Z3_goal_convert_model(ctx(), m_goal, m); + check_error(); + return model(ctx(), new_m); + } + model get_model() const { + Z3_model new_m = Z3_goal_convert_model(ctx(), m_goal, 0); + check_error(); + return model(ctx(), new_m); + } expr as_expr() const { unsigned n = size(); if (n == 0) @@ -2142,12 +2153,6 @@ namespace z3 { } unsigned size() const { return Z3_apply_result_get_num_subgoals(ctx(), m_apply_result); } goal operator[](int i) const { assert(0 <= i); Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); } - model convert_model(model const & m, unsigned i = 0) const { - check_context(*this, m); - Z3_model new_m = Z3_apply_result_convert_model(ctx(), m_apply_result, i, m); - check_error(); - return model(ctx(), new_m); - } friend std::ostream & operator<<(std::ostream & out, apply_result const & r); }; inline std::ostream & operator<<(std::ostream & out, apply_result const & r) { out << Z3_apply_result_to_string(r.ctx(), r); return out; } diff --git a/src/api/dotnet/ApplyResult.cs b/src/api/dotnet/ApplyResult.cs index 608be7080..db2922460 100644 --- a/src/api/dotnet/ApplyResult.cs +++ b/src/api/dotnet/ApplyResult.cs @@ -55,19 +55,6 @@ namespace Microsoft.Z3 } } - /// - /// Convert a model for the subgoal into a model for the original - /// goal g, that the ApplyResult was obtained from. - /// - /// A model for g - public Model ConvertModel(uint i, Model m) - { - Contract.Requires(m != null); - Contract.Ensures(Contract.Result() != null); - - return new Model(Context, Native.Z3_apply_result_convert_model(Context.nCtx, NativeObject, i, m.NativeObject)); - } - /// /// A string representation of the ApplyResult. /// diff --git a/src/api/dotnet/Goal.cs b/src/api/dotnet/Goal.cs index 25aeba741..03e573538 100644 --- a/src/api/dotnet/Goal.cs +++ b/src/api/dotnet/Goal.cs @@ -174,6 +174,21 @@ namespace Microsoft.Z3 get { return Native.Z3_goal_is_decided_unsat(Context.nCtx, NativeObject) != 0; } } + /// + /// Convert a model for the goal into a model of the + /// original goal from which this goal was derived. + /// + /// A model for g + public Model ConvertModel(Model m) + { + Contract.Ensures(Contract.Result() != null); + if (m != null) + return new Model(Context, Native.Z3_goal_convert_model(Context.nCtx, NativeObject, m.NativeObject)); + else + return new Model(Context, Native.Z3_goal_convert_model(Context.nCtx, NativeObject, IntPtr.Zero)); + } + + /// /// Translates (copies) the Goal to the target Context . /// diff --git a/src/api/java/ApplyResult.java b/src/api/java/ApplyResult.java index 6fafbd888..6cfedd404 100644 --- a/src/api/java/ApplyResult.java +++ b/src/api/java/ApplyResult.java @@ -46,19 +46,6 @@ public class ApplyResult extends Z3Object { return res; } - /** - * Convert a model for the subgoal {@code i} into a model for the - * original goal {@code g}, that the ApplyResult was obtained from. - * - * @return A model for {@code g} - * @throws Z3Exception - **/ - public Model convertModel(int i, Model m) - { - return new Model(getContext(), - Native.applyResultConvertModel(getContext().nCtx(), getNativeObject(), i, m.getNativeObject())); - } - /** * A string representation of the ApplyResult. **/ diff --git a/src/api/java/Goal.java b/src/api/java/Goal.java index 25b1fe511..903325850 100644 --- a/src/api/java/Goal.java +++ b/src/api/java/Goal.java @@ -240,6 +240,21 @@ public class Goal extends Z3Object { (unsatCores), (proofs))); } + /** + * Convert a model for the goal into a model of the + * original goal from which this goal was derived. + * + * @return A model for {@code g} + * @throws Z3Exception + **/ + public Model convertModel(Model m) + { + return new Model(getContext(), + Native.goalConvertModel(getContext().nCtx(), getNativeObject(), m.getNativeObject())); + } + + + @Override void incRef() { Native.goalIncRef(getContext().nCtx(), getNativeObject()); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index e281a1273..f911732ef 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -4964,6 +4964,35 @@ class Goal(Z3PPObject): """ self.assert_exprs(*args) + def convert_model(self, model): + """Retrieve model from a satisfiable goal + >>> a, b = Ints('a b') + >>> g = Goal() + >>> g.add(Or(a == 0, a == 1), Or(b == 0, b == 1), a > b) + >>> t = Then(Tactic('split-clause'), Tactic('solve-eqs')) + >>> r = t(g) + >>> r[0] + [Or(b == 0, b == 1), Not(0 <= b)] + >>> r[1] + [Or(b == 0, b == 1), Not(1 <= b)] + >>> # Remark: the subgoal r[0] is unsatisfiable + >>> # Creating a solver for solving the second subgoal + >>> s = Solver() + >>> s.add(r[1]) + >>> s.check() + sat + >>> s.model() + [b = 0] + >>> # Model s.model() does not assign a value to `a` + >>> # It is a model for subgoal `r[1]`, but not for goal `g` + >>> # The method convert_model creates a model for `g` from a model for `r[1]`. + >>> r[1].convert_model(s.model()) + [b = 0, a = 1] + """ + if __debug__: + _z3_assert(isinstance(model, ModelRef), "Z3 Model expected") + return ModelRef(Z3_goal_convert_model(self.ctx.ref(), self.goal, model.model), self.ctx) + def __repr__(self): return obj_to_string(self) @@ -7072,36 +7101,6 @@ class ApplyResult(Z3PPObject): """Return a textual representation of the s-expression representing the set of subgoals in `self`.""" return Z3_apply_result_to_string(self.ctx.ref(), self.result) - def convert_model(self, model, idx=0): - """Convert a model for a subgoal into a model for the original goal. - - >>> a, b = Ints('a b') - >>> g = Goal() - >>> g.add(Or(a == 0, a == 1), Or(b == 0, b == 1), a > b) - >>> t = Then(Tactic('split-clause'), Tactic('solve-eqs')) - >>> r = t(g) - >>> r[0] - [Or(b == 0, b == 1), Not(0 <= b)] - >>> r[1] - [Or(b == 0, b == 1), Not(1 <= b)] - >>> # Remark: the subgoal r[0] is unsatisfiable - >>> # Creating a solver for solving the second subgoal - >>> s = Solver() - >>> s.add(r[1]) - >>> s.check() - sat - >>> s.model() - [b = 0] - >>> # Model s.model() does not assign a value to `a` - >>> # It is a model for subgoal `r[1]`, but not for goal `g` - >>> # The method convert_model creates a model for `g` from a model for `r[1]`. - >>> r.convert_model(s.model(), 1) - [b = 0, a = 1] - """ - if __debug__: - _z3_assert(idx < len(self), "index out of bounds") - _z3_assert(isinstance(model, ModelRef), "Z3 Model expected") - return ModelRef(Z3_apply_result_convert_model(self.ctx.ref(), self.result, idx, model.model), self.ctx) def as_expr(self): """Return a Z3 expression consisting of all subgoals. @@ -8057,13 +8056,13 @@ def parse_smt2_string(s, sorts={}, decls={}, ctx=None): the symbol table used for the SMT 2.0 parser. >>> parse_smt2_string('(declare-const x Int) (assert (> x 0)) (assert (< x 10))') - And(x > 0, x < 10) + [x > 0, x < 10] >>> x, y = Ints('x y') >>> f = Function('f', IntSort(), IntSort()) >>> parse_smt2_string('(assert (> (+ foo (g bar)) 0))', decls={ 'foo' : x, 'bar' : y, 'g' : f}) - x + f(y) > 0 + [x + f(y) > 0] >>> parse_smt2_string('(declare-const a U) (assert (> a 0))', sorts={ 'U' : IntSort() }) - a > 0 + [a > 0] """ ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 67fc0c903..c9603c018 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5561,6 +5561,15 @@ extern "C" { */ Z3_goal Z3_API Z3_goal_translate(Z3_context source, Z3_goal g, Z3_context target); + /** + \brief Convert a model of the formulas of a goal to a model of an original goal. + The model may be null, in which case the returned model is valid if the goal was + established satisfiable. + + def_API('Z3_goal_convert_model', MODEL, (_in(CONTEXT), _in(GOAL), _in(MODEL))) + */ + Z3_model Z3_API Z3_goal_convert_model(Z3_context c, Z3_goal g, Z3_model m); + /** \brief Convert a goal into a string. @@ -5927,14 +5936,6 @@ extern "C" { */ Z3_goal Z3_API Z3_apply_result_get_subgoal(Z3_context c, Z3_apply_result r, unsigned i); - /** - \brief Convert a model for the subgoal \c Z3_apply_result_get_subgoal(c, r, i) into a model for the original goal \c g. - Where \c g is the goal used to create \c r using \c Z3_tactic_apply(c, t, g). - - def_API('Z3_apply_result_convert_model', MODEL, (_in(CONTEXT), _in(APPLY_RESULT), _in(UINT), _in(MODEL))) - */ - Z3_model Z3_API Z3_apply_result_convert_model(Z3_context c, Z3_apply_result r, unsigned i, Z3_model m); - /*@}*/ /** @name Solvers*/ diff --git a/src/cmd_context/echo_tactic.cpp b/src/cmd_context/echo_tactic.cpp index 3b4f8962f..37dcc0a29 100644 --- a/src/cmd_context/echo_tactic.cpp +++ b/src/cmd_context/echo_tactic.cpp @@ -29,7 +29,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { #pragma omp critical (echo_tactic) { @@ -37,7 +36,7 @@ public: if (m_newline) m_ctx.regular_stream() << std::endl; } - skip_tactic::operator()(in, result, mc, core); + skip_tactic::operator()(in, result, core); } }; @@ -62,7 +61,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { double val = (*m_p)(*(in.get())).get_value(); #pragma omp critical (probe_value_tactic) @@ -73,7 +71,7 @@ public: if (m_newline) m_ctx.diagnostic_stream() << std::endl; } - skip_tactic::operator()(in, result, mc, core); + skip_tactic::operator()(in, result, core); } }; diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 1cdde738e..20f6fc632 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -213,7 +213,6 @@ public: assert_exprs_from(ctx, *g); TRACE("check_sat_using", g->display(tout);); model_ref md; - model_converter_ref mc; proof_ref pr(m); expr_dependency_ref core(m); std::string reason_unknown; @@ -229,7 +228,7 @@ public: cmd_context::scoped_watch sw(ctx); lbool r = l_undef; try { - r = check_sat(t, g, md, mc, result->labels, pr, core, reason_unknown); + r = check_sat(t, g, md, result->labels, pr, core, reason_unknown); ctx.display_sat_result(r); result->set_status(r); if (r == l_undef) { @@ -327,7 +326,6 @@ public: unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit); goal_ref_buffer result_goals; - model_converter_ref mc; expr_dependency_ref core(m); std::string reason_unknown; @@ -339,7 +337,7 @@ public: scoped_timer timer(timeout, &eh); cmd_context::scoped_watch sw(ctx); try { - exec(t, g, result_goals, mc, core); + exec(t, g, result_goals, core); } catch (tactic_exception & ex) { ctx.regular_stream() << "(error \"tactic failed: " << ex.msg() << "\")" << std::endl; @@ -398,8 +396,8 @@ public: } } - if (!failed && mc && p.get_bool("print_model_converter", false)) - mc->display(ctx.regular_stream()); + if (!failed && g->mc() && p.get_bool("print_model_converter", false)) + g->mc()->display(ctx.regular_stream()); if (p.get_bool("print_statistics", false)) display_statistics(ctx, tref.get()); diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index cb5cf9703..5940dcbfc 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -243,14 +243,12 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { m_imp->process(*in); m_imp->collect_statistics(m_stats); result.reset(); result.push_back(in.get()); - mc = 0; core = 0; } catch (z3_exception & ex) { diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 463b78c4a..b781a8640 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -380,26 +380,29 @@ namespace datalog { public: skip_model_converter() {} - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { return alloc(skip_model_converter); } - virtual void display(std::ostream & out) { } + void operator()(model_ref&) override {} + + void display(std::ostream & out) override { } }; model_converter* mk_skip_model_converter() { return alloc(skip_model_converter); } class skip_proof_converter : public proof_converter { - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + + proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { SASSERT(num_source == 1); - result = source[0]; + return proof_ref(source[0], m); } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return alloc(skip_proof_converter); } - virtual void display(std::ostream & out) { out << "(skip-proof-converter)\n"; } + void display(std::ostream & out) override { out << "(skip-proof-converter)\n"; } }; proof_converter* mk_skip_proof_converter() { return alloc(skip_proof_converter); } diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 5fd41facc..4802bbb33 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -178,10 +178,9 @@ class horn_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("horn", *g); bool produce_proofs = g->proofs_enabled(); @@ -230,11 +229,12 @@ class horn_tactic : public tactic { queries.push_back(q); generic_model_converter* mc1 = alloc(generic_model_converter, m); mc1->hide(q); - mc = mc1; + g->add(mc1); } SASSERT(queries.size() == 1); q = queries[0].get(); proof_converter_ref pc = g->pc(); + model_converter_ref mc; if (m_is_simplify) { simplify(q, g, result, mc, pc); } @@ -242,6 +242,7 @@ class horn_tactic : public tactic { verify(q, g, result, mc, pc); } g->set(pc.get()); + g->set(mc.get()); } void verify(expr* q, @@ -386,9 +387,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void collect_statistics(statistics & st) const { diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index e3681d366..452be8914 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -202,10 +202,9 @@ namespace pdr { void pred_transformer::simplify_formulas(tactic& tac, expr_ref_vector& v) { goal_ref g(alloc(goal, m, false, false, false)); for (unsigned j = 0; j < v.size(); ++j) g->assert_expr(v[j].get()); - model_converter_ref mc; expr_dependency_ref core(m); goal_ref_buffer result; - tac(g, result, mc, core); + tac(g, result, core); SASSERT(result.size() == 1); goal* r = result[0]; v.reset(); @@ -390,7 +389,7 @@ namespace pdr { md->register_decl(m_head, fi); } model_converter_ref mc = ctx.get_model_converter(); - apply(mc, md, 0); + apply(mc, md); if (p_orig->get_arity() == 0) { result = md->get_const_interp(p_orig); } diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 83b0d2c00..68a9db2ef 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -520,11 +520,10 @@ namespace pdr { g->assert_expr(lemmas[i].get()); } expr_ref tmp(m); - model_converter_ref mc; expr_dependency_ref core(m); goal_ref_buffer result; tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result, mc, core); + (*simplifier)(g, result, core); lemmas.reset(); SASSERT(result.size() == 1); goal* r = result[0]; diff --git a/src/muz/pdr/pdr_manager.cpp b/src/muz/pdr/pdr_manager.cpp index 077d27427..da15bf094 100644 --- a/src/muz/pdr/pdr_manager.cpp +++ b/src/muz/pdr/pdr_manager.cpp @@ -107,7 +107,7 @@ namespace pdr { } } TRACE("pdr", model_smt2_pp(tout, m, *md, 0);); - apply(const_cast(m_mc), md, 0); + apply(const_cast(m_mc), md); } expr_ref inductive_property::to_expr() const { diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 484456640..d1350d29a 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -528,7 +528,7 @@ expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) md->register_decl(m_head, fi); } model_converter_ref mc = ctx.get_model_converter(); - apply(mc, md, 0); + apply(mc, md); if (p_orig->get_arity() == 0) { result = md->get_const_interp(p_orig); } else { @@ -1367,7 +1367,6 @@ void pred_transformer::frames::simplify_formulas () // normalize level unsigned level = i < m_size ? i : infty_level (); - model_converter_ref mc; expr_dependency_ref core(m); goal_ref_buffer result; @@ -1394,7 +1393,7 @@ void pred_transformer::frames::simplify_formulas () } // more than one lemma at current level. simplify. - (*simplifier)(g, result, mc, core); + (*simplifier)(g, result, core); SASSERT(result.size () == 1); goal *r = result[0]; @@ -2062,8 +2061,8 @@ bool context::validate() expr_ref_vector refs(m); expr_ref tmp(m); model_ref model; - vector rs; model_converter_ref mc; + vector rs; get_level_property(m_inductive_lvl, refs, rs); inductive_property ex(m, mc, rs); ex.to_model(model); diff --git a/src/muz/spacer/spacer_legacy_frames.cpp b/src/muz/spacer/spacer_legacy_frames.cpp index 5c7fae9ac..176e0101b 100644 --- a/src/muz/spacer/spacer_legacy_frames.cpp +++ b/src/muz/spacer/spacer_legacy_frames.cpp @@ -46,10 +46,9 @@ void pred_transformer::legacy_frames::simplify_formulas(tactic& tac, ast_manager &m = m_pt.get_ast_manager(); goal_ref g(alloc(goal, m, false, false, false)); for (unsigned j = 0; j < v.size(); ++j) { g->assert_expr(v[j].get()); } - model_converter_ref mc; expr_dependency_ref core(m); goal_ref_buffer result; - tac(g, result, mc, core); + tac(g, result, core); SASSERT(result.size() == 1); goal* r = result[0]; v.reset(); diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index 4ad3e0d7f..ba4ca0da7 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -113,7 +113,7 @@ void inductive_property::to_model(model_ref& md) const } } TRACE("spacer", model_smt2_pp(tout, m, *md, 0);); - apply(const_cast(m_mc), md, 0); + apply(const_cast(m_mc), md); } expr_ref inductive_property::to_expr() const diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 05c26b923..726ff86c8 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -929,11 +929,10 @@ void simplify_bounds_old(expr_ref_vector& cube) { } expr_ref tmp(m); - model_converter_ref mc; expr_dependency_ref core(m); goal_ref_buffer result; tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result, mc, core); + (*simplifier)(g, result, core); SASSERT(result.size() == 1); goal* r = result[0]; @@ -954,14 +953,13 @@ void simplify_bounds_new (expr_ref_vector &cube) { g->assert_expr(cube.get(i)); } - model_converter_ref mc; expr_dependency_ref dep(m); goal_ref_buffer goals; tactic_ref prop_values = mk_propagate_values_tactic(m); tactic_ref prop_bounds = mk_propagate_ineqs_tactic(m); tactic_ref t = and_then(prop_values.get(), prop_bounds.get()); - (*t)(g, goals, mc, dep); + (*t)(g, goals, dep); SASSERT(goals.size() == 1); g = goals[0]; diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index 8809c0dc7..ad3006508 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -1602,7 +1602,7 @@ namespace datalog { pc.invert(); prs.push_back(m.mk_asserted(root)); - pc(m, 1, prs.c_ptr(), pr); + pr = pc(m, 1, prs.c_ptr()); return pr; } diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index 8b38335e0..ce1b8e582 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -271,20 +271,21 @@ namespace datalog { m_renaming.insert(orig_rule, unsigned_vector(sz, renaming)); } - virtual void operator()(ast_manager& m, unsigned num_source, proof * const * source, proof_ref & result) { + proof_ref operator()(ast_manager& m, unsigned num_source, proof * const * source) override { SASSERT(num_source == 1); - result = source[0]; + proof_ref result(source[0], m); init_form2rule(); translate_proof(result); + return result; } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { UNREACHABLE(); // this would require implementing translation for the dl_context. return 0; } - virtual void display(std::ostream& out) { out << "(slice-proof-converter)\n"; } + void display(std::ostream& out) override { out << "(slice-proof-converter)\n"; } }; class mk_slice::slice_model_converter : public model_converter { @@ -307,7 +308,7 @@ namespace datalog { m_sliceable.insert(f, bv); } - virtual void operator()(model_ref & md) { + void operator()(model_ref & md) override { if (m_slice2old.empty()) { return; } @@ -393,12 +394,12 @@ namespace datalog { TRACE("dl", model_smt2_pp(tout, m, *md, 0); ); } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { UNREACHABLE(); return 0; } - virtual void display(std::ostream& out) { out << "(slice-model-converter)\n"; } + void display(std::ostream& out) override { out << "(slice-model-converter)\n"; } }; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 5757220b4..bedd7c655 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -130,10 +130,9 @@ class nlsat_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("nlsat", *g); if (g->is_decided()) { @@ -165,9 +164,11 @@ class nlsat_tactic : public tactic { if (!contains_unsupported(b2a, x2t)) { // If mk_model is false it means that the model produced by nlsat // assigns noninteger values to integer variables + model_converter_ref mc; if (mk_model(*g.get(), b2a, x2t, mc)) { // result goal is trivially SAT g->reset(); + g->add(mc.get()); } } } @@ -176,8 +177,8 @@ class nlsat_tactic : public tactic { if (g->unsat_core_enabled()) { vector assumptions; m_solver.get_core(assumptions); - for (unsigned i = 0; i < assumptions.size(); ++i) { - expr_dependency* d = static_cast(assumptions[i]); + for (nlsat::assumption a : assumptions) { + expr_dependency* d = static_cast(a); lcore = m.mk_join(lcore, d); } } @@ -233,12 +234,11 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { imp local_imp(in->m(), m_params); scoped_set_imp setter(*this, local_imp); - local_imp(in, result, mc, core); + local_imp(in, result, core); } catch (z3_error & ex) { throw ex; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 19cfc4b9c..edcdb64e0 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -324,10 +324,8 @@ namespace opt { void context::fix_model(model_ref& mdl) { if (mdl) { - if (m_model_converter) { - (*m_model_converter)(mdl, 0); - } - m_fm(mdl, 0); + apply(m_model_converter, mdl); + m_fm(mdl); } } @@ -749,9 +747,10 @@ namespace opt { } expr_dependency_ref core(m); goal_ref_buffer result; - (*m_simplify)(g, result, m_model_converter, core); + (*m_simplify)(g, result, core); SASSERT(result.size() == 1); goal* r = result[0]; + m_model_converter = r->mc(); fmls.reset(); expr_ref tmp(m); for (unsigned i = 0; i < r->size(); ++i) { diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index e593e6627..87e713efc 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -659,9 +659,8 @@ namespace qe { goal_ref g = alloc(goal, m); g->assert_expr(fml); expr_dependency_ref core(m); - model_converter_ref mc; goal_ref_buffer result; - (*m_nftactic)(g, result, mc, core); + (*m_nftactic)(g, result, core); SASSERT(result.size() == 1); TRACE("qe", result[0]->display(tout);); g2s(*result[0], m_params, m_solver, m_a2b, m_t2x); @@ -812,14 +811,13 @@ namespace qe { void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, /* out */ expr_dependency_ref & core) { tactic_report report("nlqsat-tactic", *in); ptr_vector fmls; expr_ref fml(m); - mc = 0; core = 0; + core = 0; in->get_formulas(fmls); fml = mk_and(m, fmls.size(), fmls.c_ptr()); if (m_mode == elim_t) { @@ -850,7 +848,9 @@ namespace qe { in->inc_depth(); result.push_back(in.get()); if (in->models_enabled()) { + model_converter_ref mc; VERIFY(mk_model(mc)); + in->add(mc.get()); } break; case l_undef: diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index c7b16417c..51e5c1b78 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -2533,10 +2533,9 @@ class qe_lite_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("qe-lite", *g); proof_ref new_pr(m); expr_ref new_f(m); @@ -2603,9 +2602,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 6f09df5b6..28bc78f84 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -234,7 +234,6 @@ namespace qe { virtual void operator()( goal_ref const& goal, goal_ref_buffer& result, - model_converter_ref& mc, expr_dependency_ref& core) { try { @@ -259,7 +258,7 @@ namespace qe { else { goal->reset(); // equi-satisfiable. What to do with model? - mc = model2model_converter(&*model); + goal->add(model2model_converter(&*model)); } result.push_back(goal.get()); } @@ -269,16 +268,16 @@ namespace qe { } virtual void collect_statistics(statistics & st) const { - for (unsigned i = 0; i < m_solvers.size(); ++i) { - m_solvers[i]->collect_statistics(st); + for (auto const * s : m_solvers) { + s->collect_statistics(st); } m_solver.collect_statistics(st); m_ctx_rewriter.collect_statistics(st); } virtual void reset_statistics() { - for (unsigned i = 0; i < m_solvers.size(); ++i) { - m_solvers[i]->reset_statistics(); + for (auto * s : m_solvers) { + s->reset_statistics(); } m_solver.reset_statistics(); m_ctx_rewriter.reset_statistics(); diff --git a/src/qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp index ce1b3003a..131d0d3fb 100644 --- a/src/qe/qe_tactic.cpp +++ b/src/qe/qe_tactic.cpp @@ -51,10 +51,9 @@ class qe_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("qe", *g); m_fparams.m_model = g->models_enabled(); proof_ref new_pr(m); @@ -121,9 +120,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); m_st.reset(); m_imp->collect_statistics(m_st); diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 3040a68fe..ca8a36844 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -1212,13 +1212,12 @@ namespace qe { void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, /* out */ expr_dependency_ref & core) { tactic_report report("qsat-tactic", *in); ptr_vector fmls; expr_ref_vector defs(m); expr_ref fml(m); - mc = 0; core = 0; + core = 0; in->get_formulas(fmls); @@ -1271,8 +1270,10 @@ namespace qe { in->inc_depth(); result.push_back(in.get()); if (in->models_enabled()) { + model_converter_ref mc; mc = model2model_converter(m_model.get()); mc = concat(m_pred_abs.fmc(), mc.get()); + in->add(mc.get()); } break; case l_undef: diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 29de5f107..d391eddd0 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -505,7 +505,7 @@ private: SASSERT(!g->proofs_enabled()); TRACE("sat", g->display(tout);); try { - (*m_preprocess)(g, m_subgoals, m_mc, m_dep_core); + (*m_preprocess)(g, m_subgoals, m_dep_core); } catch (tactic_exception & ex) { IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); @@ -521,6 +521,7 @@ private: g = m_subgoals[0]; expr_ref_vector atoms(m); m_pc = g->pc(); + m_mc = g->mc(); TRACE("sat", g->display_with_dependencies(tout);); m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, false, is_lemma); m_goal2sat.get_interpreted_atoms(atoms); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index d730ea0ee..7c703653c 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -922,8 +922,7 @@ struct sat2goal::imp { } } - virtual void operator()(model_ref & md, unsigned goal_idx) { - SASSERT(goal_idx == 0); + virtual void operator()(model_ref & md) { TRACE("sat_mc", tout << "before sat_mc\n"; model_v2_pp(tout, *md); display(tout);); // REMARK: potential problem // model_evaluator can't evaluate quantifiers. Then, diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index ba6b53e17..413dfa9bf 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -40,9 +40,8 @@ class sat_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; fail_if_proof_generation("sat", g); bool produce_models = g->models_enabled(); bool produce_core = g->unsat_core_enabled(); @@ -102,7 +101,7 @@ class sat_tactic : public tactic { } } TRACE("sat_tactic", model_v2_pp(tout, *md);); - mc = model2model_converter(md.get()); + g->add(model2model_converter(md.get())); } } else { @@ -111,7 +110,9 @@ class sat_tactic : public tactic { IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "\"formula constains interpreted atoms, recovering formula from sat solver...\"\n";); #endif m_solver.pop_to_base_level(); + model_converter_ref mc; m_sat2goal(m_solver, map, m_params, *(g.get()), mc); + g->add(mc.get()); } g->inc_depth(); result.push_back(g.get()); @@ -175,12 +176,11 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { imp proc(g->m(), m_params); scoped_set_imp set(this, &proc); try { - proc(g, result, mc, core); + proc(g, result, core); proc.m_solver.collect_statistics(m_stats); } catch (sat::solver_exception & ex) { diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 7866f15e9..68312c6a9 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -109,7 +109,7 @@ namespace smt { if (m_name2assertion.contains(a)) { throw default_exception("named assertion defined twice"); } - solver_na2as::assert_expr(t, a); + solver_na2as::assert_expr_core(t, a); get_manager().inc_ref(t); m_name2assertion.insert(a, t); } diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 5b2537b9b..d504a63b2 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -71,10 +71,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; reduce(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 08ce9bded..2bb68d590 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -146,11 +146,10 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { IF_VERBOSE(10, verbose_stream() << "(smt.tactic start)\n";); - mc = 0; core = 0; + core = 0; SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " " @@ -220,8 +219,10 @@ public: m_ctx->get_model(md); buffer r; m_ctx->get_relevant_labels(0, r); + model_converter_ref mc; mc = model_and_labels2model_converter(md.get(), r); mc = concat(fmc.get(), mc.get()); + in->add(mc.get()); } return; } @@ -269,7 +270,7 @@ public: m_ctx->get_model(md); buffer r; m_ctx->get_relevant_labels(0, r); - mc = model_and_labels2model_converter(md.get(), r); + in->add(model_and_labels2model_converter(md.get(), r)); } return; default: diff --git a/src/smt/tactic/unit_subsumption_tactic.cpp b/src/smt/tactic/unit_subsumption_tactic.cpp index f02829af0..0b900426b 100644 --- a/src/smt/tactic/unit_subsumption_tactic.cpp +++ b/src/smt/tactic/unit_subsumption_tactic.cpp @@ -41,7 +41,6 @@ struct unit_subsumption_tactic : public tactic { virtual void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, /* out */ expr_dependency_ref & core) { reduce_core(in, result); } diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 7d3076643..60a7404b6 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -103,9 +103,8 @@ public: virtual void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, /* out */ expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; expr_ref_vector clauses(m); expr2expr_map bool2dep; ptr_vector assumptions; @@ -119,9 +118,11 @@ public: if (in->models_enabled()) { model_ref mdl; local_solver->get_model(mdl); + model_converter_ref mc; mc = model2model_converter(mdl.get()); mc = concat(fmc.get(), mc.get()); mc = concat(local_solver->mc0(), mc.get()); + in->add(mc.get()); } in->reset(); result.push_back(in.get()); @@ -150,9 +151,11 @@ public: if (m.canceled()) { throw tactic_exception(Z3_CANCELED_MSG); } + model_converter_ref mc; mc = local_solver->get_model_converter(); mc = concat(fmc.get(), mc.get()); in->reset(); + in->add(mc.get()); unsigned sz = local_solver->get_num_assertions(); for (unsigned i = 0; i < sz; ++i) { in->assert_expr(local_solver->get_assertion(i)); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 35fe9cf8e..4585af65e 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -159,7 +159,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass std::string reason_unknown = "unknown"; labels_vec labels; try { - switch (::check_sat(*m_tactic, g, md, m_mc, labels, pr, core, reason_unknown)) { + switch (::check_sat(*m_tactic, g, md, labels, pr, core, reason_unknown)) { case l_true: m_result->set_status(l_true); break; @@ -176,6 +176,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass } break; } + m_mc = g->mc(); } catch (z3_error & ex) { TRACE("tactic2solver", tout << "exception: " << ex.msg() << "\n";); diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index e51dc527c..6de44c654 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -92,10 +92,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { fail_if_proof_generation("aig", g); - mc = 0; core = 0; + core = 0; operator()(g); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index 50a30b0ef..852eb9cc0 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -112,9 +112,8 @@ class add_bounds_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; tactic_report report("add-bounds", *g); bound_manager bm(m); expr_fast_mark1 visited; @@ -161,9 +160,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(g, result, mc, core); + (*m_imp)(g, result, core); } virtual void cleanup() { diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index bc7d4b51f..d86d8dd8f 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -25,7 +25,6 @@ struct arith_bounds_tactic : public tactic { virtual void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, /* out */ expr_dependency_ref & core) { bounds_arith_subsumption(in, result); } diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index c2715da7a..ec9f92a35 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -54,11 +54,10 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { TRACE("card2bv-before", g->display(tout);); SASSERT(g->is_well_sorted()); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); tactic_report report("card2bv", *g); th_rewriter rw1(m, m_params); pb2bv_rewriter rw2(m, m_params); @@ -89,10 +88,8 @@ public: func_decl_ref_vector const& fns = rw2.fresh_constants(); if (!fns.empty()) { generic_model_converter* filter = alloc(generic_model_converter, m); - for (unsigned i = 0; i < fns.size(); ++i) { - filter->hide(fns[i]); - } - mc = filter; + for (func_decl* f : fns) filter->hide(f); + g->add(filter); } g->inc_depth(); diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 06e81bc68..62b030706 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -224,14 +224,14 @@ class degree_shift_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; m_produce_proofs = g->proofs_enabled(); m_produce_models = g->models_enabled(); tactic_report report("degree_shift", *g); collect(*g); + model_converter_ref mc; discard_non_candidates(); if (!m_var2degree.empty()) { prepare_substitution(mc); @@ -269,6 +269,7 @@ class degree_shift_tactic : public tactic { } } g->inc_depth(); + g->add(mc.get()); result.push_back(g.get()); TRACE("degree_shift", g->display(tout); if (mc) mc->display(tout);); SASSERT(g->is_well_sorted()); @@ -291,9 +292,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index 1bc1c4b73..06966178f 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -314,11 +314,10 @@ class diff_neq_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); m_produce_models = g->models_enabled(); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); tactic_report report("diff-neq", *g); fail_if_proof_generation("diff-neq", g); fail_if_unsat_core_generation("diff-neq", g); @@ -331,8 +330,9 @@ class diff_neq_tactic : public tactic { bool r = search(); report_tactic_progress(":conflicts", m_num_conflicts); if (r) { - if (m_produce_models) - mc = model2model_converter(mk_model()); + if (m_produce_models) { + g->add(model2model_converter(mk_model())); + } g->reset(); } else { @@ -384,9 +384,8 @@ public: */ virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index dd1dfbd7e..731ca4b5d 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -41,8 +41,7 @@ public: m_refs(m) {} - virtual void operator()(model_ref & old_model, unsigned goal_idx) { - SASSERT(goal_idx == 0); + virtual void operator()(model_ref & old_model) { model * new_model = alloc(model, m); unsigned num = old_model->get_num_constants(); for (unsigned i = 0; i < m_nums_as_int.size(); ++i) { @@ -154,16 +153,14 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("elim01", *g); expr_safe_replace sub(m); - bool2int_model_converter* b2i = alloc(bool2int_model_converter, m); - mc = b2i; + ref b2i = alloc(bool2int_model_converter, m); bound_manager bounds(m); expr_ref_vector axioms(m); bounds(*g); @@ -178,7 +175,7 @@ public: if (a.is_int(x) && bounds.has_lower(x, lo, s1) && !s1 && zero <= lo && bounds.has_upper(x, hi, s2) && !s2 && hi <= m_max_hi && lo <= hi) { - add_variable(b2i, sub, x, lo.get_unsigned(), hi.get_unsigned(), axioms); + add_variable(b2i.get(), sub, x, lo.get_unsigned(), hi.get_unsigned(), axioms); } else if (a.is_int(x)) { TRACE("pb", tout << "Not adding variable " << mk_pp(x, m) << " has lower: " @@ -204,9 +201,9 @@ public: } g->update(i, new_curr, new_pr, g->dep(i)); } - for (unsigned i = 0; i < axioms.size(); ++i) { - g->assert_expr(axioms[i].get()); - } + for (expr* a : axioms) + g->assert_expr(a); + g->add(b2i.get()); g->inc_depth(); result.push_back(g.get()); TRACE("pb", g->display(tout);); diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 819b8cb94..74bc9a5ef 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -152,10 +152,9 @@ public: virtual void operator()( goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; m_trail.reset(); m_fd.reset(); m_max.reset(); @@ -211,7 +210,7 @@ public: } } g->inc_depth(); - mc = mc1.get(); + g->add(mc1.get()); result.push_back(g.get()); TRACE("pb", g->display(tout);); SASSERT(g->is_well_sorted()); diff --git a/src/tactic/arith/factor_tactic.cpp b/src/tactic/arith/factor_tactic.cpp index e4ab1ca05..1233ddf9d 100644 --- a/src/tactic/arith/factor_tactic.cpp +++ b/src/tactic/arith/factor_tactic.cpp @@ -258,10 +258,9 @@ class factor_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("factor", *g); bool produce_proofs = g->proofs_enabled(); @@ -313,10 +312,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } catch (z3_error & ex) { throw ex; diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 68d31621f..16288f7ad 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -250,10 +250,9 @@ class fix_dl_var_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("fix-dl-var", *g); bool produce_proofs = g->proofs_enabled(); m_produce_models = g->models_enabled(); @@ -269,9 +268,9 @@ class fix_dl_var_tactic : public tactic { m_rw.set_substitution(&subst); if (m_produce_models) { - generic_model_converter * _mc = alloc(generic_model_converter, m); - _mc->add(var, zero); - mc = _mc; + generic_model_converter * mc = alloc(generic_model_converter, m); + mc->add(var, zero); + g->add(mc); } expr_ref new_curr(m); @@ -321,10 +320,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index c53ef7274..92e6ee530 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -180,7 +180,7 @@ class fm_tactic : public tactic { m_clauses.back().swap(c); } - virtual void operator()(model_ref & md, unsigned goal_idx) { + virtual void operator()(model_ref & md) { TRACE("fm_mc", model_v2_pp(tout, *md); display(tout);); model_evaluator ev(*(md.get())); ev.set_model_completion(true); @@ -1551,10 +1551,9 @@ class fm_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("fm", *g); fail_if_proof_generation("fm", g); m_produce_models = g->models_enabled(); @@ -1602,7 +1601,7 @@ class fm_tactic : public tactic { report_tactic_progress(":fm-cost", m_counter); if (!m_inconsistent) { copy_remaining(); - mc = m_mc.get(); + m_new_goal->add(concat(g->mc(), m_mc.get())); } } reset_constraints(); @@ -1675,9 +1674,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } }; diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index dfe7037f4..dfff44526 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -160,10 +160,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; m_01s->reset(); tactic_report report("cardinality-intro", *g); @@ -172,9 +171,7 @@ public: bounds(*g); - bound_manager::iterator bit = bounds.begin(), bend = bounds.end(); - for (; bit != bend; ++bit) { - expr* x = *bit; + for (expr* x : bounds) { bool s1 = false, s2 = false; rational lo, hi; if (a.is_int(x) && @@ -196,9 +193,7 @@ public: g->update(i, new_curr, new_pr, g->dep(i)); mark_rec(subfmls, new_curr); } - expr_set::iterator it = m_01s->begin(), end = m_01s->end(); - for (; it != end; ++it) { - expr* v = *it; + for (expr* v : *m_01s) { if (subfmls.is_marked(v)) { g->assert_expr(a.mk_le(v, a.mk_numeral(rational(1), true))); g->assert_expr(a.mk_le(a.mk_numeral(rational(0), true), v)); diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index a1834a73a..cc339f74a 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -189,13 +189,12 @@ class lia2pb_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("lia2pb", g); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); tactic_report report("lia2pb", *g); m_bm.reset(); m_rw.reset(); m_new_deps.reset(); @@ -222,10 +221,9 @@ class lia2pb_tactic : public tactic { if (!check_num_bits()) throw tactic_exception("lia2pb failed, number of necessary bits exceeds specified threshold (use option :lia2pb-total-bits to increase threshold)"); - generic_model_converter * gmc = 0; + ref gmc; if (m_produce_models) { gmc = alloc(generic_model_converter, m); - mc = gmc; } expr_ref zero(m); @@ -295,6 +293,7 @@ class lia2pb_tactic : public tactic { g->update(idx, new_curr, new_pr, dep); } g->inc_depth(); + g->add(gmc.get()); result.push_back(g.get()); TRACE("lia2pb", g->display(tout);); SASSERT(g->is_well_sorted()); @@ -330,10 +329,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 65ed8ffbe..2b4783c6f 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -441,17 +441,17 @@ public: */ virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("nla2bv", g); fail_if_unsat_core_generation("nla2bv", g); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); imp proc(g->m(), m_params); scoped_set_imp setter(*this, proc); + model_converter_ref mc; proc(*(g.get()), mc); - + g->add(mc.get()); result.push_back(g.get()); SASSERT(g->is_well_sorted()); } diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index afc165866..955e92f1a 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -81,9 +81,8 @@ class normalize_bounds_tactic : public tactic { void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; bool produce_models = in->models_enabled(); bool produce_proofs = in->proofs_enabled(); tactic_report report("normalize-bounds", *in); @@ -99,16 +98,13 @@ class normalize_bounds_tactic : public tactic { generic_model_converter * gmc = 0; if (produce_models) { gmc = alloc(generic_model_converter, m); - mc = gmc; + in->add(gmc); } unsigned num_norm_bounds = 0; expr_substitution subst(m); rational val; - bound_manager::iterator it = m_bm.begin(); - bound_manager::iterator end = m_bm.end(); - for (; it != end; ++it) { - expr * x = *it; + for (expr * x : m_bm) { if (is_target(x, val)) { num_norm_bounds++; sort * s = m.get_sort(x); @@ -171,10 +167,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/pb2bv_model_converter.cpp b/src/tactic/arith/pb2bv_model_converter.cpp index df5bd5745..16deb7cd7 100644 --- a/src/tactic/arith/pb2bv_model_converter.cpp +++ b/src/tactic/arith/pb2bv_model_converter.cpp @@ -27,17 +27,12 @@ pb2bv_model_converter::pb2bv_model_converter(ast_manager & _m) : m(_m) { pb2bv_model_converter::pb2bv_model_converter(ast_manager & _m, obj_map const & c2bit, bound_manager const & bm): m(_m) { - obj_map::iterator it = c2bit.begin(); - obj_map::iterator end = c2bit.end(); - for ( ; it != end; it++) { - m_c2bit.push_back(func_decl_pair(it->m_key, to_app(it->m_value)->get_decl())); - m.inc_ref(it->m_key); - m.inc_ref(to_app(it->m_value)->get_decl()); + for (auto const& kv : c2bit) { + m_c2bit.push_back(func_decl_pair(kv.m_key, to_app(kv.m_value)->get_decl())); + m.inc_ref(kv.m_key); + m.inc_ref(to_app(kv.m_value)->get_decl()); } - bound_manager::iterator it2 = bm.begin(); - bound_manager::iterator end2 = bm.end(); - for (; it2 != end2; ++it2) { - expr * c = *it2; + for (expr* c : bm) { SASSERT(is_uninterp_const(c)); func_decl * d = to_app(c)->get_decl(); if (!c2bit.contains(d)) { @@ -49,53 +44,43 @@ pb2bv_model_converter::pb2bv_model_converter(ast_manager & _m, obj_map::const_iterator it = m_c2bit.begin(); - svector::const_iterator end = m_c2bit.end(); - for (; it != end; ++it) { - m.dec_ref(it->first); - m.dec_ref(it->second); + for (auto const& kv : m_c2bit) { + m.dec_ref(kv.first); + m.dec_ref(kv.second); } } -void pb2bv_model_converter::operator()(model_ref & md) { - (*this)(md, 0); -} -void pb2bv_model_converter::operator()(model_ref & md, unsigned goal_idx) { - SASSERT(goal_idx == 0); +void pb2bv_model_converter::operator()(model_ref & md) { TRACE("pb2bv", tout << "converting model:\n"; model_v2_pp(tout, *md); display(tout);); arith_util a_util(m); - svector::const_iterator it = m_c2bit.begin(); - svector::const_iterator end = m_c2bit.end(); - for (; it != end; ++it) { - if (it->second) { - expr * val = md->get_const_interp(it->second); + for (auto const& kv : m_c2bit) { + if (kv.second) { + expr * val = md->get_const_interp(kv.second); if (val == 0 || m.is_false(val)) { /* false's and don't cares get the integer 0 solution*/ - md->register_decl(it->first, a_util.mk_numeral(rational(0), true)); + md->register_decl(kv.first, a_util.mk_numeral(rational(0), true)); } else { - md->register_decl(it->first, a_util.mk_numeral(rational(1), true)); + md->register_decl(kv.first, a_util.mk_numeral(rational(1), true)); } } else { - // it->first is a don't care. - md->register_decl(it->first, a_util.mk_numeral(rational(0), true)); + // kv.first is a don't care. + md->register_decl(kv.first, a_util.mk_numeral(rational(0), true)); } } } void pb2bv_model_converter::display(std::ostream & out) { out << "(pb2bv-model-converter"; - svector::const_iterator it = m_c2bit.begin(); - svector::const_iterator end = m_c2bit.end(); - for (; it != end; ++it) { - out << "\n (" << it->first->get_name() << " "; - if (it->second == 0) + for (auto const& kv : m_c2bit) { + out << "\n (" << kv.first->get_name() << " "; + if (kv.second == 0) out << "0"; else - out << it->second->get_name(); + out << kv.second->get_name(); out << ")"; } out << ")\n"; @@ -104,11 +89,9 @@ void pb2bv_model_converter::display(std::ostream & out) { model_converter * pb2bv_model_converter::translate(ast_translation & translator) { ast_manager & to = translator.to(); pb2bv_model_converter * res = alloc(pb2bv_model_converter, to); - svector::iterator it = m_c2bit.begin(); - svector::iterator end = m_c2bit.end(); - for (; it != end; it++) { - func_decl * f1 = translator(it->first); - func_decl * f2 = translator(it->second); + for (auto const& kv : m_c2bit) { + func_decl * f1 = translator(kv.first); + func_decl * f2 = translator(kv.second); res->m_c2bit.push_back(func_decl_pair(f1, f2)); to.inc_ref(f1); to.inc_ref(f2); diff --git a/src/tactic/arith/pb2bv_model_converter.h b/src/tactic/arith/pb2bv_model_converter.h index 0c2826573..59825b10f 100644 --- a/src/tactic/arith/pb2bv_model_converter.h +++ b/src/tactic/arith/pb2bv_model_converter.h @@ -31,10 +31,9 @@ public: pb2bv_model_converter(ast_manager & _m); pb2bv_model_converter(ast_manager & _m, obj_map const & c2bit, bound_manager const & bm); virtual ~pb2bv_model_converter(); - virtual void operator()(model_ref & md); - virtual void operator()(model_ref & md, unsigned goal_idx); - virtual void display(std::ostream & out); - virtual model_converter * translate(ast_translation & translator); + void operator()(model_ref & md) override; + void display(std::ostream & out) override; + model_converter * translate(ast_translation & translator) override; }; #endif diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 76f003737..e06c44110 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -887,14 +887,13 @@ private: void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { TRACE("pb2bv", g->display(tout);); SASSERT(g->is_well_sorted()); fail_if_proof_generation("pb2bv", g); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); tactic_report report("pb2bv", *g); m_bm.reset(); m_rw.reset(); m_new_deps.reset(); @@ -948,6 +947,7 @@ private: g->update(idx, new_exprs[idx].get(), 0, (m_produce_unsat_cores) ? new_deps[idx].get() : g->dep(idx)); if (m_produce_models) { + model_converter_ref mc; generic_model_converter * mc1 = alloc(generic_model_converter, m); for (auto const& kv : m_const2bit) mc1->hide(kv.m_value); @@ -956,7 +956,8 @@ private: for (unsigned i = 0; i < num_temps; i++) mc1->hide(m_temporary_ints.get(i)); pb2bv_model_converter * mc2 = alloc(pb2bv_model_converter, m, m_const2bit, m_bm); - mc = concat(mc1, mc2); + mc = concat(mc1, mc2); + g->add(mc.get()); } g->inc_depth(); @@ -999,9 +1000,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/arith/propagate_ineqs_tactic.cpp b/src/tactic/arith/propagate_ineqs_tactic.cpp index e52668f33..58fdf14ca 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.cpp +++ b/src/tactic/arith/propagate_ineqs_tactic.cpp @@ -52,7 +52,7 @@ public: virtual void updt_params(params_ref const & p); virtual void collect_param_descrs(param_descrs & r) {} - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); + virtual void operator()(goal_ref const & g, goal_ref_buffer & result, expr_dependency_ref & core); virtual void cleanup(); }; @@ -528,12 +528,11 @@ void propagate_ineqs_tactic::updt_params(params_ref const & p) { void propagate_ineqs_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("propagate-ineqs", g); fail_if_unsat_core_generation("propagate-ineqs", g); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); goal_ref r; (*m_imp)(g.get(), r); result.push_back(r.get()); diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 2affd8012..0caa0194d 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -822,11 +822,10 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("purify-arith", *g); TRACE("purify_arith", g->display(tout);); bool produce_proofs = g->proofs_enabled(); @@ -834,10 +833,10 @@ public: bool elim_root_objs = m_params.get_bool("elim_root_objects", true); bool elim_inverses = m_params.get_bool("elim_inverses", true); bool complete = m_params.get_bool("complete", true); - purify_arith_proc proc(*(g.get()), m_util, produce_proofs, elim_root_objs, elim_inverses, complete); - + purify_arith_proc proc(*(g.get()), m_util, produce_proofs, elim_root_objs, elim_inverses, complete); + model_converter_ref mc; proc(mc, produce_models); - + g->add(mc.get()); g->inc_depth(); result.push_back(g.get()); TRACE("purify_arith", g->display(tout);); diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index 11144c89b..2fde96caf 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -293,13 +293,12 @@ class recover_01_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("recover-01", g); fail_if_unsat_core_generation("recover-01", g); m_produce_models = g->models_enabled(); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); tactic_report report("recover-01", *g); bool saved = false; @@ -307,7 +306,9 @@ class recover_01_tactic : public tactic { SASSERT(new_goal->depth() == g->depth()); SASSERT(new_goal->prec() == g->prec()); new_goal->inc_depth(); - + new_goal->add(g->mc()); + new_goal->add(g->pc()); + unsigned sz = g->size(); for (unsigned i = 0; i < sz; i++) { expr * f = g->form(i); @@ -326,7 +327,7 @@ class recover_01_tactic : public tactic { if (m_produce_models) { gmc = alloc(generic_model_converter, m); - mc = gmc; + new_goal->add(gmc); } dec_ref_key_values(m, bool2int); @@ -335,25 +336,20 @@ class recover_01_tactic : public tactic { bool recovered = false; expr_substitution _subst(m); subst = &_subst; - var2clauses::iterator it = m_var2clauses.begin(); - var2clauses::iterator end = m_var2clauses.end(); - for (; it != end; ++it) { - if (process(it->m_key, it->m_value)) { + for (auto& kv : m_var2clauses) { + if (process(kv.m_key, kv.m_value)) { recovered = true; counter++; } else { - ptr_vector::iterator it2 = it->m_value.begin(); - ptr_vector::iterator end2 = it->m_value.end(); - for (; it2 != end2; ++it2) { - new_goal->assert_expr(*it2); + for (app* a : kv.m_value) { + new_goal->assert_expr(a); } } } if (!recovered) { result.push_back(g.get()); - mc = 0; return; } @@ -406,10 +402,9 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { - (*m_imp)(g, result, mc, core); + (*m_imp)(g, result, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index cdcc486a6..3ead0876a 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -172,8 +172,7 @@ struct bit_blaster_model_converter : public model_converter { return result; } - void operator()(model_ref & md, unsigned goal_idx) override { - SASSERT(goal_idx == 0); + void operator()(model_ref & md) override { model * new_model = alloc(model, m()); obj_hashtable bits; collect_bits(bits); @@ -182,10 +181,6 @@ struct bit_blaster_model_converter : public model_converter { md = new_model; } - void operator()(model_ref & md) override { - operator()(md, 0); - } - /** \brief simplisic expansion operator for formulas. It just adds back bit-vector definitions to the formula whether they are used or not. diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index d7df2e1c4..7928185b3 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -52,9 +52,8 @@ class bit_blaster_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; bool proofs_enabled = g->proofs_enabled(); if (proofs_enabled && m_blast_quant) @@ -87,12 +86,10 @@ class bit_blaster_tactic : public tactic { } if (change && g->models_enabled()) - mc = mk_bit_blaster_model_converter(m(), m_rewriter->const2bits()); - else - mc = 0; + g->add(mk_bit_blaster_model_converter(m(), m_rewriter->const2bits())); g->inc_depth(); result.push_back(g.get()); - TRACE("after_bit_blaster", g->display(tout); if (mc) mc->display(tout); tout << "\n";); + TRACE("after_bit_blaster", g->display(tout); if (g->mc()) g->mc()->display(tout); tout << "\n";); m_rewriter->cleanup(); } @@ -135,10 +132,9 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { - (*m_imp)(g, result, mc, core); + (*m_imp)(g, result, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index 9dc247455..9e31330fd 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -380,9 +380,8 @@ class bv1_blaster_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; if (!is_target(*g)) throw tactic_exception("bv1 blaster cannot be applied to goal"); @@ -408,7 +407,7 @@ class bv1_blaster_tactic : public tactic { } if (g->models_enabled()) - mc = mk_bv1_blaster_model_converter(m(), m_rw.cfg().m_const2bits); + g->add(mk_bv1_blaster_model_converter(m(), m_rw.cfg().m_const2bits)); g->inc_depth(); result.push_back(g.get()); m_rw.cfg().cleanup(); @@ -455,9 +454,8 @@ public: */ virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(g, result, mc, core); + (*m_imp)(g, result, core); } virtual void cleanup() { diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 487bbb762..151b00f50 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -138,7 +138,6 @@ public: virtual ~bv_bound_chk_tactic(); void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core); virtual tactic * translate(ast_manager & m); virtual void updt_params(params_ref const & p); @@ -198,13 +197,12 @@ bv_bound_chk_tactic::~bv_bound_chk_tactic() { void bv_bound_chk_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("bv-bound-chk", g); fail_if_unsat_core_generation("bv-bound-chk", g); TRACE("bv-bound-chk", g->display(tout << "before:"); tout << std::endl;); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); m_imp->operator()(g); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index e3a5edd84..e7cda8a2f 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -39,7 +39,7 @@ public: virtual ~bv_size_reduction_tactic(); - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); + virtual void operator()(goal_ref const & g, goal_ref_buffer & result, expr_dependency_ref & core); virtual void cleanup(); }; @@ -383,14 +383,15 @@ bv_size_reduction_tactic::~bv_size_reduction_tactic() { void bv_size_reduction_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("bv-size-reduction", g); fail_if_unsat_core_generation("bv-size-reduction", g); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); + model_converter_ref mc; m_imp->operator()(*(g.get()), mc); g->inc_depth(); + g->add(mc.get()); result.push_back(g.get()); SASSERT(g->is_well_sorted()); } diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index 3aba9a073..421b3e1e7 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -54,16 +54,16 @@ class bvarray2uf_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); tactic_report report("bvarray2uf", *g); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); fail_if_unsat_core_generation("bvarray2uf", g); TRACE("bvarray2uf", tout << "Before: " << std::endl; g->display(tout); ); m_produce_models = g->models_enabled(); + model_converter_ref mc; if (m_produce_models) { generic_model_converter * fmc = alloc(generic_model_converter, m_manager); @@ -92,6 +92,7 @@ class bvarray2uf_tactic : public tactic { g->assert_expr(m_rw.m_cfg.extra_assertions[i].get()); g->inc_depth(); + g->add(mc.get()); result.push_back(g.get()); TRACE("bvarray2uf", tout << "After: " << std::endl; g->display(tout);); SASSERT(g->is_well_sorted()); @@ -129,9 +130,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 722d2d359..a50658b5a 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -118,9 +118,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; bool produce_proofs = g->proofs_enabled(); tactic_report report("dt2bv", *g); unsigned size = g->size(); @@ -154,7 +153,7 @@ public: for (auto const& kv : rw.enum2def()) filter->add(kv.m_key, kv.m_value); - mc = filter.get(); + g->add(filter.get()); report_tactic_progress(":fd-num-translated", rw.num_translated()); } g->inc_depth(); diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index a86b41dcc..2d8224f42 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -226,10 +226,9 @@ class elim_small_bv_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("elim-small-bv", *g); bool produce_proofs = g->proofs_enabled(); fail_if_proof_generation("elim-small-bv", g); @@ -249,7 +248,7 @@ class elim_small_bv_tactic : public tactic { } g->update(idx, new_curr, new_pr, g->dep(idx)); } - mc = m_rw.m_cfg.m_mc.get(); + g->add(m_rw.m_cfg.m_mc.get()); report_tactic_progress(":elim-small-bv-num-eliminated", m_rw.m_cfg.m_num_eliminated); g->inc_depth(); @@ -288,9 +287,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index 8a6090ca3..e9452dbbc 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -238,10 +238,9 @@ class max_bv_sharing_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("max-bv-sharing", *g); bool produce_proofs = g->proofs_enabled(); @@ -299,9 +298,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index 7a6643568..e24ae0eb2 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -115,10 +115,9 @@ class blast_term_ite_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("blast-term-ite", *g); bool produce_proofs = g->proofs_enabled(); @@ -172,9 +171,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index d139d60e9..e43d0c1ef 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -56,13 +56,12 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("cofactor-term-ite", g); fail_if_unsat_core_generation("cofactor-term-ite", g); tactic_report report("cofactor-term-ite", *g); - mc = 0; core = 0; + core = 0; process(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index b71c566d6..faba93dc5 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -64,9 +64,7 @@ public: virtual void collect_param_descrs(param_descrs & r) {} virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; tactic_report report("collect-statistics", *g); collect_proc cp(m, m_stats); @@ -76,10 +74,8 @@ public: for_each_expr(cp, visited, g->form(i)); std::cout << "(" << std::endl; - stats_type::iterator it = m_stats.begin(); - stats_type::iterator end = m_stats.end(); - for (; it != end; it++) - std::cout << " :" << it->first << " " << it->second << std::endl; + for (auto const& kv : m_stats) + std::cout << " :" << kv.first << " " << kv.second << std::endl; std::cout << ")" << std::endl; g->inc_depth(); diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 43371235c..1216a7556 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -622,9 +622,8 @@ void ctx_simplify_tactic::get_param_descrs(param_descrs & r) { void ctx_simplify_tactic::operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index 2ad6e9243..21468d6da 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -56,7 +56,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core); virtual void cleanup(); diff --git a/src/tactic/core/der_tactic.cpp b/src/tactic/core/der_tactic.cpp index 1151d6770..1b51c92e6 100644 --- a/src/tactic/core/der_tactic.cpp +++ b/src/tactic/core/der_tactic.cpp @@ -75,9 +75,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp index 16e2c5f78..dd887a0e1 100644 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ b/src/tactic/core/distribute_forall_tactic.cpp @@ -101,14 +101,13 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); ast_manager & m = g->m(); bool produce_proofs = g->proofs_enabled(); rw r(m, produce_proofs); m_rw = &r; - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); tactic_report report("distribute-forall", *g); expr_ref new_curr(m); diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index d175ba0c4..c18f6cd29 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -186,9 +186,8 @@ tactic * dom_simplify_tactic::translate(ast_manager & m) { void dom_simplify_tactic::operator()( goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; tactic_report report("dom-simplify", *in.get()); simplify_goal(*(in.get())); diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index fd4e9e49b..10a56a979 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -139,7 +139,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core); virtual void cleanup(); diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 3f65f4b9d..3035a8582 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -101,10 +101,9 @@ class elim_term_ite_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("elim-term-ite", *g); bool produce_proofs = g->proofs_enabled(); m_rw.cfg().m_produce_models = g->models_enabled(); @@ -123,7 +122,7 @@ class elim_term_ite_tactic : public tactic { } g->update(idx, new_curr, new_pr, g->dep(idx)); } - mc = m_rw.m_cfg.m_mc.get(); + g->add(m_rw.m_cfg.m_mc.get()); report_tactic_progress(":elim-term-ite-consts", m_rw.m_cfg.m_num_fresh); g->inc_depth(); result.push_back(g.get()); @@ -162,9 +161,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 3660fdccb..a3bb482f1 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -816,10 +816,9 @@ class elim_uncnstr_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - expr_dependency_ref & core) { - mc = 0; core = 0; + goal_ref_buffer & result, + expr_dependency_ref & core) { + core = 0; bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); @@ -864,8 +863,7 @@ class elim_uncnstr_tactic : public tactic { g->update(idx, new_f, new_pr, g->dep(idx)); } if (!modified) { - if (round == 0) { - mc = 0; + if (round == 0) { } else { app_ref_vector & fresh_vars = m_rw->cfg().m_fresh_vars; @@ -874,15 +872,14 @@ class elim_uncnstr_tactic : public tactic { generic_model_converter * fmc = alloc(generic_model_converter, m()); for (app * f : fresh_vars) fmc->hide(f); - mc = concat(fmc, m_mc.get()); + g->add(concat(fmc, m_mc.get())); } else { - mc = 0; + g->set((model_converter*)nullptr); } } m_mc = 0; m_rw = 0; - TRACE("elim_uncnstr", if (mc) mc->display(tout);); result.push_back(g.get()); g->inc_depth(); return; @@ -933,9 +930,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(g, result, mc, core); + (*m_imp)(g, result, core); report_tactic_progress(":num-elim-apps", get_num_elim_apps()); } diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp index 4c03254c4..9c233ac1c 100644 --- a/src/tactic/core/injectivity_tactic.cpp +++ b/src/tactic/core/injectivity_tactic.cpp @@ -145,10 +145,9 @@ class injectivity_tactic : public tactic { void operator()(goal_ref const & goal, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(goal->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("injectivity", *goal); fail_if_unsat_core_generation("injectivity", goal); // TODO: Support UNSAT cores fail_if_proof_generation("injectivity", goal); @@ -271,9 +270,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_finder)(g, result, mc, core); + (*m_finder)(g, result, core); for (unsigned i = 0; i < g->size(); ++i) { expr* curr = g->form(i); diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index 080fc0bec..37251b8e9 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -55,11 +55,10 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { TRACE("nnf", tout << "params: " << m_params << "\n"; g->display(tout);); SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("nnf", *g); bool produce_proofs = g->proofs_enabled(); @@ -97,7 +96,7 @@ public: unsigned num_extra_names = dnames.get_num_names(); if (num_extra_names > 0) { generic_model_converter * fmc = alloc(generic_model_converter, m); - mc = fmc; + g->add(fmc); for (unsigned i = 0; i < num_extra_names; i++) fmc->hide(dnames.get_name_decl(i)); } diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index 8ce514401..a1cf0931a 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -129,10 +129,9 @@ class occf_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; fail_if_proof_generation("occf", g); @@ -157,7 +156,7 @@ class occf_tactic : public tactic { continue; if (produce_models && !m_mc) { m_mc = alloc(generic_model_converter, m); - mc = m_mc; + g->add(m_mc); } expr * keep = 0; new_lits.reset(); @@ -211,9 +210,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 897d560cf..e622eb9a3 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -48,8 +48,7 @@ class pb_preproc_model_converter : public model_converter { public: pb_preproc_model_converter(ast_manager& m):m(m), pb(m), m_refs(m) {} - virtual void operator()(model_ref & mdl, unsigned goal_idx) { - SASSERT(goal_idx == 0); + virtual void operator()(model_ref & mdl) { for (auto const& kv : m_const) { mdl->register_decl(kv.first->get_decl(), kv.second); } @@ -151,7 +150,6 @@ public: virtual void operator()( goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); core = 0; @@ -161,7 +159,7 @@ public: } pb_preproc_model_converter* pp = alloc(pb_preproc_model_converter, m); - mc = pp; + g->add(pp); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 61804d336..12a14f5a6 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -137,10 +137,9 @@ class propagate_values_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("propagate-values", *g); m_goal = g.get(); @@ -241,10 +240,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index aa53cd9cc..25f0a8f36 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -73,7 +73,7 @@ public: virtual ~reduce_args_tactic(); - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); + virtual void operator()(goal_ref const & g, goal_ref_buffer & result, expr_dependency_ref & core); virtual void cleanup(); }; @@ -439,7 +439,7 @@ struct reduce_args_tactic::imp { return f_mc; } - void operator()(goal & g, model_converter_ref & mc) { + void operator()(goal & g) { if (g.inconsistent()) return; TRACE("reduce_args", g.display(tout);); @@ -468,9 +468,9 @@ struct reduce_args_tactic::imp { report_tactic_progress(":reduced-funcs", decl2args.size()); if (g.models_enabled()) - mc = mk_mc(decl2args, ctx.m_decl2arg2funcs); + g.add(mk_mc(decl2args, ctx.m_decl2arg2funcs)); - TRACE("reduce_args", g.display(tout); if (mc) mc->display(tout);); + TRACE("reduce_args", g.display(tout); if (g.mc()) g.mc()->display(tout);); } }; @@ -484,13 +484,12 @@ reduce_args_tactic::~reduce_args_tactic() { void reduce_args_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("reduce-args", g); fail_if_unsat_core_generation("reduce-args", g); - mc = 0; core = 0; result.reset(); - m_imp->operator()(*(g.get()), mc); + core = 0; result.reset(); + m_imp->operator()(*(g.get())); g->inc_depth(); result.push_back(g.get()); SASSERT(g->is_well_sorted()); diff --git a/src/tactic/core/simplify_tactic.cpp b/src/tactic/core/simplify_tactic.cpp index 84ade7ba3..a8278c383 100644 --- a/src/tactic/core/simplify_tactic.cpp +++ b/src/tactic/core/simplify_tactic.cpp @@ -94,13 +94,12 @@ void simplify_tactic::get_param_descrs(param_descrs & r) { void simplify_tactic::operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); - mc = 0; core = 0; + core = 0; } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/core/simplify_tactic.h b/src/tactic/core/simplify_tactic.h index f14f219d4..282feda0f 100644 --- a/src/tactic/core/simplify_tactic.h +++ b/src/tactic/core/simplify_tactic.h @@ -36,7 +36,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core); virtual void cleanup(); diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 6fbefcba3..fec0edd81 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -668,10 +668,10 @@ class solve_eqs_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; + model_converter_ref mc; tactic_report report("solve_eqs", *g); m_produce_models = g->models_enabled(); m_produce_proofs = g->proofs_enabled(); @@ -691,7 +691,6 @@ class solve_eqs_tactic : public tactic { normalize(); substitute(*(g.get())); if (g->inconsistent()) { - mc = 0; break; } save_elim_vars(mc); @@ -699,6 +698,7 @@ class solve_eqs_tactic : public tactic { } } g->inc_depth(); + g->add(mc.get()); result.push_back(g.get()); TRACE("solve_eqs", g->display(tout);); SASSERT(g->is_well_sorted()); @@ -734,9 +734,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); report_tactic_progress(":num-elim-vars", m_imp->get_num_eliminated_vars()); } diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index f383036f7..60dbdd568 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -46,21 +46,16 @@ class split_clause_tactic : public tactic { } class split_pc : public proof_converter { - ast_manager & m_manager; - app * m_clause; - proof * m_clause_pr; + ast_manager & m; + app_ref m_clause; + proof_ref m_clause_pr; public: - split_pc(ast_manager & m, app * cls, proof * pr):m_manager(m), m_clause(cls), m_clause_pr(pr) { - m.inc_ref(cls); - m.inc_ref(pr); + split_pc(ast_manager & m, app * cls, proof * pr):m(m), m_clause(cls, m), m_clause_pr(pr, m) { } - ~split_pc() { - m_manager.dec_ref(m_clause); - m_manager.dec_ref(m_clause_pr); - } + virtual ~split_pc() { } - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { // Let m_clause be of the form (l_0 or ... or l_{num_source - 1}) // Each source[i] proof is a proof for "false" using l_i as a hypothesis // So, I use lemma for producing a proof for (not l_i) that does not contain the hypothesis, @@ -73,14 +68,14 @@ class split_clause_tactic : public tactic { expr * not_li = m.mk_not(m_clause->get_arg(i)); prs.push_back(m.mk_lemma(pr_i, not_li)); } - result = m.mk_unit_resolution(prs.size(), prs.c_ptr()); + return proof_ref(m.mk_unit_resolution(prs.size(), prs.c_ptr()), m); } - virtual proof_converter * translate(ast_translation & translator) { - return alloc(split_pc, translator.to(), translator(m_clause), translator(m_clause_pr)); + proof_converter * translate(ast_translation & translator) override { + return alloc(split_pc, translator.to(), translator(m_clause.get()), translator(m_clause_pr.get())); } - virtual void display(std::ostream & out) { out << "(split-clause-pc)\n"; } + void display(std::ostream & out) override { out << "(split-clause-pc)\n"; } }; public: @@ -97,22 +92,21 @@ public: virtual ~split_clause_tactic() { } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_largest_clause = p.get_bool("split_largest_clause", false); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("split_largest_clause", CPK_BOOL, "(default: false) split the largest clause in the goal."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + expr_dependency_ref & core) override { SASSERT(in->is_well_sorted()); tactic_report report("split-clause", *in); TRACE("before_split_clause", in->display(tout);); - mc = 0; core = 0; + core = 0; ast_manager & m = in->m(); unsigned cls_pos = select_clause(m, in); if (cls_pos == UINT_MAX) { @@ -123,15 +117,10 @@ public: expr_dependency * cls_dep = in->dep(cls_pos); if (produce_proofs) in->set(alloc(split_pc, m, cls, in->pr(cls_pos))); - unsigned cls_sz = cls->get_num_args(); - report_tactic_progress(":num-new-branches", cls_sz); - for (unsigned i = 0; i < cls_sz; i++) { - goal * subgoal_i; - if (i == cls_sz - 1) - subgoal_i = in.get(); - else - subgoal_i = alloc(goal, *in); - expr * lit_i = cls->get_arg(i); + report_tactic_progress(":num-new-branches", cls->get_num_args()); + for (expr* lit_i : *cls) { + goal * subgoal_i = alloc(goal, *in); + subgoal_i->set(in->mc()); proof * pr_i = 0; if (produce_proofs) pr_i = m.mk_hypothesis(lit_i); @@ -139,6 +128,7 @@ public: subgoal_i->inc_depth(); result.push_back(subgoal_i); } + in->set(concat(in->pc(), result.size(), result.c_ptr())); } virtual void cleanup() { diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index 89013a6da..920521e0c 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -40,7 +40,6 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core); virtual void cleanup(); }; @@ -635,11 +634,10 @@ symmetry_reduce_tactic::~symmetry_reduce_tactic() { void symmetry_reduce_tactic::operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { fail_if_proof_generation("symmetry_reduce", g); fail_if_unsat_core_generation("symmetry_reduce", g); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); (*m_imp)(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index 22a2dc500..11b7ceb8c 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -800,10 +800,9 @@ class tseitin_cnf_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("tseitin-cnf", *g); fail_if_proof_generation("tseitin-cnf", g); m_produce_models = g->models_enabled(); @@ -842,9 +841,7 @@ class tseitin_cnf_tactic : public tactic { g->assert_expr(cls); } if (m_produce_models && !m_fresh_vars.empty()) - mc = m_mc.get(); - else - mc = 0; + g->add(m_mc.get()); g->inc_depth(); result.push_back(g.get()); TRACE("tseitin_cnf", g->display(tout);); @@ -884,9 +881,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); report_tactic_progress(":cnf-aux-vars", m_imp->m_num_aux_vars); } diff --git a/src/tactic/equiv_proof_converter.h b/src/tactic/equiv_proof_converter.h index 0ee44aec2..1afd6e610 100644 --- a/src/tactic/equiv_proof_converter.h +++ b/src/tactic/equiv_proof_converter.h @@ -35,11 +35,11 @@ public: virtual ~equiv_proof_converter() {} - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { - m_replace(m, num_source, source, result); + proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { + return m_replace(m, num_source, source); } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return m_replace.translate(translator); } @@ -47,7 +47,7 @@ public: ast_manager& get_manager() { return m; } - virtual void display(std::ostream & out) {} + void display(std::ostream & out) override {} }; #endif diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 989caaa58..462bf28bd 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -37,20 +37,16 @@ public: dealloc(m_bv2fp); } - virtual void operator()(model_ref & md, unsigned goal_idx) { - SASSERT(goal_idx == 0); + void operator()(model_ref & md) override { model * new_model = alloc(model, m); convert(md.get(), new_model); md = new_model; } - virtual void operator()(model_ref & md) { - operator()(md, 0); - } - void display(std::ostream & out); + void display(std::ostream & out) override; - virtual model_converter * translate(ast_translation & translator); + model_converter * translate(ast_translation & translator) override; protected: fpa2bv_model_converter(ast_manager & m) : diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 99b50429c..3ed9f9cb0 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -48,14 +48,13 @@ class fpa2bv_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); m_proofs_enabled = g->proofs_enabled(); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); tactic_report report("fpa2bv", *g); m_rw.reset(); @@ -99,7 +98,7 @@ class fpa2bv_tactic : public tactic { } if (g->models_enabled()) - mc = mk_fpa2bv_model_converter(m, m_conv); + g->add(mk_fpa2bv_model_converter(m, m_conv)); g->inc_depth(); result.push_back(g.get()); @@ -109,7 +108,7 @@ class fpa2bv_tactic : public tactic { SASSERT(g->is_well_sorted()); TRACE("fpa2bv", tout << "AFTER: " << std::endl; g->display(tout); - if (mc) mc->display(tout); tout << std::endl; ); + if (g->mc()) g->mc()->display(tout); tout << std::endl; ); } }; @@ -140,10 +139,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { try { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 03361cac1..3993f20c9 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -23,8 +23,7 @@ Notes: #include "model/model_evaluator.h" -void generic_model_converter::operator()(model_ref & md, unsigned goal_idx) { - std::cout << "model converter\n"; +void generic_model_converter::operator()(model_ref & md) { TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout);); model_evaluator ev(*(md.get())); ev.set_model_completion(true); @@ -35,12 +34,10 @@ void generic_model_converter::operator()(model_ref & md, unsigned goal_idx) { entry const& e = m_entries[i]; switch (e.m_instruction) { case HIDE: - std::cout << "hide " << e.m_f << "\n"; md->unregister_decl(e.m_f); break; case ADD: ev(e.m_def, val); - std::cout << e.m_f << " " << e.m_def << " " << val << "\n"; TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";); arity = e.m_f->get_arity(); if (arity == 0) { diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index 014725bb0..affafb0c1 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -46,19 +46,17 @@ public: void add(expr * d, expr* e) { SASSERT(is_app(d) && to_app(d)->get_num_args() == 0); m_entries.push_back(entry(to_app(d)->get_decl(), e, m, ADD)); } - virtual void operator()(model_ref & md, unsigned goal_idx); - - virtual void operator()(svector & labels, unsigned goal_idx) {} + void operator()(labels_vec & labels) override {} - virtual void operator()(model_ref & md) { operator()(md, 0); } + void operator()(model_ref & md) override; - virtual void cancel() {} + void cancel() override {} - virtual void display(std::ostream & out); + void display(std::ostream & out) override; - virtual model_converter * translate(ast_translation & translator); + model_converter * translate(ast_translation & translator) override; - virtual void collect(ast_pp_util& visitor); + void collect(ast_pp_util& visitor) override; void operator()(expr_ref& fml) override; }; diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index ab1e2a9bc..da6a0dcf8 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -68,14 +68,9 @@ public: this->m_c2->operator()(fml); } - void operator()(model_ref & m, unsigned goal_idx) override { - this->m_c2->operator()(m, goal_idx); - this->m_c1->operator()(m, 0); - } - - void operator()(labels_vec & r, unsigned goal_idx) override { - this->m_c2->operator()(r, goal_idx); - this->m_c1->operator()(r, 0); + void operator()(labels_vec & r) override { + this->m_c2->operator()(r); + this->m_c1->operator()(r); } char const * get_name() const override { return "concat-model-converter"; } @@ -98,75 +93,6 @@ model_converter * concat(model_converter * mc1, model_converter * mc2) { return alloc(concat_model_converter, mc1, mc2); } -class concat_star_model_converter : public concat_star_converter { -public: - concat_star_model_converter(model_converter * mc1, unsigned num, model_converter * const * mc2s, unsigned * szs): - concat_star_converter(mc1, num, mc2s, szs) { - } - - void operator()(model_ref & m) override { - // TODO: delete method after conversion is complete - UNREACHABLE(); - } - - void operator()(model_ref & m, unsigned goal_idx) override { - unsigned num = this->m_c2s.size(); - for (unsigned i = 0; i < num; i++) { - if (goal_idx < this->m_szs[i]) { - // found the model converter that should be used - model_converter * c2 = this->m_c2s[i]; - if (c2) - c2->operator()(m, goal_idx); - if (m_c1) - this->m_c1->operator()(m, i); - return; - } - // invalid goal - goal_idx -= this->m_szs[i]; - } - UNREACHABLE(); - } - - void operator()(labels_vec & r, unsigned goal_idx) override { - unsigned num = this->m_c2s.size(); - for (unsigned i = 0; i < num; i++) { - if (goal_idx < this->m_szs[i]) { - // found the model converter that should be used - model_converter * c2 = this->m_c2s[i]; - if (c2) - c2->operator()(r, goal_idx); - if (m_c1) - this->m_c1->operator()(r, i); - return; - } - // invalid goal - goal_idx -= this->m_szs[i]; - } - UNREACHABLE(); - } - - char const * get_name() const override { return "concat-star-model-converter"; } - - model_converter * translate(ast_translation & translator) override { - return this->translate_core(translator); - } -}; - -model_converter * concat(model_converter * mc1, unsigned num, model_converter * const * mc2s, unsigned * szs) { - SASSERT(num > 0); - if (num == 1) - return concat(mc1, mc2s[0]); - unsigned i; - for (i = 0; i < num; i++) { - if (mc2s[i] != 0) - break; - } - if (i == num) { - // all mc2s are 0 - return mc1; - } - return alloc(concat_star_model_converter, mc1, num, mc2s, szs); -} class model2mc : public model_converter { model_ref m_model; @@ -182,11 +108,7 @@ public: m = m_model; } - void operator()(model_ref & m, unsigned goal_idx) override { - m = m_model; - } - - void operator()(labels_vec & r, unsigned goal_idx) { + void operator()(labels_vec & r) { r.append(m_labels.size(), m_labels.c_ptr()); } @@ -227,13 +149,13 @@ model_converter * model_and_labels2model_converter(model * m, buffer & r void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m) { if (mc) { m = alloc(model, mng); - (*mc)(m, 0); + (*mc)(m); } } -void apply(model_converter_ref & mc, model_ref & m, unsigned gidx) { +void apply(model_converter_ref & mc, model_ref & m) { if (mc) { - (*mc)(m, gidx); + (*mc)(m); } } diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 720ae1916..7069e868e 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -19,10 +19,10 @@ Notes: #ifndef MODEL_CONVERTER_H_ #define MODEL_CONVERTER_H_ +#include "util/ref.h" #include "ast/ast_pp_util.h" #include "model/model.h" #include "tactic/converter.h" -#include "util/ref.h" class labels_vec : public svector {}; class smt2_pp_environment; @@ -36,17 +36,11 @@ protected: public: - model_converter(): m_env(0) {} + model_converter(): m_env(nullptr) {} - virtual void operator()(model_ref & m) {} // TODO: delete + virtual void operator()(model_ref & m) = 0; - virtual void operator()(model_ref & m, unsigned goal_idx) { - // TODO: make it virtual after the transition to goal/tactic/tactical is complete - SASSERT(goal_idx == 0); - operator()(m); - } - - virtual void operator()(labels_vec & r, unsigned goal_idx) {} + virtual void operator()(labels_vec & r) {} virtual model_converter * translate(ast_translation & translator) = 0; @@ -61,25 +55,18 @@ public: }; typedef ref model_converter_ref; +typedef sref_vector model_converter_ref_vector; +typedef sref_buffer model_converter_ref_buffer; model_converter * concat(model_converter * mc1, model_converter * mc2); -/** - \brief \c mc1 is the model converter for a sequence of subgoals of size \c num. - Given an i in [0, num), mc2s[i] is the model converter for subgoal i, - and num_subgoals[i] is the number of subgoals of subgoals[i]. -*/ -model_converter * concat(model_converter * mc1, unsigned num, model_converter * const * mc2s, unsigned * num_subgoals); - model_converter * model2model_converter(model * m); model_converter * model_and_labels2model_converter(model * m, buffer &r); void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m); -void apply(model_converter_ref & mc, model_ref & m, unsigned gidx); +void apply(model_converter_ref & mc, model_ref & m); -typedef sref_vector model_converter_ref_vector; -typedef sref_buffer model_converter_ref_buffer; #endif diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index bc7c5d49c..7a8a0930c 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -210,7 +210,7 @@ private: } generic_model_converter filter(m); for (func_decl* f : m_bv_fns) filter.hide(f); - filter(mdl, 0); + filter(mdl); } void extend_model(model_ref& mdl) { @@ -225,7 +225,7 @@ private: TRACE("int2bv", tout << mk_pp(kv.m_key, m) << " " << value << "\n";); ext.add(kv.m_key, value); } - ext(mdl, 0); + ext(mdl); } void accumulate_sub(expr_safe_replace& sub) const { diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 50fb7d925..4feaa622b 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -167,14 +167,14 @@ public: for (auto const& kv : m_rewriter.enum2bv()) { filter.hide(kv.m_value); } - filter(mdl, 0); + filter(mdl); } void extend_model(model_ref& mdl) { generic_model_converter ext(m); for (auto const& kv : m_rewriter.enum2def()) ext.add(kv.m_key, kv.m_value); - ext(mdl, 0); + ext(mdl); } virtual unsigned get_num_assertions() const { diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 16eb2b4a7..abb8df188 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -541,7 +541,7 @@ public: init(); } - void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc, expr_dependency_ref & dep) { + void operator ()(const goal_ref & g,goal_ref_buffer & result, expr_dependency_ref & dep) { ast_manager& m = g->m(); solver* s = mk_fd_solver(m, m_params); solver_state* st = alloc(solver_state, 0, s, m_params, cube_task); @@ -560,8 +560,7 @@ public: switch (is_sat) { case l_true: if (g->models_enabled()) { - mc = model2model_converter(mdl.get()); - mc = concat(fmc.get(), mc.get()); + g->add(concat(fmc.get(), model2model_converter(mdl.get()))); } g->reset(); break; diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 334d14d86..9b8eed98d 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -118,7 +118,7 @@ public: for (func_decl* f : fns) { filter.hide(f); } - filter(mdl, 0); + filter(mdl); } virtual unsigned get_num_assertions() const { diff --git a/src/tactic/proof_converter.cpp b/src/tactic/proof_converter.cpp index 095488415..a8d3ff578 100644 --- a/src/tactic/proof_converter.cpp +++ b/src/tactic/proof_converter.cpp @@ -17,6 +17,7 @@ Notes: --*/ #include "tactic/proof_converter.h" +#include "tactic/goal.h" #include "ast/ast_smt2_pp.h" class concat_proof_converter : public concat_converter { @@ -25,14 +26,14 @@ public: virtual char const * get_name() const { return "concat-proof-converter"; } - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { proof_ref tmp(m); - this->m_c2->operator()(m, num_source, source, tmp); + tmp = this->m_c2->operator()(m, num_source, source); proof * new_source = tmp.get(); - this->m_c1->operator()(m, 1, &new_source, result); + return this->m_c1->operator()(m, 1, &new_source); } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return this->translate_core(translator); } }; @@ -45,66 +46,39 @@ proof_converter * concat(proof_converter * pc1, proof_converter * pc2) { return alloc(concat_proof_converter, pc1, pc2); } -class concat_star_proof_converter : public concat_star_converter { +class subgoal_proof_converter : public proof_converter { + proof_converter_ref m_pc; + goal_ref_buffer m_goals; public: - concat_star_proof_converter(proof_converter * pc1, unsigned num, proof_converter * const * pc2s, unsigned * szs): - concat_star_converter(pc1, num, pc2s, szs) { + subgoal_proof_converter(proof_converter* pc, unsigned n, goal * const* goals): + m_pc(pc) + { + for (unsigned i = 0; i < n; ++i) m_goals.push_back(goals[i]); } - virtual char const * get_name() const { return "concat-star-proof-converter"; } - - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { - unsigned num = this->m_szs.size(); -#ifdef Z3DEBUG - unsigned sum = 0; - for (unsigned i = 0; i < num; i++) { - sum += this->m_szs[i]; - } - SASSERT(sum == num_source); -#endif - proof_ref_buffer tmp_prs(m); - for (unsigned i = 0; i < num; i++) { - unsigned sz = m_szs[i]; - proof_converter * c2 = m_c2s[i]; - proof_ref pr(m); - if (c2) { - (*c2)(m, sz, source, pr); - } - else { - SASSERT(sz == 1); - pr = *source; - } - source += sz; - tmp_prs.push_back(pr.get()); - } - if (m_c1) { - (*m_c1)(m, tmp_prs.size(), tmp_prs.c_ptr(), result); - } - else { - SASSERT(tmp_prs.size() == 1); - result = tmp_prs[0]; + proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { + // ignore the proofs from the arguments, instead obtain the proofs fromt he subgoals. + SASSERT(num_source == 0); + proof_converter_ref_buffer pc_buffer; + for (goal_ref g : m_goals) { + pc_buffer.push_back(g->pc()); } + return apply(m, m_pc, pc_buffer); } - virtual proof_converter * translate(ast_translation & translator) { - return this->translate_core(translator); + proof_converter* translate(ast_translation& tr) override { + proof_converter_ref pc1 = m_pc->translate(tr); + goal_ref_buffer goals; + for (goal_ref g : m_goals) goals.push_back(g->translate(tr)); + return alloc(subgoal_proof_converter, pc1.get(), goals.size(), goals.c_ptr()); } + + void display(std::ostream& out) override {} + }; -proof_converter * concat(proof_converter * pc1, unsigned num, proof_converter * const * pc2s, unsigned * szs) { - SASSERT(num > 0); - if (num == 1) - return concat(pc1, pc2s[0]); - unsigned i; - for (i = 0; i < num; i++) { - if (pc2s[i] != 0) - break; - } - if (i == num) { - // all pc2s are 0 - return pc1; - } - return alloc(concat_star_proof_converter, pc1, num, pc2s, szs); +proof_converter * concat(proof_converter *pc, unsigned n, goal* const* goals) { + return alloc(subgoal_proof_converter, pc, n, goals); } class proof2pc : public proof_converter { @@ -113,16 +87,16 @@ public: proof2pc(ast_manager & m, proof * pr):m_pr(pr, m) {} virtual ~proof2pc() {} - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { SASSERT(num_source == 0); - result = m_pr; + return m_pr; } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return alloc(proof2pc, translator.to(), translator(m_pr.get())); } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(proof->proof-converter-wrapper\n" << mk_ismt2_pp(m_pr.get(), m_pr.get_manager()) << ")\n"; } }; @@ -136,7 +110,7 @@ proof_converter * proof2proof_converter(ast_manager & m, proof * pr) { void apply(ast_manager & m, proof_converter * pc, proof_ref & pr) { if (pc) { proof * _pr = pr.get(); - (*pc)(m, 1, &_pr, pr); + pr = (*pc)(m, 1, &_pr); } } @@ -148,15 +122,15 @@ void apply(ast_manager & m, proof_converter * pc, proof_ref & pr) { pc1 and pc2s must be different from 0. */ -void apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffer & pc2s, proof_ref & result) { +proof_ref apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffer & pc2s) { SASSERT(pc1); proof_ref_buffer prs(m); unsigned sz = pc2s.size(); for (unsigned i = 0; i < sz; i++) { proof_ref pr(m); SASSERT(pc2s[i]); // proof production is enabled - pc2s[i]->operator()(m, 0, 0, pr); + pr = pc2s[i]->operator()(m, 0, 0); prs.push_back(pr); } - (*pc1)(m, sz, prs.c_ptr(), result); + return (*pc1)(m, sz, prs.c_ptr()); } diff --git a/src/tactic/proof_converter.h b/src/tactic/proof_converter.h index e925436d2..162623da9 100644 --- a/src/tactic/proof_converter.h +++ b/src/tactic/proof_converter.h @@ -20,33 +20,34 @@ Notes: #define PROOF_CONVERTER_H_ #include "ast/ast.h" -#include "tactic/converter.h" #include "util/ref.h" +#include "tactic/converter.h" +class goal; class proof_converter : public converter { public: virtual ~proof_converter() { } - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) = 0; + virtual proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) = 0; virtual proof_converter * translate(ast_translation & translator) = 0; }; typedef ref proof_converter_ref; +typedef sref_vector proof_converter_ref_vector; +typedef sref_buffer proof_converter_ref_buffer; + proof_converter * concat(proof_converter * pc1, proof_converter * pc2); /** - \brief \c pc1 is the proof converter for a sequence of subgoals of size \c num. - Given an i in [0, num), pc2s[i] is the proof converter for subgoal i, - and num_subgoals[i] is the number of subgoals of subgoals[i]. -*/ -proof_converter * concat(proof_converter * pc1, unsigned num, proof_converter * const * pc2s, unsigned * num_subgoals); + \brief create a proof converter that takes a set of subgoals and converts their proofs to a proof of + the goal they were derived from. + */ +proof_converter * concat(proof_converter *pc1, unsigned n, goal* const* goals); proof_converter * proof2proof_converter(ast_manager & m, proof * pr); -typedef sref_vector proof_converter_ref_vector; -typedef sref_buffer proof_converter_ref_buffer; - -void apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffer & pc2s, proof_ref & result); void apply(ast_manager & m, proof_converter * pc, proof_ref & pr); +proof_ref apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffer & pc2s); + #endif diff --git a/src/tactic/replace_proof_converter.cpp b/src/tactic/replace_proof_converter.cpp index 98f28bb1b..9ef49dd5f 100644 --- a/src/tactic/replace_proof_converter.cpp +++ b/src/tactic/replace_proof_converter.cpp @@ -53,8 +53,7 @@ public: }; -void replace_proof_converter::operator()(ast_manager & m, unsigned num_source, - proof * const * source, proof_ref & result) { +proof_ref replace_proof_converter::operator()(ast_manager & m, unsigned num_source, proof * const * source) { SASSERT(num_source == 1); replace_map replace(m); proof_ref p(m); @@ -73,14 +72,12 @@ void replace_proof_converter::operator()(ast_manager & m, unsigned num_source, replace.apply(tmp); TRACE("proof_converter", tout << mk_pp(source[0], m) << "\n"; tout << mk_pp(tmp.get(), m) << "\n";); - result = to_app(tmp); + return proof_ref(to_app(tmp), m); } proof_converter * replace_proof_converter::translate(ast_translation & translator) { replace_proof_converter* rp = alloc(replace_proof_converter, m); - for (unsigned i = 0; i < m_proofs.size(); ++i) { - rp->insert(translator(m_proofs[i].get())); - } + for (proof* p : m_proofs) rp->insert(translator(p)); return rp; } diff --git a/src/tactic/replace_proof_converter.h b/src/tactic/replace_proof_converter.h index d5cf7dc31..91bbc4813 100644 --- a/src/tactic/replace_proof_converter.h +++ b/src/tactic/replace_proof_converter.h @@ -34,9 +34,9 @@ public: virtual ~replace_proof_converter() {} - virtual void operator()(ast_manager & _m, unsigned num_source, proof * const * source, proof_ref & result); + proof_ref operator()(ast_manager & _m, unsigned num_source, proof * const * source) override; - virtual proof_converter * translate(ast_translation & translator); + proof_converter * translate(ast_translation & translator) override; void insert(proof* p) { m_proofs.push_back(p); } @@ -45,7 +45,7 @@ public: // run the replacements the inverse direction. void invert() { m_proofs.reverse(); } - virtual void display(std::ostream & out) {} + void display(std::ostream & out) override {} }; diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 4e4efeb8f..532169d46 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -48,9 +48,8 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; + core = 0; TRACE("sine", g->display(tout);); TRACE("sine", tout << g->size();); @@ -66,8 +65,6 @@ public: result.push_back(g.get()); TRACE("sine", result[0]->display(tout);); SASSERT(g->is_well_sorted()); - generic_model_converter * fmc = alloc(generic_model_converter, m); - mc = fmc; } virtual void cleanup() { diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index a96cf117a..18328f0b8 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -61,16 +61,16 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; result.reset(); + core = 0; result.reset(); TRACE("sls", g->display(tout);); tactic_report report("sls", *g); + model_converter_ref mc; m_engine->operator()(g, mc); - + g->add(mc.get()); g->inc_depth(); result.push_back(g.get()); TRACE("sls", g->display(tout);); diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index a4995535e..84d445f45 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -55,9 +55,7 @@ public: virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; ast_manager& m(g->m()); tactic_report report("qfufbv_ackr", *g); fail_if_unsat_core_generation("qfufbv_ackr", g); @@ -79,7 +77,7 @@ public: // report model if (g->models_enabled() && (o == l_true)) { model_ref abstr_model = imp->get_model(); - mc = mk_qfufbv_ackr_model_converter(m, imp->get_info(), abstr_model); + g->add(mk_qfufbv_ackr_model_converter(m, imp->get_info(), abstr_model)); } } diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 3a8e128ec..ed78f229d 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -69,11 +69,9 @@ void report_tactic_progress(char const * id, unsigned val) { void skip_tactic::operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { result.reset(); result.push_back(in.get()); - mc = 0; core = 0; } @@ -85,14 +83,13 @@ class fail_tactic : public tactic { public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { throw tactic_exception("fail tactic"); } - virtual void cleanup() {} + void cleanup() override {} - virtual tactic * translate(ast_manager & m) { return this; } + tactic * translate(ast_manager & m) override { return this; } }; tactic * mk_fail_tactic() { @@ -105,12 +102,11 @@ class report_verbose_tactic : public skip_tactic { public: report_verbose_tactic(char const * msg, unsigned lvl) : m_msg(msg), m_lvl(lvl) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + expr_dependency_ref & core) override { IF_VERBOSE(m_lvl, verbose_stream() << m_msg << "\n";); - skip_tactic::operator()(in, result, mc, core); + skip_tactic::operator()(in, result, core); } }; @@ -123,13 +119,12 @@ class trace_tactic : public skip_tactic { public: trace_tactic(char const * tag): m_tag(tag) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + expr_dependency_ref & core) override { TRACE(m_tag, in->display(tout);); (void)m_tag; - skip_tactic::operator()(in, result, mc, core); + skip_tactic::operator()(in, result, core); } }; @@ -141,13 +136,12 @@ class fail_if_undecided_tactic : public skip_tactic { public: fail_if_undecided_tactic() {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + expr_dependency_ref & core) override { if (!in->is_decided()) throw tactic_exception("undecided"); - skip_tactic::operator()(in, result, mc, core); + skip_tactic::operator()(in, result, core); } }; @@ -155,10 +149,10 @@ tactic * mk_fail_if_undecided_tactic() { return alloc(fail_if_undecided_tactic); } -void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core) { +void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, expr_dependency_ref & core) { t.reset_statistics(); try { - t(in, result, mc, core); + t(in, result, core); t.cleanup(); } catch (tactic_exception & ex) { @@ -169,7 +163,7 @@ void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_conve } -lbool check_sat(tactic & t, goal_ref & g, model_ref & md, model_converter_ref& mc, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { +lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown) { bool models_enabled = g->models_enabled(); bool proofs_enabled = g->proofs_enabled(); bool cores_enabled = g->unsat_core_enabled(); @@ -179,21 +173,20 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, model_converter_ref& m ast_manager & m = g->m(); goal_ref_buffer r; try { - exec(t, g, r, mc, core); + exec(t, g, r, core); } catch (tactic_exception & ex) { reason_unknown = ex.msg(); return l_undef; } - TRACE("tactic_mc", mc->display(tout);); TRACE("tactic_check_sat", tout << "r.size(): " << r.size() << "\n"; for (unsigned i = 0; i < r.size(); i++) r[i]->display(tout);); if (is_decided_sat(r)) { - if (models_enabled) { - if (mc) - (*mc)(labels, 0); + model_converter_ref mc = r[0]->mc(); + if (mc.get()) { + (*mc)(labels); model_converter2model(m, mc.get(), md); if (!md) { // create empty model. @@ -210,10 +203,11 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, model_converter_ref& m return l_false; } else { - if (models_enabled) { + if (models_enabled && r.size() >= 1) { + model_converter_ref mc = r[0]->mc(); model_converter2model(m, mc.get(), md); if (mc) - (*mc)(labels, 0); + (*mc)(labels); } reason_unknown = "incomplete"; return l_undef; diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 3b8110fd2..98c57f12c 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -24,8 +24,6 @@ Notes: #include "tactic/goal.h" #include "util/params.h" #include "util/statistics.h" -#include "tactic/model_converter.h" -#include "tactic/proof_converter.h" #include "tactic/tactic_exception.h" #include "util/lbool.h" @@ -50,19 +48,7 @@ public: The list of resultant subgoals is stored in \c result. The content of \c in may be destroyed during the operation. - - The resultant model converter \c mc can be used to convert a model for one of the returned subgoals - into a model for \in. If mc == 0, then model construction is disabled or any model for a subgoal - of \c in is also a model for \c in. - If \c result is decided_sat (i.e., it contains a single empty subgoal), then - the model converter is just wrapping the model. - - The resultant proof converter \c pc can be used to convert proofs for each subgoal in \c result - into a proof for \c in. If pc == 0, then one of the following conditions should hold: - 1- proof construction is disabled, - 2- result contains a single subgoal, and any proof of unsatisfiability for this subgoal is a proof for \c in. - 3- result is an decided_unsat (i.e., it contains a single unsat subgoal). The actual proof can be extracted from this goal. - + The output parameter \c core is used to accumulate the unsat core of closed subgoals. It must be 0 if dependency tracking is disabled, or the result is decided unsat, or no tagged assertions were used to close any subgoal. @@ -77,7 +63,6 @@ public: */ virtual void operator()(/* in */ goal_ref const & in, /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, /* out */ expr_dependency_ref & core) = 0; virtual void collect_statistics(statistics & st) const {} @@ -118,9 +103,9 @@ void report_tactic_progress(char const * id, unsigned val); class skip_tactic : public tactic { public: - virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); - virtual void cleanup() {} - virtual tactic * translate(ast_manager & m) { return this; } + void operator()(goal_ref const & in, goal_ref_buffer & result, expr_dependency_ref & core) override; + void cleanup() override {} + tactic * translate(ast_manager & m) override { return this; } }; tactic * mk_skip_tactic(); @@ -151,8 +136,8 @@ public: #define MK_SIMPLE_TACTIC_FACTORY(NAME, ST) MK_TACTIC_FACTORY(NAME, return ST;) -void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, expr_dependency_ref & core); -lbool check_sat(tactic & t, goal_ref & g, model_ref & md, model_converter_ref& mc, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); +void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, expr_dependency_ref & core); +lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); // Throws an exception if goal \c in requires proof generation. void fail_if_proof_generation(char const * tactic_name, goal_ref const & in); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 3f94908b3..5003a4f9d 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -16,33 +16,28 @@ Author: Notes: --*/ -#include "tactic/tactical.h" #include "util/scoped_timer.h" #include "util/cancel_eh.h" #include "util/cooperate.h" #include "util/scoped_ptr_vector.h" #include "util/z3_omp.h" +#include "tactic/tactical.h" class binary_tactical : public tactic { protected: - tactic * m_t1; - tactic * m_t2; - + tactic_ref m_t1; + tactic_ref m_t2; public: + binary_tactical(tactic * t1, tactic * t2): m_t1(t1), m_t2(t2) { SASSERT(m_t1); SASSERT(m_t2); - m_t1->inc_ref(); - m_t2->inc_ref(); } - virtual ~binary_tactical() { - m_t1->dec_ref(); - m_t2->dec_ref(); - } + virtual ~binary_tactical() {} virtual void updt_params(params_ref const & p) { m_t1->updt_params(p); @@ -108,7 +103,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { bool models_enabled = in->models_enabled(); @@ -117,50 +111,35 @@ public: ast_manager & m = in->m(); goal_ref_buffer r1; - model_converter_ref mc1; expr_dependency_ref core1(m); result.reset(); - mc = 0; core = 0; - m_t1->operator()(in, r1, mc1, core1); + m_t1->operator()(in, r1, core1); SASSERT(!is_decided(r1) || !core1); // the pc and core of decided goals is 0 unsigned r1_size = r1.size(); SASSERT(r1_size > 0); if (r1_size == 1) { if (r1[0]->is_decided()) { - result.push_back(r1[0]); - if (models_enabled) mc = mc1; + result.push_back(r1[0]); return; } goal_ref r1_0 = r1[0]; - m_t2->operator()(r1_0, result, mc, core); - if (models_enabled) mc = concat(mc1.get(), mc.get()); + m_t2->operator()(r1_0, result, core); if (cores_enabled) core = m.mk_join(core1.get(), core); } else { if (cores_enabled) core = core1; - model_converter_ref_buffer mc_buffer; - sbuffer sz_buffer; goal_ref_buffer r2; for (unsigned i = 0; i < r1_size; i++) { goal_ref g = r1[i]; - r2.reset(); - model_converter_ref mc2; + r2.reset(); expr_dependency_ref core2(m); - m_t2->operator()(g, r2, mc2, core2); + m_t2->operator()(g, r2, core2); if (is_decided(r2)) { SASSERT(r2.size() == 1); if (is_decided_sat(r2)) { // found solution... result.push_back(r2[0]); - if (models_enabled) { - // mc2 contains the actual model - model_ref md; - md = alloc(model, m); - apply(mc2, md, 0); - apply(mc1, md, i); - mc = model2model_converter(md.get()); - } SASSERT(!core); return; } @@ -169,45 +148,30 @@ public: // the proof and unsat core of a decided_unsat goal are stored in the node itself. // core2 must be 0. SASSERT(!core2); - if (models_enabled) mc_buffer.push_back(0); - if (models_enabled || proofs_enabled) sz_buffer.push_back(0); if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); } } else { result.append(r2.size(), r2.c_ptr()); - if (models_enabled) mc_buffer.push_back(mc2.get()); - if (models_enabled || proofs_enabled) sz_buffer.push_back(r2.size()); if (cores_enabled) core = m.mk_join(core.get(), core2.get()); } } - - proof_converter_ref_buffer pc_buffer; - proof_converter_ref pc(in->pc()); - if (proofs_enabled) { - for (goal* g : r1) { - pc_buffer.push_back(g->pc()); - } - } - + if (result.empty()) { // all subgoals were shown to be unsat. // create an decided_unsat goal with the proof in->reset_all(); proof_ref pr(m); if (proofs_enabled) { - apply(m, pc, pc_buffer, pr); - in->set(proof2proof_converter(m, pr)); + apply(m, in->pc(), pr); } SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); core = 0; result.push_back(in.get()); - SASSERT(!mc); SASSERT(!core); + SASSERT(!core); } else { - if (models_enabled) mc = concat(mc1.get(), mc_buffer.size(), mc_buffer.c_ptr(), sz_buffer.c_ptr()); - if (proofs_enabled) in->set(concat(pc.get(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr())); SASSERT(cores_enabled || core == 0); } } @@ -272,92 +236,58 @@ tactic * and_then(unsigned num, tactic * const * ts) { class nary_tactical : public tactic { protected: - ptr_vector m_ts; + sref_vector m_ts; public: nary_tactical(unsigned num, tactic * const * ts) { for (unsigned i = 0; i < num; i++) { SASSERT(ts[i]); m_ts.push_back(ts[i]); - ts[i]->inc_ref(); } } - virtual ~nary_tactical() { - unsigned sz = m_ts.size(); - for (unsigned i = 0; i < sz; i++) { - m_ts[i]->dec_ref(); - } - } + virtual ~nary_tactical() {} - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { TRACE("nary_tactical_updt_params", tout << "updt_params: " << p << "\n";); - ptr_vector::iterator it = m_ts.begin(); - ptr_vector::iterator end = m_ts.end(); - for (; it != end; ++it) - (*it)->updt_params(p); + for (tactic* t : m_ts) t->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { - ptr_vector::iterator it = m_ts.begin(); - ptr_vector::iterator end = m_ts.end(); - for (; it != end; ++it) - (*it)->collect_param_descrs(r); + void collect_param_descrs(param_descrs & r) override { + for (tactic* t : m_ts) t->collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { - ptr_vector::const_iterator it = m_ts.begin(); - ptr_vector::const_iterator end = m_ts.end(); - for (; it != end; ++it) - (*it)->collect_statistics(st); + void collect_statistics(statistics & st) const override { + for (tactic const* t : m_ts) t->collect_statistics(st); } - virtual void reset_statistics() { - ptr_vector::const_iterator it = m_ts.begin(); - ptr_vector::const_iterator end = m_ts.end(); - for (; it != end; ++it) - (*it)->reset_statistics(); + void reset_statistics() override { + for (tactic* t : m_ts) t->reset_statistics(); } - virtual void cleanup() { - ptr_vector::iterator it = m_ts.begin(); - ptr_vector::iterator end = m_ts.end(); - for (; it != end; ++it) - (*it)->cleanup(); + void cleanup() override { + for (tactic* t : m_ts) t->cleanup(); } - virtual void reset() { - ptr_vector::iterator it = m_ts.begin(); - ptr_vector::iterator end = m_ts.end(); - for (; it != end; ++it) - (*it)->reset(); + void reset() override { + for (tactic* t : m_ts) t->reset(); } - virtual void set_logic(symbol const & l) { - ptr_vector::iterator it = m_ts.begin(); - ptr_vector::iterator end = m_ts.end(); - for (; it != end; ++it) - (*it)->set_logic(l); + void set_logic(symbol const & l) override { + for (tactic* t : m_ts) t->set_logic(l); } - virtual void set_progress_callback(progress_callback * callback) { - ptr_vector::iterator it = m_ts.begin(); - ptr_vector::iterator end = m_ts.end(); - for (; it != end; ++it) - (*it)->set_progress_callback(callback); + void set_progress_callback(progress_callback * callback) override { + for (tactic* t : m_ts) t->set_progress_callback(callback); } protected: template tactic * translate_core(ast_manager & m) { - ptr_buffer new_ts; - ptr_vector::iterator it = m_ts.begin(); - ptr_vector::iterator end = m_ts.end(); - for (; it != end; ++it) { - tactic * curr = *it; - tactic * new_curr = curr->translate(m); - new_ts.push_back(new_curr); + sref_vector new_ts; + for (tactic* curr : m_ts) { + new_ts.push_back(curr->translate(m)); } return alloc(T, new_ts.size(), new_ts.c_ptr()); } @@ -372,7 +302,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { goal orig(*(in.get())); proof_converter_ref pc = in->pc(); @@ -381,13 +310,12 @@ public: for (i = 0; i < sz; i++) { tactic * t = m_ts[i]; result.reset(); - mc = 0; pc = 0; core = 0; SASSERT(sz > 0); if (i < sz - 1) { try { - t->operator()(in, result, mc, core); + t->operator()(in, result, core); return; } catch (tactic_exception &) { @@ -395,7 +323,7 @@ public: } } else { - t->operator()(in, result, mc, core); + t->operator()(in, result, core); return; } in->reset_all(); @@ -472,7 +400,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { bool use_seq; #ifdef _NO_OMP_ @@ -482,7 +409,7 @@ public: #endif if (use_seq) { // execute tasks sequentially - or_else_tactical::operator()(in, result, mc, core); + or_else_tactical::operator()(in, result, core); return; } @@ -510,14 +437,13 @@ public: #pragma omp parallel for for (int i = 0; i < static_cast(sz); i++) { goal_ref_buffer _result; - model_converter_ref _mc; expr_dependency_ref _core(*(managers[i])); goal_ref in_copy = in_copies[i]; tactic & t = *(ts.get(i)); try { - t(in_copy, _result, _mc, _core); + t(in_copy, _result, _core); bool first = false; #pragma omp critical (par_tactical) { @@ -533,10 +459,9 @@ public: } } ast_translation translator(*(managers[i]), m, false); - for (unsigned k = 0; k < _result.size(); k++) { - result.push_back(_result[k]->translate(translator)); + for (goal* g : _result) { + result.push_back(g->translate(translator)); } - mc = _mc ? _mc->translate(translator) : 0; expr_dependency_translation td(translator); core = td(_core); } @@ -561,7 +486,6 @@ public: } } if (finished_id == UINT_MAX) { - mc = 0; switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); case TACTIC_EX: throw tactic_exception(ex_msg.c_str()); @@ -600,7 +524,6 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { bool use_seq; #ifdef _NO_OMP_ @@ -610,22 +533,22 @@ public: #endif if (use_seq) { // execute tasks sequentially - and_then_tactical::operator()(in, result, mc, core); + and_then_tactical::operator()(in, result, core); return; } + // enabling proofs is possible, but requires translating subgoals back. + fail_if_proof_generation("par_and_then", in); bool models_enabled = in->models_enabled(); bool proofs_enabled = in->proofs_enabled(); bool cores_enabled = in->unsat_core_enabled(); ast_manager & m = in->m(); goal_ref_buffer r1; - model_converter_ref mc1; expr_dependency_ref core1(m); result.reset(); - mc = 0; core = 0; - m_t1->operator()(in, r1, mc1, core1); + m_t1->operator()(in, r1, core1); SASSERT(!is_decided(r1) || !core1); // the core of decided goals is 0 unsigned r1_size = r1.size(); SASSERT(r1_size > 0); @@ -633,13 +556,11 @@ public: // Only one subgoal created... no need for parallelism if (r1[0]->is_decided()) { result.push_back(r1[0]); - if (models_enabled) mc = mc1; SASSERT(!core); return; } goal_ref r1_0 = r1[0]; - m_t2->operator()(r1_0, result, mc, core); - if (models_enabled) mc = concat(mc1.get(), mc.get()); + m_t2->operator()(r1_0, result, core); if (cores_enabled) core = m.mk_join(core1.get(), core); } else { @@ -657,15 +578,11 @@ public: ts2.push_back(m_t2->translate(*new_m)); } - model_converter_ref_buffer mc_buffer; - proof_converter_ref_buffer pc_buffer; scoped_ptr_vector core_buffer; scoped_ptr_vector goals_vect; - mc_buffer.resize(r1_size); core_buffer.resize(r1_size); goals_vect.resize(r1_size); - pc_buffer.resize(r1_size); bool found_solution = false; bool failed = false; @@ -679,13 +596,12 @@ public: goal_ref new_g = g_copies[i]; goal_ref_buffer r2; - model_converter_ref mc2; expr_dependency_ref core2(new_m); bool curr_failed = false; try { - ts2[i]->operator()(new_g, r2, mc2, core2); + ts2[i]->operator()(new_g, r2, core2); } catch (tactic_exception & ex) { #pragma omp critical (par_and_then_tactical) @@ -750,30 +666,16 @@ public: } ast_translation translator(new_m, m, false); SASSERT(r2.size() == 1); - result.push_back(r2[0]->translate(translator)); - if (models_enabled) { - // mc2 contains the actual model - mc2 = mc2 ? mc2->translate(translator) : 0; - model_ref md; - md = alloc(model, m); - apply(mc2, md, 0); - apply(mc1, md, i); - mc = model2model_converter(md.get()); - } + result.push_back(r2[0]->translate(translator)); SASSERT(!core); } } else { SASSERT(is_decided_unsat(r2)); // the proof and unsat core of a decided_unsat goal are stored in the node itself. - // pc2 and core2 must be 0. + // core2 must be 0. SASSERT(!core2); - if (models_enabled) mc_buffer.set(i, 0); - if (proofs_enabled) { - proof * pr = r2[0]->pr(0); - pc_buffer.push_back(proof2proof_converter(m, pr)); - } if (cores_enabled && r2[0]->dep(0) != 0) { expr_dependency_ref * new_dep = alloc(expr_dependency_ref, new_m); *new_dep = r2[0]->dep(0); @@ -785,8 +687,6 @@ public: goal_ref_buffer * new_r2 = alloc(goal_ref_buffer); goals_vect.set(i, new_r2); new_r2->append(r2.size(), r2.c_ptr()); - mc_buffer.set(i, mc2.get()); - pc_buffer.set(i, new_g->pc()); if (cores_enabled && core2 != 0) { expr_dependency_ref * new_dep = alloc(expr_dependency_ref, new_m); *new_dep = core2; @@ -809,23 +709,20 @@ public: return; core = 0; - sbuffer sz_buffer; for (unsigned i = 0; i < r1_size; i++) { ast_translation translator(*(managers[i]), m, false); goal_ref_buffer * r = goals_vect[i]; + unsigned j = result.size(); if (r != 0) { for (unsigned k = 0; k < r->size(); k++) { result.push_back((*r)[k]->translate(translator)); } - sz_buffer.push_back(r->size()); } - else { - sz_buffer.push_back(0); + if (proofs_enabled) { + // update proof converter of r1[i] + r1[i]->set(concat(r1[i]->pc(), result.size() - j, result.c_ptr() + j)); } - if (mc_buffer[i] != 0) - mc_buffer.set(i, mc_buffer[i]->translate(translator)); - if (pc_buffer[i] != 0) - pc_buffer.set(i, pc_buffer[i]->translate(translator)); + expr_dependency_translation td(translator); if (core_buffer[i] != 0) { expr_dependency_ref curr_core(m); @@ -841,23 +738,15 @@ public: in->reset_all(); proof_ref pr(m); if (proofs_enabled) { - proof_converter_ref_buffer pc_buffer; - for (goal_ref g : r1) { - pc_buffer.push_back(g->pc()); - } - proof_converter_ref pc = in->pc(); - apply(m, pc, pc_buffer, pr); - in->set(proof2proof_converter(m, pr)); + apply(m, in->pc(), pr); } SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); core = 0; result.push_back(in.get()); - SASSERT(!mc); SASSERT(!core); + SASSERT(!core); } else { - if (models_enabled) mc = concat(mc1.get(), mc_buffer.size(), mc_buffer.c_ptr(), sz_buffer.c_ptr()); - if (proofs_enabled) in->set(concat(in->pc(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr())); SASSERT(cores_enabled || core == 0); } } @@ -886,25 +775,21 @@ tactic * par_and_then(unsigned num, tactic * const * ts) { class unary_tactical : public tactic { protected: - tactic * m_t; + tactic_ref m_t; public: unary_tactical(tactic * t): m_t(t) { - SASSERT(t); - t->inc_ref(); + SASSERT(t); } - virtual ~unary_tactical() { - m_t->dec_ref(); - } + virtual ~unary_tactical() { } virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - m_t->operator()(in, result, mc, core); + m_t->operator()(in, result, core); } virtual void cleanup(void) { m_t->cleanup(); } @@ -930,12 +815,10 @@ class repeat_tactical : public unary_tactical { void operator()(unsigned depth, goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { // TODO: implement a non-recursive version. if (depth > m_max_depth) { result.push_back(in.get()); - mc = 0; core = 0; return; } @@ -945,20 +828,17 @@ class repeat_tactical : public unary_tactical { bool cores_enabled = in->unsat_core_enabled(); ast_manager & m = in->m(); - goal_ref_buffer r1; - model_converter_ref mc1; + goal_ref_buffer r1; expr_dependency_ref core1(m); result.reset(); - mc = 0; core = 0; { goal orig_in(in->m(), proofs_enabled, models_enabled, cores_enabled); orig_in.copy_from(*(in.get())); - m_t->operator()(in, r1, mc1, core1); - if (is_equal(orig_in, *(in.get()))) { - result.push_back(r1[0]); - if (models_enabled) mc = mc1; - if (cores_enabled) core = core1; + m_t->operator()(in, r1, core1); + if (r1.size() == 1 && is_equal(orig_in, *(r1[0]))) { + result.push_back(r1[0]); + if (cores_enabled) core = core1; return; } } @@ -966,62 +846,41 @@ class repeat_tactical : public unary_tactical { SASSERT(r1_size > 0); if (r1_size == 1) { if (r1[0]->is_decided()) { - result.push_back(r1[0]); - if (models_enabled) mc = mc1; + result.push_back(r1[0]); SASSERT(!core); return; } goal_ref r1_0 = r1[0]; - operator()(depth+1, r1_0, result, mc, core); - if (models_enabled) mc = concat(mc.get(), mc1.get()); - if (cores_enabled) core = m.mk_join(core1.get(), core); + operator()(depth+1, r1_0, result, core); + if (cores_enabled) core = m.mk_join(core1.get(), core); } else { if (cores_enabled) core = core1; - model_converter_ref_buffer mc_buffer; - sbuffer sz_buffer; goal_ref_buffer r2; for (unsigned i = 0; i < r1_size; i++) { goal_ref g = r1[i]; - r2.reset(); - model_converter_ref mc2; + r2.reset(); expr_dependency_ref core2(m); - operator()(depth+1, g, r2, mc2, core2); + operator()(depth+1, g, r2, core2); if (is_decided(r2)) { SASSERT(r2.size() == 1); if (is_decided_sat(r2)) { // found solution... result.push_back(r2[0]); - if (models_enabled) { - // mc2 contains the actual model - model_ref md; - if (mc2) (*mc2)(md, 0); - if (mc1) (*mc1)(md, i); - mc = model2model_converter(md.get()); - } SASSERT(!core); return; } else { SASSERT(is_decided_unsat(r2)); SASSERT(!core2); - if (models_enabled) mc_buffer.push_back(0); - if (models_enabled || proofs_enabled) sz_buffer.push_back(0); if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); } } else { - result.append(r2.size(), r2.c_ptr()); - if (models_enabled) mc_buffer.push_back(mc2.get()); - if (models_enabled || proofs_enabled) sz_buffer.push_back(r2.size()); + result.append(r2.size(), r2.c_ptr()); if (cores_enabled) core = m.mk_join(core.get(), core2.get()); } } - - proof_converter_ref_buffer pc_buffer; - if (proofs_enabled) { - for (goal_ref g : r1) pc_buffer.push_back(g->pc()); - } if (result.empty()) { // all subgoals were shown to be unsat. @@ -1029,19 +888,15 @@ class repeat_tactical : public unary_tactical { in->reset_all(); proof_ref pr(m); if (proofs_enabled) { - proof_converter_ref pc = in->pc(); - apply(m, pc, pc_buffer, pr); - in->set(proof2proof_converter(m, pr)); + apply(m, in->pc(), pr); } SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); core = 0; result.push_back(in.get()); - SASSERT(!mc); SASSERT(!core); + SASSERT(!core); } else { - if (models_enabled) mc = concat(mc1.get(), mc_buffer.size(), mc_buffer.c_ptr(), sz_buffer.c_ptr()); - if (proofs_enabled) in->set(concat(in->pc(), pc_buffer.size(), pc_buffer.c_ptr(), sz_buffer.c_ptr())); SASSERT(cores_enabled || core == 0); } } @@ -1055,9 +910,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - operator()(0, in, result, mc, core); + operator()(0, in, result, core); } virtual tactic * translate(ast_manager & m) { @@ -1077,12 +931,10 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - m_t->operator()(in, result, mc, core); + m_t->operator()(in, result, core); if (result.size() > m_threshold) { result.reset(); - mc = 0; core = 0; throw tactic_exception("failed-if-branching tactical"); } @@ -1104,9 +956,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - m_t->operator()(in, result, mc, core); + m_t->operator()(in, result, core); m_t->cleanup(); } @@ -1127,13 +978,12 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { cancel_eh eh(in->m().limit()); { // Warning: scoped_timer is not thread safe in Linux. scoped_timer timer(m_timeout, &eh); - m_t->operator()(in, result, mc, core); + m_t->operator()(in, result, core); } } @@ -1196,10 +1046,9 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { scope _scope(m_name); - m_t->operator()(in, result, mc, core); + m_t->operator()(in, result, core); } virtual tactic * translate(ast_manager & m) { @@ -1214,33 +1063,29 @@ tactic * annotate_tactic(char const* name, tactic * t) { } class cond_tactical : public binary_tactical { - probe * m_p; + probe_ref m_p; public: cond_tactical(probe * p, tactic * t1, tactic * t2): binary_tactical(t1, t2), m_p(p) { SASSERT(m_p); - m_p->inc_ref(); } - ~cond_tactical() { - m_p->dec_ref(); - } + virtual ~cond_tactical() {} virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { if (m_p->operator()(*(in.get())).is_true()) - m_t1->operator()(in, result, mc, core); + m_t1->operator()(in, result, core); else - m_t2->operator()(in, result, mc, core); + m_t2->operator()(in, result, core); } virtual tactic * translate(ast_manager & m) { tactic * new_t1 = m_t1->translate(m); tactic * new_t2 = m_t2->translate(m); - return alloc(cond_tactical, m_p, new_t1, new_t2); + return alloc(cond_tactical, m_p.get(), new_t1, new_t2); } }; @@ -1253,25 +1098,20 @@ tactic * when(probe * p, tactic * t) { } class fail_if_tactic : public tactic { - probe * m_p; + probe_ref m_p; public: fail_if_tactic(probe * p): m_p(p) { SASSERT(m_p); - m_p->inc_ref(); } - ~fail_if_tactic() { - m_p->dec_ref(); - } + virtual ~fail_if_tactic() {} void cleanup() {} virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - mc = 0; core = 0; if (m_p->operator()(*(in.get())).is_true()) { throw tactic_exception("fail-if tactic"); @@ -1298,15 +1138,14 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { if (in->proofs_enabled()) { - mc = 0; core = 0; + core = 0; result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, mc, core); + m_t->operator()(in, result, core); } } @@ -1319,15 +1158,14 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { if (in->unsat_core_enabled()) { - mc = 0; core = 0; + core = 0; result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, mc, core); + m_t->operator()(in, result, core); } } @@ -1340,15 +1178,14 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { if (in->models_enabled()) { - mc = 0; core = 0; + core = 0; result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, mc, core); + m_t->operator()(in, result, core); } } diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index 71034b2b1..fb5c7d458 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -39,10 +39,9 @@ class macro_finder_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("macro-finder", *g); bool produce_proofs = g->proofs_enabled(); @@ -75,8 +74,7 @@ class macro_finder_tactic : public tactic { func_decl * f = mm.get_macro_interpretation(i, f_interp); evmc->add(f, f_interp); } - mc = evmc; - + g->add(evmc); g->inc_depth(); result.push_back(g.get()); TRACE("macro-finder", g->display(tout);); @@ -118,9 +116,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index c8c1f2b0f..61dbcaf01 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -37,10 +37,9 @@ class quasi_macros_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("quasi-macros", *g); bool produce_proofs = g->proofs_enabled(); @@ -87,8 +86,7 @@ class quasi_macros_tactic : public tactic { func_decl * f = mm.get_macro_interpretation(i, f_interp); evmc->add(f, f_interp); } - mc = evmc; - + g->add(evmc); g->inc_depth(); result.push_back(g.get()); TRACE("quasi-macros", g->display(tout);); @@ -129,9 +127,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index e4ba71ad7..6b9882e29 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -33,10 +33,9 @@ class ufbv_rewriter_tactic : public tactic { void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; core = 0; + core = 0; tactic_report report("ufbv-rewriter", *g); fail_if_unsat_core_generation("ufbv-rewriter", g); @@ -59,7 +58,8 @@ class ufbv_rewriter_tactic : public tactic { for (unsigned i = 0; i < new_forms.size(); i++) g->assert_expr(new_forms.get(i), produce_proofs ? new_proofs.get(i) : 0, 0); - mc = 0; // CMW: Remark: The demodulator could potentially remove all references to a variable. + // CMW: Remark: The demodulator could potentially + // remove all references to a variable. g->inc_depth(); result.push_back(g.get()); @@ -101,9 +101,8 @@ public: virtual void operator()(goal_ref const & in, goal_ref_buffer & result, - model_converter_ref & mc, expr_dependency_ref & core) { - (*m_imp)(in, result, mc, core); + (*m_imp)(in, result, core); } virtual void cleanup() { diff --git a/src/test/horn_subsume_model_converter.cpp b/src/test/horn_subsume_model_converter.cpp index a361cfb2a..3e493d408 100644 --- a/src/test/horn_subsume_model_converter.cpp +++ b/src/test/horn_subsume_model_converter.cpp @@ -31,17 +31,17 @@ void tst_horn_subsume_model_converter() { mc->insert(p, m.mk_app(q, a.mk_numeral(rational(1), true), a.mk_numeral(rational(2), true))); model_converter_ref mcr = mc.get(); - apply(mcr, mr, 0); + apply(mcr, mr); model_smt2_pp(std::cout, m, *mr.get(), 0); mr = alloc(model, m); mc->insert(p, m.mk_app(q, a.mk_numeral(rational(3), true), a.mk_numeral(rational(5), true))); - apply(mcr, mr, 0); + apply(mcr, mr); model_smt2_pp(std::cout, m, *mr.get(), 0); mr = alloc(model, m); mc->insert(p, m.mk_app(r, m.mk_var(0,a.mk_int()), m.mk_var(1, a.mk_int()))); - apply(mcr, mr, 0); + apply(mcr, mr); model_smt2_pp(std::cout, m, *mr.get(), 0); mr = alloc(model, m); @@ -52,7 +52,7 @@ void tst_horn_subsume_model_converter() { body1 = m.mk_app(q, m.mk_var(1, a.mk_int()), m.mk_var(2, a.mk_int())); VERIFY(mc->mk_horn(head1, body1, pred, body2)); mc->insert(pred, body2); - apply(mcr, mr, 0); + apply(mcr, mr); model_smt2_pp(std::cout, m, *mr.get(), 0); mr = alloc(model, m); @@ -60,7 +60,7 @@ void tst_horn_subsume_model_converter() { body1 = m.mk_app(q, m.mk_var(1, a.mk_int()), m.mk_var(0, a.mk_int())); VERIFY(mc->mk_horn(head1, body1, pred, body2)); mc->insert(pred, body2); - apply(mcr, mr, 0); + apply(mcr, mr); model_smt2_pp(std::cout, m, *mr.get(), 0); From 2f218b0bdc9a62559ff8b6ec1798584943c73be1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 19 Nov 2017 12:18:50 -0800 Subject: [PATCH 0349/1283] remove also cores as arguments to tactics Signed-off-by: Nikolaj Bjorner --- .../ackermannize_bv_tactic.cpp | 5 +- src/api/api_tactic.cpp | 4 +- src/api/api_tactic.h | 1 - src/cmd_context/echo_tactic.cpp | 10 +- src/cmd_context/tactic_cmds.cpp | 3 +- .../subpaving/tactic/subpaving_tactic.cpp | 4 +- src/muz/fp/horn_tactic.cpp | 9 +- src/muz/pdr/pdr_context.cpp | 3 +- src/muz/pdr/pdr_farkas_learner.cpp | 3 +- src/muz/spacer/spacer_context.cpp | 3 +- src/muz/spacer/spacer_legacy_frames.cpp | 3 +- src/muz/spacer/spacer_util.cpp | 6 +- src/nlsat/tactic/nlsat_tactic.cpp | 9 +- src/opt/opt_context.cpp | 3 +- src/qe/nlqsat.cpp | 6 +- src/qe/qe_lite.cpp | 9 +- src/qe/qe_sat_tactic.cpp | 3 +- src/qe/qe_tactic.cpp | 9 +- src/qe/qsat.cpp | 6 +- src/sat/sat_solver/inc_sat_solver.cpp | 5 +- src/sat/tactic/sat_tactic.cpp | 9 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 4 +- src/smt/tactic/smt_tactic.cpp | 4 +- src/smt/tactic/unit_subsumption_tactic.cpp | 3 +- src/solver/solver2tactic.cpp | 12 +- src/tactic/CMakeLists.txt | 1 + src/tactic/aig/aig_tactic.cpp | 5 +- src/tactic/arith/add_bounds_tactic.cpp | 9 +- src/tactic/arith/arith_bounds_tactic.cpp | 3 +- src/tactic/arith/card2bv_tactic.cpp | 5 +- src/tactic/arith/degree_shift_tactic.cpp | 9 +- src/tactic/arith/diff_neq_tactic.cpp | 10 +- src/tactic/arith/elim01_tactic.cpp | 4 +- src/tactic/arith/eq2bv_tactic.cpp | 6 +- src/tactic/arith/factor_tactic.cpp | 9 +- src/tactic/arith/fix_dl_var_tactic.cpp | 9 +- src/tactic/arith/fm_tactic.cpp | 9 +- src/tactic/arith/lia2card_tactic.cpp | 4 +- src/tactic/arith/lia2pb_tactic.cpp | 10 +- src/tactic/arith/nla2bv_tactic.cpp | 5 +- src/tactic/arith/normalize_bounds_tactic.cpp | 10 +- src/tactic/arith/pb2bv_tactic.cpp | 10 +- src/tactic/arith/propagate_ineqs_tactic.cpp | 7 +- src/tactic/arith/purify_arith_tactic.cpp | 4 +- src/tactic/arith/recover_01_tactic.cpp | 10 +- src/tactic/bv/bit_blaster_tactic.cpp | 9 +- src/tactic/bv/bv1_blaster_tactic.cpp | 9 +- src/tactic/bv/bv_bound_chk_tactic.cpp | 10 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 7 +- src/tactic/bv/bvarray2uf_tactic.cpp | 10 +- src/tactic/bv/dt2bv_tactic.cpp | 5 +- src/tactic/bv/elim_small_bv_tactic.cpp | 10 +- src/tactic/bv/max_bv_sharing_tactic.cpp | 9 +- src/tactic/core/blast_term_ite_tactic.cpp | 10 +- src/tactic/core/cofactor_term_ite_tactic.cpp | 5 +- src/tactic/core/collect_statistics_tactic.cpp | 3 +- src/tactic/core/ctx_simplify_tactic.cpp | 4 +- src/tactic/core/ctx_simplify_tactic.h | 3 +- src/tactic/core/der_tactic.cpp | 4 +- src/tactic/core/distribute_forall_tactic.cpp | 5 +- src/tactic/core/dom_simplify_tactic.cpp | 8 +- src/tactic/core/dom_simplify_tactic.h | 4 +- src/tactic/core/elim_term_ite_tactic.cpp | 9 +- src/tactic/core/elim_uncnstr_tactic.cpp | 9 +- src/tactic/core/injectivity_tactic.cpp | 9 +- src/tactic/core/nnf_tactic.cpp | 4 +- src/tactic/core/occf_tactic.cpp | 9 +- src/tactic/core/pb_preprocess_tactic.cpp | 6 +- src/tactic/core/propagate_values_tactic.cpp | 10 +- src/tactic/core/reduce_args_tactic.cpp | 9 +- src/tactic/core/simplify_tactic.cpp | 4 +- src/tactic/core/simplify_tactic.h | 14 +- src/tactic/core/solve_eqs_tactic.cpp | 12 +- src/tactic/core/split_clause_tactic.cpp | 5 +- src/tactic/core/symmetry_reduce_tactic.cpp | 8 +- src/tactic/core/tseitin_cnf_tactic.cpp | 9 +- src/tactic/fpa/fpa2bv_tactic.cpp | 10 +- src/tactic/goal.cpp | 2 + src/tactic/goal.h | 5 + src/tactic/model_converter.h | 36 +++ src/tactic/portfolio/parallel_tactic.cpp | 2 +- src/tactic/sine_filter.cpp | 6 +- src/tactic/sls/sls_tactic.cpp | 5 +- src/tactic/smtlogics/qfufbv_tactic.cpp | 3 +- src/tactic/tactic.cpp | 34 +-- src/tactic/tactic.h | 8 +- src/tactic/tactical.cpp | 246 ++++++------------ src/tactic/ufbv/macro_finder_tactic.cpp | 9 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 9 +- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 9 +- 90 files changed, 326 insertions(+), 565 deletions(-) diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index a38b19c7d..f0e960644 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -29,9 +29,7 @@ public: virtual ~ackermannize_bv_tactic() { } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + virtual void operator()(goal_ref const & g, goal_ref_buffer & result) { tactic_report report("ackermannize", *g); fail_if_unsat_core_generation("ackermannize", g); fail_if_proof_generation("ackermannize", g); @@ -49,7 +47,6 @@ public: TRACE("ackermannize", tout << "ackermannize not run due to limit" << std::endl;); result.reset(); result.push_back(g.get()); - core = 0; return; } result.push_back(resg.get()); diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 2d9a47863..e9b3bb47d 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -25,7 +25,7 @@ Revision History: #include "util/cancel_eh.h" #include "util/scoped_timer.h" -Z3_apply_result_ref::Z3_apply_result_ref(api::context& c, ast_manager & m): api::object(c), m_core(m) { +Z3_apply_result_ref::Z3_apply_result_ref(api::context& c, ast_manager & m): api::object(c) { } extern "C" { @@ -418,7 +418,7 @@ extern "C" { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); scoped_timer timer(timeout, &eh); try { - exec(*to_tactic_ref(t), new_goal, ref->m_subgoals, ref->m_core); + exec(*to_tactic_ref(t), new_goal, ref->m_subgoals); ref->m_pc = new_goal->pc(); ref->m_mc = new_goal->mc(); return of_apply_result(ref); diff --git a/src/api/api_tactic.h b/src/api/api_tactic.h index fd2f05185..909785748 100644 --- a/src/api/api_tactic.h +++ b/src/api/api_tactic.h @@ -50,7 +50,6 @@ struct Z3_apply_result_ref : public api::object { goal_ref_buffer m_subgoals; model_converter_ref m_mc; proof_converter_ref m_pc; - expr_dependency_ref m_core; Z3_apply_result_ref(api::context& c, ast_manager & m); virtual ~Z3_apply_result_ref() {} }; diff --git a/src/cmd_context/echo_tactic.cpp b/src/cmd_context/echo_tactic.cpp index 37dcc0a29..131962716 100644 --- a/src/cmd_context/echo_tactic.cpp +++ b/src/cmd_context/echo_tactic.cpp @@ -28,15 +28,14 @@ public: echo_tactic(cmd_context & ctx, char const * msg, bool newline):m_ctx(ctx), m_msg(msg), m_newline(newline) {} virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { #pragma omp critical (echo_tactic) { m_ctx.regular_stream() << m_msg; if (m_newline) m_ctx.regular_stream() << std::endl; } - skip_tactic::operator()(in, result, core); + skip_tactic::operator()(in, result); } }; @@ -60,8 +59,7 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { double val = (*m_p)(*(in.get())).get_value(); #pragma omp critical (probe_value_tactic) { @@ -71,7 +69,7 @@ public: if (m_newline) m_ctx.diagnostic_stream() << std::endl; } - skip_tactic::operator()(in, result, core); + skip_tactic::operator()(in, result); } }; diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 20f6fc632..efbb81e28 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -326,7 +326,6 @@ public: unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit); goal_ref_buffer result_goals; - expr_dependency_ref core(m); std::string reason_unknown; bool failed = false; @@ -337,7 +336,7 @@ public: scoped_timer timer(timeout, &eh); cmd_context::scoped_watch sw(ctx); try { - exec(t, g, result_goals, core); + exec(t, g, result_goals); } catch (tactic_exception & ex) { ctx.regular_stream() << "(error \"tactic failed: " << ex.msg() << "\")" << std::endl; diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index 5940dcbfc..184d7f54a 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -242,14 +242,12 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { m_imp->process(*in); m_imp->collect_statistics(m_stats); result.reset(); result.push_back(in.get()); - core = 0; } catch (z3_exception & ex) { // convert all Z3 exceptions into tactic exceptions diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 4802bbb33..881ae9aec 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -177,10 +177,8 @@ class horn_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("horn", *g); bool produce_proofs = g->proofs_enabled(); @@ -386,9 +384,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void collect_statistics(statistics & st) const { diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 452be8914..effb9f613 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -202,9 +202,8 @@ namespace pdr { void pred_transformer::simplify_formulas(tactic& tac, expr_ref_vector& v) { goal_ref g(alloc(goal, m, false, false, false)); for (unsigned j = 0; j < v.size(); ++j) g->assert_expr(v[j].get()); - expr_dependency_ref core(m); goal_ref_buffer result; - tac(g, result, core); + tac(g, result); SASSERT(result.size() == 1); goal* r = result[0]; v.reset(); diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 68a9db2ef..59cc7de0b 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -520,10 +520,9 @@ namespace pdr { g->assert_expr(lemmas[i].get()); } expr_ref tmp(m); - expr_dependency_ref core(m); goal_ref_buffer result; tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result, core); + (*simplifier)(g, result); lemmas.reset(); SASSERT(result.size() == 1); goal* r = result[0]; diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index d1350d29a..3a032fdb3 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1367,7 +1367,6 @@ void pred_transformer::frames::simplify_formulas () // normalize level unsigned level = i < m_size ? i : infty_level (); - expr_dependency_ref core(m); goal_ref_buffer result; // simplify lemmas of the current level @@ -1393,7 +1392,7 @@ void pred_transformer::frames::simplify_formulas () } // more than one lemma at current level. simplify. - (*simplifier)(g, result, core); + (*simplifier)(g, result); SASSERT(result.size () == 1); goal *r = result[0]; diff --git a/src/muz/spacer/spacer_legacy_frames.cpp b/src/muz/spacer/spacer_legacy_frames.cpp index 176e0101b..49157a085 100644 --- a/src/muz/spacer/spacer_legacy_frames.cpp +++ b/src/muz/spacer/spacer_legacy_frames.cpp @@ -46,9 +46,8 @@ void pred_transformer::legacy_frames::simplify_formulas(tactic& tac, ast_manager &m = m_pt.get_ast_manager(); goal_ref g(alloc(goal, m, false, false, false)); for (unsigned j = 0; j < v.size(); ++j) { g->assert_expr(v[j].get()); } - expr_dependency_ref core(m); goal_ref_buffer result; - tac(g, result, core); + tac(g, result); SASSERT(result.size() == 1); goal* r = result[0]; v.reset(); diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 726ff86c8..1eddedb68 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -929,10 +929,9 @@ void simplify_bounds_old(expr_ref_vector& cube) { } expr_ref tmp(m); - expr_dependency_ref core(m); goal_ref_buffer result; tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result, core); + (*simplifier)(g, result); SASSERT(result.size() == 1); goal* r = result[0]; @@ -953,13 +952,12 @@ void simplify_bounds_new (expr_ref_vector &cube) { g->assert_expr(cube.get(i)); } - expr_dependency_ref dep(m); goal_ref_buffer goals; tactic_ref prop_values = mk_propagate_values_tactic(m); tactic_ref prop_bounds = mk_propagate_ineqs_tactic(m); tactic_ref t = and_then(prop_values.get(), prop_bounds.get()); - (*t)(g, goals, dep); + (*t)(g, goals); SASSERT(goals.size() == 1); g = goals[0]; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index bedd7c655..25e5b12cc 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -129,10 +129,8 @@ class nlsat_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("nlsat", *g); if (g->is_decided()) { @@ -233,12 +231,11 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { imp local_imp(in->m(), m_params); scoped_set_imp setter(*this, local_imp); - local_imp(in, result, core); + local_imp(in, result); } catch (z3_error & ex) { throw ex; diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index edcdb64e0..dd90963df 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -745,9 +745,8 @@ namespace opt { else { set_simplify(tac0.get()); } - expr_dependency_ref core(m); goal_ref_buffer result; - (*m_simplify)(g, result, core); + (*m_simplify)(g, result); SASSERT(result.size() == 1); goal* r = result[0]; m_model_converter = r->mc(); diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 87e713efc..ec27e168a 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -660,7 +660,7 @@ namespace qe { g->assert_expr(fml); expr_dependency_ref core(m); goal_ref_buffer result; - (*m_nftactic)(g, result, core); + (*m_nftactic)(g, result); SASSERT(result.size() == 1); TRACE("qe", result[0]->display(tout);); g2s(*result[0], m_params, m_solver, m_a2b, m_t2x); @@ -810,14 +810,12 @@ namespace qe { void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ expr_dependency_ref & core) { + /* out */ goal_ref_buffer & result) { tactic_report report("nlqsat-tactic", *in); ptr_vector fmls; expr_ref fml(m); - core = 0; in->get_formulas(fmls); fml = mk_and(m, fmls.size(), fmls.c_ptr()); if (m_mode == elim_t) { diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 51e5c1b78..5c0e3b7d8 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -2532,10 +2532,8 @@ class qe_lite_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("qe-lite", *g); proof_ref new_pr(m); expr_ref new_f(m); @@ -2601,9 +2599,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 28bc78f84..43029204e 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -233,8 +233,7 @@ namespace qe { virtual void operator()( goal_ref const& goal, - goal_ref_buffer& result, - expr_dependency_ref& core) + goal_ref_buffer& result) { try { checkpoint(); diff --git a/src/qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp index 131d0d3fb..80f52020c 100644 --- a/src/qe/qe_tactic.cpp +++ b/src/qe/qe_tactic.cpp @@ -50,10 +50,8 @@ class qe_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("qe", *g); m_fparams.m_model = g->models_enabled(); proof_ref new_pr(m); @@ -119,9 +117,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); m_st.reset(); m_imp->collect_statistics(m_st); diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index ca8a36844..2e78574ec 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -1211,16 +1211,12 @@ namespace qe { void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ expr_dependency_ref & core) { + /* out */ goal_ref_buffer & result) { tactic_report report("qsat-tactic", *in); ptr_vector fmls; expr_ref_vector defs(m); expr_ref fml(m); - core = 0; in->get_formulas(fmls); - - fml = mk_and(m, fmls.size(), fmls.c_ptr()); // for now: diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index d391eddd0..3f5744556 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -61,7 +61,6 @@ class inc_sat_solver : public solver { model_converter_ref m_mc; model_converter_ref m_mc0; model_converter_ref m_sat_mc; - expr_dependency_ref m_dep_core; svector m_weights; std::string m_unknown; // access formulas after they have been pre-processed and handled by the sat solver. @@ -82,7 +81,6 @@ public: m_core(m), m_map(m), m_num_scopes(0), - m_dep_core(m), m_unknown("no reason given"), m_internalized(false), m_internalized_converted(false), @@ -495,7 +493,6 @@ private: lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm, bool is_lemma) { m_mc.reset(); m_pc.reset(); - m_dep_core.reset(); m_subgoals.reset(); init_preprocess(); SASSERT(g->models_enabled()); @@ -505,7 +502,7 @@ private: SASSERT(!g->proofs_enabled()); TRACE("sat", g->display(tout);); try { - (*m_preprocess)(g, m_subgoals, m_dep_core); + (*m_preprocess)(g, m_subgoals); } catch (tactic_exception & ex) { IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 413dfa9bf..a708f99bf 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -39,9 +39,7 @@ class sat_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + goal_ref_buffer & result) { fail_if_proof_generation("sat", g); bool produce_models = g->models_enabled(); bool produce_core = g->unsat_core_enabled(); @@ -175,12 +173,11 @@ public: } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { imp proc(g->m(), m_params); scoped_set_imp set(this, &proc); try { - proc(g, result, core); + proc(g, result); proc.m_solver.collect_statistics(m_stats); } catch (sat::solver_exception & ex) { diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index d504a63b2..b2385b971 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -70,10 +70,8 @@ public: virtual void reset_statistics() { m_num_steps = 0; } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { - core = 0; reduce(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 2bb68d590..dc927e9f3 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -145,11 +145,9 @@ public: virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { IF_VERBOSE(10, verbose_stream() << "(smt.tactic start)\n";); - core = 0; SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " " diff --git a/src/smt/tactic/unit_subsumption_tactic.cpp b/src/smt/tactic/unit_subsumption_tactic.cpp index 0b900426b..5258f8711 100644 --- a/src/smt/tactic/unit_subsumption_tactic.cpp +++ b/src/smt/tactic/unit_subsumption_tactic.cpp @@ -40,8 +40,7 @@ struct unit_subsumption_tactic : public tactic { void cleanup() {} virtual void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ expr_dependency_ref & core) { + /* out */ goal_ref_buffer & result) { reduce_core(in, result); } diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 60a7404b6..6863c935e 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -102,9 +102,7 @@ public: } virtual void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ expr_dependency_ref & core) { - core = 0; + /* out */ goal_ref_buffer & result) { expr_ref_vector clauses(m); expr2expr_map bool2dep; ptr_vector assumptions; @@ -130,7 +128,7 @@ public: case l_false: { in->reset(); proof* pr = 0; - expr_dependency* lcore = 0; + expr_dependency_ref lcore(m); if (in->proofs_enabled()) { pr = local_solver->get_proof(); in->set(proof2proof_converter(m, pr)); @@ -138,13 +136,13 @@ public: if (in->unsat_core_enabled()) { ptr_vector core; local_solver->get_unsat_core(core); - for (unsigned i = 0; i < core.size(); ++i) { - lcore = m.mk_join(lcore, m.mk_leaf(bool2dep.find(core[i]))); + for (expr* c : core) { + lcore = m.mk_join(lcore, m.mk_leaf(bool2dep.find(c))); } } in->assert_expr(m.mk_false(), pr, lcore); result.push_back(in.get()); - core = lcore; + in->set(dependency_converter::unit(lcore)); break; } case l_undef: diff --git a/src/tactic/CMakeLists.txt b/src/tactic/CMakeLists.txt index 8e1ae8cd5..c9554b76a 100644 --- a/src/tactic/CMakeLists.txt +++ b/src/tactic/CMakeLists.txt @@ -1,5 +1,6 @@ z3_add_component(tactic SOURCES + dependency_converter.cpp equiv_proof_converter.cpp generic_model_converter.cpp goal.cpp diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index 6de44c654..606ed7d82 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -90,11 +90,8 @@ public: SASSERT(g->is_well_sorted()); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + virtual void operator()(goal_ref const & g, goal_ref_buffer & result) { fail_if_proof_generation("aig", g); - core = 0; operator()(g); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index 852eb9cc0..1449ae645 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -111,9 +111,7 @@ class add_bounds_tactic : public tactic { }; void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + goal_ref_buffer & result) { tactic_report report("add-bounds", *g); bound_manager bm(m); expr_fast_mark1 visited; @@ -159,9 +157,8 @@ public: } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(g, result, core); + goal_ref_buffer & result) { + (*m_imp)(g, result); } virtual void cleanup() { diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index d86d8dd8f..afac5b4e6 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -24,8 +24,7 @@ struct arith_bounds_tactic : public tactic { virtual void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ expr_dependency_ref & core) { + /* out */ goal_ref_buffer & result) { bounds_arith_subsumption(in, result); } diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index ec9f92a35..6349c40b2 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -53,11 +53,10 @@ public: virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { TRACE("card2bv-before", g->display(tout);); SASSERT(g->is_well_sorted()); - core = 0; result.reset(); + result.reset(); tactic_report report("card2bv", *g); th_rewriter rw1(m, m_params); pb2bv_rewriter rw2(m, m_params); diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 62b030706..704d48eac 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -223,10 +223,8 @@ class degree_shift_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; m_produce_proofs = g->proofs_enabled(); m_produce_models = g->models_enabled(); tactic_report report("degree_shift", *g); @@ -291,9 +289,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index 06966178f..bf45e1afe 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -313,11 +313,10 @@ class diff_neq_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); m_produce_models = g->models_enabled(); - core = 0; result.reset(); + result.reset(); tactic_report report("diff-neq", *g); fail_if_proof_generation("diff-neq", g); fail_if_unsat_core_generation("diff-neq", g); @@ -383,9 +382,8 @@ public: If s is not really in the difference logic fragment, then this is a NOOP. */ virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index 731ca4b5d..a287e7a83 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -152,10 +152,8 @@ public: virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("elim01", *g); diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 74bc9a5ef..50dd142e6 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -149,12 +149,8 @@ public: void updt_params(params_ref const & p) { } - virtual void operator()( - goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + virtual void operator()(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; m_trail.reset(); m_fd.reset(); m_max.reset(); diff --git a/src/tactic/arith/factor_tactic.cpp b/src/tactic/arith/factor_tactic.cpp index 1233ddf9d..3ddc8b7bf 100644 --- a/src/tactic/arith/factor_tactic.cpp +++ b/src/tactic/arith/factor_tactic.cpp @@ -257,10 +257,8 @@ class factor_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("factor", *g); bool produce_proofs = g->proofs_enabled(); @@ -311,10 +309,9 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { - (*m_imp)(in, result, core); + (*m_imp)(in, result); } catch (z3_error & ex) { throw ex; diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 16288f7ad..fe1b64e90 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -249,10 +249,8 @@ class fix_dl_var_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("fix-dl-var", *g); bool produce_proofs = g->proofs_enabled(); m_produce_models = g->models_enabled(); @@ -319,10 +317,9 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { - (*m_imp)(in, result, core); + (*m_imp)(in, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 92e6ee530..fac826811 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -1550,10 +1550,8 @@ class fm_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("fm", *g); fail_if_proof_generation("fm", g); m_produce_models = g->models_enabled(); @@ -1673,9 +1671,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } }; diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index dfff44526..4bcf24534 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -159,10 +159,8 @@ public: } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; m_01s->reset(); tactic_report report("cardinality-intro", *g); diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index cc339f74a..274c6dd40 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -188,13 +188,12 @@ class lia2pb_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("lia2pb", g); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - core = 0; result.reset(); + result.reset(); tactic_report report("lia2pb", *g); m_bm.reset(); m_rw.reset(); m_new_deps.reset(); @@ -328,10 +327,9 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { - (*m_imp)(in, result, core); + (*m_imp)(in, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 2b4783c6f..f7c985129 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -440,12 +440,11 @@ public: \return false if transformation is not possible. */ virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("nla2bv", g); fail_if_unsat_core_generation("nla2bv", g); - core = 0; result.reset(); + result.reset(); imp proc(g->m(), m_params); scoped_set_imp setter(*this, proc); diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index 955e92f1a..130b5cfe6 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -79,10 +79,7 @@ class normalize_bounds_tactic : public tactic { return false; } - void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + void operator()(goal_ref const & in, goal_ref_buffer & result) { bool produce_models = in->models_enabled(); bool produce_proofs = in->proofs_enabled(); tactic_report report("normalize-bounds", *in); @@ -166,10 +163,9 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { - (*m_imp)(in, result, core); + (*m_imp)(in, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index e06c44110..de4fa8221 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -886,14 +886,13 @@ private: } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { TRACE("pb2bv", g->display(tout);); SASSERT(g->is_well_sorted()); fail_if_proof_generation("pb2bv", g); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - core = 0; result.reset(); + result.reset(); tactic_report report("pb2bv", *g); m_bm.reset(); m_rw.reset(); m_new_deps.reset(); @@ -999,9 +998,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/arith/propagate_ineqs_tactic.cpp b/src/tactic/arith/propagate_ineqs_tactic.cpp index 58fdf14ca..926fea829 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.cpp +++ b/src/tactic/arith/propagate_ineqs_tactic.cpp @@ -52,7 +52,7 @@ public: virtual void updt_params(params_ref const & p); virtual void collect_param_descrs(param_descrs & r) {} - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, expr_dependency_ref & core); + virtual void operator()(goal_ref const & g, goal_ref_buffer & result); virtual void cleanup(); }; @@ -527,12 +527,11 @@ void propagate_ineqs_tactic::updt_params(params_ref const & p) { } void propagate_ineqs_tactic::operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("propagate-ineqs", g); fail_if_unsat_core_generation("propagate-ineqs", g); - core = 0; result.reset(); + result.reset(); goal_ref r; (*m_imp)(g.get(), r); result.push_back(r.get()); diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 0caa0194d..692d6ab6d 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -821,11 +821,9 @@ public: } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("purify-arith", *g); TRACE("purify_arith", g->display(tout);); bool produce_proofs = g->proofs_enabled(); diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index 2fde96caf..7645f34cd 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -292,13 +292,12 @@ class recover_01_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("recover-01", g); fail_if_unsat_core_generation("recover-01", g); m_produce_models = g->models_enabled(); - core = 0; result.reset(); + result.reset(); tactic_report report("recover-01", *g); bool saved = false; @@ -401,10 +400,9 @@ public: } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { - (*m_imp)(g, result, core); + (*m_imp)(g, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 7928185b3..989427ee7 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -51,9 +51,7 @@ class bit_blaster_tactic : public tactic { void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + goal_ref_buffer & result) { bool proofs_enabled = g->proofs_enabled(); if (proofs_enabled && m_blast_quant) @@ -131,10 +129,9 @@ public: } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { - (*m_imp)(g, result, core); + (*m_imp)(g, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index 9e31330fd..d23d7a308 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -379,9 +379,7 @@ class bv1_blaster_tactic : public tactic { void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + goal_ref_buffer & result) { if (!is_target(*g)) throw tactic_exception("bv1 blaster cannot be applied to goal"); @@ -453,9 +451,8 @@ public: Return a model_converter that converts any model for the updated set into a model for the old set. */ virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(g, result, core); + goal_ref_buffer & result) { + (*m_imp)(g, result); } virtual void cleanup() { diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 151b00f50..beacc52ad 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -136,9 +136,7 @@ class bv_bound_chk_tactic : public tactic { public: bv_bound_chk_tactic(ast_manager & m, params_ref const & p); virtual ~bv_bound_chk_tactic(); - void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core); + void operator()(goal_ref const & g, goal_ref_buffer & result) override; virtual tactic * translate(ast_manager & m); virtual void updt_params(params_ref const & p); void cleanup(); @@ -195,14 +193,12 @@ bv_bound_chk_tactic::~bv_bound_chk_tactic() { dealloc(m_imp); } -void bv_bound_chk_tactic::operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { +void bv_bound_chk_tactic::operator()(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("bv-bound-chk", g); fail_if_unsat_core_generation("bv-bound-chk", g); TRACE("bv-bound-chk", g->display(tout << "before:"); tout << std::endl;); - core = 0; result.reset(); + result.reset(); m_imp->operator()(g); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index e7cda8a2f..8c4ea22ad 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -39,7 +39,7 @@ public: virtual ~bv_size_reduction_tactic(); - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, expr_dependency_ref & core); + virtual void operator()(goal_ref const & g, goal_ref_buffer & result); virtual void cleanup(); }; @@ -382,12 +382,11 @@ bv_size_reduction_tactic::~bv_size_reduction_tactic() { } void bv_size_reduction_tactic::operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("bv-size-reduction", g); fail_if_unsat_core_generation("bv-size-reduction", g); - core = 0; result.reset(); + result.reset(); model_converter_ref mc; m_imp->operator()(*(g.get()), mc); g->inc_depth(); diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index 421b3e1e7..7718a9679 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -53,12 +53,11 @@ class bvarray2uf_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); tactic_report report("bvarray2uf", *g); - core = 0; result.reset(); + result.reset(); fail_if_unsat_core_generation("bvarray2uf", g); TRACE("bvarray2uf", tout << "Before: " << std::endl; g->display(tout); ); @@ -129,9 +128,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index a50658b5a..bbfbe02fd 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -116,10 +116,7 @@ public: virtual void collect_param_descrs(param_descrs & r) { } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + virtual void operator()(goal_ref const & g, goal_ref_buffer & result) { bool produce_proofs = g->proofs_enabled(); tactic_report report("dt2bv", *g); unsigned size = g->size(); diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 2d8224f42..7da9aa1ae 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -224,11 +224,8 @@ class elim_small_bv_tactic : public tactic { m_rw.cfg().updt_params(p); } - void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("elim-small-bv", *g); bool produce_proofs = g->proofs_enabled(); fail_if_proof_generation("elim-small-bv", g); @@ -286,9 +283,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index e9452dbbc..e9922b7e1 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -237,10 +237,8 @@ class max_bv_sharing_tactic : public tactic { ast_manager & m() const { return m_rw.m(); } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("max-bv-sharing", *g); bool produce_proofs = g->proofs_enabled(); @@ -297,9 +295,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index e24ae0eb2..f8c5d33c0 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -113,11 +113,8 @@ class blast_term_ite_tactic : public tactic { m_rw.cfg().updt_params(p); } - void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("blast-term-ite", *g); bool produce_proofs = g->proofs_enabled(); @@ -170,9 +167,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index e43d0c1ef..f04dd6313 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -54,14 +54,11 @@ public: virtual void updt_params(params_ref const & p) { m_params = p; m_elim_ite.updt_params(p); } virtual void collect_param_descrs(param_descrs & r) { m_elim_ite.collect_param_descrs(r); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, goal_ref_buffer& result) override { SASSERT(g->is_well_sorted()); fail_if_proof_generation("cofactor-term-ite", g); fail_if_unsat_core_generation("cofactor-term-ite", g); tactic_report report("cofactor-term-ite", *g); - core = 0; process(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index faba93dc5..85e2d6199 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -63,8 +63,7 @@ public: virtual void collect_param_descrs(param_descrs & r) {} - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - expr_dependency_ref & core) { + virtual void operator()(goal_ref const & g, goal_ref_buffer & result) { tactic_report report("collect-statistics", *g); collect_proc cp(m, m_stats); diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 1216a7556..eece6a889 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -621,9 +621,7 @@ void ctx_simplify_tactic::get_param_descrs(param_descrs & r) { } void ctx_simplify_tactic::operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + goal_ref_buffer & result) { (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index 21468d6da..bde74508e 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -55,8 +55,7 @@ public: virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core); + goal_ref_buffer & result); virtual void cleanup(); }; diff --git a/src/tactic/core/der_tactic.cpp b/src/tactic/core/der_tactic.cpp index 1b51c92e6..aa6838d0b 100644 --- a/src/tactic/core/der_tactic.cpp +++ b/src/tactic/core/der_tactic.cpp @@ -74,9 +74,7 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + goal_ref_buffer & result) { (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp index dd887a0e1..3c5f8057a 100644 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ b/src/tactic/core/distribute_forall_tactic.cpp @@ -100,14 +100,13 @@ public: } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); ast_manager & m = g->m(); bool produce_proofs = g->proofs_enabled(); rw r(m, produce_proofs); m_rw = &r; - core = 0; result.reset(); + result.reset(); tactic_report report("distribute-forall", *g); expr_ref new_curr(m); diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index c18f6cd29..caeb4c245 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -183,17 +183,11 @@ tactic * dom_simplify_tactic::translate(ast_manager & m) { return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params); } -void dom_simplify_tactic::operator()( - goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; - +void dom_simplify_tactic::operator()(goal_ref const & in, goal_ref_buffer & result) { tactic_report report("dom-simplify", *in.get()); simplify_goal(*(in.get())); in->inc_depth(); result.push_back(in.get()); - } void dom_simplify_tactic::cleanup() { diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 10a56a979..e2fbe81fa 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -137,9 +137,7 @@ public: static void get_param_descrs(param_descrs & r) {} virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core); + void operator()(goal_ref const & in, goal_ref_buffer & result) override; virtual void cleanup(); }; diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 3035a8582..e4e337e00 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -100,10 +100,8 @@ class elim_term_ite_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("elim-term-ite", *g); bool produce_proofs = g->proofs_enabled(); m_rw.cfg().m_produce_models = g->models_enabled(); @@ -160,9 +158,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index a3bb482f1..cc5402e41 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -816,9 +816,7 @@ class elim_uncnstr_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + goal_ref_buffer & result) { bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); @@ -929,9 +927,8 @@ public: } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(g, result, core); + goal_ref_buffer & result) { + (*m_imp)(g, result); report_tactic_progress(":num-elim-apps", get_num_elim_apps()); } diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp index 9c233ac1c..0f7cec782 100644 --- a/src/tactic/core/injectivity_tactic.cpp +++ b/src/tactic/core/injectivity_tactic.cpp @@ -144,10 +144,8 @@ class injectivity_tactic : public tactic { } void operator()(goal_ref const & goal, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(goal->is_well_sorted()); - core = 0; tactic_report report("injectivity", *goal); fail_if_unsat_core_generation("injectivity", goal); // TODO: Support UNSAT cores fail_if_proof_generation("injectivity", goal); @@ -269,9 +267,8 @@ public: } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_finder)(g, result, core); + goal_ref_buffer & result) { + (*m_finder)(g, result); for (unsigned i = 0; i < g->size(); ++i) { expr* curr = g->form(i); diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index 37251b8e9..c13f49b52 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -54,11 +54,9 @@ public: virtual void collect_param_descrs(param_descrs & r) { nnf::get_param_descrs(r); } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { TRACE("nnf", tout << "params: " << m_params << "\n"; g->display(tout);); SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("nnf", *g); bool produce_proofs = g->proofs_enabled(); diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index a1cf0931a..e875a0472 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -128,10 +128,8 @@ class occf_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; fail_if_proof_generation("occf", g); @@ -209,9 +207,8 @@ public: virtual void collect_param_descrs(param_descrs & r) {} virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index e622eb9a3..4ed55b0d2 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -147,12 +147,10 @@ public: return alloc(pb_preprocess_tactic, m); } - virtual void operator()( + void operator()( goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) override { SASSERT(g->is_well_sorted()); - core = 0; if (g->proofs_enabled()) { throw tactic_exception("pb-preprocess does not support proofs"); diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 12a14f5a6..45ff6250a 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -136,10 +136,8 @@ class propagate_values_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("propagate-values", *g); m_goal = g.get(); @@ -238,11 +236,9 @@ public: r.insert("max_rounds", CPK_UINT, "(default: 2) maximum number of rounds."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer & result) override { try { - (*m_imp)(in, result, core); + (*m_imp)(in, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index 25f0a8f36..1e7baa14f 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -73,8 +73,8 @@ public: virtual ~reduce_args_tactic(); - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, expr_dependency_ref & core); - virtual void cleanup(); + void operator()(goal_ref const & g, goal_ref_buffer & result) override; + void cleanup() override; }; tactic * mk_reduce_args_tactic(ast_manager & m, params_ref const & p) { @@ -483,12 +483,11 @@ reduce_args_tactic::~reduce_args_tactic() { } void reduce_args_tactic::operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); fail_if_proof_generation("reduce-args", g); fail_if_unsat_core_generation("reduce-args", g); - core = 0; result.reset(); + result.reset(); m_imp->operator()(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/simplify_tactic.cpp b/src/tactic/core/simplify_tactic.cpp index a8278c383..93495922b 100644 --- a/src/tactic/core/simplify_tactic.cpp +++ b/src/tactic/core/simplify_tactic.cpp @@ -93,13 +93,11 @@ void simplify_tactic::get_param_descrs(param_descrs & r) { } void simplify_tactic::operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); - core = 0; } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/core/simplify_tactic.h b/src/tactic/core/simplify_tactic.h index 282feda0f..872eb6bab 100644 --- a/src/tactic/core/simplify_tactic.h +++ b/src/tactic/core/simplify_tactic.h @@ -30,19 +30,19 @@ public: simplify_tactic(ast_manager & m, params_ref const & ref = params_ref()); virtual ~simplify_tactic(); - virtual void updt_params(params_ref const & p); + void updt_params(params_ref const & p) override; + static void get_param_descrs(param_descrs & r); - virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core); + void collect_param_descrs(param_descrs & r) override { get_param_descrs(r); } - virtual void cleanup(); + void operator()(goal_ref const & in, goal_ref_buffer & result) override; + + void cleanup() override; unsigned get_num_steps() const; - virtual tactic * translate(ast_manager & m) { return alloc(simplify_tactic, m, m_params); } + tactic * translate(ast_manager & m) override { return alloc(simplify_tactic, m, m_params); } }; diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index fec0edd81..22b87d60e 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -666,11 +666,8 @@ class solve_eqs_tactic : public tactic { return m_num_eliminated_vars; } - void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; model_converter_ref mc; tactic_report report("solve_eqs", *g); m_produce_models = g->models_enabled(); @@ -732,10 +729,9 @@ public: r.insert("ite_solver", CPK_BOOL, "(default: true) use if-then-else solver."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + void operator()(goal_ref const & in, + goal_ref_buffer & result) override { + (*m_imp)(in, result); report_tactic_progress(":num-elim-vars", m_imp->get_num_eliminated_vars()); } diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index 60dbdd568..4f0edf797 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -101,12 +101,10 @@ public: } void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) override { + goal_ref_buffer & result) override { SASSERT(in->is_well_sorted()); tactic_report report("split-clause", *in); TRACE("before_split_clause", in->display(tout);); - core = 0; ast_manager & m = in->m(); unsigned cls_pos = select_clause(m, in); if (cls_pos == UINT_MAX) { @@ -129,6 +127,7 @@ public: result.push_back(subgoal_i); } in->set(concat(in->pc(), result.size(), result.c_ptr())); + in->add(dependency_converter::concat(result.size(), result.c_ptr())); } virtual void cleanup() { diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index 920521e0c..cf48a8a09 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -39,8 +39,7 @@ public: virtual ~symmetry_reduce_tactic(); virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core); + goal_ref_buffer & result); virtual void cleanup(); }; @@ -633,11 +632,10 @@ symmetry_reduce_tactic::~symmetry_reduce_tactic() { } void symmetry_reduce_tactic::operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { fail_if_proof_generation("symmetry_reduce", g); fail_if_unsat_core_generation("symmetry_reduce", g); - core = 0; result.reset(); + result.reset(); (*m_imp)(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index 11b7ceb8c..91f974eb9 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -799,10 +799,8 @@ class tseitin_cnf_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("tseitin-cnf", *g); fail_if_proof_generation("tseitin-cnf", g); m_produce_models = g->models_enabled(); @@ -880,9 +878,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); report_tactic_progress(":cnf-aux-vars", m_imp->m_num_aux_vars); } diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 3ed9f9cb0..9a0579346 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -47,14 +47,13 @@ class fpa2bv_tactic : public tactic { } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); m_proofs_enabled = g->proofs_enabled(); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - core = 0; result.reset(); + result.reset(); tactic_report report("fpa2bv", *g); m_rw.reset(); @@ -138,10 +137,9 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { try { - (*m_imp)(in, result, core); + (*m_imp)(in, result); } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 778c3804b..c7b730099 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -107,6 +107,7 @@ void goal::copy_to(goal & target) const { target.m_precision = mk_union(prec(), target.prec()); target.m_mc = m_mc.get(); target.m_pc = m_pc.get(); + target.m_dc = m_dc.get(); } void goal::push_back(expr * f, proof * pr, expr_dependency * d) { @@ -655,6 +656,7 @@ goal * goal::translate(ast_translation & translator) const { res->m_precision = m_precision; res->m_pc = m_pc ? m_pc->translate(translator) : nullptr; res->m_mc = m_mc ? m_mc->translate(translator) : nullptr; + res->m_dc = m_dc ? m_dc->translate(translator) : nullptr; return res; } diff --git a/src/tactic/goal.h b/src/tactic/goal.h index 73fbb6f17..06c51b4b6 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -37,6 +37,7 @@ Revision History: #include "util/ref_buffer.h" #include "tactic/model_converter.h" #include "tactic/proof_converter.h" +#include "tactic/dependency_converter.h" class goal { public: @@ -53,6 +54,7 @@ protected: ast_manager & m_manager; model_converter_ref m_mc; proof_converter_ref m_pc; + dependency_converter_ref m_dc; unsigned m_ref_count; expr_array m_forms; expr_array m_proofs; @@ -147,10 +149,13 @@ public: bool is_decided() const; bool is_well_sorted() const; + dependency_converter* dc() { return m_dc.get(); } model_converter* mc() { return m_mc.get(); } proof_converter* pc() { return inconsistent() ? proof2proof_converter(m(), pr(0)) : m_pc.get(); } + void add(dependency_converter* d) { m_dc = dependency_converter::concat(m_dc.get(), d); } void add(model_converter* m) { m_mc = concat(m_mc.get(), m); } void add(proof_converter* p) { m_pc = concat(m_pc.get(), p); } + void set(dependency_converter* d) { m_dc = d; } void set(model_converter* m) { m_mc = m; } void set(proof_converter* p) { m_pc = p; } diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index 7069e868e..c768a0cae 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -15,6 +15,42 @@ Author: Notes: + A model converter, mc, can be used to convert a model for one + of a generated subgoal into a model for an initial goal or solver state. + For a goal or solver state that is decided, a model converter can be + a simple wrapper around a model. + + Logically, given a formula F and subgoal formula F_s a model converter mc + for F_s relative to F has the property: + + m |= F_s iff mc(m) |= F for every model m + + For the evaluator associated with models, m, we expect + + eval(m)(F_s) <=> eval(mc(m))(F) + + This property holds for both eval, that decides on a fixed value + for constants that have no interpretation in m and for 'peval' + (partial eval) that retuns just the constants that are unfixed. + (in the model evaluator one can control this behavior using a + configuration flag) + + and more generally over the eval method have: + + G => F_s iff peval(mc(e))(G) => F for every formula G + + + where e is the empty model (a model that does not evaluate any + + When a model converter supports application to a formula it satisfies + the following property: + + mc(G) & F_s is SAT iff G & F is SAT + + For a model converter that is a sequence of definitions and removals + of functions we can obtain mc(G) by adding back or expanding definitinos + that are required to interpret G fully in the context of F_s. + --*/ #ifndef MODEL_CONVERTER_H_ #define MODEL_CONVERTER_H_ diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index abb8df188..8e14d77e2 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -541,7 +541,7 @@ public: init(); } - void operator ()(const goal_ref & g,goal_ref_buffer & result, expr_dependency_ref & dep) { + void operator ()(const goal_ref & g,goal_ref_buffer & result) { ast_manager& m = g->m(); solver* s = mk_fd_solver(m, m_params); solver_state* st = alloc(solver_state, 0, s, m_params, cube_task); diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 532169d46..7099f0fdf 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -46,11 +46,7 @@ public: virtual void collect_param_descrs(param_descrs & r) { } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; - + void operator()(goal_ref const & g, goal_ref_buffer& result) override { TRACE("sine", g->display(tout);); TRACE("sine", tout << g->size();); ptr_vector new_forms; diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index 18328f0b8..2fb0d4269 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -60,10 +60,9 @@ public: } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; result.reset(); + result.reset(); TRACE("sls", g->display(tout);); tactic_report report("sls", *g); diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index 84d445f45..7e64b9c2c 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -54,8 +54,7 @@ public: virtual ~qfufbv_ackr_tactic() { } virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { ast_manager& m(g->m()); tactic_report report("qfufbv_ackr", *g); fail_if_unsat_core_generation("qfufbv_ackr", g); diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index ed78f229d..c4ae3e106 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -67,12 +67,8 @@ void report_tactic_progress(char const * id, unsigned val) { } } -void skip_tactic::operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - result.reset(); +void skip_tactic::operator()(goal_ref const & in, goal_ref_buffer& result) { result.push_back(in.get()); - core = 0; } tactic * mk_skip_tactic() { @@ -81,9 +77,7 @@ tactic * mk_skip_tactic() { class fail_tactic : public tactic { public: - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer & result) override { throw tactic_exception("fail tactic"); } @@ -102,11 +96,9 @@ class report_verbose_tactic : public skip_tactic { public: report_verbose_tactic(char const * msg, unsigned lvl) : m_msg(msg), m_lvl(lvl) {} - void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) override { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { IF_VERBOSE(m_lvl, verbose_stream() << m_msg << "\n";); - skip_tactic::operator()(in, result, core); + skip_tactic::operator()(in, result); } }; @@ -119,12 +111,10 @@ class trace_tactic : public skip_tactic { public: trace_tactic(char const * tag): m_tag(tag) {} - void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) override { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { TRACE(m_tag, in->display(tout);); (void)m_tag; - skip_tactic::operator()(in, result, core); + skip_tactic::operator()(in, result); } }; @@ -136,12 +126,10 @@ class fail_if_undecided_tactic : public skip_tactic { public: fail_if_undecided_tactic() {} - void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) override { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { if (!in->is_decided()) throw tactic_exception("undecided"); - skip_tactic::operator()(in, result, core); + skip_tactic::operator()(in, result); } }; @@ -149,10 +137,10 @@ tactic * mk_fail_if_undecided_tactic() { return alloc(fail_if_undecided_tactic); } -void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, expr_dependency_ref & core) { +void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result) { t.reset_statistics(); try { - t(in, result, core); + t(in, result); t.cleanup(); } catch (tactic_exception & ex) { @@ -173,7 +161,7 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p ast_manager & m = g->m(); goal_ref_buffer r; try { - exec(t, g, r, core); + exec(t, g, r); } catch (tactic_exception & ex) { reason_unknown = ex.msg(); diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 98c57f12c..c9b5a23fd 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -61,9 +61,7 @@ public: Therefore, in most cases, pc == 0 and core == 0 for non-branching tactics. */ - virtual void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ expr_dependency_ref & core) = 0; + virtual void operator()(goal_ref const & in, goal_ref_buffer& result) = 0; virtual void collect_statistics(statistics & st) const {} virtual void reset_statistics() {} @@ -103,7 +101,7 @@ void report_tactic_progress(char const * id, unsigned val); class skip_tactic : public tactic { public: - void operator()(goal_ref const & in, goal_ref_buffer & result, expr_dependency_ref & core) override; + void operator()(goal_ref const & in, goal_ref_buffer& result) override; void cleanup() override {} tactic * translate(ast_manager & m) override { return this; } }; @@ -136,7 +134,7 @@ public: #define MK_SIMPLE_TACTIC_FACTORY(NAME, ST) MK_TACTIC_FACTORY(NAME, return ST;) -void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result, expr_dependency_ref & core); +void exec(tactic & t, goal_ref const & in, goal_ref_buffer & result); lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, proof_ref & pr, expr_dependency_ref & core, std::string & reason_unknown); // Throws an exception if goal \c in requires proof generation. diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 5003a4f9d..96979a3ff 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -101,59 +101,45 @@ public: and_then_tactical(tactic * t1, tactic * t2):binary_tactical(t1, t2) {} virtual ~and_then_tactical() {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { bool models_enabled = in->models_enabled(); bool proofs_enabled = in->proofs_enabled(); bool cores_enabled = in->unsat_core_enabled(); - ast_manager & m = in->m(); - goal_ref_buffer r1; - expr_dependency_ref core1(m); - result.reset(); - core = 0; - m_t1->operator()(in, r1, core1); - SASSERT(!is_decided(r1) || !core1); // the pc and core of decided goals is 0 + ast_manager & m = in->m(); + goal_ref_buffer r1; + m_t1->operator()(in, r1); unsigned r1_size = r1.size(); - SASSERT(r1_size > 0); + SASSERT(r1_size > 0); if (r1_size == 1) { if (r1[0]->is_decided()) { result.push_back(r1[0]); - return; + return; } goal_ref r1_0 = r1[0]; - m_t2->operator()(r1_0, result, core); - if (cores_enabled) core = m.mk_join(core1.get(), core); + m_t2->operator()(r1_0, result); } else { - if (cores_enabled) core = core1; - goal_ref_buffer r2; + goal_ref_buffer r2; for (unsigned i = 0; i < r1_size; i++) { - goal_ref g = r1[i]; - r2.reset(); - expr_dependency_ref core2(m); - m_t2->operator()(g, r2, core2); + goal_ref g = r1[i]; + r2.reset(); + m_t2->operator()(g, r2); if (is_decided(r2)) { SASSERT(r2.size() == 1); if (is_decided_sat(r2)) { - // found solution... + // found solution... + result.reset(); result.push_back(r2[0]); - SASSERT(!core); - return; + return; } else { SASSERT(is_decided_unsat(r2)); - // the proof and unsat core of a decided_unsat goal are stored in the node itself. - // core2 must be 0. - SASSERT(!core2); - if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); } } else { result.append(r2.size(), r2.c_ptr()); - if (cores_enabled) core = m.mk_join(core.get(), core2.get()); } } @@ -162,17 +148,16 @@ public: // create an decided_unsat goal with the proof in->reset_all(); proof_ref pr(m); + expr_dependency_ref core(m); if (proofs_enabled) { apply(m, in->pc(), pr); } - SASSERT(cores_enabled || core == 0); + dependency_converter* dc = in->dc(); + if (cores_enabled && dc) { + core = (*dc)(); + } in->assert_expr(m.mk_false(), pr, core); - core = 0; result.push_back(in.get()); - SASSERT(!core); - } - else { - SASSERT(cores_enabled || core == 0); } } } @@ -300,30 +285,24 @@ public: virtual ~or_else_tactical() {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + virtual void operator()(goal_ref const & in, goal_ref_buffer& result) { goal orig(*(in.get())); - proof_converter_ref pc = in->pc(); unsigned sz = m_ts.size(); unsigned i; for (i = 0; i < sz; i++) { tactic * t = m_ts[i]; - result.reset(); - pc = 0; - core = 0; SASSERT(sz > 0); if (i < sz - 1) { try { - t->operator()(in, result, core); + t->operator()(in, result); return; } catch (tactic_exception &) { - in->set(pc.get()); + result.reset(); } } else { - t->operator()(in, result, core); + t->operator()(in, result); return; } in->reset_all(); @@ -398,9 +377,7 @@ public: - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { bool use_seq; #ifdef _NO_OMP_ use_seq = true; @@ -409,7 +386,7 @@ public: #endif if (use_seq) { // execute tasks sequentially - or_else_tactical::operator()(in, result, core); + or_else_tactical::operator()(in, result); return; } @@ -437,13 +414,12 @@ public: #pragma omp parallel for for (int i = 0; i < static_cast(sz); i++) { goal_ref_buffer _result; - expr_dependency_ref _core(*(managers[i])); goal_ref in_copy = in_copies[i]; tactic & t = *(ts.get(i)); try { - t(in_copy, _result, _core); + t(in_copy, _result); bool first = false; #pragma omp critical (par_tactical) { @@ -462,8 +438,8 @@ public: for (goal* g : _result) { result.push_back(g->translate(translator)); } - expr_dependency_translation td(translator); - core = td(_core); + goal_ref in2(in_copy->translate(translator)); + in->copy_from(*(in2.get())); } } catch (tactic_exception & ex) { @@ -522,9 +498,7 @@ public: par_and_then_tactical(tactic * t1, tactic * t2):and_then_tactical(t1, t2) {} virtual ~par_and_then_tactical() {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { bool use_seq; #ifdef _NO_OMP_ use_seq = true; @@ -533,7 +507,7 @@ public: #endif if (use_seq) { // execute tasks sequentially - and_then_tactical::operator()(in, result, core); + and_then_tactical::operator()(in, result); return; } @@ -544,27 +518,20 @@ public: bool cores_enabled = in->unsat_core_enabled(); ast_manager & m = in->m(); - goal_ref_buffer r1; - expr_dependency_ref core1(m); - result.reset(); - core = 0; - m_t1->operator()(in, r1, core1); - SASSERT(!is_decided(r1) || !core1); // the core of decided goals is 0 - unsigned r1_size = r1.size(); + goal_ref_buffer r1; + m_t1->operator()(in, r1); + unsigned r1_size = r1.size(); SASSERT(r1_size > 0); if (r1_size == 1) { // Only one subgoal created... no need for parallelism if (r1[0]->is_decided()) { - result.push_back(r1[0]); - SASSERT(!core); - return; + result.push_back(r1[0]); + return; } goal_ref r1_0 = r1[0]; - m_t2->operator()(r1_0, result, core); - if (cores_enabled) core = m.mk_join(core1.get(), core); + m_t2->operator()(r1_0, result); } else { - if (cores_enabled) core = core1; scoped_ptr_vector managers; tactic_ref_vector ts2; @@ -596,12 +563,11 @@ public: goal_ref new_g = g_copies[i]; goal_ref_buffer r2; - expr_dependency_ref core2(new_m); bool curr_failed = false; try { - ts2[i]->operator()(new_g, r2, core2); + ts2[i]->operator()(new_g, r2); } catch (tactic_exception & ex) { #pragma omp critical (par_and_then_tactical) @@ -667,14 +633,10 @@ public: ast_translation translator(new_m, m, false); SASSERT(r2.size() == 1); result.push_back(r2[0]->translate(translator)); - SASSERT(!core); } } else { SASSERT(is_decided_unsat(r2)); - // the proof and unsat core of a decided_unsat goal are stored in the node itself. - // core2 must be 0. - SASSERT(!core2); if (cores_enabled && r2[0]->dep(0) != 0) { expr_dependency_ref * new_dep = alloc(expr_dependency_ref, new_m); @@ -687,9 +649,10 @@ public: goal_ref_buffer * new_r2 = alloc(goal_ref_buffer); goals_vect.set(i, new_r2); new_r2->append(r2.size(), r2.c_ptr()); - if (cores_enabled && core2 != 0) { + dependency_converter* dc = r1[i]->dc(); + if (cores_enabled && dc) { expr_dependency_ref * new_dep = alloc(expr_dependency_ref, new_m); - *new_dep = core2; + *new_dep = (*dc)(); core_buffer.set(i, new_dep); } } @@ -707,8 +670,8 @@ public: if (found_solution) return; - - core = 0; + + expr_dependency_ref core(m); for (unsigned i = 0; i < r1_size; i++) { ast_translation translator(*(managers[i]), m, false); goal_ref_buffer * r = goals_vect[i]; @@ -730,7 +693,9 @@ public: core = m.mk_join(curr_core, core); } } - + if (core) { + in->add(dependency_converter::unit(core)); + } if (result.empty()) { // all subgoals were shown to be unsat. @@ -740,14 +705,12 @@ public: if (proofs_enabled) { apply(m, in->pc(), pr); } - SASSERT(cores_enabled || core == 0); + dependency_converter* dc = in->dc(); + if (cores_enabled && dc) { + core = (*dc)(); + } in->assert_expr(m.mk_false(), pr, core); - core = 0; result.push_back(in.get()); - SASSERT(!core); - } - else { - SASSERT(cores_enabled || core == 0); } } } @@ -786,10 +749,8 @@ public: virtual ~unary_tactical() { } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - m_t->operator()(in, result, core); + void operator()(goal_ref const & in, goal_ref_buffer& result) override { + m_t->operator()(in, result); } virtual void cleanup(void) { m_t->cleanup(); } @@ -814,12 +775,10 @@ class repeat_tactical : public unary_tactical { void operator()(unsigned depth, goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer& result) { // TODO: implement a non-recursive version. if (depth > m_max_depth) { result.push_back(in.get()); - core = 0; return; } @@ -828,17 +787,14 @@ class repeat_tactical : public unary_tactical { bool cores_enabled = in->unsat_core_enabled(); ast_manager & m = in->m(); - goal_ref_buffer r1; - expr_dependency_ref core1(m); - result.reset(); - core = 0; + goal_ref_buffer r1; + result.reset(); { goal orig_in(in->m(), proofs_enabled, models_enabled, cores_enabled); orig_in.copy_from(*(in.get())); - m_t->operator()(in, r1, core1); + m_t->operator()(in, r1); if (r1.size() == 1 && is_equal(orig_in, *(r1[0]))) { result.push_back(r1[0]); - if (cores_enabled) core = core1; return; } } @@ -847,38 +803,30 @@ class repeat_tactical : public unary_tactical { if (r1_size == 1) { if (r1[0]->is_decided()) { result.push_back(r1[0]); - SASSERT(!core); return; } goal_ref r1_0 = r1[0]; - operator()(depth+1, r1_0, result, core); - if (cores_enabled) core = m.mk_join(core1.get(), core); + operator()(depth+1, r1_0, result); } else { - if (cores_enabled) core = core1; goal_ref_buffer r2; for (unsigned i = 0; i < r1_size; i++) { goal_ref g = r1[i]; r2.reset(); - expr_dependency_ref core2(m); - operator()(depth+1, g, r2, core2); + operator()(depth+1, g, r2); if (is_decided(r2)) { SASSERT(r2.size() == 1); if (is_decided_sat(r2)) { // found solution... result.push_back(r2[0]); - SASSERT(!core); return; } else { SASSERT(is_decided_unsat(r2)); - SASSERT(!core2); - if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); } } else { result.append(r2.size(), r2.c_ptr()); - if (cores_enabled) core = m.mk_join(core.get(), core2.get()); } } @@ -887,17 +835,15 @@ class repeat_tactical : public unary_tactical { // create an decided_unsat goal with the proof in->reset_all(); proof_ref pr(m); + expr_dependency_ref core(m); if (proofs_enabled) { apply(m, in->pc(), pr); } - SASSERT(cores_enabled || core == 0); + if (cores_enabled && in->dc()) { + core = (*in->dc())(); + } in->assert_expr(m.mk_false(), pr, core); - core = 0; result.push_back(in.get()); - SASSERT(!core); - } - else { - SASSERT(cores_enabled || core == 0); } } } @@ -908,10 +854,8 @@ public: m_max_depth(max_depth) { } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - operator()(0, in, result, core); + void operator()(goal_ref const & in, goal_ref_buffer& result) override { + operator()(0, in, result); } virtual tactic * translate(ast_manager & m) { @@ -929,13 +873,10 @@ class fail_if_branching_tactical : public unary_tactical { public: fail_if_branching_tactical(tactic * t, unsigned threshold):unary_tactical(t), m_threshold(threshold) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - m_t->operator()(in, result, core); + void operator()(goal_ref const & in, goal_ref_buffer& result) override { + m_t->operator()(in, result); if (result.size() > m_threshold) { - result.reset(); - core = 0; + result.reset(); // assumes in is not strenthened to one of the branches throw tactic_exception("failed-if-branching tactical"); } }; @@ -954,10 +895,8 @@ class cleanup_tactical : public unary_tactical { public: cleanup_tactical(tactic * t):unary_tactical(t) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - m_t->operator()(in, result, core); + void operator()(goal_ref const & in, goal_ref_buffer& result) override { + m_t->operator()(in, result); m_t->cleanup(); } @@ -976,14 +915,12 @@ class try_for_tactical : public unary_tactical { public: try_for_tactical(tactic * t, unsigned ts):unary_tactical(t), m_timeout(ts) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { cancel_eh eh(in->m().limit()); { // Warning: scoped_timer is not thread safe in Linux. scoped_timer timer(m_timeout, &eh); - m_t->operator()(in, result, core); + m_t->operator()(in, result); } } @@ -1044,11 +981,9 @@ public: annotate_tactical(char const* name, tactic* t): unary_tactical(t), m_name(name) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { scope _scope(m_name); - m_t->operator()(in, result, core); + m_t->operator()(in, result); } virtual tactic * translate(ast_manager & m) { @@ -1073,13 +1008,11 @@ public: virtual ~cond_tactical() {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer & result) override { if (m_p->operator()(*(in.get())).is_true()) - m_t1->operator()(in, result, core); + m_t1->operator()(in, result); else - m_t2->operator()(in, result, core); + m_t2->operator()(in, result); } virtual tactic * translate(ast_manager & m) { @@ -1109,10 +1042,7 @@ public: void cleanup() {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - core = 0; + void operator()(goal_ref const & in, goal_ref_buffer& result) override { if (m_p->operator()(*(in.get())).is_true()) { throw tactic_exception("fail-if tactic"); } @@ -1136,16 +1066,12 @@ class if_no_proofs_tactical : public unary_tactical { public: if_no_proofs_tactical(tactic * t):unary_tactical(t) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer & result) override { if (in->proofs_enabled()) { - core = 0; - result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, core); + m_t->operator()(in, result); } } @@ -1156,16 +1082,12 @@ class if_no_unsat_cores_tactical : public unary_tactical { public: if_no_unsat_cores_tactical(tactic * t):unary_tactical(t) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { if (in->unsat_core_enabled()) { - core = 0; - result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, core); + m_t->operator()(in, result); } } @@ -1176,16 +1098,12 @@ class if_no_models_tactical : public unary_tactical { public: if_no_models_tactical(tactic * t):unary_tactical(t) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { if (in->models_enabled()) { - core = 0; - result.reset(); result.push_back(in.get()); } else { - m_t->operator()(in, result, core); + m_t->operator()(in, result); } } diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index fb5c7d458..efed67486 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -38,10 +38,8 @@ class macro_finder_tactic : public tactic { void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("macro-finder", *g); bool produce_proofs = g->proofs_enabled(); @@ -115,9 +113,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index 61dbcaf01..05c5bdd73 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -36,10 +36,8 @@ class quasi_macros_tactic : public tactic { void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("quasi-macros", *g); bool produce_proofs = g->proofs_enabled(); @@ -126,9 +124,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index 6b9882e29..914c874ee 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -32,10 +32,8 @@ class ufbv_rewriter_tactic : public tactic { ast_manager & m() const { return m_manager; } void operator()(goal_ref const & g, - goal_ref_buffer & result, - expr_dependency_ref & core) { + goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - core = 0; tactic_report report("ufbv-rewriter", *g); fail_if_unsat_core_generation("ufbv-rewriter", g); @@ -100,9 +98,8 @@ public: } virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - expr_dependency_ref & core) { - (*m_imp)(in, result, core); + goal_ref_buffer & result) { + (*m_imp)(in, result); } virtual void cleanup() { From 2f6283e1ed1b589d239092e53718780d39aa1c3c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 19 Nov 2017 13:06:30 -0800 Subject: [PATCH 0350/1283] add converters Signed-off-by: Nikolaj Bjorner --- src/tactic/dependency_converter.cpp | 107 ++++++++++++++++++++++++++++ src/tactic/dependency_converter.h | 47 ++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 src/tactic/dependency_converter.cpp create mode 100644 src/tactic/dependency_converter.h diff --git a/src/tactic/dependency_converter.cpp b/src/tactic/dependency_converter.cpp new file mode 100644 index 000000000..fbd445d52 --- /dev/null +++ b/src/tactic/dependency_converter.cpp @@ -0,0 +1,107 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + dependency_converter.cpp + +Abstract: + + Utility for converting dependencies across subgoals. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Notes: + + +--*/ + +#include "tactic/dependency_converter.h" +#include "tactic/goal.h" + +class unit_dependency_converter : public dependency_converter { + expr_dependency_ref m_dep; +public: + + unit_dependency_converter(expr_dependency_ref& d) : m_dep(d) {} + + virtual expr_dependency_ref operator()() { return m_dep; } + + virtual dependency_converter * translate(ast_translation & translator) { + expr_dependency_translation tr(translator); + expr_dependency_ref d(tr(m_dep), translator.to()); + return alloc(unit_dependency_converter, d); + } + + virtual void display(std::ostream& out) { + out << m_dep << "\n"; + } +}; + +class concat_dependency_converter : public dependency_converter { + dependency_converter_ref m_dc1; + dependency_converter_ref m_dc2; +public: + + concat_dependency_converter(dependency_converter* c1, dependency_converter* c2) : m_dc1(c1), m_dc2(c2) {} + + virtual expr_dependency_ref operator()() { + expr_dependency_ref d1 = (*m_dc1)(); + expr_dependency_ref d2 = (*m_dc2)(); + ast_manager& m = d1.get_manager(); + return expr_dependency_ref(m.mk_join(d1, d2), m); + } + + virtual dependency_converter * translate(ast_translation & translator) { + return alloc(concat_dependency_converter, m_dc1->translate(translator), m_dc2->translate(translator)); + } + + virtual void display(std::ostream& out) { + m_dc1->display(out); + m_dc2->display(out); + } +}; + +class goal_dependency_converter : public dependency_converter { + ast_manager& m; + goal_ref_buffer m_goals; +public: + goal_dependency_converter(unsigned n, goal * const* goals) : + m(goals[0]->m()) { + for (unsigned i = 0; i < n; ++i) m_goals.push_back(goals[i]); + } + + virtual expr_dependency_ref operator()() { + expr_dependency_ref result(m.mk_empty_dependencies(), m); + for (goal_ref g : m_goals) { + dependency_converter_ref dc = g->dc(); + if (dc) result = m.mk_join(result, (*dc)()); + } + return result; + } + virtual dependency_converter * translate(ast_translation & translator) { + goal_ref_buffer goals; + for (goal_ref g : m_goals) goals.push_back(g->translate(translator)); + return alloc(goal_dependency_converter, goals.size(), goals.c_ptr()); + } + + virtual void display(std::ostream& out) { out << "goal-dep\n"; } + +}; + +dependency_converter * dependency_converter::concat(dependency_converter * mc1, dependency_converter * mc2) { + if (!mc1) return mc2; + if (!mc2) return mc1; + return alloc(concat_dependency_converter, mc1, mc2); +} + +dependency_converter* dependency_converter::unit(expr_dependency_ref& d) { + return alloc(unit_dependency_converter, d); +} + +dependency_converter * dependency_converter::concat(unsigned n, goal * const* goals) { + if (n == 0) return nullptr; + return alloc(goal_dependency_converter, n, goals); +} diff --git a/src/tactic/dependency_converter.h b/src/tactic/dependency_converter.h new file mode 100644 index 000000000..4ea0c6672 --- /dev/null +++ b/src/tactic/dependency_converter.h @@ -0,0 +1,47 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + dependency_converter.h + +Abstract: + + Utility for converting dependencies across subgoals. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Notes: + + +--*/ +#ifndef DEPENDENCY_CONVERTER_H_ +#define DEPENDENCY_CONVERTER_H_ + +#include "util/ref.h" +#include "ast/ast_pp_util.h" +#include "model/model.h" +#include "tactic/converter.h" + +class goal; + +class dependency_converter : public converter { +public: + static dependency_converter* unit(expr_dependency_ref& d); + + static dependency_converter* concat(dependency_converter * dc1, dependency_converter * dc2); + + static dependency_converter* concat(unsigned n, goal * const* goals); + + virtual expr_dependency_ref operator()() = 0; + + virtual dependency_converter * translate(ast_translation & translator) = 0; +}; + +typedef ref dependency_converter_ref; +typedef sref_vector dependency_converter_ref_vector; +typedef sref_buffer dependency_converter_ref_buffer; + +#endif From bdbaf68f8b4960e99cc49e4b4bc3b3d0668ffcdd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 19 Nov 2017 15:21:09 -0800 Subject: [PATCH 0351/1283] adding handlers for dimacs for solver_from_file, and opb, wncf for opt_from_file, #1361 Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 26 ++- src/api/api_solver.cpp | 25 ++- src/opt/CMakeLists.txt | 1 + src/opt/opt_parse.cpp | 317 +++++++++++++++++++++++++++++++++++++ src/opt/opt_parse.h | 28 ++++ src/shell/main.cpp | 14 +- src/shell/opt_frontend.cpp | 277 +------------------------------- src/util/file_path.h | 38 +++++ 8 files changed, 431 insertions(+), 295 deletions(-) create mode 100644 src/opt/opt_parse.cpp create mode 100644 src/opt/opt_parse.h create mode 100644 src/util/file_path.h diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index a70f3f660..5ff408bb7 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -16,6 +16,9 @@ Revision History: --*/ #include +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" +#include "util/file_path.h" #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_stats.h" @@ -24,11 +27,11 @@ Revision History: #include "api/api_model.h" #include "opt/opt_context.h" #include "opt/opt_cmds.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" +#include "opt/opt_parse.h" #include "parsers/smt2/smt2parser.h" #include "api/api_ast_vector.h" + extern "C" { struct Z3_optimize_ref : public api::object { @@ -286,8 +289,19 @@ extern "C" { static void Z3_optimize_from_stream( Z3_context c, Z3_optimize opt, - std::istream& s) { - ast_manager& m = mk_c(c)->m(); + std::istream& s, + char const* ext) { + ast_manager& m = mk_c(c)->m(); + if (ext && std::string("opb") == ext) { + unsigned_vector h; + parse_opb(*to_optimize_ptr(opt), s, h); + return; + } + if (ext && std::string("wcnf") == ext) { + unsigned_vector h; + parse_wcnf(*to_optimize_ptr(opt), s, h); + return; + } scoped_ptr ctx = alloc(cmd_context, false, &m); install_opt_cmds(*ctx.get(), to_optimize_ptr(opt)); ctx->set_ignore_check(true); @@ -311,7 +325,7 @@ extern "C" { //LOG_Z3_optimize_from_string(c, d, s); std::string str(s); std::istringstream is(str); - Z3_optimize_from_stream(c, d, is); + Z3_optimize_from_stream(c, d, is, nullptr); Z3_CATCH; } @@ -327,7 +341,7 @@ extern "C" { strm << "Could not open file " << s; throw default_exception(strm.str()); } - Z3_optimize_from_stream(c, d, is); + Z3_optimize_from_stream(c, d, is, get_extension(s)); Z3_CATCH; } diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 9f13ce3c1..2455d3a81 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -29,12 +29,16 @@ Revision History: #include "util/scoped_ctrl_c.h" #include "util/cancel_eh.h" #include "util/scoped_timer.h" +#include "util/file_path.h" #include "tactic/portfolio/smt_strategic_solver.h" #include "smt/smt_solver.h" #include "smt/smt_implied_equalities.h" #include "solver/smt_logics.h" #include "cmd_context/cmd_context.h" #include "parsers/smt2/smt2parser.h" +#include "sat/dimacs.h" +#include "sat/sat_solver.h" +#include "sat/tactic/goal2sat.h" extern "C" { @@ -127,13 +131,30 @@ extern "C" { void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name) { Z3_TRY; LOG_Z3_solver_from_file(c, s, file_name); - scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); - ctx->set_ignore_check(true); + char const* ext = get_extension(file_name); std::ifstream is(file_name); if (!is) { SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); return; } + if (ext && std::string("dimacs") == ext) { + ast_manager& m = to_solver_ref(s)->get_manager(); + sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); + parse_dimacs(is, solver); + sat2goal s2g; + model_converter_ref mc; + atom2bool_var a2b(m); + goal g(m); + s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); + for (unsigned i = 0; i < g.size(); ++i) { + to_solver_ref(s)->assert_expr(g.form(i)); + } + return; + } + + scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); + ctx->set_ignore_check(true); + if (!parse_smt2_commands(*ctx.get(), is)) { ctx = nullptr; SET_ERROR_CODE(Z3_PARSER_ERROR); diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index 05a62b6c2..28a14be2e 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -6,6 +6,7 @@ z3_add_component(opt opt_cmds.cpp opt_context.cpp opt_pareto.cpp + opt_parse.cpp optsmt.cpp opt_solver.cpp pb_sls.cpp diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp new file mode 100644 index 000000000..2cba7561f --- /dev/null +++ b/src/opt/opt_parse.cpp @@ -0,0 +1,317 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + opt_parse.cpp + +Abstract: + + Parse utilities for optimization. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#include "opt/opt_context.h" +#include "opt/opt_parse.h" + + +class opt_stream_buffer { + std::istream & m_stream; + int m_val; + unsigned m_line; +public: + opt_stream_buffer(std::istream & s): + m_stream(s), + m_line(0) { + m_val = m_stream.get(); + } + int operator *() const { return m_val;} + void operator ++() { m_val = m_stream.get(); } + int ch() const { return m_val; } + void next() { m_val = m_stream.get(); } + bool eof() const { return ch() == EOF; } + unsigned line() const { return m_line; } + void skip_whitespace(); + void skip_space(); + void skip_line(); + bool parse_token(char const* token); + int parse_int(); + unsigned parse_unsigned(); +}; + + +void opt_stream_buffer::skip_whitespace() { + while ((ch() >= 9 && ch() <= 13) || ch() == 32) { + if (ch() == 10) ++m_line; + next(); + } +} + +void opt_stream_buffer::skip_space() { + while (ch() != 10 && ((ch() >= 9 && ch() <= 13) || ch() == 32)) { + next(); + } +} +void opt_stream_buffer::skip_line() { + while(true) { + if (eof()) { + return; + } + if (ch() == '\n') { + ++m_line; + next(); + return; + } + next(); + } +} + +bool opt_stream_buffer::parse_token(char const* token) { + skip_whitespace(); + char const* t = token; + while (ch() == *t) { + next(); + ++t; + } + return 0 == *t; +} + +unsigned opt_stream_buffer::parse_unsigned() { + skip_space(); + if (ch() == '\n') { + return UINT_MAX; + } + unsigned val = 0; + while (ch() >= '0' && ch() <= '9') { + val = val*10 + (ch() - '0'); + next(); + } + return val; +} + +int opt_stream_buffer::parse_int() { + int val = 0; + bool neg = false; + skip_whitespace(); + + if (ch() == '-') { + neg = true; + next(); + } + else if (ch() == '+') { + next(); + } + if (ch() < '0' || ch() > '9') { + std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\" )\n"; + exit(3); + } + while (ch() >= '0' && ch() <= '9') { + val = val*10 + (ch() - '0'); + next(); + } + return neg ? -val : val; +} + + +class wcnf { + opt::context& opt; + ast_manager& m; + opt_stream_buffer& in; + unsigned_vector& m_handles; + + app_ref read_clause(unsigned& weight) { + int parsed_lit; + int var; + weight = in.parse_unsigned(); + app_ref result(m), p(m); + expr_ref_vector ors(m); + while (true) { + parsed_lit = in.parse_int(); + if (parsed_lit == 0) + break; + var = abs(parsed_lit); + p = m.mk_const(symbol(var), m.mk_bool_sort()); + if (parsed_lit < 0) p = m.mk_not(p); + ors.push_back(p); + } + result = to_app(mk_or(m, ors.size(), ors.c_ptr())); + return result; + } + + void parse_spec(unsigned& num_vars, unsigned& num_clauses, unsigned& max_weight) { + in.parse_token("wcnf"); + num_vars = in.parse_unsigned(); + num_clauses = in.parse_unsigned(); + max_weight = in.parse_unsigned(); + } + +public: + + wcnf(opt::context& opt, opt_stream_buffer& in, unsigned_vector& h): opt(opt), m(opt.get_manager()), in(in), m_handles(h) { + opt.set_clausal(true); + } + + void parse() { + unsigned num_vars = 0, num_clauses = 0, max_weight = 0; + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == 'c') { + in.skip_line(); + } + else if (*in == 'p') { + ++in; + parse_spec(num_vars, num_clauses, max_weight); + } + else { + unsigned weight = 0; + app_ref cls = read_clause(weight); + if (weight >= max_weight) { + opt.add_hard_constraint(cls); + } + else { + unsigned id = opt.add_soft_constraint(cls, rational(weight), symbol::null); + if (m_handles.empty()) { + m_handles.push_back(id); + } + } + } + } + } +}; + + +class opb { + opt::context& opt; + ast_manager& m; + opt_stream_buffer& in; + unsigned_vector& m_handles; + arith_util arith; + + app_ref parse_id() { + bool negated = in.parse_token("~"); + if (!in.parse_token("x")) { + std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\" expected \"x\")\n"; + exit(3); + } + app_ref p(m); + int id = in.parse_int(); + p = m.mk_const(symbol(id), m.mk_bool_sort()); + if (negated) p = m.mk_not(p); + in.skip_whitespace(); + return p; + } + + app_ref parse_ids() { + app_ref result = parse_id(); + while (*in == '~' || *in == 'x') { + result = m.mk_and(result, parse_id()); + } + return result; + } + + rational parse_coeff_r() { + in.skip_whitespace(); + svector num; + bool pos = true; + if (*in == '-') pos = false, ++in; + if (*in == '+') ++in; + if (!pos) num.push_back('-'); + in.skip_whitespace(); + while ('0' <= *in && *in <='9') num.push_back(*in), ++in; + num.push_back(0); + return rational(num.c_ptr()); + } + + app_ref parse_coeff() { + return app_ref(arith.mk_numeral(parse_coeff_r(), true), m); + } + + app_ref parse_term() { + app_ref c = parse_coeff(); + app_ref e = parse_ids(); + return app_ref(m.mk_ite(e, c, arith.mk_numeral(rational(0), true)), m); + } + + void parse_objective(bool is_min) { + app_ref t = parse_term(); + while (!in.parse_token(";") && !in.eof()) { + if (is_min) { + t = arith.mk_add(t, parse_term()); + } + else { + t = arith.mk_sub(t, parse_term()); + } + } + m_handles.push_back(opt.add_objective(t, false)); + } + + void parse_constraint() { + app_ref t = parse_term(); + while (!in.eof()) { + if (in.parse_token(">=")) { + t = arith.mk_ge(t, parse_coeff()); + in.parse_token(";"); + break; + } + if (in.parse_token("=")) { + t = m.mk_eq(t, parse_coeff()); + in.parse_token(";"); + break; + } + if (in.parse_token("<=")) { + t = arith.mk_le(t, parse_coeff()); + in.parse_token(";"); + break; + } + t = arith.mk_add(t, parse_term()); + } + opt.add_hard_constraint(t); + } +public: + opb(opt::context& opt, opt_stream_buffer& in, unsigned_vector& h): + opt(opt), m(opt.get_manager()), + in(in), m_handles(h), arith(m) {} + + void parse() { + while (true) { + in.skip_whitespace(); + if (in.eof()) { + break; + } + else if (*in == '*') { + in.skip_line(); + } + else if (in.parse_token("min:")) { + parse_objective(true); + } + else if (in.parse_token("max:")) { + parse_objective(false); + } + else { + parse_constraint(); + } + } + } +}; + +void parse_wcnf(opt::context& opt, std::istream& is, unsigned_vector& h) { + opt_stream_buffer _is(is); + wcnf w(opt, _is, h); + w.parse(); +} + +void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h) { + opt_stream_buffer _is(is); + opb opb(opt, _is, h); + opb.parse(); +} + + diff --git a/src/opt/opt_parse.h b/src/opt/opt_parse.h new file mode 100644 index 000000000..b058efcac --- /dev/null +++ b/src/opt/opt_parse.h @@ -0,0 +1,28 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + opt_parse.h + +Abstract: + + Parse utilities for optimization. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#ifndef OPT_PARSE_H_ +#define OPT_PARSE_H_ + +void parse_wcnf(opt::context& opt, std::istream& is, unsigned_vector& h); + +void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h); + +#endif /* OPT_PARSE_H_ */ + + diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 3d2609c4f..fe115611c 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -33,6 +33,7 @@ Revision History: #include "util/timeout.h" #include "util/z3_exception.h" #include "util/error_codes.h" +#include "util/file_path.h" #include "util/gparams.h" #include "util/env_params.h" #include "shell/lp_frontend.h" @@ -289,19 +290,6 @@ void parse_cmd_line_args(int argc, char ** argv) { } } -char const * get_extension(char const * file_name) { - if (file_name == 0) - return 0; - char const * last_dot = 0; - for (;;) { - char const * tmp = strchr(file_name, '.'); - if (tmp == 0) { - return last_dot; - } - last_dot = tmp + 1; - file_name = last_dot; - } -} int STD_CALL main(int argc, char ** argv) { try{ diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index ce402bb29..8154cbde4 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -13,6 +13,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/gparams.h" #include "util/timeout.h" #include "ast/reg_decl_plugins.h" +#include "opt/opt_parse.h" extern bool g_display_statistics; static bool g_first_interrupt = true; @@ -20,275 +21,6 @@ static opt::context* g_opt = 0; static double g_start_time = 0; static unsigned_vector g_handles; -class opt_stream_buffer { - std::istream & m_stream; - int m_val; - unsigned m_line; -public: - opt_stream_buffer(std::istream & s): - m_stream(s), - m_line(0) { - m_val = m_stream.get(); - } - int operator *() const { return m_val;} - void operator ++() { m_val = m_stream.get(); } - int ch() const { return m_val; } - void next() { m_val = m_stream.get(); } - bool eof() const { return ch() == EOF; } - unsigned line() const { return m_line; } - void skip_whitespace() { - while ((ch() >= 9 && ch() <= 13) || ch() == 32) { - if (ch() == 10) ++m_line; - next(); - } - } - void skip_space() { - while (ch() != 10 && ((ch() >= 9 && ch() <= 13) || ch() == 32)) { - next(); - } - } - void skip_line() { - while(true) { - if (eof()) { - return; - } - if (ch() == '\n') { - ++m_line; - next(); - return; - } - next(); - } - } - - bool parse_token(char const* token) { - skip_whitespace(); - char const* t = token; - while (ch() == *t) { - next(); - ++t; - } - return 0 == *t; - } - - int parse_int() { - int val = 0; - bool neg = false; - skip_whitespace(); - - if (ch() == '-') { - neg = true; - next(); - } - else if (ch() == '+') { - next(); - } - if (ch() < '0' || ch() > '9') { - std::cerr << "(error line " << line() << " \"unexpected char: " << ((char)ch()) << "\" )\n"; - exit(3); - } - while (ch() >= '0' && ch() <= '9') { - val = val*10 + (ch() - '0'); - next(); - } - return neg ? -val : val; - } - - unsigned parse_unsigned() { - skip_space(); - if (ch() == '\n') { - return UINT_MAX; - } - unsigned val = 0; - while (ch() >= '0' && ch() <= '9') { - val = val*10 + (ch() - '0'); - next(); - } - return val; - } -}; - -class wcnf { - opt::context& opt; - ast_manager& m; - opt_stream_buffer& in; - - app_ref read_clause(unsigned& weight) { - int parsed_lit; - int var; - weight = in.parse_unsigned(); - app_ref result(m), p(m); - expr_ref_vector ors(m); - while (true) { - parsed_lit = in.parse_int(); - if (parsed_lit == 0) - break; - var = abs(parsed_lit); - p = m.mk_const(symbol(var), m.mk_bool_sort()); - if (parsed_lit < 0) p = m.mk_not(p); - ors.push_back(p); - } - result = to_app(mk_or(m, ors.size(), ors.c_ptr())); - return result; - } - - void parse_spec(unsigned& num_vars, unsigned& num_clauses, unsigned& max_weight) { - in.parse_token("wcnf"); - num_vars = in.parse_unsigned(); - num_clauses = in.parse_unsigned(); - max_weight = in.parse_unsigned(); - } - -public: - - wcnf(opt::context& opt, opt_stream_buffer& in): opt(opt), m(opt.get_manager()), in(in) { - opt.set_clausal(true); - } - - void parse() { - unsigned num_vars = 0, num_clauses = 0, max_weight = 0; - while (true) { - in.skip_whitespace(); - if (in.eof()) { - break; - } - else if (*in == 'c') { - in.skip_line(); - } - else if (*in == 'p') { - ++in; - parse_spec(num_vars, num_clauses, max_weight); - } - else { - unsigned weight = 0; - app_ref cls = read_clause(weight); - if (weight >= max_weight) { - opt.add_hard_constraint(cls); - } - else { - unsigned id = opt.add_soft_constraint(cls, rational(weight), symbol::null); - if (g_handles.empty()) { - g_handles.push_back(id); - } - } - } - } - } -}; - - -class opb { - opt::context& opt; - ast_manager& m; - opt_stream_buffer& in; - arith_util arith; - - app_ref parse_id() { - bool negated = in.parse_token("~"); - if (!in.parse_token("x")) { - std::cerr << "(error line " << in.line() << " \"unexpected char: " << ((char)in.ch()) << "\" expected \"x\")\n"; - exit(3); - } - app_ref p(m); - int id = in.parse_int(); - p = m.mk_const(symbol(id), m.mk_bool_sort()); - if (negated) p = m.mk_not(p); - in.skip_whitespace(); - return p; - } - - app_ref parse_ids() { - app_ref result = parse_id(); - while (*in == '~' || *in == 'x') { - result = m.mk_and(result, parse_id()); - } - return result; - } - - rational parse_coeff_r() { - in.skip_whitespace(); - svector num; - bool pos = true; - if (*in == '-') pos = false, ++in; - if (*in == '+') ++in; - if (!pos) num.push_back('-'); - in.skip_whitespace(); - while ('0' <= *in && *in <='9') num.push_back(*in), ++in; - num.push_back(0); - return rational(num.c_ptr()); - } - - app_ref parse_coeff() { - return app_ref(arith.mk_numeral(parse_coeff_r(), true), m); - } - - app_ref parse_term() { - app_ref c = parse_coeff(); - app_ref e = parse_ids(); - return app_ref(m.mk_ite(e, c, arith.mk_numeral(rational(0), true)), m); - } - - void parse_objective(bool is_min) { - app_ref t = parse_term(); - while (!in.parse_token(";") && !in.eof()) { - if (is_min) { - t = arith.mk_add(t, parse_term()); - } - else { - t = arith.mk_sub(t, parse_term()); - } - } - g_handles.push_back(opt.add_objective(t, false)); - } - - void parse_constraint() { - app_ref t = parse_term(); - while (!in.eof()) { - if (in.parse_token(">=")) { - t = arith.mk_ge(t, parse_coeff()); - in.parse_token(";"); - break; - } - if (in.parse_token("=")) { - t = m.mk_eq(t, parse_coeff()); - in.parse_token(";"); - break; - } - if (in.parse_token("<=")) { - t = arith.mk_le(t, parse_coeff()); - in.parse_token(";"); - break; - } - t = arith.mk_add(t, parse_term()); - } - opt.add_hard_constraint(t); - } -public: - opb(opt::context& opt, opt_stream_buffer& in): - opt(opt), m(opt.get_manager()), - in(in), arith(m) {} - - void parse() { - while (true) { - in.skip_whitespace(); - if (in.eof()) { - break; - } - else if (*in == '*') { - in.skip_line(); - } - else if (in.parse_token("min:")) { - parse_objective(true); - } - else if (in.parse_token("max:")) { - parse_objective(false); - } - else { - parse_constraint(); - } - } - } -}; static void display_results() { @@ -348,14 +80,11 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { g_opt = &opt; params_ref p = gparams::get_module("opt"); opt.updt_params(p); - opt_stream_buffer _in(in); if (is_wcnf) { - wcnf wcnf(opt, _in); - wcnf.parse(); + parse_wcnf(opt, in, g_handles); } else { - opb opb(opt, _in); - opb.parse(); + parse_opb(opt, in, g_handles); } try { lbool r = opt.optimize(); diff --git a/src/util/file_path.h b/src/util/file_path.h new file mode 100644 index 000000000..8a2d053d8 --- /dev/null +++ b/src/util/file_path.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + file_path.h + +Abstract: + + File path functions. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-11-19 + +Revision History: + +--*/ +#ifndef FILE_PATH_H_ +#define FILE_PATH_H_ + +inline char const * get_extension(char const * file_name) { + if (file_name == 0) + return 0; + char const * last_dot = 0; + for (;;) { + char const * tmp = strchr(file_name, '.'); + if (tmp == 0) { + return last_dot; + } + last_dot = tmp + 1; + file_name = last_dot; + } +} + +#endif /* FILE_PATH_H_ */ + + From 92cd92e690d095e5f378ea8beaef765fc771c563 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 20 Nov 2017 12:09:37 -0800 Subject: [PATCH 0352/1283] expose probing configuration parameters Signed-off-by: Nikolaj Bjorner --- src/sat/sat_probing.cpp | 14 ++++++++------ src/sat/sat_simplifier_params.pyg | 7 ++++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index cafc5e3bb..fe4691660 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -19,6 +19,7 @@ Revision History: --*/ #include "sat/sat_probing.h" #include "sat/sat_solver.h" +#include "sat/sat_simplifier_params.hpp" namespace sat { probing::probing(solver & _s, params_ref const & p): @@ -238,12 +239,13 @@ namespace sat { return r; } - void probing::updt_params(params_ref const & p) { - m_probing = p.get_bool("probing", true); - m_probing_limit = p.get_uint("probing_limit", 5000000); - m_probing_cache = p.get_bool("probing_cache", true); - m_probing_binary = p.get_bool("probing_binary", true); - m_probing_cache_limit = megabytes_to_bytes(p.get_uint("probing_chache_limit", 1024)); + void probing::updt_params(params_ref const & _p) { + sat_simplifier_params p(_p); + m_probing = p.probing(); + m_probing_limit = p.probing_limit(); + m_probing_cache = p.probing_cache(); + m_probing_binary = p.probing_binary(); + m_probing_cache_limit = p.probing_cache_limit(); } void probing::collect_param_descrs(param_descrs & d) { diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index a8f0db724..b78980774 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -23,6 +23,11 @@ def_module_params(module_name='sat', ('resolution.cls_cutoff2', UINT, 700000000, 'limit2 - total number of problems clauses for the second cutoff of Boolean variable elimination'), ('elim_vars', BOOL, True, 'enable variable elimination using resolution during simplification'), ('elim_vars_bdd', BOOL, True, 'enable variable elimination using BDD recompilation during simplification'), - ('elim_vars_bdd_delay', UINT, 3, 'delay elimination of variables using BDDs until after simplification round'), + ('elim_vars_bdd_delay', UINT, 3, 'delay elimination of variables using BDDs until after simplification round'), + ('probing', BOOL, True, 'apply failed literal detection during simplification'), + ('probing_limit', UINT, 5000000, 'limit to the number of probe calls'), + ('probing_cache', BOOL, True, 'add binary literals as lemmas'), + ('probing_cache_limit', UINT, 1024, 'cache binaries unless overall memory usage exceeds cache limit'), + ('probing_binary', BOOL, True, 'probe binary clauses'), ('subsumption', BOOL, True, 'eliminate subsumed clauses'), ('subsumption.limit', UINT, 100000000, 'approx. maximum number of literals visited during subsumption (and subsumption resolution)'))) From 773d938925c6be6c7afc7ff1a4c861c45a3b55b9 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Tue, 21 Nov 2017 13:24:14 -0800 Subject: [PATCH 0353/1283] re-adding simplified constraints based on model converter Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/tactic/goal2sat.cpp | 34 ++++++++++++++++++++++++-- src/tactic/generic_model_converter.cpp | 2 +- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 7c703653c..dc4200349 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -885,7 +885,8 @@ struct sat2goal::imp { sat::model_converter m_mc; expr_ref_vector m_var2expr; generic_model_converter_ref m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion - + generic_model_converter_ref m_imc; // used to ensure correctness in incremental calls with simplifications that require model conversions + sat_model_converter(ast_manager & m): m_var2expr(m) { } @@ -894,6 +895,7 @@ struct sat2goal::imp { sat_model_converter(ast_manager & m, sat::solver const & s):m_var2expr(m) { m_mc.copy(s.get_model_converter()); m_fmc = alloc(generic_model_converter, m); + m_imc = nullptr; } ast_manager & m() { return m_var2expr.get_manager(); } @@ -920,6 +922,7 @@ struct sat2goal::imp { insert(l.var(), m().mk_fresh_const(0, m().mk_bool_sort()), true); } } + m_imc = nullptr; } virtual void operator()(model_ref & md) { @@ -1026,7 +1029,34 @@ struct sat2goal::imp { } void operator()(expr_ref& formula) override { - NOT_IMPLEMENTED_YET(); + if (!m_imc) { + m_imc = alloc(generic_model_converter, m()); + sat::literal_vector updates; + m_mc.expand(updates); + sat::literal_vector clause; + expr_ref_vector tail(m()); + expr_ref def(m()); + for (sat::literal l : updates) { + if (l == sat::null_literal) { + sat::literal lit0 = clause[0]; + for (unsigned i = 1; i < clause.size(); ++i) { + tail.push_back(lit2expr(~clause[i])); + } + def = m().mk_or(lit2expr(lit0), mk_and(tail)); + if (lit0.sign()) { + lit0.neg(); + def = m().mk_not(def); + } + m_imc->add(lit2expr(lit0), def); + clause.reset(); + tail.reset(); + } + else { + clause.push_back(l); + } + } + } + (*m_imc)(formula); } }; diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index aeec97260..19caa62ac 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -104,7 +104,6 @@ void generic_model_converter::operator()(expr_ref& fml) { unsigned min_idx = min_proc.m_min; for (unsigned i = m_add_entries.size(); i-- > min_idx;) { entry const& e = m_add_entries[i]; - m_add_entries.pop_back(); unsigned arity = e.m_f->get_arity(); if (arity == 0) { fml = m.mk_and(fml, m.mk_eq(m.mk_const(e.m_f), e.m_def)); @@ -115,5 +114,6 @@ void generic_model_converter::operator()(expr_ref& fml) { if (m_first_idx[e.m_f] == i) { m_first_idx.remove(e.m_f); } + m_add_entries.pop_back(); } } From ef30868ad7eca70af5f1e74f70351c31efeb483e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Nov 2017 13:32:40 -0800 Subject: [PATCH 0354/1283] change lookahead equivalence filter Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index d79aeffde..32cc877dd 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -678,7 +678,7 @@ namespace sat { for (literal u : succ) { SASSERT(u != l); // l => u - if (u.index() > l.index() && is_stamped(u)) { + if (u.index() > (~l).index() && is_stamped(u)) { add_arc(~l, ~u); add_arc( u, l); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 7c703653c..75231f274 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -921,7 +921,7 @@ struct sat2goal::imp { } } } - + virtual void operator()(model_ref & md) { TRACE("sat_mc", tout << "before sat_mc\n"; model_v2_pp(tout, *md); display(tout);); // REMARK: potential problem From edffdf857cf0c396c1a2885316b8bd09dc7b9c22 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Nov 2017 16:07:10 -0800 Subject: [PATCH 0355/1283] use expr-vectors Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 6 ++---- src/model/model_pp.cpp | 6 ++---- src/tactic/generic_model_converter.cpp | 18 ++++++++++++++++-- src/tactic/portfolio/bounded_int2bv_solver.cpp | 8 ++++---- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index bb5359c19..f6169a851 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1031,10 +1031,8 @@ class smt2_printer { void reset_expr2alias_stack() { SASSERT(!m_expr2alias_stack.empty()); - ptr_vector::iterator it = m_expr2alias_stack.begin(); - ptr_vector::iterator end = m_expr2alias_stack.end(); - for (; it != end; ++it) - (*it)->reset(); + for (expr2alias * e : m_expr2alias_stack) + e->reset(); m_expr2alias = m_expr2alias_stack[0]; } diff --git a/src/model/model_pp.cpp b/src/model/model_pp.cpp index 2f9b114bb..08d63803b 100644 --- a/src/model/model_pp.cpp +++ b/src/model/model_pp.cpp @@ -31,10 +31,8 @@ static void display_uninterp_sorts(std::ostream & out, model_core const & md) { sort * s = md.get_uninterpreted_sort(i); out << "(define-sort " << mk_pp(s, m); ptr_vector const & univ = md.get_universe(s); - ptr_vector::const_iterator it = univ.begin(); - ptr_vector::const_iterator end = univ.end(); - for (; it != end; ++it) { - out << " " << mk_ismt2_pp(*it, m); + for (expr* e : univ) { + out << " " << mk_ismt2_pp(e, m); } out << ")\n"; } diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 19caa62ac..ae75028b0 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -19,6 +19,7 @@ Notes: --*/ #include "ast/ast_pp.h" #include "ast/for_each_expr.h" +#include "ast/ast_util.h" #include "tactic/generic_model_converter.h" #include "model/model_v2_pp.h" #include "model/model_evaluator.h" @@ -101,19 +102,32 @@ struct min_app_idx_proc { void generic_model_converter::operator()(expr_ref& fml) { min_app_idx_proc min_proc(m_first_idx); for_each_expr(min_proc, fml); + expr_ref_vector fmls(m); + fmls.push_back(fml); unsigned min_idx = min_proc.m_min; for (unsigned i = m_add_entries.size(); i-- > min_idx;) { entry const& e = m_add_entries[i]; unsigned arity = e.m_f->get_arity(); if (arity == 0) { - fml = m.mk_and(fml, m.mk_eq(m.mk_const(e.m_f), e.m_def)); + fmls.push_back(m.mk_eq(m.mk_const(e.m_f), e.m_def)); } else { - NOT_IMPLEMENTED_YET(); + expr_ref_vector args(m); + sort_ref_vector sorts(m); + svector names; + for (unsigned i = 0; i < arity; ++i) { + sorts.push_back(e.m_f->get_domain(i)); + names.push_back(symbol(i)); + args.push_back(m.mk_var(i, sorts.back())); + } + expr_ref lhs(m.mk_app(e.m_f, arity, args.c_ptr()), m); + expr_ref body(m.mk_eq(lhs, e.m_def), m); + fmls.push_back(m.mk_forall(arity, sorts.c_ptr(), names.c_ptr(), body)); } if (m_first_idx[e.m_f] == i) { m_first_idx.remove(e.m_f); } m_add_entries.pop_back(); } + fml = mk_and(fmls); } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 7a8a0930c..a2f4cabe4 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -304,8 +304,8 @@ private: void flush_assertions() const { if (m_assertions.empty()) return; bound_manager& bm = *m_bounds.back(); - for (unsigned i = 0; i < m_assertions.size(); ++i) { - bm(m_assertions[i].get()); + for (expr* a : m_assertions) { + bm(a); } TRACE("int2bv", bm.display(tout);); expr_safe_replace sub(m); @@ -316,8 +316,8 @@ private: m_solver->assert_expr(m_assertions); } else { - for (unsigned i = 0; i < m_assertions.size(); ++i) { - sub(m_assertions[i].get(), fml1); + for (expr* a : m_assertions) { + sub(a, fml1); m_rewriter(fml1, fml2, proof); if (m.canceled()) { m_rewriter.reset(); From 70b344513a4504b0519831aa0e06d1801ef106e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Nov 2017 16:15:02 -0800 Subject: [PATCH 0356/1283] add notes about quantifier ordering, bypass Signed-off-by: Nikolaj Bjorner --- src/tactic/generic_model_converter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index ae75028b0..3a4573517 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -102,9 +102,10 @@ struct min_app_idx_proc { void generic_model_converter::operator()(expr_ref& fml) { min_app_idx_proc min_proc(m_first_idx); for_each_expr(min_proc, fml); + unsigned min_idx = min_proc.m_min; + if (min_idx == UINT_MAX) return; expr_ref_vector fmls(m); fmls.push_back(fml); - unsigned min_idx = min_proc.m_min; for (unsigned i = m_add_entries.size(); i-- > min_idx;) { entry const& e = m_add_entries[i]; unsigned arity = e.m_f->get_arity(); @@ -120,6 +121,7 @@ void generic_model_converter::operator()(expr_ref& fml) { names.push_back(symbol(i)); args.push_back(m.mk_var(i, sorts.back())); } + // TBD: check if order is correct with respect to quantifier binding ordering expr_ref lhs(m.mk_app(e.m_f, arity, args.c_ptr()), m); expr_ref body(m.mk_eq(lhs, e.m_def), m); fmls.push_back(m.mk_forall(arity, sorts.c_ptr(), names.c_ptr(), body)); From 46a96127bef61e5fa00153e11e7852a5139bf98b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Nov 2017 18:37:20 -0800 Subject: [PATCH 0357/1283] add solver_from_string to APIs Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 60 ++++++++++++++++++++++++---------------- src/api/dotnet/Solver.cs | 8 ++++++ src/api/java/Solver.java | 17 ++++++++++++ src/api/python/z3/z3.py | 2 +- src/api/z3_api.h | 7 +++++ 5 files changed, 69 insertions(+), 25 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 2455d3a81..8c2cbf25e 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -128,30 +128,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name) { - Z3_TRY; - LOG_Z3_solver_from_file(c, s, file_name); - char const* ext = get_extension(file_name); - std::ifstream is(file_name); - if (!is) { - SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); - return; - } - if (ext && std::string("dimacs") == ext) { - ast_manager& m = to_solver_ref(s)->get_manager(); - sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); - parse_dimacs(is, solver); - sat2goal s2g; - model_converter_ref mc; - atom2bool_var a2b(m); - goal g(m); - s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); - for (unsigned i = 0; i < g.size(); ++i) { - to_solver_ref(s)->assert_expr(g.form(i)); - } - return; - } - + 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); @@ -170,6 +147,41 @@ extern "C" { to_solver_ref(s)->assert_expr(*it); } to_solver_ref(s)->set_model_converter(ctx->get_model_converter()); + } + + void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string c_str) { + Z3_TRY; + LOG_Z3_solver_from_string(c, s, c_str); + std::string str(c_str); + std::istringstream is(str); + solver_from_stream(c, s, is); + Z3_CATCH; + } + + void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name) { + Z3_TRY; + LOG_Z3_solver_from_file(c, s, file_name); + char const* ext = get_extension(file_name); + std::ifstream is(file_name); + if (!is) { + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); + } + else if (ext && std::string("dimacs") == ext) { + ast_manager& m = to_solver_ref(s)->get_manager(); + sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); + parse_dimacs(is, solver); + sat2goal s2g; + model_converter_ref mc; + atom2bool_var a2b(m); + goal g(m); + s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); + for (unsigned i = 0; i < g.size(); ++i) { + to_solver_ref(s)->assert_expr(g.form(i)); + } + } + else { + solver_from_stream(c, s, is); + } Z3_CATCH; } diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index e310f938c..af5f8e47e 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -231,6 +231,14 @@ namespace Microsoft.Z3 Native.Z3_solver_from_file(Context.nCtx, NativeObject, file); } + /// + /// Load solver assertions from a string. + /// + public void FromString(string str) + { + Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); + } + /// /// Assert a lemma (or multiple) into the solver. /// diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index 19f3b01da..8eb634e23 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -170,6 +170,23 @@ public class Solver extends Z3Object { constraint.getNativeObject(), p.getNativeObject()); } + /// + /// Load solver assertions from a file. + /// + public void FromFile(string file) + { + Native.Z3_solver_from_file(Context.nCtx, NativeObject, file); + } + + /// + /// Load solver assertions from a string. + /// + public void FromString(string str) + { + Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); + } + + /** * The number of assertions in the solver. * diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index f911732ef..9819af47f 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6335,7 +6335,7 @@ class Solver(Z3PPObject): def from_string(self, s): """Parse assertions from a string""" - self.add([f for f in parse_smt2_string(s, ctx=self.ctx)]) + Z3_solver_from_string(self.ctx.ref(), self.solver, filename) def assertions(self): """Return an AST vector containing all added constraints. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index c9603c018..7f92501ec 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6152,6 +6152,13 @@ extern "C" { */ void Z3_API Z3_solver_from_file(Z3_context c, Z3_solver s, Z3_string file_name); + /** + \brief load solver assertions from a string. + + def_API('Z3_solver_from_string', VOID, (_in(CONTEXT), _in(SOLVER), _in(STRING))) + */ + void Z3_API Z3_solver_from_string(Z3_context c, Z3_solver s, Z3_string file_name); + /** \brief Return the set of asserted formulas on the solver. From 433239d5e9af6c16cab7d98c567ba1bb80cfe365 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Nov 2017 18:39:16 -0800 Subject: [PATCH 0358/1283] add solver_from_string to APIs Signed-off-by: Nikolaj Bjorner --- src/api/java/Solver.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index 8eb634e23..a64c4a9c5 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -173,17 +173,17 @@ public class Solver extends Z3Object { /// /// Load solver assertions from a file. /// - public void FromFile(string file) + public void fromFile(String file) { - Native.Z3_solver_from_file(Context.nCtx, NativeObject, file); + Native.solverFromFile(getContext().nCtx(), getNativeObject(), file); } /// /// Load solver assertions from a string. /// - public void FromString(string str) + public void fromString(String str) { - Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); + Native.solverFromString(getContext().nCtx(), getNativeObject(), str); } From 2313b14210bed44699212b1ba9358807b8525146 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Nov 2017 20:40:43 -0800 Subject: [PATCH 0359/1283] include mc0 for display method Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 6 ++++-- src/solver/check_sat_result.h | 2 +- src/solver/solver.cpp | 9 +-------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 06a7cba19..8d23c5ef4 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -864,7 +864,8 @@ void cmd_context::insert(symbol const & s, object_ref * r) { } void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domain, expr * t) { - if (!m_mc0) m_mc0 = alloc(generic_model_converter, m()); + if (!m_mc0.get()) m_mc0 = alloc(generic_model_converter, m()); + if (m_solver.get() && !m_solver->mc0()) m_solver->set_model_converter(m_mc0.get()); func_decl_ref fn(m().mk_func_decl(s, arity, domain, m().get_sort(t)), m()); dictionary::entry * e = m_func_decls.insert_if_not_there2(s, func_decls()); func_decls & fs = e->get_data().m_value; @@ -873,7 +874,8 @@ void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domai } void cmd_context::model_del(func_decl* f) { - if (!m_mc0) m_mc0 = alloc(generic_model_converter, m()); + if (!m_mc0.get()) m_mc0 = alloc(generic_model_converter, m()); + if (m_solver.get() && !m_solver->mc0()) m_solver->set_model_converter(m_mc0.get()); m_mc0->hide(f); } diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 572c4d88d..4ea28ee61 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -57,7 +57,7 @@ public: r.append(core.size(), core.c_ptr()); } void set_model_converter(model_converter* mc) { m_mc0 = mc; } - model_converter* mc0() { return m_mc0.get(); } + model_converter* mc0() const { return m_mc0.get(); } virtual void get_model_core(model_ref & m) = 0; void get_model(model_ref & m) { get_model_core(m); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index f14467337..3d36fb01e 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -40,27 +40,20 @@ std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assum expr_ref_vector fmls(get_manager()); stopwatch sw; sw.start(); - // std::cout << "display 1\n"; get_assertions(fmls); - // std::cout << "display 2 " << sw.get_current_seconds() << "\n"; ast_pp_util visitor(get_manager()); model_converter_ref mc = get_model_converter(); - // std::cout << "display 3 " << sw.get_current_seconds() << "\n"; + mc = concat(mc0(), mc.get()); if (mc.get()) { mc->collect(visitor); } - // std::cout << "display 4 " << sw.get_current_seconds() << "\n"; visitor.collect(fmls); - // std::cout << "display 5 " << sw.get_current_seconds() << "\n"; visitor.collect(n, assumptions); visitor.display_decls(out); - // std::cout << "display 6 " << sw.get_current_seconds() << "\n"; visitor.display_asserts(out, fmls, true); - // std::cout << "display 7 " << sw.get_current_seconds() << "\n"; if (mc.get()) { mc->display(out); } - // std::cout << "display 8 " << sw.get_current_seconds() << "\n"; return out; } From 107bfb1438f89e1afb61893941dd3f7cc5580e8e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Nov 2017 21:26:07 -0800 Subject: [PATCH 0360/1283] print model-add in display method Signed-off-by: Nikolaj Bjorner --- src/smt/tactic/smt_tactic.cpp | 8 ++++++-- src/solver/solver.cpp | 2 ++ src/tactic/generic_model_converter.cpp | 2 +- src/tactic/model_converter.cpp | 16 +++++++--------- src/tactic/model_converter.h | 2 +- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index dc927e9f3..97b6d89d7 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -217,8 +217,10 @@ public: m_ctx->get_model(md); buffer r; m_ctx->get_relevant_labels(0, r); + labels_vec rv; + rv.append(r.size(), r.c_ptr()); model_converter_ref mc; - mc = model_and_labels2model_converter(md.get(), r); + mc = model_and_labels2model_converter(md.get(), rv); mc = concat(fmc.get(), mc.get()); in->add(mc.get()); } @@ -268,7 +270,9 @@ public: m_ctx->get_model(md); buffer r; m_ctx->get_relevant_labels(0, r); - in->add(model_and_labels2model_converter(md.get(), r)); + labels_vec rv; + rv.append(r.size(), r.c_ptr()); + in->add(model_and_labels2model_converter(md.get(), rv)); } return; default: diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 3d36fb01e..2556f40bd 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -179,6 +179,7 @@ bool solver::is_literal(ast_manager& m, expr* e) { void solver::assert_expr(expr* f) { expr_ref fml(f, get_manager()); model_converter_ref mc = get_model_converter(); + mc = concat(mc0(), mc.get()); if (mc) { (*mc)(fml); } @@ -190,6 +191,7 @@ void solver::assert_expr(expr* f, expr* t) { expr_ref fml(f, m); expr_ref a(t, m); model_converter_ref mc = get_model_converter(); + mc = concat(mc0(), mc.get()); if (mc) { (*mc)(fml); // (*mc0())(a); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 3a4573517..8befffff5 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -58,7 +58,7 @@ void generic_model_converter::display(std::ostream & out) { display_del(out, e.m_f); } for (entry const& e : m_add_entries) { - display_del(out, e.m_f); + display_add(out, m, e.m_f, e.m_def); } } diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index da6a0dcf8..2598aa4f1 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -96,11 +96,11 @@ model_converter * concat(model_converter * mc1, model_converter * mc2) { class model2mc : public model_converter { model_ref m_model; - buffer m_labels; + labels_vec m_labels; public: model2mc(model * m):m_model(m) {} - model2mc(model * m, buffer const & r):m_model(m), m_labels(r) {} + model2mc(model * m, labels_vec const & r):m_model(m), m_labels(r) {} virtual ~model2mc() {} @@ -122,27 +122,25 @@ public: } void display(std::ostream & out) override { - out << "(model->model-converter-wrapper\n"; + out << "(rmodel->model-converter-wrapper\n"; model_v2_pp(out, *m_model); out << ")\n"; } virtual model_converter * translate(ast_translation & translator) { model * m = m_model->translate(translator); - return alloc(model2mc, m); + return alloc(model2mc, m, m_labels); } }; model_converter * model2model_converter(model * m) { - if (m == 0) - return 0; + if (!m) return nullptr; return alloc(model2mc, m); } -model_converter * model_and_labels2model_converter(model * m, buffer & r) { - if (m == 0) - return 0; +model_converter * model_and_labels2model_converter(model * m, labels_vec const & r) { + if (!m) return nullptr; return alloc(model2mc, m, r); } diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index c768a0cae..d4991e672 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -98,7 +98,7 @@ model_converter * concat(model_converter * mc1, model_converter * mc2); model_converter * model2model_converter(model * m); -model_converter * model_and_labels2model_converter(model * m, buffer &r); +model_converter * model_and_labels2model_converter(model * m, labels_vec const &r); void model_converter2model(ast_manager & mng, model_converter * mc, model_ref & m); From 8230cbef4c2faa325ad0dd2ad61dab24ea570e68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Nov 2017 08:55:21 -0800 Subject: [PATCH 0361/1283] fix mc efficiency issues Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver/inc_sat_solver.cpp | 12 ++++++++---- src/sat/tactic/goal2sat.cpp | 1 + src/solver/solver.cpp | 4 ++-- src/tactic/portfolio/pb2bv_solver.cpp | 1 + 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 3f5744556..5aab0b25f 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -61,6 +61,7 @@ class inc_sat_solver : public solver { model_converter_ref m_mc; model_converter_ref m_mc0; model_converter_ref m_sat_mc; + mutable model_converter_ref m_cached_mc; svector m_weights; std::string m_unknown; // access formulas after they have been pre-processed and handled by the sat solver. @@ -435,10 +436,12 @@ public: virtual model_converter_ref get_model_converter() const { const_cast(this)->convert_internalized(); if (m_internalized && m_internalized_converted) { - model_converter_ref mc = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); - mc = concat(solver::get_model_converter().get(), mc.get()); - mc = concat(mc.get(), m_sat_mc.get()); - return mc; + if (m_cached_mc) + return m_cached_mc; + m_cached_mc = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); + m_cached_mc = concat(solver::get_model_converter().get(), m_cached_mc.get()); + m_cached_mc = concat(m_cached_mc.get(), m_sat_mc.get()); + return m_cached_mc; } else { return solver::get_model_converter(); @@ -449,6 +452,7 @@ public: if (!m_internalized || m_internalized_converted) return; sat2goal s2g; m_sat_mc = nullptr; + m_cached_mc = nullptr; goal g(m, false, true, false); s2g(m_solver, m_map, m_params, g, m_sat_mc); m_internalized_fmls.reset(); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index a954f08c0..009d2818c 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1030,6 +1030,7 @@ struct sat2goal::imp { void operator()(expr_ref& formula) override { if (!m_imc) { + std::cout << "create generic\n"; m_imc = alloc(generic_model_converter, m()); sat::literal_vector updates; m_mc.expand(updates); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 2556f40bd..2460557bc 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -40,7 +40,7 @@ std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assum expr_ref_vector fmls(get_manager()); stopwatch sw; sw.start(); - get_assertions(fmls); + get_assertions(fmls); ast_pp_util visitor(get_manager()); model_converter_ref mc = get_model_converter(); mc = concat(mc0(), mc.get()); @@ -194,7 +194,7 @@ void solver::assert_expr(expr* f, expr* t) { mc = concat(mc0(), mc.get()); if (mc) { (*mc)(fml); - // (*mc0())(a); + // (*mc)(a); } assert_expr_core(fml, a); } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 9b8eed98d..ffc1ea09f 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -134,6 +134,7 @@ public: private: void flush_assertions() const { + if (m_assertions.empty()) return; m_rewriter.updt_params(get_params()); proof_ref proof(m); expr_ref fml1(m), fml(m); From 5f0a02b5f72be2450a1c814aac5ecba48f75e8c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Nov 2017 09:05:17 -0800 Subject: [PATCH 0362/1283] remove output Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 009d2818c..a954f08c0 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1030,7 +1030,6 @@ struct sat2goal::imp { void operator()(expr_ref& formula) override { if (!m_imc) { - std::cout << "create generic\n"; m_imc = alloc(generic_model_converter, m()); sat::literal_vector updates; m_mc.expand(updates); From 1101c927c9bbbd9aa684625df15fab5d830e38a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Nov 2017 13:46:02 -0800 Subject: [PATCH 0363/1283] prepare for transitive reduction / hyper-binary clause addition Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 55 ++++++++++++++++++++++------- src/sat/sat_lookahead.cpp | 37 ++++++++++++++----- src/sat/sat_lookahead.h | 4 ++- 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 0fdee0700..1e8cd7182 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -77,7 +77,33 @@ struct pb2bv_rewriter::imp { fmls.push_back(bv.mk_ule(bound, result)); } return result; + } + typedef std::pair ca; + + struct compare_coeffs { + bool operator()(ca const& x, ca const& y) const { + return x.first < y.first; + } + }; + + void sort_args() { + vector cas; + for (unsigned i = 0; i < m_args.size(); ++i) { + cas.push_back(std::make_pair(m_coeffs[i], expr_ref(m_args[i].get(), m))); + } + //for (ca const& ca : cas) std::cout << ca.first << " "; + //std::cout << "\n"; + std::sort(cas.begin(), cas.end(), compare_coeffs()); + //std::cout << "post-sort\n"; + //for (ca const& ca : cas) std::cout << ca.first << " "; + //std::cout << "\n"; + m_coeffs.reset(); + m_args.reset(); + for (ca const& ca : cas) { + m_coeffs.push_back(ca.first); + m_args.push_back(ca.second); + } } // @@ -93,7 +119,10 @@ struct pb2bv_rewriter::imp { // is_le = l_false - >= // template - expr_ref mk_le_ge(unsigned sz, expr * const* args, rational const & k) { + expr_ref mk_le_ge(rational const & k) { + //sort_args(); + unsigned sz = m_args.size(); + expr * const* args = m_args.c_ptr(); TRACE("pb", for (unsigned i = 0; i < sz; ++i) { tout << m_coeffs[i] << "*" << mk_pp(args[i], m) << " "; @@ -107,7 +136,7 @@ struct pb2bv_rewriter::imp { tout << k << "\n";); if (k.is_zero()) { if (is_le != l_false) { - return expr_ref(m.mk_not(::mk_or(m, sz, args)), m); + return expr_ref(m.mk_not(::mk_or(m_args)), m); } else { return expr_ref(m.mk_true(), m); @@ -501,25 +530,25 @@ struct pb2bv_rewriter::imp { decl_kind kind = f->get_decl_kind(); rational k = pb.get_k(f); m_coeffs.reset(); + m_args.reset(); for (unsigned i = 0; i < sz; ++i) { m_coeffs.push_back(pb.get_coeff(f, i)); + m_args.push_back(args[i]); } CTRACE("pb", k.is_neg(), tout << expr_ref(m.mk_app(f, sz, args), m) << "\n";); SASSERT(!k.is_neg()); switch (kind) { case OP_PB_GE: case OP_AT_LEAST_K: { - expr_ref_vector nargs(m); - nargs.append(sz, args); - dualize(f, nargs, k); + dualize(f, m_args, k); SASSERT(!k.is_neg()); - return mk_le_ge(sz, nargs.c_ptr(), k); + return mk_le_ge(k); } case OP_PB_LE: case OP_AT_MOST_K: - return mk_le_ge(sz, args, k); + return mk_le_ge(k); case OP_PB_EQ: - return mk_le_ge(sz, args, k); + return mk_le_ge(k); default: UNREACHABLE(); return expr_ref(m.mk_true(), m); @@ -591,21 +620,21 @@ struct pb2bv_rewriter::imp { // skip } else if (au.is_le(f) && is_pb(args[0], args[1])) { - result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + result = mk_le_ge(m_k); } else if (au.is_lt(f) && is_pb(args[0], args[1])) { ++m_k; - result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + result = mk_le_ge(m_k); } else if (au.is_ge(f) && is_pb(args[1], args[0])) { - result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + result = mk_le_ge(m_k); } else if (au.is_gt(f) && is_pb(args[1], args[0])) { ++m_k; - result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + result = mk_le_ge(m_k); } else if (m.is_eq(f) && is_pb(args[0], args[1])) { - result = mk_le_ge(m_args.size(), m_args.c_ptr(), m_k); + result = mk_le_ge(m_k); } else { return false; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 32cc877dd..bc5f9b071 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -233,7 +233,6 @@ namespace sat { if (is_sat()) { return false; } - std::cout << "include newbies\n"; } SASSERT(!m_candidates.empty()); // cut number of candidates down to max_num_cand. @@ -437,8 +436,8 @@ namespace sat { for (binary b : m_ternary[(~l1).index()]) { if (sz-- == 0) break; if (!(is_true(b.m_u) || is_true(b.m_v) || (is_undef(b.m_v) && is_undef(b.m_u)))) { - std::cout << b.m_u << " " << b.m_v << "\n"; - std::cout << get_level(b.m_u) << " " << get_level(b.m_v) << " level: " << m_level << "\n"; + IF_VERBOSE(0, verbose_stream() << b.m_u << " " << b.m_v << "\n" + << get_level(b.m_u) << " " << get_level(b.m_v) << " level: " << m_level << "\n";); UNREACHABLE(); } if ((is_false(b.m_u) && is_undef(b.m_v)) || (is_false(b.m_v) && is_undef(b.m_u))) @@ -649,6 +648,7 @@ namespace sat { TRACE("sat", display_scc(tout);); } void lookahead::init_scc() { + std::cerr << "init-scc\n"; inc_bstamp(); for (unsigned i = 0; i < m_candidates.size(); ++i) { literal lit(m_candidates[i].m_var, false); @@ -661,6 +661,7 @@ namespace sat { init_arcs(~lit); } m_rank = 0; + m_rank_max = UINT_MAX; m_active = null_literal; m_settled = null_literal; TRACE("sat", display_dfs(tout);); @@ -678,15 +679,19 @@ namespace sat { for (literal u : succ) { SASSERT(u != l); // l => u - if (u.index() > (~l).index() && is_stamped(u)) { + // NB. u.index() > l.index() iff u.index() > (~l).index(). + // since indices for the same boolean variables occupy + // two adjacent numbers. + if (u.index() > l.index() && is_stamped(u)) { add_arc(~l, ~u); add_arc( u, l); } } for (auto w : m_watches[l.index()]) { + lits.reset(); if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { for (literal u : lits) { - if (u.index() > (~l).index() && is_stamped(u)) { + if (u.index() > l.index() && is_stamped(u)) { add_arc(~l, ~u); add_arc( u, l); } @@ -695,6 +700,11 @@ namespace sat { } } + void lookahead::add_arc(literal u, literal v) { + auto & lst = m_dfs[u.index()].m_next; + if (lst.empty() || lst.back() != v) lst.push_back(v); + } + void lookahead::get_scc(literal v) { TRACE("scc", tout << v << "\n";); set_parent(v, null_literal); @@ -744,7 +754,7 @@ namespace sat { m_active = get_link(v); literal best = v; double best_rating = get_rating(v); - set_rank(v, UINT_MAX); + set_rank(v, m_rank_max); set_link(v, m_settled); m_settled = t; while (t != v) { if (t == ~v) { @@ -752,7 +762,7 @@ namespace sat { set_conflict(); break; } - set_rank(t, UINT_MAX); + set_rank(t, m_rank_max); set_parent(t, v); double t_rating = get_rating(t); if (t_rating > best_rating) { @@ -763,7 +773,7 @@ namespace sat { } set_parent(v, v); set_vcomp(v, best); - if (get_rank(~v) == UINT_MAX) { + if (maxed_rank(~v)) { set_vcomp(v, ~get_vcomp(get_parent(~v))); } } @@ -2279,6 +2289,17 @@ namespace sat { IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); elim_eqs elim(m_s); elim(roots, to_elim); + +#if 0 + // TBD: + // Finally create a new graph between parents + // based on the arcs in the the m_dfs[index].m_next structure + // Visit all nodes, assign DFS numbers + // Then prune binary clauses that differ in DFS number more than 1 + // Add binary clauses that have DFS number 1, but no companion binary clause. + // +#endif + } } m_lookahead.reset(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index e65e7021a..99d5511ea 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -387,6 +387,7 @@ namespace sat { literal m_active; unsigned m_rank; + unsigned m_rank_max; literal m_settled; vector m_dfs; @@ -394,7 +395,7 @@ namespace sat { void init_scc(); void init_dfs_info(literal l); void init_arcs(literal l); - void add_arc(literal u, literal v) { m_dfs[u.index()].m_next.push_back(v); } + void add_arc(literal u, literal v); bool has_arc(literal v) const { return m_dfs[v.index()].m_next.size() > m_dfs[v.index()].m_nextp; } arcs get_arcs(literal v) const { return m_dfs[v.index()].m_next; } literal pop_arc(literal u) { return m_dfs[u.index()].m_next[m_dfs[u.index()].m_nextp++]; } @@ -402,6 +403,7 @@ namespace sat { literal get_next(literal u, unsigned i) const { return m_dfs[u.index()].m_next[i]; } literal get_min(literal v) const { return m_dfs[v.index()].m_min; } unsigned get_rank(literal v) const { return m_dfs[v.index()].m_rank; } + bool maxed_rank(literal v) const { return get_rank(v) >= m_rank_max; } unsigned get_height(literal v) const { return m_dfs[v.index()].m_height; } literal get_parent(literal u) const { return m_dfs[u.index()].m_parent; } literal get_link(literal u) const { return m_dfs[u.index()].m_link; } From 62e39069576fa199255aafa51c8c98ecf5d8ec07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Nov 2017 10:53:22 -0800 Subject: [PATCH 0364/1283] add options to perform transitive reduction and add hyper binary clauses Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 2 + src/sat/sat_config.h | 1 + src/sat/sat_elim_eqs.cpp | 8 +-- src/sat/sat_lookahead.cpp | 64 ++++++++++++++----- src/sat/sat_lookahead.h | 3 + src/sat/sat_params.pyg | 1 + src/sat/sat_scc.cpp | 123 ++++++++++++++++++++++++++++++++++++- src/sat/sat_scc.h | 9 +++ src/sat/sat_scc_params.pyg | 3 +- 9 files changed, 189 insertions(+), 25 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index e062841b7..b672fe065 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -41,6 +41,7 @@ namespace sat { m_local_search = 0; m_lookahead_search = false; m_lookahead_simplify = false; + m_lookahead_simplify_bca = false; m_elim_vars = false; m_incremental = false; updt_params(p); @@ -90,6 +91,7 @@ namespace sat { m_local_search = p.local_search(); m_local_search_threads = p.local_search_threads(); m_lookahead_simplify = p.lookahead_simplify(); + m_lookahead_simplify_bca = p.lookahead_simplify_bca(); m_lookahead_search = p.lookahead_search(); if (p.lookahead_reward() == symbol("heule_schur")) { m_lookahead_reward = heule_schur_reward; diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 4fc1f4e7e..132b85b24 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -84,6 +84,7 @@ namespace sat { bool m_local_search; bool m_lookahead_search; bool m_lookahead_simplify; + bool m_lookahead_simplify_bca; unsigned m_lookahead_cube_cutoff; double m_lookahead_cube_fraction; reward_t m_lookahead_reward; diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 49b371104..cb659247f 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -34,11 +34,9 @@ namespace sat { } void elim_eqs::cleanup_bin_watches(literal_vector const & roots) { - vector::iterator it = m_solver.m_watches.begin(); - vector::iterator end = m_solver.m_watches.end(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - watch_list & wlist = *it; - literal l1 = ~to_literal(l_idx); + unsigned l_idx = 0; + for (watch_list & wlist : m_solver.m_watches) { + literal l1 = ~to_literal(l_idx++); literal r1 = norm(roots, l1); watch_list::iterator it2 = wlist.begin(); watch_list::iterator itprev = it2; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index bc5f9b071..b50d7aa2f 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -17,9 +17,10 @@ Author: Notes: --*/ -#include "sat_solver.h" -#include "sat_extension.h" -#include "sat_lookahead.h" +#include "sat/sat_solver.h" +#include "sat/sat_extension.h" +#include "sat/sat_lookahead.h" +#include "util/union_find.h" namespace sat { lookahead::scoped_ext::scoped_ext(lookahead& p): p(p) { @@ -648,7 +649,6 @@ namespace sat { TRACE("sat", display_scc(tout);); } void lookahead::init_scc() { - std::cerr << "init-scc\n"; inc_bstamp(); for (unsigned i = 0; i < m_candidates.size(); ++i) { literal lit(m_candidates[i].m_var, false); @@ -2290,20 +2290,51 @@ namespace sat { elim_eqs elim(m_s); elim(roots, to_elim); -#if 0 - // TBD: - // Finally create a new graph between parents - // based on the arcs in the the m_dfs[index].m_next structure - // Visit all nodes, assign DFS numbers - // Then prune binary clauses that differ in DFS number more than 1 - // Add binary clauses that have DFS number 1, but no companion binary clause. - // -#endif - + if (get_config().m_lookahead_simplify_bca) { + add_hyper_binary(); + } } } - m_lookahead.reset(); - + m_lookahead.reset(); + } + + /** + \brief reduction based on binary implication graph + */ + + void lookahead::add_hyper_binary() { + unsigned num_lits = m_s.num_vars() * 2; + union_find_default_ctx ufctx; + union_find uf(ufctx); + for (unsigned i = 0; i < num_lits; ++i) uf.mk_var(); + for (unsigned idx = 0; idx < num_lits; ++idx) { + literal u = get_parent(to_literal(idx)); + if (null_literal != u) { + for (watched const& w : m_s.m_watches[idx]) { + if (!w.is_binary_clause()) continue; + literal v = get_parent(w.get_literal()); + if (null_literal != v) { + uf.merge(u.index(), v.index()); + } + } + } + } + + unsigned disconnected = 0; + for (unsigned i = 0; i < m_binary.size(); ++i) { + literal u = to_literal(i); + if (u == get_parent(u)) { + for (literal v : m_binary[i]) { + if (v == get_parent(v) && uf.find(u.index()) != uf.find(v.index())) { + ++disconnected; + uf.merge(u.index(), v.index()); + m_s.mk_clause(~u, v, true); + } + } + } + } + IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << disconnected << ")\n";); + m_stats.m_bca += disconnected; } void lookahead::normalize_parents() { @@ -2378,6 +2409,7 @@ namespace sat { void lookahead::collect_statistics(statistics& st) const { st.update("lh bool var", m_vprefix.size()); // TBD: keep count of ternary and >3-ary clauses. + st.update("lh bca", m_stats.m_bca); st.update("lh add binary", m_stats.m_add_binary); st.update("lh del binary", m_stats.m_del_binary); st.update("lh propagations", m_stats.m_propagations); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 99d5511ea..6f0c256a7 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -115,6 +115,7 @@ namespace sat { struct stats { unsigned m_propagations; + unsigned m_bca; unsigned m_add_binary; unsigned m_del_binary; unsigned m_decisions; @@ -533,6 +534,8 @@ namespace sat { void normalize_parents(); + void add_hyper_binary(); + public: lookahead(solver& s) : m_s(s), diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index bae1d0c11..887cea2a7 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -41,6 +41,7 @@ def_module_params('sat', ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), + ('lookahead_simplify.bca', BOOL, False, 'add learned binary clauses as part of lookahead simplification'), ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'), ('dimacs.inprocess.display', BOOL, False, 'display SAT instance in DIMACS format if unsolved after inprocess.max inprocessing passes'))) diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 544ef1f66..df574f4a8 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -45,16 +45,20 @@ namespace sat { scc & m_scc; stopwatch m_watch; unsigned m_num_elim; + unsigned m_num_elim_bin; report(scc & c): m_scc(c), - m_num_elim(c.m_num_elim) { + m_num_elim(c.m_num_elim), + m_num_elim_bin(c.m_num_elim_bin) { m_watch.start(); } ~report() { m_watch.stop(); + unsigned elim_bin = m_scc.m_num_elim_bin - m_num_elim_bin; IF_VERBOSE(SAT_VB_LVL, - verbose_stream() << " (sat-scc :elim-vars " << (m_scc.m_num_elim - m_num_elim) - << mk_stat(m_scc.m_solver) + verbose_stream() << " (sat-scc :elim-vars " << (m_scc.m_num_elim - m_num_elim); + if (elim_bin > 0) verbose_stream() << " :elim-bin " << elim_bin; + verbose_stream() << mk_stat(m_scc.m_solver) << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } }; @@ -223,20 +227,133 @@ namespace sat { eliminator(roots, to_elim); TRACE("scc_detail", m_solver.display(tout);); CASSERT("scc_bug", m_solver.check_invariant()); + + if (m_scc_tr) { + reduce_tr(); + } return to_elim.size(); } + void scc::get_dfs_num(svector& dfs, bool learned) { + unsigned num_lits = m_solver.num_vars() * 2; + vector dag(num_lits); + svector roots(num_lits, true); + literal_vector todo; + SASSERT(dfs.size() == num_lits); + unsigned num_edges = 0; + + // retrieve DAG + for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { + literal u(to_literal(l_idx)); + if (m_solver.was_eliminated(u.var())) + continue; + auto& edges = dag[u.index()]; + for (watched const& w : m_solver.m_watches[l_idx]) { + if (learned ? w.is_binary_clause() : w.is_binary_unblocked_clause()) { + literal v = w.get_literal(); + roots[v.index()] = false; + edges.push_back(v); + ++num_edges; + } + } + unsigned sz = edges.size(); + // shuffle vertices to obtain different DAG traversal each time + if (sz > 1) { + for (unsigned i = sz; i-- > 0; ) { + std::swap(edges[i], edges[m_rand(i+1)]); + } + } + } + // std::cout << "dag num edges: " << num_edges << "\n"; + // retrieve literals that have no predecessors + for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { + literal u(to_literal(l_idx)); + if (roots[u.index()]) todo.push_back(u); + } + // std::cout << "num roots: " << roots.size() << "\n"; + // traverse DAG, annotate nodes with DFS number + int dfs_num = 0; + while (!todo.empty()) { + literal u = todo.back(); + int& d = dfs[u.index()]; + // already visited + if (d > 0) { + todo.pop_back(); + } + // visited as child: + else if (d < 0) { + d = -d; + for (literal v : dag[u.index()]) { + if (dfs[v.index()] == 0) { + dfs[v.index()] = - d - 1; + todo.push_back(v); + } + } + } + // new root. + else { + d = --dfs_num; + } + } + } + + bool scc::reduce_tr(svector const& dfs, bool learned) { + unsigned idx = 0; + bool reduced = false; + for (watch_list & wlist : m_solver.m_watches) { + literal u = to_literal(idx++); + watch_list::iterator it = wlist.begin(); + watch_list::iterator itprev = it; + watch_list::iterator end = wlist.end(); + for (; it != end; ++it) { + watched& w = *it; + if (learned ? w.is_binary_learned_clause() : w.is_binary_unblocked_clause()) { + literal v = w.get_literal(); + if (dfs[u.index()] + 1 < dfs[v.index()]) { + ++m_num_elim_bin; + reduced = true; + } + else { + *itprev = *it; + itprev++; + } + } + else { + *itprev = *it; + itprev++; + } + } + wlist.set_end(itprev); + } + return reduced; + } + + bool scc::reduce_tr(bool learned) { + unsigned num_lits = m_solver.num_vars() * 2; + svector dfs(num_lits); + get_dfs_num(dfs, learned); + return reduce_tr(dfs, learned); + } + + void scc::reduce_tr() { + while (reduce_tr(false)) {} + while (reduce_tr(true)) {} + } + void scc::collect_statistics(statistics & st) const { st.update("elim bool vars", m_num_elim); + st.update("elim binary", m_num_elim_bin); } void scc::reset_statistics() { m_num_elim = 0; + m_num_elim_bin = 0; } void scc::updt_params(params_ref const & _p) { sat_scc_params p(_p); m_scc = p.scc(); + m_scc_tr = p.scc_tr(); } void scc::collect_param_descrs(param_descrs & d) { diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index c8392685e..cfad76d71 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -31,8 +31,17 @@ namespace sat { solver & m_solver; // config bool m_scc; + bool m_scc_tr; // stats unsigned m_num_elim; + unsigned m_num_elim_bin; + random_gen m_rand; + + void get_dfs_num(svector& dfs, bool learned); + void reduce_tr(); + bool reduce_tr(bool learned); + bool reduce_tr(svector const& dfs, bool learned); + public: scc(solver & s, params_ref const & p); unsigned operator()(); diff --git a/src/sat/sat_scc_params.pyg b/src/sat/sat_scc_params.pyg index b88de4de8..0bf88a0cd 100644 --- a/src/sat/sat_scc_params.pyg +++ b/src/sat/sat_scc_params.pyg @@ -1,5 +1,6 @@ def_module_params(module_name='sat', class_name='sat_scc_params', export=True, - params=(('scc', BOOL, True, 'eliminate Boolean variables by computing strongly connected components'),)) + params=(('scc', BOOL, True, 'eliminate Boolean variables by computing strongly connected components'), + ('scc.tr', BOOL, False, 'apply transitive reduction, eliminate redundant binary clauses'), )) From fbae881ece6a08a6e2a0bbe3fdc1eba8024370d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Nov 2017 16:24:14 -0800 Subject: [PATCH 0365/1283] add option to bypass model converter during constraint addition. Simplify model definitions that come from blocked clauses Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver/inc_sat_solver.cpp | 1 + src/solver/solver.cpp | 33 ++++++++++++++++-------- src/solver/solver.h | 6 +++-- src/tactic/generic_model_converter.cpp | 35 +++++++++++++++++++++++++- src/tactic/generic_model_converter.h | 3 +++ 5 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 5aab0b25f..7bbe4d29c 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -266,6 +266,7 @@ public: } virtual void set_produce_models(bool f) {} virtual void collect_param_descrs(param_descrs & r) { + solver::collect_param_descrs(r); goal2sat::collect_param_descrs(r); sat::solver::collect_param_descrs(r); } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 2460557bc..eb2b0d016 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -178,24 +178,37 @@ bool solver::is_literal(ast_manager& m, expr* e) { void solver::assert_expr(expr* f) { expr_ref fml(f, get_manager()); - model_converter_ref mc = get_model_converter(); - mc = concat(mc0(), mc.get()); - if (mc) { - (*mc)(fml); + if (m_enforce_model_conversion) { + model_converter_ref mc = get_model_converter(); + mc = concat(mc0(), mc.get()); + if (mc) { + (*mc)(fml); + } } assert_expr_core(fml); } void solver::assert_expr(expr* f, expr* t) { ast_manager& m = get_manager(); - expr_ref fml(f, m); + expr_ref fml(f, m); expr_ref a(t, m); - model_converter_ref mc = get_model_converter(); - mc = concat(mc0(), mc.get()); - if (mc) { - (*mc)(fml); - // (*mc)(a); + if (m_enforce_model_conversion) { + model_converter_ref mc = get_model_converter(); + mc = concat(mc0(), mc.get()); + if (mc) { + (*mc)(fml); + // (*mc)(a); + } } assert_expr_core(fml, a); } +void solver::collect_param_descrs(param_descrs & r) { + r.insert("solver.enforce_model_conversion", CPK_BOOL, "(default: true) enforce model conversion when asserting formulas"); +} + +void solver::updt_params(params_ref const & p) { + m_params.copy(p); + m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", true); +} + diff --git a/src/solver/solver.h b/src/solver/solver.h index 780a55cf5..f6ad74042 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -45,7 +45,9 @@ public: */ class solver : public check_sat_result { params_ref m_params; + bool m_enforce_model_conversion; public: + solver(): m_enforce_model_conversion(true) {} virtual ~solver() {} /** @@ -56,7 +58,7 @@ public: /** \brief Update the solver internal settings. */ - virtual void updt_params(params_ref const & p) { m_params.copy(p); } + virtual void updt_params(params_ref const & p); /** \brief Retrieve set of parameters set on solver. @@ -67,7 +69,7 @@ public: \brief Store in \c r a description of the configuration parameters available in this solver. */ - virtual void collect_param_descrs(param_descrs & r) {} + virtual void collect_param_descrs(param_descrs & r); /** \brief Enable/Disable model generation for this solver object. diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 8befffff5..5c0f8ed5c 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -20,6 +20,8 @@ Notes: #include "ast/ast_pp.h" #include "ast/for_each_expr.h" #include "ast/ast_util.h" +#include "ast/occurs.h" +#include "ast/rewriter/expr_safe_replace.h" #include "tactic/generic_model_converter.h" #include "model/model_v2_pp.h" #include "model/model_evaluator.h" @@ -110,7 +112,7 @@ void generic_model_converter::operator()(expr_ref& fml) { entry const& e = m_add_entries[i]; unsigned arity = e.m_f->get_arity(); if (arity == 0) { - fmls.push_back(m.mk_eq(m.mk_const(e.m_f), e.m_def)); + fmls.push_back(simplify_def(e)); } else { expr_ref_vector args(m); @@ -133,3 +135,34 @@ void generic_model_converter::operator()(expr_ref& fml) { } fml = mk_and(fmls); } + +/* + \brief simplify definition expansion from model converter in the case they come from blocked clauses. + In this case the definitions are of the form: + + x <=> x or not (C) + + or dually, + + x <=> not (not x or not C) + + in either case the definitions simplify to + + x or C + + */ +expr_ref generic_model_converter::simplify_def(entry const& e) { + expr_ref result(m); + expr_ref c(m.mk_const(e.m_f), m); + if (m.is_bool(c) && occurs(c, e.m_def)) { + expr_safe_replace rep(m); + expr_ref result1 = e.m_def; + expr_ref result2 = e.m_def; + rep.apply_substitution(c, m.mk_true(), result1); + rep.apply_substitution(c, m.mk_false(), result2); + return expr_ref(m.mk_and(m.mk_or(c, result2), m.mk_or(m.mk_not(c), result1)), m); + } + else { + return expr_ref(m.mk_eq(c, e.m_def), m); + } +} diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index 805bad0d8..a9043d5cf 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -35,6 +35,9 @@ class generic_model_converter : public model_converter { vector m_add_entries; vector m_hide_entries; obj_map m_first_idx; + + expr_ref simplify_def(entry const& e); + public: generic_model_converter(ast_manager & m) : m(m) {} From f009dfcc007b654b192b3c070ecf056c6ce34bb1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Nov 2017 17:05:08 -0800 Subject: [PATCH 0366/1283] update scoring approach Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index b50d7aa2f..fbd237339 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1452,9 +1452,9 @@ namespace sat { for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; unsigned nonfixed = n->dec_size(); - if (is_true(n->get_head())) continue; + // if (is_true(n->get_head())) continue; if (inconsistent()) continue; - if (nonfixed <= 1) { + if (nonfixed <= 1 && !is_true(n->get_head())) { bool found_conflict = true; for (literal lit : *n) { if (!is_fixed(lit)) { @@ -1473,7 +1473,7 @@ namespace sat { continue; } } - else if (m_search_mode == lookahead_mode::lookahead1) { + if (m_search_mode == lookahead_mode::lookahead1) { SASSERT(nonfixed >= 2); switch (m_config.m_reward_type) { case heule_schur_reward: { From b5ff4602e9996aca0e262edfe1e411e5093651cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Nov 2017 17:50:51 -0800 Subject: [PATCH 0367/1283] fix model converter to include negation Signed-off-by: Nikolaj Bjorner --- src/tactic/generic_model_converter.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 5c0f8ed5c..eb18aa545 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -22,6 +22,7 @@ Notes: #include "ast/ast_util.h" #include "ast/occurs.h" #include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/th_rewriter.h" #include "tactic/generic_model_converter.h" #include "model/model_v2_pp.h" #include "model/model_evaluator.h" @@ -160,7 +161,10 @@ expr_ref generic_model_converter::simplify_def(entry const& e) { expr_ref result2 = e.m_def; rep.apply_substitution(c, m.mk_true(), result1); rep.apply_substitution(c, m.mk_false(), result2); - return expr_ref(m.mk_and(m.mk_or(c, result2), m.mk_or(m.mk_not(c), result1)), m); + th_rewriter rw(m); + expr_ref result(m.mk_and(m.mk_implies(result2, c), m.mk_implies(c, result1)), m); + rw(result); + return result; } else { return expr_ref(m.mk_eq(c, e.m_def), m); From a57628fbccf01cb1fcd21962f508e1983ffab74b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 14:12:05 -0800 Subject: [PATCH 0368/1283] fix missing conversions Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver/inc_sat_solver.cpp | 5 ++--- src/sat/tactic/goal2sat.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 7bbe4d29c..86b7e477d 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -436,9 +436,9 @@ public: virtual model_converter_ref get_model_converter() const { const_cast(this)->convert_internalized(); + if (m_cached_mc) + return m_cached_mc; if (m_internalized && m_internalized_converted) { - if (m_cached_mc) - return m_cached_mc; m_cached_mc = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); m_cached_mc = concat(solver::get_model_converter().get(), m_cached_mc.get()); m_cached_mc = concat(m_cached_mc.get(), m_sat_mc.get()); @@ -452,7 +452,6 @@ public: void convert_internalized() { if (!m_internalized || m_internalized_converted) return; sat2goal s2g; - m_sat_mc = nullptr; m_cached_mc = nullptr; goal g(m, false, true, false); s2g(m_solver, m_map, m_params, g, m_sat_mc); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index a954f08c0..75892d12b 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1183,8 +1183,8 @@ struct sat2goal::imp { ref _mc; if (r.models_enabled()) { _mc = alloc(sat_model_converter, m, s); + mc = _mc.get(); } - mc = _mc.get(); init_lit2expr(s, map, _mc); // collect units unsigned num_vars = s.num_vars(); From 7e56d05dcf4598b04d925ccebd8b786a5722e6ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Nov 2017 15:17:00 -0800 Subject: [PATCH 0369/1283] translation? Signed-off-by: Nikolaj Bjorner --- src/ast/ast_translation.h | 9 ++++++--- src/sat/sat_solver/inc_sat_solver.cpp | 13 +++++++++++-- src/solver/solver.cpp | 4 ++++ src/solver/solver.h | 1 + src/tactic/portfolio/bounded_int2bv_solver.cpp | 6 +++++- src/tactic/portfolio/enum2bv_solver.cpp | 5 +++-- src/tactic/portfolio/pb2bv_solver.cpp | 5 +++-- 7 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/ast/ast_translation.h b/src/ast/ast_translation.h index 886aaf417..9d09fbb76 100644 --- a/src/ast/ast_translation.h +++ b/src/ast/ast_translation.h @@ -50,15 +50,18 @@ class ast_translation { public: ast_translation(ast_manager & from, ast_manager & to, bool copy_plugins = true) : m_from_manager(from), m_to_manager(to) { - if (copy_plugins) - m_to_manager.copy_families_plugins(m_from_manager); - m_to_manager.update_fresh_id(m_from_manager); + if (&from != &to) { + if (copy_plugins) + m_to_manager.copy_families_plugins(m_from_manager); + m_to_manager.update_fresh_id(m_from_manager); + } } ~ast_translation(); template T * operator()(T const * n) { + if (&from() == &to()) return const_cast(n); SASSERT(!n || from().contains(const_cast(n))); ast * r = process(n); SASSERT((!n && !r) || to().contains(const_cast(r))); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 86b7e477d..60f185695 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -108,11 +108,20 @@ public: for (unsigned l : m_fmls_lim) result->m_fmls_lim.push_back(l); for (unsigned a : m_asms_lim) result->m_asms_lim.push_back(a); for (unsigned h : m_fmls_head_lim) result->m_fmls_head_lim.push_back(h); + std::cout << "translate internalized " << m_internalized_fmls.size() << "\n"; + std::cout.flush(); for (expr* f : m_internalized_fmls) result->m_internalized_fmls.push_back(tr(f)); - if (m_mc0.get()) result->m_mc0 = m_mc0->translate(tr); + std::cout << "mc0\n"; + std::cout.flush(); + model_converter_ref mc = concat(mc0(), get_model_converter().get()); + if (mc) { + ast_translation tr(m, dst_m); + result->set_model_converter(mc->translate(tr)); + } + std::cout << "mc1\n"; + std::cout.flush(); result->m_internalized = m_internalized; result->m_internalized_converted = m_internalized_converted; - if (mc0()) result->set_model_converter(mc0()->translate(tr)); return result; } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index eb2b0d016..606c32bed 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -212,3 +212,7 @@ void solver::updt_params(params_ref const & p) { m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", true); } +void solver::hoist_converter(model_converter_ref& mc) { + +} + diff --git a/src/solver/solver.h b/src/solver/solver.h index f6ad74042..2b1824cd3 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -226,6 +226,7 @@ protected: bool is_literal(ast_manager& m, expr* e); + void hoist_converter(model_converter_ref& mc); }; typedef ref solver_ref; diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index a2f4cabe4..0eb5cef18 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -81,7 +81,11 @@ public: for (func_decl* f : m_bv_fns) result->m_bv_fns.push_back(tr(f)); for (func_decl* f : m_int_fns) result->m_int_fns.push_back(tr(f)); for (bound_manager* b : m_bounds) result->m_bounds.push_back(b->translate(dst_m)); - if (mc0()) result->set_model_converter(mc0()->translate(tr)); + model_converter_ref mc = concat(mc0(), m_solver->get_model_converter().get()); + if (mc) { + ast_translation tr(m, dst_m); + result->set_model_converter(mc->translate(tr)); + } return result; } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 4feaa622b..9c522a714 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -50,9 +50,10 @@ public: virtual solver* translate(ast_manager& dst_m, params_ref const& p) { solver* result = alloc(enum2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); - if (mc0()) { + model_converter_ref mc = concat(mc0(), m_solver->get_model_converter().get()); + if (mc) { ast_translation tr(m, dst_m); - result->set_model_converter(mc0()->translate(tr)); + result->set_model_converter(mc->translate(tr)); } return result; } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index ffc1ea09f..e22a41ad3 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -50,9 +50,10 @@ public: virtual solver* translate(ast_manager& dst_m, params_ref const& p) { flush_assertions(); solver* result = alloc(pb2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); - if (mc0()) { + model_converter_ref mc = concat(mc0(), m_solver->get_model_converter().get()); + if (mc) { ast_translation tr(m, dst_m); - result->set_model_converter(mc0()->translate(tr)); + result->set_model_converter(mc->translate(tr)); } return result; } From b3ebcfe55855589d3b2fb4dbeda1310a64a23862 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 29 Nov 2017 18:20:59 -0500 Subject: [PATCH 0370/1283] correctly check third argument of str.indexof in theory_str --- src/smt/theory_str.cpp | 47 ++++++++++++++++++++++-------------------- src/smt/theory_str.h | 2 +- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 7936b581c..a931ae458 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -641,7 +641,6 @@ namespace smt { } app * theory_str::mk_indexof(expr * haystack, expr * needle) { - // TODO check meaning of the third argument here app * indexof = u.str.mk_index(haystack, needle, mk_int(0)); m_trail.push_back(indexof); // immediately force internalization so that axiom setup does not fail @@ -844,14 +843,7 @@ namespace smt { instantiate_axiom_Contains(e); } else if (u.str.is_index(a)) { instantiate_axiom_Indexof(e); - /* TODO NEXT: Indexof2/Lastindexof rewrite? - } else if (is_Indexof2(e)) { - instantiate_axiom_Indexof2(e); - } else if (is_LastIndexof(e)) { - instantiate_axiom_LastIndexof(e); - */ } else if (u.str.is_extract(a)) { - // TODO check semantics of substr vs. extract instantiate_axiom_Substr(e); } else if (u.str.is_replace(a)) { instantiate_axiom_Replace(e); @@ -1232,27 +1224,37 @@ namespace smt { context & ctx = get_context(); ast_manager & m = get_manager(); - app * expr = e->get_owner(); - if (axiomatized_terms.contains(expr)) { - TRACE("str", tout << "already set up Indexof axiom for " << mk_pp(expr, m) << std::endl;); + app * ex = e->get_owner(); + if (axiomatized_terms.contains(ex)) { + TRACE("str", tout << "already set up str.indexof axiom for " << mk_pp(ex, m) << std::endl;); return; } - axiomatized_terms.insert(expr); + SASSERT(ex->get_num_args() == 3); + // if the third argument is exactly the integer 0, we can use this "simple" indexof; + // otherwise, we call the "extended" version + expr * startingPosition = ex->get_arg(2); + rational startingInteger; + if (!m_autil.is_numeral(startingPosition, startingInteger) || !startingInteger.is_zero()) { + // "extended" indexof term with prefix + instantiate_axiom_Indexof_extended(e); + return; + } + axiomatized_terms.insert(ex); - TRACE("str", tout << "instantiate Indexof axiom for " << mk_pp(expr, m) << std::endl;); + TRACE("str", tout << "instantiate str.indexof axiom for " << mk_pp(ex, m) << std::endl;); expr_ref x1(mk_str_var("x1"), m); expr_ref x2(mk_str_var("x2"), m); expr_ref indexAst(mk_int_var("index"), m); - expr_ref condAst(mk_contains(expr->get_arg(0), expr->get_arg(1)), m); + expr_ref condAst(mk_contains(ex->get_arg(0), ex->get_arg(1)), m); SASSERT(condAst); // ----------------------- // true branch expr_ref_vector thenItems(m); // args[0] = x1 . args[1] . x2 - thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x1, mk_concat(expr->get_arg(1), x2)))); + thenItems.push_back(ctx.mk_eq_atom(ex->get_arg(0), mk_concat(x1, mk_concat(ex->get_arg(1), x2)))); // indexAst = |x1| thenItems.push_back(ctx.mk_eq_atom(indexAst, mk_strlen(x1))); // args[0] = x3 . x4 @@ -1260,11 +1262,11 @@ namespace smt { // /\ ! contains(x3, args[1]) expr_ref x3(mk_str_var("x3"), m); expr_ref x4(mk_str_var("x4"), m); - expr_ref tmpLen(m_autil.mk_add(indexAst, mk_strlen(expr->get_arg(1)), mk_int(-1)), m); + expr_ref tmpLen(m_autil.mk_add(indexAst, mk_strlen(ex->get_arg(1)), mk_int(-1)), m); SASSERT(tmpLen); - thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); + thenItems.push_back(ctx.mk_eq_atom(ex->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); - thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x3, ex->get_arg(1)))); expr_ref thenBranch(m.mk_and(thenItems.size(), thenItems.c_ptr()), m); SASSERT(thenBranch); @@ -1276,7 +1278,7 @@ namespace smt { expr_ref breakdownAssert(m.mk_ite(condAst, thenBranch, elseBranch), m); SASSERT(breakdownAssert); - expr_ref reduceToIndex(ctx.mk_eq_atom(expr, indexAst), m); + expr_ref reduceToIndex(ctx.mk_eq_atom(ex, indexAst), m); SASSERT(reduceToIndex); expr_ref finalAxiom(m.mk_and(breakdownAssert, reduceToIndex), m); @@ -1284,18 +1286,19 @@ namespace smt { assert_axiom(finalAxiom); } - void theory_str::instantiate_axiom_Indexof2(enode * e) { + void theory_str::instantiate_axiom_Indexof_extended(enode * e) { context & ctx = get_context(); ast_manager & m = get_manager(); app * expr = e->get_owner(); if (axiomatized_terms.contains(expr)) { - TRACE("str", tout << "already set up Indexof2 axiom for " << mk_pp(expr, m) << std::endl;); + TRACE("str", tout << "already set up extended str.indexof axiom for " << mk_pp(expr, m) << std::endl;); return; } + SASSERT(expr->get_num_args() == 3); axiomatized_terms.insert(expr); - TRACE("str", tout << "instantiate Indexof2 axiom for " << mk_pp(expr, m) << std::endl;); + TRACE("str", tout << "instantiate extended str.indexof axiom for " << mk_pp(expr, m) << std::endl;); // ------------------------------------------------------------------------------- // if (arg[2] >= length(arg[0])) // ite2 diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 03fd31162..dd2ca585b 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -447,7 +447,7 @@ protected: void instantiate_axiom_suffixof(enode * e); void instantiate_axiom_Contains(enode * e); void instantiate_axiom_Indexof(enode * e); - void instantiate_axiom_Indexof2(enode * e); + void instantiate_axiom_Indexof_extended(enode * e); void instantiate_axiom_LastIndexof(enode * e); void instantiate_axiom_Substr(enode * e); void instantiate_axiom_Replace(enode * e); From cba0599046763d48d6ac8696c659ac6e23f350be Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Wed, 29 Nov 2017 17:14:49 -0800 Subject: [PATCH 0371/1283] model converter fixes Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_solver/inc_sat_solver.cpp | 15 ++--- src/sat/tactic/goal2sat.cpp | 86 +++++++++++---------------- 2 files changed, 39 insertions(+), 62 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 60f185695..1eee15893 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -108,18 +108,11 @@ public: for (unsigned l : m_fmls_lim) result->m_fmls_lim.push_back(l); for (unsigned a : m_asms_lim) result->m_asms_lim.push_back(a); for (unsigned h : m_fmls_head_lim) result->m_fmls_head_lim.push_back(h); - std::cout << "translate internalized " << m_internalized_fmls.size() << "\n"; - std::cout.flush(); for (expr* f : m_internalized_fmls) result->m_internalized_fmls.push_back(tr(f)); - std::cout << "mc0\n"; - std::cout.flush(); - model_converter_ref mc = concat(mc0(), get_model_converter().get()); - if (mc) { - ast_translation tr(m, dst_m); - result->set_model_converter(mc->translate(tr)); - } - std::cout << "mc1\n"; - std::cout.flush(); + if (m_mc) result->m_mc = m_mc->translate(tr); + if (m_mc0) result->m_mc0 = m_mc0->translate(tr); + //if (m_sat_mc) result->m_sat_mc = m_sat_mc->translate(tr); MN: commenting this line removes bloat + // copy m_bb_rewriter? result->m_internalized = m_internalized; result->m_internalized_converted = m_internalized_converted; return result; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 75892d12b..648bd3cf1 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -891,6 +891,35 @@ struct sat2goal::imp { m_var2expr(m) { } + void ensure_imc() { + if (m_imc) return; + m_imc = alloc(generic_model_converter, m()); + sat::literal_vector updates; + m_mc.expand(updates); + sat::literal_vector clause; + expr_ref_vector tail(m()); + expr_ref def(m()); + for (sat::literal l : updates) { + if (l == sat::null_literal) { + sat::literal lit0 = clause[0]; + for (unsigned i = 1; i < clause.size(); ++i) { + tail.push_back(lit2expr(~clause[i])); + } + def = m().mk_or(lit2expr(lit0), mk_and(tail)); + if (lit0.sign()) { + lit0.neg(); + def = m().mk_not(def); + } + m_imc->add(lit2expr(lit0), def); + clause.reset(); + tail.reset(); + } + else { + clause.push_back(l); + } + } + } + public: sat_model_converter(ast_manager & m, sat::solver const & s):m_var2expr(m) { m_mc.copy(s.get_model_converter()); @@ -979,6 +1008,7 @@ struct sat2goal::imp { virtual model_converter * translate(ast_translation & translator) { sat_model_converter * res = alloc(sat_model_converter, translator.to()); + res->m_mc = m_mc; res->m_fmc = static_cast(m_fmc->translate(translator)); for (expr* e : m_var2expr) res->m_var2expr.push_back(e ? translator(e) : nullptr); @@ -995,30 +1025,8 @@ struct sat2goal::imp { } void display(std::ostream & out) { - sat::literal_vector updates; - m_mc.expand(updates); - sat::literal_vector clause; - expr_ref_vector tail(m()); - expr_ref def(m()); - for (sat::literal l : updates) { - if (l == sat::null_literal) { - sat::literal lit0 = clause[0]; - for (unsigned i = 1; i < clause.size(); ++i) { - tail.push_back(lit2expr(~clause[i])); - } - def = m().mk_or(lit2expr(lit0), mk_and(tail)); - if (lit0.sign()) { - lit0.neg(); - def = m().mk_not(def); - } - display_add(out, m(), to_app(lit2expr(lit0))->get_decl(), def); - clause.reset(); - tail.reset(); - } - else { - clause.push_back(l); - } - } + ensure_imc(); + m_imc->display(out); m_fmc->display(out); } @@ -1026,36 +1034,12 @@ struct sat2goal::imp { m_env = &visitor.env(); for (expr* e : m_var2expr) if (e) visitor.coll.visit(e); if (m_fmc) m_fmc->collect(visitor); + ensure_imc(); + m_imc->collect(visitor); } void operator()(expr_ref& formula) override { - if (!m_imc) { - m_imc = alloc(generic_model_converter, m()); - sat::literal_vector updates; - m_mc.expand(updates); - sat::literal_vector clause; - expr_ref_vector tail(m()); - expr_ref def(m()); - for (sat::literal l : updates) { - if (l == sat::null_literal) { - sat::literal lit0 = clause[0]; - for (unsigned i = 1; i < clause.size(); ++i) { - tail.push_back(lit2expr(~clause[i])); - } - def = m().mk_or(lit2expr(lit0), mk_and(tail)); - if (lit0.sign()) { - lit0.neg(); - def = m().mk_not(def); - } - m_imc->add(lit2expr(lit0), def); - clause.reset(); - tail.reset(); - } - else { - clause.push_back(l); - } - } - } + ensure_imc(); (*m_imc)(formula); } }; From a4dc68766db8a07676ce3cb4f0842558d46e94a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Nov 2017 17:16:15 -0800 Subject: [PATCH 0372/1283] preparing for more efficient asymmetric branching Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- src/sat/sat_asymm_branch.cpp | 42 +++++++++++++++------------ src/sat/sat_asymm_branch.h | 2 ++ src/sat/sat_config.cpp | 2 ++ src/sat/sat_config.h | 2 ++ src/sat/sat_lookahead.cpp | 9 ++++++ src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 2 ++ src/sat/sat_solver.h | 4 +-- src/tactic/aig/aig.cpp | 6 ++-- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 11 files changed, 47 insertions(+), 27 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 9819af47f..f15386a93 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6335,7 +6335,7 @@ class Solver(Z3PPObject): def from_string(self, s): """Parse assertions from a string""" - Z3_solver_from_string(self.ctx.ref(), self.solver, filename) + Z3_solver_from_string(self.ctx.ref(), self.solver, s) def assertions(self): """Return an AST vector containing all added constraints. diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index abf1d95be..aed29312a 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -56,25 +56,8 @@ namespace sat { << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } }; - - void asymm_branch::operator()(bool force) { - ++m_calls; - if (m_calls <= 1) - return; - if (!m_asymm_branch && !m_asymm_branch_all) - return; - s.propagate(false); // must propagate, since it uses s.push() - if (s.m_inconsistent) - return; - if (!force && m_counter > 0) { - m_counter /= 100; - return; - } - CASSERT("asymm_branch", s.check_invariant()); - TRACE("asymm_branch_detail", s.display(tout);); - report rpt(*this); - svector saved_phase(s.m_phase); - m_counter = 0; + + void asymm_branch::process(clause_vector& clauses) { int64 limit = -m_asymm_branch_limit; std::stable_sort(s.m_clauses.begin(), s.m_clauses.end(), clause_size_lt()); m_counter -= s.m_clauses.size(); @@ -114,6 +97,27 @@ namespace sat { m_counter = -m_counter; throw ex; } + } + + void asymm_branch::operator()(bool force) { + ++m_calls; + if (m_calls <= 1) + return; + if (!m_asymm_branch && !m_asymm_branch_all) + return; + s.propagate(false); // must propagate, since it uses s.push() + if (s.m_inconsistent) + return; + if (!force && m_counter > 0) { + m_counter /= 100; + return; + } + CASSERT("asymm_branch", s.check_invariant()); + TRACE("asymm_branch_detail", s.display(tout);); + report rpt(*this); + svector saved_phase(s.m_phase); + m_counter = 0; + process(s.m_clauses); m_counter = -m_counter; s.m_phase = saved_phase; m_asymm_branch_limit *= 2; diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index a6e44a4e2..0de4c8d99 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -44,6 +44,8 @@ namespace sat { unsigned m_elim_literals; bool process(clause & c); + + void process(clause_vector & c); bool process_all(clause & c); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index b672fe065..24d2bca9b 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -176,6 +176,8 @@ namespace sat { m_reward_multiplier = 0.9; m_reward_offset = 1000000.0; + m_variable_decay = p.variable_decay(); + // PB parameters s = p.pb_solver(); if (s == symbol("circuit")) { diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 132b85b24..9a20bbc63 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -95,6 +95,8 @@ namespace sat { double m_simplify_mult2; unsigned m_simplify_max; + unsigned m_variable_decay; + gc_strategy m_gc_strategy; unsigned m_gc_initial; unsigned m_gc_increment; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index fbd237339..306912b57 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2303,7 +2303,16 @@ namespace sat { */ void lookahead::add_hyper_binary() { + + std::cout << "binary trail size: " << m_binary_trail.size() << "\n"; + std::cout << "Are windfalls still on the trail at base level?\n"; unsigned num_lits = m_s.num_vars() * 2; + unsigned_vector bin_size(num_lits); + for (unsigned idx : m_binary_trail) { + bin_size[idx]++; + } + + union_find_default_ctx ufctx; union_find uf(ufctx); for (unsigned i = 0; i < num_lits; ++i) uf.mk_var(); diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 887cea2a7..4f65b100b 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -9,6 +9,7 @@ def_module_params('sat', ('restart.initial', UINT, 100, 'initial restart (number of conflicts)'), ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), + ('variable_decay', UINT, 120, 'multiplier (divided by 100) for the VSIDS activity increement'), ('inprocess.max', UINT, UINT_MAX, 'maximal number of inprocessing passes'), ('branching.heuristic', SYMBOL, 'vsids', 'branching heuristic vsids, lrb or chb'), ('branching.anti_exploration', BOOL, False, 'apply anti-exploration heuristic for branch selection'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e4d239605..89acdc408 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1415,6 +1415,7 @@ namespace sat { m_next_simplify = 0; m_min_d_tk = 1.0; m_search_lvl = 0; + m_conflicts_since_gc = 0; m_asymm_branch.init_search(); m_stopwatch.reset(); m_stopwatch.start(); @@ -1660,6 +1661,7 @@ namespace sat { void solver::gc() { if (m_conflicts_since_gc <= m_gc_threshold) return; + IF_VERBOSE(1, verbose_stream() << "gc\n";); CASSERT("sat_gc_bug", check_invariant()); switch (m_config.m_gc_strategy) { case GC_GLUE: diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 45f91e7a8..0d65de1e1 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -575,8 +575,8 @@ namespace sat { } void decay_activity() { - m_activity_inc *= 11; - m_activity_inc /= 10; + m_activity_inc *= m_config.m_variable_decay; + m_activity_inc /= 100; } private: diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index e8226e159..067e7445e 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -635,10 +635,8 @@ struct aig_manager::imp { } bool check_cache() const { - obj_map::iterator it = m_cache.begin(); - obj_map::iterator end = m_cache.end(); - for (; it != end; ++it) { - SASSERT(ref_count(it->m_value) > 0); + for (auto const& kv : m_cache) { + SASSERT(ref_count(kv.m_value) > 0); } return true; } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index e22a41ad3..96656ef00 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -50,7 +50,7 @@ public: virtual solver* translate(ast_manager& dst_m, params_ref const& p) { flush_assertions(); solver* result = alloc(pb2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); - model_converter_ref mc = concat(mc0(), m_solver->get_model_converter().get()); + model_converter_ref mc = mc0(); if (mc) { ast_translation tr(m, dst_m); result->set_model_converter(mc->translate(tr)); From da0aa710827912f1a8e6579285ed18283174ea1a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Nov 2017 21:21:56 -0800 Subject: [PATCH 0373/1283] adding uhle/uhte for faster asymmetric branching Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 124 ++++++++++++++++++++++++++++++++--- src/sat/sat_asymm_branch.h | 29 ++++++-- src/sat/sat_scc.cpp | 99 ++++++++++++++++------------ src/sat/sat_scc.h | 26 +++++++- 4 files changed, 221 insertions(+), 57 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index aed29312a..f88f4c5a7 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -19,6 +19,7 @@ Revision History: #include "sat/sat_asymm_branch.h" #include "sat/sat_asymm_branch_params.hpp" #include "sat/sat_solver.h" +#include "sat/sat_scc.h" #include "util/stopwatch.h" #include "util/trace.h" @@ -26,6 +27,7 @@ namespace sat { asymm_branch::asymm_branch(solver & _s, params_ref const & p): s(_s), + m_params(p), m_counter(0) { updt_params(p); reset_statistics(); @@ -59,12 +61,12 @@ namespace sat { void asymm_branch::process(clause_vector& clauses) { int64 limit = -m_asymm_branch_limit; - std::stable_sort(s.m_clauses.begin(), s.m_clauses.end(), clause_size_lt()); - m_counter -= s.m_clauses.size(); + std::stable_sort(clauses.begin(), clauses.end(), clause_size_lt()); + m_counter -= clauses.size(); SASSERT(s.m_qhead == s.m_trail.size()); - clause_vector::iterator it = s.m_clauses.begin(); + clause_vector::iterator it = clauses.begin(); clause_vector::iterator it2 = it; - clause_vector::iterator end = s.m_clauses.end(); + clause_vector::iterator end = clauses.end(); try { for (; it != end; ++it) { if (s.inconsistent()) { @@ -86,14 +88,14 @@ namespace sat { *it2 = *it; ++it2; } - s.m_clauses.set_end(it2); + clauses.set_end(it2); } catch (solver_exception & ex) { // put m_clauses in a consistent state... for (; it != end; ++it, ++it2) { *it2 = *it; } - s.m_clauses.set_end(it2); + clauses.set_end(it2); m_counter = -m_counter; throw ex; } @@ -143,6 +145,99 @@ namespace sat { return true; } + void asymm_branch::setup_big() { + scc scc(s, m_params); + vector const& big = scc.get_big(true); // include learned binary clauses + + } + + struct asymm_branch::compare_left { + scc& s; + compare_left(scc& s): s(s) {} + bool operator()(literal u, literal v) const { + return s.get_left(u) < s.get_left(v); + } + }; + + void asymm_branch::sort(scc& scc, clause const& c) { + m_pos.reset(); m_neg.reset(); + for (literal l : c) { + m_pos.push_back(l); + m_neg.push_back(~l); + } + compare_left cmp(scc); + std::sort(m_pos.begin(), m_pos.end(), cmp); + std::sort(m_neg.begin(), m_neg.end(), cmp); + } + + bool asymm_branch::uhte(scc& scc, clause & c) { + unsigned pindex = 0, nindex = 0; + literal lpos = m_pos[pindex++]; + literal lneg = m_neg[nindex++]; + while (true) { + if (scc.get_left(lneg) > scc.get_left(lpos)) { + if (pindex == m_pos.size()) return false; + lpos = m_pos[pindex++]; + } + else if (scc.get_right(lneg) < scc.get_right(lpos) || + (m_pos.size() == 2 && (lpos == ~lneg || scc.get_parent(lpos) == lneg))) { + if (nindex == m_neg.size()) return false; + lneg = m_neg[nindex++]; + } + else { + return true; + } + } + return false; + } + + bool asymm_branch::uhle(scoped_detach& scoped_d, scc& scc, clause & c) { + int right = scc.get_right(m_pos.back()); + m_to_delete.reset(); + for (unsigned i = m_pos.size() - 1; i-- > 0; ) { + literal lit = m_pos[i]; + SASSERT(scc.get_left(lit) < scc.get_left(last)); + int right2 = scc.get_right(lit); + if (right2 > right) { + // lit => last, so lit can be deleted + m_to_delete.push_back(lit); + } + else { + right = right2; + } + } + right = scc.get_right(m_neg[0]); + for (unsigned i = 1; i < m_neg.size(); ++i) { + literal lit = m_neg[i]; + int right2 = scc.get_right(lit); + if (right > right2) { + // ~first => ~lit + m_to_delete.push_back(~lit); + } + else { + right = right2; + } + } + if (!m_to_delete.empty()) { + unsigned j = 0; + for (unsigned i = 0; i < c.size(); ++i) { + if (!m_to_delete.contains(c[i])) { + c[j] = c[i]; + ++j; + } + else { + m_pos.erase(c[i]); + m_neg.erase(~c[i]); + } + } + return re_attach(scoped_d, c, j); + } + else { + return true; + } + } + + bool asymm_branch::propagate_literal(clause const& c, literal l) { SASSERT(!s.inconsistent()); TRACE("asymm_branch_detail", tout << "assigning: " << l << "\n";); @@ -190,8 +285,12 @@ namespace sat { new_sz = j; m_elim_literals += c.size() - new_sz; // std::cout << "cleanup: " << c.id() << ": " << literal_vector(new_sz, c.begin()) << " delta: " << (c.size() - new_sz) << " " << skip_idx << " " << new_sz << "\n"; - switch(new_sz) { - case 0: + return re_attach(scoped_d, c, new_sz); + } + + bool asymm_branch::re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz) { + switch(new_sz) { + case 0: s.set_conflict(justification()); return false; case 1: @@ -216,6 +315,15 @@ namespace sat { } } + bool asymm_branch::process2(scc& scc, clause & c) { + scoped_detach scoped_d(s, c); + if (uhte(scc, c)) { + scoped_d.del_clause(); + return false; + } + return uhle(scoped_d, scc, c); + } + bool asymm_branch::process(clause & c) { if (c.is_blocked()) return true; TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";); diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 0de4c8d99..87e5cbac5 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -20,6 +20,7 @@ Revision History: #define SAT_ASYMM_BRANCH_H_ #include "sat/sat_types.h" +#include "sat/sat_scc.h" #include "util/statistics.h" #include "util/params.h" @@ -30,21 +31,37 @@ namespace sat { class asymm_branch { struct report; - solver & s; + solver & s; + params_ref m_params; int64 m_counter; random_gen m_rand; unsigned m_calls; // config - bool m_asymm_branch; - bool m_asymm_branch_all; - int64 m_asymm_branch_limit; + bool m_asymm_branch; + bool m_asymm_branch_all; + int64 m_asymm_branch_limit; // stats - unsigned m_elim_literals; + unsigned m_elim_literals; + + literal_vector m_pos, m_neg; // literals (complements of literals) in clauses sorted by discovery time (m_left in scc). + literal_vector m_to_delete; + + struct compare_left; + + void sort(scc & scc, clause const& c); + + bool uhle(scoped_detach& scoped_d, scc & scc, clause & c); + + bool uhte(scc & scc, clause & c); + + bool re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz); bool process(clause & c); + bool process2(scc& scc, clause & c); + void process(clause_vector & c); bool process_all(clause & c); @@ -55,6 +72,8 @@ namespace sat { bool propagate_literal(clause const& c, literal l); + void setup_big(); + public: asymm_branch(solver & s, params_ref const & p); diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index df574f4a8..9da54da29 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -234,58 +234,70 @@ namespace sat { return to_elim.size(); } - void scc::get_dfs_num(svector& dfs, bool learned) { - unsigned num_lits = m_solver.num_vars() * 2; - vector dag(num_lits); - svector roots(num_lits, true); - literal_vector todo; - SASSERT(dfs.size() == num_lits); - unsigned num_edges = 0; + // shuffle vertices to obtain different DAG traversal each time + void scc::shuffle(literal_vector& lits) { + unsigned sz = lits.size(); + if (sz > 1) { + for (unsigned i = sz; i-- > 0; ) { + std::swap(lits[i], lits[m_rand(i+1)]); + } + } + } - // retrieve DAG + vector const& scc::get_big(bool learned) { + unsigned num_lits = m_solver.num_vars() * 2; + m_dag.reset(); + m_roots.reset(); + m_dag.resize(num_lits, 0); + m_roots.resize(num_lits, true); + SASSERT(num_lits == m_dag.size() && num_lits == m_roots.size()); for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { - literal u(to_literal(l_idx)); + literal u = to_literal(l_idx); if (m_solver.was_eliminated(u.var())) continue; - auto& edges = dag[u.index()]; + auto& edges = m_dag[l_idx]; for (watched const& w : m_solver.m_watches[l_idx]) { if (learned ? w.is_binary_clause() : w.is_binary_unblocked_clause()) { literal v = w.get_literal(); - roots[v.index()] = false; + m_roots[v.index()] = false; edges.push_back(v); - ++num_edges; - } - } - unsigned sz = edges.size(); - // shuffle vertices to obtain different DAG traversal each time - if (sz > 1) { - for (unsigned i = sz; i-- > 0; ) { - std::swap(edges[i], edges[m_rand(i+1)]); } } + shuffle(edges); } - // std::cout << "dag num edges: " << num_edges << "\n"; + return m_dag; + } + + void scc::get_dfs_num(bool learned) { + unsigned num_lits = m_solver.num_vars() * 2; + SASSERT(m_left.size() == num_lits); + SASSERT(m_right.size() == num_lits); + literal_vector todo; // retrieve literals that have no predecessors for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { literal u(to_literal(l_idx)); - if (roots[u.index()]) todo.push_back(u); + if (m_roots[u.index()]) todo.push_back(u); } - // std::cout << "num roots: " << roots.size() << "\n"; - // traverse DAG, annotate nodes with DFS number + shuffle(todo); int dfs_num = 0; while (!todo.empty()) { literal u = todo.back(); - int& d = dfs[u.index()]; + int& d = m_left[u.index()]; // already visited if (d > 0) { + if (m_right[u.index()] < 0) { + m_right[u.index()] = dfs_num; + } todo.pop_back(); } // visited as child: else if (d < 0) { d = -d; - for (literal v : dag[u.index()]) { - if (dfs[v.index()] == 0) { - dfs[v.index()] = - d - 1; + for (literal v : m_dag[u.index()]) { + if (m_left[v.index()] == 0) { + m_left[v.index()] = - d - 1; + m_root[v.index()] = m_root[u.index()]; + m_parent[v.index()] = u; todo.push_back(v); } } @@ -297,9 +309,21 @@ namespace sat { } } - bool scc::reduce_tr(svector const& dfs, bool learned) { + unsigned scc::reduce_tr(bool learned) { + unsigned num_lits = m_solver.num_vars() * 2; + m_left.reset(); + m_right.reset(); + m_root.reset(); + m_parent.reset(); + m_left.resize(num_lits, 0); + m_right.resize(num_lits, -1); + for (unsigned i = 0; i < num_lits; ++i) { + m_root[i] = to_literal(i); + m_parent[i] = to_literal(i); + } + get_dfs_num(learned); unsigned idx = 0; - bool reduced = false; + unsigned elim = m_num_elim_bin; for (watch_list & wlist : m_solver.m_watches) { literal u = to_literal(idx++); watch_list::iterator it = wlist.begin(); @@ -309,9 +333,8 @@ namespace sat { watched& w = *it; if (learned ? w.is_binary_learned_clause() : w.is_binary_unblocked_clause()) { literal v = w.get_literal(); - if (dfs[u.index()] + 1 < dfs[v.index()]) { + if (m_left[u.index()] + 1 < m_left[v.index()]) { ++m_num_elim_bin; - reduced = true; } else { *itprev = *it; @@ -325,19 +348,13 @@ namespace sat { } wlist.set_end(itprev); } - return reduced; - } - - bool scc::reduce_tr(bool learned) { - unsigned num_lits = m_solver.num_vars() * 2; - svector dfs(num_lits); - get_dfs_num(dfs, learned); - return reduce_tr(dfs, learned); + return m_num_elim_bin - elim; } void scc::reduce_tr() { - while (reduce_tr(false)) {} - while (reduce_tr(true)) {} + unsigned quota = 0, num_reduced = 0; + while ((num_reduced = reduce_tr(false)) > quota) { quota = std::max(100u, num_reduced / 2); } + while ((num_reduced = reduce_tr(true)) > quota) { quota = std::max(100u, num_reduced / 2); } } void scc::collect_statistics(statistics & st) const { diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index cfad76d71..806cf8f33 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -37,12 +37,19 @@ namespace sat { unsigned m_num_elim_bin; random_gen m_rand; - void get_dfs_num(svector& dfs, bool learned); + // BIG state: + + vector m_dag; + svector m_roots; + svector m_left, m_right; + literal_vector m_root, m_parent; + + void shuffle(literal_vector& lits); void reduce_tr(); - bool reduce_tr(bool learned); - bool reduce_tr(svector const& dfs, bool learned); + unsigned reduce_tr(bool learned); public: + scc(solver & s, params_ref const & p); unsigned operator()(); @@ -51,6 +58,19 @@ namespace sat { void collect_statistics(statistics & st) const; void reset_statistics(); + + /* + \brief retrieve binary implication graph + */ + vector const& get_big(bool learned); + + int get_left(literal l) const { return m_left[l.index()]; } + int get_right(literal l) const { return m_right[l.index()]; } + literal get_parent(literal l) const { return m_parent[l.index()]; } + literal get_root(literal l) const { return m_root[l.index()]; } + + void get_dfs_num(bool learned); + }; }; From 427b5ef0025ba99f0ab27a3d03be531913e3733f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 30 Nov 2017 11:20:19 -0800 Subject: [PATCH 0374/1283] set eliminated to false on literals used in clauses Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 2 +- src/sat/sat_solver.h | 1 + src/sat/tactic/goal2sat.cpp | 1 + src/solver/solver.cpp | 4 ++-- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index cb659247f..ea44c870d 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -96,7 +96,7 @@ namespace sat { // apply substitution for (i = 0; i < sz; i++) { c[i] = norm(roots, c[i]); - VERIFY(c[i] == norm(roots, c[i])); + VERIFY(c[i] == norm(roots, c[i])); VERIFY(!m_solver.was_eliminated(c[i].var())); } std::sort(c.begin(), c.end()); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 0d65de1e1..7cadffd27 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -266,6 +266,7 @@ namespace sat { void set_external(bool_var v); void set_non_external(bool_var v); bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } + void set_eliminated(bool_var v, bool f) { m_eliminated[v] = f; } unsigned scope_lvl() const { return m_scope_lvl; } unsigned search_lvl() const { return m_search_lvl; } bool at_search_lvl() const { return m_scope_lvl == m_search_lvl; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 648bd3cf1..3e2abf8e8 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -151,6 +151,7 @@ struct goal2sat::imp { else { SASSERT(v != sat::null_bool_var); l = sat::literal(v, sign); + m_solver.set_eliminated(v, false); } SASSERT(l != sat::null_literal); if (root) diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 606c32bed..43ca9870a 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -204,12 +204,12 @@ void solver::assert_expr(expr* f, expr* t) { } void solver::collect_param_descrs(param_descrs & r) { - r.insert("solver.enforce_model_conversion", CPK_BOOL, "(default: true) enforce model conversion when asserting formulas"); + r.insert("solver.enforce_model_conversion", CPK_BOOL, "(default: false) enforce model conversion when asserting formulas"); } void solver::updt_params(params_ref const & p) { m_params.copy(p); - m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", true); + m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); } void solver::hoist_converter(model_converter_ref& mc) { From 018411bc5816c1655f20193663ae643d990cd169 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 08:23:55 -0800 Subject: [PATCH 0375/1283] fix bug in PB constraint init_watch handling, adding transitive reduction, HLE, ULT, Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 53 ++++++------ src/sat/ba_solver.h | 8 +- src/sat/sat_asymm_branch.cpp | 81 +++++++++++++------ src/sat/sat_asymm_branch.h | 8 +- src/sat/sat_asymm_branch_params.pyg | 2 + src/sat/sat_lookahead.cpp | 94 +++++++++++++++++++--- src/sat/sat_scc.cpp | 120 +++++++++++++++------------- src/sat/sat_scc.h | 14 ++-- src/sat/sat_simplifier_params.pyg | 2 +- src/sat/sat_solver.h | 2 +- 10 files changed, 248 insertions(+), 136 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index a1a80df97..05dde2331 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -216,12 +216,12 @@ namespace sat { // ---------------------------- // card - bool ba_solver::init_watch(card& c, bool is_true) { + bool ba_solver::init_watch(card& c) { clear_watch(c); literal root = c.lit(); - if (root != null_literal && root.sign() == is_true) { + if (root != null_literal && value(root) == l_false) { c.negate(); - root.neg(); + root.neg(); } if (root != null_literal) { if (!is_watched(root, c)) watch_literal(root, c); @@ -352,7 +352,7 @@ namespace sat { IF_VERBOSE(100, display(verbose_stream() << "nullify tracking literal\n", p, true);); SASSERT(lvl(p.lit()) == 0); nullify_tracking_literal(p); - init_watch(p, true); + init_watch(p); } SASSERT(p.lit() == null_literal || value(p.lit()) != l_false); @@ -379,7 +379,7 @@ namespace sat { } else if (true_val == 0 && num_false == 0) { if (p.lit() == null_literal || value(p.lit()) == l_true) { - init_watch(p, true); + init_watch(p); } } else if (true_val >= p.k()) { @@ -431,7 +431,7 @@ namespace sat { return; } else if (p.lit() == null_literal || value(p.lit()) == l_true) { - init_watch(p, true); + init_watch(p); } else { SASSERT(value(p.lit()) == l_undef); @@ -510,13 +510,13 @@ namespace sat { // watch a prefix of literals, such that the slack of these is >= k - bool ba_solver::init_watch(pb& p, bool is_true) { + bool ba_solver::init_watch(pb& p) { clear_watch(p); - if (p.lit() != null_literal && p.lit().sign() == is_true) { - p.negate(); + if (p.lit() != null_literal && value(p.lit()) == l_false) { + p.negate(); } - SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); + VERIFY(p.lit() == null_literal || value(p.lit()) == l_true); unsigned sz = p.size(), bound = p.k(); // put the non-false literals into the head. @@ -548,7 +548,7 @@ namespace sat { if (slack < bound) { literal lit = p[j].second; - SASSERT(value(lit) == l_false); + VERIFY(value(lit) == l_false); for (unsigned i = j + 1; i < sz; ++i) { if (lvl(lit) < lvl(p[i].second)) { lit = p[i].second; @@ -826,7 +826,7 @@ namespace sat { SASSERT(p.well_formed()); if (p.lit() == null_literal || value(p.lit()) == l_true) { - init_watch(p, true); + init_watch(p); } } } @@ -909,9 +909,9 @@ namespace sat { return odd; } - bool ba_solver::init_watch(xor& x, bool is_true) { + bool ba_solver::init_watch(xor& x) { clear_watch(x); - if (x.lit() != null_literal && x.lit().sign() == is_true) { + if (x.lit() != null_literal && value(x.lit()) == l_false) { x.negate(); } TRACE("ba", display(tout, x, true);); @@ -1566,7 +1566,7 @@ namespace sat { m_constraint_to_reinit.push_back(c); } else if (lit == null_literal) { - init_watch(*c, true); + init_watch(*c); } else { if (m_solver) m_solver->set_external(lit.var()); @@ -1577,12 +1577,12 @@ namespace sat { } - bool ba_solver::init_watch(constraint& c, bool is_true) { + bool ba_solver::init_watch(constraint& c) { if (inconsistent()) return false; switch (c.tag()) { - case card_t: return init_watch(c.to_card(), is_true); - case pb_t: return init_watch(c.to_pb(), is_true); - case xor_t: return init_watch(c.to_xor(), is_true); + case card_t: return init_watch(c.to_card()); + case pb_t: return init_watch(c.to_pb()); + case xor_t: return init_watch(c.to_xor()); } UNREACHABLE(); return false; @@ -1642,7 +1642,7 @@ namespace sat { constraint& c = index2constraint(idx); TRACE("ba", tout << l << "\n";); if (c.lit() != null_literal && l.var() == c.lit().var()) { - init_watch(c, !l.sign()); + init_watch(c); return true; } else if (c.lit() != null_literal && value(c.lit()) != l_true) { @@ -2358,7 +2358,7 @@ namespace sat { unsigned sz = m_constraint_to_reinit_last_sz; for (unsigned i = sz; i < m_constraint_to_reinit.size(); ++i) { constraint* c = m_constraint_to_reinit[i]; - if (!init_watch(*c, true) && !s().at_base_lvl()) { + if (!init_watch(*c) && !s().at_base_lvl()) { m_constraint_to_reinit[sz++] = c; } } @@ -2677,7 +2677,7 @@ namespace sat { } else { if (c.lit() == null_literal || value(c.lit()) == l_true) { - init_watch(c, true); + init_watch(c); } SASSERT(c.lit() == null_literal || is_watched(c.lit(), c)); SASSERT(c.well_formed()); @@ -2753,10 +2753,7 @@ namespace sat { recompile(c); } else { - // review for potential incompleteness: if c.lit() == l_false, do propagations happen? - if (c.lit() == null_literal || value(c.lit()) == l_true) { - init_watch(c, true); - } + if (c.lit() == null_literal || value(c.lit()) != l_undef) init_watch(c); SASSERT(c.well_formed()); } } @@ -2870,7 +2867,6 @@ namespace sat { s().set_external(v); } } - IF_VERBOSE(10, verbose_stream() << "non-external variables converted: " << ext << "\n";); return ext; } @@ -2897,7 +2893,6 @@ namespace sat { ++pure_literals; } } - IF_VERBOSE(10, verbose_stream() << "pure literals converted: " << pure_literals << " " << inconsistent() << "\n";); return pure_literals; } @@ -3119,7 +3114,7 @@ namespace sat { } } c2.set_size(c2.size() - 1); - init_watch(c2, true); + init_watch(c2); m_simplify_change = true; #endif } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 4eb46609f..b5ea1e1ad 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -296,7 +296,7 @@ namespace sat { void watch_literal(wliteral w, pb& p); bool is_watched(literal l, constraint const& c) const; void add_constraint(constraint* c); - bool init_watch(constraint& c, bool is_true); + bool init_watch(constraint& c); void init_watch(bool_var v); void clear_watch(constraint& c); lbool add_assign(constraint& c, literal l); @@ -320,7 +320,7 @@ namespace sat { // cardinality - bool init_watch(card& c, bool is_true); + bool init_watch(card& c); lbool add_assign(card& c, literal lit); void clear_watch(card& c); void reset_coeffs(); @@ -334,7 +334,7 @@ namespace sat { // xor specific functionality void clear_watch(xor& x); - bool init_watch(xor& x, bool is_true); + bool init_watch(xor& x); bool parity(xor const& x, unsigned offset) const; lbool add_assign(xor& x, literal alit); void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); @@ -345,7 +345,7 @@ namespace sat { // pb functionality unsigned m_a_max; - bool init_watch(pb& p, bool is_true); + bool init_watch(pb& p); lbool add_assign(pb& p, literal alit); void add_index(pb& p, unsigned index, literal lit); void clear_watch(pb& p); diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index f88f4c5a7..869b4ac4c 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -59,7 +59,7 @@ namespace sat { } }; - void asymm_branch::process(clause_vector& clauses) { + void asymm_branch::process(scc& scc, clause_vector& clauses) { int64 limit = -m_asymm_branch_limit; std::stable_sort(clauses.begin(), clauses.end(), clause_size_lt()); m_counter -= clauses.size(); @@ -83,8 +83,9 @@ namespace sat { } s.checkpoint(); clause & c = *(*it); - if (!process(c)) + if (m_asymm_branch_sampled ? !process_sampled(scc, c) : !process(c)) { continue; // clause was removed + } *it2 = *it; ++it2; } @@ -103,7 +104,7 @@ namespace sat { void asymm_branch::operator()(bool force) { ++m_calls; - if (m_calls <= 1) + if (m_calls <= m_asymm_branch_delay) return; if (!m_asymm_branch && !m_asymm_branch_all) return; @@ -118,9 +119,27 @@ namespace sat { TRACE("asymm_branch_detail", s.display(tout);); report rpt(*this); svector saved_phase(s.m_phase); - m_counter = 0; - process(s.m_clauses); - m_counter = -m_counter; + if (m_asymm_branch_sampled) { + scc scc(s, m_params); + while (true) { + unsigned elim = m_elim_literals; + scc.init_big(true); + process(scc, s.m_clauses); + process(scc, s.m_learned); + s.propagate(false); + if (s.m_inconsistent) + break; + std::cout << m_elim_literals - elim << "\n"; + if (m_elim_literals == elim) + break; + } + } + else { + scc scc(s, m_params); + m_counter = 0; + process(scc, s.m_clauses); + m_counter = -m_counter; + } s.m_phase = saved_phase; m_asymm_branch_limit *= 2; if (m_asymm_branch_limit > UINT_MAX) @@ -145,12 +164,6 @@ namespace sat { return true; } - void asymm_branch::setup_big() { - scc scc(s, m_params); - vector const& big = scc.get_big(true); // include learned binary clauses - - } - struct asymm_branch::compare_left { scc& s; compare_left(scc& s): s(s) {} @@ -206,19 +219,34 @@ namespace sat { right = right2; } } - right = scc.get_right(m_neg[0]); - for (unsigned i = 1; i < m_neg.size(); ++i) { - literal lit = m_neg[i]; - int right2 = scc.get_right(lit); - if (right > right2) { - // ~first => ~lit - m_to_delete.push_back(~lit); - } - else { - right = right2; + if (m_to_delete.empty()) { + right = scc.get_right(m_neg[0]); + for (unsigned i = 1; i < m_neg.size(); ++i) { + literal lit = m_neg[i]; + int right2 = scc.get_right(lit); + if (right > right2) { + // ~first => ~lit + m_to_delete.push_back(~lit); + } + else { + right = right2; + } } } if (!m_to_delete.empty()) { +#if 0 + std::cout << "delete " << m_to_delete << "\n"; + + std::cout << "pos\n"; + for (literal l : m_pos) { + std::cout << l << ": " << scc.get_left(l) << " " << scc.get_right(l) << "\n"; + } + std::cout << "neg\n"; + for (literal l : m_neg) { + std::cout << l << ": " << scc.get_left(l) << " " << scc.get_right(l) << "\n"; + } + std::cout << "\n"; +#endif unsigned j = 0; for (unsigned i = 0; i < c.size(); ++i) { if (!m_to_delete.contains(c[i])) { @@ -282,13 +310,13 @@ namespace sat { break; } } - new_sz = j; - m_elim_literals += c.size() - new_sz; + new_sz = j; // std::cout << "cleanup: " << c.id() << ": " << literal_vector(new_sz, c.begin()) << " delta: " << (c.size() - new_sz) << " " << skip_idx << " " << new_sz << "\n"; return re_attach(scoped_d, c, new_sz); } bool asymm_branch::re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz) { + m_elim_literals += c.size() - new_sz; switch(new_sz) { case 0: s.set_conflict(justification()); @@ -315,8 +343,9 @@ namespace sat { } } - bool asymm_branch::process2(scc& scc, clause & c) { + bool asymm_branch::process_sampled(scc& scc, clause & c) { scoped_detach scoped_d(s, c); + sort(scc, c); if (uhte(scc, c)) { scoped_d.del_clause(); return false; @@ -372,6 +401,8 @@ namespace sat { void asymm_branch::updt_params(params_ref const & _p) { sat_asymm_branch_params p(_p); m_asymm_branch = p.asymm_branch(); + m_asymm_branch_delay = p.asymm_branch_delay(); + m_asymm_branch_sampled = p.asymm_branch_sampled(); m_asymm_branch_limit = p.asymm_branch_limit(); m_asymm_branch_all = p.asymm_branch_all(); if (m_asymm_branch_limit > UINT_MAX) diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 87e5cbac5..b7e2b0218 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -39,6 +39,8 @@ namespace sat { // config bool m_asymm_branch; + unsigned m_asymm_branch_delay; + bool m_asymm_branch_sampled; bool m_asymm_branch_all; int64 m_asymm_branch_limit; @@ -60,9 +62,9 @@ namespace sat { bool process(clause & c); - bool process2(scc& scc, clause & c); + bool process_sampled(scc& scc, clause & c); - void process(clause_vector & c); + void process(scc& scc, clause_vector & c); bool process_all(clause & c); @@ -72,8 +74,6 @@ namespace sat { bool propagate_literal(clause const& c, literal l); - void setup_big(); - public: asymm_branch(solver & s, params_ref const & p); diff --git a/src/sat/sat_asymm_branch_params.pyg b/src/sat/sat_asymm_branch_params.pyg index bc50804ba..a457220be 100644 --- a/src/sat/sat_asymm_branch_params.pyg +++ b/src/sat/sat_asymm_branch_params.pyg @@ -2,5 +2,7 @@ def_module_params(module_name='sat', class_name='sat_asymm_branch_params', export=True, params=(('asymm_branch', BOOL, True, 'asymmetric branching'), + ('asymm_branch.delay', UINT, 1, 'number of simplification rounds to wait until invoking asymmetric branch simplification'), + ('asymm_branch.sampled', BOOL, False, 'use sampling based asymmetric branching based on binary implication graph'), ('asymm_branch.limit', UINT, 100000000, 'approx. maximum number of literals visited during asymmetric branching'), ('asymm_branch.all', BOOL, False, 'asymmetric branching on all literals per clause'))) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 306912b57..7464c4156 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -20,6 +20,7 @@ Notes: #include "sat/sat_solver.h" #include "sat/sat_extension.h" #include "sat/sat_lookahead.h" +#include "sat/sat_scc.h" #include "util/union_find.h" namespace sat { @@ -2304,15 +2305,86 @@ namespace sat { void lookahead::add_hyper_binary() { + unsigned num_lits = m_s.num_vars() * 2; + +#if 0 std::cout << "binary trail size: " << m_binary_trail.size() << "\n"; std::cout << "Are windfalls still on the trail at base level?\n"; - unsigned num_lits = m_s.num_vars() * 2; +#endif + + unsigned disconnected1 = 0; + unsigned disconnected2 = 0; + +#if 1 + typedef std::pair u_pair; + hashtable, default_eq > imp; + for (unsigned idx = 0; idx < num_lits; ++idx) { + literal u = get_parent(to_literal(idx)); + if (null_literal != u) { + for (watched const& w : m_s.m_watches[idx]) { + if (!w.is_binary_clause()) continue; + literal v = get_parent(w.get_literal()); + if (null_literal != v) { + imp.insert(std::make_pair(u.index(), v.index())); + } + } + } + } + + scc scc(m_s, m_s.m_params); + scc.init_big(true); + svector> candidates; + unsigned_vector bin_size(num_lits); for (unsigned idx : m_binary_trail) { bin_size[idx]++; } - + for (unsigned idx = 0; idx < num_lits; ++idx) { + literal u = to_literal(idx); + if (u != get_parent(u)) continue; + if (m_s.was_eliminated(u.var())) continue; + literal_vector const& lits = m_binary[idx]; + for (unsigned sz = bin_size[idx]; sz > 0; --sz) { + literal v = lits[lits.size() - sz]; + if (v != get_parent(v)) continue; + if (m_s.was_eliminated(v.var())) continue; + if (imp.contains(std::make_pair(u.index(), v.index()))) continue; + if (scc.reaches(u, v)) continue; + candidates.push_back(std::make_pair(u, v)); + } + } + for (unsigned i = 0; i < 5; ++i) { + scc.init_big(true); + unsigned k = 0; + union_find_default_ctx ufctx; + union_find uf(ufctx); + for (unsigned i = 0; i < num_lits; ++i) uf.mk_var(); + for (unsigned j = 0; j < candidates.size(); ++j) { + literal u = candidates[j].first; + literal v = candidates[j].second; + if (!scc.reaches(u, v)) { + if (uf.find(u.index()) != uf.find(v.index())) { + ++disconnected1; + uf.merge(u.index(), v.index()); + uf.merge((~u).index(), (~v).index()); + m_s.mk_clause(~u, v, true); + } + else { + candidates[k] = candidates[j]; + ++k; + } + } + } + std::cout << candidates.size() << " -> " << k << "\n"; + if (k == candidates.size()) break; + candidates.shrink(k); + } + std::cout << "candidates: " << candidates.size() << "\n"; + +#endif + +#if 0 union_find_default_ctx ufctx; union_find uf(ufctx); for (unsigned i = 0; i < num_lits; ++i) uf.mk_var(); @@ -2329,21 +2401,25 @@ namespace sat { } } - unsigned disconnected = 0; for (unsigned i = 0; i < m_binary.size(); ++i) { literal u = to_literal(i); - if (u == get_parent(u)) { + if (u == get_parent(u) && !m_s.was_eliminated(u.var())) { for (literal v : m_binary[i]) { - if (v == get_parent(v) && uf.find(u.index()) != uf.find(v.index())) { - ++disconnected; + if (v == get_parent(v) && + !m_s.was_eliminated(v.var()) && + uf.find(u.index()) != uf.find(v.index())) { + ++disconnected2; uf.merge(u.index(), v.index()); - m_s.mk_clause(~u, v, true); + // m_s.mk_clause(~u, v, true); } } } } - IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << disconnected << ")\n";); - m_stats.m_bca += disconnected; +#endif + + IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << disconnected1 << " " << disconnected2 << ")\n";); + //IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << disconnected << ")\n";); + //m_stats.m_bca += disconnected; } void lookahead::normalize_parents() { diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 9da54da29..7615a19a3 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -234,17 +234,7 @@ namespace sat { return to_elim.size(); } - // shuffle vertices to obtain different DAG traversal each time - void scc::shuffle(literal_vector& lits) { - unsigned sz = lits.size(); - if (sz > 1) { - for (unsigned i = sz; i-- > 0; ) { - std::swap(lits[i], lits[m_rand(i+1)]); - } - } - } - - vector const& scc::get_big(bool learned) { + void scc::init_big(bool learned) { unsigned num_lits = m_solver.num_vars() * 2; m_dag.reset(); m_roots.reset(); @@ -263,53 +253,21 @@ namespace sat { edges.push_back(v); } } - shuffle(edges); + shuffle(edges.size(), edges.c_ptr(), m_rand); } - return m_dag; + init_dfs_num(learned); } - void scc::get_dfs_num(bool learned) { - unsigned num_lits = m_solver.num_vars() * 2; - SASSERT(m_left.size() == num_lits); - SASSERT(m_right.size() == num_lits); - literal_vector todo; - // retrieve literals that have no predecessors - for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { - literal u(to_literal(l_idx)); - if (m_roots[u.index()]) todo.push_back(u); - } - shuffle(todo); - int dfs_num = 0; - while (!todo.empty()) { - literal u = todo.back(); - int& d = m_left[u.index()]; - // already visited - if (d > 0) { - if (m_right[u.index()] < 0) { - m_right[u.index()] = dfs_num; - } - todo.pop_back(); - } - // visited as child: - else if (d < 0) { - d = -d; - for (literal v : m_dag[u.index()]) { - if (m_left[v.index()] == 0) { - m_left[v.index()] = - d - 1; - m_root[v.index()] = m_root[u.index()]; - m_parent[v.index()] = u; - todo.push_back(v); - } - } - } - // new root. - else { - d = --dfs_num; - } - } - } + struct scc::pframe { + literal m_parent; + literal m_child; + pframe(literal p, literal c): + m_parent(p), m_child(c) {} + literal child() const { return m_child; } + literal parent() const { return m_parent; } + }; - unsigned scc::reduce_tr(bool learned) { + void scc::init_dfs_num(bool learned) { unsigned num_lits = m_solver.num_vars() * 2; m_left.reset(); m_right.reset(); @@ -317,11 +275,61 @@ namespace sat { m_parent.reset(); m_left.resize(num_lits, 0); m_right.resize(num_lits, -1); + m_root.resize(num_lits, null_literal); + m_parent.resize(num_lits, null_literal); for (unsigned i = 0; i < num_lits; ++i) { m_root[i] = to_literal(i); m_parent[i] = to_literal(i); } - get_dfs_num(learned); + svector todo; + // retrieve literals that have no predecessors + for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { + literal u(to_literal(l_idx)); + if (m_roots[u.index()]) { + todo.push_back(pframe(null_literal, u)); + } + } + shuffle(todo.size(), todo.c_ptr(), m_rand); + int dfs_num = 0; + while (!todo.empty()) { + literal u = todo.back().child(); + if (m_left[u.index()] > 0) { + // already visited + if (m_right[u.index()] < 0) { + m_right[u.index()] = ++dfs_num; + } + todo.pop_back(); + } + else { + SASSERT(m_left[u.index()] == 0); + m_left[u.index()] = ++dfs_num; + for (literal v : m_dag[u.index()]) { + if (m_left[v.index()] == 0) { + todo.push_back(pframe(u, v)); + } + } + literal p = todo.back().parent(); + if (p != null_literal) { + m_root[u.index()] = m_root[p.index()]; + m_parent[u.index()] = p; + } + } + } + for (unsigned i = 0; i < num_lits; ++i) { + if (m_right[i] < 0) { + VERIFY(m_left[i] == 0); + m_left[i] = ++dfs_num; + m_right[i] = ++dfs_num; + } + } + for (unsigned i = 0; i < num_lits; ++i) { + VERIFY(m_left[i] < m_right[i]); + } + } + + unsigned scc::reduce_tr(bool learned) { + unsigned num_lits = m_solver.num_vars() * 2; + init_big(learned); unsigned idx = 0; unsigned elim = m_num_elim_bin; for (watch_list & wlist : m_solver.m_watches) { @@ -333,7 +341,7 @@ namespace sat { watched& w = *it; if (learned ? w.is_binary_learned_clause() : w.is_binary_unblocked_clause()) { literal v = w.get_literal(); - if (m_left[u.index()] + 1 < m_left[v.index()]) { + if (reaches(u, v) && u != get_parent(v)) { ++m_num_elim_bin; } else { diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index 806cf8f33..2973245a3 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -44,10 +44,13 @@ namespace sat { svector m_left, m_right; literal_vector m_root, m_parent; - void shuffle(literal_vector& lits); void reduce_tr(); unsigned reduce_tr(bool learned); + void init_dfs_num(bool learned); + + struct pframe; + public: scc(solver & s, params_ref const & p); @@ -60,17 +63,14 @@ namespace sat { void reset_statistics(); /* - \brief retrieve binary implication graph + \brief create binary implication graph and associated data-structures to check transitivity. */ - vector const& get_big(bool learned); - + void init_big(bool learned); int get_left(literal l) const { return m_left[l.index()]; } int get_right(literal l) const { return m_right[l.index()]; } literal get_parent(literal l) const { return m_parent[l.index()]; } literal get_root(literal l) const { return m_root[l.index()]; } - - void get_dfs_num(bool learned); - + bool reaches(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; } }; }; diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index b78980774..32d318536 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -2,7 +2,7 @@ def_module_params(module_name='sat', class_name='sat_simplifier_params', export=True, params=(('elim_blocked_clauses', BOOL, False, 'eliminate blocked clauses'), - ('abce', BOOL, BOOL, False, 'eliminate blocked clauses using asymmmetric literals'), + ('abce', BOOL, False, 'eliminate blocked clauses using asymmmetric literals'), ('cce', BOOL, False, 'eliminate covered clauses'), ('acce', BOOL, False, 'eliminate covered clauses using asymmetric added literals'), ('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 7cadffd27..602850487 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -191,7 +191,7 @@ namespace sat { // Misc // // ----------------------- - void updt_params(params_ref const & p); + void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); void collect_statistics(statistics & st) const; From e0d69a0033bcc67296746037f57a4cc5e74010d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 08:24:42 -0800 Subject: [PATCH 0376/1283] fix perf bug Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 55 +++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 656bff104..283083237 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -958,8 +958,10 @@ namespace sat { literal_vector m_covered_clause; literal_vector m_intersection; + literal_vector m_new_intersection; + svector m_in_intersection; sat::model_converter::elim_stackv m_elim_stack; - unsigned m_ala_qhead; + unsigned m_ala_qhead; blocked_clause_elim(simplifier & _s, unsigned limit, model_converter & _mc, use_list & l, vector & wlist): @@ -967,6 +969,7 @@ namespace sat { m_counter(limit), mc(_mc), m_queue(l, wlist) { + m_in_intersection.resize(s.s.num_vars() * 2, false); } void insert(literal l) { @@ -986,7 +989,7 @@ namespace sat { cce(); if (s.bca_enabled()) bca(); - } + } void block_clauses() { insert_queue(); @@ -1066,13 +1069,26 @@ namespace sat { s.block_clause(*c); } + void reset_intersection() { + for (literal l : m_intersection) m_in_intersection[l.index()] = false; + m_intersection.reset(); + } + + void add_intersection(literal lit) { + m_intersection.push_back(lit); + m_in_intersection[lit.index()] = true; + } + + + // // Resolve intersection // Find literals that are in the intersection of all resolvents with l. // - bool resolution_intersection(literal l, literal_vector& inter, bool adding) { + bool resolution_intersection(literal l, bool adding) { if (!process_var(l.var())) return false; bool first = true; + reset_intersection(); for (watched & w : s.get_wlist(l)) { // when adding a blocked clause, then all non-learned clauses have to be considered for the // resolution intersection. @@ -1083,11 +1099,12 @@ namespace sat { continue; // tautology } if (!first || s.is_marked(lit)) { - inter.reset(); + reset_intersection(); return false; // intersection is empty or does not add anything new. } first = false; - inter.push_back(lit); + SASSERT(m_intersection.empty()); + add_intersection(lit); } } clause_use_list & neg_occs = s.m_use_list.get(~l); @@ -1103,20 +1120,22 @@ namespace sat { } if (!tautology) { if (first) { - for (literal lit : c) { - if (lit != ~l && !s.is_marked(lit)) inter.push_back(lit); - } + for (literal lit : c) + if (lit != ~l && !s.is_marked(lit)) + add_intersection(lit); first = false; - if (inter.empty()) return false; } else { - unsigned j = 0; - for (literal lit : inter) - if (c.contains(lit)) - inter[j++] = lit; - inter.shrink(j); - if (j == 0) return false; + m_new_intersection.reset(); + for (literal lit : c) + if (m_in_intersection[lit.index()]) + m_new_intersection.push_back(lit); + reset_intersection(); + for (literal lit : m_new_intersection) + add_intersection(lit); } + if (m_intersection.empty()) + return false; } } return first; @@ -1176,8 +1195,7 @@ namespace sat { */ bool add_cla(literal& blocked) { for (unsigned i = 0; i < m_covered_clause.size(); ++i) { - m_intersection.reset(); - if (resolution_intersection(m_covered_clause[i], m_intersection, false)) { + if (resolution_intersection(m_covered_clause[i], false)) { blocked = m_covered_clause[i]; return true; } @@ -1404,8 +1422,7 @@ namespace sat { Then the following binary clause is blocked: l \/ ~l' */ void bca(literal l) { - m_intersection.reset(); - if (resolution_intersection(l, m_intersection, true)) { + if (resolution_intersection(l, true)) { // this literal is pure. return; } From c8e655830f59785aae19710282292cf6ca8b57ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 10:13:54 -0800 Subject: [PATCH 0377/1283] add statistics to cubing Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 12 ++++++++++-- src/sat/sat_lookahead.h | 10 +++++++++- src/sat/sat_solver.cpp | 1 + 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 7464c4156..2a2da1c90 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2013,6 +2013,11 @@ namespace sat { return true; } + void lookahead::update_cube_statistics(statistics& st) { + st.update("lh cube cutoffs", m_cube_state.m_cutoffs); + st.update("lh cube conflicts", m_cube_state.m_conflicts); + } + lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level) { scoped_ext _scoped_ext(*this); lits.reset(); @@ -2031,6 +2036,7 @@ namespace sat { unsigned depth = 0; unsigned init_trail = m_trail.size(); + m_cube_state.reset_stats(); if (!is_first) { goto pick_up_work; } @@ -2041,8 +2047,9 @@ namespace sat { inc_istamp(); if (inconsistent()) { TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); - m_cube_state.m_freevars_threshold = m_freevars.size(); - if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; + m_cube_state.m_freevars_threshold = m_freevars.size(); + m_cube_state.inc_conflict(); + if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; continue; } pick_up_work: @@ -2059,6 +2066,7 @@ namespace sat { (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) { m_cube_state.m_freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); set_conflict(); + m_cube_state.inc_cutoff(); #if 0 // return cube of all literals, not just the ones in the main cube lits.append(m_trail.size() - init_trail, m_trail.c_ptr() + init_trail); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 6f0c256a7..2f62c932d 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -167,13 +167,19 @@ namespace sat { svector m_is_decision; literal_vector m_cube; double m_freevars_threshold; + unsigned m_conflicts; + unsigned m_cutoffs; cube_state() { reset(); } void reset() { m_first = true; m_is_decision.reset(); m_cube.reset(); - m_freevars_threshold = 0; + m_freevars_threshold = 0; + reset_stats(); } + void reset_stats() { m_conflicts = 0; m_cutoffs = 0; } + void inc_conflict() { ++m_conflicts; } + void inc_cutoff() { ++m_cutoffs; } }; config m_config; @@ -572,6 +578,8 @@ namespace sat { lbool cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level); + void update_cube_statistics(statistics& st); + literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** \brief simplify set of clauses by extracting units from a lookahead at base level. diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 89acdc408..5a7e234e9 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -859,6 +859,7 @@ namespace sat { m_cuber = alloc(lookahead, *this); } lbool result = m_cuber->cube(vars, lits, backtrack_level); + m_cuber->update_cube_statistics(m_aux_stats); if (result == l_false) { dealloc(m_cuber); m_cuber = nullptr; From 1b7cb110d34b748e2b501bd13947c943c6aaf0c4 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Fri, 1 Dec 2017 11:02:29 -0800 Subject: [PATCH 0378/1283] freevars cube cutoff Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_config.cpp | 15 ++++++++++++++- src/sat/sat_config.h | 10 +++++++++- src/sat/sat_lookahead.cpp | 10 ++++++++-- src/sat/sat_lookahead.h | 11 ++++++++--- src/sat/sat_params.pyg | 9 +++++++-- 5 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 24d2bca9b..bd2a48ff2 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -112,8 +112,21 @@ namespace sat { throw sat_param_exception("invalid reward type supplied: accepted heuristics are 'ternary', 'heuleu', 'unit' or 'heule_schur'"); } + if (p.lookahead_cube_cutoff() == symbol("adaptive")) { + m_lookahead_cube_cutoff = adaptive_cutoff; + } + else if (p.lookahead_cube_cutoff() == symbol("fixed_depth")) { + m_lookahead_cube_cutoff = fixed_depth_cutoff; + } + else if (p.lookahead_cube_cutoff() == symbol("fixed_freevars")) { + m_lookahead_cube_cutoff = fixed_freevars_cutoff; + } + else { + throw sat_param_exception("invalid cutoff type supplied: accepted cutoffs are 'adaptive', 'fixed_depth', 'fixed_freevars'"); + } m_lookahead_cube_fraction = p.lookahead_cube_fraction(); - m_lookahead_cube_cutoff = p.lookahead_cube_cutoff(); + m_lookahead_cube_depth = p.lookahead_cube_depth(); + m_lookahead_cube_freevars = p.lookahead_cube_freevars(); m_lookahead_global_autarky = p.lookahead_global_autarky(); // These parameters are not exposed diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 9a20bbc63..f6f6774fc 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -65,6 +65,12 @@ namespace sat { march_cu_reward }; + enum cutoff_t { + adaptive_cutoff, + fixed_depth_cutoff, + fixed_freevars_cutoff + }; + struct config { unsigned long long m_max_memory; phase_selection m_phase; @@ -85,8 +91,10 @@ namespace sat { bool m_lookahead_search; bool m_lookahead_simplify; bool m_lookahead_simplify_bca; - unsigned m_lookahead_cube_cutoff; + cutoff_t m_lookahead_cube_cutoff; double m_lookahead_cube_fraction; + unsigned m_lookahead_cube_depth; + double m_lookahead_cube_freevars; reward_t m_lookahead_reward; bool m_lookahead_global_autarky; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 306912b57..2784b97d2 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1032,6 +1032,7 @@ namespace sat { } propagate(); m_qhead = m_trail.size(); + m_init_freevars = m_freevars.size(); TRACE("sat", m_s.display(tout); display(tout);); } @@ -2054,8 +2055,11 @@ namespace sat { } backtrack_level = UINT_MAX; depth = m_cube_state.m_cube.size(); - if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || - (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) { + if ((m_config.m_cube_cutoff == fixed_depth_cutoff && depth == m_config.m_cube_depth) || + (m_config.m_cube_cutoff == adaptive_cutoff && m_freevars.size() < m_cube_state.m_freevars_threshold) || + /* m_cube_cutoff is fixed_freevars */ m_freevars.size() <= m_init_freevars * m_config.m_cube_freevars) { + /*if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || + (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) {*/ m_cube_state.m_freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); set_conflict(); #if 0 @@ -2413,6 +2417,8 @@ namespace sat { m_config.m_reward_type = m_s.m_config.m_lookahead_reward; m_config.m_cube_cutoff = m_s.m_config.m_lookahead_cube_cutoff; m_config.m_cube_fraction = m_s.m_config.m_lookahead_cube_fraction; + m_config.m_cube_depth = m_s.m_config.m_lookahead_cube_depth; + m_config.m_cube_freevars = m_s.m_config.m_lookahead_cube_freevars; } void lookahead::collect_statistics(statistics& st) const { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 6f0c256a7..db9ebdaa4 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -80,8 +80,10 @@ namespace sat { unsigned m_dl_max_iterations; unsigned m_tc1_limit; reward_t m_reward_type; - unsigned m_cube_cutoff; + cutoff_t m_cube_cutoff; + unsigned m_cube_depth; double m_cube_fraction; + double m_cube_freevars; config() { memset(this, sizeof(*this), 0); @@ -96,8 +98,10 @@ namespace sat { m_dl_max_iterations = 2; m_tc1_limit = 10000000; m_reward_type = ternary_reward; - m_cube_cutoff = 0; + m_cube_cutoff = adaptive_cutoff; + m_cube_depth = 10; m_cube_fraction = 0.4; + m_cube_freevars = 0.8; } }; @@ -222,11 +226,12 @@ namespace sat { svector m_vprefix; // var: prefix where variable participates in propagation unsigned m_rating_throttle; // throttle to recompute rating indexed_uint_set m_freevars; + unsigned m_init_freevars; lookahead_mode m_search_mode; // mode of search stats m_stats; model m_model; cube_state m_cube_state; - scoped_ptr m_ext; + scoped_ptr m_ext; // --------------------------------------- // truth values diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 4f65b100b..085f0c067 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -37,8 +37,13 @@ def_module_params('sat', ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), - ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'), - ('lookahead.cube.cutoff', UINT, 10, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), + ('lookahead.cube.cutoff', SYMBOL, 'adaptive', 'cutoff type used to create lookahead cubes: adaptive, fixed_depth, fixed_freevars, psat'), + ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive'), + ('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is fixed_depth.'), + ('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is fixed_freevars'), + ('lookahead.cube.psat.var_exp', DOUBLE, 1, 'free variable exponent for PSAT cutoff'), + ('lookahead.cube.psat.clause_base', DOUBLE, 1, 'clause base for PSAT cutoff') + ('lookahead.cube.psat.probability', DOUBLE' 0.5, 'probability to create lookahead cubes for PSAT cutoff') ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), From b98c864d760c141a0e622f9af18f6db204d04974 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Dec 2017 18:06:26 -0800 Subject: [PATCH 0379/1283] fixes to inprocessing code Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 21 ++++++++++----------- src/sat/sat_asymm_branch.h | 3 ++- src/sat/sat_elim_eqs.cpp | 7 ++++--- src/sat/sat_lookahead.cpp | 3 +++ src/sat/sat_scc.cpp | 12 ++++++------ src/sat/sat_solver.cpp | 21 +++------------------ src/sat/sat_solver.h | 1 - 7 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 869b4ac4c..8e5e556e3 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -59,7 +59,7 @@ namespace sat { } }; - void asymm_branch::process(scc& scc, clause_vector& clauses) { + void asymm_branch::process(scc* scc, clause_vector& clauses) { int64 limit = -m_asymm_branch_limit; std::stable_sort(clauses.begin(), clauses.end(), clause_size_lt()); m_counter -= clauses.size(); @@ -83,7 +83,7 @@ namespace sat { } s.checkpoint(); clause & c = *(*it); - if (m_asymm_branch_sampled ? !process_sampled(scc, c) : !process(c)) { + if (scc ? !process_sampled(*scc, c) : !process(c)) { continue; // clause was removed } *it2 = *it; @@ -106,7 +106,7 @@ namespace sat { ++m_calls; if (m_calls <= m_asymm_branch_delay) return; - if (!m_asymm_branch && !m_asymm_branch_all) + if (!m_asymm_branch && !m_asymm_branch_all && !m_asymm_branch_sampled) return; s.propagate(false); // must propagate, since it uses s.push() if (s.m_inconsistent) @@ -119,13 +119,18 @@ namespace sat { TRACE("asymm_branch_detail", s.display(tout);); report rpt(*this); svector saved_phase(s.m_phase); + if (m_asymm_branch) { + m_counter = 0; + process(nullptr, s.m_clauses); + m_counter = -m_counter; + } if (m_asymm_branch_sampled) { scc scc(s, m_params); while (true) { unsigned elim = m_elim_literals; scc.init_big(true); - process(scc, s.m_clauses); - process(scc, s.m_learned); + process(&scc, s.m_clauses); + process(&scc, s.m_learned); s.propagate(false); if (s.m_inconsistent) break; @@ -134,12 +139,6 @@ namespace sat { break; } } - else { - scc scc(s, m_params); - m_counter = 0; - process(scc, s.m_clauses); - m_counter = -m_counter; - } s.m_phase = saved_phase; m_asymm_branch_limit *= 2; if (m_asymm_branch_limit > UINT_MAX) diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index b7e2b0218..4510aaddf 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -41,6 +41,7 @@ namespace sat { bool m_asymm_branch; unsigned m_asymm_branch_delay; bool m_asymm_branch_sampled; + bool m_asymm_branch_propagate; bool m_asymm_branch_all; int64 m_asymm_branch_limit; @@ -64,7 +65,7 @@ namespace sat { bool process_sampled(scc& scc, clause & c); - void process(scc& scc, clause_vector & c); + void process(scc* scc, clause_vector & c); bool process_all(clause & c); diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index ea44c870d..d0166b64e 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -94,10 +94,11 @@ namespace sat { if (!c.frozen()) m_solver.detach_clause(c); // apply substitution - for (i = 0; i < sz; i++) { - c[i] = norm(roots, c[i]); + for (i = 0; i < sz; i++) { + literal lit = c[i]; + c[i] = norm(roots, lit); VERIFY(c[i] == norm(roots, c[i])); - VERIFY(!m_solver.was_eliminated(c[i].var())); + VERIFY(!m_solver.was_eliminated(c[i].var()) || lit == c[i]); } std::sort(c.begin(), c.end()); for (literal l : c) VERIFY(l == norm(roots, l)); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 2a2da1c90..843c70fd8 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2081,6 +2081,7 @@ namespace sat { if (inconsistent()) { TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); m_cube_state.m_freevars_threshold = prev_nfreevars; + m_cube_state.inc_conflict(); if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; continue; } @@ -2375,6 +2376,8 @@ namespace sat { ++disconnected1; uf.merge(u.index(), v.index()); uf.merge((~u).index(), (~v).index()); + VERIFY(!m_s.was_eliminated(u.var())); + VERIFY(!m_s.was_eliminated(v.var())); m_s.mk_clause(~u, v, true); } else { diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 7615a19a3..59c53304d 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -303,16 +303,16 @@ namespace sat { else { SASSERT(m_left[u.index()] == 0); m_left[u.index()] = ++dfs_num; - for (literal v : m_dag[u.index()]) { - if (m_left[v.index()] == 0) { - todo.push_back(pframe(u, v)); - } - } literal p = todo.back().parent(); if (p != null_literal) { m_root[u.index()] = m_root[p.index()]; m_parent[u.index()] = p; } + for (literal v : m_dag[u.index()]) { + if (m_left[v.index()] == 0) { + todo.push_back(pframe(u, v)); + } + } } } for (unsigned i = 0; i < num_lits; ++i) { @@ -339,7 +339,7 @@ namespace sat { watch_list::iterator end = wlist.end(); for (; it != end; ++it) { watched& w = *it; - if (learned ? w.is_binary_learned_clause() : w.is_binary_unblocked_clause()) { + if (learned ? w.is_binary_learned_clause() : w.is_binary_clause()) { literal v = w.get_literal(); if (reaches(u, v) && u != get_parent(v)) { ++m_num_elim_bin; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5a7e234e9..f8425b9bc 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -159,17 +159,20 @@ namespace sat { } } // copy high quality lemmas + unsigned num_learned = 0; for (clause* c : src.m_learned) { if (c->glue() <= 2 || (c->size() <= 40 && c->glue() <= 8)) { buffer.reset(); for (literal l : *c) buffer.push_back(l); clause* c1 = mk_clause_core(buffer.size(), buffer.c_ptr(), true); if (c1) { + ++num_learned; c1->set_glue(c->glue()); c1->set_psm(c->psm()); } } } + IF_VERBOSE(1, verbose_stream() << "(sat.copy :learned " << num_learned << ")\n";); } m_user_scope_literals.reset(); @@ -879,9 +882,6 @@ namespace sat { m_stats.m_units = init_trail_size(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); - if (m_config.m_lookahead_search && num_lits == 0) { - return lookahead_search(); - } if (m_config.m_local_search) { return do_local_search(num_lits, lits); @@ -984,21 +984,6 @@ namespace sat { return r; } - lbool solver::lookahead_search() { - lookahead lh(*this); - lbool r = l_undef; - try { - r = lh.check(); - m_model = lh.get_model(); - } - catch (z3_exception&) { - lh.collect_statistics(m_aux_stats); - throw; - } - lh.collect_statistics(m_aux_stats); - return r; - } - lbool solver::check_par(unsigned num_lits, literal const* lits) { scoped_ptr_vector ls; int num_threads = static_cast(m_config.m_num_threads + m_config.m_local_search_threads); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 602850487..135d9e067 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -394,7 +394,6 @@ namespace sat { void sort_watch_lits(); void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); - lbool lookahead_search(); lbool do_local_search(unsigned num_lits, literal const* lits); // ----------------------- From fc3cbcbe026d6cacec681b4f39d7f9715022980b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Dec 2017 10:16:35 -0800 Subject: [PATCH 0380/1283] remove deprecated options Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 4 ---- src/sat/sat_config.h | 3 --- src/sat/sat_params.pyg | 6 ++---- src/sat/sat_solver.cpp | 6 ------ 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 24d2bca9b..ed951fd93 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -38,8 +38,6 @@ namespace sat { m_glue_psm("glue_psm"), m_psm_glue("psm_glue") { m_num_threads = 1; - m_local_search = 0; - m_lookahead_search = false; m_lookahead_simplify = false; m_lookahead_simplify_bca = false; m_elim_vars = false; @@ -92,7 +90,6 @@ namespace sat { m_local_search_threads = p.local_search_threads(); m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify_bca = p.lookahead_simplify_bca(); - m_lookahead_search = p.lookahead_search(); if (p.lookahead_reward() == symbol("heule_schur")) { m_lookahead_reward = heule_schur_reward; } @@ -195,7 +192,6 @@ namespace sat { else { throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); } - m_dimacs_inprocess_display = p.dimacs_inprocess_display(); sat_simplifier_params sp(_p); m_elim_vars = sp.elim_vars(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 9a20bbc63..c3018ef29 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -82,7 +82,6 @@ namespace sat { unsigned m_num_threads; unsigned m_local_search_threads; bool m_local_search; - bool m_lookahead_search; bool m_lookahead_simplify; bool m_lookahead_simplify_bca; unsigned m_lookahead_cube_cutoff; @@ -112,8 +111,6 @@ namespace sat { bool m_drat_check_unsat; bool m_drat_check_sat; - bool m_dimacs_inprocess_display; - symbol m_always_true; symbol m_always_false; symbol m_caching; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 4f65b100b..e8ae53dca 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -35,15 +35,13 @@ def_module_params('sat', ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), ('xor.solver', BOOL, False, 'use xor solver'), ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), - ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search', BOOL, False, 'use local search instead of CDCL'), + ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'), ('lookahead.cube.cutoff', UINT, 10, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), - ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead_simplify.bca', BOOL, False, 'add learned binary clauses as part of lookahead simplification'), ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), - ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'), - ('dimacs.inprocess.display', BOOL, False, 'display SAT instance in DIMACS format if unsolved after inprocess.max inprocessing passes'))) + ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f8425b9bc..b3fc95f47 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -950,12 +950,6 @@ namespace sat { if (m_config.m_inprocess_max <= m_simplifications) { m_reason_unknown = "sat.max.inprocess"; IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-inprocess\")\n";); - if (m_config.m_dimacs_inprocess_display) { - display_dimacs(std::cout); - for (unsigned i = 0; i < num_lits; ++lits) { - std::cout << dimacs_lit(lits[i]) << " 0\n"; - } - } return l_undef; } From e0dfbd6d1cf7341da84a315bb1e715d3767c9126 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Mon, 4 Dec 2017 14:33:48 -0800 Subject: [PATCH 0381/1283] fixed freevars and psat cube cutoffs Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_config.cpp | 6 ++++++ src/sat/sat_config.h | 6 +++++- src/sat/sat_lookahead.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/sat/sat_lookahead.h | 8 ++++++++ src/sat/sat_params.pyg | 4 ++-- 5 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index bd2a48ff2..b0797dae9 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -121,12 +121,18 @@ namespace sat { else if (p.lookahead_cube_cutoff() == symbol("fixed_freevars")) { m_lookahead_cube_cutoff = fixed_freevars_cutoff; } + else if (p.lookahead_cube_cutoff() == symbol("psat")) { + m_lookahead_cube_cutoff = psat_cutoff; + } else { throw sat_param_exception("invalid cutoff type supplied: accepted cutoffs are 'adaptive', 'fixed_depth', 'fixed_freevars'"); } m_lookahead_cube_fraction = p.lookahead_cube_fraction(); m_lookahead_cube_depth = p.lookahead_cube_depth(); m_lookahead_cube_freevars = p.lookahead_cube_freevars(); + m_lookahead_cube_psat_var_exp = p.lookahead_cube_psat_var_exp(); + m_lookahead_cube_psat_clause_base = p.lookahead_cube_psat_clause_base(); + m_lookahead_cube_psat_trigger = p.lookahead_cube_psat_trigger(); m_lookahead_global_autarky = p.lookahead_global_autarky(); // These parameters are not exposed diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index f6f6774fc..1529466ee 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -68,7 +68,8 @@ namespace sat { enum cutoff_t { adaptive_cutoff, fixed_depth_cutoff, - fixed_freevars_cutoff + fixed_freevars_cutoff, + psat_cutoff }; struct config { @@ -95,6 +96,9 @@ namespace sat { double m_lookahead_cube_fraction; unsigned m_lookahead_cube_depth; double m_lookahead_cube_freevars; + double m_lookahead_cube_psat_var_exp; + double m_lookahead_cube_psat_clause_base; + double m_lookahead_cube_psat_trigger; reward_t m_lookahead_reward; bool m_lookahead_global_autarky; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 6aae5738e..3feb9455d 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2019,6 +2019,35 @@ namespace sat { st.update("lh cube conflicts", m_cube_state.m_conflicts); } + double lookahead::psat_heur() { + double h = 0.0; + for (bool_var x : m_freevars) { + literal l(x, false); + for (literal lit : m_binary[l.index()]) { + h += l.index() > lit.index() ? 1.0 / m_config.m_cube_psat_clause_base : 0.0; + } + for (literal lit : m_binary[(~l).index()]) { + h += l.index() > lit.index() ? 1.0 / m_config.m_cube_psat_clause_base : 0.0; + } + for (binary b : m_ternary[l.index()]) { + h += l.index() > b.m_u.index() && l.index() > b.m_v.index() ? + 1.0 / pow(m_config.m_cube_psat_clause_base, 2) : + 0.0; + } + for (binary b : m_ternary[(~l).index()]) { + h += l.index() > b.m_u.index() && l.index() > b.m_v.index() ? + 1.0 / pow(m_config.m_cube_psat_clause_base, 2) : + 0.0; + } + } + for (nary * n : m_nary_clauses) { + h += 1.0 / pow(m_config.m_cube_psat_clause_base, n->size() - 1); + } + h /= pow(m_freevars.size(), m_config.m_cube_psat_var_exp); + IF_VERBOSE(10, verbose_stream() << "(sat-cube-psat :val " << h << ")\n";); + return h; + } + lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level) { scoped_ext _scoped_ext(*this); lits.reset(); @@ -2065,9 +2094,8 @@ namespace sat { depth = m_cube_state.m_cube.size(); if ((m_config.m_cube_cutoff == fixed_depth_cutoff && depth == m_config.m_cube_depth) || (m_config.m_cube_cutoff == adaptive_cutoff && m_freevars.size() < m_cube_state.m_freevars_threshold) || - /* m_cube_cutoff is fixed_freevars */ m_freevars.size() <= m_init_freevars * m_config.m_cube_freevars) { - /*if ((m_config.m_cube_cutoff != 0 && depth == m_config.m_cube_cutoff) || - (m_config.m_cube_cutoff == 0 && m_freevars.size() < m_cube_state.m_freevars_threshold)) {*/ + (m_config.m_cube_cutoff == fixed_freevars_cutoff && m_freevars.size() <= m_init_freevars * m_config.m_cube_freevars) || + (m_config.m_cube_cutoff == psat_cutoff && psat_heur() >= m_config.m_cube_psat_trigger)) { m_cube_state.m_freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); set_conflict(); m_cube_state.inc_cutoff(); @@ -2085,6 +2113,7 @@ namespace sat { if (inconsistent()) { TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); m_cube_state.m_freevars_threshold = prev_nfreevars; + m_cube_state.inc_conflict(); if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; continue; } @@ -2503,6 +2532,9 @@ namespace sat { m_config.m_cube_fraction = m_s.m_config.m_lookahead_cube_fraction; m_config.m_cube_depth = m_s.m_config.m_lookahead_cube_depth; m_config.m_cube_freevars = m_s.m_config.m_lookahead_cube_freevars; + m_config.m_cube_psat_var_exp = m_s.m_config.m_lookahead_cube_psat_var_exp; + m_config.m_cube_psat_clause_base = m_s.m_config.m_lookahead_cube_psat_clause_base; + m_config.m_cube_psat_trigger = m_s.m_config.m_lookahead_cube_psat_trigger; } void lookahead::collect_statistics(statistics& st) const { diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index bd4198dcd..254dd614f 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -84,6 +84,9 @@ namespace sat { unsigned m_cube_depth; double m_cube_fraction; double m_cube_freevars; + double m_cube_psat_var_exp; + double m_cube_psat_clause_base; + double m_cube_psat_trigger; config() { memset(this, sizeof(*this), 0); @@ -102,6 +105,9 @@ namespace sat { m_cube_depth = 10; m_cube_fraction = 0.4; m_cube_freevars = 0.8; + m_cube_psat_var_exp = 1.0; + m_cube_psat_clause_base = 2.0; + m_cube_psat_trigger = 5.0; } }; @@ -547,6 +553,8 @@ namespace sat { void add_hyper_binary(); + double psat_heur(); + public: lookahead(solver& s) : m_s(s), diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 085f0c067..565c6dbcc 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -42,8 +42,8 @@ def_module_params('sat', ('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is fixed_depth.'), ('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is fixed_freevars'), ('lookahead.cube.psat.var_exp', DOUBLE, 1, 'free variable exponent for PSAT cutoff'), - ('lookahead.cube.psat.clause_base', DOUBLE, 1, 'clause base for PSAT cutoff') - ('lookahead.cube.psat.probability', DOUBLE' 0.5, 'probability to create lookahead cubes for PSAT cutoff') + ('lookahead.cube.psat.clause_base', DOUBLE, 2, 'clause base for PSAT cutoff'), + ('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff'), ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), From fbe8d1577ed54671a6d9fab0a59520225b701127 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 4 Dec 2017 18:05:00 -0500 Subject: [PATCH 0382/1283] new regex automata start; add complexity estimation --- src/ast/rewriter/seq_rewriter.cpp | 3 + src/ast/rewriter/seq_rewriter.h | 5 +- src/smt/params/smt_params_helper.pyg | 1 + src/smt/params/theory_str_params.cpp | 1 + src/smt/params/theory_str_params.h | 10 ++- src/smt/theory_str.cpp | 105 +++++++++++++++++++++++++++ src/smt/theory_str.h | 5 +- 7 files changed, 127 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index fa95278b4..6f501c6e0 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -200,6 +200,9 @@ void re2automaton::set_solver(expr_solver* solver) { m_sa = alloc(symbolic_automata_t, sm, *m_ba.get()); } +eautomaton* re2automaton::mk_product(eautomaton* a1, eautomaton* a2) { + return m_sa->mk_product(*a1, *a2); +} eautomaton* re2automaton::operator()(expr* e) { eautomaton* r = re2aut(e); diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 69f319168..95b043bd7 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -53,7 +53,9 @@ public: bool is_range() const { return m_ty == t_range; } sort* get_sort() const { return m_sort; } expr* get_char() const { SASSERT(is_char()); return m_t; } - + expr* get_pred() const { SASSERT(is_pred()); return m_t; } + expr* get_lo() const { SASSERT(is_range()); return m_t; } + expr* get_hi() const { SASSERT(is_range()); return m_s; } }; class sym_expr_manager { @@ -87,6 +89,7 @@ public: ~re2automaton(); eautomaton* operator()(expr* e); void set_solver(expr_solver* solver); + eautomaton* mk_product(eautomaton *a1, eautomaton *a2); }; /** diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 937aa6a2b..7f35feb64 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -79,6 +79,7 @@ def_module_params(module_name='smt', ('theory_aware_branching', BOOL, False, 'Allow the context to use extra information from theory solvers regarding literal branching prioritization.'), ('str.finite_overlap_models', BOOL, False, 'attempt a finite model search for overlapping variables instead of completely giving up on the arrangement'), ('str.overlap_priority', DOUBLE, -0.1, 'theory-aware priority for overlapping variable cases; use smt.theory_aware_branching=true'), + ('str.regex_automata', BOOL, True, 'use automata-based reasoning for regular expressions (Z3str3 only)'), ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'), diff --git a/src/smt/params/theory_str_params.cpp b/src/smt/params/theory_str_params.cpp index afbfc33fc..b5451b9dc 100644 --- a/src/smt/params/theory_str_params.cpp +++ b/src/smt/params/theory_str_params.cpp @@ -31,4 +31,5 @@ void theory_str_params::updt_params(params_ref const & _p) { m_UseBinarySearch = p.str_use_binary_search(); m_BinarySearchInitialUpperBound = p.str_binary_search_start(); m_OverlapTheoryAwarePriority = p.str_overlap_priority(); + m_RegexAutomata = p.str_regex_automata(); } diff --git a/src/smt/params/theory_str_params.h b/src/smt/params/theory_str_params.h index c841609db..4135cf0d6 100644 --- a/src/smt/params/theory_str_params.h +++ b/src/smt/params/theory_str_params.h @@ -80,6 +80,13 @@ struct theory_str_params { double m_OverlapTheoryAwarePriority; + /* + * If RegexAutomata is set to true, + * Z3str3 will use automata-based methods to reason about + * regular expression constraints. + */ + bool m_RegexAutomata; + theory_str_params(params_ref const & p = params_ref()): m_StrongArrangements(true), m_AggressiveLengthTesting(false), @@ -91,7 +98,8 @@ struct theory_str_params { m_FiniteOverlapModels(false), m_UseBinarySearch(false), m_BinarySearchInitialUpperBound(64), - m_OverlapTheoryAwarePriority(-0.1) + m_OverlapTheoryAwarePriority(-0.1), + m_RegexAutomata(true) { updt_params(p); } diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 7936b581c..a859dae9d 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6446,6 +6446,111 @@ namespace smt { } } + // saturating unsigned addition + unsigned inline _qadd(unsigned a, unsigned b) { + if (a == UINT_MAX || b == UINT_MAX) { + return UINT_MAX; + } + unsigned result = a + b; + if (result < a || result < b) { + return UINT_MAX; + } + return result; + } + + // saturating unsigned multiply + unsigned inline _qmul(unsigned a, unsigned b) { + if (a == UINT_MAX || b == UINT_MAX) { + return UINT_MAX; + } + unsigned result = a * b; + if (result < a || result < b) { + return UINT_MAX; + } + return result; + } + + unsigned theory_str::estimate_regex_complexity(expr * re) { + ENSURE(u.is_re(re)); + expr * sub1; + expr * sub2; + if (u.re.is_to_re(re, sub1)) { + SASSERT(u.str.is_string(sub1)); + zstring str; + u.str.is_string(sub1, str); + return str.length(); + } else if (u.re.is_complement(re, sub1)) { + return estimate_regex_complexity_under_complement(sub1); + } else if (u.re.is_concat(re, sub1, sub2)) { + unsigned cx1 = estimate_regex_complexity(sub1); + unsigned cx2 = estimate_regex_complexity(sub2); + return _qadd(cx1, cx2); + } else if (u.re.is_union(re, sub1, sub2)) { + unsigned cx1 = estimate_regex_complexity(sub1); + unsigned cx2 = estimate_regex_complexity(sub2); + return _qadd(cx1, cx2); + } else if (u.re.is_star(re, sub1) || u.re.is_plus(re, sub1)) { + unsigned cx = estimate_regex_complexity(sub1); + return _qmul(2, cx); + } else if (u.re.is_range(re, sub1, sub2)) { + SASSERT(u.str.is_string(sub1)); + SASSERT(u.str.is_string(sub2)); + zstring str1, str2; + u.str.is_string(sub1, str1); + u.str.is_string(sub2, str2); + SASSERT(str1.length() == 1); + SASSERT(str2.length() == 1); + return 1 + str2[0] - str1[0]; + } else if (u.re.is_full(re)) { + return 1; + } else { + TRACE("str", tout << "WARNING: unknown regex term " << mk_pp(re, get_manager()) << std::endl;); + return 1; + } + } + + unsigned theory_str::estimate_regex_complexity_under_complement(expr * re) { + ENSURE(u.is_re(re)); + expr * sub1; + expr * sub2; + if (u.re.is_to_re(re, sub1)) { + SASSERT(u.str.is_string(sub1)); + zstring str; + u.str.is_string(sub1, str); + return str.length(); + } else if (u.re.is_complement(re, sub1)) { + // Why don't we return the regular complexity here? + // We could, but this might be called from under another complemented subexpression. + // It's better to give a worst-case complexity. + return estimate_regex_complexity_under_complement(sub1); + } else if (u.re.is_concat(re, sub1, sub2)) { + unsigned cx1 = estimate_regex_complexity_under_complement(sub1); + unsigned cx2 = estimate_regex_complexity_under_complement(sub2); + return _qadd(_qmul(2, cx1), cx2); + } else if (u.re.is_union(re, sub1, sub2)) { + unsigned cx1 = estimate_regex_complexity_under_complement(sub1); + unsigned cx2 = estimate_regex_complexity_under_complement(sub2); + return _qmul(cx1, cx2); + } else if (u.re.is_star(re, sub1) || u.re.is_plus(re, sub1)) { + unsigned cx = estimate_regex_complexity_under_complement(sub1); + return _qmul(2, cx); + } else if (u.re.is_range(re, sub1, sub2)) { + SASSERT(u.str.is_string(sub1)); + SASSERT(u.str.is_string(sub2)); + zstring str1, str2; + u.str.is_string(sub1, str1); + u.str.is_string(sub2, str2); + SASSERT(str1.length() == 1); + SASSERT(str2.length() == 1); + return 1 + str2[0] - str1[0]; + } else if (u.re.is_full(re)) { + return 1; + } else { + TRACE("str", tout << "WARNING: unknown regex term " << mk_pp(re, get_manager()) << std::endl;); + return 1; + } + } + /* * strArgmt::solve_concat_eq_str() * Solve concatenations of the form: diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 03fd31162..72643c4be 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -457,11 +457,14 @@ protected: expr * mk_RegexIn(expr * str, expr * regexp); void instantiate_axiom_RegexIn(enode * e); app * mk_unroll(expr * n, expr * bound); - void process_unroll_eq_const_str(expr * unrollFunc, expr * constStr); void unroll_str2reg_constStr(expr * unrollFunc, expr * eqConstStr); void process_concat_eq_unroll(expr * concat, expr * unroll); + // regex automata + unsigned estimate_regex_complexity(expr * re); + unsigned estimate_regex_complexity_under_complement(expr * re); + void set_up_axioms(expr * ex); void handle_equality(expr * lhs, expr * rhs); From 38751430df4078e14feda6d8e50f9bf5ae1b1419 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Tue, 5 Dec 2017 17:53:48 -0800 Subject: [PATCH 0383/1283] adaptive psat cutoff Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_config.cpp | 19 +++++++++++-------- src/sat/sat_config.h | 9 +++++---- src/sat/sat_lookahead.cpp | 15 ++++++++++----- src/sat/sat_lookahead.h | 4 +++- src/sat/sat_params.pyg | 10 +++++----- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 87d84f133..660337071 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -109,20 +109,23 @@ namespace sat { throw sat_param_exception("invalid reward type supplied: accepted heuristics are 'ternary', 'heuleu', 'unit' or 'heule_schur'"); } - if (p.lookahead_cube_cutoff() == symbol("adaptive")) { - m_lookahead_cube_cutoff = adaptive_cutoff; + if (p.lookahead_cube_cutoff() == symbol("depth")) { + m_lookahead_cube_cutoff = depth_cutoff; } - else if (p.lookahead_cube_cutoff() == symbol("fixed_depth")) { - m_lookahead_cube_cutoff = fixed_depth_cutoff; - } - else if (p.lookahead_cube_cutoff() == symbol("fixed_freevars")) { - m_lookahead_cube_cutoff = fixed_freevars_cutoff; + else if (p.lookahead_cube_cutoff() == symbol("freevars")) { + m_lookahead_cube_cutoff = freevars_cutoff; } else if (p.lookahead_cube_cutoff() == symbol("psat")) { m_lookahead_cube_cutoff = psat_cutoff; } + else if (p.lookahead_cube_cutoff() == symbol("adaptive_freevars")) { + m_lookahead_cube_cutoff = adaptive_freevars_cutoff; + } + else if (p.lookahead_cube_cutoff() == symbol("adaptive_psat")) { + m_lookahead_cube_cutoff = adaptive_psat_cutoff; + } else { - throw sat_param_exception("invalid cutoff type supplied: accepted cutoffs are 'adaptive', 'fixed_depth', 'fixed_freevars'"); + throw sat_param_exception("invalid cutoff type supplied: accepted cutoffs are 'depth', 'freevars', 'psat', 'adaptive_freevars' and 'adaptive_psat'"); } m_lookahead_cube_fraction = p.lookahead_cube_fraction(); m_lookahead_cube_depth = p.lookahead_cube_depth(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index ed7802cef..f66c0dbdf 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -66,10 +66,11 @@ namespace sat { }; enum cutoff_t { - adaptive_cutoff, - fixed_depth_cutoff, - fixed_freevars_cutoff, - psat_cutoff + depth_cutoff, + freevars_cutoff, + psat_cutoff, + adaptive_freevars_cutoff, + adaptive_psat_cutoff }; struct config { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index a9ae3b641..ec1bf23f2 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2092,11 +2092,14 @@ namespace sat { } backtrack_level = UINT_MAX; depth = m_cube_state.m_cube.size(); - if ((m_config.m_cube_cutoff == fixed_depth_cutoff && depth == m_config.m_cube_depth) || - (m_config.m_cube_cutoff == adaptive_cutoff && m_freevars.size() < m_cube_state.m_freevars_threshold) || - (m_config.m_cube_cutoff == fixed_freevars_cutoff && m_freevars.size() <= m_init_freevars * m_config.m_cube_freevars) || - (m_config.m_cube_cutoff == psat_cutoff && psat_heur() >= m_config.m_cube_psat_trigger)) { - m_cube_state.m_freevars_threshold *= (1.0 - pow(m_config.m_cube_fraction, depth)); + if ((m_config.m_cube_cutoff == depth_cutoff && depth == m_config.m_cube_depth) || + (m_config.m_cube_cutoff == freevars_cutoff && m_freevars.size() <= m_init_freevars * m_config.m_cube_freevars) || + (m_config.m_cube_cutoff == psat_cutoff && psat_heur() >= m_config.m_cube_psat_trigger) || + (m_config.m_cube_cutoff == adaptive_freevars_cutoff && m_freevars.size() < m_cube_state.m_freevars_threshold) || + (m_config.m_cube_cutoff == adaptive_psat_cutoff && psat_heur() >= m_cube_state.m_psat_threshold)) { + double dec = (1.0 - pow(m_config.m_cube_fraction, depth)); + m_cube_state.m_freevars_threshold *= dec; + m_cube_state.m_psat_threshold *= dec; set_conflict(); m_cube_state.inc_cutoff(); #if 0 @@ -2109,10 +2112,12 @@ namespace sat { return l_undef; } int prev_nfreevars = m_freevars.size(); + double prev_psat = m_config.m_cube_cutoff == adaptive_psat_cutoff ? psat_heur() : DBL_MAX; // MN. only compute PSAT if enabled literal lit = choose(); if (inconsistent()) { TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); m_cube_state.m_freevars_threshold = prev_nfreevars; + m_cube_state.m_psat_threshold = prev_psat; m_cube_state.inc_conflict(); if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; continue; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 254dd614f..6a7bb7449 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -101,7 +101,7 @@ namespace sat { m_dl_max_iterations = 2; m_tc1_limit = 10000000; m_reward_type = ternary_reward; - m_cube_cutoff = adaptive_cutoff; + m_cube_cutoff = adaptive_freevars_cutoff; m_cube_depth = 10; m_cube_fraction = 0.4; m_cube_freevars = 0.8; @@ -177,6 +177,7 @@ namespace sat { svector m_is_decision; literal_vector m_cube; double m_freevars_threshold; + double m_psat_threshold; unsigned m_conflicts; unsigned m_cutoffs; cube_state() { reset(); } @@ -185,6 +186,7 @@ namespace sat { m_is_decision.reset(); m_cube.reset(); m_freevars_threshold = 0; + m_psat_threshold = DBL_MAX; reset_stats(); } void reset_stats() { m_conflicts = 0; m_cutoffs = 0; } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 0e6823030..4432c0b16 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -37,13 +37,13 @@ def_module_params('sat', ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), - ('lookahead.cube.cutoff', SYMBOL, 'adaptive', 'cutoff type used to create lookahead cubes: adaptive, fixed_depth, fixed_freevars, psat'), - ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive'), - ('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is fixed_depth.'), - ('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is fixed_freevars'), + ('lookahead.cube.cutoff', SYMBOL, 'adaptive_freevars', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), + ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat'), + ('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'), + ('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is freevars'), ('lookahead.cube.psat.var_exp', DOUBLE, 1, 'free variable exponent for PSAT cutoff'), ('lookahead.cube.psat.clause_base', DOUBLE, 2, 'clause base for PSAT cutoff'), - ('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff'), + ('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff. Used when lookahead.cube.cutoff is psat'), ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), From a5c828f6f2ea967b4b17efc8ba22070a517696d2 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 6 Dec 2017 18:32:11 -0500 Subject: [PATCH 0384/1283] length estimation --- src/smt/theory_str.cpp | 116 ++++++++++++++++++++++++++++++++++++++++- src/smt/theory_str.h | 7 ++- 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index a859dae9d..88180352c 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -25,6 +25,8 @@ #include "smt/theory_seq_empty.h" #include "smt/theory_arith.h" #include "ast/ast_util.h" +#include "seq_rewriter.h" +#include "smt_kernel.h" namespace smt { @@ -48,6 +50,7 @@ namespace smt { finalCheckProgressIndicator(false), m_trail(m), m_factory(nullptr), + m_mk_aut(m), m_unused_id(0), m_delayed_axiom_setup_terms(m), tmpStringVarCount(0), @@ -95,6 +98,26 @@ namespace smt { return u.str.mk_string(sym); } + class seq_expr_solver : public expr_solver { + kernel m_kernel; + public: + seq_expr_solver(ast_manager& m, smt_params& fp): + m_kernel(m, fp) {} + virtual lbool check_sat(expr* e) { + m_kernel.push(); + m_kernel.assert_expr(e); + lbool r = m_kernel.check(); + m_kernel.pop(1); + return r; + } + }; + + void theory_str::init(context * ctx) { + theory::init(ctx); + m_mk_aut.set_solver(alloc(seq_expr_solver, get_manager(), + get_context().get_fparams())); + } + void theory_str::initialize_charset() { bool defaultCharset = true; if (defaultCharset) { @@ -1718,6 +1741,11 @@ namespace smt { regex_in_var_reg_str_map[ex->get_arg(0)].insert(regexStr); } + if (m_params.m_RegexAutomata) { + // stop setting up axioms here, we do this differently + return; + } + expr_ref str(ex->get_arg(0), m); app * regex = to_app(ex->get_arg(1)); @@ -1887,7 +1915,7 @@ namespace smt { check_contain_in_new_eq(lhs, rhs); } - if (!regex_in_bool_map.empty()) { + if (!regex_in_bool_map.empty() && !m_params.m_RegexAutomata) { TRACE("str", tout << "checking regex consistency" << std::endl;); check_regex_in(lhs, rhs); } @@ -6550,6 +6578,92 @@ namespace smt { return 1; } } + /* + * Infer all length constraints implied by the given regular expression `re` + * in order to constrain `lenVar` (which must be of sort Int). + * This assumes that `re` appears in a positive context. + * Returns a Boolean formula expressing the appropriate constraints over `lenVar`. + * In some cases, the returned formula requires one or more free integer variables to be created. + * These variables are returned in the reference parameter `freeVariables`. + * Extra assertions should be made for these free variables constraining them to be non-negative. + */ + expr_ref theory_str::infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables) { + ENSURE(u.is_re(re)); + context & ctx = get_context(); + ast_manager & m = get_manager(); + expr * sub1; + expr * sub2; + if (u.re.is_to_re(re, sub1)) { + SASSERT(u.str.is_string(sub1)); + zstring str; + u.str.is_string(sub1, str); + rational strlen(str.length()); + expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_numeral(strlen, true)), m); + return retval; + } else if (u.re.is_union(re, sub1, sub2)) { + expr_ref r1 = infer_all_regex_lengths(lenVar, sub1, freeVariables); + expr_ref r2 = infer_all_regex_lengths(lenVar, sub2, freeVariables); + expr_ref retval(m.mk_or(r1, r2), m); + return retval; + } else if (u.re.is_concat(re, sub1, sub2)) { + expr * v1 = mk_int_var("rlen1"); + expr * v2 = mk_int_var("rlen2"); + freeVariables.push_back(v1); + freeVariables.push_back(v2); + expr_ref r1 = infer_all_regex_lengths(v1, sub1, freeVariables); + expr_ref r2 = infer_all_regex_lengths(v2, sub2, freeVariables); + expr_ref_vector finalResult(m); + finalResult.push_back(ctx.mk_eq_atom(lenVar, m_autil.mk_add(v1, v2))); + finalResult.push_back(r1); + finalResult.push_back(r2); + expr_ref retval(mk_and(finalResult), m); + return retval; + } else if (u.re.is_star(re, sub1)) { + expr * v = mk_int_var("rlen"); + expr * n = mk_int_var("rstar"); + freeVariables.push_back(v); + freeVariables.push_back(n); + expr_ref rsub = infer_all_regex_lengths(v, sub1, freeVariables); + expr_ref_vector finalResult(m); + finalResult.push_back(rsub); + finalResult.push_back(ctx.mk_eq_atom(lenVar, m_autil.mk_mul(v, n))); + expr_ref retval(mk_and(finalResult), m); + return retval; + } else if (u.re.is_plus(re, sub1)) { + expr * v = mk_int_var("rlen"); + expr * n = mk_int_var("rstar"); + freeVariables.push_back(v); + freeVariables.push_back(n); + expr_ref rsub = infer_all_regex_lengths(v, sub1, freeVariables); + expr_ref_vector finalResult(m); + finalResult.push_back(rsub); + finalResult.push_back(ctx.mk_eq_atom(lenVar, m_autil.mk_mul(v, n))); + finalResult.push_back(m_autil.mk_ge(n, m_autil.mk_numeral(rational::one(), true))); + expr_ref retval(mk_and(finalResult), m); + return retval; + } else if (u.re.is_range(re, sub1, sub2)) { + SASSERT(u.str.is_string(sub1)); + SASSERT(u.str.is_string(sub2)); + zstring str1, str2; + u.str.is_string(sub1, str1); + u.str.is_string(sub2, str2); + SASSERT(str1.length() == 1); + SASSERT(str2.length() == 1); + expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_numeral(rational::one(), true)), m); + return retval; + } else if (u.re.is_full(re)) { + expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_numeral(rational::one(), true)), m); + return retval; + } else if (u.re.is_complement(re)) { + // skip complement for now, in general this is difficult to predict + expr_ref retval(m_autil.mk_ge(lenVar, m_autil.mk_numeral(rational::zero(), true)), m); + return retval; + } else { + TRACE("str", tout << "WARNING: unknown regex term " << mk_pp(re, m) << std::endl;); + expr_ref retval(m_autil.mk_ge(lenVar, m_autil.mk_numeral(rational::zero(), true)), m); + return retval; + } + } /* * strArgmt::solve_concat_eq_str() diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 72643c4be..602f9feab 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -23,6 +23,7 @@ #include "ast/ast_pp.h" #include "ast/arith_decl_plugin.h" #include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/seq_rewriter.h" #include "ast/seq_decl_plugin.h" #include "smt/smt_theory.h" #include "smt/params/theory_str_params.h" @@ -267,6 +268,8 @@ protected: str_value_factory * m_factory; + re2automaton m_mk_aut; + // Unique identifier appended to unused variables to ensure that model construction // does not introduce equalities when they weren't enforced. unsigned m_unused_id; @@ -461,9 +464,10 @@ protected: void unroll_str2reg_constStr(expr * unrollFunc, expr * eqConstStr); void process_concat_eq_unroll(expr * concat, expr * unroll); - // regex automata + // regex automata and length-aware regex unsigned estimate_regex_complexity(expr * re); unsigned estimate_regex_complexity_under_complement(expr * re); + expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); void set_up_axioms(expr * ex); void handle_equality(expr * lhs, expr * rhs); @@ -640,6 +644,7 @@ protected: virtual void new_diseq_eh(theory_var, theory_var); virtual theory* mk_fresh(context*) { return alloc(theory_str, get_manager(), m_params); } + virtual void init(context * ctx); virtual void init_search_eh(); virtual void add_theory_assumptions(expr_ref_vector & assumptions); virtual lbool validate_unsat_core(expr_ref_vector & unsat_core); From 9554723b44860733e8a633de724aa06bb9ed9a99 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 6 Dec 2017 20:50:03 -0500 Subject: [PATCH 0385/1283] use safer mk_and in extended indexof --- src/smt/theory_str.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index a931ae458..4f84ed2f7 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1330,7 +1330,7 @@ namespace smt { ite2ElseItems.push_back(ctx.mk_eq_atom(indexAst, mk_indexof(suffix, expr->get_arg(1)))); ite2ElseItems.push_back(ctx.mk_eq_atom(expr->get_arg(2), prefixLen)); ite2ElseItems.push_back(ite3); - expr_ref ite2Else(m.mk_and(ite2ElseItems.size(), ite2ElseItems.c_ptr()), m); + expr_ref ite2Else(mk_and(ite2ElseItems), m); SASSERT(ite2Else); expr_ref ite2(m.mk_ite( From 6d729f1f158ebc406262dad703b31470a42ea0a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Dec 2017 10:36:42 -0800 Subject: [PATCH 0386/1283] disable UHLT Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 8e5e556e3..dbb5ea123 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -208,7 +208,6 @@ namespace sat { m_to_delete.reset(); for (unsigned i = m_pos.size() - 1; i-- > 0; ) { literal lit = m_pos[i]; - SASSERT(scc.get_left(lit) < scc.get_left(last)); int right2 = scc.get_right(lit); if (right2 > right) { // lit => last, so lit can be deleted @@ -345,10 +344,12 @@ namespace sat { bool asymm_branch::process_sampled(scc& scc, clause & c) { scoped_detach scoped_d(s, c); sort(scc, c); +#if 0 if (uhte(scc, c)) { scoped_d.del_clause(); return false; } +#endif return uhle(scoped_d, scc, c); } From 35a3523fd6fb612fc796f6c0d1794ea1e5a93373 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Dec 2017 14:09:34 -0800 Subject: [PATCH 0387/1283] fix bug in double collection of declarations Signed-off-by: Nikolaj Bjorner --- src/ast/ast.h | 3 +++ src/ast/decl_collector.cpp | 25 ++++++++++--------------- src/ast/decl_collector.h | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index e579e4565..682660638 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -622,6 +622,9 @@ public: sort * const * get_domain() const { return m_domain; } sort * get_range() const { return m_range; } unsigned get_size() const { return get_obj_size(m_arity); } + sort * const * begin() const { return get_domain(); } + sort * const * end() const { return get_domain() + get_arity(); } + }; // ----------------------------------- diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index 0df4b0fc5..5d47170ee 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -20,20 +20,15 @@ Revision History: #include "ast/decl_collector.h" void decl_collector::visit_sort(sort * n) { + SASSERT(!m_visited.is_marked(n)); family_id fid = n->get_family_id(); if (m().is_uninterp(n)) m_sorts.push_back(n); - if (fid == m_dt_fid) { + else if (fid == m_dt_fid) { m_sorts.push_back(n); - - unsigned num_cnstr = m_dt_util.get_datatype_num_constructors(n); - for (unsigned i = 0; i < num_cnstr; i++) { - func_decl * cnstr = m_dt_util.get_datatype_constructors(n)->get(i); + for (func_decl* cnstr : *m_dt_util.get_datatype_constructors(n)) { m_decls.push_back(cnstr); - ptr_vector const & cnstr_acc = *m_dt_util.get_constructor_accessors(cnstr); - unsigned num_cas = cnstr_acc.size(); - for (unsigned j = 0; j < num_cas; j++) { - func_decl * accsr = cnstr_acc.get(j); + for (func_decl * accsr : *m_dt_util.get_constructor_accessors(cnstr)) { m_decls.push_back(accsr); } } @@ -53,6 +48,7 @@ void decl_collector::visit_func(func_decl * n) { else m_decls.push_back(n); } + m_visited.mark(n, true); } } @@ -72,11 +68,10 @@ void decl_collector::visit(ast* n) { if (!m_visited.is_marked(n)) { switch(n->get_kind()) { case AST_APP: { - app * a = to_app(n); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - m_todo.push_back(a->get_arg(i)); + for (expr * e : *to_app(n)) { + m_todo.push_back(e); } - m_todo.push_back(a->get_decl()); + m_todo.push_back(to_app(n)->get_decl()); break; } case AST_QUANTIFIER: { @@ -96,8 +91,8 @@ void decl_collector::visit(ast* n) { break; case AST_FUNC_DECL: { func_decl * d = to_func_decl(n); - for (unsigned i = 0; i < d->get_arity(); ++i) { - m_todo.push_back(d->get_domain(i)); + for (sort* srt : *d) { + m_todo.push_back(srt); } m_todo.push_back(d->get_range()); visit_func(d); diff --git a/src/ast/decl_collector.h b/src/ast/decl_collector.h index 0a812bb2c..36d7c930b 100644 --- a/src/ast/decl_collector.h +++ b/src/ast/decl_collector.h @@ -41,7 +41,7 @@ class decl_collector { public: // if preds == true, then predicates are stored in a separate collection. - decl_collector(ast_manager & m, bool preds=true); + decl_collector(ast_manager & m, bool preds = true); ast_manager & m() { return m_manager; } void visit_func(func_decl* n); From 9f0a8af2555bc031d004c8f23d62c6e915147ac6 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Mon, 11 Dec 2017 14:14:16 -0800 Subject: [PATCH 0388/1283] fixed adaptive apsat Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_asymm_branch.cpp | 2 +- src/sat/sat_lookahead.cpp | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 8e5e556e3..d8235d6b1 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -208,7 +208,7 @@ namespace sat { m_to_delete.reset(); for (unsigned i = m_pos.size() - 1; i-- > 0; ) { literal lit = m_pos[i]; - SASSERT(scc.get_left(lit) < scc.get_left(last)); + //SASSERT(scc.get_left(lit) < scc.get_left(last)); int right2 = scc.get_right(lit); if (right2 > right) { // lit => last, so lit can be deleted diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index ec1bf23f2..08d7ad9e4 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1476,7 +1476,7 @@ namespace sat { } } if (m_search_mode == lookahead_mode::lookahead1) { - SASSERT(nonfixed >= 2); + //SASSERT(nonfixed >= 2); switch (m_config.m_reward_type) { case heule_schur_reward: { double to_add = 0; @@ -1492,7 +1492,7 @@ namespace sat { m_lookahead_reward += pow(0.5, nonfixed); break; case march_cu_reward: - m_lookahead_reward += 3.3 * pow(0.5, nonfixed - 2); + m_lookahead_reward += nonfixed >= 2 ? 3.3 * pow(0.5, nonfixed - 2) : 0.0; break; case ternary_reward: UNREACHABLE(); @@ -1702,7 +1702,8 @@ namespace sat { num_units += do_double(lit, dl_lvl); if (dl_lvl > level) { base = dl_lvl; - SASSERT(get_level(m_trail.back()) == base + m_lookahead[i].m_offset); + //SASSERT(get_level(m_trail.back()) == base + m_lookahead[i].m_offset); + SASSERT(get_level(m_trail.back()) == base); } unsat = inconsistent(); pop_lookahead1(lit, num_units); @@ -1821,11 +1822,11 @@ namespace sat { unsigned lookahead::double_look(literal l, unsigned& base) { SASSERT(!inconsistent()); SASSERT(dl_no_overflow(base)); + SASSERT(is_fixed_at(l, base)); base += m_lookahead.size(); unsigned dl_truth = base + m_lookahead.size() * m_config.m_dl_max_iterations; scoped_level _sl(*this, dl_truth); - SASSERT(get_level(m_trail.back()) == dl_truth); - SASSERT(is_fixed(l)); + //SASSERT(get_level(m_trail.back()) == dl_truth); IF_VERBOSE(2, verbose_stream() << "(sat-lookahead :double " << l << " :depth " << m_trail_lim.size() << ")\n";); lookahead_backtrack(); assign(l); @@ -2077,7 +2078,8 @@ namespace sat { inc_istamp(); if (inconsistent()) { TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); - m_cube_state.m_freevars_threshold = m_freevars.size(); + m_cube_state.m_freevars_threshold = m_freevars.size(); + m_cube_state.m_psat_threshold = m_config.m_cube_cutoff == adaptive_psat_cutoff ? psat_heur() : DBL_MAX; // MN. only compute PSAT if enabled m_cube_state.inc_conflict(); if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; continue; @@ -2099,7 +2101,7 @@ namespace sat { (m_config.m_cube_cutoff == adaptive_psat_cutoff && psat_heur() >= m_cube_state.m_psat_threshold)) { double dec = (1.0 - pow(m_config.m_cube_fraction, depth)); m_cube_state.m_freevars_threshold *= dec; - m_cube_state.m_psat_threshold *= dec; + m_cube_state.m_psat_threshold *= 2.0 - dec; set_conflict(); m_cube_state.inc_cutoff(); #if 0 @@ -2423,12 +2425,12 @@ namespace sat { } } } - std::cout << candidates.size() << " -> " << k << "\n"; + //std::cout << candidates.size() << " -> " << k << "\n"; if (k == candidates.size()) break; candidates.shrink(k); } - std::cout << "candidates: " << candidates.size() << "\n"; + //std::cout << "candidates: " << candidates.size() << "\n"; #endif From 7afbf8165ed403dd23e6510fa0c44feaad20158f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Dec 2017 01:36:44 -0800 Subject: [PATCH 0389/1283] snapshot Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 9 - src/api/dotnet/Solver.cs | 24 +-- src/api/z3_api.h | 10 -- src/ast/rewriter/pb2bv_rewriter.cpp | 5 +- src/sat/sat_asymm_branch.cpp | 161 ++++++++++++------ src/sat/sat_asymm_branch.h | 10 ++ src/sat/sat_asymm_branch_params.pyg | 1 + src/sat/sat_config.cpp | 118 +++++-------- src/sat/sat_config.h | 14 +- src/sat/sat_elim_vars.cpp | 3 +- src/sat/sat_local_search.cpp | 38 ++--- src/sat/sat_lookahead.cpp | 73 ++------ src/sat/sat_params.pyg | 3 +- src/sat/sat_scc.h | 5 +- src/sat/sat_simplifier.cpp | 27 +-- src/sat/sat_simplifier.h | 1 + src/sat/sat_solver.cpp | 13 +- src/sat/sat_solver.h | 2 + src/sat/sat_solver/inc_sat_solver.cpp | 11 +- src/smt/smt_solver.cpp | 4 - src/solver/combined_solver.cpp | 6 - src/solver/solver.h | 6 - .../portfolio/bounded_int2bv_solver.cpp | 4 - src/tactic/portfolio/enum2bv_solver.cpp | 10 -- src/tactic/portfolio/pb2bv_solver.cpp | 4 - 25 files changed, 230 insertions(+), 332 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 8c2cbf25e..2805e7e2d 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -323,15 +323,6 @@ extern "C" { Z3_CATCH; } - void Z3_API Z3_solver_assert_lemma(Z3_context c, Z3_solver s, Z3_ast a) { - Z3_TRY; - LOG_Z3_solver_assert_lemma(c, s, a); - RESET_ERROR_CODE(); - init_solver(c, s); - CHECK_FORMULA(a,); - to_solver_ref(s)->assert_lemma(to_expr(a)); - Z3_CATCH; - } Z3_ast_vector Z3_API Z3_solver_get_assertions(Z3_context c, Z3_solver s) { Z3_TRY; diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index af5f8e47e..e136516e4 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -239,29 +239,6 @@ namespace Microsoft.Z3 Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); } - /// - /// Assert a lemma (or multiple) into the solver. - /// - public void AssertLemma(params BoolExpr[] constraints) - { - Contract.Requires(constraints != null); - Contract.Requires(Contract.ForAll(constraints, c => c != null)); - - Context.CheckContextMatch(constraints); - foreach (BoolExpr a in constraints) - { - Native.Z3_solver_assert_lemma(Context.nCtx, NativeObject, a.NativeObject); - } - } - - /// - /// Assert a lemma (or multiple) into the solver. - /// - public void AddLemma(IEnumerable constraints) - { - AssertLemma(constraints.ToArray()); - } - /// /// The number of assertions in the solver. /// @@ -325,6 +302,7 @@ namespace Microsoft.Z3 return lboolToStatus(r); } + /// /// Retrieve fixed assignments to the set of variables in the form of consequences. /// Each consequence is an implication of the form diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7f92501ec..b212912b9 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6135,16 +6135,6 @@ extern "C" { */ void Z3_API Z3_solver_assert_and_track(Z3_context c, Z3_solver s, Z3_ast a, Z3_ast p); - /** - \brief add a lemma. A lemma is a assumed to be a consequence of the current assertions. - Adding a lemma should therefore be a logical no-op. Solvers are free to ignore lemmas. - - \pre \c a must be a Boolean expression - - def_API('Z3_solver_assert_lemma', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST))) - */ - void Z3_API Z3_solver_assert_lemma(Z3_context c, Z3_solver s, Z3_ast a); - /** \brief load solver assertions from a file. diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 1e8cd7182..0a0fed292 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -319,9 +319,8 @@ struct pb2bv_rewriter::imp { sums.insert(sum); } } - uint_set::iterator it = sums.begin(), end = sums.end(); - for (; it != end; ++it) { - oc.push_back(*it); + for (unsigned u : sums) { + oc.push_back(u); } std::sort(oc.begin(), oc.end()); DEBUG_CODE( diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 8e5e556e3..eb7be411a 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -42,9 +42,13 @@ namespace sat { asymm_branch & m_asymm_branch; stopwatch m_watch; unsigned m_elim_literals; + unsigned m_elim_learned_literals; + unsigned m_hidden_tautologies; report(asymm_branch & a): m_asymm_branch(a), - m_elim_literals(a.m_elim_literals) { + m_elim_literals(a.m_elim_literals), + m_elim_learned_literals(a.m_elim_learned_literals), + m_hidden_tautologies(a.m_hidden_tautologies) { m_watch.start(); } @@ -53,12 +57,35 @@ namespace sat { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << " (sat-asymm-branch :elim-literals " << (m_asymm_branch.m_elim_literals - m_elim_literals) + << " :elim-learned-literals " << (m_asymm_branch.m_elim_learned_literals - m_elim_learned_literals) + << " :hidden-tautologies " << (m_asymm_branch.m_hidden_tautologies - m_hidden_tautologies) << " :cost " << m_asymm_branch.m_counter << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } }; + bool asymm_branch::process(scc* scc) { + unsigned elim0 = m_elim_literals; + unsigned eliml0 = m_elim_learned_literals; + for (unsigned i = 0; i < m_asymm_branch_rounds; ++i) { + unsigned elim = m_elim_literals; + if (scc) scc->init_big(true); + process(scc, s.m_clauses); + process(scc, s.m_learned); + s.propagate(false); + if (s.m_inconsistent) + break; + std::cout << "elim: " << m_elim_literals - elim << "\n"; + if (m_elim_literals == elim) + break; + } + std::cout << "elim-literals: " << m_elim_literals - elim0 << "\n"; + std::cout << "elim-learned-literals: " << m_elim_learned_literals - eliml0 << "\n"; + return m_elim_literals > elim0; + } + + void asymm_branch::process(scc* scc, clause_vector& clauses) { int64 limit = -m_asymm_branch_limit; std::stable_sort(clauses.begin(), clauses.end(), clause_size_lt()); @@ -119,26 +146,23 @@ namespace sat { TRACE("asymm_branch_detail", s.display(tout);); report rpt(*this); svector saved_phase(s.m_phase); - if (m_asymm_branch) { - m_counter = 0; - process(nullptr, s.m_clauses); - m_counter = -m_counter; - } - if (m_asymm_branch_sampled) { - scc scc(s, m_params); - while (true) { - unsigned elim = m_elim_literals; - scc.init_big(true); - process(&scc, s.m_clauses); - process(&scc, s.m_learned); - s.propagate(false); - if (s.m_inconsistent) - break; - std::cout << m_elim_literals - elim << "\n"; - if (m_elim_literals == elim) - break; + + bool change = true; + unsigned counter = 0; + while (change && counter < 2) { + ++counter; + change = false; + if (m_asymm_branch_sampled) { + scc sc(s, m_params); + if (process(&sc)) change = true; + } + if (m_asymm_branch) { + m_counter = 0; + if (process(nullptr)) change = true; + m_counter = -m_counter; } } + s.m_phase = saved_phase; m_asymm_branch_limit *= 2; if (m_asymm_branch_limit > UINT_MAX) @@ -172,8 +196,13 @@ namespace sat { }; void asymm_branch::sort(scc& scc, clause const& c) { + sort(scc, c.begin(), c.end()); + } + + void asymm_branch::sort(scc& scc, literal const* begin, literal const* end) { m_pos.reset(); m_neg.reset(); - for (literal l : c) { + for (; begin != end; ++begin) { + literal l = *begin; m_pos.push_back(l); m_neg.push_back(~l); } @@ -203,23 +232,42 @@ namespace sat { return false; } - bool asymm_branch::uhle(scoped_detach& scoped_d, scc& scc, clause & c) { - int right = scc.get_right(m_pos.back()); - m_to_delete.reset(); - for (unsigned i = m_pos.size() - 1; i-- > 0; ) { - literal lit = m_pos[i]; - SASSERT(scc.get_left(lit) < scc.get_left(last)); - int right2 = scc.get_right(lit); - if (right2 > right) { - // lit => last, so lit can be deleted - m_to_delete.push_back(lit); + void asymm_branch::minimize(scc& scc, literal_vector& lemma) { + scc.ensure_big(true); + sort(scc, lemma.begin(), lemma.end()); + uhle(scc); + if (!m_to_delete.empty()) { + unsigned j = 0; + for (unsigned i = 0; i < lemma.size(); ++i) { + literal l = lemma[i]; + if (!m_to_delete.contains(l)) { + lemma[j++] = l; + } } - else { - right = right2; + // std::cout << lemma.size() << " -> " << j << "\n"; + lemma.shrink(j); + } + } + + void asymm_branch::uhle(scc& scc) { + m_to_delete.reset(); + if (m_to_delete.empty()) { + int right = scc.get_right(m_pos.back()); + for (unsigned i = m_pos.size() - 1; i-- > 0; ) { + literal lit = m_pos[i]; + SASSERT(scc.get_left(lit) < scc.get_left(last)); + int right2 = scc.get_right(lit); + if (right2 > right) { + // lit => last, so lit can be deleted + m_to_delete.push_back(lit); + } + else { + right = right2; + } } } if (m_to_delete.empty()) { - right = scc.get_right(m_neg[0]); + int right = scc.get_right(m_neg[0]); for (unsigned i = 1; i < m_neg.size(); ++i) { literal lit = m_neg[i]; int right2 = scc.get_right(lit); @@ -232,20 +280,11 @@ namespace sat { } } } - if (!m_to_delete.empty()) { -#if 0 - std::cout << "delete " << m_to_delete << "\n"; + } - std::cout << "pos\n"; - for (literal l : m_pos) { - std::cout << l << ": " << scc.get_left(l) << " " << scc.get_right(l) << "\n"; - } - std::cout << "neg\n"; - for (literal l : m_neg) { - std::cout << l << ": " << scc.get_left(l) << " " << scc.get_right(l) << "\n"; - } - std::cout << "\n"; -#endif + bool asymm_branch::uhle(scoped_detach& scoped_d, scc& scc, clause & c) { + uhle(scc); + if (!m_to_delete.empty()) { unsigned j = 0; for (unsigned i = 0; i < c.size(); ++i) { if (!m_to_delete.contains(c[i])) { @@ -314,10 +353,13 @@ namespace sat { return re_attach(scoped_d, c, new_sz); } - bool asymm_branch::re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz) { - m_elim_literals += c.size() - new_sz; - switch(new_sz) { - case 0: + bool asymm_branch::re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz) { + m_elim_literals += c.size() - new_sz; + if (c.is_learned()) { + m_elim_learned_literals += c.size() - new_sz; + } + switch(new_sz) { + case 0: s.set_conflict(justification()); return false; case 1: @@ -329,7 +371,7 @@ namespace sat { return false; // check_missed_propagation() may fail, since m_clauses is not in a consistent state. case 2: SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); - s.mk_bin_clause(c[0], c[1], false); + s.mk_bin_clause(c[0], c[1], c.is_learned()); scoped_d.del_clause(); SASSERT(s.m_qhead == s.m_trail.size()); return false; @@ -345,10 +387,13 @@ namespace sat { bool asymm_branch::process_sampled(scc& scc, clause & c) { scoped_detach scoped_d(s, c); sort(scc, c); +#if 0 if (uhte(scc, c)) { + ++m_hidden_tautologies; scoped_d.del_clause(); return false; } +#endif return uhle(scoped_d, scc, c); } @@ -381,7 +426,7 @@ namespace sat { // clause must not be used for propagation scoped_detach scoped_d(s, c); unsigned new_sz = c.size(); - unsigned flip_position = 2 + m_rand(c.size() - 2); // don't flip on the watch literals. + unsigned flip_position = m_rand(c.size()); bool found_conflict = flip_literal_at(c, flip_position, new_sz); SASSERT(!s.inconsistent()); SASSERT(s.scope_lvl() == 0); @@ -399,11 +444,12 @@ namespace sat { void asymm_branch::updt_params(params_ref const & _p) { sat_asymm_branch_params p(_p); - m_asymm_branch = p.asymm_branch(); - m_asymm_branch_delay = p.asymm_branch_delay(); + m_asymm_branch = p.asymm_branch(); + m_asymm_branch_rounds = p.asymm_branch_rounds(); + m_asymm_branch_delay = p.asymm_branch_delay(); m_asymm_branch_sampled = p.asymm_branch_sampled(); - m_asymm_branch_limit = p.asymm_branch_limit(); - m_asymm_branch_all = p.asymm_branch_all(); + m_asymm_branch_limit = p.asymm_branch_limit(); + m_asymm_branch_all = p.asymm_branch_all(); if (m_asymm_branch_limit > UINT_MAX) m_asymm_branch_limit = UINT_MAX; } @@ -414,10 +460,13 @@ namespace sat { void asymm_branch::collect_statistics(statistics & st) const { st.update("elim literals", m_elim_literals); + st.update("hidden tautologies", m_hidden_tautologies); } void asymm_branch::reset_statistics() { m_elim_literals = 0; + m_elim_learned_literals = 0; + m_hidden_tautologies = 0; } }; diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 4510aaddf..14c37427e 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -39,6 +39,7 @@ namespace sat { // config bool m_asymm_branch; + unsigned m_asymm_branch_rounds; unsigned m_asymm_branch_delay; bool m_asymm_branch_sampled; bool m_asymm_branch_propagate; @@ -47,20 +48,27 @@ namespace sat { // stats unsigned m_elim_literals; + unsigned m_elim_learned_literals; + unsigned m_hidden_tautologies; literal_vector m_pos, m_neg; // literals (complements of literals) in clauses sorted by discovery time (m_left in scc). literal_vector m_to_delete; struct compare_left; + void sort(scc& scc, literal const* begin, literal const* end); void sort(scc & scc, clause const& c); bool uhle(scoped_detach& scoped_d, scc & scc, clause & c); + void uhle(scc & scc); + bool uhte(scc & scc, clause & c); bool re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz); + bool process(scc* scc); + bool process(clause & c); bool process_sampled(scc& scc, clause & c); @@ -86,6 +94,8 @@ namespace sat { void collect_statistics(statistics & st) const; void reset_statistics(); + void minimize(scc& scc, literal_vector& lemma); + void init_search() { m_calls = 0; } inline void dec(unsigned c) { m_counter -= c; } diff --git a/src/sat/sat_asymm_branch_params.pyg b/src/sat/sat_asymm_branch_params.pyg index a457220be..0fd19d500 100644 --- a/src/sat/sat_asymm_branch_params.pyg +++ b/src/sat/sat_asymm_branch_params.pyg @@ -2,6 +2,7 @@ def_module_params(module_name='sat', class_name='sat_asymm_branch_params', export=True, params=(('asymm_branch', BOOL, True, 'asymmetric branching'), + ('asymm_branch.rounds', UINT, 10, 'maximal number of rounds to run asymmetric branch simplifications if progress is made'), ('asymm_branch.delay', UINT, 1, 'number of simplification rounds to wait until invoking asymmetric branch simplification'), ('asymm_branch.sampled', BOOL, False, 'use sampling based asymmetric branching based on binary implication graph'), ('asymm_branch.limit', UINT, 100000000, 'approx. maximum number of literals visited during asymmetric branching'), diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index ed951fd93..940dc4e43 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -24,24 +24,8 @@ Revision History: namespace sat { - config::config(params_ref const & p): - m_restart_max(0), - m_always_true("always_true"), - m_always_false("always_false"), - m_caching("caching"), - m_random("random"), - m_geometric("geometric"), - m_luby("luby"), - m_dyn_psm("dyn_psm"), - m_psm("psm"), - m_glue("glue"), - m_glue_psm("glue_psm"), - m_psm_glue("psm_glue") { - m_num_threads = 1; - m_lookahead_simplify = false; - m_lookahead_simplify_bca = false; - m_elim_vars = false; - m_incremental = false; + config::config(params_ref const & p) { + m_incremental = false; // ad-hoc parameter updt_params(p); } @@ -50,21 +34,21 @@ namespace sat { m_max_memory = megabytes_to_bytes(p.max_memory()); symbol s = p.restart(); - if (s == m_luby) + if (s == symbol("luby")) m_restart = RS_LUBY; - else if (s == m_geometric) + else if (s == symbol("geometric")) m_restart = RS_GEOMETRIC; else throw sat_param_exception("invalid restart strategy"); s = p.phase(); - if (s == m_always_false) + if (s == symbol("always_false")) m_phase = PS_ALWAYS_FALSE; - else if (s == m_always_true) + else if (s == symbol("always_true")) m_phase = PS_ALWAYS_TRUE; - else if (s == m_caching) + else if (s == symbol("caching")) m_phase = PS_CACHING; - else if (s == m_random) + else if (s == symbol("random")) m_phase = PS_RANDOM; else throw sat_param_exception("invalid phase selection strategy"); @@ -90,24 +74,18 @@ namespace sat { m_local_search_threads = p.local_search_threads(); m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify_bca = p.lookahead_simplify_bca(); - if (p.lookahead_reward() == symbol("heule_schur")) { + if (p.lookahead_reward() == symbol("heule_schur")) m_lookahead_reward = heule_schur_reward; - } - else if (p.lookahead_reward() == symbol("heuleu")) { + else if (p.lookahead_reward() == symbol("heuleu")) m_lookahead_reward = heule_unit_reward; - } - else if (p.lookahead_reward() == symbol("ternary")) { + else if (p.lookahead_reward() == symbol("ternary")) m_lookahead_reward = ternary_reward; - } - else if (p.lookahead_reward() == symbol("unit")) { + else if (p.lookahead_reward() == symbol("unit")) m_lookahead_reward = unit_literal_reward; - } - else if (p.lookahead_reward() == symbol("march_cu")) { + else if (p.lookahead_reward() == symbol("march_cu")) m_lookahead_reward = march_cu_reward; - } - else { + else throw sat_param_exception("invalid reward type supplied: accepted heuristics are 'ternary', 'heuleu', 'unit' or 'heule_schur'"); - } m_lookahead_cube_fraction = p.lookahead_cube_fraction(); m_lookahead_cube_cutoff = p.lookahead_cube_cutoff(); @@ -120,29 +98,23 @@ namespace sat { // -------------------------------- s = p.gc(); - if (s == m_dyn_psm) { - m_gc_strategy = GC_DYN_PSM; - m_gc_initial = p.gc_initial(); - m_gc_increment = p.gc_increment(); - m_gc_small_lbd = p.gc_small_lbd(); - m_gc_k = p.gc_k(); - if (m_gc_k > 255) - m_gc_k = 255; - } - else { - if (s == m_glue_psm) - m_gc_strategy = GC_GLUE_PSM; - else if (s == m_glue) - m_gc_strategy = GC_GLUE; - else if (s == m_psm) - m_gc_strategy = GC_PSM; - else if (s == m_psm_glue) - m_gc_strategy = GC_PSM_GLUE; - else - throw sat_param_exception("invalid gc strategy"); - m_gc_initial = p.gc_initial(); - m_gc_increment = p.gc_increment(); - } + if (s == symbol("dyn_psm")) + m_gc_strategy = GC_DYN_PSM; + else if (s == symbol("glue_psm")) + m_gc_strategy = GC_GLUE_PSM; + else if (s == symbol("glue")) + m_gc_strategy = GC_GLUE; + else if (s == symbol("psm")) + m_gc_strategy = GC_PSM; + else if (s == symbol("psm_glue")) + m_gc_strategy = GC_PSM_GLUE; + else + throw sat_param_exception("invalid gc strategy"); + m_gc_initial = p.gc_initial(); + m_gc_increment = p.gc_increment(); + m_gc_small_lbd = p.gc_small_lbd(); + m_gc_k = std::min(255u, p.gc_k()); + m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); @@ -154,18 +126,15 @@ namespace sat { // Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016. m_branching_heuristic = BH_VSIDS; - if (p.branching_heuristic() == symbol("vsids")) { + if (p.branching_heuristic() == symbol("vsids")) m_branching_heuristic = BH_VSIDS; - } - else if (p.branching_heuristic() == symbol("chb")) { + else if (p.branching_heuristic() == symbol("chb")) m_branching_heuristic = BH_CHB; - } - else if (p.branching_heuristic() == symbol("lrb")) { + else if (p.branching_heuristic() == symbol("lrb")) m_branching_heuristic = BH_LRB; - } - else { + else throw sat_param_exception("invalid branching heuristic: accepted heuristics are 'vsids', 'lrb' or 'chb'"); - } + m_anti_exploration = p.branching_anti_exploration(); m_step_size_init = 0.40; m_step_size_dec = 0.000001; @@ -177,21 +146,16 @@ namespace sat { // PB parameters s = p.pb_solver(); - if (s == symbol("circuit")) { + if (s == symbol("circuit")) m_pb_solver = PB_CIRCUIT; - } - else if (s == symbol("sorting")) { + else if (s == symbol("sorting")) m_pb_solver = PB_SORTING; - } - else if (s == symbol("totalizer")) { + else if (s == symbol("totalizer")) m_pb_solver = PB_TOTALIZER; - } - else if (s == symbol("solver")) { + else if (s == symbol("solver")) m_pb_solver = PB_SOLVER; - } - else { + else throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); - } sat_simplifier_params sp(_p); m_elim_vars = sp.elim_vars(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index c3018ef29..b2ccb8a1f 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -101,6 +101,7 @@ namespace sat { unsigned m_gc_increment; unsigned m_gc_small_lbd; unsigned m_gc_k; + bool m_gc_burst; bool m_minimize_lemmas; bool m_dyn_sub_res; @@ -110,20 +111,7 @@ namespace sat { symbol m_drat_file; bool m_drat_check_unsat; bool m_drat_check_sat; - - symbol m_always_true; - symbol m_always_false; - symbol m_caching; - symbol m_random; - symbol m_geometric; - symbol m_luby; - symbol m_dyn_psm; - symbol m_psm; - symbol m_glue; - symbol m_glue_psm; - symbol m_psm_glue; - pb_solver m_pb_solver; // branching heuristic settings. diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 5dd3ed1f7..7e803eaa5 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -87,6 +87,7 @@ namespace sat{ simp.m_neg_cls.reset(); simp.collect_clauses(pos_l, simp.m_pos_cls, false); simp.collect_clauses(neg_l, simp.m_neg_cls, false); + VERIFY(!s.is_external(v)); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); simp.save_clauses(mc_entry, simp.m_pos_cls); simp.save_clauses(mc_entry, simp.m_neg_cls); @@ -99,7 +100,7 @@ namespace sat{ pos_occs.reset(); neg_occs.reset(); literal_vector lits; - add_clauses(b, lits); + add_clauses(b, lits); return true; } diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 3a9e48182..726fda7f4 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -301,12 +301,10 @@ namespace sat { for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { literal l1 = ~to_literal(l_idx); watch_list const & wlist = s.m_watches[l_idx]; - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_unblocked_clause()) + for (watched const& w : wlist) { + if (!w.is_binary_unblocked_clause()) continue; - literal l2 = it->get_literal(); + literal l2 = w.get_literal(); if (l1.index() > l2.index()) continue; literal ls[2] = { l1, l2 }; @@ -316,11 +314,8 @@ namespace sat { } // copy clauses - clause_vector::const_iterator it = s.m_clauses.begin(); - clause_vector::const_iterator end = s.m_clauses.end(); - for (; it != end; ++it) { - clause& c = *(*it); - add_clause(c.size(), c.begin()); + for (clause* c : s.m_clauses) { + add_clause(c->size(), c->begin()); } m_num_non_binary_clauses = s.m_clauses.size(); @@ -568,12 +563,11 @@ namespace sat { best_var = v = l.var(); bool tt = cur_solution(v); coeff_vector const& falsep = m_vars[v].m_watch[!tt]; - coeff_vector::const_iterator it = falsep.begin(), end = falsep.end(); - for (; it != end; ++it) { - int slack = constraint_slack(it->m_constraint_id); + for (pbcoeff const& pbc : falsep) { + int slack = constraint_slack(pbc.m_constraint_id); if (slack < 0) ++best_bsb; - else if (slack < static_cast(it->m_coeff)) + else if (slack < static_cast(pbc.m_coeff)) best_bsb += num_unsat; } ++cit; @@ -583,7 +577,7 @@ namespace sat { v = l.var(); unsigned bsb = 0; coeff_vector const& falsep = m_vars[v].m_watch[!cur_solution(v)]; - coeff_vector::const_iterator it = falsep.begin(), end = falsep.end(); + auto it = falsep.begin(), end = falsep.end(); for (; it != end; ++it) { int slack = constraint_slack(it->m_constraint_id); if (slack < 0) { @@ -637,22 +631,20 @@ namespace sat { coeff_vector const& truep = m_vars[flipvar].m_watch[flip_is_true]; coeff_vector const& falsep = m_vars[flipvar].m_watch[!flip_is_true]; - coeff_vector::const_iterator it = truep.begin(), end = truep.end(); - for (; it != end; ++it) { - unsigned ci = it->m_constraint_id; + for (auto const& pbc : truep) { + unsigned ci = pbc.m_constraint_id; constraint& c = m_constraints[ci]; int old_slack = c.m_slack; - c.m_slack -= it->m_coeff; + c.m_slack -= pbc.m_coeff; if (c.m_slack < 0 && old_slack >= 0) { // from non-negative to negative: sat -> unsat unsat(ci); } } - it = falsep.begin(), end = falsep.end(); - for (; it != end; ++it) { - unsigned ci = it->m_constraint_id; + for (auto const& pbc : falsep) { + unsigned ci = pbc.m_constraint_id; constraint& c = m_constraints[ci]; int old_slack = c.m_slack; - c.m_slack += it->m_coeff; + c.m_slack += pbc.m_coeff; if (c.m_slack >= 0 && old_slack < 0) { // from negative to non-negative: unsat -> sat sat(ci); } diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 843c70fd8..ef9c0aedf 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2254,7 +2254,7 @@ namespace sat { init(); if (inconsistent()) return; inc_istamp(); - literal l = choose(); + literal l = choose(); if (inconsistent()) return; SASSERT(m_trail_lim.empty()); unsigned num_units = 0; @@ -2266,7 +2266,7 @@ namespace sat { ++num_units; } } - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << " :propagations " << m_stats.m_propagations << ")\n";); if (m_s.inconsistent()) return; @@ -2315,16 +2315,8 @@ namespace sat { void lookahead::add_hyper_binary() { unsigned num_lits = m_s.num_vars() * 2; + unsigned num_bins = 0; -#if 0 - std::cout << "binary trail size: " << m_binary_trail.size() << "\n"; - std::cout << "Are windfalls still on the trail at base level?\n"; -#endif - - unsigned disconnected1 = 0; - unsigned disconnected2 = 0; - -#if 1 typedef std::pair u_pair; hashtable, default_eq > imp; for (unsigned idx = 0; idx < num_lits; ++idx) { @@ -2355,14 +2347,16 @@ namespace sat { literal_vector const& lits = m_binary[idx]; for (unsigned sz = bin_size[idx]; sz > 0; --sz) { literal v = lits[lits.size() - sz]; - if (v != get_parent(v)) continue; - if (m_s.was_eliminated(v.var())) continue; - if (imp.contains(std::make_pair(u.index(), v.index()))) continue; - if (scc.reaches(u, v)) continue; - candidates.push_back(std::make_pair(u, v)); + if (v == get_parent(v) && + !m_s.was_eliminated(v.var()) && + !imp.contains(std::make_pair(u.index(), v.index())) && + !scc.reaches(u, v)) { + candidates.push_back(std::make_pair(u, v)); + } } } - for (unsigned i = 0; i < 5; ++i) { + + for (unsigned count = 0; count < 5; ++count) { scc.init_big(true); unsigned k = 0; union_find_default_ctx ufctx; @@ -2373,7 +2367,7 @@ namespace sat { literal v = candidates[j].second; if (!scc.reaches(u, v)) { if (uf.find(u.index()) != uf.find(v.index())) { - ++disconnected1; + ++num_bins; uf.merge(u.index(), v.index()); uf.merge((~u).index(), (~v).index()); VERIFY(!m_s.was_eliminated(u.var())); @@ -2389,48 +2383,11 @@ namespace sat { std::cout << candidates.size() << " -> " << k << "\n"; if (k == candidates.size()) break; candidates.shrink(k); + if (k == 0) break; } - - std::cout << "candidates: " << candidates.size() << "\n"; - -#endif - -#if 0 - union_find_default_ctx ufctx; - union_find uf(ufctx); - for (unsigned i = 0; i < num_lits; ++i) uf.mk_var(); - for (unsigned idx = 0; idx < num_lits; ++idx) { - literal u = get_parent(to_literal(idx)); - if (null_literal != u) { - for (watched const& w : m_s.m_watches[idx]) { - if (!w.is_binary_clause()) continue; - literal v = get_parent(w.get_literal()); - if (null_literal != v) { - uf.merge(u.index(), v.index()); - } - } - } - } - - for (unsigned i = 0; i < m_binary.size(); ++i) { - literal u = to_literal(i); - if (u == get_parent(u) && !m_s.was_eliminated(u.var())) { - for (literal v : m_binary[i]) { - if (v == get_parent(v) && - !m_s.was_eliminated(v.var()) && - uf.find(u.index()) != uf.find(v.index())) { - ++disconnected2; - uf.merge(u.index(), v.index()); - // m_s.mk_clause(~u, v, true); - } - } - } - } -#endif - IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << disconnected1 << " " << disconnected2 << ")\n";); - //IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << disconnected << ")\n";); - //m_stats.m_bca += disconnected; + IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << num_bins << ")\n";); + m_stats.m_bca += num_bins; } void lookahead::normalize_parents() { diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index e8ae53dca..fde5f1272 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -18,10 +18,11 @@ def_module_params('sat', ('burst_search', UINT, 100, 'number of conflicts before first global simplification'), ('max_conflicts', UINT, UINT_MAX, 'maximum number of conflicts'), ('gc', SYMBOL, 'glue_psm', 'garbage collection strategy: psm, glue, glue_psm, dyn_psm'), - ('gc.initial', UINT, 20000, 'learned clauses garbage collection frequence'), + ('gc.initial', UINT, 20000, 'learned clauses garbage collection frequency'), ('gc.increment', UINT, 500, 'increment to the garbage collection threshold'), ('gc.small_lbd', UINT, 3, 'learned clauses with small LBD are never deleted (only used in dyn_psm)'), ('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'), + ('gc.burst', BOOL, True, 'perform eager garbage collection during initialization'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index 2973245a3..84858ca27 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -51,6 +51,8 @@ namespace sat { struct pframe; + bool reaches_aux(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; } + public: scc(solver & s, params_ref const & p); @@ -66,11 +68,12 @@ namespace sat { \brief create binary implication graph and associated data-structures to check transitivity. */ void init_big(bool learned); + void ensure_big(bool learned) { if (m_left.empty()) init_big(learned); } int get_left(literal l) const { return m_left[l.index()]; } int get_right(literal l) const { return m_right[l.index()]; } literal get_parent(literal l) const { return m_parent[l.index()]; } literal get_root(literal l) const { return m_root[l.index()]; } - bool reaches(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; } + bool reaches(literal u, literal v) const { return reaches_aux(u, v) || reaches_aux(~v, ~u); } }; }; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 283083237..87218b735 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -77,6 +77,7 @@ namespace sat { inline bool simplifier::is_external(bool_var v) const { return s.is_assumption(v) || + (s.is_external(v) && s.is_incremental()) || (s.is_external(v) && s.m_ext && (!m_ext_use_list.get(literal(v, false)).empty() || !m_ext_use_list.get(literal(v, true)).empty())); @@ -154,6 +155,7 @@ namespace sat { else { remove_clause(c); } + } inline void simplifier::unblock_clause(clause & c) { @@ -1354,6 +1356,7 @@ namespace sat { void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); + VERIFY(!s.is_external(l)); if (new_entry == 0 && !s.m_retain_blocked_clauses) new_entry = &(mc.mk(k, l.var())); m_to_remove.push_back(&c); @@ -1365,20 +1368,22 @@ namespace sat { } void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { + SASSERT(!s.is_external(l.var())); prepare_block_clause(c, l, new_entry, model_converter::BLOCK_LIT); - if (!s.m_retain_blocked_clauses) - mc.insert(*new_entry, c); + mc.insert(*new_entry, c); } void block_covered_clause(clause& c, literal l, model_converter::kind k) { + SASSERT(!s.is_external(l.var())); model_converter::entry * new_entry = 0; prepare_block_clause(c, l, new_entry, k); - if (!s.m_retain_blocked_clauses) - mc.insert(*new_entry, m_covered_clause, m_elim_stack); + mc.insert(*new_entry, m_covered_clause, m_elim_stack); } void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) { - if (new_entry == 0 && !s.m_retain_blocked_clauses) + SASSERT(!s.is_external(blocked)); + VERIFY(!s.is_external(blocked)); + if (new_entry == 0) new_entry = &(mc.mk(k, blocked.var())); literal l2 = it->get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); @@ -1394,15 +1399,13 @@ namespace sat { void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { prepare_block_binary(it, l, l, new_entry, model_converter::BLOCK_LIT); - if (!s.m_retain_blocked_clauses) - mc.insert(*new_entry, l, it->get_literal()); + mc.insert(*new_entry, l, it->get_literal()); } void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::kind k) { model_converter::entry * new_entry = 0; prepare_block_binary(it, l, blocked, new_entry, k); - if (!s.m_retain_blocked_clauses) - mc.insert(*new_entry, m_covered_clause, m_elim_stack); + mc.insert(*new_entry, m_covered_clause, m_elim_stack); } void bca() { @@ -1779,6 +1782,7 @@ namespace sat { // eliminate variable ++s.m_stats.m_elim_var_res; + VERIFY(!s.is_external(v)); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); save_clauses(mc_entry, m_pos_cls); save_clauses(mc_entry, m_neg_cls); @@ -1867,7 +1871,10 @@ namespace sat { checkpoint(); if (m_elim_counter < 0) break; - if (try_eliminate(v)) { + if (is_external(v)) { + // skip + } + else if (try_eliminate(v)) { m_num_elim_vars++; } else if (elim_vars_bdd_enabled() && elim_bdd(v)) { diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 0acb78ce1..75703e34b 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -163,6 +163,7 @@ namespace sat { void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists); bool is_external(bool_var v) const; + bool is_external(literal l) const { return is_external(l.var()); } bool was_eliminated(bool_var v) const; lbool value(bool_var v) const; lbool value(literal l) const; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index b3fc95f47..d4a57a9b1 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -904,6 +904,11 @@ namespace sat { propagate(false); if (check_inconsistent()) return l_false; cleanup(); + if (m_config.m_gc_burst) { + // force gc + m_conflicts_since_gc = m_gc_threshold + 1; + gc(); + } if (m_config.m_max_conflicts > 0 && m_config.m_burst_search > 0) { m_restart_threshold = m_config.m_burst_search; lbool r = bounded_search(); @@ -1326,6 +1331,7 @@ namespace sat { void solver::add_assumption(literal lit) { m_assumption_set.insert(lit); m_assumptions.push_back(lit); + VERIFY(is_external(lit.var())); } void solver::pop_assumption() { @@ -1438,14 +1444,12 @@ namespace sat { CASSERT("sat_simplify_bug", check_invariant()); } - if (m_config.m_lookahead_simplify) { lookahead lh(*this); lh.simplify(); lh.collect_statistics(m_aux_stats); } - sort_watch_lits(); CASSERT("sat_simplify_bug", check_invariant()); @@ -1585,6 +1589,8 @@ namespace sat { } for (literal l : m_assumptions) { if (value_at(l, m) != l_true) { + VERIFY(is_external(l.var())); + IF_VERBOSE(0, verbose_stream() << l << " does not model check " << value_at(l, m) << "\n";); TRACE("sat", tout << l << " does not model check\n"; tout << "trail: " << m_trail << "\n"; @@ -1641,7 +1647,7 @@ namespace sat { void solver::gc() { if (m_conflicts_since_gc <= m_gc_threshold) return; - IF_VERBOSE(1, verbose_stream() << "gc\n";); + IF_VERBOSE(10, verbose_stream() << "(sat.gc)\n";); CASSERT("sat_gc_bug", check_invariant()); switch (m_config.m_gc_strategy) { case GC_GLUE: @@ -2099,6 +2105,7 @@ namespace sat { pop_reinit(m_scope_lvl - new_scope_lvl); TRACE("sat_conflict_detail", tout << new_scope_lvl << "\n"; display(tout);); + // unsound: m_asymm_branch.minimize(m_scc, m_lemma); clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.c_ptr(), true); if (lemma) { lemma->set_glue(glue); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 135d9e067..37290940d 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -263,6 +263,7 @@ namespace sat { unsigned num_clauses() const; unsigned num_restarts() const { return m_restarts; } bool is_external(bool_var v) const { return m_external[v] != 0; } + bool is_external(literal l) const { return is_external(l.var()); } void set_external(bool_var v); void set_non_external(bool_var v); bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } @@ -305,6 +306,7 @@ namespace sat { bool canceled() { return !m_rlimit.inc(); } config const& get_config() const { return m_config; } void set_incremental(bool b) { m_config.m_incremental = b; } + bool is_incremental() const { return m_config.m_incremental; } extension* get_extension() const { return m_ext.get(); } void set_extension(extension* e); bool set_root(literal l, literal r); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 1eee15893..9e185e6fa 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -251,15 +251,6 @@ public: } } - virtual void assert_lemma(expr* e) { - dep2asm_t dep2asm; - goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled - for (unsigned i = m_fmls_head ; i < m_fmls.size(); ++i) { - g->assert_expr(m_fmls[i].get()); - } - VERIFY(l_undef != internalize_goal(g, dep2asm, true)); - } - virtual ast_manager& get_manager() const { return m; } virtual void assert_expr_core(expr * t) { m_internalized = false; @@ -526,7 +517,7 @@ private: m_pc = g->pc(); m_mc = g->mc(); TRACE("sat", g->display_with_dependencies(tout);); - m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, false, is_lemma); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, m_solver.get_config().m_incremental, is_lemma); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { std::stringstream strm; diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 68312c6a9..01ea61fd9 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -114,10 +114,6 @@ namespace smt { m_name2assertion.insert(a, t); } - virtual void assert_lemma(expr* t) { - // no-op - } - virtual void push_core() { m_context.push(); } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 90a6cb7c8..29f6a32f1 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -180,12 +180,6 @@ public: m_solver2->assert_expr(t, a); } - virtual void assert_lemma(expr* t) { - m_solver1->assert_lemma(t); - if (m_solver2_initialized) - m_solver2->assert_lemma(t); - } - virtual void push() { switch_inc_mode(); m_solver1->push(); diff --git a/src/solver/solver.h b/src/solver/solver.h index 2b1824cd3..7a51725a2 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -104,12 +104,6 @@ public: virtual void assert_expr_core(expr * t, expr * a) = 0; - /** - \brief Add a lemma to the assertion stack. A lemma is assumed to be a consequence of already - asserted formulas. The solver is free to ignore lemmas. - */ - virtual void assert_lemma(expr * t) {} - /** \brief Create a backtracking point. */ diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 0eb5cef18..b8a8f6704 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -105,10 +105,6 @@ public: } } - virtual void assert_lemma(expr * t) { - m_solver->assert_lemma(t); - } - virtual void push_core() { flush_assertions(); m_solver->push(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 9c522a714..ffb51fe2e 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -68,16 +68,6 @@ public: m_solver->assert_expr(bounds); } - virtual void assert_lemma(expr* t) { - expr_ref tmp(t, m); - expr_ref_vector bounds(m); - proof_ref tmp_proof(m); - m_rewriter(t, tmp, tmp_proof); - m_solver->assert_lemma(tmp); - m_rewriter.flush_side_constraints(bounds); - m_solver->assert_expr(bounds); - } - virtual void push_core() { m_rewriter.push(); m_solver->push(); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 96656ef00..cb5327443 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -62,10 +62,6 @@ public: m_assertions.push_back(t); } - virtual void assert_lemma(expr * t) { - m_solver->assert_lemma(t); - } - virtual void push_core() { flush_assertions(); m_rewriter.push(); From 921423ec8032eeacba091b82f0e3e3b13ae7d616 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Dec 2017 10:43:23 -0800 Subject: [PATCH 0390/1283] fix model conversions for incremental SAT, fix lookahead with ba_solver Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 9 -- src/api/dotnet/Solver.cs | 24 +--- src/api/z3_api.h | 10 -- src/ast/rewriter/pb2bv_rewriter.cpp | 5 +- src/sat/sat_config.cpp | 118 ++++++------------ src/sat/sat_config.h | 14 +-- src/sat/sat_elim_vars.cpp | 3 +- src/sat/sat_local_search.cpp | 38 +++--- src/sat/sat_lookahead.cpp | 78 +++--------- src/sat/sat_params.pyg | 13 +- src/sat/sat_scc.h | 5 +- src/sat/sat_simplifier.cpp | 27 ++-- src/sat/sat_simplifier.h | 1 + src/sat/sat_solver.cpp | 13 +- src/sat/sat_solver.h | 2 + src/sat/sat_solver/inc_sat_solver.cpp | 11 +- src/smt/smt_solver.cpp | 4 - .../portfolio/bounded_int2bv_solver.cpp | 4 - src/tactic/portfolio/enum2bv_solver.cpp | 10 -- src/tactic/portfolio/pb2bv_solver.cpp | 4 - 20 files changed, 119 insertions(+), 274 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 8c2cbf25e..2805e7e2d 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -323,15 +323,6 @@ extern "C" { Z3_CATCH; } - void Z3_API Z3_solver_assert_lemma(Z3_context c, Z3_solver s, Z3_ast a) { - Z3_TRY; - LOG_Z3_solver_assert_lemma(c, s, a); - RESET_ERROR_CODE(); - init_solver(c, s); - CHECK_FORMULA(a,); - to_solver_ref(s)->assert_lemma(to_expr(a)); - Z3_CATCH; - } Z3_ast_vector Z3_API Z3_solver_get_assertions(Z3_context c, Z3_solver s) { Z3_TRY; diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index af5f8e47e..e136516e4 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -239,29 +239,6 @@ namespace Microsoft.Z3 Native.Z3_solver_from_string(Context.nCtx, NativeObject, str); } - /// - /// Assert a lemma (or multiple) into the solver. - /// - public void AssertLemma(params BoolExpr[] constraints) - { - Contract.Requires(constraints != null); - Contract.Requires(Contract.ForAll(constraints, c => c != null)); - - Context.CheckContextMatch(constraints); - foreach (BoolExpr a in constraints) - { - Native.Z3_solver_assert_lemma(Context.nCtx, NativeObject, a.NativeObject); - } - } - - /// - /// Assert a lemma (or multiple) into the solver. - /// - public void AddLemma(IEnumerable constraints) - { - AssertLemma(constraints.ToArray()); - } - /// /// The number of assertions in the solver. /// @@ -325,6 +302,7 @@ namespace Microsoft.Z3 return lboolToStatus(r); } + /// /// Retrieve fixed assignments to the set of variables in the form of consequences. /// Each consequence is an implication of the form diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7f92501ec..b212912b9 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6135,16 +6135,6 @@ extern "C" { */ void Z3_API Z3_solver_assert_and_track(Z3_context c, Z3_solver s, Z3_ast a, Z3_ast p); - /** - \brief add a lemma. A lemma is a assumed to be a consequence of the current assertions. - Adding a lemma should therefore be a logical no-op. Solvers are free to ignore lemmas. - - \pre \c a must be a Boolean expression - - def_API('Z3_solver_assert_lemma', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST))) - */ - void Z3_API Z3_solver_assert_lemma(Z3_context c, Z3_solver s, Z3_ast a); - /** \brief load solver assertions from a file. diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 1e8cd7182..0a0fed292 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -319,9 +319,8 @@ struct pb2bv_rewriter::imp { sums.insert(sum); } } - uint_set::iterator it = sums.begin(), end = sums.end(); - for (; it != end; ++it) { - oc.push_back(*it); + for (unsigned u : sums) { + oc.push_back(u); } std::sort(oc.begin(), oc.end()); DEBUG_CODE( diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 660337071..361e15d91 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -24,24 +24,8 @@ Revision History: namespace sat { - config::config(params_ref const & p): - m_restart_max(0), - m_always_true("always_true"), - m_always_false("always_false"), - m_caching("caching"), - m_random("random"), - m_geometric("geometric"), - m_luby("luby"), - m_dyn_psm("dyn_psm"), - m_psm("psm"), - m_glue("glue"), - m_glue_psm("glue_psm"), - m_psm_glue("psm_glue") { - m_num_threads = 1; - m_lookahead_simplify = false; - m_lookahead_simplify_bca = false; - m_elim_vars = false; - m_incremental = false; + config::config(params_ref const & p) { + m_incremental = false; // ad-hoc parameter updt_params(p); } @@ -50,21 +34,21 @@ namespace sat { m_max_memory = megabytes_to_bytes(p.max_memory()); symbol s = p.restart(); - if (s == m_luby) + if (s == symbol("luby")) m_restart = RS_LUBY; - else if (s == m_geometric) + else if (s == symbol("geometric")) m_restart = RS_GEOMETRIC; else throw sat_param_exception("invalid restart strategy"); s = p.phase(); - if (s == m_always_false) + if (s == symbol("always_false")) m_phase = PS_ALWAYS_FALSE; - else if (s == m_always_true) + else if (s == symbol("always_true")) m_phase = PS_ALWAYS_TRUE; - else if (s == m_caching) + else if (s == symbol("caching")) m_phase = PS_CACHING; - else if (s == m_random) + else if (s == symbol("random")) m_phase = PS_RANDOM; else throw sat_param_exception("invalid phase selection strategy"); @@ -90,24 +74,18 @@ namespace sat { m_local_search_threads = p.local_search_threads(); m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify_bca = p.lookahead_simplify_bca(); - if (p.lookahead_reward() == symbol("heule_schur")) { + if (p.lookahead_reward() == symbol("heule_schur")) m_lookahead_reward = heule_schur_reward; - } - else if (p.lookahead_reward() == symbol("heuleu")) { + else if (p.lookahead_reward() == symbol("heuleu")) m_lookahead_reward = heule_unit_reward; - } - else if (p.lookahead_reward() == symbol("ternary")) { + else if (p.lookahead_reward() == symbol("ternary")) m_lookahead_reward = ternary_reward; - } - else if (p.lookahead_reward() == symbol("unit")) { + else if (p.lookahead_reward() == symbol("unit")) m_lookahead_reward = unit_literal_reward; - } - else if (p.lookahead_reward() == symbol("march_cu")) { + else if (p.lookahead_reward() == symbol("march_cu")) m_lookahead_reward = march_cu_reward; - } - else { + else throw sat_param_exception("invalid reward type supplied: accepted heuristics are 'ternary', 'heuleu', 'unit' or 'heule_schur'"); - } if (p.lookahead_cube_cutoff() == symbol("depth")) { m_lookahead_cube_cutoff = depth_cutoff; @@ -142,29 +120,23 @@ namespace sat { // -------------------------------- s = p.gc(); - if (s == m_dyn_psm) { - m_gc_strategy = GC_DYN_PSM; - m_gc_initial = p.gc_initial(); - m_gc_increment = p.gc_increment(); - m_gc_small_lbd = p.gc_small_lbd(); - m_gc_k = p.gc_k(); - if (m_gc_k > 255) - m_gc_k = 255; - } - else { - if (s == m_glue_psm) - m_gc_strategy = GC_GLUE_PSM; - else if (s == m_glue) - m_gc_strategy = GC_GLUE; - else if (s == m_psm) - m_gc_strategy = GC_PSM; - else if (s == m_psm_glue) - m_gc_strategy = GC_PSM_GLUE; - else - throw sat_param_exception("invalid gc strategy"); - m_gc_initial = p.gc_initial(); - m_gc_increment = p.gc_increment(); - } + if (s == symbol("dyn_psm")) + m_gc_strategy = GC_DYN_PSM; + else if (s == symbol("glue_psm")) + m_gc_strategy = GC_GLUE_PSM; + else if (s == symbol("glue")) + m_gc_strategy = GC_GLUE; + else if (s == symbol("psm")) + m_gc_strategy = GC_PSM; + else if (s == symbol("psm_glue")) + m_gc_strategy = GC_PSM_GLUE; + else + throw sat_param_exception("invalid gc strategy"); + m_gc_initial = p.gc_initial(); + m_gc_increment = p.gc_increment(); + m_gc_small_lbd = p.gc_small_lbd(); + m_gc_k = std::min(255u, p.gc_k()); + m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); m_core_minimize_partial = p.core_minimize_partial(); @@ -176,18 +148,15 @@ namespace sat { // Parameters used in Liang, Ganesh, Poupart, Czarnecki AAAI 2016. m_branching_heuristic = BH_VSIDS; - if (p.branching_heuristic() == symbol("vsids")) { + if (p.branching_heuristic() == symbol("vsids")) m_branching_heuristic = BH_VSIDS; - } - else if (p.branching_heuristic() == symbol("chb")) { + else if (p.branching_heuristic() == symbol("chb")) m_branching_heuristic = BH_CHB; - } - else if (p.branching_heuristic() == symbol("lrb")) { + else if (p.branching_heuristic() == symbol("lrb")) m_branching_heuristic = BH_LRB; - } - else { + else throw sat_param_exception("invalid branching heuristic: accepted heuristics are 'vsids', 'lrb' or 'chb'"); - } + m_anti_exploration = p.branching_anti_exploration(); m_step_size_init = 0.40; m_step_size_dec = 0.000001; @@ -199,21 +168,16 @@ namespace sat { // PB parameters s = p.pb_solver(); - if (s == symbol("circuit")) { + if (s == symbol("circuit")) m_pb_solver = PB_CIRCUIT; - } - else if (s == symbol("sorting")) { + else if (s == symbol("sorting")) m_pb_solver = PB_SORTING; - } - else if (s == symbol("totalizer")) { + else if (s == symbol("totalizer")) m_pb_solver = PB_TOTALIZER; - } - else if (s == symbol("solver")) { + else if (s == symbol("solver")) m_pb_solver = PB_SOLVER; - } - else { + else throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); - } sat_simplifier_params sp(_p); m_elim_vars = sp.elim_vars(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index f66c0dbdf..da225c26b 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -114,6 +114,7 @@ namespace sat { unsigned m_gc_increment; unsigned m_gc_small_lbd; unsigned m_gc_k; + bool m_gc_burst; bool m_minimize_lemmas; bool m_dyn_sub_res; @@ -123,20 +124,7 @@ namespace sat { symbol m_drat_file; bool m_drat_check_unsat; bool m_drat_check_sat; - - symbol m_always_true; - symbol m_always_false; - symbol m_caching; - symbol m_random; - symbol m_geometric; - symbol m_luby; - symbol m_dyn_psm; - symbol m_psm; - symbol m_glue; - symbol m_glue_psm; - symbol m_psm_glue; - pb_solver m_pb_solver; // branching heuristic settings. diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 5dd3ed1f7..7e803eaa5 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -87,6 +87,7 @@ namespace sat{ simp.m_neg_cls.reset(); simp.collect_clauses(pos_l, simp.m_pos_cls, false); simp.collect_clauses(neg_l, simp.m_neg_cls, false); + VERIFY(!s.is_external(v)); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); simp.save_clauses(mc_entry, simp.m_pos_cls); simp.save_clauses(mc_entry, simp.m_neg_cls); @@ -99,7 +100,7 @@ namespace sat{ pos_occs.reset(); neg_occs.reset(); literal_vector lits; - add_clauses(b, lits); + add_clauses(b, lits); return true; } diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 3a9e48182..726fda7f4 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -301,12 +301,10 @@ namespace sat { for (unsigned l_idx = 0; l_idx < sz; ++l_idx) { literal l1 = ~to_literal(l_idx); watch_list const & wlist = s.m_watches[l_idx]; - watch_list::const_iterator it = wlist.begin(); - watch_list::const_iterator end = wlist.end(); - for (; it != end; ++it) { - if (!it->is_binary_unblocked_clause()) + for (watched const& w : wlist) { + if (!w.is_binary_unblocked_clause()) continue; - literal l2 = it->get_literal(); + literal l2 = w.get_literal(); if (l1.index() > l2.index()) continue; literal ls[2] = { l1, l2 }; @@ -316,11 +314,8 @@ namespace sat { } // copy clauses - clause_vector::const_iterator it = s.m_clauses.begin(); - clause_vector::const_iterator end = s.m_clauses.end(); - for (; it != end; ++it) { - clause& c = *(*it); - add_clause(c.size(), c.begin()); + for (clause* c : s.m_clauses) { + add_clause(c->size(), c->begin()); } m_num_non_binary_clauses = s.m_clauses.size(); @@ -568,12 +563,11 @@ namespace sat { best_var = v = l.var(); bool tt = cur_solution(v); coeff_vector const& falsep = m_vars[v].m_watch[!tt]; - coeff_vector::const_iterator it = falsep.begin(), end = falsep.end(); - for (; it != end; ++it) { - int slack = constraint_slack(it->m_constraint_id); + for (pbcoeff const& pbc : falsep) { + int slack = constraint_slack(pbc.m_constraint_id); if (slack < 0) ++best_bsb; - else if (slack < static_cast(it->m_coeff)) + else if (slack < static_cast(pbc.m_coeff)) best_bsb += num_unsat; } ++cit; @@ -583,7 +577,7 @@ namespace sat { v = l.var(); unsigned bsb = 0; coeff_vector const& falsep = m_vars[v].m_watch[!cur_solution(v)]; - coeff_vector::const_iterator it = falsep.begin(), end = falsep.end(); + auto it = falsep.begin(), end = falsep.end(); for (; it != end; ++it) { int slack = constraint_slack(it->m_constraint_id); if (slack < 0) { @@ -637,22 +631,20 @@ namespace sat { coeff_vector const& truep = m_vars[flipvar].m_watch[flip_is_true]; coeff_vector const& falsep = m_vars[flipvar].m_watch[!flip_is_true]; - coeff_vector::const_iterator it = truep.begin(), end = truep.end(); - for (; it != end; ++it) { - unsigned ci = it->m_constraint_id; + for (auto const& pbc : truep) { + unsigned ci = pbc.m_constraint_id; constraint& c = m_constraints[ci]; int old_slack = c.m_slack; - c.m_slack -= it->m_coeff; + c.m_slack -= pbc.m_coeff; if (c.m_slack < 0 && old_slack >= 0) { // from non-negative to negative: sat -> unsat unsat(ci); } } - it = falsep.begin(), end = falsep.end(); - for (; it != end; ++it) { - unsigned ci = it->m_constraint_id; + for (auto const& pbc : falsep) { + unsigned ci = pbc.m_constraint_id; constraint& c = m_constraints[ci]; int old_slack = c.m_slack; - c.m_slack += it->m_coeff; + c.m_slack += pbc.m_coeff; if (c.m_slack >= 0 && old_slack < 0) { // from negative to non-negative: unsat -> sat sat(ci); } diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index ec1bf23f2..f58339922 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -683,7 +683,7 @@ namespace sat { // NB. u.index() > l.index() iff u.index() > (~l).index(). // since indices for the same boolean variables occupy // two adjacent numbers. - if (u.index() > l.index() && is_stamped(u)) { + if (u.index() > l.index() && is_stamped(u) && ~l != u) { add_arc(~l, ~u); add_arc( u, l); } @@ -692,7 +692,8 @@ namespace sat { lits.reset(); if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { for (literal u : lits) { - if (u.index() > l.index() && is_stamped(u)) { + // u is positive in lits, l is negative: + if (~l != u && u.index() > l.index() && is_stamped(u)) { add_arc(~l, ~u); add_arc( u, l); } @@ -2291,7 +2292,7 @@ namespace sat { init(); if (inconsistent()) return; inc_istamp(); - literal l = choose(); + literal l = choose(); if (inconsistent()) return; SASSERT(m_trail_lim.empty()); unsigned num_units = 0; @@ -2303,7 +2304,7 @@ namespace sat { ++num_units; } } - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_units << " :propagations " << m_stats.m_propagations << ")\n";); if (m_s.inconsistent()) return; @@ -2352,16 +2353,8 @@ namespace sat { void lookahead::add_hyper_binary() { unsigned num_lits = m_s.num_vars() * 2; + unsigned num_bins = 0; -#if 0 - std::cout << "binary trail size: " << m_binary_trail.size() << "\n"; - std::cout << "Are windfalls still on the trail at base level?\n"; -#endif - - unsigned disconnected1 = 0; - unsigned disconnected2 = 0; - -#if 1 typedef std::pair u_pair; hashtable, default_eq > imp; for (unsigned idx = 0; idx < num_lits; ++idx) { @@ -2392,14 +2385,16 @@ namespace sat { literal_vector const& lits = m_binary[idx]; for (unsigned sz = bin_size[idx]; sz > 0; --sz) { literal v = lits[lits.size() - sz]; - if (v != get_parent(v)) continue; - if (m_s.was_eliminated(v.var())) continue; - if (imp.contains(std::make_pair(u.index(), v.index()))) continue; - if (scc.reaches(u, v)) continue; - candidates.push_back(std::make_pair(u, v)); + if (v == get_parent(v) && + !m_s.was_eliminated(v.var()) && + !imp.contains(std::make_pair(u.index(), v.index())) && + !scc.reaches(u, v)) { + candidates.push_back(std::make_pair(u, v)); + } } } - for (unsigned i = 0; i < 5; ++i) { + + for (unsigned count = 0; count < 5; ++count) { scc.init_big(true); unsigned k = 0; union_find_default_ctx ufctx; @@ -2410,7 +2405,7 @@ namespace sat { literal v = candidates[j].second; if (!scc.reaches(u, v)) { if (uf.find(u.index()) != uf.find(v.index())) { - ++disconnected1; + ++num_bins; uf.merge(u.index(), v.index()); uf.merge((~u).index(), (~v).index()); VERIFY(!m_s.was_eliminated(u.var())); @@ -2426,48 +2421,11 @@ namespace sat { std::cout << candidates.size() << " -> " << k << "\n"; if (k == candidates.size()) break; candidates.shrink(k); + if (k == 0) break; } - - std::cout << "candidates: " << candidates.size() << "\n"; - -#endif - -#if 0 - union_find_default_ctx ufctx; - union_find uf(ufctx); - for (unsigned i = 0; i < num_lits; ++i) uf.mk_var(); - for (unsigned idx = 0; idx < num_lits; ++idx) { - literal u = get_parent(to_literal(idx)); - if (null_literal != u) { - for (watched const& w : m_s.m_watches[idx]) { - if (!w.is_binary_clause()) continue; - literal v = get_parent(w.get_literal()); - if (null_literal != v) { - uf.merge(u.index(), v.index()); - } - } - } - } - - for (unsigned i = 0; i < m_binary.size(); ++i) { - literal u = to_literal(i); - if (u == get_parent(u) && !m_s.was_eliminated(u.var())) { - for (literal v : m_binary[i]) { - if (v == get_parent(v) && - !m_s.was_eliminated(v.var()) && - uf.find(u.index()) != uf.find(v.index())) { - ++disconnected2; - uf.merge(u.index(), v.index()); - // m_s.mk_clause(~u, v, true); - } - } - } - } -#endif - IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << disconnected1 << " " << disconnected2 << ")\n";); - //IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << disconnected << ")\n";); - //m_stats.m_bca += disconnected; + IF_VERBOSE(10, verbose_stream() << "(sat-lookahead :bca " << num_bins << ")\n";); + m_stats.m_bca += num_bins; } void lookahead::normalize_parents() { diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 4432c0b16..fde5f1272 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -18,10 +18,11 @@ def_module_params('sat', ('burst_search', UINT, 100, 'number of conflicts before first global simplification'), ('max_conflicts', UINT, UINT_MAX, 'maximum number of conflicts'), ('gc', SYMBOL, 'glue_psm', 'garbage collection strategy: psm, glue, glue_psm, dyn_psm'), - ('gc.initial', UINT, 20000, 'learned clauses garbage collection frequence'), + ('gc.initial', UINT, 20000, 'learned clauses garbage collection frequency'), ('gc.increment', UINT, 500, 'increment to the garbage collection threshold'), ('gc.small_lbd', UINT, 3, 'learned clauses with small LBD are never deleted (only used in dyn_psm)'), ('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'), + ('gc.burst', BOOL, True, 'perform eager garbage collection during initialization'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), @@ -37,14 +38,8 @@ def_module_params('sat', ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), - ('lookahead.cube.cutoff', SYMBOL, 'adaptive_freevars', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), - ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat'), - ('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'), - ('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is freevars'), - ('lookahead.cube.psat.var_exp', DOUBLE, 1, 'free variable exponent for PSAT cutoff'), - ('lookahead.cube.psat.clause_base', DOUBLE, 2, 'clause base for PSAT cutoff'), - ('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff. Used when lookahead.cube.cutoff is psat'), - ('lookahead_search', BOOL, False, 'use lookahead solver'), + ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'), + ('lookahead.cube.cutoff', UINT, 10, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead_simplify.bca', BOOL, False, 'add learned binary clauses as part of lookahead simplification'), diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index 2973245a3..84858ca27 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -51,6 +51,8 @@ namespace sat { struct pframe; + bool reaches_aux(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; } + public: scc(solver & s, params_ref const & p); @@ -66,11 +68,12 @@ namespace sat { \brief create binary implication graph and associated data-structures to check transitivity. */ void init_big(bool learned); + void ensure_big(bool learned) { if (m_left.empty()) init_big(learned); } int get_left(literal l) const { return m_left[l.index()]; } int get_right(literal l) const { return m_right[l.index()]; } literal get_parent(literal l) const { return m_parent[l.index()]; } literal get_root(literal l) const { return m_root[l.index()]; } - bool reaches(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; } + bool reaches(literal u, literal v) const { return reaches_aux(u, v) || reaches_aux(~v, ~u); } }; }; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 283083237..87218b735 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -77,6 +77,7 @@ namespace sat { inline bool simplifier::is_external(bool_var v) const { return s.is_assumption(v) || + (s.is_external(v) && s.is_incremental()) || (s.is_external(v) && s.m_ext && (!m_ext_use_list.get(literal(v, false)).empty() || !m_ext_use_list.get(literal(v, true)).empty())); @@ -154,6 +155,7 @@ namespace sat { else { remove_clause(c); } + } inline void simplifier::unblock_clause(clause & c) { @@ -1354,6 +1356,7 @@ namespace sat { void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); + VERIFY(!s.is_external(l)); if (new_entry == 0 && !s.m_retain_blocked_clauses) new_entry = &(mc.mk(k, l.var())); m_to_remove.push_back(&c); @@ -1365,20 +1368,22 @@ namespace sat { } void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { + SASSERT(!s.is_external(l.var())); prepare_block_clause(c, l, new_entry, model_converter::BLOCK_LIT); - if (!s.m_retain_blocked_clauses) - mc.insert(*new_entry, c); + mc.insert(*new_entry, c); } void block_covered_clause(clause& c, literal l, model_converter::kind k) { + SASSERT(!s.is_external(l.var())); model_converter::entry * new_entry = 0; prepare_block_clause(c, l, new_entry, k); - if (!s.m_retain_blocked_clauses) - mc.insert(*new_entry, m_covered_clause, m_elim_stack); + mc.insert(*new_entry, m_covered_clause, m_elim_stack); } void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) { - if (new_entry == 0 && !s.m_retain_blocked_clauses) + SASSERT(!s.is_external(blocked)); + VERIFY(!s.is_external(blocked)); + if (new_entry == 0) new_entry = &(mc.mk(k, blocked.var())); literal l2 = it->get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); @@ -1394,15 +1399,13 @@ namespace sat { void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { prepare_block_binary(it, l, l, new_entry, model_converter::BLOCK_LIT); - if (!s.m_retain_blocked_clauses) - mc.insert(*new_entry, l, it->get_literal()); + mc.insert(*new_entry, l, it->get_literal()); } void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::kind k) { model_converter::entry * new_entry = 0; prepare_block_binary(it, l, blocked, new_entry, k); - if (!s.m_retain_blocked_clauses) - mc.insert(*new_entry, m_covered_clause, m_elim_stack); + mc.insert(*new_entry, m_covered_clause, m_elim_stack); } void bca() { @@ -1779,6 +1782,7 @@ namespace sat { // eliminate variable ++s.m_stats.m_elim_var_res; + VERIFY(!s.is_external(v)); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); save_clauses(mc_entry, m_pos_cls); save_clauses(mc_entry, m_neg_cls); @@ -1867,7 +1871,10 @@ namespace sat { checkpoint(); if (m_elim_counter < 0) break; - if (try_eliminate(v)) { + if (is_external(v)) { + // skip + } + else if (try_eliminate(v)) { m_num_elim_vars++; } else if (elim_vars_bdd_enabled() && elim_bdd(v)) { diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 0acb78ce1..75703e34b 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -163,6 +163,7 @@ namespace sat { void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists); bool is_external(bool_var v) const; + bool is_external(literal l) const { return is_external(l.var()); } bool was_eliminated(bool_var v) const; lbool value(bool_var v) const; lbool value(literal l) const; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index b3fc95f47..d4a57a9b1 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -904,6 +904,11 @@ namespace sat { propagate(false); if (check_inconsistent()) return l_false; cleanup(); + if (m_config.m_gc_burst) { + // force gc + m_conflicts_since_gc = m_gc_threshold + 1; + gc(); + } if (m_config.m_max_conflicts > 0 && m_config.m_burst_search > 0) { m_restart_threshold = m_config.m_burst_search; lbool r = bounded_search(); @@ -1326,6 +1331,7 @@ namespace sat { void solver::add_assumption(literal lit) { m_assumption_set.insert(lit); m_assumptions.push_back(lit); + VERIFY(is_external(lit.var())); } void solver::pop_assumption() { @@ -1438,14 +1444,12 @@ namespace sat { CASSERT("sat_simplify_bug", check_invariant()); } - if (m_config.m_lookahead_simplify) { lookahead lh(*this); lh.simplify(); lh.collect_statistics(m_aux_stats); } - sort_watch_lits(); CASSERT("sat_simplify_bug", check_invariant()); @@ -1585,6 +1589,8 @@ namespace sat { } for (literal l : m_assumptions) { if (value_at(l, m) != l_true) { + VERIFY(is_external(l.var())); + IF_VERBOSE(0, verbose_stream() << l << " does not model check " << value_at(l, m) << "\n";); TRACE("sat", tout << l << " does not model check\n"; tout << "trail: " << m_trail << "\n"; @@ -1641,7 +1647,7 @@ namespace sat { void solver::gc() { if (m_conflicts_since_gc <= m_gc_threshold) return; - IF_VERBOSE(1, verbose_stream() << "gc\n";); + IF_VERBOSE(10, verbose_stream() << "(sat.gc)\n";); CASSERT("sat_gc_bug", check_invariant()); switch (m_config.m_gc_strategy) { case GC_GLUE: @@ -2099,6 +2105,7 @@ namespace sat { pop_reinit(m_scope_lvl - new_scope_lvl); TRACE("sat_conflict_detail", tout << new_scope_lvl << "\n"; display(tout);); + // unsound: m_asymm_branch.minimize(m_scc, m_lemma); clause * lemma = mk_clause_core(m_lemma.size(), m_lemma.c_ptr(), true); if (lemma) { lemma->set_glue(glue); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 135d9e067..37290940d 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -263,6 +263,7 @@ namespace sat { unsigned num_clauses() const; unsigned num_restarts() const { return m_restarts; } bool is_external(bool_var v) const { return m_external[v] != 0; } + bool is_external(literal l) const { return is_external(l.var()); } void set_external(bool_var v); void set_non_external(bool_var v); bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } @@ -305,6 +306,7 @@ namespace sat { bool canceled() { return !m_rlimit.inc(); } config const& get_config() const { return m_config; } void set_incremental(bool b) { m_config.m_incremental = b; } + bool is_incremental() const { return m_config.m_incremental; } extension* get_extension() const { return m_ext.get(); } void set_extension(extension* e); bool set_root(literal l, literal r); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 1eee15893..9e185e6fa 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -251,15 +251,6 @@ public: } } - virtual void assert_lemma(expr* e) { - dep2asm_t dep2asm; - goal_ref g = alloc(goal, m, true, false); // models, maybe cores are enabled - for (unsigned i = m_fmls_head ; i < m_fmls.size(); ++i) { - g->assert_expr(m_fmls[i].get()); - } - VERIFY(l_undef != internalize_goal(g, dep2asm, true)); - } - virtual ast_manager& get_manager() const { return m; } virtual void assert_expr_core(expr * t) { m_internalized = false; @@ -526,7 +517,7 @@ private: m_pc = g->pc(); m_mc = g->mc(); TRACE("sat", g->display_with_dependencies(tout);); - m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, false, is_lemma); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, m_solver.get_config().m_incremental, is_lemma); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { std::stringstream strm; diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 68312c6a9..01ea61fd9 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -114,10 +114,6 @@ namespace smt { m_name2assertion.insert(a, t); } - virtual void assert_lemma(expr* t) { - // no-op - } - virtual void push_core() { m_context.push(); } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 0eb5cef18..b8a8f6704 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -105,10 +105,6 @@ public: } } - virtual void assert_lemma(expr * t) { - m_solver->assert_lemma(t); - } - virtual void push_core() { flush_assertions(); m_solver->push(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 9c522a714..ffb51fe2e 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -68,16 +68,6 @@ public: m_solver->assert_expr(bounds); } - virtual void assert_lemma(expr* t) { - expr_ref tmp(t, m); - expr_ref_vector bounds(m); - proof_ref tmp_proof(m); - m_rewriter(t, tmp, tmp_proof); - m_solver->assert_lemma(tmp); - m_rewriter.flush_side_constraints(bounds); - m_solver->assert_expr(bounds); - } - virtual void push_core() { m_rewriter.push(); m_solver->push(); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 96656ef00..cb5327443 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -62,10 +62,6 @@ public: m_assertions.push_back(t); } - virtual void assert_lemma(expr * t) { - m_solver->assert_lemma(t); - } - virtual void push_core() { flush_assertions(); m_rewriter.push(); From 159df60336d22b3eb1c4fab97c2363ab2295f38a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Dec 2017 13:22:31 -0800 Subject: [PATCH 0391/1283] local changes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index dbb5ea123..1eb84d6f4 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -134,7 +134,7 @@ namespace sat { s.propagate(false); if (s.m_inconsistent) break; - std::cout << m_elim_literals - elim << "\n"; + // std::cout << m_elim_literals - elim << "\n"; if (m_elim_literals == elim) break; } From deda8f46f87d7cbdfb35d4695877433087f0ee3f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Dec 2017 13:25:36 -0800 Subject: [PATCH 0392/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 87218b735..558bfb11e 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1357,7 +1357,7 @@ namespace sat { void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); VERIFY(!s.is_external(l)); - if (new_entry == 0 && !s.m_retain_blocked_clauses) + if (new_entry == 0) new_entry = &(mc.mk(k, l.var())); m_to_remove.push_back(&c); for (literal lit : c) { From dbe7828f1de48167fff14b19a904a6dc2ca5d6e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Dec 2017 14:33:23 -0800 Subject: [PATCH 0393/1283] inherit incremental override on the solver state Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 14 -------------- src/sat/sat_simplifier.cpp | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 18 +++++++++++++++--- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 1eb84d6f4..3a3184141 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -134,7 +134,6 @@ namespace sat { s.propagate(false); if (s.m_inconsistent) break; - // std::cout << m_elim_literals - elim << "\n"; if (m_elim_literals == elim) break; } @@ -232,19 +231,6 @@ namespace sat { } } if (!m_to_delete.empty()) { -#if 0 - std::cout << "delete " << m_to_delete << "\n"; - - std::cout << "pos\n"; - for (literal l : m_pos) { - std::cout << l << ": " << scc.get_left(l) << " " << scc.get_right(l) << "\n"; - } - std::cout << "neg\n"; - for (literal l : m_neg) { - std::cout << l << ": " << scc.get_left(l) << " " << scc.get_right(l) << "\n"; - } - std::cout << "\n"; -#endif unsigned j = 0; for (unsigned i = 0; i < c.size(); ++i) { if (!m_to_delete.contains(c[i])) { diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 558bfb11e..674ee9121 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1782,7 +1782,7 @@ namespace sat { // eliminate variable ++s.m_stats.m_elim_var_res; - VERIFY(!s.is_external(v)); + VERIFY(!is_external(v)); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); save_clauses(mc_entry, m_pos_cls); save_clauses(mc_entry, m_neg_cls); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 9e185e6fa..2af846f42 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -36,6 +36,7 @@ Notes: #include "ast/ast_util.h" #include "tactic/core/propagate_values_tactic.h" #include "sat/sat_params.hpp" +#include "sat/sat_simplifier_params.hpp" // incremental SAT solver. class inc_sat_solver : public solver { @@ -88,7 +89,17 @@ public: m_internalized_fmls(m) { updt_params(p); init_preprocess(); - m_solver.set_incremental(incremental_mode); + m_solver.set_incremental(incremental_mode && !override_incremental()); + } + + bool override_incremental() const { + sat_simplifier_params p(m_params); + std::cout << "override: " << p.override_incremental() << "\n"; + return p.override_incremental(); + } + + bool is_incremental() const { + return m_solver.get_config().m_incremental; } virtual ~inc_sat_solver() {} @@ -99,7 +110,7 @@ public: } ast_translation tr(m, dst_m); m_solver.pop_to_base_level(); - inc_sat_solver* result = alloc(inc_sat_solver, dst_m, p, m_solver.get_config().m_incremental); + inc_sat_solver* result = alloc(inc_sat_solver, dst_m, p, is_incremental()); result->m_solver.copy(m_solver); result->m_fmls_head = m_fmls_head; for (expr* f : m_fmls) result->m_fmls.push_back(tr(f)); @@ -272,6 +283,7 @@ public: m_params.set_bool("pb_totalizer", m_solver.get_config().m_pb_solver == sat::PB_TOTALIZER); m_params.set_bool("xor_solver", p1.xor_solver()); m_solver.updt_params(m_params); + m_solver.set_incremental(is_incremental() && !override_incremental()); } virtual void collect_statistics(statistics & st) const { @@ -517,7 +529,7 @@ private: m_pc = g->pc(); m_mc = g->mc(); TRACE("sat", g->display_with_dependencies(tout);); - m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, m_solver.get_config().m_incremental, is_lemma); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, is_incremental(), is_lemma); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { std::stringstream strm; From c92e6ac658faefcf906645ffb11ca080cb1daf84 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Tue, 12 Dec 2017 14:35:24 -0800 Subject: [PATCH 0394/1283] merge Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_params.pyg | 9 +++++++-- src/sat/sat_simplifier.cpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index a72a896cc..0632d3076 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2420,7 +2420,7 @@ namespace sat { } } } - std::cout << candidates.size() << " -> " << k << "\n"; + //std::cout << candidates.size() << " -> " << k << "\n"; if (k == candidates.size()) break; candidates.shrink(k); if (k == 0) break; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index fde5f1272..3fc5194f0 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -38,8 +38,13 @@ def_module_params('sat', ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), - ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead_cube is true'), - ('lookahead.cube.cutoff', UINT, 10, 'cut-off depth to create cubes. Only enabled when non-zero. Used when lookahead_cube is true.'), + ('lookahead.cube.cutoff', SYMBOL, 'adaptive_freevars', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), + ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat'), + ('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'), + ('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is freevars'), + ('lookahead.cube.psat.var_exp', DOUBLE, 1, 'free variable exponent for PSAT cutoff'), + ('lookahead.cube.psat.clause_base', DOUBLE, 2, 'clause base for PSAT cutoff'), + ('lookahead.cube.psat.trigger', DOUBLE, 5, 'trigger value to create lookahead cubes for PSAT cutoff. Used when lookahead.cube.cutoff is psat'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead_simplify.bca', BOOL, False, 'add learned binary clauses as part of lookahead simplification'), diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 87218b735..558bfb11e 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1357,7 +1357,7 @@ namespace sat { void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); VERIFY(!s.is_external(l)); - if (new_entry == 0 && !s.m_retain_blocked_clauses) + if (new_entry == 0) new_entry = &(mc.mk(k, l.var())); m_to_remove.push_back(&c); for (literal lit : c) { From bffa0facee3ca9e532b9c1bd1aa10383e88b14e2 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Wed, 13 Dec 2017 10:09:44 -0800 Subject: [PATCH 0395/1283] pre-merge commit Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_elim_vars.cpp | 2 +- src/sat/sat_simplifier.cpp | 6 +++--- src/sat/sat_solver.cpp | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 7e803eaa5..584433cc1 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -87,7 +87,7 @@ namespace sat{ simp.m_neg_cls.reset(); simp.collect_clauses(pos_l, simp.m_pos_cls, false); simp.collect_clauses(neg_l, simp.m_neg_cls, false); - VERIFY(!s.is_external(v)); + //VERIFY(!s.is_external(v)); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); simp.save_clauses(mc_entry, simp.m_pos_cls); simp.save_clauses(mc_entry, simp.m_neg_cls); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 674ee9121..6ceb53265 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1356,7 +1356,7 @@ namespace sat { void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); - VERIFY(!s.is_external(l)); + //VERIFY(!s.is_external(l)); if (new_entry == 0) new_entry = &(mc.mk(k, l.var())); m_to_remove.push_back(&c); @@ -1382,7 +1382,7 @@ namespace sat { void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) { SASSERT(!s.is_external(blocked)); - VERIFY(!s.is_external(blocked)); + //VERIFY(!s.is_external(blocked)); if (new_entry == 0) new_entry = &(mc.mk(k, blocked.var())); literal l2 = it->get_literal(); @@ -1782,7 +1782,7 @@ namespace sat { // eliminate variable ++s.m_stats.m_elim_var_res; - VERIFY(!is_external(v)); + //VERIFY(!is_external(v)); model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); save_clauses(mc_entry, m_pos_cls); save_clauses(mc_entry, m_neg_cls); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d4a57a9b1..03f56a497 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1331,7 +1331,7 @@ namespace sat { void solver::add_assumption(literal lit) { m_assumption_set.insert(lit); m_assumptions.push_back(lit); - VERIFY(is_external(lit.var())); + set_external(lit.var()); } void solver::pop_assumption() { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 2af846f42..6802b7373 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -94,7 +94,7 @@ public: bool override_incremental() const { sat_simplifier_params p(m_params); - std::cout << "override: " << p.override_incremental() << "\n"; + //std::cout << "override: " << p.override_incremental() << "\n"; return p.override_incremental(); } From aeabdb4aaec7672f676e7d46f49c12a5315bd06e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Dec 2017 14:06:35 -0800 Subject: [PATCH 0396/1283] add checks for flipping externals / assumptions in model converter, fix scc converter bug Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 2 +- src/sat/sat_model_converter.cpp | 26 ++++++++++++++++++++++++-- src/sat/sat_model_converter.h | 2 ++ src/sat/sat_solver.cpp | 6 +++--- src/sat/sat_solver.h | 2 +- 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index d0166b64e..6b8d4cba7 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -182,7 +182,7 @@ namespace sat { literal l(v, false); literal r = roots[v]; SASSERT(v != r.var()); - if (m_solver.is_external(v) && !m_solver.set_root(l, r)) { + if (m_solver.is_external(v) || !m_solver.set_root(l, r)) { // cannot really eliminate v, since we have to notify extension of future assignments m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(l, ~r, false); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index d46063455..05c89fba7 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -39,6 +39,22 @@ namespace sat { return *this; } + bool model_converter::legal_to_flip(bool_var v) const { + // std::cout << "check " << v << " " << m_solver << "\n"; + if (m_solver && m_solver->is_assumption(v)) { + std::cout << "flipping assumption v" << v << "\n"; + UNREACHABLE(); + throw solver_exception("flipping assumption"); + } + if (m_solver && m_solver->is_external(v)) { + std::cout << "flipping external v" << v << "\n"; + UNREACHABLE(); + throw solver_exception("flipping external"); + } + return !m_solver || !m_solver->is_assumption(v); + } + + void model_converter::process_stack(model & m, literal_vector const& c, elim_stackv const& stack) const { SASSERT(!stack.empty()); unsigned sz = stack.size(); @@ -50,6 +66,7 @@ namespace sat { sat = value_at(c[j], m) == l_true; } if (!sat) { + VERIFY(legal_to_flip(lit.var())); m[lit.var()] = lit.sign() ? l_false : l_true; } } @@ -59,7 +76,7 @@ namespace sat { vector::const_iterator begin = m_entries.begin(); vector::const_iterator it = m_entries.end(); bool first = true; - //VERIFY(!m_solver || m_solver->check_clauses(m)); + //SASSERT(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; SASSERT(it->get_kind() != ELIM_VAR || m[it->var()] == l_undef); @@ -69,11 +86,13 @@ namespace sat { bool var_sign = false; unsigned index = 0; literal_vector clause; + VERIFY(legal_to_flip(it->var())); for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause elim_stack* st = it->m_elim_stack[index]; - if (!sat) { + if (!sat) { + VERIFY(legal_to_flip(it->var())); m[it->var()] = var_sign ? l_false : l_true; } if (st) { @@ -101,6 +120,7 @@ namespace sat { if (value_at(l, m) == l_true) sat = true; else if (!sat && v != it->var() && m[v] == l_undef) { + VERIFY(legal_to_flip(v)); // clause can be satisfied by assigning v. m[v] = sign ? l_false : l_true; // if (first) std::cout << "set: " << l << "\n"; @@ -170,6 +190,7 @@ namespace sat { entry & e = m_entries.back(); SASSERT(e.var() == v); SASSERT(e.get_kind() == k); + VERIFY(legal_to_flip(v)); return e; } @@ -213,6 +234,7 @@ namespace sat { for (literal l : c) e.m_clauses.push_back(l); e.m_clauses.push_back(null_literal); e.m_elim_stack.push_back(elims.empty() ? nullptr : alloc(elim_stack, elims)); + for (auto const& s : elims) VERIFY(legal_to_flip(s.second.var())); TRACE("sat_mc_bug", tout << "adding: " << c << "\n";); } diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index 8f8b1a41b..28f23c063 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -92,6 +92,8 @@ namespace sat { std::ostream& display(std::ostream & out, entry const& entry) const; + bool legal_to_flip(bool_var v) const; + public: model_converter(); ~model_converter(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0e51c3332..db6f3d356 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -61,7 +61,7 @@ namespace sat { m_num_checkpoints = 0; m_simplifications = 0; m_cuber = nullptr; - m_mc.set_solver(nullptr); + m_mc.set_solver(this); } solver::~solver() { @@ -1544,7 +1544,7 @@ namespace sat { if (m_config.m_drat) m_drat.check_model(m_model); - m_mc.set_solver(nullptr); + // m_mc.set_solver(nullptr); m_mc(m_model); @@ -1601,7 +1601,7 @@ namespace sat { for (literal l : m_assumptions) { if (value_at(l, m) != l_true) { VERIFY(is_external(l.var())); - IF_VERBOSE(0, verbose_stream() << l << " does not model check " << value_at(l, m) << "\n";); + IF_VERBOSE(0, verbose_stream() << "assumption: " << l << " does not model check " << value_at(l, m) << "\n";); TRACE("sat", tout << l << " does not model check\n"; tout << "trail: " << m_trail << "\n"; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index ec6746763..8f70086ba 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -353,6 +353,7 @@ namespace sat { void set_model(model const& mdl); char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } bool check_clauses(model const& m) const; + bool is_assumption(bool_var v) const; literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); lbool cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level); @@ -389,7 +390,6 @@ namespace sat { void reinit_assumptions(); bool tracking_assumptions() const; bool is_assumption(literal l) const; - bool is_assumption(bool_var v) const; void simplify_problem(); void mk_model(); bool check_model(model const & m) const; From d1854ab4d263abde358699839d65ce44285342ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Dec 2017 15:24:40 -0800 Subject: [PATCH 0397/1283] fix assertion in model converter for incremental mode Signed-off-by: Nikolaj Bjorner --- src/sat/sat_model_converter.cpp | 2 +- src/sat/sat_simplifier.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 05c89fba7..fac4cface 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -46,7 +46,7 @@ namespace sat { UNREACHABLE(); throw solver_exception("flipping assumption"); } - if (m_solver && m_solver->is_external(v)) { + if (m_solver && m_solver->is_external(v) && m_solver->is_incremental()) { std::cout << "flipping external v" << v << "\n"; UNREACHABLE(); throw solver_exception("flipping external"); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 6d578b4f9..c101e3a29 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -970,11 +970,12 @@ namespace sat { } void insert(literal l) { + VERIFY(process_var(l.var())); m_queue.insert(l); } bool process_var(bool_var v) { - return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v); + return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v); } void operator()() { From 42499eac1cd543c59ff161313bacaa25f3533037 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Wed, 13 Dec 2017 16:55:16 -0800 Subject: [PATCH 0398/1283] pre-merge Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_integrity_checker.cpp | 1 + src/sat/sat_solver.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index bdc72602d..03cf00e0b 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -155,6 +155,7 @@ namespace sat { } bool integrity_checker::check_watches(literal l, watch_list const& wlist) const { + return true; // TODO: remove for (watched const& w : wlist) { switch (w.get_kind()) { case watched::BINARY: diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0e51c3332..dc3d6711c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1550,8 +1550,8 @@ namespace sat { if (!check_clauses(m_model)) { IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";); - UNREACHABLE(); - throw solver_exception("check model failed"); + //UNREACHABLE(); // TODO: uncomment + //throw solver_exception("check model failed"); // TODO: uncomment } TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); From 209d31346b56e58165e77061660f1e432bd12c28 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Dec 2017 18:03:25 -0800 Subject: [PATCH 0399/1283] fix crash regression Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 4 ++-- src/sat/sat_elim_eqs.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index cd7f23576..edf1c82a2 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2294,8 +2294,8 @@ namespace sat { // literal is no longer watched. return l_undef; } - SASSERT(index <= bound); - SASSERT(c[index] == alit); + VERIFY(index <= bound); + VERIFY(c[index] == alit); // find a literal to swap with: for (unsigned i = bound + 1; i < sz; ++i) { diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 6b8d4cba7..a8eb09278 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -181,8 +181,9 @@ namespace sat { for (bool_var v : to_elim) { literal l(v, false); literal r = roots[v]; - SASSERT(v != r.var()); - if (m_solver.is_external(v) || !m_solver.set_root(l, r)) { + SASSERT(v != r.var()); + if (m_solver.is_external(v)) { + m_solver.set_root(l, r); // cannot really eliminate v, since we have to notify extension of future assignments m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(l, ~r, false); From a74d18a69583992abd4e87a9ef50afb345a4a2cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Dec 2017 20:11:16 -0800 Subject: [PATCH 0400/1283] prepare for variable scoping and autarkies Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 5 +++-- src/muz/spacer/spacer_itp_solver.h | 2 +- src/muz/spacer/spacer_virtual_solver.h | 2 +- src/opt/maxres.cpp | 2 ++ src/opt/opt_solver.h | 2 +- src/sat/sat_asymm_branch.h | 1 - src/sat/sat_elim_eqs.cpp | 3 ++- src/sat/sat_elim_vars.cpp | 4 ++-- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/smt/smt_solver.cpp | 2 +- src/solver/combined_solver.cpp | 4 ++-- src/solver/solver.h | 2 +- src/solver/solver_pool.cpp | 2 +- src/solver/tactic2solver.cpp | 2 +- src/tactic/portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/tactic/portfolio/parallel_tactic.cpp | 3 ++- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 18 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 2805e7e2d..9e7223aee 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -557,7 +557,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_cube(c, s, cutoff); ast_manager& m = mk_c(c)->m(); - expr_ref_vector result(m); + expr_ref_vector result(m), vars(m); unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); @@ -568,7 +568,7 @@ extern "C" { scoped_timer timer(timeout, &eh); scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); try { - result.append(to_solver_ref(s)->cube(cutoff)); + result.append(to_solver_ref(s)->cube(vars, cutoff)); } catch (z3_exception & ex) { mk_c(c)->handle_exception(ex); @@ -580,6 +580,7 @@ extern "C" { for (expr* e : result) { v->m_ast_vector.push_back(e); } + // TBD: save return variables from vars into variable ast-vector. RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 84469f490..55c1711c3 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -119,7 +119,7 @@ public: {NOT_IMPLEMENTED_YET();} virtual void assert_lemma(expr* e) { NOT_IMPLEMENTED_YET(); } virtual expr_ref lookahead(const expr_ref_vector &,const expr_ref_vector &) { return expr_ref(m.mk_true(), m); } - virtual expr_ref_vector cube(unsigned) { return expr_ref_vector(m); } + virtual expr_ref_vector cube(expr_ref_vector&, unsigned) { return expr_ref_vector(m); } virtual void push(); diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 946df95ad..c7dfd3c11 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -94,7 +94,7 @@ public: virtual void reset(); virtual void set_progress_callback(progress_callback *callback) {UNREACHABLE();} - virtual expr_ref_vector cube(unsigned) { return expr_ref_vector(m); } + virtual expr_ref_vector cube(expr_ref_vector&, unsigned) { return expr_ref_vector(m); } virtual solver *translate(ast_manager &m, params_ref const &p); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 117b65c5a..5fa87b3ba 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -285,10 +285,12 @@ public: m_last_index = 0; bool first = index > 0; SASSERT(index < asms.size() || asms.empty()); + IF_VERBOSE(1, verbose_stream() << "start hill climb " << index << " asms: " << asms.size() << "\n";); while (index < asms.size() && is_sat == l_true) { while (!first && asms.size() > 20*(index - m_last_index) && index < asms.size()) { index = next_index(asms, index); } + IF_VERBOSE(1, verbose_stream() << "hill climb " << index << "\n";); first = false; // IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << " num soft: " << index << "\n";); m_last_index = index; diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 9d1eccb38..4d2f39416 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -108,7 +108,7 @@ namespace opt { virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); - virtual expr_ref_vector cube(unsigned) { return expr_ref_vector(m); } + virtual expr_ref_vector cube(expr_ref_vector&, unsigned) { return expr_ref_vector(m); } void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index b18c549ac..6790bd963 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -42,7 +42,6 @@ namespace sat { unsigned m_asymm_branch_rounds; unsigned m_asymm_branch_delay; bool m_asymm_branch_sampled; - bool m_asymm_branch_propagate; bool m_asymm_branch_all; int64 m_asymm_branch_limit; diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 6b8d4cba7..32988b216 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -182,7 +182,8 @@ namespace sat { literal l(v, false); literal r = roots[v]; SASSERT(v != r.var()); - if (m_solver.is_external(v) || !m_solver.set_root(l, r)) { + if (m_solver.is_external(v)) { + m_solver.set_root(l, r); // cannot really eliminate v, since we have to notify extension of future assignments m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(l, ~r, false); diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 379888b15..f04318a5d 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -123,13 +123,13 @@ namespace sat{ TRACE("elim_vars", tout << "eliminate " << v << "\n"; for (watched const& w : simp.get_wlist(~pos_l)) { - if (w.is_binary_unblocked_clause()) { + if (w.is_binary_non_learned_clause()) { tout << pos_l << " " << w.get_literal() << "\n"; } } m.display(tout, b1); for (watched const& w : simp.get_wlist(~neg_l)) { - if (w.is_binary_unblocked_clause()) { + if (w.is_binary_non_learned_clause()) { tout << neg_l << " " << w.get_literal() << "\n"; } } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 2af846f42..3984ec324 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -305,7 +305,7 @@ public: return 0; } - virtual expr_ref_vector cube(unsigned backtrack_level) { + virtual expr_ref_vector cube(expr_ref_vector& vs, unsigned backtrack_level) { if (!m_internalized) { dep2asm_t dep2asm; m_model = 0; diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 01ea61fd9..3449ad480 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -222,7 +222,7 @@ namespace smt { return expr_ref(m.mk_true(), m); } - virtual expr_ref_vector cube(unsigned) { + virtual expr_ref_vector cube(expr_ref_vector&, unsigned) { return expr_ref_vector(get_manager()); } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 29f6a32f1..713009cd6 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -275,8 +275,8 @@ public: return m_solver1->get_num_assumptions() + m_solver2->get_num_assumptions(); } - virtual expr_ref_vector cube(unsigned backtrack_level) { - return m_solver1->cube(backtrack_level); + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) { + return m_solver1->cube(vars, backtrack_level); } virtual expr * get_assumption(unsigned idx) const { diff --git a/src/solver/solver.h b/src/solver/solver.h index 7a51725a2..7634a346e 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -190,7 +190,7 @@ public: \brief extract a lookahead candidates for branching. */ - virtual expr_ref_vector cube(unsigned backtrack_level) = 0; + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) = 0; /** \brief Display the content of this solver. diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 1b7203351..2f6a22580 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -223,7 +223,7 @@ public: virtual void get_labels(svector & r) { return m_base->get_labels(r); } virtual void set_progress_callback(progress_callback * callback) { m_base->set_progress_callback(callback); } - virtual expr_ref_vector cube(unsigned ) { return expr_ref_vector(m); } + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned ) { return expr_ref_vector(m); } virtual ast_manager& get_manager() const { return m_base->get_manager(); } diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 4585af65e..cbe6b34a9 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -77,7 +77,7 @@ public: virtual ast_manager& get_manager() const; - virtual expr_ref_vector cube(unsigned ) { + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned ) { return expr_ref_vector(get_manager()); } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index b8a8f6704..c81d413b8 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -162,7 +162,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref_vector cube(unsigned backtrack_level) { flush_assertions(); return m_solver->cube(backtrack_level); } + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) { flush_assertions(); return m_solver->cube(vars, backtrack_level); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index ffb51fe2e..bfe057f82 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -103,7 +103,7 @@ public: virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual expr_ref_vector cube(unsigned backtrack_level) { return m_solver->cube(backtrack_level); } + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) { return m_solver->cube(vars, backtrack_level); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { datatype_util dt(m); diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 8e14d77e2..f4982c2c2 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -414,7 +414,8 @@ private: cubes.reset(); s.set_cube_params(); while (true) { - expr_ref_vector c = s.get_solver().cube(UINT_MAX); // TBD tune this + expr_ref_vector vars(m); + expr_ref_vector c = s.get_solver().cube(vars, UINT_MAX); // TBD tune this if (c.empty()) { report_undef(s); return; diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index cb5327443..eba10cbd1 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -100,7 +100,7 @@ public: virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual expr_ref_vector cube(unsigned backtrack_level) { flush_assertions(); return m_solver->cube(backtrack_level); } + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) { flush_assertions(); return m_solver->cube(vars, backtrack_level); } virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { flush_assertions(); From 6b258578f9b20164d7dc203392a775515c5414de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 02:38:45 -0800 Subject: [PATCH 0401/1283] fix uninitialized variable m_gc_burst in config, have cuber accept and receive optional vector of variables indicating splits and global autarky as output Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 2 +- src/api/api_solver.cpp | 17 +++++++-- src/api/c++/z3++.h | 44 ++++++++++++++++------- src/api/dotnet/Solver.cs | 14 ++++++-- src/api/python/z3/z3.py | 15 +++++--- src/api/z3_api.h | 11 ++++-- src/sat/sat_asymm_branch.cpp | 2 +- src/sat/sat_config.cpp | 1 + src/sat/sat_elim_eqs.cpp | 4 +-- src/sat/sat_lookahead.cpp | 50 ++++++--------------------- src/sat/sat_lookahead.h | 5 ++- src/sat/sat_solver.cpp | 7 +--- src/sat/sat_solver.h | 4 +-- src/sat/sat_solver/inc_sat_solver.cpp | 43 ++++++++++++----------- src/solver/solver.h | 2 +- 15 files changed, 121 insertions(+), 100 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 732a89099..6fa4e809e 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -707,7 +707,7 @@ void tactic_example7() { std::cout << s.check() << "\n"; model m = s.get_model(); std::cout << "model for subgoal:\n" << m << "\n"; - std::cout << "model for original goal:\n" << r.convert_model(m) << "\n"; + std::cout << "model for original goal:\n" << subgoal.convert_model(m) << "\n"; } void tactic_example8() { diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 9e7223aee..48ce6d22d 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -553,11 +553,19 @@ extern "C" { Z3_CATCH_RETURN(Z3_L_UNDEF); } - Z3_ast_vector Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, unsigned cutoff) { + Z3_ast_vector Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, Z3_ast_vector vs, unsigned cutoff) { Z3_TRY; - LOG_Z3_solver_cube(c, s, cutoff); + LOG_Z3_solver_cube(c, s, vs, cutoff); ast_manager& m = mk_c(c)->m(); 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); + } + else { + vars.push_back(to_expr(a)); + } + } unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()); bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); @@ -580,7 +588,10 @@ extern "C" { for (expr* e : result) { v->m_ast_vector.push_back(e); } - // TBD: save return variables from vars into variable ast-vector. + to_ast_vector_ref(vs).reset(); + for (expr* a : vars) { + to_ast_vector_ref(vs).push_back(a); + } RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 428f210ee..270a98ca9 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1999,18 +1999,23 @@ namespace z3 { param_descrs get_param_descrs() { return param_descrs(ctx(), Z3_solver_get_param_descrs(ctx(), m_solver)); } - expr_vector cube(unsigned cutoff) { Z3_ast_vector r = Z3_solver_cube(ctx(), m_solver, cutoff); check_error(); return expr_vector(ctx(), r); } + expr_vector cube(expr_vector& vars, unsigned cutoff) { + Z3_ast_vector r = Z3_solver_cube(ctx(), m_solver, vars, cutoff); + check_error(); + return expr_vector(ctx(), r); + } class cube_iterator { - solver& m_solver; - unsigned& m_cutoff; - expr_vector m_cube; - bool m_end; - bool m_empty; + solver& m_solver; + unsigned& m_cutoff; + expr_vector& m_vars; + expr_vector m_cube; + bool m_end; + bool m_empty; void inc() { assert(!m_end && !m_empty); - m_cube = m_solver.cube(m_cutoff); + m_cube = m_solver.cube(m_vars, m_cutoff); m_cutoff = 0xFFFFFFFF; if (m_cube.size() == 1 && m_cube[0].is_false()) { m_cube = z3::expr_vector(m_solver.ctx()); @@ -2021,9 +2026,10 @@ namespace z3 { } } public: - cube_iterator(solver& s, unsigned& cutoff, bool end): + cube_iterator(solver& s, expr_vector& vars, unsigned& cutoff, bool end): m_solver(s), m_cutoff(cutoff), + m_vars(vars), m_cube(s.ctx()), m_end(end), m_empty(false) { @@ -2056,20 +2062,32 @@ namespace z3 { }; class cube_generator { - solver& m_solver; - unsigned m_cutoff; + solver& m_solver; + unsigned m_cutoff; + expr_vector m_default_vars; + expr_vector& m_vars; public: cube_generator(solver& s): m_solver(s), - m_cutoff(0xFFFFFFFF) + m_cutoff(0xFFFFFFFF), + m_default_vars(s.ctx()), + m_vars(m_default_vars) {} - cube_iterator begin() { return cube_iterator(m_solver, m_cutoff, false); } - cube_iterator end() { return cube_iterator(m_solver, m_cutoff, true); } + cube_generator(solver& s, expr_vector& vars): + m_solver(s), + m_cutoff(0xFFFFFFFF), + m_default_vars(s.ctx()), + m_vars(vars) + {} + + cube_iterator begin() { return cube_iterator(m_solver, m_vars, m_cutoff, false); } + cube_iterator end() { return cube_iterator(m_solver, m_vars, m_cutoff, true); } void set_cutoff(unsigned c) { m_cutoff = c; } }; cube_generator cubes() { return cube_generator(*this); } + cube_generator cubes(expr_vector& vars) { return cube_generator(*this, vars); } }; inline std::ostream & operator<<(std::ostream & out, solver const & s) { out << Z3_solver_to_string(s.ctx(), s); return out; } diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index e136516e4..f67a298bb 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -404,6 +404,11 @@ namespace Microsoft.Z3 /// Backtrack level that can be adjusted by conquer process /// public uint BacktrackLevel { get; set; } + + /// + /// Variables available and returned by the cuber. + /// + public BoolExpr[] CubeVariables { get; set; } /// @@ -411,16 +416,21 @@ namespace Microsoft.Z3 /// public IEnumerable Cube() { + ASTVector cv = new ASTVector(Context); + if (CubeVariables != null) + foreach (var b in CubeVariables) cv.Push(b); + while (true) { var lvl = BacktrackLevel; BacktrackLevel = uint.MaxValue; - ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, lvl)); + ASTVector r = new ASTVector(Context, Native.Z3_solver_cube(Context.nCtx, NativeObject, cv.NativeObject, lvl)); var v = r.ToBoolExprArray(); + CubeVariables = cv.ToBoolExprArray(); if (v.Length == 1 && v[0].IsFalse) { break; } yield return v; - if (v.Length == 0) { + if (v.Length == 0) { break; } } diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index f15386a93..e16459fda 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6313,18 +6313,25 @@ class Solver(Z3PPObject): consequences = [ consequences[i] for i in range(sz) ] return CheckSatResult(r), consequences - def cube(self): + def cube(self, vars = None): """Get set of cubes""" + self.cube_vs = AstVector(None, self.ctx) + if vars is not None: + for v in vars: + self.cube_vs.push(v) while True: lvl = self.backtrack_level self.backtrack_level = 4000000000 - r = AstVector(Z3_solver_cube(self.ctx.ref(), self.solver, lvl), self.ctx) + r = AstVector(Z3_solver_cube(self.ctx.ref(), self.solver, self.cube_vs.vector, lvl), self.ctx) if (len(r) == 1 and is_false(r[0])): - return - yield r + return + yield r if (len(r) == 0): return + def cube_vars(self): + return self.cube_vs + def proof(self): """Return a proof for the last `check()`. Proof construction must be enabled.""" return _to_expr_ref(Z3_solver_get_proof(self.ctx.ref(), self.solver), self.ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index b212912b9..99d6021ef 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6230,13 +6230,20 @@ extern "C" { The number of (non-constant) cubes is by default 1. For the sat solver cubing is controlled using parameters sat.lookahead.cube.cutoff and sat.lookahead.cube.fraction. + The third argument is a vector of variables that may be used for cubing. + The contents of the vector is only used in the first call. The initial list of variables + is used in subsequent calls until it returns the unsatisfiable cube. + The vector is modified to contain a set of Autarky variables that occor in clauses that + are affected by the (last literal in the) cube. These variables could be used by a different + cuber (on a different solver object) for further recursive cubing. + The last argument is a backtracking level. It instructs the cube process to backtrack below the indicated level for the next cube. - def_API('Z3_solver_cube', AST_VECTOR, (_in(CONTEXT), _in(SOLVER), _in(UINT))) + def_API('Z3_solver_cube', AST_VECTOR, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(UINT))) */ - Z3_ast_vector Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, unsigned backtrack_level); + Z3_ast_vector Z3_API Z3_solver_cube(Z3_context c, Z3_solver s, Z3_ast_vector vars, unsigned backtrack_level); /** \brief Retrieve the model for the last #Z3_solver_check or #Z3_solver_check_assumptions diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index e3543ff0f..0d0e3a682 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -72,7 +72,7 @@ namespace sat { unsigned elim = m_elim_literals; if (big) big->init_big(s, true); process(big, s.m_clauses); - process(big, s.m_learned); + if (big) process(big, s.m_learned); s.propagate(false); if (s.m_inconsistent) break; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 361e15d91..09610a3a7 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -136,6 +136,7 @@ namespace sat { m_gc_increment = p.gc_increment(); m_gc_small_lbd = p.gc_small_lbd(); m_gc_k = std::min(255u, p.gc_k()); + m_gc_burst = p.gc_burst(); m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index a8eb09278..582194bc2 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -182,8 +182,8 @@ namespace sat { literal l(v, false); literal r = roots[v]; SASSERT(v != r.var()); - if (m_solver.is_external(v)) { - m_solver.set_root(l, r); + bool root_ok = !m_solver.is_external(v) || m_solver.set_root(l, r); + if (m_solver.is_external(v) && (m_solver.is_incremental() || !root_ok)) { // cannot really eliminate v, since we have to notify extension of future assignments m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(l, ~r, false); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index fd4f63c1e..9fc818014 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -338,7 +338,7 @@ namespace sat { } TRACE("sat", display_candidates(tout << "sum: " << sum << "\n");); if (skip_candidates > 0) { - IF_VERBOSE(0, verbose_stream() << "candidates: " << m_candidates.size() << " skip: " << skip_candidates << "\n";); + IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :candidates " << m_candidates.size() << " :skipped " << skip_candidates << ")\n";); } return sum; } @@ -2049,15 +2049,15 @@ namespace sat { return h; } - lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level) { + lbool lookahead::cube(bool_var_vector& vars, literal_vector& lits, unsigned backtrack_level) { scoped_ext _scoped_ext(*this); lits.reset(); - m_select_lookahead_vars.reset(); - for (auto v : vars) { - m_select_lookahead_vars.insert(v); - } bool is_first = m_cube_state.m_first; if (is_first) { + m_select_lookahead_vars.reset(); + for (auto v : vars) { + m_select_lookahead_vars.insert(v); + } init_search(); m_model.reset(); m_cube_state.m_first = false; @@ -2109,6 +2109,8 @@ namespace sat { #else lits.append(m_cube_state.m_cube); #endif + vars.reset(); + for (auto v : m_freevars) if (in_reduced_clause(v)) vars.push_back(v); backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision); return l_undef; } @@ -2124,6 +2126,8 @@ namespace sat { continue; } if (lit == null_literal) { + vars.reset(); + for (auto v : m_freevars) if (in_reduced_clause(v)) vars.push_back(v); return l_true; } TRACE("sat", tout << "choose: " << lit << " cube: " << m_cube_state.m_cube << "\n";); @@ -2246,40 +2250,6 @@ namespace sat { return l; } - - literal lookahead::select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars) { - IF_VERBOSE(1, verbose_stream() << "(sat-select " << vars.size() << ")\n";); - scoped_ext _sext(*this); - m_search_mode = lookahead_mode::searching; - scoped_level _sl(*this, c_fixed_truth); - init(); - if (inconsistent()) return null_literal; - inc_istamp(); - for (auto v : vars) { - m_select_lookahead_vars.insert(v); - } - - scoped_assumptions _sa(*this, assumptions); - literal l = choose(); - m_select_lookahead_vars.reset(); - if (inconsistent()) l = null_literal; - -#if 0 - // assign unit literals that were found during search for lookahead. - if (assumptions.empty()) { - unsigned num_assigned = 0; - for (literal lit : m_trail) { - if (!m_s.was_eliminated(lit.var()) && m_s.value(lit) != l_true) { - m_s.assign(lit, justification()); - ++num_assigned; - } - } - IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :units " << num_assigned << ")\n";); - } -#endif - return l; - } - /** \brief simplify set of clauses by extracting units from a lookahead at base level. */ diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 6a7bb7449..3ebbfb7a5 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -587,15 +587,14 @@ namespace sat { /** \brief create cubes to std-out in DIMACS form. The cubes are controlled using cut-depth and cut-fraction parameters. - If cut-depth != 0, then it is used to control the depth of cuts. + If cut-depth != 0, then it is used to control thedepth of cuts. Otherwise, cut-fraction gives an adaptive threshold for creating cuts. */ - lbool cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level); + lbool cube(bool_var_vector& vars, literal_vector& lits, unsigned backtrack_level); void update_cube_statistics(statistics& st); - literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** \brief simplify set of clauses by extracting units from a lookahead at base level. */ diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index db6f3d356..8c7c4d421 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -861,12 +861,7 @@ namespace sat { return r; } - literal solver::select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars) { - lookahead lh(*this); - return lh.select_lookahead(assumptions, vars); - } - - lbool solver::cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level) { + lbool solver::cube(bool_var_vector& vars, literal_vector& lits, unsigned backtrack_level) { if (!m_cuber) { m_cuber = alloc(lookahead, *this); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 8f70086ba..bac9c4bb3 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -355,10 +355,10 @@ namespace sat { bool check_clauses(model const& m) const; bool is_assumption(bool_var v) const; - literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); - lbool cube(bool_var_vector const& vars, literal_vector& lits, unsigned backtrack_level); + lbool cube(bool_var_vector& vars, literal_vector& lits, unsigned backtrack_level); protected: + unsigned m_conflicts_since_init; unsigned m_restarts; unsigned m_conflicts_since_restart; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 3984ec324..d731c246c 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -67,12 +67,12 @@ class inc_sat_solver : public solver { std::string m_unknown; // access formulas after they have been pre-processed and handled by the sat solver. // this allows to access the internal state of the SAT solver and carry on partial results. - bool m_internalized; // are formulas internalized? bool m_internalized_converted; // have internalized formulas been converted back expr_ref_vector m_internalized_fmls; // formulas in internalized format - typedef obj_map dep2asm_t; + + bool is_internalized() const { return m_fmls_head == m_fmls.size(); } public: inc_sat_solver(ast_manager& m, params_ref const& p, bool incremental_mode): m(m), @@ -84,7 +84,6 @@ public: m_map(m), m_num_scopes(0), m_unknown("no reason given"), - m_internalized(false), m_internalized_converted(false), m_internalized_fmls(m) { updt_params(p); @@ -94,7 +93,6 @@ public: bool override_incremental() const { sat_simplifier_params p(m_params); - std::cout << "override: " << p.override_incremental() << "\n"; return p.override_incremental(); } @@ -124,7 +122,6 @@ public: if (m_mc0) result->m_mc0 = m_mc0->translate(tr); //if (m_sat_mc) result->m_sat_mc = m_sat_mc->translate(tr); MN: commenting this line removes bloat // copy m_bb_rewriter? - result->m_internalized = m_internalized; result->m_internalized_converted = m_internalized_converted; return result; } @@ -188,8 +185,6 @@ public: if (r != l_true) return r; r = internalize_assumptions(sz, _assumptions.c_ptr(), dep2asm); if (r != l_true) return r; - m_internalized = true; - m_internalized_converted = false; init_reason_unknown(); try { @@ -226,11 +221,8 @@ public: m_fmls_head_lim.push_back(m_fmls_head); if (m_bb_rewriter) m_bb_rewriter->push(); m_map.push(); - m_internalized = true; - m_internalized_converted = false; } virtual void pop(unsigned n) { - m_internalized = false; if (n > m_num_scopes) { // allow inc_sat_solver to n = m_num_scopes; // take over for another solver. } @@ -264,7 +256,6 @@ public: virtual ast_manager& get_manager() const { return m; } virtual void assert_expr_core(expr * t) { - m_internalized = false; TRACE("goal2sat", tout << mk_pp(t, m) << "\n";); m_fmls.push_back(t); } @@ -306,17 +297,18 @@ public: } virtual expr_ref_vector cube(expr_ref_vector& vs, unsigned backtrack_level) { - if (!m_internalized) { - dep2asm_t dep2asm; + if (!is_internalized()) { m_model = 0; lbool r = internalize_formulas(); if (r != l_true) return expr_ref_vector(m); - m_internalized = true; } convert_internalized(); + obj_hashtable _vs; + for (expr* v : vs) _vs.insert(v); sat::bool_var_vector vars; for (auto& kv : m_map) { - vars.push_back(kv.m_value); + if (_vs.empty() || _vs.contains(kv.m_key)) + vars.push_back(kv.m_value); } sat::literal_vector lits; lbool result = m_solver.cube(vars, lits, backtrack_level); @@ -327,7 +319,7 @@ public: } if (result == l_true) { return expr_ref_vector(m); - } + } expr_ref_vector fmls(m); expr_ref_vector lit2expr(m); lit2expr.resize(m_solver.num_vars() * 2); @@ -335,6 +327,13 @@ public: for (sat::literal l : lits) { fmls.push_back(lit2expr[l.index()].get()); } + vs.reset(); + for (sat::bool_var v : vars) { + expr* x = lit2expr[sat::literal(v, false).index()].get(); + if (x) { + vs.push_back(x); + } + } return fmls; } @@ -419,7 +418,7 @@ public: } virtual unsigned get_num_assertions() const { const_cast(this)->convert_internalized(); - if (m_internalized && m_internalized_converted) { + if (is_internalized() && m_internalized_converted) { return m_internalized_fmls.size(); } else { @@ -427,7 +426,7 @@ public: } } virtual expr * get_assertion(unsigned idx) const { - if (m_internalized && m_internalized_converted) { + if (is_internalized() && m_internalized_converted) { return m_internalized_fmls[idx]; } return m_fmls[idx]; @@ -443,7 +442,7 @@ public: const_cast(this)->convert_internalized(); if (m_cached_mc) return m_cached_mc; - if (m_internalized && m_internalized_converted) { + if (is_internalized() && m_internalized_converted) { m_cached_mc = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); m_cached_mc = concat(solver::get_model_converter().get(), m_cached_mc.get()); m_cached_mc = concat(m_cached_mc.get(), m_sat_mc.get()); @@ -455,7 +454,10 @@ public: } void convert_internalized() { - if (!m_internalized || m_internalized_converted) return; + if (!is_internalized() && m_fmls_head > 0) { + internalize_formulas(); + } + if (!is_internalized() || m_internalized_converted) return; sat2goal s2g; m_cached_mc = nullptr; goal g(m, false, true, false); @@ -679,6 +681,7 @@ private: if (res != l_undef) { m_fmls_head = m_fmls.size(); } + m_internalized_converted = false; return res; } diff --git a/src/solver/solver.h b/src/solver/solver.h index 7634a346e..bc6ffb0e0 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -47,7 +47,7 @@ class solver : public check_sat_result { params_ref m_params; bool m_enforce_model_conversion; public: - solver(): m_enforce_model_conversion(true) {} + solver(): m_enforce_model_conversion(false) {} virtual ~solver() {} /** From e45dc51e70dea7c6b754f5faedf243763da5631e Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Thu, 14 Dec 2017 09:58:57 -0800 Subject: [PATCH 0402/1283] commented non-compiling debug traces Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_elim_vars.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 379888b15..f9f06f222 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -122,17 +122,17 @@ namespace sat{ bdd b = m.mk_exists(m_var2index[v], b0); TRACE("elim_vars", tout << "eliminate " << v << "\n"; - for (watched const& w : simp.get_wlist(~pos_l)) { + /*for (watched const& w : simp.get_wlist(~pos_l)) { if (w.is_binary_unblocked_clause()) { tout << pos_l << " " << w.get_literal() << "\n"; } - } + }*/ m.display(tout, b1); - for (watched const& w : simp.get_wlist(~neg_l)) { + /*for (watched const& w : simp.get_wlist(~neg_l)) { if (w.is_binary_unblocked_clause()) { tout << neg_l << " " << w.get_literal() << "\n"; } - } + }*/ m.display(tout, b2); clause_use_list::iterator itp = pos_occs.mk_iterator(); while (!itp.at_end()) { From 030868d8def00cffabe7dff5a5bd8b9cab7dbe0e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Dec 2017 07:21:37 -0800 Subject: [PATCH 0403/1283] reset cache in ast_translation periodically to avoid congestion Signed-off-by: Nikolaj Bjorner --- src/ast/ast_translation.cpp | 44 ++++++++++++++++++++++++++++--------- src/ast/ast_translation.h | 16 ++++++++++++++ src/sat/sat_config.cpp | 18 +++++---------- src/util/hashtable.h | 38 +++++++++++++++++++++++++++----- src/util/obj_hashtable.h | 8 +++++++ 5 files changed, 97 insertions(+), 27 deletions(-) diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index e6be3da98..a57e5d194 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -23,6 +23,7 @@ Revision History: #include "ast/format.h" #include "ast/ast_translation.h" #include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" ast_translation::~ast_translation() { reset_cache(); @@ -47,7 +48,12 @@ void ast_translation::reset_cache() { void ast_translation::cache(ast * s, ast * t) { SASSERT(!m_cache.contains(s)); if (s->get_ref_count() > 1) { + if (m_insert_count > (1 << 17)) { + reset_cache(); + m_insert_count = 0; + } m_cache.insert(s, t); + ++m_insert_count; m_from_manager.inc_ref(s); m_to_manager.inc_ref(t); } @@ -76,9 +82,15 @@ void ast_translation::push_frame(ast * n) { bool ast_translation::visit(ast * n) { ast * r; - if (n->get_ref_count() > 1 && m_cache.find(n, r)) { - m_result_stack.push_back(r); - return true; + if (n->get_ref_count() > 1) { + if (m_cache.find(n, r)) { + m_result_stack.push_back(r); + ++m_hit_count; + return true; + } + else { + ++m_miss_count; + } } push_frame(n); return false; @@ -187,20 +199,32 @@ ast * ast_translation::process(ast const * _n) { SASSERT(m_frame_stack.empty()); SASSERT(m_extra_children_stack.empty()); + ++m_num_process; + if (m_num_process > (1 << 16)) { + reset_cache(); + m_num_process = 0; + } if (!visit(const_cast(_n))) { while (!m_frame_stack.empty()) { loop: + ++m_loop_count; frame & fr = m_frame_stack.back(); ast * n = fr.m_n; ast * r; TRACE("ast_translation", tout << mk_ll_pp(n, m_from_manager, false) << "\n";); - if (fr.m_idx == 0 && n->get_ref_count() > 1 && m_cache.find(n, r)) { - SASSERT(m_result_stack.size() == fr.m_rpos); - m_result_stack.push_back(r); - m_extra_children_stack.shrink(fr.m_cpos); - m_frame_stack.pop_back(); - TRACE("ast_translation", tout << "hit\n";); - continue; + if (fr.m_idx == 0 && n->get_ref_count() > 1) { + if (m_cache.find(n, r)) { + SASSERT(m_result_stack.size() == fr.m_rpos); + m_result_stack.push_back(r); + m_extra_children_stack.shrink(fr.m_cpos); + m_frame_stack.pop_back(); + TRACE("ast_translation", tout << "hit\n";); + m_hit_count++; + continue; + } + else { + m_miss_count++; + } } switch (n->get_kind()) { case AST_VAR: { diff --git a/src/ast/ast_translation.h b/src/ast/ast_translation.h index 9d09fbb76..47517a073 100644 --- a/src/ast/ast_translation.h +++ b/src/ast/ast_translation.h @@ -37,6 +37,11 @@ class ast_translation { ptr_vector m_extra_children_stack; // for sort and func_decl, since they have nested AST in their parameters ptr_vector m_result_stack; obj_map m_cache; + unsigned m_loop_count; + unsigned m_hit_count; + unsigned m_miss_count; + unsigned m_insert_count; + unsigned m_num_process; void cache(ast * s, ast * t); void collect_decl_extra_children(decl * d); @@ -50,6 +55,11 @@ class ast_translation { public: ast_translation(ast_manager & from, ast_manager & to, bool copy_plugins = true) : m_from_manager(from), m_to_manager(to) { + m_loop_count = 0; + m_hit_count = 0; + m_miss_count = 0; + m_insert_count = 0; + m_num_process = 0; if (&from != &to) { if (copy_plugins) m_to_manager.copy_families_plugins(m_from_manager); @@ -73,6 +83,12 @@ public: void reset_cache(); void cleanup(); + + unsigned loop_count() const { return m_loop_count; } + unsigned hit_count() const { return m_hit_count; } + unsigned miss_count() const { return m_miss_count; } + unsigned insert_count() const { return m_insert_count; } + unsigned long long get_num_collision() const { return m_cache.get_num_collision(); } }; // Translation with non-persistent cache. diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 09610a3a7..73bb94c7d 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -87,24 +87,18 @@ namespace sat { else throw sat_param_exception("invalid reward type supplied: accepted heuristics are 'ternary', 'heuleu', 'unit' or 'heule_schur'"); - if (p.lookahead_cube_cutoff() == symbol("depth")) { + if (p.lookahead_cube_cutoff() == symbol("depth")) m_lookahead_cube_cutoff = depth_cutoff; - } - else if (p.lookahead_cube_cutoff() == symbol("freevars")) { + else if (p.lookahead_cube_cutoff() == symbol("freevars")) m_lookahead_cube_cutoff = freevars_cutoff; - } - else if (p.lookahead_cube_cutoff() == symbol("psat")) { + else if (p.lookahead_cube_cutoff() == symbol("psat")) m_lookahead_cube_cutoff = psat_cutoff; - } - else if (p.lookahead_cube_cutoff() == symbol("adaptive_freevars")) { + else if (p.lookahead_cube_cutoff() == symbol("adaptive_freevars")) m_lookahead_cube_cutoff = adaptive_freevars_cutoff; - } - else if (p.lookahead_cube_cutoff() == symbol("adaptive_psat")) { + else if (p.lookahead_cube_cutoff() == symbol("adaptive_psat")) m_lookahead_cube_cutoff = adaptive_psat_cutoff; - } - else { + else throw sat_param_exception("invalid cutoff type supplied: accepted cutoffs are 'depth', 'freevars', 'psat', 'adaptive_freevars' and 'adaptive_psat'"); - } m_lookahead_cube_fraction = p.lookahead_cube_fraction(); m_lookahead_cube_depth = p.lookahead_cube_depth(); m_lookahead_cube_freevars = p.lookahead_cube_freevars(); diff --git a/src/util/hashtable.h b/src/util/hashtable.h index fa9fef180..e7b57d7f6 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -24,11 +24,12 @@ Revision History: #include #include "util/memory_manager.h" #include "util/hash.h" +#include "util/vector.h" #define DEFAULT_HASHTABLE_INITIAL_CAPACITY 8 #define SMALL_TABLE_CAPACITY 64 -// #define HASHTABLE_STATISTICS +// #define HASHTABLE_STATISTICS #ifdef HASHTABLE_STATISTICS #define HS_CODE(CODE) { CODE } @@ -375,8 +376,7 @@ public: } ((void) 0) void insert(data && e) { - if ((m_size + m_num_deleted) << 2 > (m_capacity * 3)) { - // if ((m_size + m_num_deleted) * 2 > (m_capacity)) { + if (((m_size + m_num_deleted) << 2) > (m_capacity * 3)) { expand_table(); } unsigned hash = get_hash(e); @@ -488,7 +488,9 @@ public: else if (curr->is_free()) { \ return 0; \ } \ - HS_CODE(const_cast(this)->m_st_collision++;); \ + else { \ + HS_CODE(const_cast(this)->m_st_collision++;); \ + } \ } ((void) 0) entry * find_core(data const & e) const { @@ -655,7 +657,33 @@ public: unsigned long long get_num_collision() const { return 0; } #endif - +#define COLL_LOOP_BODY() { \ + if (curr->is_used()) { \ + if (curr->get_hash() == hash && equals(curr->get_data(), e)) return; \ + collisions.push_back(curr->get_data()); \ + continue; \ + } \ + else if (curr->is_free()) { \ + continue; \ + } \ + collisions.push_back(curr->get_data()); \ + } ((void) 0); + + void get_collisions(data const& e, vector& collisions) { + unsigned hash = get_hash(e); + unsigned mask = m_capacity - 1; + unsigned idx = hash & mask; + entry * begin = m_table + idx; + entry * end = m_table + m_capacity; + entry * curr = begin; + for (; curr != end; ++curr) { + COLL_LOOP_BODY(); + } + for (curr = m_table; curr != begin; ++curr) { + COLL_LOOP_BODY(); + } + + } }; template diff --git a/src/util/obj_hashtable.h b/src/util/obj_hashtable.h index df279383b..dc876ffb2 100644 --- a/src/util/obj_hashtable.h +++ b/src/util/obj_hashtable.h @@ -204,6 +204,14 @@ public: unsigned long long get_num_collision() const { return m_table.get_num_collision(); } + void get_collisions(Key * k, vector& collisions) { + vector cs; + m_table.get_collisions(key_data(k), cs); + for (key_data const& kd : cs) { + collisions.push_back(kd.m_key); + } + } + void swap(obj_map & other) { m_table.swap(other.m_table); } From b3e5fade32564dd0d87095b95ec4369fd20e07f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Dec 2017 11:22:50 -0800 Subject: [PATCH 0404/1283] remove cache reset that causes crash Signed-off-by: Nikolaj Bjorner --- src/ast/ast_translation.cpp | 8 ++------ src/sat/sat_asymm_branch.cpp | 37 ++++++++++++++++++++++++------------ src/sat/sat_asymm_branch.h | 2 ++ src/sat/sat_big.cpp | 30 ++++++++++++++++++++++------- src/sat/sat_big.h | 14 +++++++++++++- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_lookahead.cpp | 28 +++++++++++++++++++++++++++ src/sat/sat_lookahead.h | 2 ++ src/sat/sat_params.pyg | 1 + 10 files changed, 98 insertions(+), 26 deletions(-) diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index a57e5d194..b7ed86da5 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -48,14 +48,10 @@ void ast_translation::reset_cache() { void ast_translation::cache(ast * s, ast * t) { SASSERT(!m_cache.contains(s)); if (s->get_ref_count() > 1) { - if (m_insert_count > (1 << 17)) { - reset_cache(); - m_insert_count = 0; - } - m_cache.insert(s, t); - ++m_insert_count; m_from_manager.inc_ref(s); m_to_manager.inc_ref(t); + m_cache.insert(s, t); + ++m_insert_count; } } diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 0d0e3a682..ee8e9db88 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -55,9 +55,11 @@ namespace sat { ~report() { m_watch.stop(); IF_VERBOSE(SAT_VB_LVL, - verbose_stream() << " (sat-asymm-branch :elim-literals " - << (m_asymm_branch.m_elim_literals - m_elim_literals) - << " :elim-learned-literals " << (m_asymm_branch.m_elim_learned_literals - m_elim_learned_literals) + unsigned num_learned = (m_asymm_branch.m_elim_learned_literals - m_elim_learned_literals); + unsigned num_total = (m_asymm_branch.m_elim_literals - m_elim_literals); + verbose_stream() + << " (sat-asymm-branch :elim-literals " << (num_total - num_learned) + << " :elim-learned-literals " << num_learned << " :hidden-tautologies " << (m_asymm_branch.m_hidden_tautologies - m_hidden_tautologies) << " :cost " << m_asymm_branch.m_counter << mem_stat() @@ -76,12 +78,15 @@ namespace sat { s.propagate(false); if (s.m_inconsistent) break; - std::cout << "elim: " << m_elim_literals - elim << "\n"; - if (m_elim_literals == elim) + unsigned num_elim = m_elim_literals - elim; + IF_VERBOSE(1, verbose_stream() << "(sat-asymm-branch-step :elim " << num_elim << ")\n";); + if (num_elim == 0) break; - } - std::cout << "elim-literals: " << m_elim_literals - elim0 << "\n"; - std::cout << "elim-learned-literals: " << m_elim_learned_literals - eliml0 << "\n"; + if (num_elim > 1000) + i = 0; + } + IF_VERBOSE(1, if (m_elim_learned_literals > eliml0) + verbose_stream() << "(sat-asymm-branch :elim " << m_elim_learned_literals - eliml0 << ")\n";); return m_elim_literals > elim0; } @@ -128,6 +133,16 @@ namespace sat { throw ex; } } + + void asymm_branch::operator()(big& big) { + s.propagate(false); + if (s.m_inconsistent) + return; + report rpt(*this); + svector saved_phase(s.m_phase); + process(&big); + s.m_phase = saved_phase; + } void asymm_branch::operator()(bool force) { ++m_calls; @@ -244,7 +259,6 @@ namespace sat { lemma[j++] = l; } } - // std::cout << lemma.size() << " -> " << j << "\n"; lemma.shrink(j); } } @@ -347,8 +361,7 @@ namespace sat { break; } } - new_sz = j; - // std::cout << "cleanup: " << c.id() << ": " << literal_vector(new_sz, c.begin()) << " delta: " << (c.size() - new_sz) << " " << skip_idx << " " << new_sz << "\n"; + new_sz = j; return re_attach(scoped_d, c, new_sz); } @@ -386,7 +399,7 @@ namespace sat { bool asymm_branch::process_sampled(big& big, clause & c) { scoped_detach scoped_d(s, c); sort(big, c); -#if 0 +#if 1 if (uhte(big, c)) { ++m_hidden_tautologies; scoped_d.del_clause(); diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 6790bd963..226684c85 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -87,6 +87,8 @@ namespace sat { void operator()(bool force = false); + void operator()(big& big); + void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index aa4a62745..5b32911f1 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -24,12 +24,8 @@ namespace sat { big::big() {} void big::init_big(solver& s, bool learned) { - m_num_vars = s.num_vars(); + init_adding_edges(s.num_vars()); unsigned num_lits = m_num_vars * 2; - m_dag.reset(); - m_roots.reset(); - m_dag.resize(num_lits, 0); - m_roots.resize(num_lits, true); literal_vector lits; SASSERT(num_lits == m_dag.size() && num_lits == m_roots.size()); for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { @@ -44,11 +40,31 @@ namespace sat { edges.push_back(v); } } + } + done_adding_edges(); + } + + void big::init_adding_edges(unsigned num_vars) { + m_num_vars = num_vars; + unsigned num_lits = m_num_vars * 2; + m_dag.reset(); + m_roots.reset(); + m_dag.resize(num_lits, 0); + m_roots.resize(num_lits, true); + } + + void big::add_edge(literal u, literal v) { + m_dag[u.index()].push_back(v); + } + + void big::done_adding_edges() { + for (auto& edges : m_dag) { shuffle(edges.size(), edges.c_ptr(), m_rand); } - init_dfs_num(learned); + init_dfs_num(); } + struct big::pframe { literal m_parent; literal m_child; @@ -58,7 +74,7 @@ namespace sat { literal parent() const { return m_parent; } }; - void big::init_dfs_num(bool learned) { + void big::init_dfs_num() { unsigned num_lits = m_num_vars * 2; m_left.reset(); m_right.reset(); diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index ca9f131eb..9896a3215 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -34,13 +34,24 @@ namespace sat { svector m_left, m_right; literal_vector m_root, m_parent; - void init_dfs_num(bool learned); + void init_dfs_num(); struct pframe; public: big(); + /** + \brief initialize a BIG from a solver. + */ void init_big(solver& s, bool learned); + + /** + \brief initialize a BIG externally by adding implications. + */ + void init_adding_edges(unsigned num_vars); + void add_edge(literal u, literal v); + void done_adding_edges(); + void ensure_big(solver& s, bool learned) { if (m_left.empty()) init_big(s, learned); } int get_left(literal l) const { return m_left[l.index()]; } int get_right(literal l) const { return m_right[l.index()]; } @@ -49,6 +60,7 @@ namespace sat { bool reaches(literal u, literal v) const { return m_left[u.index()] < m_left[v.index()] && m_right[v.index()] < m_right[u.index()]; } bool connected(literal u, literal v) const { return reaches(u, v) || reaches(~v, ~u); } void display(std::ostream& out) const; + }; }; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 73bb94c7d..cf26fc09e 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -74,6 +74,7 @@ namespace sat { m_local_search_threads = p.local_search_threads(); m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify_bca = p.lookahead_simplify_bca(); + m_lookahead_simplify_asymm_branch = p.lookahead_simplify_asymm_branch(); if (p.lookahead_reward() == symbol("heule_schur")) m_lookahead_reward = heule_schur_reward; else if (p.lookahead_reward() == symbol("heuleu")) diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index da225c26b..c40266c93 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -92,6 +92,7 @@ namespace sat { bool m_local_search; bool m_lookahead_simplify; bool m_lookahead_simplify_bca; + bool m_lookahead_simplify_asymm_branch; cutoff_t m_lookahead_cube_cutoff; double m_lookahead_cube_fraction; unsigned m_lookahead_cube_depth; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 9fc818014..29eaccb8e 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2308,14 +2308,42 @@ namespace sat { elim_eqs elim(m_s); elim(roots, to_elim); + if (get_config().m_lookahead_simplify_asymm_branch) { + big_asymm_branch(); + } if (get_config().m_lookahead_simplify_bca) { add_hyper_binary(); } + } } m_lookahead.reset(); } + /** + \brief extract binary implication graph from learned binary clauses and use it + for strengthening clauses. + */ + + void lookahead::big_asymm_branch() { + unsigned num_lits = m_s.num_vars() * 2; + unsigned idx = 0; + big big; + big.init_adding_edges(m_s.num_vars()); + for (auto const& lits : m_binary) { + literal u = get_parent(to_literal(idx++)); + if (u == null_literal) continue; + for (literal v : lits) { + v = get_parent(v); + if (v != null_literal) + big.add_edge(u, v); + } + } + big.done_adding_edges(); + asymm_branch ab(m_s, m_s.m_params); + ab(big); + } + /** \brief reduction based on binary implication graph */ diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 3ebbfb7a5..75ce4fe6d 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -555,6 +555,8 @@ namespace sat { void add_hyper_binary(); + void big_asymm_branch(); + double psat_heur(); public: diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 672e22512..9d1585e7a 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -49,6 +49,7 @@ def_module_params('sat', ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead_simplify.bca', BOOL, False, 'add learned binary clauses as part of lookahead simplification'), + ('lookahead_simplify.asymm_branch', BOOL, False, 'apply asymmetric branch simplification with lookahead simplifier'), ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'))) From b731d02adc9537477bdf22a2c82c749464bf66ed Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Fri, 15 Dec 2017 13:56:59 -0800 Subject: [PATCH 0405/1283] fixes Signed-off-by: Miguel Angelo Da Terra Neves --- src/ast/ast_translation.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index a57e5d194..51f198929 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -48,14 +48,11 @@ void ast_translation::reset_cache() { void ast_translation::cache(ast * s, ast * t) { SASSERT(!m_cache.contains(s)); if (s->get_ref_count() > 1) { - if (m_insert_count > (1 << 17)) { - reset_cache(); - m_insert_count = 0; - } - m_cache.insert(s, t); - ++m_insert_count; m_from_manager.inc_ref(s); m_to_manager.inc_ref(t); + m_cache.insert(s, t); + ++m_insert_count; + } } @@ -81,8 +78,8 @@ void ast_translation::push_frame(ast * n) { } bool ast_translation::visit(ast * n) { - ast * r; if (n->get_ref_count() > 1) { + ast * r; if (m_cache.find(n, r)) { m_result_stack.push_back(r); ++m_hit_count; From 0f1286adae6d0c8e9f398b614eab605854c7b2cd Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Fri, 15 Dec 2017 14:00:20 -0800 Subject: [PATCH 0406/1283] restored commented out code Signed-off-by: Miguel Angelo Da Terra Neves --- src/sat/sat_asymm_branch.cpp | 6 +++--- src/sat/sat_integrity_checker.cpp | 1 - src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_simplifier.cpp | 2 +- src/sat/sat_solver.cpp | 4 ++-- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 8211c4760..0d0e3a682 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -76,12 +76,12 @@ namespace sat { s.propagate(false); if (s.m_inconsistent) break; - //std::cout << "elim: " << m_elim_literals - elim << "\n"; + std::cout << "elim: " << m_elim_literals - elim << "\n"; if (m_elim_literals == elim) break; } - //std::cout << "elim-literals: " << m_elim_literals - elim0 << "\n"; - //std::cout << "elim-learned-literals: " << m_elim_learned_literals - eliml0 << "\n"; + std::cout << "elim-literals: " << m_elim_literals - elim0 << "\n"; + std::cout << "elim-learned-literals: " << m_elim_learned_literals - eliml0 << "\n"; return m_elim_literals > elim0; } diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index 03cf00e0b..bdc72602d 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -155,7 +155,6 @@ namespace sat { } bool integrity_checker::check_watches(literal l, watch_list const& wlist) const { - return true; // TODO: remove for (watched const& w : wlist) { switch (w.get_kind()) { case watched::BINARY: diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index f3d4a3125..b7694e562 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2390,7 +2390,7 @@ namespace sat { } } } - //std::cout << candidates.size() << " -> " << k << "\n"; + std::cout << candidates.size() << " -> " << k << "\n"; if (k == candidates.size()) break; candidates.shrink(k); if (k == 0) break; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 7010a4536..ce3e5472a 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1360,7 +1360,7 @@ namespace sat { void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); - //VERIFY(!s.is_external(l)); + VERIFY(!s.is_external(l)); if (new_entry == 0) new_entry = &(mc.mk(k, l.var())); m_to_remove.push_back(&c); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a52ab4c8d..b9d4b0132 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1546,8 +1546,8 @@ namespace sat { if (!check_clauses(m_model)) { IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";); - //UNREACHABLE(); // TODO: uncomment - //throw solver_exception("check model failed"); // TODO: uncomment + UNREACHABLE(); + throw solver_exception("check model failed"); } TRACE("sat", for (bool_var v = 0; v < num; v++) tout << v << ": " << m_model[v] << "\n";); From a5b663c52df3d15d5b83987c00587f01b0f453c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Dec 2017 16:09:07 -0800 Subject: [PATCH 0407/1283] add unit walk engine Signed-off-by: Nikolaj Bjorner --- src/sat/CMakeLists.txt | 1 + src/sat/ba_solver.cpp | 2 +- src/sat/ba_solver.h | 25 ++- src/sat/sat_config.cpp | 2 + src/sat/sat_config.h | 2 + src/sat/sat_extension.h | 1 + src/sat/sat_parallel.cpp | 32 +++- src/sat/sat_parallel.h | 3 + src/sat/sat_params.pyg | 2 + src/sat/sat_solver.cpp | 121 ++++++++++--- src/sat/sat_solver.h | 4 +- src/sat/sat_types.h | 1 + src/sat/sat_unit_walk.cpp | 362 ++++++++++++++++++++++++++++++++++++++ src/sat/sat_unit_walk.h | 79 +++++++++ src/sat/sat_watched.cpp | 12 +- src/sat/sat_watched.h | 2 + 16 files changed, 604 insertions(+), 47 deletions(-) create mode 100644 src/sat/sat_unit_walk.cpp create mode 100644 src/sat/sat_unit_walk.h diff --git a/src/sat/CMakeLists.txt b/src/sat/CMakeLists.txt index d7da09826..320a674a2 100644 --- a/src/sat/CMakeLists.txt +++ b/src/sat/CMakeLists.txt @@ -24,6 +24,7 @@ z3_add_component(sat sat_scc.cpp sat_simplifier.cpp sat_solver.cpp + sat_unit_walk.cpp sat_watched.cpp COMPONENT_DEPENDENCIES util diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index edf1c82a2..e5623c05f 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1518,7 +1518,7 @@ namespace sat { return p; } - ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_constraint_id(0) { + ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_unit_walk(0), m_constraint_id(0) { TRACE("ba", tout << this << "\n";); } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index b5ea1e1ad..e7a220f5c 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -24,6 +24,7 @@ Revision History: #include "sat/sat_extension.h" #include "sat/sat_solver.h" #include "sat/sat_lookahead.h" +#include "sat/sat_unit_walk.h" #include "util/scoped_ptr_vector.h" #include "util/lp/lar_solver.h" @@ -204,6 +205,7 @@ namespace sat { solver* m_solver; lookahead* m_lookahead; + unit_walk* m_unit_walk; stats m_stats; small_object_allocator m_allocator; @@ -362,13 +364,25 @@ namespace sat { // access solver inline lbool value(bool_var v) const { return value(literal(v, false)); } inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } - inline unsigned lvl(literal lit) const { return m_lookahead ? 0 : m_solver->lvl(lit); } - inline unsigned lvl(bool_var v) const { return m_lookahead ? 0 : m_solver->lvl(v); } - inline bool inconsistent() const { return m_lookahead ? m_lookahead->inconsistent() : m_solver->inconsistent(); } + inline unsigned lvl(literal lit) const { return m_lookahead || m_unit_walk ? 0 : m_solver->lvl(lit); } + inline unsigned lvl(bool_var v) const { return m_lookahead || m_unit_walk ? 0 : m_solver->lvl(v); } + inline bool inconsistent() const { + if (m_lookahead) return m_lookahead->inconsistent(); + if (m_unit_walk) return m_unit_walk->inconsistent(); + return m_solver->inconsistent(); + } inline watch_list& get_wlist(literal l) { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } - inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); } - inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); } + inline void assign(literal l, justification j) { + if (m_lookahead) m_lookahead->assign(l); + else if (m_unit_walk) m_unit_walk->assign(l); + else m_solver->assign(l, j); + } + inline void set_conflict(justification j, literal l) { + if (m_lookahead) m_lookahead->set_conflict(); + else if (m_unit_walk) m_unit_walk->set_conflict(); + else m_solver->set_conflict(j, l); + } inline config const& get_config() const { return m_lookahead ? m_lookahead->get_config() : m_solver->get_config(); } inline void drat_add(literal_vector const& c, svector const& premises) { if (m_solver) m_solver->m_drat.add(c, premises); } @@ -434,6 +448,7 @@ namespace sat { virtual ~ba_solver(); virtual void set_solver(solver* s) { m_solver = s; } virtual void set_lookahead(lookahead* l) { m_lookahead = l; } + virtual void set_unit_walk(unit_walk* u) { m_unit_walk = u; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); void add_pb_ge(bool_var v, svector const& wlits, unsigned k); void add_xor(bool_var v, literal_vector const& lits); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index cf26fc09e..4cf448394 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -72,6 +72,8 @@ namespace sat { m_num_threads = p.threads(); m_local_search = p.local_search(); m_local_search_threads = p.local_search_threads(); + m_unit_walk = p.unit_walk(); + m_unit_walk_threads = p.unit_walk_threads(); m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify_bca = p.lookahead_simplify_bca(); m_lookahead_simplify_asymm_branch = p.lookahead_simplify_asymm_branch(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index c40266c93..2aa5a325b 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -90,6 +90,8 @@ namespace sat { unsigned m_num_threads; unsigned m_local_search_threads; bool m_local_search; + unsigned m_unit_walk_threads; + bool m_unit_walk; bool m_lookahead_simplify; bool m_lookahead_simplify_bca; bool m_lookahead_simplify_asymm_branch; diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index c2a9197c1..7db5d63ec 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -52,6 +52,7 @@ namespace sat { virtual ~extension() {} virtual void set_solver(solver* s) = 0; virtual void set_lookahead(lookahead* s) = 0; + virtual void set_unit_walk(unit_walk* u) = 0; virtual bool propagate(literal l, ext_constraint_idx idx) = 0; virtual double get_reward(literal l, ext_constraint_idx idx, literal_occs_fun& occs) const = 0; virtual void get_antecedents(literal l, ext_justification_idx idx, literal_vector & r) = 0; diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 7ba1ba7c6..462439499 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -91,7 +91,7 @@ namespace sat { return false; } - parallel::parallel(solver& s): m_scoped_rlimit(s.rlimit()), m_num_clauses(0) {} + parallel::parallel(solver& s): m_scoped_rlimit(s.rlimit()), m_num_clauses(0), m_consumer_ready(false) {} parallel::~parallel() { for (unsigned i = 0; i < m_solvers.size(); ++i) { @@ -230,14 +230,14 @@ namespace sat { } } IF_VERBOSE(1, verbose_stream() << "set phase: " << m_num_clauses << " " << s.m_clauses.size() << " " << m_solver_copy << "\n";); - if (m_num_clauses == 0 || (m_num_clauses > s.m_clauses.size())) { - // time to update local search with new clauses. - // there could be multiple local search engines runing at the same time. - IF_VERBOSE(1, verbose_stream() << "(sat-parallel refresh local search " << m_num_clauses << " -> " << s.m_clauses.size() << ")\n";); - m_solver_copy = alloc(solver, s.m_params, s.rlimit()); - m_solver_copy->copy(s); - m_num_clauses = s.m_clauses.size(); - } + } + if (m_consumer_ready && (m_num_clauses == 0 || (m_num_clauses > s.m_clauses.size()))) { + // time to update local search with new clauses. + // there could be multiple local search engines runing at the same time. + IF_VERBOSE(1, verbose_stream() << "(sat-parallel refresh :from " << m_num_clauses << " :to " << s.m_clauses.size() << ")\n";); + m_solver_copy = alloc(solver, s.m_params, s.rlimit()); + m_solver_copy->copy(s); + m_num_clauses = s.m_clauses.size(); } } @@ -285,6 +285,7 @@ namespace sat { void parallel::set_phase(local_search& s) { #pragma omp critical (par_solver) { + m_consumer_ready = true; m_phase.reserve(s.num_vars(), l_undef); for (unsigned i = 0; i < s.num_vars(); ++i) { m_phase[i] = s.get_phase(i) ? l_true : l_false; @@ -293,6 +294,19 @@ namespace sat { } } + bool parallel::copy_solver(solver& s) { + bool copied = false; + #pragma omp critical (par_solver) + { + m_consumer_ready = true; + if (m_solver_copy && s.m_clauses.size() > m_solver_copy->m_clauses.size()) { + s.copy(*m_solver_copy); + copied = true; + m_num_clauses = s.m_clauses.size(); + } + } + return copied; + } }; diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index f09f07f51..f37c99151 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -65,6 +65,7 @@ namespace sat { svector m_phase; unsigned m_num_clauses; scoped_ptr m_solver_copy; + bool m_consumer_ready; scoped_limits m_scoped_rlimit; vector m_limits; @@ -106,6 +107,8 @@ namespace sat { void set_phase(local_search& s); void get_phase(local_search& s); + + bool copy_solver(solver& s); }; }; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 9d1585e7a..c8d47ddd3 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -38,6 +38,8 @@ def_module_params('sat', ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), + ('unit_walk', BOOL, False, 'use unit-walk search instead of CDCL'), + ('unit_walk_threads', UINT, 0, 'number of unit-walk search threads to find satisfiable solution'), ('lookahead.cube.cutoff', SYMBOL, 'adaptive_freevars', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat'), ('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index b9d4b0132..de75882af 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -20,6 +20,7 @@ Revision History: #include "sat/sat_solver.h" #include "sat/sat_integrity_checker.h" #include "sat/sat_lookahead.h" +#include "sat/sat_unit_walk.h" #include "util/luby.h" #include "util/trace.h" #include "util/max_cliques.h" @@ -69,15 +70,15 @@ namespace sat { m_ext = 0; SASSERT(check_invariant()); TRACE("sat", tout << "Delete clauses\n";); - del_clauses(m_clauses.begin(), m_clauses.end()); + del_clauses(m_clauses); TRACE("sat", tout << "Delete learned\n";); - del_clauses(m_learned.begin(), m_learned.end()); + del_clauses(m_learned); } - void solver::del_clauses(clause * const * begin, clause * const * end) { - for (clause * const * it = begin; it != end; ++it) { - m_cls_allocator.del_clause(*it); - } + void solver::del_clauses(clause_vector& clauses) { + for (clause * cp : clauses) + m_cls_allocator.del_clause(cp); + clauses.reset(); ++m_stats.m_non_learned_generation; } @@ -88,24 +89,46 @@ namespace sat { void solver::copy(solver const & src) { pop_to_base_level(); + del_clauses(m_clauses); + del_clauses(m_learned); + m_watches.reset(); + m_assignment.reset(); + m_justification.reset(); + m_decision.reset(); + m_eliminated.reset(); + m_activity.reset(); + m_level.reset(); + m_mark.reset(); + m_lit_mark.reset(); + m_phase.reset(); + m_prev_phase.reset(); + m_assigned_since_gc.reset(); + m_last_conflict.reset(); + m_last_propagation.reset(); + m_participated.reset(); + m_canceled.reset(); + m_reasoned.reset(); + m_simplifier.reset_todos(); + m_qhead = 0; + m_trail.reset(); + m_scopes.reset(); + // create new vars - if (num_vars() < src.num_vars()) { - for (bool_var v = num_vars(); v < src.num_vars(); v++) { - bool ext = src.m_external[v] != 0; - bool dvar = src.m_decision[v] != 0; - VERIFY(v == mk_var(ext, dvar)); - if (src.was_eliminated(v)) { - m_eliminated[v] = true; - } - m_phase[v] = src.m_phase[v]; - m_prev_phase[v] = src.m_prev_phase[v]; - -#if 1 - // inherit activity: - m_activity[v] = src.m_activity[v]; - m_case_split_queue.activity_changed_eh(v, false); -#endif + for (bool_var v = num_vars(); v < src.num_vars(); v++) { + bool ext = src.m_external[v] != 0; + bool dvar = src.m_decision[v] != 0; + VERIFY(v == mk_var(ext, dvar)); + if (src.was_eliminated(v)) { + m_eliminated[v] = true; } + m_phase[v] = src.m_phase[v]; + m_prev_phase[v] = src.m_prev_phase[v]; + +#if 1 + // inherit activity: + m_activity[v] = src.m_activity[v]; + m_case_split_queue.activity_changed_eh(v, false); +#endif } // @@ -891,7 +914,7 @@ namespace sat { if (m_config.m_local_search) { return do_local_search(num_lits, lits); } - if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0) && !m_par) { + if ((m_config.m_num_threads > 1 || m_config.m_local_search_threads > 0 || m_config.m_unit_walk_threads > 0) && !m_par) { SASSERT(scope_lvl() == 0); return check_par(num_lits, lits); } @@ -909,6 +932,10 @@ namespace sat { propagate(false); if (check_inconsistent()) return l_false; cleanup(); + + if (m_config.m_unit_walk) { + return do_unit_walk(); + } if (m_config.m_gc_burst) { // force gc m_conflicts_since_gc = m_gc_threshold + 1; @@ -988,11 +1015,19 @@ namespace sat { return r; } + lbool solver::do_unit_walk() { + unit_walk srch(*this); + lbool r = srch(); + return r; + } + lbool solver::check_par(unsigned num_lits, literal const* lits) { scoped_ptr_vector ls; - int num_threads = static_cast(m_config.m_num_threads + m_config.m_local_search_threads); + scoped_ptr_vector uw; int num_extra_solvers = m_config.m_num_threads - 1; int num_local_search = static_cast(m_config.m_local_search_threads); + int num_unit_walk = static_cast(m_config.m_unit_walk_threads); + int num_threads = num_extra_solvers + 1 + num_local_search + num_unit_walk; for (int i = 0; i < num_local_search; ++i) { local_search* l = alloc(local_search); l->config().set_seed(m_config.m_random_seed + i); @@ -1000,9 +1035,23 @@ namespace sat { ls.push_back(l); } + // set up unit walk + vector lims(num_unit_walk); + for (int i = 0; i < num_unit_walk; ++i) { + solver* s = alloc(solver, m_params, lims[i]); + s->copy(*this); + s->m_config.m_unit_walk = true; + uw.push_back(s); + } + + int local_search_offset = num_extra_solvers; + int unit_walk_offset = num_extra_solvers + num_local_search; + int main_solver_offset = unit_walk_offset + num_unit_walk; + #define IS_AUX_SOLVER(i) (0 <= i && i < num_extra_solvers) -#define IS_LOCAL_SEARCH(i) (num_extra_solvers <= i && i + 1 < num_threads) -#define IS_MAIN_SOLVER(i) (i + 1 == num_threads) +#define IS_LOCAL_SEARCH(i) (local_search_offset <= i && i < unit_walk_offset) +#define IS_UNIT_WALK(i) (unit_walk_offset <= i && i < main_solver_offset) +#define IS_MAIN_SOLVER(i) (i == main_solver_offset) sat::parallel par(*this); par.reserve(num_threads, 1 << 12); @@ -1010,6 +1059,12 @@ namespace sat { for (unsigned i = 0; i < ls.size(); ++i) { par.push_child(ls[i]->rlimit()); } + for (reslimit& rl : lims) { + par.push_child(rl); + } + for (unsigned i = 0; i < uw.size(); ++i) { + uw[i]->set_par(&par, 0); + } int finished_id = -1; std::string ex_msg; par_exception_kind ex_kind = DEFAULT_EX; @@ -1024,7 +1079,10 @@ namespace sat { r = par.get_solver(i).check(num_lits, lits); } else if (IS_LOCAL_SEARCH(i)) { - r = ls[i-num_extra_solvers]->check(num_lits, lits, &par); + r = ls[i-local_search_offset]->check(num_lits, lits); + } + else if (IS_UNIT_WALK(i)) { + r = uw[i-unit_walk_offset]->check(num_lits, lits); } else { r = check(num_lits, lits); @@ -1042,6 +1100,9 @@ namespace sat { for (unsigned j = 0; j < ls.size(); ++j) { ls[j]->rlimit().cancel(); } + for (auto& rl : lims) { + rl.cancel(); + } for (int j = 0; j < num_extra_solvers; ++j) { if (i != j) { par.cancel_solver(j); @@ -1076,13 +1137,17 @@ namespace sat { m_core.append(par.get_solver(finished_id).get_core()); } if (result == l_true && IS_LOCAL_SEARCH(finished_id)) { - set_model(ls[finished_id - num_extra_solvers]->get_model()); + set_model(ls[finished_id - local_search_offset]->get_model()); + } + if (result == l_true && IS_UNIT_WALK(finished_id)) { + set_model(uw[finished_id - unit_walk_offset]->get_model()); } if (!canceled) { rlimit().reset_cancel(); } set_par(0, 0); ls.reset(); + uw.reset(); if (finished_id == -1) { switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index bac9c4bb3..56d1ace39 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -163,7 +163,7 @@ namespace sat { statistics m_aux_stats; - void del_clauses(clause * const * begin, clause * const * end); + void del_clauses(clause_vector& clauses); friend class integrity_checker; friend class cleaner; @@ -180,6 +180,7 @@ namespace sat { friend class parallel; friend class lookahead; friend class local_search; + friend class unit_walk; friend struct mk_stat; friend class elim_vars; friend class scoped_detach; @@ -398,6 +399,7 @@ namespace sat { void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); lbool do_local_search(unsigned num_lits, literal const* lits); + lbool do_unit_walk(); // ----------------------- // diff --git a/src/sat/sat_types.h b/src/sat/sat_types.h index 5eded92ec..002e49006 100644 --- a/src/sat/sat_types.h +++ b/src/sat/sat_types.h @@ -125,6 +125,7 @@ namespace sat { class solver; class lookahead; + class unit_walk; class clause; class clause_wrapper; class integrity_checker; diff --git a/src/sat/sat_unit_walk.cpp b/src/sat/sat_unit_walk.cpp new file mode 100644 index 000000000..7d556c740 --- /dev/null +++ b/src/sat/sat_unit_walk.cpp @@ -0,0 +1,362 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_unit_walk.cpp + +Abstract: + + unit walk local search procedure. + A variant of UnitWalk. Hirsch and Kojevinkov, SAT 2001. + This version uses a trail to reset assignments and integrates directly with the + watch list structure. Thus, assignments are not delayed and we avoid treating + pending units as a multi-set. + + It uses standard DPLL approach for backracking, flipping the last decision literal that + lead to a conflict. It restarts after evern 100 conflicts. + + It does not attempt to add conflict clauses or alternate with + walksat. + + It can receive conflict clauses from a concurrent CDCL solver and does not + create its own conflict clauses. + + The phase of variables is optionally sticky between rounds. We use a decay rate + to compute stickiness of a variable. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-12-15. + +Revision History: + +--*/ + +#include "sat_unit_walk.h" + +namespace sat { + + unit_walk::unit_walk(solver& s): + s(s) + { + m_runs = 0; + m_periods = 0; + m_max_runs = UINT_MAX; + m_max_periods = 100; // 5000; // UINT_MAX; // TBD configure + m_max_conflicts = 100; + m_sticky_phase = true; + m_flips = 0; + } + + class scoped_set_unit_walk { + solver& s; + public: + scoped_set_unit_walk(unit_walk* u, solver& s): s(s) { + if (s.get_extension()) s.get_extension()->set_unit_walk(u); + } + ~scoped_set_unit_walk() { + if (s.get_extension()) s.get_extension()->set_unit_walk(nullptr); + } + }; + + lbool unit_walk::operator()() { + scoped_set_unit_walk _scoped_set(this, s); + init_runs(); + for (m_runs = 0; m_runs < m_max_runs || m_max_runs == UINT_MAX; ++m_runs) { + init_propagation(); + init_phase(); + for (m_periods = 0; m_periods < m_max_periods || m_max_periods == UINT_MAX; ++m_periods) { + if (!s.rlimit().inc()) return l_undef; + lbool r = unit_propagation(); + if (r != l_undef) return r; + } + } + return l_undef; + } + + lbool unit_walk::unit_propagation() { + init_propagation(); + while (!m_freevars.empty() && !inconsistent()) { + bool_var v = m_freevars.begin()[m_rand(m_freevars.size())]; + literal lit(v, !m_phase[v]); + ++s.m_stats.m_decision; + m_decisions.push_back(lit); + assign(lit); + propagate(); + while (inconsistent() && !m_decisions.empty()) { + ++m_conflicts; + backtrack(); + propagate(); + } + if (m_conflicts >= m_max_conflicts && !m_freevars.empty()) { + set_conflict(); + break; + } + } + if (!inconsistent()) { + log_status(); + IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk sat)\n";); + s.mk_model(); + return l_true; + } + return l_undef; + } + + void unit_walk::init_runs() { + m_freevars.reset(); + m_trail.reset(); + m_decisions.reset(); + m_phase.resize(s.num_vars()); + double2 d2; + d2.t = 1.0; + d2.f = 1.0; + m_phase_tf.resize(s.num_vars(), d2); + for (unsigned i = 0; i < s.num_vars(); ++i) { + literal l(i, false); + if (!s.was_eliminated(l.var()) && s.m_assignment[l.index()] == l_undef) + m_freevars.insert(l.var()); + } + IF_VERBOSE(1, verbose_stream() << "num vars: " << s.num_vars() << " free vars: " << m_freevars.size() << "\n";); + } + + void unit_walk::init_phase() { + m_max_trail = 0; + if (m_sticky_phase) { + for (bool_var v : m_freevars) { + m_phase[v] = m_rand(100 * static_cast(m_phase_tf[v].t + m_phase_tf[v].f)) <= 100 * m_phase_tf[v].t; + } + } + else { + for (bool_var v : m_freevars) + m_phase[v] = (m_rand(2) == 0); + } + } + + void unit_walk::init_propagation() { + if (s.m_par && s.m_par->copy_solver(s)) { + IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk fresh copy)\n";); + if (s.get_extension()) s.get_extension()->set_unit_walk(this); + init_runs(); + init_phase(); + } + if (m_max_trail == 0 || m_trail.size() > m_max_trail) { + m_max_trail = m_trail.size(); + log_status(); + } + for (literal lit : m_trail) { + s.m_assignment[lit.index()] = l_undef; + s.m_assignment[(~lit).index()] = l_undef; + m_freevars.insert(lit.var()); + } + m_flips = 0; + m_trail.reset(); + m_conflicts = 0; + m_decisions.reset(); + m_qhead = 0; + m_inconsistent = false; + } + + void unit_walk::propagate() { + while (m_qhead < m_trail.size() && !inconsistent()) + propagate(choose_literal()); + // IF_VERBOSE(1, verbose_stream() << m_trail.size() << " " << inconsistent() << "\n";); + } + + void unit_walk::propagate(literal l) { + ++s.m_stats.m_propagate; + literal not_l = ~l; + literal l1, l2; + lbool val1, val2; + bool keep; + watch_list & wlist = s.get_wlist(l); + watch_list::iterator it = wlist.begin(); + watch_list::iterator it2 = it; + watch_list::iterator end = wlist.end(); + for (; it != end; ++it) { + switch (it->get_kind()) { + case watched::BINARY: + l1 = it->get_literal(); + switch (value(l1)) { + case l_false: + conflict_cleanup(it, it2, wlist); + set_conflict(l,l1); + return; + case l_undef: + assign(l1); + break; + case l_true: + break; // skip + } + *it2 = *it; + it2++; + break; + case watched::TERNARY: + l1 = it->get_literal1(); + l2 = it->get_literal2(); + val1 = value(l1); + val2 = value(l2); + if (val1 == l_false && val2 == l_undef) { + assign(l2); + } + else if (val1 == l_undef && val2 == l_false) { + assign(l1); + } + else if (val1 == l_false && val2 == l_false) { + conflict_cleanup(it, it2, wlist); + set_conflict(l,l1,l2); + return; + } + *it2 = *it; + it2++; + break; + case watched::CLAUSE: { + if (value(it->get_blocked_literal()) == l_true) { + *it2 = *it; + it2++; + break; + } + clause_offset cls_off = it->get_clause_offset(); + clause & c = s.get_clause(cls_off); + if (c[0] == not_l) + std::swap(c[0], c[1]); + if (c[1] != not_l) { + *it2 = *it; + it2++; + break; + } + if (value(c[0]) == l_true) { + it2->set_clause(c[0], cls_off); + it2++; + break; + } + SASSERT(c[1] == not_l); + literal * l_it = c.begin() + 2; + literal * l_end = c.end(); + for (; l_it != l_end; ++l_it) { + if (value(*l_it) != l_false) { + c[1] = *l_it; + *l_it = not_l; + s.get_wlist((~c[1]).index()).push_back(watched(c[0], cls_off)); + goto end_clause_case; + } + } + SASSERT(value(c[0]) == l_false || value(c[0]) == l_undef); + if (value(c[0]) == l_false) { + c.mark_used(); + conflict_cleanup(it, it2, wlist); + set_conflict(c); + return; + } + else { + *it2 = *it; + it2++; + assign(c[0]); + } + end_clause_case: + break; + } + case watched::EXT_CONSTRAINT: + SASSERT(s.get_extension()); + keep = s.get_extension()->propagate(l, it->get_ext_constraint_idx()); + if (inconsistent()) { + if (!keep) { + ++it; + } + set_conflict(l, l); + conflict_cleanup(it, it2, wlist); + return; + } + if (keep) { + *it2 = *it; + it2++; + } + break; + default: + UNREACHABLE(); + break; + } + } + wlist.set_end(it2); + } + + void unit_walk::assign(literal lit) { + SASSERT(value(lit) == l_undef); + s.m_assignment[lit.index()] = l_true; + s.m_assignment[(~lit).index()] = l_false; + m_trail.push_back(lit); + m_freevars.remove(lit.var()); + if (s.get_extension() && s.is_external(lit.var())) { + s.get_extension()->asserted(lit); + } + if (m_phase[lit.var()] == lit.sign()) { + ++m_flips; + flip_phase(lit); + } + } + + void unit_walk::flip_phase(literal l) { + bool_var v = l.var(); + m_phase[v] = !m_phase[v]; + if (m_sticky_phase) { + m_phase_tf[v].f *= 0.98; + m_phase_tf[v].t *= 0.98; + if (m_phase[v]) m_phase_tf[v].t += 1; else m_phase_tf[v].f += 1; + } + } + + void unit_walk::log_status() { + IF_VERBOSE(1, verbose_stream() << "(sat-unit-walk :trail " << m_max_trail + << " :branches " << m_decisions.size() + << " :free " << m_freevars.size() + << " :periods " << m_periods + << " :decisions " << s.m_stats.m_decision + << " :propagations " << s.m_stats.m_propagate + << ")\n";); + } + + literal unit_walk::choose_literal() { + SASSERT(m_qhead < m_trail.size()); + unsigned idx = m_rand(m_trail.size() - m_qhead); + std::swap(m_trail[m_qhead], m_trail[m_qhead + idx]); + literal lit = m_trail[m_qhead++]; + return lit; + } + + void unit_walk::set_conflict(literal l1, literal l2) { + set_conflict(); + } + + void unit_walk::set_conflict(literal l1, literal l2, literal l3) { + set_conflict(); + } + + void unit_walk::set_conflict(clause const& c) { + set_conflict(); + } + + void unit_walk::set_conflict() { + m_inconsistent = true; + } + + void unit_walk::backtrack() { + if (m_decisions.empty()) return; + literal dlit = m_decisions.back(); + literal lit; + do { + SASSERT(!m_trail.empty()); + lit = m_trail.back(); + s.m_assignment[lit.index()] = l_undef; + s.m_assignment[(~lit).index()] = l_undef; + m_freevars.insert(lit.var()); + m_trail.pop_back(); + } + while (lit != dlit); + m_inconsistent = false; + m_decisions.pop_back(); + m_qhead = m_trail.size(); + assign(~dlit); + } + +}; + diff --git a/src/sat/sat_unit_walk.h b/src/sat/sat_unit_walk.h new file mode 100644 index 000000000..8ab9bab70 --- /dev/null +++ b/src/sat/sat_unit_walk.h @@ -0,0 +1,79 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + sat_unit_walk.h + +Abstract: + + unit walk local search procedure. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-12-15. + +Revision History: + +--*/ +#ifndef SAT_UNIT_WALK_H_ +#define SAT_UNIT_WALK_H_ + +#include "sat/sat_solver.h" + +namespace sat { + + class unit_walk { + struct double2 { + double t, f; + }; + solver& s; + random_gen m_rand; + svector m_phase; + svector m_phase_tf; + indexed_uint_set m_freevars; + unsigned m_runs; + unsigned m_periods; + + // settings + unsigned m_max_runs; + unsigned m_max_periods; + unsigned m_max_conflicts; + bool m_sticky_phase; + + unsigned m_propagations; + unsigned m_flips; + unsigned m_max_trail; + unsigned m_qhead; + literal_vector m_trail; + bool m_inconsistent; + literal_vector m_decisions; + unsigned m_conflicts; + + void push(); + void backtrack(); + void init_runs(); + void init_phase(); + void init_propagation(); + void flip_phase(literal l); + lbool unit_propagation(); + void propagate(); + void propagate(literal lit); + literal choose_literal(); + void set_conflict(literal l1, literal l2); + void set_conflict(literal l1, literal l2, literal l3); + void set_conflict(clause const& c); + inline lbool value(literal lit) { return s.value(lit); } + void log_status(); + public: + + unit_walk(solver& s); + lbool operator()(); + std::ostream& display(std::ostream& out) const; + bool inconsistent() const { return m_inconsistent; } + void set_conflict(); + void assign(literal lit); + }; +}; + +#endif diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index 369e95034..1a0880282 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -27,11 +27,10 @@ namespace sat { for (; it != end; ++it) { if (it->is_clause() && it->get_clause_offset() == c) { watch_list::iterator it2 = it; - ++it; - for (; it != end; ++it) { + ++it; + for (; it != end; ++it, ++it2) { SASSERT(!((it->is_clause() && it->get_clause_offset() == c))); *it2 = *it; - ++it2; } wlist.set_end(it2); return true; @@ -71,6 +70,13 @@ namespace sat { VERIFY(found); } + void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist) { + watch_list::iterator end = wlist.end(); + for (; it != end; ++it, ++it2) + *it2 = *it; + wlist.set_end(it2); + } + std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist) { bool first = true; diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 305948251..e66197878 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -139,6 +139,8 @@ namespace sat { class clause_allocator; std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist); + + void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist); }; #endif From b0aaa4c6d7a739eb5e8e56a73e0486df46483222 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 14:18:30 +0000 Subject: [PATCH 0408/1283] Updated release notes --- RELEASE_NOTES | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index e85e3d8d6..4f10cad26 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -2,6 +2,7 @@ RELEASE NOTES Version 4.6.0 ============= + - New requirements: - C++11 capable compiler to build Z3. - C++ API now requires C++11 or newer. @@ -14,6 +15,10 @@ Version 4.6.0 issuing the command (get-objectives). Pareto front objectives are accessed by issuing multiple (check-sat) calls until it returns unsat. +- Removed features: + - Removed support for SMT-LIB 1.x + + Version 4.5.0 ============= @@ -49,10 +54,9 @@ Version 4.5.0 over compound formulas, introduce a fresh predicate whose arguments are the relevant free variables in the formula and add a rule that uses the fresh predicate in the head and formula in the body. - - minimization of unsat cores is avaialble as an option for the SAT and SMT cores. + - Minimization of unsat cores is available as an option for the SAT and SMT cores. By setting smt.core.minimize=true resp. sat.core.minimize=true - cores produced by these modules are minimized. - + cores produced by these modules are minimized. - A multitude of bugs has been fixed. From 63951b815dec78bf4b49e9e39a1fef8b5e739939 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 18:58:21 +0000 Subject: [PATCH 0409/1283] Bumped version number. --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 871852c04..0be2de537 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 6) -set(Z3_VERSION_PATCH 0) +set(Z3_VERSION_PATCH 1) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 60b3b7756..8f75e97ed 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 6, 0, 0) + set_version(4, 6, 1, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') From c199344bbf443fe0ce880b0f24a1f11e56249455 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 11:12:27 -0800 Subject: [PATCH 0410/1283] fix sat model converter to work with incrementality Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 2 +- src/sat/sat_model_converter.cpp | 5 + src/sat/sat_model_converter.h | 6 +- src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 9 +- src/sat/tactic/goal2sat.cpp | 336 ++++++++++++-------------- src/sat/tactic/goal2sat.h | 37 ++- src/sat/tactic/sat_tactic.cpp | 2 +- 8 files changed, 198 insertions(+), 200 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 48ce6d22d..97fa23a79 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -171,7 +171,7 @@ extern "C" { sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); parse_dimacs(is, solver); sat2goal s2g; - model_converter_ref mc; + ref mc; atom2bool_var a2b(m); goal g(m); s2g(solver, a2b, to_solver_ref(s)->get_params(), g, mc); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index fac4cface..cc6614621 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -324,6 +324,11 @@ namespace sat { m_entries.append(src.m_entries); } + void model_converter::flush(model_converter & src) { + m_entries.append(src.m_entries); + src.m_entries.reset(); + } + void model_converter::collect_vars(bool_var_set & s) const { for (entry const & e : m_entries) s.insert(e.m_var); } diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index 28f23c063..88fdfe5b7 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -113,8 +113,12 @@ namespace sat { bool check_invariant(unsigned num_vars) const; void display(std::ostream & out) const; bool check_model(model const & m) const; - void copy(model_converter const & src); + + /* + \brief Append entries from src, then remove entries in src. + */ + void flush(model_converter& src); void collect_vars(bool_var_set & s) const; unsigned max_var(unsigned min) const; /* diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 56d1ace39..bbeb87f83 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -351,6 +351,7 @@ namespace sat { bool model_is_current() const { return m_model_is_current; } literal_vector const& get_core() const { return m_core; } model_converter const & get_model_converter() const { return m_mc; } + void flush(model_converter& mc) { mc.flush(m_mc); } void set_model(model const& mdl); char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } bool check_clauses(model const& m) const; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index d731c246c..39b58e3a5 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -61,7 +61,7 @@ class inc_sat_solver : public solver { proof_converter_ref m_pc; model_converter_ref m_mc; model_converter_ref m_mc0; - model_converter_ref m_sat_mc; + ref m_sat_mc; mutable model_converter_ref m_cached_mc; svector m_weights; std::string m_unknown; @@ -120,7 +120,7 @@ public: for (expr* f : m_internalized_fmls) result->m_internalized_fmls.push_back(tr(f)); if (m_mc) result->m_mc = m_mc->translate(tr); if (m_mc0) result->m_mc0 = m_mc0->translate(tr); - //if (m_sat_mc) result->m_sat_mc = m_sat_mc->translate(tr); MN: commenting this line removes bloat + if (m_sat_mc) result->m_sat_mc = dynamic_cast(m_sat_mc->translate(tr)); // copy m_bb_rewriter? result->m_internalized_converted = m_internalized_converted; return result; @@ -531,6 +531,11 @@ private: m_pc = g->pc(); m_mc = g->mc(); TRACE("sat", g->display_with_dependencies(tout);); + + // ensure that if goal is already internalized, then import mc from m_solver. + if (!m_sat_mc) m_sat_mc = alloc(sat2goal::mc, m); + m_sat_mc->flush_smc(m_solver); + m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, is_incremental(), is_lemma); m_goal2sat.get_interpreted_atoms(atoms); if (!atoms.empty()) { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 3e2abf8e8..bcfb06356 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -878,173 +878,135 @@ void goal2sat::get_interpreted_atoms(expr_ref_vector& atoms) { } +sat2goal::mc::mc(ast_manager& m): m(m), m_var2expr(m) {} + +void sat2goal::mc::flush_smc(sat::solver& s) { + s.flush(m_smc); +} + +void sat2goal::mc::flush_gmc() { + sat::literal_vector updates; + m_smc.expand(updates); + m_smc.reset(); + if (!m_gmc) m_gmc = alloc(generic_model_converter, m); + // now gmc owns the model converter + sat::literal_vector clause; + expr_ref_vector tail(m); + expr_ref def(m); + for (sat::literal l : updates) { + if (l == sat::null_literal) { + sat::literal lit0 = clause[0]; + for (unsigned i = 1; i < clause.size(); ++i) { + tail.push_back(lit2expr(~clause[i])); + } + def = m.mk_or(lit2expr(lit0), mk_and(tail)); + if (lit0.sign()) { + lit0.neg(); + def = m.mk_not(def); + } + m_gmc->add(lit2expr(lit0), def); + clause.reset(); + tail.reset(); + } + else { + clause.push_back(l); + } + } +} + +model_converter* sat2goal::mc::translate(ast_translation& translator) { + mc* result = alloc(mc, m); + result->m_smc.copy(m_smc); + result->m_gmc = m_gmc ? dynamic_cast(m_gmc->translate(translator)) : nullptr; + for (app* e : m_var2expr) { + result->m_var2expr.push_back(translator(e)); + } + return result; +} + +void sat2goal::mc::collect(ast_pp_util& visitor) { + flush_gmc(); + collect(visitor); +} + +void sat2goal::mc::display(std::ostream& out) { + flush_gmc(); + if (m_gmc) m_gmc->display(out); +} + +void sat2goal::mc::operator()(model_ref & md) { + model_evaluator ev(*md); + ev.set_model_completion(false); + + // create a SAT model using md + sat::model sat_md; + expr_ref val(m); + for (expr * atom : m_var2expr) { + if (!atom) { + sat_md.push_back(l_undef); + continue; + } + ev(atom, val); + if (m.is_true(val)) + sat_md.push_back(l_true); + else if (m.is_false(val)) + sat_md.push_back(l_false); + else + sat_md.push_back(l_undef); + } + + // apply SAT model converter + m_smc(sat_md); + + // register value of non-auxiliary boolean variables back into md + unsigned sz = m_var2expr.size(); + for (sat::bool_var v = 0; v < sz; v++) { + app * atom = m_var2expr.get(v); + if (atom && is_uninterp_const(atom)) { + func_decl * d = atom->get_decl(); + lbool new_val = sat_md[v]; + if (new_val == l_true) + md->register_decl(d, m.mk_true()); + else if (new_val == l_false) + md->register_decl(d, m.mk_false()); + } + } + // apply externalized model converter + if (m_gmc) (*m_gmc)(md); + TRACE("sat_mc", tout << "after sat_mc\n"; model_v2_pp(tout, *md);); +} + + +void sat2goal::mc::operator()(expr_ref& fml) { + flush_gmc(); + if (m_gmc) (*m_gmc)(fml); +} + +void sat2goal::mc::insert(sat::bool_var v, app * atom, bool aux) { + VERIFY(!m_var2expr.get(v, nullptr)); + m_var2expr.reserve(v + 1); + m_var2expr.set(v, atom); + if (aux) { + SASSERT(is_uninterp_const(atom)); + SASSERT(m.is_bool(atom)); + if (!m_gmc) m_gmc = alloc(generic_model_converter, m); + m_gmc->hide(atom->get_decl()); + } +} + +expr_ref sat2goal::mc::lit2expr(sat::literal l) { + VERIFY(m_var2expr.get(l.var())); + expr_ref result(m_var2expr.get(l.var()), m); + if (l.sign()) { + result = m.mk_not(result); + } + return result; +} + + struct sat2goal::imp { - // Wrapper for sat::model_converter: converts it into an "AST level" model_converter. - class sat_model_converter : public model_converter { - model_converter_ref m_cached_mc; - sat::model_converter m_mc; - expr_ref_vector m_var2expr; - generic_model_converter_ref m_fmc; // filter for eliminating fresh variables introduced in the assertion-set --> sat conversion - generic_model_converter_ref m_imc; // used to ensure correctness in incremental calls with simplifications that require model conversions - - sat_model_converter(ast_manager & m): - m_var2expr(m) { - } - - void ensure_imc() { - if (m_imc) return; - m_imc = alloc(generic_model_converter, m()); - sat::literal_vector updates; - m_mc.expand(updates); - sat::literal_vector clause; - expr_ref_vector tail(m()); - expr_ref def(m()); - for (sat::literal l : updates) { - if (l == sat::null_literal) { - sat::literal lit0 = clause[0]; - for (unsigned i = 1; i < clause.size(); ++i) { - tail.push_back(lit2expr(~clause[i])); - } - def = m().mk_or(lit2expr(lit0), mk_and(tail)); - if (lit0.sign()) { - lit0.neg(); - def = m().mk_not(def); - } - m_imc->add(lit2expr(lit0), def); - clause.reset(); - tail.reset(); - } - else { - clause.push_back(l); - } - } - } - - public: - sat_model_converter(ast_manager & m, sat::solver const & s):m_var2expr(m) { - m_mc.copy(s.get_model_converter()); - m_fmc = alloc(generic_model_converter, m); - m_imc = nullptr; - } - - ast_manager & m() { return m_var2expr.get_manager(); } - - void init(unsigned num_vars) { - m_var2expr.resize(num_vars); - } - - void insert(unsigned v, expr * atom, bool aux) { - VERIFY(!m_var2expr.get(v)); - m_var2expr[v] = atom; - if (aux) { - SASSERT(is_uninterp_const(atom)); - SASSERT(m().is_bool(atom)); - m_fmc->hide(to_app(atom)->get_decl()); - } - } - - void finish() { - sat::literal_vector updates; - m_mc.expand(updates); - for (sat::literal l : updates) { - if (l != sat::null_literal && !m_var2expr.get(l.var())) { - insert(l.var(), m().mk_fresh_const(0, m().mk_bool_sort()), true); - } - } - m_imc = nullptr; - } - - virtual void operator()(model_ref & md) { - TRACE("sat_mc", tout << "before sat_mc\n"; model_v2_pp(tout, *md); display(tout);); - // REMARK: potential problem - // model_evaluator can't evaluate quantifiers. Then, - // an eliminated variable that depends on a quantified expression can't be recovered. - // A similar problem also affects any model_converter that uses elim_var_model_converter. - // - // Possible solution: - // model_converters reject any variable elimination that depends on a quantified expression. - - model_evaluator ev(*md); - ev.set_model_completion(false); - - // create a SAT model using md - sat::model sat_md; - expr_ref val(m()); - for (expr * atom : m_var2expr) { - if (!atom) { - sat_md.push_back(l_undef); - continue; - } - ev(atom, val); - if (m().is_true(val)) - sat_md.push_back(l_true); - else if (m().is_false(val)) - sat_md.push_back(l_false); - else - sat_md.push_back(l_undef); - } - - // apply SAT model converter - m_mc(sat_md); - - // register value of non-auxiliary boolean variables back into md - unsigned sz = m_var2expr.size(); - for (sat::bool_var v = 0; v < sz; v++) { - expr * atom = m_var2expr.get(v); - if (atom && is_uninterp_const(atom)) { - func_decl * d = to_app(atom)->get_decl(); - lbool new_val = sat_md[v]; - if (new_val == l_true) - md->register_decl(d, m().mk_true()); - else if (new_val == l_false) - md->register_decl(d, m().mk_false()); - } - } - - // apply filter model converter - (*m_fmc)(md); - TRACE("sat_mc", tout << "after sat_mc\n"; model_v2_pp(tout, *md);); - } - - virtual model_converter * translate(ast_translation & translator) { - sat_model_converter * res = alloc(sat_model_converter, translator.to()); - res->m_mc = m_mc; - res->m_fmc = static_cast(m_fmc->translate(translator)); - for (expr* e : m_var2expr) - res->m_var2expr.push_back(e ? translator(e) : nullptr); - return res; - } - - expr_ref lit2expr(sat::literal l) { - VERIFY(m_var2expr.get(l.var())); - expr_ref result(m_var2expr.get(l.var()), m()); - if (l.sign()) { - result = m().mk_not(result); - } - return result; - } - - void display(std::ostream & out) { - ensure_imc(); - m_imc->display(out); - m_fmc->display(out); - } - - virtual void collect(ast_pp_util& visitor) { - m_env = &visitor.env(); - for (expr* e : m_var2expr) if (e) visitor.coll.visit(e); - if (m_fmc) m_fmc->collect(visitor); - ensure_imc(); - m_imc->collect(visitor); - } - - void operator()(expr_ref& formula) override { - ensure_imc(); - (*m_imc)(formula); - } - }; - + typedef mc sat_model_converter; typedef ref sat_model_converter_ref; ast_manager & m; @@ -1073,12 +1035,11 @@ struct sat2goal::imp { m_lit2expr.resize(num_vars * 2); map.mk_inv(m_lit2expr); if (mc) { - mc->init(num_vars); for (sat::bool_var v = 0; v < num_vars; v++) { - checkpoint(); + checkpoint(); sat::literal l(v, false); if (m_lit2expr.get(l.index())) { - mc->insert(v, m_lit2expr.get(l.index()), false); + mc->insert(v, to_app(m_lit2expr.get(l.index())), false); SASSERT(m_lit2expr.get((~l).index())); } } @@ -1088,9 +1049,12 @@ struct sat2goal::imp { expr * lit2expr(sat_model_converter_ref& mc, sat::literal l) { if (!m_lit2expr.get(l.index())) { SASSERT(m_lit2expr.get((~l).index()) == 0); - app * aux = m.mk_fresh_const(0, m.mk_bool_sort()); - if (mc) - mc->insert(l.var(), aux, true); + app* aux = mc ? mc->var2expr(l.var()) : nullptr; + if (!aux) { + aux = m.mk_fresh_const(0, m.mk_bool_sort()); + if (mc) + mc->insert(l.var(), aux, true); + } m_lit2expr.set(l.index(), aux); m_lit2expr.set((~l).index(), m.mk_not(aux)); } @@ -1160,27 +1124,26 @@ struct sat2goal::imp { return dynamic_cast(s.get_extension()); } - void operator()(sat::solver const & s, atom2bool_var const & map, goal & r, model_converter_ref & mc) { + void operator()(sat::solver & s, atom2bool_var const & map, goal & r, ref & mc) { if (s.inconsistent()) { r.assert_expr(m.mk_false()); return; } - ref _mc; - if (r.models_enabled()) { - _mc = alloc(sat_model_converter, m, s); - mc = _mc.get(); + if (r.models_enabled() && !mc) { + mc = alloc(sat_model_converter, m); } - init_lit2expr(s, map, _mc); + if (mc) mc->flush_smc(s); + init_lit2expr(s, map, mc); // collect units unsigned num_vars = s.num_vars(); for (sat::bool_var v = 0; v < num_vars; v++) { checkpoint(); switch (s.value(v)) { case l_true: - r.assert_expr(lit2expr(_mc, sat::literal(v, false))); + r.assert_expr(lit2expr(mc, sat::literal(v, false))); break; case l_false: - r.assert_expr(lit2expr(_mc, sat::literal(v, true))); + r.assert_expr(lit2expr(mc, sat::literal(v, true))); break; case l_undef: break; @@ -1191,28 +1154,27 @@ struct sat2goal::imp { s.collect_bin_clauses(bin_clauses, m_learned); for (sat::solver::bin_clause const& bc : bin_clauses) { checkpoint(); - r.assert_expr(m.mk_or(lit2expr(_mc, bc.first), lit2expr(_mc, bc.second))); + r.assert_expr(m.mk_or(lit2expr(mc, bc.first), lit2expr(mc, bc.second))); } // collect clauses - assert_clauses(_mc, s, s.clauses(), r, true); + assert_clauses(mc, s, s.clauses(), r, true); sat::ba_solver* ext = get_ba_solver(s); if (ext) { for (auto* c : ext->constraints()) { switch (c->tag()) { case sat::ba_solver::card_t: - assert_card(_mc, r, c->to_card()); + assert_card(mc, r, c->to_card()); break; case sat::ba_solver::pb_t: - assert_pb(_mc, r, c->to_pb()); + assert_pb(mc, r, c->to_pb()); break; case sat::ba_solver::xor_t: - assert_xor(_mc, r, c->to_xor()); + assert_xor(mc, r, c->to_xor()); break; } } } - if (_mc) _mc->finish(); } void add_clause(sat_model_converter_ref& mc, sat::literal_vector const& lits, expr_ref_vector& lemmas) { @@ -1255,8 +1217,8 @@ struct sat2goal::scoped_set_imp { } }; -void sat2goal::operator()(sat::solver const & t, atom2bool_var const & m, params_ref const & p, - goal & g, model_converter_ref & mc) { +void sat2goal::operator()(sat::solver & t, atom2bool_var const & m, params_ref const & p, + goal & g, ref & mc) { imp proc(g.m(), p); scoped_set_imp set(this, &proc); proc(t, m, g, mc); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 9d2f310fc..43ee5a835 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -32,6 +32,7 @@ Notes: #include "tactic/goal.h" #include "sat/sat_solver.h" #include "tactic/model_converter.h" +#include "tactic/generic_model_converter.h" #include "sat/tactic/atom2bool_var.h" class goal2sat { @@ -73,8 +74,35 @@ class sat2goal { imp * m_imp; struct scoped_set_imp; public: + + class mc : public model_converter { + ast_manager& m; + sat::model_converter m_smc; + generic_model_converter_ref m_gmc; + app_ref_vector m_var2expr; + + // flushes from m_smc to m_gmc; + void flush_gmc(); + + public: + mc(ast_manager& m); + virtual ~mc() {} + // flush model converter from SAT solver to this structure. + void flush_smc(sat::solver& s); + void operator()(model_ref& md) override; + void operator()(expr_ref& fml) override; + model_converter* translate(ast_translation& translator) override; + void collect(ast_pp_util& visitor) override; + void display(std::ostream& out) override; + + app* var2expr(sat::bool_var v) const { return m_var2expr.get(v, nullptr); } + expr_ref lit2expr(sat::literal l); + void insert(sat::bool_var v, app * atom, bool aux); + }; + sat2goal(); + static void collect_param_descrs(param_descrs & r); /** @@ -85,14 +113,7 @@ public: \warning conversion throws a tactic_exception, if it is interrupted (by set_cancel), or memory consumption limit is reached (set with param :max-memory). */ - void operator()(sat::solver const & t, atom2bool_var const & m, params_ref const & p, goal & s, model_converter_ref & mc); - - - /** - \brief extract learned clauses only that are in the domain of m. - - */ - void get_learned(sat::solver const& s, atom2bool_var const& m, params_ref const& p, expr_ref_vector& learned); + void operator()(sat::solver & t, atom2bool_var const & m, params_ref const & p, goal & s, ref & mc); }; diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index a708f99bf..6beec79c9 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -108,7 +108,7 @@ class sat_tactic : public tactic { IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "\"formula constains interpreted atoms, recovering formula from sat solver...\"\n";); #endif m_solver.pop_to_base_level(); - model_converter_ref mc; + ref mc; m_sat2goal(m_solver, map, m_params, *(g.get()), mc); g->add(mc.get()); } From c3c06d756c9fe7a1e9ed06600cb500014977bf99 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 20:11:18 +0000 Subject: [PATCH 0411/1283] Documentation fixes. --- doc/mk_api_doc.py | 7 +++++-- src/api/ml/z3.mli | 4 +--- src/api/z3_api.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index a944f2c65..a1a9e64bd 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -226,12 +226,14 @@ try: website_dox_substitutions = {} bullet_point_prefix='\n - ' if Z3PY_ENABLED: + print("Python documentation enabled") website_dox_substitutions['PYTHON_API'] = ( '{prefix}Python API ' '(also available in pydoc format)' ).format( prefix=bullet_point_prefix) else: + print("Python documentation disabled") website_dox_substitutions['PYTHON_API'] = '' if DOTNET_ENABLED: website_dox_substitutions['DOTNET_API'] = ( @@ -250,7 +252,7 @@ try: website_dox_substitutions['JAVA_API'] = '' if ML_ENABLED: website_dox_substitutions['OCAML_API'] = ( - 'ML/OCaml API' + '{prefix}ML/OCaml API' ).format( prefix=bullet_point_prefix) else: @@ -316,7 +318,7 @@ try: if ML_ENABLED: ml_output_dir = os.path.join(OUTPUT_DIRECTORY, 'html', 'ml') mk_dir(ml_output_dir) - if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, doc_path('../src/api/ml/z3enums.mli'), doc_path('../src/api/ml/z3.mli')]) != 0: + if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, '%s/api/ml/z3enums.mli' % BUILD_DIR, '%s/api/ml/z3.mli' % BUILD_DIR]) != 0: print("ERROR: ocamldoc failed.") exit(1) print("Generated ML/OCaml documentation.") @@ -326,3 +328,4 @@ except Exception: exctype, value = sys.exc_info()[:2] print("ERROR: failed to generate documentation: %s" % value) exit(1) + diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 9f4cd9cd9..80923a0c7 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -3443,12 +3443,10 @@ sig (** Parse the given string using the SMT-LIB2 parser. - {!parse_smtlib_string} @return A conjunction of assertions in the scope (up to push/pop) at the end of the string. *) val parse_smtlib2_string : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr - (** Parse the given file using the SMT-LIB2 parser. - {!parse_smtlib2_string} *) + (** Parse the given file using the SMT-LIB2 parser. *) val parse_smtlib2_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr end diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 064476b9b..007bc3ab6 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1331,7 +1331,7 @@ typedef enum { - Z3_IOB: Index out of bounds. - Z3_INVALID_ARG: Invalid argument was provided. - Z3_PARSER_ERROR: An error occurred when parsing a string or file. - - Z3_NO_PARSER: Parser output is not available, that is, user didn't invoke #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. + - Z3_NO_PARSER: Parser output is not available, that is, user didn't invoke #Z3_parse_smtlib2_string or #Z3_parse_smtlib2_file. - Z3_INVALID_PATTERN: Invalid pattern was used to build a quantifier. - Z3_MEMOUT_FAIL: A memory allocation failure was encountered. - Z3_FILE_ACCESS_ERRROR: A file could not be accessed. From 399b27fda3874a3897e8af8d531758e54b71f818 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 12:20:44 -0800 Subject: [PATCH 0412/1283] add Python facility for int2bv, fix #1398 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 237f35433..3bf48b611 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -3568,6 +3568,14 @@ def BV2Int(a, is_signed=False): ## investigate problem with bv2int return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), is_signed), ctx) +def Int2BV(a, num_bits): + """Return the z3 expression Int2BV(a, num_bits). + It is a bit-vector of width num_bits and represents the + modulo of a by 2^num_bits + """ + ctx = a.ctx + return BitVecRef(Z3_mk_int2bv(ctx.ref(), num_bits, a.as_ast()), ctx) + def BitVecSort(sz, ctx=None): """Return a Z3 bit-vector sort of the given size. If `ctx=None`, then the global context is used. From d695767f61f752ca8aecfe53792dd0fd1b90ec1e Mon Sep 17 00:00:00 2001 From: bannsec Date: Mon, 18 Dec 2017 21:48:54 +0000 Subject: [PATCH 0413/1283] Allowing slices and negative index in assertions --- src/api/python/z3/z3.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 3bf48b611..4cc401156 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5140,9 +5140,18 @@ class AstVector(Z3PPObject): >>> A[1] y """ - if i >= self.__len__(): - raise IndexError - return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx) + + if isinstance(i, int): + if i < 0: + i += self.__len__() + + if i >= self.__len__(): + raise IndexError + return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx) + + elif isinstance(i, slice): + return [_to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, ii), self.ctx) for ii in range(*i.indices(self.__len__()))] + def __setitem__(self, i, v): """Update AST at position `i`. From 13ee8da65968d3f111666032f27813eee51e9e66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 15:57:16 -0800 Subject: [PATCH 0414/1283] add virtual destructor to see if this helps ASan error Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 8704f4444..488e16ae9 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -151,6 +151,7 @@ namespace nlsat { class solver_exception : public default_exception { public: solver_exception(char const * msg):default_exception(msg) {} + virtual ~solver_exception() {} }; class assignment; From 517b0812021129377590f2fc2afcbd263461a3ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 21:13:03 -0800 Subject: [PATCH 0415/1283] remove custom exception, perhaps this handles exception issue Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_types.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 488e16ae9..db3b6ffa5 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -148,11 +148,7 @@ namespace nlsat { typedef algebraic_numbers::anum anum; typedef algebraic_numbers::manager anum_manager; - class solver_exception : public default_exception { - public: - solver_exception(char const * msg):default_exception(msg) {} - virtual ~solver_exception() {} - }; + typedef default_exception solver_exception; class assignment; From 36204fafa09f601052044052e1477b7ad3264005 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Dec 2017 20:27:08 -0800 Subject: [PATCH 0416/1283] alternate strategies for QF_NIA Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/qflia_tactic.cpp | 1 - src/tactic/smtlogics/qfnia_tactic.cpp | 14 +++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index de542f3c4..23ae179e2 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -24,7 +24,6 @@ Notes: #include "tactic/core/solve_eqs_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "smt/tactic/smt_tactic.h" -// include"mip_tactic.h" #include "tactic/arith/add_bounds_tactic.h" #include "tactic/arith/pb2bv_tactic.h" #include "tactic/arith/lia2pb_tactic.h" diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 5374ba1c1..d967660ce 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -102,13 +102,17 @@ static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { mk_fail_if_undecided_tactic()); } -tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { +static tactic * mk_qfnia_smt_solver(ast_manager& m, params_ref const& p) { params_ref simp_p = p; simp_p.set_bool("som", true); // expand into sums of monomials + return and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()); +} + +tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_nlsat_solver(m, p), - mk_qfnia_sat_solver(m, p), - and_then(using_params(mk_simplify_tactic(m), simp_p), - mk_smt_tactic()))); + 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))); } From 0ac7082c8092c25efb3b9f893b2982a9e0ab556e Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 21 Dec 2017 17:13:39 -0500 Subject: [PATCH 0417/1283] add upper bound refinement (WIP) --- src/smt/theory_str.cpp | 239 ++++++++++++++++++++++++++++++++++++++++- src/smt/theory_str.h | 69 ++++++++++++ 2 files changed, 305 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 88180352c..2f41a6617 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -74,6 +74,7 @@ namespace smt { theory_str::~theory_str() { m_trail_stack.reset(); + regex_automata.clear(); } expr * theory_str::mk_string(zstring const& str) { @@ -1741,14 +1742,19 @@ namespace smt { regex_in_var_reg_str_map[ex->get_arg(0)].insert(regexStr); } + expr_ref str(ex->get_arg(0), m); + app * regex = to_app(ex->get_arg(1)); + if (m_params.m_RegexAutomata) { + regex_terms.insert(ex); + if (!regex_terms_by_string.contains(str)) { + regex_terms_by_string.insert(str, ptr_vector()); + } + regex_terms_by_string[str].push_back(ex); // stop setting up axioms here, we do this differently return; } - expr_ref str(ex->get_arg(0), m); - app * regex = to_app(ex->get_arg(1)); - // quick reference for the following code: // - ex: top-level regex membership term // - str: string term appearing in ex @@ -6665,6 +6671,77 @@ namespace smt { } } + /* + * Refine the upper bound on the length of a solution to a given automaton. + * The method returns TRUE if a solution of length `current_upper_bound` exists, + * and FALSE otherwise. In addition, the reference parameter `refined_upper_bound` + * is assigned the length of the longest solution shorter than `current_upper_bound`, + * if a shorter solution exists, or -1 otherwise. + */ + bool theory_str::refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound) { + ENSURE(aut != NULL); + + if (aut->final_states().empty()) { + // no solutions at all! + refined_upper_bound = rational::minus_one(); + return false; + } + + // from here we assume there is a final state reachable from the initial state + unsigned_vector search_queue; + // populate search queue with all states reachable from the epsilon-closure of the start state + aut->get_epsilon_closure(aut->init(), search_queue); + + rational last_solution_depth = rational::minus_one(); + bool found_solution_at_upper_bound = false; + + unsigned search_depth = 0; + hashtable > next_states; + unsigned_vector next_search_queue; + + while(!search_queue.empty()) { + // see if any of the current states are final + for (unsigned_vector::iterator it = search_queue.begin(); it != search_queue.end(); ++it) { + unsigned src = *it; + if (aut->is_final_state(src)) { + if (search_depth == current_upper_bound.get_unsigned()) { + found_solution_at_upper_bound = true; + } else { + last_solution_depth = rational(search_depth); + } + break; + } + } + + if (search_depth == current_upper_bound.get_unsigned()) { + break; + } + + next_states.reset(); + next_search_queue.clear(); + // move one step along all states + for (unsigned_vector::iterator it = search_queue.begin(); it != search_queue.end(); ++it) { + unsigned src = *it; + eautomaton::moves next_moves; + aut->get_moves_from(src, next_moves, true); + for (eautomaton::moves::iterator moves_it = next_moves.begin(); + moves_it != next_moves.end(); ++moves_it) { + unsigned dst = moves_it->dst(); + if (!next_states.contains(dst)) { + next_states.insert(dst); + next_search_queue.push_back(dst); + } + } + } + search_queue.clear(); + search_queue.append(next_search_queue); + search_depth += 1; + } //!search_queue.empty() + + refined_upper_bound = last_solution_depth; + return found_solution_at_upper_bound; + } + /* * strArgmt::solve_concat_eq_str() * Solve concatenations of the form: @@ -9076,6 +9153,155 @@ namespace smt { } } + // regex automata + if (m_params.m_RegexAutomata) { + bool regex_axiom_add = false; + for (obj_hashtable::iterator it = regex_terms.begin(); it != regex_terms.end(); ++it) { + expr * str_in_re = *it; + expr * str; + expr * re; + u.str.is_in_re(str_in_re, str, re); + lbool current_assignment = ctx.get_assignment(str_in_re); + TRACE("str", tout << "regex term: " << mk_pp(str, m) << " in " << mk_pp(re, m) << " : " << current_assignment << std::endl;); + if (current_assignment == l_undef) { + continue; + } + rational exact_length_value; + if (get_len_value(str, exact_length_value)) { + TRACE("str", tout << "exact length of " << mk_pp(str, m) << " is " << exact_length_value << std::endl;); + NOT_IMPLEMENTED_YET(); + } + expr_ref str_len(mk_strlen(str), m); + rational lower_bound_value; + rational upper_bound_value; + bool lower_bound_exists = lower_bound(str_len, lower_bound_value); + bool upper_bound_exists = upper_bound(str_len, upper_bound_value); + CTRACE("str", lower_bound_exists, tout << "lower bound of " << mk_pp(str, m) << " is " << lower_bound_value << std::endl;); + CTRACE("str", upper_bound_exists, tout << "upper bound of " << mk_pp(str, m) << " is " << upper_bound_value << std::endl;); + + if (upper_bound_exists) { + // check current assumptions + if (regex_automaton_assumptions.contains(re) && + !regex_automaton_assumptions[re].empty()){ + // one or more existing assumptions. + // see if the (current best) upper bound can be refined + // (note that if we have an automaton with no assumption, + // this automatically counts as best) + bool need_assumption = true; + regex_automaton_under_assumptions last_assumption; + rational last_ub = rational::minus_one(); + for (svector::iterator it = regex_automaton_assumptions[re].begin(); + it != regex_automaton_assumptions[re].end(); ++it) { + regex_automaton_under_assumptions autA = *it; + if ((current_assignment == l_true && autA.get_polarity() == false) + || (current_assignment == l_false && autA.get_polarity() == true)) { + // automaton uses incorrect polarity + continue; + } + rational this_ub; + if (autA.get_upper_bound(this_ub)) { + if (last_ub == rational::minus_one() || this_ub < last_ub) { + last_ub = this_ub; + last_assumption = autA; + } + } else { + need_assumption = false; + last_assumption = autA; + break; + } + } + if (!last_ub.is_minus_one() || !need_assumption) { + CTRACE("str", !need_assumption, tout << "using automaton with full length information" << std::endl;); + CTRACE("str", need_assumption, tout << "using automaton with assumed upper bound of " << last_ub << std::endl;); + + rational refined_upper_bound; + bool solution_at_upper_bound = refine_automaton_upper_bound(last_assumption.get_automaton(), + upper_bound_value, refined_upper_bound); + TRACE("str", tout << "refined upper bound is " << refined_upper_bound << + (solution_at_upper_bound?", solution at upper bound":", no solution at upper bound") << std::endl;); + + expr_ref_vector lhs(m); + if (current_assignment == l_false) { + lhs.push_back(m.mk_not(str_in_re)); + } else { + lhs.push_back(str_in_re); + } + if (need_assumption) { + lhs.push_back(m_autil.mk_le(str_len, m_autil.mk_numeral(last_ub, true))); + } + lhs.push_back(m_autil.mk_le(str_len, m_autil.mk_numeral(upper_bound_value, true))); + + expr_ref_vector rhs(m); + + if (solution_at_upper_bound) { + if (refined_upper_bound.is_minus_one()) { + // If there are solutions at the upper bound but not below it, make the bound exact. + NOT_IMPLEMENTED_YET(); + } else { + // If there are solutions at and below the upper bound, add an additional bound. + NOT_IMPLEMENTED_YET(); + } + } else { + if (refined_upper_bound.is_minus_one()) { + // If there are no solutions at or below the upper bound, assert a conflict clause. + rhs.push_back(m.mk_not(m_autil.mk_le(str_len, m_autil.mk_numeral(upper_bound_value, true)))); + } else { + // If there are solutions below the upper bound but not at it, refine the bound. + NOT_IMPLEMENTED_YET(); + } + } + + expr_ref lhs_terms(mk_and(lhs), m); + expr_ref rhs_terms(mk_and(rhs), m); + assert_implication(lhs_terms, rhs_terms); + regex_axiom_add = true; + } + } else { + // no existing automata/assumptions. + // if it's easy to construct a full automaton for R, do so + unsigned expected_complexity = estimate_regex_complexity(re); + unsigned threshold = 1000; // TODO better metric + if (expected_complexity <= threshold) { + eautomaton * aut = m_mk_aut(re); + aut->compress(); + regex_automata.push_back(aut); + regex_automaton_under_assumptions new_aut(re, aut, true); + if (!regex_automaton_assumptions.contains(re)) { + regex_automaton_assumptions.insert(re, svector()); + } + regex_automaton_assumptions[re].push_back(new_aut); + TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); + regex_axiom_add = true; + // TODO immediately attempt to learn lower/upper bound info here + } else { + // TODO check negation? + // construct a partial automaton for R to the given upper bound + NOT_IMPLEMENTED_YET(); + } + } + // if we have *any* automaton for R, and the upper bound is not too large, + // finitize the automaton (if we have not already done so) and assert all solutions + if (upper_bound_value < 50) { // TODO better metric for threshold + // NOT_IMPLEMENTED_YET(); // TODO(mtrberzi) + } + } else { // !upper_bound_exists + // no upper bound information + if (lower_bound_exists) { + // lower bound, no upper bound + NOT_IMPLEMENTED_YET(); + } else { // !lower_bound_exists + // no bounds information + NOT_IMPLEMENTED_YET(); + } + } + + // NOT_IMPLEMENTED_YET(); + } + if (regex_axiom_add) { + return FC_CONTINUE; + } + } // RegexAutomata + bool needToAssignFreeVars = false; std::set free_variables; std::set unused_internal_variables; @@ -10567,6 +10793,13 @@ namespace smt { SASSERT(lenTestAssert != NULL); return lenTestAssert; } else { + // if we are performing automata-based reasoning and the term associated with + // this length tester is in any way constrained by regex terms, + // do not perform value testing -- this term is not a free variable. + if (m_params.m_RegexAutomata) { + NOT_IMPLEMENTED_YET(); // TODO + } + TRACE("str", tout << "length is fixed; generating models for free var" << std::endl;); // length is fixed expr * valueAssert = gen_free_var_options(freeVar, effectiveLenInd, effectiveLenIndiStr, NULL, zstring("")); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 602f9feab..57fa48142 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -166,6 +166,69 @@ public: bool matches(zstring input); }; +class regex_automaton_under_assumptions { +protected: + expr * str_in_re; + eautomaton * aut; + bool polarity; + + bool assume_lower_bound; + rational lower_bound; + + bool assume_upper_bound; + rational upper_bound; +public: + regex_automaton_under_assumptions() : + str_in_re(NULL), aut(NULL), polarity(false), + assume_lower_bound(false), assume_upper_bound(false) {} + + regex_automaton_under_assumptions(expr * str_in_re, eautomaton * aut, bool polarity) : + str_in_re(str_in_re), aut(aut), polarity(polarity), + assume_lower_bound(false), assume_upper_bound(false) {} + + void set_lower_bound(rational & lb) { + lower_bound = lb; + assume_lower_bound = true; + } + void unset_lower_bound() { + assume_lower_bound = false; + } + + void set_upper_bound(rational & ub) { + upper_bound = ub; + assume_upper_bound = true; + } + void unset_upper_bound() { + assume_upper_bound = false; + } + + bool get_lower_bound(rational & lb) const { + if (assume_lower_bound) { + lb = lower_bound; + return true; + } else { + return false; + } + } + + bool get_upper_bound(rational & ub) const { + if (assume_upper_bound) { + ub = upper_bound; + return true; + } else { + return false; + } + } + + eautomaton * get_automaton() const { return aut; } + bool get_polarity() const { return polarity; } + + virtual ~regex_automaton_under_assumptions() { + // don't free str_in_re or aut; + // they are managed separately + } +}; + class theory_str : public theory { struct T_cut { @@ -338,6 +401,11 @@ protected: std::map, expr*> regex_in_bool_map; std::map > regex_in_var_reg_str_map; + // regex automata + ptr_vector regex_automata; + obj_hashtable regex_terms; + obj_map > regex_terms_by_string; // S --> [ (str.in.re S *) ] + obj_map > regex_automaton_assumptions; // RegEx --> [ aut+assumptions ] std::map regex_nfa_cache; // Regex term --> NFA svector char_set; @@ -468,6 +536,7 @@ protected: unsigned estimate_regex_complexity(expr * re); unsigned estimate_regex_complexity_under_complement(expr * re); expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); + bool refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound); void set_up_axioms(expr * ex); void handle_equality(expr * lhs, expr * rhs); From 8198a8ce7bebcd79ea5ba798bf5ee618ab2d1d33 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Dec 2017 14:41:16 -0800 Subject: [PATCH 0418/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/ast/ast_translation.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 8 ++++++-- src/util/resource_limit.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index 532795c5c..d4709c077 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -196,7 +196,7 @@ ast * ast_translation::process(ast const * _n) { SASSERT(m_extra_children_stack.empty()); ++m_num_process; - if (m_num_process > (1 << 16)) { + if (m_num_process > (1 << 14)) { reset_cache(); m_num_process = 0; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index bcfb06356..bcd264743 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -915,7 +915,7 @@ void sat2goal::mc::flush_gmc() { } model_converter* sat2goal::mc::translate(ast_translation& translator) { - mc* result = alloc(mc, m); + mc* result = alloc(mc, translator.to()); result->m_smc.copy(m_smc); result->m_gmc = m_gmc ? dynamic_cast(m_gmc->translate(translator)) : nullptr; for (app* e : m_var2expr) { @@ -983,6 +983,10 @@ void sat2goal::mc::operator()(expr_ref& fml) { } void sat2goal::mc::insert(sat::bool_var v, app * atom, bool aux) { + if (m_var2expr.get(v, nullptr)) { + std::cout << mk_pp(atom, m) << "\n"; + std::cout << mk_pp(m_var2expr.get(v, nullptr), m) << "\n"; + } VERIFY(!m_var2expr.get(v, nullptr)); m_var2expr.reserve(v + 1); m_var2expr.set(v, atom); @@ -1038,7 +1042,7 @@ struct sat2goal::imp { for (sat::bool_var v = 0; v < num_vars; v++) { checkpoint(); sat::literal l(v, false); - if (m_lit2expr.get(l.index())) { + if (m_lit2expr.get(l.index()) && !mc->var2expr(v)) { mc->insert(v, to_app(m_lit2expr.get(l.index())), false); SASSERT(m_lit2expr.get((~l).index())); } diff --git a/src/util/resource_limit.h b/src/util/resource_limit.h index 3f5c4d520..969953aaf 100644 --- a/src/util/resource_limit.h +++ b/src/util/resource_limit.h @@ -1,7 +1,7 @@ /*++ Copyright (c) 2006 Microsoft Corporation -Module Name: +Modulre Name: resource_limit.h From 0b424942abb90a51220e70f6e7cab30ff2e18fe5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Dec 2017 14:42:21 -0800 Subject: [PATCH 0419/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 6 +----- src/util/resource_limit.h | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index bcd264743..257cf3b53 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -983,11 +983,7 @@ void sat2goal::mc::operator()(expr_ref& fml) { } void sat2goal::mc::insert(sat::bool_var v, app * atom, bool aux) { - if (m_var2expr.get(v, nullptr)) { - std::cout << mk_pp(atom, m) << "\n"; - std::cout << mk_pp(m_var2expr.get(v, nullptr), m) << "\n"; - } - VERIFY(!m_var2expr.get(v, nullptr)); + SASSERT(!m_var2expr.get(v, nullptr)); m_var2expr.reserve(v + 1); m_var2expr.set(v, atom); if (aux) { diff --git a/src/util/resource_limit.h b/src/util/resource_limit.h index 969953aaf..3f5c4d520 100644 --- a/src/util/resource_limit.h +++ b/src/util/resource_limit.h @@ -1,7 +1,7 @@ /*++ Copyright (c) 2006 Microsoft Corporation -Modulre Name: +Module Name: resource_limit.h From 5bc4c9809e232d63f46018b200cb930bca993ce5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Dec 2017 12:50:11 -0800 Subject: [PATCH 0420/1283] initialize additional assumptions after setup_context is called the first time Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 59 +++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3b69d4846..a87042e2b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3202,10 +3202,8 @@ namespace smt { }); validate_unsat_core(); // theory validation of unsat core - ptr_vector::iterator th_it = m_theory_set.begin(); - ptr_vector::iterator th_end = m_theory_set.end(); - for (; th_it != th_end; ++th_it) { - lbool theory_result = (*th_it)->validate_unsat_core(m_unsat_core); + for (theory* th : m_theory_set) { + lbool theory_result = th->validate_unsat_core(m_unsat_core); if (theory_result == l_undef) { return l_undef; } @@ -3296,10 +3294,8 @@ namespace smt { #ifndef _EXTERNAL_RELEASE if (m_fparams.m_display_installed_theories) { std::cout << "(theories"; - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - std::cout << " " << (*it)->get_name(); + for (theory* th : m_theory_set) { + std::cout << " " << th->get_name(); } std::cout << ")" << std::endl; } @@ -3316,17 +3312,13 @@ namespace smt { m_fparams.m_relevancy_lemma = false; // setup all the theories - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) - (*it)->setup(); + for (theory* th : m_theory_set) + th->setup(); } void context::add_theory_assumptions(expr_ref_vector & theory_assumptions) { - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - (*it)->add_theory_assumptions(theory_assumptions); + for (theory* th : m_theory_set) { + th->add_theory_assumptions(theory_assumptions); } } @@ -3342,18 +3334,7 @@ namespace smt { if (!check_preamble(reset_cancel)) return l_undef; - expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); - if (!already_did_theory_assumptions) { - add_theory_assumptions(all_assumptions); - } - - unsigned num_assumptions = all_assumptions.size(); - expr * const * assumptions = all_assumptions.c_ptr(); - - if (!validate_assumptions(num_assumptions, assumptions)) - return l_undef; TRACE("check_bug", tout << "inconsistent: " << inconsistent() << ", m_unsat_core.empty(): " << m_unsat_core.empty() << "\n";); - TRACE("unsat_core_bug", for (unsigned i = 0; i < num_assumptions; i++) { tout << mk_pp(assumptions[i], m_manager) << "\n";}); pop_to_base_lvl(); TRACE("before_search", display(tout);); SASSERT(at_base_level()); @@ -3363,6 +3344,18 @@ namespace smt { } else { setup_context(false); + expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); + if (!already_did_theory_assumptions) { + add_theory_assumptions(all_assumptions); + } + + unsigned num_assumptions = all_assumptions.size(); + expr * const * assumptions = all_assumptions.c_ptr(); + + if (!validate_assumptions(num_assumptions, assumptions)) + return l_undef; + TRACE("unsat_core_bug", tout << all_assumptions << "\n";); + internalize_assertions(); TRACE("after_internalize_assertions", display(tout);); if (m_asserted_formulas.inconsistent()) { @@ -3551,10 +3544,9 @@ namespace smt { pop_scope(m_scope_lvl - curr_lvl); SASSERT(at_search_level()); } - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end && !inconsistent(); ++it) - (*it)->restart_eh(); + for (theory* th : m_theory_set) { + if (!inconsistent()) th->restart_eh(); + } TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); if (!inconsistent()) { m_qmanager->restart_eh(); @@ -4070,10 +4062,7 @@ namespace smt { bool include = false; if (at_lbls) { // include if there is a label with the '@' sign. - buffer::const_iterator it = lbls.begin(); - buffer::const_iterator end = lbls.end(); - for (; it != end; ++it) { - symbol const & s = *it; + for (symbol const& s : lbls) { if (s.contains('@')) { include = true; break; From d86e8f02d7808fed783a5eedc4d8f5255008c6f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Dec 2017 10:09:10 -0800 Subject: [PATCH 0421/1283] fix get-objectives error #1419 message (get-objectives) Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 3d296d92b..0daf98320 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1235,6 +1235,9 @@ namespace opt { } void context::display_assignment(std::ostream& out) { + if (m_scoped_state.m_objectives.size() != m_objectives.size()) { + throw default_exception("check-sat has not been called with latest objectives"); + } out << "(objectives\n"; for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { objective const& obj = m_scoped_state.m_objectives[i]; From b1724b2f629e71e7bdf8b104dd052bfc95b140f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Dec 2017 14:39:16 -0800 Subject: [PATCH 0422/1283] fix update to variables Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 257cf3b53..6d78bc331 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -926,7 +926,7 @@ model_converter* sat2goal::mc::translate(ast_translation& translator) { void sat2goal::mc::collect(ast_pp_util& visitor) { flush_gmc(); - collect(visitor); + if (m_gmc) m_gmc->collect(visitor); } void sat2goal::mc::display(std::ostream& out) { @@ -995,6 +995,10 @@ void sat2goal::mc::insert(sat::bool_var v, app * atom, bool aux) { } expr_ref sat2goal::mc::lit2expr(sat::literal l) { + if (!m_var2expr.get(l.var())) { + app* aux = m.mk_fresh_const(0, m.mk_bool_sort()); + m_var2expr.set(l.var(), aux); + } VERIFY(m_var2expr.get(l.var())); expr_ref result(m_var2expr.get(l.var()), m); if (l.sign()) { From c80f34102fa0a290b2798b256ca09c3b4cd56786 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Dec 2017 17:29:31 -0800 Subject: [PATCH 0423/1283] adding ad-hoc method for converting models Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 8 ++ src/api/dotnet/Solver.cs | 7 ++ src/api/z3_api.h | 7 ++ src/sat/ba_solver.cpp | 176 +++++++++++++++------------------------ src/sat/ba_solver.h | 28 +++++-- src/sat/sat_config.cpp | 2 + src/sat/sat_config.h | 1 + 7 files changed, 113 insertions(+), 116 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 97fa23a79..4e7719f56 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -128,6 +128,14 @@ extern "C" { Z3_CATCH_RETURN(0); } + void Z3_API Z3_solver_import_model_converter(Z3_context c, Z3_solver src, Z3_solver dst) { + Z3_TRY; + LOG_Z3_solver_import_model_converter(c, src, dst); + model_converter_ref mc = to_solver_ref(src)->get_model_converter(); + to_solver_ref(dst)->set_model_converter(mc.get()); + Z3_CATCH; + } + 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); diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index f67a298bb..1a62aa8e3 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -446,6 +446,13 @@ namespace Microsoft.Z3 return new Solver(ctx, Native.Z3_solver_translate(Context.nCtx, NativeObject, ctx.nCtx)); } + /// + /// Import model converter from other solver. + /// + public void ImportModelConverter(Solver src) + { + Native.Z3_solver_import_model_converter(Context.nCtx, src.NativeObject, NativeObject); + } /// /// Solver statistics. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 99d6021ef..02ca43910 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6035,6 +6035,13 @@ extern "C" { */ Z3_solver Z3_API Z3_solver_translate(Z3_context source, Z3_solver s, Z3_context target); + /** + \brief Ad-hoc method for importing model convertion from solver. + + def_API('Z3_solver_import_model_converter', VOID, (_in(CONTEXT), _in(SOLVER), _in(SOLVER))) + */ + void Z3_API Z3_solver_import_model_converter(Z3_context ctx, Z3_solver src, Z3_solver dst); + /** \brief Return a string describing all solver available parameters. diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index e5623c05f..be4498061 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1518,7 +1518,7 @@ namespace sat { return p; } - ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_unit_walk(0), m_constraint_id(0) { + ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_unit_walk(0), m_constraint_id(0), m_ba(*this), m_sort(m_ba) { TRACE("ba", tout << this << "\n";); } @@ -2436,119 +2436,54 @@ namespace sat { } } - // ---------------------------------- - // lp based relaxation - -#if 0 - void ba_solver::lp_add_var(int coeff, lp::var_index v, lhs_t& lhs, rational& rhs) { - if (coeff < 0) { - rhs += rational(coeff); - } - lhs.push_back(std::make_pair(rational(coeff), v)); + // ------------------------- + // sorting networks + literal ba_solver::ba_sort::mk_false() { + return ~mk_true(); } - void ba_solver::lp_add_clause(lp::lar_solver& s, svector const& vars, clause const& c) { - lhs_t lhs; - rational rhs; - if (c.frozen()) return; - rhs = rational::one(); - for (literal l : c) { - lp_add_var(l.sign() ? -1 : 1, vars[l.var()], lhs, rhs); + literal ba_solver::ba_sort::mk_true() { + if (m_true == null_literal) { + bool_var v = s.s().mk_var(false, false); + m_true = literal(v, false); + s.s().mk_clause(1,&m_true); } - s.add_constraint(lhs, lp::GE, rhs); + VERIFY(m_true != null_literal); + return m_true; } - void ba_solver::lp_lookahead_reduction() { - lp::lar_solver solver; - solver.settings().set_message_ostream(&std::cout); - solver.settings().set_debug_ostream(&std::cout); - solver.settings().print_statistics = true; - solver.settings().report_frequency = 1000; - // solver.settings().simplex_strategy() = lp::simplex_strategy_enum::lu; - runs out of memory - // TBD: set rlimit on the solver - svector vars; - for (unsigned i = 0; i < s().num_vars(); ++i) { - lp::var_index v = solver.add_var(i, false); - vars.push_back(v); - solver.add_var_bound(v, lp::GE, rational::zero()); - solver.add_var_bound(v, lp::LE, rational::one()); - switch (value(v)) { - case l_true: solver.add_var_bound(v, lp::GE, rational::one()); break; - case l_false: solver.add_var_bound(v, lp::LE, rational::zero()); break; - default: break; - } - } - lhs_t lhs; - rational rhs; - for (clause* c : s().m_clauses) { - lp_add_clause(solver, vars, *c); - } - for (clause* c : s().m_learned) { - lp_add_clause(solver, vars, *c); - } - for (constraint const* c : m_constraints) { - if (c->lit() != null_literal) continue; // ignore definitions for now. - switch (c->tag()) { - case card_t: - case pb_t: { - pb_base const& p = dynamic_cast(*c); - rhs = rational(p.k()); - lhs.reset(); - for (unsigned i = 0; i < p.size(); ++i) { - literal l = p.get_lit(i); - int co = p.get_coeff(i); - lp_add_var(l.sign() ? -co : co, vars[l.var()], lhs, rhs); - } - solver.add_constraint(lhs, lp::GE, rhs); - break; - } - default: - // ignore xor - break; - } - } - std::cout << "lp solve\n"; - std::cout.flush(); - - lp::lp_status st = solver.solve(); - if (st == lp::lp_status::INFEASIBLE) { - std::cout << "infeasible\n"; - s().set_conflict(justification()); - return; - } - std::cout << "feasible\n"; - std::cout.flush(); - for (unsigned i = 0; i < s().num_vars(); ++i) { - lp::var_index v = vars[i]; - if (value(v) != l_undef) continue; - // TBD: take initial model into account to limit queries. - std::cout << "solve v" << v << "\n"; - std::cout.flush(); - solver.push(); - solver.add_var_bound(v, lp::GE, rational::one()); - st = solver.solve(); - solver.pop(1); - if (st == lp::lp_status::INFEASIBLE) { - std::cout << "found unit: " << literal(v, true) << "\n"; - s().assign(literal(v, true), justification()); - solver.add_var_bound(v, lp::LE, rational::zero()); - continue; - } - - solver.push(); - solver.add_var_bound(v, lp::LE, rational::zero()); - st = solver.solve(); - solver.pop(1); - if (st == lp::lp_status::INFEASIBLE) { - std::cout << "found unit: " << literal(v, false) << "\n"; - s().assign(literal(v, false), justification()); - solver.add_var_bound(v, lp::GE, rational::zero()); - continue; - } - } + literal ba_solver::ba_sort::mk_not(literal l) { + return ~l; } -#endif + literal ba_solver::ba_sort::fresh(char const*) { + bool_var v = s.s().mk_var(false, true); + 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_min(literal l1, literal l2) { + return ~mk_max(~l1, ~l2); + } + + void ba_solver::ba_sort::mk_clause(unsigned n, literal const* lits) { + literal_vector _lits(n, lits); + s.s().mk_clause(n, _lits.c_ptr()); + } + // ------------------------------- // set literals equivalent @@ -2665,6 +2600,10 @@ namespace sat { c.set_size(sz); c.set_k(k); + if (clausify(c)) { + return; + } + if (!all_units) { TRACE("ba", tout << "replacing by pb: " << c << "\n";); m_wlits.reset(); @@ -2684,6 +2623,27 @@ namespace sat { } } + bool ba_solver::clausify(card& c) { +#if 0 + if (get_config().m_card_solver) + return false; + + // + // TBD: conditions for when to clausify are TBD and + // handling of conditional cardinality as well. + // + if (c.lit() == null_literal) { + if (!c.learned() && !std::any_of(c.begin(), c.end(), [&](literal l) { return s().was_eliminated(l.var()); })) { + IF_VERBOSE(0, verbose_stream() << "clausify " << c << "\n"; + m_sort.ge(false, c.k(), c.size(), c.begin()); + } + remove_constraint(c, "recompiled to clauses"); + return true; + } +#endif + return false; + } + void ba_solver::split_root(constraint& c) { switch (c.tag()) { @@ -2693,8 +2653,6 @@ namespace sat { } } - - void ba_solver::flush_roots(constraint& c) { if (c.lit() != null_literal && !is_watched(c.lit(), c)) { watch_literal(c.lit(), c); diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index e7a220f5c..f447be64c 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -26,8 +26,7 @@ Revision History: #include "sat/sat_lookahead.h" #include "sat/sat_unit_walk.h" #include "util/scoped_ptr_vector.h" -#include "util/lp/lar_solver.h" - +#include "util/sorting_network.h" namespace sat { @@ -232,6 +231,24 @@ namespace sat { unsigned_vector m_pb_undef; + struct ba_sort { + ba_solver& s; + literal m_true; + + typedef sat::literal literal; + typedef sat::literal_vector literal_vector; + ba_sort(ba_solver& s): s(s), m_true(null_literal) {} + literal mk_false(); + literal mk_true(); + literal mk_not(literal l); + literal fresh(char const*); + literal mk_max(literal l1, literal l2); + literal mk_min(literal l1, literal l2); + void mk_clause(unsigned n, literal const* lits); + }; + ba_sort m_ba; + psort_nw m_sort; + void ensure_parity_size(bool_var v); unsigned get_parity(bool_var v); void inc_parity(bool_var v); @@ -277,11 +294,6 @@ namespace sat { void update_psm(constraint& c) const; void mutex_reduction(); - typedef vector> lhs_t; - void lp_lookahead_reduction(); - void lp_add_var(int coeff, lp::var_index v, lhs_t& lhs, rational& rhs); - void lp_add_clause(lp::lar_solver& s, svector const& vars, clause const& c); - unsigned use_count(literal lit) const { return m_cnstr_use_list[lit.index()].size() + m_clause_use_list.get(lit).size(); } void cleanup_clauses(); @@ -330,6 +342,7 @@ namespace sat { void get_antecedents(literal l, card const& c, literal_vector & r); void flush_roots(card& c); void recompile(card& c); + bool clausify(card& c); lbool eval(card const& c) const; double get_reward(card const& c, literal_occs_fun& occs) const; @@ -482,6 +495,7 @@ namespace sat { virtual bool validate(); + }; }; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 4cf448394..b67666993 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -177,6 +177,8 @@ namespace sat { else throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); + m_card_solver = p.cardinality_solver(); + sat_simplifier_params sp(_p); m_elim_vars = sp.elim_vars(); } diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 2aa5a325b..e64c0c544 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -129,6 +129,7 @@ namespace sat { bool m_drat_check_sat; pb_solver m_pb_solver; + bool m_card_solver; // branching heuristic settings. branching_heuristic m_branching_heuristic; From 444e178a016dc047666059abe96495109e925986 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Dec 2017 10:24:48 -0800 Subject: [PATCH 0424/1283] fix up convertion and printing Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 1 + src/tactic/model_converter.cpp | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 4e7719f56..d8a1a7be3 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -131,6 +131,7 @@ extern "C" { void Z3_API Z3_solver_import_model_converter(Z3_context c, Z3_solver src, Z3_solver dst) { Z3_TRY; LOG_Z3_solver_import_model_converter(c, src, dst); + std::cout << "import converter\n"; model_converter_ref mc = to_solver_ref(src)->get_model_converter(); to_solver_ref(dst)->set_model_converter(mc.get()); Z3_CATCH; diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 2598aa4f1..6055105c0 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -24,16 +24,21 @@ Notes: * Add or overwrite value in model. */ void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { - VERIFY(m_env); - ast_smt2_pp(out, f, e, *m_env, params_ref(), 0, "model-add") << "\n"; + smt2_pp_environment_dbg env(m); + smt2_pp_environment* _env = m_env ? m_env : &env; + ast_smt2_pp(out, f, e, *_env, params_ref(), 0, "model-add") << "\n"; } /* * A value is removed from the model. */ void model_converter::display_del(std::ostream& out, func_decl* f) const { - VERIFY(m_env); - ast_smt2_pp(out << "(model-del ", f->get_name(), f->is_skolem(), *m_env) << ")\n"; + if (m_env) { + ast_smt2_pp(out << "(model-del ", f->get_name(), f->is_skolem(), *m_env) << ")\n"; + } + else { + out << "(model-del " << f->get_name() << ")\n"; + } } void model_converter::display_add(std::ostream& out, ast_manager& m) { From 69879322d8633505a89a8ead9e7936cbea79fa2d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Dec 2017 10:26:32 -0800 Subject: [PATCH 0425/1283] fix up convertion and printing Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index d8a1a7be3..4e7719f56 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -131,7 +131,6 @@ extern "C" { void Z3_API Z3_solver_import_model_converter(Z3_context c, Z3_solver src, Z3_solver dst) { Z3_TRY; LOG_Z3_solver_import_model_converter(c, src, dst); - std::cout << "import converter\n"; model_converter_ref mc = to_solver_ref(src)->get_model_converter(); to_solver_ref(dst)->set_model_converter(mc.get()); Z3_CATCH; From 79a9dfd8fdd1ff3072fc571286217f788147084c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Dec 2017 20:35:33 -0800 Subject: [PATCH 0426/1283] adding pre-processing to nlsat for equations Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 4 +- src/math/polynomial/polynomial.cpp | 93 +++- src/math/polynomial/polynomial.h | 35 +- src/nlsat/nlsat_clause.h | 2 + src/nlsat/nlsat_solver.cpp | 631 +++++++++++++++++------- src/nlsat/nlsat_solver.h | 2 +- src/nlsat/nlsat_types.h | 2 + src/nlsat/tactic/nlsat_tactic.cpp | 8 +- src/nlsat/tactic/qfnra_nlsat_tactic.cpp | 4 + src/qe/nlqsat.cpp | 2 +- src/tactic/core/solve_eqs_tactic.cpp | 135 +++-- 11 files changed, 696 insertions(+), 222 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 4b24ea5e6..4850b52a8 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -370,7 +370,7 @@ public: app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); } app * mk_gt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GT, arg1, arg2); } - app * mk_add(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); } + app * mk_add(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(m_afid, OP_ADD, num_args, args); } app * mk_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); } app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); } @@ -378,7 +378,7 @@ public: app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); } app * mk_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); } app * mk_mul(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); } - app * mk_mul(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); } + app * mk_mul(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(m_afid, OP_MUL, num_args, args); } app * mk_uminus(expr * arg) const { return m_manager.mk_app(m_afid, OP_UMINUS, arg); } app * mk_div(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_DIV, arg1, arg2); } app * mk_idiv(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_IDIV, arg1, arg2); } diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index d6d392148..51d8489e3 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -150,7 +150,6 @@ namespace polynomial { return r; } - /** \brief Monomials (power products) */ @@ -192,7 +191,7 @@ namespace polynomial { }; static unsigned get_obj_size(unsigned sz) { return sizeof(monomial) + sz * sizeof(power); } - + monomial(unsigned id, unsigned sz, power const * pws, unsigned h): m_ref_count(0), m_id(id), @@ -257,9 +256,7 @@ namespace polynomial { if (m_size < SMALL_MONOMIAL) { // use linear search for small monomials // search backwards since we usually ask for the degree of "big" variables - unsigned i = last; - while (i > 0) { - --i; + for (unsigned i = last; i-- > 0; ) { if (get_var(i) == x) return i; } @@ -798,9 +795,8 @@ namespace polynomial { dec_ref(m_unit); CTRACE("polynomial", !m_monomials.empty(), tout << "monomials leaked\n"; - monomial_table::iterator it = m_monomials.begin(); monomial_table::iterator end = m_monomials.end(); - for (; it != end; ++it) { - (*it)->display(tout); tout << "\n"; + for (auto * m : m_monomials) { + m->display(tout); tout << "\n"; }); SASSERT(m_monomials.empty()); if (m_own_allocator) @@ -1510,6 +1506,8 @@ namespace polynomial { unsigned id() const { return m_id; } unsigned size() const { return m_size; } monomial * m(unsigned idx) const { SASSERT(idx < size()); return m_ms[idx]; } + monomial *const* begin() const { return m_ms; } + monomial *const* end() const { return m_ms + size(); } numeral const & a(unsigned idx) const { SASSERT(idx < size()); return m_as[idx]; } numeral & a(unsigned idx) { SASSERT(idx < size()); return m_as[idx]; } numeral const * as() const { return m_as; } @@ -1773,11 +1771,9 @@ namespace polynomial { } bool manager::is_linear(polynomial const * p) { - unsigned sz = p->size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_linear(p->m(0))) + for (monomial* m : *p) + if (!is_linear(m)) return false; - } return true; } @@ -2396,6 +2392,7 @@ namespace polynomial { return mm().is_valid(x); } + void add_del_eh(del_eh * eh) { eh->m_next = m_del_eh; m_del_eh = eh; @@ -6101,6 +6098,33 @@ namespace polynomial { }); } + lbool sign(monomial* m, numeral const& c, svector const& sign_of_vars) { + unsigned sz = size(m); + lbool sign1 = m_manager.is_pos(c) ? l_true : l_false; + for (unsigned i = 0; i < sz; ++i) { + var v = get_var(m, i); + unsigned d = degree(m, i); + lbool sign2 = sign_of_vars.get(v, l_undef); + if (sign2 == l_undef) + return l_undef; + else if (1 == (d % 2) && sign2 == l_false) { + sign1 = sign1 == l_true ? l_false : l_true; + } + } + return sign1; + } + + lbool sign(polynomial const * p, svector const& sign_of_vars) { + unsigned sz = size(p); + if (sz == 0) return l_undef; + lbool sign1 = sign(p->m(0), p->a(0), sign_of_vars); + for (unsigned i = 1; sign1 != l_undef && i < sz; ++i) { + if (sign(p->m(i), p->a(i), sign_of_vars) != sign1) + return l_undef; + } + return sign1; + } + bool is_pos(polynomial const * p) { bool found_unit = false; unsigned sz = p->size(); @@ -6372,6 +6396,31 @@ namespace polynomial { R.add(new_a, mk_monomial(new_m)); } return R.mk(); + } + + void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { + unsigned md = degree(r, x); + if (md == 0) { + result = const_cast(r); + return; + } + result = 0; + polynomial_ref p1(pm()), q1(pm()); + polynomial_ref_buffer ps(pm()); + unsigned sz = r->size(); + for (unsigned i = 0; i < sz; i++) { + monomial * m0 = r->m(i); + unsigned dm = m0->degree_of(x); + SASSERT(md >= dm); + monomial_ref m1(div_x(m0, x), pm()); + pw(p, dm, p1); + pw(q, md - dm, q1); + p1 = mul(r->a(i), m1, p1 * q1); + if (result) + result = add(result, p1); + else + result = p1; + } } @@ -6918,6 +6967,18 @@ namespace polynomial { return m_imp->m().set_zp(p); } + bool manager::is_var(polynomial const* p, var& v) { + return p->size() == 1 && is_var(p->m(0), v) && m_imp->m().is_one(p->a(0)); + } + + bool manager::is_var(monomial const* m, var& v) { + return m->size() == 1 && m->degree(0) == 1 && (v = m->get_var(0), true); + } + + bool manager::is_var_num(polynomial const* p, var& v, scoped_numeral& n) { + return p->size() == 2 && m_imp->m().is_one(p->a(0)) && is_var(p->m(0), v) && is_unit(p->m(1)) && (n = p->a(1), true); + } + small_object_allocator & manager::allocator() const { return m_imp->mm().allocator(); } @@ -7271,6 +7332,10 @@ namespace polynomial { void manager::psc_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S) { m_imp->psc_chain(p, q, x, S); } + + lbool manager::sign(polynomial const * p, svector const& sign_of_vars) { + return m_imp->sign(p, sign_of_vars); + } bool manager::is_pos(polynomial const * p) { return m_imp->is_pos(p); @@ -7307,6 +7372,10 @@ namespace polynomial { polynomial * manager::substitute(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs) { return m_imp->substitute(p, xs_sz, xs, vs); } + + void manager::substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { + m_imp->substitute(r, x, p, q, result); + } void manager::factor(polynomial const * p, factors & r, factor_params const & params) { m_imp->factor(p, r, params); diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 43b3c1138..b09af94bc 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -29,6 +29,7 @@ Notes: #include "util/params.h" #include "util/mpbqi.h" #include "util/rlimit.h" +#include "util/lbool.h" class small_object_allocator; @@ -98,7 +99,7 @@ namespace polynomial { }; struct display_var_proc { - virtual void operator()(std::ostream & out, var x) const { out << "x" << x; } + virtual std::ostream& operator()(std::ostream & out, var x) const { return out << "x" << x; } }; class polynomial; @@ -306,12 +307,27 @@ namespace polynomial { \brief Return true if m is linear (i.e., it is of the form 1 or x). */ static bool is_linear(monomial const * m); - + /** \brief Return true if all monomials in p are linear. */ static bool is_linear(polynomial const * p); + /** + \brief Return true if the monomial is a variable. + */ + static bool is_var(monomial const* p, var& v); + + /** + \brief Return true if the polynomial is a variable. + */ + bool is_var(polynomial const* p, var& v); + + /** + \brief Return true if the polynomial is of the form x + k + */ + bool is_var_num(polynomial const* p, var& v, scoped_numeral& n); + /** \brief Return the degree of variable x in p. */ @@ -860,7 +876,13 @@ namespace polynomial { \brief Return true if p is a square, and store its square root in r. */ bool sqrt(polynomial const * p, polynomial_ref & r); - + + + /** + \brief obtain the sign of the polynomial given sign of variables. + */ + lbool sign(polynomial const* p, svector const& sign_of_vars); + /** \brief Return true if p is always positive for any assignment of its variables. @@ -936,6 +958,13 @@ namespace polynomial { return substitute(p, 1, &x, &v); } + /** + \brief Apply substiution [x -> p/q] in r. + That is, given r \in Z[x, y_1, .., y_m] return + polynomial q^k * r(p/q, y_1, .., y_m), where k is the maximal degree of x in r. + */ + void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result); + /** \brief Factorize the given polynomial p and store its factors in r. */ diff --git a/src/nlsat/nlsat_clause.h b/src/nlsat/nlsat_clause.h index 898c32449..93dfb0e80 100644 --- a/src/nlsat/nlsat_clause.h +++ b/src/nlsat/nlsat_clause.h @@ -44,6 +44,8 @@ namespace nlsat { bool is_learned() const { return m_learned; } literal * begin() { return m_lits; } literal * end() { return m_lits + m_size; } + literal const * begin() const { return m_lits; } + literal const * end() const { return m_lits + m_size; } literal const * c_ptr() const { return m_lits; } void inc_activity() { m_activity++; } void set_activity(unsigned v) { m_activity = v; } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index e1dadf12b..4cba6d123 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -18,19 +18,20 @@ Author: Revision History: --*/ +#include "util/z3_exception.h" +#include "util/chashtable.h" +#include "util/id_gen.h" +#include "util/map.h" +#include "util/dependency.h" +#include "util/permutation.h" +#include "math/polynomial/algebraic_numbers.h" +#include "math/polynomial/polynomial_cache.h" #include "nlsat/nlsat_solver.h" #include "nlsat/nlsat_clause.h" #include "nlsat/nlsat_assignment.h" #include "nlsat/nlsat_justification.h" #include "nlsat/nlsat_evaluator.h" #include "nlsat/nlsat_explain.h" -#include "math/polynomial/algebraic_numbers.h" -#include "util/z3_exception.h" -#include "util/chashtable.h" -#include "util/id_gen.h" -#include "util/dependency.h" -#include "math/polynomial/polynomial_cache.h" -#include "util/permutation.h" #include "nlsat/nlsat_params.hpp" #define NLSAT_EXTRA_VERBOSE @@ -68,6 +69,7 @@ namespace nlsat { reslimit& m_rlimit; small_object_allocator m_allocator; + bool m_incremental; unsynch_mpq_manager m_qm; pmanager m_pm; cache m_cache; @@ -78,6 +80,8 @@ namespace nlsat { interval_set_manager & m_ism; ineq_atom_table m_ineq_atoms; root_atom_table m_root_atoms; + svector m_patch_var; + polynomial_ref_vector m_patch_num, m_patch_denom; id_gen m_cid_gen; clause_vector m_clauses; // set of clauses @@ -108,11 +112,12 @@ namespace nlsat { m_perm(perm), m_proc(0) { } - virtual void operator()(std::ostream & out, var x) const { + std::ostream& operator()(std::ostream & out, var x) const { if (m_proc == 0) m_default_display_var(out, x); else (*m_proc)(out, m_perm[x]); + return out; } }; perm_display_var_proc m_display_var; @@ -158,9 +163,10 @@ namespace nlsat { unsigned m_stages; unsigned m_irrational_assignments; // number of irrational witnesses - imp(solver& s, reslimit& rlim, params_ref const & p): + imp(solver& s, reslimit& rlim, params_ref const & p, bool incremental): m_rlimit(rlim), m_allocator("nlsat"), + m_incremental(incremental), m_pm(rlim, m_qm, &m_allocator), m_cache(m_pm), m_am(rlim, m_qm, p, &m_allocator), @@ -168,6 +174,8 @@ namespace nlsat { m_assignment(m_am), m_evaluator(s, m_assignment, m_pm, m_allocator), m_ism(m_evaluator.ism()), + m_patch_num(m_pm), + m_patch_denom(m_pm), m_num_bool_vars(0), m_display_var(m_perm), m_explain(s, m_assignment, m_cache, m_atoms, m_var2eq, m_evaluator), @@ -330,9 +338,7 @@ namespace nlsat { */ bool_var max_bvar(clause const & cls) const { bool_var b = null_bool_var; - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = cls[i]; + for (literal l : cls) { if (b == null_bool_var || l.var() > b) b = l.var(); } @@ -367,9 +373,7 @@ namespace nlsat { if (x == null_var) return 0; unsigned max = 0; - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = c[i]; + for (literal l : c) { atom const * a = m_atoms[l.var()]; if (a == 0) continue; @@ -496,13 +500,12 @@ namespace nlsat { // Delete atoms with ref_count == 0 void del_unref_atoms() { - unsigned sz = m_atoms.size(); - for (unsigned i = 0; i < sz; i++) { - del(m_atoms[i]); + for (auto* a : m_atoms) { + del(a); } } - bool_var mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { + ineq_atom* mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even, bool& is_new) { SASSERT(sz >= 1); SASSERT(k == atom::LT || k == atom::GT || k == atom::EQ); int sign = 1; @@ -522,23 +525,36 @@ namespace nlsat { void * mem = m_allocator.allocate(ineq_atom::get_obj_size(sz)); if (sign < 0) k = atom::flip(k); - ineq_atom * new_atom = new (mem) ineq_atom(k, sz, uniq_ps.c_ptr(), is_even, max); + ineq_atom * tmp_atom = new (mem) ineq_atom(k, sz, uniq_ps.c_ptr(), is_even, max); TRACE("nlsat_table_bug", ineq_atom::hash_proc h; - tout << "mk_ineq_atom hash: " << h(new_atom) << "\n"; display(tout, *new_atom, m_display_var); tout << "\n";); - ineq_atom * old_atom = m_ineq_atoms.insert_if_not_there(new_atom); - CTRACE("nlsat_table_bug", old_atom->max_var() != max, display(tout, *old_atom, m_display_var); tout << "\n";); - SASSERT(old_atom->max_var() == max); - if (old_atom != new_atom) { - deallocate(new_atom); - return old_atom->bvar(); + tout << "mk_ineq_atom hash: " << h(tmp_atom) << "\n"; display(tout, *tmp_atom, m_display_var); tout << "\n";); + ineq_atom * atom = m_ineq_atoms.insert_if_not_there(tmp_atom); + CTRACE("nlsat_table_bug", atom->max_var() != max, display(tout, *atom, m_display_var); tout << "\n";); + SASSERT(atom->max_var() == max); + is_new = (atom == tmp_atom); + if (is_new) { + for (unsigned i = 0; i < sz; i++) { + m_pm.inc_ref(atom->p(i)); + } } - bool_var b = mk_bool_var_core(); - m_atoms[b] = new_atom; - new_atom->m_bool_var = b; - for (unsigned i = 0; i < sz; i++) { - m_pm.inc_ref(new_atom->p(i)); + else { + deallocate(tmp_atom); + } + return atom; + } + + bool_var mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { + bool is_new = false; + ineq_atom* atom = mk_ineq_atom(k, sz, ps, is_even, is_new); + if (!is_new) { + return atom->bvar(); + } + else { + bool_var b = mk_bool_var_core(); + m_atoms[b] = atom; + atom->m_bool_var = b; + return b; } - return b; } literal mk_ineq_literal(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { @@ -619,10 +635,14 @@ namespace nlsat { deallocate(cls); } + void del_clause(clause * cls, clause_vector& clauses) { + clauses.erase(cls); + del_clause(cls); + } + void del_clauses(ptr_vector & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) - del_clause(cs[i]); + for (clause* cp : cs) + del_clause(cp); } void del_clauses() { @@ -927,10 +947,9 @@ namespace nlsat { \brief Return true if the given clause is already satisfied in the current partial interpretation. */ bool is_satisfied(clause const & cls) const { - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { - if (const_cast(this)->value(cls[i]) == l_true) { - TRACE("value_bug:", tout << cls[i] << " := true\n";); + for (literal l : cls) { + if (const_cast(this)->value(l) == l_true) { + TRACE("value_bug:", tout << l << " := true\n";); return true; } } @@ -1023,7 +1042,7 @@ namespace nlsat { SASSERT(x != null_var); if (m_var2eq[x] != 0 && degree(m_var2eq[x]) <= degree(a)) return; // we only update m_var2eq if the new equality has smaller degree - TRACE("simplify_core", tout << "Saving equality for "; m_display_var(tout, x); tout << " (x" << x << ") "; + TRACE("simplify_core", tout << "Saving equality for "; m_display_var(tout, x) << " (x" << x << ") "; tout << "scope-lvl: " << scope_lvl() << "\n"; display(tout, literal(b, false)); tout << "\n";); save_updt_eq_trail(m_var2eq[x]); m_var2eq[x] = a; @@ -1045,10 +1064,9 @@ namespace nlsat { interval_set_ref first_undef_set(m_ism); // infeasible region of the first undefined literal interval_set * xk_set = m_infeasible[m_xk]; // current set of infeasible interval for current variable SASSERT(!m_ism.is_full(xk_set)); - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { + for (unsigned idx = 0; idx < cls.size(); ++idx) { + literal l = cls[idx]; checkpoint(); - literal l = cls[i]; if (value(l) == l_false) continue; SASSERT(value(l) == l_undef); @@ -1085,7 +1103,7 @@ namespace nlsat { } num_undef++; if (first_undef == UINT_MAX) { - first_undef = i; + first_undef = idx; first_undef_set = curr_set; } } @@ -1131,9 +1149,7 @@ namespace nlsat { Return 0, if the set was satisfied, or the violating clause otherwise */ clause * process_clauses(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause * c = cs[i]; + for (clause* c : cs) { if (!process_clause(*c, false)) return c; } @@ -1175,7 +1191,7 @@ namespace nlsat { m_ism.peek_in_complement(m_infeasible[m_xk], m_is_int[m_xk], w, m_randomize); TRACE("nlsat", tout << "infeasible intervals: "; m_ism.display(tout, m_infeasible[m_xk]); tout << "\n"; - tout << "assigning "; m_display_var(tout, m_xk); tout << "(x" << m_xk << ") -> " << w << "\n";); + tout << "assigning "; m_display_var(tout, m_xk) << "(x" << m_xk << ") -> " << w << "\n";); TRACE("nlsat_root", tout << "value as root object: "; m_am.display_root(tout, w); tout << "\n";); if (!m_am.is_rational(w)) m_irrational_assignments++; @@ -1205,6 +1221,7 @@ namespace nlsat { TRACE("nlsat_bug", tout << "xk: x" << m_xk << " bk: b" << m_bk << "\n";); if (m_bk == null_bool_var && m_xk >= num_vars()) { TRACE("nlsat", tout << "found model\n"; display_assignment(tout);); + fix_patch(); return l_true; // all variables were assigned, and all clauses were satisfied. } TRACE("nlsat", tout << "processing variable "; @@ -1295,6 +1312,13 @@ namespace nlsat { init_search(); m_explain.set_full_dimensional(is_full_dimensional()); bool reordered = false; + +#if 0 + // disabled + if (!m_incremental) + simplify(); +#endif + if (!can_reorder()) { } @@ -1497,9 +1521,9 @@ namespace nlsat { TRACE("nlsat_mathematica", display_mathematica_lemma(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr());); TRACE("nlsat_proof_sk", tout << "theory lemma\n"; display_abst(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()); tout << "\n";); TRACE("nlsat_resolve", - tout << "m_xk: " << m_xk << ", "; m_display_var(tout, m_xk); tout << "\n"; + tout << "m_xk: " << m_xk << ", "; m_display_var(tout, m_xk) << "\n"; tout << "new valid clause:\n"; - display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()); tout << "\n";); + display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()) << "\n";); DEBUG_CODE({ unsigned sz = m_lazy_clause.size(); @@ -1633,15 +1657,10 @@ namespace nlsat { TRACE("nlsat_proof", tout << "STARTING RESOLUTION\n";); TRACE("nlsat_proof_sk", tout << "STARTING RESOLUTION\n";); m_conflicts++; - TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause); tout << "\n"; + TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause) << "\n"; tout << "xk: "; if (m_xk != null_var) m_display_var(tout, m_xk); else tout << ""; tout << "\n"; tout << "scope_lvl: " << scope_lvl() << "\n"; tout << "current assignment\n"; display_assignment(tout);); - - // static unsigned counter = 0; - // counter++; - // if (counter > 6) - // exit(0); m_num_marks = 0; m_lemma.reset(); @@ -1750,7 +1769,7 @@ namespace nlsat { SASSERT(m_xk == new_max_var); new_cls = mk_clause(sz, m_lemma.c_ptr(), true, m_lemma_assumptions.get()); TRACE("nlsat", tout << "new_level: " << scope_lvl() << "\nnew_stage: " << new_max_var << " "; - if (new_max_var != null_var) m_display_var(tout, new_max_var); tout << "\n";); + if (new_max_var != null_var) m_display_var(tout, new_max_var) << "\n";); } else { SASSERT(scope_lvl() >= 1); @@ -1931,11 +1950,12 @@ namespace nlsat { collect(*(cs[i])); } - void display(std::ostream & out, display_var_proc const & proc) { + std::ostream& display(std::ostream & out, display_var_proc const & proc) { unsigned sz = m_num_occs.size(); for (unsigned i = 0; i < sz; i++) { proc(out, i); out << " -> " << m_max_degree[i] << " : " << m_num_occs[i] << "\n"; } + return out; } }; @@ -2169,12 +2189,10 @@ namespace nlsat { } void reattach_arith_clauses(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause & c = *cs[i]; - var x = max_var(c); + for (clause* cp : cs) { + var x = max_var(*cp); if (x != null_var) - m_watches[x].push_back(&c); + m_watches[x].push_back(cp); } } @@ -2251,18 +2269,16 @@ namespace nlsat { } bool is_full_dimensional(clause const & c) const { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_full_dimensional(c[i])) + for (literal l : c) { + if (!is_full_dimensional(l)) return false; } return true; } bool is_full_dimensional(clause_vector const & cs) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_full_dimensional(*(cs[i]))) + for (clause* c : cs) { + if (!is_full_dimensional(*c)) return false; } return true; @@ -2272,13 +2288,271 @@ namespace nlsat { return is_full_dimensional(m_clauses); } + + // ----------------------- + // + // Simplification + // + // ----------------------- + + // solve simple equalities + // TBD WU-Reit decomposition? + + /** + \brief isolate variables in unit equalities. + Assume a clause is c == v*p + q + and the context implies p > 0 + + replace v by -q/p + remove clause c, + The for other occurrences of v, + replace v*r + v*v*r' > 0 by + by p*p*v*r + p*p*v*v*r' > 0 + by p*q*r + q*q*r' > 0 + + The method ignores lemmas and assumes constraints don't use roots. + */ + + void simplify() { + polynomial_ref p(m_pm), q(m_pm); + var v; + init_var_signs(); + SASSERT(m_learned.empty()); + bool change = true; + while (change) { + change = false; + for (clause* c : m_clauses) { + if (solve_var(*c, v, p, q)) { + q = -q; + m_patch_var.push_back(v); + m_patch_num.push_back(q); + m_patch_denom.push_back(p); + del_clause(c, m_clauses); + substitute_var(v, p, q); + change = true; + break; + } + } + } + } + + void fix_patch() { + for (unsigned i = m_patch_var.size(); i-- > 0; ) { + var v = m_patch_var[i]; + poly* q = m_patch_num.get(i); + poly* p = m_patch_denom.get(i); + scoped_anum pv(m_am), qv(m_am), val(m_am); + m_pm.eval(p, m_assignment, pv); + m_pm.eval(q, m_assignment, qv); + val = qv / pv; + TRACE("nlsat", + m_display_var(tout << "patch ", v) << "\n"; + if (m_assignment.is_assigned(v)) m_am.display(tout << "previous value: ", m_assignment.value(v)); tout << "\n"; + m_am.display(tout << "updated value: ", val); tout << "\n"; + ); + m_assignment.set_core(v, val); + } + } + + void substitute_var(var x, poly* p, poly* q) { + polynomial_ref pr(m_pm); + polynomial_ref_vector ps(m_pm); + u_map b2l; + svector even; + unsigned num_atoms = m_atoms.size(); + for (unsigned j = 0; j < num_atoms; ++j) { + atom* a = m_atoms[j]; + if (a && a->is_ineq_atom()) { + ineq_atom const& a1 = *to_ineq_atom(a); + unsigned sz = a1.size(); + ps.reset(); + even.reset(); + bool change = false; + for (unsigned i = 0; i < sz; ++i) { + poly * po = a1.p(i); + m_pm.substitute(po, x, q, p, pr); + ps.push_back(pr); + even.push_back(a1.is_even(i)); + change |= pr != po; + if (m_pm.is_zero(pr)) { + ps.reset(); + even.reset(); + change = true; + break; + } + } + if (!change) continue; + literal l = mk_ineq_literal(a1.get_kind(), ps.size(), ps.c_ptr(), even.c_ptr()); + if (a1.m_bool_var != l.var()) { + b2l.insert(a1.m_bool_var, l); + inc_ref(l); + } + } + } + update_clauses(b2l); + for (auto const& kv : b2l) { + dec_ref(kv.m_value); + } + } + + + void update_clauses(u_map const& b2l) { + literal_vector lits; + clause_vector to_delete; + unsigned n = m_clauses.size(); + for (unsigned i = 0; i < n; ++i) { + clause* c = m_clauses[i]; + lits.reset(); + bool changed = false; + bool is_tautology = false; + for (literal l : *c) { + literal lit = null_literal; + if (b2l.find(l.var(), lit)) { + lit = l.sign() ? ~lit : lit; + if (lit == true_literal) { + is_tautology = true; + } + else if (lit != false_literal) { + lits.push_back(lit); + } + changed = true; + } + else { + lits.push_back(l); + } + } + if (changed) { + to_delete.push_back(c); + if (!is_tautology) { + mk_clause(lits.size(), lits.c_ptr(), c->is_learned(), static_cast<_assumption_set>(c->assumptions())); + } + } + } + for (clause* c : to_delete) { + del_clause(c, m_clauses); + } + } + + bool is_unit_ineq(clause const& c) const { + return + c.size() == 1 && + m_atoms[c[0].var()] && + m_atoms[c[0].var()]->is_ineq_atom(); + } + + bool is_unit_eq(clause const& c) const { + return + is_unit_ineq(c) && + !c[0].sign() && + m_atoms[c[0].var()]->is_eq(); + } + + /** + \brief determine whether the clause is a comparison v > k or v < k', where k >= 0 or k' <= 0. + */ + lbool is_cmp0(clause const& c, var& v) { + if (!is_unit_ineq(c)) return l_undef; + literal lit = c[0]; + ineq_atom const& a = *to_ineq_atom(m_atoms[lit.var()]); + bool sign = lit.sign(); + poly * p0; + if (!is_single_poly(a, p0)) return l_undef; + if (m_pm.is_var(p0, v)) { + if (!sign && a.get_kind() == atom::GT) { + return l_true; + } + if (!sign && a.get_kind() == atom::LT) { + return l_false; + } + return l_undef; + } + polynomial::scoped_numeral n(m_pm.m()); + if (m_pm.is_var_num(p0, v, n)) { + // x - k > 0 + if (!sign && a.get_kind() == atom::GT && m_pm.m().is_nonneg(n)) { + return l_true; + } + // x + k < 0 + if (!sign && a.get_kind() == atom::LT && m_pm.m().is_nonpos(n)) { + return l_false; + } + // !(x + k > 0) + if (sign && a.get_kind() == atom::GT && m_pm.m().is_pos(n)) { + return l_false; + } + // !(x - k < 0) + if (sign && a.get_kind() == atom::LT && m_pm.m().is_neg(n)) { + return l_true; + } + } + return l_undef; + } + + bool is_single_poly(ineq_atom const& a, poly*& p) { + unsigned sz = a.size(); + return sz == 1 && a.is_odd(0) && (p = a.p(0), true); + } + + svector m_var_signs; + + void init_var_signs() { + m_var_signs.reset(); + for (clause* cp : m_clauses) { + clause& c = *cp; + var x = 0; + lbool cmp = is_cmp0(c, x); + switch (cmp) { + case l_true: + m_var_signs.setx(x, l_true, l_undef); + break; + case l_false: + m_var_signs.setx(x, l_false, l_undef); + break; + default: + break; + } + } + } + + /** + \brief returns true then c is an equality that is equivalent to v*p + q, + and p > 0, v does not occur in p, q. + */ + bool solve_var(clause& c, var& v, polynomial_ref& p, polynomial_ref& q) { + poly* p0; + if (!is_unit_eq(c)) return false; + ineq_atom & a = *to_ineq_atom(m_atoms[c[0].var()]); + if (!is_single_poly(a, p0)) return false; + var mx = max_var(p0); + if (mx >= m_is_int.size()) return false; + for (var x = 0; x <= mx; ++x) { + if (m_is_int[x]) continue; + if (1 == m_pm.degree(p0, x)) { + p = m_pm.coeff(p0, x, 1, q); + switch (m_pm.sign(p, m_var_signs)) { + case l_true: + v = x; + return true; + case l_false: + v = x; + p = -p; + q = -q; + return true; + default: + break; + } + } + } + return false; + } + // ----------------------- // // Pretty printing // // ----------------------- - void display_num_assignment(std::ostream & out, display_var_proc const & proc) const { + std::ostream& display_num_assignment(std::ostream & out, display_var_proc const & proc) const { for (var x = 0; x < num_vars(); x++) { if (m_assignment.is_assigned(x)) { proc(out, x); @@ -2287,9 +2561,10 @@ namespace nlsat { out << "\n"; } } + return out; } - void display_bool_assignment(std::ostream & out) const { + std::ostream& display_bool_assignment(std::ostream & out) const { unsigned sz = m_atoms.size(); for (bool_var b = 0; b < sz; b++) { if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) { @@ -2300,6 +2575,7 @@ namespace nlsat { for (bool_var b = 0; b < sz; b++) { out << "b" << b << " -> " << m_bvalues[b] << " " << m_atoms[b] << "\n"; }); + return out; } bool display_mathematica_assignment(std::ostream & out) const { @@ -2317,16 +2593,17 @@ namespace nlsat { return !first; } - void display_num_assignment(std::ostream & out) const { - display_num_assignment(out, m_display_var); + std::ostream& display_num_assignment(std::ostream & out) const { + return display_num_assignment(out, m_display_var); } - void display_assignment(std::ostream& out) const { + std::ostream& display_assignment(std::ostream& out) const { display_bool_assignment(out); display_num_assignment(out); + return out; } - void display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { + std::ostream& display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { unsigned sz = a.size(); for (unsigned i = 0; i < sz; i++) { if (use_star && i > 0) @@ -2346,9 +2623,10 @@ namespace nlsat { case atom::EQ: out << " = 0"; break; default: UNREACHABLE(); break; } + return out; } - - void display_mathematica(std::ostream & out, ineq_atom const & a) const { + + std::ostream& display_mathematica(std::ostream & out, ineq_atom const & a) const { unsigned sz = a.size(); for (unsigned i = 0; i < sz; i++) { if (i > 0) @@ -2370,9 +2648,10 @@ namespace nlsat { case atom::EQ: out << " == 0"; break; default: UNREACHABLE(); break; } + return out; } - void display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { switch (a.get_kind()) { case atom::LT: out << "(< "; break; case atom::GT: out << "(> "; break; @@ -2398,9 +2677,10 @@ namespace nlsat { if (sz > 1) out << ")"; out << " 0)"; + return out; } - void display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { proc(out, a.x()); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; @@ -2413,21 +2693,22 @@ namespace nlsat { out << "root[" << a.i() << "]("; m_pm.display(out, a.p(), proc); out << ")"; + return out; } struct mathematica_var_proc : public display_var_proc { var m_x; public: mathematica_var_proc(var x):m_x(x) {} - virtual void operator()(std::ostream & out, var x) const { + virtual std::ostream& operator()(std::ostream & out, var x) const { if (m_x == x) - out << "#1"; + return out << "#1"; else - out << "x" << x; + return out << "x" << x; } }; - void display_mathematica(std::ostream & out, root_atom const & a) const { + std::ostream& display_mathematica(std::ostream & out, root_atom const & a) const { out << "x" << a.x(); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; @@ -2440,65 +2721,74 @@ namespace nlsat { out << "Root["; m_pm.display(out, a.p(), mathematica_var_proc(a.x()), true); out << " &, " << a.i() << "]"; + return out; } - void display_smt2(std::ostream & out, root_atom const & a) const { + std::ostream& display_smt2(std::ostream & out, root_atom const & a) const { NOT_IMPLEMENTED_YET(); + return out; } - void display(std::ostream & out, atom const & a, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, atom const & a, display_var_proc const & proc) const { if (a.is_ineq_atom()) - display(out, static_cast(a), proc); + return display(out, static_cast(a), proc); else - display(out, static_cast(a), proc); + return display(out, static_cast(a), proc); } - void display_mathematica(std::ostream & out, atom const & a) const { - if (a.is_ineq_atom()) - display_mathematica(out, static_cast(a)); - else - display_mathematica(out, static_cast(a)); + std::ostream& display(std::ostream & out, atom const & a) const { + return display(out, a, m_display_var); } - void display_smt2(std::ostream & out, atom const & a, display_var_proc const & proc) const { + std::ostream& display_mathematica(std::ostream & out, atom const & a) const { if (a.is_ineq_atom()) - display_smt2(out, static_cast(a), proc); + return display_mathematica(out, static_cast(a)); else - display_smt2(out, static_cast(a), proc); + return display_mathematica(out, static_cast(a)); } - void display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, atom const & a, display_var_proc const & proc) const { + if (a.is_ineq_atom()) + return display_smt2(out, static_cast(a), proc); + else + return display_smt2(out, static_cast(a), proc); + } + + std::ostream& display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { if (b == 0) out << "true"; else if (m_atoms[b] == 0) out << "b" << b; else display(out, *(m_atoms[b]), proc); + return out; } - void display_atom(std::ostream & out, bool_var b) const { - display_atom(out, b, m_display_var); + std::ostream& display_atom(std::ostream & out, bool_var b) const { + return display_atom(out, b, m_display_var); } - void display_mathematica_atom(std::ostream & out, bool_var b) const { + std::ostream& display_mathematica_atom(std::ostream & out, bool_var b) const { if (b == 0) out << "(0 < 1)"; else if (m_atoms[b] == 0) out << "b" << b; else display_mathematica(out, *(m_atoms[b])); + return out; } - void display_smt2_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { + std::ostream& display_smt2_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { if (b == 0) out << "true"; else if (m_atoms[b] == 0) out << "b" << b; else display_smt2(out, *(m_atoms[b]), proc); + return out; } - void display(std::ostream & out, literal l, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, literal l, display_var_proc const & proc) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2511,13 +2801,14 @@ namespace nlsat { else { display_atom(out, l.var(), proc); } + return out; } - void display(std::ostream & out, literal l) const { - display(out, l, m_display_var); + std::ostream& display(std::ostream & out, literal l) const { + return display(out, l, m_display_var); } - void display_mathematica(std::ostream & out, literal l) const { + std::ostream& display_mathematica(std::ostream & out, literal l) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2530,9 +2821,10 @@ namespace nlsat { else { display_mathematica_atom(out, l.var()); } + return out; } - void display_smt2(std::ostream & out, literal l, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, literal l, display_var_proc const & proc) const { if (l.sign()) { bool_var b = l.var(); out << "(not "; @@ -2542,41 +2834,43 @@ namespace nlsat { else { display_smt2_atom(out, l.var(), proc); } + return out; } - void display_assumptions(std::ostream & out, _assumption_set s) const { - + std::ostream& display_assumptions(std::ostream & out, _assumption_set s) const { + return out; } - void display(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { for (unsigned i = 0; i < num; i++) { if (i > 0) out << " or "; display(out, ls[i], proc); } + return out; } - void display(std::ostream & out, unsigned num, literal const * ls) { - display(out, num, ls, m_display_var); + std::ostream& display(std::ostream & out, unsigned num, literal const * ls) { + return display(out, num, ls, m_display_var); + } + + std::ostream& display(std::ostream & out, scoped_literal_vector const & cs) { + return display(out, cs.size(), cs.c_ptr(), m_display_var); } - void display(std::ostream & out, scoped_literal_vector const & cs) { - display(out, cs.size(), cs.c_ptr(), m_display_var); - } - - void display(std::ostream & out, clause const & c, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, clause const & c, display_var_proc const & proc) const { if (c.assumptions() != 0) { display_assumptions(out, static_cast<_assumption_set>(c.assumptions())); out << " |- "; } - display(out, c.size(), c.c_ptr(), proc); + return display(out, c.size(), c.c_ptr(), proc); } - void display(std::ostream & out, clause const & c) const { - display(out, c, m_display_var); + std::ostream& display(std::ostream & out, clause const & c) const { + return display(out, c, m_display_var); } - void display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { if (num == 0) { out << "false"; } @@ -2591,13 +2885,14 @@ namespace nlsat { } out << ")"; } + return out; } - void display_smt2(std::ostream & out, clause const & c, display_var_proc const & proc = display_var_proc()) const { - display_smt2(out, c.size(), c.c_ptr(), proc); + std::ostream& display_smt2(std::ostream & out, clause const & c, display_var_proc const & proc = display_var_proc()) const { + return display_smt2(out, c.size(), c.c_ptr(), proc); } - void display_abst(std::ostream & out, literal l) const { + std::ostream& display_abst(std::ostream & out, literal l) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2609,25 +2904,27 @@ namespace nlsat { else { out << "b" << l.var(); } + return out; } - void display_abst(std::ostream & out, unsigned num, literal const * ls) const { + std::ostream& display_abst(std::ostream & out, unsigned num, literal const * ls) const { for (unsigned i = 0; i < num; i++) { if (i > 0) out << " or "; display_abst(out, ls[i]); } + return out; } - void display_abst(std::ostream & out, scoped_literal_vector const & cs) const { - display_abst(out, cs.size(), cs.c_ptr()); + std::ostream& display_abst(std::ostream & out, scoped_literal_vector const & cs) const { + return display_abst(out, cs.size(), cs.c_ptr()); } - void display_abst(std::ostream & out, clause const & c) const { - display_abst(out, c.size(), c.c_ptr()); + std::ostream& display_abst(std::ostream & out, clause const & c) const { + return display_abst(out, c.size(), c.c_ptr()); } - void display_mathematica(std::ostream & out, clause const & c) const { + std::ostream& display_mathematica(std::ostream & out, clause const & c) const { out << "("; unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) { @@ -2636,12 +2933,13 @@ namespace nlsat { display_mathematica(out, c[i]); } out << ")"; + return out; } // Debugging support: // Display generated lemma in Mathematica format. // Mathematica must reduce lemma to True (modulo resource constraints). - void display_mathematica_lemma(std::ostream & out, unsigned num, literal const * ls, bool include_assignment = false) const { + std::ostream& display_mathematica_lemma(std::ostream & out, unsigned num, literal const * ls, bool include_assignment = false) const { out << "Resolve[ForAll[{"; // var definition for (unsigned i = 0; i < num_vars(); i++) { @@ -2662,71 +2960,69 @@ namespace nlsat { display_mathematica(out, ls[i]); } out << "], Reals]\n"; // end of exists + return out; } - void display(std::ostream & out, clause_vector const & cs, display_var_proc const & proc) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - display(out, *(cs[i]), proc); - out << "\n"; + std::ostream& display(std::ostream & out, clause_vector const & cs, display_var_proc const & proc) const { + for (clause* c : cs) { + display(out, *c, proc) << "\n"; } + return out; } - void display(std::ostream & out, clause_vector const & cs) const { - display(out, cs, m_display_var); + std::ostream& display(std::ostream & out, clause_vector const & cs) const { + return display(out, cs, m_display_var); } - void display_mathematica(std::ostream & out, clause_vector const & cs) const { + std::ostream& display_mathematica(std::ostream & out, clause_vector const & cs) const { unsigned sz = cs.size(); for (unsigned i = 0; i < sz; i++) { if (i > 0) out << ",\n"; - out << " "; - display_mathematica(out, *(cs[i])); + display_mathematica(out << " ", *(cs[i])); } + return out; } - void display_abst(std::ostream & out, clause_vector const & cs) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - display_abst(out, *(cs[i])); - out << "\n"; + std::ostream& display_abst(std::ostream & out, clause_vector const & cs) const { + for (clause* c : cs) { + display_abst(out, *c) << "\n"; } + return out; } - void display(std::ostream & out, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, display_var_proc const & proc) const { display(out, m_clauses, proc); if (!m_learned.empty()) { - out << "Lemmas:\n"; - display(out, m_learned, proc); + display(out << "Lemmas:\n", m_learned, proc); } + return out; } - void display_mathematica(std::ostream & out) const { - out << "{\n"; - display_mathematica(out, m_clauses); - out << "}\n"; + std::ostream& display_mathematica(std::ostream & out) const { + return display_mathematica(out << "{\n", m_clauses) << "}\n"; } - void display_abst(std::ostream & out) const { + std::ostream& display_abst(std::ostream & out) const { display_abst(out, m_clauses); if (!m_learned.empty()) { - out << "Lemmas:\n"; - display_abst(out, m_learned); + display_abst(out << "Lemmas:\n", m_learned); } + return out; } - void display(std::ostream & out) const { + std::ostream& display(std::ostream & out) const { display(out, m_display_var); - display_assignment(out); + return display_assignment(out); } - void display_vars(std::ostream & out) const { + std::ostream& display_vars(std::ostream & out) const { for (unsigned i = 0; i < num_vars(); i++) { out << i << " -> "; m_display_var(out, i); out << "\n"; } + return out; } - void display_smt2_arith_decls(std::ostream & out) const { + std::ostream& display_smt2_arith_decls(std::ostream & out) const { unsigned sz = m_is_int.size(); for (unsigned i = 0; i < sz; i++) { if (m_is_int[i]) @@ -2734,31 +3030,32 @@ namespace nlsat { else out << "(declare-fun x" << i << " () Real)\n"; } + return out; } - void display_smt2_bool_decls(std::ostream & out) const { + std::ostream& display_smt2_bool_decls(std::ostream & out) const { unsigned sz = m_atoms.size(); for (unsigned i = 0; i < sz; i++) { if (m_atoms[i] == 0) out << "(declare-fun b" << i << " () Bool)\n"; } + return out; } - void display_smt2(std::ostream & out) const { + std::ostream& display_smt2(std::ostream & out) const { display_smt2_bool_decls(out); display_smt2_arith_decls(out); out << "(assert (and true\n"; - unsigned sz = m_clauses.size(); - for (unsigned i = 0; i < sz; i++) { - display_smt2(out, *(m_clauses[i])); - out << "\n"; + for (clause* c : m_clauses) { + display_smt2(out, *c) << "\n"; } out << "))\n(check-sat)" << std::endl; + return out; } }; - solver::solver(reslimit& rlim, params_ref const & p) { - m_imp = alloc(imp, *this, rlim, p); + solver::solver(reslimit& rlim, params_ref const & p, bool incremental) { + m_imp = alloc(imp, *this, rlim, p, incremental); } solver::~solver() { diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index ac503c603..c632a0334 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -35,7 +35,7 @@ namespace nlsat { struct imp; imp * m_imp; public: - solver(reslimit& rlim, params_ref const & p); + solver(reslimit& rlim, params_ref const & p, bool incremental); ~solver(); /** diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index db3b6ffa5..647a5e3ee 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -47,6 +47,8 @@ namespace nlsat { typedef polynomial::var_vector var_vector; typedef polynomial::manager pmanager; typedef polynomial::polynomial poly; + typedef polynomial::monomial monomial; + typedef polynomial::numeral numeral; const var null_var = polynomial::null_var; const var true_bool_var = 0; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 510f503e7..9de7215e3 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -32,11 +32,11 @@ class nlsat_tactic : public tactic { ast_manager & m; expr_ref_vector m_var2expr; expr_display_var_proc(ast_manager & _m):m(_m), m_var2expr(_m) {} - virtual void operator()(std::ostream & out, nlsat::var x) const { + virtual std::ostream& operator()(std::ostream & out, nlsat::var x) const { if (x < m_var2expr.size()) - out << mk_ismt2_pp(m_var2expr.get(x), m); + return out << mk_ismt2_pp(m_var2expr.get(x), m); else - out << "x!" << x; + return out << "x!" << x; } }; @@ -51,7 +51,7 @@ class nlsat_tactic : public tactic { m(_m), m_params(p), m_display_var(_m), - m_solver(m.limit(), p) { + m_solver(m.limit(), p, false) { } void updt_params(params_ref const & p) { diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index 22f64af47..47b9e0505 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -48,11 +48,15 @@ tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & 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), diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index ab5095328..e28f6ae4f 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -782,7 +782,7 @@ namespace qe { m(m), m_mode(mode), m_params(p), - m_solver(m.limit(), p), + m_solver(m.limit(), p, true), m_nftactic(0), m_rmodel(m_solver.am()), m_rmodel0(m_solver.am()), diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 65d474182..5df523ff7 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -44,6 +44,7 @@ class solve_eqs_tactic : public tactic { expr_sparse_mark m_candidate_set; ptr_vector m_candidates; ptr_vector m_vars; + expr_sparse_mark m_nonzero; ptr_vector m_ordered_vars; bool m_produce_proofs; bool m_produce_unsat_cores; @@ -55,8 +56,7 @@ class solve_eqs_tactic : public tactic { m_r_owner(r == 0 || owner), m_a_util(m), m_num_steps(0), - m_num_eliminated_vars(0) - { + m_num_eliminated_vars(0) { updt_params(p); if (m_r == 0) m_r = mk_default_expr_replacer(m); @@ -78,7 +78,7 @@ class solve_eqs_tactic : public tactic { void checkpoint() { if (m().canceled()) throw tactic_exception(m().limit().get_cancel_msg()); - cooperate("solve-eqs"); + cooperate("solve-eqs"); } // Check if the number of occurrences of t is below the specified threshold :solve-eqs-max-occs @@ -106,7 +106,8 @@ class solve_eqs_tactic : public tactic { } } bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { - if (trivial_solve1(lhs, rhs, var, def, pr)) return true; + if (trivial_solve1(lhs, rhs, var, def, pr)) + return true; if (trivial_solve1(rhs, lhs, var, def, pr)) { if (m_produce_proofs) { pr = m().mk_commutativity(m().mk_eq(lhs, rhs)); @@ -187,6 +188,77 @@ class solve_eqs_tactic : public tactic { } return false; } + + void add_pos(expr* f) { + expr* lhs = nullptr, *rhs = nullptr; + rational val; + if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_neg()) { + m_nonzero.mark(lhs); + } + else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_pos()) { + m_nonzero.mark(lhs); + } + else if (m().is_not(f, f)) { + if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_neg()) { + m_nonzero.mark(lhs); + } + else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_pos()) { + m_nonzero.mark(lhs); + } + else if (m().is_eq(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_zero()) { + m_nonzero.mark(lhs); + } + } + } + + bool is_nonzero(expr* e) { + return m_nonzero.is_marked(e); + } + + bool isolate_var(app* arg, app_ref& var, expr_ref& div, unsigned i, app* lhs, expr* rhs) { + if (!m_a_util.is_mul(arg)) return false; + unsigned n = arg->get_num_args(); + for (unsigned j = 0; j < n; ++j) { + expr* e = arg->get_arg(j); + bool ok = is_uninterp_const(e) && check_occs(e) && !occurs(e, rhs) && !occurs_except(e, lhs, i); + if (!ok) continue; + var = to_app(e); + for (unsigned k = 0; ok && k < n; ++k) { + expr* arg_k = arg->get_arg(k); + ok = k == j || (!occurs(var, arg_k) && is_nonzero(arg_k)); + } + if (!ok) continue; + ptr_vector args; + for (unsigned k = 0; k < n; ++k) { + if (k != j) args.push_back(arg->get_arg(k)); + } + div = m_a_util.mk_mul(args.size(), args.c_ptr()); + return true; + } + return false; + } + + bool solve_nl(app * lhs, expr * rhs, expr* eq, app_ref& var, expr_ref & def, proof_ref & pr) { + SASSERT(m_a_util.is_add(lhs)); + if (m_a_util.is_int(lhs)) return false; + unsigned num = lhs->get_num_args(); + expr_ref div(m()); + for (unsigned i = 0; i < num; i++) { + expr * arg = lhs->get_arg(i); + if (is_app(arg) && isolate_var(to_app(arg), var, div, i, lhs, rhs)) { + ptr_vector args; + for (unsigned k = 0; k < num; ++k) { + if (k != i) args.push_back(lhs->get_arg(k)); + } + def = m_a_util.mk_sub(rhs, m_a_util.mk_add(args.size(), args.c_ptr())); + def = m_a_util.mk_div(def, div); + if (m_produce_proofs) + pr = m().mk_rewrite(eq, m().mk_eq(var, def)); + return true; + } + } + return false; + } bool solve_arith_core(app * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { SASSERT(m_a_util.is_add(lhs)); @@ -204,7 +276,8 @@ class solve_eqs_tactic : public tactic { break; } else if (m_a_util.is_mul(arg, a, v) && - is_uninterp_const(v) && !m_candidate_vars.is_marked(v) && + is_uninterp_const(v) && + !m_candidate_vars.is_marked(v) && m_a_util.is_numeral(a, a_val) && !a_val.is_zero() && (!is_int || a_val.is_minus_one()) && @@ -252,16 +325,20 @@ class solve_eqs_tactic : public tactic { return (m_a_util.is_add(lhs) && solve_arith_core(to_app(lhs), rhs, eq, var, def, pr)) || (m_a_util.is_add(rhs) && solve_arith_core(to_app(rhs), lhs, eq, var, def, pr)); +#if 0 + // better done inside of nlsat + (m_a_util.is_add(lhs) && solve_nl(to_app(lhs), rhs, eq, var, def, pr)) || + (m_a_util.is_add(rhs) && solve_nl(to_app(rhs), lhs, eq, var, def, pr)); +#endif } bool solve(expr * f, app_ref & var, expr_ref & def, proof_ref & pr) { - if (m().is_eq(f)) { - if (trivial_solve(to_app(f)->get_arg(0), to_app(f)->get_arg(1), var, def, pr)) + expr* arg1 = 0, *arg2 = 0; + if (m().is_eq(f, arg1, arg2)) { + if (trivial_solve(arg1, arg2, var, def, pr)) return true; if (m_theory_solver) { - expr * lhs = to_app(f)->get_arg(0); - expr * rhs = to_app(f)->get_arg(1); - if (solve_arith(lhs, rhs, f, var, def, pr)) + if (solve_arith(arg1, arg2, f, var, def, pr)) return true; } return false; @@ -321,11 +398,14 @@ class solve_eqs_tactic : public tactic { m_candidate_set.reset(); m_candidates.reset(); m_vars.reset(); - + m_nonzero.reset(); app_ref var(m()); expr_ref def(m()); proof_ref pr(m()); unsigned size = g.size(); + for (unsigned idx = 0; idx < size; idx++) { + add_pos(g.form(idx)); + } for (unsigned idx = 0; idx < size; idx++) { checkpoint(); expr * f = g.form(idx); @@ -347,10 +427,8 @@ class solve_eqs_tactic : public tactic { TRACE("solve_eqs", tout << "candidate vars:\n"; - ptr_vector::iterator it = m_vars.begin(); - ptr_vector::iterator end = m_vars.end(); - for (; it != end; ++it) { - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_vars) { + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); } @@ -374,12 +452,9 @@ class solve_eqs_tactic : public tactic { typedef std::pair frame; svector todo; - ptr_vector::const_iterator it = m_vars.begin(); - ptr_vector::const_iterator end = m_vars.end(); - unsigned num; - for (; it != end; ++it) { + unsigned num = 0; + for (app* v : m_vars) { checkpoint(); - app * v = *it; if (!m_candidate_vars.is_marked(v)) continue; todo.push_back(frame(v, 0)); @@ -483,20 +558,19 @@ class solve_eqs_tactic : public tactic { } // cleanup - it = m_vars.begin(); - for (unsigned idx = 0; it != end; ++it, ++idx) { - if (!m_candidate_vars.is_marked(*it)) { + unsigned idx = 0; + for (expr* v : m_vars) { + if (!m_candidate_vars.is_marked(v)) { m_candidate_set.mark(m_candidates[idx], false); } + ++idx; } TRACE("solve_eqs", tout << "ordered vars:\n"; - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - SASSERT(m_candidate_vars.is_marked(*it)); - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_ordered_vars) { + SASSERT(m_candidate_vars.is_marked(v)); + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); m_candidate_vars.reset(); @@ -609,10 +683,7 @@ class solve_eqs_tactic : public tactic { if (m_produce_models) { if (mc.get() == 0) mc = alloc(gmc, m()); - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - app * v = *it; + for (app* v : m_ordered_vars) { expr * def = 0; proof * pr; expr_dependency * dep; From b78c538e021763ef6608801bfa84d593964a63f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Dec 2017 22:58:41 -0800 Subject: [PATCH 0427/1283] fix build of test Signed-off-by: Nikolaj Bjorner --- src/test/nlsat.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/nlsat.cpp b/src/test/nlsat.cpp index ecf73843f..19add1fab 100644 --- a/src/test/nlsat.cpp +++ b/src/test/nlsat.cpp @@ -272,7 +272,7 @@ static void tst4() { static void tst5() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -330,7 +330,7 @@ static nlsat::literal mk_eq(nlsat::solver& s, nlsat::poly* p) { static void tst6() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -390,7 +390,7 @@ static void tst6() { static void tst7() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); nlsat::pmanager & pm = s.pm(); nlsat::var x0, x1, x2, a, b, c, d; a = s.mk_var(false); @@ -443,7 +443,7 @@ static void tst7() { static void tst8() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -492,7 +492,7 @@ static void tst8() { static void tst9() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -624,7 +624,7 @@ static bool satisfies_root(nlsat::solver& s, nlsat::atom::kind k, nlsat::poly* p static void tst10() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); From 8dadd30db5e1f09739bcb877e9dc5fb3240b1cf9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 17:11:43 -0800 Subject: [PATCH 0428/1283] add __copy__, __deepcopy__ as alias to translate on same context #1427. Add generalized Gaussian elimination as an option to first-pass NL solver Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 24 +++++++++++++++++++ .../bit_blaster/bit_blaster_tpl_def.h | 1 - src/nlsat/nlsat_params.pyg | 1 + src/nlsat/nlsat_solver.cpp | 7 +++--- src/tactic/smtlogics/qfnra_tactic.cpp | 6 +++-- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4cc401156..20c521df6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -365,6 +365,12 @@ class AstRef(Z3PPObject): _z3_assert(isinstance(target, Context), "argument must be a Z3 context") return _to_ast_ref(Z3_translate(self.ctx.ref(), self.as_ast(), target.ref()), target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def hash(self): """Return a hashcode for the `self`. @@ -5048,6 +5054,12 @@ class Goal(Z3PPObject): _z3_assert(isinstance(target, Context), "target must be a context") return Goal(goal=Z3_goal_translate(self.ctx.ref(), self.goal, target.ref()), ctx=target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def simplify(self, *arguments, **keywords): """Return a new simplified goal. @@ -5230,6 +5242,12 @@ class AstVector(Z3PPObject): """ return AstVector(Z3_ast_vector_translate(self.ctx.ref(), self.vector, other_ctx.ref()), other_ctx) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def __repr__(self): return obj_to_string(self) @@ -6430,6 +6448,12 @@ class Solver(Z3PPObject): solver = Z3_solver_translate(self.ctx.ref(), self.solver, target.ref()) return Solver(solver, target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def sexpr(self): """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index a80994f6c..cf7e7c951 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -1193,7 +1193,6 @@ bool bit_blaster_tpl::mk_const_case_multiplier(unsigned sz, expr * const * return false; } SASSERT(out_bits.empty()); - ptr_buffer na_bits; na_bits.append(sz, a_bits); ptr_buffer nb_bits; diff --git a/src/nlsat/nlsat_params.pyg b/src/nlsat/nlsat_params.pyg index 6b1577113..0f2e03069 100644 --- a/src/nlsat/nlsat_params.pyg +++ b/src/nlsat/nlsat_params.pyg @@ -10,6 +10,7 @@ def_module_params('nlsat', ('randomize', BOOL, True, "randomize selection of a witness in nlsat."), ('max_conflicts', UINT, UINT_MAX, "maximum number of conflicts."), ('shuffle_vars', BOOL, False, "use a random variable order."), + ('inline_vars', BOOL, False, "inline variables that can be isolated from equations"), ('seed', UINT, 0, "random seed."), ('factor', BOOL, True, "factor polynomials produced during conflict resolution.") )) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 4cba6d123..448aa624d 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -154,6 +154,7 @@ namespace nlsat { bool m_randomize; bool m_random_order; unsigned m_random_seed; + bool m_inline_vars; unsigned m_max_conflicts; // statistics @@ -210,6 +211,7 @@ namespace nlsat { m_max_conflicts = p.max_conflicts(); m_random_order = p.shuffle_vars(); m_random_seed = p.seed(); + m_inline_vars = p.inline_vars(); m_ism.set_seed(m_random_seed); m_explain.set_simplify_cores(m_simplify_cores); m_explain.set_minimize_cores(min_cores); @@ -1313,11 +1315,8 @@ namespace nlsat { m_explain.set_full_dimensional(is_full_dimensional()); bool reordered = false; -#if 0 - // disabled - if (!m_incremental) + if (!m_incremental && m_inline_vars) simplify(); -#endif if (!can_reorder()) { diff --git a/src/tactic/smtlogics/qfnra_tactic.cpp b/src/tactic/smtlogics/qfnra_tactic.cpp index 63c09c19c..cc01950a2 100644 --- a/src/tactic/smtlogics/qfnra_tactic.cpp +++ b/src/tactic/smtlogics/qfnra_tactic.cpp @@ -33,7 +33,9 @@ static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigne } tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { - params_ref p1 = p; + params_ref p0 = p; + p0.set_bool("inline_vars", true); + params_ref p1 = p; p1.set_uint("seed", 11); p1.set_bool("factor", false); params_ref p2 = p; @@ -42,7 +44,7 @@ tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { return and_then(mk_simplify_tactic(m, p), mk_propagate_values_tactic(m, p), - or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000), + or_else(try_for(mk_qfnra_nlsat_tactic(m, p0), 5000), try_for(mk_qfnra_nlsat_tactic(m, p1), 10000), mk_qfnra_sat_solver(m, p, 4), and_then(try_for(mk_smt_tactic(), 5000), mk_fail_if_undecided_tactic()), From f0a30ded7db8aa1e93cf91840ae2469e51c5deb5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 19:25:09 -0800 Subject: [PATCH 0429/1283] add shorthand for translating models #1407 Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 12 ++++++++++++ src/api/c++/z3++.h | 2 ++ src/api/python/z3/z3.py | 31 +++++++++++++++++++++++++------ src/api/z3_api.h | 7 +++++++ src/smt/theory_seq.cpp | 3 ++- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index bda33f186..d9936ff66 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -212,6 +212,18 @@ extern "C" { RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } + + Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context target) { + Z3_TRY; + LOG_Z3_model_translate(c, m, target); + RESET_ERROR_CODE(); + Z3_model_ref* dst = alloc(Z3_model_ref, *mk_c(target)); + ast_translation tr(mk_c(c)->m(), mk_c(target)->m()); + dst->m_model = to_model_ref(m)->translate(tr); + mk_c(target)->save_object(dst); + RETURN_Z3(of_model(dst)); + Z3_CATCH_RETURN(0); + } Z3_bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a) { Z3_TRY; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8ff2be239..b1e667e9f 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1809,9 +1809,11 @@ namespace z3 { Z3_model_inc_ref(ctx(), m); } public: + struct translate {}; model(context & c):object(c) { init(Z3_mk_model(c)); } model(context & c, Z3_model m):object(c) { init(m); } model(model const & s):object(s) { init(s.m_model); } + model(model& src, context& dst, translate) : object(dst) { init(Z3_model_translate(src.ctx(), src, dst)); } ~model() { Z3_model_dec_ref(ctx(), m_model); } operator Z3_model() const { return m_model; } model & operator=(model const & s) { diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 20c521df6..465e9aab8 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5585,6 +5585,17 @@ class FuncInterp(Z3PPObject): raise IndexError return FuncEntry(Z3_func_interp_get_entry(self.ctx.ref(), self.f, idx), self.ctx) + def translate(self, other_ctx): + """Copy model 'self' to context 'other_ctx'. + """ + return ModelRef(Z3_model_translate(self.ctx.ref(), self.model, other_ctx.ref()), other_ctx) + + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def as_list(self): """Return the function interpretation as a Python list. >>> f = Function('f', IntSort(), IntSort()) @@ -5614,9 +5625,6 @@ class ModelRef(Z3PPObject): self.ctx = ctx Z3_model_inc_ref(self.ctx.ref(), self.model) - def __deepcopy__(self, memo={}): - return ModelRef(self.m, self.ctx) - def __del__(self): if self.ctx.ref() is not None: Z3_model_dec_ref(self.ctx.ref(), self.model) @@ -5870,6 +5878,20 @@ class ModelRef(Z3PPObject): r.append(FuncDeclRef(Z3_model_get_func_decl(self.ctx.ref(), self.model, i), self.ctx)) return r + def translate(self, target): + """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`. + """ + if __debug__: + _z3_assert(isinstance(target, Context), "argument must be a Z3 context") + model = Z3_model_translate(self.ctx.ref(), self.model, target.ref()) + return Model(model, target) + + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def is_as_array(n): """Return true if n is a Z3 expression of the form (_ as-array f).""" return isinstance(n, ExprRef) and Z3_is_as_array(n.ctx.ref(), n.as_ast()) @@ -6072,9 +6094,6 @@ class Solver(Z3PPObject): self.solver = solver Z3_solver_inc_ref(self.ctx.ref(), self.solver) - def __deepcopy__(self, memo={}): - return Solver(self.solver, self.ctx) - def __del__(self): if self.solver is not None and self.ctx.ref() is not None: Z3_solver_dec_ref(self.ctx.ref(), self.solver) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 007bc3ab6..0ba49a5e5 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4896,6 +4896,13 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_model_get_sort_universe(Z3_context c, Z3_model m, Z3_sort s); + /** + \brief translate model from context c to context \c dst. + + def_API('Z3_model_translate', MODEL, (_in(CONTEXT), _in(MODEL), _in(CONTEXT))) + */ + Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context dst); + /** \brief The \ccode{(_ as-array f)} AST node is a construct for assigning interpretations for arrays in Z3. It is the array such that forall indices \c i we have that \ccode{(select (_ as-array f) i)} is equal to \ccode{(f i)}. diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 597348589..27ed95155 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3218,9 +3218,10 @@ void theory_seq::add_indexof_axiom(expr* i) { literal t_eq_empty = mk_eq_empty(t); // |t| = 0 => |s| = 0 or indexof(t,s,offset) = -1 - // ~contains(t,s) => indexof(t,s,offset) = -1 + // ~contains(t,s) <=> indexof(t,s,offset) = -1 add_axiom(cnt, i_eq_m1); + add_axiom(~cnt, ~i_eq_m1); add_axiom(~t_eq_empty, s_eq_empty, i_eq_m1); if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) { From c1c1b7378cffe3ac0781d4765fd1602c40531d33 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 19:44:16 -0800 Subject: [PATCH 0430/1283] removing axiom exposing unsoundness, replace by weaker axiom Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 27ed95155..f91685d43 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3221,7 +3221,7 @@ void theory_seq::add_indexof_axiom(expr* i) { // ~contains(t,s) <=> indexof(t,s,offset) = -1 add_axiom(cnt, i_eq_m1); - add_axiom(~cnt, ~i_eq_m1); +// add_axiom(~cnt, ~i_eq_m1); add_axiom(~t_eq_empty, s_eq_empty, i_eq_m1); if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) { @@ -3234,6 +3234,7 @@ void theory_seq::add_indexof_axiom(expr* i) { add_axiom(~s_eq_empty, i_eq_0); add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy)); add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx, false)); + add_axiom(~cnt, mk_literal(m_autil.mk_ge(i, zero))); tightest_prefix(s, x); } else { From e8a9e1a58b3dac9155e93bd2b61ee89ba1275771 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 20:04:55 -0800 Subject: [PATCH 0431/1283] set default rewriter behavior in incremental mode to distribute multiplication over addition #1373 Signed-off-by: Nikolaj Bjorner --- src/smt/asserted_formulas.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 56600266a..6ddce341d 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -131,6 +131,7 @@ void asserted_formulas::set_eliminate_and(bool flag) { p.set_bool("gcd_rounding", true); p.set_bool("expand_select_store", true); p.set_bool("bv_sort_ac", true); + p.set_bool("som", true); m_rewriter.updt_params(p); flush_cache(); } From 73b3da37d898c261892807197f72df48711383ab Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 22:47:52 +0700 Subject: [PATCH 0432/1283] Typo fixes. --- README-CMake.md | 4 +- RELEASE_NOTES | 2 +- cmake/Z3Config.cmake.in | 2 +- contrib/suppressions/sanitizers/README.md | 2 +- examples/c/test_capi.c | 4 +- examples/dotnet/Program.cs | 2 +- examples/java/JavaExample.java | 2 +- examples/maxsat/README | 2 +- src/api/dotnet/Context.cs | 12 +++--- src/api/dotnet/Expr.cs | 14 +++---- src/api/dotnet/Model.cs | 2 +- src/api/java/Context.java | 6 +-- src/api/java/Expr.java | 10 ++--- src/api/java/Model.java | 2 +- src/api/ml/z3.mli | 26 ++++++------ src/api/python/z3/z3.py | 10 ++--- src/api/z3_api.h | 50 +++++++++++------------ src/ast/ast.h | 14 +++---- src/ast/proofs/proof_checker.cpp | 2 +- src/interp/iz3proof_itp.cpp | 8 ++-- src/interp/iz3translate_direct.cpp | 2 +- src/math/simplex/simplex_def.h | 2 +- src/muz/rel/dl_compiler.h | 2 +- src/muz/rel/dl_relation_manager.h | 2 +- src/nlsat/nlsat_solver.cpp | 8 ++-- src/qe/qe_lite.cpp | 2 +- src/smt/mam.cpp | 4 +- src/smt/smt_internalizer.cpp | 12 +++--- src/smt/smt_model_finder.cpp | 22 +++++----- src/smt/smt_quantifier.h | 2 +- src/smt/theory_arith.h | 2 +- src/tactic/arith/purify_arith_tactic.h | 2 +- src/tactic/ufbv/ufbv_rewriter.h | 2 +- 33 files changed, 120 insertions(+), 120 deletions(-) diff --git a/README-CMake.md b/README-CMake.md index 0d323e08f..1b1f72729 100644 --- a/README-CMake.md +++ b/README-CMake.md @@ -5,7 +5,7 @@ of the project written in the ``CMakeLists.txt`` files and emits a build system for that project of your choice using one of CMake's "generators". This allows CMake to support many different platforms and build tools. You can run ``cmake --help`` to see the list of supported "generators" -on your platform. Example generators include "UNIX Makfiles" and "Visual Studio +on your platform. Example generators include "UNIX Makefiles" and "Visual Studio 12 2013". ## Getting started @@ -44,7 +44,7 @@ cmake -G "Unix Makefiles" ../ make -j4 # Replace 4 with an appropriate number ``` -Note that on some platforms "Unix Makesfiles" is the default generator so on those +Note that on some platforms "Unix Makefiles" is the default generator so on those platforms you don't need to pass ``-G "Unix Makefiles"`` command line option to ``cmake``. diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 4f10cad26..5ce4d2682 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -712,7 +712,7 @@ The following bugs are fixed in this release: bvshl when using a shift amount that evaluates to the length of the bit-vector. Thanks to Trevor Hansen and Robert Brummayer. -- Incorrect NNF conversion in linear quantifier elimniation routines. +- Incorrect NNF conversion in linear quantifier elimination routines. Thanks to Josh Berdine. - Missing constant folding of extraction for large bit-vectors. diff --git a/cmake/Z3Config.cmake.in b/cmake/Z3Config.cmake.in index e7f604591..dbd63b103 100644 --- a/cmake/Z3Config.cmake.in +++ b/cmake/Z3Config.cmake.in @@ -2,7 +2,7 @@ # @AUTO_GEN_MSG@ # # This file is intended to be consumed by clients who wish to use Z3 from CMake. -# It can be use by doing `find_package(Z3 config)` from within a +# It can be used by doing `find_package(Z3 config)` from within a # `CMakeLists.txt` file. If CMake doesn't find this package automatically you # can give it a hint by passing `-DZ3_DIR=` to the CMake invocation where # `` is the path to the directory containing this file. diff --git a/contrib/suppressions/sanitizers/README.md b/contrib/suppressions/sanitizers/README.md index f76f920b2..1d7cd0ac8 100644 --- a/contrib/suppressions/sanitizers/README.md +++ b/contrib/suppressions/sanitizers/README.md @@ -1,4 +1,4 @@ -# Sanitizer supression files +# Sanitizer suppression files This directory contains files used to suppress ASan/LSan/UBSan warnings/errors. diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index d71771f98..b947928a7 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -1546,7 +1546,7 @@ void two_contexts_example1() } /** - \brief Demonstrates how error codes can be read insted of registering an error handler. + \brief Demonstrates how error codes can be read instead of registering an error handler. */ void error_code_example1() { @@ -2533,7 +2533,7 @@ void reference_counter_example() { cfg = Z3_mk_config(); Z3_set_param_value(cfg, "model", "true"); - // Create a Z3 context where the user is reponsible for managing + // Create a Z3 context where the user is responsible for managing // Z3_ast reference counters. ctx = Z3_mk_context_rc(cfg); Z3_del_config(cfg); diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 71364013b..aec3bdcc5 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -622,7 +622,7 @@ namespace test_mapi Console.WriteLine("{0}", q1); } - // Quantifier with de-Brujin indices. + // Quantifier with de-Bruijn indices. { Expr x = ctx.MkBound(1, ctx.IntSort); Expr y = ctx.MkBound(0, ctx.IntSort); diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 40fb25a92..7b8902768 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -660,7 +660,7 @@ class JavaExample System.out.println(q1); } - // Quantifier with de-Brujin indices. + // Quantifier with de-Bruijn indices. { Expr x = ctx.mkBound(1, ctx.getIntSort()); Expr y = ctx.mkBound(0, ctx.getIntSort()); diff --git a/examples/maxsat/README b/examples/maxsat/README index e5e4ba610..6c24da66b 100644 --- a/examples/maxsat/README +++ b/examples/maxsat/README @@ -9,4 +9,4 @@ On OSX and Linux, you must install z3 first using sudo make install OR update LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (OSX) with the build directory. You need that to be able to find the Z3 shared library. -This directory contains a test file (ex.smt) that can be use as input for the maxsat test application. +This directory contains a test file (ex.smt) that can be used as input for the maxsat test application. diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index ac23d1dbc..cbd6a1bac 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2262,7 +2262,7 @@ namespace Microsoft.Z3 /// Maps f on the argument arrays. /// /// - /// Eeach element of args must be of an array sort [domain_i -> range_i]. + /// Each element of args must be of an array sort [domain_i -> range_i]. /// The function declaration f must have type range_1 .. range_n -> range. /// v must have sort range. The sort of the result is [domain_i -> range]. /// @@ -2862,7 +2862,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2878,7 +2878,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2894,7 +2894,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2910,7 +2910,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -3211,7 +3211,7 @@ namespace Microsoft.Z3 /// Create an existential Quantifier. /// /// - /// Creates an existential quantifier using de-Brujin indexed variables. + /// Creates an existential quantifier using de-Bruijn indexed variables. /// (). /// public Quantifier MkExists(Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 4fd306052..0726f9d53 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -959,7 +959,7 @@ namespace Microsoft.Z3 /// Tn: (R t_n s_n) /// [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) /// Remark: if t_i == s_i, then the antecedent Ti is suppressed. - /// That is, reflexivity proofs are supressed to save space. + /// That is, reflexivity proofs are suppressed to save space. /// public bool IsProofMonotonicity { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_MONOTONICITY; } } @@ -1002,7 +1002,7 @@ namespace Microsoft.Z3 public bool IsProofAndElimination { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_AND_ELIM; } } /// - /// Indicates whether the term is a proof by eliminiation of not-or + /// Indicates whether the term is a proof by elimination of not-or /// /// /// Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). @@ -1112,7 +1112,7 @@ namespace Microsoft.Z3 public bool IsProofQuantInst { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_QUANT_INST; } } /// - /// Indicates whether the term is a hypthesis marker. + /// Indicates whether the term is a hypothesis marker. /// /// Mark a hypothesis in a natural deduction style proof. public bool IsProofHypothesis { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_HYPOTHESIS; } } @@ -1433,7 +1433,7 @@ namespace Microsoft.Z3 /// /// Filter (restrict) a relation with respect to a predicate. /// The first argument is a relation. - /// The second argument is a predicate with free de-Brujin indices + /// The second argument is a predicate with free de-Bruijn indices /// corresponding to the columns of the relation. /// So the first column in the relation has index 0. /// @@ -1649,7 +1649,7 @@ namespace Microsoft.Z3 public bool IsFPMul { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MUL; } } /// - /// Indicates whether the term is a floating-point divison term + /// Indicates whether the term is a floating-point division term /// public bool IsFPDiv { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_DIV; } } @@ -1709,7 +1709,7 @@ namespace Microsoft.Z3 public bool IsFPLe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_LE; } } /// - /// Indicates whether the term is a floating-point greater-than or erqual term + /// Indicates whether the term is a floating-point greater-than or equal term /// public bool IsFPGe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_GE; } } @@ -1789,7 +1789,7 @@ namespace Microsoft.Z3 #region Bound Variables /// - /// The de-Burijn index of a bound variable. + /// The de-Bruijn index of a bound variable. /// /// /// Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index 12992fa8a..d11a57052 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -253,7 +253,7 @@ namespace Microsoft.Z3 /// The uninterpreted sorts that the model has an interpretation for. /// /// - /// Z3 also provides an intepretation for uninterpreted sorts used in a formula. + /// Z3 also provides an interpretation for uninterpreted sorts used in a formula. /// The interpretation for a sort is a finite set of distinct values. We say this finite set is /// the "universe" of the sort. /// diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 3458f4d97..7e73fc15e 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2234,7 +2234,7 @@ public class Context implements AutoCloseable { } /** - * Create a Term of a given sort. This function can be use to create + * Create a Term of a given sort. This function can be used to create * numerals that fit in a machine integer. It is slightly faster than * {@code MakeNumeral} since it is not necessary to parse a string. * @@ -2250,7 +2250,7 @@ public class Context implements AutoCloseable { } /** - * Create a Term of a given sort. This function can be use to create + * Create a Term of a given sort. This function can be used to create * numerals that fit in a machine integer. It is slightly faster than * {@code MakeNumeral} since it is not necessary to parse a string. * @@ -2438,7 +2438,7 @@ public class Context implements AutoCloseable { } /** - * Creates an existential quantifier using de-Brujin indexed variables. + * Creates an existential quantifier using de-Bruijn indexed variables. * @see #mkForall(Sort[],Symbol[],Expr,int,Pattern[],Expr[],Symbol,Symbol) **/ public Quantifier mkExists(Sort[] sorts, Symbol[] names, Expr body, diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index d3793a24b..7b20b7993 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1421,7 +1421,7 @@ public class Expr extends AST * Remarks: T1: * (R t_1 s_1) ... Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... * t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is - * suppressed. That is, reflexivity proofs are supressed to save space. + * suppressed. That is, reflexivity proofs are suppressed to save space. * * @throws Z3Exception on error * @return a boolean @@ -1473,7 +1473,7 @@ public class Expr extends AST } /** - * Indicates whether the term is a proof by eliminiation of not-or + * Indicates whether the term is a proof by elimination of not-or * Remarks: * Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). * T1: (not (or l_1 ... l_n)) [not-or-elim T1]: (not l_i) * @throws Z3Exception on error * @return a boolean @@ -1605,7 +1605,7 @@ public class Expr extends AST } /** - * Indicates whether the term is a hypthesis marker. + * Indicates whether the term is a hypothesis marker. * Remarks: Mark a * hypothesis in a natural deduction style proof. * @throws Z3Exception on error @@ -1987,7 +1987,7 @@ public class Expr extends AST * Indicates whether the term is a relation filter * Remarks: Filter * (restrict) a relation with respect to a predicate. The first argument is - * a relation. The second argument is a predicate with free de-Brujin + * a relation. The second argument is a predicate with free de-Bruijn * indices corresponding to the columns of the relation. So the first column * in the relation has index 0. * @throws Z3Exception on error @@ -2094,7 +2094,7 @@ public class Expr extends AST } /** - * The de-Burijn index of a bound variable. + * The de-Bruijn index of a bound variable. * Remarks: Bound variables are * indexed by de-Bruijn indices. It is perhaps easiest to explain the * meaning of de-Bruijn indices by indicating the compilation process from diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 9c7013aca..d809b6790 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -239,7 +239,7 @@ public class Model extends Z3Object { /** * The uninterpreted sorts that the model has an interpretation for. - * Remarks: Z3 also provides an intepretation for uninterpreted sorts used + * Remarks: Z3 also provides an interpretation for uninterpreted sorts used * in a formula. The interpretation for a sort is a finite set of distinct * values. We say this finite set is the "universe" of the sort. * diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 80923a0c7..20a1e9c10 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -536,7 +536,7 @@ sig @return A Term with the given value and sort *) val mk_numeral_string : context -> string -> Sort.sort -> expr - (** Create a numeral of a given sort. This function can be use to create numerals that fit in a machine integer. + (** Create a numeral of a given sort. This function can be used to create numerals that fit in a machine integer. It is slightly faster than [MakeNumeral] since it is not necessary to parse a string. @return A Term with the given value and sort *) val mk_numeral_int : context -> int -> Sort.sort -> expr @@ -667,7 +667,7 @@ sig end - (** The de-Burijn index of a bound variable. + (** The de-Bruijn index of a bound variable. Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain the meaning of de-Bruijn indices by indicating the compilation process from @@ -830,7 +830,7 @@ sig (** Maps f on the argument arrays. - Eeach element of [args] must be of an array sort [[domain_i -> range_i]]. + Each element of [args] must be of an array sort [[domain_i -> range_i]]. The function declaration [f] must have type [ range_1 .. range_n -> range]. [v] must have sort range. The sort of the result is [[domain_i -> range]]. {!Z3Array.mk_sort} @@ -962,7 +962,7 @@ sig Filter (restrict) a relation with respect to a predicate. The first argument is a relation. - The second argument is a predicate with free de-Brujin indices + The second argument is a predicate with free de-Bruijn indices corresponding to the columns of the relation. So the first column in the relation has index 0. *) val is_filter : Expr.expr -> bool @@ -2085,7 +2085,7 @@ sig (** Indicates whether an expression is a floating-point lt expression *) val is_lt : Expr.expr -> bool - (** Indicates whether an expression is a floating-point geqexpression *) + (** Indicates whether an expression is a floating-point geq expression *) val is_geq : Expr.expr -> bool (** Indicates whether an expression is a floating-point gt expression *) @@ -2233,7 +2233,7 @@ sig (** Conversion of a 2's complement unsigned bit-vector term into a term of FloatingPoint sort. *) val mk_to_fp_unsigned : context -> Expr.expr -> Expr.expr -> Sort.sort -> Expr.expr - (** C1onversion of a floating-point term into an unsigned bit-vector. *) + (** Conversion of a floating-point term into an unsigned bit-vector. *) val mk_to_ubv : context -> Expr.expr -> Expr.expr -> int -> Expr.expr (** Conversion of a floating-point term into a signed bit-vector. *) @@ -2385,7 +2385,7 @@ sig Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is suppressed. - That is, reflexivity proofs are supressed to save space. *) + That is, reflexivity proofs are suppressed to save space. *) val is_monotonicity : Expr.expr -> bool (** Indicates whether the term is a quant-intro proof @@ -2417,7 +2417,7 @@ sig [and-elim T1]: l_i *) val is_and_elimination : Expr.expr -> bool - (** Indicates whether the term is a proof by eliminiation of not-or + (** Indicates whether the term is a proof by elimination of not-or Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). T1: (not (or l_1 ... l_n)) @@ -2500,7 +2500,7 @@ sig A proof of (or (not (forall (x) (P x))) (P a)) *) val is_quant_inst : Expr.expr -> bool - (** Indicates whether the term is a hypthesis marker. + (** Indicates whether the term is a hypothesis marker. Mark a hypothesis in a natural deduction style proof. *) val is_hypothesis : Expr.expr -> bool @@ -2882,7 +2882,7 @@ sig (** The uninterpreted sorts that the model has an interpretation for. - Z3 also provides an intepretation for uninterpreted sorts used in a formula. + Z3 also provides an interpretation for uninterpreted sorts used in a formula. The interpretation for a sort is a finite set of distinct values. We say this finite set is the "universe" of the sort. {!get_num_sorts} @@ -3056,7 +3056,7 @@ sig (** Create a tactic that fails if the probe evaluates to false. *) val fail_if : context -> Probe.probe -> tactic - (** Create a tactic that fails if the goal is not triviall satisfiable (i.e., empty) + (** Create a tactic that fails if the goal is not trivially satisfiable (i.e., empty) or trivially unsatisfiable (i.e., contains `false'). *) val fail_if_not_decided : context -> tactic @@ -3105,7 +3105,7 @@ sig (** True if the entry is float-valued. *) val is_float : statistics_entry -> bool - (** The string representation of the the entry's value. *) + (** The string representation of the entry's value. *) val to_string_value : statistics_entry -> string (** The string representation of the entry (key and value) *) @@ -3370,7 +3370,7 @@ sig (** Assert a constraints into the optimize solver. *) val add : optimize -> Expr.expr list -> unit - (** Asssert a soft constraint. + (** Assert a soft constraint. Supply integer weight and string that identifies a group of soft constraints. *) val add_soft : optimize -> Expr.expr -> string -> Symbol.symbol -> handle diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 465e9aab8..4896a475d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -182,7 +182,7 @@ class Context: """Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions. This method can be invoked from a thread different from the one executing the - interruptable procedure. + interruptible procedure. """ Z3_interrupt(self.ref()) @@ -602,7 +602,7 @@ def _sort(ctx, a): return _to_sort_ref(Z3_get_sort(ctx.ref(), a), ctx) def DeclareSort(name, ctx=None): - """Create a new uninterpred sort named `name`. + """Create a new uninterpreted sort named `name`. If `ctx=None`, then the new sort is declared in the global Z3Py context. @@ -724,7 +724,7 @@ class FuncDeclRef(AstRef): The arguments must be Z3 expressions. This method assumes that the sorts of the elements in `args` match the sorts of the - domain. Limited coersion is supported. For example, if + domain. Limited coercion is supported. For example, if args[0] is a Python integer, and the function expects a Z3 integer, then the argument is automatically converted into a Z3 integer. @@ -9243,7 +9243,7 @@ def fpMul(rm, a, b, ctx=None): return _mk_fp_bin(Z3_mk_fpa_mul, rm, a, b, ctx) def fpDiv(rm, a, b, ctx=None): - """Create a Z3 floating-point divison expression. + """Create a Z3 floating-point division expression. >>> s = FPSort(8, 24) >>> rm = RNE() @@ -9270,7 +9270,7 @@ def fpRem(a, b, ctx=None): return _mk_fp_bin_norm(Z3_mk_fpa_rem, a, b, ctx) def fpMin(a, b, ctx=None): - """Create a Z3 floating-point minimium expression. + """Create a Z3 floating-point minimum expression. >>> s = FPSort(8, 24) >>> rm = RNE() diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 0ba49a5e5..5e5b84450 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -270,7 +270,7 @@ typedef enum - Z3_OP_ARRAY_MAP Array map operator. It satisfies map[f](a1,..,a_n)[i] = f(a1[i],...,a_n[i]) for every i. - - Z3_OP_SET_UNION Set union between two Booelan arrays (two arrays whose range type is Boolean). The function is binary. + - Z3_OP_SET_UNION Set union between two Boolean arrays (two arrays whose range type is Boolean). The function is binary. - Z3_OP_SET_INTERSECT Set intersection between two Boolean arrays. The function is binary. @@ -406,7 +406,7 @@ typedef enum - Z3_OP_BSMUL_NO_UDFL: check that bit-wise signed multiplication does not underflow. Signed multiplication underflows if the operands have opposite signs and the result of multiplication - does not fit within the avaialble bits. Z3_mk_bvmul_no_underflow. + does not fit within the available bits. Z3_mk_bvmul_no_underflow. - Z3_OP_BSDIV_I: Binary signed division. It has the same semantics as Z3_OP_BSDIV, but created in a context where the second operand can be assumed to be non-zero. @@ -485,7 +485,7 @@ typedef enum [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) } Remark: if t_i == s_i, then the antecedent Ti is suppressed. - That is, reflexivity proofs are supressed to save space. + That is, reflexivity proofs are suppressed to save space. - Z3_OP_PR_QUANT_INTRO: Given a proof for (~ p q), produces a proof for (~ (forall (x) p) (forall (x) q)). @@ -832,7 +832,7 @@ typedef enum - Z3_OP_RA_FILTER: Filter (restrict) a relation with respect to a predicate. The first argument is a relation. - The second argument is a predicate with free de-Brujin indices + The second argument is a predicate with free de-Bruijn indices corresponding to the columns of the relation. So the first column in the relation has index 0. @@ -969,7 +969,7 @@ typedef enum - Z3_OP_FPA_TO_FP: Floating-point conversion (various) - - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigend bit-vector + - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigned bit-vector - Z3_OP_FPA_TO_UBV: Floating-point conversion to unsigned bit-vector @@ -984,7 +984,7 @@ typedef enum of non-relevant terms in theory_fpa) - Z3_OP_FPA_BV2RM: Conversion of a 3-bit bit-vector term to a - floating-point rouding-mode term + floating-point rounding-mode term The conversion uses the following values: 0 = 000 = Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN, @@ -1922,7 +1922,7 @@ extern "C" { \param c logical context \param name name of the enumeration sort. - \param n number of elemenets in enumeration sort. + \param n number of elements in enumeration sort. \param enum_names names of the enumerated elements. \param enum_consts constants corresponding to the enumerated elements. \param enum_testers predicates testing if terms of the enumeration sort correspond to an enumeration. @@ -3186,7 +3186,7 @@ extern "C" { \param c logical context. \param num numerator of rational. - \param den denomerator of rational. + \param den denominator of rational. \pre den != 0 @@ -3201,7 +3201,7 @@ extern "C" { /** \brief Create a numeral of an int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine integer. + This function can be used to create numerals that fit in a machine integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3213,7 +3213,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine unsinged integer. + This function can be used to create numerals that fit in a machine unsigned integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3225,7 +3225,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine __int64 integer. + This function can be used to create numerals that fit in a machine __int64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3237,7 +3237,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine __uint64 integer. + This function can be used to create numerals that fit in a machine __uint64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3493,8 +3493,8 @@ extern "C" { Z3_ast Z3_API Z3_mk_re_range(Z3_context c, Z3_ast lo, Z3_ast hi); /** - \brief Create a regular expression loop. The supplied regular expression \c r is repated - between \c lo and \c hi times. The \c lo should be below \c hi with one exection: when + \brief Create a regular expression loop. The supplied regular expression \c r is repeated + between \c lo and \c hi times. The \c lo should be below \c hi with one exception: when supplying the value \c hi as 0, the meaning is to repeat the argument \c r at least \c lo number of times, and with an unbounded upper bound. @@ -4248,7 +4248,7 @@ extern "C" { Z3_sort Z3_API Z3_get_decl_sort_parameter(Z3_context c, Z3_func_decl d, unsigned idx); /** - \brief Return the expresson value associated with an expression parameter. + \brief Return the expression value associated with an expression parameter. \pre Z3_get_decl_parameter_kind(c, d, idx) == Z3_PARAMETER_AST @@ -4257,7 +4257,7 @@ extern "C" { Z3_ast Z3_API Z3_get_decl_ast_parameter(Z3_context c, Z3_func_decl d, unsigned idx); /** - \brief Return the expresson value associated with an expression parameter. + \brief Return the expression value associated with an expression parameter. \pre Z3_get_decl_parameter_kind(c, d, idx) == Z3_PARAMETER_FUNC_DECL @@ -4327,7 +4327,7 @@ extern "C" { /** \brief Return a hash code for the given AST. - The hash code is structural. You can use Z3_get_ast_id interchangably with + The hash code is structural. You can use Z3_get_ast_id interchangeably with this function. def_API('Z3_get_ast_hash', UINT, (_in(CONTEXT), _in(AST))) @@ -4556,7 +4556,7 @@ extern "C" { Z3_ast Z3_API Z3_get_pattern(Z3_context c, Z3_pattern p, unsigned idx); /** - \brief Return index of de-Brujin bound variable. + \brief Return index of de-Bruijn bound variable. \pre Z3_get_ast_kind(a) == Z3_VAR_AST @@ -4659,7 +4659,7 @@ extern "C" { Provides an interface to the AST simplifier used by Z3. It returns an AST object which is equal to the argument. - The returned AST is simplified using algebraic simplificaiton rules, + The returned AST is simplified using algebraic simplification rules, such as constant propagation (propagating true/false over logical connectives). def_API('Z3_simplify', AST, (_in(CONTEXT), _in(AST))) @@ -4861,9 +4861,9 @@ extern "C" { Z3_func_decl Z3_API Z3_model_get_func_decl(Z3_context c, Z3_model m, unsigned i); /** - \brief Return the number of uninterpreted sorts that \c m assigs an interpretation to. + \brief Return the number of uninterpreted sorts that \c m assigns an interpretation to. - Z3 also provides an intepretation for uninterpreted sorts used in a formua. + Z3 also provides an interpretation for uninterpreted sorts used in a formula. The interpretation for a sort \c s is a finite set of distinct values. We say this finite set is the "universe" of \c s. @@ -4971,7 +4971,7 @@ extern "C" { unsigned Z3_API Z3_func_interp_get_num_entries(Z3_context c, Z3_func_interp f); /** - \brief Return a "point" of the given function intepretation. It represents the + \brief Return a "point" of the given function interpretation. It represents the value of \c f in a particular point. \pre i < Z3_func_interp_get_num_entries(c, f) @@ -5013,7 +5013,7 @@ extern "C" { \brief add a function entry to a function interpretation. \param c logical context - \param fi a function interpregation to be updated. + \param fi a function interpretation to be updated. \param args list of arguments. They should be constant values (such as integers) and be of the same types as the domain of the function. \param value value of the function when the parameters match args. @@ -5466,7 +5466,7 @@ extern "C" { Z3_bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g); /** - \brief Copy a goal \c g from the context \c source to a the context \c target. + \brief Copy a goal \c g from the context \c source to the context \c target. def_API('Z3_goal_translate', GOAL, (_in(CONTEXT), _in(GOAL), _in(CONTEXT))) */ @@ -5932,7 +5932,7 @@ extern "C" { Z3_solver Z3_API Z3_mk_solver_from_tactic(Z3_context c, Z3_tactic t); /** - \brief Copy a solver \c s from the context \c source to a the context \c target. + \brief Copy a solver \c s from the context \c source to the context \c target. def_API('Z3_solver_translate', SOLVER, (_in(CONTEXT), _in(SOLVER), _in(CONTEXT))) */ diff --git a/src/ast/ast.h b/src/ast/ast.h index 2d06d03de..24e2b93b6 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -330,7 +330,7 @@ std::ostream& operator<<(std::ostream& out, sort_size const & ss); // ----------------------------------- /** - \brief Extra information that may be attached to intepreted sorts. + \brief Extra information that may be attached to interpreted sorts. */ class sort_info : public decl_info { sort_size m_num_elements; @@ -932,7 +932,7 @@ struct builtin_name { }; /** - \brief Each family of intepreted function declarations and sorts must provide a plugin + \brief Each family of interpreted function declarations and sorts must provide a plugin to build sorts and decls of the family. */ class decl_plugin { @@ -1059,7 +1059,7 @@ protected: ptr_vector m_eq_decls; // cached eqs ptr_vector m_ite_decls; // cached ites - ptr_vector m_oeq_decls; // cached obsevational eqs + ptr_vector m_oeq_decls; // cached observational eqs sort * m_proof_sort; func_decl * m_undef_decl; func_decl * m_true_pr_decl; @@ -1161,7 +1161,7 @@ public: virtual expr * get_some_value(sort * s); }; -typedef app proof; /* a proof is just an applicaton */ +typedef app proof; /* a proof is just an application */ // ----------------------------------- // @@ -1220,7 +1220,7 @@ enum pattern_op_kind { /** \brief Patterns are used to group expressions. These expressions are using during E-matching for - heurisitic quantifier instantiation. + heuristic quantifier instantiation. */ class pattern_decl_plugin : public decl_plugin { public: @@ -1245,13 +1245,13 @@ enum model_value_op_kind { /** \brief Values are used during model construction. All values are assumed to be different. Users should not use them, since they may - introduce unsoundess if the sort of a value is finite. + introduce unsoundness if the sort of a value is finite. Moreover, values should never be internalized in a logical context. However, values can be used during evaluation (i.e., simplification). - \remark Model values can be viewed as the partion ids in Z3 1.x. + \remark Model values can be viewed as the partition ids in Z3 1.x. */ class model_value_decl_plugin : public decl_plugin { public: diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 6fd876efc..5126198c6 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -502,7 +502,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { return false; } case PR_HYPOTHESIS: { - // TBD all branches with hyptheses must be closed by a later lemma. + // TBD all branches with hypotheses must be closed by a later lemma. if (match_proof(p) && match_fact(p, fml)) { return true; diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index fc9d0fac6..32cb9cccb 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -55,7 +55,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* The summation rule. The term sum(p,c,i) takes a proof p of an inequality i', an integer coefficient c and an inequality i, and - yieds a proof of i' + ci. */ + yields a proof of i' + ci. */ symb sum; /* Proof rotation. The proof term rotate(q,p) takes a @@ -75,7 +75,7 @@ class iz3proof_itp_impl : public iz3proof_itp { symb leq2eq; /* Equality to inequality. eq2leq(p, q) takes a proof p of x=y, and - a proof q ~(x <= y) and and yields a proof of false. */ + a proof q ~(x <= y) and yields a proof of false. */ symb eq2leq; /* Proof term cong(p,q) takes a proof p of x=y and a proof @@ -97,7 +97,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* This oprerator represents a concatenation of rewrites. The term a=b;c=d represents an A rewrite from a to b, followed by a B - rewrite fron b to c, followed by an A rewrite from c to d. + rewrite from b to c, followed by an A rewrite from c to d. */ symb concat; @@ -1542,7 +1542,7 @@ class iz3proof_itp_impl : public iz3proof_itp { return my_implies(arg(rew,1),arg(rew,2)); } - // make rewrite rew conditon on rewrite cond + // make rewrite rew condition on rewrite cond ast rewrite_conditional(const ast &cond, const ast &rew){ ast cf = rewrite_to_formula(cond); return make(sym(rew),arg(rew,0),my_and(arg(rew,1),cf),arg(rew,2)); diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index b88e488b4..e71475e45 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -9,7 +9,7 @@ Translate a Z3 proof into the interpolating proof calculus. Translation is direct, without transformations on the target proof - representaiton. + representation. Author: diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index 762e8ceb2..ceec60622 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -634,7 +634,7 @@ namespace simplex { // // max { c*x | A*x = 0 and l <= x <= u } // - // start with feasible assigment + // start with feasible assignment // A*x0 = 0 and l <= x0 <= u // // Identify pivot: i, j: such that x_i is base, diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 9aedf141a..6ac33ae91 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -60,7 +60,7 @@ namespace datalog { ACK_UNBOUND_VAR(var_index) - encodes that the column contains a variable that is unbound (by the corresponding rule body), - var_index is the de-Brujin index (var->get_idx()) + var_index is the de-Bruijn index (var->get_idx()) of the variable associated with the column. ACK_CONSTANT(constant) - encodes that the column contains the constant. diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index c77127eb7..610c523e1 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -609,7 +609,7 @@ namespace datalog { std::string to_nice_string(const relation_element & el) const; /** This one may give a nicer representation of \c el than the - \c to_nice_string(const relation_element & el) function, by unsing the information about the sort + \c to_nice_string(const relation_element & el) function, by using the information about the sort of the element. */ std::string to_nice_string(const relation_sort & s, const relation_element & el) const; diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 448aa624d..12b063759 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -89,7 +89,7 @@ namespace nlsat { unsigned m_num_bool_vars; atom_vector m_atoms; // bool_var -> atom - svector m_bvalues; // boolean assigment + svector m_bvalues; // boolean assignment unsigned_vector m_levels; // bool_var -> level svector m_justifications; vector m_bwatches; // bool_var (that are not attached to atoms) -> clauses where it is maximal @@ -1051,7 +1051,7 @@ namespace nlsat { } /** - \brief Process a clause that contains nonlinar arithmetic literals + \brief Process a clause that contains nonlinear arithmetic literals If satisfy_learned is true, then learned clauses are satisfied even if m_lazy > 0 */ @@ -1569,7 +1569,7 @@ namespace nlsat { max = lvl; } else { - // l must be a literal from a previous stage that is false in the current intepretation + // l must be a literal from a previous stage that is false in the current interpretation SASSERT(assigned_value(l) == l_undef); SASSERT(max_var(b) != null_var); SASSERT(m_xk != null_var); @@ -1890,7 +1890,7 @@ namespace nlsat { // ----------------------- // - // Variable reodering + // Variable reordering // // ----------------------- diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 01806bc24..3975945cb 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -974,7 +974,7 @@ namespace ar { // ------------------------------------------------------------ -// fm_tactic adapted to eliminate designated de-Brujin indices. +// fm_tactic adapted to eliminate designated de-Bruijn indices. namespace fm { typedef ptr_vector clauses; diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 96334e3ce..c979e476e 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -188,7 +188,7 @@ namespace smt { 1) Variables: (f ... X ...) 2) Ground terms: (f ... t ...) 3) depth 2 joint: (f ... (g ... X ...) ...) - Joint2 stores the declartion g, and the position of variable X, and its idx. + Joint2 stores the declaration g, and the position of variable X, and its idx. \remark Z3 has no support for depth 3 joints (f ... (g ... (h ... X ...) ...) ....) */ @@ -211,7 +211,7 @@ namespace smt { approx_set m_lbl_set; // singleton set containing m_label /* The following field is an array of tagged pointers. - Each positon contains: + Each position contains: 1- null (no joint), NULL_TAG 2- a boxed integer (i.e., register that contains the variable bind) VAR_TAG 3- an enode pointer (ground term) GROUND_TERM_TAG diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index ffaee434f..c38ef4e4a 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -369,7 +369,7 @@ namespace smt { else { TRACE("internalize_bug", tout << "creating enode for #" << n->get_id() << "\n";); mk_enode(to_app(n), - true, /* supress arguments, we not not use CC for this kind of enode */ + true, /* suppress arguments, we not not use CC for this kind of enode */ true, /* bool enode must be merged with true/false, since it is not in the context of a gate */ false /* CC is not enabled */ ); set_enode_flag(v, false); @@ -453,7 +453,7 @@ namespace smt { // must be associated with an enode. if (!e_internalized(n)) { mk_enode(to_app(n), - true, /* supress arguments, we not not use CC for this kind of enode */ + true, /* suppress arguments, we not not use CC for this kind of enode */ true /* bool enode must be merged with true/false, since it is not in the context of a gate */, false /* CC is not enabled */); } @@ -739,7 +739,7 @@ namespace smt { app_ref eq1(mk_eq_atom(n, t), m_manager); app_ref eq2(mk_eq_atom(n, e), m_manager); mk_enode(n, - true /* supress arguments, I don't want to apply CC on ite terms */, + true /* suppress arguments, I don't want to apply CC on ite terms */, false /* it is a term, so it should not be merged with true/false */, false /* CC is not enabled */); internalize(c, true); @@ -797,7 +797,7 @@ namespace smt { } enode * e = mk_enode(n, - false, /* do not supress args */ + false, /* do not suppress args */ false, /* it is a term, so it should not be merged with true/false */ true); apply_sort_cnstr(n, e); @@ -1506,7 +1506,7 @@ namespace smt { relevancy_eh * eh = m_relevancy_propagator->mk_and_relevancy_eh(n); unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { - // if one child is assigned to false, the the and-parent must be notified + // if one child is assigned to false, the and-parent must be notified literal l = get_literal(n->get_arg(i)); add_rel_watch(~l, eh); } @@ -1518,7 +1518,7 @@ namespace smt { relevancy_eh * eh = m_relevancy_propagator->mk_or_relevancy_eh(n); unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { - // if one child is assigned to true, the the or-parent must be notified + // if one child is assigned to true, the or-parent must be notified literal l = get_literal(n->get_arg(i)); add_rel_watch(l, eh); } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 28a65f898..f443d671b 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -537,7 +537,7 @@ namespace smt { } } - // For each instantiation_set, reemove entries that do not evaluate to values. + // For each instantiation_set, remove entries that do not evaluate to values. void cleanup_instantiation_sets() { ptr_vector to_delete; for (node * curr : m_nodes) { @@ -735,7 +735,7 @@ namespace smt { } } // TBD: add support for the else of bitvectors. - // Idea: get the term t with the minimal interpreation and use t - 1. + // Idea: get the term t with the minimal interpretation and use t - 1. } n->set_else((*(elems.begin())).m_key); } @@ -955,7 +955,7 @@ namespace smt { if (elems.empty()) { // The method get_some_value cannot be used if n->get_sort() is an uninterpreted sort or is a sort built using uninterpreted sorts // (e.g., (Array S S) where S is uninterpreted). The problem is that these sorts do not have a fixed interpretation. - // Moreover, a model assigns an arbitrary intepretation to these sorts using "model_values" a model value. + // Moreover, a model assigns an arbitrary interpretation to these sorts using "model_values" a model value. // If these module values "leak" inside the logical context, they may affect satisfiability. // sort * ns = n->get_sort(); @@ -1007,7 +1007,7 @@ namespace smt { This may happen because the evaluator uses model_completion. In the beginning of fix_model() we collected all f with partial interpretations. During the process of computing the - projections we used the evalutator with model_completion, + projections we used the evaluator with model_completion, and it may have fixed the "else" case of some partial interpretations. This is ok, because in the "limit" the "else" of the interpretation is irrelevant after the projections are applied. @@ -1570,7 +1570,7 @@ namespace smt { ast_manager & m = ctx->get_manager(); sort * s = q->get_decl_sort(num_vars - m_var_i - 1); if (m.is_uninterp(s)) { - // For uninterpreted sorst, we add all terms in the context. + // For uninterpreted sorts, we add all terms in the context. // See Section 4.1 in the paper "Complete Quantifier Instantiation" node * S_q_i = slv.get_uvar(q, m_var_i); ptr_vector::const_iterator it = ctx->begin_enodes(); @@ -1741,7 +1741,7 @@ namespace smt { if (has_quantifiers(q->get_expr())) { static bool displayed_flat_msg = false; if (!displayed_flat_msg) { - // [Leo]: This warning message is not usefult. + // [Leo]: This warning message is not useful. // warning_msg("For problems containing quantifiers, the model finding capabilities of Z3 work better when the formula does not contain nested quantifiers. You can use PULL_NESTED_QUANTIFIERS=true to eliminate nested quantifiers."); displayed_flat_msg = true; } @@ -2104,7 +2104,7 @@ namespace smt { } /** - \brief Process unintrepreted applications. + \brief Process uninterpreted applications. */ void process_u_app(app * t) { unsigned num_args = t->get_num_args(); @@ -2130,7 +2130,7 @@ namespace smt { /** \brief A term \c t is said to be a auf_select if - it is of ther form + it is of the form (select a i) Where: @@ -2151,7 +2151,7 @@ namespace smt { } /** - \brief Process intrepreted applications. + \brief Process interpreted applications. */ void process_i_app(app * t) { if (is_auf_select(t)) { @@ -2512,7 +2512,7 @@ namespace smt { SASSERT(f_else != 0); // Remark: I can ignore the conditions of m because // I know the (partial) interpretation of f satisfied the ground part. - // MBQI will force extra instantiations if the the (partial) interpretation of f + // MBQI will force extra instantiations if the (partial) interpretation of f // does not satisfy the quantifier. // In all other cases the "else" of f will satisfy the quantifier. set_else_interp(f, f_else); @@ -2937,7 +2937,7 @@ namespace smt { } /** - \brief Use m_fs to set the interpreation of the function symbols that were used to satisfy the + \brief Use m_fs to set the interpretation of the function symbols that were used to satisfy the quantifiers in m_satisfied. */ void set_interp() { diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index d89f3f6a4..ad5f58e49 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -152,7 +152,7 @@ namespace smt { virtual bool mbqi_enabled(quantifier *q) const {return true;} /** - \brief Give a change to the plugin to adjust the interpretation of unintepreted functions. + \brief Give a change to the plugin to adjust the interpretation of uninterpreted functions. It can basically change the "else" of each uninterpreted function. */ virtual void adjust_model(proto_model * m) = 0; diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 806b2a05b..6794ca3ac 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -660,7 +660,7 @@ namespace smt { satisfy their respective constraints. However, when they do that the may create inconsistencies in the other modules. I use m_liberal_final_check to avoid infinite - loops where the modules keep changing the assigment and no + loops where the modules keep changing the assignment and no progress is made. If m_liberal_final_check is set to false, these modules will avoid mutating the assignment to satisfy constraints. diff --git a/src/tactic/arith/purify_arith_tactic.h b/src/tactic/arith/purify_arith_tactic.h index bbb62710c..44b4f9b58 100644 --- a/src/tactic/arith/purify_arith_tactic.h +++ b/src/tactic/arith/purify_arith_tactic.h @@ -16,7 +16,7 @@ Abstract: Remarks: - The semantics of division by zero is not specified. Thus, uninterpreted functions are used. An ExRCF procedure may - treat the unintepreted function applications as fresh + treat the uninterpreted function applications as fresh constants. Then, in any model produced by this procedure, the interpretation for division by zero must be checked. diff --git a/src/tactic/ufbv/ufbv_rewriter.h b/src/tactic/ufbv/ufbv_rewriter.h index 1e13f4fa4..af9888751 100644 --- a/src/tactic/ufbv/ufbv_rewriter.h +++ b/src/tactic/ufbv/ufbv_rewriter.h @@ -74,7 +74,7 @@ each offset is a different "variable bank". A pair (expr, offset) is essentially where every variable in expr is assumed to be from the "bank" offset. The class substitution (in substitution.h) manages offsets for us. -The class matcher (in matcher.h) can be use to test whether an expression is an instance of another one. +The class matcher (in matcher.h) can be used to test whether an expression is an instance of another one. Finally, there is the problem when we have N demodulators (where N is big), and a big formula, and we want to traverse the formula only once looking for opportunities for applying these N demodulators. From a3ad0aff8b6750c25e730c3e6493736545fd841c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 22:50:50 +0700 Subject: [PATCH 0433/1283] print_stat_f: Remove implicit conversion of float to double. --- src/util/stats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/stats.h b/src/util/stats.h index 0acc18f43..680f9c9df 100644 --- a/src/util/stats.h +++ b/src/util/stats.h @@ -29,7 +29,7 @@ inline void print_stat(std::ostream& out, char const* msg, unsigned num) { } inline void print_stat_f(std::ostream& out, char const* msg, float num) { - if (num > 0.0) { + if (num > 0.0f) { out << msg << num << "\n"; } } From a875d3e491052bccb62ac490cbb554a97be4c129 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 07:54:31 -0800 Subject: [PATCH 0434/1283] fix #1429 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index ce305bb4e..120b0ddfd 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1994,7 +1994,7 @@ struct if csn <> cs || cdn <> cd then raise (Error "Argument size mismatch") else - Z3native.parse_smtlib2_string ctx file_name + Z3native.parse_smtlib2_file ctx file_name cs sort_names sorts cd decl_names decls end From a5a31fc23cd74463749da2911a71d60edcddcb19 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:11:36 +0700 Subject: [PATCH 0435/1283] Fix code formatting: Incorrect indentation. --- src/util/container_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/container_util.h b/src/util/container_util.h index e114c87b9..e68ab7199 100644 --- a/src/util/container_util.h +++ b/src/util/container_util.h @@ -29,7 +29,7 @@ Revision History: // ----------------------------------- template - void set_intersection(Set1 & tgt, const Set2 & src) { +void set_intersection(Set1 & tgt, const Set2 & src) { svector to_remove; for (auto const& itm : tgt) if (!src.contains(itm)) From 11db7784425516f77d1a378cea2a3c5bb5589a63 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:12:28 +0700 Subject: [PATCH 0436/1283] Remove ignored const qualifiers. The `const` qualifier on a scalar value is ignored in return types. --- src/util/lp/numeric_pair.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/lp/numeric_pair.h b/src/util/lp/numeric_pair.h index 4ebe63613..a8a743a71 100644 --- a/src/util/lp/numeric_pair.h +++ b/src/util/lp/numeric_pair.h @@ -38,10 +38,10 @@ template class numeric_traits {}; template <> class numeric_traits { public: static bool precise() { return true; } - static unsigned const zero() { return 0; } - static unsigned const one() { return 1; } + static unsigned zero() { return 0; } + static unsigned one() { return 1; } static bool is_zero(unsigned v) { return v == 0; } - static double const get_double(unsigned const & d) { return d; } + static double get_double(unsigned const & d) { return d; } }; template <> class numeric_traits { @@ -66,7 +66,7 @@ template <> class numeric_traits { static rational const & zero() { return rational::zero(); } static rational const & one() { return rational::one(); } static bool is_zero(const rational & v) { return v.is_zero(); } - static double const get_double(const rational & d) { return d.get_double();} + static double get_double(const rational & d) { return d.get_double();} static rational log(rational const& r) { UNREACHABLE(); return r; } static rational from_string(std::string const & str) { return rational(str.c_str()); } static bool is_pos(const rational & d) {return d.is_pos();} From 5a0f5a778fd6cdc383dd3594034b456b5911fb99 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:14:29 +0700 Subject: [PATCH 0437/1283] Remove unnecessary copy of coeff in iteration. --- src/smt/theory_lra.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 292d2ab0d..21b66d3a0 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1916,7 +1916,7 @@ namespace smt { lp::var_index vi = m_theory_var2var_index[v]; SASSERT(m_solver->is_term(vi)); lp::lar_term const& term = m_solver->get_term(vi); - for (auto const coeff : term.m_coeffs) { + for (auto const& coeff : term.m_coeffs) { lp::var_index wi = coeff.first; lp::constraint_index ci; rational value; From b06f4135852cce8649fa1da92a9a53a8c7994782 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:20:00 +0700 Subject: [PATCH 0438/1283] raise_exception: Annotate that this doesn't return. --- src/ast/ast.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 24e2b93b6..ea97af004 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,6 +53,12 @@ Revision History: #pragma warning(disable : 4355) #endif +#ifdef __GNUC__ +# define Z3_NORETURN __attribute__((noreturn)) +#else +# define Z3_NORETURN +#endif + class ast; class ast_manager; @@ -1515,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg); + void raise_exception(char const * msg) Z3_NORETURN; bool is_format_manager() const { return m_format_manager == 0; } From 7457fa77cb44f9cfdfb4fc552581e10c41ee69b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 08:46:17 -0800 Subject: [PATCH 0439/1283] add noreturn attribute #1435 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 41 ++++++++++++++--------------------------- src/ast/ast.h | 8 +------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 3824325b3..0f18170df 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1492,11 +1492,8 @@ void ast_manager::compact_memory() { unsigned capacity = m_ast_table.capacity(); if (capacity > 4*m_ast_table.size()) { ast_table new_ast_table; - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - new_ast_table.insert(*it); - } + for (ast* curr : m_ast_table) + new_ast_table.insert(curr); m_ast_table.swap(new_ast_table); IF_VERBOSE(10, verbose_stream() << "(ast-table :prev-capacity " << capacity << " :capacity " << m_ast_table.capacity() << " :size " << m_ast_table.size() << ")\n";); @@ -1510,10 +1507,7 @@ void ast_manager::compress_ids() { ptr_vector asts; m_expr_id_gen.cleanup(); m_decl_id_gen.cleanup(c_first_decl_id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * n = *it; + for (ast * n : m_ast_table) { if (is_decl(n)) n->m_id = m_decl_id_gen.mk(); else @@ -1521,13 +1515,11 @@ void ast_manager::compress_ids() { asts.push_back(n); } m_ast_table.finalize(); - ptr_vector::iterator it2 = asts.begin(); - ptr_vector::iterator end2 = asts.end(); - for (; it2 != end2; ++it2) - m_ast_table.insert(*it2); + for (ast* a : asts) + m_ast_table.insert(a); } -void ast_manager::raise_exception(char const * msg) { +[[noreturn]] void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } @@ -1570,20 +1562,15 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { } void ast_manager::set_next_expr_id(unsigned id) { - while (true) { - id = m_expr_id_gen.set_next_id(id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * curr = *it; - if (curr->get_id() == id) - break; + try_again: + id = m_expr_id_gen.set_next_id(id); + for (ast * curr : m_ast_table) { + if (curr->get_id() == id) { + // id is in use, move to the next one. + ++id; + goto try_again; } - if (it == end) - return; - // id is in use, move to the next one. - id++; - } + } } unsigned ast_manager::get_node_size(ast const * n) { return ::get_node_size(n); } diff --git a/src/ast/ast.h b/src/ast/ast.h index ea97af004..482ec3a99 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,12 +53,6 @@ Revision History: #pragma warning(disable : 4355) #endif -#ifdef __GNUC__ -# define Z3_NORETURN __attribute__((noreturn)) -#else -# define Z3_NORETURN -#endif - class ast; class ast_manager; @@ -1521,7 +1515,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg) Z3_NORETURN; + [[noreturn]] void raise_exception(char const * msg); bool is_format_manager() const { return m_format_manager == 0; } From 16044c74bfcd64384065fa38b514882a52a013c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 09:29:14 -0800 Subject: [PATCH 0440/1283] revert use of [[noreturn]]. It's not fully supported on compilers #1435 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 2 +- src/ast/ast.h | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 0f18170df..cc4beb1b6 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1519,7 +1519,7 @@ void ast_manager::compress_ids() { m_ast_table.insert(a); } -[[noreturn]] void ast_manager::raise_exception(char const * msg) { +void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } diff --git a/src/ast/ast.h b/src/ast/ast.h index 482ec3a99..ea97af004 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,6 +53,12 @@ Revision History: #pragma warning(disable : 4355) #endif +#ifdef __GNUC__ +# define Z3_NORETURN __attribute__((noreturn)) +#else +# define Z3_NORETURN +#endif + class ast; class ast_manager; @@ -1515,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - [[noreturn]] void raise_exception(char const * msg); + void raise_exception(char const * msg) Z3_NORETURN; bool is_format_manager() const { return m_format_manager == 0; } From 11f5fdccdf1f3e7b72a052be73203760d75472b4 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 3 Jan 2018 01:02:07 +0700 Subject: [PATCH 0441/1283] Use noreturn attribute and __declspec version. --- src/ast/ast.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index ea97af004..7a662a193 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,10 +53,10 @@ Revision History: #pragma warning(disable : 4355) #endif -#ifdef __GNUC__ -# define Z3_NORETURN __attribute__((noreturn)) +#ifdef _MSC_VER +# define Z3_NORETURN __declspec(noreturn) #else -# define Z3_NORETURN +# define Z3_NORETURN [[noreturn]] #endif class ast; @@ -1521,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg) Z3_NORETURN; + Z3_NORETURN void raise_exception(char const * msg); bool is_format_manager() const { return m_format_manager == 0; } From e9be339d9df0d7d16d31e58aeb1ff81b9215a563 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Wed, 3 Jan 2018 12:42:43 +0000 Subject: [PATCH 0442/1283] [CMake] Fix #1437. The `clock_gettime()` function in glibc < 2.17 required linking against librt. Until #1437 nobody had tried using the CMake build system with a really old version of glibc (in this case 2.12). The python build system always linked against librt but the CMake build system never tried to link against it leading to link failures. This patch teaches the CMake build system to detect if librt is required when linking against `clock_gettime()` and adds `rt` as a link dependency if necessary. --- CMakeLists.txt | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0be2de537..69a0ca123 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,6 +257,46 @@ list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/src" "${CMAKE_SOURCE_DIR}/src" ) + +################################################################################ +# Linux specific configuration +################################################################################ +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + # Try to detect if it is necessary to link against librt. + # Note that glibc < 2.17 required librt to be linked to use clock_gettime() + # and friends. + set(CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE + " + #include + int main() { + timespec res; + int result = clock_gettime(CLOCK_REALTIME, &res); + return result == 0; + } + " + ) + check_cxx_source_compiles( + "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" + CLOCK_GETTIME_NO_REQUIRE_LIBRT + ) + if (NOT CLOCK_GETTIME_NO_REQUIRE_LIBRT) + # Try again with librt + message(STATUS "Failed to link against clock_gettime(), trying with librt") + set(CMAKE_REQUIRED_LIBRARIES_OLD "${CMAKE_REQUIRED_LIBRARIES}") + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} rt") + check_cxx_source_compiles( + "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" + CLOCK_GETTIME_REQUIRES_LIBRT + ) + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_OLD}") + if (CLOCK_GETTIME_REQUIRES_LIBRT) + list(APPEND Z3_DEPENDENT_LIBS "rt") + else() + message(FATAL_ERROR "Failed to link against clock_gettime()") + endif() + endif() +endif() + ################################################################################ # GNU multiple precision library support ################################################################################ From 0917af7c569eb7380f04ff0165861912ba9f3109 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 3 Jan 2018 12:02:11 -0500 Subject: [PATCH 0443/1283] full upper bound refinement --- src/smt/theory_str.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 2f41a6617..b0b712511 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9236,10 +9236,13 @@ namespace smt { if (solution_at_upper_bound) { if (refined_upper_bound.is_minus_one()) { // If there are solutions at the upper bound but not below it, make the bound exact. - NOT_IMPLEMENTED_YET(); + rhs.push_back(ctx.mk_eq_atom(str_len, m_autil.mk_numeral(upper_bound_value, true))); } else { // If there are solutions at and below the upper bound, add an additional bound. - NOT_IMPLEMENTED_YET(); + rhs.push_back(m.mk_or( + ctx.mk_eq_atom(str_len, m_autil.mk_numeral(upper_bound_value, true)), + m_autil.mk_le(str_len, m_autil.mk_numeral(refined_upper_bound, true)) + )); } } else { if (refined_upper_bound.is_minus_one()) { @@ -9247,7 +9250,7 @@ namespace smt { rhs.push_back(m.mk_not(m_autil.mk_le(str_len, m_autil.mk_numeral(upper_bound_value, true)))); } else { // If there are solutions below the upper bound but not at it, refine the bound. - NOT_IMPLEMENTED_YET(); + rhs.push_back(m_autil.mk_le(str_len, m_autil.mk_numeral(refined_upper_bound, true))); } } From 0f20944aebf2f13e624b36d7b66dbba5a8e1233a Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 3 Jan 2018 13:54:18 -0500 Subject: [PATCH 0444/1283] regex lower bound (WIP) --- src/smt/theory_str.cpp | 158 ++++++++++++++++++++++++++++++++++++++++- src/smt/theory_str.h | 1 + 2 files changed, 158 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index b0b712511..04eb86fe4 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6671,6 +6671,118 @@ namespace smt { } } + /* + * Refine the lower bound on the length of a solution to a given automaton. + * The method returns TRUE if a solution of length `current_lower_bound` exists, + * and FALSE otherwise. In addition, the reference parameter `refined_lower_bound` + * is assigned the length of the shortest solution longer than `current_lower_bound` + * if it exists, or -1 otherwise. + */ + bool theory_str::refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound) { + ENSURE(aut != NULL); + + ast_manager & m = get_manager(); + + if (aut->final_states().size() < 1) { + // no solutions at all + refined_lower_bound = rational::minus_one(); + return false; + } + + // from here we assume that there is a final state reachable from the initial state + + unsigned_vector search_queue; + // populate search_queue with all states reachable from the epsilon-closure of start state + aut->get_epsilon_closure(aut->init(), search_queue); + + unsigned search_depth = 0; + hashtable> next_states; + unsigned_vector next_search_queue; + + bool found_solution_at_lower_bound = false; + + while (!search_queue.empty()) { + // if we are at the lower bound, check for final states + if (search_depth == current_lower_bound.get_unsigned()) { + for (unsigned_vector::iterator it = search_queue.begin(); it != search_queue.end(); ++it) { + unsigned state = *it; + if (aut->is_final_state(state)) { + found_solution_at_lower_bound = true; + break; + } + } + // end phase 1 + break; + } + next_states.reset(); + next_search_queue.clear(); + // move one step along all states + for (unsigned_vector::iterator it = search_queue.begin(); it != search_queue.end(); ++it) { + unsigned src = *it; + eautomaton::moves next_moves; + aut->get_moves_from(src, next_moves, true); + for (eautomaton::moves::iterator move_it = next_moves.begin(); + move_it != next_moves.end(); ++move_it) { + unsigned dst = move_it->dst(); + if (!next_states.contains(dst)) { + next_states.insert(dst); + next_search_queue.push_back(dst); + } + } + } + search_queue.clear(); + search_queue.append(next_search_queue); + search_depth += 1; + } // !search_queue.empty() + + // if we got here before reaching the lower bound, + // there aren't any solutions at or above it, so stop + if (search_depth < current_lower_bound.get_unsigned()) { + refined_lower_bound = rational::minus_one(); + return false; + } + + // phase 2: continue exploring the automaton above the lower bound + SASSERT(search_depth == current_lower_bound.get_unsigned()); + + while (!search_queue.empty()) { + if (search_depth > current_lower_bound.get_unsigned()) { + // check if we have found a solution above the lower bound + for (unsigned_vector::iterator it = search_queue.begin(); it != search_queue.end(); ++it) { + unsigned state = *it; + if (aut->is_final_state(state)) { + // this is a solution at a depth higher than the lower bound + refined_lower_bound = rational(search_depth); + return found_solution_at_lower_bound; + } + } + } + next_states.reset(); + next_search_queue.clear(); + // move one step along all states + for (unsigned_vector::iterator it = search_queue.begin(); it != search_queue.end(); ++it) { + unsigned src = *it; + eautomaton::moves next_moves; + aut->get_moves_from(src, next_moves, true); + for (eautomaton::moves::iterator move_it = next_moves.begin(); + move_it != next_moves.end(); ++move_it) { + unsigned dst = move_it->dst(); + if (!next_states.contains(dst)) { + next_states.insert(dst); + next_search_queue.push_back(dst); + } + } + } + search_queue.clear(); + search_queue.append(next_search_queue); + search_depth += 1; + } + // if we reached this point, we explored the whole automaton and didn't find any + // solutions above the lower bound + refined_lower_bound = rational::minus_one(); + return found_solution_at_lower_bound; + } + /* * Refine the upper bound on the length of a solution to a given automaton. * The method returns TRUE if a solution of length `current_upper_bound` exists, @@ -9291,7 +9403,51 @@ namespace smt { // no upper bound information if (lower_bound_exists) { // lower bound, no upper bound - NOT_IMPLEMENTED_YET(); + + // check current assumptions + if (regex_automaton_assumptions.contains(re) && + !regex_automaton_assumptions[re].empty()){ + // one or more existing assumptions. + // see if the (current best) lower bound can be refined + // (note that if we have an automaton with no assumption, + // this automatically counts as best) + bool need_assumption = true; + regex_automaton_under_assumptions last_assumption; + rational last_lb = rational::zero(); // the default + for (svector::iterator it = regex_automaton_assumptions[re].begin(); + it != regex_automaton_assumptions[re].end(); ++it) { + regex_automaton_under_assumptions autA = *it; + if ((current_assignment == l_true && autA.get_polarity() == false) + || (current_assignment == l_false && autA.get_polarity() == true)) { + // automaton uses incorrect polarity + continue; + } + rational this_lb; + if (autA.get_lower_bound(this_lb)) { + if (this_lb > last_lb) { + last_lb = this_lb; + last_assumption = autA; + } + } else { + need_assumption = false; + last_assumption = autA; + break; + } + } + if (!last_lb.is_zero() || !need_assumption) { + CTRACE("str", !need_assumption, tout << "using automaton with full length information" << std::endl;); + CTRACE("str", need_assumption, tout << "using automaton with assumed lower bound of " << last_lb << std::endl;); + rational refined_lower_bound; + bool solution_at_lower_bound = refine_automaton_lower_bound(last_assumption.get_automaton(), + lower_bound_value, refined_lower_bound); + TRACE("str", tout << "refined lower bound is " << refined_lower_bound << + (solution_at_lower_bound?", solution at upper bound":", no solution at upper bound") << std::endl;); + NOT_IMPLEMENTED_YET(); + } + } else { + // no existing automata/assumptions. + NOT_IMPLEMENTED_YET(); + } } else { // !lower_bound_exists // no bounds information NOT_IMPLEMENTED_YET(); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 57fa48142..999fc7dc0 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -536,6 +536,7 @@ protected: unsigned estimate_regex_complexity(expr * re); unsigned estimate_regex_complexity_under_complement(expr * re); expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); + bool refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound); bool refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound); void set_up_axioms(expr * ex); From a5180edc760a49ce05ddef98e69af510fc19f6b5 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 3 Jan 2018 16:05:34 -0500 Subject: [PATCH 0445/1283] make linear search the default for theory_str --- 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 937aa6a2b..d6ca8c9b2 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -74,7 +74,7 @@ def_module_params(module_name='smt', ('str.fast_length_tester_cache', BOOL, False, 'cache length tester constants instead of regenerating them'), ('str.fast_value_tester_cache', BOOL, True, 'cache value tester constants instead of regenerating them'), ('str.string_constant_cache', BOOL, True, 'cache all generated string constants generated from anywhere in theory_str'), - ('str.use_binary_search', BOOL, True, 'use a binary search heuristic for finding concrete length values for free variables in theory_str (set to False to use linear search)'), + ('str.use_binary_search', BOOL, False, 'use a binary search heuristic for finding concrete length values for free variables in theory_str (set to False to use linear search)'), ('str.binary_search_start', UINT, 64, 'initial upper bound for theory_str binary search'), ('theory_aware_branching', BOOL, False, 'Allow the context to use extra information from theory solvers regarding literal branching prioritization.'), ('str.finite_overlap_models', BOOL, False, 'attempt a finite model search for overlapping variables instead of completely giving up on the arrangement'), From 482738bc8a08e7abd0abaa7030261aa5255a984d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 Jan 2018 15:51:45 -0800 Subject: [PATCH 0446/1283] avoid reset_error in dec_ref in bv_val #1443. Add BSD required template instance #1444 Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 6 ++++++ src/api/api_context.h | 2 +- src/api/api_numeral.cpp | 4 ++-- src/api/c++/z3++.h | 10 +++++----- src/util/lp/lp_solver_instances.cpp | 1 + 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 23ac62a66..8299c136c 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -152,6 +152,12 @@ namespace api { } } + void context::reset_error_code() { + m_error_code = Z3_OK; + } + + + void context::check_searching() { if (m_searching) { set_error_code(Z3_INVALID_USAGE); // TBD: error code could be fixed. diff --git a/src/api/api_context.h b/src/api/api_context.h index 58893d1c1..a2321d7fe 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -138,7 +138,7 @@ namespace api { datatype_decl_plugin * get_dt_plugin() const { return m_dt_plugin; } Z3_error_code get_error_code() const { return m_error_code; } - void reset_error_code() { m_error_code = Z3_OK; } + void reset_error_code(); void set_error_code(Z3_error_code err); void set_error_handler(Z3_error_handler h) { m_error_handler = h; } // Sign an error if solver is searching diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 9a778d6e0..1cee7469c 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -73,7 +73,7 @@ extern "C" { ('P' == *m) || ('+' == *m))))) { SET_ERROR_CODE(Z3_PARSER_ERROR); - return 0; + RETURN_Z3(0); } ++m; } @@ -235,7 +235,7 @@ extern "C" { expr* e = to_expr(a); if (!e) { SET_ERROR_CODE(Z3_INVALID_ARG); - return ""; + RETURN_Z3(""); } rational r; arith_util & u = mk_c(c)->autil(); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b1e667e9f..808382561 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2524,11 +2524,11 @@ namespace z3 { inline expr context::real_val(__uint64 n) { Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } inline expr context::real_val(char const * n) { Z3_ast r = Z3_mk_numeral(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } - inline expr context::bv_val(int n, unsigned sz) { Z3_ast r = Z3_mk_int(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); } - inline expr context::bv_val(unsigned n, unsigned sz) { Z3_ast r = Z3_mk_unsigned_int(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); } - inline expr context::bv_val(__int64 n, unsigned sz) { Z3_ast r = Z3_mk_int64(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); } - inline expr context::bv_val(__uint64 n, unsigned sz) { Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); } - inline expr context::bv_val(char const * n, unsigned sz) { Z3_ast r = Z3_mk_numeral(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); } + inline expr context::bv_val(int n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_int(m_ctx, n, s); check_error(); return expr(*this, r); } + inline expr context::bv_val(unsigned n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_unsigned_int(m_ctx, n, s); check_error(); return expr(*this, r); } + inline expr context::bv_val(__int64 n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_int64(m_ctx, n, s); check_error(); return expr(*this, r); } + inline expr context::bv_val(__uint64 n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, s); check_error(); return expr(*this, r); } + inline expr context::bv_val(char const * n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_numeral(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr context::bv_val(unsigned n, bool const* bits) { array _bits(n); for (unsigned i = 0; i < n; ++i) _bits[i] = bits[i] ? 1 : 0; diff --git a/src/util/lp/lp_solver_instances.cpp b/src/util/lp/lp_solver_instances.cpp index 4fe04c05f..599a0a8bc 100644 --- a/src/util/lp/lp_solver_instances.cpp +++ b/src/util/lp/lp_solver_instances.cpp @@ -34,6 +34,7 @@ template void lp::lp_solver::print_statistics_on_A(std::ostream template bool lp::lp_solver::problem_is_empty(); template void lp::lp_solver::scale(); template void lp::lp_solver::set_scaled_cost(unsigned int); +template std::string lp::lp_solver::get_column_name(unsigned int) const; template lp::lp_solver::~lp_solver(); template void lp::lp_solver::add_constraint(lp::lp_relation, lp::mpq, unsigned int); template void lp::lp_solver::cleanup(); From e7851a063761785c25c4285c502313a4844bc1f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 Jan 2018 18:32:31 -0800 Subject: [PATCH 0447/1283] fix build 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 1cee7469c..d3dabcd4e 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -235,7 +235,7 @@ extern "C" { expr* e = to_expr(a); if (!e) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(""); + return ""; } rational r; arith_util & u = mk_c(c)->autil(); From 1992749e785762338f83f03fc38717757daab98e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 7 Jan 2018 18:52:00 -0800 Subject: [PATCH 0448/1283] to ascii or not to ascii #1447 Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 45ea9be23..18878d6ea 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1696,7 +1696,11 @@ if _lib is None: def _to_ascii(s): if isinstance(s, str): - return s.encode('ascii') + try: + return s.encode('ascii') + except: + # kick the bucket down the road. :-J + return s else: return s From cfdde2f4d1d1286d2bfcaad7bf5c7be202b024ad Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 8 Jan 2018 13:24:52 +0000 Subject: [PATCH 0449/1283] Added apply_result::as_expr to the C++ API. Requested here: https://stackoverflow.com/questions/48071840/get-result-of-tactics-application-as-an-expression-in-z3 --- src/api/c++/z3++.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 808382561..89b051eb5 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2101,6 +2101,19 @@ namespace z3 { check_error(); return model(ctx(), new_m); } + expr as_expr() const { + unsigned n = size(); + if (n == 0) + return ctx().bool_val(true); + else if (n == 1) + return operator[](0).as_expr(); + else { + array args(n); + for (unsigned i = 0; i < n; i++) + args[i] = operator[](i).as_expr(); + return expr(ctx(), Z3_mk_or(ctx(), n, args.ptr())); + } + } friend std::ostream & operator<<(std::ostream & out, apply_result const & r); }; inline std::ostream & operator<<(std::ostream & out, apply_result const & r) { out << Z3_apply_result_to_string(r.ctx(), r); return out; } From 98691a2c498198f2e71cc2cc01c3fb5c17210b65 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 8 Jan 2018 15:56:21 -0500 Subject: [PATCH 0450/1283] lower bound refinement --- src/smt/theory_str.cpp | 83 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 9ced6d186..eb1da0c4e 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9441,16 +9441,93 @@ namespace smt { bool solution_at_lower_bound = refine_automaton_lower_bound(last_assumption.get_automaton(), lower_bound_value, refined_lower_bound); TRACE("str", tout << "refined lower bound is " << refined_lower_bound << - (solution_at_lower_bound?", solution at upper bound":", no solution at upper bound") << std::endl;); - NOT_IMPLEMENTED_YET(); + (solution_at_lower_bound?", solution at lower bound":", no solution at lower bound") << std::endl;); + + expr_ref_vector lhs(m); + if (current_assignment == l_false) { + lhs.push_back(m.mk_not(str_in_re)); + } else { + lhs.push_back(str_in_re); + } + if (need_assumption) { + lhs.push_back(m_autil.mk_ge(str_len, m_autil.mk_numeral(last_lb, true))); + } + lhs.push_back(m_autil.mk_ge(str_len, m_autil.mk_numeral(lower_bound_value, true))); + + expr_ref_vector rhs(m); + + if (solution_at_lower_bound) { + if (refined_lower_bound.is_minus_one()) { + // If there are solutions at the lower bound but not above it, make the bound exact. + rhs.push_back(ctx.mk_eq_atom(str_len, m_autil.mk_numeral(lower_bound_value, true))); + } else { + // If there are solutions at and above the lower bound, add an additional bound. + rhs.push_back(m.mk_or( + ctx.mk_eq_atom(str_len, m_autil.mk_numeral(lower_bound_value, true)), + m_autil.mk_ge(str_len, m_autil.mk_numeral(refined_lower_bound, true)) + )); + } + } else { + if (refined_lower_bound.is_minus_one()) { + // If there are no solutions at or above the lower bound, assert a conflict clause. + rhs.push_back(m.mk_not(m_autil.mk_ge(str_len, m_autil.mk_numeral(lower_bound_value, true)))); + } else { + // If there are solutions above the lower bound but not at it, refine the bound. + rhs.push_back(m_autil.mk_ge(str_len, m_autil.mk_numeral(refined_lower_bound, true))); + } + } + + expr_ref lhs_terms(mk_and(lhs), m); + expr_ref rhs_terms(mk_and(rhs), m); + assert_implication(lhs_terms, rhs_terms); + regex_axiom_add = true; } } else { // no existing automata/assumptions. - NOT_IMPLEMENTED_YET(); + // if it's easy to construct a full automaton for R, do so + unsigned expected_complexity = estimate_regex_complexity(re); + unsigned threshold = 1000; // TODO better metric + if (expected_complexity <= threshold) { + eautomaton * aut = m_mk_aut(re); + aut->compress(); + regex_automata.push_back(aut); + regex_automaton_under_assumptions new_aut(re, aut, true); + if (!regex_automaton_assumptions.contains(re)) { + regex_automaton_assumptions.insert(re, svector()); + } + regex_automaton_assumptions[re].push_back(new_aut); + TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); + regex_axiom_add = true; + // TODO immediately attempt to learn lower/upper bound info here + } else { + // TODO check negation? + // construct a partial automaton for R to the given upper bound + NOT_IMPLEMENTED_YET(); + } } } else { // !lower_bound_exists // no bounds information + // check for existing automata; + // try to construct an automaton if we don't have one yet + // and doing so without bounds is not difficult NOT_IMPLEMENTED_YET(); + if (true) { + unsigned expected_complexity = estimate_regex_complexity(re); + unsigned threshold = 1000; // TODO better metric + if (expected_complexity <= threshold) { + eautomaton * aut = m_mk_aut(re); + aut->compress(); + regex_automata.push_back(aut); + regex_automaton_under_assumptions new_aut(re, aut, true); + if (!regex_automaton_assumptions.contains(re)) { + regex_automaton_assumptions.insert(re, svector()); + } + regex_automaton_assumptions[re].push_back(new_aut); + TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); + regex_axiom_add = true; + // TODO immediately attempt to learn lower/upper bound info here + } + } } } From bac5a648d960a45295f2a05e433b3f85cd4df0f1 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Tue, 9 Jan 2018 20:20:04 -0500 Subject: [PATCH 0451/1283] regex path constraint generation (WIP) --- src/smt/theory_str.cpp | 232 +++++++++++++++++++++++++++++++++++++++++ src/smt/theory_str.h | 3 + 2 files changed, 235 insertions(+) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index eb1da0c4e..54636b8df 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6854,6 +6854,237 @@ namespace smt { return found_solution_at_upper_bound; } + void theory_str::aut_path_add_next(u_map& next, expr_ref_vector& trail, unsigned idx, expr* cond) { + expr* acc; + if (!get_manager().is_true(cond) && next.find(idx, acc)) { + expr* args[2] = { cond, acc }; + cond = mk_or(get_manager(), 2, args); + } + trail.push_back(cond); + next.insert(idx, cond); + } + + expr_ref theory_str::aut_path_rewrite_constraint(expr * cond, expr * ch_var) { + context & ctx = get_context(); + ast_manager & m = get_manager(); + bv_util bvu(m); + + expr_ref retval(m); + + rational char_val; + unsigned int bv_width; + + expr * lhs; + expr * rhs; + + if (bvu.is_numeral(cond, char_val, bv_width)) { + SASSERT(char_val.is_nonneg() && char_val.get_unsigned() < 256); + TRACE("str", tout << "rewrite character constant " << char_val << std::endl;); + zstring str_const(char_val.get_unsigned()); + retval = u.str.mk_string(str_const); + return retval; + } else if (is_var(cond)) { + TRACE("str", tout << "substitute var" << std::endl;); + retval = ch_var; + return retval; + } else if (m.is_eq(cond, lhs, rhs)) { + // handle this specially because the sort of the equality will change + expr_ref new_lhs(aut_path_rewrite_constraint(lhs, ch_var), m); + SASSERT(new_lhs); + expr_ref new_rhs(aut_path_rewrite_constraint(rhs, ch_var), m); + SASSERT(new_rhs); + retval = ctx.mk_eq_atom(new_lhs, new_rhs); + return retval; + } else if (m.is_bool(cond)) { + TRACE("str", tout << "rewrite boolean term " << mk_pp(cond, m) << std::endl;); + app * a_cond = to_app(cond); + expr_ref_vector rewritten_args(m); + for (unsigned i = 0; i < a_cond->get_num_args(); ++i) { + expr * argI = a_cond->get_arg(i); + expr_ref new_arg(aut_path_rewrite_constraint(argI, ch_var), m); + SASSERT(new_arg); + rewritten_args.push_back(new_arg); + } + retval = m.mk_app(a_cond->get_decl(), rewritten_args.c_ptr()); + TRACE("str", tout << "final rewritten term is " << mk_pp(retval, m) << std::endl;); + return retval; + } else { + TRACE("str", tout << "ERROR: unrecognized automaton path constraint " << mk_pp(cond, m) << ", cannot translate" << std::endl;); + retval = NULL; + return retval; + } + } + + /* + * Create finite path constraints for the string variable `str` with respect to the automaton `aut`. + * The returned expression is the right-hand side of a constraint of the form + * (str in re) AND (|str| = len) AND (any applicable length assumptions on aut) -> RHS + */ + expr_ref theory_str::generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal) { + ENSURE(aut != NULL); + context & ctx = get_context(); + ast_manager & m = get_manager(); + + if (lenVal.is_zero()) { + // if any state in the epsilon-closure of the start state is accepting, + // then the empty string is in this language + unsigned_vector states; + bool has_final = false; + aut->get_epsilon_closure(aut->init(), states); + for (unsigned i = 0; i < states.size() && !has_final; ++i) { + has_final = aut->is_final_state(states[i]); + } + if (has_final) { + // empty string is OK, assert axiom + expr_ref rhs(ctx.mk_eq_atom(stringTerm, mk_string("")), m); + SASSERT(rhs); + //regex_automata_assertions.insert(stringTerm, final_axiom); + //m_trail_stack.push(insert_obj_map(regex_automata_assertions, stringTerm) ); + return rhs; + } else { + // negate -- the empty string isn't in the language + //expr_ref conflict(m.mk_not(mk_and(toplevel_lhs)), m); + //assert_axiom(conflict); + expr_ref conflict(m.mk_false(), m); + return conflict; + } + } // lenVal.is_zero() + + expr_ref_vector pathChars(m); + expr_ref_vector pathChars_len_constraints(m); + for (unsigned i = 0; i < lenVal.get_unsigned(); ++i) { + std::stringstream ss; + ss << "ch" << i; + expr_ref ch(mk_str_var(ss.str()), m); + pathChars.push_back(ch); + pathChars_len_constraints.push_back(ctx.mk_eq_atom(mk_strlen(ch), m_autil.mk_numeral(rational::one(), true))); + } + + // modification of code in seq_rewriter::mk_str_in_regexp() + expr_ref_vector trail(m); + u_map maps[2]; + bool select_map = false; + expr_ref ch(m), cond(m); + eautomaton::moves mvs; + maps[0].insert(aut->init(), m.mk_true()); + // is_accepted(a, aut) & some state in frontier is final. + for (unsigned i = 0; i < lenVal.get_unsigned(); ++i) { + u_map& frontier = maps[select_map]; + u_map& next = maps[!select_map]; + select_map = !select_map; + ch = pathChars.get(i); + next.reset(); + u_map::iterator it = frontier.begin(), end = frontier.end(); + for (; it != end; ++it) { + mvs.reset(); + unsigned state = it->m_key; + expr* acc = it->m_value; + aut->get_moves_from(state, mvs, false); + for (unsigned j = 0; j < mvs.size(); ++j) { + eautomaton::move const& mv = mvs[j]; + SASSERT(mv.t()); + if (mv.t()->is_char() && m.is_value(mv.t()->get_char())) { + // change this to a string constraint + expr_ref cond_rhs = aut_path_rewrite_constraint(mv.t()->get_char(), ch); + SASSERT(cond_rhs); + cond = ctx.mk_eq_atom(ch, cond_rhs); + SASSERT(cond); + expr * args[2] = {cond, acc}; + cond = mk_and(m, 2, args); + aut_path_add_next(next, trail, mv.dst(), cond); + } else if (mv.t()->is_range()) { + expr_ref range_lo(mv.t()->get_lo(), m); + expr_ref range_hi(mv.t()->get_hi(), m); + bv_util bvu(m); + + rational lo_val, hi_val; + unsigned int bv_width; + + if (bvu.is_numeral(range_lo, lo_val, bv_width) && bvu.is_numeral(range_hi, hi_val, bv_width)) { + TRACE("str", tout << "make range predicate from " << lo_val << " to " << hi_val << std::endl;); + expr_ref cond_rhs(m); + + if (hi_val < lo_val) { + rational tmp = lo_val; + lo_val = hi_val; + hi_val = tmp; + } + + expr_ref_vector cond_rhs_terms(m); + for (unsigned i = lo_val.get_unsigned(); i <= hi_val.get_unsigned(); ++i) { + zstring str_const(i); + expr_ref str_expr(u.str.mk_string(str_const), m); + cond_rhs_terms.push_back(ctx.mk_eq_atom(ch, str_expr)); + } + cond_rhs = mk_or(cond_rhs_terms); + SASSERT(cond_rhs); + expr * args[2] = {cond_rhs, acc}; + cond = mk_and(m, 2, args); + aut_path_add_next(next, trail, mv.dst(), cond); + } else { + TRACE("str", tout << "warning: non-bitvectors in automaton range predicate" << std::endl;); + UNREACHABLE(); + } + } else if (mv.t()->is_pred()) { + // rewrite this constraint over string terms + expr_ref cond_rhs = aut_path_rewrite_constraint(mv.t()->get_pred(), ch); + SASSERT(cond_rhs); + + if (m.is_false(cond_rhs)) { + continue; + } else if (m.is_true(cond_rhs)) { + aut_path_add_next(next, trail, mv.dst(), acc); + continue; + } + expr * args[2] = {cond_rhs, acc}; + cond = mk_and(m, 2, args); + aut_path_add_next(next, trail, mv.dst(), cond); + } + } + } + } + u_map const& frontier = maps[select_map]; + u_map::iterator it = frontier.begin(), end = frontier.end(); + expr_ref_vector ors(m); + for (; it != end; ++it) { + unsigned_vector states; + bool has_final = false; + aut->get_epsilon_closure(it->m_key, states); + for (unsigned i = 0; i < states.size() && !has_final; ++i) { + has_final = aut->is_final_state(states[i]); + } + if (has_final) { + ors.push_back(it->m_value); + } + } + expr_ref result(mk_or(ors)); + TRACE("str", tout << "regex path constraint: " << mk_pp(result, m) << "\n";); + + // if the path constraint is instantly false, then we know that the LHS must be false, + // so negate it and instantly assert a conflict clause + if (m.is_false(result)) { + expr_ref conflict(m.mk_false(), m); + return conflict; + } else { + expr_ref concat_rhs(m); + if (pathChars.size() == 1) { + concat_rhs = ctx.mk_eq_atom(stringTerm, pathChars.get(0)); + } else { + expr_ref acc(pathChars.get(0), m); + for (unsigned i = 1; i < pathChars.size(); ++i) { + acc = mk_concat(acc, pathChars.get(i)); + } + concat_rhs = ctx.mk_eq_atom(stringTerm, acc); + } + + expr_ref toplevel_rhs(m.mk_and(result, mk_and(pathChars_len_constraints), concat_rhs), m); + //expr_ref final_axiom(rewrite_implication(mk_and(toplevel_lhs), toplevel_rhs), m); + //regex_automata_assertions.insert(stringTerm, final_axiom); + //m_trail_stack.push(insert_obj_map(regex_automata_assertions, stringTerm) ); + return toplevel_rhs; + } + } + /* * strArgmt::solve_concat_eq_str() * Solve concatenations of the form: @@ -9281,6 +9512,7 @@ namespace smt { rational exact_length_value; if (get_len_value(str, exact_length_value)) { TRACE("str", tout << "exact length of " << mk_pp(str, m) << " is " << exact_length_value << std::endl;); + // TODO generate_regex_path_constraints(); NOT_IMPLEMENTED_YET(); } expr_ref str_len(mk_strlen(str), m); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 999fc7dc0..c6dad045f 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -538,6 +538,9 @@ protected: expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); bool refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound); bool refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound); + expr_ref generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal); + void aut_path_add_next(u_map& next, expr_ref_vector& trail, unsigned idx, expr* cond); + expr_ref aut_path_rewrite_constraint(expr * cond, expr * ch_var); void set_up_axioms(expr * ex); void handle_equality(expr * lhs, expr * rhs); From 6b799706b5adf865cc1b3e73d00d37a86610c619 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 10 Jan 2018 17:24:47 -0500 Subject: [PATCH 0452/1283] add path constraint generation for regex terms --- src/smt/params/smt_params_helper.pyg | 1 + src/smt/params/theory_str_params.cpp | 1 + src/smt/params/theory_str_params.h | 9 +- src/smt/theory_str.cpp | 165 +++++++++++++++++++++------ src/smt/theory_str.h | 4 +- 5 files changed, 145 insertions(+), 35 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 122d09f32..7ab0d52f2 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -80,6 +80,7 @@ def_module_params(module_name='smt', ('str.finite_overlap_models', BOOL, False, 'attempt a finite model search for overlapping variables instead of completely giving up on the arrangement'), ('str.overlap_priority', DOUBLE, -0.1, 'theory-aware priority for overlapping variable cases; use smt.theory_aware_branching=true'), ('str.regex_automata', BOOL, True, 'use automata-based reasoning for regular expressions (Z3str3 only)'), + ('str.regex_automata_difficulty_threshold', UINT, 1000, 'difficulty threshold for regex automata heuristics'), ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'), diff --git a/src/smt/params/theory_str_params.cpp b/src/smt/params/theory_str_params.cpp index b5451b9dc..fa6862161 100644 --- a/src/smt/params/theory_str_params.cpp +++ b/src/smt/params/theory_str_params.cpp @@ -32,4 +32,5 @@ void theory_str_params::updt_params(params_ref const & _p) { m_BinarySearchInitialUpperBound = p.str_binary_search_start(); m_OverlapTheoryAwarePriority = p.str_overlap_priority(); m_RegexAutomata = p.str_regex_automata(); + m_RegexAutomata_DifficultyThreshold = p.str_regex_automata_difficulty_threshold(); } diff --git a/src/smt/params/theory_str_params.h b/src/smt/params/theory_str_params.h index 4135cf0d6..48c0205ee 100644 --- a/src/smt/params/theory_str_params.h +++ b/src/smt/params/theory_str_params.h @@ -87,6 +87,12 @@ struct theory_str_params { */ bool m_RegexAutomata; + /* + * RegexAutomata_DifficultyThreshold is the lowest difficulty above which Z3str3 + * will not eagerly construct an automaton for a regular expression term. + */ + unsigned m_RegexAutomata_DifficultyThreshold; + theory_str_params(params_ref const & p = params_ref()): m_StrongArrangements(true), m_AggressiveLengthTesting(false), @@ -99,7 +105,8 @@ struct theory_str_params { m_UseBinarySearch(false), m_BinarySearchInitialUpperBound(64), m_OverlapTheoryAwarePriority(-0.1), - m_RegexAutomata(true) + m_RegexAutomata(true), + m_RegexAutomata_DifficultyThreshold(1000) { updt_params(p); } diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 54636b8df..5910d9d95 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6918,9 +6918,11 @@ namespace smt { /* * Create finite path constraints for the string variable `str` with respect to the automaton `aut`. * The returned expression is the right-hand side of a constraint of the form - * (str in re) AND (|str| = len) AND (any applicable length assumptions on aut) -> RHS + * (str in re) AND (|str| = len) AND (any applicable length assumptions on aut) -> (rhs AND character constraints). + * The character constraints, which are (str = c0 . c1 . (...) . cn) and (|c0| = 1, ...), + * are returned in `characterConstraints`. */ - expr_ref theory_str::generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal) { + expr_ref theory_str::generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal, expr_ref & characterConstraints) { ENSURE(aut != NULL); context & ctx = get_context(); ast_manager & m = get_manager(); @@ -7060,29 +7062,23 @@ namespace smt { expr_ref result(mk_or(ors)); TRACE("str", tout << "regex path constraint: " << mk_pp(result, m) << "\n";); - // if the path constraint is instantly false, then we know that the LHS must be false, - // so negate it and instantly assert a conflict clause - if (m.is_false(result)) { - expr_ref conflict(m.mk_false(), m); - return conflict; + expr_ref concat_rhs(m); + if (pathChars.size() == 1) { + concat_rhs = ctx.mk_eq_atom(stringTerm, pathChars.get(0)); } else { - expr_ref concat_rhs(m); - if (pathChars.size() == 1) { - concat_rhs = ctx.mk_eq_atom(stringTerm, pathChars.get(0)); - } else { - expr_ref acc(pathChars.get(0), m); - for (unsigned i = 1; i < pathChars.size(); ++i) { - acc = mk_concat(acc, pathChars.get(i)); - } - concat_rhs = ctx.mk_eq_atom(stringTerm, acc); + expr_ref acc(pathChars.get(0), m); + for (unsigned i = 1; i < pathChars.size(); ++i) { + acc = mk_concat(acc, pathChars.get(i)); } - - expr_ref toplevel_rhs(m.mk_and(result, mk_and(pathChars_len_constraints), concat_rhs), m); - //expr_ref final_axiom(rewrite_implication(mk_and(toplevel_lhs), toplevel_rhs), m); - //regex_automata_assertions.insert(stringTerm, final_axiom); - //m_trail_stack.push(insert_obj_map(regex_automata_assertions, stringTerm) ); - return toplevel_rhs; + concat_rhs = ctx.mk_eq_atom(stringTerm, acc); } + + //expr_ref toplevel_rhs(m.mk_and(result, mk_and(pathChars_len_constraints), concat_rhs), m); + characterConstraints = m.mk_and(mk_and(pathChars_len_constraints), concat_rhs); + //expr_ref final_axiom(rewrite_implication(mk_and(toplevel_lhs), toplevel_rhs), m); + //regex_automata_assertions.insert(stringTerm, final_axiom); + //m_trail_stack.push(insert_obj_map(regex_automata_assertions, stringTerm) ); + return result; } /* @@ -8241,6 +8237,27 @@ namespace smt { ); } + // returns true if needle appears as a subterm anywhere under haystack, + // or if needle appears in the same EQC as a subterm anywhere under haystack + bool theory_str::term_appears_as_subterm(expr * needle, expr * haystack) { + if (in_same_eqc(needle, haystack)) { + return true; + } + + if (is_app(haystack)) { + app * a_haystack = to_app(haystack); + for (unsigned i = 0; i < a_haystack->get_num_args(); ++i) { + expr * subterm = a_haystack->get_arg(i); + if (term_appears_as_subterm(needle, subterm)) { + return true; + } + } + } + + // not found + return false; + } + void theory_str::classify_ast_by_type(expr * node, std::map & varMap, std::map & concatMap, std::map & unrollMap) { @@ -9512,8 +9529,78 @@ namespace smt { rational exact_length_value; if (get_len_value(str, exact_length_value)) { TRACE("str", tout << "exact length of " << mk_pp(str, m) << " is " << exact_length_value << std::endl;); - // TODO generate_regex_path_constraints(); - NOT_IMPLEMENTED_YET(); + + if (regex_terms_with_path_constraints.contains(str_in_re)) { + TRACE("str", tout << "term " << mk_pp(str_in_re, m) << " already has path constraints set up" << std::endl;); + continue; + } + + // find a consistent automaton for this term + bool found = false; + regex_automaton_under_assumptions assumption; + if (regex_automaton_assumptions.contains(re) && + !regex_automaton_assumptions[re].empty()){ + for (svector::iterator it = regex_automaton_assumptions[re].begin(); + it != regex_automaton_assumptions[re].end(); ++it) { + regex_automaton_under_assumptions autA = *it; + rational assumed_upper_bound, assumed_lower_bound; + bool assumes_upper_bound = autA.get_upper_bound(assumed_upper_bound); + bool assumes_lower_bound = autA.get_lower_bound(assumed_lower_bound); + if (!assumes_upper_bound && !assumes_lower_bound) { + // automaton with no assumptions is always usable + assumption = autA; + found = true; + break; + } + // check consistency of bounds assumptions + } // foreach(a in regex_automaton_assumptions) + } + if (found) { + expr_ref pathConstraint(m); + expr_ref characterConstraints(m); + pathConstraint = generate_regex_path_constraints(str, assumption.get_automaton(), exact_length_value, characterConstraints); + TRACE("str", tout << "generated regex path constraint " << mk_pp(pathConstraint, m) << std::endl;); + TRACE("str", tout << "character constraints are " << mk_pp(characterConstraints, m) << std::endl;); + + expr_ref_vector lhs_terms(m); + lhs_terms.push_back(str_in_re); + lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true))); + expr_ref lhs(mk_and(lhs_terms), m); + // If the automaton was built with the same polarity as the constraint, + // assert directly. Otherwise, negate the path constraint + if ( (current_assignment == l_true && assumption.get_polarity()) + || (current_assignment == l_false && !assumption.get_polarity())) { + expr_ref rhs(m.mk_and(pathConstraint, characterConstraints), m); + assert_implication(lhs, rhs); + } else { + expr_ref rhs(m.mk_and(m.mk_not(pathConstraint), characterConstraints), m); + assert_implication(lhs, rhs); + } + regex_terms_with_path_constraints.insert(str_in_re); + m_trail_stack.push(insert_obj_trail(regex_terms_with_path_constraints, str_in_re)); + regex_axiom_add = true; + continue; + } else { + // no automata available, or else all bounds assumptions are invalid + unsigned expected_complexity = estimate_regex_complexity(re); + if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold) { + eautomaton * aut = m_mk_aut(re); + aut->compress(); + regex_automata.push_back(aut); + regex_automaton_under_assumptions new_aut(re, aut, true); + if (!regex_automaton_assumptions.contains(re)) { + regex_automaton_assumptions.insert(re, svector()); + } + regex_automaton_assumptions[re].push_back(new_aut); + TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); + regex_axiom_add = true; + // TODO immediately attempt to learn lower/upper bound info here + } else { + // TODO increment failure count + NOT_IMPLEMENTED_YET(); + } + continue; + } } expr_ref str_len(mk_strlen(str), m); rational lower_bound_value; @@ -9607,8 +9694,7 @@ namespace smt { // no existing automata/assumptions. // if it's easy to construct a full automaton for R, do so unsigned expected_complexity = estimate_regex_complexity(re); - unsigned threshold = 1000; // TODO better metric - if (expected_complexity <= threshold) { + if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold) { eautomaton * aut = m_mk_aut(re); aut->compress(); regex_automata.push_back(aut); @@ -9622,9 +9708,11 @@ namespace smt { // TODO immediately attempt to learn lower/upper bound info here } else { // TODO check negation? - // construct a partial automaton for R to the given upper bound + // TODO construct a partial automaton for R to the given upper bound? + // TODO increment failure count if we can't NOT_IMPLEMENTED_YET(); } + continue; } // if we have *any* automaton for R, and the upper bound is not too large, // finitize the automaton (if we have not already done so) and assert all solutions @@ -9718,8 +9806,7 @@ namespace smt { // no existing automata/assumptions. // if it's easy to construct a full automaton for R, do so unsigned expected_complexity = estimate_regex_complexity(re); - unsigned threshold = 1000; // TODO better metric - if (expected_complexity <= threshold) { + if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold) { eautomaton * aut = m_mk_aut(re); aut->compress(); regex_automata.push_back(aut); @@ -9733,9 +9820,11 @@ namespace smt { // TODO immediately attempt to learn lower/upper bound info here } else { // TODO check negation? - // construct a partial automaton for R to the given upper bound + // TODO construct a partial automaton for R to the given lower bound? + // TODO increment failure count NOT_IMPLEMENTED_YET(); } + continue; } } else { // !lower_bound_exists // no bounds information @@ -9745,8 +9834,7 @@ namespace smt { NOT_IMPLEMENTED_YET(); if (true) { unsigned expected_complexity = estimate_regex_complexity(re); - unsigned threshold = 1000; // TODO better metric - if (expected_complexity <= threshold) { + if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold) { eautomaton * aut = m_mk_aut(re); aut->compress(); regex_automata.push_back(aut); @@ -11265,7 +11353,18 @@ namespace smt { // this length tester is in any way constrained by regex terms, // do not perform value testing -- this term is not a free variable. if (m_params.m_RegexAutomata) { - NOT_IMPLEMENTED_YET(); // TODO + std::map, expr*>::iterator it = regex_in_bool_map.begin(); + for (; it != regex_in_bool_map.end(); ++it) { + expr * re = it->second; + expr * re_str = to_app(re)->get_arg(0); + // recursive descent through all subterms of re_str to see if any of them are + // - the same as freeVar + // - in the same EQC as freeVar + if (term_appears_as_subterm(freeVar, re_str)) { + TRACE("str", tout << "prevent value testing on free var " << mk_pp(freeVar, m) << " as it belongs to one or more regex constraints." << std::endl;); + return NULL; + } + } } TRACE("str", tout << "length is fixed; generating models for free var" << std::endl;); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index c6dad045f..c64eec838 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -407,6 +407,7 @@ protected: obj_map > regex_terms_by_string; // S --> [ (str.in.re S *) ] obj_map > regex_automaton_assumptions; // RegEx --> [ aut+assumptions ] std::map regex_nfa_cache; // Regex term --> NFA + obj_hashtable regex_terms_with_path_constraints; // set of string terms which have had path constraints asserted in the current scope svector char_set; std::map charSetLookupTable; @@ -538,7 +539,7 @@ protected: expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); bool refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound); bool refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound); - expr_ref generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal); + expr_ref generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal, expr_ref & characterConstraints); void aut_path_add_next(u_map& next, expr_ref_vector& trail, unsigned idx, expr* cond); expr_ref aut_path_rewrite_constraint(expr * cond, expr * ch_var); @@ -629,6 +630,7 @@ protected: std::map > & concat_eq_concat_map, std::map > & unrollGroupMap); + bool term_appears_as_subterm(expr * needle, expr * haystack); void classify_ast_by_type(expr * node, std::map & varMap, std::map & concatMap, std::map & unrollMap); void classify_ast_by_type_in_positive_context(std::map & varMap, From 1c2966f8e97da8cd08b5beb26583dc86772b5f11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Jan 2018 11:20:23 -0800 Subject: [PATCH 0453/1283] updates to model generation Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 12 +++++++----- src/sat/tactic/goal2sat.cpp | 16 ++++------------ src/tactic/generic_model_converter.cpp | 7 +++++++ src/tactic/generic_model_converter.h | 6 +----- src/tactic/model_converter.cpp | 1 + 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index bbeb87f83..ad1f36c99 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -279,6 +279,7 @@ namespace sat { unsigned lvl(bool_var v) const { return m_level[v]; } unsigned lvl(literal l) const { return m_level[l.var()]; } unsigned init_trail_size() const { return at_base_lvl() ? m_trail.size() : m_scopes[0].m_trail_lim; } + literal trail_literal(unsigned i) const { return m_trail[i]; } void assign(literal l, justification j) { TRACE("sat_assign", tout << l << " previous value: " << value(l) << "\n";); switch (value(l)) { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 39b58e3a5..97818e155 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -787,21 +787,23 @@ private: } m_model = md; + if (m_sat_mc) { + (*m_sat_mc)(m_model); + } if (m_bb_rewriter.get() && !m_bb_rewriter->const2bits().empty()) { m_mc0 = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); } - if (m_mc0) { + if (m_mc0) { (*m_mc0)(m_model); } SASSERT(m_model); DEBUG_CODE( - for (unsigned i = 0; i < m_fmls.size(); ++i) { + for (expr * f : m_fmls) { expr_ref tmp(m); - if (m_model->eval(m_fmls[i].get(), tmp, true)) { + if (m_model->eval(f, tmp, true)) { CTRACE("sat", !m.is_true(tmp), - tout << "Evaluation failed: " << mk_pp(m_fmls[i].get(), m) - << " to " << tmp << "\n"; + tout << "Evaluation failed: " << mk_pp(f, m) << " to " << tmp << "\n"; model_smt2_pp(tout, m, *(m_model.get()), 0);); SASSERT(m.is_true(tmp)); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 6d78bc331..d810c60b7 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1139,20 +1139,12 @@ struct sat2goal::imp { if (mc) mc->flush_smc(s); init_lit2expr(s, map, mc); // collect units - unsigned num_vars = s.num_vars(); - for (sat::bool_var v = 0; v < num_vars; v++) { + unsigned trail_sz = s.init_trail_size(); + for (unsigned i = 0; i < trail_sz; ++i) { checkpoint(); - switch (s.value(v)) { - case l_true: - r.assert_expr(lit2expr(mc, sat::literal(v, false))); - break; - case l_false: - r.assert_expr(lit2expr(mc, sat::literal(v, true))); - break; - case l_undef: - break; - } + r.assert_expr(lit2expr(mc, s.trail_literal(i))); } + // collect binary clauses svector bin_clauses; s.collect_bin_clauses(bin_clauses, m_learned); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index eb18aa545..47a4b4d48 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -28,6 +28,13 @@ Notes: #include "model/model_evaluator.h" +void generic_model_converter::add(func_decl * d, expr* e) { + struct entry et(d, e, m, ADD); + VERIFY(d->get_range() == m.get_sort(e)); + m_first_idx.insert_if_not_there(et.m_f, m_add_entries.size()); + m_add_entries.push_back(et); +} + void generic_model_converter::operator()(model_ref & md) { TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout);); model_evaluator ev(*(md.get())); diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index a9043d5cf..34e9d8166 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -47,11 +47,7 @@ public: void hide(func_decl * f) { m_hide_entries.push_back(entry(f, 0, m, HIDE)); } - void add(func_decl * d, expr* e) { - struct entry et(d, e, m, ADD); - m_first_idx.insert_if_not_there(et.m_f, m_add_entries.size()); - m_add_entries.push_back(et); - } + void add(func_decl * d, expr* e); void add(expr * d, expr* e) { SASSERT(is_app(d) && to_app(d)->get_num_args() == 0); add(to_app(d)->get_decl(), e); } diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 2598aa4f1..25829d3ce 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -25,6 +25,7 @@ Notes: */ void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { VERIFY(m_env); + VERIFY(f->get_range() == m.get_sort(e)); ast_smt2_pp(out, f, e, *m_env, params_ref(), 0, "model-add") << "\n"; } From 9635a74e52f723873e23329f3ceade0ae523ec50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 12 Jan 2018 08:23:22 -0800 Subject: [PATCH 0454/1283] add clausification features Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 11 +++++ src/opt/maxres.cpp | 4 +- src/opt/maxsmt.cpp | 22 ++++++++-- src/opt/opt_cmds.cpp | 4 +- src/sat/ba_solver.cpp | 91 ++++++++++++++++++++++++++++++++++------- src/sat/ba_solver.h | 5 +++ src/sat/sat_solver.h | 1 + 7 files changed, 117 insertions(+), 21 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index e16459fda..cf86ee03d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1407,6 +1407,17 @@ def is_or(a): """ return is_app_of(a, Z3_OP_OR) +def is_implies(a): + """Return `True` if `a` is a Z3 implication expression. + + >>> p, q = Bools('p q') + >>> is_implies(Implies(p, q)) + True + >>> is_implies(And(p, q)) + False + """ + return is_app_of(a, Z3_OP_IMPLIES) + def is_not(a): """Return `True` if `a` is a Z3 not expression. diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 5fa87b3ba..e1a4a74eb 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -285,13 +285,13 @@ public: m_last_index = 0; bool first = index > 0; SASSERT(index < asms.size() || asms.empty()); - IF_VERBOSE(1, verbose_stream() << "start hill climb " << index << " asms: " << asms.size() << "\n";); + IF_VERBOSE(10, verbose_stream() << "start hill climb " << index << " asms: " << asms.size() << "\n";); while (index < asms.size() && is_sat == l_true) { while (!first && asms.size() > 20*(index - m_last_index) && index < asms.size()) { index = next_index(asms, index); } - IF_VERBOSE(1, verbose_stream() << "hill climb " << index << "\n";); first = false; + IF_VERBOSE(3, verbose_stream() << "hill climb " << index << "\n";); // IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << " num soft: " << index << "\n";); m_last_index = index; is_sat = check_sat(index, asms.c_ptr()); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 25616b00f..636bbf9f9 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -353,12 +353,26 @@ namespace opt { m_upper += w; } + struct cmp_first { + bool operator()(std::pair const& x, std::pair const& y) const { + return x.first < y.first; + } + }; + void maxsmt::display_answer(std::ostream& out) const { - for (unsigned i = 0; i < m_soft_constraints.size(); ++i) { - expr* e = m_soft_constraints[i]; + vector> sorted_weights; + unsigned n = m_weights.size(); + for (unsigned i = 0; i < n; ++i) { + sorted_weights.push_back(std::make_pair(i, m_weights[i])); + } + std::sort(sorted_weights.begin(), sorted_weights.end(), cmp_first()); + sorted_weights.reverse(); + for (unsigned i = 0; i < n; ++i) { + unsigned idx = sorted_weights[i].first; + expr* e = m_soft_constraints[idx]; bool is_not = m.is_not(e, e); - out << m_weights[i] << ": " << mk_pp(e, m) - << ((is_not != get_assignment(i))?" |-> true ":" |-> false ") + out << m_weights[idx] << ": " << mk_pp(e, m) + << ((is_not != get_assignment(idx))?" |-> true ":" |-> false ") << "\n"; } diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 89264a9c8..a614b774c 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -166,7 +166,9 @@ public: } virtual void execute(cmd_context & ctx) { - get_opt(ctx, m_opt).display_assignment(ctx.regular_stream()); + if (!ctx.ignore_check()) { + get_opt(ctx, m_opt).display_assignment(ctx.regular_stream()); + } } }; diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index be4498061..963a7723e 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -446,7 +446,7 @@ namespace sat { } /* - \brief slit PB constraint into two because root is reused in arguments. + \brief split PB constraint into two because root is reused in arguments. x <=> a*x + B*y >= k @@ -825,6 +825,9 @@ namespace sat { p.set_k(k); SASSERT(p.well_formed()); + if (clausify(p)) { + return; + } if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p); } @@ -1543,6 +1546,9 @@ namespace sat { s().mk_clause(_lits.size(), _lits.c_ptr(), learned); return 0; } + if (!learned && clausify(lit, lits.size(), lits.c_ptr(), k)) { + return 0; + } void * mem = m_allocator.allocate(card::get_obj_size(lits.size())); card* c = new (mem) card(next_id(), lit, lits, k); c->set_learned(learned); @@ -2370,13 +2376,16 @@ namespace sat { SASSERT(s().at_base_lvl()); switch (c.tag()) { case card_t: - simplify(c.to_card()); + if (!clausify(c.to_card())) + simplify(c.to_card()); break; case pb_t: - simplify(c.to_pb()); + if (!clausify(c.to_pb())) + simplify(c.to_pb()); break; case xor_t: - simplify(c.to_xor()); + if (!clausify(c.to_xor())) + simplify(c.to_xor()); break; default: UNREACHABLE(); @@ -2480,8 +2489,9 @@ namespace sat { } void ba_solver::ba_sort::mk_clause(unsigned n, literal const* lits) { - literal_vector _lits(n, lits); - s.s().mk_clause(n, _lits.c_ptr()); + m_lits.reset(); + m_lits.append(n, lits); + s.s().mk_clause(n, m_lits.c_ptr()); } // ------------------------------- @@ -2623,8 +2633,25 @@ namespace sat { } } + bool ba_solver::clausify(literal lit, unsigned n, literal const* lits, unsigned k) { + bool is_def = lit != null_literal; + if ((!is_def || !s().was_eliminated(lit)) && + !std::any_of(lits, lits + n, [&](literal l) { return s().was_eliminated(l); })) { + literal def_lit = m_sort.ge(is_def, k, n, lits); + if (is_def) { + s().mk_clause(~lit, def_lit); + s().mk_clause( lit, ~def_lit); + } + return true; + } + return false; + } + + bool ba_solver::clausify(xor& x) { + return false; + } + bool ba_solver::clausify(card& c) { -#if 0 if (get_config().m_card_solver) return false; @@ -2632,18 +2659,54 @@ namespace sat { // TBD: conditions for when to clausify are TBD and // handling of conditional cardinality as well. // - if (c.lit() == null_literal) { - if (!c.learned() && !std::any_of(c.begin(), c.end(), [&](literal l) { return s().was_eliminated(l.var()); })) { - IF_VERBOSE(0, verbose_stream() << "clausify " << c << "\n"; - m_sort.ge(false, c.k(), c.size(), c.begin()); - } - remove_constraint(c, "recompiled to clauses"); + if (!c.learned() && clausify(c.lit(), c.size(), c.begin(), c.k())) { + IF_VERBOSE(0, verbose_stream() << "clausify " << c << "\n";); + // compiled + } + remove_constraint(c, "recompiled to clauses"); + return true; + } + + bool ba_solver::clausify(pb& p) { + if (get_config().m_card_solver) + return false; + + bool ok = !p.learned(); + bool is_def = p.lit() != null_literal; + for (wliteral wl : p) { + ok &= !s().was_eliminated(wl.second); + } + ok &= !is_def || !s().was_eliminated(p.lit()); + if (!ok) { + remove_constraint(p, "recompiled to clauses"); + return true; + } + + if (is_cardinality(p, m_lemma)) { + literal lit = m_sort.ge(is_def, p.k(), m_lemma.size(), m_lemma.c_ptr()); + if (is_def) { + s().mk_clause(p.lit(), ~lit); + s().mk_clause(~p.lit(), lit); + } + remove_constraint(p, "recompiled to clauses"); return true; } -#endif return false; } + bool ba_solver::is_cardinality(pb const& p, literal_vector& lits) { + lits.reset(); + p.size(); + for (wliteral wl : p) { + if (lits.size() > 2*p.size() + wl.first) { + return false; + } + for (unsigned i = 0; i < wl.first; ++i) { + lits.push_back(wl.second); + } + } + return true; + } void ba_solver::split_root(constraint& c) { switch (c.tag()) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index f447be64c..1116bb166 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -234,6 +234,7 @@ namespace sat { struct ba_sort { ba_solver& s; literal m_true; + literal_vector m_lits; typedef sat::literal literal; typedef sat::literal_vector literal_vector; @@ -343,6 +344,7 @@ namespace sat { void flush_roots(card& c); void recompile(card& c); bool clausify(card& c); + bool clausify(literal lit, unsigned n, literal const* lits, unsigned k); lbool eval(card const& c) const; double get_reward(card const& c, literal_occs_fun& occs) const; @@ -355,6 +357,7 @@ namespace sat { void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); void get_antecedents(literal l, xor const& x, literal_vector & r); void simplify(xor& x); + bool clausify(xor& x); void flush_roots(xor& x); lbool eval(xor const& x) const; @@ -371,6 +374,8 @@ namespace sat { bool is_cardinality(pb const& p); void flush_roots(pb& p); void recompile(pb& p); + bool clausify(pb& p); + bool is_cardinality(pb const& p, literal_vector& lits); lbool eval(pb const& p) const; double get_reward(pb const& p, literal_occs_fun& occs) const; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index bbeb87f83..0ca1bf7a8 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -270,6 +270,7 @@ namespace sat { void set_non_external(bool_var v); bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } void set_eliminated(bool_var v, bool f) { m_eliminated[v] = f; } + bool was_eliminated(literal l) const { return was_eliminated(l.var()); } unsigned scope_lvl() const { return m_scope_lvl; } unsigned search_lvl() const { return m_search_lvl; } bool at_search_lvl() const { return m_scope_lvl == m_search_lvl; } From ca3784449f02ce860736a741befb62ff33d9549b Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Fri, 12 Jan 2018 13:53:02 -0500 Subject: [PATCH 0455/1283] regex failsafe and intersect WIP --- src/smt/params/smt_params_helper.pyg | 4 ++ src/smt/params/theory_str_params.cpp | 4 ++ src/smt/params/theory_str_params.h | 30 ++++++++- src/smt/theory_str.cpp | 94 ++++++++++++++++++++++++++-- src/smt/theory_str.h | 9 +++ 5 files changed, 136 insertions(+), 5 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 7ab0d52f2..1f691d587 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -81,6 +81,10 @@ def_module_params(module_name='smt', ('str.overlap_priority', DOUBLE, -0.1, 'theory-aware priority for overlapping variable cases; use smt.theory_aware_branching=true'), ('str.regex_automata', BOOL, True, 'use automata-based reasoning for regular expressions (Z3str3 only)'), ('str.regex_automata_difficulty_threshold', UINT, 1000, 'difficulty threshold for regex automata heuristics'), + ('str.regex_automata_intersection_difficulty_threshold', UINT, 1000, 'difficulty threshold for regex intersection heuristics'), + ('str.regex_automata_failed_automaton_threshold', UINT, 10, 'number of failed automaton construction attempts after which a full automaton is automatically built'), + ('str.regex_automata_failed_intersection_threshold', UINT, 10, 'number of failed automaton intersection attempts after which intersection is always computed'), + ('str.regex_automata_length_attempt_threshold', UINT, 10, 'number of length/path constraint attempts before checking unsatisfiability of regex terms'), ('core.minimize', BOOL, False, 'minimize unsat core produced by SMT context'), ('core.extend_patterns', BOOL, False, 'extend unsat core with literals that trigger (potential) quantifier instances'), ('core.extend_patterns.max_distance', UINT, UINT_MAX, 'limits the distance of a pattern-extended unsat core'), diff --git a/src/smt/params/theory_str_params.cpp b/src/smt/params/theory_str_params.cpp index fa6862161..92478bcd9 100644 --- a/src/smt/params/theory_str_params.cpp +++ b/src/smt/params/theory_str_params.cpp @@ -33,4 +33,8 @@ void theory_str_params::updt_params(params_ref const & _p) { m_OverlapTheoryAwarePriority = p.str_overlap_priority(); m_RegexAutomata = p.str_regex_automata(); m_RegexAutomata_DifficultyThreshold = p.str_regex_automata_difficulty_threshold(); + m_RegexAutomata_IntersectionDifficultyThreshold = p.str_regex_automata_intersection_difficulty_threshold(); + m_RegexAutomata_FailedAutomatonThreshold = p.str_regex_automata_failed_automaton_threshold(); + m_RegexAutomata_FailedIntersectionThreshold = p.str_regex_automata_failed_intersection_threshold(); + m_RegexAutomata_LengthAttemptThreshold = p.str_regex_automata_length_attempt_threshold(); } diff --git a/src/smt/params/theory_str_params.h b/src/smt/params/theory_str_params.h index 48c0205ee..8c7816839 100644 --- a/src/smt/params/theory_str_params.h +++ b/src/smt/params/theory_str_params.h @@ -93,6 +93,30 @@ struct theory_str_params { */ unsigned m_RegexAutomata_DifficultyThreshold; + /* + * RegexAutomata_IntersectionDifficultyThreshold is the lowest difficulty above which Z3str3 + * will not eagerly intersect automata to check unsatisfiability. + */ + unsigned m_RegexAutomata_IntersectionDifficultyThreshold; + + /* + * RegexAutomata_FailedAutomatonThreshold is the number of failed attempts to build an automaton + * after which a full automaton (i.e. with no length information) will be built regardless of difficulty. + */ + unsigned m_RegexAutomata_FailedAutomatonThreshold; + + /* + * RegexAutomaton_FailedIntersectionThreshold is the number of failed attempts to perform automaton + * intersection after which intersection will always be performed regardless of difficulty. + */ + unsigned m_RegexAutomata_FailedIntersectionThreshold; + + /* + * RegexAutomaton_LengthAttemptThreshold is the number of attempts to satisfy length/path constraints + * before which we begin checking unsatisfiability of a regex term. + */ + unsigned m_RegexAutomata_LengthAttemptThreshold; + theory_str_params(params_ref const & p = params_ref()): m_StrongArrangements(true), m_AggressiveLengthTesting(false), @@ -106,7 +130,11 @@ struct theory_str_params { m_BinarySearchInitialUpperBound(64), m_OverlapTheoryAwarePriority(-0.1), m_RegexAutomata(true), - m_RegexAutomata_DifficultyThreshold(1000) + m_RegexAutomata_DifficultyThreshold(1000), + m_RegexAutomata_IntersectionDifficultyThreshold(1000), + m_RegexAutomata_FailedAutomatonThreshold(10), + m_RegexAutomata_FailedIntersectionThreshold(10), + m_RegexAutomata_LengthAttemptThreshold(10) { updt_params(p); } diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 5910d9d95..6e4211f7b 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6480,6 +6480,26 @@ namespace smt { } } + void theory_str::regex_inc_counter(obj_map & counter_map, expr * key) { + unsigned old_v; + if (counter_map.find(key, old_v)) { + unsigned new_v = old_v += 1; + counter_map.insert(key, new_v); + } else { + counter_map.insert(key, 1); + } + } + + unsigned theory_str::regex_get_counter(obj_map & counter_map, expr * key) { + unsigned v; + if (counter_map.find(key, v)) { + return v; + } else { + counter_map.insert(key, 0); + return 0; + } + } + // saturating unsigned addition unsigned inline _qadd(unsigned a, unsigned b) { if (a == UINT_MAX || b == UINT_MAX) { @@ -9515,6 +9535,7 @@ namespace smt { // regex automata if (m_params.m_RegexAutomata) { + // TODO since heuristics might fail, the "no progress" flag might need to be handled specially here bool regex_axiom_add = false; for (obj_hashtable::iterator it = regex_terms.begin(); it != regex_terms.end(); ++it) { expr * str_in_re = *it; @@ -9579,11 +9600,16 @@ namespace smt { regex_terms_with_path_constraints.insert(str_in_re); m_trail_stack.push(insert_obj_trail(regex_terms_with_path_constraints, str_in_re)); regex_axiom_add = true; + + // increment LengthAttemptCount + regex_inc_counter(regex_length_attempt_count, str_in_re); continue; } else { // no automata available, or else all bounds assumptions are invalid unsigned expected_complexity = estimate_regex_complexity(re); - if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold) { + if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold || regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold) { + CTRACE("str", regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold, + tout << "failed automaton threshold reached for " << mk_pp(str_in_re, m) << " -- automatically constructing full automaton" << std::endl;); eautomaton * aut = m_mk_aut(re); aut->compress(); regex_automata.push_back(aut); @@ -9596,8 +9622,7 @@ namespace smt { regex_axiom_add = true; // TODO immediately attempt to learn lower/upper bound info here } else { - // TODO increment failure count - NOT_IMPLEMENTED_YET(); + regex_inc_counter(regex_fail_count, str_in_re); } continue; } @@ -9852,7 +9877,68 @@ namespace smt { } // NOT_IMPLEMENTED_YET(); - } + } // foreach (entry in regex_terms) + + for (obj_map >::iterator it = regex_terms_by_string.begin(); + it != regex_terms_by_string.end(); ++it) { + // TODO do we need to check equivalence classes of strings here? + + expr * str = it->m_key; + ptr_vector str_in_re_terms = it->m_value; + + svector intersect_constraints; + // we may find empty intersection before checking every constraint; + // this vector keeps track of which ones actually take part in intersection + svector used_intersect_constraints; + + // choose an automaton/assumption for each assigned (str.in.re) + // that's consistent with the current length information + NOT_IMPLEMENTED_YET(); + + eautomaton * aut_inter = NULL; + CTRACE("str", !intersect_constraints.empty(), tout << "check intersection of automata constraints for " << mk_pp(str, m) << std::endl;); + for (svector::iterator aut_it = intersect_constraints.begin(); + aut_it != intersect_constraints.end(); ++aut_it) { + regex_automaton_under_assumptions aut = *aut_it; + if (aut_inter == NULL) { + // start somewhere + aut_inter = aut.get_automaton(); + used_intersect_constraints.push_back(aut); + continue; + } + + if (regex_get_counter(regex_length_attempt_count, aut.get_regex_term()) >= m_params.m_RegexAutomata_LengthAttemptThreshold) { + unsigned intersectionDifficulty = 0; // TODO EstimateIntersectionDifficulty + if (intersectionDifficulty <= m_params.m_RegexAutomata_IntersectionDifficultyThreshold + || regex_get_counter(regex_intersection_fail_count, aut.get_regex_term()) >= m_params.m_RegexAutomata_FailedIntersectionThreshold) { + lbool current_assignment = ctx.get_assignment(aut.get_regex_term()); + // if the assignment is consistent with our assumption, use the automaton directly; + // otherwise, complement it (and save that automaton for next time) + // TODO we should cache these intermediate results + // TODO do we need to push the intermediates into a vector for deletion anyway? + if ( (current_assignment == l_true && aut.get_polarity()) + || (current_assignment == l_false && !aut.get_polarity())) { + aut_inter = m_mk_aut.mk_product(aut_inter, aut.get_automaton()); + } else { + // need to complement first + NOT_IMPLEMENTED_YET(); + } + used_intersect_constraints.push_back(aut); + if (aut_inter->is_empty()) { + break; + } + } else { + // failed intersection + regex_inc_counter(regex_intersection_fail_count, aut.get_regex_term()); + } + } + } // foreach(entry in intersect_constraints) + if (aut_inter->is_empty()) { + TRACE("str", tout << "product automaton is empty; asserting conflict clause" << std::endl;); + NOT_IMPLEMENTED_YET(); + } + } // foreach (entry in regex_terms_by_string) + if (regex_axiom_add) { return FC_CONTINUE; } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index c64eec838..45df675fb 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -221,6 +221,7 @@ public: } eautomaton * get_automaton() const { return aut; } + expr * get_regex_term() const { return str_in_re; } bool get_polarity() const { return polarity; } virtual ~regex_automaton_under_assumptions() { @@ -409,6 +410,12 @@ protected: std::map regex_nfa_cache; // Regex term --> NFA obj_hashtable regex_terms_with_path_constraints; // set of string terms which have had path constraints asserted in the current scope + // each counter maps a (str.in.re) expression to an integer. + // use helper functions regex_inc_counter() and regex_get_counter() to access + obj_map regex_length_attempt_count; + obj_map regex_fail_count; + obj_map regex_intersection_fail_count; + svector char_set; std::map charSetLookupTable; int charSetSize; @@ -542,6 +549,8 @@ protected: expr_ref generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal, expr_ref & characterConstraints); void aut_path_add_next(u_map& next, expr_ref_vector& trail, unsigned idx, expr* cond); expr_ref aut_path_rewrite_constraint(expr * cond, expr * ch_var); + void regex_inc_counter(obj_map & counter_map, expr * key); + unsigned regex_get_counter(obj_map & counter_map, expr * key); void set_up_axioms(expr * ex); void handle_equality(expr * lhs, expr * rhs); From 5159291d573e18d582c813bc10a59f6c6327c1e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 12 Jan 2018 19:29:42 -0800 Subject: [PATCH 0456/1283] add missing interpreted tail during bottom-up simplification #1452 Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_coi_filter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 3ea0e305a..2ca64aa68 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -79,6 +79,10 @@ namespace datalog { } if (contained) { if (new_tail) { + for (unsigned i = r->get_uninterpreted_tail_size(); i < r->get_tail_size(); ++i) { + m_new_tail.push_back(r->get_tail(i)); + m_new_tail_neg.push_back(false); + } rule* new_r = m_context.get_rule_manager().mk(r->get_head(), m_new_tail.size(), m_new_tail.c_ptr(), m_new_tail_neg.c_ptr(), symbol::null, false); res->add_rule(new_r); From d79c33fb21eda6a2804d4820d2547526579ee128 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Jan 2018 16:12:38 -0800 Subject: [PATCH 0457/1283] fix model bugs Signed-off-by: Nikolaj Bjorner --- src/ast/expr2var.cpp | 8 ++--- src/sat/sat_solver/inc_sat_solver.cpp | 26 ++++++++------- src/sat/tactic/atom2bool_var.cpp | 6 ++++ src/sat/tactic/atom2bool_var.h | 1 + src/sat/tactic/goal2sat.cpp | 46 ++++++++++----------------- src/sat/tactic/goal2sat.h | 2 +- 6 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/ast/expr2var.cpp b/src/ast/expr2var.cpp index 2f850d645..ffa0b4fba 100644 --- a/src/ast/expr2var.cpp +++ b/src/ast/expr2var.cpp @@ -58,11 +58,9 @@ void expr2var::display(std::ostream & out) const { } void expr2var::mk_inv(expr_ref_vector & var2expr) const { - obj_map::iterator it = m_mapping.begin(); - obj_map::iterator end = m_mapping.end(); - for (; it != end; ++it) { - expr * t = it->m_key; - var x = it->m_value; + for (auto & kv : m_mapping) { + expr * t = kv.m_key; + var x = kv.m_value; if (x >= var2expr.size()) var2expr.resize(x+1, 0); var2expr.set(x, t); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 97818e155..bfa1731b2 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -533,11 +533,11 @@ private: TRACE("sat", g->display_with_dependencies(tout);); // ensure that if goal is already internalized, then import mc from m_solver. - if (!m_sat_mc) m_sat_mc = alloc(sat2goal::mc, m); - m_sat_mc->flush_smc(m_solver); m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, is_incremental(), is_lemma); m_goal2sat.get_interpreted_atoms(atoms); + if (!m_sat_mc) m_sat_mc = alloc(sat2goal::mc, m); + m_sat_mc->flush_smc(m_solver, m_map); if (!atoms.empty()) { std::stringstream strm; strm << "interpreted atoms sent to SAT solver " << atoms; @@ -798,16 +798,20 @@ private: } SASSERT(m_model); - DEBUG_CODE( - for (expr * f : m_fmls) { - expr_ref tmp(m); - if (m_model->eval(f, tmp, true)) { - CTRACE("sat", !m.is_true(tmp), - tout << "Evaluation failed: " << mk_pp(f, m) << " to " << tmp << "\n"; - model_smt2_pp(tout, m, *(m_model.get()), 0);); - SASSERT(m.is_true(tmp)); + IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); + for (expr * f : m_fmls) { + expr_ref tmp(m); + if (m_model->eval(f, tmp, true)) { + CTRACE("sat", !m.is_true(tmp), + tout << "Evaluation failed: " << mk_pp(f, m) << " to " << tmp << "\n"; + model_smt2_pp(tout, m, *(m_model.get()), 0);); + if (!m.is_true(tmp)) { + IF_VERBOSE(0, verbose_stream() << "failed to verify: " << tmp << "\n";); + IF_VERBOSE(0, verbose_stream() << m_params << "\n";); } - }); + VERIFY(m.is_true(tmp)); + } + } } }; diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp index d8827fe66..e3c9b6767 100644 --- a/src/sat/tactic/atom2bool_var.cpp +++ b/src/sat/tactic/atom2bool_var.cpp @@ -31,6 +31,12 @@ void atom2bool_var::mk_inv(expr_ref_vector & lit2expr) const { } } +void atom2bool_var::mk_var_inv(app_ref_vector & var2expr) const { + for (auto const& kv : m_mapping) { + var2expr.set(kv.m_value, to_app(kv.m_key)); + } +} + sat::bool_var atom2bool_var::to_bool_var(expr * n) const { sat::bool_var v = sat::null_bool_var; m_mapping.find(n, v); diff --git a/src/sat/tactic/atom2bool_var.h b/src/sat/tactic/atom2bool_var.h index d360d3fe0..b7f533537 100644 --- a/src/sat/tactic/atom2bool_var.h +++ b/src/sat/tactic/atom2bool_var.h @@ -31,6 +31,7 @@ public: void insert(expr * n, sat::bool_var v) { expr2var::insert(n, v); } sat::bool_var to_bool_var(expr * n) const; void mk_inv(expr_ref_vector & lit2expr) const; + void mk_var_inv(app_ref_vector & var2expr) const; // return true if the mapping contains uninterpreted atoms. bool interpreted_atoms() const { return expr2var::interpreted_vars(); } }; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index d810c60b7..97129a861 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -880,8 +880,10 @@ void goal2sat::get_interpreted_atoms(expr_ref_vector& atoms) { sat2goal::mc::mc(ast_manager& m): m(m), m_var2expr(m) {} -void sat2goal::mc::flush_smc(sat::solver& s) { +void sat2goal::mc::flush_smc(sat::solver& s, atom2bool_var const& map) { s.flush(m_smc); + m_var2expr.resize(s.num_vars()); + map.mk_var_inv(m_var2expr); } void sat2goal::mc::flush_gmc() { @@ -941,6 +943,7 @@ void sat2goal::mc::operator()(model_ref & md) { // create a SAT model using md sat::model sat_md; expr_ref val(m); + VERIFY(!m_var2expr.empty()); for (expr * atom : m_var2expr) { if (!atom) { sat_md.push_back(l_undef); @@ -1011,7 +1014,6 @@ expr_ref sat2goal::mc::lit2expr(sat::literal l) { struct sat2goal::imp { typedef mc sat_model_converter; - typedef ref sat_model_converter_ref; ast_manager & m; expr_ref_vector m_lit2expr; @@ -1034,23 +1036,7 @@ struct sat2goal::imp { throw tactic_exception(TACTIC_MAX_MEMORY_MSG); } - void init_lit2expr(sat::solver const & s, atom2bool_var const & map, sat_model_converter_ref & mc) { - unsigned num_vars = s.num_vars(); - m_lit2expr.resize(num_vars * 2); - map.mk_inv(m_lit2expr); - if (mc) { - for (sat::bool_var v = 0; v < num_vars; v++) { - checkpoint(); - sat::literal l(v, false); - if (m_lit2expr.get(l.index()) && !mc->var2expr(v)) { - mc->insert(v, to_app(m_lit2expr.get(l.index())), false); - SASSERT(m_lit2expr.get((~l).index())); - } - } - } - } - - expr * lit2expr(sat_model_converter_ref& mc, sat::literal l) { + expr * lit2expr(ref& mc, sat::literal l) { if (!m_lit2expr.get(l.index())) { SASSERT(m_lit2expr.get((~l).index()) == 0); app* aux = mc ? mc->var2expr(l.var()) : nullptr; @@ -1059,13 +1045,14 @@ struct sat2goal::imp { if (mc) mc->insert(l.var(), aux, true); } - m_lit2expr.set(l.index(), aux); - m_lit2expr.set((~l).index(), m.mk_not(aux)); + sat::literal lit(l.var(), false); + m_lit2expr.set(lit.index(), aux); + m_lit2expr.set((~lit).index(), m.mk_not(aux)); } return m_lit2expr.get(l.index()); } - void assert_pb(sat_model_converter_ref& mc, goal& r, sat::ba_solver::pb const& p) { + void assert_pb(ref& mc, goal& r, sat::ba_solver::pb const& p) { pb_util pb(m); ptr_buffer lits; vector coeffs; @@ -1082,7 +1069,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_card(sat_model_converter_ref& mc, goal& r, sat::ba_solver::card const& c) { + void assert_card(ref& mc, goal& r, sat::ba_solver::card const& c) { pb_util pb(m); ptr_buffer lits; for (sat::literal l : c) { @@ -1096,7 +1083,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_xor(sat_model_converter_ref& mc, goal & r, sat::ba_solver::xor const& x) { + void assert_xor(ref& mc, goal & r, sat::ba_solver::xor const& x) { ptr_buffer lits; for (sat::literal l : x) { lits.push_back(lit2expr(mc, l)); @@ -1109,7 +1096,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_clauses(sat_model_converter_ref& mc, sat::solver const & s, sat::clause_vector const& clauses, goal & r, bool asserted) { + void assert_clauses(ref& mc, sat::solver const & s, sat::clause_vector const& clauses, goal & r, bool asserted) { ptr_buffer lits; for (sat::clause* cp : clauses) { checkpoint(); @@ -1136,8 +1123,9 @@ struct sat2goal::imp { if (r.models_enabled() && !mc) { mc = alloc(sat_model_converter, m); } - if (mc) mc->flush_smc(s); - init_lit2expr(s, map, mc); + if (mc) mc->flush_smc(s, map); + m_lit2expr.resize(s.num_vars() * 2); + map.mk_inv(m_lit2expr); // collect units unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { @@ -1173,7 +1161,7 @@ struct sat2goal::imp { } } - void add_clause(sat_model_converter_ref& mc, sat::literal_vector const& lits, expr_ref_vector& lemmas) { + void add_clause(ref& mc, sat::literal_vector const& lits, expr_ref_vector& lemmas) { expr_ref_vector lemma(m); for (sat::literal l : lits) { expr* e = lit2expr(mc, l); @@ -1183,7 +1171,7 @@ struct sat2goal::imp { lemmas.push_back(mk_or(lemma)); } - void add_clause(sat_model_converter_ref& mc, sat::clause const& c, expr_ref_vector& lemmas) { + void add_clause(ref& mc, sat::clause const& c, expr_ref_vector& lemmas) { expr_ref_vector lemma(m); for (sat::literal l : c) { expr* e = lit2expr(mc, l); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 43ee5a835..463a50ff6 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -88,7 +88,7 @@ public: mc(ast_manager& m); virtual ~mc() {} // flush model converter from SAT solver to this structure. - void flush_smc(sat::solver& s); + void flush_smc(sat::solver& s, atom2bool_var const& map); void operator()(model_ref& md) override; void operator()(expr_ref& fml) override; model_converter* translate(ast_translation& translator) override; From 4adb24ede5879995a71e4f12d8e917ee6d4a8157 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Jan 2018 16:12:59 -0800 Subject: [PATCH 0458/1283] fix model bugs Signed-off-by: Nikolaj Bjorner --- src/model/model.cpp | 6 ++-- src/opt/maxres.cpp | 22 ++++++++----- src/opt/opt_context.cpp | 36 ++++++++++---------- src/sat/ba_solver.cpp | 3 +- src/sat/sat_solver.h | 1 + src/sat/sat_solver/inc_sat_solver.cpp | 28 +++++++++------- src/sat/tactic/atom2bool_var.cpp | 6 ++++ src/sat/tactic/atom2bool_var.h | 1 + src/sat/tactic/goal2sat.cpp | 47 ++++++++++----------------- src/sat/tactic/goal2sat.h | 2 +- 10 files changed, 79 insertions(+), 73 deletions(-) diff --git a/src/model/model.cpp b/src/model/model.cpp index 7ac1300de..d02785584 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -42,10 +42,8 @@ model::~model() { void model::copy_const_interps(model const & source) { - decl2expr::iterator it1 = source.m_interp.begin(); - decl2expr::iterator end1 = source.m_interp.end(); - for (; it1 != end1; ++it1) { - register_decl(it1->m_key, it1->m_value); + for (auto const& kv : source.m_interp) { + register_decl(kv.m_key, kv.m_value); } } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 5fa87b3ba..3d638212b 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -52,18 +52,19 @@ Notes: --*/ +#include "ast/ast_pp.h" +#include "ast/pb_decl_plugin.h" +#include "ast/ast_util.h" +#include "model/model_smt2_pp.h" #include "solver/solver.h" +#include "solver/mus.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "smt/smt_solver.h" +#include "opt/opt_context.h" +#include "opt/opt_params.hpp" #include "opt/maxsmt.h" #include "opt/maxres.h" -#include "ast/ast_pp.h" -#include "solver/mus.h" #include "opt/mss.h" -#include "sat/sat_solver/inc_sat_solver.h" -#include "opt/opt_context.h" -#include "ast/pb_decl_plugin.h" -#include "opt/opt_params.hpp" -#include "ast/ast_util.h" -#include "smt/smt_solver.h" using namespace opt; @@ -737,6 +738,8 @@ public: m_model = mdl; + TRACE("opt", model_smt2_pp(tout << "updated model\n", m, *m_model, 0);); + for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); } @@ -780,6 +783,9 @@ public: bool is_true(expr_ref_vector const& es) { unsigned i = 0; for (; i < es.size() && is_true(es[i]); ++i) { } + CTRACE("opt", i < es.size(), tout << mk_pp(es[i], m) << "\n"; + model_smt2_pp(tout, m, *m_model, 0); + ); return i == es.size(); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index dd90963df..7cb2c6034 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -17,11 +17,13 @@ Notes: --*/ -#include "opt/opt_context.h" -#include "ast/ast_pp.h" -#include "opt/opt_solver.h" -#include "opt/opt_params.hpp" #include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "ast/bv_decl_plugin.h" +#include "ast/pb_decl_plugin.h" +#include "ast/ast_smt_pp.h" +#include "ast/ast_pp_util.h" +#include "model/model_smt2_pp.h" #include "tactic/goal.h" #include "tactic/tactic.h" #include "tactic/arith/lia2card_tactic.h" @@ -32,17 +34,16 @@ Notes: #include "tactic/core/solve_eqs_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "tactic/tactical.h" -#include "model/model_smt2_pp.h" #include "tactic/arith/card2bv_tactic.h" #include "tactic/arith/eq2bv_tactic.h" #include "tactic/bv/dt2bv_tactic.h" -#include "sat/sat_solver/inc_sat_solver.h" -#include "ast/bv_decl_plugin.h" -#include "ast/pb_decl_plugin.h" -#include "ast/ast_smt_pp.h" #include "tactic/generic_model_converter.h" -#include "ast/ast_pp_util.h" +#include "sat/sat_solver/inc_sat_solver.h" #include "qe/qsat.h" +#include "opt/opt_context.h" +#include "opt/opt_solver.h" +#include "opt/opt_params.hpp" + namespace opt { @@ -995,7 +996,11 @@ namespace opt { } rational v = m_objectives[index].m_adjust_value(_v); expr_ref val(m); - model_ref mdl = md; + // + // we have to clone the model so that maxsat solver can use + // internal variables that are otherwise deleted from the model. + // + model_ref mdl = md->copy(); fix_model(mdl); if (!mdl->eval(term, val)) { @@ -1021,9 +1026,7 @@ namespace opt { generic_model_converter_ref fm; if (m_arith.is_add(term)) { expr_ref_vector args(m); - unsigned sz = term->get_num_args(); - for (unsigned i = 0; i < sz; ++i) { - expr* arg = term->get_arg(i); + for (expr* arg : *term) { if (is_mul_const(arg)) { args.push_back(arg); } @@ -1364,9 +1367,8 @@ namespace opt { if (m_simplify) { m_simplify->collect_statistics(stats); } - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; it != end; ++it) { - it->m_value->collect_statistics(stats); + for (auto const& kv : m_maxsmts) { + kv.m_value->collect_statistics(stats); } get_memory_statistics(stats); get_rlimit_statistics(m.limit(), stats); diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index be4498061..20a0a774d 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1640,7 +1640,6 @@ namespace sat { bool ba_solver::propagate(literal l, ext_constraint_idx idx) { SASSERT(value(l) == l_true); constraint& c = index2constraint(idx); - TRACE("ba", tout << l << "\n";); if (c.lit() != null_literal && l.var() == c.lit().var()) { init_watch(c); return true; @@ -1756,7 +1755,7 @@ namespace sat { for (unsigned i = 1; i < x.size(); ++i) { literal lit(value(x[i]) == l_true ? x[i] : ~x[i]); inc_parity(lit.var()); - if (true || lvl(lit) == level) { + if (lvl(lit) == level) { ++num_marks; } else { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index ad1f36c99..651eedee8 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -270,6 +270,7 @@ namespace sat { void set_non_external(bool_var v); bool was_eliminated(bool_var v) const { return m_eliminated[v] != 0; } void set_eliminated(bool_var v, bool f) { m_eliminated[v] = f; } + bool was_eliminated(literal l) const { return was_eliminated(l.var()); } unsigned scope_lvl() const { return m_scope_lvl; } unsigned search_lvl() const { return m_search_lvl; } bool at_search_lvl() const { return m_scope_lvl == m_search_lvl; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 97818e155..9f248c25f 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -533,11 +533,11 @@ private: TRACE("sat", g->display_with_dependencies(tout);); // ensure that if goal is already internalized, then import mc from m_solver. - if (!m_sat_mc) m_sat_mc = alloc(sat2goal::mc, m); - m_sat_mc->flush_smc(m_solver); m_goal2sat(*g, m_params, m_solver, m_map, dep2asm, is_incremental(), is_lemma); m_goal2sat.get_interpreted_atoms(atoms); + if (!m_sat_mc) m_sat_mc = alloc(sat2goal::mc, m); + m_sat_mc->flush_smc(m_solver, m_map); if (!atoms.empty()) { std::stringstream strm; strm << "interpreted atoms sent to SAT solver " << atoms; @@ -796,18 +796,22 @@ private: if (m_mc0) { (*m_mc0)(m_model); } - SASSERT(m_model); + TRACE("sat", model_smt2_pp(tout, m, *m_model, 0);); - DEBUG_CODE( - for (expr * f : m_fmls) { - expr_ref tmp(m); - if (m_model->eval(f, tmp, true)) { - CTRACE("sat", !m.is_true(tmp), - tout << "Evaluation failed: " << mk_pp(f, m) << " to " << tmp << "\n"; - model_smt2_pp(tout, m, *(m_model.get()), 0);); - SASSERT(m.is_true(tmp)); + IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); + for (expr * f : m_fmls) { + expr_ref tmp(m); + if (m_model->eval(f, tmp, true)) { + CTRACE("sat", !m.is_true(tmp), + tout << "Evaluation failed: " << mk_pp(f, m) << " to " << mk_pp(f, m) << "\n"; + model_smt2_pp(tout, m, *(m_model.get()), 0);); + if (!m.is_true(tmp)) { + IF_VERBOSE(0, verbose_stream() << "failed to verify: " << tmp << "\n";); + IF_VERBOSE(0, verbose_stream() << m_params << "\n";); } - }); + VERIFY(m.is_true(tmp)); + } + } } }; diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp index d8827fe66..e3c9b6767 100644 --- a/src/sat/tactic/atom2bool_var.cpp +++ b/src/sat/tactic/atom2bool_var.cpp @@ -31,6 +31,12 @@ void atom2bool_var::mk_inv(expr_ref_vector & lit2expr) const { } } +void atom2bool_var::mk_var_inv(app_ref_vector & var2expr) const { + for (auto const& kv : m_mapping) { + var2expr.set(kv.m_value, to_app(kv.m_key)); + } +} + sat::bool_var atom2bool_var::to_bool_var(expr * n) const { sat::bool_var v = sat::null_bool_var; m_mapping.find(n, v); diff --git a/src/sat/tactic/atom2bool_var.h b/src/sat/tactic/atom2bool_var.h index d360d3fe0..b7f533537 100644 --- a/src/sat/tactic/atom2bool_var.h +++ b/src/sat/tactic/atom2bool_var.h @@ -31,6 +31,7 @@ public: void insert(expr * n, sat::bool_var v) { expr2var::insert(n, v); } sat::bool_var to_bool_var(expr * n) const; void mk_inv(expr_ref_vector & lit2expr) const; + void mk_var_inv(app_ref_vector & var2expr) const; // return true if the mapping contains uninterpreted atoms. bool interpreted_atoms() const { return expr2var::interpreted_vars(); } }; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index d810c60b7..0e488c5c1 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -880,8 +880,11 @@ void goal2sat::get_interpreted_atoms(expr_ref_vector& atoms) { sat2goal::mc::mc(ast_manager& m): m(m), m_var2expr(m) {} -void sat2goal::mc::flush_smc(sat::solver& s) { + +void sat2goal::mc::flush_smc(sat::solver& s, atom2bool_var const& map) { s.flush(m_smc); + m_var2expr.resize(s.num_vars()); + map.mk_var_inv(m_var2expr); } void sat2goal::mc::flush_gmc() { @@ -941,6 +944,7 @@ void sat2goal::mc::operator()(model_ref & md) { // create a SAT model using md sat::model sat_md; expr_ref val(m); + VERIFY(!m_var2expr.empty()); for (expr * atom : m_var2expr) { if (!atom) { sat_md.push_back(l_undef); @@ -1011,7 +1015,6 @@ expr_ref sat2goal::mc::lit2expr(sat::literal l) { struct sat2goal::imp { typedef mc sat_model_converter; - typedef ref sat_model_converter_ref; ast_manager & m; expr_ref_vector m_lit2expr; @@ -1034,23 +1037,7 @@ struct sat2goal::imp { throw tactic_exception(TACTIC_MAX_MEMORY_MSG); } - void init_lit2expr(sat::solver const & s, atom2bool_var const & map, sat_model_converter_ref & mc) { - unsigned num_vars = s.num_vars(); - m_lit2expr.resize(num_vars * 2); - map.mk_inv(m_lit2expr); - if (mc) { - for (sat::bool_var v = 0; v < num_vars; v++) { - checkpoint(); - sat::literal l(v, false); - if (m_lit2expr.get(l.index()) && !mc->var2expr(v)) { - mc->insert(v, to_app(m_lit2expr.get(l.index())), false); - SASSERT(m_lit2expr.get((~l).index())); - } - } - } - } - - expr * lit2expr(sat_model_converter_ref& mc, sat::literal l) { + expr * lit2expr(ref& mc, sat::literal l) { if (!m_lit2expr.get(l.index())) { SASSERT(m_lit2expr.get((~l).index()) == 0); app* aux = mc ? mc->var2expr(l.var()) : nullptr; @@ -1059,13 +1046,14 @@ struct sat2goal::imp { if (mc) mc->insert(l.var(), aux, true); } - m_lit2expr.set(l.index(), aux); - m_lit2expr.set((~l).index(), m.mk_not(aux)); + sat::literal lit(l.var(), false); + m_lit2expr.set(lit.index(), aux); + m_lit2expr.set((~lit).index(), m.mk_not(aux)); } return m_lit2expr.get(l.index()); } - void assert_pb(sat_model_converter_ref& mc, goal& r, sat::ba_solver::pb const& p) { + void assert_pb(ref& mc, goal& r, sat::ba_solver::pb const& p) { pb_util pb(m); ptr_buffer lits; vector coeffs; @@ -1082,7 +1070,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_card(sat_model_converter_ref& mc, goal& r, sat::ba_solver::card const& c) { + void assert_card(ref& mc, goal& r, sat::ba_solver::card const& c) { pb_util pb(m); ptr_buffer lits; for (sat::literal l : c) { @@ -1096,7 +1084,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_xor(sat_model_converter_ref& mc, goal & r, sat::ba_solver::xor const& x) { + void assert_xor(ref& mc, goal & r, sat::ba_solver::xor const& x) { ptr_buffer lits; for (sat::literal l : x) { lits.push_back(lit2expr(mc, l)); @@ -1109,7 +1097,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_clauses(sat_model_converter_ref& mc, sat::solver const & s, sat::clause_vector const& clauses, goal & r, bool asserted) { + void assert_clauses(ref& mc, sat::solver const & s, sat::clause_vector const& clauses, goal & r, bool asserted) { ptr_buffer lits; for (sat::clause* cp : clauses) { checkpoint(); @@ -1136,8 +1124,9 @@ struct sat2goal::imp { if (r.models_enabled() && !mc) { mc = alloc(sat_model_converter, m); } - if (mc) mc->flush_smc(s); - init_lit2expr(s, map, mc); + if (mc) mc->flush_smc(s, map); + m_lit2expr.resize(s.num_vars() * 2); + map.mk_inv(m_lit2expr); // collect units unsigned trail_sz = s.init_trail_size(); for (unsigned i = 0; i < trail_sz; ++i) { @@ -1173,7 +1162,7 @@ struct sat2goal::imp { } } - void add_clause(sat_model_converter_ref& mc, sat::literal_vector const& lits, expr_ref_vector& lemmas) { + void add_clause(ref& mc, sat::literal_vector const& lits, expr_ref_vector& lemmas) { expr_ref_vector lemma(m); for (sat::literal l : lits) { expr* e = lit2expr(mc, l); @@ -1183,7 +1172,7 @@ struct sat2goal::imp { lemmas.push_back(mk_or(lemma)); } - void add_clause(sat_model_converter_ref& mc, sat::clause const& c, expr_ref_vector& lemmas) { + void add_clause(ref& mc, sat::clause const& c, expr_ref_vector& lemmas) { expr_ref_vector lemma(m); for (sat::literal l : c) { expr* e = lit2expr(mc, l); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 43ee5a835..463a50ff6 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -88,7 +88,7 @@ public: mc(ast_manager& m); virtual ~mc() {} // flush model converter from SAT solver to this structure. - void flush_smc(sat::solver& s); + void flush_smc(sat::solver& s, atom2bool_var const& map); void operator()(model_ref& md) override; void operator()(expr_ref& fml) override; model_converter* translate(ast_translation& translator) override; From 3047d930e12297ae74d4d11979f5c266e41475f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Jan 2018 19:53:50 -0800 Subject: [PATCH 0459/1283] fix xor processing Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 65 ++++++++++++++++++++----------------- src/sat/ba_solver.h | 7 ++-- src/sat/tactic/goal2sat.cpp | 10 ++++-- 3 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index e6f16dba5..7865f618e 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -189,8 +189,8 @@ namespace sat { // ----------------------------------- // xor - ba_solver::xor::xor(unsigned id, literal lit, literal_vector const& lits): - constraint(xor_t, id, lit, lits.size(), get_obj_size(lits.size())) { + ba_solver::xor::xor(unsigned id, literal_vector const& lits): + constraint(xor_t, id, null_literal, lits.size(), get_obj_size(lits.size())) { for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; } @@ -959,17 +959,19 @@ namespace sat { lbool ba_solver::add_assign(xor& x, literal alit) { // literal is assigned unsigned sz = x.size(); - TRACE("ba", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); + TRACE("ba", tout << "assign: " << ~alit << "@" << lvl(~alit) << " " << x << "\n"; display(tout, x, true); ); - SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); + SASSERT(x.lit() == null_literal); SASSERT(value(alit) != l_undef); unsigned index = 0; - for (; index <= 2; ++index) { + for (; index < 2; ++index) { if (x[index].var() == alit.var()) break; } if (index == 2) { // literal is no longer watched. - UNREACHABLE(); + // this can happen as both polarities of literals + // are put in watch lists and they are removed only + // one polarity at a time. return l_undef; } SASSERT(x[index].var() == alit.var()); @@ -979,7 +981,10 @@ namespace sat { literal lit2 = x[i]; if (value(lit2) == l_undef) { x.swap(index, i); + // unwatch_literal(alit, x); watch_literal(lit2, x); + watch_literal(~lit2, x); + TRACE("ba", tout << "swap in: " << lit2 << " " << x << "\n";); return l_undef; } } @@ -1627,13 +1632,13 @@ namespace sat { add_pb_ge(lit, wlits, k, false); } - void ba_solver::add_xor(bool_var v, literal_vector const& lits) { - add_xor(literal(v, false), lits, false); + void ba_solver::add_xor(literal_vector const& lits) { + add_xor(lits, false); } - ba_solver::constraint* ba_solver::add_xor(literal lit, literal_vector const& lits, bool learned) { + ba_solver::constraint* ba_solver::add_xor(literal_vector const& lits, bool learned) { void * mem = m_allocator.allocate(xor::get_obj_size(lits.size())); - xor* x = new (mem) xor(next_id(), lit, lits); + xor* x = new (mem) xor(next_id(), lits); x->set_learned(learned); add_constraint(x); for (literal l : lits) s().set_external(l.var()); // TBD: determine if goal2sat does this. @@ -1740,20 +1745,24 @@ namespace sat { unsigned level = lvl(l); bool_var v = l.var(); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); - TRACE("ba", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); + TRACE("ba", tout << l << ": " << js << "\n"; + for (unsigned i = 0; i <= index; ++i) tout << s().m_trail[i] << " "; tout << "\n"; + s().display_units(tout); + ); unsigned num_marks = 0; unsigned count = 0; while (true) { + TRACE("ba", tout << "process: " << l << "\n";); ++count; if (js.get_kind() == justification::EXT_JUSTIFICATION) { constraint& c = index2constraint(js.get_ext_justification_idx()); + TRACE("ba", tout << c << "\n";); if (!c.is_xor()) { r.push_back(l); } else { - xor& x = c.to_xor(); - if (x.lit() != null_literal && lvl(x.lit()) > 0) r.push_back(x.lit()); + xor& x = c.to_xor(); if (x[1].var() == l.var()) { x.swap(0, 1); } @@ -1762,6 +1771,7 @@ namespace sat { literal lit(value(x[i]) == l_true ? x[i] : ~x[i]); inc_parity(lit.var()); if (lvl(lit) == level) { + TRACE("ba", tout << "mark: " << lit << "\n";); ++num_marks; } else { @@ -1773,24 +1783,25 @@ namespace sat { else { r.push_back(l); } + bool found = false; while (num_marks > 0) { l = s().m_trail[index]; v = l.var(); unsigned n = get_parity(v); if (n > 0) { reset_parity(v); + num_marks -= n; if (n % 2 == 1) { + found = true; break; } - --num_marks; } --index; } - if (num_marks == 0) { + if (!found) { break; } --index; - --num_marks; js = s().m_justification[v]; } @@ -2492,6 +2503,11 @@ namespace sat { m_lits.append(n, lits); s.s().mk_clause(n, m_lits.c_ptr()); } + + std::ostream& ba_solver::ba_sort::pp(std::ostream& out, literal l) const { + return out << l; + } + // ------------------------------- // set literals equivalent @@ -3299,7 +3315,7 @@ namespace sat { xor const& x = cp->to_xor(); lits.reset(); for (literal l : x) lits.push_back(l); - result->add_xor(x.lit(), lits, x.learned()); + result->add_xor(lits, x.learned()); break; } default: @@ -3427,19 +3443,8 @@ namespace sat { } void ba_solver::display(std::ostream& out, xor const& x, bool values) const { - out << "xor " << x.lit(); - if (x.lit() != null_literal && values) { - out << "@(" << value(x.lit()); - if (value(x.lit()) != l_undef) { - out << ":" << lvl(x.lit()); - } - out << "): "; - } - else { - out << ": "; - } - for (unsigned i = 0; i < x.size(); ++i) { - literal l = x[i]; + out << "xor: "; + for (literal l : x) { out << l; if (values) { out << "@(" << value(l); diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 1116bb166..cd2e941ce 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -178,7 +178,7 @@ namespace sat { literal m_lits[0]; public: static size_t get_obj_size(unsigned num_lits) { return sizeof(xor) + num_lits * sizeof(literal); } - xor(unsigned id, literal lit, literal_vector const& lits); + xor(unsigned id, literal_vector const& lits); literal operator[](unsigned i) const { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return begin() + m_size; } @@ -246,6 +246,7 @@ namespace sat { literal mk_max(literal l1, literal l2); literal mk_min(literal l1, literal l2); void mk_clause(unsigned n, literal const* lits); + std::ostream& pp(std::ostream& out, literal l) const; }; ba_sort m_ba; psort_nw m_sort; @@ -458,7 +459,7 @@ namespace sat { constraint* add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned); constraint* add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); - constraint* add_xor(literal l, literal_vector const& lits, bool learned); + constraint* add_xor(literal_vector const& lits, bool learned); void copy_core(ba_solver* result); public: @@ -469,7 +470,7 @@ namespace sat { virtual void set_unit_walk(unit_walk* u) { m_unit_walk = u; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); void add_pb_ge(bool_var v, svector const& wlits, unsigned k); - void add_xor(bool_var v, literal_vector const& lits); + void add_xor(literal_vector const& lits); virtual bool propagate(literal l, ext_constraint_idx idx); virtual lbool resolve_conflict(); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 97129a861..596712a7b 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -392,11 +392,15 @@ struct goal2sat::imp { return; } sat::literal_vector lits; - convert_pb_args(num, lits); sat::bool_var v = m_solver.mk_var(true); + lits.push_back(sat::literal(v, true)); + convert_pb_args(num, lits); + // ensure that = is converted to xor + for (unsigned i = 1; i + 1 < lits.size(); ++i) { + lits[i].neg(); + } ensure_extension(); - if (lits.size() % 2 == 0) lits[0].neg(); - m_ext->add_xor(v, lits); + m_ext->add_xor(lits); sat::literal lit(v, sign); if (root) { m_result_stack.reset(); From b5335bc34be690c722e94192d4471c3894ab67da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Jan 2018 20:08:23 -0800 Subject: [PATCH 0460/1283] change behavior of single-objective pareto to use Pareto GIA algorithm (so not a good idea with MaxSAT solving, but then uniform behavior #1439 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 0daf98320..f5f3f06fd 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -287,27 +287,24 @@ namespace opt { TRACE("opt", model_smt2_pp(tout, m, *m_model, 0);); m_optsmt.setup(*m_opt_solver.get()); update_lower(); + + opt_params optp(m_params); + symbol pri = optp.priority(); - switch (m_objectives.size()) { - case 0: - break; - case 1: - is_sat = execute(m_objectives[0], true, false); - break; - default: { - opt_params optp(m_params); - symbol pri = optp.priority(); - if (pri == symbol("pareto")) { - is_sat = execute_pareto(); - } - else if (pri == symbol("box")) { - is_sat = execute_box(); - } - else { - is_sat = execute_lex(); - } - break; + if (0 == m_objectives.size()) { + // no op } + else if (pri == symbol("pareto")) { + is_sat = execute_pareto(); + } + else if (1 == m_objectives.size()) { + is_sat = execute(m_objectives[0], true, false); + } + else if (pri == symbol("box")) { + is_sat = execute_box(); + } + else { + is_sat = execute_lex(); } return adjust_unknown(is_sat); } From 6f889ab699b4115f92530040840d2fd01489717e Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 15 Jan 2018 14:08:15 -0500 Subject: [PATCH 0461/1283] intersection WIP; fix polarity of generated path constraint LHS --- src/smt/theory_str.cpp | 74 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 6e4211f7b..27757a53e 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6982,6 +6982,9 @@ namespace smt { pathChars_len_constraints.push_back(ctx.mk_eq_atom(mk_strlen(ch), m_autil.mk_numeral(rational::one(), true))); } + // TODO(mtrberzi) possibly modify this to reuse character terms over the same string, + // i.e. across different constraints over S the same variables S_0, S_1, ... are always used and refreshed + // modification of code in seq_rewriter::mk_str_in_regexp() expr_ref_vector trail(m); u_map maps[2]; @@ -9536,6 +9539,7 @@ namespace smt { // regex automata if (m_params.m_RegexAutomata) { // TODO since heuristics might fail, the "no progress" flag might need to be handled specially here + // TODO learning of linear length constraints in the style of length automata, if possible? bool regex_axiom_add = false; for (obj_hashtable::iterator it = regex_terms.begin(); it != regex_terms.end(); ++it) { expr * str_in_re = *it; @@ -9584,16 +9588,22 @@ namespace smt { TRACE("str", tout << "character constraints are " << mk_pp(characterConstraints, m) << std::endl;); expr_ref_vector lhs_terms(m); - lhs_terms.push_back(str_in_re); + if (current_assignment == l_true) { + lhs_terms.push_back(str_in_re); + } else { + lhs_terms.push_back(m.mk_not(str_in_re)); + } lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true))); expr_ref lhs(mk_and(lhs_terms), m); // If the automaton was built with the same polarity as the constraint, // assert directly. Otherwise, negate the path constraint if ( (current_assignment == l_true && assumption.get_polarity()) || (current_assignment == l_false && !assumption.get_polarity())) { + TRACE("str", tout << "automaton and regex term have same polarity" << std::endl;); expr_ref rhs(m.mk_and(pathConstraint, characterConstraints), m); assert_implication(lhs, rhs); } else { + TRACE("str", tout << "automaton and regex term have opposite polarity" << std::endl;); expr_ref rhs(m.mk_and(m.mk_not(pathConstraint), characterConstraints), m); assert_implication(lhs, rhs); } @@ -9893,7 +9903,64 @@ namespace smt { // choose an automaton/assumption for each assigned (str.in.re) // that's consistent with the current length information - NOT_IMPLEMENTED_YET(); + for (ptr_vector::iterator term_it = str_in_re_terms.begin(); + term_it != str_in_re_terms.end(); ++term_it) { + expr * _unused; + expr * re; + SASSERT(u.str.is_in_re(*term_it)); + u.str.is_in_re(*term_it, _unused, re); + + rational exact_len; + bool has_exact_len = get_len_value(str, exact_len); + + rational lb, ub; + bool has_lower_bound = lower_bound(mk_strlen(str), lb); + bool has_upper_bound = upper_bound(mk_strlen(str), ub); + + if (regex_automaton_assumptions.contains(re) && + !regex_automaton_assumptions[re].empty()){ + for (svector::iterator aut_it = regex_automaton_assumptions[re].begin(); + aut_it != regex_automaton_assumptions[re].end(); ++aut_it) { + regex_automaton_under_assumptions aut = *aut_it; + rational aut_ub; + bool assume_ub = aut.get_upper_bound(aut_ub); + rational aut_lb; + bool assume_lb = aut.get_lower_bound(aut_lb); + bool consistent = true; + + if (assume_ub) { + // check consistency of assumed upper bound + if (has_exact_len) { + if (exact_len > aut_ub) { + consistent = false; + } + } else { + if (has_upper_bound && ub > aut_ub) { + consistent = false; + } + } + } + + if (assume_lb) { + // check consistency of assumed lower bound + if (has_exact_len) { + if (exact_len < aut_lb) { + consistent = false; + } + } else { + if (has_lower_bound && lb < aut_lb) { + consistent = false; + } + } + } + + if (consistent) { + intersect_constraints.push_back(aut); + break; + } + } + } + } // foreach(term in str_in_re_terms) eautomaton * aut_inter = NULL; CTRACE("str", !intersect_constraints.empty(), tout << "check intersection of automata constraints for " << mk_pp(str, m) << std::endl;); @@ -9933,7 +10000,8 @@ namespace smt { } } } // foreach(entry in intersect_constraints) - if (aut_inter->is_empty()) { + TRACE("str", tout << "intersected " << used_intersect_constraints.size() << " constraints" << std::endl;); + if (aut_inter != NULL && aut_inter->is_empty()) { TRACE("str", tout << "product automaton is empty; asserting conflict clause" << std::endl;); NOT_IMPLEMENTED_YET(); } From 058d24fd096ec30b0f55fe84afa56c9213b045e7 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 15 Jan 2018 14:30:12 -0500 Subject: [PATCH 0462/1283] reuse regex character constraints for the same string --- src/smt/theory_str.cpp | 43 +++++++++++++++++++++++++++++++++--------- src/smt/theory_str.h | 1 + 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 27757a53e..1fc04c77f 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6974,16 +6974,41 @@ namespace smt { expr_ref_vector pathChars(m); expr_ref_vector pathChars_len_constraints(m); - for (unsigned i = 0; i < lenVal.get_unsigned(); ++i) { - std::stringstream ss; - ss << "ch" << i; - expr_ref ch(mk_str_var(ss.str()), m); - pathChars.push_back(ch); - pathChars_len_constraints.push_back(ctx.mk_eq_atom(mk_strlen(ch), m_autil.mk_numeral(rational::one(), true))); - } - // TODO(mtrberzi) possibly modify this to reuse character terms over the same string, - // i.e. across different constraints over S the same variables S_0, S_1, ... are always used and refreshed + // reuse character terms over the same string + if (string_chars.contains(stringTerm)) { + // find out whether we have enough characters already + ptr_vector old_chars; + string_chars.find(stringTerm, old_chars); + if (old_chars.size() < lenVal.get_unsigned()) { + for (unsigned i = old_chars.size(); i < lenVal.get_unsigned(); ++i) { + std::stringstream ss; + ss << "ch" << i; + expr_ref ch(mk_str_var(ss.str()), m); + m_trail.push_back(ch); + old_chars.push_back(ch); + } + } + string_chars.insert(stringTerm, old_chars); + // now we're guaranteed to have at least the right number of characters in old_chars + for (unsigned i = 0; i < lenVal.get_unsigned(); ++i) { + expr_ref ch(old_chars.get(i), m); + refresh_theory_var(ch); + pathChars.push_back(ch); + pathChars_len_constraints.push_back(ctx.mk_eq_atom(mk_strlen(ch), m_autil.mk_numeral(rational::one(), true))); + } + } else { + ptr_vector new_chars; + for (unsigned i = 0; i < lenVal.get_unsigned(); ++i) { + std::stringstream ss; + ss << "ch" << i; + expr_ref ch(mk_str_var(ss.str()), m); + pathChars.push_back(ch); + pathChars_len_constraints.push_back(ctx.mk_eq_atom(mk_strlen(ch), m_autil.mk_numeral(rational::one(), true))); + new_chars.push_back(ch); + } + string_chars.insert(stringTerm, new_chars); + } // modification of code in seq_rewriter::mk_str_in_regexp() expr_ref_vector trail(m); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 45df675fb..86929d4d3 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -415,6 +415,7 @@ protected: obj_map regex_length_attempt_count; obj_map regex_fail_count; obj_map regex_intersection_fail_count; + obj_map > string_chars; // S --> [S_0, S_1, ...] for character terms S_i svector char_set; std::map charSetLookupTable; From 191cc30e2a6116b1f3c03c05495bb52da762275a Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 15 Jan 2018 15:30:12 -0500 Subject: [PATCH 0463/1283] intersection of regex constraints produces a conflict clause --- src/smt/theory_str.cpp | 56 +++++++++++++++++++++++++++++++++++++----- src/smt/theory_str.h | 10 ++++---- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 1fc04c77f..4c36b0f45 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9637,7 +9637,13 @@ namespace smt { regex_axiom_add = true; // increment LengthAttemptCount - regex_inc_counter(regex_length_attempt_count, str_in_re); + regex_inc_counter(regex_length_attempt_count, re); + + { + unsigned v = regex_get_counter(regex_length_attempt_count, re); + TRACE("str", tout << "length attempt count for " << mk_pp(re, m) << " is " << v << std::endl;); + } + continue; } else { // no automata available, or else all bounds assumptions are invalid @@ -9910,8 +9916,6 @@ namespace smt { } } } - - // NOT_IMPLEMENTED_YET(); } // foreach (entry in regex_terms) for (obj_map >::iterator it = regex_terms_by_string.begin(); @@ -9999,11 +10003,19 @@ namespace smt { continue; } + { + unsigned v = regex_get_counter(regex_length_attempt_count, aut.get_regex_term()); + TRACE("str", tout << "length attempt count of " << mk_pp(aut.get_regex_term(), m) << " is " << v + << ", threshold is " << m_params.m_RegexAutomata_LengthAttemptThreshold << std::endl;); + } + if (regex_get_counter(regex_length_attempt_count, aut.get_regex_term()) >= m_params.m_RegexAutomata_LengthAttemptThreshold) { unsigned intersectionDifficulty = 0; // TODO EstimateIntersectionDifficulty if (intersectionDifficulty <= m_params.m_RegexAutomata_IntersectionDifficultyThreshold || regex_get_counter(regex_intersection_fail_count, aut.get_regex_term()) >= m_params.m_RegexAutomata_FailedIntersectionThreshold) { - lbool current_assignment = ctx.get_assignment(aut.get_regex_term()); + + expr * str_in_re_term(u.re.mk_in_re(str, aut.get_regex_term())); + lbool current_assignment = ctx.get_assignment(str_in_re_term); // if the assignment is consistent with our assumption, use the automaton directly; // otherwise, complement it (and save that automaton for next time) // TODO we should cache these intermediate results @@ -10013,7 +10025,12 @@ namespace smt { aut_inter = m_mk_aut.mk_product(aut_inter, aut.get_automaton()); } else { // need to complement first - NOT_IMPLEMENTED_YET(); + expr_ref rc(u.re.mk_complement(aut.get_regex_term()), m); + eautomaton * aut_c = m_mk_aut(rc); + regex_automata.push_back(aut_c); + // TODO is there any way to build a complement automaton from an existing one? + // this discards length information + aut_inter = m_mk_aut.mk_product(aut_inter, aut_c); } used_intersect_constraints.push_back(aut); if (aut_inter->is_empty()) { @@ -10028,7 +10045,34 @@ namespace smt { TRACE("str", tout << "intersected " << used_intersect_constraints.size() << " constraints" << std::endl;); if (aut_inter != NULL && aut_inter->is_empty()) { TRACE("str", tout << "product automaton is empty; asserting conflict clause" << std::endl;); - NOT_IMPLEMENTED_YET(); + expr_ref_vector conflict_terms(m); + + for (svector::iterator aut_it = used_intersect_constraints.begin(); + aut_it != used_intersect_constraints.end(); ++aut_it) { + regex_automaton_under_assumptions aut = *aut_it; + expr * str_in_re_term(u.re.mk_in_re(str, aut.get_regex_term())); + lbool current_assignment = ctx.get_assignment(str_in_re_term); + if (current_assignment == l_true) { + conflict_terms.push_back(str_in_re_term); + } else if (current_assignment == l_false) { + conflict_terms.push_back(m.mk_not(str_in_re_term)); + } + // add length assumptions, if any + rational ub; + if (aut.get_upper_bound(ub)) { + expr_ref ub_term(m_autil.mk_le(mk_strlen(str), m_autil.mk_numeral(ub, true)), m); + conflict_terms.push_back(ub_term); + } + rational lb; + if (aut.get_lower_bound(lb)) { + expr_ref lb_term(m_autil.mk_ge(mk_strlen(str), m_autil.mk_numeral(lb, true)), m); + conflict_terms.push_back(lb_term); + } + } + + expr_ref conflict_clause(m.mk_not(mk_and(conflict_terms)), m); + assert_axiom(conflict_clause); + regex_axiom_add = true; } } // foreach (entry in regex_terms_by_string) diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 86929d4d3..acab8e019 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -168,7 +168,7 @@ public: class regex_automaton_under_assumptions { protected: - expr * str_in_re; + expr * re_term; eautomaton * aut; bool polarity; @@ -179,11 +179,11 @@ protected: rational upper_bound; public: regex_automaton_under_assumptions() : - str_in_re(NULL), aut(NULL), polarity(false), + re_term(NULL), aut(NULL), polarity(false), assume_lower_bound(false), assume_upper_bound(false) {} - regex_automaton_under_assumptions(expr * str_in_re, eautomaton * aut, bool polarity) : - str_in_re(str_in_re), aut(aut), polarity(polarity), + regex_automaton_under_assumptions(expr * re_term, eautomaton * aut, bool polarity) : + re_term(re_term), aut(aut), polarity(polarity), assume_lower_bound(false), assume_upper_bound(false) {} void set_lower_bound(rational & lb) { @@ -221,7 +221,7 @@ public: } eautomaton * get_automaton() const { return aut; } - expr * get_regex_term() const { return str_in_re; } + expr * get_regex_term() const { return re_term; } bool get_polarity() const { return polarity; } virtual ~regex_automaton_under_assumptions() { From ae728374c84a6bf65f4849d3341ad83140105005 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Jan 2018 17:20:19 -0800 Subject: [PATCH 0464/1283] disable buggy clausification in ba_solver Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 ++ src/sat/sat_solver/inc_sat_solver.cpp | 26 +++++++++++++++++++++----- src/solver/solver.cpp | 2 ++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 7865f618e..4099693c5 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2649,6 +2649,7 @@ namespace sat { } bool ba_solver::clausify(literal lit, unsigned n, literal const* lits, unsigned k) { + return false; bool is_def = lit != null_literal; if ((!is_def || !s().was_eliminated(lit)) && !std::any_of(lits, lits + n, [&](literal l) { return s().was_eliminated(l); })) { @@ -2667,6 +2668,7 @@ namespace sat { } bool ba_solver::clausify(card& c) { + return false; if (get_config().m_card_solver) return false; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 9f248c25f..ef85ad921 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -60,7 +60,8 @@ class inc_sat_solver : public solver { goal_ref_buffer m_subgoals; proof_converter_ref m_pc; model_converter_ref m_mc; - model_converter_ref m_mc0; + mutable model_converter_ref m_mc0; + mutable obj_hashtable m_inserted_const2bits; ref m_sat_mc; mutable model_converter_ref m_cached_mc; svector m_weights; @@ -227,6 +228,7 @@ public: n = m_num_scopes; // take over for another solver. } if (m_bb_rewriter) m_bb_rewriter->pop(n); + m_inserted_const2bits.reset(); m_map.pop(n); SASSERT(n <= m_num_scopes); m_solver.user_pop(n); @@ -443,7 +445,8 @@ public: if (m_cached_mc) return m_cached_mc; if (is_internalized() && m_internalized_converted) { - m_cached_mc = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); + insert_const2bits(); + m_cached_mc = m_mc0.get(); m_cached_mc = concat(solver::get_model_converter().get(), m_cached_mc.get()); m_cached_mc = concat(m_cached_mc.get(), m_sat_mc.get()); return m_cached_mc; @@ -500,6 +503,21 @@ public: private: + void insert_const2bits() const { + if (!m_bb_rewriter) return; + obj_map to_insert; + obj_map const& const2bits = m_bb_rewriter->const2bits(); + for (auto const& kv : const2bits) { + if (!m_inserted_const2bits.contains(kv.m_key)) { + m_inserted_const2bits.insert(kv.m_key); + to_insert.insert(kv.m_key, kv.m_value); + } + } + if (!to_insert.empty()) { + m_mc0 = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, to_insert)); + } + } + lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm, bool is_lemma) { m_mc.reset(); @@ -790,9 +808,7 @@ private: if (m_sat_mc) { (*m_sat_mc)(m_model); } - if (m_bb_rewriter.get() && !m_bb_rewriter->const2bits().empty()) { - m_mc0 = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, m_bb_rewriter->const2bits())); - } + insert_const2bits(); if (m_mc0) { (*m_mc0)(m_model); } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 43ca9870a..9fbaa8032 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -193,6 +193,8 @@ void solver::assert_expr(expr* f, expr* t) { expr_ref fml(f, m); expr_ref a(t, m); if (m_enforce_model_conversion) { + IF_VERBOSE(0, verbose_stream() << "enforce model conversion\n";); + exit(0); model_converter_ref mc = get_model_converter(); mc = concat(mc0(), mc.get()); if (mc) { From 6c4c9a10e4be2ae1baf646580f635a831f319b02 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Tue, 16 Jan 2018 13:16:31 -0500 Subject: [PATCH 0465/1283] regex length linearity check WIP --- src/smt/theory_str.cpp | 34 ++++++++++++++++++++++++++++++++++ src/smt/theory_str.h | 2 ++ 2 files changed, 36 insertions(+) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 4c36b0f45..c19b17aec 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6604,6 +6604,40 @@ namespace smt { return 1; } } + + // Check whether a regex translates well to a linear set of length constraints. + bool theory_str::check_regex_length_linearity(expr * re) { + return check_regex_length_linearity_helper(re, false); + } + + bool theory_str::check_regex_length_linearity_helper(expr * re, bool already_star) { + expr * sub1; + expr * sub2; + if (u.re.is_to_re(re)) { + return true; + } else if (u.re.is_concat(re, sub1, sub2)) { + return check_regex_length_linearity_helper(sub1, already_star) && check_regex_length_linearity_helper(sub2, already_star); + } else if (u.re.is_union(re, sub1, sub2)) { + return check_regex_length_linearity_helper(sub1, already_star) && check_regex_length_linearity_helper(sub2, already_star); + } else if (u.re.is_star(re, sub1) || u.re.is_plus(re, sub1)) { + if (already_star) { + return false; + } else { + return check_regex_length_linearity_helper(sub1, true); + } + } else if (u.re.is_range(re)) { + return true; + } else if (u.re.is_full(re)) { + return true; + } else if (u.re.is_complement(re)) { + // TODO can we do better? + return false; + } else { + TRACE("str", tout << "WARNING: unknown regex term " << mk_pp(re, get_manager()) << std::endl;); + UNREACHABLE(); return false; + } + } + /* * Infer all length constraints implied by the given regular expression `re` * in order to constrain `lenVar` (which must be of sort Int). diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index acab8e019..26a6acf8d 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -544,6 +544,8 @@ protected: // regex automata and length-aware regex unsigned estimate_regex_complexity(expr * re); unsigned estimate_regex_complexity_under_complement(expr * re); + bool check_regex_length_linearity(expr * re); + bool check_regex_length_linearity_helper(expr * re, bool already_star); expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); bool refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound); bool refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound); From 153701eabe3562fd169d4bc863ebb1b5827fe842 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Tue, 16 Jan 2018 13:56:01 -0500 Subject: [PATCH 0466/1283] regex length term assertion WIP --- src/smt/theory_str.cpp | 49 ++++++++++++++++++++++++++++++++++++++++-- src/smt/theory_str.h | 3 +++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index c19b17aec..59b3b7753 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6735,8 +6735,6 @@ namespace smt { bool theory_str::refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound) { ENSURE(aut != NULL); - ast_manager & m = get_manager(); - if (aut->final_states().size() < 1) { // no solutions at all refined_lower_bound = rational::minus_one(); @@ -9610,6 +9608,53 @@ namespace smt { if (current_assignment == l_undef) { continue; } + + if (!regex_terms_with_length_constraints.contains(str_in_re)) { + if (current_assignment == l_true && check_regex_length_linearity(re)) { + TRACE("str", tout << "regex length constraints expected to be linear -- generating and asserting them" << std::endl;); + + if (regex_term_to_length_constraint.contains(str_in_re)) { + // use existing length constraint + expr * top_level_length_constraint; + regex_term_to_length_constraint.find(str_in_re, top_level_length_constraint); + + ptr_vector extra_length_vars; + regex_term_to_extra_length_vars.find(str_in_re, extra_length_vars); + + assert_axiom(top_level_length_constraint); + for(ptr_vector::iterator it = extra_length_vars.begin(); it != extra_length_vars.end(); ++it) { + expr * v = *it; + refresh_theory_var(v); + expr_ref len_constraint(m_autil.mk_ge(v, m_autil.mk_numeral(rational::zero(), true)), m); + assert_axiom(len_constraint); + } + } else { + // generate new length constraint + expr_ref_vector extra_length_vars(m); + expr_ref top_level_length_constraint = infer_all_regex_lengths(mk_strlen(str), re, extra_length_vars); + TRACE("str", tout << "top-level length constraint: " << mk_pp(top_level_length_constraint, m) << std::endl;); + // assert and track length constraint + assert_axiom(top_level_length_constraint); + for(expr_ref_vector::iterator it = extra_length_vars.begin(); it != extra_length_vars.end(); ++it) { + expr * v = *it; + expr_ref len_constraint(m_autil.mk_ge(v, m_autil.mk_numeral(rational::zero(), true)), m); + assert_axiom(len_constraint); + } + + regex_term_to_length_constraint.insert(str_in_re, top_level_length_constraint); + ptr_vector vtmp; + for(expr_ref_vector::iterator it = extra_length_vars.begin(); it != extra_length_vars.end(); ++it) { + vtmp.push_back(*it); + } + regex_term_to_extra_length_vars.insert(str_in_re, vtmp); + } + + regex_terms_with_length_constraints.insert(str_in_re); + m_trail_stack.push(insert_obj_trail(regex_terms_with_length_constraints, str_in_re)); + regex_axiom_add = true; + } + } // re not in regex_terms_with_length_constraints + rational exact_length_value; if (get_len_value(str, exact_length_value)) { TRACE("str", tout << "exact length of " << mk_pp(str, m) << " is " << exact_length_value << std::endl;); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 26a6acf8d..0d56211cd 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -409,6 +409,9 @@ protected: obj_map > regex_automaton_assumptions; // RegEx --> [ aut+assumptions ] std::map regex_nfa_cache; // Regex term --> NFA obj_hashtable regex_terms_with_path_constraints; // set of string terms which have had path constraints asserted in the current scope + obj_hashtable regex_terms_with_length_constraints; // set of regex terms which had had length constraints asserted in the current scope + obj_map regex_term_to_length_constraint; // (str.in.re S R) -> (length constraint over S wrt. R) + obj_map > regex_term_to_extra_length_vars; // extra length vars used in regex_term_to_length_constraint entries // each counter maps a (str.in.re) expression to an integer. // use helper functions regex_inc_counter() and regex_get_counter() to access From e5585ecf4c65e1c7427339a6a86998afad450220 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Tue, 16 Jan 2018 18:15:29 -0500 Subject: [PATCH 0467/1283] regex fail count and automaton fallback --- src/smt/theory_str.cpp | 29 +++++++++++++++++++++-------- src/smt/theory_str.h | 1 + 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 59b3b7753..474dd9c39 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9854,8 +9854,11 @@ namespace smt { } else { // TODO check negation? // TODO construct a partial automaton for R to the given upper bound? - // TODO increment failure count if we can't - NOT_IMPLEMENTED_YET(); + if (false) { + + } else { + regex_inc_counter(regex_fail_count, str_in_re); + } } continue; } @@ -9866,8 +9869,8 @@ namespace smt { } } else { // !upper_bound_exists // no upper bound information - if (lower_bound_exists) { - // lower bound, no upper bound + if (lower_bound_exists && !lower_bound_value.is_zero()) { + // nonzero lower bound, no upper bound // check current assumptions if (regex_automaton_assumptions.contains(re) && @@ -9967,7 +9970,11 @@ namespace smt { // TODO check negation? // TODO construct a partial automaton for R to the given lower bound? // TODO increment failure count - NOT_IMPLEMENTED_YET(); + if (false) { + + } else { + regex_inc_counter(regex_fail_count, str_in_re); + } } continue; } @@ -9976,10 +9983,12 @@ namespace smt { // check for existing automata; // try to construct an automaton if we don't have one yet // and doing so without bounds is not difficult - NOT_IMPLEMENTED_YET(); - if (true) { + bool existingAutomata = (regex_automaton_assumptions.contains(re) && !regex_automaton_assumptions[re].empty()); + bool failureThresholdExceeded = (regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold); + if (!existingAutomata || failureThresholdExceeded) { unsigned expected_complexity = estimate_regex_complexity(re); - if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold) { + if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold + || failureThresholdExceeded) { eautomaton * aut = m_mk_aut(re); aut->compress(); regex_automata.push_back(aut); @@ -9991,7 +10000,11 @@ namespace smt { TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); regex_axiom_add = true; // TODO immediately attempt to learn lower/upper bound info here + } else { + regex_inc_counter(regex_fail_count, str_in_re); } + } else { + regex_inc_counter(regex_fail_count, str_in_re); } } } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 0d56211cd..7398f599b 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -418,6 +418,7 @@ protected: obj_map regex_length_attempt_count; obj_map regex_fail_count; obj_map regex_intersection_fail_count; + obj_map > string_chars; // S --> [S_0, S_1, ...] for character terms S_i svector char_set; From 26ab91a4480f60a0c8ecd7a6d5cac8bc502eecc9 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 17 Jan 2018 13:02:32 -0500 Subject: [PATCH 0468/1283] check duplicate bounds info for regex terms --- src/smt/theory_str.cpp | 32 ++++++++++++++++++++++++++++++-- src/smt/theory_str.h | 5 +++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 474dd9c39..3dccc5681 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9755,7 +9755,32 @@ namespace smt { CTRACE("str", lower_bound_exists, tout << "lower bound of " << mk_pp(str, m) << " is " << lower_bound_value << std::endl;); CTRACE("str", upper_bound_exists, tout << "upper bound of " << mk_pp(str, m) << " is " << upper_bound_value << std::endl;); - if (upper_bound_exists) { + bool new_lower_bound_info = true; + bool new_upper_bound_info = true; + // check last seen lower/upper bound to avoid performing duplicate work + if (regex_last_lower_bound.contains(str)) { + rational last_lb_value; + regex_last_lower_bound.find(str, last_lb_value); + if (last_lb_value == lower_bound_value) { + new_lower_bound_info = false; + } + } + if (regex_last_upper_bound.contains(str)) { + rational last_ub_value; + regex_last_upper_bound.find(str, last_ub_value); + if (last_ub_value == upper_bound_value) { + new_upper_bound_info = false; + } + } + + if (new_lower_bound_info) { + regex_last_lower_bound.insert(str, lower_bound_value); + } + if (new_upper_bound_info) { + regex_last_upper_bound.insert(str, upper_bound_value); + } + + if (upper_bound_exists && new_upper_bound_info) { // check current assumptions if (regex_automaton_assumptions.contains(re) && !regex_automaton_assumptions[re].empty()){ @@ -9869,7 +9894,7 @@ namespace smt { } } else { // !upper_bound_exists // no upper bound information - if (lower_bound_exists && !lower_bound_value.is_zero()) { + if (lower_bound_exists && !lower_bound_value.is_zero() && new_lower_bound_info) { // nonzero lower bound, no upper bound // check current assumptions @@ -9930,10 +9955,13 @@ namespace smt { rhs.push_back(ctx.mk_eq_atom(str_len, m_autil.mk_numeral(lower_bound_value, true))); } else { // If there are solutions at and above the lower bound, add an additional bound. + // DISABLED as this is causing non-termination in the integer solver. --mtrberzi + /* rhs.push_back(m.mk_or( ctx.mk_eq_atom(str_len, m_autil.mk_numeral(lower_bound_value, true)), m_autil.mk_ge(str_len, m_autil.mk_numeral(refined_lower_bound, true)) )); + */ } } else { if (refined_lower_bound.is_minus_one()) { diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 7398f599b..cf3958ceb 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -413,6 +413,11 @@ protected: obj_map regex_term_to_length_constraint; // (str.in.re S R) -> (length constraint over S wrt. R) obj_map > regex_term_to_extra_length_vars; // extra length vars used in regex_term_to_length_constraint entries + // keep track of the last lower/upper bound we saw for each string term + // so we don't perform duplicate work + obj_map regex_last_lower_bound; + obj_map regex_last_upper_bound; + // each counter maps a (str.in.re) expression to an integer. // use helper functions regex_inc_counter() and regex_get_counter() to access obj_map regex_length_attempt_count; From c0ed683882c77143539050149cb1e6ef27cbd735 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 17 Jan 2018 13:32:44 -0500 Subject: [PATCH 0469/1283] disable regex length constraint generation as it currently makes unsound axioms --- src/smt/theory_str.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 3dccc5681..9aec6fab7 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9609,6 +9609,8 @@ namespace smt { continue; } + // DISABLED due to bug -- star-over-union (and possibly others) results in unsound constraints + /* if (!regex_terms_with_length_constraints.contains(str_in_re)) { if (current_assignment == l_true && check_regex_length_linearity(re)) { TRACE("str", tout << "regex length constraints expected to be linear -- generating and asserting them" << std::endl;); @@ -9654,6 +9656,7 @@ namespace smt { regex_axiom_add = true; } } // re not in regex_terms_with_length_constraints + */ rational exact_length_value; if (get_len_value(str, exact_length_value)) { From 7b8101c502e41930ec0e4d0217311eb2a2790c57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Jan 2018 12:25:24 -0800 Subject: [PATCH 0470/1283] fix bugs related to model-converter Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 12 ++ src/cmd_context/basic_cmds.cpp | 12 +- src/cmd_context/cmd_context.cpp | 11 +- src/cmd_context/cmd_context.h | 2 +- src/cmd_context/eval_cmd.cpp | 8 +- src/parsers/smt2/smt2parser.cpp | 10 +- src/sat/ba_solver.cpp | 11 +- src/sat/ba_solver.h | 1 + src/sat/sat_model_converter.cpp | 1 + src/sat/sat_scc.cpp | 2 +- src/sat/sat_simplifier.cpp | 13 +- src/sat/sat_solver.cpp | 13 +- src/sat/sat_solver.h | 2 + src/sat/sat_solver/inc_sat_solver.cpp | 51 +++++--- src/sat/tactic/goal2sat.cpp | 20 ++- src/tactic/generic_model_converter.cpp | 115 ++++++++++++------ src/tactic/generic_model_converter.h | 12 +- .../portfolio/bounded_int2bv_solver.cpp | 5 +- src/tactic/portfolio/enum2bv_solver.cpp | 5 +- src/tactic/portfolio/pb2bv_solver.cpp | 17 ++- 20 files changed, 211 insertions(+), 112 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 0a0fed292..d4aa5ad3e 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -39,6 +39,8 @@ struct pb2bv_rewriter::imp { func_decl_ref_vector m_fresh; // all fresh variables unsigned_vector m_fresh_lim; unsigned m_num_translated; + unsigned m_compile_bv; + unsigned m_compile_card; struct card2bv_rewriter { typedef expr* literal; @@ -526,6 +528,7 @@ struct pb2bv_rewriter::imp { } expr_ref mk_bv(func_decl * f, unsigned sz, expr * const* args) { + ++m_imp.m_compile_bv; decl_kind kind = f->get_decl_kind(); rational k = pb.get_k(f); m_coeffs.reset(); @@ -735,22 +738,27 @@ struct pb2bv_rewriter::imp { else if (pb.is_at_most_k(f) && pb.get_k(f).is_unsigned()) { if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); + ++m_imp.m_compile_card; } else if (pb.is_at_least_k(f) && pb.get_k(f).is_unsigned()) { if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); + ++m_imp.m_compile_card; } else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.eq(full, pb.get_k(f).get_unsigned(), sz, args); + ++m_imp.m_compile_card; } else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.le(full, pb.get_k(f).get_unsigned(), sz, args); + ++m_imp.m_compile_card; } else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && pb.has_unit_coefficients(f)) { if (m_keep_cardinality_constraints && f->get_arity() >= m_min_arity) return false; result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); + ++m_imp.m_compile_card; } else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) { return false; @@ -909,6 +917,8 @@ struct pb2bv_rewriter::imp { m_num_translated(0), m_rw(*this, m) { updt_params(p); + m_compile_bv = 0; + m_compile_card = 0; } void updt_params(params_ref const & p) { @@ -953,6 +963,8 @@ struct pb2bv_rewriter::imp { } void collect_statistics(statistics & st) const { + st.update("pb-compile-bv", m_compile_bv); + st.update("pb-compile-card", m_compile_card); st.update("pb-aux-variables", m_fresh.size()); st.update("pb-aux-clauses", m_rw.m_cfg.m_r.m_sort.m_stats.m_num_compiled_clauses); } diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 65c8860b1..88c5cb257 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -109,15 +109,12 @@ public: virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_UINT; } virtual void set_next_arg(cmd_context & ctx, unsigned index) { m_index = index; } virtual void execute(cmd_context & ctx) { - if (!ctx.is_model_available() || ctx.get_check_sat_result() == 0) - throw cmd_exception("model is not available"); model_ref m; + if (!ctx.is_model_available(m) || ctx.get_check_sat_result() == 0) + throw cmd_exception("model is not available"); if (m_index > 0 && ctx.get_opt()) { ctx.get_opt()->get_box_model(m, m_index); } - else { - ctx.get_check_sat_result()->get_model(m); - } ctx.display_model(m); } virtual void reset(cmd_context& ctx) { @@ -127,10 +124,9 @@ public: ATOMIC_CMD(get_assignment_cmd, "get-assignment", "retrieve assignment", { - if (!ctx.is_model_available() || ctx.get_check_sat_result() == 0) - throw cmd_exception("model is not available"); model_ref m; - ctx.get_check_sat_result()->get_model(m); + if (!ctx.is_model_available(m) || ctx.get_check_sat_result() == 0) + throw cmd_exception("model is not available"); ctx.regular_stream() << "("; dictionary const & macros = ctx.get_macros(); bool first = true; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 8d23c5ef4..93d83d2a4 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1696,11 +1696,11 @@ struct contains_underspecified_op_proc { \brief Complete the model if necessary. */ void cmd_context::complete_model() { - if (!is_model_available() || + model_ref md; + if (!is_model_available(md) || gparams::get_value("model.completion") != "true") return; - model_ref md; get_check_sat_result()->get_model(md); SASSERT(md.get() != 0); params_ref p; @@ -1765,11 +1765,11 @@ void cmd_context::complete_model() { \brief Check if the current model satisfies the quantifier free formulas. */ void cmd_context::validate_model() { + model_ref md; if (!validate_model_enabled()) return; - if (!is_model_available()) + if (!is_model_available(md)) return; - model_ref md; get_check_sat_result()->get_model(md); SASSERT(md.get() != 0); params_ref p; @@ -1897,11 +1897,10 @@ void cmd_context::display_assertions() { regular_stream() << ")" << std::endl; } -bool cmd_context::is_model_available() const { +bool cmd_context::is_model_available(model_ref& md) const { if (produce_models() && has_manager() && (cs_state() == css_sat || cs_state() == css_unknown)) { - model_ref md; get_check_sat_result()->get_model(md); return md.get() != 0; } diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 440c17285..dc85ad2e0 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -445,7 +445,7 @@ public: model_converter* get_model_converter() { return m_mc0.get(); } - bool is_model_available() const; + bool is_model_available(model_ref& md) const; double get_seconds() const { return m_watch.get_seconds(); } diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp index 9d3c1ced3..00aabfff3 100644 --- a/src/cmd_context/eval_cmd.cpp +++ b/src/cmd_context/eval_cmd.cpp @@ -56,16 +56,14 @@ public: } virtual void execute(cmd_context & ctx) { - if (!ctx.is_model_available()) + model_ref md; + if (!ctx.is_model_available(md)) throw cmd_exception("model is not available"); if (!m_target) throw cmd_exception("no arguments passed to eval"); - model_ref md; unsigned index = m_params.get_uint("model_index", 0); - check_sat_result * last_result = ctx.get_check_sat_result(); - SASSERT(last_result); if (index == 0 || !ctx.get_opt()) { - last_result->get_model(md); + // already have model. } else { ctx.get_opt()->get_box_model(md, index); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 4facbc41c..b2fc7d0c7 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -2593,15 +2593,11 @@ namespace smt2 { } check_rparen("invalid get-value command, ')' expected"); - if (!m_ctx.is_model_available() || m_ctx.get_check_sat_result() == 0) - throw cmd_exception("model is not available"); model_ref md; - if (index == 0) { - m_ctx.get_check_sat_result()->get_model(md); - } - else { + if (!m_ctx.is_model_available(md) || m_ctx.get_check_sat_result() == 0) + throw cmd_exception("model is not available"); + if (index != 0) { m_ctx.get_opt()->get_box_model(md, index); - } m_ctx.regular_stream() << "("; expr ** expr_it = expr_stack().c_ptr() + spos; diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 4099693c5..5868c4289 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1139,8 +1139,7 @@ namespace sat { if (m_overflow || offset > (1 << 12)) { IF_VERBOSE(20, verbose_stream() << "offset: " << offset << "\n"; - active2pb(m_A); - display(verbose_stream(), m_A);); + DEBUG_CODE(active2pb(m_A); display(verbose_stream(), m_A););); goto bail_out; } @@ -1148,7 +1147,7 @@ namespace sat { goto process_next_resolvent; } - TRACE("sat_verbose", display(tout, m_A);); + DEBUG_CODE(TRACE("sat_verbose", display(tout, m_A););); TRACE("ba", tout << "process consequent: " << consequent << " : "; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); @@ -1248,9 +1247,8 @@ namespace sat { DEBUG_CODE( active2pb(m_C); VERIFY(validate_resolvent()); - m_A = m_C;); - - TRACE("ba", display(tout << "conflict: ", m_A);); + m_A = m_C; + TRACE("ba", display(tout << "conflict: ", m_A););); cut(); @@ -1528,6 +1526,7 @@ namespace sat { ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_unit_walk(0), m_constraint_id(0), m_ba(*this), m_sort(m_ba) { TRACE("ba", tout << this << "\n";); + m_num_propagations_since_pop = 0; } ba_solver::~ba_solver() { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index cd2e941ce..6e5c00e38 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -198,6 +198,7 @@ namespace sat { literal_vector m_lits; svector m_coeffs; uint64 m_k; + ineq(): m_k(0) {} void reset(uint64 k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } void push(literal l, uint64 c) { m_lits.push_back(l); m_coeffs.push_back(c); } }; diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index cc6614621..ce059a07b 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -325,6 +325,7 @@ namespace sat { } void model_converter::flush(model_converter & src) { + VERIFY(this != &src); m_entries.append(src.m_entries); src.m_entries.reset(); } diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 960174e79..4bd16c5c5 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -275,7 +275,7 @@ namespace sat { } void scc::collect_statistics(statistics & st) const { - st.update("elim bool vars", m_num_elim); + st.update("elim bool vars scc", m_num_elim); st.update("elim binary", m_num_elim_bin); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index c101e3a29..b983a0da3 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -260,7 +260,6 @@ namespace sat { break; } while (!m_sub_todo.empty()); - bool vars_eliminated = m_num_elim_vars > m_old_num_elim_vars; if (m_need_cleanup || vars_eliminated) { @@ -981,17 +980,21 @@ namespace sat { void operator()() { integrity_checker si(s.s); si.check_watches(); - if (s.bce_enabled()) + if (s.bce_enabled()) { block_clauses(); + } si.check_watches(); - if (s.abce_enabled()) + if (s.abce_enabled()) { cce(); + } si.check_watches(); - if (s.cce_enabled()) + if (s.cce_enabled()) { cce(); + } si.check_watches(); - if (s.bca_enabled()) + if (s.bca_enabled()) { bca(); + } si.check_watches(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index de75882af..61e05b3ed 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1566,6 +1566,17 @@ namespace sat { #endif } + unsigned solver::get_hash() const { + unsigned result = 0; + for (clause* cp : m_clauses) { + result = combine_hash(cp->size(), combine_hash(result, cp->id())); + } + for (clause* cp : m_learned) { + result = combine_hash(cp->size(), combine_hash(result, cp->id())); + } + return result; + } + bool solver::set_root(literal l, literal r) { return !m_ext || m_ext->set_root(l, r); } @@ -4032,7 +4043,7 @@ namespace sat { st.update("dyn subsumption resolution", m_dyn_sub_res); st.update("blocked correction sets", m_blocked_corr_sets); st.update("units", m_units); - st.update("elim bool vars", m_elim_var_res); + st.update("elim bool vars res", m_elim_var_res); st.update("elim bool vars bdd", m_elim_var_bdd); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 651eedee8..e37fa3cca 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -538,6 +538,8 @@ namespace sat { private: + unsigned get_hash() const; + typedef hashtable index_set; u_map m_antecedents; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index ef85ad921..e0cc8e581 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -18,30 +18,31 @@ Notes: --*/ +#include "ast/ast_pp.h" +#include "ast/ast_translation.h" +#include "ast/ast_util.h" #include "solver/solver.h" -#include "tactic/tactical.h" -#include "sat/sat_solver.h" #include "solver/tactic2solver.h" +#include "tactic/tactical.h" #include "tactic/aig/aig_tactic.h" #include "tactic/core/propagate_values_tactic.h" #include "tactic/bv/max_bv_sharing_tactic.h" #include "tactic/arith/card2bv_tactic.h" #include "tactic/bv/bit_blaster_tactic.h" #include "tactic/core/simplify_tactic.h" -#include "sat/tactic/goal2sat.h" -#include "ast/ast_pp.h" #include "model/model_smt2_pp.h" +#include "model/model_v2_pp.h" #include "tactic/bv/bit_blaster_model_converter.h" -#include "ast/ast_translation.h" -#include "ast/ast_util.h" #include "tactic/core/propagate_values_tactic.h" +#include "sat/sat_solver.h" #include "sat/sat_params.hpp" +#include "sat/tactic/goal2sat.h" #include "sat/sat_simplifier_params.hpp" // incremental SAT solver. class inc_sat_solver : public solver { ast_manager& m; - sat::solver m_solver; + mutable sat::solver m_solver; goal2sat m_goal2sat; params_ref m_params; expr_ref_vector m_fmls; @@ -62,7 +63,7 @@ class inc_sat_solver : public solver { model_converter_ref m_mc; mutable model_converter_ref m_mc0; mutable obj_hashtable m_inserted_const2bits; - ref m_sat_mc; + mutable ref m_sat_mc; mutable model_converter_ref m_cached_mc; svector m_weights; std::string m_unknown; @@ -382,7 +383,7 @@ public: return r; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { sat::literal_vector ls; u_map lit2var; for (unsigned i = 0; i < vars.size(); ++i) { @@ -410,15 +411,19 @@ public: void init_reason_unknown() { m_unknown = "no reason given"; } - virtual std::string reason_unknown() const { + + std::string reason_unknown() const override { return m_unknown; } - virtual void set_reason_unknown(char const* msg) { + + void set_reason_unknown(char const* msg) override { m_unknown = msg; } - virtual void get_labels(svector & r) { + + void get_labels(svector & r) override { } - virtual unsigned get_num_assertions() const { + + unsigned get_num_assertions() const override { const_cast(this)->convert_internalized(); if (is_internalized() && m_internalized_converted) { return m_internalized_fmls.size(); @@ -427,28 +432,33 @@ public: return m_fmls.size(); } } - virtual expr * get_assertion(unsigned idx) const { + + expr * get_assertion(unsigned idx) const override { if (is_internalized() && m_internalized_converted) { return m_internalized_fmls[idx]; } return m_fmls[idx]; } - virtual unsigned get_num_assumptions() const { + + unsigned get_num_assumptions() const override { return m_asmsf.size(); } - virtual expr * get_assumption(unsigned idx) const { + + expr * get_assumption(unsigned idx) const override { return m_asmsf[idx]; } - virtual model_converter_ref get_model_converter() const { + model_converter_ref get_model_converter() const override { const_cast(this)->convert_internalized(); if (m_cached_mc) return m_cached_mc; if (is_internalized() && m_internalized_converted) { insert_const2bits(); + m_sat_mc->flush_smc(m_solver, m_map); m_cached_mc = m_mc0.get(); m_cached_mc = concat(solver::get_model_converter().get(), m_cached_mc.get()); m_cached_mc = concat(m_cached_mc.get(), m_sat_mc.get()); + // IF_VERBOSE(0, m_cached_mc->display(verbose_stream() << "get-model-converter\n");); return m_cached_mc; } else { @@ -804,16 +814,22 @@ private: } } m_model = md; + //IF_VERBOSE(0, model_v2_pp(verbose_stream(), *m_model, true);); if (m_sat_mc) { + // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n");); (*m_sat_mc)(m_model); } insert_const2bits(); if (m_mc0) { + // IF_VERBOSE(0, m_mc0->display(verbose_stream() << "mc0\n");); (*m_mc0)(m_model); } TRACE("sat", model_smt2_pp(tout, m, *m_model, 0);); + // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "after\n");); + +#if 0 IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); for (expr * f : m_fmls) { expr_ref tmp(m); @@ -828,6 +844,7 @@ private: VERIFY(m.is_true(tmp)); } } +#endif } }; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 596712a7b..68d15c48f 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -892,14 +892,15 @@ void sat2goal::mc::flush_smc(sat::solver& s, atom2bool_var const& map) { void sat2goal::mc::flush_gmc() { sat::literal_vector updates; - m_smc.expand(updates); + m_smc.expand(updates); m_smc.reset(); if (!m_gmc) m_gmc = alloc(generic_model_converter, m); // now gmc owns the model converter sat::literal_vector clause; expr_ref_vector tail(m); expr_ref def(m); - for (sat::literal l : updates) { + for (unsigned i = 0; i < updates.size(); ++i) { + sat::literal l = updates[i]; if (l == sat::null_literal) { sat::literal lit0 = clause[0]; for (unsigned i = 1; i < clause.size(); ++i) { @@ -914,6 +915,21 @@ void sat2goal::mc::flush_gmc() { clause.reset(); tail.reset(); } + // short circuit for equivalences: + else if (clause.empty() && tail.empty() && + i + 5 < updates.size() && + updates[i] == ~updates[i + 3] && + updates[i + 1] == ~updates[i + 4] && + updates[i + 2] == sat::null_literal && + updates[i + 5] == sat::null_literal) { + sat::literal r = ~updates[i+1]; + if (l.sign()) { + l.neg(); + r.neg(); + } + m_gmc->add(lit2expr(l), lit2expr(r)); + i += 5; + } else { clause.push_back(l); } diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 47a4b4d48..aa1f1cdc4 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -31,8 +31,8 @@ Notes: void generic_model_converter::add(func_decl * d, expr* e) { struct entry et(d, e, m, ADD); VERIFY(d->get_range() == m.get_sort(e)); - m_first_idx.insert_if_not_there(et.m_f, m_add_entries.size()); - m_add_entries.push_back(et); + m_first_idx.insert_if_not_there(et.m_f, m_entries.size()); + m_entries.push_back(et); } void generic_model_converter::operator()(model_ref & md) { @@ -42,54 +42,86 @@ void generic_model_converter::operator()(model_ref & md) { ev.set_expand_array_equalities(false); expr_ref val(m); unsigned arity; - for (unsigned i = m_hide_entries.size(); i-- > 0; ) { - entry const& e = m_hide_entries[i]; - md->unregister_decl(e.m_f); - } - for (unsigned i = m_add_entries.size(); i-- > 0; ) { - entry const& e = m_add_entries[i]; - ev(e.m_def, val); - TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";); - arity = e.m_f->get_arity(); - if (arity == 0) { - md->register_decl(e.m_f, val); - } - else { - func_interp * new_fi = alloc(func_interp, m, arity); - new_fi->set_else(val); - md->register_decl(e.m_f, new_fi); + for (unsigned i = m_entries.size(); i-- > 0; ) { + entry const& e = m_entries[i]; + switch (e.m_instruction) { + case instruction::HIDE: + md->unregister_decl(e.m_f); + break; + case instruction::ADD: + ev(e.m_def, val); +#if 0 + if (e.m_f->get_name() == symbol("XX")) { + IF_VERBOSE(0, verbose_stream() << e.m_f->get_name() << " " << e.m_def << " -> " << val << "\n";); + ptr_vector ts; + ts.push_back(e.m_def); + while (!ts.empty()) { + app* t = to_app(ts.back()); + ts.pop_back(); + if (t->get_num_args() > 0) { + ts.append(t->get_num_args(), t->get_args()); + } + expr_ref tmp(m); + ev(t, tmp); + IF_VERBOSE(0, verbose_stream() << mk_pp(t, m) << " -> " << tmp << "\n";); + } + } +#endif + TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";); + arity = e.m_f->get_arity(); + if (arity == 0) { + expr* old_val = md->get_const_interp(e.m_f); + if (old_val && old_val == val) { + // skip + } + else { + if (old_val) ev.reset(); + md->register_decl(e.m_f, val); + } + } + else { + func_interp * old_val = md->get_func_interp(e.m_f); + if (old_val && old_val->get_else() == val) { + // skip + } + else { + if (old_val) ev.reset(); + func_interp * new_fi = alloc(func_interp, m, arity); + new_fi->set_else(val); + md->register_decl(e.m_f, new_fi); + } + } + break; } } TRACE("model_converter", tout << "after generic_model_converter\n"; model_v2_pp(tout, *md);); } void generic_model_converter::display(std::ostream & out) { - for (entry const& e : m_hide_entries) { - display_del(out, e.m_f); - } - for (entry const& e : m_add_entries) { - display_add(out, m, e.m_f, e.m_def); + for (entry const& e : m_entries) { + switch (e.m_instruction) { + case instruction::HIDE: + display_del(out, e.m_f); + break; + case instruction::ADD: + display_add(out, m, e.m_f, e.m_def); + break; + } } } model_converter * generic_model_converter::translate(ast_translation & translator) { ast_manager& to = translator.to(); generic_model_converter * res = alloc(generic_model_converter, to); - for (entry const& e : m_hide_entries) { - res->m_hide_entries.push_back(entry(translator(e.m_f.get()), translator(e.m_def.get()), to, e.m_instruction)); - } - for (entry const& e : m_add_entries) { - res->m_add_entries.push_back(entry(translator(e.m_f.get()), translator(e.m_def.get()), to, e.m_instruction)); + for (entry const& e : m_entries) { + res->m_entries.push_back(entry(translator(e.m_f.get()), translator(e.m_def.get()), to, e.m_instruction)); } return res; } void generic_model_converter::collect(ast_pp_util& visitor) { m_env = &visitor.env(); - for (entry const& e : m_hide_entries) { - visitor.coll.visit_func(e.m_f); - } - for (entry const& e : m_add_entries) { + for (entry const& e : m_entries) { visitor.coll.visit_func(e.m_f); if (e.m_def) visitor.coll.visit(e.m_def); } @@ -116,8 +148,11 @@ void generic_model_converter::operator()(expr_ref& fml) { if (min_idx == UINT_MAX) return; expr_ref_vector fmls(m); fmls.push_back(fml); - for (unsigned i = m_add_entries.size(); i-- > min_idx;) { - entry const& e = m_add_entries[i]; + for (unsigned i = m_entries.size(); i-- > min_idx;) { + entry const& e = m_entries[i]; + if (e.m_instruction != instruction::ADD) { + continue; + } unsigned arity = e.m_f->get_arity(); if (arity == 0) { fmls.push_back(simplify_def(e)); @@ -139,8 +174,18 @@ void generic_model_converter::operator()(expr_ref& fml) { if (m_first_idx[e.m_f] == i) { m_first_idx.remove(e.m_f); } - m_add_entries.pop_back(); } + unsigned j = min_idx; + for (unsigned i = min_idx; i < m_entries.size(); ++i) { + entry const& e = m_entries[i]; + if (e.m_instruction == instruction::HIDE) { + if (i != j) { + m_entries[j] = e; + } + ++j; + } + } + m_entries.shrink(j); fml = mk_and(fmls); } diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index 34e9d8166..8d40d55b7 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -30,10 +30,16 @@ class generic_model_converter : public model_converter { instruction m_instruction; entry(func_decl* f, expr* d, ast_manager& m, instruction i): m_f(f, m), m_def(d, m), m_instruction(i) {} + + entry& operator=(entry const& other) { + m_f = other.m_f; + m_def = other.m_def; + m_instruction = other.m_instruction; + return *this; + } }; ast_manager& m; - vector m_add_entries; - vector m_hide_entries; + vector m_entries; obj_map m_first_idx; expr_ref simplify_def(entry const& e); @@ -45,7 +51,7 @@ public: void hide(expr* e) { SASSERT(is_app(e) && to_app(e)->get_num_args() == 0); hide(to_app(e)->get_decl()); } - void hide(func_decl * f) { m_hide_entries.push_back(entry(f, 0, m, HIDE)); } + void hide(func_decl * f) { m_entries.push_back(entry(f, 0, m, HIDE)); } void add(func_decl * d, expr* e); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index c81d413b8..3e1b5d2f4 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -81,10 +81,9 @@ public: for (func_decl* f : m_bv_fns) result->m_bv_fns.push_back(tr(f)); for (func_decl* f : m_int_fns) result->m_int_fns.push_back(tr(f)); for (bound_manager* b : m_bounds) result->m_bounds.push_back(b->translate(dst_m)); - model_converter_ref mc = concat(mc0(), m_solver->get_model_converter().get()); - if (mc) { + if (mc0()) { ast_translation tr(m, dst_m); - result->set_model_converter(mc->translate(tr)); + result->set_model_converter(mc0()->translate(tr)); } return result; } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index bfe057f82..5db907c2c 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -50,10 +50,9 @@ public: virtual solver* translate(ast_manager& dst_m, params_ref const& p) { solver* result = alloc(enum2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); - model_converter_ref mc = concat(mc0(), m_solver->get_model_converter().get()); - if (mc) { + if (mc0()) { ast_translation tr(m, dst_m); - result->set_model_converter(mc->translate(tr)); + result->set_model_converter(mc0()->translate(tr)); } return result; } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index eba10cbd1..cee566ec6 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -16,14 +16,14 @@ Notes: --*/ -#include "tactic/portfolio/pb2bv_solver.h" -#include "solver/solver_na2as.h" -#include "tactic/tactic.h" -#include "ast/rewriter/pb2bv_rewriter.h" -#include "ast/rewriter/th_rewriter.h" -#include "tactic/generic_model_converter.h" #include "ast/ast_pp.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" class pb2bv_solver : public solver_na2as { ast_manager& m; @@ -50,10 +50,9 @@ public: virtual solver* translate(ast_manager& dst_m, params_ref const& p) { flush_assertions(); solver* result = alloc(pb2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); - model_converter_ref mc = mc0(); - if (mc) { + if (mc0()) { ast_translation tr(m, dst_m); - result->set_model_converter(mc->translate(tr)); + result->set_model_converter(mc0()->translate(tr)); } return result; } From c2b268c64555199e9134948474899e87eb7b9707 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 17 Jan 2018 18:26:31 -0500 Subject: [PATCH 0471/1283] short path for length-0 regex terms --- src/smt/theory_str.cpp | 324 ++++++++++++++++++++++++++--------------- src/smt/theory_str.h | 1 + 2 files changed, 206 insertions(+), 119 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 9aec6fab7..e25dc84f3 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6646,6 +6646,9 @@ namespace smt { * In some cases, the returned formula requires one or more free integer variables to be created. * These variables are returned in the reference parameter `freeVariables`. * Extra assertions should be made for these free variables constraining them to be non-negative. + * + * TODO: star unrolling? + * TODO: generate stars "correctly" as a linear combination of all possible subterm lengths */ expr_ref theory_str::infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables) { ENSURE(u.is_re(re)); @@ -6725,6 +6728,59 @@ namespace smt { } } + /* + * Assert initial lower and upper bounds for the positive constraint (str in re) corresponding + * to the automaton `aut`. + * This asserts a constraint of the form: + * str_in_re --> (len(str) ?= 0 OR len(str) >= lb) AND len(str) <= ub + * where the upper bound clause is omitted if the upper bound doesn't exist + * and the equality with 0 is based on whether solutions of length 0 are allowed. + */ + void theory_str::find_automaton_initial_bounds(expr * str_in_re, eautomaton * aut) { + ENSURE(aut != NULL); + context & ctx = get_context(); + ast_manager & m = get_manager(); + + expr_ref_vector rhs(m); + expr * str; + expr * re; + u.str.is_in_re(str_in_re, str, re); + expr_ref strlen(mk_strlen(str), m); + + // lower bound first + rational nonzero_lower_bound; + bool zero_sol_exists = refine_automaton_lower_bound(aut, rational::zero(), nonzero_lower_bound); + if (zero_sol_exists) { + regex_last_lower_bound.insert(str, rational::zero()); + // solution at 0 + if (!nonzero_lower_bound.is_minus_one()) { + expr_ref rhs1(ctx.mk_eq_atom(strlen, m_autil.mk_numeral(rational::zero(), true)), m); + expr_ref rhs2(m_autil.mk_ge(strlen, m_autil.mk_numeral(nonzero_lower_bound, true)), m); + rhs.push_back(m.mk_or(rhs1, rhs2)); + } else { + // shouldn't happen + UNREACHABLE(); + } + } else { + // no solution at 0 + if (!nonzero_lower_bound.is_minus_one()) { + regex_last_lower_bound.insert(str, nonzero_lower_bound); + expr_ref rhs2(m_autil.mk_ge(strlen, m_autil.mk_numeral(nonzero_lower_bound, true)), m); + rhs.push_back(rhs2); + } else { + // shouldn't happen + UNREACHABLE(); + } + } + // TODO upper bound check + + if (!rhs.empty()) { + expr_ref lhs(str_in_re, m); + expr_ref _rhs(mk_and(rhs), m); + assert_implication(lhs, _rhs); + } + } + /* * Refine the lower bound on the length of a solution to a given automaton. * The method returns TRUE if a solution of length `current_lower_bound` exists, @@ -9596,7 +9652,6 @@ namespace smt { // regex automata if (m_params.m_RegexAutomata) { // TODO since heuristics might fail, the "no progress" flag might need to be handled specially here - // TODO learning of linear length constraints in the style of length automata, if possible? bool regex_axiom_add = false; for (obj_hashtable::iterator it = regex_terms.begin(); it != regex_terms.end(); ++it) { expr * str_in_re = *it; @@ -9667,89 +9722,96 @@ namespace smt { continue; } - // find a consistent automaton for this term - bool found = false; - regex_automaton_under_assumptions assumption; - if (regex_automaton_assumptions.contains(re) && - !regex_automaton_assumptions[re].empty()){ - for (svector::iterator it = regex_automaton_assumptions[re].begin(); - it != regex_automaton_assumptions[re].end(); ++it) { - regex_automaton_under_assumptions autA = *it; - rational assumed_upper_bound, assumed_lower_bound; - bool assumes_upper_bound = autA.get_upper_bound(assumed_upper_bound); - bool assumes_lower_bound = autA.get_lower_bound(assumed_lower_bound); - if (!assumes_upper_bound && !assumes_lower_bound) { - // automaton with no assumptions is always usable - assumption = autA; - found = true; - break; - } - // check consistency of bounds assumptions - } // foreach(a in regex_automaton_assumptions) - } - if (found) { - expr_ref pathConstraint(m); - expr_ref characterConstraints(m); - pathConstraint = generate_regex_path_constraints(str, assumption.get_automaton(), exact_length_value, characterConstraints); - TRACE("str", tout << "generated regex path constraint " << mk_pp(pathConstraint, m) << std::endl;); - TRACE("str", tout << "character constraints are " << mk_pp(characterConstraints, m) << std::endl;); - - expr_ref_vector lhs_terms(m); - if (current_assignment == l_true) { - lhs_terms.push_back(str_in_re); - } else { - lhs_terms.push_back(m.mk_not(str_in_re)); - } - lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true))); - expr_ref lhs(mk_and(lhs_terms), m); - // If the automaton was built with the same polarity as the constraint, - // assert directly. Otherwise, negate the path constraint - if ( (current_assignment == l_true && assumption.get_polarity()) - || (current_assignment == l_false && !assumption.get_polarity())) { - TRACE("str", tout << "automaton and regex term have same polarity" << std::endl;); - expr_ref rhs(m.mk_and(pathConstraint, characterConstraints), m); - assert_implication(lhs, rhs); - } else { - TRACE("str", tout << "automaton and regex term have opposite polarity" << std::endl;); - expr_ref rhs(m.mk_and(m.mk_not(pathConstraint), characterConstraints), m); - assert_implication(lhs, rhs); - } - regex_terms_with_path_constraints.insert(str_in_re); - m_trail_stack.push(insert_obj_trail(regex_terms_with_path_constraints, str_in_re)); - regex_axiom_add = true; - - // increment LengthAttemptCount - regex_inc_counter(regex_length_attempt_count, re); - - { - unsigned v = regex_get_counter(regex_length_attempt_count, re); - TRACE("str", tout << "length attempt count for " << mk_pp(re, m) << " is " << v << std::endl;); - } - - continue; + if (exact_length_value.is_zero()) { + // shortcut + expr_ref lhs(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(rational::zero(), true)), m); + expr_ref rhs(ctx.mk_eq_atom(str, mk_string("")), m); + assert_implication(lhs, rhs); } else { - // no automata available, or else all bounds assumptions are invalid - unsigned expected_complexity = estimate_regex_complexity(re); - if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold || regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold) { - CTRACE("str", regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold, - tout << "failed automaton threshold reached for " << mk_pp(str_in_re, m) << " -- automatically constructing full automaton" << std::endl;); - eautomaton * aut = m_mk_aut(re); - aut->compress(); - regex_automata.push_back(aut); - regex_automaton_under_assumptions new_aut(re, aut, true); - if (!regex_automaton_assumptions.contains(re)) { - regex_automaton_assumptions.insert(re, svector()); - } - regex_automaton_assumptions[re].push_back(new_aut); - TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); - regex_axiom_add = true; - // TODO immediately attempt to learn lower/upper bound info here - } else { - regex_inc_counter(regex_fail_count, str_in_re); + // find a consistent automaton for this term + bool found = false; + regex_automaton_under_assumptions assumption; + if (regex_automaton_assumptions.contains(re) && + !regex_automaton_assumptions[re].empty()){ + for (svector::iterator it = regex_automaton_assumptions[re].begin(); + it != regex_automaton_assumptions[re].end(); ++it) { + regex_automaton_under_assumptions autA = *it; + rational assumed_upper_bound, assumed_lower_bound; + bool assumes_upper_bound = autA.get_upper_bound(assumed_upper_bound); + bool assumes_lower_bound = autA.get_lower_bound(assumed_lower_bound); + if (!assumes_upper_bound && !assumes_lower_bound) { + // automaton with no assumptions is always usable + assumption = autA; + found = true; + break; + } + // check consistency of bounds assumptions + } // foreach(a in regex_automaton_assumptions) } - continue; - } - } + if (found) { + expr_ref pathConstraint(m); + expr_ref characterConstraints(m); + pathConstraint = generate_regex_path_constraints(str, assumption.get_automaton(), exact_length_value, characterConstraints); + TRACE("str", tout << "generated regex path constraint " << mk_pp(pathConstraint, m) << std::endl;); + TRACE("str", tout << "character constraints are " << mk_pp(characterConstraints, m) << std::endl;); + + expr_ref_vector lhs_terms(m); + if (current_assignment == l_true) { + lhs_terms.push_back(str_in_re); + } else { + lhs_terms.push_back(m.mk_not(str_in_re)); + } + lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true))); + expr_ref lhs(mk_and(lhs_terms), m); + // If the automaton was built with the same polarity as the constraint, + // assert directly. Otherwise, negate the path constraint + if ( (current_assignment == l_true && assumption.get_polarity()) + || (current_assignment == l_false && !assumption.get_polarity())) { + TRACE("str", tout << "automaton and regex term have same polarity" << std::endl;); + expr_ref rhs(m.mk_and(pathConstraint, characterConstraints), m); + assert_implication(lhs, rhs); + } else { + TRACE("str", tout << "automaton and regex term have opposite polarity" << std::endl;); + expr_ref rhs(m.mk_and(m.mk_not(pathConstraint), characterConstraints), m); + assert_implication(lhs, rhs); + } + regex_terms_with_path_constraints.insert(str_in_re); + m_trail_stack.push(insert_obj_trail(regex_terms_with_path_constraints, str_in_re)); + regex_axiom_add = true; + + // increment LengthAttemptCount + regex_inc_counter(regex_length_attempt_count, re); + + { + unsigned v = regex_get_counter(regex_length_attempt_count, re); + TRACE("str", tout << "length attempt count for " << mk_pp(re, m) << " is " << v << std::endl;); + } + + continue; + } else { + // no automata available, or else all bounds assumptions are invalid + unsigned expected_complexity = estimate_regex_complexity(re); + if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold || regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold) { + CTRACE("str", regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold, + tout << "failed automaton threshold reached for " << mk_pp(str_in_re, m) << " -- automatically constructing full automaton" << std::endl;); + eautomaton * aut = m_mk_aut(re); + aut->compress(); + regex_automata.push_back(aut); + regex_automaton_under_assumptions new_aut(re, aut, true); + if (!regex_automaton_assumptions.contains(re)) { + regex_automaton_assumptions.insert(re, svector()); + } + regex_automaton_assumptions[re].push_back(new_aut); + TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); + regex_axiom_add = true; + find_automaton_initial_bounds(str_in_re, aut); + } else { + regex_inc_counter(regex_fail_count, str_in_re); + } + continue; + } + } // !length is zero + } // get_len_value() expr_ref str_len(mk_strlen(str), m); rational lower_bound_value; rational upper_bound_value; @@ -9858,10 +9920,12 @@ namespace smt { } } - expr_ref lhs_terms(mk_and(lhs), m); - expr_ref rhs_terms(mk_and(rhs), m); - assert_implication(lhs_terms, rhs_terms); - regex_axiom_add = true; + if (!rhs.empty()) { + expr_ref lhs_terms(mk_and(lhs), m); + expr_ref rhs_terms(mk_and(rhs), m); + assert_implication(lhs_terms, rhs_terms); + regex_axiom_add = true; + } } } else { // no existing automata/assumptions. @@ -9878,7 +9942,7 @@ namespace smt { regex_automaton_assumptions[re].push_back(new_aut); TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); regex_axiom_add = true; - // TODO immediately attempt to learn lower/upper bound info here + find_automaton_initial_bounds(str_in_re, aut); } else { // TODO check negation? // TODO construct a partial automaton for R to the given upper bound? @@ -9976,10 +10040,12 @@ namespace smt { } } - expr_ref lhs_terms(mk_and(lhs), m); - expr_ref rhs_terms(mk_and(rhs), m); - assert_implication(lhs_terms, rhs_terms); - regex_axiom_add = true; + if (!rhs.empty()) { + expr_ref lhs_terms(mk_and(lhs), m); + expr_ref rhs_terms(mk_and(rhs), m); + assert_implication(lhs_terms, rhs_terms); + regex_axiom_add = true; + } } } else { // no existing automata/assumptions. @@ -9996,7 +10062,7 @@ namespace smt { regex_automaton_assumptions[re].push_back(new_aut); TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); regex_axiom_add = true; - // TODO immediately attempt to learn lower/upper bound info here + find_automaton_initial_bounds(str_in_re, aut); } else { // TODO check negation? // TODO construct a partial automaton for R to the given lower bound? @@ -10016,7 +10082,7 @@ namespace smt { // and doing so without bounds is not difficult bool existingAutomata = (regex_automaton_assumptions.contains(re) && !regex_automaton_assumptions[re].empty()); bool failureThresholdExceeded = (regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold); - if (!existingAutomata || failureThresholdExceeded) { + if (!existingAutomata) { unsigned expected_complexity = estimate_regex_complexity(re); if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold || failureThresholdExceeded) { @@ -10030,7 +10096,7 @@ namespace smt { regex_automaton_assumptions[re].push_back(new_aut); TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); regex_axiom_add = true; - // TODO immediately attempt to learn lower/upper bound info here + find_automaton_initial_bounds(str_in_re, aut); } else { regex_inc_counter(regex_fail_count, str_in_re); } @@ -10165,42 +10231,62 @@ namespace smt { } } } // foreach(entry in intersect_constraints) + aut_inter->compress(); TRACE("str", tout << "intersected " << used_intersect_constraints.size() << " constraints" << std::endl;); - if (aut_inter != NULL && aut_inter->is_empty()) { - TRACE("str", tout << "product automaton is empty; asserting conflict clause" << std::endl;); - expr_ref_vector conflict_terms(m); - for (svector::iterator aut_it = used_intersect_constraints.begin(); - aut_it != used_intersect_constraints.end(); ++aut_it) { - regex_automaton_under_assumptions aut = *aut_it; - expr * str_in_re_term(u.re.mk_in_re(str, aut.get_regex_term())); - lbool current_assignment = ctx.get_assignment(str_in_re_term); - if (current_assignment == l_true) { - conflict_terms.push_back(str_in_re_term); - } else if (current_assignment == l_false) { - conflict_terms.push_back(m.mk_not(str_in_re_term)); - } - // add length assumptions, if any - rational ub; - if (aut.get_upper_bound(ub)) { - expr_ref ub_term(m_autil.mk_le(mk_strlen(str), m_autil.mk_numeral(ub, true)), m); - conflict_terms.push_back(ub_term); - } - rational lb; - if (aut.get_lower_bound(lb)) { - expr_ref lb_term(m_autil.mk_ge(mk_strlen(str), m_autil.mk_numeral(lb, true)), m); - conflict_terms.push_back(lb_term); + expr_ref_vector conflict_terms(m); + expr_ref conflict_lhs(m); + for (svector::iterator aut_it = used_intersect_constraints.begin(); + aut_it != used_intersect_constraints.end(); ++aut_it) { + regex_automaton_under_assumptions aut = *aut_it; + expr * str_in_re_term(u.re.mk_in_re(str, aut.get_regex_term())); + lbool current_assignment = ctx.get_assignment(str_in_re_term); + if (current_assignment == l_true) { + conflict_terms.push_back(str_in_re_term); + } else if (current_assignment == l_false) { + conflict_terms.push_back(m.mk_not(str_in_re_term)); + } + // add length assumptions, if any + rational ub; + if (aut.get_upper_bound(ub)) { + expr_ref ub_term(m_autil.mk_le(mk_strlen(str), m_autil.mk_numeral(ub, true)), m); + conflict_terms.push_back(ub_term); + } + rational lb; + if (aut.get_lower_bound(lb)) { + expr_ref lb_term(m_autil.mk_ge(mk_strlen(str), m_autil.mk_numeral(lb, true)), m); + conflict_terms.push_back(lb_term); + } + } + conflict_lhs = mk_and(conflict_terms); + + if (used_intersect_constraints.size() > 1 && aut_inter != NULL) { + // check whether the intersection is only the empty string + unsigned initial_state = aut_inter->init(); + if (aut_inter->final_states().size() == 1 && aut_inter->is_final_state(initial_state)) { + // initial state is final and it is the only final state + // if there are no moves from the initial state, + // the only solution is the empty string + if (aut_inter->get_moves_from(initial_state).empty()) { + TRACE("str", tout << "product automaton only accepts empty string" << std::endl;); + expr_ref rhs1(ctx.mk_eq_atom(str, mk_string("")), m); + expr_ref rhs2(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(rational::zero(), true)), m); + expr_ref rhs(m.mk_and(rhs1, rhs2), m); + assert_implication(conflict_lhs, rhs); + regex_axiom_add = true; } } + } + if (aut_inter != NULL && aut_inter->is_empty()) { + TRACE("str", tout << "product automaton is empty; asserting conflict clause" << std::endl;); expr_ref conflict_clause(m.mk_not(mk_and(conflict_terms)), m); assert_axiom(conflict_clause); regex_axiom_add = true; } } // foreach (entry in regex_terms_by_string) - if (regex_axiom_add) { - return FC_CONTINUE; + //return FC_CONTINUE; } } // RegexAutomata diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index cf3958ceb..4e790e838 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -556,6 +556,7 @@ protected: bool check_regex_length_linearity(expr * re); bool check_regex_length_linearity_helper(expr * re, bool already_star); expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); + void find_automaton_initial_bounds(expr * str_in_re, eautomaton * aut); bool refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound); bool refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound); expr_ref generate_regex_path_constraints(expr * stringTerm, eautomaton * aut, rational lenVal, expr_ref & characterConstraints); From dbb15f65b5d6deba9cefbd4f9298a3e8fe4c6fe5 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 17 Jan 2018 19:26:42 -0500 Subject: [PATCH 0472/1283] correct generation of linear length constraints for regex star terms --- src/smt/theory_str.cpp | 97 ++++++++++++++++++++++++++++++++++++++++-- src/smt/theory_str.h | 3 ++ 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index e25dc84f3..c4e6a9471 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6638,6 +6638,68 @@ namespace smt { } } + // note: returns an empty set `lens` if something went wrong + void theory_str::check_subterm_lengths(expr * re, integer_set & lens) { + expr * sub1; + expr * sub2; + if (u.re.is_to_re(re, sub1)) { + SASSERT(u.str.is_string(sub1)); + zstring(str); + u.str.is_string(sub1, str); + lens.insert(str.length()); + } else if (u.re.is_concat(re, sub1, sub2)) { + integer_set lens_1, lens_2; + check_subterm_lengths(sub1, lens_1); + check_subterm_lengths(sub2, lens_2); + if (lens_1.empty() || lens_2.empty()) { + lens.reset(); + } else { + // take all pairwise lengths + for (integer_set::iterator it1 = lens_1.begin(); it1 != lens_1.end(); ++it1) { + for(integer_set::iterator it2 = lens_2.begin(); it2 != lens_2.end(); ++it2) { + int l1 = *it1; + int l2 = *it2; + lens.insert(l1 + l2); + } + } + } + } else if (u.re.is_union(re, sub1, sub2)) { + integer_set lens_1, lens_2; + check_subterm_lengths(sub1, lens_1); + check_subterm_lengths(sub2, lens_2); + if (lens_1.empty() || lens_2.empty()) { + lens.reset(); + } else { + // take all possibilities from either side + for (integer_set::iterator it1 = lens_1.begin(); it1 != lens_1.end(); ++it1) { + lens.insert(*it1); + } + for (integer_set::iterator it2 = lens_2.begin(); it2 != lens_2.end(); ++it2) { + lens.insert(*it2); + } + } + } else if (u.re.is_star(re, sub1) || u.re.is_plus(re, sub1)) { + // this is bad -- term generation requires this not to appear + lens.reset(); + } else if (u.re.is_range(re, sub1, sub2)) { + SASSERT(u.str.is_string(sub1)); + SASSERT(u.str.is_string(sub2)); + zstring str1, str2; + u.str.is_string(sub1, str1); + u.str.is_string(sub2, str2); + SASSERT(str1.length() == 1); + SASSERT(str2.length() == 1); + lens.insert(1); + } else if (u.re.is_full(re)) { + lens.insert(1); + } else if (u.re.is_complement(re)) { + lens.reset(); + } else { + TRACE("str", tout << "WARNING: unknown regex term " << mk_pp(re, get_manager()) << std::endl;); + lens.reset(); + } + } + /* * Infer all length constraints implied by the given regular expression `re` * in order to constrain `lenVar` (which must be of sort Int). @@ -6648,7 +6710,6 @@ namespace smt { * Extra assertions should be made for these free variables constraining them to be non-negative. * * TODO: star unrolling? - * TODO: generate stars "correctly" as a linear combination of all possible subterm lengths */ expr_ref theory_str::infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables) { ENSURE(u.is_re(re)); @@ -6682,6 +6743,9 @@ namespace smt { expr_ref retval(mk_and(finalResult), m); return retval; } else if (u.re.is_star(re, sub1)) { + // stars are generated as a linear combination of all possible subterm lengths; + // this requires that there are no stars under this one + /* expr * v = mk_int_var("rlen"); expr * n = mk_int_var("rstar"); freeVariables.push_back(v); @@ -6692,7 +6756,32 @@ namespace smt { finalResult.push_back(ctx.mk_eq_atom(lenVar, m_autil.mk_mul(v, n))); expr_ref retval(mk_and(finalResult), m); return retval; + */ + integer_set subterm_lens; + check_subterm_lengths(sub1, subterm_lens); + if (subterm_lens.empty()) { + // somehow generation was impossible + expr_ref retval(m_autil.mk_ge(lenVar, m_autil.mk_numeral(rational::zero(), true)), m); + return retval; + } else { + TRACE("str", tout << "subterm lengths:"; + for(integer_set::iterator it = subterm_lens.begin(); it != subterm_lens.end(); ++it) { + tout << " " << *it; + } + tout << std::endl;); + expr_ref_vector sum_terms(m); + for (integer_set::iterator it = subterm_lens.begin(); it != subterm_lens.end(); ++it) { + rational lenOption(*it); + expr * n = mk_int_var("rstar"); + freeVariables.push_back(n); + expr_ref term(m_autil.mk_mul(m_autil.mk_numeral(lenOption, true), n), m); + sum_terms.push_back(term); + } + expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_add_simplify(sum_terms)), m); + return retval; + } } else if (u.re.is_plus(re, sub1)) { + /* expr * v = mk_int_var("rlen"); expr * n = mk_int_var("rstar"); freeVariables.push_back(v); @@ -6704,6 +6793,9 @@ namespace smt { finalResult.push_back(m_autil.mk_ge(n, m_autil.mk_numeral(rational::one(), true))); expr_ref retval(mk_and(finalResult), m); return retval; + */ + // TODO this should really be done as a sub-case of star + NOT_IMPLEMENTED_YET(); } else if (u.re.is_range(re, sub1, sub2)) { SASSERT(u.str.is_string(sub1)); SASSERT(u.str.is_string(sub2)); @@ -9664,8 +9756,6 @@ namespace smt { continue; } - // DISABLED due to bug -- star-over-union (and possibly others) results in unsound constraints - /* if (!regex_terms_with_length_constraints.contains(str_in_re)) { if (current_assignment == l_true && check_regex_length_linearity(re)) { TRACE("str", tout << "regex length constraints expected to be linear -- generating and asserting them" << std::endl;); @@ -9711,7 +9801,6 @@ namespace smt { regex_axiom_add = true; } } // re not in regex_terms_with_length_constraints - */ rational exact_length_value; if (get_len_value(str, exact_length_value)) { diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 4e790e838..ea4449b13 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -20,6 +20,7 @@ #include "util/trail.h" #include "util/union_find.h" #include "util/scoped_ptr_vector.h" +#include "util/hashtable.h" #include "ast/ast_pp.h" #include "ast/arith_decl_plugin.h" #include "ast/rewriter/th_rewriter.h" @@ -37,6 +38,7 @@ namespace smt { typedef hashtable symbol_set; +typedef int_hashtable > integer_set; class str_value_factory : public value_factory { seq_util u; @@ -556,6 +558,7 @@ protected: bool check_regex_length_linearity(expr * re); bool check_regex_length_linearity_helper(expr * re, bool already_star); expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); + void check_subterm_lengths(expr * re, integer_set & lens); void find_automaton_initial_bounds(expr * str_in_re, eautomaton * aut); bool refine_automaton_lower_bound(eautomaton * aut, rational current_lower_bound, rational & refined_lower_bound); bool refine_automaton_upper_bound(eautomaton * aut, rational current_upper_bound, rational & refined_upper_bound); From 57406d6cc4f6f4c5ee6725e5e1f4a0188105ffe2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Jan 2018 18:11:14 -0800 Subject: [PATCH 0473/1283] more updates for #1439 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 17 +++++++++++++---- src/opt/opt_context.h | 3 ++- src/sat/sat_model_converter.cpp | 4 +--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index f5f3f06fd..4ccf30563 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -122,6 +122,7 @@ namespace opt { m_bv(m), m_hard_constraints(m), m_solver(0), + m_pareto1(false), m_box_index(UINT_MAX), m_optsmt(m), m_scoped_state(m), @@ -294,12 +295,19 @@ namespace opt { if (0 == m_objectives.size()) { // no op } + else if (1 == m_objectives.size()) { + if (m_pareto1) { + is_sat = l_false; + m_pareto1 = false; + } + else { + m_pareto1 = (pri == symbol("pareto")); + is_sat = execute(m_objectives[0], true, false); + } + } else if (pri == symbol("pareto")) { is_sat = execute_pareto(); } - else if (1 == m_objectives.size()) { - is_sat = execute(m_objectives[0], true, false); - } else if (pri == symbol("box")) { is_sat = execute_box(); } @@ -1358,13 +1366,14 @@ namespace opt { } void context::clear_state() { - set_pareto(0); + set_pareto(0); m_box_index = UINT_MAX; m_model.reset(); } void context::set_pareto(pareto_base* p) { m_pareto = p; + m_pareto1 = p != nullptr; } void context::collect_statistics(statistics& stats) const { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 1ae60ef87..513f2dd85 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -144,7 +144,8 @@ namespace opt { ref m_opt_solver; ref m_solver; ref m_sat_solver; - scoped_ptr m_pareto; + scoped_ptr m_pareto; + bool m_pareto1; scoped_ptr m_qmax; sref_vector m_box_models; unsigned m_box_index; diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 1a881618a..1a3b4104f 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -74,9 +74,7 @@ namespace sat { DEBUG_CODE({ // all clauses must be satisfied bool sat = false; - it2 = it->m_clauses.begin(); - for (; it2 != end2; ++it2) { - literal l = *it2; + for (literal l : m_clauses) { if (l == null_literal) { SASSERT(sat); sat = false; From c7ee532173b97b67e93f3d0b02f3d425bb1ff96f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Jan 2018 10:44:40 -0800 Subject: [PATCH 0474/1283] fix static Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 6 ++++-- src/ast/format.cpp | 4 ++-- src/ast/pb_decl_plugin.cpp | 1 + src/ast/pb_decl_plugin.h | 1 - src/sat/ba_solver.cpp | 14 ++++++++------ src/sat/sat_solver/inc_sat_solver.cpp | 19 ++++++++++--------- src/sat/tactic/goal2sat.cpp | 22 ++++++++++++++-------- 7 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index f6169a851..e1db044da 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -122,8 +122,10 @@ format * smt2_pp_environment::pp_fdecl_params(format * fname, func_decl * f) { (f->get_parameter(i).is_ast() && is_func_decl(f->get_parameter(i).get_ast()))); if (f->get_parameter(i).is_int()) fs.push_back(mk_int(get_manager(), f->get_parameter(i).get_int())); - else if (f->get_parameter(i).is_rational()) - fs.push_back(mk_string(get_manager(), f->get_parameter(i).get_rational().to_string().c_str())); + else if (f->get_parameter(i).is_rational()) { + std::string str = f->get_parameter(i).get_rational().to_string(); + fs.push_back(mk_string(get_manager(), str.c_str())); + } else fs.push_back(pp_fdecl_ref(to_func_decl(f->get_parameter(i).get_ast()))); } diff --git a/src/ast/format.cpp b/src/ast/format.cpp index 835892121..6c2a02989 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -151,7 +151,7 @@ namespace format_ns { } format * mk_int(ast_manager & m, int i) { - static char buffer[128]; + char buffer[128]; #ifdef _WINDOWS sprintf_s(buffer, ARRAYSIZE(buffer), "%d", i); #else @@ -161,7 +161,7 @@ namespace format_ns { } format * mk_unsigned(ast_manager & m, unsigned u) { - static char buffer[128]; + char buffer[128]; #ifdef _WINDOWS sprintf_s(buffer, ARRAYSIZE(buffer), "%u", u); #else diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 928680131..298733a94 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -19,6 +19,7 @@ Revision History: #include "ast/pb_decl_plugin.h" #include "ast/ast_util.h" +#include "ast/ast_pp.h" pb_decl_plugin::pb_decl_plugin(): m_at_most_sym("at-most"), diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 7fdb592aa..94536dfd6 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -123,7 +123,6 @@ public: app* mk_fresh_bool(); - private: rational to_rational(parameter const& p) const; }; diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 5868c4289..d29f81fca 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -111,7 +111,7 @@ namespace sat { // card ba_solver::card::card(unsigned id, literal lit, literal_vector const& lits, unsigned k): - pb_base(card_t, id, lit, lits.size(), get_obj_size(lits.size()), k) { + pb_base(card_t, id, lit, lits.size(), get_obj_size(lits.size()), k) { for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; } @@ -420,17 +420,18 @@ namespace sat { sz = j; // _bad_id = p.id(); BADLOG(display(verbose_stream() << "simplify ", p, true)); - - p.set_size(sz); - p.set_k(p.k() - true_val); - if (p.k() == 1 && p.lit() == null_literal) { + unsigned k = p.k() - true_val; + + if (k == 1 && p.lit() == null_literal) { literal_vector lits(sz, p.literals().c_ptr()); s().mk_clause(sz, lits.c_ptr(), p.learned()); remove_constraint(p, "is clause"); return; } - else if (p.lit() == null_literal || value(p.lit()) == l_true) { + p.set_size(sz); + p.set_k(k); + if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p); } else { @@ -2621,6 +2622,7 @@ namespace sat { return; } + VERIFY(c.size() - c.k() >= sz - k); c.set_size(sz); c.set_k(k); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index e0cc8e581..f0d945d59 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -32,6 +32,7 @@ Notes: #include "tactic/core/simplify_tactic.h" #include "model/model_smt2_pp.h" #include "model/model_v2_pp.h" +#include "model/model_evaluator.h" #include "tactic/bv/bit_blaster_model_converter.h" #include "tactic/core/propagate_values_tactic.h" #include "sat/sat_solver.h" @@ -831,18 +832,18 @@ private: #if 0 IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); + model_evaluator eval(*m_model); for (expr * f : m_fmls) { expr_ref tmp(m); - if (m_model->eval(f, tmp, true)) { - CTRACE("sat", !m.is_true(tmp), - tout << "Evaluation failed: " << mk_pp(f, m) << " to " << mk_pp(f, m) << "\n"; - model_smt2_pp(tout, m, *(m_model.get()), 0);); - if (!m.is_true(tmp)) { - IF_VERBOSE(0, verbose_stream() << "failed to verify: " << tmp << "\n";); - IF_VERBOSE(0, verbose_stream() << m_params << "\n";); - } - VERIFY(m.is_true(tmp)); + eval(f, tmp); + CTRACE("sat", !m.is_true(tmp), + tout << "Evaluation failed: " << mk_pp(f, m) << " to " << mk_pp(f, m) << "\n"; + model_smt2_pp(tout, m, *(m_model.get()), 0);); + if (!m.is_true(tmp)) { + IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n";); + IF_VERBOSE(0, verbose_stream() << m_params << "\n";); } + VERIFY(m.is_true(tmp)); } #endif } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 68d15c48f..0b9f9805a 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -520,7 +520,7 @@ struct goal2sat::imp { } } - void convert_at_least_k(app* t, rational k, bool root, bool sign) { + void convert_at_least_k(app* t, rational const& k, bool root, bool sign) { SASSERT(k.is_unsigned()); sat::literal_vector lits; unsigned sz = m_result_stack.size(); @@ -539,7 +539,7 @@ struct goal2sat::imp { } } - void convert_at_most_k(app* t, rational k, bool root, bool sign) { + void convert_at_most_k(app* t, rational const& k, bool root, bool sign) { SASSERT(k.is_unsigned()); sat::literal_vector lits; unsigned sz = m_result_stack.size(); @@ -560,7 +560,7 @@ struct goal2sat::imp { } } - void convert_eq_k(app* t, rational k, bool root, bool sign) { + void convert_eq_k(app* t, rational const& k, bool root, bool sign) { SASSERT(k.is_unsigned()); sat::literal_vector lits; convert_pb_args(t->get_num_args(), lits); @@ -622,16 +622,20 @@ struct goal2sat::imp { } else if (t->get_family_id() == pb.get_family_id()) { ensure_extension(); + rational k; switch (t->get_decl_kind()) { case OP_AT_MOST_K: - convert_at_most_k(t, pb.get_k(t), root, sign); + k = pb.get_k(t); + convert_at_most_k(t, k, root, sign); break; case OP_AT_LEAST_K: - convert_at_least_k(t, pb.get_k(t), root, sign); + k = pb.get_k(t); + convert_at_least_k(t, k, root, sign); break; case OP_PB_LE: if (pb.has_unit_coefficients(t)) { - convert_at_most_k(t, pb.get_k(t), root, sign); + k = pb.get_k(t); + convert_at_most_k(t, k, root, sign); } else { convert_pb_le(t, root, sign); @@ -639,7 +643,8 @@ struct goal2sat::imp { break; case OP_PB_GE: if (pb.has_unit_coefficients(t)) { - convert_at_least_k(t, pb.get_k(t), root, sign); + k = pb.get_k(t); + convert_at_least_k(t, k, root, sign); } else { convert_pb_ge(t, root, sign); @@ -647,7 +652,8 @@ struct goal2sat::imp { break; case OP_PB_EQ: if (pb.has_unit_coefficients(t)) { - convert_eq_k(t, pb.get_k(t), root, sign); + k = pb.get_k(t); + convert_eq_k(t, k, root, sign); } else { convert_pb_eq(t, root, sign); From 5727950a3ced8c32a3a7d19680cd0dc5717fee7e Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 18 Jan 2018 17:52:55 -0500 Subject: [PATCH 0475/1283] zero-length automaton solution fix --- src/smt/theory_str.cpp | 148 ++++++++++++++++++++++++++++------------- 1 file changed, 100 insertions(+), 48 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index c4e6a9471..1f84b5faf 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9811,33 +9811,85 @@ namespace smt { continue; } - if (exact_length_value.is_zero()) { - // shortcut - expr_ref lhs(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(rational::zero(), true)), m); - expr_ref rhs(ctx.mk_eq_atom(str, mk_string("")), m); - assert_implication(lhs, rhs); - } else { - // find a consistent automaton for this term - bool found = false; - regex_automaton_under_assumptions assumption; - if (regex_automaton_assumptions.contains(re) && - !regex_automaton_assumptions[re].empty()){ - for (svector::iterator it = regex_automaton_assumptions[re].begin(); - it != regex_automaton_assumptions[re].end(); ++it) { - regex_automaton_under_assumptions autA = *it; - rational assumed_upper_bound, assumed_lower_bound; - bool assumes_upper_bound = autA.get_upper_bound(assumed_upper_bound); - bool assumes_lower_bound = autA.get_lower_bound(assumed_lower_bound); - if (!assumes_upper_bound && !assumes_lower_bound) { - // automaton with no assumptions is always usable - assumption = autA; - found = true; - break; + + // find a consistent automaton for this term + bool found = false; + regex_automaton_under_assumptions assumption; + if (regex_automaton_assumptions.contains(re) && + !regex_automaton_assumptions[re].empty()){ + for (svector::iterator it = regex_automaton_assumptions[re].begin(); + it != regex_automaton_assumptions[re].end(); ++it) { + regex_automaton_under_assumptions autA = *it; + rational assumed_upper_bound, assumed_lower_bound; + bool assumes_upper_bound = autA.get_upper_bound(assumed_upper_bound); + bool assumes_lower_bound = autA.get_lower_bound(assumed_lower_bound); + if (!assumes_upper_bound && !assumes_lower_bound) { + // automaton with no assumptions is always usable + assumption = autA; + found = true; + break; + } + // check consistency of bounds assumptions + } // foreach(a in regex_automaton_assumptions) + } + if (found) { + if (exact_length_value.is_zero()) { + // check consistency of 0-length solution with automaton + eautomaton * aut = assumption.get_automaton(); + bool zero_solution = false; + unsigned initial_state = aut->init(); + if (aut->is_final_state(initial_state)) { + zero_solution = true; + } else { + unsigned_vector eps_states; + aut->get_epsilon_closure(initial_state, eps_states); + for (unsigned_vector::iterator it = eps_states.begin(); it != eps_states.end(); ++it) { + unsigned state = *it; + if (aut->is_final_state(state)) { + zero_solution = true; + break; + } } - // check consistency of bounds assumptions - } // foreach(a in regex_automaton_assumptions) - } - if (found) { + } + + // now check polarity of automaton wrt. original term + if ( (current_assignment == l_true && !assumption.get_polarity()) + || (current_assignment == l_false && assumption.get_polarity())) { + // invert sense + NOT_IMPLEMENTED_YET(); + } + + if (zero_solution) { + TRACE("str", tout << "zero-length solution OK -- asserting empty path constraint" << std::endl;); + expr_ref_vector lhs_terms(m); + if (current_assignment == l_true) { + lhs_terms.push_back(str_in_re); + } else { + lhs_terms.push_back(m.mk_not(str_in_re)); + } + lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true))); + expr_ref lhs(mk_and(lhs_terms), m); + expr_ref rhs(ctx.mk_eq_atom(str, mk_string("")), m); + assert_implication(lhs, rhs); + regex_terms_with_path_constraints.insert(str_in_re); + m_trail_stack.push(insert_obj_trail(regex_terms_with_path_constraints, str_in_re)); + } else { + TRACE("str", tout << "zero-length solution not admitted by this automaton -- asserting conflict clause" << std::endl;); + expr_ref_vector lhs_terms(m); + if (current_assignment == l_true) { + lhs_terms.push_back(str_in_re); + } else { + lhs_terms.push_back(m.mk_not(str_in_re)); + } + lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true))); + expr_ref lhs(mk_and(lhs_terms), m); + expr_ref conflict(m.mk_not(lhs), m); + assert_axiom(conflict); + } + regex_axiom_add = true; + regex_inc_counter(regex_length_attempt_count, re); + continue; + } else { expr_ref pathConstraint(m); expr_ref characterConstraints(m); pathConstraint = generate_regex_path_constraints(str, assumption.get_automaton(), exact_length_value, characterConstraints); @@ -9876,30 +9928,30 @@ namespace smt { TRACE("str", tout << "length attempt count for " << mk_pp(re, m) << " is " << v << std::endl;); } - continue; - } else { - // no automata available, or else all bounds assumptions are invalid - unsigned expected_complexity = estimate_regex_complexity(re); - if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold || regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold) { - CTRACE("str", regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold, - tout << "failed automaton threshold reached for " << mk_pp(str_in_re, m) << " -- automatically constructing full automaton" << std::endl;); - eautomaton * aut = m_mk_aut(re); - aut->compress(); - regex_automata.push_back(aut); - regex_automaton_under_assumptions new_aut(re, aut, true); - if (!regex_automaton_assumptions.contains(re)) { - regex_automaton_assumptions.insert(re, svector()); - } - regex_automaton_assumptions[re].push_back(new_aut); - TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); - regex_axiom_add = true; - find_automaton_initial_bounds(str_in_re, aut); - } else { - regex_inc_counter(regex_fail_count, str_in_re); - } continue; } - } // !length is zero + } else { + // no automata available, or else all bounds assumptions are invalid + unsigned expected_complexity = estimate_regex_complexity(re); + if (expected_complexity <= m_params.m_RegexAutomata_DifficultyThreshold || regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold) { + CTRACE("str", regex_get_counter(regex_fail_count, str_in_re) >= m_params.m_RegexAutomata_FailedAutomatonThreshold, + tout << "failed automaton threshold reached for " << mk_pp(str_in_re, m) << " -- automatically constructing full automaton" << std::endl;); + eautomaton * aut = m_mk_aut(re); + aut->compress(); + regex_automata.push_back(aut); + regex_automaton_under_assumptions new_aut(re, aut, true); + if (!regex_automaton_assumptions.contains(re)) { + regex_automaton_assumptions.insert(re, svector()); + } + regex_automaton_assumptions[re].push_back(new_aut); + TRACE("str", tout << "add new automaton for " << mk_pp(re, m) << ": no assumptions" << std::endl;); + regex_axiom_add = true; + find_automaton_initial_bounds(str_in_re, aut); + } else { + regex_inc_counter(regex_fail_count, str_in_re); + } + continue; + } } // get_len_value() expr_ref str_len(mk_strlen(str), m); rational lower_bound_value; From a9fda81d0350fa586f9ef12c10309adab65847b0 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 18 Jan 2018 17:53:42 -0500 Subject: [PATCH 0476/1283] check polarity --- src/smt/theory_str.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 1f84b5faf..dceb17a06 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9856,7 +9856,7 @@ namespace smt { if ( (current_assignment == l_true && !assumption.get_polarity()) || (current_assignment == l_false && assumption.get_polarity())) { // invert sense - NOT_IMPLEMENTED_YET(); + zero_solution = !zero_solution; } if (zero_solution) { From 2065ea88ee3000c24d3d3fc2fade98c899f261d6 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Fri, 19 Jan 2018 14:56:06 -0500 Subject: [PATCH 0477/1283] fix null pointer dereference --- src/smt/theory_str.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index dceb17a06..5d66a4ec3 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -10372,7 +10372,9 @@ namespace smt { } } } // foreach(entry in intersect_constraints) - aut_inter->compress(); + if (aut_inter != NULL) { + aut_inter->compress(); + } TRACE("str", tout << "intersected " << used_intersect_constraints.size() << " constraints" << std::endl;); expr_ref_vector conflict_terms(m); From d9d3ef78d2a4c8e643e33cdfaf5ae3b30c1c2a4d Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Fri, 19 Jan 2018 16:14:56 -0500 Subject: [PATCH 0478/1283] temporarily disable final check progress checking it is interfering with regex automata solving --- src/smt/theory_str.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 5d66a4ec3..933796d9c 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -35,7 +35,7 @@ namespace smt { m_params(params), /* Options */ opt_EagerStringConstantLengthAssertions(true), - opt_VerifyFinalCheckProgress(true), + opt_VerifyFinalCheckProgress(false), opt_LCMUnrollStep(2), opt_NoQuickReturn_IntegerTheory(false), opt_DisableIntegerTheoryIntegration(false), From d6c49adddb5cb76391591940846bf2986ff97129 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Jan 2018 13:57:21 -0800 Subject: [PATCH 0479/1283] local Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/goal2sat.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 596712a7b..bc4b7a672 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -311,7 +311,6 @@ struct goal2sat::imp { } } - void convert_ite(app * n, bool root, bool sign) { unsigned sz = m_result_stack.size(); SASSERT(sz >= 3); From e4f29a7b8a1f8692b65d73b0a1dfe009df567b67 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Jan 2018 21:09:52 -0800 Subject: [PATCH 0480/1283] debugging mc Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 4 +- src/muz/base/dl_rule.cpp | 2 +- src/muz/fp/horn_tactic.cpp | 2 +- src/muz/transforms/dl_mk_bit_blast.cpp | 2 +- src/muz/transforms/dl_mk_coi_filter.cpp | 4 +- src/opt/opt_context.cpp | 4 +- src/opt/sortmax.cpp | 2 +- src/qe/qsat.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 4 +- src/solver/solver.cpp | 3 - src/solver/solver2tactic.cpp | 2 +- src/tactic/arith/card2bv_tactic.cpp | 2 +- src/tactic/arith/degree_shift_tactic.cpp | 2 +- src/tactic/arith/fix_dl_var_tactic.cpp | 2 +- src/tactic/arith/lia2pb_tactic.cpp | 2 +- src/tactic/arith/nla2bv_tactic.cpp | 2 +- src/tactic/arith/normalize_bounds_tactic.cpp | 2 +- src/tactic/arith/pb2bv_tactic.cpp | 2 +- src/tactic/arith/purify_arith_tactic.cpp | 4 +- src/tactic/arith/recover_01_tactic.cpp | 2 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 6 +- src/tactic/bv/bvarray2uf_tactic.cpp | 2 +- src/tactic/bv/dt2bv_tactic.cpp | 3 +- src/tactic/core/elim_term_ite_tactic.cpp | 2 +- src/tactic/core/elim_uncnstr_tactic.cpp | 4 +- src/tactic/core/nnf_tactic.cpp | 2 +- src/tactic/core/occf_tactic.cpp | 2 +- src/tactic/core/reduce_args_tactic.cpp | 2 +- src/tactic/core/solve_eqs_tactic.cpp | 2 +- src/tactic/core/tseitin_cnf_tactic.cpp | 2 +- src/tactic/generic_model_converter.cpp | 35 +++++------ src/tactic/generic_model_converter.h | 3 +- src/tactic/model_converter.cpp | 1 + .../portfolio/bounded_int2bv_solver.cpp | 61 ++++++++++--------- src/tactic/portfolio/enum2bv_solver.cpp | 53 ++++++++++------ src/tactic/portfolio/pb2bv_solver.cpp | 31 +++++++--- src/tactic/ufbv/macro_finder_tactic.cpp | 2 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 2 +- 38 files changed, 143 insertions(+), 123 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 93d83d2a4..0b2decec8 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -864,7 +864,7 @@ void cmd_context::insert(symbol const & s, object_ref * r) { } void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domain, expr * t) { - if (!m_mc0.get()) m_mc0 = alloc(generic_model_converter, m()); + if (!m_mc0.get()) m_mc0 = alloc(generic_model_converter, m(), "cmd_context"); if (m_solver.get() && !m_solver->mc0()) m_solver->set_model_converter(m_mc0.get()); func_decl_ref fn(m().mk_func_decl(s, arity, domain, m().get_sort(t)), m()); dictionary::entry * e = m_func_decls.insert_if_not_there2(s, func_decls()); @@ -874,7 +874,7 @@ void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domai } void cmd_context::model_del(func_decl* f) { - if (!m_mc0.get()) m_mc0 = alloc(generic_model_converter, m()); + if (!m_mc0.get()) m_mc0 = alloc(generic_model_converter, m(), "model_del"); if (m_solver.get() && !m_solver->mc0()) m_solver->set_model_converter(m_mc0.get()); m_mc0->hide(f); } diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index c188426f0..c74b9cfc4 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -326,7 +326,7 @@ namespace datalog { rules.set_output_predicate(qpred); if (m_ctx.get_model_converter()) { - generic_model_converter* mc = alloc(generic_model_converter, m); + generic_model_converter* mc = alloc(generic_model_converter, m, "dl_rule"); mc->hide(qpred); m_ctx.add_model_converter(mc); } diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 881ae9aec..5027e42cf 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -225,7 +225,7 @@ class horn_tactic : public tactic { } queries.reset(); queries.push_back(q); - generic_model_converter* mc1 = alloc(generic_model_converter, m); + generic_model_converter* mc1 = alloc(generic_model_converter, m, "horn"); mc1->hide(q); g->add(mc1); } diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 7f3ae43f3..4d4c22780 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -299,7 +299,7 @@ namespace datalog { } if (m_context.get_model_converter()) { - generic_model_converter* fmc = alloc(generic_model_converter, m); + generic_model_converter* fmc = alloc(generic_model_converter, m, "dl_mk_bit_blast"); bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); func_decl_ref_vector const& old_funcs = m_rewriter.m_cfg.old_funcs(); func_decl_ref_vector const& new_funcs = m_rewriter.m_cfg.new_funcs(); diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index a75c08ec4..afaf5ba19 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -90,7 +90,7 @@ namespace datalog { // set to false each unreached predicate if (m_context.get_model_converter()) { - generic_model_converter* mc0 = alloc(generic_model_converter, m); + generic_model_converter* mc0 = alloc(generic_model_converter, m, "dl_coi"); for (auto const& kv : engine) { if (!kv.m_value.is_reachable()) { mc0->add(kv.m_key, m.mk_false()); @@ -127,7 +127,7 @@ namespace datalog { if (res && m_context.get_model_converter()) { func_decl_set::iterator end = pruned_preds.end(); func_decl_set::iterator it = pruned_preds.begin(); - generic_model_converter* mc0 = alloc(generic_model_converter, m); + generic_model_converter* mc0 = alloc(generic_model_converter, m, "dl_coi"); for (; it != end; ++it) { const rule_vector& rules = source.get_predicate_rules(*it); expr_ref_vector fmls(m); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 7cb2c6034..9e72d24dc 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -126,7 +126,7 @@ namespace opt { m_box_index(UINT_MAX), m_optsmt(m), m_scoped_state(m), - m_fm(m), + m_fm(m, "opt"), m_objective_refs(m), m_enable_sat(false), m_is_clausal(false), @@ -1062,7 +1062,7 @@ namespace opt { std::ostringstream out; out << mk_pp(term, m); app* q = m.mk_fresh_const(out.str().c_str(), m.get_sort(term)); - if (!fm) fm = alloc(generic_model_converter, m); + if (!fm) fm = alloc(generic_model_converter, m, "opt"); m_hard_constraints.push_back(m.mk_eq(q, term)); fm->hide(q); return q; diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 18c3edc76..966fe12db 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -50,7 +50,7 @@ namespace opt { if (is_sat != l_true) { return is_sat; } - m_filter = alloc(generic_model_converter, m); + m_filter = alloc(generic_model_converter, m, "sortmax"); rational offset = m_lower; m_upper = offset; expr_ref_vector in(m); diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 2e78574ec..a5ef4e94d 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -44,7 +44,7 @@ namespace qe { m(m), m_asms(m), m_trail(m), - m_fmc(alloc(generic_model_converter, m)) + m_fmc(alloc(generic_model_converter, m, "qsat")) { } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 0b9f9805a..2dfcb7bb8 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -900,7 +900,7 @@ void sat2goal::mc::flush_gmc() { sat::literal_vector updates; m_smc.expand(updates); m_smc.reset(); - if (!m_gmc) m_gmc = alloc(generic_model_converter, m); + if (!m_gmc) m_gmc = alloc(generic_model_converter, m, "sat2goal"); // now gmc owns the model converter sat::literal_vector clause; expr_ref_vector tail(m); @@ -1018,7 +1018,7 @@ void sat2goal::mc::insert(sat::bool_var v, app * atom, bool aux) { if (aux) { SASSERT(is_uninterp_const(atom)); SASSERT(m.is_bool(atom)); - if (!m_gmc) m_gmc = alloc(generic_model_converter, m); + if (!m_gmc) m_gmc = alloc(generic_model_converter, m, "sat2goal"); m_gmc->hide(atom->get_decl()); } } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 9fbaa8032..356eaf2ed 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -43,7 +43,6 @@ std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assum get_assertions(fmls); ast_pp_util visitor(get_manager()); model_converter_ref mc = get_model_converter(); - mc = concat(mc0(), mc.get()); if (mc.get()) { mc->collect(visitor); } @@ -180,7 +179,6 @@ void solver::assert_expr(expr* f) { expr_ref fml(f, get_manager()); if (m_enforce_model_conversion) { model_converter_ref mc = get_model_converter(); - mc = concat(mc0(), mc.get()); if (mc) { (*mc)(fml); } @@ -196,7 +194,6 @@ void solver::assert_expr(expr* f, expr* t) { IF_VERBOSE(0, verbose_stream() << "enforce model conversion\n";); exit(0); model_converter_ref mc = get_model_converter(); - mc = concat(mc0(), mc.get()); if (mc) { (*mc)(fml); // (*mc)(a); diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 6863c935e..ecf676bc6 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -65,7 +65,7 @@ void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clause bool2dep.insert(b, d); assumptions.push_back(b); if (!fmc) { - fmc = alloc(generic_model_converter, m); + fmc = alloc(generic_model_converter, m, "solver2tactic"); } fmc->hide(to_app(b)->get_decl()); } diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 6349c40b2..36a73198d 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -86,7 +86,7 @@ public: func_decl_ref_vector const& fns = rw2.fresh_constants(); if (!fns.empty()) { - generic_model_converter* filter = alloc(generic_model_converter, m); + generic_model_converter* filter = alloc(generic_model_converter, m, "card2bv"); for (func_decl* f : fns) filter->hide(f); g->add(filter); } diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 704d48eac..4e9a39a97 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -198,7 +198,7 @@ class degree_shift_tactic : public tactic { SASSERT(!m_var2degree.empty()); generic_model_converter * xmc = 0; if (m_produce_models) { - xmc = alloc(generic_model_converter, m); + xmc = alloc(generic_model_converter, m, "degree_shift"); mc = xmc; } for (auto const& kv : m_var2degree) { diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index fe1b64e90..45ff10953 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -266,7 +266,7 @@ class fix_dl_var_tactic : public tactic { m_rw.set_substitution(&subst); if (m_produce_models) { - generic_model_converter * mc = alloc(generic_model_converter, m); + generic_model_converter * mc = alloc(generic_model_converter, m, "fix_dl"); mc->add(var, zero); g->add(mc); } diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index 274c6dd40..9d62e6dc4 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -222,7 +222,7 @@ class lia2pb_tactic : public tactic { ref gmc; if (m_produce_models) { - gmc = alloc(generic_model_converter, m); + gmc = alloc(generic_model_converter, m, "lia2pb"); } expr_ref zero(m); diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index f7c985129..9eca330cd 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -85,7 +85,7 @@ class nla2bv_tactic : public tactic { TRACE("nla2bv", g.display(tout); tout << "Muls: " << count_mul(g) << "\n"; ); - m_fmc = alloc(generic_model_converter, m_manager); + m_fmc = alloc(generic_model_converter, m_manager, "nla2bv"); m_bounds(g); collect_power2(g); if(!collect_vars(g)) { diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index 130b5cfe6..a4454679c 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -94,7 +94,7 @@ class normalize_bounds_tactic : public tactic { generic_model_converter * gmc = 0; if (produce_models) { - gmc = alloc(generic_model_converter, m); + gmc = alloc(generic_model_converter, m, "normalize_bounds"); in->add(gmc); } diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index de4fa8221..14593c9a8 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -947,7 +947,7 @@ private: if (m_produce_models) { model_converter_ref mc; - generic_model_converter * mc1 = alloc(generic_model_converter, m); + generic_model_converter * mc1 = alloc(generic_model_converter, m, "pb2bv"); for (auto const& kv : m_const2bit) mc1->hide(kv.m_value); // store temp int constants in the filter diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 692d6ab6d..a75e0dc52 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -765,7 +765,7 @@ struct purify_arith_proc { // add generic_model_converter to eliminate auxiliary variables from model if (produce_models) { - generic_model_converter * fmc = alloc(generic_model_converter, m()); + generic_model_converter * fmc = alloc(generic_model_converter, m(), "purify"); mc = fmc; obj_map & f2v = r.cfg().m_app2fresh; for (auto const& kv : f2v) { @@ -775,7 +775,7 @@ struct purify_arith_proc { } } if (produce_models && !m_sin_cos.empty()) { - generic_model_converter* emc = alloc(generic_model_converter, m()); + generic_model_converter* emc = alloc(generic_model_converter, m(), "purify_sin_cos"); mc = concat(mc.get(), emc); obj_map >::iterator it = m_sin_cos.begin(), end = m_sin_cos.end(); for (; it != end; ++it) { diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index 7645f34cd..4e1727139 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -325,7 +325,7 @@ class recover_01_tactic : public tactic { } if (m_produce_models) { - gmc = alloc(generic_model_converter, m); + gmc = alloc(generic_model_converter, m, "recover_01"); new_goal->add(gmc); } diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index 8c4ea22ad..5577b3dfe 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -265,10 +265,10 @@ struct bv_size_reduction_tactic::imp { subst.insert(v, new_def); if (m_produce_models) { if (!m_mc) - m_mc = alloc(bv_size_reduction_mc, m); + m_mc = alloc(bv_size_reduction_mc, m, "bv_size_reduction"); m_mc->add(v, new_def); if (!m_fmc && new_const) - m_fmc = alloc(generic_model_converter, m); + m_fmc = alloc(generic_model_converter, m, "bv_size_reduction"); if (new_const) m_fmc->hide(new_const); } @@ -334,7 +334,7 @@ struct bv_size_reduction_tactic::imp { m_mc = alloc(bv_size_reduction_mc, m); m_mc->insert(v->get_decl(), new_def); if (!m_fmc && new_const) - m_fmc = alloc(generic_model_converter, m); + m_fmc = alloc(generic_model_converter, m, "bv_size_reduction"); if (new_const) m_fmc->hide(new_const); } diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index 7718a9679..0636c74cf 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -65,7 +65,7 @@ class bvarray2uf_tactic : public tactic { model_converter_ref mc; if (m_produce_models) { - generic_model_converter * fmc = alloc(generic_model_converter, m_manager); + generic_model_converter * fmc = alloc(generic_model_converter, m_manager, "bvarray2uf"); mc = fmc; m_rw.set_mcs(fmc); } diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index bbfbe02fd..f8456e12b 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -25,7 +25,6 @@ Revision History: #include "ast/datatype_decl_plugin.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" -#include "tactic/generic_model_converter.h" #include "ast/rewriter/var_subst.h" #include "ast/ast_util.h" #include "ast/rewriter/enum2bv_rewriter.h" @@ -128,7 +127,7 @@ public: for (sort* s : m_non_fd_sorts) m_fd_sorts.remove(s); if (!m_fd_sorts.empty()) { - ref filter = alloc(generic_model_converter, m); + ref filter = alloc(generic_model_converter, m, "dt2bv"); enum2bv_rewriter rw(m, m_params); rw.set_is_fd(&m_is_fd); expr_ref new_curr(m); diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index e4e337e00..49815b6d1 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -55,7 +55,7 @@ class elim_term_ite_tactic : public tactic { m_num_fresh++; if (m_produce_models) { if (!m_mc) - m_mc = alloc(generic_model_converter, m); + m_mc = alloc(generic_model_converter, m, "elim_term_ite"); m_mc->hide(_result->get_decl()); } } diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index cc5402e41..2f961f9bc 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -808,7 +808,7 @@ class elim_uncnstr_tactic : public tactic { m_mc = 0; return; } - m_mc = alloc(mc, m()); + m_mc = alloc(mc, m(), "elim_uncstr"); } void init_rw(bool produce_proofs) { @@ -867,7 +867,7 @@ class elim_uncnstr_tactic : public tactic { app_ref_vector & fresh_vars = m_rw->cfg().m_fresh_vars; m_num_elim_apps = fresh_vars.size(); if (produce_models && !fresh_vars.empty()) { - generic_model_converter * fmc = alloc(generic_model_converter, m()); + generic_model_converter * fmc = alloc(generic_model_converter, m(), "elim_uncnstr"); for (app * f : fresh_vars) fmc->hide(f); g->add(concat(fmc, m_mc.get())); diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index c13f49b52..b6bab648c 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -93,7 +93,7 @@ public: result.push_back(g.get()); unsigned num_extra_names = dnames.get_num_names(); if (num_extra_names > 0) { - generic_model_converter * fmc = alloc(generic_model_converter, m); + generic_model_converter * fmc = alloc(generic_model_converter, m, "nnf"); g->add(fmc); for (unsigned i = 0; i < num_extra_names; i++) fmc->hide(dnames.get_name_decl(i)); diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index e875a0472..86e776081 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -153,7 +153,7 @@ class occf_tactic : public tactic { if (!is_target(cls)) continue; if (produce_models && !m_mc) { - m_mc = alloc(generic_model_converter, m); + m_mc = alloc(generic_model_converter, m, "occf"); g->add(m_mc); } expr * keep = 0; diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index 1e7baa14f..ac4a009e9 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -393,7 +393,7 @@ struct reduce_args_tactic::imp { ptr_buffer new_args; var_ref_vector new_vars(m_manager); ptr_buffer new_eqs; - generic_model_converter * f_mc = alloc(generic_model_converter, m_manager); + generic_model_converter * f_mc = alloc(generic_model_converter, m_manager, "reduce_args"); for (auto const& kv : decl2arg2funcs) { func_decl * f = kv.m_key; arg2func * map = kv.m_value; diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 22b87d60e..5fbf9aaf5 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -606,7 +606,7 @@ class solve_eqs_tactic : public tactic { m_num_eliminated_vars += m_ordered_vars.size(); if (m_produce_models) { if (mc.get() == 0) - mc = alloc(gmc, m()); + mc = alloc(gmc, m(), "solve_eqs"); for (app * v : m_ordered_vars) { expr * def = 0; proof * pr; diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index 91f974eb9..eae724c7a 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -813,7 +813,7 @@ class tseitin_cnf_tactic : public tactic { m_frame_stack.reset(); m_clauses.reset(); if (m_produce_models) - m_mc = alloc(generic_model_converter, m); + m_mc = alloc(generic_model_converter, m, "tseitin"); else m_mc = 0; diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index aa1f1cdc4..4f48c78e1 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -29,6 +29,7 @@ Notes: void generic_model_converter::add(func_decl * d, expr* e) { + VERIFY(e); struct entry et(d, e, m, ADD); VERIFY(d->get_range() == m.get_sort(e)); m_first_idx.insert_if_not_there(et.m_f, m_entries.size()); @@ -39,9 +40,10 @@ void generic_model_converter::operator()(model_ref & md) { TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout);); model_evaluator ev(*(md.get())); ev.set_model_completion(true); - ev.set_expand_array_equalities(false); + ev.set_expand_array_equalities(false); expr_ref val(m); unsigned arity; + bool reset_ev = false; for (unsigned i = m_entries.size(); i-- > 0; ) { entry const& e = m_entries[i]; switch (e.m_instruction) { @@ -50,32 +52,16 @@ void generic_model_converter::operator()(model_ref & md) { break; case instruction::ADD: ev(e.m_def, val); -#if 0 - if (e.m_f->get_name() == symbol("XX")) { - IF_VERBOSE(0, verbose_stream() << e.m_f->get_name() << " " << e.m_def << " -> " << val << "\n";); - ptr_vector ts; - ts.push_back(e.m_def); - while (!ts.empty()) { - app* t = to_app(ts.back()); - ts.pop_back(); - if (t->get_num_args() > 0) { - ts.append(t->get_num_args(), t->get_args()); - } - expr_ref tmp(m); - ev(t, tmp); - IF_VERBOSE(0, verbose_stream() << mk_pp(t, m) << " -> " << tmp << "\n";); - } - } -#endif TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";); arity = e.m_f->get_arity(); + reset_ev = false; if (arity == 0) { expr* old_val = md->get_const_interp(e.m_f); if (old_val && old_val == val) { // skip } else { - if (old_val) ev.reset(); + reset_ev = old_val != nullptr; md->register_decl(e.m_f, val); } } @@ -85,12 +71,17 @@ void generic_model_converter::operator()(model_ref & md) { // skip } else { - if (old_val) ev.reset(); + reset_ev = old_val != nullptr; func_interp * new_fi = alloc(func_interp, m, arity); new_fi->set_else(val); md->register_decl(e.m_f, new_fi); } } + if (reset_ev) { + ev.reset(); + ev.set_model_completion(true); + ev.set_expand_array_equalities(false); + } break; } } @@ -98,7 +89,9 @@ void generic_model_converter::operator()(model_ref & md) { } void generic_model_converter::display(std::ostream & out) { + unsigned i = 0; for (entry const& e : m_entries) { + ++i; switch (e.m_instruction) { case instruction::HIDE: display_del(out, e.m_f); @@ -112,7 +105,7 @@ void generic_model_converter::display(std::ostream & out) { model_converter * generic_model_converter::translate(ast_translation & translator) { ast_manager& to = translator.to(); - generic_model_converter * res = alloc(generic_model_converter, to); + generic_model_converter * res = alloc(generic_model_converter, to, m_orig.c_str()); for (entry const& e : m_entries) { res->m_entries.push_back(entry(translator(e.m_f.get()), translator(e.m_def.get()), to, e.m_instruction)); } diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index 8d40d55b7..a85cc9766 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -39,13 +39,14 @@ class generic_model_converter : public model_converter { } }; ast_manager& m; + std::string m_orig; vector m_entries; obj_map m_first_idx; expr_ref simplify_def(entry const& e); public: - generic_model_converter(ast_manager & m) : m(m) {} + generic_model_converter(ast_manager & m, char const* orig) : m(m), m_orig(orig) {} virtual ~generic_model_converter() { } diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 161666d01..6c77d91b6 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -24,6 +24,7 @@ Notes: * Add or overwrite value in model. */ void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { + VERIFY(e); smt2_pp_environment_dbg env(m); smt2_pp_environment* _env = m_env ? m_env : &env; VERIFY(f->get_range() == m.get_sort(e)); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 3e1b5d2f4..ee6630fd3 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -81,9 +81,10 @@ public: for (func_decl* f : m_bv_fns) result->m_bv_fns.push_back(tr(f)); for (func_decl* f : m_int_fns) result->m_int_fns.push_back(tr(f)); for (bound_manager* b : m_bounds) result->m_bounds.push_back(b->translate(dst_m)); - if (mc0()) { + model_converter_ref mc = external_model_converter(); + if (mc) { ast_translation tr(m, dst_m); - result->set_model_converter(mc0()->translate(tr)); + result->set_model_converter(mc->translate(tr)); } return result; } @@ -151,11 +152,36 @@ public: virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { - extend_model(mdl); - filter_model(mdl); + model_converter_ref mc = bounded_model_converter(); + if (mc) (*mc)(mdl); } } - virtual model_converter_ref get_model_converter() const { return m_solver->get_model_converter(); } + model_converter* external_model_converter() const { + return concat(mc0(), bounded_model_converter()); + } + model_converter* bounded_model_converter() const { + if (m_int2bv.empty() && m_bv_fns.empty()) return nullptr; + generic_model_converter* mc = alloc(generic_model_converter, m, "bounded_int2bv"); + for (func_decl* f : m_bv_fns) + mc->hide(f); + for (auto const& kv : m_int2bv) { + rational offset; + VERIFY (m_bv2offset.find(kv.m_value, offset)); + expr_ref value(m_bv.mk_bv2int(m.mk_const(kv.m_value)), m); + if (!offset.is_zero()) { + value = m_arith.mk_add(value, m_arith.mk_numeral(offset, true)); + } + TRACE("int2bv", tout << mk_pp(kv.m_key, m) << " " << value << "\n";); + mc->add(kv.m_key, value); + } + return mc; + } + + virtual model_converter_ref get_model_converter() const { + model_converter_ref mc = concat(mc0(), bounded_model_converter()); + mc = concat(mc.get(), m_solver->get_model_converter().get()); + return mc; + } virtual proof * get_proof() { return m_solver->get_proof(); } virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } @@ -198,35 +224,10 @@ public: } } return r; - } private: - void filter_model(model_ref& mdl) const { - if (m_bv_fns.empty()) { - return; - } - generic_model_converter filter(m); - for (func_decl* f : m_bv_fns) filter.hide(f); - filter(mdl); - } - - void extend_model(model_ref& mdl) { - generic_model_converter ext(m); - for (auto const& kv : m_int2bv) { - rational offset; - VERIFY (m_bv2offset.find(kv.m_value, offset)); - expr_ref value(m_bv.mk_bv2int(m.mk_const(kv.m_value)), m); - if (!offset.is_zero()) { - value = m_arith.mk_add(value, m_arith.mk_numeral(offset, true)); - } - TRACE("int2bv", tout << mk_pp(kv.m_key, m) << " " << value << "\n";); - ext.add(kv.m_key, value); - } - ext(mdl); - } - void accumulate_sub(expr_safe_replace& sub) const { for (unsigned i = 0; i < m_bounds.size(); ++i) { accumulate_sub(sub, *m_bounds[i]); diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 5db907c2c..9567f369f 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -50,9 +50,10 @@ public: virtual solver* translate(ast_manager& dst_m, params_ref const& p) { solver* result = alloc(enum2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); - if (mc0()) { + model_converter_ref mc = external_model_converter(); + if (mc) { ast_translation tr(m, dst_m); - result->set_model_converter(mc0()->translate(tr)); + result->set_model_converter(mc->translate(tr)); } return result; } @@ -91,18 +92,43 @@ public: virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { - extend_model(mdl); - filter_model(mdl); + model_converter_ref mc = enum_model_converter(); + if (mc) (*mc)(mdl); } } - virtual model_converter_ref get_model_converter() const { return m_solver->get_model_converter(); } + model_converter* enum_model_converter() const { + if (m_rewriter.enum2def().empty() && + m_rewriter.enum2bv().empty()) { + return nullptr; + } + generic_model_converter* mc = alloc(generic_model_converter, m, "enum2bv"); + for (auto const& kv : m_rewriter.enum2bv()) + mc->hide(kv.m_value); + for (auto const& kv : m_rewriter.enum2def()) + mc->add(kv.m_key, kv.m_value); + return mc; + } + + model_converter* external_model_converter() const { + return concat(mc0(), enum_model_converter()); + } + + virtual model_converter_ref get_model_converter() const { + model_converter_ref mc = external_model_converter(); + mc = concat(mc.get(), m_solver->get_model_converter().get()); + return mc; + } virtual proof * get_proof() { return m_solver->get_proof(); } virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } virtual void get_labels(svector & r) { m_solver->get_labels(r); } virtual ast_manager& get_manager() const { return m; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) { return m_solver->cube(vars, backtrack_level); } + virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + return m_solver->find_mutexes(vars, mutexes); + } + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) { + return m_solver->cube(vars, backtrack_level); + } virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { datatype_util dt(m); @@ -152,20 +178,7 @@ public: return r; } - void filter_model(model_ref& mdl) { - generic_model_converter filter(m); - for (auto const& kv : m_rewriter.enum2bv()) { - filter.hide(kv.m_value); - } - filter(mdl); - } - void extend_model(model_ref& mdl) { - generic_model_converter ext(m); - for (auto const& kv : m_rewriter.enum2def()) - ext.add(kv.m_key, kv.m_value); - ext(mdl); - } virtual unsigned get_num_assertions() const { return m_solver->get_num_assertions(); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index cee566ec6..6660e1bb4 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -50,9 +50,10 @@ public: virtual solver* translate(ast_manager& dst_m, params_ref const& p) { flush_assertions(); solver* result = alloc(pb2bv_solver, dst_m, p, m_solver->translate(dst_m, p)); - if (mc0()) { + model_converter_ref mc = external_model_converter(); + if (mc.get()) { ast_translation tr(m, dst_m); - result->set_model_converter(mc0()->translate(tr)); + result->set_model_converter(mc->translate(tr)); } return result; } @@ -93,7 +94,14 @@ public: filter_model(mdl); } } - virtual model_converter_ref get_model_converter() const { return m_solver->get_model_converter(); } + model_converter* external_model_converter() const { + return concat(mc0(), filter_model_converter()); + } + virtual model_converter_ref get_model_converter() const { + model_converter_ref mc = concat(mc0(), filter_model_converter()); + mc = concat(mc.get(), m_solver->get_model_converter().get()); + return mc; + } virtual proof * get_proof() { return m_solver->get_proof(); } virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } @@ -105,16 +113,23 @@ public: flush_assertions(); return m_solver->get_consequences(asms, vars, consequences); } - void filter_model(model_ref& mdl) { + model_converter* filter_model_converter() const { if (m_rewriter.fresh_constants().empty()) { - return; + return nullptr; } - generic_model_converter filter(m); + generic_model_converter* filter = alloc(generic_model_converter, m, "pb2bv"); func_decl_ref_vector const& fns = m_rewriter.fresh_constants(); for (func_decl* f : fns) { - filter.hide(f); + filter->hide(f); + } + return filter; + } + + void filter_model(model_ref& mdl) { + model_converter_ref mc = filter_model_converter(); + if (mc.get()) { + (*mc)(mdl); } - filter(mdl); } virtual unsigned get_num_assertions() const { diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index efed67486..62c1d0340 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -65,7 +65,7 @@ class macro_finder_tactic : public tactic { produce_proofs ? new_proofs.get(i) : 0, unsat_core_enabled ? new_deps.get(i) : 0); - generic_model_converter * evmc = alloc(generic_model_converter, mm.get_manager()); + generic_model_converter * evmc = alloc(generic_model_converter, mm.get_manager(), "macro_finder"); unsigned num = mm.get_num_macros(); for (unsigned i = 0; i < num; i++) { expr_ref f_interp(mm.get_manager()); diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index 05c5bdd73..93e893f89 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -77,7 +77,7 @@ class quasi_macros_tactic : public tactic { produce_proofs ? proofs.get(i) : 0, produce_unsat_cores ? deps.get(i) : 0); - generic_model_converter * evmc = alloc(generic_model_converter, mm.get_manager()); + generic_model_converter * evmc = alloc(generic_model_converter, mm.get_manager(), "quasi_macros"); unsigned num = mm.get_num_macros(); for (unsigned i = 0; i < num; i++) { expr_ref f_interp(mm.get_manager()); From b129ee764fda0d33fdf94b487e0c265a3a308e6c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2018 10:20:22 -0800 Subject: [PATCH 0481/1283] debugging opt Signed-off-by: Nikolaj Bjorner --- src/cmd_context/pdecl.cpp | 3 +++ src/sat/sat_solver/inc_sat_solver.cpp | 5 ++++- src/tactic/generic_model_converter.cpp | 2 -- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 7eac1f347..7a85e87a2 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -866,6 +866,7 @@ psort * pdecl_manager::mk_psort_cnst(sort * s) { } psort * pdecl_manager::register_psort(psort * n) { + enable_trace("register_psort"); TRACE("register_psort", tout << "registering psort...\n"; n->display(tout); tout << "\n";); psort * r = m_table.insert_if_not_there(n); if (r != n) { @@ -946,6 +947,8 @@ void pdecl_manager::del_decl_core(pdecl * p) { } void pdecl_manager::del_decl(pdecl * p) { +enable_trace("register_psort"); + TRACE("register_psort", tout << "del psort "; p->display(tout); tout << "\n";); if (p->is_psort()) { psort * _p = static_cast(p); if (_p->is_sort_wrapper()) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index f0d945d59..0ad665c5e 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -830,7 +830,7 @@ private: // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "after\n");); -#if 0 +#if 1 IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); model_evaluator eval(*m_model); for (expr * f : m_fmls) { @@ -842,6 +842,9 @@ private: if (!m.is_true(tmp)) { IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n";); IF_VERBOSE(0, verbose_stream() << m_params << "\n";); + IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "sat mc\n");); + IF_VERBOSE(0, if (m_mc0) m_mc0->display(verbose_stream() << "mc0\n");); + break; } VERIFY(m.is_true(tmp)); } diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 4f48c78e1..139355d5f 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -89,9 +89,7 @@ void generic_model_converter::operator()(model_ref & md) { } void generic_model_converter::display(std::ostream & out) { - unsigned i = 0; for (entry const& e : m_entries) { - ++i; switch (e.m_instruction) { case instruction::HIDE: display_del(out, e.m_f); From ece5ad90e04cdf09634d7356154828a91928ed17 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2018 17:09:43 -0800 Subject: [PATCH 0482/1283] fix model conversion bugs Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 20 ++++----- src/cmd_context/cmd_context.h | 2 +- src/cmd_context/pdecl.cpp | 4 +- src/sat/sat_model_converter.cpp | 40 +++++++++--------- src/sat/sat_model_converter.h | 2 + src/sat/sat_simplifier.cpp | 15 ++++--- src/sat/sat_solver/inc_sat_solver.cpp | 42 +++++++------------ src/tactic/generic_model_converter.cpp | 1 + .../portfolio/bounded_int2bv_solver.cpp | 8 ++-- src/tactic/portfolio/enum2bv_solver.cpp | 6 +-- src/tactic/portfolio/pb2bv_solver.cpp | 16 +++---- 11 files changed, 68 insertions(+), 88 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 0b2decec8..f82f8868d 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1419,7 +1419,9 @@ void cmd_context::restore_assertions(unsigned old_sz) { SASSERT(m_assertions.empty()); return; } - SASSERT(old_sz <= m_assertions.size()); + if (old_sz == m_assertions.size()) + return; + SASSERT(old_sz < m_assertions.size()); SASSERT(!m_interactive_mode || m_assertions.size() == m_assertion_strings.size()); restore(m(), m_assertions, old_sz); if (produce_unsat_cores()) @@ -1520,7 +1522,6 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions } display_sat_result(r); if (r == l_true) { - complete_model(); validate_model(); } validate_check_sat_result(r); @@ -1528,9 +1529,8 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions // get_opt()->display_assignment(regular_stream()); } - if (r == l_true && m_params.m_dump_models) { - model_ref md; - get_check_sat_result()->get_model(md); + model_ref md; + if (r == l_true && m_params.m_dump_models && is_model_available(md)) { display_model(md); } } @@ -1695,14 +1695,10 @@ struct contains_underspecified_op_proc { /** \brief Complete the model if necessary. */ -void cmd_context::complete_model() { - model_ref md; - if (!is_model_available(md) || - gparams::get_value("model.completion") != "true") +void cmd_context::complete_model(model_ref& md) const { + if (gparams::get_value("model.completion") != "true" || !md.get()) return; - get_check_sat_result()->get_model(md); - SASSERT(md.get() != 0); params_ref p; p.set_uint("max_degree", UINT_MAX); // evaluate algebraic numbers of any degree. p.set_uint("sort_store", true); @@ -1770,7 +1766,6 @@ void cmd_context::validate_model() { return; if (!is_model_available(md)) return; - get_check_sat_result()->get_model(md); SASSERT(md.get() != 0); params_ref p; p.set_uint("max_degree", UINT_MAX); // evaluate algebraic numbers of any degree. @@ -1902,6 +1897,7 @@ bool cmd_context::is_model_available(model_ref& md) const { has_manager() && (cs_state() == css_sat || cs_state() == css_unknown)) { get_check_sat_result()->get_model(md); + complete_model(md); return md.get() != 0; } return false; diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index dc85ad2e0..253384f35 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -365,7 +365,7 @@ public: void set_check_sat_result(check_sat_result * r) { m_check_sat_result = r; } check_sat_result * get_check_sat_result() const { return m_check_sat_result.get(); } check_sat_state cs_state() const; - void complete_model(); + void complete_model(model_ref& mdl) const; void validate_model(); void display_model(model_ref& mdl); diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 7a85e87a2..51220b1d0 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include "cmd_context/pdecl.h" #include "ast/datatype_decl_plugin.h" +#include using namespace format_ns; class psort_inst_cache { @@ -866,8 +867,6 @@ psort * pdecl_manager::mk_psort_cnst(sort * s) { } psort * pdecl_manager::register_psort(psort * n) { - enable_trace("register_psort"); - TRACE("register_psort", tout << "registering psort...\n"; n->display(tout); tout << "\n";); psort * r = m_table.insert_if_not_there(n); if (r != n) { del_decl_core(n); @@ -947,7 +946,6 @@ void pdecl_manager::del_decl_core(pdecl * p) { } void pdecl_manager::del_decl(pdecl * p) { -enable_trace("register_psort"); TRACE("register_psort", tout << "del psort "; p->display(tout); tout << "\n";); if (p->is_psort()) { psort * _p = static_cast(p); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index ce059a07b..7a2b4f5f4 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -347,6 +347,17 @@ namespace sat { return result; } + void model_converter::swap(bool_var v, unsigned sz, literal_vector& clause) { + for (unsigned j = 0; j < sz; ++j) { + if (v == clause[j].var()) { + std::swap(clause[0], clause[j]); + return; + } + } + IF_VERBOSE(0, verbose_stream() << "not found: v" << v << " " << clause << "\n";); + UNREACHABLE(); + } + void model_converter::expand(literal_vector& update_stack) { sat::literal_vector clause; for (entry const& e : m_entries) { @@ -357,34 +368,23 @@ namespace sat { if (l == null_literal) { elim_stack* st = e.m_elim_stack[index]; if (st) { - // clause sizes increase - elim_stackv const& stack = st->stack(); - unsigned sz = stack.size(); - for (unsigned i = 0; i < sz; ++i) { - unsigned csz = stack[i].first; - literal lit = stack[i].second; - BOOL found = false; - unsigned j = 0; - for (j = 0; j < csz; ++j) { - if (clause[j] == lit) { - std::swap(clause[j], clause[0]); - found = true; - break; - } - } - SASSERT(found); + // clause sizes increase, so we can always swap + // the blocked literal to the front from the prefix. + for (auto const& p : st->stack()) { + unsigned csz = p.first; + literal lit = p.second; + swap(lit.var(), csz, clause); update_stack.append(csz, clause.c_ptr()); update_stack.push_back(null_literal); } } + swap(e.var(), clause.size(), clause); update_stack.append(clause); update_stack.push_back(null_literal); clause.reset(); - continue; } - clause.push_back(l); - if (l.var() == e.var()) { - std::swap(clause[0], clause.back()); + else { + clause.push_back(l); } } } diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index 88fdfe5b7..be7d03188 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -94,6 +94,8 @@ namespace sat { bool legal_to_flip(bool_var v) const; + void swap(bool_var v, unsigned sz, literal_vector& clause); + public: model_converter(); ~model_converter(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b983a0da3..66e0baa89 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -231,7 +231,7 @@ namespace sat { if (bce_enabled() || abce_enabled() || bca_enabled()) { elim_blocked_clauses(); } - si.check_watches(); + if (!m_need_cleanup) si.check_watches(); if (!learned) { m_num_calls++; @@ -680,7 +680,7 @@ namespace sat { } void simplifier::elim_lit(clause & c, literal l) { - TRACE("elim_lit", tout << "processing: " << c << "\n";); + TRACE("elim_lit", tout << "processing: " << l << " @ " << c << "\n";); m_need_cleanup = true; m_num_elim_lits++; insert_elim_todo(l.var()); @@ -979,23 +979,23 @@ namespace sat { void operator()() { integrity_checker si(s.s); - si.check_watches(); + //si.check_watches(); if (s.bce_enabled()) { block_clauses(); } - si.check_watches(); + //si.check_watches(); if (s.abce_enabled()) { cce(); } - si.check_watches(); + //si.check_watches(); if (s.cce_enabled()) { cce(); } - si.check_watches(); + //si.check_watches(); if (s.bca_enabled()) { bca(); } - si.check_watches(); + //si.check_watches(); } void block_clauses() { @@ -1829,7 +1829,6 @@ namespace sat { return true; } } - return true; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0ad665c5e..03f6e6d0b 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -54,7 +54,6 @@ class inc_sat_solver : public solver { unsigned m_fmls_head; expr_ref_vector m_core; atom2bool_var m_map; - model_ref m_model; scoped_ptr m_bb_rewriter; tactic_ref m_preprocess; unsigned m_num_scopes; @@ -183,7 +182,6 @@ public: TRACE("sat", tout << _assumptions << "\n";); dep2asm_t dep2asm; - m_model = 0; lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(sz, _assumptions.c_ptr(), dep2asm); @@ -289,12 +287,6 @@ public: r.reset(); r.append(m_core.size(), m_core.c_ptr()); } - virtual void get_model_core(model_ref & mdl) { - if (!m_model.get()) { - extract_model(); - } - mdl = m_model; - } virtual proof * get_proof() { UNREACHABLE(); return 0; @@ -302,7 +294,6 @@ public: virtual expr_ref_vector cube(expr_ref_vector& vs, unsigned backtrack_level) { if (!is_internalized()) { - m_model = 0; lbool r = internalize_formulas(); if (r != l_true) return expr_ref_vector(m); } @@ -789,14 +780,14 @@ private: } } - void extract_model() { + virtual void get_model_core(model_ref & mdl) { TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); if (!m_solver.model_is_current()) { - m_model = 0; + mdl = nullptr; return; } sat::model const & ll_m = m_solver.get_model(); - model_ref md = alloc(model, m); + mdl = alloc(model, m); for (auto const& kv : m_map) { expr * n = kv.m_key; if (is_app(n) && to_app(n)->get_num_args() > 0) { @@ -805,40 +796,39 @@ private: sat::bool_var v = kv.m_value; switch (sat::value_at(v, ll_m)) { case l_true: - md->register_decl(to_app(n)->get_decl(), m.mk_true()); + mdl->register_decl(to_app(n)->get_decl(), m.mk_true()); break; case l_false: - md->register_decl(to_app(n)->get_decl(), m.mk_false()); + mdl->register_decl(to_app(n)->get_decl(), m.mk_false()); break; default: break; } } - m_model = md; - //IF_VERBOSE(0, model_v2_pp(verbose_stream(), *m_model, true);); + //IF_VERBOSE(0, model_v2_pp(verbose_stream(), *mdl, true);); if (m_sat_mc) { - // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n");); - (*m_sat_mc)(m_model); + //IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n");); + (*m_sat_mc)(mdl); } insert_const2bits(); if (m_mc0) { - // IF_VERBOSE(0, m_mc0->display(verbose_stream() << "mc0\n");); - (*m_mc0)(m_model); + //IF_VERBOSE(0, m_mc0->display(verbose_stream() << "mc0\n");); + (*m_mc0)(mdl); } - TRACE("sat", model_smt2_pp(tout, m, *m_model, 0);); + TRACE("sat", model_smt2_pp(tout, m, *mdl, 0);); + + // IF_VERBOSE(0, model_smt2_pp(verbose_stream() << "after\n", m, *mdl, 0);); - // IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "after\n");); - -#if 1 +#if 0 IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); - model_evaluator eval(*m_model); + model_evaluator eval(*mdl); for (expr * f : m_fmls) { expr_ref tmp(m); eval(f, tmp); CTRACE("sat", !m.is_true(tmp), tout << "Evaluation failed: " << mk_pp(f, m) << " to " << mk_pp(f, m) << "\n"; - model_smt2_pp(tout, m, *(m_model.get()), 0);); + model_smt2_pp(tout, m, *(mdl.get()), 0);); if (!m.is_true(tmp)) { IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n";); IF_VERBOSE(0, verbose_stream() << m_params << "\n";); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 139355d5f..485682858 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -38,6 +38,7 @@ void generic_model_converter::add(func_decl * d, expr* e) { void generic_model_converter::operator()(model_ref & md) { TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout);); + // IF_VERBOSE(0, verbose_stream() << "Apply converter " << m_orig << "\n";); model_evaluator ev(*(md.get())); ev.set_model_completion(true); ev.set_expand_array_equalities(false); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index ee6630fd3..7d198468c 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -152,14 +152,14 @@ public: virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { - model_converter_ref mc = bounded_model_converter(); + model_converter_ref mc = local_model_converter(); if (mc) (*mc)(mdl); } } model_converter* external_model_converter() const { - return concat(mc0(), bounded_model_converter()); + return concat(mc0(), local_model_converter()); } - model_converter* bounded_model_converter() const { + model_converter* local_model_converter() const { if (m_int2bv.empty() && m_bv_fns.empty()) return nullptr; generic_model_converter* mc = alloc(generic_model_converter, m, "bounded_int2bv"); for (func_decl* f : m_bv_fns) @@ -178,7 +178,7 @@ public: } virtual model_converter_ref get_model_converter() const { - model_converter_ref mc = concat(mc0(), bounded_model_converter()); + model_converter_ref mc = external_model_converter(); mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 9567f369f..527d9aeb3 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -92,11 +92,11 @@ public: virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { - model_converter_ref mc = enum_model_converter(); + model_converter_ref mc = local_model_converter(); if (mc) (*mc)(mdl); } } - model_converter* enum_model_converter() const { + model_converter* local_model_converter() const { if (m_rewriter.enum2def().empty() && m_rewriter.enum2bv().empty()) { return nullptr; @@ -110,7 +110,7 @@ public: } model_converter* external_model_converter() const { - return concat(mc0(), enum_model_converter()); + return concat(mc0(), local_model_converter()); } virtual model_converter_ref get_model_converter() const { diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 6660e1bb4..14e58a637 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -91,14 +91,15 @@ public: virtual void get_model_core(model_ref & mdl) { m_solver->get_model(mdl); if (mdl) { - filter_model(mdl); + model_converter_ref mc = local_model_converter(); + if (mc) (*mc)(mdl); } } model_converter* external_model_converter() const { - return concat(mc0(), filter_model_converter()); + return concat(mc0(), local_model_converter()); } virtual model_converter_ref get_model_converter() const { - model_converter_ref mc = concat(mc0(), filter_model_converter()); + model_converter_ref mc = external_model_converter(); mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; } @@ -113,7 +114,7 @@ public: flush_assertions(); return m_solver->get_consequences(asms, vars, consequences); } - model_converter* filter_model_converter() const { + model_converter* local_model_converter() const { if (m_rewriter.fresh_constants().empty()) { return nullptr; } @@ -125,13 +126,6 @@ public: return filter; } - void filter_model(model_ref& mdl) { - model_converter_ref mc = filter_model_converter(); - if (mc.get()) { - (*mc)(mdl); - } - } - virtual unsigned get_num_assertions() const { flush_assertions(); return m_solver->get_num_assertions(); From 3b1810d8933cc35f903fa2a358673f53a1b0ccec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 21 Jan 2018 23:18:41 -0800 Subject: [PATCH 0483/1283] fix hidden tautology bug on non-learned clauses Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 4 +--- src/sat/sat_elim_vars.cpp | 3 ++- src/sat/sat_model_converter.cpp | 9 +-------- src/sat/sat_model_converter.h | 10 ++++++++++ src/sat/sat_simplifier.cpp | 2 ++ src/sat/sat_solver.cpp | 4 +++- src/sat/tactic/goal2sat.cpp | 3 +++ 7 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index ee8e9db88..dfe94c5f4 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -399,13 +399,11 @@ namespace sat { bool asymm_branch::process_sampled(big& big, clause & c) { scoped_detach scoped_d(s, c); sort(big, c); -#if 1 - if (uhte(big, c)) { + if (c.is_learned() && uhte(big, c)) { ++m_hidden_tautologies; scoped_d.del_clause(); return false; } -#endif return uhle(scoped_d, big, c); } diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index f04318a5d..a2e6b445b 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -88,6 +88,7 @@ namespace sat{ simp.collect_clauses(pos_l, simp.m_pos_cls); simp.collect_clauses(neg_l, simp.m_neg_cls); VERIFY(!simp.is_external(v)); + model_converter::entry & mc_entry = s.m_mc.mk(model_converter::ELIM_VAR, v); simp.save_clauses(mc_entry, simp.m_pos_cls); simp.save_clauses(mc_entry, simp.m_neg_cls); @@ -100,7 +101,7 @@ namespace sat{ pos_occs.reset(); neg_occs.reset(); literal_vector lits; - add_clauses(b, lits); + add_clauses(b, lits); return true; } diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 7a2b4f5f4..9bda5cf3d 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -275,14 +275,7 @@ namespace sat { } std::ostream& model_converter::display(std::ostream& out, entry const& entry) const { - out << " ("; - switch (entry.get_kind()) { - case ELIM_VAR: out << "elim"; break; - case BLOCK_LIT: out << "blocked"; break; - case CCE: out << "cce"; break; - case ACCE: out << "acce"; break; - } - out << " " << entry.var(); + out << " (" << entry.get_kind() << " " << entry.var(); bool start = true; unsigned index = 0; for (literal l : entry.m_clauses) { diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index be7d03188..bc60844ca 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -134,6 +134,16 @@ namespace sat { void expand(literal_vector& update_stack); }; + inline std::ostream& operator<<(std::ostream& out, model_converter::kind k) { + switch (k) { + case model_converter::ELIM_VAR: out << "elim"; break; + case model_converter::BLOCK_LIT: out << "blocked"; break; + case model_converter::CCE: out << "cce"; break; + case model_converter::ACCE: out << "acce"; break; + } + return out; + } + }; #endif diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 66e0baa89..de59966e6 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1818,6 +1818,7 @@ namespace sat { if (s.m_config.m_drat) s.m_drat.add(*new_c, true); s.m_clauses.push_back(new_c); + m_use_list.insert(*new_c); if (m_sub_counter > 0) back_subsumption1(*new_c); @@ -1829,6 +1830,7 @@ namespace sat { return true; } } + return true; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 61e05b3ed..2dd459372 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3225,7 +3225,9 @@ namespace sat { literal l2 = w.get_literal(); if (l.index() > l2.index()) continue; - out << "(" << l << " " << l2 << ")\n"; + out << "(" << l << " " << l2 << ")"; + if (w.is_learned()) out << "*"; + out << "\n"; } } } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 9dbfaea57..a7b2eb582 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -142,6 +142,7 @@ struct goal2sat::imp { sat::bool_var v = m_solver.mk_var(ext); m_map.insert(t, v); l = sat::literal(v, sign); + // if (to_app(t)->get_decl()->get_name() == "XX") IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(t, m) << ": " << "v" << v << "\n";); TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";); if (ext && !is_uninterp_const(t)) { m_interpreted_atoms.push_back(t); @@ -1025,6 +1026,7 @@ void sat2goal::mc::insert(sat::bool_var v, app * atom, bool aux) { expr_ref sat2goal::mc::lit2expr(sat::literal l) { if (!m_var2expr.get(l.var())) { app* aux = m.mk_fresh_const(0, m.mk_bool_sort()); + // if (aux->get_decl()->get_name() == "k!81740") IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(aux, m) << ": " << "v" << l.var() << "\n";); m_var2expr.set(l.var(), aux); } VERIFY(m_var2expr.get(l.var())); @@ -1067,6 +1069,7 @@ struct sat2goal::imp { app* aux = mc ? mc->var2expr(l.var()) : nullptr; if (!aux) { aux = m.mk_fresh_const(0, m.mk_bool_sort()); + // if (aux->get_decl()->get_name() == "k!81740") IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(aux, m) << ": " << "v" << l.var() << "\n";); if (mc) mc->insert(l.var(), aux, true); } From d648f95f633626ac66b29c9ff1322ca995065e5d Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 24 Jan 2018 21:25:45 -0500 Subject: [PATCH 0484/1283] fix setup of path constraints when the path constraint is False --- src/smt/theory_str.cpp | 49 +++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 933796d9c..680500229 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9904,21 +9904,44 @@ namespace smt { } lhs_terms.push_back(ctx.mk_eq_atom(mk_strlen(str), m_autil.mk_numeral(exact_length_value, true))); expr_ref lhs(mk_and(lhs_terms), m); - // If the automaton was built with the same polarity as the constraint, - // assert directly. Otherwise, negate the path constraint - if ( (current_assignment == l_true && assumption.get_polarity()) - || (current_assignment == l_false && !assumption.get_polarity())) { - TRACE("str", tout << "automaton and regex term have same polarity" << std::endl;); - expr_ref rhs(m.mk_and(pathConstraint, characterConstraints), m); - assert_implication(lhs, rhs); + + // If the path constraint comes out as "false", this means there are no paths of that length + // in the automaton. If the polarity is the same, we can assert a conflict clause. + // If the polarity is opposite, we ignore the path constraint. + + if (m.is_false(pathConstraint)) { + if ( (current_assignment == l_true && assumption.get_polarity()) + || (current_assignment == l_false && !assumption.get_polarity())) { + // automaton and constraint have same polarity -- assert conflict clause + TRACE("str", tout << "path constraint is false with matching polarity; asserting conflict clause" << std::endl;); + expr_ref conflict(m.mk_not(mk_and(lhs_terms)), m); + assert_axiom(conflict); + // don't set up "regex_terms_with_path_constraints" as a conflict clause is not a path constraint + } else { + // automaton and constraint have opposite polarity -- ignore path constraint + TRACE("str", tout << "path constraint is false with opposite polarity; ignoring path constraint" << std::endl;); + assert_implication(lhs, characterConstraints); + regex_terms_with_path_constraints.insert(str_in_re); + m_trail_stack.push(insert_obj_trail(regex_terms_with_path_constraints, str_in_re)); + } + regex_axiom_add = true; } else { - TRACE("str", tout << "automaton and regex term have opposite polarity" << std::endl;); - expr_ref rhs(m.mk_and(m.mk_not(pathConstraint), characterConstraints), m); - assert_implication(lhs, rhs); + // If the automaton was built with the same polarity as the constraint, + // assert directly. Otherwise, negate the path constraint + if ( (current_assignment == l_true && assumption.get_polarity()) + || (current_assignment == l_false && !assumption.get_polarity())) { + TRACE("str", tout << "automaton and regex term have same polarity" << std::endl;); + expr_ref rhs(m.mk_and(pathConstraint, characterConstraints), m); + assert_implication(lhs, rhs); + } else { + TRACE("str", tout << "automaton and regex term have opposite polarity" << std::endl;); + expr_ref rhs(m.mk_and(m.mk_not(pathConstraint), characterConstraints), m); + assert_implication(lhs, rhs); + } + regex_terms_with_path_constraints.insert(str_in_re); + m_trail_stack.push(insert_obj_trail(regex_terms_with_path_constraints, str_in_re)); + regex_axiom_add = true; } - regex_terms_with_path_constraints.insert(str_in_re); - m_trail_stack.push(insert_obj_trail(regex_terms_with_path_constraints, str_in_re)); - regex_axiom_add = true; // increment LengthAttemptCount regex_inc_counter(regex_length_attempt_count, re); From 8d5065d35d310b0b2e1d1950797c983df4f4f8a4 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 24 Jan 2018 22:02:00 -0500 Subject: [PATCH 0485/1283] fix constant eqc bug in mk_concat --- src/smt/theory_str.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 680500229..a9eac7dd4 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -709,6 +709,12 @@ namespace smt { bool n2HasEqcValue = false; expr * v1 = get_eqc_value(n1, n1HasEqcValue); expr * v2 = get_eqc_value(n2, n2HasEqcValue); + if (u.str.is_string(v1)) { + n1HasEqcValue = true; + } + if (u.str.is_string(v2)) { + n2HasEqcValue = true; + } if (n1HasEqcValue && n2HasEqcValue) { zstring n1_str; u.str.is_string(v1, n1_str); From 305212c021a0b43961076f182c05a3f3075aa77a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 25 Jan 2018 15:18:05 +0000 Subject: [PATCH 0486/1283] Added rewrite cycle detection in demodulator/ufbv_rewriter. Partial fix for #1456. --- src/tactic/ufbv/ufbv_rewriter.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/tactic/ufbv/ufbv_rewriter.cpp index 446d1a49c..573873c89 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/tactic/ufbv/ufbv_rewriter.cpp @@ -322,8 +322,27 @@ bool ufbv_rewriter::rewrite_visit_children(app * a) { while (j > 0) { expr * e = a->get_arg(--j); if (!m_rewrite_cache.contains(e) || !m_rewrite_cache.get(e).second) { - m_rewrite_todo.push_back(e); - res = false; + bool recursive = false; + unsigned sz = m_rewrite_todo.size(); + expr * v = e; + if (m_rewrite_cache.contains(e)) { + expr_bool_pair const & ebp = m_rewrite_cache.get(e); + if (ebp.second) + v = ebp.first; + } + for (unsigned i = sz; i > 0; i--) { + if (m_rewrite_todo[i - 1] == v) { + recursive = true; + TRACE("demodulator", tout << "Detected demodulator cycle: " << + mk_pp(a, m_manager) << " --> " << mk_pp(v, m_manager) << std::endl;); + m_rewrite_cache.insert(e, expr_bool_pair(v, true)); + break; + } + } + if (!recursive) { + m_rewrite_todo.push_back(e); + res = false; + } } } return res; @@ -347,7 +366,8 @@ expr * ufbv_rewriter::rewrite(expr * n) { while (!m_rewrite_todo.empty()) { TRACE("demodulator_stack", tout << "STACK: " << std::endl; for ( unsigned i = 0; i Date: Thu, 25 Jan 2018 15:52:57 -0500 Subject: [PATCH 0488/1283] always rewrite regex length constraints as they are sometimes malformed --- src/smt/theory_str.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index d30d406b2..9de0375b9 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9787,7 +9787,10 @@ namespace smt { } else { // generate new length constraint expr_ref_vector extra_length_vars(m); - expr_ref top_level_length_constraint = infer_all_regex_lengths(mk_strlen(str), re, extra_length_vars); + expr_ref _top_level_length_constraint = infer_all_regex_lengths(mk_strlen(str), re, extra_length_vars); + expr_ref top_level_length_constraint(_top_level_length_constraint, m); + th_rewriter rw(m); + rw(top_level_length_constraint); TRACE("str", tout << "top-level length constraint: " << mk_pp(top_level_length_constraint, m) << std::endl;); // assert and track length constraint assert_axiom(top_level_length_constraint); From c01dda4e313f3fd72a5fa8453e112be6a79ad3ef Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 25 Jan 2018 16:11:31 -0500 Subject: [PATCH 0489/1283] experimental str.to.int fix --- src/smt/theory_str.cpp | 50 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 9de0375b9..2cbade1d5 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -9371,7 +9371,7 @@ namespace smt { bool Ival_exists = get_arith_value(a, Ival); if (Ival_exists) { TRACE("str", tout << "integer theory assigns " << mk_pp(a, m) << " = " << Ival.to_string() << std::endl;); - // if that value is not -1, we can assert (str.to-int S) = Ival --> S = "Ival" + // if that value is not -1, we can assert (str.to.int S) = Ival --> S = "Ival" if (!Ival.is_minus_one()) { zstring Ival_str(Ival.to_string().c_str()); expr_ref premise(ctx.mk_eq_atom(a, m_autil.mk_numeral(Ival, true)), m); @@ -9393,6 +9393,54 @@ namespace smt { // NOT_IMPLEMENTED_YET(); } + bool S_hasEqcValue; + expr * S_str = get_eqc_value(S, S_hasEqcValue); + if (S_hasEqcValue) { + zstring str; + u.str.is_string(S_str, str); + bool valid = true; + rational convertedRepresentation(0); + rational ten(10); + if (str.length() == 0) { + valid = false; + } else { + for (unsigned i = 0; i < str.length(); ++i) { + if (!('0' <= str[i] && str[i] <= '9')) { + valid = false; + break; + } else { + // accumulate + char digit = (int)str[i]; + std::string sDigit(1, digit); + int val = atoi(sDigit.c_str()); + convertedRepresentation = (ten * convertedRepresentation) + rational(val); + } + } + } + // TODO this duplicates code a bit, we can simplify the branch on "conclusion" only + if (valid) { + expr_ref premise(ctx.mk_eq_atom(S, mk_string(str)), m); + expr_ref conclusion(ctx.mk_eq_atom(a, m_autil.mk_numeral(convertedRepresentation, true)), m); + expr_ref axiom(rewrite_implication(premise, conclusion), m); + if (!string_int_axioms.contains(axiom)) { + string_int_axioms.insert(axiom); + assert_axiom(axiom); + m_trail_stack.push(insert_obj_trail(string_int_axioms, axiom)); + axiomAdd = true; + } + } else { + expr_ref premise(ctx.mk_eq_atom(S, mk_string(str)), m); + expr_ref conclusion(ctx.mk_eq_atom(a, m_autil.mk_numeral(rational::minus_one(), true)), m); + expr_ref axiom(rewrite_implication(premise, conclusion), m); + if (!string_int_axioms.contains(axiom)) { + string_int_axioms.insert(axiom); + assert_axiom(axiom); + m_trail_stack.push(insert_obj_trail(string_int_axioms, axiom)); + axiomAdd = true; + } + } + } + return axiomAdd; } From fddc4e311f4a407e771b0b3b20d92e49b1658ee6 Mon Sep 17 00:00:00 2001 From: Virgile ROBLES Date: Fri, 26 Jan 2018 00:30:59 +0100 Subject: [PATCH 0490/1283] Fix encoding error The encode/decode is not needed and fails if any non-ASCII character is returned by g++ or clang++ --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 03256125c..3a719d322 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -889,7 +889,7 @@ def is_CXX_gpp(): return is_compiler(CXX, 'g++') def is_clang_in_gpp_form(cc): - version_string = check_output([cc, '--version']).encode('utf-8').decode('utf-8') + version_string = check_output([cc, '--version']) return version_string.find('clang') != -1 def is_CXX_clangpp(): From 1ee5ce96b8745ec9fa1ea37e2a0dbb2482a373dc Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Fri, 26 Jan 2018 14:52:18 -0500 Subject: [PATCH 0491/1283] use regex instead of head/tail split for string-integer conversion; check sort of refreshed vars; add intersection difficulty estimation --- src/smt/theory_str.cpp | 26 +++++++++++++++++--------- src/smt/theory_str.h | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 2cbade1d5..5bc0590e6 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -287,10 +287,13 @@ namespace smt { } void theory_str::refresh_theory_var(expr * e) { + ast_manager & m = get_manager(); enode * en = ensure_enode(e); theory_var v = mk_var(en); (void)v; TRACE("str", tout << "refresh " << mk_pp(e, get_manager()) << ": v#" << v << std::endl;); - m_basicstr_axiom_todo.push_back(en); + if (m.get_sort(e) == u.str.mk_string_sort()) { + m_basicstr_axiom_todo.push_back(en); + } } theory_var theory_str::mk_var(enode* n) { @@ -1628,12 +1631,11 @@ namespace smt { { expr_ref premise(m_autil.mk_ge(ex, m_autil.mk_numeral(rational::one(), true)), m); - expr_ref hd(mk_str_var("hd"), m); - expr_ref tl(mk_str_var("tl"), m); - expr_ref conclusion1(ctx.mk_eq_atom(S, mk_concat(hd, tl)), m); - expr_ref conclusion2(ctx.mk_eq_atom(mk_strlen(hd), m_autil.mk_numeral(rational::one(), true)), m); - expr_ref conclusion3(mk_not(m, ctx.mk_eq_atom(hd, mk_string("0"))), m); - expr_ref conclusion(m.mk_and(conclusion1, conclusion2, conclusion3), m); + // S >= 1 --> S in [1-9][0-9]* + expr_ref re_positiveInteger(u.re.mk_concat( + u.re.mk_range(mk_string("1"), mk_string("9")), + u.re.mk_star(u.re.mk_range(mk_string("0"), mk_string("9")))), m); + expr_ref conclusion(mk_RegexIn(S, re_positiveInteger), m); SASSERT(premise); SASSERT(conclusion); assert_implication(premise, conclusion); @@ -6614,6 +6616,12 @@ namespace smt { } } + unsigned theory_str::estimate_automata_intersection_difficulty(eautomaton * aut1, eautomaton * aut2) { + ENSURE(aut1 != NULL); + ENSURE(aut2 != NULL); + return _qmul(aut1->num_states(), aut2->num_states()); + } + // Check whether a regex translates well to a linear set of length constraints. bool theory_str::check_regex_length_linearity(expr * re) { return check_regex_length_linearity_helper(re, false); @@ -10291,7 +10299,6 @@ namespace smt { } else { // TODO check negation? // TODO construct a partial automaton for R to the given lower bound? - // TODO increment failure count if (false) { } else { @@ -10424,7 +10431,8 @@ namespace smt { } if (regex_get_counter(regex_length_attempt_count, aut.get_regex_term()) >= m_params.m_RegexAutomata_LengthAttemptThreshold) { - unsigned intersectionDifficulty = 0; // TODO EstimateIntersectionDifficulty + unsigned intersectionDifficulty = estimate_automata_intersection_difficulty(aut_inter, aut.get_automaton()); + TRACE("str", tout << "intersection difficulty is " << intersectionDifficulty << std::endl;); if (intersectionDifficulty <= m_params.m_RegexAutomata_IntersectionDifficultyThreshold || regex_get_counter(regex_intersection_fail_count, aut.get_regex_term()) >= m_params.m_RegexAutomata_FailedIntersectionThreshold) { diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index ea4449b13..1330f9904 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -555,6 +555,7 @@ protected: // regex automata and length-aware regex unsigned estimate_regex_complexity(expr * re); unsigned estimate_regex_complexity_under_complement(expr * re); + unsigned estimate_automata_intersection_difficulty(eautomaton * aut1, eautomaton * aut2); bool check_regex_length_linearity(expr * re); bool check_regex_length_linearity_helper(expr * re, bool already_star); expr_ref infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables); From e4198c38e2184432ce6f38967749fea4a05e75b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 28 Jan 2018 11:45:39 -0800 Subject: [PATCH 0492/1283] add solution_prefix per #1463, have parto with single objective behave similar to multipe-objectives #1439 Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 1 + src/opt/maxsmt.cpp | 6 +++++- src/opt/maxsmt.h | 1 + src/opt/opt_context.cpp | 19 ++++++++++++++++++- src/opt/opt_context.h | 6 +++++- src/opt/opt_params.pyg | 1 + 6 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index b06773223..9d32d48e3 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -727,6 +727,7 @@ public: } m_model = mdl; + m_c.model_updated(mdl); for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 8df6c04a6..6df375240 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -155,7 +155,7 @@ namespace opt { rational l = m_adjust_value(m_lower); rational u = m_adjust_value(m_upper); if (l > u) std::swap(l, u); - verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); + verbose_stream() << "(opt." << solver << " [" << l << ":" << u << "])\n";); } lbool maxsmt_solver_base::find_mutexes(obj_map& new_soft) { @@ -391,6 +391,10 @@ namespace opt { return m_c.get_solver(); } + void maxsmt::model_updated(model* mdl) { + m_c.model_updated(mdl); + } + }; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 0541a9a88..7b4be9842 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -147,6 +147,7 @@ namespace opt { bool get_assignment(unsigned index) const; void display_answer(std::ostream& out) const; void collect_statistics(statistics& st) const; + void model_updated(model* mdl); private: bool is_maxsat_problem(weights_t& ws) const; void verify_assignment(); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 4ccf30563..743ab20d9 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -138,6 +138,7 @@ namespace opt { p.set_bool("unsat_core", true); p.set_bool("elim_to_real", true); updt_params(p); + m_model_counter = 0; } context::~context() { @@ -1007,6 +1008,22 @@ namespace opt { } } + void context::model_updated(model* md) { + opt_params optp(m_params); + symbol prefix = optp.solution_prefix(); + if (prefix == symbol::null) return; + model_ref mdl = md->copy(); + fix_model(mdl); + std::ostringstream buffer; + buffer << prefix << (m_model_counter++) << ".smt2"; + std::ofstream out(buffer.str()); + if (out) { + model_smt2_pp(out, m, *mdl, 0); + out.close(); + } + } + + bool context::verify_model(unsigned index, model* md, rational const& _v) { rational r; app_ref term = m_objectives[index].m_term; @@ -1015,7 +1032,7 @@ namespace opt { } rational v = m_objectives[index].m_adjust_value(_v); expr_ref val(m); - model_ref mdl = md; + model_ref mdl = md->copy(); fix_model(mdl); if (!mdl->eval(term, val)) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 513f2dd85..372c6672c 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -57,6 +57,7 @@ namespace opt { virtual unsigned num_objectives() = 0; virtual bool verify_model(unsigned id, model* mdl, rational const& v) = 0; virtual void set_model(model_ref& _m) = 0; + virtual void model_updated(model* mdl) = 0; }; /** @@ -154,9 +155,10 @@ namespace opt { map_t m_maxsmts; scoped_state m_scoped_state; vector m_objectives; - model_ref m_model; + model_ref m_model; model_converter_ref m_model_converter; filter_model_converter m_fm; + unsigned m_model_counter; obj_map m_objective_fns; obj_map m_objective_orig; func_decl_ref_vector m_objective_refs; @@ -231,6 +233,8 @@ namespace opt { virtual bool verify_model(unsigned id, model* mdl, rational const& v); + + virtual void model_updated(model* mdl); private: lbool execute(objective const& obj, bool committed, bool scoped); diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index cfcc5e47e..09d849e1a 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -5,6 +5,7 @@ def_module_params('opt', ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), + ('solution_prefix', SYMBOL, None, "path prefix to dump intermediary, but non-optimal, solutions"), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), From 2f6c80ef086161331dfc1aefe762f380ed1afd54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 28 Jan 2018 12:06:14 -0800 Subject: [PATCH 0493/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/sat/sat_model_converter.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 1a3b4104f..4882018bb 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -43,10 +43,7 @@ namespace sat { // and the following procedure flips its value. bool sat = false; bool var_sign = false; - literal_vector::const_iterator it2 = it->m_clauses.begin(); - literal_vector::const_iterator end2 = it->m_clauses.end(); - for (; it2 != end2; ++it2) { - literal l = *it2; + for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause if (!sat) { @@ -74,7 +71,7 @@ namespace sat { DEBUG_CODE({ // all clauses must be satisfied bool sat = false; - for (literal l : m_clauses) { + for (literal l : it->m_clauses) { if (l == null_literal) { SASSERT(sat); sat = false; From 5a16d3ef7ff477cebea9593c067cf01c7ccbfda1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Jan 2018 19:14:17 -0800 Subject: [PATCH 0494/1283] fix license in sstream Signed-off-by: Nikolaj Bjorner --- src/util/sstream.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/util/sstream.h b/src/util/sstream.h index 23d5bdfbb..fba13c5d5 100644 --- a/src/util/sstream.h +++ b/src/util/sstream.h @@ -1,10 +1,20 @@ - - /* -Copyright (c) 2013 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + nat_set.h + +Abstract: + + Wrapper for sstream. + +Author: + + Leonardo de Moura (leonardo) 2013 + +Revision History: -Author: Leonardo de Moura */ #pragma once #include From 5a2b072ddf781e9b1205935e4a68ff3ed166441e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Jan 2018 20:32:06 -0800 Subject: [PATCH 0495/1283] working on completing ATE/ALA for acce and abce Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 15 +- src/sat/ba_solver.h | 5 +- src/sat/sat_asymm_branch.cpp | 63 +++++-- src/sat/sat_asymm_branch.h | 8 +- src/sat/sat_asymm_branch_params.pyg | 2 +- src/sat/sat_big.cpp | 47 ++++- src/sat/sat_big.h | 19 +- src/sat/sat_clause.cpp | 2 - src/sat/sat_clause.h | 15 +- src/sat/sat_clause_use_list.cpp | 8 +- src/sat/sat_clause_use_list.h | 30 +-- src/sat/sat_cleaner.cpp | 3 +- src/sat/sat_config.cpp | 4 +- src/sat/sat_elim_vars.cpp | 14 +- src/sat/sat_extension.h | 2 +- src/sat/sat_iff3_finder.cpp | 2 +- src/sat/sat_integrity_checker.cpp | 12 +- src/sat/sat_lookahead.cpp | 35 ++-- src/sat/sat_lookahead.h | 6 +- src/sat/sat_params.pyg | 4 +- src/sat/sat_scc.cpp | 38 +--- src/sat/sat_scc.h | 8 +- src/sat/sat_scc_params.pyg | 2 +- src/sat/sat_simplifier.cpp | 282 +++++++++++++++++++++------- src/sat/sat_simplifier.h | 2 + src/sat/sat_simplifier_params.pyg | 2 +- src/sat/sat_solver.cpp | 52 +++-- src/sat/sat_solver.h | 1 + src/sat/sat_watched.h | 13 +- 29 files changed, 466 insertions(+), 230 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index d29f81fca..55a7713ce 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -3282,21 +3282,26 @@ namespace sat { extension* ba_solver::copy(solver* s) { ba_solver* result = alloc(ba_solver); result->set_solver(s); - copy_core(result); + copy_core(result, false); return result; } - extension* ba_solver::copy(lookahead* s) { + extension* ba_solver::copy(lookahead* s, bool learned) { ba_solver* result = alloc(ba_solver); result->set_lookahead(s); - copy_core(result); + copy_core(result, learned); return result; } - void ba_solver::copy_core(ba_solver* result) { + void ba_solver::copy_core(ba_solver* result, bool learned) { + copy_constraints(result, m_constraints); + if (learned) copy_constraints(result, m_learned); + } + + void ba_solver::copy_constraints(ba_solver* result, ptr_vector const& constraints) { literal_vector lits; svector wlits; - for (constraint* cp : m_constraints) { + for (constraint* cp : constraints) { switch (cp->tag()) { case card_t: { card const& c = cp->to_card(); diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 6e5c00e38..d950cb8cc 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -462,7 +462,8 @@ namespace sat { constraint* add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); constraint* add_xor(literal_vector const& lits, bool learned); - void copy_core(ba_solver* result); + void copy_core(ba_solver* result, bool learned); + void copy_constraints(ba_solver* result, ptr_vector const& constraints); public: ba_solver(); virtual ~ba_solver(); @@ -489,7 +490,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); - virtual extension* copy(lookahead* s); + virtual extension* copy(lookahead* s, bool learned); virtual void find_mutexes(literal_vector& lits, vector & mutexes); virtual void pop_reinit(); virtual void gc(); diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index dfe94c5f4..1b37e4dbc 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -67,22 +67,28 @@ namespace sat { } }; - bool asymm_branch::process(big* big) { + void asymm_branch::process_bin(big& big) { + unsigned elim = big.reduce_tr(s); + m_hidden_tautologies += elim; + } + + bool asymm_branch::process(big& big, bool learned) { unsigned elim0 = m_elim_literals; unsigned eliml0 = m_elim_learned_literals; for (unsigned i = 0; i < m_asymm_branch_rounds; ++i) { - unsigned elim = m_elim_literals; - if (big) big->init_big(s, true); - process(big, s.m_clauses); - if (big) process(big, s.m_learned); + unsigned elim = m_elim_literals + m_hidden_tautologies; + big.init(s, learned); + process(&big, s.m_clauses); + process(&big, s.m_learned); + process_bin(big); s.propagate(false); if (s.m_inconsistent) break; - unsigned num_elim = m_elim_literals - elim; + unsigned num_elim = m_elim_literals + m_hidden_tautologies - elim; IF_VERBOSE(1, verbose_stream() << "(sat-asymm-branch-step :elim " << num_elim << ")\n";); if (num_elim == 0) break; - if (num_elim > 1000) + if (num_elim > 100) i = 0; } IF_VERBOSE(1, if (m_elim_learned_literals > eliml0) @@ -90,6 +96,16 @@ namespace sat { return m_elim_literals > elim0; } + bool asymm_branch::process(bool learned) { + unsigned eliml0 = m_elim_learned_literals; + unsigned elim = m_elim_literals; + process(nullptr, s.m_clauses); + s.propagate(false); + IF_VERBOSE(1, if (m_elim_learned_literals > eliml0) + verbose_stream() << "(sat-asymm-branch :elim " << m_elim_learned_literals - eliml0 << ")\n";); + return m_elim_literals > elim; + } + void asymm_branch::process(big* big, clause_vector& clauses) { int64 limit = -m_asymm_branch_limit; @@ -138,10 +154,22 @@ namespace sat { s.propagate(false); if (s.m_inconsistent) return; - report rpt(*this); - svector saved_phase(s.m_phase); - process(&big); - s.m_phase = saved_phase; + report rpt(*this); + + for (unsigned i = 0; i < m_asymm_branch_rounds; ++i) { + unsigned elim = m_elim_literals; + big.reinit(); + process(&big, s.m_clauses); + process(&big, s.m_learned); + process_bin(big); + unsigned num_elim = m_elim_literals - elim; + IF_VERBOSE(1, verbose_stream() << "(sat-asymm-branch-step :elim " << num_elim << ")\n";); + if (num_elim == 0) + break; + if (num_elim > 1000) + i = 0; + } + s.propagate(false); } void asymm_branch::operator()(bool force) { @@ -168,12 +196,16 @@ namespace sat { ++counter; change = false; if (m_asymm_branch_sampled) { - big big; - if (process(&big)) change = true; + big big(s.m_rand, true); + if (process(big, true)) change = true; + } + if (m_asymm_branch_sampled) { + big big(s.m_rand, false); + if (process(big, false)) change = true; } if (m_asymm_branch) { m_counter = 0; - if (process(nullptr)) change = true; + if (process(true)) change = true; m_counter = -m_counter; } } @@ -399,7 +431,7 @@ namespace sat { bool asymm_branch::process_sampled(big& big, clause & c) { scoped_detach scoped_d(s, c); sort(big, c); - if (c.is_learned() && uhte(big, c)) { + if ((c.is_learned() || !big.learned()) && uhte(big, c)) { ++m_hidden_tautologies; scoped_d.del_clause(); return false; @@ -408,7 +440,6 @@ namespace sat { } bool asymm_branch::process(clause & c) { - if (c.is_blocked()) return true; TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";); SASSERT(s.scope_lvl() == 0); SASSERT(s.m_qhead == s.m_trail.size()); diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 226684c85..fb8048c37 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -66,7 +66,9 @@ namespace sat { bool re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz); - bool process(big* big); + bool process(bool learned); + + bool process(big& big, bool learned); bool process(clause & c); @@ -75,6 +77,8 @@ namespace sat { void process(big* big, clause_vector & c); bool process_all(clause & c); + + void process_bin(big& big); bool flip_literal_at(clause const& c, unsigned flip_index, unsigned& new_sz); @@ -85,7 +89,7 @@ namespace sat { public: asymm_branch(solver & s, params_ref const & p); - void operator()(bool force = false); + void operator()(bool force); void operator()(big& big); diff --git a/src/sat/sat_asymm_branch_params.pyg b/src/sat/sat_asymm_branch_params.pyg index 0fd19d500..b04b5ff01 100644 --- a/src/sat/sat_asymm_branch_params.pyg +++ b/src/sat/sat_asymm_branch_params.pyg @@ -4,6 +4,6 @@ def_module_params(module_name='sat', params=(('asymm_branch', BOOL, True, 'asymmetric branching'), ('asymm_branch.rounds', UINT, 10, 'maximal number of rounds to run asymmetric branch simplifications if progress is made'), ('asymm_branch.delay', UINT, 1, 'number of simplification rounds to wait until invoking asymmetric branch simplification'), - ('asymm_branch.sampled', BOOL, False, 'use sampling based asymmetric branching based on binary implication graph'), + ('asymm_branch.sampled', BOOL, True, 'use sampling based asymmetric branching based on binary implication graph'), ('asymm_branch.limit', UINT, 100000000, 'approx. maximum number of literals visited during asymmetric branching'), ('asymm_branch.all', BOOL, False, 'asymmetric branching on all literals per clause'))) diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 5b32911f1..b35930e96 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -21,10 +21,13 @@ Revision History: namespace sat { - big::big() {} + big::big(random_gen& rand, bool binary): + m_rand(rand) { + m_binary = binary; + } - void big::init_big(solver& s, bool learned) { - init_adding_edges(s.num_vars()); + void big::init(solver& s, bool learned) { + init_adding_edges(s.num_vars(), learned); unsigned num_lits = m_num_vars * 2; literal_vector lits; SASSERT(num_lits == m_dag.size() && num_lits == m_roots.size()); @@ -44,7 +47,12 @@ namespace sat { done_adding_edges(); } - void big::init_adding_edges(unsigned num_vars) { + void big::reinit() { + done_adding_edges(); + } + + void big::init_adding_edges(unsigned num_vars, bool learned) { + m_learned = learned; m_num_vars = num_vars; unsigned num_lits = m_num_vars * 2; m_dag.reset(); @@ -129,9 +137,36 @@ namespace sat { m_right[i] = ++dfs_num; } } - for (unsigned i = 0; i < num_lits; ++i) { - VERIFY(m_left[i] < m_right[i]); + DEBUG_CODE(for (unsigned i = 0; i < num_lits; ++i) { VERIFY(m_left[i] < m_right[i]);}); + } + + unsigned big::reduce_tr(solver& s) { + if (!m_binary && learned()) return 0; + unsigned num_lits = s.num_vars() * 2; + unsigned idx = 0; + unsigned elim = 0; + for (watch_list & wlist : s.m_watches) { + literal u = to_literal(idx++); + watch_list::iterator it = wlist.begin(); + watch_list::iterator itprev = it; + watch_list::iterator end = wlist.end(); + for (; it != end; ++it) { + watched& w = *it; + if (learned() ? w.is_binary_learned_clause() : w.is_binary_clause()) { + literal v = w.get_literal(); + if (reaches(u, v) && u != get_parent(v)) { + ++elim; + // could turn non-learned non-binary tautology into learned binary. + s.get_wlist(~v).erase(watched(~u, w.is_learned())); + continue; + } + } + *itprev = *it; + itprev++; + } + wlist.set_end(itprev); } + return elim; } void big::display(std::ostream& out) const { diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index 9896a3215..8477ad186 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -27,32 +27,41 @@ namespace sat { class solver; class big { - random_gen m_rand; + random_gen& m_rand; unsigned m_num_vars; vector m_dag; svector m_roots; svector m_left, m_right; literal_vector m_root, m_parent; + bool m_learned; + bool m_binary; // is the BIG produced from binary clauses or hyper-binary resolution? void init_dfs_num(); struct pframe; public: - big(); + big(random_gen& rand, bool binary); /** \brief initialize a BIG from a solver. */ - void init_big(solver& s, bool learned); + void init(solver& s, bool learned); + + void reinit(); /** \brief initialize a BIG externally by adding implications. */ - void init_adding_edges(unsigned num_vars); + void init_adding_edges(unsigned num_vars, bool learned); void add_edge(literal u, literal v); void done_adding_edges(); - void ensure_big(solver& s, bool learned) { if (m_left.empty()) init_big(s, learned); } + void ensure_big(solver& s, bool learned) { if (m_left.empty()) init(s, learned); } + + unsigned reduce_tr(solver& s); + + // does it include learned binaries? + bool learned() const { return m_learned; } int get_left(literal l) const { return m_left[l.index()]; } int get_right(literal l) const { return m_right[l.index()]; } literal get_parent(literal l) const { return m_parent[l.index()]; } diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 8b7a4ca46..3600ac1a3 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -29,7 +29,6 @@ namespace sat { m_capacity(sz), m_removed(false), m_learned(learned), - m_blocked(false), m_used(false), m_frozen(false), m_reinit_stack(false), @@ -165,7 +164,6 @@ namespace sat { if (c.was_removed()) out << "x"; if (c.strengthened()) out << "+"; if (c.is_learned()) out << "*"; - if (c.is_blocked()) out << "b"; return out; } diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 76f1a9ad3..7bacf0777 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -50,7 +50,6 @@ namespace sat { unsigned m_used:1; unsigned m_frozen:1; unsigned m_reinit_stack:1; - unsigned m_blocked; unsigned m_inact_rounds:8; unsigned m_glue:8; unsigned m_psm:8; // transient field used during gc @@ -66,6 +65,7 @@ namespace sat { literal & operator[](unsigned idx) { SASSERT(idx < m_size); return m_lits[idx]; } literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; } bool is_learned() const { return m_learned; } + void set_learned() { SASSERT(!is_learned()); m_learned = true; } void unset_learned() { SASSERT(is_learned()); m_learned = false; } void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); } } bool strengthened() const { return m_strengthened; } @@ -92,9 +92,6 @@ namespace sat { unsigned inact_rounds() const { return m_inact_rounds; } bool frozen() const { return m_frozen; } void freeze() { SASSERT(is_learned()); SASSERT(!frozen()); m_frozen = true; } - bool is_blocked() const { return m_blocked; } - void block() { SASSERT(!m_blocked); SASSERT(!is_learned()); m_blocked = true; } - void unblock() { SASSERT(m_blocked); SASSERT(!is_learned()); m_blocked = false; } void unfreeze() { SASSERT(is_learned()); SASSERT(frozen()); m_frozen = false; } static var_approx_set approx(unsigned num, literal const * lits); void set_glue(unsigned glue) { m_glue = glue > 255 ? 255 : glue; } @@ -161,6 +158,16 @@ namespace sat { public: clause_wrapper(literal l1, literal l2):m_l1_idx(l1.to_uint()), m_l2_idx(l2.to_uint()) {} clause_wrapper(clause & c):m_cls(&c), m_l2_idx(null_literal.to_uint()) {} + clause_wrapper& operator=(clause_wrapper const& other) { + if (other.is_binary()) { + m_l1_idx = other.m_l1_idx; + } + else { + m_cls = other.m_cls; + } + m_l2_idx = other.m_l2_idx; + return *this; + } bool is_binary() const { return m_l2_idx != null_literal.to_uint(); } unsigned size() const { return is_binary() ? 2 : m_cls->size(); } diff --git a/src/sat/sat_clause_use_list.cpp b/src/sat/sat_clause_use_list.cpp index 363ef784e..7ca0aa2c6 100644 --- a/src/sat/sat_clause_use_list.cpp +++ b/src/sat/sat_clause_use_list.cpp @@ -27,11 +27,11 @@ namespace sat { if (!c->was_removed()) sz++; SASSERT(sz == m_size); - unsigned blocked = 0; + unsigned redundant = 0; for (clause* c : m_clauses) - if (c->is_blocked()) - blocked++; - SASSERT(blocked == m_num_blocked); + if (c->is_learned()) + redundant++; + SASSERT(redundant == m_num_redundant); return true; } diff --git a/src/sat/sat_clause_use_list.h b/src/sat/sat_clause_use_list.h index 08b50086a..c028ad713 100644 --- a/src/sat/sat_clause_use_list.h +++ b/src/sat/sat_clause_use_list.h @@ -30,24 +30,24 @@ namespace sat { class clause_use_list { clause_vector m_clauses; unsigned m_size; - unsigned m_num_blocked; + unsigned m_num_redundant; public: clause_use_list() { STRACE("clause_use_list_bug", tout << "[cul_created] " << this << "\n";); m_size = 0; - m_num_blocked = 0; + m_num_redundant = 0; } unsigned size() const { return m_size; } - unsigned num_blocked() const { - return m_num_blocked; + unsigned num_redundant() const { + return m_num_redundant; } - - unsigned non_blocked_size() const { - return m_size - m_num_blocked; + + unsigned num_irredundant() const { + return m_size - m_num_redundant; } bool empty() const { return size() == 0; } @@ -58,7 +58,7 @@ namespace sat { SASSERT(!c.was_removed()); m_clauses.push_back(&c); m_size++; - if (c.is_blocked()) ++m_num_blocked; + if (c.is_learned()) ++m_num_redundant; } void erase_not_removed(clause & c) { @@ -67,7 +67,7 @@ namespace sat { SASSERT(!c.was_removed()); m_clauses.erase(&c); m_size--; - if (c.is_blocked()) --m_num_blocked; + if (c.is_learned()) --m_num_redundant; } void erase(clause & c) { @@ -75,25 +75,25 @@ namespace sat { SASSERT(m_clauses.contains(&c)); SASSERT(c.was_removed()); m_size--; - if (c.is_blocked()) --m_num_blocked; + if (c.is_learned()) --m_num_redundant; } void block(clause const& c) { - SASSERT(c.is_blocked()); - ++m_num_blocked; + SASSERT(c.is_learned()); + ++m_num_redundant; SASSERT(check_invariant()); } void unblock(clause const& c) { - SASSERT(!c.is_blocked()); - --m_num_blocked; + SASSERT(!c.is_learned()); + --m_num_redundant; SASSERT(check_invariant()); } void reset() { m_clauses.finalize(); m_size = 0; - m_num_blocked = 0; + m_num_redundant = 0; } bool check_invariant() const; diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index e52cf139f..286cc1661 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -137,8 +137,7 @@ namespace sat { SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); if (new_sz == 2) { TRACE("cleanup_bug", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";); - if (!c.is_blocked()) - s.mk_bin_clause(c[0], c[1], c.is_learned()); + s.mk_bin_clause(c[0], c[1], c.is_learned()); s.del_clause(c); } else { diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index b67666993..c3352797e 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -111,8 +111,8 @@ namespace sat { m_lookahead_global_autarky = p.lookahead_global_autarky(); // These parameters are not exposed - m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); - m_simplify_mult2 = _p.get_double("simplify_mult2", 1.5); + m_simplify_mult1 = _p.get_uint("simplify_mult1", 100); + m_simplify_mult2 = _p.get_double("simplify_mult2", 1.2); m_simplify_max = _p.get_uint("simplify_max", 500000); // -------------------------------- diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index a2e6b445b..0adcc95ef 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -43,7 +43,7 @@ namespace sat{ if (num_bin_neg > m_max_literals) return false; clause_use_list & pos_occs = simp.m_use_list.get(pos_l); clause_use_list & neg_occs = simp.m_use_list.get(neg_l); - unsigned clause_size = num_bin_pos + num_bin_neg + pos_occs.non_blocked_size() + neg_occs.non_blocked_size(); + unsigned clause_size = num_bin_pos + num_bin_neg + pos_occs.num_irredundant() + neg_occs.num_irredundant(); if (clause_size == 0) { return false; } @@ -307,13 +307,11 @@ namespace sat{ bdd result = m.mk_true(); for (auto it = occs.mk_iterator(); !it.at_end(); it.next()) { clause const& c = it.curr(); - if (!c.is_blocked()) { - bdd cl = m.mk_false(); - for (literal l : c) { - cl |= mk_literal(l); - } - result &= cl; - } + bdd cl = m.mk_false(); + for (literal l : c) { + cl |= mk_literal(l); + } + result &= cl; } return result; } diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 7db5d63ec..ff23c9be7 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -72,7 +72,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; virtual void collect_statistics(statistics& st) const = 0; virtual extension* copy(solver* s) = 0; - virtual extension* copy(lookahead* s) = 0; + virtual extension* copy(lookahead* s, bool learned) = 0; virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; virtual void gc() = 0; virtual void pop_reinit() = 0; diff --git a/src/sat/sat_iff3_finder.cpp b/src/sat/sat_iff3_finder.cpp index af7a6f438..8bbfc0ce0 100644 --- a/src/sat/sat_iff3_finder.cpp +++ b/src/sat/sat_iff3_finder.cpp @@ -73,7 +73,7 @@ namespace sat { It assumes wlist have been sorted using iff3_lt */ static bool contains(watch_list const & wlist, literal l1, literal l2) { - watched k(l1, l2); + watched k(l1, l2, false); if (wlist.size() < SMALL_WLIST) return wlist.contains(k); iff3_lt lt; diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index bdc72602d..f68dc80df 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -28,8 +28,8 @@ namespace sat { } // for ternary clauses - static bool contains_watched(watch_list const & wlist, literal l1, literal l2) { - return wlist.contains(watched(l1, l2)); + static bool contains_watched(watch_list const & wlist, literal l1, literal l2, bool learned) { + return wlist.contains(watched(l1, l2, learned)); } // for nary clauses @@ -64,13 +64,13 @@ namespace sat { return true; if (c.size() == 3) { - CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2]), tout << c << "\n"; + CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2], c.learned()), tout << c << "\n"; tout << "watch_list:\n"; sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~c[0])); tout << "\n";); - VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2])); - VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2])); - VERIFY(contains_watched(s.get_wlist(~c[2]), c[0], c[1])); + VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2], c.is_learned())); + VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2], c.is_learned())); + VERIFY(contains_watched(s.get_wlist(~c[2]), c[0], c[1], c.is_learned())); } else { if (s.value(c[0]) == l_false || s.value(c[1]) == l_false) { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 3339bc4e6..94f73dffc 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -989,7 +989,7 @@ namespace sat { m_freevars.insert(v); } - void lookahead::init() { + void lookahead::init(bool learned) { m_delta_trigger = 0.0; m_delta_decrease = 0.0; m_config.m_dl_success = 0.8; @@ -1010,6 +1010,8 @@ namespace sat { for (auto& w : wlist) { if (!w.is_binary_clause()) continue; + if (!learned && w.is_learned()) + continue; literal l2 = w.get_literal(); if (l.index() < l2.index() && !m_s.was_eliminated(l2.var())) add_binary(l, l2); @@ -1017,7 +1019,7 @@ namespace sat { } copy_clauses(m_s.m_clauses, false); - copy_clauses(m_s.m_learned, true); + if (learned) copy_clauses(m_s.m_learned, true); // copy units unsigned trail_sz = m_s.init_trail_size(); @@ -1030,7 +1032,7 @@ namespace sat { } if (m_s.m_ext) { - m_ext = m_s.m_ext->copy(this); + m_ext = m_s.m_ext->copy(this, learned); } propagate(); m_qhead = m_trail.size(); @@ -2223,7 +2225,7 @@ namespace sat { void lookahead::init_search() { m_search_mode = lookahead_mode::searching; scoped_level _sl(*this, c_fixed_truth); - init(); + init(true); } void lookahead::checkpoint() { @@ -2255,13 +2257,13 @@ namespace sat { /** \brief simplify set of clauses by extracting units from a lookahead at base level. */ - void lookahead::simplify() { + void lookahead::simplify(bool learned) { scoped_ext _scoped_ext(*this); SASSERT(m_prefix == 0); SASSERT(m_watches.empty()); m_search_mode = lookahead_mode::searching; scoped_level _sl(*this, c_fixed_truth); - init(); + init(learned); if (inconsistent()) return; inc_istamp(); literal l = choose(); @@ -2311,12 +2313,11 @@ namespace sat { elim(roots, to_elim); if (get_config().m_lookahead_simplify_asymm_branch) { - big_asymm_branch(); + big_asymm_branch(learned); } - if (get_config().m_lookahead_simplify_bca) { + if (learned && get_config().m_lookahead_simplify_bca) { add_hyper_binary(); - } - + } } } m_lookahead.reset(); @@ -2327,11 +2328,11 @@ namespace sat { for strengthening clauses. */ - void lookahead::big_asymm_branch() { + void lookahead::big_asymm_branch(bool learned) { unsigned num_lits = m_s.num_vars() * 2; unsigned idx = 0; - big big; - big.init_adding_edges(m_s.num_vars()); + big big(m_s.m_rand, false); + big.init_adding_edges(m_s.num_vars(), learned); for (auto const& lits : m_binary) { literal u = get_parent(to_literal(idx++)); if (u == null_literal) continue; @@ -2370,8 +2371,8 @@ namespace sat { } } - big big; - big.init_big(m_s, true); + big big(m_s.m_rand, false); + big.init(m_s, true); svector> candidates; unsigned_vector bin_size(num_lits); @@ -2395,7 +2396,7 @@ namespace sat { } for (unsigned count = 0; count < 5; ++count) { - big.init_big(m_s, true); + big.init(m_s, true); unsigned k = 0; union_find_default_ctx ufctx; union_find uf(ufctx); @@ -2418,7 +2419,7 @@ namespace sat { } } } - std::cout << candidates.size() << " -> " << k << "\n"; + // std::cout << candidates.size() << " -> " << k << "\n"; if (k == candidates.size()) break; candidates.shrink(k); if (k == 0) break; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 75ce4fe6d..794d868f1 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -488,7 +488,7 @@ namespace sat { // initialization void init_var(bool_var v); - void init(); + void init(bool learned); void copy_clauses(clause_vector const& clauses, bool learned); nary * copy_clause(clause const& c); @@ -555,7 +555,7 @@ namespace sat { void add_hyper_binary(); - void big_asymm_branch(); + void big_asymm_branch(bool learned); double psat_heur(); @@ -600,7 +600,7 @@ namespace sat { /** \brief simplify set of clauses by extracting units from a lookahead at base level. */ - void simplify(); + void simplify(bool learned); std::ostream& display(std::ostream& out) const; std::ostream& display_summary(std::ostream& out) const; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index c8d47ddd3..3630365d6 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -50,8 +50,8 @@ def_module_params('sat', ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), - ('lookahead_simplify.bca', BOOL, False, 'add learned binary clauses as part of lookahead simplification'), - ('lookahead_simplify.asymm_branch', BOOL, False, 'apply asymmetric branch simplification with lookahead simplifier'), + ('lookahead_simplify.bca', BOOL, True, 'add learned binary clauses as part of lookahead simplification'), + ('lookahead_simplify.asymm_branch', BOOL, True, 'apply asymmetric branch simplification with lookahead simplifier'), ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'))) diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 4bd16c5c5..484cb93ff 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -26,7 +26,8 @@ Revision History: namespace sat { scc::scc(solver & s, params_ref const & p): - m_solver(s) { + m_solver(s), + m_big(s.m_rand, true) { reset_statistics(); updt_params(p); } @@ -237,41 +238,16 @@ namespace sat { unsigned scc::reduce_tr(bool learned) { unsigned num_lits = m_solver.num_vars() * 2; init_big(learned); - - unsigned idx = 0; - unsigned elim = m_num_elim_bin; - for (watch_list & wlist : m_solver.m_watches) { - literal u = to_literal(idx++); - watch_list::iterator it = wlist.begin(); - watch_list::iterator itprev = it; - watch_list::iterator end = wlist.end(); - for (; it != end; ++it) { - watched& w = *it; - if (learned ? w.is_binary_learned_clause() : w.is_binary_clause()) { - literal v = w.get_literal(); - if (reaches(u, v) && u != get_parent(v)) { - ++m_num_elim_bin; - m_solver.get_wlist(~v).erase(watched(~u, w.is_learned())); - } - else { - *itprev = *it; - itprev++; - } - } - else { - *itprev = *it; - itprev++; - } - } - wlist.set_end(itprev); - } - return m_num_elim_bin - elim; + unsigned num_elim = m_big.reduce_tr(m_solver); + m_num_elim_bin += num_elim; + return num_elim; } void scc::reduce_tr() { unsigned quota = 0, num_reduced = 0; while ((num_reduced = reduce_tr(false)) > quota) { quota = std::max(100u, num_reduced / 2); } - while ((num_reduced = reduce_tr(true)) > quota) { quota = std::max(100u, num_reduced / 2); } + quota = 0; + while ((num_reduced = reduce_tr(true)) > quota) { quota = std::max(100u, num_reduced / 2); } } void scc::collect_statistics(statistics & st) const { diff --git a/src/sat/sat_scc.h b/src/sat/sat_scc.h index 5e61e557e..146bd2366 100644 --- a/src/sat/sat_scc.h +++ b/src/sat/sat_scc.h @@ -56,16 +56,12 @@ namespace sat { /* \brief create binary implication graph and associated data-structures to check transitivity. */ - void init_big(bool learned) { m_big.init_big(m_solver, learned); } + void init_big(bool learned) { m_big.init(m_solver, learned); } void ensure_big(bool learned) { m_big.ensure_big(m_solver, learned); } int get_left(literal l) const { return m_big.get_left(l); } int get_right(literal l) const { return m_big.get_right(l); } - literal get_parent(literal l) const { return m_big.get_parent(l); } literal get_root(literal l) const { return m_big.get_root(l); } - bool reaches(literal u, literal v) const { return m_big.reaches(u, v); } - bool connected(literal u, literal v) const { - return m_big.connected(u, v); - } + bool connected(literal u, literal v) const { return m_big.connected(u, v); } }; }; diff --git a/src/sat/sat_scc_params.pyg b/src/sat/sat_scc_params.pyg index 0bf88a0cd..ead4eeb96 100644 --- a/src/sat/sat_scc_params.pyg +++ b/src/sat/sat_scc_params.pyg @@ -2,5 +2,5 @@ def_module_params(module_name='sat', class_name='sat_scc_params', export=True, params=(('scc', BOOL, True, 'eliminate Boolean variables by computing strongly connected components'), - ('scc.tr', BOOL, False, 'apply transitive reduction, eliminate redundant binary clauses'), )) + ('scc.tr', BOOL, True, 'apply transitive reduction, eliminate redundant binary clauses'), )) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index de59966e6..106cc791e 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -150,7 +150,8 @@ namespace sat { inline void simplifier::block_clause(clause & c) { if (m_retain_blocked_clauses) { - c.block(); + m_need_cleanup = true; + c.set_learned(); m_use_list.block(c); } else { @@ -160,7 +161,7 @@ namespace sat { } inline void simplifier::unblock_clause(clause & c) { - c.unblock(); + c.unset_learned(); m_use_list.unblock(c); } @@ -231,7 +232,6 @@ namespace sat { if (bce_enabled() || abce_enabled() || bca_enabled()) { elim_blocked_clauses(); } - if (!m_need_cleanup) si.check_watches(); if (!learned) { m_num_calls++; @@ -265,6 +265,8 @@ namespace sat { if (m_need_cleanup || vars_eliminated) { TRACE("after_simplifier", tout << "cleanning watches...\n";); cleanup_watches(); + move_clauses(s.m_learned, true); + move_clauses(s.m_clauses, false); cleanup_clauses(s.m_learned, true, vars_eliminated, m_learned_in_use_lists); cleanup_clauses(s.m_clauses, false, vars_eliminated, true); } @@ -302,6 +304,26 @@ namespace sat { } } + void simplifier::move_clauses(clause_vector& cs, bool learned) { + clause_vector::iterator it = cs.begin(); + clause_vector::iterator it2 = it; + clause_vector::iterator end = cs.end(); + for (; it != end; ++it) { + clause & c = *(*it); + if (learned && !c.is_learned()) { + s.m_clauses.push_back(&c); + } + else if (!learned && c.is_learned()) { + s.m_learned.push_back(&c); + } + else { + *it2 = *it; + ++it2; + } + } + cs.set_end(it2); + } + void simplifier::cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists) { TRACE("sat", tout << "cleanup_clauses\n";); clause_vector::iterator it = cs.begin(); @@ -309,6 +331,7 @@ namespace sat { clause_vector::iterator end = cs.end(); for (; it != end; ++it) { clause & c = *(*it); + VERIFY(learned == c.is_learned()); if (c.was_removed()) { s.del_clause(c); continue; @@ -350,10 +373,10 @@ namespace sat { s.del_clause(c); continue; } - // clause became a problem clause - if (learned && !c.is_learned()) { + // clause became a learned clause + if (!learned && c.is_learned()) { SASSERT(!c.frozen()); - s.m_clauses.push_back(&c); + s.m_learned.push_back(&c); continue; } *it2 = *it; @@ -433,7 +456,6 @@ namespace sat { */ void simplifier::collect_subsumed1_core(clause const & c1, clause_vector & out, literal_vector & out_lits, literal target) { - if (c1.is_blocked()) return; clause_use_list const & cs = m_use_list.get(target); for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) { clause & c2 = it.curr(); @@ -474,17 +496,15 @@ namespace sat { literal_vector::iterator l_it = m_bs_ls.begin(); for (; it != end; ++it, ++l_it) { clause & c2 = *(*it); - if (!c2.was_removed() && !c1.is_blocked() && *l_it == null_literal) { + if (!c2.was_removed() && *l_it == null_literal) { // c2 was subsumed if (c1.is_learned() && !c2.is_learned()) c1.unset_learned(); - else if (c1.is_blocked() && !c2.is_learned() && !c2.is_blocked()) - unblock_clause(c1); TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";); remove_clause(c2); m_num_subsumed++; } - else if (!c2.was_removed() && !c1.is_blocked()) { + else if (!c2.was_removed()) { // subsumption resolution TRACE("subsumption_resolution", tout << c1 << " sub-ref(" << *l_it << ") " << c2 << "\n";); elim_lit(c2, *l_it); @@ -544,7 +564,6 @@ namespace sat { \brief Collect the clauses subsumed by c1 (using the occurrence list of target). */ void simplifier::collect_subsumed0_core(clause const & c1, clause_vector & out, literal target) { - if (c1.is_blocked()) return; clause_use_list const & cs = m_use_list.get(target); clause_use_list::iterator it = cs.mk_iterator(); for (; !it.at_end(); it.next()) { @@ -955,16 +974,19 @@ namespace sat { literal_vector m_covered_clause; literal_vector m_intersection; literal_vector m_new_intersection; + literal_vector m_blocked_binary; svector m_in_intersection; sat::model_converter::elim_stackv m_elim_stack; unsigned m_ala_qhead; + clause_wrapper m_clause; blocked_clause_elim(simplifier & _s, unsigned limit, model_converter & _mc, use_list & l, vector & wlist): s(_s), m_counter(limit), mc(_mc), - m_queue(l, wlist) { + m_queue(l, wlist), + m_clause(null_literal, null_literal) { m_in_intersection.resize(s.s.num_vars() * 2, false); } @@ -977,25 +999,34 @@ namespace sat { return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v); } + enum elim_type { + cce_t, + acce_t, + abce_t + }; + + enum verdict_type { + at_t, // asymmetric tautology + bc_t, // blocked clause + no_t // neither + }; + void operator()() { - integrity_checker si(s.s); - //si.check_watches(); if (s.bce_enabled()) { block_clauses(); } - //si.check_watches(); if (s.abce_enabled()) { - cce(); + cce(); } - //si.check_watches(); if (s.cce_enabled()) { - cce(); + cce(); + } + if (s.acce_enabled()) { + cce(); } - //si.check_watches(); if (s.bca_enabled()) { bca(); } - //si.check_watches(); } void block_clauses() { @@ -1022,13 +1053,12 @@ namespace sat { return; } integrity_checker si(s.s); - //si.check_watches(); process_clauses(l); process_binary(l); - //si.check_watches(); - } + } void process_binary(literal l) { + m_blocked_binary.reset(); model_converter::entry* new_entry = 0; watch_list & wlist = s.get_wlist(~l); m_counter -= wlist.size(); @@ -1046,6 +1076,7 @@ namespace sat { if (all_tautology(l)) { block_binary(it, l, new_entry); s.m_num_blocked_clauses++; + m_blocked_binary.push_back(l2); } else { *it2 = *it; it2++; @@ -1053,6 +1084,12 @@ namespace sat { s.unmark_visited(l2); } wlist.set_end(it2); + if (s.m_retain_blocked_clauses && !m_blocked_binary.empty()) { + IF_VERBOSE(0, verbose_stream() << "retaining " << m_blocked_binary.size() << " binary clauses\n";); + for (literal lit2 : m_blocked_binary) { + s.s.mk_bin_clause(l, lit2, true); + } + } } void process_clauses(literal l) { @@ -1062,7 +1099,7 @@ namespace sat { clause_use_list::iterator it = occs.mk_iterator(); for (; !it.at_end(); it.next()) { clause & c = it.curr(); - if (c.is_blocked()) continue; + if (c.is_learned()) continue; m_counter -= c.size(); SASSERT(c.contains(l)); s.mark_all_but(c, l); @@ -1118,7 +1155,7 @@ namespace sat { for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) { bool tautology = false; clause & c = it.curr(); - if (c.is_blocked() && !adding) continue; + if (c.is_learned() && !adding) continue; for (literal lit : c) { if (s.is_marked(~lit) && lit != ~l) { tautology = true; @@ -1159,7 +1196,7 @@ namespace sat { clause_use_list & neg_occs = s.m_use_list.get(~l); for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) { clause & c = it.curr(); - if (c.is_blocked()) continue; + if (c.is_learned()) continue; bool tautology = false; for (literal lit : c) { if (s.is_marked(~lit) && lit != ~l) { @@ -1172,24 +1209,107 @@ namespace sat { return true; } + bool revisit_binary(literal l1, literal l2) const { + return m_clause.is_binary() && + ((m_clause[0] == l1 && m_clause[1] == l2) || + (m_clause[0] == l2 && m_clause[1] == l1)); + } + + bool revisit_ternary(literal l1, literal l2, literal l3) const { + return m_clause.size() == 3 && + ((m_clause[0] == l1 && m_clause[1] == l2 && m_clause[2] == l3) || + (m_clause[0] == l2 && m_clause[1] == l1 && m_clause[2] == l3) || + (m_clause[0] == l2 && m_clause[1] == l3 && m_clause[2] == l1) || + (m_clause[0] == l1 && m_clause[1] == l3 && m_clause[2] == l2) || + (m_clause[0] == l3 && m_clause[1] == l1 && m_clause[2] == l2) || + (m_clause[0] == l3 && m_clause[1] == l2 && m_clause[2] == l1)); + } + + bool revisit_clause(clause const& c) const { + return !m_clause.is_binary() && (m_clause.get_clause() == &c); + } + /* * C \/ l l \/ lit * ------------------- * C \/ l \/ ~lit + * + * C \/ lit \/ l l \/ lit + * ------------------------ + * l \/ lit C \/ lit \/ l can be removed + * + * C \/ l1 \/ ... \/ lk l1 \/ ... \/ lk \/ lit + * ----------------------------------------------- + * C \/ l1 \/ ... \/ lk \/ ~lit + * unless C contains lit, and it is a tautology. */ - void add_ala() { + bool add_ala() { for (; m_ala_qhead < m_covered_clause.size(); ++m_ala_qhead) { literal l = m_covered_clause[m_ala_qhead]; for (watched & w : s.get_wlist(~l)) { if (w.is_binary_non_learned_clause()) { literal lit = w.get_literal(); - if (!s.is_marked(lit) && !s.is_marked(~lit)) { + if (revisit_binary(l, lit)) continue; + if (s.is_marked(lit)) { + IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " binary: " << l << " " << lit << "\n";); + return true; + } + if (!s.is_marked(~lit)) { + IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " binary " << l << " " << lit << " " << (~lit) << "\n";); m_covered_clause.push_back(~lit); s.mark_visited(~lit); } } + else if (w.is_ternary_clause() && !w.is_learned()) { + literal lit1 = w.get_literal1(); + literal lit2 = w.get_literal2(); + if (revisit_ternary(l, lit1, lit2)) continue; + if (s.is_marked(lit1) && s.is_marked(lit2)) { + IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " ternary: " << l << " " << lit1 << " " << lit2 << "\n";); + return true; + } + if (s.is_marked(lit1) && !s.is_marked(~lit2)) { + IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " ternary " << l << " " << lit1 << " " << lit2 << " " << (~lit2) << "\n";); + m_covered_clause.push_back(~lit2); + s.mark_visited(~lit2); + continue; + } + if (s.is_marked(lit2) && !s.is_marked(~lit1)) { + IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " ternay " << l << " " << lit1 << " " << lit2 << " " << (~lit1) << "\n";); + m_covered_clause.push_back(~lit1); + s.mark_visited(~lit1); + continue; + } + } + else if (w.is_clause()) { + clause & c = s.s.get_clause(w.get_clause_offset()); + if (c.is_learned()) continue; + if (revisit_clause(c)) continue; + literal lit1 = null_literal; + bool ok = true; + for (literal lit : c) { + if (lit == l) continue; + if (s.is_marked(lit)) continue; + if (!s.is_marked(~lit) && lit1 == null_literal) { + lit1 = lit; + } + else { + ok = false; + break; + } + } + if (!ok) continue; + if (lit1 == null_literal) { + IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " clause " << c << "\n";); + return true; + } + IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " clause " << c << " " << (~lit1) << "\n";); + m_covered_clause.push_back(~lit1); + s.mark_visited(~lit1); + } } } + return false; } @@ -1220,11 +1340,12 @@ namespace sat { } bool above_threshold(unsigned sz0) const { - return sz0 * 10 < m_covered_clause.size(); + if (sz0 * 400 < m_covered_clause.size()) IF_VERBOSE(0, verbose_stream() << "above threshold " << sz0 << " " << m_covered_clause.size() << "\n";); + return sz0 * 400 < m_covered_clause.size(); } - template - bool cla(literal& blocked, model_converter::kind& k) { + template + verdict_type cla(literal& blocked, model_converter::kind& k) { bool is_tautology = false; for (literal l : m_covered_clause) s.mark_visited(l); unsigned num_iterations = 0, sz; @@ -1240,9 +1361,9 @@ namespace sat { * So we record sz0, the original set of literals in the clause, mark additional literals, * and then check if any of the first sz0 literals are blocked. */ - if (s.abce_enabled() && !use_ri) { - add_ala(); - for (unsigned i = 0; i < sz0; ++i) { + if (et == abce_t) { + if (add_ala()) return at_t; + for (unsigned i = 0; !is_tautology && i < sz0; ++i) { if (check_abce_tautology(m_covered_clause[i])) { blocked = m_covered_clause[i]; is_tautology = true; @@ -1252,7 +1373,7 @@ namespace sat { k = model_converter::BLOCK_LIT; // actually ABCE for (literal l : m_covered_clause) s.unmark_visited(l); m_covered_clause.shrink(sz0); - return is_tautology; + return is_tautology ? bc_t : no_t; } /* @@ -1268,53 +1389,56 @@ namespace sat { } while (m_covered_clause.size() > sz && !is_tautology); if (above_threshold(sz0)) break; - if (s.acce_enabled() && !is_tautology) { + if (et == acce_t && !is_tautology) { sz = m_covered_clause.size(); - add_ala(); + if (add_ala()) return at_t; k = model_converter::ACCE; } } while (m_covered_clause.size() > sz && !is_tautology); // if (is_tautology) std::cout << num_iterations << " " << m_covered_clause.size() << " " << sz0 << " " << is_tautology << " " << m_elim_stack.size() << "\n"; for (literal l : m_covered_clause) s.unmark_visited(l); - return is_tautology && !above_threshold(sz0); + return (is_tautology && !above_threshold(sz0)) ? bc_t : no_t; } // perform covered clause elimination. // first extract the covered literal addition (CLA). // then check whether the CLA is blocked. - template - bool cce(clause& c, literal& blocked, model_converter::kind& k) { + template + verdict_type cce(clause& c, literal& blocked, model_converter::kind& k) { + m_clause = clause_wrapper(c); m_covered_clause.reset(); for (literal l : c) m_covered_clause.push_back(l); - return cla(blocked, k); + return cla(blocked, k); } - template - bool cce(literal l1, literal l2, literal& blocked, model_converter::kind& k) { + template + verdict_type cce(literal l1, literal l2, literal& blocked, model_converter::kind& k) { + m_clause = clause_wrapper(l1, l2); m_covered_clause.reset(); m_covered_clause.push_back(l1); m_covered_clause.push_back(l2); - return cla(blocked, k); + return cla(blocked, k); } - template + template void cce() { insert_queue(); - cce_clauses(); - cce_binary(); + cce_clauses(); + cce_binary(); } - template + template void cce_binary() { while (!m_queue.empty() && m_counter >= 0) { s.checkpoint(); - process_cce_binary(m_queue.next()); + process_cce_binary(m_queue.next()); } } - template + template void process_cce_binary(literal l) { + m_blocked_binary.reset(); literal blocked = null_literal; watch_list & wlist = s.get_wlist(~l); m_counter -= wlist.size(); @@ -1329,29 +1453,51 @@ namespace sat { continue; } literal l2 = it->get_literal(); - if (cce(l, l2, blocked, k)) { + switch (cce(l, l2, blocked, k)) { + case bc_t: block_covered_binary(it, l, blocked, k); s.m_num_covered_clauses++; - } - else { + m_blocked_binary.push_back(l2); + break; + case at_t: + s.m_num_ate++; + m_blocked_binary.push_back(l2); + break; + case no_t: *it2 = *it; it2++; + break; } } wlist.set_end(it2); + if (s.m_retain_blocked_clauses && !m_blocked_binary.empty()) { + IF_VERBOSE(0, verbose_stream() << "retaining " << m_blocked_binary.size() << " binary clauses\n";); + for (literal lit2 : m_blocked_binary) { + s.s.mk_bin_clause(l, lit2, true); + } + } } - template + template void cce_clauses() { m_to_remove.reset(); literal blocked; model_converter::kind k; for (clause* cp : s.s.m_clauses) { clause& c = *cp; - if (!c.was_removed() && !c.is_blocked() && cce(c, blocked, k)) { - block_covered_clause(c, blocked, k); - s.m_num_covered_clauses++; + if (!c.was_removed() && !c.is_learned()) { + switch (cce(c, blocked, k)) { + case bc_t: + block_covered_clause(c, blocked, k); + s.m_num_covered_clauses++; + break; + case at_t: + m_to_remove.push_back(&c); + break; + case no_t: + break; + } } } for (clause* c : m_to_remove) { @@ -1456,7 +1602,7 @@ namespace sat { clause_use_list::iterator it = neg_occs.mk_iterator(); for (; !it.at_end(); it.next()) { clause & c = it.curr(); - if (c.is_blocked()) continue; + if (c.is_learned()) continue; m_counter -= c.size(); unsigned sz = c.size(); unsigned i; @@ -1485,11 +1631,13 @@ namespace sat { stopwatch m_watch; unsigned m_num_blocked_clauses; unsigned m_num_covered_clauses; + unsigned m_num_ate; unsigned m_num_added_clauses; blocked_cls_report(simplifier & s): m_simplifier(s), m_num_blocked_clauses(s.m_num_blocked_clauses), m_num_covered_clauses(s.m_num_covered_clauses), + m_num_ate(s.m_num_ate), m_num_added_clauses(s.m_num_bca) { m_watch.start(); } @@ -1503,6 +1651,8 @@ namespace sat { << (m_simplifier.m_num_covered_clauses - m_num_covered_clauses) << " :added-clauses " << (m_simplifier.m_num_bca - m_num_added_clauses) + << " :ate " + << (m_simplifier.m_num_ate - m_num_ate) << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } @@ -1571,7 +1721,7 @@ namespace sat { void simplifier::collect_clauses(literal l, clause_wrapper_vector & r) { clause_use_list const & cs = m_use_list.get(l); for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) { - if (!it.curr().is_blocked()) { + if (!it.curr().is_learned()) { r.push_back(clause_wrapper(it.curr())); SASSERT(r.back().size() == it.curr().size()); } @@ -1715,8 +1865,8 @@ namespace sat { unsigned num_bin_neg = get_num_unblocked_bin(neg_l); clause_use_list & pos_occs = m_use_list.get(pos_l); clause_use_list & neg_occs = m_use_list.get(neg_l); - unsigned num_pos = pos_occs.non_blocked_size() + num_bin_pos; - unsigned num_neg = neg_occs.non_blocked_size() + num_bin_neg; + unsigned num_pos = pos_occs.num_irredundant() + num_bin_pos; + unsigned num_neg = neg_occs.num_irredundant() + num_bin_neg; TRACE("resolution", tout << v << " num_pos: " << num_pos << " neg_pos: " << num_neg << "\n";); @@ -1726,12 +1876,12 @@ namespace sat { unsigned before_lits = num_bin_pos*2 + num_bin_neg*2; for (auto it = pos_occs.mk_iterator(); !it.at_end(); it.next()) { - if (!it.curr().is_blocked()) + if (!it.curr().is_learned()) before_lits += it.curr().size(); } for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) { - if (!it.curr().is_blocked()) + if (!it.curr().is_learned()) before_lits += it.curr().size(); } @@ -1847,7 +1997,7 @@ namespace sat { ~elim_var_report() { m_watch.stop(); IF_VERBOSE(SAT_VB_LVL, - verbose_stream() << " (sat-resolution :elim-bool-vars " + verbose_stream() << " (sat-resolution :elim-vars " << (m_simplifier.m_num_elim_vars - m_num_elim_vars) << " :threshold " << m_simplifier.m_elim_counter << mem_stat() @@ -1921,6 +2071,7 @@ namespace sat { st.update("elim blocked clauses", m_num_blocked_clauses); st.update("elim covered clauses", m_num_covered_clauses); st.update("blocked clauses added", m_num_bca); + st.update("asymmetric tautologies eliminated", m_num_ate); } void simplifier::reset_statistics() { @@ -1931,5 +2082,6 @@ namespace sat { m_num_elim_lits = 0; m_num_elim_vars = 0; m_num_bca = 0; + m_num_ate = 0; } }; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 589061df5..69a444954 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -107,6 +107,7 @@ namespace sat { unsigned m_num_sub_res; unsigned m_num_elim_lits; unsigned m_num_bca; + unsigned m_num_ate; bool m_learned_in_use_lists; unsigned m_old_num_elim_vars; @@ -159,6 +160,7 @@ namespace sat { void mark_as_not_learned(literal l1, literal l2); void cleanup_watches(); + void move_clauses(clause_vector & cs, bool learned); void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists); bool is_external(bool_var v) const; diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index 32d318536..f988c3c8b 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -8,7 +8,7 @@ def_module_params(module_name='sat', ('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), ('bca', BOOL, False, 'blocked clause addition - add blocked binary clauses'), ('bce_delay', UINT, 0, 'delay eliminate blocked clauses until simplification round'), - ('retain_blocked_clauses', BOOL, False, 'retain blocked clauses for propagation, hide them from variable elimination'), + ('retain_blocked_clauses', BOOL, True, 'retain blocked clauses as lemmas'), ('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'), ('override_incremental', BOOL, False, 'override incemental safety gaps. Enable elimination of blocked clauses and variables even if solver is reused'), ('resolution.limit', UINT, 500000000, 'approx. maximum number of literals visited during variable elimination'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2dd459372..0c2d34dac 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -173,11 +173,9 @@ namespace sat { for (clause* c : src.m_clauses) { buffer.reset(); for (literal l : *c) buffer.push_back(l); - clause* c1 = mk_clause_core(buffer); - if (c1 && c->is_blocked()) { - c1->block(); - } + mk_clause_core(buffer); } + // copy high quality lemmas unsigned num_learned = 0; for (clause* c : src.m_learned) { @@ -398,9 +396,9 @@ namespace sat { bool solver::attach_ter_clause(clause & c) { bool reinit = false; - m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); - m_watches[(~c[1]).index()].push_back(watched(c[0], c[2])); - m_watches[(~c[2]).index()].push_back(watched(c[0], c[1])); + m_watches[(~c[0]).index()].push_back(watched(c[1], c[2], c.is_learned())); + m_watches[(~c[1]).index()].push_back(watched(c[0], c[2], c.is_learned())); + m_watches[(~c[2]).index()].push_back(watched(c[0], c[1], c.is_learned())); if (!at_base_lvl()) { if (value(c[1]) == l_false && value(c[2]) == l_false) { m_stats.m_ter_propagate++; @@ -1508,6 +1506,7 @@ namespace sat { CASSERT("sat_simplify_bug", check_invariant()); si.check_watches(); + m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); @@ -1517,11 +1516,6 @@ namespace sat { CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); } - if (m_config.m_lookahead_simplify) { - lookahead lh(*this); - lh.simplify(); - lh.collect_statistics(m_aux_stats); - } sort_watch_lits(); CASSERT("sat_simplify_bug", check_invariant()); @@ -1529,7 +1523,7 @@ namespace sat { CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); - m_asymm_branch(); + m_asymm_branch(false); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); @@ -1538,6 +1532,17 @@ namespace sat { m_ext->simplify(); } + if (m_config.m_lookahead_simplify) { + lookahead lh(*this); + lh.simplify(true); + lh.collect_statistics(m_aux_stats); + } + if (false && m_config.m_lookahead_simplify) { + lookahead lh(*this); + lh.simplify(false); + lh.collect_statistics(m_aux_stats); + } + TRACE("sat", display(tout << "consistent: " << (!inconsistent()) << "\n");); reinit_assumptions(); @@ -1639,7 +1644,7 @@ namespace sat { bool ok = true; for (clause const* cp : m_clauses) { clause const & c = *cp; - if (!c.satisfied_by(m) && !c.is_blocked()) { + if (!c.satisfied_by(m)) { IF_VERBOSE(0, verbose_stream() << "failed clause " << c.id() << ": " << c << "\n";); TRACE("sat", tout << "failed: " << c << "\n"; tout << "assumptions: " << m_assumptions << "\n"; @@ -3282,6 +3287,19 @@ namespace sat { return num_cls + m_clauses.size() + m_learned.size(); } + void solver::num_binary(unsigned& given, unsigned& learned) const { + given = learned = 0; + unsigned l_idx = 0; + for (auto const& wl : m_watches) { + literal l = ~to_literal(l_idx++); + for (auto const& w : wl) { + if (w.is_binary_clause() && l.index() < w.get_literal().index()) { + if (w.is_learned()) ++learned; else ++given; + } + } + } + } + void solver::display_dimacs(std::ostream & out) const { out << "p cnf " << num_vars() << " " << num_clauses() << "\n"; for (literal lit : m_trail) { @@ -4054,10 +4072,12 @@ namespace sat { } void mk_stat::display(std::ostream & out) const { + unsigned given, learned; + m_solver.num_binary(given, learned); if (!m_solver.m_clauses.empty()) - out << " :clauses " << m_solver.m_clauses.size(); + out << " :clauses " << m_solver.m_clauses.size() + given << "/" << given; if (!m_solver.m_learned.empty()) { - out << " :learned " << (m_solver.m_learned.size() - m_solver.m_num_frozen); + out << " :learned " << (m_solver.m_learned.size() + learned - m_solver.m_num_frozen) << "/" << learned; if (m_solver.m_num_frozen > 0) out << " :frozen " << m_solver.m_num_frozen; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index e37fa3cca..8b97dc7ea 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -263,6 +263,7 @@ namespace sat { bool inconsistent() const { return m_inconsistent; } unsigned num_vars() const { return m_level.size(); } unsigned num_clauses() const; + void num_binary(unsigned& given, unsigned& learned) const; unsigned num_restarts() const { return m_restarts; } bool is_external(bool_var v) const { return m_external[v] != 0; } bool is_external(literal l) const { return is_external(l.var()); } diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index e66197878..88b6f3e51 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -53,15 +53,16 @@ namespace sat { SASSERT(learned || is_binary_non_learned_clause()); } - watched(literal l1, literal l2) { + watched(literal l1, literal l2, bool learned) { SASSERT(l1 != l2); if (l1.index() > l2.index()) std::swap(l1, l2); m_val1 = l1.to_uint(); - m_val2 = static_cast(TERNARY) + (l2.to_uint() << 2); + m_val2 = static_cast(TERNARY) + (static_cast(learned) << 2) + (l2.to_uint() << 3); SASSERT(is_ternary_clause()); SASSERT(get_literal1() == l1); SASSERT(get_literal2() == l2); + SASSERT(is_learned() == learned); } unsigned val2() const { return m_val2; } @@ -91,12 +92,12 @@ namespace sat { bool is_binary_learned_clause() const { return is_binary_clause() && is_learned(); } bool is_binary_non_learned_clause() const { return is_binary_clause() && !is_learned(); } - void set_not_learned() { SASSERT(is_learned()); m_val2 = static_cast(BINARY); SASSERT(!is_learned()); } - void set_learned() { SASSERT(!is_learned()); m_val2 = static_cast(BINARY) + (1u << 2); SASSERT(is_learned()); } + void set_not_learned() { SASSERT(is_learned()); m_val2 &= 0x3; SASSERT(!is_learned()); } + void set_learned() { SASSERT(!is_learned()); m_val2 |= 0x4; SASSERT(is_learned()); } bool is_ternary_clause() const { return get_kind() == TERNARY; } literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast(m_val1)); } - literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 2); } + literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 3); } bool is_clause() const { return get_kind() == CLAUSE; } clause_offset get_clause_offset() const { SASSERT(is_clause()); return static_cast(m_val1); } @@ -135,7 +136,7 @@ namespace sat { watched* find_binary_watch(watch_list & wlist, literal l); watched const* find_binary_watch(watch_list const & wlist, literal l); bool erase_clause_watch(watch_list & wlist, clause_offset c); - inline void erase_ternary_watch(watch_list & wlist, literal l1, literal l2) { wlist.erase(watched(l1, l2)); } + inline void erase_ternary_watch(watch_list & wlist, literal l1, literal l2) { wlist.erase(watched(l1, l2, true)); wlist.erase(watched(l1, l2, false)); } class clause_allocator; std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist); From 73e9d351dc9870cc2190ba36ddcf46e22a8d9038 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2018 03:21:58 -0800 Subject: [PATCH 0496/1283] adding initial model to updated #1463 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 743ab20d9..a7c8c3f5b 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -280,6 +280,7 @@ namespace opt { if (is_sat != l_false) { s.get_model(m_model); s.get_labels(m_labels); + model_updated(m_model.get()); } if (is_sat != l_true) { TRACE("opt", tout << m_hard_constraints << "\n";); From ede12553f2add216b56819501c3e53a7fd26040e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2018 03:31:28 -0800 Subject: [PATCH 0497/1283] fix learned annotation on ternary Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.h | 3 +-- src/sat/sat_simplifier.cpp | 16 ++++++++-------- src/sat/sat_solver.cpp | 17 +++++++++++++++-- src/sat/sat_solver.h | 3 ++- src/sat/sat_watched.cpp | 26 +++++++++++++++++++++++++- src/sat/sat_watched.h | 10 +++++----- 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 7bacf0777..1477cc6e3 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -65,8 +65,7 @@ namespace sat { literal & operator[](unsigned idx) { SASSERT(idx < m_size); return m_lits[idx]; } literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; } bool is_learned() const { return m_learned; } - void set_learned() { SASSERT(!is_learned()); m_learned = true; } - void unset_learned() { SASSERT(is_learned()); m_learned = false; } + void set_learned(bool l) { SASSERT(is_learned() != l); m_learned = l; } void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); } } bool strengthened() const { return m_strengthened; } void mark_strengthened() { m_strengthened = true; update_approx(); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 106cc791e..577badbc8 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -151,7 +151,7 @@ namespace sat { inline void simplifier::block_clause(clause & c) { if (m_retain_blocked_clauses) { m_need_cleanup = true; - c.set_learned(); + s.set_learned(c, true); m_use_list.block(c); } else { @@ -161,7 +161,7 @@ namespace sat { } inline void simplifier::unblock_clause(clause & c) { - c.unset_learned(); + s.set_learned(c, false); m_use_list.unblock(c); } @@ -499,7 +499,7 @@ namespace sat { if (!c2.was_removed() && *l_it == null_literal) { // c2 was subsumed if (c1.is_learned() && !c2.is_learned()) - c1.unset_learned(); + s.set_learned(c1, false); TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";); remove_clause(c2); m_num_subsumed++; @@ -599,7 +599,7 @@ namespace sat { clause & c2 = *cp; // c2 was subsumed if (c1.is_learned() && !c2.is_learned()) - c1.unset_learned(); + s.set_learned(c1, false); TRACE("subsumption", tout << c1 << " subsumed " << c2 << "\n";); remove_clause(c2); m_num_subsumed++; @@ -759,7 +759,7 @@ namespace sat { SASSERT(wlist[j] == w); TRACE("set_not_learned_bug", tout << "marking as not learned: " << l2 << " " << wlist[j].is_learned() << "\n";); - wlist[j].set_not_learned(); + wlist[j].set_learned(false); mark_as_not_learned_core(get_wlist(~l2), l); } if (s.inconsistent()) @@ -776,7 +776,7 @@ namespace sat { void simplifier::mark_as_not_learned_core(watch_list & wlist, literal l2) { for (watched & w : wlist) { if (w.is_binary_clause() && w.get_literal() == l2 && w.is_learned()) { - w.set_not_learned(); + w.set_learned(false); return; } } @@ -1793,7 +1793,7 @@ namespace sat { w = find_binary_watch(wlist1, l2); if (w) { if (w->is_learned()) - w->set_not_learned(); + w->set_learned(false); } else { wlist1.push_back(watched(l2, false)); @@ -1802,7 +1802,7 @@ namespace sat { w = find_binary_watch(wlist2, l1); if (w) { if (w->is_learned()) - w->set_not_learned(); + w->set_learned(false); } else { wlist2.push_back(watched(l1, false)); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 0c2d34dac..d21e773f3 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -336,13 +336,13 @@ namespace sat { watched* w0 = find_binary_watch(get_wlist(~l1), l2); if (w0) { if (w0->is_learned() && !learned) { - w0->set_not_learned(); + w0->set_learned(false); } w0 = find_binary_watch(get_wlist(~l2), l1); } if (w0) { if (w0->is_learned() && !learned) { - w0->set_not_learned(); + w0->set_learned(false); } return; } @@ -481,6 +481,19 @@ namespace sat { reinit = attach_nary_clause(c); } + void solver::set_learned(clause& c, bool learned) { + if (c.is_learned() == learned) + return; + + if (c.size() == 3) { + set_ternary_learned(get_wlist(~c[0]), c[1], c[2], learned); + set_ternary_learned(get_wlist(~c[1]), c[0], c[2], learned); + set_ternary_learned(get_wlist(~c[2]), c[0], c[1], learned); + } + c.set_learned(learned); + } + + /** \brief Select a watch literal starting the search at the given position. This method is only used for clauses created during the search. diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 8b97dc7ea..0370d634d 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -233,6 +233,7 @@ namespace sat { bool attach_nary_clause(clause & c); void attach_clause(clause & c, bool & reinit); void attach_clause(clause & c) { bool reinit; attach_clause(c, reinit); } + void set_learned(clause& c, bool learned); class scoped_disable_checkpoint { solver& s; public: @@ -611,7 +612,7 @@ namespace sat { clause * const * end_learned() const { return m_learned.end(); } clause_vector const& learned() const { return m_learned; } clause_vector const& clauses() const { return m_clauses; } - void collect_bin_clauses(svector & r, bool learned, bool learned_only = false) const; + void collect_bin_clauses(svector & r, bool learned, bool learned_only = false) const; // ----------------------- // diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index 1a0880282..d7c6520bd 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -52,7 +52,7 @@ namespace sat { } return nullptr; } - + void erase_binary_watch(watch_list& wlist, literal l) { watch_list::iterator it = wlist.begin(), end = wlist.end(); watch_list::iterator it2 = it; @@ -70,6 +70,30 @@ namespace sat { VERIFY(found); } + void erase_ternary_watch(watch_list& wlist, literal l1, literal l2) { + watch_list::iterator it = wlist.begin(), end = wlist.end(); + watch_list::iterator it2 = it; + bool found = false; + for (; it != end; ++it) { + if (it->is_ternary_clause() && it->get_literal1() == l1 && it->get_literal2() == l2) { + found = true; + continue; + } + *it2 = *it; + ++it2; + } + wlist.set_end(it2); + VERIFY(found); + } + + void set_ternary_learned(watch_list& wlist, literal l1, literal l2, bool learned) { + for (watched& w : wlist) { + if (w.is_ternary_clause() && w.get_literal1() == l1 && w.get_literal2() == l2) { + w.set_learned(learned); + } + } + } + void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist) { watch_list::iterator end = wlist.end(); for (; it != end; ++it, ++it2) diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 88b6f3e51..8979405ae 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -33,7 +33,7 @@ namespace sat { For binary clauses: we use a bit to store whether the binary clause was learned or not. - Remark: there is not Clause object for binary clauses. + Remark: there are no clause objects for binary clauses. */ class watched { public: @@ -87,13 +87,12 @@ namespace sat { bool is_binary_clause() const { return get_kind() == BINARY; } literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(static_cast(m_val1)); } void set_literal(literal l) { SASSERT(is_binary_clause()); m_val1 = l.to_uint(); } - bool is_learned() const { SASSERT(is_binary_clause()); return (m_val2 >> 2) == 1; } + bool is_learned() const { SASSERT(is_binary_clause() || is_ternary_clause()); return ((m_val2 >> 2) & 1) == 1; } bool is_binary_learned_clause() const { return is_binary_clause() && is_learned(); } bool is_binary_non_learned_clause() const { return is_binary_clause() && !is_learned(); } - void set_not_learned() { SASSERT(is_learned()); m_val2 &= 0x3; SASSERT(!is_learned()); } - void set_learned() { SASSERT(!is_learned()); m_val2 |= 0x4; SASSERT(is_learned()); } + void set_learned(bool l) { SASSERT(is_learned() != l); if (l) m_val2 |= 4; else m_val2 &= 3; SASSERT(is_learned() == l); } bool is_ternary_clause() const { return get_kind() == TERNARY; } literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast(m_val1)); } @@ -136,7 +135,8 @@ namespace sat { watched* find_binary_watch(watch_list & wlist, literal l); watched const* find_binary_watch(watch_list const & wlist, literal l); bool erase_clause_watch(watch_list & wlist, clause_offset c); - inline void erase_ternary_watch(watch_list & wlist, literal l1, literal l2) { wlist.erase(watched(l1, l2, true)); wlist.erase(watched(l1, l2, false)); } + void erase_ternary_watch(watch_list & wlist, literal l1, literal l2); + void set_ternary_learned(watch_list& wlist, literal l1, literal l2, bool learned); class clause_allocator; std::ostream& display_watch_list(std::ostream & out, clause_allocator const & ca, watch_list const & wlist); From 177414c0ee82e10d9243fac9be219f7bf951b766 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 30 Jan 2018 21:43:56 +0700 Subject: [PATCH 0498/1283] Use const refs to reduce copying. These are things that have been found by `clang-tidy`. --- src/ast/proofs/proof_utils.h | 2 +- src/cmd_context/cmd_context.h | 2 +- src/duality/duality.h | 2 +- src/duality/duality_rpfp.cpp | 4 ++-- src/duality/duality_solver.cpp | 2 +- src/duality/duality_wrapper.h | 16 ++++++++-------- src/muz/base/dl_context.cpp | 4 ++-- src/muz/base/dl_context.h | 2 +- src/muz/base/dl_util.cpp | 8 ++++---- src/muz/base/dl_util.h | 12 ++++++------ src/muz/fp/datalog_parser.cpp | 6 +++--- src/muz/rel/dl_finite_product_relation.cpp | 4 ++-- src/muz/rel/dl_finite_product_relation.h | 4 ++-- src/muz/rel/dl_instruction.cpp | 8 ++++---- src/muz/rel/dl_instruction.h | 8 ++++---- src/muz/rel/dl_mk_explanations.cpp | 2 +- src/muz/rel/dl_product_relation.cpp | 2 +- src/muz/rel/dl_relation_manager.h | 8 ++++---- src/muz/rel/dl_sieve_relation.h | 2 +- src/muz/rel/dl_table_relation.cpp | 2 +- src/muz/spacer/spacer_context.cpp | 2 +- src/muz/spacer/spacer_context.h | 2 +- src/muz/spacer/spacer_matrix.cpp | 4 ++-- src/muz/spacer/spacer_matrix.h | 4 ++-- src/muz/spacer/spacer_unsat_core_learner.cpp | 2 +- src/muz/spacer/spacer_unsat_core_learner.h | 2 +- src/smt/smt_context.cpp | 2 +- src/smt/smt_context.h | 6 +++--- 28 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h index b953c834d..473df31e6 100644 --- a/src/ast/proofs/proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -88,7 +88,7 @@ class elim_aux_assertions { app_ref m_aux; public: - elim_aux_assertions(app_ref aux) : m_aux(aux) {} + elim_aux_assertions(app_ref aux) : m_aux(std::move(aux)) {} void mk_or_core(expr_ref_vector &args, expr_ref &res) { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 99d6c8284..212de585a 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -125,7 +125,7 @@ class stream_ref { std::ostream * m_stream; bool m_owner; public: - stream_ref(std::string n, std::ostream & d):m_default_name(n), m_default(d), m_name(n), m_stream(&d), m_owner(false) {} + stream_ref(const std::string& n, std::ostream & d):m_default_name(n), m_default(d), m_name(n), m_stream(&d), m_owner(false) {} ~stream_ref() { reset(); } void set(char const * name); void set(std::ostream& strm); diff --git a/src/duality/duality.h b/src/duality/duality.h index 657fa18b4..28cf96df3 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -66,7 +66,7 @@ namespace Duality { bool is_variable(const Term &t); - FuncDecl SuffixFuncDecl(Term t, int n); + FuncDecl SuffixFuncDecl(const Term &t, int n); Term SubstRecHide(hash_map &memo, const Term &t, int number); diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index 5dc2283ae..9dae5eba9 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -2157,7 +2157,7 @@ namespace Duality { std::vector la_pos_vars; bool fixing; - void IndexLAcoeff(const Term &coeff1, const Term &coeff2, Term t, int id) { + void IndexLAcoeff(const Term &coeff1, const Term &coeff2, const Term &t, int id) { Term coeff = coeff1 * coeff2; coeff = coeff.simplify(); Term is_pos = (coeff >= ctx.int_val(0)); @@ -3303,7 +3303,7 @@ namespace Duality { // This returns a new FuncDel with same sort as top-level function // of term t, but with numeric suffix appended to name. - Z3User::FuncDecl Z3User::SuffixFuncDecl(Term t, int n) + Z3User::FuncDecl Z3User::SuffixFuncDecl(const Term &t, int n) { std::string name = t.decl().name().str() + "_" + string_of_int(n); std::vector sorts; diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index 1711b65ad..15d79ba8d 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -107,7 +107,7 @@ namespace Duality { struct InternalError { std::string msg; - InternalError(const std::string _msg) + InternalError(const std::string & _msg) : msg(_msg) {} }; diff --git a/src/duality/duality_wrapper.h b/src/duality/duality_wrapper.h index 96c49b36b..18b6948d5 100644 --- a/src/duality/duality_wrapper.h +++ b/src/duality/duality_wrapper.h @@ -191,7 +191,7 @@ namespace Duality { sort int_sort(); sort real_sort(); sort bv_sort(unsigned sz); - sort array_sort(sort d, sort r); + sort array_sort(const sort & d, const sort & r); func_decl function(symbol const & name, unsigned arity, sort const * domain, sort const & range); func_decl function(char const * name, unsigned arity, sort const * domain, sort const & range); @@ -763,11 +763,11 @@ namespace Duality { unsigned size() const; func_decl operator[](unsigned i) const; - expr get_const_interp(func_decl f) const { + expr get_const_interp(const func_decl & f) const { return ctx().cook(m_model->get_const_interp(to_func_decl(f.raw()))); } - func_interp get_func_interp(func_decl f) const { + func_interp get_func_interp(const func_decl & f) const { return func_interp(ctx(),m_model->get_func_interp(to_func_decl(f.raw()))); } @@ -1169,7 +1169,7 @@ namespace Duality { ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); return sort(*this, s); } - inline sort context::array_sort(sort d, sort r) { + inline sort context::array_sort(const sort & d, const sort & r) { parameter params[2] = { parameter(d), parameter(to_sort(r)) }; ::sort * s = m().mk_sort(m_array_fid, ARRAY_SORT, 2, params); return sort(*this, s); @@ -1274,11 +1274,11 @@ namespace Duality { class TermTree { public: - TermTree(expr _term){ + TermTree(const expr &_term){ term = _term; } - TermTree(expr _term, const std::vector &_children){ + TermTree(const expr &_term, const std::vector &_children){ term = _term; children = _children; } @@ -1302,9 +1302,9 @@ namespace Duality { return num; } - inline void setTerm(expr t){term = t;} + inline void setTerm(const expr &t){term = t;} - inline void addTerm(expr t){terms.push_back(t);} + inline void addTerm(const expr &t){terms.push_back(t);} inline void setChildren(const std::vector & _children){ children = _children; diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 39e044ec3..78860bdde 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -400,7 +400,7 @@ namespace datalog { } uint64 res; if (!try_get_sort_constant_count(srt, res)) { - sort_size sz = srt->get_num_elements(); + const sort_size & sz = srt->get_num_elements(); if (sz.is_finite()) { res = sz.size(); } @@ -411,7 +411,7 @@ namespace datalog { return res; } - void context::set_argument_names(const func_decl * pred, svector var_names) + void context::set_argument_names(const func_decl * pred, const svector & var_names) { SASSERT(!m_argument_var_names.contains(pred)); m_argument_var_names.insert(pred, var_names); diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 129277514..0fb68d396 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -368,7 +368,7 @@ namespace datalog { These names are used when printing out the relations to make the output conform to the one of bddbddb. */ - void set_argument_names(const func_decl * pred, svector var_names); + void set_argument_names(const func_decl * pred, const svector & var_names); symbol get_argument_name(const func_decl * pred, unsigned arg_index); void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index fad424b90..e391da381 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -547,7 +547,7 @@ namespace datalog { // // ----------------------------------- - void get_file_names(std::string directory, std::string extension, bool traverse_subdirs, + void get_file_names(std::string directory, const std::string & extension, bool traverse_subdirs, string_vector & res) { if(directory[directory.size()-1]!='\\' && directory[directory.size()-1]!='/') { @@ -595,7 +595,7 @@ namespace datalog { #endif } - bool file_exists(std::string name) { + bool file_exists(const std::string & name) { struct stat st; if(stat(name.c_str(),&st) == 0) { return true; @@ -603,7 +603,7 @@ namespace datalog { return false; } - bool is_directory(std::string name) { + bool is_directory(const std::string & name) { if(!file_exists(name)) { return false; } @@ -612,7 +612,7 @@ namespace datalog { return (status.st_mode&S_IFDIR)!=0; } - std::string get_file_name_without_extension(std::string name) { + std::string get_file_name_without_extension(const std::string & name) { size_t slash_index = name.find_last_of("\\/"); size_t dot_index = name.rfind("."); size_t ofs = (slash_index==std::string::npos) ? 0 : slash_index+1; diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index 6b689fd17..32f016f63 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -290,7 +290,7 @@ namespace datalog { } template - void project_out_vector_columns(T & container, const unsigned_vector removed_cols) { + void project_out_vector_columns(T & container, const unsigned_vector & removed_cols) { project_out_vector_columns(container, removed_cols.size(), removed_cols.c_ptr()); } @@ -342,7 +342,7 @@ namespace datalog { } template - void permutate_by_cycle(T & container, const unsigned_vector permutation_cycle) { + void permutate_by_cycle(T & container, const unsigned_vector & permutation_cycle) { permutate_by_cycle(container, permutation_cycle.size(), permutation_cycle.c_ptr()); } @@ -578,13 +578,13 @@ namespace datalog { // // ----------------------------------- - void get_file_names(std::string directory, std::string extension, bool traverse_subdirs, + void get_file_names(std::string directory, const std::string & extension, bool traverse_subdirs, string_vector & res); - bool file_exists(std::string name); - bool is_directory(std::string name); + bool file_exists(const std::string & name); + bool is_directory(const std::string & name); - std::string get_file_name_without_extension(std::string name); + std::string get_file_name_without_extension(const std::string & name); // ----------------------------------- // diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index 7191f1931..f839c5c5a 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -1303,7 +1303,7 @@ private: } } - void parse_rules_file(std::string fname) { + void parse_rules_file(const std::string & fname) { SASSERT(file_exists(fname)); flet flet_cur_file(m_current_file, fname); @@ -1347,7 +1347,7 @@ private: return true; } - void parse_rel_file(std::string fname) { + void parse_rel_file(const std::string & fname) { SASSERT(file_exists(fname)); IF_VERBOSE(10, verbose_stream() << "Parsing relation file " << fname << "\n";); @@ -1496,7 +1496,7 @@ private: return true; } - void parse_map_file(std::string fname) { + void parse_map_file(const std::string & fname) { SASSERT(file_exists(fname)); IF_VERBOSE(10, verbose_stream() << "Parsing map file " << fname << "\n";); diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index c036d3cfd..163ba1b0b 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -1924,7 +1924,7 @@ namespace datalog { } } - void finite_product_relation::extract_table_fact(const relation_fact rf, table_fact & tf) const { + void finite_product_relation::extract_table_fact(const relation_fact & rf, table_fact & tf) const { const relation_signature & sig = get_signature(); relation_manager & rmgr = get_manager(); @@ -1940,7 +1940,7 @@ namespace datalog { tf.push_back(0); } - void finite_product_relation::extract_other_fact(const relation_fact rf, relation_fact & of) const { + void finite_product_relation::extract_other_fact(const relation_fact & rf, relation_fact & of) const { of.reset(); unsigned o_sz = m_other_sig.size(); for(unsigned i=0; idisplay_indented(ctx, out, indentation+" "); } }; @@ -1182,7 +1182,7 @@ namespace datalog { } } - void instruction_block::display_indented(execution_context const& _ctx, std::ostream & out, std::string indentation) const { + void instruction_block::display_indented(execution_context const& _ctx, std::ostream & out, const std::string & indentation) const { rel_context const& ctx = _ctx.get_rel_context(); instr_seq_type::const_iterator it = m_data.begin(); instr_seq_type::const_iterator end = m_data.end(); diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index 56dd249a5..d2e1c30f5 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -150,7 +150,7 @@ namespace datalog { return m_reg_annotation.find(reg, res); } - void set_register_annotation(reg_idx reg, std::string str) { + void set_register_annotation(reg_idx reg, const std::string & str) { m_reg_annotation.insert(reg, str); } @@ -233,7 +233,7 @@ namespace datalog { Each line must be prepended by \c indentation and ended by a newline character. */ - virtual void display_body_impl(execution_context const & ctx, std::ostream & out, std::string indentation) const {} + virtual void display_body_impl(execution_context const & ctx, std::ostream & out, const std::string & indentation) const {} void log_verbose(execution_context& ctx); public: @@ -249,7 +249,7 @@ namespace datalog { void display(execution_context const& ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(execution_context const & ctx, std::ostream & out, std::string indentation) const; + void display_indented(execution_context const & ctx, std::ostream & out, const std::string & indentation) const; static instruction * mk_load(ast_manager & m, func_decl * pred, reg_idx tgt); /** @@ -359,7 +359,7 @@ namespace datalog { void display(execution_context const & ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(execution_context const & ctx, std::ostream & out, std::string indentation) const; + void display_indented(execution_context const & ctx, std::ostream & out, const std::string & indentation) const; unsigned num_instructions() const { return m_data.size(); } }; diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index c4fb57eeb..ca04ca099 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -454,7 +454,7 @@ namespace datalog { : m_manager(ctx.get_manager()), m_subst(ctx.get_var_subst()), m_col_idx(col_idx), - m_new_rule(new_rule) {} + m_new_rule(std::move(new_rule)) {} virtual void operator()(relation_base & r0) { explanation_relation & r = static_cast(r0); diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index 8a2029748..1a91d6828 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -488,7 +488,7 @@ namespace datalog { ptr_vector m_transforms; public: transform_fn(relation_signature s, unsigned num_trans, relation_transformer_fn** trans): - m_sig(s), + m_sig(std::move(s)), m_transforms(num_trans, trans) {} ~transform_fn() { dealloc_ptr_vector_content(m_transforms); } diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 610c523e1..088b246e4 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -289,7 +289,7 @@ namespace datalog { relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, const unsigned * permutation); relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, - const unsigned_vector permutation) { + const unsigned_vector & permutation) { SASSERT(t.get_signature().size()==permutation.size()); return mk_permutation_rename_fn(t, permutation.c_ptr()); } @@ -343,7 +343,7 @@ namespace datalog { relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, const unsigned * identical_cols); - relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, const unsigned_vector identical_cols) { + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, const unsigned_vector & identical_cols) { return mk_filter_identical_fn(t, identical_cols.size(), identical_cols.c_ptr()); } @@ -468,7 +468,7 @@ namespace datalog { of column number. */ table_transformer_fn * mk_permutation_rename_fn(const table_base & t, const unsigned * permutation); - table_transformer_fn * mk_permutation_rename_fn(const table_base & t, const unsigned_vector permutation) { + table_transformer_fn * mk_permutation_rename_fn(const table_base & t, const unsigned_vector & permutation) { SASSERT(t.get_signature().size()==permutation.size()); return mk_permutation_rename_fn(t, permutation.c_ptr()); } @@ -522,7 +522,7 @@ namespace datalog { table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, const unsigned * identical_cols); - table_mutator_fn * mk_filter_identical_fn(const table_base & t, const unsigned_vector identical_cols) { + table_mutator_fn * mk_filter_identical_fn(const table_base & t, const unsigned_vector & identical_cols) { return mk_filter_identical_fn(t, identical_cols.size(), identical_cols.c_ptr()); } diff --git a/src/muz/rel/dl_sieve_relation.h b/src/muz/rel/dl_sieve_relation.h index 021c9d8df..e369e04aa 100644 --- a/src/muz/rel/dl_sieve_relation.h +++ b/src/muz/rel/dl_sieve_relation.h @@ -108,7 +108,7 @@ namespace datalog { sieve_relation * mk_from_inner(const relation_signature & s, const bool * inner_columns, relation_base * inner_rel); - sieve_relation * mk_from_inner(const relation_signature & s, const svector inner_columns, + sieve_relation * mk_from_inner(const relation_signature & s, const svector & inner_columns, relation_base * inner_rel) { SASSERT(inner_columns.size()==s.size()); return mk_from_inner(s, inner_columns.c_ptr(), inner_rel); diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index d8f1c7314..b8cf8e724 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -240,7 +240,7 @@ namespace datalog { const table_relation & tr_src = static_cast(src); relation_manager & rmgr = tr_src.get_manager(); - relation_signature sig = tr_src.get_signature(); + const relation_signature & sig = tr_src.get_signature(); SASSERT(tgt.get_signature()==sig); SASSERT(!delta || delta->get_signature()==sig); diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index b057730d8..28ff7d787 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -3418,7 +3418,7 @@ expr_ref context::get_constraints (unsigned level) return m_pm.mk_and (constraints); } -void context::add_constraints (unsigned level, expr_ref c) +void context::add_constraints (unsigned level, const expr_ref& c) { if (!c.get()) { return; } if (m.is_true(c)) { return; } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index cb422d08f..898c1639e 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -833,7 +833,7 @@ public: pob& get_root() const { return m_pob_queue.get_root(); } expr_ref get_constraints (unsigned lvl); - void add_constraints (unsigned lvl, expr_ref c); + void add_constraints (unsigned lvl, const expr_ref& c); }; inline bool pred_transformer::use_native_mbp () {return ctx.use_native_mbp ();} diff --git a/src/muz/spacer/spacer_matrix.cpp b/src/muz/spacer/spacer_matrix.cpp index 3cc83996c..ea9b3cb32 100644 --- a/src/muz/spacer/spacer_matrix.cpp +++ b/src/muz/spacer/spacer_matrix.cpp @@ -42,7 +42,7 @@ namespace spacer return m_num_cols; } - rational spacer_matrix::get(unsigned int i, unsigned int j) + const rational& spacer_matrix::get(unsigned int i, unsigned int j) { SASSERT(i < m_num_rows); SASSERT(j < m_num_cols); @@ -50,7 +50,7 @@ namespace spacer return m_matrix[i][j]; } - void spacer_matrix::set(unsigned int i, unsigned int j, rational v) + void spacer_matrix::set(unsigned int i, unsigned int j, const rational& v) { SASSERT(i < m_num_rows); SASSERT(j < m_num_cols); diff --git a/src/muz/spacer/spacer_matrix.h b/src/muz/spacer/spacer_matrix.h index 4fc418f2b..5e6dabea8 100644 --- a/src/muz/spacer/spacer_matrix.h +++ b/src/muz/spacer/spacer_matrix.h @@ -30,8 +30,8 @@ namespace spacer { unsigned num_rows(); unsigned num_cols(); - rational get(unsigned i, unsigned j); - void set(unsigned i, unsigned j, rational v); + const rational& get(unsigned i, unsigned j); + void set(unsigned i, unsigned j, const rational& v); unsigned perform_gaussian_elimination(); diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index d478b1e8f..bc066d32d 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -301,7 +301,7 @@ public: void operator()(quantifier*) {} }; -void unsat_core_learner::collect_symbols_b(expr_set axioms_b) +void unsat_core_learner::collect_symbols_b(const expr_set& axioms_b) { expr_mark visited; collect_pure_proc proc(m_symbols_b); diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index a7c9f6aa7..87238b5fd 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -82,7 +82,7 @@ namespace spacer { private: ptr_vector m_plugins; func_decl_set m_symbols_b; // symbols, which occur in any b-asserted formula - void collect_symbols_b(expr_set axioms_b); + void collect_symbols_b(const expr_set& axioms_b); ast_mark m_a_mark; ast_mark m_b_mark; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a87042e2b..375ff7e6f 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1791,7 +1791,7 @@ namespace smt { } } - void context::set_conflict(b_justification js, literal not_l) { + void context::set_conflict(const b_justification & js, literal not_l) { if (!inconsistent()) { TRACE("set_conflict", display_literal_verbose(tout, not_l); display(tout, js); ); m_conflict = js; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index e50c03c8a..55d8f03f2 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -897,7 +897,7 @@ namespace smt { void trace_assign(literal l, b_justification j, bool decision) const; public: - void assign(literal l, b_justification j, bool decision = false) { + void assign(literal l, const b_justification & j, bool decision = false) { SASSERT(l != false_literal); SASSERT(l != null_literal); switch (get_assignment(l)) { @@ -998,9 +998,9 @@ namespace smt { void assign_quantifier(quantifier * q); - void set_conflict(b_justification js, literal not_l); + void set_conflict(const b_justification & js, literal not_l); - void set_conflict(b_justification js) { + void set_conflict(const b_justification & js) { set_conflict(js, null_literal); } From 6d6b61492456af67958d23b8ea22d6833e4e3ff9 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 30 Jan 2018 21:45:12 +0700 Subject: [PATCH 0499/1283] Use char version of rfind. There is only a single character involved, so use the char version. This was found via `clang-tidy`. --- src/muz/base/dl_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index fad424b90..787dc6cfa 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -614,7 +614,7 @@ namespace datalog { std::string get_file_name_without_extension(std::string name) { size_t slash_index = name.find_last_of("\\/"); - size_t dot_index = name.rfind("."); + size_t dot_index = name.rfind('.'); size_t ofs = (slash_index==std::string::npos) ? 0 : slash_index+1; size_t count = (dot_index!=std::string::npos && dot_index>ofs) ? (dot_index-ofs) : std::string::npos; From 2d0f80f78ede999250f8465eb2a154c54e7b9bef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2018 09:22:36 -0800 Subject: [PATCH 0500/1283] add cce minimization Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.h | 4 +- src/sat/sat_integrity_checker.cpp | 8 +-- src/sat/sat_simplifier.cpp | 86 +++++++++++++++++++++++++++++-- 3 files changed, 86 insertions(+), 12 deletions(-) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 1477cc6e3..f9e3bb33f 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -155,8 +155,8 @@ namespace sat { }; unsigned m_l2_idx; public: - clause_wrapper(literal l1, literal l2):m_l1_idx(l1.to_uint()), m_l2_idx(l2.to_uint()) {} - clause_wrapper(clause & c):m_cls(&c), m_l2_idx(null_literal.to_uint()) {} + explicit clause_wrapper(literal l1, literal l2):m_l1_idx(l1.to_uint()), m_l2_idx(l2.to_uint()) {} + explicit clause_wrapper(clause & c):m_cls(&c), m_l2_idx(null_literal.to_uint()) {} clause_wrapper& operator=(clause_wrapper const& other) { if (other.is_binary()) { m_l1_idx = other.m_l1_idx; diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index f68dc80df..d09fb9581 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -202,12 +202,8 @@ namespace sat { } bool integrity_checker::check_reinit_stack() const { - clause_wrapper_vector::const_iterator it = s.m_clauses_to_reinit.begin(); - clause_wrapper_vector::const_iterator end = s.m_clauses_to_reinit.end(); - for (; it != end; ++it) { - if (it->is_binary()) - continue; - SASSERT(it->get_clause()->on_reinit_stack()); + for (auto const& c : s.m_clauses_to_reinit) { + SASSERT(c.is_binary() || c.get_clause()->on_reinit_stack()); } return true; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 577badbc8..c7addcffc 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -943,6 +943,27 @@ namespace sat { } }; + class clause_ante { + literal m_lit1; + literal m_lit2; + clause* m_clause; + public: + clause_ante(): + m_lit1(null_literal), m_lit2(null_literal), m_clause(nullptr) {} + clause_ante(literal l1): + m_lit1(l1), m_lit2(null_literal), m_clause(nullptr) {} + clause_ante(literal l1, literal l2): + m_lit1(l1), m_lit2(l2), m_clause(nullptr) {} + clause_ante(clause& c): + m_lit1(null_literal), m_lit2(null_literal), m_clause(&c) {} + literal lit1() const { return m_lit1; } + literal lit2() const { return m_lit2; } + clause* cls() const { return m_clause; } + bool operator==(clause_ante const& a) const { + return a.m_lit1 == m_lit1 && a.m_lit2 == m_lit2 && a.m_clause == m_clause; + } + }; + class queue { heap m_queue; public: @@ -972,6 +993,7 @@ namespace sat { clause_vector m_to_remove; literal_vector m_covered_clause; + svector m_covered_antecedent; literal_vector m_intersection; literal_vector m_new_intersection; literal_vector m_blocked_binary; @@ -1229,6 +1251,41 @@ namespace sat { return !m_clause.is_binary() && (m_clause.get_clause() == &c); } + void minimize_covered_clause(unsigned idx) { + IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause << " @ " << idx << "\n";); + for (literal l : m_covered_clause) s.unmark_visited(l); + s.mark_visited(m_covered_clause[idx]); + for (unsigned i = idx; i > 0; --i) { + literal lit = m_covered_clause[i]; + if (!s.is_marked(lit)) continue; + clause_ante const& ante = m_covered_antecedent[i]; + if (ante.cls()) { + for (literal l : *ante.cls()) { + IF_VERBOSE(0, verbose_stream() << "clause ante: " << l << "\n";); + if (l != ~lit) s.mark_visited(l); + } + } + if (ante.lit1() != null_literal) { + IF_VERBOSE(0, verbose_stream() << "ante1: " << ante.lit1() << "\n";); + s.mark_visited(ante.lit1()); + } + if (ante.lit2() != null_literal) { + IF_VERBOSE(0, verbose_stream() << "ante2: " << ante.lit2() << "\n";); + s.mark_visited(ante.lit2()); + } + } + unsigned j = 0; + for (unsigned i = 0; i <= idx; ++i) { + literal lit = m_covered_clause[i]; + if (s.is_marked(lit) || m_covered_antecedent[i] == clause_ante()) { + m_covered_clause[j++] = lit; + s.unmark_visited(lit); + } + } + m_covered_clause.resize(j); + IF_VERBOSE(0, verbose_stream() << "reduced: " << m_covered_clause << "\n";); + } + /* * C \/ l l \/ lit * ------------------- @@ -1257,6 +1314,7 @@ namespace sat { if (!s.is_marked(~lit)) { IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " binary " << l << " " << lit << " " << (~lit) << "\n";); m_covered_clause.push_back(~lit); + m_covered_antecedent.push_back(clause_ante(l)); s.mark_visited(~lit); } } @@ -1271,12 +1329,14 @@ namespace sat { if (s.is_marked(lit1) && !s.is_marked(~lit2)) { IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " ternary " << l << " " << lit1 << " " << lit2 << " " << (~lit2) << "\n";); m_covered_clause.push_back(~lit2); + m_covered_antecedent.push_back(clause_ante(l, lit1)); s.mark_visited(~lit2); continue; } if (s.is_marked(lit2) && !s.is_marked(~lit1)) { IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " ternay " << l << " " << lit1 << " " << lit2 << " " << (~lit1) << "\n";); m_covered_clause.push_back(~lit1); + m_covered_antecedent.push_back(clause_ante(l, lit2)); s.mark_visited(~lit1); continue; } @@ -1305,6 +1365,7 @@ namespace sat { } IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " clause " << c << " " << (~lit1) << "\n";); m_covered_clause.push_back(~lit1); + m_covered_antecedent.push_back(clause_ante(c)); s.mark_visited(~lit1); } } @@ -1322,8 +1383,10 @@ namespace sat { */ bool add_cla(literal& blocked) { for (unsigned i = 0; i < m_covered_clause.size(); ++i) { - if (resolution_intersection(m_covered_clause[i], false)) { + literal lit = m_covered_clause[i]; + if (resolution_intersection(lit, false)) { blocked = m_covered_clause[i]; + minimize_covered_clause(i); return true; } if (!m_intersection.empty()) { @@ -1333,6 +1396,7 @@ namespace sat { if (!s.is_marked(l)) { s.mark_visited(l); m_covered_clause.push_back(l); + m_covered_antecedent.push_back(clause_ante(lit)); } } } @@ -1362,10 +1426,14 @@ namespace sat { * and then check if any of the first sz0 literals are blocked. */ if (et == abce_t) { - if (add_ala()) return at_t; + if (add_ala()) { + for (literal l : m_covered_clause) s.unmark_visited(l); + return at_t; + } for (unsigned i = 0; !is_tautology && i < sz0; ++i) { if (check_abce_tautology(m_covered_clause[i])) { blocked = m_covered_clause[i]; + minimize_covered_clause(i); is_tautology = true; break; } @@ -1391,7 +1459,10 @@ namespace sat { if (above_threshold(sz0)) break; if (et == acce_t && !is_tautology) { sz = m_covered_clause.size(); - if (add_ala()) return at_t; + if (add_ala()) { + for (literal l : m_covered_clause) s.unmark_visited(l); + return at_t; + } k = model_converter::ACCE; } } @@ -1408,7 +1479,11 @@ namespace sat { verdict_type cce(clause& c, literal& blocked, model_converter::kind& k) { m_clause = clause_wrapper(c); m_covered_clause.reset(); - for (literal l : c) m_covered_clause.push_back(l); + m_covered_antecedent.reset(); + for (literal l : c) { + m_covered_clause.push_back(l); + m_covered_antecedent.push_back(clause_ante()); + } return cla(blocked, k); } @@ -1416,8 +1491,11 @@ namespace sat { verdict_type cce(literal l1, literal l2, literal& blocked, model_converter::kind& k) { m_clause = clause_wrapper(l1, l2); m_covered_clause.reset(); + m_covered_antecedent.reset(); m_covered_clause.push_back(l1); m_covered_clause.push_back(l2); + m_covered_antecedent.push_back(clause_ante()); + m_covered_antecedent.push_back(clause_ante()); return cla(blocked, k); } From 2739342abab997e671b6cd8badd56eff76f129f0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2018 23:41:04 -0800 Subject: [PATCH 0501/1283] fix updates to cce Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 +- src/sat/sat_asymm_branch.cpp | 13 +- src/sat/sat_clause.cpp | 9 + src/sat/sat_clause.h | 2 +- src/sat/sat_cleaner.cpp | 5 +- src/sat/sat_elim_eqs.cpp | 4 +- src/sat/sat_elim_vars.cpp | 4 +- src/sat/sat_iff3_finder.cpp | 2 +- src/sat/sat_integrity_checker.cpp | 10 +- src/sat/sat_lookahead.cpp | 1 + src/sat/sat_simplifier.cpp | 371 ++++++++++++++---------------- src/sat/sat_simplifier.h | 17 +- src/sat/sat_solver.cpp | 32 +-- src/sat/sat_solver.h | 2 + src/sat/sat_watched.cpp | 18 +- src/sat/sat_watched.h | 10 +- 16 files changed, 248 insertions(+), 254 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 55a7713ce..42a78b5f1 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2798,7 +2798,7 @@ namespace sat { } unsigned ba_solver::get_num_unblocked_bin(literal l) { - return s().m_simplifier.get_num_unblocked_bin(l); + return s().m_simplifier.num_nonlearned_bin(l); } /* diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 1b37e4dbc..b05de55e6 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -60,7 +60,7 @@ namespace sat { verbose_stream() << " (sat-asymm-branch :elim-literals " << (num_total - num_learned) << " :elim-learned-literals " << num_learned - << " :hidden-tautologies " << (m_asymm_branch.m_hidden_tautologies - m_hidden_tautologies) + << " :hte " << (m_asymm_branch.m_hidden_tautologies - m_hidden_tautologies) << " :cost " << m_asymm_branch.m_counter << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); @@ -124,13 +124,13 @@ namespace sat { break; } SASSERT(s.m_qhead == s.m_trail.size()); - if (m_counter < limit || s.inconsistent()) { + clause & c = *(*it); + if (m_counter < limit || s.inconsistent() || c.was_removed()) { *it2 = *it; ++it2; continue; } - s.checkpoint(); - clause & c = *(*it); + s.checkpoint(); if (big ? !process_sampled(*big, c) : !process(c)) { continue; // clause was removed } @@ -431,7 +431,8 @@ namespace sat { bool asymm_branch::process_sampled(big& big, clause & c) { scoped_detach scoped_d(s, c); sort(big, c); - if ((c.is_learned() || !big.learned()) && uhte(big, c)) { + if (!big.learned() && !c.is_learned() && uhte(big, c)) { + // TBD: mark clause as learned. ++m_hidden_tautologies; scoped_d.del_clause(); return false; @@ -501,7 +502,7 @@ namespace sat { void asymm_branch::collect_statistics(statistics & st) const { st.update("elim literals", m_elim_literals); - st.update("hidden tautologies", m_hidden_tautologies); + st.update("hte", m_hidden_tautologies); } void asymm_branch::reset_statistics() { diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 3600ac1a3..f433f884d 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -87,6 +87,15 @@ namespace sat { mark_strengthened(); } + void clause::shrink(unsigned num_lits) { + SASSERT(num_lits <= m_size); + if (num_lits < m_size) { + m_size = num_lits; + mark_strengthened(); + } + } + + bool clause::satisfied_by(model const & m) const { for (literal l : *this) { if (l.sign()) { diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index f9e3bb33f..c7273f57d 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -66,7 +66,7 @@ namespace sat { literal const & operator[](unsigned idx) const { SASSERT(idx < m_size); return m_lits[idx]; } bool is_learned() const { return m_learned; } void set_learned(bool l) { SASSERT(is_learned() != l); m_learned = l; } - void shrink(unsigned num_lits) { SASSERT(num_lits <= m_size); if (num_lits < m_size) { m_size = num_lits; mark_strengthened(); } } + void shrink(unsigned num_lits); bool strengthened() const { return m_strengthened; } void mark_strengthened() { m_strengthened = true; update_approx(); } void unmark_strengthened() { m_strengthened = false; } diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 286cc1661..3d0899692 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -145,10 +145,7 @@ namespace sat { *it2 = *it; it2++; if (!c.frozen()) { - if (new_sz == 3) - s.attach_ter_clause(c); - else - s.attach_nary_clause(c); + s.attach_clause(c); } if (s.m_config.m_drat) { // for optimization, could also report deletion diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 270ae9d04..b178c52e2 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -95,10 +95,10 @@ namespace sat { m_solver.detach_clause(c); // apply substitution for (i = 0; i < sz; i++) { - literal lit = c[i]; + literal lit = c[i]; c[i] = norm(roots, lit); VERIFY(c[i] == norm(roots, c[i])); - VERIFY(!m_solver.was_eliminated(c[i].var()) || lit == c[i]); + VERIFY(!m_solver.was_eliminated(c[i].var()) || lit == c[i]); } std::sort(c.begin(), c.end()); for (literal l : c) VERIFY(l == norm(roots, l)); diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 0adcc95ef..34f871a8f 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -37,9 +37,9 @@ namespace sat{ literal pos_l(v, false); literal neg_l(v, true); - unsigned num_bin_pos = simp.get_num_unblocked_bin(pos_l); + unsigned num_bin_pos = simp.num_nonlearned_bin(pos_l); if (num_bin_pos > m_max_literals) return false; - unsigned num_bin_neg = simp.get_num_unblocked_bin(neg_l); + unsigned num_bin_neg = simp.num_nonlearned_bin(neg_l); if (num_bin_neg > m_max_literals) return false; clause_use_list & pos_occs = simp.m_use_list.get(pos_l); clause_use_list & neg_occs = simp.m_use_list.get(neg_l); diff --git a/src/sat/sat_iff3_finder.cpp b/src/sat/sat_iff3_finder.cpp index 8bbfc0ce0..af7a6f438 100644 --- a/src/sat/sat_iff3_finder.cpp +++ b/src/sat/sat_iff3_finder.cpp @@ -73,7 +73,7 @@ namespace sat { It assumes wlist have been sorted using iff3_lt */ static bool contains(watch_list const & wlist, literal l1, literal l2) { - watched k(l1, l2, false); + watched k(l1, l2); if (wlist.size() < SMALL_WLIST) return wlist.contains(k); iff3_lt lt; diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index d09fb9581..d581dbd36 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -28,8 +28,8 @@ namespace sat { } // for ternary clauses - static bool contains_watched(watch_list const & wlist, literal l1, literal l2, bool learned) { - return wlist.contains(watched(l1, l2, learned)); + static bool contains_watched(watch_list const & wlist, literal l1, literal l2) { + return wlist.contains(watched(l1, l2)); } // for nary clauses @@ -68,9 +68,9 @@ namespace sat { tout << "watch_list:\n"; sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~c[0])); tout << "\n";); - VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2], c.is_learned())); - VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2], c.is_learned())); - VERIFY(contains_watched(s.get_wlist(~c[2]), c[0], c[1], c.is_learned())); + VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2])); + VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2])); + VERIFY(contains_watched(s.get_wlist(~c[2]), c[0], c[1])); } else { if (s.value(c[0]) == l_false || s.value(c[1]) == l_false) { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 94f73dffc..5bf3a194d 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2306,6 +2306,7 @@ namespace sat { roots[v] = p; VERIFY(get_parent(p) == p); VERIFY(get_parent(~p) == ~p); + IF_VERBOSE(0, verbose_stream() << p << " " << q << "\n";); } } IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index c7addcffc..3e7b32eb4 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -148,27 +148,17 @@ namespace sat { m_use_list.erase(c, l); } - inline void simplifier::block_clause(clause & c) { - if (m_retain_blocked_clauses) { - m_need_cleanup = true; - s.set_learned(c, true); - m_use_list.block(c); - } - else { - remove_clause(c); - } - + inline void simplifier::set_learned(clause & c) { + m_need_cleanup = true; + s.set_learned(c, true); + m_use_list.block(c); } - inline void simplifier::unblock_clause(clause & c) { - s.set_learned(c, false); - m_use_list.unblock(c); - } - - inline void simplifier::remove_bin_clause_half(literal l1, literal l2, bool learned) { - get_wlist(~l1).erase(watched(l2, learned)); - m_sub_bin_todo.erase(bin_clause(l1, l2, learned)); - m_sub_bin_todo.erase(bin_clause(l2, l1, learned)); + inline void simplifier::set_learned(literal l1, literal l2) { + m_sub_bin_todo.erase(bin_clause(l1, l2, false)); + m_sub_bin_todo.erase(bin_clause(l2, l1, false)); + m_sub_bin_todo.push_back(bin_clause(l1, l2, true)); + m_sub_bin_todo.push_back(bin_clause(l2, l1, true)); } void simplifier::init_visited() { @@ -308,13 +298,16 @@ namespace sat { clause_vector::iterator it = cs.begin(); clause_vector::iterator it2 = it; clause_vector::iterator end = cs.end(); + unsigned nm = 0; for (; it != end; ++it) { clause & c = *(*it); if (learned && !c.is_learned()) { s.m_clauses.push_back(&c); + ++nm; } else if (!learned && c.is_learned()) { s.m_learned.push_back(&c); + ++nm; } else { *it2 = *it; @@ -322,6 +315,7 @@ namespace sat { } } cs.set_end(it2); + IF_VERBOSE(0, verbose_stream() << "num moved: " << nm << "\n";); } void simplifier::cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists) { @@ -373,19 +367,10 @@ namespace sat { s.del_clause(c); continue; } - // clause became a learned clause - if (!learned && c.is_learned()) { - SASSERT(!c.frozen()); - s.m_learned.push_back(&c); - continue; - } *it2 = *it; it2++; if (!c.frozen()) { - if (sz == 3) - s.attach_ter_clause(c); - else - s.attach_nary_clause(c); + s.attach_clause(c); if (s.m_config.m_drat) { s.m_drat.add(c, true); } @@ -895,6 +880,10 @@ namespace sat { break; clause & c = m_sub_todo.erase(); + if (c.id() == 60127) { + IF_VERBOSE(0, verbose_stream() << "subsume " << c << "\n";); + } + c.unmark_strengthened(); m_sub_counter--; TRACE("subsumption", tout << "next: " << c << "\n";); @@ -904,6 +893,9 @@ namespace sat { continue; } unsigned sz = c.size(); + if (c.id() == 60127) { + IF_VERBOSE(0, verbose_stream() << "subsume " << c << "\n";); + } if (sz == 0) { s.set_conflict(justification()); return; @@ -990,11 +982,11 @@ namespace sat { int m_counter; model_converter & mc; queue m_queue; - clause_vector m_to_remove; literal_vector m_covered_clause; svector m_covered_antecedent; literal_vector m_intersection; + literal_vector m_tautology; literal_vector m_new_intersection; literal_vector m_blocked_binary; svector m_in_intersection; @@ -1084,39 +1076,25 @@ namespace sat { model_converter::entry* new_entry = 0; watch_list & wlist = s.get_wlist(~l); m_counter -= wlist.size(); - watch_list::iterator it = wlist.begin(); - watch_list::iterator it2 = it; - watch_list::iterator end = wlist.end(); - - for (; it != end; ++it) { - if (!it->is_binary_non_learned_clause()) { - *it2 = *it; it2++; + for (watched& w : wlist) { + if (!w.is_binary_non_learned_clause()) { continue; } - literal l2 = it->get_literal(); + literal l2 = w.get_literal(); s.mark_visited(l2); if (all_tautology(l)) { - block_binary(it, l, new_entry); - s.m_num_blocked_clauses++; + block_binary(w, l, new_entry); + w.set_learned(true); + s.s.set_learned1(l2, l, true); + s.m_num_bce++; m_blocked_binary.push_back(l2); } - else { - *it2 = *it; it2++; - } s.unmark_visited(l2); } - wlist.set_end(it2); - if (s.m_retain_blocked_clauses && !m_blocked_binary.empty()) { - IF_VERBOSE(0, verbose_stream() << "retaining " << m_blocked_binary.size() << " binary clauses\n";); - for (literal lit2 : m_blocked_binary) { - s.s.mk_bin_clause(l, lit2, true); - } - } } void process_clauses(literal l) { model_converter::entry* new_entry = 0; - m_to_remove.reset(); clause_use_list & occs = s.m_use_list.get(l); clause_use_list::iterator it = occs.mk_iterator(); for (; !it.at_end(); it.next()) { @@ -1127,12 +1105,11 @@ namespace sat { s.mark_all_but(c, l); if (all_tautology(l)) { block_clause(c, l, new_entry); - s.m_num_blocked_clauses++; + s.m_num_bce++; + s.set_learned(c); } s.unmark_all(c); - } - for (clause* c : m_to_remove) - s.block_clause(*c); + } } void reset_intersection() { @@ -1155,6 +1132,7 @@ namespace sat { if (!process_var(l.var())) return false; bool first = true; reset_intersection(); + m_tautology.reset(); for (watched & w : s.get_wlist(l)) { // when adding a blocked clause, then all non-learned clauses have to be considered for the // resolution intersection. @@ -1162,6 +1140,7 @@ namespace sat { if (process_bin) { literal lit = w.get_literal(); if (s.is_marked(~lit) && lit != ~l) { + m_tautology.push_back(~lit); continue; // tautology } if (!first || s.is_marked(lit)) { @@ -1178,8 +1157,10 @@ namespace sat { bool tautology = false; clause & c = it.curr(); if (c.is_learned() && !adding) continue; + if (c.was_removed()) continue; for (literal lit : c) { if (s.is_marked(~lit) && lit != ~l) { + m_tautology.push_back(~lit); tautology = true; break; } @@ -1204,25 +1185,30 @@ namespace sat { return false; } } + // if (first) IF_VERBOSE(0, verbose_stream() << "taut: " << m_tautology << "\n";); return first; } bool check_abce_tautology(literal l) { + m_tautology.reset(); if (!process_var(l.var())) return false; for (watched & w : s.get_wlist(l)) { if (w.is_binary_non_learned_clause()) { literal lit = w.get_literal(); - if (!s.is_marked(~lit) || lit == ~l) return false; + VERIFY(lit != ~l); + if (!s.is_marked(~lit)) return false; + m_tautology.push_back(~lit); } } clause_use_list & neg_occs = s.m_use_list.get(~l); for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) { clause & c = it.curr(); - if (c.is_learned()) continue; + if (c.is_learned() || c.was_removed()) continue; bool tautology = false; for (literal lit : c) { if (s.is_marked(~lit) && lit != ~l) { tautology = true; + m_tautology.push_back(~lit); break; } } @@ -1251,26 +1237,36 @@ namespace sat { return !m_clause.is_binary() && (m_clause.get_clause() == &c); } + /** + \brief idx is the index of the blocked literal. + m_tautology contains literals that were used to establish that the current members of m_covered_clause is blocked. + This routine removes literals that were not relevant to establishing it was blocked. + */ void minimize_covered_clause(unsigned idx) { - IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause << " @ " << idx << "\n";); + // IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause << " @ " << idx << "\n" << "tautology: " << m_tautology << "\n";); + for (literal l : m_tautology) VERIFY(s.is_marked(l)); for (literal l : m_covered_clause) s.unmark_visited(l); + for (literal l : m_tautology) s.mark_visited(l); s.mark_visited(m_covered_clause[idx]); + for (unsigned i = 0; i < m_covered_clause.size(); ++i) { + if (s.is_marked(m_covered_clause[i])) idx = i; + } for (unsigned i = idx; i > 0; --i) { literal lit = m_covered_clause[i]; if (!s.is_marked(lit)) continue; clause_ante const& ante = m_covered_antecedent[i]; if (ante.cls()) { + //IF_VERBOSE(0, verbose_stream() << "clause ante: " << lit << ": " << *ante.cls() << "\n";); for (literal l : *ante.cls()) { - IF_VERBOSE(0, verbose_stream() << "clause ante: " << l << "\n";); if (l != ~lit) s.mark_visited(l); } } if (ante.lit1() != null_literal) { - IF_VERBOSE(0, verbose_stream() << "ante1: " << ante.lit1() << "\n";); + //IF_VERBOSE(0, verbose_stream() << "ante1: " << lit << ": " << ante.lit1() << "\n";); s.mark_visited(ante.lit1()); } if (ante.lit2() != null_literal) { - IF_VERBOSE(0, verbose_stream() << "ante2: " << ante.lit2() << "\n";); + //IF_VERBOSE(0, verbose_stream() << "ante2: " << lit << ": " << ante.lit2() << "\n";); s.mark_visited(ante.lit2()); } } @@ -1282,8 +1278,16 @@ namespace sat { s.unmark_visited(lit); } } + // ensure that rest of literals from original clause are included + for (unsigned i = idx + 1; i < m_covered_clause.size() && m_covered_antecedent[i] == clause_ante(); ++i) { + literal lit = m_covered_clause[i]; + m_covered_clause[j++] = lit; + } + for (literal l : m_covered_clause) VERIFY(!s.is_marked(l)); + unsigned sz0 = m_covered_clause.size(); m_covered_clause.resize(j); - IF_VERBOSE(0, verbose_stream() << "reduced: " << m_covered_clause << "\n";); + VERIFY(j >= m_clause.size()); + // IF_VERBOSE(0, verbose_stream() << "reduced from size " << sz0 << " to " << m_covered_clause << "\n" << m_clause << "\n";); } /* @@ -1303,71 +1307,51 @@ namespace sat { bool add_ala() { for (; m_ala_qhead < m_covered_clause.size(); ++m_ala_qhead) { literal l = m_covered_clause[m_ala_qhead]; + for (watched & w : s.get_wlist(~l)) { if (w.is_binary_non_learned_clause()) { literal lit = w.get_literal(); if (revisit_binary(l, lit)) continue; if (s.is_marked(lit)) { - IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " binary: " << l << " " << lit << "\n";); + //IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " binary: " << l << " " << lit << "\n";); return true; } if (!s.is_marked(~lit)) { - IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " binary " << l << " " << lit << " " << (~lit) << "\n";); + //IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " binary " << l << " " << lit << " " << (~lit) << "\n";); m_covered_clause.push_back(~lit); m_covered_antecedent.push_back(clause_ante(l)); s.mark_visited(~lit); } } - else if (w.is_ternary_clause() && !w.is_learned()) { - literal lit1 = w.get_literal1(); - literal lit2 = w.get_literal2(); - if (revisit_ternary(l, lit1, lit2)) continue; - if (s.is_marked(lit1) && s.is_marked(lit2)) { - IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " ternary: " << l << " " << lit1 << " " << lit2 << "\n";); - return true; + } + clause_use_list & pos_occs = s.m_use_list.get(l); + clause_use_list::iterator it = pos_occs.mk_iterator(); + for (; !it.at_end(); it.next()) { + clause & c = it.curr(); + if (c.is_learned() || c.was_removed()) continue; + if (revisit_clause(c)) continue; + literal lit1 = null_literal; + bool ok = true; + for (literal lit : c) { + if (lit == l) continue; + if (s.is_marked(lit)) continue; + if (!s.is_marked(~lit) && lit1 == null_literal) { + lit1 = lit; } - if (s.is_marked(lit1) && !s.is_marked(~lit2)) { - IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " ternary " << l << " " << lit1 << " " << lit2 << " " << (~lit2) << "\n";); - m_covered_clause.push_back(~lit2); - m_covered_antecedent.push_back(clause_ante(l, lit1)); - s.mark_visited(~lit2); - continue; - } - if (s.is_marked(lit2) && !s.is_marked(~lit1)) { - IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " ternay " << l << " " << lit1 << " " << lit2 << " " << (~lit1) << "\n";); - m_covered_clause.push_back(~lit1); - m_covered_antecedent.push_back(clause_ante(l, lit2)); - s.mark_visited(~lit1); - continue; + else { + ok = false; + break; } } - else if (w.is_clause()) { - clause & c = s.s.get_clause(w.get_clause_offset()); - if (c.is_learned()) continue; - if (revisit_clause(c)) continue; - literal lit1 = null_literal; - bool ok = true; - for (literal lit : c) { - if (lit == l) continue; - if (s.is_marked(lit)) continue; - if (!s.is_marked(~lit) && lit1 == null_literal) { - lit1 = lit; - } - else { - ok = false; - break; - } - } - if (!ok) continue; - if (lit1 == null_literal) { - IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " clause " << c << "\n";); - return true; - } - IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " clause " << c << " " << (~lit1) << "\n";); - m_covered_clause.push_back(~lit1); - m_covered_antecedent.push_back(clause_ante(c)); - s.mark_visited(~lit1); + if (!ok) continue; + if (lit1 == null_literal) { + //IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " clause " << c << "\n";); + return true; } + // IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " clause " << c << " " << (~lit1) << "\n";); + m_covered_clause.push_back(~lit1); + m_covered_antecedent.push_back(clause_ante(c)); + s.mark_visited(~lit1); } } return false; @@ -1430,10 +1414,9 @@ namespace sat { for (literal l : m_covered_clause) s.unmark_visited(l); return at_t; } - for (unsigned i = 0; !is_tautology && i < sz0; ++i) { + for (unsigned i = 0; i < sz0; ++i) { if (check_abce_tautology(m_covered_clause[i])) { blocked = m_covered_clause[i]; - minimize_covered_clause(i); is_tautology = true; break; } @@ -1456,7 +1439,6 @@ namespace sat { is_tautology = add_cla(blocked); } while (m_covered_clause.size() > sz && !is_tautology); - if (above_threshold(sz0)) break; if (et == acce_t && !is_tautology) { sz = m_covered_clause.size(); if (add_ala()) { @@ -1465,9 +1447,9 @@ namespace sat { } k = model_converter::ACCE; } + if (above_threshold(sz0)) break; } while (m_covered_clause.size() > sz && !is_tautology); - // if (is_tautology) std::cout << num_iterations << " " << m_covered_clause.size() << " " << sz0 << " " << is_tautology << " " << m_elim_stack.size() << "\n"; for (literal l : m_covered_clause) s.unmark_visited(l); return (is_tautology && !above_threshold(sz0)) ? bc_t : no_t; } @@ -1484,6 +1466,7 @@ namespace sat { m_covered_clause.push_back(l); m_covered_antecedent.push_back(clause_ante()); } + // shuffle(s.s.m_rand, m_covered_clause); return cla(blocked, k); } @@ -1516,81 +1499,68 @@ namespace sat { template void process_cce_binary(literal l) { - m_blocked_binary.reset(); literal blocked = null_literal; watch_list & wlist = s.get_wlist(~l); m_counter -= wlist.size(); - watch_list::iterator it = wlist.begin(); - watch_list::iterator it2 = it; - watch_list::iterator end = wlist.end(); model_converter::kind k; - for (; it != end; ++it) { - if (!it->is_binary_non_learned_clause()) { - *it2 = *it; - it2++; - continue; - } - literal l2 = it->get_literal(); + for (watched & w : wlist) { + if (!w.is_binary_non_learned_clause()) continue; + literal l2 = w.get_literal(); switch (cce(l, l2, blocked, k)) { case bc_t: - block_covered_binary(it, l, blocked, k); - s.m_num_covered_clauses++; - m_blocked_binary.push_back(l2); + inc_bc(); + block_covered_binary(w, l, blocked, k); + w.set_learned(true); + s.s.set_learned1(l2, l, true); break; case at_t: s.m_num_ate++; - m_blocked_binary.push_back(l2); + w.set_learned(true); + s.s.set_learned1(l2, l, true); break; case no_t: - *it2 = *it; - it2++; break; } } - wlist.set_end(it2); - if (s.m_retain_blocked_clauses && !m_blocked_binary.empty()) { - IF_VERBOSE(0, verbose_stream() << "retaining " << m_blocked_binary.size() << " binary clauses\n";); - for (literal lit2 : m_blocked_binary) { - s.s.mk_bin_clause(l, lit2, true); - } - } } - template void cce_clauses() { - m_to_remove.reset(); literal blocked; model_converter::kind k; for (clause* cp : s.s.m_clauses) { clause& c = *cp; - if (!c.was_removed() && !c.is_learned()) { - switch (cce(c, blocked, k)) { - case bc_t: - block_covered_clause(c, blocked, k); - s.m_num_covered_clauses++; - break; - case at_t: - m_to_remove.push_back(&c); - break; - case no_t: - break; - } + if (c.was_removed() || c.is_learned()) continue; + switch (cce(c, blocked, k)) { + case bc_t: + inc_bc(); + block_covered_clause(c, blocked, k); + s.set_learned(c); + break; + case at_t: + s.m_num_ate++; + s.set_learned(c); + break; + case no_t: + break; } } - for (clause* c : m_to_remove) { - s.block_clause(*c); - } - m_to_remove.reset(); } + template + void inc_bc() { + switch (et) { + case cce_t: s.m_num_cce++; break; + case acce_t: s.m_num_acce++; break; + case abce_t: s.m_num_abce++; break; + } + } void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); VERIFY(!s.is_external(l)); if (new_entry == 0) new_entry = &(mc.mk(k, l.var())); - m_to_remove.push_back(&c); for (literal lit : c) { if (lit != l && process_var(lit.var())) { m_queue.decreased(~lit); @@ -1611,25 +1581,25 @@ namespace sat { mc.insert(*new_entry, m_covered_clause, m_elim_stack); } - void prepare_block_binary(watch_list::iterator it, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) { + void prepare_block_binary(watched const& w, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) { SASSERT(!s.is_external(blocked)); if (new_entry == 0) new_entry = &(mc.mk(k, blocked.var())); - literal l2 = it->get_literal(); + literal l2 = w.get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); - s.remove_bin_clause_half(l2, l1, it->is_learned()); + s.set_learned(l1, l2); m_queue.decreased(~l2); } - void block_binary(watch_list::iterator it, literal l, model_converter::entry *& new_entry) { - literal l2 = it->get_literal(); - prepare_block_binary(it, l, l, new_entry, model_converter::BLOCK_LIT); + void block_binary(watched const& w, literal l, model_converter::entry *& new_entry) { + literal l2 = w.get_literal(); + prepare_block_binary(w, l, l, new_entry, model_converter::BLOCK_LIT); mc.insert(*new_entry, l, l2); } - void block_covered_binary(watch_list::iterator it, literal l, literal blocked, model_converter::kind k) { + void block_covered_binary(watched const& w, literal l, literal blocked, model_converter::kind k) { model_converter::entry * new_entry = 0; - prepare_block_binary(it, l, blocked, new_entry, k); + prepare_block_binary(w, l, blocked, new_entry, k); mc.insert(*new_entry, m_covered_clause, m_elim_stack); } @@ -1681,6 +1651,7 @@ namespace sat { for (; !it.at_end(); it.next()) { clause & c = it.curr(); if (c.is_learned()) continue; + if (c.was_removed()) continue; m_counter -= c.size(); unsigned sz = c.size(); unsigned i; @@ -1707,33 +1678,40 @@ namespace sat { struct simplifier::blocked_cls_report { simplifier & m_simplifier; stopwatch m_watch; - unsigned m_num_blocked_clauses; - unsigned m_num_covered_clauses; + unsigned m_num_bce; + unsigned m_num_cce; + unsigned m_num_acce; + unsigned m_num_abce; unsigned m_num_ate; - unsigned m_num_added_clauses; + unsigned m_num_bca; blocked_cls_report(simplifier & s): m_simplifier(s), - m_num_blocked_clauses(s.m_num_blocked_clauses), - m_num_covered_clauses(s.m_num_covered_clauses), + m_num_bce(s.m_num_bce), + m_num_cce(s.m_num_cce), + m_num_acce(s.m_num_acce), + m_num_abce(s.m_num_abce), m_num_ate(s.m_num_ate), - m_num_added_clauses(s.m_num_bca) { + m_num_bca(s.m_num_bca) { m_watch.start(); } ~blocked_cls_report() { m_watch.stop(); IF_VERBOSE(SAT_VB_LVL, - verbose_stream() << " (sat-blocked-clauses :elim-blocked-clauses " - << (m_simplifier.m_num_blocked_clauses - m_num_blocked_clauses) - << " :elim-covered-clauses " - << (m_simplifier.m_num_covered_clauses - m_num_covered_clauses) - << " :added-clauses " - << (m_simplifier.m_num_bca - m_num_added_clauses) - << " :ate " - << (m_simplifier.m_num_ate - m_num_ate) - << mem_stat() + verbose_stream() << " (sat-blocked-clauses"; + report(m_simplifier.m_num_ate, m_num_ate, " :ate "); + report(m_simplifier.m_num_bce, m_num_bce, " :bce "); + report(m_simplifier.m_num_abce, m_num_abce, " :abce "); + report(m_simplifier.m_num_cce, m_num_cce, " :cce "); + report(m_simplifier.m_num_bca, m_num_bca, " :bca "); + report(m_simplifier.m_num_acce, m_num_acce, " :acce "); + verbose_stream() << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); } + + void report(unsigned n, unsigned m, char const* s) { + if (n > m) verbose_stream() << s << (n - m); + } }; void simplifier::elim_blocked_clauses() { @@ -1743,7 +1721,7 @@ namespace sat { elim(); } - unsigned simplifier::get_num_unblocked_bin(literal l) const { + unsigned simplifier::num_nonlearned_bin(literal l) const { unsigned r = 0; watch_list const & wlist = get_wlist(~l); for (auto & w : wlist) { @@ -1758,8 +1736,8 @@ namespace sat { literal neg_l(v, true); unsigned num_pos = m_use_list.get(pos_l).size(); unsigned num_neg = m_use_list.get(neg_l).size(); - unsigned num_bin_pos = get_num_unblocked_bin(pos_l); - unsigned num_bin_neg = get_num_unblocked_bin(neg_l); + unsigned num_bin_pos = num_nonlearned_bin(pos_l); + unsigned num_bin_neg = num_nonlearned_bin(neg_l); unsigned cost = 2 * num_pos * num_neg + num_pos * num_bin_neg + num_neg * num_bin_pos; CTRACE("elim_vars_detail", cost == 0, tout << v << " num_pos: " << num_pos << " num_neg: " << num_neg << " num_bin_pos: " << num_bin_pos << " num_bin_neg: " << num_bin_neg << " cost: " << cost << "\n";); @@ -1799,9 +1777,10 @@ namespace sat { void simplifier::collect_clauses(literal l, clause_wrapper_vector & r) { clause_use_list const & cs = m_use_list.get(l); for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) { - if (!it.curr().is_learned()) { - r.push_back(clause_wrapper(it.curr())); - SASSERT(r.back().size() == it.curr().size()); + clause& c = it.curr(); + if (!c.is_learned() && !c.was_removed()) { + r.push_back(clause_wrapper(c)); + SASSERT(r.back().size() == c.size()); } } @@ -1939,8 +1918,8 @@ namespace sat { literal pos_l(v, false); literal neg_l(v, true); - unsigned num_bin_pos = get_num_unblocked_bin(pos_l); - unsigned num_bin_neg = get_num_unblocked_bin(neg_l); + unsigned num_bin_pos = num_nonlearned_bin(pos_l); + unsigned num_bin_neg = num_nonlearned_bin(neg_l); clause_use_list & pos_occs = m_use_list.get(pos_l); clause_use_list & neg_occs = m_use_list.get(neg_l); unsigned num_pos = pos_occs.num_irredundant() + num_bin_pos; @@ -2146,15 +2125,19 @@ namespace sat { st.update("subsumed", m_num_subsumed); st.update("subsumption resolution", m_num_sub_res); st.update("elim literals", m_num_elim_lits); - st.update("elim blocked clauses", m_num_blocked_clauses); - st.update("elim covered clauses", m_num_covered_clauses); - st.update("blocked clauses added", m_num_bca); - st.update("asymmetric tautologies eliminated", m_num_ate); + st.update("bce", m_num_bce); + st.update("cce", m_num_cce); + st.update("acce", m_num_acce); + st.update("abce", m_num_abce); + st.update("bca", m_num_bca); + st.update("ate", m_num_ate); } void simplifier::reset_statistics() { - m_num_blocked_clauses = 0; - m_num_covered_clauses = 0; + m_num_bce = 0; + m_num_cce = 0; + m_num_acce = 0; + m_num_abce = 0; m_num_subsumed = 0; m_num_sub_res = 0; m_num_elim_lits = 0; diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 69a444954..e0a0e6b67 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -100,14 +100,16 @@ namespace sat { unsigned m_elim_vars_bdd_delay; // stats - unsigned m_num_blocked_clauses; - unsigned m_num_covered_clauses; + unsigned m_num_bce; + unsigned m_num_cce; + unsigned m_num_acce; + unsigned m_num_abce; + unsigned m_num_bca; + unsigned m_num_ate; unsigned m_num_subsumed; unsigned m_num_elim_vars; unsigned m_num_sub_res; unsigned m_num_elim_lits; - unsigned m_num_bca; - unsigned m_num_ate; bool m_learned_in_use_lists; unsigned m_old_num_elim_vars; @@ -132,9 +134,8 @@ namespace sat { void remove_clause_core(clause & c); void remove_clause(clause & c); void remove_clause(clause & c, literal l); - void block_clause(clause & c); - void unblock_clause(clause & c); - void remove_bin_clause_half(literal l1, literal l2, bool learned); + void set_learned(clause & c); + void set_learned(literal l1, literal l2); bool_var get_min_occ_var(clause const & c) const; bool subsumes1(clause const & c1, clause const & c2, literal & l); @@ -183,7 +184,7 @@ namespace sat { bool elim_vars_bdd_enabled() const; bool elim_vars_enabled() const; - unsigned get_num_unblocked_bin(literal l) const; + unsigned num_nonlearned_bin(literal l) const; unsigned get_to_elim_cost(bool_var v) const; void order_vars_for_elim(bool_var_vector & r); void collect_clauses(literal l, clause_wrapper_vector & r); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d21e773f3..b8850ce95 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -396,9 +396,9 @@ namespace sat { bool solver::attach_ter_clause(clause & c) { bool reinit = false; - m_watches[(~c[0]).index()].push_back(watched(c[1], c[2], c.is_learned())); - m_watches[(~c[1]).index()].push_back(watched(c[0], c[2], c.is_learned())); - m_watches[(~c[2]).index()].push_back(watched(c[0], c[1], c.is_learned())); + m_watches[(~c[0]).index()].push_back(watched(c[1], c[2])); + m_watches[(~c[1]).index()].push_back(watched(c[0], c[2])); + m_watches[(~c[2]).index()].push_back(watched(c[0], c[1])); if (!at_base_lvl()) { if (value(c[1]) == l_false && value(c[2]) == l_false) { m_stats.m_ter_propagate++; @@ -482,17 +482,23 @@ namespace sat { } void solver::set_learned(clause& c, bool learned) { - if (c.is_learned() == learned) - return; - - if (c.size() == 3) { - set_ternary_learned(get_wlist(~c[0]), c[1], c[2], learned); - set_ternary_learned(get_wlist(~c[1]), c[0], c[2], learned); - set_ternary_learned(get_wlist(~c[2]), c[0], c[1], learned); - } - c.set_learned(learned); + if (c.is_learned() != learned) + c.set_learned(learned); } + void solver::set_learned1(literal l1, literal l2, bool learned) { + for (watched& w : get_wlist(~l1)) { + if (w.is_binary_clause() && l2 == w.get_literal() && !w.is_learned()) { + w.set_learned(learned); + break; + } + } + } + + void solver::set_learned(literal l1, literal l2, bool learned) { + set_learned1(l1, l2, learned); + set_learned1(l2, l1, learned); + } /** \brief Select a watch literal starting the search at the given position. @@ -1523,7 +1529,7 @@ namespace sat { m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); - si.check_watches(); + si.check_watches(); if (!m_learned.empty()) { m_simplifier(true); CASSERT("sat_missed_prop", check_missed_propagation()); diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 0370d634d..824d728d6 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -234,6 +234,8 @@ namespace sat { void attach_clause(clause & c, bool & reinit); void attach_clause(clause & c) { bool reinit; attach_clause(c, reinit); } void set_learned(clause& c, bool learned); + void set_learned(literal l1, literal l2, bool learned); + void set_learned1(literal l1, literal l2, bool learned); class scoped_disable_checkpoint { solver& s; public: diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index d7c6520bd..5e86a7a87 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -71,29 +71,23 @@ namespace sat { } void erase_ternary_watch(watch_list& wlist, literal l1, literal l2) { + watched w(l1, l2); watch_list::iterator it = wlist.begin(), end = wlist.end(); watch_list::iterator it2 = it; bool found = false; for (; it != end; ++it) { - if (it->is_ternary_clause() && it->get_literal1() == l1 && it->get_literal2() == l2) { + if (!found && w == *it) { found = true; - continue; } - *it2 = *it; - ++it2; + else { + *it2 = *it; + ++it2; + } } wlist.set_end(it2); VERIFY(found); } - void set_ternary_learned(watch_list& wlist, literal l1, literal l2, bool learned) { - for (watched& w : wlist) { - if (w.is_ternary_clause() && w.get_literal1() == l1 && w.get_literal2() == l2) { - w.set_learned(learned); - } - } - } - void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist) { watch_list::iterator end = wlist.end(); for (; it != end; ++it, ++it2) diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index 8979405ae..acd4ed9c0 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -53,12 +53,12 @@ namespace sat { SASSERT(learned || is_binary_non_learned_clause()); } - watched(literal l1, literal l2, bool learned) { + watched(literal l1, literal l2) { SASSERT(l1 != l2); if (l1.index() > l2.index()) std::swap(l1, l2); m_val1 = l1.to_uint(); - m_val2 = static_cast(TERNARY) + (static_cast(learned) << 2) + (l2.to_uint() << 3); + m_val2 = static_cast(TERNARY) + (l2.to_uint() << 2); SASSERT(is_ternary_clause()); SASSERT(get_literal1() == l1); SASSERT(get_literal2() == l2); @@ -87,16 +87,16 @@ namespace sat { bool is_binary_clause() const { return get_kind() == BINARY; } literal get_literal() const { SASSERT(is_binary_clause()); return to_literal(static_cast(m_val1)); } void set_literal(literal l) { SASSERT(is_binary_clause()); m_val1 = l.to_uint(); } - bool is_learned() const { SASSERT(is_binary_clause() || is_ternary_clause()); return ((m_val2 >> 2) & 1) == 1; } + bool is_learned() const { SASSERT(is_binary_clause()); return ((m_val2 >> 2) & 1) == 1; } bool is_binary_learned_clause() const { return is_binary_clause() && is_learned(); } bool is_binary_non_learned_clause() const { return is_binary_clause() && !is_learned(); } - void set_learned(bool l) { SASSERT(is_learned() != l); if (l) m_val2 |= 4; else m_val2 &= 3; SASSERT(is_learned() == l); } + void set_learned(bool l) { if (l) m_val2 |= 4u; else m_val2 &= ~4u; SASSERT(is_learned() == l); } bool is_ternary_clause() const { return get_kind() == TERNARY; } literal get_literal1() const { SASSERT(is_ternary_clause()); return to_literal(static_cast(m_val1)); } - literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 3); } + literal get_literal2() const { SASSERT(is_ternary_clause()); return to_literal(m_val2 >> 2); } bool is_clause() const { return get_kind() == CLAUSE; } clause_offset get_clause_offset() const { SASSERT(is_clause()); return static_cast(m_val1); } From e32bfda5a63ed70c23e80b7ecd6cf0b637e60fb6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2018 10:21:27 -0800 Subject: [PATCH 0502/1283] fixup cce Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 86 ++++++++++++++------------------------ 1 file changed, 31 insertions(+), 55 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 3e7b32eb4..7bf850469 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -315,7 +315,6 @@ namespace sat { } } cs.set_end(it2); - IF_VERBOSE(0, verbose_stream() << "num moved: " << nm << "\n";); } void simplifier::cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists) { @@ -880,9 +879,6 @@ namespace sat { break; clause & c = m_sub_todo.erase(); - if (c.id() == 60127) { - IF_VERBOSE(0, verbose_stream() << "subsume " << c << "\n";); - } c.unmark_strengthened(); m_sub_counter--; @@ -893,9 +889,6 @@ namespace sat { continue; } unsigned sz = c.size(); - if (c.id() == 60127) { - IF_VERBOSE(0, verbose_stream() << "subsume " << c << "\n";); - } if (sz == 0) { s.set_conflict(justification()); return; @@ -936,21 +929,23 @@ namespace sat { }; class clause_ante { + bool m_from_ri; literal m_lit1; literal m_lit2; clause* m_clause; public: clause_ante(): - m_lit1(null_literal), m_lit2(null_literal), m_clause(nullptr) {} - clause_ante(literal l1): - m_lit1(l1), m_lit2(null_literal), m_clause(nullptr) {} + m_from_ri(false), m_lit1(null_literal), m_lit2(null_literal), m_clause(nullptr) {} + clause_ante(literal l1, bool from_ri): + m_from_ri(from_ri), m_lit1(l1), m_lit2(null_literal), m_clause(nullptr) {} clause_ante(literal l1, literal l2): - m_lit1(l1), m_lit2(l2), m_clause(nullptr) {} + m_from_ri(false), m_lit1(l1), m_lit2(l2), m_clause(nullptr) {} clause_ante(clause& c): - m_lit1(null_literal), m_lit2(null_literal), m_clause(&c) {} + m_from_ri(false), m_lit1(null_literal), m_lit2(null_literal), m_clause(&c) {} literal lit1() const { return m_lit1; } literal lit2() const { return m_lit2; } clause* cls() const { return m_clause; } + bool from_ri() const { return m_from_ri; } bool operator==(clause_ante const& a) const { return a.m_lit1 == m_lit1 && a.m_lit2 == m_lit2 && a.m_clause == m_clause; } @@ -983,12 +978,11 @@ namespace sat { model_converter & mc; queue m_queue; - literal_vector m_covered_clause; - svector m_covered_antecedent; - literal_vector m_intersection; - literal_vector m_tautology; + literal_vector m_covered_clause; // covered clause + svector m_covered_antecedent; // explainations for literals in covered clause + literal_vector m_intersection; // current resolution intersection + literal_vector m_tautology; // literals that are used in blocking tautology literal_vector m_new_intersection; - literal_vector m_blocked_binary; svector m_in_intersection; sat::model_converter::elim_stackv m_elim_stack; unsigned m_ala_qhead; @@ -1072,7 +1066,6 @@ namespace sat { } void process_binary(literal l) { - m_blocked_binary.reset(); model_converter::entry* new_entry = 0; watch_list & wlist = s.get_wlist(~l); m_counter -= wlist.size(); @@ -1087,7 +1080,6 @@ namespace sat { w.set_learned(true); s.s.set_learned1(l2, l, true); s.m_num_bce++; - m_blocked_binary.push_back(l2); } s.unmark_visited(l2); } @@ -1120,9 +1112,7 @@ namespace sat { void add_intersection(literal lit) { m_intersection.push_back(lit); m_in_intersection[lit.index()] = true; - } - - + } // // Resolve intersection @@ -1223,16 +1213,6 @@ namespace sat { (m_clause[0] == l2 && m_clause[1] == l1)); } - bool revisit_ternary(literal l1, literal l2, literal l3) const { - return m_clause.size() == 3 && - ((m_clause[0] == l1 && m_clause[1] == l2 && m_clause[2] == l3) || - (m_clause[0] == l2 && m_clause[1] == l1 && m_clause[2] == l3) || - (m_clause[0] == l2 && m_clause[1] == l3 && m_clause[2] == l1) || - (m_clause[0] == l1 && m_clause[1] == l3 && m_clause[2] == l2) || - (m_clause[0] == l3 && m_clause[1] == l1 && m_clause[2] == l2) || - (m_clause[0] == l3 && m_clause[1] == l2 && m_clause[2] == l1)); - } - bool revisit_clause(clause const& c) const { return !m_clause.is_binary() && (m_clause.get_clause() == &c); } @@ -1249,42 +1229,46 @@ namespace sat { for (literal l : m_tautology) s.mark_visited(l); s.mark_visited(m_covered_clause[idx]); for (unsigned i = 0; i < m_covered_clause.size(); ++i) { - if (s.is_marked(m_covered_clause[i])) idx = i; + literal lit = m_covered_clause[i]; + if (m_covered_antecedent[i] == clause_ante()) s.mark_visited(lit); + if (s.is_marked(lit)) idx = i; } for (unsigned i = idx; i > 0; --i) { literal lit = m_covered_clause[i]; if (!s.is_marked(lit)) continue; clause_ante const& ante = m_covered_antecedent[i]; if (ante.cls()) { - //IF_VERBOSE(0, verbose_stream() << "clause ante: " << lit << ": " << *ante.cls() << "\n";); for (literal l : *ante.cls()) { if (l != ~lit) s.mark_visited(l); } } if (ante.lit1() != null_literal) { - //IF_VERBOSE(0, verbose_stream() << "ante1: " << lit << ": " << ante.lit1() << "\n";); s.mark_visited(ante.lit1()); } if (ante.lit2() != null_literal) { - //IF_VERBOSE(0, verbose_stream() << "ante2: " << lit << ": " << ante.lit2() << "\n";); s.mark_visited(ante.lit2()); } } unsigned j = 0; + literal blocked = null_literal; for (unsigned i = 0; i <= idx; ++i) { literal lit = m_covered_clause[i]; - if (s.is_marked(lit) || m_covered_antecedent[i] == clause_ante()) { + if (s.is_marked(lit)) { + // + // Record that the resolving literal for + // resolution intersection can be flipped. + // + clause_ante const& ante = m_covered_antecedent[i]; + if (ante.from_ri() && blocked != ante.lit1()) { + blocked = ante.lit1(); + m_elim_stack.push_back(std::make_pair(j, blocked)); + } m_covered_clause[j++] = lit; s.unmark_visited(lit); } } - // ensure that rest of literals from original clause are included - for (unsigned i = idx + 1; i < m_covered_clause.size() && m_covered_antecedent[i] == clause_ante(); ++i) { - literal lit = m_covered_clause[i]; - m_covered_clause[j++] = lit; - } for (literal l : m_covered_clause) VERIFY(!s.is_marked(l)); - unsigned sz0 = m_covered_clause.size(); + // unsigned sz0 = m_covered_clause.size(); m_covered_clause.resize(j); VERIFY(j >= m_clause.size()); // IF_VERBOSE(0, verbose_stream() << "reduced from size " << sz0 << " to " << m_covered_clause << "\n" << m_clause << "\n";); @@ -1306,20 +1290,17 @@ namespace sat { */ bool add_ala() { for (; m_ala_qhead < m_covered_clause.size(); ++m_ala_qhead) { - literal l = m_covered_clause[m_ala_qhead]; - + literal l = m_covered_clause[m_ala_qhead]; for (watched & w : s.get_wlist(~l)) { if (w.is_binary_non_learned_clause()) { literal lit = w.get_literal(); if (revisit_binary(l, lit)) continue; if (s.is_marked(lit)) { - //IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " binary: " << l << " " << lit << "\n";); return true; } if (!s.is_marked(~lit)) { - //IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " binary " << l << " " << lit << " " << (~lit) << "\n";); m_covered_clause.push_back(~lit); - m_covered_antecedent.push_back(clause_ante(l)); + m_covered_antecedent.push_back(clause_ante(l, false)); s.mark_visited(~lit); } } @@ -1345,10 +1326,8 @@ namespace sat { } if (!ok) continue; if (lit1 == null_literal) { - //IF_VERBOSE(0, verbose_stream() << "ATE: " << m_covered_clause << " clause " << c << "\n";); return true; } - // IF_VERBOSE(0, verbose_stream() << "ALA: " << m_covered_clause << " clause " << c << " " << (~lit1) << "\n";); m_covered_clause.push_back(~lit1); m_covered_antecedent.push_back(clause_ante(c)); s.mark_visited(~lit1); @@ -1373,14 +1352,11 @@ namespace sat { minimize_covered_clause(i); return true; } - if (!m_intersection.empty()) { - m_elim_stack.push_back(std::make_pair(m_covered_clause.size(), m_covered_clause[i])); - } for (literal l : m_intersection) { if (!s.is_marked(l)) { s.mark_visited(l); m_covered_clause.push_back(l); - m_covered_antecedent.push_back(clause_ante(lit)); + m_covered_antecedent.push_back(clause_ante(lit, true)); } } } @@ -1451,7 +1427,7 @@ namespace sat { } while (m_covered_clause.size() > sz && !is_tautology); for (literal l : m_covered_clause) s.unmark_visited(l); - return (is_tautology && !above_threshold(sz0)) ? bc_t : no_t; + return is_tautology ? bc_t : no_t; } // perform covered clause elimination. From 7ada6c25d95403d46731c104de9dc5b7c6cb94c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2018 11:10:42 -0800 Subject: [PATCH 0503/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/sat/sat_integrity_checker.cpp | 2 +- src/tactic/generic_model_converter.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index d09fb9581..867dd104c 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -64,7 +64,7 @@ namespace sat { return true; if (c.size() == 3) { - CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2], c.learned()), tout << c << "\n"; + CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2], c.is_learned()), tout << c << "\n"; tout << "watch_list:\n"; sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~c[0])); tout << "\n";); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 485682858..2e800da48 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -53,6 +53,21 @@ void generic_model_converter::operator()(model_ref & md) { break; case instruction::ADD: ev(e.m_def, val); + if (e.m_f->get_name() == symbol("FOX-PIT-17")) { + IF_VERBOSE(0, verbose_stream() << e.m_f->get_name() << " " << e.m_def << " -> " << val << "\n";); + ptr_vector ts; + ts.push_back(e.m_def); + while (!ts.empty()) { + app* t = to_app(ts.back()); + ts.pop_back(); + if (t->get_num_args() > 0) { + ts.append(t->get_num_args(), t->get_args()); + } + expr_ref tmp(m); + ev(t, tmp); + IF_VERBOSE(0, verbose_stream() << mk_pp(t, m) << " -> " << tmp << "\n";); + } + } TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";); arity = e.m_f->get_arity(); reset_ev = false; From 75bf942237a2e250855f37ba6493a46286f70924 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2018 21:15:07 -0800 Subject: [PATCH 0504/1283] throttle cce pass Signed-off-by: Nikolaj Bjorner --- src/sat/sat_integrity_checker.cpp | 2 +- src/sat/sat_simplifier.cpp | 211 ++++++++++++++++-------------- src/sat/sat_simplifier.h | 7 +- src/sat/sat_simplifier_params.pyg | 1 + 4 files changed, 117 insertions(+), 104 deletions(-) diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index 7a2cd9034..e0e285d56 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -64,7 +64,7 @@ namespace sat { return true; if (c.size() == 3) { - CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2], c.is_learned()), tout << c << "\n"; + CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2]), tout << c << "\n"; tout << "watch_list:\n"; sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~c[0])); tout << "\n";); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 7bf850469..831539351 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -94,23 +94,18 @@ namespace sat { bool simplifier::single_threaded() const { return s.m_config.m_num_threads == 1; } - bool simplifier::bce_enabled() const { + bool simplifier::bce_enabled_base() const { return - !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && - (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls || cce_enabled()); - } - bool simplifier::acce_enabled() const { - return !s.m_ext && !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_acce; - } - bool simplifier::cce_enabled() const { - return !s.m_ext && !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && (m_cce || acce_enabled()); - } - bool simplifier::abce_enabled() const { - return !s.m_ext && !m_incremental_mode && !s.tracking_assumptions() && !m_learned_in_use_lists && m_num_calls >= m_bce_delay && m_abce; - } - bool simplifier::bca_enabled() const { - return !s.m_ext && !m_incremental_mode && !s.tracking_assumptions() && m_bca && m_learned_in_use_lists && single_threaded(); + !m_incremental_mode && !s.tracking_assumptions() && + !m_learned_in_use_lists && m_num_calls >= m_bce_delay && single_threaded(); } + + bool simplifier::ate_enabled() const { return m_ate; } + bool simplifier::bce_enabled() const { return bce_enabled_base() && (m_bce || m_bce_at == m_num_calls || m_acce || m_abce || m_cce); } + bool simplifier::acce_enabled() const { return bce_enabled_base() && m_acce; } + bool simplifier::cce_enabled() const { return bce_enabled_base() && (m_cce || m_acce); } + bool simplifier::abce_enabled() const { return bce_enabled_base() && m_abce; } + bool simplifier::bca_enabled() const { return bce_enabled_base() && m_bca; } bool simplifier::elim_vars_bdd_enabled() const { return !m_incremental_mode && !s.tracking_assumptions() && m_elim_vars_bdd && m_num_calls >= m_elim_vars_bdd_delay && single_threaded(); } @@ -219,7 +214,7 @@ namespace sat { } register_clauses(s.m_clauses); - if (bce_enabled() || abce_enabled() || bca_enabled()) { + if (bce_enabled() || bca_enabled() || ate_enabled()) { elim_blocked_clauses(); } @@ -1010,28 +1005,27 @@ namespace sat { enum elim_type { cce_t, acce_t, - abce_t - }; - - enum verdict_type { - at_t, // asymmetric tautology - bc_t, // blocked clause - no_t // neither + abce_t, + ate_t, + no_t }; void operator()() { - if (s.bce_enabled()) { - block_clauses(); - } - if (s.abce_enabled()) { - cce(); - } - if (s.cce_enabled()) { - cce(); - } if (s.acce_enabled()) { cce(); } + if (s.ate_enabled() && !s.abce_enabled() && !s.acce_enabled()) { + cce(); + } + if (s.cce_enabled() && !s.acce_enabled()) { + cce(); + } + if (s.abce_enabled() && !s.acce_enabled()) { + cce(); + } + if (s.bce_enabled() && !s.cce_enabled() && !s.abce_enabled()) { + block_clauses(); + } if (s.bca_enabled()) { bca(); } @@ -1223,7 +1217,8 @@ namespace sat { This routine removes literals that were not relevant to establishing it was blocked. */ void minimize_covered_clause(unsigned idx) { - // IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause << " @ " << idx << "\n" << "tautology: " << m_tautology << "\n";); + // IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause + // << " @ " << idx << "\n" << "tautology: " << m_tautology << "\n";); for (literal l : m_tautology) VERIFY(s.is_marked(l)); for (literal l : m_covered_clause) s.unmark_visited(l); for (literal l : m_tautology) s.mark_visited(l); @@ -1369,14 +1364,25 @@ namespace sat { } template - verdict_type cla(literal& blocked, model_converter::kind& k) { - bool is_tautology = false; + elim_type cce(literal& blocked, model_converter::kind& k) { + bool is_tautology = false, first = true; + unsigned sz = 0, sz0 = m_covered_clause.size(); for (literal l : m_covered_clause) s.mark_visited(l); - unsigned num_iterations = 0, sz; + shuffle(m_covered_clause.size(), m_covered_clause.c_ptr(), s.s.m_rand); m_elim_stack.reset(); m_ala_qhead = 0; - k = model_converter::CCE; - unsigned sz0 = m_covered_clause.size(); + + switch (et) { + case abce_t: + k = model_converter::BLOCK_LIT; + break; + case cce_t: + k = model_converter::CCE; + break; + case acce_t: + k = model_converter::ACCE; + break; + } /* * For blocked clause elimination with asymmetric literal addition (ABCE) @@ -1385,56 +1391,48 @@ namespace sat { * So we record sz0, the original set of literals in the clause, mark additional literals, * and then check if any of the first sz0 literals are blocked. */ - if (et == abce_t) { - if (add_ala()) { - for (literal l : m_covered_clause) s.unmark_visited(l); - return at_t; - } - for (unsigned i = 0; i < sz0; ++i) { - if (check_abce_tautology(m_covered_clause[i])) { - blocked = m_covered_clause[i]; - is_tautology = true; - break; - } - } - k = model_converter::BLOCK_LIT; // actually ABCE - for (literal l : m_covered_clause) s.unmark_visited(l); - m_covered_clause.shrink(sz0); - return is_tautology ? bc_t : no_t; - } - /* - * For CCE we add the resolution intersection while checking if the clause becomes a tautology. - * For ACCE, in addition, we add literals. - */ - do { - do { - if (above_threshold(sz0)) break; - ++num_iterations; - sz = m_covered_clause.size(); + while (!is_tautology && m_covered_clause.size() > sz && !above_threshold(sz0)) { + SASSERT(!is_tautology); + if ((et == abce_t || et == acce_t || et == ate_t) && add_ala()) { + for (literal l : m_covered_clause) s.unmark_visited(l); + return ate_t; + } + + if (first) { + for (unsigned i = 0; i < sz0; ++i) { + if (check_abce_tautology(m_covered_clause[i])) { + blocked = m_covered_clause[i]; + is_tautology = true; + break; + } + } + first = false; + } + + if (is_tautology || et == abce_t) { + for (literal l : m_covered_clause) s.unmark_visited(l); + m_covered_clause.shrink(sz0); + return is_tautology ? abce_t : no_t; + } + + /* + * Add resolution intersection while checking if the clause becomes a tautology. + */ + sz = m_covered_clause.size(); + if (et == cce_t || et == acce_t) { is_tautology = add_cla(blocked); } - while (m_covered_clause.size() > sz && !is_tautology); - if (et == acce_t && !is_tautology) { - sz = m_covered_clause.size(); - if (add_ala()) { - for (literal l : m_covered_clause) s.unmark_visited(l); - return at_t; - } - k = model_converter::ACCE; - } - if (above_threshold(sz0)) break; } - while (m_covered_clause.size() > sz && !is_tautology); for (literal l : m_covered_clause) s.unmark_visited(l); - return is_tautology ? bc_t : no_t; + return is_tautology ? et : no_t; } // perform covered clause elimination. // first extract the covered literal addition (CLA). // then check whether the CLA is blocked. template - verdict_type cce(clause& c, literal& blocked, model_converter::kind& k) { + elim_type cce(clause& c, literal& blocked, model_converter::kind& k) { m_clause = clause_wrapper(c); m_covered_clause.reset(); m_covered_antecedent.reset(); @@ -1443,11 +1441,11 @@ namespace sat { m_covered_antecedent.push_back(clause_ante()); } // shuffle(s.s.m_rand, m_covered_clause); - return cla(blocked, k); + return cce(blocked, k); } template - verdict_type cce(literal l1, literal l2, literal& blocked, model_converter::kind& k) { + elim_type cce(literal l1, literal l2, literal& blocked, model_converter::kind& k) { m_clause = clause_wrapper(l1, l2); m_covered_clause.reset(); m_covered_antecedent.reset(); @@ -1455,7 +1453,7 @@ namespace sat { m_covered_clause.push_back(l2); m_covered_antecedent.push_back(clause_ante()); m_covered_antecedent.push_back(clause_ante()); - return cla(blocked, k); + return cce(blocked, k); } template @@ -1481,21 +1479,22 @@ namespace sat { model_converter::kind k; for (watched & w : wlist) { if (!w.is_binary_non_learned_clause()) continue; + if (!select_clause(2)) continue; literal l2 = w.get_literal(); - switch (cce(l, l2, blocked, k)) { - case bc_t: - inc_bc(); - block_covered_binary(w, l, blocked, k); - w.set_learned(true); - s.s.set_learned1(l2, l, true); - break; - case at_t: - s.m_num_ate++; + elim_type r = cce(l, l2, blocked, k); + inc_bc(r); + switch (r) { + case ate_t: w.set_learned(true); s.s.set_learned1(l2, l, true); break; case no_t: break; + default: + block_covered_binary(w, l, blocked, k); + w.set_learned(true); + s.s.set_learned1(l2, l, true); + break; } } } @@ -1507,31 +1506,40 @@ namespace sat { for (clause* cp : s.s.m_clauses) { clause& c = *cp; if (c.was_removed() || c.is_learned()) continue; - switch (cce(c, blocked, k)) { - case bc_t: - inc_bc(); - block_covered_clause(c, blocked, k); - s.set_learned(c); - break; - case at_t: - s.m_num_ate++; + if (!select_clause(c.size())) continue; + elim_type r = cce(c, blocked, k); + inc_bc(r); + switch (r) { + case ate_t: s.set_learned(c); break; case no_t: break; + default: + block_covered_clause(c, blocked, k); + s.set_learned(c); + break; } } } - template - void inc_bc() { + void inc_bc(elim_type et) { switch (et) { case cce_t: s.m_num_cce++; break; case acce_t: s.m_num_acce++; break; case abce_t: s.m_num_abce++; break; + case ate_t: s.m_num_ate++; break; + default: break; } } + // select 25% of clauses size 2, 3 + // always try to remove larger clauses. + template + bool select_clause(unsigned sz) { + return et == ate_t || (sz > 3) || s.s.m_rand(4) == 0; + } + void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); VERIFY(!s.is_external(l)); @@ -2070,9 +2078,10 @@ namespace sat { m_acce = p.acce(); m_bca = p.bca(); m_abce = p.abce(); + m_ate = p.ate(); m_bce_delay = p.bce_delay(); - m_elim_blocked_clauses = p.elim_blocked_clauses(); - m_elim_blocked_clauses_at = p.elim_blocked_clauses_at(); + m_bce = p.elim_blocked_clauses(); + m_bce_at = p.elim_blocked_clauses_at(); m_retain_blocked_clauses = p.retain_blocked_clauses(); m_blocked_clause_limit = p.blocked_clause_limit(); m_res_limit = p.resolution_limit(); diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index e0a0e6b67..086111f84 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -76,8 +76,9 @@ namespace sat { bool m_acce; // cce with asymetric literal addition bool m_bca; // blocked (binary) clause addition. unsigned m_bce_delay; - bool m_elim_blocked_clauses; - unsigned m_elim_blocked_clauses_at; + bool m_bce; // blocked clause elimination + bool m_ate; // asymmetric tautology elimination + unsigned m_bce_at; bool m_retain_blocked_clauses; unsigned m_blocked_clause_limit; bool m_incremental_mode; @@ -176,6 +177,8 @@ namespace sat { void elim_blocked_clauses(); bool single_threaded() const; // { return s.m_config.m_num_threads == 1; } + bool bce_enabled_base() const; + bool ate_enabled() const; bool bce_enabled() const; bool acce_enabled() const; bool cce_enabled() const; diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index f988c3c8b..4bbc490cc 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -4,6 +4,7 @@ def_module_params(module_name='sat', params=(('elim_blocked_clauses', BOOL, False, 'eliminate blocked clauses'), ('abce', BOOL, False, 'eliminate blocked clauses using asymmmetric literals'), ('cce', BOOL, False, 'eliminate covered clauses'), + ('ate', BOOL, True, 'asymmetric tautology elimination'), ('acce', BOOL, False, 'eliminate covered clauses using asymmetric added literals'), ('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), ('bca', BOOL, False, 'blocked clause addition - add blocked binary clauses'), From ae8027e594c67a78366c2662a36b1ec110a23d4e Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 30 Jan 2018 20:36:12 +0700 Subject: [PATCH 0505/1283] Fix typos. --- RELEASE_NOTES | 12 ++++---- src/api/api_context.h | 4 +-- src/api/c++/z3++.h | 10 +++---- src/api/dotnet/Statistics.cs | 2 +- src/api/java/Context.java | 2 +- src/api/java/Statistics.java | 2 +- src/api/python/z3/z3.py | 10 +++---- src/api/z3_fixedpoint.h | 2 +- src/api/z3_fpa.h | 2 +- src/ast/proofs/proof_utils.cpp | 10 +++---- src/cmd_context/basic_cmds.cpp | 2 +- src/duality/duality_solver.cpp | 4 +-- src/math/polynomial/polynomial.h | 8 +++--- .../polynomial/upolynomial_factorization.cpp | 28 +++++++++---------- .../polynomial/upolynomial_factorization.h | 12 ++++---- src/muz/rel/aig_exporter.cpp | 2 +- src/muz/rel/dl_sieve_relation.cpp | 2 +- src/muz/rel/dl_sparse_table.h | 4 +-- src/muz/spacer/spacer_matrix.h | 2 +- src/nlsat/nlsat_explain.cpp | 4 +-- src/test/rational.cpp | 4 +-- src/util/gparams.h | 4 +-- src/util/mpz.h | 2 +- 23 files changed, 67 insertions(+), 67 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 5ce4d2682..86e7039dd 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -427,11 +427,11 @@ Version 3.0 - New Bitvector (QF_BV) solver. The new solver is only available when using the new SMT2 front-end. -- Major performace improvements. +- Major performance improvements. - New preprocessing stack. -- Performance improvements for linear and nonlinear arithmetic. The improvements are only available when using the the SMT2 front-end. +- Performance improvements for linear and nonlinear arithmetic. The improvements are only available when using the SMT2 front-end. - Added API for parsing SMT2 files. @@ -772,7 +772,7 @@ This release also introduces some new preprocessing features: - More efficient destructive equality resolution DER=true. -- DISTRIBUTE_FORALL=true (distributes universal quatifiers over conjunctions, this transformation may affect pattern inference). +- DISTRIBUTE_FORALL=true (distributes universal quantifiers over conjunctions, this transformation may affect pattern inference). - Rewriter that uses universally quantified equations PRE_DEMODULATOR=true (yes, the option name is not good, we will change it in a future release). @@ -842,7 +842,7 @@ This release introduces the following features: It fixes the following bugs: -- Incorrect simplification of map over store in the extendted array theory. Reported by Catalin Hritcu. +- Incorrect simplification of map over store in the extended array theory. Reported by Catalin Hritcu. - Incomplete handling of equality propagation with constant arrays. Reported by Catalin Hritcu. @@ -886,7 +886,7 @@ Version 2.0 proof object. - Proof Objects. - The #Z3_check_assumptions retuns a proof object if + The #Z3_check_assumptions returns a proof object if the configuration flag PROOF_MODE is set to 1 or 2. - Partial support for non-linear arithmetic. @@ -899,4 +899,4 @@ Version 2.0 The theory of well-founded recursive data-types is supported over the binary APIs. It supports ground satisfiability checking for tuples, enumeration types (scalars), - lists and mututally recursive data-types. + lists and mutually recursive data-types. diff --git a/src/api/api_context.h b/src/api/api_context.h index a2321d7fe..7009250cc 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -51,7 +51,7 @@ namespace api { class context : public tactic_manager { struct add_plugins { add_plugins(ast_manager & m); }; context_params m_params; - bool m_user_ref_count; //!< if true, the user is responsible for managing referenc counters. + bool m_user_ref_count; //!< if true, the user is responsible for managing reference counters. scoped_ptr m_manager; add_plugins m_plugins; @@ -158,7 +158,7 @@ namespace api { // Create a numeral of the given sort expr * mk_numeral_core(rational const & n, sort * s); - // Return a conjuction that will be exposed to the "external" world. + // Return a conjunction that will be exposed to the "external" world. expr * mk_and(unsigned num_exprs, expr * const * exprs); // Hack for preventing an AST for being GC when ref-count is not used diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 89b051eb5..49f6cfbf3 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -187,8 +187,8 @@ namespace z3 { \brief The C++ API uses by defaults exceptions on errors. For applications that don't work well with exceptions (there should be only few) you have the ability to turn off exceptions. The tradeoffs are that applications - have to very careful about using check_error() after calls that may result in an errornous - state. + have to very careful about using check_error() after calls that may result in an + erroneous state. */ void set_enable_exceptions(bool f) { m_enable_exceptions = f; } @@ -213,7 +213,7 @@ namespace z3 { /** \brief Interrupt the current procedure being executed by any object managed by this context. - This is a soft interruption: there is no guarantee the object will actualy stop. + This is a soft interruption: there is no guarantee the object will actually stop. */ void interrupt() { Z3_interrupt(m_ctx); } @@ -709,7 +709,7 @@ namespace z3 { It only makes sense to use this function if the caller can ensure that the result is an integer or if exceptions are enabled. - If exceptions are disabled, then use the the is_numeral_i function. + If exceptions are disabled, then use the is_numeral_i function. \pre is_numeral() */ @@ -729,7 +729,7 @@ namespace z3 { It only makes sense to use this function if the caller can ensure that the result is an integer or if exceptions are enabled. - If exceptions are disabled, then use the the is_numeral_u function. + If exceptions are disabled, then use the is_numeral_u function. \pre is_numeral() */ unsigned get_numeral_uint() const { diff --git a/src/api/dotnet/Statistics.cs b/src/api/dotnet/Statistics.cs index cf4b703fe..c94af625c 100644 --- a/src/api/dotnet/Statistics.cs +++ b/src/api/dotnet/Statistics.cs @@ -56,7 +56,7 @@ namespace Microsoft.Z3 public bool IsDouble { get { return m_is_double; } } /// - /// The string representation of the the entry's value. + /// The string representation of the entry's value. /// public string Value { diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 7e73fc15e..ba96209b3 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -934,7 +934,7 @@ public class Context implements AutoCloseable { * exposed. It follows the semantics prescribed by the SMT-LIB standard. * * You can take the floor of a real by creating an auxiliary integer Term - * {@code k} and and asserting + * {@code k} and asserting * {@code MakeInt2Real(k) <= t1 < MkInt2Real(k)+1}. The argument * must be of integer sort. **/ diff --git a/src/api/java/Statistics.java b/src/api/java/Statistics.java index 356cbeadb..d509424ed 100644 --- a/src/api/java/Statistics.java +++ b/src/api/java/Statistics.java @@ -65,7 +65,7 @@ public class Statistics extends Z3Object { } /** - * The string representation of the the entry's value. + * The string representation of the entry's value. * * @throws Z3Exception **/ diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4896a475d..c28a14c3b 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5741,7 +5741,7 @@ class ModelRef(Z3PPObject): return None def num_sorts(self): - """Return the number of unintepreted sorts that contain an interpretation in the model `self`. + """Return the number of uninterpreted sorts that contain an interpretation in the model `self`. >>> A = DeclareSort('A') >>> a, b = Consts('a b', A) @@ -5756,7 +5756,7 @@ class ModelRef(Z3PPObject): return int(Z3_model_get_num_sorts(self.ctx.ref(), self.model)) def get_sort(self, idx): - """Return the unintepreted sort at position `idx` < self.num_sorts(). + """Return the uninterpreted sort at position `idx` < self.num_sorts(). >>> A = DeclareSort('A') >>> B = DeclareSort('B') @@ -5796,7 +5796,7 @@ class ModelRef(Z3PPObject): return [ self.get_sort(i) for i in range(self.num_sorts()) ] def get_universe(self, s): - """Return the intepretation for the uninterpreted sort `s` in the model `self`. + """Return the interpretation for the uninterpreted sort `s` in the model `self`. >>> A = DeclareSort('A') >>> a, b = Consts('a b', A) @@ -5816,7 +5816,7 @@ class ModelRef(Z3PPObject): return None def __getitem__(self, idx): - """If `idx` is an integer, then the declaration at position `idx` in the model `self` is returned. If `idx` is a declaration, then the actual interpreation is returned. + """If `idx` is an integer, then the declaration at position `idx` in the model `self` is returned. If `idx` is a declaration, then the actual interpretation is returned. The elements can be retrieved using position or the actual declaration. @@ -5860,7 +5860,7 @@ class ModelRef(Z3PPObject): return None def decls(self): - """Return a list with all symbols that have an interpreation in the model `self`. + """Return a list with all symbols that have an interpretation in the model `self`. >>> f = Function('f', IntSort(), IntSort()) >>> x = Int('x') >>> s = Solver() diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index dc98fdb30..a651993ce 100644 --- a/src/api/z3_fixedpoint.h +++ b/src/api/z3_fixedpoint.h @@ -363,7 +363,7 @@ extern "C" { void Z3_API Z3_fixedpoint_set_reduce_assign_callback( Z3_context c ,Z3_fixedpoint d, Z3_fixedpoint_reduce_assign_callback_fptr cb); - /** \brief Register a callback for buildling terms based on the relational operators. */ + /** \brief Register a callback for building terms based on the relational operators. */ void Z3_API Z3_fixedpoint_set_reduce_app_callback( Z3_context c, Z3_fixedpoint d, Z3_fixedpoint_reduce_app_callback_fptr cb); diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index e92b728d7..358a3c619 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -433,7 +433,7 @@ extern "C" { \param c logical context \param rm term of RoundingMode sort \param t1 term of FloatingPoint sort - \param t2 term of FloatingPoint sor + \param t2 term of FloatingPoint sort \param t3 term of FloatingPoint sort The result is round((t1 * t2) + t3) diff --git a/src/ast/proofs/proof_utils.cpp b/src/ast/proofs/proof_utils.cpp index 58500cb79..722bfe14e 100644 --- a/src/ast/proofs/proof_utils.cpp +++ b/src/ast/proofs/proof_utils.cpp @@ -83,7 +83,7 @@ class reduce_hypotheses { // map from unit literals to their hypotheses-free derivations obj_map m_units; - // -- all hypotheses in the the proof + // -- all hypotheses in the proof obj_hashtable m_hyps; // marks hypothetical proofs @@ -192,7 +192,7 @@ class reduce_hypotheses { res = mk_lemma_core(args.get(0), m.get_fact(p)); compute_mark1(res); } else if (m.is_unit_resolution(p)) { - // unit: reduce untis; reduce the first premise; rebuild unit resolution + // unit: reduce units; reduce the first premise; rebuild unit resolution res = mk_unit_resolution_core(args.size(), args.c_ptr()); compute_mark1(res); } else { @@ -340,7 +340,7 @@ void reduce_hypotheses(proof_ref &pr) { class reduce_hypotheses0 { typedef obj_hashtable expr_set; ast_manager& m; - // reference for any expression created by the tranformation + // reference for any expression created by the transformation expr_ref_vector m_refs; // currently computed result obj_map m_cache; @@ -352,7 +352,7 @@ class reduce_hypotheses0 { unsigned_vector m_limits; // map from proofs to active hypotheses obj_map m_hypmap; - // refernce train for hypotheses sets + // reference train for hypotheses sets ptr_vector m_hyprefs; ptr_vector m_literals; @@ -492,7 +492,7 @@ public: // replace result by m_units[m.get_fact (p)] if defined // AG: This is the main step. Replace a hypothesis by a derivation of its consequence if (!m_units.find(m.get_fact(p), result)) { - // restore ther result back to p + // restore the result back to p result = p.get(); } // compute hypothesis of the result diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 65c8860b1..572abc8fe 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -761,7 +761,7 @@ public: return m_array_fid; } virtual char const * get_usage() const { return " (+) "; } - virtual char const * get_descr(cmd_context & ctx) const { return "declare a new array map operator with name using the given function declaration.\n ::= \n | ( (*) )\n | ((_ +) (*) )\nThe last two cases are used to disumbiguate between declarations with the same name and/or select (indexed) builtin declarations.\nFor more details about the the array map operator, see 'Generalized and Efficient Array Decision Procedures' (FMCAD 2009).\nExample: (declare-map set-union (Int) (or (Bool Bool) Bool))\nDeclares a new function (declare-fun set-union ((Array Int Bool) (Array Int Bool)) (Array Int Bool)).\nThe instance of the map axiom for this new declaration is:\n(forall ((a1 (Array Int Bool)) (a2 (Array Int Bool)) (i Int)) (= (select (set-union a1 a2) i) (or (select a1 i) (select a2 i))))"; } + virtual char const * get_descr(cmd_context & ctx) const { return "declare a new array map operator with name using the given function declaration.\n ::= \n | ( (*) )\n | ((_ +) (*) )\nThe last two cases are used to disumbiguate between declarations with the same name and/or select (indexed) builtin declarations.\nFor more details about the array map operator, see 'Generalized and Efficient Array Decision Procedures' (FMCAD 2009).\nExample: (declare-map set-union (Int) (or (Bool Bool) Bool))\nDeclares a new function (declare-fun set-union ((Array Int Bool) (Array Int Bool)) (Array Int Bool)).\nThe instance of the map axiom for this new declaration is:\n(forall ((a1 (Array Int Bool)) (a2 (Array Int Bool)) (i Int)) (= (select (set-union a1 a2) i) (or (select a1 i) (select a2 i))))"; } virtual unsigned get_arity() const { return 3; } virtual void prepare(cmd_context & ctx) { m_name = symbol::null; m_domain.reset(); } virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index 1711b65ad..165f1d2bc 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -112,9 +112,9 @@ namespace Duality { }; - /** This is the main solver. It takes anarbitrary (possibly cyclic) + /** This is the main solver. It takes an arbitrary (possibly cyclic) RPFP and either annotates it with a solution, or returns a - counterexample derivation in the form of an embedd RPFP tree. */ + counterexample derivation in the form of an embedded RPFP tree. */ class Duality : public Solver { diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index b09af94bc..c4dedb043 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -233,7 +233,7 @@ namespace polynomial { /** \brief Install a "delete polynomial" event handler. - The even hanlder is not owned by the polynomial manager. + The event handler is not owned by the polynomial manager. If eh = 0, then it uninstall the event handler. */ void add_del_eh(del_eh * eh); @@ -426,7 +426,7 @@ namespace polynomial { polynomial * flip_sign_if_lm_neg(polynomial const * p); /** - \breif Return the gcd g of p and q. + \brief Return the gcd g of p and q. */ void gcd(polynomial const * p, polynomial const * q, polynomial_ref & g); @@ -853,7 +853,7 @@ namespace polynomial { void resultant(polynomial const * p, polynomial const * q, var x, polynomial_ref & r); /** - \brief Stroe in r the discriminant of p with respect to variable x. + \brief Store in r the discriminant of p with respect to variable x. discriminant(p, x, r) == resultant(p, derivative(p, x), x, r) */ void discriminant(polynomial const * p, var x, polynomial_ref & r); @@ -959,7 +959,7 @@ namespace polynomial { } /** - \brief Apply substiution [x -> p/q] in r. + \brief Apply substitution [x -> p/q] in r. That is, given r \in Z[x, y_1, .., y_m] return polynomial q^k * r(p/q, y_1, .., y_m), where k is the maximal degree of x in r. */ diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index 11a37648a..a1f6e6ec1 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -152,7 +152,7 @@ public: } /** - \brief 'Disagonalizes' the matrix using only column operations. The reusling matrix will have -1 at pivot + \brief 'Diagonalizes' the matrix using only column operations. The resulting matrix will have -1 at pivot elements. Returns the rank of the null space. */ unsigned diagonalize() { @@ -170,7 +170,7 @@ public: m_column_pivot[j] = i; m_row_pivot[i] = j; - // found a pivot, to make it -1 we compute the multuplier -p^-1 + // found a pivot, to make it -1 we compute the multiplier -p^-1 m_zpm.set(multiplier, get(i, j)); m_zpm.inv(multiplier); m_zpm.neg(multiplier); @@ -201,7 +201,7 @@ public: } /** - If rank of the matrix is n - r, we are interested in linearly indeprendent vectors v_1, ..., v_r (the basis of + If rank of the matrix is n - r, we are interested in linearly independent vectors v_1, ..., v_r (the basis of the null space), such that v_k A = 0. This method will give one at a time. The method returns true if vector has been computed properly. The first vector [1, 0, ..., 0] is ignored (m_null_row starts from 1). */ @@ -417,7 +417,7 @@ bool zp_factor_square_free_berlekamp(zp_manager & upm, numeral_vector const & f, // construct the berlekamp Q matrix to get the null space berlekamp_matrix Q_I(upm, f); - // copy the inital polynomial to factors + // copy the initial polynomial to factors unsigned first_factor = factors.distinct_factors(); factors.push_back(f, 1); @@ -473,7 +473,7 @@ bool zp_factor_square_free_berlekamp(zp_manager & upm, numeral_vector const & f, // get the gcd upm.gcd(v_k.size(), v_k.c_ptr(), current_factor.size(), current_factor.c_ptr(), gcd); - // if the gcd is 1, or the the gcd is f, we just ignroe it + // if the gcd is 1, or the gcd is f, we just ignore it if (gcd.size() != 1 && gcd.size() != current_factor.size()) { // get the divisor also (no need to normalize the div, both are monic) @@ -568,13 +568,13 @@ bool check_hansel_lift(z_manager & upm, numeral_vector const & C, } /** - Performs a Hensel lift of A and B in Z_a to Z_b, where p is prime and and a = p^{a_k}, b = p^{b_k}, + Performs a Hensel lift of A and B in Z_a to Z_b, where p is prime and a = p^{a_k}, b = p^{b_k}, r = (a, b), with the following assumptions: - (1) UA + VB = 1 (mod a) + (1) UA + VB = 1 (mod a) (2) C = A*B (mod b) - (3) (l(A), r) = 1 (importand in order to divide by A, i.e. to invert l(A)) - (4) deg(A) + deg(B) = deg(C) + (3) (l(A), r) = 1 (important in order to divide by A, i.e. to invert l(A)) + (4) deg(A) + deg(B) = deg(C) The output of is two polynomials A1, B1 such that A1 = A (mod b), B1 = B (mod b), l(A1) = l(A), deg(A1) = deg(A), deg(B1) = deg(B) and C = A1 B1 (mod b*r). Such A1, B1 are unique if @@ -625,7 +625,7 @@ void hensel_lift(z_manager & upm, numeral const & a, numeral const & b, numeral // having (1) AU + BV = 1 (mod r) and (5) AT + BS = f (mod r), we know that // A*(fU) + B*(fV) = f (mod r), i.e. T = fU, S = fV is a solution // but we also know that we need an S with deg(S) <= deg(A) so we can do the following - // we know that l(A) is invertible so we can find the exact remainder of fV with A, i.e. find the qotient + // we know that l(A) is invertible so we can find the exact remainder of fV with A, i.e. find the quotient // t in the division and set // A*(fU + tB) + B*(fV - tA) = f // T = fU + tB, S = fU - tA @@ -1093,7 +1093,7 @@ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, continue; } - // if it's not square free, we also try somehting else + // if it's not square free, we also try something else scoped_numeral_vector f_pp_zp(nm); to_zp_manager(zp_upm, f_pp, f_pp_zp); @@ -1170,7 +1170,7 @@ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, zp_numeral_manager & zpe_nm = zpe_upm.m(); zp_factors zpe_fs(zpe_upm); - // this might give something bigger than p^e, but the lifting proocedure will update the zpe_nm + // this might give something bigger than p^e, but the lifting procedure will update the zpe_nm // zp factors are monic, so will be the zpe factors, i.e. f_pp = zpe_fs * lc(f_pp) (mod p^e) hensel_lift(upm, f_pp, zp_fs, e, zpe_fs); @@ -1182,7 +1182,7 @@ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, scoped_numeral f_pp_lc(nm); zpe_nm.set(f_pp_lc, f_pp.back()); - // we always keep in f_pp the the actual primitive part f_pp*lc(f_pp) + // we always keep in f_pp the actual primitive part f_pp*lc(f_pp) upm.mul(f_pp, f_pp_lc); // now we go through the combinations of factors to check construct the factorization @@ -1287,7 +1287,7 @@ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, fs.push_back(f_pp, k); } else { - // if a constant it must be 1 (it was primitve) + // if a constant it must be 1 (it was primitive) SASSERT(f_pp.size() == 1 && nm.is_one(f_pp.back())); } diff --git a/src/math/polynomial/upolynomial_factorization.h b/src/math/polynomial/upolynomial_factorization.h index 6fe0f2be6..c33f1844d 100644 --- a/src/math/polynomial/upolynomial_factorization.h +++ b/src/math/polynomial/upolynomial_factorization.h @@ -34,12 +34,12 @@ namespace upolynomial { typedef manager::scoped_numeral scoped_numeral; /** - \breif Factor f into f = f_1^k_1 * ... * p_n^k_n, such that p_i are square-free and coprime. + \brief Factor f into f = f_1^k_1 * ... * p_n^k_n, such that p_i are square-free and coprime. */ void zp_square_free_factor(zp_manager & zp_upm, numeral_vector const & f, zp_factors & sq_free_factors); /** - \brief Factor the monic square-free polynomial f from Z_p[x]. Returns true if factorization was sucesseful, or false + \brief Factor the monic square-free polynomial f from Z_p[x]. Returns true if factorization was successful, or false if f is an irreducible square-free polynomial in Z_p[x]. */ bool zp_factor_square_free(zp_manager & zp_upm, numeral_vector const & f, zp_factors & factors); @@ -55,17 +55,17 @@ namespace upolynomial { bool zp_factor_square_free_berlekamp(zp_manager & zp_upm, numeral_vector const & f, zp_factors & factors, bool randomized = true); /** - \brief Factor the polynomial f from Z_p[x]. Returns true if factorization was sucesseful, or false if f is + \brief Factor the polynomial f from Z_p[x]. Returns true if factorization was successful, or false if f is an irreducible polynomial in Z_p[x] */ bool zp_factor(zp_manager & zp_upm, numeral_vector const & f, zp_factors & factors); /** - \brief Performs a Hensel lift of A and B in Z_a to Z_b, where p is prime and and a = p^{a_k}, b = p^{b_k}, + \brief Performs a Hensel lift of A and B in Z_a to Z_b, where p is prime and a = p^{a_k}, b = p^{b_k}, r = (a, b), with the following assumptions: * UA + VB = 1 (mod a) * C = AB (mod b) - * (l(A), r) = 1 (importand in order to divide by A, i.e. to invert l(A)) + * (l(A), r) = 1 (important in order to divide by A, i.e. to invert l(A)) the output of is two polynomials A1, B1 (replacing A and B) such that A1 = A (mod b), B1 = B (mod b), l(A1) = l(A), deg(A1) = deg(A), deg(B1) = deg(B) and C = A1 B1 (mod b*r). Such A1, B1 are unique if r is prime. See [3] p. 138. @@ -82,7 +82,7 @@ namespace upolynomial { void hensel_lift(z_manager & upm, numeral_vector const & f, zp_factors const & factors_p, unsigned e, zp_factors & factors_pe); /** - \brief Factor the square-free polynomial f from Z[x]. Returns true if factorization was sucesseful, or false if + \brief Factor the square-free polynomial f from Z[x]. Returns true if factorization was successful, or false if f is an irreducible polynomial in Z[x]. The vector of factors is cleared. */ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, factor_params const & ps = factor_params()); diff --git a/src/muz/rel/aig_exporter.cpp b/src/muz/rel/aig_exporter.cpp index bc98ab1f8..3fed47f80 100644 --- a/src/muz/rel/aig_exporter.cpp +++ b/src/muz/rel/aig_exporter.cpp @@ -32,7 +32,7 @@ namespace datalog { predicates.insert(I->first); } - // reserve pred id = 0 for initalization purposes + // reserve pred id = 0 for initialization purposes unsigned num_preds = (unsigned)predicates.size() + 1; // poor's man round-up log2 diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index 0d70212e2..7e274cbef 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -67,7 +67,7 @@ namespace datalog { } relation_base * sieve_relation::complement(func_decl* p) const { - //this is not precisely a complement, because we still treat the ignored collumns as + //this is not precisely a complement, because we still treat the ignored columns as //full, but it should give reasonable results inside the product relation relation_base * new_inner = get_inner().complement(p); return get_plugin().mk_from_inner(get_signature(), m_inner_cols.c_ptr(), new_inner); diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index a699cf165..d3481dc7f 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -424,7 +424,7 @@ namespace datalog { /** \c array \c removed_cols contains column indexes to be removed in ascending order and - is terminated by a number greated than the highest column index of a join the the two tables. + is terminated by a number greater than the highest column index of a join the two tables. This is to simplify the traversal of the array when building facts. */ static void concatenate_rows(const column_layout & layout1, const column_layout & layout2, @@ -436,7 +436,7 @@ namespace datalog { columns from t2 using indexing. \c array \c removed_cols contains column indexes to be removed in ascending order and - is terminated by a number greated than the highest column index of a join the the two tables. + is terminated by a number greater than the highest column index of a join the two tables. This is to simplify the traversal of the array when building facts. \c tables_swapped value means that the resulting facts should contain facts from t2 first, diff --git a/src/muz/spacer/spacer_matrix.h b/src/muz/spacer/spacer_matrix.h index 4fc418f2b..a5ee909b2 100644 --- a/src/muz/spacer/spacer_matrix.h +++ b/src/muz/spacer/spacer_matrix.h @@ -25,7 +25,7 @@ namespace spacer { class spacer_matrix { public: - spacer_matrix(unsigned m, unsigned n); // m rows, n colums + spacer_matrix(unsigned m, unsigned n); // m rows, n columns unsigned num_rows(); unsigned num_cols(); diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 3a6c3f067..8d32a0edf 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -242,7 +242,7 @@ namespace nlsat { } /** - \breif Store in ps the polynomials occurring in the given literals. + \brief Store in ps the polynomials occurring in the given literals. */ void collect_polys(unsigned num, literal const * ls, polynomial_ref_vector & ps) { ps.reset(); @@ -332,7 +332,7 @@ namespace nlsat { if (!is_zero(lc)) { if (sign(lc) != 0) return; - // lc is not the zero polynomial, but it vanished in the current interpretaion. + // lc is not the zero polynomial, but it vanished in the current interpretation. // so we keep searching... add_zero_assumption(lc); } diff --git a/src/test/rational.cpp b/src/test/rational.cpp index 7b5e474f0..0618a01fb 100644 --- a/src/test/rational.cpp +++ b/src/test/rational.cpp @@ -387,9 +387,9 @@ static void tst9() { static void tst10(bool use_ints) { if (use_ints) - std::cout << "Testing multiplication performace using small ints\n"; + std::cout << "Testing multiplication performance using small ints\n"; else - std::cout << "Testing multiplication performace using small rationals\n"; + std::cout << "Testing multiplication performance using small rationals\n"; vector vals; vector vals2; vector fvals; diff --git a/src/util/gparams.h b/src/util/gparams.h index 894732890..7ddaf0ccb 100644 --- a/src/util/gparams.h +++ b/src/util/gparams.h @@ -47,7 +47,7 @@ public: set_global_param('pp.decimal', 'true') will set the parameter "decimal" in the module "pp" to true. - An exception is thrown if the the parameter name is unknown, or if the value is incorrect. + An exception is thrown if the parameter name is unknown, or if the value is incorrect. */ static void set(char const * name, char const * value); static void set(symbol const & name, char const * value); @@ -57,7 +57,7 @@ public: If the parameter is not set, then it just returns 'default'. - An exception is thrown if the the parameter name is unknown. + An exception is thrown if the parameter name is unknown. */ static std::string get_value(char const * name); static std::string get_value(symbol const & name); diff --git a/src/util/mpz.h b/src/util/mpz.h index f04430e17..f4629958f 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -187,7 +187,7 @@ class mpz_manager { /** \brief Set \c a with the value stored at m_tmp[IDX], and the given sign. - \c sz is an overapproximation of the the size of the number stored at \c tmp. + \c sz is an overapproximation of the size of the number stored at \c tmp. */ template void set(mpz & a, int sign, unsigned sz); From eca250933df23dbc170c49df91c813c8327c8a6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2018 19:56:01 -0800 Subject: [PATCH 0506/1283] disable uhle from lookahead solver Signed-off-by: Nikolaj Bjorner --- src/opt/opt_parse.cpp | 229 ++++++++++++++++++++++++++++++----- src/sat/sat_asymm_branch.cpp | 34 +----- src/sat/sat_asymm_branch.h | 2 - src/sat/sat_big.cpp | 4 +- src/sat/sat_big.h | 2 +- src/sat/sat_config.cpp | 1 - src/sat/sat_config.h | 1 - src/sat/sat_lookahead.cpp | 29 +---- src/sat/sat_lookahead.h | 2 - src/sat/sat_params.pyg | 1 - src/sat/sat_scc.cpp | 2 +- src/sat/sat_simplifier.cpp | 2 +- 12 files changed, 213 insertions(+), 96 deletions(-) diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 2cba7561f..6a7ea3614 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -36,40 +36,36 @@ public: void next() { m_val = m_stream.get(); } bool eof() const { return ch() == EOF; } unsigned line() const { return m_line; } - void skip_whitespace(); - void skip_space(); - void skip_line(); + void skip_whitespace() { + while ((ch() >= 9 && ch() <= 13) || ch() == 32) { + if (ch() == 10) ++m_line; + next(); + } + } + void skip_space() { + while (ch() != 10 && ((ch() >= 9 && ch() <= 13) || ch() == 32)) + next(); + } + void skip_line() { + while(true) { + if (eof()) { + return; + } + if (ch() == '\n') { + ++m_line; + next(); + return; + } + next(); + } + } bool parse_token(char const* token); int parse_int(); unsigned parse_unsigned(); }; -void opt_stream_buffer::skip_whitespace() { - while ((ch() >= 9 && ch() <= 13) || ch() == 32) { - if (ch() == 10) ++m_line; - next(); - } -} -void opt_stream_buffer::skip_space() { - while (ch() != 10 && ((ch() >= 9 && ch() <= 13) || ch() == 32)) { - next(); - } -} -void opt_stream_buffer::skip_line() { - while(true) { - if (eof()) { - return; - } - if (ch() == '\n') { - ++m_line; - next(); - return; - } - next(); - } -} bool opt_stream_buffer::parse_token(char const* token) { skip_whitespace(); @@ -314,4 +310,183 @@ void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h) { opb.parse(); } +#if 0 +class lp_stream_buffer : opt_stream_buffer { +public: + lp_stream_buffer(std::istream & s): + opt_stream_buffer(s) + {} + + char lower(char c) { + return ('A' <= c && c <= 'Z') ? c - 'A' + 'a' : c; + } + + bool parse_token_nocase(char const* token) { + skip_whitespace(); + char const* t = token; + while (lower(ch()) == *t) { + next(); + ++t; + } + return 0 == *t; + } +}; + + +class lp_tokenizer { + opt_stream_buffer& in; +public: + lp_tokenizer(opt_stream_buffer& in): + in(in) + {} + +}; + +class lp_parse { + opt::context& opt; + lp_tokenizer& tok; +public: + lp_parse(opt::context& opt, lp_stream_buffer& in): opt(opt), tok(is) {} + + void parse() { + objective(); + subject_to(); + bounds(); + general(); + binary(); + } + + void objective() { + m_objective.m_is_max = minmax(); + m_objective.m_name = try_name(); + m_objective.m_expr = expr(); + } + + bool minmax() { + if (try_accept("minimize")) + return false; + if (try_accept("min")) + return false; + if (try_accept("maximize")) + return true; + if (try_accept("max")) + return true; + error("expected min or max objective"); + return false; + } + + bool try_accept(char const* token) { + return false; + } + + bool indicator(symbol& var, bool& val) { + if (!try_variable(var)) return false; + check(in.parse_token("=")); + + } + + + def indicator(self): + v = self.variable() + self.accept("=") + val = self.try_accept("1") + if val is None: + val = self.accept("0") + self.accept("->") + return (var, val) + + def try_indicator(self): + try: + return self.indicator() + with: + return None + + def constraints(self): + return [c for c in self._constraints()] + + def _constraints(self): + while True: + c = self.try_constraint() + if c in None: + return + yield c + + def try_constraint(self): + try: + return self.constraint() + except: + return None + + def constraint(self): + name = self.try_label() + guard = self.try_guard() + e = self.expr() + op = self.relation() + rhs = self.numeral() + return (name, guard, e, ops, rhs) + + def expr(self): + return [t for t in self.terms()] + + def terms(self): + while True: + t = self.term() + if t is None: + return None + yield t + + def term(self): + sign = self.sign() + coeff = self.coeff() + v = self.variable() + return (sign*coeff, v) + + def sign(self): + if self.try_accept("-"): + return -1 + return 1 + + def coeff(self): + tok = self.peek() + if tok is int: + self.next() + return (int) tok + return 1 + + def relation(self): + if self.try_accept("<="): + return "<=" + if self.try_accept(">="): + return ">=" + if self.try_accept("=<"): + return "<=" + if self.try_accept("=>"): + return ">=" + if self.try_accept("="): + return "=" + return None + + def subject_to(self): + if self.accept("subject") and self.accept("to"): + return + if self.accept("such") and self.accept("that"): + return + if self.accept("st"): + return + if self.accept("s"): + self.try_accept(".") + self.accept("t") + self.accept(".") + return + + +}; + +void parse_lp(opt::context& opt, std::istream& is) { + lp_stream_buffer _is(is); + lp_parse lp(opt, _is); + lp.parse(); +} + +#endif diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index b05de55e6..a94ea461a 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -150,27 +150,6 @@ namespace sat { } } - void asymm_branch::operator()(big& big) { - s.propagate(false); - if (s.m_inconsistent) - return; - report rpt(*this); - - for (unsigned i = 0; i < m_asymm_branch_rounds; ++i) { - unsigned elim = m_elim_literals; - big.reinit(); - process(&big, s.m_clauses); - process(&big, s.m_learned); - process_bin(big); - unsigned num_elim = m_elim_literals - elim; - IF_VERBOSE(1, verbose_stream() << "(sat-asymm-branch-step :elim " << num_elim << ")\n";); - if (num_elim == 0) - break; - if (num_elim > 1000) - i = 0; - } - s.propagate(false); - } void asymm_branch::operator()(bool force) { ++m_calls; @@ -196,11 +175,11 @@ namespace sat { ++counter; change = false; if (m_asymm_branch_sampled) { - big big(s.m_rand, true); + big big(s.m_rand); if (process(big, true)) change = true; } if (m_asymm_branch_sampled) { - big big(s.m_rand, false); + big big(s.m_rand); if (process(big, false)) change = true; } if (m_asymm_branch) { @@ -431,11 +410,10 @@ namespace sat { bool asymm_branch::process_sampled(big& big, clause & c) { scoped_detach scoped_d(s, c); sort(big, c); - if (!big.learned() && !c.is_learned() && uhte(big, c)) { - // TBD: mark clause as learned. - ++m_hidden_tautologies; - scoped_d.del_clause(); - return false; + if (uhte(big, c)) { + // don't touch hidden tautologies. + // ATE takes care of them. + return true; } return uhle(scoped_d, big, c); } diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index fb8048c37..1a57f8800 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -91,8 +91,6 @@ namespace sat { void operator()(bool force); - void operator()(big& big); - void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index b35930e96..9c2bef50e 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -21,9 +21,8 @@ Revision History: namespace sat { - big::big(random_gen& rand, bool binary): + big::big(random_gen& rand): m_rand(rand) { - m_binary = binary; } void big::init(solver& s, bool learned) { @@ -141,7 +140,6 @@ namespace sat { } unsigned big::reduce_tr(solver& s) { - if (!m_binary && learned()) return 0; unsigned num_lits = s.num_vars() * 2; unsigned idx = 0; unsigned elim = 0; diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index 8477ad186..cb3466d26 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -41,7 +41,7 @@ namespace sat { public: - big(random_gen& rand, bool binary); + big(random_gen& rand); /** \brief initialize a BIG from a solver. */ diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index c3352797e..e2cbf0e3c 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -76,7 +76,6 @@ namespace sat { m_unit_walk_threads = p.unit_walk_threads(); m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify_bca = p.lookahead_simplify_bca(); - m_lookahead_simplify_asymm_branch = p.lookahead_simplify_asymm_branch(); if (p.lookahead_reward() == symbol("heule_schur")) m_lookahead_reward = heule_schur_reward; else if (p.lookahead_reward() == symbol("heuleu")) diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index e64c0c544..d70ae0cb7 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -94,7 +94,6 @@ namespace sat { bool m_unit_walk; bool m_lookahead_simplify; bool m_lookahead_simplify_bca; - bool m_lookahead_simplify_asymm_branch; cutoff_t m_lookahead_cube_cutoff; double m_lookahead_cube_fraction; unsigned m_lookahead_cube_depth; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 5bf3a194d..804f06341 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2306,16 +2306,12 @@ namespace sat { roots[v] = p; VERIFY(get_parent(p) == p); VERIFY(get_parent(~p) == ~p); - IF_VERBOSE(0, verbose_stream() << p << " " << q << "\n";); } } IF_VERBOSE(1, verbose_stream() << "(sat-lookahead :equivalences " << to_elim.size() << ")\n";); elim_eqs elim(m_s); elim(roots, to_elim); - if (get_config().m_lookahead_simplify_asymm_branch) { - big_asymm_branch(learned); - } if (learned && get_config().m_lookahead_simplify_bca) { add_hyper_binary(); } @@ -2324,29 +2320,6 @@ namespace sat { m_lookahead.reset(); } - /** - \brief extract binary implication graph from learned binary clauses and use it - for strengthening clauses. - */ - - void lookahead::big_asymm_branch(bool learned) { - unsigned num_lits = m_s.num_vars() * 2; - unsigned idx = 0; - big big(m_s.m_rand, false); - big.init_adding_edges(m_s.num_vars(), learned); - for (auto const& lits : m_binary) { - literal u = get_parent(to_literal(idx++)); - if (u == null_literal) continue; - for (literal v : lits) { - v = get_parent(v); - if (v != null_literal) - big.add_edge(u, v); - } - } - big.done_adding_edges(); - asymm_branch ab(m_s, m_s.m_params); - ab(big); - } /** \brief reduction based on binary implication graph @@ -2372,7 +2345,7 @@ namespace sat { } } - big big(m_s.m_rand, false); + big big(m_s.m_rand); big.init(m_s, true); svector> candidates; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 794d868f1..a37f32a1b 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -555,8 +555,6 @@ namespace sat { void add_hyper_binary(); - void big_asymm_branch(bool learned); - double psat_heur(); public: diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 3630365d6..c702941f6 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -51,7 +51,6 @@ def_module_params('sat', ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead_simplify.bca', BOOL, True, 'add learned binary clauses as part of lookahead simplification'), - ('lookahead_simplify.asymm_branch', BOOL, True, 'apply asymmetric branch simplification with lookahead simplifier'), ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'))) diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 484cb93ff..3010c92f2 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -27,7 +27,7 @@ namespace sat { scc::scc(solver & s, params_ref const & p): m_solver(s), - m_big(s.m_rand, true) { + m_big(s.m_rand) { reset_statistics(); updt_params(p); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 831539351..f439036b2 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -214,7 +214,7 @@ namespace sat { } register_clauses(s.m_clauses); - if (bce_enabled() || bca_enabled() || ate_enabled()) { + if (!learned && (bce_enabled() || bca_enabled() || ate_enabled())) { elim_blocked_clauses(); } From ad92bfb1a1bb58a7fb200fcb0334064f7dff5337 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2018 20:19:24 -0800 Subject: [PATCH 0507/1283] fix python build Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 5 +- src/sat/ba_solver.cpp | 1 - src/tactic/portfolio/default_tactic.cpp | 1 - src/tactic/portfolio/smt_strategic_solver.cpp | 1 - src/tactic/smtlogics/qfufnra_tactic.cpp | 50 ------------------- src/tactic/smtlogics/qfufnra_tactic.h | 31 ------------ src/util/memory_manager.cpp | 2 +- src/util/util.cpp | 2 +- 8 files changed, 4 insertions(+), 89 deletions(-) delete mode 100644 src/tactic/smtlogics/qfufnra_tactic.cpp delete mode 100644 src/tactic/smtlogics/qfufnra_tactic.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 05190f217..0b5bdb89e 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -11,10 +11,10 @@ from mk_util import * def init_project_def(): set_version(4, 5, 1, 0) add_lib('util', []) - add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) add_lib('nlsat', ['polynomial', 'sat']) + add_lib('lp', ['util','nlsat'], 'util/lp') add_lib('hilbert', ['util'], 'math/hilbert') add_lib('simplex', ['util'], 'math/simplex') add_lib('automata', ['util'], 'math/automata') @@ -69,10 +69,9 @@ def init_project_def(): add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf') add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality') add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf', 'spacer'], 'muz/fp') - add_lib('nlsat_smt_tactic', ['nlsat_tactic', 'smt_tactic'], 'tactic/nlsat_smt') 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','nlsat_smt_tactic'], 'tactic/smtlogics') + 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('smtparser', ['portfolio'], 'parsers/smt') diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 42a78b5f1..e7365ce8a 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -19,7 +19,6 @@ Revision History: #include "sat/ba_solver.h" #include "sat/sat_types.h" -#include "util/lp/lar_solver.h" namespace sat { diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index e463d2058..f040056a5 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -30,7 +30,6 @@ Notes: #include "tactic/fpa/qffp_tactic.h" #include "tactic/smtlogics/qfaufbv_tactic.h" #include "tactic/smtlogics/qfauflia_tactic.h" -#include "tactic/smtlogics/qfufnra_tactic.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 2b1f5bcdf..9a541f90e 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -36,7 +36,6 @@ Notes: #include "tactic/portfolio/fd_solver.h" #include "tactic/ufbv/ufbv_tactic.h" #include "tactic/fpa/qffp_tactic.h" -#include "tactic/smtlogics/qfufnra_tactic.h" #include "muz/fp/horn_tactic.h" #include "smt/smt_solver.h" #include "sat/sat_solver/inc_sat_solver.h" diff --git a/src/tactic/smtlogics/qfufnra_tactic.cpp b/src/tactic/smtlogics/qfufnra_tactic.cpp deleted file mode 100644 index e031b0f52..000000000 --- a/src/tactic/smtlogics/qfufnra_tactic.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - qfufnra_tactic.cpp - -Abstract: - - Tactic for QF_UFNRA - -Author: - - Nikolaj (nbjorner) 2015-05-05 - -Notes: - ---*/ -#include "tactic/tactical.h" -#include "tactic/core/simplify_tactic.h" -#include "tactic/core/propagate_values_tactic.h" -#include "tactic/nlsat_smt/nl_purify_tactic.h" -#include "tactic/smtlogics/qfufnra_tactic.h" -#include "tactic/arith/purify_arith_tactic.h" -#include "tactic/core/solve_eqs_tactic.h" -#include "tactic/core/elim_term_ite_tactic.h" -#include "tactic/core/elim_uncnstr_tactic.h" -#include "tactic/core/simplify_tactic.h" -#include "tactic/core/nnf_tactic.h" -#include "tactic/core/tseitin_cnf_tactic.h" - -tactic * mk_qfufnra_tactic(ast_manager & m, params_ref const& p) { - params_ref main_p = p; - main_p.set_bool("elim_and", true); - main_p.set_bool("blast_distinct", true); - - return and_then(and_then(using_params(mk_simplify_tactic(m, p), main_p), - mk_purify_arith_tactic(m, p), - mk_propagate_values_tactic(m, p), - mk_solve_eqs_tactic(m, p), - mk_elim_uncnstr_tactic(m, p)), - and_then(mk_elim_term_ite_tactic(m, p), - mk_solve_eqs_tactic(m, 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_nl_purify_tactic(m, p))); -} - - diff --git a/src/tactic/smtlogics/qfufnra_tactic.h b/src/tactic/smtlogics/qfufnra_tactic.h deleted file mode 100644 index 026ab5c5c..000000000 --- a/src/tactic/smtlogics/qfufnra_tactic.h +++ /dev/null @@ -1,31 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - qfufnra_tactic.h - -Abstract: - - Tactic for QF_UFNRA - -Author: - - Leonardo (leonardo) 2012-02-28 - -Notes: - ---*/ -#ifndef QFUFNRA_TACTIC_H_ -#define QFUFNRA_TACTIC_H_ - -#include "util/params.h" -class ast_manager; -class tactic; - -tactic * mk_qfufnra_tactic(ast_manager & m, params_ref const & p = params_ref()); -/* - ADD_TACTIC("qfufnra", "builtin strategy for solving QF_UNFRA problems.", "mk_qfufnra_tactic(m, p)") -*/ - -#endif diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 35bdce43d..52046447f 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -183,7 +183,7 @@ unsigned long long memory::get_max_used_memory() { } #if defined(_WINDOWS) -#include "Windows.h" +#include #endif unsigned long long memory::get_max_memory_size() { diff --git a/src/util/util.cpp b/src/util/util.cpp index bcf1dbdb8..f11c402b8 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #ifdef _WINDOWS -#include "windows.h" +#include #endif #include "util/util.h" From 161ee1c108ad4958c62fa6bd57b90597a71f6da7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2018 20:23:21 -0800 Subject: [PATCH 0508/1283] fix ugcd Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index e7365ce8a..653e578a3 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -19,6 +19,7 @@ Revision History: #include "sat/ba_solver.h" #include "sat/sat_types.h" +#include "util/mpz.h" namespace sat { From a6ac6958a6f2a3ae27c606fc2dbd4639260f4437 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2018 09:48:02 -0800 Subject: [PATCH 0509/1283] fix gcc compilation error Signed-off-by: Nikolaj Bjorner --- src/util/memory_manager.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 52046447f..7647e0989 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -11,6 +11,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/memory_manager.h" #include "util/error_codes.h" #include "util/z3_omp.h" +#include "util/debug.h" // The following two function are automatically generated by the mk_make.py script. // The script collects ADD_INITIALIZER and ADD_FINALIZER commands in the .h files. // For example, rational.h contains @@ -58,8 +59,6 @@ static void throw_out_of_memory() { g_memory_out_of_memory = true; } - __assume(0); - if (g_exit_when_out_of_memory) { std::cerr << g_out_of_memory_msg << "\n"; exit(ERR_MEMOUT); @@ -193,9 +192,8 @@ unsigned long long memory::get_max_memory_size() { GlobalMemoryStatusEx (&statex); return statex.ullTotalPhys; #else - NOT_IMPLEMENTED_YET(); - // two GB - return 1 << 31; + // 16 GB + return 1ull << 34ull; #endif } From ad3b0ecad0dc32ac06295a3164def5e029d7d66d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 2 Feb 2018 19:27:36 +0000 Subject: [PATCH 0510/1283] Fixed pattern rewriting to produce only valid patterns (which led to a segfault). Bug reported by Youcheng Sun. --- src/ast/rewriter/rewriter_def.h | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 2abd6d467..5a3b930c8 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -497,23 +497,27 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { SASSERT(fr.m_spos + num_children == result_stack().size()); expr * const * it = result_stack().c_ptr() + fr.m_spos; expr * new_body = *it; - expr * const * new_pats; - expr * const * new_no_pats; + unsigned num_pats = q->get_num_patterns(); + unsigned num_no_pats = q->get_num_no_patterns(); + expr_ref_vector new_pats(m_manager, num_pats, q->get_patterns()); + expr_ref_vector new_no_pats(m_manager, num_no_pats, q->get_no_patterns()); if (rewrite_patterns()) { TRACE("reduce_quantifier_bug", tout << "rewrite patterns\n";); - new_pats = it + 1; - new_no_pats = new_pats + q->get_num_patterns(); - } - else { - new_pats = q->get_patterns(); - new_no_pats = q->get_no_patterns(); + expr * const * np = it + 1; + expr * const * nnp = np + num_pats; + for (unsigned i = 0; i < num_pats; i++) + if (m_manager.is_pattern(np[i])) + new_pats[i] = np[i]; + for (unsigned i = 0; i < num_no_pats; i++) + if (m_manager.is_pattern(nnp[i])) + new_no_pats[i] = nnp[i]; } if (ProofGen) { - quantifier_ref new_q(m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body), m()); + quantifier_ref new_q(m().update_quantifier(q, num_pats, new_pats.c_ptr(), num_no_pats, new_no_pats.c_ptr(), new_body), m()); m_pr = q == new_q ? 0 : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos)); m_r = new_q; proof_ref pr2(m()); - if (m_cfg.reduce_quantifier(new_q, new_body, new_pats, new_no_pats, m_r, pr2)) { + if (m_cfg.reduce_quantifier(new_q, new_body, new_pats.c_ptr(), new_no_pats.c_ptr(), m_r, pr2)) { m_pr = m().mk_transitivity(m_pr, pr2); } TRACE("reduce_quantifier_bug", tout << "m_pr is_null: " << (m_pr.get() == 0) << "\n"; @@ -524,9 +528,9 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { else { expr_ref tmp(m()); TRACE("reduce_quantifier_bug", tout << mk_ismt2_pp(q, m()) << " " << mk_ismt2_pp(new_body, m()) << "\n";); - if (!m_cfg.reduce_quantifier(q, new_body, new_pats, new_no_pats, m_r, m_pr)) { + if (!m_cfg.reduce_quantifier(q, new_body, new_pats.c_ptr(), new_no_pats.c_ptr(), m_r, m_pr)) { if (fr.m_new_child) { - m_r = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body); + m_r = m().update_quantifier(q, num_pats, new_pats.c_ptr(), num_no_pats, new_no_pats.c_ptr(), new_body); } else { TRACE("rewriter_reuse", tout << "reusing:\n" << mk_ismt2_pp(q, m()) << "\n";); From e95840b640658557a278ea6f881ce2bbfc2c8b7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2018 20:51:41 -0800 Subject: [PATCH 0511/1283] ate/acce Signed-off-by: Nikolaj Bjorner --- src/opt/opt_parse.cpp | 78 +++++++++++++++++++++++++------ src/sat/sat_asymm_branch.cpp | 21 ++++----- src/sat/sat_asymm_branch.h | 2 +- src/sat/sat_simplifier.cpp | 13 ++++-- src/sat/sat_simplifier_params.pyg | 10 ++-- 5 files changed, 90 insertions(+), 34 deletions(-) diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 6a7ea3614..9ac0f77a0 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -344,23 +344,60 @@ public: }; class lp_parse { - opt::context& opt; - lp_tokenizer& tok; + typedef svector > lin_term; + + struct objective { + bool m_is_max; + symbol m_name; + lin_term m_expr; + }; + + enum rel_op { + le, ge, eq + }; + + struct indicator { + symbol m_var; + bool m_true; + }; + + struct constraint { + optional m_ind; + lin_term m_expr; + rel_op m_rel; + int m_bound; + }; + + struct bound { + symbol m_var; + option m_lo, m_hi; + }; + + opt::context& opt; + lp_tokenizer& tok; + objective m_objective; + vector m_constraints; + vector m_bounds; + hashtable m_binary; + public: - lp_parse(opt::context& opt, lp_stream_buffer& in): opt(opt), tok(is) {} + + lp_parse(opt::context& opt, lp_stream_buffer& in): + opt(opt), tok(is) {} void parse() { - objective(); - subject_to(); - bounds(); - general(); - binary(); + parse_objective(); + parse_subject_to(); + parse_bounds(); + parse_general(); + parse_binary(); + post_process(); } - void objective() { + void parse_objective() { m_objective.m_is_max = minmax(); m_objective.m_name = try_name(); - m_objective.m_expr = expr(); + parse_expr(m_objective.m_expr); } bool minmax() { @@ -376,16 +413,31 @@ public: return false; } + bool try_accept(char const* token) { return false; } - bool indicator(symbol& var, bool& val) { - if (!try_variable(var)) return false; - check(in.parse_token("=")); + bool parse_indicator(symbol& var, bool& val) { + if (!peek("=", 1)) return false; + if (!peek(":", 3)) return false; + if (!peek("1", 2) && !peek("0", 2)) return false; + val = peek("1",2); + parse_variable(var); + accept("="); + accept(); + accept(":"); + return true; + } + + void parse_bounds() { + if (!try_accept("bounds")) return; } + void parse_indicator() { + + } def indicator(self): v = self.variable() diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index a94ea461a..64b1d5e67 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -43,12 +43,12 @@ namespace sat { stopwatch m_watch; unsigned m_elim_literals; unsigned m_elim_learned_literals; - unsigned m_hidden_tautologies; + unsigned m_tr; report(asymm_branch & a): m_asymm_branch(a), m_elim_literals(a.m_elim_literals), m_elim_learned_literals(a.m_elim_learned_literals), - m_hidden_tautologies(a.m_hidden_tautologies) { + m_tr(a.m_tr) { m_watch.start(); } @@ -60,7 +60,7 @@ namespace sat { verbose_stream() << " (sat-asymm-branch :elim-literals " << (num_total - num_learned) << " :elim-learned-literals " << num_learned - << " :hte " << (m_asymm_branch.m_hidden_tautologies - m_hidden_tautologies) + << " :hte " << (m_asymm_branch.m_tr - m_tr) << " :cost " << m_asymm_branch.m_counter << mem_stat() << " :time " << std::fixed << std::setprecision(2) << m_watch.get_seconds() << ")\n";); @@ -68,15 +68,14 @@ namespace sat { }; void asymm_branch::process_bin(big& big) { - unsigned elim = big.reduce_tr(s); - m_hidden_tautologies += elim; + m_tr += big.reduce_tr(s); } bool asymm_branch::process(big& big, bool learned) { unsigned elim0 = m_elim_literals; unsigned eliml0 = m_elim_learned_literals; for (unsigned i = 0; i < m_asymm_branch_rounds; ++i) { - unsigned elim = m_elim_literals + m_hidden_tautologies; + unsigned elim = m_elim_literals + m_tr; big.init(s, learned); process(&big, s.m_clauses); process(&big, s.m_learned); @@ -84,11 +83,11 @@ namespace sat { s.propagate(false); if (s.m_inconsistent) break; - unsigned num_elim = m_elim_literals + m_hidden_tautologies - elim; + unsigned num_elim = m_elim_literals + m_tr - elim; IF_VERBOSE(1, verbose_stream() << "(sat-asymm-branch-step :elim " << num_elim << ")\n";); if (num_elim == 0) break; - if (num_elim > 100) + if (false && num_elim > 1000) i = 0; } IF_VERBOSE(1, if (m_elim_learned_literals > eliml0) @@ -149,7 +148,7 @@ namespace sat { throw ex; } } - + void asymm_branch::operator()(bool force) { ++m_calls; @@ -480,13 +479,13 @@ namespace sat { void asymm_branch::collect_statistics(statistics & st) const { st.update("elim literals", m_elim_literals); - st.update("hte", m_hidden_tautologies); + st.update("tr", m_tr); } void asymm_branch::reset_statistics() { m_elim_literals = 0; m_elim_learned_literals = 0; - m_hidden_tautologies = 0; + m_tr = 0; } }; diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index 1a57f8800..cc354a5c8 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -48,7 +48,7 @@ namespace sat { // stats unsigned m_elim_literals; unsigned m_elim_learned_literals; - unsigned m_hidden_tautologies; + unsigned m_tr; literal_vector m_pos, m_neg; // literals (complements of literals) in clauses sorted by discovery time (m_left in BIG). literal_vector m_to_delete; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index f439036b2..dee2afb87 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1394,11 +1394,17 @@ namespace sat { while (!is_tautology && m_covered_clause.size() > sz && !above_threshold(sz0)) { SASSERT(!is_tautology); + if ((et == abce_t || et == acce_t || et == ate_t) && add_ala()) { for (literal l : m_covered_clause) s.unmark_visited(l); return ate_t; } + if (et == ate_t) { + for (literal l : m_covered_clause) s.unmark_visited(l); + return no_t; + } + if (first) { for (unsigned i = 0; i < sz0; ++i) { if (check_abce_tautology(m_covered_clause[i])) { @@ -1440,7 +1446,6 @@ namespace sat { m_covered_clause.push_back(l); m_covered_antecedent.push_back(clause_ante()); } - // shuffle(s.s.m_rand, m_covered_clause); return cce(blocked, k); } @@ -1537,7 +1542,7 @@ namespace sat { // always try to remove larger clauses. template bool select_clause(unsigned sz) { - return et == ate_t || (sz > 3) || s.s.m_rand(4) == 0; + return (sz > 3) || s.s.m_rand(4) == 0; } void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { @@ -2080,8 +2085,8 @@ namespace sat { m_abce = p.abce(); m_ate = p.ate(); m_bce_delay = p.bce_delay(); - m_bce = p.elim_blocked_clauses(); - m_bce_at = p.elim_blocked_clauses_at(); + m_bce = p.bce(); + m_bce_at = p.bce_at(); m_retain_blocked_clauses = p.retain_blocked_clauses(); m_blocked_clause_limit = p.blocked_clause_limit(); m_res_limit = p.resolution_limit(); diff --git a/src/sat/sat_simplifier_params.pyg b/src/sat/sat_simplifier_params.pyg index 4bbc490cc..3757aad2d 100644 --- a/src/sat/sat_simplifier_params.pyg +++ b/src/sat/sat_simplifier_params.pyg @@ -1,14 +1,14 @@ def_module_params(module_name='sat', class_name='sat_simplifier_params', export=True, - params=(('elim_blocked_clauses', BOOL, False, 'eliminate blocked clauses'), + params=(('bce', BOOL, False, 'eliminate blocked clauses'), ('abce', BOOL, False, 'eliminate blocked clauses using asymmmetric literals'), - ('cce', BOOL, False, 'eliminate covered clauses'), - ('ate', BOOL, True, 'asymmetric tautology elimination'), + ('cce', BOOL, False, 'eliminate covered clauses'), + ('ate', BOOL, True, 'asymmetric tautology elimination'), ('acce', BOOL, False, 'eliminate covered clauses using asymmetric added literals'), - ('elim_blocked_clauses_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), + ('bce_at', UINT, 2, 'eliminate blocked clauses only once at the given simplification round'), ('bca', BOOL, False, 'blocked clause addition - add blocked binary clauses'), - ('bce_delay', UINT, 0, 'delay eliminate blocked clauses until simplification round'), + ('bce_delay', UINT, 2, 'delay eliminate blocked clauses until simplification round'), ('retain_blocked_clauses', BOOL, True, 'retain blocked clauses as lemmas'), ('blocked_clause_limit', UINT, 100000000, 'maximum number of literals visited during blocked clause elimination'), ('override_incremental', BOOL, False, 'override incemental safety gaps. Enable elimination of blocked clauses and variables even if solver is reused'), From 8689921e9cf96426ca47054f3f618300e7e1ce27 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 3 Feb 2018 15:16:23 +0000 Subject: [PATCH 0512/1283] Fixed missing bit of precision in fp.to_ubv/fp.to_sbv. Thanks to Youcheng Sun for reporting this bug. --- src/ast/fpa/fpa2bv_converter.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d2a946e0c..b2c07d56e 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3139,6 +3139,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); expr_ref bv0(m), bv1(m); + bv0 = m_bv_util.mk_numeral(0, 1); bv1 = m_bv_util.mk_numeral(1, 1); expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m); @@ -3188,9 +3189,9 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args exp_m_lz = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp), m_bv_util.mk_zero_extend(2, lz)); - // big_sig is +- [... bv_sz+2 bits ...].[r][g][ ... sbits-1 ... ] - big_sig = m_bv_util.mk_zero_extend(bv_sz+2, sig); - unsigned big_sig_sz = sig_sz+bv_sz+2; + // big_sig is +- [... bv_sz+2 bits ...][1].[r][ ... sbits-1 ... ] + big_sig = m_bv_util.mk_concat(m_bv_util.mk_zero_extend(bv_sz + 2, sig), bv0); + unsigned big_sig_sz = sig_sz+1+bv_sz+2; SASSERT(m_bv_util.get_bv_size(big_sig) == big_sig_sz); is_neg_shift = m_bv_util.mk_sle(exp_m_lz, m_bv_util.mk_numeral(0, ebits+2)); From c3ed9860318d3d9ae2b5f9c5da31264188b05794 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 3 Feb 2018 16:44:44 +0000 Subject: [PATCH 0513/1283] Fixed RNA FP rounding mode semantics. Fixes #1190 and bugs reported by Youcheng Sun. --- src/ast/fpa/fpa2bv_converter.cpp | 6 +----- src/util/mpf.cpp | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index b2c07d56e..7c13d4315 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3746,14 +3746,10 @@ expr_ref fpa2bv_converter::mk_rounding_decision(expr * rm, expr * sgn, expr * la expr * nround_lors[2] = { not_round, not_lors }; expr * pos_args[2] = { sgn, not_rors }; expr * neg_args[2] = { not_sgn, not_rors }; - expr * nl_r[2] = { last, not_round }; - expr * nl_nr_sn[3] = { not_last, not_round, not_sticky }; expr_ref inc_teven(m), inc_taway(m), inc_pos(m), inc_neg(m); inc_teven = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, nround_lors)); - expr *taway_args[2] = { m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, nl_r)), - m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(3, nl_nr_sn)) }; - inc_taway = m_bv_util.mk_bv_or(2, taway_args); + inc_taway = round; inc_pos = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, pos_args)); inc_neg = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, neg_args)); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 9e309a726..b9829f02d 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -2045,7 +2045,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { bool inc = false; switch (rm) { case MPF_ROUND_NEAREST_TEVEN: inc = round && (last || sticky); break; - case MPF_ROUND_NEAREST_TAWAY: inc = round && (!last || sticky); break; + case MPF_ROUND_NEAREST_TAWAY: inc = round; break; case MPF_ROUND_TOWARD_POSITIVE: inc = (!o.sign && (round || sticky)); break; case MPF_ROUND_TOWARD_NEGATIVE: inc = (o.sign && (round || sticky)); break; case MPF_ROUND_TOWARD_ZERO: inc = false; break; From 333374229d99157f6edd5bc6d21af595ed89dbd2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 3 Feb 2018 16:48:05 +0000 Subject: [PATCH 0514/1283] Fixed UFs for unspecified cases of FP conversion operators. Thanks for Youcheng Sun for reporting this bug. --- src/ast/fpa/fpa2bv_converter.cpp | 36 ++++++++++++++++++-------------- src/ast/fpa/fpa2bv_converter.h | 1 + 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 7c13d4315..df5d56505 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3098,13 +3098,11 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex join_fp(result, result); } else { - expr * n = args[0]; - expr_ref n_bv(m); - join_fp(n, n_bv); + expr_ref nw = nan_wrap(args[0]); - sort * domain[1] = { m.get_sort(n_bv) }; + sort * domain[1] = { m.get_sort(nw) }; func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); - result = m.mk_app(f_bv, n_bv); + result = m.mk_app(f_bv, nw); expr_ref exp_bv(m), exp_all_ones(m); exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result); @@ -3280,6 +3278,17 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg mk_to_bv(f, num, args, true, result); } +expr_ref fpa2bv_converter::nan_wrap(expr * n) { + expr_ref n_bv(m), arg_is_nan(m), nan(m), nan_bv(m), res(m); + mk_is_nan(n, arg_is_nan); + mk_nan(m.get_sort(n), nan); + join_fp(nan, nan_bv); + join_fp(n, n_bv); + res = expr_ref(m.mk_ite(arg_is_nan, nan_bv, n_bv), m); + SASSERT(is_well_sorted(m, res)); + return res; +} + void fpa2bv_converter::mk_to_bv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); SASSERT(m_util.is_bv2rm(args[0])); @@ -3289,13 +3298,10 @@ void fpa2bv_converter::mk_to_bv_unspecified(func_decl * f, unsigned num, expr * result = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(f->get_range())); else { expr * rm_bv = to_app(args[0])->get_arg(0); - expr * n = args[1]; - expr_ref n_bv(m); - join_fp(n, n_bv); - - sort * domain[2] = { m.get_sort(rm_bv), m.get_sort(n_bv) }; + expr_ref nw = nan_wrap(args[1]); + sort * domain[2] = { m.get_sort(rm_bv), m.get_sort(nw) }; func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); - result = m.mk_app(f_bv, rm_bv, n_bv); + result = m.mk_app(f_bv, rm_bv, nw); } TRACE("fpa2bv_to_bv_unspecified", tout << "result=" << mk_ismt2_pp(result, m) << std::endl;); @@ -3309,12 +3315,10 @@ void fpa2bv_converter::mk_to_real_unspecified(func_decl * f, unsigned num, expr result = m_arith_util.mk_numeral(rational(0), false); else { expr * n = args[0]; - expr_ref n_bv(m); - join_fp(n, n_bv); - - sort * domain[1] = { m.get_sort(n_bv) }; + expr_ref nw = nan_wrap(n); + sort * domain[1] = { m.get_sort(nw) }; func_decl * f_bv = mk_bv_uf(f, domain, f->get_range()); - result = m.mk_app(f_bv, n_bv); + result = m.mk_app(f_bv, nw); } } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index f0e50ba2d..062f7afe9 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -219,6 +219,7 @@ private: void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result); func_decl * mk_bv_uf(func_decl * f, sort * const * domain, sort * range); + expr_ref nan_wrap(expr * n); }; #endif From db347c007dcb242cf0e4830bdb06b55eb1f6482a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2018 09:39:39 -0800 Subject: [PATCH 0515/1283] remove legacy bce Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 4 +- src/sat/sat_simplifier.cpp | 109 ++++++------------------------------- 2 files changed, 18 insertions(+), 95 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index e2cbf0e3c..381692654 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -110,8 +110,8 @@ namespace sat { m_lookahead_global_autarky = p.lookahead_global_autarky(); // These parameters are not exposed - m_simplify_mult1 = _p.get_uint("simplify_mult1", 100); - m_simplify_mult2 = _p.get_double("simplify_mult2", 1.2); + m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); + m_simplify_mult2 = _p.get_double("simplify_mult2", 1.5); m_simplify_max = _p.get_uint("simplify_max", 500000); // -------------------------------- diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index dee2afb87..a18743438 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1003,6 +1003,7 @@ namespace sat { } enum elim_type { + bce_t, cce_t, acce_t, abce_t, @@ -1024,21 +1025,13 @@ namespace sat { cce(); } if (s.bce_enabled() && !s.cce_enabled() && !s.abce_enabled()) { - block_clauses(); + cce(); } if (s.bca_enabled()) { bca(); } } - void block_clauses() { - insert_queue(); - while (!m_queue.empty() && m_counter >= 0) { - s.checkpoint(); - process(m_queue.next()); - } - } - void insert_queue() { unsigned num_vars = s.s.num_vars(); for (bool_var v = 0; v < num_vars; v++) { @@ -1049,55 +1042,6 @@ namespace sat { } } - void process(literal l) { - TRACE("blocked_clause", tout << "processing: " << l << "\n";); - if (!process_var(l.var())) { - return; - } - integrity_checker si(s.s); - process_clauses(l); - process_binary(l); - } - - void process_binary(literal l) { - model_converter::entry* new_entry = 0; - watch_list & wlist = s.get_wlist(~l); - m_counter -= wlist.size(); - for (watched& w : wlist) { - if (!w.is_binary_non_learned_clause()) { - continue; - } - literal l2 = w.get_literal(); - s.mark_visited(l2); - if (all_tautology(l)) { - block_binary(w, l, new_entry); - w.set_learned(true); - s.s.set_learned1(l2, l, true); - s.m_num_bce++; - } - s.unmark_visited(l2); - } - } - - void process_clauses(literal l) { - model_converter::entry* new_entry = 0; - clause_use_list & occs = s.m_use_list.get(l); - clause_use_list::iterator it = occs.mk_iterator(); - for (; !it.at_end(); it.next()) { - clause & c = it.curr(); - if (c.is_learned()) continue; - m_counter -= c.size(); - SASSERT(c.contains(l)); - s.mark_all_but(c, l); - if (all_tautology(l)) { - block_clause(c, l, new_entry); - s.m_num_bce++; - s.set_learned(c); - } - s.unmark_all(c); - } - } - void reset_intersection() { for (literal l : m_intersection) m_in_intersection[l.index()] = false; m_intersection.reset(); @@ -1359,7 +1303,7 @@ namespace sat { } bool above_threshold(unsigned sz0) const { - if (sz0 * 400 < m_covered_clause.size()) IF_VERBOSE(0, verbose_stream() << "above threshold " << sz0 << " " << m_covered_clause.size() << "\n";); + // if (sz0 * 400 < m_covered_clause.size()) IF_VERBOSE(0, verbose_stream() << "above threshold " << sz0 << " " << m_covered_clause.size() << "\n";); return sz0 * 400 < m_covered_clause.size(); } @@ -1374,6 +1318,7 @@ namespace sat { switch (et) { case abce_t: + case bce_t: k = model_converter::BLOCK_LIT; break; case cce_t: @@ -1416,10 +1361,12 @@ namespace sat { first = false; } - if (is_tautology || et == abce_t) { + if (is_tautology || et == abce_t || et == bce_t) { for (literal l : m_covered_clause) s.unmark_visited(l); m_covered_clause.shrink(sz0); - return is_tautology ? abce_t : no_t; + if (!is_tautology) return no_t; + if (et == bce_t) return bce_t; + return abce_t; } /* @@ -1534,6 +1481,7 @@ namespace sat { case acce_t: s.m_num_acce++; break; case abce_t: s.m_num_abce++; break; case ate_t: s.m_num_ate++; break; + case bce_t: s.m_num_bce++; break; default: break; } } @@ -1545,52 +1493,27 @@ namespace sat { return (sz > 3) || s.s.m_rand(4) == 0; } - void prepare_block_clause(clause& c, literal l, model_converter::entry*& new_entry, model_converter::kind k) { + void block_covered_clause(clause& c, literal l, model_converter::kind k) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); - VERIFY(!s.is_external(l)); - if (new_entry == 0) - new_entry = &(mc.mk(k, l.var())); + SASSERT(!s.is_external(l)); + model_converter::entry& new_entry = mc.mk(k, l.var()); for (literal lit : c) { if (lit != l && process_var(lit.var())) { m_queue.decreased(~lit); } } - } - - void block_clause(clause& c, literal l, model_converter::entry *& new_entry) { - SASSERT(!s.is_external(l.var())); - prepare_block_clause(c, l, new_entry, model_converter::BLOCK_LIT); - mc.insert(*new_entry, c); - } - - void block_covered_clause(clause& c, literal l, model_converter::kind k) { - SASSERT(!s.is_external(l.var())); - model_converter::entry * new_entry = 0; - prepare_block_clause(c, l, new_entry, k); - mc.insert(*new_entry, m_covered_clause, m_elim_stack); + mc.insert(new_entry, m_covered_clause, m_elim_stack); } - void prepare_block_binary(watched const& w, literal l1, literal blocked, model_converter::entry*& new_entry, model_converter::kind k) { + void block_covered_binary(watched const& w, literal l1, literal blocked, model_converter::kind k) { SASSERT(!s.is_external(blocked)); - if (new_entry == 0) - new_entry = &(mc.mk(k, blocked.var())); + model_converter::entry& new_entry = mc.mk(k, blocked.var()); literal l2 = w.get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); s.set_learned(l1, l2); + mc.insert(new_entry, m_covered_clause, m_elim_stack); m_queue.decreased(~l2); } - - void block_binary(watched const& w, literal l, model_converter::entry *& new_entry) { - literal l2 = w.get_literal(); - prepare_block_binary(w, l, l, new_entry, model_converter::BLOCK_LIT); - mc.insert(*new_entry, l, l2); - } - - void block_covered_binary(watched const& w, literal l, literal blocked, model_converter::kind k) { - model_converter::entry * new_entry = 0; - prepare_block_binary(w, l, blocked, new_entry, k); - mc.insert(*new_entry, m_covered_clause, m_elim_stack); - } void bca() { m_queue.reset(); From d07688d80b444d2a5e81c0084f27551868a20502 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2018 15:52:34 -0800 Subject: [PATCH 0516/1283] update lia2card to handle broader intervals Signed-off-by: Nikolaj Bjorner --- src/sat/sat_watched.h | 1 - src/tactic/arith/lia2card_tactic.cpp | 123 +++++++++++++-------------- 2 files changed, 61 insertions(+), 63 deletions(-) diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index acd4ed9c0..09ad22ffd 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -62,7 +62,6 @@ namespace sat { SASSERT(is_ternary_clause()); SASSERT(get_literal1() == l1); SASSERT(get_literal2() == l2); - SASSERT(is_learned() == learned); } unsigned val2() const { return m_val2; } diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 4bcf24534..09facedbe 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -34,17 +34,29 @@ Author: Notes: --*/ -#include "tactic/tactical.h" #include "util/cooperate.h" -#include "tactic/arith/bound_manager.h" #include "ast/ast_pp.h" #include "ast/pb_decl_plugin.h" #include "ast/arith_decl_plugin.h" #include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/expr_safe_replace.h" #include "ast/ast_util.h" #include "ast/ast_pp_util.h" +#include "tactic/tactical.h" +#include "tactic/arith/bound_manager.h" +#include "tactic/generic_model_converter.h" class lia2card_tactic : public tactic { + + struct bound { + unsigned m_lo; + unsigned m_hi; + expr* m_expr; + bound(unsigned lo, unsigned hi, expr* b): + m_lo(lo), m_hi(hi), m_expr(b) {} + bound(): m_lo(0), m_hi(0), m_expr(0) {} + }; + struct lia_rewriter_cfg : public default_rewriter_cfg { ast_manager& m; lia2card_tactic& t; @@ -58,7 +70,7 @@ class lia2card_tactic : public tactic { coeffs.reset(); coeff.reset(); return - t.get_pb_sum(x, rational::one(), args, coeffs, coeff) && + t.get_pb_sum(x, rational::one(), args, coeffs, coeff) && t.get_pb_sum(y, -rational::one(), args, coeffs, coeff); } @@ -128,15 +140,17 @@ class lia2card_tactic : public tactic { }; public: - typedef obj_hashtable expr_set; + typedef obj_map bounds_map; ast_manager & m; arith_util a; lia_rewriter m_rw; params_ref m_params; pb_util m_pb; mutable ptr_vector* m_todo; - expr_set* m_01s; + bounds_map m_bounds; bool m_compile_equality; + unsigned m_max_ub; + ref m_mc; lia2card_tactic(ast_manager & _m, params_ref const & p): m(_m), @@ -144,13 +158,12 @@ public: m_rw(*this), m_pb(m), m_todo(alloc(ptr_vector)), - m_01s(alloc(expr_set)), m_compile_equality(false) { + m_max_ub = 100; } virtual ~lia2card_tactic() { dealloc(m_todo); - dealloc(m_01s); } void updt_params(params_ref const & p) { @@ -158,85 +171,75 @@ public: m_compile_equality = p.get_bool("compile_equality", false); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result) { + expr_ref mk_bounded(expr_ref_vector& axioms, app* x, unsigned lo, unsigned hi) { + expr_ref_vector xs(m); + expr_ref last_v(m); + if (!m_mc) m_mc = alloc(generic_model_converter, m, "lia2card"); + for (unsigned i = 0; i < hi; ++i) { + if (i < lo) { + xs.push_back(a.mk_int(1)); + continue; + } + std::string name(x->get_decl()->get_name().str()); + expr_ref v(m.mk_fresh_const(name.c_str(), m.mk_bool_sort()), m); + if (last_v) axioms.push_back(m.mk_implies(v, last_v)); + xs.push_back(m.mk_ite(v, a.mk_int(1), a.mk_int(0))); + m_mc->hide(v); + last_v = v; + } + expr* r = a.mk_add(xs.size(), xs.c_ptr()); + m_mc->add(x->get_decl(), r); + return expr_ref(r, m); + } + + virtual void operator()(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); - m_01s->reset(); + m_bounds.reset(); + m_mc.reset(); + expr_ref_vector axioms(m); + expr_safe_replace rep(m); tactic_report report("cardinality-intro", *g); bound_manager bounds(m); bounds(*g); - for (expr* x : bounds) { bool s1 = false, s2 = false; rational lo, hi; if (a.is_int(x) && - bounds.has_lower(x, lo, s1) && !s1 && lo.is_zero() && - bounds.has_upper(x, hi, s2) && !s2 && hi.is_one()) { - m_01s->insert(x); + is_uninterp_const(x) && + bounds.has_lower(x, lo, s1) && !s1 && lo.is_unsigned() && + bounds.has_upper(x, hi, s2) && !s2 && hi.is_unsigned() && hi.get_unsigned() <= m_max_ub) { + expr_ref b = mk_bounded(axioms, to_app(x), lo.get_unsigned(), hi.get_unsigned()); + rep.insert(x, b); + m_bounds.insert(x, bound(lo.get_unsigned(), hi.get_unsigned(), b)); TRACE("pb", tout << "add bound " << mk_pp(x, m) << "\n";); } } - expr_mark subfmls; for (unsigned i = 0; i < g->size(); i++) { - expr_ref new_curr(m); + expr_ref new_curr(m), tmp(m); proof_ref new_pr(m); - m_rw(g->form(i), new_curr, new_pr); + rep(g->form(i), tmp); + if (tmp == g->form(i)) continue; + m_rw(tmp, new_curr, new_pr); if (m.proofs_enabled() && !new_pr) { new_pr = m.mk_rewrite(g->form(i), new_curr); new_pr = m.mk_modus_ponens(g->pr(i), new_pr); } g->update(i, new_curr, new_pr, g->dep(i)); - mark_rec(subfmls, new_curr); } - for (expr* v : *m_01s) { - if (subfmls.is_marked(v)) { - g->assert_expr(a.mk_le(v, a.mk_numeral(rational(1), true))); - g->assert_expr(a.mk_le(a.mk_numeral(rational(0), true), v)); - } + for (expr* a : axioms) { + g->assert_expr(a); } + if (m_mc) g->add(m_mc.get()); g->inc_depth(); result.push_back(g.get()); TRACE("pb", g->display(tout);); SASSERT(g->is_well_sorted()); - - // TBD: convert models for 0-1 variables. - // TBD: support proof conversion (or not..) + m_bounds.reset(); } - void mark_rec(expr_mark& mark, expr* e) { - ptr_vector todo; - todo.push_back(e); - while (!todo.empty()) { - e = todo.back(); - todo.pop_back(); - if (!mark.is_marked(e)) { - mark.mark(e); - if (is_app(e)) { - for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { - todo.push_back(to_app(e)->get_arg(i)); - } - } - else if (is_quantifier(e)) { - todo.push_back(to_quantifier(e)->get_expr()); - } - } - } - } - - - bool is_01var(expr* x) const { - return m_01s->contains(x); - } - - expr_ref mk_01(expr* x) { - expr* r = m.mk_eq(x, a.mk_numeral(rational(1), m.get_sort(x))); - return expr_ref(r, m); - } - - expr* mk_le(unsigned sz, rational const* weights, expr* const* args, rational const& w) { if (sz == 0) { return w.is_neg()?m.mk_false():m.mk_true(); @@ -324,9 +327,6 @@ public: ok &= get_sum(u, mul, conds, args, coeffs, coeff); conds.pop_back(); } - else if (is_01var(x)) { - insert_arg(mul, conds, mk_01(x), args, coeffs, coeff); - } else if (is_numeral(x, r)) { insert_arg(mul*r, conds, m.mk_true(), args, coeffs, coeff); } @@ -391,9 +391,8 @@ public: } virtual void cleanup() { - expr_set* d = alloc(expr_set); + bounds_map* d = alloc(bounds_map); ptr_vector* todo = alloc(ptr_vector); - std::swap(m_01s, d); std::swap(m_todo, todo); dealloc(d); dealloc(todo); From badb32f9aeda4f95e512e2bdfee27c87d037a122 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2018 16:33:14 -0800 Subject: [PATCH 0517/1283] neatify rewriting Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 12 ++++++++++++ src/ast/rewriter/pb_rewriter.cpp | 13 ++++++++++--- src/tactic/arith/lia2card_tactic.cpp | 4 ++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 298733a94..d36c4ba89 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -129,9 +129,15 @@ app * pb_util::mk_le(unsigned num_args, rational const * coeffs, expr * const * normalize(num_args, coeffs, k); m_params.reset(); m_params.push_back(parameter(floor(m_k))); + bool all_ones = true; for (unsigned i = 0; i < num_args; ++i) { + all_ones &= m_coeffs[i].is_one(); m_params.push_back(parameter(m_coeffs[i])); } + if (all_ones && k.is_unsigned()) { + m_params[0] = parameter(floor(m_k).get_unsigned()); + return m.mk_app(m_fid, OP_AT_MOST_K, 1, m_params.c_ptr(), num_args, args, m.mk_bool_sort()); + } return m.mk_app(m_fid, OP_PB_LE, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort()); } @@ -139,9 +145,15 @@ app * pb_util::mk_ge(unsigned num_args, rational const * coeffs, expr * const * normalize(num_args, coeffs, k); m_params.reset(); m_params.push_back(parameter(ceil(m_k))); + bool all_ones = true; for (unsigned i = 0; i < num_args; ++i) { + all_ones &= m_coeffs[i].is_one(); m_params.push_back(parameter(m_coeffs[i])); } + if (all_ones && k.is_unsigned()) { + m_params[0] = parameter(ceil(m_k).get_unsigned()); + return m.mk_app(m_fid, OP_AT_LEAST_K, 1, m_params.c_ptr(), num_args, args, m.mk_bool_sort()); + } return m.mk_app(m_fid, OP_PB_GE, m_params.size(), m_params.c_ptr(), num_args, args, m.mk_bool_sort()); } diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 33527ea2c..004f0d592 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -115,14 +115,15 @@ expr_ref pb_rewriter::translate_pb2lia(obj_map& vars, expr* fml) { else { tmp = a.mk_add(es.size(), es.c_ptr()); } + rational k = util.get_k(fml); if (util.is_le(fml)) { - result = a.mk_le(tmp, a.mk_numeral(util.get_k(fml), false)); + result = a.mk_le(tmp, a.mk_numeral(k, false)); } else if (util.is_ge(fml)) { - result = a.mk_ge(tmp, a.mk_numeral(util.get_k(fml), false)); + result = a.mk_ge(tmp, a.mk_numeral(k, false)); } else { - result = m().mk_eq(tmp, a.mk_numeral(util.get_k(fml), false)); + result = m().mk_eq(tmp, a.mk_numeral(k, false)); } } else { @@ -265,6 +266,12 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons if (sz == 0) { result = k.is_zero()?m.mk_true():m.mk_false(); } + else if (k.is_zero()) { + result = mk_not(m, mk_or(m, sz, m_args.c_ptr())); + } + else if (k.is_one() && all_unit && m_args.size() == 1) { + result = m_args.back(); + } else { result = m_util.mk_eq(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k); } diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 09facedbe..dd9c5ff6b 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -158,7 +158,7 @@ public: m_rw(*this), m_pb(m), m_todo(alloc(ptr_vector)), - m_compile_equality(false) { + m_compile_equality(true) { m_max_ub = 100; } @@ -168,7 +168,7 @@ public: void updt_params(params_ref const & p) { m_params = p; - m_compile_equality = p.get_bool("compile_equality", false); + m_compile_equality = p.get_bool("compile_equality", true); } expr_ref mk_bounded(expr_ref_vector& axioms, app* x, unsigned lo, unsigned hi) { From 354c16454a6704f2176573eed418c87a28b4d355 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2018 22:19:25 -0800 Subject: [PATCH 0518/1283] fix bug in translation of pbeq into sat Signed-off-by: Nikolaj Bjorner --- src/ast/pb_decl_plugin.cpp | 3 +++ src/ast/rewriter/pb2bv_rewriter.cpp | 5 ----- src/ast/rewriter/pb_rewriter.cpp | 2 +- src/cmd_context/basic_cmds.cpp | 2 ++ src/sat/tactic/goal2sat.cpp | 5 ++++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index d36c4ba89..b189eabf7 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -162,6 +162,9 @@ app * pb_util::mk_eq(unsigned num_args, rational const * coeffs, expr * const * if (!m_k.is_int()) { return m.mk_false(); } + if (num_args == 0) { + return m_k.is_zero() ? m.mk_true() : m.mk_false(); + } m_params.reset(); m_params.push_back(parameter(m_k)); for (unsigned i = 0; i < num_args; ++i) { diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index d4aa5ad3e..3b657f1a3 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -94,12 +94,7 @@ struct pb2bv_rewriter::imp { for (unsigned i = 0; i < m_args.size(); ++i) { cas.push_back(std::make_pair(m_coeffs[i], expr_ref(m_args[i].get(), m))); } - //for (ca const& ca : cas) std::cout << ca.first << " "; - //std::cout << "\n"; std::sort(cas.begin(), cas.end(), compare_coeffs()); - //std::cout << "post-sort\n"; - //for (ca const& ca : cas) std::cout << ca.first << " "; - //std::cout << "\n"; m_coeffs.reset(); m_args.reset(); for (ca const& ca : cas) { diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 004f0d592..8bf7f2078 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -329,7 +329,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons tout << tmp << "\n"; tout << result << "\n"; ); - + TRACE("pb_validate", validate_rewrite(f, num_args, args, result);); diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 88c5cb257..d5e295b37 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -110,6 +110,8 @@ public: virtual void set_next_arg(cmd_context & ctx, unsigned index) { m_index = index; } virtual void execute(cmd_context & ctx) { model_ref m; + if (ctx.ignore_check()) + return; if (!ctx.is_model_available(m) || ctx.get_check_sat_result() == 0) throw cmd_exception("model is not available"); if (m_index > 0 && ctx.get_opt()) { diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index a7b2eb582..b84a64651 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -571,6 +571,8 @@ struct goal2sat::imp { l.neg(); } m_ext->add_at_least(v2, lits, lits.size() - k.get_unsigned()); + + if (root) { m_result_stack.reset(); } @@ -582,7 +584,8 @@ struct goal2sat::imp { mk_clause(~l, l2); mk_clause(~l1, ~l2, l); m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); - m_result_stack.push_back(l); + m_result_stack.push_back(sign ? ~l : l); + } } From 20fe08d80cdfcfa3c47c584a3f1c7269b30b7068 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2018 09:51:45 -0800 Subject: [PATCH 0519/1283] fix more bugs with compilation of pb equalities Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 17 +++++++++-------- src/tactic/arith/lia2card_tactic.cpp | 17 +---------------- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 653e578a3..ac332d362 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1571,7 +1571,7 @@ namespace sat { m_constraints.push_back(c); } literal lit = c->lit(); - if (c->learned() && !s().at_base_lvl()) { + if (c->learned() && m_solver && !s().at_base_lvl()) { SASSERT(lit == null_literal); // gets initialized after backjump. m_constraint_to_reinit.push_back(c); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index b84a64651..5bba70659 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -495,8 +495,8 @@ struct goal2sat::imp { SASSERT(k.is_unsigned()); svector wlits; convert_pb_args(t, wlits); - sat::bool_var v1 = root ? sat::null_bool_var : m_solver.mk_var(true); - sat::bool_var v2 = root ? sat::null_bool_var : m_solver.mk_var(true); + sat::bool_var v1 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true); + sat::bool_var v2 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true); m_ext->add_pb_ge(v1, wlits, k.get_unsigned()); k.neg(); for (wliteral& wl : wlits) { @@ -505,7 +505,7 @@ struct goal2sat::imp { } check_unsigned(k); m_ext->add_pb_ge(v2, wlits, k.get_unsigned()); - if (root) { + if (root && !sign) { m_result_stack.reset(); } else { @@ -516,7 +516,8 @@ struct goal2sat::imp { mk_clause(~l, l2); mk_clause(~l1, ~l2, l); m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); - m_result_stack.push_back(l); + m_result_stack.push_back(sign ? ~l : l); + if (root) mk_clause(~l); } } @@ -564,8 +565,8 @@ struct goal2sat::imp { SASSERT(k.is_unsigned()); sat::literal_vector lits; convert_pb_args(t->get_num_args(), lits); - sat::bool_var v1 = root ? sat::null_bool_var : m_solver.mk_var(true); - sat::bool_var v2 = root ? sat::null_bool_var : m_solver.mk_var(true); + sat::bool_var v1 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true); + sat::bool_var v2 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true); m_ext->add_at_least(v1, lits, k.get_unsigned()); for (sat::literal& l : lits) { l.neg(); @@ -573,7 +574,7 @@ struct goal2sat::imp { m_ext->add_at_least(v2, lits, lits.size() - k.get_unsigned()); - if (root) { + if (root && !sign) { m_result_stack.reset(); } else { @@ -585,7 +586,7 @@ struct goal2sat::imp { mk_clause(~l1, ~l2, l); m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); m_result_stack.push_back(sign ? ~l : l); - + if (root) mk_clause(~l); } } diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index dd9c5ff6b..18acde8a8 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -103,21 +103,6 @@ class lia2card_tactic : public tactic { } TRACE("pbsum", tout << expr_ref(m.mk_app(f, sz, es), m) << " ==>\n" << result << "\n";); -#if 0 - expr_ref vc(m); - vc = m.mk_not(m.mk_eq(m.mk_app(f, sz, es), result)); - ast_pp_util pp(m); - pp.collect(vc); - std::cout - << "(push)\n" - << "(echo \"" << result << "\")\n" - ; - pp.display_decls(std::cout); - std::cout - << "(assert " << vc << ")\n" - << "(check-sat)\n" - << "(pop)\n"; -#endif return BR_DONE; } @@ -237,7 +222,7 @@ public: result.push_back(g.get()); TRACE("pb", g->display(tout);); SASSERT(g->is_well_sorted()); - m_bounds.reset(); + m_bounds.reset(); } expr* mk_le(unsigned sz, rational const* weights, expr* const* args, rational const& w) { From 20d6543538e993a596b77175a22476e7372d77e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2018 12:56:21 -0800 Subject: [PATCH 0520/1283] set uninitialized fields. Maybe related to #1468 Signed-off-by: Nikolaj Bjorner --- src/interp/iz3interp.cpp | 4 ++++ src/interp/iz3translate.cpp | 33 +++++++++++++++++---------------- src/interp/iz3translate.h | 3 ++- src/sat/sat_clause.cpp | 2 ++ src/sat/sat_solver.cpp | 5 +---- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp index c1c4588cc..6f918bccb 100755 --- a/src/interp/iz3interp.cpp +++ b/src/interp/iz3interp.cpp @@ -255,9 +255,11 @@ public: throw interpolation_failure(msg); } catch (const iz3translation::unsupported &) { + TRACE("iz3", tout << "unsupported\n";); throw interpolation_error(); } catch (const iz3proof::proof_error &) { + TRACE("iz3", tout << "proof error\n";); throw interpolation_error(); } profiling::timer_stop("Proof translation"); @@ -304,9 +306,11 @@ public: throw interpolation_failure(msg); } catch (const iz3translation::unsupported &) { + TRACE("iz3", tout << "unsupported\n";); throw interpolation_error(); } catch (const iz3proof::proof_error &) { + TRACE("iz3", tout << "proof error\n";); throw interpolation_error(); } profiling::timer_stop("Proof translation"); diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index ce2249a88..b108ba047 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -983,6 +983,7 @@ public: ast get_bounded_variable(const ast &ineq, bool &lb){ ast nineq = normalize_inequality(ineq); ast lhs = arg(nineq,0); + lhs.raw(); switch(op(lhs)){ case Uninterpreted: lb = false; @@ -993,10 +994,10 @@ public: else if(arg(lhs,0) == make_int(rational(-1))) lb = true; else - throw unsupported(); + throw unsupported(lhs); return arg(lhs,1); default: - throw unsupported(); + throw unsupported(lhs); } } @@ -1101,10 +1102,10 @@ public: rational xcoeff = get_first_coefficient(arg(x,0),xvar); rational ycoeff = get_first_coefficient(arg(y,0),yvar); if(xcoeff == rational(0) || ycoeff == rational(0) || xvar != yvar) - throw unsupported(); // can be caused by non-linear arithmetic + throw unsupported(x); // can be caused by non-linear arithmetic rational ratio = xcoeff/ycoeff; if(denominator(ratio) != rational(1)) - throw unsupported(); // can this ever happen? + throw unsupported(y); // can this ever happen? return make_int(ratio); // better be integer! } @@ -1113,7 +1114,7 @@ public: get_assign_bounds_coeffs(proof,farkas_coeffs); int nargs = num_args(con); if(nargs != (int)(farkas_coeffs.size())) - throw unsupported(); // should never happen + throw unsupported(proof); // should never happen #if 0 if(farkas_coeffs[0] != make_int(rational(1))) farkas_coeffs[0] = make_int(rational(1)); @@ -1237,7 +1238,7 @@ public: if(pr(rew) == PR_REWRITE){ return clause; // just hope the rewrite does nothing! } - throw unsupported(); + throw unsupported(rew); } @@ -1311,7 +1312,7 @@ public: ast commute_equality_iff(const ast &con){ if(op(con) != Iff || op(arg(con,0)) != Equal) - throw unsupported(); + throw unsupported(con); return make(Iff,commute_equality(arg(con,0)),commute_equality(arg(con,1))); } @@ -1337,7 +1338,7 @@ public: prs.push_back(con); return clone(proof,prs); default: - throw unsupported(); + throw unsupported(proof); } } @@ -1837,7 +1838,7 @@ public: for(unsigned i = 0; i < nprems; i++) if(sym(args[i]) == commute && !(dk == PR_TRANSITIVITY || dk == PR_MODUS_PONENS || dk == PR_SYMMETRY || (dk == PR_MONOTONICITY && op(arg(con,0)) == Not))) - throw unsupported(); + throw unsupported(proof); switch(dk){ case PR_TRANSITIVITY: { @@ -1908,7 +1909,7 @@ public: int nargs = num_args(con); if(farkas_coeffs.size() != (unsigned)nargs){ pfgoto(proof); - throw unsupported(); + throw unsupported(proof); } for(int i = 0; i < nargs; i++){ ast lit = mk_not(arg(con,i)); @@ -1946,7 +1947,7 @@ public: get_broken_gcd_test_coeffs(proof,farkas_coeffs); if(farkas_coeffs.size() != nprems){ pfgoto(proof); - throw unsupported(); + throw unsupported(proof); } std::vector my_prems; my_prems.resize(2); std::vector my_prem_cons; my_prem_cons.resize(2); @@ -1969,7 +1970,7 @@ public: if(args.size() > 0) res = GomoryCutRule2Farkas(proof, conc(proof), args); else - throw unsupported(); + throw unsupported(proof); break; } case EqPropagateKind: { @@ -1988,7 +1989,7 @@ public: break; } default: - throw unsupported(); + throw unsupported(proof); } break; case ArrayTheory: {// nothing fancy for this @@ -2000,7 +2001,7 @@ public: break; } default: - throw unsupported(); + throw unsupported(proof); } break; } @@ -2024,7 +2025,7 @@ public: if(is_local(con)) res = args[0]; else - throw unsupported(); + throw unsupported(con); break; } case PR_COMMUTATIVITY: { @@ -2048,7 +2049,7 @@ public: IF_VERBOSE(0, verbose_stream() << "Unsupported proof rule: " << expr_ref((expr*)proof.raw(), *proof.mgr()) << "\n";); // pfgoto(proof); // SASSERT(0 && "translate_main: unsupported proof rule"); - throw unsupported(); + throw unsupported(proof); } } diff --git a/src/interp/iz3translate.h b/src/interp/iz3translate.h index 8ecafbd3a..d80c3b3fe 100755 --- a/src/interp/iz3translate.h +++ b/src/interp/iz3translate.h @@ -36,7 +36,8 @@ class iz3translation : public iz3base { /** This is thrown when the proof cannot be translated. */ struct unsupported: public iz3_exception { - unsupported(): iz3_exception("unsupported") { } + raw_ast* m_ast; + unsupported(ast const& a): iz3_exception("unsupported"), m_ast(a.raw()) { } }; static iz3translation *create(iz3mgr &mgr, diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index c5829ae4e..76a1ee8c3 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -33,6 +33,8 @@ namespace sat { m_frozen(false), m_reinit_stack(false), m_inact_rounds(0) { + m_psm = 0; + m_glue = 0; memcpy(m_lits, lits, sizeof(literal) * sz); mark_strengthened(); SASSERT(check_approx()); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 03c17aaf0..91bff7406 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2460,10 +2460,7 @@ namespace sat { // try to use cached implication if available literal_vector * implied_lits = m_probing.cached_implied_lits(~l); if (implied_lits) { - literal_vector::iterator it = implied_lits->begin(); - literal_vector::iterator end = implied_lits->end(); - for (; it != end; ++it) { - literal l2 = *it; + for (literal l2 : *implied_lits) { // Here, we must check l0 != ~l2. // l \/ l2 is an implied binary clause. // However, it may have been deduced using a lemma that has been deleted. From bf04c38a639556ef17ef7afc5eea1cd769626b51 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2018 13:06:14 -0800 Subject: [PATCH 0521/1283] add logging for #1470 Signed-off-by: Nikolaj Bjorner --- src/interp/iz3translate.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index b108ba047..4831e7eaf 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -49,6 +49,9 @@ using namespace stl_ext; prover is used. */ + +#define throw_unsupported(_e_) { TRACE("iz3", tout << expr_ref((expr*)_e_.raw(), *_e_.mgr()) << "\n";); throw unsupported(_e_); } + class iz3translation_full : public iz3translation { public: @@ -994,10 +997,10 @@ public: else if(arg(lhs,0) == make_int(rational(-1))) lb = true; else - throw unsupported(lhs); + throw_unsupported(lhs); return arg(lhs,1); default: - throw unsupported(lhs); + throw_unsupported(lhs); } } @@ -1102,10 +1105,10 @@ public: rational xcoeff = get_first_coefficient(arg(x,0),xvar); rational ycoeff = get_first_coefficient(arg(y,0),yvar); if(xcoeff == rational(0) || ycoeff == rational(0) || xvar != yvar) - throw unsupported(x); // can be caused by non-linear arithmetic + throw_unsupported(x); // can be caused by non-linear arithmetic rational ratio = xcoeff/ycoeff; if(denominator(ratio) != rational(1)) - throw unsupported(y); // can this ever happen? + throw_unsupported(y); // can this ever happen? return make_int(ratio); // better be integer! } @@ -1114,7 +1117,7 @@ public: get_assign_bounds_coeffs(proof,farkas_coeffs); int nargs = num_args(con); if(nargs != (int)(farkas_coeffs.size())) - throw unsupported(proof); // should never happen + throw_unsupported(proof); // should never happen #if 0 if(farkas_coeffs[0] != make_int(rational(1))) farkas_coeffs[0] = make_int(rational(1)); @@ -1238,7 +1241,7 @@ public: if(pr(rew) == PR_REWRITE){ return clause; // just hope the rewrite does nothing! } - throw unsupported(rew); + throw_unsupported(rew); } @@ -1312,7 +1315,7 @@ public: ast commute_equality_iff(const ast &con){ if(op(con) != Iff || op(arg(con,0)) != Equal) - throw unsupported(con); + throw_unsupported(con); return make(Iff,commute_equality(arg(con,0)),commute_equality(arg(con,1))); } @@ -1338,7 +1341,7 @@ public: prs.push_back(con); return clone(proof,prs); default: - throw unsupported(proof); + throw_unsupported(proof); } } @@ -1838,7 +1841,7 @@ public: for(unsigned i = 0; i < nprems; i++) if(sym(args[i]) == commute && !(dk == PR_TRANSITIVITY || dk == PR_MODUS_PONENS || dk == PR_SYMMETRY || (dk == PR_MONOTONICITY && op(arg(con,0)) == Not))) - throw unsupported(proof); + throw_unsupported(proof); switch(dk){ case PR_TRANSITIVITY: { @@ -1909,7 +1912,7 @@ public: int nargs = num_args(con); if(farkas_coeffs.size() != (unsigned)nargs){ pfgoto(proof); - throw unsupported(proof); + throw_unsupported(proof); } for(int i = 0; i < nargs; i++){ ast lit = mk_not(arg(con,i)); @@ -1947,7 +1950,7 @@ public: get_broken_gcd_test_coeffs(proof,farkas_coeffs); if(farkas_coeffs.size() != nprems){ pfgoto(proof); - throw unsupported(proof); + throw_unsupported(proof); } std::vector my_prems; my_prems.resize(2); std::vector my_prem_cons; my_prem_cons.resize(2); @@ -1970,7 +1973,7 @@ public: if(args.size() > 0) res = GomoryCutRule2Farkas(proof, conc(proof), args); else - throw unsupported(proof); + throw_unsupported(proof); break; } case EqPropagateKind: { @@ -1989,7 +1992,7 @@ public: break; } default: - throw unsupported(proof); + throw_unsupported(proof); } break; case ArrayTheory: {// nothing fancy for this @@ -2001,7 +2004,7 @@ public: break; } default: - throw unsupported(proof); + throw_unsupported(proof); } break; } @@ -2025,7 +2028,7 @@ public: if(is_local(con)) res = args[0]; else - throw unsupported(con); + throw_unsupported(con); break; } case PR_COMMUTATIVITY: { @@ -2049,7 +2052,7 @@ public: IF_VERBOSE(0, verbose_stream() << "Unsupported proof rule: " << expr_ref((expr*)proof.raw(), *proof.mgr()) << "\n";); // pfgoto(proof); // SASSERT(0 && "translate_main: unsupported proof rule"); - throw unsupported(proof); + throw_unsupported(proof); } } From 885dfad237e897920618641fafe1f1dd31c4a4f9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2018 20:54:21 -0800 Subject: [PATCH 0522/1283] fix #1458 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 91bff7406..4cb7339d1 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2715,6 +2715,7 @@ namespace sat { void solver::user_pop(unsigned num_scopes) { pop_to_base_level(); + TRACE("sat", display(tout);); while (num_scopes > 0) { literal lit = m_user_scope_literals.back(); m_user_scope_literals.pop_back(); @@ -2734,8 +2735,10 @@ namespace sat { break; } } - gc_var(lit.var()); + gc_var(lit.var()); } + m_qhead = 0; + propagate(false); } void solver::pop_to_base_level() { From a5caa506067a949afc445c5bf467fe8403538ec9 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 5 Feb 2018 09:42:56 -0800 Subject: [PATCH 0523/1283] adding template definitions Signed-off-by: Lev Nachmanson --- src/util/lp/lp_solver_instances.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/lp/lp_solver_instances.cpp b/src/util/lp/lp_solver_instances.cpp index 599a0a8bc..4de1f74c8 100644 --- a/src/util/lp/lp_solver_instances.cpp +++ b/src/util/lp/lp_solver_instances.cpp @@ -54,3 +54,5 @@ template void lp::lp_solver::scale(); template void lp::lp_solver::set_scaled_cost(unsigned int); template lp::lp_solver::~lp_solver(); template double lp::lp_solver::get_column_value_by_name(std::string) const; +template std::string lp::lp_solver::get_column_name(unsigned int) const; +template std::string lp::lp_solver::get_column_name(unsigned int) const; From 3e810d6c547e404cbc96aea0972485434d0baecd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Feb 2018 16:46:49 -0800 Subject: [PATCH 0524/1283] remove static from format (not thread safe), remove std::move #1466 Signed-off-by: Nikolaj Bjorner --- src/ast/format.cpp | 4 ++-- src/ast/proofs/proof_utils.h | 2 +- src/muz/rel/dl_instruction.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ast/format.cpp b/src/ast/format.cpp index 835892121..6c2a02989 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -151,7 +151,7 @@ namespace format_ns { } format * mk_int(ast_manager & m, int i) { - static char buffer[128]; + char buffer[128]; #ifdef _WINDOWS sprintf_s(buffer, ARRAYSIZE(buffer), "%d", i); #else @@ -161,7 +161,7 @@ namespace format_ns { } format * mk_unsigned(ast_manager & m, unsigned u) { - static char buffer[128]; + char buffer[128]; #ifdef _WINDOWS sprintf_s(buffer, ARRAYSIZE(buffer), "%u", u); #else diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h index 473df31e6..455f39c4f 100644 --- a/src/ast/proofs/proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -88,7 +88,7 @@ class elim_aux_assertions { app_ref m_aux; public: - elim_aux_assertions(app_ref aux) : m_aux(std::move(aux)) {} + elim_aux_assertions(app_ref const& aux) : m_aux(aux) {} void mk_or_core(expr_ref_vector &args, expr_ref &res) { diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 0a33e99f1..26139fb7c 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -190,8 +190,8 @@ namespace datalog { func_decl_ref m_pred; reg_idx m_reg; public: - instr_io(bool store, func_decl_ref pred, reg_idx reg) - : m_store(store), m_pred(std::move(pred)), m_reg(reg) {} + instr_io(bool store, func_decl_ref const& pred, reg_idx reg) + : m_store(store), m_pred(pred), m_reg(reg) {} virtual bool perform(execution_context & ctx) { log_verbose(ctx); if (m_store) { From a1d4e485a4435a0e5de38ba17337fa7fd77953ae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Feb 2018 18:33:31 -0800 Subject: [PATCH 0525/1283] fix #1469 Signed-off-by: Nikolaj Bjorner --- src/qe/qe.cpp | 71 +++++++++++++++++++------------------- src/qe/qe.h | 2 +- src/qe/qe_arith_plugin.cpp | 43 +++++++++++++++-------- src/qe/qe_sat_tactic.cpp | 2 +- 4 files changed, 65 insertions(+), 53 deletions(-) diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 061f403e3..0a3f880b7 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -130,8 +130,7 @@ namespace qe { visited.mark(e, true); } } - for (unsigned i = 0; i < conjs.size(); ++i) { - expr* e = conjs[i].get(); + for (expr* e : conjs) { bool cv = contains_var.is_marked(e); bool cu = contains_uf.is_marked(e); if (cv && cu) { @@ -989,11 +988,11 @@ namespace qe { todo.pop_back(); if (st->m_children.empty() && st->fml() && st->m_vars.empty() && !st->has_var()) { + TRACE("qe", st->display(tout << "appending leaf\n");); result.push_back(st->fml()); } - for (unsigned i = 0; i < st->m_children.size(); ++i) { - todo.push_back(st->m_children[i]); - } + for (auto * ch : st->m_children) + todo.push_back(ch); } } @@ -1020,9 +1019,7 @@ namespace qe { void reset() { TRACE("qe",tout << "resetting\n";); - for (unsigned i = 0; i < m_children.size(); ++i) { - dealloc(m_children[i]); - } + for (auto* ch : m_children) dealloc(ch); m_pos.reset(); m_neg.reset(); m_children.reset(); @@ -1046,9 +1043,10 @@ namespace qe { } unsigned num_free_vars() const { return m_vars.size(); } - app* const* free_vars() const { return m_vars.c_ptr(); } + // app* const* free_vars() const { return m_vars.c_ptr(); } + app_ref_vector const& free_vars() const { return m_vars; } app* free_var(unsigned i) const { return m_vars[i]; } - void reset_free_vars() { m_vars.reset(); } + void reset_free_vars() { TRACE("qe", tout << m_vars << "\n";); m_vars.reset(); } atom_set const& pos_atoms() const { return m_pos; } atom_set const& neg_atoms() const { return m_neg; } @@ -1119,7 +1117,7 @@ namespace qe { st->init(fml); st->m_vars.append(m_vars.size(), m_vars.c_ptr()); SASSERT(invariant()); - TRACE("qe", tout << mk_pp(m_fml, m) << " child: " << mk_pp(fml, m) << "\n";); + TRACE("qe", display_node(tout); st->display_node(tout);); return st; } @@ -1133,7 +1131,7 @@ namespace qe { m_branch_index.insert(branch_id, index); st->m_vars.append(m_vars.size(), m_vars.c_ptr()); SASSERT(invariant()); - //TRACE("qe", tout << mk_pp(m_fml, m) << " child: " << mk_pp(st->fml(), m) << "\n";); + TRACE("qe", display_node(tout); st->display_node(tout);); return st; } @@ -1141,27 +1139,29 @@ namespace qe { display(out, ""); } - void display(std::ostream& out, char const* indent) const { - - out << indent << "node\n"; + void display_node(std::ostream& out, char const* indent = "") const { + out << indent << "node " << std::hex << this << std::dec << "\n"; if (m_var) { - out << indent << " var: " << mk_ismt2_pp(m_var.get(), m) << "\n"; + out << indent << " var: " << m_var << "\n"; } - for (unsigned i = 0; i < m_vars.size(); ++i) { - out << indent << " free: " << mk_ismt2_pp(m_vars[i], m) << "\n"; + for (app* v : m_vars) { + out << indent << " free: " << mk_pp(v, m) << "\n"; } if (m_fml) { - out << indent << " fml: " << mk_ismt2_pp(m_fml.get(), m) << "\n"; + out << indent << " fml: " << m_fml << "\n"; } for (unsigned i = 0; i < m_def.size(); ++i) { out << indent << " def: " << m_def.var(i)->get_name() << " = " << mk_ismt2_pp(m_def.def(i), m) << "\n"; } out << indent << " branches: " << m_num_branches << "\n"; + } + void display(std::ostream& out, char const* indent) const { + display_node(out, indent); std::string new_indent(indent); new_indent += " "; - for (unsigned i = 0; i < m_children.size(); ++i) { - m_children[i]->display(out, new_indent.c_str()); + for (auto * ch : m_children) { + ch->display(out, new_indent.c_str()); } } @@ -1214,6 +1214,7 @@ namespace qe { out << "(push)\n"; pp.display_smt2(out, fml); out << "(pop)\n\n"; +#if 0 DEBUG_CODE( smt_params params; params.m_simplify_bit2int = true; @@ -1227,7 +1228,8 @@ namespace qe { std::cout << "; Validation failed:\n"; std::cout << mk_pp(fml, m) << "\n"; } -); + ); +#endif } for (unsigned i = 0; i < m_children.size(); ++i) { @@ -1486,9 +1488,7 @@ namespace qe { tout << "subformula: " << mk_ismt2_pp(m_subfml, m) << "\n"; m_root.display(tout); m_root.display_validate(tout); - for (unsigned i = 0; i < m_free_vars.size(); ++i) tout << mk_ismt2_pp(m_free_vars[i].get(), m) << " "; - tout << "\n"; - ); + tout << "free: " << m_free_vars << "\n";); free_vars.append(m_free_vars); if (!m_free_vars.empty() || m_solver.inconsistent()) { @@ -1546,14 +1546,14 @@ namespace qe { app* get_var(unsigned idx) const { return m_current->free_var(idx); } - app* const* get_vars() const { return m_current->free_vars(); } + app_ref_vector const& get_vars() const { return m_current->free_vars(); } contains_app& contains(unsigned idx) { return contains(get_var(idx)); } // // The variable at idx is eliminated (without branching). // - void elim_var(unsigned idx, expr* _fml, expr* def) { + void elim_var(unsigned idx, expr* _fml, expr* def) override { app* x = get_var(idx); expr_ref fml(_fml, m); TRACE("qe", tout << mk_pp(x,m) << " " << mk_pp(def, m) << "\n";); @@ -1598,7 +1598,7 @@ namespace qe { add_literal(l3); expr_ref fml(m); fml = m.mk_or(m_literals.size(), m_literals.c_ptr()); - TRACE("qe", tout << mk_ismt2_pp(fml, m) << "\n";); + TRACE("qe", tout << fml << "\n";); m_solver.assert_expr(fml); } @@ -1654,9 +1654,7 @@ namespace qe { } app* get_branch_id(app* x) { - app* result = 0; - VERIFY (m_var2branch.find(x, result)); - return result; + return m_var2branch[x]; } bool extract_partition(ptr_vector& vars) { @@ -1912,6 +1910,7 @@ namespace qe { } m_current->set_var(x, k); + TRACE("qe", tout << mk_pp(x, m) << " := " << k << "\n";); if (m_bv.is_bv(x)) { return; } @@ -1952,7 +1951,7 @@ namespace qe { vars.reset(); closed = closed && (r != l_undef); } - TRACE("qe", tout << mk_pp(fml, m) << "\n";); + TRACE("qe", tout << fml << " free: " << m_current->free_vars() << "\n";); m_current->add_child(fml)->reset_free_vars(); block_assignment(); } @@ -1961,9 +1960,7 @@ namespace qe { // variable queueing. contains_app& contains(app* x) { - contains_app* result = 0; - VERIFY(m_var2contains.find(x, result)); - return *result; + return *m_var2contains[x]; } bool find_min_weight(app*& x, rational& num_branches) { @@ -2003,6 +2000,7 @@ namespace qe { bool solved = true; while (solved) { expr_ref fml(m_current->fml(), m); + TRACE("qe", tout << fml << "\n";); conj_enum conjs(m, fml); solved = false; for (unsigned i = 0; !solved && i < m_plugins.size(); ++i) { @@ -2512,7 +2510,7 @@ namespace qe { // Access current set of variables to solve virtual unsigned get_num_vars() const { return m_vars->size(); } virtual app* get_var(unsigned idx) const { return (*m_vars)[idx].get(); } - virtual app*const* get_vars() const { return m_vars->c_ptr(); } + virtual app_ref_vector const& get_vars() const { return *m_vars; } virtual bool is_var(expr* e, unsigned& idx) const { for (unsigned i = 0; i < m_vars->size(); ++i) { if ((*m_vars)[i].get() == e) { @@ -2540,6 +2538,7 @@ namespace qe { // callback to add new variable to branch. virtual void add_var(app* x) { + TRACE("qe", tout << "add var: " << mk_pp(x, m) << "\n";); m_vars->push_back(x); } diff --git a/src/qe/qe.h b/src/qe/qe.h index b6754b384..6946f9566 100644 --- a/src/qe/qe.h +++ b/src/qe/qe.h @@ -86,7 +86,7 @@ namespace qe { // Access current set of variables to solve virtual unsigned get_num_vars() const = 0; virtual app* get_var(unsigned idx) const = 0; - virtual app*const* get_vars() const = 0; + virtual app_ref_vector const& get_vars() const = 0; virtual bool is_var(expr* e, unsigned& idx) const; virtual contains_app& contains(unsigned idx) = 0; diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 1085ec3c2..89dee9586 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -105,6 +105,7 @@ namespace qe { public: arith_util m_arith; // initialize before m_zero_i, etc. th_rewriter simplify; + app_ref_vector m_vars_added; private: arith_eq_solver m_arith_solver; bv_util m_bv; @@ -126,6 +127,7 @@ namespace qe { m_ctx(ctx), m_arith(m), simplify(m), + m_vars_added(m), m_arith_solver(m), m_bv(m), m_zero_i(m_arith.mk_numeral(numeral(0), true), m), @@ -783,6 +785,11 @@ namespace qe { } } + void add_var(app* v, bool track = true) { + m_ctx.add_var(v); + if (track) m_vars_added.push_back(v); + } + private: @@ -850,10 +857,11 @@ namespace qe { << mk_pp(result, m) << "\n";); } + void mk_big_or_symbolic(numeral up, app* x, expr* body, expr_ref& result) { app_ref z_bv(m); mk_big_or_symbolic(up, x, body, z_bv, result); - m_ctx.add_var(z_bv); + add_var(z_bv); } void mk_big_or_symbolic_blast(numeral up, app* x, expr* body, expr_ref& result) { @@ -999,9 +1007,9 @@ namespace qe { bool solve_linear(expr* p, expr* fml) { vector values; unsigned num_vars = m_ctx.get_num_vars(); - app*const* vars_ptr = m_ctx.get_vars(); + app_ref_vector const& vars = m_ctx.get_vars(); - if (!is_linear(p, num_vars, vars_ptr, values)) { + if (!is_linear(p, num_vars, vars.c_ptr(), values)) { return false; } @@ -1025,7 +1033,7 @@ namespace qe { // it has coefficient 'm' = values[index]. SASSERT(values[index] >= rational(3)); z = m.mk_fresh_const("x", m_arith.mk_int()); - m_ctx.add_var(z); + add_var(z); p1 = m_arith.mk_mul(m_arith.mk_numeral(values[index], true), z); } else { @@ -1475,16 +1483,18 @@ public: expr* m_result; rational m_coeff; expr* m_term; + ptr_vector m_vars; branch_formula(): m_fml(0), m_var(0), m_branch(0), m_result(0), m_term(0) {} - branch_formula(expr* fml, app* var, unsigned b, expr* r, rational coeff, expr* term): + branch_formula(expr* fml, app* var, unsigned b, expr* r, rational coeff, expr* term, app_ref_vector const& vars): m_fml(fml), m_var(var), m_branch(b), m_result(r), m_coeff(coeff), - m_term(term) + m_term(term), + m_vars(vars.size(), vars.c_ptr()) {} unsigned mk_hash() const { @@ -1544,6 +1554,7 @@ public: if (get_cache(x, fml, v, result)) { return; } + m_util.m_vars_added.reset(); bounds_proc& bounds = get_bounds(x, fml); bool is_lower = get_bound_sizes(bounds, x, t_size, e_size); @@ -1601,8 +1612,7 @@ public: expr_ref t(bounds.exprs(is_strict, is_lower)[index], m); rational a = bounds.coeffs(is_strict, is_lower)[index]; - - + mk_bounds(bounds, x, true, is_eq, is_strict, is_lower, index, a, t, result); mk_bounds(bounds, x, false, is_eq, is_strict, is_lower, index, a, t, result); @@ -1617,7 +1627,7 @@ public: { tout << vl << " " << mk_pp(bounds.atoms(is_strict, is_lower)[index],m) << "\n"; tout << mk_pp(fml, m) << "\n"; - tout << mk_pp(result, m) << "\n"; + tout << result << "\n"; } ); } @@ -1637,7 +1647,7 @@ public: virtual void subst(contains_app& contains_x, rational const& vl, expr_ref& fml, expr_ref* def) { SASSERT(vl.is_unsigned()); - if (def) { + if (def) { get_def(contains_x, vl.get_unsigned(), fml, *def); } VERIFY(get_cache(contains_x.x(), fml, vl.get_unsigned(), fml)); @@ -1740,7 +1750,7 @@ public: x_subst x_t(m_util); bounds_proc& bounds = get_bounds(x, fml); branch_formula bf; - VERIFY (m_subst.find(branch_formula(fml, x, v, 0, rational::zero(), 0), bf)); + VERIFY (m_subst.find(branch_formula(fml, x, v, 0, rational::zero(), 0, m_util.m_vars_added), bf)); x_t.set_term(bf.m_term); x_t.set_coeff(bf.m_coeff); @@ -2022,16 +2032,19 @@ public: m_trail.push_back(fml); m_trail.push_back(result); if (term) m_trail.push_back(term); - m_subst.insert(branch_formula(fml, x, v, result, coeff, term)); + m_subst.insert(branch_formula(fml, x, v, result, coeff, term, m_util.m_vars_added)); } bool get_cache(app* x, expr* fml, unsigned v, expr_ref& result) { branch_formula bf; - if (!m_subst.find(branch_formula(fml, x, v, 0, rational::zero(), 0), bf)) { + if (!m_subst.find(branch_formula(fml, x, v, 0, rational::zero(), 0, m_util.m_vars_added), bf)) { return false; } SASSERT(bf.m_result); result = bf.m_result; + for (app* v : bf.m_vars) { + m_util.add_var(v, false); + } return true; } @@ -2043,7 +2056,7 @@ public: if (!bounds.div_z(d, z_bv, z)) { return; } - m_ctx.add_var(z_bv); + m_util.add_var(z_bv); // // assert @@ -2120,7 +2133,7 @@ public: app* z1_bv = bounds.nested_div_z_bv(i); app* z1 = bounds.nested_div_z(i); - m_ctx.add_var(z1_bv); + m_util.add_var(z1_bv); // // assert diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 69ebc1a42..250ffff4a 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -122,7 +122,7 @@ namespace qe { // Access current set of variables to solve virtual unsigned get_num_vars() const { return m_vars.size(); } virtual app* get_var(unsigned idx) const { return m_vars[idx]; } - virtual app*const* get_vars() const { return m_vars.c_ptr(); } + virtual app_ref_vector const& get_vars() const { return m_vars; } virtual bool is_var(expr* e, unsigned& idx) const { for (unsigned i = 0; i < m_vars.size(); ++i) { if (e == m_vars[i]) return (idx = i, true); From b2bd4dd3b4ce591aab630adb25ddf2df30e8fc5f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Feb 2018 18:54:14 -0800 Subject: [PATCH 0526/1283] fix #1471 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_integrity_checker.cpp | 30 ++++++++++++++---------------- src/sat/sat_solver.cpp | 26 ++++++++++++++++---------- src/sat/sat_solver.h | 2 +- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index 08a6072b6..027cd8a6f 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -153,7 +153,7 @@ namespace sat { } bool integrity_checker::check_watches() const { - DEBUG_CODE( + DEBUG_CODE( vector::const_iterator it = s.m_watches.begin(); vector::const_iterator end = s.m_watches.end(); for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { @@ -165,30 +165,28 @@ namespace sat { s.display_watches(tout); s.display(tout);); SASSERT(!s.was_eliminated(l.var()) || wlist.empty()); - watch_list::const_iterator it2 = wlist.begin(); - watch_list::const_iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - switch (it2->get_kind()) { + for (watched const& w : wlist) { + switch (w.get_kind()) { case watched::BINARY: - SASSERT(!s.was_eliminated(it2->get_literal().var())); - CTRACE("sat_watched_bug", !s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned())), - tout << "l: " << l << " l2: " << it2->get_literal() << "\n"; + SASSERT(!s.was_eliminated(w.get_literal().var())); + CTRACE("sat_watched_bug", !s.get_wlist(~(w.get_literal())).contains(watched(l, w.is_learned())), + tout << "l: " << l << " l2: " << w.get_literal() << "\n"; tout << "was_eliminated1: " << s.was_eliminated(l.var()); - tout << " was_eliminated2: " << s.was_eliminated(it2->get_literal().var()); - tout << " learned: " << it2->is_learned() << "\n"; + tout << " was_eliminated2: " << s.was_eliminated(w.get_literal().var()); + tout << " learned: " << w.is_learned() << "\n"; sat::display(tout, s.m_cls_allocator, wlist); tout << "\n"; - sat::display(tout, s.m_cls_allocator, s.get_wlist(~(it2->get_literal()))); + sat::display(tout, s.m_cls_allocator, s.get_wlist(~(w.get_literal()))); tout << "\n";); - SASSERT(s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned()))); + SASSERT(s.get_wlist(~(w.get_literal())).contains(watched(l, w.is_learned()))); break; case watched::TERNARY: - SASSERT(!s.was_eliminated(it2->get_literal1().var())); - SASSERT(!s.was_eliminated(it2->get_literal2().var())); - SASSERT(it2->get_literal1().index() < it2->get_literal2().index()); + SASSERT(!s.was_eliminated(w.get_literal1().var())); + SASSERT(!s.was_eliminated(w.get_literal2().var())); + SASSERT(w.get_literal1().index() < w.get_literal2().index()); break; case watched::CLAUSE: - SASSERT(!s.m_cls_allocator.get_clause(it2->get_clause_offset())->was_removed()); + SASSERT(!s.m_cls_allocator.get_clause(w.get_clause_offset())->was_removed()); break; default: break; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4cb7339d1..f0c23e087 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2641,15 +2641,22 @@ namespace sat { clauses.shrink(j); } - void solver::gc_bin(bool learned, literal nlit) { - m_user_bin_clauses.reset(); - collect_bin_clauses(m_user_bin_clauses, learned); - for (unsigned i = 0; i < m_user_bin_clauses.size(); ++i) { - literal l1 = m_user_bin_clauses[i].first; - literal l2 = m_user_bin_clauses[i].second; - if (nlit == l1 || nlit == l2) { - detach_bin_clause(l1, l2, learned); + void solver::gc_bin(literal lit) { + bool_var v = lit.var(); + for (watch_list& wlist : m_watches) { + watch_list::iterator it = wlist.begin(); + watch_list::iterator it2 = wlist.begin(); + watch_list::iterator end = wlist.end(); + for (; it != end; ++it) { + if (it->is_binary_clause() && it->get_literal().var() == v) { + // skip + } + else { + *it2 = *it; + ++it2; + } } + wlist.set_end(it2); } } @@ -2724,8 +2731,7 @@ namespace sat { gc_lit(m_learned, lit); gc_lit(m_clauses, lit); - gc_bin(true, lit); - gc_bin(false, lit); + gc_bin(lit); TRACE("sat", tout << "gc: " << lit << "\n"; display(tout);); --num_scopes; for (unsigned i = 0; i < m_trail.size(); ++i) { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c011eb46d..c275b8ee2 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -444,7 +444,7 @@ namespace sat { literal_vector m_aux_literals; svector m_user_bin_clauses; void gc_lit(clause_vector& clauses, literal lit); - void gc_bin(bool learned, literal nlit); + void gc_bin(literal lit); void gc_var(bool_var v); bool_var max_var(clause_vector& clauses, bool_var v); From 54b3cd00717914aad0d343d381621506ff3f40c4 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 6 Feb 2018 11:21:17 +0700 Subject: [PATCH 0527/1283] Reserve vector space when possible. This fixes all current instances of the `performance-inefficient-vector-operation` warning in clang-tidy. --- src/duality/duality.h | 1 + src/duality/duality_rpfp.cpp | 21 +++++++++++++++++++-- src/duality/duality_solver.cpp | 1 + src/interp/iz3interp.cpp | 1 + src/interp/iz3translate.cpp | 2 ++ src/muz/duality/duality_dl_interface.cpp | 1 + 6 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/duality/duality.h b/src/duality/duality.h index 28cf96df3..e8f36a0cd 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -507,6 +507,7 @@ namespace Duality { { std::vector _IndParams; int nargs = t.num_args(); + _IndParams.reserve(nargs); for(int i = 0; i < nargs; i++) _IndParams.push_back(t.arg(i)); Node *n = new Node(t.decl(), diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index 9dae5eba9..b6dd42f00 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -234,6 +234,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for (int i = 0; i < nargs; i++) args.push_back(LocalizeRec(e, memo, t.arg(i))); hash_map::iterator rit = e->relMap.find(f); @@ -352,6 +353,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for (int i = 0; i < nargs; i++) args.push_back(SubstRec(memo, t.arg(i))); res = f(args.size(), VEC2PTR(args)); @@ -379,6 +381,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for (int i = 0; i < nargs; i++) args.push_back(SubstRec(memo, map, t.arg(i))); hash_map::iterator it = map.find(f); @@ -409,6 +412,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for (int i = 0; i < nargs; i++) args.push_back(ExtractStores(memo, t.arg(i), cnstrs, renaming)); res = f(args.size(), VEC2PTR(args)); @@ -655,6 +659,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for (int i = 0; i < nargs; i++) args.push_back(RemoveRedundancyRec(memo, smemo, t.arg(i))); @@ -703,6 +708,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for (int i = 0; i < nargs; i++) args.push_back(IneqToEqRec(memo, t.arg(i))); @@ -749,6 +755,7 @@ namespace Duality { res = ctx.constant(name.c_str(), t.get_sort()); return res; } + args.reserve(nargs); for (int i = 0; i < nargs; i++) args.push_back(SubstRec(memo, t.arg(i))); res = f(args.size(), VEC2PTR(args)); @@ -3308,6 +3315,7 @@ namespace Duality { std::string name = t.decl().name().str() + "_" + string_of_int(n); std::vector sorts; int nargs = t.num_args(); + sorts.reserve(nargs); for(int i = 0; i < nargs; i++) sorts.push_back(t.arg(i).get_sort()); return ctx.function(name.c_str(), nargs, VEC2PTR(sorts), t.get_sort()); @@ -3319,8 +3327,9 @@ namespace Duality { name = name.substr(0,name.rfind('_')) + "_" + string_of_int(n); int arity = f.arity(); std::vector domain; + domain.reserve(arity); for(int i = 0; i < arity; i++) - domain.push_back(f.domain(i)); + domain.push_back(f.domain(i)); return ctx.function(name.c_str(), arity, VEC2PTR(domain), f.range()); } @@ -3330,8 +3339,9 @@ namespace Duality { name = name + "_" + string_of_int(n); int arity = f.arity(); std::vector domain; + domain.reserve(arity); for(int i = 0; i < arity; i++) - domain.push_back(f.domain(i)); + domain.push_back(f.domain(i)); return ctx.function(name.c_str(), arity, VEC2PTR(domain), f.range()); } @@ -3355,6 +3365,7 @@ namespace Duality { } int nargs = t.num_args(); std::vector args; + args.reserve(nargs); for(int i = 0; i < nargs; i++) args.push_back(ScanBody(memo,t.arg(i),pmap,parms,nodes)); res = f(nargs, VEC2PTR(args)); @@ -3403,6 +3414,7 @@ namespace Duality { else { int nargs = t.num_args(); std::vector args; + args.reserve(nargs); for(int i = 0; i < nargs; i++) args.push_back(RemoveLabelsRec(memo,t.arg(i),lbls)); res = f(nargs, VEC2PTR(args)); @@ -3432,6 +3444,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); if(nargs == 0 && f.get_decl_kind() == Uninterpreted) ls->declare_constant(f); // keep track of background constants for(int i = 0; i < nargs; i++) @@ -3474,6 +3487,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for(int i = 0; i < nargs; i++) args.push_back(DeleteBoundRec(memo, level, num, t.arg(i))); res = f(args.size(), VEC2PTR(args)); @@ -3870,6 +3884,7 @@ namespace Duality { void RPFP::AddParamsToNode(Node *node, const std::vector ¶ms){ int arity = node->Annotation.IndParams.size(); std::vector domain; + domain.reserve(arity + params.size()); for(int i = 0; i < arity; i++) domain.push_back(node->Annotation.IndParams[i].get_sort()); for(unsigned i = 0; i < params.size(); i++) @@ -3936,6 +3951,7 @@ namespace Duality { func_decl fd = SuffixFuncDecl(new_lit,j); int nargs = new_lit.num_args(); std::vector args; + args.reserve(nargs); for(int k = 0; k < nargs; k++) args.push_back(new_lit.arg(k)); new_lit = fd(nargs, VEC2PTR(args)); @@ -4126,6 +4142,7 @@ namespace Duality { // int idx; std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for(int i = 0; i < nargs; i++) args.push_back(ToRuleRec(e, memo, t.arg(i),quants)); hash_map::iterator rit = e->relMap.find(f); diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index 59e68e046..6053295b5 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -3424,6 +3424,7 @@ namespace Duality { func_decl f = t.decl(); std::vector args; int nargs = t.num_args(); + args.reserve(nargs); for(int i = 0; i < nargs; i++) args.push_back(AddParamToRels(memo, rmap, p, t.arg(i))); hash_map::iterator rit = rmap.find(f); diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp index 6f918bccb..91b0c5a63 100755 --- a/src/interp/iz3interp.cpp +++ b/src/interp/iz3interp.cpp @@ -97,6 +97,7 @@ struct frame_reducer : public iz3mgr { // if multiple children of a tree node are used, we can't delete it std::vector used_children; + used_children.reserve(frames); for(int i = 0; i < frames; i++) used_children.push_back(0); for(int i = 0; i < frames; i++) diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index 4831e7eaf..32b76b224 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -1146,6 +1146,7 @@ public: my_cons.push_back(mk_not(farkas_con)); my_coeffs.push_back(make_int("1")); std::vector my_hyps; + my_hyps.reserve(nargs); for(int i = 0; i < nargs; i++) my_hyps.push_back(iproof->make_hypothesis(my_cons[i])); ast res = iproof->make_farkas(mk_false(),my_hyps,my_cons,my_coeffs); @@ -1203,6 +1204,7 @@ public: int nargs = num_prems(proof); if(nargs != (int)(my_coeffs.size())) throw "bad gomory-cut theory lemma"; + my_prem_cons.reserve(nargs); for(int i = 0; i < nargs; i++) my_prem_cons.push_back(conc(prem(proof,i))); ast my_con = normalize_inequality(sum_inequalities(my_coeffs,my_prem_cons)); diff --git a/src/muz/duality/duality_dl_interface.cpp b/src/muz/duality/duality_dl_interface.cpp index 5ce4ef957..15f7f84d8 100755 --- a/src/muz/duality/duality_dl_interface.cpp +++ b/src/muz/duality/duality_dl_interface.cpp @@ -273,6 +273,7 @@ namespace Duality { if (!heads.contains(fd)) { int arity = f.arity(); std::vector args; + args.reserve(arity); for (int j = 0; j < arity; j++) args.push_back(_d->ctx.fresh_func_decl("X", f.domain(j))()); expr c = implies(_d->ctx.bool_val(false), f(args)); From 5911f810edb8933bd903153d03ff42f4ede23f53 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 6 Feb 2018 11:23:08 +0700 Subject: [PATCH 0528/1283] Fix inconsistent missing override warnings. --- src/qe/qe.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 0a3f880b7..57a8c365b 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -1536,19 +1536,19 @@ namespace qe { pop(*model_eval); } - ast_manager& get_manager() { return m; } + ast_manager& get_manager() override { return m; } - atom_set const& pos_atoms() const { return m_current->pos_atoms(); } + atom_set const& pos_atoms() const override { return m_current->pos_atoms(); } - atom_set const& neg_atoms() const { return m_current->neg_atoms(); } + atom_set const& neg_atoms() const override { return m_current->neg_atoms(); } - unsigned get_num_vars() const { return m_current->num_free_vars(); } + unsigned get_num_vars() const override { return m_current->num_free_vars(); } - app* get_var(unsigned idx) const { return m_current->free_var(idx); } + app* get_var(unsigned idx) const override { return m_current->free_var(idx); } - app_ref_vector const& get_vars() const { return m_current->free_vars(); } + app_ref_vector const& get_vars() const override { return m_current->free_vars(); } - contains_app& contains(unsigned idx) { return contains(get_var(idx)); } + contains_app& contains(unsigned idx) override { return contains(get_var(idx)); } // // The variable at idx is eliminated (without branching). @@ -1564,7 +1564,7 @@ namespace qe { normalize(*m_current); } - void add_var(app* x) { + void add_var(app* x) override { m_new_vars.push_back(x); if (m_var2branch.contains(x)) { return; @@ -1583,7 +1583,7 @@ namespace qe { m_var2branch.insert(x, bv); } - virtual void add_constraint(bool use_current_val, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) { + void add_constraint(bool use_current_val, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) override { search_tree* node = m_current; if (!use_current_val) { node = m_current->parent(); @@ -1602,7 +1602,7 @@ namespace qe { m_solver.assert_expr(fml); } - void blast_or(app* var, expr_ref& fml) { + void blast_or(app* var, expr_ref& fml) override { m_qe.eliminate_exists(1, &var, fml, m_free_vars, false, 0); } From c74ad466827307ca847ea5c4940baf8cb2d26374 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 5 Feb 2018 21:22:46 -0800 Subject: [PATCH 0529/1283] remove a duplicate definition Signed-off-by: Lev Nachmanson --- src/util/lp/lp_solver_instances.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/lp/lp_solver_instances.cpp b/src/util/lp/lp_solver_instances.cpp index 4de1f74c8..d7caf9a18 100644 --- a/src/util/lp/lp_solver_instances.cpp +++ b/src/util/lp/lp_solver_instances.cpp @@ -54,5 +54,4 @@ template void lp::lp_solver::scale(); template void lp::lp_solver::set_scaled_cost(unsigned int); template lp::lp_solver::~lp_solver(); template double lp::lp_solver::get_column_value_by_name(std::string) const; -template std::string lp::lp_solver::get_column_name(unsigned int) const; template std::string lp::lp_solver::get_column_name(unsigned int) const; From cb6896087dbb3a1746dd2d0e76dfe57c99804655 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Feb 2018 10:21:02 -0800 Subject: [PATCH 0530/1283] fix #1468 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_probing.h | 2 +- src/sat/sat_solver.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sat/sat_probing.h b/src/sat/sat_probing.h index 391098ef7..fb9b1dd30 100644 --- a/src/sat/sat_probing.h +++ b/src/sat/sat_probing.h @@ -55,7 +55,6 @@ namespace sat { struct report; - void reset_cache(literal l); void cache_bins(literal l, unsigned old_tr_sz); bool try_lit(literal l, bool updt_cache); void process(bool_var v); @@ -66,6 +65,7 @@ namespace sat { bool operator()(bool force = false); + void reset_cache(literal l); void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f0c23e087..dbd996cd0 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2702,6 +2702,8 @@ namespace sat { if (v < m_level.size()) { for (bool_var i = v; i < m_level.size(); ++i) { m_case_split_queue.del_var_eh(i); + m_probing.reset_cache(literal(i, true)); + m_probing.reset_cache(literal(i, false)); } m_watches.shrink(2*v); m_assignment.shrink(2*v); From 43441d0fd535dda9c475b9e5ecf654c3a8f20b32 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Feb 2018 14:02:44 -0800 Subject: [PATCH 0531/1283] add LP parser option to front-end and opt context Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 5 + src/opt/opt_parse.cpp | 570 +++++++++++++++++++-------- src/opt/opt_parse.h | 2 + src/sat/sat_watched.cpp | 2 +- src/shell/main.cpp | 21 +- src/shell/opt_frontend.cpp | 20 +- src/shell/opt_frontend.h | 4 +- src/tactic/arith/lia2card_tactic.cpp | 11 +- 8 files changed, 459 insertions(+), 176 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 5ff408bb7..afb7d25c4 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -302,6 +302,11 @@ extern "C" { parse_wcnf(*to_optimize_ptr(opt), s, h); return; } + if (ext && std::string("lp") == ext) { + unsigned_vector h; + parse_lp(*to_optimize_ptr(opt), s, h); + return; + } scoped_ptr ctx = alloc(cmd_context, false, &m); install_opt_cmds(*ctx.get(), to_optimize_ptr(opt)); ctx->set_ignore_check(true); diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 9ac0f77a0..5ca1faed6 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -310,41 +310,164 @@ void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h) { opb.parse(); } -#if 0 +/** + * \brief Parser for a modest subset of the CPLEX LP format. + * Reference: http://eaton.math.rpi.edu/cplex90html/reffileformatscplex/reffileformatscplex5.html + */ -class lp_stream_buffer : opt_stream_buffer { -public: - lp_stream_buffer(std::istream & s): - opt_stream_buffer(s) - {} - - char lower(char c) { - return ('A' <= c && c <= 'Z') ? c - 'A' + 'a' : c; - } - - bool parse_token_nocase(char const* token) { - skip_whitespace(); - char const* t = token; - while (lower(ch()) == *t) { - next(); - ++t; - } - return 0 == *t; - } +struct asymbol { + bool m_is_num; + symbol m_sym; + rational m_num; + unsigned m_line; + asymbol(symbol const& s, unsigned l): m_is_num(false), m_sym(s), m_line(l) {} + asymbol(rational const& r, unsigned l): m_is_num(true), m_num(r), m_line(l) {} }; - class lp_tokenizer { - opt_stream_buffer& in; + vector m_tokens; + unsigned m_pos; + svector m_buffer; public: lp_tokenizer(opt_stream_buffer& in): - in(in) - {} + m_pos(0) + { + parse_all(in); + } + + symbol const& peek(unsigned i) { + if (i + m_pos >= m_tokens.size()) { + return symbol::null; + } + return m_tokens[i + m_pos].m_sym; + } + + bool peek_num(unsigned i) { + if (i + m_pos >= m_tokens.size()) { + return false; + } + return m_tokens[i + m_pos].m_is_num; + } + + rational const& get_num(unsigned i) { + return m_tokens[i + m_pos].m_num; + } + + void next(unsigned delta = 1) { + m_pos += delta; + } + + bool eof() const { + return m_pos == m_tokens.size(); + } + + unsigned line() const { + if (m_pos < m_tokens.size()) return m_tokens[m_pos].m_line; + return 0; + } + +private: + + bool is_separator(char c) { + return c == '\n' || c == '\\' || c == '*' || c == '+'; + } + + char lower(char c) { + if ('A' <= c && c <= 'Z') + return c - ('A' - 'a'); + return c; + } + + void parse_all(opt_stream_buffer& in) { + while (!in.eof()) { + in.skip_whitespace(); + char c = in.ch(); + if (c == '\\') { + in.skip_line(); + continue; + } + + if (is_num(c)) { + rational n(0); + unsigned div = 1; + while (is_num(c) && !in.eof()) { + n = n*rational(10) + rational(c - '0'); + in.next(); + c = in.ch(); + } + if (c == '.') { + in.next(); + while (is_num(c) && !in.eof()) { + n = n*rational(10) + rational(c - '0'); + in.next(); + div *= 10; + c = in.ch(); + } + } + if (div > 1) n = n / rational(div); + m_tokens.push_back(asymbol(n, in.line())); + continue; + } + m_buffer.reset(); + if (is_alpha(c)) { + while (is_sym(c) && !in.eof()) { + m_buffer.push_back(lower(c)); + in.next(); + c = in.ch(); + } + } + else { + while (!is_ws(c) && !in.eof()) { + m_buffer.push_back(c); + in.next(); + c = in.ch(); + } + } + m_buffer.push_back(0); + m_tokens.push_back(asymbol(symbol(m_buffer.c_ptr()), in.line())); + } + } + + bool is_alpha(char c) const { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); + } + + bool is_num(char c) const { + return '0' <= c && c <= '9'; + } + + bool is_ws(char c) const { + return c == ' ' || c == '\n' || c == '\t'; + } + + bool is_sym(char c) const { + return + is_alpha(c) || + is_num(c) || + c == '!' || + c == '"' || + c == '#' || + c == '$' || + c == '%' || + c == '&' || + c == '{' || + c == '}' || + c == ',' || + c == '.' || + c == ';' || + c == '?' || + c == '@' || + c == '`' || + c == '\'' || + c == '(' || + c == ')' || + c == '~'; + } }; class lp_parse { - typedef svector > lin_term; + typedef vector > lin_term; struct objective { bool m_is_max; @@ -356,47 +479,96 @@ class lp_parse { le, ge, eq }; - struct indicator { - symbol m_var; - bool m_true; - }; - struct constraint { - optional m_ind; + symbol m_name; + symbol m_bvar; + rational m_bval; lin_term m_expr; rel_op m_rel; - int m_bound; + rational m_bound; + constraint(symbol const& name, symbol const& v, rational const& val, lin_term& terms, rel_op r, rational const& bound): + m_name(name), m_bvar(v), m_bval(val), m_expr(terms), m_rel(r), m_bound(bound) {} }; struct bound { - symbol m_var; - option m_lo, m_hi; + optional m_lo, m_hi; + bool m_int; + bound() : m_int(false) {} }; - opt::context& opt; - lp_tokenizer& tok; - objective m_objective; - vector m_constraints; - vector m_bounds; - hashtable m_binary; + opt::context& opt; + unsigned_vector& m_h; + lp_tokenizer tok; + objective m_objective; + vector m_constraints; + map m_bounds; public: - lp_parse(opt::context& opt, lp_stream_buffer& in): - opt(opt), tok(is) {} + lp_parse(opt::context& opt, opt_stream_buffer& in, unsigned_vector& h) : + opt(opt), m_h(h), tok(in) {} void parse() { parse_objective(); - parse_subject_to(); - parse_bounds(); - parse_general(); - parse_binary(); + if (!try_subject_to()) { + error("subject to section expected"); + return; + } + + while (!is_section()) { + parse_constraint(); + } + + while (true) { + if (is_bounds()) { + tok.next(); + while (!is_section()) { + parse_bound(); + } + } + else if (is_binary()) { + tok.next(); + while (!is_section()) { + parse_binary(); + } + } + else if (is_general()) { + tok.next(); + while (!is_section()) { + parse_general(); + } + } + else { + break; + } + } post_process(); } +private: + + void error(char const* msg) { + std::ostringstream ous; + ous << tok.line() << ": " << msg << " got: " << peek(0) << "\n"; + throw default_exception(ous.str()); + } + + symbol const& peek(unsigned i) { return tok.peek(i); } + + bool try_accept(char * token) { + if (peek(0) == token) { + tok.next(); + return true; + } + return false; + } + void parse_objective() { m_objective.m_is_max = minmax(); - m_objective.m_name = try_name(); + if (peek(1) == ":") { + m_objective.m_name = peek(0); + tok.next(2); + } parse_expr(m_objective.m_expr); } @@ -413,132 +585,218 @@ public: return false; } + void parse_constraint() { + symbol name; + if (peek(1) == ":") { + name = peek(0); + tok.next(2); + } + rational val(0); + symbol var; + parse_indicator(var, val); + lin_term terms; + parse_expr(terms); + rel_op op = parse_relation(); + rational rhs = tok.get_num(0); + tok.next(); + m_constraints.push_back(constraint(name, var, val, terms, op, rhs)); + } - bool try_accept(char const* token) { + void parse_expr(lin_term& terms) { + bool pos = true; + if (peek(0) == "-") { + pos = false; + tok.next(); + } + while (peek(0) == "+") { + tok.next(); + } + terms.push_back(parse_term()); + if (!pos) terms.back().first = -terms.back().first; + while (peek(0) == "+" || peek(0) == "-") { + bool pos = peek(0) == "+"; + tok.next(); + terms.push_back(parse_term()); + if (!pos) terms.back().first = -terms.back().first; + } + } + + std::pair parse_term() { + std::pair r(rational::one(), peek(0)); + if (tok.peek_num(0)) { + r.first = tok.get_num(0); + r.second = peek(1); + tok.next(2); + } + else { + tok.next(1); + } + return r; + } + + rel_op parse_relation() { + if (try_accept("<=")) return le; + if (try_accept("=<")) return le; + if (try_accept(">=")) return ge; + if (try_accept("=>")) return ge; + if (try_accept("=")) return eq; + error("expected relation"); + return eq; + } + + bool peek_le(unsigned pos) { + return peek(pos) == "<=" || peek(pos) == "=<"; + } + + void parse_indicator(symbol& var, rational& val) { + if (peek(1) == "=" && tok.peek_num(2) && peek(3) == "->") { + var = peek(0); + val = tok.get_num(2); + tok.next(4); + } + } + + bool try_subject_to() { + if (try_accept("subject") && try_accept("to")) return true; + if (try_accept("such") && try_accept("that")) return true; + if (try_accept("st")) return true; + if (try_accept("s.t.")) return true; return false; } - bool parse_indicator(symbol& var, bool& val) { - if (!peek("=", 1)) return false; - if (!peek(":", 3)) return false; - if (!peek("1", 2) && !peek("0", 2)) return false; - val = peek("1",2); - parse_variable(var); - accept("="); - accept(); - accept(":"); - return true; + bool is_section() { return is_general() || is_binary() || is_bounds() || is_end();} + bool is_bounds() { return peek(0) == "bounds"; } + bool is_general() { return peek(0) == "general" || peek(0) == "gen" || peek(0) == "generals"; } + bool is_binary() { return peek(0) == "binary" || peek(0) == "binaries" || peek(0) == "bin"; } + bool is_end() { return peek(0) == "end" || tok.eof(); } + + // lo <= x + // x <= hi + // lo <= x <= hi + // + void parse_bound() { + symbol v; + if (peek_le(1) && tok.peek_num(0)) { + rational lhs = tok.get_num(0); + v = peek(2); + update_lower(lhs, v); + tok.next(3); + if (peek_le(0) && tok.peek_num(1)) { + rational rhs = tok.get_num(1); + update_upper(v, rhs); + tok.next(2); + } + } + if (peek_le(1) && tok.peek_num(2)) { + v = peek(0); + tok.next(2); + rational rhs = tok.get_num(0); + update_upper(v, rhs); + tok.next(1); + } } - void parse_bounds() { - if (!try_accept("bounds")) return; - + void update_lower(rational const& r, symbol const& v) { + bound b; + m_bounds.find(v, b); + b.m_lo = r; + m_bounds.insert(v, b); } - void parse_indicator() { - + void update_upper(symbol const& v, rational const& r) { + bound b; + if (!m_bounds.find(v, b)) { + // set the lower bound to default 0 + b.m_lo = rational::zero(); + } + b.m_hi = r; + m_bounds.insert(v, b); } - - def indicator(self): - v = self.variable() - self.accept("=") - val = self.try_accept("1") - if val is None: - val = self.accept("0") - self.accept("->") - return (var, val) - def try_indicator(self): - try: - return self.indicator() - with: - return None + void parse_binary() { + symbol const& v = peek(0); + update_lower(rational::zero(), v); + update_upper(v, rational::one()); + m_bounds[v].m_int = true; + tok.next(); + } - def constraints(self): - return [c for c in self._constraints()] + void parse_general() { + symbol const& v = peek(0); + bound b; + m_bounds.find(v, b); + b.m_int = true; + m_bounds.insert(v, b); + tok.next(); + } - def _constraints(self): - while True: - c = self.try_constraint() - if c in None: - return - yield c + void post_process() { + ast_manager& m = opt.get_manager(); + arith_util a(m); + for (constraint const& c : m_constraints) { + expr_ref fml(m); + expr_ref term = process_terms(c.m_expr); + bool is_int = a.is_int(term) && c.m_bound.is_int(); + switch (c.m_rel) { + case le: fml = a.mk_le(term, a.mk_numeral(c.m_bound, is_int)); break; + case ge: fml = a.mk_ge(term, a.mk_numeral(c.m_bound, is_int)); break; + case eq: fml = m.mk_eq(term, a.mk_numeral(c.m_bound, is_int)); break; + } + if (c.m_bvar != symbol::null) { + term = mk_var(c.m_bvar); + bool is_int = c.m_bval.is_int() && a.is_int(term); + term = m.mk_eq(mk_var(c.m_bvar), a.mk_numeral(c.m_bval, is_int)); + fml = m.mk_implies(term, fml); + } + opt.add_hard_constraint(fml); + } + for (auto const& kv : m_bounds) { + bound const& b = kv.m_value; + expr_ref term = mk_var(kv.m_key); + if (b.m_lo) { + bool is_int = b.m_lo->is_int() && a.is_int(term); + opt.add_hard_constraint(a.mk_le(a.mk_numeral(*b.m_lo, is_int), term)); + } + if (b.m_hi) { + bool is_int = b.m_hi->is_int() && a.is_int(term); + opt.add_hard_constraint(a.mk_le(term, a.mk_numeral(*b.m_hi, is_int))); + } + } + expr_ref term = process_terms(m_objective.m_expr); + m_h.push_back(opt.add_objective(to_app(term), m_objective.m_is_max)); + } - def try_constraint(self): - try: - return self.constraint() - except: - return None - - def constraint(self): - name = self.try_label() - guard = self.try_guard() - e = self.expr() - op = self.relation() - rhs = self.numeral() - return (name, guard, e, ops, rhs) + expr_ref process_terms(lin_term const& terms) { + ast_manager& m = opt.get_manager(); + arith_util a(m); + expr_ref_vector result(m); + for (auto const& kv : terms) { + expr_ref term = mk_var(kv.second); + if (!kv.first.is_one()) { + bool is_int = kv.first.is_int() && a.is_int(term); + term = a.mk_mul(a.mk_numeral(kv.first, is_int), term); + } + result.push_back(term); + } + return expr_ref(a.mk_add(result.size(), result.c_ptr()), m); + } - def expr(self): - return [t for t in self.terms()] - - def terms(self): - while True: - t = self.term() - if t is None: - return None - yield t - - def term(self): - sign = self.sign() - coeff = self.coeff() - v = self.variable() - return (sign*coeff, v) - - def sign(self): - if self.try_accept("-"): - return -1 - return 1 - - def coeff(self): - tok = self.peek() - if tok is int: - self.next() - return (int) tok - return 1 - - def relation(self): - if self.try_accept("<="): - return "<=" - if self.try_accept(">="): - return ">=" - if self.try_accept("=<"): - return "<=" - if self.try_accept("=>"): - return ">=" - if self.try_accept("="): - return "=" - return None - - def subject_to(self): - if self.accept("subject") and self.accept("to"): - return - if self.accept("such") and self.accept("that"): - return - if self.accept("st"): - return - if self.accept("s"): - self.try_accept(".") - self.accept("t") - self.accept(".") - return - + expr_ref mk_var(symbol const& v) { + ast_manager& m = opt.get_manager(); + arith_util a(m); + bound b; + if (!m_bounds.find(v, b)) { + b.m_lo = rational::zero(); + m_bounds.insert(v, b); + } + return expr_ref(m.mk_const(v, b.m_int ? a.mk_int() : a.mk_real()), m); + } }; -void parse_lp(opt::context& opt, std::istream& is) { - lp_stream_buffer _is(is); - lp_parse lp(opt, _is); +void parse_lp(opt::context& opt, std::istream& is, unsigned_vector& h) { + opt_stream_buffer _is(is); + lp_parse lp(opt, _is, h); lp.parse(); } -#endif diff --git a/src/opt/opt_parse.h b/src/opt/opt_parse.h index b058efcac..6cf92bd9c 100644 --- a/src/opt/opt_parse.h +++ b/src/opt/opt_parse.h @@ -23,6 +23,8 @@ void parse_wcnf(opt::context& opt, std::istream& is, unsigned_vector& h); void parse_opb(opt::context& opt, std::istream& is, unsigned_vector& h); +void parse_lp(opt::context& opt, std::istream& is, unsigned_vector& h); + #endif /* OPT_PARSE_H_ */ diff --git a/src/sat/sat_watched.cpp b/src/sat/sat_watched.cpp index 5e86a7a87..199d12797 100644 --- a/src/sat/sat_watched.cpp +++ b/src/sat/sat_watched.cpp @@ -85,7 +85,7 @@ namespace sat { } } wlist.set_end(it2); - VERIFY(found); + //VERIFY(found); } void conflict_cleanup(watch_list::iterator it, watch_list::iterator it2, watch_list& wlist) { diff --git a/src/shell/main.cpp b/src/shell/main.cpp index fe115611c..58deb7e95 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -38,7 +38,7 @@ Revision History: #include "util/env_params.h" #include "shell/lp_frontend.h" -typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind; +typedef enum { IN_UNSPECIFIED, IN_SMTLIB, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_LP, IN_Z3_LOG, IN_MPS } input_kind; std::string g_aux_input_file; char const * g_input_file = 0; @@ -71,10 +71,12 @@ void display_usage() { std::cout << "]. (C) Copyright 2006-2016 Microsoft Corp.\n"; std::cout << "Usage: z3 [options] [-file:]file\n"; std::cout << "\nInput format:\n"; - std::cout << " -smt use parser for SMT input format.\n"; std::cout << " -smt2 use parser for SMT 2 input format.\n"; std::cout << " -dl use parser for Datalog input format.\n"; std::cout << " -dimacs use parser for DIMACS input format.\n"; + std::cout << " -wcnf use parser for Weighted CNF DIMACS input format.\n"; + std::cout << " -opb use parser for PB optimization input format.\n"; + std::cout << " -lp use parser for a modest subset of CPLEX LP input format.\n"; std::cout << " -log use parser for Z3 log input format.\n"; std::cout << " -in read formula from standard input.\n"; std::cout << "\nMiscellaneous:\n"; @@ -188,9 +190,12 @@ void parse_cmd_line_args(int argc, char ** argv) { else if (strcmp(opt_name, "wcnf") == 0) { g_input_kind = IN_WCNF; } - else if (strcmp(opt_name, "bpo") == 0) { + else if (strcmp(opt_name, "pbo") == 0) { g_input_kind = IN_OPB; } + else if (strcmp(opt_name, "lp") == 0) { + g_input_kind = IN_LP; + } else if (strcmp(opt_name, "log") == 0) { g_input_kind = IN_Z3_LOG; } @@ -322,6 +327,9 @@ int STD_CALL main(int argc, char ** argv) { else if (strcmp(ext, "opb") == 0) { g_input_kind = IN_OPB; } + else if (strcmp(ext, "lp") == 0) { + g_input_kind = IN_LP; + } else if (strcmp(ext, "log") == 0) { g_input_kind = IN_Z3_LOG; } @@ -349,10 +357,13 @@ int STD_CALL main(int argc, char ** argv) { return_value = read_dimacs(g_input_file); break; case IN_WCNF: - return_value = parse_opt(g_input_file, true); + return_value = parse_opt(g_input_file, wcnf_t); break; case IN_OPB: - return_value = parse_opt(g_input_file, false); + return_value = parse_opt(g_input_file, opb_t); + break; + case IN_LP: + return_value = parse_opt(g_input_file, lp_t); break; case IN_DATALOG: read_datalog(g_input_file); diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 8154cbde4..48efd1148 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -14,6 +14,7 @@ Copyright (c) 2015 Microsoft Corporation #include "util/timeout.h" #include "ast/reg_decl_plugins.h" #include "opt/opt_parse.h" +#include "shell/opt_frontend.h" extern bool g_display_statistics; static bool g_first_interrupt = true; @@ -73,18 +74,23 @@ static void on_timeout() { } } -static unsigned parse_opt(std::istream& in, bool is_wcnf) { +static unsigned parse_opt(std::istream& in, opt_format f) { ast_manager m; reg_decl_plugins(m); opt::context opt(m); g_opt = &opt; params_ref p = gparams::get_module("opt"); opt.updt_params(p); - if (is_wcnf) { + switch (f) { + case wcnf_t: parse_wcnf(opt, in, g_handles); - } - else { + break; + case opb_t: parse_opb(opt, in, g_handles); + break; + case lp_t: + parse_lp(opt, in, g_handles); + break; } try { lbool r = opt.optimize(); @@ -121,7 +127,7 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { return 0; } -unsigned parse_opt(char const* file_name, bool is_wcnf) { +unsigned parse_opt(char const* file_name, opt_format f) { g_first_interrupt = true; g_start_time = static_cast(clock()); register_on_timeout_proc(on_timeout); @@ -132,10 +138,10 @@ unsigned parse_opt(char const* file_name, bool is_wcnf) { std::cerr << "(error \"failed to open file '" << file_name << "'\")" << std::endl; exit(ERR_OPEN_FILE); } - return parse_opt(in, is_wcnf); + return parse_opt(in, f); } else { - return parse_opt(std::cin, is_wcnf); + return parse_opt(std::cin, f); } } diff --git a/src/shell/opt_frontend.h b/src/shell/opt_frontend.h index 65ec606a5..1266ed76b 100644 --- a/src/shell/opt_frontend.h +++ b/src/shell/opt_frontend.h @@ -13,7 +13,9 @@ Author: #ifndef OPT_FRONTEND_H_ #define OPT_FRONTEND_H_ -unsigned parse_opt(char const* file_name, bool is_wcnf); +enum opt_format { opb_t, wcnf_t, lp_t }; + +unsigned parse_opt(char const* file_name, opt_format f); #endif /* OPT_FRONTEND_H_ */ diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 18acde8a8..4e97b1e57 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -160,11 +160,10 @@ public: expr_ref_vector xs(m); expr_ref last_v(m); if (!m_mc) m_mc = alloc(generic_model_converter, m, "lia2card"); - for (unsigned i = 0; i < hi; ++i) { - if (i < lo) { - xs.push_back(a.mk_int(1)); - continue; - } + if (lo > 0) { + xs.push_back(a.mk_int(lo)); + } + for (unsigned i = lo; i < hi; ++i) { std::string name(x->get_decl()->get_name().str()); expr_ref v(m.mk_fresh_const(name.c_str(), m.mk_bool_sort()), m); if (last_v) axioms.push_back(m.mk_implies(v, last_v)); @@ -195,7 +194,7 @@ public: if (a.is_int(x) && is_uninterp_const(x) && bounds.has_lower(x, lo, s1) && !s1 && lo.is_unsigned() && - bounds.has_upper(x, hi, s2) && !s2 && hi.is_unsigned() && hi.get_unsigned() <= m_max_ub) { + bounds.has_upper(x, hi, s2) && !s2 && hi.is_unsigned() && hi.get_unsigned() - lo.get_unsigned() <= m_max_ub) { expr_ref b = mk_bounded(axioms, to_app(x), lo.get_unsigned(), hi.get_unsigned()); rep.insert(x, b); m_bounds.insert(x, bound(lo.get_unsigned(), hi.get_unsigned(), b)); From 1ee7871bbfb0b92be2a2eb58349e489db75e300a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Feb 2018 18:48:03 -0800 Subject: [PATCH 0532/1283] to fix #1476 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 +- src/opt/opt_params.pyg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index a7c8c3f5b..2fdef6ca4 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1012,7 +1012,7 @@ namespace opt { void context::model_updated(model* md) { opt_params optp(m_params); symbol prefix = optp.solution_prefix(); - if (prefix == symbol::null) return; + if (prefix == symbol::null || prefix == symbol("")) return; model_ref mdl = md->copy(); fix_model(mdl); std::ostringstream buffer; diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 09d849e1a..1d6d7ee6a 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -5,7 +5,7 @@ def_module_params('opt', ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), - ('solution_prefix', SYMBOL, None, "path prefix to dump intermediary, but non-optimal, solutions"), + ('solution_prefix', SYMBOL, '', "path prefix to dump intermediary, but non-optimal, solutions"), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), From bee4716a850f96283c3f71bda67d44c4f93df429 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 12:56:30 -0800 Subject: [PATCH 0533/1283] lia2card simplifications, move up before elim01 (which could be deprecated) Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb_rewriter.cpp | 3 +++ src/opt/opt_context.cpp | 4 ++-- src/opt/opt_parse.cpp | 27 +++++++++++++++++++++++- src/sat/sat_big.cpp | 9 +++++++- src/tactic/arith/lia2card_tactic.cpp | 6 ++++-- src/tactic/portfolio/parallel_tactic.cpp | 4 ++++ src/util/util.h | 12 +++++++---- 7 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 8bf7f2078..42efb3c6c 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -272,6 +272,9 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons else if (k.is_one() && all_unit && m_args.size() == 1) { result = m_args.back(); } + else if (slack == k) { + result = mk_and(m, sz, m_args.c_ptr()); + } else { result = m_util.mk_eq(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 9e72d24dc..e62a1c647 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -735,8 +735,8 @@ namespace opt { tactic_ref tac1, tac2, tac3, tac4; if (optp.elim_01()) { tac1 = mk_dt2bv_tactic(m); - tac2 = mk_elim01_tactic(m); - tac3 = mk_lia2card_tactic(m); + tac2 = mk_lia2card_tactic(m); + tac3 = mk_elim01_tactic(m); tac4 = mk_eq2bv_tactic(m); params_ref lia_p; lia_p.set_bool("compile_equality", optp.pb_compile_equality()); diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 5ca1faed6..758379517 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -386,6 +386,26 @@ private: in.skip_line(); continue; } + bool neg = false; + if (c == '-') { + in.next(); + c = in.ch(); + m_buffer.reset(); + m_buffer.push_back('-'); + if (is_num(c)) { + neg = true; + } + else { + while (!is_ws(c) && !in.eof()) { + m_buffer.push_back(c); + in.next(); + c = in.ch(); + } + m_buffer.push_back(0); + m_tokens.push_back(asymbol(symbol(m_buffer.c_ptr()), in.line())); + continue; + } + } if (is_num(c)) { rational n(0); @@ -405,6 +425,7 @@ private: } } if (div > 1) n = n / rational(div); + if (neg) n.neg(); m_tokens.push_back(asymbol(n, in.line())); continue; } @@ -453,6 +474,7 @@ private: c == '{' || c == '}' || c == ',' || + c == '_' || c == '.' || c == ';' || c == '?' || @@ -687,13 +709,16 @@ private: tok.next(2); } } - if (peek_le(1) && tok.peek_num(2)) { + else if (peek_le(1) && tok.peek_num(2)) { v = peek(0); tok.next(2); rational rhs = tok.get_num(0); update_upper(v, rhs); tok.next(1); } + else { + error("bound expected"); + } } void update_lower(rational const& r, symbol const& v) { diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 9c2bef50e..b7dc0bf8a 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -28,7 +28,7 @@ namespace sat { void big::init(solver& s, bool learned) { init_adding_edges(s.num_vars(), learned); unsigned num_lits = m_num_vars * 2; - literal_vector lits; + literal_vector lits, r; SASSERT(num_lits == m_dag.size() && num_lits == m_roots.size()); for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { literal u = to_literal(l_idx); @@ -41,6 +41,13 @@ namespace sat { m_roots[v.index()] = false; edges.push_back(v); } +#if 0 + if (w.is_ext_constraint() && + s.m_ext && + s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), r)) { + IF_VERBOSE(0, verbose_stream() << "extended binary " << r.size() << "\n";); + } +#endif } } done_adding_edges(); diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 4e97b1e57..bc7e3a4ee 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -160,6 +160,9 @@ public: expr_ref_vector xs(m); expr_ref last_v(m); if (!m_mc) m_mc = alloc(generic_model_converter, m, "lia2card"); + if (hi == 0) { + return expr_ref(a.mk_int(0), m); + } if (lo > 0) { xs.push_back(a.mk_int(lo)); } @@ -183,7 +186,7 @@ public: expr_ref_vector axioms(m); expr_safe_replace rep(m); - tactic_report report("cardinality-intro", *g); + tactic_report report("lia2card", *g); bound_manager bounds(m); bounds(*g); @@ -205,7 +208,6 @@ public: expr_ref new_curr(m), tmp(m); proof_ref new_pr(m); rep(g->form(i), tmp); - if (tmp == g->form(i)) continue; m_rw(tmp, new_curr, new_pr); if (m.proofs_enabled() && !new_pr) { new_pr = m.mk_rewrite(g->form(i), new_curr); diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index f4982c2c2..4a5af3679 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -242,6 +242,7 @@ class parallel_tactic : public tactic { lbool simplify() { lbool r = l_undef; if (m_depth == 1) { + IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-1)\n";); set_simplify_params(true, true); // retain PB, retain blocked r = get_solver().check_sat(0,0); if (r != l_undef) return r; @@ -255,9 +256,11 @@ class parallel_tactic : public tactic { m_solver->set_model_converter(mc.get()); m_solver->assert_expr(fmls); } + IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-2)\n";); set_simplify_params(false, true); // remove PB, retain blocked r = get_solver().check_sat(0,0); if (r != l_undef) return r; + IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-3)\n";); set_simplify_params(false, false); // remove any PB, remove blocked r = get_solver().check_sat(0,0); return r; @@ -398,6 +401,7 @@ private: cube.reset(); cube.append(s.split_cubes(1)); SASSERT(cube.size() <= 1); + IF_VERBOSE(2, verbose_stream() << "(sat.parallel :split-cube " << cube.size() << ")\n";); if (!s.cubes().empty()) m_queue.add_task(s.clone()); if (!cube.empty()) s.assert_cube(cube.get(0)); s.inc_depth(1); diff --git a/src/util/util.h b/src/util/util.h index 931ea34b4..6da289071 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -197,13 +197,17 @@ bool is_threaded(); } \ } } ((void) 0) +#ifdef _NO_OMP_ +#define LOCK_CODE(CODE) CODE; +#else #define LOCK_CODE(CODE) \ { \ - __pragma(omp critical (verbose_lock)) \ - { \ - CODE; \ - } \ + __pragma(omp critical (verbose_lock)) \ + { \ + CODE; \ + } \ } +#endif template struct default_eq { From 10894069b09c13c0ff7593cdd8eaa86c2009d5a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 13:19:40 -0800 Subject: [PATCH 0534/1283] fix compiler error reported by Luca Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 3b657f1a3..8125a651a 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -471,7 +471,8 @@ struct pb2bv_rewriter::imp { expr_ref gt = mod_ge(out, B, d_i + 1); expr_ref ge = mod_ge(out, B, d_i); - result = mk_or(gt, mk_and(ge, result)); + result = mk_and(ge, result); + result = mk_or(gt, result); TRACE("pb", tout << "b: " << b_i << " d: " << d_i << " gt: " << gt << " ge: " << ge << " " << result << "\n";); new_carry.reset(); From 734d48fa33433430a757ade527efe10445f97719 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 14:29:28 -0800 Subject: [PATCH 0535/1283] fix errors Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 2 +- src/opt/opt_parse.cpp | 2 +- src/util/file_path.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index afb7d25c4..65be0de0a 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -141,7 +141,7 @@ extern "C" { } catch (z3_exception& ex) { r = l_undef; - if (ex.msg() == "canceled" && mk_c(c)->m().canceled()) { + if (ex.msg() == std::string("canceled") && mk_c(c)->m().canceled()) { to_optimize_ptr(o)->set_reason_unknown(ex.msg()); } else { diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 758379517..666f79d97 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -577,7 +577,7 @@ private: symbol const& peek(unsigned i) { return tok.peek(i); } - bool try_accept(char * token) { + bool try_accept(char const * token) { if (peek(0) == token) { tok.next(); return true; diff --git a/src/util/file_path.h b/src/util/file_path.h index 8a2d053d8..ee0f3d620 100644 --- a/src/util/file_path.h +++ b/src/util/file_path.h @@ -19,6 +19,8 @@ Revision History: #ifndef FILE_PATH_H_ #define FILE_PATH_H_ +#include + inline char const * get_extension(char const * file_name) { if (file_name == 0) return 0; From 5a8154c1564908ef4be5c98fcc973bfba36e9dd3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 14:47:16 -0800 Subject: [PATCH 0536/1283] fix errors Signed-off-by: Nikolaj Bjorner --- src/solver/solver_na2as.cpp | 4 ++-- src/solver/solver_na2as.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index ae4014c7f..3cffd40cf 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -32,7 +32,7 @@ solver_na2as::~solver_na2as() {} void solver_na2as::assert_expr_core(expr * t, expr * a) { if (a == 0) { - assert_expr_core(t); + solver::assert_expr_core(t); } else { SASSERT(is_uninterp_const(a)); @@ -41,7 +41,7 @@ void solver_na2as::assert_expr_core(expr * t, expr * a) { m_assumptions.push_back(a); expr_ref new_t(m); new_t = m.mk_implies(a, t); - assert_expr_core(new_t); + solver::assert_expr_core(new_t); } } diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 061d62aee..2cbaaba5a 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -35,7 +35,7 @@ public: virtual ~solver_na2as(); void assert_expr_core(expr * t, expr * a) override; - virtual void assert_expr_core(expr * t) = 0; + // virtual void assert_expr_core(expr * t) = 0; // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions); From fa0c75e76ef03db5309bbdd0a884f49171dba174 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:13:13 -0800 Subject: [PATCH 0537/1283] rename to core2 to avoid overloaded virtual Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_itp_solver.h | 2 +- src/muz/spacer/spacer_virtual_solver.cpp | 2 +- src/sat/sat_lookahead.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 4 ++-- src/smt/smt_solver.cpp | 4 ++-- src/solver/combined_solver.cpp | 2 +- src/solver/solver.cpp | 2 +- src/solver/solver.h | 2 +- src/solver/solver_na2as.cpp | 6 +++--- src/solver/solver_na2as.h | 2 +- src/solver/solver_pool.cpp | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 55c1711c3..41e67afd1 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -115,7 +115,7 @@ public: virtual void assert_expr_core(expr *t) {m_solver.assert_expr(t);} - virtual void assert_expr_core(expr *t, expr *a) + virtual void assert_expr_core2(expr *t, expr *a) {NOT_IMPLEMENTED_YET();} virtual void assert_lemma(expr* e) { NOT_IMPLEMENTED_YET(); } virtual expr_ref lookahead(const expr_ref_vector &,const expr_ref_vector &) { return expr_ref(m.mk_true(), m); } diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 0c3adbbbd..ecb3c15a1 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -50,7 +50,7 @@ virtual_solver::virtual_solver(virtual_solver_factory &factory, // -- change m_context, but will add m_pred to // -- the private field solver_na2as::m_assumptions if (m_virtual) - { solver_na2as::assert_expr_core(m.mk_true(), m_pred); } + { solver_na2as::assert_expr_core2(m.mk_true(), m_pred); } } virtual_solver::~virtual_solver() diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index a37f32a1b..f81417d41 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -186,7 +186,7 @@ namespace sat { m_is_decision.reset(); m_cube.reset(); m_freevars_threshold = 0; - m_psat_threshold = DBL_MAX; + m_psat_threshold = 100000000.0; reset_stats(); } void reset_stats() { m_conflicts = 0; m_cutoffs = 0; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 03f6e6d0b..0ba8926cd 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -243,10 +243,10 @@ public: --n; } } - virtual unsigned get_scope_level() const { + unsigned get_scope_level() const override { return m_num_scopes; } - virtual void assert_expr_core(expr * t, expr * a) { + void assert_expr_core2(expr * t, expr * a) override { if (a) { m_asmsf.push_back(a); assert_expr_core(m.mk_implies(a, t)); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 3449ad480..780495e9c 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -105,11 +105,11 @@ namespace smt { m_context.assert_expr(t); } - virtual void assert_expr_core(expr * t, expr * a) { + virtual void assert_expr_core2(expr * t, expr * a) { if (m_name2assertion.contains(a)) { throw default_exception("named assertion defined twice"); } - solver_na2as::assert_expr_core(t, a); + solver_na2as::assert_expr_core2(t, a); get_manager().inc_ref(t); m_name2assertion.insert(a, t); } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 713009cd6..521cf8dec 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -172,7 +172,7 @@ public: m_solver2->assert_expr(t); } - virtual void assert_expr_core(expr * t, expr * a) { + virtual void assert_expr_core2(expr * t, expr * a) { if (m_check_sat_executed) switch_inc_mode(); m_solver1->assert_expr(t, a); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 356eaf2ed..3a772e7f2 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -199,7 +199,7 @@ void solver::assert_expr(expr* f, expr* t) { // (*mc)(a); } } - assert_expr_core(fml, a); + assert_expr_core2(fml, a); } void solver::collect_param_descrs(param_descrs & r) { diff --git a/src/solver/solver.h b/src/solver/solver.h index bc6ffb0e0..5bd25d8a6 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -102,7 +102,7 @@ public: void assert_expr(expr * t, expr* a); - virtual void assert_expr_core(expr * t, expr * a) = 0; + virtual void assert_expr_core2(expr * t, expr * a) = 0; /** \brief Create a backtracking point. diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 3cffd40cf..f98e08cdb 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -30,9 +30,9 @@ solver_na2as::solver_na2as(ast_manager & m): solver_na2as::~solver_na2as() {} -void solver_na2as::assert_expr_core(expr * t, expr * a) { +void solver_na2as::assert_expr_core2(expr * t, expr * a) { if (a == 0) { - solver::assert_expr_core(t); + assert_expr_core(t); } else { SASSERT(is_uninterp_const(a)); @@ -41,7 +41,7 @@ void solver_na2as::assert_expr_core(expr * t, expr * a) { m_assumptions.push_back(a); expr_ref new_t(m); new_t = m.mk_implies(a, t); - solver::assert_expr_core(new_t); + assert_expr_core(new_t); } } diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 2cbaaba5a..93526e844 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -34,7 +34,7 @@ public: solver_na2as(ast_manager & m); virtual ~solver_na2as(); - void assert_expr_core(expr * t, expr * a) override; + void assert_expr_core2(expr * t, expr * a) override; // virtual void assert_expr_core(expr * t) = 0; // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 2f6a22580..772650e64 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -49,7 +49,7 @@ public: m_in_delayed_scope(false), m_dump_counter(0) { if (is_virtual()) { - solver_na2as::assert_expr_core(m.mk_true(), pred); + solver_na2as::assert_expr_core2(m.mk_true(), pred); } } From 61f99b242e3f41e636240447068b20a3ce847f9c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:25:02 -0800 Subject: [PATCH 0538/1283] xor to xr to avoid clang issue Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 128 +++++++++++++------------- src/sat/ba_solver.h | 48 +++++----- src/sat/sat_local_search.cpp | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 38 ++++---- src/sat/tactic/goal2sat.cpp | 8 +- 5 files changed, 114 insertions(+), 110 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index ac332d362..f7b9e7749 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Extension for cardinality and xor reasoning. + Extension for cardinality and xr reasoning. Author: @@ -47,14 +47,14 @@ namespace sat { return static_cast(*this); } - ba_solver::xor& ba_solver::constraint::to_xor() { - SASSERT(is_xor()); - return static_cast(*this); + ba_solver::xr& ba_solver::constraint::to_xr() { + SASSERT(is_xr()); + return static_cast(*this); } - ba_solver::xor const& ba_solver::constraint::to_xor() const{ - SASSERT(is_xor()); - return static_cast(*this); + ba_solver::xr const& ba_solver::constraint::to_xr() const{ + SASSERT(is_xr()); + return static_cast(*this); } std::ostream& operator<<(std::ostream& out, ba_solver::constraint const& cnstr) { @@ -77,8 +77,8 @@ namespace sat { out << " >= " << p.k(); break; } - case ba_solver::xor_t: { - ba_solver::xor const& x = cnstr.to_xor(); + case ba_solver::xr_t: { + ba_solver::xr const& x = cnstr.to_xr(); for (unsigned i = 0; i < x.size(); ++i) { out << x[i] << " "; if (i + 1 < x.size()) out << "x "; @@ -187,22 +187,22 @@ namespace sat { // ----------------------------------- - // xor + // xr - ba_solver::xor::xor(unsigned id, literal_vector const& lits): - constraint(xor_t, id, null_literal, lits.size(), get_obj_size(lits.size())) { + ba_solver::xr::xr(unsigned id, literal_vector const& lits): + constraint(xr_t, id, null_literal, lits.size(), get_obj_size(lits.size())) { for (unsigned i = 0; i < size(); ++i) { m_lits[i] = lits[i]; } } - bool ba_solver::xor::is_watching(literal l) const { + bool ba_solver::xr::is_watching(literal l) const { return l == (*this)[0] || l == (*this)[1] || ~l == (*this)[0] || ~l == (*this)[1]; } - bool ba_solver::xor::well_formed() const { + bool ba_solver::xr::well_formed() const { uint_set vars; if (lit() != null_literal) vars.insert(lit().var()); for (literal l : *this) { @@ -305,7 +305,7 @@ namespace sat { UNREACHABLE(); } SASSERT(validate_conflict(c)); - if (c.is_xor() && value(lit) == l_true) lit.neg(); + if (c.is_xr() && value(lit) == l_true) lit.neg(); SASSERT(value(lit) == l_false); set_conflict(justification::mk_ext_justification(c.index()), ~lit); SASSERT(inconsistent()); @@ -892,16 +892,16 @@ namespace sat { // -------------------- - // xor: + // xr: - void ba_solver::clear_watch(xor& x) { + void ba_solver::clear_watch(xr& x) { unwatch_literal(x[0], x); unwatch_literal(x[1], x); unwatch_literal(~x[0], x); unwatch_literal(~x[1], x); } - bool ba_solver::parity(xor const& x, unsigned offset) const { + bool ba_solver::parity(xr const& x, unsigned offset) const { bool odd = false; unsigned sz = x.size(); for (unsigned i = offset; i < sz; ++i) { @@ -913,7 +913,7 @@ namespace sat { return odd; } - bool ba_solver::init_watch(xor& x) { + bool ba_solver::init_watch(xr& x) { clear_watch(x); if (x.lit() != null_literal && value(x.lit()) == l_false) { x.negate(); @@ -957,7 +957,7 @@ namespace sat { } - lbool ba_solver::add_assign(xor& x, literal alit) { + lbool ba_solver::add_assign(xr& x, literal alit) { // literal is assigned unsigned sz = x.size(); TRACE("ba", tout << "assign: " << ~alit << "@" << lvl(~alit) << " " << x << "\n"; display(tout, x, true); ); @@ -1223,12 +1223,12 @@ namespace sat { for (literal l : m_lemma) process_antecedent(~l, offset); break; } - case xor_t: { + case xr_t: { // jus.push_back(js); m_lemma.reset(); inc_bound(offset); inc_coeff(consequent, offset); - get_xor_antecedents(consequent, idx, js, m_lemma); + get_xr_antecedents(consequent, idx, js, m_lemma); for (literal l : m_lemma) process_antecedent(~l, offset); break; } @@ -1593,7 +1593,7 @@ namespace sat { switch (c.tag()) { case card_t: return init_watch(c.to_card()); case pb_t: return init_watch(c.to_pb()); - case xor_t: return init_watch(c.to_xor()); + case xr_t: return init_watch(c.to_xr()); } UNREACHABLE(); return false; @@ -1603,7 +1603,7 @@ namespace sat { switch (c.tag()) { case card_t: return add_assign(c.to_card(), l); case pb_t: return add_assign(c.to_pb(), l); - case xor_t: return add_assign(c.to_xor(), l); + case xr_t: return add_assign(c.to_xr(), l); } UNREACHABLE(); return l_undef; @@ -1632,13 +1632,13 @@ namespace sat { add_pb_ge(lit, wlits, k, false); } - void ba_solver::add_xor(literal_vector const& lits) { - add_xor(lits, false); + void ba_solver::add_xr(literal_vector const& lits) { + add_xr(lits, false); } - ba_solver::constraint* ba_solver::add_xor(literal_vector const& lits, bool learned) { - void * mem = m_allocator.allocate(xor::get_obj_size(lits.size())); - xor* x = new (mem) xor(next_id(), lits); + ba_solver::constraint* ba_solver::add_xr(literal_vector const& lits, bool learned) { + void * mem = m_allocator.allocate(xr::get_obj_size(lits.size())); + xr* x = new (mem) xr(next_id(), lits); x->set_learned(learned); add_constraint(x); for (literal l : lits) s().set_external(l.var()); // TBD: determine if goal2sat does this. @@ -1709,7 +1709,7 @@ namespace sat { switch (c.tag()) { case card_t: return get_reward(c.to_card(), occs); case pb_t: return get_reward(c.to_pb(), occs); - case xor_t: return 0; + case xr_t: return 0; default: UNREACHABLE(); return 0; } } @@ -1737,11 +1737,11 @@ namespace sat { } /** - \brief perform parity resolution on xor premises. - The idea is to collect premises based on xor resolvents. + \brief perform parity resolution on xr premises. + The idea is to collect premises based on xr resolvents. Variables that are repeated an even number of times cancel out. */ - void ba_solver::get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r) { + void ba_solver::get_xr_antecedents(literal l, unsigned index, justification js, literal_vector& r) { unsigned level = lvl(l); bool_var v = l.var(); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); @@ -1758,11 +1758,11 @@ namespace sat { if (js.get_kind() == justification::EXT_JUSTIFICATION) { constraint& c = index2constraint(js.get_ext_justification_idx()); TRACE("ba", tout << c << "\n";); - if (!c.is_xor()) { + if (!c.is_xr()) { r.push_back(l); } else { - xor& x = c.to_xor(); + xr& x = c.to_xr(); if (x[1].var() == l.var()) { x.swap(0, 1); } @@ -1959,7 +1959,7 @@ namespace sat { } } - void ba_solver::simplify(xor& x) { + void ba_solver::simplify(xr& x) { // no-op } @@ -1979,7 +1979,7 @@ namespace sat { } } - void ba_solver::get_antecedents(literal l, xor const& x, literal_vector& r) { + void ba_solver::get_antecedents(literal l, xr const& x, literal_vector& r) { if (x.lit() != null_literal) r.push_back(x.lit()); // TRACE("ba", display(tout << l << " ", x, true);); SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); @@ -2021,7 +2021,7 @@ namespace sat { switch (c.tag()) { case card_t: get_antecedents(l, c.to_card(), r); break; case pb_t: get_antecedents(l, c.to_pb(), r); break; - case xor_t: get_antecedents(l, c.to_xor(), r); break; + case xr_t: get_antecedents(l, c.to_xr(), r); break; default: UNREACHABLE(); break; } } @@ -2042,8 +2042,8 @@ namespace sat { case pb_t: clear_watch(c.to_pb()); break; - case xor_t: - clear_watch(c.to_xor()); + case xr_t: + clear_watch(c.to_xr()); break; default: UNREACHABLE(); @@ -2066,7 +2066,7 @@ namespace sat { switch (c.tag()) { case card_t: return validate_unit_propagation(c.to_card(), l); case pb_t: return validate_unit_propagation(c.to_pb(), l); - case xor_t: return true; + case xr_t: return true; default: UNREACHABLE(); break; } return false; @@ -2081,7 +2081,7 @@ namespace sat { switch (c.tag()) { case card_t: return eval(v1, eval(c.to_card())); case pb_t: return eval(v1, eval(c.to_pb())); - case xor_t: return eval(v1, eval(c.to_xor())); + case xr_t: return eval(v1, eval(c.to_xr())); default: UNREACHABLE(); break; } return l_undef; @@ -2120,7 +2120,7 @@ namespace sat { return l_undef; } - lbool ba_solver::eval(xor const& x) const { + lbool ba_solver::eval(xr const& x) const { bool odd = false; for (auto l : x) { @@ -2393,9 +2393,9 @@ namespace sat { if (!clausify(c.to_pb())) simplify(c.to_pb()); break; - case xor_t: - if (!clausify(c.to_xor())) - simplify(c.to_xor()); + case xr_t: + if (!clausify(c.to_xr())) + simplify(c.to_xr()); break; default: UNREACHABLE(); @@ -2551,7 +2551,7 @@ namespace sat { case pb_t: recompile(c.to_pb()); break; - case xor_t: + case xr_t: NOT_IMPLEMENTED_YET(); break; default: @@ -2664,7 +2664,7 @@ namespace sat { return false; } - bool ba_solver::clausify(xor& x) { + bool ba_solver::clausify(xr& x) { return false; } @@ -2730,7 +2730,7 @@ namespace sat { switch (c.tag()) { case card_t: split_root(c.to_card()); break; case pb_t: split_root(c.to_pb()); break; - case xor_t: NOT_IMPLEMENTED_YET(); break; + case xr_t: NOT_IMPLEMENTED_YET(); break; } } @@ -2843,8 +2843,8 @@ namespace sat { } break; } - case xor_t: { - xor& x = cp->to_xor(); + case xr_t: { + xr& x = cp->to_xr(); for (literal l : x) { m_cnstr_use_list[l.index()].push_back(&x); m_cnstr_use_list[(~l).index()].push_back(&x); @@ -3319,11 +3319,11 @@ namespace sat { result->add_pb_ge(p.lit(), wlits, p.k(), p.learned()); break; } - case xor_t: { - xor const& x = cp->to_xor(); + case xr_t: { + xr const& x = cp->to_xr(); lits.reset(); for (literal l : x) lits.push_back(l); - result->add_xor(lits, x.learned()); + result->add_xr(lits, x.learned()); break; } default: @@ -3355,8 +3355,8 @@ namespace sat { } break; } - case xor_t: { - xor const& x = cp->to_xor(); + case xr_t: { + xr const& x = cp->to_xr(); for (literal l : x) { ul.insert(l, idx); ul.insert(~l, idx); @@ -3450,8 +3450,8 @@ namespace sat { out << ">= " << ineq.m_k << "\n"; } - void ba_solver::display(std::ostream& out, xor const& x, bool values) const { - out << "xor: "; + void ba_solver::display(std::ostream& out, xr const& x, bool values) const { + out << "xr: "; for (literal l : x) { out << l; if (values) { @@ -3520,7 +3520,7 @@ namespace sat { switch (c.tag()) { case card_t: display(out, c.to_card(), values); break; case pb_t: display(out, c.to_pb(), values); break; - case xor_t: display(out, c.to_xor(), values); break; + case xr_t: display(out, c.to_xr(), values); break; default: UNREACHABLE(); break; } } @@ -3612,7 +3612,7 @@ namespace sat { return false; } - bool ba_solver::validate_unit_propagation(xor const& x, literal alit) const { + bool ba_solver::validate_unit_propagation(xr const& x, literal alit) const { if (value(x.lit()) != l_true) return false; for (unsigned i = 1; i < x.size(); ++i) { if (value(x[i]) == l_undef) return false; @@ -3827,14 +3827,14 @@ namespace sat { if (p.lit() != null_literal) ineq.push(~p.lit(), p.k()); break; } - case xor_t: { - xor& x = cnstr.to_xor(); + case xr_t: { + xr& x = cnstr.to_xr(); literal_vector ls; get_antecedents(lit, x, ls); ineq.reset(offset); for (literal l : ls) ineq.push(~l, offset); - literal lxor = x.lit(); - if (lxor != null_literal) ineq.push(~lxor, offset); + literal lxr = x.lit(); + if (lxr != null_literal) ineq.push(~lxr, offset); break; } default: diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index d950cb8cc..63e58d4b6 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -51,12 +51,12 @@ namespace sat { enum tag_t { card_t, pb_t, - xor_t + xr_t }; class card; class pb; - class xor; + class xr; class constraint { protected: @@ -91,13 +91,13 @@ namespace sat { size_t obj_size() const { return m_obj_size; } card& to_card(); pb& to_pb(); - xor& to_xor(); + xr& to_xr(); card const& to_card() const; pb const& to_pb() const; - xor const& to_xor() const; + xr const& to_xr() const; bool is_card() const { return m_tag == card_t; } bool is_pb() const { return m_tag == pb_t; } - bool is_xor() const { return m_tag == xor_t; } + bool is_xr() const { return m_tag == xr_t; } virtual bool is_watching(literal l) const { UNREACHABLE(); return false; }; virtual literal_vector literals() const { UNREACHABLE(); return literal_vector(); } @@ -174,11 +174,11 @@ namespace sat { virtual unsigned get_coeff(unsigned i) const { return m_wlits[i].first; } }; - class xor : public constraint { + class xr : public constraint { literal m_lits[0]; public: - static size_t get_obj_size(unsigned num_lits) { return sizeof(xor) + num_lits * sizeof(literal); } - xor(unsigned id, literal_vector const& lits); + static size_t get_obj_size(unsigned num_lits) { return sizeof(xr) + num_lits * sizeof(literal); } + xr(unsigned id, literal_vector const& lits); literal operator[](unsigned i) const { return m_lits[i]; } literal const* begin() const { return m_lits; } literal const* end() const { return begin() + m_size; } @@ -351,17 +351,17 @@ namespace sat { double get_reward(card const& c, literal_occs_fun& occs) const; - // xor specific functionality - void clear_watch(xor& x); - bool init_watch(xor& x); - bool parity(xor const& x, unsigned offset) const; - lbool add_assign(xor& x, literal alit); - void get_xor_antecedents(literal l, unsigned index, justification js, literal_vector& r); - void get_antecedents(literal l, xor const& x, literal_vector & r); - void simplify(xor& x); - bool clausify(xor& x); - void flush_roots(xor& x); - lbool eval(xor const& x) const; + // xr specific functionality + void clear_watch(xr& x); + bool init_watch(xr& x); + bool parity(xr const& x, unsigned offset) const; + lbool add_assign(xr& x, literal alit); + void get_xr_antecedents(literal l, unsigned index, justification js, literal_vector& r); + void get_antecedents(literal l, xr const& x, literal_vector & r); + void simplify(xr& x); + bool clausify(xr& x); + void flush_roots(xr& x); + lbool eval(xr const& x) const; // pb functionality unsigned m_a_max; @@ -425,14 +425,14 @@ namespace sat { // validation utilities bool validate_conflict(card const& c) const; - bool validate_conflict(xor const& x) const; + bool validate_conflict(xr const& x) const; bool validate_conflict(pb const& p) const; bool validate_assign(literal_vector const& lits, literal lit); bool validate_lemma(); bool validate_unit_propagation(card const& c, literal alit) const; bool validate_unit_propagation(pb const& p, literal alit) const; bool validate_unit_propagation(pb const& p, literal_vector const& r, literal alit) const; - bool validate_unit_propagation(xor const& x, literal alit) const; + bool validate_unit_propagation(xr const& x, literal alit) const; bool validate_conflict(literal_vector const& lits, ineq& p); bool validate_watch_literals() const; bool validate_watch_literal(literal lit) const; @@ -456,11 +456,11 @@ namespace sat { void display(std::ostream& out, constraint const& c, bool values) const; void display(std::ostream& out, card const& c, bool values) const; void display(std::ostream& out, pb const& p, bool values) const; - void display(std::ostream& out, xor const& c, bool values) const; + void display(std::ostream& out, xr const& c, bool values) const; constraint* add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned); constraint* add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); - constraint* add_xor(literal_vector const& lits, bool learned); + constraint* add_xr(literal_vector const& lits, bool learned); void copy_core(ba_solver* result, bool learned); void copy_constraints(ba_solver* result, ptr_vector const& constraints); @@ -472,7 +472,7 @@ namespace sat { virtual void set_unit_walk(unit_walk* u) { m_unit_walk = u; } void add_at_least(bool_var v, literal_vector const& lits, unsigned k); void add_pb_ge(bool_var v, svector const& wlits, unsigned k); - void add_xor(literal_vector const& lits); + void add_xr(literal_vector const& lits); virtual bool propagate(literal l, ext_constraint_idx idx); virtual lbool resolve_conflict(); diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 376d607ab..da9617151 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -400,7 +400,7 @@ namespace sat { } break; } - case ba_solver::xor_t: + case ba_solver::xr_t: NOT_IMPLEMENTED_YET(); break; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0ba8926cd..c6d6b4cac 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -104,7 +104,7 @@ public: virtual ~inc_sat_solver() {} - virtual solver* translate(ast_manager& dst_m, params_ref const& p) { + solver* translate(ast_manager& dst_m, params_ref const& p) override { if (m_num_scopes > 0) { throw default_exception("Cannot translate sat solver at non-base level"); } @@ -128,7 +128,7 @@ public: return result; } - virtual void set_progress_callback(progress_callback * callback) {} + void set_progress_callback(progress_callback * callback) override {} void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) { if (weights != 0) { @@ -160,7 +160,7 @@ public: (m.is_not(e, e) && is_uninterp_const(e)); } - virtual lbool check_sat(unsigned sz, expr * const * assumptions) { + lbool check_sat(unsigned sz, expr * const * assumptions) override { m_solver.pop_to_base_level(); m_core.reset(); if (m_solver.inconsistent()) return l_false; @@ -213,7 +213,8 @@ public: } return r; } - virtual void push() { + + void push() override { internalize_formulas(); m_solver.user_push(); ++m_num_scopes; @@ -223,7 +224,8 @@ public: if (m_bb_rewriter) m_bb_rewriter->push(); m_map.push(); } - virtual void pop(unsigned n) { + + void pop(unsigned n) override { if (n > m_num_scopes) { // allow inc_sat_solver to n = m_num_scopes; // take over for another solver. } @@ -243,9 +245,11 @@ public: --n; } } + unsigned get_scope_level() const override { return m_num_scopes; } + void assert_expr_core2(expr * t, expr * a) override { if (a) { m_asmsf.push_back(a); @@ -256,18 +260,18 @@ public: } } - virtual ast_manager& get_manager() const { return m; } - virtual void assert_expr_core(expr * t) { + ast_manager& get_manager() const override { return m; } + void assert_expr_core(expr * t) override { TRACE("goal2sat", tout << mk_pp(t, m) << "\n";); m_fmls.push_back(t); } - virtual void set_produce_models(bool f) {} - virtual void collect_param_descrs(param_descrs & r) { + void set_produce_models(bool f) override {} + void collect_param_descrs(param_descrs & r) override { solver::collect_param_descrs(r); goal2sat::collect_param_descrs(r); sat::solver::collect_param_descrs(r); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params.append(p); sat_params p1(p); m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); @@ -279,20 +283,20 @@ public: m_solver.set_incremental(is_incremental() && !override_incremental()); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { if (m_preprocess) m_preprocess->collect_statistics(st); m_solver.collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { + void get_unsat_core(ptr_vector & r) override { r.reset(); r.append(m_core.size(), m_core.c_ptr()); } - virtual proof * get_proof() { + proof * get_proof() override { UNREACHABLE(); return 0; } - virtual expr_ref_vector cube(expr_ref_vector& vs, unsigned backtrack_level) { + expr_ref_vector cube(expr_ref_vector& vs, unsigned backtrack_level) override { if (!is_internalized()) { lbool r = internalize_formulas(); if (r != l_true) return expr_ref_vector(m); @@ -331,8 +335,8 @@ public: } return fmls; } - - virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + + lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) override { init_preprocess(); TRACE("sat", tout << assumptions << "\n" << vars << "\n";); sat::literal_vector asms; @@ -780,7 +784,7 @@ private: } } - virtual void get_model_core(model_ref & mdl) { + void get_model_core(model_ref & mdl) override { TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); if (!m_solver.model_is_current()) { mdl = nullptr; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 5bba70659..ac97eb3c3 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -400,7 +400,7 @@ struct goal2sat::imp { lits[i].neg(); } ensure_extension(); - m_ext->add_xor(lits); + m_ext->add_xr(lits); sat::literal lit(v, sign); if (root) { m_result_stack.reset(); @@ -1115,7 +1115,7 @@ struct sat2goal::imp { r.assert_expr(fml); } - void assert_xor(ref& mc, goal & r, sat::ba_solver::xor const& x) { + void assert_xor(ref& mc, goal & r, sat::ba_solver::xr const& x) { ptr_buffer lits; for (sat::literal l : x) { lits.push_back(lit2expr(mc, l)); @@ -1185,8 +1185,8 @@ struct sat2goal::imp { case sat::ba_solver::pb_t: assert_pb(mc, r, c->to_pb()); break; - case sat::ba_solver::xor_t: - assert_xor(mc, r, c->to_xor()); + case sat::ba_solver::xr_t: + assert_xor(mc, r, c->to_xr()); break; } } From 6f610674fa4a94675fe5b99f32b03c84c3fe1b57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:31:57 -0800 Subject: [PATCH 0539/1283] fix errors Signed-off-by: Nikolaj Bjorner --- src/tactic/core/dom_simplify_tactic.h | 11 ++++------- src/tactic/core/elim_term_ite_tactic.cpp | 18 +++++++++--------- src/tactic/dependency_converter.cpp | 2 +- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index e2fbe81fa..8ebbe9cb4 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -129,17 +129,14 @@ public: m_trail(m), m_args(m), m_dominators(m), m_depth(0), m_max_depth(1024), m_forward(true) {} - virtual ~dom_simplify_tactic(); - virtual tactic * translate(ast_manager & m); - virtual void updt_params(params_ref const & p) {} + tactic * translate(ast_manager & m) override; + void updt_params(params_ref const & p) override {} static void get_param_descrs(param_descrs & r) {} - virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } - + void collect_param_descrs(param_descrs & r) override { get_param_descrs(r); } void operator()(goal_ref const & in, goal_ref_buffer & result) override; - - virtual void cleanup(); + void cleanup() override; }; class expr_substitution_simplifier : public dom_simplifier { diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 49815b6d1..c8591840d 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -136,33 +136,33 @@ public: m_params(p) { m_imp = alloc(imp, m, p); } - - virtual tactic * translate(ast_manager & m) { - return alloc(elim_term_ite_tactic, m, m_params); - } virtual ~elim_term_ite_tactic() { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + tactic * translate(ast_manager & m) override { + return alloc(elim_term_ite_tactic, m, m_params); + } + + void updt_params(params_ref const & p) override { m_params = p; m_imp->m_rw.cfg().updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); r.insert("max_args", CPK_UINT, "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result) { + void operator()(goal_ref const & in, + goal_ref_buffer & result) override { (*m_imp)(in, result); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; m_imp->~imp(); m_imp = new (m_imp) imp(m, m_params); diff --git a/src/tactic/dependency_converter.cpp b/src/tactic/dependency_converter.cpp index fbd445d52..34c864526 100644 --- a/src/tactic/dependency_converter.cpp +++ b/src/tactic/dependency_converter.cpp @@ -36,7 +36,7 @@ public: } virtual void display(std::ostream& out) { - out << m_dep << "\n"; + out << m_dep.get() << "\n"; } }; From 25eeb7aeac20a69c52e4bff97480089b2c52b32c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:39:56 -0800 Subject: [PATCH 0540/1283] fix build isses Signed-off-by: Nikolaj Bjorner --- src/tactic/model_converter.cpp | 2 +- src/tactic/proof_converter.cpp | 2 +- src/tactic/tactical.cpp | 64 ++-- src/util/lp/init_lar_solver.cpp | 589 -------------------------------- 4 files changed, 35 insertions(+), 622 deletions(-) delete mode 100644 src/util/lp/init_lar_solver.cpp diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 6c77d91b6..ef04af15f 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -134,7 +134,7 @@ public: out << ")\n"; } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { model * m = m_model->translate(translator); return alloc(model2mc, m, m_labels); } diff --git a/src/tactic/proof_converter.cpp b/src/tactic/proof_converter.cpp index a8d3ff578..0dc3a5ba2 100644 --- a/src/tactic/proof_converter.cpp +++ b/src/tactic/proof_converter.cpp @@ -24,7 +24,7 @@ class concat_proof_converter : public concat_converter { public: concat_proof_converter(proof_converter * pc1, proof_converter * pc2):concat_converter(pc1, pc2) {} - virtual char const * get_name() const { return "concat-proof-converter"; } + char const * get_name() const override { return "concat-proof-converter"; } proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { proof_ref tmp(m); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 96979a3ff..1899876df 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -39,42 +39,42 @@ public: virtual ~binary_tactical() {} - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_t1->updt_params(p); m_t2->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_t1->collect_param_descrs(r); m_t2->collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { m_t1->collect_statistics(st); m_t2->collect_statistics(st); } - virtual void reset_statistics() { + void reset_statistics() override { m_t1->reset_statistics(); m_t2->reset_statistics(); } - virtual void cleanup() { + void cleanup() override { m_t1->cleanup(); m_t2->cleanup(); } - virtual void reset() { + void reset() override { m_t1->reset(); m_t2->reset(); } - virtual void set_logic(symbol const & l) { + void set_logic(symbol const & l) override { m_t1->set_logic(l); m_t2->set_logic(l); } - virtual void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { m_t1->set_progress_callback(callback); m_t2->set_progress_callback(callback); } @@ -162,7 +162,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return translate_core(m); } @@ -285,7 +285,7 @@ public: virtual ~or_else_tactical() {} - virtual void operator()(goal_ref const & in, goal_ref_buffer& result) { + void operator()(goal_ref const & in, goal_ref_buffer& result) override { goal orig(*(in.get())); unsigned sz = m_ts.size(); unsigned i; @@ -310,7 +310,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { return translate_core(m); } }; tactic * or_else(unsigned num, tactic * const * ts) { @@ -471,7 +471,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { return translate_core(m); } }; tactic * par(unsigned num, tactic * const * ts) { @@ -715,7 +715,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return translate_core(m); } @@ -753,14 +753,14 @@ public: m_t->operator()(in, result); } - virtual void cleanup(void) { m_t->cleanup(); } - virtual void collect_statistics(statistics & st) const { m_t->collect_statistics(st); } - virtual void reset_statistics() { m_t->reset_statistics(); } - virtual void updt_params(params_ref const & p) { m_t->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_t->collect_param_descrs(r); } - virtual void reset() { m_t->reset(); } - virtual void set_logic(symbol const& l) { m_t->set_logic(l); } - virtual void set_progress_callback(progress_callback * callback) { m_t->set_progress_callback(callback); } + void cleanup(void) override { m_t->cleanup(); } + void collect_statistics(statistics & st) const override { m_t->collect_statistics(st); } + void reset_statistics() override { m_t->reset_statistics(); } + void updt_params(params_ref const & p) override { m_t->updt_params(p); } + void collect_param_descrs(param_descrs & r) override { m_t->collect_param_descrs(r); } + void reset() override { m_t->reset(); } + void set_logic(symbol const& l) override { m_t->set_logic(l); } + void set_progress_callback(progress_callback * callback) override { m_t->set_progress_callback(callback); } protected: template @@ -858,7 +858,7 @@ public: operator()(0, in, result); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(repeat_tactical, new_t, m_max_depth); } @@ -881,7 +881,7 @@ public: } }; - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(fail_if_branching_tactical, new_t, m_threshold); } @@ -900,7 +900,7 @@ public: m_t->cleanup(); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(cleanup_tactical, new_t); } @@ -924,7 +924,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(try_for_tactical, new_t, m_timeout); } @@ -941,7 +941,7 @@ public: t->updt_params(p); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { TRACE("using_params", tout << "before p: " << p << "\n"; tout << "m_params: " << m_params << "\n";); @@ -956,7 +956,7 @@ public: tout << "new_p: " << new_p << "\n";); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(using_params_tactical, new_t, m_params); } @@ -986,7 +986,7 @@ public: m_t->operator()(in, result); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(annotate_tactical, m_name.c_str(), new_t); } @@ -1015,7 +1015,7 @@ public: m_t2->operator()(in, result); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t1 = m_t1->translate(m); tactic * new_t2 = m_t2->translate(m); return alloc(cond_tactical, m_p.get(), new_t1, new_t2); @@ -1049,7 +1049,7 @@ public: result.push_back(in.get()); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return this; } }; @@ -1075,7 +1075,9 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { + return translate_core(m); + } }; class if_no_unsat_cores_tactical : public unary_tactical { diff --git a/src/util/lp/init_lar_solver.cpp b/src/util/lp/init_lar_solver.cpp deleted file mode 100644 index a410d04ae..000000000 --- a/src/util/lp/init_lar_solver.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -// this file represents the intiialization functionality of lar_solver - - -#include "util/lp/lar_solver.h" -namespace lean { - -bool lar_solver::strategy_is_undecided() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; -} - -var_index lar_solver::add_var(unsigned ext_j, bool is_integer) { - var_index i; - lean_assert (ext_j < m_terms_start_index); - - if (ext_j >= m_terms_start_index) - throw 0; // todo : what is the right way to exit? - auto it = m_ext_vars_to_columns.find(ext_j); - if (it != m_ext_vars_to_columns.end()) { - return it->second.ext_j(); - } - lean_assert(m_vars_to_ul_pairs.size() == A_r().column_count()); - i = A_r().column_count(); - m_vars_to_ul_pairs.push_back (ul_pair(static_cast(-1))); - add_non_basic_var_to_core_fields(ext_j); - lean_assert(sizes_are_correct()); - lean_assert(!column_is_integer(i)); - return i; -} - -void lar_solver::register_new_ext_var_index(unsigned ext_v) { - lean_assert(!contains(m_ext_vars_to_columns, ext_v)); - unsigned j = static_cast(m_ext_vars_to_columns.size()); - m_ext_vars_to_columns.insert(std::make_pair(ext_v, ext_var_info(j))); - lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j); - m_columns_to_ext_vars_or_term_indices.push_back(ext_v); -} - -void lar_solver::add_non_basic_var_to_core_fields(unsigned ext_j) { - register_new_ext_var_index(ext_j); - m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); - m_columns_with_changed_bound.increase_size_by_one(); - add_new_var_to_core_fields_for_mpq(false); - if (use_lu()) - add_new_var_to_core_fields_for_doubles(false); -} - -void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) { - unsigned j = A_d().column_count(); - A_d().add_column(); - lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); - m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_d().add_row(); - m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); - m_mpq_lar_core_solver.m_d_basis.push_back(j); - }else { - m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_d_nbasis.push_back(j); - } -} - -void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) { - unsigned j = A_r().column_count(); - A_r().add_column(); - lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_r_x.resize(j + 1); - m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); - m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_r().add_row(); - m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); - m_mpq_lar_core_solver.m_r_basis.push_back(j); - if (m_settings.bound_propagation()) - m_rows_with_changed_bounds.insert(A_r().row_count() - 1); - } else { - m_mpq_lar_core_solver.m_r_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_r_nbasis.push_back(j); - } -} - - -var_index lar_solver::add_term_undecided(const vector> & coeffs, - const mpq &m_v) { - m_terms.push_back(new lar_term(coeffs, m_v)); - return m_terms_start_index + m_terms.size() - 1; -} - -// terms -var_index lar_solver::add_term(const vector> & coeffs, - const mpq &m_v) { - if (strategy_is_undecided()) - return add_term_undecided(coeffs, m_v); - - m_terms.push_back(new lar_term(coeffs, m_v)); - unsigned adjusted_term_index = m_terms.size() - 1; - var_index ret = m_terms_start_index + adjusted_term_index; - if (use_tableau() && !coeffs.empty()) { - add_row_for_term(m_terms.back(), ret); - if (m_settings.bound_propagation()) - m_rows_with_changed_bounds.insert(A_r().row_count() - 1); - } - lean_assert(m_ext_vars_to_columns.size() == A_r().column_count()); - return ret; -} - -void lar_solver::add_row_for_term(const lar_term * term, unsigned term_ext_index) { - lean_assert(sizes_are_correct()); - add_row_from_term_no_constraint(term, term_ext_index); - lean_assert(sizes_are_correct()); -} - -void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { - register_new_ext_var_index(term_ext_index); - // j will be a new variable - unsigned j = A_r().column_count(); - ul_pair ul(j); - m_vars_to_ul_pairs.push_back(ul); - add_basic_var_to_core_fields(); - if (use_tableau()) { - auto it = iterator_on_term_with_basis_var(*term, j); - A_r().fill_last_row_with_pivoting(it, - m_mpq_lar_core_solver.m_r_solver.m_basis_heading); - m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type()); - } else { - fill_last_row_of_A_r(A_r(), term); - } - m_mpq_lar_core_solver.m_r_x[j] = get_basic_var_value_from_row_directly(A_r().row_count() - 1); - if (use_lu()) - fill_last_row_of_A_d(A_d(), term); -} - -void lar_solver::add_basic_var_to_core_fields() { - bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); - lean_assert(!use_lu || A_r().column_count() == A_d().column_count()); - m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); - m_columns_with_changed_bound.increase_size_by_one(); - m_rows_with_changed_bounds.increase_size_by_one(); - add_new_var_to_core_fields_for_mpq(true); - if (use_lu) - add_new_var_to_core_fields_for_doubles(true); -} - -constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { - constraint_index ci = m_constraints.size(); - if (!is_term(j)) { // j is a var - auto vc = new lar_var_constraint(j, kind, right_side); - m_constraints.push_back(vc); - update_column_type_and_bound(j, kind, right_side, ci); - } else { - add_var_bound_on_constraint_for_term(j, kind, right_side, ci); - } - lean_assert(sizes_are_correct()); - return ci; -} - -void lar_solver::update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { - switch(m_mpq_lar_core_solver.m_column_types[j]) { - case column_type::free_column: - update_free_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::boxed: - update_boxed_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::low_bound: - update_low_bound_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::upper_bound: - update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::fixed: - update_fixed_column_type_and_bound(j, kind, right_side, constr_index); - break; - default: - lean_assert(false); // cannot be here - } -} - -void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(is_term(j)); - unsigned adjusted_term_index = adjust_term_index(j); - auto it = m_ext_vars_to_columns.find(j); - if (it != m_ext_vars_to_columns.end()) { - unsigned term_j = it->second.ext_j(); - mpq rs = right_side - m_terms[adjusted_term_index]->m_v; - m_constraints.push_back(new lar_term_constraint(m_terms[adjusted_term_index], kind, right_side)); - update_column_type_and_bound(term_j, kind, rs, ci); - } - else { - add_constraint_from_term_and_create_new_column_row(j, m_terms[adjusted_term_index], kind, right_side); - } -} - -constraint_index lar_solver::add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { - vector> left_side; - mpq rs = - right_side_parm; - substitute_terms_in_linear_expression(left_side_with_terms, left_side, rs); - unsigned term_index = add_term(left_side, zero_of_type()); - constraint_index ci = m_constraints.size(); - add_var_bound_on_constraint_for_term(term_index, kind_par, -rs, ci); - return ci; -} - -void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, - lconstraint_kind kind, const mpq & right_side) { - - add_row_from_term_no_constraint(term, term_j); - unsigned j = A_r().column_count() - 1; - update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size()); - m_constraints.push_back(new lar_term_constraint(term, kind, right_side)); - lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); -} - -void lar_solver::decide_on_strategy_and_adjust_initial_state() { - lean_assert(strategy_is_undecided()); - if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { - m_settings.simplex_strategy() = simplex_strategy_enum::lu; - } else { - m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs? - } - adjust_initial_state(); -} - -void lar_solver::adjust_initial_state() { - switch (m_settings.simplex_strategy()) { - case simplex_strategy_enum::lu: - adjust_initial_state_for_lu(); - break; - case simplex_strategy_enum::tableau_rows: - adjust_initial_state_for_tableau_rows(); - break; - case simplex_strategy_enum::tableau_costs: - lean_assert(false); // not implemented - case simplex_strategy_enum::undecided: - adjust_initial_state_for_tableau_rows(); - break; - } -} - -void lar_solver::adjust_initial_state_for_lu() { - copy_from_mpq_matrix(A_d()); - unsigned n = A_d().column_count(); - m_mpq_lar_core_solver.m_d_x.resize(n); - m_mpq_lar_core_solver.m_d_low_bounds.resize(n); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); - m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; - m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; - - /* - unsigned j = A_d().column_count(); - A_d().add_column(); - lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); - m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_d().add_row(); - m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); - m_mpq_lar_core_solver.m_d_basis.push_back(j); - }else { - m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_d_nbasis.push_back(j); - }*/ -} - -void lar_solver::adjust_initial_state_for_tableau_rows() { - for (unsigned j = 0; j < m_terms.size(); j++) { - if (contains(m_ext_vars_to_columns, j + m_terms_start_index)) - continue; - add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index); - } -} - -// this fills the last row of A_d and sets the basis column: -1 in the last column of the row -void lar_solver::fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { - lean_assert(A.row_count() > 0); - lean_assert(A.column_count() > 0); - unsigned last_row = A.row_count() - 1; - lean_assert(A.m_rows[last_row].empty()); - - for (auto & t : ls->m_coeffs) { - lean_assert(!is_zero(t.second)); - var_index j = t.first; - A.set(last_row, j, - t.second.get_double()); - } - - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, - 1 ); -} - -void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); - lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); - { - auto up = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - } - set_upper_bound_witness(j, constr_ind); - break; - case GT: - y_of_bound = 1; - case GE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound; - lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); - { - auto low = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - } - set_low_bound_witness(j, constr_ind); - break; - case EQ: - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair(right_side, zero_of_type()); - set_upper_bound_witness(j, constr_ind); - set_low_bound_witness(j, constr_ind); - break; - - default: - lean_unreachable(); - - } - m_columns_with_changed_bound.insert(j); -} - -void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - if (up < m_mpq_lar_core_solver.m_r_upper_bounds()[j]) { - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - } - } - break; - case GT: - y_of_bound = 1; - case GE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed; - { - auto low = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - set_low_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - } else { - m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed; - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - set_low_bound_witness(j, ci); - m_infeasible_column_index = j; - } else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - break; - } - break; - - default: - lean_unreachable(); - - } -} - -void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - } - - if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - lean_assert(false); - m_infeasible_column_index = j; - } else { - if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]) - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - } - break; - case GT: - y_of_bound = 1; - case GE: - { - auto low = numeric_pair(right_side, y_of_bound); - if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - } - if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - } else if ( low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - m_columns_with_changed_bound.insert(j); - } - - break; - } - - default: - lean_unreachable(); - - } -} -void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - - if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - } else { - m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed; - } - } - break; - case GT: - y_of_bound = 1; - case GE: - { - auto low = numeric_pair(right_side, y_of_bound); - if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - m_columns_with_changed_bound.insert(j); - break; - } - - default: - lean_unreachable(); - - } -} - -void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - lean_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); - auto v = numeric_pair(right_side, mpq(0)); - - mpq y_of_bound(0); - switch (kind) { - case LT: - if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - break; - case LE: - { - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - } - break; - case GT: - { - if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index =j; - set_low_bound_witness(j, ci); - } - } - break; - case GE: - { - if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } - } - break; - case EQ: - { - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } - break; - } - - default: - lean_unreachable(); - - } -} - -} From 4ecf186580fdcdfd381b95bc32fbadceb15a4c54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:43:33 -0800 Subject: [PATCH 0541/1283] remove files Signed-off-by: Nikolaj Bjorner --- src/util/lp/int_solver.cpp | 1155 -------------------- src/util/lp/lar_solver.cpp | 2089 ------------------------------------ 2 files changed, 3244 deletions(-) delete mode 100644 src/util/lp/int_solver.cpp delete mode 100644 src/util/lp/lar_solver.cpp diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp deleted file mode 100644 index 87fafee77..000000000 --- a/src/util/lp/int_solver.cpp +++ /dev/null @@ -1,1155 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ - -#include "util/lp/int_solver.h" -#include "util/lp/lar_solver.h" -#include "util/lp/cut_solver.h" -#include -namespace lp { - -void int_solver::failed() { - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - - for (unsigned j : m_old_values_set.m_index) { - lcs.m_r_x[j] = m_old_values_data[j]; - lp_assert(lcs.m_r_solver.column_is_feasible(j)); - lcs.m_r_solver.remove_column_from_inf_set(j); - } - lp_assert(lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis()); - lp_assert(lcs.m_r_solver.current_x_is_feasible()); - m_old_values_set.clear(); -} - -void int_solver::trace_inf_rows() const { - TRACE("arith_int_rows", - unsigned num = m_lar_solver->A_r().column_count(); - for (unsigned v = 0; v < num; v++) { - if (is_int(v) && !get_value(v).is_int()) { - display_column(tout, v); - } - } - - num = 0; - for (unsigned i = 0; i < m_lar_solver->A_r().row_count(); i++) { - unsigned j = m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i]; - if (column_is_int_inf(j)) { - num++; - iterator_on_row it(m_lar_solver->A_r().m_rows[i]); - m_lar_solver->print_linear_iterator(&it, tout); - tout << "\n"; - } - } - tout << "num of int infeasible: " << num << "\n"; - ); -} - -int_set& int_solver::inf_int_set() { - return m_lar_solver->m_inf_int_set; -} - -const int_set& int_solver::inf_int_set() const { - return m_lar_solver->m_inf_int_set; -} - -bool int_solver::has_inf_int() const { - return !inf_int_set().is_empty(); -} - -int int_solver::find_inf_int_base_column() { - if (inf_int_set().is_empty()) - return -1; - int j = find_inf_int_boxed_base_column_with_smallest_range(); - if (j != -1) - return j; - unsigned k = settings().random_next() % inf_int_set().m_index.size(); - return inf_int_set().m_index[k]; -} - -int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { - int result = -1; - mpq range; - mpq new_range; - mpq small_range_thresold(1024); - unsigned n; - lar_core_solver & lcs = m_lar_solver->m_mpq_lar_core_solver; - - for (int j : inf_int_set().m_index) { - lp_assert(is_base(j) && column_is_int_inf(j)); - lp_assert(!is_fixed(j)); - if (!is_boxed(j)) - continue; - new_range = lcs.m_r_upper_bounds()[j].x - lcs.m_r_low_bounds()[j].x; - if (new_range > small_range_thresold) - continue; - if (result == -1) { - result = j; - range = new_range; - n = 1; - continue; - } - if (new_range < range) { - n = 1; - result = j; - range = new_range; - continue; - } - if (new_range == range) { - lp_assert(n >= 1); - if (settings().random_next() % (++n) == 0) { - result = j; - continue; - } - } - } - return result; - -} - -bool int_solver::is_gomory_cut_target(linear_combination_iterator &iter) { - unsigned j; - lp_assert(iter.is_reset()); - // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). - while (iter.next(j)) { - if (is_base(j)) continue; - if (!is_zero(get_value(j).y)) { - TRACE("gomory_cut", tout << "row is not gomory cut target:\n"; - display_column(tout, j); - tout << "infinitesimal: " << !is_zero(get_value(j).y) << "\n";); - iter.reset(); - return false; - } - } - iter.reset(); - return true; -} - - -void int_solver::real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& pol, explanation & expl, unsigned gomory_cut_inf_column) { - TRACE("gomory_cut_detail_real", tout << "real\n";); - mpq f_0 = fractional_part(get_value(gomory_cut_inf_column)); - mpq new_a; - if (at_low(x_j)) { - if (a.is_pos()) { - new_a = a / (1 - f_0); - } - else { - new_a = a / f_0; - new_a.neg(); - } - k.addmul(new_a, low_bound(x_j).x); // is it a faster operation than - // k += lower_bound(x_j).x * new_a; - expl.push_justification(column_low_bound_constraint(x_j), new_a); - } - else { - lp_assert(at_upper(x_j)); - if (a.is_pos()) { - new_a = a / f_0; - new_a.neg(); // the upper terms are inverted. - } - else { - new_a = a / (mpq(1) - f_0); - } - k.addmul(new_a, upper_bound(x_j).x); // k += upper_bound(x_j).x * new_a; - expl.push_justification(column_upper_bound_constraint(x_j), new_a); - } - TRACE("gomory_cut_detail_real", tout << a << "*v" << x_j << " k: " << k << "\n";); - pol.add_monomial(new_a, x_j); -} - -constraint_index int_solver::column_upper_bound_constraint(unsigned j) const { - return m_lar_solver->get_column_upper_bound_witness(j); -} - -constraint_index int_solver::column_low_bound_constraint(unsigned j) const { - return m_lar_solver->get_column_low_bound_witness(j); -} - - -void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term & t, explanation& expl, mpq & lcm_den, unsigned inf_column) { - lp_assert(is_int(x_j)); - lp_assert(!a.is_int()); - mpq f_0 = fractional_part(get_value(inf_column)); - lp_assert(f_0 > zero_of_type() && f_0 < one_of_type()); - mpq f_j = fractional_part(a); - TRACE("gomory_cut_detail", - tout << a << " x_j" << x_j << " k = " << k << "\n"; - tout << "f_j: " << f_j << "\n"; - tout << "f_0: " << f_0 << "\n"; - tout << "1 - f_0: " << 1 - f_0 << "\n"; - tout << "at_low(" << x_j << ") = " << at_low(x_j) << std::endl; - ); - lp_assert (!f_j.is_zero()); - mpq new_a; - if (at_low(x_j)) { - auto one_minus_f_0 = 1 - f_0; - if (f_j <= one_minus_f_0) { - new_a = f_j / one_minus_f_0; - } - else { - new_a = (1 - f_j) / f_0; - } - k.addmul(new_a, low_bound(x_j).x); - expl.push_justification(column_low_bound_constraint(x_j), new_a); - } - else { - lp_assert(at_upper(x_j)); - if (f_j <= f_0) { - new_a = f_j / f_0; - } - else { - new_a = (mpq(1) - f_j) / (1 - f_0); - } - new_a.neg(); // the upper terms are inverted - k.addmul(new_a, upper_bound(x_j).x); - expl.push_justification(column_upper_bound_constraint(x_j), new_a); - } - TRACE("gomory_cut_detail", tout << "new_a: " << new_a << " k: " << k << "\n";); - t.add_monomial(new_a, x_j); - lcm_den = lcm(lcm_den, denominator(new_a)); -} - -lia_move int_solver::report_conflict_from_gomory_cut(mpq & k) { - TRACE("empty_pol",); - lp_assert(k.is_pos()); - // conflict 0 >= k where k is positive - k.neg(); // returning 0 <= -k - return lia_move::conflict; -} - -void int_solver::gomory_cut_adjust_t_and_k(vector> & pol, - lar_term & t, - mpq &k, - bool some_ints, - mpq & lcm_den) { - if (!some_ints) - return; - - t.clear(); - if (pol.size() == 1) { - unsigned v = pol[0].second; - lp_assert(is_int(v)); - bool k_is_int = k.is_int(); - const mpq& a = pol[0].first; - k /= a; - if (a.is_pos()) { // we have av >= k - if (!k_is_int) - k = ceil(k); - // switch size - t.add_monomial(- mpq(1), v); - k.neg(); - } else { - if (!k_is_int) - k = floor(k); - t.add_monomial(mpq(1), v); - } - } else if (some_ints) { - lcm_den = lcm(lcm_den, denominator(k)); - lp_assert(lcm_den.is_pos()); - if (!lcm_den.is_one()) { - // normalize coefficients of integer parameters to be integers. - for (auto & pi: pol) { - pi.first *= lcm_den; - SASSERT(!is_int(pi.second) || pi.first.is_int()); - } - k *= lcm_den; - } - // negate everything to return -pol <= -k - for (const auto & pi: pol) - t.add_monomial(-pi.first, pi.second); - k.neg(); - } -} - -bool int_solver::current_solution_is_inf_on_cut(const lar_term& t, const mpq& k) const { - const auto & x = m_lar_solver->m_mpq_lar_core_solver.m_r_x; - impq v = t.apply(x); - TRACE( - "current_solution_is_inf_on_cut", tout << "v = " << v << " k = " << k << std::endl; - if (v <=k) { - tout << "v <= k - it should not happen!\n"; - } - ); - - return v > k; -} - -void int_solver::adjust_term_and_k_for_some_ints_case_gomory(lar_term& t, mpq& k, mpq &lcm_den) { - lp_assert(!t.is_empty()); - auto pol = t.coeffs_as_vector(); - t.clear(); - if (pol.size() == 1) { - TRACE("gomory_cut_detail", tout << "pol.size() is 1" << std::endl;); - unsigned v = pol[0].second; - lp_assert(is_int(v)); - const mpq& a = pol[0].first; - k /= a; - if (a.is_pos()) { // we have av >= k - if (!k.is_int()) - k = ceil(k); - // switch size - t.add_monomial(- mpq(1), v); - k.neg(); - } else { - if (!k.is_int()) - k = floor(k); - t.add_monomial(mpq(1), v); - } - } else { - TRACE("gomory_cut_detail", tout << "pol.size() > 1" << std::endl;); - lcm_den = lcm(lcm_den, denominator(k)); - lp_assert(lcm_den.is_pos()); - if (!lcm_den.is_one()) { - // normalize coefficients of integer parameters to be integers. - for (auto & pi: pol) { - pi.first *= lcm_den; - SASSERT(!is_int(pi.second) || pi.first.is_int()); - } - k *= lcm_den; - } - // negate everything to return -pol <= -k - for (const auto & pi: pol) - t.add_monomial(-pi.first, pi.second); - k.neg(); - } - TRACE("gomory_cut_detail", tout << "k = " << k << std::endl;); - lp_assert(k.is_int()); -} - - - - -lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl, unsigned inf_col, linear_combination_iterator& iter) { - - lp_assert(column_is_int_inf(inf_col)); - - TRACE("gomory_cut", - tout << "applying cut at:\n"; m_lar_solver->print_linear_iterator_indices_only(&iter, tout); tout << std::endl; - iter.reset(); - unsigned j; - while(iter.next(j)) { - m_lar_solver->m_mpq_lar_core_solver.m_r_solver.print_column_info(j, tout); - } - iter.reset(); - tout << "inf_col = " << inf_col << std::endl; - ); - - // gomory will be t >= k - k = 1; - mpq lcm_den(1); - unsigned x_j; - mpq a; - bool some_int_columns = false; - lp_assert(iter.is_reset()); - while (iter.next(a, x_j)) { - if (x_j == inf_col) - continue; - // make the format compatible with the format used in: Integrating Simplex with DPLL(T) - a.neg(); - if (is_real(x_j)) - real_case_in_gomory_cut(a, x_j, k, t, expl, inf_col); - else { - if (a.is_int()) continue; // f_j will be zero and no monomial will be added - some_int_columns = true; - int_case_in_gomory_cut(a, x_j, k, t, expl, lcm_den, inf_col); - } - } - - if (t.is_empty()) - return report_conflict_from_gomory_cut(k); - if (some_int_columns) - adjust_term_and_k_for_some_ints_case_gomory(t, k, lcm_den); - - lp_assert(current_solution_is_inf_on_cut(t, k)); - m_lar_solver->subs_term_columns(t); - return lia_move::cut; - -} - -void int_solver::init_check_data() { - unsigned n = m_lar_solver->A_r().column_count(); - m_old_values_set.resize(n); - m_old_values_data.resize(n); -} - -int int_solver::find_free_var_in_gomory_row(linear_combination_iterator& iter) { - unsigned j; - while(iter.next(j)) { - if (!is_base(j) && is_free(j)) - return static_cast(j); - } - iter.reset(); - return -1; -} - -lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex, unsigned j) { - lia_move ret; - linear_combination_iterator* iter = m_lar_solver->get_iterator_on_row(row_of_basic_column(j)); - int free_j = find_free_var_in_gomory_row(*iter); - if (free_j != -1) { - ret = create_branch_on_column(j, t, k, true); - } else if (!is_gomory_cut_target(*iter)) { - ret = create_branch_on_column(j, t, k, false); - } else { - ret = mk_gomory_cut(t, k, ex, j, *iter); - } - delete iter; - return ret; -} - - -unsigned int_solver::row_of_basic_column(unsigned j) const { - return m_lar_solver->m_mpq_lar_core_solver.m_r_heading[j]; -} - -template -void int_solver::fill_cut_solver(cut_solver & cs) { - for (lar_base_constraint * c : m_lar_solver->constraints()) - fill_cut_solver_for_constraint(c, cs); -} - -template -void int_solver::fill_cut_solver_for_constraint(const lar_base_constraint* c, cut_solver & cs) { - vector> coeffs; - T rs; - get_int_coeffs_from_constraint(c, coeffs, rs); - cs.add_ineq(coeffs, rs); -} - - -// it produces an inequality coeff*x <= rs -template -void int_solver::get_int_coeffs_from_constraint(const lar_base_constraint* c, vector>& coeffs, T & rs) { - lp_assert(c->m_kind != EQ); // it is not implemented, we need to create two inequalities in this case - int sign = ((int)c->m_kind > 0) ? -1 : 1; - vector> lhs = c->get_left_side_coefficients(); - T den = denominator(c->m_right_side); - for (auto & kv : lhs) { - den = lcm(den, denominator(kv.first)); - } - lp_assert(den > 0); - for (auto& kv : lhs) { - coeffs.push_back(std::make_pair(den * kv.first * sign, kv.second)); - } - rs = den * c->m_right_side * sign; - if (kind_is_strict(c->m_kind)) - rs--; -} - - -// this will allow to enable and disable tracking of the pivot rows -struct pivoted_rows_tracking_control { - lar_solver * m_lar_solver; - bool m_track_pivoted_rows; - pivoted_rows_tracking_control(lar_solver* ls) : - m_lar_solver(ls), - m_track_pivoted_rows(ls->get_track_pivoted_rows()) - { - TRACE("pivoted_rows", tout << "pivoted rows = " << ls->m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows->size() << std::endl;); - m_lar_solver->set_track_pivoted_rows(false); - } - ~pivoted_rows_tracking_control() { - TRACE("pivoted_rows", tout << "pivoted rows = " << m_lar_solver->m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows->size() << std::endl;); - m_lar_solver->set_track_pivoted_rows(m_track_pivoted_rows); - } -}; - -lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { - init_check_data(); - lp_assert(inf_int_set_is_correct()); - // it is mostly a reimplementation of - // final_check_status theory_arith::check_int_feasibility() - // from theory_arith_int.h - if (!has_inf_int()) - return lia_move::ok; - if (settings().m_run_gcd_test) - if (!gcd_test(ex)) - return lia_move::conflict; - pivoted_rows_tracking_control pc(m_lar_solver); - /* if (m_params.m_arith_euclidean_solver) apply_euclidean_solver(); */ - //m_lar_solver->pivot_fixed_vars_from_basis(); - patch_int_infeasible_nbasic_columns(); - if (!has_inf_int()) - return lia_move::ok; - - // lp_assert(non_basic_columns_are_at_bounds()); - TRACE("gomory_cut", tout << m_branch_cut_counter+1 << ", " << settings().m_int_branch_cut_gomory_threshold << std::endl;); - if (++m_branch_cut_counter > 0) { // testing cut_solver - cut_solver cs; - fill_cut_solver(cs); - } else - if ((++m_branch_cut_counter) % settings().m_int_branch_cut_gomory_threshold == 0) { - if (move_non_basic_columns_to_bounds()) { - lp_status st = m_lar_solver->find_feasible_solution(); - lp_assert(non_basic_columns_are_at_bounds()); - if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { - TRACE("arith_int", tout << "give_up\n";); - return lia_move::give_up; - } - } - int j = find_inf_int_base_column(); - if (j == -1) return lia_move::ok; - TRACE("arith_int", tout << "j = " << j << " does not have an integer assignment: " << get_value(j) << "\n";); - return proceed_with_gomory_cut(t, k, ex, j); - } - return create_branch_on_column(find_inf_int_base_column(), t, k, false); -} - -bool int_solver::move_non_basic_column_to_bounds(unsigned j) { - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - auto & val = lcs.m_r_x[j]; - switch (lcs.m_column_types()[j]) { - case column_type::boxed: - if (val != lcs.m_r_low_bounds()[j] && val != lcs.m_r_upper_bounds()[j]) { - if (random() % 2 == 0) - set_value_for_nbasic_column(j, lcs.m_r_low_bounds()[j]); - else - set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); - return true; - } - break; - case column_type::low_bound: - if (val != lcs.m_r_low_bounds()[j]) { - set_value_for_nbasic_column(j, lcs.m_r_low_bounds()[j]); - return true; - } - break; - case column_type::upper_bound: - if (val != lcs.m_r_upper_bounds()[j]) { - set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); - return true; - } - break; - default: - if (is_int(j) && !val.is_int()) { - set_value_for_nbasic_column(j, impq(floor(val))); - return true; - } - break; - } - return false; -} - -bool int_solver::move_non_basic_columns_to_bounds() { - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - bool change = false; - for (unsigned j : lcs.m_r_nbasis) { - if (move_non_basic_column_to_bounds(j)) - change = true; - } - return change; -} - -void int_solver::set_value_for_nbasic_column_ignore_old_values(unsigned j, const impq & new_val) { - lp_assert(!is_base(j)); - auto & x = m_lar_solver->m_mpq_lar_core_solver.m_r_x[j]; - auto delta = new_val - x; - x = new_val; - update_column_in_int_inf_set(j); - m_lar_solver->change_basic_columns_dependend_on_a_given_nb_column(j, delta); -} - - -void int_solver::set_value_for_nbasic_column(unsigned j, const impq & new_val) { - lp_assert(!is_base(j)); - auto & x = m_lar_solver->m_mpq_lar_core_solver.m_r_x[j]; - if (m_lar_solver->has_int_var() && !m_old_values_set.contains(j)) { - m_old_values_set.insert(j); - m_old_values_data[j] = x; - } - auto delta = new_val - x; - x = new_val; - update_column_in_int_inf_set(j); - m_lar_solver->change_basic_columns_dependend_on_a_given_nb_column(j, delta); -} - -void int_solver::patch_int_infeasible_non_basic_column(unsigned j) { - if (!is_int(j)) return; - bool inf_l, inf_u; - impq l, u; - mpq m; - if (!get_value(j).is_int() || !get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m)) { - move_non_basic_column_to_bounds(j); - return; - } - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - impq & val = lcs.m_r_x[j]; - bool val_is_int = val.is_int(); - bool m_is_one = m.is_one(); - if (m.is_one() && val_is_int) - return; - // check whether value of j is already a multiple of m. - if (val_is_int && (val.x / m).is_int()) - return; - TRACE("patch_int", - tout << "TARGET j" << j << " -> ["; - if (inf_l) tout << "-oo"; else tout << l; - tout << ", "; - if (inf_u) tout << "oo"; else tout << u; - tout << "]"; - tout << ", m: " << m << ", val: " << val << ", is_int: " << m_lar_solver->column_is_int(j) << "\n";); - if (!inf_l) { - l = m_is_one ? ceil(l) : m * ceil(l / m); - if (inf_u || l <= u) { - TRACE("patch_int", - tout << "patching with l: " << l << '\n';); - - set_value_for_nbasic_column(j, l); - } - else { - TRACE("patch_int", - tout << "not patching " << l << "\n";); - } - } - else if (!inf_u) { - u = m_is_one ? floor(u) : m * floor(u / m); - set_value_for_nbasic_column(j, u); - TRACE("patch_int", - tout << "patching with u: " << u << '\n';); - } - else { - set_value_for_nbasic_column(j, impq(0)); - TRACE("patch_int", - tout << "patching with 0\n";); - } -} -void int_solver::patch_int_infeasible_nbasic_columns() { - lp_assert(is_feasible()); - for (unsigned j : m_lar_solver->m_mpq_lar_core_solver.m_r_nbasis) { - patch_int_infeasible_non_basic_column(j); - if (!is_feasible()) - break; - } - if (!is_feasible()) { - move_non_basic_columns_to_bounds(); - m_lar_solver->find_feasible_solution(); - } - lp_assert(is_feasible() && inf_int_set_is_correct()); -} - -mpq get_denominators_lcm(iterator_on_row &it) { - mpq r(1); - mpq a; - unsigned j; - while (it.next(a, j)) { - r = lcm(r, denominator(a)); - } - return r; -} - -bool int_solver::gcd_test_for_row(static_matrix> & A, unsigned i, explanation & ex) { - iterator_on_row it(A.m_rows[i]); - mpq lcm_den = get_denominators_lcm(it); - mpq consts(0); - mpq gcds(0); - mpq least_coeff(0); - bool least_coeff_is_bounded = false; - mpq a; - unsigned j; - while (it.next(a, j)) { - if (m_lar_solver->column_is_fixed(j)) { - mpq aux = lcm_den * a; - consts += aux * m_lar_solver->column_low_bound(j).x; - } - else if (m_lar_solver->column_is_real(j)) { - return true; - } - else if (gcds.is_zero()) { - gcds = abs(lcm_den * a); - least_coeff = gcds; - least_coeff_is_bounded = m_lar_solver->column_is_bounded(j); - } - else { - mpq aux = abs(lcm_den * a); - gcds = gcd(gcds, aux); - if (aux < least_coeff) { - least_coeff = aux; - least_coeff_is_bounded = m_lar_solver->column_is_bounded(j); - } - else if (least_coeff_is_bounded && aux == least_coeff) { - least_coeff_is_bounded = m_lar_solver->column_is_bounded(j); - } - } - SASSERT(gcds.is_int()); - SASSERT(least_coeff.is_int()); - TRACE("gcd_test_bug", tout << "coeff: " << a << ", gcds: " << gcds - << " least_coeff: " << least_coeff << " consts: " << consts << "\n";); - - } - - if (gcds.is_zero()) { - // All variables are fixed. - // This theory guarantees that the assignment satisfies each row, and - // fixed integer variables are assigned to integer values. - return true; - } - - if (!(consts / gcds).is_int()) - fill_explanation_from_fixed_columns(it, ex); - - if (least_coeff.is_one() && !least_coeff_is_bounded) { - SASSERT(gcds.is_one()); - return true; - } - - if (least_coeff_is_bounded) { - return ext_gcd_test(it, least_coeff, lcm_den, consts, ex); - } - return true; -} - -void int_solver::add_to_explanation_from_fixed_or_boxed_column(unsigned j, explanation & ex) { - constraint_index lc, uc; - m_lar_solver->get_bound_constraint_witnesses_for_column(j, lc, uc); - ex.m_explanation.push_back(std::make_pair(mpq(1), lc)); - ex.m_explanation.push_back(std::make_pair(mpq(1), uc)); -} -void int_solver::fill_explanation_from_fixed_columns(iterator_on_row & it, explanation & ex) { - it.reset(); - unsigned j; - while (it.next(j)) { - if (!m_lar_solver->column_is_fixed(j)) - continue; - add_to_explanation_from_fixed_or_boxed_column(j, ex); - } -} - -bool int_solver::gcd_test(explanation & ex) { - auto & A = m_lar_solver->A_r(); // getting the matrix - for (unsigned i = 0; i < A.row_count(); i++) - if (!gcd_test_for_row(A, i, ex)) { - std::cout << "false from gcd_test\n" ; - return false; - } - - return true; -} - -bool int_solver::ext_gcd_test(iterator_on_row & it, - mpq const & least_coeff, - mpq const & lcm_den, - mpq const & consts, explanation& ex) { - mpq gcds(0); - mpq l(consts); - mpq u(consts); - - it.reset(); - mpq a; - unsigned j; - while (it.next(a, j)) { - if (m_lar_solver->column_is_fixed(j)) - continue; - SASSERT(!m_lar_solver->column_is_real(j)); - mpq ncoeff = lcm_den * a; - SASSERT(ncoeff.is_int()); - mpq abs_ncoeff = abs(ncoeff); - if (abs_ncoeff == least_coeff) { - SASSERT(m_lar_solver->column_is_bounded(j)); - if (ncoeff.is_pos()) { - // l += ncoeff * m_lar_solver->column_low_bound(j).x; - l.addmul(ncoeff, m_lar_solver->column_low_bound(j).x); - // u += ncoeff * m_lar_solver->column_upper_bound(j).x; - u.addmul(ncoeff, m_lar_solver->column_upper_bound(j).x); - } - else { - // l += ncoeff * upper_bound(j).get_rational(); - l.addmul(ncoeff, m_lar_solver->column_upper_bound(j).x); - // u += ncoeff * low_bound(j).get_rational(); - u.addmul(ncoeff, m_lar_solver->column_low_bound(j).x); - } - add_to_explanation_from_fixed_or_boxed_column(j, ex); - } - else if (gcds.is_zero()) { - gcds = abs_ncoeff; - } - else { - gcds = gcd(gcds, abs_ncoeff); - } - SASSERT(gcds.is_int()); - } - - if (gcds.is_zero()) { - return true; - } - - mpq l1 = ceil(l/gcds); - mpq u1 = floor(u/gcds); - - if (u1 < l1) { - fill_explanation_from_fixed_columns(it, ex); - return false; - } - - return true; - -} - -linear_combination_iterator * int_solver::get_column_iterator(unsigned j) { - if (m_lar_solver->use_tableau()) - return new iterator_on_column(m_lar_solver->A_r().m_columns[j], m_lar_solver->A_r()); - return new iterator_on_indexed_vector(m_lar_solver->get_column_in_lu_mode(j)); -} - - -int_solver::int_solver(lar_solver* lar_slv) : - m_lar_solver(lar_slv), - m_branch_cut_counter(0) { - lp_assert(m_old_values_set.size() == 0); - m_old_values_set.resize(lar_slv->A_r().column_count()); - m_old_values_data.resize(lar_slv->A_r().column_count(), zero_of_type()); - m_lar_solver->set_int_solver(this); -} - -bool int_solver::has_low(unsigned j) const { - switch (m_lar_solver->m_mpq_lar_core_solver.m_column_types()[j]) { - case column_type::fixed: - case column_type::boxed: - case column_type::low_bound: - return true; - default: - return false; - } -} - -bool int_solver::has_upper(unsigned j) const { - switch (m_lar_solver->m_mpq_lar_core_solver.m_column_types()[j]) { - case column_type::fixed: - case column_type::boxed: - case column_type::upper_bound: - return true; - default: - return false; - } -} - - -void set_lower(impq & l, - bool & inf_l, - impq const & v ) { - if (inf_l || v > l) { - l = v; - inf_l = false; - } -} - -void set_upper(impq & u, - bool & inf_u, - impq const & v) { - if (inf_u || v < u) { - u = v; - inf_u = false; - } -} - -bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m) { - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - if (lcs.m_r_heading[j] >= 0) // the basic var - return false; - - impq const & xj = get_value(j); - linear_combination_iterator *it = get_column_iterator(j); - - inf_l = true; - inf_u = true; - l = u = zero_of_type(); - m = mpq(1); - - if (has_low(j)) { - set_lower(l, inf_l, low_bound(j)); - } - if (has_upper(j)) { - set_upper(u, inf_u, upper_bound(j)); - } - - mpq a; // the coefficient in the column - unsigned row_index; - while (it->next(a, row_index)) { - unsigned i = lcs.m_r_basis[row_index]; - impq const & xi = get_value(i); - if (is_int(i) && is_int(j) && !a.is_int()) - m = lcm(m, denominator(a)); - if (a.is_neg()) { - if (has_low(i)) - set_lower(l, inf_l, xj + (xi - lcs.m_r_low_bounds()[i]) / a); - - if (has_upper(i)) - set_upper(u, inf_u, xj + (xi - lcs.m_r_upper_bounds()[i]) / a); - } - else { - if (has_upper(i)) - set_lower(l, inf_l, xj + (xi - lcs.m_r_upper_bounds()[i]) / a); - if (has_low(i)) - set_upper(u, inf_u, xj + (xi - lcs.m_r_low_bounds()[i]) / a); - } - if (!inf_l && !inf_u && l == u) break;; - } - - delete it; - TRACE("freedom_interval", - tout << "freedom variable for:\n"; - tout << m_lar_solver->get_column_name(j); - tout << "["; - if (inf_l) tout << "-oo"; else tout << l; - tout << "; "; - if (inf_u) tout << "oo"; else tout << u; - tout << "]\n"; - tout << "val = " << get_value(j) << "\n"; - ); - lp_assert(inf_l || l <= get_value(j)); - lp_assert(inf_u || u >= get_value(j)); - return true; - -} - -bool int_solver::is_int(unsigned j) const { - return m_lar_solver->column_is_int(j); -} - -bool int_solver::is_real(unsigned j) const { - return !is_int(j); -} - -bool int_solver::value_is_int(unsigned j) const { - return m_lar_solver->column_value_is_int(j); -} - - - -bool int_solver::is_feasible() const { - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - lp_assert( - lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis() == - lcs.m_r_solver.current_x_is_feasible()); - return lcs.m_r_solver.current_x_is_feasible(); -} -const impq & int_solver::get_value(unsigned j) const { - return m_lar_solver->m_mpq_lar_core_solver.m_r_x[j]; -} - -void int_solver::display_column(std::ostream & out, unsigned j) const { - m_lar_solver->m_mpq_lar_core_solver.m_r_solver.print_column_info(j, out); -} - -bool int_solver::inf_int_set_is_correct() const { - for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) { - if (inf_int_set().contains(j) != (is_int(j) && (!value_is_int(j)))) { - TRACE("arith_int", tout << "j= " << j << " inf_int_set().contains(j) = " << inf_int_set().contains(j) << ", is_int(j) = " << is_int(j) << "\nvalue_is_int(j) = " << value_is_int(j) << ", val = " << get_value(j) << std::endl;); - return false; - } - } - return true; -} - -bool int_solver::column_is_int_inf(unsigned j) const { - return is_int(j) && (!value_is_int(j)); -} - -void int_solver::update_column_in_int_inf_set(unsigned j) { - if (is_int(j) && (!value_is_int(j))) - inf_int_set().insert(j); - else - inf_int_set().erase(j); -} - -bool int_solver::is_base(unsigned j) const { - return m_lar_solver->m_mpq_lar_core_solver.m_r_heading[j] >= 0; -} - -bool int_solver::is_boxed(unsigned j) const { - return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed; -} - -bool int_solver::is_fixed(unsigned j) const { - return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::fixed; -} - -bool int_solver::is_free(unsigned j) const { - return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::free_column; -} - -bool int_solver::at_bound(unsigned j) const { - auto & mpq_solver = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; - switch (mpq_solver.m_column_types[j] ) { - case column_type::fixed: - case column_type::boxed: - return - mpq_solver.m_low_bounds[j] == get_value(j) || - mpq_solver.m_upper_bounds[j] == get_value(j); - case column_type::low_bound: - return mpq_solver.m_low_bounds[j] == get_value(j); - case column_type::upper_bound: - return mpq_solver.m_upper_bounds[j] == get_value(j); - default: - return false; - } -} - -bool int_solver::at_low(unsigned j) const { - auto & mpq_solver = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; - switch (mpq_solver.m_column_types[j] ) { - case column_type::fixed: - case column_type::boxed: - case column_type::low_bound: - return mpq_solver.m_low_bounds[j] == get_value(j); - default: - return false; - } -} - -bool int_solver::at_upper(unsigned j) const { - auto & mpq_solver = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; - switch (mpq_solver.m_column_types[j] ) { - case column_type::fixed: - case column_type::boxed: - case column_type::upper_bound: - return mpq_solver.m_upper_bounds[j] == get_value(j); - default: - return false; - } -} - - - -lp_settings& int_solver::settings() { - return m_lar_solver->settings(); -} - -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; - auto it = m_lar_solver->get_iterator_on_row(row_index); - mpq a; - unsigned j; - while (it->next(a, j)) { - if (numeric_traits::is_pos(a)) - out << "+"; - out << a << rslv.column_name(j) << " "; - } - - it->reset(); - while(it->next(j)) { - rslv.print_column_bound_info(j, out); - } - rslv.print_column_bound_info(rslv.m_basis[row_index], out); - delete it; -} - -unsigned int_solver::random() { - return m_lar_solver->get_core_solver().settings().random_next(); -} - -bool int_solver::shift_var(unsigned j, unsigned range) { - if (is_fixed(j) || is_base(j)) - return false; - - bool inf_l, inf_u; - impq l, u; - mpq m; - get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m); - if (inf_l && inf_u) { - impq new_val = impq(random() % (range + 1)); - set_value_for_nbasic_column_ignore_old_values(j, new_val); - return true; - } - if (is_int(j)) { - if (!inf_l) { - l = ceil(l); - if (!m.is_one()) - l = m*ceil(l/m); - } - if (!inf_u) { - u = floor(u); - if (!m.is_one()) - u = m*floor(u/m); - } - } - if (!inf_l && !inf_u && l >= u) - return false; - if (inf_u) { - SASSERT(!inf_l); - impq delta = impq(random() % (range + 1)); - impq new_val = l + m*delta; - set_value_for_nbasic_column_ignore_old_values(j, new_val); - return true; - } - if (inf_l) { - SASSERT(!inf_u); - impq delta = impq(random() % (range + 1)); - impq new_val = u - m*delta; - set_value_for_nbasic_column_ignore_old_values(j, new_val); - return true; - } - if (!is_int(j)) { - SASSERT(!inf_l && !inf_u); - mpq delta = mpq(random() % (range + 1)); - impq new_val = l + ((delta * (u - l)) / mpq(range)); - set_value_for_nbasic_column_ignore_old_values(j, new_val); - return true; - } - else { - mpq r = (u.x - l.x) / m; - if (r < mpq(range)) - range = static_cast(r.get_uint64()); - impq new_val = l + m * (impq(random() % (range + 1))); - set_value_for_nbasic_column_ignore_old_values(j, new_val); - return true; - } -} - -bool int_solver::non_basic_columns_are_at_bounds() const { - auto & lcs = m_lar_solver->m_mpq_lar_core_solver; - for (unsigned j :lcs.m_r_nbasis) { - auto & val = lcs.m_r_x[j]; - switch (lcs.m_column_types()[j]) { - case column_type::boxed: - if (val != lcs.m_r_low_bounds()[j] && val != lcs.m_r_upper_bounds()[j]) - return false; - break; - case column_type::low_bound: - if (val != lcs.m_r_low_bounds()[j]) - return false; - break; - case column_type::upper_bound: - if (val != lcs.m_r_upper_bounds()[j]) - return false; - break; - default: - if (is_int(j) && !val.is_int()) { - return false; - } - } - } - return true; -} - -const impq& int_solver::low_bound(unsigned j) const { - return m_lar_solver->column_low_bound(j); -} - -lia_move int_solver::create_branch_on_column(int j, lar_term& t, mpq& k, bool free_column) const { - lp_assert(t.is_empty()); - lp_assert(j != -1); - t.add_monomial(mpq(1), m_lar_solver->adjust_column_index_to_term_index(j)); - k = free_column? mpq(0) : floor(get_value(j)); - TRACE("arith_int", tout << "branching v" << j << " = " << get_value(j) << "\n"; - display_column(tout, j); - tout << "k = " << k << std::endl; - ); - return lia_move::branch; - -} - -const impq& int_solver::upper_bound(unsigned j) const { - return m_lar_solver->column_upper_bound(j); -} -void int_solver::display_inf_or_int_inf_columns(std::ostream & out) const { - out << "int inf\n"; - for (unsigned j : m_lar_solver->m_inf_int_set.m_index) { - display_column(out, j); - } - out << "regular inf\n"; - for (unsigned j : m_lar_solver->m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { - display_column(out, j); - } -} -} diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp deleted file mode 100644 index 6846717af..000000000 --- a/src/util/lp/lar_solver.cpp +++ /dev/null @@ -1,2089 +0,0 @@ -#include "util/lp/lar_solver.h" -/* - Copyright (c) 2017 Microsoft Corporation - Author: Nikolaj Bjorner, Lev Nachmanson -*/ - -namespace lp { - -unsigned lar_solver::constraint_count() const { - return m_constraints.size(); -} -const lar_base_constraint& lar_solver::get_constraint(unsigned ci) const { - return *(m_constraints[ci]); -} - -////////////////// methods //////////////////////////////// -static_matrix> & lar_solver::A_r() { return m_mpq_lar_core_solver.m_r_A;} -static_matrix> const & lar_solver::A_r() const { return m_mpq_lar_core_solver.m_r_A;} -static_matrix & lar_solver::A_d() { return m_mpq_lar_core_solver.m_d_A;} -static_matrix const & lar_solver::A_d() const { return m_mpq_lar_core_solver.m_d_A;} - -lp_settings & lar_solver::settings() { return m_settings;} - -lp_settings const & lar_solver::settings() const { return m_settings;} - -void clear() {lp_assert(false); // not implemented -} - - -lar_solver::lar_solver() : m_status(lp_status::OPTIMAL), - m_infeasible_column_index(-1), - m_terms_start_index(1000000), - m_mpq_lar_core_solver(m_settings, *this), - m_tracker_of_x_change([&](unsigned j) { - call_assignment_tracker(j); - } - ), - m_int_solver(nullptr) -{} - -void lar_solver::set_track_pivoted_rows(bool v) { - m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; -} - -bool lar_solver::get_track_pivoted_rows() const { - return m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows != nullptr; -} - - -lar_solver::~lar_solver(){ - for (auto c : m_constraints) - delete c; - for (auto t : m_terms) - delete t; -} - -bool lar_solver::is_term(var_index j) const { - return j >= m_terms_start_index && j - m_terms_start_index < m_terms.size(); -} - -unsigned lar_solver::adjust_term_index(unsigned j) const { - lp_assert(is_term(j)); - return j - m_terms_start_index; -} - - -bool lar_solver::use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } - -bool lar_solver::sizes_are_correct() const { - lp_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); - lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); - lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); - return true; -} - - -void lar_solver::print_implied_bound(const implied_bound& be, std::ostream & out) const { - out << "implied bound\n"; - unsigned v = be.m_j; - if (is_term(v)) { - out << "it is a term number " << be.m_j << std::endl; - print_term(*m_terms[be.m_j - m_terms_start_index], out); - } - else { - out << get_column_name(v); - } - out << " " << lconstraint_kind_string(be.kind()) << " " << be.m_bound << std::endl; - out << "end of implied bound" << std::endl; -} - -bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { - std::unordered_map coeff_map; - auto rs_of_evidence = zero_of_type(); - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto & it : explanation) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - const auto & constr = *m_constraints[con_ind]; - lconstraint_kind kind = coeff.is_pos() ? constr.m_kind : flip_kind(constr.m_kind); - register_in_map(coeff_map, constr, coeff); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) n_of_G++; - else if (kind == LE || kind == LT) n_of_L++; - rs_of_evidence += coeff*constr.m_right_side; - } - lp_assert(n_of_G == 0 || n_of_L == 0); - lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - kind = static_cast((static_cast(kind) / 2)); - - if (!is_term(be.m_j)) { - if (coeff_map.size() != 1) - return false; - auto it = coeff_map.find(be.m_j); - if (it == coeff_map.end()) return false; - mpq ratio = it->second; - if (ratio < zero_of_type()) { - kind = static_cast(-kind); - } - rs_of_evidence /= ratio; - } else { - const lar_term * t = m_terms[adjust_term_index(be.m_j)]; - const auto first_coeff = *t->m_coeffs.begin(); - unsigned j = first_coeff.first; - auto it = coeff_map.find(j); - if (it == coeff_map.end()) - return false; - mpq ratio = it->second / first_coeff.second; - for (auto & p : t->m_coeffs) { - it = coeff_map.find(p.first); - if (it == coeff_map.end()) - return false; - if (p.second * ratio != it->second) - return false; - } - if (ratio < zero_of_type()) { - kind = static_cast(-kind); - } - rs_of_evidence /= ratio; - rs_of_evidence += t->m_v * ratio; - } - - return kind == be.kind() && rs_of_evidence == be.m_bound; -} - - -void lar_solver::analyze_new_bounds_on_row( - unsigned row_index, - bound_propagator & bp) { - lp_assert(!use_tableau()); - iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); - - bound_analyzer_on_row ra_pos(it, - zero_of_type>(), - row_index, - bp - ); - ra_pos.analyze(); -} - -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) - return; - iterator_on_row it(A_r().m_rows[row_index]); - lp_assert(use_tableau()); - bound_analyzer_on_row::analyze_row(it, - zero_of_type>(), - row_index, - bp - ); -} - - -void lar_solver::substitute_basis_var_in_terms_for_row(unsigned i) { - // todo : create a map from term basic vars to the rows where they are used - unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; - for (unsigned k = 0; k < m_terms.size(); k++) { - if (term_is_used_as_row(k)) - continue; - if (!m_terms[k]->contains(basis_j)) - continue; - m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); - } -} - -void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { - if(use_tableau()) { - analyze_new_bounds_on_row_tableau(i, bp); - } else { - m_mpq_lar_core_solver.calculate_pivot_row(i); - substitute_basis_var_in_terms_for_row(i); - analyze_new_bounds_on_row(i, bp); - } -} - - -linear_combination_iterator * lar_solver::create_new_iter_from_term(unsigned term_index) const { - lp_assert(false); // not implemented - return nullptr; - // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); -} - -unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const { - unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; - return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; -} - -void lar_solver::propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { - lp_assert(false); // not implemented -} - - -void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp) { - unsigned i = ib.m_row_or_term_index; - int bound_sign = ib.m_is_low_bound? 1: -1; - int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; - unsigned m_j = ib.m_j; - if (is_term(m_j)) { - auto it = m_ext_vars_to_columns.find(m_j); - lp_assert(it != m_ext_vars_to_columns.end()); - m_j = it->second.ext_j(); - } - for (auto const& r : A_r().m_rows[i]) { - unsigned j = r.m_j; - mpq const& a = r.get_val(); - if (j == m_j) continue; - if (is_term(j)) { - auto it = m_ext_vars_to_columns.find(j); - lp_assert(it != m_ext_vars_to_columns.end()); - j = it->second.ext_j(); - } - int a_sign = is_pos(a)? 1: -1; - int sign = j_sign * a_sign; - const ul_pair & ul = m_columns_to_ul_pairs[j]; - auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); - lp_assert(is_valid(witness)); - bp.consume(a, witness); - } - // lp_assert(implied_bound_is_correctly_explained(ib, explanation)); -} - - -bool lar_solver::term_is_used_as_row(unsigned term) const { - lp_assert(is_term(term)); - return contains(m_ext_vars_to_columns, term); -} - -void lar_solver::propagate_bounds_on_terms(bound_propagator & bp) { - for (unsigned i = 0; i < m_terms.size(); i++) { - if (term_is_used_as_row(i + m_terms_start_index)) - continue; // this term is used a left side of a constraint, - // it was processed as a touched row if needed - propagate_bounds_on_a_term(*m_terms[i], bp, i); - } -} - - -// goes over touched rows and tries to induce bounds -void lar_solver::propagate_bounds_for_touched_rows(bound_propagator & bp) { - if (!use_tableau()) - return; // todo: consider to remove the restriction - - for (unsigned i : m_rows_with_changed_bounds.m_index) { - calculate_implied_bounds_for_row(i, bp); - } - m_rows_with_changed_bounds.clear(); - if (!use_tableau()) { - propagate_bounds_on_terms(bp); - } -} - -lp_status lar_solver::get_status() const { return m_status;} - -void lar_solver::set_status(lp_status s) {m_status = s;} - -bool lar_solver::has_int_var() const { - return m_mpq_lar_core_solver.m_r_solver.m_tracker_of_x_change != nullptr; -} - -lp_status lar_solver::find_feasible_solution() { - lp_assert(inf_int_set_is_correct()); - m_settings.st().m_make_feasible++; - if (A_r().column_count() > m_settings.st().m_max_cols) - m_settings.st().m_max_cols = A_r().column_count(); - if (A_r().row_count() > m_settings.st().m_max_rows) - m_settings.st().m_max_rows = A_r().row_count(); - if (strategy_is_undecided()) - decide_on_strategy_and_adjust_initial_state(); - - if (has_int_var()) { - m_inf_int_set.resize(A_r().column_count()); - } - - m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; - auto ret = solve(); - TRACE("intinf", m_int_solver->display_inf_or_int_inf_columns(tout);); - lp_assert(inf_int_set_is_correct()); - return ret; -} - -lp_status lar_solver::solve() { - lp_assert(inf_int_set_is_correct()); - if (m_status == lp_status::INFEASIBLE) { - return m_status; - } - solve_with_core_solver(); - if (m_status != lp_status::INFEASIBLE) { - if (m_settings.bound_propagation()) - detect_rows_with_changed_bounds(); - } - - m_columns_with_changed_bound.clear(); - lp_assert(inf_int_set_is_correct()); - return m_status; -} - -void lar_solver::fill_explanation_from_infeasible_column(vector> & evidence) const{ - - // this is the case when the lower bound is in conflict with the upper one - const ul_pair & ul = m_columns_to_ul_pairs[m_infeasible_column_index]; - evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); - evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); -} - - -unsigned lar_solver::get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } -vector lar_solver::get_list_of_all_var_indices() const { - vector ret; - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) - ret.push_back(j); - return ret; -} -void lar_solver::push() { - m_simplex_strategy = m_settings.simplex_strategy(); - m_simplex_strategy.push(); - m_columns_to_ul_pairs.push(); - m_infeasible_column_index.push(); - m_mpq_lar_core_solver.push(); - m_term_count = m_terms.size(); - m_term_count.push(); - m_constraint_count = m_constraints.size(); - m_constraint_count.push(); -} - -void lar_solver::clean_popped_elements(unsigned n, int_set& set) { - vector to_remove; - for (unsigned j: set.m_index) - if (j >= n) - to_remove.push_back(j); - for (unsigned j : to_remove) - set.erase(j); -} - -void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { - clean_popped_elements(n, set); - set.resize(n); -} - - -void lar_solver::pop(unsigned k) { - TRACE("arith_int", tout << "pop" << std::endl;); - lp_assert(inf_int_set_is_correct()); - TRACE("lar_solver", tout << "k = " << k << std::endl;); - - int n_was = static_cast(m_ext_vars_to_columns.size()); - m_infeasible_column_index.pop(k); - unsigned n = m_columns_to_ul_pairs.peek_size(k); - for (unsigned j = n_was; j-- > n;) - m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); - m_columns_to_ext_vars_or_term_indices.resize(n); - TRACE("arith_int", tout << "pop" << std::endl;); - if (m_settings.use_tableau()) { - pop_tableau(); - } - lp_assert(A_r().column_count() == n); - m_columns_to_ul_pairs.pop(k); - - m_mpq_lar_core_solver.pop(k); - clean_popped_elements(n, m_columns_with_changed_bound); - clean_popped_elements(n, m_inf_int_set); - unsigned m = A_r().row_count(); - lp_assert(inf_int_set_is_correct()); - clean_popped_elements(m, m_rows_with_changed_bounds); - lp_assert(inf_int_set_is_correct()); - clean_inf_set_of_r_solver_after_pop(); - lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || - (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - - - lp_assert(ax_is_correct()); - lp_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); - m_constraint_count.pop(k); - for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) - delete m_constraints[i]; - - m_constraints.resize(m_constraint_count); - m_term_count.pop(k); - for (unsigned i = m_term_count; i < m_terms.size(); i++) { - delete m_terms[i]; - } - m_terms.resize(m_term_count); - m_simplex_strategy.pop(k); - m_settings.simplex_strategy() = m_simplex_strategy; - lp_assert(sizes_are_correct()); - lp_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - m_status = m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()? lp_status::OPTIMAL: lp_status::UNKNOWN; - -} - -vector lar_solver::get_all_constraint_indices() const { - vector ret; - constraint_index i = 0; - while ( i < m_constraints.size()) - ret.push_back(i++); - return ret; -} - -bool lar_solver::maximize_term_on_tableau(const vector> & term, - impq &term_max) { - if (settings().simplex_strategy() == simplex_strategy_enum::undecided) - decide_on_strategy_and_adjust_initial_state(); - - m_mpq_lar_core_solver.solve(); - if (m_mpq_lar_core_solver.m_r_solver.get_status() == lp_status::UNBOUNDED) - return false; - - term_max = 0; - for (auto & p : term) - term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second]; - - return true; -} - -bool lar_solver::costs_are_zeros_for_r_solver() const { - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { - lp_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); - } - return true; -} -bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const { - for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { - lp_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); - } - return true; -} - -void lar_solver::set_costs_to_zero(const vector> & term) { - auto & rslv = m_mpq_lar_core_solver.m_r_solver; - auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now - lp_assert(jset.m_index.size()==0); - - for (auto & p : term) { - unsigned j = p.second; - rslv.m_costs[j] = zero_of_type(); - int i = rslv.m_basis_heading[j]; - if (i < 0) - jset.insert(j); - else { - for (auto & rc : A_r().m_rows[i]) - jset.insert(rc.m_j); - } - } - - for (unsigned j : jset.m_index) - rslv.m_d[j] = zero_of_type(); - - jset.clear(); - - lp_assert(reduced_costs_are_zeroes_for_r_solver()); - lp_assert(costs_are_zeros_for_r_solver()); -} - -void lar_solver::prepare_costs_for_r_solver(const vector> & term) { - - auto & rslv = m_mpq_lar_core_solver.m_r_solver; - rslv.m_using_infeas_costs = false; - lp_assert(costs_are_zeros_for_r_solver()); - lp_assert(reduced_costs_are_zeroes_for_r_solver()); - rslv.m_costs.resize(A_r().column_count(), zero_of_type()); - for (auto & p : term) { - unsigned j = p.second; - rslv.m_costs[j] = p.first; - if (rslv.m_basis_heading[j] < 0) - rslv.m_d[j] += p.first; - else - rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); - } - lp_assert(rslv.reduced_costs_are_correct_tableau()); -} - -bool lar_solver::maximize_term_on_corrected_r_solver(const vector> & term, - impq &term_max) { - settings().backup_costs = false; - switch (settings().simplex_strategy()) { - case simplex_strategy_enum::tableau_rows: - prepare_costs_for_r_solver(term); - settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; - { - bool ret = maximize_term_on_tableau(term, term_max); - settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); - return ret; - } - case simplex_strategy_enum::tableau_costs: - prepare_costs_for_r_solver(term); - { - bool ret = maximize_term_on_tableau(term, term_max); - set_costs_to_zero(term); - m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); - return ret; - } - - case simplex_strategy_enum::lu: - lp_assert(false); // not implemented - return false; - default: - lp_unreachable(); // wrong mode - } - return false; -} -// starting from a given feasible state look for the maximum of the term -// return true if found and false if unbounded -bool lar_solver::maximize_term(const vector> & term, - impq &term_max) { - lp_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); - m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; - return maximize_term_on_corrected_r_solver(term, term_max); -} - - - -const lar_term & lar_solver::get_term(unsigned j) const { - lp_assert(j >= m_terms_start_index); - return *m_terms[j - m_terms_start_index]; -} - -void lar_solver::pop_core_solver_params() { - pop_core_solver_params(1); -} - -void lar_solver::pop_core_solver_params(unsigned k) { - A_r().pop(k); - A_d().pop(k); -} - - -void lar_solver::set_upper_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_columns_to_ul_pairs[j]; - ul.upper_bound_witness() = ci; - m_columns_to_ul_pairs[j] = ul; -} - -void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) { - ul_pair ul = m_columns_to_ul_pairs[j]; - ul.low_bound_witness() = ci; - m_columns_to_ul_pairs[j] = ul; -} - -void lar_solver::register_monoid_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j) { - auto it = coeffs.find(j); - if (it == coeffs.end()) { - coeffs[j] = a; - } else { - it->second += a; - } -} - - -void lar_solver::substitute_terms_in_linear_expression(const vector>& left_side_with_terms, - vector> &left_side, mpq & free_coeff) const { - std::unordered_map coeffs; - for (auto & t : left_side_with_terms) { - unsigned j = t.second; - if (!is_term(j)) { - register_monoid_in_map(coeffs, t.first, j); - } else { - const lar_term & term = * m_terms[adjust_term_index(t.second)]; - for (auto & p : term.coeffs()){ - register_monoid_in_map(coeffs, t.first * p.second , p.first); - } - free_coeff += t.first * term.m_v; - } - } - - for (auto & p : coeffs) - left_side.push_back(std::make_pair(p.second, p.first)); -} - - -void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { - if (A_r().row_count() != m_column_buffer.data_size()) - m_column_buffer.resize(A_r().row_count()); - else - m_column_buffer.clear(); - lp_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); - - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) - m_rows_with_changed_bounds.insert(i); -} - - - -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); -} - -bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } - -bool lar_solver::use_tableau_costs() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; -} - -void lar_solver::detect_rows_of_column_with_bound_change(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column - // just mark the row at touched and exit - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); - return; - } - - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); -} - -void lar_solver::adjust_x_of_column(unsigned j) { - lp_assert(false); -} - -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]; - return is_zero(r); -} - -bool lar_solver::ax_is_correct() const { - for (unsigned i = 0; i < A_r().row_count(); i++) { - if (!row_is_correct(i)) - return false; - } - return true; -} - -bool lar_solver::tableau_with_costs() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; -} - -bool lar_solver::costs_are_used() const { - return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; -} - -void lar_solver::change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair & delta) { - lp_assert(inf_int_set_is_correct()); - 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 (tableau_with_costs()) { - m_basic_columns_with_changed_cost.insert(bj); - } - m_mpq_lar_core_solver.m_r_solver.update_x_with_delta_and_track_feasibility(bj, - A_r().get_val(c) * delta); - TRACE("change_x_del", - tout << "changed basis column " << bj << ", it is " << - ( m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj)? "feas":"inf") << std::endl;); - - } - } else { - m_column_buffer.clear(); - m_column_buffer.resize(A_r().row_count()); - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; - m_mpq_lar_core_solver.m_r_solver.update_x_with_delta_and_track_feasibility(bj, -m_column_buffer[i] * delta); - } - } - lp_assert(inf_int_set_is_correct()); -} - -void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - if (costs_are_used()) { - bool was_infeas = m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j); - m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); - if (was_infeas != m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j)) - m_basic_columns_with_changed_cost.insert(j); - } else { - m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); - } - } else { - numeric_pair delta; - if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) - change_basic_columns_dependend_on_a_given_nb_column(j, delta); - } -} - - -void lar_solver::detect_rows_with_changed_bounds_for_column(unsigned j) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); - return; - } - - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); -} - -void lar_solver::detect_rows_with_changed_bounds() { - for (auto j : m_columns_with_changed_bound.m_index) - detect_rows_with_changed_bounds_for_column(j); -} - -void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds() { - for (auto j : m_columns_with_changed_bound.m_index) - update_x_and_inf_costs_for_column_with_changed_bounds(j); -} - -void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { - for (auto j : m_columns_with_changed_bound.m_index) - update_x_and_inf_costs_for_column_with_changed_bounds(j); - - if (tableau_with_costs()) { - for (unsigned j : m_basic_columns_with_changed_cost.m_index) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lp_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } -} - - -void lar_solver::solve_with_core_solver() { - if (!use_tableau()) - add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); - if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { - add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); - } - m_mpq_lar_core_solver.prefix_r(); - if (costs_are_used()) { - m_basic_columns_with_changed_cost.clear(); - m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); - } - if (use_tableau()) - update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - else - update_x_and_inf_costs_for_columns_with_changed_bounds(); - TRACE("intinf", m_int_solver->display_inf_or_int_inf_columns(tout);); - m_mpq_lar_core_solver.solve(); - set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); - lp_assert(inf_int_set_is_correct()); - lp_assert(m_status != lp_status::OPTIMAL || all_constraints_hold()); -} - - -numeric_pair lar_solver::get_basic_var_value_from_row_directly(unsigned i) { - numeric_pair r = zero_of_type>(); - - 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 (!is_zero(x)) - r -= c.m_value * x; - } - return r; -} - -numeric_pair lar_solver::get_basic_var_value_from_row(unsigned i) { - if (settings().use_tableau()) { - return get_basic_var_value_from_row_directly(i); - } - - numeric_pair r = zero_of_type>(); - m_mpq_lar_core_solver.calculate_pivot_row(i); - for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { - lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); - r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; - } - return r; -} - -template -void lar_solver::add_last_rows_to_lu(lp_primal_core_solver & s) { - auto & f = s.m_factorization; - if (f != nullptr) { - auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); - if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { - delete f; - f = nullptr; - } else { - f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); - } - } - if (f == nullptr) { - init_factorization(f, s.m_A, s.m_basis, m_settings); - if (f->get_status() != LU_status::OK) { - delete f; - f = nullptr; - } - } - -} - -bool lar_solver::x_is_correct() const { - if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { - // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; - return false; - } - for (unsigned i = 0; i < A_r().row_count(); i++) { - numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); - if (!delta.is_zero()) { - // std::cout << "x is off ("; - // std::cout << "m_b[" << i << "] = " << m_b[i] << " "; - // std::cout << "left side = " << A().dot_product_with_row(i, m_r_solver.m_x) << ' '; - // std::cout << "delta = " << delta << ' '; - // std::cout << "iters = " << total_iterations() << ")" << std::endl; - // std::cout << "row " << i << " is off" << std::endl; - return false; - } - } - return true;; - -} - -bool lar_solver::var_is_registered(var_index vj) const { - if (vj >= m_terms_start_index) { - if (vj - m_terms_start_index >= m_terms.size()) - return false; - } else if ( vj >= A_r().column_count()) { - return false; - } - return true; -} - -unsigned lar_solver::constraint_stack_size() const { - return m_constraint_count.stack_size(); -} - -void lar_solver::fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { - 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); - for (auto & t : ls->m_coeffs) { - lp_assert(!is_zero(t.second)); - var_index j = t.first; - A.set(last_row, j, - t.second); - } - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, mpq(1)); -} - -template -void lar_solver::create_matrix_A(static_matrix & matr) { - lp_assert(false); // not implemented - /* - unsigned m = number_or_nontrivial_left_sides(); - unsigned n = m_vec_of_canonic_left_sides.size(); - if (matr.row_count() == m && matr.column_count() == n) - return; - matr.init_empty_matrix(m, n); - copy_from_mpq_matrix(matr); - */ -} - -template -void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { - matr.m_rows.resize(A_r().row_count()); - 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())); - } - } -} - - -bool lar_solver::try_to_set_fixed(column_info & ci) { - if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { - ci.set_fixed_value(ci.get_upper_bound()); - return true; - } - return false; -} - -column_type lar_solver::get_column_type(const column_info & ci) { - auto ret = ci.get_column_type_no_flipping(); - if (ret == column_type::boxed) { // changing boxed to fixed because of the no span - if (ci.get_low_bound() == ci.get_upper_bound()) - ret = column_type::fixed; - } - return ret; -} - -std::string lar_solver::get_column_name(unsigned j) const { - if (j >= m_terms_start_index) - return std::string("_t") + T_to_string(j); - if (j >= m_columns_to_ext_vars_or_term_indices.size()) - return std::string("_s") + T_to_string(j); - - return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]); -} - -bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { - for (auto it : left_side) { - if (! var_is_registered(it.second)) - return false; - } - return true; -} - -bool lar_solver::all_constraints_hold() const { - if (m_settings.get_cancel_flag()) - return true; - std::unordered_map var_map; - get_model_do_not_care_about_diff_vars(var_map); - - for (unsigned i = 0; i < m_constraints.size(); i++) { - if (!constraint_holds(*m_constraints[i], var_map)) { - print_constraint(i, std::cout); - return false; - } - } - return true; -} - -bool lar_solver::constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { - return true; - mpq left_side_val = get_left_side_val(constr, var_map); - switch (constr.m_kind) { - case LE: return left_side_val <= constr.m_right_side; - case LT: return left_side_val < constr.m_right_side; - case GE: return left_side_val >= constr.m_right_side; - case GT: return left_side_val > constr.m_right_side; - case EQ: return left_side_val == constr.m_right_side; - default: - lp_unreachable(); - } - return false; // it is unreachable -} - -bool lar_solver::the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const { - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lconstraint_kind kind = coeff.is_pos() ? - m_constraints[con_ind]->m_kind : - flip_kind(m_constraints[con_ind]->m_kind); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) n_of_G++; - else if (kind == LE || kind == LT) n_of_L++; - } - the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); - - return n_of_G == 0 || n_of_L == 0; -} - -void lar_solver::register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a) { - for (auto & it : cn.get_left_side_coefficients()) { - unsigned j = it.second; - auto p = coeffs.find(j); - if (p == coeffs.end()) - coeffs[j] = it.first * a; - else { - p->second += it.first * a; - if (p->second.is_zero()) - coeffs.erase(p); - } - } -} - -bool lar_solver::the_left_sides_sum_to_zero(const vector> & evidence) const { - std::unordered_map coeff_map; - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lp_assert(con_ind < m_constraints.size()); - register_in_map(coeff_map, *m_constraints[con_ind], coeff); - } - - if (!coeff_map.empty()) { - std::cout << "left side = "; - vector> t; - for (auto & it : coeff_map) { - t.push_back(std::make_pair(it.second, it.first)); - } - print_linear_combination_of_column_indices(t, std::cout); - std::cout << std::endl; - return false; - } - - return true; -} - -bool lar_solver::the_right_sides_do_not_sum_to_zero(const vector> & evidence) { - mpq ret = numeric_traits::zero(); - for (auto & it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lp_assert(con_ind < m_constraints.size()); - const lar_constraint & constr = *m_constraints[con_ind]; - ret += constr.m_right_side * coeff; - } - return !numeric_traits::is_zero(ret); -} - -bool lar_solver::explanation_is_correct(const vector>& explanation) const { -#ifdef LEAN_DEBUG - lconstraint_kind kind; - lp_assert(the_relations_are_of_same_type(explanation, kind)); - lp_assert(the_left_sides_sum_to_zero(explanation)); - mpq rs = sum_of_right_sides_of_explanation(explanation); - switch (kind) { - case LE: lp_assert(rs < zero_of_type()); - break; - case LT: lp_assert(rs <= zero_of_type()); - break; - case GE: lp_assert(rs > zero_of_type()); - break; - case GT: lp_assert(rs >= zero_of_type()); - break; - case EQ: lp_assert(rs != zero_of_type()); - break; - default: - lp_assert(false); - return false; - } -#endif - return true; -} - -bool lar_solver::inf_explanation_is_correct() const { -#ifdef LEAN_DEBUG - vector> explanation; - get_infeasibility_explanation(explanation); - return explanation_is_correct(explanation); -#endif - return true; -} - -mpq lar_solver::sum_of_right_sides_of_explanation(const vector> & explanation) const { - mpq ret = numeric_traits::zero(); - for (auto & it : explanation) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lp_assert(con_ind < m_constraints.size()); - ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; - } - return ret; -} - -bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - - if (var >= m_columns_to_ul_pairs.size()) { - // TBD: bounds on terms could also be used, caller may have to track these. - return false; - } - const ul_pair & ul = m_columns_to_ul_pairs[var]; - ci = ul.low_bound_witness(); - if (ci != static_cast(-1)) { - auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; - value = p.x; - is_strict = p.y.is_pos(); - return true; - } - else { - return false; - } -} - -bool lar_solver::has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { - - if (var >= m_columns_to_ul_pairs.size()) { - // TBD: bounds on terms could also be used, caller may have to track these. - return false; - } - const ul_pair & ul = m_columns_to_ul_pairs[var]; - ci = ul.upper_bound_witness(); - if (ci != static_cast(-1)) { - auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; - value = p.x; - is_strict = p.y.is_neg(); - return true; - } - else { - return false; - } -} - -void lar_solver::get_infeasibility_explanation(vector> & explanation) const { - explanation.clear(); - if (m_infeasible_column_index != -1) { - fill_explanation_from_infeasible_column(explanation); - return; - } - if (m_mpq_lar_core_solver.get_infeasible_sum_sign() == 0) { - return; - } - // the infeasibility sign - int inf_sign; - auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); - get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); - lp_assert(explanation_is_correct(explanation)); -} - - - -void lar_solver::get_infeasibility_explanation_for_inf_sign( - vector> & explanation, - const vector> & inf_row, - int inf_sign) const { - - for (auto & it : inf_row) { - mpq coeff = it.first; - unsigned j = it.second; - - int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; - const ul_pair & ul = m_columns_to_ul_pairs[j]; - - constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); - lp_assert(bound_constr_i < m_constraints.size()); - explanation.push_back(std::make_pair(coeff, bound_constr_i)); - } -} - -void lar_solver::get_model(std::unordered_map & variable_values) const { - mpq delta = mpq(1, 2); // start from 0.5 to have less clashes - lp_assert(m_status == lp_status::OPTIMAL); - unsigned i; - do { - // different pairs have to produce different singleton values - std::unordered_set set_of_different_pairs; - std::unordered_set set_of_different_singles; - delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); - for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { - const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; - set_of_different_pairs.insert(rp); - mpq x = rp.x + delta * rp.y; - set_of_different_singles.insert(x); - if (set_of_different_pairs.size() - != set_of_different_singles.size()) { - delta /= mpq(2); - break; - } - - variable_values[i] = x; - } - } while (i != m_mpq_lar_core_solver.m_r_x.size()); -} - -void lar_solver::get_model_do_not_care_about_diff_vars(std::unordered_map & variable_values) const { - mpq delta = mpq(1); - delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); - for (unsigned i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { - const impq & rp = m_mpq_lar_core_solver.m_r_x[i]; - variable_values[i] = rp.x + delta * rp.y; - } -} - - -std::string lar_solver::get_variable_name(var_index vi) const { - return get_column_name(vi); -} - -// ********** print region start -void lar_solver::print_constraint(constraint_index ci, std::ostream & out) const { - if (ci >= m_constraints.size()) { - out << "constraint " << T_to_string(ci) << " is not found"; - out << std::endl; - return; - } - - print_constraint(m_constraints[ci], out); -} - -void lar_solver::print_constraints(std::ostream& out) const { - for (auto c : m_constraints) { - print_constraint(c, out); - } -} - -void lar_solver::print_terms(std::ostream& out) const { - for (auto it : m_terms) { - print_term(*it, out); - out << "\n"; - } -} - -void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const { - print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out); - mpq free_coeff = c->get_free_coeff_of_left_side(); - if (!is_zero(free_coeff)) - out << " + " << free_coeff; - -} - -void lar_solver::print_term(lar_term const& term, std::ostream & out) const { - if (!numeric_traits::is_zero(term.m_v)) { - out << term.m_v << " + "; - } - print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); -} - -void lar_solver::print_term_as_indices(lar_term const& term, std::ostream & out) const { - if (!numeric_traits::is_zero(term.m_v)) { - out << term.m_v << " + "; - } - print_linear_combination_of_column_indices_only(term.coeffs_as_vector(), out); -} - -mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { - mpq ret = cns.get_free_coeff_of_left_side(); - for (auto & it : cns.get_left_side_coefficients()) { - var_index j = it.second; - auto vi = var_map.find(j); - lp_assert(vi != var_map.end()); - ret += it.first * vi->second; - } - return ret; -} - -void lar_solver::print_constraint(const lar_base_constraint * c, std::ostream & out) const { - print_left_side_of_constraint(c, out); - out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; -} - -void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { - for (unsigned i = 0; i < sz; i++) { - var_index var = vars[i]; - if (var >= m_terms_start_index) { // handle the term - for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { - column_list.push_back(it.first); - } - } else { - column_list.push_back(var); - } - } -} - -void lar_solver::random_update(unsigned sz, var_index const * vars) { - vector column_list; - fill_var_set_for_random_update(sz, vars, column_list); - random_updater ru(*this, column_list); - ru.update(); - lp_assert(inf_int_set_is_correct()); -} - - -void lar_solver::pivot_fixed_vars_from_basis() { - m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); -} - -void lar_solver::pop() { - pop(1); -} - -bool lar_solver::column_represents_row_in_tableau(unsigned j) { - return m_columns_to_ul_pairs()[j].m_i != static_cast(-1); -} - -void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { - // i, j - is the indices of the bottom-right element of the tableau - 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;){ - auto & cc = last_column[k]; - if (cc.m_i == 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); -} - -void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { - lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - auto & slv = m_mpq_lar_core_solver.m_r_solver; - unsigned i = A_r().row_count() - 1; //last row index - make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); - if (slv.m_basis_heading[j] < 0) { - slv.pivot_column_tableau(j, i); - } - - 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;) { - auto &rc = last_row[k]; - if (cost_is_nz) { - m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); - } - - A_r().remove_element(last_row, rc); - } - 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(); - 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); - A_r().m_columns.pop_back(); -} - -void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { - auto& rslv = m_mpq_lar_core_solver.m_r_solver; - int i = rslv.m_basis_heading[j]; - if (i >= 0) { // j is a basic var - int last_pos = static_cast(rslv.m_basis.size()) - 1; - lp_assert(last_pos >= 0); - if (i != last_pos) { - unsigned j_at_last_pos = rslv.m_basis[last_pos]; - rslv.m_basis[i] = j_at_last_pos; - rslv.m_basis_heading[j_at_last_pos] = i; - } - rslv.m_basis.pop_back(); // remove j from the basis - } else { - int last_pos = static_cast(rslv.m_nbasis.size()) - 1; - lp_assert(last_pos >= 0); - i = - 1 - i; - if (i != last_pos) { - unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; - rslv.m_nbasis[i] = j_at_last_pos; - rslv.m_basis_heading[j_at_last_pos] = - i - 1; - } - rslv.m_nbasis.pop_back(); // remove j from the basis - } - rslv.m_basis_heading.pop_back(); - lp_assert(rslv.m_basis.size() == A_r().row_count()); - lp_assert(rslv.basis_heading_is_correct()); -} - -void lar_solver::remove_last_column_from_tableau() { - auto& rslv = m_mpq_lar_core_solver.m_r_solver; - unsigned j = A_r().column_count() - 1; - lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); - if (column_represents_row_in_tableau(j)) { - remove_last_row_and_column_from_tableau(j); - if (rslv.m_basis_heading[j] < 0) - rslv.change_basis_unconditionally(j, rslv.m_basis[A_r().row_count()]); // A_r().row_count() is the index of the last row in the basis still - } - else { - remove_last_column_from_A(); - } - rslv.m_x.pop_back(); - rslv.m_d.pop_back(); - rslv.m_costs.pop_back(); - - remove_last_column_from_basis_tableau(j); - lp_assert(m_mpq_lar_core_solver.r_basis_is_OK()); - lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); -} - -void lar_solver::pop_tableau() { - lp_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - - lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); - // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). - // At this moment m_column_names is already popped - while (A_r().column_count() > m_columns_to_ext_vars_or_term_indices.size()) - remove_last_column_from_tableau(); - lp_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); - lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); - lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); -} - -void lar_solver::clean_inf_set_of_r_solver_after_pop() { - lp_assert(inf_int_set_is_correct()); - vector became_feas; - clean_popped_elements(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); - std::unordered_set basic_columns_with_changed_cost; - auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; - for (auto j: inf_index_copy) { - if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - continue; - } - // some basic columns might become non-basic - these columns need to be made feasible - numeric_pair delta; - if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) { - - change_basic_columns_dependend_on_a_given_nb_column(j, delta); - } - became_feas.push_back(j); - } - - for (unsigned j : became_feas) { - lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); - m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; - m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); - m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - } - became_feas.clear(); - for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { - lp_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); - if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) - became_feas.push_back(j); - } - for (unsigned j : became_feas) - m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); - - - if (use_tableau_costs()) { - for (unsigned j : became_feas) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - for (unsigned j : basic_columns_with_changed_cost) - m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); - lp_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); - } -} - -void lar_solver::shrink_explanation_to_minimum(vector> & explanation) const { - // implementing quickXplain - quick_xplain::run(explanation, *this); - lp_assert(this->explanation_is_correct(explanation)); -} - -bool lar_solver::model_is_int_feasible() const { - unsigned n = A_r().column_count(); - for (unsigned j = 0; j < n; j++) { - if (column_is_int(j) && !column_value_is_integer(j)) - return false; - } - return true; -} - -bool lar_solver::term_is_int(const lar_term * t) const { - for (auto const & p : t->m_coeffs) - if (! (column_is_int(p.first) && p.second.is_int())) - return false; - return t->m_v.is_int(); -} - -bool lar_solver::var_is_int(var_index v) const { - if (is_term(v)) { - lar_term const& t = get_term(v); - return term_is_int(&t); - } - else { - return column_is_int(v); - } -} - -bool lar_solver::column_is_int(unsigned j) const { - unsigned ext_var = m_columns_to_ext_vars_or_term_indices[j]; - lp_assert(contains(m_ext_vars_to_columns, ext_var)); - return m_ext_vars_to_columns.find(ext_var)->second.is_integer(); -} - -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 { - auto it = m_ext_vars_to_columns.find(ext_var); - lp_assert(it != m_ext_vars_to_columns.end()); - return it == m_ext_vars_to_columns.end() || it->second.is_integer(); -} - -// below is the initialization functionality of lar_solver - -bool lar_solver::strategy_is_undecided() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; -} - -var_index lar_solver::add_var(unsigned ext_j, bool is_int) { - TRACE("add_var", tout << "adding var " << ext_j << (is_int? " int" : " nonint") << std::endl;); - var_index i; - lp_assert(ext_j < m_terms_start_index); - - if (ext_j >= m_terms_start_index) - throw 0; // todo : what is the right way to exit? - auto it = m_ext_vars_to_columns.find(ext_j); - if (it != m_ext_vars_to_columns.end()) { - return it->second.ext_j(); - } - lp_assert(m_columns_to_ul_pairs.size() == A_r().column_count()); - i = A_r().column_count(); - m_columns_to_ul_pairs.push_back(ul_pair(static_cast(-1))); - add_non_basic_var_to_core_fields(ext_j, is_int); - lp_assert(sizes_are_correct()); - if (is_int) { - m_mpq_lar_core_solver.m_r_solver.set_tracker_of_x(& m_tracker_of_x_change); - } - lp_assert(inf_int_set_is_correct()); - return i; -} - -void lar_solver::register_new_ext_var_index(unsigned ext_v, bool is_int) { - lp_assert(!contains(m_ext_vars_to_columns, ext_v)); - unsigned j = static_cast(m_ext_vars_to_columns.size()); - m_ext_vars_to_columns.insert(std::make_pair(ext_v, ext_var_info(j, is_int))); - lp_assert(m_columns_to_ext_vars_or_term_indices.size() == j); - m_columns_to_ext_vars_or_term_indices.push_back(ext_v); -} - -void lar_solver::add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int) { - register_new_ext_var_index(ext_j, is_int); - m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); - m_columns_with_changed_bound.increase_size_by_one(); - m_inf_int_set.increase_size_by_one(); - add_new_var_to_core_fields_for_mpq(false); - if (use_lu()) - add_new_var_to_core_fields_for_doubles(false); -} - -void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) { - unsigned j = A_d().column_count(); - A_d().add_column(); - lp_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lp_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_d_x.resize(j + 1); - m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lp_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_d().add_row(); - m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); - m_mpq_lar_core_solver.m_d_basis.push_back(j); - } - else { - m_mpq_lar_core_solver.m_d_heading.push_back(-static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_d_nbasis.push_back(j); - } -} - -void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) { - unsigned j = A_r().column_count(); - A_r().add_column(); - lp_assert(m_mpq_lar_core_solver.m_r_x.size() == j); - // lp_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_r_x.resize(j + 1); - m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one(); - m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); - m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); - lp_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_r().add_row(); - m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); - m_mpq_lar_core_solver.m_r_basis.push_back(j); - if (m_settings.bound_propagation()) - m_rows_with_changed_bounds.insert(A_r().row_count() - 1); - } - else { - m_mpq_lar_core_solver.m_r_heading.push_back(-static_cast(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_r_nbasis.push_back(j); - } -} - - -var_index lar_solver::add_term_undecided(const vector> & coeffs, - const mpq &m_v) { - m_terms.push_back(new lar_term(coeffs, m_v)); - return m_terms_start_index + m_terms.size() - 1; -} - -// terms -var_index lar_solver::add_term(const vector> & coeffs, - const mpq &m_v) { - if (strategy_is_undecided()) - return add_term_undecided(coeffs, m_v); - - m_terms.push_back(new lar_term(coeffs, m_v)); - unsigned adjusted_term_index = m_terms.size() - 1; - var_index ret = m_terms_start_index + adjusted_term_index; - if (use_tableau() && !coeffs.empty()) { - add_row_from_term_no_constraint(m_terms.back(), ret); - if (m_settings.bound_propagation()) - m_rows_with_changed_bounds.insert(A_r().row_count() - 1); - } - lp_assert(m_ext_vars_to_columns.size() == A_r().column_count()); - return ret; -} - -void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { - register_new_ext_var_index(term_ext_index, term_is_int(term)); - // j will be a new variable - unsigned j = A_r().column_count(); - ul_pair ul(j); - m_columns_to_ul_pairs.push_back(ul); - add_basic_var_to_core_fields(); - if (use_tableau()) { - auto it = iterator_on_term_with_basis_var(*term, j); - A_r().fill_last_row_with_pivoting(it, - m_mpq_lar_core_solver.m_r_solver.m_basis_heading); - m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type()); - } - else { - fill_last_row_of_A_r(A_r(), term); - } - m_mpq_lar_core_solver.m_r_solver.update_x_and_call_tracker(j, get_basic_var_value_from_row_directly(A_r().row_count() - 1)); - if (use_lu()) - fill_last_row_of_A_d(A_d(), term); - lp_assert(inf_int_set_is_correct()); -} - -void lar_solver::add_basic_var_to_core_fields() { - bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); - lp_assert(!use_lu || A_r().column_count() == A_d().column_count()); - m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); - m_columns_with_changed_bound.increase_size_by_one(); - m_rows_with_changed_bounds.increase_size_by_one(); - m_inf_int_set.increase_size_by_one(); - add_new_var_to_core_fields_for_mpq(true); - if (use_lu) - add_new_var_to_core_fields_for_doubles(true); -} - -bool lar_solver::bound_is_integer_if_needed(unsigned j, const mpq & right_side) const { - if (!column_is_int(j)) - return true; - return right_side.is_int(); -} - -constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { - TRACE("lar_solver", tout << "j = " << j << std::endl;); - constraint_index ci = m_constraints.size(); - if (!is_term(j)) { // j is a var - lp_assert(bound_is_integer_if_needed(j, right_side)); - auto vc = new lar_var_constraint(j, kind, right_side); - m_constraints.push_back(vc); - update_column_type_and_bound(j, kind, right_side, ci); - } - else { - add_var_bound_on_constraint_for_term(j, kind, right_side, ci); - } - lp_assert(sizes_are_correct()); - lp_assert(inf_int_set_is_correct()); - return ci; -} - -void lar_solver::update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { - switch (m_mpq_lar_core_solver.m_column_types[j]) { - case column_type::free_column: - update_free_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::boxed: - update_boxed_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::low_bound: - update_low_bound_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::upper_bound: - update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index); - break; - case column_type::fixed: - update_fixed_column_type_and_bound(j, kind, right_side, constr_index); - break; - default: - lp_assert(false); // cannot be here - } -} - -void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lp_assert(is_term(j)); - unsigned adjusted_term_index = adjust_term_index(j); - lp_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int()); - auto it = m_ext_vars_to_columns.find(j); - if (it != m_ext_vars_to_columns.end()) { - unsigned term_j = it->second.ext_j(); - mpq rs = right_side - m_terms[adjusted_term_index]->m_v; - m_constraints.push_back(new lar_term_constraint(m_terms[adjusted_term_index], kind, right_side)); - update_column_type_and_bound(term_j, kind, rs, ci); - } - else { - add_constraint_from_term_and_create_new_column_row(j, m_terms[adjusted_term_index], kind, right_side); - } -} - -constraint_index lar_solver::add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { - vector> left_side; - mpq rs = -right_side_parm; - substitute_terms_in_linear_expression(left_side_with_terms, left_side, rs); - unsigned term_index = add_term(left_side, zero_of_type()); - constraint_index ci = m_constraints.size(); - add_var_bound_on_constraint_for_term(term_index, kind_par, -rs, ci); - return ci; -} - -void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, - lconstraint_kind kind, const mpq & right_side) { - - add_row_from_term_no_constraint(term, term_j); - unsigned j = A_r().column_count() - 1; - update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size()); - m_constraints.push_back(new lar_term_constraint(term, kind, right_side)); - lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); -} - -void lar_solver::decide_on_strategy_and_adjust_initial_state() { - lp_assert(strategy_is_undecided()); - if (m_columns_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { - m_settings.simplex_strategy() = simplex_strategy_enum::lu; - } - else { - m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs? - } - adjust_initial_state(); -} - -void lar_solver::adjust_initial_state() { - switch (m_settings.simplex_strategy()) { - case simplex_strategy_enum::lu: - adjust_initial_state_for_lu(); - break; - case simplex_strategy_enum::tableau_rows: - adjust_initial_state_for_tableau_rows(); - break; - case simplex_strategy_enum::tableau_costs: - lp_assert(false); // not implemented - case simplex_strategy_enum::undecided: - adjust_initial_state_for_tableau_rows(); - break; - } -} - -void lar_solver::adjust_initial_state_for_lu() { - copy_from_mpq_matrix(A_d()); - unsigned n = A_d().column_count(); - m_mpq_lar_core_solver.m_d_x.resize(n); - m_mpq_lar_core_solver.m_d_low_bounds.resize(n); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); - m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; - m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; - - /* - unsigned j = A_d().column_count(); - A_d().add_column(); - lp_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lp_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); - m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lp_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_d().add_row(); - m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); - m_mpq_lar_core_solver.m_d_basis.push_back(j); - }else { - m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_d_nbasis.push_back(j); - }*/ -} - -void lar_solver::adjust_initial_state_for_tableau_rows() { - for (unsigned j = 0; j < m_terms.size(); j++) { - if (contains(m_ext_vars_to_columns, j + m_terms_start_index)) - continue; - add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index); - } -} - -// this fills the last row of A_d and sets the basis column: -1 in the last column of the row -void lar_solver::fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { - 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].empty()); - - 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()); - } - - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, -1); -} - -void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; - lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); - lp_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); - { - auto up = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - } - set_upper_bound_witness(j, constr_ind); - break; - case GT: - y_of_bound = 1; - case GE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound; - lp_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); - { - auto low = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - } - set_low_bound_witness(j, constr_ind); - break; - case EQ: - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair(right_side, zero_of_type()); - set_upper_bound_witness(j, constr_ind); - set_low_bound_witness(j, constr_ind); - break; - - default: - lp_unreachable(); - - } - m_columns_with_changed_bound.insert(j); -} - -void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - if (up < m_mpq_lar_core_solver.m_r_upper_bounds()[j]) { - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - } - } - break; - case GT: - y_of_bound = 1; - case GE: - m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed; - { - auto low = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - set_low_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - } - else { - m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j] ? column_type::boxed : column_type::fixed; - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = lp_status::INFEASIBLE; - set_low_bound_witness(j, ci); - m_infeasible_column_index = j; - } - else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - break; - } - break; - - default: - lp_unreachable(); - - } -} - -void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - } - - if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = lp_status::INFEASIBLE; - lp_assert(false); - m_infeasible_column_index = j; - } - else { - if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]) - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - } - break; - case GT: - y_of_bound = 1; - case GE: - { - auto low = numeric_pair(right_side, y_of_bound); - if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - } - if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - } - else if (low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } - else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - m_columns_with_changed_bound.insert(j); - } - - break; - } - - default: - lp_unreachable(); - - } -} -void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); - mpq y_of_bound(0); - switch (kind) { - case LT: - y_of_bound = -1; - case LE: - { - auto up = numeric_pair(right_side, y_of_bound); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, ci); - m_columns_with_changed_bound.insert(j); - - if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - } - else { - m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j] ? column_type::boxed : column_type::fixed; - } - } - break; - case GT: - y_of_bound = 1; - case GE: - { - auto low = numeric_pair(right_side, y_of_bound); - if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_mpq_lar_core_solver.m_r_low_bounds[j] = low; - m_columns_with_changed_bound.insert(j); - set_low_bound_witness(j, ci); - } - } - break; - case EQ: - { - auto v = numeric_pair(right_side, zero_of_type()); - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - else { - m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; - set_low_bound_witness(j, ci); - set_upper_bound_witness(j, ci); - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; - } - m_columns_with_changed_bound.insert(j); - break; - } - - default: - lp_unreachable(); - - } -} - -void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { - lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); - lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); - auto v = numeric_pair(right_side, mpq(0)); - - mpq y_of_bound(0); - switch (kind) { - case LT: - if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - break; - case LE: - { - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - } - break; - case GT: - { - if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } - } - break; - case GE: - { - if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } - } - break; - case EQ: - { - if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_upper_bound_witness(j, ci); - } - else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - m_status = lp_status::INFEASIBLE; - m_infeasible_column_index = j; - set_low_bound_witness(j, ci); - } - break; - } - - default: - lp_unreachable(); - - } -} - - -} // namespace lp - - From 41cb2870791a6af47054b5541be09f97de2059dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:48:34 -0800 Subject: [PATCH 0542/1283] re-add cpp file Signed-off-by: Nikolaj Bjorner --- src/util/lp/lar_solver.hpp | 2089 ++++++++++++++++++++++++++ src/util/lp/lar_solver_instances.cpp | 2 +- 2 files changed, 2090 insertions(+), 1 deletion(-) create mode 100644 src/util/lp/lar_solver.hpp diff --git a/src/util/lp/lar_solver.hpp b/src/util/lp/lar_solver.hpp new file mode 100644 index 000000000..6846717af --- /dev/null +++ b/src/util/lp/lar_solver.hpp @@ -0,0 +1,2089 @@ +#include "util/lp/lar_solver.h" +/* + Copyright (c) 2017 Microsoft Corporation + Author: Nikolaj Bjorner, Lev Nachmanson +*/ + +namespace lp { + +unsigned lar_solver::constraint_count() const { + return m_constraints.size(); +} +const lar_base_constraint& lar_solver::get_constraint(unsigned ci) const { + return *(m_constraints[ci]); +} + +////////////////// methods //////////////////////////////// +static_matrix> & lar_solver::A_r() { return m_mpq_lar_core_solver.m_r_A;} +static_matrix> const & lar_solver::A_r() const { return m_mpq_lar_core_solver.m_r_A;} +static_matrix & lar_solver::A_d() { return m_mpq_lar_core_solver.m_d_A;} +static_matrix const & lar_solver::A_d() const { return m_mpq_lar_core_solver.m_d_A;} + +lp_settings & lar_solver::settings() { return m_settings;} + +lp_settings const & lar_solver::settings() const { return m_settings;} + +void clear() {lp_assert(false); // not implemented +} + + +lar_solver::lar_solver() : m_status(lp_status::OPTIMAL), + m_infeasible_column_index(-1), + m_terms_start_index(1000000), + m_mpq_lar_core_solver(m_settings, *this), + m_tracker_of_x_change([&](unsigned j) { + call_assignment_tracker(j); + } + ), + m_int_solver(nullptr) +{} + +void lar_solver::set_track_pivoted_rows(bool v) { + m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows = v? (& m_rows_with_changed_bounds) : nullptr; +} + +bool lar_solver::get_track_pivoted_rows() const { + return m_mpq_lar_core_solver.m_r_solver.m_pivoted_rows != nullptr; +} + + +lar_solver::~lar_solver(){ + for (auto c : m_constraints) + delete c; + for (auto t : m_terms) + delete t; +} + +bool lar_solver::is_term(var_index j) const { + return j >= m_terms_start_index && j - m_terms_start_index < m_terms.size(); +} + +unsigned lar_solver::adjust_term_index(unsigned j) const { + lp_assert(is_term(j)); + return j - m_terms_start_index; +} + + +bool lar_solver::use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } + +bool lar_solver::sizes_are_correct() const { + lp_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); + return true; +} + + +void lar_solver::print_implied_bound(const implied_bound& be, std::ostream & out) const { + out << "implied bound\n"; + unsigned v = be.m_j; + if (is_term(v)) { + out << "it is a term number " << be.m_j << std::endl; + print_term(*m_terms[be.m_j - m_terms_start_index], out); + } + else { + out << get_column_name(v); + } + out << " " << lconstraint_kind_string(be.kind()) << " " << be.m_bound << std::endl; + out << "end of implied bound" << std::endl; +} + +bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const { + std::unordered_map coeff_map; + auto rs_of_evidence = zero_of_type(); + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : explanation) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + const auto & constr = *m_constraints[con_ind]; + lconstraint_kind kind = coeff.is_pos() ? constr.m_kind : flip_kind(constr.m_kind); + register_in_map(coeff_map, constr, coeff); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + rs_of_evidence += coeff*constr.m_right_side; + } + lp_assert(n_of_G == 0 || n_of_L == 0); + lconstraint_kind kind = n_of_G ? GE : (n_of_L ? LE : EQ); + if (strict) + kind = static_cast((static_cast(kind) / 2)); + + if (!is_term(be.m_j)) { + if (coeff_map.size() != 1) + return false; + auto it = coeff_map.find(be.m_j); + if (it == coeff_map.end()) return false; + mpq ratio = it->second; + if (ratio < zero_of_type()) { + kind = static_cast(-kind); + } + rs_of_evidence /= ratio; + } else { + const lar_term * t = m_terms[adjust_term_index(be.m_j)]; + const auto first_coeff = *t->m_coeffs.begin(); + unsigned j = first_coeff.first; + auto it = coeff_map.find(j); + if (it == coeff_map.end()) + return false; + mpq ratio = it->second / first_coeff.second; + for (auto & p : t->m_coeffs) { + it = coeff_map.find(p.first); + if (it == coeff_map.end()) + return false; + if (p.second * ratio != it->second) + return false; + } + if (ratio < zero_of_type()) { + kind = static_cast(-kind); + } + rs_of_evidence /= ratio; + rs_of_evidence += t->m_v * ratio; + } + + return kind == be.kind() && rs_of_evidence == be.m_bound; +} + + +void lar_solver::analyze_new_bounds_on_row( + unsigned row_index, + bound_propagator & bp) { + lp_assert(!use_tableau()); + iterator_on_pivot_row it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]); + + bound_analyzer_on_row ra_pos(it, + zero_of_type>(), + row_index, + bp + ); + ra_pos.analyze(); +} + +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) + return; + iterator_on_row it(A_r().m_rows[row_index]); + lp_assert(use_tableau()); + bound_analyzer_on_row::analyze_row(it, + zero_of_type>(), + row_index, + bp + ); +} + + +void lar_solver::substitute_basis_var_in_terms_for_row(unsigned i) { + // todo : create a map from term basic vars to the rows where they are used + unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; + for (unsigned k = 0; k < m_terms.size(); k++) { + if (term_is_used_as_row(k)) + continue; + if (!m_terms[k]->contains(basis_j)) + continue; + m_terms[k]->subst(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); + } +} + +void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp) { + if(use_tableau()) { + analyze_new_bounds_on_row_tableau(i, bp); + } else { + m_mpq_lar_core_solver.calculate_pivot_row(i); + substitute_basis_var_in_terms_for_row(i); + analyze_new_bounds_on_row(i, bp); + } +} + + +linear_combination_iterator * lar_solver::create_new_iter_from_term(unsigned term_index) const { + lp_assert(false); // not implemented + return nullptr; + // new linear_combination_iterator_on_vector(m_terms[adjust_term_index(term_index)]->coeffs_as_vector()); +} + +unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const { + unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j]; + return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term; +} + +void lar_solver::propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset) { + lp_assert(false); // not implemented +} + + +void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp) { + unsigned i = ib.m_row_or_term_index; + int bound_sign = ib.m_is_low_bound? 1: -1; + int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign; + unsigned m_j = ib.m_j; + if (is_term(m_j)) { + auto it = m_ext_vars_to_columns.find(m_j); + lp_assert(it != m_ext_vars_to_columns.end()); + m_j = it->second.ext_j(); + } + for (auto const& r : A_r().m_rows[i]) { + unsigned j = r.m_j; + mpq const& a = r.get_val(); + if (j == m_j) continue; + if (is_term(j)) { + auto it = m_ext_vars_to_columns.find(j); + lp_assert(it != m_ext_vars_to_columns.end()); + j = it->second.ext_j(); + } + int a_sign = is_pos(a)? 1: -1; + int sign = j_sign * a_sign; + const ul_pair & ul = m_columns_to_ul_pairs[j]; + auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness(); + lp_assert(is_valid(witness)); + bp.consume(a, witness); + } + // lp_assert(implied_bound_is_correctly_explained(ib, explanation)); +} + + +bool lar_solver::term_is_used_as_row(unsigned term) const { + lp_assert(is_term(term)); + return contains(m_ext_vars_to_columns, term); +} + +void lar_solver::propagate_bounds_on_terms(bound_propagator & bp) { + for (unsigned i = 0; i < m_terms.size(); i++) { + if (term_is_used_as_row(i + m_terms_start_index)) + continue; // this term is used a left side of a constraint, + // it was processed as a touched row if needed + propagate_bounds_on_a_term(*m_terms[i], bp, i); + } +} + + +// goes over touched rows and tries to induce bounds +void lar_solver::propagate_bounds_for_touched_rows(bound_propagator & bp) { + if (!use_tableau()) + return; // todo: consider to remove the restriction + + for (unsigned i : m_rows_with_changed_bounds.m_index) { + calculate_implied_bounds_for_row(i, bp); + } + m_rows_with_changed_bounds.clear(); + if (!use_tableau()) { + propagate_bounds_on_terms(bp); + } +} + +lp_status lar_solver::get_status() const { return m_status;} + +void lar_solver::set_status(lp_status s) {m_status = s;} + +bool lar_solver::has_int_var() const { + return m_mpq_lar_core_solver.m_r_solver.m_tracker_of_x_change != nullptr; +} + +lp_status lar_solver::find_feasible_solution() { + lp_assert(inf_int_set_is_correct()); + m_settings.st().m_make_feasible++; + if (A_r().column_count() > m_settings.st().m_max_cols) + m_settings.st().m_max_cols = A_r().column_count(); + if (A_r().row_count() > m_settings.st().m_max_rows) + m_settings.st().m_max_rows = A_r().row_count(); + if (strategy_is_undecided()) + decide_on_strategy_and_adjust_initial_state(); + + if (has_int_var()) { + m_inf_int_set.resize(A_r().column_count()); + } + + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; + auto ret = solve(); + TRACE("intinf", m_int_solver->display_inf_or_int_inf_columns(tout);); + lp_assert(inf_int_set_is_correct()); + return ret; +} + +lp_status lar_solver::solve() { + lp_assert(inf_int_set_is_correct()); + if (m_status == lp_status::INFEASIBLE) { + return m_status; + } + solve_with_core_solver(); + if (m_status != lp_status::INFEASIBLE) { + if (m_settings.bound_propagation()) + detect_rows_with_changed_bounds(); + } + + m_columns_with_changed_bound.clear(); + lp_assert(inf_int_set_is_correct()); + return m_status; +} + +void lar_solver::fill_explanation_from_infeasible_column(vector> & evidence) const{ + + // this is the case when the lower bound is in conflict with the upper one + const ul_pair & ul = m_columns_to_ul_pairs[m_infeasible_column_index]; + evidence.push_back(std::make_pair(numeric_traits::one(), ul.upper_bound_witness())); + evidence.push_back(std::make_pair(-numeric_traits::one(), ul.low_bound_witness())); +} + + +unsigned lar_solver::get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } +vector lar_solver::get_list_of_all_var_indices() const { + vector ret; + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_heading.size(); j++) + ret.push_back(j); + return ret; +} +void lar_solver::push() { + m_simplex_strategy = m_settings.simplex_strategy(); + m_simplex_strategy.push(); + m_columns_to_ul_pairs.push(); + m_infeasible_column_index.push(); + m_mpq_lar_core_solver.push(); + m_term_count = m_terms.size(); + m_term_count.push(); + m_constraint_count = m_constraints.size(); + m_constraint_count.push(); +} + +void lar_solver::clean_popped_elements(unsigned n, int_set& set) { + vector to_remove; + for (unsigned j: set.m_index) + if (j >= n) + to_remove.push_back(j); + for (unsigned j : to_remove) + set.erase(j); +} + +void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) { + clean_popped_elements(n, set); + set.resize(n); +} + + +void lar_solver::pop(unsigned k) { + TRACE("arith_int", tout << "pop" << std::endl;); + lp_assert(inf_int_set_is_correct()); + TRACE("lar_solver", tout << "k = " << k << std::endl;); + + int n_was = static_cast(m_ext_vars_to_columns.size()); + m_infeasible_column_index.pop(k); + unsigned n = m_columns_to_ul_pairs.peek_size(k); + for (unsigned j = n_was; j-- > n;) + m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]); + m_columns_to_ext_vars_or_term_indices.resize(n); + TRACE("arith_int", tout << "pop" << std::endl;); + if (m_settings.use_tableau()) { + pop_tableau(); + } + lp_assert(A_r().column_count() == n); + m_columns_to_ul_pairs.pop(k); + + m_mpq_lar_core_solver.pop(k); + clean_popped_elements(n, m_columns_with_changed_bound); + clean_popped_elements(n, m_inf_int_set); + unsigned m = A_r().row_count(); + lp_assert(inf_int_set_is_correct()); + clean_popped_elements(m, m_rows_with_changed_bounds); + lp_assert(inf_int_set_is_correct()); + clean_inf_set_of_r_solver_after_pop(); + lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || + (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + + + lp_assert(ax_is_correct()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct()); + m_constraint_count.pop(k); + for (unsigned i = m_constraint_count; i < m_constraints.size(); i++) + delete m_constraints[i]; + + m_constraints.resize(m_constraint_count); + m_term_count.pop(k); + for (unsigned i = m_term_count; i < m_terms.size(); i++) { + delete m_terms[i]; + } + m_terms.resize(m_term_count); + m_simplex_strategy.pop(k); + m_settings.simplex_strategy() = m_simplex_strategy; + lp_assert(sizes_are_correct()); + lp_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + m_status = m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()? lp_status::OPTIMAL: lp_status::UNKNOWN; + +} + +vector lar_solver::get_all_constraint_indices() const { + vector ret; + constraint_index i = 0; + while ( i < m_constraints.size()) + ret.push_back(i++); + return ret; +} + +bool lar_solver::maximize_term_on_tableau(const vector> & term, + impq &term_max) { + if (settings().simplex_strategy() == simplex_strategy_enum::undecided) + decide_on_strategy_and_adjust_initial_state(); + + m_mpq_lar_core_solver.solve(); + if (m_mpq_lar_core_solver.m_r_solver.get_status() == lp_status::UNBOUNDED) + return false; + + term_max = 0; + for (auto & p : term) + term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second]; + + return true; +} + +bool lar_solver::costs_are_zeros_for_r_solver() const { + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_costs.size(); j++) { + lp_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_costs[j])); + } + return true; +} +bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const { + for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_solver.m_d.size(); j++) { + lp_assert(is_zero(m_mpq_lar_core_solver.m_r_solver.m_d[j])); + } + return true; +} + +void lar_solver::set_costs_to_zero(const vector> & term) { + auto & rslv = m_mpq_lar_core_solver.m_r_solver; + auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now + lp_assert(jset.m_index.size()==0); + + for (auto & p : term) { + unsigned j = p.second; + rslv.m_costs[j] = zero_of_type(); + int i = rslv.m_basis_heading[j]; + if (i < 0) + jset.insert(j); + else { + for (auto & rc : A_r().m_rows[i]) + jset.insert(rc.m_j); + } + } + + for (unsigned j : jset.m_index) + rslv.m_d[j] = zero_of_type(); + + jset.clear(); + + lp_assert(reduced_costs_are_zeroes_for_r_solver()); + lp_assert(costs_are_zeros_for_r_solver()); +} + +void lar_solver::prepare_costs_for_r_solver(const vector> & term) { + + auto & rslv = m_mpq_lar_core_solver.m_r_solver; + rslv.m_using_infeas_costs = false; + lp_assert(costs_are_zeros_for_r_solver()); + lp_assert(reduced_costs_are_zeroes_for_r_solver()); + rslv.m_costs.resize(A_r().column_count(), zero_of_type()); + for (auto & p : term) { + unsigned j = p.second; + rslv.m_costs[j] = p.first; + if (rslv.m_basis_heading[j] < 0) + rslv.m_d[j] += p.first; + else + rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j); + } + lp_assert(rslv.reduced_costs_are_correct_tableau()); +} + +bool lar_solver::maximize_term_on_corrected_r_solver(const vector> & term, + impq &term_max) { + settings().backup_costs = false; + switch (settings().simplex_strategy()) { + case simplex_strategy_enum::tableau_rows: + prepare_costs_for_r_solver(term); + settings().simplex_strategy() = simplex_strategy_enum::tableau_costs; + { + bool ret = maximize_term_on_tableau(term, term_max); + settings().simplex_strategy() = simplex_strategy_enum::tableau_rows; + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); + return ret; + } + case simplex_strategy_enum::tableau_costs: + prepare_costs_for_r_solver(term); + { + bool ret = maximize_term_on_tableau(term, term_max); + set_costs_to_zero(term); + m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); + return ret; + } + + case simplex_strategy_enum::lu: + lp_assert(false); // not implemented + return false; + default: + lp_unreachable(); // wrong mode + } + return false; +} +// starting from a given feasible state look for the maximum of the term +// return true if found and false if unbounded +bool lar_solver::maximize_term(const vector> & term, + impq &term_max) { + lp_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()); + m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false; + return maximize_term_on_corrected_r_solver(term, term_max); +} + + + +const lar_term & lar_solver::get_term(unsigned j) const { + lp_assert(j >= m_terms_start_index); + return *m_terms[j - m_terms_start_index]; +} + +void lar_solver::pop_core_solver_params() { + pop_core_solver_params(1); +} + +void lar_solver::pop_core_solver_params(unsigned k) { + A_r().pop(k); + A_d().pop(k); +} + + +void lar_solver::set_upper_bound_witness(var_index j, constraint_index ci) { + ul_pair ul = m_columns_to_ul_pairs[j]; + ul.upper_bound_witness() = ci; + m_columns_to_ul_pairs[j] = ul; +} + +void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) { + ul_pair ul = m_columns_to_ul_pairs[j]; + ul.low_bound_witness() = ci; + m_columns_to_ul_pairs[j] = ul; +} + +void lar_solver::register_monoid_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j) { + auto it = coeffs.find(j); + if (it == coeffs.end()) { + coeffs[j] = a; + } else { + it->second += a; + } +} + + +void lar_solver::substitute_terms_in_linear_expression(const vector>& left_side_with_terms, + vector> &left_side, mpq & free_coeff) const { + std::unordered_map coeffs; + for (auto & t : left_side_with_terms) { + unsigned j = t.second; + if (!is_term(j)) { + register_monoid_in_map(coeffs, t.first, j); + } else { + const lar_term & term = * m_terms[adjust_term_index(t.second)]; + for (auto & p : term.coeffs()){ + register_monoid_in_map(coeffs, t.first * p.second , p.first); + } + free_coeff += t.first * term.m_v; + } + } + + for (auto & p : coeffs) + left_side.push_back(std::make_pair(p.second, p.first)); +} + + +void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { + if (A_r().row_count() != m_column_buffer.data_size()) + m_column_buffer.resize(A_r().row_count()); + else + m_column_buffer.clear(); + lp_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); + + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + for (unsigned i : m_column_buffer.m_index) + m_rows_with_changed_bounds.insert(i); +} + + + +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); +} + +bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } + +bool lar_solver::use_tableau_costs() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; +} + +void lar_solver::detect_rows_of_column_with_bound_change(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { // it is a basic column + // just mark the row at touched and exit + m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + return; + } + + if (use_tableau()) + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + else + detect_rows_of_bound_change_column_for_nbasic_column(j); +} + +void lar_solver::adjust_x_of_column(unsigned j) { + lp_assert(false); +} + +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]; + return is_zero(r); +} + +bool lar_solver::ax_is_correct() const { + for (unsigned i = 0; i < A_r().row_count(); i++) { + if (!row_is_correct(i)) + return false; + } + return true; +} + +bool lar_solver::tableau_with_costs() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; +} + +bool lar_solver::costs_are_used() const { + return m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows; +} + +void lar_solver::change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair & delta) { + lp_assert(inf_int_set_is_correct()); + 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 (tableau_with_costs()) { + m_basic_columns_with_changed_cost.insert(bj); + } + m_mpq_lar_core_solver.m_r_solver.update_x_with_delta_and_track_feasibility(bj, - A_r().get_val(c) * delta); + TRACE("change_x_del", + tout << "changed basis column " << bj << ", it is " << + ( m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj)? "feas":"inf") << std::endl;); + + } + } else { + m_column_buffer.clear(); + m_column_buffer.resize(A_r().row_count()); + m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); + for (unsigned i : m_column_buffer.m_index) { + unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; + m_mpq_lar_core_solver.m_r_solver.update_x_with_delta_and_track_feasibility(bj, -m_column_buffer[i] * delta); + } + } + lp_assert(inf_int_set_is_correct()); +} + +void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + if (costs_are_used()) { + bool was_infeas = m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j); + m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); + if (was_infeas != m_mpq_lar_core_solver.m_r_solver.m_inf_set.contains(j)) + m_basic_columns_with_changed_cost.insert(j); + } else { + m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); + } + } else { + numeric_pair delta; + if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) + change_basic_columns_dependend_on_a_given_nb_column(j, delta); + } +} + + +void lar_solver::detect_rows_with_changed_bounds_for_column(unsigned j) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + return; + } + + if (use_tableau()) + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + else + detect_rows_of_bound_change_column_for_nbasic_column(j); +} + +void lar_solver::detect_rows_with_changed_bounds() { + for (auto j : m_columns_with_changed_bound.m_index) + detect_rows_with_changed_bounds_for_column(j); +} + +void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds() { + for (auto j : m_columns_with_changed_bound.m_index) + update_x_and_inf_costs_for_column_with_changed_bounds(j); +} + +void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { + for (auto j : m_columns_with_changed_bound.m_index) + update_x_and_inf_costs_for_column_with_changed_bounds(j); + + if (tableau_with_costs()) { + for (unsigned j : m_basic_columns_with_changed_cost.m_index) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + lp_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + } +} + + +void lar_solver::solve_with_core_solver() { + if (!use_tableau()) + add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); + if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { + add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); + } + m_mpq_lar_core_solver.prefix_r(); + if (costs_are_used()) { + m_basic_columns_with_changed_cost.clear(); + m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); + } + if (use_tableau()) + update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); + else + update_x_and_inf_costs_for_columns_with_changed_bounds(); + TRACE("intinf", m_int_solver->display_inf_or_int_inf_columns(tout);); + m_mpq_lar_core_solver.solve(); + set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); + lp_assert(inf_int_set_is_correct()); + lp_assert(m_status != lp_status::OPTIMAL || all_constraints_hold()); +} + + +numeric_pair lar_solver::get_basic_var_value_from_row_directly(unsigned i) { + numeric_pair r = zero_of_type>(); + + 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 (!is_zero(x)) + r -= c.m_value * x; + } + return r; +} + +numeric_pair lar_solver::get_basic_var_value_from_row(unsigned i) { + if (settings().use_tableau()) { + return get_basic_var_value_from_row_directly(i); + } + + numeric_pair r = zero_of_type>(); + m_mpq_lar_core_solver.calculate_pivot_row(i); + for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_index) { + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + r -= m_mpq_lar_core_solver.m_r_solver.m_pivot_row.m_data[j] * m_mpq_lar_core_solver.m_r_x[j]; + } + return r; +} + +template +void lar_solver::add_last_rows_to_lu(lp_primal_core_solver & s) { + auto & f = s.m_factorization; + if (f != nullptr) { + auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); + if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { + delete f; + f = nullptr; + } else { + f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); + } + } + if (f == nullptr) { + init_factorization(f, s.m_A, s.m_basis, m_settings); + if (f->get_status() != LU_status::OK) { + delete f; + f = nullptr; + } + } + +} + +bool lar_solver::x_is_correct() const { + if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { + // std::cout << "the size is off " << m_r_solver.m_x.size() << ", " << A().column_count() << std::endl; + return false; + } + for (unsigned i = 0; i < A_r().row_count(); i++) { + numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); + if (!delta.is_zero()) { + // std::cout << "x is off ("; + // std::cout << "m_b[" << i << "] = " << m_b[i] << " "; + // std::cout << "left side = " << A().dot_product_with_row(i, m_r_solver.m_x) << ' '; + // std::cout << "delta = " << delta << ' '; + // std::cout << "iters = " << total_iterations() << ")" << std::endl; + // std::cout << "row " << i << " is off" << std::endl; + return false; + } + } + return true;; + +} + +bool lar_solver::var_is_registered(var_index vj) const { + if (vj >= m_terms_start_index) { + if (vj - m_terms_start_index >= m_terms.size()) + return false; + } else if ( vj >= A_r().column_count()) { + return false; + } + return true; +} + +unsigned lar_solver::constraint_stack_size() const { + return m_constraint_count.stack_size(); +} + +void lar_solver::fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls) { + 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); + for (auto & t : ls->m_coeffs) { + lp_assert(!is_zero(t.second)); + var_index j = t.first; + A.set(last_row, j, - t.second); + } + unsigned basis_j = A.column_count() - 1; + A.set(last_row, basis_j, mpq(1)); +} + +template +void lar_solver::create_matrix_A(static_matrix & matr) { + lp_assert(false); // not implemented + /* + unsigned m = number_or_nontrivial_left_sides(); + unsigned n = m_vec_of_canonic_left_sides.size(); + if (matr.row_count() == m && matr.column_count() == n) + return; + matr.init_empty_matrix(m, n); + copy_from_mpq_matrix(matr); + */ +} + +template +void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { + matr.m_rows.resize(A_r().row_count()); + 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())); + } + } +} + + +bool lar_solver::try_to_set_fixed(column_info & ci) { + if (ci.upper_bound_is_set() && ci.low_bound_is_set() && ci.get_upper_bound() == ci.get_low_bound() && !ci.is_fixed()) { + ci.set_fixed_value(ci.get_upper_bound()); + return true; + } + return false; +} + +column_type lar_solver::get_column_type(const column_info & ci) { + auto ret = ci.get_column_type_no_flipping(); + if (ret == column_type::boxed) { // changing boxed to fixed because of the no span + if (ci.get_low_bound() == ci.get_upper_bound()) + ret = column_type::fixed; + } + return ret; +} + +std::string lar_solver::get_column_name(unsigned j) const { + if (j >= m_terms_start_index) + return std::string("_t") + T_to_string(j); + if (j >= m_columns_to_ext_vars_or_term_indices.size()) + return std::string("_s") + T_to_string(j); + + return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]); +} + +bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { + for (auto it : left_side) { + if (! var_is_registered(it.second)) + return false; + } + return true; +} + +bool lar_solver::all_constraints_hold() const { + if (m_settings.get_cancel_flag()) + return true; + std::unordered_map var_map; + get_model_do_not_care_about_diff_vars(var_map); + + for (unsigned i = 0; i < m_constraints.size(); i++) { + if (!constraint_holds(*m_constraints[i], var_map)) { + print_constraint(i, std::cout); + return false; + } + } + return true; +} + +bool lar_solver::constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const { + return true; + mpq left_side_val = get_left_side_val(constr, var_map); + switch (constr.m_kind) { + case LE: return left_side_val <= constr.m_right_side; + case LT: return left_side_val < constr.m_right_side; + case GE: return left_side_val >= constr.m_right_side; + case GT: return left_side_val > constr.m_right_side; + case EQ: return left_side_val == constr.m_right_side; + default: + lp_unreachable(); + } + return false; // it is unreachable +} + +bool lar_solver::the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const { + unsigned n_of_G = 0, n_of_L = 0; + bool strict = false; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lconstraint_kind kind = coeff.is_pos() ? + m_constraints[con_ind]->m_kind : + flip_kind(m_constraints[con_ind]->m_kind); + if (kind == GT || kind == LT) + strict = true; + if (kind == GE || kind == GT) n_of_G++; + else if (kind == LE || kind == LT) n_of_L++; + } + the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); + if (strict) + the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); + + return n_of_G == 0 || n_of_L == 0; +} + +void lar_solver::register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a) { + for (auto & it : cn.get_left_side_coefficients()) { + unsigned j = it.second; + auto p = coeffs.find(j); + if (p == coeffs.end()) + coeffs[j] = it.first * a; + else { + p->second += it.first * a; + if (p->second.is_zero()) + coeffs.erase(p); + } + } +} + +bool lar_solver::the_left_sides_sum_to_zero(const vector> & evidence) const { + std::unordered_map coeff_map; + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lp_assert(con_ind < m_constraints.size()); + register_in_map(coeff_map, *m_constraints[con_ind], coeff); + } + + if (!coeff_map.empty()) { + std::cout << "left side = "; + vector> t; + for (auto & it : coeff_map) { + t.push_back(std::make_pair(it.second, it.first)); + } + print_linear_combination_of_column_indices(t, std::cout); + std::cout << std::endl; + return false; + } + + return true; +} + +bool lar_solver::the_right_sides_do_not_sum_to_zero(const vector> & evidence) { + mpq ret = numeric_traits::zero(); + for (auto & it : evidence) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lp_assert(con_ind < m_constraints.size()); + const lar_constraint & constr = *m_constraints[con_ind]; + ret += constr.m_right_side * coeff; + } + return !numeric_traits::is_zero(ret); +} + +bool lar_solver::explanation_is_correct(const vector>& explanation) const { +#ifdef LEAN_DEBUG + lconstraint_kind kind; + lp_assert(the_relations_are_of_same_type(explanation, kind)); + lp_assert(the_left_sides_sum_to_zero(explanation)); + mpq rs = sum_of_right_sides_of_explanation(explanation); + switch (kind) { + case LE: lp_assert(rs < zero_of_type()); + break; + case LT: lp_assert(rs <= zero_of_type()); + break; + case GE: lp_assert(rs > zero_of_type()); + break; + case GT: lp_assert(rs >= zero_of_type()); + break; + case EQ: lp_assert(rs != zero_of_type()); + break; + default: + lp_assert(false); + return false; + } +#endif + return true; +} + +bool lar_solver::inf_explanation_is_correct() const { +#ifdef LEAN_DEBUG + vector> explanation; + get_infeasibility_explanation(explanation); + return explanation_is_correct(explanation); +#endif + return true; +} + +mpq lar_solver::sum_of_right_sides_of_explanation(const vector> & explanation) const { + mpq ret = numeric_traits::zero(); + for (auto & it : explanation) { + mpq coeff = it.first; + constraint_index con_ind = it.second; + lp_assert(con_ind < m_constraints.size()); + ret += (m_constraints[con_ind]->m_right_side - m_constraints[con_ind]->get_free_coeff_of_left_side()) * coeff; + } + return ret; +} + +bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { + + if (var >= m_columns_to_ul_pairs.size()) { + // TBD: bounds on terms could also be used, caller may have to track these. + return false; + } + const ul_pair & ul = m_columns_to_ul_pairs[var]; + ci = ul.low_bound_witness(); + if (ci != static_cast(-1)) { + auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var]; + value = p.x; + is_strict = p.y.is_pos(); + return true; + } + else { + return false; + } +} + +bool lar_solver::has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) { + + if (var >= m_columns_to_ul_pairs.size()) { + // TBD: bounds on terms could also be used, caller may have to track these. + return false; + } + const ul_pair & ul = m_columns_to_ul_pairs[var]; + ci = ul.upper_bound_witness(); + if (ci != static_cast(-1)) { + auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; + value = p.x; + is_strict = p.y.is_neg(); + return true; + } + else { + return false; + } +} + +void lar_solver::get_infeasibility_explanation(vector> & explanation) const { + explanation.clear(); + if (m_infeasible_column_index != -1) { + fill_explanation_from_infeasible_column(explanation); + return; + } + if (m_mpq_lar_core_solver.get_infeasible_sum_sign() == 0) { + return; + } + // the infeasibility sign + int inf_sign; + auto inf_row = m_mpq_lar_core_solver.get_infeasibility_info(inf_sign); + get_infeasibility_explanation_for_inf_sign(explanation, inf_row, inf_sign); + lp_assert(explanation_is_correct(explanation)); +} + + + +void lar_solver::get_infeasibility_explanation_for_inf_sign( + vector> & explanation, + const vector> & inf_row, + int inf_sign) const { + + for (auto & it : inf_row) { + mpq coeff = it.first; + unsigned j = it.second; + + int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; + const ul_pair & ul = m_columns_to_ul_pairs[j]; + + constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness(); + lp_assert(bound_constr_i < m_constraints.size()); + explanation.push_back(std::make_pair(coeff, bound_constr_i)); + } +} + +void lar_solver::get_model(std::unordered_map & variable_values) const { + mpq delta = mpq(1, 2); // start from 0.5 to have less clashes + lp_assert(m_status == lp_status::OPTIMAL); + unsigned i; + do { + // different pairs have to produce different singleton values + std::unordered_set set_of_different_pairs; + std::unordered_set set_of_different_singles; + delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); + for (i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { + const numeric_pair & rp = m_mpq_lar_core_solver.m_r_x[i]; + set_of_different_pairs.insert(rp); + mpq x = rp.x + delta * rp.y; + set_of_different_singles.insert(x); + if (set_of_different_pairs.size() + != set_of_different_singles.size()) { + delta /= mpq(2); + break; + } + + variable_values[i] = x; + } + } while (i != m_mpq_lar_core_solver.m_r_x.size()); +} + +void lar_solver::get_model_do_not_care_about_diff_vars(std::unordered_map & variable_values) const { + mpq delta = mpq(1); + delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(delta); + for (unsigned i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++ ) { + const impq & rp = m_mpq_lar_core_solver.m_r_x[i]; + variable_values[i] = rp.x + delta * rp.y; + } +} + + +std::string lar_solver::get_variable_name(var_index vi) const { + return get_column_name(vi); +} + +// ********** print region start +void lar_solver::print_constraint(constraint_index ci, std::ostream & out) const { + if (ci >= m_constraints.size()) { + out << "constraint " << T_to_string(ci) << " is not found"; + out << std::endl; + return; + } + + print_constraint(m_constraints[ci], out); +} + +void lar_solver::print_constraints(std::ostream& out) const { + for (auto c : m_constraints) { + print_constraint(c, out); + } +} + +void lar_solver::print_terms(std::ostream& out) const { + for (auto it : m_terms) { + print_term(*it, out); + out << "\n"; + } +} + +void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const { + print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out); + mpq free_coeff = c->get_free_coeff_of_left_side(); + if (!is_zero(free_coeff)) + out << " + " << free_coeff; + +} + +void lar_solver::print_term(lar_term const& term, std::ostream & out) const { + if (!numeric_traits::is_zero(term.m_v)) { + out << term.m_v << " + "; + } + print_linear_combination_of_column_indices(term.coeffs_as_vector(), out); +} + +void lar_solver::print_term_as_indices(lar_term const& term, std::ostream & out) const { + if (!numeric_traits::is_zero(term.m_v)) { + out << term.m_v << " + "; + } + print_linear_combination_of_column_indices_only(term.coeffs_as_vector(), out); +} + +mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const { + mpq ret = cns.get_free_coeff_of_left_side(); + for (auto & it : cns.get_left_side_coefficients()) { + var_index j = it.second; + auto vi = var_map.find(j); + lp_assert(vi != var_map.end()); + ret += it.first * vi->second; + } + return ret; +} + +void lar_solver::print_constraint(const lar_base_constraint * c, std::ostream & out) const { + print_left_side_of_constraint(c, out); + out << " " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side << std::endl; +} + +void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list) { + for (unsigned i = 0; i < sz; i++) { + var_index var = vars[i]; + if (var >= m_terms_start_index) { // handle the term + for (auto & it : m_terms[var - m_terms_start_index]->m_coeffs) { + column_list.push_back(it.first); + } + } else { + column_list.push_back(var); + } + } +} + +void lar_solver::random_update(unsigned sz, var_index const * vars) { + vector column_list; + fill_var_set_for_random_update(sz, vars, column_list); + random_updater ru(*this, column_list); + ru.update(); + lp_assert(inf_int_set_is_correct()); +} + + +void lar_solver::pivot_fixed_vars_from_basis() { + m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); +} + +void lar_solver::pop() { + pop(1); +} + +bool lar_solver::column_represents_row_in_tableau(unsigned j) { + return m_columns_to_ul_pairs()[j].m_i != static_cast(-1); +} + +void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { + // i, j - is the indices of the bottom-right element of the tableau + 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;){ + auto & cc = last_column[k]; + if (cc.m_i == 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); +} + +void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + auto & slv = m_mpq_lar_core_solver.m_r_solver; + unsigned i = A_r().row_count() - 1; //last row index + make_sure_that_the_bottom_right_elem_not_zero_in_tableau(i, j); + if (slv.m_basis_heading[j] < 0) { + slv.pivot_column_tableau(j, i); + } + + 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;) { + auto &rc = last_row[k]; + if (cost_is_nz) { + m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); + } + + A_r().remove_element(last_row, rc); + } + 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(); + 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); + A_r().m_columns.pop_back(); +} + +void lar_solver::remove_last_column_from_basis_tableau(unsigned j) { + auto& rslv = m_mpq_lar_core_solver.m_r_solver; + int i = rslv.m_basis_heading[j]; + if (i >= 0) { // j is a basic var + int last_pos = static_cast(rslv.m_basis.size()) - 1; + lp_assert(last_pos >= 0); + if (i != last_pos) { + unsigned j_at_last_pos = rslv.m_basis[last_pos]; + rslv.m_basis[i] = j_at_last_pos; + rslv.m_basis_heading[j_at_last_pos] = i; + } + rslv.m_basis.pop_back(); // remove j from the basis + } else { + int last_pos = static_cast(rslv.m_nbasis.size()) - 1; + lp_assert(last_pos >= 0); + i = - 1 - i; + if (i != last_pos) { + unsigned j_at_last_pos = rslv.m_nbasis[last_pos]; + rslv.m_nbasis[i] = j_at_last_pos; + rslv.m_basis_heading[j_at_last_pos] = - i - 1; + } + rslv.m_nbasis.pop_back(); // remove j from the basis + } + rslv.m_basis_heading.pop_back(); + lp_assert(rslv.m_basis.size() == A_r().row_count()); + lp_assert(rslv.basis_heading_is_correct()); +} + +void lar_solver::remove_last_column_from_tableau() { + auto& rslv = m_mpq_lar_core_solver.m_r_solver; + unsigned j = A_r().column_count() - 1; + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); + if (column_represents_row_in_tableau(j)) { + remove_last_row_and_column_from_tableau(j); + if (rslv.m_basis_heading[j] < 0) + rslv.change_basis_unconditionally(j, rslv.m_basis[A_r().row_count()]); // A_r().row_count() is the index of the last row in the basis still + } + else { + remove_last_column_from_A(); + } + rslv.m_x.pop_back(); + rslv.m_d.pop_back(); + rslv.m_costs.pop_back(); + + remove_last_column_from_basis_tableau(j); + lp_assert(m_mpq_lar_core_solver.r_basis_is_OK()); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); +} + +void lar_solver::pop_tableau() { + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); + // We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size(). + // At this moment m_column_names is already popped + while (A_r().column_count() > m_columns_to_ext_vars_or_term_indices.size()) + remove_last_column_from_tableau(); + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct()); +} + +void lar_solver::clean_inf_set_of_r_solver_after_pop() { + lp_assert(inf_int_set_is_correct()); + vector became_feas; + clean_popped_elements(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set); + std::unordered_set basic_columns_with_changed_cost; + auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index; + for (auto j: inf_index_copy) { + if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { + continue; + } + // some basic columns might become non-basic - these columns need to be made feasible + numeric_pair delta; + if (m_mpq_lar_core_solver.m_r_solver.make_column_feasible(j, delta)) { + + change_basic_columns_dependend_on_a_given_nb_column(j, delta); + } + became_feas.push_back(j); + } + + for (unsigned j : became_feas) { + lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis_heading[j] < 0); + m_mpq_lar_core_solver.m_r_solver.m_d[j] -= m_mpq_lar_core_solver.m_r_solver.m_costs[j]; + m_mpq_lar_core_solver.m_r_solver.m_costs[j] = zero_of_type(); + m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); + } + became_feas.clear(); + for (unsigned j : m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index) { + lp_assert(m_mpq_lar_core_solver.m_r_heading[j] >= 0); + if (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j)) + became_feas.push_back(j); + } + for (unsigned j : became_feas) + m_mpq_lar_core_solver.m_r_solver.m_inf_set.erase(j); + + + if (use_tableau_costs()) { + for (unsigned j : became_feas) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + for (unsigned j : basic_columns_with_changed_cost) + m_mpq_lar_core_solver.m_r_solver.update_inf_cost_for_column_tableau(j); + lp_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + } +} + +void lar_solver::shrink_explanation_to_minimum(vector> & explanation) const { + // implementing quickXplain + quick_xplain::run(explanation, *this); + lp_assert(this->explanation_is_correct(explanation)); +} + +bool lar_solver::model_is_int_feasible() const { + unsigned n = A_r().column_count(); + for (unsigned j = 0; j < n; j++) { + if (column_is_int(j) && !column_value_is_integer(j)) + return false; + } + return true; +} + +bool lar_solver::term_is_int(const lar_term * t) const { + for (auto const & p : t->m_coeffs) + if (! (column_is_int(p.first) && p.second.is_int())) + return false; + return t->m_v.is_int(); +} + +bool lar_solver::var_is_int(var_index v) const { + if (is_term(v)) { + lar_term const& t = get_term(v); + return term_is_int(&t); + } + else { + return column_is_int(v); + } +} + +bool lar_solver::column_is_int(unsigned j) const { + unsigned ext_var = m_columns_to_ext_vars_or_term_indices[j]; + lp_assert(contains(m_ext_vars_to_columns, ext_var)); + return m_ext_vars_to_columns.find(ext_var)->second.is_integer(); +} + +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 { + auto it = m_ext_vars_to_columns.find(ext_var); + lp_assert(it != m_ext_vars_to_columns.end()); + return it == m_ext_vars_to_columns.end() || it->second.is_integer(); +} + +// below is the initialization functionality of lar_solver + +bool lar_solver::strategy_is_undecided() const { + return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; +} + +var_index lar_solver::add_var(unsigned ext_j, bool is_int) { + TRACE("add_var", tout << "adding var " << ext_j << (is_int? " int" : " nonint") << std::endl;); + var_index i; + lp_assert(ext_j < m_terms_start_index); + + if (ext_j >= m_terms_start_index) + throw 0; // todo : what is the right way to exit? + auto it = m_ext_vars_to_columns.find(ext_j); + if (it != m_ext_vars_to_columns.end()) { + return it->second.ext_j(); + } + lp_assert(m_columns_to_ul_pairs.size() == A_r().column_count()); + i = A_r().column_count(); + m_columns_to_ul_pairs.push_back(ul_pair(static_cast(-1))); + add_non_basic_var_to_core_fields(ext_j, is_int); + lp_assert(sizes_are_correct()); + if (is_int) { + m_mpq_lar_core_solver.m_r_solver.set_tracker_of_x(& m_tracker_of_x_change); + } + lp_assert(inf_int_set_is_correct()); + return i; +} + +void lar_solver::register_new_ext_var_index(unsigned ext_v, bool is_int) { + lp_assert(!contains(m_ext_vars_to_columns, ext_v)); + unsigned j = static_cast(m_ext_vars_to_columns.size()); + m_ext_vars_to_columns.insert(std::make_pair(ext_v, ext_var_info(j, is_int))); + lp_assert(m_columns_to_ext_vars_or_term_indices.size() == j); + m_columns_to_ext_vars_or_term_indices.push_back(ext_v); +} + +void lar_solver::add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int) { + register_new_ext_var_index(ext_j, is_int); + m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); + m_columns_with_changed_bound.increase_size_by_one(); + m_inf_int_set.increase_size_by_one(); + add_new_var_to_core_fields_for_mpq(false); + if (use_lu()) + add_new_var_to_core_fields_for_doubles(false); +} + +void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) { + unsigned j = A_d().column_count(); + A_d().add_column(); + lp_assert(m_mpq_lar_core_solver.m_d_x.size() == j); + // lp_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_d_x.resize(j + 1); + m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); + lp_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_d().add_row(); + m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); + m_mpq_lar_core_solver.m_d_basis.push_back(j); + } + else { + m_mpq_lar_core_solver.m_d_heading.push_back(-static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_d_nbasis.push_back(j); + } +} + +void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) { + unsigned j = A_r().column_count(); + A_r().add_column(); + lp_assert(m_mpq_lar_core_solver.m_r_x.size() == j); + // lp_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_r_x.resize(j + 1); + m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one(); + m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1); + m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1); + lp_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_r().add_row(); + m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); + m_mpq_lar_core_solver.m_r_basis.push_back(j); + if (m_settings.bound_propagation()) + m_rows_with_changed_bounds.insert(A_r().row_count() - 1); + } + else { + m_mpq_lar_core_solver.m_r_heading.push_back(-static_cast(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_r_nbasis.push_back(j); + } +} + + +var_index lar_solver::add_term_undecided(const vector> & coeffs, + const mpq &m_v) { + m_terms.push_back(new lar_term(coeffs, m_v)); + return m_terms_start_index + m_terms.size() - 1; +} + +// terms +var_index lar_solver::add_term(const vector> & coeffs, + const mpq &m_v) { + if (strategy_is_undecided()) + return add_term_undecided(coeffs, m_v); + + m_terms.push_back(new lar_term(coeffs, m_v)); + unsigned adjusted_term_index = m_terms.size() - 1; + var_index ret = m_terms_start_index + adjusted_term_index; + if (use_tableau() && !coeffs.empty()) { + add_row_from_term_no_constraint(m_terms.back(), ret); + if (m_settings.bound_propagation()) + m_rows_with_changed_bounds.insert(A_r().row_count() - 1); + } + lp_assert(m_ext_vars_to_columns.size() == A_r().column_count()); + return ret; +} + +void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) { + register_new_ext_var_index(term_ext_index, term_is_int(term)); + // j will be a new variable + unsigned j = A_r().column_count(); + ul_pair ul(j); + m_columns_to_ul_pairs.push_back(ul); + add_basic_var_to_core_fields(); + if (use_tableau()) { + auto it = iterator_on_term_with_basis_var(*term, j); + A_r().fill_last_row_with_pivoting(it, + m_mpq_lar_core_solver.m_r_solver.m_basis_heading); + m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type()); + } + else { + fill_last_row_of_A_r(A_r(), term); + } + m_mpq_lar_core_solver.m_r_solver.update_x_and_call_tracker(j, get_basic_var_value_from_row_directly(A_r().row_count() - 1)); + if (use_lu()) + fill_last_row_of_A_d(A_d(), term); + lp_assert(inf_int_set_is_correct()); +} + +void lar_solver::add_basic_var_to_core_fields() { + bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); + lp_assert(!use_lu || A_r().column_count() == A_d().column_count()); + m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); + m_columns_with_changed_bound.increase_size_by_one(); + m_rows_with_changed_bounds.increase_size_by_one(); + m_inf_int_set.increase_size_by_one(); + add_new_var_to_core_fields_for_mpq(true); + if (use_lu) + add_new_var_to_core_fields_for_doubles(true); +} + +bool lar_solver::bound_is_integer_if_needed(unsigned j, const mpq & right_side) const { + if (!column_is_int(j)) + return true; + return right_side.is_int(); +} + +constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) { + TRACE("lar_solver", tout << "j = " << j << std::endl;); + constraint_index ci = m_constraints.size(); + if (!is_term(j)) { // j is a var + lp_assert(bound_is_integer_if_needed(j, right_side)); + auto vc = new lar_var_constraint(j, kind, right_side); + m_constraints.push_back(vc); + update_column_type_and_bound(j, kind, right_side, ci); + } + else { + add_var_bound_on_constraint_for_term(j, kind, right_side, ci); + } + lp_assert(sizes_are_correct()); + lp_assert(inf_int_set_is_correct()); + return ci; +} + +void lar_solver::update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) { + switch (m_mpq_lar_core_solver.m_column_types[j]) { + case column_type::free_column: + update_free_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::boxed: + update_boxed_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::low_bound: + update_low_bound_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::upper_bound: + update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index); + break; + case column_type::fixed: + update_fixed_column_type_and_bound(j, kind, right_side, constr_index); + break; + default: + lp_assert(false); // cannot be here + } +} + +void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lp_assert(is_term(j)); + unsigned adjusted_term_index = adjust_term_index(j); + lp_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int()); + auto it = m_ext_vars_to_columns.find(j); + if (it != m_ext_vars_to_columns.end()) { + unsigned term_j = it->second.ext_j(); + mpq rs = right_side - m_terms[adjusted_term_index]->m_v; + m_constraints.push_back(new lar_term_constraint(m_terms[adjusted_term_index], kind, right_side)); + update_column_type_and_bound(term_j, kind, rs, ci); + } + else { + add_constraint_from_term_and_create_new_column_row(j, m_terms[adjusted_term_index], kind, right_side); + } +} + +constraint_index lar_solver::add_constraint(const vector>& left_side_with_terms, lconstraint_kind kind_par, const mpq& right_side_parm) { + vector> left_side; + mpq rs = -right_side_parm; + substitute_terms_in_linear_expression(left_side_with_terms, left_side, rs); + unsigned term_index = add_term(left_side, zero_of_type()); + constraint_index ci = m_constraints.size(); + add_var_bound_on_constraint_for_term(term_index, kind_par, -rs, ci); + return ci; +} + +void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, + lconstraint_kind kind, const mpq & right_side) { + + add_row_from_term_no_constraint(term, term_j); + unsigned j = A_r().column_count() - 1; + update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size()); + m_constraints.push_back(new lar_term_constraint(term, kind, right_side)); + lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); +} + +void lar_solver::decide_on_strategy_and_adjust_initial_state() { + lp_assert(strategy_is_undecided()); + if (m_columns_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { + m_settings.simplex_strategy() = simplex_strategy_enum::lu; + } + else { + m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs? + } + adjust_initial_state(); +} + +void lar_solver::adjust_initial_state() { + switch (m_settings.simplex_strategy()) { + case simplex_strategy_enum::lu: + adjust_initial_state_for_lu(); + break; + case simplex_strategy_enum::tableau_rows: + adjust_initial_state_for_tableau_rows(); + break; + case simplex_strategy_enum::tableau_costs: + lp_assert(false); // not implemented + case simplex_strategy_enum::undecided: + adjust_initial_state_for_tableau_rows(); + break; + } +} + +void lar_solver::adjust_initial_state_for_lu() { + copy_from_mpq_matrix(A_d()); + unsigned n = A_d().column_count(); + m_mpq_lar_core_solver.m_d_x.resize(n); + m_mpq_lar_core_solver.m_d_low_bounds.resize(n); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); + m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; + m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; + + /* + unsigned j = A_d().column_count(); + A_d().add_column(); + lp_assert(m_mpq_lar_core_solver.m_d_x.size() == j); + // lp_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later + m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); + m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1); + m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); + lp_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method + if (register_in_basis) { + A_d().add_row(); + m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); + m_mpq_lar_core_solver.m_d_basis.push_back(j); + }else { + m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); + m_mpq_lar_core_solver.m_d_nbasis.push_back(j); + }*/ +} + +void lar_solver::adjust_initial_state_for_tableau_rows() { + for (unsigned j = 0; j < m_terms.size(); j++) { + if (contains(m_ext_vars_to_columns, j + m_terms_start_index)) + continue; + add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index); + } +} + +// this fills the last row of A_d and sets the basis column: -1 in the last column of the row +void lar_solver::fill_last_row_of_A_d(static_matrix & A, const lar_term* ls) { + 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].empty()); + + 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()); + } + + unsigned basis_j = A.column_count() - 1; + A.set(last_row, basis_j, -1); +} + +void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound; + lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + lp_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + { + auto up = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + } + set_upper_bound_witness(j, constr_ind); + break; + case GT: + y_of_bound = 1; + case GE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound; + lp_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j); + { + auto low = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + } + set_low_bound_witness(j, constr_ind); + break; + case EQ: + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair(right_side, zero_of_type()); + set_upper_bound_witness(j, constr_ind); + set_low_bound_witness(j, constr_ind); + break; + + default: + lp_unreachable(); + + } + m_columns_with_changed_bound.insert(j); +} + +void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + if (up < m_mpq_lar_core_solver.m_r_upper_bounds()[j]) { + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + } + } + break; + case GT: + y_of_bound = 1; + case GE: + m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed; + { + auto low = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + set_low_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + } + else { + m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j] ? column_type::boxed : column_type::fixed; + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = lp_status::INFEASIBLE; + set_low_bound_witness(j, ci); + m_infeasible_column_index = j; + } + else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + break; + } + break; + + default: + lp_unreachable(); + + } +} + +void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + } + + if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = lp_status::INFEASIBLE; + lp_assert(false); + m_infeasible_column_index = j; + } + else { + if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]) + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + } + break; + case GT: + y_of_bound = 1; + case GE: + { + auto low = numeric_pair(right_side, y_of_bound); + if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + } + if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + } + else if (low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + m_columns_with_changed_bound.insert(j); + } + + break; + } + + default: + lp_unreachable(); + + } +} +void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lp_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound); + mpq y_of_bound(0); + switch (kind) { + case LT: + y_of_bound = -1; + case LE: + { + auto up = numeric_pair(right_side, y_of_bound); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, ci); + m_columns_with_changed_bound.insert(j); + + if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + } + else { + m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j] ? column_type::boxed : column_type::fixed; + } + } + break; + case GT: + y_of_bound = 1; + case GE: + { + auto low = numeric_pair(right_side, y_of_bound); + if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_mpq_lar_core_solver.m_r_low_bounds[j] = low; + m_columns_with_changed_bound.insert(j); + set_low_bound_witness(j, ci); + } + } + break; + case EQ: + { + auto v = numeric_pair(right_side, zero_of_type()); + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + else { + m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v; + set_low_bound_witness(j, ci); + set_upper_bound_witness(j, ci); + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + } + m_columns_with_changed_bound.insert(j); + break; + } + + default: + lp_unreachable(); + + } +} + +void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) { + lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])); + lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero())); + auto v = numeric_pair(right_side, mpq(0)); + + mpq y_of_bound(0); + switch (kind) { + case LT: + if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + break; + case LE: + { + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + } + break; + case GT: + { + if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + } + break; + case GE: + { + if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + } + break; + case EQ: + { + if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_upper_bound_witness(j, ci); + } + else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { + m_status = lp_status::INFEASIBLE; + m_infeasible_column_index = j; + set_low_bound_witness(j, ci); + } + break; + } + + default: + lp_unreachable(); + + } +} + + +} // namespace lp + + diff --git a/src/util/lp/lar_solver_instances.cpp b/src/util/lp/lar_solver_instances.cpp index 602df0326..2c8747ad4 100644 --- a/src/util/lp/lar_solver_instances.cpp +++ b/src/util/lp/lar_solver_instances.cpp @@ -3,7 +3,7 @@ Author: Lev Nachmanson */ -#include "util/lp/lar_solver.cpp" +#include "util/lp/lar_solver.hpp" template void lp::lar_solver::copy_from_mpq_matrix(class lp::static_matrix &); From 7a4a2b6b5bf97b68b8f4c38ee1e201ea3fc5540a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:51:22 -0800 Subject: [PATCH 0543/1283] remove file Signed-off-by: Nikolaj Bjorner --- src/util/lp/lar_solver_instances.cpp | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/util/lp/lar_solver_instances.cpp diff --git a/src/util/lp/lar_solver_instances.cpp b/src/util/lp/lar_solver_instances.cpp deleted file mode 100644 index 2c8747ad4..000000000 --- a/src/util/lp/lar_solver_instances.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ - -#include "util/lp/lar_solver.hpp" - -template void lp::lar_solver::copy_from_mpq_matrix(class lp::static_matrix &); - - - - - From 42cc7c7f872fde48a3c3ad4dd396a23a4cb19403 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:53:24 -0800 Subject: [PATCH 0544/1283] remove file Signed-off-by: Nikolaj Bjorner --- src/util/lp/{nra_solver.cpp => nra_solver.cpp2} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/util/lp/{nra_solver.cpp => nra_solver.cpp2} (100%) diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp2 similarity index 100% rename from src/util/lp/nra_solver.cpp rename to src/util/lp/nra_solver.cpp2 From d684d4fce0ab7e5521b9c0670ab7d3514cb3ca93 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 15:57:25 -0800 Subject: [PATCH 0545/1283] dbl-max Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 10 +++++----- src/sat/sat_lookahead.cpp | 4 ++-- src/sat/sat_lookahead.h | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index f7b9e7749..517bd4593 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1070,7 +1070,7 @@ namespace sat { m_overflow = true; return UINT_MAX; } - return static_cast(abs(c)); + return static_cast(std::abs(c)); } int ba_solver::get_int_coeff(bool_var v) const { @@ -1376,16 +1376,16 @@ namespace sat { unsigned acoeff = get_abs_coeff(v); if (lvl(lit) == m_conflict_lvl) { if (m_lemma[0] == null_literal) { - asserting_coeff = abs(coeff); + asserting_coeff = std::abs(coeff); slack -= asserting_coeff; m_lemma[0] = ~lit; } else { ++num_skipped; - if (asserting_coeff < abs(coeff)) { + if (asserting_coeff < std::abs(coeff)) { m_lemma[0] = ~lit; - slack -= (abs(coeff) - asserting_coeff); - asserting_coeff = abs(coeff); + slack -= (std::abs(coeff) - asserting_coeff); + asserting_coeff = std::abs(coeff); } } } diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 804f06341..cd3b0e19b 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2082,7 +2082,7 @@ namespace sat { if (inconsistent()) { TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); m_cube_state.m_freevars_threshold = m_freevars.size(); - m_cube_state.m_psat_threshold = m_config.m_cube_cutoff == adaptive_psat_cutoff ? psat_heur() : DBL_MAX; // MN. only compute PSAT if enabled + m_cube_state.m_psat_threshold = m_config.m_cube_cutoff == adaptive_psat_cutoff ? psat_heur() : dbl_max; // MN. only compute PSAT if enabled m_cube_state.inc_conflict(); if (!backtrack(m_cube_state.m_cube, m_cube_state.m_is_decision)) return l_false; continue; @@ -2119,7 +2119,7 @@ namespace sat { return l_undef; } int prev_nfreevars = m_freevars.size(); - double prev_psat = m_config.m_cube_cutoff == adaptive_psat_cutoff ? psat_heur() : DBL_MAX; // MN. only compute PSAT if enabled + double prev_psat = m_config.m_cube_cutoff == adaptive_psat_cutoff ? psat_heur() : dbl_max; // MN. only compute PSAT if enabled literal lit = choose(); if (inconsistent()) { TRACE("sat", tout << "inconsistent: " << m_cube_state.m_cube << "\n";); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index f81417d41..b86b7cb14 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -60,6 +60,8 @@ namespace sat { return out; } + const double dbl_max = 100000000.0; + class lookahead { solver& m_s; unsigned m_num_vars; @@ -186,7 +188,7 @@ namespace sat { m_is_decision.reset(); m_cube.reset(); m_freevars_threshold = 0; - m_psat_threshold = 100000000.0; + m_psat_threshold = dbl_max; reset_stats(); } void reset_stats() { m_conflicts = 0; m_cutoffs = 0; } From d7f2638ecf5d0f2fa95fe442f2109550a9c968a8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 16:03:14 -0800 Subject: [PATCH 0546/1283] reference get_wlist Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 4 ++-- src/sat/sat_simplifier.cpp | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 517bd4593..6486380dd 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1390,7 +1390,7 @@ namespace sat { } } else { - slack -= abs(coeff); + slack -= std::abs(coeff); m_lemma.push_back(~lit); } } @@ -3655,7 +3655,7 @@ namespace sat { m_active_var_set.insert(v); literal lit(v, coeff < 0); p.m_lits.push_back(lit); - p.m_coeffs.push_back(abs(coeff)); + p.m_coeffs.push_back(std::abs(coeff)); } } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index a18743438..f773b05e7 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -71,11 +71,11 @@ namespace sat { finalize(); } - inline watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); } + watch_list & simplifier::get_wlist(literal l) { return s.get_wlist(l); } - inline watch_list const & simplifier::get_wlist(literal l) const { return s.get_wlist(l); } + watch_list const & simplifier::get_wlist(literal l) const { return s.get_wlist(l); } - inline bool simplifier::is_external(bool_var v) const { + bool simplifier::is_external(bool_var v) const { return s.is_assumption(v) || (s.is_external(v) && s.is_incremental()) || @@ -1317,16 +1317,15 @@ namespace sat { m_ala_qhead = 0; switch (et) { - case abce_t: - case bce_t: - k = model_converter::BLOCK_LIT; - break; case cce_t: k = model_converter::CCE; break; case acce_t: k = model_converter::ACCE; break; + default: + k = model_converter::BLOCK_LIT; + break; } /* From 064a7f9097da8af84ffa8e601f6303de41c92591 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 16:05:06 -0800 Subject: [PATCH 0547/1283] remove tautology Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 6486380dd..41d043526 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1318,7 +1318,7 @@ namespace sat { m_overflow = false; - while (m_num_marks > 0 && idx >= 0) { + while (m_num_marks > 0) { bool_var v = lits[idx].var(); if (s().is_marked(v)) { s().reset_mark(v); From 615e1e08450d4a48038cb0b8c36727e4bb0eee0a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 17:17:27 -0800 Subject: [PATCH 0548/1283] remove redundant tactic Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 6 +- src/tactic/arith/CMakeLists.txt | 2 - src/tactic/arith/elim01_tactic.cpp | 266 ----------------------------- src/tactic/arith/elim01_tactic.h | 33 ---- 4 files changed, 2 insertions(+), 305 deletions(-) delete mode 100644 src/tactic/arith/elim01_tactic.cpp delete mode 100644 src/tactic/arith/elim01_tactic.h diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e62a1c647..5c0c09125 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -27,7 +27,6 @@ Notes: #include "tactic/goal.h" #include "tactic/tactic.h" #include "tactic/arith/lia2card_tactic.h" -#include "tactic/arith/elim01_tactic.h" #include "tactic/core/solve_eqs_tactic.h" #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" @@ -736,12 +735,11 @@ namespace opt { if (optp.elim_01()) { tac1 = mk_dt2bv_tactic(m); tac2 = mk_lia2card_tactic(m); - tac3 = mk_elim01_tactic(m); - tac4 = mk_eq2bv_tactic(m); + tac3 = mk_eq2bv_tactic(m); params_ref lia_p; lia_p.set_bool("compile_equality", optp.pb_compile_equality()); tac3->updt_params(lia_p); - set_simplify(and_then(tac0.get(), tac1.get(), tac2.get(), tac3.get(), tac4.get(), mk_simplify_tactic(m))); + set_simplify(and_then(tac0.get(), tac1.get(), tac2.get(), tac3.get(), mk_simplify_tactic(m))); } else { set_simplify(tac0.get()); diff --git a/src/tactic/arith/CMakeLists.txt b/src/tactic/arith/CMakeLists.txt index 335020838..cb025b206 100644 --- a/src/tactic/arith/CMakeLists.txt +++ b/src/tactic/arith/CMakeLists.txt @@ -9,7 +9,6 @@ z3_add_component(arith_tactics card2bv_tactic.cpp degree_shift_tactic.cpp diff_neq_tactic.cpp - elim01_tactic.cpp eq2bv_tactic.cpp factor_tactic.cpp fix_dl_var_tactic.cpp @@ -33,7 +32,6 @@ z3_add_component(arith_tactics card2bv_tactic.h degree_shift_tactic.h diff_neq_tactic.h - elim01_tactic.h eq2bv_tactic.h factor_tactic.h fix_dl_var_tactic.h diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp deleted file mode 100644 index a287e7a83..000000000 --- a/src/tactic/arith/elim01_tactic.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - elim01_tactic.cpp - -Abstract: - - Replace 0-1 integer variables by Booleans. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-12-7 - -Notes: - ---*/ -#include "tactic/tactical.h" -#include "util/cooperate.h" -#include "tactic/arith/bound_manager.h" -#include "ast/ast_pp.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/arith_decl_plugin.h" -#include "tactic/arith/elim01_tactic.h" -#include "model/model_smt2_pp.h" -#include "ast/rewriter/th_rewriter.h" - -class bool2int_model_converter : public model_converter { - ast_manager& m; - arith_util a; - func_decl_ref_vector m_refs; - obj_hashtable m_bools; - vector > m_nums_as_bool; - ptr_vector m_nums_as_int; -public: - - bool2int_model_converter(ast_manager& m): - m(m), - a(m), - m_refs(m) - {} - - virtual void operator()(model_ref & old_model) { - model * new_model = alloc(model, m); - unsigned num = old_model->get_num_constants(); - for (unsigned i = 0; i < m_nums_as_int.size(); ++i) { - func_decl* f_old = m_nums_as_int[i]; - rational val(0); - rational po(1); - bool is_value = true; - for (unsigned j = 0; is_value && j < m_nums_as_bool[i].size(); ++j) { - func_decl* f = m_nums_as_bool[i][j]; - expr* fi = old_model->get_const_interp(f); - if (!fi) { - is_value = false; - } - else if (m.is_true(fi)) { - val += po; - } - else if (!m.is_false(fi)) { - is_value = false; - } - po *= rational(2); - } - if (is_value) { - expr* fi = a.mk_numeral(val, true); - new_model->register_decl(f_old, fi); - } - } - for (unsigned i = 0; i < num; ++i) { - func_decl* f = old_model->get_constant(i); - expr* fi = old_model->get_const_interp(f); - if (!m_bools.contains(f)) { - new_model->register_decl(f, fi); - } - } - num = old_model->get_num_functions(); - for (unsigned i = 0; i < num; i++) { - func_decl * f = old_model->get_function(i); - func_interp * fi = old_model->get_func_interp(f); - new_model->register_decl(f, fi->copy()); - } - new_model->copy_usort_interps(*old_model); - old_model = new_model; - } - - void insert(func_decl* x_new, func_decl* x_old) { - m_refs.push_back(x_new); - m_refs.push_back(x_old); - m_bools.insert(x_new); - m_nums_as_int.push_back(x_old); - m_nums_as_bool.push_back(ptr_vector()); - m_nums_as_bool.back().push_back(x_new); - } - - void insert(func_decl* x_old, unsigned sz, func_decl * const* x_new) { - m_nums_as_int.push_back(x_old); - m_nums_as_bool.push_back(ptr_vector()); - m_refs.push_back(x_old); - for (unsigned i = 0; i < sz; ++i) { - m_refs.push_back(x_new[i]); - m_nums_as_bool.back().push_back(x_new[i]); - m_bools.insert(x_new[i]); - } - } - - virtual model_converter * translate(ast_translation & translator) { - bool2int_model_converter* mc = alloc(bool2int_model_converter, translator.to()); - for (unsigned i = 0; i < m_nums_as_int.size(); ++i) { - mc->insert(m_nums_as_int[i], m_nums_as_bool[i].size(), m_nums_as_bool[i].c_ptr()); - } - return mc; - } - - virtual void display(std::ostream & out) { - out << "(elim01-model-converter)\n"; - } - -}; - - -class elim01_tactic : public tactic { -public: - typedef obj_hashtable expr_set; - ast_manager & m; - arith_util a; - th_rewriter m_rewriter; - params_ref m_params; - unsigned m_max_hi_default; - rational m_max_hi; - - elim01_tactic(ast_manager & _m, params_ref const & p): - m(_m), - a(m), - m_rewriter(m), - m_max_hi_default(8), - m_max_hi(rational(m_max_hi_default)) { - } - - virtual ~elim01_tactic() { - } - - virtual void updt_params(params_ref const & p) { - m_max_hi = rational(p.get_uint("max_coefficient", m_max_hi_default)); - m_params = p; - } - - virtual void collect_param_descrs(param_descrs & r) { - r.insert("max_coefficient", CPK_UINT, "(default: 1) maximal upper bound for finite range -> Bool conversion"); - } - - - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result) { - SASSERT(g->is_well_sorted()); - - tactic_report report("elim01", *g); - - expr_safe_replace sub(m); - ref b2i = alloc(bool2int_model_converter, m); - bound_manager bounds(m); - expr_ref_vector axioms(m); - bounds(*g); - - rational zero(0); - bound_manager::iterator bit = bounds.begin(), bend = bounds.end(); - for (; bit != bend; ++bit) { - if (!is_app(*bit)) continue; - app* x = to_app(*bit); - bool s1 = false, s2 = false; - rational lo, hi; - if (a.is_int(x) && - bounds.has_lower(x, lo, s1) && !s1 && zero <= lo && - bounds.has_upper(x, hi, s2) && !s2 && hi <= m_max_hi && lo <= hi) { - add_variable(b2i.get(), sub, x, lo.get_unsigned(), hi.get_unsigned(), axioms); - } - else if (a.is_int(x)) { - TRACE("pb", tout << "Not adding variable " << mk_pp(x, m) << " has lower: " - << bounds.has_lower(x, lo, s1) << " " << lo << " has upper: " - << bounds.has_upper(x, hi, s2) << " " << hi << "\n";); - } - } - - if (sub.empty()) { - result.push_back(g.get()); - return; - } - - expr_ref new_curr(m), tmp_curr(m); - proof_ref new_pr(m); - for (unsigned i = 0; i < g->size(); i++) { - expr * curr = g->form(i); - sub(curr, tmp_curr); - m_rewriter(tmp_curr, new_curr); - if (m.proofs_enabled()) { - new_pr = m.mk_rewrite(curr, new_curr); - new_pr = m.mk_modus_ponens(g->pr(i), new_pr); - } - g->update(i, new_curr, new_pr, g->dep(i)); - } - for (expr* a : axioms) - g->assert_expr(a); - g->add(b2i.get()); - g->inc_depth(); - result.push_back(g.get()); - TRACE("pb", g->display(tout);); - SASSERT(g->is_well_sorted()); - - // TBD: support proof conversion (or not..) - } - - virtual tactic * translate(ast_manager & m) { - return alloc(elim01_tactic, m, m_params); - } - - virtual void cleanup() {} - - void add_variable(bool2int_model_converter* b2i, - expr_safe_replace& sub, - app* x, - unsigned min_value, - unsigned max_value, - expr_ref_vector& axioms) { - std::string name = x->get_decl()->get_name().str(); - unsigned sh = 0; - app_ref_vector xs(m), ites(m); - func_decl_ref_vector xfs(m); - app_ref zero(m), sum(m); - zero = a.mk_numeral(rational(0), true); - while (max_value >= (1ul << sh)) { - xs.push_back(m.mk_fresh_const(name.c_str(), m.mk_bool_sort())); - xfs.push_back(xs.back()->get_decl()); - ites.push_back(m.mk_ite(xs.back(), a.mk_numeral(rational(1 << sh), true), zero)); - ++sh; - } - switch (ites.size()) { - case 0: - sum = zero; - break; - case 1: - sum = ites[0].get(); - break; - default: - sum = a.mk_add(ites.size(), (expr*const*)ites.c_ptr()); - break; - } - TRACE("pb", tout << mk_pp(x, m) << " " << sum << " max: " << max_value << "\n";); - - sub.insert(x, sum); - b2i->insert(x->get_decl(), xfs.size(), xfs.c_ptr()); - // if max_value+1 is not a power of two: - if ((max_value & (max_value + 1)) != 0) { - axioms.push_back(a.mk_le(sum, a.mk_numeral(rational(max_value), true))); - } - if (min_value > 0) { - axioms.push_back(a.mk_ge(sum, a.mk_numeral(rational(min_value), true))); - } - } - -}; - -tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(elim01_tactic, m, p)); -} - diff --git a/src/tactic/arith/elim01_tactic.h b/src/tactic/arith/elim01_tactic.h deleted file mode 100644 index d9cd3a2ed..000000000 --- a/src/tactic/arith/elim01_tactic.h +++ /dev/null @@ -1,33 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - elim01_tactic.h - -Abstract: - - Replace 0-1 integer variables by Booleans. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-12-7 - -Notes: - ---*/ -#ifndef ELIM01_TACTIC_H_ -#define ELIM01_TACTIC_H_ - -#include "util/params.h" -class ast_manager; -class tactic; - -tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p = params_ref()); - -/* - ADD_TACTIC("elim01", "eliminate 0-1 integer variables, replace them by Booleans.", "mk_elim01_tactic(m, p)") -*/ - - -#endif From 61934d81061344e9c15b03e9ab0ab0d8025b64a2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 20:08:15 -0800 Subject: [PATCH 0549/1283] align semantics of re.allchar with string proposal. #1475 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 5 ++-- src/api/api_seq.cpp | 2 +- src/ast/rewriter/seq_rewriter.cpp | 41 ++++++++++++++++++++++--------- src/ast/seq_decl_plugin.cpp | 25 +++++++++++++------ src/ast/seq_decl_plugin.h | 11 ++++++--- src/smt/theory_seq.cpp | 3 ++- src/smt/theory_str.cpp | 11 ++++++--- 7 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index ae23ca100..6c39ad07d 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1115,7 +1115,7 @@ extern "C" { case _OP_STRING_SUBSTR: return Z3_OP_SEQ_EXTRACT; case _OP_STRING_STRIDOF: return Z3_OP_SEQ_INDEX; case _OP_REGEXP_EMPTY: return Z3_OP_RE_EMPTY_SET; - case _OP_REGEXP_FULL: return Z3_OP_RE_FULL_SET; + case _OP_REGEXP_FULL_CHAR: return Z3_OP_RE_FULL_SET; case OP_STRING_STOI: return Z3_OP_STR_TO_INT; case OP_STRING_ITOS: return Z3_OP_INT_TO_STR; @@ -1127,7 +1127,8 @@ extern "C" { case OP_RE_UNION: return Z3_OP_RE_UNION; case OP_RE_INTERSECT: return Z3_OP_RE_INTERSECT; case OP_RE_LOOP: return Z3_OP_RE_LOOP; - case OP_RE_FULL_SET: return Z3_OP_RE_FULL_SET; + // case OP_RE_FULL_SEQ_SET: return Z3_OP_RE_FULL_SET; + case OP_RE_FULL_CHAR_SET: return Z3_OP_RE_FULL_SET; case OP_RE_EMPTY_SET: return Z3_OP_RE_EMPTY_SET; default: return Z3_OP_INTERNAL; diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 44003a5fb..428d86d0d 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -165,7 +165,7 @@ extern "C" { MK_BINARY(Z3_mk_re_range, mk_c(c)->get_seq_fid(), OP_RE_RANGE, SKIP); MK_SORTED(Z3_mk_re_empty, mk_c(c)->sutil().re.mk_empty); - MK_SORTED(Z3_mk_re_full, mk_c(c)->sutil().re.mk_full); + MK_SORTED(Z3_mk_re_full, mk_c(c)->sutil().re.mk_full_seq); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index fa95278b4..ec3e72cc4 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -286,7 +286,7 @@ eautomaton* re2automaton::re2aut(expr* e) { else if (u.re.is_empty(e)) { return alloc(eautomaton, sm); } - else if (u.re.is_full(e)) { + else if (u.re.is_full_seq(e)) { expr_ref tt(m.mk_true(), m); sort *seq_s = 0, *char_s = 0; VERIFY (u.is_re(m.get_sort(e), seq_s)); @@ -294,6 +294,15 @@ eautomaton* re2automaton::re2aut(expr* e) { sym_expr* _true = sym_expr::mk_pred(tt, char_s); return eautomaton::mk_loop(sm, _true); } + else if (u.re.is_full_char(e)) { + expr_ref tt(m.mk_true(), m); + sort *seq_s = 0, *char_s = 0; + VERIFY (u.is_re(m.get_sort(e), seq_s)); + VERIFY (u.is_seq(seq_s, char_s)); + sym_expr* _true = sym_expr::mk_pred(tt, char_s); + a = alloc(eautomaton, sm, _true); + return a.detach(); + } else if (u.re.is_intersection(e, e1, e2) && m_sa && (a = re2aut(e1)) && (b = re2aut(e2))) { return m_sa->mk_product(*a, *b); } @@ -370,7 +379,9 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con return mk_re_loop(num_args, args, result); case OP_RE_EMPTY_SET: return BR_FAILED; - case OP_RE_FULL_SET: + case OP_RE_FULL_SEQ_SET: + return BR_FAILED; + case OP_RE_FULL_CHAR_SET: return BR_FAILED; case OP_RE_OF_PRED: return BR_FAILED; @@ -1217,7 +1228,7 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) { result = m().mk_false(); return BR_DONE; } - if (m_util.re.is_full(b)) { + if (m_util.re.is_full_seq(b)) { result = m().mk_true(); return BR_DONE; } @@ -1312,7 +1323,7 @@ br_status seq_rewriter::mk_str_to_regexp(expr* a, expr_ref& result) { return BR_FAILED; } br_status seq_rewriter::mk_re_concat(expr* a, expr* b, expr_ref& result) { - if (m_util.re.is_full(a) && m_util.re.is_full(b)) { + if (m_util.re.is_full_seq(a) && m_util.re.is_full_seq(b)) { result = a; return BR_DONE; } @@ -1352,11 +1363,11 @@ br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) { result = a; return BR_DONE; } - if (m_util.re.is_full(a)) { + if (m_util.re.is_full_seq(a)) { result = a; return BR_DONE; } - if (m_util.re.is_full(b)) { + if (m_util.re.is_full_seq(b)) { result = b; return BR_DONE; } @@ -1382,10 +1393,10 @@ br_status seq_rewriter::mk_re_complement(expr* a, expr_ref& result) { return BR_REWRITE2; } if (m_util.re.is_empty(a)) { - result = m_util.re.mk_full(m().get_sort(a)); + result = m_util.re.mk_full_seq(m().get_sort(a)); return BR_DONE; } - if (m_util.re.is_full(a)) { + if (m_util.re.is_full_seq(a)) { result = m_util.re.mk_empty(m().get_sort(a)); return BR_DONE; } @@ -1412,11 +1423,11 @@ br_status seq_rewriter::mk_re_inter(expr* a, expr* b, expr_ref& result) { result = b; return BR_DONE; } - if (m_util.re.is_full(a)) { + if (m_util.re.is_full_seq(a)) { result = b; return BR_DONE; } - if (m_util.re.is_full(b)) { + if (m_util.re.is_full_seq(b)) { result = a; return BR_DONE; } @@ -1459,10 +1470,16 @@ br_status seq_rewriter::mk_re_loop(unsigned num_args, expr* const* args, expr_re */ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) { expr* b, *c, *b1, *c1; - if (m_util.re.is_star(a) || m_util.re.is_full(a)) { + if (m_util.re.is_star(a) || m_util.re.is_full_seq(a)) { result = a; return BR_DONE; } + if (m_util.re.is_full_char(a)) { + sort* seq_sort = 0; + VERIFY(m_util.is_re(a, seq_sort)); + result = m_util.re.mk_full_seq(seq_sort); + return BR_DONE; + } if (m_util.re.is_empty(a)) { sort* seq_sort = 0; VERIFY(m_util.is_re(a, seq_sort)); @@ -1519,7 +1536,7 @@ br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) { result = a; return BR_DONE; } - if (m_util.re.is_full(a)) { + if (m_util.re.is_full_seq(a)) { result = a; return BR_DONE; } diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 7cc0ccb12..daf39b79e 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -544,7 +544,8 @@ void seq_decl_plugin::init() { m_sigs[OP_RE_LOOP] = alloc(psig, m, "re.loop", 1, 1, &reA, reA); m_sigs[OP_RE_COMPLEMENT] = alloc(psig, m, "re.complement", 1, 1, &reA, reA); m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re.empty", 1, 0, 0, reA); - m_sigs[OP_RE_FULL_SET] = alloc(psig, m, "re.all", 1, 0, 0, reA); + m_sigs[OP_RE_FULL_SEQ_SET] = alloc(psig, m, "re.all", 1, 0, 0, reA); + m_sigs[OP_RE_FULL_CHAR_SET] = alloc(psig, m, "re.all1", 1, 0, 0, reA); m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re.of.pred", 1, 1, &predA, reA); m_sigs[OP_SEQ_TO_RE] = alloc(psig, m, "seq.to.re", 1, 1, &seqA, reA); m_sigs[OP_SEQ_IN_RE] = alloc(psig, m, "seq.in.re", 1, 2, seqAreA, boolT); @@ -562,7 +563,7 @@ void seq_decl_plugin::init() { m_sigs[_OP_STRING_IN_REGEXP] = alloc(psig, m, "str.in.re", 0, 2, strTreT, boolT); m_sigs[_OP_STRING_TO_REGEXP] = alloc(psig, m, "str.to.re", 0, 1, &strT, reT); m_sigs[_OP_REGEXP_EMPTY] = alloc(psig, m, "re.nostr", 0, 0, 0, reT); - m_sigs[_OP_REGEXP_FULL] = alloc(psig, m, "re.allchar", 0, 0, 0, reT); + m_sigs[_OP_REGEXP_FULL_CHAR] = alloc(psig, m, "re.allchar", 0, 0, 0, reT); m_sigs[_OP_STRING_SUBSTR] = alloc(psig, m, "str.substr", 0, 3, strTint2T, strT); m_sigs[_OP_RE_UNROLL] = alloc(psig, m, "_re.unroll", 0, 2, reTintT, strT); } @@ -669,20 +670,24 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k)); - case _OP_REGEXP_FULL: + case _OP_REGEXP_FULL_CHAR: if (!range) { range = m_re; } match(*m_sigs[k], arity, domain, range, rng); - return m.mk_func_decl(symbol("re.allchar"), arity, domain, rng, func_decl_info(m_family_id, OP_RE_FULL_SET)); - case OP_RE_FULL_SET: + return m.mk_func_decl(symbol("re.allchar"), arity, domain, rng, func_decl_info(m_family_id, OP_RE_FULL_CHAR_SET)); + + case OP_RE_FULL_CHAR_SET: if (!range) range = m_re; if (range == m_re) { match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(symbol("re.allchar"), arity, domain, rng, func_decl_info(m_family_id, k)); } return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k)); - + + case OP_RE_FULL_SEQ_SET: + if (!range) range = m_re; + return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k)); case _OP_REGEXP_EMPTY: if (!range) { @@ -972,8 +977,12 @@ app* seq_util::re::mk_loop(expr* r, unsigned lo, unsigned hi) { return m.mk_app(m_fid, OP_RE_LOOP, 2, params, 1, &r); } -app* seq_util::re::mk_full(sort* s) { - return m.mk_app(m_fid, OP_RE_FULL_SET, 0, 0, 0, 0, s); +app* seq_util::re::mk_full_char(sort* s) { + return m.mk_app(m_fid, OP_RE_FULL_CHAR_SET, 0, 0, 0, 0, s); +} + +app* seq_util::re::mk_full_seq(sort* s) { + return m.mk_app(m_fid, OP_RE_FULL_SEQ_SET, 0, 0, 0, 0, s); } app* seq_util::re::mk_empty(sort* s) { diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 17fa50423..2e3b3fd24 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -56,7 +56,8 @@ enum seq_op_kind { OP_RE_LOOP, OP_RE_COMPLEMENT, OP_RE_EMPTY_SET, - OP_RE_FULL_SET, + OP_RE_FULL_SEQ_SET, + OP_RE_FULL_CHAR_SET, OP_RE_OF_PRED, @@ -77,7 +78,7 @@ enum seq_op_kind { _OP_STRING_SUBSTR, _OP_STRING_STRIDOF, _OP_REGEXP_EMPTY, - _OP_REGEXP_FULL, + _OP_REGEXP_FULL_CHAR, _OP_SEQ_SKOLEM, _OP_RE_UNROLL, LAST_SEQ_OP @@ -327,7 +328,8 @@ public: app* mk_opt(expr* r) { return m.mk_app(m_fid, OP_RE_OPTION, r); } app* mk_loop(expr* r, unsigned lo); app* mk_loop(expr* r, unsigned lo, unsigned hi); - app* mk_full(sort* s); + app* mk_full_char(sort* s); + app* mk_full_seq(sort* s); app* mk_empty(sort* s); bool is_to_re(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_TO_RE); } @@ -341,7 +343,8 @@ public: bool is_range(expr const* n) const { return is_app_of(n, m_fid, OP_RE_RANGE); } bool is_loop(expr const* n) const { return is_app_of(n, m_fid, OP_RE_LOOP); } bool is_empty(expr const* n) const { return is_app_of(n, m_fid, OP_RE_EMPTY_SET); } - bool is_full(expr const* n) const { return is_app_of(n, m_fid, OP_RE_FULL_SET); } + bool is_full_char(expr const* n) const { return is_app_of(n, m_fid, OP_RE_FULL_CHAR_SET); } + bool is_full_seq(expr const* n) const { return is_app_of(n, m_fid, OP_RE_FULL_SEQ_SET); } MATCH_UNARY(is_to_re); MATCH_BINARY(is_concat); MATCH_BINARY(is_union); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index f91685d43..4c1a63a2f 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2271,7 +2271,8 @@ bool theory_seq::internalize_re(expr* e) { m_util.re.is_concat(e, e1, e2)) { return internalize_re(e1) && internalize_re(e2); } - if (m_util.re.is_full(e) || + if (m_util.re.is_full_seq(e) || + m_util.re.is_full_char(e) || m_util.re.is_empty(e)) { return true; } diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 022a2ad73..56a54f964 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1689,8 +1689,10 @@ namespace smt { u.str.is_string(range1, range1val); u.str.is_string(range2, range2val); return zstring("[") + range1val + zstring("-") + range2val + zstring("]"); - } else if (u.re.is_full(a_regex)) { + } else if (u.re.is_full_seq(a_regex)) { return zstring("(.*)"); + } else if (u.re.is_full_char(a_regex)) { + return zstring("str.allchar"); } else { TRACE("str", tout << "BUG: unrecognized regex term " << mk_pp(regex, get_manager()) << std::endl;); UNREACHABLE(); return zstring(""); @@ -1806,9 +1808,12 @@ namespace smt { expr_ref finalAxiom(m.mk_iff(ex, rhs), m); SASSERT(finalAxiom); assert_axiom(finalAxiom); - } else if (u.re.is_full(regex)) { + } else if (u.re.is_full_seq(regex)) { // trivially true for any string! assert_axiom(ex); + } else if (u.re.is_full_char(regex)) { + TRACE("str", tout << "ERROR: unknown regex expression " << mk_pp(regex, m) << "!" << std::endl;); + NOT_IMPLEMENTED_YET(); } else { TRACE("str", tout << "ERROR: unknown regex expression " << mk_pp(regex, m) << "!" << std::endl;); NOT_IMPLEMENTED_YET(); @@ -6309,7 +6314,7 @@ namespace smt { } TRACE("str", tout << "range NFA: start = " << start << ", end = " << end << std::endl;); - } else if (u.re.is_full(e)) { + } else if (u.re.is_full_seq(e)) { // effectively the same as .* where . can be any single character // start --e--> tmp // tmp --e--> end From 3f7453f5c5b59396daa55e98de73b7d6aa816d7e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 20:23:31 -0800 Subject: [PATCH 0550/1283] fixing build Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- src/ast/seq_decl_plugin.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index c28a14c3b..641dba59c 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -9838,7 +9838,7 @@ def Full(s): re.all >>> e1 = Full(ReSort(StringSort())) >>> print(e1) - re.allchar + re.all """ if isinstance(s, ReSortRef): return ReRef(Z3_mk_re_full(s.ctx_ref(), s.ast), s.ctx) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index daf39b79e..2790c5c48 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -545,7 +545,7 @@ void seq_decl_plugin::init() { m_sigs[OP_RE_COMPLEMENT] = alloc(psig, m, "re.complement", 1, 1, &reA, reA); m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re.empty", 1, 0, 0, reA); m_sigs[OP_RE_FULL_SEQ_SET] = alloc(psig, m, "re.all", 1, 0, 0, reA); - m_sigs[OP_RE_FULL_CHAR_SET] = alloc(psig, m, "re.all1", 1, 0, 0, reA); + m_sigs[OP_RE_FULL_CHAR_SET] = alloc(psig, m, "re.allchar", 1, 0, 0, reA); m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re.of.pred", 1, 1, &predA, reA); m_sigs[OP_SEQ_TO_RE] = alloc(psig, m, "seq.to.re", 1, 1, &seqA, reA); m_sigs[OP_SEQ_IN_RE] = alloc(psig, m, "seq.in.re", 1, 2, seqAreA, boolT); From 5e482def18b824ca573d5d424f9a4b57a5f95ec1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Feb 2018 07:27:32 -0800 Subject: [PATCH 0551/1283] fix local search encoding bug Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 4 +- src/sat/ba_solver.h | 2 +- src/sat/sat_local_search.cpp | 67 +++++++++++++++++--------- src/sat/sat_local_search.h | 11 +++-- src/sat/tactic/goal2sat.cpp | 12 +++-- src/shell/opt_frontend.cpp | 28 +++++------ src/tactic/arith/lia2card_tactic.cpp | 2 + src/tactic/generic_model_converter.cpp | 15 ------ 8 files changed, 78 insertions(+), 63 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 5c0c09125..f2e98fa59 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -721,8 +721,8 @@ namespace opt { } goal_ref g(alloc(goal, m, true, false)); - for (unsigned i = 0; i < fmls.size(); ++i) { - g->assert_expr(fmls[i].get()); + for (expr* fml : fmls) { + g->assert_expr(fml); } tactic_ref tac0 = and_then(mk_simplify_tactic(m, m_params), diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 63e58d4b6..9e17b0594 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -453,7 +453,6 @@ namespace sat { bool validate_resolvent(); void display(std::ostream& out, ineq& p, bool values = false) const; - void display(std::ostream& out, constraint const& c, bool values) const; void display(std::ostream& out, card const& c, bool values) const; void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xr const& c, bool values) const; @@ -500,6 +499,7 @@ namespace sat { virtual bool is_blocked(literal l, ext_constraint_idx idx); ptr_vector const & constraints() const { return m_constraints; } + void display(std::ostream& out, constraint const& c, bool values) const; virtual bool validate(); diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index da9617151..5e5f49eb4 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -104,7 +104,7 @@ namespace sat { coeff_vector& falsep = m_vars[v].m_watch[!is_true]; for (unsigned i = 0; i < falsep.size(); ++i) { constraint& c = m_constraints[falsep[i].m_constraint_id]; - SASSERT(falsep[i].m_coeff == 1); + //SASSERT(falsep[i].m_coeff == 1); // will --slack if (c.m_slack <= 0) { dec_slack_score(v); @@ -113,7 +113,7 @@ namespace sat { } } for (unsigned i = 0; i < truep.size(); ++i) { - SASSERT(truep[i].m_coeff == 1); + //SASSERT(truep[i].m_coeff == 1); constraint& c = m_constraints[truep[i].m_constraint_id]; // will --true_terms_count[c] // will ++slack @@ -139,7 +139,8 @@ namespace sat { void local_search::reinit() { - if (!m_is_pb) { + IF_VERBOSE(10, verbose_stream() << "(sat-local-search reinit)\n";); + if (true || !m_is_pb) { // // the following methods does NOT converge for pseudo-boolean // can try other way to define "worse" and "better" @@ -156,8 +157,7 @@ namespace sat { } } - for (unsigned i = 0; i < m_constraints.size(); ++i) { - constraint& c = m_constraints[i]; + for (constraint & c : m_constraints) { c.m_slack = c.m_k; } @@ -216,31 +216,43 @@ namespace sat { } void local_search::verify_solution() const { - for (unsigned i = 0; i < m_constraints.size(); ++i) { - verify_constraint(m_constraints[i]); - } + for (constraint const& c : m_constraints) + verify_constraint(c); } - void local_search::verify_unsat_stack() const { - for (unsigned i = 0; i < m_unsat_stack.size(); ++i) { - constraint const& c = m_constraints[m_unsat_stack[i]]; + void local_search::verify_unsat_stack() const { + for (unsigned i : m_unsat_stack) { + constraint const& c = m_constraints[i]; SASSERT(c.m_k < constraint_value(c)); } } + unsigned local_search::constraint_coeff(constraint const& c, literal l) const { + for (auto const& pb : m_vars[l.var()].m_watch[is_pos(l)]) { + if (pb.m_constraint_id == c.m_id) return pb.m_coeff; + } + UNREACHABLE(); + return 0; + } + + unsigned local_search::constraint_value(constraint const& c) const { unsigned value = 0; for (unsigned i = 0; i < c.size(); ++i) { - value += is_true(c[i]) ? 1 : 0; + literal t = c[i]; + if (is_true(t)) { + value += constraint_coeff(c, t); + } } return value; } void local_search::verify_constraint(constraint const& c) const { unsigned value = constraint_value(c); + IF_VERBOSE(11, display(verbose_stream() << "verify ", c);); + TRACE("sat", display(verbose_stream() << "verify ", c);); if (c.m_k < value) { - IF_VERBOSE(0, display(verbose_stream() << "violated constraint: ", c); - verbose_stream() << "value: " << value << "\n";); + IF_VERBOSE(0, display(verbose_stream() << "violated constraint: ", c) << "value: " << value << "\n";); UNREACHABLE(); } } @@ -252,7 +264,7 @@ namespace sat { // ~c <= k void local_search::add_cardinality(unsigned sz, literal const* c, unsigned k) { unsigned id = m_constraints.size(); - m_constraints.push_back(constraint(k)); + m_constraints.push_back(constraint(k, id)); for (unsigned i = 0; i < sz; ++i) { m_vars.reserve(c[i].var() + 1); literal t(~c[i]); @@ -264,14 +276,15 @@ namespace sat { } } + // c * coeffs <= k void local_search::add_pb(unsigned sz, literal const* c, unsigned const* coeffs, unsigned k) { unsigned id = m_constraints.size(); - m_constraints.push_back(constraint(k)); + m_constraints.push_back(constraint(k, id)); for (unsigned i = 0; i < sz; ++i) { m_vars.reserve(c[i].var() + 1); - literal t(~c[i]); + literal t(c[i]); m_vars[t.var()].m_watch[is_pos(t)].push_back(pbcoeff(id, coeffs[i])); - m_constraints.back().push(t); // add coefficient to constraint? + m_constraints.back().push(t); } if (sz == 1 && k == 0) { m_vars[c[0].var()].m_bias = c[0].sign() ? 0 : 100; @@ -359,7 +372,7 @@ namespace sat { lits.reset(); coeffs.reset(); - for (unsigned j = 0; j < n; ++j) lits.push_back(~c[j]), coeffs.push_back(1); + for (literal l : c) lits.push_back(~l), coeffs.push_back(1); lits.push_back(c.lit()); coeffs.push_back(k); add_pb(lits.size(), lits.c_ptr(), coeffs.c_ptr(), n); } @@ -889,21 +902,27 @@ namespace sat { } } - void local_search::display(std::ostream& out) const { + std::ostream& local_search::display(std::ostream& out) const { for (constraint const& c : m_constraints) { display(out, c); } for (bool_var v = 0; v < num_vars(); ++v) { display(out, v, m_vars[v]); } + return out; } - void local_search::display(std::ostream& out, constraint const& c) const { - out << c.m_literals << " <= " << c.m_k << " lhs value: " << constraint_value(c) << "\n"; + std::ostream& local_search::display(std::ostream& out, constraint const& c) const { + for (literal l : c) { + unsigned coeff = constraint_coeff(c, l); + if (coeff > 1) out << coeff << " * "; + out << l << " "; + } + return out << " <= " << c.m_k << " lhs value: " << constraint_value(c) << "\n"; } - void local_search::display(std::ostream& out, unsigned v, var_info const& vi) const { - out << "v" << v << " := " << (vi.m_value?"true":"false") << " bias: " << vi.m_bias << "\n"; + std::ostream& local_search::display(std::ostream& out, unsigned v, var_info const& vi) const { + return out << "v" << v << " := " << (vi.m_value?"true":"false") << " bias: " << vi.m_bias << "\n"; } bool local_search::check_goodvar() { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 735ff9c65..b0483c5b9 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -99,11 +99,12 @@ namespace sat { }; struct constraint { + unsigned m_id; unsigned m_k; int m_slack; unsigned m_size; literal_vector m_literals; - constraint(unsigned k) : m_k(k), m_slack(0), m_size(0) {} + constraint(unsigned k, unsigned id) : m_id(id), m_k(k), m_slack(0), m_size(0) {} void push(literal l) { m_literals.push_back(l); ++m_size; } unsigned size() const { return m_size; } literal const& operator[](unsigned idx) const { return m_literals[idx]; } @@ -232,6 +233,8 @@ namespace sat { unsigned constraint_value(constraint const& c) const; + unsigned constraint_coeff(constraint const& c, literal l) const; + void print_info(std::ostream& out); void extract_model(); @@ -240,11 +243,11 @@ namespace sat { void add_clause(unsigned sz, literal const* c); - void display(std::ostream& out) const; + std::ostream& display(std::ostream& out) const; - void display(std::ostream& out, constraint const& c) const; + std::ostream& display(std::ostream& out, constraint const& c) const; - void display(std::ostream& out, unsigned v, var_info const& vi) const; + std::ostream& display(std::ostream& out, unsigned v, var_info const& vi) const; public: diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index ac97eb3c3..d6d6c0892 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -517,7 +517,10 @@ struct goal2sat::imp { mk_clause(~l1, ~l2, l); m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); m_result_stack.push_back(sign ? ~l : l); - if (root) mk_clause(~l); + if (root) { + m_result_stack.reset(); + mk_clause(~l); + } } } @@ -586,7 +589,10 @@ struct goal2sat::imp { mk_clause(~l1, ~l2, l); m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); m_result_stack.push_back(sign ? ~l : l); - if (root) mk_clause(~l); + if (root) { + mk_clause(~l); + m_result_stack.reset(); + } } } @@ -808,7 +814,7 @@ struct goal2sat::imp { } f = m.mk_or(fmls.size(), fmls.c_ptr()); } - TRACE("goal2sat", tout << mk_pp(f, m) << "\n";); + TRACE("goal2sat", tout << f << "\n";); process(f); skip_dep: ; diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 48efd1148..7dcb761db 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -10,6 +10,7 @@ Copyright (c) 2015 Microsoft Corporation #include "opt/opt_context.h" #include "ast/ast_util.h" #include "ast/arith_decl_plugin.h" +#include "ast/ast_pp.h" #include "util/gparams.h" #include "util/timeout.h" #include "ast/reg_decl_plugins.h" @@ -99,21 +100,20 @@ static unsigned parse_opt(std::istream& in, opt_format f) { case l_false: std::cout << "unsat\n"; break; case l_undef: std::cout << "unknown\n"; break; } - DEBUG_CODE( - if (false && r == l_true) { - model_ref mdl; - opt.get_model(mdl); - expr_ref_vector hard(m); - opt.get_hard_constraints(hard); - for (unsigned i = 0; i < hard.size(); ++i) { - std::cout << "validate: " << i << "\n"; - expr_ref tmp(m); - VERIFY(mdl->eval(hard[i].get(), tmp)); - if (!m.is_true(tmp)) { - std::cout << tmp << "\n"; - } + + if (r != l_false && gparams::get().get_bool("model_validate", false)) { + model_ref mdl; + opt.get_model(mdl); + expr_ref_vector hard(m); + opt.get_hard_constraints(hard); + for (expr* h : hard) { + expr_ref tmp(m); + VERIFY(mdl->eval(h, tmp)); + if (!m.is_true(tmp)) { + std::cout << mk_pp(h, m) << " " << tmp << "\n"; } - }); + } + } } catch (z3_exception & ex) { std::cerr << ex.msg() << "\n"; diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index bc7e3a4ee..e598b876d 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -213,7 +213,9 @@ public: new_pr = m.mk_rewrite(g->form(i), new_curr); new_pr = m.mk_modus_ponens(g->pr(i), new_pr); } + // IF_VERBOSE(0, verbose_stream() << mk_pp(g->form(i), m) << "\n--->\n" << new_curr << "\n";); g->update(i, new_curr, new_pr, g->dep(i)); + } for (expr* a : axioms) { g->assert_expr(a); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 2e800da48..485682858 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -53,21 +53,6 @@ void generic_model_converter::operator()(model_ref & md) { break; case instruction::ADD: ev(e.m_def, val); - if (e.m_f->get_name() == symbol("FOX-PIT-17")) { - IF_VERBOSE(0, verbose_stream() << e.m_f->get_name() << " " << e.m_def << " -> " << val << "\n";); - ptr_vector ts; - ts.push_back(e.m_def); - while (!ts.empty()) { - app* t = to_app(ts.back()); - ts.pop_back(); - if (t->get_num_args() > 0) { - ts.append(t->get_num_args(), t->get_args()); - } - expr_ref tmp(m); - ev(t, tmp); - IF_VERBOSE(0, verbose_stream() << mk_pp(t, m) << " -> " << tmp << "\n";); - } - } TRACE("model_converter", tout << e.m_f->get_name() << " ->\n" << e.m_def << "\n==>\n" << val << "\n";); arity = e.m_f->get_arity(); reset_ev = false; From 4f630f2a009b7fda2ea7cd3bafdbb5cfe3be4e38 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Feb 2018 09:09:53 -0800 Subject: [PATCH 0552/1283] fix configuration for compiling equalities, add extended binaries Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 2 +- src/sat/sat_big.cpp | 21 +++++++++++++++++++-- src/shell/opt_frontend.cpp | 19 +++++++++++++------ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index f2e98fa59..ec2059642 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -738,7 +738,7 @@ namespace opt { tac3 = mk_eq2bv_tactic(m); params_ref lia_p; lia_p.set_bool("compile_equality", optp.pb_compile_equality()); - tac3->updt_params(lia_p); + tac2->updt_params(lia_p); set_simplify(and_then(tac0.get(), tac1.get(), tac2.get(), tac3.get(), mk_simplify_tactic(m))); } else { diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index b7dc0bf8a..1845a9632 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -30,6 +30,7 @@ namespace sat { unsigned num_lits = m_num_vars * 2; literal_vector lits, r; SASSERT(num_lits == m_dag.size() && num_lits == m_roots.size()); + size_t_map seen_idx; for (unsigned l_idx = 0; l_idx < num_lits; l_idx++) { literal u = to_literal(l_idx); if (s.was_eliminated(u.var())) @@ -41,11 +42,27 @@ namespace sat { m_roots[v.index()] = false; edges.push_back(v); } -#if 0 +#if 1 if (w.is_ext_constraint() && s.m_ext && + learned && + !seen_idx.contains(w.get_ext_constraint_idx()) && s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), r)) { - IF_VERBOSE(0, verbose_stream() << "extended binary " << r.size() << "\n";); + seen_idx.insert(w.get_ext_constraint_idx(), true); + for (unsigned i = 0; i < r.size(); ++i) { + literal u = r[i]; + for (unsigned j = i + 1; j < r.size(); ++j) { + // add r[i] -> ~r[j] + literal v = ~r[j]; + m_roots[v.index()] = false; + m_dag[u.index()].push_back(v); + // add r[j] -> ~r[i] + v.neg(); + u.neg(); + m_roots[u.index()] = false; + m_dag[v.index()].push_back(u); + } + } } #endif } diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 7dcb761db..8ce573e9a 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -7,13 +7,14 @@ Copyright (c) 2015 Microsoft Corporation #include #include #include -#include "opt/opt_context.h" +#include "util/gparams.h" +#include "util/timeout.h" #include "ast/ast_util.h" #include "ast/arith_decl_plugin.h" #include "ast/ast_pp.h" -#include "util/gparams.h" -#include "util/timeout.h" #include "ast/reg_decl_plugins.h" +#include "model/model_smt2_pp.h" +#include "opt/opt_context.h" #include "opt/opt_parse.h" #include "shell/opt_frontend.h" @@ -27,9 +28,15 @@ static unsigned_vector g_handles; static void display_results() { if (g_opt) { - for (unsigned i = 0; i < g_handles.size(); ++i) { - expr_ref lo = g_opt->get_lower(g_handles[i]); - expr_ref hi = g_opt->get_upper(g_handles[i]); + model_ref mdl; + g_opt->get_model(mdl); + if (mdl) { + model_smt2_pp(std::cout, g_opt->get_manager(), *mdl, 0); + } + + for (unsigned h : g_handles) { + expr_ref lo = g_opt->get_lower(h); + expr_ref hi = g_opt->get_upper(h); if (lo == hi) { std::cout << " " << lo << "\n"; } From a0b5f6937bcc8c2f38ac5dd524d9db28e4418478 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Feb 2018 10:05:26 -0800 Subject: [PATCH 0553/1283] fix bugs, add soft timeout to opt frontend Signed-off-by: Nikolaj Bjorner --- src/sat/sat_big.cpp | 7 ++++--- src/shell/opt_frontend.cpp | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 1845a9632..a59deeafd 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -52,11 +52,12 @@ namespace sat { for (unsigned i = 0; i < r.size(); ++i) { literal u = r[i]; for (unsigned j = i + 1; j < r.size(); ++j) { - // add r[i] -> ~r[j] - literal v = ~r[j]; + // add ~r[i] -> r[j] + literal v = r[j]; + literal u = ~r[j]; m_roots[v.index()] = false; m_dag[u.index()].push_back(v); - // add r[j] -> ~r[i] + // add ~r[j] -> r[i] v.neg(); u.neg(); m_roots[u.index()] = false; diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 8ce573e9a..9509db760 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -9,6 +9,8 @@ Copyright (c) 2015 Microsoft Corporation #include #include "util/gparams.h" #include "util/timeout.h" +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" #include "ast/ast_util.h" #include "ast/arith_decl_plugin.h" #include "ast/ast_pp.h" @@ -101,6 +103,11 @@ static unsigned parse_opt(std::istream& in, opt_format f) { break; } try { + cancel_eh eh(m.limit()); + unsigned timeout = std::stoi(gparams::get_value("timeout")); + unsigned rlimit = std::stoi(gparams::get_value("rlimit")); + scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(m.limit(), rlimit); lbool r = opt.optimize(); switch (r) { case l_true: std::cout << "sat\n"; break; From 72a7164e2dea289aa6370e7642dc1d7e2f62b513 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Feb 2018 13:03:57 -0800 Subject: [PATCH 0554/1283] add model checker to external Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 81 +++++++++++++++++++++++++++++++++++------ src/sat/ba_solver.h | 8 +++- src/sat/sat_extension.h | 1 + src/sat/sat_solver.cpp | 4 +- 4 files changed, 80 insertions(+), 14 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 41d043526..428577de7 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1641,7 +1641,6 @@ namespace sat { xr* x = new (mem) xr(next_id(), lits); x->set_learned(learned); add_constraint(x); - for (literal l : lits) s().set_external(l.var()); // TBD: determine if goal2sat does this. return x; } @@ -1715,7 +1714,6 @@ namespace sat { } - void ba_solver::ensure_parity_size(bool_var v) { if (m_parity_marks.size() <= static_cast(v)) { m_parity_marks.resize(static_cast(v) + 1, 0); @@ -2087,6 +2085,17 @@ namespace sat { return l_undef; } + lbool ba_solver::eval(model const& m, constraint const& c) const { + lbool v1 = c.lit() == null_literal ? l_true : value(c.lit()); + switch (c.tag()) { + case card_t: return eval(v1, eval(m, c.to_card())); + case pb_t: return eval(v1, eval(m, c.to_pb())); + case xr_t: return eval(v1, eval(m, c.to_xr())); + default: UNREACHABLE(); break; + } + return l_undef; + } + lbool ba_solver::eval(lbool a, lbool b) const { if (a == l_undef || b == l_undef) return l_undef; return (a == b) ? l_true : l_false; @@ -2106,6 +2115,34 @@ namespace sat { return l_undef; } + lbool ba_solver::eval(model const& m, card const& c) const { + unsigned trues = 0, undefs = 0; + for (literal l : c) { + switch (l.sign() ? ~m[l.var()] : m[l.var()]) { + case l_true: trues++; break; + case l_undef: undefs++; break; + default: break; + } + } + if (trues + undefs < c.k()) return l_false; + if (trues >= c.k()) return l_true; + return l_undef; + } + + lbool ba_solver::eval(model const& m, pb const& p) const { + unsigned trues = 0, undefs = 0; + for (wliteral wl : p) { + switch (wl.second.sign() ? ~m[wl.second.var()] : m[wl.second.var()]) { + case l_true: trues += wl.first; break; + case l_undef: undefs += wl.first; break; + default: break; + } + } + if (trues + undefs < p.k()) return l_false; + if (trues >= p.k()) return l_true; + return l_undef; + } + lbool ba_solver::eval(pb const& p) const { unsigned trues = 0, undefs = 0; for (wliteral wl : p) { @@ -2133,6 +2170,19 @@ namespace sat { return odd ? l_true : l_false; } + lbool ba_solver::eval(model const& m, xr const& x) const { + bool odd = false; + + for (auto l : x) { + switch (l.sign() ? ~m[l.var()] : m[l.var()]) { + case l_true: odd = !odd; break; + case l_false: break; + default: return l_undef; + } + } + return odd ? l_true : l_false; + } + bool ba_solver::validate() { if (!validate_watch_literals()) { return false; @@ -2903,7 +2953,6 @@ namespace sat { remove_constraint(c, "contains eliminated var"); break; } - s().set_external(v); } } return ext; @@ -2984,14 +3033,6 @@ namespace sat { m_constraint_removed = false; } - void ba_solver::ensure_external(constraint const& c) { - literal_vector lits(c.literals()); - for (literal l : lits) { - s().set_external(l.var()); - } - } - - void ba_solver::cleanup_constraints(ptr_vector& cs, bool learned) { ptr_vector::iterator it = cs.begin(); ptr_vector::iterator it2 = it; @@ -3004,7 +3045,6 @@ namespace sat { m_allocator.deallocate(c.obj_size(), &c); } else if (learned && !c.learned()) { - ensure_external(c); m_constraints.push_back(&c); } else { @@ -4051,6 +4091,23 @@ namespace sat { return value < p.m_k; } + bool ba_solver::check_model(model const& m) const { + bool ok = true; + for (constraint const* c : m_constraints) { + if (!check_model(m, *c)) ok = false; + } + return ok; + } + + bool ba_solver::check_model(model const& m, constraint const& c) const { + if (eval(m, c) != l_true) { + IF_VERBOSE(0, verbose_stream() << "failed checking " << c.id() << ": " << c << "\n";); + return false; + } + else { + return true; + } + } }; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 9e17b0594..8ed303469 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -302,7 +302,6 @@ namespace sat { void cleanup_clauses(); void cleanup_constraints(); void cleanup_constraints(ptr_vector& cs, bool learned); - void ensure_external(constraint const& c); void remove_constraint(constraint& c, char const* reason); // constraints @@ -328,6 +327,7 @@ namespace sat { void attach_constraint(constraint const& c); void detach_constraint(constraint const& c); lbool eval(constraint const& c) const; + lbool eval(model const& m, constraint const& c) const; lbool eval(lbool a, lbool b) const; void assert_unconstrained(literal lit, literal_vector const& lits); void flush_roots(constraint& c); @@ -348,6 +348,7 @@ namespace sat { bool clausify(card& c); bool clausify(literal lit, unsigned n, literal const* lits, unsigned k); lbool eval(card const& c) const; + lbool eval(model const& m, card const& c) const; double get_reward(card const& c, literal_occs_fun& occs) const; @@ -362,6 +363,7 @@ namespace sat { bool clausify(xr& x); void flush_roots(xr& x); lbool eval(xr const& x) const; + lbool eval(model const& m, xr const& x) const; // pb functionality unsigned m_a_max; @@ -379,6 +381,7 @@ namespace sat { bool clausify(pb& p); bool is_cardinality(pb const& p, literal_vector& lits); lbool eval(pb const& p) const; + lbool eval(model const& m, pb const& p) const; double get_reward(pb const& p, literal_occs_fun& occs) const; // access solver @@ -463,6 +466,8 @@ namespace sat { void copy_core(ba_solver* result, bool learned); void copy_constraints(ba_solver* result, ptr_vector const& constraints); + + bool check_model(model const& m, constraint const& c) const; public: ba_solver(); virtual ~ba_solver(); @@ -497,6 +502,7 @@ namespace sat { virtual bool is_extended_binary(ext_justification_idx idx, literal_vector & r); virtual void init_use_list(ext_use_list& ul); virtual bool is_blocked(literal l, ext_constraint_idx idx); + virtual bool check_model(model const& m) const; ptr_vector const & constraints() const { return m_constraints; } void display(std::ostream& out, constraint const& c, bool values) const; diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index ff23c9be7..e687ab2b0 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -79,6 +79,7 @@ namespace sat { virtual bool validate() = 0; virtual void init_use_list(ext_use_list& ul) = 0; virtual bool is_blocked(literal l, ext_constraint_idx) = 0; + virtual bool check_model(model const& m) const = 0; }; }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index b8850ce95..e384a944d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -244,7 +244,6 @@ namespace sat { void solver::set_external(bool_var v) { if (m_external[v] != 0) return; m_external[v] = 1; - if (!m_ext) return; lbool val = value(v); @@ -1707,6 +1706,9 @@ namespace sat { ok = false; } } + if (m_ext && !m_ext->check_model(m)) { + ok = false; + } return ok; } From 908dfd392e77631ac74a48c4165cd35ab5f1bf46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Feb 2018 14:08:51 -0800 Subject: [PATCH 0555/1283] fix validation code, disable PB compilation code Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 33 +++++++++++++++++---------------- src/sat/ba_solver.h | 3 ++- src/sat/sat_big.cpp | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 428577de7..3b9b81448 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2086,7 +2086,7 @@ namespace sat { } lbool ba_solver::eval(model const& m, constraint const& c) const { - lbool v1 = c.lit() == null_literal ? l_true : value(c.lit()); + lbool v1 = c.lit() == null_literal ? l_true : value(m, c.lit()); switch (c.tag()) { case card_t: return eval(v1, eval(m, c.to_card())); case pb_t: return eval(v1, eval(m, c.to_pb())); @@ -2118,7 +2118,7 @@ namespace sat { lbool ba_solver::eval(model const& m, card const& c) const { unsigned trues = 0, undefs = 0; for (literal l : c) { - switch (l.sign() ? ~m[l.var()] : m[l.var()]) { + switch (value(m, l)) { case l_true: trues++; break; case l_undef: undefs++; break; default: break; @@ -2132,7 +2132,7 @@ namespace sat { lbool ba_solver::eval(model const& m, pb const& p) const { unsigned trues = 0, undefs = 0; for (wliteral wl : p) { - switch (wl.second.sign() ? ~m[wl.second.var()] : m[wl.second.var()]) { + switch (value(m, wl.second)) { case l_true: trues += wl.first; break; case l_undef: undefs += wl.first; break; default: break; @@ -2174,7 +2174,7 @@ namespace sat { bool odd = false; for (auto l : x) { - switch (l.sign() ? ~m[l.var()] : m[l.var()]) { + switch (value(m, l)) { case l_true: odd = !odd; break; case l_false: break; default: return l_undef; @@ -2736,9 +2736,10 @@ namespace sat { } bool ba_solver::clausify(pb& p) { + return false; if (get_config().m_card_solver) return false; - + bool ok = !p.learned(); bool is_def = p.lit() != null_literal; for (wliteral wl : p) { @@ -4094,21 +4095,21 @@ namespace sat { bool ba_solver::check_model(model const& m) const { bool ok = true; for (constraint const* c : m_constraints) { - if (!check_model(m, *c)) ok = false; + switch (eval(m, *c)) { + case l_false: + IF_VERBOSE(0, verbose_stream() << "failed checking " << c->id() << ": " << *c << "\n";); + ok = false; + break; + case l_true: + break; + case l_undef: + IF_VERBOSE(0, verbose_stream() << "undef " << c->id() << ": " << *c << "\n";); + break; + } } return ok; } - bool ba_solver::check_model(model const& m, constraint const& c) const { - if (eval(m, c) != l_true) { - IF_VERBOSE(0, verbose_stream() << "failed checking " << c.id() << ": " << c << "\n";); - return false; - } - else { - return true; - } - } - }; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 8ed303469..6b6d10c38 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -387,6 +387,8 @@ namespace sat { // access solver inline lbool value(bool_var v) const { return value(literal(v, false)); } inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } + inline lbool value(model const& m, literal l) const { return l.sign() ? ~m[l.var()] : m[l.var()]; } + inline unsigned lvl(literal lit) const { return m_lookahead || m_unit_walk ? 0 : m_solver->lvl(lit); } inline unsigned lvl(bool_var v) const { return m_lookahead || m_unit_walk ? 0 : m_solver->lvl(v); } inline bool inconsistent() const { @@ -467,7 +469,6 @@ namespace sat { void copy_core(ba_solver* result, bool learned); void copy_constraints(ba_solver* result, ptr_vector const& constraints); - bool check_model(model const& m, constraint const& c) const; public: ba_solver(); virtual ~ba_solver(); diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index a59deeafd..c820aa4f8 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -42,7 +42,7 @@ namespace sat { m_roots[v.index()] = false; edges.push_back(v); } -#if 1 +#if 0 if (w.is_ext_constraint() && s.m_ext && learned && From 50f3e9c3c054691fefefc8b3d3f02114cd1591c8 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 6 Feb 2018 14:30:43 +0700 Subject: [PATCH 0556/1283] Fix typos. --- src/ast/rewriter/der.cpp | 2 +- src/duality/duality.h | 12 ++++++------ src/duality/duality_rpfp.cpp | 4 ++-- src/math/polynomial/polynomial.cpp | 10 +++++----- src/muz/spacer/spacer_unsat_core_learner.cpp | 2 +- src/qe/qe_lite.cpp | 2 +- src/smt/theory_arith_core.h | 2 +- src/smt/theory_arith_nl.h | 4 ++-- src/tactic/arith/fix_dl_var_tactic.cpp | 2 +- src/tactic/core/occf_tactic.cpp | 2 +- src/tactic/core/occf_tactic.h | 2 +- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/ast/rewriter/der.cpp b/src/ast/rewriter/der.cpp index 56f895b8a..d1fecf2fb 100644 --- a/src/ast/rewriter/der.cpp +++ b/src/ast/rewriter/der.cpp @@ -260,7 +260,7 @@ void der_sort_vars(ptr_vector & vars, ptr_vector & definitions, unsig vidx = to_var(t)->get_idx(); if (fr.second == 0) { CTRACE("der_bug", vidx >= definitions.size(), tout << "vidx: " << vidx << "\n";); - // Remark: The size of definitions may be smaller than the number of variables occuring in the quantified formula. + // Remark: The size of definitions may be smaller than the number of variables occurring in the quantified formula. if (definitions.get(vidx, 0) != 0) { if (visiting.is_marked(t)) { // cycle detected: remove t diff --git a/src/duality/duality.h b/src/duality/duality.h index e8f36a0cd..f1aba90bc 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -722,7 +722,7 @@ namespace Duality { check_result CheckUpdateModel(Node *root, std::vector assumps); - /** Determines the value in the counterexample of a symbol occuring in the transformer formula of + /** Determines the value in the counterexample of a symbol occurring in the transformer formula of * a given edge. */ Term Eval(Edge *e, Term t); @@ -731,7 +731,7 @@ namespace Duality { Term EvalNode(Node *p); - /** Returns true if the given node is empty in the primal solution. For proecudure summaries, + /** Returns true if the given node is empty in the primal solution. For procedure summaries, this means that the procedure is not called in the current counter-model. */ bool Empty(Node *p); @@ -854,7 +854,7 @@ namespace Duality { /** Write the RPFP to a file (currently in SMTLIB 1.2 format) */ void WriteProblemToFile(std::string filename, FileFormat format = DualityFormat); - /** Read the RPFP from a file (in specificed format) */ + /** Read the RPFP from a file (in specified format) */ void ReadProblemFromFile(std::string filename, FileFormat format = DualityFormat); /** Translate problem to Horn clause form */ @@ -870,9 +870,9 @@ namespace Duality { std::vector edges; /** Fuse a vector of transformers. If the total number of inputs of the transformers - is N, then the result is an N-ary transfomer whose output is the union of - the outputs of the given transformers. The is, suppose we have a vetor of transfoermers - {T_i(r_i1,...,r_iN(i) : i=1..M}. The the result is a transformer + is N, then the result is an N-ary transformer whose output is the union of + the outputs of the given transformers. The is, suppose we have a vector of transformers + {T_i(r_i1,...,r_iN(i) : i=1..M}. The result is a transformer F(r_11,...,r_iN(1),...,r_M1,...,r_MN(M)) = T_1(r_11,...,r_iN(1)) U ... U T_M(r_M1,...,r_MN(M)) diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index b6dd42f00..81ed3d017 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -1491,7 +1491,7 @@ namespace Duality { return res; } - /** Determines the value in the counterexample of a symbol occuring in the transformer formula of + /** Determines the value in the counterexample of a symbol occurring in the transformer formula of * a given edge. */ RPFP::Term RPFP::Eval(Edge *e, Term t) @@ -1500,7 +1500,7 @@ namespace Duality { return dualModel.eval(tl); } - /** Returns true if the given node is empty in the primal solution. For proecudure summaries, + /** Returns true if the given node is empty in the primal solution. For proceudure summaries, this means that the procedure is not called in the current counter-model. */ bool RPFP::Empty(Node *p) diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 51d8489e3..dcd5af1cc 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -1421,7 +1421,7 @@ namespace polynomial { } } - // Return the maximal variable y occuring in [m_ms + start, m_ms + end) that is smaller than x + // Return the maximal variable y occurring in [m_ms + start, m_ms + end) that is smaller than x var max_smaller_than(unsigned start, unsigned end, var x) { var max = null_var; for (unsigned i = start; i < end; i++) { @@ -1456,7 +1456,7 @@ namespace polynomial { } /** - \brief Make sure that the first monomial contains the maximal variable x occuring in the polynomial, + \brief Make sure that the first monomial contains the maximal variable x occurring in the polynomial, and x occurs with maximal degree. */ void make_first_maximal() { @@ -3209,7 +3209,7 @@ namespace polynomial { typedef sbuffer var_buffer; /** - Store in pws the variables occuring in p and their (minimal or maximal) degrees. + Store in pws the variables occurring in p and their (minimal or maximal) degrees. */ unsigned_vector m_var_degrees_tmp; template @@ -3470,7 +3470,7 @@ namespace polynomial { pp = mk_one(); return; } - // Apply filter and collect powers of x occuring in p + // Apply filter and collect powers of x occurring in p // The quick filter is the following: // If p contains a monomial x^k and no monomial of the form m*x^k m != 1, then // c = m_unit_poly @@ -3479,7 +3479,7 @@ namespace polynomial { // - found monomial x^k then iccp_powers[k]++; // - found monomial m*x^k then iccp_powers[k]+=2; // If after traversing p, there is a k s.t. iccp_powers[k] == 1, we know c == 1 - // We store iccp_powers the powers of x occuring in p. + // We store iccp_powers the powers of x occurring in p. sbuffer iccp_filter; sbuffer iccp_powers; iccp_filter.resize(d+1, 0); diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index bc066d32d..f36143c5f 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -46,7 +46,7 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n"; ); - // compute symbols occuring in B + // compute symbols occurring in B collect_symbols_b(asserted_b); // traverse proof diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 3975945cb..1220bd571 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -125,7 +125,7 @@ namespace eq { vidx = to_var(t)->get_idx(); if (fr.second == 0) { CTRACE("der_bug", vidx >= definitions.size(), tout << "vidx: " << vidx << "\n";); - // Remark: The size of definitions may be smaller than the number of variables occuring in the quantified formula. + // Remark: The size of definitions may be smaller than the number of variables occurring in the quantified formula. if (definitions.get(vidx, 0) != 0) { if (visiting.is_marked(t)) { // cycle detected: remove t diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index b00648c36..03830f7d0 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -40,7 +40,7 @@ namespace smt { template void theory_arith::found_underspecified_op(app * n) { if (!m_found_underspecified_op) { - TRACE("arith", tout << "found underspecificed expression:\n" << mk_pp(n, get_manager()) << "\n";); + TRACE("arith", tout << "found underspecified expression:\n" << mk_pp(n, get_manager()) << "\n";); get_context().push_trail(value_trail(m_found_underspecified_op)); m_found_underspecified_op = true; } diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 87b811e8f..7eee008e9 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -141,8 +141,8 @@ namespace smt { \brief Return the number of variables that do not have bounds associated with it. The result is 0, 1, or 2. The value 2 means "2 or more". - The second value is the idx of the a variable that does not - have bounds associated with it. It is only usefull when the first value is 1. + The second value is the idx of the variable that does not + have bounds associated with it. It is only useful when the first value is 1. The second value is -1 if such variable does not exist, that is, the first value is 0. diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 7ff7bd835..2c25c12e1 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -196,7 +196,7 @@ class fix_dl_var_tactic : public tactic { app * most_occs() { // We try to choose a variable that when set to 0 will generate many bounded variables. - // That is why we give preference to variables occuring in non-nested inequalities. + // That is why we give preference to variables occurring in non-nested inequalities. unsigned best1, best2; app * r1, * r2; r1 = most_occs(m_non_nested_occs, best1); diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index 6d9d63971..254f8166c 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -9,7 +9,7 @@ Abstract: Put clauses in the assertion set in OOC (one constraint per clause) form. - Constraints occuring in formulas that + Constraints occurring in formulas that are not clauses are ignored. The formula can be put into CNF by using mk_sat_preprocessor strategy. diff --git a/src/tactic/core/occf_tactic.h b/src/tactic/core/occf_tactic.h index 80f8f6042..0ef7eb1f6 100644 --- a/src/tactic/core/occf_tactic.h +++ b/src/tactic/core/occf_tactic.h @@ -9,7 +9,7 @@ Abstract: Put clauses in the assertion set in OOC (one constraint per clause) form. - Constraints occuring in formulas that + Constraints occurring in formulas that are not clauses are ignored. The formula can be put into CNF by using mk_sat_preprocessor strategy. From 757b7c66efa6b8e081489b3c6105d324ff009beb Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 6 Feb 2018 14:29:54 +0700 Subject: [PATCH 0557/1283] Remove unnecessary value parameter copies. --- src/ast/rewriter/bv_bounds.cpp | 12 +++++----- src/ast/rewriter/bv_bounds.h | 16 +++++++------- src/duality/duality.h | 2 +- src/duality/duality_rpfp.cpp | 2 +- src/interp/iz3mgr.h | 28 ++++++++++++------------ src/util/lp/core_solver_pretty_printer.h | 2 +- src/util/lp/mps_reader.h | 18 +++++++-------- 7 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp index fd263efb2..0a32f8bc2 100644 --- a/src/ast/rewriter/bv_bounds.cpp +++ b/src/ast/rewriter/bv_bounds.cpp @@ -449,7 +449,7 @@ bool bv_bounds::add_constraint(expr* e) { return m_okay; } -bool bv_bounds::add_bound_unsigned(app * v, numeral a, numeral b, bool negate) { +bool bv_bounds::add_bound_unsigned(app * v, const numeral& a, const numeral& b, bool negate) { TRACE("bv_bounds", tout << "bound_unsigned " << mk_ismt2_pp(v, m_m) << ": " << (negate ? "~[" : "[") << a << ";" << b << "]" << std::endl;); const unsigned bv_sz = m_bv_util.get_bv_size(v); const numeral& zero = numeral::zero(); @@ -472,7 +472,7 @@ bool bv_bounds::add_bound_unsigned(app * v, numeral a, numeral b, bool negate) { } } -bv_bounds::conv_res bv_bounds::convert_signed(app * v, numeral a, numeral b, bool negate, vector& nis) { +bv_bounds::conv_res bv_bounds::convert_signed(app * v, const numeral& a, const numeral& b, bool negate, vector& nis) { TRACE("bv_bounds", tout << "convert_signed " << mk_ismt2_pp(v, m_m) << ":" << (negate ? "~[" : "[") << a << ";" << b << "]" << std::endl;); const unsigned bv_sz = m_bv_util.get_bv_size(v); SASSERT(a <= b); @@ -496,7 +496,7 @@ bv_bounds::conv_res bv_bounds::convert_signed(app * v, numeral a, numeral b, boo } } -bool bv_bounds::add_bound_signed(app * v, numeral a, numeral b, bool negate) { +bool bv_bounds::add_bound_signed(app * v, const numeral& a, const numeral& b, bool negate) { TRACE("bv_bounds", tout << "bound_signed " << mk_ismt2_pp(v, m_m) << ":" << (negate ? "~" : " ") << a << ";" << b << std::endl;); const unsigned bv_sz = m_bv_util.get_bv_size(v); SASSERT(a <= b); @@ -519,7 +519,7 @@ bool bv_bounds::add_bound_signed(app * v, numeral a, numeral b, bool negate) { } } -bool bv_bounds::bound_lo(app * v, numeral l) { +bool bv_bounds::bound_lo(app * v, const numeral& l) { SASSERT(in_range(v, l)); TRACE("bv_bounds", tout << "lower " << mk_ismt2_pp(v, m_m) << ":" << l << std::endl;); // l <= v @@ -530,7 +530,7 @@ bool bv_bounds::bound_lo(app * v, numeral l) { return m_okay; } -bool bv_bounds::bound_up(app * v, numeral u) { +bool bv_bounds::bound_up(app * v, const numeral& u) { SASSERT(in_range(v, u)); TRACE("bv_bounds", tout << "upper " << mk_ismt2_pp(v, m_m) << ":" << u << std::endl;); // v <= u @@ -541,7 +541,7 @@ bool bv_bounds::bound_up(app * v, numeral u) { return m_okay; } -bool bv_bounds::add_neg_bound(app * v, numeral a, numeral b) { +bool bv_bounds::add_neg_bound(app * v, const numeral& a, const numeral& b) { TRACE("bv_bounds", tout << "negative bound " << mk_ismt2_pp(v, m_m) << ":" << a << ";" << b << std::endl;); bv_bounds::interval negative_interval(a, b); SASSERT(m_bv_util.is_bv(v)); diff --git a/src/ast/rewriter/bv_bounds.h b/src/ast/rewriter/bv_bounds.h index 4a7226fa7..775941d1d 100644 --- a/src/ast/rewriter/bv_bounds.h +++ b/src/ast/rewriter/bv_bounds.h @@ -49,11 +49,11 @@ public: // bounds addition methods **/ bool add_constraint(expr* e); - bool bound_up(app * v, numeral u); // v <= u - bool bound_lo(app * v, numeral l); // l <= v - inline bool add_neg_bound(app * v, numeral a, numeral b); // not (a<=v<=b) - bool add_bound_signed(app * v, numeral a, numeral b, bool negate); - bool add_bound_unsigned(app * v, numeral a, numeral b, bool negate); + bool bound_up(app * v, const numeral& u); // v <= u + bool bound_lo(app * v, const numeral& l); // l <= v + inline bool add_neg_bound(app * v, const numeral& a, const numeral& b); // not (a<=v<=b) + bool add_bound_signed(app * v, const numeral& a, const numeral& b, bool negate); + bool add_bound_unsigned(app * v, const numeral& a, const numeral& b, bool negate); public: bool is_sat(); ///< Determine if the set of considered constraints is satisfiable. bool is_okay(); @@ -70,7 +70,7 @@ protected: enum conv_res { CONVERTED, UNSAT, UNDEF }; conv_res convert(expr * e, vector& nis, bool negated); conv_res record(app * v, numeral lo, numeral hi, bool negated, vector& nis); - conv_res convert_signed(app * v, numeral a, numeral b, bool negate, vector& nis); + conv_res convert_signed(app * v, const numeral& a, const numeral& b, bool negate, vector& nis); typedef vector intervals; typedef obj_map intervals_map; @@ -83,7 +83,7 @@ protected: bool m_okay; bool is_sat(app * v); bool is_sat_core(app * v); - inline bool in_range(app *v, numeral l); + inline bool in_range(app *v, const numeral& l); inline bool is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val); void record_singleton(app * v, numeral& singleton_value); inline bool to_bound(const expr * e) const; @@ -99,7 +99,7 @@ inline bool bv_bounds::to_bound(const expr * e) const { && !m_bv_util.is_numeral(e); } -inline bool bv_bounds::in_range(app *v, bv_bounds::numeral n) { +inline bool bv_bounds::in_range(app *v, const bv_bounds::numeral& n) { const unsigned bv_sz = m_bv_util.get_bv_size(v); const bv_bounds::numeral zero(0); const bv_bounds::numeral mod(rational::power_of_two(bv_sz)); diff --git a/src/duality/duality.h b/src/duality/duality.h index e8f36a0cd..71687c648 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -725,7 +725,7 @@ namespace Duality { /** Determines the value in the counterexample of a symbol occuring in the transformer formula of * a given edge. */ - Term Eval(Edge *e, Term t); + Term Eval(Edge *e, const Term& t); /** Return the fact derived at node p in a counterexample. */ diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index b6dd42f00..5ddc196c8 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -1494,7 +1494,7 @@ namespace Duality { /** Determines the value in the counterexample of a symbol occuring in the transformer formula of * a given edge. */ - RPFP::Term RPFP::Eval(Edge *e, Term t) + RPFP::Term RPFP::Eval(Edge *e, const Term& t) { Term tl = Localize(e, t); return dualModel.eval(tl); diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index 0ad751326..8de1a44e8 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -245,7 +245,7 @@ class iz3mgr { /** Methods for destructing ast. */ - int num_args(ast t){ + int num_args(const ast& t){ ast_kind dk = t.raw()->get_kind(); switch(dk){ case AST_APP: @@ -285,7 +285,7 @@ class iz3mgr { return res; } - symb sym(ast t){ + symb sym(const ast& t){ raw_ast *_ast = t.raw(); return is_app(_ast) ? to_app(_ast)->get_decl() : 0; } @@ -302,7 +302,7 @@ class iz3mgr { } } - type get_type(ast t){ + type get_type(const ast& t){ return m().get_sort(to_expr(t.raw())); } @@ -442,23 +442,23 @@ class iz3mgr { bool is_farkas_coefficient_negative(const ast &proof, int n); - bool is_true(ast t){ + bool is_true(const ast& t){ return op(t) == True; } - bool is_false(ast t){ + bool is_false(const ast& t){ return op(t) == False; } - bool is_iff(ast t){ + bool is_iff(const ast& t){ return op(t) == Iff; } - bool is_or(ast t){ + bool is_or(const ast& t){ return op(t) == Or; } - bool is_not(ast t){ + bool is_not(const ast& t){ return op(t) == Not; } @@ -472,7 +472,7 @@ class iz3mgr { // Some constructors that simplify things - ast mk_not(ast x){ + ast mk_not(const ast& x){ opr o = op(x); if(o == True) return make(False); if(o == False) return make(True); @@ -480,7 +480,7 @@ class iz3mgr { return make(Not,x); } - ast mk_and(ast x, ast y){ + ast mk_and(const ast& x, const ast& y){ opr ox = op(x); opr oy = op(y); if(ox == True) return y; @@ -491,7 +491,7 @@ class iz3mgr { return make(And,x,y); } - ast mk_or(ast x, ast y){ + ast mk_or(const ast& x, const ast& y){ opr ox = op(x); opr oy = op(y); if(ox == False) return y; @@ -502,7 +502,7 @@ class iz3mgr { return make(Or,x,y); } - ast mk_implies(ast x, ast y){ + ast mk_implies(const ast& x, const ast& y){ opr ox = op(x); opr oy = op(y); if(ox == True) return y; @@ -537,7 +537,7 @@ class iz3mgr { return make(And,conjs); } - ast mk_equal(ast x, ast y){ + ast mk_equal(const ast& x, const ast& y){ if(x == y) return make(True); opr ox = op(x); opr oy = op(y); @@ -550,7 +550,7 @@ class iz3mgr { return make(Equal,x,y); } - ast z3_ite(ast x, ast y, ast z){ + ast z3_ite(const ast& x, const ast& y, const ast& z){ opr ox = op(x); opr oy = op(y); opr oz = op(z); diff --git a/src/util/lp/core_solver_pretty_printer.h b/src/util/lp/core_solver_pretty_printer.h index 20b2c1cbe..87c528792 100644 --- a/src/util/lp/core_solver_pretty_printer.h +++ b/src/util/lp/core_solver_pretty_printer.h @@ -86,7 +86,7 @@ public: unsigned get_column_width(unsigned column); - unsigned regular_cell_width(unsigned row, unsigned column, std::string name) { + unsigned regular_cell_width(unsigned row, unsigned column, const std::string & name) { return regular_cell_string(row, column, name).size(); } diff --git a/src/util/lp/mps_reader.h b/src/util/lp/mps_reader.h index 1b020407d..916e56322 100644 --- a/src/util/lp/mps_reader.h +++ b/src/util/lp/mps_reader.h @@ -95,7 +95,7 @@ inline vector string_split(const std::string &source, const char *d return results; } -inline vector split_and_trim(std::string line) { +inline vector split_and_trim(const std::string &line) { auto split = string_split(line, " \t", false); vector ret; for (auto s : split) { @@ -127,9 +127,9 @@ class mps_reader { std::string m_name; bound * m_bound; unsigned m_index; - column(std::string name, unsigned index): m_name(name), - m_bound(nullptr), - m_index(index) { + column(const std::string &name, unsigned index): m_name(name), + m_bound(nullptr), + m_index(index) { } }; @@ -140,7 +140,7 @@ class mps_reader { unsigned m_index; T m_right_side; T m_range; - row(row_type type, std::string name, unsigned index) : + row(row_type type, const std::string &name, unsigned index) : m_type(type), m_name(name), m_index(index), @@ -254,7 +254,7 @@ class mps_reader { } while (m_is_OK); } - void read_column_by_columns(std::string column_name, std::string column_data) { + void read_column_by_columns(const std::string & column_name, std::string column_data) { // uph, let us try to work with columns if (column_data.size() >= 22) { std::string ss = column_data.substr(0, 8); @@ -283,7 +283,7 @@ class mps_reader { } } - void read_column(std::string column_name, std::string column_data){ + void read_column(const std::string & column_name, const std::string & column_data){ auto tokens = split_and_trim(column_data); for (unsigned i = 0; i < tokens.size() - 1; i+= 2) { auto row_name = tokens[i]; @@ -421,7 +421,7 @@ class mps_reader { } - void read_bound_by_columns(std::string colstr) { + void read_bound_by_columns(const std::string & colstr) { if (colstr.size() < 14) { (*m_message_stream) << "line is too short" << std::endl; (*m_message_stream) << m_line << std::endl; @@ -763,7 +763,7 @@ public: } } - mps_reader(std::string file_name): + mps_reader(const std::string & file_name): m_is_OK(true), m_file_name(file_name), m_file_stream(file_name), From 19b858dbea1ae968a2f886213208fb53220cb059 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 04:00:32 -0800 Subject: [PATCH 0558/1283] fix reset code for level marking Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 +- src/sat/sat_solver.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 3b9b81448..e5dd057bb 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1389,7 +1389,7 @@ namespace sat { } } } - else { + else if (lvl(lit) < m_conflict_lvl) { slack -= std::abs(coeff); m_lemma.push_back(~lit); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index e384a944d..84a875d55 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2536,8 +2536,13 @@ namespace sat { } num = i; // reset m_diff_levels. - for (i = 0; i < num; i++) - m_diff_levels[lvl(lits[i])] = false; + for (i = 0; i < num; i++) { + literal lit = lits[i]; + if (value(lit) == l_false) { + VERIFY(lvl(lit) < m_diff_levels.size()); + m_diff_levels[lvl(lit)] = false; + } + } return glue < max_glue; } From b7d1753843609dc007ea2d919e62b910da632da6 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 9 Feb 2018 21:15:02 +0700 Subject: [PATCH 0559/1283] Use override rather than virtual. --- src/ast/arith_decl_plugin.h | 38 +-- src/ast/array_decl_plugin.h | 18 +- src/ast/ast.h | 74 +++--- src/ast/ast_printer.cpp | 20 +- src/ast/ast_printer.h | 2 +- src/ast/ast_smt2_pp.h | 18 +- src/ast/bv_decl_plugin.h | 32 +-- src/ast/datatype_decl_plugin.h | 54 ++-- src/ast/dl_decl_plugin.h | 18 +- src/ast/expr2polynomial.h | 6 +- src/ast/expr_functors.h | 2 +- src/ast/format.cpp | 14 +- src/ast/fpa_decl_plugin.h | 30 +-- src/ast/normal_forms/defined_names.cpp | 2 +- src/ast/normal_forms/name_exprs.cpp | 16 +- src/ast/pb_decl_plugin.h | 14 +- src/ast/proofs/proof_checker.h | 22 +- src/ast/rewriter/elim_bounds.h | 2 +- src/ast/rewriter/expr_replacer.cpp | 22 +- src/ast/rewriter/maximize_ac_sharing.h | 4 +- src/ast/rewriter/pull_ite_tree.h | 4 +- src/ast/rewriter/push_app_ite.h | 2 +- src/ast/rewriter/rewriter.h | 6 +- src/ast/rewriter/seq_rewriter.cpp | 16 +- src/ast/seq_decl_plugin.h | 28 +- src/cmd_context/basic_cmds.cpp | 134 +++++----- src/cmd_context/cmd_context.cpp | 26 +- src/cmd_context/cmd_context.h | 36 +-- src/cmd_context/echo_tactic.cpp | 22 +- src/cmd_context/eval_cmd.cpp | 14 +- src/cmd_context/extra_cmds/dbg_cmds.cpp | 60 ++--- .../extra_cmds/polynomial_cmds.cpp | 32 +-- src/cmd_context/interpolant_cmds.cpp | 16 +- src/cmd_context/parametric_cmd.h | 28 +- src/cmd_context/pdecl.cpp | 68 ++--- src/cmd_context/pdecl.h | 74 +++--- src/cmd_context/simplify_cmd.cpp | 18 +- src/cmd_context/tactic_cmds.cpp | 40 +-- src/duality/duality.h | 36 +-- src/duality/duality_solver.cpp | 76 +++--- src/math/automata/boolean_algebra.h | 2 +- src/math/polynomial/polynomial_var2value.h | 6 +- src/model/model.cpp | 2 +- src/model/model.h | 12 +- src/nlsat/nlsat_assignment.h | 12 +- src/nlsat/nlsat_solver.cpp | 4 +- src/nlsat/tactic/goal2nlsat.cpp | 4 +- src/nlsat/tactic/nlsat_tactic.cpp | 26 +- src/solver/check_sat_result.h | 18 +- src/solver/combined_solver.cpp | 58 ++-- src/solver/solver.h | 2 +- src/solver/solver2tactic.cpp | 28 +- src/solver/solver_na2as.h | 22 +- src/solver/solver_pool.cpp | 38 +-- src/solver/tactic2solver.cpp | 48 ++-- src/tactic/aig/aig_tactic.cpp | 18 +- src/tactic/arith/add_bounds_tactic.cpp | 24 +- src/tactic/arith/arith_bounds_tactic.cpp | 14 +- src/tactic/arith/card2bv_tactic.cpp | 20 +- src/tactic/arith/degree_shift_tactic.cpp | 16 +- src/tactic/arith/diff_neq_tactic.cpp | 24 +- src/tactic/arith/elim01_tactic.cpp | 22 +- src/tactic/arith/eq2bv_tactic.cpp | 25 +- src/tactic/arith/factor_tactic.cpp | 20 +- src/tactic/arith/fix_dl_var_tactic.cpp | 20 +- src/tactic/arith/fm_tactic.cpp | 28 +- src/tactic/arith/lia2card_tactic.cpp | 18 +- src/tactic/arith/lia2pb_tactic.cpp | 20 +- src/tactic/arith/nla2bv_tactic.cpp | 20 +- src/tactic/arith/normalize_bounds_tactic.cpp | 20 +- src/tactic/arith/pb2bv_model_converter.h | 10 +- src/tactic/arith/pb2bv_tactic.cpp | 22 +- src/tactic/arith/probe_arith.cpp | 34 +-- src/tactic/arith/propagate_ineqs_tactic.cpp | 12 +- src/tactic/arith/purify_arith_tactic.cpp | 20 +- src/tactic/arith/recover_01_tactic.cpp | 18 +- src/tactic/bv/bit_blaster_model_converter.cpp | 10 +- src/tactic/bv/bit_blaster_tactic.cpp | 20 +- src/tactic/bv/bv1_blaster_tactic.cpp | 22 +- src/tactic/bv/bv_bound_chk_tactic.cpp | 16 +- src/tactic/bv/bv_bounds_tactic.cpp | 28 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 8 +- src/tactic/bv/bvarray2uf_tactic.cpp | 20 +- src/tactic/bv/dt2bv_tactic.cpp | 22 +- src/tactic/bv/elim_small_bv_tactic.cpp | 14 +- src/tactic/bv/max_bv_sharing_tactic.cpp | 20 +- src/tactic/converter.h | 12 +- src/tactic/core/blast_term_ite_tactic.cpp | 20 +- src/tactic/core/cofactor_term_ite_tactic.cpp | 20 +- src/tactic/core/collect_statistics_tactic.cpp | 22 +- src/tactic/core/ctx_simplify_tactic.cpp | 12 +- src/tactic/core/ctx_simplify_tactic.h | 20 +- src/tactic/core/der_tactic.cpp | 16 +- src/tactic/core/distribute_forall_tactic.cpp | 14 +- src/tactic/core/dom_simplify_tactic.h | 32 +-- src/tactic/core/elim_term_ite_tactic.cpp | 20 +- src/tactic/core/elim_uncnstr_tactic.cpp | 24 +- src/tactic/core/injectivity_tactic.cpp | 20 +- src/tactic/core/nnf_tactic.cpp | 20 +- src/tactic/core/occf_tactic.cpp | 20 +- src/tactic/core/pb_preprocess_tactic.cpp | 25 +- src/tactic/core/propagate_values_tactic.cpp | 20 +- src/tactic/core/reduce_args_tactic.cpp | 8 +- src/tactic/core/simplify_tactic.h | 22 +- src/tactic/core/solve_eqs_tactic.cpp | 24 +- src/tactic/core/split_clause_tactic.cpp | 26 +- src/tactic/core/symmetry_reduce_tactic.cpp | 16 +- src/tactic/core/tseitin_cnf_tactic.cpp | 24 +- src/tactic/equiv_proof_converter.h | 6 +- src/tactic/extension_model_converter.h | 8 +- src/tactic/filter_model_converter.h | 12 +- src/tactic/fpa/fpa2bv_model_converter.h | 10 +- src/tactic/fpa/fpa2bv_tactic.cpp | 20 +- src/tactic/fpa/qffp_tactic.cpp | 8 +- src/tactic/horn_subsume_model_converter.h | 4 +- src/tactic/model_converter.cpp | 34 +-- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 22 +- .../portfolio/bounded_int2bv_solver.cpp | 44 +-- src/tactic/portfolio/enum2bv_solver.cpp | 44 +-- src/tactic/portfolio/pb2bv_solver.cpp | 44 +-- src/tactic/portfolio/smt_strategic_solver.cpp | 4 +- src/tactic/probe.cpp | 52 ++-- src/tactic/proof_converter.cpp | 20 +- src/tactic/proof_converter.h | 2 +- src/tactic/replace_proof_converter.h | 6 +- src/tactic/sine_filter.cpp | 18 +- src/tactic/sls/sls_tactic.cpp | 24 +- src/tactic/smtlogics/qflia_tactic.cpp | 2 +- src/tactic/smtlogics/qfufbv_tactic.cpp | 16 +- src/tactic/tactic.cpp | 44 +-- src/tactic/tactic.h | 6 +- src/tactic/tactic_exception.h | 4 +- src/tactic/tactical.cpp | 251 +++++++++--------- src/tactic/ufbv/macro_finder_tactic.cpp | 20 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 20 +- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 20 +- src/util/cancel_eh.h | 4 +- src/util/z3_exception.h | 8 +- 138 files changed, 1621 insertions(+), 1624 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 4850b52a8..6cebdaded 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -145,7 +145,7 @@ protected: bool m_convert_int_numerals_to_real; func_decl * mk_func_decl(decl_kind k, bool is_real); - virtual void set_manager(ast_manager * m, family_id id); + void set_manager(ast_manager * m, family_id id) override; decl_kind fix_kind(decl_kind k, unsigned arity); void check_arity(unsigned arity, unsigned expected_arity); func_decl * mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity); @@ -153,38 +153,38 @@ protected: public: arith_decl_plugin(); - virtual ~arith_decl_plugin(); - virtual void finalize(); + ~arith_decl_plugin() override; + void finalize() override; algebraic_numbers::manager & am() const; algebraic_numbers_wrapper & aw() const; - virtual void del(parameter const & p); - virtual parameter translate(parameter const & p, decl_plugin & target); + void del(parameter const & p) override; + parameter translate(parameter const & p, decl_plugin & target) override; - virtual decl_plugin * mk_fresh() { + decl_plugin * mk_fresh() override { return alloc(arith_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned num_args, expr * const * args, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned num_args, expr * const * args, sort * range) override; - virtual bool is_value(app * e) const; + bool is_value(app * e) const override; - virtual bool is_unique_value(app * e) const; + bool is_unique_value(app * e) const override; - virtual bool are_equal(app * a, app * b) const; + bool are_equal(app * a, app * b) const override; - virtual bool are_distinct(app * a, app * b) const; + bool are_distinct(app * a, app * b) const override; - virtual void get_op_names(svector & op_names, symbol const & logic); + void get_op_names(svector & op_names, symbol const & logic) override; - virtual void get_sort_names(svector & sort_names, symbol const & logic); + void get_sort_names(svector & sort_names, symbol const & logic) override; app * mk_numeral(rational const & n, bool is_int); @@ -197,9 +197,9 @@ public: app * mk_e() const { return m_e; } - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; - virtual bool is_considered_uninterpreted(func_decl * f) { + bool is_considered_uninterpreted(func_decl * f) override { if (f->get_family_id() != get_family_id()) return false; switch (f->get_decl_kind()) diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 911bb3f27..488ee71fb 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -98,9 +98,9 @@ class array_decl_plugin : public decl_plugin { bool is_array_sort(sort* s) const; public: array_decl_plugin(); - virtual ~array_decl_plugin() {} + ~array_decl_plugin() override {} - virtual decl_plugin * mk_fresh() { + decl_plugin * mk_fresh() override { return alloc(array_decl_plugin); } @@ -111,23 +111,23 @@ class array_decl_plugin : public decl_plugin { // parameters[n-1] - nth dimension // parameters[n] - range // - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; // // Contract for func_decl: // parameters[0] - array sort // Contract for others: // no parameters - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual void get_op_names(svector & op_names, symbol const & logic); + void get_op_names(svector & op_names, symbol const & logic) override; - virtual void get_sort_names(svector & sort_names, symbol const & logic); + void get_sort_names(svector & sort_names, symbol const & logic) override; - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; - virtual bool is_fully_interp(sort * s) const; + bool is_fully_interp(sort * s) const override; }; class array_recognizers { diff --git a/src/ast/ast.h b/src/ast/ast.h index 7a662a193..77049fa53 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1129,7 +1129,7 @@ protected: unsigned num_parameters, parameter const* params, unsigned num_parents); - virtual void set_manager(ast_manager * m, family_id id); + void set_manager(ast_manager * m, family_id id) override; func_decl * mk_eq_decl_core(char const * name, decl_kind k, sort * s, ptr_vector & cache); func_decl * mk_ite_decl(sort * s); sort* join(sort* s1, sort* s2); @@ -1138,33 +1138,33 @@ protected: public: basic_decl_plugin(); - virtual ~basic_decl_plugin() {} - virtual void finalize(); + ~basic_decl_plugin() override {} + void finalize() override; - virtual decl_plugin * mk_fresh() { + decl_plugin * mk_fresh() override { return alloc(basic_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned num_args, expr * const * args, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned num_args, expr * const * args, sort * range) override; - virtual void get_op_names(svector & op_names, symbol const & logic); + void get_op_names(svector & op_names, symbol const & logic) override; - virtual void get_sort_names(svector & sort_names, symbol const & logic); + void get_sort_names(svector & sort_names, symbol const & logic) override; - virtual bool is_value(app* a) const; + bool is_value(app* a) const override; - virtual bool is_unique_value(app* a) const; + bool is_unique_value(app* a) const override; sort * mk_bool_sort() const { return m_bool_sort; } sort * mk_proof_sort() const { return m_proof_sort; } - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; }; typedef app proof; /* a proof is just an application */ @@ -1188,15 +1188,15 @@ class label_decl_plugin : public decl_plugin { symbol m_lblneg; symbol m_lbllit; - virtual void set_manager(ast_manager * m, family_id id); + void set_manager(ast_manager * m, family_id id) override; public: label_decl_plugin(); - virtual ~label_decl_plugin(); + ~label_decl_plugin() override; - virtual decl_plugin * mk_fresh() { return alloc(label_decl_plugin); } + decl_plugin * mk_fresh() override { return alloc(label_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; /** contract: when label @@ -1210,8 +1210,8 @@ public: ... parameter[n-1] (symbol): label's tag. */ - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; }; // ----------------------------------- @@ -1230,12 +1230,12 @@ enum pattern_op_kind { */ class pattern_decl_plugin : public decl_plugin { public: - virtual decl_plugin * mk_fresh() { return alloc(pattern_decl_plugin); } + decl_plugin * mk_fresh() override { return alloc(pattern_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; }; // ----------------------------------- @@ -1263,21 +1263,21 @@ class model_value_decl_plugin : public decl_plugin { public: model_value_decl_plugin() {} - virtual decl_plugin * mk_fresh() { return alloc(model_value_decl_plugin); } + decl_plugin * mk_fresh() override { return alloc(model_value_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; /** contract: parameter[0]: (integer) value idx parameter[1]: (ast) sort of the value. */ - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual bool is_value(app* n) const; + bool is_value(app* n) const override; - virtual bool is_unique_value(app* a) const; + bool is_unique_value(app* a) const override; }; // ----------------------------------- @@ -1292,11 +1292,11 @@ class user_sort_plugin : public decl_plugin { public: user_sort_plugin() {} - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; decl_kind register_name(symbol s); - virtual decl_plugin * mk_fresh(); + decl_plugin * mk_fresh() override; }; @@ -2467,9 +2467,9 @@ class scoped_mark : public ast_mark { unsigned_vector m_lim; public: scoped_mark(ast_manager& m): m_stack(m) {} - virtual ~scoped_mark() {} - virtual void mark(ast * n, bool flag); - virtual void reset(); + ~scoped_mark() override {} + void mark(ast * n, bool flag) override; + void reset() override; void mark(ast * n); void push_scope(); void pop_scope(); diff --git a/src/ast/ast_printer.cpp b/src/ast/ast_printer.cpp index b5cf60ee9..63e855c59 100644 --- a/src/ast/ast_printer.cpp +++ b/src/ast/ast_printer.cpp @@ -25,24 +25,24 @@ class simple_ast_printer_context : public ast_printer_context { smt2_pp_environment_dbg & env() const { return *(m_env.get()); } public: simple_ast_printer_context(ast_manager & m):m_manager(m) { m_env = alloc(smt2_pp_environment_dbg, m); } - virtual ~simple_ast_printer_context() {} + ~simple_ast_printer_context() override {} ast_manager & m() const { return m_manager; } - virtual ast_manager & get_ast_manager() { return m_manager; } - virtual void display(std::ostream & out, sort * s, unsigned indent = 0) const { out << mk_ismt2_pp(s, m(), indent); } - virtual void display(std::ostream & out, expr * n, unsigned indent = 0) const { out << mk_ismt2_pp(n, m(), indent); } - virtual void display(std::ostream & out, func_decl * f, unsigned indent = 0) const { + ast_manager & get_ast_manager() override { return m_manager; } + void display(std::ostream & out, sort * s, unsigned indent = 0) const override { out << mk_ismt2_pp(s, m(), indent); } + void display(std::ostream & out, expr * n, unsigned indent = 0) const override { out << mk_ismt2_pp(n, m(), indent); } + void display(std::ostream & out, func_decl * f, unsigned indent = 0) const override { out << f->get_name(); } - virtual void pp(sort * s, format_ns::format_ref & r) const { mk_smt2_format(s, env(), params_ref(), r); } - virtual void pp(func_decl * f, format_ns::format_ref & r) const { mk_smt2_format(f, env(), params_ref(), r); } - virtual void pp(expr * n, format_ns::format_ref & r) const { + void pp(sort * s, format_ns::format_ref & r) const override { mk_smt2_format(s, env(), params_ref(), r); } + void pp(func_decl * f, format_ns::format_ref & r) const override { mk_smt2_format(f, env(), params_ref(), r); } + void pp(expr * n, format_ns::format_ref & r) const override { sbuffer buf; mk_smt2_format(n, env(), params_ref(), 0, 0, r, buf); } - virtual void pp(expr * n, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer & var_names) const { + void pp(expr * n, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer & var_names) const override { mk_smt2_format(n, env(), params_ref(), num_vars, var_prefix, r, var_names); } - virtual void display(std::ostream & out, expr * n, unsigned indent, unsigned num_vars, char const * var_prefix, sbuffer & var_names) const { + void display(std::ostream & out, expr * n, unsigned indent, unsigned num_vars, char const * var_prefix, sbuffer & var_names) const override { NOT_IMPLEMENTED_YET(); } diff --git a/src/ast/ast_printer.h b/src/ast/ast_printer.h index 87fa8ef3d..c962fedc5 100644 --- a/src/ast/ast_printer.h +++ b/src/ast/ast_printer.h @@ -45,7 +45,7 @@ public: class ast_printer_context : public ast_printer { public: - virtual ~ast_printer_context() {} + ~ast_printer_context() override {} virtual ast_manager & get_ast_manager() = 0; virtual std::ostream & regular_stream() { return std::cout; } virtual std::ostream & diagnostic_stream() { return std::cerr; } diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 3e8b1aa39..041622b74 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -80,15 +80,15 @@ class smt2_pp_environment_dbg : public smt2_pp_environment { datalog::dl_decl_util m_dlutil; public: smt2_pp_environment_dbg(ast_manager & m):m_manager(m), m_autil(m), m_bvutil(m), m_arutil(m), m_futil(m), m_sutil(m), m_dtutil(m), m_dlutil(m) {} - virtual ast_manager & get_manager() const { return m_manager; } - virtual arith_util & get_autil() { return m_autil; } - virtual bv_util & get_bvutil() { return m_bvutil; } - virtual seq_util & get_sutil() { return m_sutil; } - virtual array_util & get_arutil() { return m_arutil; } - virtual fpa_util & get_futil() { return m_futil; } - virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; } - virtual datatype_util& get_dtutil() { return m_dtutil; } - virtual bool uses(symbol const & s) const { return false; } + ast_manager & get_manager() const override { return m_manager; } + arith_util & get_autil() override { return m_autil; } + bv_util & get_bvutil() override { return m_bvutil; } + seq_util & get_sutil() override { return m_sutil; } + array_util & get_arutil() override { return m_arutil; } + fpa_util & get_futil() override { return m_futil; } + datalog::dl_decl_util& get_dlutil() override { return m_dlutil; } + datatype_util& get_dtutil() override { return m_dtutil; } + bool uses(symbol const & s) const override { return false; } }; void mk_smt2_format(expr * n, smt2_pp_environment & env, params_ref const & p, diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index a4ea7af80..18054ca09 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -204,7 +204,7 @@ protected: vector > m_bit2bool; ptr_vector m_mkbv; - virtual void set_manager(ast_manager * m, family_id id); + void set_manager(ast_manager * m, family_id id) override; void mk_bv_sort(unsigned bv_size); sort * get_bv_sort(unsigned bv_size); func_decl * mk_func_decl(decl_kind k, unsigned bv_size); @@ -241,34 +241,34 @@ protected: public: bv_decl_plugin(); - virtual ~bv_decl_plugin() {} - virtual void finalize(); + ~bv_decl_plugin() override {} + void finalize() override; - virtual decl_plugin * mk_fresh() { return alloc(bv_decl_plugin); } + decl_plugin * mk_fresh() override { return alloc(bv_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned num_args, expr * const * args, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned num_args, expr * const * args, sort * range) override; - virtual bool is_value(app * e) const; + bool is_value(app * e) const override; - virtual bool is_unique_value(app * e) const { return is_value(e); } + bool is_unique_value(app * e) const override { return is_value(e); } - virtual void get_op_names(svector & op_names, symbol const & logic); + void get_op_names(svector & op_names, symbol const & logic) override; - virtual void get_sort_names(svector & sort_names, symbol const & logic); + void get_sort_names(svector & sort_names, symbol const & logic) override; - virtual bool are_distinct(app* a, app* b) const; + bool are_distinct(app* a, app* b) const override; - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; bool get_int2bv_size(unsigned num_parameters, parameter const * parameters, int & result); - virtual bool is_considered_uninterpreted(func_decl * f) { + bool is_considered_uninterpreted(func_decl * f) override { if (f->get_family_id() != get_family_id()) return false; switch (f->get_decl_kind()) { diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 515ca6e20..b61142909 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -124,16 +124,16 @@ namespace datatype { struct offset : public size { sort_size m_offset; offset(sort_size const& s): m_offset(s) {} - virtual ~offset() {} - virtual size* subst(obj_map& S) { return this; } - virtual sort_size eval(obj_map const& S) { return m_offset; } + ~offset() override {} + size* subst(obj_map& S) override { return this; } + sort_size eval(obj_map const& S) override { return m_offset; } }; struct plus : public size { size* m_arg1, *m_arg2; plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();} - virtual ~plus() { m_arg1->dec_ref(); m_arg2->dec_ref(); } - virtual size* subst(obj_map& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size eval(obj_map const& S) { + ~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; @@ -147,9 +147,9 @@ namespace datatype { struct times : public size { size* m_arg1, *m_arg2; times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } - virtual ~times() { m_arg1->dec_ref(); m_arg2->dec_ref(); } - virtual size* subst(obj_map& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size eval(obj_map const& S) { + ~times() override { m_arg1->dec_ref(); m_arg2->dec_ref(); } + size* subst(obj_map& S) override { return mk_times(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; @@ -163,9 +163,9 @@ namespace datatype { struct power : public size { size* m_arg1, *m_arg2; power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } - virtual ~power() { m_arg1->dec_ref(); m_arg2->dec_ref(); } - virtual size* subst(obj_map& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size eval(obj_map const& S) { + ~power() override { m_arg1->dec_ref(); m_arg2->dec_ref(); } + size* subst(obj_map& S) override { return mk_power(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); // s1^s2 @@ -183,9 +183,9 @@ namespace datatype { struct sparam : public size { sort_ref m_param; sparam(sort_ref& p): m_param(p) {} - virtual ~sparam() {} - virtual size* subst(obj_map& S) { return S[m_param]; } - virtual sort_size eval(obj_map const& S) { return S[m_param]; } + ~sparam() override {} + size* subst(obj_map& S) override { return S[m_param]; } + sort_size eval(obj_map const& S) override { return S[m_param]; } }; }; @@ -241,30 +241,30 @@ namespace datatype { unsigned m_class_id; util & u() const; - virtual void inherit(decl_plugin* other_p, ast_translation& tr); + void inherit(decl_plugin* other_p, ast_translation& tr) override; public: plugin(): m_class_id(0) {} - virtual ~plugin(); + ~plugin() override; - virtual void finalize(); + void finalize() override; - virtual decl_plugin * mk_fresh() { return alloc(plugin); } + decl_plugin * mk_fresh() override { return alloc(plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; - virtual bool is_fully_interp(sort * s) const; + bool is_fully_interp(sort * s) const override; - virtual bool is_value(app* e) const; + bool is_value(app* e) const override; - virtual bool is_unique_value(app * e) const { return is_value(e); } + bool is_unique_value(app * e) const override { return is_value(e); } - virtual void get_op_names(svector & op_names, symbol const & logic); + void get_op_names(svector & op_names, symbol const & logic) override; void begin_def_block() { m_class_id++; m_def_block.reset(); } diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 75969d385..2c68cc12c 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -102,9 +102,9 @@ namespace datalog { public: dl_decl_plugin(); - virtual ~dl_decl_plugin() {} + ~dl_decl_plugin() override {} - virtual decl_plugin * mk_fresh() { return alloc(dl_decl_plugin); } + decl_plugin * mk_fresh() override { return alloc(dl_decl_plugin); } // // Contract for sort DL_RELATION_SORT @@ -116,7 +116,7 @@ namespace datalog { // parameters[0] - name // parameters[1] - uint64 // - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; // // Contract for func_decl: @@ -126,15 +126,15 @@ namespace datalog { // parameters[1] - a DL_FINITE_SORT sort of the constant // Contract for others: // no parameters - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual void get_op_names(svector & op_names, symbol const & logic); + void get_op_names(svector & op_names, symbol const & logic) override; - virtual void get_sort_names(svector & sort_names, symbol const & logic); + void get_sort_names(svector & sort_names, symbol const & logic) override; - virtual bool is_value(app * e) const { return is_app_of(e, m_family_id, OP_DL_CONSTANT); } - virtual bool is_unique_value(app * e) const { return is_value(e); } + bool is_value(app * e) const override { return is_app_of(e, m_family_id, OP_DL_CONSTANT); } + bool is_unique_value(app * e) const override { return is_value(e); } }; diff --git a/src/ast/expr2polynomial.h b/src/ast/expr2polynomial.h index e7cbac6e5..8becf55dd 100644 --- a/src/ast/expr2polynomial.h +++ b/src/ast/expr2polynomial.h @@ -103,10 +103,10 @@ class default_expr2polynomial : public expr2polynomial { svector m_is_int; public: default_expr2polynomial(ast_manager & am, polynomial::manager & pm); - virtual ~default_expr2polynomial(); - virtual bool is_int(polynomial::var x) const; + ~default_expr2polynomial() override; + bool is_int(polynomial::var x) const override; protected: - virtual polynomial::var mk_var(bool is_int); + polynomial::var mk_var(bool is_int) override; }; #endif diff --git a/src/ast/expr_functors.h b/src/ast/expr_functors.h index 322b9402a..3d66a69ae 100644 --- a/src/ast/expr_functors.h +++ b/src/ast/expr_functors.h @@ -73,7 +73,7 @@ class contains_app { app* m_x; public: pred(app* x) : m_x(x) {} - virtual bool operator()(expr* e) { + bool operator()(expr* e) override { return m_x == e; } }; diff --git a/src/ast/format.cpp b/src/ast/format.cpp index 6c2a02989..3013e3e40 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -32,7 +32,7 @@ namespace format_ns { symbol m_line_break; symbol m_line_break_ext; - virtual void set_manager(ast_manager * m, family_id id) { + void set_manager(ast_manager * m, family_id id) override { SASSERT(m->is_format_manager()); decl_plugin::set_manager(m, id); @@ -52,24 +52,24 @@ namespace format_ns { m_line_break_ext("cr++") { } - virtual ~format_decl_plugin() {} + ~format_decl_plugin() override {} - virtual void finalize() { + void finalize() override { if (m_format_sort) m_manager->dec_ref(m_format_sort); } - virtual decl_plugin * mk_fresh() { + decl_plugin * mk_fresh() override { return alloc(format_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters) { + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters) override { SASSERT(k == FORMAT_SORT); return m_format_sort; } - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override { switch (k) { case OP_NIL: return m_manager->mk_func_decl(m_nil, arity, domain, m_format_sort, diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 4e86c9d3f..4d0accfbb 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -159,11 +159,11 @@ class fpa_decl_plugin : public decl_plugin { func_decl * mk_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); - virtual void set_manager(ast_manager * m, family_id id); + void set_manager(ast_manager * m, family_id id) override; unsigned mk_id(mpf const & v); void recycled_id(unsigned id); - virtual bool is_considered_uninterpreted(func_decl * f) { return false; } + bool is_considered_uninterpreted(func_decl * f) override { return false; } public: fpa_decl_plugin(); @@ -171,18 +171,18 @@ public: bool is_float_sort(sort * s) const { return is_sort_of(s, m_family_id, FLOATING_POINT_SORT); } bool is_rm_sort(sort * s) const { return is_sort_of(s, m_family_id, ROUNDING_MODE_SORT); } - virtual ~fpa_decl_plugin(); - virtual void finalize(); + ~fpa_decl_plugin() override; + void finalize() override; - virtual decl_plugin * mk_fresh(); - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - virtual void get_op_names(svector & op_names, symbol const & logic); - virtual void get_sort_names(svector & sort_names, symbol const & logic); - virtual expr * get_some_value(sort * s); - virtual bool is_value(app* e) const; - virtual bool is_unique_value(app* e) const; + decl_plugin * mk_fresh() override; + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; + void get_op_names(svector & op_names, symbol const & logic) override; + void get_sort_names(svector & sort_names, symbol const & logic) override; + expr * get_some_value(sort * s) override; + bool is_value(app* e) const override; + bool is_unique_value(app* e) const override; mpf_manager & fm() { return m_fm; } func_decl * mk_numeral_decl(mpf const & v); @@ -197,8 +197,8 @@ public: return m_values[id]; } - virtual void del(parameter const & p); - virtual parameter translate(parameter const & p, decl_plugin & target); + void del(parameter const & p) override; + parameter translate(parameter const & p, decl_plugin & target) override; }; class fpa_util { diff --git a/src/ast/normal_forms/defined_names.cpp b/src/ast/normal_forms/defined_names.cpp index 12085b992..cab14c433 100644 --- a/src/ast/normal_forms/defined_names.cpp +++ b/src/ast/normal_forms/defined_names.cpp @@ -74,7 +74,7 @@ struct defined_names::impl { struct defined_names::pos_impl : public defined_names::impl { pos_impl(ast_manager & m, char const * fresh_prefix):impl(m, fresh_prefix) {} - virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer const & var_names, expr_ref & new_def); + void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer const & var_names, expr_ref & new_def) override; }; diff --git a/src/ast/normal_forms/name_exprs.cpp b/src/ast/normal_forms/name_exprs.cpp index 7cc2719c9..909f0abb1 100644 --- a/src/ast/normal_forms/name_exprs.cpp +++ b/src/ast/normal_forms/name_exprs.cpp @@ -77,10 +77,10 @@ public: m_rw(m, m.proofs_enabled(), m_cfg) { } - virtual ~name_exprs_core() { + ~name_exprs_core() override { } - virtual void operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) { + void operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) override { m_cfg.m_def_exprs = &new_defs; m_cfg.m_def_proofs = &new_def_proofs; m_rw(n, r, p); @@ -88,7 +88,7 @@ public: } - virtual void reset() { + void reset() override { m_rw.reset(); } }; @@ -102,7 +102,7 @@ class name_quantifier_labels : public name_exprs_core { ast_manager & m_manager; public: pred(ast_manager & m):m_manager(m) {} - virtual bool operator()(expr * t) { + bool operator()(expr * t) override { return is_quantifier(t) || m_manager.is_label(t); } }; @@ -114,7 +114,7 @@ public: m_pred(m) { } - virtual ~name_quantifier_labels() { + ~name_quantifier_labels() override { } }; @@ -129,7 +129,7 @@ class name_nested_formulas : public name_exprs_core { pred(ast_manager & m):m_manager(m), m_root(0) {} - virtual bool operator()(expr * t) { + bool operator()(expr * t) override { TRACE("name_exprs", tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m_manager) << "\n";); if (is_app(t)) return to_app(t)->get_family_id() == m_manager.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root; @@ -145,10 +145,10 @@ public: m_pred(m) { } - virtual ~name_nested_formulas() { + ~name_nested_formulas() override { } - virtual void operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) { + void operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) override { m_pred.m_root = n; TRACE("name_exprs", tout << "operator()\n";); name_exprs_core::operator()(n, new_defs, new_def_proofs, r, p); diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index 7fdb592aa..e7c42d569 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -53,14 +53,14 @@ class pb_decl_plugin : public decl_plugin { func_decl * mk_eq(unsigned arity, rational const* coeffs, int k); public: pb_decl_plugin(); - virtual ~pb_decl_plugin() {} + ~pb_decl_plugin() override {} - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { UNREACHABLE(); return 0; } - virtual decl_plugin * mk_fresh() { + decl_plugin * mk_fresh() override { return alloc(pb_decl_plugin); } @@ -69,11 +69,11 @@ public: // parameters[0] - integer (at most k elements) // all sorts are Booleans // parameters[1] .. parameters[arity] - coefficients - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - virtual void get_op_names(svector & op_names, symbol const & logic); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; + void get_op_names(svector & op_names, symbol const & logic) override; - virtual bool is_considered_uninterpreted(func_decl * f) { return false; } + bool is_considered_uninterpreted(func_decl * f) override { return false; } }; diff --git a/src/ast/proofs/proof_checker.h b/src/ast/proofs/proof_checker.h index ce2684c51..ccb815c61 100644 --- a/src/ast/proofs/proof_checker.h +++ b/src/ast/proofs/proof_checker.h @@ -48,24 +48,24 @@ class proof_checker { func_decl* m_atom; func_decl* m_nil; sort* m_cell; - virtual void set_manager(ast_manager * m, family_id id); + void set_manager(ast_manager * m, family_id id) override; func_decl * mk_func_decl(decl_kind k); public: hyp_decl_plugin(); - virtual ~hyp_decl_plugin() {} + ~hyp_decl_plugin() override {} - virtual void finalize(); + void finalize() override; - virtual decl_plugin * mk_fresh() { return alloc(hyp_decl_plugin); } + decl_plugin * mk_fresh() override { return alloc(hyp_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters); - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned num_args, expr * const * args, sort * range); - virtual void get_op_names(svector & op_names, symbol const & logic); - virtual void get_sort_names(svector & sort_names, symbol const & logic); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters) override; + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned num_args, expr * const * args, sort * range) override; + void get_op_names(svector & op_names, symbol const & logic) override; + void get_sort_names(svector & sort_names, symbol const & logic) override; }; public: proof_checker(ast_manager& m); diff --git a/src/ast/rewriter/elim_bounds.h b/src/ast/rewriter/elim_bounds.h index e0bba4e60..4dcb24173 100644 --- a/src/ast/rewriter/elim_bounds.h +++ b/src/ast/rewriter/elim_bounds.h @@ -70,7 +70,7 @@ public: m_cfg(m) {} - virtual ~elim_bounds_rw() {} + ~elim_bounds_rw() override {} }; #endif /* ELIM_BOUNDS2_H_ */ diff --git a/src/ast/rewriter/expr_replacer.cpp b/src/ast/rewriter/expr_replacer.cpp index 70e12dced..fb85e3372 100644 --- a/src/ast/rewriter/expr_replacer.cpp +++ b/src/ast/rewriter/expr_replacer.cpp @@ -90,14 +90,14 @@ public: m_replacer(m, m.proofs_enabled(), m_cfg) { } - virtual ast_manager & m() const { return m_replacer.m(); } + ast_manager & m() const override { return m_replacer.m(); } - virtual void set_substitution(expr_substitution * s) { + void set_substitution(expr_substitution * s) override { m_replacer.cleanup(); m_replacer.cfg().m_subst = s; } - virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) { + void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) override { result_dep = 0; m_replacer.operator()(t, result, result_pr); if (m_cfg.m_used_dependencies != 0) { @@ -108,11 +108,11 @@ public: } - virtual unsigned get_num_steps() const { + unsigned get_num_steps() const override { return m_replacer.get_num_steps(); } - virtual void reset() { + void reset() override { m_replacer.reset(); } }; @@ -131,23 +131,23 @@ public: m_r(m, p) { } - virtual ~th_rewriter2expr_replacer() {} + ~th_rewriter2expr_replacer() override {} - virtual ast_manager & m() const { return m_r.m(); } + ast_manager & m() const override { return m_r.m(); } - virtual void set_substitution(expr_substitution * s) { m_r.set_substitution(s); } + void set_substitution(expr_substitution * s) override { m_r.set_substitution(s); } - virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) { + void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) override { m_r(t, result, result_pr); result_dep = m_r.get_used_dependencies(); m_r.reset_used_dependencies(); } - virtual unsigned get_num_steps() const { + unsigned get_num_steps() const override { return m_r.get_num_steps(); } - virtual void reset() { + void reset() override { m_r.reset(); } diff --git a/src/ast/rewriter/maximize_ac_sharing.h b/src/ast/rewriter/maximize_ac_sharing.h index c0ee0d09f..7144c7ad3 100644 --- a/src/ast/rewriter/maximize_ac_sharing.h +++ b/src/ast/rewriter/maximize_ac_sharing.h @@ -103,8 +103,8 @@ public: class maximize_bv_sharing : public maximize_ac_sharing { bv_util m_util; protected: - virtual void init_core(); - virtual bool is_numeral(expr * n) const; + void init_core() override; + bool is_numeral(expr * n) const override; public: maximize_bv_sharing(ast_manager & m); }; diff --git a/src/ast/rewriter/pull_ite_tree.h b/src/ast/rewriter/pull_ite_tree.h index 3ff0a716d..ea462315a 100644 --- a/src/ast/rewriter/pull_ite_tree.h +++ b/src/ast/rewriter/pull_ite_tree.h @@ -96,8 +96,8 @@ public: class pull_cheap_ite_tree_cfg : public pull_ite_tree_cfg { public: pull_cheap_ite_tree_cfg(ast_manager & m):pull_ite_tree_cfg(m) {} - virtual ~pull_cheap_ite_tree_cfg() {} - virtual bool is_target(app * n) const; + ~pull_cheap_ite_tree_cfg() override {} + bool is_target(app * n) const override; }; class pull_cheap_ite_tree_rw : public rewriter_tpl { diff --git a/src/ast/rewriter/push_app_ite.h b/src/ast/rewriter/push_app_ite.h index ae06aad30..8f737ea4d 100644 --- a/src/ast/rewriter/push_app_ite.h +++ b/src/ast/rewriter/push_app_ite.h @@ -45,7 +45,7 @@ struct push_app_ite_cfg : public default_rewriter_cfg { */ class ng_push_app_ite_cfg : public push_app_ite_cfg { protected: - virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args); + bool is_target(func_decl * decl, unsigned num_args, expr * const * args) override; public: ng_push_app_ite_cfg(ast_manager& m, bool conservative = true): push_app_ite_cfg(m, conservative) {} virtual ~ng_push_app_ite_cfg() {} diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h index 17742f670..8c00f541b 100644 --- a/src/ast/rewriter/rewriter.h +++ b/src/ast/rewriter/rewriter.h @@ -150,7 +150,7 @@ class var_shifter : public var_shifter_core { unsigned m_bound; unsigned m_shift1; unsigned m_shift2; - virtual void process_var(var * v); + void process_var(var * v) override; public: var_shifter(ast_manager & m):var_shifter_core(m) {} void operator()(expr * t, unsigned bound, unsigned shift1, unsigned shift2, expr_ref & r); @@ -183,7 +183,7 @@ public: class inv_var_shifter : public var_shifter_core { protected: unsigned m_shift; - virtual void process_var(var * v); + void process_var(var * v) override; public: inv_var_shifter(ast_manager & m):var_shifter_core(m) {} void operator()(expr * t, unsigned shift, expr_ref & r); @@ -339,7 +339,7 @@ public: Config & cfg() { return m_cfg; } Config const & cfg() const { return m_cfg; } - ~rewriter_tpl(); + ~rewriter_tpl() override; void reset(); void cleanup(); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index ec3e72cc4..5fb85d6bb 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -85,15 +85,15 @@ public: sym_expr_boolean_algebra(ast_manager& m, expr_solver& s): m(m), m_solver(s) {} - virtual T mk_false() { + T mk_false() override { expr_ref fml(m.mk_false(), m); return sym_expr::mk_pred(fml, m.mk_bool_sort()); // use of Bool sort for bound variable is arbitrary } - virtual T mk_true() { + T mk_true() override { expr_ref fml(m.mk_true(), m); return sym_expr::mk_pred(fml, m.mk_bool_sort()); } - virtual T mk_and(T x, T y) { + T mk_and(T x, T y) override { if (x->is_char() && y->is_char()) { if (x->get_char() == y->get_char()) { return x; @@ -118,7 +118,7 @@ public: br.mk_and(fml1, fml2, fml); return sym_expr::mk_pred(fml, x->get_sort()); } - virtual T mk_or(T x, T y) { + T mk_or(T x, T y) override { if (x->is_char() && y->is_char() && x->get_char() == y->get_char()) { return x; @@ -135,7 +135,7 @@ public: return sym_expr::mk_pred(fml, x->get_sort()); } - virtual T mk_and(unsigned sz, T const* ts) { + T mk_and(unsigned sz, T const* ts) override { switch (sz) { case 0: return mk_true(); case 1: return ts[0]; @@ -148,7 +148,7 @@ public: } } } - virtual T mk_or(unsigned sz, T const* ts) { + T mk_or(unsigned sz, T const* ts) override { switch (sz) { case 0: return mk_false(); case 1: return ts[0]; @@ -161,7 +161,7 @@ public: } } } - virtual lbool is_sat(T x) { + lbool is_sat(T x) override { if (x->is_char()) { return l_true; } @@ -178,7 +178,7 @@ public: } return m_solver.check_sat(fml); } - virtual T mk_not(T x) { + T mk_not(T x) override { var_ref v(m.mk_var(0, x->get_sort()), m); expr_ref fml(m.mk_not(x->accept(v)), m); return sym_expr::mk_pred(fml, x->get_sort()); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 2e3b3fd24..e765e69a4 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -162,34 +162,34 @@ class seq_decl_plugin : public decl_plugin { void init(); - virtual void set_manager(ast_manager * m, family_id id); + void set_manager(ast_manager * m, family_id id) override; public: seq_decl_plugin(); - virtual ~seq_decl_plugin() {} - virtual void finalize(); + ~seq_decl_plugin() override {} + void finalize() override; - virtual decl_plugin * mk_fresh() { return alloc(seq_decl_plugin); } + decl_plugin * mk_fresh() override { return alloc(seq_decl_plugin); } - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override; - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) override; - virtual void get_op_names(svector & op_names, symbol const & logic); + void get_op_names(svector & op_names, symbol const & logic) override; - virtual void get_sort_names(svector & sort_names, symbol const & logic); + void get_sort_names(svector & sort_names, symbol const & logic) override; - virtual bool is_value(app * e) const; + bool is_value(app * e) const override; - virtual bool is_unique_value(app * e) const { return false; } + bool is_unique_value(app * e) const override { return false; } - virtual bool are_equal(app* a, app* b) const; + bool are_equal(app* a, app* b) const override; - virtual bool are_distinct(app* a, app* b) const; + bool are_distinct(app* a, app* b) const override; - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; bool is_char(ast* a) const { return a == m_char; } diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 572abc8fe..f1357126c 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -49,12 +49,12 @@ class help_cmd : public cmd { public: help_cmd():cmd("help") {} - virtual char const * get_usage() const { return "*"; } - virtual char const * get_descr(cmd_context & ctx) const { return "print this help."; } - virtual unsigned get_arity() const { return VAR_ARITY; } - virtual void prepare(cmd_context & ctx) { m_cmds.reset(); } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_SYMBOL; } - virtual void set_next_arg(cmd_context & ctx, symbol const & s) { + char const * get_usage() const override { return "*"; } + char const * get_descr(cmd_context & ctx) const override { return "print this help."; } + unsigned get_arity() const override { return VAR_ARITY; } + void prepare(cmd_context & ctx) override { m_cmds.reset(); } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_SYMBOL; } + void set_next_arg(cmd_context & ctx, symbol const & s) override { cmd * c = ctx.find_cmd(s); if (c == 0) { std::string err_msg("unknown command '"); @@ -69,7 +69,7 @@ public: bool operator()(named_cmd const & c1, named_cmd const & c2) const { return c1.first.str() < c2.first.str(); } }; - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { ctx.regular_stream() << "\""; if (m_cmds.empty()) { vector cmds; @@ -101,14 +101,14 @@ class get_model_cmd : public cmd { unsigned m_index; public: get_model_cmd(): cmd("get-model"), m_index(0) {} - virtual char const * get_usage() const { return "[]"; } - virtual char const * get_descr(cmd_context & ctx) const { + char const * get_usage() const override { return "[]"; } + char const * get_descr(cmd_context & ctx) const override { return "retrieve model for the last check-sat command.\nSupply optional index if retrieving a model corresponding to a box optimization objective"; } - virtual unsigned get_arity() const { return VAR_ARITY; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_UINT; } - virtual void set_next_arg(cmd_context & ctx, unsigned index) { m_index = index; } - virtual void execute(cmd_context & ctx) { + unsigned get_arity() const override { return VAR_ARITY; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_UINT; } + void set_next_arg(cmd_context & ctx, unsigned index) override { m_index = index; } + void execute(cmd_context & ctx) override { if (!ctx.is_model_available() || ctx.get_check_sat_result() == 0) throw cmd_exception("model is not available"); model_ref m; @@ -120,7 +120,7 @@ public: } ctx.display_model(m); } - virtual void reset(cmd_context& ctx) { + void reset(cmd_context& ctx) override { m_index = 0; } }; @@ -166,10 +166,10 @@ class cmd_is_declared : public ast_smt_pp::is_declared { public: cmd_is_declared(cmd_context& ctx): m_ctx(ctx) {} - virtual bool operator()(func_decl* d) const { + bool operator()(func_decl* d) const override { return m_ctx.is_func_decl(d->get_name()); } - virtual bool operator()(sort* s) const { + bool operator()(sort* s) const override { return m_ctx.is_sort_decl(s->get_name()); } }; @@ -360,7 +360,7 @@ public: m_int_real_coercions(":int-real-coercions"), m_reproducible_resource_limit(":reproducible-resource-limit") { } - virtual ~set_get_option_cmd() {} + ~set_get_option_cmd() override {} }; @@ -477,19 +477,19 @@ public: m_unsupported(false) { } - virtual char const * get_usage() const { return " "; } + char const * get_usage() const override { return " "; } - virtual char const * get_descr(cmd_context & ctx) const { return "set configuration option."; } + char const * get_descr(cmd_context & ctx) const override { return "set configuration option."; } - virtual unsigned get_arity() const { return 2; } + unsigned get_arity() const override { return 2; } - virtual void prepare(cmd_context & ctx) { m_unsupported = false; m_option = symbol::null; } + void prepare(cmd_context & ctx) override { m_unsupported = false; m_option = symbol::null; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return m_option == symbol::null ? CPK_KEYWORD : CPK_OPTION_VALUE; } - virtual void set_next_arg(cmd_context & ctx, symbol const & opt) { + void set_next_arg(cmd_context & ctx, symbol const & opt) override { if (m_option == symbol::null) { m_option = opt; } @@ -498,7 +498,7 @@ public: } } - virtual void set_next_arg(cmd_context & ctx, rational const & val) { + void set_next_arg(cmd_context & ctx, rational const & val) override { if (m_option == m_random_seed) { ctx.set_random_seed(to_unsigned(val)); } @@ -517,7 +517,7 @@ public: } } - virtual void set_next_arg(cmd_context & ctx, char const * value) { + void set_next_arg(cmd_context & ctx, char const * value) override { if (m_option == m_regular_output_channel) { ctx.set_regular_stream(value); } @@ -532,7 +532,7 @@ public: } } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { if (m_unsupported) ctx.print_unsupported(m_option, m_line, m_pos); else @@ -557,11 +557,11 @@ public: get_option_cmd(): set_get_option_cmd("get-option") { } - virtual char const * get_usage() const { return ""; } - virtual char const * get_descr(cmd_context & ctx) const { return "get configuration option."; } - virtual unsigned get_arity() const { return 1; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_KEYWORD; } - virtual void set_next_arg(cmd_context & ctx, symbol const & opt) { + char const * get_usage() const override { return ""; } + char const * get_descr(cmd_context & ctx) const override { return "get configuration option."; } + unsigned get_arity() const override { return 1; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_KEYWORD; } + void set_next_arg(cmd_context & ctx, symbol const & opt) override { if (opt == m_print_success) { print_bool(ctx, ctx.print_success_enabled()); } @@ -651,11 +651,11 @@ public: m_all_statistics(":all-statistics"), m_assertion_stack_levels(":assertion-stack-levels") { } - virtual char const * get_usage() const { return ""; } - virtual char const * get_descr(cmd_context & ctx) const { return "get information."; } - virtual unsigned get_arity() const { return 1; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_KEYWORD; } - virtual void set_next_arg(cmd_context & ctx, symbol const & opt) { + char const * get_usage() const override { return ""; } + char const * get_descr(cmd_context & ctx) const override { return "get information."; } + unsigned get_arity() const override { return 1; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_KEYWORD; } + void set_next_arg(cmd_context & ctx, symbol const & opt) override { if (opt == m_error_behavior) { if (ctx.exit_on_error()) ctx.regular_stream() << "(:error-behavior immediate-exit)" << std::endl; @@ -707,16 +707,16 @@ public: m_sat("sat"), m_unknown("unknown") { } - virtual char const * get_usage() const { return " "; } - virtual char const * get_descr(cmd_context & ctx) const { return "set information."; } - virtual unsigned get_arity() const { return 2; } - virtual void prepare(cmd_context & ctx) { m_info = symbol::null; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + char const * get_usage() const override { return " "; } + char const * get_descr(cmd_context & ctx) const override { return "set information."; } + unsigned get_arity() const override { return 2; } + void prepare(cmd_context & ctx) override { m_info = symbol::null; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return m_info == symbol::null ? CPK_KEYWORD : CPK_OPTION_VALUE; } - virtual void set_next_arg(cmd_context & ctx, rational const & val) {} - virtual void set_next_arg(cmd_context & ctx, char const * val) {} - virtual void set_next_arg(cmd_context & ctx, symbol const & s) { + void set_next_arg(cmd_context & ctx, rational const & val) override {} + void set_next_arg(cmd_context & ctx, char const * val) override {} + void set_next_arg(cmd_context & ctx, symbol const & s) override { if (m_info == symbol::null) { m_info = s; } @@ -737,7 +737,7 @@ public: } } } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { ctx.print_success(); } }; @@ -760,30 +760,30 @@ public: } return m_array_fid; } - virtual char const * get_usage() const { return " (+) "; } - virtual char const * get_descr(cmd_context & ctx) const { return "declare a new array map operator with name using the given function declaration.\n ::= \n | ( (*) )\n | ((_ +) (*) )\nThe last two cases are used to disumbiguate between declarations with the same name and/or select (indexed) builtin declarations.\nFor more details about the array map operator, see 'Generalized and Efficient Array Decision Procedures' (FMCAD 2009).\nExample: (declare-map set-union (Int) (or (Bool Bool) Bool))\nDeclares a new function (declare-fun set-union ((Array Int Bool) (Array Int Bool)) (Array Int Bool)).\nThe instance of the map axiom for this new declaration is:\n(forall ((a1 (Array Int Bool)) (a2 (Array Int Bool)) (i Int)) (= (select (set-union a1 a2) i) (or (select a1 i) (select a2 i))))"; } - virtual unsigned get_arity() const { return 3; } - virtual void prepare(cmd_context & ctx) { m_name = symbol::null; m_domain.reset(); } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + char const * get_usage() const override { return " (+) "; } + char const * get_descr(cmd_context & ctx) const override { return "declare a new array map operator with name using the given function declaration.\n ::= \n | ( (*) )\n | ((_ +) (*) )\nThe last two cases are used to disumbiguate between declarations with the same name and/or select (indexed) builtin declarations.\nFor more details about the array map operator, see 'Generalized and Efficient Array Decision Procedures' (FMCAD 2009).\nExample: (declare-map set-union (Int) (or (Bool Bool) Bool))\nDeclares a new function (declare-fun set-union ((Array Int Bool) (Array Int Bool)) (Array Int Bool)).\nThe instance of the map axiom for this new declaration is:\n(forall ((a1 (Array Int Bool)) (a2 (Array Int Bool)) (i Int)) (= (select (set-union a1 a2) i) (or (select a1 i) (select a2 i))))"; } + unsigned get_arity() const override { return 3; } + void prepare(cmd_context & ctx) override { m_name = symbol::null; m_domain.reset(); } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_name == symbol::null) return CPK_SYMBOL; if (m_domain.empty()) return CPK_SORT_LIST; return CPK_FUNC_DECL; } - virtual void set_next_arg(cmd_context & ctx, symbol const & s) { m_name = s; } - virtual void set_next_arg(cmd_context & ctx, unsigned num, sort * const * slist) { + void set_next_arg(cmd_context & ctx, symbol const & s) override { m_name = s; } + void set_next_arg(cmd_context & ctx, unsigned num, sort * const * slist) override { if (num == 0) throw cmd_exception("invalid map declaration, empty sort list"); m_domain.append(num, slist); } - virtual void set_next_arg(cmd_context & ctx, func_decl * f) { + void set_next_arg(cmd_context & ctx, func_decl * f) override { m_f = f; if (m_f->get_arity() == 0) throw cmd_exception("invalid map declaration, function declaration must have arity > 0"); } - virtual void reset(cmd_context & ctx) { + void reset(cmd_context & ctx) override { m_array_fid = null_family_id; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { psort_decl * array_sort = ctx.find_psort_decl(m_array_sort); if (array_sort == 0) throw cmd_exception("Array sort is not available"); @@ -813,11 +813,11 @@ class get_consequences_cmd : public cmd { unsigned m_count; public: get_consequences_cmd(): cmd("get-consequences"), m_count(0) {} - virtual char const * get_usage() const { return "(*) (*)"; } - virtual char const * get_descr(cmd_context & ctx) const { return "retrieve consequences that fix values for supplied variables"; } - virtual unsigned get_arity() const { return 2; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_EXPR_LIST; } - virtual void set_next_arg(cmd_context & ctx, unsigned num, expr * const * tlist) { + char const * get_usage() const override { return "(*) (*)"; } + char const * get_descr(cmd_context & ctx) const override { return "retrieve consequences that fix values for supplied variables"; } + unsigned get_arity() const override { return 2; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_EXPR_LIST; } + void set_next_arg(cmd_context & ctx, unsigned num, expr * const * tlist) override { if (m_count == 0) { m_assumptions.append(num, tlist); ++m_count; @@ -826,8 +826,8 @@ public: m_variables.append(num, tlist); } } - virtual void failure_cleanup(cmd_context & ctx) {} - virtual void execute(cmd_context & ctx) { + void failure_cleanup(cmd_context & ctx) override {} + void execute(cmd_context & ctx) override { ast_manager& m = ctx.m(); expr_ref_vector assumptions(m), variables(m), consequences(m); assumptions.append(m_assumptions.size(), m_assumptions.c_ptr()); @@ -835,12 +835,12 @@ public: ctx.get_consequences(assumptions, variables, consequences); ctx.regular_stream() << consequences << "\n"; } - virtual void prepare(cmd_context & ctx) { reset(ctx); } + void prepare(cmd_context & ctx) override { reset(ctx); } - virtual void reset(cmd_context& ctx) { + void reset(cmd_context& ctx) override { m_assumptions.reset(); m_variables.reset(); m_count = 0; } - virtual void finalize(cmd_context & ctx) {} + void finalize(cmd_context & ctx) override {} }; // provides "help" for builtin cmds @@ -850,8 +850,8 @@ class builtin_cmd : public cmd { public: builtin_cmd(char const * name, char const * usage, char const * descr): cmd(name), m_usage(usage), m_descr(descr) {} - virtual char const * get_usage() const { return m_usage; } - virtual char const * get_descr(cmd_context & ctx) const { return m_descr; } + char const * get_usage() const override { return m_usage; } + char const * get_descr(cmd_context & ctx) const override { return m_descr; } }; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index ec2eea032..c6c36606a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -414,25 +414,25 @@ protected: public: pp_env(cmd_context & o):m_owner(o), m_autil(o.m()), m_bvutil(o.m()), m_arutil(o.m()), m_futil(o.m()), m_sutil(o.m()), m_dtutil(o.m()), m_dlutil(o.m()) {} - virtual ~pp_env() {} - virtual ast_manager & get_manager() const { return m_owner.m(); } - virtual arith_util & get_autil() { return m_autil; } - virtual bv_util & get_bvutil() { return m_bvutil; } - virtual array_util & get_arutil() { return m_arutil; } - virtual fpa_util & get_futil() { return m_futil; } - virtual seq_util & get_sutil() { return m_sutil; } - virtual datatype_util & get_dtutil() { return m_dtutil; } + ~pp_env() override {} + ast_manager & get_manager() const override { return m_owner.m(); } + arith_util & get_autil() override { return m_autil; } + bv_util & get_bvutil() override { return m_bvutil; } + array_util & get_arutil() override { return m_arutil; } + fpa_util & get_futil() override { return m_futil; } + seq_util & get_sutil() override { return m_sutil; } + datatype_util & get_dtutil() override { return m_dtutil; } - virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; } - virtual bool uses(symbol const & s) const { + datalog::dl_decl_util& get_dlutil() override { return m_dlutil; } + bool uses(symbol const & s) const override { return m_owner.m_builtin_decls.contains(s) || m_owner.m_func_decls.contains(s); } - virtual format_ns::format * pp_sort(sort * s) { + format_ns::format * pp_sort(sort * s) override { return m_owner.pp(s); } - virtual format_ns::format * pp_fdecl(func_decl * f, unsigned & len) { + format_ns::format * pp_fdecl(func_decl * f, unsigned & len) override { symbol s = f->get_name(); func_decls fs; if (m_owner.m_func_decls.find(s, fs) && fs.contains(f)) { @@ -443,7 +443,7 @@ public: } return smt2_pp_environment::pp_fdecl(f, len); } - virtual format_ns::format * pp_fdecl_ref(func_decl * f) { + format_ns::format * pp_fdecl_ref(func_decl * f) override { symbol s = f->get_name(); func_decls fs; if (m_owner.m_func_decls.find(s, fs) && fs.contains(f)) { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 212de585a..cd3191fc6 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -112,10 +112,10 @@ class ast_object_ref : public object_ref { ast * m_ast; public: ast_object_ref(cmd_context & ctx, ast * a); - virtual void finalize(cmd_context & ctx); + void finalize(cmd_context & ctx) override; ast * get_ast() const { return m_ast; } static char const * cls_kind() { return "AST"; } - virtual char const * kind() const { return cls_kind(); } + char const * kind() const override { return cls_kind(); } }; class stream_ref { @@ -250,8 +250,8 @@ protected: datatype_util m_dt_util; public: dt_eh(cmd_context & owner); - virtual ~dt_eh(); - virtual void operator()(sort * dt, pdecl* pd); + ~dt_eh() override; + void operator()(sort * dt, pdecl* pd) override; }; friend class dt_eh; @@ -307,7 +307,7 @@ protected: public: cmd_context(bool main_ctx = true, ast_manager * m = 0, symbol const & l = symbol::null); - ~cmd_context(); + ~cmd_context() override; void set_cancel(bool f); context_params & params() { return m_params; } solver_factory &get_solver_factory() { return *m_solver_factory; } @@ -354,7 +354,7 @@ public: bool has_manager() const { return m_manager != 0; } ast_manager & m() const { const_cast(this)->init_manager(); return *m_manager; } - virtual ast_manager & get_ast_manager() { return m(); } + ast_manager & get_ast_manager() override { return m(); } pdecl_manager & pm() const { if (!m_pmanager) const_cast(this)->init_manager(); return *m_pmanager; } sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; } @@ -407,8 +407,8 @@ public: void set_regular_stream(char const * name) { m_regular.set(name); } void set_regular_stream(std::ostream& out) { m_regular.set(out); } void set_diagnostic_stream(char const * name); - virtual std::ostream & regular_stream() { return *m_regular; } - virtual std::ostream & diagnostic_stream() { return *m_diagnostic; } + std::ostream & regular_stream() override { return *m_regular; } + std::ostream & diagnostic_stream() override { return *m_diagnostic; } char const * get_regular_stream_name() const { return m_regular.name(); } char const * get_diagnostic_stream_name() const { return m_diagnostic.name(); } typedef dictionary::iterator cmd_iterator; @@ -462,14 +462,14 @@ public: } format_ns::format * pp(sort * s) const; - virtual void pp(sort * s, format_ns::format_ref & r) const { r = pp(s); } - virtual void pp(func_decl * f, format_ns::format_ref & r) const; - virtual void pp(expr * n, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer & var_names) const; - virtual void pp(expr * n, format_ns::format_ref & r) const; - virtual void display(std::ostream & out, sort * s, unsigned indent = 0) const; - virtual void display(std::ostream & out, expr * n, unsigned indent, unsigned num_vars, char const * var_prefix, sbuffer & var_names) const; - virtual void display(std::ostream & out, expr * n, unsigned indent = 0) const; - virtual void display(std::ostream & out, func_decl * f, unsigned indent = 0) const; + void pp(sort * s, format_ns::format_ref & r) const override { r = pp(s); } + void pp(func_decl * f, format_ns::format_ref & r) const override; + void pp(expr * n, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer & var_names) const override; + void pp(expr * n, format_ns::format_ref & r) const override; + void display(std::ostream & out, sort * s, unsigned indent = 0) const override; + void display(std::ostream & out, expr * n, unsigned indent, unsigned num_vars, char const * var_prefix, sbuffer & var_names) const override; + void display(std::ostream & out, expr * n, unsigned indent = 0) const override; + void display(std::ostream & out, func_decl * f, unsigned indent = 0) const override; // dump assertions in out using the pretty printer. void dump_assertions(std::ostream & out) const; @@ -478,8 +478,8 @@ public: void display_smt2_benchmark(std::ostream & out, unsigned num, expr * const * assertions, symbol const & logic = symbol::null) const; - virtual void slow_progress_sample(); - virtual void fast_progress_sample(); + void slow_progress_sample() override; + void fast_progress_sample() override; }; std::ostream & operator<<(std::ostream & out, cmd_context::status st); diff --git a/src/cmd_context/echo_tactic.cpp b/src/cmd_context/echo_tactic.cpp index 848ae5429..b511d509f 100644 --- a/src/cmd_context/echo_tactic.cpp +++ b/src/cmd_context/echo_tactic.cpp @@ -27,11 +27,11 @@ class echo_tactic : public skip_tactic { public: echo_tactic(cmd_context & ctx, char const * msg, bool newline):m_ctx(ctx), m_msg(msg), m_newline(newline) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { #pragma omp critical (echo_tactic) { m_ctx.regular_stream() << m_msg; @@ -57,15 +57,15 @@ public: m_p->inc_ref(); } - ~probe_value_tactic() { + ~probe_value_tactic() override { m_p->dec_ref(); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { double val = (*m_p)(*(in.get())).get_value(); #pragma omp critical (probe_value_tactic) { diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp index 9d3c1ced3..b1a7905d1 100644 --- a/src/cmd_context/eval_cmd.cpp +++ b/src/cmd_context/eval_cmd.cpp @@ -29,33 +29,33 @@ class eval_cmd : public parametric_cmd { public: eval_cmd():parametric_cmd("eval") {} - virtual char const * get_usage() const { return " ( )*"; } + char const * get_usage() const override { return " ( )*"; } - virtual char const * get_main_descr() const { + char const * get_main_descr() const override { return "evaluate the given term in the current model."; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { model_evaluator::get_param_descrs(p); insert_timeout(p); p.insert("model_index", CPK_UINT, "(default: 0) index of model from box optimization objective"); } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); m_target = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_target == 0) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } - virtual void set_next_arg(cmd_context & ctx, expr * arg) { + void set_next_arg(cmd_context & ctx, expr * arg) override { m_target = arg; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { if (!ctx.is_model_available()) throw cmd_exception("model is not available"); if (!m_target) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index dfdfa6175..6dab3e39f 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -104,15 +104,15 @@ class subst_cmd : public cmd { ptr_vector m_subst; public: subst_cmd():cmd("dbg-subst") {} - virtual char const * get_usage() const { return " (*) "; } - virtual char const * get_descr(cmd_context & ctx) const { return "substitute the free variables in the AST referenced by using the ASTs referenced by *"; } - virtual unsigned get_arity() const { return 3; } - virtual void prepare(cmd_context & ctx) { m_idx = 0; m_source = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + char const * get_usage() const override { return " (*) "; } + char const * get_descr(cmd_context & ctx) const override { return "substitute the free variables in the AST referenced by using the ASTs referenced by *"; } + unsigned get_arity() const override { return 3; } + void prepare(cmd_context & ctx) override { m_idx = 0; m_source = 0; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_idx == 1) return CPK_SYMBOL_LIST; return CPK_SYMBOL; } - virtual void set_next_arg(cmd_context & ctx, symbol const & s) { + void set_next_arg(cmd_context & ctx, symbol const & s) override { if (m_idx == 0) { m_source = get_expr_ref(ctx, s); } @@ -121,7 +121,7 @@ public: } m_idx++; } - virtual void set_next_arg(cmd_context & ctx, unsigned num, symbol const * s) { + void set_next_arg(cmd_context & ctx, unsigned num, symbol const * s) override { m_subst.reset(); unsigned i = num; while (i > 0) { @@ -130,7 +130,7 @@ public: } m_idx++; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { expr_ref r(ctx.m()); beta_reducer p(ctx.m()); p(m_source, m_subst.size(), m_subst.c_ptr(), r); @@ -179,18 +179,18 @@ class lt_cmd : public cmd { expr * m_t2; public: lt_cmd():cmd("dbg-lt") {} - virtual char const * get_usage() const { return " "; } - virtual char const * get_descr(cmd_context & ctx) const { return "return true if the first term is smaller than the second one in the internal Z3 total order on terms."; } - virtual unsigned get_arity() const { return 2; } - virtual void prepare(cmd_context & ctx) { m_t1 = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_EXPR; } - virtual void set_next_arg(cmd_context & ctx, expr * arg) { + char const * get_usage() const override { return " "; } + char const * get_descr(cmd_context & ctx) const override { return "return true if the first term is smaller than the second one in the internal Z3 total order on terms."; } + unsigned get_arity() const override { return 2; } + void prepare(cmd_context & ctx) override { m_t1 = 0; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_EXPR; } + void set_next_arg(cmd_context & ctx, expr * arg) override { if (m_t1 == 0) m_t1 = arg; else m_t2 = arg; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { bool r = lt(m_t1, m_t2); ctx.regular_stream() << (r ? "true" : "false") << std::endl; } @@ -283,23 +283,23 @@ protected: ptr_vector m_args; public: instantiate_cmd_core(char const * name):cmd(name) {} - virtual char const * get_usage() const { return " (*)"; } - virtual char const * get_descr(cmd_context & ctx) const { return "instantiate the quantifier using the given expressions."; } - virtual unsigned get_arity() const { return 2; } - virtual void prepare(cmd_context & ctx) { m_q = 0; m_args.reset(); } + char const * get_usage() const override { return " (*)"; } + char const * get_descr(cmd_context & ctx) const override { return "instantiate the quantifier using the given expressions."; } + unsigned get_arity() const override { return 2; } + void prepare(cmd_context & ctx) override { m_q = 0; m_args.reset(); } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_q == 0) return CPK_EXPR; else return CPK_EXPR_LIST; } - virtual void set_next_arg(cmd_context & ctx, expr * s) { + void set_next_arg(cmd_context & ctx, expr * s) override { if (!is_quantifier(s)) throw cmd_exception("invalid command, quantifier expected."); m_q = to_quantifier(s); } - virtual void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) { + void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) override { if (num != m_q->get_num_decls()) throw cmd_exception("invalid command, mismatch between the number of quantified variables and the number of arguments."); unsigned i = num; @@ -315,7 +315,7 @@ public: m_args.append(num, ts); } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { expr_ref r(ctx.m()); instantiate(ctx.m(), m_q, m_args.c_ptr(), r); ctx.display(ctx.regular_stream(), r); @@ -332,9 +332,9 @@ class instantiate_nested_cmd : public instantiate_cmd_core { public: instantiate_nested_cmd():instantiate_cmd_core("dbg-instantiate-nested") {} - virtual char const * get_descr(cmd_context & ctx) const { return "instantiate the quantifier nested in the outermost quantifier, this command is used to test the instantiation procedure with quantifiers that contain free variables."; } + char const * get_descr(cmd_context & ctx) const override { return "instantiate the quantifier nested in the outermost quantifier, this command is used to test the instantiation procedure with quantifiers that contain free variables."; } - virtual void set_next_arg(cmd_context & ctx, expr * s) { + void set_next_arg(cmd_context & ctx, expr * s) override { instantiate_cmd_core::set_next_arg(ctx, s); if (!is_quantifier(m_q->get_expr())) throw cmd_exception("invalid command, nested quantifier expected"); @@ -345,11 +345,11 @@ public: class print_dimacs_cmd : public cmd { public: print_dimacs_cmd():cmd("display-dimacs") {} - virtual char const * get_usage() const { return ""; } - virtual char const * get_descr(cmd_context & ctx) const { return "print benchmark in DIMACS format"; } - virtual unsigned get_arity() const { return 0; } - virtual void prepare(cmd_context & ctx) {} - virtual void execute(cmd_context & ctx) { ctx.display_dimacs(); } + char const * get_usage() const override { return ""; } + char const * get_descr(cmd_context & ctx) const override { return "print benchmark in DIMACS format"; } + unsigned get_arity() const override { return 0; } + void prepare(cmd_context & ctx) override {} + void execute(cmd_context & ctx) override { ctx.display_dimacs(); } }; diff --git a/src/cmd_context/extra_cmds/polynomial_cmds.cpp b/src/cmd_context/extra_cmds/polynomial_cmds.cpp index 7a748ac66..8adaa660d 100644 --- a/src/cmd_context/extra_cmds/polynomial_cmds.cpp +++ b/src/cmd_context/extra_cmds/polynomial_cmds.cpp @@ -164,33 +164,33 @@ class poly_isolate_roots_cmd : public cmd { public: poly_isolate_roots_cmd(char const * name = "poly/isolate-roots"):cmd(name), m_ctx(0) {} - virtual char const * get_usage() const { return " ( )*"; } + char const * get_usage() const override { return " ( )*"; } - virtual char const * get_descr(cmd_context & ctx) const { return "isolate the roots a multivariate polynomial modulo an assignment"; } + char const * get_descr(cmd_context & ctx) const override { return "isolate the roots a multivariate polynomial modulo an assignment"; } - virtual unsigned get_arity() const { return VAR_ARITY; } + unsigned get_arity() const override { return VAR_ARITY; } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { m_ctx = alloc(context, ctx.m()); } - virtual void finalize(cmd_context & ctx) { + void finalize(cmd_context & ctx) override { m_ctx = 0; } - virtual void failure_cleanup(cmd_context & ctx) { + void failure_cleanup(cmd_context & ctx) override { m_ctx = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_EXPR; } - virtual void set_next_arg(cmd_context & ctx, expr * arg) { + void set_next_arg(cmd_context & ctx, expr * arg) override { m_ctx->set_next_arg(ctx, arg); } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { m_ctx->execute(ctx); m_ctx = 0; } @@ -204,31 +204,31 @@ class poly_factor_cmd : public parametric_cmd { public: poly_factor_cmd(char const * name = "poly/factor"):parametric_cmd(name) {} - virtual char const * get_usage() const { return " ( )*"; } + char const * get_usage() const override { return " ( )*"; } - virtual char const * get_main_descr() const { + char const * get_main_descr() const override { return "factor a polynomial"; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { polynomial::factor_params::get_param_descrs(p); } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); m_target = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_target == 0) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } - virtual void set_next_arg(cmd_context & ctx, expr * arg) { + void set_next_arg(cmd_context & ctx, expr * arg) override { m_target = arg; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { polynomial::factor_params ps; ps.updt_params(m_params); factor(ctx, m_target, ps); diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp index 8b9f0ebd8..62824c2ec 100644 --- a/src/cmd_context/interpolant_cmds.cpp +++ b/src/cmd_context/interpolant_cmds.cpp @@ -219,29 +219,29 @@ protected: public: get_interpolant_cmd(char const * name = "get-interpolant"):parametric_cmd(name) {} - virtual char const * get_usage() const { return "+"; } + char const * get_usage() const override { return "+"; } - virtual char const * get_main_descr() const { + char const * get_main_descr() const override { return "get interpolant for formulas"; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); m_targets.resize(0); } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_EXPR; } - virtual void set_next_arg(cmd_context & ctx, expr * arg) { + void set_next_arg(cmd_context & ctx, expr * arg) override { m_targets.push_back(arg); } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { get_interpolant(ctx,m_targets,m_params); } }; @@ -250,7 +250,7 @@ class compute_interpolant_cmd : public get_interpolant_cmd { public: compute_interpolant_cmd(char const * name = "compute-interpolant"):get_interpolant_cmd(name) {} - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { compute_interpolant(ctx,m_targets,m_params); } diff --git a/src/cmd_context/parametric_cmd.h b/src/cmd_context/parametric_cmd.h index 6d676d6f9..84b29a17d 100644 --- a/src/cmd_context/parametric_cmd.h +++ b/src/cmd_context/parametric_cmd.h @@ -31,48 +31,48 @@ public: scoped_ptr m_pdescrs; public: parametric_cmd(char const * name):cmd(name), m_descr(0) {} - virtual ~parametric_cmd() { if (m_descr) dealloc(m_descr); } + ~parametric_cmd() override { if (m_descr) dealloc(m_descr); } virtual void init_pdescrs(cmd_context & ctx, param_descrs & d) = 0; param_descrs const & pdescrs(cmd_context & ctx) const; params_ref const & ps() const { return m_params; } virtual char const * get_main_descr() const = 0; - virtual char const * get_descr(cmd_context & ctx) const; - virtual unsigned get_arity() const { return VAR_ARITY; } - virtual void prepare(cmd_context & ctx) { m_last = symbol::null; m_params.reset(); } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const; - virtual void set_next_arg(cmd_context & ctx, symbol const & s); - virtual void set_next_arg(cmd_context & ctx, unsigned val) { + char const * get_descr(cmd_context & ctx) const override; + unsigned get_arity() const override { return VAR_ARITY; } + void prepare(cmd_context & ctx) override { m_last = symbol::null; m_params.reset(); } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override; + void set_next_arg(cmd_context & ctx, symbol const & s) override; + void set_next_arg(cmd_context & ctx, unsigned val) override { m_params.set_uint(m_last, val); m_last = symbol::null; } - virtual void set_next_arg(cmd_context & ctx, bool val) { + void set_next_arg(cmd_context & ctx, bool val) override { m_params.set_bool(m_last, val); m_last = symbol::null; } - virtual void set_next_arg(cmd_context & ctx, rational const & val) { + void set_next_arg(cmd_context & ctx, rational const & val) override { m_params.set_rat(m_last, val); m_last = symbol::null; } - virtual void set_next_arg(cmd_context & ctx, char const * val) { + void set_next_arg(cmd_context & ctx, char const * val) override { m_params.set_str(m_last, val); m_last = symbol::null; } - virtual void set_next_arg(cmd_context & ctx, sort * s) { + void set_next_arg(cmd_context & ctx, sort * s) override { NOT_IMPLEMENTED_YET(); // m_params.set_sort(m_last, s); // m_last = symbol::null; } - virtual void set_next_arg(cmd_context & ctx, expr * t) { + void set_next_arg(cmd_context & ctx, expr * t) override { NOT_IMPLEMENTED_YET(); // m_params.set_expr(m_last, t); // m_last = symbol::null; } - virtual void set_next_arg(cmd_context & ctx, func_decl * f) { + void set_next_arg(cmd_context & ctx, func_decl * f) override { NOT_IMPLEMENTED_YET(); // m_params.set_func_decl(m_last, f); // m_last = symbol::null; } - virtual void set_next_arg(cmd_context & ctx, sexpr * n) { UNREACHABLE(); } + void set_next_arg(cmd_context & ctx, sexpr * n) override { UNREACHABLE(); } }; #endif diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index f75fbfa29..f485aea75 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -136,25 +136,25 @@ class psort_sort : public psort { friend class pdecl_manager; sort * m_sort; psort_sort(unsigned id, pdecl_manager & m, sort * s):psort(id, 0), m_sort(s) { m.m().inc_ref(m_sort); } - virtual void finalize(pdecl_manager & m) { + void finalize(pdecl_manager & m) override { m.m().dec_ref(m_sort); psort::finalize(m); } - virtual bool check_num_params(pdecl * other) const { return true; } - virtual size_t obj_size() const { return sizeof(psort_sort); } + bool check_num_params(pdecl * other) const override { return true; } + size_t obj_size() const override { return sizeof(psort_sort); } sort * get_sort() const { return m_sort; } - virtual sort * instantiate(pdecl_manager & m, sort * const * s) { return m_sort; } + sort * instantiate(pdecl_manager & m, sort * const * s) override { return m_sort; } public: - virtual ~psort_sort() {} - virtual bool is_sort_wrapper() const { return true; } - virtual char const * hcons_kind() const { return "psort_sort"; } - virtual unsigned hcons_hash() const { return m_sort->get_id(); } - virtual bool hcons_eq(psort const * other) const { + ~psort_sort() override {} + bool is_sort_wrapper() const override { return true; } + char const * hcons_kind() const override { return "psort_sort"; } + unsigned hcons_hash() const override { return m_sort->get_id(); } + bool hcons_eq(psort const * other) const override { if (other->hcons_kind() != hcons_kind()) return false; return m_sort == static_cast(other)->m_sort; } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { out << m_sort->get_name(); } }; @@ -163,19 +163,19 @@ class psort_var : public psort { friend class pdecl_manager; unsigned m_idx; psort_var(unsigned id, unsigned num_params, unsigned idx):psort(id, num_params), m_idx(idx) { SASSERT(idx < num_params); } - virtual sort * instantiate(pdecl_manager & m, sort * const * s) { return s[m_idx]; } - virtual size_t obj_size() const { return sizeof(psort_var); } + sort * instantiate(pdecl_manager & m, sort * const * s) override { return s[m_idx]; } + size_t obj_size() const override { return sizeof(psort_var); } public: - virtual ~psort_var() {} - virtual char const * hcons_kind() const { return "psort_var"; } - virtual unsigned hcons_hash() const { return hash_u_u(m_num_params, m_idx); } - virtual bool hcons_eq(psort const * other) const { + ~psort_var() override {} + char const * hcons_kind() const override { return "psort_var"; } + unsigned hcons_hash() const override { return hash_u_u(m_num_params, m_idx); } + bool hcons_eq(psort const * other) const override { return other->hcons_kind() == hcons_kind() && get_num_params() == other->get_num_params() && m_idx == static_cast(other)->m_idx; } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { out << "s_" << m_idx; } unsigned idx() const { return m_idx; } @@ -196,13 +196,13 @@ class psort_app : public psort { DEBUG_CODE(if (num_args == num_params) { for (unsigned i = 0; i < num_params; i++) args[i]->check_num_params(this); }); } - virtual void finalize(pdecl_manager & m) { + void finalize(pdecl_manager & m) override { m.lazy_dec_ref(m_decl); m.lazy_dec_ref(m_args.size(), m_args.c_ptr()); psort::finalize(m); } - virtual size_t obj_size() const { return sizeof(psort_app); } + size_t obj_size() const override { return sizeof(psort_app); } struct khasher { unsigned operator()(psort_app const * d) const { return d->m_decl->hash(); } @@ -212,7 +212,7 @@ class psort_app : public psort { unsigned operator()(psort_app const * d, unsigned idx) const { return d->m_args[idx]->hash(); } }; - virtual sort * instantiate(pdecl_manager & m, sort * const * s) { + sort * instantiate(pdecl_manager & m, sort * const * s) override { sort * r = find(s); if (r) return r; @@ -228,12 +228,12 @@ class psort_app : public psort { } public: - virtual ~psort_app() {} - virtual char const * hcons_kind() const { return "psort_app"; } - virtual unsigned hcons_hash() const { + ~psort_app() override {} + char const * hcons_kind() const override { return "psort_app"; } + unsigned hcons_hash() const override { return get_composite_hash(const_cast(this), m_args.size()); } - virtual bool hcons_eq(psort const * other) const { + bool hcons_eq(psort const * other) const override { if (other->hcons_kind() != hcons_kind()) return false; if (get_num_params() != other->get_num_params()) @@ -249,7 +249,7 @@ public: } return true; } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { if (m_args.empty()) { out << m_decl->get_name(); } @@ -752,16 +752,16 @@ struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info { m.m().inc_array_ref(n, s); } - virtual ~app_sort_info() {} + ~app_sort_info() override {} - virtual unsigned obj_size() const { return sizeof(app_sort_info); } + unsigned obj_size() const override { return sizeof(app_sort_info); } - virtual void finalize(pdecl_manager & m) { + void finalize(pdecl_manager & m) override { sort_info::finalize(m); m.m().dec_array_ref(m_args.size(), m_args.c_ptr()); } - virtual void display(std::ostream & out, pdecl_manager const & m) const { + void display(std::ostream & out, pdecl_manager const & m) const override { if (m_args.empty()) { out << m_decl->get_name(); } @@ -775,7 +775,7 @@ struct pdecl_manager::app_sort_info : public pdecl_manager::sort_info { } } - virtual format * pp(pdecl_manager const & m) const { + format * pp(pdecl_manager const & m) const override { if (m_args.empty()) { return mk_string(m.m(), m_decl->get_name().str().c_str()); } @@ -796,11 +796,11 @@ struct pdecl_manager::indexed_sort_info : public pdecl_manager::sort_info { m_indices(n, s) { } - virtual ~indexed_sort_info() {} + ~indexed_sort_info() override {} - virtual unsigned obj_size() const { return sizeof(indexed_sort_info); } + unsigned obj_size() const override { return sizeof(indexed_sort_info); } - virtual void display(std::ostream & out, pdecl_manager const & m) const { + void display(std::ostream & out, pdecl_manager const & m) const override { if (m_indices.empty()) { out << m_decl->get_name(); } @@ -813,7 +813,7 @@ struct pdecl_manager::indexed_sort_info : public pdecl_manager::sort_info { } } - virtual format * pp(pdecl_manager const & m) const { + format * pp(pdecl_manager const & m) const override { if (m_indices.empty()) { return mk_string(m.m(), m_decl->get_name().str().c_str()); } diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index c72020827..d6fea179d 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -65,9 +65,9 @@ protected: psort_inst_cache * m_inst_cache; friend class pdecl_manager; psort(unsigned id, unsigned num_params):pdecl(id, num_params), m_inst_cache(0) {} - virtual bool is_psort() const { return true; } - virtual void finalize(pdecl_manager & m); - virtual ~psort() {} + bool is_psort() const override { return true; } + void finalize(pdecl_manager & m) override; + ~psort() override {} virtual void cache(pdecl_manager & m, sort * const * s, sort * r); virtual sort * find(sort * const * s) const; public: @@ -77,7 +77,7 @@ public: virtual char const * hcons_kind() const = 0; virtual unsigned hcons_hash() const = 0; virtual bool hcons_eq(psort const * other) const = 0; - virtual void reset_cache(pdecl_manager& m); + void reset_cache(pdecl_manager& m) override; }; // for hash consing @@ -98,8 +98,8 @@ protected: void cache(pdecl_manager & m, sort * const * s, sort * r); sort * find(sort * const * s); psort_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n); - virtual void finalize(pdecl_manager & m); - virtual ~psort_decl() {} + void finalize(pdecl_manager & m) override; + ~psort_decl() override {} public: virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) = 0; virtual sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) { return 0; } @@ -108,7 +108,7 @@ public: // Only builtin declarations can have a variable number of parameters. bool has_var_params() const { return m_num_params == PSORT_DECL_VAR_PARAMS; } symbol const & get_name() const { return m_name; } - virtual void reset_cache(pdecl_manager& m); + void reset_cache(pdecl_manager& m) override; bool is_user_decl() const { return m_psort_kind == PSORT_USER; } bool is_builtin_decl() const { return m_psort_kind == PSORT_BUILTIN; } bool is_dt_decl() const { return m_psort_kind == PSORT_DT; } @@ -119,12 +119,12 @@ protected: friend class pdecl_manager; psort * m_def; psort_user_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, psort * p); - virtual size_t obj_size() const { return sizeof(psort_user_decl); } - virtual void finalize(pdecl_manager & m); - virtual ~psort_user_decl() {} + size_t obj_size() const override { return sizeof(psort_user_decl); } + void finalize(pdecl_manager & m) override; + ~psort_user_decl() override {} public: - virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); - virtual void display(std::ostream & out) const; + sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; + void display(std::ostream & out) const override; }; class psort_builtin_decl : public psort_decl { @@ -133,23 +133,23 @@ protected: family_id m_fid; decl_kind m_kind; psort_builtin_decl(unsigned id, pdecl_manager & m, symbol const & n, family_id fid, decl_kind k); - virtual size_t obj_size() const { return sizeof(psort_builtin_decl); } - virtual ~psort_builtin_decl() {} + size_t obj_size() const override { return sizeof(psort_builtin_decl); } + ~psort_builtin_decl() override {} public: - virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); - virtual sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s); - virtual void display(std::ostream & out) const; + sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; + sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) override; + void display(std::ostream & out) const override; }; class psort_dt_decl : public psort_decl { protected: friend class pdecl_manager; psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n); - virtual size_t obj_size() const { return sizeof(psort_dt_decl); } - virtual ~psort_dt_decl() {} + size_t obj_size() const override { return sizeof(psort_dt_decl); } + ~psort_dt_decl() override {} public: - virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); - virtual void display(std::ostream & out) const; + sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; + void display(std::ostream & out) const override; }; @@ -190,16 +190,16 @@ class paccessor_decl : public pdecl { symbol m_name; ptype m_type; paccessor_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, ptype const & r); - virtual void finalize(pdecl_manager & m); - virtual size_t obj_size() const { return sizeof(paccessor_decl); } + void finalize(pdecl_manager & m) override; + size_t obj_size() const override { return sizeof(paccessor_decl); } bool has_missing_refs(symbol & missing) const; bool fix_missing_refs(dictionary const & symbol2idx, symbol & missing); accessor_decl * instantiate_decl(pdecl_manager & m, sort * const * s); symbol const & get_name() const { return m_name; } ptype const & get_type() const { return m_type; } - virtual ~paccessor_decl() {} + ~paccessor_decl() override {} public: - virtual void display(std::ostream & out) const { pdecl::display(out); } + void display(std::ostream & out) const override { pdecl::display(out); } void display(std::ostream & out, pdatatype_decl const * const * dts) const; }; @@ -211,16 +211,16 @@ class pconstructor_decl : public pdecl { ptr_vector m_accessors; pconstructor_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, symbol const & r, unsigned num_accessors, paccessor_decl * const * accessors); - virtual void finalize(pdecl_manager & m); - virtual size_t obj_size() const { return sizeof(pconstructor_decl); } + void finalize(pdecl_manager & m) override; + size_t obj_size() const override { return sizeof(pconstructor_decl); } bool has_missing_refs(symbol & missing) const; bool fix_missing_refs(dictionary const & symbol2idx, symbol & missing); symbol const & get_name() const { return m_name; } symbol const & get_recognizer_name() const { return m_recogniser_name; } constructor_decl * instantiate_decl(pdecl_manager & m, sort * const * s); - virtual ~pconstructor_decl() {} + ~pconstructor_decl() override {} public: - virtual void display(std::ostream & out) const { pdecl::display(out); } + void display(std::ostream & out) const override { pdecl::display(out); } void display(std::ostream & out, pdatatype_decl const * const * dts) const; }; @@ -231,14 +231,14 @@ class pdatatype_decl : public psort_decl { pdatatypes_decl * m_parent; pdatatype_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, unsigned num_constructors, pconstructor_decl * const * constructors); - virtual void finalize(pdecl_manager & m); - virtual size_t obj_size() const { return sizeof(pdatatype_decl); } + void finalize(pdecl_manager & m) override; + size_t obj_size() const override { return sizeof(pdatatype_decl); } bool fix_missing_refs(dictionary const & symbol2idx, symbol & missing); datatype_decl * instantiate_decl(pdecl_manager & m, sort * const * s); - virtual ~pdatatype_decl() {} + ~pdatatype_decl() override {} public: - sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); - virtual void display(std::ostream & out) const; + sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) override; + void display(std::ostream & out) const override; bool has_missing_refs(symbol & missing) const; bool has_duplicate_accessors(symbol & repeated) const; bool commit(pdecl_manager& m); @@ -252,11 +252,11 @@ class pdatatypes_decl : public pdecl { friend class pdatatype_decl; ptr_vector m_datatypes; pdatatypes_decl(unsigned id, unsigned num_params, pdecl_manager & m, unsigned num_datatypes, pdatatype_decl * const * dts); - virtual void finalize(pdecl_manager & m); - virtual size_t obj_size() const { return sizeof(pdatatypes_decl); } + void finalize(pdecl_manager & m) override; + size_t obj_size() const override { return sizeof(pdatatypes_decl); } bool fix_missing_refs(symbol & missing); bool instantiate(pdecl_manager & m, sort * const * s); - virtual ~pdatatypes_decl() {} + ~pdatatypes_decl() override {} public: pdatatype_decl const * const * children() const { return m_datatypes.c_ptr(); } pdatatype_decl * const * begin() const { return m_datatypes.begin(); } diff --git a/src/cmd_context/simplify_cmd.cpp b/src/cmd_context/simplify_cmd.cpp index 5112a6ea2..999351d25 100644 --- a/src/cmd_context/simplify_cmd.cpp +++ b/src/cmd_context/simplify_cmd.cpp @@ -36,7 +36,7 @@ class simplify_cmd : public parametric_cmd { public: th_solver(cmd_context& ctx): m_ctx(ctx) {} - virtual lbool check_sat(expr* e) { + lbool check_sat(expr* e) override { if (!m_solver) { m_solver = m_ctx.get_solver_factory()(m_ctx.m(), m_params, false, true, false, symbol::null); } @@ -52,13 +52,13 @@ class simplify_cmd : public parametric_cmd { public: simplify_cmd(char const * name = "simplify"):parametric_cmd(name) {} - virtual char const * get_usage() const { return " ( )*"; } + char const * get_usage() const override { return " ( )*"; } - virtual char const * get_main_descr() const { + char const * get_main_descr() const override { return "simplify the given term using builtin theory simplification rules."; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { th_rewriter::get_param_descrs(p); insert_timeout(p); p.insert("print", CPK_BOOL, "(default: true) print the simplified term."); @@ -66,24 +66,24 @@ public: p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics."); } - virtual ~simplify_cmd() { + ~simplify_cmd() override { } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); m_target = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_target == 0) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } - virtual void set_next_arg(cmd_context & ctx, expr * arg) { + void set_next_arg(cmd_context & ctx, expr * arg) override { m_target = arg; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { if (m_target == 0) throw cmd_exception("invalid simplify command, argument expected"); expr_ref r(ctx.m()); diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index cbc90c62c..f35267714 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -58,17 +58,17 @@ public: m_decl(0) { } - virtual char const * get_usage() const { return " "; } - virtual char const * get_descr(cmd_context & ctx) const { return "declare a new tactic, use (help-tactic) for the tactic language syntax."; } - virtual unsigned get_arity() const { return 2; } - virtual void prepare(cmd_context & ctx) { m_name = symbol::null; m_decl = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + char const * get_usage() const override { return " "; } + char const * get_descr(cmd_context & ctx) const override { return "declare a new tactic, use (help-tactic) for the tactic language syntax."; } + unsigned get_arity() const override { return 2; } + void prepare(cmd_context & ctx) override { m_name = symbol::null; m_decl = 0; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_name == symbol::null) return CPK_SYMBOL; return CPK_SEXPR; } - virtual void set_next_arg(cmd_context & ctx, symbol const & s) { m_name = s; } - virtual void set_next_arg(cmd_context & ctx, sexpr * n) { m_decl = n; } - virtual void execute(cmd_context & ctx) { + void set_next_arg(cmd_context & ctx, symbol const & s) override { m_name = s; } + void set_next_arg(cmd_context & ctx, sexpr * n) override { m_decl = n; } + void execute(cmd_context & ctx) override { tactic_ref t = sexpr2tactic(ctx, m_decl); // make sure the tactic is well formed. ctx.insert_user_tactic(m_name, m_decl); } @@ -133,23 +133,23 @@ public: parametric_cmd(name) { } - virtual char const * get_usage() const { return " ( )*"; } + char const * get_usage() const override { return " ( )*"; } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); m_tactic = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_tactic == 0) return CPK_SEXPR; return parametric_cmd::next_arg_kind(ctx); } - virtual void set_next_arg(cmd_context & ctx, sexpr * arg) { + void set_next_arg(cmd_context & ctx, sexpr * arg) override { m_tactic = arg; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { insert_timeout(p); insert_max_memory(p); p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics."); @@ -172,7 +172,7 @@ public: check_sat_tactic_result(ast_manager & m) : simple_check_sat_result(m) { } - virtual void get_labels(svector & r) { + void get_labels(svector & r) override { r.append(labels); } @@ -187,16 +187,16 @@ public: exec_given_tactic_cmd("check-sat-using") { } - virtual char const * get_main_descr() const { return "check if the current context is satisfiable using the given tactic, use (help-tactic) for the tactic language syntax."; } + char const * get_main_descr() const override { return "check if the current context is satisfiable using the given tactic, use (help-tactic) for the tactic language syntax."; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { exec_given_tactic_cmd::init_pdescrs(ctx, p); p.insert("print_unsat_core", CPK_BOOL, "(default: false) print unsatisfiable core."); p.insert("print_proof", CPK_BOOL, "(default: false) print proof."); p.insert("print_model", CPK_BOOL, "(default: false) print model."); } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { if (!m_tactic) { throw cmd_exception("check-sat-using needs a tactic argument"); } @@ -295,9 +295,9 @@ public: exec_given_tactic_cmd("apply") { } - virtual char const * get_main_descr() const { return "apply the given tactic to the current context, and print the resultant set of goals."; } + char const * get_main_descr() const override { return "apply the given tactic to the current context, and print the resultant set of goals."; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { p.insert("print", CPK_BOOL, "(default: true) print resultant goals."); #ifndef _EXTERNAL_RELEASE p.insert("print_proof", CPK_BOOL, "(default: false) print proof associated with each assertion."); @@ -308,7 +308,7 @@ public: exec_given_tactic_cmd::init_pdescrs(ctx, p); } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { if (!m_tactic) { throw cmd_exception("apply needs a tactic argument"); } diff --git a/src/duality/duality.h b/src/duality/duality.h index c9ef3c52d..bb736feb9 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -248,14 +248,14 @@ namespace Duality { TermTree *&interpolants, model &_model, TermTree *goals = 0, - bool weak = false) + bool weak = false) override { literals _labels; islvr->SetWeakInterpolants(weak); return islvr->interpolate_tree(assumptions,interpolants,_model,_labels,true); } - void assert_axiom(const expr &axiom){ + void assert_axiom(const expr &axiom) override { #if 1 // HACK: large "distict" predicates can kill the legacy SMT solver. // encode them with a UIF @@ -280,11 +280,11 @@ namespace Duality { islvr->AssertInterpolationAxiom(axiom); } - const std::vector &get_axioms() { + const std::vector &get_axioms() override { return islvr->GetInterpolationAxioms(); } - std::string profile(){ + std::string profile() override { return islvr->profile(); } @@ -307,31 +307,31 @@ namespace Duality { void write_interpolation_problem(const std::string &file_name, const std::vector &assumptions, const std::vector &theory - ){ + ) override { #if 0 islvr->write_interpolation_problem(file_name,assumptions,theory); #endif } - void cancel(){islvr->cancel();} + void cancel() override {islvr->cancel();} /** Declare a constant in the background theory. */ - virtual void declare_constant(const func_decl &f){ + void declare_constant(const func_decl &f) override { bckg.insert(f); } /** Is this a background constant? */ - virtual bool is_constant(const func_decl &f){ + bool is_constant(const func_decl &f) override { return bckg.find(f) != bckg.end(); } /** Get the constants in the background vocabulary */ - virtual hash_set &get_constants(){ + hash_set &get_constants() override { return bckg; } - ~iZ3LogicSolver(){ + ~iZ3LogicSolver() override { // delete ictx; delete islvr; } @@ -1274,7 +1274,7 @@ namespace Duality { virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false); #endif - virtual ~RPFP_caching(){} + ~RPFP_caching() override {} protected: hash_map AssumptionLits; @@ -1320,21 +1320,21 @@ namespace Duality { void FilterCore(std::vector &core, std::vector &full_core); void ConstrainEdgeLocalizedCache(Edge *e, const Term &tl, std::vector &lits); - virtual void slvr_add(const expr &e); + void slvr_add(const expr &e) override; - virtual void slvr_pop(int i); + void slvr_pop(int i) override; - virtual void slvr_push(); + void slvr_push() override; - virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0); + check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0) override; - virtual lbool ls_interpolate_tree(TermTree *assumptions, + lbool ls_interpolate_tree(TermTree *assumptions, TermTree *&interpolants, model &_model, TermTree *goals = 0, - bool weak = false); + bool weak = false) override; - virtual bool proof_core_contains(const expr &e); + bool proof_core_contains(const expr &e) override; void GetTermTreeAssertionLiterals(TermTree *assumptions); diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index 6053295b5..66bcf4ab3 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -151,7 +151,7 @@ namespace Duality { } } - ~Duality(){ + ~Duality() override { #ifdef USE_RPFP_CLONE delete clone_rpfp; #endif @@ -321,7 +321,7 @@ namespace Duality { #endif /** Solve the problem. */ - virtual bool Solve(){ + bool Solve() override { PreSolve(); bool res = SolveMain(); // does the actual work PostSolve(); @@ -398,7 +398,7 @@ namespace Duality { } - void Cancel(){ + void Cancel() override { // TODO } @@ -418,7 +418,7 @@ namespace Duality { } #endif - virtual void LearnFrom(Solver *other_solver){ + void LearnFrom(Solver *other_solver) override { // get the counterexample as a guide cex.swap(other_solver->GetCounterexample()); @@ -429,7 +429,7 @@ namespace Duality { } /** Return a reference to the counterexample */ - virtual Counterexample &GetCounterexample(){ + Counterexample &GetCounterexample() override { return cex; } @@ -462,7 +462,7 @@ namespace Duality { } /** Set options (not currently used) */ - virtual bool SetOption(const std::string &option, const std::string &value){ + bool SetOption(const std::string &option, const std::string &value) override { if(option == "full_expand"){ return SetBoolOption(FullExpand,value); } @@ -828,7 +828,7 @@ namespace Duality { } } - bool IsResultRecursionBounded(){ + bool IsResultRecursionBounded() override { return recursionBounded; } @@ -2186,7 +2186,7 @@ namespace Duality { struct DoRestart {}; - virtual bool Build(){ + bool Build() override { restart_interval = 3; while (true) { try { @@ -2499,7 +2499,7 @@ namespace Duality { hash_map > node_map; std::list updated_nodes; - virtual void ExpandNode(RPFP::Node *p){ + void ExpandNode(RPFP::Node *p) override { stack.push_back(stack_entry()); stack.back().level = tree->slvr().get_scope_level(); stack.back().expansions.push_back(p); @@ -2990,13 +2990,13 @@ namespace Duality { old_cex.swap(_old_cex); // take ownership from caller } - ~ReplayHeuristic(){ + ~ReplayHeuristic() override { } // Maps nodes of derivation tree into old cex hash_map cex_map; - void Done() { + void Done() override { cex_map.clear(); old_cex.clear(); } @@ -3045,7 +3045,7 @@ namespace Duality { return cex_map[node]; } - int UseNode(Node *node){ + int UseNode(Node *node) override { if (!old_cex.get_tree()) return 0; Node *old_node = MatchNode(node); @@ -3054,7 +3054,7 @@ namespace Duality { return old_cex.get_tree()->Empty(old_node) ? -1 : 1; } - virtual void ChooseExpand(const std::set &choices, std::set &best, bool high_priority, bool best_only){ + void ChooseExpand(const std::set &choices, std::set &best, bool high_priority, bool best_only) override { if(cex_map.empty()) cex_map[*(choices.begin())] = old_cex.get_root(); // match the root nodes if(!high_priority || !old_cex.get_tree()){ @@ -3099,7 +3099,7 @@ namespace Duality { // Maps nodes of derivation tree into old subtree hash_map cex_map; - virtual void ChooseExpand(const std::set &choices, std::set &best, bool, bool){ + void ChooseExpand(const std::set &choices, std::set &best, bool, bool) override { if(old_node == 0){ Heuristic::ChooseExpand(choices,best); return; @@ -3200,11 +3200,11 @@ namespace Duality { } } - virtual std::vector &Propose(Node *node){ + std::vector &Propose(Node *node) override { return conjectures[node->map]; } - virtual ~HistoryProposer(){ + ~HistoryProposer() override { }; private: @@ -3273,68 +3273,68 @@ namespace Duality { } s << "[" << event++ << "]" ; } - virtual void Extend(RPFP::Node *node){ + void Extend(RPFP::Node *node) override { ev(); s << "node " << node->number << ": " << node->Name.name(); std::vector &rps = node->Outgoing->Children; for(unsigned i = 0; i < rps.size(); i++) s << " " << rps[i]->number; s << std::endl; } - virtual void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager){ + void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager) override { ev(); s << "update " << node->number << " " << node->Name.name() << ": "; rpfp->Summarize(update.Formula); if(depth > 0) s << " (depth=" << depth << ")"; if(eager) s << " (eager)"; s << std::endl; } - virtual void Bound(RPFP::Node *node){ + void Bound(RPFP::Node *node) override { ev(); s << "check " << node->number << std::endl; } - virtual void Expand(RPFP::Edge *edge){ + void Expand(RPFP::Edge *edge) override { RPFP::Node *node = edge->Parent; ev(); s << "expand " << node->map->number << " " << node->Name.name(); if(depth > 0) s << " (depth=" << depth << ")"; s << std::endl; } - virtual void Depth(int d){ + void Depth(int d) override { depth = d; } - virtual void AddCover(RPFP::Node *covered, std::vector &covering){ + void AddCover(RPFP::Node *covered, std::vector &covering) override { ev(); s << "cover " << covered->Name.name() << ": " << covered->number << " by "; for(unsigned i = 0; i < covering.size(); i++) s << covering[i]->number << " "; s << std::endl; } - virtual void RemoveCover(RPFP::Node *covered, RPFP::Node *covering){ + void RemoveCover(RPFP::Node *covered, RPFP::Node *covering) override { ev(); s << "uncover " << covered->Name.name() << ": " << covered->number << " by " << covering->number << std::endl; } - virtual void Forcing(RPFP::Node *covered, RPFP::Node *covering){ + void Forcing(RPFP::Node *covered, RPFP::Node *covering) override { ev(); s << "forcing " << covered->Name.name() << ": " << covered->number << " by " << covering->number << std::endl; } - virtual void Conjecture(RPFP::Node *node, const RPFP::Transformer &t){ + void Conjecture(RPFP::Node *node, const RPFP::Transformer &t) override { ev(); s << "conjecture " << node->number << " " << node->Name.name() << ": "; rpfp->Summarize(t.Formula); s << std::endl; } - virtual void Dominates(RPFP::Node *node, RPFP::Node *other){ + void Dominates(RPFP::Node *node, RPFP::Node *other) override { ev(); s << "dominates " << node->Name.name() << ": " << node->number << " > " << other->number << std::endl; } - virtual void InductionFailure(RPFP::Edge *edge, const std::vector &children){ + void InductionFailure(RPFP::Edge *edge, const std::vector &children) override { ev(); s << "induction failure: " << edge->Parent->Name.name() << ", children ="; for(unsigned i = 0; i < children.size(); i++) s << " " << children[i]->number; s << std::endl; } - virtual void UpdateUnderapprox(RPFP::Node *node, const RPFP::Transformer &update){ + void UpdateUnderapprox(RPFP::Node *node, const RPFP::Transformer &update) override { ev(); s << "underapprox " << node->number << " " << node->Name.name() << ": " << update.Formula << std::endl; } - virtual void Reject(RPFP::Edge *edge, const std::vector &children){ + void Reject(RPFP::Edge *edge, const std::vector &children) override { ev(); s << "reject " << edge->Parent->number << " " << edge->Parent->Name.name() << ": "; for(unsigned i = 0; i < children.size(); i++) s << " " << children[i]->number; s << std::endl; } - virtual void Message(const std::string &msg){ + void Message(const std::string &msg) override { ev(); s << "msg " << msg << std::endl; } @@ -3356,12 +3356,12 @@ namespace Duality { duality = alloc(Duality,drpfp); } - ~DualityDepthBounded(){ + ~DualityDepthBounded() override { dealloc(duality); delete drpfp; } - bool Solve(){ + bool Solve() override { int depth_bound = 10; bool res; SetMaxDepthRPFP(depth_bound); @@ -3382,26 +3382,26 @@ namespace Duality { return res; } - Counterexample &GetCounterexample(){ + Counterexample &GetCounterexample() override { return cex; } - bool SetOption(const std::string &option, const std::string &value){ + bool SetOption(const std::string &option, const std::string &value) override { return duality->SetOption(option,value); } - virtual void LearnFrom(Solver *old_solver){ + void LearnFrom(Solver *old_solver) override { DualityDepthBounded *old = dynamic_cast(old_solver); if(old){ duality->LearnFrom(old->duality); } } - bool IsResultRecursionBounded(){ + bool IsResultRecursionBounded() override { return duality->IsResultRecursionBounded(); } - void Cancel(){ + void Cancel() override { duality->Cancel(); } @@ -3580,7 +3580,7 @@ namespace Duality { public: ConjectureFileReporter(RPFP *_rpfp, const std::string &fname) : Reporter(_rpfp), s(fname.c_str()) {} - virtual void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager){ + void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager) override { s << "(define-fun " << node->Name.name() << " ("; for(unsigned i = 0; i < update.IndParams.size(); i++){ if(i != 0) diff --git a/src/math/automata/boolean_algebra.h b/src/math/automata/boolean_algebra.h index d54ff5d1a..ea2b66995 100644 --- a/src/math/automata/boolean_algebra.h +++ b/src/math/automata/boolean_algebra.h @@ -39,7 +39,7 @@ public: template class boolean_algebra : public positive_boolean_algebra { public: - virtual ~boolean_algebra() {} + ~boolean_algebra() override {} virtual T mk_not(T x) = 0; }; diff --git a/src/math/polynomial/polynomial_var2value.h b/src/math/polynomial/polynomial_var2value.h index c4aa16dfa..523703709 100644 --- a/src/math/polynomial/polynomial_var2value.h +++ b/src/math/polynomial/polynomial_var2value.h @@ -32,9 +32,9 @@ namespace polynomial { public: simple_var2value(ValManager & m):m_vs(m) {} void push_back(var x, typename ValManager::numeral const & v) { m_xs.push_back(x); m_vs.push_back(v); } - virtual ValManager & m() const { return m_vs.m(); } - virtual bool contains(var x) const { return std::find(m_xs.begin(), m_xs.end(), x) != m_xs.end(); } - virtual typename ValManager::numeral const & operator()(var x) const { + ValManager & m() const override { return m_vs.m(); } + bool contains(var x) const override { return std::find(m_xs.begin(), m_xs.end(), x) != m_xs.end(); } + typename ValManager::numeral const & operator()(var x) const override { for (unsigned i = 0; i < m_xs.size(); i++) if (m_xs[i] == x) return m_vs[i]; diff --git a/src/model/model.cpp b/src/model/model.cpp index 7ac1300de..7823a6f6b 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -93,7 +93,7 @@ bool model::eval(expr * e, expr_ref & result, bool model_completion) { struct model::value_proc : public some_value_proc { model & m_model; value_proc(model & m):m_model(m) {} - virtual expr * operator()(sort * s) { + expr * operator()(sort * s) override { ptr_vector * u = 0; if (m_model.m_usort2universe.find(s, u)) { if (u->size() > 0) diff --git a/src/model/model.h b/src/model/model.h index f6de8ce0e..758d3d451 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -33,7 +33,7 @@ protected: public: model(ast_manager & m); - virtual ~model(); + ~model() override; void copy_func_interps(model const & source); void copy_const_interps(model const & source); @@ -44,11 +44,11 @@ public: bool eval(func_decl * f, expr_ref & r) const { return model_core::eval(f, r); } bool eval(expr * e, expr_ref & result, bool model_completion = false); - virtual expr * get_some_value(sort * s); - virtual ptr_vector const & get_universe(sort * s) const; - virtual unsigned get_num_uninterpreted_sorts() const; - virtual sort * get_uninterpreted_sort(unsigned idx) const; - bool has_uninterpreted_sort(sort * s) const; + expr * get_some_value(sort * s) override; + ptr_vector const & get_universe(sort * s) const override; + unsigned get_num_uninterpreted_sorts() const override; + sort * get_uninterpreted_sort(unsigned idx) const override; + bool has_uninterpreted_sort(sort * s) const; // // Primitives for building models diff --git a/src/nlsat/nlsat_assignment.h b/src/nlsat/nlsat_assignment.h index 097ad76b6..cae15f4e1 100644 --- a/src/nlsat/nlsat_assignment.h +++ b/src/nlsat/nlsat_assignment.h @@ -66,9 +66,9 @@ namespace nlsat { void reset() { m_assigned.reset(); } bool is_assigned(var x) const { return m_assigned.get(x, false); } anum const & value(var x) const { return m_values[x]; } - virtual anum_manager & m() const { return am(); } - virtual bool contains(var x) const { return is_assigned(x); } - virtual anum const & operator()(var x) const { SASSERT(is_assigned(x)); return value(x); } + anum_manager & m() const override { return am(); } + bool contains(var x) const override { return is_assigned(x); } + anum const & operator()(var x) const override { SASSERT(is_assigned(x)); return value(x); } void swap(var x, var y) { SASSERT(x < m_values.size() && y < m_values.size()); std::swap(m_assigned[x], m_assigned[y]); @@ -95,9 +95,9 @@ namespace nlsat { var m_y; public: undef_var_assignment(assignment const & a, var y):m_assignment(a), m_y(y) {} - virtual anum_manager & m() const { return m_assignment.am(); } - virtual bool contains(var x) const { return x != m_y && m_assignment.is_assigned(x); } - virtual anum const & operator()(var x) const { return m_assignment.value(x); } + anum_manager & m() const override { return m_assignment.am(); } + bool contains(var x) const override { return x != m_y && m_assignment.is_assigned(x); } + anum const & operator()(var x) const override { return m_assignment.value(x); } }; }; diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 12b063759..3358dd61a 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -112,7 +112,7 @@ namespace nlsat { m_perm(perm), m_proc(0) { } - std::ostream& operator()(std::ostream & out, var x) const { + std::ostream& operator()(std::ostream & out, var x) const override { if (m_proc == 0) m_default_display_var(out, x); else @@ -2699,7 +2699,7 @@ namespace nlsat { var m_x; public: mathematica_var_proc(var x):m_x(x) {} - virtual std::ostream& operator()(std::ostream & out, var x) const { + std::ostream& operator()(std::ostream & out, var x) const override { if (m_x == x) return out << "#1"; else diff --git a/src/nlsat/tactic/goal2nlsat.cpp b/src/nlsat/tactic/goal2nlsat.cpp index 6d7e1c767..51536e493 100644 --- a/src/nlsat/tactic/goal2nlsat.cpp +++ b/src/nlsat/tactic/goal2nlsat.cpp @@ -41,11 +41,11 @@ struct goal2nlsat::imp { m_solver(s) { } - virtual bool is_int(polynomial::var x) const { + bool is_int(polynomial::var x) const override { return m_solver.is_int(x); } - virtual polynomial::var mk_var(bool is_int) { + polynomial::var mk_var(bool is_int) override { return m_solver.mk_var(is_int); } }; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 9de7215e3..74531a9a7 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -32,7 +32,7 @@ class nlsat_tactic : public tactic { ast_manager & m; expr_ref_vector m_var2expr; expr_display_var_proc(ast_manager & _m):m(_m), m_var2expr(_m) {} - virtual std::ostream& operator()(std::ostream & out, nlsat::var x) const { + std::ostream& operator()(std::ostream & out, nlsat::var x) const override { if (x < m_var2expr.size()) return out << mk_ismt2_pp(m_var2expr.get(x), m); else @@ -214,29 +214,29 @@ public: m_imp = 0; } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(nlsat_tactic, m_params); } - virtual ~nlsat_tactic() { + ~nlsat_tactic() override { SASSERT(m_imp == 0); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { goal2nlsat::collect_param_descrs(r); nlsat::solver::collect_param_descrs(r); algebraic_numbers::manager::collect_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { imp local_imp(in->m(), m_params); scoped_set_imp setter(*this, local_imp); @@ -251,13 +251,13 @@ public: } } - virtual void cleanup() {} + void cleanup() override {} - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.copy(m_stats); } - virtual void reset_statistics() { + void reset_statistics() override { m_stats.reset(); } }; diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 38720a5e9..76956718c 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -76,15 +76,15 @@ struct simple_check_sat_result : public check_sat_result { simple_check_sat_result(ast_manager & m); - virtual ~simple_check_sat_result(); - virtual ast_manager& get_manager() const { return m_proof.get_manager(); } - virtual void collect_statistics(statistics & st) const; - virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & m); - virtual proof * get_proof(); - virtual std::string reason_unknown() const; - virtual void get_labels(svector & r); - virtual void set_reason_unknown(char const* msg) { m_unknown = msg; } + ~simple_check_sat_result() override; + ast_manager& get_manager() const override { return m_proof.get_manager(); } + void collect_statistics(statistics & st) const override; + void get_unsat_core(ptr_vector & r) override; + void get_model(model_ref & m) override; + proof * get_proof() override; + std::string reason_unknown() const override; + void get_labels(svector & r) override; + void set_reason_unknown(char const* msg) override { m_unknown = msg; } }; #endif diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 81e10e443..397f3bdb1 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -84,12 +84,12 @@ private: solver * m_solver; volatile bool m_canceled; aux_timeout_eh(solver * s):m_solver(s), m_canceled(false) {} - ~aux_timeout_eh() { + ~aux_timeout_eh() override { if (m_canceled) { m_solver->get_manager().limit().dec_cancel(); } } - virtual void operator()(event_handler_caller_t caller_id) { + void operator()(event_handler_caller_t caller_id) override { m_canceled = true; m_solver->get_manager().limit().inc_cancel(); } @@ -102,7 +102,7 @@ private: m_inc_unknown_behavior = static_cast(p.solver2_unknown()); } - virtual ast_manager& get_manager() const { return m_solver1->get_manager(); } + ast_manager& get_manager() const override { return m_solver1->get_manager(); } bool has_quantifiers() const { unsigned sz = get_num_assertions(); @@ -135,7 +135,7 @@ public: m_use_solver1_results = true; } - solver* translate(ast_manager& m, params_ref const& p) { + solver* translate(ast_manager& m, params_ref const& p) override { solver* s1 = m_solver1->translate(m, p); solver* s2 = m_solver2->translate(m, p); combined_solver* r = alloc(combined_solver, s1, s2, p); @@ -146,25 +146,25 @@ public: return r; } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver1->updt_params(p); m_solver2->updt_params(p); updt_local_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_solver1->collect_param_descrs(r); m_solver2->collect_param_descrs(r); combined_solver_params::collect_param_descrs(r); } - virtual void set_produce_models(bool f) { + void set_produce_models(bool f) override { m_solver1->set_produce_models(f); m_solver2->set_produce_models(f); } - virtual void assert_expr(expr * t) { + void assert_expr(expr * t) override { if (m_check_sat_executed) switch_inc_mode(); m_solver1->assert_expr(t); @@ -172,7 +172,7 @@ public: m_solver2->assert_expr(t); } - virtual void assert_expr(expr * t, expr * a) { + void assert_expr(expr * t, expr * a) override { if (m_check_sat_executed) switch_inc_mode(); m_solver1->assert_expr(t, a); @@ -180,23 +180,23 @@ public: m_solver2->assert_expr(t, a); } - virtual void push() { + void push() override { switch_inc_mode(); m_solver1->push(); m_solver2->push(); } - virtual void pop(unsigned n) { + void pop(unsigned n) override { switch_inc_mode(); m_solver1->pop(n); m_solver2->pop(n); } - virtual unsigned get_scope_level() const { + unsigned get_scope_level() const override { return m_solver1->get_scope_level(); } - virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { switch_inc_mode(); m_use_solver1_results = false; try { @@ -213,7 +213,7 @@ public: return l_undef; } - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions) { + lbool check_sat(unsigned num_assumptions, expr * const * assumptions) override { m_check_sat_executed = true; m_use_solver1_results = false; @@ -258,73 +258,73 @@ public: return m_solver1->check_sat(num_assumptions, assumptions); } - virtual void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { m_solver1->set_progress_callback(callback); m_solver2->set_progress_callback(callback); } - virtual unsigned get_num_assertions() const { + unsigned get_num_assertions() const override { return m_solver1->get_num_assertions(); } - virtual expr * get_assertion(unsigned idx) const { + expr * get_assertion(unsigned idx) const override { return m_solver1->get_assertion(idx); } - virtual unsigned get_num_assumptions() const { + unsigned get_num_assumptions() const override { return m_solver1->get_num_assumptions() + m_solver2->get_num_assumptions(); } - virtual expr * get_assumption(unsigned idx) const { + expr * get_assumption(unsigned idx) const override { unsigned c1 = m_solver1->get_num_assumptions(); if (idx < c1) return m_solver1->get_assumption(idx); return m_solver2->get_assumption(idx - c1); } - virtual std::ostream& display(std::ostream & out, unsigned n, expr* const* es) const { + std::ostream& display(std::ostream & out, unsigned n, expr* const* es) const override { return m_solver1->display(out, n, es); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { m_solver2->collect_statistics(st); if (m_use_solver1_results) m_solver1->collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { + void get_unsat_core(ptr_vector & r) override { if (m_use_solver1_results) m_solver1->get_unsat_core(r); else m_solver2->get_unsat_core(r); } - virtual void get_model(model_ref & m) { + void get_model(model_ref & m) override { if (m_use_solver1_results) m_solver1->get_model(m); else m_solver2->get_model(m); } - virtual proof * get_proof() { + proof * get_proof() override { if (m_use_solver1_results) return m_solver1->get_proof(); else return m_solver2->get_proof(); } - virtual std::string reason_unknown() const { + std::string reason_unknown() const override { if (m_use_solver1_results) return m_solver1->reason_unknown(); else return m_solver2->reason_unknown(); } - virtual void set_reason_unknown(char const* msg) { + void set_reason_unknown(char const* msg) override { m_solver1->set_reason_unknown(msg); m_solver2->set_reason_unknown(msg); } - virtual void get_labels(svector & r) { + void get_labels(svector & r) override { if (m_use_solver1_results) return m_solver1->get_labels(r); else @@ -343,9 +343,9 @@ class combined_solver_factory : public solver_factory { scoped_ptr m_f2; public: combined_solver_factory(solver_factory * f1, solver_factory * f2):m_f1(f1), m_f2(f2) {} - virtual ~combined_solver_factory() {} + ~combined_solver_factory() override {} - virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) { + solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) override { return mk_combined_solver((*m_f1)(m, p, proofs_enabled, models_enabled, unsat_core_enabled, logic), (*m_f2)(m, p, proofs_enabled, models_enabled, unsat_core_enabled, logic), p); diff --git a/src/solver/solver.h b/src/solver/solver.h index 0a406455b..0b0acb644 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -45,7 +45,7 @@ public: class solver : public check_sat_result { params_ref m_params; public: - virtual ~solver() {} + ~solver() override {} /** \brief Creates a clone of the solver. diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index fa0711d70..3bc66e3b4 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -92,20 +92,20 @@ public: m_solver(s) {} - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params.append(p); m_solver->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_solver->collect_param_descrs(r); } - virtual void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, - /* out */ expr_dependency_ref & core) { + void operator()(/* in */ goal_ref const & in, + /* out */ goal_ref_buffer & result, + /* out */ model_converter_ref & mc, + /* out */ proof_converter_ref & pc, + /* out */ expr_dependency_ref & core) override { pc = 0; mc = 0; core = 0; expr_ref_vector clauses(m); expr2expr_map bool2dep; @@ -155,21 +155,21 @@ public: local_solver->collect_statistics(m_st); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.copy(m_st); } - virtual void reset_statistics() { m_st.reset(); } + void reset_statistics() override { m_st.reset(); } - virtual void cleanup() { } - virtual void reset() { cleanup(); } + void cleanup() override { } + void reset() override { cleanup(); } - virtual void set_logic(symbol const & l) {} + void set_logic(symbol const & l) override {} - virtual void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { m_solver->set_progress_callback(callback); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(solver2tactic, m_solver->translate(m, m_params)); } }; diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 3e726be12..0a041bd57 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -32,21 +32,21 @@ class solver_na2as : public solver { void restore_assumptions(unsigned old_sz); public: solver_na2as(ast_manager & m); - virtual ~solver_na2as(); + ~solver_na2as() override; - virtual void assert_expr(expr * t, expr * a); - virtual void assert_expr(expr * t) = 0; + void assert_expr(expr * t, expr * a) override; + void assert_expr(expr * t) override = 0; // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. - virtual lbool check_sat(unsigned num_assumptions, expr * const * assumptions); - virtual void push(); - virtual void pop(unsigned n); - virtual unsigned get_scope_level() const; + lbool check_sat(unsigned num_assumptions, expr * const * assumptions) override; + void push() override; + void pop(unsigned n) override; + unsigned get_scope_level() const override; - virtual unsigned get_num_assumptions() const { return m_assumptions.size(); } - virtual expr * get_assumption(unsigned idx) const { return m_assumptions[idx]; } - virtual lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences); - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); + unsigned get_num_assumptions() const override { return m_assumptions.size(); } + expr * get_assumption(unsigned idx) const override { return m_assumptions[idx]; } + lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override; + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; protected: virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; virtual void push_core() = 0; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index c8899e365..d58895708 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -53,7 +53,7 @@ public: } } - virtual ~pool_solver() { + ~pool_solver() override { if (m_pushed) pop(get_scope_level()); if (is_virtual()) { m_pred = m.mk_not(m_pred); @@ -63,12 +63,12 @@ public: solver* base_solver() { return m_base.get(); } - virtual solver* translate(ast_manager& m, params_ref const& p) { UNREACHABLE(); return nullptr; } - virtual void updt_params(params_ref const& p) { solver::updt_params(p); m_base->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_base->collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { m_base->collect_statistics(st); } + solver* translate(ast_manager& m, params_ref const& p) override { UNREACHABLE(); return nullptr; } + void updt_params(params_ref const& p) override { solver::updt_params(p); m_base->updt_params(p); } + void collect_param_descrs(param_descrs & r) override { m_base->collect_param_descrs(r); } + void collect_statistics(statistics & st) const override { m_base->collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { + void get_unsat_core(ptr_vector & r) override { m_base->get_unsat_core(r); unsigned j = 0; for (unsigned i = 0; i < r.size(); ++i) @@ -77,12 +77,12 @@ public: r.shrink(j); } - virtual unsigned get_num_assumptions() const { + unsigned get_num_assumptions() const override { unsigned sz = solver_na2as::get_num_assumptions(); return is_virtual() ? sz - 1 : sz; } - virtual proof * get_proof() { + proof * get_proof() override { scoped_watch _t_(m_pool.m_proof_watch); if (!m_proof.get()) { elim_aux_assertions pc(m_pred); @@ -101,7 +101,7 @@ public: } } - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); scoped_watch _t_(m_pool.m_check_watch); @@ -158,7 +158,7 @@ public: return res; } - virtual void push_core() { + void push_core() override { SASSERT(!m_pushed || get_scope_level() > 0); if (m_in_delayed_scope) { // second push @@ -178,7 +178,7 @@ public: } } - virtual void pop_core(unsigned n) { + void pop_core(unsigned n) override { SASSERT(!m_pushed || get_scope_level() > 0); if (m_pushed) { SASSERT(!m_in_delayed_scope); @@ -190,7 +190,7 @@ public: } } - virtual void assert_expr(expr * e) { + void assert_expr(expr * e) override { SASSERT(!m_pushed || get_scope_level() > 0); if (m.is_true(e)) return; if (m_in_delayed_scope) { @@ -211,18 +211,18 @@ public: } } - virtual void get_model(model_ref & _m) { m_base->get_model(_m); } + void get_model(model_ref & _m) override { m_base->get_model(_m); } - virtual expr * get_assumption(unsigned idx) const { + expr * get_assumption(unsigned idx) const override { return solver_na2as::get_assumption(idx + is_virtual()); } - virtual std::string reason_unknown() const { return m_base->reason_unknown(); } - virtual void set_reason_unknown(char const* msg) { return m_base->set_reason_unknown(msg); } - virtual void get_labels(svector & r) { return m_base->get_labels(r); } - virtual void set_progress_callback(progress_callback * callback) { m_base->set_progress_callback(callback); } + std::string reason_unknown() const override { return m_base->reason_unknown(); } + void set_reason_unknown(char const* msg) override { return m_base->set_reason_unknown(msg); } + void get_labels(svector & r) override { return m_base->get_labels(r); } + void set_progress_callback(progress_callback * callback) override { m_base->set_progress_callback(callback); } - virtual ast_manager& get_manager() const { return m_base->get_manager(); } + ast_manager& get_manager() const override { return m_base->get_manager(); } void refresh(solver* new_base) { SASSERT(!m_pushed); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index a24f1d4c7..9dc4fe43d 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -44,36 +44,36 @@ class tactic2solver : public solver_na2as { public: tactic2solver(ast_manager & m, tactic * t, params_ref const & p, bool produce_proofs, bool produce_models, bool produce_unsat_cores, symbol const & logic); - virtual ~tactic2solver(); + ~tactic2solver() override; - virtual solver* translate(ast_manager& m, params_ref const& p); + solver* translate(ast_manager& m, params_ref const& p) override; - virtual void updt_params(params_ref const & p); - virtual void collect_param_descrs(param_descrs & r); + void updt_params(params_ref const & p) override; + void collect_param_descrs(param_descrs & r) override; - virtual void set_produce_models(bool f) { m_produce_models = f; } + void set_produce_models(bool f) override { m_produce_models = f; } - virtual void assert_expr(expr * t); + void assert_expr(expr * t) override; - virtual void push_core(); - virtual void pop_core(unsigned n); - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); + void push_core() override; + void pop_core(unsigned n) override; + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override; - virtual void collect_statistics(statistics & st) const; - virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & m); - virtual proof * get_proof(); - virtual std::string reason_unknown() const; - virtual void set_reason_unknown(char const* msg); - virtual void get_labels(svector & r) {} + void collect_statistics(statistics & st) const override; + void get_unsat_core(ptr_vector & r) override; + void get_model(model_ref & m) override; + proof * get_proof() override; + std::string reason_unknown() const override; + void set_reason_unknown(char const* msg) override; + void get_labels(svector & r) override {} - virtual void set_progress_callback(progress_callback * callback) {} + void set_progress_callback(progress_callback * callback) override {} - virtual unsigned get_num_assertions() const; - virtual expr * get_assertion(unsigned idx) const; + unsigned get_num_assertions() const override; + expr * get_assertion(unsigned idx) const override; - virtual ast_manager& get_manager() const; + ast_manager& get_manager() const override; }; ast_manager& tactic2solver::get_manager() const { return m_assertions.get_manager(); } @@ -261,9 +261,9 @@ public: tactic2solver_factory(tactic * t):m_tactic(t) { } - virtual ~tactic2solver_factory() {} + ~tactic2solver_factory() override {} - virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) { + solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) override { return mk_tactic2solver(m, m_tactic.get(), p, proofs_enabled, models_enabled, unsat_core_enabled, logic); } }; @@ -274,9 +274,9 @@ public: tactic_factory2solver_factory(tactic_factory * f):m_factory(f) { } - virtual ~tactic_factory2solver_factory() {} + ~tactic_factory2solver_factory() override {} - virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) { + solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) override { tactic * t = (*m_factory)(m, p); return mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, logic); } diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index 37ffc6124..b6b5021a1 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -46,7 +46,7 @@ public: updt_params(p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { aig_tactic * t = alloc(aig_tactic); t->m_max_memory = m_max_memory; t->m_aig_gate_encoding = m_aig_gate_encoding; @@ -54,13 +54,13 @@ public: return t; } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); m_aig_gate_encoding = p.get_bool("aig_default_gate_encoding", true); m_aig_per_assertion = p.get_bool("aig_per_assertion", true); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); r.insert("aig_per_assertion", CPK_BOOL, "(default: true) process one assertion at a time."); } @@ -90,11 +90,11 @@ public: SASSERT(g->is_well_sorted()); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { fail_if_proof_generation("aig", g); mc = 0; pc = 0; core = 0; operator()(g); @@ -102,7 +102,7 @@ public: result.push_back(g.get()); } - virtual void cleanup() {} + void cleanup() override {} }; diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index ac105eb06..e71542532 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -48,10 +48,10 @@ bool is_unbounded(goal const & g) { class is_unbounded_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_unbounded(g); } - virtual ~is_unbounded_probe() {} + ~is_unbounded_probe() override {} }; probe * mk_is_unbounded_probe() { @@ -142,33 +142,33 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(add_bounds_tactic, m, m_params); } - virtual ~add_bounds_tactic() { + ~add_bounds_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("add_bound_lower", CPK_NUMERAL, "(default: -2) lower bound to be added to unbounded variables."); r.insert("add_bound_upper", CPK_NUMERAL, "(default: 2) upper bound to be added to unbounded variables."); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(g, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m, m_params); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index b750689b1..31e5d4fdc 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -23,15 +23,15 @@ struct arith_bounds_tactic : public tactic { ast_manager& get_manager() { return m; } - virtual void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, - /* out */ expr_dependency_ref & core) { + void operator()(/* in */ goal_ref const & in, + /* out */ goal_ref_buffer & result, + /* out */ model_converter_ref & mc, + /* out */ proof_converter_ref & pc, + /* out */ expr_dependency_ref & core) override { bounds_arith_subsumption(in, result); } - virtual tactic* translate(ast_manager & mgr) { + tactic* translate(ast_manager & mgr) override { return alloc(arith_bounds_tactic, mgr); } @@ -146,7 +146,7 @@ struct arith_bounds_tactic : public tactic { TRACE("arith_subsumption", s->display(tout); ); } - virtual void cleanup() {} + void cleanup() override {} }; diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index d2453eba2..b268ea3de 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -36,26 +36,26 @@ public: m_params(p) { } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(card2bv_tactic, m, m_params); } - virtual ~card2bv_tactic() { + ~card2bv_tactic() override { } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { TRACE("card2bv-before", g->display(tout);); SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; result.reset(); @@ -101,7 +101,7 @@ public: SASSERT(g->is_well_sorted()); } - virtual void cleanup() { + void cleanup() override { } }; diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 6344c4c51..778a73ba5 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -297,23 +297,23 @@ public: m_imp = alloc(imp, m); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(degree_shift_tactic, m); } - virtual ~degree_shift_tactic() { + ~degree_shift_tactic() override { dealloc(m_imp); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index c66483750..90dcf099c 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -354,28 +354,28 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(diff_neq_tactic, m, m_params); } - virtual ~diff_neq_tactic() { + ~diff_neq_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("diff_neq_max_k", CPK_UINT, "(default: 1024) maximum variable upper bound for diff neq solver."); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.update("conflicts", m_imp->m_num_conflicts); } - virtual void reset_statistics() { + void reset_statistics() override { m_imp->m_num_conflicts = 0; } @@ -383,15 +383,15 @@ public: \brief Fix a DL variable in s to 0. If s is not really in the difference logic fragment, then this is a NOOP. */ - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m, m_params); d->m_num_conflicts = m_imp->m_num_conflicts; std::swap(d, m_imp); diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index b6fd5eee7..7a923cf0a 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -41,7 +41,7 @@ public: m_refs(m) {} - virtual void operator()(model_ref & old_model, unsigned goal_idx) { + void operator()(model_ref & old_model, unsigned goal_idx) override { SASSERT(goal_idx == 0); model * new_model = alloc(model, m); unsigned num = old_model->get_num_constants(); @@ -106,7 +106,7 @@ public: } } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { bool2int_model_converter* mc = alloc(bool2int_model_converter, translator.to()); for (unsigned i = 0; i < m_nums_as_int.size(); ++i) { mc->insert(m_nums_as_int[i], m_nums_as_bool[i].size(), m_nums_as_bool[i].c_ptr()); @@ -134,24 +134,24 @@ public: m_max_hi(rational(m_max_hi_default)) { } - virtual ~elim01_tactic() { + ~elim01_tactic() override { } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_max_hi = rational(p.get_uint("max_coefficient", m_max_hi_default)); m_params = p; } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("max_coefficient", CPK_UINT, "(default: 1) maximal upper bound for finite range -> Bool conversion"); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; @@ -211,11 +211,11 @@ public: // TBD: support proof conversion (or not..) } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(elim01_tactic, m, m_params); } - virtual void cleanup() {} + void cleanup() override {} void add_variable(bool2int_model_converter* b2i, expr_safe_replace& sub, diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 255665b56..1219b980e 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -82,7 +82,7 @@ class eq2bv_tactic : public tactic { m_map.insert(c_new, c_old); } - virtual void operator()(model_ref& mdl) { + void operator()(model_ref& mdl) override { ast_manager& m = mdl->get_manager(); bv_util bv(m); arith_util a(m); @@ -105,7 +105,7 @@ class eq2bv_tactic : public tactic { mdl = new_m; } - virtual model_converter* translate(ast_translation & translator) { + model_converter* translate(ast_translation & translator) override { bvmc* v = alloc(bvmc); obj_map::iterator it = m_map.begin(), end = m_map.end(); for (; it != end; ++it) { @@ -136,19 +136,18 @@ public: m_bounds(m) { } - virtual ~eq2bv_tactic() { + ~eq2bv_tactic() override { } - void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { } - virtual void operator()( - goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; m_trail.reset(); @@ -213,14 +212,14 @@ public: } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(eq2bv_tactic, m); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } - virtual void cleanup() { + void cleanup() override { } void cleanup_fd(ref& mc) { diff --git a/src/tactic/arith/factor_tactic.cpp b/src/tactic/arith/factor_tactic.cpp index d187c0078..ed49e11f7 100644 --- a/src/tactic/arith/factor_tactic.cpp +++ b/src/tactic/arith/factor_tactic.cpp @@ -293,30 +293,30 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(factor_tactic, m, m_params); } - virtual ~factor_tactic() { + ~factor_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->m_rw.cfg().updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("split_factors", CPK_BOOL, "(default: true) apply simplifications such as (= (* p1 p2) 0) --> (or (= p1 0) (= p2 0))."); polynomial::factor_params::get_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { (*m_imp)(in, result, mc, pc, core); } @@ -328,7 +328,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m, m_params); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 2c25c12e1..0e0a15ba6 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -303,28 +303,28 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(fix_dl_var_tactic, m, m_params); } - virtual ~fix_dl_var_tactic() { + ~fix_dl_var_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { th_rewriter::get_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { (*m_imp)(in, result, mc, pc, core); } @@ -333,7 +333,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m, m_params); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 48f584169..9a27d6874 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -164,7 +164,7 @@ class fm_tactic : public tactic { public: fm_model_converter(ast_manager & _m):m(_m) {} - virtual ~fm_model_converter() { + ~fm_model_converter() override { m.dec_array_ref(m_xs.size(), m_xs.c_ptr()); vector::iterator it = m_clauses.begin(); vector::iterator end = m_clauses.end(); @@ -180,7 +180,7 @@ class fm_tactic : public tactic { m_clauses.back().swap(c); } - virtual void operator()(model_ref & md, unsigned goal_idx) { + void operator()(model_ref & md, unsigned goal_idx) override { TRACE("fm_mc", model_v2_pp(tout, *md); display(tout);); model_evaluator ev(*(md.get())); ev.set_model_completion(true); @@ -244,7 +244,7 @@ class fm_tactic : public tactic { } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(fm-model-converter"; SASSERT(m_xs.size() == m_clauses.size()); unsigned sz = m_xs.size(); @@ -261,7 +261,7 @@ class fm_tactic : public tactic { out << ")\n"; } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { ast_manager & to_m = translator.to(); fm_model_converter * res = alloc(fm_model_converter, to_m); unsigned sz = m_xs.size(); @@ -1643,20 +1643,20 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(fm_tactic, m, m_params); } - virtual ~fm_tactic() { + ~fm_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_produce_models(r); insert_max_memory(r); r.insert("fm_real_only", CPK_BOOL, "(default: true) consider only real variables for fourier-motzkin elimination."); @@ -1668,17 +1668,17 @@ public: } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m, m_params); std::swap(d, m_imp); dealloc(d); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } }; diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index ec41f5845..8b95d0781 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -148,21 +148,21 @@ public: m_compile_equality(false) { } - virtual ~lia2card_tactic() { + ~lia2card_tactic() override { dealloc(m_todo); dealloc(m_01s); } - void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_compile_equality = p.get_bool("compile_equality", false); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; m_01s->reset(); @@ -389,16 +389,16 @@ public: } } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(lia2card_tactic, m, m_params); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("compile_equality", CPK_BOOL, "(default:false) compile equalities into pseudo-Boolean equality"); } - virtual void cleanup() { + void cleanup() override { expr_set* d = alloc(expr_set); ptr_vector* todo = alloc(ptr_vector); std::swap(m_01s, d); diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index d303463db..ce21aa824 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -313,30 +313,30 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(lia2pb_tactic, m, m_params); } - virtual ~lia2pb_tactic() { + ~lia2pb_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("lia2pb_partial", CPK_BOOL, "(default: false) partial lia2pb conversion."); r.insert("lia2pb_max_bits", CPK_UINT, "(default: 32) maximum number of bits to be used (per variable) in lia2pb."); r.insert("lia2pb_total_bits", CPK_UINT, "(default: 2048) total number of bits to be used (per problem) in lia2pb."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { (*m_imp)(in, result, mc, pc, core); } @@ -345,7 +345,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m, m_params); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 6f5f49aee..08eb97c4b 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -418,18 +418,18 @@ public: m_imp(0) { } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(nla2bv_tactic, m_params); } - virtual ~nla2bv_tactic() { + ~nla2bv_tactic() override { } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("nla2bv_max_bv_size", CPK_UINT, "(default: inf) maximum bit-vector size used by nla2bv tactic"); r.insert("nla2bv_bv_size", CPK_UINT, "(default: 4) default bit-vector size used by nla2bv tactic."); r.insert("nla2bv_root", CPK_UINT, "(default: 2) nla2bv tactic encodes reals into bit-vectors using expressions of the form a+b*sqrt(c), this parameter sets the value of c used in the encoding."); @@ -441,11 +441,11 @@ public: arithmetic in place of non-linear integer arithmetic. \return false if transformation is not possible. */ - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); fail_if_proof_generation("nla2bv", g); fail_if_unsat_core_generation("nla2bv", g); @@ -459,7 +459,7 @@ public: SASSERT(g->is_well_sorted()); } - virtual void cleanup(void) { + void cleanup(void) override { } }; diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index 2b3ff5ab0..a9eeb3744 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -156,28 +156,28 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(normalize_bounds_tactic, m, m_params); } - virtual ~normalize_bounds_tactic() { + ~normalize_bounds_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_produce_models(r); r.insert("norm_int_only", CPK_BOOL, "(default: true) normalize only the bounds of integer constants."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { (*m_imp)(in, result, mc, pc, core); } @@ -186,7 +186,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; imp * d = alloc(imp, m, m_params); std::swap(d, m_imp); diff --git a/src/tactic/arith/pb2bv_model_converter.h b/src/tactic/arith/pb2bv_model_converter.h index 0c2826573..7e181b7dc 100644 --- a/src/tactic/arith/pb2bv_model_converter.h +++ b/src/tactic/arith/pb2bv_model_converter.h @@ -30,11 +30,11 @@ class pb2bv_model_converter : public model_converter { public: pb2bv_model_converter(ast_manager & _m); pb2bv_model_converter(ast_manager & _m, obj_map const & c2bit, bound_manager const & bm); - virtual ~pb2bv_model_converter(); - virtual void operator()(model_ref & md); - virtual void operator()(model_ref & md, unsigned goal_idx); - virtual void display(std::ostream & out); - virtual model_converter * translate(ast_translation & translator); + ~pb2bv_model_converter() override; + void operator()(model_ref & md) override; + void operator()(model_ref & md, unsigned goal_idx) override; + void display(std::ostream & out) override; + model_converter * translate(ast_translation & translator) override; }; #endif diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 259cbc0c8..05b91cf53 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -983,32 +983,32 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(pb2bv_tactic, m, m_params); } - virtual ~pb2bv_tactic() { + ~pb2bv_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_imp->collect_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; imp * d = alloc(imp, m, m_params); std::swap(d, m_imp); @@ -1023,7 +1023,7 @@ tactic * mk_pb2bv_tactic(ast_manager & m, params_ref const & p) { } struct is_pb_probe : public probe { - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { try { ast_manager & m = g.m(); bound_manager bm(m); diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index edd4483e7..36ee89a1b 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -74,7 +74,7 @@ class arith_degree_probe : public probe { public: arith_degree_probe(bool avg):m_avg(avg) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { proc p(g.m()); for_each_expr_at(p, g); if (m_avg) @@ -117,7 +117,7 @@ class arith_bw_probe : public probe { public: arith_bw_probe(bool avg):m_avg(avg) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { proc p(g.m()); for_each_expr_at(p, g); if (m_avg) @@ -269,14 +269,14 @@ static bool is_qfauflia(goal const & g) { class is_qflia_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_qflia(g); } }; class is_qfauflia_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_qfauflia(g); } }; @@ -288,7 +288,7 @@ static bool is_qflra(goal const & g) { class is_qflra_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_qflra(g); } }; @@ -300,7 +300,7 @@ static bool is_qflira(goal const & g) { class is_qflira_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_qflira(g); } }; @@ -344,14 +344,14 @@ static bool is_mip(goal const & g) { class is_ilp_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_ilp(g); } }; class is_mip_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_mip(g); } }; @@ -583,56 +583,56 @@ struct is_non_qfufnra_functor { class is_qfnia_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_qfnia(g); } }; class is_qfnra_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_qfnra(g); } }; class is_nia_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_nia(g); } }; class is_nra_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_nra(g); } }; class is_nira_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_nira(g); } }; class is_lia_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_lia(g); } }; class is_lra_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_lra(g); } }; class is_lira_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_lira(g); } }; @@ -644,7 +644,7 @@ static bool is_qfufnra(goal const& g) { class is_qfufnra_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return is_qfufnra(g); } }; diff --git a/src/tactic/arith/propagate_ineqs_tactic.cpp b/src/tactic/arith/propagate_ineqs_tactic.cpp index d7209740f..cbb29f6b4 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.cpp +++ b/src/tactic/arith/propagate_ineqs_tactic.cpp @@ -43,18 +43,18 @@ class propagate_ineqs_tactic : public tactic { public: propagate_ineqs_tactic(ast_manager & m, params_ref const & p); - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(propagate_ineqs_tactic, m, m_params); } - virtual ~propagate_ineqs_tactic(); + ~propagate_ineqs_tactic() override; - virtual void updt_params(params_ref const & p); - virtual void collect_param_descrs(param_descrs & r) {} + void updt_params(params_ref const & p) override; + void collect_param_descrs(param_descrs & r) override {} - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); + void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override; - virtual void cleanup(); + void cleanup() override; }; tactic * mk_propagate_ineqs_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 7e89794ce..38ea0a2b9 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -802,18 +802,18 @@ public: m_params(p) { } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(purify_arith_tactic, m, m_params); } - virtual ~purify_arith_tactic() { + ~purify_arith_tactic() override { } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("complete", CPK_BOOL, "(default: true) add constraints to make sure that any interpretation of a underspecified arithmetic operators is a function. The result will include additional uninterpreted functions/constants: /0, div0, mod0, 0^0, neg-root"); r.insert("elim_root_objects", CPK_BOOL, @@ -823,11 +823,11 @@ public: th_rewriter::get_param_descrs(r); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; @@ -852,7 +852,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { } }; diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index d3b9ecc3e..cf2beacb2 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -390,29 +390,29 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(recover_01_tactic, m, m_params); } - virtual ~recover_01_tactic() { + ~recover_01_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { th_rewriter::get_param_descrs(r); r.insert("recover_01_max_bits", CPK_UINT, "(default: 10) maximum number of bits to consider in a clause."); } - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + expr_dependency_ref & core) override { try { (*m_imp)(g, result, mc, pc, core); } @@ -421,7 +421,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m, m_params); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 373cf3113..2a1ddcd4a 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -46,7 +46,7 @@ struct bit_blaster_model_converter : public model_converter { } } - virtual ~bit_blaster_model_converter() { + ~bit_blaster_model_converter() override { } void collect_bits(obj_hashtable & bits) { @@ -142,7 +142,7 @@ struct bit_blaster_model_converter : public model_converter { } } - virtual void operator()(model_ref & md, unsigned goal_idx) { + void operator()(model_ref & md, unsigned goal_idx) override { SASSERT(goal_idx == 0); model * new_model = alloc(model, m()); obj_hashtable bits; @@ -152,11 +152,11 @@ struct bit_blaster_model_converter : public model_converter { md = new_model; } - virtual void operator()(model_ref & md) { + void operator()(model_ref & md) override { operator()(md, 0); } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(bit-blaster-model-converter"; unsigned sz = m_vars.size(); for (unsigned i = 0; i < sz; i++) { @@ -171,7 +171,7 @@ protected: bit_blaster_model_converter(ast_manager & m):m_vars(m), m_bits(m) { } public: - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { bit_blaster_model_converter * res = alloc(bit_blaster_model_converter, translator.to()); for (unsigned i = 0; i < m_vars.size(); i++) res->m_vars.push_back(translator(m_vars[i].get())); diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 5c6c43778..a44f32044 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -111,21 +111,21 @@ public: m_imp = alloc(imp, m, m_rewriter, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { SASSERT(!m_rewriter); // assume translation isn't used where rewriter is external. return alloc(bit_blaster_tactic, m, 0, m_params); } - virtual ~bit_blaster_tactic() { + ~bit_blaster_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); r.insert("blast_mul", CPK_BOOL, "(default: true) bit-blast multipliers (and dividers, remainders)."); @@ -134,11 +134,11 @@ public: r.insert("blast_full", CPK_BOOL, "(default: false) bit-blast any term with bit-vector sort, this option will make E-matching ineffective in any pattern containing bit-vector terms."); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { (*m_imp)(g, result, mc, pc, core); } @@ -147,7 +147,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m(), m_rewriter, m_params); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index e7e374184..196835c51 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -426,20 +426,20 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(bv1_blaster_tactic, m, m_params); } - virtual ~bv1_blaster_tactic() { + ~bv1_blaster_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->m_rw.cfg().updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); } @@ -454,15 +454,15 @@ public: It also does not support quantifiers. Return a model_converter that converts any model for the updated set into a model for the old set. */ - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(g, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m(), m_params); std::swap(d, m_imp); dealloc(d); @@ -480,7 +480,7 @@ tactic * mk_bv1_blaster_tactic(ast_manager & m, params_ref const & p) { class is_qfbv_eq_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { bv1_blaster_tactic t(g.m()); return t.is_target(g); diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index b71b44bd0..2d717c0ae 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -111,7 +111,7 @@ struct bv_bound_chk_rewriter : public rewriter_tpl { updt_params(p); } - virtual ~bv_bound_chk_rewriter() {} + ~bv_bound_chk_rewriter() override {} void updt_params(params_ref const & _p) { m_cfg.updt_params(_p); @@ -135,17 +135,17 @@ class bv_bound_chk_tactic : public tactic { bv_bound_chk_stats m_stats; public: bv_bound_chk_tactic(ast_manager & m, params_ref const & p); - virtual ~bv_bound_chk_tactic(); + ~bv_bound_chk_tactic() override; void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core); - virtual tactic * translate(ast_manager & m); - virtual void updt_params(params_ref const & p); - void cleanup(); - void collect_statistics(statistics & st) const; - void reset_statistics(); + expr_dependency_ref & core) override; + tactic * translate(ast_manager & m) override; + void updt_params(params_ref const & p) override; + void cleanup() override; + void collect_statistics(statistics & st) const override; + void reset_statistics() override; }; class bv_bound_chk_tactic::imp { diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index a279e441b..0628b4013 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -305,7 +305,7 @@ namespace { updt_params(p); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_propagate_eq = p.get_bool("propagate_eq", false); } @@ -313,7 +313,7 @@ namespace { r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); } - virtual ~bv_bounds_simplifier() { + ~bv_bounds_simplifier() override { for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { dealloc(m_expr_vars[i]); } @@ -322,7 +322,7 @@ namespace { } } - virtual bool assert_expr(expr * t, bool sign) { + bool assert_expr(expr * t, bool sign) override { while (m.is_not(t, t)) { sign = !sign; } @@ -353,7 +353,7 @@ namespace { return true; } - virtual bool simplify(expr* t, expr_ref& result) { + bool simplify(expr* t, expr_ref& result) override { expr* t1; interval b; @@ -465,7 +465,7 @@ namespace { return false; } - virtual bool may_simplify(expr* t) { + bool may_simplify(expr* t) override { if (m_bv.is_numeral(t)) return false; @@ -504,7 +504,7 @@ namespace { return false; } - virtual void pop(unsigned num_scopes) { + void pop(unsigned num_scopes) override { TRACE("bv", tout << "pop: " << num_scopes << "\n";); if (m_scopes.empty()) return; @@ -526,11 +526,11 @@ namespace { m_scopes.shrink(target); } - virtual simplifier * translate(ast_manager & m) { + simplifier * translate(ast_manager & m) override { return alloc(bv_bounds_simplifier, m, m_params); } - virtual unsigned scope_level() const { + unsigned scope_level() const override { return m_scopes.size(); } }; @@ -622,7 +622,7 @@ namespace { r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); } - virtual ~dom_bv_bounds_simplifier() { + ~dom_bv_bounds_simplifier() override { for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { dealloc(m_expr_vars[i]); } @@ -631,7 +631,7 @@ namespace { } } - virtual bool assert_expr(expr * t, bool sign) { + bool assert_expr(expr * t, bool sign) override { while (m.is_not(t, t)) { sign = !sign; } @@ -662,7 +662,7 @@ namespace { return true; } - virtual void operator()(expr_ref& r) { + void operator()(expr_ref& r) override { expr* t1, * t = r; interval b; @@ -781,7 +781,7 @@ namespace { return false; } - virtual void pop(unsigned num_scopes) { + void pop(unsigned num_scopes) override { TRACE("bv", tout << "pop: " << num_scopes << "\n";); if (m_scopes.empty()) return; @@ -803,11 +803,11 @@ namespace { m_scopes.shrink(target); } - virtual dom_simplifier * translate(ast_manager & m) { + dom_simplifier * translate(ast_manager & m) override { return alloc(dom_bv_bounds_simplifier, m, m_params); } - virtual unsigned scope_level() const { + unsigned scope_level() const override { return m_scopes.size(); } diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index ec4c21fe8..2c70e554f 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -34,15 +34,15 @@ class bv_size_reduction_tactic : public tactic { public: bv_size_reduction_tactic(ast_manager & m); - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(bv_size_reduction_tactic, m); } - virtual ~bv_size_reduction_tactic(); + ~bv_size_reduction_tactic() override; - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); + void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override; - virtual void cleanup(); + void cleanup() override; }; tactic * mk_bv_size_reduction_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index 87f43ae8d..844d64429 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -113,32 +113,32 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(bvarray2uf_tactic, m, m_params); } - virtual ~bvarray2uf_tactic() { + ~bvarray2uf_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_produce_models(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m(); imp * d = alloc(imp, m, m_params); std::swap(d, m_imp); diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index fe59480e7..62093d191 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -95,8 +95,8 @@ class dt2bv_tactic : public tactic { struct sort_pred : public i_sort_pred { dt2bv_tactic& m_t; sort_pred(dt2bv_tactic& t): m_t(t) {} - virtual ~sort_pred() {} - virtual bool operator()(sort* s) { + ~sort_pred() override {} + bool operator()(sort* s) override { return m_t.m_fd_sorts.contains(s); } }; @@ -107,21 +107,21 @@ public: dt2bv_tactic(ast_manager& m, params_ref const& p): m(m), m_params(p), m_dt(m), m_bv(m), m_is_fd(*this) {} - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(dt2bv_tactic, m, m_params); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { mc = 0; pc = 0; core = 0; bool produce_proofs = g->proofs_enabled(); tactic_report report("dt2bv", *g); @@ -177,7 +177,7 @@ public: SASSERT(g->is_well_sorted()); } - virtual void cleanup() { + void cleanup() override { m_fd_sorts.reset(); m_non_fd_sorts.reset(); } diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index ab4b3920d..f5f0c2b88 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -268,34 +268,34 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(elim_small_bv_tactic, m, m_params); } - virtual ~elim_small_bv_tactic() { + ~elim_small_bv_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->m_rw.cfg().updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); r.insert("max_bits", CPK_UINT, "(default: 4) maximum bit-vector size of quantified bit-vectors to be eliminated."); } - virtual void operator()(goal_ref const & in, + void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; m_imp->~imp(); m_imp = new (m_imp) imp(m, m_params); diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index becaed276..0b7d0d345 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -278,35 +278,35 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(max_bv_sharing_tactic, m, m_params); } - virtual ~max_bv_sharing_tactic() { + ~max_bv_sharing_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->m_rw.cfg().updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); r.insert("max_args", CPK_UINT, "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m(); params_ref p = std::move(m_params); m_imp->~imp(); diff --git a/src/tactic/converter.h b/src/tactic/converter.h index 9de8218c3..924971d27 100644 --- a/src/tactic/converter.h +++ b/src/tactic/converter.h @@ -58,16 +58,16 @@ protected: public: concat_converter(T * c1, T * c2):m_c1(c1), m_c2(c2) {} - virtual ~concat_converter() {} + ~concat_converter() override {} - virtual void cancel() { + void cancel() override { m_c2->cancel(); m_c1->cancel(); } virtual char const * get_name() const = 0; - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(" << get_name() << "\n"; m_c1->display(out); m_c2->display(out); @@ -104,7 +104,7 @@ public: } } - virtual ~concat_star_converter() { + ~concat_star_converter() override { unsigned sz = m_c2s.size(); for (unsigned i = 0; i < sz; i++) { T * c2 = m_c2s[i]; @@ -113,7 +113,7 @@ public: } } - virtual void cancel() { + void cancel() override { if (m_c1) m_c1->cancel(); unsigned num = m_c2s.size(); @@ -125,7 +125,7 @@ public: virtual char const * get_name() const = 0; - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(" << get_name() << "\n"; if (m_c1) m_c1->display(out); diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index ae0ea019b..27d907b63 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -152,35 +152,35 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(blast_term_ite_tactic, m, m_params); } - virtual ~blast_term_ite_tactic() { + ~blast_term_ite_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->m_rw.cfg().updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); r.insert("max_args", CPK_UINT, "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; dealloc(m_imp); m_imp = alloc(imp, m, m_params); diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index 65cdef147..64c2c0f66 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -46,19 +46,19 @@ public: m_elim_ite(m, p) { } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(cofactor_term_ite_tactic, m, m_params); } - virtual ~cofactor_term_ite_tactic() {} - virtual void updt_params(params_ref const & p) { m_params = p; m_elim_ite.updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_elim_ite.collect_param_descrs(r); } + ~cofactor_term_ite_tactic() override {} + void updt_params(params_ref const & p) override { m_params = p; m_elim_ite.updt_params(p); } + void collect_param_descrs(param_descrs & r) override { m_elim_ite.collect_param_descrs(r); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); fail_if_proof_generation("cofactor-term-ite", g); fail_if_unsat_core_generation("cofactor-term-ite", g); @@ -71,7 +71,7 @@ public: SASSERT(g->is_well_sorted()); } - virtual void cleanup() { return m_elim_ite.cleanup(); } + void cleanup() override { return m_elim_ite.cleanup(); } }; diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 26f6842e3..166fb6036 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -51,21 +51,21 @@ public: m_params(p) { } - virtual ~collect_statistics_tactic() {} + ~collect_statistics_tactic() override {} - virtual tactic * translate(ast_manager & m_) { + tactic * translate(ast_manager & m_) override { return alloc(collect_statistics_tactic, m_, m_params); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; } - virtual void collect_param_descrs(param_descrs & r) {} + void collect_param_descrs(param_descrs & r) override {} - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, - model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, + expr_dependency_ref & core) override { mc = 0; tactic_report report("collect-statistics", *g); @@ -86,13 +86,13 @@ public: result.push_back(g.get()); } - virtual void cleanup() {} + void cleanup() override {} - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { } - virtual void reset_statistics() { reset(); } - virtual void reset() { cleanup(); } + void reset_statistics() override { reset(); } + void reset() override { cleanup(); } protected: class collect_proc { diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 5bb54073d..89bdcca1c 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -33,13 +33,13 @@ class ctx_propagate_assertions : public ctx_simplify_tactic::simplifier { void assert_eq_core(expr * t, app * val); public: ctx_propagate_assertions(ast_manager& m); - virtual ~ctx_propagate_assertions() {} - virtual bool assert_expr(expr * t, bool sign); - virtual bool simplify(expr* t, expr_ref& result); + ~ctx_propagate_assertions() override {} + bool assert_expr(expr * t, bool sign) override; + bool simplify(expr* t, expr_ref& result) override; void push(); - virtual void pop(unsigned num_scopes); - virtual unsigned scope_level() const { return m_scopes.size(); } - virtual simplifier * translate(ast_manager & m); + void pop(unsigned num_scopes) override; + unsigned scope_level() const override { return m_scopes.size(); } + simplifier * translate(ast_manager & m) override; }; diff --git a/src/tactic/core/ctx_simplify_tactic.h b/src/tactic/core/ctx_simplify_tactic.h index 9efa7e7db..e84a5fccc 100644 --- a/src/tactic/core/ctx_simplify_tactic.h +++ b/src/tactic/core/ctx_simplify_tactic.h @@ -46,21 +46,21 @@ protected: public: ctx_simplify_tactic(ast_manager & m, simplifier* simp, params_ref const & p = params_ref()); - virtual tactic * translate(ast_manager & m); + tactic * translate(ast_manager & m) override; - virtual ~ctx_simplify_tactic(); + ~ctx_simplify_tactic() override; - virtual void updt_params(params_ref const & p); + void updt_params(params_ref const & p) override; static void get_param_descrs(param_descrs & r); - virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } + void collect_param_descrs(param_descrs & r) override { get_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core); + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override; - virtual void cleanup(); + void cleanup() override; }; tactic * mk_ctx_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()); diff --git a/src/tactic/core/der_tactic.cpp b/src/tactic/core/der_tactic.cpp index 5df009969..d4c20a065 100644 --- a/src/tactic/core/der_tactic.cpp +++ b/src/tactic/core/der_tactic.cpp @@ -65,26 +65,26 @@ public: m_imp = alloc(imp, m); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(der_tactic, m); } - virtual ~der_tactic() { + ~der_tactic() override { dealloc(m_imp); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { mc = 0; pc = 0; core = 0; (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m(); imp * d = alloc(imp, m); std::swap(d, m_imp); diff --git a/src/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp index 3ee2697c4..9a5ef0c48 100644 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ b/src/tactic/core/distribute_forall_tactic.cpp @@ -95,15 +95,15 @@ class distribute_forall_tactic : public tactic { public: distribute_forall_tactic():m_rw(0) {} - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(distribute_forall_tactic); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); ast_manager & m = g->m(); bool produce_proofs = g->proofs_enabled(); @@ -134,7 +134,7 @@ public: m_rw = 0; } - virtual void cleanup() {} + void cleanup() override {} }; tactic * mk_distribute_forall_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 56eea8d9a..2b114bb71 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -130,20 +130,20 @@ public: m_dominators(m), m_depth(0), m_max_depth(1024), m_forward(true) {} - virtual ~dom_simplify_tactic(); + ~dom_simplify_tactic() override; - virtual tactic * translate(ast_manager & m); - virtual void updt_params(params_ref const & p) {} + tactic * translate(ast_manager & m) override; + void updt_params(params_ref const & p) override {} static void get_param_descrs(param_descrs & r) {} - virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } + void collect_param_descrs(param_descrs & r) override { get_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core); + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override; - virtual void cleanup(); + void cleanup() override; }; class expr_substitution_simplifier : public dom_simplifier { @@ -160,18 +160,18 @@ class expr_substitution_simplifier : public dom_simplifier { public: expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst), m_trail(m) {} - virtual ~expr_substitution_simplifier() {} - virtual bool assert_expr(expr * t, bool sign); + ~expr_substitution_simplifier() override {} + bool assert_expr(expr * t, bool sign) override; void update_substitution(expr* n, proof* pr); - virtual void operator()(expr_ref& r) { r = m_scoped_substitution.find(r); } + void operator()(expr_ref& r) override { r = m_scoped_substitution.find(r); } - virtual void pop(unsigned num_scopes) { m_scoped_substitution.pop(num_scopes); } + void pop(unsigned num_scopes) override { m_scoped_substitution.pop(num_scopes); } - virtual unsigned scope_level() const { return m_scoped_substitution.scope_level(); } + unsigned scope_level() const override { return m_scoped_substitution.scope_level(); } - virtual dom_simplifier * translate(ast_manager & m) { + dom_simplifier * translate(ast_manager & m) override { SASSERT(m_subst.empty()); return alloc(expr_substitution_simplifier, m); } diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 79526a101..522aa90c6 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -141,35 +141,35 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(elim_term_ite_tactic, m, m_params); } - virtual ~elim_term_ite_tactic() { + ~elim_term_ite_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->m_rw.cfg().updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); r.insert("max_args", CPK_UINT, "(default: 128) maximum number of arguments (per application) that will be considered by the greedy (quadratic) heuristic."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; m_imp->~imp(); m_imp = new (m_imp) imp(m, m_params); diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 6a38f787e..a702ab18f 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -915,34 +915,34 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(elim_uncnstr_tactic, m, m_params); } - virtual ~elim_uncnstr_tactic() { + ~elim_uncnstr_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_max_steps(r); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(g, result, mc, pc, core); report_tactic_progress(":num-elim-apps", get_num_elim_apps()); } - virtual void cleanup() { + void cleanup() override { unsigned num_elim_apps = get_num_elim_apps(); ast_manager & m = m_imp->m_manager; imp * d = alloc(imp, m, m_params); @@ -955,11 +955,11 @@ public: return m_imp->m_num_elim_apps; } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.update("eliminated applications", get_num_elim_apps()); } - virtual void reset_statistics() { + void reset_statistics() override { m_imp->m_num_elim_apps = 0; } diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp index 7d90a2155..e4c6408bd 100644 --- a/src/tactic/core/injectivity_tactic.cpp +++ b/src/tactic/core/injectivity_tactic.cpp @@ -250,31 +250,31 @@ public: m_eq = alloc(rewriter_eq, m, *m_map, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(injectivity_tactic, m, m_params); } - virtual ~injectivity_tactic() { + ~injectivity_tactic() override { dealloc(m_finder); dealloc(m_eq); dealloc(m_map); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_finder->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_produce_models(r); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_finder)(g, result, mc, pc, core); for (unsigned i = 0; i < g->size(); ++i) { @@ -287,7 +287,7 @@ public: result.push_back(g.get()); } - virtual void cleanup() { + void cleanup() override { InjHelper * m = alloc(InjHelper, m_manager); finder * f = alloc(finder, m_manager, *m, m_params); rewriter_eq * r = alloc(rewriter_eq, m_manager, *m, m_params); diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index 6b360e711..1f2454d5e 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -43,21 +43,21 @@ public: TRACE("nnf", tout << "nnf_tactic constructor: " << p << "\n";); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(nnf_tactic, m_params); } - virtual ~nnf_tactic() {} + ~nnf_tactic() override {} - virtual void updt_params(params_ref const & p) { m_params = p; } + void updt_params(params_ref const & p) override { m_params = p; } - virtual void collect_param_descrs(param_descrs & r) { nnf::get_param_descrs(r); } + void collect_param_descrs(param_descrs & r) override { nnf::get_param_descrs(r); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { TRACE("nnf", tout << "params: " << m_params << "\n"; g->display(tout);); SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; @@ -106,7 +106,7 @@ public: SASSERT(g->is_well_sorted()); } - virtual void cleanup() {} + void cleanup() override {} }; tactic * mk_snf_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index 254f8166c..69e5e8fb2 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -199,26 +199,26 @@ public: m_imp = alloc(imp, m); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(occf_tactic, m); } - virtual ~occf_tactic() { + ~occf_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) {} - virtual void collect_param_descrs(param_descrs & r) {} + void updt_params(params_ref const & p) override {} + void collect_param_descrs(param_descrs & r) override {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 6a0d7205b..5f128d378 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -48,7 +48,7 @@ class pb_preproc_model_converter : public model_converter { public: pb_preproc_model_converter(ast_manager& m):m(m), pb(m), m_refs(m) {} - virtual void operator()(model_ref & mdl, unsigned goal_idx) { + void operator()(model_ref & mdl, unsigned goal_idx) override { SASSERT(goal_idx == 0); for (unsigned i = 0; i < m_const.size(); ++i) { mdl->register_decl(m_const[i].first->get_decl(), m_const[i].second); @@ -63,7 +63,7 @@ public: set_value_p(to_app(e), p?m.mk_true():m.mk_false()); } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { pb_preproc_model_converter* mc = alloc(pb_preproc_model_converter, translator.to()); for (unsigned i = 0; i < m_const.size(); ++i) { mc->set_value_p(translator(m_const[i].first), translator(m_const[i].second)); @@ -136,18 +136,17 @@ public: pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): m(m), pb(m), m_r(m) {} - virtual ~pb_preprocess_tactic() {} + ~pb_preprocess_tactic() override {} - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(pb_preprocess_tactic, m); } - virtual void operator()( - goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); pc = 0; core = 0; @@ -262,15 +261,15 @@ public: return m_progress; } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { } - virtual void cleanup() { + void cleanup() override { } private: - void reset() { + void reset() override { m_ge.reset(); m_other.reset(); m_vars.reset(); diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 607ecbd79..39333226b 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -222,29 +222,29 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(propagate_values_tactic, m, m_params); } - virtual ~propagate_values_tactic() { + ~propagate_values_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { th_rewriter::get_param_descrs(r); r.insert("max_rounds", CPK_UINT, "(default: 2) maximum number of rounds."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { (*m_imp)(in, result, mc, pc, core); } @@ -253,7 +253,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; params_ref p = std::move(m_params); m_imp->~imp(); diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index 476c21232..a7aadedbe 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -68,14 +68,14 @@ class reduce_args_tactic : public tactic { public: reduce_args_tactic(ast_manager & m); - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(reduce_args_tactic, m); } - virtual ~reduce_args_tactic(); + ~reduce_args_tactic() override; - virtual void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); - virtual void cleanup(); + void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override; + void cleanup() override; }; tactic * mk_reduce_args_tactic(ast_manager & m, params_ref const & p) { diff --git a/src/tactic/core/simplify_tactic.h b/src/tactic/core/simplify_tactic.h index 1e8420c62..c780ceabd 100644 --- a/src/tactic/core/simplify_tactic.h +++ b/src/tactic/core/simplify_tactic.h @@ -28,23 +28,23 @@ class simplify_tactic : public tactic { params_ref m_params; public: simplify_tactic(ast_manager & m, params_ref const & ref = params_ref()); - virtual ~simplify_tactic(); + ~simplify_tactic() override; - virtual void updt_params(params_ref const & p); + void updt_params(params_ref const & p) override; static void get_param_descrs(param_descrs & r); - virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } + void collect_param_descrs(param_descrs & r) override { get_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core); - - virtual void cleanup(); + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override; + + void cleanup() override; unsigned get_num_steps() const; - virtual tactic * translate(ast_manager & m) { return alloc(simplify_tactic, m, m_params); } + tactic * translate(ast_manager & m) override { return alloc(simplify_tactic, m, m_params); } }; diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 5df523ff7..a6346185f 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -790,35 +790,35 @@ public: m_imp = alloc(imp, m, p, r, owner); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(solve_eqs_tactic, m, m_params, mk_expr_simp_replacer(m, m_params), true); } - virtual ~solve_eqs_tactic() { + ~solve_eqs_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("solve_eqs_max_occs", CPK_UINT, "(default: infty) maximum number of occurrences for considering a variable for gaussian eliminations."); r.insert("theory_solver", CPK_BOOL, "(default: true) use theory solvers."); r.insert("ite_solver", CPK_BOOL, "(default: true) use if-then-else solver."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); report_tactic_progress(":num-elim-vars", m_imp->get_num_eliminated_vars()); } - virtual void cleanup() { + void cleanup() override { unsigned num_elim_vars = m_imp->m_num_eliminated_vars; ast_manager & m = m_imp->m(); expr_replacer * r = m_imp->m_r; @@ -833,11 +833,11 @@ public: dealloc(d); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.update("eliminated vars", m_imp->get_num_eliminated_vars()); } - virtual void reset_statistics() { + void reset_statistics() override { m_imp->m_num_eliminated_vars = 0; } diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index 7a2df81b5..5986ca392 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -55,12 +55,12 @@ class split_clause_tactic : public tactic { m.inc_ref(pr); } - ~split_pc() { + ~split_pc() override { m_manager.dec_ref(m_clause); m_manager.dec_ref(m_clause_pr); } - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) override { // Let m_clause be of the form (l_0 or ... or l_{num_source - 1}) // Each source[i] proof is a proof for "false" using l_i as a hypothesis // So, I use lemma for producing a proof for (not l_i) that does not contain the hypothesis, @@ -76,7 +76,7 @@ class split_clause_tactic : public tactic { result = m.mk_unit_resolution(prs.size(), prs.c_ptr()); } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return alloc(split_pc, translator.to(), translator(m_clause), translator(m_clause_pr)); } }; @@ -86,28 +86,28 @@ public: updt_params(ref); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { split_clause_tactic * t = alloc(split_clause_tactic); t->m_largest_clause = m_largest_clause; return t; } - virtual ~split_clause_tactic() { + ~split_clause_tactic() override { } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_largest_clause = p.get_bool("split_largest_clause", false); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("split_largest_clause", CPK_BOOL, "(default: false) split the largest clause in the goal."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { SASSERT(in->is_well_sorted()); tactic_report report("split-clause", *in); TRACE("before_split_clause", in->display(tout);); @@ -140,7 +140,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { // do nothing this tactic is too simple } }; diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index 8e87a6741..1bc3fde60 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -32,18 +32,18 @@ class symmetry_reduce_tactic : public tactic { public: symmetry_reduce_tactic(ast_manager & m); - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(symmetry_reduce_tactic, m); } - virtual ~symmetry_reduce_tactic(); + ~symmetry_reduce_tactic() override; - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core); - virtual void cleanup(); + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override; + void cleanup() override; }; class ac_rewriter { diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index dbfc748b0..af0143488 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -861,20 +861,20 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(tseitin_cnf_tactic, m, m_params); } - virtual ~tseitin_cnf_tactic() { + ~tseitin_cnf_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); r.insert("common_patterns", CPK_BOOL, "(default: true) minimize the number of auxiliary variables during CNF encoding by identifing commonly used patterns"); r.insert("distributivity", CPK_BOOL, "(default: true) minimize the number of auxiliary variables during CNF encoding by applying distributivity over unshared subformulas"); @@ -883,16 +883,16 @@ public: r.insert("ite_extra", CPK_BOOL, "(default: true) add redundant clauses (that improve unit propagation) when encoding if-then-else formulas"); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); report_tactic_progress(":cnf-aux-vars", m_imp->m_num_aux_vars); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; imp * d = alloc(imp, m, m_params); d->m_num_aux_vars = m_imp->m_num_aux_vars; @@ -900,11 +900,11 @@ public: dealloc(d); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.update("cnf encoding aux vars", m_imp->m_num_aux_vars); } - virtual void reset_statistics() { + void reset_statistics() override { m_imp->m_num_aux_vars = 0; } }; diff --git a/src/tactic/equiv_proof_converter.h b/src/tactic/equiv_proof_converter.h index 79f5142b2..12cd26215 100644 --- a/src/tactic/equiv_proof_converter.h +++ b/src/tactic/equiv_proof_converter.h @@ -33,13 +33,13 @@ public: equiv_proof_converter(ast_manager& m): m(m), m_replace(m) {} - virtual ~equiv_proof_converter() {} + ~equiv_proof_converter() override {} - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) override { m_replace(m, num_source, source, result); } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return m_replace.translate(translator); } diff --git a/src/tactic/extension_model_converter.h b/src/tactic/extension_model_converter.h index dbd7a7e3b..bc1a2699d 100644 --- a/src/tactic/extension_model_converter.h +++ b/src/tactic/extension_model_converter.h @@ -31,18 +31,18 @@ public: extension_model_converter(ast_manager & m):m_vars(m), m_defs(m) { } - virtual ~extension_model_converter(); + ~extension_model_converter() override; ast_manager & m() const { return m_vars.get_manager(); } - virtual void operator()(model_ref & md, unsigned goal_idx); + void operator()(model_ref & md, unsigned goal_idx) override; - virtual void display(std::ostream & out); + void display(std::ostream & out) override; // register a variable that was eliminated void insert(func_decl * v, expr * def); - virtual model_converter * translate(ast_translation & translator); + model_converter * translate(ast_translation & translator) override; }; diff --git a/src/tactic/filter_model_converter.h b/src/tactic/filter_model_converter.h index b5d6b86f4..012c43fb6 100644 --- a/src/tactic/filter_model_converter.h +++ b/src/tactic/filter_model_converter.h @@ -26,25 +26,25 @@ class filter_model_converter : public model_converter { public: filter_model_converter(ast_manager & m):m_decls(m) {} - virtual ~filter_model_converter(); + ~filter_model_converter() override; ast_manager & m() const { return m_decls.get_manager(); } - virtual void operator()(model_ref & md, unsigned goal_idx); + void operator()(model_ref & md, unsigned goal_idx) override; virtual void operator()(svector & labels, unsigned goal_idx); - virtual void operator()(model_ref & md) { operator()(md, 0); } // TODO: delete + void operator()(model_ref & md) override { operator()(md, 0); } // TODO: delete - virtual void cancel() {} + void cancel() override {} - virtual void display(std::ostream & out); + void display(std::ostream & out) override; void insert(func_decl * d) { m_decls.push_back(d); } - virtual model_converter * translate(ast_translation & translator); + model_converter * translate(ast_translation & translator) override; }; typedef ref filter_model_converter_ref; diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 989caaa58..cf26f53db 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -33,24 +33,24 @@ public: m_bv2fp(alloc(bv2fpa_converter, m, conv)) { } - virtual ~fpa2bv_model_converter() { + ~fpa2bv_model_converter() override { dealloc(m_bv2fp); } - virtual void operator()(model_ref & md, unsigned goal_idx) { + void operator()(model_ref & md, unsigned goal_idx) override { SASSERT(goal_idx == 0); model * new_model = alloc(model, m); convert(md.get(), new_model); md = new_model; } - virtual void operator()(model_ref & md) { + void operator()(model_ref & md) override { operator()(md, 0); } - void display(std::ostream & out); + void display(std::ostream & out) override; - virtual model_converter * translate(ast_translation & translator); + model_converter * translate(ast_translation & translator) override; protected: fpa2bv_model_converter(ast_manager & m) : diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 6d90b46ea..7cd4a404c 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -123,27 +123,27 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(fpa2bv_tactic, m, m_params); } - virtual ~fpa2bv_tactic() { + ~fpa2bv_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { (*m_imp)(in, result, mc, pc, core); } @@ -152,7 +152,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { imp * d = alloc(imp, m_imp->m, m_params); std::swap(d, m_imp); dealloc(d); diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index cdc363453..1c48fef38 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -66,10 +66,10 @@ struct is_non_fp_qfnra_predicate { class is_fp_qfnra_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return !test(g); } - virtual ~is_fp_qfnra_probe() {} + ~is_fp_qfnra_probe() override {} }; probe * mk_is_fp_qfnra_probe() { @@ -141,11 +141,11 @@ struct is_non_qffp_predicate { class is_qffp_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return !test(g); } - virtual ~is_qffp_probe() {} + ~is_qffp_probe() override {} }; probe * mk_is_qffp_probe() { diff --git a/src/tactic/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h index 1c1ae9feb..5b9c22f17 100644 --- a/src/tactic/horn_subsume_model_converter.h +++ b/src/tactic/horn_subsume_model_converter.h @@ -72,9 +72,9 @@ public: void insert(func_decl* p, expr* body) { m_funcs.push_back(p); m_bodies.push_back(body); } - virtual void operator()(model_ref& _m); + void operator()(model_ref& _m) override; - virtual model_converter * translate(ast_translation & translator); + model_converter * translate(ast_translation & translator) override; ast_manager& get_manager() { return m; } diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 4269946a1..351fbcce7 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -23,25 +23,25 @@ class concat_model_converter : public concat_converter { public: concat_model_converter(model_converter * mc1, model_converter * mc2):concat_converter(mc1, mc2) {} - virtual void operator()(model_ref & m) { + void operator()(model_ref & m) override { this->m_c2->operator()(m); this->m_c1->operator()(m); } - virtual void operator()(model_ref & m, unsigned goal_idx) { + void operator()(model_ref & m, unsigned goal_idx) override { this->m_c2->operator()(m, goal_idx); this->m_c1->operator()(m, 0); } - virtual void operator()(labels_vec & r, unsigned goal_idx) { + void operator()(labels_vec & r, unsigned goal_idx) override { this->m_c2->operator()(r, goal_idx); this->m_c1->operator()(r, 0); } - virtual char const * get_name() const { return "concat-model-converter"; } + char const * get_name() const override { return "concat-model-converter"; } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { return this->translate_core(translator); } }; @@ -60,12 +60,12 @@ public: concat_star_converter(mc1, num, mc2s, szs) { } - virtual void operator()(model_ref & m) { + void operator()(model_ref & m) override { // TODO: delete method after conversion is complete UNREACHABLE(); } - virtual void operator()(model_ref & m, unsigned goal_idx) { + void operator()(model_ref & m, unsigned goal_idx) override { unsigned num = this->m_c2s.size(); for (unsigned i = 0; i < num; i++) { if (goal_idx < this->m_szs[i]) { @@ -83,7 +83,7 @@ public: UNREACHABLE(); } - virtual void operator()(labels_vec & r, unsigned goal_idx) { + void operator()(labels_vec & r, unsigned goal_idx) override { unsigned num = this->m_c2s.size(); for (unsigned i = 0; i < num; i++) { if (goal_idx < this->m_szs[i]) { @@ -101,9 +101,9 @@ public: UNREACHABLE(); } - virtual char const * get_name() const { return "concat-star-model-converter"; } + char const * get_name() const override { return "concat-star-model-converter"; } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { return this->translate_core(translator); } }; @@ -132,30 +132,30 @@ public: model2mc(model * m, buffer const & r):m_model(m), m_labels(r) {} - virtual ~model2mc() {} + ~model2mc() override {} - virtual void operator()(model_ref & m) { + void operator()(model_ref & m) override { m = m_model; } - virtual void operator()(model_ref & m, unsigned goal_idx) { + void operator()(model_ref & m, unsigned goal_idx) override { m = m_model; } - virtual void operator()(labels_vec & r, unsigned goal_idx) { + void operator()(labels_vec & r, unsigned goal_idx) override { r.append(m_labels.size(), m_labels.c_ptr()); } - virtual void cancel() { + void cancel() override { } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(model->model-converter-wrapper\n"; model_v2_pp(out, *m_model); out << ")\n"; } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { model * m = m_model->translate(translator); return alloc(model2mc, m); } diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index c99ea545a..828758caa 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -709,27 +709,27 @@ public: m_asms(m) {} - virtual ~nl_purify_tactic() {} + ~nl_purify_tactic() override {} - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; } - virtual tactic * translate(ast_manager& m) { + tactic * translate(ast_manager& m) override { return alloc(nl_purify_tactic, m, m_params); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { m_nl_tac->collect_statistics(st); m_solver->collect_statistics(st); } - virtual void reset_statistics() { + void reset_statistics() override { m_nl_tac->reset_statistics(); } - virtual void cleanup() { + void cleanup() override { m_solver = mk_smt_solver(m, m_params, symbol::null); m_nl_tac->cleanup(); m_eq_preds.reset(); @@ -744,11 +744,11 @@ public: m_bool2dep.reset(); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { tactic_report report("qfufnl-purify", *g); TRACE("nlsat_smt", g->display(tout);); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 58078e106..7b82772c5 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -65,18 +65,18 @@ public: m_bounds.push_back(alloc(bound_manager, m)); } - virtual ~bounded_int2bv_solver() { + ~bounded_int2bv_solver() override { while (!m_bounds.empty()) { dealloc(m_bounds.back()); m_bounds.pop_back(); } } - virtual solver* translate(ast_manager& m, params_ref const& p) { + solver* translate(ast_manager& m, params_ref const& p) override { return alloc(bounded_int2bv_solver, m, p, m_solver->translate(m, p)); } - virtual void assert_expr(expr * t) { + void assert_expr(expr * t) override { unsigned i = m_assertions.size(); m_assertions.push_back(t); while (i < m_assertions.size()) { @@ -92,14 +92,14 @@ public: } } - virtual void push_core() { + void push_core() override { flush_assertions(); m_solver->push(); m_bv_fns_lim.push_back(m_bv_fns.size()); m_bounds.push_back(alloc(bound_manager, m)); } - virtual void pop_core(unsigned n) { + void pop_core(unsigned n) override { m_assertions.reset(); m_solver->pop(n); @@ -125,31 +125,31 @@ public: } } - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { flush_assertions(); return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } - virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } - virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } - virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model(model_ref & mdl) { + void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver->updt_params(p); } + void collect_param_descrs(param_descrs & r) override { m_solver->collect_param_descrs(r); } + void set_produce_models(bool f) override { m_solver->set_produce_models(f); } + void set_progress_callback(progress_callback * callback) override { m_solver->set_progress_callback(callback); } + void collect_statistics(statistics & st) const override { m_solver->collect_statistics(st); } + void get_unsat_core(ptr_vector & r) override { m_solver->get_unsat_core(r); } + void get_model(model_ref & mdl) override { m_solver->get_model(mdl); if (mdl) { extend_model(mdl); filter_model(mdl); } } - virtual proof * get_proof() { return m_solver->get_proof(); } - virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } - virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } - virtual void get_labels(svector & r) { m_solver->get_labels(r); } - virtual ast_manager& get_manager() const { return m; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + proof * get_proof() override { return m_solver->get_proof(); } + std::string reason_unknown() const override { return m_solver->reason_unknown(); } + void set_reason_unknown(char const* msg) override { m_solver->set_reason_unknown(msg); } + void get_labels(svector & r) override { m_solver->get_labels(r); } + ast_manager& get_manager() const override { return m; } + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { return m_solver->find_mutexes(vars, mutexes); } + lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { flush_assertions(); expr_ref_vector bvars(m); for (unsigned i = 0; i < vars.size(); ++i) { @@ -319,12 +319,12 @@ private: m_rewriter.reset(); } - virtual unsigned get_num_assertions() const { + unsigned get_num_assertions() const override { flush_assertions(); return m_solver->get_num_assertions(); } - virtual expr * get_assertion(unsigned idx) const { + expr * get_assertion(unsigned idx) const override { flush_assertions(); return m_solver->get_assertion(idx); } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index dd0ee7c4b..029914b88 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -47,13 +47,13 @@ public: solver::updt_params(p); } - virtual ~enum2bv_solver() {} + ~enum2bv_solver() override {} - virtual solver* translate(ast_manager& m, params_ref const& p) { + solver* translate(ast_manager& m, params_ref const& p) override { return alloc(enum2bv_solver, m, p, m_solver->translate(m, p)); } - virtual void assert_expr(expr * t) { + void assert_expr(expr * t) override { expr_ref tmp(t, m); expr_ref_vector bounds(m); proof_ref tmp_proof(m); @@ -63,40 +63,40 @@ public: m_solver->assert_expr(bounds); } - virtual void push_core() { + void push_core() override { m_rewriter.push(); m_solver->push(); } - virtual void pop_core(unsigned n) { + void pop_core(unsigned n) override { m_solver->pop(n); m_rewriter.pop(n); } - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } - virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } - virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } - virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model(model_ref & mdl) { + void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver->updt_params(p); } + void collect_param_descrs(param_descrs & r) override { m_solver->collect_param_descrs(r); } + void set_produce_models(bool f) override { m_solver->set_produce_models(f); } + void set_progress_callback(progress_callback * callback) override { m_solver->set_progress_callback(callback); } + void collect_statistics(statistics & st) const override { m_solver->collect_statistics(st); } + void get_unsat_core(ptr_vector & r) override { m_solver->get_unsat_core(r); } + void get_model(model_ref & mdl) override { m_solver->get_model(mdl); if (mdl) { extend_model(mdl); filter_model(mdl); } } - virtual proof * get_proof() { return m_solver->get_proof(); } - virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } - virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } - virtual void get_labels(svector & r) { m_solver->get_labels(r); } - virtual ast_manager& get_manager() const { return m; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + proof * get_proof() override { return m_solver->get_proof(); } + std::string reason_unknown() const override { return m_solver->reason_unknown(); } + void set_reason_unknown(char const* msg) override { m_solver->set_reason_unknown(msg); } + void get_labels(svector & r) override { m_solver->get_labels(r); } + ast_manager& get_manager() const override { return m; } + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { return m_solver->find_mutexes(vars, mutexes); } + lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { datatype_util dt(m); bv_util bv(m); expr_ref_vector bvars(m), conseq(m), bounds(m); @@ -163,11 +163,11 @@ public: ext(mdl, 0); } - virtual unsigned get_num_assertions() const { + unsigned get_num_assertions() const override { return m_solver->get_num_assertions(); } - virtual expr * get_assertion(unsigned idx) const { + expr * get_assertion(unsigned idx) const override { return m_solver->get_assertion(idx); } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index a06ff77c0..8339272b1 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -42,55 +42,55 @@ public: solver::updt_params(p); } - virtual ~pb2bv_solver() {} + ~pb2bv_solver() override {} - virtual solver* translate(ast_manager& m, params_ref const& p) { + solver* translate(ast_manager& m, params_ref const& p) override { return alloc(pb2bv_solver, m, p, m_solver->translate(m, p)); } - virtual void assert_expr(expr * t) { + void assert_expr(expr * t) override { m_assertions.push_back(t); } - virtual void push_core() { + void push_core() override { flush_assertions(); m_rewriter.push(); m_solver->push(); } - virtual void pop_core(unsigned n) { + void pop_core(unsigned n) override { m_assertions.reset(); m_solver->pop(n); m_rewriter.pop(n); } - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { flush_assertions(); return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } - virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } - virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } - virtual void collect_statistics(statistics & st) const { + void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver->updt_params(p); } + void collect_param_descrs(param_descrs & r) override { m_solver->collect_param_descrs(r); } + void set_produce_models(bool f) override { m_solver->set_produce_models(f); } + void set_progress_callback(progress_callback * callback) override { m_solver->set_progress_callback(callback); } + void collect_statistics(statistics & st) const override { m_rewriter.collect_statistics(st); m_solver->collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model(model_ref & mdl) { + void get_unsat_core(ptr_vector & r) override { m_solver->get_unsat_core(r); } + void get_model(model_ref & mdl) override { m_solver->get_model(mdl); if (mdl) { filter_model(mdl); } } - virtual proof * get_proof() { return m_solver->get_proof(); } - virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } - virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } - virtual void get_labels(svector & r) { m_solver->get_labels(r); } - virtual ast_manager& get_manager() const { return m; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { return m_solver->find_mutexes(vars, mutexes); } - virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + proof * get_proof() override { return m_solver->get_proof(); } + std::string reason_unknown() const override { return m_solver->reason_unknown(); } + void set_reason_unknown(char const* msg) override { m_solver->set_reason_unknown(msg); } + void get_labels(svector & r) override { m_solver->get_labels(r); } + ast_manager& get_manager() const override { return m; } + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { return m_solver->find_mutexes(vars, mutexes); } + lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { flush_assertions(); return m_solver->get_consequences(asms, vars, consequences); } @@ -106,12 +106,12 @@ public: filter(mdl, 0); } - virtual unsigned get_num_assertions() const { + unsigned get_num_assertions() const override { flush_assertions(); return m_solver->get_num_assertions(); } - virtual expr * get_assertion(unsigned idx) const { + expr * get_assertion(unsigned idx) const override { flush_assertions(); return m_solver->get_assertion(idx); } diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 3e77b7abc..aa699695e 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -122,8 +122,8 @@ class smt_strategic_solver_factory : public solver_factory { public: smt_strategic_solver_factory(symbol const & logic):m_logic(logic) {} - virtual ~smt_strategic_solver_factory() {} - virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) { + ~smt_strategic_solver_factory() override {} + solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) override { symbol l; if (m_logic != symbol::null) l = m_logic; diff --git a/src/tactic/probe.cpp b/src/tactic/probe.cpp index 072b866b1..c9863c9b1 100644 --- a/src/tactic/probe.cpp +++ b/src/tactic/probe.cpp @@ -27,7 +27,7 @@ Revision History: class memory_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(static_cast(memory::get_allocation_size())/static_cast(1024*1024)); } }; @@ -38,21 +38,21 @@ probe * mk_memory_probe() { class depth_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(g.depth()); } }; class size_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(g.size()); } }; class num_exprs_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(g.num_exprs()); } }; @@ -79,7 +79,7 @@ public: p->inc_ref(); } - ~unary_probe() { + ~unary_probe() override { m_p->dec_ref(); } @@ -99,7 +99,7 @@ public: p2->inc_ref(); } - ~bin_probe() { + ~bin_probe() override { m_p1->dec_ref(); m_p2->dec_ref(); } @@ -108,7 +108,7 @@ public: class not_probe : public unary_probe { public: not_probe(probe * p):unary_probe(p) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(!m_p->operator()(g).is_true()); } }; @@ -116,7 +116,7 @@ public: class and_probe : public bin_probe { public: and_probe(probe * p1, probe * p2):bin_probe(p1, p2) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_p1->operator()(g).is_true() && m_p2->operator()(g).is_true()); } }; @@ -124,7 +124,7 @@ public: class or_probe : public bin_probe { public: or_probe(probe * p1, probe * p2):bin_probe(p1, p2) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_p1->operator()(g).is_true() || m_p2->operator()(g).is_true()); } }; @@ -132,7 +132,7 @@ public: class eq_probe : public bin_probe { public: eq_probe(probe * p1, probe * p2):bin_probe(p1, p2) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_p1->operator()(g).get_value() == m_p2->operator()(g).get_value()); } }; @@ -140,7 +140,7 @@ public: class le_probe : public bin_probe { public: le_probe(probe * p1, probe * p2):bin_probe(p1, p2) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_p1->operator()(g).get_value() <= m_p2->operator()(g).get_value()); } }; @@ -148,7 +148,7 @@ public: class add_probe : public bin_probe { public: add_probe(probe * p1, probe * p2):bin_probe(p1, p2) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_p1->operator()(g).get_value() + m_p2->operator()(g).get_value()); } }; @@ -156,7 +156,7 @@ public: class sub_probe : public bin_probe { public: sub_probe(probe * p1, probe * p2):bin_probe(p1, p2) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_p1->operator()(g).get_value() - m_p2->operator()(g).get_value()); } }; @@ -164,7 +164,7 @@ public: class mul_probe : public bin_probe { public: mul_probe(probe * p1, probe * p2):bin_probe(p1, p2) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_p1->operator()(g).get_value() * m_p2->operator()(g).get_value()); } }; @@ -172,7 +172,7 @@ public: class div_probe : public bin_probe { public: div_probe(probe * p1, probe * p2):bin_probe(p1, p2) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_p1->operator()(g).get_value() / m_p2->operator()(g).get_value()); } }; @@ -182,7 +182,7 @@ class const_probe : public probe { public: const_probe(double v):m_val(v) {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return result(m_val); } }; @@ -303,7 +303,7 @@ struct is_non_qfbv_predicate { class is_propositional_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return !test(g); } }; @@ -311,7 +311,7 @@ public: class is_qfbv_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return !test(g); } }; @@ -353,7 +353,7 @@ struct is_non_qfaufbv_predicate { class is_qfaufbv_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return !test(g); } }; @@ -391,7 +391,7 @@ struct is_non_qfufbv_predicate { class is_qfufbv_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return !test(g); } }; @@ -442,7 +442,7 @@ public: num_consts_probe(bool b, char const * f): m_bool(b), m_family(f) { } - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { proc p(g.m(), m_bool, m_family); unsigned sz = g.size(); expr_fast_mark1 visited; @@ -471,21 +471,21 @@ probe * mk_num_bv_consts_probe() { class produce_proofs_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return g.proofs_enabled(); } }; class produce_models_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return g.models_enabled(); } }; class produce_unsat_cores_probe : public probe { public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { return g.unsat_core_enabled(); } }; @@ -514,7 +514,7 @@ struct has_pattern_probe : public probe { } }; public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { try { expr_fast_mark1 visited; proc p; @@ -544,7 +544,7 @@ struct has_quantifier_probe : public probe { void operator()(quantifier * n) { throw found(); } }; public: - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { try { expr_fast_mark1 visited; proc p; diff --git a/src/tactic/proof_converter.cpp b/src/tactic/proof_converter.cpp index 095488415..5ac48def0 100644 --- a/src/tactic/proof_converter.cpp +++ b/src/tactic/proof_converter.cpp @@ -23,16 +23,16 @@ class concat_proof_converter : public concat_converter { public: concat_proof_converter(proof_converter * pc1, proof_converter * pc2):concat_converter(pc1, pc2) {} - virtual char const * get_name() const { return "concat-proof-converter"; } + char const * get_name() const override { return "concat-proof-converter"; } - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) override { proof_ref tmp(m); this->m_c2->operator()(m, num_source, source, tmp); proof * new_source = tmp.get(); this->m_c1->operator()(m, 1, &new_source, result); } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return this->translate_core(translator); } }; @@ -51,9 +51,9 @@ public: concat_star_converter(pc1, num, pc2s, szs) { } - virtual char const * get_name() const { return "concat-star-proof-converter"; } + char const * get_name() const override { return "concat-star-proof-converter"; } - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) override { unsigned num = this->m_szs.size(); #ifdef Z3DEBUG unsigned sum = 0; @@ -86,7 +86,7 @@ public: } } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return this->translate_core(translator); } }; @@ -111,18 +111,18 @@ class proof2pc : public proof_converter { proof_ref m_pr; public: proof2pc(ast_manager & m, proof * pr):m_pr(pr, m) {} - virtual ~proof2pc() {} + ~proof2pc() override {} - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) override { SASSERT(num_source == 0); result = m_pr; } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return alloc(proof2pc, translator.to(), translator(m_pr.get())); } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(proof->proof-converter-wrapper\n" << mk_ismt2_pp(m_pr.get(), m_pr.get_manager()) << ")\n"; } }; diff --git a/src/tactic/proof_converter.h b/src/tactic/proof_converter.h index e925436d2..c3a841b31 100644 --- a/src/tactic/proof_converter.h +++ b/src/tactic/proof_converter.h @@ -25,7 +25,7 @@ Notes: class proof_converter : public converter { public: - virtual ~proof_converter() { } + ~proof_converter() override { } virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) = 0; virtual proof_converter * translate(ast_translation & translator) = 0; }; diff --git a/src/tactic/replace_proof_converter.h b/src/tactic/replace_proof_converter.h index b768a18a0..44ba2d82d 100644 --- a/src/tactic/replace_proof_converter.h +++ b/src/tactic/replace_proof_converter.h @@ -32,11 +32,11 @@ public: replace_proof_converter(ast_manager& _m): m(_m), m_proofs(m) {} - virtual ~replace_proof_converter() {} + ~replace_proof_converter() override {} - virtual void operator()(ast_manager & _m, unsigned num_source, proof * const * source, proof_ref & result); + void operator()(ast_manager & _m, unsigned num_source, proof * const * source, proof_ref & result) override; - virtual proof_converter * translate(ast_translation & translator); + proof_converter * translate(ast_translation & translator) override; void insert(proof* p) { m_proofs.push_back(p); } diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index ba35bac84..4aecc0274 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -38,21 +38,21 @@ public: sine_tactic(ast_manager& m, params_ref const& p): m(m), m_params(p) {} - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(sine_tactic, m, m_params); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { mc = 0; pc = 0; core = 0; TRACE("sine", g->display(tout);); @@ -73,7 +73,7 @@ public: mc = fmc; } - virtual void cleanup() { + void cleanup() override { } private: diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index 19937e8b0..aaf4c24c0 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -42,28 +42,28 @@ public: m_engine = alloc(sls_engine, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(sls_tactic, m, m_params); } - virtual ~sls_tactic() { + ~sls_tactic() override { dealloc(m_engine); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_engine->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { sls_params::collect_param_descrs(r); } - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; result.reset(); @@ -78,17 +78,17 @@ public: SASSERT(g->is_well_sorted()); } - virtual void cleanup() { + void cleanup() override { sls_engine * d = alloc(sls_engine, m, m_params); std::swap(d, m_engine); dealloc(d); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { m_engine->collect_statistics(st); } - virtual void reset_statistics() { + void reset_statistics() override { m_engine->reset_statistics(); } diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index 23ae179e2..628555cae 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -36,7 +36,7 @@ Notes: #include "tactic/arith/probe_arith.h" struct quasi_pb_probe : public probe { - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { bool found_non_01 = false; bound_manager bm(g.m()); bm(g); diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index df2791a8f..1d3f251a4 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -51,13 +51,13 @@ public: , m_inc_use_sat(false) {} - virtual ~qfufbv_ackr_tactic() { } + ~qfufbv_ackr_tactic() override { } - virtual void operator()(goal_ref const & g, + void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + expr_dependency_ref & core) override { mc = 0; ast_manager& m(g->m()); tactic_report report("qfufbv_ackr", *g); @@ -84,23 +84,23 @@ public: } } - void updt_params(params_ref const & _p) { + void updt_params(params_ref const & _p) override { qfufbv_tactic_params p(_p); m_use_sat = p.sat_backend(); m_inc_use_sat = p.inc_sat_backend(); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { ackermannization_params p(m_p); if (!p.eager()) st.update("lackr-its", m_st.m_it); st.update("ackr-constraints", m_st.m_ackrs_sz); } - virtual void reset_statistics() { m_st.reset(); } + void reset_statistics() override { m_st.reset(); } - virtual void cleanup() { } + void cleanup() override { } - virtual tactic* translate(ast_manager& m) { + tactic* translate(ast_manager& m) override { return alloc(qfufbv_ackr_tactic, m, m_p); } private: diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 6c4ca7476..7ccd44e7d 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -85,17 +85,17 @@ tactic * mk_skip_tactic() { class fail_tactic : public tactic { public: - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { throw tactic_exception("fail tactic"); } - virtual void cleanup() {} + void cleanup() override {} - virtual tactic * translate(ast_manager & m) { return this; } + tactic * translate(ast_manager & m) override { return this; } }; tactic * mk_fail_tactic() { @@ -108,11 +108,11 @@ class report_verbose_tactic : public skip_tactic { public: report_verbose_tactic(char const * msg, unsigned lvl) : m_msg(msg), m_lvl(lvl) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { IF_VERBOSE(m_lvl, verbose_stream() << m_msg << "\n";); skip_tactic::operator()(in, result, mc, pc, core); } @@ -127,11 +127,11 @@ class trace_tactic : public skip_tactic { public: trace_tactic(char const * tag): m_tag(tag) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { TRACE(m_tag, in->display(tout);); (void)m_tag; skip_tactic::operator()(in, result, mc, pc, core); @@ -146,11 +146,11 @@ class fail_if_undecided_tactic : public skip_tactic { public: fail_if_undecided_tactic() {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { if (!in->is_decided()) throw tactic_exception("undecided"); skip_tactic::operator()(in, result, mc, pc, core); diff --git a/src/tactic/tactic.h b/src/tactic/tactic.h index 0e4c61611..096ce367e 100644 --- a/src/tactic/tactic.h +++ b/src/tactic/tactic.h @@ -119,9 +119,9 @@ void report_tactic_progress(char const * id, unsigned val); class skip_tactic : public tactic { public: - virtual void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core); - virtual void cleanup() {} - virtual tactic * translate(ast_manager & m) { return this; } + void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override; + void cleanup() override {} + tactic * translate(ast_manager & m) override { return this; } }; tactic * mk_skip_tactic(); diff --git a/src/tactic/tactic_exception.h b/src/tactic/tactic_exception.h index e989ed2bf..177524726 100644 --- a/src/tactic/tactic_exception.h +++ b/src/tactic/tactic_exception.h @@ -27,8 +27,8 @@ protected: std::string m_msg; public: tactic_exception(char const * msg):m_msg(msg) {} - virtual ~tactic_exception() {} - virtual char const * msg() const { return m_msg.c_str(); } + ~tactic_exception() override {} + char const * msg() const override { return m_msg.c_str(); } }; #define TACTIC_CANCELED_MSG Z3_CANCELED_MSG diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index c5a70c0db..fe0c7385f 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -39,47 +39,47 @@ public: m_t2->inc_ref(); } - virtual ~binary_tactical() { + ~binary_tactical() override { m_t1->dec_ref(); m_t2->dec_ref(); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_t1->updt_params(p); m_t2->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_t1->collect_param_descrs(r); m_t2->collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { m_t1->collect_statistics(st); m_t2->collect_statistics(st); } - virtual void reset_statistics() { + void reset_statistics() override { m_t1->reset_statistics(); m_t2->reset_statistics(); } - virtual void cleanup() { + void cleanup() override { m_t1->cleanup(); m_t2->cleanup(); } - virtual void reset() { + void reset() override { m_t1->reset(); m_t2->reset(); } - virtual void set_logic(symbol const & l) { + void set_logic(symbol const & l) override { m_t1->set_logic(l); m_t2->set_logic(l); } - virtual void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { m_t1->set_progress_callback(callback); m_t2->set_progress_callback(callback); } @@ -104,13 +104,13 @@ struct false_pred { class and_then_tactical : public binary_tactical { public: and_then_tactical(tactic * t1, tactic * t2):binary_tactical(t1, t2) {} - virtual ~and_then_tactical() {} + ~and_then_tactical() override {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { bool models_enabled = in->models_enabled(); bool proofs_enabled = in->proofs_enabled(); @@ -212,7 +212,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return translate_core(m); } @@ -282,14 +282,14 @@ public: } } - virtual ~nary_tactical() { + ~nary_tactical() override { unsigned sz = m_ts.size(); for (unsigned i = 0; i < sz; i++) { m_ts[i]->dec_ref(); } } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { TRACE("nary_tactical_updt_params", tout << "updt_params: " << p << "\n";); ptr_vector::iterator it = m_ts.begin(); ptr_vector::iterator end = m_ts.end(); @@ -297,49 +297,49 @@ public: (*it)->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { ptr_vector::iterator it = m_ts.begin(); ptr_vector::iterator end = m_ts.end(); for (; it != end; ++it) (*it)->collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { ptr_vector::const_iterator it = m_ts.begin(); ptr_vector::const_iterator end = m_ts.end(); for (; it != end; ++it) (*it)->collect_statistics(st); } - virtual void reset_statistics() { + void reset_statistics() override { ptr_vector::const_iterator it = m_ts.begin(); ptr_vector::const_iterator end = m_ts.end(); for (; it != end; ++it) (*it)->reset_statistics(); } - virtual void cleanup() { + void cleanup() override { ptr_vector::iterator it = m_ts.begin(); ptr_vector::iterator end = m_ts.end(); for (; it != end; ++it) (*it)->cleanup(); } - virtual void reset() { + void reset() override { ptr_vector::iterator it = m_ts.begin(); ptr_vector::iterator end = m_ts.end(); for (; it != end; ++it) (*it)->reset(); } - virtual void set_logic(symbol const & l) { + void set_logic(symbol const & l) override { ptr_vector::iterator it = m_ts.begin(); ptr_vector::iterator end = m_ts.end(); for (; it != end; ++it) (*it)->set_logic(l); } - virtual void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { ptr_vector::iterator it = m_ts.begin(); ptr_vector::iterator end = m_ts.end(); for (; it != end; ++it) @@ -367,13 +367,13 @@ class or_else_tactical : public nary_tactical { public: or_else_tactical(unsigned num, tactic * const * ts):nary_tactical(num, ts) { SASSERT(num > 0); } - virtual ~or_else_tactical() {} + ~or_else_tactical() override {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { goal orig(*(in.get())); unsigned sz = m_ts.size(); unsigned i; @@ -401,7 +401,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { return translate_core(m); } }; tactic * or_else(unsigned num, tactic * const * ts) { @@ -464,15 +464,15 @@ class par_tactical : public or_else_tactical { public: par_tactical(unsigned num, tactic * const * ts):or_else_tactical(num, ts) {} - virtual ~par_tactical() {} + ~par_tactical() override {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { bool use_seq; #ifdef _NO_OMP_ use_seq = true; @@ -572,7 +572,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { return translate_core(m); } }; tactic * par(unsigned num, tactic * const * ts) { @@ -597,13 +597,13 @@ tactic * par(tactic * t1, tactic * t2, tactic * t3, tactic * t4) { class par_and_then_tactical : public and_then_tactical { public: par_and_then_tactical(tactic * t1, tactic * t2):and_then_tactical(t1, t2) {} - virtual ~par_and_then_tactical() {} + ~par_and_then_tactical() override {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { bool use_seq; #ifdef _NO_OMP_ use_seq = true; @@ -862,7 +862,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return translate_core(m); } @@ -895,26 +895,26 @@ public: t->inc_ref(); } - virtual ~unary_tactical() { + ~unary_tactical() override { m_t->dec_ref(); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { m_t->operator()(in, result, mc, pc, core); } - virtual void cleanup(void) { m_t->cleanup(); } - virtual void collect_statistics(statistics & st) const { m_t->collect_statistics(st); } - virtual void reset_statistics() { m_t->reset_statistics(); } - virtual void updt_params(params_ref const & p) { m_t->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_t->collect_param_descrs(r); } - virtual void reset() { m_t->reset(); } - virtual void set_logic(symbol const& l) { m_t->set_logic(l); } - virtual void set_progress_callback(progress_callback * callback) { m_t->set_progress_callback(callback); } + void cleanup(void) override { m_t->cleanup(); } + void collect_statistics(statistics & st) const override { m_t->collect_statistics(st); } + void reset_statistics() override { m_t->reset_statistics(); } + void updt_params(params_ref const & p) override { m_t->updt_params(p); } + void collect_param_descrs(param_descrs & r) override { m_t->collect_param_descrs(r); } + void reset() override { m_t->reset(); } + void set_logic(symbol const& l) override { m_t->set_logic(l); } + void set_progress_callback(progress_callback * callback) override { m_t->set_progress_callback(callback); } protected: template @@ -1056,15 +1056,15 @@ public: m_max_depth(max_depth) { } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { operator()(0, in, result, mc, pc, core); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(repeat_tactical, new_t, m_max_depth); } @@ -1079,11 +1079,11 @@ class fail_if_branching_tactical : public unary_tactical { public: fail_if_branching_tactical(tactic * t, unsigned threshold):unary_tactical(t), m_threshold(threshold) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { m_t->operator()(in, result, mc, pc, core); if (result.size() > m_threshold) { result.reset(); @@ -1094,7 +1094,7 @@ public: } }; - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(fail_if_branching_tactical, new_t, m_threshold); } @@ -1108,16 +1108,16 @@ class cleanup_tactical : public unary_tactical { public: cleanup_tactical(tactic * t):unary_tactical(t) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { m_t->operator()(in, result, mc, pc, core); m_t->cleanup(); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(cleanup_tactical, new_t); } @@ -1132,11 +1132,11 @@ class try_for_tactical : public unary_tactical { public: try_for_tactical(tactic * t, unsigned ts):unary_tactical(t), m_timeout(ts) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { cancel_eh eh(in->m().limit()); { // Warning: scoped_timer is not thread safe in Linux. @@ -1145,7 +1145,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(try_for_tactical, new_t, m_timeout); } @@ -1162,7 +1162,7 @@ public: t->updt_params(p); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { TRACE("using_params", tout << "before p: " << p << "\n"; tout << "m_params: " << m_params << "\n";); @@ -1177,7 +1177,7 @@ public: tout << "new_p: " << new_p << "\n";); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(using_params_tactical, new_t, m_params); } @@ -1202,16 +1202,16 @@ public: annotate_tactical(char const* name, tactic* t): unary_tactical(t), m_name(name) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { scope _scope(m_name); m_t->operator()(in, result, mc, pc, core); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t = m_t->translate(m); return alloc(annotate_tactical, m_name.c_str(), new_t); } @@ -1232,22 +1232,22 @@ public: m_p->inc_ref(); } - ~cond_tactical() { + ~cond_tactical() override { m_p->dec_ref(); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { if (m_p->operator()(*(in.get())).is_true()) m_t1->operator()(in, result, mc, pc, core); else m_t2->operator()(in, result, mc, pc, core); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { tactic * new_t1 = m_t1->translate(m); tactic * new_t2 = m_t2->translate(m); return alloc(cond_tactical, m_p, new_t1, new_t2); @@ -1271,17 +1271,17 @@ public: m_p->inc_ref(); } - ~fail_if_tactic() { + ~fail_if_tactic() override { m_p->dec_ref(); } - void cleanup() {} + void cleanup() override {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { mc = 0; pc = 0; core = 0; @@ -1291,7 +1291,7 @@ public: result.push_back(in.get()); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return this; } }; @@ -1308,11 +1308,11 @@ class if_no_proofs_tactical : public unary_tactical { public: if_no_proofs_tactical(tactic * t):unary_tactical(t) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { if (in->proofs_enabled()) { mc = 0; pc = 0; core = 0; result.reset(); @@ -1323,18 +1323,18 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { return translate_core(m); } }; class if_no_unsat_cores_tactical : public unary_tactical { public: if_no_unsat_cores_tactical(tactic * t):unary_tactical(t) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { if (in->unsat_core_enabled()) { mc = 0; pc = 0; core = 0; result.reset(); @@ -1345,18 +1345,18 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { return translate_core(m); } }; class if_no_models_tactical : public unary_tactical { public: if_no_models_tactical(tactic * t):unary_tactical(t) {} - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { if (in->models_enabled()) { mc = 0; pc = 0; core = 0; result.reset(); @@ -1367,7 +1367,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { return translate_core(m); } }; tactic * if_no_proofs(tactic * t) { @@ -1386,4 +1386,3 @@ tactic * skip_if_failed(tactic * t) { return or_else(t, mk_skip_tactic()); } - diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index 3a482f37c..88b1e6a67 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -97,35 +97,35 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(macro_finder_tactic, m, m_params); } - virtual ~macro_finder_tactic() { + ~macro_finder_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_produce_models(r); insert_produce_proofs(r); r.insert("elim_and", CPK_BOOL, "(default: false) eliminate conjunctions during (internal) calls to the simplifier."); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m(); imp * d = alloc(imp, m, m_params); std::swap(d, m_imp); diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index 925b5a5e3..e9d081c53 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -109,34 +109,34 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(quasi_macros_tactic, m, m_params); } - virtual ~quasi_macros_tactic() { + ~quasi_macros_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_produce_models(r); insert_produce_proofs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m(); imp * d = alloc(imp, m, m_params); std::swap(d, m_imp); diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index 615593317..3dcc6d9a1 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -81,34 +81,34 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(ufbv_rewriter_tactic, m, m_params); } - virtual ~ufbv_rewriter_tactic() { + ~ufbv_rewriter_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); insert_produce_models(r); insert_produce_proofs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m(); imp * d = alloc(imp, m, m_params); std::swap(d, m_imp); diff --git a/src/util/cancel_eh.h b/src/util/cancel_eh.h index 59f11b3f3..09b996582 100644 --- a/src/util/cancel_eh.h +++ b/src/util/cancel_eh.h @@ -30,8 +30,8 @@ class cancel_eh : public event_handler { T & m_obj; public: cancel_eh(T & o): m_canceled(false), m_obj(o) {} - ~cancel_eh() { if (m_canceled) m_obj.dec_cancel(); } - virtual void operator()(event_handler_caller_t caller_id) { + ~cancel_eh() override { if (m_canceled) m_obj.dec_cancel(); } + void operator()(event_handler_caller_t caller_id) override { if (!m_canceled) { m_caller_id = caller_id; m_canceled = true; diff --git a/src/util/z3_exception.h b/src/util/z3_exception.h index 8d0acda28..e3260e89d 100644 --- a/src/util/z3_exception.h +++ b/src/util/z3_exception.h @@ -33,8 +33,8 @@ class z3_error : public z3_exception { unsigned m_error_code; public: z3_error(unsigned error_code); - virtual char const * msg() const; - virtual unsigned error_code() const; + char const * msg() const override; + unsigned error_code() const override; }; class default_exception : public z3_exception { @@ -43,8 +43,8 @@ public: struct fmt {}; default_exception(std::string const& msg); default_exception(fmt, char const* msg, ...); - virtual ~default_exception() {} - virtual char const * msg() const; + ~default_exception() override {} + char const * msg() const override; }; #endif From 5206e29bddccdad63bd61a50d6e3678aa9215a3d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 09:18:05 -0800 Subject: [PATCH 0560/1283] fix wrong check Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index e5dd057bb..259b1550a 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2672,11 +2672,11 @@ namespace sat { return; } - VERIFY(c.size() - c.k() >= sz - k); + VERIFY(!all_units || c.size() - c.k() >= sz - k); c.set_size(sz); c.set_k(k); - if (clausify(c)) { + if (all_units && clausify(c)) { return; } From 4f7b6a2f1801076f89fb1e5f44729b5419136255 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 10:55:31 -0800 Subject: [PATCH 0561/1283] fix missing clear of weights Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 259b1550a..607335055 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -481,6 +481,7 @@ namespace sat { w2 = m_weights[(~l).index()]; if (w1 >= w2) { if (w2 >= k) { + for (literal l2 : lits) m_weights[l2.index()] = 0; // constraint is true return; } @@ -2614,8 +2615,8 @@ namespace sat { // pre-condition is that the literals, except c.lit(), in c are unwatched. if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; - // IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); m_weights.resize(2*s().num_vars(), 0); + for (literal l : c) { ++m_weights[l.index()]; } From f28b158d57ba6a680419edf34986ea89d5a3ef17 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 13:47:55 -0800 Subject: [PATCH 0562/1283] fix another recompilation bug Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 33 ++++++++++++++++++++++++++++++++- src/shell/opt_frontend.cpp | 36 ++++++++++++++++++------------------ 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 607335055..117c9c6f8 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2615,8 +2615,9 @@ namespace sat { // pre-condition is that the literals, except c.lit(), in c are unwatched. if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; + // IF_VERBOSE(0, verbose_stream() << c << "\n";); m_weights.resize(2*s().num_vars(), 0); - + // for (unsigned w : m_weights) VERIFY(w == 0); for (literal l : c) { ++m_weights[l.index()]; } @@ -2673,6 +2674,36 @@ namespace sat { return; } + if (sz == 0) { + if (c.lit() == null_literal) { + if (k > 0) { + s().mk_clause(0, nullptr, true); + } + } + else if (k > 0) { + literal lit = ~c.lit(); + s().mk_clause(1, &lit, c.learned()); + } + else { + literal lit = c.lit(); + s().mk_clause(1, &lit, c.learned()); + } + remove_constraint(c, "recompiled to clause"); + return; + } + if (all_units && sz < k) { + // IF_VERBOSE(0, verbose_stream() << "all units " << sz << " " << k << "\n"); + if (c.lit() == null_literal) { + s().mk_clause(0, nullptr, true); + } + else { + literal lit = ~c.lit(); + s().mk_clause(1, &lit, c.learned()); + } + remove_constraint(c, "recompiled to clause"); + return; + } + // IF_VERBOSE(0, verbose_stream() << "csz: " << c.size() << " ck:" << c.k() << " sz:" << sz << " k:" << k << "\n"); VERIFY(!all_units || c.size() - c.k() >= sz - k); c.set_size(sz); c.set_k(k); diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 9509db760..1d5efdd82 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -29,24 +29,24 @@ static unsigned_vector g_handles; static void display_results() { - if (g_opt) { - model_ref mdl; - g_opt->get_model(mdl); - if (mdl) { - model_smt2_pp(std::cout, g_opt->get_manager(), *mdl, 0); - } - - for (unsigned h : g_handles) { - expr_ref lo = g_opt->get_lower(h); - expr_ref hi = g_opt->get_upper(h); - if (lo == hi) { - std::cout << " " << lo << "\n"; - } - else { - std::cout << " [" << lo << ":" << hi << "]\n"; - } - } - } + IF_VERBOSE(1, + if (g_opt) { + model_ref mdl; + g_opt->get_model(mdl); + if (mdl) { + model_smt2_pp(verbose_stream(), g_opt->get_manager(), *mdl, 0); + } + for (unsigned h : g_handles) { + expr_ref lo = g_opt->get_lower(h); + expr_ref hi = g_opt->get_upper(h); + if (lo == hi) { + std::cout << " " << lo << "\n"; + } + else { + std::cout << " [" << lo << ":" << hi << "]\n"; + } + } + }); } static void display_statistics() { From 18b66a4bd757eca95c227aca4d57d0b3d9ddf036 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 14:20:07 -0800 Subject: [PATCH 0563/1283] fix parameter processing Signed-off-by: Nikolaj Bjorner --- src/shell/opt_frontend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 1d5efdd82..caeff146c 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -104,7 +104,7 @@ static unsigned parse_opt(std::istream& in, opt_format f) { } try { cancel_eh eh(m.limit()); - unsigned timeout = std::stoi(gparams::get_value("timeout")); + unsigned timeout = std::stoul(gparams::get_value("timeout")); unsigned rlimit = std::stoi(gparams::get_value("rlimit")); scoped_timer timer(timeout, &eh); scoped_rlimit _rlimit(m.limit(), rlimit); From 7167fda1dc839b6caa558fe08269988b258b7e93 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 10 Feb 2018 09:15:12 +0700 Subject: [PATCH 0564/1283] Use override rather than virtual. --- .../ackermannize_bv_tactic.cpp | 18 +- src/ackermannization/ackr_bound_probe.cpp | 2 +- src/ackermannization/ackr_model_converter.cpp | 8 +- .../lackr_model_converter_lazy.cpp | 8 +- src/api/api_algebraic.cpp | 6 +- src/api/api_ast_map.h | 2 +- src/api/api_ast_vector.h | 2 +- src/api/api_datalog.cpp | 8 +- src/api/api_datalog.h | 2 +- src/api/api_goal.h | 2 +- src/api/api_model.h | 6 +- src/api/api_opt.cpp | 2 +- src/api/api_solver.h | 2 +- src/api/api_stats.h | 2 +- src/api/api_tactic.h | 6 +- src/api/api_util.h | 4 +- src/ast/ast_trail.h | 2 +- src/interp/iz3proof_itp.cpp | 38 ++--- src/interp/iz3translate.cpp | 4 +- src/interp/iz3translate_direct.cpp | 4 +- src/math/hilbert/heap_trie.h | 16 +- src/math/hilbert/hilbert_basis.cpp | 2 +- src/math/polynomial/algebraic_numbers.cpp | 30 ++-- src/math/polynomial/polynomial.cpp | 12 +- .../upolynomial_factorization_int.h | 2 +- src/math/realclosure/realclosure.cpp | 4 +- src/math/subpaving/subpaving.cpp | 64 +++---- src/math/subpaving/subpaving_t_def.h | 6 +- .../subpaving/tactic/subpaving_tactic.cpp | 26 +-- src/muz/base/dl_context.cpp | 16 +- src/muz/base/dl_context.h | 6 +- src/muz/base/dl_util.cpp | 6 +- src/muz/bmc/dl_bmc_engine.h | 14 +- src/muz/clp/clp_context.h | 12 +- src/muz/ddnf/ddnf.h | 12 +- src/muz/duality/duality_dl_interface.h | 28 +-- src/muz/fp/datalog_parser.cpp | 8 +- src/muz/fp/dl_cmds.cpp | 84 ++++----- src/muz/fp/dl_register_engine.h | 4 +- src/muz/fp/horn_tactic.cpp | 24 +-- src/muz/pdr/pdr_dl_interface.h | 24 +-- src/muz/pdr/pdr_generalizers.h | 30 ++-- src/muz/pdr/pdr_smt_context_manager.h | 18 +- src/muz/rel/check_relation.cpp | 36 ++-- src/muz/rel/check_relation.h | 76 ++++----- src/muz/rel/dl_base.cpp | 6 +- src/muz/rel/dl_base.h | 34 ++-- src/muz/rel/dl_bound_relation.cpp | 20 +-- src/muz/rel/dl_bound_relation.h | 76 ++++----- src/muz/rel/dl_check_table.cpp | 22 +-- src/muz/rel/dl_check_table.h | 74 ++++---- src/muz/rel/dl_compiler.h | 2 +- src/muz/rel/dl_external_relation.cpp | 14 +- src/muz/rel/dl_external_relation.h | 58 +++---- src/muz/rel/dl_finite_product_relation.cpp | 36 ++-- src/muz/rel/dl_finite_product_relation.h | 72 ++++---- src/muz/rel/dl_instruction.cpp | 114 ++++++------- src/muz/rel/dl_interval_relation.cpp | 14 +- src/muz/rel/dl_interval_relation.h | 64 +++---- src/muz/rel/dl_lazy_table.cpp | 16 +- src/muz/rel/dl_lazy_table.h | 122 ++++++------- src/muz/rel/dl_mk_explanations.cpp | 70 ++++---- src/muz/rel/dl_mk_explanations.h | 2 +- src/muz/rel/dl_mk_similarity_compressor.h | 2 +- src/muz/rel/dl_mk_simple_joins.h | 2 +- src/muz/rel/dl_product_relation.cpp | 24 +-- src/muz/rel/dl_product_relation.h | 62 +++---- src/muz/rel/dl_relation_manager.cpp | 68 ++++---- src/muz/rel/dl_sieve_relation.cpp | 10 +- src/muz/rel/dl_sieve_relation.h | 64 +++---- src/muz/rel/dl_sparse_table.cpp | 30 ++-- src/muz/rel/dl_sparse_table.h | 78 ++++----- src/muz/rel/dl_table.cpp | 20 +-- src/muz/rel/dl_table.h | 36 ++-- src/muz/rel/dl_table_relation.cpp | 12 +- src/muz/rel/dl_table_relation.h | 80 ++++----- src/muz/rel/dl_vector_relation.h | 8 +- src/muz/rel/karr_relation.cpp | 30 ++-- src/muz/rel/karr_relation.h | 34 ++-- src/muz/rel/rel_context.h | 58 +++---- src/muz/rel/udoc_relation.cpp | 28 +-- src/muz/rel/udoc_relation.h | 82 ++++----- src/muz/spacer/spacer_dl_interface.h | 34 ++-- src/muz/spacer/spacer_generalizers.h | 28 +-- src/muz/spacer/spacer_itp_solver.h | 52 +++--- src/muz/spacer/spacer_qe_project.cpp | 4 +- src/muz/spacer/spacer_unsat_core_plugin.h | 14 +- src/muz/spacer/spacer_virtual_solver.h | 40 ++--- src/muz/tab/tab_context.h | 14 +- src/muz/transforms/dl_mk_array_blast.h | 4 +- src/muz/transforms/dl_mk_array_eq_rewrite.h | 4 +- .../transforms/dl_mk_array_instantiation.h | 4 +- src/muz/transforms/dl_mk_backwards.h | 4 +- src/muz/transforms/dl_mk_bit_blast.cpp | 4 +- src/muz/transforms/dl_mk_bit_blast.h | 4 +- src/muz/transforms/dl_mk_coalesce.h | 2 +- src/muz/transforms/dl_mk_coi_filter.h | 2 +- src/muz/transforms/dl_mk_filter_rules.h | 4 +- .../transforms/dl_mk_interp_tail_simplifier.h | 4 +- src/muz/transforms/dl_mk_karr_invariants.cpp | 6 +- src/muz/transforms/dl_mk_karr_invariants.h | 4 +- src/muz/transforms/dl_mk_loop_counter.h | 4 +- src/muz/transforms/dl_mk_magic_sets.h | 2 +- src/muz/transforms/dl_mk_magic_symbolic.h | 4 +- .../dl_mk_quantifier_abstraction.cpp | 6 +- .../transforms/dl_mk_quantifier_abstraction.h | 4 +- .../dl_mk_quantifier_instantiation.h | 4 +- src/muz/transforms/dl_mk_rule_inliner.h | 6 +- src/muz/transforms/dl_mk_scale.cpp | 6 +- src/muz/transforms/dl_mk_scale.h | 4 +- .../transforms/dl_mk_separate_negated_tails.h | 2 +- src/muz/transforms/dl_mk_slice.cpp | 8 +- src/muz/transforms/dl_mk_slice.h | 4 +- .../transforms/dl_mk_subsumption_checker.h | 4 +- src/muz/transforms/dl_mk_unbound_compressor.h | 2 +- src/muz/transforms/dl_mk_unfold.h | 2 +- src/opt/maxsmt.h | 14 +- src/opt/opt_context.h | 70 ++++---- src/opt/opt_pareto.h | 8 +- src/opt/opt_solver.h | 42 ++--- src/parsers/util/cost_parser.h | 6 +- src/qe/nlarith_util.cpp | 34 ++-- src/qe/nlqsat.cpp | 22 +-- src/qe/qe.cpp | 42 ++--- src/qe/qe.h | 4 +- src/qe/qe_arith.h | 10 +- src/qe/qe_arith_plugin.cpp | 38 ++--- src/qe/qe_array_plugin.cpp | 12 +- src/qe/qe_arrays.h | 8 +- src/qe/qe_bool_plugin.cpp | 14 +- src/qe/qe_bv_plugin.cpp | 14 +- src/qe/qe_cmd.cpp | 16 +- src/qe/qe_datatype_plugin.cpp | 18 +- src/qe/qe_datatypes.h | 8 +- src/qe/qe_dl_plugin.cpp | 10 +- src/qe/qe_lite.cpp | 18 +- src/qe/qe_sat_tactic.cpp | 57 +++---- src/qe/qe_tactic.cpp | 24 +-- src/qe/qe_vartest.h | 2 +- src/qe/qsat.cpp | 22 +-- src/sat/sat_solver/inc_sat_solver.cpp | 52 +++--- src/sat/tactic/goal2sat.cpp | 6 +- src/sat/tactic/sat_tactic.cpp | 28 +-- src/shell/lp_frontend.cpp | 2 +- src/smt/arith_eq_adapter.cpp | 6 +- src/smt/asserted_formulas.h | 52 +++--- src/smt/dyn_ack.cpp | 12 +- src/smt/mam.cpp | 30 ++-- src/smt/proto_model/array_factory.h | 8 +- src/smt/proto_model/datatype_factory.h | 6 +- src/smt/proto_model/numeral_factory.h | 10 +- src/smt/proto_model/proto_model.h | 10 +- src/smt/proto_model/struct_factory.h | 6 +- src/smt/proto_model/value_factory.h | 30 ++-- src/smt/smt2_extra_cmds.cpp | 20 +-- src/smt/smt_case_split_queue.cpp | 160 +++++++++--------- src/smt/smt_context.cpp | 8 +- src/smt/smt_context.h | 4 +- src/smt/smt_for_each_relevant_expr.h | 8 +- src/smt/smt_internalizer.cpp | 8 +- src/smt/smt_justification.h | 110 ++++++------ src/smt/smt_model_finder.cpp | 100 +++++------ src/smt/smt_model_generator.h | 8 +- src/smt/smt_quantifier.cpp | 42 ++--- src/smt/smt_relevancy.cpp | 40 ++--- src/smt/smt_relevancy.h | 8 +- src/smt/smt_solver.cpp | 46 ++--- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 25 ++- src/smt/tactic/smt_tactic.cpp | 28 +-- src/smt/tactic/unit_subsumption_tactic.cpp | 16 +- src/smt/theory_arith.h | 104 ++++++------ src/smt/theory_arith_int.h | 2 +- src/smt/theory_array.h | 36 ++-- src/smt/theory_array_base.cpp | 6 +- src/smt/theory_array_base.h | 20 +-- src/smt/theory_array_full.h | 36 ++-- src/smt/theory_bv.cpp | 20 +-- src/smt/theory_bv.h | 50 +++--- src/smt/theory_datatype.cpp | 8 +- src/smt/theory_datatype.h | 46 ++--- src/smt/theory_dense_diff_logic.h | 62 +++---- src/smt/theory_diff_logic.h | 64 +++---- src/smt/theory_dl.cpp | 28 +-- src/smt/theory_dummy.h | 24 +-- src/smt/theory_fpa.cpp | 4 +- src/smt/theory_fpa.h | 64 +++---- src/smt/theory_lra.cpp | 6 +- src/smt/theory_lra.h | 62 +++---- src/smt/theory_pb.cpp | 22 +-- src/smt/theory_pb.h | 40 ++--- src/smt/theory_seq.cpp | 8 +- src/smt/theory_seq.h | 64 +++---- src/smt/theory_seq_empty.h | 26 +-- src/smt/theory_str.h | 60 +++---- src/smt/theory_utvpi.h | 58 +++---- src/smt/theory_wmaxsat.h | 38 ++--- src/test/ex.cpp | 4 +- src/util/checked_int64.h | 2 +- src/util/lp/eta_matrix.h | 10 +- src/util/lp/iterator_on_column.h | 10 +- src/util/lp/iterator_on_indexed_vector.h | 10 +- src/util/lp/iterator_on_pivot_row.h | 10 +- src/util/lp/iterator_on_row.h | 10 +- src/util/lp/iterator_on_term_with_basis_var.h | 10 +- src/util/lp/lar_constraints.h | 14 +- src/util/lp/lar_solver.h | 2 +- src/util/lp/lp_dual_core_solver.h | 2 +- src/util/lp/lp_dual_simplex.h | 8 +- src/util/lp/lp_primal_core_solver.h | 2 +- src/util/lp/lp_primal_simplex.h | 8 +- src/util/lp/lp_settings.h | 2 +- src/util/lp/lu.h | 10 +- src/util/lp/permutation_matrix.h | 10 +- src/util/lp/row_eta_matrix.h | 10 +- src/util/lp/square_dense_submatrix.h | 10 +- src/util/mpff.h | 6 +- src/util/mpfx.h | 6 +- src/util/timeout.cpp | 2 +- src/util/trail.h | 42 ++--- src/util/union_find.h | 8 +- 220 files changed, 2546 insertions(+), 2548 deletions(-) diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index 82ef19274..5d749b7d5 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -27,13 +27,13 @@ public: : m(m), m_p(p) {} - virtual ~ackermannize_bv_tactic() { } + ~ackermannize_bv_tactic() override { } - virtual void operator()(goal_ref const & g, + void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + expr_dependency_ref & core) override { mc = 0; tactic_report report("ackermannize", *g); fail_if_unsat_core_generation("ackermannize", g); @@ -69,24 +69,24 @@ public: } - void updt_params(params_ref const & _p) { + void updt_params(params_ref const & _p) override { ackermannize_bv_tactic_params p(_p); m_lemma_limit = p.div0_ackermann_limit(); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { ackermannize_bv_tactic_params::collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.update("ackr-constraints", m_st.m_ackrs_sz); } - virtual void reset_statistics() { m_st.reset(); } + void reset_statistics() override { m_st.reset(); } - virtual void cleanup() { } + void cleanup() override { } - virtual tactic* translate(ast_manager& m) { + tactic* translate(ast_manager& m) override { return alloc(ackermannize_bv_tactic, m, m_p); } private: diff --git a/src/ackermannization/ackr_bound_probe.cpp b/src/ackermannization/ackr_bound_probe.cpp index 50b9cc092..f5e072368 100644 --- a/src/ackermannization/ackr_bound_probe.cpp +++ b/src/ackermannization/ackr_bound_probe.cpp @@ -57,7 +57,7 @@ class ackr_bound_probe : public probe { public: ackr_bound_probe() {} - virtual result operator()(goal const & g) { + result operator()(goal const & g) override { proc p(g.m()); unsigned sz = g.size(); expr_fast_mark1 visited; diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index a7c021913..c8df89bad 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -37,9 +37,9 @@ public: , fixed_model(false) { } - virtual ~ackr_model_converter() { } + ~ackr_model_converter() override { } - virtual void operator()(model_ref & md, unsigned goal_idx) { + void operator()(model_ref & md, unsigned goal_idx) override { SASSERT(goal_idx == 0); SASSERT(!fixed_model || md.get() == 0 || (!md->get_num_constants() && !md->get_num_functions())); model_ref& old_model = fixed_model ? abstr_model : md; @@ -49,9 +49,9 @@ public: md = new_model; } - virtual void operator()(model_ref & md) { operator()(md, 0); } + void operator()(model_ref & md) override { operator()(md, 0); } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { ackr_info_ref retv_info = info->translate(translator); if (fixed_model) { model_ref retv_mod_ref = abstr_model->translate(translator); diff --git a/src/ackermannization/lackr_model_converter_lazy.cpp b/src/ackermannization/lackr_model_converter_lazy.cpp index 2a7adb839..15673ffb6 100644 --- a/src/ackermannization/lackr_model_converter_lazy.cpp +++ b/src/ackermannization/lackr_model_converter_lazy.cpp @@ -28,9 +28,9 @@ public: , model_constructor(lmc) { } - virtual ~lackr_model_converter_lazy() { } + ~lackr_model_converter_lazy() override { } - virtual void operator()(model_ref & md, unsigned goal_idx) { + void operator()(model_ref & md, unsigned goal_idx) override { SASSERT(goal_idx == 0); SASSERT(md.get() == 0 || (!md->get_num_constants() && !md->get_num_functions())); SASSERT(model_constructor.get()); @@ -39,13 +39,13 @@ public: model_constructor->make_model(md); } - virtual void operator()(model_ref & md) { + void operator()(model_ref & md) override { operator()(md, 0); } //void display(std::ostream & out); - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { NOT_IMPLEMENTED_YET(); } protected: diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 96d8392ba..b4eda2c03 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -345,9 +345,9 @@ extern "C" { public: vector_var2anum(scoped_anum_vector & as):m_as(as) {} virtual ~vector_var2anum() {} - virtual algebraic_numbers::manager & m() const { return m_as.m(); } - virtual bool contains(polynomial::var x) const { return static_cast(x) < m_as.size(); } - virtual algebraic_numbers::anum const & operator()(polynomial::var x) const { return m_as.get(x); } + algebraic_numbers::manager & m() const override { return m_as.m(); } + bool contains(polynomial::var x) const override { return static_cast(x) < m_as.size(); } + algebraic_numbers::anum const & operator()(polynomial::var x) const override { return m_as.get(x); } }; Z3_ast_vector Z3_API Z3_algebraic_roots(Z3_context c, Z3_ast p, unsigned n, Z3_ast a[]) { diff --git a/src/api/api_ast_map.h b/src/api/api_ast_map.h index 3dacc54f1..27ad1eb9d 100644 --- a/src/api/api_ast_map.h +++ b/src/api/api_ast_map.h @@ -25,7 +25,7 @@ struct Z3_ast_map_ref : public api::object { ast_manager & m; obj_map m_map; Z3_ast_map_ref(api::context& c, ast_manager & _m): api::object(c), m(_m) {} - virtual ~Z3_ast_map_ref(); + ~Z3_ast_map_ref() override; }; inline Z3_ast_map_ref * to_ast_map(Z3_ast_map v) { return reinterpret_cast(v); } diff --git a/src/api/api_ast_vector.h b/src/api/api_ast_vector.h index ced20481e..d9d3913e7 100644 --- a/src/api/api_ast_vector.h +++ b/src/api/api_ast_vector.h @@ -27,7 +27,7 @@ namespace api { struct Z3_ast_vector_ref : public api::object { ast_ref_vector m_ast_vector; Z3_ast_vector_ref(api::context& c, ast_manager & m): api::object(c), m_ast_vector(m) {} - virtual ~Z3_ast_vector_ref() {} + ~Z3_ast_vector_ref() override {} }; inline Z3_ast_vector_ref * to_ast_vector(Z3_ast_vector v) { return reinterpret_cast(v); } diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 397e2a8af..431638864 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -51,8 +51,8 @@ namespace api { m_context(m, m_register_engine, p), m_trail(m) {} - virtual ~fixedpoint_context() {} - family_id get_family_id() const { return const_cast(m_context).get_decl_util().get_family_id(); } + ~fixedpoint_context() override {} + family_id get_family_id() const override { return const_cast(m_context).get_decl_util().get_family_id(); } void set_state(void* state) { SASSERT(!m_state); m_state = state; @@ -73,7 +73,7 @@ namespace api { void set_reduce_assign(reduce_assign_callback_fptr f) { m_reduce_assign = f; } - virtual void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) { + void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) override { expr* r = 0; if (m_reduce_app) { m_reduce_app(m_state, f, num_args, args, &r); @@ -90,7 +90,7 @@ namespace api { result = m.mk_app(f, num_args, args); } } - virtual void reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs) { + void reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs) override { if (m_reduce_assign) { m_trail.push_back(f); for (unsigned i = 0; i < num_args; ++i) { diff --git a/src/api/api_datalog.h b/src/api/api_datalog.h index c8dbc4180..588ee02d3 100644 --- a/src/api/api_datalog.h +++ b/src/api/api_datalog.h @@ -38,7 +38,7 @@ struct Z3_fixedpoint_ref : public api::object { api::fixedpoint_context * m_datalog; params_ref m_params; Z3_fixedpoint_ref(api::context& c): api::object(c), m_datalog(0) {} - virtual ~Z3_fixedpoint_ref() { dealloc(m_datalog); } + ~Z3_fixedpoint_ref() override { dealloc(m_datalog); } }; inline Z3_fixedpoint_ref * to_fixedpoint(Z3_fixedpoint s) { return reinterpret_cast(s); } diff --git a/src/api/api_goal.h b/src/api/api_goal.h index 4e9729df5..3b109f8da 100644 --- a/src/api/api_goal.h +++ b/src/api/api_goal.h @@ -24,7 +24,7 @@ Revision History: struct Z3_goal_ref : public api::object { goal_ref m_goal; Z3_goal_ref(api::context& c) : api::object(c) {} - virtual ~Z3_goal_ref() {} + ~Z3_goal_ref() override {} }; inline Z3_goal_ref * to_goal(Z3_goal g) { return reinterpret_cast(g); } diff --git a/src/api/api_model.h b/src/api/api_model.h index 64427cfb8..1ab10da79 100644 --- a/src/api/api_model.h +++ b/src/api/api_model.h @@ -24,7 +24,7 @@ Revision History: struct Z3_model_ref : public api::object { model_ref m_model; Z3_model_ref(api::context& c): api::object(c) {} - virtual ~Z3_model_ref() {} + ~Z3_model_ref() override {} }; inline Z3_model_ref * to_model(Z3_model s) { return reinterpret_cast(s); } @@ -35,7 +35,7 @@ struct Z3_func_interp_ref : public api::object { model_ref m_model; // must have it to prevent reference to m_func_interp to be killed. func_interp * m_func_interp; Z3_func_interp_ref(api::context& c, model * m): api::object(c), m_model(m), m_func_interp(0) {} - virtual ~Z3_func_interp_ref() {} + ~Z3_func_interp_ref() override {} }; inline Z3_func_interp_ref * to_func_interp(Z3_func_interp s) { return reinterpret_cast(s); } @@ -47,7 +47,7 @@ struct Z3_func_entry_ref : public api::object { func_interp * m_func_interp; func_entry const * m_func_entry; Z3_func_entry_ref(api::context& c, model * m):api::object(c), m_model(m), m_func_interp(0), m_func_entry(0) {} - virtual ~Z3_func_entry_ref() {} + ~Z3_func_entry_ref() override {} }; inline Z3_func_entry_ref * to_func_entry(Z3_func_entry s) { return reinterpret_cast(s); } diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 0d96a6719..72180388e 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -36,7 +36,7 @@ extern "C" { struct Z3_optimize_ref : public api::object { opt::context* m_opt; Z3_optimize_ref(api::context& c): api::object(c), m_opt(0) {} - virtual ~Z3_optimize_ref() { dealloc(m_opt); } + ~Z3_optimize_ref() override { dealloc(m_opt); } }; inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast(o); } inline Z3_optimize of_optimize(Z3_optimize_ref * o) { return reinterpret_cast(o); } diff --git a/src/api/api_solver.h b/src/api/api_solver.h index 4f344a00d..3da702f1e 100644 --- a/src/api/api_solver.h +++ b/src/api/api_solver.h @@ -27,7 +27,7 @@ struct Z3_solver_ref : public api::object { params_ref m_params; symbol m_logic; Z3_solver_ref(api::context& c, solver_factory * f): api::object(c), m_solver_factory(f), m_solver(0), m_logic(symbol::null) {} - virtual ~Z3_solver_ref() {} + ~Z3_solver_ref() override {} }; inline Z3_solver_ref * to_solver(Z3_solver s) { return reinterpret_cast(s); } diff --git a/src/api/api_stats.h b/src/api/api_stats.h index 5ce616084..e5ad5d315 100644 --- a/src/api/api_stats.h +++ b/src/api/api_stats.h @@ -24,7 +24,7 @@ Revision History: struct Z3_stats_ref : public api::object { statistics m_stats; Z3_stats_ref(api::context& c): api::object(c) {} - virtual ~Z3_stats_ref() {} + ~Z3_stats_ref() override {} }; inline Z3_stats_ref * to_stats(Z3_stats s) { return reinterpret_cast(s); } diff --git a/src/api/api_tactic.h b/src/api/api_tactic.h index fd2f05185..cc5e55a4e 100644 --- a/src/api/api_tactic.h +++ b/src/api/api_tactic.h @@ -29,13 +29,13 @@ namespace api { struct Z3_tactic_ref : public api::object { tactic_ref m_tactic; Z3_tactic_ref(api::context& c): api::object(c) {} - virtual ~Z3_tactic_ref() {} + ~Z3_tactic_ref() override {} }; struct Z3_probe_ref : public api::object { probe_ref m_probe; Z3_probe_ref(api::context& c):api::object(c) {} - virtual ~Z3_probe_ref() {} + ~Z3_probe_ref() override {} }; inline Z3_tactic_ref * to_tactic(Z3_tactic g) { return reinterpret_cast(g); } @@ -52,7 +52,7 @@ struct Z3_apply_result_ref : public api::object { proof_converter_ref m_pc; expr_dependency_ref m_core; Z3_apply_result_ref(api::context& c, ast_manager & m); - virtual ~Z3_apply_result_ref() {} + ~Z3_apply_result_ref() override {} }; inline Z3_apply_result_ref * to_apply_result(Z3_apply_result g) { return reinterpret_cast(g); } diff --git a/src/api/api_util.h b/src/api/api_util.h index bc6781c2c..e2e4621d4 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -88,7 +88,7 @@ inline lbool to_lbool(Z3_lbool b) { return static_cast(b); } struct Z3_params_ref : public api::object { params_ref m_params; Z3_params_ref(api::context& c): api::object(c) {} - virtual ~Z3_params_ref() {} + ~Z3_params_ref() override {} }; inline Z3_params_ref * to_params(Z3_params p) { return reinterpret_cast(p); } @@ -98,7 +98,7 @@ inline params_ref to_param_ref(Z3_params p) { return p == 0 ? params_ref() : to_ struct Z3_param_descrs_ref : public api::object { param_descrs m_descrs; Z3_param_descrs_ref(api::context& c): api::object(c) {} - virtual ~Z3_param_descrs_ref() {} + ~Z3_param_descrs_ref() override {} }; inline Z3_param_descrs_ref * to_param_descrs(Z3_param_descrs p) { return reinterpret_cast(p); } diff --git a/src/ast/ast_trail.h b/src/ast/ast_trail.h index d5245bd77..78ef74a47 100644 --- a/src/ast/ast_trail.h +++ b/src/ast/ast_trail.h @@ -66,7 +66,7 @@ public: m.insert(s,t); } - virtual void undo(Ctx& ctx) { + void undo(Ctx& ctx) override { m_map.pop(); } }; diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index 32cb9cccb..bbeb8d072 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -211,7 +211,7 @@ class iz3proof_itp_impl : public iz3proof_itp { pivot literal, while the conclusion of premise2 should contain the pivot literal. */ - node make_resolution(ast pivot, const std::vector &conc, node premise1, node premise2) { + node make_resolution(ast pivot, const std::vector &conc, node premise1, node premise2) override { LitType lt = get_term_type(pivot); if(lt == LitA) return my_or(premise1,premise2); @@ -2146,7 +2146,7 @@ class iz3proof_itp_impl : public iz3proof_itp { } /** Make an assumption node. The given clause is assumed in the given frame. */ - virtual node make_assumption(int frame, const std::vector &assumption){ + node make_assumption(int frame, const std::vector &assumption) override { if(!weak){ if(pv->in_range(frame,rng)){ std::vector itp_clause; @@ -2219,7 +2219,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /** Make a modus-ponens node. This takes derivations of |- x and |- x = y and produces |- y */ - virtual node make_mp(const ast &p_eq_q, const ast &prem1, const ast &prem2){ + node make_mp(const ast &p_eq_q, const ast &prem1, const ast &prem2) override { /* Interpolate the axiom p, p=q -> q */ ast p = arg(p_eq_q,0); @@ -2281,7 +2281,7 @@ class iz3proof_itp_impl : public iz3proof_itp { } /** Make an axiom node. The conclusion must be an instance of an axiom. */ - virtual node make_axiom(const std::vector &conclusion, prover::range frng){ + node make_axiom(const std::vector &conclusion, prover::range frng) override { int nargs = conclusion.size(); std::vector largs(nargs); std::vector eqs; @@ -2306,20 +2306,20 @@ class iz3proof_itp_impl : public iz3proof_itp { return capture_localization(itp); } - virtual node make_axiom(const std::vector &conclusion){ + node make_axiom(const std::vector &conclusion) override { return make_axiom(conclusion,pv->range_full()); } /** Make a Contra node. This rule takes a derivation of the form Gamma |- False and produces |- \/~Gamma. */ - virtual node make_contra(node prem, const std::vector &conclusion){ + node make_contra(node prem, const std::vector &conclusion) override { return prem; } /** Make hypothesis. Creates a node of the form P |- P. */ - virtual node make_hypothesis(const ast &P){ + node make_hypothesis(const ast &P) override { if(is_not(P)) return make_hypothesis(arg(P,0)); switch(get_term_type(P)){ @@ -2354,7 +2354,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /** Make a Reflexivity node. This rule produces |- x = x */ - virtual node make_reflexivity(ast con){ + node make_reflexivity(ast con) override { if(get_term_type(con) == LitA) return mk_false(); if(get_term_type(con) == LitB) @@ -2367,7 +2367,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /** Make a Symmetry node. This takes a derivation of |- x = y and produces | y = x. Ditto for ~(x=y) */ - virtual node make_symmetry(ast con, const ast &premcon, node prem){ + node make_symmetry(ast con, const ast &premcon, node prem) override { #if 0 ast x = arg(con,0); ast y = arg(con,1); @@ -2394,7 +2394,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /** Make a transitivity node. This takes derivations of |- x = y and |- y = z produces | x = z */ - virtual node make_transitivity(const ast &x, const ast &y, const ast &z, node prem1, node prem2){ + node make_transitivity(const ast &x, const ast &y, const ast &z, node prem1, node prem2) override { /* Interpolate the axiom x=y,y=z,-> x=z */ ast p = make_equiv_rel(x,y); @@ -2413,7 +2413,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /** Make a congruence node. This takes derivations of |- x_i = y_i and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */ - virtual node make_congruence(const ast &p, const ast &con, const ast &prem1){ + node make_congruence(const ast &p, const ast &con, const ast &prem1) override { ast x = arg(p,0), y = arg(p,1); ast itp; LitType con_t = get_term_type(con); @@ -2454,7 +2454,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /** Make a congruence node. This takes derivations of |- x_i1 = y_i1, |- x_i2 = y_i2,... and produces |- f(...x_i1...x_i2...) = f(...y_i1...y_i2...) */ - node make_congruence(const std::vector &p, const ast &con, const std::vector &prems){ + node make_congruence(const std::vector &p, const ast &con, const std::vector &prems) override { if(p.size() == 0) throw proof_error(); if(p.size() == 1) @@ -2516,8 +2516,8 @@ class iz3proof_itp_impl : public iz3proof_itp { /** Make a farkas proof node. */ - virtual node make_farkas(ast con, const std::vector &prems, const std::vector &prem_cons, - const std::vector &coeffs){ + node make_farkas(ast con, const std::vector &prems, const std::vector &prem_cons, + const std::vector &coeffs) override { /* Compute the interpolant for the clause */ @@ -2619,7 +2619,7 @@ class iz3proof_itp_impl : public iz3proof_itp { } /* Make an axiom instance of the form |- x<=y, y<= x -> x =y */ - virtual node make_leq2eq(ast x, ast y, const ast &xleqy, const ast &yleqx){ + node make_leq2eq(ast x, ast y, const ast &xleqy, const ast &yleqx) override { ast con = make(Equal,x,y); ast itp; switch(get_term_type(con)){ @@ -2658,7 +2658,7 @@ class iz3proof_itp_impl : public iz3proof_itp { } /* Make an axiom instance of the form |- x = y -> x <= y */ - virtual node make_eq2leq(ast x, ast y, const ast &xleqy){ + node make_eq2leq(ast x, ast y, const ast &xleqy) override { ast itp; switch(get_term_type(xleqy)){ case LitA: @@ -2681,7 +2681,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* Make an inference of the form t <= c |- t/d <= floor(c/d) where t is an affine term divisble by d and c is an integer constant */ - virtual node make_cut_rule(const ast &tleqc, const ast &d, const ast &con, const ast &prem){ + node make_cut_rule(const ast &tleqc, const ast &d, const ast &con, const ast &prem) override { ast itp = mk_false(); switch(get_term_type(con)){ case LitA: @@ -2965,7 +2965,7 @@ class iz3proof_itp_impl : public iz3proof_itp { } /* Return an interpolant from a proof of false */ - ast interpolate(const node &pf){ + ast interpolate(const node &pf) override { // proof of false must be a formula, with quantified symbols #ifndef BOGUS_QUANTS return close_universally(add_quants(z3_simplify(pf))); @@ -3089,7 +3089,7 @@ public: m().inc_ref(sexists); } - ~iz3proof_itp_impl(){ + ~iz3proof_itp_impl() override { m().dec_ref(contra); m().dec_ref(sum); m().dec_ref(rotate_sum); diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index 32b76b224..4196d2016 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -2068,7 +2068,7 @@ public: // We actually compute the interpolant here and then produce a proof consisting of just a lemma - iz3proof::node translate(ast proof, iz3proof &dst){ + iz3proof::node translate(ast proof, iz3proof &dst) override { std::vector itps; scan_skolems(proof); for(int i = 0; i < frames -1; i++){ @@ -2114,7 +2114,7 @@ public: m().inc_ref(commute); } - ~iz3translation_full(){ + ~iz3translation_full() override { m().dec_ref(commute); } }; diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index e71475e45..0d5b9ccc3 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -1611,7 +1611,7 @@ public: // 1) Translate ast proof term to Zproof // 2) Translate Zproof to Iproof - Iproof::node translate(ast proof, Iproof &dst){ + Iproof::node translate(ast proof, Iproof &dst) override { iproof = &dst; Iproof::node Ipf = translate_main(proof,0); // builds result in dst return Ipf; @@ -1629,7 +1629,7 @@ public: traced_lit = ast(); } - ~iz3translation_direct(){ + ~iz3translation_direct() override { for(hash_map::iterator it = non_local_lits_unique.begin(), en = non_local_lits_unique.end(); diff --git a/src/math/hilbert/heap_trie.h b/src/math/hilbert/heap_trie.h index ace5381b8..e53f9e7dc 100644 --- a/src/math/hilbert/heap_trie.h +++ b/src/math/hilbert/heap_trie.h @@ -81,14 +81,14 @@ class heap_trie { Value m_value; public: leaf(): node(leaf_t) {} - virtual ~leaf() {} + ~leaf() override {} Value const& get_value() const { return m_value; } void set_value(Value const& v) { m_value = v; } - virtual void display(std::ostream& out, unsigned indent) const { + void display(std::ostream& out, unsigned indent) const override { out << " value: " << m_value; } - virtual unsigned num_nodes() const { return 1; } - virtual unsigned num_leaves() const { return this->ref_count()>0?1:0; } + unsigned num_nodes() const override { return 1; } + unsigned num_leaves() const override { return this->ref_count()>0?1:0; } }; typedef buffer, true, 2> children_t; @@ -99,7 +99,7 @@ class heap_trie { public: trie(): node(trie_t) {} - virtual ~trie() { + ~trie() override { } node* find_or_insert(Key k, node* n) { @@ -137,7 +137,7 @@ class heap_trie { children_t const& nodes() const { return m_nodes; } children_t & nodes() { return m_nodes; } - virtual void display(std::ostream& out, unsigned indent) const { + void display(std::ostream& out, unsigned indent) const override { for (unsigned j = 0; j < m_nodes.size(); ++j) { if (j != 0 || indent > 0) { out << "\n"; @@ -151,7 +151,7 @@ class heap_trie { } } - virtual unsigned num_nodes() const { + unsigned num_nodes() const override { unsigned sz = 1; for (unsigned j = 0; j < m_nodes.size(); ++j) { sz += m_nodes[j].second->num_nodes(); @@ -159,7 +159,7 @@ class heap_trie { return sz; } - virtual unsigned num_leaves() const { + unsigned num_leaves() const override { unsigned sz = 0; for (unsigned j = 0; j < m_nodes.size(); ++j) { sz += m_nodes[j].second->num_leaves(); diff --git a/src/math/hilbert/hilbert_basis.cpp b/src/math/hilbert/hilbert_basis.cpp index 9baa0beac..bbc56bdd5 100644 --- a/src/math/hilbert/hilbert_basis.cpp +++ b/src/math/hilbert/hilbert_basis.cpp @@ -175,7 +175,7 @@ class hilbert_basis::value_index2 { hilbert_basis* hb; offset_t m_value; checker(): hb(0) {} - virtual bool operator()(unsigned const& v) { + bool operator()(unsigned const& v) override { if (m_value.m_offset != v) { // && hb->is_subsumed(m_value, offset_t(v))) { return true; } diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 9484c3c83..8c42bb418 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -1932,9 +1932,9 @@ namespace algebraic_numbers { imp & m_imp; polynomial::var2anum const & m_x2v; opt_var2basic(imp & i, polynomial::var2anum const & x2v):m_imp(i), m_x2v(x2v) {} - virtual unsynch_mpq_manager & m() const { return m_imp.qm(); } - virtual bool contains(polynomial::var x) const { return m_x2v.contains(x); } - virtual mpq const & operator()(polynomial::var x) const { + unsynch_mpq_manager & m() const override { return m_imp.qm(); } + bool contains(polynomial::var x) const override { return m_x2v.contains(x); } + mpq const & operator()(polynomial::var x) const override { anum const & v = m_x2v(x); if (!v.is_basic()) throw failed(); @@ -1949,9 +1949,9 @@ namespace algebraic_numbers { imp & m_imp; polynomial::var2anum const & m_x2v; var2basic(imp & i, polynomial::var2anum const & x2v):m_imp(i), m_x2v(x2v) {} - virtual unsynch_mpq_manager & m() const { return m_imp.qm(); } - virtual bool contains(polynomial::var x) const { return m_x2v.contains(x) && m_x2v(x).is_basic(); } - virtual mpq const & operator()(polynomial::var x) const { + unsynch_mpq_manager & m() const override { return m_imp.qm(); } + bool contains(polynomial::var x) const override { return m_x2v.contains(x) && m_x2v(x).is_basic(); } + mpq const & operator()(polynomial::var x) const override { anum const & v = m_x2v(x); SASSERT(v.is_basic()); TRACE("var2basic", tout << "getting value of x" << x << " -> " << m().to_string(m_imp.basic_value(v)) << "\n";); @@ -1966,9 +1966,9 @@ namespace algebraic_numbers { imp & m_imp; polynomial::var2anum const & m_x2v; var2interval(imp & i, polynomial::var2anum const & x2v):m_imp(i), m_x2v(x2v) {} - virtual mpbqi_manager & m() const { return m_imp.bqim(); } - virtual bool contains(polynomial::var x) const { return m_x2v.contains(x) && !m_x2v(x).is_basic(); } - virtual mpbqi const & operator()(polynomial::var x) const { + mpbqi_manager & m() const override { return m_imp.bqim(); } + bool contains(polynomial::var x) const override { return m_x2v.contains(x) && !m_x2v(x).is_basic(); } + mpbqi const & operator()(polynomial::var x) const override { anum const & v = m_x2v(x); SASSERT(!v.is_basic()); return v.to_algebraic()->m_interval; @@ -2220,9 +2220,9 @@ namespace algebraic_numbers { m_x(x), m_v(v) { } - virtual manager & m() const { return m_am; } - virtual bool contains(polynomial::var x) const { return x == m_x || m_x2v.contains(x); } - virtual anum const & operator()(polynomial::var x) const { + manager & m() const override { return m_am; } + bool contains(polynomial::var x) const override { return x == m_x || m_x2v.contains(x); } + anum const & operator()(polynomial::var x) const override { if (x == m_x) return m_v; else @@ -2553,9 +2553,9 @@ namespace algebraic_numbers { m_x2v(x2v), m_v(v) { } - virtual manager & m() const { return m_am; } - virtual bool contains(polynomial::var x) const { return true; } - virtual anum const & operator()(polynomial::var x) const { + manager & m() const override { return m_am; } + bool contains(polynomial::var x) const override { return true; } + anum const & operator()(polynomial::var x) const override { if (m_x2v.contains(x)) return m_x2v(x); else diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index dcd5af1cc..d6eafac05 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -6350,9 +6350,9 @@ namespace polynomial { m_var_pos(buffer, xs_sz, xs), m_vs(vs) { } - virtual unsynch_mpq_manager & m() const { UNREACHABLE(); static unsynch_mpq_manager m; return m; } - virtual bool contains(var x) const { return m_var_pos(x) != UINT_MAX; } - virtual mpq const & operator()(var x) const { return m_vs[m_var_pos(x)]; } + unsynch_mpq_manager & m() const override { UNREACHABLE(); static unsynch_mpq_manager m; return m; } + bool contains(var x) const override { return m_var_pos(x) != UINT_MAX; } + mpq const & operator()(var x) const override { return m_vs[m_var_pos(x)]; } }; polynomial * substitute(polynomial const * p, unsigned xs_sz, var const * xs, mpq const * vs) { @@ -6527,9 +6527,9 @@ namespace polynomial { numeral const & m_val; public: single_var2value(numeral_manager & m, var x, numeral const & val):m_manager(m), m_x(x), m_val(val) {} - virtual numeral_manager & m() const { return m_manager; } - virtual bool contains(var x) const { return m_x == x; } - virtual numeral const & operator()(var x) const { SASSERT(m_x == x); return m_val; } + numeral_manager & m() const override { return m_manager; } + bool contains(var x) const override { return m_x == x; } + numeral const & operator()(var x) const override { SASSERT(m_x == x); return m_val; } }; void univ_eval(polynomial const * p, var x, numeral const & val, numeral & r) { diff --git a/src/math/polynomial/upolynomial_factorization_int.h b/src/math/polynomial/upolynomial_factorization_int.h index ea2b51d8f..e422c15a6 100644 --- a/src/math/polynomial/upolynomial_factorization_int.h +++ b/src/math/polynomial/upolynomial_factorization_int.h @@ -322,7 +322,7 @@ namespace upolynomial { /** \brief Filter the ones not in the degree set. */ - bool filter_current() const { + bool filter_current() const override { // select only the ones that have degrees in the degree set if (!m_degree_set.in_set(current_degree())) { diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 8f2d933e2..3f399990d 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -344,13 +344,13 @@ namespace realclosure { // --------------------------------- struct mk_pi_interval : public mk_interval { - virtual void operator()(unsigned k, mpqi_manager & im, mpqi_manager::interval & r) { + void operator()(unsigned k, mpqi_manager & im, mpqi_manager::interval & r) override { im.pi(k, r); } }; struct mk_e_interval : public mk_interval { - virtual void operator()(unsigned k, mpqi_manager & im, mpqi_manager::interval & r) { + void operator()(unsigned k, mpqi_manager & im, mpqi_manager::interval & r) override { im.e(k, r); } }; diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index 96fc5b6d7..1f32a6189 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -38,22 +38,22 @@ namespace subpaving { CTX m_ctx; public: context_wrapper(reslimit& lim, typename CTX::numeral_manager & m, params_ref const & p, small_object_allocator * a):m_ctx(lim, m, p, a) {} - virtual ~context_wrapper() {} - virtual unsigned num_vars() const { return m_ctx.num_vars(); } - virtual var mk_var(bool is_int) { return m_ctx.mk_var(is_int); } - virtual bool is_int(var x) const { return m_ctx.is_int(x); } - virtual var mk_monomial(unsigned sz, power const * pws) { return m_ctx.mk_monomial(sz, pws); } - virtual void inc_ref(ineq * a) { m_ctx.inc_ref(reinterpret_cast(a)); } - virtual void dec_ref(ineq * a) { m_ctx.dec_ref(reinterpret_cast(a)); } - virtual void add_clause(unsigned sz, ineq * const * atoms) { m_ctx.add_clause(sz, reinterpret_cast(atoms)); } - virtual void display_constraints(std::ostream & out, bool use_star) const { m_ctx.display_constraints(out, use_star); } - virtual void set_display_proc(display_var_proc * p) { m_ctx.set_display_proc(p); } - virtual void reset_statistics() { m_ctx.reset_statistics(); } - virtual void collect_statistics(statistics & st) const { m_ctx.collect_statistics(st); } - virtual void collect_param_descrs(param_descrs & r) { m_ctx.collect_param_descrs(r); } - virtual void updt_params(params_ref const & p) { m_ctx.updt_params(p); } - virtual void operator()() { m_ctx(); } - virtual void display_bounds(std::ostream & out) const { m_ctx.display_bounds(out); } + ~context_wrapper() override {} + unsigned num_vars() const override { return m_ctx.num_vars(); } + var mk_var(bool is_int) override { return m_ctx.mk_var(is_int); } + bool is_int(var x) const override { return m_ctx.is_int(x); } + var mk_monomial(unsigned sz, power const * pws) override { return m_ctx.mk_monomial(sz, pws); } + void inc_ref(ineq * a) override { m_ctx.inc_ref(reinterpret_cast(a)); } + void dec_ref(ineq * a) override { m_ctx.dec_ref(reinterpret_cast(a)); } + void add_clause(unsigned sz, ineq * const * atoms) override { m_ctx.add_clause(sz, reinterpret_cast(atoms)); } + void display_constraints(std::ostream & out, bool use_star) const override { m_ctx.display_constraints(out, use_star); } + void set_display_proc(display_var_proc * p) override { m_ctx.set_display_proc(p); } + void reset_statistics() override { m_ctx.reset_statistics(); } + void collect_statistics(statistics & st) const override { m_ctx.collect_statistics(st); } + void collect_param_descrs(param_descrs & r) override { m_ctx.collect_param_descrs(r); } + void updt_params(params_ref const & p) override { m_ctx.updt_params(p); } + void operator()() override { m_ctx(); } + void display_bounds(std::ostream & out) const override { m_ctx.display_bounds(out); } }; class context_mpq_wrapper : public context_wrapper { @@ -66,11 +66,11 @@ namespace subpaving { m_as(m) {} - virtual ~context_mpq_wrapper() {} + ~context_mpq_wrapper() override {} - virtual unsynch_mpq_manager & qm() const { return m_ctx.nm(); } + unsynch_mpq_manager & qm() const override { return m_ctx.nm(); } - virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) { + var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) override { m_as.reserve(sz); for (unsigned i = 0; i < sz; i++) { m_ctx.nm().set(m_as[i], as[i]); @@ -78,7 +78,7 @@ namespace subpaving { m_ctx.nm().set(m_c, c); return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs); } - virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) { + ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) override { return reinterpret_cast(m_ctx.mk_ineq(x, k, lower, open)); } }; @@ -108,11 +108,11 @@ namespace subpaving { m_q2(m_qm) { } - virtual ~context_mpf_wrapper() {} + ~context_mpf_wrapper() override {} - virtual unsynch_mpq_manager & qm() const { return m_qm; } + unsynch_mpq_manager & qm() const override { return m_qm; } - virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) { + var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) override { try { m_as.reserve(sz); for (unsigned i = 0; i < sz; i++) { @@ -125,7 +125,7 @@ namespace subpaving { throw subpaving::exception(); } } - virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) { + ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) override { try { f2n & m = m_ctx.nm(); if (lower) @@ -165,11 +165,11 @@ namespace subpaving { m_qm(qm) { } - virtual ~context_hwf_wrapper() {} + ~context_hwf_wrapper() override {} - virtual unsynch_mpq_manager & qm() const { return m_qm; } + unsynch_mpq_manager & qm() const override { return m_qm; } - virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) { + var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) override { try { m_as.reserve(sz); for (unsigned i = 0; i < sz; i++) { @@ -182,7 +182,7 @@ namespace subpaving { throw subpaving::exception(); } } - virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) { + ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) override { try { f2n & m = m_ctx.nm(); if (lower) @@ -223,11 +223,11 @@ namespace subpaving { m_z2(m_qm) { } - virtual ~context_fpoint_wrapper() {} + ~context_fpoint_wrapper() override {} - virtual unsynch_mpq_manager & qm() const { return m_qm; } + unsynch_mpq_manager & qm() const override { return m_qm; } - virtual var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) { + var mk_sum(mpz const & c, unsigned sz, mpz const * as, var const * xs) override { try { m_as.reserve(sz); for (unsigned i = 0; i < sz; i++) { @@ -241,7 +241,7 @@ namespace subpaving { } } - virtual ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) { + ineq * mk_ineq(var x, mpq const & k, bool lower, bool open) override { try { typename context_fpoint::numeral_manager & m = this->m_ctx.nm(); if (lower) diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index 3574787d8..5729cbfa0 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -36,7 +36,7 @@ public: context_t::node_selector(ctx) { } - virtual node * operator()(node * front, node * back) { + node * operator()(node * front, node * back) override { return back; } }; @@ -80,7 +80,7 @@ public: } // Return the next variable to branch. - virtual var operator()(typename context_t::node * n) { + var operator()(typename context_t::node * n) override { typename context_t::numeral_manager & nm = this->ctx()->nm(); SASSERT(this->ctx()->num_vars() > 0); var x = this->ctx()->splitting_var(n); @@ -197,7 +197,7 @@ public: SASSERT(m_delta < INT_MAX); } - virtual void operator()(node * n, var x) { + void operator()(node * n, var x) override { SASSERT(!n->inconsistent()); numeral_manager & nm = this->ctx()->nm(); node * left = this->mk_node(n); diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index 6a7bc11e8..ebc9356d9 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -40,7 +40,7 @@ class subpaving_tactic : public tactic { ast_manager & m() const { return m_inv.get_manager(); } - virtual void operator()(std::ostream & out, subpaving::var x) const { + void operator()(std::ostream & out, subpaving::var x) const override { expr * t = m_inv.get(x, 0); if (t != 0) out << mk_ismt2_pp(t, m()); @@ -216,36 +216,36 @@ public: m_params(p) { } - virtual ~subpaving_tactic() { + ~subpaving_tactic() override { dealloc(m_imp); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(subpaving_tactic, m, m_params); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_imp->collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.copy(m_stats); } - virtual void reset_statistics() { + void reset_statistics() override { m_stats.reset(); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { m_imp->process(*in); m_imp->collect_statistics(m_stats); @@ -261,7 +261,7 @@ public: } } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m(); dealloc(m_imp); m_imp = alloc(imp, m, m_params); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 78860bdde..106c15d5f 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -90,10 +90,10 @@ namespace datalog { return idx; } - virtual unsigned get_constant_count() const { + unsigned get_constant_count() const override { return m_el_names.size(); } - virtual void print_element(finite_element el_num, std::ostream & out) { + void print_element(finite_element el_num, std::ostream & out) override { if (el_num>=m_el_names.size()) { out << el_num; return; @@ -132,10 +132,10 @@ namespace datalog { } return idx; } - virtual unsigned get_constant_count() const { + unsigned get_constant_count() const override { return m_el_names.size(); } - virtual void print_element(finite_element el_num, std::ostream & out) { + void print_element(finite_element el_num, std::ostream & out) override { if (el_num >= m_el_names.size()) { out << "get_name() << ":" << el_num << '>'; return; @@ -159,9 +159,9 @@ namespace datalog { public: restore_rules(rule_set& r): m_old_rules(alloc(rule_set, r)) {} - virtual ~restore_rules() {} + ~restore_rules() override {} - virtual void undo(context& ctx) { + void undo(context& ctx) override { ctx.replace_rules(*m_old_rules); reset(); } @@ -173,8 +173,8 @@ namespace datalog { unsigned m_old_size; public: restore_vec_size_trail(Vec& v): m_vector(v), m_old_size(v.size()) {} - virtual ~restore_vec_size_trail() {} - virtual void undo(Ctx& ctx) { m_vector.shrink(m_old_size); } + ~restore_vec_size_trail() override {} + void undo(Ctx& ctx) override { m_vector.shrink(m_old_size); } }; void context::push() { diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 0fb68d396..3051dbf86 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -110,7 +110,7 @@ namespace datalog { class rel_context_base : public engine_base { public: rel_context_base(ast_manager& m, char const* name): engine_base(m, name) {} - virtual ~rel_context_base() {} + ~rel_context_base() override {} virtual relation_manager & get_rmanager() = 0; virtual const relation_manager & get_rmanager() const = 0; virtual relation_base & get_relation(func_decl * pred) = 0; @@ -146,9 +146,9 @@ namespace datalog { context const& ctx; public: contains_pred(context& ctx): ctx(ctx) {} - virtual ~contains_pred() {} + ~contains_pred() override {} - virtual bool operator()(expr* e) { + bool operator()(expr* e) override { return ctx.is_predicate(e); } }; diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 715964e3a..aceeba364 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -385,7 +385,7 @@ namespace datalog { public: skip_model_converter() {} - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { return alloc(skip_model_converter); } @@ -394,12 +394,12 @@ namespace datalog { model_converter* mk_skip_model_converter() { return alloc(skip_model_converter); } class skip_proof_converter : public proof_converter { - virtual void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) { + void operator()(ast_manager & m, unsigned num_source, proof * const * source, proof_ref & result) override { SASSERT(num_source == 1); result = source[0]; } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { return alloc(skip_proof_converter); } diff --git a/src/muz/bmc/dl_bmc_engine.h b/src/muz/bmc/dl_bmc_engine.h index fd5ce92e6..a5824fa82 100644 --- a/src/muz/bmc/dl_bmc_engine.h +++ b/src/muz/bmc/dl_bmc_engine.h @@ -55,18 +55,18 @@ namespace datalog { public: bmc(context& ctx); - ~bmc(); + ~bmc() override; - lbool query(expr* query); + lbool query(expr* query) override; - void display_certificate(std::ostream& out) const; + void display_certificate(std::ostream& out) const override; - void collect_statistics(statistics& st) const; + void collect_statistics(statistics& st) const override; - void reset_statistics(); - void get_rules_along_trace(datalog::rule_ref_vector& rules); + void reset_statistics() override; + void get_rules_along_trace(datalog::rule_ref_vector& rules) override; - expr_ref get_answer(); + expr_ref get_answer() override; // direct access to (new) non-linear compiler. void compile(rule_set const& rules, expr_ref_vector& fmls, unsigned level); diff --git a/src/muz/clp/clp_context.h b/src/muz/clp/clp_context.h index 44f99d564..378fdd473 100644 --- a/src/muz/clp/clp_context.h +++ b/src/muz/clp/clp_context.h @@ -32,12 +32,12 @@ namespace datalog { imp* m_imp; public: clp(context& ctx); - ~clp(); - virtual lbool query(expr* query); - virtual void reset_statistics(); - virtual void collect_statistics(statistics& st) const; - virtual void display_certificate(std::ostream& out) const; - virtual expr_ref get_answer(); + ~clp() override; + lbool query(expr* query) override; + void reset_statistics() override; + void collect_statistics(statistics& st) const override; + void display_certificate(std::ostream& out) const override; + expr_ref get_answer() override; }; }; diff --git a/src/muz/ddnf/ddnf.h b/src/muz/ddnf/ddnf.h index 29e9b1555..14c9f3cc7 100644 --- a/src/muz/ddnf/ddnf.h +++ b/src/muz/ddnf/ddnf.h @@ -35,12 +35,12 @@ namespace datalog { imp* m_imp; public: ddnf(context& ctx); - ~ddnf(); - virtual lbool query(expr* query); - virtual void reset_statistics(); - virtual void collect_statistics(statistics& st) const; - virtual void display_certificate(std::ostream& out) const; - virtual expr_ref get_answer(); + ~ddnf() override; + lbool query(expr* query) override; + void reset_statistics() override; + void collect_statistics(statistics& st) const override; + void display_certificate(std::ostream& out) const override; + expr_ref get_answer() override; }; class ddnf_node; diff --git a/src/muz/duality/duality_dl_interface.h b/src/muz/duality/duality_dl_interface.h index 506642217..8178618ae 100644 --- a/src/muz/duality/duality_dl_interface.h +++ b/src/muz/duality/duality_dl_interface.h @@ -41,33 +41,33 @@ namespace Duality { public: dl_interface(datalog::context& ctx); - ~dl_interface(); + ~dl_interface() override; - lbool query(expr* query); + lbool query(expr* query) override; - void cancel(); + void cancel() override; - void cleanup(); + void cleanup() override; - void display_certificate(std::ostream& out) const; + void display_certificate(std::ostream& out) const override; - void collect_statistics(statistics& st) const; + void collect_statistics(statistics& st) const override; - void reset_statistics(); + void reset_statistics() override; - expr_ref get_answer(); + expr_ref get_answer() override; - unsigned get_num_levels(func_decl* pred); + unsigned get_num_levels(func_decl* pred) override; - expr_ref get_cover_delta(int level, func_decl* pred); + expr_ref get_cover_delta(int level, func_decl* pred) override; - void add_cover(int level, func_decl* pred, expr* property); + void add_cover(int level, func_decl* pred, expr* property) override; - void updt_params(); + void updt_params() override; - model_ref get_model(); + model_ref get_model() override; - proof_ref get_proof(); + proof_ref get_proof() override; duality_data *dd(){return _d;} diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index f839c5c5a..fd3eae944 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -494,7 +494,7 @@ public: { } - virtual bool parse_file(char const * filename) { + bool parse_file(char const * filename) override { reset(); if (filename != 0) { set_path(filename); @@ -510,7 +510,7 @@ public: } } - virtual bool parse_string(char const * string) { + bool parse_string(char const * string) override { reset(); std::string s(string); std::istringstream is(s); @@ -1200,13 +1200,13 @@ public: m_short_sort(ctx.get_manager()), m_use_map_names(ctx.use_map_names()) { } - ~wpa_parser_impl() { + ~wpa_parser_impl() override { reset_dealloc_values(m_sort_contents); } void reset() { } - virtual bool parse_directory(char const * path) { + bool parse_directory(char const * path) override { bool result = false; try { result = parse_directory_core(path); diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 2610f821c..deb8887ec 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -166,10 +166,10 @@ public: m_arg_idx(0), m_t(0), m_bound(UINT_MAX) {} - virtual char const * get_usage() const { return "(forall (q) (=> (and body) head)) :optional-name :optional-recursion-bound"; } - virtual char const * get_descr(cmd_context & ctx) const { return "add a Horn rule."; } - virtual unsigned get_arity() const { return VAR_ARITY; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + char const * get_usage() const override { return "(forall (q) (=> (and body) head)) :optional-name :optional-recursion-bound"; } + char const * get_descr(cmd_context & ctx) const override { return "add a Horn rule."; } + unsigned get_arity() const override { return VAR_ARITY; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { switch(m_arg_idx) { case 0: return CPK_EXPR; case 1: return CPK_SYMBOL; @@ -177,23 +177,23 @@ public: default: return CPK_SYMBOL; } } - virtual void set_next_arg(cmd_context & ctx, expr * t) { + void set_next_arg(cmd_context & ctx, expr * t) override { m_t = t; m_arg_idx++; } - virtual void set_next_arg(cmd_context & ctx, symbol const & s) { + void set_next_arg(cmd_context & ctx, symbol const & s) override { m_name = s; m_arg_idx++; } - virtual void set_next_arg(cmd_context & ctx, unsigned bound) { + void set_next_arg(cmd_context & ctx, unsigned bound) override { m_bound = bound; m_arg_idx++; } - virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); m_t = nullptr; } - virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; } - virtual void finalize(cmd_context & ctx) { + void reset(cmd_context & ctx) override { m_dl_ctx->reset(); prepare(ctx); m_t = nullptr; } + void prepare(cmd_context& ctx) override { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; } + void finalize(cmd_context & ctx) override { } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { if (!m_t) throw cmd_exception("invalid rule, expected formula"); m_dl_ctx->add_rule(m_t, m_name, m_bound); } @@ -208,17 +208,17 @@ public: m_dl_ctx(dl_ctx), m_target(0) { } - virtual char const * get_usage() const { return "predicate"; } - virtual char const * get_main_descr() const { + char const * get_usage() const override { return "predicate"; } + char const * get_main_descr() const override { return "pose a query to a predicate based on the Horn rules."; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_target == 0) return CPK_FUNC_DECL; return parametric_cmd::next_arg_kind(ctx); } - virtual void set_next_arg(cmd_context & ctx, func_decl* t) { + void set_next_arg(cmd_context & ctx, func_decl* t) override { m_target = t; if (t->get_family_id() != null_family_id) { throw cmd_exception("Invalid query argument, expected uinterpreted function name, but argument is interpreted"); @@ -229,13 +229,13 @@ public: } } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { ctx.m(); // ensure manager is initialized. parametric_cmd::prepare(ctx); m_target = 0; } - virtual void execute(cmd_context& ctx) { + void execute(cmd_context& ctx) override { if (m_target == 0) { throw cmd_exception("invalid query command, argument expected"); } @@ -321,7 +321,7 @@ public: m_target = 0; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { m_dl_ctx->dlctx().collect_params(p); } @@ -385,30 +385,30 @@ public: m_dl_ctx(dl_ctx), m_domain(0) {} - virtual char const * get_usage() const { return " ( ...) *"; } - virtual char const * get_descr(cmd_context & ctx) const { return "declare new relation"; } - virtual unsigned get_arity() const { return VAR_ARITY; } + char const * get_usage() const override { return " ( ...) *"; } + char const * get_descr(cmd_context & ctx) const override { return "declare new relation"; } + unsigned get_arity() const override { return VAR_ARITY; } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { ctx.m(); // ensure manager is initialized. m_arg_idx = 0; m_query_arg_idx = 0; m_domain.reset(); m_kinds.reset(); } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { switch(m_query_arg_idx++) { case 0: return CPK_SYMBOL; // relation name case 1: return CPK_SORT_LIST; // arguments default: return CPK_SYMBOL; // optional representation specification } } - virtual void set_next_arg(cmd_context & ctx, unsigned num, sort * const * slist) { + void set_next_arg(cmd_context & ctx, unsigned num, sort * const * slist) override { m_domain.reset(); m_domain.append(num, slist); m_arg_idx++; } - virtual void set_next_arg(cmd_context & ctx, symbol const & s) { + void set_next_arg(cmd_context & ctx, symbol const & s) override { if(m_arg_idx==0) { m_rel_name = s; } @@ -418,7 +418,7 @@ public: } m_arg_idx++; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { if(m_arg_idx<2) { throw cmd_exception("at least 2 arguments expected"); } @@ -444,15 +444,15 @@ public: m_dl_ctx(dl_ctx) {} - virtual char const * get_usage() const { return " "; } - virtual char const * get_descr(cmd_context & ctx) const { return "declare constant as variable"; } - virtual unsigned get_arity() const { return 2; } + char const * get_usage() const override { return " "; } + char const * get_descr(cmd_context & ctx) const override { return "declare constant as variable"; } + unsigned get_arity() const override { return 2; } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { ctx.m(); // ensure manager is initialized. m_arg_idx = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { SASSERT(m_arg_idx <= 1); if (m_arg_idx == 0) { return CPK_SYMBOL; @@ -460,17 +460,17 @@ public: return CPK_SORT; } - virtual void set_next_arg(cmd_context & ctx, sort* s) { + void set_next_arg(cmd_context & ctx, sort* s) override { m_var_sort = s; ++m_arg_idx; } - virtual void set_next_arg(cmd_context & ctx, symbol const & s) { + void set_next_arg(cmd_context & ctx, symbol const & s) override { m_var_name = s; ++m_arg_idx; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { ast_manager& m = ctx.m(); func_decl_ref var(m.mk_func_decl(m_var_name, 0, static_cast(0), m_var_sort), m); ctx.insert(var); @@ -489,10 +489,10 @@ public: m_dl_ctx(dl_ctx) {} - virtual char const * get_usage() const { return ""; } - virtual char const * get_descr(cmd_context & ctx) const { return "push the fixedpoint context"; } - virtual unsigned get_arity() const { return 0; } - virtual void execute(cmd_context & ctx) { + char const * get_usage() const override { return ""; } + char const * get_descr(cmd_context & ctx) const override { return "push the fixedpoint context"; } + unsigned get_arity() const override { return 0; } + void execute(cmd_context & ctx) override { m_dl_ctx->push(); } }; @@ -508,10 +508,10 @@ public: m_dl_ctx(dl_ctx) {} - virtual char const * get_usage() const { return ""; } - virtual char const * get_descr(cmd_context & ctx) const { return "pop the fixedpoint context"; } - virtual unsigned get_arity() const { return 0; } - virtual void execute(cmd_context & ctx) { + char const * get_usage() const override { return ""; } + char const * get_descr(cmd_context & ctx) const override { return "pop the fixedpoint context"; } + unsigned get_arity() const override { return 0; } + void execute(cmd_context & ctx) override { m_dl_ctx->pop(); } }; diff --git a/src/muz/fp/dl_register_engine.h b/src/muz/fp/dl_register_engine.h index 11f778346..e401c141a 100644 --- a/src/muz/fp/dl_register_engine.h +++ b/src/muz/fp/dl_register_engine.h @@ -27,8 +27,8 @@ namespace datalog { context* m_ctx; public: register_engine(); - engine_base* mk_engine(DL_ENGINE engine_type); - void set_context(context* ctx) { m_ctx = ctx; } + engine_base* mk_engine(DL_ENGINE engine_type) override; + void set_context(context* ctx) override { m_ctx = ctx; } }; } diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 5db57a12c..273489164 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -365,43 +365,43 @@ public: m_imp = alloc(imp, t, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(horn_tactic, m_is_simplify, m, m_params); } - virtual ~horn_tactic() { + ~horn_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_imp->collect_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { m_imp->collect_statistics(st); st.copy(m_stats); } - virtual void reset_statistics() { + void reset_statistics() override { m_stats.reset(); m_imp->reset_statistics(); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; m_imp->collect_statistics(m_stats); dealloc(m_imp); diff --git a/src/muz/pdr/pdr_dl_interface.h b/src/muz/pdr/pdr_dl_interface.h index 884f89e4b..1a0b04635 100644 --- a/src/muz/pdr/pdr_dl_interface.h +++ b/src/muz/pdr/pdr_dl_interface.h @@ -47,29 +47,29 @@ namespace pdr { public: dl_interface(datalog::context& ctx); - ~dl_interface(); + ~dl_interface() override; - virtual lbool query(expr* query); + lbool query(expr* query) override; - virtual void display_certificate(std::ostream& out) const; + void display_certificate(std::ostream& out) const override; - virtual void collect_statistics(statistics& st) const; + void collect_statistics(statistics& st) const override; - virtual void reset_statistics(); + void reset_statistics() override; - virtual expr_ref get_answer(); + expr_ref get_answer() override; - virtual unsigned get_num_levels(func_decl* pred); + unsigned get_num_levels(func_decl* pred) override; - virtual expr_ref get_cover_delta(int level, func_decl* pred); + expr_ref get_cover_delta(int level, func_decl* pred) override; - virtual void add_cover(int level, func_decl* pred, expr* property); + void add_cover(int level, func_decl* pred, expr* property) override; - virtual void updt_params(); + void updt_params() override; - virtual model_ref get_model(); + model_ref get_model() override; - virtual proof_ref get_proof(); + proof_ref get_proof() override; }; } diff --git a/src/muz/pdr/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h index e0feda310..a75b347a4 100644 --- a/src/muz/pdr/pdr_generalizers.h +++ b/src/muz/pdr/pdr_generalizers.h @@ -30,8 +30,8 @@ namespace pdr { unsigned m_failure_limit; public: core_bool_inductive_generalizer(context& ctx, unsigned failure_limit) : core_generalizer(ctx), m_failure_limit(failure_limit) {} - virtual ~core_bool_inductive_generalizer() {} - virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); + ~core_bool_inductive_generalizer() override {} + void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; }; template @@ -61,17 +61,17 @@ namespace pdr { bool substitute_alias(rational const&r, expr* x, expr* e, expr_ref& result); public: core_arith_inductive_generalizer(context& ctx); - virtual ~core_arith_inductive_generalizer() {} - virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); + ~core_arith_inductive_generalizer() override {} + void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; }; class core_farkas_generalizer : public core_generalizer { farkas_learner m_farkas_learner; public: core_farkas_generalizer(context& ctx, ast_manager& m, smt_params& p); - virtual ~core_farkas_generalizer() {} - virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); - virtual void collect_statistics(statistics& st) const; + ~core_farkas_generalizer() override {} + void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; + void collect_statistics(statistics& st) const override; }; @@ -85,26 +85,26 @@ namespace pdr { bool is_unsat(expr_ref_vector const& As, expr* B); public: core_convex_hull_generalizer(context& ctx, bool is_closure); - virtual ~core_convex_hull_generalizer() {} - virtual void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); - virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); + ~core_convex_hull_generalizer() override {} + void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) override; + void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; }; class core_multi_generalizer : public core_generalizer { core_bool_inductive_generalizer m_gen; public: core_multi_generalizer(context& ctx, unsigned max_failures): core_generalizer(ctx), m_gen(ctx, max_failures) {} - virtual ~core_multi_generalizer() {} - virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); - virtual void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); + ~core_multi_generalizer() override {} + void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; + void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) override; }; class core_induction_generalizer : public core_generalizer { class imp; public: core_induction_generalizer(context& ctx): core_generalizer(ctx) {} - virtual ~core_induction_generalizer() {} - virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); + ~core_induction_generalizer() override {} + void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; }; }; #endif diff --git a/src/muz/pdr/pdr_smt_context_manager.h b/src/muz/pdr/pdr_smt_context_manager.h index 735b2cd62..747cd6457 100644 --- a/src/muz/pdr/pdr_smt_context_manager.h +++ b/src/muz/pdr/pdr_smt_context_manager.h @@ -59,15 +59,15 @@ namespace pdr { smt::kernel & m_context; public: _smt_context(smt::kernel & ctx, smt_context_manager& p, app* pred); - virtual ~_smt_context() {} - virtual void assert_expr(expr* e); - virtual lbool check(expr_ref_vector& assumptions); - virtual void get_model(model_ref& model); - virtual proof* get_proof(); - virtual void push() { m_context.push(); } - virtual void pop() { m_context.pop(1); } - virtual unsigned get_unsat_core_size() { return m_context.get_unsat_core_size(); } - virtual expr* get_unsat_core_expr(unsigned i) { return m_context.get_unsat_core_expr(i); } + ~_smt_context() override {} + void assert_expr(expr* e) override; + lbool check(expr_ref_vector& assumptions) override; + void get_model(model_ref& model) override; + proof* get_proof() override; + void push() override { m_context.push(); } + void pop() override { m_context.pop(1); } + unsigned get_unsat_core_size() override { return m_context.get_unsat_core_size(); } + expr* get_unsat_core_expr(unsigned i) override { return m_context.get_unsat_core_expr(i); } }; class smt_context_manager { diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index ddda295cd..a6298cf22 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -192,8 +192,8 @@ namespace datalog { const unsigned * cols1, const unsigned * cols2) : convenient_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2), m_join(j) {} - virtual ~join_fn() {} - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + ~join_fn() override {} + relation_base * operator()(const relation_base & r1, const relation_base & r2) override { check_relation const& t1 = get(r1); check_relation const& t2 = get(r2); check_relation_plugin& p = t1.get_plugin(); @@ -221,8 +221,8 @@ namespace datalog { : convenient_join_project_fn(o1_sig, o2_sig, col_cnt, cols1, cols2, removed_col_cnt, removed_cols), m_join(j) {} - virtual ~join_project_fn() {} - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + ~join_project_fn() override {} + relation_base * operator()(const relation_base & r1, const relation_base & r2) override { check_relation const& t1 = get(r1); check_relation const& t2 = get(r2); check_relation_plugin& p = t1.get_plugin(); @@ -491,7 +491,7 @@ namespace datalog { public: union_fn(relation_union_fn* m): m_union(m) {} - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) override { TRACE("doc", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); check_relation& r = get(_r); check_relation const& src = get(_src); @@ -529,9 +529,9 @@ namespace datalog { m_filter(f) { } - virtual ~filter_identical_fn() {} + ~filter_identical_fn() override {} - virtual void operator()(relation_base & _r) { + void operator()(relation_base & _r) override { check_relation& r = get(_r); check_relation_plugin& p = r.get_plugin(); ast_manager& m = p.m; @@ -565,9 +565,9 @@ namespace datalog { m_condition(condition) { } - virtual ~filter_interpreted_fn() {} + ~filter_interpreted_fn() override {} - virtual void operator()(relation_base & tb) { + void operator()(relation_base & tb) override { check_relation& r = get(tb); check_relation_plugin& p = r.get_plugin(); expr_ref fml = r.m_fml; @@ -592,9 +592,9 @@ namespace datalog { m_project(p) { } - virtual ~project_fn() {} + ~project_fn() override {} - virtual relation_base * operator()(const relation_base & tb) { + relation_base * operator()(const relation_base & tb) override { check_relation const& t = get(tb); check_relation_plugin& p = t.get_plugin(); relation_base* r = (*m_project)(t.rb()); @@ -620,9 +620,9 @@ namespace datalog { m_permute(permute) { } - virtual ~rename_fn() {} + ~rename_fn() override {} - virtual relation_base * operator()(const relation_base & _t) { + relation_base * operator()(const relation_base & _t) override { check_relation const& t = get(_t); check_relation_plugin& p = t.get_plugin(); relation_signature const& sig = get_result_signature(); @@ -649,8 +649,8 @@ namespace datalog { m_val(val), m_col(col) {} - virtual ~filter_equal_fn() { } - virtual void operator()(relation_base & tb) { + ~filter_equal_fn() override { } + void operator()(relation_base & tb) override { check_relation & t = get(tb); check_relation_plugin& p = t.get_plugin(); (*m_filter)(t.rb()); @@ -682,7 +682,7 @@ namespace datalog { SASSERT(joined_col_cnt > 0); } - virtual void operator()(relation_base& tb, const relation_base& negb) { + void operator()(relation_base& tb, const relation_base& negb) override { check_relation& t = get(tb); check_relation const& n = get(negb); check_relation_plugin& p = t.get_plugin(); @@ -763,9 +763,9 @@ namespace datalog { m_xform(xform) {} - virtual ~filter_proj_fn() {} + ~filter_proj_fn() override {} - virtual relation_base* operator()(const relation_base & tb) { + relation_base* operator()(const relation_base & tb) override { check_relation const & t = get(tb); check_relation_plugin& p = t.get_plugin(); relation_base* r = (*m_xform)(t.rb()); diff --git a/src/muz/rel/check_relation.h b/src/muz/rel/check_relation.h index 0fbb2a269..8fbce4184 100644 --- a/src/muz/rel/check_relation.h +++ b/src/muz/rel/check_relation.h @@ -38,20 +38,20 @@ namespace datalog { expr_ref mk_eq(relation_fact const& f) const; public: check_relation(check_relation_plugin& p, relation_signature const& s, relation_base* r); - virtual ~check_relation(); - virtual void reset(); - virtual void add_fact(const relation_fact & f); - virtual void add_new_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual check_relation * clone() const; - virtual check_relation * complement(func_decl*) const; - virtual void to_formula(expr_ref& fml) const; + ~check_relation() override; + void reset() override; + void add_fact(const relation_fact & f) override; + void add_new_fact(const relation_fact & f) override; + bool contains_fact(const relation_fact & f) const override; + check_relation * clone() const override; + check_relation * complement(func_decl*) const override; + void to_formula(expr_ref& fml) const override; check_relation_plugin& get_plugin() const; - virtual bool fast_empty() const; - virtual bool empty() const; - virtual void display(std::ostream& out) const; - virtual bool is_precise() const { return m_relation->is_precise(); } - virtual unsigned get_size_estimate_rows() const { return m_relation->get_size_estimate_rows(); } + bool fast_empty() const override; + bool empty() const override; + void display(std::ostream& out) const override; + bool is_precise() const override { return m_relation->is_precise(); } + unsigned get_size_estimate_rows() const override { return m_relation->get_size_estimate_rows(); } relation_base& rb() { return *m_relation; } relation_base const& rb() const { return *m_relation; } expr_ref ground(expr* fml) const; @@ -90,39 +90,39 @@ namespace datalog { unsigned_vector const& cols1, unsigned_vector const& cols2); public: check_relation_plugin(relation_manager& rm); - ~check_relation_plugin(); + ~check_relation_plugin() override; void set_plugin(relation_plugin* p) { m_base = p; } - virtual bool can_handle_signature(const relation_signature & s); + bool can_handle_signature(const relation_signature & s) override; static symbol get_name() { return symbol("check_relation"); } - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_join_fn * mk_join_project_fn( + relation_base * mk_empty(const relation_signature & s) override; + relation_base * mk_full(func_decl* p, const relation_signature & s) override; + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_join_fn * mk_join_project_fn( const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn( + unsigned removed_col_cnt, const unsigned * removed_cols) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; + relation_intersection_filter_fn * mk_filter_by_negation_fn( const relation_base& t, const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, - const unsigned *negated_cols); - virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( + const unsigned *negated_cols) override; + relation_transformer_fn * mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, - unsigned removed_col_cnt, const unsigned * removed_cols); + unsigned removed_col_cnt, const unsigned * removed_cols) override; void verify_join(relation_base const& t1, relation_base const& t2, relation_base const& t, unsigned_vector const& cols1, unsigned_vector const& cols2); diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index 904faf71f..5ca84c895 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -423,17 +423,17 @@ namespace datalog { const row_interface & m_parent; unsigned m_index; protected: - virtual bool is_finished() const { return m_index==m_parent.size(); } + bool is_finished() const override { return m_index==m_parent.size(); } public: fact_row_iterator(const row_interface & row, bool finished) : m_parent(row), m_index(finished ? row.size() : 0) {} - virtual table_element operator*() { + table_element operator*() override { SASSERT(!is_finished()); return m_parent[m_index]; } - virtual void operator++() { + void operator++() override { m_index++; SASSERT(m_index<=m_parent.size()); } diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 4e59e9258..277f37f70 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -220,7 +220,7 @@ namespace datalog { */ class mutator_fn : public base_fn { public: - virtual ~mutator_fn() {} + ~mutator_fn() override {} virtual void operator()(base_object & t) = 0; @@ -629,19 +629,19 @@ namespace datalog { class identity_transformer_fn : public transformer_fn { public: - virtual base_object * operator()(const base_object & t) { + base_object * operator()(const base_object & t) override { return t.clone(); } }; class identity_mutator_fn : public mutator_fn { public: - virtual void operator()(base_object & t) {}; + void operator()(base_object & t) override {}; }; class identity_intersection_filter_fn : public intersection_filter_fn { public: - virtual void operator()(base_object & t, const base_object & neg) {}; + void operator()(base_object & t, const base_object & neg) override {}; }; class default_permutation_rename_fn : public transformer_fn { @@ -655,11 +655,11 @@ namespace datalog { : m_permutation(o.get_signature().size(), permutation), m_renamers_initialized(false) {} - ~default_permutation_rename_fn() { + ~default_permutation_rename_fn() override { dealloc_ptr_vector_content(m_renamers); } - base_object * operator()(const base_object & o) { + base_object * operator()(const base_object & o) override { const base_object * res = &o; scoped_rel res_scoped; if(m_renamers_initialized) { @@ -803,11 +803,11 @@ namespace datalog { protected: relation_base(relation_plugin & plugin, const relation_signature & s) : base_ancestor(plugin, s) {} - virtual ~relation_base() {} + ~relation_base() override {} public: virtual relation_base * complement(func_decl* p) const = 0; - virtual void reset(); + void reset() override; virtual void display_tuples(func_decl & pred, std::ostream & out) const { out << "Tuples in " << pred.get_name() << ": \n"; @@ -1022,7 +1022,7 @@ namespace datalog { table_plugin(symbol const& n, relation_manager & manager) : plugin_object(n, manager) {} public: - virtual bool can_handle_signature(const table_signature & s) { return s.functional_columns()==0; } + bool can_handle_signature(const table_signature & s) override { return s.functional_columns()==0; } protected: /** @@ -1044,17 +1044,17 @@ namespace datalog { protected: table_base(table_plugin & plugin, const table_signature & s) : base_ancestor(plugin, s) {} - virtual ~table_base() {} + ~table_base() override {} public: - virtual table_base * clone() const; + table_base * clone() const override; virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; - virtual bool empty() const; + bool empty() const override; /** \brief Return true if table contains fact that corresponds to \c f in all non-functional columns. */ - virtual bool contains_fact(const table_fact & f) const; + bool contains_fact(const table_fact & f) const override; /** \brief If \c f (i.e. its non-functional part) is not present in the table, @@ -1082,11 +1082,11 @@ namespace datalog { virtual void remove_fact(table_element const* fact) = 0; virtual void remove_facts(unsigned fact_cnt, const table_fact * facts); virtual void remove_facts(unsigned fact_cnt, const table_element * facts); - virtual void reset(); + void reset() override; class row_interface; - virtual void display(std::ostream & out) const; + void display(std::ostream & out) const override; /** \brief Convert table to a formula that encodes the table. @@ -1245,9 +1245,9 @@ namespace datalog { public: caching_row_interface(const table_base & parent) : row_interface(parent) {} - virtual void get_fact(table_fact & result) const = 0; + void get_fact(table_fact & result) const override = 0; - virtual table_element operator[](unsigned col) const { + table_element operator[](unsigned col) const override { ensure_populated(); return m_current[col]; } diff --git a/src/muz/rel/dl_bound_relation.cpp b/src/muz/rel/dl_bound_relation.cpp index 9dc0eb8d5..74b87d96e 100644 --- a/src/muz/rel/dl_bound_relation.cpp +++ b/src/muz/rel/dl_bound_relation.cpp @@ -79,7 +79,7 @@ namespace datalog { : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2) { } - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + relation_base * operator()(const relation_base & _r1, const relation_base & _r2) override { bound_relation const& r1 = get(_r1); bound_relation const& r2 = get(_r2); bound_relation_plugin& p = r1.get_plugin(); @@ -104,7 +104,7 @@ namespace datalog { : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { } - virtual relation_base * operator()(const relation_base & _r) { + relation_base * operator()(const relation_base & _r) override { bound_relation const& r = get(_r); bound_relation_plugin& p = r.get_plugin(); bound_relation* result = get(p.mk_full(0, get_result_signature())); @@ -124,7 +124,7 @@ namespace datalog { : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { } - virtual relation_base * operator()(const relation_base & _r) { + relation_base * operator()(const relation_base & _r) override { bound_relation const& r = get(_r); bound_relation_plugin& p = r.get_plugin(); bound_relation* result = get(p.mk_full(0, get_result_signature())); @@ -148,7 +148,7 @@ namespace datalog { union_fn(bool is_widen) : m_is_widen(is_widen) { } - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) override { TRACE("bound_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); get(_r).mk_union(get(_src), get(_delta), m_is_widen); } @@ -160,7 +160,7 @@ namespace datalog { union_fn_i(bool is_widen) : m_is_widen(is_widen) { } - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) override { TRACE("bound_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); get(_r).mk_union_i(get_interval_relation(_src), get(_delta), m_is_widen); TRACE("bound_relation", _r.display(tout << "dst':\n");); @@ -197,7 +197,7 @@ namespace datalog { filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) : m_cols(col_cnt, identical_cols) {} - virtual void operator()(relation_base & r) { + void operator()(relation_base & r) override { for (unsigned i = 1; i < m_cols.size(); ++i) { get(r).equate(m_cols[0], m_cols[i]); } @@ -216,7 +216,7 @@ namespace datalog { public: filter_equal_fn(relation_element const& value, unsigned col) {} - virtual void operator()(relation_base & r) { } + void operator()(relation_base & r) override { } }; relation_mutator_fn * bound_relation_plugin::mk_filter_equal_fn(const relation_base & r, @@ -342,7 +342,7 @@ namespace datalog { // x < y + z // - void operator()(relation_base& t) { + void operator()(relation_base& t) override { TRACE("dl", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); bound_relation& r = get(t); switch(m_kind) { @@ -370,11 +370,11 @@ namespace datalog { TRACE("dl", t.display(tout << "result\n");); } - bool supports_attachment(relation_base& t) { + bool supports_attachment(relation_base& t) override { return is_interval_relation(t); } - void attach(relation_base& t) { + void attach(relation_base& t) override { SASSERT(is_interval_relation(t)); interval_relation& r = get_interval_relation(t); m_interval = &r; diff --git a/src/muz/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h index 3dec9d313..da1aad71a 100644 --- a/src/muz/rel/dl_bound_relation.h +++ b/src/muz/rel/dl_bound_relation.h @@ -47,29 +47,29 @@ namespace datalog { bool_rewriter m_bsimp; public: bound_relation_plugin(relation_manager& m); - virtual bool can_handle_signature(const relation_signature & s); + bool can_handle_signature(const relation_signature & s) override; static symbol get_name() { return symbol("bound_relation"); } - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - - virtual relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { return 0; } + relation_base * mk_empty(const relation_signature & s) override; + relation_base * mk_full(func_decl* p, const relation_signature & s) override; + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; + + relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) override { return 0; } #if 0 @@ -123,12 +123,12 @@ namespace datalog { bound_relation(bound_relation_plugin& p, relation_signature const& s, bool is_empty); bound_relation& operator=(bound_relation const& other); - virtual bool empty() const { return m_empty; } - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual bound_relation * clone() const; - virtual bound_relation * complement(func_decl* p) const; - virtual void to_formula(expr_ref& fml) const; + bool empty() const override { return m_empty; } + void add_fact(const relation_fact & f) override; + bool contains_fact(const relation_fact & f) const override; + bound_relation * clone() const override; + bound_relation * complement(func_decl* p) const override; + void to_formula(expr_ref& fml) const override; bound_relation_plugin& get_plugin() const; void mk_union_i(interval_relation const& src, bound_relation* delta, bool is_widen); @@ -141,28 +141,28 @@ namespace datalog { bool is_lt(unsigned i, unsigned j) const; - virtual bool is_precise() const { return false; } + bool is_precise() const override { return false; } private: typedef uint_set2 T; - virtual T mk_intersect(T const& t1, T const& t2, bool& is_empty) const; + T mk_intersect(T const& t1, T const& t2, bool& is_empty) const override; - virtual T mk_widen(T const& t1, T const& t2) const; + T mk_widen(T const& t1, T const& t2) const override; - virtual T mk_unite(T const& t1, T const& t2) const; + T mk_unite(T const& t1, T const& t2) const override; - virtual T mk_eq(union_find<> const& old_eqs, union_find<> const& new_eqs, T const& t) const; + T mk_eq(union_find<> const& old_eqs, union_find<> const& new_eqs, T const& t) const override; - virtual void mk_rename_elem(T& i, unsigned col_cnt, unsigned const* cycle); + void mk_rename_elem(T& i, unsigned col_cnt, unsigned const* cycle) override; - virtual bool is_subset_of(T const& t1, T const& t2) const; + bool is_subset_of(T const& t1, T const& t2) const override; - virtual bool is_full(T const& t) const; + bool is_full(T const& t) const override; - virtual bool is_empty(unsigned idx, T const& t) const; + bool is_empty(unsigned idx, T const& t) const override; - virtual void display_index(unsigned idx, T const& t, std::ostream& out) const; + void display_index(unsigned idx, T const& t, std::ostream& out) const override; void normalize(T const& src, T& dst) const; diff --git a/src/muz/rel/dl_check_table.cpp b/src/muz/rel/dl_check_table.cpp index 0c4be18f1..b7d22159e 100644 --- a/src/muz/rel/dl_check_table.cpp +++ b/src/muz/rel/dl_check_table.cpp @@ -65,7 +65,7 @@ namespace datalog { m_checker = p.get_manager().mk_join_fn(checker(t1), checker(t2), col_cnt, cols1, cols2); } - virtual table_base* operator()(const table_base & t1, const table_base & t2) { + table_base* operator()(const table_base & t1, const table_base & t2) override { IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2)); table_base* tchecker = (*m_checker)(checker(t1), checker(t2)); @@ -93,7 +93,7 @@ namespace datalog { m_checker = p.get_manager().mk_join_project_fn(checker(t1), checker(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); } - virtual table_base* operator()(const table_base & t1, const table_base & t2) { + table_base* operator()(const table_base & t1, const table_base & t2) override { table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2)); table_base* tchecker = (*m_checker)(checker(t1), checker(t2)); check_table* result = alloc(check_table, get(t1).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); @@ -119,7 +119,7 @@ namespace datalog { m_checker = p.get_manager().mk_union_fn(checker(tgt), checker(src), checker(delta)); } - virtual void operator()(table_base& tgt, const table_base& src, table_base* delta) { + void operator()(table_base& tgt, const table_base& src, table_base* delta) override { IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); (*m_tocheck)(tocheck(tgt), tocheck(src), tocheck(delta)); (*m_checker)(checker(tgt), checker(src), checker(delta)); @@ -147,7 +147,7 @@ namespace datalog { m_tocheck = p.get_manager().mk_project_fn(tocheck(t), col_cnt, removed_cols); } - table_base* operator()(table_base const& src) { + table_base* operator()(table_base const& src) override { table_base* tchecker = (*m_checker)(checker(src)); table_base* ttocheck = (*m_tocheck)(tocheck(src)); check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker); @@ -171,7 +171,7 @@ namespace datalog { m_tocheck = p.get_manager().mk_select_equal_and_project_fn(tocheck(t), value, col); } - table_base* operator()(table_base const& src) { + table_base* operator()(table_base const& src) override { table_base* tchecker = (*m_checker)(checker(src)); table_base* ttocheck = (*m_tocheck)(tocheck(src)); check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker); @@ -196,7 +196,7 @@ namespace datalog { m_tocheck = p.get_manager().mk_rename_fn(tocheck(t), cycle_len, cycle); } - table_base* operator()(table_base const& src) { + table_base* operator()(table_base const& src) override { IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); table_base* tchecker = (*m_checker)(checker(src)); table_base* ttocheck = (*m_tocheck)(tocheck(src)); @@ -222,7 +222,7 @@ namespace datalog { m_tocheck = p.get_manager().mk_filter_identical_fn(tocheck(t), cnt, cols); } - void operator()(table_base & t) { + void operator()(table_base & t) override { (*m_checker)(checker(t)); (*m_tocheck)(tocheck(t)); get(t).well_formed(); @@ -247,7 +247,7 @@ namespace datalog { m_tocheck = p.get_manager().mk_filter_equal_fn(tocheck(t), v, col); } - virtual void operator()(table_base& src) { + void operator()(table_base& src) override { (*m_checker)(checker(src)); (*m_tocheck)(tocheck(src)); get(src).well_formed(); @@ -271,7 +271,7 @@ namespace datalog { m_tocheck = p.get_manager().mk_filter_interpreted_fn(tocheck(t), condition); } - virtual void operator()(table_base& src) { + void operator()(table_base& src) override { (*m_checker)(checker(src)); (*m_tocheck)(tocheck(src)); get(src).well_formed(); @@ -296,7 +296,7 @@ namespace datalog { m_tocheck = p.get_manager().mk_filter_interpreted_and_project_fn(tocheck(t), condition, removed_col_cnt, removed_cols); } - table_base* operator()(table_base const& src) { + table_base* operator()(table_base const& src) override { table_base* tchecker = (*m_checker)(checker(src)); table_base* ttocheck = (*m_tocheck)(tocheck(src)); check_table* result = alloc(check_table, get(src).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); @@ -325,7 +325,7 @@ namespace datalog { m_tocheck = p.get_manager().mk_filter_by_negation_fn(tocheck(t), tocheck(negated_obj), joined_col_cnt, t_cols, negated_cols); } - virtual void operator()(table_base& src, table_base const& negated_obj) { + void operator()(table_base& src, table_base const& negated_obj) override { IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); (*m_checker)(checker(src), checker(negated_obj)); (*m_tocheck)(tocheck(src), tocheck(negated_obj)); diff --git a/src/muz/rel/dl_check_table.h b/src/muz/rel/dl_check_table.h index 412dd2dbc..77d9d0cdf 100644 --- a/src/muz/rel/dl_check_table.h +++ b/src/muz/rel/dl_check_table.h @@ -53,34 +53,34 @@ namespace datalog { m_checker(*manager.get_table_plugin(checker)), m_tocheck(*manager.get_table_plugin(tocheck)), m_count(0) {} - virtual table_base * mk_empty(const table_signature & s); + table_base * mk_empty(const table_signature & s) override; - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols); - virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, - const table_element & value, unsigned col); - virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, - unsigned col); - virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition); - virtual table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); - virtual table_intersection_filter_fn * mk_filter_by_negation_fn( - const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); + table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) override; + table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta) override; + table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col) override; + table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, + unsigned col) override; + table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition) override; + table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) override; + table_intersection_filter_fn * mk_filter_by_negation_fn( + const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) override; - virtual bool can_handle_signature(table_signature const& s); + bool can_handle_signature(table_signature const& s) override; private: static check_table& get(table_base& r); @@ -106,7 +106,7 @@ namespace datalog { check_table(check_table_plugin & p, const table_signature & sig); check_table(check_table_plugin & p, const table_signature & sig, table_base* tocheck, table_base* checker); - virtual ~check_table(); + ~check_table() override; bool well_formed() const; @@ -116,18 +116,18 @@ namespace datalog { return static_cast(table_base::get_plugin()); } - virtual bool empty() const; - virtual void add_fact(const table_fact & f); - virtual void remove_fact(const table_element* fact); - virtual bool contains_fact(const table_fact & f) const; - virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; - virtual table_base * clone() const; + bool empty() const override; + void add_fact(const table_fact & f) override; + void remove_fact(const table_element* fact) override; + bool contains_fact(const table_fact & f) const override; + table_base * complement(func_decl* p, const table_element * func_columns = 0) const override; + table_base * clone() const override; - virtual iterator begin() const { SASSERT(well_formed()); return m_tocheck->begin(); } - virtual iterator end() const { return m_tocheck->end(); } + iterator begin() const override { SASSERT(well_formed()); return m_tocheck->begin(); } + iterator end() const override { return m_tocheck->end(); } - virtual unsigned get_size_estimate_rows() const { return m_tocheck->get_size_estimate_rows(); } - virtual unsigned get_size_estimate_bytes() const { return m_tocheck->get_size_estimate_bytes(); } + unsigned get_size_estimate_rows() const override { return m_tocheck->get_size_estimate_rows(); } + unsigned get_size_estimate_bytes() const override { return m_tocheck->get_size_estimate_bytes(); } }; }; diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 6ac33ae91..51ec7643c 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -97,7 +97,7 @@ namespace datalog { void start_rule(rule * r) { SASSERT(!m_current); m_current=r; } void finish_rule() { m_current = 0; } - virtual void notify(instruction * i) { + void notify(instruction * i) override { if(m_current) { i->set_accounting_parent_object(m_parent.m_context, m_current); } diff --git a/src/muz/rel/dl_external_relation.cpp b/src/muz/rel/dl_external_relation.cpp index ff9bef40e..403c5cbd3 100644 --- a/src/muz/rel/dl_external_relation.cpp +++ b/src/muz/rel/dl_external_relation.cpp @@ -195,7 +195,7 @@ namespace datalog { m_join_fn = m.mk_func_decl(fid, OP_RA_JOIN, params.size(), params.c_ptr(), 2, domain); } - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + relation_base * operator()(const relation_base & r1, const relation_base & r2) override { expr_ref res(m_plugin.get_ast_manager()); m_args[0] = get(r1).get_relation(); m_args[1] = get(r2).get_relation(); @@ -231,7 +231,7 @@ namespace datalog { m_project_fn = m.mk_func_decl(fid, OP_RA_PROJECT, params.size(), params.c_ptr(), 1, &relation_sort); } - virtual relation_base * operator()(const relation_base & r) { + relation_base * operator()(const relation_base & r) override { expr_ref res(m_plugin.get_ast_manager()); expr* rel = get(r).get_relation(); m_plugin.reduce(m_project_fn, 1, &rel, res); @@ -265,7 +265,7 @@ namespace datalog { m_rename_fn = m.mk_func_decl(fid, OP_RA_RENAME, params.size(), params.c_ptr(), 1, &relation_sort); } - virtual relation_base * operator()(const relation_base & r) { + relation_base * operator()(const relation_base & r) override { expr* rel = get(r).get_relation(); expr_ref res(m_plugin.get_ast_manager()); m_args[0] = rel; @@ -298,7 +298,7 @@ namespace datalog { m_union_fn = m.mk_func_decl(p.get_family_id(), k, 0, 0, 2, domain); } - virtual void operator()(relation_base & r, const relation_base & src, relation_base * delta) { + void operator()(relation_base & r, const relation_base & src, relation_base * delta) override { ast_manager& m = m_plugin.get_ast_manager(); expr_ref_vector res(m); m_args[0] = get(r).get_relation(); @@ -342,7 +342,7 @@ namespace datalog { SASSERT(p.get_ast_manager().is_bool(condition)); } - virtual void operator()(relation_base & r) { + void operator()(relation_base & r) override { SASSERT(m_plugin.check_kind(r)); expr* arg = get(r).get_relation(); m_plugin.reduce_assign(m_filter_fn, 1, &arg, 1, &arg); @@ -396,7 +396,7 @@ namespace datalog { } } - virtual void operator()(relation_base & r) { + void operator()(relation_base & r) override { expr* r0 = get(r).get_relation(); for (unsigned i = 0; i < m_filter_fn.size(); ++i) { m_plugin.reduce_assign(m_filter_fn[i].get(), 1, &r0, 1, &r0); @@ -436,7 +436,7 @@ namespace datalog { m_negated_filter_fn = m.mk_func_decl(fid, OP_RA_NEGATION_FILTER, params.size(), params.c_ptr(), 2, domain); } - void operator()(relation_base & t, const relation_base & negated_obj) { + void operator()(relation_base & t, const relation_base & negated_obj) override { m_args[0] = get(t).get_relation(); m_args[1] = get(negated_obj).get_relation(); m_plugin.reduce_assign(m_negated_filter_fn.get(), 2, m_args, 1, m_args); diff --git a/src/muz/rel/dl_external_relation.h b/src/muz/rel/dl_external_relation.h index 0dfb4a7f2..485e03618 100644 --- a/src/muz/rel/dl_external_relation.h +++ b/src/muz/rel/dl_external_relation.h @@ -54,30 +54,30 @@ namespace datalog { public: external_relation_plugin(external_relation_context& ctx, relation_manager & m); - virtual bool can_handle_signature(const relation_signature & s) { return true; } + bool can_handle_signature(const relation_signature & s) override { return true; } static symbol get_name() { return symbol("external_relation"); } - virtual relation_base * mk_empty(const relation_signature & s); + relation_base * mk_empty(const relation_signature & s) override; - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; + relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) override; private: @@ -123,28 +123,28 @@ namespace datalog { void mk_accessor(decl_kind k, func_decl_ref& fn, const relation_fact& f, bool destructive, expr_ref& res) const; external_relation(external_relation_plugin & p, const relation_signature & s, expr* r); - virtual ~external_relation(); + ~external_relation() override; public: external_relation_plugin & get_plugin() const; - virtual bool empty() const; + bool empty() const override; - virtual void add_fact(const relation_fact & f); + void add_fact(const relation_fact & f) override; - virtual bool contains_fact(const relation_fact & f) const; + bool contains_fact(const relation_fact & f) const override; - virtual external_relation * clone() const; + external_relation * clone() const override; - virtual external_relation * complement(func_decl*) const; + external_relation * complement(func_decl*) const override; - virtual void display(std::ostream & out) const; + void display(std::ostream & out) const override; - virtual void display_tuples(func_decl & pred, std::ostream & out) const; + void display_tuples(func_decl & pred, std::ostream & out) const override; expr* get_relation() const { return m_rel.get(); } - virtual void to_formula(expr_ref& fml) const { fml = get_relation(); } + void to_formula(expr_ref& fml) const override { fml = get_relation(); } }; diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 163ba1b0b..4cb683df1 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -333,7 +333,7 @@ namespace datalog { : convenient_relation_join_fn(sig1, sig2, col_cnt, cols1, cols2), m_plugin(plugin) {} - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + relation_base * operator()(const relation_base & r1, const relation_base & r2) override { scoped_rel r1_conv; if(&r1.get_plugin()!=&m_plugin) { r1_conv = convert(r1); @@ -390,7 +390,7 @@ namespace datalog { relation_vector & rjoins) : m_parent(parent), m_r1(r1), m_r2(r2), m_rjoins(rjoins) {} - virtual bool operator()(table_element * func_columns) { + bool operator()(table_element * func_columns) override { const relation_base & or1 = m_r1.get_inner_rel(func_columns[0]); const relation_base & or2 = m_r2.get_inner_rel(func_columns[1]); SASSERT(&or1); @@ -450,7 +450,7 @@ namespace datalog { return (*m_rjoin_fn)(r1, r2); } - virtual relation_base * operator()(const relation_base & rb1, const relation_base & rb2) { + relation_base * operator()(const relation_base & rb1, const relation_base & rb2) override { finite_product_relation_plugin & plugin = get(rb1).get_plugin(); relation_manager & rmgr = plugin.get_manager(); @@ -565,7 +565,7 @@ namespace datalog { project_reducer(project_fn & parent, relation_vector & relations) : m_parent(parent), m_relations(relations) {} - virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { + void operator()(table_element * func_columns, const table_element * merged_func_columns) override { relation_base * tgt = m_relations[static_cast(func_columns[0])]->clone(); relation_base & src = *m_relations[static_cast(merged_func_columns[0])]; if(!m_parent.m_inner_rel_union) { @@ -579,7 +579,7 @@ namespace datalog { } }; - virtual relation_base * operator()(const relation_base & rb) { + relation_base * operator()(const relation_base & rb) override { const finite_product_relation & r = get(rb); finite_product_relation_plugin & plugin = r.get_plugin(); const table_base & rtable = r.get_table(); @@ -696,7 +696,7 @@ namespace datalog { } - virtual relation_base * operator()(const relation_base & rb) { + relation_base * operator()(const relation_base & rb) override { const finite_product_relation & r = get(rb); const table_base & rtable = r.get_table(); @@ -795,9 +795,9 @@ namespace datalog { m_delta_indexes(delta_indexes), m_delta_rels(delta_rels) {} - virtual ~union_mapper() {} + ~union_mapper() override {} - virtual bool operator()(table_element * func_columns) { + bool operator()(table_element * func_columns) override { relation_base & otgt_orig = m_tgt.get_inner_rel(func_columns[0]); const relation_base & osrc = m_src.get_inner_rel(func_columns[1]); @@ -838,7 +838,7 @@ namespace datalog { src_copying_mapper(finite_product_relation & tgt, const finite_product_relation & src) : m_tgt(tgt), m_src(src) {} - virtual bool operator()(table_element * func_columns) { + bool operator()(table_element * func_columns) override { const relation_base & osrc = m_src.get_inner_rel(func_columns[0]); unsigned new_tgt_idx = m_tgt.get_next_rel_idx(); m_tgt.set_inner_rel(new_tgt_idx, osrc.clone()); @@ -847,7 +847,7 @@ namespace datalog { } }; - virtual void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) { + void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) override { finite_product_relation & tgt = get(tgtb); const finite_product_relation & src0 = get(srcb); finite_product_relation * delta = get(deltab); @@ -1088,7 +1088,7 @@ namespace datalog { class finite_product_relation_plugin::converting_union_fn : public relation_union_fn { scoped_ptr m_tr_union_fun; public: - virtual void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) { + void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) override { SASSERT(srcb.get_plugin().is_finite_product_relation()); const finite_product_relation & src = get(srcb); finite_product_relation_plugin & plugin = src.get_plugin(); @@ -1164,7 +1164,7 @@ namespace datalog { SASSERT(m_rel_filter); } - virtual void operator()(relation_base & rb) { + void operator()(relation_base & rb) override { finite_product_relation & r = get(rb); if(m_table_cols.size()>1) { @@ -1212,7 +1212,7 @@ namespace datalog { } } - virtual void operator()(relation_base & rb) { + void operator()(relation_base & rb) override { finite_product_relation & r = get(rb); if(m_table_filter) { @@ -1339,7 +1339,7 @@ namespace datalog { } } - virtual void operator()(relation_base & rb) { + void operator()(relation_base & rb) override { finite_product_relation & r = get(rb); table_base & rtable = r.get_table(); table_plugin & tplugin = r.get_table_plugin(); @@ -1537,7 +1537,7 @@ namespace datalog { const finite_product_relation & inters) : m_parent(parent), m_r(r), m_inters(inters) {} - virtual bool operator()(table_element * func_columns) { + bool operator()(table_element * func_columns) override { relation_base * r_inner = m_r.get_inner_rel(func_columns[0]).clone(); const relation_base & inters_inner = m_inters.get_inner_rel(func_columns[1]); @@ -1557,7 +1557,7 @@ namespace datalog { }; - virtual void operator()(relation_base & rb, const relation_base & negb) { + void operator()(relation_base & rb, const relation_base & negb) override { finite_product_relation & r = get(rb); const finite_product_relation & neg = get(negb); @@ -1662,7 +1662,7 @@ namespace datalog { } } - virtual void operator()(relation_base & rb) { + void operator()(relation_base & rb) override { finite_product_relation & r = get(rb); finite_product_relation_plugin & plugin = r.get_plugin(); table_plugin & tplugin = r.get_table_plugin(); @@ -2043,7 +2043,7 @@ namespace datalog { public: live_rel_collection_reducer(idx_set & accumulator) : m_accumulator(accumulator) {} - virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { + void operator()(table_element * func_columns, const table_element * merged_func_columns) override { m_accumulator.insert(static_cast(merged_func_columns[0])); } }; diff --git a/src/muz/rel/dl_finite_product_relation.h b/src/muz/rel/dl_finite_product_relation.h index e13b7fcf9..750ac325f 100644 --- a/src/muz/rel/dl_finite_product_relation.h +++ b/src/muz/rel/dl_finite_product_relation.h @@ -93,23 +93,23 @@ namespace datalog { finite_product_relation_plugin(relation_plugin & inner_plugin, relation_manager & manager); - virtual void initialize(family_id fid); + void initialize(family_id fid) override; relation_plugin & get_inner_plugin() const { return m_inner_plugin; } - virtual bool can_handle_signature(const relation_signature & s); + bool can_handle_signature(const relation_signature & s) override; - virtual relation_base * mk_empty(const relation_signature & s); + relation_base * mk_empty(const relation_signature & s) override; /** \c inner_kind==null_family_id means we don't care about the kind of the inner relation */ finite_product_relation * mk_empty(const relation_signature & s, const bool * table_columns, family_id inner_kind=null_family_id); finite_product_relation * mk_empty(const finite_product_relation & original); - virtual relation_base * mk_empty(const relation_base & original); - virtual relation_base * mk_empty(const relation_signature & s, family_id kind); + relation_base * mk_empty(const relation_base & original) override; + relation_base * mk_empty(const relation_signature & s, family_id kind) override; - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + relation_base * mk_full(func_decl* p, const relation_signature & s) override; /** \brief Return true if \c r can be converted to \c finite_product_relation_plugin either @@ -127,22 +127,22 @@ namespace datalog { table_relation * to_table_relation(const finite_product_relation & r); protected: - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; + relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) override; private: /** @@ -309,7 +309,7 @@ namespace datalog { bool try_modify_specification(const bool * table_cols); - virtual bool can_swap(const relation_base & r) const + bool can_swap(const relation_base & r) const override { return &get_plugin()==&r.get_plugin(); } /** @@ -317,7 +317,7 @@ namespace datalog { Both relations must come from the same plugin and be of the same signature. */ - virtual void swap(relation_base & r); + void swap(relation_base & r) override; /** \brief Create a \c finite_product_relation object. @@ -325,7 +325,7 @@ namespace datalog { finite_product_relation(finite_product_relation_plugin & p, const relation_signature & s, const bool * table_columns, table_plugin & tplugin, relation_plugin & oplugin, family_id other_kind); finite_product_relation(const finite_product_relation & r); - virtual ~finite_product_relation(); + ~finite_product_relation() override; public: context & get_context() const; finite_product_relation_plugin & get_plugin() const { @@ -342,22 +342,22 @@ namespace datalog { /** The function calls garbage_collect, so the internal state may change when it is called. */ - virtual bool empty() const; - void reset() { m_table->reset(); garbage_collect(false); } + bool empty() const override; + void reset() override { m_table->reset(); garbage_collect(false); } - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; + void add_fact(const relation_fact & f) override; + bool contains_fact(const relation_fact & f) const override; - virtual finite_product_relation * clone() const; - virtual finite_product_relation * complement(func_decl* p) const; + finite_product_relation * clone() const override; + finite_product_relation * complement(func_decl* p) const override; - virtual void display(std::ostream & out) const; - virtual void display_tuples(func_decl & pred, std::ostream & out) const; + void display(std::ostream & out) const override; + void display_tuples(func_decl & pred, std::ostream & out) const override; - virtual unsigned get_size_estimate_rows() const { return m_table->get_size_estimate_rows(); } - virtual unsigned get_size_estimate_bytes() const { return m_table->get_size_estimate_bytes(); } + unsigned get_size_estimate_rows() const override { return m_table->get_size_estimate_rows(); } + unsigned get_size_estimate_bytes() const override { return m_table->get_size_estimate_bytes(); } - virtual void to_formula(expr_ref& fml) const; + void to_formula(expr_ref& fml) const override; }; }; diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index 26139fb7c..d82f42b19 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -192,7 +192,7 @@ namespace datalog { public: instr_io(bool store, func_decl_ref const& pred, reg_idx reg) : m_store(store), m_pred(pred), m_reg(reg) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); if (m_store) { if (ctx.reg(m_reg)) { @@ -218,10 +218,10 @@ namespace datalog { } return true; } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str()); } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { const char * rel_name = m_pred->get_name().bare_str(); if (m_store) { out << "store " << m_reg << " into " << rel_name; @@ -245,14 +245,14 @@ namespace datalog { reg_idx m_reg; public: instr_dealloc(reg_idx reg) : m_reg(reg) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { ctx.make_empty(m_reg); return true; } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { ctx.set_register_annotation(m_reg, "alloc"); } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "dealloc " << m_reg; } }; @@ -268,7 +268,7 @@ namespace datalog { public: instr_clone_move(bool clone, reg_idx src, reg_idx tgt) : m_clone(clone), m_src(src), m_tgt(tgt) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { if (ctx.reg(m_src)) log_verbose(ctx); if (m_clone) { ctx.set_reg(m_tgt, ctx.reg(m_src) ? ctx.reg(m_src)->clone() : 0); @@ -278,7 +278,7 @@ namespace datalog { } return true; } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::string str; if (ctx.get_register_annotation(m_src, str)) { ctx.set_register_annotation(m_tgt, str); @@ -287,7 +287,7 @@ namespace datalog { ctx.set_register_annotation(m_src, str); } } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << (m_clone ? "clone " : "move ") << m_src << " into " << m_tgt; } }; @@ -317,17 +317,17 @@ namespace datalog { return true; } protected: - virtual void process_all_costs() { + void process_all_costs() override { instruction::process_all_costs(); m_body->process_all_costs(); } public: instr_while_loop(unsigned control_reg_cnt, const reg_idx * control_regs, instruction_block * body) : m_controls(control_reg_cnt, control_regs), m_body(body) {} - virtual ~instr_while_loop() { + ~instr_while_loop() override { dealloc(m_body); } - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); TRACE("dl", tout << "loop entered\n";); unsigned count = 0; @@ -341,14 +341,14 @@ namespace datalog { TRACE("dl", tout << "while loop exited\n";); return true; } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { m_body->make_annotations(ctx); } - virtual void display_head_impl(execution_context const & ctx, std::ostream & out) const { + void display_head_impl(execution_context const & ctx, std::ostream & out) const override { out << "while"; print_container(m_controls, out); } - virtual void display_body_impl(execution_context const & ctx, std::ostream & out, const std::string & indentation) const { + void display_body_impl(execution_context const & ctx, std::ostream & out, const std::string & indentation) const override { m_body->display_indented(ctx, out, indentation+" "); } }; @@ -371,7 +371,7 @@ namespace datalog { const unsigned * cols2, reg_idx result) : m_rel1(rel1), m_rel2(rel2), m_cols1(col_cnt, cols1), m_cols2(col_cnt, cols2), m_res(result) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); ++ctx.m_stats.m_join; if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { @@ -408,13 +408,13 @@ namespace datalog { } return true; } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::string a1 = "rel1", a2 = "rel2"; ctx.get_register_annotation(m_rel1, a1); ctx.get_register_annotation(m_rel1, a1); ctx.set_register_annotation(m_res, "join " + a1 + " " + a2); } - virtual void display_head_impl(execution_context const & ctx, std::ostream & out) const { + void display_head_impl(execution_context const & ctx, std::ostream & out) const override { out << "join " << m_rel1; print_container(m_cols1, out); out << " and " << m_rel2; @@ -435,7 +435,7 @@ namespace datalog { public: instr_filter_equal(ast_manager & m, reg_idx reg, const relation_element & value, unsigned col) : m_reg(reg), m_value(value, m), m_col(col) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); ++ctx.m_stats.m_filter_eq; if (!ctx.reg(m_reg)) { @@ -460,12 +460,12 @@ namespace datalog { } return true; } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::stringstream a; a << "filter_equal " << m_col << " val: " << ctx.get_rel_context().get_rmanager().to_nice_string(m_value); ctx.set_register_annotation(m_reg, a.str()); } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "filter_equal " << m_reg << " col: " << m_col << " val: " << ctx.get_rel_context().get_rmanager().to_nice_string(m_value); } @@ -484,7 +484,7 @@ namespace datalog { public: instr_filter_identical(reg_idx reg, unsigned col_cnt, const unsigned * identical_cols) : m_reg(reg), m_cols(col_cnt, identical_cols) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); ++ctx.m_stats.m_filter_id; if (!ctx.reg(m_reg)) { @@ -509,11 +509,11 @@ namespace datalog { } return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "filter_identical " << m_reg << " "; print_container(m_cols, out); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { ctx.set_register_annotation(m_reg, "filter_identical"); } }; @@ -529,7 +529,7 @@ namespace datalog { public: instr_filter_interpreted(reg_idx reg, app_ref & condition) : m_reg(reg), m_cond(condition) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { if (!ctx.reg(m_reg)) { return true; } @@ -557,11 +557,11 @@ namespace datalog { return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "filter_interpreted " << m_reg << " using " << mk_pp(m_cond, m_cond.get_manager()); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::stringstream a; a << "filter_interpreted " << mk_pp(m_cond, m_cond.get_manager()); ctx.set_register_annotation(m_reg, a.str()); @@ -584,7 +584,7 @@ namespace datalog { : m_src(src), m_cond(condition), m_cols(col_cnt, removed_cols), m_res(result) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); if (!ctx.reg(m_src)) { ctx.make_empty(m_res); @@ -614,14 +614,14 @@ namespace datalog { return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "filter_interpreted_and_project " << m_src << " into " << m_res; out << " using " << mk_pp(m_cond, m_cond.get_manager()); out << " deleting columns "; print_container(m_cols, out); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::stringstream s; std::string a = "rel_src"; ctx.get_register_annotation(m_src, a); @@ -644,7 +644,7 @@ namespace datalog { public: instr_union(reg_idx src, reg_idx tgt, reg_idx delta, bool widen) : m_src(src), m_tgt(tgt), m_delta(delta), m_widen(widen) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { TRACE("dl", tout << "union " << m_src << " into " << m_tgt << " " << ctx.reg(m_src) << " " << ctx.reg(m_tgt) << "\n";); if (!ctx.reg(m_src)) { @@ -721,7 +721,7 @@ namespace datalog { return true; } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::string str = "union"; if (!ctx.get_register_annotation(m_tgt, str)) { ctx.set_register_annotation(m_tgt, "union"); @@ -731,7 +731,7 @@ namespace datalog { } ctx.set_register_annotation(m_delta, str); } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << (m_widen ? "widen " : "union ") << m_src << " into " << m_tgt; if (m_delta!=execution_context::void_register) { out << " with delta " << m_delta; @@ -758,7 +758,7 @@ namespace datalog { instr_project_rename(bool projection, reg_idx src, unsigned col_cnt, const unsigned * cols, reg_idx tgt) : m_projection(projection), m_src(src), m_cols(col_cnt, cols), m_tgt(tgt) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { if (!ctx.reg(m_src)) { ctx.make_empty(m_tgt); return true; @@ -787,12 +787,12 @@ namespace datalog { return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << (m_projection ? "project " : "rename ") << m_src << " into " << m_tgt; out << (m_projection ? " deleting columns " : " with cycle "); print_container(m_cols, out); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::stringstream s; std::string a = "rel_src"; ctx.get_register_annotation(m_src, a); @@ -825,7 +825,7 @@ namespace datalog { : m_rel1(rel1), m_rel2(rel2), m_cols1(joined_col_cnt, cols1), m_cols2(joined_col_cnt, cols2), m_removed_cols(removed_col_cnt, removed_cols), m_res(result) { } - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { ctx.make_empty(m_res); @@ -852,7 +852,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { relation_base const* r1 = ctx.reg(m_rel1); relation_base const* r2 = ctx.reg(m_rel2); out << "join_project " << m_rel1; @@ -870,7 +870,7 @@ namespace datalog { out << " into " << m_res << " removing columns "; print_container(m_removed_cols, out); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::string s1 = "rel1", s2 = "rel2"; ctx.get_register_annotation(m_rel1, s1); ctx.get_register_annotation(m_rel2, s2); @@ -898,7 +898,7 @@ namespace datalog { // TRACE("dl", tout << "src:" << m_src << " result: " << m_result << " value:" << m_value << " column:" << m_col << "\n";); } - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { if (!ctx.reg(m_src)) { ctx.make_empty(m_result); return true; @@ -923,11 +923,11 @@ namespace datalog { } return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "select_equal_and_project " << m_src <<" into " << m_result << " col: " << m_col << " val: " << ctx.get_rel_context().get_rmanager().to_nice_string(m_value); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::stringstream s; std::string s1 = "src"; ctx.get_register_annotation(m_src, s1); @@ -953,7 +953,7 @@ namespace datalog { instr_filter_by_negation(reg_idx tgt, reg_idx neg_rel, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) : m_tgt(tgt), m_neg_rel(neg_rel), m_cols1(col_cnt, cols1), m_cols2(col_cnt, cols2) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); if (!ctx.reg(m_tgt) || !ctx.reg(m_neg_rel)) { return true; @@ -980,14 +980,14 @@ namespace datalog { } return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "filter_by_negation on " << m_tgt; print_container(m_cols1, out); out << " with " << m_neg_rel; print_container(m_cols2, out); out << " as the negated table"; } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::string s = "negated relation"; ctx.get_register_annotation(m_neg_rel, s); ctx.set_register_annotation(m_tgt, "filter by negation " + s); @@ -1011,7 +1011,7 @@ namespace datalog { m_sig.push_back(s); m_fact.push_back(val); } - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); ++ctx.m_stats.m_unary_singleton; relation_base * rel = ctx.get_rel_context().get_rmanager().mk_empty_relation(m_sig, m_pred); @@ -1019,12 +1019,12 @@ namespace datalog { ctx.set_reg(m_tgt, rel); return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "mk_unary_singleton into " << m_tgt << " sort:" << ctx.get_rel_context().get_rmanager().to_nice_string(m_sig[0]) << " val:" << ctx.get_rel_context().get_rmanager().to_nice_string(m_sig[0], m_fact[0]); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::string s; if (!ctx.get_register_annotation(m_tgt, s)) { ctx.set_register_annotation(m_tgt, "mk unary singleton"); @@ -1044,18 +1044,18 @@ namespace datalog { reg_idx m_tgt; public: instr_mk_total(const relation_signature & sig, func_decl* p, reg_idx tgt) : m_sig(sig), m_pred(p), m_tgt(tgt) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); ++ctx.m_stats.m_total; ctx.set_reg(m_tgt, ctx.get_rel_context().get_rmanager().mk_full_relation(m_sig, m_pred)); return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "mk_total into " << m_tgt << " sort:" << ctx.get_rel_context().get_rmanager().to_nice_string(m_sig) << " " << m_pred->get_name(); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::string s; if (!ctx.get_register_annotation(m_tgt, s)) { ctx.set_register_annotation(m_tgt, "mk_total"); @@ -1072,15 +1072,15 @@ namespace datalog { public: instr_mark_saturated(ast_manager & m, func_decl * pred) : m_pred(pred, m) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); ctx.get_rel_context().get_rmanager().mark_saturated(m_pred); return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "mark_saturated " << m_pred->get_name().bare_str(); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { } }; @@ -1094,18 +1094,18 @@ namespace datalog { public: instr_assert_signature(const relation_signature & s, reg_idx tgt) : m_sig(s), m_tgt(tgt) {} - virtual bool perform(execution_context & ctx) { + bool perform(execution_context & ctx) override { log_verbose(ctx); if (ctx.reg(m_tgt)) { SASSERT(ctx.reg(m_tgt)->get_signature()==m_sig); } return true; } - virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const { + void display_head_impl(execution_context const& ctx, std::ostream & out) const override { out << "instr_assert_signature of " << m_tgt << " signature:"; print_container(m_sig, out); } - virtual void make_annotations(execution_context & ctx) { + void make_annotations(execution_context & ctx) override { std::string s; if (!ctx.get_register_annotation(m_tgt, s)) { ctx.set_register_annotation(m_tgt, "assert signature"); diff --git a/src/muz/rel/dl_interval_relation.cpp b/src/muz/rel/dl_interval_relation.cpp index e14d242bb..12b6815cc 100644 --- a/src/muz/rel/dl_interval_relation.cpp +++ b/src/muz/rel/dl_interval_relation.cpp @@ -59,7 +59,7 @@ namespace datalog { : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ } - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + relation_base * operator()(const relation_base & _r1, const relation_base & _r2) override { interval_relation const& r1 = get(_r1); interval_relation const& r2 = get(_r2); interval_relation_plugin& p = r1.get_plugin(); @@ -84,7 +84,7 @@ namespace datalog { : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { } - virtual relation_base * operator()(const relation_base & _r) { + relation_base * operator()(const relation_base & _r) override { interval_relation const& r = get(_r); interval_relation_plugin& p = r.get_plugin(); interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); @@ -104,7 +104,7 @@ namespace datalog { : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { } - virtual relation_base * operator()(const relation_base & _r) { + relation_base * operator()(const relation_base & _r) override { interval_relation const& r = get(_r); interval_relation_plugin& p = r.get_plugin(); interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); @@ -198,7 +198,7 @@ namespace datalog { m_is_widen(is_widen) { } - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) override { TRACE("interval_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); @@ -237,7 +237,7 @@ namespace datalog { filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) : m_identical_cols(col_cnt, identical_cols) {} - virtual void operator()(relation_base & r) { + void operator()(relation_base & r) override { interval_relation & pr = get(r); for (unsigned i = 1; i < m_identical_cols.size(); ++i) { unsigned c1 = m_identical_cols[0]; @@ -266,7 +266,7 @@ namespace datalog { VERIFY(arith.is_numeral(value, m_value)); } - virtual void operator()(relation_base & _r) { + void operator()(relation_base & _r) override { interval_relation & r = get(_r); interval_relation_plugin & p = r.get_plugin(); r.mk_intersect(m_col, interval(p.dep(), m_value)); @@ -290,7 +290,7 @@ namespace datalog { m_cond(cond, t.get_plugin().get_ast_manager()) { } - void operator()(relation_base& t) { + void operator()(relation_base& t) override { get(t).filter_interpreted(m_cond); TRACE("interval_relation", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); } diff --git a/src/muz/rel/dl_interval_relation.h b/src/muz/rel/dl_interval_relation.h index a9cce9802..896bb30ab 100644 --- a/src/muz/rel/dl_interval_relation.h +++ b/src/muz/rel/dl_interval_relation.h @@ -53,25 +53,25 @@ namespace datalog { public: interval_relation_plugin(relation_manager& m); - virtual bool can_handle_signature(const relation_signature & s); + bool can_handle_signature(const relation_signature & s) override; static symbol get_name() { return symbol("interval_relation"); } - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + relation_base * mk_empty(const relation_signature & s) override; + relation_base * mk_full(func_decl* p, const relation_signature & s) override; + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; static bool is_empty(unsigned idx, interval const& i); static bool is_infinite(interval const& i); @@ -97,39 +97,39 @@ namespace datalog { public: interval_relation(interval_relation_plugin& p, relation_signature const& s, bool is_empty); - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual interval_relation * clone() const; - virtual interval_relation * complement(func_decl*) const; - virtual void to_formula(expr_ref& fml) const; + void add_fact(const relation_fact & f) override; + bool contains_fact(const relation_fact & f) const override; + interval_relation * clone() const override; + interval_relation * complement(func_decl*) const override; + void to_formula(expr_ref& fml) const override; interval_relation_plugin& get_plugin() const; void filter_interpreted(app* cond); - virtual bool is_precise() const { return false; } + bool is_precise() const override { return false; } private: - virtual interval mk_intersect(interval const& t1, interval const& t2, bool& is_empty) const { + interval mk_intersect(interval const& t1, interval const& t2, bool& is_empty) const override { return get_plugin().meet(t1, t2, is_empty); } - virtual interval mk_unite(interval const& t1, interval const& t2) const { return get_plugin().unite(t1,t2); } + interval mk_unite(interval const& t1, interval const& t2) const override { return get_plugin().unite(t1,t2); } - virtual interval mk_widen(interval const& t1, interval const& t2) const { return get_plugin().widen(t1,t2); } + interval mk_widen(interval const& t1, interval const& t2) const override { return get_plugin().widen(t1,t2); } - virtual bool is_subset_of(interval const& t1, interval const& t2) const { NOT_IMPLEMENTED_YET(); return false; } + bool is_subset_of(interval const& t1, interval const& t2) const override { NOT_IMPLEMENTED_YET(); return false; } - virtual bool is_full(interval const& t) const { + bool is_full(interval const& t) const override { return interval_relation_plugin::is_infinite(t); } - virtual bool is_empty(unsigned idx, interval const& t) const { + bool is_empty(unsigned idx, interval const& t) const override { return interval_relation_plugin::is_empty(idx, t); } - virtual void mk_rename_elem(interval& i, unsigned col_cnt, unsigned const* cycle); + void mk_rename_elem(interval& i, unsigned col_cnt, unsigned const* cycle) override; - virtual void display_index(unsigned idx, interval const & i, std::ostream& out) const; + void display_index(unsigned idx, interval const & i, std::ostream& out) const override; void mk_intersect(unsigned idx, interval const& i); diff --git a/src/muz/rel/dl_lazy_table.cpp b/src/muz/rel/dl_lazy_table.cpp index 54105891a..1b8681ab0 100644 --- a/src/muz/rel/dl_lazy_table.cpp +++ b/src/muz/rel/dl_lazy_table.cpp @@ -50,7 +50,7 @@ namespace datalog { unsigned const* cols1, unsigned const* cols2): convenient_table_join_fn(s1, s2, col_cnt, cols1, cols2) {} - virtual table_base* operator()(const table_base& _t1, const table_base& _t2) { + table_base* operator()(const table_base& _t1, const table_base& _t2) override { lazy_table const& t1 = get(_t1); lazy_table const& t2 = get(_t2); lazy_table_ref* tr = alloc(lazy_table_join, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr(), t1, t2, get_result_signature()); @@ -75,7 +75,7 @@ namespace datalog { class lazy_table_plugin::union_fn : public table_union_fn { public: void operator()(table_base & _tgt, const table_base & _src, - table_base * _delta) { + table_base * _delta) override { lazy_table& tgt = get(_tgt); lazy_table const& src = get(_src); lazy_table* delta = get(_delta); @@ -111,7 +111,7 @@ namespace datalog { convenient_table_project_fn(orig_sig, cnt, cols) {} - virtual table_base* operator()(table_base const& _t) { + table_base* operator()(table_base const& _t) override { lazy_table const& t = get(_t); return alloc(lazy_table, alloc(lazy_table_project, m_removed_cols.size(), m_removed_cols.c_ptr(), t, get_result_signature())); } @@ -137,7 +137,7 @@ namespace datalog { convenient_table_rename_fn(orig_sig, cnt, cols) {} - virtual table_base* operator()(table_base const& _t) { + table_base* operator()(table_base const& _t) override { lazy_table const& t = get(_t); return alloc(lazy_table, alloc(lazy_table_rename, m_cycle.size(), m_cycle.c_ptr(), t, get_result_signature())); } @@ -163,7 +163,7 @@ namespace datalog { public: filter_identical_fn(unsigned cnt, unsigned const* cols): m_cols(cnt, cols) {} - virtual void operator()(table_base& _t) { + void operator()(table_base& _t) override { lazy_table& t = get(_t); t.set(alloc(lazy_table_filter_identical, m_cols.size(), m_cols.c_ptr(), t)); } @@ -188,7 +188,7 @@ namespace datalog { public: filter_interpreted_fn(app_ref& p): m_condition(p) {} - virtual void operator()(table_base& _t) { + void operator()(table_base& _t) override { lazy_table& t = get(_t); t.set(alloc(lazy_table_filter_interpreted, t, m_condition)); } @@ -214,7 +214,7 @@ namespace datalog { public: filter_by_negation_fn(unsigned cnt, unsigned const* cols1, unsigned const* cols2): m_cols1(cnt, cols1), m_cols2(cnt, cols2) {} - virtual void operator()(table_base & _t, const table_base & _intersected_obj) { + void operator()(table_base & _t, const table_base & _intersected_obj) override { lazy_table& t = get(_t); lazy_table const& it = get(_intersected_obj); t.set(alloc(lazy_table_filter_by_negation, t, it, m_cols1, m_cols2)); @@ -246,7 +246,7 @@ namespace datalog { m_col(col) { } - virtual void operator()(table_base& _t) { + void operator()(table_base& _t) override { lazy_table& t = get(_t); t.set(alloc(lazy_table_filter_equal, m_col, m_value, t)); } diff --git a/src/muz/rel/dl_lazy_table.h b/src/muz/rel/dl_lazy_table.h index 6752e5a5a..19ea6773e 100644 --- a/src/muz/rel/dl_lazy_table.h +++ b/src/muz/rel/dl_lazy_table.h @@ -48,37 +48,37 @@ namespace datalog { table_plugin(mk_name(p), p.get_manager()), m_plugin(p) {} - virtual bool can_handle_signature(const table_signature & s) { + bool can_handle_signature(const table_signature & s) override { return m_plugin.can_handle_signature(s); } - virtual table_base * mk_empty(const table_signature & s); + table_base * mk_empty(const table_signature & s) override; static table_plugin* mk_sparse(relation_manager& rm); protected: - virtual table_join_fn * mk_join_fn( + table_join_fn * mk_join_fn( const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual table_union_fn * mk_union_fn( - const table_base & tgt, const table_base & src, - const table_base * delta); - virtual table_transformer_fn * mk_project_fn( - const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual table_transformer_fn * mk_rename_fn( + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + table_union_fn * mk_union_fn( + const table_base & tgt, const table_base & src, + const table_base * delta) override; + table_transformer_fn * mk_project_fn( + const table_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + table_transformer_fn * mk_rename_fn( const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual table_mutator_fn * mk_filter_identical_fn( - const table_base & t, unsigned col_cnt, const unsigned * identical_cols); - virtual table_mutator_fn * mk_filter_equal_fn( - const table_base & t, const table_element & value, unsigned col); - virtual table_mutator_fn * mk_filter_interpreted_fn( - const table_base & t, app * condition); - virtual table_intersection_filter_fn * mk_filter_by_negation_fn( - const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); + const unsigned * permutation_cycle) override; + table_mutator_fn * mk_filter_identical_fn( + const table_base & t, unsigned col_cnt, const unsigned * identical_cols) override; + table_mutator_fn * mk_filter_equal_fn( + const table_base & t, const table_element & value, unsigned col) override; + table_mutator_fn * mk_filter_interpreted_fn( + const table_base & t, app * condition) override; + table_intersection_filter_fn * mk_filter_by_negation_fn( + const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) override; static lazy_table const& get(table_base const& tb); static lazy_table& get(table_base& tb); @@ -129,30 +129,30 @@ namespace datalog { m_ref(t) {} - virtual ~lazy_table() {} + ~lazy_table() override {} lazy_table_plugin& get_lplugin() const { return dynamic_cast(table_base::get_plugin()); } - virtual table_base * clone() const; - virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; - virtual bool empty() const; - virtual bool contains_fact(const table_fact & f) const; - virtual void remove_fact(table_element const* fact); - virtual void remove_facts(unsigned fact_cnt, const table_fact * facts); - virtual void remove_facts(unsigned fact_cnt, const table_element * facts); - virtual void reset(); - virtual void add_fact(table_fact const& f); + table_base * clone() const override; + table_base * complement(func_decl* p, const table_element * func_columns = 0) const override; + bool empty() const override; + bool contains_fact(const table_fact & f) const override; + void remove_fact(table_element const* fact) override; + void remove_facts(unsigned fact_cnt, const table_fact * facts) override; + void remove_facts(unsigned fact_cnt, const table_element * facts) override; + void reset() override; + void add_fact(table_fact const& f) override; - virtual unsigned get_size_estimate_rows() const { return 1; } - virtual unsigned get_size_estimate_bytes() const { return 1; } - virtual bool knows_exact_size() const { return false; } + unsigned get_size_estimate_rows() const override { return 1; } + unsigned get_size_estimate_bytes() const override { return 1; } + bool knows_exact_size() const override { return false; } table_base* eval() const; - virtual table_base::iterator begin() const; - virtual table_base::iterator end() const; + table_base::iterator begin() const override; + table_base::iterator end() const override; lazy_table_ref* get_ref() const { return m_ref.get(); } void set(lazy_table_ref* r) { m_ref = r; } @@ -165,9 +165,9 @@ namespace datalog { m_table = table; // SASSERT(&p.m_plugin == &table->get_lplugin()); } - virtual ~lazy_table_base() {} - virtual lazy_table_kind kind() const { return LAZY_TABLE_BASE; } - virtual table_base* force() { return m_table.get(); } + ~lazy_table_base() override {} + lazy_table_kind kind() const override { return LAZY_TABLE_BASE; } + table_base* force() override { return m_table.get(); } }; class lazy_table_join : public lazy_table_ref { @@ -184,13 +184,13 @@ namespace datalog { m_cols2(col_cnt, cols2), m_t1(t1.get_ref()), m_t2(t2.get_ref()) { } - virtual ~lazy_table_join() {} - virtual lazy_table_kind kind() const { return LAZY_TABLE_JOIN; } + ~lazy_table_join() override {} + lazy_table_kind kind() const override { return LAZY_TABLE_JOIN; } unsigned_vector const& cols1() const { return m_cols1; } unsigned_vector const& cols2() const { return m_cols2; } lazy_table_ref* t1() const { return m_t1.get(); } lazy_table_ref* t2() const { return m_t2.get(); } - virtual table_base* force(); + table_base* force() override; }; @@ -202,12 +202,12 @@ namespace datalog { : lazy_table_ref(src.get_lplugin(), sig), m_cols(col_cnt, cols), m_src(src.get_ref()) {} - virtual ~lazy_table_project() {} + ~lazy_table_project() override {} - virtual lazy_table_kind kind() const { return LAZY_TABLE_PROJECT; } + lazy_table_kind kind() const override { return LAZY_TABLE_PROJECT; } unsigned_vector const& cols() const { return m_cols; } lazy_table_ref* src() const { return m_src.get(); } - virtual table_base* force(); + table_base* force() override; }; class lazy_table_rename : public lazy_table_ref { @@ -218,12 +218,12 @@ namespace datalog { : lazy_table_ref(src.get_lplugin(), sig), m_cols(col_cnt, cols), m_src(src.get_ref()) {} - virtual ~lazy_table_rename() {} + ~lazy_table_rename() override {} - virtual lazy_table_kind kind() const { return LAZY_TABLE_RENAME; } + lazy_table_kind kind() const override { return LAZY_TABLE_RENAME; } unsigned_vector const& cols() const { return m_cols; } lazy_table_ref* src() const { return m_src.get(); } - virtual table_base* force(); + table_base* force() override; }; class lazy_table_filter_identical : public lazy_table_ref { @@ -232,12 +232,12 @@ namespace datalog { public: lazy_table_filter_identical(unsigned col_cnt, const unsigned * cols, lazy_table const& src) : lazy_table_ref(src.get_lplugin(), src.get_signature()), m_cols(col_cnt, cols), m_src(src.get_ref()) {} - virtual ~lazy_table_filter_identical() {} + ~lazy_table_filter_identical() override {} - virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_IDENTICAL; } + lazy_table_kind kind() const override { return LAZY_TABLE_FILTER_IDENTICAL; } unsigned_vector const& cols() const { return m_cols; } lazy_table_ref* src() const { return m_src.get(); } - virtual table_base* force(); + table_base* force() override; }; class lazy_table_filter_equal : public lazy_table_ref { @@ -250,13 +250,13 @@ namespace datalog { m_col(col), m_value(value), m_src(src.get_ref()) {} - virtual ~lazy_table_filter_equal() {} + ~lazy_table_filter_equal() override {} - virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_EQUAL; } + lazy_table_kind kind() const override { return LAZY_TABLE_FILTER_EQUAL; } unsigned col() const { return m_col; } table_element value() const { return m_value; } lazy_table_ref* src() const { return m_src.get(); } - virtual table_base* force(); + table_base* force() override; }; class lazy_table_filter_interpreted : public lazy_table_ref { @@ -266,12 +266,12 @@ namespace datalog { lazy_table_filter_interpreted(lazy_table const& src, app* condition) : lazy_table_ref(src.get_lplugin(), src.get_signature()), m_condition(condition, src.get_lplugin().get_ast_manager()), m_src(src.get_ref()) {} - virtual ~lazy_table_filter_interpreted() {} + ~lazy_table_filter_interpreted() override {} - virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_INTERPRETED; } + lazy_table_kind kind() const override { return LAZY_TABLE_FILTER_INTERPRETED; } app* condition() const { return m_condition; } lazy_table_ref* src() const { return m_src.get(); } - virtual table_base* force(); + table_base* force() override; }; @@ -288,13 +288,13 @@ namespace datalog { m_src(src.get_ref()), m_cols1(c1), m_cols2(c2) {} - virtual ~lazy_table_filter_by_negation() {} - virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_BY_NEGATION; } + ~lazy_table_filter_by_negation() override {} + lazy_table_kind kind() const override { return LAZY_TABLE_FILTER_BY_NEGATION; } lazy_table_ref* tgt() const { return m_tgt.get(); } lazy_table_ref* src() const { return m_src.get(); } unsigned_vector const& cols1() const { return m_cols1; } unsigned_vector const& cols2() const { return m_cols2; } - virtual table_base* force(); + table_base* force() override; }; diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index ca04ca099..4823ffb9b 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -69,7 +69,7 @@ namespace datalog { m_relation_level_explanations(relation_level), m_union_decl(mk_explanations::get_union_decl(get_context()), get_ast_manager()) {} - ~explanation_relation_plugin() { + ~explanation_relation_plugin() override { for (unsigned i = 0; i < m_pool.size(); ++i) { for (unsigned j = 0; j < m_pool[i].size(); ++j) { dealloc(m_pool[i][j]); @@ -77,7 +77,7 @@ namespace datalog { } } - virtual bool can_handle_signature(const relation_signature & s) { + bool can_handle_signature(const relation_signature & s) override { unsigned n=s.size(); for (unsigned i=0; i(relation_base::get_plugin()); } - virtual void to_formula(expr_ref& fml) const { + void to_formula(expr_ref& fml) const override { ast_manager& m = fml.get_manager(); fml = m.mk_eq(m.mk_var(0, m.get_sort(m_data[0])), m_data[0]); } @@ -204,23 +204,23 @@ namespace datalog { return true; } - virtual bool empty() const { return m_empty; } + bool empty() const override { return m_empty; } - virtual void reset() { + void reset() override { m_empty = true; } - virtual void add_fact(const relation_fact & f) { + void add_fact(const relation_fact & f) override { SASSERT(empty()); assign_data(f); } - virtual bool contains_fact(const relation_fact & f) const { + bool contains_fact(const relation_fact & f) const override { UNREACHABLE(); throw 0; } - virtual explanation_relation * clone() const { + explanation_relation * clone() const override { explanation_relation * res = static_cast(get_plugin().mk_empty(get_signature())); res->m_empty = m_empty; SASSERT(res->m_data.empty()); @@ -228,7 +228,7 @@ namespace datalog { return res; } - virtual relation_base * complement(func_decl* pred) const { + relation_base * complement(func_decl* pred) const override { explanation_relation * res = static_cast(get_plugin().mk_empty(get_signature())); if (empty()) { res->set_undefined(); @@ -247,7 +247,7 @@ namespace datalog { } } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { if (empty()) { out << "\n"; return; @@ -298,7 +298,7 @@ namespace datalog { join_fn(const relation_signature & sig1, const relation_signature & sig2) : convenient_relation_join_fn(sig1, sig2, 0, 0, 0) {} - virtual relation_base * operator()(const relation_base & r1_0, const relation_base & r2_0) { + relation_base * operator()(const relation_base & r1_0, const relation_base & r2_0) override { const explanation_relation & r1 = static_cast(r1_0); const explanation_relation & r2 = static_cast(r2_0); explanation_relation_plugin & plugin = r1.get_plugin(); @@ -331,7 +331,7 @@ namespace datalog { project_fn(const relation_signature & sig, unsigned col_cnt, const unsigned * removed_cols) : convenient_relation_project_fn(sig, col_cnt, removed_cols) {} - virtual relation_base * operator()(const relation_base & r0) { + relation_base * operator()(const relation_base & r0) override { const explanation_relation & r = static_cast(r0); explanation_relation_plugin & plugin = r.get_plugin(); @@ -359,7 +359,7 @@ namespace datalog { rename_fn(const relation_signature & sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) : convenient_relation_rename_fn(sig, permutation_cycle_len, permutation_cycle) {} - virtual relation_base * operator()(const relation_base & r0) { + relation_base * operator()(const relation_base & r0) override { const explanation_relation & r = static_cast(r0); explanation_relation_plugin & plugin = r.get_plugin(); @@ -382,7 +382,7 @@ namespace datalog { class explanation_relation_plugin::union_fn : public relation_union_fn { scoped_ptr m_delta_union_fun; public: - virtual void operator()(relation_base & tgt0, const relation_base & src0, relation_base * delta0) { + void operator()(relation_base & tgt0, const relation_base & src0, relation_base * delta0) override { explanation_relation & tgt = static_cast(tgt0); const explanation_relation & src = static_cast(src0); explanation_relation * delta = delta0 ? static_cast(delta0) : 0; @@ -418,7 +418,7 @@ namespace datalog { class explanation_relation_plugin::foreign_union_fn : public relation_union_fn { scoped_ptr m_delta_union_fun; public: - virtual void operator()(relation_base & tgt0, const relation_base & src, relation_base * delta0) { + void operator()(relation_base & tgt0, const relation_base & src, relation_base * delta0) override { explanation_relation & tgt = static_cast(tgt0); explanation_relation * delta = delta0 ? static_cast(delta0) : 0; @@ -456,7 +456,7 @@ namespace datalog { m_col_idx(col_idx), m_new_rule(std::move(new_rule)) {} - virtual void operator()(relation_base & r0) { + void operator()(relation_base & r0) override { explanation_relation & r = static_cast(r0); if (!r.is_undefined(m_col_idx)) { @@ -509,7 +509,7 @@ namespace datalog { class explanation_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { public: - virtual void operator()(relation_base & r, const relation_base & neg) { + void operator()(relation_base & r, const relation_base & neg) override { if (!neg.empty()) { r.reset(); } @@ -531,7 +531,7 @@ namespace datalog { intersection_filter_fn(explanation_relation_plugin & plugin) : m_union_decl(plugin.m_union_decl) {} - virtual void operator()(relation_base & tgt0, const relation_base & src0) { + void operator()(relation_base & tgt0, const relation_base & src0) override { explanation_relation & tgt = static_cast(tgt0); const explanation_relation & src = static_cast(src0); diff --git a/src/muz/rel/dl_mk_explanations.h b/src/muz/rel/dl_mk_explanations.h index 6142b61d6..a96d50cb3 100644 --- a/src/muz/rel/dl_mk_explanations.h +++ b/src/muz/rel/dl_mk_explanations.h @@ -76,7 +76,7 @@ namespace datalog { return get_union_decl(m_context); } - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; static expr* get_explanation(relation_base const& r); }; diff --git a/src/muz/rel/dl_mk_similarity_compressor.h b/src/muz/rel/dl_mk_similarity_compressor.h index 096305c59..da56e9eca 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.h +++ b/src/muz/rel/dl_mk_similarity_compressor.h @@ -69,7 +69,7 @@ namespace datalog { public: mk_similarity_compressor(context & ctx); - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/rel/dl_mk_simple_joins.h b/src/muz/rel/dl_mk_simple_joins.h index cf4522c22..8eb6bd0c2 100644 --- a/src/muz/rel/dl_mk_simple_joins.h +++ b/src/muz/rel/dl_mk_simple_joins.h @@ -54,7 +54,7 @@ namespace datalog { public: mk_simple_joins(context & ctx); - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index 1a91d6828..56fd56505 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -444,12 +444,12 @@ namespace datalog { init(r1.get_signature(), 1, rels1, r2.get_signature(), 1, rels2, col_cnt, cols1, cols2); } - ~join_fn() { + ~join_fn() override { dealloc_ptr_vector_content(m_joins); dealloc_ptr_vector_content(m_full); } - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + relation_base * operator()(const relation_base & _r1, const relation_base & _r2) override { TRACE("dl", _r1.display(tout); _r2.display(tout);); ptr_vector relations; unsigned sz = m_joins.size(); @@ -491,9 +491,9 @@ namespace datalog { m_sig(std::move(s)), m_transforms(num_trans, trans) {} - ~transform_fn() { dealloc_ptr_vector_content(m_transforms); } + ~transform_fn() override { dealloc_ptr_vector_content(m_transforms); } - virtual relation_base * operator()(const relation_base & _r) { + relation_base * operator()(const relation_base & _r) override { product_relation const& r = get(_r); product_relation_plugin& p = r.get_plugin(); SASSERT(m_transforms.size() == r.size()); @@ -628,14 +628,14 @@ namespace datalog { init(tgt.m_relations, src.m_relations, delta ? &delta->m_relations : 0); } - ~aligned_union_fn() { + ~aligned_union_fn() override { unsigned sz = m_unions.size(); for(unsigned i=0; iis_precise()) { return false; diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 1eb973776..8226d0198 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -538,7 +538,7 @@ namespace datalog { class relation_manager::empty_signature_relation_join_fn : public relation_join_fn { public: - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + relation_base * operator()(const relation_base & r1, const relation_base & r2) override { TRACE("dl", tout << r1.get_plugin().get_name() << " " << r2.get_plugin().get_name() << "\n";); if(r1.get_signature().empty()) { if(r1.empty()) { @@ -615,7 +615,7 @@ namespace datalog { m_project(0), m_removed_cols(removed_col_cnt, removed_cols) {} - virtual relation_base * operator()(const relation_base & t) { + relation_base * operator()(const relation_base & t) override { scoped_rel t1 = t.clone(); (*m_filter)(*t1); if( !m_project) { @@ -658,11 +658,11 @@ namespace datalog { default_relation_apply_sequential_fn(unsigned n, relation_mutator_fn ** mutators): m_mutators(n, mutators) { } - virtual ~default_relation_apply_sequential_fn() { + ~default_relation_apply_sequential_fn() override { std::for_each(m_mutators.begin(), m_mutators.end(), delete_proc()); } - virtual void operator()(relation_base& t) { + void operator()(relation_base& t) override { for (unsigned i = 0; i < m_mutators.size(); ++i) { if (t.empty()) return; (*(m_mutators[i]))(t); @@ -688,7 +688,7 @@ namespace datalog { const unsigned * removed_cols) : m_join(join), m_project(0), m_removed_cols(removed_col_cnt, removed_cols) {} - virtual relation_base * operator()(const relation_base & t1, const relation_base & t2) { + relation_base * operator()(const relation_base & t1, const relation_base & t2) override { scoped_rel aux = (*m_join)(t1, t2); if(!m_project) { relation_manager & rmgr = aux->get_plugin().get_manager(); @@ -787,7 +787,7 @@ namespace datalog { default_relation_select_equal_and_project_fn(relation_mutator_fn * filter, relation_transformer_fn * project) : m_filter(filter), m_project(project) {} - virtual relation_base * operator()(const relation_base & t1) { + relation_base * operator()(const relation_base & t1) override { TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); scoped_rel aux = t1.clone(); (*m_filter)(*aux); @@ -823,7 +823,7 @@ namespace datalog { default_relation_intersection_filter_fn(relation_join_fn * join_fun, relation_union_fn * union_fun) : m_join_fun(join_fun), m_union_fun(union_fun) {} - virtual void operator()(relation_base & tgt, const relation_base & intersected_obj) { + void operator()(relation_base & tgt, const relation_base & intersected_obj) override { scoped_rel filtered_rel = (*m_join_fun)(tgt, intersected_obj); TRACE("dl", tgt.display(tout << "tgt:\n"); @@ -926,7 +926,7 @@ namespace datalog { const unsigned * cols1, const unsigned * cols2) : convenient_table_join_fn(t1_sig, t2_sig, col_cnt, cols1, cols2), m_col_cnt(col_cnt) {} - virtual table_base * operator()(const table_base & t1, const table_base & t2) { + table_base * operator()(const table_base & t1, const table_base & t2) override { table_plugin * plugin = &t1.get_plugin(); const table_signature & res_sign = get_result_signature(); @@ -1037,15 +1037,15 @@ namespace datalog { SASSERT(removed_col_cnt>0); } - virtual const table_signature & get_result_signature() const { + const table_signature & get_result_signature() const override { return convenient_table_project_fn::get_result_signature(); } - virtual void modify_fact(table_fact & f) const { + void modify_fact(table_fact & f) const override { project_out_vector_columns(f, m_removed_cols); } - virtual table_base * operator()(const table_base & t) { + table_base * operator()(const table_base & t) override { return auxiliary_table_transformer_fn::operator()(t); } }; @@ -1054,7 +1054,7 @@ namespace datalog { const table_signature m_empty_sig; public: null_signature_table_project_fn() : m_empty_sig() {} - virtual table_base * operator()(const table_base & t) { + table_base * operator()(const table_base & t) override { relation_manager & m = t.get_plugin().get_manager(); table_base * res = m.mk_empty_table(m_empty_sig); if(!t.empty()) { @@ -1096,14 +1096,14 @@ namespace datalog { m_removed_cols(removed_col_cnt, removed_cols) {} class unreachable_reducer : public table_row_pair_reduce_fn { - virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { + void operator()(table_element * func_columns, const table_element * merged_func_columns) override { //we do project_with_reduce only if we are sure there will be no reductions //(see code of the table_signature::from_join_project function) UNREACHABLE(); } }; - virtual table_base * operator()(const table_base & t1, const table_base & t2) { + table_base * operator()(const table_base & t1, const table_base & t2) override { table_base * aux = (*m_join)(t1, t2); if(m_project==0) { relation_manager & rmgr = aux->get_plugin().get_manager(); @@ -1154,15 +1154,15 @@ namespace datalog { SASSERT(permutation_cycle_len>=2); } - virtual const table_signature & get_result_signature() const { + const table_signature & get_result_signature() const override { return convenient_table_rename_fn::get_result_signature(); } - virtual void modify_fact(table_fact & f) const { + void modify_fact(table_fact & f) const override { permutate_by_cycle(f, m_cycle); } - virtual table_base * operator()(const table_base & t) { + table_base * operator()(const table_base & t) override { return auxiliary_table_transformer_fn::operator()(t); } @@ -1190,7 +1190,7 @@ namespace datalog { class relation_manager::default_table_union_fn : public table_union_fn { table_fact m_row; public: - virtual void operator()(table_base & tgt, const table_base & src, table_base * delta) { + void operator()(table_base & tgt, const table_base & src, table_base * delta) override { table_base::iterator it = src.begin(); table_base::iterator iend = src.end(); @@ -1283,7 +1283,7 @@ namespace datalog { SASSERT(col_cnt>=2); } - virtual bool should_remove(const table_fact & f) const { + bool should_remove(const table_fact & f) const override { table_element val=f[m_identical_cols[0]]; for(unsigned i=1; i(m_args); args.reset(); @@ -1425,7 +1425,7 @@ namespace datalog { return m_ast_manager.is_false(ground); } - virtual void operator()(table_base & t) { + void operator()(table_base & t) override { auxiliary_table_filter_fn::operator()(t); } }; @@ -1455,7 +1455,7 @@ namespace datalog { : m_filter(filter), m_condition(condition, ctx.get_manager()), m_removed_cols(removed_col_cnt, removed_cols) {} - virtual table_base* operator()(const table_base & tb) { + table_base* operator()(const table_base & tb) override { table_base *t2 = tb.clone(); (*m_filter)(*t2); if (!m_project) { @@ -1506,7 +1506,7 @@ namespace datalog { m_aux_fact.resize(neg_t.get_signature().size()); } - virtual bool should_remove(const table_fact & f) const { + bool should_remove(const table_fact & f) const override { if(!m_all_neg_bound || m_overlap) { table_base::iterator nit = m_negated_table->begin(); table_base::iterator nend = m_negated_table->end(); @@ -1524,7 +1524,7 @@ namespace datalog { } } - virtual void operator()(table_base & tgt, const table_base & negated_table) { + void operator()(table_base & tgt, const table_base & negated_table) override { SASSERT(m_negated_table==0); flet flet_neg_table(m_negated_table, &negated_table); auxiliary_table_filter_fn::operator()(tgt); @@ -1568,7 +1568,7 @@ namespace datalog { default_table_select_equal_and_project_fn(table_mutator_fn * filter, table_transformer_fn * project) : m_filter(filter), m_project(project) {} - virtual table_base * operator()(const table_base & t1) { + table_base * operator()(const table_base & t1) override { TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); scoped_rel aux = t1.clone(); (*m_filter)(*aux); @@ -1606,9 +1606,9 @@ namespace datalog { m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(0)); } - virtual ~default_table_map_fn() {} + ~default_table_map_fn() override {} - virtual void operator()(table_base & t) { + void operator()(table_base & t) override { SASSERT(t.get_signature()==m_aux_table->get_signature()); if(!m_aux_table->empty()) { m_aux_table->reset(); @@ -1664,7 +1664,7 @@ namespace datalog { m_former_row.resize(get_result_signature().size()); } - virtual ~default_table_project_with_reduce_fn() {} + ~default_table_project_with_reduce_fn() override {} virtual void modify_fact(table_fact & f) const { unsigned ofs=1; @@ -1693,7 +1693,7 @@ namespace datalog { } } - virtual table_base * operator()(const table_base & t) { + table_base * operator()(const table_base & t) override { table_plugin & plugin = t.get_plugin(); const table_signature & res_sign = get_result_signature(); SASSERT(plugin.can_handle_signature(res_sign)); diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index 7e274cbef..401d519d5 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -294,7 +294,7 @@ namespace datalog { } } - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + relation_base * operator()(const relation_base & r1, const relation_base & r2) override { bool r1_sieved = r1.get_plugin().is_sieve_relation(); bool r2_sieved = r2.get_plugin().is_sieve_relation(); SASSERT(r1_sieved || r2_sieved); @@ -357,7 +357,7 @@ namespace datalog { get_result_signature() = result_sig; } - virtual relation_base * operator()(const relation_base & r0) { + relation_base * operator()(const relation_base & r0) override { SASSERT(r0.get_plugin().is_sieve_relation()); const sieve_relation & r = static_cast(r0); sieve_relation_plugin & plugin = r.get_plugin(); @@ -439,7 +439,7 @@ namespace datalog { public: union_fn(relation_union_fn * union_fun) : m_union_fun(union_fun) {} - virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { + void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) override { bool tgt_sieved = tgt.get_plugin().is_sieve_relation(); bool src_sieved = src.get_plugin().is_sieve_relation(); bool delta_sieved = delta && delta->get_plugin().is_sieve_relation(); @@ -504,7 +504,7 @@ namespace datalog { filter_fn(relation_mutator_fn * inner_fun) : m_inner_fun(inner_fun) {} - virtual void operator()(relation_base & r0) { + void operator()(relation_base & r0) override { SASSERT(r0.get_plugin().is_sieve_relation()); sieve_relation & r = static_cast(r0); @@ -600,7 +600,7 @@ namespace datalog { negation_filter_fn(relation_intersection_filter_fn * inner_fun) : m_inner_fun(inner_fun) {} - virtual void operator()(relation_base & r, const relation_base & neg) { + void operator()(relation_base & r, const relation_base & neg) override { bool r_sieved = r.get_plugin().is_sieve_relation(); bool neg_sieved = neg.get_plugin().is_sieve_relation(); SASSERT(r_sieved || neg_sieved); diff --git a/src/muz/rel/dl_sieve_relation.h b/src/muz/rel/dl_sieve_relation.h index e369e04aa..5f20cecb4 100644 --- a/src/muz/rel/dl_sieve_relation.h +++ b/src/muz/rel/dl_sieve_relation.h @@ -85,7 +85,7 @@ namespace datalog { sieve_relation_plugin(relation_manager & manager); - virtual void initialize(family_id fid); + void initialize(family_id fid) override; family_id get_relation_kind(const relation_signature & sig, const bool * inner_columns, family_id inner_kind); @@ -95,15 +95,15 @@ namespace datalog { return get_relation_kind(sig, inner_columns.c_ptr(), inner_kind); } - virtual bool can_handle_signature(const relation_signature & s); + bool can_handle_signature(const relation_signature & s) override; - virtual relation_base * mk_empty(const relation_signature & s); + relation_base * mk_empty(const relation_signature & s) override; sieve_relation * mk_empty(const sieve_relation & original); - virtual relation_base * mk_empty(const relation_base & original); - virtual relation_base * mk_empty(const relation_signature & s, family_id kind); + relation_base * mk_empty(const relation_base & original) override; + relation_base * mk_empty(const relation_signature & s, family_id kind) override; sieve_relation * mk_empty(const relation_signature & s, relation_plugin & inner_plugin); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + relation_base * mk_full(func_decl* p, const relation_signature & s) override; sieve_relation * full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin); sieve_relation * mk_from_inner(const relation_signature & s, const bool * inner_columns, @@ -116,22 +116,22 @@ namespace datalog { protected: - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; + relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) override; }; @@ -176,18 +176,18 @@ namespace datalog { relation_base & get_inner() { return *m_inner; } const relation_base & get_inner() const { return *m_inner; } - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual sieve_relation * clone() const; - virtual relation_base * complement(func_decl*p) const; - virtual void to_formula(expr_ref& fml) const; + void add_fact(const relation_fact & f) override; + bool contains_fact(const relation_fact & f) const override; + sieve_relation * clone() const override; + relation_base * complement(func_decl*p) const override; + void to_formula(expr_ref& fml) const override; - virtual bool empty() const { return get_inner().empty(); } - virtual void reset() { get_inner().reset(); } - virtual unsigned get_size_estimate_rows() const { return get_inner().get_size_estimate_rows(); } - virtual unsigned get_size_estimate_bytes() const { return get_inner().get_size_estimate_bytes(); } + bool empty() const override { return get_inner().empty(); } + void reset() override { get_inner().reset(); } + unsigned get_size_estimate_rows() const override { return get_inner().get_size_estimate_rows(); } + unsigned get_size_estimate_bytes() const override { return get_inner().get_size_estimate_bytes(); } - virtual void display(std::ostream & out) const; + void display(std::ostream & out) const override; }; diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index 6048f358b..50386152c 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -198,7 +198,7 @@ namespace datalog { row_interface(t), m_parent(parent) {} - virtual table_element operator[](unsigned col) const { + table_element operator[](unsigned col) const override { return m_parent.m_layout.get(m_parent.m_ptr, col); } @@ -218,15 +218,15 @@ namespace datalog { m_row_obj(t, *this), m_layout(t.m_column_layout) {} - virtual bool is_finished() const { + bool is_finished() const override { return m_ptr == m_end; } - virtual row_interface & operator*() { + row_interface & operator*() override { SASSERT(!is_finished()); return m_row_obj; } - virtual void operator++() { + void operator++() override { SASSERT(!is_finished()); m_ptr+=m_fact_size; } @@ -312,7 +312,7 @@ namespace datalog { m_keys(key_len*sizeof(table_element)), m_first_nonindexed(0) {} - virtual void update(const sparse_table & t) { + void update(const sparse_table & t) override { if (m_first_nonindexed == t.m_data.after_last_offset()) { return; } @@ -351,7 +351,7 @@ namespace datalog { m_first_nonindexed = t.m_data.after_last_offset(); } - virtual query_result get_matching_offsets(const key_value & key) const { + query_result get_matching_offsets(const key_value & key) const override { key_to_reserve(key); store_offset ofs; if (!m_keys.find_reserve_content(ofs)) { @@ -406,9 +406,9 @@ namespace datalog { m_key_fact.resize(t.get_signature().size()); } - virtual ~full_signature_key_indexer() {} + ~full_signature_key_indexer() override {} - virtual query_result get_matching_offsets(const key_value & key) const { + query_result get_matching_offsets(const key_value & key) const override { unsigned key_len = m_key_cols.size(); for (unsigned i=0; i0; } - virtual table_base * mk_empty(const table_signature & s); + table_base * mk_empty(const table_signature & s) override; sparse_table * mk_clone(const sparse_table & t); protected: - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols); - virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, - const table_element & value, unsigned col); - virtual table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - virtual table_intersection_join_filter_fn* mk_filter_by_negated_join_fn( - const table_base & t, - const table_base & src1, - const table_base & src2, + table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) override; + table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta) override; + table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col) override; + table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) override; + table_intersection_join_filter_fn* mk_filter_by_negated_join_fn( + const table_base & t, + const table_base & src1, + const table_base & src2, unsigned_vector const& t_cols, unsigned_vector const& src_cols, unsigned_vector const& src1_cols, - unsigned_vector const& src2_cols); + unsigned_vector const& src2_cols) override; static sparse_table const& get(table_base const&); static sparse_table& get(table_base&); @@ -463,10 +463,10 @@ namespace datalog { sparse_table(sparse_table_plugin & p, const table_signature & sig, unsigned init_capacity=0); sparse_table(const sparse_table & t); - virtual ~sparse_table(); + ~sparse_table() override; public: - virtual void deallocate() { + void deallocate() override { get_plugin().recycle(this); } @@ -475,22 +475,22 @@ namespace datalog { sparse_table_plugin & get_plugin() const { return static_cast(table_base::get_plugin()); } - virtual bool empty() const { return row_count()==0; } - virtual void add_fact(const table_fact & f); - virtual bool contains_fact(const table_fact & f) const; - virtual bool fetch_fact(table_fact & f) const; - virtual void ensure_fact(const table_fact & f); - virtual void remove_fact(const table_element* fact); - virtual void reset(); + bool empty() const override { return row_count()==0; } + void add_fact(const table_fact & f) override; + bool contains_fact(const table_fact & f) const override; + bool fetch_fact(table_fact & f) const override; + void ensure_fact(const table_fact & f) override; + void remove_fact(const table_element* fact) override; + void reset() override; - virtual table_base * clone() const; + table_base * clone() const override; - virtual table_base::iterator begin() const; - virtual table_base::iterator end() const; + table_base::iterator begin() const override; + table_base::iterator end() const override; - virtual unsigned get_size_estimate_rows() const { return row_count(); } - virtual unsigned get_size_estimate_bytes() const; - virtual bool knows_exact_size() const { return true; } + unsigned get_size_estimate_rows() const override { return row_count(); } + unsigned get_size_estimate_bytes() const override; + bool knows_exact_size() const override { return true; } }; }; diff --git a/src/muz/rel/dl_table.cpp b/src/muz/rel/dl_table.cpp index 1c068a878..963820c91 100644 --- a/src/muz/rel/dl_table.cpp +++ b/src/muz/rel/dl_table.cpp @@ -43,7 +43,7 @@ namespace datalog { : convenient_table_join_fn(t1_sig, t2_sig, col_cnt, cols1, cols2), m_joined_col_cnt(col_cnt) {} - virtual table_base * operator()(const table_base & t1, const table_base & t2) { + table_base * operator()(const table_base & t1, const table_base & t2) override { const hashtable_table & ht1 = static_cast(t1); const hashtable_table & ht2 = static_cast(t2); @@ -105,10 +105,10 @@ namespace datalog { public: our_row(const our_iterator_core & parent) : row_interface(parent.m_parent), m_parent(parent) {} - virtual void get_fact(table_fact & result) const { + void get_fact(table_fact & result) const override { result = *m_parent.m_inner; } - virtual table_element operator[](unsigned col) const { + table_element operator[](unsigned col) const override { return (*m_parent.m_inner)[col]; } @@ -121,15 +121,15 @@ namespace datalog { m_parent(t), m_inner(finished ? t.m_data.end() : t.m_data.begin()), m_end(t.m_data.end()), m_row_obj(*this) {} - virtual bool is_finished() const { + bool is_finished() const override { return m_inner==m_end; } - virtual row_interface & operator*() { + row_interface & operator*() override { SASSERT(!is_finished()); return m_row_obj; } - virtual void operator++() { + void operator++() override { SASSERT(!is_finished()); ++m_inner; } @@ -192,7 +192,7 @@ namespace datalog { const bv_iterator& m_parent; public: our_row(const bv_iterator & p) : caching_row_interface(p.m_bv), m_parent(p) {} - virtual void get_fact(table_fact& result) const { + void get_fact(table_fact& result) const override { if (result.size() < size()) { result.resize(size(), 0); } @@ -210,15 +210,15 @@ namespace datalog { } } - virtual bool is_finished() const { + bool is_finished() const override { return m_offset == m_bv.m_bv.size(); } - virtual row_interface & operator*() { + row_interface & operator*() override { SASSERT(!is_finished()); return m_row_obj; } - virtual void operator++() { + void operator++() override { SASSERT(!is_finished()); ++m_offset; while (!is_finished() && !m_bv.m_bv.get(m_offset)) { diff --git a/src/muz/rel/dl_table.h b/src/muz/rel/dl_table.h index c428191af..168108e65 100644 --- a/src/muz/rel/dl_table.h +++ b/src/muz/rel/dl_table.h @@ -61,10 +61,10 @@ namespace datalog { hashtable_table_plugin(relation_manager & manager) : table_plugin(symbol("hashtable"), manager) {} - virtual table_base * mk_empty(const table_signature & s); + table_base * mk_empty(const table_signature & s) override; - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; }; class hashtable_table : public table_base { @@ -84,23 +84,23 @@ namespace datalog { hashtable_table_plugin & get_plugin() const { return static_cast(table_base::get_plugin()); } - virtual void add_fact(const table_fact & f) { + void add_fact(const table_fact & f) override { m_data.insert(f); } - virtual void remove_fact(const table_element* fact) { + void remove_fact(const table_element* fact) override { table_fact f(get_signature().size(), fact); m_data.remove(f); } - virtual bool contains_fact(const table_fact & f) const { + bool contains_fact(const table_fact & f) const override { return m_data.contains(f); } - virtual iterator begin() const; - virtual iterator end() const; + iterator begin() const override; + iterator end() const override; - virtual unsigned get_size_estimate_rows() const { return m_data.size(); } - virtual unsigned get_size_estimate_bytes() const { return m_data.size()*get_signature().size()*8; } - virtual bool knows_exact_size() const { return true; } + unsigned get_size_estimate_rows() const override { return m_data.size(); } + unsigned get_size_estimate_bytes() const override { return m_data.size()*get_signature().size()*8; } + bool knows_exact_size() const override { return true; } }; // ----------------------------------- @@ -118,9 +118,9 @@ namespace datalog { bitvector_table_plugin(relation_manager & manager) : table_plugin(symbol("bitvector"), manager) {} - virtual bool can_handle_signature(const table_signature & s); + bool can_handle_signature(const table_signature & s) override; - virtual table_base * mk_empty(const table_signature & s); + table_base * mk_empty(const table_signature & s) override; }; class bitvector_table : public table_base { @@ -137,11 +137,11 @@ namespace datalog { bitvector_table(bitvector_table_plugin & plugin, const table_signature & sig); public: - virtual void add_fact(const table_fact & f); - virtual void remove_fact(const table_element* fact); - virtual bool contains_fact(const table_fact & f) const; - virtual iterator begin() const; - virtual iterator end() const; + void add_fact(const table_fact & f) override; + void remove_fact(const table_element* fact) override; + bool contains_fact(const table_fact & f) const override; + iterator begin() const override; + iterator end() const override; }; diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index b8cf8e724..d5d8fd3c9 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -82,7 +82,7 @@ namespace datalog { : convenient_relation_join_project_fn(s1, s2, col_cnt, cols1, cols2, removed_col_cnt, removed_cols), m_tfun(tfun) {} - virtual relation_base * operator()(const relation_base & t1, const relation_base & t2) { + relation_base * operator()(const relation_base & t1, const relation_base & t2) override { SASSERT(t1.from_table()); SASSERT(t2.from_table()); table_relation_plugin & plugin = static_cast(t1.get_plugin()); @@ -146,7 +146,7 @@ namespace datalog { tr_transformer_fn(const relation_signature & rsig, table_transformer_fn * tfun) : m_tfun(tfun) { get_result_signature() = rsig; } - virtual relation_base * operator()(const relation_base & t) { + relation_base * operator()(const relation_base & t) override { SASSERT(t.from_table()); table_relation_plugin & plugin = static_cast(t.get_plugin()); @@ -235,7 +235,7 @@ namespace datalog { by iterating through the table and calling \c add_fact of the target relation. */ class table_relation_plugin::universal_target_union_fn : public relation_union_fn { - virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { + void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) override { SASSERT(src.from_table()); const table_relation & tr_src = static_cast(src); @@ -271,7 +271,7 @@ namespace datalog { public: tr_union_fn(table_union_fn * tfun) : m_tfun(tfun) {} - virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { + void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) override { SASSERT(tgt.from_table()); SASSERT(src.from_table()); SASSERT(!delta || delta->from_table()); @@ -311,7 +311,7 @@ namespace datalog { public: tr_mutator_fn(table_mutator_fn * tfun) : m_tfun(tfun) {} - virtual void operator()(relation_base & r) { + void operator()(relation_base & r) override { SASSERT(r.from_table()); table_relation & tr = static_cast(r); (*m_tfun)(tr.get_table()); @@ -377,7 +377,7 @@ namespace datalog { public: tr_intersection_filter_fn(table_intersection_filter_fn * tfun) : m_tfun(tfun) {} - virtual void operator()(relation_base & r, const relation_base & src) { + void operator()(relation_base & r, const relation_base & src) override { SASSERT(r.from_table()); SASSERT(src.from_table()); diff --git a/src/muz/rel/dl_table_relation.h b/src/muz/rel/dl_table_relation.h index 16ff8c482..8ebb6d44d 100644 --- a/src/muz/rel/dl_table_relation.h +++ b/src/muz/rel/dl_table_relation.h @@ -46,40 +46,40 @@ namespace datalog { table_plugin & get_table_plugin() { return m_table_plugin; } - virtual bool can_handle_signature(const relation_signature & s); + bool can_handle_signature(const relation_signature & s) override; - virtual relation_base * mk_empty(const relation_signature & s); + relation_base * mk_empty(const relation_signature & s) override; virtual relation_base * mk_full_relation(const relation_signature & s, func_decl* p, family_id kind); relation_base * mk_from_table(const relation_signature & s, table_base * t); protected: - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, - const unsigned * permutation); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); - virtual relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & t, - const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - virtual relation_transformer_fn * mk_select_equal_and_project_fn(const relation_base & t, - const relation_element & value, unsigned col); + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, + const unsigned * permutation) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; + relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) override; + relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & t, + const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) override; + relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) override; + relation_transformer_fn * mk_select_equal_and_project_fn(const relation_base & t, + const relation_element & value, unsigned col) override; }; class table_relation : public relation_base { @@ -107,24 +107,24 @@ namespace datalog { table_base & get_table() { return *m_table; } const table_base & get_table() const { return *m_table; } - virtual bool empty() const { return m_table->empty(); } + bool empty() const override { return m_table->empty(); } void add_table_fact(const table_fact & f); - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual relation_base * clone() const; - virtual relation_base * complement(func_decl* p) const; - virtual void to_formula(expr_ref& fml) const { get_table().to_formula(get_signature(), fml); } + void add_fact(const relation_fact & f) override; + bool contains_fact(const relation_fact & f) const override; + relation_base * clone() const override; + relation_base * complement(func_decl* p) const override; + void to_formula(expr_ref& fml) const override { get_table().to_formula(get_signature(), fml); } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { get_table().display(out); } - virtual void display_tuples(func_decl & pred, std::ostream & out) const; + void display_tuples(func_decl & pred, std::ostream & out) const override; - virtual unsigned get_size_estimate_rows() const { return m_table->get_size_estimate_rows(); } - virtual unsigned get_size_estimate_bytes() const { return m_table->get_size_estimate_bytes(); } - virtual bool knows_exact_size() const { return m_table->knows_exact_size(); } + unsigned get_size_estimate_rows() const override { return m_table->get_size_estimate_rows(); } + unsigned get_size_estimate_bytes() const override { return m_table->get_size_estimate_bytes(); } + bool knows_exact_size() const override { return m_table->knows_exact_size(); } }; }; diff --git a/src/muz/rel/dl_vector_relation.h b/src/muz/rel/dl_vector_relation.h index 85e7a78d1..fe1d603fe 100644 --- a/src/muz/rel/dl_vector_relation.h +++ b/src/muz/rel/dl_vector_relation.h @@ -55,12 +55,12 @@ namespace datalog { } } - virtual ~vector_relation() { + ~vector_relation() override { dealloc(m_eqs); dealloc(m_elems); } - virtual void swap(relation_base& other) { + void swap(relation_base& other) override { vector_relation& o = dynamic_cast(other); if (&o == this) return; std::swap(o.m_eqs, m_eqs); @@ -85,7 +85,7 @@ namespace datalog { } - virtual bool empty() const { return m_empty; } + bool empty() const override { return m_empty; } T& operator[](unsigned i) { return (*m_elems)[find(i)]; } @@ -93,7 +93,7 @@ namespace datalog { virtual void display_index(unsigned i, T const& t, std::ostream& out) const = 0; - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { if (empty()) { out << "empty\n"; return; diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index c8a489d69..c73b8356d 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -36,13 +36,13 @@ namespace datalog { { } - virtual bool empty() const { + bool empty() const override { return m_empty; } - virtual bool is_precise() const { return false; } + bool is_precise() const override { return false; } - virtual void add_fact(const relation_fact & f) { + void add_fact(const relation_fact & f) override { SASSERT(m_empty); SASSERT(!m_basis_valid); m_empty = false; @@ -60,12 +60,12 @@ namespace datalog { } } - virtual bool contains_fact(const relation_fact & f) const { + bool contains_fact(const relation_fact & f) const override { UNREACHABLE(); return false; } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { if (m_fn) { out << m_fn->get_name() << "\n"; } @@ -82,18 +82,18 @@ namespace datalog { } } - virtual karr_relation * clone() const { + karr_relation * clone() const override { karr_relation* result = alloc(karr_relation, m_plugin, m_fn, get_signature(), m_empty); result->copy(*this); return result; } - virtual karr_relation * complement(func_decl*) const { + karr_relation * complement(func_decl*) const override { UNREACHABLE(); return 0; } - virtual void to_formula(expr_ref& fml) const { + void to_formula(expr_ref& fml) const override { if (empty()) { fml = m.mk_false(); } @@ -514,7 +514,7 @@ namespace datalog { : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ } - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + relation_base * operator()(const relation_base & _r1, const relation_base & _r2) override { karr_relation const& r1 = get(_r1); karr_relation const& r2 = get(_r2); karr_relation_plugin& p = r1.get_plugin(); @@ -540,7 +540,7 @@ namespace datalog { : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { } - virtual relation_base * operator()(const relation_base & _r) { + relation_base * operator()(const relation_base & _r) override { karr_relation const& r = get(_r); karr_relation_plugin& p = r.get_plugin(); karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); @@ -559,7 +559,7 @@ namespace datalog { rename_fn(karr_relation_plugin& p, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) {} - virtual relation_base * operator()(const relation_base & _r) { + relation_base * operator()(const relation_base & _r) override { karr_relation const& r = get(_r); karr_relation_plugin& p = r.get_plugin(); karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); @@ -676,7 +676,7 @@ namespace datalog { public: union_fn() {} - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) override { karr_relation& r = get(_r); karr_relation const& src = get(_src); @@ -707,7 +707,7 @@ namespace datalog { filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) : m_identical_cols(col_cnt, identical_cols) {} - virtual void operator()(relation_base & _r) { + void operator()(relation_base & _r) override { karr_relation & r = get(_r); TRACE("dl", r.display(tout << "src:\n");); r.get_ineqs(); @@ -747,7 +747,7 @@ namespace datalog { m_valid = arith.is_numeral(value, m_value) && m_value.is_int(); } - virtual void operator()(relation_base & _r) { + void operator()(relation_base & _r) override { karr_relation & r = get(_r); if (m_valid) { r.get_ineqs(); @@ -779,7 +779,7 @@ namespace datalog { m_cond(cond, t.get_plugin().get_ast_manager()) { } - void operator()(relation_base& t) { + void operator()(relation_base& t) override { get(t).filter_interpreted(m_cond); TRACE("dl", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); } diff --git a/src/muz/rel/karr_relation.h b/src/muz/rel/karr_relation.h index 47e10f09e..e8637f2bd 100644 --- a/src/muz/rel/karr_relation.h +++ b/src/muz/rel/karr_relation.h @@ -45,33 +45,33 @@ namespace datalog { a(get_ast_manager()) {} - virtual bool can_handle_signature(const relation_signature & sig) { + bool can_handle_signature(const relation_signature & sig) override { return get_manager().get_context().karr(); } static symbol get_name() { return symbol("karr_relation"); } - virtual relation_base * mk_empty(const relation_signature & s); + relation_base * mk_empty(const relation_signature & s) override; - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + relation_base * mk_full(func_decl* p, const relation_signature & s) override; static karr_relation& get(relation_base& r); static karr_relation const & get(relation_base const& r); - virtual relation_join_fn * mk_join_fn( - const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + relation_join_fn * mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; private: bool dualizeI(matrix& dst, matrix const& src); diff --git a/src/muz/rel/rel_context.h b/src/muz/rel/rel_context.h index f4a87d496..0a31c4e9f 100644 --- a/src/muz/rel/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -56,72 +56,72 @@ namespace datalog { public: rel_context(context& ctx); - virtual ~rel_context(); + ~rel_context() override; - virtual relation_manager & get_rmanager(); - virtual const relation_manager & get_rmanager() const; + relation_manager & get_rmanager() override; + const relation_manager & get_rmanager() const override; ast_manager& get_manager() const { return m; } context& get_context() const { return m_context; } - virtual relation_base & get_relation(func_decl * pred); - virtual relation_base * try_get_relation(func_decl * pred) const; - virtual bool is_empty_relation(func_decl* pred) const; - virtual expr_ref try_get_formula(func_decl * pred) const; - virtual expr_ref get_answer() { return m_answer; } + relation_base & get_relation(func_decl * pred) override; + relation_base * try_get_relation(func_decl * pred) const override; + bool is_empty_relation(func_decl* pred) const override; + expr_ref try_get_formula(func_decl * pred) const override; + expr_ref get_answer() override { return m_answer; } - virtual bool output_profile() const; + bool output_profile() const override; - virtual lbool query(expr* q); - virtual lbool query(unsigned num_rels, func_decl * const* rels); + lbool query(expr* q) override; + lbool query(unsigned num_rels, func_decl * const* rels) override; - virtual void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, - symbol const * relation_names); + void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, + symbol const * relation_names) override; - virtual void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred); + void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred) override; - virtual void collect_statistics(statistics& st) const; + void collect_statistics(statistics& st) const override; - virtual void updt_params(); + void updt_params() override; /** \brief Restrict the set of used predicates to \c res. The function deallocates unsused relations, it does not deal with rules. */ - virtual void restrict_predicates(func_decl_set const& predicates); + void restrict_predicates(func_decl_set const& predicates) override; - virtual void transform_rules(); + void transform_rules() override; - virtual bool try_get_size(func_decl* pred, unsigned& rel_size) const; + bool try_get_size(func_decl* pred, unsigned& rel_size) const override; /** \brief query result if it contains fact. */ - virtual bool result_contains_fact(relation_fact const& f); + bool result_contains_fact(relation_fact const& f) override; - virtual void collect_non_empty_predicates(func_decl_set& ps) { + void collect_non_empty_predicates(func_decl_set& ps) override { return get_rmanager().collect_non_empty_predicates(ps); } /** \brief add facts to relation */ - virtual void add_fact(func_decl* pred, relation_fact const& fact); - virtual void add_fact(func_decl* pred, table_fact const& fact); + void add_fact(func_decl* pred, relation_fact const& fact) override; + void add_fact(func_decl* pred, table_fact const& fact) override; /** \brief check if facts were added to relation */ - virtual bool has_facts(func_decl * pred) const; + bool has_facts(func_decl * pred) const override; /** \brief Store the relation \c rel under the predicate \c pred. The \c context object takes over the ownership of the relation object. */ - virtual void store_relation(func_decl * pred, relation_base * rel); + void store_relation(func_decl * pred, relation_base * rel) override; - virtual void display_output_facts(rule_set const& rules, std::ostream & out) const; - virtual void display_facts(std::ostream & out) const; + void display_output_facts(rule_set const& rules, std::ostream & out) const override; + void display_facts(std::ostream & out) const override; - virtual void display_profile(std::ostream& out); + void display_profile(std::ostream& out) override; - virtual lbool saturate(); + lbool saturate() override; }; }; diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index febabb36d..a5b9a2084 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -328,7 +328,7 @@ namespace datalog { t2.expand_column_vector(m_cols2); } - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + relation_base * operator()(const relation_base & _r1, const relation_base & _r2) override { udoc_relation const& r1 = get(_r1); udoc_relation const& r2 = get(_r2); TRACE("doc", r1.display(tout << "r1:\n"); r2.display(tout << "r2:\n");); @@ -369,7 +369,7 @@ namespace datalog { } } - virtual relation_base * operator()(const relation_base & tb) { + relation_base * operator()(const relation_base & tb) override { TRACE("doc", tb.display(tout << "src:\n");); udoc_relation const& t = get(tb); udoc_plugin& p = t.get_plugin(); @@ -462,7 +462,7 @@ namespace datalog { } } - virtual relation_base * operator()(const relation_base & _r) { + relation_base * operator()(const relation_base & _r) override { udoc_relation const& r = get(_r); TRACE("doc", r.display(tout << "r:\n");); udoc_plugin& p = r.get_plugin(); @@ -494,7 +494,7 @@ namespace datalog { public: union_fn() {} - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) override { TRACE("doc", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); udoc_relation& r = get(_r); udoc_relation const& src = get(_src); @@ -574,7 +574,7 @@ namespace datalog { } } - virtual void operator()(relation_base & _r) { + void operator()(relation_base & _r) override { udoc_relation& r = get(_r); udoc& d = r.get_udoc(); doc_manager& dm = r.get_dm(); @@ -602,10 +602,10 @@ namespace datalog { SASSERT(num_bits == hi - lo); dm.tbvm().set(m_filter->pos(), r, hi-1, lo); } - virtual ~filter_equal_fn() { + ~filter_equal_fn() override { dm.deallocate(m_filter); } - virtual void operator()(relation_base & tb) { + void operator()(relation_base & tb) override { udoc_relation & t = get(tb); t.get_udoc().intersect(dm, *m_filter); SASSERT(t.get_udoc().well_formed(t.get_dm())); @@ -932,11 +932,11 @@ namespace datalog { m_udoc.display(dm, tout) << "\n";); } - virtual ~filter_interpreted_fn() { + ~filter_interpreted_fn() override { m_udoc.reset(dm); } - virtual void operator()(relation_base & tb) { + void operator()(relation_base & tb) override { udoc_relation & t = get(tb); udoc& u = t.get_udoc(); SASSERT(u.well_formed(dm)); @@ -987,7 +987,7 @@ namespace datalog { // TBD: replace this by "join" given below. - virtual relation_base* operator()(relation_base const& t1, relation_base const& t2) { + relation_base* operator()(relation_base const& t1, relation_base const& t2) override { #if 1 return join(get(t1), get(t2)); #else @@ -1043,7 +1043,7 @@ namespace datalog { public: join_project_and_fn() {} - virtual relation_base* operator()(relation_base const& t1, relation_base const& t2) { + relation_base* operator()(relation_base const& t1, relation_base const& t2) override { udoc_relation *result = get(t1.clone()); result->get_udoc().intersect(result->get_dm(), get(t2).get_udoc()); return result; @@ -1121,7 +1121,7 @@ namespace datalog { neg.expand_column_vector(m_neg_cols); } - virtual void operator()(relation_base& tb, const relation_base& negb) { + void operator()(relation_base& tb, const relation_base& negb) override { udoc_relation& t = get(tb); udoc_relation const& n = get(negb); IF_VERBOSE(3, t.display(verbose_stream() << "dst:");); @@ -1223,10 +1223,10 @@ namespace datalog { t.compile_guard(guard, m_udoc, m_to_delete); } - virtual ~filter_proj_fn() { + ~filter_proj_fn() override { m_udoc.reset(dm); } - virtual relation_base* operator()(const relation_base & tb) { + relation_base* operator()(const relation_base & tb) override { udoc_relation const & t = get(tb); udoc const& u1 = t.get_udoc(); doc_manager& dm = t.get_dm(); diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 15918d80d..87755f75e 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -39,21 +39,21 @@ namespace datalog { expr_ref to_formula(doc const& d) const; public: udoc_relation(udoc_plugin& p, relation_signature const& s); - virtual ~udoc_relation(); - virtual void reset(); - virtual void add_fact(const relation_fact & f); - virtual void add_new_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual udoc_relation * clone() const; - virtual udoc_relation * complement(func_decl*) const; - virtual void to_formula(expr_ref& fml) const; + ~udoc_relation() override; + void reset() override; + void add_fact(const relation_fact & f) override; + void add_new_fact(const relation_fact & f) override; + bool contains_fact(const relation_fact & f) const override; + udoc_relation * clone() const override; + udoc_relation * complement(func_decl*) const override; + void to_formula(expr_ref& fml) const override; udoc_plugin& get_plugin() const; - virtual bool fast_empty() const { return m_elems.is_empty(); } - virtual bool empty() const; - virtual void display(std::ostream& out) const; - virtual bool is_precise() const { return true; } - virtual unsigned get_size_estimate_rows() const { return m_elems.size(); } - virtual unsigned get_size_estimate_bytes() const; + bool fast_empty() const override { return m_elems.is_empty(); } + bool empty() const override; + void display(std::ostream& out) const override; + bool is_precise() const override { return true; } + unsigned get_size_estimate_rows() const override { return m_elems.size(); } + unsigned get_size_estimate_bytes() const override; doc_manager& get_dm() const { return dm; } udoc const& get_udoc() const { return m_elems; } @@ -113,38 +113,38 @@ namespace datalog { expr* mk_numeral(rational const& r, sort* s); public: udoc_plugin(relation_manager& rm); - ~udoc_plugin(); - virtual bool can_handle_signature(const relation_signature & s); + ~udoc_plugin() override; + bool can_handle_signature(const relation_signature & s) override; static symbol get_name() { return symbol("doc"); } - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn( + relation_base * mk_empty(const relation_signature & s) override; + relation_base * mk_full(func_decl* p, const relation_signature & s) override; + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) override; + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) override; + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) override; + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) override; + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) override; + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) override; + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition) override; + relation_intersection_filter_fn * mk_filter_by_negation_fn( const relation_base& t, const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, - const unsigned *negated_cols); - virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn( + const unsigned *negated_cols) override; + relation_transformer_fn * mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, - unsigned removed_col_cnt, const unsigned * removed_cols); - virtual relation_join_fn * mk_join_project_fn( + unsigned removed_col_cnt, const unsigned * removed_cols) override; + relation_join_fn * mk_join_project_fn( relation_base const& t1, relation_base const& t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols); - + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) override; + void disable_fast_pass() { m_disable_fast_pass = true; } }; }; diff --git a/src/muz/spacer/spacer_dl_interface.h b/src/muz/spacer/spacer_dl_interface.h index 1581762d5..e5a41427d 100644 --- a/src/muz/spacer/spacer_dl_interface.h +++ b/src/muz/spacer/spacer_dl_interface.h @@ -45,39 +45,39 @@ class dl_interface : public datalog::engine_base { public: dl_interface(datalog::context& ctx); - ~dl_interface(); + ~dl_interface() override; - lbool query(expr* query); + lbool query(expr* query) override; - lbool query_from_lvl(expr* query, unsigned lvl); + lbool query_from_lvl(expr* query, unsigned lvl) override; - void display_certificate(std::ostream& out) const; + void display_certificate(std::ostream& out) const override; - void collect_statistics(statistics& st) const; + void collect_statistics(statistics& st) const override; - void reset_statistics(); + void reset_statistics() override; - expr_ref get_answer(); + expr_ref get_answer() override; - expr_ref get_ground_sat_answer(); + expr_ref get_ground_sat_answer() override; - void get_rules_along_trace(datalog::rule_ref_vector& rules); + void get_rules_along_trace(datalog::rule_ref_vector& rules) override; - unsigned get_num_levels(func_decl* pred); + unsigned get_num_levels(func_decl* pred) override; - expr_ref get_cover_delta(int level, func_decl* pred); + expr_ref get_cover_delta(int level, func_decl* pred) override; - void add_cover(int level, func_decl* pred, expr* property); + void add_cover(int level, func_decl* pred, expr* property) override; - void add_invariant(func_decl* pred, expr* property); + void add_invariant(func_decl* pred, expr* property) override; - expr_ref get_reachable(func_decl *pred); + expr_ref get_reachable(func_decl *pred) override; - void updt_params(); + void updt_params() override; - model_ref get_model(); + model_ref get_model() override; - proof_ref get_proof(); + proof_ref get_proof() override; }; } diff --git a/src/muz/spacer/spacer_generalizers.h b/src/muz/spacer/spacer_generalizers.h index aa542ec04..1962e74e0 100644 --- a/src/muz/spacer/spacer_generalizers.h +++ b/src/muz/spacer/spacer_generalizers.h @@ -30,8 +30,8 @@ namespace spacer { class lemma_sanity_checker : public lemma_generalizer { public: lemma_sanity_checker(context& ctx) : lemma_generalizer(ctx) {} - virtual ~lemma_sanity_checker() {} - virtual void operator()(lemma_ref &lemma); + ~lemma_sanity_checker() override {} + void operator()(lemma_ref &lemma) override; }; /** @@ -53,11 +53,11 @@ class lemma_bool_inductive_generalizer : public lemma_generalizer { public: lemma_bool_inductive_generalizer(context& ctx, unsigned failure_limit) : lemma_generalizer(ctx), m_failure_limit(failure_limit) {} - virtual ~lemma_bool_inductive_generalizer() {} - virtual void operator()(lemma_ref &lemma); + ~lemma_bool_inductive_generalizer() override {} + void operator()(lemma_ref &lemma) override; - virtual void collect_statistics(statistics& st) const; - virtual void reset_statistics() {m_st.reset();} + void collect_statistics(statistics& st) const override; + void reset_statistics() override {m_st.reset();} }; class unsat_core_generalizer : public lemma_generalizer { @@ -72,26 +72,26 @@ class unsat_core_generalizer : public lemma_generalizer { stats m_st; public: unsat_core_generalizer(context &ctx) : lemma_generalizer(ctx) {} - virtual ~unsat_core_generalizer() {} - virtual void operator()(lemma_ref &lemma); + ~unsat_core_generalizer() override {} + void operator()(lemma_ref &lemma) override; - virtual void collect_statistics(statistics &st) const; - virtual void reset_statistics() {m_st.reset();} + void collect_statistics(statistics &st) const override; + void reset_statistics() override {m_st.reset();} }; class lemma_array_eq_generalizer : public lemma_generalizer { public: lemma_array_eq_generalizer(context &ctx) : lemma_generalizer(ctx) {} - virtual ~lemma_array_eq_generalizer() {} - virtual void operator()(lemma_ref &lemma); + ~lemma_array_eq_generalizer() override {} + void operator()(lemma_ref &lemma) override; }; class lemma_eq_generalizer : public lemma_generalizer { public: lemma_eq_generalizer(context &ctx) : lemma_generalizer(ctx) {} - virtual ~lemma_eq_generalizer() {} - virtual void operator()(lemma_ref &lemma); + ~lemma_eq_generalizer() override {} + void operator()(lemma_ref &lemma) override; }; diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 8194379b8..8dbac022e 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -86,10 +86,10 @@ public: m_farkas_a_const(farkas_a_const) {} - virtual ~itp_solver() {} + ~itp_solver() override {} /* itp solver specific */ - virtual void get_unsat_core(expr_ref_vector &core); + void get_unsat_core(expr_ref_vector &core) override; virtual void get_itp_core(expr_ref_vector &core); void set_split_literals(bool v) {m_split_literals = v;} bool mk_proxies(expr_ref_vector &v, unsigned from = 0); @@ -104,53 +104,53 @@ public: /* solver interface */ - virtual solver* translate(ast_manager &m, params_ref const &p) + solver* translate(ast_manager &m, params_ref const &p) override {return m_solver.translate(m, p);} - virtual void updt_params(params_ref const &p) + void updt_params(params_ref const &p) override {m_solver.updt_params(p);} - virtual void collect_param_descrs(param_descrs &r) + void collect_param_descrs(param_descrs &r) override {m_solver.collect_param_descrs(r);} - virtual void set_produce_models(bool f) + void set_produce_models(bool f) override {m_solver.set_produce_models(f);} - virtual void assert_expr(expr *t) + void assert_expr(expr *t) override {m_solver.assert_expr(t);} - virtual void assert_expr(expr *t, expr *a) + void assert_expr(expr *t, expr *a) override {NOT_IMPLEMENTED_YET();} - virtual void push(); - virtual void pop(unsigned n); - virtual unsigned get_scope_level() const + void push() override; + void pop(unsigned n) override; + unsigned get_scope_level() const override {return m_solver.get_scope_level();} - virtual lbool check_sat(unsigned num_assumptions, expr * const *assumptions); - virtual void set_progress_callback(progress_callback *callback) + lbool check_sat(unsigned num_assumptions, expr * const *assumptions) override; + void set_progress_callback(progress_callback *callback) override {m_solver.set_progress_callback(callback);} - virtual unsigned get_num_assertions() const + unsigned get_num_assertions() const override {return m_solver.get_num_assertions();} - virtual expr * get_assertion(unsigned idx) const + expr * get_assertion(unsigned idx) const override {return m_solver.get_assertion(idx);} - virtual unsigned get_num_assumptions() const + unsigned get_num_assumptions() const override {return m_solver.get_num_assumptions();} - virtual expr * get_assumption(unsigned idx) const + expr * get_assumption(unsigned idx) const override {return m_solver.get_assumption(idx);} - virtual std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const + std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const override { return m_solver.display(out, n, es); } /* check_sat_result interface */ - virtual void collect_statistics(statistics &st) const ; + void collect_statistics(statistics &st) const override ; virtual void reset_statistics(); - virtual void get_unsat_core(ptr_vector &r); - virtual void get_model(model_ref &m) {m_solver.get_model(m);} - virtual proof *get_proof() {return m_solver.get_proof();} - virtual std::string reason_unknown() const + void get_unsat_core(ptr_vector &r) override; + void get_model(model_ref &m) override {m_solver.get_model(m);} + proof *get_proof() override {return m_solver.get_proof();} + std::string reason_unknown() const override {return m_solver.reason_unknown();} - virtual void set_reason_unknown(char const* msg) + void set_reason_unknown(char const* msg) override {m_solver.set_reason_unknown(msg);} - virtual void get_labels(svector &r) + void get_labels(svector &r) override {m_solver.get_labels(r);} - virtual ast_manager &get_manager() const {return m;} + ast_manager &get_manager() const override {return m;} virtual void refresh(); diff --git a/src/muz/spacer/spacer_qe_project.cpp b/src/muz/spacer/spacer_qe_project.cpp index 9f4f4e4fe..cde188aac 100644 --- a/src/muz/spacer/spacer_qe_project.cpp +++ b/src/muz/spacer/spacer_qe_project.cpp @@ -190,14 +190,14 @@ namespace qe { class is_relevant_default : public i_expr_pred { public: - bool operator()(expr* e) { + bool operator()(expr* e) override { return true; } }; class mk_atom_default : public i_nnf_atom { public: - virtual void operator()(expr* e, bool pol, expr_ref& result) { + void operator()(expr* e, bool pol, expr_ref& result) override { if (pol) result = e; else result = result.get_manager().mk_not(e); } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index 96d03140c..2ea4b4b51 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -43,7 +43,7 @@ class unsat_core_plugin_lemma : public unsat_core_plugin { public: unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){}; - virtual void compute_partial_core(proof* step) override; + void compute_partial_core(proof* step) override; private: void add_lowest_split_to_core(proof* step) const; @@ -55,7 +55,7 @@ class unsat_core_plugin_farkas_lemma : public unsat_core_plugin { public: unsat_core_plugin_farkas_lemma(unsat_core_learner& learner, bool split_literals, bool use_constant_from_a=true) : unsat_core_plugin(learner), m_split_literals(split_literals), m_use_constant_from_a(use_constant_from_a) {}; - virtual void compute_partial_core(proof* step) override; + void compute_partial_core(proof* step) override; private: bool m_split_literals; @@ -71,8 +71,8 @@ private: public: unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner), m(m) {}; - virtual void compute_partial_core(proof* step) override; - virtual void finalize() override; + void compute_partial_core(proof* step) override; + void finalize() override; protected: vector > > m_linear_combinations; @@ -88,7 +88,7 @@ private: public: unsat_core_plugin_farkas_lemma_bounded(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin_farkas_lemma_optimized(learner, m) {}; - virtual void finalize() override; + void finalize() override; }; class unsat_core_plugin_min_cut : public unsat_core_plugin { @@ -96,8 +96,8 @@ private: public: unsat_core_plugin_min_cut(unsat_core_learner& learner, ast_manager& m); - virtual void compute_partial_core(proof* step) override; - virtual void finalize() override; + void compute_partial_core(proof* step) override; + void finalize() override; private: ast_manager& m; diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index fed64c589..38e038d9e 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -65,46 +65,46 @@ private: void refresh(); public: - virtual ~virtual_solver(); - virtual unsigned get_num_assumptions() const + ~virtual_solver() override; + unsigned get_num_assumptions() const override { unsigned sz = solver_na2as::get_num_assumptions(); return m_virtual ? sz - 1 : sz; } - virtual expr* get_assumption(unsigned idx) const + expr* get_assumption(unsigned idx) const override { if(m_virtual) { idx++; } return solver_na2as::get_assumption(idx); } - virtual void get_unsat_core(ptr_vector &r); - virtual void assert_expr(expr *e); - virtual void collect_statistics(statistics &st) const {} - virtual void get_model(model_ref &m) {m_context.get_model(m);} - virtual proof* get_proof(); - virtual std::string reason_unknown() const + void get_unsat_core(ptr_vector &r) override; + void assert_expr(expr *e) override; + void collect_statistics(statistics &st) const override {} + void get_model(model_ref &m) override {m_context.get_model(m);} + proof* get_proof() override; + std::string reason_unknown() const override {return m_context.last_failure_as_string();} - virtual void set_reason_unknown(char const *msg) + void set_reason_unknown(char const *msg) override {m_context.set_reason_unknown(msg);} - virtual ast_manager& get_manager() const {return m;} - virtual void get_labels(svector &r); - virtual void set_produce_models(bool f); + ast_manager& get_manager() const override {return m;} + void get_labels(svector &r) override; + void set_produce_models(bool f) override; virtual bool get_produce_models(); virtual smt_params &fparams(); virtual void reset(); - virtual void set_progress_callback(progress_callback *callback) + void set_progress_callback(progress_callback *callback) override {UNREACHABLE();} - virtual solver *translate(ast_manager &m, params_ref const &p); + solver *translate(ast_manager &m, params_ref const &p) override; - virtual void updt_params(params_ref const &p); - virtual void collect_param_descrs(param_descrs &r); + void updt_params(params_ref const &p) override; + void collect_param_descrs(param_descrs &r) override; protected: - virtual lbool check_sat_core(unsigned num_assumptions, expr *const * assumptions); - virtual void push_core(); - virtual void pop_core(unsigned n); + lbool check_sat_core(unsigned num_assumptions, expr *const * assumptions) override; + void push_core() override; + void pop_core(unsigned n) override; }; /// multi-solver abstraction on top of a single smt::kernel diff --git a/src/muz/tab/tab_context.h b/src/muz/tab/tab_context.h index 329234524..84d6e2420 100644 --- a/src/muz/tab/tab_context.h +++ b/src/muz/tab/tab_context.h @@ -32,13 +32,13 @@ namespace datalog { imp* m_imp; public: tab(context& ctx); - ~tab(); - virtual lbool query(expr* query); - virtual void cleanup(); - virtual void reset_statistics(); - virtual void collect_statistics(statistics& st) const; - virtual void display_certificate(std::ostream& out) const; - virtual expr_ref get_answer(); + ~tab() override; + lbool query(expr* query) override; + void cleanup() override; + void reset_statistics() override; + void collect_statistics(statistics& st) const override; + void display_certificate(std::ostream& out) const override; + expr_ref get_answer() override; }; }; diff --git a/src/muz/transforms/dl_mk_array_blast.h b/src/muz/transforms/dl_mk_array_blast.h index e7b951168..ba2f826dd 100644 --- a/src/muz/transforms/dl_mk_array_blast.h +++ b/src/muz/transforms/dl_mk_array_blast.h @@ -66,9 +66,9 @@ namespace datalog { */ mk_array_blast(context & ctx, unsigned priority); - virtual ~mk_array_blast(); + ~mk_array_blast() override; - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; diff --git a/src/muz/transforms/dl_mk_array_eq_rewrite.h b/src/muz/transforms/dl_mk_array_eq_rewrite.h index 166c01142..298697998 100644 --- a/src/muz/transforms/dl_mk_array_eq_rewrite.h +++ b/src/muz/transforms/dl_mk_array_eq_rewrite.h @@ -40,8 +40,8 @@ namespace datalog { public: mk_array_eq_rewrite(context & ctx, unsigned priority); - rule_set * operator()(rule_set const & source); - virtual ~mk_array_eq_rewrite(){} + rule_set * operator()(rule_set const & source) override; + ~mk_array_eq_rewrite() override{} }; diff --git a/src/muz/transforms/dl_mk_array_instantiation.h b/src/muz/transforms/dl_mk_array_instantiation.h index b87f679fc..cd5715a4f 100644 --- a/src/muz/transforms/dl_mk_array_instantiation.h +++ b/src/muz/transforms/dl_mk_array_instantiation.h @@ -112,8 +112,8 @@ namespace datalog { expr_ref_vector getId(app*old_pred, const expr_ref_vector& new_args); public: mk_array_instantiation(context & ctx, unsigned priority); - rule_set * operator()(rule_set const & source); - virtual ~mk_array_instantiation(){} + rule_set * operator()(rule_set const & source) override; + ~mk_array_instantiation() override{} }; diff --git a/src/muz/transforms/dl_mk_backwards.h b/src/muz/transforms/dl_mk_backwards.h index ca441fd0a..344da2afb 100644 --- a/src/muz/transforms/dl_mk_backwards.h +++ b/src/muz/transforms/dl_mk_backwards.h @@ -28,8 +28,8 @@ namespace datalog { context& m_ctx; public: mk_backwards(context & ctx, unsigned priority = 33000); - ~mk_backwards(); - rule_set * operator()(rule_set const & source); + ~mk_backwards() override; + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 3c8045e34..8637af14f 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -59,11 +59,11 @@ namespace datalog { m_new_funcs.push_back(new_f); } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { return alloc(bit_blast_model_converter, m); } - virtual void operator()(model_ref & model) { + void operator()(model_ref & model) override { for (unsigned i = 0; i < m_new_funcs.size(); ++i) { func_decl* p = m_new_funcs[i].get(); func_decl* q = m_old_funcs[i].get(); diff --git a/src/muz/transforms/dl_mk_bit_blast.h b/src/muz/transforms/dl_mk_bit_blast.h index 31df57567..a8be254a6 100644 --- a/src/muz/transforms/dl_mk_bit_blast.h +++ b/src/muz/transforms/dl_mk_bit_blast.h @@ -28,8 +28,8 @@ namespace datalog { impl* m_impl; public: mk_bit_blast(context & ctx, unsigned priority = 35000); - ~mk_bit_blast(); - rule_set * operator()(rule_set const & source); + ~mk_bit_blast() override; + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_coalesce.h b/src/muz/transforms/dl_mk_coalesce.h index 47d702fbb..7721d7556 100644 --- a/src/muz/transforms/dl_mk_coalesce.h +++ b/src/muz/transforms/dl_mk_coalesce.h @@ -52,7 +52,7 @@ namespace datalog { */ mk_coalesce(context & ctx); - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_coi_filter.h b/src/muz/transforms/dl_mk_coi_filter.h index c03308b6a..4fe7033bd 100644 --- a/src/muz/transforms/dl_mk_coi_filter.h +++ b/src/muz/transforms/dl_mk_coi_filter.h @@ -42,7 +42,7 @@ namespace datalog { m(ctx.get_manager()), m_context(ctx) {} - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; } diff --git a/src/muz/transforms/dl_mk_filter_rules.h b/src/muz/transforms/dl_mk_filter_rules.h index b81921d59..3e357dc4e 100644 --- a/src/muz/transforms/dl_mk_filter_rules.h +++ b/src/muz/transforms/dl_mk_filter_rules.h @@ -73,11 +73,11 @@ namespace datalog { public: mk_filter_rules(context & ctx); - ~mk_filter_rules(); + ~mk_filter_rules() override; /** \brief Return a new rule set where only filter rules contain atoms with repeated variables and/or values. */ - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.h b/src/muz/transforms/dl_mk_interp_tail_simplifier.h index a8a7393cd..e9120b9b1 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.h +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.h @@ -90,7 +90,7 @@ namespace datalog { bool transform_rules(const rule_set & orig, rule_set & tgt); public: mk_interp_tail_simplifier(context & ctx, unsigned priority=40000); - virtual ~mk_interp_tail_simplifier(); + ~mk_interp_tail_simplifier() override; /**If rule should be retained, assign transformed version to res and return true; if rule can be deleted, return false. @@ -100,7 +100,7 @@ namespace datalog { */ bool transform_rule(rule * r, rule_ref& res); - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 48219eeb9..5dafafb19 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -111,7 +111,7 @@ namespace datalog { add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m), m_invs(m) {} - virtual ~add_invariant_model_converter() { } + ~add_invariant_model_converter() override { } void add(func_decl* p, expr* inv) { if (!m.is_true(inv)) { @@ -120,7 +120,7 @@ namespace datalog { } } - virtual void operator()(model_ref & mr) { + void operator()(model_ref & mr) override { for (unsigned i = 0; i < m_funcs.size(); ++i) { func_decl* p = m_funcs[i].get(); func_interp* f = mr->get_func_interp(p); @@ -142,7 +142,7 @@ namespace datalog { } } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { add_invariant_model_converter* mc = alloc(add_invariant_model_converter, m); for (unsigned i = 0; i < m_funcs.size(); ++i) { mc->add(translator(m_funcs[i].get()), m_invs[i].get()); diff --git a/src/muz/transforms/dl_mk_karr_invariants.h b/src/muz/transforms/dl_mk_karr_invariants.h index b31f1f8d9..cf021efda 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.h +++ b/src/muz/transforms/dl_mk_karr_invariants.h @@ -65,9 +65,9 @@ namespace datalog { public: mk_karr_invariants(context & ctx, unsigned priority); - virtual ~mk_karr_invariants(); + ~mk_karr_invariants() override; - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; diff --git a/src/muz/transforms/dl_mk_loop_counter.h b/src/muz/transforms/dl_mk_loop_counter.h index fb4b6d704..cf79dc218 100644 --- a/src/muz/transforms/dl_mk_loop_counter.h +++ b/src/muz/transforms/dl_mk_loop_counter.h @@ -36,9 +36,9 @@ namespace datalog { app_ref del_arg(app* fn); public: mk_loop_counter(context & ctx, unsigned priority = 33000); - ~mk_loop_counter(); + ~mk_loop_counter() override; - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; func_decl* get_old(func_decl* f) const { return m_new2old.find(f); } diff --git a/src/muz/transforms/dl_mk_magic_sets.h b/src/muz/transforms/dl_mk_magic_sets.h index 73b5e94f6..dc3ad03b7 100644 --- a/src/muz/transforms/dl_mk_magic_sets.h +++ b/src/muz/transforms/dl_mk_magic_sets.h @@ -126,7 +126,7 @@ namespace datalog { */ mk_magic_sets(context & ctx, func_decl* goal); - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_magic_symbolic.h b/src/muz/transforms/dl_mk_magic_symbolic.h index 9c51a5287..451b2c46f 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.h +++ b/src/muz/transforms/dl_mk_magic_symbolic.h @@ -30,8 +30,8 @@ namespace datalog { app_ref mk_query(app* q); public: mk_magic_symbolic(context & ctx, unsigned priority = 33037); - ~mk_magic_symbolic(); - rule_set * operator()(rule_set const & source); + ~mk_magic_symbolic() override; + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index b171aaa7c..a4a5ac35f 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -47,9 +47,9 @@ namespace datalog { qa_model_converter(ast_manager& m): m(m), m_old_funcs(m), m_new_funcs(m) {} - virtual ~qa_model_converter() {} + ~qa_model_converter() override {} - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { return alloc(qa_model_converter, m); } @@ -61,7 +61,7 @@ namespace datalog { m_sorts.push_back(sorts); } - virtual void operator()(model_ref & old_model) { + void operator()(model_ref & old_model) override { model_ref new_model = alloc(model, m); for (unsigned i = 0; i < m_new_funcs.size(); ++i) { func_decl* p = m_new_funcs[i].get(); diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.h b/src/muz/transforms/dl_mk_quantifier_abstraction.h index 593e458b9..83d0e975d 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.h +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.h @@ -51,9 +51,9 @@ namespace datalog { public: mk_quantifier_abstraction(context & ctx, unsigned priority); - virtual ~mk_quantifier_abstraction(); + ~mk_quantifier_abstraction() override; - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.h b/src/muz/transforms/dl_mk_quantifier_instantiation.h index 4f1626ec6..f8e12f712 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.h +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.h @@ -61,9 +61,9 @@ namespace datalog { public: mk_quantifier_instantiation(context & ctx, unsigned priority); - virtual ~mk_quantifier_instantiation(); + ~mk_quantifier_instantiation() override; - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; diff --git a/src/muz/transforms/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h index 55b9b9487..7b00d26ad 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -89,7 +89,7 @@ namespace datalog { obj_map m_positions; public: visitor(context& c, substitution & s): st_visitor(s), m_context(c) { (void) m_context; } - virtual bool operator()(expr* e); + bool operator()(expr* e) override; void reset() { m_unifiers.reset(); } void reset(unsigned sz); svector& can_remove() { return m_can_remove; } @@ -194,9 +194,9 @@ namespace datalog { m_head_visitor(ctx, m_subst), m_tail_visitor(ctx, m_subst) {} - virtual ~mk_rule_inliner() { } + ~mk_rule_inliner() override { } - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index 5bc10b957..abc5d20e7 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -30,7 +30,7 @@ namespace datalog { public: scale_model_converter(ast_manager& m): m(m), m_trail(m), a(m) {} - virtual ~scale_model_converter() {} + ~scale_model_converter() override {} void add_new2old(func_decl* new_f, func_decl* old_f) { m_trail.push_back(old_f); @@ -38,7 +38,7 @@ namespace datalog { m_new2old.insert(new_f, old_f); } - virtual void operator()(model_ref& md) { + void operator()(model_ref& md) override { model_ref old_model = alloc(model, m); obj_map::iterator it = m_new2old.begin(); obj_map::iterator end = m_new2old.end(); @@ -95,7 +95,7 @@ namespace datalog { //TRACE("dl", model_smt2_pp(tout, m, *md, 0); ); } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { UNREACHABLE(); return 0; } diff --git a/src/muz/transforms/dl_mk_scale.h b/src/muz/transforms/dl_mk_scale.h index 10a5ea8b2..c171a1d06 100644 --- a/src/muz/transforms/dl_mk_scale.h +++ b/src/muz/transforms/dl_mk_scale.h @@ -43,8 +43,8 @@ namespace datalog { app_ref mk_constraint(unsigned num_vars, app* q); public: mk_scale(context & ctx, unsigned priority = 33039); - virtual ~mk_scale(); - rule_set * operator()(rule_set const & source); + ~mk_scale() override; + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.h b/src/muz/transforms/dl_mk_separate_negated_tails.h index a5cdda003..aae90b2db 100644 --- a/src/muz/transforms/dl_mk_separate_negated_tails.h +++ b/src/muz/transforms/dl_mk_separate_negated_tails.h @@ -51,7 +51,7 @@ namespace datalog { public: mk_separate_negated_tails(context& ctx, unsigned priority = 21000); - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; } diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index dc11935e3..3c5cf53c7 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -271,14 +271,14 @@ namespace datalog { m_renaming.insert(orig_rule, unsigned_vector(sz, renaming)); } - virtual void operator()(ast_manager& m, unsigned num_source, proof * const * source, proof_ref & result) { + void operator()(ast_manager& m, unsigned num_source, proof * const * source, proof_ref & result) override { SASSERT(num_source == 1); result = source[0]; init_form2rule(); translate_proof(result); } - virtual proof_converter * translate(ast_translation & translator) { + proof_converter * translate(ast_translation & translator) override { UNREACHABLE(); // this would require implementing translation for the dl_context. return 0; @@ -305,7 +305,7 @@ namespace datalog { m_sliceable.insert(f, bv); } - virtual void operator()(model_ref & md) { + void operator()(model_ref & md) override { if (m_slice2old.empty()) { return; } @@ -391,7 +391,7 @@ namespace datalog { TRACE("dl", model_smt2_pp(tout, m, *md, 0); ); } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { UNREACHABLE(); return 0; } diff --git a/src/muz/transforms/dl_mk_slice.h b/src/muz/transforms/dl_mk_slice.h index 4a7d4a81a..0bc58c95a 100644 --- a/src/muz/transforms/dl_mk_slice.h +++ b/src/muz/transforms/dl_mk_slice.h @@ -100,9 +100,9 @@ namespace datalog { */ mk_slice(context & ctx); - virtual ~mk_slice() { } + ~mk_slice() override { } - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; func_decl* get_predicate(func_decl* p) { func_decl* q = p; m_predicates.find(p, q); return q; } diff --git a/src/muz/transforms/dl_mk_subsumption_checker.h b/src/muz/transforms/dl_mk_subsumption_checker.h index 01d828d6e..8c71096c3 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.h +++ b/src/muz/transforms/dl_mk_subsumption_checker.h @@ -80,11 +80,11 @@ namespace datalog { m_context(ctx), m_ref_holder(ctx.get_rule_manager()), m_new_total_relation_discovery_during_transformation(true) {} - ~mk_subsumption_checker() { + ~mk_subsumption_checker() override { reset_dealloc_values(m_ground_unconditional_rule_heads); } - virtual rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_unbound_compressor.h b/src/muz/transforms/dl_mk_unbound_compressor.h index 6f53e0707..b37a2f1a7 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.h +++ b/src/muz/transforms/dl_mk_unbound_compressor.h @@ -86,7 +86,7 @@ namespace datalog { public: mk_unbound_compressor(context & ctx); - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/muz/transforms/dl_mk_unfold.h b/src/muz/transforms/dl_mk_unfold.h index 8ebe2d328..02469e6fb 100644 --- a/src/muz/transforms/dl_mk_unfold.h +++ b/src/muz/transforms/dl_mk_unfold.h @@ -44,7 +44,7 @@ namespace datalog { */ mk_unfold(context & ctx); - rule_set * operator()(rule_set const & source); + rule_set * operator()(rule_set const & source) override; }; }; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 7b4be9842..ebe226db0 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -73,15 +73,15 @@ namespace opt { public: maxsmt_solver_base(maxsat_context& c, weights_t& ws, expr_ref_vector const& soft); - virtual ~maxsmt_solver_base() {} - virtual rational get_lower() const { return m_lower; } - virtual rational get_upper() const { return m_upper; } - virtual bool get_assignment(unsigned index) const { return m_assignment[index]; } - virtual void collect_statistics(statistics& st) const { } - virtual void get_model(model_ref& mdl, svector& labels) { mdl = m_model.get(); labels = m_labels;} + ~maxsmt_solver_base() override {} + rational get_lower() const override { return m_lower; } + rational get_upper() const override { return m_upper; } + bool get_assignment(unsigned index) const override { return m_assignment[index]; } + void collect_statistics(statistics& st) const override { } + void get_model(model_ref& mdl, svector& labels) override { mdl = m_model.get(); labels = m_labels;} virtual void commit_assignment(); void set_model() { s().get_model(m_model); s().get_labels(m_labels); } - virtual void updt_params(params_ref& p); + void updt_params(params_ref& p) override; solver& s(); bool init(); void set_mus(bool f); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 372c6672c..c9e5ce3de 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -173,7 +173,7 @@ namespace opt { std::string m_unknown; public: context(ast_manager& m); - virtual ~context(); + ~context() override; unsigned add_soft_constraint(expr* f, rational const& w, symbol const& id); unsigned add_objective(app* t, bool is_max); void add_hard_constraint(expr* f); @@ -181,30 +181,30 @@ namespace opt { void get_hard_constraints(expr_ref_vector& hard); expr_ref get_objective(unsigned i); - virtual void push(); - virtual void pop(unsigned n); - virtual bool empty() { return m_scoped_state.m_objectives.empty(); } - virtual void set_hard_constraints(ptr_vector & hard); - virtual lbool optimize(); - virtual void set_model(model_ref& _m) { m_model = _m; } - virtual void get_model(model_ref& _m); - virtual void get_box_model(model_ref& _m, unsigned index); - virtual void fix_model(model_ref& _m); - virtual void collect_statistics(statistics& stats) const; - virtual proof* get_proof() { return 0; } - virtual void get_labels(svector & r); - virtual void get_unsat_core(ptr_vector & r); - virtual std::string reason_unknown() const; - virtual void set_reason_unknown(char const* msg) { m_unknown = msg; } + void push() override; + void pop(unsigned n) override; + bool empty() override { return m_scoped_state.m_objectives.empty(); } + void set_hard_constraints(ptr_vector & hard) override; + lbool optimize() override; + void set_model(model_ref& _m) override { m_model = _m; } + void get_model(model_ref& _m) override; + void get_box_model(model_ref& _m, unsigned index) override; + void fix_model(model_ref& _m) override; + void collect_statistics(statistics& stats) const override; + proof* get_proof() override { return 0; } + void get_labels(svector & r) override; + void get_unsat_core(ptr_vector & r) override; + std::string reason_unknown() const override; + void set_reason_unknown(char const* msg) override { m_unknown = msg; } - virtual void display_assignment(std::ostream& out); - virtual bool is_pareto() { return m_pareto.get() != 0; } - virtual void set_logic(symbol const& s) { m_logic = s; } + void display_assignment(std::ostream& out) override; + bool is_pareto() override { return m_pareto.get() != 0; } + void set_logic(symbol const& s) override { m_logic = s; } void set_clausal(bool f) { m_is_clausal = f; } void display(std::ostream& out); static void collect_param_descrs(param_descrs & r); - virtual void updt_params(params_ref const& p); + void updt_params(params_ref const& p) override; params_ref& get_params() { return m_params; } expr_ref get_lower(unsigned idx); @@ -216,25 +216,25 @@ namespace opt { std::string to_string() const; - virtual unsigned num_objectives() { return m_scoped_state.m_objectives.size(); } - virtual expr_ref mk_gt(unsigned i, model_ref& model); - virtual expr_ref mk_ge(unsigned i, model_ref& model); - virtual expr_ref mk_le(unsigned i, model_ref& model); + unsigned num_objectives() override { return m_scoped_state.m_objectives.size(); } + expr_ref mk_gt(unsigned i, model_ref& model) override; + expr_ref mk_ge(unsigned i, model_ref& model) override; + expr_ref mk_le(unsigned i, model_ref& model) override; - virtual smt::context& smt_context() { return m_opt_solver->get_context(); } - virtual filter_model_converter& fm() { return m_fm; } - virtual bool sat_enabled() const { return 0 != m_sat_solver.get(); } - virtual solver& get_solver(); - virtual ast_manager& get_manager() const { return this->m; } - virtual params_ref& params() { return m_params; } - virtual void enable_sls(bool force); - virtual symbol const& maxsat_engine() const { return m_maxsat_engine; } - virtual void get_base_model(model_ref& _m); + smt::context& smt_context() override { return m_opt_solver->get_context(); } + filter_model_converter& fm() override { return m_fm; } + bool sat_enabled() const override { return 0 != m_sat_solver.get(); } + solver& get_solver() override; + ast_manager& get_manager() const override { return this->m; } + params_ref& params() override { return m_params; } + void enable_sls(bool force) override; + symbol const& maxsat_engine() const override { return m_maxsat_engine; } + void get_base_model(model_ref& _m) override; - virtual bool verify_model(unsigned id, model* mdl, rational const& v); + bool verify_model(unsigned id, model* mdl, rational const& v) override; - virtual void model_updated(model* mdl); + void model_updated(model* mdl) override; private: lbool execute(objective const& obj, bool committed, bool scoped); diff --git a/src/opt/opt_pareto.h b/src/opt/opt_pareto.h index c0ccc93da..5a2aab6f3 100644 --- a/src/opt/opt_pareto.h +++ b/src/opt/opt_pareto.h @@ -87,9 +87,9 @@ namespace opt { params_ref & p): pareto_base(m, cb, s, p) { } - virtual ~gia_pareto() {} + ~gia_pareto() override {} - virtual lbool operator()(); + lbool operator()() override; }; // opportunistic improvement algorithm. @@ -101,9 +101,9 @@ namespace opt { params_ref & p): pareto_base(m, cb, s, p) { } - virtual ~oia_pareto() {} + ~oia_pareto() override {} - virtual lbool operator()(); + lbool operator()() override; }; } diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 4bd23c120..41e9dee2d 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -85,28 +85,28 @@ namespace opt { bool m_was_unknown; public: opt_solver(ast_manager & m, params_ref const & p, filter_model_converter& fm); - virtual ~opt_solver(); + ~opt_solver() override; - virtual solver* translate(ast_manager& m, params_ref const& p); - virtual void updt_params(params_ref const& p); - virtual void collect_param_descrs(param_descrs & r); - virtual void collect_statistics(statistics & st) const; - virtual void assert_expr(expr * t); - virtual void push_core(); - virtual void pop_core(unsigned n); - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions); - virtual void get_unsat_core(ptr_vector & r); - virtual void get_model(model_ref & _m); - virtual proof * get_proof(); - virtual std::string reason_unknown() const; - virtual void set_reason_unknown(char const* msg); - virtual void get_labels(svector & r); - virtual void set_progress_callback(progress_callback * callback); - virtual unsigned get_num_assertions() const; - virtual expr * get_assertion(unsigned idx) const; - virtual ast_manager& get_manager() const { return m; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); - virtual lbool preferred_sat(expr_ref_vector const& asms, vector& cores); + solver* translate(ast_manager& m, params_ref const& p) override; + void updt_params(params_ref const& p) override; + void collect_param_descrs(param_descrs & r) override; + void collect_statistics(statistics & st) const override; + void assert_expr(expr * t) override; + void push_core() override; + void pop_core(unsigned n) override; + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override; + void get_unsat_core(ptr_vector & r) override; + void get_model(model_ref & _m) override; + proof * get_proof() override; + std::string reason_unknown() const override; + void set_reason_unknown(char const* msg) override; + void get_labels(svector & r) override; + void set_progress_callback(progress_callback * callback) override; + unsigned get_num_assertions() const override; + expr * get_assertion(unsigned idx) const override; + ast_manager& get_manager() const override { return m; } + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; + lbool preferred_sat(expr_ref_vector const& asms, vector& cores) override; void set_logic(symbol const& logic); smt::theory_var add_objective(app* term); diff --git a/src/parsers/util/cost_parser.h b/src/parsers/util/cost_parser.h index f0330d824..d2a96dc25 100644 --- a/src/parsers/util/cost_parser.h +++ b/src/parsers/util/cost_parser.h @@ -27,9 +27,9 @@ class cost_parser : public simple_parser { var_ref_vector m_vars; public: cost_parser(ast_manager & m); - virtual ~cost_parser() {} - virtual expr * parse_int(rational const & r); - virtual expr * parse_float(rational const & r); + ~cost_parser() override {} + expr * parse_int(rational const & r) override; + expr * parse_float(rational const & r) override; unsigned add_var(symbol name); unsigned add_var(char const * name) { return add_var(symbol(name)); } void reset_vars(); diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index 4f07b59dd..7d86860b3 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -1018,13 +1018,13 @@ namespace nlarith { app* m_x; public: basic_subst(imp& i, app* x) : isubst(i), m_x(x) {} - virtual void mk_lt(poly const& p, app_ref& r) { + void mk_lt(poly const& p, app_ref& r) override { imp& I = m_imp; app_ref result(I.m()); I.mk_polynomial(m_x, p, result); r = I.mk_lt(result); } - virtual void mk_eq(poly const& p, app_ref& r) { + void mk_eq(poly const& p, app_ref& r) override { imp& I = m_imp; app_ref result(I.m()); I.mk_polynomial(m_x, p, result); @@ -1039,7 +1039,7 @@ namespace nlarith { // p[e/x] < 0: (a*parity(d) < 0 /\ 0 < a*a - b*b*c) \/ // (b*parity(d) <= 0 /\ (a*parity(d) < 0 \/ a*a - b*b*c < 0)) - virtual void mk_lt(poly const& p, app_ref& r) { + void mk_lt(poly const& p, app_ref& r) override { imp& I = m_imp; ast_manager& m = I.m(); app_ref a(m), b(m), c(m_s.m_c), d(m); @@ -1061,7 +1061,7 @@ namespace nlarith { // p[e/x] = 0: a*b <= 0 & a*a - b*b*c = 0 - virtual void mk_eq(poly const& p, app_ref& r) { + void mk_eq(poly const& p, app_ref& r) override { imp& I = m_imp; ast_manager& m = I.m(); app_ref a(m), b(m), c(m_s.m_c),d(m), aabbc(m); @@ -1076,7 +1076,7 @@ namespace nlarith { } // p[e/x] <= 0: a*parity(d) <= 0 /\ 0 <= a*a - b*b*c \/ b*parity(d) <= 0 /\ a*a - b*b*c <= 0 - virtual void mk_le(poly const& p, app_ref& r) { + void mk_le(poly const& p, app_ref& r) override { imp& I = m_imp; ast_manager& m = I.m(); app_ref a(m), b(m), c(m_s.m_c), d(m); @@ -1125,10 +1125,10 @@ namespace nlarith { public: plus_eps_subst(imp& i, isubst& s) : isubst(i), m_s(s) {} - virtual void mk_lt(poly const& p, app_ref& r) { mk_nu(p, r); } + void mk_lt(poly const& p, app_ref& r) override { mk_nu(p, r); } // /\ p[i] = 0 - virtual void mk_eq(poly const& p, app_ref& r) { r = m_imp.mk_zero(p); } + void mk_eq(poly const& p, app_ref& r) override { r = m_imp.mk_zero(p); } }; class minus_eps_subst : public isubst { @@ -1172,10 +1172,10 @@ namespace nlarith { public: minus_eps_subst(imp& i, isubst& s) : isubst(i), m_s(s) {} - virtual void mk_lt(poly const& p, app_ref& r) { mk_nu(p, true, r); } + void mk_lt(poly const& p, app_ref& r) override { mk_nu(p, true, r); } // /\ p[i] = 0 - virtual void mk_eq(poly const& p, app_ref& r) { r = m_imp.mk_zero(p); } + void mk_eq(poly const& p, app_ref& r) override { r = m_imp.mk_zero(p); } }; class minus_inf_subst : public isubst { @@ -1208,12 +1208,12 @@ namespace nlarith { public: minus_inf_subst(imp& i) : isubst(i) {} - virtual void mk_lt(poly const& p, app_ref& r) { + void mk_lt(poly const& p, app_ref& r) override { r = mk_lt(p, p.size()); } // /\ p[i] = 0 - virtual void mk_eq(poly const& p, app_ref& r) { r = m_imp.mk_zero(p); } + void mk_eq(poly const& p, app_ref& r) override { r = m_imp.mk_zero(p); } }; @@ -1238,10 +1238,10 @@ namespace nlarith { public: plus_inf_subst(imp& i) : isubst(i) {} - virtual void mk_lt(poly const& p, app_ref& r) { r = mk_lt(p, p.size()); } + void mk_lt(poly const& p, app_ref& r) override { r = mk_lt(p, p.size()); } // /\ p[i] = 0 - virtual void mk_eq(poly const& p, app_ref& r) { r = m_imp.mk_zero(p); } + void mk_eq(poly const& p, app_ref& r) override { r = m_imp.mk_zero(p); } }; /** @@ -1615,9 +1615,9 @@ namespace nlarith { public: simple_branch(ast_manager& m, app* cnstr): m_cnstr(cnstr, m), m_atoms(m) {} - virtual ~simple_branch() {} - virtual app* get_constraint() { return m_cnstr.get(); } - virtual void get_updates(ptr_vector& atoms, svector& updates) { + ~simple_branch() override {} + app* get_constraint() override { return m_cnstr.get(); } + void get_updates(ptr_vector& atoms, svector& updates) override { for (unsigned i = 0; i < m_atoms.size(); ++i) { atoms.push_back(m_atoms[i].get()); updates.push_back(m_updates[i]); @@ -1635,7 +1635,7 @@ namespace nlarith { public: ins_rem_branch(ast_manager& m, app* a, app* r, app* cnstr): simple_branch(m, cnstr) { insert(a); remove(r); } - virtual ~ins_rem_branch() {} + ~ins_rem_branch() override {} }; /** diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index e28f6ae4f..0898afeda 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -555,7 +555,7 @@ namespace qe { } - void reset() { + void reset() override { //m_solver.reset(); m_asms.reset(); m_cached_asms.reset(); @@ -798,16 +798,16 @@ namespace qe { m_nftactic = mk_tseitin_cnf_tactic(m); } - virtual ~nlqsat() { + ~nlqsat() override { } - void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { params_ref p2(p); p2.set_bool("factor", false); m_solver.updt_params(p2); } - void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } @@ -815,7 +815,7 @@ namespace qe { /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, /* out */ proof_converter_ref & pc, - /* out */ expr_dependency_ref & core) { + /* out */ expr_dependency_ref & core) override { tactic_report report("nlqsat-tactic", *in); @@ -863,27 +863,27 @@ namespace qe { } - void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.copy(m_st); st.update("qsat num rounds", m_stats.m_num_rounds); } - void reset_statistics() { + void reset_statistics() override { m_stats.reset(); m_solver.reset_statistics(); } - void cleanup() { + void cleanup() override { reset(); } - void set_logic(symbol const & l) { + void set_logic(symbol const & l) override { } - void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { } - tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(nlqsat, m, m_mode, m_params); } }; diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 57a8c365b..08a0c44c0 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -1383,7 +1383,7 @@ namespace qe { m_rewriter.updt_params(params); } - virtual ~quant_elim_plugin() { + ~quant_elim_plugin() override { reset(); } @@ -2035,7 +2035,7 @@ namespace qe { { } - virtual ~quant_elim_new() { + ~quant_elim_new() override { reset(); } @@ -2052,17 +2052,17 @@ namespace qe { } - void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { for (unsigned i = 0; i < m_plugins.size(); ++i) { m_plugins[i]->collect_statistics(st); } } - void updt_params(params_ref const& p) { + void updt_params(params_ref const& p) override { m_eliminate_variables_as_block = p.get_bool("eliminate_variables_as_block", m_eliminate_variables_as_block); } - void eliminate(bool is_forall, unsigned num_vars, app* const* vars, expr_ref& fml) { + void eliminate(bool is_forall, unsigned num_vars, app* const* vars, expr_ref& fml) override { if (is_forall) { eliminate_forall_bind(num_vars, vars, fml); } @@ -2092,14 +2092,14 @@ namespace qe { } } - virtual void set_assumption(expr* fml) { + void set_assumption(expr* fml) override { m_assumption = fml; } - virtual lbool eliminate_exists( + lbool eliminate_exists( unsigned num_vars, app* const* vars, expr_ref& fml, - app_ref_vector& free_vars, bool get_first, guarded_defs* defs) { + app_ref_vector& free_vars, bool get_first, guarded_defs* defs) override { if (get_first) { return eliminate_block(num_vars, vars, fml, free_vars, get_first, defs); } @@ -2483,7 +2483,7 @@ namespace qe { m_fparams.updt_params(p); } - virtual ~simplify_solver_context() { reset(); } + ~simplify_solver_context() override { reset(); } void solve(expr_ref& fml, app_ref_vector& vars) { @@ -2502,16 +2502,16 @@ namespace qe { while (solved); } - virtual ast_manager& get_manager() { return m; } + ast_manager& get_manager() override { return m; } - virtual atom_set const& pos_atoms() const { return m_pos; } - virtual atom_set const& neg_atoms() const { return m_neg; } + atom_set const& pos_atoms() const override { return m_pos; } + atom_set const& neg_atoms() const override { return m_neg; } // Access current set of variables to solve - virtual unsigned get_num_vars() const { return m_vars->size(); } - virtual app* get_var(unsigned idx) const { return (*m_vars)[idx].get(); } - virtual app_ref_vector const& get_vars() const { return *m_vars; } - virtual bool is_var(expr* e, unsigned& idx) const { + unsigned get_num_vars() const override { return m_vars->size(); } + app* get_var(unsigned idx) const override { return (*m_vars)[idx].get(); } + app_ref_vector const& get_vars() const override { return *m_vars; } + bool is_var(expr* e, unsigned& idx) const override { for (unsigned i = 0; i < m_vars->size(); ++i) { if ((*m_vars)[i].get() == e) { idx = i; @@ -2521,12 +2521,12 @@ namespace qe { return false; } - virtual contains_app& contains(unsigned idx) { + contains_app& contains(unsigned idx) override { return *m_contains[idx]; } // callback to replace variable at index 'idx' with definition 'def' and updated formula 'fml' - virtual void elim_var(unsigned idx, expr* fml, expr* def) { + void elim_var(unsigned idx, expr* fml, expr* def) override { TRACE("qe", tout << mk_pp(m_vars->get(idx), m) << " " << mk_pp(fml, m) << "\n";); *m_fml = fml; m_vars->set(idx, m_vars->get(m_vars->size()-1)); @@ -2537,17 +2537,17 @@ namespace qe { } // callback to add new variable to branch. - virtual void add_var(app* x) { + void add_var(app* x) override { TRACE("qe", tout << "add var: " << mk_pp(x, m) << "\n";); m_vars->push_back(x); } // callback to add constraints in branch. - virtual void add_constraint(bool use_var, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) { + void add_constraint(bool use_var, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) override { UNREACHABLE(); } // eliminate finite domain variable 'var' from fml. - virtual void blast_or(app* var, expr_ref& fml) { + void blast_or(app* var, expr_ref& fml) override { UNREACHABLE(); } diff --git a/src/qe/qe.h b/src/qe/qe.h index 6946f9566..bdce4d159 100644 --- a/src/qe/qe.h +++ b/src/qe/qe.h @@ -49,13 +49,13 @@ namespace qe { i_solver_context& m_s; public: is_relevant(i_solver_context& s):m_s(s) {} - virtual bool operator()(expr* e); + bool operator()(expr* e) override; }; class mk_atom_fn : public i_nnf_atom { i_solver_context& m_s; public: mk_atom_fn(i_solver_context& s) : m_s(s) {} - void operator()(expr* e, bool p, expr_ref& result); + void operator()(expr* e, bool p, expr_ref& result) override; }; is_relevant m_is_relevant; diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index 88675d5a4..8e2400ac7 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -25,11 +25,11 @@ namespace qe { imp* m_imp; public: arith_project_plugin(ast_manager& m); - virtual ~arith_project_plugin(); - virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits); - virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); - virtual family_id get_family_id(); - virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits); + ~arith_project_plugin() override; + bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) override; + bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; + family_id get_family_id() override; + void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt); diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 89dee9586..9e056cdc2 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -1536,14 +1536,14 @@ public: m_trail(m) {} - ~arith_plugin() { + ~arith_plugin() override { bounds_cache::iterator it = m_bounds_cache.begin(), end = m_bounds_cache.end(); for (; it != end; ++it) { dealloc(it->get_value()); } } - virtual void assign(contains_app& contains_x, expr* fml, rational const& vl) { + void assign(contains_app& contains_x, expr* fml, rational const& vl) override { SASSERT(vl.is_unsigned()); app* x = contains_x.x(); unsigned v = vl.get_unsigned(); @@ -1633,7 +1633,7 @@ public: } - virtual bool get_num_branches(contains_app& contains_x, expr* fml, rational& nb) { + bool get_num_branches(contains_app& contains_x, expr* fml, rational& nb) override { app* x = contains_x.x(); if (!update_bounds(contains_x, fml)) { return false; @@ -1645,7 +1645,7 @@ public: return true; } - virtual void subst(contains_app& contains_x, rational const& vl, expr_ref& fml, expr_ref* def) { + void subst(contains_app& contains_x, rational const& vl, expr_ref& fml, expr_ref* def) override { SASSERT(vl.is_unsigned()); if (def) { get_def(contains_x, vl.get_unsigned(), fml, *def); @@ -1654,7 +1654,7 @@ public: TRACE("qe", tout << mk_pp(contains_x.x(), m) << " " << vl << "\n" << mk_pp(fml, m) << "\n";); } - virtual bool project(contains_app& x, model_ref& model, expr_ref& fml) { + bool project(contains_app& x, model_ref& model, expr_ref& fml) override { if (!update_bounds(x, fml)) { TRACE("qe", tout << mk_pp(x.x(), m) << " failed to update bounds\n";); return false; @@ -1668,19 +1668,19 @@ public: } - virtual unsigned get_weight(contains_app& contains_x, expr* fml) { + unsigned get_weight(contains_app& contains_x, expr* fml) override { return 2; } - virtual bool solve(conj_enum& conjs, expr* fml) { + bool solve(conj_enum& conjs, expr* fml) override { return m_util.solve(conjs, fml); } - virtual bool mk_atom(expr* e, bool p, expr_ref& result) { + bool mk_atom(expr* e, bool p, expr_ref& result) override { return m_util.mk_atom(e, p, result); } - virtual bool is_uninterpreted(app* f) { + bool is_uninterpreted(app* f) override { switch(f->get_decl_kind()) { case OP_NUM: case OP_LE: @@ -2456,7 +2456,7 @@ public: m_util.set_enable_linear(true); // (produce_models); } - virtual ~nlarith_plugin() { + ~nlarith_plugin() override { bcs_t::iterator it = m_cache.begin(), end = m_cache.end(); for (; it != end; ++it) { dealloc(it->get_value()); @@ -2467,7 +2467,7 @@ public: } } - virtual bool simplify(expr_ref& fml) { + bool simplify(expr_ref& fml) override { expr_ref tmp(m), tmp2(m); m_factor_rw(fml, tmp); m_rewriter(tmp, tmp2); @@ -2478,7 +2478,7 @@ public: return false; } - virtual void assign(contains_app& x, expr* fml, rational const& vl) { + void assign(contains_app& x, expr* fml, rational const& vl) override { nlarith::branch_conditions *brs = 0; VERIFY (m_cache.find(x.x(), fml, brs)); SASSERT(vl.is_unsigned()); @@ -2491,8 +2491,8 @@ public: m_ctx.add_constraint(true, result); } - virtual bool get_num_branches(contains_app& x, - expr* fml, rational& num_branches) { + bool get_num_branches(contains_app& x, + expr* fml, rational& num_branches) override { nlarith::branch_conditions *brs; if (m_cache.find(x.x(), fml, brs)) { num_branches = rational(brs->size()); @@ -2515,7 +2515,7 @@ public: return true; } - virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) { + void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override { nlarith::branch_conditions *brs = 0; VERIFY (m_cache.find(x.x(), fml, brs)); SASSERT(vl.is_unsigned()); @@ -2534,7 +2534,7 @@ public: } - virtual unsigned get_weight(contains_app& x, expr* fml) { + unsigned get_weight(contains_app& x, expr* fml) override { obj_map* weights = 0; unsigned weight = 0; if (!m_weights.find(fml, weights)) { @@ -2553,12 +2553,12 @@ public: return UINT_MAX; } - virtual bool solve(conj_enum& conjs, expr* fml) { return false; } + bool solve(conj_enum& conjs, expr* fml) override { return false; } // we don't need to modify the atom. - virtual bool mk_atom(expr* e, bool p, expr_ref& result) { return false; } + bool mk_atom(expr* e, bool p, expr_ref& result) override { return false; } - virtual bool is_uninterpreted(app* f) { + bool is_uninterpreted(app* f) override { if (m_produce_models) { return true; } diff --git a/src/qe/qe_array_plugin.cpp b/src/qe/qe_array_plugin.cpp index 9eeccd6a4..775dd0443 100644 --- a/src/qe/qe_array_plugin.cpp +++ b/src/qe/qe_array_plugin.cpp @@ -27,23 +27,23 @@ namespace qe { { } - virtual ~array_plugin() {} + ~array_plugin() override {} - virtual void assign(contains_app& x, expr* fml, rational const& vl) { + void assign(contains_app& x, expr* fml, rational const& vl) override { UNREACHABLE(); } - virtual bool get_num_branches( contains_app& x, expr* fml, rational& num_branches) { + bool get_num_branches( contains_app& x, expr* fml, rational& num_branches) override { return false; } - virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) { + void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override { UNREACHABLE(); } - virtual bool solve(conj_enum& conjs, expr* fml) { + bool solve(conj_enum& conjs, expr* fml) override { conj_enum::iterator it = conjs.begin(), end = conjs.end(); for (; it != end; ++it) { @@ -65,7 +65,7 @@ namespace qe { return false; } - virtual bool is_uninterpreted(app* f) { + bool is_uninterpreted(app* f) override { return true; } diff --git a/src/qe/qe_arrays.h b/src/qe/qe_arrays.h index e100ebce4..a955250a8 100644 --- a/src/qe/qe_arrays.h +++ b/src/qe/qe_arrays.h @@ -31,10 +31,10 @@ namespace qe { imp* m_imp; public: array_project_plugin(ast_manager& m); - virtual ~array_project_plugin(); - virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits); - virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); - virtual family_id get_family_id(); + ~array_project_plugin() override; + bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) override; + bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; + family_id get_family_id() override; }; }; diff --git a/src/qe/qe_bool_plugin.cpp b/src/qe/qe_bool_plugin.cpp index 82e09bbed..eb0553a0e 100644 --- a/src/qe/qe_bool_plugin.cpp +++ b/src/qe/qe_bool_plugin.cpp @@ -39,16 +39,16 @@ namespace qe { m_replace(m) {} - virtual void assign(contains_app& x, expr* fml, rational const& vl) { + void assign(contains_app& x, expr* fml, rational const& vl) override { SASSERT(vl.is_zero() || vl.is_one()); } - virtual bool get_num_branches(contains_app& x, expr* fml, rational& nb) { + bool get_num_branches(contains_app& x, expr* fml, rational& nb) override { nb = rational(2); return true; } - virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) { + void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override { SASSERT(vl.is_one() || vl.is_zero()); expr* tf = (vl.is_one())?m.mk_true():m.mk_false(); m_replace.apply_substitution(x.x(), tf, fml); @@ -57,7 +57,7 @@ namespace qe { } } - virtual bool project(contains_app& x, model_ref& model, expr_ref& fml) { + bool project(contains_app& x, model_ref& model, expr_ref& fml) override { model_evaluator model_eval(*model); expr_ref val_x(m); rational val; @@ -69,7 +69,7 @@ namespace qe { return true; } - virtual unsigned get_weight(contains_app& contains_x, expr* fml) { + unsigned get_weight(contains_app& contains_x, expr* fml) override { app* x = contains_x.x(); bool p = m_ctx.pos_atoms().contains(x); bool n = m_ctx.neg_atoms().contains(x); @@ -79,13 +79,13 @@ namespace qe { return 0; } - virtual bool solve(conj_enum& conjs,expr* fml) { + bool solve(conj_enum& conjs,expr* fml) override { return solve_units(conjs, fml) || solve_polarized(fml); } - virtual bool is_uninterpreted(app* a) { + bool is_uninterpreted(app* a) override { return false; } diff --git a/src/qe/qe_bv_plugin.cpp b/src/qe/qe_bv_plugin.cpp index 6678d6fcf..ef87f235f 100644 --- a/src/qe/qe_bv_plugin.cpp +++ b/src/qe/qe_bv_plugin.cpp @@ -37,16 +37,16 @@ namespace qe { m_bv(m) {} - virtual void assign(contains_app& x, expr* fml, rational const& vl) { + void assign(contains_app& x, expr* fml, rational const& vl) override { } - virtual bool get_num_branches(contains_app& x, expr* fml, rational& nb) { + bool get_num_branches(contains_app& x, expr* fml, rational& nb) override { unsigned sz = m_bv.get_bv_size(x.x()); nb = power(rational(2), sz); return true; } - virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) { + void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override { app_ref c(m_bv.mk_numeral(vl, m_bv.get_bv_size(x.x())), m); m_replace.apply_substitution(x.x(), c, fml); if (def) { @@ -54,7 +54,7 @@ namespace qe { } } - virtual bool project(contains_app& x, model_ref& model, expr_ref& fml) { + bool project(contains_app& x, model_ref& model, expr_ref& fml) override { model_evaluator model_eval(*model); expr_ref val_x(m); rational val(0); @@ -65,13 +65,13 @@ namespace qe { return true; } - virtual unsigned get_weight(contains_app& contains_x, expr* fml) { + unsigned get_weight(contains_app& contains_x, expr* fml) override { return 2; } - bool solve(conj_enum& conjs, expr* fml) { return false; } + bool solve(conj_enum& conjs, expr* fml) override { return false; } - virtual bool is_uninterpreted(app* f) { + bool is_uninterpreted(app* f) override { switch(f->get_decl_kind()) { case OP_BSDIV0: case OP_BUDIV0: diff --git a/src/qe/qe_cmd.cpp b/src/qe/qe_cmd.cpp index 3c55c0f49..eb119ce0b 100644 --- a/src/qe/qe_cmd.cpp +++ b/src/qe/qe_cmd.cpp @@ -14,36 +14,36 @@ class qe_cmd : public parametric_cmd { public: qe_cmd(char const* name = "elim-quantifiers"):parametric_cmd(name) {} - virtual char const * get_usage() const { return " ( )*"; } + char const * get_usage() const override { return " ( )*"; } - virtual char const * get_main_descr() const { + char const * get_main_descr() const override { return "apply quantifier elimination to the supplied expression"; } - virtual void init_pdescrs(cmd_context & ctx, param_descrs & p) { + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { insert_timeout(p); p.insert("print", CPK_BOOL, "(default: true) print the simplified term."); p.insert("print_statistics", CPK_BOOL, "(default: false) print statistics."); } - virtual ~qe_cmd() { + ~qe_cmd() override { } - virtual void prepare(cmd_context & ctx) { + void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); m_target = 0; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_target == 0) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } - virtual void set_next_arg(cmd_context & ctx, expr * arg) { + void set_next_arg(cmd_context & ctx, expr * arg) override { m_target = arg; } - virtual void execute(cmd_context & ctx) { + void execute(cmd_context & ctx) override { proof_ref pr(ctx.m()); qe::simplify_rewriter_star qe(ctx.m()); expr_ref result(ctx.m()); diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index c3525aa33..0bfe82751 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -435,7 +435,7 @@ namespace qe { { } - virtual ~datatype_plugin() { + ~datatype_plugin() override { { eqs_cache::iterator it = m_eqs_cache.begin(), end = m_eqs_cache.end(); for (; it != end; ++it) { @@ -451,7 +451,7 @@ namespace qe { } - virtual bool get_num_branches( contains_app& x, expr* fml, rational& num_branches) { + bool get_num_branches( contains_app& x, expr* fml, rational& num_branches) override { sort* s = x.x()->get_decl()->get_range(); SASSERT(m_datatype_util.is_datatype(s)); if (m_datatype_util.is_recursive(s)) { @@ -463,7 +463,7 @@ namespace qe { } - virtual void assign(contains_app& x, expr* fml, rational const& vl) { + void assign(contains_app& x, expr* fml, rational const& vl) override { sort* s = x.x()->get_decl()->get_range(); SASSERT(m_datatype_util.is_datatype(s)); TRACE("qe", tout << mk_pp(x.x(), m) << " " << vl << "\n";); @@ -475,7 +475,7 @@ namespace qe { } } - virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) { + void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override { sort* s = x.x()->get_decl()->get_range(); SASSERT(m_datatype_util.is_datatype(s)); TRACE("qe", tout << mk_pp(x.x(), m) << " " << vl << "\n";); @@ -487,20 +487,20 @@ namespace qe { } } - virtual unsigned get_weight( contains_app& x, expr* fml) { + unsigned get_weight( contains_app& x, expr* fml) override { return UINT_MAX; } - virtual bool solve( conj_enum& conj, expr* fml) { + bool solve( conj_enum& conj, expr* fml) override { return false; } - virtual bool simplify( expr_ref& fml) { + bool simplify( expr_ref& fml) override { lift_foreign_vars lift(m, m_datatype_util, m_ctx); return lift.lift(fml); } - virtual bool mk_atom(expr* e, bool p, expr_ref& result) { + bool mk_atom(expr* e, bool p, expr_ref& result) override { return false; } @@ -807,7 +807,7 @@ namespace qe { public: has_select(app* x, func_decl* c, datatype_util& u): m_x(x), m_c(c), m_util(u) {} - virtual bool operator()(expr* e) { + bool operator()(expr* e) override { if (!is_app(e)) return false; app* a = to_app(e); if (!m_util.is_accessor(a)) return false; diff --git a/src/qe/qe_datatypes.h b/src/qe/qe_datatypes.h index 7352b4ca7..9c8eb5a76 100644 --- a/src/qe/qe_datatypes.h +++ b/src/qe/qe_datatypes.h @@ -31,10 +31,10 @@ namespace qe { imp* m_imp; public: datatype_project_plugin(ast_manager& m); - virtual ~datatype_project_plugin(); - virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits); - virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); - virtual family_id get_family_id(); + ~datatype_project_plugin() override; + bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) override; + bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; + family_id get_family_id() override; }; }; diff --git a/src/qe/qe_dl_plugin.cpp b/src/qe/qe_dl_plugin.cpp index 7ff7bc11e..714540e41 100644 --- a/src/qe/qe_dl_plugin.cpp +++ b/src/qe/qe_dl_plugin.cpp @@ -56,7 +56,7 @@ namespace qe { { } - virtual ~dl_plugin() { + ~dl_plugin() override { eqs_cache::iterator it = m_eqs_cache.begin(), end = m_eqs_cache.end(); for (; it != end; ++it) { dealloc(it->get_value()); @@ -65,7 +65,7 @@ namespace qe { - bool get_num_branches(contains_app & x,expr * fml,rational & num_branches) { + bool get_num_branches(contains_app & x,expr * fml,rational & num_branches) override { if (!update_eqs(x, fml)) { return false; } @@ -80,7 +80,7 @@ namespace qe { return true; } - void assign(contains_app & x,expr * fml,const rational & v) { + void assign(contains_app & x,expr * fml,const rational & v) override { SASSERT(v.is_unsigned()); eq_atoms& eqs = get_eqs(x.x(), fml); unsigned uv = v.get_unsigned(); @@ -94,7 +94,7 @@ namespace qe { } } - void subst(contains_app & x,const rational & v,expr_ref & fml, expr_ref* def) { + void subst(contains_app & x,const rational & v,expr_ref & fml, expr_ref* def) override { SASSERT(v.is_unsigned()); eq_atoms& eqs = get_eqs(x.x(), fml); unsigned uv = v.get_unsigned(); @@ -111,7 +111,7 @@ namespace qe { } } - virtual bool solve(conj_enum& conjs, expr* fml) { return false; } + bool solve(conj_enum& conjs, expr* fml) override { return false; } private: diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 1220bd571..678c5e29b 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -2607,43 +2607,43 @@ public: m_imp = alloc(imp, m, p); } - virtual ~qe_lite_tactic() { + ~qe_lite_tactic() override { dealloc(m_imp); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(qe_lite_tactic, m, m_params); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; // m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { // m_imp->collect_param_descrs(r); } - virtual void operator()(goal_ref const & in, + void operator()(goal_ref const & in, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { // m_imp->collect_statistics(st); } - virtual void reset_statistics() { + void reset_statistics() override { // m_imp->reset_statistics(); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; dealloc(m_imp); m_imp = alloc(imp, m, m_params); diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 250ffff4a..547f6bad1 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -39,14 +39,14 @@ namespace qe { class is_relevant_default : public i_expr_pred { public: - bool operator()(expr* e) { + bool operator()(expr* e) override { return true; } }; class mk_atom_default : public i_nnf_atom { public: - virtual void operator()(expr* e, bool pol, expr_ref& result) { + void operator()(expr* e, bool pol, expr_ref& result) override { if (pol) result = e; else result = result.get_manager().mk_not(e); } @@ -97,7 +97,7 @@ namespace qe { m_fml(m), m_projection_mode_param(true) {} - virtual ~solver_context() { + ~solver_context() override { std::for_each(m_contains_app.begin(), m_contains_app.end(), delete_proc()); } @@ -111,28 +111,28 @@ namespace qe { void set_projection_mode(bool p) { m_projection_mode_param = p; } - ast_manager& get_manager() { return m; } + ast_manager& get_manager() override { return m; } expr* fml() { return m_fml; } // set of atoms in current formula. - virtual atom_set const& pos_atoms() const { return m_pos; } - virtual atom_set const& neg_atoms() const { return m_neg; } + atom_set const& pos_atoms() const override { return m_pos; } + atom_set const& neg_atoms() const override { return m_neg; } // Access current set of variables to solve - virtual unsigned get_num_vars() const { return m_vars.size(); } - virtual app* get_var(unsigned idx) const { return m_vars[idx]; } - virtual app_ref_vector const& get_vars() const { return m_vars; } - virtual bool is_var(expr* e, unsigned& idx) const { + unsigned get_num_vars() const override { return m_vars.size(); } + app* get_var(unsigned idx) const override { return m_vars[idx]; } + app_ref_vector const& get_vars() const override { return m_vars; } + bool is_var(expr* e, unsigned& idx) const override { for (unsigned i = 0; i < m_vars.size(); ++i) { if (e == m_vars[i]) return (idx = i, true); } return false; } - virtual contains_app& contains(unsigned idx) { return *m_contains_app[idx]; } + contains_app& contains(unsigned idx) override { return *m_contains_app[idx]; } // callback to replace variable at index 'idx' with definition 'def' and updated formula 'fml' - virtual void elim_var(unsigned idx, expr* fml, expr* def) { + void elim_var(unsigned idx, expr* fml, expr* def) override { m_fml = fml; m_pos.reset(); m_neg.reset(); @@ -143,13 +143,13 @@ namespace qe { } // callback to add new variable to branch. - virtual void add_var(app* x) { + void add_var(app* x) override { m_vars.push_back(x); m_contains_app.push_back(alloc(contains_app, m, x)); } // callback to add constraints in branch. - virtual void add_constraint(bool use_var, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) { + void add_constraint(bool use_var, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) override { ptr_buffer args; if (l1) args.push_back(l1); if (l2) args.push_back(l2); @@ -160,7 +160,7 @@ namespace qe { } // eliminate finite domain variable 'var' from fml. - virtual void blast_or(app* var, expr_ref& fml) { + void blast_or(app* var, expr_ref& fml) override { expr_ref result(m); expr_quant_elim qelim(m, m_super.m_fparams); qe::mk_exists(1, &var, fml); @@ -223,20 +223,19 @@ namespace qe { m_fparams.m_model = true; } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(sat_tactic, m); } - virtual ~sat_tactic() { + ~sat_tactic() override { reset(); } - virtual void operator()( - goal_ref const& goal, - goal_ref_buffer& result, - model_converter_ref& mc, - proof_converter_ref & pc, - expr_dependency_ref& core) + void operator()(goal_ref const& goal, + goal_ref_buffer& result, + model_converter_ref& mc, + proof_converter_ref & pc, + expr_dependency_ref& core) override { try { checkpoint(); @@ -269,7 +268,7 @@ namespace qe { } } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { for (unsigned i = 0; i < m_solvers.size(); ++i) { m_solvers[i]->collect_statistics(st); } @@ -277,7 +276,7 @@ namespace qe { m_ctx_rewriter.collect_statistics(st); } - virtual void reset_statistics() { + void reset_statistics() override { for (unsigned i = 0; i < m_solvers.size(); ++i) { m_solvers[i]->reset_statistics(); } @@ -285,9 +284,9 @@ namespace qe { m_ctx_rewriter.reset_statistics(); } - virtual void cleanup() {} + void cleanup() override {} - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_extrapolate_strategy_param = p.get_uint("extrapolate_strategy", m_extrapolate_strategy_param); m_projection_mode_param = p.get_bool("projection_mode", m_projection_mode_param); m_strong_context_simplify_param = p.get_bool("strong_context_simplify", m_strong_context_simplify_param); @@ -296,7 +295,7 @@ namespace qe { m_qe_rw.updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("extrapolate_strategy",CPK_UINT, "(default: 0 trivial extrapolation) 1 - nnf strengthening 2 - smt-test 3 - nnf_weakening"); r.insert("projection_mode", CPK_BOOL, "(default: true - full) false - partial quantifier instantiation"); r.insert("strong_context_simplify", CPK_BOOL, "(default: true) use strong context simplifier on result of quantifier elimination"); @@ -326,7 +325,7 @@ namespace qe { smt::kernel& solver(unsigned i) { return *m_solvers[i]; } - void reset() { + void reset() override { for (unsigned i = 0; i < m_solvers.size(); ++i) { dealloc(m_solvers[i]); } diff --git a/src/qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp index 5d1a74813..5a8c3061c 100644 --- a/src/qe/qe_tactic.cpp +++ b/src/qe/qe_tactic.cpp @@ -102,46 +102,46 @@ public: m_imp = alloc(imp, m, p); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(qe_tactic, m, m_params); } - virtual ~qe_tactic() { + ~qe_tactic() override { dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("qe_nonlinear", CPK_BOOL, "(default: false) enable virtual term substitution."); m_imp->collect_param_descrs(r); } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { (*m_imp)(in, result, mc, pc, core); m_st.reset(); m_imp->collect_statistics(m_st); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.copy(m_st); } - virtual void reset_statistics() { + void reset_statistics() override { m_st.reset(); } - virtual void cleanup() { + void cleanup() override { ast_manager & m = m_imp->m; dealloc(m_imp); m_imp = alloc(imp, m, m_params); diff --git a/src/qe/qe_vartest.h b/src/qe/qe_vartest.h index 047964825..56d9229b8 100644 --- a/src/qe/qe_vartest.h +++ b/src/qe/qe_vartest.h @@ -42,7 +42,7 @@ public: m_num_decls(num_decls), m_var_kind(BY_NUM_DECLS) {} - virtual bool operator()(expr* e) const { + bool operator()(expr* e) const override { if (!is_var(e)) { return false; } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 2419d1c77..6d470c5de 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -696,7 +696,7 @@ namespace qe { m_level -= num_scopes; } - void reset() { + void reset() override { m_st.reset(); m_fa.s().collect_statistics(m_st); m_ex.s().collect_statistics(m_st); @@ -1204,14 +1204,14 @@ namespace qe { reset(); } - virtual ~qsat() { + ~qsat() override { reset(); } - void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { } - void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } @@ -1219,7 +1219,7 @@ namespace qe { /* out */ goal_ref_buffer & result, /* out */ model_converter_ref & mc, /* out */ proof_converter_ref & pc, - /* out */ expr_dependency_ref & core) { + /* out */ expr_dependency_ref & core) override { tactic_report report("qsat-tactic", *in); ptr_vector fmls; expr_ref_vector defs(m); @@ -1291,7 +1291,7 @@ namespace qe { } } - void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.copy(m_st); m_fa.s().collect_statistics(st); m_ex.s().collect_statistics(st); @@ -1300,23 +1300,23 @@ namespace qe { m_pred_abs.collect_statistics(st); } - void reset_statistics() { + void reset_statistics() override { m_stats.reset(); m_fa.reset(); m_ex.reset(); } - void cleanup() { + void cleanup() override { reset(); } - void set_logic(symbol const & l) { + void set_logic(symbol const & l) override { } - void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { } - tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(qsat, m, m_params, m_mode); } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 191c49294..0b0ef24d2 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -83,9 +83,9 @@ public: init_preprocess(); } - virtual ~inc_sat_solver() {} + ~inc_sat_solver() override {} - virtual solver* translate(ast_manager& dst_m, params_ref const& p) { + solver* translate(ast_manager& dst_m, params_ref const& p) override { ast_translation tr(m, dst_m); if (m_num_scopes > 0) { throw default_exception("Cannot translate sat solver at non-base level"); @@ -103,7 +103,7 @@ public: return result; } - virtual void set_progress_callback(progress_callback * callback) {} + void set_progress_callback(progress_callback * callback) override {} void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) { if (weights != 0) { @@ -135,7 +135,7 @@ public: (m.is_not(e, e) && is_uninterp_const(e)); } - virtual lbool check_sat(unsigned sz, expr * const * assumptions) { + lbool check_sat(unsigned sz, expr * const * assumptions) override { m_solver.pop_to_base_level(); expr_ref_vector _assumptions(m); obj_map asm2fml; @@ -185,7 +185,7 @@ public: } return r; } - virtual void push() { + void push() override { internalize_formulas(); m_solver.user_push(); ++m_num_scopes; @@ -195,7 +195,7 @@ public: if (m_bb_rewriter) m_bb_rewriter->push(); m_map.push(); } - virtual void pop(unsigned n) { + void pop(unsigned n) override { if (n > m_num_scopes) { // allow inc_sat_solver to n = m_num_scopes; // take over for another solver. } @@ -214,10 +214,10 @@ public: --n; } } - virtual unsigned get_scope_level() const { + unsigned get_scope_level() const override { return m_num_scopes; } - virtual void assert_expr(expr * t, expr * a) { + void assert_expr(expr * t, expr * a) override { if (a) { m_asmsf.push_back(a); assert_expr(m.mk_implies(a, t)); @@ -226,42 +226,42 @@ public: assert_expr(t); } } - virtual ast_manager& get_manager() const { return m; } - virtual void assert_expr(expr * t) { + ast_manager& get_manager() const override { return m; } + void assert_expr(expr * t) override { TRACE("sat", tout << mk_pp(t, m) << "\n";); m_fmls.push_back(t); } - virtual void set_produce_models(bool f) {} - virtual void collect_param_descrs(param_descrs & r) { + void set_produce_models(bool f) override {} + void collect_param_descrs(param_descrs & r) override { goal2sat::collect_param_descrs(r); sat::solver::collect_param_descrs(r); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { solver::updt_params(p); m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { if (m_preprocess) m_preprocess->collect_statistics(st); m_solver.collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { + void get_unsat_core(ptr_vector & r) override { r.reset(); r.append(m_core.size(), m_core.c_ptr()); } - virtual void get_model(model_ref & mdl) { + void get_model(model_ref & mdl) override { if (!m_model.get()) { extract_model(); } mdl = m_model; } - virtual proof * get_proof() { + proof * get_proof() override { UNREACHABLE(); return 0; } - virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) override { init_preprocess(); TRACE("sat", tout << assumptions << "\n" << vars << "\n";); sat::literal_vector asms; @@ -304,7 +304,7 @@ public: return r; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { sat::literal_vector ls; u_map lit2var; for (unsigned i = 0; i < vars.size(); ++i) { @@ -330,24 +330,24 @@ public: return l_true; } - virtual std::string reason_unknown() const { + std::string reason_unknown() const override { return m_unknown; } - virtual void set_reason_unknown(char const* msg) { + void set_reason_unknown(char const* msg) override { m_unknown = msg; } - virtual void get_labels(svector & r) { + void get_labels(svector & r) override { } - virtual unsigned get_num_assertions() const { + unsigned get_num_assertions() const override { return m_fmls.size(); } - virtual expr * get_assertion(unsigned idx) const { + expr * get_assertion(unsigned idx) const override { return m_fmls[idx]; } - virtual unsigned get_num_assumptions() const { + unsigned get_num_assumptions() const override { return m_asmsf.size(); } - virtual expr * get_assumption(unsigned idx) const { + expr * get_assumption(unsigned idx) const override { return m_asmsf[idx]; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 1f9dd91d1..bb5907003 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -593,7 +593,7 @@ struct sat2goal::imp { } } - virtual void operator()(model_ref & md, unsigned goal_idx) { + void operator()(model_ref & md, unsigned goal_idx) override { SASSERT(goal_idx == 0); TRACE("sat_mc", tout << "before sat_mc\n"; model_v2_pp(tout, *md); display(tout);); // REMARK: potential problem @@ -644,7 +644,7 @@ struct sat2goal::imp { TRACE("sat_mc", tout << "after sat_mc\n"; model_v2_pp(tout, *md);); } - virtual model_converter * translate(ast_translation & translator) { + model_converter * translate(ast_translation & translator) override { sat_model_converter * res = alloc(sat_model_converter, translator.to()); res->m_fmc = static_cast(m_fmc->translate(translator)); unsigned sz = m_var2expr.size(); @@ -653,7 +653,7 @@ struct sat2goal::imp { return res; } - void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(sat-model-converter\n"; m_mc.display(out); sat::bool_var_set vars; diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 4a6171f70..3db379cb1 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -39,9 +39,9 @@ class sat_tactic : public tactic { SASSERT(!m.proofs_enabled()); } - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { mc = 0; pc = 0; core = 0; @@ -162,29 +162,29 @@ public: m_params(p) { } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(sat_tactic, m, m_params); } - virtual ~sat_tactic() { + ~sat_tactic() override { SASSERT(m_imp == 0); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { goal2sat::collect_param_descrs(r); sat2goal::collect_param_descrs(r); sat::solver::collect_param_descrs(r); } - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, + void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, - expr_dependency_ref & core) { + expr_dependency_ref & core) override { imp proc(g->m(), m_params); scoped_set_imp set(this, &proc); try { @@ -198,15 +198,15 @@ public: TRACE("sat_stats", m_stats.display_smt2(tout);); } - virtual void cleanup() { + void cleanup() override { SASSERT(m_imp == 0); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.copy(m_stats); } - virtual void reset_statistics() { + void reset_statistics() override { m_stats.reset(); } diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index 95f9e1eb3..c1afd5e13 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -49,7 +49,7 @@ struct front_end_resource_limit : public lp::lp_resource_limit { m_reslim(lim) {} - virtual bool get_cancel_flag() { return !m_reslim.inc(); } + bool get_cancel_flag() override { return !m_reslim.inc(); } }; void run_solver(lp_params & params, char const * mps_file_name) { diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index 307bdc671..febec9565 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -42,7 +42,7 @@ namespace smt { m_n2(n2) { } - virtual void undo(context & ctx) { + void undo(context & ctx) override { m_already_processed.erase(m_n1, m_n2); TRACE("arith_eq_adapter_profile", tout << "del #" << m_n1->get_owner_id() << " #" << m_n2->get_owner_id() << "\n";); } @@ -67,9 +67,9 @@ namespace smt { m_ge(ge) { } - virtual ~arith_eq_relevancy_eh() {} + ~arith_eq_relevancy_eh() override {} - virtual void operator()(relevancy_propagator & rp) { + void operator()(relevancy_propagator & rp) override { if (!rp.is_relevant(m_n1)) return; if (!rp.is_relevant(m_n2)) diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index 88c9e13a7..a67b975eb 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -82,80 +82,80 @@ class asserted_formulas { class reduce_asserted_formulas_fn : public simplify_fmls { public: reduce_asserted_formulas_fn(asserted_formulas& af): simplify_fmls(af, "reduce-asserted") {} - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { af.m_rewriter(j.get_fml(), n, p); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { af.m_rewriter(j.get_fml(), n, p); } }; class find_macros_fn : public simplify_fmls { public: find_macros_fn(asserted_formulas& af): simplify_fmls(af, "find-macros") {} - virtual void operator()() { af.find_macros_core(); } - virtual bool should_apply() const { return af.m_params.m_macro_finder && af.has_quantifiers(); } - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + void operator()() override { af.find_macros_core(); } + bool should_apply() const override { return af.m_params.m_macro_finder && af.has_quantifiers(); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { UNREACHABLE(); } }; class apply_quasi_macros_fn : public simplify_fmls { public: apply_quasi_macros_fn(asserted_formulas& af): simplify_fmls(af, "find-quasi-macros") {} - virtual void operator()() { af.apply_quasi_macros(); } - virtual bool should_apply() const { return af.m_params.m_quasi_macros && af.has_quantifiers(); } - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + void operator()() override { af.apply_quasi_macros(); } + bool should_apply() const override { return af.m_params.m_quasi_macros && af.has_quantifiers(); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { UNREACHABLE(); } }; class nnf_cnf_fn : public simplify_fmls { public: nnf_cnf_fn(asserted_formulas& af): simplify_fmls(af, "nnf-cnf") {} - virtual void operator()() { af.nnf_cnf(); } - virtual bool should_apply() const { return af.m_params.m_nnf_cnf || (af.m_params.m_mbqi && af.has_quantifiers()); } - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + void operator()() override { af.nnf_cnf(); } + bool should_apply() const override { return af.m_params.m_nnf_cnf || (af.m_params.m_mbqi && af.has_quantifiers()); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { UNREACHABLE(); } }; class propagate_values_fn : public simplify_fmls { public: propagate_values_fn(asserted_formulas& af): simplify_fmls(af, "propagate-values") {} - virtual void operator()() { af.propagate_values(); } - virtual bool should_apply() const { return af.m_params.m_propagate_values; } - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + void operator()() override { af.propagate_values(); } + bool should_apply() const override { return af.m_params.m_propagate_values; } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { UNREACHABLE(); } }; class distribute_forall_fn : public simplify_fmls { distribute_forall m_functor; public: distribute_forall_fn(asserted_formulas& af): simplify_fmls(af, "distribute-forall"), m_functor(af.m) {} - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_functor(j.get_fml(), n); } - virtual bool should_apply() const { return af.m_params.m_distribute_forall && af.has_quantifiers(); } - virtual void post_op() { af.reduce_and_solve(); TRACE("asserted_formulas", af.display(tout);); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { m_functor(j.get_fml(), n); } + bool should_apply() const override { return af.m_params.m_distribute_forall && af.has_quantifiers(); } + void post_op() override { af.reduce_and_solve(); TRACE("asserted_formulas", af.display(tout);); } }; class pattern_inference_fn : public simplify_fmls { pattern_inference_rw m_infer; public: pattern_inference_fn(asserted_formulas& af): simplify_fmls(af, "pattern-inference"), m_infer(af.m, af.m_params) {} - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_infer(j.get_fml(), n, p); } - virtual bool should_apply() const { return af.m_params.m_ematching && af.has_quantifiers(); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { m_infer(j.get_fml(), n, p); } + bool should_apply() const override { return af.m_params.m_ematching && af.has_quantifiers(); } }; class refine_inj_axiom_fn : public simplify_fmls { public: refine_inj_axiom_fn(asserted_formulas& af): simplify_fmls(af, "refine-injectivity") {} - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p); - virtual bool should_apply() const { return af.m_params.m_refine_inj_axiom && af.has_quantifiers(); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override; + bool should_apply() const override { return af.m_params.m_refine_inj_axiom && af.has_quantifiers(); } }; class max_bv_sharing_fn : public simplify_fmls { public: max_bv_sharing_fn(asserted_formulas& af): simplify_fmls(af, "maximizing-bv-sharing") {} - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { af.m_bv_sharing(j.get_fml(), n, p); } - virtual bool should_apply() const { return af.m_params.m_max_bv_sharing; } - virtual void post_op() { af.m_reduce_asserted_formulas(); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { af.m_bv_sharing(j.get_fml(), n, p); } + bool should_apply() const override { return af.m_params.m_max_bv_sharing; } + void post_op() override { af.m_reduce_asserted_formulas(); } }; class elim_term_ite_fn : public simplify_fmls { elim_term_ite_rw m_elim; public: elim_term_ite_fn(asserted_formulas& af): simplify_fmls(af, "elim-term-ite"), m_elim(af.m, af.m_defined_names) {} - virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_elim(j.get_fml(), n, p); } - virtual bool should_apply() const { return af.m_params.m_eliminate_term_ite && af.m_params.m_lift_ite != LI_FULL; } - virtual void post_op() { af.m_formulas.append(m_elim.new_defs()); af.reduce_and_solve(); m_elim.reset(); } + void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) override { m_elim(j.get_fml(), n, p); } + bool should_apply() const override { return af.m_params.m_eliminate_term_ite && af.m_params.m_lift_ite != LI_FULL; } + void post_op() override { af.m_formulas.append(m_elim.new_defs()); af.reduce_and_solve(); m_elim.reset(); } }; #define MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, ARG, REDUCE) \ diff --git a/src/smt/dyn_ack.cpp b/src/smt/dyn_ack.cpp index baa8129bb..dd77640bc 100644 --- a/src/smt/dyn_ack.cpp +++ b/src/smt/dyn_ack.cpp @@ -39,12 +39,12 @@ namespace smt { SASSERT(m_app1->get_id() < m_app2->get_id()); } - virtual char const * get_name() const { return "dyn-ack"; } + char const * get_name() const override { return "dyn-ack"; } - virtual void get_antecedents(conflict_resolution & cr) { + void get_antecedents(conflict_resolution & cr) override { } - virtual void display_debug_info(conflict_resolution & cr, std::ostream & out) { + void display_debug_info(conflict_resolution & cr, std::ostream & out) override { ast_manager & m = cr.get_manager(); out << "m_app1:\n" << mk_pp(m_app1, m) << "\n"; out << "m_app2:\n" << mk_pp(m_app2, m) << "\n"; @@ -70,7 +70,7 @@ namespace smt { } } - virtual proof * mk_proof(conflict_resolution & cr) { + proof * mk_proof(conflict_resolution & cr) override { ast_manager & m = cr.get_manager(); context & ctx = cr.get_context(); unsigned num_args = m_app1->get_num_args(); @@ -288,8 +288,8 @@ namespace smt { dyn_ack_clause_del_eh(dyn_ack_manager & m): m_manager(m) { } - virtual ~dyn_ack_clause_del_eh() {} - virtual void operator()(ast_manager & m, clause * cls) { + ~dyn_ack_clause_del_eh() override {} + void operator()(ast_manager & m, clause * cls) override { m_manager.del_clause_eh(cls); dealloc(this); } diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index c979e476e..7fd1dd9d0 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -2844,7 +2844,7 @@ namespace smt { unsigned m_lbl_id; public: mk_tree_trail(ptr_vector & t, unsigned id):m_trees(t), m_lbl_id(id) {} - virtual void undo(mam_impl & m) { + void undo(mam_impl & m) override { dealloc(m_trees[m_lbl_id]); m_trees[m_lbl_id] = 0; } @@ -3104,7 +3104,7 @@ namespace smt { enode * m_enode; public: add_shared_enode_trail(enode * n):m_enode(n) {} - virtual void undo(mam_impl & m) { m.m_shared_enodes.erase(m_enode); } + void undo(mam_impl & m) override { m.m_shared_enodes.erase(m_enode); } }; #ifdef Z3DEBUG @@ -3819,11 +3819,11 @@ namespace smt { reset_pp_pc(); } - virtual ~mam_impl() { + ~mam_impl() override { m_trail_stack.reset(); } - virtual void add_pattern(quantifier * qa, app * mp) { + void add_pattern(quantifier * qa, app * mp) override { SASSERT(m_ast_manager.is_pattern(mp)); TRACE("trigger_bug", tout << "adding pattern\n" << mk_ismt2_pp(qa, m_ast_manager) << "\n" << mk_ismt2_pp(mp, m_ast_manager) << "\n";); TRACE("mam_bug", tout << "adding pattern\n" << mk_pp(qa, m_ast_manager) << "\n" << mk_pp(mp, m_ast_manager) << "\n";); @@ -3846,11 +3846,11 @@ namespace smt { m_trees.add_pattern(qa, mp, i); } - virtual void push_scope() { + void push_scope() override { m_trail_stack.push_scope(); } - virtual void pop_scope(unsigned num_scopes) { + void pop_scope(unsigned num_scopes) override { if (!m_to_match.empty()) { ptr_vector::iterator it = m_to_match.begin(); ptr_vector::iterator end = m_to_match.end(); @@ -3864,7 +3864,7 @@ namespace smt { m_trail_stack.pop_scope(num_scopes); } - virtual void reset() { + void reset() override { m_trail_stack.reset(); m_trees.reset(); m_to_match.reset(); @@ -3875,7 +3875,7 @@ namespace smt { m_tmp_region.reset(); } - virtual void display(std::ostream& out) { + void display(std::ostream& out) override { out << "mam:\n"; m_lbl_hasher.display(out); ptr_vector::iterator it = m_trees.begin_code_trees(); @@ -3886,7 +3886,7 @@ namespace smt { } } - virtual void match() { + void match() override { TRACE("trigger_bug", tout << "match\n"; display(tout);); ptr_vector::iterator it = m_to_match.begin(); ptr_vector::iterator end = m_to_match.end(); @@ -3903,7 +3903,7 @@ namespace smt { } } - virtual void rematch(bool use_irrelevant) { + void rematch(bool use_irrelevant) override { ptr_vector::iterator it = m_trees.begin_code_trees(); ptr_vector::iterator end = m_trees.end_code_trees(); unsigned lbl = 0; @@ -3932,7 +3932,7 @@ namespace smt { } #endif - virtual void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector & used_enodes) { + void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector & used_enodes) override { TRACE("trigger_bug", tout << "found match " << mk_pp(qa, m_ast_manager) << "\n";); #ifdef Z3DEBUG if (m_check_missing_instances) { @@ -3955,13 +3955,13 @@ namespace smt { m_context.add_instance(qa, pat, num_bindings, bindings, max_generation, min_gen, max_gen, used_enodes); } - virtual bool is_shared(enode * n) const { + bool is_shared(enode * n) const override { return !m_shared_enodes.empty() && m_shared_enodes.contains(n); } // This method is invoked when n becomes relevant. // If lazy == true, then n is not added to the list of candidate enodes for matching. That is, the method just updates the lbls. - virtual void relevant_eh(enode * n, bool lazy) { + void relevant_eh(enode * n, bool lazy) override { TRACE("trigger_bug", tout << "relevant_eh:\n" << mk_ismt2_pp(n->get_owner(), m_ast_manager) << "\n"; tout << "mam: " << this << "\n";); TRACE("mam", tout << "relevant_eh: #" << n->get_owner_id() << "\n";); @@ -3984,11 +3984,11 @@ namespace smt { } } - virtual bool has_work() const { + bool has_work() const override { return !m_to_match.empty() || !m_new_patterns.empty(); } - virtual void add_eq_eh(enode * r1, enode * r2) { + void add_eq_eh(enode * r1, enode * r2) override { flet l1(m_r1, r1); flet l2(m_r2, r2); diff --git a/src/smt/proto_model/array_factory.h b/src/smt/proto_model/array_factory.h index 4d4f52944..b59df3f94 100644 --- a/src/smt/proto_model/array_factory.h +++ b/src/smt/proto_model/array_factory.h @@ -32,13 +32,13 @@ class array_factory : public struct_factory { public: array_factory(ast_manager & m, proto_model & md); - virtual ~array_factory() {} + ~array_factory() override {} - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2); + bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override; - virtual expr * get_fresh_value(sort * s); + expr * get_fresh_value(sort * s) override; }; #endif /* ARRAY_FACTORY_H_ */ diff --git a/src/smt/proto_model/datatype_factory.h b/src/smt/proto_model/datatype_factory.h index 9f64b8daa..85b264382 100644 --- a/src/smt/proto_model/datatype_factory.h +++ b/src/smt/proto_model/datatype_factory.h @@ -33,9 +33,9 @@ class datatype_factory : public struct_factory { public: datatype_factory(ast_manager & m, proto_model & md); - virtual ~datatype_factory() {} - virtual expr * get_some_value(sort * s); - virtual expr * get_fresh_value(sort * s); + ~datatype_factory() override {} + expr * get_some_value(sort * s) override; + expr * get_fresh_value(sort * s) override; }; #endif /* DATATYPE_FACTORY_H_ */ diff --git a/src/smt/proto_model/numeral_factory.h b/src/smt/proto_model/numeral_factory.h index f1b68223b..198ff0d32 100644 --- a/src/smt/proto_model/numeral_factory.h +++ b/src/smt/proto_model/numeral_factory.h @@ -26,17 +26,17 @@ Revision History: class numeral_factory : public simple_factory { public: numeral_factory(ast_manager & m, family_id fid):simple_factory(m, fid) {} - virtual ~numeral_factory() {} + ~numeral_factory() override {} }; class arith_factory : public numeral_factory { arith_util m_util; - virtual app * mk_value_core(rational const & val, sort * s); + app * mk_value_core(rational const & val, sort * s) override; public: arith_factory(ast_manager & m); - virtual ~arith_factory(); + ~arith_factory() override; app * mk_num_value(rational const & val, bool is_int); }; @@ -44,11 +44,11 @@ public: class bv_factory : public numeral_factory { bv_util m_util; - virtual app * mk_value_core(rational const & val, sort * s); + app * mk_value_core(rational const & val, sort * s) override; public: bv_factory(ast_manager & m); - virtual ~bv_factory(); + ~bv_factory() override; app * mk_num_value(rational const & val, unsigned bv_size); }; diff --git a/src/smt/proto_model/proto_model.h b/src/smt/proto_model/proto_model.h index 05af0091c..d92d459e4 100644 --- a/src/smt/proto_model/proto_model.h +++ b/src/smt/proto_model/proto_model.h @@ -60,7 +60,7 @@ class proto_model : public model_core { public: proto_model(ast_manager & m, params_ref const & p = params_ref()); - virtual ~proto_model() {} + ~proto_model() override {} void register_factory(value_factory * f) { m_factories.register_plugin(f); } @@ -69,7 +69,7 @@ public: value_factory * get_factory(family_id fid); - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2); @@ -93,9 +93,9 @@ public: void freeze_universe(sort * s); bool is_finite(sort * s) const; obj_hashtable const & get_known_universe(sort * s) const; - virtual ptr_vector const & get_universe(sort * s) const; - virtual unsigned get_num_uninterpreted_sorts() const; - virtual sort * get_uninterpreted_sort(unsigned idx) const; + ptr_vector const & get_universe(sort * s) const override; + unsigned get_num_uninterpreted_sorts() const override; + sort * get_uninterpreted_sort(unsigned idx) const override; // // Complete partial function interps diff --git a/src/smt/proto_model/struct_factory.h b/src/smt/proto_model/struct_factory.h index bfbd90ede..9fe54392c 100644 --- a/src/smt/proto_model/struct_factory.h +++ b/src/smt/proto_model/struct_factory.h @@ -43,11 +43,11 @@ protected: public: struct_factory(ast_manager & m, family_id fid, proto_model & md); - virtual ~struct_factory(); + ~struct_factory() override; - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2); + bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override; - virtual void register_value(expr * array_value); + void register_value(expr * array_value) override; }; #endif /* STRUCT_FACTORY_H_ */ diff --git a/src/smt/proto_model/value_factory.h b/src/smt/proto_model/value_factory.h index e81c63306..3979a47bb 100644 --- a/src/smt/proto_model/value_factory.h +++ b/src/smt/proto_model/value_factory.h @@ -64,13 +64,13 @@ class basic_factory : public value_factory { public: basic_factory(ast_manager & m); - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2); + bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override; - virtual expr * get_fresh_value(sort * s); + expr * get_fresh_value(sort * s) override; - virtual void register_value(expr * n) { } + void register_value(expr * n) override { } }; /** @@ -133,11 +133,11 @@ public: m_sorts(m) { } - virtual ~simple_factory() { + ~simple_factory() override { std::for_each(m_sets.begin(), m_sets.end(), delete_proc()); } - virtual expr * get_some_value(sort * s) { + expr * get_some_value(sort * s) override { value_set * set = 0; expr * result = 0; if (m_sort2value_set.find(s, set) && !set->m_values.empty()) @@ -147,7 +147,7 @@ public: return result; } - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { + bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override { value_set * set = 0; if (m_sort2value_set.find(s, set)) { switch (set->m_values.size()) { @@ -176,7 +176,7 @@ public: return true; } - virtual expr * get_fresh_value(sort * s) { + expr * get_fresh_value(sort * s) override { value_set * set = get_value_set(s); bool is_new = false; expr * result = 0; @@ -202,7 +202,7 @@ public: return result; } - virtual void register_value(expr * n) { + void register_value(expr * n) override { sort * s = this->m_manager.get_sort(n); value_set * set = get_value_set(s); if (!set->m_values.contains(n)) { @@ -228,10 +228,10 @@ public: class user_sort_factory : public simple_factory { obj_hashtable m_finite; //!< set of sorts that are marked as finite. obj_hashtable m_empty_universe; - virtual app * mk_value_core(unsigned const & val, sort * s); + app * mk_value_core(unsigned const & val, sort * s) override; public: user_sort_factory(ast_manager & m); - virtual ~user_sort_factory() {} + ~user_sort_factory() override {} /** \brief Make the universe of \c s finite, by preventing new @@ -257,13 +257,13 @@ public: */ obj_hashtable const & get_finite_sorts() const { return m_finite; } - virtual expr * get_some_value(sort * s); + expr * get_some_value(sort * s) override; - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2); + bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override; - virtual expr * get_fresh_value(sort * s); + expr * get_fresh_value(sort * s) override; - virtual void register_value(expr * n); + void register_value(expr * n) override; }; #endif /* VALUE_FACTORY_H_ */ diff --git a/src/smt/smt2_extra_cmds.cpp b/src/smt/smt2_extra_cmds.cpp index 136805e43..238295a49 100644 --- a/src/smt/smt2_extra_cmds.cpp +++ b/src/smt/smt2_extra_cmds.cpp @@ -24,22 +24,22 @@ class include_cmd : public cmd { char const * m_filename; public: include_cmd() : cmd("include"), m_filename(0) {} - virtual char const * get_usage() const { return ""; } - virtual char const * get_descr(cmd_context & ctx) const { return "include a file"; } - virtual unsigned get_arity() const { return 1; } - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { return CPK_STRING; } - virtual void set_next_arg(cmd_context & ctx, char const * val) { m_filename = val; } - virtual void failure_cleanup(cmd_context & ctx) {} - virtual void execute(cmd_context & ctx) { + char const * get_usage() const override { return ""; } + char const * get_descr(cmd_context & ctx) const override { return "include a file"; } + unsigned get_arity() const override { return 1; } + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_STRING; } + void set_next_arg(cmd_context & ctx, char const * val) override { m_filename = val; } + void failure_cleanup(cmd_context & ctx) override {} + void execute(cmd_context & ctx) override { std::ifstream is(m_filename); if (is.bad() || is.fail()) throw cmd_exception(std::string("failed to open file '") + m_filename + "'"); parse_smt2_commands(ctx, is, false, params_ref(), m_filename); is.close(); } - virtual void prepare(cmd_context & ctx) { reset(ctx); } - virtual void reset(cmd_context & ctx) { m_filename = 0; } - virtual void finalize(cmd_context & ctx) { reset(ctx); } + void prepare(cmd_context & ctx) override { reset(ctx); } + void reset(cmd_context & ctx) override { m_filename = 0; } + void finalize(cmd_context & ctx) override { reset(ctx); } }; void install_smt2_extra_cmds(cmd_context & ctx) { diff --git a/src/smt/smt_case_split_queue.cpp b/src/smt/smt_case_split_queue.cpp index 6aef5f0a9..3da6ce295 100644 --- a/src/smt/smt_case_split_queue.cpp +++ b/src/smt/smt_case_split_queue.cpp @@ -75,42 +75,42 @@ namespace smt { m_queue(1024, bool_var_act_lt(ctx.get_activity_vector())) { } - virtual void activity_increased_eh(bool_var v) { + void activity_increased_eh(bool_var v) override { if (m_queue.contains(v)) m_queue.decreased(v); } - virtual void mk_var_eh(bool_var v) { + void mk_var_eh(bool_var v) override { m_queue.reserve(v+1); SASSERT(!m_queue.contains(v)); m_queue.insert(v); } - virtual void del_var_eh(bool_var v) { + void del_var_eh(bool_var v) override { if (m_queue.contains(v)) m_queue.erase(v); } - virtual void unassign_var_eh(bool_var v) { + void unassign_var_eh(bool_var v) override { if (!m_queue.contains(v)) m_queue.insert(v); } - virtual void relevant_eh(expr * n) {} + void relevant_eh(expr * n) override {} - virtual void init_search_eh() {} + void init_search_eh() override {} - virtual void end_search_eh() {} + void end_search_eh() override {} - virtual void reset() { + void reset() override { m_queue.reset(); } - virtual void push_scope() {} + void push_scope() override {} - virtual void pop_scope(unsigned num_scopes) {} + void pop_scope(unsigned num_scopes) override {} - virtual void next_case_split(bool_var & next, lbool & phase) { + void next_case_split(bool_var & next, lbool & phase) override { phase = l_undef; if (m_context.get_random_value() < static_cast(m_params.m_random_var_freq * random_gen::max_value())) { @@ -129,7 +129,7 @@ namespace smt { next = null_bool_var; } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { bool first = true; for (unsigned v : m_queue) { if (m_context.get_assignment(v) == l_undef) { @@ -144,7 +144,7 @@ namespace smt { out << "\n"; } - virtual ~act_case_split_queue() {}; + ~act_case_split_queue() override {}; }; /** @@ -159,7 +159,7 @@ namespace smt { m_delayed_queue(1024, bool_var_act_lt(ctx.get_activity_vector())) { } - virtual void activity_increased_eh(bool_var v) { + void activity_increased_eh(bool_var v) override { act_case_split_queue::activity_increased_eh(v); if (m_queue.contains(v)) m_queue.decreased(v); @@ -167,7 +167,7 @@ namespace smt { m_delayed_queue.decreased(v); } - virtual void mk_var_eh(bool_var v) { + void mk_var_eh(bool_var v) override { m_queue.reserve(v+1); m_delayed_queue.reserve(v+1); SASSERT(!m_delayed_queue.contains(v)); @@ -178,28 +178,28 @@ namespace smt { m_queue.insert(v); } - virtual void del_var_eh(bool_var v) { + void del_var_eh(bool_var v) override { act_case_split_queue::del_var_eh(v); if (m_delayed_queue.contains(v)) m_delayed_queue.erase(v); } - virtual void relevant_eh(expr * n) {} + void relevant_eh(expr * n) override {} - virtual void init_search_eh() {} + void init_search_eh() override {} - virtual void end_search_eh() {} + void end_search_eh() override {} - virtual void reset() { + void reset() override { act_case_split_queue::reset(); m_delayed_queue.reset(); } - virtual void push_scope() {} + void push_scope() override {} - virtual void pop_scope(unsigned num_scopes) {} + void pop_scope(unsigned num_scopes) override {} - virtual void next_case_split(bool_var & next, lbool & phase) { + void next_case_split(bool_var & next, lbool & phase) override { act_case_split_queue::next_case_split(next, phase); if (next != null_bool_var) return; @@ -229,7 +229,7 @@ namespace smt { m_cache_domain(ctx.get_manager()) { } - virtual void mk_var_eh(bool_var v) { + void mk_var_eh(bool_var v) override { expr * n = m_context.bool_var2expr(v); double act; if (m_cache.find(n, act)) @@ -237,7 +237,7 @@ namespace smt { act_case_split_queue::mk_var_eh(v); } - virtual void del_var_eh(bool_var v) { + void del_var_eh(bool_var v) override { if (m_context.is_searching()) { double act = m_context.get_activity(v); if (act > 0.0) { @@ -249,14 +249,14 @@ namespace smt { act_case_split_queue::del_var_eh(v); } - virtual void init_search_eh() { + void init_search_eh() override { m_cache.reset(); m_cache_domain.reset(); } - virtual void end_search_eh() {} + void end_search_eh() override {} - virtual void reset() { + void reset() override { init_search_eh(); } }; @@ -322,15 +322,15 @@ namespace smt { m_head2(0) { } - virtual void activity_increased_eh(bool_var v) {} + void activity_increased_eh(bool_var v) override {} - virtual void mk_var_eh(bool_var v) {} + void mk_var_eh(bool_var v) override {} - virtual void del_var_eh(bool_var v) {} + void del_var_eh(bool_var v) override {} - virtual void unassign_var_eh(bool_var v) {} + void unassign_var_eh(bool_var v) override {} - virtual void relevant_eh(expr * n) { + void relevant_eh(expr * n) override { if (!m_manager.is_bool(n)) return; bool is_or = m_manager.is_or(n); @@ -361,15 +361,15 @@ namespace smt { m_queue2.push_back(n); } - virtual void init_search_eh() { + void init_search_eh() override { m_bs_num_bool_vars = m_context.get_num_bool_vars(); } - virtual void end_search_eh() { + void end_search_eh() override { m_bs_num_bool_vars = UINT_MAX; } - virtual void reset() { + void reset() override { m_queue.reset(); m_head = 0; m_queue2.reset(); @@ -377,7 +377,7 @@ namespace smt { m_scopes.reset(); } - virtual void push_scope() { + void push_scope() override { m_scopes.push_back(scope()); scope & s = m_scopes.back(); s.m_queue_trail = m_queue.size(); @@ -387,7 +387,7 @@ namespace smt { TRACE("case_split", tout << "head: " << m_head << "\n";); } - virtual void pop_scope(unsigned num_scopes) { + void pop_scope(unsigned num_scopes) override { SASSERT(num_scopes <= m_scopes.size()); unsigned new_lvl = m_scopes.size() - num_scopes; scope & s = m_scopes[new_lvl]; @@ -443,7 +443,7 @@ namespace smt { next = null_bool_var; } - virtual void next_case_split(bool_var & next, lbool & phase) { + void next_case_split(bool_var & next, lbool & phase) override { next_case_split_core(m_queue, m_head, next, phase); if (next == null_bool_var) next_case_split_core(m_queue2, m_head2, next, phase); @@ -471,7 +471,7 @@ namespace smt { out << "\n"; } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { if (m_queue.empty() && m_queue2.empty()) return; out << "case-splits:\n"; @@ -507,9 +507,9 @@ namespace smt { m_delayed_queue(1024, bool_var_act_lt(ctx.get_activity_vector())) { } - virtual void activity_increased_eh(bool_var v) {} + void activity_increased_eh(bool_var v) override {} - virtual void mk_var_eh(bool_var v) { + void mk_var_eh(bool_var v) override { if (m_context.is_searching()) { SASSERT(v >= m_bs_num_bool_vars); m_delayed_queue.reserve(v+1); @@ -517,19 +517,19 @@ namespace smt { } } - virtual void del_var_eh(bool_var v) { + void del_var_eh(bool_var v) override { if (v >= m_bs_num_bool_vars && m_delayed_queue.contains(v)) m_delayed_queue.erase(v); } - virtual void unassign_var_eh(bool_var v) { + void unassign_var_eh(bool_var v) override { if (v < m_bs_num_bool_vars) return; if (!m_delayed_queue.contains(v)) m_delayed_queue.insert(v); } - virtual void relevant_eh(expr * n) { + void relevant_eh(expr * n) override { if (!m_manager.is_bool(n)) return; bool is_or = m_manager.is_or(n); @@ -558,22 +558,22 @@ namespace smt { m_queue.push_back(n); } - virtual void init_search_eh() { + void init_search_eh() override { m_bs_num_bool_vars = m_context.get_num_bool_vars(); } - virtual void end_search_eh() { + void end_search_eh() override { m_bs_num_bool_vars = UINT_MAX; } - virtual void reset() { + void reset() override { m_queue.reset(); m_head = 0; m_delayed_queue.reset(); m_scopes.reset(); } - virtual void push_scope() { + void push_scope() override { m_scopes.push_back(scope()); scope & s = m_scopes.back(); s.m_queue_trail = m_queue.size(); @@ -581,7 +581,7 @@ namespace smt { TRACE("case_split", tout << "head: " << m_head << "\n";); } - virtual void pop_scope(unsigned num_scopes) { + void pop_scope(unsigned num_scopes) override { SASSERT(num_scopes <= m_scopes.size()); unsigned new_lvl = m_scopes.size() - num_scopes; scope & s = m_scopes[new_lvl]; @@ -632,7 +632,7 @@ namespace smt { next = null_bool_var; } - virtual void next_case_split(bool_var & next, lbool & phase) { + void next_case_split(bool_var & next, lbool & phase) override { if (m_context.get_random_value() < static_cast(0.02 * random_gen::max_value())) { next = m_context.get_random_value() % m_context.get_num_b_internalized(); TRACE("random_split", tout << "next: " << next << " get_assignment(next): " << m_context.get_assignment(next) << "\n";); @@ -664,7 +664,7 @@ namespace smt { out << "\n"; } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { if (m_queue.empty()) return; out << "case-splits:\n"; @@ -751,15 +751,15 @@ namespace smt { set_global_generation(); } - virtual void activity_increased_eh(bool_var v) {} + void activity_increased_eh(bool_var v) override {} - virtual void mk_var_eh(bool_var v) {} + void mk_var_eh(bool_var v) override {} - virtual void del_var_eh(bool_var v) {} + void del_var_eh(bool_var v) override {} - virtual void unassign_var_eh(bool_var v) {} + void unassign_var_eh(bool_var v) override {} - virtual void relevant_eh(expr * n) { + void relevant_eh(expr * n) override { if (get_generation(n) == 0 && m_current_generation != 0) set_generation_rec(n, m_current_generation); @@ -793,21 +793,21 @@ namespace smt { add_to_queue2(n); } - virtual void internalize_instance_eh(expr * e, unsigned gen) + void internalize_instance_eh(expr * e, unsigned gen) override { //lower_generation(e, gen); } - virtual void init_search_eh() { + void init_search_eh() override { m_bs_num_bool_vars = m_context.get_num_bool_vars(); set_global_generation(); } - virtual void end_search_eh() { + void end_search_eh() override { m_bs_num_bool_vars = UINT_MAX; } - virtual void reset() { + void reset() override { m_queue.reset(); m_head = 0; m_queue2.reset(); @@ -816,7 +816,7 @@ namespace smt { set_global_generation(); } - virtual void push_scope() { + void push_scope() override { m_scopes.push_back(scope()); scope & s = m_scopes.back(); s.m_queue_trail = m_queue.size(); @@ -827,7 +827,7 @@ namespace smt { TRACE("case_split", tout << "head: " << m_head << "\n";); } - virtual void pop_scope(unsigned num_scopes) { + void pop_scope(unsigned num_scopes) override { SASSERT(num_scopes <= m_scopes.size()); unsigned new_lvl = m_scopes.size() - num_scopes; scope & s = m_scopes[new_lvl]; @@ -898,7 +898,7 @@ namespace smt { next = null_bool_var; } - virtual void next_case_split(bool_var & next, lbool & phase) { + void next_case_split(bool_var & next, lbool & phase) override { phase = l_undef; next = null_bool_var; @@ -943,7 +943,7 @@ namespace smt { out << "\n"; } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { if (m_queue.empty() && m_queue2.empty()) return; out << "case-splits:\n"; @@ -951,7 +951,7 @@ namespace smt { //display_core(out, m_queue2, m_head2, 2); } - virtual void assign_lit_eh(literal l) { + void assign_lit_eh(literal l) override { // if (m_current_generation > stop_gen) // m_current_generation--; @@ -1128,41 +1128,41 @@ namespace smt { m_queue(1024, theory_aware_act_lt(ctx.get_activity_vector(), m_theory_var_priority)) { } - virtual void activity_increased_eh(bool_var v) { + void activity_increased_eh(bool_var v) override { if (m_queue.contains(v)) m_queue.decreased(v); } - virtual void mk_var_eh(bool_var v) { + void mk_var_eh(bool_var v) override { m_queue.reserve(v+1); m_queue.insert(v); } - virtual void del_var_eh(bool_var v) { + void del_var_eh(bool_var v) override { if (m_queue.contains(v)) m_queue.erase(v); } - virtual void unassign_var_eh(bool_var v) { + void unassign_var_eh(bool_var v) override { if (!m_queue.contains(v)) m_queue.insert(v); } - virtual void relevant_eh(expr * n) {} + void relevant_eh(expr * n) override {} - virtual void init_search_eh() {} + void init_search_eh() override {} - virtual void end_search_eh() {} + void end_search_eh() override {} - virtual void reset() { + void reset() override { m_queue.reset(); } - virtual void push_scope() {} + void push_scope() override {} - virtual void pop_scope(unsigned num_scopes) {} + void pop_scope(unsigned num_scopes) override {} - virtual void next_case_split(bool_var & next, lbool & phase) { + void next_case_split(bool_var & next, lbool & phase) override { int threshold = static_cast(m_params.m_random_var_freq * random_gen::max_value()); SASSERT(threshold >= 0); if (m_context.get_random_value() < threshold) { @@ -1187,7 +1187,7 @@ namespace smt { } } - virtual void add_theory_aware_branching_info(bool_var v, double priority, lbool phase) { + void add_theory_aware_branching_info(bool_var v, double priority, lbool phase) override { TRACE("theory_aware_branching", tout << "Add theory-aware branching information for l#" << v << ": priority=" << priority << std::endl;); m_theory_vars.insert(v); m_theory_var_phase.insert(v, phase); @@ -1203,7 +1203,7 @@ namespace smt { // m_theory_queue.insert(v); } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { bool first = true; bool_var_act_queue::const_iterator it = m_queue.begin(); bool_var_act_queue::const_iterator end = m_queue.end(); @@ -1222,7 +1222,7 @@ namespace smt { } - virtual ~theory_aware_branching_queue() {}; + ~theory_aware_branching_queue() override {}; }; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 375ff7e6f..0f09f1f59 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -476,7 +476,7 @@ namespace smt { m_r2_num_parents(r2_num_parents) { } - virtual void undo(context & ctx) { + void undo(context & ctx) override { ctx.undo_add_eq(m_r1, m_n1, m_r2_num_parents); } }; @@ -1451,7 +1451,7 @@ namespace smt { bool_var m_var; public: set_var_theory_trail(bool_var v):m_var(v) {} - virtual void undo(context & ctx) { + void undo(context & ctx) override { bool_var_data & d = ctx.m_bdata[m_var]; d.reset_notify_theory(); } @@ -2951,7 +2951,7 @@ namespace smt { case_split_insert_trail(literal l): l(l) { } - virtual void undo(context & ctx) { + void undo(context & ctx) override { ctx.undo_th_case_split(l); } }; @@ -4131,7 +4131,7 @@ namespace smt { bool_var m_var; public: set_true_first_trail(bool_var v):m_var(v) {} - virtual void undo(context & ctx) { + void undo(context & ctx) override { ctx.m_bdata[m_var].reset_true_first_flag(); } }; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 55d8f03f2..3cd93fbe5 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -746,7 +746,7 @@ namespace smt { friend class mk_bool_var_trail; class mk_bool_var_trail : public trail { public: - virtual void undo(context & ctx) { ctx.undo_mk_bool_var(); } + void undo(context & ctx) override { ctx.undo_mk_bool_var(); } }; mk_bool_var_trail m_mk_bool_var_trail; @@ -755,7 +755,7 @@ namespace smt { friend class mk_enode_trail; class mk_enode_trail : public trail { public: - virtual void undo(context & ctx) { ctx.undo_mk_enode(); } + void undo(context & ctx) override { ctx.undo_mk_enode(); } }; mk_enode_trail m_mk_enode_trail; diff --git a/src/smt/smt_for_each_relevant_expr.h b/src/smt/smt_for_each_relevant_expr.h index b81023349..3626e37c7 100644 --- a/src/smt/smt_for_each_relevant_expr.h +++ b/src/smt/smt_for_each_relevant_expr.h @@ -93,8 +93,8 @@ namespace smt { for_each_relevant_expr(ctx), m_buffer(b) { } - virtual ~collect_relevant_label_lits() {} - virtual void operator()(expr * n); + ~collect_relevant_label_lits() override {} + void operator()(expr * n) override; }; class collect_relevant_labels : public for_each_relevant_expr { @@ -104,8 +104,8 @@ namespace smt { for_each_relevant_expr(ctx), m_buffer(b) { } - virtual ~collect_relevant_labels() {} - virtual void operator()(expr * n); + ~collect_relevant_labels() override {} + void operator()(expr * n) override; }; }; diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index c38ef4e4a..3c92b8318 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -631,7 +631,7 @@ namespace smt { set_merge_tf_trail(enode * n): m_node(n) { } - virtual void undo(context & ctx) { + void undo(context & ctx) override { m_node->m_merge_tf = false; } }; @@ -667,7 +667,7 @@ namespace smt { set_enode_flag_trail(bool_var v): m_var(v) { } - virtual void undo(context & ctx) { + void undo(context & ctx) override { bool_var_data & data = ctx.m_bdata[m_var]; data.reset_enode_flag(); } @@ -1612,7 +1612,7 @@ namespace smt { SASSERT(m_th_var != null_theory_var); } - virtual void undo(context & ctx) { + void undo(context & ctx) override { theory_var v = m_enode->get_th_var(m_th_id); SASSERT(v != null_theory_var); SASSERT(m_th_var == v); @@ -1637,7 +1637,7 @@ namespace smt { m_old_th_var(old_var) { } - virtual void undo(context & ctx) { + void undo(context & ctx) override { SASSERT(m_enode->get_th_var(m_th_id) != null_theory_var); m_enode->replace_th_var(m_old_th_var, m_th_id); } diff --git a/src/smt/smt_justification.h b/src/smt/smt_justification.h index 0af8e61ff..1b5aecfe5 100644 --- a/src/smt/smt_justification.h +++ b/src/smt/smt_justification.h @@ -102,15 +102,15 @@ namespace smt { public: justification_proof_wrapper(context & ctx, proof * pr, bool in_region = true); - virtual bool has_del_eh() const { + bool has_del_eh() const override { return true; } - virtual void del_eh(ast_manager & m); + void del_eh(ast_manager & m) override; - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "proof-wrapper"; } + char const * get_name() const override { return "proof-wrapper"; } }; class unit_resolution_justification : public justification { @@ -122,21 +122,21 @@ namespace smt { unit_resolution_justification(justification * js, unsigned num_lits, literal const * lits); - ~unit_resolution_justification(); + ~unit_resolution_justification() override; - virtual bool has_del_eh() const { + bool has_del_eh() const override { return !in_region() && m_antecedent && m_antecedent->has_del_eh(); } - virtual void del_eh(ast_manager & m) { + void del_eh(ast_manager & m) override { if (!in_region() && m_antecedent) m_antecedent->del_eh(m); } - virtual void get_antecedents(conflict_resolution & cr); + void get_antecedents(conflict_resolution & cr) override; - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "unit-resolution"; } + char const * get_name() const override { return "unit-resolution"; } }; class eq_conflict_justification : public justification { @@ -150,11 +150,11 @@ namespace smt { m_js(js) { } - virtual void get_antecedents(conflict_resolution & cr); + void get_antecedents(conflict_resolution & cr) override; - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "eq-conflict"; } + char const * get_name() const override { return "eq-conflict"; } }; /** @@ -166,11 +166,11 @@ namespace smt { eq_root_propagation_justification(enode * n):m_node(n) { } - virtual void get_antecedents(conflict_resolution & cr); + void get_antecedents(conflict_resolution & cr) override; - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "eq-root"; } + char const * get_name() const override { return "eq-root"; } }; /** @@ -184,11 +184,11 @@ namespace smt { SASSERT(n1 != n2); } - virtual void get_antecedents(conflict_resolution & cr); + void get_antecedents(conflict_resolution & cr) override; - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "eq-propagation"; } + char const * get_name() const override { return "eq-propagation"; } }; /** @@ -201,11 +201,11 @@ namespace smt { mp_iff_justification(enode * n1, enode * n2):m_node1(n1), m_node2(n2) { } - virtual void get_antecedents(conflict_resolution & cr); + void get_antecedents(conflict_resolution & cr) override; - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "mp-iff"; } + char const * get_name() const override { return "mp-iff"; } }; /** @@ -221,11 +221,11 @@ namespace smt { public: simple_justification(region & r, unsigned num_lits, literal const * lits); - virtual void get_antecedents(conflict_resolution & cr); + void get_antecedents(conflict_resolution & cr) override; - virtual proof * mk_proof(conflict_resolution & cr) = 0; + proof * mk_proof(conflict_resolution & cr) override = 0; - virtual char const * get_name() const { return "simple"; } + char const * get_name() const override { return "simple"; } }; @@ -240,13 +240,13 @@ namespace smt { unsigned num_params, parameter* params): simple_justification(r, num_lits, lits), m_th_id(fid), m_params(num_params, params) {} - virtual ~simple_theory_justification() {} + ~simple_theory_justification() override {} - virtual bool has_del_eh() const { return !m_params.empty(); } + bool has_del_eh() const override { return !m_params.empty(); } - virtual void del_eh(ast_manager & m) { m_params.reset(); } + void del_eh(ast_manager & m) override { m_params.reset(); } - virtual theory_id get_from_theory() const { return m_th_id; } + theory_id get_from_theory() const override { return m_th_id; } }; @@ -258,11 +258,11 @@ namespace smt { unsigned num_params = 0, parameter* params = 0): simple_theory_justification(fid, r, num_lits, lits, num_params, params) {} - virtual void get_antecedents(conflict_resolution & cr) {} + void get_antecedents(conflict_resolution & cr) override {} - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "theory-axiom"; } + char const * get_name() const override { return "theory-axiom"; } }; class theory_propagation_justification : public simple_theory_justification { @@ -272,10 +272,10 @@ namespace smt { unsigned num_params = 0, parameter* params = 0): simple_theory_justification(fid, r, num_lits, lits, num_params, params), m_consequent(consequent) {} - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "theory-propagation"; } + char const * get_name() const override { return "theory-propagation"; } }; @@ -285,9 +285,9 @@ namespace smt { unsigned num_params = 0, parameter* params = 0): simple_theory_justification(fid, r, num_lits, lits, num_params, params) {} - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "theory-conflict"; } + char const * get_name() const override { return "theory-conflict"; } }; /** @@ -304,11 +304,11 @@ namespace smt { ext_simple_justification(region & r, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs); - virtual void get_antecedents(conflict_resolution & cr); + void get_antecedents(conflict_resolution & cr) override; - virtual proof * mk_proof(conflict_resolution & cr) = 0; + proof * mk_proof(conflict_resolution & cr) override = 0; - virtual char const * get_name() const { return "ext-simple"; } + char const * get_name() const override { return "ext-simple"; } }; /** @@ -325,13 +325,13 @@ namespace smt { unsigned num_params = 0, parameter* params = 0): ext_simple_justification(r, num_lits, lits, num_eqs, eqs), m_th_id(fid), m_params(num_params, params) {} - virtual ~ext_theory_simple_justification() {} + ~ext_theory_simple_justification() override {} - virtual bool has_del_eh() const { return !m_params.empty(); } + bool has_del_eh() const override { return !m_params.empty(); } - virtual void del_eh(ast_manager & m) { m_params.reset(); } + void del_eh(ast_manager & m) override { m_params.reset(); } - virtual theory_id get_from_theory() const { return m_th_id; } + theory_id get_from_theory() const override { return m_th_id; } }; class ext_theory_propagation_justification : public ext_theory_simple_justification { @@ -345,9 +345,9 @@ namespace smt { ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params), m_consequent(consequent) {} - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "ext-theory-propagation"; } + char const * get_name() const override { return "ext-theory-propagation"; } }; class ext_theory_conflict_justification : public ext_theory_simple_justification { @@ -357,9 +357,9 @@ namespace smt { unsigned num_params = 0, parameter* params = 0): ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params) {} - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "ext-theory-conflict"; } + char const * get_name() const override { return "ext-theory-conflict"; } }; class ext_theory_eq_propagation_justification : public ext_theory_simple_justification { @@ -374,9 +374,9 @@ namespace smt { unsigned num_params = 0, parameter* params = 0): ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params), m_lhs(lhs), m_rhs(rhs) {} - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "ext-theory-eq-propagation"; } + char const * get_name() const override { return "ext-theory-eq-propagation"; } }; /** @@ -394,19 +394,19 @@ namespace smt { theory_lemma_justification(family_id fid, context & ctx, unsigned num_lits, literal const * lits, unsigned num_params = 0, parameter* params = 0); - virtual ~theory_lemma_justification(); + ~theory_lemma_justification() override; - virtual bool has_del_eh() const { + bool has_del_eh() const override { return true; } - virtual void del_eh(ast_manager & m); + void del_eh(ast_manager & m) override; - virtual void get_antecedents(conflict_resolution & cr) {} + void get_antecedents(conflict_resolution & cr) override {} - virtual proof * mk_proof(conflict_resolution & cr); + proof * mk_proof(conflict_resolution & cr) override; - virtual char const * get_name() const { return "theory-lemma"; } + char const * get_name() const override { return "theory-lemma"; } }; }; diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index f443d671b..447705572 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -566,7 +566,7 @@ namespace smt { } } - virtual expr * eval(expr * n, bool model_completion) { + expr * eval(expr * n, bool model_completion) override { expr * r = 0; if (m_eval_cache[model_completion].find(n, r)) { return r; @@ -1134,24 +1134,24 @@ namespace smt { unsigned m_var_j; public: f_var(func_decl * f, unsigned i, unsigned j):m_f(f), m_arg_i(i), m_var_j(j) {} - virtual ~f_var() {} + ~f_var() override {} - virtual char const * get_kind() const { + char const * get_kind() const override { return "f_var"; } - virtual bool is_equal(qinfo const * qi) const { + bool is_equal(qinfo const * qi) const override { if (qi->get_kind() != get_kind()) return false; f_var const * other = static_cast(qi); return m_f == other->m_f && m_arg_i == other->m_arg_i && m_var_j == other->m_var_j; } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { out << "(" << m_f->get_name() << ":" << m_arg_i << " -> v!" << m_var_j << ")"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { node * n1 = s.get_A_f_i(m_f, m_arg_i); node * n2 = s.get_uvar(q, m_var_j); CTRACE("model_finder", n1->get_sort() != n2->get_sort(), @@ -1170,7 +1170,7 @@ namespace smt { n1->merge(n2); } - virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { + void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) override { node * A_f_i = s.get_A_f_i(m_f, m_arg_i); enode_vector::const_iterator it = ctx->begin_enodes_of(m_f); enode_vector::const_iterator end = ctx->end_enodes_of(m_f); @@ -1193,7 +1193,7 @@ namespace smt { } } - virtual void populate_inst_sets(quantifier * q, func_decl * mhead, ptr_vector & uvar_inst_sets, context * ctx) { + void populate_inst_sets(quantifier * q, func_decl * mhead, ptr_vector & uvar_inst_sets, context * ctx) override { if (m_f != mhead) return; uvar_inst_sets.reserve(m_var_j+1, 0); @@ -1222,31 +1222,31 @@ namespace smt { f_var(f, i, j), m_offset(offset, m) { } - virtual ~f_var_plus_offset() {} + ~f_var_plus_offset() override {} - virtual char const * get_kind() const { + char const * get_kind() const override { return "f_var_plus_offset"; } - virtual bool is_equal(qinfo const * qi) const { + bool is_equal(qinfo const * qi) const override { if (qi->get_kind() != get_kind()) return false; f_var_plus_offset const * other = static_cast(qi); return m_f == other->m_f && m_arg_i == other->m_arg_i && m_var_j == other->m_var_j && m_offset.get() == other->m_offset.get(); } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { out << "(" << m_f->get_name() << ":" << m_arg_i << " - " << mk_bounded_pp(m_offset.get(), m_offset.get_manager()) << " -> v!" << m_var_j << ")"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { // just create the nodes /* node * A_f_i = */ s.get_A_f_i(m_f, m_arg_i); /* node * S_j = */ s.get_uvar(q, m_var_j); } - virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { + void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) override { // S_j is not necessary equal to A_f_i. node * A_f_i = s.get_A_f_i(m_f, m_arg_i)->get_root(); node * S_j = s.get_uvar(q, m_var_j)->get_root(); @@ -1318,7 +1318,7 @@ namespace smt { } } - virtual void populate_inst_sets2(quantifier * q, auf_solver & s, context * ctx) { + void populate_inst_sets2(quantifier * q, auf_solver & s, context * ctx) override { node * A_f_i = s.get_A_f_i(m_f, m_arg_i)->get_root(); node * S_j = s.get_uvar(q, m_var_j)->get_root(); // If A_f_i == S_j, then there is no finite fixpoint, so we do nothing here. @@ -1331,7 +1331,7 @@ namespace smt { } } - virtual void populate_inst_sets(quantifier * q, func_decl * mhead, ptr_vector & uvar_inst_sets, context * ctx) { + void populate_inst_sets(quantifier * q, func_decl * mhead, ptr_vector & uvar_inst_sets, context * ctx) override { // ignored when in macro } @@ -1391,24 +1391,24 @@ namespace smt { public: select_var(ast_manager & m, app * s, unsigned i, unsigned j):m_manager(m), m_array(m), m_select(s), m_arg_i(i), m_var_j(j) {} - virtual ~select_var() {} + ~select_var() override {} - virtual char const * get_kind() const { + char const * get_kind() const override { return "select_var"; } - virtual bool is_equal(qinfo const * qi) const { + bool is_equal(qinfo const * qi) const override { if (qi->get_kind() != get_kind()) return false; select_var const * other = static_cast(qi); return m_select == other->m_select && m_arg_i == other->m_arg_i && m_var_j == other->m_var_j; } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { out << "(" << mk_bounded_pp(m_select, m_manager) << ":" << m_arg_i << " -> v!" << m_var_j << ")"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { ptr_buffer arrays; get_auf_arrays(get_array(), ctx, arrays); TRACE("select_var", @@ -1428,7 +1428,7 @@ namespace smt { } } - virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { + void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) override { ptr_buffer arrays; get_auf_arrays(get_array(), ctx, arrays); for (enode * curr : arrays) { @@ -1461,20 +1461,20 @@ namespace smt { std::swap(m_var_i, m_var_j); } - virtual ~var_pair() {} + ~var_pair() override {} - virtual bool is_equal(qinfo const * qi) const { + bool is_equal(qinfo const * qi) const override { if (qi->get_kind() != get_kind()) return false; var_pair const * other = static_cast(qi); return m_var_i == other->m_var_i && m_var_j == other->m_var_j; } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { out << "(" << get_kind() << ":v!" << m_var_i << ":v!" << m_var_j << ")"; } - virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { + void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) override { // do nothing } }; @@ -1482,9 +1482,9 @@ namespace smt { class x_eq_y : public var_pair { public: x_eq_y(unsigned i, unsigned j):var_pair(i, j) {} - virtual char const * get_kind() const { return "x_eq_y"; } + char const * get_kind() const override { return "x_eq_y"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { node * n1 = s.get_uvar(q, m_var_i); node * n2 = s.get_uvar(q, m_var_j); n1->insert_avoid(n2); @@ -1496,9 +1496,9 @@ namespace smt { class x_neq_y : public var_pair { public: x_neq_y(unsigned i, unsigned j):var_pair(i, j) {} - virtual char const * get_kind() const { return "x_neq_y"; } + char const * get_kind() const override { return "x_neq_y"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { node * n1 = s.get_uvar(q, m_var_i); node * n2 = s.get_uvar(q, m_var_j); n1->merge(n2); @@ -1508,9 +1508,9 @@ namespace smt { class x_leq_y : public var_pair { public: x_leq_y(unsigned i, unsigned j):var_pair(i, j) {} - virtual char const * get_kind() const { return "x_leq_y"; } + char const * get_kind() const override { return "x_leq_y"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { node * n1 = s.get_uvar(q, m_var_i); node * n2 = s.get_uvar(q, m_var_j); n1->merge(n2); @@ -1522,9 +1522,9 @@ namespace smt { class x_sleq_y : public x_leq_y { public: x_sleq_y(unsigned i, unsigned j):x_leq_y(i, j) {} - virtual char const * get_kind() const { return "x_sleq_y"; } + char const * get_kind() const override { return "x_sleq_y"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { node * n1 = s.get_uvar(q, m_var_i); node * n2 = s.get_uvar(q, m_var_j); n1->merge(n2); @@ -1540,16 +1540,16 @@ namespace smt { public: var_expr_pair(ast_manager & m, unsigned i, expr * t): m_var_i(i), m_t(t, m) {} - ~var_expr_pair() {} + ~var_expr_pair() override {} - virtual bool is_equal(qinfo const * qi) const { + bool is_equal(qinfo const * qi) const override { if (qi->get_kind() != get_kind()) return false; var_expr_pair const * other = static_cast(qi); return m_var_i == other->m_var_i && m_t.get() == other->m_t.get(); } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { out << "(" << get_kind() << ":v!" << m_var_i << ":" << mk_bounded_pp(m_t.get(), m_t.get_manager()) << ")"; } }; @@ -1558,14 +1558,14 @@ namespace smt { public: x_eq_t(ast_manager & m, unsigned i, expr * t): var_expr_pair(m, i, t) {} - virtual char const * get_kind() const { return "x_eq_t"; } + char const * get_kind() const override { return "x_eq_t"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { node * n1 = s.get_uvar(q, m_var_i); n1->insert_exception(m_t); } - virtual void populate_inst_sets(quantifier * q, auf_solver & slv, context * ctx) { + void populate_inst_sets(quantifier * q, auf_solver & slv, context * ctx) override { unsigned num_vars = q->get_num_decls(); ast_manager & m = ctx->get_manager(); sort * s = q->get_decl_sort(num_vars - m_var_i - 1); @@ -1589,14 +1589,14 @@ namespace smt { public: x_neq_t(ast_manager & m, unsigned i, expr * t): var_expr_pair(m, i, t) {} - virtual char const * get_kind() const { return "x_neq_t"; } + char const * get_kind() const override { return "x_neq_t"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { // make sure that S_q_i is create. s.get_uvar(q, m_var_i); } - virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { + void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) override { node * S_q_i = s.get_uvar(q, m_var_i); S_q_i->insert(m_t, 0); } @@ -1606,15 +1606,15 @@ namespace smt { public: x_gle_t(ast_manager & m, unsigned i, expr * t): var_expr_pair(m, i, t) {} - virtual char const * get_kind() const { return "x_gle_t"; } + char const * get_kind() const override { return "x_gle_t"; } - virtual void process_auf(quantifier * q, auf_solver & s, context * ctx) { + void process_auf(quantifier * q, auf_solver & s, context * ctx) override { // make sure that S_q_i is create. node * n1 = s.get_uvar(q, m_var_i); n1->set_mono_proj(); } - virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { + void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) override { node * S_q_i = s.get_uvar(q, m_var_i); S_q_i->insert(m_t, 0); } @@ -2524,7 +2524,7 @@ namespace smt { return false; } - virtual bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) { + bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) override { bool removed = false; for (quantifier* q : qs) { if (process(q, qs)) @@ -2957,7 +2957,7 @@ namespace smt { m_fs.reset(); } - virtual bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) { + bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) override { reset(); ptr_vector qcandidates; preprocess(qs, qcandidates, new_qs); @@ -2988,7 +2988,7 @@ namespace smt { m_satisfied(ev_handler(this)) { } - virtual ~hint_solver() { + ~hint_solver() override { reset(); } @@ -3115,7 +3115,7 @@ namespace smt { } } - virtual bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) { + bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) override { obj_map full_macros; func_decl_set cond_macros; obj_hashtable removed; diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index ee133482d..2c86ff9ce 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -159,16 +159,16 @@ namespace smt { app * m_value; public: expr_wrapper_proc(app * v):m_value(v) {} - virtual app * mk_value(model_generator & m, ptr_vector & values) { return m_value; } + app * mk_value(model_generator & m, ptr_vector & values) override { return m_value; } }; class fresh_value_proc : public model_value_proc { extra_fresh_value * m_value; public: fresh_value_proc(extra_fresh_value * v):m_value(v) {} - virtual void get_dependencies(buffer & result) { result.push_back(m_value); } - virtual app * mk_value(model_generator & m, ptr_vector & values) { return to_app(values[0]); } - virtual bool is_fresh() const { return true; } + void get_dependencies(buffer & result) override { result.push_back(m_value); } + 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/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index c6f83c611..108ebfaf2 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -415,10 +415,10 @@ namespace smt { m_active(false) { } - virtual ~default_qm_plugin() { + ~default_qm_plugin() override { } - virtual void set_manager(quantifier_manager & qm) { + void set_manager(quantifier_manager & qm) override { SASSERT(m_qm == 0); m_qm = &qm; m_context = &(qm.get_context()); @@ -434,11 +434,11 @@ namespace smt { m_model_checker->set_qm(qm); } - virtual quantifier_manager_plugin * mk_fresh() { return alloc(default_qm_plugin); } + quantifier_manager_plugin * mk_fresh() override { return alloc(default_qm_plugin); } - virtual bool model_based() const { return m_fparams->m_mbqi; } + bool model_based() const override { return m_fparams->m_mbqi; } - virtual bool mbqi_enabled(quantifier *q) const { + bool mbqi_enabled(quantifier *q) const override { if (!m_fparams->m_mbqi_id) return true; const symbol &s = q->get_qid(); size_t len = strlen(m_fparams->m_mbqi_id); @@ -450,16 +450,16 @@ namespace smt { /* Quantifier id's must begin with the prefix specified by parameter mbqi.id to be instantiated with MBQI. The default value is the empty string, so all quantifiers are instantiated. */ - virtual void add(quantifier * q) { + void add(quantifier * q) override { if (m_fparams->m_mbqi && mbqi_enabled(q)) { m_active = true; m_model_finder->register_quantifier(q); } } - virtual void del(quantifier * q) { } + void del(quantifier * q) override { } - virtual void push() { + void push() override { m_mam->push_scope(); m_lazy_mam->push_scope(); if (m_fparams->m_mbqi) { @@ -467,7 +467,7 @@ namespace smt { } } - virtual void pop(unsigned num_scopes) { + void pop(unsigned num_scopes) override { m_mam->pop_scope(num_scopes); m_lazy_mam->pop_scope(num_scopes); if (m_fparams->m_mbqi) { @@ -475,7 +475,7 @@ namespace smt { } } - virtual void init_search_eh() { + void init_search_eh() override { m_lazy_matching_idx = 0; if (m_fparams->m_mbqi) { m_model_finder->init_search_eh(); @@ -483,7 +483,7 @@ namespace smt { } } - virtual void assign_eh(quantifier * q) { + void assign_eh(quantifier * q) override { m_active = true; ast_manager& m = m_context->get_manager(); if (!m_fparams->m_ematching) { @@ -531,23 +531,23 @@ namespace smt { return m_fparams->m_ematching && !m_qm->empty(); } - virtual void add_eq_eh(enode * e1, enode * e2) { + void add_eq_eh(enode * e1, enode * e2) override { if (use_ematching()) m_mam->add_eq_eh(e1, e2); } - virtual void relevant_eh(enode * e) { + void relevant_eh(enode * e) override { if (use_ematching()) { m_mam->relevant_eh(e, false); m_lazy_mam->relevant_eh(e, true); } } - virtual bool can_propagate() const { + bool can_propagate() const override { return m_mam->has_work(); } - virtual void restart_eh() { + void restart_eh() override { if (m_fparams->m_mbqi) { m_model_finder->restart_eh(); m_model_checker->restart_eh(); @@ -555,17 +555,17 @@ namespace smt { TRACE("mam_stats", m_mam->display(tout);); } - virtual bool is_shared(enode * n) const { + bool is_shared(enode * n) const override { return m_active && (m_mam->is_shared(n) || m_lazy_mam->is_shared(n)); } - virtual void adjust_model(proto_model * m) { + void adjust_model(proto_model * m) override { if (m_fparams->m_mbqi) { m_model_finder->fix_model(m); } } - virtual void propagate() { + void propagate() override { m_mam->match(); if (!m_context->relevancy() && use_ematching()) { ptr_vector::const_iterator it = m_context->begin_enodes(); @@ -585,8 +585,8 @@ namespace smt { } } - virtual quantifier_manager::check_model_result - check_model(proto_model * m, obj_map const & root2value) { + quantifier_manager::check_model_result + check_model(proto_model * m, obj_map const & root2value) override { if (m_fparams->m_mbqi) { IF_VERBOSE(10, verbose_stream() << "(smt.mbqi)\n";); if (m_model_checker->check(m, root2value)) { @@ -599,7 +599,7 @@ namespace smt { return quantifier_manager::UNKNOWN; } - virtual final_check_status final_check_eh(bool full) { + final_check_status final_check_eh(bool full) override { if (!full) { if (m_fparams->m_qi_lazy_instantiation) return final_check_quant(); diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 00457c643..7a2d4167f 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -52,24 +52,24 @@ namespace smt { app * m_parent; public: and_relevancy_eh(app * p):m_parent(p) {} - virtual ~and_relevancy_eh() {} - virtual void operator()(relevancy_propagator & rp); + ~and_relevancy_eh() override {} + void operator()(relevancy_propagator & rp) override; }; class or_relevancy_eh : public relevancy_eh { app * m_parent; public: or_relevancy_eh(app * p):m_parent(p) {} - virtual ~or_relevancy_eh() {} - virtual void operator()(relevancy_propagator & rp); + ~or_relevancy_eh() override {} + void operator()(relevancy_propagator & rp) override; }; class ite_relevancy_eh : public relevancy_eh { app * m_parent; public: ite_relevancy_eh(app * p):m_parent(p) {} - virtual ~ite_relevancy_eh() {} - virtual void operator()(relevancy_propagator & rp); + ~ite_relevancy_eh() override {} + void operator()(relevancy_propagator & rp) override; }; class ite_term_relevancy_eh : public relevancy_eh { @@ -78,8 +78,8 @@ namespace smt { app * m_else_eq; public: ite_term_relevancy_eh(app * p, app * then_eq, app * else_eq):m_parent(p), m_then_eq(then_eq), m_else_eq(else_eq) {} - virtual ~ite_term_relevancy_eh() {} - virtual void operator()(relevancy_propagator & rp); + ~ite_term_relevancy_eh() override {} + void operator()(relevancy_propagator & rp) override; }; relevancy_propagator::relevancy_propagator(context & ctx): @@ -154,7 +154,7 @@ namespace smt { relevancy_propagator(ctx), m_qhead(0), m_relevant_exprs(ctx.get_manager()), m_propagating(false) {} - virtual ~relevancy_propagator_imp() { + ~relevancy_propagator_imp() override { undo_trail(0); } @@ -191,7 +191,7 @@ namespace smt { m_trail.push_back(t); } - virtual void add_handler(expr * source, relevancy_eh * eh) { + void add_handler(expr * source, relevancy_eh * eh) override { if (!enabled()) return; if (is_relevant_core(source)) { @@ -204,7 +204,7 @@ namespace smt { } } - virtual void add_watch(expr * n, bool val, relevancy_eh * eh) { + void add_watch(expr * n, bool val, relevancy_eh * eh) override { if (!enabled()) return; lbool lval = m_context.find_assignment(n); @@ -224,7 +224,7 @@ namespace smt { } } - virtual void add_watch(expr * n, bool val, expr * target) { + void add_watch(expr * n, bool val, expr * target) override { if (!enabled()) return; lbool lval = m_context.find_assignment(n); @@ -244,18 +244,18 @@ namespace smt { bool is_relevant_core(expr * n) const { return m_is_relevant.contains(n); } - virtual bool is_relevant(expr * n) const { + bool is_relevant(expr * n) const override { return !enabled() || is_relevant_core(n); } - virtual void push() { + void push() override { m_scopes.push_back(scope()); scope & s = m_scopes.back(); s.m_relevant_exprs_lim = m_relevant_exprs.size(); s.m_trail_lim = m_trail.size(); } - virtual void pop(unsigned num_scopes) { + void pop(unsigned num_scopes) override { SASSERT(m_context.get_scope_level() == m_scopes.size()); unsigned lvl = m_scopes.size(); SASSERT(num_scopes <= lvl); @@ -325,7 +325,7 @@ namespace smt { \brief Mark the given expression as relevant if it is not already marked. */ - virtual void mark_as_relevant(expr * n) { + void mark_as_relevant(expr * n) override { if (!enabled()) return; if (!is_relevant_core(n)) { @@ -450,7 +450,7 @@ namespace smt { [m_qhead, m_relevant_exprs.size()) in the stack of relevant expressions. */ - virtual void propagate() { + void propagate() override { if (m_propagating) { return; } @@ -494,11 +494,11 @@ namespace smt { } } - virtual bool can_propagate() const { + bool can_propagate() const override { return m_qhead < m_relevant_exprs.size(); } - virtual void assign_eh(expr * n, bool val) { + void assign_eh(expr * n, bool val) override { if (!enabled()) return; ast_manager & m = get_manager(); @@ -516,7 +516,7 @@ namespace smt { } } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { if (enabled() && !m_relevant_exprs.empty()) { out << "relevant exprs:\n"; for (unsigned i = 0; i < m_relevant_exprs.size(); i++) { diff --git a/src/smt/smt_relevancy.h b/src/smt/smt_relevancy.h index 75019b110..edaa237b8 100644 --- a/src/smt/smt_relevancy.h +++ b/src/smt/smt_relevancy.h @@ -50,8 +50,8 @@ namespace smt { expr * m_target; public: simple_relevancy_eh(expr * t):m_target(t) {} - virtual ~simple_relevancy_eh() {} - virtual void operator()(relevancy_propagator & rp); + ~simple_relevancy_eh() override {} + void operator()(relevancy_propagator & rp) override; }; /** @@ -63,8 +63,8 @@ namespace smt { expr * m_target; public: pair_relevancy_eh(expr * s1, expr * s2, expr * t):m_source1(s1), m_source2(s2), m_target(t) {} - virtual ~pair_relevancy_eh() {} - virtual void operator()(relevancy_propagator & rp); + ~pair_relevancy_eh() override {} + void operator()(relevancy_propagator & rp) override; }; /** diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 1f9ad3ef7..b805253d8 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -55,7 +55,7 @@ namespace smt { updt_params(p); } - virtual solver * translate(ast_manager & m, params_ref const & p) { + solver * translate(ast_manager & m, params_ref const & p) override { ast_translation translator(get_manager(), m); smt_solver * result = alloc(smt_solver, m, p, m_logic); @@ -68,11 +68,11 @@ namespace smt { return result; } - virtual ~smt_solver() { + ~smt_solver() override { dec_ref_values(get_manager(), m_name2assertion); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { solver::updt_params(p); m_smt_params.updt_params(p); m_context.updt_params(p); @@ -82,28 +82,28 @@ namespace smt { m_core_extend_nonlocal_patterns = smth.core_extend_nonlocal_patterns(); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_context.collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { m_context.collect_statistics(st); } - virtual lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) { + lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) override { expr_ref_vector unfixed(m_context.m()); return m_context.get_consequences(assumptions, vars, conseq, unfixed); } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { return m_context.find_mutexes(vars, mutexes); } - virtual void assert_expr(expr * t) { + void assert_expr(expr * t) override { m_context.assert_expr(t); } - virtual void assert_expr(expr * t, expr * a) { + void assert_expr(expr * t, expr * a) override { if (m_name2assertion.contains(a)) { throw default_exception("named assertion defined twice"); } @@ -112,11 +112,11 @@ namespace smt { m_name2assertion.insert(a, t); } - virtual void push_core() { + void push_core() override { m_context.push(); } - virtual void pop_core(unsigned n) { + void pop_core(unsigned n) override { unsigned cur_sz = m_assumptions.size(); if (n > 0 && cur_sz > 0) { unsigned lvl = m_scopes.size(); @@ -135,7 +135,7 @@ namespace smt { m_context.pop(n); } - virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { TRACE("solver_na2as", tout << "smt_solver::check_sat_core: " << num_assumptions << "\n";); return m_context.check(num_assumptions, assumptions); } @@ -154,7 +154,7 @@ namespace smt { } }; - virtual void get_unsat_core(ptr_vector & r) { + void get_unsat_core(ptr_vector & r) override { unsigned sz = m_context.get_unsat_core_size(); for (unsigned i = 0; i < sz; i++) { r.push_back(m_context.get_unsat_core_expr(i)); @@ -177,40 +177,40 @@ namespace smt { add_nonlocal_pattern_literals_to_core(r); } - virtual void get_model(model_ref & m) { + void get_model(model_ref & m) override { m_context.get_model(m); } - virtual proof * get_proof() { + proof * get_proof() override { return m_context.get_proof(); } - virtual std::string reason_unknown() const { + std::string reason_unknown() const override { return m_context.last_failure_as_string(); } - virtual void set_reason_unknown(char const* msg) { + void set_reason_unknown(char const* msg) override { m_context.set_reason_unknown(msg); } - virtual void get_labels(svector & r) { + void get_labels(svector & r) override { buffer tmp; m_context.get_relevant_labels(0, tmp); r.append(tmp.size(), tmp.c_ptr()); } - virtual ast_manager & get_manager() const { return m_context.m(); } + ast_manager & get_manager() const override { return m_context.m(); } - virtual void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { m_callback = callback; m_context.set_progress_callback(callback); } - virtual unsigned get_num_assertions() const { + unsigned get_num_assertions() const override { return m_context.size(); } - virtual expr * get_assertion(unsigned idx) const { + expr * get_assertion(unsigned idx) const override { SASSERT(idx < get_num_assertions()); return m_context.get_formula(idx); } @@ -368,7 +368,7 @@ solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & log class smt_solver_factory : public solver_factory { public: - virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) { + solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) override { return mk_smt_solver(m, p, logic); } }; diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index edc4b4ff5..98de6a79b 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -43,11 +43,11 @@ public: m_fn = m.mk_func_decl(symbol(0xbeef101), i_sort, m.mk_bool_sort()); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(ctx_solver_simplify_tactic, m, m_params); } - virtual ~ctx_solver_simplify_tactic() { + ~ctx_solver_simplify_tactic() override { obj_map::iterator it = m_fns.begin(), end = m_fns.end(); for (; it != end; ++it) { m.dec_ref(it->m_value); @@ -55,33 +55,32 @@ public: m_fns.reset(); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_solver.updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { m_solver.collect_param_descrs(r); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.update("solver-simplify-steps", m_num_steps); } - virtual void reset_statistics() { m_num_steps = 0; } + void reset_statistics() override { m_num_steps = 0; } - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { - + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { mc = 0; pc = 0; core = 0; reduce(*(in.get())); in->inc_depth(); result.push_back(in.get()); } - virtual void cleanup() { + void cleanup() override { reset_statistics(); m_solver.reset(); } diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 57ac7b34b..af717c807 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -53,11 +53,11 @@ public: TRACE("smt_tactic", tout << "p: " << p << "\n";); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(smt_tactic, m_params_ref); } - virtual ~smt_tactic() { + ~smt_tactic() override { SASSERT(m_ctx == 0); } @@ -74,7 +74,7 @@ public: m_fail_if_inconclusive = p.get_bool("fail_if_inconclusive", true); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { TRACE("smt_tactic", tout << "updt_params: " << p << "\n";); updt_params_core(p); fparams().updt_params(p); @@ -86,7 +86,7 @@ public: SASSERT(p.get_bool("auto_config", fparams().m_auto_config) == fparams().m_auto_config); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("candidate_models", CPK_BOOL, "(default: false) create candidate models even when quantifier or theory reasoning is incomplete."); r.insert("fail_if_inconclusive", CPK_BOOL, "(default: true) fail if found unsat (sat) for under (over) approximated goal."); smt_params_helper::collect_param_descrs(r); @@ -94,25 +94,25 @@ public: } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { if (m_ctx) m_ctx->collect_statistics(st); // ctx is still running... else st.copy(m_stats); } - virtual void cleanup() { + void cleanup() override { } - virtual void reset_statistics() { + void reset_statistics() override { m_stats.reset(); } - virtual void set_logic(symbol const & l) { + void set_logic(symbol const & l) override { m_logic = l; } - virtual void set_progress_callback(progress_callback * callback) { + void set_progress_callback(progress_callback * callback) override { m_callback = callback; } @@ -144,11 +144,11 @@ public: }; - virtual void operator()(goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { + void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) override { try { IF_VERBOSE(10, verbose_stream() << "(smt.tactic start)\n";); mc = 0; pc = 0; core = 0; diff --git a/src/smt/tactic/unit_subsumption_tactic.cpp b/src/smt/tactic/unit_subsumption_tactic.cpp index 68a34cea8..3adf1cb51 100644 --- a/src/smt/tactic/unit_subsumption_tactic.cpp +++ b/src/smt/tactic/unit_subsumption_tactic.cpp @@ -37,22 +37,22 @@ struct unit_subsumption_tactic : public tactic { m_clauses(m) { } - void cleanup() {} + void cleanup() override {} - virtual void operator()(/* in */ goal_ref const & in, - /* out */ goal_ref_buffer & result, - /* out */ model_converter_ref & mc, - /* out */ proof_converter_ref & pc, - /* out */ expr_dependency_ref & core) { + void operator()(/* in */ goal_ref const & in, + /* out */ goal_ref_buffer & result, + /* out */ model_converter_ref & mc, + /* out */ proof_converter_ref & pc, + /* out */ expr_dependency_ref & core) override { reduce_core(in, result); } - virtual void updt_params(params_ref const& p) { + void updt_params(params_ref const& p) override { m_params = p; // m_context.updt_params(p); does not exist. } - virtual tactic* translate(ast_manager& m) { + tactic* translate(ast_manager& m) override { return alloc(unit_subsumption_tactic, m, m_params); } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 6794ca3ac..98bbefd42 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -306,16 +306,16 @@ namespace smt { public: atom(bool_var bv, theory_var v, inf_numeral const & k, atom_kind kind); atom_kind get_atom_kind() const { return static_cast(m_atom_kind); } - virtual ~atom() {} + ~atom() override {} inline inf_numeral const & get_k() const { return m_k; } bool_var get_bool_var() const { return m_bvar; } bool is_true() const { return m_is_true; } void assign_eh(bool is_true, inf_numeral const & epsilon); - virtual bool has_justification() const { return true; } - virtual void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) { + bool has_justification() const override { return true; } + void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) override { a.push_lit(literal(get_bool_var(), !m_is_true), coeff, proofs_enabled); } - virtual void display(theory_arith const& th, std::ostream& out) const; + void display(theory_arith const& th, std::ostream& out) const override; }; class eq_bound : public bound { @@ -328,13 +328,13 @@ namespace smt { m_rhs(rhs) { SASSERT(m_lhs->get_root() == m_rhs->get_root()); } - virtual ~eq_bound() {} - virtual bool has_justification() const { return true; } - virtual void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) { + ~eq_bound() override {} + bool has_justification() const override { return true; } + void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) override { SASSERT(m_lhs->get_root() == m_rhs->get_root()); a.push_eq(enode_pair(m_lhs, m_rhs), coeff, proofs_enabled); } - virtual void display(theory_arith const& th, std::ostream& out) const; + void display(theory_arith const& th, std::ostream& out) const override; }; class derived_bound : public bound { @@ -344,14 +344,14 @@ namespace smt { friend class theory_arith; public: derived_bound(theory_var v, inf_numeral const & val, bound_kind k):bound(v, val, k, false) {} - virtual ~derived_bound() {} + ~derived_bound() override {} literal_vector const& lits() const { return m_lits; } eq_vector const& eqs() const { return m_eqs; } - virtual bool has_justification() const { return true; } - virtual void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled); + bool has_justification() const override { return true; } + void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) override; virtual void push_lit(literal l, numeral const&) { m_lits.push_back(l); } virtual void push_eq(enode_pair const& p, numeral const&) { m_eqs.push_back(p); } - virtual void display(theory_arith const& th, std::ostream& out) const; + void display(theory_arith const& th, std::ostream& out) const override; }; @@ -361,12 +361,12 @@ namespace smt { friend class theory_arith; public: justified_derived_bound(theory_var v, inf_numeral const & val, bound_kind k):derived_bound(v, val, k) {} - virtual ~justified_derived_bound() {} - virtual bool has_justification() const { return true; } - virtual void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled); - virtual void push_lit(literal l, numeral const& coeff); + ~justified_derived_bound() override {} + bool has_justification() const override { return true; } + void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled) override; + void push_lit(literal l, numeral const& coeff) override; - virtual void push_eq(enode_pair const& p, numeral const& coeff); + void push_eq(enode_pair const& p, numeral const& coeff) override; }; typedef int_hashtable > literal_idx_set; @@ -510,7 +510,7 @@ namespace smt { typedef int_hashtable var_value_table; var_value_table m_var_value_table; - virtual theory_var mk_var(enode * n); + theory_var mk_var(enode * n) override; void found_unsupported_op(app * n); void found_underspecified_op(app * n); @@ -635,24 +635,24 @@ namespace smt { struct compare_atoms { bool operator()(atom* a1, atom* a2) const { return a1->get_k() < a2->get_k(); } }; - virtual bool default_internalizer() const { return false; } - virtual bool internalize_atom(app * n, bool gate_ctx); - virtual bool internalize_term(app * term); - virtual void internalize_eq_eh(app * atom, bool_var v); - virtual void apply_sort_cnstr(enode * n, sort * s); + bool default_internalizer() const override { return false; } + bool internalize_atom(app * n, bool gate_ctx) override; + bool internalize_term(app * term) override; + void internalize_eq_eh(app * atom, bool_var v) override; + void apply_sort_cnstr(enode * n, sort * s) override; - virtual void assign_eh(bool_var v, bool is_true); - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual bool use_diseqs() const; - virtual void new_diseq_eh(theory_var v1, theory_var v2); + void assign_eh(bool_var v, bool is_true) override; + void new_eq_eh(theory_var v1, theory_var v2) override; + bool use_diseqs() const override; + void new_diseq_eh(theory_var v1, theory_var v2) override; - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; - virtual void relevant_eh(app * n); + void relevant_eh(app * n) override; - virtual void restart_eh(); - virtual void init_search_eh(); + void restart_eh() override; + void init_search_eh() override; /** \brief True if the assignment may be changed during final check. assume_eqs, check_int_feasibility, @@ -669,18 +669,18 @@ namespace smt { */ bool m_liberal_final_check; final_check_status final_check_core(); - virtual final_check_status final_check_eh(); + final_check_status final_check_eh() override; - virtual bool can_propagate(); - virtual void propagate(); + bool can_propagate() override; + void propagate() override; bool propagate_core(); void failed(); - virtual void flush_eh(); - virtual void reset_eh(); + void flush_eh() override; + void reset_eh() override; - virtual bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const; + bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override; // ----------------------------------- // @@ -867,7 +867,7 @@ namespace smt { void propagate_cheap_eq(unsigned rid); void propagate_eq_to_core(theory_var x, theory_var y, antecedents& antecedents); - virtual bool is_shared(theory_var v) const; + bool is_shared(theory_var v) const override; // ----------------------------------- // @@ -909,7 +909,7 @@ namespace smt { /** \brief See comment in theory::mk_eq_atom */ - virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return m_util.mk_eq(lhs, rhs); } + app * mk_eq_atom(expr * lhs, expr * rhs) override { return m_util.mk_eq(lhs, rhs); } // ----------------------------------- // @@ -1039,13 +1039,13 @@ namespace smt { // ----------------------------------- public: theory_arith(ast_manager & m, theory_arith_params & params); - virtual ~theory_arith(); + ~theory_arith() override; - virtual theory * mk_fresh(context * new_ctx); + theory * mk_fresh(context * new_ctx) override; - virtual void setup(); + void setup() override; - virtual char const * get_name() const { return "arithmetic"; } + char const * get_name() const override { return "arithmetic"; } // ----------------------------------- // @@ -1058,15 +1058,15 @@ namespace smt { void compute_epsilon(); void refine_epsilon(); - virtual void init_model(model_generator & m); - virtual model_value_proc * mk_value(enode * n, model_generator & mg); + void init_model(model_generator & m) override; + model_value_proc * mk_value(enode * n, model_generator & mg) override; // ----------------------------------- // // Model checker // // ----------------------------------- - virtual bool get_value(enode * n, expr_ref & r); + bool get_value(enode * n, expr_ref & r) override; bool get_lower(enode* n, expr_ref& r); bool get_upper(enode* n, expr_ref& r); @@ -1078,9 +1078,9 @@ namespace smt { // Optimization // // ----------------------------------- - virtual inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared); - virtual inf_eps_rational value(theory_var v); - virtual theory_var add_objective(app* term); + inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared) override; + inf_eps_rational value(theory_var v) override; + theory_var add_objective(app* term) override; expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); void enable_record_conflict(expr* bound); void record_conflict(unsigned num_lits, literal const * lits, @@ -1102,8 +1102,8 @@ namespace smt { // // ----------------------------------- public: - virtual void collect_statistics(::statistics & st) const; - virtual void display(std::ostream & out) const; + void collect_statistics(::statistics & st) const override; + void display(std::ostream & out) const override; protected: void display_row(std::ostream & out, unsigned r_id, bool compact = true) const; void display_row(std::ostream & out, row const & r, bool compact = true) const; diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 4f15a6156..593b9c56b 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -472,7 +472,7 @@ namespace smt { bounds.num_params(), bounds.params("gomory-cut")) { } // Remark: the assignment must be propagated back to arith - virtual theory_id get_from_theory() const { return null_theory_id; } + theory_id get_from_theory() const override { return null_theory_id; } }; /** diff --git a/src/smt/theory_array.h b/src/smt/theory_array.h index 3a013cf73..26d59c7bf 100644 --- a/src/smt/theory_array.h +++ b/src/smt/theory_array.h @@ -55,19 +55,19 @@ namespace smt { th_trail_stack m_trail_stack; unsigned m_final_check_idx; - virtual void init(context * ctx); - virtual theory_var mk_var(enode * n); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term); - virtual void apply_sort_cnstr(enode * n, sort * s); - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual void new_diseq_eh(theory_var v1, theory_var v2); - virtual void relevant_eh(app * n); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual final_check_status final_check_eh(); - virtual void reset_eh(); - virtual void init_search_eh() { m_final_check_idx = 0; } + void init(context * ctx) override; + theory_var mk_var(enode * n) override; + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override; + void apply_sort_cnstr(enode * n, sort * s) override; + void new_eq_eh(theory_var v1, theory_var v2) override; + void new_diseq_eh(theory_var v1, theory_var v2) override; + void relevant_eh(app * n) override; + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + final_check_status final_check_eh() override; + void reset_eh() override; + void init_search_eh() override { m_final_check_idx = 0; } virtual void set_prop_upward(theory_var v); virtual void set_prop_upward(enode* n); @@ -96,15 +96,15 @@ namespace smt { static void display_ids(std::ostream & out, unsigned n, enode * const * v); public: theory_array(ast_manager & m, theory_array_params & params); - virtual ~theory_array(); + ~theory_array() override; - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_array, new_ctx->get_manager(), new_ctx->get_fparams()); } + theory * mk_fresh(context * new_ctx) override { return alloc(theory_array, new_ctx->get_manager(), new_ctx->get_fparams()); } - virtual char const * get_name() const { return "array"; } + char const * get_name() const override { return "array"; } virtual void display_var(std::ostream & out, theory_var v) const; - virtual void display(std::ostream & out) const; - virtual void collect_statistics(::statistics & st) const; + void display(std::ostream & out) const override; + void collect_statistics(::statistics & st) const override; th_trail_stack & get_trail_stack() { return m_trail_stack; } virtual void merge_eh(theory_var v1, theory_var v2, theory_var, theory_var); static void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) {} diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 472053fdc..0aba7c2f2 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -828,7 +828,7 @@ namespace smt { m_unspecified_else(true) { } - virtual ~array_value_proc() {} + ~array_value_proc() override {} void add_entry(unsigned num_args, enode * const * args, enode * value) { SASSERT(num_args > 0); @@ -840,11 +840,11 @@ namespace smt { m_dependencies.push_back(model_value_dependency(value)); } - virtual void get_dependencies(buffer & result) { + void get_dependencies(buffer & result) override { result.append(m_dependencies.size(), m_dependencies.c_ptr()); } - virtual app * mk_value(model_generator & mg, ptr_vector & values) { + app * mk_value(model_generator & mg, ptr_vector & values) override { // values must have size = m_num_entries * (m_dim + 1) + ((m_else || m_unspecified_else) ? 0 : 1) // an array value is a lookup table + else_value // each entry has m_dim indexes that map to a value. diff --git a/src/smt/theory_array_base.h b/src/smt/theory_array_base.h index 197ad9d2f..730c02f94 100644 --- a/src/smt/theory_array_base.h +++ b/src/smt/theory_array_base.h @@ -123,15 +123,15 @@ namespace smt { // // // -------------------------------------------------- - virtual bool is_shared(theory_var v) const; + bool is_shared(theory_var v) const override; void collect_shared_vars(sbuffer & result); unsigned mk_interface_eqs(); - virtual bool can_propagate(); - virtual void propagate(); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual void reset_eh(); + bool can_propagate() override; + void propagate() override; + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + void reset_eh() override; void reset_queues(); // ----------------------------------- @@ -177,7 +177,7 @@ namespace smt { void set_default(theory_var v, enode* n); enode* get_default(theory_var v); - virtual void init_model(model_generator & m); + void init_model(model_generator & m) override; bool is_unspecified_default_ok() const; void collect_defaults(); void collect_selects(); @@ -185,12 +185,12 @@ namespace smt { void propagate_selects_to_store_parents(enode * r, enode_pair_vector & todo); void propagate_selects(); select_set * get_select_set(enode * n); - virtual void finalize_model(model_generator & m); - virtual model_value_proc * mk_value(enode * n, model_generator & m); + void finalize_model(model_generator & m) override; + model_value_proc * mk_value(enode * n, model_generator & m) override; public: theory_array_base(ast_manager & m); - virtual ~theory_array_base() { restore_sorts(0); } + ~theory_array_base() override { restore_sorts(0); } }; }; diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index 2cad3acbd..3216b4286 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -42,29 +42,29 @@ namespace smt { protected: //virtual final_check_status final_check_eh(); - virtual void reset_eh(); + void reset_eh() override; - virtual void set_prop_upward(theory_var v); - virtual void set_prop_upward(enode* n); - virtual void set_prop_upward(theory_var v, var_data* d); - virtual unsigned get_lambda_equiv_size(theory_var v, var_data* d); + void set_prop_upward(theory_var v) override; + void set_prop_upward(enode* n) override; + void set_prop_upward(theory_var v, var_data* d) override; + unsigned get_lambda_equiv_size(theory_var v, var_data* d) override; - virtual bool internalize_term(app * term); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual void pop_scope_eh(unsigned num_scopes); - virtual theory_var mk_var(enode * n); - virtual void relevant_eh(app * n); + bool internalize_term(app * term) override; + bool internalize_atom(app * atom, bool gate_ctx) override; + void pop_scope_eh(unsigned num_scopes) override; + theory_var mk_var(enode * n) override; + void relevant_eh(app * n) override; void add_const(theory_var v, enode* c); void add_map(theory_var v, enode* s); void add_parent_map(theory_var v, enode* s); void add_as_array(theory_var v, enode* arr); - virtual void add_parent_select(theory_var v, enode * s); + void add_parent_select(theory_var v, enode * s) override; void add_parent_default(theory_var v); - virtual final_check_status assert_delayed_axioms(); + final_check_status assert_delayed_axioms() override; bool instantiate_default_const_axiom(enode* cnst); bool instantiate_default_store_axiom(enode* store); @@ -87,14 +87,14 @@ namespace smt { public: theory_array_full(ast_manager & m, theory_array_params & params); - virtual ~theory_array_full(); + ~theory_array_full() override; - virtual theory * mk_fresh(context * new_ctx); + theory * mk_fresh(context * new_ctx) override; - virtual void merge_eh(theory_var v1, theory_var v2, theory_var, theory_var); - virtual void display_var(std::ostream & out, theory_var v) const; - virtual void collect_statistics(::statistics & st) const; - virtual void init(context* ctx) { + void merge_eh(theory_var v1, theory_var v2, theory_var, theory_var) override; + void display_var(std::ostream & out, theory_var v) const override; + void collect_statistics(::statistics & st) const override; + void init(context* ctx) override { // the parent class is theory_array. // theory::init(ctx); theory_array::init(ctx); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index ec3913415..0f5c235f3 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -65,7 +65,7 @@ namespace smt { bool_var m_var; public: mk_atom_trail(bool_var v):m_var(v) {} - virtual void undo(theory_bv & th) { + void undo(theory_bv & th) override { theory_bv::atom * a = th.get_bv2a(m_var); a->~atom(); th.erase_bv2a(m_var); @@ -213,7 +213,7 @@ namespace smt { theory_bv::bit_atom * m_atom; public: add_var_pos_trail(theory_bv::bit_atom * a):m_atom(a) {} - virtual void undo(theory_bv & th) { + void undo(theory_bv & th) override { SASSERT(m_atom->m_occs); m_atom->m_occs = m_atom->m_occs->m_next; } @@ -389,12 +389,12 @@ namespace smt { m_th(th), m_var1(v1), m_var2(v2) { } - virtual void get_antecedents(conflict_resolution & cr) { + void get_antecedents(conflict_resolution & cr) override { mark_bits(cr, m_th.m_bits[m_var1]); mark_bits(cr, m_th.m_bits[m_var2]); } - virtual proof * mk_proof(conflict_resolution & cr) { + proof * mk_proof(conflict_resolution & cr) override { ptr_buffer prs; context & ctx = cr.get_context(); bool visited = true; @@ -414,11 +414,11 @@ namespace smt { return m.mk_th_lemma(get_from_theory(), fact, prs.size(), prs.c_ptr()); } - virtual theory_id get_from_theory() const { + theory_id get_from_theory() const override { return m_th.get_id(); } - virtual char const * get_name() const { return "bv-fixed-eq"; } + char const * get_name() const override { return "bv-fixed-eq"; } }; @@ -1510,13 +1510,13 @@ namespace smt { bit_eq_justification(theory_id th_id, enode * v1, enode * v2, literal c, literal a): m_v1(v1), m_v2(v2), m_th_id(th_id), m_consequent(c), m_antecedent(a) {} - virtual void get_antecedents(conflict_resolution & cr) { + void get_antecedents(conflict_resolution & cr) override { cr.mark_eq(m_v1, m_v2); if (m_antecedent.var() != true_bool_var) cr.mark_literal(m_antecedent); } - virtual proof * mk_proof(conflict_resolution & cr) { + proof * mk_proof(conflict_resolution & cr) override { bool visited = true; ptr_buffer prs; proof * pr = cr.get_proof(m_v1, m_v2); @@ -1540,11 +1540,11 @@ namespace smt { return m.mk_th_lemma(get_from_theory(), fact, prs.size(), prs.c_ptr()); } - virtual theory_id get_from_theory() const { + theory_id get_from_theory() const override { return m_th_id; } - virtual char const * get_name() const { return "bv-bit-eq"; } + char const * get_name() const override { return "bv-bit-eq"; } }; inline justification * theory_bv::mk_bit_eq_justification(theory_var v1, theory_var v2, literal consequent, literal antecedent) { diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index c35078ace..ca3338cb7 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -58,16 +58,16 @@ namespace smt { struct bit_atom : public atom { var_pos_occ * m_occs; bit_atom():m_occs(0) {} - virtual ~bit_atom() {} - virtual bool is_bit() const { return true; } + ~bit_atom() override {} + bool is_bit() const override { return true; } }; struct le_atom : public atom { literal m_var; literal m_def; le_atom(literal v, literal d):m_var(v), m_def(d) {} - virtual ~le_atom() {} - virtual bool is_bit() const { return false; } + ~le_atom() override {} + bool is_bit() const override { return false; } }; /** @@ -216,21 +216,21 @@ namespace smt { void assert_bv2int_axiom(app* n); protected: - virtual void init(context * ctx); - virtual theory_var mk_var(enode * n); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term); - virtual void apply_sort_cnstr(enode * n, sort * s); - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual void new_diseq_eh(theory_var v1, theory_var v2); + void init(context * ctx) override; + theory_var mk_var(enode * n) override; + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override; + void apply_sort_cnstr(enode * n, sort * s) override; + void new_eq_eh(theory_var v1, theory_var v2) override; + void new_diseq_eh(theory_var v1, theory_var v2) override; virtual void expand_diseq(theory_var v1, theory_var v2); - virtual void assign_eh(bool_var v, bool is_true); - virtual void relevant_eh(app * n); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual final_check_status final_check_eh(); - virtual void reset_eh(); - virtual bool include_func_interp(func_decl* f); + void assign_eh(bool_var v, bool is_true) override; + void relevant_eh(app * n) override; + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + final_check_status final_check_eh() override; + void reset_eh() override; + bool include_func_interp(func_decl* f) override; svector m_merge_aux[2]; //!< auxiliary vector used in merge_zero_one_bits bool merge_zero_one_bits(theory_var r1, theory_var r2); @@ -240,16 +240,16 @@ namespace smt { // // ----------------------------------- bv_factory * m_factory; - virtual void init_model(model_generator & m); - virtual model_value_proc * mk_value(enode * n, model_generator & mg); + void init_model(model_generator & m) override; + model_value_proc * mk_value(enode * n, model_generator & mg) override; public: theory_bv(ast_manager & m, theory_bv_params const & params, bit_blaster_params const & bb_params); - virtual ~theory_bv(); + ~theory_bv() override; - virtual theory * mk_fresh(context * new_ctx); + theory * mk_fresh(context * new_ctx) override; - virtual char const * get_name() const { return "bit-vector"; } + char const * get_name() const override { return "bit-vector"; } th_trail_stack & get_trail_stack() { return m_trail_stack; } void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2); @@ -259,8 +259,8 @@ namespace smt { void display_var(std::ostream & out, theory_var v) const; void display_bit_atom(std::ostream & out, bool_var v, bit_atom const * a) const; void display_atoms(std::ostream & out) const; - virtual void display(std::ostream & out) const; - virtual void collect_statistics(::statistics & st) const; + void display(std::ostream & out) const override; + void collect_statistics(::statistics & st) const override; bool get_fixed_value(app* x, numeral & result) const; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index bbed6840d..f9422ee8a 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -33,7 +33,7 @@ namespace smt { ext_theory_eq_propagation_justification(fid, r, 1, &antecedent, 0, 0, lhs, rhs) { } // Remark: the assignment must be propagated back to the datatype theory. - virtual theory_id get_from_theory() const { return null_theory_id; } + theory_id get_from_theory() const override { return null_theory_id; } }; @@ -551,11 +551,11 @@ namespace smt { public: datatype_value_proc(func_decl * d):m_constructor(d) {} void add_dependency(enode * n) { m_dependencies.push_back(model_value_dependency(n)); } - virtual ~datatype_value_proc() {} - virtual void get_dependencies(buffer & result) { + ~datatype_value_proc() override {} + void get_dependencies(buffer & result) override { result.append(m_dependencies.size(), m_dependencies.c_ptr()); } - virtual app * mk_value(model_generator & mg, ptr_vector & values) { + app * mk_value(model_generator & mg, ptr_vector & values) override { SASSERT(values.size() == m_dependencies.size()); return mg.get_manager().mk_app(m_constructor, values.size(), values.c_ptr()); } diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 20fa371fa..3329c71cb 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -84,35 +84,35 @@ namespace smt { void display_var(std::ostream & out, theory_var v) const; protected: - virtual theory_var mk_var(enode * n); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term); - virtual void apply_sort_cnstr(enode * n, sort * s); - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual bool use_diseqs() const; - virtual void new_diseq_eh(theory_var v1, theory_var v2); - virtual void assign_eh(bool_var v, bool is_true); - virtual void relevant_eh(app * n); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual final_check_status final_check_eh(); - virtual void reset_eh(); - virtual void restart_eh() { m_util.reset(); } - virtual bool is_shared(theory_var v) const; + theory_var mk_var(enode * n) override; + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override; + void apply_sort_cnstr(enode * n, sort * s) override; + void new_eq_eh(theory_var v1, theory_var v2) override; + bool use_diseqs() const override; + void new_diseq_eh(theory_var v1, theory_var v2) override; + void assign_eh(bool_var v, bool is_true) override; + void relevant_eh(app * n) override; + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + final_check_status final_check_eh() override; + void reset_eh() override; + void restart_eh() override { m_util.reset(); } + bool is_shared(theory_var v) const override; public: theory_datatype(ast_manager & m, theory_datatype_params & p); - virtual ~theory_datatype(); - virtual theory * mk_fresh(context * new_ctx); - virtual void display(std::ostream & out) const; - virtual void collect_statistics(::statistics & st) const; - virtual void init_model(model_generator & m); - virtual model_value_proc * mk_value(enode * n, model_generator & m); + ~theory_datatype() override; + theory * mk_fresh(context * new_ctx) override; + void display(std::ostream & out) const override; + void collect_statistics(::statistics & st) const override; + void init_model(model_generator & m) override; + model_value_proc * mk_value(enode * n, model_generator & m) override; th_trail_stack & get_trail_stack() { return m_trail_stack; } virtual void merge_eh(theory_var v1, theory_var v2, theory_var, theory_var); static void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) {} void unmerge_eh(theory_var v1, theory_var v2); - virtual char const * get_name() const { return "datatype"; } - virtual bool include_func_interp(func_decl* f); + char const * get_name() const override { return "datatype"; } + bool include_func_interp(func_decl* f) override; }; diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index 980830447..dbf6a13a9 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -182,7 +182,7 @@ namespace smt { return false; } app * mk_zero_for(expr * n); - theory_var mk_var(enode * n); + theory_var mk_var(enode * n) override; theory_var internalize_term_core(app * n); void found_non_diff_logic_expr(expr * n); bool is_connected(theory_var source, theory_var target) const { return m_matrix[source][target].m_edge_id != null_edge_id; } @@ -214,38 +214,38 @@ namespace smt { // Internalization // // ----------------------------------- - virtual bool internalize_atom(app * n, bool gate_ctx); - virtual bool internalize_term(app * term); - virtual void internalize_eq_eh(app * atom, bool_var v); - virtual void apply_sort_cnstr(enode * n, sort * s); + bool internalize_atom(app * n, bool gate_ctx) override; + bool internalize_term(app * term) override; + void internalize_eq_eh(app * atom, bool_var v) override; + void apply_sort_cnstr(enode * n, sort * s) override; - virtual void assign_eh(bool_var v, bool is_true); - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual bool use_diseqs() const; - virtual void new_diseq_eh(theory_var v1, theory_var v2); + void assign_eh(bool_var v, bool is_true) override; + void new_eq_eh(theory_var v1, theory_var v2) override; + bool use_diseqs() const override; + void new_diseq_eh(theory_var v1, theory_var v2) override; - virtual void conflict_resolution_eh(app * atom, bool_var v); + void conflict_resolution_eh(app * atom, bool_var v) override; - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; - virtual void restart_eh(); - virtual void init_search_eh(); - virtual final_check_status final_check_eh(); + void restart_eh() override; + void init_search_eh() override; + final_check_status final_check_eh() override; - virtual bool can_propagate(); - virtual void propagate(); + bool can_propagate() override; + void propagate() override; - virtual void flush_eh(); - virtual void reset_eh(); + void flush_eh() override; + void reset_eh() override; bool dump_lemmas() const { return m_params.m_arith_dump_lemmas; } - virtual bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const; + bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override; - virtual void display(std::ostream & out) const; + void display(std::ostream & out) const override; virtual void display_atom(std::ostream & out, atom * a) const; - virtual void collect_statistics(::statistics & st) const; + void collect_statistics(::statistics & st) const override; // ----------------------------------- // @@ -258,8 +258,8 @@ namespace smt { void compute_epsilon(); void fix_zero(); - virtual void init_model(model_generator & m); - virtual model_value_proc * mk_value(enode * n, model_generator & mg); + void init_model(model_generator & m) override; + model_value_proc * mk_value(enode * n, model_generator & mg) override; // ----------------------------------- // @@ -267,9 +267,9 @@ namespace smt { // // ----------------------------------- - virtual inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared); - virtual inf_eps_rational value(theory_var v); - virtual theory_var add_objective(app* term); + inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared) override; + inf_eps_rational value(theory_var v) override; + theory_var add_objective(app* term) override; virtual expr_ref mk_gt(theory_var v, inf_eps const& val); expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val); @@ -280,16 +280,16 @@ namespace smt { // ----------------------------------- public: theory_dense_diff_logic(ast_manager & m, theory_arith_params & p); - virtual ~theory_dense_diff_logic() { reset_eh(); } + ~theory_dense_diff_logic() override { reset_eh(); } - virtual theory * mk_fresh(context * new_ctx); + theory * mk_fresh(context * new_ctx) override; - virtual char const * get_name() const { return "difference-logic"; } + char const * get_name() const override { return "difference-logic"; } /** \brief See comment in theory::mk_eq_atom */ - virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return m_autil.mk_eq(lhs, rhs); } + app * mk_eq_atom(expr * lhs, expr * rhs) override { return m_autil.mk_eq(lhs, rhs); } }; typedef theory_dense_diff_logic theory_dense_mi; diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 1ad239e58..ce0814f10 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -208,7 +208,7 @@ namespace smt { void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges); // Create a new theory variable. - virtual theory_var mk_var(enode* n); + theory_var mk_var(enode* n) override; virtual theory_var mk_var(app* n); @@ -240,79 +240,79 @@ namespace smt { m_num_simplex_edges(0) { } - virtual ~theory_diff_logic() { + ~theory_diff_logic() override { reset_eh(); } - virtual theory * mk_fresh(context * new_ctx); + theory * mk_fresh(context * new_ctx) override; - virtual char const * get_name() const { return "difference-logic"; } + char const * get_name() const override { return "difference-logic"; } /** \brief See comment in theory::mk_eq_atom */ - virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return m_util.mk_eq(lhs, rhs); } + app * mk_eq_atom(expr * lhs, expr * rhs) override { return m_util.mk_eq(lhs, rhs); } - virtual void init(context * ctx); + void init(context * ctx) override; - virtual bool internalize_atom(app * atom, bool gate_ctx); + bool internalize_atom(app * atom, bool gate_ctx) override; - virtual bool internalize_term(app * term); + bool internalize_term(app * term) override; - virtual void internalize_eq_eh(app * atom, bool_var v); + void internalize_eq_eh(app * atom, bool_var v) override; - virtual void assign_eh(bool_var v, bool is_true); + void assign_eh(bool_var v, bool is_true) override; - virtual void new_eq_eh(theory_var v1, theory_var v2); + void new_eq_eh(theory_var v1, theory_var v2) override; - virtual bool use_diseqs() const { return true; } + bool use_diseqs() const override { return true; } - virtual void new_diseq_eh(theory_var v1, theory_var v2); + void new_diseq_eh(theory_var v1, theory_var v2) override; - virtual void push_scope_eh(); + void push_scope_eh() override; - virtual void pop_scope_eh(unsigned num_scopes); + void pop_scope_eh(unsigned num_scopes) override; - virtual void restart_eh() { + void restart_eh() override { m_arith_eq_adapter.restart_eh(); } - virtual void relevant_eh(app* e) {} + void relevant_eh(app* e) override {} - virtual void init_search_eh() { + void init_search_eh() override { m_arith_eq_adapter.init_search_eh(); } - virtual final_check_status final_check_eh(); + final_check_status final_check_eh() override; - virtual bool is_shared(theory_var v) const { + bool is_shared(theory_var v) const override { return false; } - virtual bool can_propagate() { + bool can_propagate() override { return m_asserted_qhead != m_asserted_atoms.size(); } - virtual void propagate(); + void propagate() override; - virtual justification * why_is_diseq(theory_var v1, theory_var v2) { + justification * why_is_diseq(theory_var v1, theory_var v2) override { NOT_IMPLEMENTED_YET(); return 0; } // virtual void flush_eh(); - virtual void reset_eh(); + void reset_eh() override; - virtual void init_model(model_generator & m); + void init_model(model_generator & m) override; - virtual model_value_proc * mk_value(enode * n, model_generator & mg); + model_value_proc * mk_value(enode * n, model_generator & mg) override; - virtual bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const; + bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override; - virtual void display(std::ostream & out) const; + void display(std::ostream & out) const override; - virtual void collect_statistics(::statistics & st) const; + void collect_statistics(::statistics & st) const override; // ----------------------------------- @@ -321,9 +321,9 @@ namespace smt { // // ----------------------------------- - virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared); - virtual inf_eps value(theory_var v); - virtual theory_var add_objective(app* term); + inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) override; + inf_eps value(theory_var v) override; + theory_var add_objective(app* term) override; expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index ea02121d9..1e9df2973 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -51,7 +51,7 @@ namespace smt { m_util(u) {} - virtual app * mk_value_core(unsigned const & val, sort * s) { + app * mk_value_core(unsigned const & val, sort * s) override { return m_util.mk_numeral(val, s); } }; @@ -74,9 +74,9 @@ namespace smt { dl_value_proc(theory_dl& th, smt::enode* n) : m_th(th), m_node(n) {} - virtual void get_dependencies(buffer & result) {} + void get_dependencies(buffer & result) override {} - virtual app * mk_value(smt::model_generator & mg, ptr_vector & ) { + app * mk_value(smt::model_generator & mg, ptr_vector & ) override { smt::context& ctx = m_th.get_context(); app* result = 0; expr* n = m_node->get_owner(); @@ -111,9 +111,9 @@ namespace smt { } - virtual char const * get_name() const { return "datalog"; } + char const * get_name() const override { return "datalog"; } - virtual bool internalize_atom(app * atom, bool gate_ctx) { + bool internalize_atom(app * atom, bool gate_ctx) override { TRACE("theory_dl", tout << mk_pp(atom, m()) << "\n";); context& ctx = get_context(); if (ctx.b_internalized(atom)) { @@ -136,7 +136,7 @@ namespace smt { return false; } - virtual bool internalize_term(app * term) { + bool internalize_term(app * term) override { TRACE("theory_dl", tout << mk_pp(term, m()) << "\n";); if (u().is_finite_sort(term)) { return mk_rep(term); @@ -146,27 +146,27 @@ namespace smt { } } - virtual void new_eq_eh(theory_var v1, theory_var v2) { + void new_eq_eh(theory_var v1, theory_var v2) override { } - virtual void new_diseq_eh(theory_var v1, theory_var v2) { + void new_diseq_eh(theory_var v1, theory_var v2) override { } - virtual theory * mk_fresh(context * new_ctx) { + theory * mk_fresh(context * new_ctx) override { return alloc(theory_dl, new_ctx->get_manager()); } - virtual void init_model(smt::model_generator & m) { + void init_model(smt::model_generator & m) override { m.register_factory(alloc(dl_factory, m_util, m.get_model())); } - virtual smt::model_value_proc * mk_value(smt::enode * n, smt::model_generator&) { + smt::model_value_proc * mk_value(smt::enode * n, smt::model_generator&) override { return alloc(dl_value_proc, *this, n); } - virtual void apply_sort_cnstr(enode * n, sort * s) { + void apply_sort_cnstr(enode * n, sort * s) override { app* term = n->get_owner(); if (u().is_finite_sort(term)) { mk_rep(term); @@ -174,7 +174,7 @@ namespace smt { } - virtual void relevant_eh(app * n) { + void relevant_eh(app * n) override { if (u().is_finite_sort(n)) { sort* s = m().get_sort(n); func_decl* r, *v; @@ -194,7 +194,7 @@ namespace smt { } } - virtual void display(std::ostream & out) const { + void display(std::ostream & out) const override { } diff --git a/src/smt/theory_dummy.h b/src/smt/theory_dummy.h index b20d86270..c58695aac 100644 --- a/src/smt/theory_dummy.h +++ b/src/smt/theory_dummy.h @@ -33,25 +33,25 @@ namespace smt { void found_theory_expr(); protected: - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term); - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual bool use_diseqs() const; - virtual void new_diseq_eh(theory_var v1, theory_var v2); - virtual void reset_eh(); - virtual final_check_status final_check_eh(); - virtual bool build_models() const { + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override; + void new_eq_eh(theory_var v1, theory_var v2) override; + bool use_diseqs() const override; + void new_diseq_eh(theory_var v1, theory_var v2) override; + void reset_eh() override; + final_check_status final_check_eh() override; + bool build_models() const override { return false; } - virtual void display(std::ostream& out) const {} + void display(std::ostream& out) const override {} public: theory_dummy(family_id fid, char const * name); - virtual ~theory_dummy() {} + ~theory_dummy() override {} - virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_dummy, get_family_id(), m_name); } + theory * mk_fresh(context * new_ctx) override { return alloc(theory_dummy, get_family_id(), m_name); } - virtual char const * get_name() const; + char const * get_name() const override; }; }; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index cc9b0017d..36ee5c15a 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -32,8 +32,8 @@ namespace smt { public: fpa2bv_conversion_trail_elem(ast_manager & m, obj_map & map, expr * e) : m(m), m_map(map), key(e, m) { } - virtual ~fpa2bv_conversion_trail_elem() { } - virtual void undo(theory_fpa & th) { + ~fpa2bv_conversion_trail_elem() override { } + void undo(theory_fpa & th) override { expr * val = m_map.find(key); m_map.remove(key); m.dec_ref(key); diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 9e9801ee0..8cd01d2e9 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -43,16 +43,16 @@ namespace smt { value_factory(m, fid), m_util(m) {} - virtual ~fpa_value_factory() {} + ~fpa_value_factory() override {} - virtual expr * get_some_value(sort * s) { + expr * get_some_value(sort * s) override { mpf_manager & mpfm = m_util.fm(); scoped_mpf q(mpfm); mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 0); return m_util.mk_value(q); } - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { + bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override { mpf_manager & mpfm = m_util.fm(); scoped_mpf q(mpfm); mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 0); @@ -62,8 +62,8 @@ namespace smt { return true; } - virtual expr * get_fresh_value(sort * s) { NOT_IMPLEMENTED_YET(); } - virtual void register_value(expr * n) { /* Ignore */ } + expr * get_fresh_value(sort * s) override { NOT_IMPLEMENTED_YET(); } + void register_value(expr * n) override { /* Ignore */ } app * mk_value(mpf const & x) { return m_util.mk_value(x); @@ -81,8 +81,8 @@ namespace smt { fpa2bv_converter(m), m_th(*th) {} virtual ~fpa2bv_converter_wrapped() {} - virtual void mk_const(func_decl * f, expr_ref & result); - virtual void mk_rm_const(func_decl * f, expr_ref & result); + void mk_const(func_decl * f, expr_ref & result) override; + void mk_rm_const(func_decl * f, expr_ref & result) override; }; class fpa_value_proc : public model_value_proc { @@ -100,15 +100,15 @@ namespace smt { m_th(*th), m(th->get_manager()), m_fu(th->m_fpa_util), m_bu(th->m_bv_util), m_ebits(ebits), m_sbits(sbits) {} - virtual ~fpa_value_proc() {} + ~fpa_value_proc() override {} void add_dependency(enode * e) { m_deps.push_back(model_value_dependency(e)); } - virtual void get_dependencies(buffer & result) { + void get_dependencies(buffer & result) override { result.append(m_deps); } - virtual app * mk_value(model_generator & mg, ptr_vector & values); + app * mk_value(model_generator & mg, ptr_vector & values) override; }; class fpa_rm_value_proc : public model_value_proc { @@ -124,12 +124,12 @@ namespace smt { void add_dependency(enode * e) { m_deps.push_back(model_value_dependency(e)); } - virtual void get_dependencies(buffer & result) { + void get_dependencies(buffer & result) override { result.append(m_deps); } - virtual ~fpa_rm_value_proc() {} - virtual app * mk_value(model_generator & mg, ptr_vector & values); + ~fpa_rm_value_proc() override {} + app * mk_value(model_generator & mg, ptr_vector & values) override; }; protected: @@ -145,32 +145,32 @@ namespace smt { bool m_is_initialized; obj_hashtable m_is_added_to_model; - virtual final_check_status final_check_eh(); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term); - virtual void apply_sort_cnstr(enode * n, sort * s); - virtual void new_eq_eh(theory_var, theory_var); - virtual void new_diseq_eh(theory_var, theory_var); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual void reset_eh(); - virtual theory* mk_fresh(context* new_ctx); - virtual char const * get_name() const { return "fpa"; } + final_check_status final_check_eh() override; + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override; + void apply_sort_cnstr(enode * n, sort * s) override; + void new_eq_eh(theory_var, theory_var) override; + void new_diseq_eh(theory_var, theory_var) override; + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + void reset_eh() override; + theory* mk_fresh(context* new_ctx) override; + char const * get_name() const override { return "fpa"; } - virtual model_value_proc * mk_value(enode * n, model_generator & mg); + model_value_proc * mk_value(enode * n, model_generator & mg) override; - void assign_eh(bool_var v, bool is_true); - virtual void relevant_eh(app * n); - virtual void init_model(model_generator & m); - virtual void finalize_model(model_generator & mg); + void assign_eh(bool_var v, bool is_true) override; + void relevant_eh(app * n) override; + void init_model(model_generator & m) override; + void finalize_model(model_generator & mg) override; public: theory_fpa(ast_manager & m); - virtual ~theory_fpa(); + ~theory_fpa() override; - virtual void init(context * ctx); + void init(context * ctx) override; - virtual void display(std::ostream & out) const; + void display(std::ostream & out) const override; protected: expr_ref mk_side_conditions(); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 21b66d3a0..d369ddefa 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -137,7 +137,7 @@ namespace smt { imp& m_imp; public: resource_limit(imp& i): m_imp(i) { } - virtual bool get_cancel_flag() { return m_imp.m.canceled(); } + bool get_cancel_flag() override { return m_imp.m.canceled(); } }; @@ -1358,11 +1358,11 @@ namespace smt { imp & m_imp; local_bound_propagator(imp& i) : lp_bound_propagator(*i.m_solver), m_imp(i) {} - bool bound_is_interesting(unsigned j, lp::lconstraint_kind kind, const rational & v) { + bool bound_is_interesting(unsigned j, lp::lconstraint_kind kind, const rational & v) override { return m_imp.bound_is_interesting(j, kind, v); } - virtual void consume(rational const& v, unsigned j) { + void consume(rational const& v, unsigned j) override { m_imp.set_evidence(j); } }; diff --git a/src/smt/theory_lra.h b/src/smt/theory_lra.h index 774ec15ad..f3ef77495 100644 --- a/src/smt/theory_lra.h +++ b/src/smt/theory_lra.h @@ -29,66 +29,66 @@ namespace smt { public: theory_lra(ast_manager& m, theory_arith_params& ap); - virtual ~theory_lra(); - virtual theory* mk_fresh(context* new_ctx); - virtual char const* get_name() const { return "lra"; } + ~theory_lra() override; + theory* mk_fresh(context* new_ctx) override; + char const* get_name() const override { return "lra"; } - virtual void init(context * ctx); + void init(context * ctx) override; - virtual bool internalize_atom(app * atom, bool gate_ctx); + bool internalize_atom(app * atom, bool gate_ctx) override; - virtual bool internalize_term(app * term); + bool internalize_term(app * term) override; - virtual void internalize_eq_eh(app * atom, bool_var v); + void internalize_eq_eh(app * atom, bool_var v) override; - virtual void assign_eh(bool_var v, bool is_true); + void assign_eh(bool_var v, bool is_true) override; - virtual void new_eq_eh(theory_var v1, theory_var v2); + void new_eq_eh(theory_var v1, theory_var v2) override; - virtual bool use_diseqs() const; + bool use_diseqs() const override; - virtual void new_diseq_eh(theory_var v1, theory_var v2); + void new_diseq_eh(theory_var v1, theory_var v2) override; - virtual void push_scope_eh(); + void push_scope_eh() override; - virtual void pop_scope_eh(unsigned num_scopes); + void pop_scope_eh(unsigned num_scopes) override; - virtual void restart_eh(); + void restart_eh() override; - virtual void relevant_eh(app* e); + void relevant_eh(app* e) override; - virtual void init_search_eh(); + void init_search_eh() override; - virtual final_check_status final_check_eh(); + final_check_status final_check_eh() override; - virtual bool is_shared(theory_var v) const; + bool is_shared(theory_var v) const override; - virtual bool can_propagate(); + bool can_propagate() override; - virtual void propagate(); + void propagate() override; - virtual justification * why_is_diseq(theory_var v1, theory_var v2); + justification * why_is_diseq(theory_var v1, theory_var v2) override; // virtual void flush_eh(); - virtual void reset_eh(); + void reset_eh() override; - virtual void init_model(model_generator & m); + void init_model(model_generator & m) override; - virtual model_value_proc * mk_value(enode * n, model_generator & mg); + model_value_proc * mk_value(enode * n, model_generator & mg) override; - virtual bool get_value(enode* n, expr_ref& r); + bool get_value(enode* n, expr_ref& r) override; - virtual bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const; + bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override; - virtual void display(std::ostream & out) const; + void display(std::ostream & out) const override; - virtual void collect_statistics(::statistics & st) const; + void collect_statistics(::statistics & st) const override; // optimization - virtual inf_eps value(theory_var); - virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared); - virtual theory_var add_objective(app* term); + inf_eps value(theory_var) override; + inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) override; + theory_var add_objective(app* term) override; virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 9d2059f55..cc9b6b9b1 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -254,7 +254,7 @@ namespace smt { unsigned v; public: remove_var(theory_pb& pb, unsigned v): pb(pb), v(v) {} - virtual void undo(context& ctx) { + void undo(context& ctx) override { pb.m_vars.remove(v); pb.m_simplex.unset_lower(v); pb.m_simplex.unset_upper(v); @@ -282,7 +282,7 @@ namespace smt { m_last_bound_valid(last_bound_valid), m_last_explain(last_explain) {} - virtual void undo(context& ctx) { + void undo(context& ctx) override { if (m_is_lower) { if (m_last_bound_valid) { pb.m_simplex.set_lower(m_v, m_last_bound); @@ -889,7 +889,7 @@ namespace smt { ineq& c; public: rewatch_vars(theory_pb& p, ineq& c): pb(p), c(c) {} - virtual void undo(context& ctx) { + void undo(context& ctx) override { for (unsigned i = 0; i < c.size(); ++i) { pb.watch_var(c.lit(i).var(), &c); } @@ -900,7 +900,7 @@ namespace smt { ineq& c; public: negate_ineq(ineq& c): c(c) {} - virtual void undo(context& ctx) { + void undo(context& ctx) override { c.negate(); } }; @@ -1357,7 +1357,7 @@ namespace smt { public: unwatch_ge(theory_pb& p, ineq& c): pb(p), c(c) {} - virtual void undo(context& ctx) { + void undo(context& ctx) override { for (unsigned i = 0; i < c.watch_size(); ++i) { pb.unwatch_literal(c.lit(i), &c); } @@ -2008,11 +2008,11 @@ namespace smt { m_dependencies.push_back(model_value_dependency(n)); } - virtual void get_dependencies(buffer & result) { + void get_dependencies(buffer & result) override { result.append(m_dependencies.size(), m_dependencies.c_ptr()); } - virtual app * mk_value(model_generator & mg, ptr_vector & values) { + app * mk_value(model_generator & mg, ptr_vector & values) override { ast_manager& m = mg.get_manager(); SASSERT(values.size() == m_dependencies.size()); SASSERT(values.size() == m_app->get_num_args()); @@ -2049,18 +2049,18 @@ namespace smt { pb_factory(ast_manager& m, family_id fid): value_factory(m, fid) {} - virtual expr * get_some_value(sort * s) { + expr * get_some_value(sort * s) override { return m_manager.mk_true(); } - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { + bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override { v1 = m_manager.mk_true(); v2 = m_manager.mk_false(); return true; } - virtual expr * get_fresh_value(sort * s) { + expr * get_fresh_value(sort * s) override { return 0; } - virtual void register_value(expr * n) { } + void register_value(expr * n) override { } }; void theory_pb::init_model(model_generator & m) { diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 662378bdf..5eb6e3312 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -261,7 +261,7 @@ namespace smt { std::ostream& display(std::ostream& out, ineq const& c, bool values = false) const; std::ostream& display(std::ostream& out, arg_t const& c, bool values = false) const; - virtual void display(std::ostream& out) const; + void display(std::ostream& out) const override; void display_watch(std::ostream& out, bool_var v, bool sign) const; void display_resolved_lemma(std::ostream& out) const; @@ -317,26 +317,26 @@ namespace smt { public: theory_pb(ast_manager& m, theory_pb_params& p); - virtual ~theory_pb(); + ~theory_pb() override; - virtual theory * mk_fresh(context * new_ctx); - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term) { UNREACHABLE(); return false; } - virtual void new_eq_eh(theory_var v1, theory_var v2); - virtual void new_diseq_eh(theory_var v1, theory_var v2) { } - virtual bool use_diseqs() const { return false; } - virtual bool build_models() const { return false; } - virtual final_check_status final_check_eh(); - virtual void reset_eh(); - virtual void assign_eh(bool_var v, bool is_true); - virtual void init_search_eh(); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual void restart_eh(); - virtual void collect_statistics(::statistics & st) const; - virtual model_value_proc * mk_value(enode * n, model_generator & mg); - virtual void init_model(model_generator & m); - virtual bool include_func_interp(func_decl* f) { return false; } + theory * mk_fresh(context * new_ctx) override; + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override { UNREACHABLE(); return false; } + void new_eq_eh(theory_var v1, theory_var v2) override; + void new_diseq_eh(theory_var v1, theory_var v2) override { } + bool use_diseqs() const override { return false; } + bool build_models() const override { return false; } + final_check_status final_check_eh() override; + void reset_eh() override; + void assign_eh(bool_var v, bool is_true) override; + void init_search_eh() override; + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + void restart_eh() override; + void collect_statistics(::statistics & st) const override; + model_value_proc * mk_value(enode * n, model_generator & mg) override; + void init_model(model_generator & m) override; + bool include_func_interp(func_decl* f) override { return false; } static literal assert_ge(context& ctx, unsigned k, unsigned n, literal const* xs); }; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 4c1a63a2f..6fabbf865 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -45,7 +45,7 @@ public: m_kernel(m, fp) {} - virtual lbool check_sat(expr* e) { + lbool check_sat(expr* e) override { m_kernel.push(); m_kernel.assert_expr(e); lbool r = m_kernel.check(); @@ -2691,7 +2691,7 @@ class theory_seq::seq_value_proc : public model_value_proc { public: seq_value_proc(theory_seq& th, sort* s): th(th), m_sort(s) { } - virtual ~seq_value_proc() {} + ~seq_value_proc() override {} void add_unit(enode* n) { m_dependencies.push_back(model_value_dependency(n)); m_source.push_back(unit_source); @@ -2704,7 +2704,7 @@ public: m_strings.push_back(n); m_source.push_back(string_source); } - virtual void get_dependencies(buffer & result) { + void get_dependencies(buffer & result) override { result.append(m_dependencies.size(), m_dependencies.c_ptr()); } @@ -2714,7 +2714,7 @@ public: } } - virtual app * mk_value(model_generator & mg, ptr_vector & values) { + app * mk_value(model_generator & mg, ptr_vector & values) override { SASSERT(values.size() == m_dependencies.size()); expr_ref_vector args(th.m); unsigned j = 0, k = 0; diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 46f803f5b..3cb1f1b4b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -224,8 +224,8 @@ namespace smt { expr_ref m_e; public: replay_length_coherence(ast_manager& m, expr* e) : m_e(e, m) {} - virtual ~replay_length_coherence() {} - virtual void operator()(theory_seq& th) { + ~replay_length_coherence() override {} + void operator()(theory_seq& th) override { th.check_length_coherence(m_e); m_e.reset(); } @@ -235,8 +235,8 @@ namespace smt { expr_ref m_e; public: replay_fixed_length(ast_manager& m, expr* e) : m_e(e, m) {} - virtual ~replay_fixed_length() {} - virtual void operator()(theory_seq& th) { + ~replay_fixed_length() override {} + void operator()(theory_seq& th) override { th.fixed_length(m_e); m_e.reset(); } @@ -246,8 +246,8 @@ namespace smt { expr_ref m_e; public: replay_axiom(ast_manager& m, expr* e) : m_e(e, m) {} - virtual ~replay_axiom() {} - virtual void operator()(theory_seq& th) { + ~replay_axiom() override {} + void operator()(theory_seq& th) override { th.enque_axiom(m_e); m_e.reset(); } @@ -257,7 +257,7 @@ namespace smt { apply* m_apply; public: push_replay(apply* app): m_apply(app) {} - virtual void undo(theory_seq& th) { + void undo(theory_seq& th) override { th.m_replay.push_back(m_apply); } }; @@ -266,7 +266,7 @@ namespace smt { unsigned k; public: pop_branch(unsigned k): k(k) {} - virtual void undo(theory_seq& th) { + void undo(theory_seq& th) override { th.m_branch_start.erase(k); } }; @@ -340,29 +340,29 @@ namespace smt { obj_hashtable m_fixed; // string variables that are fixed length. - virtual void init(context* ctx); - virtual final_check_status final_check_eh(); - virtual bool internalize_atom(app* atom, bool); - virtual bool internalize_term(app*); - virtual void internalize_eq_eh(app * atom, bool_var v); - virtual void new_eq_eh(theory_var, theory_var); - virtual void new_diseq_eh(theory_var, theory_var); - virtual void assign_eh(bool_var v, bool is_true); - virtual bool can_propagate(); - virtual void propagate(); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual void restart_eh(); - virtual void relevant_eh(app* n); - virtual theory* mk_fresh(context* new_ctx) { return alloc(theory_seq, new_ctx->get_manager()); } - virtual char const * get_name() const { return "seq"; } - virtual theory_var mk_var(enode* n); - virtual void apply_sort_cnstr(enode* n, sort* s); - virtual void display(std::ostream & out) const; - virtual void collect_statistics(::statistics & st) const; - virtual model_value_proc * mk_value(enode * n, model_generator & mg); - virtual void init_model(model_generator & mg); - virtual void init_search_eh(); + void init(context* ctx) override; + final_check_status final_check_eh() override; + bool internalize_atom(app* atom, bool) override; + bool internalize_term(app*) override; + void internalize_eq_eh(app * atom, bool_var v) override; + void new_eq_eh(theory_var, theory_var) override; + void new_diseq_eh(theory_var, theory_var) override; + void assign_eh(bool_var v, bool is_true) override; + bool can_propagate() override; + void propagate() override; + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + void restart_eh() override; + void relevant_eh(app* n) override; + theory* mk_fresh(context* new_ctx) override { return alloc(theory_seq, new_ctx->get_manager()); } + char const * get_name() const override { return "seq"; } + theory_var mk_var(enode* n) override; + void apply_sort_cnstr(enode* n, sort* s) override; + void display(std::ostream & out) const override; + void collect_statistics(::statistics & st) const override; + model_value_proc * mk_value(enode * n, model_generator & mg) override; + void init_model(model_generator & mg) override; + void init_search_eh() override; void init_model(expr_ref_vector const& es); // final check @@ -584,7 +584,7 @@ namespace smt { void display_nc(std::ostream& out, nc const& nc) const; public: theory_seq(ast_manager& m); - virtual ~theory_seq(); + ~theory_seq() override; // model building app* mk_value(app* a); diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index 85408f7e5..647b54320 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -63,7 +63,7 @@ namespace smt { m_unique_sequences.insert(m.get_sort(uniq), uniq); } - virtual expr* get_some_value(sort* s) { + expr* get_some_value(sort* s) override { if (u.is_seq(s)) { return u.str.mk_empty(s); } @@ -74,7 +74,7 @@ namespace smt { UNREACHABLE(); return 0; } - virtual bool get_some_values(sort* s, expr_ref& v1, expr_ref& v2) { + bool get_some_values(sort* s, expr_ref& v1, expr_ref& v2) override { if (u.is_string(s)) { v1 = u.str.mk_string(symbol("a")); v2 = u.str.mk_string(symbol("b")); @@ -94,7 +94,7 @@ namespace smt { NOT_IMPLEMENTED_YET(); return false; } - virtual expr* get_fresh_value(sort* s) { + expr* get_fresh_value(sort* s) override { if (u.is_string(s)) { while (true) { std::ostringstream strm; @@ -122,7 +122,7 @@ namespace smt { UNREACHABLE(); return 0; } - virtual void register_value(expr* n) { + void register_value(expr* n) override { symbol sym; if (u.str.is_string(n, sym)) { m_strings.insert(sym); @@ -148,17 +148,17 @@ namespace smt { class theory_seq_empty : public theory { bool m_used; - virtual final_check_status final_check_eh() { return m_used?FC_GIVEUP:FC_DONE; } - virtual bool internalize_atom(app*, bool) { if (!m_used) { get_context().push_trail(value_trail(m_used)); m_used = true; } return false; } - virtual bool internalize_term(app*) { return internalize_atom(0,false); } - virtual void new_eq_eh(theory_var, theory_var) { } - virtual void new_diseq_eh(theory_var, theory_var) {} - virtual theory* mk_fresh(context* new_ctx) { return alloc(theory_seq_empty, new_ctx->get_manager()); } - virtual char const * get_name() const { return "seq-empty"; } - virtual void display(std::ostream& out) const {} + final_check_status final_check_eh() override { return m_used?FC_GIVEUP:FC_DONE; } + bool internalize_atom(app*, bool) override { if (!m_used) { get_context().push_trail(value_trail(m_used)); m_used = true; } return false; } + bool internalize_term(app*) override { return internalize_atom(0,false); } + void new_eq_eh(theory_var, theory_var) override { } + void new_diseq_eh(theory_var, theory_var) override {} + theory* mk_fresh(context* new_ctx) override { return alloc(theory_seq_empty, new_ctx->get_manager()); } + char const * get_name() const override { return "seq-empty"; } + void display(std::ostream& out) const override {} public: theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {} - virtual void init_model(model_generator & mg) { + void init_model(model_generator & mg) override { mg.register_factory(alloc(seq_factory, get_manager(), get_family_id(), mg.get_model())); } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 03fd31162..52d06efd1 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -46,16 +46,16 @@ public: str_value_factory(ast_manager & m, family_id fid) : value_factory(m, fid), u(m), delim("!"), m_next(0) {} - virtual ~str_value_factory() {} - virtual expr * get_some_value(sort * s) { + ~str_value_factory() override {} + expr * get_some_value(sort * s) override { return u.str.mk_string(symbol("some value")); } - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { + bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override { v1 = u.str.mk_string(symbol("value 1")); v2 = u.str.mk_string(symbol("value 2")); return true; } - virtual expr * get_fresh_value(sort * s) { + expr * get_fresh_value(sort * s) override { if (u.is_string(s)) { while (true) { std::ostringstream strm; @@ -74,7 +74,7 @@ public: TRACE("t_str", tout << "unexpected sort in get_fresh_value(): " << mk_pp(s, m_manager) << std::endl;); UNREACHABLE(); return NULL; } - virtual void register_value(expr * n) { /* Ignore */ } + void register_value(expr * n) override { /* Ignore */ } }; // rather than modify obj_pair_map I inherit from it and add my own helper methods @@ -104,8 +104,8 @@ class binary_search_trail : public trail { public: binary_search_trail(obj_map > & target, expr * entry) : target(target), entry(entry) {} - virtual ~binary_search_trail() {} - virtual void undo(Ctx & ctx) { + ~binary_search_trail() override {} + void undo(Ctx & ctx) override { TRACE("t_str_binary_search", tout << "in binary_search_trail::undo()" << std::endl;); if (target.contains(entry)) { if (!target[entry].empty()) { @@ -616,10 +616,10 @@ protected: public: theory_str(ast_manager & m, theory_str_params const & params); - virtual ~theory_str(); + ~theory_str() override; - virtual char const * get_name() const { return "seq"; } - virtual void display(std::ostream & out) const; + char const * get_name() const override { return "seq"; } + void display(std::ostream & out) const override; bool overlapping_variables_detected() const { return loopDetected; } @@ -628,33 +628,33 @@ public: void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) { } void unmerge_eh(theory_var v1, theory_var v2) {} protected: - virtual bool internalize_atom(app * atom, bool gate_ctx); - virtual bool internalize_term(app * term); + bool internalize_atom(app * atom, bool gate_ctx) override; + bool internalize_term(app * term) override; virtual enode* ensure_enode(expr* e); - virtual theory_var mk_var(enode * n); + theory_var mk_var(enode * n) override; - virtual void new_eq_eh(theory_var, theory_var); - virtual void new_diseq_eh(theory_var, theory_var); + void new_eq_eh(theory_var, theory_var) override; + void new_diseq_eh(theory_var, theory_var) override; - virtual theory* mk_fresh(context*) { return alloc(theory_str, get_manager(), m_params); } - virtual void init_search_eh(); - virtual void add_theory_assumptions(expr_ref_vector & assumptions); - virtual lbool validate_unsat_core(expr_ref_vector & unsat_core); - virtual void relevant_eh(app * n); - virtual void assign_eh(bool_var v, bool is_true); - virtual void push_scope_eh(); - virtual void pop_scope_eh(unsigned num_scopes); - virtual void reset_eh(); + theory* mk_fresh(context*) override { return alloc(theory_str, get_manager(), m_params); } + void init_search_eh() override; + void add_theory_assumptions(expr_ref_vector & assumptions) override; + lbool validate_unsat_core(expr_ref_vector & unsat_core) override; + void relevant_eh(app * n) override; + void assign_eh(bool_var v, bool is_true) override; + void push_scope_eh() override; + void pop_scope_eh(unsigned num_scopes) override; + void reset_eh() override; - virtual bool can_propagate(); - virtual void propagate(); + bool can_propagate() override; + void propagate() override; - virtual final_check_status final_check_eh(); + final_check_status final_check_eh() override; virtual void attach_new_th_var(enode * n); - virtual void init_model(model_generator & m); - virtual model_value_proc * mk_value(enode * n, model_generator & mg); - virtual void finalize_model(model_generator & mg); + void init_model(model_generator & m) override; + model_value_proc * mk_value(enode * n, model_generator & mg) override; + void finalize_model(model_generator & mg) override; }; }; diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index 55bbb9838..ca4f4737e 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -166,7 +166,7 @@ namespace smt { void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {} // Create a new theory variable. - virtual th_var mk_var(enode* n); + th_var mk_var(enode* n) override; virtual th_var mk_var(expr* n); @@ -181,83 +181,83 @@ namespace smt { public: theory_utvpi(ast_manager& m); - virtual ~theory_utvpi(); + ~theory_utvpi() override; - virtual theory * mk_fresh(context * new_ctx); + theory * mk_fresh(context * new_ctx) override; - virtual char const * get_name() const { return "utvpi-logic"; } + char const * get_name() const override { return "utvpi-logic"; } /** \brief See comment in theory::mk_eq_atom */ - virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return a.mk_eq(lhs, rhs); } + app * mk_eq_atom(expr * lhs, expr * rhs) override { return a.mk_eq(lhs, rhs); } - virtual void init(context * ctx); + void init(context * ctx) override; - virtual bool internalize_atom(app * atom, bool gate_ctx); + bool internalize_atom(app * atom, bool gate_ctx) override; - virtual bool internalize_term(app * term); + bool internalize_term(app * term) override; - virtual void internalize_eq_eh(app * atom, bool_var v); + void internalize_eq_eh(app * atom, bool_var v) override; - virtual void assign_eh(bool_var v, bool is_true); + void assign_eh(bool_var v, bool is_true) override; - virtual void new_eq_eh(th_var v1, th_var v2) { + void new_eq_eh(th_var v1, th_var v2) override { m_stats.m_num_core2th_eqs++; m_arith_eq_adapter.new_eq_eh(v1, v2); } - virtual bool use_diseqs() const { return true; } + bool use_diseqs() const override { return true; } - virtual void new_diseq_eh(th_var v1, th_var v2) { + void new_diseq_eh(th_var v1, th_var v2) override { m_arith_eq_adapter.new_diseq_eh(v1, v2); } - virtual void push_scope_eh(); + void push_scope_eh() override; - virtual void pop_scope_eh(unsigned num_scopes); + void pop_scope_eh(unsigned num_scopes) override; - virtual void restart_eh() { + void restart_eh() override { m_arith_eq_adapter.restart_eh(); } - virtual void relevant_eh(app* e) {} + void relevant_eh(app* e) override {} - virtual void init_search_eh() { + void init_search_eh() override { m_arith_eq_adapter.init_search_eh(); } - virtual final_check_status final_check_eh(); + final_check_status final_check_eh() override; - virtual bool is_shared(th_var v) const { + bool is_shared(th_var v) const override { return false; } - virtual bool can_propagate() { + bool can_propagate() override { SASSERT(m_asserted_qhead <= m_asserted_atoms.size()); return m_asserted_qhead != m_asserted_atoms.size(); } - virtual void propagate(); + void propagate() override; - virtual justification * why_is_diseq(th_var v1, th_var v2) { + justification * why_is_diseq(th_var v1, th_var v2) override { UNREACHABLE(); return 0; } - virtual void reset_eh(); + void reset_eh() override; - virtual void init_model(model_generator & m); + void init_model(model_generator & m) override; - virtual model_value_proc * mk_value(enode * n, model_generator & mg); + model_value_proc * mk_value(enode * n, model_generator & mg) override; - virtual bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const { + bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const override { return true; } - virtual void display(std::ostream & out) const; + void display(std::ostream & out) const override; - virtual void collect_statistics(::statistics & st) const; + void collect_statistics(::statistics & st) const override; private: diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 739a22c71..16dab488b 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -57,7 +57,7 @@ namespace smt { stats m_stats; public: theory_wmaxsat(ast_manager& m, filter_model_converter& mc); - virtual ~theory_wmaxsat(); + ~theory_wmaxsat() override; void get_assignment(svector& result); expr* assert_weighted(expr* fml, rational const& w); void disable_var(expr* var); @@ -76,43 +76,43 @@ namespace smt { old.push_back(value); } - virtual ~numeral_trail() { + ~numeral_trail() override { } - virtual void undo(context & ctx) { + void undo(context & ctx) override { m_value = m_old_values.back(); m_old_values.shrink(m_old_values.size() - 1); } }; - virtual void init_search_eh(); - virtual void assign_eh(bool_var v, bool is_true); - virtual final_check_status final_check_eh(); - virtual bool use_diseqs() const { + void init_search_eh() override; + void assign_eh(bool_var v, bool is_true) override; + final_check_status final_check_eh() override; + bool use_diseqs() const override { return false; } - virtual bool build_models() const { + bool build_models() const override { return false; } void reset_local(); - virtual void reset_eh(); - virtual theory * mk_fresh(context * new_ctx) { return 0; } - virtual bool internalize_atom(app * atom, bool gate_ctx) { return false; } - virtual bool internalize_term(app * term) { return false; } - virtual void new_eq_eh(theory_var v1, theory_var v2) { } - virtual void new_diseq_eh(theory_var v1, theory_var v2) { } - virtual void display(std::ostream& out) const {} - virtual void restart_eh(); + void reset_eh() override; + theory * mk_fresh(context * new_ctx) override { return 0; } + bool internalize_atom(app * atom, bool gate_ctx) override { return false; } + bool internalize_term(app * term) override { return false; } + void new_eq_eh(theory_var v1, theory_var v2) override { } + void new_diseq_eh(theory_var v1, theory_var v2) override { } + void display(std::ostream& out) const override {} + void restart_eh() override; - virtual void collect_statistics(::statistics & st) const { + void collect_statistics(::statistics & st) const override { st.update("wmaxsat num blocks", m_stats.m_num_blocks); st.update("wmaxsat num props", m_stats.m_num_propagations); } - virtual bool can_propagate() { + bool can_propagate() override { return m_propagate || m_can_propagate; } - virtual void propagate(); + void propagate() override; bool is_optimal() const; expr_ref mk_block(); diff --git a/src/test/ex.cpp b/src/test/ex.cpp index 591813814..444431475 100644 --- a/src/test/ex.cpp +++ b/src/test/ex.cpp @@ -29,14 +29,14 @@ class ex1 : public ex { char const * m_msg; public: ex1(char const * m):m_msg(m) {} - virtual char const * msg() const { return m_msg; } + char const * msg() const override { return m_msg; } }; class ex2 : public ex { std::string m_msg; public: ex2(char const * m):m_msg(m) {} - virtual char const * msg() const { return m_msg.c_str(); } + char const * msg() const override { return m_msg.c_str(); } }; static void th() { diff --git a/src/util/checked_int64.h b/src/util/checked_int64.h index 8a2eb124d..e5a88fb31 100644 --- a/src/util/checked_int64.h +++ b/src/util/checked_int64.h @@ -41,7 +41,7 @@ public: checked_int64(checked_int64 const& other) { m_value = other.m_value; } class overflow_exception : public z3_exception { - virtual char const * msg() const { return "checked_int64 overflow/underflow";} + char const * msg() const override { return "checked_int64 overflow/underflow";} }; bool is_zero() const { return m_value == 0; } diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index 6c30e2146..7224fa846 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -46,7 +46,7 @@ public: #endif m_column_index(column_index) {} - bool is_dense() const { return false; } + bool is_dense() const override { return false; } void print(std::ostream & out) { print_matrix(*this, out); @@ -65,12 +65,12 @@ public: return m_diagonal_element; } - void apply_from_left(vector & w, lp_settings & ); + void apply_from_left(vector & w, lp_settings & ) override; template void apply_from_left_local(indexed_vector & w, lp_settings & settings); - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override { apply_from_left_local(w, settings); } @@ -80,8 +80,8 @@ public: m_column_vector.push_back(row_index, val); } - void apply_from_right(vector & w); - void apply_from_right(indexed_vector & w); + void apply_from_right(vector & w) override; + void apply_from_right(indexed_vector & w) override; T get_elem(unsigned i, unsigned j) const; #ifdef Z3DEBUG diff --git a/src/util/lp/iterator_on_column.h b/src/util/lp/iterator_on_column.h index 5bb43f4c6..c9112a064 100644 --- a/src/util/lp/iterator_on_column.h +++ b/src/util/lp/iterator_on_column.h @@ -27,14 +27,14 @@ struct iterator_on_column:linear_combination_iterator { const vector& m_column; // the offset in term coeffs const static_matrix & m_A; int m_i; // the initial offset in the column - unsigned size() const { return m_column.size(); } + unsigned size() const override { return m_column.size(); } iterator_on_column(const vector& column, const static_matrix & A) // the offset in term coeffs : m_column(column), m_A(A), m_i(-1) {} - bool next(mpq & a, unsigned & i) { + bool next(mpq & a, unsigned & i) override { if (++m_i >= static_cast(m_column.size())) return false; @@ -44,7 +44,7 @@ struct iterator_on_column:linear_combination_iterator { return true; } - bool next(unsigned & i) { + bool next(unsigned & i) override { if (++m_i >= static_cast(m_column.size())) return false; @@ -53,11 +53,11 @@ struct iterator_on_column:linear_combination_iterator { return true; } - void reset() { + void reset() override { m_i = -1; } - linear_combination_iterator * clone() { + linear_combination_iterator * clone() override { iterator_on_column * r = new iterator_on_column(m_column, m_A); return r; } diff --git a/src/util/lp/iterator_on_indexed_vector.h b/src/util/lp/iterator_on_indexed_vector.h index 2c8daf83b..6cb98b8f2 100644 --- a/src/util/lp/iterator_on_indexed_vector.h +++ b/src/util/lp/iterator_on_indexed_vector.h @@ -28,8 +28,8 @@ struct iterator_on_indexed_vector:linear_combination_iterator { m_v(v), m_offset(0) {} - unsigned size() const { return m_v.m_index.size(); } - bool next(T & a, unsigned & i) { + unsigned size() const override { return m_v.m_index.size(); } + bool next(T & a, unsigned & i) override { if (m_offset >= m_v.m_index.size()) return false; i = m_v.m_index[m_offset++]; @@ -37,16 +37,16 @@ struct iterator_on_indexed_vector:linear_combination_iterator { return true; } - bool next(unsigned & i) { + bool next(unsigned & i) override { if (m_offset >= m_v.m_index.size()) return false; i = m_v.m_index[m_offset++]; return true; } - void reset() { + void reset() override { m_offset = 0; } - linear_combination_iterator* clone() { + linear_combination_iterator* clone() override { return new iterator_on_indexed_vector(m_v); } }; diff --git a/src/util/lp/iterator_on_pivot_row.h b/src/util/lp/iterator_on_pivot_row.h index 8aa498477..721502bc2 100644 --- a/src/util/lp/iterator_on_pivot_row.h +++ b/src/util/lp/iterator_on_pivot_row.h @@ -26,11 +26,11 @@ struct iterator_on_pivot_row:linear_combination_iterator { const indexed_vector & m_v; unsigned m_basis_j; iterator_on_indexed_vector m_it; - unsigned size() const { return m_it.size(); } + unsigned size() const override { return m_it.size(); } iterator_on_pivot_row(const indexed_vector & v, unsigned basis_j) : m_basis_returned(false), m_v(v), m_basis_j(basis_j), m_it(v) {} - bool next(T & a, unsigned & i) { + bool next(T & a, unsigned & i) override { if (m_basis_returned == false) { m_basis_returned = true; a = one_of_type(); @@ -39,7 +39,7 @@ struct iterator_on_pivot_row:linear_combination_iterator { } return m_it.next(a, i); } - bool next(unsigned & i) { + bool next(unsigned & i) override { if (m_basis_returned == false) { m_basis_returned = true; i = m_basis_j; @@ -47,11 +47,11 @@ struct iterator_on_pivot_row:linear_combination_iterator { } return m_it.next(i); } - void reset() { + void reset() override { m_basis_returned = false; m_it.reset(); } - linear_combination_iterator * clone() { + linear_combination_iterator * clone() override { iterator_on_pivot_row * r = new iterator_on_pivot_row(m_v, m_basis_j); return r; } diff --git a/src/util/lp/iterator_on_row.h b/src/util/lp/iterator_on_row.h index 1ac5b66bc..55fbda907 100644 --- a/src/util/lp/iterator_on_row.h +++ b/src/util/lp/iterator_on_row.h @@ -26,8 +26,8 @@ struct iterator_on_row:linear_combination_iterator { unsigned m_i; // offset iterator_on_row(const vector> & row) : m_row(row), m_i(0) {} - unsigned size() const { return m_row.size(); } - bool next(T & a, unsigned & i) { + unsigned size() const override { return m_row.size(); } + bool next(T & a, unsigned & i) override { if (m_i == m_row.size()) return false; auto &c = m_row[m_i++]; @@ -35,17 +35,17 @@ struct iterator_on_row:linear_combination_iterator { a = c.get_val(); return true; } - bool next(unsigned & i) { + bool next(unsigned & i) override { if (m_i == m_row.size()) return false; auto &c = m_row[m_i++]; i = c.m_j; return true; } - void reset() { + void reset() override { m_i = 0; } - linear_combination_iterator* clone() { + linear_combination_iterator* clone() override { return new iterator_on_row(m_row); } }; diff --git a/src/util/lp/iterator_on_term_with_basis_var.h b/src/util/lp/iterator_on_term_with_basis_var.h index e566b92b5..85d11cf36 100644 --- a/src/util/lp/iterator_on_term_with_basis_var.h +++ b/src/util/lp/iterator_on_term_with_basis_var.h @@ -27,14 +27,14 @@ struct iterator_on_term_with_basis_var:linear_combination_iterator { std::unordered_map::const_iterator m_i; // the offset in term coeffs bool m_term_j_returned; unsigned m_term_j; - unsigned size() const {return static_cast(m_term.m_coeffs.size() + 1);} + unsigned size() const override {return static_cast(m_term.m_coeffs.size() + 1);} iterator_on_term_with_basis_var(const lar_term & t, unsigned term_j) : m_term(t), m_i(t.m_coeffs.begin()), m_term_j_returned(false), m_term_j(term_j) {} - bool next(mpq & a, unsigned & i) { + bool next(mpq & a, unsigned & i) override { if (m_term_j_returned == false) { m_term_j_returned = true; a = - one_of_type(); @@ -48,7 +48,7 @@ struct iterator_on_term_with_basis_var:linear_combination_iterator { m_i++; return true; } - bool next(unsigned & i) { + bool next(unsigned & i) override { if (m_term_j_returned == false) { m_term_j_returned = true; i = m_term_j; @@ -60,11 +60,11 @@ struct iterator_on_term_with_basis_var:linear_combination_iterator { m_i++; return true; } - void reset() { + void reset() override { m_term_j_returned = false; m_i = m_term.m_coeffs.begin(); } - linear_combination_iterator * clone() { + linear_combination_iterator * clone() override { iterator_on_term_with_basis_var * r = new iterator_on_term_with_basis_var(m_term, m_term_j); return r; } diff --git a/src/util/lp/lar_constraints.h b/src/util/lp/lar_constraints.h index 7b573bab7..9d3a0e0aa 100644 --- a/src/util/lp/lar_constraints.h +++ b/src/util/lp/lar_constraints.h @@ -59,24 +59,24 @@ public: struct lar_var_constraint: public lar_base_constraint { unsigned m_j; - vector> get_left_side_coefficients() const { + vector> get_left_side_coefficients() const override { vector> ret; ret.push_back(std::make_pair(one_of_type(), m_j)); return ret; } - unsigned size() const { return 1;} + unsigned size() const override { return 1;} lar_var_constraint(unsigned j, lconstraint_kind kind, const mpq& right_side) : lar_base_constraint(kind, right_side), m_j(j) { } }; struct lar_term_constraint: public lar_base_constraint { const lar_term * m_term; - vector> get_left_side_coefficients() const { + vector> get_left_side_coefficients() const override { return m_term->coeffs_as_vector(); } - unsigned size() const { return m_term->size();} + unsigned size() const override { return m_term->size();} lar_term_constraint(const lar_term *t, lconstraint_kind kind, const mpq& right_side) : lar_base_constraint(kind, right_side), m_term(t) { } - virtual mpq get_free_coeff_of_left_side() const { return m_term->m_v;} + mpq get_free_coeff_of_left_side() const override { return m_term->m_v;} }; @@ -92,10 +92,10 @@ public: SASSERT(false); // should not be called : todo! } - unsigned size() const { + unsigned size() const override { return static_cast(m_coeffs.size()); } - vector> get_left_side_coefficients() const { return m_coeffs; } + vector> get_left_side_coefficients() const override { return m_coeffs; } }; } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 1f1054bb6..c26333edb 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -1011,7 +1011,7 @@ public: return ret; } - std::string get_column_name(unsigned j) const { + std::string get_column_name(unsigned j) const override { if (j >= m_terms_start_index) return std::string("_t") + T_to_string(j); if (j >= m_columns_to_ext_vars_or_term_indices.size()) diff --git a/src/util/lp/lp_dual_core_solver.h b/src/util/lp/lp_dual_core_solver.h index ba4be494f..7aa572171 100644 --- a/src/util/lp/lp_dual_core_solver.h +++ b/src/util/lp/lp_dual_core_solver.h @@ -207,6 +207,6 @@ public: void solve(); - bool low_bounds_are_set() const { return true; } + bool low_bounds_are_set() const override { return true; } }; } diff --git a/src/util/lp/lp_dual_simplex.h b/src/util/lp/lp_dual_simplex.h index c17a9e99e..15463fc34 100644 --- a/src/util/lp/lp_dual_simplex.h +++ b/src/util/lp/lp_dual_simplex.h @@ -33,7 +33,7 @@ class lp_dual_simplex: public lp_solver { vector m_column_types_of_logicals; vector m_can_enter_basis; public: - ~lp_dual_simplex() { + ~lp_dual_simplex() override { if (m_core_solver != nullptr) { delete m_core_solver; } @@ -84,12 +84,12 @@ public: void copy_m_b_aside_and_set_it_to_zeros(); - void find_maximal_solution(); + void find_maximal_solution() override; - virtual T get_column_value(unsigned column) const { + T get_column_value(unsigned column) const override { return this->get_column_value_with_core_solver(column, m_core_solver); } - T get_current_cost() const; + T get_current_cost() const override; }; } diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index a7614862b..139cf3ad5 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -770,7 +770,7 @@ public: void init_reduced_costs(); - bool low_bounds_are_set() const { return true; } + bool low_bounds_are_set() const override { return true; } int advance_on_sorted_breakpoints(unsigned entering, X & t); diff --git a/src/util/lp/lp_primal_simplex.h b/src/util/lp/lp_primal_simplex.h index d8fd114e4..06ea26f8f 100644 --- a/src/util/lp/lp_primal_simplex.h +++ b/src/util/lp/lp_primal_simplex.h @@ -70,7 +70,7 @@ public: void set_core_solver_bounds(); - void find_maximal_solution(); + void find_maximal_solution() override; void fill_A_x_and_basis_for_stage_one_total_inf(); @@ -79,7 +79,7 @@ public: void solve_with_total_inf(); - ~lp_primal_simplex(); + ~lp_primal_simplex() override; bool bounds_hold(std::unordered_map const & solution); @@ -96,11 +96,11 @@ public: return bounds_hold(solution) && row_constraints_hold(solution); } - virtual T get_column_value(unsigned column) const { + T get_column_value(unsigned column) const override { return this->get_column_value_with_core_solver(column, m_core_solver); } - T get_current_cost() const; + T get_current_cost() const override; }; diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index a7e6e2665..cd9e78321 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -109,7 +109,7 @@ private: default_lp_resource_limit(lp_settings& s): m_settings(s) { m_sw.start(); } - virtual bool get_cancel_flag() { + bool get_cancel_flag() override { return (m_sw.get_current_seconds() > m_settings.time_limit); } }; diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h index 5498a1849..f9432c323 100644 --- a/src/util/lp/lu.h +++ b/src/util/lp/lu.h @@ -67,7 +67,7 @@ public: #endif } - bool is_dense() const { return false; } + bool is_dense() const override { return false; } one_elem_on_diag(const one_elem_on_diag & o); @@ -83,15 +83,15 @@ public: unsigned row_count() const { return m_m; } // not defined } unsigned column_count() const { return m_m; } // not defined } #endif - void apply_from_left(vector & w, lp_settings &) { + void apply_from_left(vector & w, lp_settings &) override { w[m_i] /= m_val; } - void apply_from_right(vector & w) { + void apply_from_right(vector & w) override { w[m_i] /= m_val; } - void apply_from_right(indexed_vector & w) { + void apply_from_right(indexed_vector & w) override { if (is_zero(w.m_data[m_i])) return; auto & v = w.m_data[m_i] /= m_val; @@ -102,7 +102,7 @@ public: } - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings); + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override; void conjugate_by_permutation(permutation_matrix & p) { // this = p * this * p(-1) diff --git a/src/util/lp/permutation_matrix.h b/src/util/lp/permutation_matrix.h index 7cf64a5c7..f080d45b9 100644 --- a/src/util/lp/permutation_matrix.h +++ b/src/util/lp/permutation_matrix.h @@ -64,7 +64,7 @@ class permutation_matrix : public tail_matrix { // create a unit permutation of the given length void init(unsigned length); unsigned get_rev(unsigned i) { return m_rev[i]; } - bool is_dense() const { return false; } + bool is_dense() const override { return false; } #ifdef Z3DEBUG permutation_matrix get_inverse() const { return permutation_matrix(size(), m_rev); @@ -76,13 +76,13 @@ class permutation_matrix : public tail_matrix { unsigned operator[](unsigned i) const { return m_permutation[i]; } - void apply_from_left(vector & w, lp_settings &); + void apply_from_left(vector & w, lp_settings &) override; - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings); + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override; - void apply_from_right(vector & w); + void apply_from_right(vector & w) override; - void apply_from_right(indexed_vector & w); + void apply_from_right(indexed_vector & w) override; template void copy_aside(vector & t, vector & tmp_index, indexed_vector & w); diff --git a/src/util/lp/row_eta_matrix.h b/src/util/lp/row_eta_matrix.h index c287e263a..f6fb4537d 100644 --- a/src/util/lp/row_eta_matrix.h +++ b/src/util/lp/row_eta_matrix.h @@ -50,7 +50,7 @@ public: m_row_start(row_start), m_row(row) { } - bool is_dense() const { return false; } + bool is_dense() const override { return false; } void print(std::ostream & out) { print_matrix(*this, out); @@ -60,12 +60,12 @@ public: return m_row_vector.m_data[m_row]; } - void apply_from_left(vector & w, lp_settings &); + void apply_from_left(vector & w, lp_settings &) override; void apply_from_left_local_to_T(indexed_vector & w, lp_settings & settings); void apply_from_left_local_to_X(indexed_vector & w, lp_settings & settings); - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override { apply_from_left_local_to_T(w, settings); } @@ -74,8 +74,8 @@ public: m_row_vector.push_back(row_index, val); } - void apply_from_right(vector & w); - void apply_from_right(indexed_vector & w); + void apply_from_right(vector & w) override; + void apply_from_right(indexed_vector & w) override; void conjugate_by_permutation(permutation_matrix & p); #ifdef Z3DEBUG diff --git a/src/util/lp/square_dense_submatrix.h b/src/util/lp/square_dense_submatrix.h index 3e88e8114..a2cade85a 100644 --- a/src/util/lp/square_dense_submatrix.h +++ b/src/util/lp/square_dense_submatrix.h @@ -70,7 +70,7 @@ public: void init(sparse_matrix *parent_matrix, unsigned index_start); - bool is_dense() const { return true; } + bool is_dense() const override { return true; } ref operator[] (unsigned i) { SASSERT(i >= m_index_start); @@ -137,13 +137,13 @@ public: bool is_L_matrix() const; - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { + void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override { apply_from_left_local(w, settings); } - void apply_from_right(indexed_vector & w) { + void apply_from_right(indexed_vector & w) override { #if 1==0 indexed_vector wcopy = w; apply_from_right(wcopy.m_data); @@ -207,11 +207,11 @@ public: w = m_work_vector; #endif } - void apply_from_left(vector & w, lp_settings & /*settings*/) { + void apply_from_left(vector & w, lp_settings & /*settings*/) override { apply_from_left_to_vector(w);// , settings); } - void apply_from_right(vector & w); + void apply_from_right(vector & w) override; #ifdef Z3DEBUG T get_elem (unsigned i, unsigned j) const; diff --git a/src/util/mpff.h b/src/util/mpff.h index 4fdd0baef..e34f2cb41 100644 --- a/src/util/mpff.h +++ b/src/util/mpff.h @@ -178,15 +178,15 @@ public: static bool field() { return true; } class exception : public z3_exception { - virtual char const * msg() const { return "multi-precision floating point (mpff) exception"; } + char const * msg() const override { return "multi-precision floating point (mpff) exception"; } }; class overflow_exception : public exception { - virtual char const * msg() const { return "multi-precision floating point (mpff) overflow"; } + char const * msg() const override { return "multi-precision floating point (mpff) overflow"; } }; class div0_exception : public exception { - virtual char const * msg() const { return "multi-precision floating point (mpff) division by zero"; } + char const * msg() const override { return "multi-precision floating point (mpff) division by zero"; } }; mpff_manager(unsigned prec = 2, unsigned initial_capacity = 1024); diff --git a/src/util/mpfx.h b/src/util/mpfx.h index 98f9bb322..03a805f69 100644 --- a/src/util/mpfx.h +++ b/src/util/mpfx.h @@ -125,15 +125,15 @@ public: static bool field() { return true; } class exception : public z3_exception { - virtual char const * msg() const { return "multi-precision fixed point (mpfx) exception"; } + char const * msg() const override { return "multi-precision fixed point (mpfx) exception"; } }; class overflow_exception : public exception { - virtual char const * msg() const { return "multi-precision fixed point (mpfx) overflow"; } + char const * msg() const override { return "multi-precision fixed point (mpfx) overflow"; } }; class div0_exception : public exception { - virtual char const * msg() const { return "multi-precision fixed point (mpfx) division by zero"; } + char const * msg() const override { return "multi-precision fixed point (mpfx) division by zero"; } }; mpfx_manager(unsigned int_sz = 2, unsigned frac_sz = 1, unsigned initial_capacity = 1024); diff --git a/src/util/timeout.cpp b/src/util/timeout.cpp index 67995c2aa..496c5c859 100644 --- a/src/util/timeout.cpp +++ b/src/util/timeout.cpp @@ -32,7 +32,7 @@ void (* g_on_timeout)() = 0; class g_timeout_eh : public event_handler { public: - void operator()(event_handler_caller_t caller_id) { + void operator()(event_handler_caller_t caller_id) override { #pragma omp critical (g_timeout_cs) { std::cout << "timeout\n"; diff --git a/src/util/trail.h b/src/util/trail.h index bba71fb00..adcd57860 100644 --- a/src/util/trail.h +++ b/src/util/trail.h @@ -43,10 +43,10 @@ public: m_old_value(value) { } - virtual ~value_trail() { + ~value_trail() override { } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_value = m_old_value; } }; @@ -59,10 +59,10 @@ public: m_value(value) { } - virtual ~reset_flag_trail() { + ~reset_flag_trail() override { } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_value = false; } }; @@ -76,7 +76,7 @@ public: SASSERT(m_ptr == 0); } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_ptr = 0; } }; @@ -94,9 +94,9 @@ public: m_vector(v), m_old_size(v.size()) { } - virtual ~restore_size_trail() { + ~restore_size_trail() override { } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_vector.shrink(m_old_size); } }; @@ -113,10 +113,10 @@ public: m_old_value(v[idx]) { } - virtual ~vector_value_trail() { + ~vector_value_trail() override { } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_vector[m_idx] = m_old_value; } }; @@ -128,8 +128,8 @@ class insert_obj_map : public trail { D* m_obj; public: insert_obj_map(obj_map& t, D* o) : m_map(t), m_obj(o) {} - virtual ~insert_obj_map() {} - virtual void undo(Ctx & ctx) { m_map.remove(m_obj); } + ~insert_obj_map() override {} + void undo(Ctx & ctx) override { m_map.remove(m_obj); } }; template @@ -138,8 +138,8 @@ class insert_map : public trail { D m_obj; public: insert_map(M& t, D o) : m_map(t), m_obj(o) {} - virtual ~insert_map() {} - virtual void undo(Ctx & ctx) { m_map.remove(m_obj); } + ~insert_map() override {} + void undo(Ctx & ctx) override { m_map.remove(m_obj); } }; @@ -152,7 +152,7 @@ public: m_vector(v) { } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_vector.pop_back(); } }; @@ -167,10 +167,10 @@ public: m_idx(idx) { } - virtual ~set_vector_idx_trail() { + ~set_vector_idx_trail() override { } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_vector[m_idx] = 0; } }; @@ -218,7 +218,7 @@ public: m_vector(v) { } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_vector.pop_back(); } }; @@ -251,7 +251,7 @@ public: m_vector[m_idx] = true; } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { m_vector[m_idx] = false; } }; @@ -264,7 +264,7 @@ public: m_obj(obj) { } - virtual void undo(Ctx & ctx) { + void undo(Ctx & ctx) override { dealloc(m_obj); } }; @@ -288,8 +288,8 @@ class insert_obj_trail : public trail { T* m_obj; public: insert_obj_trail(obj_hashtable& t, T* o) : m_table(t), m_obj(o) {} - virtual ~insert_obj_trail() {} - virtual void undo(Ctx & ctx) { m_table.remove(m_obj); } + ~insert_obj_trail() override {} + void undo(Ctx & ctx) override { m_table.remove(m_obj); } }; diff --git a/src/util/union_find.h b/src/util/union_find.h index 416b653af..9dd0b6fbd 100644 --- a/src/util/union_find.h +++ b/src/util/union_find.h @@ -52,8 +52,8 @@ class union_find { union_find & m_owner; public: mk_var_trail(union_find & o):m_owner(o) {} - virtual ~mk_var_trail() {} - virtual void undo(Ctx & ctx) { + ~mk_var_trail() override {} + void undo(Ctx & ctx) override { m_owner.m_find.pop_back(); m_owner.m_size.pop_back(); m_owner.m_next.pop_back(); @@ -70,8 +70,8 @@ class union_find { unsigned m_r1; public: merge_trail(union_find & o, unsigned r1):m_owner(o), m_r1(r1) {} - virtual ~merge_trail() {} - virtual void undo(Ctx & ctx) { m_owner.unmerge(m_r1); } + ~merge_trail() override {} + void undo(Ctx & ctx) override { m_owner.unmerge(m_r1); } }; void unmerge(unsigned r1) { From e183f8b7434d4f2db72c7b6eac3778b2f639396c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 21:46:45 -0800 Subject: [PATCH 0565/1283] disable lookahead simplification when external solver is used Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 2 ++ src/sat/sat_integrity_checker.cpp | 60 +++++++++++++++---------------- src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_simplifier.cpp | 8 +---- src/sat/sat_solver.cpp | 22 ++++-------- 5 files changed, 40 insertions(+), 54 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 117c9c6f8..412b81ccc 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2248,6 +2248,8 @@ namespace sat { display(verbose_stream(), c, true); if (c.lit() != null_literal) verbose_stream() << value(c.lit()) << "\n";); + IF_VERBOSE(0, s().display_watches(verbose_stream())); + UNREACHABLE(); exit(1); return false; diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index e0e285d56..7f56e2b36 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -38,7 +38,7 @@ namespace sat { if (w.is_clause()) { if (w.get_clause_offset() == cls_off) { // the blocked literal must be in the clause. - SASSERT(c.contains(w.get_blocked_literal())); + VERIFY(c.contains(w.get_blocked_literal())); return true; } } @@ -50,12 +50,12 @@ namespace sat { bool integrity_checker::check_clause(clause const & c) const { SASSERT(!c.was_removed()); for (unsigned i = 0; i < c.size(); i++) { - SASSERT(c[i].var() <= s.num_vars()); + VERIFY(c[i].var() <= s.num_vars()); CTRACE("sat_bug", s.was_eliminated(c[i].var()), tout << "l: " << c[i].var() << "\n"; tout << "c: " << c << "\n"; s.display(tout);); - SASSERT(!s.was_eliminated(c[i].var())); + VERIFY(!s.was_eliminated(c[i].var())); } SASSERT(c.check_approx()); @@ -88,7 +88,7 @@ namespace sat { CTRACE("sat_bug", s.value(c[i]) != l_false, tout << c << " status: " << s.status(c) << "\n"; for (unsigned i = 0; i < c.size(); i++) tout << "val(" << i << "): " << s.value(c[i]) << "\n";); - SASSERT(s.value(c[i]) == l_false); + VERIFY(s.value(c[i]) == l_false); } } } @@ -102,7 +102,7 @@ namespace sat { bool integrity_checker::check_clauses(clause * const * begin, clause * const * end) const { for (clause * const * it = begin; it != end; ++it) { - SASSERT(check_clause(*(*it))); + VERIFY(check_clause(*(*it))); } return true; } @@ -128,23 +128,23 @@ namespace sat { } bool integrity_checker::check_bool_vars() const { - SASSERT(s.m_watches.size() == s.num_vars() * 2); - SASSERT(s.m_assignment.size() == s.num_vars() * 2); - SASSERT(s.m_lit_mark.size() == s.num_vars() * 2); - SASSERT(s.m_justification.size() == s.num_vars()); - SASSERT(s.m_decision.size() == s.num_vars()); - SASSERT(s.m_eliminated.size() == s.num_vars()); - SASSERT(s.m_external.size() == s.num_vars()); - SASSERT(s.m_level.size() == s.num_vars()); - SASSERT(s.m_mark.size() == s.num_vars()); - SASSERT(s.m_activity.size() == s.num_vars()); - SASSERT(s.m_phase.size() == s.num_vars()); - SASSERT(s.m_prev_phase.size() == s.num_vars()); - SASSERT(s.m_assigned_since_gc.size() == s.num_vars()); + VERIFY(s.m_watches.size() == s.num_vars() * 2); + VERIFY(s.m_assignment.size() == s.num_vars() * 2); + VERIFY(s.m_lit_mark.size() == s.num_vars() * 2); + VERIFY(s.m_justification.size() == s.num_vars()); + VERIFY(s.m_decision.size() == s.num_vars()); + VERIFY(s.m_eliminated.size() == s.num_vars()); + VERIFY(s.m_external.size() == s.num_vars()); + VERIFY(s.m_level.size() == s.num_vars()); + VERIFY(s.m_mark.size() == s.num_vars()); + VERIFY(s.m_activity.size() == s.num_vars()); + VERIFY(s.m_phase.size() == s.num_vars()); + VERIFY(s.m_prev_phase.size() == s.num_vars()); + VERIFY(s.m_assigned_since_gc.size() == s.num_vars()); for (bool_var v = 0; v < s.num_vars(); v++) { if (s.was_eliminated(v)) { - SASSERT(s.get_wlist(literal(v, false)).empty()); - SASSERT(s.get_wlist(literal(v, true)).empty()); + VERIFY(s.get_wlist(literal(v, false)).empty()); + VERIFY(s.get_wlist(literal(v, true)).empty()); } } return true; @@ -158,7 +158,7 @@ namespace sat { for (watched const& w : wlist) { switch (w.get_kind()) { case watched::BINARY: - SASSERT(!s.was_eliminated(w.get_literal().var())); + VERIFY(!s.was_eliminated(w.get_literal().var())); CTRACE("sat_watched_bug", !s.get_wlist(~(w.get_literal())).contains(watched(l, w.is_learned())), tout << "l: " << l << " l2: " << w.get_literal() << "\n"; tout << "was_eliminated1: " << s.was_eliminated(l.var()); @@ -176,7 +176,7 @@ namespace sat { VERIFY(w.get_literal1().index() < w.get_literal2().index()); break; case watched::CLAUSE: - SASSERT(!s.m_cls_allocator.get_clause(w.get_clause_offset())->was_removed()); + VERIFY(!s.m_cls_allocator.get_clause(w.get_clause_offset())->was_removed()); break; default: break; @@ -194,7 +194,7 @@ namespace sat { tout << "l: " << l << "\n"; s.display_watches(tout); s.display(tout);); - SASSERT(!s.was_eliminated(l.var()) || wlist.empty()); + VERIFY(!s.was_eliminated(l.var()) || wlist.empty()); if (!check_watches(l, wlist)) return false; } @@ -203,7 +203,7 @@ namespace sat { bool integrity_checker::check_reinit_stack() const { for (auto const& c : s.m_clauses_to_reinit) { - SASSERT(c.is_binary() || c.get_clause()->on_reinit_stack()); + VERIFY(c.is_binary() || c.get_clause()->on_reinit_stack()); } return true; } @@ -225,12 +225,12 @@ namespace sat { bool integrity_checker::operator()() const { if (s.inconsistent()) return true; - SASSERT(check_clauses()); - SASSERT(check_learned_clauses()); - SASSERT(check_watches()); - SASSERT(check_bool_vars()); - SASSERT(check_reinit_stack()); - SASSERT(check_disjoint_clauses()); + VERIFY(check_clauses()); + VERIFY(check_learned_clauses()); + VERIFY(check_watches()); + VERIFY(check_bool_vars()); + VERIFY(check_reinit_stack()); + VERIFY(check_disjoint_clauses()); return true; } }; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index cd3b0e19b..460695edd 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2317,7 +2317,7 @@ namespace sat { } } } - m_lookahead.reset(); + m_lookahead.reset(); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index f773b05e7..b4f5ffeca 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -188,9 +188,6 @@ namespace sat { void simplifier::operator()(bool learned) { - integrity_checker si(s); - si.check_watches(); - if (s.inconsistent()) return; if (!m_subsumption && !bce_enabled() && !bca_enabled() && !elim_vars_enabled()) @@ -255,14 +252,12 @@ namespace sat { cleanup_clauses(s.m_learned, true, vars_eliminated, m_learned_in_use_lists); cleanup_clauses(s.m_clauses, false, vars_eliminated, true); } - si.check_watches(); CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); finalize(); - si.check_watches(); } /** @@ -285,7 +280,7 @@ namespace sat { break; } } - wlist.set_end(itprev); + wlist.set_end(itprev); } } @@ -1948,7 +1943,6 @@ namespace sat { return true; } } - return true; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 84a875d55..9db241199 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1505,8 +1505,6 @@ namespace sat { if (m_conflicts_since_init < m_next_simplify) { return; } - integrity_checker si(*this); - si.check_watches(); m_simplifications++; IF_VERBOSE(2, verbose_stream() << "(sat.simplify :simplifications " << m_simplifications << ")\n";); @@ -1518,17 +1516,14 @@ namespace sat { m_cleaner(); CASSERT("sat_simplify_bug", check_invariant()); - si.check_watches(); m_scc(); CASSERT("sat_simplify_bug", check_invariant()); - si.check_watches(); m_simplifier(false); CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); - si.check_watches(); if (!m_learned.empty()) { m_simplifier(true); CASSERT("sat_missed_prop", check_missed_propagation()); @@ -1540,26 +1535,18 @@ namespace sat { m_probing(); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); - m_asymm_branch(false); CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); - if (m_ext) { m_ext->clauses_modifed(); m_ext->simplify(); } - - if (m_config.m_lookahead_simplify) { + if (m_config.m_lookahead_simplify && !m_ext) { lookahead lh(*this); lh.simplify(true); lh.collect_statistics(m_aux_stats); } - if (false && m_config.m_lookahead_simplify) { - lookahead lh(*this); - lh.simplify(false); - lh.collect_statistics(m_aux_stats); - } TRACE("sat", display(tout << "consistent: " << (!inconsistent()) << "\n");); @@ -1574,6 +1561,7 @@ namespace sat { m_next_simplify = m_conflicts_since_init + m_config.m_simplify_max; } + if (m_par) m_par->set_phase(*this); #if 0 @@ -1756,6 +1744,8 @@ namespace sat { void solver::gc() { if (m_conflicts_since_gc <= m_gc_threshold) return; + if (m_config.m_gc_strategy == GC_DYN_PSM && !at_base_lvl()) + return; IF_VERBOSE(10, verbose_stream() << "(sat.gc)\n";); CASSERT("sat_gc_bug", check_invariant()); switch (m_config.m_gc_strategy) { @@ -3233,8 +3223,8 @@ namespace sat { bool solver::check_invariant() const { if (!m_rlimit.inc()) return true; integrity_checker checker(*this); - SASSERT(checker()); - SASSERT(!m_ext || m_ext->validate()); + VERIFY(checker()); + VERIFY(!m_ext || m_ext->validate()); return true; } From 4695ca16c84aa0de6b7b9360db5645baa0ee6102 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Feb 2018 11:43:33 -0800 Subject: [PATCH 0566/1283] perf improvements Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 2 +- src/sat/ba_solver.cpp | 16 ++++++++++++++-- src/sat/ba_solver.h | 8 +++++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 8125a651a..0157ca9ff 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -610,7 +610,7 @@ struct pb2bv_rewriter::imp { m_keep_pb_constraints(false), m_pb_num_system(false), m_pb_totalizer(false), - m_min_arity(2) + m_min_arity(3) {} bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 412b81ccc..d265ada75 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -213,13 +213,13 @@ namespace sat { return true; } - // ---------------------------- + // ---------------------------- // card bool ba_solver::init_watch(card& c) { - clear_watch(c); literal root = c.lit(); if (root != null_literal && value(root) == l_false) { + clear_watch(c); c.negate(); root.neg(); } @@ -240,6 +240,10 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) { if (value(c[i]) != l_false) { if (j != i) { + if (c.is_watched() && j <= bound && i > bound) { + unwatch_literal(c[j], c); + watch_literal(c[i], c); + } c.swap(i, j); } ++j; @@ -255,6 +259,7 @@ namespace sat { // j is the number of non-false, sz - j the number of false. if (j < bound) { + if (c.is_watched()) clear_watch(c); SASSERT(0 < bound && bound < sz); literal alit = c[j]; @@ -280,14 +285,19 @@ namespace sat { return false; } else { + if (c.is_watched()) return true; + clear_watch(c); for (unsigned i = 0; i <= bound; ++i) { watch_literal(c[i], c); } + c.set_watch(); return true; } } void ba_solver::clear_watch(card& c) { + if (c.is_clear()) return; + c.clear_watch(); unsigned sz = std::min(c.k() + 1, c.size()); for (unsigned i = 0; i < sz; ++i) { unwatch_literal(c[i], c); @@ -747,6 +757,7 @@ namespace sat { } void ba_solver::clear_watch(pb& p) { + p.clear_watch(); for (unsigned i = 0; i < p.num_watch(); ++i) { unwatch_literal(p[i].second, p); } @@ -896,6 +907,7 @@ namespace sat { // xr: void ba_solver::clear_watch(xr& x) { + x.clear_watch(); unwatch_literal(x[0], x); unwatch_literal(x[1], x); unwatch_literal(~x[0], x); diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 6b6d10c38..390025d63 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -63,6 +63,7 @@ namespace sat { tag_t m_tag; bool m_removed; literal m_lit; + literal m_watch; unsigned m_glue; unsigned m_psm; unsigned m_size; @@ -70,7 +71,8 @@ namespace sat { bool m_learned; unsigned m_id; public: - constraint(tag_t t, unsigned id, literal l, unsigned sz, size_t osz): m_tag(t), m_removed(false), m_lit(l), m_glue(0), m_psm(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id) {} + constraint(tag_t t, unsigned id, literal l, unsigned sz, size_t osz): + m_tag(t), m_removed(false), m_lit(l), m_watch(null_literal), m_glue(0), m_psm(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id) {} ext_constraint_idx index() const { return reinterpret_cast(this); } unsigned id() const { return m_id; } tag_t tag() const { return m_tag; } @@ -87,6 +89,10 @@ namespace sat { void set_psm(unsigned p) { m_psm = p; } void set_learned(bool f) { m_learned = f; } bool learned() const { return m_learned; } + bool is_watched() const { return m_watch == m_lit && m_lit != null_literal; } + void set_watch() { m_watch = m_lit; } + void clear_watch() { m_watch = null_literal; } + bool is_clear() const { return m_watch == null_literal && m_lit != null_literal; } size_t obj_size() const { return m_obj_size; } card& to_card(); From 8fb7fb9f987188a8125d85122285d9117342cf45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Feb 2018 19:27:00 -0800 Subject: [PATCH 0567/1283] add missing caching of PB/cardinality constraints, increase limit for compiling cardinalities to circuits Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 4 +- src/sat/ba_solver.cpp | 451 +++++++++++++++++++++++--- src/sat/ba_solver.h | 80 ++++- src/sat/sat_simplifier.cpp | 4 +- src/sat/sat_solver/inc_sat_solver.cpp | 6 +- src/sat/tactic/goal2sat.cpp | 44 ++- src/tactic/arith/lia2card_tactic.cpp | 18 - 7 files changed, 530 insertions(+), 77 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 0157ca9ff..179773c34 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -610,7 +610,7 @@ struct pb2bv_rewriter::imp { m_keep_pb_constraints(false), m_pb_num_system(false), m_pb_totalizer(false), - m_min_arity(3) + m_min_arity(9) {} bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { @@ -797,7 +797,7 @@ struct pb2bv_rewriter::imp { m_trail.push_back(l); return l; } - literal fresh(char const* n) { + literal fresh(char const* n) { expr_ref fr(m.mk_fresh_const(n, m.mk_bool_sort()), m); m_imp.m_fresh.push_back(to_app(fr)->get_decl()); return trail(fr); diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index d265ada75..ccc453650 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -47,6 +47,16 @@ namespace sat { return static_cast(*this); } + ba_solver::eq& ba_solver::constraint::to_eq() { + SASSERT(is_eq()); + return static_cast(*this); + } + + ba_solver::eq const& ba_solver::constraint::to_eq() const{ + SASSERT(is_eq()); + return static_cast(*this); + } + ba_solver::xr& ba_solver::constraint::to_xr() { SASSERT(is_xr()); return static_cast(*this); @@ -85,6 +95,15 @@ namespace sat { } break; } + case ba_solver::eq_t: { + ba_solver::eq const& e = cnstr.to_eq(); + for (ba_solver::eliteral wl : e) { + if (wl.weight != 1) out << wl.weight << " * "; + out << wl.lit << " "; + } + out << " = " << e.k(); + break; + } default: UNREACHABLE(); } @@ -186,6 +205,33 @@ namespace sat { } + // ----------------------------------- + // eq + + ba_solver::eq::eq(unsigned id, literal lit, svector const& wlits, unsigned k): + constraint(eq_t, id, lit, wlits.size(), eq::get_obj_size(wlits.size())), + m_lo(0), + m_hi(0), + m_max(0), + m_k(k) + { + unsigned i = 0; + for (wliteral const& w : wlits) { + m_wlits[i++] = eliteral(w.first, w.second); + m_max += w.first; + } + m_hi = m_max; + m_trail_sz = 0; + } + + unsigned ba_solver::eq::index(literal l) const { + for (unsigned i = 0; i < size(); ++i) { + if (l.var() == m_wlits[i].lit.var()) return i; + } + UNREACHABLE(); + return UINT_MAX; + } + // ----------------------------------- // xr @@ -451,7 +497,6 @@ namespace sat { // display(verbose_stream(), c, true); _bad_id = 11111111; SASSERT(p.well_formed()); - if (p.is_pb()) simplify2(p.to_pb()); m_simplify_change = true; } } @@ -847,28 +892,6 @@ namespace sat { } } - void ba_solver::simplify2(pb& p) { - return; - - if (p.is_cardinality()) { - literal_vector lits(p.literals()); - unsigned k = (p.k() + p[0].first - 1) / p[0].first; - add_at_least(p.lit(), lits, k, p.learned()); - remove_constraint(p, "simplified to cardinality"); - } - else if (p.lit() == null_literal) { - for (wliteral wl : p) { - if (p.k() > p.max_sum() - wl.first) { - TRACE("ba", - tout << "unit literal " << wl.second << "\n"; - display(tout, p, true);); - - s().assign(wl.second, justification()); - } - } - } - } - void ba_solver::display(std::ostream& out, pb const& p, bool values) const { if (p.lit() != null_literal) out << p.lit() << " == "; if (values) { @@ -902,6 +925,250 @@ namespace sat { out << ">= " << p.k() << "\n"; } + // -------------------- + // eq: + + ba_solver::constraint* ba_solver::add_eq(literal lit, svector const& wlits, unsigned k, bool learned) { + void * mem = m_allocator.allocate(eq::get_obj_size(wlits.size())); + eq* e = new (mem) eq(next_id(), lit, wlits, k); + e->set_learned(learned); + add_constraint(e); + for (eliteral const& wl : *e) { + watch_literal(wl.lit, *e); + watch_literal(~(wl.lit), *e); + } + return e; + } + + void ba_solver::display(std::ostream& out, eq const& e, bool values) const { + display_lit(out, e.lit(), e.size(), values); + if (values) { + if (e.trail_sz() > 0) { + out << "trail: "; + for (unsigned i = 0; i < e.trail_sz(); ++i) { + out << e[i].tweight << " * " << e[i].tlit << " "; + } + } + out << "[" << e.lo() << ":" << e.hi() << "] "; + } + for (eliteral wl : e) { + literal l = wl.lit; + unsigned w = wl.weight; + if (w > 1) out << w << " * "; + out << l; + if (values) { + out << "@(" << value(l); + if (value(l) != l_undef) { + out << ":" << lvl(l); + } + out << ") "; + } + else { + out << " "; + } + } + out << "= " << e.k() << "\n"; + } + + bool ba_solver::init_watch(eq& e) { + return true; + } + + void ba_solver::clear_watch(eq& e) { + for (eliteral const& wl : e) { + unwatch_literal(wl.lit, e); + unwatch_literal(~(wl.lit), e); + } + if (e.lit() != null_literal) { + unwatch_literal(e.lit(), e); + unwatch_literal(~e.lit(), e); + } + } + + /* + * \update the bounds for [lo,hi] based on what is unassigned on the trail. + */ + void ba_solver::pop_eq(eq& e) { + unsigned idx = e.trail_sz() - 1; + literal tlit = e[idx].tlit; + if (tlit.sign()) { + e.inc_hi(e[idx].tweight); + } + else { + e.dec_lo(e[idx].tweight); + } + e.set_trail_sz(idx); + } + + lbool ba_solver::add_assign(eq& e, literal nl) { + //IF_VERBOSE(0, verbose_stream() << nl << "@" << lvl(nl) << ": " << e << "\n"); + SASSERT(value(nl) == l_false); + if (nl.var() == e.lit().var()) { + // no-op + } + else { + unsigned i = e.index(nl); + eliteral wl = e[i]; + if (wl.lit == nl) { + e.dec_hi(wl); + } + else { + SASSERT(wl.lit == ~nl); + e.inc_lo(wl); + } + m_eq_to_pop.push_back(&e); + } + if (e.lo() > e.k() || e.hi() < e.k()) { + if (e.lit() == null_literal || value(e.lit()) == l_true) { + set_conflict(e, nl); + return l_false; + } + if (e.lit() != null_literal && value(e.lit()) == l_undef) { + assign(e, ~e.lit()); + } + } + else if (e.lo() == e.hi()) { + SASSERT(e.lo() == e.k()); + if (e.lit() != null_literal && value(e.lit()) == l_false) { + set_conflict(e, nl); + return l_false; + } + if (e.lit() != null_literal && value(e.lit()) == l_undef) { + assign(e, e.lit()); + } + } + else if ((e.lit() == null_literal || value(e.lit()) == l_true)) { + if (e.lo() == e.k()) { + for (eliteral el : e) { + if (value(el.lit) == l_undef) { + //IF_VERBOSE(0, display(verbose_stream() << "proapgate " << ~el.lit << " ", e, true)); + assign(e, ~el.lit); + } + } + } + else if (e.hi() == e.k()) { + for (eliteral el : e) { + if (value(el.lit) == l_undef) { + //IF_VERBOSE(0, display(verbose_stream() << "proapgate " << el.lit << " ", e, true)); + assign(e, el.lit); + } + } + } + } + return l_true; + } + + void ba_solver::simplify(eq& e) { + // no-op for now + } + + void ba_solver::recompile(eq& e) { + for (eliteral const& el : e) { + m_weights[el.lit.index()] += el.weight; + } + unsigned k = e.k(), sz = e.size(); + unsigned j = 0; + bool is_false = false; + for (unsigned i = 0; i < sz; ++i) { + eliteral el = e[i]; + unsigned w1 = m_weights[el.lit.index()]; + unsigned w2 = m_weights[(~el.lit).index()]; + if (w1 == 0 || w1 < w2) continue; + if (k < w2) { + is_false = true; + break; + } + k -= w2; + w1 -= w2; + if (w1 == 0) continue; + e[j++] = eliteral(w1, el.lit); + } + sz = j; + for (eliteral const& el : e) { + m_weights[el.lit.index()] = 0; + m_weights[(~el.lit).index()] = 0; + } + if (is_false) { + if (e.lit() == null_literal) { + s().mk_clause(0, 0, true); + } + else { + literal lit = ~e.lit(); + s().mk_clause(1, &lit, true); + } + remove_constraint(e, "recompiled to false"); + return; + } + // update trail + e.set_size(sz); + e.set_k(k); + for (unsigned i = 0; i < sz; ++i) { + e[i].tlit = null_literal; + } + e.set_trail_sz(0); + e.reset_lo(); + e.reset_hi(); + for (eliteral const& el : e) { + switch (value(el.lit)) { + case l_true: e.inc_lo(el); break; + case l_false: e.dec_hi(el); break; + default: break; + } + } + } + + void ba_solver::split_root(eq& e) { + NOT_IMPLEMENTED_YET(); + } + + void ba_solver::get_antecedents(literal l, eq const& e, literal_vector& r) { + for (eliteral wl : e) { + if (wl.lit.var() == l.var()) continue; + switch (value(wl.lit)) { + case l_true: r.push_back(wl.lit); break; + case l_false: r.push_back(~wl.lit); break; + default: break; + } + } + if (e.lit() != null_literal && l.var() != e.lit().var()) { + switch (value(e.lit())) { + case l_true: r.push_back(e.lit()); break; + case l_false: r.push_back(~e.lit()); break; + default: break; + } + } + } + + lbool ba_solver::eval(eq const& e) const { + unsigned trues = 0, undefs = 0; + for (eliteral wl : e) { + switch (value(wl.lit)) { + case l_true: trues += wl.weight; break; + case l_undef: undefs += wl.weight; break; + default: break; + } + } + if (trues + undefs < e.k()) return l_false; + if (trues > e.k()) return l_false; + if (trues == e.k() && undefs == 0) return l_true; + return l_undef; + } + + lbool ba_solver::eval(model const& m, eq const& e) const { + unsigned trues = 0, undefs = 0; + for (eliteral wl : e) { + switch (value(m, wl.lit)) { + case l_true: trues += wl.weight; break; + case l_undef: undefs += wl.weight; break; + default: break; + } + } + if (trues + undefs < e.k()) return l_false; + if (trues > e.k()) return l_false; + if (trues == e.k() && undefs == 0) return l_true; + return l_undef; + } + // -------------------- // xr: @@ -1245,6 +1512,17 @@ namespace sat { for (literal l : m_lemma) process_antecedent(~l, offset); break; } + case eq_t: { + eq& e = cnstr.to_eq(); + m_lemma.reset(); + inc_bound(offset); + inc_coeff(consequent, offset); + get_antecedents(consequent, e, m_lemma); + TRACE("ba", display(tout, e, true); tout << m_lemma << "\n";); + for (literal l : m_lemma) process_antecedent(~l, offset); + break; + + } default: UNREACHABLE(); break; @@ -1487,7 +1765,7 @@ namespace sat { void ba_solver::process_card(card& c, unsigned offset) { literal lit = c.lit(); SASSERT(c.k() <= c.size()); - SASSERT(lit == null_literal || value(lit) == l_true); + SASSERT(lit == null_literal || value(lit) != l_undef); SASSERT(0 < offset); for (unsigned i = c.k(); i < c.size(); ++i) { process_antecedent(c[i], offset); @@ -1500,9 +1778,12 @@ namespace sat { if (offset1 > UINT_MAX) { m_overflow = true; } - else { + if (value(lit) == l_true) { process_antecedent(~lit, static_cast(offset1)); } + else { + process_antecedent(lit, static_cast(offset1)); + } } } @@ -1607,6 +1888,7 @@ namespace sat { case card_t: return init_watch(c.to_card()); case pb_t: return init_watch(c.to_pb()); case xr_t: return init_watch(c.to_xr()); + case eq_t: return init_watch(c.to_eq()); } UNREACHABLE(); return false; @@ -1616,7 +1898,8 @@ namespace sat { switch (c.tag()) { case card_t: return add_assign(c.to_card(), l); case pb_t: return add_assign(c.to_pb(), l); - case xr_t: return add_assign(c.to_xr(), l); + case xr_t: return add_assign(c.to_xr(), l); + case eq_t: return add_assign(c.to_eq(), l); } UNREACHABLE(); return l_undef; @@ -1667,7 +1950,7 @@ namespace sat { init_watch(c); return true; } - else if (c.lit() != null_literal && value(c.lit()) != l_true) { + else if (c.lit() != null_literal && value(c.lit()) != l_true && c.tag() != eq_t) { return true; } else { @@ -1722,6 +2005,7 @@ namespace sat { case card_t: return get_reward(c.to_card(), occs); case pb_t: return get_reward(c.to_pb(), occs); case xr_t: return 0; + case eq_t: return 1; default: UNREACHABLE(); return 0; } } @@ -1982,8 +2266,9 @@ namespace sat { } SASSERT(found);); - if (c.lit() != null_literal) r.push_back(c.lit()); - SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); + // IF_VERBOSE(0, if (_debug_conflict) verbose_stream() << "ante " << l << " " << c << "\n"); + SASSERT(c.lit() == null_literal || value(c.lit()) != l_false); + if (c.lit() != null_literal) r.push_back(value(c.lit()) == l_true ? c.lit() : ~c.lit()); for (unsigned i = c.k(); i < c.size(); ++i) { SASSERT(value(c[i]) == l_false); r.push_back(~c[i]); @@ -2033,6 +2318,7 @@ namespace sat { case card_t: get_antecedents(l, c.to_card(), r); break; case pb_t: get_antecedents(l, c.to_pb(), r); break; case xr_t: get_antecedents(l, c.to_xr(), r); break; + case eq_t: get_antecedents(l, c.to_eq(), r); break; default: UNREACHABLE(); break; } } @@ -2056,6 +2342,9 @@ namespace sat { case xr_t: clear_watch(c.to_xr()); break; + case eq_t: + clear_watch(c.to_eq()); + break; default: UNREACHABLE(); } @@ -2078,6 +2367,7 @@ namespace sat { case card_t: return validate_unit_propagation(c.to_card(), l); case pb_t: return validate_unit_propagation(c.to_pb(), l); case xr_t: return true; + case eq_t: return validate_unit_propagation(c.to_eq(), l); default: UNREACHABLE(); break; } return false; @@ -2093,6 +2383,7 @@ namespace sat { case card_t: return eval(v1, eval(c.to_card())); case pb_t: return eval(v1, eval(c.to_pb())); case xr_t: return eval(v1, eval(c.to_xr())); + case eq_t: return eval(v1, eval(c.to_eq())); default: UNREACHABLE(); break; } return l_undef; @@ -2103,7 +2394,8 @@ namespace sat { switch (c.tag()) { case card_t: return eval(v1, eval(m, c.to_card())); case pb_t: return eval(v1, eval(m, c.to_pb())); - case xr_t: return eval(v1, eval(m, c.to_xr())); + case xr_t: return eval(v1, eval(m, c.to_xr())); + case eq_t: return eval(v1, eval(m, c.to_eq())); default: UNREACHABLE(); break; } return l_undef; @@ -2360,6 +2652,10 @@ namespace sat { SASSERT(0 < bound && bound <= sz); if (bound == sz) { + if (c.lit() != null_literal && value(c.lit()) == l_undef) { + assign(c, ~c.lit()); + return inconsistent() ? l_false : l_true; + } set_conflict(c, alit); return l_false; } @@ -2391,6 +2687,10 @@ namespace sat { // conflict if (bound != index && value(c[bound]) == l_false) { TRACE("ba", tout << "conflict " << c[bound] << " " << alit << "\n";); + if (c.lit() != null_literal && value(c.lit()) == l_undef) { + assign(c, ~c.lit()); + return inconsistent() ? l_false : l_true; + } set_conflict(c, alit); return l_false; } @@ -2403,6 +2703,11 @@ namespace sat { if (index != bound) { c.swap(index, bound); } + + if (c.lit() != null_literal && value(c.lit()) == l_undef) { + return l_true; + } + for (unsigned i = 0; i < bound; ++i) { assign(c, c[i]); } @@ -2425,6 +2730,7 @@ namespace sat { void ba_solver::push() { m_constraint_to_reinit_lim.push_back(m_constraint_to_reinit.size()); + m_eq_to_pop_lim.push_back(m_eq_to_pop.size()); } void ba_solver::pop(unsigned n) { @@ -2433,6 +2739,13 @@ namespace sat { m_constraint_to_reinit_last_sz = m_constraint_to_reinit_lim[new_lim]; m_constraint_to_reinit_lim.shrink(new_lim); m_num_propagations_since_pop = 0; + + new_lim = m_eq_to_pop_lim.size() - n; + for (unsigned i = m_eq_to_pop_lim[new_lim]; i < m_eq_to_pop.size(); ++i) { + pop_eq(*m_eq_to_pop[i]); + } + m_eq_to_pop.shrink(m_eq_to_pop_lim[new_lim]); + m_eq_to_pop_lim.shrink(new_lim); } void ba_solver::pop_reinit() { @@ -2451,16 +2764,16 @@ namespace sat { SASSERT(s().at_base_lvl()); switch (c.tag()) { case card_t: - if (!clausify(c.to_card())) - simplify(c.to_card()); + simplify(c.to_card()); break; case pb_t: - if (!clausify(c.to_pb())) - simplify(c.to_pb()); + simplify(c.to_pb()); break; case xr_t: - if (!clausify(c.to_xr())) - simplify(c.to_xr()); + simplify(c.to_xr()); + break; + case eq_t: + simplify(c.to_eq()); break; default: UNREACHABLE(); @@ -2498,6 +2811,7 @@ namespace sat { << " :gc " << m_stats.m_num_gc << ")\n";); + // IF_VERBOSE(0, s().display(verbose_stream())); // mutex_reduction(); // if (s().m_clauses.size() < 80000) lp_lookahead_reduction(); @@ -2616,6 +2930,9 @@ namespace sat { case pb_t: recompile(c.to_pb()); break; + case eq_t: + recompile(c.to_eq()); + break; case xr_t: NOT_IMPLEMENTED_YET(); break; @@ -2631,7 +2948,6 @@ namespace sat { if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; // IF_VERBOSE(0, verbose_stream() << c << "\n";); m_weights.resize(2*s().num_vars(), 0); - // for (unsigned w : m_weights) VERIFY(w == 0); for (literal l : c) { ++m_weights[l.index()]; } @@ -2828,6 +3144,7 @@ namespace sat { case card_t: split_root(c.to_card()); break; case pb_t: split_root(c.to_pb()); break; case xr_t: NOT_IMPLEMENTED_YET(); break; + case eq_t: split_root(c.to_eq()); break; } } @@ -2948,6 +3265,15 @@ namespace sat { } break; } + case eq_t: { + eq& e = cp->to_eq(); + for (eliteral wl : e) { + literal l = wl.lit; + m_cnstr_use_list[l.index()].push_back(&e); + m_cnstr_use_list[(~l).index()].push_back(&e); + } + break; + } } } } @@ -2970,6 +3296,8 @@ namespace sat { } break; } + case eq_t: + break; default: break; } @@ -3044,6 +3372,8 @@ namespace sat { if (p.k() > 1) subsumption(p); break; } + case eq_t: + break; default: break; } @@ -3185,6 +3515,8 @@ namespace sat { case pb_t: s = subsumes(p1, c->to_pb()); break; + case eq_t: + break; default: break; } @@ -3413,6 +3745,15 @@ namespace sat { result->add_xr(lits, x.learned()); break; } + case eq_t: { + eq const& e = cp->to_eq(); + wlits.reset(); + for (eliteral w : e) { + wlits.push_back(wliteral(w.weight, w.lit)); + } + result->add_eq(e.lit(), wlits, e.k(), e.learned()); + break; + } default: UNREACHABLE(); } @@ -3450,6 +3791,14 @@ namespace sat { } break; } + case eq_t: { + eq const& e = cp->to_eq(); + for (eliteral w : e) { + ul.insert(w.lit, idx); + ul.insert(~(w.lit), idx); + } + break; + } default: UNREACHABLE(); } @@ -3491,6 +3840,8 @@ namespace sat { } return weight >= p.k(); } + case eq_t: + break; default: break; } @@ -3555,20 +3906,24 @@ namespace sat { out << "\n"; } - void ba_solver::display(std::ostream& out, card const& c, bool values) const { - if (c.lit() != null_literal) { + void ba_solver::display_lit(std::ostream& out, literal lit, unsigned sz, bool values) const { + if (lit != null_literal) { if (values) { - out << c.lit() << "[" << c.size() << "]"; - out << "@(" << value(c.lit()); - if (value(c.lit()) != l_undef) { - out << ":" << lvl(c.lit()); + out << lit << "[" << sz << "]"; + out << "@(" << value(lit); + if (value(lit) != l_undef) { + out << ":" << lvl(lit); } out << "): "; } else { - out << c.lit() << " == "; + out << lit << " == "; } } + } + + void ba_solver::display(std::ostream& out, card const& c, bool values) const { + display_lit(out, c.lit(), c.size(), values); for (unsigned i = 0; i < c.size(); ++i) { literal l = c[i]; out << l; @@ -3608,6 +3963,7 @@ namespace sat { case card_t: display(out, c.to_card(), values); break; case pb_t: display(out, c.to_pb(), values); break; case xr_t: display(out, c.to_xr(), values); break; + case eq_t: display(out, c.to_eq(), values); break; default: UNREACHABLE(); break; } } @@ -3924,6 +4280,13 @@ namespace sat { if (lxr != null_literal) ineq.push(~lxr, offset); break; } + case eq_t: { + eq& e = cnstr.to_eq(); + ineq.reset(e.k()); + for (eliteral wl : e) ineq.push(wl.lit, wl.weight); + if (e.lit() != null_literal) ineq.push(~e.lit(), e.k()); + break; + } default: UNREACHABLE(); break; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 390025d63..e63cd5333 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -51,12 +51,14 @@ namespace sat { enum tag_t { card_t, pb_t, - xr_t + xr_t, + eq_t }; class card; class pb; class xr; + class eq; class constraint { protected: @@ -98,12 +100,15 @@ namespace sat { card& to_card(); pb& to_pb(); xr& to_xr(); + eq& to_eq(); card const& to_card() const; pb const& to_pb() const; xr const& to_xr() const; + eq const& to_eq() const; bool is_card() const { return m_tag == card_t; } bool is_pb() const { return m_tag == pb_t; } bool is_xr() const { return m_tag == xr_t; } + bool is_eq() const { return m_tag == eq_t; } virtual bool is_watching(literal l) const { UNREACHABLE(); return false; }; virtual literal_vector literals() const { UNREACHABLE(); return literal_vector(); } @@ -180,6 +185,60 @@ namespace sat { virtual unsigned get_coeff(unsigned i) const { return m_wlits[i].first; } }; + struct eliteral { + unsigned weight; + literal lit; + unsigned tweight; + literal tlit; + eliteral(unsigned w, literal lit): + weight(w), lit(lit), tweight(0), tlit(null_literal) + {} + eliteral(): weight(0), lit(null_literal), tweight(0), tlit(null_literal) {} + }; + class eq : public constraint { + unsigned m_lo, m_hi, m_max, m_k, m_trail_sz; + eliteral m_wlits[0]; + public: + static size_t get_obj_size(unsigned num_lits) { return sizeof(eq) + num_lits * sizeof(eliteral); } + eq(unsigned id, literal lit, svector const& wlits, unsigned k); + literal lit() const { return m_lit; } + eliteral operator[](unsigned i) const { return m_wlits[i]; } + eliteral& operator[](unsigned i) { return m_wlits[i]; } + eliteral const* begin() const { return m_wlits; } + eliteral const* end() const { return begin() + m_size; } + unsigned index(literal l) const; + unsigned k() const { return m_k; } + void reset_lo() { m_lo = 0; } + void reset_hi() { m_hi = m_max; } + unsigned lo() const { return m_lo; } + unsigned hi() const { return m_hi; } + void inc_hi(unsigned d) { m_hi += d; } + void dec_lo(unsigned d) { SASSERT(d <= m_lo); m_lo -= d; } + // increment/decrement lo/hi save delta and variable in a trail. + void inc_lo(eliteral const& e) { + m_lo += e.weight; + m_wlits[m_trail_sz].tlit = literal(e.lit.var(), false); + m_wlits[m_trail_sz++].tweight = e.weight; + } + void dec_hi(eliteral const& e) { + m_hi -= e.weight; + m_wlits[m_trail_sz].tlit = literal(e.lit.var(), true); + m_wlits[m_trail_sz++].tweight = e.weight; + } + unsigned trail_sz() const { return m_trail_sz; } + void set_trail_sz(unsigned sz) { m_trail_sz = sz; } + + virtual void negate() { SASSERT(lit() != null_literal); m_lit.neg(); } + virtual void set_k(unsigned k) { m_k = k; } + virtual void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } + virtual literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.lit); return lits; } + virtual bool is_watching(literal l) const { return true; } + virtual literal get_lit(unsigned i) const { return m_wlits[i].lit; } + virtual void set_lit(unsigned i, literal l) { m_wlits[i].lit = l; } + virtual unsigned get_coeff(unsigned i) const { return m_wlits[i].weight; } + + }; + class xr : public constraint { literal m_lits[0]; public: @@ -222,6 +281,8 @@ namespace sat { unsigned_vector m_constraint_to_reinit_lim; unsigned m_constraint_to_reinit_last_sz; unsigned m_constraint_id; + ptr_vector m_eq_to_pop; + unsigned_vector m_eq_to_pop_lim; // conflict resolution unsigned m_num_marks; @@ -390,6 +451,19 @@ namespace sat { lbool eval(model const& m, pb const& p) const; double get_reward(pb const& p, literal_occs_fun& occs) const; + // eq functionality + void pop_eq(eq& e); + bool init_watch(eq& e); + void clear_watch(eq& e); + lbool add_assign(eq& e, literal alit); + void get_antecedents(literal l, eq const& e, literal_vector& r); + void simplify(eq& e); + void recompile(eq& e); + void split_root(eq& e); + void calibrate(eq& e); + lbool eval(eq const& e) const; + lbool eval(model const& m, eq const& e) const; + // access solver inline lbool value(bool_var v) const { return value(literal(v, false)); } inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } @@ -467,10 +541,13 @@ namespace sat { void display(std::ostream& out, card const& c, bool values) const; void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xr const& c, bool values) const; + void display(std::ostream& out, eq const& e, bool values) const; + void display_lit(std::ostream& out, literal l, unsigned sz, bool values) const; constraint* add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned); constraint* add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); constraint* add_xr(literal_vector const& lits, bool learned); + constraint* add_eq(literal l, svector const& wlits, unsigned k, bool learned); void copy_core(ba_solver* result, bool learned); void copy_constraints(ba_solver* result, ptr_vector const& constraints); @@ -484,6 +561,7 @@ namespace sat { void add_at_least(bool_var v, literal_vector const& lits, unsigned k); void add_pb_ge(bool_var v, svector const& wlits, unsigned k); void add_xr(literal_vector const& lits); + void add_eq(literal l, svector const& wlits, unsigned k) { add_eq(l, wlits, k, false); } virtual bool propagate(literal l, ext_constraint_idx idx); virtual lbool resolve_conflict(); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index b4f5ffeca..c52b36417 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1052,10 +1052,10 @@ namespace sat { // Find literals that are in the intersection of all resolvents with l. // bool resolution_intersection(literal l, bool adding) { - if (!process_var(l.var())) return false; - bool first = true; reset_intersection(); m_tautology.reset(); + if (!process_var(l.var())) return false; + bool first = true; for (watched & w : s.get_wlist(l)) { // when adding a blocked clause, then all non-learned clauses have to be considered for the // resolution intersection. diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index c6d6b4cac..0f74fac8b 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -60,7 +60,6 @@ class inc_sat_solver : public solver { sat::literal_vector m_asms; goal_ref_buffer m_subgoals; proof_converter_ref m_pc; - model_converter_ref m_mc; mutable model_converter_ref m_mc0; mutable obj_hashtable m_inserted_const2bits; mutable ref m_sat_mc; @@ -120,7 +119,6 @@ public: for (unsigned a : m_asms_lim) result->m_asms_lim.push_back(a); for (unsigned h : m_fmls_head_lim) result->m_fmls_head_lim.push_back(h); for (expr* f : m_internalized_fmls) result->m_internalized_fmls.push_back(tr(f)); - if (m_mc) result->m_mc = m_mc->translate(tr); if (m_mc0) result->m_mc0 = m_mc0->translate(tr); if (m_sat_mc) result->m_sat_mc = dynamic_cast(m_sat_mc->translate(tr)); // copy m_bb_rewriter? @@ -189,6 +187,7 @@ public: init_reason_unknown(); try { + // IF_VERBOSE(0, m_solver.display(verbose_stream())); r = m_solver.check(m_asms.size(), m_asms.c_ptr()); } catch (z3_exception& ex) { @@ -526,7 +525,6 @@ private: lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm, bool is_lemma) { - m_mc.reset(); m_pc.reset(); m_subgoals.reset(); init_preprocess(); @@ -553,7 +551,7 @@ private: g = m_subgoals[0]; expr_ref_vector atoms(m); m_pc = g->pc(); - m_mc = g->mc(); + m_mc0 = concat(m_mc0.get(), g->mc()); TRACE("sat", g->display_with_dependencies(tout);); // ensure that if goal is already internalized, then import mc from m_solver. diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index d6d6c0892..7323dc6b8 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -491,6 +491,7 @@ struct goal2sat::imp { } void convert_pb_eq(app* t, bool root, bool sign) { + IF_VERBOSE(0, verbose_stream() << "pbeq: " << mk_pp(t, m) << "\n";); rational k = pb.get_k(t); SASSERT(k.is_unsigned()); svector wlits; @@ -515,11 +516,13 @@ struct goal2sat::imp { mk_clause(~l, l1); mk_clause(~l, l2); mk_clause(~l1, ~l2, l); + m_cache.insert(t, l); m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); - m_result_stack.push_back(sign ? ~l : l); + if (sign) l.neg(); + m_result_stack.push_back(l); if (root) { m_result_stack.reset(); - mk_clause(~l); + mk_clause(l); } } } @@ -535,8 +538,10 @@ struct goal2sat::imp { } else { sat::bool_var v = m_solver.mk_var(true); - sat::literal lit(v, sign); + sat::literal lit(v, false); m_ext->add_at_least(v, lits, k.get_unsigned()); + m_cache.insert(t, lit); + if (sign) lit.neg(); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); m_result_stack.shrink(sz - t->get_num_args()); m_result_stack.push_back(lit); @@ -557,15 +562,39 @@ struct goal2sat::imp { } else { sat::bool_var v = m_solver.mk_var(true); - sat::literal lit(v, sign); + sat::literal lit(v, false); m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); + m_cache.insert(t, lit); m_result_stack.shrink(sz - t->get_num_args()); + if (sign) lit.neg(); m_result_stack.push_back(lit); } } void convert_eq_k(app* t, rational const& k, bool root, bool sign) { SASSERT(k.is_unsigned()); +#if 0 + IF_VERBOSE(0, verbose_stream() << t->get_id() << ": " << mk_pp(t, m) << "\n";); + svector wlits; + convert_pb_args(t, wlits); + if (root && !sign) { + m_ext->add_eq(sat::null_literal, wlits, k.get_unsigned()); + m_result_stack.reset(); + } + else { + sat::bool_var v = m_solver.mk_var(); + sat::literal l(v, false); + m_ext->add_eq(l, wlits, k.get_unsigned()); + m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); + m_cache.insert(t, l); + if (sign) l.neg(); + m_result_stack.push_back(l); + if (root) { + mk_clause(l); + m_result_stack.reset(); + } + } +#else sat::literal_vector lits; convert_pb_args(t->get_num_args(), lits); sat::bool_var v1 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true); @@ -587,13 +616,16 @@ struct goal2sat::imp { mk_clause(~l, l1); mk_clause(~l, l2); mk_clause(~l1, ~l2, l); + m_cache.insert(t, l); m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); - m_result_stack.push_back(sign ? ~l : l); + if (sign) l.neg(); + m_result_stack.push_back(l); if (root) { - mk_clause(~l); + mk_clause(l); m_result_stack.reset(); } } +#endif } void ensure_extension() { diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index e598b876d..9f9288753 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -15,24 +15,6 @@ Author: Notes: ---*/ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - lia2card_tactic.cpp - -Abstract: - - Convert 0-1 integer variables cardinality constraints to built-in cardinality operator. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-11-5 - -Notes: - --*/ #include "util/cooperate.h" #include "ast/ast_pp.h" From bb4888ce31e7ac0762007adfcffd4001fde3f348 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Feb 2018 21:21:55 -0800 Subject: [PATCH 0568/1283] support self-subsumption, remove verbose log 0 Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 28 ++++++++++++++-------------- src/sat/sat_solver.cpp | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index ccc453650..6adaa1ef6 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -3439,7 +3439,7 @@ namespace sat { - A >= k subsumes A + B >= k' for k' <= k - A + A' >= k subsumes A + B >= k' for k' + |A'| <= k - A + lit >= k self subsumes A + ~lit + B >= k' into A + B >= k' for k' <= k - - TBD: consider version that generalizes self-subsumption to more than one literal + - version that generalizes self-subsumption to more than one literal A + ~L + B >= k' => A + B >= k' if A + A' + L >= k and k' + |L| + |A'| <= k */ bool ba_solver::subsumes(card& c1, card& c2, literal_vector & comp) { @@ -3480,12 +3480,14 @@ namespace sat { } } - if (!comp.empty()) { - // self-subsumption is TBD. + unsigned c1_exclusive = c1.size() - common - comp.size(); + bool result = c1_exclusive + 1 <= c1.k(); + + if (!comp.empty() && result) { + IF_VERBOSE(10, verbose_stream() << "self-subsume clause " << c2 << " is TBD\n";); return false; } - unsigned c1_exclusive = c1.size() - common - comp.size(); - return c1_exclusive + 1 <= c1.k(); + return result; } /* @@ -3559,22 +3561,20 @@ namespace sat { } else { TRACE("ba", tout << "self subsume cardinality\n";); - IF_VERBOSE(0, - verbose_stream() << "self-subsume cardinality is TBD\n"; + IF_VERBOSE(11, + verbose_stream() << "self-subsume cardinality\n"; verbose_stream() << c1 << "\n"; verbose_stream() << c2 << "\n";); -#if 0 clear_watch(c2); + unsigned j = 0; for (unsigned i = 0; i < c2.size(); ++i) { - if (slit == c2[i]) { - c2.swap(i, c2.size() -1); - break; + if (!is_marked(~c2[i])) { + c2[j++] = c2[i]; } } - c2.set_size(c2.size() - 1); + c2.set_size(j); init_watch(c2); m_simplify_change = true; -#endif } } } @@ -3594,7 +3594,7 @@ namespace sat { c1.set_learned(false); } else { - IF_VERBOSE(0, verbose_stream() << "self-subsume clause is TBD\n";); + IF_VERBOSE(11, verbose_stream() << "self-subsume clause is TBD\n";); // remove literal slit from c2. TRACE("ba", tout << "TBD remove literals " << slit << " from " << c2 << "\n";); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 9db241199..8c7450a61 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1860,7 +1860,7 @@ namespace sat { void solver::gc_half(char const * st_name) { TRACE("sat", tout << "gc\n";); unsigned sz = m_learned.size(); - unsigned new_sz = sz/2; + unsigned new_sz = sz/2; // std::min(sz/2, m_clauses.size()*2); unsigned j = new_sz; for (unsigned i = new_sz; i < sz; i++) { clause & c = *(m_learned[i]); From 76eb7b9edec29f0583255855d3ff2f89e3ad8d80 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 12 Feb 2018 14:05:55 +0700 Subject: [PATCH 0569/1283] Use nullptr. --- .../ackermannize_bv_tactic.cpp | 10 +- src/ackermannization/ackr_bound_probe.cpp | 2 +- src/ackermannization/ackr_info.h | 2 +- src/ackermannization/ackr_model_converter.cpp | 4 +- src/ackermannization/lackr.cpp | 8 +- .../lackr_model_constructor.cpp | 14 +- src/api/api_algebraic.cpp | 46 ++-- src/api/api_arith.cpp | 36 +-- src/api/api_array.cpp | 50 ++-- src/api/api_ast.cpp | 104 ++++---- src/api/api_ast_map.cpp | 14 +- src/api/api_ast_vector.cpp | 12 +- src/api/api_bv.cpp | 30 +-- src/api/api_config_params.cpp | 2 +- src/api/api_context.cpp | 20 +- src/api/api_datalog.cpp | 42 +-- src/api/api_datalog.h | 2 +- src/api/api_datalog_spacer.inc | 8 +- src/api/api_datatype.cpp | 74 ++--- src/api/api_fpa.cpp | 252 +++++++++--------- src/api/api_goal.cpp | 10 +- src/api/api_goal.h | 2 +- src/api/api_interp.cpp | 20 +- src/api/api_log.cpp | 16 +- src/api/api_model.cpp | 64 ++--- src/api/api_model.h | 4 +- src/api/api_numeral.cpp | 28 +- src/api/api_opt.cpp | 22 +- src/api/api_params.cpp | 12 +- src/api/api_parsers.cpp | 8 +- src/api/api_pb.cpp | 10 +- src/api/api_polynomial.cpp | 4 +- src/api/api_qe.cpp | 14 +- src/api/api_quant.cpp | 54 ++-- src/api/api_rcf.cpp | 24 +- src/api/api_seq.cpp | 10 +- src/api/api_solver.cpp | 46 ++-- src/api/api_solver.h | 2 +- src/api/api_tactic.cpp | 76 +++--- src/api/api_tactic.h | 4 +- src/api/api_util.h | 4 +- src/api/z3_replayer.cpp | 8 +- src/ast/act_cache.cpp | 4 +- src/ast/arith_decl_plugin.cpp | 114 ++++---- src/ast/array_decl_plugin.cpp | 82 +++--- src/ast/array_decl_plugin.h | 6 +- src/ast/ast.cpp | 224 ++++++++-------- src/ast/ast.h | 106 ++++---- src/ast/ast_ll_pp.cpp | 4 +- src/ast/ast_pp.h | 4 +- src/ast/ast_pp_util.cpp | 2 +- src/ast/ast_printer.cpp | 2 +- src/ast/ast_smt2_pp.cpp | 16 +- src/ast/ast_smt2_pp.h | 6 +- src/ast/ast_smt_pp.cpp | 4 +- src/ast/ast_smt_pp.h | 6 +- src/ast/ast_translation.cpp | 8 +- src/ast/ast_util.cpp | 2 +- src/ast/bv_decl_plugin.cpp | 50 ++-- src/ast/bv_decl_plugin.h | 2 +- src/ast/datatype_decl_plugin.cpp | 44 +-- src/ast/datatype_decl_plugin.h | 6 +- src/ast/dl_decl_plugin.cpp | 152 +++++------ src/ast/dl_decl_plugin.h | 4 +- src/ast/expr2polynomial.cpp | 10 +- src/ast/expr2var.cpp | 2 +- src/ast/expr_abstract.cpp | 2 +- src/ast/expr_delta_pair.h | 2 +- src/ast/expr_functors.cpp | 10 +- src/ast/expr_functors.h | 2 +- src/ast/expr_map.cpp | 6 +- src/ast/expr_substitution.cpp | 6 +- src/ast/expr_substitution.h | 6 +- src/ast/factor_equivs.cpp | 4 +- src/ast/format.cpp | 10 +- src/ast/fpa/bv2fpa_converter.cpp | 12 +- src/ast/fpa/bv2fpa_converter.h | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 20 +- src/ast/fpa/fpa2bv_rewriter.cpp | 4 +- src/ast/fpa_decl_plugin.cpp | 24 +- src/ast/fpa_decl_plugin.h | 2 +- src/ast/func_decl_dependencies.cpp | 4 +- src/ast/func_decl_dependencies.h | 2 +- src/ast/macro_substitution.cpp | 6 +- src/ast/macro_substitution.h | 2 +- src/ast/macros/macro_finder.cpp | 18 +- src/ast/macros/macro_manager.cpp | 16 +- src/ast/macros/macro_manager.h | 4 +- src/ast/macros/macro_util.cpp | 32 +-- src/ast/macros/macro_util.h | 2 +- src/ast/macros/quasi_macros.cpp | 12 +- src/ast/normal_forms/defined_names.cpp | 2 +- src/ast/normal_forms/name_exprs.cpp | 6 +- src/ast/normal_forms/nnf.cpp | 26 +- src/ast/normal_forms/pull_quant.cpp | 12 +- src/ast/pattern/expr_pattern_match.cpp | 2 +- src/ast/pattern/expr_pattern_match.h | 4 +- src/ast/pattern/pattern_inference.cpp | 22 +- src/ast/pattern/pattern_inference.h | 2 +- src/ast/pb_decl_plugin.cpp | 6 +- src/ast/pb_decl_plugin.h | 2 +- src/ast/proofs/proof_checker.cpp | 20 +- src/ast/proofs/proof_utils.cpp | 10 +- src/ast/recurse_expr_def.h | 2 +- src/ast/rewriter/arith_rewriter.cpp | 10 +- src/ast/rewriter/bit2int.cpp | 2 +- src/ast/rewriter/bit2int.h | 2 +- .../bit_blaster/bit_blaster_rewriter.cpp | 10 +- src/ast/rewriter/bool_rewriter.cpp | 2 +- src/ast/rewriter/bool_rewriter.h | 2 +- src/ast/rewriter/bv_bounds.cpp | 10 +- src/ast/rewriter/bv_bounds.h | 2 +- src/ast/rewriter/bv_elim.cpp | 2 +- src/ast/rewriter/bv_rewriter.cpp | 18 +- src/ast/rewriter/bv_trailing.cpp | 22 +- src/ast/rewriter/der.cpp | 12 +- src/ast/rewriter/distribute_forall.h | 2 +- src/ast/rewriter/elim_bounds.cpp | 22 +- src/ast/rewriter/enum2bv_rewriter.cpp | 4 +- src/ast/rewriter/expr_replacer.cpp | 12 +- src/ast/rewriter/expr_safe_replace.cpp | 2 +- src/ast/rewriter/factor_rewriter.h | 2 +- src/ast/rewriter/fpa_rewriter.cpp | 6 +- src/ast/rewriter/inj_axiom.cpp | 8 +- src/ast/rewriter/maximize_ac_sharing.cpp | 4 +- src/ast/rewriter/maximize_ac_sharing.h | 2 +- src/ast/rewriter/mk_extract_proc.cpp | 4 +- src/ast/rewriter/mk_simplified_app.cpp | 2 +- src/ast/rewriter/pb2bv_rewriter.cpp | 2 +- src/ast/rewriter/poly_rewriter.h | 2 +- src/ast/rewriter/poly_rewriter_def.h | 22 +- src/ast/rewriter/pull_ite_tree.cpp | 34 +-- src/ast/rewriter/push_app_ite.cpp | 2 +- src/ast/rewriter/rewriter.cpp | 10 +- src/ast/rewriter/rewriter_def.h | 58 ++-- src/ast/rewriter/seq_rewriter.cpp | 28 +- src/ast/rewriter/th_rewriter.cpp | 28 +- src/ast/rewriter/var_subst.cpp | 4 +- src/ast/seq_decl_plugin.cpp | 32 +-- src/ast/seq_decl_plugin.h | 4 +- src/ast/substitution/expr_offset.h | 2 +- src/ast/substitution/substitution.cpp | 12 +- src/ast/substitution/substitution.h | 2 +- src/ast/substitution/substitution_tree.cpp | 18 +- src/ast/substitution/substitution_tree.h | 2 +- src/cmd_context/basic_cmds.cpp | 8 +- src/cmd_context/check_logic.cpp | 10 +- src/cmd_context/cmd_context.cpp | 128 ++++----- src/cmd_context/cmd_context.h | 14 +- src/cmd_context/cmd_context_to_goal.cpp | 4 +- src/cmd_context/context_params.cpp | 4 +- src/cmd_context/eval_cmd.cpp | 4 +- src/cmd_context/extra_cmds/dbg_cmds.cpp | 10 +- .../extra_cmds/polynomial_cmds.cpp | 16 +- src/cmd_context/interpolant_cmds.cpp | 4 +- src/cmd_context/parametric_cmd.cpp | 2 +- src/cmd_context/parametric_cmd.h | 2 +- src/cmd_context/pdecl.cpp | 56 ++-- src/cmd_context/pdecl.h | 10 +- src/cmd_context/simplify_cmd.cpp | 8 +- src/cmd_context/tactic_cmds.cpp | 20 +- src/cmd_context/tactic_manager.cpp | 4 +- src/duality/duality.h | 36 +-- src/duality/duality_profiling.cpp | 2 +- src/duality/duality_rpfp.cpp | 14 +- src/duality/duality_solver.cpp | 42 +-- src/duality/duality_wrapper.cpp | 16 +- src/duality/duality_wrapper.h | 24 +- src/interp/iz3base.cpp | 4 +- src/interp/iz3checker.cpp | 4 +- src/interp/iz3hash.h | 18 +- src/interp/iz3interp.cpp | 12 +- src/interp/iz3interp.h | 4 +- src/interp/iz3mgr.cpp | 14 +- src/interp/iz3mgr.h | 6 +- src/interp/iz3profiling.cpp | 2 +- src/interp/iz3proof.h | 2 +- src/interp/iz3translate.cpp | 2 +- src/interp/iz3translate_direct.cpp | 12 +- src/math/automata/automaton.h | 8 +- src/math/automata/symbolic_automata_def.h | 2 +- src/math/euclid/euclidean_solver.cpp | 8 +- src/math/grobner/grobner.cpp | 22 +- src/math/grobner/grobner.h | 10 +- src/math/hilbert/heap_trie.h | 8 +- src/math/hilbert/hilbert_basis.cpp | 4 +- src/math/polynomial/algebraic_numbers.cpp | 22 +- src/math/polynomial/algebraic_numbers.h | 4 +- src/math/polynomial/polynomial.cpp | 60 ++--- src/math/polynomial/polynomial.h | 4 +- src/math/polynomial/polynomial_cache.cpp | 4 +- src/math/polynomial/rpolynomial.cpp | 54 ++-- src/math/polynomial/rpolynomial.h | 2 +- src/math/polynomial/upolynomial.cpp | 2 +- src/math/polynomial/upolynomial.h | 2 +- src/math/realclosure/mpz_matrix.cpp | 8 +- src/math/realclosure/mpz_matrix.h | 2 +- src/math/realclosure/realclosure.cpp | 134 +++++----- src/math/realclosure/realclosure.h | 4 +- src/math/simplex/simplex_def.h | 2 +- src/math/simplex/sparse_matrix_def.h | 2 +- src/math/subpaving/subpaving.h | 10 +- src/math/subpaving/subpaving_t.h | 20 +- src/math/subpaving/subpaving_t_def.h | 142 +++++----- src/math/subpaving/tactic/expr2subpaving.cpp | 6 +- src/math/subpaving/tactic/expr2subpaving.h | 2 +- .../subpaving/tactic/subpaving_tactic.cpp | 12 +- src/model/func_interp.cpp | 26 +- src/model/func_interp.h | 2 +- src/model/model.cpp | 10 +- src/model/model_core.cpp | 2 +- src/model/model_core.h | 4 +- src/model/model_evaluator.cpp | 16 +- src/model/model_implicant.cpp | 6 +- src/muz/base/dl_boogie_proof.h | 2 +- src/muz/base/dl_context.cpp | 30 +-- src/muz/base/dl_context.h | 4 +- src/muz/base/dl_costs.cpp | 4 +- src/muz/base/dl_costs.h | 4 +- src/muz/base/dl_rule.cpp | 16 +- src/muz/base/dl_rule.h | 6 +- src/muz/base/dl_rule_set.cpp | 10 +- src/muz/base/dl_rule_transformer.h | 2 +- src/muz/base/dl_util.cpp | 8 +- src/muz/base/hnf.cpp | 14 +- src/muz/bmc/dl_bmc_engine.cpp | 24 +- src/muz/clp/clp_context.cpp | 2 +- src/muz/ddnf/ddnf.cpp | 12 +- src/muz/duality/duality_dl_interface.cpp | 10 +- src/muz/fp/datalog_parser.cpp | 42 +-- src/muz/fp/dl_cmds.cpp | 20 +- src/muz/fp/dl_register_engine.cpp | 6 +- src/muz/fp/horn_tactic.cpp | 8 +- src/muz/pdr/pdr_closure.h | 4 +- src/muz/pdr/pdr_context.cpp | 44 +-- src/muz/pdr/pdr_context.h | 10 +- src/muz/pdr/pdr_dl_interface.cpp | 2 +- src/muz/pdr/pdr_farkas_learner.cpp | 2 +- src/muz/pdr/pdr_generalizers.cpp | 10 +- src/muz/pdr/pdr_manager.h | 2 +- src/muz/pdr/pdr_prop_solver.cpp | 14 +- src/muz/pdr/pdr_reachable_cache.cpp | 2 +- src/muz/pdr/pdr_smt_context_manager.cpp | 2 +- src/muz/pdr/pdr_sym_mux.h | 4 +- src/muz/pdr/pdr_util.cpp | 2 +- src/muz/rel/aig_exporter.cpp | 4 +- src/muz/rel/aig_exporter.h | 4 +- src/muz/rel/check_relation.cpp | 34 +-- src/muz/rel/dl_base.cpp | 4 +- src/muz/rel/dl_base.h | 44 +-- src/muz/rel/dl_bound_relation.cpp | 28 +- src/muz/rel/dl_bound_relation.h | 2 +- src/muz/rel/dl_check_table.cpp | 30 +-- src/muz/rel/dl_check_table.h | 2 +- src/muz/rel/dl_compiler.cpp | 6 +- src/muz/rel/dl_compiler.h | 4 +- src/muz/rel/dl_external_relation.cpp | 30 +-- src/muz/rel/dl_finite_product_relation.cpp | 48 ++-- src/muz/rel/dl_instruction.cpp | 14 +- src/muz/rel/dl_instruction.h | 6 +- src/muz/rel/dl_interval_relation.cpp | 48 ++-- src/muz/rel/dl_lazy_table.cpp | 28 +- src/muz/rel/dl_lazy_table.h | 2 +- src/muz/rel/dl_mk_explanations.cpp | 40 +-- src/muz/rel/dl_mk_similarity_compressor.cpp | 2 +- src/muz/rel/dl_mk_simple_joins.cpp | 16 +- src/muz/rel/dl_product_relation.cpp | 42 +-- src/muz/rel/dl_relation_manager.cpp | 48 ++-- src/muz/rel/dl_relation_manager.h | 8 +- src/muz/rel/dl_sieve_relation.cpp | 70 ++--- src/muz/rel/dl_sparse_table.cpp | 30 +-- src/muz/rel/dl_table.cpp | 2 +- src/muz/rel/dl_table_relation.cpp | 40 +-- src/muz/rel/doc.cpp | 2 +- src/muz/rel/doc.h | 6 +- src/muz/rel/karr_relation.cpp | 28 +- src/muz/rel/rel_context.cpp | 4 +- src/muz/rel/tbv.h | 4 +- src/muz/rel/udoc_relation.cpp | 24 +- src/muz/rel/udoc_relation.h | 2 +- src/muz/spacer/spacer_antiunify.cpp | 2 +- src/muz/spacer/spacer_context.cpp | 80 +++--- src/muz/spacer/spacer_context.h | 18 +- src/muz/spacer/spacer_dl_interface.cpp | 2 +- src/muz/spacer/spacer_generalizers.cpp | 2 +- src/muz/spacer/spacer_itp_solver.cpp | 2 +- src/muz/spacer/spacer_legacy_mev.cpp | 2 +- src/muz/spacer/spacer_prop_solver.cpp | 12 +- src/muz/spacer/spacer_prop_solver.h | 2 +- src/muz/spacer/spacer_qe_project.cpp | 48 ++-- src/muz/spacer/spacer_smt_context_manager.cpp | 2 +- src/muz/spacer/spacer_sym_mux.h | 4 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 6 +- src/muz/spacer/spacer_util.cpp | 8 +- src/muz/spacer/spacer_util.h | 2 +- src/muz/spacer/spacer_virtual_solver.cpp | 4 +- src/muz/tab/tab_context.cpp | 2 +- src/muz/transforms/dl_mk_array_blast.cpp | 6 +- src/muz/transforms/dl_mk_bit_blast.cpp | 10 +- src/muz/transforms/dl_mk_coi_filter.cpp | 6 +- src/muz/transforms/dl_mk_filter_rules.cpp | 6 +- .../dl_mk_interp_tail_simplifier.cpp | 24 +- .../transforms/dl_mk_interp_tail_simplifier.h | 2 +- src/muz/transforms/dl_mk_karr_invariants.cpp | 14 +- src/muz/transforms/dl_mk_loop_counter.cpp | 2 +- src/muz/transforms/dl_mk_magic_sets.cpp | 16 +- src/muz/transforms/dl_mk_magic_symbolic.cpp | 4 +- .../dl_mk_quantifier_abstraction.cpp | 18 +- .../dl_mk_quantifier_instantiation.cpp | 12 +- src/muz/transforms/dl_mk_rule_inliner.cpp | 20 +- src/muz/transforms/dl_mk_rule_inliner.h | 2 +- src/muz/transforms/dl_mk_scale.cpp | 4 +- .../dl_mk_separate_negated_tails.cpp | 2 +- src/muz/transforms/dl_mk_slice.cpp | 22 +- .../transforms/dl_mk_subsumption_checker.cpp | 6 +- .../transforms/dl_mk_unbound_compressor.cpp | 4 +- src/nlsat/nlsat_explain.cpp | 24 +- src/nlsat/nlsat_interval_set.cpp | 22 +- src/nlsat/nlsat_interval_set.h | 4 +- src/nlsat/nlsat_justification.h | 4 +- src/nlsat/nlsat_solver.cpp | 58 ++-- src/nlsat/nlsat_solver.h | 2 +- src/nlsat/tactic/goal2nlsat.cpp | 4 +- src/nlsat/tactic/nlsat_tactic.cpp | 14 +- src/opt/maxres.cpp | 16 +- src/opt/maxsmt.cpp | 4 +- src/opt/opt_cmds.cpp | 4 +- src/opt/opt_cmds.h | 2 +- src/opt/opt_context.cpp | 14 +- src/opt/opt_context.h | 6 +- src/opt/opt_pareto.cpp | 6 +- src/opt/opt_solver.cpp | 8 +- src/opt/optsmt.cpp | 18 +- src/opt/optsmt.h | 2 +- src/opt/sortmax.cpp | 2 +- src/opt/wmax.cpp | 6 +- src/parsers/smt2/marshal.cpp | 2 +- src/parsers/smt2/smt2parser.cpp | 114 ++++---- src/parsers/smt2/smt2parser.h | 2 +- src/parsers/util/simple_parser.cpp | 6 +- src/qe/nlarith_util.cpp | 14 +- src/qe/nlqsat.cpp | 6 +- src/qe/qe.cpp | 52 ++-- src/qe/qe.h | 2 +- src/qe/qe_arith.cpp | 2 +- src/qe/qe_arith_plugin.cpp | 24 +- src/qe/qe_arrays.cpp | 2 +- src/qe/qe_bool_plugin.cpp | 2 +- src/qe/qe_bv_plugin.cpp | 2 +- src/qe/qe_cmd.cpp | 4 +- src/qe/qe_datatype_plugin.cpp | 20 +- src/qe/qe_dl_plugin.cpp | 6 +- src/qe/qe_lite.cpp | 32 +-- src/qe/qe_mbp.cpp | 2 +- src/qe/qe_sat_tactic.cpp | 8 +- src/qe/qe_tactic.cpp | 4 +- src/qe/qsat.cpp | 10 +- src/sat/sat_clause.cpp | 2 +- src/sat/sat_clause.h | 2 +- src/sat/sat_probing.cpp | 2 +- src/sat/sat_probing.h | 6 +- src/sat/sat_simplifier.cpp | 6 +- src/sat/sat_solver.cpp | 14 +- src/sat/sat_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 18 +- src/sat/tactic/goal2sat.cpp | 12 +- src/sat/tactic/sat_tactic.cpp | 12 +- src/shell/datalog_frontend.cpp | 4 +- src/shell/dimacs_frontend.cpp | 6 +- src/shell/lp_frontend.cpp | 6 +- src/shell/main.cpp | 10 +- src/shell/opt_frontend.cpp | 6 +- src/shell/smtlib_frontend.cpp | 4 +- src/smt/arith_eq_adapter.cpp | 4 +- src/smt/arith_eq_adapter.h | 2 +- src/smt/asserted_formulas.cpp | 14 +- src/smt/cached_var_subst.cpp | 4 +- src/smt/dyn_ack.cpp | 6 +- src/smt/expr_context_simplifier.cpp | 10 +- src/smt/fingerprints.cpp | 6 +- src/smt/mam.cpp | 120 ++++----- src/smt/old_interval.cpp | 58 ++-- src/smt/old_interval.h | 2 +- src/smt/params/qi_params.h | 2 +- src/smt/proto_model/array_factory.cpp | 12 +- src/smt/proto_model/datatype_factory.cpp | 14 +- src/smt/proto_model/proto_model.cpp | 10 +- src/smt/proto_model/struct_factory.cpp | 2 +- src/smt/proto_model/value_factory.cpp | 14 +- src/smt/proto_model/value_factory.h | 14 +- src/smt/qi_queue.cpp | 2 +- src/smt/smt2_extra_cmds.cpp | 4 +- src/smt/smt_almost_cg_table.cpp | 6 +- src/smt/smt_almost_cg_table.h | 2 +- src/smt/smt_b_justification.h | 2 +- src/smt/smt_case_split_queue.cpp | 8 +- src/smt/smt_cg_table.h | 10 +- src/smt/smt_checker.cpp | 18 +- src/smt/smt_checker.h | 4 +- src/smt/smt_clause.cpp | 8 +- src/smt/smt_clause.h | 10 +- src/smt/smt_conflict_resolution.cpp | 58 ++-- src/smt/smt_consequences.cpp | 2 +- src/smt/smt_context.cpp | 70 ++--- src/smt/smt_context.h | 24 +- src/smt/smt_enode.cpp | 12 +- src/smt/smt_enode.h | 6 +- src/smt/smt_eq_justification.h | 2 +- src/smt/smt_implied_equalities.cpp | 16 +- src/smt/smt_internalizer.cpp | 26 +- src/smt/smt_justification.cpp | 34 +-- src/smt/smt_justification.h | 16 +- src/smt/smt_kernel.h | 2 +- src/smt/smt_model_checker.cpp | 28 +- src/smt/smt_model_finder.cpp | 126 ++++----- src/smt/smt_model_generator.cpp | 24 +- src/smt/smt_model_generator.h | 4 +- src/smt/smt_quantifier.cpp | 8 +- src/smt/smt_quantifier_stat.h | 2 +- src/smt/smt_quick_checker.cpp | 6 +- src/smt/smt_quick_checker.h | 2 +- src/smt/smt_relevancy.cpp | 18 +- src/smt/smt_solver.cpp | 2 +- src/smt/smt_theory.cpp | 4 +- src/smt/smt_theory.h | 6 +- src/smt/smt_theory_var_list.h | 4 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 8 +- src/smt/tactic/smt_tactic.cpp | 16 +- src/smt/theory_arith.h | 18 +- src/smt/theory_arith_aux.h | 18 +- src/smt/theory_arith_core.h | 38 +-- src/smt/theory_arith_eq.h | 2 +- src/smt/theory_arith_int.h | 22 +- src/smt/theory_arith_nl.h | 72 ++--- src/smt/theory_arith_pp.h | 4 +- src/smt/theory_array_base.cpp | 32 +-- src/smt/theory_array_full.cpp | 2 +- src/smt/theory_bv.cpp | 6 +- src/smt/theory_bv.h | 4 +- src/smt/theory_datatype.cpp | 30 +-- src/smt/theory_datatype.h | 2 +- src/smt/theory_dense_diff_logic_def.h | 2 +- src/smt/theory_diff_logic.h | 4 +- src/smt/theory_diff_logic_def.h | 14 +- src/smt/theory_dl.cpp | 8 +- src/smt/theory_fpa.cpp | 10 +- src/smt/theory_lra.cpp | 34 +-- src/smt/theory_pb.cpp | 42 +-- src/smt/theory_pb.h | 6 +- src/smt/theory_seq.cpp | 182 ++++++------- src/smt/theory_seq.h | 6 +- src/smt/theory_seq_empty.h | 10 +- src/smt/theory_str.cpp | 186 ++++++------- src/smt/theory_str.h | 6 +- src/smt/theory_utvpi.h | 2 +- src/smt/theory_utvpi_def.h | 6 +- src/smt/theory_wmaxsat.cpp | 4 +- src/smt/theory_wmaxsat.h | 2 +- src/smt/watch_list.cpp | 2 +- src/smt/watch_list.h | 10 +- src/solver/check_sat_result.cpp | 4 +- src/solver/mus.cpp | 4 +- src/solver/solver.cpp | 4 +- src/solver/solver2tactic.cpp | 12 +- src/solver/solver_na2as.cpp | 2 +- src/solver/tactic2solver.cpp | 12 +- src/solver/tactic2solver.h | 2 +- src/tactic/aig/aig.cpp | 32 +-- src/tactic/aig/aig_tactic.cpp | 8 +- src/tactic/arith/add_bounds_tactic.cpp | 2 +- src/tactic/arith/arith_bounds_tactic.cpp | 2 +- src/tactic/arith/bound_manager.cpp | 10 +- src/tactic/arith/bound_manager.h | 6 +- src/tactic/arith/bound_propagator.cpp | 14 +- src/tactic/arith/bv2int_rewriter.cpp | 6 +- src/tactic/arith/bv2int_rewriter.h | 2 +- src/tactic/arith/bv2real_rewriter.h | 4 +- src/tactic/arith/card2bv_tactic.cpp | 2 +- src/tactic/arith/card2bv_tactic.h | 2 +- src/tactic/arith/degree_shift_tactic.cpp | 14 +- src/tactic/arith/diff_neq_tactic.cpp | 2 +- src/tactic/arith/elim01_tactic.cpp | 2 +- src/tactic/arith/eq2bv_tactic.cpp | 6 +- src/tactic/arith/factor_tactic.cpp | 2 +- src/tactic/arith/fix_dl_var_tactic.cpp | 10 +- src/tactic/arith/fm_tactic.cpp | 32 +-- src/tactic/arith/lia2card_tactic.cpp | 4 +- src/tactic/arith/lia2pb_tactic.cpp | 16 +- src/tactic/arith/linear_equation.cpp | 4 +- src/tactic/arith/nla2bv_tactic.cpp | 8 +- src/tactic/arith/normalize_bounds_tactic.cpp | 8 +- src/tactic/arith/pb2bv_model_converter.cpp | 4 +- src/tactic/arith/pb2bv_tactic.cpp | 14 +- src/tactic/arith/propagate_ineqs_tactic.cpp | 12 +- src/tactic/arith/purify_arith_tactic.cpp | 14 +- src/tactic/arith/recover_01_tactic.cpp | 16 +- src/tactic/bv/bit_blaster_model_converter.cpp | 4 +- src/tactic/bv/bit_blaster_tactic.cpp | 8 +- src/tactic/bv/bv1_blaster_tactic.cpp | 6 +- src/tactic/bv/bv_bound_chk_tactic.cpp | 4 +- src/tactic/bv/bv_bounds_tactic.cpp | 6 +- src/tactic/bv/bv_size_reduction_tactic.cpp | 22 +- src/tactic/bv/bvarray2uf_rewriter.cpp | 8 +- src/tactic/bv/bvarray2uf_tactic.cpp | 2 +- src/tactic/bv/dt2bv_tactic.cpp | 2 +- src/tactic/bv/elim_small_bv_tactic.cpp | 10 +- src/tactic/bv/max_bv_sharing_tactic.cpp | 14 +- src/tactic/converter.h | 4 +- src/tactic/core/blast_term_ite_tactic.cpp | 2 +- src/tactic/core/cofactor_elim_term_ite.cpp | 28 +- src/tactic/core/cofactor_term_ite_tactic.cpp | 4 +- src/tactic/core/collect_statistics_tactic.cpp | 2 +- src/tactic/core/ctx_simplify_tactic.cpp | 24 +- src/tactic/core/der_tactic.cpp | 2 +- src/tactic/core/distribute_forall_tactic.cpp | 6 +- src/tactic/core/dom_simplify_tactic.cpp | 22 +- src/tactic/core/dom_simplify_tactic.h | 2 +- src/tactic/core/elim_term_ite_tactic.cpp | 8 +- src/tactic/core/elim_uncnstr_tactic.cpp | 84 +++--- src/tactic/core/injectivity_tactic.cpp | 2 +- src/tactic/core/nnf_tactic.cpp | 10 +- src/tactic/core/occf_tactic.cpp | 30 +-- src/tactic/core/pb_preprocess_tactic.cpp | 14 +- src/tactic/core/propagate_values_tactic.cpp | 8 +- src/tactic/core/reduce_args_tactic.cpp | 12 +- src/tactic/core/simplify_tactic.cpp | 2 +- src/tactic/core/solve_eqs_tactic.cpp | 34 +-- src/tactic/core/solve_eqs_tactic.h | 2 +- src/tactic/core/split_clause_tactic.cpp | 4 +- src/tactic/core/symmetry_reduce_tactic.cpp | 14 +- src/tactic/core/tseitin_cnf_tactic.cpp | 16 +- src/tactic/fpa/fpa2bv_model_converter.h | 2 +- src/tactic/fpa/fpa2bv_tactic.cpp | 2 +- src/tactic/goal.cpp | 14 +- src/tactic/goal.h | 8 +- src/tactic/model_converter.cpp | 14 +- src/tactic/nlsat_smt/nl_purify_tactic.cpp | 18 +- .../portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 4 +- src/tactic/portfolio/smt_strategic_solver.cpp | 2 +- src/tactic/probe.cpp | 6 +- src/tactic/proof_converter.cpp | 12 +- src/tactic/replace_proof_converter.cpp | 2 +- src/tactic/sine_filter.cpp | 4 +- src/tactic/sls/bvsls_opt_engine.cpp | 2 +- src/tactic/sls/sls_engine.cpp | 4 +- src/tactic/sls/sls_tactic.cpp | 2 +- src/tactic/sls/sls_tracker.h | 12 +- src/tactic/smtlogics/qfufbv_tactic.cpp | 4 +- src/tactic/tactic.cpp | 14 +- src/tactic/tactical.cpp | 80 +++--- src/tactic/ufbv/macro_finder_tactic.cpp | 6 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 6 +- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 6 +- src/test/check_assumptions.cpp | 12 +- src/test/cnf_backbones.cpp | 6 +- src/test/ddnf.cpp | 2 +- src/test/escaped.cpp | 4 +- src/test/expr_rand.cpp | 4 +- src/test/fuzzing/expr_rand.cpp | 90 +++---- src/test/get_consequences.cpp | 12 +- src/test/hilbert_basis.cpp | 2 +- src/test/list.cpp | 8 +- src/test/main.cpp | 6 +- src/test/nlsat.cpp | 2 +- src/test/old_interval.cpp | 6 +- src/test/pb2bv.cpp | 4 +- src/test/pdr.cpp | 2 +- src/test/polynorm.cpp | 2 +- src/test/sat_user_scope.cpp | 4 +- src/test/smt2print_parse.cpp | 20 +- src/test/sorting_network.cpp | 2 +- src/test/theory_pb.cpp | 4 +- src/test/udoc_relation.cpp | 10 +- src/test/var_subst.cpp | 2 +- src/util/array.h | 6 +- src/util/bit_vector.h | 4 +- src/util/chashtable.h | 54 ++-- src/util/cmd_context_types.h | 4 +- src/util/cooperate.cpp | 2 +- src/util/debug.cpp | 8 +- src/util/dependency.h | 6 +- src/util/file_path.h | 8 +- src/util/gparams.cpp | 30 +-- src/util/hashtable.h | 22 +- src/util/list.h | 4 +- src/util/lp/lar_core_solver.h | 2 +- src/util/map.h | 4 +- src/util/memory_manager.cpp | 4 +- src/util/memory_manager.h | 6 +- src/util/mpfx.cpp | 2 +- src/util/mpz.h | 12 +- src/util/obj_hashtable.h | 16 +- src/util/obj_pair_hashtable.h | 14 +- src/util/obj_ref.h | 10 +- src/util/obj_triple_hashtable.h | 12 +- src/util/optional.h | 8 +- src/util/page.cpp | 2 +- src/util/params.cpp | 22 +- src/util/params.h | 6 +- src/util/parray.h | 22 +- src/util/plugin_manager.h | 2 +- src/util/prime_generator.cpp | 2 +- src/util/prime_generator.h | 2 +- src/util/rational.cpp | 4 +- src/util/ref.h | 8 +- src/util/region.cpp | 20 +- src/util/s_integer.cpp | 2 +- src/util/scoped_ctrl_c.cpp | 2 +- src/util/scoped_ptr_vector.h | 4 +- src/util/scoped_timer.cpp | 8 +- src/util/small_object_allocator.cpp | 28 +- src/util/smt2_util.cpp | 2 +- src/util/stack.cpp | 8 +- src/util/symbol.cpp | 12 +- src/util/symbol.h | 8 +- src/util/symbol_table.h | 4 +- src/util/timeit.cpp | 2 +- src/util/timeout.cpp | 6 +- src/util/trace.cpp | 4 +- src/util/trail.h | 2 +- src/util/util.cpp | 4 +- src/util/util.h | 6 +- src/util/vector.h | 30 +-- src/util/warning.cpp | 4 +- 625 files changed, 4639 insertions(+), 4639 deletions(-) mode change 100755 => 100644 src/duality/duality_profiling.cpp mode change 100755 => 100644 src/duality/duality_rpfp.cpp mode change 100755 => 100644 src/duality/duality_wrapper.cpp mode change 100755 => 100644 src/interp/iz3base.cpp mode change 100755 => 100644 src/interp/iz3checker.cpp mode change 100755 => 100644 src/interp/iz3interp.cpp mode change 100755 => 100644 src/interp/iz3mgr.cpp mode change 100755 => 100644 src/interp/iz3mgr.h mode change 100755 => 100644 src/interp/iz3profiling.cpp mode change 100755 => 100644 src/interp/iz3proof.h mode change 100755 => 100644 src/interp/iz3translate.cpp mode change 100755 => 100644 src/interp/iz3translate_direct.cpp mode change 100755 => 100644 src/muz/duality/duality_dl_interface.cpp diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index 5d749b7d5..73034622e 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -34,7 +34,7 @@ public: model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override { - mc = 0; + mc = nullptr; tactic_report report("ackermannize", *g); fail_if_unsat_core_generation("ackermannize", g); fail_if_proof_generation("ackermannize", g); @@ -43,7 +43,7 @@ public: expr_ref_vector flas(m); const unsigned sz = g->size(); for (unsigned i = 0; i < sz; i++) flas.push_back(g->form(i)); - lackr lackr(m, m_p, m_st, flas, NULL); + lackr lackr(m, m_p, m_st, flas, nullptr); // mk result goal_ref resg(alloc(goal, *g, true)); @@ -52,9 +52,9 @@ public: TRACE("ackermannize", tout << "ackermannize not run due to limit" << std::endl;); result.reset(); result.push_back(g.get()); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; return; } result.push_back(resg.get()); diff --git a/src/ackermannization/ackr_bound_probe.cpp b/src/ackermannization/ackr_bound_probe.cpp index f5e072368..c6cdaf268 100644 --- a/src/ackermannization/ackr_bound_probe.cpp +++ b/src/ackermannization/ackr_bound_probe.cpp @@ -45,7 +45,7 @@ class ackr_bound_probe : public probe { if (a->get_num_args() == 0) return; if (!m_ackr_helper.should_ackermannize(a)) return; func_decl* const fd = a->get_decl(); - app_set* ts = 0; + app_set* ts = nullptr; if (!m_fun2terms.find(fd, ts)) { ts = alloc(app_set); m_fun2terms.insert(fd, ts); diff --git a/src/ackermannization/ackr_info.h b/src/ackermannization/ackr_info.h index 0b67e144f..db5f64a70 100644 --- a/src/ackermannization/ackr_info.h +++ b/src/ackermannization/ackr_info.h @@ -65,7 +65,7 @@ class ackr_info { } inline app* find_term(func_decl* c) const { - app * rv = 0; + app * rv = nullptr; m_c2t.find(c,rv); return rv; } diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index c8df89bad..f5b90de1b 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -116,7 +116,7 @@ void ackr_model_converter::add_entry(model_evaluator & evaluator, << mk_ismt2_pp(value, m, 2) << "\n"; ); - func_interp * fi = 0; + func_interp * fi = nullptr; func_decl * const declaration = term->get_decl(); const unsigned sz = declaration->get_arity(); SASSERT(sz == term->get_num_args()); @@ -133,7 +133,7 @@ void ackr_model_converter::add_entry(model_evaluator & evaluator, evaluator(aarg, arg_value); args.push_back(arg_value); } - if (fi->get_entry(args.c_ptr()) == 0) { + if (fi->get_entry(args.c_ptr()) == nullptr) { TRACE("ackr_model", tout << mk_ismt2_pp(declaration, m) << " args: " << std::endl; for (unsigned i = 0; i < args.size(); i++) diff --git a/src/ackermannization/lackr.cpp b/src/ackermannization/lackr.cpp index aac98d7dc..b739af9d3 100644 --- a/src/ackermannization/lackr.cpp +++ b/src/ackermannization/lackr.cpp @@ -185,7 +185,7 @@ void lackr::add_term(app* a) { if (a->get_num_args() == 0) return; if (!m_ackr_helper.should_ackermannize(a)) return; func_decl* const fd = a->get_decl(); - app_set* ts = 0; + app_set* ts = nullptr; if (!m_fun2terms.find(fd, ts)) { ts = alloc(app_set); m_fun2terms.insert(fd, ts); @@ -205,7 +205,7 @@ lbool lackr::eager() { SASSERT(m_is_init); push_abstraction(); TRACE("lackr", tout << "run sat 0\n"; ); - const lbool rv0 = m_sat->check_sat(0, 0); + const lbool rv0 = m_sat->check_sat(0, nullptr); if (rv0 == l_false) return l_false; eager_enc(); expr_ref all(m_m); @@ -213,7 +213,7 @@ lbool lackr::eager() { m_simp(all); m_sat->assert_expr(all); TRACE("lackr", tout << "run sat all\n"; ); - return m_sat->check_sat(0, 0); + return m_sat->check_sat(0, nullptr); } lbool lackr::lazy() { @@ -225,7 +225,7 @@ lbool lackr::lazy() { m_st.m_it++; checkpoint(); TRACE("lackr", tout << "lazy check: " << m_st.m_it << "\n";); - const lbool r = m_sat->check_sat(0, 0); + const lbool r = m_sat->check_sat(0, nullptr); if (r == l_undef) return l_undef; // give up if (r == l_false) return l_false; // abstraction unsat // reconstruct model diff --git a/src/ackermannization/lackr_model_constructor.cpp b/src/ackermannization/lackr_model_constructor.cpp index 641c70cbc..420fbda10 100644 --- a/src/ackermannization/lackr_model_constructor.cpp +++ b/src/ackermannization/lackr_model_constructor.cpp @@ -34,7 +34,7 @@ struct lackr_model_constructor::imp { , m_conflicts(conflicts) , m_b_rw(m) , m_bv_rw(m) - , m_evaluator(NULL) + , m_evaluator(nullptr) , m_empty_model(m) , m_ackr_helper(m) {} @@ -121,7 +121,7 @@ struct lackr_model_constructor::imp { void add_entry(app* term, expr* value, obj_map& interpretations) { - func_interp* fi = 0; + func_interp* fi = nullptr; func_decl * const declaration = term->get_decl(); const unsigned sz = declaration->get_arity(); SASSERT(sz == term->get_num_args()); @@ -169,7 +169,7 @@ struct lackr_model_constructor::imp { // Stops upon the first failure. // Returns true if and only if all congruence checks succeeded. bool _check_stack() { - if (m_evaluator == NULL) m_evaluator = alloc(model_evaluator, m_empty_model); + if (m_evaluator == nullptr) m_evaluator = alloc(model_evaluator, m_empty_model); expr * curr; while (!m_stack.empty()) { curr = m_stack.back(); @@ -276,7 +276,7 @@ struct lackr_model_constructor::imp { SASSERT(a->get_num_args() == 0); func_decl * const fd = a->get_decl(); expr * val = m_abstr_model->get_const_interp(fd); - if (val == 0) { // TODO: avoid model completetion? + if (val == nullptr) { // TODO: avoid model completetion? sort * s = fd->get_range(); val = m_abstr_model->get_some_value(s); } @@ -295,7 +295,7 @@ struct lackr_model_constructor::imp { expr_ref value(m_m); value = m_abstr_model->get_const_interp(ac->get_decl()); // get ackermann constant's interpretation - if (value.get() == 0) { // TODO: avoid model completion? + if (value.get() == nullptr) { // TODO: avoid model completion? sort * s = a_fd->get_range(); value = m_abstr_model->get_some_value(s); } @@ -362,7 +362,7 @@ struct lackr_model_constructor::imp { }; lackr_model_constructor::lackr_model_constructor(ast_manager& m, ackr_info_ref info) - : m_imp(0) + : m_imp(nullptr) , m_m(m) , m_state(UNKNOWN) , m_info(info) @@ -377,7 +377,7 @@ bool lackr_model_constructor::check(model_ref& abstr_model) { m_conflicts.reset(); if (m_imp) { dealloc(m_imp); - m_imp = 0; + m_imp = nullptr; } m_imp = alloc(lackr_model_constructor::imp, m_m, m_info, abstr_model, m_conflicts); const bool rv = m_imp->check(); diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index b4eda2c03..47d91209e 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -162,57 +162,57 @@ extern "C" { Z3_TRY; LOG_Z3_algebraic_add(c, a, b); RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + CHECK_IS_ALGEBRAIC_X(a, nullptr); + CHECK_IS_ALGEBRAIC_X(b, nullptr); BIN_OP(+,add); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_algebraic_sub(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_sub(c, a, b); RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + CHECK_IS_ALGEBRAIC_X(a, nullptr); + CHECK_IS_ALGEBRAIC_X(b, nullptr); BIN_OP(-,sub); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_algebraic_mul(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_mul(c, a, b); RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + CHECK_IS_ALGEBRAIC_X(a, nullptr); + CHECK_IS_ALGEBRAIC_X(b, nullptr); BIN_OP(*,mul); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_algebraic_div(Z3_context c, Z3_ast a, Z3_ast b) { Z3_TRY; LOG_Z3_algebraic_div(c, a, b); RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); - CHECK_IS_ALGEBRAIC_X(b, 0); + CHECK_IS_ALGEBRAIC_X(a, nullptr); + 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } BIN_OP(/,div); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_algebraic_root(Z3_context c, Z3_ast a, unsigned k) { Z3_TRY; LOG_Z3_algebraic_root(c, a, k); RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); + CHECK_IS_ALGEBRAIC_X(a, nullptr); 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } } algebraic_numbers::manager & _am = am(c); @@ -229,14 +229,14 @@ extern "C" { expr * r = au(c).mk_numeral(_r, false); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_algebraic_power(Z3_context c, Z3_ast a, unsigned k) { Z3_TRY; LOG_Z3_algebraic_power(c, a, k); RESET_ERROR_CODE(); - CHECK_IS_ALGEBRAIC_X(a, 0); + CHECK_IS_ALGEBRAIC_X(a, nullptr); algebraic_numbers::manager & _am = am(c); scoped_anum _r(_am); if (is_rational(c, a)) { @@ -251,7 +251,7 @@ extern "C" { expr * r = au(c).mk_numeral(_r, false); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } #define BIN_PRED(RAT_PRED, IRAT_PRED) \ @@ -357,17 +357,17 @@ extern "C" { polynomial::manager & pm = mk_c(c)->pm(); polynomial_ref _p(pm); polynomial::scoped_numeral d(pm.m()); - expr2polynomial converter(mk_c(c)->m(), pm, 0, true); + 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); - return 0; + 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); - return 0; + return nullptr; } scoped_anum_vector roots(_am); { @@ -383,7 +383,7 @@ extern "C" { result->m_ast_vector.push_back(au(c).mk_numeral(roots.get(i), false)); } RETURN_Z3(of_ast_vector(result)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } int Z3_API Z3_algebraic_eval(Z3_context c, Z3_ast p, unsigned n, Z3_ast a[]) { @@ -393,7 +393,7 @@ extern "C" { polynomial::manager & pm = mk_c(c)->pm(); polynomial_ref _p(pm); polynomial::scoped_numeral d(pm.m()); - expr2polynomial converter(mk_c(c)->m(), pm, 0, true); + 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); diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index 8fbed6f46..9bb236fe2 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -34,7 +34,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_sort r = of_sort(mk_c(c)->m().mk_sort(mk_c(c)->get_arith_fid(), INT_SORT)); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_real_sort(Z3_context c) { @@ -43,7 +43,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_sort r = of_sort(mk_c(c)->m().mk_sort(mk_c(c)->get_arith_fid(), REAL_SORT)); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_real(Z3_context c, int num, int den) { @@ -52,12 +52,12 @@ extern "C" { RESET_ERROR_CODE(); if (den == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } sort* s = mk_c(c)->m().mk_sort(mk_c(c)->get_arith_fid(), REAL_SORT); ast* a = mk_c(c)->mk_numeral_core(rational(num, den), s); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } MK_ARITH_OP(Z3_mk_add, OP_ADD); @@ -77,11 +77,11 @@ extern "C" { k = OP_DIV; } expr * args[2] = { to_expr(n1), to_expr(n2) }; - ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), k, 0, 0, 2, args); + ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), k, 0, nullptr, 2, args); mk_c(c)->save_ast_trail(a); check_sorts(c, a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } MK_ARITH_PRED(Z3_mk_lt, OP_LT); @@ -98,17 +98,17 @@ extern "C" { RESET_ERROR_CODE(); if (num_args == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr* r = to_expr(args[0]); for (unsigned i = 1; i < num_args; ++i) { expr* args1[2] = { r, to_expr(args[i]) }; - r = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), OP_SUB, 0, 0, 2, args1); + r = mk_c(c)->m().mk_app(mk_c(c)->get_arith_fid(), OP_SUB, 0, nullptr, 2, args1); check_sorts(c, r); } mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_unary_minus(Z3_context c, Z3_ast n) { @@ -116,7 +116,7 @@ extern "C" { LOG_Z3_mk_unary_minus(c, n); RESET_ERROR_CODE(); MK_UNARY_BODY(Z3_mk_unary_minus, mk_c(c)->get_arith_fid(), OP_UMINUS, SKIP); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_is_algebraic_number(Z3_context c, Z3_ast a) { @@ -134,7 +134,7 @@ extern "C" { RESET_ERROR_CODE(); if (!Z3_is_algebraic_number(c, a)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr * e = to_expr(a); algebraic_numbers::anum const & val = mk_c(c)->autil().to_irrational_algebraic_numeral(e); @@ -143,7 +143,7 @@ extern "C" { expr * r = mk_c(c)->autil().mk_numeral(l, false); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_get_algebraic_number_upper(Z3_context c, Z3_ast a, unsigned precision) { @@ -152,7 +152,7 @@ extern "C" { RESET_ERROR_CODE(); if (!Z3_is_algebraic_number(c, a)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr * e = to_expr(a); algebraic_numbers::anum const & val = mk_c(c)->autil().to_irrational_algebraic_numeral(e); @@ -161,7 +161,7 @@ extern "C" { expr * r = mk_c(c)->autil().mk_numeral(l, false); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_get_numerator(Z3_context c, Z3_ast a) { @@ -172,12 +172,12 @@ extern "C" { 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr * r = mk_c(c)->autil().mk_numeral(numerator(val), true); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_get_denominator(Z3_context c, Z3_ast a) { @@ -188,12 +188,12 @@ extern "C" { 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr * r = mk_c(c)->autil().mk_numeral(denominator(val), true); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index 5e6764dff..61c37ec3e 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -31,7 +31,7 @@ extern "C" { sort * ty = mk_c(c)->m().mk_sort(mk_c(c)->get_array_fid(), ARRAY_SORT, 2, params); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const* domain, Z3_sort range) { @@ -44,7 +44,7 @@ extern "C" { sort * ty = mk_c(c)->m().mk_sort(mk_c(c)->get_array_fid(), ARRAY_SORT, params.size(), params.c_ptr()); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i) { @@ -58,7 +58,7 @@ extern "C" { sort * i_ty = m.get_sort(_i); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } sort * domain[2] = {a_ty, i_ty}; func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_SELECT, 2, a_ty->get_parameters(), 2, domain); @@ -67,7 +67,7 @@ extern "C" { mk_c(c)->save_ast_trail(r); check_sorts(c, r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs) { @@ -81,7 +81,7 @@ extern "C" { // sort * i_ty = m.get_sort(_i); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } ptr_vector domain; ptr_vector args; @@ -96,7 +96,7 @@ extern "C" { mk_c(c)->save_ast_trail(r); check_sorts(c, r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) { @@ -112,7 +112,7 @@ extern "C" { sort * v_ty = m.get_sort(_v); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } sort * domain[3] = {a_ty, i_ty, v_ty}; func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_STORE, 2, a_ty->get_parameters(), 3, domain); @@ -121,7 +121,7 @@ extern "C" { mk_c(c)->save_ast_trail(r); check_sorts(c, r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v) { @@ -135,7 +135,7 @@ extern "C" { sort * v_ty = m.get_sort(_v); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } ptr_vector domain; ptr_vector args; @@ -152,7 +152,7 @@ extern "C" { mk_c(c)->save_ast_trail(r); check_sorts(c, r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) { @@ -161,7 +161,7 @@ extern "C" { RESET_ERROR_CODE(); if (n == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } ast_manager & m = mk_c(c)->m(); func_decl* _f = to_func_decl(f); @@ -177,7 +177,7 @@ extern "C" { mk_c(c)->save_ast_trail(r); check_sorts(c, r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_const_array(Z3_context c, Z3_sort domain, Z3_ast v) { @@ -196,7 +196,7 @@ extern "C" { mk_c(c)->save_ast_trail(r); check_sorts(c, r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_array_default(Z3_context c, Z3_ast array) { @@ -206,12 +206,12 @@ extern "C" { ast_manager & m = mk_c(c)->m(); expr * _a = to_expr(array); - func_decl * f = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_ARRAY_DEFAULT, 0, 0, 1, &_a); + func_decl * f = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_ARRAY_DEFAULT, 0, nullptr, 1, &_a); app * r = m.mk_app(f, 1, &_a); mk_c(c)->save_ast_trail(r); check_sorts(c, r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast mk_app_array_core(Z3_context c, Z3_sort domain, Z3_ast v) { @@ -233,7 +233,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_set_sort(Z3_context c, Z3_sort ty) { Z3_TRY; return Z3_mk_array_sort(c, ty, Z3_mk_bool_sort(c)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_empty_set(Z3_context c, Z3_sort domain) { @@ -242,7 +242,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_ast r = mk_app_array_core(c, domain, Z3_mk_false(c)); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_full_set(Z3_context c, Z3_sort domain) { @@ -251,7 +251,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_ast r = mk_app_array_core(c, domain, Z3_mk_true(c)); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } MK_NARY(Z3_mk_set_union, mk_c(c)->get_array_fid(), OP_SET_UNION, SKIP); @@ -270,7 +270,7 @@ extern "C" { app * r = a.mk_as_array(to_func_decl(f)); mk_c(c)->save_ast_trail(r); return of_ast(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_mk_set_member(Z3_context c, Z3_ast elem, Z3_ast set) { @@ -289,22 +289,22 @@ extern "C" { Z3_TRY; LOG_Z3_get_array_sort_domain(c, t); RESET_ERROR_CODE(); - CHECK_VALID_AST(t, 0); + CHECK_VALID_AST(t, nullptr); if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && to_sort(t)->get_decl_kind() == ARRAY_SORT) { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(0).get_ast()); RETURN_Z3(r); } SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - Z3_CATCH_RETURN(0); + RETURN_Z3(nullptr); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_get_array_sort_range(Z3_context c, Z3_sort t) { Z3_TRY; LOG_Z3_get_array_sort_range(c, t); RESET_ERROR_CODE(); - CHECK_VALID_AST(t, 0); + CHECK_VALID_AST(t, nullptr); if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && to_sort(t)->get_decl_kind() == ARRAY_SORT) { unsigned n = to_sort(t)->get_num_parameters(); @@ -312,8 +312,8 @@ extern "C" { RETURN_Z3(r); } SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - Z3_CATCH_RETURN(0); + RETURN_Z3(nullptr); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 6c39ad07d..f820b184b 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -49,11 +49,11 @@ extern "C" { RESET_ERROR_CODE(); if (i < 0 || (size_t)i >= (SIZE_MAX >> PTR_ALIGNMENT)) { SET_ERROR_CODE(Z3_IOB); - return 0; + return nullptr; } Z3_symbol result = of_symbol(symbol(i)); return result; - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_symbol Z3_API Z3_mk_string_symbol(Z3_context c, char const * str) { @@ -61,13 +61,13 @@ extern "C" { LOG_Z3_mk_string_symbol(c, str); RESET_ERROR_CODE(); symbol s; - if (str == 0 || *str == 0) + if (str == nullptr || *str == 0) s = symbol::null; else s = symbol(str); Z3_symbol result = of_symbol(s); return result; - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_is_eq_sort(Z3_context c, Z3_sort s1, Z3_sort s2) { @@ -82,7 +82,7 @@ extern "C" { sort* ty = mk_c(c)->m().mk_uninterpreted_sort(to_symbol(name)); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_is_eq_ast(Z3_context c, Z3_ast s1, Z3_ast s2) { @@ -107,7 +107,7 @@ extern "C" { mk_c(c)->save_ast_trail(d); RETURN_Z3(of_func_decl(d)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_app(Z3_context c, Z3_func_decl d, unsigned num_args, Z3_ast const * args) { @@ -123,7 +123,7 @@ extern "C" { mk_c(c)->save_ast_trail(a); check_sorts(c, a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_const(Z3_context c, Z3_symbol s, Z3_sort ty) { @@ -133,7 +133,7 @@ extern "C" { app* a = mk_c(c)->m().mk_const(mk_c(c)->m().mk_const_decl(to_symbol(s), to_sort(ty))); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } @@ -142,7 +142,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_fresh_func_decl(c, prefix, domain_size, domain, range); RESET_ERROR_CODE(); - if (prefix == 0) { + if (prefix == nullptr) { prefix = ""; } @@ -153,20 +153,20 @@ extern "C" { mk_c(c)->save_ast_trail(d); RETURN_Z3(of_func_decl(d)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fresh_const(Z3_context c, const char * prefix, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_fresh_const(c, prefix, ty); RESET_ERROR_CODE(); - if (prefix == 0) { + if (prefix == nullptr) { prefix = ""; } app* a = mk_c(c)->m().mk_fresh_const(prefix, to_sort(ty)); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_true(Z3_context c) { @@ -175,7 +175,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_ast r = of_ast(mk_c(c)->m().mk_true()); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_false(Z3_context c) { @@ -184,7 +184,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_ast r = of_ast(mk_c(c)->m().mk_false()); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } MK_UNARY(Z3_mk_not, mk_c(c)->get_basic_fid(), OP_NOT, SKIP); @@ -210,7 +210,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_ast r = mk_ite_core(c, t1, t2, t3); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_bool_sort(Z3_context c) { @@ -219,7 +219,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_sort r = of_sort(mk_c(c)->m().mk_sort(mk_c(c)->m().get_basic_family_id(), BOOL_SORT)); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_app_to_ast(Z3_context c, Z3_app a) { @@ -335,7 +335,7 @@ extern "C" { Z3_bool Z3_API Z3_is_app(Z3_context c, Z3_ast a) { LOG_Z3_is_app(c, a); RESET_ERROR_CODE(); - return a != 0 && is_app(reinterpret_cast(a)); + return a != nullptr && is_app(reinterpret_cast(a)); } Z3_app Z3_API Z3_to_app(Z3_context c, Z3_ast a) { @@ -357,7 +357,7 @@ extern "C" { RESET_ERROR_CODE(); if (!is_app(reinterpret_cast(a))) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } RETURN_Z3(of_func_decl(to_app(a)->get_decl())); } @@ -373,11 +373,11 @@ extern "C" { RESET_ERROR_CODE(); if (!is_app(reinterpret_cast(a))) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } if (i >= to_app(a)->get_num_args()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } RETURN_Z3(of_ast(to_app(a)->get_arg(i))); } @@ -466,15 +466,15 @@ extern "C" { RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { SET_ERROR_CODE(Z3_IOB); - return 0; + return nullptr; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_symbol()) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } return of_symbol(p.get_symbol()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_get_decl_sort_parameter(Z3_context c, Z3_func_decl d, unsigned idx) { @@ -483,15 +483,15 @@ extern "C" { RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } RETURN_Z3(of_sort(to_sort(p.get_ast()))); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_get_decl_ast_parameter(Z3_context c, Z3_func_decl d, unsigned idx) { @@ -500,15 +500,15 @@ extern "C" { RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_ast()) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } RETURN_Z3(of_ast(p.get_ast())); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_func_decl Z3_API Z3_get_decl_func_decl_parameter(Z3_context c, Z3_func_decl d, unsigned idx) { @@ -517,15 +517,15 @@ extern "C" { RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } RETURN_Z3(of_func_decl(to_func_decl(p.get_ast()))); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_get_decl_rational_parameter(Z3_context c, Z3_func_decl d, unsigned idx) { @@ -551,17 +551,17 @@ extern "C" { LOG_Z3_get_sort_name(c, t); RESET_ERROR_CODE(); return of_symbol(to_sort(t)->get_name()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_get_sort(Z3_context c, Z3_ast a) { Z3_TRY; LOG_Z3_get_sort(c, a); RESET_ERROR_CODE(); - CHECK_IS_EXPR(a, 0); + CHECK_IS_EXPR(a, nullptr); Z3_sort r = of_sort(mk_c(c)->m().get_sort(to_expr(a))); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_get_arity(Z3_context c, Z3_func_decl d) { @@ -586,21 +586,21 @@ extern "C" { RESET_ERROR_CODE(); if (i >= to_func_decl(d)->get_arity()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_sort r = of_sort(to_func_decl(d)->get_domain(i)); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_get_range(Z3_context c, Z3_func_decl d) { Z3_TRY; LOG_Z3_get_range(c, d); RESET_ERROR_CODE(); - CHECK_VALID_AST(d, 0); + CHECK_VALID_AST(d, nullptr); Z3_sort r = of_sort(to_func_decl(d)->get_range()); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort_kind Z3_get_sort_kind(Z3_context c, Z3_sort t) { @@ -688,17 +688,17 @@ extern "C" { } catch (z3_exception & ex) { mk_c(c)->handle_exception(ex); - return 0; + return nullptr; } } mk_c(c)->save_ast_trail(result); return of_ast(result.get()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_simplify(Z3_context c, Z3_ast _a) { LOG_Z3_simplify(c, _a); - RETURN_Z3(simplify(c, _a, 0)); + RETURN_Z3(simplify(c, _a, nullptr)); } Z3_ast Z3_API Z3_simplify_ex(Z3_context c, Z3_ast _a, Z3_params p) { @@ -727,7 +727,7 @@ extern "C" { th_rewriter::get_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_update_term(Z3_context c, Z3_ast _a, unsigned num_args, Z3_ast const _args[]) { @@ -762,7 +762,7 @@ extern "C" { } mk_c(c)->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_substitute(Z3_context c, @@ -777,11 +777,11 @@ extern "C" { expr * a = to_expr(_a); expr * const * from = to_exprs(_from); expr * const * to = to_exprs(_to); - expr * r = 0; + 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); - RETURN_Z3(of_expr(0)); + RETURN_Z3(of_expr(nullptr)); } SASSERT(from[i]->get_ref_count() > 0); SASSERT(to[i]->get_ref_count() > 0); @@ -795,7 +795,7 @@ extern "C" { mk_c(c)->save_ast_trail(new_a); r = new_a.get(); RETURN_Z3(of_expr(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_substitute_vars(Z3_context c, @@ -813,7 +813,7 @@ extern "C" { subst(a, num_exprs, to, new_a); mk_c(c)->save_ast_trail(new_a); RETURN_Z3(of_expr(new_a.get())); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_API char const * Z3_ast_to_string(Z3_context c, Z3_ast a) { @@ -839,7 +839,7 @@ extern "C" { UNREACHABLE(); } return mk_c(c)->mk_external_string(buffer.str()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_API char const * Z3_sort_to_string(Z3_context c, Z3_sort s) { @@ -1233,17 +1233,17 @@ extern "C" { Z3_TRY; LOG_Z3_translate(c, a, target); RESET_ERROR_CODE(); - CHECK_VALID_AST(a, 0); + CHECK_VALID_AST(a, nullptr); if (c == target) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } SASSERT(mk_c(c)->m().contains(to_ast(a))); ast_translation translator(mk_c(c)->m(), mk_c(target)->m()); ast * _result = translator(to_ast(a)); mk_c(target)->save_ast_trail(_result); RETURN_Z3(of_ast(_result)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index d0388b97a..17dd086b5 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -38,7 +38,7 @@ extern "C" { mk_c(c)->save_object(m); Z3_ast_map r = of_ast_map(m); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_ast_map_inc_ref(Z3_context c, Z3_ast_map m) { @@ -70,15 +70,15 @@ extern "C" { LOG_Z3_ast_map_find(c, m, k); RESET_ERROR_CODE(); obj_map::obj_map_entry * entry = to_ast_map_ref(m).find_core(to_ast(k)); - if (entry == 0) { + if (entry == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } else { ast * r = entry->get_data().m_value; RETURN_Z3(of_ast(r)); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_ast_map_insert(Z3_context c, Z3_ast_map m, Z3_ast k, Z3_ast v) { @@ -115,7 +115,7 @@ extern "C" { Z3_TRY; LOG_Z3_ast_map_erase(c, m, k); RESET_ERROR_CODE(); - ast * v = 0; + ast * v = nullptr; if (to_ast_map_ref(m).find(to_ast(k), v)) { to_ast_map_ref(m).erase(to_ast(k)); ast_manager & mng = to_ast_map(m)->m; @@ -146,7 +146,7 @@ extern "C" { } Z3_ast_vector r = of_ast_vector(v); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_ast_map_to_string(Z3_context c, Z3_ast_map m) { @@ -163,7 +163,7 @@ extern "C" { } buffer << ")"; return mk_c(c)->mk_external_string(buffer.str()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index 471a308b6..ae5adecea 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -33,7 +33,7 @@ extern "C" { mk_c(c)->save_object(v); Z3_ast_vector r = of_ast_vector(v); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_ast_vector_inc_ref(Z3_context c, Z3_ast_vector v) { @@ -66,12 +66,12 @@ extern "C" { RESET_ERROR_CODE(); if (i >= to_ast_vector_ref(v).size()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } // Remark: Don't need to invoke save_object. ast * r = to_ast_vector_ref(v).get(i); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_ast_vector_set(Z3_context c, Z3_ast_vector v, unsigned i, Z3_ast a) { @@ -108,7 +108,7 @@ extern "C" { RESET_ERROR_CODE(); if (c == t) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } 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()); @@ -119,7 +119,7 @@ extern "C" { new_v->m_ast_vector.push_back(new_ast); } RETURN_Z3(of_ast_vector(new_v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_ast_vector_to_string(Z3_context c, Z3_ast_vector v) { @@ -134,7 +134,7 @@ extern "C" { } buffer << ")"; return mk_c(c)->mk_external_string(buffer.str()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 3b5d60be3..1876d930d 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -33,7 +33,7 @@ extern "C" { 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); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } #define MK_BV_UNARY(NAME, OP) MK_UNARY(NAME, mk_c(c)->get_bv_fid(), OP, SKIP) @@ -85,7 +85,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_ast r = mk_extract_core(c, high, low, n); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } #define MK_BV_PUNARY(NAME, OP) \ @@ -146,7 +146,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ check_sorts(c, a); RETURN_Z3(of_ast(a)); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } /** @@ -164,7 +164,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ unsigned sz = Z3_get_bv_sort_size(c, s); if (sz == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } Z3_ast x = Z3_mk_int64(c, 1, s); Z3_inc_ref(c, x); @@ -174,7 +174,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_dec_ref(c, x); Z3_dec_ref(c, y); return result; - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_mk_bvsmin(Z3_context c, Z3_sort s) { @@ -229,7 +229,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_dec_ref(c, r); return result; } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } // only for signed machine integers @@ -257,7 +257,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_dec_ref(c, args_neg); Z3_dec_ref(c, zero); return result; - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } // only for signed machine integers @@ -286,7 +286,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_dec_ref(c, z); Z3_dec_ref(c, zero); return result; - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_bvsub_no_underflow(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_bool is_signed) { @@ -311,7 +311,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ else { return Z3_mk_bvule(c, t2, t1); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_bvmul_no_overflow(Z3_context c, Z3_ast n1, Z3_ast n2, Z3_bool is_signed) { @@ -336,11 +336,11 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_TRY; RESET_ERROR_CODE(); Z3_ast min = Z3_mk_bvsmin(c, Z3_get_sort(c, t)); - if (Z3_get_error_code(c) != Z3_OK) return 0; + if (Z3_get_error_code(c) != Z3_OK) return nullptr; Z3_ast eq = Z3_mk_eq(c, t, min); - if (Z3_get_error_code(c) != Z3_OK) return 0; + if (Z3_get_error_code(c) != Z3_OK) return nullptr; return Z3_mk_not(c, eq); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } // only for signed machine integers @@ -366,7 +366,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_dec_ref(c, z); Z3_dec_ref(c, u); return result; - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_bvsub(Z3_context c, Z3_ast n1, Z3_ast n2) { @@ -374,7 +374,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ LOG_Z3_mk_bvsub(c, n1, n2); RESET_ERROR_CODE(); MK_BINARY_BODY(Z3_mk_bvsub, mk_c(c)->get_bv_fid(), OP_BSUB, SKIP); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_bvneg(Z3_context c, Z3_ast n) { @@ -382,7 +382,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ LOG_Z3_mk_bvneg(c, n); RESET_ERROR_CODE(); MK_UNARY_BODY(Z3_mk_bvneg, mk_c(c)->get_bv_fid(), OP_BNEG, SKIP); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_get_bv_sort_size(Z3_context c, Z3_sort t) { diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 460101d34..604177561 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -53,7 +53,7 @@ extern "C" { Z3_bool_opt Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value) { memory::initialize(UINT_MAX); LOG_Z3_global_param_get(param_id, param_value); - *param_value = 0; + *param_value = nullptr; try { g_Z3_global_param_get_buffer = gparams::get_value(param_id); *param_value = g_Z3_global_param_get_buffer.c_str(); diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 8299c136c..12a4642c1 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -70,7 +70,7 @@ namespace api { // ------------------------ context::context(context_params * p, bool user_ref_count): - m_params(p != 0 ? *p : context_params()), + m_params(p != nullptr ? *p : context_params()), m_user_ref_count(user_ref_count), m_manager(m_params.mk_ast_manager()), m_plugins(m()), @@ -89,7 +89,7 @@ namespace api { m_searching = false; - m_interruptable = 0; + m_interruptable = nullptr; m_error_handler = &default_error_handler; m_basic_fid = m().get_basic_family_id(); @@ -108,7 +108,7 @@ namespace api { context::~context() { - m_last_obj = 0; + m_last_obj = nullptr; u_map::iterator it = m_allocated_objects.begin(); while (it != m_allocated_objects.end()) { api::object* val = it->m_value; @@ -131,7 +131,7 @@ namespace api { context::set_interruptable::~set_interruptable() { #pragma omp critical (set_interruptable) { - m_ctx.m_interruptable = 0; + m_ctx.m_interruptable = nullptr; } } @@ -175,7 +175,7 @@ namespace api { } expr * context::mk_numeral_core(rational const & n, sort * s) { - expr* e = 0; + expr* e = nullptr; family_id fid = s->get_family_id(); if (fid == m_arith_fid) { e = m_arith_util.mk_numeral(n, s); @@ -239,7 +239,7 @@ namespace api { void context::reset_last_result() { if (m_user_ref_count) m_last_result.reset(); - m_last_obj = 0; + m_last_obj = nullptr; } void context::save_object(object * r) { @@ -313,7 +313,7 @@ namespace api { // // ----------------------- realclosure::manager & context::rcfm() { - if (m_rcf_manager.get() == 0) { + if (m_rcf_manager.get() == nullptr) { m_rcf_manager = alloc(realclosure::manager, m_limit, m_rcf_qm); } return *(m_rcf_manager.get()); @@ -336,7 +336,7 @@ extern "C" { memory::initialize(UINT_MAX); Z3_context r = reinterpret_cast(alloc(api::context, reinterpret_cast(c), false)); RETURN_Z3(r); - Z3_CATCH_RETURN_NO_HANDLE(0); + Z3_CATCH_RETURN_NO_HANDLE(nullptr); } Z3_context Z3_API Z3_mk_context_rc(Z3_config c) { @@ -345,7 +345,7 @@ extern "C" { memory::initialize(UINT_MAX); Z3_context r = reinterpret_cast(alloc(api::context, reinterpret_cast(c), true)); RETURN_Z3(r); - Z3_CATCH_RETURN_NO_HANDLE(0); + Z3_CATCH_RETURN_NO_HANDLE(nullptr); } void Z3_API Z3_del_context(Z3_context c) { @@ -459,7 +459,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 == 0 ? "Z3 exception" : mk_c(c)->get_exception_msg(); + case Z3_EXCEPTION: return c == nullptr ? "Z3 exception" : mk_c(c)->get_exception_msg(); default: return "unknown"; } } diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 431638864..5e0082f09 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -45,9 +45,9 @@ namespace api { ast_ref_vector m_trail; public: fixedpoint_context(ast_manager& m, smt_params& p): - m_state(0), - m_reduce_app(0), - m_reduce_assign(0), + m_state(nullptr), + m_reduce_app(nullptr), + m_reduce_assign(nullptr), m_context(m, m_register_engine, p), m_trail(m) {} @@ -74,7 +74,7 @@ namespace api { m_reduce_assign = f; } void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) override { - expr* r = 0; + expr* r = nullptr; if (m_reduce_app) { m_reduce_app(m_state, f, num_args, args, &r); result = r; @@ -85,7 +85,7 @@ namespace api { m_trail.push_back(r); } // allow fallthrough. - if (r == 0) { + if (r == nullptr) { ast_manager& m = m_context.get_manager(); result = m.mk_app(f, num_args, args); } @@ -171,22 +171,22 @@ extern "C" { sort * r = to_sort(s); if (Z3_get_sort_kind(c, s) != Z3_RELATION_SORT) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } if (col >= r->get_num_parameters()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_sort res = of_sort(to_sort(p.get_ast())); RETURN_Z3(res); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, __uint64 size) { @@ -196,7 +196,7 @@ extern "C" { sort* s = mk_c(c)->datalog_util().mk_sort(to_symbol(name), size); mk_c(c)->save_ast_trail(s); RETURN_Z3(of_sort(s)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, __uint64 * out) { @@ -228,7 +228,7 @@ extern "C" { mk_c(c)->save_object(d); Z3_fixedpoint r = of_datalog(d); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_fixedpoint_inc_ref(Z3_context c, Z3_fixedpoint s) { @@ -331,7 +331,7 @@ extern "C" { expr* e = to_fixedpoint_ref(d)->ctx().get_answer_as_formula(); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_fixedpoint_get_reason_unknown(Z3_context c,Z3_fixedpoint d) { @@ -366,7 +366,7 @@ extern "C" { ctx.set_ignore_check(true); if (!parse_smt2_commands(ctx, s)) { SET_ERROR_CODE(Z3_PARSER_ERROR); - return 0; + return nullptr; } Z3_ast_vector_ref* v = alloc(Z3_ast_vector_ref, *mk_c(c), m); @@ -398,7 +398,7 @@ extern "C" { std::string str(s); std::istringstream is(str); RETURN_Z3(Z3_fixedpoint_from_stream(c, d, is)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast_vector Z3_API Z3_fixedpoint_from_file( @@ -410,10 +410,10 @@ extern "C" { std::ifstream is(s); if (!is) { SET_ERROR_CODE(Z3_PARSER_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } RETURN_Z3(Z3_fixedpoint_from_stream(c, d, is)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } @@ -426,7 +426,7 @@ extern "C" { mk_c(c)->save_object(st); Z3_stats r = of_stats(st); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_fixedpoint_register_relation(Z3_context c,Z3_fixedpoint d, Z3_func_decl f) { @@ -473,7 +473,7 @@ extern "C" { v->m_ast_vector.push_back(m.mk_not(queries[i].get())); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast_vector Z3_API Z3_fixedpoint_get_assertions( @@ -490,7 +490,7 @@ extern "C" { v->m_ast_vector.push_back(to_fixedpoint_ref(d)->ctx().get_assertion(i)); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_fixedpoint_set_reduce_assign_callback( @@ -541,7 +541,7 @@ extern "C" { expr_ref r = to_fixedpoint_ref(d)->get_cover_delta(level, to_func_decl(pred)); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r.get())); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_fixedpoint_add_cover(Z3_context c, Z3_fixedpoint d, int level, Z3_func_decl pred, Z3_ast property) { @@ -573,7 +573,7 @@ extern "C" { to_fixedpoint_ref(f)->collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_fixedpoint_set_params(Z3_context c, Z3_fixedpoint d, Z3_params p) { diff --git a/src/api/api_datalog.h b/src/api/api_datalog.h index 588ee02d3..35458f902 100644 --- a/src/api/api_datalog.h +++ b/src/api/api_datalog.h @@ -37,7 +37,7 @@ namespace api { struct Z3_fixedpoint_ref : public api::object { api::fixedpoint_context * m_datalog; params_ref m_params; - Z3_fixedpoint_ref(api::context& c): api::object(c), m_datalog(0) {} + Z3_fixedpoint_ref(api::context& c): api::object(c), m_datalog(nullptr) {} ~Z3_fixedpoint_ref() override { dealloc(m_datalog); } }; diff --git a/src/api/api_datalog_spacer.inc b/src/api/api_datalog_spacer.inc index 871d2be63..1888d4b96 100644 --- a/src/api/api_datalog_spacer.inc +++ b/src/api/api_datalog_spacer.inc @@ -49,7 +49,7 @@ Notes: expr* e = to_fixedpoint_ref(d)->ctx().get_ground_sat_answer(); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast_vector Z3_API Z3_fixedpoint_get_rules_along_trace( @@ -69,7 +69,7 @@ Notes: v->m_ast_vector.push_back(rules[i].get()); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_symbol Z3_API Z3_fixedpoint_get_rule_names_along_trace( @@ -90,7 +90,7 @@ Notes: ss << ";" << names[i].str(); } RETURN_Z3(of_symbol(symbol(ss.str().substr(1).c_str()))); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_fixedpoint_add_invariant(Z3_context c, Z3_fixedpoint d, Z3_func_decl pred, Z3_ast property) { @@ -108,6 +108,6 @@ Notes: expr_ref r = to_fixedpoint_ref(d)->ctx().get_reachable(to_func_decl(pred)); mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r.get())); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index d667a7428..df0b2317f 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -52,12 +52,12 @@ extern "C" { { datatype_decl * dt = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, 1, constrs); - bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, 0, tuples); + bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, nullptr, tuples); del_datatype_decl(dt); if (!is_ok) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } } @@ -82,7 +82,7 @@ extern "C" { proj_decls[i] = of_func_decl(_accs[i]); } RETURN_Z3_mk_tuple_sort(of_sort(tuple)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_enumeration_sort(Z3_context c, @@ -108,18 +108,18 @@ extern "C" { recognizer_s += e_name.str(); symbol recognizer(recognizer_s.c_str()); - constrs.push_back(mk_constructor_decl(e_name, recognizer, 0, 0)); + constrs.push_back(mk_constructor_decl(e_name, recognizer, 0, nullptr)); } { - datatype_decl * dt = mk_datatype_decl(dt_util, to_symbol(name), 0, 0, n, constrs.c_ptr()); - bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, 0, sorts); + datatype_decl * dt = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, n, constrs.c_ptr()); + bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, nullptr, sorts); del_datatype_decl(dt); if (!is_ok) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } } @@ -143,7 +143,7 @@ extern "C" { } RETURN_Z3_mk_enumeration_sort(of_sort(e)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_list_sort(Z3_context c, @@ -168,7 +168,7 @@ extern "C" { mk_accessor_decl(m, symbol("tail"), type_ref(0)) }; constructor_decl* constrs[2] = { - mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, 0), + mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, nullptr), // Leo: SMT 2.0 document uses 'insert' instead of cons mk_constructor_decl(symbol("cons"), symbol("is_cons"), 2, head_tail) }; @@ -176,12 +176,12 @@ extern "C" { sort_ref_vector sorts(m); { datatype_decl * decl = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, 2, constrs); - bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &decl, 0, 0, sorts); + bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &decl, 0, nullptr, sorts); del_datatype_decl(decl); if (!is_ok) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } } sort * s = sorts.get(0); @@ -225,7 +225,7 @@ extern "C" { *tail_decl = of_func_decl(f); } RETURN_Z3_mk_list_sort(of_sort(s)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } struct constructor { @@ -259,7 +259,7 @@ extern "C" { cnstr->m_sort_refs.push_back(sort_refs[i]); } RETURN_Z3(reinterpret_cast(cnstr)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } @@ -349,12 +349,12 @@ extern "C" { sort_ref_vector sorts(m); { datatype_decl * data = mk_datatype_decl(c, name, num_constructors, constructors); - bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &data, 0, 0, sorts); + bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &data, 0, nullptr, sorts); del_datatype_decl(data); if (!is_ok) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } } sort * s = sorts.get(0); @@ -367,7 +367,7 @@ extern "C" { cn->m_constructor = cnstrs[i]; } RETURN_Z3_mk_datatype(of_sort(s)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } typedef ptr_vector constructor_list; @@ -383,7 +383,7 @@ extern "C" { result->push_back(reinterpret_cast(constructors[i])); } RETURN_Z3(reinterpret_cast(result)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_del_constructor_list(Z3_context c, Z3_constructor_list clist) { @@ -412,7 +412,7 @@ extern "C" { datas.push_back(mk_datatype_decl(c, sort_names[i], cl->size(), reinterpret_cast(cl->c_ptr()))); } sort_ref_vector _sorts(m); - bool ok = mk_c(c)->get_dt_plugin()->mk_datatypes(datas.size(), datas.c_ptr(), 0, 0, _sorts); + bool ok = mk_c(c)->get_dt_plugin()->mk_datatypes(datas.size(), datas.c_ptr(), 0, nullptr, _sorts); del_datatype_decls(datas.size(), datas.c_ptr()); if (!ok) { @@ -454,17 +454,17 @@ extern "C" { Z3_func_decl get_datatype_sort_constructor_core(Z3_context c, Z3_sort t, unsigned idx) { RESET_ERROR_CODE(); - CHECK_VALID_AST(t, 0); + CHECK_VALID_AST(t, nullptr); 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); - return 0; + return nullptr; } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } func_decl* decl = (decls)[idx]; mk_c(c)->save_ast_trail(decl); @@ -477,7 +477,7 @@ extern "C" { RESET_ERROR_CODE(); Z3_func_decl r = get_datatype_sort_constructor_core(c, t, idx); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_func_decl Z3_API Z3_get_datatype_sort_recognizer(Z3_context c, Z3_sort t, unsigned idx) { @@ -489,18 +489,18 @@ extern "C" { if (!dt_util.is_datatype(_t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } func_decl* decl = (decls)[idx]; decl = dt_util.get_constructor_recognizer(decl); mk_c(c)->save_ast_trail(decl); RETURN_Z3(of_func_decl(decl)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_func_decl Z3_API Z3_get_datatype_sort_constructor_accessor(Z3_context c, Z3_sort t, unsigned idx_c, unsigned idx_a) { @@ -512,28 +512,28 @@ extern "C" { if (!dt_util.is_datatype(_t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx_c >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } func_decl* decl = (decls)[idx_c]; if (decl->get_arity() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } decl = (accs)[idx_a]; mk_c(c)->save_ast_trail(decl); RETURN_Z3(of_func_decl(decl)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_func_decl Z3_API Z3_get_tuple_sort_mk_decl(Z3_context c, Z3_sort t) { @@ -544,11 +544,11 @@ extern "C" { 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_func_decl r = get_datatype_sort_constructor_core(c, t, 0); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_get_tuple_sort_num_fields(Z3_context c, Z3_sort t) { @@ -579,22 +579,22 @@ extern "C" { 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } ptr_vector const & accs = *dt_util.get_constructor_accessors((decls)[0]); if (accs.size() <= i) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } func_decl* acc = (accs)[i]; mk_c(c)->save_ast_trail(acc); RETURN_Z3(of_func_decl(acc)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_datatype_update_field( @@ -614,7 +614,7 @@ extern "C" { mk_c(c)->save_ast_trail(r); check_sorts(c, r); RETURN_Z3(of_ast(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 484cb3d76..972505ca2 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -56,7 +56,7 @@ extern "C" { sort * s = ctx->fpautil().mk_rm_sort(); mk_c(c)->save_ast_trail(s); RETURN_Z3(of_sort(s)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_even(Z3_context c) { @@ -67,7 +67,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_nearest_ties_to_even(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_rne(Z3_context c) { @@ -78,7 +78,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_nearest_ties_to_even(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_away(Z3_context c) { @@ -89,7 +89,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_nearest_ties_to_away(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_rna(Z3_context c) { @@ -100,7 +100,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_nearest_ties_to_away(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_round_toward_positive(Z3_context c) { @@ -111,7 +111,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_toward_positive(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_rtp(Z3_context c) { @@ -122,7 +122,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_toward_positive(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_round_toward_negative(Z3_context c) { @@ -133,7 +133,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_toward_negative(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_rtn(Z3_context c) { @@ -144,7 +144,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_toward_negative(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(Z3_context c) { @@ -155,7 +155,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_toward_zero(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_rtz(Z3_context c) { @@ -166,7 +166,7 @@ extern "C" { expr * a = ctx->fpautil().mk_round_toward_zero(); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } @@ -181,7 +181,7 @@ extern "C" { sort * s = ctx->fpautil().mk_float_sort(ebits, sbits); ctx->save_ast_trail(s); RETURN_Z3(of_sort(s)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_fpa_sort_half(Z3_context c) { @@ -220,50 +220,50 @@ extern "C" { Z3_TRY; LOG_Z3_mk_fpa_nan(c, s); RESET_ERROR_CODE(); - CHECK_VALID_AST(s, 0); + CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_nan(to_sort(s)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_inf(Z3_context c, Z3_sort s, Z3_bool negative) { Z3_TRY; LOG_Z3_mk_fpa_inf(c, s, negative); RESET_ERROR_CODE(); - CHECK_VALID_AST(s, 0); + CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = negative != 0 ? ctx->fpautil().mk_ninf(to_sort(s)) : ctx->fpautil().mk_pinf(to_sort(s)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_zero(Z3_context c, Z3_sort s, Z3_bool negative) { Z3_TRY; LOG_Z3_mk_fpa_inf(c, s, negative); RESET_ERROR_CODE(); - CHECK_VALID_AST(s, 0); + CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = negative != 0 ? ctx->fpautil().mk_nzero(to_sort(s)) : ctx->fpautil().mk_pzero(to_sort(s)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_fp(Z3_context c, Z3_ast sgn, Z3_ast exp, Z3_ast sig) { @@ -272,13 +272,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_bv(c, sgn) || !is_bv(c, exp) || !is_bv(c, sig)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_fp(to_expr(sgn), to_expr(exp), to_expr(sig)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_numeral_float(Z3_context c, float v, Z3_sort ty) { @@ -287,7 +287,7 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); scoped_mpf tmp(ctx->fpautil().fm()); @@ -298,7 +298,7 @@ extern "C" { expr * a = ctx->fpautil().mk_value(tmp); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_numeral_double(Z3_context c, double v, Z3_sort ty) { @@ -307,7 +307,7 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); scoped_mpf tmp(ctx->fpautil().fm()); @@ -315,7 +315,7 @@ extern "C" { expr * a = ctx->fpautil().mk_value(tmp); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_numeral_int(Z3_context c, signed v, Z3_sort ty) { @@ -324,7 +324,7 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); scoped_mpf tmp(ctx->fpautil().fm()); @@ -335,7 +335,7 @@ extern "C" { expr * a = ctx->fpautil().mk_value(tmp); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_numeral_int_uint(Z3_context c, Z3_bool sgn, signed exp, unsigned sig, Z3_sort ty) { @@ -344,7 +344,7 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); scoped_mpf tmp(ctx->fpautil().fm()); @@ -355,7 +355,7 @@ extern "C" { expr * a = ctx->fpautil().mk_value(tmp); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, Z3_bool sgn, __int64 exp, __uint64 sig, Z3_sort ty) { @@ -364,7 +364,7 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); scoped_mpf tmp(ctx->fpautil().fm()); @@ -375,7 +375,7 @@ extern "C" { expr * a = ctx->fpautil().mk_value(tmp); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_abs(Z3_context c, Z3_ast t) { @@ -384,13 +384,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_abs(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_neg(Z3_context c, Z3_ast t) { @@ -399,13 +399,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_neg(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_add(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2) { @@ -414,13 +414,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_add(to_expr(rm), to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_sub(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2) { @@ -429,13 +429,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_sub(to_expr(rm), to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_mul(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2) { @@ -444,13 +444,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_mul(to_expr(rm), to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_div(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2) { @@ -459,13 +459,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_div(to_expr(rm), to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_fma(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2, Z3_ast t3) { @@ -474,13 +474,13 @@ extern "C" { 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_fma(to_expr(rm), to_expr(t1), to_expr(t2), to_expr(t3)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_sqrt(Z3_context c, Z3_ast rm, Z3_ast t) { @@ -489,13 +489,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_sqrt(to_expr(rm), to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_rem(Z3_context c, Z3_ast t1, Z3_ast t2) { @@ -504,13 +504,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_rem(to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_round_to_integral(Z3_context c, Z3_ast rm, Z3_ast t) { @@ -519,13 +519,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_round_to_integral(to_expr(rm), to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_min(Z3_context c, Z3_ast t1, Z3_ast t2) { @@ -534,13 +534,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_min(to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_max(Z3_context c, Z3_ast t1, Z3_ast t2) { @@ -549,13 +549,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_max(to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_leq(Z3_context c, Z3_ast t1, Z3_ast t2) { @@ -564,13 +564,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_le(to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_lt(Z3_context c, Z3_ast t1, Z3_ast t2) { @@ -579,13 +579,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_lt(to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_geq(Z3_context c, Z3_ast t1, Z3_ast t2) { @@ -594,13 +594,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_ge(to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_gt(Z3_context c, Z3_ast t1, Z3_ast t2) { @@ -609,13 +609,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_gt(to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_eq(Z3_context c, Z3_ast t1, Z3_ast t2) { @@ -624,13 +624,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_float_eq(to_expr(t1), to_expr(t2)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_is_normal(Z3_context c, Z3_ast t) { @@ -639,13 +639,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_is_normal(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_is_subnormal(Z3_context c, Z3_ast t) { @@ -654,13 +654,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_is_subnormal(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_is_zero(Z3_context c, Z3_ast t) { @@ -669,13 +669,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_is_zero(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_is_infinite(Z3_context c, Z3_ast t) { @@ -684,13 +684,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_is_inf(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_is_nan(Z3_context c, Z3_ast t) { @@ -699,13 +699,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_is_nan(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_is_negative(Z3_context c, Z3_ast t) { @@ -714,13 +714,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_is_negative(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_is_positive(Z3_context c, Z3_ast t) { @@ -729,13 +729,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_is_positive(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } @@ -745,19 +745,19 @@ extern "C" { RESET_ERROR_CODE(); if (!is_bv(c, bv) || !is_fp_sort(c, s)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + 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); - return 0; + return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(bv)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_fp_float(Z3_context c, Z3_ast rm, Z3_ast t, Z3_sort s) { @@ -770,12 +770,12 @@ extern "C" { !fu.is_float(to_expr(t)) || !fu.is_float(to_sort(s))) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_fp_real(Z3_context c, Z3_ast rm, Z3_ast t, Z3_sort s) { @@ -788,12 +788,12 @@ extern "C" { !ctx->autil().is_real(to_expr(t)) || !fu.is_float(to_sort(s))) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_fp_signed(Z3_context c, Z3_ast rm, Z3_ast t, Z3_sort s) { @@ -806,12 +806,12 @@ extern "C" { !ctx->bvutil().is_bv(to_expr(t)) || !fu.is_float(to_sort(s))) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_fp_unsigned(Z3_context c, Z3_ast rm, Z3_ast t, Z3_sort s) { @@ -824,12 +824,12 @@ extern "C" { !ctx->bvutil().is_bv(to_expr(t)) || !fu.is_float(to_sort(s))) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } expr * a = fu.mk_to_fp_unsigned(to_sort(s), to_expr(rm), to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_ubv(Z3_context c, Z3_ast rm, Z3_ast t, unsigned sz) { @@ -838,13 +838,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_to_ubv(to_expr(rm), to_expr(t), sz); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_sbv(Z3_context c, Z3_ast rm, Z3_ast t, unsigned sz) { @@ -853,13 +853,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_to_sbv(to_expr(rm), to_expr(t), sz); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_real(Z3_context c, Z3_ast t) { @@ -868,13 +868,13 @@ extern "C" { RESET_ERROR_CODE(); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); expr * a = ctx->fpautil().mk_to_real(to_expr(t)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_fpa_get_ebits(Z3_context c, Z3_sort s) { @@ -911,7 +911,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); - if (sgn == 0) { + if (sgn == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } @@ -939,8 +939,8 @@ extern "C" { Z3_TRY; LOG_Z3_fpa_get_numeral_sign_bv(c, t); RESET_ERROR_CODE(); - CHECK_NON_NULL(t, 0); - CHECK_VALID_AST(t, 0); + CHECK_NON_NULL(t, nullptr); + CHECK_VALID_AST(t, nullptr); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); family_id fid = mk_c(c)->get_fpa_fid(); @@ -949,13 +949,13 @@ extern "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); - RETURN_Z3(0); + 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); - return 0; + return nullptr; } app * a; if (mpfm.is_pos(val)) @@ -964,15 +964,15 @@ extern "C" { a = ctx->bvutil().mk_numeral(1, 1); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_fpa_get_numeral_significand_bv(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_get_numeral_significand_bv(c, t); RESET_ERROR_CODE(); - CHECK_NON_NULL(t, 0); - CHECK_VALID_AST(t, 0); + CHECK_NON_NULL(t, nullptr); + CHECK_VALID_AST(t, nullptr); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); @@ -982,13 +982,13 @@ extern "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); - RETURN_Z3(0); + 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } unsigned sbits = val.get().get_sbits(); scoped_mpq q(mpqm); @@ -997,15 +997,15 @@ extern "C" { app * a = mk_c(c)->bvutil().mk_numeral(q.get(), sbits-1); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_fpa_get_numeral_significand_string(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_fpa_get_numeral_significand_string(c, t); RESET_ERROR_CODE(); - CHECK_NON_NULL(t, 0); - CHECK_VALID_AST(t, 0); + CHECK_NON_NULL(t, nullptr); + CHECK_VALID_AST(t, nullptr); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); @@ -1041,7 +1041,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); - if (n == 0) { + if (n == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } @@ -1076,8 +1076,8 @@ extern "C" { Z3_TRY; LOG_Z3_fpa_get_numeral_exponent_string(c, t, biased); RESET_ERROR_CODE(); - CHECK_NON_NULL(t, 0); - CHECK_VALID_AST(t, 0); + CHECK_NON_NULL(t, nullptr); + CHECK_VALID_AST(t, nullptr); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); family_id fid = mk_c(c)->get_fpa_fid(); @@ -1119,7 +1119,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); - if (n == 0) { + if (n == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } @@ -1161,8 +1161,8 @@ extern "C" { Z3_TRY; LOG_Z3_fpa_get_numeral_exponent_bv(c, t, biased); RESET_ERROR_CODE(); - CHECK_NON_NULL(t, 0); - CHECK_VALID_AST(t, 0); + CHECK_NON_NULL(t, nullptr); + CHECK_VALID_AST(t, nullptr); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); family_id fid = mk_c(c)->get_fpa_fid(); @@ -1170,13 +1170,13 @@ extern "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); - RETURN_Z3(0); + 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } unsigned ebits = val.get().get_ebits(); mpf_exp_t exp; @@ -1194,23 +1194,23 @@ extern "C" { app * a = mk_c(c)->bvutil().mk_numeral(exp, ebits); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_ieee_bv(Z3_context c, Z3_ast t) { Z3_TRY; LOG_Z3_mk_fpa_to_ieee_bv(c, t); RESET_ERROR_CODE(); - CHECK_NON_NULL(t, 0); - CHECK_VALID_AST(t, 0); + CHECK_NON_NULL(t, nullptr); + CHECK_VALID_AST(t, nullptr); if (!is_fp(c, t)) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); Z3_ast r = of_ast(ctx->fpautil().mk_to_ieee_bv(to_expr(t))); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_fpa_to_fp_int_real(Z3_context c, Z3_ast rm, Z3_ast exp, Z3_ast sig, Z3_sort s) { @@ -1224,12 +1224,12 @@ extern "C" { !ctx->autil().is_real(to_expr(sig)) || !fu.is_float(to_sort(s))) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(exp), to_expr(sig)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_fpa_is_numeral_nan(Z3_context c, Z3_ast t) { diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 0f1b9056b..0783af5ab 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -30,14 +30,14 @@ extern "C" { RESET_ERROR_CODE(); if (proofs != 0 && !mk_c(c)->m().proofs_enabled()) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_goal_ref * g = alloc(Z3_goal_ref, *mk_c(c)); g->m_goal = alloc(goal, mk_c(c)->m(), proofs != 0, models != 0, unsat_cores != 0); mk_c(c)->save_object(g); Z3_goal r = of_goal(g); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_goal_inc_ref(Z3_context c, Z3_goal g) { @@ -119,12 +119,12 @@ extern "C" { RESET_ERROR_CODE(); if (idx >= to_goal_ref(g)->size()) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr * result = to_goal_ref(g)->form(idx); mk_c(c)->save_ast_trail(result); RETURN_Z3(of_ast(result)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_goal_num_exprs(Z3_context c, Z3_goal g) { @@ -161,7 +161,7 @@ extern "C" { mk_c(target)->save_object(_r); Z3_goal r = of_goal(_r); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_goal_to_string(Z3_context c, Z3_goal g) { diff --git a/src/api/api_goal.h b/src/api/api_goal.h index 3b109f8da..fa2ea61cf 100644 --- a/src/api/api_goal.h +++ b/src/api/api_goal.h @@ -29,6 +29,6 @@ struct Z3_goal_ref : public api::object { inline Z3_goal_ref * to_goal(Z3_goal g) { return reinterpret_cast(g); } inline Z3_goal of_goal(Z3_goal_ref * g) { return reinterpret_cast(g); } -inline goal_ref to_goal_ref(Z3_goal g) { return g == 0 ? goal_ref() : to_goal(g)->m_goal; } +inline goal_ref to_goal_ref(Z3_goal g) { return g == nullptr ? goal_ref() : to_goal(g)->m_goal; } #endif diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index d6f4e1128..1000a6d3b 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -110,7 +110,7 @@ extern "C" { pre_parents_vec, interpolants, theory_vec, - 0); // ignore params for now FIXME + nullptr); // ignore params for now FIXME // copy result back for (unsigned i = 0; i < interpolants.size(); i++){ @@ -174,7 +174,7 @@ extern "C" { itp_vec, theory_vec); - *error = res ? 0 : itp_err.str().c_str(); + *error = res ? nullptr : itp_err.str().c_str(); return res; } @@ -227,7 +227,7 @@ extern "C" { cnsts, _pat, interp, - (interpolation_options_struct *)0 // ignore params for now + (interpolation_options_struct *)nullptr // ignore params for now ); // copy result back @@ -236,7 +236,7 @@ extern "C" { _m.dec_ref(interp[i]); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_lbool Z3_API Z3_compute_interpolant(Z3_context c, Z3_ast pat, Z3_params p, Z3_ast_vector *out_interp, Z3_model *model){ @@ -283,7 +283,7 @@ extern "C" { cnsts, interp, m, - 0 // ignore params for now + nullptr // ignore params for now ); } catch (z3_exception & ex) { @@ -297,8 +297,8 @@ extern "C" { Z3_lbool status = of_lbool(_status); - Z3_ast_vector_ref *v = 0; - *model = 0; + Z3_ast_vector_ref *v = nullptr; + *model = nullptr; if (_status == l_false){ // copy result back @@ -510,7 +510,7 @@ extern "C" { read_error.clear(); try { std::string foo(filename); - Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, 0, 0, 0, 0, 0); + Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, nullptr, nullptr, 0, nullptr, nullptr); Z3_app app = Z3_to_app(ctx, assrts); int nconjs = Z3_get_app_num_args(ctx, app); assertions.resize(nconjs); @@ -523,7 +523,7 @@ extern "C" { *error = read_msg.c_str(); return false; } - Z3_set_error_handler(ctx, 0); + Z3_set_error_handler(ctx, nullptr); return true; } @@ -571,7 +571,7 @@ extern "C" { hash_map pred_map; for (unsigned j = 0; j < num; j++){ - Z3_ast lhs = 0, rhs = read_cnsts[j]; + Z3_ast lhs = nullptr, rhs = read_cnsts[j]; if (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, rhs))) == Z3_OP_IMPLIES){ Z3_app app1 = Z3_to_app(ctx, rhs); diff --git a/src/api/api_log.cpp b/src/api/api_log.cpp index 410110d9a..1bdbb8735 100644 --- a/src/api/api_log.cpp +++ b/src/api/api_log.cpp @@ -21,15 +21,15 @@ Revision History: #include "util/util.h" #include "util/version.h" -std::ostream * g_z3_log = 0; +std::ostream * g_z3_log = nullptr; bool g_z3_log_enabled = false; extern "C" { void Z3_close_log_unsafe(void) { - if (g_z3_log != 0) { + if (g_z3_log != nullptr) { dealloc(g_z3_log); g_z3_log_enabled = false; - g_z3_log = 0; + g_z3_log = nullptr; } } @@ -40,12 +40,12 @@ extern "C" { #pragma omp critical (z3_log) { #endif - if (g_z3_log != 0) + if (g_z3_log != nullptr) Z3_close_log_unsafe(); g_z3_log = alloc(std::ofstream, filename); if (g_z3_log->bad() || g_z3_log->fail()) { dealloc(g_z3_log); - g_z3_log = 0; + g_z3_log = nullptr; res = Z3_FALSE; } else { @@ -61,13 +61,13 @@ extern "C" { } void Z3_API Z3_append_log(Z3_string str) { - if (g_z3_log == 0) + if (g_z3_log == nullptr) return; #ifdef Z3_LOG_SYNC #pragma omp critical (z3_log) { #endif - if (g_z3_log != 0) + if (g_z3_log != nullptr) _Z3_append_log(static_cast(str)); #ifdef Z3_LOG_SYNC } @@ -75,7 +75,7 @@ extern "C" { } void Z3_API Z3_close_log(void) { - if (g_z3_log != 0) { + if (g_z3_log != nullptr) { #ifdef Z3_LOG_SYNC #pragma omp critical (z3_log) { diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index d9936ff66..09a255738 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -38,7 +38,7 @@ extern "C" { m_ref->m_model = alloc(model, mk_c(c)->m()); mk_c(c)->save_object(m_ref); RETURN_Z3(of_model(m_ref)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_model_inc_ref(Z3_context c, Z3_model m) { @@ -65,14 +65,14 @@ extern "C" { Z3_TRY; LOG_Z3_model_get_const_interp(c, m, a); RESET_ERROR_CODE(); - CHECK_NON_NULL(m, 0); + CHECK_NON_NULL(m, nullptr); expr * r = to_model_ref(m)->get_const_interp(to_func_decl(a)); if (!r) { - RETURN_Z3(0); + RETURN_Z3(nullptr); } mk_c(c)->save_ast_trail(r); RETURN_Z3(of_expr(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_model_has_interp(Z3_context c, Z3_model m, Z3_func_decl a) { @@ -91,17 +91,17 @@ extern "C" { Z3_TRY; LOG_Z3_model_get_func_interp(c, m, f); RESET_ERROR_CODE(); - CHECK_NON_NULL(m, 0); + 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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_func_interp_ref * fi = alloc(Z3_func_interp_ref, *mk_c(c), to_model_ref(m)); fi->m_func_interp = _fi; mk_c(c)->save_object(fi); RETURN_Z3(of_func_interp(fi)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_model_get_num_consts(Z3_context c, Z3_model m) { @@ -117,16 +117,16 @@ extern "C" { Z3_TRY; LOG_Z3_model_get_const_decl(c, m, i); RESET_ERROR_CODE(); - CHECK_NON_NULL(m, 0); + CHECK_NON_NULL(m, nullptr); model * _m = to_model_ref(m); if (i < _m->get_num_constants()) { RETURN_Z3(of_func_decl(_m->get_constant(i))); } else { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_model_get_num_funcs(Z3_context c, Z3_model m) { @@ -139,11 +139,11 @@ extern "C" { } Z3_func_decl get_model_func_decl_core(Z3_context c, Z3_model m, unsigned i) { - CHECK_NON_NULL(m, 0); + CHECK_NON_NULL(m, nullptr); model * _m = to_model_ref(m); if (i >= _m->get_num_functions()) { SET_ERROR_CODE(Z3_IOB); - return 0; + return nullptr; } return of_func_decl(_m->get_function(i)); } @@ -154,13 +154,13 @@ extern "C" { RESET_ERROR_CODE(); Z3_func_decl r = get_model_func_decl_core(c, m, i); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, Z3_bool model_completion, Z3_ast * v) { Z3_TRY; LOG_Z3_model_eval(c, m, t, model_completion, v); - if (v) *v = 0; + if (v) *v = nullptr; RESET_ERROR_CODE(); CHECK_NON_NULL(m, Z3_FALSE); CHECK_IS_EXPR(t, Z3_FALSE); @@ -187,11 +187,11 @@ extern "C" { RESET_ERROR_CODE(); if (i >= to_model_ref(m)->get_num_uninterpreted_sorts()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } sort * s = to_model_ref(m)->get_uninterpreted_sort(i); RETURN_Z3(of_sort(s)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast_vector Z3_API Z3_model_get_sort_universe(Z3_context c, Z3_model m, Z3_sort s) { @@ -200,7 +200,7 @@ extern "C" { RESET_ERROR_CODE(); if (!to_model_ref(m)->has_uninterpreted_sort(to_sort(s))) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } 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()); @@ -210,7 +210,7 @@ extern "C" { v->m_ast_vector.push_back(universe[i]); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context target) { @@ -222,7 +222,7 @@ extern "C" { dst->m_model = to_model_ref(m)->translate(tr); mk_c(target)->save_object(dst); RETURN_Z3(of_model(dst)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a) { @@ -242,9 +242,9 @@ extern "C" { } else { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_func_interp Z3_API Z3_add_func_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast else_val) { @@ -259,7 +259,7 @@ extern "C" { mdl->register_decl(d, f_ref->m_func_interp); f_ref->m_func_interp->set_else(to_expr(else_val)); RETURN_Z3(of_func_interp(f_ref)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_add_const_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast a) { @@ -310,30 +310,30 @@ extern "C" { Z3_TRY; LOG_Z3_func_interp_get_entry(c, f, i); RESET_ERROR_CODE(); - CHECK_NON_NULL(f, 0); + CHECK_NON_NULL(f, nullptr); if (i >= to_func_interp_ref(f)->num_entries()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_func_entry_ref * e = alloc(Z3_func_entry_ref, *mk_c(c), to_func_interp(f)->m_model.get()); e->m_func_interp = to_func_interp_ref(f); e->m_func_entry = to_func_interp_ref(f)->get_entry(i); mk_c(c)->save_object(e); RETURN_Z3(of_func_entry(e)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_func_interp_get_else(Z3_context c, Z3_func_interp f) { Z3_TRY; LOG_Z3_func_interp_get_else(c, f); RESET_ERROR_CODE(); - CHECK_NON_NULL(f, 0); + CHECK_NON_NULL(f, nullptr); expr * e = to_func_interp_ref(f)->get_else(); if (e) { mk_c(c)->save_ast_trail(e); } RETURN_Z3(of_expr(e)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_func_interp_set_else(Z3_context c, Z3_func_interp f, Z3_ast else_value) { @@ -399,7 +399,7 @@ extern "C" { expr * v = to_func_entry_ref(e)->get_result(); mk_c(c)->save_ast_trail(v); RETURN_Z3(of_expr(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_func_entry_get_num_args(Z3_context c, Z3_func_entry e) { @@ -416,11 +416,11 @@ extern "C" { RESET_ERROR_CODE(); if (i >= to_func_entry(e)->m_func_interp->get_arity()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr * r = to_func_entry(e)->m_func_entry->get_arg(i); RETURN_Z3(of_expr(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } // ---------------------------- @@ -491,7 +491,7 @@ extern "C" { Z3_TRY; LOG_Z3_model_to_string(c, m); RESET_ERROR_CODE(); - CHECK_NON_NULL(m, 0); + CHECK_NON_NULL(m, nullptr); std::ostringstream buffer; std::string result; if (mk_c(c)->get_print_mode() == Z3_PRINT_SMTLIB2_COMPLIANT) { @@ -507,7 +507,7 @@ extern "C" { result = buffer.str(); } return mk_c(c)->mk_external_string(result); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_model.h b/src/api/api_model.h index 1ab10da79..fa94e9728 100644 --- a/src/api/api_model.h +++ b/src/api/api_model.h @@ -34,7 +34,7 @@ inline model * to_model_ref(Z3_model s) { return to_model(s)->m_model.get(); } struct Z3_func_interp_ref : public api::object { model_ref m_model; // must have it to prevent reference to m_func_interp to be killed. func_interp * m_func_interp; - Z3_func_interp_ref(api::context& c, model * m): api::object(c), m_model(m), m_func_interp(0) {} + Z3_func_interp_ref(api::context& c, model * m): api::object(c), m_model(m), m_func_interp(nullptr) {} ~Z3_func_interp_ref() override {} }; @@ -46,7 +46,7 @@ struct Z3_func_entry_ref : public api::object { model_ref m_model; // must have it to prevent reference to m_func_entry to be killed. func_interp * m_func_interp; func_entry const * m_func_entry; - Z3_func_entry_ref(api::context& c, model * m):api::object(c), m_model(m), m_func_interp(0), m_func_entry(0) {} + Z3_func_entry_ref(api::context& c, model * m):api::object(c), m_model(m), m_func_interp(nullptr), m_func_entry(nullptr) {} ~Z3_func_entry_ref() override {} }; diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index d3dabcd4e..5aa762a96 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -52,11 +52,11 @@ extern "C" { LOG_Z3_mk_numeral(c, n, ty); RESET_ERROR_CODE(); if (!check_numeral_sort(c, ty)) { - RETURN_Z3(0); + RETURN_Z3(nullptr); } if (!n) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } sort * _ty = to_sort(ty); bool is_float = mk_c(c)->fpautil().is_float(_ty); @@ -73,11 +73,11 @@ extern "C" { ('P' == *m) || ('+' == *m))))) { SET_ERROR_CODE(Z3_PARSER_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } ++m; } - ast * a = 0; + ast * a = nullptr; if (_ty->get_family_id() == mk_c(c)->get_fpa_fid()) { // avoid expanding floats into huge rationals. fpa_util & fu = mk_c(c)->fpautil(); @@ -89,7 +89,7 @@ extern "C" { else a = mk_c(c)->mk_numeral_core(rational(n), _ty); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_int(Z3_context c, int value, Z3_sort ty) { @@ -97,11 +97,11 @@ extern "C" { LOG_Z3_mk_int(c, value, ty); RESET_ERROR_CODE(); if (!check_numeral_sort(c, ty)) { - RETURN_Z3(0); + RETURN_Z3(nullptr); } ast * a = mk_c(c)->mk_numeral_core(rational(value), to_sort(ty)); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_unsigned_int(Z3_context c, unsigned value, Z3_sort ty) { @@ -109,11 +109,11 @@ extern "C" { LOG_Z3_mk_unsigned_int(c, value, ty); RESET_ERROR_CODE(); if (!check_numeral_sort(c, ty)) { - RETURN_Z3(0); + RETURN_Z3(nullptr); } ast * a = mk_c(c)->mk_numeral_core(rational(value), to_sort(ty)); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_int64(Z3_context c, long long value, Z3_sort ty) { @@ -121,12 +121,12 @@ extern "C" { LOG_Z3_mk_int64(c, value, ty); RESET_ERROR_CODE(); if (!check_numeral_sort(c, ty)) { - RETURN_Z3(0); + RETURN_Z3(nullptr); } rational n(value, rational::i64()); ast* a = mk_c(c)->mk_numeral_core(n, to_sort(ty)); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, unsigned long long value, Z3_sort ty) { @@ -134,12 +134,12 @@ extern "C" { LOG_Z3_mk_unsigned_int64(c, value, ty); RESET_ERROR_CODE(); if (!check_numeral_sort(c, ty)) { - RETURN_Z3(0); + RETURN_Z3(nullptr); } rational n(value, rational::ui64()); ast * a = mk_c(c)->mk_numeral_core(n, to_sort(ty)); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_is_numeral_ast(Z3_context c, Z3_ast a) { @@ -397,7 +397,7 @@ extern "C" { } ast * a = mk_c(c)->mk_numeral_core(r, mk_c(c)->bvutil().mk_sort(sz)); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 72180388e..2712eef6f 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -35,7 +35,7 @@ extern "C" { struct Z3_optimize_ref : public api::object { opt::context* m_opt; - Z3_optimize_ref(api::context& c): api::object(c), m_opt(0) {} + Z3_optimize_ref(api::context& c): api::object(c), m_opt(nullptr) {} ~Z3_optimize_ref() override { dealloc(m_opt); } }; inline Z3_optimize_ref * to_optimize(Z3_optimize o) { return reinterpret_cast(o); } @@ -50,7 +50,7 @@ extern "C" { o->m_opt = alloc(opt::context,mk_c(c)->m()); mk_c(c)->save_object(o); RETURN_Z3(of_optimize(o)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_optimize_inc_ref(Z3_context c, Z3_optimize o) { @@ -171,7 +171,7 @@ extern "C" { } mk_c(c)->save_object(m_ref); RETURN_Z3(of_model(m_ref)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_optimize_set_params(Z3_context c, Z3_optimize o, Z3_params p) { @@ -195,7 +195,7 @@ extern "C" { to_optimize_ptr(o)->collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } // get lower value or current approximation @@ -206,7 +206,7 @@ extern "C" { expr_ref e = to_optimize_ptr(o)->get_lower(idx); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } // get upper or current approximation @@ -217,7 +217,7 @@ extern "C" { expr_ref e = to_optimize_ptr(o)->get_upper(idx); mk_c(c)->save_ast_trail(e); RETURN_Z3(of_expr(e)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } // get lower value or current approximation @@ -231,7 +231,7 @@ extern "C" { mk_c(c)->save_object(v); v->m_ast_vector.append(es.size(), (ast*const*)es.c_ptr()); RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } // get upper or current approximation @@ -245,7 +245,7 @@ extern "C" { mk_c(c)->save_object(v); v->m_ast_vector.append(es.size(), (ast*const*)es.c_ptr()); RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_optimize_to_string(Z3_context c, Z3_optimize o) { @@ -277,7 +277,7 @@ extern "C" { mk_c(c)->save_object(st); Z3_stats r = of_stats(st); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } static void Z3_optimize_from_stream( @@ -367,7 +367,7 @@ extern "C" { v->m_ast_vector.push_back(h); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast_vector Z3_API Z3_optimize_get_objectives(Z3_context c, Z3_optimize o) { @@ -381,7 +381,7 @@ extern "C" { v->m_ast_vector.push_back(to_optimize_ptr(o)->get_objective(i)); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index 3f3cbed1d..d021ed6ad 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -34,7 +34,7 @@ extern "C" { mk_c(c)->save_object(p); Z3_params r = of_params(p); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } /** @@ -172,11 +172,11 @@ extern "C" { RESET_ERROR_CODE(); if (i >= to_param_descrs_ptr(p)->size()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_symbol result = of_symbol(to_param_descrs_ptr(p)->get_param_name(i)); return result; - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_param_descrs_get_documentation(Z3_context c, Z3_param_descrs p, Z3_symbol s) { @@ -184,12 +184,12 @@ extern "C" { LOG_Z3_param_descrs_get_documentation(c, p, s); RESET_ERROR_CODE(); char const* result = to_param_descrs_ptr(p)->get_descr(to_symbol(s)); - if (result == 0) { + if (result == nullptr) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } return mk_c(c)->mk_external_string(result); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_param_descrs_to_string(Z3_context c, Z3_param_descrs p) { diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index d5a98672b..2e33c1a13 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -80,7 +80,7 @@ extern "C" { ptr_vector::const_iterator end = ctx->end_assertions(); unsigned size = static_cast(end - it); return of_ast(mk_c(c)->mk_and(size, it)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_parse_smtlib2_string(Z3_context c, Z3_string str, @@ -96,7 +96,7 @@ extern "C" { std::istringstream is(s); Z3_ast r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_parse_smtlib2_file(Z3_context c, Z3_string file_name, @@ -111,10 +111,10 @@ extern "C" { std::ifstream is(file_name); if (!is) { SET_ERROR_CODE(Z3_PARSER_ERROR); - return 0; + return nullptr; } Z3_ast r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_pb.cpp b/src/api/api_pb.cpp index e6f8f77b4..8116789f9 100644 --- a/src/api/api_pb.cpp +++ b/src/api/api_pb.cpp @@ -34,7 +34,7 @@ extern "C" { mk_c(c)->save_ast_trail(a); check_sorts(c, a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_atleast(Z3_context c, unsigned num_args, @@ -48,7 +48,7 @@ extern "C" { mk_c(c)->save_ast_trail(a); check_sorts(c, a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_pble(Z3_context c, unsigned num_args, @@ -66,7 +66,7 @@ extern "C" { mk_c(c)->save_ast_trail(a); check_sorts(c, a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_pbge(Z3_context c, unsigned num_args, @@ -84,7 +84,7 @@ extern "C" { mk_c(c)->save_ast_trail(a); check_sorts(c, a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_pbeq(Z3_context c, unsigned num_args, @@ -102,7 +102,7 @@ extern "C" { mk_c(c)->save_ast_trail(a); check_sorts(c, a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 9be73289f..35ece4a59 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -50,7 +50,7 @@ extern "C" { if (!converter.to_polynomial(to_expr(p), _p, d) || !converter.to_polynomial(to_expr(q), _q, d)) { SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; + return nullptr; } Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(result); @@ -74,7 +74,7 @@ extern "C" { } } RETURN_Z3(of_ast_vector(result)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_qe.cpp b/src/api/api_qe.cpp index 34f21d64b..2516aacfb 100644 --- a/src/api/api_qe.cpp +++ b/src/api/api_qe.cpp @@ -56,7 +56,7 @@ extern "C" app_ref_vector vars(mk_c(c)->m ()); if (!to_apps(num_bounds, bound, vars)) { SET_ERROR_CODE (Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr_ref result (mk_c(c)->m ()); @@ -66,7 +66,7 @@ extern "C" mk_c(c)->save_ast_trail (result.get ()); return of_expr (result.get ()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_qe_model_project_skolem (Z3_context c, @@ -83,7 +83,7 @@ extern "C" ast_manager& man = mk_c(c)->m (); app_ref_vector vars(man); if (!to_apps(num_bounds, bound, vars)) { - RETURN_Z3(0); + RETURN_Z3(nullptr); } expr_ref result (mk_c(c)->m ()); @@ -103,7 +103,7 @@ extern "C" } return of_expr (result.get ()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_model_extrapolate (Z3_context c, @@ -130,7 +130,7 @@ extern "C" mk_c(c)->save_ast_trail (result.get ()); return of_expr (result.get ()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_qe_lite (Z3_context c, Z3_ast_vector vars, Z3_ast body) @@ -145,7 +145,7 @@ extern "C" app *a = to_app (vVars.get (i)); if (a->get_kind () != AST_APP) { SET_ERROR_CODE (Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } vApps.push_back (a); } @@ -167,7 +167,7 @@ extern "C" mk_c(c)->save_ast_trail (result.get ()); return of_expr (result); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } } diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index e56505e6d..6e0162024 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -37,10 +37,10 @@ extern "C" { c, is_forall, weight, - 0, - 0, + nullptr, + nullptr, num_patterns, patterns, - 0, 0, + 0, nullptr, num_decls, sorts, decl_names, body @@ -104,7 +104,7 @@ extern "C" { } mk_c(c)->save_ast_trail(result.get()); return of_ast(result.get()); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_quantifier_ex( @@ -166,17 +166,17 @@ extern "C" { ptr_vector bound_asts; if (num_patterns > 0 && num_no_patterns > 0) { SET_ERROR_CODE(Z3_INVALID_USAGE); - RETURN_Z3(0); + RETURN_Z3(nullptr); } if (num_bound == 0) { SET_ERROR_CODE(Z3_INVALID_USAGE); - RETURN_Z3(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); - RETURN_Z3(0); + RETURN_Z3(nullptr); } symbol s(to_app(a)->get_decl()->get_name()); names.push_back(of_symbol(s)); @@ -184,7 +184,7 @@ extern "C" { bound_asts.push_back(a); if (a->get_family_id() != null_family_id || a->get_num_args() != 0) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } } // Abstract patterns @@ -205,7 +205,7 @@ extern "C" { expr_ref result(mk_c(c)->m()); if (!is_app(to_expr(no_patterns[i]))) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } app* pat = to_app(to_expr(no_patterns[i])); expr_abstract(mk_c(c)->m(), 0, num_bound, bound_asts.c_ptr(), pat, result); @@ -224,7 +224,7 @@ extern "C" { names.size(), types.c_ptr(), names.c_ptr(), of_ast(abs_body.get())); RETURN_Z3(result); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_quantifier_const(Z3_context c, @@ -235,10 +235,10 @@ extern "C" { unsigned num_patterns, Z3_pattern const patterns[], Z3_ast body) { - return Z3_mk_quantifier_const_ex(c, is_forall, weight, 0, 0, + return Z3_mk_quantifier_const_ex(c, is_forall, weight, nullptr, nullptr, num_bound, bound, num_patterns, patterns, - 0, 0, + 0, nullptr, body); } @@ -269,13 +269,13 @@ extern "C" { for (unsigned i = 0; i < num_patterns; ++i) { if (!is_app(to_expr(terms[i]))) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } } app* a = mk_c(c)->m().mk_pattern(num_patterns, reinterpret_cast(to_exprs(terms))); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_pattern(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_bound(Z3_context c, unsigned index, Z3_sort ty) { @@ -285,7 +285,7 @@ extern "C" { ast* a = mk_c(c)->m().mk_var(index, to_sort(ty)); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_is_quantifier_forall(Z3_context c, Z3_ast a) { @@ -344,9 +344,9 @@ extern "C" { } else { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } @@ -376,9 +376,9 @@ extern "C" { } else { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_symbol Z3_API Z3_get_quantifier_bound_name(Z3_context c, Z3_ast a, unsigned i) { @@ -391,9 +391,9 @@ extern "C" { } else { SET_ERROR_CODE(Z3_SORT_ERROR); - return 0; + return nullptr; } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_get_quantifier_bound_sort(Z3_context c, Z3_ast a, unsigned i) { @@ -407,9 +407,9 @@ extern "C" { } else { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_get_quantifier_body(Z3_context c, Z3_ast a) { @@ -423,9 +423,9 @@ extern "C" { } else { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_get_quantifier_num_bound(Z3_context c, Z3_ast a) { @@ -470,9 +470,9 @@ extern "C" { } else { SET_ERROR_CODE(Z3_SORT_ERROR); - RETURN_Z3(0); + RETURN_Z3(nullptr); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_pattern_to_ast(Z3_context c, Z3_pattern p) { diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index 84c250114..3d65cb1cd 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -62,7 +62,7 @@ extern "C" { rcnumeral r; rcfm(c).set(r, q); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_mk_small_int(Z3_context c, int val) { @@ -73,7 +73,7 @@ extern "C" { rcnumeral r; rcfm(c).set(r, val); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_mk_pi(Z3_context c) { @@ -84,7 +84,7 @@ extern "C" { rcnumeral r; rcfm(c).mk_pi(r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_mk_e(Z3_context c) { @@ -95,7 +95,7 @@ extern "C" { rcnumeral r; rcfm(c).mk_e(r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_mk_infinitesimal(Z3_context c) { @@ -106,7 +106,7 @@ extern "C" { rcnumeral r; rcfm(c).mk_infinitesimal(r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_rcf_mk_roots(Z3_context c, unsigned n, Z3_rcf_num const a[], Z3_rcf_num roots[]) { @@ -145,7 +145,7 @@ extern "C" { rcnumeral r; rcfm(c).add(to_rcnumeral(a), to_rcnumeral(b), r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_sub(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { @@ -156,7 +156,7 @@ extern "C" { rcnumeral r; rcfm(c).sub(to_rcnumeral(a), to_rcnumeral(b), r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_mul(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { @@ -167,7 +167,7 @@ extern "C" { rcnumeral r; rcfm(c).mul(to_rcnumeral(a), to_rcnumeral(b), r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_div(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { @@ -178,7 +178,7 @@ extern "C" { rcnumeral r; rcfm(c).div(to_rcnumeral(a), to_rcnumeral(b), r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_neg(Z3_context c, Z3_rcf_num a) { @@ -189,7 +189,7 @@ extern "C" { rcnumeral r; rcfm(c).neg(to_rcnumeral(a), r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_inv(Z3_context c, Z3_rcf_num a) { @@ -200,7 +200,7 @@ extern "C" { rcnumeral r; rcfm(c).inv(to_rcnumeral(a), r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_rcf_num Z3_API Z3_rcf_power(Z3_context c, Z3_rcf_num a, unsigned k) { @@ -211,7 +211,7 @@ extern "C" { rcnumeral r; rcfm(c).power(to_rcnumeral(a), k, r); RETURN_Z3(from_rcnumeral(r)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_rcf_lt(Z3_context c, Z3_rcf_num a, Z3_rcf_num b) { diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 428d86d0d..84cfdca32 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -31,7 +31,7 @@ extern "C" { sort * ty = mk_c(c)->sutil().str.mk_seq(to_sort(domain)); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_re_sort(Z3_context c, Z3_sort domain) { @@ -41,7 +41,7 @@ extern "C" { sort * ty = mk_c(c)->sutil().re.mk_re(to_sort(domain)); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_mk_string(Z3_context c, Z3_string str) { @@ -52,7 +52,7 @@ extern "C" { app* a = mk_c(c)->sutil().str.mk_string(s); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_sort Z3_API Z3_mk_string_sort(Z3_context c) { @@ -62,7 +62,7 @@ extern "C" { sort* ty = mk_c(c)->sutil().str.mk_string_sort(); mk_c(c)->save_ast_trail(ty); RETURN_Z3(of_sort(ty)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s) { @@ -152,7 +152,7 @@ extern "C" { app* a = hi == 0 ? mk_c(c)->sutil().re.mk_loop(to_expr(r), lo) : mk_c(c)->sutil().re.mk_loop(to_expr(r), lo, hi); mk_c(c)->save_ast_trail(a); RETURN_Z3(of_ast(a)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 0a0039f4c..aab783afa 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -57,7 +57,7 @@ extern "C" { } static void init_solver(Z3_context c, Z3_solver s) { - if (to_solver(s)->m_solver.get() == 0) + if (to_solver(s)->m_solver.get() == nullptr) init_solver_core(c, s); } @@ -69,7 +69,7 @@ extern "C" { mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_solver Z3_API Z3_mk_solver(Z3_context c) { @@ -80,7 +80,7 @@ extern "C" { mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_solver Z3_API Z3_mk_solver_for_logic(Z3_context c, Z3_symbol logic) { @@ -91,7 +91,7 @@ extern "C" { std::ostringstream strm; strm << "logic '" << to_symbol(logic) << "' is not recognized"; throw default_exception(strm.str()); - RETURN_Z3(0); + RETURN_Z3(nullptr); } else { Z3_solver_ref * s = alloc(Z3_solver_ref, *mk_c(c), mk_smt_strategic_solver_factory(to_symbol(logic))); @@ -99,7 +99,7 @@ extern "C" { Z3_solver r = of_solver(s); RETURN_Z3(r); } - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_solver Z3_API Z3_mk_solver_from_tactic(Z3_context c, Z3_tactic t) { @@ -110,7 +110,7 @@ extern "C" { mk_c(c)->save_object(s); Z3_solver r = of_solver(s); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_solver Z3_API Z3_solver_translate(Z3_context c, Z3_solver s, Z3_context target) { @@ -118,13 +118,13 @@ extern "C" { LOG_Z3_solver_translate(c, s, target); RESET_ERROR_CODE(); params_ref const& p = to_solver(s)->m_params; - Z3_solver_ref * sr = alloc(Z3_solver_ref, *mk_c(target), 0); + Z3_solver_ref * sr = alloc(Z3_solver_ref, *mk_c(target), nullptr); init_solver(c, s); sr->m_solver = to_solver(s)->m_solver->translate(mk_c(target)->m(), p); mk_c(target)->save_object(sr); Z3_solver r = of_solver(sr); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void solver_from_stream(Z3_context c, Z3_solver s, std::istream& is) { @@ -137,7 +137,7 @@ extern "C" { return; } - bool initialized = to_solver(s)->m_solver.get() != 0; + bool initialized = to_solver(s)->m_solver.get() != nullptr; if (!initialized) init_solver(c, s); ptr_vector::const_iterator it = ctx->begin_assertions(); @@ -190,13 +190,13 @@ extern "C" { RESET_ERROR_CODE(); std::ostringstream buffer; param_descrs descrs; - bool initialized = to_solver(s)->m_solver.get() != 0; + bool initialized = to_solver(s)->m_solver.get() != nullptr; if (!initialized) init_solver(c, s); to_solver_ref(s)->collect_param_descrs(descrs); context_params::collect_solver_param_descrs(descrs); if (!initialized) - to_solver(s)->m_solver = 0; + to_solver(s)->m_solver = nullptr; descrs.display(buffer); return mk_c(c)->mk_external_string(buffer.str()); Z3_CATCH_RETURN(""); @@ -208,16 +208,16 @@ extern "C" { RESET_ERROR_CODE(); Z3_param_descrs_ref * d = alloc(Z3_param_descrs_ref, *mk_c(c)); mk_c(c)->save_object(d); - bool initialized = to_solver(s)->m_solver.get() != 0; + bool initialized = to_solver(s)->m_solver.get() != nullptr; if (!initialized) init_solver(c, s); to_solver_ref(s)->collect_param_descrs(d->m_descrs); context_params::collect_solver_param_descrs(d->m_descrs); if (!initialized) - to_solver(s)->m_solver = 0; + to_solver(s)->m_solver = nullptr; Z3_param_descrs r = of_param_descrs(d); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_solver_set_params(Z3_context c, Z3_solver s, Z3_params p) { @@ -288,7 +288,7 @@ extern "C" { Z3_TRY; LOG_Z3_solver_reset(c, s); RESET_ERROR_CODE(); - to_solver(s)->m_solver = 0; + to_solver(s)->m_solver = nullptr; Z3_CATCH; } @@ -334,7 +334,7 @@ extern "C" { v->m_ast_vector.push_back(to_solver_ref(s)->get_assertion(i)); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } static Z3_lbool _solver_check(Z3_context c, Z3_solver s, unsigned num_assumptions, Z3_ast const assumptions[]) { @@ -375,7 +375,7 @@ extern "C" { LOG_Z3_solver_check(c, s); RESET_ERROR_CODE(); init_solver(c, s); - return _solver_check(c, s, 0, 0); + return _solver_check(c, s, 0, nullptr); Z3_CATCH_RETURN(Z3_L_UNDEF); } @@ -397,13 +397,13 @@ extern "C" { to_solver_ref(s)->get_model(_m); if (!_m) { SET_ERROR_CODE(Z3_INVALID_USAGE); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); m_ref->m_model = _m; mk_c(c)->save_object(m_ref); RETURN_Z3(of_model(m_ref)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast Z3_API Z3_solver_get_proof(Z3_context c, Z3_solver s) { @@ -414,11 +414,11 @@ extern "C" { proof * p = to_solver_ref(s)->get_proof(); if (!p) { SET_ERROR_CODE(Z3_INVALID_USAGE); - RETURN_Z3(0); + RETURN_Z3(nullptr); } mk_c(c)->save_ast_trail(p); RETURN_Z3(of_ast(p)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_ast_vector Z3_API Z3_solver_get_unsat_core(Z3_context c, Z3_solver s) { @@ -434,7 +434,7 @@ extern "C" { v->m_ast_vector.push_back(core[i]); } RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_solver_get_reason_unknown(Z3_context c, Z3_solver s) { @@ -458,7 +458,7 @@ extern "C" { mk_c(c)->save_object(st); Z3_stats r = of_stats(st); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_solver_to_string(Z3_context c, Z3_solver s) { diff --git a/src/api/api_solver.h b/src/api/api_solver.h index 3da702f1e..90d1c2c65 100644 --- a/src/api/api_solver.h +++ b/src/api/api_solver.h @@ -26,7 +26,7 @@ struct Z3_solver_ref : public api::object { ref m_solver; params_ref m_params; symbol m_logic; - Z3_solver_ref(api::context& c, solver_factory * f): api::object(c), m_solver_factory(f), m_solver(0), m_logic(symbol::null) {} + Z3_solver_ref(api::context& c, solver_factory * f): api::object(c), m_solver_factory(f), m_solver(nullptr), m_logic(symbol::null) {} ~Z3_solver_ref() override {} }; diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index ccb1ce597..fb2c10b68 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -51,13 +51,13 @@ extern "C" { LOG_Z3_mk_tactic(c, name); RESET_ERROR_CODE(); tactic_cmd * t = mk_c(c)->find_tactic_cmd(symbol(name)); - if (t == 0) { + if (t == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } tactic * new_t = t->mk(mk_c(c)->m()); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_tactic_inc_ref(Z3_context c, Z3_tactic t) { @@ -81,13 +81,13 @@ extern "C" { LOG_Z3_mk_probe(c, name); RESET_ERROR_CODE(); probe_info * p = mk_c(c)->find_probe(symbol(name)); - if (p == 0) { + if (p == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); + RETURN_Z3(nullptr); } probe * new_p = p->get(); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_probe_inc_ref(Z3_context c, Z3_probe p) { @@ -112,7 +112,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = and_then(to_tactic_ref(t1), to_tactic_ref(t2)); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_or_else(Z3_context c, Z3_tactic t1, Z3_tactic t2) { @@ -121,7 +121,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = or_else(to_tactic_ref(t1), to_tactic_ref(t2)); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_par_or(Z3_context c, unsigned num, Z3_tactic const ts[]) { @@ -134,7 +134,7 @@ extern "C" { } tactic * new_t = par(num, _ts.c_ptr()); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_par_and_then(Z3_context c, Z3_tactic t1, Z3_tactic t2) { @@ -143,7 +143,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = par_and_then(to_tactic_ref(t1), to_tactic_ref(t2)); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_try_for(Z3_context c, Z3_tactic t, unsigned ms) { @@ -152,7 +152,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = try_for(to_tactic_ref(t), ms); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_when(Z3_context c, Z3_probe p, Z3_tactic t) { @@ -161,7 +161,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = when(to_probe_ref(p), to_tactic_ref(t)); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_cond(Z3_context c, Z3_probe p, Z3_tactic t1, Z3_tactic t2) { @@ -170,7 +170,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = cond(to_probe_ref(p), to_tactic_ref(t1), to_tactic_ref(t2)); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_repeat(Z3_context c, Z3_tactic t, unsigned max) { @@ -179,7 +179,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = repeat(to_tactic_ref(t), max); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_skip(Z3_context c) { @@ -188,7 +188,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = mk_skip_tactic(); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_fail(Z3_context c) { @@ -197,7 +197,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = mk_fail_tactic(); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_fail_if(Z3_context c, Z3_probe p) { @@ -206,7 +206,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = fail_if(to_probe_ref(p)); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_fail_if_not_decided(Z3_context c) { @@ -215,7 +215,7 @@ extern "C" { RESET_ERROR_CODE(); tactic * new_t = mk_fail_if_undecided_tactic(); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_tactic Z3_API Z3_tactic_using_params(Z3_context c, Z3_tactic t, Z3_params p) { @@ -227,7 +227,7 @@ extern "C" { to_param_ref(p).validate(r); tactic * new_t = using_params(to_tactic_ref(t), to_param_ref(p)); RETURN_TACTIC(new_t); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_const(Z3_context c, double val) { @@ -236,7 +236,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_const_probe(val); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_lt(Z3_context c, Z3_probe p1, Z3_probe p2) { @@ -245,7 +245,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_lt(to_probe_ref(p1), to_probe_ref(p2)); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_gt(Z3_context c, Z3_probe p1, Z3_probe p2) { @@ -254,7 +254,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_gt(to_probe_ref(p1), to_probe_ref(p2)); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_le(Z3_context c, Z3_probe p1, Z3_probe p2) { @@ -263,7 +263,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_le(to_probe_ref(p1), to_probe_ref(p2)); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_ge(Z3_context c, Z3_probe p1, Z3_probe p2) { @@ -272,7 +272,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_ge(to_probe_ref(p1), to_probe_ref(p2)); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_eq(Z3_context c, Z3_probe p1, Z3_probe p2) { @@ -281,7 +281,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_eq(to_probe_ref(p1), to_probe_ref(p2)); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_and(Z3_context c, Z3_probe p1, Z3_probe p2) { @@ -290,7 +290,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_and(to_probe_ref(p1), to_probe_ref(p2)); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_or(Z3_context c, Z3_probe p1, Z3_probe p2) { @@ -299,7 +299,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_or(to_probe_ref(p1), to_probe_ref(p2)); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_probe Z3_API Z3_probe_not(Z3_context c, Z3_probe p) { @@ -308,7 +308,7 @@ extern "C" { RESET_ERROR_CODE(); probe * new_p = mk_not(to_probe_ref(p)); RETURN_PROBE(new_p); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } unsigned Z3_API Z3_get_num_tactics(Z3_context c) { @@ -372,7 +372,7 @@ extern "C" { to_tactic_ref(t)->collect_param_descrs(d->m_descrs); Z3_param_descrs r = of_param_descrs(d); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_string Z3_API Z3_tactic_get_descr(Z3_context c, Z3_string name) { @@ -380,7 +380,7 @@ extern "C" { LOG_Z3_tactic_get_descr(c, name); RESET_ERROR_CODE(); tactic_cmd * t = mk_c(c)->find_tactic_cmd(symbol(name)); - if (t == 0) { + if (t == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } @@ -393,7 +393,7 @@ extern "C" { LOG_Z3_probe_get_descr(c, name); RESET_ERROR_CODE(); probe_info * p = mk_c(c)->find_probe(symbol(name)); - if (p == 0) { + if (p == nullptr) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } @@ -423,7 +423,7 @@ extern "C" { } catch (z3_exception & ex) { mk_c(c)->handle_exception(ex); - return 0; + return nullptr; } } } @@ -443,7 +443,7 @@ extern "C" { params_ref p; Z3_apply_result r = _tactic_apply(c, t, g, p); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_apply_result Z3_API Z3_tactic_apply_ex(Z3_context c, Z3_tactic t, Z3_goal g, Z3_params p) { @@ -455,7 +455,7 @@ extern "C" { to_param_ref(p).validate(pd); Z3_apply_result r = _tactic_apply(c, t, g, to_param_ref(p)); RETURN_Z3(r); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } void Z3_API Z3_apply_result_inc_ref(Z3_context c, Z3_apply_result r) { @@ -503,14 +503,14 @@ extern "C" { RESET_ERROR_CODE(); if (i > to_apply_result(r)->m_subgoals.size()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } Z3_goal_ref * g = alloc(Z3_goal_ref, *mk_c(c)); g->m_goal = to_apply_result(r)->m_subgoals[i]; mk_c(c)->save_object(g); Z3_goal result = of_goal(g); RETURN_Z3(result); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } Z3_model Z3_API Z3_apply_result_convert_model(Z3_context c, Z3_apply_result r, unsigned i, Z3_model m) { @@ -519,7 +519,7 @@ extern "C" { RESET_ERROR_CODE(); if (i > to_apply_result(r)->m_subgoals.size()) { SET_ERROR_CODE(Z3_IOB); - RETURN_Z3(0); + RETURN_Z3(nullptr); } model_ref new_m = to_model_ref(m)->copy(); if (to_apply_result(r)->m_mc) @@ -528,7 +528,7 @@ extern "C" { m_ref->m_model = new_m; mk_c(c)->save_object(m_ref); RETURN_Z3(of_model(m_ref)); - Z3_CATCH_RETURN(0); + Z3_CATCH_RETURN(nullptr); } }; diff --git a/src/api/api_tactic.h b/src/api/api_tactic.h index cc5e55a4e..d33f3afe2 100644 --- a/src/api/api_tactic.h +++ b/src/api/api_tactic.h @@ -40,11 +40,11 @@ struct Z3_probe_ref : public api::object { inline Z3_tactic_ref * to_tactic(Z3_tactic g) { return reinterpret_cast(g); } inline Z3_tactic of_tactic(Z3_tactic_ref * g) { return reinterpret_cast(g); } -inline tactic * to_tactic_ref(Z3_tactic g) { return g == 0 ? 0 : to_tactic(g)->m_tactic.get(); } +inline tactic * to_tactic_ref(Z3_tactic g) { return g == nullptr ? nullptr : to_tactic(g)->m_tactic.get(); } inline Z3_probe_ref * to_probe(Z3_probe g) { return reinterpret_cast(g); } inline Z3_probe of_probe(Z3_probe_ref * g) { return reinterpret_cast(g); } -inline probe * to_probe_ref(Z3_probe g) { return g == 0 ? 0 : to_probe(g)->m_probe.get(); } +inline probe * to_probe_ref(Z3_probe g) { return g == nullptr ? nullptr : to_probe(g)->m_probe.get(); } struct Z3_apply_result_ref : public api::object { goal_ref_buffer m_subgoals; diff --git a/src/api/api_util.h b/src/api/api_util.h index e2e4621d4..848d935c5 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -93,7 +93,7 @@ struct Z3_params_ref : public api::object { inline Z3_params_ref * to_params(Z3_params p) { return reinterpret_cast(p); } inline Z3_params of_params(Z3_params_ref * p) { return reinterpret_cast(p); } -inline params_ref to_param_ref(Z3_params p) { return p == 0 ? params_ref() : to_params(p)->m_params; } +inline params_ref to_param_ref(Z3_params p) { return p == nullptr ? params_ref() : to_params(p)->m_params; } struct Z3_param_descrs_ref : public api::object { param_descrs m_descrs; @@ -103,7 +103,7 @@ struct Z3_param_descrs_ref : public api::object { inline Z3_param_descrs_ref * to_param_descrs(Z3_param_descrs p) { return reinterpret_cast(p); } inline Z3_param_descrs of_param_descrs(Z3_param_descrs_ref * p) { return reinterpret_cast(p); } -inline param_descrs * to_param_descrs_ptr(Z3_param_descrs p) { return p == 0 ? 0 : &(to_param_descrs(p)->m_descrs); } +inline param_descrs * to_param_descrs_ptr(Z3_param_descrs p) { return p == nullptr ? nullptr : &(to_param_descrs(p)->m_descrs); } #define SKIP ((void) 0) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 84dcfc363..1515e6df7 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -430,10 +430,10 @@ struct z3_replayer::imp { next(); skip_blank(); read_ptr(); TRACE("z3_replayer", tout << "[" << m_line << "] " << "P " << m_ptr << "\n";); if (m_ptr == 0) { - m_args.push_back(0); + m_args.push_back(nullptr); } else { - void * obj = 0; + void * obj = nullptr; if (!m_heap.find(m_ptr, obj)) throw z3_replayer_exception("invalid pointer"); m_args.push_back(value(obj)); @@ -453,7 +453,7 @@ struct z3_replayer::imp { // push null symbol next(); TRACE("z3_replayer", tout << "[" << m_line << "] " << "N\n";); - m_args.push_back(value(SYMBOL, static_cast(0))); + m_args.push_back(value(SYMBOL, static_cast(nullptr))); break; case '$': { // push symbol @@ -689,7 +689,7 @@ struct z3_replayer::imp { } void reset() { - m_result = 0; + m_result = nullptr; m_args.reset(); m_obj_arrays.reset(); m_sym_arrays.reset(); diff --git a/src/ast/act_cache.cpp b/src/ast/act_cache.cpp index 74a7d6fca..14f0985b4 100644 --- a/src/ast/act_cache.cpp +++ b/src/ast/act_cache.cpp @@ -187,8 +187,8 @@ void act_cache::insert(expr * k, expr * v) { */ expr * act_cache::find(expr * k) { map::key_value * entry = m_table.find_core(k); - if (entry == 0) - return 0; + if (entry == nullptr) + return nullptr; if (GET_TAG(entry->m_value) == 0) { entry->m_value = TAG(expr*, entry->m_value, 1); SASSERT(GET_TAG(entry->m_value) == 1); diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index 85c54d1fa..688edbcd5 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -65,7 +65,7 @@ struct arith_decl_plugin::algebraic_numbers_wrapper { }; arith_decl_plugin::algebraic_numbers_wrapper & arith_decl_plugin::aw() const { - if (m_aw == 0) + if (m_aw == nullptr) const_cast(this)->m_aw = alloc(algebraic_numbers_wrapper, m_manager->limit()); return *m_aw; } @@ -100,7 +100,7 @@ app * arith_decl_plugin::mk_numeral(sexpr const * p, unsigned i) { void arith_decl_plugin::del(parameter const & p) { SASSERT(p.is_external()); - if (m_aw != 0) { + if (m_aw != nullptr) { aw().recycle_id(p.get_ext_id()); } } @@ -222,56 +222,56 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) { } arith_decl_plugin::arith_decl_plugin(): - m_aw(0), + m_aw(nullptr), m_intv_sym("Int"), m_realv_sym("Real"), m_rootv_sym("RootObject"), - m_real_decl(0), - m_int_decl(0), - m_r_le_decl(0), - m_r_ge_decl(0), - m_r_lt_decl(0), - m_r_gt_decl(0), - m_r_add_decl(0), - m_r_sub_decl(0), - m_r_uminus_decl(0), - m_r_mul_decl(0), - m_r_div_decl(0), - m_i_le_decl(0), - m_i_ge_decl(0), - m_i_lt_decl(0), - m_i_gt_decl(0), - m_i_add_decl(0), - m_i_sub_decl(0), - m_i_uminus_decl(0), - m_i_mul_decl(0), - m_i_div_decl(0), - m_i_mod_decl(0), - m_i_rem_decl(0), - m_to_real_decl(0), - m_to_int_decl(0), - m_is_int_decl(0), - m_r_power_decl(0), - m_i_power_decl(0), - m_r_abs_decl(0), - m_i_abs_decl(0), - m_sin_decl(0), - m_cos_decl(0), - m_tan_decl(0), - m_asin_decl(0), - m_acos_decl(0), - m_atan_decl(0), - m_sinh_decl(0), - m_cosh_decl(0), - m_tanh_decl(0), - m_asinh_decl(0), - m_acosh_decl(0), - m_atanh_decl(0), - m_pi(0), - m_e(0), - m_neg_root_decl(0), - m_u_asin_decl(0), - m_u_acos_decl(0), + m_real_decl(nullptr), + m_int_decl(nullptr), + m_r_le_decl(nullptr), + m_r_ge_decl(nullptr), + m_r_lt_decl(nullptr), + m_r_gt_decl(nullptr), + m_r_add_decl(nullptr), + m_r_sub_decl(nullptr), + m_r_uminus_decl(nullptr), + m_r_mul_decl(nullptr), + m_r_div_decl(nullptr), + m_i_le_decl(nullptr), + m_i_ge_decl(nullptr), + m_i_lt_decl(nullptr), + m_i_gt_decl(nullptr), + m_i_add_decl(nullptr), + m_i_sub_decl(nullptr), + m_i_uminus_decl(nullptr), + m_i_mul_decl(nullptr), + m_i_div_decl(nullptr), + m_i_mod_decl(nullptr), + m_i_rem_decl(nullptr), + m_to_real_decl(nullptr), + m_to_int_decl(nullptr), + m_is_int_decl(nullptr), + m_r_power_decl(nullptr), + m_i_power_decl(nullptr), + m_r_abs_decl(nullptr), + m_i_abs_decl(nullptr), + m_sin_decl(nullptr), + m_cos_decl(nullptr), + m_tan_decl(nullptr), + m_asin_decl(nullptr), + m_acos_decl(nullptr), + m_atan_decl(nullptr), + m_sinh_decl(nullptr), + m_cosh_decl(nullptr), + m_tanh_decl(nullptr), + m_asinh_decl(nullptr), + m_acosh_decl(nullptr), + m_atanh_decl(nullptr), + m_pi(nullptr), + m_e(nullptr), + m_neg_root_decl(nullptr), + m_u_asin_decl(nullptr), + m_u_acos_decl(nullptr), m_convert_int_numerals_to_real(false) { } @@ -335,7 +335,7 @@ sort * arith_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete switch (k) { case REAL_SORT: return m_real_decl; case INT_SORT: return m_int_decl; - default: return 0; + default: return nullptr; } } @@ -380,7 +380,7 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) { //case OP_MOD_0: return m_mod_0_decl; case OP_U_ASIN: return m_u_asin_decl; case OP_U_ACOS: return m_u_acos_decl; - default: return 0; + default: return nullptr; } } @@ -408,7 +408,7 @@ app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) { if (u_val < MAX_SMALL_NUM_TO_CACHE) { if (is_int && !m_convert_int_numerals_to_real) { app * r = m_small_ints.get(u_val, 0); - if (r == 0) { + if (r == nullptr) { parameter p[2] = { parameter(val), parameter(1) }; r = m_manager->mk_const(m_manager->mk_const_decl(m_intv_sym, m_int_decl, func_decl_info(m_family_id, OP_NUM, 2, p))); m_manager->inc_ref(r); @@ -418,7 +418,7 @@ app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) { } else { app * r = m_small_reals.get(u_val, 0); - if (r == 0) { + if (r == nullptr) { parameter p[2] = { parameter(val), parameter(0) }; r = m_manager->mk_const(m_manager->mk_const_decl(m_realv_sym, m_real_decl, func_decl_info(m_family_id, OP_NUM, 2, p))); m_manager->inc_ref(r); @@ -440,7 +440,7 @@ app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) { func_decl * arith_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity) { if (!(num_parameters == 2 && arity == 0 && parameters[0].is_rational() && parameters[1].is_int())) { m_manager->raise_exception("invalid numeral declaration"); - return 0; + return nullptr; } if (parameters[1].get_int() != 0) return m_manager->mk_const_decl(m_intv_sym, m_int_decl, func_decl_info(m_family_id, OP_NUM, num_parameters, parameters)); @@ -480,7 +480,7 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters return mk_num_decl(num_parameters, parameters, arity); if (arity == 0 && !is_const_op(k)) { m_manager->raise_exception("no arguments supplied to arithmetical operator"); - return 0; + return nullptr; } 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)); @@ -497,7 +497,7 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters return mk_num_decl(num_parameters, parameters, num_args); if (num_args == 0 && !is_const_op(k)) { m_manager->raise_exception("no arguments supplied to arithmetical operator"); - return 0; + return nullptr; } 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)); @@ -641,7 +641,7 @@ bool arith_recognizers::is_numeral(expr const * n, rational & val, bool & is_int arith_util::arith_util(ast_manager & m): arith_recognizers(m.mk_family_id("arith")), m_manager(m), - m_plugin(0) { + m_plugin(nullptr) { } void arith_util::init_plugin() { diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 1e789b7e5..af451f9c5 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -44,7 +44,7 @@ sort * array_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete if (k == _SET_SORT) { if (num_parameters != 1) { m_manager->raise_exception("invalid array sort definition, invalid number of parameters"); - return 0; + return nullptr; } parameter params[2] = { parameters[0], parameter(m_manager->mk_bool_sort()) }; return mk_sort(ARRAY_SORT, 2, params); @@ -52,13 +52,13 @@ sort * array_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete SASSERT(k == ARRAY_SORT); if (num_parameters < 2) { m_manager->raise_exception("invalid array sort definition, invalid number of parameters"); - return 0; + return nullptr; } for (unsigned i = 0; i < num_parameters; i++) { if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) { m_manager->raise_exception("invalid array sort definition, parameter is not a sort"); - return 0; + return nullptr; } } sort * range = to_sort(parameters[num_parameters - 1].get_ast()); @@ -120,15 +120,15 @@ bool array_decl_plugin::is_array_sort(sort* s) const { func_decl * array_decl_plugin::mk_const(sort * s, unsigned arity, sort * const * domain) { if (arity != 1) { m_manager->raise_exception("invalid const array definition, invalid domain size"); - return 0; + return nullptr; } if (!is_array_sort(s)) { m_manager->raise_exception("invalid const array definition, parameter is not an array sort"); - return 0; + return nullptr; } if (!m_manager->compatible_sorts(get_array_range(s), domain[0])) { m_manager->raise_exception("invalid const array definition, sort mismatch between array range and argument"); - return 0; + return nullptr; } parameter param(s); func_decl_info info(m_family_id, OP_CONST_ARRAY, 1, ¶m); @@ -142,11 +142,11 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* buffer << "map expects to take as many arguments as the function being mapped, " << "it was given " << arity << " but expects " << f->get_arity(); m_manager->raise_exception(buffer.str().c_str()); - return 0; + return nullptr; } if (arity == 0) { m_manager->raise_exception("don't use map on constants"); - return 0; + return nullptr; } // // check that each domain[i] is an array sort @@ -159,14 +159,14 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* std::ostringstream buffer; buffer << "map expects an array sort as argument at position " << i; m_manager->raise_exception(buffer.str().c_str()); - return 0; + return nullptr; } if (get_array_arity(domain[i]) != dom_arity) { std::ostringstream buffer; buffer << "map expects all arguments to have the same array domain, " << "this is not the case for argument " << i; m_manager->raise_exception(buffer.str().c_str()); - return 0; + return nullptr; } for (unsigned j = 0; j < dom_arity; ++j) { if (get_array_domain(domain[i],j) != get_array_domain(domain[0],j)) { @@ -174,7 +174,7 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* buffer << "map expects all arguments to have the same array domain, " << "this is not the case for argument " << i; m_manager->raise_exception(buffer.str().c_str()); - return 0; + return nullptr; } } if (get_array_range(domain[i]) != f->get_domain(i)) { @@ -182,7 +182,7 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* buffer << "map expects the argument at position " << i << " to have the array range the same as the function"; m_manager->raise_exception(buffer.str().c_str()); - return 0; + return nullptr; } } vector parameters; @@ -211,19 +211,19 @@ func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* func_decl * array_decl_plugin::mk_default(unsigned domain_size, sort * const * domain) { if (domain_size != 1) { m_manager->raise_exception("invalid default array definition, invalid domain size"); - return 0; + return nullptr; } // check that domain[0] is an array sort. unsigned num_parameters = domain[0]->get_num_parameters(); if (num_parameters <= 1) { m_manager->raise_exception("parameter mismatch. There should be more than one parameter to defaults"); - return 0; + return nullptr; } parameter param(domain[0]->get_parameter(num_parameters-1)); if (!param.is_ast() || !is_sort(param.get_ast())) { m_manager->raise_exception("last parameter should be a sort"); - return 0; + return nullptr; } sort * s = to_sort(param.get_ast()); @@ -235,7 +235,7 @@ func_decl * array_decl_plugin::mk_default(unsigned domain_size, sort * const * d func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { if (arity <= 1) { m_manager->raise_exception("select takes at least two arguments"); - return 0; + return nullptr; } sort * s = domain[0]; unsigned num_parameters = s->get_num_parameters(); @@ -245,7 +245,7 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { std::stringstream strm; strm << "select requires " << num_parameters << " arguments, but was provided with " << arity << " arguments"; m_manager->raise_exception(strm.str().c_str()); - return 0; + return nullptr; } ptr_buffer new_domain; // we need this because of coercions. new_domain.push_back(s); @@ -255,7 +255,7 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { !m_manager->compatible_sorts(domain[i+1], to_sort(parameters[i].get_ast()))) { m_manager->raise_exception("domain sort and parameter do not match"); UNREACHABLE(); - return 0; + return nullptr; } new_domain.push_back(to_sort(parameters[i].get_ast())); } @@ -267,7 +267,7 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { if (arity < 3) { m_manager->raise_exception("store takes at least 3 arguments"); - return 0; + return nullptr; } sort * s = domain[0]; unsigned num_parameters = s->get_num_parameters(); @@ -275,7 +275,7 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { if (!is_array_sort(s)) { m_manager->raise_exception("store expects the first argument sort to be an array"); UNREACHABLE(); - return 0; + return nullptr; } if (arity != num_parameters+1) { std::ostringstream buffer; @@ -283,19 +283,19 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { << ", instead it was passed " << (arity - 1) << "arguments"; m_manager->raise_exception(buffer.str().c_str()); UNREACHABLE(); - return 0; + return nullptr; } ptr_buffer new_domain; // we need this because of coercions. new_domain.push_back(s); for (unsigned i = 0; i < num_parameters; ++i) { if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) { m_manager->raise_exception("expecting sort parameter"); - return 0; + return nullptr; } if (!m_manager->compatible_sorts(to_sort(parameters[i].get_ast()), domain[i+1])) { m_manager->raise_exception("domain sort and parameter do not match"); UNREACHABLE(); - return 0; + return nullptr; } new_domain.push_back(to_sort(parameters[i].get_ast())); } @@ -307,13 +307,13 @@ func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) { func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domain, unsigned i) { if (arity != 2 || domain[0] != domain[1]) { UNREACHABLE(); - return 0; + return nullptr; } sort * s = domain[0]; unsigned num_parameters = s->get_num_parameters(); if (num_parameters == 0 || i >= num_parameters - 1) { UNREACHABLE(); - return 0; + return nullptr; } sort * r = to_sort(s->get_parameter(i).get_ast()); parameter param(i); @@ -362,11 +362,11 @@ func_decl * array_decl_plugin::mk_set_union(unsigned arity, sort * const * domai if (arity == 0) { m_manager->raise_exception("union takes at least one argument"); - return 0; + return nullptr; } sort * s = domain[0]; if (!check_set_arguments(arity, domain)) { - return 0; + return nullptr; } parameter param(s); func_decl_info info(m_family_id, OP_SET_UNION, 1, ¶m); @@ -381,10 +381,10 @@ func_decl * array_decl_plugin::mk_set_intersect(unsigned arity, sort * const * d if (arity == 0) { m_manager->raise_exception("intersection takes at least one argument"); - return 0; + return nullptr; } if (!check_set_arguments(arity, domain)) { - return 0; + return nullptr; } func_decl_info info(m_family_id, OP_SET_INTERSECT); info.set_associative(); @@ -397,10 +397,10 @@ func_decl * array_decl_plugin::mk_set_intersect(unsigned arity, sort * const * d func_decl * array_decl_plugin::mk_set_difference(unsigned arity, sort * const * domain) { if (arity != 2) { m_manager->raise_exception("set difference takes precisely two arguments"); - return 0; + return nullptr; } if (!check_set_arguments(arity, domain)) { - return 0; + return nullptr; } return m_manager->mk_func_decl(m_set_difference_sym, arity, domain, domain[0], func_decl_info(m_family_id, OP_SET_DIFFERENCE)); @@ -409,10 +409,10 @@ func_decl * array_decl_plugin::mk_set_difference(unsigned arity, sort * const * func_decl * array_decl_plugin::mk_set_complement(unsigned arity, sort * const * domain) { if (arity != 1) { m_manager->raise_exception("set complement takes one argument"); - return 0; + return nullptr; } if (!check_set_arguments(arity, domain)) { - return 0; + return nullptr; } return m_manager->mk_func_decl(m_set_complement_sym, arity, domain, domain[0], func_decl_info(m_family_id, OP_SET_COMPLEMENT)); @@ -421,10 +421,10 @@ func_decl * array_decl_plugin::mk_set_complement(unsigned arity, sort * const * func_decl * array_decl_plugin::mk_set_subset(unsigned arity, sort * const * domain) { if (arity != 2) { m_manager->raise_exception("subset takes two arguments"); - return 0; + return nullptr; } if (!check_set_arguments(arity, domain)) { - return 0; + return nullptr; } sort * bool_sort = m_manager->mk_bool_sort(); return m_manager->mk_func_decl(m_set_subset_sym, arity, domain, bool_sort, @@ -456,20 +456,20 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters sort * s = to_sort(parameters[0].get_ast()); return mk_const(s, arity, domain); } - else if (range != 0) { + else if (range != nullptr) { return mk_const(range, arity, domain); } else { m_manager->raise_exception("array operation requires one sort parameter (the array sort)"); UNREACHABLE(); - return 0; + return nullptr; } } case OP_ARRAY_MAP: { if (num_parameters != 1 || !parameters[0].is_ast() || !is_func_decl(parameters[0].get_ast())) { m_manager->raise_exception("array operation requires one function declaration parameter (the function to be mapped)"); UNREACHABLE(); - return 0; + return nullptr; } func_decl * f = to_func_decl(parameters[0].get_ast()); return mk_map(f, arity, domain); @@ -480,7 +480,7 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters } if (num_parameters != 1 || !parameters[0].is_int()) { UNREACHABLE(); - return 0; + return nullptr; } return mk_array_ext(arity, domain, parameters[0].get_int()); case OP_ARRAY_DEFAULT: @@ -506,12 +506,12 @@ func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters tout << "as-array-bug: " << to_func_decl(parameters[0].get_ast())->get_name() << " " << to_func_decl(parameters[0].get_ast())->get_arity() << std::endl;); m_manager->raise_exception("as-array takes one parameter, a function declaration with arity greater than zero"); UNREACHABLE(); - return 0; + return nullptr; } func_decl * f = to_func_decl(parameters[0].get_ast()); return mk_as_array(f); } - default: return 0; + default: return nullptr; } } diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 488ee71fb..beaccfbd3 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -161,11 +161,11 @@ public: bool is_as_array_tree(expr * n); app * mk_store(unsigned num_args, expr * const * args) { - return m_manager.mk_app(m_fid, OP_STORE, 0, 0, num_args, args); + return m_manager.mk_app(m_fid, OP_STORE, 0, nullptr, num_args, args); } app * mk_select(unsigned num_args, expr * const * args) { - return m_manager.mk_app(m_fid, OP_SELECT, 0, 0, num_args, args); + return m_manager.mk_app(m_fid, OP_SELECT, 0, nullptr, num_args, args); } app * mk_map(func_decl * f, unsigned num_args, expr * const * args) { @@ -191,7 +191,7 @@ public: app * mk_as_array(func_decl * f) { parameter param(f); - return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, 0, 0); + return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, nullptr, nullptr); } }; diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index cc4beb1b6..b524cd8d4 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -405,7 +405,7 @@ sort * get_sort(expr const * n) { break; default: UNREACHABLE(); - return 0; + return nullptr; } } } @@ -434,18 +434,18 @@ bool compare_nodes(ast const * n1, ast const * n2) { } switch (n1->get_kind()) { case AST_SORT: - if ((to_sort(n1)->get_info() == 0) != (to_sort(n2)->get_info() == 0)) { + if ((to_sort(n1)->get_info() == nullptr) != (to_sort(n2)->get_info() == nullptr)) { return false; } - if (to_sort(n1)->get_info() != 0 && !(*to_sort(n1)->get_info() == *to_sort(n2)->get_info())) { + if (to_sort(n1)->get_info() != nullptr && !(*to_sort(n1)->get_info() == *to_sort(n2)->get_info())) { return false; } return to_sort(n1)->get_name() == to_sort(n2)->get_name(); case AST_FUNC_DECL: - if ((to_func_decl(n1)->get_info() == 0) != (to_func_decl(n2)->get_info() == 0)) { + if ((to_func_decl(n1)->get_info() == nullptr) != (to_func_decl(n2)->get_info() == nullptr)) { return false; } - if (to_func_decl(n1)->get_info() != 0 && !(*to_func_decl(n1)->get_info() == *to_func_decl(n2)->get_info())) { + if (to_func_decl(n1)->get_info() != nullptr && !(*to_func_decl(n1)->get_info() == *to_func_decl(n2)->get_info())) { return false; } return @@ -549,13 +549,13 @@ unsigned get_node_hash(ast const * n) { switch (n->get_kind()) { case AST_SORT: - if (to_sort(n)->get_info() == 0) + if (to_sort(n)->get_info() == nullptr) return to_sort(n)->get_name().hash(); else return combine_hash(to_sort(n)->get_name().hash(), to_sort(n)->get_info()->hash()); case AST_FUNC_DECL: return ast_array_hash(to_func_decl(n)->get_domain(), to_func_decl(n)->get_arity(), - to_func_decl(n)->get_info() == 0 ? + to_func_decl(n)->get_info() == nullptr ? to_func_decl(n)->get_name().hash() : combine_hash(to_func_decl(n)->get_name().hash(), to_func_decl(n)->get_info()->hash())); case AST_APP: return ast_array_hash(to_app(n)->get_args(), @@ -587,13 +587,13 @@ void ast_table::erase(ast * n) { unsigned idx = h & mask; cell * c = m_table + idx; SASSERT(!c->is_free()); - cell * prev = 0; + cell * prev = nullptr; while (true) { if (c->m_data == n) { m_size--; - if (prev == 0) { + if (prev == nullptr) { cell * next = c->m_next; - if (next == 0) { + if (next == nullptr) { m_used_slots--; c->mark_free(); SASSERT(c->is_free()); @@ -638,49 +638,49 @@ func_decl * decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, para // ----------------------------------- basic_decl_plugin::basic_decl_plugin(): - m_bool_sort(0), - m_true_decl(0), - m_false_decl(0), - m_and_decl(0), - m_or_decl(0), - m_iff_decl(0), - m_xor_decl(0), - m_not_decl(0), - m_interp_decl(0), - m_implies_decl(0), + m_bool_sort(nullptr), + m_true_decl(nullptr), + m_false_decl(nullptr), + m_and_decl(nullptr), + m_or_decl(nullptr), + m_iff_decl(nullptr), + m_xor_decl(nullptr), + m_not_decl(nullptr), + m_interp_decl(nullptr), + m_implies_decl(nullptr), - m_proof_sort(0), - m_undef_decl(0), - m_true_pr_decl(0), - m_asserted_decl(0), - m_goal_decl(0), - m_modus_ponens_decl(0), - m_reflexivity_decl(0), - m_symmetry_decl(0), - m_transitivity_decl(0), - m_quant_intro_decl(0), - m_and_elim_decl(0), - m_not_or_elim_decl(0), - m_rewrite_decl(0), - m_pull_quant_decl(0), - m_pull_quant_star_decl(0), - m_push_quant_decl(0), - m_elim_unused_vars_decl(0), - m_der_decl(0), - m_quant_inst_decl(0), + m_proof_sort(nullptr), + m_undef_decl(nullptr), + m_true_pr_decl(nullptr), + m_asserted_decl(nullptr), + m_goal_decl(nullptr), + m_modus_ponens_decl(nullptr), + m_reflexivity_decl(nullptr), + m_symmetry_decl(nullptr), + m_transitivity_decl(nullptr), + m_quant_intro_decl(nullptr), + m_and_elim_decl(nullptr), + m_not_or_elim_decl(nullptr), + m_rewrite_decl(nullptr), + m_pull_quant_decl(nullptr), + m_pull_quant_star_decl(nullptr), + m_push_quant_decl(nullptr), + m_elim_unused_vars_decl(nullptr), + m_der_decl(nullptr), + m_quant_inst_decl(nullptr), - m_hypothesis_decl(0), - m_iff_true_decl(0), - m_iff_false_decl(0), - m_commutativity_decl(0), - m_def_axiom_decl(0), - m_lemma_decl(0), + m_hypothesis_decl(nullptr), + m_iff_true_decl(nullptr), + m_iff_false_decl(nullptr), + m_commutativity_decl(nullptr), + m_def_axiom_decl(nullptr), + m_lemma_decl(nullptr), - m_def_intro_decl(0), - m_iff_oeq_decl(0), - m_skolemize_decl(0), - m_mp_oeq_decl(0), - m_hyper_res_decl0(0) { + m_def_intro_decl(nullptr), + m_iff_oeq_decl(nullptr), + m_skolemize_decl(nullptr), + m_mp_oeq_decl(nullptr), + m_hyper_res_decl0(nullptr) { } bool basic_decl_plugin::check_proof_sorts(basic_op_kind k, unsigned arity, sort * const * domain) const { @@ -790,7 +790,7 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_param } default: UNREACHABLE(); - return 0; + return nullptr; } } @@ -852,7 +852,7 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_paren case PR_HYPER_RESOLVE: return mk_proof_decl("hyper-res", k, num_parents, m_hyper_res_decl0); default: UNREACHABLE(); - return 0; + return nullptr; } } @@ -1067,10 +1067,10 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_IFF: return m_iff_decl; case OP_IMPLIES: return m_implies_decl; case OP_XOR: return m_xor_decl; - case OP_ITE: return arity == 3 ? mk_ite_decl(join(domain[1], domain[2])) : 0; + case OP_ITE: return arity == 3 ? mk_ite_decl(join(domain[1], domain[2])) : nullptr; // eq and oeq must have at least two arguments, they can have more since they are chainable - case OP_EQ: return arity >= 2 ? mk_eq_decl_core("=", OP_EQ, join(arity, domain), m_eq_decls) : 0; - case OP_OEQ: return arity >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(arity, domain), m_oeq_decls) : 0; + case OP_EQ: return arity >= 2 ? mk_eq_decl_core("=", OP_EQ, join(arity, domain), m_eq_decls) : nullptr; + case OP_OEQ: return arity >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(arity, domain), m_oeq_decls) : nullptr; case OP_DISTINCT: { func_decl_info info(m_family_id, OP_DISTINCT); info.set_pairwise(); @@ -1110,10 +1110,10 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_IFF: return m_iff_decl; case OP_IMPLIES: return m_implies_decl; case OP_XOR: return m_xor_decl; - case OP_ITE: return num_args == 3 ? mk_ite_decl(join(m_manager->get_sort(args[1]), m_manager->get_sort(args[2]))): 0; + case OP_ITE: return num_args == 3 ? mk_ite_decl(join(m_manager->get_sort(args[1]), m_manager->get_sort(args[2]))): nullptr; // eq and oeq must have at least two arguments, they can have more since they are chainable - case OP_EQ: return num_args >= 2 ? mk_eq_decl_core("=", OP_EQ, join(num_args, args), m_eq_decls) : 0; - case OP_OEQ: return num_args >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(num_args, args), m_oeq_decls) : 0; + case OP_EQ: return num_args >= 2 ? mk_eq_decl_core("=", OP_EQ, join(num_args, args), m_eq_decls) : nullptr; + case OP_OEQ: return num_args >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(num_args, args), m_oeq_decls) : nullptr; case OP_DISTINCT: return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range); default: @@ -1134,7 +1134,7 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters expr * basic_decl_plugin::get_some_value(sort * s) { if (s == m_bool_sort) return m_manager->mk_false(); - return 0; + return nullptr; } bool basic_recognizers::is_ite(expr const * n, expr * & t1, expr * & t2, expr * & t3) const { @@ -1168,7 +1168,7 @@ void label_decl_plugin::set_manager(ast_manager * m, family_id id) { sort * label_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { UNREACHABLE(); - return 0; + return nullptr; } func_decl * label_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -1176,12 +1176,12 @@ func_decl * label_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters if (k == OP_LABEL) { if (arity != 1 || num_parameters < 2 || !parameters[0].is_int() || !parameters[1].is_symbol() || !m_manager->is_bool(domain[0])) { m_manager->raise_exception("invalid label declaration"); - return 0; + return nullptr; } for (unsigned i = 2; i < num_parameters; i++) { if (!parameters[i].is_symbol()) { m_manager->raise_exception("invalid label declaration"); - return 0; + return nullptr; } } return m_manager->mk_func_decl(parameters[0].get_int() ? m_lblpos : m_lblneg, arity, domain, domain[0], @@ -1191,15 +1191,15 @@ func_decl * label_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters SASSERT(k == OP_LABEL_LIT); if (arity != 0) { m_manager->raise_exception("invalid label literal declaration"); - return 0; + return nullptr; } for (unsigned i = 0; i < num_parameters; i++) { if (!parameters[i].is_symbol()) { m_manager->raise_exception("invalid label literal declaration"); - return 0; + return nullptr; } } - return m_manager->mk_func_decl(m_lbllit, 0, static_cast(0), m_manager->mk_bool_sort(), + return m_manager->mk_func_decl(m_lbllit, 0, static_cast(nullptr), m_manager->mk_bool_sort(), func_decl_info(m_family_id, OP_LABEL_LIT, num_parameters, parameters)); } } @@ -1212,7 +1212,7 @@ func_decl * label_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters sort * pattern_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { UNREACHABLE(); - return 0; + return nullptr; } func_decl * pattern_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -1230,7 +1230,7 @@ func_decl * pattern_decl_plugin::mk_func_decl(decl_kind k, unsigned num_paramete sort * model_value_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { UNREACHABLE(); - return 0; + return nullptr; } func_decl * model_value_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -1239,7 +1239,7 @@ func_decl * model_value_decl_plugin::mk_func_decl(decl_kind k, unsigned num_para if (arity != 0 || num_parameters != 2 || !parameters[0].is_int() || !parameters[1].is_ast() || !is_sort(parameters[1].get_ast())) { UNREACHABLE(); m_manager->raise_exception("invalid model value"); - return 0; + return nullptr; } int idx = parameters[0].get_int(); sort * s = to_sort(parameters[1].get_ast()); @@ -1247,7 +1247,7 @@ func_decl * model_value_decl_plugin::mk_func_decl(decl_kind k, unsigned num_para buffer << s->get_name().bare_str() << "!val!" << idx; func_decl_info info(m_family_id, k, num_parameters, parameters); info.m_private_parameters = true; - return m_manager->mk_func_decl(symbol(buffer.c_str()), 0, static_cast(0), s, info); + return m_manager->mk_func_decl(symbol(buffer.c_str()), 0, static_cast(nullptr), s, info); } bool model_value_decl_plugin::is_value(app* n) const { @@ -1274,7 +1274,7 @@ sort * user_sort_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter func_decl * user_sort_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { UNREACHABLE(); - return 0; + return nullptr; } decl_kind user_sort_plugin::register_name(symbol s) { @@ -1307,7 +1307,7 @@ ast_manager::ast_manager(proof_gen_mode m, char const * trace_file, bool is_form m_expr_dependency_manager(*this, m_alloc), m_expr_dependency_array_manager(*this, m_alloc), m_proof_mode(m), - m_trace_stream(0), + m_trace_stream(nullptr), m_trace_stream_owner(false), m_rec_fun(":rec-fun") { @@ -1319,7 +1319,7 @@ ast_manager::ast_manager(proof_gen_mode m, char const * trace_file, bool is_form if (!is_format_manager) m_format_manager = alloc(ast_manager, PGM_DISABLED, m_trace_stream, true); else - m_format_manager = 0; + m_format_manager = nullptr; init(); } @@ -1336,7 +1336,7 @@ ast_manager::ast_manager(proof_gen_mode m, std::fstream * trace_stream, bool is_ if (!is_format_manager) m_format_manager = alloc(ast_manager, PGM_DISABLED, trace_stream, true); else - m_format_manager = 0; + m_format_manager = nullptr; init(); } @@ -1361,7 +1361,7 @@ void ast_manager::init() { m_fresh_id = 0; m_expr_id_gen.reset(0); m_decl_id_gen.reset(c_first_decl_id); - m_some_value_proc = 0; + m_some_value_proc = nullptr; m_basic_family_id = mk_family_id("basic"); m_label_family_id = mk_family_id("label"); m_pattern_family_id = mk_family_id("pattern"); @@ -1427,14 +1427,14 @@ ast_manager::~ast_manager() { switch (n->get_kind()) { case AST_SORT: { sort_info* info = to_sort(n)->get_info(); - if (info != 0) { + if (info != nullptr) { mark_array_ref(mark, info->get_num_parameters(), info->get_parameters()); } break; } case AST_FUNC_DECL: { func_decl_info* info = to_func_decl(n)->get_info(); - if (info != 0) { + if (info != nullptr) { mark_array_ref(mark, info->get_num_parameters(), info->get_parameters()); } mark_array_ref(mark, to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain()); @@ -1476,14 +1476,14 @@ ast_manager::~ast_manager() { delete_node(a); } } - if (m_format_manager != 0) + if (m_format_manager != nullptr) dealloc(m_format_manager); if (m_trace_stream_owner) { std::fstream & tmp = * m_trace_stream; tmp << "[eof]\n"; tmp.close(); dealloc(m_trace_stream); - m_trace_stream = 0; + m_trace_stream = nullptr; } } @@ -1587,7 +1587,7 @@ decl_plugin * ast_manager::get_plugin(family_id fid) const { bool ast_manager::is_value(expr* e) const { - decl_plugin const * p = 0; + decl_plugin const * p = nullptr; if (is_app(e)) { p = get_plugin(to_app(e)->get_family_id()); return p && p->is_value(to_app(e)); @@ -1596,7 +1596,7 @@ bool ast_manager::is_value(expr* e) const { } bool ast_manager::is_unique_value(expr* e) const { - decl_plugin const * p = 0; + decl_plugin const * p = nullptr; if (is_app(e)) { p = get_plugin(to_app(e)->get_family_id()); return p && p->is_unique_value(to_app(e)); @@ -1698,13 +1698,13 @@ ast * ast_manager::register_node_core(ast * n) { // increment reference counters switch (n->get_kind()) { case AST_SORT: - if (to_sort(n)->m_info != 0) { + if (to_sort(n)->m_info != nullptr) { to_sort(n)->m_info = alloc(sort_info, *(to_sort(n)->get_info())); to_sort(n)->m_info->init_eh(*this); } break; case AST_FUNC_DECL: - if (to_func_decl(n)->m_info != 0) { + if (to_func_decl(n)->m_info != nullptr) { to_func_decl(n)->m_info = alloc(func_decl_info, *(to_func_decl(n)->get_info())); to_func_decl(n)->m_info->init_eh(*this); } @@ -1807,14 +1807,14 @@ void ast_manager::delete_node(ast * n) { #endif switch (n->get_kind()) { case AST_SORT: - if (to_sort(n)->m_info != 0 && !m_debug_ref_count) { + if (to_sort(n)->m_info != nullptr && !m_debug_ref_count) { sort_info * info = to_sort(n)->get_info(); info->del_eh(*this); dealloc(info); } break; case AST_FUNC_DECL: - if (to_func_decl(n)->m_info != 0 && !m_debug_ref_count) { + if (to_func_decl(n)->m_info != nullptr && !m_debug_ref_count) { func_decl_info * info = to_func_decl(n)->get_info(); info->del_eh(*this); dealloc(info); @@ -1849,7 +1849,7 @@ sort * ast_manager::mk_sort(family_id fid, decl_kind k, unsigned num_parameters, decl_plugin * p = get_plugin(fid); if (p) return p->mk_sort(k, num_parameters, parameters); - return 0; + return nullptr; } func_decl * ast_manager::mk_func_decl(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -1857,7 +1857,7 @@ func_decl * ast_manager::mk_func_decl(family_id fid, decl_kind k, unsigned num_p decl_plugin * p = get_plugin(fid); if (p) return p->mk_func_decl(k, num_parameters, parameters, arity, domain, range); - return 0; + return nullptr; } func_decl * ast_manager::mk_func_decl(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -1865,33 +1865,33 @@ func_decl * ast_manager::mk_func_decl(family_id fid, decl_kind k, unsigned num_p decl_plugin * p = get_plugin(fid); if (p) return p->mk_func_decl(k, num_parameters, parameters, num_args, args, range); - return 0; + return nullptr; } app * ast_manager::mk_app(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned num_args, expr * const * args, sort * range) { func_decl * decl = mk_func_decl(fid, k, num_parameters, parameters, num_args, args, range); - if (decl != 0) + if (decl != nullptr) return mk_app(decl, num_args, args); - return 0; + return nullptr; } app * ast_manager::mk_app(family_id fid, decl_kind k, unsigned num_args, expr * const * args) { - return mk_app(fid, k, 0, 0, num_args, args); + return mk_app(fid, k, 0, nullptr, num_args, args); } app * ast_manager::mk_app(family_id fid, decl_kind k, expr * arg) { - return mk_app(fid, k, 0, 0, 1, &arg); + return mk_app(fid, k, 0, nullptr, 1, &arg); } app * ast_manager::mk_app(family_id fid, decl_kind k, expr * arg1, expr * arg2) { expr * args[2] = { arg1, arg2 }; - return mk_app(fid, k, 0, 0, 2, args); + return mk_app(fid, k, 0, nullptr, 2, args); } app * ast_manager::mk_app(family_id fid, decl_kind k, expr * arg1, expr * arg2, expr * arg3) { expr * args[3] = { arg1, arg2, arg3 }; - return mk_app(fid, k, 0, 0, 3, args); + return mk_app(fid, k, 0, nullptr, 3, args); } sort * ast_manager::mk_sort(symbol const & name, sort_info * info) { @@ -2062,8 +2062,8 @@ bool ast_manager::coercion_needed(func_decl * decl, unsigned num_args, expr * co } app * ast_manager::mk_app_core(func_decl * decl, unsigned num_args, expr * const * args) { - app * r = 0; - app * new_node = 0; + app * r = nullptr; + app * new_node = nullptr; unsigned sz = app::get_obj_size(num_args); void * mem = allocate_node(sz); @@ -2171,7 +2171,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar << ") passed to function " << mk_pp(decl, *this); throw ast_exception(buffer.str().c_str()); } - app * r = 0; + app * r = nullptr; if (num_args == 1 && decl->is_chainable() && decl->get_arity() == 2) { r = mk_true(); } @@ -2200,7 +2200,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar r = mk_and(new_args.size(), new_args.c_ptr()); } } - if (r == 0) { + if (r == nullptr) { r = mk_app_core(decl, num_args, args); } SASSERT(r != 0); @@ -2287,7 +2287,7 @@ app * ast_manager::mk_label_lit(unsigned num_names, symbol const * names) { buffer p; for (unsigned i = 0; i < num_names; i++) p.push_back(parameter(names[i])); - return mk_app(m_label_family_id, OP_LABEL_LIT, p.size(), p.c_ptr(), 0, 0); + return mk_app(m_label_family_id, OP_LABEL_LIT, p.size(), p.c_ptr(), 0, nullptr); } app * ast_manager::mk_label_lit(symbol const & name) { @@ -2309,7 +2309,7 @@ app * ast_manager::mk_pattern(unsigned num_exprs, app * const * exprs) { for (unsigned i = 0; i < num_exprs; ++i) { SASSERT(is_app(exprs[i])); }}); - return mk_app(m_pattern_family_id, OP_PATTERN, 0, 0, num_exprs, (expr*const*)exprs); + return mk_app(m_pattern_family_id, OP_PATTERN, 0, nullptr, num_exprs, (expr*const*)exprs); } bool ast_manager::is_pattern(expr const * n) const { @@ -2406,7 +2406,7 @@ quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_pattern num_patterns, patterns, num_patterns == 0 ? q->get_num_no_patterns() : 0, - num_patterns == 0 ? q->get_no_patterns() : 0); + num_patterns == 0 ? q->get_no_patterns() : nullptr); } quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_patterns, expr * const * patterns, unsigned num_no_patterns, expr * const * no_patterns, expr * body) { @@ -2492,7 +2492,7 @@ quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, unsi num_patterns, patterns, num_patterns == 0 ? q->get_num_no_patterns() : 0, - num_patterns == 0 ? q->get_no_patterns() : 0); + num_patterns == 0 ? q->get_no_patterns() : nullptr); } app * ast_manager::mk_distinct(unsigned num_args, expr * const * args) { @@ -2524,14 +2524,14 @@ app * ast_manager::mk_distinct_expanded(unsigned num_args, expr * const * args) // ----------------------------------- expr_dependency * ast_manager::mk_leaf(expr * t) { - if (t == 0) - return 0; + if (t == nullptr) + return nullptr; else return m_expr_dependency_manager.mk_leaf(t); } expr_dependency * ast_manager::mk_join(unsigned n, expr * const * ts) { - expr_dependency * d = 0; + expr_dependency * d = nullptr; for (unsigned i = 0; i < n; i++) d = mk_join(d, mk_leaf(ts[i])); return d; @@ -2550,7 +2550,7 @@ void ast_manager::linearize(expr_dependency * d, ptr_vector & ts) { app * ast_manager::mk_model_value(unsigned idx, sort * s) { parameter p[2] = { parameter(idx), parameter(s) }; - return mk_app(m_model_value_family_id, OP_MODEL_VALUE, 2, p, 0, static_cast(0)); + return mk_app(m_model_value_family_id, OP_MODEL_VALUE, 2, p, 0, static_cast(nullptr)); } expr * ast_manager::get_some_value(sort * s, some_value_proc * p) { @@ -2559,17 +2559,17 @@ expr * ast_manager::get_some_value(sort * s, some_value_proc * p) { } expr * ast_manager::get_some_value(sort * s) { - expr * v = 0; + expr * v = nullptr; if (m_some_value_proc) v = (*m_some_value_proc)(s); - if (v != 0) + if (v != nullptr) return v; family_id fid = s->get_family_id(); if (fid != null_family_id) { decl_plugin * p = get_plugin(fid); - if (p != 0) { + if (p != nullptr) { v = p->get_some_value(s); - if (v != 0) + if (v != nullptr) return v; } } @@ -2582,7 +2582,7 @@ bool ast_manager::is_fully_interp(sort * s) const { family_id fid = s->get_family_id(); SASSERT(fid != null_family_id); decl_plugin * p = get_plugin(fid); - if (p != 0) + if (p != nullptr) return p->is_fully_interp(s); return false; } @@ -2780,14 +2780,14 @@ proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proo SASSERT(get_sort(f1) == get_sort(f2)); sort * s = get_sort(f1); sort * d[2] = { s, s }; - return mk_monotonicity(mk_func_decl(m_basic_family_id, get_eq_op(f1), 0, 0, 2, d), f1, f2, num_proofs, proofs); + return mk_monotonicity(mk_func_decl(m_basic_family_id, get_eq_op(f1), 0, nullptr, 2, d), f1, f2, num_proofs, proofs); } proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { SASSERT(get_sort(f1) == get_sort(f2)); sort * s = get_sort(f1); sort * d[2] = { s, s }; - return mk_monotonicity(mk_func_decl(m_basic_family_id, OP_OEQ, 0, 0, 2, d), f1, f2, num_proofs, proofs); + return mk_monotonicity(mk_func_decl(m_basic_family_id, OP_OEQ, 0, nullptr, 2, d), f1, f2, num_proofs, proofs); } proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) { diff --git a/src/ast/ast.h b/src/ast/ast.h index 77049fa53..55fea1b69 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -132,7 +132,7 @@ public: case PARAM_INT: m_int = other.get_int(); break; case PARAM_AST: m_ast = other.get_ast(); break; case PARAM_SYMBOL: m_symbol = other.m_symbol; break; - case PARAM_RATIONAL: m_rational = 0; std::swap(m_rational, other.m_rational); break; + case PARAM_RATIONAL: m_rational = nullptr; std::swap(m_rational, other.m_rational); break; case PARAM_DOUBLE: m_dval = other.m_dval; break; case PARAM_EXTERNAL: m_ext_id = other.m_ext_id; break; default: @@ -258,7 +258,7 @@ class decl_info { public: bool m_private_parameters; decl_info(family_id family_id = null_family_id, decl_kind k = null_decl_kind, - unsigned num_parameters = 0, parameter const * parameters = 0, bool private_params = false); + unsigned num_parameters = 0, parameter const * parameters = nullptr, bool private_params = false); decl_info(decl_info const& other); ~decl_info() {} @@ -342,17 +342,17 @@ class sort_info : public decl_info { sort_size m_num_elements; public: sort_info(family_id family_id = null_family_id, decl_kind k = null_decl_kind, - unsigned num_parameters = 0, parameter const * parameters = 0, bool private_parameters = false): + unsigned num_parameters = 0, parameter const * parameters = nullptr, bool private_parameters = false): decl_info(family_id, k, num_parameters, parameters, private_parameters) { } sort_info(family_id family_id, decl_kind k, uint64 num_elements, - unsigned num_parameters = 0, parameter const * parameters = 0, bool private_parameters = false): + unsigned num_parameters = 0, parameter const * parameters = nullptr, bool private_parameters = false): decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) { } sort_info(family_id family_id, decl_kind k, sort_size const& num_elements, - unsigned num_parameters = 0, parameter const * parameters = 0, bool private_parameters = false): + unsigned num_parameters = 0, parameter const * parameters = nullptr, bool private_parameters = false): decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) { } sort_info(sort_info const& other) : decl_info(other), m_num_elements(other.m_num_elements) { @@ -390,7 +390,7 @@ struct func_decl_info : public decl_info { bool m_idempotent:1; bool m_skolem:1; - func_decl_info(family_id family_id = null_family_id, decl_kind k = null_decl_kind, unsigned num_parameters = 0, parameter const * parameters = 0); + func_decl_info(family_id family_id = null_family_id, decl_kind k = null_decl_kind, unsigned num_parameters = 0, parameter const * parameters = nullptr); ~func_decl_info() {} bool is_associative() const { return m_left_assoc && m_right_assoc; } @@ -565,12 +565,12 @@ public: unsigned get_decl_id() const { SASSERT(get_id() >= c_first_decl_id); return get_id() - c_first_decl_id; } symbol const & get_name() const { return m_name; } decl_info * get_info() const { return m_info; } - family_id get_family_id() const { return m_info == 0 ? null_family_id : m_info->get_family_id(); } - decl_kind get_decl_kind() const { return m_info == 0 ? null_decl_kind : m_info->get_decl_kind(); } - unsigned get_num_parameters() const { return m_info == 0 ? 0 : m_info->get_num_parameters(); } + family_id get_family_id() const { return m_info == nullptr ? null_family_id : m_info->get_family_id(); } + decl_kind get_decl_kind() const { return m_info == nullptr ? null_decl_kind : m_info->get_decl_kind(); } + unsigned get_num_parameters() const { return m_info == nullptr ? 0 : m_info->get_num_parameters(); } parameter const & get_parameter(unsigned idx) const { return m_info->get_parameter(idx); } - parameter const * get_parameters() const { return m_info == 0 ? 0 : m_info->get_parameters(); } - bool private_parameters() const { return m_info != 0 && m_info->private_parameters(); } + 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(); } }; // ----------------------------------- @@ -587,8 +587,8 @@ class sort : public decl { sort(symbol const & name, sort_info * info):decl(AST_SORT, name, info) {} public: sort_info * get_info() const { return static_cast(m_info); } - bool is_infinite() const { return get_info() == 0 || get_info()->is_infinite(); } - bool is_very_big() const { return get_info() == 0 || get_info()->is_very_big(); } + bool is_infinite() const { return get_info() == nullptr || get_info()->is_infinite(); } + bool is_very_big() const { return get_info() == nullptr || get_info()->is_very_big(); } bool is_sort_of(family_id fid, decl_kind k) const { return get_family_id() == fid && get_decl_kind() == k; } sort_size const & get_num_elements() const { return get_info()->get_num_elements(); } void set_num_elements(sort_size const& s) { get_info()->set_num_elements(s); } @@ -613,16 +613,16 @@ class func_decl : public decl { func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range, func_decl_info * info); public: func_decl_info * get_info() const { return static_cast(m_info); } - bool is_associative() const { return get_info() != 0 && get_info()->is_associative(); } - bool is_left_associative() const { return get_info() != 0 && get_info()->is_left_associative(); } - bool is_right_associative() const { return get_info() != 0 && get_info()->is_right_associative(); } - bool is_flat_associative() const { return get_info() != 0 && get_info()->is_flat_associative(); } - bool is_commutative() const { return get_info() != 0 && get_info()->is_commutative(); } - bool is_chainable() const { return get_info() != 0 && get_info()->is_chainable(); } - bool is_pairwise() const { return get_info() != 0 && get_info()->is_pairwise(); } - bool is_injective() const { return get_info() != 0 && get_info()->is_injective(); } - bool is_skolem() const { return get_info() != 0 && get_info()->is_skolem(); } - bool is_idempotent() const { return get_info() != 0 && get_info()->is_idempotent(); } + bool is_associative() const { return get_info() != nullptr && get_info()->is_associative(); } + bool is_left_associative() const { return get_info() != nullptr && get_info()->is_left_associative(); } + bool is_right_associative() const { return get_info() != nullptr && get_info()->is_right_associative(); } + bool is_flat_associative() const { return get_info() != nullptr && get_info()->is_flat_associative(); } + bool is_commutative() const { return get_info() != nullptr && get_info()->is_commutative(); } + bool is_chainable() const { return get_info() != nullptr && get_info()->is_chainable(); } + bool is_pairwise() const { return get_info() != nullptr && get_info()->is_pairwise(); } + bool is_injective() const { return get_info() != nullptr && get_info()->is_injective(); } + bool is_skolem() const { return get_info() != nullptr && get_info()->is_skolem(); } + bool is_idempotent() const { return get_info() != nullptr && get_info()->is_idempotent(); } unsigned get_arity() const { return m_arity; } sort * get_domain(unsigned idx) const { SASSERT(idx < get_arity()); return m_domain[idx]; } sort * const * get_domain() const { return m_domain; } @@ -957,7 +957,7 @@ protected: friend class ast_manager; public: - decl_plugin():m_manager(0), m_family_id(null_family_id) {} + decl_plugin():m_manager(nullptr), m_family_id(null_family_id) {} virtual ~decl_plugin() {} virtual void finalize() {} @@ -1013,7 +1013,7 @@ public: virtual void get_sort_names(svector & sort_names, symbol const & logic = symbol()) {} - virtual expr * get_some_value(sort * s) { return 0; } + virtual expr * get_some_value(sort * s) { return nullptr; } // Return true if the interpreted sort s does not depend on uninterpreted sorts. // This may be the case, for example, for array and datatype sorts. @@ -1497,14 +1497,14 @@ protected: public: - ast_manager(proof_gen_mode = PGM_DISABLED, char const * trace_file = 0, bool is_format_manager = false); + ast_manager(proof_gen_mode = PGM_DISABLED, char const * trace_file = nullptr, bool is_format_manager = false); ast_manager(proof_gen_mode, std::fstream * trace_stream, bool is_format_manager = false); ast_manager(ast_manager const & src, bool disable_proofs = false); ~ast_manager(); // propagate cancellation signal to decl_plugins - bool has_trace_stream() const { return m_trace_stream != 0; } + bool has_trace_stream() const { return m_trace_stream != nullptr; } std::ostream & trace_stream() { SASSERT(has_trace_stream()); return *m_trace_stream; } void enable_int_real_coercions(bool f) { m_int_real_coercions = f; } @@ -1523,7 +1523,7 @@ public: // Equivalent to throw ast_exception(msg) Z3_NORETURN void raise_exception(char const * msg); - bool is_format_manager() const { return m_format_manager == 0; } + bool is_format_manager() const { return m_format_manager == nullptr; } ast_manager & get_format_manager() { return is_format_manager() ? *this : *m_format_manager; } @@ -1558,7 +1558,7 @@ public: decl_plugin * get_plugin(family_id fid) const; - bool has_plugin(family_id fid) const { return get_plugin(fid) != 0; } + bool has_plugin(family_id fid) const { return get_plugin(fid) != nullptr; } bool has_plugin(symbol const & s) const { return m_family_manager.has_family(s) && has_plugin(m_family_manager.get_family_id(s)); } @@ -1670,7 +1670,7 @@ private: public: sort * mk_uninterpreted_sort(symbol const & name, unsigned num_parameters, parameter const * parameters); - sort * mk_uninterpreted_sort(symbol const & name) { return mk_uninterpreted_sort(name, 0, 0); } + sort * mk_uninterpreted_sort(symbol const & name) { return mk_uninterpreted_sort(name, 0, nullptr); } sort * mk_sort(symbol const & name, sort_info const & info) { if (info.get_family_id() == null_family_id) { @@ -1681,7 +1681,7 @@ public: } } - sort * mk_sort(family_id fid, decl_kind k, unsigned num_parameters = 0, parameter const * parameters = 0); + sort * mk_sort(family_id fid, decl_kind k, unsigned num_parameters = 0, parameter const * parameters = nullptr); sort * substitute(sort* s, unsigned n, sort * const * src, sort * const * dst); @@ -1700,13 +1700,13 @@ public: bool is_fully_interp(sort * s) const; func_decl * mk_func_decl(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range = 0); + unsigned arity, sort * const * domain, sort * range = nullptr); func_decl * mk_func_decl(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned num_args, expr * const * args, sort * range = 0); + unsigned num_args, expr * const * args, sort * range = nullptr); - app * mk_app(family_id fid, decl_kind k, unsigned num_parameters = 0, parameter const * parameters = 0, - unsigned num_args = 0, expr * const * args = 0, sort * range = 0); + app * mk_app(family_id fid, decl_kind k, unsigned num_parameters = 0, parameter const * parameters = nullptr, + unsigned num_args = 0, expr * const * args = nullptr, sort * range = nullptr); app * mk_app(family_id fid, decl_kind k, unsigned num_args, expr * const * args); @@ -1716,7 +1716,7 @@ public: app * mk_app(family_id fid, decl_kind k, expr * arg1, expr * arg2, expr * arg3); - app * mk_const(family_id fid, decl_kind k) { return mk_app(fid, k, 0, static_cast(0)); } + app * mk_const(family_id fid, decl_kind k) { return mk_app(fid, k, 0, static_cast(nullptr)); } private: func_decl * mk_func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range, func_decl_info * info); @@ -1727,13 +1727,13 @@ private: public: func_decl * mk_func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range) { - return mk_func_decl(name, arity, domain, range, static_cast(0)); + return mk_func_decl(name, arity, domain, range, static_cast(nullptr)); } func_decl * mk_func_decl(symbol const & name, unsigned arity, sort * const * domain, sort * range, func_decl_info const & info) { if (info.is_null()) { - return mk_func_decl(name, arity, domain, range, static_cast(0)); + return mk_func_decl(name, arity, domain, range, static_cast(nullptr)); } else { return mk_func_decl(name, arity, domain, range, & const_cast(info)); @@ -1746,11 +1746,11 @@ public: } func_decl * mk_const_decl(symbol const & name, sort * s) { - return mk_func_decl(name, static_cast(0), 0, s); + return mk_func_decl(name, static_cast(0), nullptr, s); } func_decl * mk_const_decl(symbol const & name, sort * s, func_decl_info const & info) { - return mk_func_decl(name, static_cast(0), 0, s, info); + return mk_func_decl(name, static_cast(0), nullptr, s, info); } func_decl * mk_func_decl(symbol const & name, sort * domain, sort * range, func_decl_info const & info) { @@ -1804,7 +1804,7 @@ public: app * mk_const(func_decl * decl) { SASSERT(decl->get_arity() == 0); - return mk_app(decl, static_cast(0), static_cast(0)); + return mk_app(decl, static_cast(0), static_cast(nullptr)); } app * mk_const(symbol const & name, sort * s) { @@ -1825,9 +1825,9 @@ public: return mk_fresh_func_decl(symbol(prefix), symbol::null, arity, domain, range); } - app * mk_fresh_const(char const * prefix, sort * s) { return mk_const(mk_fresh_func_decl(prefix, 0, 0, s)); } + app * mk_fresh_const(char const * prefix, sort * s) { return mk_const(mk_fresh_func_decl(prefix, 0, nullptr, s)); } - symbol mk_fresh_var_name(char const * prefix = 0); + symbol mk_fresh_var_name(char const * prefix = nullptr); var * mk_var(unsigned idx, sort * ty); @@ -1879,21 +1879,21 @@ public: quantifier * mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null, - unsigned num_patterns = 0, expr * const * patterns = 0, - unsigned num_no_patterns = 0, expr * const * no_patterns = 0); + unsigned num_patterns = 0, expr * const * patterns = nullptr, + unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr); quantifier * mk_forall(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null, - unsigned num_patterns = 0, expr * const * patterns = 0, - unsigned num_no_patterns = 0, expr * const * no_patterns = 0) { + unsigned num_patterns = 0, expr * const * patterns = nullptr, + unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr) { return mk_quantifier(true, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns, num_no_patterns, no_patterns); } quantifier * mk_exists(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null, - unsigned num_patterns = 0, expr * const * patterns = 0, - unsigned num_no_patterns = 0, expr * const * no_patterns = 0) { + unsigned num_patterns = 0, expr * const * patterns = nullptr, + unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr) { return mk_quantifier(false, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns, num_no_patterns, no_patterns); } @@ -2057,12 +2057,12 @@ public: func_decl* mk_and_decl() { sort* domain[2] = { m_bool_sort, m_bool_sort }; - return mk_func_decl(m_basic_family_id, OP_AND, 0, 0, 2, domain); + return mk_func_decl(m_basic_family_id, OP_AND, 0, nullptr, 2, domain); } - func_decl* mk_not_decl() { return mk_func_decl(m_basic_family_id, OP_NOT, 0, 0, 1, &m_bool_sort); } + func_decl* mk_not_decl() { return mk_func_decl(m_basic_family_id, OP_NOT, 0, nullptr, 1, &m_bool_sort); } func_decl* mk_or_decl() { sort* domain[2] = { m_bool_sort, m_bool_sort }; - return mk_func_decl(m_basic_family_id, OP_OR, 0, 0, 2, domain); + return mk_func_decl(m_basic_family_id, OP_OR, 0, nullptr, 2, domain); } // ----------------------------------- @@ -2210,7 +2210,7 @@ public: proof * mk_th_lemma(family_id tid, expr * fact, unsigned num_proofs, proof * const * proofs, - unsigned num_params = 0, parameter const* params = 0); + unsigned num_params = 0, parameter const* params = nullptr); protected: bool check_nnf_proof_parents(unsigned num_proofs, proof * const * proofs) const; diff --git a/src/ast/ast_ll_pp.cpp b/src/ast/ast_ll_pp.cpp index c00053780..cbdd94efb 100644 --- a/src/ast/ast_ll_pp.cpp +++ b/src/ast/ast_ll_pp.cpp @@ -319,11 +319,11 @@ void ast_ll_pp(std::ostream & out, ast_manager & m, ast * n, ast_mark & visited, } void ast_def_ll_pp(std::ostream & out, ast_manager & m, ast * n, ast_mark & visited, bool only_exprs, bool compact) { - ll_printer p(out, m, 0, only_exprs, compact); + ll_printer p(out, m, nullptr, only_exprs, compact); p.pp(n, visited); } void ast_ll_bounded_pp(std::ostream & out, ast_manager & m, ast * n, unsigned depth) { - ll_printer p(out, m, 0, false, true); + ll_printer p(out, m, nullptr, false, true); p.display_bounded(n, depth); } diff --git a/src/ast/ast_pp.h b/src/ast/ast_pp.h index 997b1a6e0..5629f847a 100644 --- a/src/ast/ast_pp.h +++ b/src/ast/ast_pp.h @@ -24,10 +24,10 @@ Revision History: #include "ast/ast_smt2_pp.h" struct mk_pp : public mk_ismt2_pp { - mk_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0): + mk_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = nullptr): mk_ismt2_pp(t, m, p, indent, num_vars, var_prefix) { } - mk_pp(ast * t, ast_manager & m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0): + mk_pp(ast * t, ast_manager & m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = nullptr): mk_ismt2_pp(t, m, indent, num_vars, var_prefix) { } }; diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 677422b8a..4579f2ffc 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -40,7 +40,7 @@ void ast_pp_util::display_decls(std::ostream& out) { ast_smt_pp pp(m); unsigned n = coll.get_num_sorts(); for (unsigned i = 0; i < n; ++i) { - pp.display_ast_smt2(out, coll.get_sorts()[i], 0, 0, 0); + pp.display_ast_smt2(out, coll.get_sorts()[i], 0, 0, nullptr); } n = coll.get_num_decls(); for (unsigned i = 0; i < n; ++i) { diff --git a/src/ast/ast_printer.cpp b/src/ast/ast_printer.cpp index 63e855c59..536e1af92 100644 --- a/src/ast/ast_printer.cpp +++ b/src/ast/ast_printer.cpp @@ -37,7 +37,7 @@ public: void pp(func_decl * f, format_ns::format_ref & r) const override { mk_smt2_format(f, env(), params_ref(), r); } void pp(expr * n, format_ns::format_ref & r) const override { sbuffer buf; - mk_smt2_format(n, env(), params_ref(), 0, 0, r, buf); + mk_smt2_format(n, env(), params_ref(), 0, nullptr, r, buf); } void pp(expr * n, unsigned num_vars, char const * var_prefix, format_ns::format_ref & r, sbuffer & var_names) const override { mk_smt2_format(n, env(), params_ref(), num_vars, var_prefix, r, var_names); diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 0139cb0f0..8ad7c27f1 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -236,7 +236,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u mpf_manager & fm = get_futil().fm(); scoped_mpf v(fm); ast_manager & m = get_manager(); - format * body = 0; + format * body = nullptr; string_buffer<> buf; VERIFY(get_futil().is_numeral(t, v)); if (fm.is_nan(v)) { @@ -750,7 +750,7 @@ class smt2_printer { } buffer labels; bool is_pos; - format * f = 0; + format * f = nullptr; format ** it = m_format_stack.c_ptr() + fr.m_spos; format ** end = m_format_stack.c_ptr() + m_format_stack.size(); if (m().is_label(t, is_pos, labels)) { @@ -1004,7 +1004,7 @@ class smt2_printer { void del_expr2alias_stack() { std::for_each(m_expr2alias_stack.begin(), m_expr2alias_stack.end(), delete_proc()); m_expr2alias_stack.reset(); - m_expr2alias = 0; + m_expr2alias = nullptr; } void reset_expr2alias_stack() { @@ -1064,7 +1064,7 @@ public: m_manager(env.get_manager()), m_env(env), m_soccs(m_manager), - m_root(0), + m_root(nullptr), m_aliased_pps(fm()), m_next_alias_idx(1), m_format_stack(fm()) { @@ -1092,7 +1092,7 @@ public: void operator()(expr * n, unsigned num, char const * var_prefix, format_ref & r, sbuffer & var_names) { reset_var_names(); - if (var_prefix == 0) + if (var_prefix == nullptr) var_prefix = "x"; if (strcmp(var_prefix, ALIAS_PREFIX) == 0) { var_prefix = "_a"; @@ -1228,7 +1228,7 @@ mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent, unsigned num std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) { smt2_pp_environment_dbg env(p.m_manager); - if (p.m_ast == 0) { + if (p.m_ast == nullptr) { out << "null"; } else if (is_expr(p.m_ast)) { @@ -1263,13 +1263,13 @@ std::ostream& operator<<(std::ostream& out, sort_ref const& e) { std::ostream& operator<<(std::ostream& out, expr_ref_vector const& e) { smt2_pp_environment_dbg env(e.get_manager()); params_ref p; - return ast_smt2_pp(out, e.size(), e.c_ptr(), env, p, 0, 0, 0); + return ast_smt2_pp(out, e.size(), e.c_ptr(), env, p, 0, 0, nullptr); } std::ostream& operator<<(std::ostream& out, app_ref_vector const& e) { smt2_pp_environment_dbg env(e.get_manager()); params_ref p; - return ast_smt2_pp(out, e.size(), (expr*const*)e.c_ptr(), env, p, 0, 0, 0); + return ast_smt2_pp(out, e.size(), (expr*const*)e.c_ptr(), env, p, 0, 0, nullptr); } std::ostream& operator<<(std::ostream& out, func_decl_ref_vector const& e) { diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 041622b74..69b8d67f9 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -98,7 +98,7 @@ void mk_smt2_format(sort * s, smt2_pp_environment & env, params_ref const & p, f void mk_smt2_format(func_decl * f, smt2_pp_environment & env, params_ref const & p, format_ns::format_ref & r); std::ostream & ast_smt2_pp(std::ostream & out, expr * n, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0, - unsigned num_vars = 0, char const * var_prefix = 0); + unsigned num_vars = 0, char const * var_prefix = nullptr); std::ostream & ast_smt2_pp(std::ostream & out, sort * s, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0); std::ostream & ast_smt2_pp(std::ostream & out, func_decl * f, smt2_pp_environment & env, params_ref const & p = params_ref(), unsigned indent = 0); @@ -113,8 +113,8 @@ struct mk_ismt2_pp { unsigned m_indent; unsigned m_num_vars; char const * m_var_prefix; - mk_ismt2_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0); - mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0); + mk_ismt2_pp(ast * t, ast_manager & m, params_ref const & p, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = nullptr); + mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = nullptr); }; std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p); diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index bad4b1984..ace0de2cc 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -702,7 +702,7 @@ class smt_printer { public: smt_printer(std::ostream& out, ast_manager& m, ptr_vector& ql, smt_renaming& rn, - symbol logic, bool no_lets, bool simplify_implies, unsigned indent, unsigned num_var_names = 0, char const* const* var_names = 0) : + symbol logic, bool no_lets, bool simplify_implies, unsigned indent, unsigned num_var_names = 0, char const* const* var_names = nullptr) : m_out(out), m_manager(m), m_qlists(ql), @@ -768,7 +768,7 @@ public: } m_mark.reset(); m_num_lets = 0; - m_top = 0; + m_top = nullptr; } void pp_dt(ast_mark& mark, sort* s) { diff --git a/src/ast/ast_smt_pp.h b/src/ast/ast_smt_pp.h index ac2e33140..71842904c 100644 --- a/src/ast/ast_smt_pp.h +++ b/src/ast/ast_smt_pp.h @@ -76,8 +76,8 @@ public: void set_is_declared(is_declared* id) { m_is_declared = id; } void display_smt2(std::ostream& strm, expr* n); - void display_expr_smt2(std::ostream& strm, expr* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0); - void display_ast_smt2(std::ostream& strm, ast* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0); + void display_expr_smt2(std::ostream& strm, expr* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = nullptr); + void display_ast_smt2(std::ostream& strm, ast* n, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = nullptr); }; @@ -87,7 +87,7 @@ struct mk_smt_pp { unsigned m_indent; unsigned m_num_var_names; char const* const* m_var_names; - mk_smt_pp(ast* e, ast_manager & m, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = 0) : + mk_smt_pp(ast* e, ast_manager & m, unsigned indent = 0, unsigned num_var_names = 0, char const* const* var_names = nullptr) : m_ast(e), m_manager(m), m_indent(indent), m_num_var_names(num_var_names), m_var_names(var_names) {} }; diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index 1bce4bcbe..8d6ebf221 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -108,7 +108,7 @@ void ast_translation::copy_params(decl * d, unsigned rpos, buffer & p void ast_translation::mk_sort(sort * s, frame & fr) { sort_info * si = s->get_info(); sort * new_s; - if (si == 0) { + if (si == nullptr) { // TODO: investigate: this branch is probably unreachable. // It became unreachable after we started using mk_uninterpreted_sort for creating uninterpreted sorts, // and mk_uninterpreted_sort actually creates a user_sort. @@ -139,7 +139,7 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) { sort ** new_domain = reinterpret_cast(m_result_stack.c_ptr() + fr.m_rpos + num_extra); sort * new_range = static_cast(m_result_stack.back()); func_decl * new_f; - if (fi == 0) { + if (fi == nullptr) { new_f = m_to_manager.mk_func_decl(f->get_name(), f->get_arity(), new_domain, @@ -182,7 +182,7 @@ void ast_translation::mk_func_decl(func_decl * f, frame & fr) { } ast * ast_translation::process(ast const * _n) { - if (!_n) return 0; + if (!_n) return nullptr; SASSERT(m_result_stack.empty()); SASSERT(m_frame_stack.empty()); SASSERT(m_extra_children_stack.empty()); @@ -320,7 +320,7 @@ ast * ast_translation::process(ast const * _n) { } expr_dependency * expr_dependency_translation::operator()(expr_dependency * d) { - if (d == 0) + if (d == nullptr) return d; m_buffer.reset(); m_translation.from().linearize(d, m_buffer); diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 68f5b2486..92a539d88 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -38,7 +38,7 @@ app * mk_list_assoc_app(ast_manager & m, func_decl * f, unsigned num_args, expr } app * mk_list_assoc_app(ast_manager & m, family_id fid, decl_kind k, unsigned num_args, expr * const * args) { - func_decl * decl = m.mk_func_decl(fid, k, 0, 0, num_args, args, 0); + func_decl * decl = m.mk_func_decl(fid, k, 0, nullptr, num_args, args, nullptr); SASSERT(decl != 0); SASSERT(decl->is_associative()); return mk_list_assoc_app(m, decl, num_args, args); diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 28c3d5f5d..e3e7c7167 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -34,11 +34,11 @@ bv_decl_plugin::bv_decl_plugin(): m_repeat_sym("repeat"), m_bit2bool_sym("bit2bool"), m_mkbv_sym("mkbv"), - m_bit0(0), - m_bit1(0), - m_carry(0), - m_xor3(0), - m_int_sort(0) { + m_bit0(nullptr), + m_bit1(nullptr), + m_carry(nullptr), + m_xor3(nullptr), + m_int_sort(nullptr) { } void bv_decl_plugin::set_manager(ast_manager * m, family_id id) { @@ -218,7 +218,7 @@ func_decl * bv_decl_plugin::mk_int2bv(unsigned bv_size, unsigned num_parameters, if (arity != 1) { m_manager->raise_exception("expecting one argument to int2bv"); - return 0; + return nullptr; } if (m_int2bv[bv_size] == 0) { @@ -237,7 +237,7 @@ func_decl * bv_decl_plugin::mk_bv2int(unsigned bv_size, unsigned num_parameters, if (arity != 1) { m_manager->raise_exception("expecting one argument to bv2int"); - return 0; + return nullptr; } if (m_bv2int[bv_size] == 0) { @@ -341,7 +341,7 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned bv_size) { case OP_EXT_ROTATE_LEFT: return mk_binary(m_ext_rotate_left, k, "ext_rotate_left", bv_size, false); case OP_EXT_ROTATE_RIGHT: return mk_binary(m_ext_rotate_right, k, "ext_rotate_right", bv_size, false); - default: return 0; + default: return nullptr; } } @@ -417,7 +417,7 @@ bool bv_decl_plugin::get_int2bv_size(unsigned num_parameters, parameter const * func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const * parameters, unsigned arity) { if (!(num_parameters == 2 && arity == 0 && parameters[0].is_rational() && parameters[1].is_int())) { m_manager->raise_exception("invalid bit-vector numeral declaration"); - return 0; + return nullptr; } unsigned bv_size = parameters[1].get_int(); if (bv_size == 0) { @@ -437,7 +437,7 @@ func_decl * bv_decl_plugin::mk_bit2bool(unsigned bv_size, unsigned num_parameter unsigned arity, sort * const * domain) { if (!(num_parameters == 1 && parameters[0].is_int() && arity == 1 && parameters[0].get_int() < static_cast(bv_size))) { m_manager->raise_exception("invalid bit2bool declaration"); - return 0; + return nullptr; } unsigned idx = parameters[0].get_int(); m_bit2bool.reserve(bv_size+1); @@ -455,7 +455,7 @@ func_decl * bv_decl_plugin::mk_mkbv(unsigned arity, sort * const * domain) { for (unsigned i = 0; i < arity; i++) { if (!m_manager->is_bool(domain[i])) { m_manager->raise_exception("invalid mkbv operator"); - return 0; + return nullptr; } } unsigned bv_size = arity; @@ -493,26 +493,26 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p } else if (arity == 0) { m_manager->raise_exception("no arguments supplied to bit-vector operator"); - return 0; + return nullptr; } else if (!get_bv_size(domain[0], bv_size)) { m_manager->raise_exception("could not extract bit-vector size"); - return 0; + return nullptr; } func_decl * r = mk_func_decl(k, bv_size); - if (r != 0) { + if (r != nullptr) { if (arity != r->get_arity()) { if (r->get_info()->is_associative()) arity = r->get_arity(); else { m_manager->raise_exception("declared arity mismatches supplied arity"); - return 0; + return nullptr; } } for (unsigned i = 0; i < arity; ++i) { if (domain[i] != r->get_domain(i)) { m_manager->raise_exception("declared sorts do not match supplied sorts"); - return 0; + return nullptr; } } return r; @@ -565,7 +565,7 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p return m_manager->mk_func_decl(m_repeat_sym, arity, domain, get_bv_sort(bv_size * parameters[0].get_int()), func_decl_info(m_family_id, k, num_parameters, parameters)); default: - return 0; + return nullptr; } } @@ -596,24 +596,24 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p } else if (num_args == 0 || !get_bv_size(args[0], bv_size)) { m.raise_exception("operator is applied to arguments of the wrong sort"); - return 0; + return nullptr; } func_decl * r = mk_func_decl(k, bv_size); - if (r != 0) { + if (r != nullptr) { if (num_args != r->get_arity()) { if (r->get_info()->is_associative()) { sort * fs = r->get_domain(0); for (unsigned i = 0; i < num_args; ++i) { if (m.get_sort(args[i]) != fs) { m_manager->raise_exception("declared sorts do not match supplied sorts"); - return 0; + return nullptr; } } return r; } else { m.raise_exception("declared arity mismatches supplied arity"); - return 0; + return nullptr; } } for (unsigned i = 0; i < num_args; ++i) { @@ -621,7 +621,7 @@ func_decl * bv_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p std::ostringstream buffer; buffer << "Argument " << mk_pp(args[i], m) << " at position " << i << " does not match declaration " << mk_pp(r, m); m.raise_exception(buffer.str().c_str()); - return 0; + return nullptr; } } return r; @@ -747,7 +747,7 @@ 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)) }; - return m_manager->mk_app(m_family_id, OP_BV_NUM, 2, p, 0, 0); + return m_manager->mk_app(m_family_id, OP_BV_NUM, 2, p, 0, nullptr); } rational bv_recognizers::norm(rational const & val, unsigned bv_size, bool is_signed) const { @@ -856,7 +856,7 @@ bv_util::bv_util(ast_manager & m): app * bv_util::mk_numeral(rational const & val, sort* s) const { if (!is_bv_sort(s)) { - return 0; + return nullptr; } unsigned bv_size = get_bv_size(s); return mk_numeral(val, bv_size); @@ -864,7 +864,7 @@ app * bv_util::mk_numeral(rational const & val, sort* s) const { app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const { parameter p[2] = { parameter(val), parameter(static_cast(bv_size)) }; - return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0); + return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, nullptr); } sort * bv_util::mk_sort(unsigned bv_size) { diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 18054ca09..4aff8cd06 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -122,7 +122,7 @@ inline bv_op_kind get_div0_op(bv_op_kind k) { // models the value of "div" it is underspecified (i.e., when the denominator is zero). inline func_decl * get_div0_decl(ast_manager & m, func_decl * decl) { return m.mk_func_decl(decl->get_family_id(), get_div0_op(static_cast(decl->get_decl_kind())), - 0, 0, 1, decl->get_domain()); + 0, nullptr, 1, decl->get_domain()); } class bv_decl_plugin : public decl_plugin { diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 91e636ed7..44752866c 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -157,13 +157,13 @@ namespace datatype { dealloc(kv.m_value); } m_defs.reset(); - m_util = 0; // force deletion + m_util = nullptr; // force deletion } util & plugin::u() const { SASSERT(m_manager); SASSERT(m_family_id != null_family_id); - if (m_util.get() == 0) { + if (m_util.get() == nullptr) { m_util = alloc(util, *m_manager); } return *(m_util.get()); @@ -215,7 +215,7 @@ namespace datatype { sort* s = m_manager->mk_sort(name.get_symbol(), sort_info(m_family_id, k, num_parameters, parameters, true)); - def* d = 0; + def* d = nullptr; if (m_defs.find(s->get_name(), d) && d->sort_size()) { obj_map S; for (unsigned i = 0; i + 1 < num_parameters; ++i) { @@ -233,7 +233,7 @@ namespace datatype { } catch (invalid_datatype) { m_manager->raise_exception("invalid datatype"); - return 0; + return nullptr; } } @@ -245,35 +245,35 @@ namespace datatype { if (num_parameters != 1 || !parameters[0].is_ast()) { m.raise_exception("invalid parameters for datatype field update"); - return 0; + return nullptr; } if (arity != 2) { m.raise_exception("invalid number of arguments for datatype field update"); - return 0; + return nullptr; } - func_decl* acc = 0; + func_decl* acc = nullptr; if (is_func_decl(parameters[0].get_ast())) { acc = to_func_decl(parameters[0].get_ast()); } if (acc && !u().is_accessor(acc)) { - acc = 0; + acc = nullptr; } if (!acc) { m.raise_exception("datatype field update requires a datatype accessor as the second argument"); - return 0; + return nullptr; } sort* dom = acc->get_domain(0); sort* rng = acc->get_range(); if (dom != domain[0]) { m.raise_exception("first argument to field update should be a data-type"); - return 0; + return nullptr; } if (rng != domain[1]) { std::ostringstream buffer; buffer << "second argument to field update should be " << mk_ismt2_pp(rng, m) << " instead of " << mk_ismt2_pp(domain[1], m); m.raise_exception(buffer.str().c_str()); - return 0; + return nullptr; } range = domain[0]; func_decl_info info(m_family_id, k, num_parameters, parameters); @@ -345,7 +345,7 @@ namespace datatype { return mk_update_field(num_parameters, parameters, arity, domain, range); default: m_manager->raise_exception("invalid datatype operator kind"); - return 0; + return nullptr; } } @@ -386,7 +386,7 @@ namespace datatype { bool plugin::mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts) { begin_def_block(); for (unsigned i = 0; i < num_datatypes; ++i) { - def* d = 0; + def* d = nullptr; TRACE("datatype", tout << "declaring " << datatypes[i]->name() << "\n";); if (m_defs.find(datatypes[i]->name(), d)) { TRACE("datatype", tout << "delete previous version for " << datatypes[i]->name() << "\n";); @@ -404,7 +404,7 @@ namespace datatype { } void plugin::remove(symbol const& s) { - def* d = 0; + def* d = nullptr; if (m_defs.find(s, d)) dealloc(d); m_defs.remove(s); } @@ -750,7 +750,7 @@ namespace datatype { ptr_vector const * util::get_datatype_constructors(sort * ty) { SASSERT(is_datatype(ty)); - ptr_vector * r = 0; + ptr_vector * r = nullptr; if (m_datatype2constructors.find(ty, r)) return r; r = alloc(ptr_vector); @@ -768,7 +768,7 @@ namespace datatype { ptr_vector const * util::get_constructor_accessors(func_decl * con) { SASSERT(is_constructor(con)); - ptr_vector * res = 0; + ptr_vector * res = nullptr; if (m_constructor2accessors.find(con, res)) { return res; } @@ -793,7 +793,7 @@ namespace datatype { func_decl * util::get_constructor_recognizer(func_decl * con) { SASSERT(is_constructor(con)); - func_decl * d = 0; + func_decl * d = nullptr; if (m_constructor2recognizer.find(con, d)) return d; sort * datatype = con->get_range(); @@ -848,7 +848,7 @@ namespace datatype { func_decl * util::get_accessor_constructor(func_decl * accessor) { SASSERT(is_accessor(accessor)); - func_decl * r = 0; + func_decl * r = nullptr; if (m_accessor2constructor.find(accessor, r)) return r; sort * datatype = accessor->get_domain(0); @@ -892,10 +892,10 @@ namespace datatype { */ func_decl * util::get_non_rec_constructor(sort * ty) { SASSERT(is_datatype(ty)); - func_decl * r = 0; + func_decl * r = nullptr; if (m_datatype2nonrec_constructor.find(ty, r)) return r; - r = 0; + r = nullptr; ptr_vector forbidden_set; forbidden_set.push_back(ty); TRACE("util_bug", tout << "invoke get-non-rec: " << sort_ref(ty, m) << "\n";); @@ -962,14 +962,14 @@ namespace datatype { func_decl * nested_c = get_non_rec_constructor_core(T_i, forbidden_set); SASSERT(forbidden_set.back() == T_i); forbidden_set.pop_back(); - if (nested_c == 0) + if (nested_c == nullptr) break; TRACE("util_bug", tout << "nested_c: " << nested_c->get_name() << "\n";); } if (i == num_args) return c; } - return 0; + return nullptr; } unsigned util::get_constructor_idx(func_decl * f) const { diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index b61142909..81c2d09a5 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -204,7 +204,7 @@ namespace datatype { m_util(u), m_name(n), m_class_id(class_id), - m_sort_size(0), + m_sort_size(nullptr), m_params(m, num_params, params), m_sort(m) {} @@ -228,7 +228,7 @@ namespace datatype { sort_ref_vector const& params() const { return m_params; } util& u() const { return m_util; } param_size::size* sort_size() { return m_sort_size; } - void set_sort_size(param_size::size* p) { m_sort_size = p; p->inc_ref(); m_sort = 0; } + void set_sort_size(param_size::size* p) { m_sort_size = p; p->inc_ref(); m_sort = nullptr; } def* translate(ast_translation& tr, util& u); }; @@ -398,7 +398,7 @@ typedef datatype::util datatype_util; class type_ref { void * m_data; public: - type_ref():m_data(TAG(void *, static_cast(0), 1)) {} + type_ref():m_data(TAG(void *, nullptr, 1)) {} type_ref(int idx):m_data(BOXINT(void *, idx)) {} type_ref(sort * s):m_data(TAG(void *, s, 1)) {} diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index 1be3c4756..e5b9ed930 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -72,7 +72,7 @@ namespace datalog { for (unsigned i = 0; is_finite && i < num_parameters; ++i) { if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) { m_manager->raise_exception("expecting sort parameters"); - return 0; + return nullptr; } sort* s = to_sort(parameters[i].get_ast()); sort_size sz1 = s->get_num_elements(); @@ -97,16 +97,16 @@ namespace datalog { sort * dl_decl_plugin::mk_finite_sort(unsigned num_params, parameter const* params) { if (num_params != 2) { m_manager->raise_exception("expecting two parameters"); - return 0; + return nullptr; } if (!params[0].is_symbol()) { m_manager->raise_exception("expecting symbol"); - return 0; + return nullptr; } if (!params[1].is_rational() || !params[1].get_rational().is_uint64()) { m_manager->raise_exception("expecting rational"); - return 0; + return nullptr; } sort_size sz = sort_size::mk_finite(params[1].get_rational().get_uint64()); sort_info info(m_family_id, DL_FINITE_SORT, sz, num_params, params); @@ -115,7 +115,7 @@ namespace datalog { sort* dl_decl_plugin::mk_rule_sort() { sort_size sz(sort_size::mk_infinite()); - sort_info info(m_family_id, DL_RULE_SORT, sz, 0, 0); + sort_info info(m_family_id, DL_RULE_SORT, sz, 0, nullptr); return m_manager->mk_sort(m_rule_sym, info); } @@ -130,7 +130,7 @@ namespace datalog { default: UNREACHABLE(); } - return 0; + return nullptr; } bool dl_decl_plugin::is_rel_sort(sort* r) { @@ -173,11 +173,11 @@ namespace datalog { } ptr_vector sorts; if (!is_rel_sort(r, sorts)) { - return 0; + return nullptr; } if (sorts.size() + 1 != arity) { m_manager->raise_exception("wrong arity supplied to relational access"); - return 0; + return nullptr; } for (unsigned i = 0; i < sorts.size(); ++i) { if (sorts[i] != domain[i+1]) { @@ -186,10 +186,10 @@ namespace datalog { mk_pp(sorts[i], m) << "\n" << mk_pp(domain[i+1], m) << "\n";); m_manager->raise_exception("sort miss-match for relational access"); - return 0; + return nullptr; } } - func_decl_info info(m_family_id, k, 0, 0); + func_decl_info info(m_family_id, k, 0, nullptr); return m.mk_func_decl(sym, arity, domain, r, info); } @@ -197,14 +197,14 @@ namespace datalog { ast_manager& m = *m_manager; if (!p.is_ast() || !is_sort(p.get_ast())) { m_manager->raise_exception("expected sort parameter"); - return 0; + return nullptr; } sort* r = to_sort(p.get_ast()); if (!is_rel_sort(r)) { - return 0; + return nullptr; } func_decl_info info(m_family_id, OP_RA_EMPTY, 1, &p); - return m.mk_func_decl(m_empty_sym, 0, (sort*const*)0, r, info); + return m.mk_func_decl(m_empty_sym, 0, (sort*const*)nullptr, r, info); } func_decl* dl_decl_plugin::mk_project(unsigned num_params, parameter const* params, sort* r) { @@ -219,7 +219,7 @@ namespace datalog { tout << "\n"; ); if (!is_rel_sort(r, sorts)) { - return 0; + return nullptr; } SASSERT(sorts.size() >= num_params); // populate ps @@ -227,12 +227,12 @@ namespace datalog { for (; i < num_params; ++i) { if (!params[i].is_int()) { m_manager->raise_exception("expecting integer parameter"); - return 0; + return nullptr; } unsigned k = params[i].get_int(); if (j > k) { m_manager->raise_exception("arguments to projection should be increasing"); - return 0; + return nullptr; } while (j < k) { ps.push_back(parameter(sorts[j])); @@ -253,13 +253,13 @@ namespace datalog { ast_manager& m = *m_manager; if (s1 != s2) { m_manager->raise_exception("sort miss-match for arguments to union"); - return 0; + return nullptr; } if (!is_rel_sort(s1)) { - return 0; + return nullptr; } sort* domain[2] = { s1, s2 }; - func_decl_info info(m_family_id, k, 0, 0); + func_decl_info info(m_family_id, k, 0, nullptr); return m.mk_func_decl(m_union_sym, 2, domain, s1, info); } @@ -267,7 +267,7 @@ namespace datalog { ast_manager& m = *m_manager; ptr_vector sorts; if (!is_rel_sort(r, sorts)) { - return 0; + return nullptr; } if (!p.is_ast() || !is_expr(p.get_ast())) { m_manager->raise_exception("ast expression expected to filter"); @@ -277,7 +277,7 @@ namespace datalog { // 2. the free variables in f correspond to column types of r. if (!m.is_bool(f)) { m_manager->raise_exception("filter predicate should be of Boolean type"); - return 0; + return nullptr; } ptr_vector todo; todo.push_back(f); @@ -295,11 +295,11 @@ namespace datalog { idx = to_var(e)->get_idx(); if (idx >= sorts.size()) { m_manager->raise_exception("illegal index"); - return 0; + return nullptr; } if (sorts[idx] != m.get_sort(e)) { m_manager->raise_exception("sort miss-match in filter"); - return 0; + return nullptr; } break; case AST_APP: @@ -309,10 +309,10 @@ namespace datalog { break; case AST_QUANTIFIER: m_manager->raise_exception("quantifiers are not allowed in filter expressions"); - return 0; + return nullptr; default: m_manager->raise_exception("unexpected filter expression kind"); - return 0; + return nullptr; } } func_decl_info info(m_family_id, OP_RA_FILTER, 1, &p); @@ -322,23 +322,23 @@ namespace datalog { func_decl * dl_decl_plugin::mk_rename(unsigned num_params, parameter const* params, sort* r) { ptr_vector sorts; if (!is_rel_sort(r, sorts)) { - return 0; + return nullptr; } unsigned index0 = 0; - sort* last_sort = 0; + sort* last_sort = nullptr; SASSERT(num_params > 0); for (unsigned i = 0; i < num_params; ++i) { parameter const& p = params[i]; if (!p.is_int()) { m_manager->raise_exception("expected integer parameter"); - return 0; + return nullptr; } unsigned j = p.get_int(); if (j >= sorts.size()) { // We should not use ast_pp anymore on error messages. // m_manager->raise_exception("index %d out of bound %s : %d", j, ast_pp(r, *m_manager).c_str(), sorts.size()); m_manager->raise_exception("index out of bound"); - return 0; + return nullptr; } if (i == 0) { index0 = j; @@ -362,10 +362,10 @@ namespace datalog { vector params2; ptr_vector sorts1, sorts2; if (!is_rel_sort(r1, sorts1)) { - return 0; + return nullptr; } if (!is_rel_sort(r2, sorts2)) { - return 0; + return nullptr; } for (unsigned i = 0; i < sorts1.size(); ++i) { params2.push_back(parameter(sorts1[i])); @@ -375,24 +375,24 @@ namespace datalog { } if (0 != num_params % 2) { m_manager->raise_exception("expecting an even number of parameters to join"); - return 0; + return nullptr; } for (unsigned i = 0; i + 1 < num_params; i += 2) { parameter const& p1 = params[i]; parameter const& p2 = params[i+1]; if (!p1.is_int() || !p2.is_int()) { m_manager->raise_exception("encountered non-integer parameter"); - return 0; + return nullptr; } unsigned i1 = p1.get_int(); unsigned i2 = p2.get_int(); if (i1 >= sorts1.size() || i2 >= sorts2.size()) { m_manager->raise_exception("index out of bounds"); - return 0; + return nullptr; } if (sorts1[i1] != sorts2[i2]) { m_manager->raise_exception("sort miss-match in join"); - return 0; + return nullptr; } } sort* args[2] = { r1, r2 }; @@ -403,40 +403,40 @@ namespace datalog { func_decl* dl_decl_plugin::mk_complement(sort* s) { if (!is_rel_sort(s)) { - return 0; + return nullptr; } - func_decl_info info(m_family_id, OP_RA_COMPLEMENT, 0, 0); + func_decl_info info(m_family_id, OP_RA_COMPLEMENT, 0, nullptr); return m_manager->mk_func_decl(m_complement_sym, 1, &s, s, info); } func_decl * dl_decl_plugin::mk_negation_filter(unsigned num_params, parameter const* params, sort* r1, sort* r2) { ptr_vector sorts1, sorts2; if (!is_rel_sort(r1, sorts1)) { - return 0; + return nullptr; } if (!is_rel_sort(r2, sorts2)) { - return 0; + return nullptr; } if (0 != num_params % 2) { m_manager->raise_exception("expecting an even number of parameters to negation filter"); - return 0; + return nullptr; } for (unsigned i = 0; i + 1 < num_params; i += 2) { parameter const& p1 = params[i]; parameter const& p2 = params[i+1]; if (!p1.is_int() || !p2.is_int()) { m_manager->raise_exception("encountered non-integer parameter"); - return 0; + return nullptr; } unsigned i1 = p1.get_int(); unsigned i2 = p2.get_int(); if (i1 >= sorts1.size() || i2 >= sorts2.size()) { m_manager->raise_exception("index out of bounds"); - return 0; + return nullptr; } if (sorts1[i1] != sorts2[i2]) { m_manager->raise_exception("sort miss-match in join"); - return 0; + return nullptr; } } sort* args[2] = { r1, r2 }; @@ -446,9 +446,9 @@ namespace datalog { func_decl * dl_decl_plugin::mk_is_empty(sort* s) { if (!is_rel_sort(s)) { - return 0; + return nullptr; } - func_decl_info info(m_family_id, OP_RA_IS_EMPTY, 0, 0); + func_decl_info info(m_family_id, OP_RA_IS_EMPTY, 0, nullptr); sort* rng = m_manager->mk_bool_sort(); return m_manager->mk_func_decl(m_is_empty_sym, 1, &s, rng, info); } @@ -458,35 +458,35 @@ namespace datalog { parameter const& ps = params[1]; if (!p.is_rational() || !p.get_rational().is_uint64()) { m_manager->raise_exception("first parameter should be a rational"); - return 0; + return nullptr; } if (!ps.is_ast() || !is_sort(ps.get_ast()) || !is_fin_sort(to_sort(ps.get_ast()))) { m_manager->raise_exception("second parameter should be a finite domain sort"); - return 0; + return nullptr; } sort* s = to_sort(ps.get_ast()); func_decl_info info(m_family_id, OP_DL_CONSTANT, 2, params); - return m_manager->mk_func_decl(m_num_sym, 0, (sort*const*)0, s, info); + return m_manager->mk_func_decl(m_num_sym, 0, (sort*const*)nullptr, s, info); } func_decl * dl_decl_plugin::mk_compare(decl_kind k, symbol const& sym, sort *const* domain) { if (!is_sort_of(domain[0], m_family_id, DL_FINITE_SORT)) { m_manager->raise_exception("expecting finite domain sort"); - return 0; + return nullptr; } if (domain[0] != domain[1]) { m_manager->raise_exception("expecting two identical finite domain sorts"); - return 0; + return nullptr; } - func_decl_info info(m_family_id, k, 0, 0); + func_decl_info info(m_family_id, k, 0, nullptr); return m_manager->mk_func_decl(sym, 2, domain, m_manager->mk_bool_sort(), info); } func_decl * dl_decl_plugin::mk_clone(sort* s) { if (!is_rel_sort(s)) { - return 0; + return nullptr; } - func_decl_info info(m_family_id, OP_RA_CLONE, 0, 0); + func_decl_info info(m_family_id, OP_RA_CLONE, 0, nullptr); return m_manager->mk_func_decl(m_clone_sym, 1, &s, s, info); } @@ -494,14 +494,14 @@ namespace datalog { func_decl * dl_decl_plugin::mk_func_decl( decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { - func_decl* result = 0; + func_decl* result = nullptr; switch(k) { case OP_RA_STORE: case OP_RA_SELECT: if (!check_params(0, 0, num_parameters) || !check_domain(1, UINT_MAX, arity)) { - return 0; + return nullptr; } result = mk_store_select(k, arity, domain); break; @@ -509,7 +509,7 @@ namespace datalog { case OP_RA_EMPTY: if (!check_params( 1, 1, num_parameters) || !check_domain(0, 0, arity)) { - return 0; + return nullptr; } result = mk_empty(parameters[0]); break; @@ -517,7 +517,7 @@ namespace datalog { case OP_RA_JOIN: if (!check_params(0, UINT_MAX, num_parameters) || !check_domain(2, 2, arity)) { - return 0; + return nullptr; } result = mk_join(num_parameters, parameters, domain[0], domain[1]); break; @@ -526,7 +526,7 @@ namespace datalog { case OP_RA_WIDEN: if (!check_params( 0, 0, num_parameters) || !check_domain(2, 2, arity)) { - return 0; + return nullptr; } result = mk_unionw(k, domain[0], domain[1]); break; @@ -534,7 +534,7 @@ namespace datalog { case OP_RA_PROJECT: if (!check_params( 1, UINT_MAX, num_parameters) || !check_domain(1, 1, arity)) { - return 0; + return nullptr; } result = mk_project(num_parameters, parameters, domain[0]); break; @@ -542,7 +542,7 @@ namespace datalog { case OP_RA_FILTER: if (!check_params( 1, 1, num_parameters) || !check_domain(1, 1, arity)) { - return 0; + return nullptr; } result = mk_filter(parameters[0], domain[0]); break; @@ -550,7 +550,7 @@ namespace datalog { case OP_RA_IS_EMPTY: if (!check_params( 0, 0, num_parameters) || !check_domain(1, 1, arity)) { - return 0; + return nullptr; } result = mk_is_empty(domain[0]); break; @@ -558,7 +558,7 @@ namespace datalog { case OP_RA_RENAME: if (!check_params( 2, UINT_MAX, num_parameters) || !check_domain(1, 1, arity)) { - return 0; + return nullptr; } result = mk_rename(num_parameters, parameters, domain[0]); break; @@ -566,7 +566,7 @@ namespace datalog { case OP_RA_COMPLEMENT: if (!check_params( 0, 0, num_parameters) || !check_domain(1, 1, arity)) { - return 0; + return nullptr; } result = mk_complement(domain[0]); break; @@ -574,14 +574,14 @@ namespace datalog { case OP_RA_NEGATION_FILTER: if (!check_params(1, UINT_MAX, num_parameters) || !check_domain(2, 2, arity)) { - return 0; + return nullptr; } result = mk_negation_filter(num_parameters, parameters, domain[0], domain[1]); break; case OP_RA_CLONE: if (!check_params(0, 0, num_parameters) || !check_domain(1, 1, arity)) { - return 0; + return nullptr; } result = mk_clone(domain[0]); break; @@ -589,7 +589,7 @@ namespace datalog { case OP_DL_CONSTANT: if (!check_params( 2, 2, num_parameters) || !check_domain(0, 0, arity)) { - return 0; + return nullptr; } result = mk_constant(parameters); break; @@ -597,23 +597,23 @@ namespace datalog { case OP_DL_LT: if (!check_params( 0, 0, num_parameters) || !check_domain(2, 2, arity)) { - return 0; + return nullptr; } result = mk_compare(OP_DL_LT, m_lt_sym, domain); break; case OP_DL_REP: { if (!check_domain(0, 0, num_parameters) || - !check_domain(1, 1, arity)) return 0; - func_decl_info info(m_family_id, k, 0, 0); + !check_domain(1, 1, arity)) return nullptr; + func_decl_info info(m_family_id, k, 0, nullptr); result = m_manager->mk_func_decl(symbol("rep"), 1, domain, range, info); break; } case OP_DL_ABS: { if (!check_domain(0, 0, num_parameters) || - !check_domain(1, 1, arity)) return 0; - func_decl_info info(m_family_id, k, 0, 0); + !check_domain(1, 1, arity)) return nullptr; + func_decl_info info(m_family_id, k, 0, nullptr); result = m_manager->mk_func_decl(symbol("abs"), 1, domain, range, info); break; } @@ -621,7 +621,7 @@ namespace datalog { default: m_manager->raise_exception("operator not recognized"); - return 0; + return nullptr; } TRACE("dl_decl_plugin", tout << mk_pp(result, *m_manager) << "\n";); @@ -659,7 +659,7 @@ namespace datalog { m.raise_exception("value is out of bounds"); } parameter params[2] = { parameter(rational(value, rational::ui64())), parameter(s) }; - return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)0)); + return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)nullptr)); } if (m_arith.is_int(s) || m_arith.is_real(s)) { return m_arith.mk_numeral(rational(value, rational::ui64()), s); @@ -677,7 +677,7 @@ namespace datalog { std::stringstream strm; strm << "sort '" << mk_pp(s, m) << "' is not recognized as a sort that contains numeric values.\nUse Bool, BitVec, Int, Real, or a Finite domain sort"; m.raise_exception(strm.str().c_str()); - return 0; + return nullptr; } bool dl_decl_util::is_numeral(const expr* e, uint64& v) const { @@ -745,12 +745,12 @@ namespace datalog { app* dl_decl_util::mk_lt(expr* a, expr* b) { expr* args[2] = { a, b }; - return m.mk_app(m_fid, OP_DL_LT, 0, 0, 2, args); + return m.mk_app(m_fid, OP_DL_LT, 0, nullptr, 2, args); } app* dl_decl_util::mk_le(expr* a, expr* b) { expr* args[2] = { b, a }; - return m.mk_not(m.mk_app(m_fid, OP_DL_LT, 0, 0, 2, args)); + return m.mk_not(m.mk_app(m_fid, OP_DL_LT, 0, nullptr, 2, args)); } sort* dl_decl_util::mk_rule_sort() { diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 2c68cc12c..03b9d1fd8 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -204,9 +204,9 @@ namespace datalog { sort* mk_rule_sort(); - app* mk_rule(symbol const& name, unsigned num_args = 0, expr* const* args = 0); + app* mk_rule(symbol const& name, unsigned num_args = 0, expr* const* args = nullptr); - app* mk_fact(symbol const& name) { return mk_rule(name, 0, 0); } + app* mk_fact(symbol const& name) { return mk_rule(name, 0, nullptr); } ast_manager& get_manager() const { return m; } diff --git a/src/ast/expr2polynomial.cpp b/src/ast/expr2polynomial.cpp index 7413624cd..280d7487a 100644 --- a/src/ast/expr2polynomial.cpp +++ b/src/ast/expr2polynomial.cpp @@ -29,7 +29,7 @@ struct expr2polynomial::imp { struct frame { app * m_curr; unsigned m_idx; - frame():m_curr(0), m_idx(0) {} + frame():m_curr(nullptr), m_idx(0) {} frame(app * t):m_curr(t), m_idx(0) {} }; @@ -59,8 +59,8 @@ struct expr2polynomial::imp { m_am(am), m_autil(am), m_pm(pm), - m_expr2var(e2v == 0 && !use_var_idxs ? alloc(expr2var, am) : e2v), - m_expr2var_owner(e2v == 0 && !use_var_idxs), + m_expr2var(e2v == nullptr && !use_var_idxs ? alloc(expr2var, am) : e2v), + m_expr2var_owner(e2v == nullptr && !use_var_idxs), m_var2expr(am), m_cached_domain(am), m_cached_polynomials(pm), @@ -156,7 +156,7 @@ struct expr2polynomial::imp { x = m_wrapper.mk_var(is_int); m_expr2var->insert(t, x); if (x >= m_var2expr.size()) - m_var2expr.resize(x+1, 0); + m_var2expr.resize(x+1, nullptr); m_var2expr.set(x, t); } } @@ -502,7 +502,7 @@ void expr2polynomial::set_cancel(bool f) { } default_expr2polynomial::default_expr2polynomial(ast_manager & am, polynomial::manager & pm): - expr2polynomial(am, pm, 0) { + expr2polynomial(am, pm, nullptr) { } default_expr2polynomial::~default_expr2polynomial() { diff --git a/src/ast/expr2var.cpp b/src/ast/expr2var.cpp index 2f850d645..c6b4257a0 100644 --- a/src/ast/expr2var.cpp +++ b/src/ast/expr2var.cpp @@ -64,7 +64,7 @@ void expr2var::mk_inv(expr_ref_vector & var2expr) const { expr * t = it->m_key; var x = it->m_value; if (x >= var2expr.size()) - var2expr.resize(x+1, 0); + var2expr.resize(x+1, nullptr); var2expr.set(x, t); } } diff --git a/src/ast/expr_abstract.cpp b/src/ast/expr_abstract.cpp index 43035e203..c45e445fd 100644 --- a/src/ast/expr_abstract.cpp +++ b/src/ast/expr_abstract.cpp @@ -27,7 +27,7 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* result = n; return; } - expr * curr = 0, *b = 0; + expr * curr = nullptr, *b = nullptr; SASSERT(n->get_ref_count() > 0); m_stack.push_back(n); diff --git a/src/ast/expr_delta_pair.h b/src/ast/expr_delta_pair.h index f4cc40ae4..f40f4cbe8 100644 --- a/src/ast/expr_delta_pair.h +++ b/src/ast/expr_delta_pair.h @@ -26,7 +26,7 @@ struct expr_delta_pair { expr * m_node; unsigned m_delta; - expr_delta_pair():m_node(0), m_delta(0) {} + expr_delta_pair():m_node(nullptr), m_delta(0) {} expr_delta_pair(expr * n, unsigned d):m_node(n), m_delta(d) {} unsigned hash() const { return hash_u_u(m_node->hash(), m_delta); } bool operator==(const expr_delta_pair & e) const { return m_node == e.m_node && m_delta == e.m_delta; } diff --git a/src/ast/expr_functors.cpp b/src/ast/expr_functors.cpp index 4906ed3d7..cada71ac9 100644 --- a/src/ast/expr_functors.cpp +++ b/src/ast/expr_functors.cpp @@ -121,22 +121,22 @@ void map_proc::reconstruct(app* a) { } if (is_new) { expr* b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr()); - m_map.insert(a, b, 0); + m_map.insert(a, b, nullptr); } else { - m_map.insert(a, a, 0); + m_map.insert(a, a, nullptr); } } void map_proc::visit(quantifier* e) { expr_ref q(m); q = m.update_quantifier(e, get_expr(e->get_expr())); - m_map.insert(e, q, 0); + m_map.insert(e, q, nullptr); } expr* map_proc::get_expr(expr* e) { - expr* result = 0; - proof* p = 0; + expr* result = nullptr; + proof* p = nullptr; m_map.get(e, result, p); return result; } diff --git a/src/ast/expr_functors.h b/src/ast/expr_functors.h index 3d66a69ae..5a4cac477 100644 --- a/src/ast/expr_functors.h +++ b/src/ast/expr_functors.h @@ -115,7 +115,7 @@ public: void reset() { m_map.reset(); } - void visit(var* e) { m_map.insert(e, e, 0); } + void visit(var* e) { m_map.insert(e, e, nullptr); } void visit(quantifier* e); diff --git a/src/ast/expr_map.cpp b/src/ast/expr_map.cpp index 89fcccb00..a9b32f906 100644 --- a/src/ast/expr_map.cpp +++ b/src/ast/expr_map.cpp @@ -38,7 +38,7 @@ expr_map::~expr_map() { void expr_map::insert(expr * k, expr * d, proof * p) { m_manager.inc_ref(d); obj_map::obj_map_entry * entry = m_expr2expr.find_core(k); - if (entry != 0) { + if (entry != nullptr) { m_manager.dec_ref(entry->get_data().m_value); entry->get_data().m_value = d; if (m_store_proofs) { @@ -61,7 +61,7 @@ void expr_map::insert(expr * k, expr * d, proof * p) { void expr_map::get(expr * k, expr * & d, proof * & p) const { if (m_expr2expr.find(k, d)) { - p = 0; + p = nullptr; if (m_store_proofs) m_expr2pr.find(k, p); } @@ -73,7 +73,7 @@ void expr_map::erase(expr * k) { m_expr2expr.erase(k); m_manager.dec_ref(v); if (m_store_proofs) { - proof * pr = 0; + proof * pr = nullptr; m_expr2pr.find(k, pr); m_expr2pr.erase(k); m_manager.dec_ref(pr); diff --git a/src/ast/expr_substitution.cpp b/src/ast/expr_substitution.cpp index f9333c443..e8d75f461 100644 --- a/src/ast/expr_substitution.cpp +++ b/src/ast/expr_substitution.cpp @@ -106,20 +106,20 @@ void expr_substitution::insert(expr * c, expr * def, proof * def_pr, expr_depend void expr_substitution::erase(expr * c) { if (proofs_enabled()) { - proof * pr = 0; + proof * pr = nullptr; if (m_subst_pr->find(c, pr)) { m_manager.dec_ref(pr); m_subst_pr->erase(c); } } if (unsat_core_enabled()) { - expr_dependency * dep = 0; + expr_dependency * dep = nullptr; if (m_subst_dep->find(c, dep)) { m_manager.dec_ref(dep); m_subst_dep->erase(c); } } - expr * def = 0; + expr * def = nullptr; if (m_subst.find(c, def)) { m_manager.dec_ref(c); m_manager.dec_ref(def); diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index 1590f888c..cbe00433c 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -43,7 +43,7 @@ public: bool unsat_core_enabled() const { return m_cores_enabled; } bool empty() const { return m_subst.empty(); } - void insert(expr * s, expr * def, proof * def_pr = 0, expr_dependency * def_dep = 0); + void insert(expr * s, expr * def, proof * def_pr = nullptr, expr_dependency * def_dep = nullptr); void erase(expr * s); bool find(expr * s, expr * & def, proof * & def_pr); bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep); @@ -63,7 +63,7 @@ public: scoped_expr_substitution(expr_substitution& s): m_subst(s), m_trail(s.m()) {} ~scoped_expr_substitution() {} - void insert(expr * s, expr * def, proof * def_pr = 0, expr_dependency * def_dep = 0) { + void insert(expr * s, expr * def, proof * def_pr = nullptr, expr_dependency * def_dep = nullptr) { if (!m_subst.contains(s)) { m_subst.insert(s, def, def_pr, def_dep); m_trail.push_back(s); @@ -82,7 +82,7 @@ public: } unsigned scope_level() const { return m_trail_lim.size(); } bool empty() const { return m_subst.empty(); } - expr* find(expr * e) { proof* pr; expr* d = 0; if (find(e, d, pr)) return d; else return e; } + expr* find(expr * e) { proof* pr; expr* d = nullptr; if (find(e, d, pr)) return d; else return e; } bool find(expr * s, expr * & def, proof * & def_pr) { return m_subst.find(s, def, def_pr); } bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep) { return m_subst.find(s, def, def_pr, def_dep); } bool contains(expr * s) { return m_subst.contains(s); } diff --git a/src/ast/factor_equivs.cpp b/src/ast/factor_equivs.cpp index bbb21c1b2..c33b3a18e 100644 --- a/src/ast/factor_equivs.cpp +++ b/src/ast/factor_equivs.cpp @@ -34,7 +34,7 @@ Revision History: void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv) { ast_manager &m = v.get_manager(); arith_util arith(m); - expr *e1 = 0, *e2 = 0; + expr *e1 = nullptr, *e2 = nullptr; flatten_and(v); unsigned j = 0; @@ -45,7 +45,7 @@ void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv) { } // y + -1*x == 0 - expr* a0 = 0, *a1 = 0, *x = 0; + expr* a0 = nullptr, *a1 = nullptr, *x = nullptr; if (arith.is_zero(e2) && arith.is_add(e1, a0, a1)) { if (arith.is_times_minus_one(a1, x)) { e1 = a0; diff --git a/src/ast/format.cpp b/src/ast/format.cpp index 3013e3e40..40df437ea 100644 --- a/src/ast/format.cpp +++ b/src/ast/format.cpp @@ -42,7 +42,7 @@ namespace format_ns { public: format_decl_plugin(): - m_format_sort(0), + m_format_sort(nullptr), m_nil("nil"), m_string("string"), m_indent("indent"), @@ -94,7 +94,7 @@ namespace format_ns { return m_manager->mk_func_decl(m_line_break_ext, arity, domain, m_format_sort, func_decl_info(m_family_id, OP_LINE_BREAK_EXT, num_parameters, parameters)); default: - return 0; + return nullptr; } } }; @@ -124,8 +124,8 @@ namespace format_ns { SASSERT(m_manager.is_format_manager()); } - format * visit(var *) { UNREACHABLE(); return 0; } - format * visit(quantifier * q, format *, format * const *, format * const *) { UNREACHABLE(); return 0; } + format * visit(var *) { UNREACHABLE(); return nullptr; } + format * visit(quantifier * q, format *, format * const *, format * const *) { UNREACHABLE(); return nullptr; } format * visit(format * n, format * const * children) { if (is_app_of(n, m_fid, OP_LINE_BREAK)) return mk_string(m_manager, " "); @@ -147,7 +147,7 @@ namespace format_ns { format * mk_string(ast_manager & m, char const * str) { symbol s(str); parameter p(s); - return fm(m).mk_app(fid(m), OP_STRING, 1, &p, 0, 0); + return fm(m).mk_app(fid(m), OP_STRING, 1, &p, 0, nullptr); } format * mk_int(ast_manager & m, int i) { diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index d87929864..ede6e43f3 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -198,7 +198,7 @@ expr_ref bv2fpa_converter::rebuild_floats(model_core * mc, sort * s, app * e) { tout << std::endl; ); if (m_fpa_util.is_float(s)) { - if (e == 0) + if (e == nullptr) result = m_fpa_util.mk_pzero(s); else if (m_fpa_util.is_numeral(e)) result = e; @@ -208,7 +208,7 @@ expr_ref bv2fpa_converter::rebuild_floats(model_core * mc, sort * s, app * e) { } } else if (m_fpa_util.is_rm(s)) { - if (e == 0) + if (e == nullptr) result = m_fpa_util.mk_round_toward_zero(); else if (m_fpa_util.is_rm_numeral(e)) result = e; @@ -256,7 +256,7 @@ bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * f, func_decl * bv_f) { SASSERT(f->get_arity() > 0); - func_interp * result = 0; + func_interp * result = nullptr; sort * rng = f->get_range(); sort * const * dmn = f->get_domain(); @@ -291,7 +291,7 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * mk_ismt2_pp(new_args[i], m) << std::endl; tout << mk_ismt2_pp(bv_fres, m) << " == " << mk_ismt2_pp(ft_fres, m) << std::endl;); func_entry * fe = result->get_entry(new_args.c_ptr()); - if (fe == 0) + if (fe == nullptr) result->insert_new_entry(new_args.c_ptr(), ft_fres); else { // The BV model may have multiple equivalent entries using different @@ -338,7 +338,7 @@ void bv2fpa_converter::convert_consts(model_core * mc, model_core * target_model v2 = mc->get_const_interp(a2->get_decl()); #else expr * bv = mc->get_const_interp(to_app(to_app(a0)->get_arg(0))->get_decl()); - if (bv == 0) { + if (bv == nullptr) { v0 = m_bv_util.mk_numeral(0, 1); v1 = m_bv_util.mk_numeral(0, ebits); v2 = m_bv_util.mk_numeral(0, sbits-1); @@ -477,7 +477,7 @@ void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_mode fmv->set_else(m.mk_app(it->m_key, n, args.c_ptr())); #else - fmv->set_else(0); + fmv->set_else(nullptr); #endif target_model->register_decl(f, fmv); } diff --git a/src/ast/fpa/bv2fpa_converter.h b/src/ast/fpa/bv2fpa_converter.h index caf36c1fc..3cb7f4c63 100644 --- a/src/ast/fpa/bv2fpa_converter.h +++ b/src/ast/fpa/bv2fpa_converter.h @@ -64,7 +64,7 @@ public: func_interp * new_float_fi; func_decl * bv_fd; expr_ref result; - array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {} + array_model(ast_manager & m) : new_float_fd(nullptr), new_float_fi(nullptr), bv_fd(nullptr), result(m) {} }; array_model convert_array_func_interp(model_core * mc, func_decl * f, func_decl * bv_f); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index df5d56505..5e7db2ca9 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -197,7 +197,7 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) { #else app_ref bv(m); unsigned bv_sz = 1 + ebits + (sbits - 1); - bv = mk_fresh_const(0, bv_sz); + bv = mk_fresh_const(nullptr, bv_sz); sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv); e = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv); @@ -288,7 +288,7 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) { #ifdef Z3DEBUG "fpa2bv_rm" #else - 0 + nullptr #endif , m_bv_util.mk_sort(3)); @@ -1274,8 +1274,8 @@ expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr std::pair decls(0, 0); if (!m_min_max_ufs.find(f, decls)) { - decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); + decls.first = m.mk_fresh_const(nullptr, m_bv_util.mk_sort(1)); + decls.second = m.mk_fresh_const(nullptr, m_bv_util.mk_sort(1)); m_min_max_ufs.insert(f, decls); m.inc_ref(f); m.inc_ref(decls.first); @@ -2681,11 +2681,11 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con a_tz = m_plugin->mk_numeral(tz); expr_ref bv_nte(m), bv_nta(m), bv_tp(m), bv_tn(m), bv_tz(m); - mk_numeral(a_nte->get_decl(), 0, 0, bv_nte); - mk_numeral(a_nta->get_decl(), 0, 0, bv_nta); - mk_numeral(a_tp->get_decl(), 0, 0, bv_tp); - mk_numeral(a_tn->get_decl(), 0, 0, bv_tn); - mk_numeral(a_tz->get_decl(), 0, 0, bv_tz); + mk_numeral(a_nte->get_decl(), 0, nullptr, bv_nte); + mk_numeral(a_nta->get_decl(), 0, nullptr, bv_nta); + mk_numeral(a_tp->get_decl(), 0, nullptr, bv_tp); + mk_numeral(a_tn->get_decl(), 0, nullptr, bv_tn); + mk_numeral(a_tz->get_decl(), 0, nullptr, bv_tz); expr_ref c1(m), c2(m), c3(m), c4(m); c1 = m.mk_eq(bv_rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)); @@ -4103,7 +4103,7 @@ void fpa2bv_converter::reset(void) { func_decl * fpa2bv_converter::mk_bv_uf(func_decl * f, sort * const * domain, sort * range) { func_decl * res; if (!m_uf2bvuf.find(f, res)) { - res = m.mk_fresh_func_decl(0, f->get_arity(), domain, range); + res = m.mk_fresh_func_decl(nullptr, f->get_arity(), domain, range); m_uf2bvuf.insert(f, res); m.inc_ref(f); m.inc_ref(res); diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 6c96d92c1..2ddc69aaf 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -220,7 +220,7 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q, result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(), new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(), old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns); - result_pr = 0; + result_pr = nullptr; m_bindings.shrink(old_sz); TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " << mk_ismt2_pp(old_q->get_expr(), m()) << std::endl << @@ -249,7 +249,7 @@ bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & res new_exp = m().mk_var(t->get_idx(), s); result = new_exp; - result_pr = 0; + result_pr = nullptr; TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;); return true; } diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 9d298b413..419175a7f 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -23,9 +23,9 @@ Revision History: fpa_decl_plugin::fpa_decl_plugin(): m_values(m_fm), m_value_table(mpf_hash_proc(m_values), mpf_eq_proc(m_values)) { - m_real_sort = 0; - m_int_sort = 0; - m_bv_plugin = 0; + m_real_sort = nullptr; + m_int_sort = nullptr; + m_bv_plugin = nullptr; } void fpa_decl_plugin::set_manager(ast_manager * m, family_id id) { @@ -70,7 +70,7 @@ void fpa_decl_plugin::recycled_id(unsigned id) { func_decl * fpa_decl_plugin::mk_numeral_decl(mpf const & v) { sort * s = mk_float_sort(v.get_ebits(), v.get_sbits()); - func_decl * r = 0; + func_decl * r = nullptr; if (m_fm.is_nan(v)) r = m_manager->mk_const_decl(symbol("NaN"), s, func_decl_info(m_family_id, OP_FPA_NAN)); else if (m_fm.is_pinf(v)) @@ -223,7 +223,7 @@ sort * fpa_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter return mk_float_sort(15, 113); default: m_manager->raise_exception("unknown floating point theory sort"); - return 0; + return nullptr; } } @@ -248,20 +248,20 @@ func_decl * fpa_decl_plugin::mk_rm_const_decl(decl_kind k, unsigned num_paramete return m_manager->mk_const_decl(symbol("roundTowardZero"), s, finfo); default: UNREACHABLE(); - return 0; + return nullptr; } } func_decl * fpa_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { - sort * s = 0; + sort * s = nullptr; if (num_parameters == 1 && parameters[0].is_ast() && is_sort(parameters[0].get_ast()) && is_float_sort(to_sort(parameters[0].get_ast()))) { s = to_sort(parameters[0].get_ast()); } else if (num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()) { s = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); } - else if (range != 0 && is_float_sort(range)) { + else if (range != nullptr && is_float_sort(range)) { s = range; } else { @@ -561,7 +561,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para ); } - return 0; + return nullptr; } func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -779,7 +779,7 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, default: m_manager->raise_exception("unsupported floating point operator"); - return 0; + return nullptr; } } @@ -862,12 +862,12 @@ expr * fpa_decl_plugin::get_some_value(sort * s) { return res; } else if (s->is_sort_of(m_family_id, ROUNDING_MODE_SORT)) { - func_decl * f = mk_rm_const_decl(OP_FPA_RM_TOWARD_ZERO, 0, 0, 0, 0, s); + func_decl * f = mk_rm_const_decl(OP_FPA_RM_TOWARD_ZERO, 0, nullptr, 0, nullptr, s); return m_manager->mk_const(f); } UNREACHABLE(); - return 0; + return nullptr; } bool fpa_decl_plugin::is_value(app * e) const { diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 4d0accfbb..c914bb6c7 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -342,7 +342,7 @@ public: app * mk_bv2rm(expr * bv3) { SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); - return m().mk_app(m_fid, OP_FPA_BV2RM, 0, 0, 1, &bv3, mk_rm_sort()); + return m().mk_app(m_fid, OP_FPA_BV2RM, 0, nullptr, 1, &bv3, mk_rm_sort()); } bool is_bvwrap(expr const * e) const { return is_app_of(e, get_family_id(), OP_FPA_BVWRAP); } diff --git a/src/ast/func_decl_dependencies.cpp b/src/ast/func_decl_dependencies.cpp index a5412f206..2a69f4514 100644 --- a/src/ast/func_decl_dependencies.cpp +++ b/src/ast/func_decl_dependencies.cpp @@ -86,7 +86,7 @@ class func_decl_dependencies::top_sort { ptr_vector m_todo; func_decl_set * definition(func_decl * f) const { - func_decl_set * r = 0; + func_decl_set * r = nullptr; m_deps.find(f, r); return r; } @@ -210,7 +210,7 @@ bool func_decl_dependencies::insert(func_decl * f, func_decl_set * s) { } void func_decl_dependencies::erase(func_decl * f) { - func_decl_set * s = 0; + func_decl_set * s = nullptr; if (m_deps.find(f, s)) { m_manager.dec_ref(f); dec_ref(m_manager, *s); diff --git a/src/ast/func_decl_dependencies.h b/src/ast/func_decl_dependencies.h index 0a3c1892f..b813dc31f 100644 --- a/src/ast/func_decl_dependencies.h +++ b/src/ast/func_decl_dependencies.h @@ -96,7 +96,7 @@ public: */ bool contains(func_decl * f) const { return m_deps.contains(f); } - func_decl_set * get_dependencies(func_decl * f) const { func_decl_set * r = 0; m_deps.find(f, r); return r; } + func_decl_set * get_dependencies(func_decl * f) const { func_decl_set * r = nullptr; m_deps.find(f, r); return r; } /** \brief Erase \c f (and its dependencies) from the manager. diff --git a/src/ast/macro_substitution.cpp b/src/ast/macro_substitution.cpp index 7b4cd6244..a51e1a066 100644 --- a/src/ast/macro_substitution.cpp +++ b/src/ast/macro_substitution.cpp @@ -123,20 +123,20 @@ void macro_substitution::insert(func_decl * f, quantifier * q, proof * pr, expr_ void macro_substitution::erase(func_decl * f) { if (proofs_enabled()) { - proof * pr = 0; + proof * pr = nullptr; if (m_decl2macro_pr->find(f, pr)) { m_manager.dec_ref(pr); m_decl2macro_pr->erase(f); } } if (unsat_core_enabled()) { - expr_dependency * dep = 0; + expr_dependency * dep = nullptr; if (m_decl2macro_dep->find(f, dep)) { m_manager.dec_ref(dep); m_decl2macro_dep->erase(f); } } - quantifier * q = 0; + quantifier * q = nullptr; if (m_decl2macro.find(f, q)) { m_manager.dec_ref(f); m_manager.dec_ref(q); diff --git a/src/ast/macro_substitution.h b/src/ast/macro_substitution.h index 7c65421fd..e028dcef8 100644 --- a/src/ast/macro_substitution.h +++ b/src/ast/macro_substitution.h @@ -45,7 +45,7 @@ public: bool empty() const { return m_decl2macro.empty(); } - void insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep = 0); + void insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep = nullptr); void erase(func_decl * f); bool contains(func_decl * f) { return m_decl2macro.contains(f); } bool find(func_decl * f, quantifier * & q, proof * & pr); diff --git a/src/ast/macros/macro_finder.cpp b/src/ast/macros/macro_finder.cpp index ed067f331..5a46da65a 100644 --- a/src/ast/macros/macro_finder.cpp +++ b/src/ast/macros/macro_finder.cpp @@ -71,7 +71,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, e quantifier_ref new_q(m); new_q = m.update_quantifier(to_quantifier(n), new_body); - proof * new_pr = 0; + proof * new_pr = nullptr; if (m.proofs_enabled()) { proof * rw = m.mk_rewrite(n, new_q); new_pr = m.mk_modus_ponens(pr, rw); @@ -142,7 +142,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, vector& quantifier_ref new_q(m); new_q = m.update_quantifier(to_quantifier(n), new_body); - proof * new_pr = 0; + proof * new_pr = nullptr; if (m.proofs_enabled()) { proof * rw = m.mk_rewrite(n, new_q); new_pr = m.mk_modus_ponens(pr, rw); @@ -163,7 +163,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, vector& quantifier * q1 = m.update_quantifier(new_q, body1); expr * patterns[1] = { m.mk_pattern(k_app) }; quantifier * q2 = m.update_quantifier(new_q, 1, patterns, body2); - proof* pr1 = 0, *pr2 = 0; + proof* pr1 = nullptr, *pr2 = nullptr; if (m.proofs_enabled()) { // new_pr : new_q // rw : [rewrite] new_q ~ q1 & q2 @@ -233,7 +233,7 @@ static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, e app * body_1 = m.mk_eq(head, ite); app * body_2 = m.mk_not(m.mk_eq(k_app, t)); quantifier * q1 = m.update_quantifier(q, body_1); - proof * pr1 = 0, *pr2 = 0; + proof * pr1 = nullptr, *pr2 = nullptr; expr * pats[1] = { m.mk_pattern(k_app) }; quantifier * q2 = m.update_quantifier(q, 1, pats, body_2); // erase patterns if (m.proofs_enabled()) { @@ -268,8 +268,8 @@ bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * con bool found_new_macro = false; for (unsigned i = 0; i < num; i++) { expr * n = exprs[i]; - proof * pr = m.proofs_enabled() ? prs[i] : 0; - expr_dependency * depi = deps != 0 ? deps[i] : 0; + proof * pr = m.proofs_enabled() ? prs[i] : nullptr; + expr_dependency * depi = deps != nullptr ? deps[i] : nullptr; expr_ref new_n(m), def(m); proof_ref new_pr(m); expr_dependency_ref new_dep(m); @@ -292,7 +292,7 @@ bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * con new_exprs.push_back(new_n); if (m.proofs_enabled()) new_prs.push_back(new_pr); - if (deps != 0) + if (deps != nullptr) new_deps.push_back(new_dep); } } @@ -333,11 +333,11 @@ bool macro_finder::expand_macros(unsigned num, justified_expr const * fmls, vect bool found_new_macro = false; for (unsigned i = 0; i < num; i++) { expr * n = fmls[i].get_fml(); - proof * pr = m.proofs_enabled() ? fmls[i].get_proof() : 0; + proof * pr = m.proofs_enabled() ? fmls[i].get_proof() : nullptr; expr_ref new_n(m), def(m); proof_ref new_pr(m); expr_dependency_ref new_dep(m); - m_macro_manager.expand_macros(n, pr, 0, new_n, new_pr, new_dep); + m_macro_manager.expand_macros(n, pr, nullptr, new_n, new_pr, new_dep); app_ref head(m), t(m); if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr)) { TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";); diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index 855cae107..71bdac0a4 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -188,7 +188,7 @@ void macro_manager::display(std::ostream & out) { unsigned sz = m_decls.size(); for (unsigned i = 0; i < sz; i++) { func_decl * f = m_decls.get(i); - quantifier * q = 0; + quantifier * q = nullptr; m_decl2macro.find(f, q); app * head; expr * def; @@ -226,7 +226,7 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return BR_FAILED; } @@ -255,7 +255,7 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { erase_patterns = true; } if (erase_patterns) { - result = m.update_quantifier(old_q, 0, 0, 0, 0, new_body); + result = m.update_quantifier(old_q, 0, nullptr, 0, nullptr, new_body); } return erase_patterns; } @@ -264,13 +264,13 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { if (!is_app(_n)) return false; app * n = to_app(_n); - quantifier * q = 0; + quantifier * q = nullptr; func_decl * d = n->get_decl(); TRACE("macro_manager", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";); if (mm.m_decl2macro.find(d, q)) { TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";); - app * head = 0; - expr * def = 0; + app * head = nullptr; + expr * def = nullptr; mm.get_head_def(q, d, head, def); unsigned num = n->get_num_args(); SASSERT(head && def); @@ -292,14 +292,14 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { expr_ref instance(m); s(q->get_expr(), num, subst_args.c_ptr(), instance); proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr()); - proof * q_pr = 0; + proof * q_pr = nullptr; mm.m_decl2macro_pr.find(d, q_pr); SASSERT(q_pr != 0); proof * prs[2] = { qi_pr, q_pr }; p = m.mk_unit_resolution(2, prs); } else { - p = 0; + p = nullptr; } expr_dependency * ed = mm.m_decl2macro_dep.find(d); m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, ed); diff --git a/src/ast/macros/macro_manager.h b/src/ast/macros/macro_manager.h index 0205fb891..4fcb29f5d 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -67,7 +67,7 @@ public: ~macro_manager(); ast_manager & get_manager() const { return m; } macro_util & get_util() { return m_util; } - bool insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep = 0); + bool insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep = nullptr); bool has_macros() const { return !m_macros.empty(); } void push_scope(); void pop_scope(unsigned num_scopes); @@ -82,7 +82,7 @@ public: unsigned get_first_macro_last_level() const { return m_scopes.empty() ? 0 : m_scopes.back().m_decls_lim; } func_decl * get_macro_func_decl(unsigned i) const { return m_decls.get(i); } func_decl * get_macro_interpretation(unsigned i, expr_ref & interp) const; - quantifier * get_macro_quantifier(func_decl * f) const { quantifier * q = 0; m_decl2macro.find(f, q); return q; } + quantifier * get_macro_quantifier(func_decl * f) const { quantifier * q = nullptr; m_decl2macro.find(f, q); return q; } void get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def) const; void expand_macros(expr * n, proof * pr, expr_dependency * dep, expr_ref & r, proof_ref & new_pr, expr_dependency_ref & new_dep); diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 1ab54d0b5..77290c95f 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -33,8 +33,8 @@ macro_util::macro_util(ast_manager & m): m_arith(m), m_arith_rw(m), m_bv_rw(m), - m_forbidden_set(0), - m_curr_clause(0) { + m_forbidden_set(nullptr), + m_curr_clause(nullptr) { } @@ -256,7 +256,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex inv = false; ptr_buffer args; - expr * h = 0; + expr * h = nullptr; unsigned lhs_num_args; expr * const * lhs_args; if (is_add(lhs)) { @@ -270,13 +270,13 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex for (unsigned i = 0; i < lhs_num_args; i++) { expr * arg = lhs_args[i]; expr * neg_arg; - if (h == 0 && + if (h == nullptr && is_macro_head(arg, num_decls) && !is_forbidden(to_app(arg)->get_decl()) && !poly_contains_head(lhs, to_app(arg)->get_decl(), arg)) { h = arg; } - else if (h == 0 && m_arith_rw.is_times_minus_one(arg, neg_arg) && + else if (h == nullptr && m_arith_rw.is_times_minus_one(arg, neg_arg) && is_macro_head(neg_arg, num_decls) && !is_forbidden(to_app(neg_arg)->get_decl()) && !poly_contains_head(lhs, to_app(neg_arg)->get_decl(), arg)) { @@ -287,7 +287,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex args.push_back(arg); } } - if (h == 0) + if (h == nullptr) return false; head = to_app(h); expr_ref tmp(m_manager); @@ -666,7 +666,7 @@ void macro_util::insert_macro(app * head, unsigned num_decls, expr * def, expr * expr_ref norm_def(m_manager); expr_ref norm_cond(m_manager); normalize_expr(head, num_decls, def, norm_def); - if (cond != 0) + if (cond != nullptr) normalize_expr(head, num_decls, cond, norm_cond); else if (!hint) norm_cond = m_manager.mk_true(); @@ -682,7 +682,7 @@ void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, expr_ref new_cond(m_manager); if (!hint) { quasi_macro_head_to_macro_head(head, num_decls, new_head, extra_cond); - if (cond == 0) + if (cond == nullptr) new_cond = extra_cond; else bool_rewriter(m_manager).mk_and(cond, extra_cond, new_cond); @@ -701,7 +701,7 @@ void macro_util::insert_quasi_macro(app * head, unsigned num_decls, expr * def, } bool macro_util::rest_contains_decl(func_decl * f, expr * except_lit) { - if (m_curr_clause == 0) + if (m_curr_clause == nullptr) return false; SASSERT(is_clause(m_manager, m_curr_clause)); unsigned num_lits = get_clause_num_literals(m_manager, m_curr_clause); @@ -714,7 +714,7 @@ bool macro_util::rest_contains_decl(func_decl * f, expr * except_lit) { } void macro_util::get_rest_clause_as_cond(expr * except_lit, expr_ref & extra_cond) { - if (m_curr_clause == 0) + if (m_curr_clause == nullptr) return; SASSERT(is_clause(m_manager, m_curr_clause)); expr_ref_buffer neg_other_lits(m_manager); @@ -795,7 +795,7 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a mk_sub(rhs, rest, def); // If is_poly_hint, rhs may contain variables that do not occur in to_app(arg). // So, we should re-check. - if (!_is_poly_hint || is_poly_hint(def, to_app(arg), 0)) + if (!_is_poly_hint || is_poly_hint(def, to_app(arg), nullptr)) add_arith_macro_candidate(to_app(arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); } else if (is_times_minus_one(arg, neg_arg) && is_app(neg_arg)) { @@ -816,7 +816,7 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a mk_sub(rest, rhs, def); // If is_poly_hint, rhs may contain variables that do not occur in to_app(neg_arg). // So, we should re-check. - if (!_is_poly_hint || is_poly_hint(def, to_app(neg_arg), 0)) + if (!_is_poly_hint || is_poly_hint(def, to_app(neg_arg), nullptr)) add_arith_macro_candidate(to_app(neg_arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); } } @@ -885,7 +885,7 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, insert_quasi_macro(to_app(lhs), num_decls, rhs, cond, false, true, false, r); } else if (is_hint_atom(lhs, rhs)) { - insert_quasi_macro(to_app(lhs), num_decls, rhs, 0, false, true, true, r); + insert_quasi_macro(to_app(lhs), num_decls, rhs, nullptr, false, true, true, r); } if (is_quasi_macro_head(rhs, num_decls) && @@ -897,7 +897,7 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, insert_quasi_macro(to_app(rhs), num_decls, lhs, cond, false, true, false, r); } else if (is_hint_atom(rhs, lhs)) { - insert_quasi_macro(to_app(rhs), num_decls, lhs, 0, false, true, true, r); + insert_quasi_macro(to_app(rhs), num_decls, lhs, nullptr, false, true, true, r); } } @@ -905,7 +905,7 @@ void macro_util::collect_macro_candidates_core(expr * atom, unsigned num_decls, } void macro_util::collect_macro_candidates(expr * atom, unsigned num_decls, macro_candidates & r) { - m_curr_clause = 0; + m_curr_clause = nullptr; r.reset(); collect_macro_candidates_core(atom, num_decls, r); } @@ -922,7 +922,7 @@ void macro_util::collect_macro_candidates(quantifier * q, macro_candidates & r) unsigned num_lits = get_clause_num_literals(m_manager, n); for (unsigned i = 0; i < num_lits; i++) collect_macro_candidates_core(get_clause_literal(m_manager, n, i), num_decls, r); - m_curr_clause = 0; + m_curr_clause = nullptr; } else { collect_macro_candidates_core(n, num_decls, r); diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index 3ab00df2a..fecdeb97f 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -64,7 +64,7 @@ private: mutable bv_rewriter m_bv_rw; obj_hashtable * m_forbidden_set; - bool is_forbidden(func_decl * f) const { return m_forbidden_set != 0 && m_forbidden_set->contains(f); } + bool is_forbidden(func_decl * f) const { return m_forbidden_set != nullptr && m_forbidden_set->contains(f); } bool poly_contains_head(expr * n, func_decl * f, expr * exception) const; void collect_arith_macros(expr * n, unsigned num_decls, unsigned max_macros, bool allow_cond_macros, diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 7d5e7c3db..afef6c43f 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -281,10 +281,10 @@ bool quasi_macros::find_macros(unsigned n, expr * const * exprs) { quasi_macro_to_macro(to_quantifier(exprs[i]), a, t, macro); TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i], m_manager) << std::endl; tout << "Macro: " << mk_pp(macro, m_manager) << std::endl; ); - proof * pr = 0; + proof * pr = nullptr; if (m_manager.proofs_enabled()) pr = m_manager.mk_def_axiom(macro); - expr_dependency * dep = 0; + expr_dependency * dep = nullptr; if (m_macro_manager.insert(a->get_decl(), macro, pr, dep)) res = true; } @@ -320,7 +320,7 @@ bool quasi_macros::find_macros(unsigned n, justified_expr const * exprs) { quasi_macro_to_macro(to_quantifier(exprs[i].get_fml()), a, t, macro); TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i].get_fml(), m_manager) << std::endl; tout << "Macro: " << mk_pp(macro, m_manager) << std::endl; ); - proof * pr = 0; + proof * pr = nullptr; if (m_manager.proofs_enabled()) pr = m_manager.mk_def_axiom(macro); if (m_macro_manager.insert(a->get_decl(), macro, pr)) @@ -336,7 +336,7 @@ void quasi_macros::apply_macros(unsigned n, expr * const * exprs, proof * const expr_ref r(m_manager), rs(m_manager); proof_ref pr(m_manager), ps(m_manager); expr_dependency_ref dep(m_manager); - proof * p = m_manager.proofs_enabled() ? prs[i] : 0; + proof * p = m_manager.proofs_enabled() ? prs[i] : nullptr; m_macro_manager.expand_macros(exprs[i], p, deps[i], r, pr, dep); m_rewriter(r); @@ -366,9 +366,9 @@ void quasi_macros::apply_macros(unsigned n, justified_expr const* fmls, vectoris_forall()) p = m().mk_skolemization(m().mk_not(q), m().mk_not(r)); @@ -163,8 +163,8 @@ public: void operator()(quantifier * q, expr_ref & r, proof_ref & p) { r = m_cache.find(q); - if (r.get() != 0) { - p = 0; + if (r.get() != nullptr) { + p = nullptr; if (m().proofs_enabled()) p = static_cast(m_cache_pr.find(q)); } @@ -496,7 +496,7 @@ struct nnf::imp { return false; } expr * r = m_result_stack.back(); - proof * pr = 0; + proof * pr = nullptr; if (proofs_enabled()) { pr = m_result_pr_stack.back(); if (!fr.m_pol) { @@ -673,7 +673,7 @@ struct nnf::imp { } expr * arg = m_result_stack.back(); - proof * arg_pr = proofs_enabled() ? m_result_pr_stack.back() : 0; + proof * arg_pr = proofs_enabled() ? m_result_pr_stack.back() : nullptr; if (m_ignore_labels && !proofs_enabled()) return true; // the result is already on the stack @@ -765,7 +765,7 @@ struct nnf::imp { if (q->is_forall() == fr.m_pol || !m_skolemize) { expr * new_expr = m_result_stack.back(); - proof * new_expr_pr = proofs_enabled() ? m_result_pr_stack.back() : 0; + proof * new_expr_pr = proofs_enabled() ? m_result_pr_stack.back() : nullptr; ptr_buffer new_patterns; @@ -783,8 +783,8 @@ struct nnf::imp { // So, ignore patterns } - quantifier * new_q = 0; - proof * new_q_pr = 0; + quantifier * new_q = nullptr; + proof * new_q_pr = nullptr; if (fr.m_pol) { new_q = m().update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(), new_expr); if (proofs_enabled()) @@ -827,7 +827,7 @@ struct nnf::imp { if (proofs_enabled()) { result_pr = m_result_pr_stack.back(); m_result_pr_stack.pop_back(); - if (result_pr.get() == 0) + if (result_pr.get() == nullptr) result_pr = m().mk_reflexivity(t); SASSERT(m_result_pr_stack.empty()); } @@ -870,7 +870,7 @@ struct nnf::imp { if (status) { if (fr.m_cache_result) - cache_result(fr.m_curr, fr.m_pol, fr.m_in_q, m_result_stack.back(), proofs_enabled() ? m_result_pr_stack.back() : 0); + cache_result(fr.m_curr, fr.m_pol, fr.m_in_q, m_result_stack.back(), proofs_enabled() ? m_result_pr_stack.back() : nullptr); m_frame_stack.pop_back(); } } diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index ee618c747..06881f97b 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -85,7 +85,7 @@ struct pull_quant::imp { var_sorts.push_back(nested_q->get_decl_sort(j)); symbol s = nested_q->get_decl_name(j); if (std::find(var_names.begin(), var_names.end(), s) != var_names.end()) - var_names.push_back(m_manager.mk_fresh_var_name(s.is_numerical() ? 0 : s.bare_str())); + var_names.push_back(m_manager.mk_fresh_var_name(s.is_numerical() ? nullptr : s.bare_str())); else var_names.push_back(s); } @@ -215,7 +215,7 @@ struct pull_quant::imp { // Code for proof generation... void pull_quant2(expr * n, expr_ref & r, proof_ref & pr) { - pr = 0; + pr = nullptr; if (is_app(n)) { expr_ref_buffer new_args(m_manager); expr_ref new_arg(m_manager); @@ -231,8 +231,8 @@ struct pull_quant::imp { pull_quant1(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr(), r); if (m_manager.proofs_enabled()) { app * r1 = m_manager.mk_app(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr()); - proof * p1 = proofs.empty() ? 0 : m_manager.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr()); - proof * p2 = r1 == r ? 0 : m_manager.mk_pull_quant(r1, to_quantifier(r)); + proof * p1 = proofs.empty() ? nullptr : m_manager.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr()); + proof * p2 = r1 == r ? nullptr : m_manager.mk_pull_quant(r1, to_quantifier(r)); pr = m_manager.mk_transitivity(p1, p2); } } @@ -242,12 +242,12 @@ struct pull_quant::imp { pull_quant1(to_quantifier(n), new_expr, r); if (m_manager.proofs_enabled()) { quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr); - proof * p1 = 0; + proof * p1 = nullptr; if (n != q1) { proof * p0 = m_manager.mk_pull_quant(n, to_quantifier(new_expr)); p1 = m_manager.mk_quant_intro(to_quantifier(n), q1, p0); } - proof * p2 = q1 == r ? 0 : m_manager.mk_pull_quant(q1, to_quantifier(r)); + proof * p2 = q1 == r ? nullptr : m_manager.mk_pull_quant(q1, to_quantifier(r)); pr = m_manager.mk_transitivity(p1, p2); } } diff --git a/src/ast/pattern/expr_pattern_match.cpp b/src/ast/pattern/expr_pattern_match.cpp index 628c777d3..d688c840c 100644 --- a/src/ast/pattern/expr_pattern_match.cpp +++ b/src/ast/pattern/expr_pattern_match.cpp @@ -83,7 +83,7 @@ expr_pattern_match::instantiate(expr* a, unsigned num_bound, subst& s, expr_ref& inst_proc proc(m_manager, s, b, m_regs); for_each_ast(proc, a); - expr* v = 0; + expr* v = nullptr; proc.m_memoize.find(a, v); SASSERT(v); result = v; diff --git a/src/ast/pattern/expr_pattern_match.h b/src/ast/pattern/expr_pattern_match.h index 6d9d47e1e..d1388b43f 100644 --- a/src/ast/pattern/expr_pattern_match.h +++ b/src/ast/pattern/expr_pattern_match.h @@ -80,7 +80,7 @@ class expr_pattern_match { } void operator()(var* v) { - var* b = 0; + var* b = nullptr; if (m_bound.find(v, b)) { m_memoize.insert(v, b); } @@ -99,7 +99,7 @@ class expr_pattern_match { decl = to_app(m_regs[r])->get_decl(); } for (unsigned i = 0; i < num_args; ++i) { - expr* arg = 0; + expr* arg = nullptr; if (m_memoize.find(n->get_arg(i), arg)) { SASSERT(arg); args.push_back(arg); diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 17d8747f2..704de822c 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -168,7 +168,7 @@ bool pattern_inference_cfg::collect::visit_children(expr * n, unsigned delta) { inline void pattern_inference_cfg::collect::save(expr * n, unsigned delta, info * i) { m_cache.insert(entry(n, delta), i); - if (i != 0) + if (i != nullptr) m_info.push_back(i); } @@ -181,7 +181,7 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { uint_set free_vars; if (idx < m_num_bindings) free_vars.insert(idx); - info * i = 0; + info * i = nullptr; if (delta == 0) i = alloc(info, m, n, free_vars, 1); else @@ -189,7 +189,7 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { save(n, delta, i); } else { - save(n, delta, 0); + save(n, delta, nullptr); } return; } @@ -197,7 +197,7 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { app * c = to_app(n); func_decl * decl = c->get_decl(); if (m_owner.is_forbidden(c)) { - save(n, delta, 0); + save(n, delta, nullptr); return; } @@ -213,14 +213,14 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { unsigned num = c->get_num_args(); for (unsigned i = 0; i < num; i++) { expr * child = c->get_arg(i); - info * child_info = 0; + info * child_info = nullptr; #ifdef Z3DEBUG bool found = #endif m_cache.find(entry(child, delta), child_info); SASSERT(found); - if (child_info == 0) { - save(n, delta, 0); + if (child_info == nullptr) { + save(n, delta, nullptr); return; } buffer.push_back(child_info->m_node.get()); @@ -230,7 +230,7 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { changed = true; } - app * new_node = 0; + app * new_node = nullptr; if (changed) new_node = m.mk_app(decl, buffer.size(), buffer.c_ptr()); else @@ -254,7 +254,7 @@ void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) { return; } default: - save(n, delta, 0); + save(n, delta, nullptr); return; } } @@ -630,7 +630,7 @@ bool pattern_inference_cfg::reduce_quantifier( if (new_patterns.empty() && num_no_patterns > 0) { if (new_patterns.empty()) { - mk_patterns(q->get_num_decls(), new_body, 0, 0, new_patterns); + mk_patterns(q->get_num_decls(), new_body, 0, nullptr, new_patterns); if (m_params.m_pi_warnings && !new_patterns.empty()) { warning_msg("ignoring nopats annotation because Z3 couldn't find any other pattern (quantifier id: %s)", q->get_qid().str().c_str()); } @@ -683,7 +683,7 @@ bool pattern_inference_cfg::reduce_quantifier( pull(new_q, new_expr, new_pr); quantifier * result2 = to_quantifier(new_expr); if (result2 != new_q) { - mk_patterns(result2->get_num_decls(), result2->get_expr(), 0, 0, new_patterns); + mk_patterns(result2->get_num_decls(), result2->get_expr(), 0, nullptr, new_patterns); if (!new_patterns.empty()) { if (m_params.m_pi_warnings) { warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str()); diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h index 905662477..f32dcecd0 100644 --- a/src/ast/pattern/pattern_inference.h +++ b/src/ast/pattern/pattern_inference.h @@ -118,7 +118,7 @@ class pattern_inference_cfg : public default_rewriter_cfg { struct entry { expr * m_node; unsigned m_delta; - entry():m_node(0), m_delta(0) {} + entry():m_node(nullptr), m_delta(0) {} entry(expr * n, unsigned d):m_node(n), m_delta(d) {} unsigned hash() const { return hash_u_u(m_node->get_id(), m_delta); diff --git a/src/ast/pb_decl_plugin.cpp b/src/ast/pb_decl_plugin.cpp index 06c6aac48..57c6a0a8c 100644 --- a/src/ast/pb_decl_plugin.cpp +++ b/src/ast/pb_decl_plugin.cpp @@ -86,7 +86,7 @@ func_decl * pb_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p } default: UNREACHABLE(); - return 0; + return nullptr; } } @@ -299,6 +299,6 @@ bool pb_util::has_unit_coefficients(func_decl* f) const { app* pb_util::mk_fresh_bool() { symbol name = m.mk_fresh_var_name("pb"); - func_decl_info info(m_fid, OP_PB_AUX_BOOL, 0, 0); - return m.mk_const(m.mk_func_decl(name, 0, (sort *const*)0, m.mk_bool_sort(), info)); + func_decl_info info(m_fid, OP_PB_AUX_BOOL, 0, nullptr); + return m.mk_const(m.mk_func_decl(name, 0, (sort *const*)nullptr, m.mk_bool_sort(), info)); } diff --git a/src/ast/pb_decl_plugin.h b/src/ast/pb_decl_plugin.h index e7c42d569..ea4049e13 100644 --- a/src/ast/pb_decl_plugin.h +++ b/src/ast/pb_decl_plugin.h @@ -57,7 +57,7 @@ public: sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override { UNREACHABLE(); - return 0; + return nullptr; } decl_plugin * mk_fresh() override { diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 5126198c6..9ba52a402 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -17,10 +17,10 @@ Copyright (c) 2015 Microsoft Corporation #define SAME_OP(_d1_, _d2_) ((_d1_ == _d2_) || (IS_EQUIV(_d1_) && IS_EQUIV(_d2_))) proof_checker::hyp_decl_plugin::hyp_decl_plugin() : - m_cons(0), - m_atom(0), - m_nil(0), - m_cell(0) { + m_cons(nullptr), + m_atom(nullptr), + m_nil(nullptr), + m_cell(nullptr) { } void proof_checker::hyp_decl_plugin::finalize() { @@ -54,7 +54,7 @@ func_decl * proof_checker::hyp_decl_plugin::mk_func_decl(decl_kind k) { case OP_NIL: return m_nil; default: UNREACHABLE(); - return 0; + return nullptr; } } @@ -739,7 +739,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { // (not (forall ?x (p ?x y))) -> (not (p (sk y) y)) if (match_fact(p, fact) && match_oeq(fact.get(), t1, t2)) { - quantifier* q = 0; + quantifier* q = nullptr; expr* e = t1.get(); bool is_forall = false; if (match_not(t1.get(), s1)) { @@ -823,7 +823,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { premise0 = fmls[0].get(); for (unsigned i = 1; i < fmls.size(); ++i) { expr_ref lit1(m), lit2(m); - expr* lit3 = 0; + expr* lit3 = nullptr; std::pair pos = positions[i-1]; premise1 = fmls[i].get(); set_false(premise0, pos.first, lit1); @@ -1099,7 +1099,7 @@ void proof_checker::get_ors(expr* e, expr_ref_vector& ors) { void proof_checker::get_hypotheses(proof* p, expr_ref_vector& ante) { ptr_vector stack; - expr* h = 0; + expr* h = nullptr; expr_ref hyp(m); stack.push_back(p); @@ -1234,7 +1234,7 @@ bool proof_checker::is_hypothesis(proof* p) const { } expr* proof_checker::mk_hyp(unsigned num_hyps, expr * const * hyps) { - expr* result = 0; + expr* result = nullptr; for (unsigned i = 0; i < num_hyps; ++i) { if (!match_nil(hyps[i])) { if (result) { @@ -1245,7 +1245,7 @@ expr* proof_checker::mk_hyp(unsigned num_hyps, expr * const * hyps) { } } } - if (result == 0) { + if (result == nullptr) { return mk_nil(); } else { diff --git a/src/ast/proofs/proof_utils.cpp b/src/ast/proofs/proof_utils.cpp index 722bfe14e..97213c235 100644 --- a/src/ast/proofs/proof_utils.cpp +++ b/src/ast/proofs/proof_utils.cpp @@ -143,7 +143,7 @@ class reduce_hypotheses { void reduce(proof* pf, proof_ref &out) { - proof *res = NULL; + proof *res = nullptr; m_todo.reset(); m_todo.push_back(pf); @@ -392,7 +392,7 @@ class reduce_hypotheses0 { } void add_hypotheses(proof* p) { - expr_set* hyps = 0; + expr_set* hyps = nullptr; bool inherited = false; if (p->get_decl_kind() == PR_HYPOTHESIS) { hyps = alloc(expr_set); @@ -509,7 +509,7 @@ public: // eliminate hypothesis recursively in the proof of the lemma elim(tmp); expr_set* hyps = m_hypmap.find(tmp); - expr_set* new_hyps = 0; + expr_set* new_hyps = nullptr; // XXX if the proof is correct, the hypotheses of the tmp // XXX should be exactly those of the consequence of the lemma // XXX but if this code actually eliminates hypotheses, the set might be a subset @@ -567,7 +567,7 @@ public: } if (new_hyps && new_hyps->empty()) { dealloc(new_hyps); - new_hyps = 0; + new_hyps = nullptr; } m_hypmap.insert(result, new_hyps); // might push 0 into m_hyprefs. No reason for that @@ -822,7 +822,7 @@ bool proof_utils::is_closed(ast_manager& m, proof* p) { static void permute_unit_resolution(expr_ref_vector& refs, obj_map& cache, proof_ref& pr) { ast_manager& m = pr.get_manager(); - proof* pr2 = 0; + proof* pr2 = nullptr; proof_ref_vector parents(m); proof_ref prNew(pr); if (cache.find(pr, pr2)) { diff --git a/src/ast/recurse_expr_def.h b/src/ast/recurse_expr_def.h index d4f608c5a..b4a83c082 100644 --- a/src/ast/recurse_expr_def.h +++ b/src/ast/recurse_expr_def.h @@ -72,7 +72,7 @@ void recurse_expr::process(expr * n break; case AST_QUANTIFIER: if (IgnorePatterns) { - cache_result(n, this->Visitor::visit(to_quantifier(n), get_cached(to_quantifier(n)->get_expr()), 0, 0)); + cache_result(n, this->Visitor::visit(to_quantifier(n), get_cached(to_quantifier(n)->get_expr()), nullptr, nullptr)); } else { m_results1.reset(); diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index acc3b889f..744c8a235 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -1056,7 +1056,7 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) { numeral a; - expr* x = 0; + expr* x = nullptr; if (m_util.is_numeral(arg, a)) { result = m_util.mk_numeral(floor(a), true); return BR_DONE; @@ -1303,7 +1303,7 @@ expr * arith_rewriter::mk_sin_value(rational const & k) { expr * result = m_util.mk_div(m_util.mk_add(mk_sqrt(rational(6)), mk_sqrt(rational(2))), m_util.mk_numeral(rational(4), false)); return neg ? m_util.mk_uminus(result) : result; } - return 0; + return nullptr; } br_status arith_rewriter::mk_sin_core(expr * arg, expr_ref & result) { @@ -1327,7 +1327,7 @@ br_status arith_rewriter::mk_sin_core(expr * arg, expr_ref & result) { if (is_pi_multiple(arg, k)) { result = mk_sin_value(k); - if (result.get() != 0) + if (result.get() != nullptr) return BR_REWRITE_FULL; } @@ -1386,7 +1386,7 @@ br_status arith_rewriter::mk_cos_core(expr * arg, expr_ref & result) { if (is_pi_multiple(arg, k)) { k = k + rational(1, 2); result = mk_sin_value(k); - if (result.get() != 0) + if (result.get() != nullptr) return BR_REWRITE_FULL; } @@ -1443,7 +1443,7 @@ br_status arith_rewriter::mk_tan_core(expr * arg, expr_ref & result) { if (is_pi_multiple(arg, k)) { expr_ref n(m()), d(m()); n = mk_sin_value(k); - if (n.get() == 0) + if (n.get() == nullptr) goto end; if (is_zero(n)) { result = n; diff --git a/src/ast/rewriter/bit2int.cpp b/src/ast/rewriter/bit2int.cpp index 257740412..a72b73c4d 100644 --- a/src/ast/rewriter/bit2int.cpp +++ b/src/ast/rewriter/bit2int.cpp @@ -273,7 +273,7 @@ void bit2int::visit(app* n) { // bv2int(x) <= z - bv2int(y) -> bv2int(x) + bv2int(y) <= z // - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; expr_ref tmp1(m_manager), tmp2(m_manager); expr_ref tmp3(m_manager); expr_ref pos1(m_manager), neg1(m_manager); diff --git a/src/ast/rewriter/bit2int.h b/src/ast/rewriter/bit2int.h index fbbf2e6d1..048884a94 100644 --- a/src/ast/rewriter/bit2int.h +++ b/src/ast/rewriter/bit2int.h @@ -77,7 +77,7 @@ protected: bool mk_add(expr* e1, expr* e2, expr_ref& result); expr * get_cached(expr * n) const; - bool is_cached(expr * n) const { return get_cached(n) != 0; } + bool is_cached(expr * n) const { return get_cached(n) != nullptr; } void cache_result(expr * n, expr * r); void reset_cache() { m_cache.reset(); } void flush_cache() { m_cache.cleanup(); } diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index c47dacc96..ec9eaaa05 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -200,7 +200,7 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { sort * b = m().mk_bool_sort(); m_out.reset(); for (unsigned i = 0; i < bv_size; i++) { - m_out.push_back(m().mk_fresh_const(0, b)); + m_out.push_back(m().mk_fresh_const(nullptr, b)); } r = mk_mkbv(m_out); m_const2bits.insert(f, r); @@ -342,11 +342,11 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); bits.push_back(m().mk_app(butil().get_family_id(), OP_BIT2BOOL, 1, &p, 1, &t)); } result = mk_mkbv(bits); - result_pr = 0; + result_pr = nullptr; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; TRACE("bit_blaster", tout << f->get_name() << " "; for (unsigned i = 0; i < num; ++i) tout << mk_pp(args[i], m()) << " "; tout << "\n";); @@ -569,7 +569,7 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); if (t->get_idx() >= m_bindings.size()) return false; result = m_bindings.get(m_bindings.size() - t->get_idx() - 1); - result_pr = 0; + result_pr = nullptr; return true; } @@ -616,7 +616,7 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(), new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(), old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns); - result_pr = 0; + result_pr = nullptr; m_bindings.shrink(old_sz); return true; } diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 6e99cb23e..5cf25335b 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -585,7 +585,7 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ */ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) { - expr* cond = 0, *t = 0, *e = 0; + expr* cond = nullptr, *t = nullptr, *e = nullptr; VERIFY(m().is_ite(ite, cond, t, e)); SASSERT(m().is_value(val)); diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index be9799c13..34e03c1ed 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -183,7 +183,7 @@ struct bool_rewriter_cfg : public default_rewriter_cfg { bool flat_assoc(func_decl * f) const { return m_r.flat() && (m_r.m().is_and(f) || m_r.m().is_or(f)); } bool rewrite_patterns() const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; if (f->get_family_id() != m_r.get_fid()) return BR_FAILED; return m_r.mk_app_core(f, num, args, result); diff --git a/src/ast/rewriter/bv_bounds.cpp b/src/ast/rewriter/bv_bounds.cpp index 0a32f8bc2..f337ca638 100644 --- a/src/ast/rewriter/bv_bounds.cpp +++ b/src/ast/rewriter/bv_bounds.cpp @@ -200,7 +200,7 @@ bv_bounds::conv_res bv_bounds::convert(expr * e, vector& nis, bool ne } // v + c1 <= v + c2 - app * v1(NULL), *v2(NULL); + app * v1(nullptr), *v2(nullptr); numeral val1, val2; if (is_constant_add(bv_sz, lhs, v1, val1) && is_constant_add(bv_sz, rhs, v2, val2) @@ -412,7 +412,7 @@ bool bv_bounds::add_constraint(expr* e) { } // v + c1 <= v + c2 - app * v1(NULL), *v2(NULL); + app * v1(nullptr), *v2(nullptr); numeral val1, val2; if (is_constant_add(bv_sz, lhs, v1, val1) && is_constant_add(bv_sz, rhs, v2, val2) @@ -550,8 +550,8 @@ bool bv_bounds::add_neg_bound(app * v, const numeral& a, const numeral& b) { SASSERT(a <= b); intervals_map::obj_map_entry * const e = m_negative_intervals.find_core(v); - intervals * ivs(NULL); - if (e == 0) { + intervals * ivs(nullptr); + if (e == nullptr) { ivs = alloc(intervals); m_negative_intervals.insert(v, ivs); } @@ -621,7 +621,7 @@ bool bv_bounds::is_sat_core(app * v) { if (!has_lower) lower = numeral::zero(); if (!has_upper) upper = (numeral::power_of_two(bv_sz) - one); TRACE("bv_bounds", tout << "is_sat bound:" << lower << "-" << upper << std::endl;); - intervals * negative_intervals(NULL); + intervals * negative_intervals(nullptr); const bool has_neg_intervals = m_negative_intervals.find(v, negative_intervals); bool is_sat(false); numeral new_lo = lower; diff --git a/src/ast/rewriter/bv_bounds.h b/src/ast/rewriter/bv_bounds.h index 775941d1d..fcd173a12 100644 --- a/src/ast/rewriter/bv_bounds.h +++ b/src/ast/rewriter/bv_bounds.h @@ -109,7 +109,7 @@ inline bool bv_bounds::in_range(app *v, const bv_bounds::numeral& n) { inline bool bv_bounds::is_constant_add(unsigned bv_sz, expr * e, app*& v, numeral& val) { SASSERT(e && !v); SASSERT(m_bv_util.get_bv_size(e) == bv_sz); - expr *lhs(NULL), *rhs(NULL); + expr *lhs(nullptr), *rhs(nullptr); if (!m_bv_util.is_bv_add(e, lhs, rhs)) { v = to_app(e); val = rational(0); diff --git a/src/ast/rewriter/bv_elim.cpp b/src/ast/rewriter/bv_elim.cpp index 270d7deb8..0c6484ed6 100644 --- a/src/ast/rewriter/bv_elim.cpp +++ b/src/ast/rewriter/bv_elim.cpp @@ -58,7 +58,7 @@ bool bv_elim_cfg::reduce_quantifier(quantifier * q, _sorts.push_back(m.mk_bool_sort()); _names.push_back(symbol(new_name.str().c_str())); } - bv = m.mk_app(bfid, OP_MKBV, 0, 0, args.size(), args.c_ptr()); + bv = m.mk_app(bfid, OP_MKBV, 0, nullptr, args.size(), args.c_ptr()); _subst_map.push_back(bv.get()); } else { diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index ce35300ca..e327df452 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -630,13 +630,13 @@ unsigned bv_rewriter::propagate_extract(unsigned high, expr * arg, expr_ref & re const bool curr_is_conc = m_util.is_concat(curr); if (curr_is_conc && to_app(curr)->get_num_args() == 0) continue; expr * const curr_first = curr_is_conc ? to_app(curr)->get_arg(0) : curr; - expr * new_first = NULL; + expr * new_first = nullptr; if (is_numeral(curr_first, val, curr_first_sz)) { SASSERT(curr_first_sz >= removable); const unsigned new_num_sz = curr_first_sz - removable; - new_first = new_num_sz ? mk_numeral(val, new_num_sz) : NULL; + new_first = new_num_sz ? mk_numeral(val, new_num_sz) : nullptr; } - expr * new_arg = NULL; + expr * new_arg = nullptr; if (curr_is_conc) { const unsigned conc_num = to_app(curr)->get_num_args(); if (new_first) { @@ -650,7 +650,7 @@ unsigned bv_rewriter::propagate_extract(unsigned high, expr * arg, expr_ref & re expr * const * const old_conc_args = to_app(curr)->get_args(); switch (conc_num) { case 0: UNREACHABLE(); break; - case 1: new_arg = NULL; break; + case 1: new_arg = nullptr; break; case 2: new_arg = to_app(curr)->get_arg(1); break; default: new_arg = m_util.mk_concat(conc_num - 1, old_conc_args + 1); } @@ -1458,10 +1458,10 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re bool fused_extract = false; for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; - expr * prev = 0; + expr * prev = nullptr; if (i > 0) prev = new_args.back(); - if (is_numeral(arg, v1, sz1) && prev != 0 && is_numeral(prev, v2, sz2)) { + if (is_numeral(arg, v1, sz1) && prev != nullptr && is_numeral(prev, v2, sz2)) { v2 *= rational::power_of_two(sz1); v2 += v1; new_args.pop_back(); @@ -1476,7 +1476,7 @@ br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_re expanded = true; } else if (m_util.is_extract(arg) && - prev != 0 && + prev != nullptr && m_util.is_extract(prev) && to_app(arg)->get_arg(0) == to_app(prev)->get_arg(0) && m_util.get_extract_low(prev) == m_util.get_extract_high(arg) + 1) { @@ -1814,7 +1814,7 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r // if (!v1.is_zero() && num_coeffs == num - 1) { // find argument that is not a numeral - expr * t = 0; + expr * t = nullptr; for (unsigned i = 0; i < num; i++) { t = args[i]; if (!is_numeral(t)) @@ -1937,7 +1937,7 @@ br_status bv_rewriter::mk_bv_not(expr * arg, expr_ref & result) { } if (m_bvnot_simpl) { - expr *s(0), *t(0); + expr *s(nullptr), *t(nullptr); if (m_util.is_bv_mul(arg, s, t)) { // ~(-1 * x) --> (x - 1) bv_size = m_util.get_bv_size(s); diff --git a/src/ast/rewriter/bv_trailing.cpp b/src/ast/rewriter/bv_trailing.cpp index 5cdf27574..ad9350eca 100644 --- a/src/ast/rewriter/bv_trailing.cpp +++ b/src/ast/rewriter/bv_trailing.cpp @@ -39,7 +39,7 @@ struct bv_trailing::imp { TRACE("bv-trailing", tout << "ctor\n";); for (unsigned i = 0; i <= TRAILING_DEPTH; ++i) - m_count_cache[i] = NULL; + m_count_cache[i] = nullptr; } virtual ~imp() { @@ -116,7 +116,7 @@ struct bv_trailing::imp { const unsigned sz = m_util.get_bv_size(a); if (to_rm == sz) { - result = NULL; + result = nullptr; return sz; } @@ -155,7 +155,7 @@ struct bv_trailing::imp { const unsigned new_sz = sz - retv; if (!new_sz) { - result = NULL; + result = nullptr; return retv; } @@ -181,7 +181,7 @@ struct bv_trailing::imp { const unsigned num = a->get_num_args(); unsigned retv = 0; unsigned i = num; - expr_ref new_last(NULL, m); + expr_ref new_last(nullptr, m); while (i && retv < n) { i--; expr * const curr = a->get_arg(i); @@ -197,7 +197,7 @@ struct bv_trailing::imp { if (!i && !new_last) {// all args eaten completely SASSERT(retv == m_util.get_bv_size(a)); - result = NULL; + result = nullptr; return retv; } @@ -230,7 +230,7 @@ struct bv_trailing::imp { if (m_util.is_numeral(e, e_val, sz)) { retv = remove_trailing(std::min(n, sz), e_val); const unsigned new_sz = sz - retv; - result = new_sz ? (retv ? m_util.mk_numeral(e_val, new_sz) : e) : NULL; + result = new_sz ? (retv ? m_util.mk_numeral(e_val, new_sz) : e) : nullptr; return retv; } if (m_util.is_bv_mul(e)) @@ -338,7 +338,7 @@ struct bv_trailing::imp { void cache(unsigned depth, expr * e, unsigned min, unsigned max) { SASSERT(depth <= TRAILING_DEPTH); if (depth == 0) return; - if (m_count_cache[depth] == NULL) + if (m_count_cache[depth] == nullptr) m_count_cache[depth] = alloc(map); SASSERT(!m_count_cache[depth]->contains(e)); m.inc_ref(e); @@ -353,10 +353,10 @@ struct bv_trailing::imp { max = m_util.get_bv_size(e); return true; } - if (m_count_cache[depth] == NULL) + if (m_count_cache[depth] == nullptr) return false; const map::obj_map_entry * const oe = m_count_cache[depth]->find_core(e); - if (oe == NULL) return false; + if (oe == nullptr) return false; min = oe->get_data().m_value.first; max = oe->get_data().m_value.second; TRACE("bv-trailing", tout << "cached@" << depth << ": " << mk_ismt2_pp(e, m) << '[' << m_util.get_bv_size(e) << "]\n: " << min << '-' << max << "\n";); @@ -366,7 +366,7 @@ struct bv_trailing::imp { void reset_cache(const unsigned condition) { SASSERT(m_count_cache[0] == NULL); for (unsigned i = 1; i <= TRAILING_DEPTH; ++i) { - if (m_count_cache[i] == NULL) continue; + if (m_count_cache[i] == nullptr) continue; TRACE("bv-trailing", tout << "may reset cache " << i << " " << condition << "\n";); if (condition && m_count_cache[i]->size() < condition) continue; TRACE("bv-trailing", tout << "reset cache " << i << "\n";); @@ -374,7 +374,7 @@ struct bv_trailing::imp { map::iterator end = m_count_cache[i]->end(); for (; it != end; ++it) m.dec_ref(it->m_key); dealloc(m_count_cache[i]); - m_count_cache[i] = NULL; + m_count_cache[i] = nullptr; } } diff --git a/src/ast/rewriter/der.cpp b/src/ast/rewriter/der.cpp index d1fecf2fb..021943585 100644 --- a/src/ast/rewriter/der.cpp +++ b/src/ast/rewriter/der.cpp @@ -118,7 +118,7 @@ bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) { void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) { bool reduced = false; - pr = 0; + pr = nullptr; r = q; TRACE("der", tout << mk_pp(q, m_manager) << "\n";); @@ -149,14 +149,14 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) { void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) { if (!is_forall(q)) { - pr = 0; + pr = nullptr; r = q; return; } expr * e = q->get_expr(); unsigned num_decls = q->get_num_decls(); - var * v = 0; + var * v = nullptr; expr_ref t(m_manager); if (m_manager.is_or(e)) { @@ -211,7 +211,7 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) { r = q; if (m_manager.proofs_enabled()) { - pr = r == q ? 0 : m_manager.mk_der(q, r); + pr = r == q ? nullptr : m_manager.mk_der(q, r); } } @@ -223,7 +223,7 @@ void der_sort_vars(ptr_vector & vars, ptr_vector & definitions, unsig for (unsigned i = 0; i < definitions.size(); i++) { var * v = vars[i]; expr * t = definitions[i]; - if (t == 0 || has_quantifiers(t) || occurs(v, t)) + if (t == nullptr || has_quantifiers(t) || occurs(v, t)) definitions[i] = 0; else found = true; // found at least one candidate @@ -342,7 +342,7 @@ void der::get_elimination_order() { void der::create_substitution(unsigned sz) { m_subst_map.reset(); - m_subst_map.resize(sz, 0); + m_subst_map.resize(sz, nullptr); for(unsigned i = 0; i < m_order.size(); i++) { expr_ref cur(m_map[m_order[i]], m_manager); diff --git a/src/ast/rewriter/distribute_forall.h b/src/ast/rewriter/distribute_forall.h index ab0976945..8bb77d70d 100644 --- a/src/ast/rewriter/distribute_forall.h +++ b/src/ast/rewriter/distribute_forall.h @@ -71,7 +71,7 @@ protected: void reduce1_app(app * a); expr * get_cached(expr * n) const; - bool is_cached(expr * n) const { return get_cached(n) != 0; } + bool is_cached(expr * n) const { return get_cached(n) != nullptr; } void cache_result(expr * n, expr * r); void reset_cache() { m_cache.reset(); } void flush_cache() { m_cache.cleanup(); } diff --git a/src/ast/rewriter/elim_bounds.cpp b/src/ast/rewriter/elim_bounds.cpp index d3240e511..a640081ba 100644 --- a/src/ast/rewriter/elim_bounds.cpp +++ b/src/ast/rewriter/elim_bounds.cpp @@ -44,15 +44,15 @@ elim_bounds_cfg::elim_bounds_cfg(ast_manager & m): It also detects >=, and the atom can be negated. */ bool elim_bounds_cfg::is_bound(expr * n, var * & lower, var * & upper) { - upper = 0; - lower = 0; + upper = nullptr; + lower = nullptr; bool neg = false; if (m.is_not(n)) { n = to_app(n)->get_arg(0); neg = true; } - expr* l = 0, *r = 0; + expr* l = nullptr, *r = nullptr; bool le = false; if (m_util.is_le(n, l, r) && m_util.is_numeral(r)) { n = l; @@ -139,14 +139,14 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q, ptr_buffer candidates; #define ADD_CANDIDATE(V) if (!lowers.contains(V) && !uppers.contains(V)) { candidate_set.insert(V); candidates.push_back(V); } for (expr * a : atoms) { - var * lower = 0; - var * upper = 0; + var * lower = nullptr; + var * upper = nullptr; if (is_bound(a, lower, upper)) { - if (lower != 0 && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { + if (lower != nullptr && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { ADD_CANDIDATE(lower); lowers.insert(lower); } - if (upper != 0 && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { + if (upper != nullptr && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { ADD_CANDIDATE(upper); uppers.insert(upper); } @@ -167,9 +167,9 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q, unsigned j = 0; for (unsigned i = 0; i < atoms.size(); ++i) { expr * a = atoms[i]; - var * lower = 0; - var * upper = 0; - if (is_bound(a, lower, upper) && ((lower != 0 && candidate_set.contains(lower)) || (upper != 0 && candidate_set.contains(upper)))) + var * lower = nullptr; + var * upper = nullptr; + if (is_bound(a, lower, upper) && ((lower != nullptr && candidate_set.contains(lower)) || (upper != nullptr && candidate_set.contains(upper)))) continue; atoms[j] = a; j++; @@ -178,7 +178,7 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q, return false; } atoms.resize(j); - expr * new_body = 0; + expr * new_body = nullptr; switch (atoms.size()) { case 0: result = m.mk_false(); diff --git a/src/ast/rewriter/enum2bv_rewriter.cpp b/src/ast/rewriter/enum2bv_rewriter.cpp index eb6b195f0..814a25ee9 100644 --- a/src/ast/rewriter/enum2bv_rewriter.cpp +++ b/src/ast/rewriter/enum2bv_rewriter.cpp @@ -194,7 +194,7 @@ struct enum2bv_rewriter::imp { q->get_weight(), q->get_qid(), q->get_skid(), q->get_num_patterns(), new_patterns, q->get_num_no_patterns(), new_no_patterns); - result_pr = 0; + result_pr = nullptr; return true; } @@ -226,7 +226,7 @@ struct enum2bv_rewriter::imp { m_enum_bvs(m), m_enum_defs(m), m_num_translated(0), - m_sort_pred(0), + m_sort_pred(nullptr), m_rw(*this, m, p) { } diff --git a/src/ast/rewriter/expr_replacer.cpp b/src/ast/rewriter/expr_replacer.cpp index fb85e3372..c9bf834fd 100644 --- a/src/ast/rewriter/expr_replacer.cpp +++ b/src/ast/rewriter/expr_replacer.cpp @@ -34,7 +34,7 @@ void expr_replacer::operator()(expr * t, expr_ref & result) { struct expr_replacer::scoped_set_subst { expr_replacer & m_r; scoped_set_subst(expr_replacer & r, expr_substitution & s):m_r(r) { m_r.set_substitution(&s); } - ~scoped_set_subst() { m_r.set_substitution(0); } + ~scoped_set_subst() { m_r.set_substitution(nullptr); } }; void expr_replacer::apply_substitution(expr * s, expr * def, proof * def_pr, expr_ref & t) { @@ -58,14 +58,14 @@ struct default_expr_replacer_cfg : public default_rewriter_cfg { default_expr_replacer_cfg(ast_manager & _m): m(_m), - m_subst(0), + m_subst(nullptr), m_used_dependencies(_m) { } bool get_subst(expr * s, expr * & t, proof * & pr) { - if (m_subst == 0) + if (m_subst == nullptr) return false; - expr_dependency * d = 0; + expr_dependency * d = nullptr; if (m_subst->find(s, t, pr, d)) { m_used_dependencies = m.mk_join(m_used_dependencies, d); return true; @@ -98,12 +98,12 @@ public: } void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) override { - result_dep = 0; + result_dep = nullptr; m_replacer.operator()(t, result, result_pr); if (m_cfg.m_used_dependencies != 0) { result_dep = m_cfg.m_used_dependencies; m_replacer.reset(); // reset cache - m_cfg.m_used_dependencies = 0; + m_cfg.m_used_dependencies = nullptr; } } diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index 31453691e..0ed0efc00 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -61,7 +61,7 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { m_args.reset(); bool arg_differs = false; for (unsigned i = 0; i < n; ++i) { - expr* d = 0, *arg = c->get_arg(i); + expr* d = nullptr, *arg = c->get_arg(i); if (m_cache.find(arg, d)) { m_args.push_back(d); arg_differs |= arg != d; diff --git a/src/ast/rewriter/factor_rewriter.h b/src/ast/rewriter/factor_rewriter.h index aae9b05b3..823a8ae69 100644 --- a/src/ast/rewriter/factor_rewriter.h +++ b/src/ast/rewriter/factor_rewriter.h @@ -61,7 +61,7 @@ struct factor_rewriter_cfg : public default_rewriter_cfg { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return m_r.mk_app_core(f, num, args, result); } factor_rewriter_cfg(ast_manager & m):m_r(m) {} diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index e62c9346f..162f9d5c7 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -48,17 +48,17 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_FPA_RM_TOWARD_POSITIVE: case OP_FPA_RM_TOWARD_NEGATIVE: case OP_FPA_RM_TOWARD_ZERO: - SASSERT(num_args == 0); result = m().mk_app(f, (expr * const *)0); st = BR_DONE; break; + SASSERT(num_args == 0); result = m().mk_app(f, (expr * const *)nullptr); st = BR_DONE; break; case OP_FPA_PLUS_INF: case OP_FPA_MINUS_INF: case OP_FPA_NAN: case OP_FPA_PLUS_ZERO: case OP_FPA_MINUS_ZERO: - SASSERT(num_args == 0); result = m().mk_app(f, (expr * const *)0); st = BR_DONE; break; + SASSERT(num_args == 0); result = m().mk_app(f, (expr * const *)nullptr); st = BR_DONE; break; case OP_FPA_NUM: - SASSERT(num_args == 0); result = m().mk_app(f, (expr * const *)0); st = BR_DONE; break; + SASSERT(num_args == 0); result = m().mk_app(f, (expr * const *)nullptr); st = BR_DONE; break; case OP_FPA_ADD: SASSERT(num_args == 3); st = mk_add(args[0], args[1], args[2], result); break; case OP_FPA_SUB: SASSERT(num_args == 3); st = mk_sub(args[0], args[1], args[2], result); break; diff --git a/src/ast/rewriter/inj_axiom.cpp b/src/ast/rewriter/inj_axiom.cpp index d322f3228..184c84144 100644 --- a/src/ast/rewriter/inj_axiom.cpp +++ b/src/ast/rewriter/inj_axiom.cpp @@ -29,9 +29,9 @@ Revision History: */ bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) { expr * n = q->get_expr(); - expr* arg1 = 0, * arg2 = 0, *narg = 0; - expr* app1 = 0, * app2 = 0; - expr* var1 = 0, * var2 = 0; + expr* arg1 = nullptr, * arg2 = nullptr, *narg = nullptr; + expr* app1 = nullptr, * app2 = nullptr; + expr* var1 = nullptr, * var2 = nullptr; if (q->is_forall() && m.is_or(n, arg1, arg2)) { if (m.is_not(arg2)) std::swap(arg1, arg2); @@ -84,7 +84,7 @@ bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) { ptr_buffer decls; buffer names; - expr * var = 0; + expr * var = nullptr; for (unsigned i = 0; i < num; i++) { expr * c = f1->get_arg(i); if (is_var(c)) { diff --git a/src/ast/rewriter/maximize_ac_sharing.cpp b/src/ast/rewriter/maximize_ac_sharing.cpp index a838f59fa..a8bee62d5 100644 --- a/src/ast/rewriter/maximize_ac_sharing.cpp +++ b/src/ast/rewriter/maximize_ac_sharing.cpp @@ -35,7 +35,7 @@ br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr if (std::find(m_kinds.begin(), m_kinds.end(), k) == m_kinds.end()) return BR_FAILED; ptr_buffer _args; - expr * numeral = 0; + expr * numeral = nullptr; if (is_numeral(args[0])) { numeral = args[0]; for (unsigned i = 1; i < num_args; i++) @@ -86,7 +86,7 @@ br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr } num_args = j; if (num_args == 1) { - if (numeral == 0) { + if (numeral == nullptr) { result = _args[0]; } else { diff --git a/src/ast/rewriter/maximize_ac_sharing.h b/src/ast/rewriter/maximize_ac_sharing.h index 7144c7ad3..a36a31101 100644 --- a/src/ast/rewriter/maximize_ac_sharing.h +++ b/src/ast/rewriter/maximize_ac_sharing.h @@ -45,7 +45,7 @@ class maximize_ac_sharing : public default_rewriter_cfg { expr * m_arg1; expr * m_arg2; - entry(func_decl * d = 0, expr * arg1 = 0, expr * arg2 = 0):m_decl(d), m_arg1(arg1), m_arg2(arg2) { + entry(func_decl * d = nullptr, expr * arg1 = nullptr, expr * arg2 = nullptr):m_decl(d), m_arg1(arg1), m_arg2(arg2) { SASSERT((d == 0 && arg1 == 0 && arg2 == 0) || (d != 0 && arg1 != 0 && arg2 != 0)); if (arg1->get_id() > arg2->get_id()) std::swap(m_arg1, m_arg2); diff --git a/src/ast/rewriter/mk_extract_proc.cpp b/src/ast/rewriter/mk_extract_proc.cpp index da22c3b80..e245f3a3d 100644 --- a/src/ast/rewriter/mk_extract_proc.cpp +++ b/src/ast/rewriter/mk_extract_proc.cpp @@ -19,8 +19,8 @@ mk_extract_proc::mk_extract_proc(bv_util & u): m_util(u), m_high(0), m_low(UINT_MAX), - m_domain(0), - m_f_cached(0) { + m_domain(nullptr), + m_f_cached(nullptr) { } mk_extract_proc::~mk_extract_proc() { diff --git a/src/ast/rewriter/mk_simplified_app.cpp b/src/ast/rewriter/mk_simplified_app.cpp index eac26ddc3..9bf460aa9 100644 --- a/src/ast/rewriter/mk_simplified_app.cpp +++ b/src/ast/rewriter/mk_simplified_app.cpp @@ -98,7 +98,7 @@ br_status mk_simplified_app::mk_core(func_decl * decl, unsigned num, expr * cons } void mk_simplified_app::operator()(func_decl * decl, unsigned num, expr * const * args, expr_ref & result) { - result = 0; + result = nullptr; mk_core(decl, num, args, result); if (!result) result = m_imp->m.mk_app(decl, num, args); diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 39d6e2143..0bdeda475 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -403,7 +403,7 @@ struct pb2bv_rewriter::imp { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return m_r.mk_app_core(f, num, args, result); } card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {} diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index 23743399e..c4b120ae5 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -96,7 +96,7 @@ protected: public: poly_rewriter(ast_manager & m, params_ref const & p = params_ref()): Config(m), - m_curr_sort(0), + m_curr_sort(nullptr), m_sort_sums(false) { updt_params(p); SASSERT(!m_som || m_flat); // som of monomials form requires flattening to be enabled. diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 71a9079a0..f27c9ffcf 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -206,7 +206,7 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con numeral c(1); unsigned num_coeffs = 0; unsigned num_add = 0; - expr * var = 0; + expr * var = nullptr; for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; if (is_numeral(arg, a)) { @@ -290,13 +290,13 @@ br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * con if (!m_som || num_add == 0) { ptr_buffer new_args; - expr * prev = 0; + expr * prev = nullptr; bool ordered = true; for (unsigned i = 0; i < num_args; i++) { expr * curr = args[i]; if (is_numeral(curr)) continue; - if (prev != 0 && lt(curr, prev)) + if (prev != nullptr && lt(curr, prev)) ordered = false; new_args.push_back(curr); prev = curr; @@ -532,7 +532,7 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con expr_fast_mark1 visited; // visited.is_marked(power_product) if the power_product occurs in args expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once bool has_multiple = false; - expr * prev = 0; + expr * prev = nullptr; bool ordered = true; for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; @@ -543,7 +543,7 @@ br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * con ordered = !m_sort_sums || i == 0; } else if (m_sort_sums && ordered) { - if (prev != 0 && lt(arg, prev)) + if (prev != nullptr && lt(arg, prev)) ordered = false; prev = arg; } @@ -874,8 +874,8 @@ br_status poly_rewriter::cancel_monomials(expr * lhs, expr * rhs, bool m const bool insert_c_rhs = c_at_rhs && (new_rhs_monomials.size() == 1 || !c.is_zero()); const unsigned lhs_offset = insert_c_lhs ? 0 : 1; const unsigned rhs_offset = insert_c_rhs ? 0 : 1; - new_rhs_monomials[0] = insert_c_rhs ? mk_numeral(c) : NULL; - new_lhs_monomials[0] = insert_c_lhs ? mk_numeral(c) : NULL; + new_rhs_monomials[0] = insert_c_rhs ? mk_numeral(c) : nullptr; + new_lhs_monomials[0] = insert_c_lhs ? mk_numeral(c) : nullptr; lhs_result = mk_add_app(new_lhs_monomials.size() - lhs_offset, new_lhs_monomials.c_ptr() + lhs_offset); rhs_result = mk_add_app(new_rhs_monomials.size() - rhs_offset, new_rhs_monomials.c_ptr() + rhs_offset); TRACE("mk_le_bug", tout << lhs_result << " " << rhs_result << "\n";); @@ -994,7 +994,7 @@ bool poly_rewriter::is_var_plus_ground(expr * n, bool & inv, var * & v, return false; ptr_buffer args; - v = 0; + v = nullptr; expr * curr = to_app(n); bool stop = false; inv = false; @@ -1013,12 +1013,12 @@ bool poly_rewriter::is_var_plus_ground(expr * n, bool & inv, var * & v, args.push_back(arg); } else if (is_var(arg)) { - if (v != 0) + if (v != nullptr) return false; // already found variable v = to_var(arg); } else if (is_times_minus_one(arg, neg_arg) && is_var(neg_arg)) { - if (v != 0) + if (v != nullptr) return false; // already found variable v = to_var(neg_arg); inv = true; @@ -1027,7 +1027,7 @@ bool poly_rewriter::is_var_plus_ground(expr * n, bool & inv, var * & v, return false; // non ground term. } } - if (v == 0) + if (v == nullptr) return false; // did not find variable SASSERT(!args.empty()); mk_add(args.size(), args.c_ptr(), t); diff --git a/src/ast/rewriter/pull_ite_tree.cpp b/src/ast/rewriter/pull_ite_tree.cpp index 651744bf9..61114387c 100644 --- a/src/ast/rewriter/pull_ite_tree.cpp +++ b/src/ast/rewriter/pull_ite_tree.cpp @@ -56,10 +56,10 @@ void pull_ite_tree::reduce(expr * n) { expr * c = to_app(n)->get_arg(0); expr * t_old = to_app(n)->get_arg(1); expr * e_old = to_app(n)->get_arg(2); - expr * t = 0; - proof * t_pr = 0; - expr * e = 0; - proof * e_pr = 0; + expr * t = nullptr; + proof * t_pr = nullptr; + expr * e = nullptr; + proof * e_pr = nullptr; get_cached(t_old, t, t_pr); get_cached(e_old, e, e_pr); expr_ref r(m_manager); @@ -67,7 +67,7 @@ void pull_ite_tree::reduce(expr * n) { r = m_rewriter.mk_app(to_app(n)->get_decl(), 3, args); if (!m_manager.proofs_enabled()) { // expr * r = m_manager.mk_ite(c, t, e); - cache_result(n, r, 0); + cache_result(n, r, nullptr); } else { // t_pr is a proof for (m_p ... t_old ...) == t @@ -83,15 +83,15 @@ void pull_ite_tree::reduce(expr * n) { proof * pr1 = m_manager.mk_rewrite(old, tmp1); // proof for (m_p ... (ite c t_old e_old) ...) = (ite c (m_p ... t_old ...) (m_p ... e_old ...)) expr_ref tmp2(m_manager); tmp2 = m_manager.mk_ite(c, t, e); // (ite c t e) - proof * pr2 = 0; // it will contain a proof for (ite c (m_p ... t_old ...) (m_p ... e_old ...)) = (ite c t e) - proof * pr3 = 0; // it will contain a proof for (m_p ... (ite c t_old e_old) ...) = (ite c t e) + proof * pr2 = nullptr; // it will contain a proof for (ite c (m_p ... t_old ...) (m_p ... e_old ...)) = (ite c t e) + proof * pr3 = nullptr; // it will contain a proof for (m_p ... (ite c t_old e_old) ...) = (ite c t e) proof * proofs[2]; unsigned num_proofs = 0; - if (t_pr != 0) { + if (t_pr != nullptr) { proofs[num_proofs] = t_pr; num_proofs++; } - if (e_pr != 0) { + if (e_pr != nullptr) { proofs[num_proofs] = e_pr; num_proofs++; } @@ -102,8 +102,8 @@ void pull_ite_tree::reduce(expr * n) { else { pr3 = pr1; } - proof * pr4 = 0; // it will contain a proof for (ite c t e) = r - proof * pr5 = 0; // it will contain a proof for (m_p ... (ite c t_old e_old) ...) = r + proof * pr4 = nullptr; // it will contain a proof for (ite c t e) = r + proof * pr5 = nullptr; // it will contain a proof for (m_p ... (ite c t_old e_old) ...) = r if (tmp2 != r) { pr4 = m_manager.mk_rewrite(tmp2, r); pr5 = m_manager.mk_transitivity(pr3, pr4); @@ -120,14 +120,14 @@ void pull_ite_tree::reduce(expr * n) { r = m_rewriter.mk_app(m_p, m_args.size(), m_args.c_ptr()); if (!m_manager.proofs_enabled()) { // expr * r = m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr()); - cache_result(n, r, 0); + cache_result(n, r, nullptr); } else { expr_ref old(m_manager); proof * p; old = mk_p_arg(n); if (old == r) - p = 0; + p = nullptr; else p = m_manager.mk_rewrite(old, r); cache_result(n, r, p); @@ -139,7 +139,7 @@ void pull_ite_tree::operator()(app * n, app_ref & r, proof_ref & pr) { unsigned num_args = n->get_num_args(); m_args.resize(num_args); m_p = n->get_decl(); - expr * ite = 0; + expr * ite = nullptr; for (unsigned i = 0; i < num_args; i++) { expr * arg = n->get_arg(i); if (ite) { @@ -156,7 +156,7 @@ void pull_ite_tree::operator()(app * n, app_ref & r, proof_ref & pr) { } if (!ite) { r = n; - pr = 0; + pr = nullptr; return; } m_todo.push_back(ite); @@ -170,8 +170,8 @@ void pull_ite_tree::operator()(app * n, app_ref & r, proof_ref & pr) { } } SASSERT(is_cached(ite)); - expr * _r = 0; - proof * _pr = 0; + expr * _r = nullptr; + proof * _pr = nullptr; get_cached(ite, _r, _pr); r = to_app(_r); pr = _pr; diff --git a/src/ast/rewriter/push_app_ite.cpp b/src/ast/rewriter/push_app_ite.cpp index f3df4d711..411c61d8e 100644 --- a/src/ast/rewriter/push_app_ite.cpp +++ b/src/ast/rewriter/push_app_ite.cpp @@ -63,7 +63,7 @@ br_status push_app_ite_cfg::reduce_app(func_decl * f, unsigned num, expr * const return BR_FAILED; } app * ite = to_app(args[ite_arg_idx]); - expr * c = 0, * t = 0, * e = 0; + expr * c = nullptr, * t = nullptr, * e = nullptr; VERIFY(m.is_ite(ite, c, t, e)); expr ** args_prime = const_cast(args); expr * old = args_prime[ite_arg_idx]; diff --git a/src/ast/rewriter/rewriter.cpp b/src/ast/rewriter/rewriter.cpp index 36ad2dec4..4356f8f45 100644 --- a/src/ast/rewriter/rewriter.cpp +++ b/src/ast/rewriter/rewriter.cpp @@ -34,11 +34,11 @@ void rewriter_core::init_cache_stack() { void rewriter_core::del_cache_stack() { std::for_each(m_cache_stack.begin(), m_cache_stack.end(), delete_proc()); m_cache_stack.finalize(); - m_cache = 0; + m_cache = nullptr; if (m_proof_gen) { std::for_each(m_cache_pr_stack.begin(), m_cache_pr_stack.end(), delete_proc()); m_cache_pr_stack.finalize(); - m_cache_pr = 0; + m_cache_pr = nullptr; } } @@ -161,7 +161,7 @@ void rewriter_core::elim_reflex_prs(unsigned spos) { unsigned j = spos; for (unsigned i = spos; i < sz; i++) { proof * pr = m_result_pr_stack.get(i); - if (pr != 0) { + if (pr != nullptr) { if (i != j) m_result_pr_stack.set(j, pr); j++; @@ -192,7 +192,7 @@ void rewriter_core::reset() { m_result_stack.reset(); if (m_proof_gen) m_result_pr_stack.reset(); - m_root = 0; + m_root = nullptr; m_num_qvars = 0; m_scopes.reset(); } @@ -201,7 +201,7 @@ void rewriter_core::reset() { void rewriter_core::cleanup() { free_memory(); init_cache_stack(); - m_root = 0; + m_root = nullptr; m_num_qvars = 0; } diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 5a3b930c8..658fb2e05 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -28,11 +28,11 @@ void rewriter_tpl::process_var(var * v) { SASSERT(v->get_sort() == m().get_sort(m_r)); if (ProofGen) { result_pr_stack().push_back(m_pr); - m_pr = 0; + m_pr = nullptr; } set_new_child_flag(v); TRACE("rewriter", tout << mk_ismt2_pp(v, m()) << " -> " << m_r << "\n";); - m_r = 0; + m_r = nullptr; return; } if (!ProofGen) { @@ -41,7 +41,7 @@ void rewriter_tpl::process_var(var * v) { if (idx < m_bindings.size()) { unsigned index = m_bindings.size() - idx - 1; var * r = (var*)(m_bindings[index]); - if (r != 0) { + if (r != nullptr) { CTRACE("rewriter", v->get_sort() != m().get_sort(r), tout << expr_ref(v, m()) << ":" << sort_ref(v->get_sort(), m()) << " != " << expr_ref(r, m()) << ":" << sort_ref(m().get_sort(r), m()); tout << "index " << index << " bindings " << m_bindings.size() << "\n"; @@ -67,14 +67,14 @@ void rewriter_tpl::process_var(var * v) { } result_stack().push_back(v); if (ProofGen) - result_pr_stack().push_back(0); // implicit reflexivity + result_pr_stack().push_back(nullptr); // implicit reflexivity } template template void rewriter_tpl::process_const(app * t) { SASSERT(t->get_num_args() == 0); - br_status st = m_cfg.reduce_app(t->get_decl(), 0, 0, m_r, m_pr); + br_status st = m_cfg.reduce_app(t->get_decl(), 0, nullptr, m_r, m_pr); SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t)); SASSERT(st == BR_FAILED || st == BR_DONE); if (st == BR_DONE) { @@ -84,15 +84,15 @@ void rewriter_tpl::process_const(app * t) { result_pr_stack().push_back(m_pr); else result_pr_stack().push_back(m().mk_rewrite(t, m_r)); - m_pr = 0; + m_pr = nullptr; } - m_r = 0; + m_r = nullptr; set_new_child_flag(t); } else { result_stack().push_back(t); if (ProofGen) - result_pr_stack().push_back(0); // implicit reflexivity + result_pr_stack().push_back(nullptr); // implicit reflexivity } } @@ -108,8 +108,8 @@ template template bool rewriter_tpl::visit(expr * t, unsigned max_depth) { TRACE("rewriter_visit", tout << "visiting\n" << mk_ismt2_pp(t, m()) << "\n";); - expr * new_t = 0; - proof * new_t_pr = 0; + expr * new_t = nullptr; + proof * new_t_pr = nullptr; if (m_cfg.get_subst(t, new_t, new_t_pr)) { TRACE("rewriter_subst", tout << "subst\n" << mk_ismt2_pp(t, m()) << "\n---->\n" << mk_ismt2_pp(new_t, m()) << "\n";); SASSERT(m().get_sort(t) == m().get_sort(new_t)); @@ -122,7 +122,7 @@ bool rewriter_tpl::visit(expr * t, unsigned max_depth) { if (max_depth == 0) { result_stack().push_back(t); if (ProofGen) - result_pr_stack().push_back(0); // implicit reflexivity + result_pr_stack().push_back(nullptr); // implicit reflexivity return true; // t is not going to be processed } SASSERT(max_depth > 0); @@ -150,7 +150,7 @@ bool rewriter_tpl::visit(expr * t, unsigned max_depth) { if (!pre_visit(t)) { result_stack().push_back(t); if (ProofGen) - result_pr_stack().push_back(0); // implicit reflexivity + result_pr_stack().push_back(nullptr); // implicit reflexivity return true; // t is not going to be processed } switch (t->get_kind()) { @@ -183,7 +183,7 @@ template bool rewriter_tpl::constant_fold(app * t, frame & fr) { if (fr.m_i == 1 && m().is_ite(t)) { expr * cond = result_stack()[fr.m_spos].get(); - expr* arg = 0; + expr* arg = nullptr; if (m().is_true(cond)) { arg = t->get_arg(1); } @@ -203,7 +203,7 @@ bool rewriter_tpl::constant_fold(app * t, frame & fr) { frame_stack().pop_back(); set_new_child_flag(t); } - m_r = 0; + m_r = nullptr; return true; } } @@ -255,7 +255,7 @@ void rewriter_tpl::process_app(app * t, frame & fr) { unsigned num_prs = result_pr_stack().size() - fr.m_spos; if (num_prs == 0) { new_t = t; - m_pr = 0; + m_pr = nullptr; } else { new_t = m().mk_app(f, new_num_args, new_args); @@ -278,16 +278,16 @@ void rewriter_tpl::process_app(app * t, frame & fr) { if (!m_pr2) m_pr2 = m().mk_rewrite(new_t, m_r); m_pr = m().mk_transitivity(m_pr, m_pr2); - m_pr2 = 0; + m_pr2 = nullptr; result_pr_stack().push_back(m_pr); } if (st == BR_DONE) { cache_result(t, m_r, m_pr, fr.m_cache_result); frame_stack().pop_back(); set_new_child_flag(t); - m_r = 0; + m_r = nullptr; if (ProofGen) - m_pr = 0; + m_pr = nullptr; return; } else { @@ -318,16 +318,16 @@ void rewriter_tpl::process_app(app * t, frame & fr) { cache_result(t, m_r, m_pr, fr.m_cache_result); frame_stack().pop_back(); set_new_child_flag(t); - m_r = 0; + m_r = nullptr; if (ProofGen) - m_pr = 0; + m_pr = nullptr; return; } else { // frame was created for processing m_r - m_r = 0; + m_r = nullptr; if (ProofGen) - m_pr = 0; + m_pr = nullptr; return; } } @@ -407,11 +407,11 @@ void rewriter_tpl::process_app(app * t, frame & fr) { if (ProofGen) { result_pr_stack().shrink(fr.m_spos); result_pr_stack().push_back(m_pr); - m_pr = 0; + m_pr = nullptr; } frame_stack().pop_back(); set_new_child_flag(t, m_r); - m_r = 0; + m_r = nullptr; return; } case REWRITE_BUILTIN: @@ -514,7 +514,7 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { } if (ProofGen) { quantifier_ref new_q(m().update_quantifier(q, num_pats, new_pats.c_ptr(), num_no_pats, new_no_pats.c_ptr(), new_body), m()); - m_pr = q == new_q ? 0 : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos)); + m_pr = q == new_q ? nullptr : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos)); m_r = new_q; proof_ref pr2(m()); if (m_cfg.reduce_quantifier(new_q, new_body, new_pats.c_ptr(), new_no_pats.c_ptr(), m_r, pr2)) { @@ -550,9 +550,9 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { } else { cache_result(q, m_r, m_pr, fr.m_cache_result); - m_pr = 0; + m_pr = nullptr; } - m_r = 0; + m_r = nullptr; frame_stack().pop_back(); set_new_child_flag(q, m_r); } @@ -656,7 +656,7 @@ void rewriter_tpl::main_loop(expr * t, expr_ref & result, proof_ref & re if (ProofGen) { result_pr = result_pr_stack().back(); result_pr_stack().pop_back(); - if (result_pr.get() == 0) + if (result_pr.get() == nullptr) result_pr = m().mk_reflexivity(t); SASSERT(result_pr_stack().empty()); } @@ -721,7 +721,7 @@ void rewriter_tpl::resume_core(expr_ref & result, proof_ref & result_pr) if (ProofGen) { result_pr = result_pr_stack().back(); result_pr_stack().pop_back(); - if (result_pr.get() == 0) + if (result_pr.get() == nullptr) result_pr = m().mk_reflexivity(m_root); SASSERT(result_pr_stack().empty()); } diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 5fb85d6bb..387e5d6f2 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -190,7 +190,7 @@ public: }*/ }; -re2automaton::re2automaton(ast_manager& m): m(m), u(m), bv(m), m_ba(0), m_sa(0) {} +re2automaton::re2automaton(ast_manager& m): m(m), u(m), bv(m), m_ba(nullptr), m_sa(nullptr) {} re2automaton::~re2automaton() {} @@ -288,7 +288,7 @@ eautomaton* re2automaton::re2aut(expr* e) { } else if (u.re.is_full_seq(e)) { expr_ref tt(m.mk_true(), m); - sort *seq_s = 0, *char_s = 0; + sort *seq_s = nullptr, *char_s = nullptr; VERIFY (u.is_re(m.get_sort(e), seq_s)); VERIFY (u.is_seq(seq_s, char_s)); sym_expr* _true = sym_expr::mk_pred(tt, char_s); @@ -296,7 +296,7 @@ eautomaton* re2automaton::re2aut(expr* e) { } else if (u.re.is_full_char(e)) { expr_ref tt(m.mk_true(), m); - sort *seq_s = 0, *char_s = 0; + sort *seq_s = nullptr, *char_s = nullptr; VERIFY (u.is_re(m.get_sort(e), seq_s)); VERIFY (u.is_seq(seq_s, char_s)); sym_expr* _true = sym_expr::mk_pred(tt, char_s); @@ -307,7 +307,7 @@ eautomaton* re2automaton::re2aut(expr* e) { return m_sa->mk_product(*a, *b); } - return 0; + return nullptr; } eautomaton* re2automaton::seq2aut(expr* e) { @@ -335,7 +335,7 @@ eautomaton* re2automaton::seq2aut(expr* e) { } return alloc(eautomaton, sm, init, final, mvs); } - return 0; + return nullptr; } br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { @@ -993,14 +993,14 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { bool isc1 = false; bool isc2 = false; - expr *a1 = 0, *a2 = 0, *b1 = 0, *b2 = 0; + expr *a1 = nullptr, *a2 = nullptr, *b1 = nullptr, *b2 = nullptr; if (m_util.str.is_concat(a, a1, a2) && m_util.str.is_string(a2, s1)) { isc1 = true; } else if (m_util.str.is_string(a, s1)) { isc1 = true; a2 = a; - a1 = 0; + a1 = nullptr; } if (m_util.str.is_concat(b, b1, b2) && m_util.str.is_string(b2, s2)) { @@ -1009,7 +1009,7 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { else if (m_util.str.is_string(b, s2)) { isc2 = true; b2 = b; - b1 = 0; + b1 = nullptr; } if (isc1 && isc2) { if (s1.length() == s2.length()) { @@ -1019,7 +1019,7 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { } else if (s1.length() < s2.length()) { bool suffix = s1.suffixof(s2); - if (suffix && a1 == 0) { + if (suffix && a1 == nullptr) { result = m().mk_true(); return BR_DONE; } @@ -1036,7 +1036,7 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { } else { SASSERT(s1.length() > s2.length()); - if (b1 == 0) { + if (b1 == nullptr) { result = m().mk_false(); return BR_DONE; } @@ -1475,13 +1475,13 @@ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) { return BR_DONE; } if (m_util.re.is_full_char(a)) { - sort* seq_sort = 0; + sort* seq_sort = nullptr; VERIFY(m_util.is_re(a, seq_sort)); result = m_util.re.mk_full_seq(seq_sort); return BR_DONE; } if (m_util.re.is_empty(a)) { - sort* seq_sort = 0; + sort* seq_sort = nullptr; VERIFY(m_util.is_re(a, seq_sort)); result = m_util.re.mk_to_re(m_util.str.mk_empty(seq_sort)); return BR_DONE; @@ -1559,7 +1559,7 @@ br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) { } br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) { - sort* s = 0; + sort* s = nullptr; VERIFY(m_util.is_re(a, s)); result = m_util.re.mk_union(m_util.re.mk_to_re(m_util.str.mk_empty(s)), a); return BR_REWRITE1; @@ -1883,7 +1883,7 @@ expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) { bool seq_rewriter::set_empty(unsigned sz, expr* const* es, bool all, expr_ref_vector& lhs, expr_ref_vector& rhs) { zstring s; - expr* emp = 0; + expr* emp = nullptr; for (unsigned i = 0; i < sz; ++i) { if (m_util.str.is_unit(es[i])) { if (all) return false; diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index a2ca12b24..f5a0ff0f7 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -440,8 +440,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg { } if (num1 != num2 && num1 != num2 + 1 && num1 != num2 - 1) return false; - new_t1 = 0; - new_t2 = 0; + new_t1 = nullptr; + new_t2 = nullptr; expr_fast_mark1 visited1; expr_fast_mark2 visited2; for (unsigned i = 0; i < num1; i++) { @@ -533,7 +533,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr * c = args[0]; expr * t = args[1]; expr * e = args[2]; - func_decl * f_prime = 0; + func_decl * f_prime = nullptr; expr_ref new_t(m()), new_e(m()), common(m()); bool first; TRACE("push_ite", tout << "unifying:\n" << mk_ismt2_pp(t, m()) << "\n" << mk_ismt2_pp(e, m()) << "\n";); @@ -559,7 +559,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; br_status st = reduce_app_core(f, num, args, result); if (st != BR_DONE && st != BR_FAILED) { CTRACE("th_rewriter_step", st != BR_FAILED, @@ -604,7 +604,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { expr_ref & result, proof_ref & result_pr) { quantifier_ref q1(m()); - proof * p1 = 0; + proof * p1 = nullptr; if (is_quantifier(new_body) && to_quantifier(new_body)->is_forall() == old_q->is_forall() && !old_q->has_patterns() && @@ -627,7 +627,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { std::min(old_q->get_weight(), nested_q->get_weight()), old_q->get_qid(), old_q->get_skid(), - 0, 0, 0, 0); + 0, nullptr, 0, nullptr); SASSERT(is_well_sorted(m(), q1)); @@ -657,9 +657,9 @@ struct th_rewriter_cfg : public default_rewriter_cfg { TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m()) << "\n";); - result_pr = 0; + result_pr = nullptr; if (m().proofs_enabled()) { - proof * p2 = 0; + proof * p2 = nullptr; if (q1.get() != result.get()) p2 = m().mk_elim_unused_vars(q1, result); result_pr = m().mk_transitivity(p1, p2); @@ -680,7 +680,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { m_a_util(m), m_bv_util(m), m_used_dependencies(m), - m_subst(0) { + m_subst(nullptr) { updt_local_params(p); } @@ -690,13 +690,13 @@ struct th_rewriter_cfg : public default_rewriter_cfg { } void reset() { - m_subst = 0; + m_subst = nullptr; } bool get_subst(expr * s, expr * & t, proof * & pr) { - if (m_subst == 0) + if (m_subst == nullptr) return false; - expr_dependency * d = 0; + expr_dependency * d = nullptr; if (m_subst->find(s, t, pr, d)) { m_used_dependencies = m().mk_join(m_used_dependencies, d); return true; @@ -798,9 +798,9 @@ expr_dependency * th_rewriter::get_used_dependencies() { } void th_rewriter::reset_used_dependencies() { - if (get_used_dependencies() != 0) { + if (get_used_dependencies() != nullptr) { set_substitution(m_imp->cfg().m_subst); // reset cache preserving subst - m_imp->cfg().m_used_dependencies = 0; + m_imp->cfg().m_used_dependencies = nullptr; } } diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp index 756e62a5f..97e0ddb19 100644 --- a/src/ast/rewriter/var_subst.cpp +++ b/src/ast/rewriter/var_subst.cpp @@ -94,7 +94,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { } else { num_removed++; - var_mapping.push_back(0); + var_mapping.push_back(nullptr); } } // (VAR 0) is in the first position of var_mapping. @@ -104,7 +104,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { if (s) var_mapping.push_back(m.mk_var(i - num_removed, s)); else - var_mapping.push_back(0); + var_mapping.push_back(nullptr); } diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 2790c5c48..91aeeac3b 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -339,9 +339,9 @@ bool operator<(const zstring& lhs, const zstring& rhs) { seq_decl_plugin::seq_decl_plugin(): m_init(false), m_stringc_sym("String"), m_charc_sym("Char"), - m_string(0), - m_char(0), - m_re(0) {} + m_string(nullptr), + m_char(nullptr), + m_re(nullptr) {} void seq_decl_plugin::finalize() { for (unsigned i = 0; i < m_sigs.size(); ++i) @@ -524,7 +524,7 @@ void seq_decl_plugin::init() { m_sigs.resize(LAST_SEQ_OP); // TBD: have (par ..) construct and load parameterized signature from premable. m_sigs[OP_SEQ_UNIT] = alloc(psig, m, "seq.unit", 1, 1, &A, seqA); - m_sigs[OP_SEQ_EMPTY] = alloc(psig, m, "seq.empty", 1, 0, 0, seqA); + m_sigs[OP_SEQ_EMPTY] = alloc(psig, m, "seq.empty", 1, 0, nullptr, seqA); m_sigs[OP_SEQ_CONCAT] = alloc(psig, m, "seq.++", 1, 2, seqAseqA, seqA); m_sigs[OP_SEQ_PREFIX] = alloc(psig, m, "seq.prefixof", 1, 2, seqAseqA, boolT); m_sigs[OP_SEQ_SUFFIX] = alloc(psig, m, "seq.suffixof", 1, 2, seqAseqA, boolT); @@ -543,9 +543,9 @@ void seq_decl_plugin::init() { m_sigs[OP_RE_INTERSECT] = alloc(psig, m, "re.inter", 1, 2, reAreA, reA); m_sigs[OP_RE_LOOP] = alloc(psig, m, "re.loop", 1, 1, &reA, reA); m_sigs[OP_RE_COMPLEMENT] = alloc(psig, m, "re.complement", 1, 1, &reA, reA); - m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re.empty", 1, 0, 0, reA); - m_sigs[OP_RE_FULL_SEQ_SET] = alloc(psig, m, "re.all", 1, 0, 0, reA); - m_sigs[OP_RE_FULL_CHAR_SET] = alloc(psig, m, "re.allchar", 1, 0, 0, reA); + m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re.empty", 1, 0, nullptr, reA); + m_sigs[OP_RE_FULL_SEQ_SET] = alloc(psig, m, "re.all", 1, 0, nullptr, reA); + m_sigs[OP_RE_FULL_CHAR_SET] = alloc(psig, m, "re.allchar", 1, 0, nullptr, reA); m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re.of.pred", 1, 1, &predA, reA); m_sigs[OP_SEQ_TO_RE] = alloc(psig, m, "seq.to.re", 1, 1, &seqA, reA); m_sigs[OP_SEQ_IN_RE] = alloc(psig, m, "seq.in.re", 1, 2, seqAreA, boolT); @@ -562,8 +562,8 @@ void seq_decl_plugin::init() { m_sigs[_OP_STRING_SUFFIX] = alloc(psig, m, "str.suffixof", 0, 2, str2T, boolT); m_sigs[_OP_STRING_IN_REGEXP] = alloc(psig, m, "str.in.re", 0, 2, strTreT, boolT); m_sigs[_OP_STRING_TO_REGEXP] = alloc(psig, m, "str.to.re", 0, 1, &strT, reT); - m_sigs[_OP_REGEXP_EMPTY] = alloc(psig, m, "re.nostr", 0, 0, 0, reT); - m_sigs[_OP_REGEXP_FULL_CHAR] = alloc(psig, m, "re.allchar", 0, 0, 0, reT); + m_sigs[_OP_REGEXP_EMPTY] = alloc(psig, m, "re.nostr", 0, 0, nullptr, reT); + m_sigs[_OP_REGEXP_FULL_CHAR] = alloc(psig, m, "re.allchar", 0, 0, nullptr, reT); m_sigs[_OP_STRING_SUBSTR] = alloc(psig, m, "str.substr", 0, 3, strTint2T, strT); m_sigs[_OP_RE_UNROLL] = alloc(psig, m, "_re.unroll", 0, 2, reTintT, strT); } @@ -609,7 +609,7 @@ sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter return m_string; default: UNREACHABLE(); - return 0; + return nullptr; } } @@ -650,7 +650,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, match(*m_sigs[k], arity, domain, range, rng); if (rng == m_string) { parameter param(symbol("")); - return mk_func_decl(OP_STRING_CONST, 1, ¶m, 0, 0, m_string); + return mk_func_decl(OP_STRING_CONST, 1, ¶m, 0, nullptr, m_string); } else { parameter param(rng.get()); @@ -819,7 +819,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, } default: UNREACHABLE(); - return 0; + return nullptr; } } @@ -921,7 +921,7 @@ expr* seq_decl_plugin::get_some_value(sort* s) { return util.re.mk_to_re(util.str.mk_empty(seq)); } UNREACHABLE(); - return 0; + return nullptr; } app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range) { @@ -978,15 +978,15 @@ app* seq_util::re::mk_loop(expr* r, unsigned lo, unsigned hi) { } app* seq_util::re::mk_full_char(sort* s) { - return m.mk_app(m_fid, OP_RE_FULL_CHAR_SET, 0, 0, 0, 0, s); + return m.mk_app(m_fid, OP_RE_FULL_CHAR_SET, 0, nullptr, 0, nullptr, s); } app* seq_util::re::mk_full_seq(sort* s) { - return m.mk_app(m_fid, OP_RE_FULL_SEQ_SET, 0, 0, 0, 0, s); + return m.mk_app(m_fid, OP_RE_FULL_SEQ_SET, 0, nullptr, 0, nullptr, s); } app* seq_util::re::mk_empty(sort* s) { - return m.mk_app(m_fid, OP_RE_EMPTY_SET, 0, 0, 0, 0, s); + return m.mk_app(m_fid, OP_RE_EMPTY_SET, 0, nullptr, 0, nullptr, s); } diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index e765e69a4..8bd4d2807 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -233,8 +233,8 @@ public: str(seq_util& u): u(u), m(u.m), m_fid(u.m_fid) {} sort* mk_seq(sort* s) { parameter param(s); return m.mk_sort(m_fid, SEQ_SORT, 1, ¶m); } - sort* mk_string_sort() const { return m.mk_sort(m_fid, _STRING_SORT, 0, 0); } - app* mk_empty(sort* s) const { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, 0, 0, (expr*const*)0, s)); } + sort* mk_string_sort() const { return m.mk_sort(m_fid, _STRING_SORT, 0, nullptr); } + app* mk_empty(sort* s) const { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, nullptr, 0, (expr*const*)nullptr, s)); } app* mk_string(zstring const& s); app* mk_string(symbol const& s) { return u.seq.mk_string(s); } app* mk_char(char ch); diff --git a/src/ast/substitution/expr_offset.h b/src/ast/substitution/expr_offset.h index 1f27f222a..ee098053f 100644 --- a/src/ast/substitution/expr_offset.h +++ b/src/ast/substitution/expr_offset.h @@ -30,7 +30,7 @@ class expr_offset { expr * m_expr; unsigned m_offset; public: - expr_offset():m_expr(0), m_offset(0) {} + expr_offset():m_expr(nullptr), m_offset(0) {} expr_offset(expr * e, unsigned o):m_expr(e), m_offset(o) {} expr * get_expr() const { return m_expr; } diff --git a/src/ast/substitution/substitution.cpp b/src/ast/substitution/substitution.cpp index d54a8e057..39e9e07a2 100644 --- a/src/ast/substitution/substitution.cpp +++ b/src/ast/substitution/substitution.cpp @@ -79,13 +79,13 @@ void substitution::apply(unsigned num_actual_offsets, unsigned const * deltas, e // It is incorrect to cache results between different calls if we are applying a substitution // modulo a substitution s -> t. - if (m_state == INSERT || s != expr_offset(0,0)) + if (m_state == INSERT || s != expr_offset(nullptr,0)) reset_cache(); m_state = APPLY; unsigned j; - expr * e = 0; + expr * e = nullptr; unsigned off; expr_offset n1; bool visited; @@ -146,7 +146,7 @@ void substitution::apply(unsigned num_actual_offsets, unsigned const * deltas, e bool has_new_args = false; for (unsigned i = 0; i < num_args; i++) { expr * arg = to_app(e)->get_arg(i); - expr * new_arg = 0; + expr * new_arg = nullptr; VERIFY(m_apply_cache.find(expr_offset(arg, off), new_arg)); new_args.push_back(new_arg); @@ -185,10 +185,10 @@ void substitution::apply(unsigned num_actual_offsets, unsigned const * deltas, e } expr_offset body(q->get_expr(), off); expr_ref s1_ref(m_manager), t1_ref(m_manager); - if (s.get_expr() != 0) { + if (s.get_expr() != nullptr) { var_sh(s.get_expr(), num_vars, s1_ref); } - if (t.get_expr() != 0) { + if (t.get_expr() != nullptr) { var_sh(t.get_expr(), num_vars, t1_ref); } expr_offset s1(s1_ref, s.get_offset()); @@ -218,7 +218,7 @@ void substitution::apply(unsigned num_actual_offsets, unsigned const * deltas, e m_new_exprs.push_back(e); result = e; - if (s != expr_offset(0,0)) + if (s != expr_offset(nullptr,0)) reset_cache(); TRACE("subst_bug", tout << "END substitution::apply\nresult:\n" << mk_pp(e, m_manager) << "\nref_count: " << e->get_ref_count() << "\n";); diff --git a/src/ast/substitution/substitution.h b/src/ast/substitution/substitution.h index 0d318e4fb..5f1288fd7 100644 --- a/src/ast/substitution/substitution.h +++ b/src/ast/substitution/substitution.h @@ -178,7 +178,7 @@ public: to the variable x+delta[i]. */ void apply(unsigned num_actual_offsets, unsigned const * deltas, expr_offset const & n, expr_ref & result) { - apply(num_actual_offsets, deltas, n, expr_offset(0, 0), expr_offset(0, 0), result); + apply(num_actual_offsets, deltas, n, expr_offset(nullptr, 0), expr_offset(nullptr, 0), result); } /** diff --git a/src/ast/substitution/substitution_tree.cpp b/src/ast/substitution/substitution_tree.cpp index 20d5f1590..809197c8f 100644 --- a/src/ast/substitution/substitution_tree.cpp +++ b/src/ast/substitution/substitution_tree.cpp @@ -172,7 +172,7 @@ substitution_tree::node * substitution_tree::find_best_child(node * r) { #ifdef Z3DEBUG unsigned todo_size = m_todo.size(); #endif - node * best_child = 0; + node * best_child = nullptr; unsigned max_measure = 0; node * curr_child = r->m_first_child; while (curr_child) { @@ -335,7 +335,7 @@ void substitution_tree::insert(app * new_expr) { else { mark_used_regs(r->m_subst); node * best_child = find_best_child(r); - if (best_child == 0) { + if (best_child == nullptr) { // there is no compatible child node * n = mk_node_for(new_expr); n->m_next_sibling = r->m_first_child; @@ -414,7 +414,7 @@ bool substitution_tree::is_fully_compatible(svector const & sv) { */ bool substitution_tree::find_fully_compatible_child(node * r, node * & prev, node * & child) { SASSERT(!r->m_leaf); - prev = 0; + prev = nullptr; child = r->m_first_child; while (child) { if (is_fully_compatible(child->m_subst)) @@ -462,8 +462,8 @@ void substitution_tree::erase(app * e) { m_todo.push_back(0); node * r = m_roots[id]; - node * parent = 0; - node * prev = 0; + node * parent = nullptr; + node * prev = nullptr; while (true) { svector & sv = r->m_subst; @@ -495,12 +495,12 @@ void substitution_tree::erase(app * e) { if (m_todo.empty()) { reset_registers(0); SASSERT(r->m_expr == e); - if (parent == 0) { + if (parent == nullptr) { delete_node(r); m_roots[id] = 0; } else if (at_least_3_children(parent)) { - if (prev == 0) + if (prev == nullptr) parent->m_first_child = r->m_next_sibling; else prev->m_next_sibling = r->m_next_sibling; @@ -843,7 +843,7 @@ void substitution_tree::visit(expr * e, st_visitor & st, unsigned in_offset, uns ptr_vector::iterator end = m_roots.end(); for (; it != end; ++it) { node * r = *it; - if (r != 0) { + if (r != nullptr) { var * v = r->m_subst[0].first; if (v->get_sort() == to_var(e)->get_sort()) if (!visit(e, st, r)) @@ -878,7 +878,7 @@ void substitution_tree::display(std::ostream & out) const { ptr_vector::const_iterator end2 = m_vars.end(); for (; it2 != end2; ++it2) { var_ref_vector * v = *it2; - if (v == 0) + if (v == nullptr) continue; // m_vars may contain null pointers. See substitution_tree::insert. unsigned num = v->size(); for (unsigned i = 0; i < num; i++) { diff --git a/src/ast/substitution/substitution_tree.h b/src/ast/substitution/substitution_tree.h index 7a8c30a63..018bee471 100644 --- a/src/ast/substitution/substitution_tree.h +++ b/src/ast/substitution/substitution_tree.h @@ -50,7 +50,7 @@ class substitution_tree { node * m_first_child; expr * m_expr; }; - node(bool leaf):m_leaf(leaf), m_next_sibling(0), m_first_child(0) {} + node(bool leaf):m_leaf(leaf), m_next_sibling(nullptr), m_first_child(nullptr) {} }; ast_manager & m_manager; diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index f1357126c..0c9c5360c 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -56,7 +56,7 @@ public: cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_SYMBOL; } void set_next_arg(cmd_context & ctx, symbol const & s) override { cmd * c = ctx.find_cmd(s); - if (c == 0) { + if (c == nullptr) { std::string err_msg("unknown command '"); err_msg = err_msg + s.bare_str() + "'"; throw cmd_exception(err_msg); @@ -109,7 +109,7 @@ public: cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_UINT; } void set_next_arg(cmd_context & ctx, unsigned index) override { m_index = index; } void execute(cmd_context & ctx) override { - if (!ctx.is_model_available() || ctx.get_check_sat_result() == 0) + if (!ctx.is_model_available() || ctx.get_check_sat_result() == nullptr) throw cmd_exception("model is not available"); model_ref m; if (m_index > 0 && ctx.get_opt()) { @@ -785,7 +785,7 @@ public: } void execute(cmd_context & ctx) override { psort_decl * array_sort = ctx.find_psort_decl(m_array_sort); - if (array_sort == 0) + if (array_sort == nullptr) throw cmd_exception("Array sort is not available"); ptr_vector & array_sort_args = m_domain; sort_ref_buffer domain(ctx.m()); @@ -892,7 +892,7 @@ void install_ext_basic_cmds(cmd_context & ctx) { ctx.insert(alloc(echo_cmd)); ctx.insert(alloc(labels_cmd)); ctx.insert(alloc(declare_map_cmd)); - ctx.insert(alloc(builtin_cmd, "reset", 0, "reset the shell (all declarations and assertions will be erased)")); + ctx.insert(alloc(builtin_cmd, "reset", nullptr, "reset the shell (all declarations and assertions will be erased)")); install_simplify_cmd(ctx); install_eval_cmd(ctx); } diff --git a/src/cmd_context/check_logic.cpp b/src/cmd_context/check_logic.cpp index dd08ac9db..55be27c6d 100644 --- a/src/cmd_context/check_logic.cpp +++ b/src/cmd_context/check_logic.cpp @@ -328,17 +328,17 @@ struct check_logic::imp { bool is_offset(app * t) { while (true) { - expr * non_numeral = 0; + expr * non_numeral = nullptr; unsigned num_args = t->get_num_args(); for (unsigned i = 0; i < num_args; i++) { expr * arg = t->get_arg(i); if (is_numeral(arg)) continue; - if (non_numeral != 0) + if (non_numeral != nullptr) return false; non_numeral = arg; } - if (non_numeral == 0) + if (non_numeral == nullptr) return true; if (is_diff_var(non_numeral)) return true; @@ -501,7 +501,7 @@ struct check_logic::imp { }; check_logic::check_logic() { - m_imp = 0; + m_imp = nullptr; } check_logic::~check_logic() { @@ -512,7 +512,7 @@ check_logic::~check_logic() { void check_logic::reset() { if (m_imp) dealloc(m_imp); - m_imp = 0; + m_imp = nullptr; } void check_logic::set_logic(ast_manager & m, symbol const & logic) { diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index c6c36606a..436e1b538 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -67,7 +67,7 @@ void func_decls::finalize(ast_manager & m) { } dealloc(fs); } - m_decls = 0; + m_decls = nullptr; } bool func_decls::signatures_collide(func_decl* f, func_decl* g) const { @@ -116,7 +116,7 @@ bool func_decls::insert(ast_manager & m, func_decl * f) { if (contains(f)) return false; m.inc_ref(f); - if (m_decls == 0) { + if (m_decls == nullptr) { m_decls = TAG(func_decl*, f, 0); } else if (GET_TAG(m_decls) == 0) { @@ -137,7 +137,7 @@ void func_decls::erase(ast_manager & m, func_decl * f) { return; if (GET_TAG(m_decls) == 0) { m.dec_ref(f); - m_decls = 0; + m_decls = nullptr; } else { func_decl_set * fs = UNTAG(func_decl_set *, m_decls); @@ -145,7 +145,7 @@ void func_decls::erase(ast_manager & m, func_decl * f) { m.dec_ref(f); if (fs->empty()) { dealloc(fs); - m_decls = 0; + m_decls = nullptr; } } } @@ -154,7 +154,7 @@ void func_decls::erase(ast_manager & m, func_decl * f) { \brief Return true if func_decls contains a declaration different from f, but with the same domain. */ bool func_decls::clash(func_decl * f) const { - if (m_decls == 0) + if (m_decls == nullptr) return false; if (GET_TAG(m_decls) == 0) return false; @@ -176,15 +176,15 @@ bool func_decls::clash(func_decl * f) const { } bool func_decls::more_than_one() const { - if (m_decls == 0 || GET_TAG(m_decls) == 0) + if (m_decls == nullptr || GET_TAG(m_decls) == 0) return false; func_decl_set * fs = UNTAG(func_decl_set *, m_decls); return fs->size() > 1; } func_decl * func_decls::first() const { - if (m_decls == 0) - return 0; + if (m_decls == nullptr) + return nullptr; if (GET_TAG(m_decls) == 0) return UNTAG(func_decl*, m_decls); func_decl_set * fs = UNTAG(func_decl_set *, m_decls); @@ -197,7 +197,7 @@ func_decl * func_decls::find(unsigned arity, sort * const * domain, sort * range return first(); func_decl_set * fs = UNTAG(func_decl_set *, m_decls); for (func_decl * f : *fs) { - if (range != 0 && f->get_range() != range) + if (range != nullptr && f->get_range() != range) continue; if (f->get_arity() != arity) continue; @@ -209,7 +209,7 @@ func_decl * func_decls::find(unsigned arity, sort * const * domain, sort * range if (i == arity) return f; } - return 0; + return nullptr; } func_decl * func_decls::find(ast_manager & m, unsigned num_args, expr * const * args, sort * range) const { @@ -257,7 +257,7 @@ bool macro_decls::insert(ast_manager& m, unsigned arity, sort *const* domain, ex } expr* macro_decls::find(unsigned arity, sort *const* domain) const { - if (!m_decls) return 0; + if (!m_decls) return nullptr; for (auto v : *m_decls) { if (v.m_domain.size() != arity) continue; bool eq = true; @@ -266,7 +266,7 @@ expr* macro_decls::find(unsigned arity, sort *const* domain) const { } if (eq) return v.m_body; } - return 0; + return nullptr; } void macro_decls::erase_last(ast_manager& m) { @@ -291,7 +291,7 @@ bool cmd_context::contains_macro(symbol const& s, func_decl* f) const { bool cmd_context::contains_macro(symbol const& s, unsigned arity, sort *const* domain) const { macro_decls decls; - return m_macros.find(s, decls) && 0 != decls.find(arity, domain); + return m_macros.find(s, decls) && nullptr != decls.find(arity, domain); } void cmd_context::insert_macro(symbol const& s, unsigned arity, sort*const* domain, expr* t) { @@ -472,11 +472,11 @@ cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l): m_processing_pareto(false), m_exit_on_error(false), m_manager(m), - m_own_manager(m == 0), + m_own_manager(m == nullptr), m_manager_initialized(false), m_rec_fun_declared(false), - m_pmanager(0), - m_sexpr_manager(0), + m_pmanager(nullptr), + m_sexpr_manager(nullptr), m_regular("stdout", std::cout), m_diagnostic("stderr", std::cerr) { SASSERT(m != 0 || !has_manager()); @@ -498,8 +498,8 @@ cmd_context::~cmd_context() { finalize_tactic_cmds(); finalize_probes(); reset(true); - m_solver = 0; - m_check_sat_result = 0; + m_solver = nullptr; + m_check_sat_result = nullptr; } void cmd_context::set_cancel(bool f) { @@ -593,7 +593,7 @@ bool cmd_context::validate_model_enabled() const { } cmd_context::check_sat_state cmd_context::cs_state() const { - if (m_check_sat_result.get() == 0) + if (m_check_sat_result.get() == nullptr) return css_clear; switch (m_check_sat_result->status()) { case l_true: return css_sat; @@ -741,7 +741,7 @@ void cmd_context::init_manager() { else { m_manager_initialized = true; SASSERT(m_pmanager == 0); - m_check_sat_result = 0; + m_check_sat_result = nullptr; m_manager = m_params.mk_ast_manager(); m_pmanager = alloc(pdecl_manager, *m_manager); init_manager_core(true); @@ -771,7 +771,7 @@ bool cmd_context::set_logic(symbol const & s) { } std::string cmd_context::reason_unknown() const { - if (m_check_sat_result.get() == 0) + if (m_check_sat_result.get() == nullptr) return "state of the most recent check-sat command is not known"; return m_check_sat_result->reason_unknown(); } @@ -861,7 +861,7 @@ void cmd_context::insert_user_tactic(symbol const & s, sexpr * d) { void cmd_context::insert(symbol const & s, object_ref * r) { r->inc_ref(*this); - object_ref * old_r = 0; + object_ref * old_r = nullptr; if (m_object_refs.find(s, old_r)) { old_r->dec_ref(*this); } @@ -905,8 +905,8 @@ func_decl * cmd_context::find_func_decl(symbol const & s) const { try { // Remark: ignoring m_next of d. We do not allow two different theories to define the same constant name. func_decl * f; - f = m().mk_func_decl(d.m_fid, d.m_decl, 0, 0, 0, static_cast(0), 0); - if (f != 0) + f = m().mk_func_decl(d.m_fid, d.m_decl, 0, nullptr, 0, static_cast(nullptr), nullptr); + if (f != nullptr) return f; } catch (ast_exception &) { @@ -923,7 +923,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s) const { return fs.first(); } throw cmd_exception("invalid function declaration reference, unknown function ", s); - return 0; + return nullptr; } /** @@ -936,7 +936,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s) const { */ static builtin_decl const & peek_builtin_decl(builtin_decl const & first, family_id target_id) { builtin_decl const * curr = &first; - while (curr != 0) { + while (curr != nullptr) { if (curr->m_fid == target_id) return *curr; curr = curr->m_next; @@ -958,7 +958,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, } func_decl * f; if (num_indices == 0) { - f = m().mk_func_decl(fid, k, 0, 0, arity, domain, range); + f = m().mk_func_decl(fid, k, 0, nullptr, arity, domain, range); } else { buffer ps; @@ -966,7 +966,7 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, ps.push_back(parameter(indices[i])); f = m().mk_func_decl(fid, k, num_indices, ps.c_ptr(), arity, domain, range); } - if (f == 0) + if (f == nullptr) throw cmd_exception("invalid function declaration reference, invalid builtin reference ", s); return f; } @@ -977,46 +977,46 @@ func_decl * cmd_context::find_func_decl(symbol const & s, unsigned num_indices, if (num_indices > 0) throw cmd_exception("invalid indexed function declaration reference, unknown builtin function ", s); - func_decl * f = 0; + func_decl * f = nullptr; func_decls fs; if (m_func_decls.find(s, fs)) { f = fs.find(arity, domain, range); } - if (f == 0) + if (f == nullptr) throw cmd_exception("invalid function declaration reference, unknown function ", s); return f; } psort_decl * cmd_context::find_psort_decl(symbol const & s) const { - psort_decl * p = 0; + psort_decl * p = nullptr; m_psort_decls.find(s, p); return p; } cmd * cmd_context::find_cmd(symbol const & s) const { - cmd * c = 0; + cmd * c = nullptr; m_cmds.find(s, c); return c; } sexpr * cmd_context::find_user_tactic(symbol const & s) const { - sexpr * n = 0; + sexpr * n = nullptr; m_user_tactic_decls.find(s, n); return n; } object_ref * cmd_context::find_object_ref(symbol const & s) const { - object_ref * r = 0; + object_ref * r = nullptr; m_object_refs.find(s, r); - if (r == 0) throw cmd_exception("unknown global variable ", s); + if (r == nullptr) throw cmd_exception("unknown global variable ", s); return r; } #define CHECK_SORT(T) if (well_sorted_check_enabled()) m().check_sorts_core(T) void cmd_context::mk_const(symbol const & s, expr_ref & result) const { - mk_app(s, 0, 0, 0, 0, 0, result); + mk_app(s, 0, nullptr, 0, nullptr, nullptr, result); } void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * args, unsigned num_indices, parameter const * indices, sort * range, @@ -1032,12 +1032,12 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg k = d2.m_decl; } if (num_indices == 0) { - result = m().mk_app(fid, k, 0, 0, num_args, args, range); + result = m().mk_app(fid, k, 0, nullptr, num_args, args, range); } else { result = m().mk_app(fid, k, num_indices, indices, num_args, args, range); } - if (result.get() == 0) + if (result.get() == nullptr) throw cmd_exception("invalid builtin application ", s); CHECK_SORT(result.get()); return; @@ -1066,11 +1066,11 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg throw cmd_exception("unknown function/constant ", s); } - if (num_args == 0 && range == 0) { + if (num_args == 0 && range == nullptr) { if (fs.more_than_one()) throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as ) to disumbiguate ", s); func_decl * f = fs.first(); - if (f == 0) { + if (f == nullptr) { throw cmd_exception("unknown constant ", s); } if (f->get_arity() != 0) @@ -1079,7 +1079,7 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg } else { func_decl * f = fs.find(m(), num_args, args, range); - if (f == 0) { + if (f == nullptr) { std::ostringstream buffer; buffer << "unknown constant " << s << " "; buffer << " ("; @@ -1173,7 +1173,7 @@ void cmd_context::erase_user_tactic(symbol const & s) { } void cmd_context::erase_object_ref(symbol const & s) { - object_ref * r = 0; + object_ref * r = nullptr; if (m_object_refs.find(s, r)) { r->dec_ref(*this); m_object_refs.erase(s); @@ -1242,7 +1242,7 @@ void cmd_context::insert_aux_pdecl(pdecl * p) { void cmd_context::reset(bool finalize) { m_processing_pareto = false; m_logic = symbol::null; - m_check_sat_result = 0; + m_check_sat_result = nullptr; m_numeral_as_real = false; m_builtin_decls.reset(); m_extra_builtin_decls.reset(); @@ -1255,17 +1255,17 @@ void cmd_context::reset(bool finalize) { reset_func_decls(); restore_assertions(0); if (m_solver) - m_solver = 0; + m_solver = nullptr; m_scopes.reset(); - m_opt = 0; - m_pp_env = 0; - m_dt_eh = 0; + m_opt = nullptr; + m_pp_env = nullptr; + m_dt_eh = nullptr; if (m_manager) { dealloc(m_pmanager); - m_pmanager = 0; + m_pmanager = nullptr; if (m_own_manager) { dealloc(m_manager); - m_manager = 0; + m_manager = nullptr; m_manager_initialized = false; } else { @@ -1279,7 +1279,7 @@ void cmd_context::reset(bool finalize) { } if (m_sexpr_manager) { dealloc(m_sexpr_manager); - m_sexpr_manager = 0; + m_sexpr_manager = nullptr; } SASSERT(!m_own_manager || !has_manager()); } @@ -1288,7 +1288,7 @@ void cmd_context::assert_expr(expr * t) { m_processing_pareto = false; if (!m_check_logic(t)) throw cmd_exception(m_check_logic.get_last_error()); - m_check_sat_result = 0; + m_check_sat_result = nullptr; m().inc_ref(t); m_assertions.push_back(t); if (produce_unsat_cores()) @@ -1305,7 +1305,7 @@ void cmd_context::assert_expr(symbol const & name, expr * t) { assert_expr(t); return; } - m_check_sat_result = 0; + m_check_sat_result = nullptr; m().inc_ref(t); m_assertions.push_back(t); expr * ans = m().mk_const(name, m().mk_bool_sort()); @@ -1316,7 +1316,7 @@ void cmd_context::assert_expr(symbol const & name, expr * t) { } void cmd_context::push() { - m_check_sat_result = 0; + m_check_sat_result = nullptr; init_manager(); m_scopes.push_back(scope()); scope & s = m_scopes.back(); @@ -1362,7 +1362,7 @@ void cmd_context::restore_psort_decls(unsigned old_sz) { svector::iterator end = m_psort_decls_stack.end(); for (; it != end; ++it) { symbol const & s = *it; - psort_decl * d = 0; + psort_decl * d = nullptr; VERIFY(m_psort_decls.find(s, d)); pm().dec_ref(d); m_psort_decls.erase(s); @@ -1418,7 +1418,7 @@ void cmd_context::restore_assertions(unsigned old_sz) { } void cmd_context::pop(unsigned n) { - m_check_sat_result = 0; + m_check_sat_result = nullptr; m_processing_pareto = false; if (n == 0) return; @@ -1556,10 +1556,10 @@ void cmd_context::reset_assertions() { } if (m_opt) { - m_opt = 0; + m_opt = nullptr; } if (m_solver) { - m_solver = 0; + m_solver = nullptr; mk_solver(); } restore_assertions(0); @@ -1778,7 +1778,7 @@ void cmd_context::validate_model() { for (; it != end; ++it) { expr * a = *it; if (is_ground(a)) { - r = 0; + r = nullptr; evaluator(a, r); TRACE("model_validate", tout << "checking\n" << mk_ismt2_pp(a, m()) << "\nresult:\n" << mk_ismt2_pp(r, m()) << "\n";); if (m().is_true(r)) @@ -1830,8 +1830,8 @@ void cmd_context::set_interpolating_solver_factory(solver_factory * f) { void cmd_context::set_solver_factory(solver_factory * f) { m_solver_factory = f; - m_check_sat_result = 0; - if (has_manager() && f != 0) { + m_check_sat_result = nullptr; + if (has_manager() && f != nullptr) { mk_solver(); // assert formulas and create scopes in the new solver. unsigned lim = 0; @@ -1890,7 +1890,7 @@ bool cmd_context::is_model_available() const { (cs_state() == css_sat || cs_state() == css_unknown)) { model_ref md; get_check_sat_result()->get_model(md); - return md.get() != 0; + return md.get() != nullptr; } return false; } @@ -1901,7 +1901,7 @@ format_ns::format * cmd_context::pp(sort * s) const { } cmd_context::pp_env & cmd_context::get_pp_env() const { - if (m_pp_env.get() == 0) { + if (m_pp_env.get() == nullptr) { const_cast(this)->m_pp_env = alloc(pp_env, *const_cast(this)); } return *(m_pp_env.get()); @@ -1913,7 +1913,7 @@ void cmd_context::pp(expr * n, unsigned num_vars, char const * var_prefix, forma void cmd_context::pp(expr * n, format_ns::format_ref & r) const { sbuffer buf; - pp(n, 0, 0, r, buf); + pp(n, 0, nullptr, r, buf); } void cmd_context::pp(func_decl * f, format_ns::format_ref & r) const { @@ -1938,7 +1938,7 @@ void cmd_context::display(std::ostream & out, expr * n, unsigned indent, unsigne void cmd_context::display(std::ostream & out, expr * n, unsigned indent) const { sbuffer buf; - display(out, n, indent, 0, 0, buf); + display(out, n, indent, 0, nullptr, buf); } void cmd_context::display(std::ostream & out, func_decl * d, unsigned indent) const { diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index cd3191fc6..d1e470c3b 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -45,7 +45,7 @@ class func_decls { bool signatures_collide(func_decl* f, func_decl* g) const; bool signatures_collide(unsigned n, sort*const* domain, sort* range, func_decl* g) const; public: - func_decls():m_decls(0) {} + func_decls():m_decls(nullptr) {} func_decls(ast_manager & m, func_decl * f); void finalize(ast_manager & m); bool contains(func_decl * f) const; @@ -54,7 +54,7 @@ public: void erase(ast_manager & m, func_decl * f); bool more_than_one() const; bool clash(func_decl * f) const; - bool empty() const { return m_decls == 0; } + bool empty() const { return m_decls == nullptr; } func_decl * first() const; func_decl * find(unsigned arity, sort * const * domain, sort * range) const; func_decl * find(ast_manager & m, unsigned num_args, expr * const * args, sort * range) const; @@ -76,7 +76,7 @@ struct macro_decl { class macro_decls { vector* m_decls; public: - macro_decls() { m_decls = 0; } + macro_decls() { m_decls = nullptr; } void finalize(ast_manager& m); bool insert(ast_manager& m, unsigned arity, sort *const* domain, expr* body); expr* find(unsigned arity, sort *const* domain) const; @@ -138,8 +138,8 @@ struct builtin_decl { family_id m_fid; decl_kind m_decl; builtin_decl * m_next; - builtin_decl():m_fid(null_family_id), m_decl(0), m_next(0) {} - builtin_decl(family_id fid, decl_kind k, builtin_decl * n = 0):m_fid(fid), m_decl(k), m_next(n) {} + builtin_decl():m_fid(null_family_id), m_decl(0), m_next(nullptr) {} + builtin_decl(family_id fid, decl_kind k, builtin_decl * n = nullptr):m_fid(fid), m_decl(k), m_next(n) {} }; class opt_wrapper : public check_sat_result { @@ -306,7 +306,7 @@ protected: public: - cmd_context(bool main_ctx = true, ast_manager * m = 0, symbol const & l = symbol::null); + cmd_context(bool main_ctx = true, ast_manager * m = nullptr, symbol const & l = symbol::null); ~cmd_context() override; void set_cancel(bool f); context_params & params() { return m_params; } @@ -352,7 +352,7 @@ public: status get_status() const { return m_status; } std::string reason_unknown() const; - bool has_manager() const { return m_manager != 0; } + bool has_manager() const { return m_manager != nullptr; } ast_manager & m() const { const_cast(this)->init_manager(); return *m_manager; } ast_manager & get_ast_manager() override { return m(); } pdecl_manager & pm() const { if (!m_pmanager) const_cast(this)->init_manager(); return *m_pmanager; } diff --git a/src/cmd_context/cmd_context_to_goal.cpp b/src/cmd_context/cmd_context_to_goal.cpp index beff9a7bd..a66f9e5de 100644 --- a/src/cmd_context/cmd_context_to_goal.cpp +++ b/src/cmd_context/cmd_context_to_goal.cpp @@ -33,14 +33,14 @@ void assert_exprs_from(cmd_context const & ctx, goal & t) { ptr_vector::const_iterator it2 = ctx.begin_assertion_names(); SASSERT(end - it == ctx.end_assertion_names() - it2); for (; it != end; ++it, ++it2) { - t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, m.mk_leaf(*it2)); + t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : nullptr, m.mk_leaf(*it2)); } } else { ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); for (; it != end; ++it) { - t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, 0); + t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : nullptr, nullptr); } SASSERT(ctx.begin_assertion_names() == ctx.end_assertion_names()); } diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index 78f4223fc..85ac2274b 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -62,7 +62,7 @@ void context_params::set_uint(unsigned & opt, char const * param, char const * v } if (is_uint) { - long val = strtol(value, 0, 10); + long val = strtol(value, nullptr, 10); opt = static_cast(val); } else { @@ -198,7 +198,7 @@ void context_params::get_solver_params(ast_manager const & m, params_ref & p, bo ast_manager * context_params::mk_ast_manager() { ast_manager * r = alloc(ast_manager, m_proof ? PGM_ENABLED : PGM_DISABLED, - m_trace ? m_trace_file_name.c_str() : 0); + m_trace ? m_trace_file_name.c_str() : nullptr); if (m_smtlib2_compliant) r->enable_int_real_coercions(false); if (m_debug_ref_count) diff --git a/src/cmd_context/eval_cmd.cpp b/src/cmd_context/eval_cmd.cpp index b1a7905d1..d4004fca8 100644 --- a/src/cmd_context/eval_cmd.cpp +++ b/src/cmd_context/eval_cmd.cpp @@ -43,11 +43,11 @@ public: void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); - m_target = 0; + m_target = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - if (m_target == 0) return CPK_EXPR; + if (m_target == nullptr) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 6dab3e39f..465bcb956 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -107,7 +107,7 @@ public: char const * get_usage() const override { return " (*) "; } char const * get_descr(cmd_context & ctx) const override { return "substitute the free variables in the AST referenced by using the ASTs referenced by *"; } unsigned get_arity() const override { return 3; } - void prepare(cmd_context & ctx) override { m_idx = 0; m_source = 0; } + void prepare(cmd_context & ctx) override { m_idx = 0; m_source = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_idx == 1) return CPK_SYMBOL_LIST; return CPK_SYMBOL; @@ -182,10 +182,10 @@ public: char const * get_usage() const override { return " "; } char const * get_descr(cmd_context & ctx) const override { return "return true if the first term is smaller than the second one in the internal Z3 total order on terms."; } unsigned get_arity() const override { return 2; } - void prepare(cmd_context & ctx) override { m_t1 = 0; } + void prepare(cmd_context & ctx) override { m_t1 = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { return CPK_EXPR; } void set_next_arg(cmd_context & ctx, expr * arg) override { - if (m_t1 == 0) + if (m_t1 == nullptr) m_t1 = arg; else m_t2 = arg; @@ -286,10 +286,10 @@ public: char const * get_usage() const override { return " (*)"; } char const * get_descr(cmd_context & ctx) const override { return "instantiate the quantifier using the given expressions."; } unsigned get_arity() const override { return 2; } - void prepare(cmd_context & ctx) override { m_q = 0; m_args.reset(); } + void prepare(cmd_context & ctx) override { m_q = nullptr; m_args.reset(); } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - if (m_q == 0) return CPK_EXPR; + if (m_q == nullptr) return CPK_EXPR; else return CPK_EXPR_LIST; } diff --git a/src/cmd_context/extra_cmds/polynomial_cmds.cpp b/src/cmd_context/extra_cmds/polynomial_cmds.cpp index 8adaa660d..1f4915ca5 100644 --- a/src/cmd_context/extra_cmds/polynomial_cmds.cpp +++ b/src/cmd_context/extra_cmds/polynomial_cmds.cpp @@ -104,7 +104,7 @@ class poly_isolate_roots_cmd : public cmd { } void set_next_arg(cmd_context & ctx, expr * arg) { - if (m_p.get() == 0) { + if (m_p.get() == nullptr) { scoped_mpz d(m_qm); if (!m_expr2poly.to_polynomial(arg, m_p, d)) throw cmd_exception("expression is not a polynomial"); @@ -132,7 +132,7 @@ class poly_isolate_roots_cmd : public cmd { } void execute(cmd_context & ctx) { - if (m_p.get() == 0) + if (m_p.get() == nullptr) throw cmd_exception("polynomial expected"); polynomial::var_vector xs; m_pm.vars(m_p, xs); @@ -162,7 +162,7 @@ class poly_isolate_roots_cmd : public cmd { scoped_ptr m_ctx; public: - poly_isolate_roots_cmd(char const * name = "poly/isolate-roots"):cmd(name), m_ctx(0) {} + poly_isolate_roots_cmd(char const * name = "poly/isolate-roots"):cmd(name), m_ctx(nullptr) {} char const * get_usage() const override { return " ( )*"; } @@ -175,11 +175,11 @@ public: } void finalize(cmd_context & ctx) override { - m_ctx = 0; + m_ctx = nullptr; } void failure_cleanup(cmd_context & ctx) override { - m_ctx = 0; + m_ctx = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { @@ -192,7 +192,7 @@ public: void execute(cmd_context & ctx) override { m_ctx->execute(ctx); - m_ctx = 0; + m_ctx = nullptr; } }; @@ -216,11 +216,11 @@ public: void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); - m_target = 0; + m_target = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - if (m_target == 0) return CPK_EXPR; + if (m_target == nullptr) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp index 62824c2ec..dd1d0acec 100644 --- a/src/cmd_context/interpolant_cmds.cpp +++ b/src/cmd_context/interpolant_cmds.cpp @@ -117,7 +117,7 @@ static void get_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_ ptr_vector interps; try { - iz3interpolate(ctx.m(),pr.get(),cnsts,t,interps,0); + iz3interpolate(ctx.m(),pr.get(),cnsts,t,interps,nullptr); } catch (iz3_bad_tree &) { throw cmd_exception("interpolation pattern contains non-asserted formula"); @@ -160,7 +160,7 @@ static void compute_interpolant_and_maybe_check(cmd_context & ctx, expr * t, par lbool res; try { - res = iz3interpolate(_m, *sp.get(), t, cnsts, interps, m, 0); + res = iz3interpolate(_m, *sp.get(), t, cnsts, interps, m, nullptr); } catch (iz3_incompleteness &) { throw cmd_exception("incompleteness in interpolator"); diff --git a/src/cmd_context/parametric_cmd.cpp b/src/cmd_context/parametric_cmd.cpp index 4a85821b2..524662ed3 100644 --- a/src/cmd_context/parametric_cmd.cpp +++ b/src/cmd_context/parametric_cmd.cpp @@ -20,7 +20,7 @@ Notes: #include "cmd_context/parametric_cmd.h" char const * parametric_cmd::get_descr(cmd_context & ctx) const { - if (m_descr == 0) { + if (m_descr == nullptr) { const_cast(this)->m_descr = alloc(string_buffer<>); m_descr->append(get_main_descr()); m_descr->append("\nThe following options are available:\n"); diff --git a/src/cmd_context/parametric_cmd.h b/src/cmd_context/parametric_cmd.h index 84b29a17d..79517219d 100644 --- a/src/cmd_context/parametric_cmd.h +++ b/src/cmd_context/parametric_cmd.h @@ -30,7 +30,7 @@ public: params_ref m_params; scoped_ptr m_pdescrs; public: - parametric_cmd(char const * name):cmd(name), m_descr(0) {} + parametric_cmd(char const * name):cmd(name), m_descr(nullptr) {} ~parametric_cmd() override { if (m_descr) dealloc(m_descr); } virtual void init_pdescrs(cmd_context & ctx, param_descrs & d) = 0; param_descrs const & pdescrs(cmd_context & ctx) const; diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index f485aea75..3a684b867 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -25,7 +25,7 @@ class psort_inst_cache { sort * m_const; obj_map m_map; // if m_num_params == 1 value is a sort, otherwise it is a reference to another inst_cache public: - psort_inst_cache(unsigned num_params):m_num_params(num_params), m_const(0) { + psort_inst_cache(unsigned num_params):m_num_params(num_params), m_const(nullptr) { } ~psort_inst_cache() { SASSERT(m_map.empty()); SASSERT(m_const == 0); } @@ -35,7 +35,7 @@ public: SASSERT(m_map.empty()); if (m_const) m.m().dec_ref(m_const); - m_const = 0; + m_const = nullptr; } else { SASSERT(m_const == 0); @@ -71,7 +71,7 @@ public: m.m().inc_ref(r); return; } - void * next = 0; + void * next = nullptr; if (!curr->m_map.find(*s, next)) { next = new (m.a().allocate(sizeof(psort_inst_cache))) psort_inst_cache(curr->m_num_params-1); curr->m_map.insert(*s, next); @@ -90,22 +90,22 @@ public: psort_inst_cache const * curr = this; while (true) { if (curr->m_num_params == 1) { - void * r = 0; + void * r = nullptr; curr->m_map.find(*s, r); return static_cast(r); } else { - void * next = 0; + void * next = nullptr; curr->m_map.find(*s, next); - if (next == 0) - return 0; + if (next == nullptr) + return nullptr; s++; curr = static_cast(next); } } } - bool empty() const { return m_num_params == 0 ? m_const == 0 : m_map.empty(); } + bool empty() const { return m_num_params == 0 ? m_const == nullptr : m_map.empty(); } }; void psort::cache(pdecl_manager & m, sort * const * s, sort * r) { @@ -116,7 +116,7 @@ void psort::cache(pdecl_manager & m, sort * const * s, sort * r) { sort * psort::find(sort * const * s) const { if (!m_inst_cache) - return 0; + return nullptr; return m_inst_cache->find(s); } @@ -126,7 +126,7 @@ void psort::finalize(pdecl_manager & m) { void psort::reset_cache(pdecl_manager& m) { m.del_inst_cache(m_inst_cache); - m_inst_cache = 0; + m_inst_cache = nullptr; } /** @@ -269,7 +269,7 @@ psort_decl::psort_decl(unsigned id, unsigned num_params, pdecl_manager & m, symb pdecl(id, num_params), m_name(n), m_psort_kind(PSORT_BASE), - m_inst_cache(0) { + m_inst_cache(nullptr) { } void psort_decl::finalize(pdecl_manager & m) { @@ -278,7 +278,7 @@ void psort_decl::finalize(pdecl_manager & m) { void psort_decl::reset_cache(pdecl_manager& m) { m.del_inst_cache(m_inst_cache); - m_inst_cache = 0; + m_inst_cache = nullptr; } void psort_decl::cache(pdecl_manager & m, sort * const * s, sort * r) { @@ -289,7 +289,7 @@ void psort_decl::cache(pdecl_manager & m, sort * const * s, sort * r) { sort * psort_decl::find(sort * const * s) { if (!m_inst_cache) - return 0; + return nullptr; return m_inst_cache->find(s); } @@ -303,7 +303,7 @@ psort_user_decl::psort_user_decl(unsigned id, unsigned num_params, pdecl_manager void psort_user_decl::finalize(pdecl_manager & m) { m.dec_ref(m_def); - m_def = 0; + m_def = nullptr; psort_decl::finalize(m); } @@ -312,7 +312,7 @@ sort * psort_user_decl::instantiate(pdecl_manager & m, unsigned n, sort * const sort * r = find(s); if (r) return r; - if (m_def == 0) { + if (m_def == nullptr) { buffer ps; for (unsigned i = 0; i < n; i++) ps.push_back(parameter(s[i])); @@ -462,7 +462,7 @@ accessor_decl * paccessor_decl::instantiate_decl(pdecl_manager & m, sort * const default: // missing refs must have been eliminated. UNREACHABLE(); - return 0; + return nullptr; } } @@ -522,7 +522,7 @@ pdatatype_decl::pdatatype_decl(unsigned id, unsigned num_params, pdecl_manager & symbol const & n, unsigned num_constructors, pconstructor_decl * const * constructors): psort_decl(id, num_params, m, n), m_constructors(num_constructors, constructors), - m_parent(0) { + m_parent(nullptr) { m.inc_ref(num_constructors, constructors); } @@ -633,7 +633,7 @@ bool pdatatype_decl::commit(pdecl_manager& m) { TRACE("datatype", tout << m_name << "\n";); sort_ref_vector ps(m.m()); for (unsigned i = 0; i < m_num_params; ++i) { - ps.push_back(m.m().mk_uninterpreted_sort(symbol(i), 0, 0)); + ps.push_back(m.m().mk_uninterpreted_sort(symbol(i), 0, nullptr)); } datatype_decl_buffer dts; dts.m_buffer.push_back(instantiate_decl(m, ps.c_ptr())); @@ -712,7 +712,7 @@ bool pdatatypes_decl::commit(pdecl_manager& m) { for (pdatatype_decl* d : m_datatypes) { sort_ref_vector ps(m.m()); for (unsigned i = 0; i < d->get_num_params(); ++i) { - ps.push_back(m.m().mk_uninterpreted_sort(symbol(i), 0, 0)); + ps.push_back(m.m().mk_uninterpreted_sort(symbol(i), 0, nullptr)); } dts.m_buffer.push_back(d->instantiate_decl(m, ps.c_ptr())); } @@ -834,7 +834,7 @@ void pdecl_manager::init_list() { ptype ListT(0); paccessor_decl * as[2] = { mk_paccessor_decl(1, symbol("head"), T), mk_paccessor_decl(1, symbol("tail"), ListT) }; - pconstructor_decl * cs[2] = { mk_pconstructor_decl(1, symbol("nil"), symbol("is-nil"), 0, 0), + pconstructor_decl * cs[2] = { mk_pconstructor_decl(1, symbol("nil"), symbol("is-nil"), 0, nullptr), mk_pconstructor_decl(1, symbol("insert"), symbol("is-insert"), 2, as) }; m_list = mk_pdatatype_decl(1, symbol("List"), 2, cs); inc_ref(m_list); @@ -844,8 +844,8 @@ void pdecl_manager::init_list() { pdecl_manager::pdecl_manager(ast_manager & m): m_manager(m), m_allocator(m.get_allocator()), - m_new_dt_eh(0) { - m_list = 0; + m_new_dt_eh(nullptr) { + m_list = nullptr; m_datatype_fid = m.mk_family_id("datatype"); } @@ -857,7 +857,7 @@ pdecl_manager::~pdecl_manager() { } psort * pdecl_manager::mk_psort_cnst(sort * s) { - psort * r = 0; + psort * r = nullptr; if (m_sort2psort.find(s, r)) return r; r = new (a().allocate(sizeof(psort_sort))) psort_sort(m_id_gen.mk(), *this, s); @@ -907,9 +907,9 @@ psort * pdecl_manager::mk_psort_app(unsigned num_params, psort_decl * d, unsigne psort * pdecl_manager::mk_psort_app(psort_decl * d) { SASSERT(d->get_num_params() == 0 || d->get_num_params() == PSORT_DECL_VAR_PARAMS); - sort * s = d->instantiate(*this, 0, static_cast(0)); - if (s == 0) - return 0; + sort * s = d->instantiate(*this, 0, static_cast(nullptr)); + if (s == nullptr) + return nullptr; return mk_psort_cnst(s); } @@ -1010,7 +1010,7 @@ void pdecl_manager::reset_sort_info() { } void pdecl_manager::display(std::ostream & out, sort * s) const { - sort_info * info = 0; + sort_info * info = nullptr; if (m_sort2info.find(s, info)) { info->display(out, *this); return; @@ -1019,7 +1019,7 @@ void pdecl_manager::display(std::ostream & out, sort * s) const { } format * pdecl_manager::pp(sort * s) const { - sort_info * info = 0; + sort_info * info = nullptr; if (m_sort2info.find(s, info)) { return info->pp(*this); } diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index d6fea179d..12e6399fe 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -64,7 +64,7 @@ class psort : public pdecl { protected: psort_inst_cache * m_inst_cache; friend class pdecl_manager; - psort(unsigned id, unsigned num_params):pdecl(id, num_params), m_inst_cache(0) {} + psort(unsigned id, unsigned num_params):pdecl(id, num_params), m_inst_cache(nullptr) {} bool is_psort() const override { return true; } void finalize(pdecl_manager & m) override; ~psort() override {} @@ -72,7 +72,7 @@ protected: virtual sort * find(sort * const * s) const; public: virtual bool is_sort_wrapper() const { return false; } - virtual sort * instantiate(pdecl_manager & m, sort * const * s) { return 0; } + virtual sort * instantiate(pdecl_manager & m, sort * const * s) { return nullptr; } // we use hash-consing for psorts. virtual char const * hcons_kind() const = 0; virtual unsigned hcons_hash() const = 0; @@ -102,8 +102,8 @@ protected: ~psort_decl() override {} public: virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s) = 0; - virtual sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) { return 0; } - virtual sort * instantiate(pdecl_manager & m) { return instantiate(m, 0, static_cast(0)); } + virtual sort * instantiate(pdecl_manager & m, unsigned n, unsigned const * s) { return nullptr; } + virtual sort * instantiate(pdecl_manager & m) { return instantiate(m, 0, static_cast(nullptr)); } // return true if the declaration accepts a variable number of parameters. // Only builtin declarations can have a variable number of parameters. bool has_var_params() const { return m_num_params == PSORT_DECL_VAR_PARAMS; } @@ -172,7 +172,7 @@ class ptype { }; symbol m_missing_ref; public: - ptype():m_kind(PTR_PSORT), m_sort(0) {} + ptype():m_kind(PTR_PSORT), m_sort(nullptr) {} ptype(int idx):m_kind(PTR_REC_REF), m_idx(idx) {} ptype(psort * s):m_kind(PTR_PSORT), m_sort(s) {} ptype(symbol const & s):m_kind(PTR_MISSING_REF), m_missing_ref(s) {} diff --git a/src/cmd_context/simplify_cmd.cpp b/src/cmd_context/simplify_cmd.cpp index 999351d25..de548562e 100644 --- a/src/cmd_context/simplify_cmd.cpp +++ b/src/cmd_context/simplify_cmd.cpp @@ -42,7 +42,7 @@ class simplify_cmd : public parametric_cmd { } m_solver->push(); m_solver->assert_expr(e); - lbool r = m_solver->check_sat(0,0); + lbool r = m_solver->check_sat(0,nullptr); m_solver->pop(1); return r; } @@ -71,11 +71,11 @@ public: void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); - m_target = 0; + m_target = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - if (m_target == 0) return CPK_EXPR; + if (m_target == nullptr) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } @@ -84,7 +84,7 @@ public: } void execute(cmd_context & ctx) override { - if (m_target == 0) + if (m_target == nullptr) throw cmd_exception("invalid simplify command, argument expected"); expr_ref r(ctx.m()); proof_ref pr(ctx.m()); diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index f35267714..32a92ea59 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -55,13 +55,13 @@ class declare_tactic_cmd : public cmd { public: declare_tactic_cmd(): cmd("declare-tactic"), - m_decl(0) { + m_decl(nullptr) { } char const * get_usage() const override { return " "; } char const * get_descr(cmd_context & ctx) const override { return "declare a new tactic, use (help-tactic) for the tactic language syntax."; } unsigned get_arity() const override { return 2; } - void prepare(cmd_context & ctx) override { m_name = symbol::null; m_decl = 0; } + void prepare(cmd_context & ctx) override { m_name = symbol::null; m_decl = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { if (m_name == symbol::null) return CPK_SYMBOL; return CPK_SEXPR; @@ -137,11 +137,11 @@ public: void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); - m_tactic = 0; + m_tactic = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - if (m_tactic == 0) return CPK_SEXPR; + if (m_tactic == nullptr) return CPK_SEXPR; return parametric_cmd::next_arg_kind(ctx); } @@ -597,9 +597,9 @@ static tactic * mk_echo(cmd_context & ctx, sexpr * n) { if (curr->is_string()) t = mk_echo_tactic(ctx, curr->get_string().c_str(), last); else - t = mk_probe_value_tactic(ctx, 0, sexpr2probe(ctx, curr), last); + t = mk_probe_value_tactic(ctx, nullptr, sexpr2probe(ctx, curr), last); tactic * new_res; - if (res.get() == 0) + if (res.get() == nullptr) new_res = t; else new_res = and_then(res.get(), t); @@ -608,7 +608,7 @@ static tactic * mk_echo(cmd_context & ctx, sexpr * n) { res = new_res; } UNREACHABLE(); - return 0; + return nullptr; } static tactic * mk_fail_if_branching(cmd_context & ctx, sexpr * n) { @@ -665,10 +665,10 @@ static tactic * mk_skip_if_failed(cmd_context & ctx, sexpr * n) { tactic * sexpr2tactic(cmd_context & ctx, sexpr * n) { if (n->is_symbol()) { tactic_cmd * cmd = ctx.find_tactic_cmd(n->get_symbol()); - if (cmd != 0) + if (cmd != nullptr) return cmd->mk(ctx.m()); sexpr * decl = ctx.find_user_tactic(n->get_symbol()); - if (decl != 0) + if (decl != nullptr) return sexpr2tactic(ctx, decl); throw cmd_exception("invalid tactic, unknown tactic ", n->get_symbol(), n->get_line(), n->get_pos()); } @@ -778,7 +778,7 @@ MK_NARY_PROBE(mk_mul); probe * sexpr2probe(cmd_context & ctx, sexpr * n) { if (n->is_symbol()) { probe_info * pinfo = ctx.find_probe(n->get_symbol()); - if (pinfo != 0) + if (pinfo != nullptr) return pinfo->get(); throw cmd_exception("invalid probe, unknown builtin probe ", n->get_symbol(), n->get_line(), n->get_pos()); } diff --git a/src/cmd_context/tactic_manager.cpp b/src/cmd_context/tactic_manager.cpp index 94b5e35ab..d4b3374b4 100644 --- a/src/cmd_context/tactic_manager.cpp +++ b/src/cmd_context/tactic_manager.cpp @@ -38,13 +38,13 @@ void tactic_manager::insert(probe_info * p) { } tactic_cmd * tactic_manager::find_tactic_cmd(symbol const & s) const { - tactic_cmd * c = 0; + tactic_cmd * c = nullptr; m_name2tactic.find(s, c); return c; } probe_info * tactic_manager::find_probe(symbol const & s) const { - probe_info * p = 0; + probe_info * p = nullptr; m_name2probe.find(s, p); return p; } diff --git a/src/duality/duality.h b/src/duality/duality.h index bb736feb9..9bf323d8b 100644 --- a/src/duality/duality.h +++ b/src/duality/duality.h @@ -199,7 +199,7 @@ namespace Duality { lbool interpolate_tree(TermTree *assumptions, TermTree *&interpolants, model &_model, - TermTree *goals = 0, + TermTree *goals = nullptr, bool weak = false ) = 0; @@ -247,7 +247,7 @@ namespace Duality { lbool interpolate_tree(TermTree *assumptions, TermTree *&interpolants, model &_model, - TermTree *goals = 0, + TermTree *goals = nullptr, bool weak = false) override { literals _labels; @@ -393,7 +393,7 @@ namespace Duality { edgeCount = 0; stack.push_back(stack_entry()); HornClauses = false; - proof_core = 0; + proof_core = nullptr; } virtual ~RPFP(); @@ -494,7 +494,7 @@ namespace Duality { unsigned recursion_bound; Node(const FuncDecl &_Name, const Transformer &_Annotation, const Transformer &_Bound, const Transformer &_Underapprox, const Term &_dual, RPFP *_owner, int _number) - : Name(_Name), Annotation(_Annotation), Bound(_Bound), Underapprox(_Underapprox), dual(_dual) {owner = _owner; number = _number; Outgoing = 0; recursion_bound = UINT_MAX;} + : Name(_Name), Annotation(_Annotation), Bound(_Bound), Underapprox(_Underapprox), dual(_dual) {owner = _owner; number = _number; Outgoing = nullptr; recursion_bound = UINT_MAX;} }; /** Create a node in the graph. The input is a term R(v_1...v_n) @@ -591,7 +591,7 @@ namespace Duality { /** Delete a hyper-edge and unlink it from any nodes. */ void DeleteEdge(Edge *edge){ if(edge->Parent) - edge->Parent->Outgoing = 0; + edge->Parent->Outgoing = nullptr; for(unsigned int i = 0; i < edge->Children.size(); i++){ std::vector &ic = edge->Children[i]->Incoming; for(std::vector::iterator it = ic.begin(), en = ic.end(); it != en; ++it){ @@ -705,7 +705,7 @@ namespace Duality { /** Get the constraint tree (but don't solve it) */ - TermTree *GetConstraintTree(Node *root, Node *skip_descendant = 0); + TermTree *GetConstraintTree(Node *root, Node *skip_descendant = nullptr); /** Dispose of the dual model (counterexample) if there is one. */ @@ -715,7 +715,7 @@ namespace Duality { * Solve, except no primal solution (interpolant) is generated in the unsat case. */ check_result Check(Node *root, std::vector underapproxes = std::vector(), - std::vector *underapprox_core = 0); + std::vector *underapprox_core = nullptr); /** Update the model, attempting to make the propositional literals in assumps true. If possible, return sat, else return unsat and keep the old model. */ @@ -841,7 +841,7 @@ namespace Duality { #ifdef _WINDOWS __declspec(dllexport) #endif - void FromClauses(const std::vector &clauses, const std::vector *bounds = 0); + void FromClauses(const std::vector &clauses, const std::vector *bounds = nullptr); void FromFixpointContext(fixedpoint fp, std::vector &queries); @@ -927,7 +927,7 @@ namespace Duality { void ClearProofCore(){ if(proof_core) delete proof_core; - proof_core = 0; + proof_core = nullptr; } Term SuffixVariable(const Term &t, int n); @@ -944,7 +944,7 @@ namespace Duality { Term ReducedDualEdge(Edge *e); - TermTree *ToTermTree(Node *root, Node *skip_descendant = 0); + TermTree *ToTermTree(Node *root, Node *skip_descendant = nullptr); TermTree *ToGoalTree(Node *root); @@ -1096,12 +1096,12 @@ namespace Duality { virtual void slvr_push(); - virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0); + virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = nullptr, unsigned *core_size = nullptr, expr *core = nullptr); virtual lbool ls_interpolate_tree(TermTree *assumptions, TermTree *&interpolants, model &_model, - TermTree *goals = 0, + TermTree *goals = nullptr, bool weak = false); virtual bool proof_core_contains(const expr &e); @@ -1121,8 +1121,8 @@ namespace Duality { RPFP::Node *root; public: Counterexample(){ - tree = 0; - root = 0; + tree = nullptr; + root = nullptr; } Counterexample(RPFP *_tree, RPFP::Node *_root){ tree = _tree; @@ -1142,7 +1142,7 @@ namespace Duality { } void clear(){ if(tree) delete tree; - tree = 0; + tree = nullptr; } RPFP *get_tree() const {return tree;} RPFP::Node *get_root() const {return root;} @@ -1313,7 +1313,7 @@ namespace Duality { - void GetAssumptionLits(const expr &fmla, std::vector &lits, hash_map *opt_map = 0); + void GetAssumptionLits(const expr &fmla, std::vector &lits, hash_map *opt_map = nullptr); void GreedyReduceCache(std::vector &assumps, std::vector &core); @@ -1326,12 +1326,12 @@ namespace Duality { void slvr_push() override; - check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0) override; + check_result slvr_check(unsigned n = 0, expr * const assumptions = nullptr, unsigned *core_size = nullptr, expr *core = nullptr) override; lbool ls_interpolate_tree(TermTree *assumptions, TermTree *&interpolants, model &_model, - TermTree *goals = 0, + TermTree *goals = nullptr, bool weak = false) override; bool proof_core_contains(const expr &e) override; diff --git a/src/duality/duality_profiling.cpp b/src/duality/duality_profiling.cpp old mode 100755 new mode 100644 index 2e659f0a1..6bb995e2d --- a/src/duality/duality_profiling.cpp +++ b/src/duality/duality_profiling.cpp @@ -55,7 +55,7 @@ namespace Duality { node::node(){ time = 0; - parent = 0; + parent = nullptr; } struct node *current; diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp old mode 100755 new mode 100644 index 5180e1315..3358eb45e --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -1345,8 +1345,8 @@ namespace Duality { { timer_start("Solve"); TermTree *tree = GetConstraintTree(root); - TermTree *interpolant = NULL; - TermTree *goals = NULL; + TermTree *interpolant = nullptr; + TermTree *goals = nullptr; if(ls->need_goals) goals = GetGoalTree(root); ClearProofCore(); @@ -1396,11 +1396,11 @@ namespace Duality { timer_start("Solve"); TermTree *tree = CollapseTermTree(GetConstraintTree(root,node)); tree->getChildren().push_back(CollapseTermTree(ToTermTree(node))); - TermTree *interpolant = NULL; + TermTree *interpolant = nullptr; ClearProofCore(); timer_start("interpolate_tree"); - lbool res = ls_interpolate_tree(tree, interpolant, dualModel,0,true); + lbool res = ls_interpolate_tree(tree, interpolant, dualModel,nullptr,true); timer_stop("interpolate_tree"); if (res == l_false) { DecodeTree(node, interpolant->getChildren()[0], 0); @@ -1423,7 +1423,7 @@ namespace Duality { void RPFP::DisposeDualModel() { - dualModel = model(ctx,NULL); + dualModel = model(ctx,nullptr); } RPFP::Term RPFP::UnderapproxFlag(Node *n){ @@ -3281,9 +3281,9 @@ namespace Duality { { stack_entry &back = stack.back(); for(std::list::iterator it = back.edges.begin(), en = back.edges.end(); it != en; ++it) - (*it)->dual = expr(ctx,NULL); + (*it)->dual = expr(ctx,nullptr); for(std::list::iterator it = back.nodes.begin(), en = back.nodes.end(); it != en; ++it) - (*it)->dual = expr(ctx,NULL); + (*it)->dual = expr(ctx,nullptr); for(std::list >::iterator it = back.constraints.begin(), en = back.constraints.end(); it != en; ++it) (*it).first->constraints.pop_back(); stack.pop_back(); diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp index 66bcf4ab3..7782f4a8b 100644 --- a/src/duality/duality_solver.cpp +++ b/src/duality/duality_solver.cpp @@ -126,10 +126,10 @@ namespace Duality { edges(_rpfp->edges) { rpfp = _rpfp; - reporter = 0; - conj_reporter = 0; - heuristic = 0; - unwinding = 0; + reporter = nullptr; + conj_reporter = nullptr; + heuristic = nullptr; + unwinding = nullptr; FullExpand = false; NoConj = false; FeasibleEdges = true; @@ -330,7 +330,7 @@ namespace Duality { void PreSolve(){ reporter = Report ? CreateStdoutReporter(rpfp) : new Reporter(rpfp); - conj_reporter = ConjectureFile.empty() ? 0 : CreateConjectureFileReporter(rpfp,ConjectureFile); + conj_reporter = ConjectureFile.empty() ? nullptr : CreateConjectureFileReporter(rpfp,ConjectureFile); #ifndef LOCALIZE_CONJECTURES heuristic = !cex.get_tree() ? new Heuristic(rpfp) : new ReplayHeuristic(rpfp,cex); #else @@ -524,7 +524,7 @@ namespace Duality { node->Annotation.SetFull(); // allow this node to cover others else updated_nodes.insert(node); - e->map = 0; + e->map = nullptr; reporter->Extend(node); #ifdef EARLY_EXPAND if(!do_not_expand) @@ -537,7 +537,7 @@ namespace Duality { node->Annotation.SetFull(); Edge *e = unwinding->CreateLowerBoundEdge(node); overapproxes.insert(node); - e->map = 0; + e->map = nullptr; } /** We start the unwinding with leaves that under-approximate @@ -1144,14 +1144,14 @@ namespace Duality { Edge *e = unwinding->CreateLowerBoundEdge(under_node); under_node->Annotation.SetFull(); // allow this node to cover others back_edges[under_node] = back_edges[node]; - e->map = 0; + e->map = nullptr; reporter->Extend(under_node); return under_node; } /** Try to prove a conjecture about a node. If successful update the unwinding annotation appropriately. */ - bool ProveConjecture(Node *node, const RPFP::Transformer &t,Node *other = 0, Counterexample *_cex = 0){ + bool ProveConjecture(Node *node, const RPFP::Transformer &t,Node *other = nullptr, Counterexample *_cex = nullptr){ reporter->Conjecture(node,t); timer_start("ProveConjecture"); RPFP::Transformer save = node->Bound; @@ -1245,7 +1245,7 @@ namespace Duality { marker_disjunction = marker_disjunction || marker; } - bool GenNodeSolutionWithMarkers(Node *node, RPFP::Transformer &annot, bool expanded_only = false, Node *other_node = 0){ + bool GenNodeSolutionWithMarkers(Node *node, RPFP::Transformer &annot, bool expanded_only = false, Node *other_node = nullptr){ bool res = false; annot.SetFull(); expr marker_disjunction = ctx.bool_val(false); @@ -1267,14 +1267,14 @@ namespace Duality { Node *root = checker->CloneNode(edge->Parent); GenNodeSolutionFromIndSet(edge->Parent, root->Bound); if(root->Bound.IsFull()) - return 0; + return nullptr; checker->AssertNode(root); std::vector cs; for(unsigned j = 0; j < edge->Children.size(); j++){ Node *oc = edge->Children[j]; Node *nc = checker->CloneNode(oc); if(!GenNodeSolutionWithMarkers(oc,nc->Annotation,expanded_only)) - return 0; + return nullptr; Edge *e = checker->CreateLowerBoundEdge(nc); checker->AssertEdge(e); cs.push_back(nc); @@ -1873,7 +1873,7 @@ namespace Duality { mode. */ - bool Derive(RPFP *rpfp, RPFP::Node *root, bool _underapprox, bool _constrained = false, RPFP *_tree = 0){ + bool Derive(RPFP *rpfp, RPFP::Node *root, bool _underapprox, bool _constrained = false, RPFP *_tree = nullptr){ underapprox = _underapprox; constrained = _constrained; false_approx = true; @@ -2608,7 +2608,7 @@ namespace Duality { bool dominated; std::set dominates; cover_info(){ - covered_by = 0; + covered_by = nullptr; dominated = false; } }; @@ -2708,7 +2708,7 @@ namespace Duality { for(std::vector::iterator it = cs.begin(), en = cs.end(); it != en; it++){ Node *other = *it; if(covered_by(other) && CoverOrder(node,other)){ - covered_by(other) = 0; + covered_by(other) = nullptr; reporter()->RemoveCover(*it,node); } } @@ -2934,7 +2934,7 @@ namespace Duality { #else Node *GetSimilarNode(Node *node){ if(!some_updates) - return 0; + return nullptr; std::vector &insts = insts_of_node(node->map); for(int i = insts.size() - 1; i >= 0; i--){ Node *other = insts[i]; @@ -2942,19 +2942,19 @@ namespace Duality { && !IsCovered(other)) return other; } - return 0; + return nullptr; } #endif bool Dominates(Node * node, Node *other){ if(node == other) return false; - if(other->Outgoing->map == 0) return true; + if(other->Outgoing->map == nullptr) return true; if(node->Outgoing->map == other->Outgoing->map){ assert(node->Outgoing->Children.size() == other->Outgoing->Children.size()); for(unsigned i = 0; i < node->Outgoing->Children.size(); i++){ Node *nc = node->Outgoing->Children[i]; Node *oc = other->Outgoing->Children[i]; - if(!(nc == oc || oc->Outgoing->map ==0 || dominates(nc,oc))) + if(!(nc == oc || oc->Outgoing->map ==nullptr || dominates(nc,oc))) return false; } return true; @@ -3088,7 +3088,7 @@ namespace Duality { LocalHeuristic(RPFP *_rpfp) : Heuristic(_rpfp) { - old_node = 0; + old_node = nullptr; } void SetOldNode(RPFP::Node *_old_node){ @@ -3100,7 +3100,7 @@ namespace Duality { hash_map cex_map; void ChooseExpand(const std::set &choices, std::set &best, bool, bool) override { - if(old_node == 0){ + if(old_node == nullptr){ Heuristic::ChooseExpand(choices,best); return; } diff --git a/src/duality/duality_wrapper.cpp b/src/duality/duality_wrapper.cpp old mode 100755 new mode 100644 index 4493beddf..17adbdcea --- a/src/duality/duality_wrapper.cpp +++ b/src/duality/duality_wrapper.cpp @@ -111,7 +111,7 @@ namespace Duality { } expr context::mki(family_id fid, ::decl_kind dk, int n, ::expr **args){ - return cook(m().mk_app(fid, dk, 0, 0, n, (::expr **)args)); + return cook(m().mk_app(fid, dk, 0, nullptr, n, (::expr **)args)); } expr context::make(decl_kind op, const std::vector &args){ @@ -120,11 +120,11 @@ namespace Duality { a.resize(args.size()); for(unsigned i = 0; i < args.size(); i++) a[i] = to_expr(args[i].raw()); - return make(op,args.size(), args.size() ? VEC2PTR(a) : 0); + return make(op,args.size(), args.size() ? VEC2PTR(a) : nullptr); } expr context::make(decl_kind op){ - return make(op,0,0); + return make(op,0,nullptr); } expr context::make(decl_kind op, const expr &arg0){ @@ -173,8 +173,8 @@ namespace Duality { 0, ::symbol(), ::symbol(), - 0, 0, - 0, 0 + 0, nullptr, + 0, nullptr ); return cook(result.get()); } @@ -199,8 +199,8 @@ namespace Duality { 0, ::symbol(), ::symbol(), - 0, 0, - 0, 0 + 0, nullptr, + 0, nullptr ); return cook(result.get()); } @@ -422,7 +422,7 @@ namespace Duality { func_decl context::fresh_func_decl(char const * prefix, sort const & range){ ::func_decl* d = m().mk_fresh_func_decl(prefix, 0, - 0, + nullptr, to_sort(range.raw())); return func_decl(*this,d); } diff --git a/src/duality/duality_wrapper.h b/src/duality/duality_wrapper.h index 18b6948d5..69f821a08 100644 --- a/src/duality/duality_wrapper.h +++ b/src/duality/duality_wrapper.h @@ -276,7 +276,7 @@ namespace Duality { protected: context * m_ctx; public: - object(): m_ctx((context *)0) {} + object(): m_ctx((context *)nullptr) {} object(context & c):m_ctx(&c) {} object(object const & s):m_ctx(s.m_ctx) {} context & ctx() const { return *m_ctx; } @@ -317,9 +317,9 @@ namespace Duality { ::ast *_ast; public: ::ast * const &raw() const {return _ast;} - ast_i(context & c, ::ast *a = 0) : object(c) {_ast = a;} + ast_i(context & c, ::ast *a = nullptr) : object(c) {_ast = a;} - ast_i(){_ast = 0;} + ast_i(){_ast = nullptr;} bool eq(const ast_i &other) const { return _ast == other._ast; } @@ -346,7 +346,7 @@ namespace Duality { friend bool eq(ast const & a, ast const & b) { return a.raw() == b.raw(); } - ast(context &c, ::ast *a = 0) : ast_i(c,a) { + ast(context &c, ::ast *a = nullptr) : ast_i(c,a) { if(_ast) m().inc_ref(a); } @@ -729,7 +729,7 @@ namespace Duality { m_model = m; } public: - model(context & c, ::model * m = 0):object(c), m_model(m) { } + model(context & c, ::model * m = nullptr):object(c), m_model(m) { } model(model const & s):object(s), m_model(s.m_model) { } ~model() { } operator ::model *() const { return m_model.get(); } @@ -869,28 +869,28 @@ namespace Duality { check_result check() { scoped_proof_mode spm(m(),m_mode); checkpoint(); - lbool r = m_solver->check_sat(0,0); + lbool r = m_solver->check_sat(0,nullptr); model_ref m; m_solver->get_model(m); the_model = m.get(); return to_check_result(r); } - check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) { + check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = nullptr, expr *core = nullptr) { scoped_proof_mode spm(m(),m_mode); model old_model(the_model); check_result res = check(n,assumptions,core_size,core); - if(the_model == 0) + if(the_model == nullptr) the_model = old_model; return res; } - check_result check(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) { + check_result check(unsigned n, expr * const assumptions, unsigned *core_size = nullptr, expr *core = nullptr) { scoped_proof_mode spm(m(),m_mode); checkpoint(); std::vector< ::expr *> _assumptions(n); for (unsigned i = 0; i < n; i++) { _assumptions[i] = to_expr(assumptions[i]); } - the_model = 0; + the_model = nullptr; lbool r = m_solver->check_sat(n, VEC2PTR(_assumptions)); if(core_size && core){ @@ -1228,7 +1228,7 @@ namespace Duality { return operator()(args.size(), VEC2PTR(args)); } inline expr func_decl::operator()() const { - return operator()(0,0); + return operator()(0,nullptr); } inline expr func_decl::operator()(expr const & a) const { return operator()(1,&a); @@ -1413,7 +1413,7 @@ namespace Duality { template class uptr { public: X *ptr; - uptr(){ptr = 0;} + uptr(){ptr = nullptr;} void set(X *_ptr){ if(ptr) delete ptr; ptr = _ptr; diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp old mode 100755 new mode 100644 index b9284b869..43e7bdff8 --- a/src/interp/iz3base.cpp +++ b/src/interp/iz3base.cpp @@ -272,7 +272,7 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v for(unsigned i = 0; i < q.size(); i++) s.assert_expr(to_expr(q[i].raw())); - lbool res = s.check_sat(0,0); + lbool res = s.check_sat(0,nullptr); if (m().canceled()) { throw iz3_exception(Z3_CANCELED_MSG); } @@ -293,7 +293,7 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v vars[i] = cook(r.get()); } } - solver = 0; + solver = nullptr; return res != l_false; } diff --git a/src/interp/iz3checker.cpp b/src/interp/iz3checker.cpp old mode 100755 new mode 100644 index 8fa99fe10..cfea511ad --- a/src/interp/iz3checker.cpp +++ b/src/interp/iz3checker.cpp @@ -98,7 +98,7 @@ struct iz3checker : iz3base { s->assert_expr(to_expr(itp[cs[j]].raw())); if(i != num-1) s->assert_expr(to_expr(mk_not(itp[i]).raw())); - lbool result = s->check_sat(0,0); + lbool result = s->check_sat(0,nullptr); if(result != l_false){ err << "interpolant " << i << " is incorrect"; @@ -110,7 +110,7 @@ struct iz3checker : iz3base { s->assert_expr(to_expr(cnsts[j].raw())); if(i != num-1) s->assert_expr(to_expr(mk_not(itp[i]).raw())); - lbool result = s->check_sat(0,0); + lbool result = s->check_sat(0,nullptr); if(result != l_false) err << "interpolant " << i << " is not implied by its downeard closurn"; diff --git a/src/interp/iz3hash.h b/src/interp/iz3hash.h index c796a247b..f85242ed1 100644 --- a/src/interp/iz3hash.h +++ b/src/interp/iz3hash.h @@ -132,7 +132,7 @@ namespace hash_space { Entry* next; Value val; - Entry(const Value &_val) : val(_val) {next = 0;} + Entry(const Value &_val) : val(_val) {next = nullptr;} }; @@ -242,7 +242,7 @@ namespace hash_space { public: - hashtable(size_t init_size) : buckets(init_size,(Entry *)0) { + hashtable(size_t init_size) : buckets(init_size,(Entry *)nullptr) { entries = 0; } @@ -281,7 +281,7 @@ namespace hash_space { } iterator end() { - return iterator(0, this); + return iterator(nullptr, this); } const_iterator begin() const { @@ -292,7 +292,7 @@ namespace hash_space { } const_iterator end() const { - return const_iterator(0, this); + return const_iterator(nullptr, this); } size_t get_bucket(const Value& val, size_t n) const { @@ -318,7 +318,7 @@ namespace hash_space { if (key_eq_fun(get_key(ent->val), get_key(val))) return ent; - if(!ins) return 0; + if(!ins) return nullptr; Entry* tmp = new Entry(val); tmp->next = from; @@ -336,7 +336,7 @@ namespace hash_space { if (key_eq_fun(get_key(ent->val), key)) return ent; - return 0; + return nullptr; } const_iterator find(const Key& key) const { @@ -381,7 +381,7 @@ namespace hash_space { if (new_size <= old_n) return; const size_t n = next_prime(new_size); if (n <= old_n) return; - Table tmp(n, (Entry*)(0)); + Table tmp(n, (Entry*)nullptr); for (size_t i = 0; i < old_n; ++i) { Entry* ent = buckets[i]; while (ent) { @@ -398,12 +398,12 @@ namespace hash_space { void clear() { for (size_t i = 0; i < buckets.size(); ++i) { - for (Entry* ent = buckets[i]; ent != 0;) { + for (Entry* ent = buckets[i]; ent != nullptr;) { Entry* next = ent->next; delete ent; ent = next; } - buckets[i] = 0; + buckets[i] = nullptr; } entries = 0; } diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp old mode 100755 new mode 100644 index 91b0c5a63..3d1d84f3c --- a/src/interp/iz3interp.cpp +++ b/src/interp/iz3interp.cpp @@ -171,7 +171,7 @@ struct frame_reducer { template struct killme { T *p; - killme(){p = 0;} + killme(){p = nullptr;} void set(T *_p) {p = _p;} ~killme(){ if(p) @@ -205,7 +205,7 @@ public: const std::vector &parents, std::vector &interps, const std::vector &theory, - interpolation_options_struct *options = 0 + interpolation_options_struct *options = nullptr ){ #if 0 test_secondary(cnsts,parents,interps); @@ -229,7 +229,7 @@ public: parents_vec.clear(); // secondary prover no longer supported - iz3secondary *sp = NULL; + iz3secondary *sp = nullptr; #define BINARY_INTERPOLATION #ifndef BINARY_INTERPOLATION @@ -336,7 +336,7 @@ public: const std::vector &parents, std::vector &interps, const std::vector &theory, - interpolation_options_struct *options = 0 + interpolation_options_struct *options = nullptr ){ std::vector > cnsts_vec(cnsts.size()); for(unsigned i = 0; i < cnsts.size(); i++) @@ -350,7 +350,7 @@ public: const std::vector &_cnsts, const ast &tree, std::vector &interps, - interpolation_options_struct *options = 0 + interpolation_options_struct *options = nullptr ){ std::vector pos_map; @@ -524,7 +524,7 @@ lbool iz3interpolate(ast_manager &_m_manager, std::vector _cnsts; itp.assert_conjuncts(s,_cnsts,_tree); profiling::timer_start("solving"); - lbool res = s.check_sat(0,0); + lbool res = s.check_sat(0,nullptr); profiling::timer_stop("solving"); if(res == l_false){ ast *proof = s.get_proof(); diff --git a/src/interp/iz3interp.h b/src/interp/iz3interp.h index a4e1024a9..909703bed 100644 --- a/src/interp/iz3interp.h +++ b/src/interp/iz3interp.h @@ -78,7 +78,7 @@ void iz3interpolate(ast_manager &_m_manager, const ::vector &parents, ptr_vector &interps, const ptr_vector &theory, - interpolation_options_struct * options = 0); + interpolation_options_struct * options = nullptr); /* Same as above, but each constraint is a vector of formulas. */ @@ -88,7 +88,7 @@ void iz3interpolate(ast_manager &_m_manager, const ::vector &parents, ptr_vector &interps, const ptr_vector &theory, - interpolation_options_struct * options = 0); + interpolation_options_struct * options = nullptr); /* Compute an interpolant from a proof. This version uses the ast representation, for compatibility with the new API. Here, cnsts is diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp old mode 100755 new mode 100644 index 7314403b0..bb37d7f48 --- a/src/interp/iz3mgr.cpp +++ b/src/interp/iz3mgr.cpp @@ -102,7 +102,7 @@ iz3mgr::ast iz3mgr::make(opr op, int n, raw_ast **args){ } iz3mgr::ast iz3mgr::mki(family_id fid, decl_kind dk, int n, raw_ast **args){ - return cook(m().mk_app(fid, dk, 0, 0, n, (expr **)args)); + return cook(m().mk_app(fid, dk, 0, nullptr, n, (expr **)args)); } iz3mgr::ast iz3mgr::make(opr op, const std::vector &args){ @@ -111,11 +111,11 @@ iz3mgr::ast iz3mgr::make(opr op, const std::vector &args){ a.resize(args.size()); for(unsigned i = 0; i < args.size(); i++) a[i] = args[i].raw(); - return make(op,args.size(), args.size() ? &a[0] : 0); + return make(op,args.size(), args.size() ? &a[0] : nullptr); } iz3mgr::ast iz3mgr::make(opr op){ - return make(op,0,0); + return make(op,0,nullptr); } iz3mgr::ast iz3mgr::make(opr op, const ast &arg0){ @@ -148,11 +148,11 @@ iz3mgr::ast iz3mgr::make(symb sym, const std::vector &args){ a.resize(args.size()); for(unsigned i = 0; i < args.size(); i++) a[i] = args[i].raw(); - return make(sym,args.size(), args.size() ? &a[0] : 0); + return make(sym,args.size(), args.size() ? &a[0] : nullptr); } iz3mgr::ast iz3mgr::make(symb sym){ - return make(sym,0,0); + return make(sym,0,nullptr); } iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0){ @@ -201,8 +201,8 @@ iz3mgr::ast iz3mgr::make_quant(opr op, const std::vector &bvs, ast &body){ 0, symbol("itp"), symbol(), - 0, 0, - 0, 0 + 0, nullptr, + 0, nullptr ); return cook(result.get()); } diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h old mode 100755 new mode 100644 index 8de1a44e8..49552f92f --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -63,7 +63,7 @@ public: raw_ast * const &raw() const {return _ast;} ast_i(raw_ast *a){_ast = a;} - ast_i(){_ast = 0;} + ast_i(){_ast = nullptr;} bool eq(const ast_i &other) const { return _ast == other._ast; } @@ -92,7 +92,7 @@ public: m->inc_ref(a); } - ast_r() {_m = 0;} + ast_r() {_m = nullptr;} ast_r(const ast_r &other) : ast_i(other) { _m = other._m; @@ -287,7 +287,7 @@ class iz3mgr { symb sym(const ast& t){ raw_ast *_ast = t.raw(); - return is_app(_ast) ? to_app(_ast)->get_decl() : 0; + return is_app(_ast) ? to_app(_ast)->get_decl() : nullptr; } std::string string_of_symbol(symb s){ diff --git a/src/interp/iz3profiling.cpp b/src/interp/iz3profiling.cpp old mode 100755 new mode 100644 index df3126e4f..ba4fd0206 --- a/src/interp/iz3profiling.cpp +++ b/src/interp/iz3profiling.cpp @@ -75,7 +75,7 @@ namespace profiling { node::node(){ time = 0; - parent = 0; + parent = nullptr; } struct node *current; diff --git a/src/interp/iz3proof.h b/src/interp/iz3proof.h old mode 100755 new mode 100644 index ba4507ba2..a7dcb9b75 --- a/src/interp/iz3proof.h +++ b/src/interp/iz3proof.h @@ -210,7 +210,7 @@ class iz3proof { } /** Default constructor */ - iz3proof(){pv = 0;} + iz3proof(){pv = nullptr;} protected: diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp old mode 100755 new mode 100644 index 4196d2016..9680ec95e --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -2188,7 +2188,7 @@ void iz3translation_full_conc_symbols_out_of_scope(iz3translation_full *p, int i struct stdio_fixer { stdio_fixer(){ - std::cout.rdbuf()->pubsetbuf(0,0); + std::cout.rdbuf()->pubsetbuf(nullptr,0); } } my_stdio_fixer; diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp old mode 100755 new mode 100644 index 0d5b9ccc3..8c2016149 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -1124,7 +1124,7 @@ public: for(unsigned i = 0; i < la.size(); i++) lits.push_back(mk_not(from_ast(conc(la[i])))); // lits.push_back(from_ast(conc(proof))); - Iproof::node res =fix_lemma(lits,hyps, lemma_nll ? nll : 0); + Iproof::node res =fix_lemma(lits,hyps, lemma_nll ? nll : nullptr); for(unsigned i = 0; i < la.size(); i++){ Iproof::node q = translate_main(la[i],nll,false); ast pnode = from_ast(conc(la[i])); @@ -1200,7 +1200,7 @@ public: Iproof::node res = iproof->make_contra(ipf,lits); for(unsigned i = 0; i < la.size(); i++){ - Iproof::node q = translate_main(la[i],0,false); + Iproof::node q = translate_main(la[i],nullptr,false); ast pnode = from_ast(conc(la[i])); assert(is_local(pnode) || equivs.find(pnode) != equivs.end()); Iproof::node neg = res; @@ -1381,8 +1381,8 @@ public: non_local_lits *find_nll(ResolventAppSet &proofs){ if(proofs.empty()) - return (non_local_lits *)0; - std::pair foo(non_local_lits(proofs),(non_local_lits *)0); + return (non_local_lits *)nullptr; + std::pair foo(non_local_lits(proofs),(non_local_lits *)nullptr); std::pair::iterator,bool> bar = non_local_lits_unique.insert(foo); non_local_lits *&res = bar.first->second; @@ -1392,7 +1392,7 @@ public: } Z3_resolvent *find_resolvent(ast proof, bool unit, ast pivot){ - std::pair foo(Z3_resolvent(proof,unit,pivot),(Z3_resolvent *)0); + std::pair foo(Z3_resolvent(proof,unit,pivot),(Z3_resolvent *)nullptr); std::pair::iterator,bool> bar = Z3_resolvent_unique.insert(foo); Z3_resolvent *&res = bar.first->second; @@ -1613,7 +1613,7 @@ public: Iproof::node translate(ast proof, Iproof &dst) override { iproof = &dst; - Iproof::node Ipf = translate_main(proof,0); // builds result in dst + Iproof::node Ipf = translate_main(proof,nullptr); // builds result in dst return Ipf; } diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index 41fc19907..de72d6b2d 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -43,7 +43,7 @@ public: unsigned m_src; unsigned m_dst; public: - move(M& m, unsigned s, unsigned d, T* t = 0): m(m), m_t(t), m_src(s), m_dst(d) { + move(M& m, unsigned s, unsigned d, T* t = nullptr): m(m), m_t(t), m_src(s), m_dst(d) { if (t) m.inc_ref(t); } ~move() { @@ -69,7 +69,7 @@ public: unsigned src() const { return m_src; } T* t() const { return m_t; } - bool is_epsilon() const { return m_t == 0; } + bool is_epsilon() const { return m_t == nullptr; } }; typedef vector moves; private: @@ -407,7 +407,7 @@ public: mvs1.push_back(move(m, mv1.src(), dst1, t)); } for (move const& mv1 : mvs1) { - remove(mv1.src(), dst, 0); + remove(mv1.src(), dst, nullptr); add(mv1); } remove(dst, dst1, t); @@ -431,7 +431,7 @@ public: else { continue; } - remove(src, dst, 0); + remove(src, dst, nullptr); --j; } } diff --git a/src/math/automata/symbolic_automata_def.h b/src/math/automata/symbolic_automata_def.h index be38a60bc..17a53fc33 100644 --- a/src/math/automata/symbolic_automata_def.h +++ b/src/math/automata/symbolic_automata_def.h @@ -399,7 +399,7 @@ typename symbolic_automata::automaton_t* symbolic_automata::mk_produ continue; } else if (is_sat == l_undef) { - return 0; + return nullptr; } unsigned_pair tgt_pair(mvsA[i].dst(), mvsB[j].dst()); unsigned tgt; diff --git a/src/math/euclid/euclidean_solver.cpp b/src/math/euclid/euclidean_solver.cpp index 1be239c36..70b424375 100644 --- a/src/math/euclid/euclidean_solver.cpp +++ b/src/math/euclid/euclidean_solver.cpp @@ -506,8 +506,8 @@ struct euclidean_solver::imp { } imp(numeral_manager * m): - m_manager(m == 0 ? alloc(numeral_manager) : m), - m_owns_m(m == 0), + m_manager(m == nullptr ? alloc(numeral_manager) : m), + m_owns_m(m == nullptr), m_decompose_buffer(*m_manager), m_as_buffer(*m_manager), m_bs_buffer(*m_manager), @@ -550,7 +550,7 @@ struct euclidean_solver::imp { return; equation * eq; if (j == null_justification) { - eq = mk_eq(num, as, xs, c, 0, 0, 0); + eq = mk_eq(num, as, xs, c, 0, nullptr, nullptr); } else { mpq one(1); @@ -694,7 +694,7 @@ struct euclidean_solver::imp { mpz new_c; decompose(m_next_pos_a, m_next_a, eq.m_c, new_c, eq.m_c); // create auxiliary equation - equation * new_eq = mk_eq(m_tmp_xs.size(), buffer.c_ptr(), m_tmp_xs.c_ptr(), new_c, 0, 0, 0, false); + equation * new_eq = mk_eq(m_tmp_xs.size(), buffer.c_ptr(), m_tmp_xs.c_ptr(), new_c, 0, nullptr, nullptr, false); // new_eq doesn't need to normalized, since it has unit coefficients TRACE("euclidean_solver", tout << "decomposition: new parameter x" << p << " aux eq:\n"; display(tout, *new_eq); tout << "\n"; diff --git a/src/math/grobner/grobner.cpp b/src/math/grobner/grobner.cpp index 3295c4eae..017f1cf77 100644 --- a/src/math/grobner/grobner.cpp +++ b/src/math/grobner/grobner.cpp @@ -29,7 +29,7 @@ grobner::grobner(ast_manager & m, v_dependency_manager & d): m_var_lt(m_var2weight), m_monomial_lt(m_var_lt), m_changed_leading_term(false), - m_unsat(0) { + m_unsat(nullptr) { } grobner::~grobner() { @@ -116,7 +116,7 @@ void grobner::reset() { m_to_process.reset(); m_equations_to_unfreeze.reset(); m_equations_to_delete.reset(); - m_unsat = 0; + m_unsat = nullptr; } void grobner::display_var(std::ostream & out, expr * var) const { @@ -410,7 +410,7 @@ void grobner::assert_monomial_tautology(expr * m) { m1->m_vars.push_back(m); eq->m_monomials.push_back(m1); normalize_coeff(eq->m_monomials); - init_equation(eq, static_cast(0)); \ + init_equation(eq, static_cast(nullptr)); \ m_to_process.insert(eq); } @@ -625,7 +625,7 @@ grobner::equation * grobner::copy_equation(equation const * eq) { grobner::equation * grobner::simplify(equation const * source, equation * target) { TRACE("grobner", tout << "simplifying: "; display_equation(tout, *target); tout << "using: "; display_equation(tout, *source);); if (source->get_num_monomials() == 0) - return 0; + return nullptr; m_stats.m_simplify++; bool result = false; bool simplified; @@ -676,7 +676,7 @@ grobner::equation * grobner::simplify(equation const * source, equation * target } while (simplified && !m_manager.canceled()); TRACE("grobner", tout << "result: "; display_equation(tout, *target);); - return result ? target : 0; + return result ? target : nullptr; } /** @@ -702,13 +702,13 @@ grobner::equation * grobner::simplify_using_processed(equation * eq) { eq = new_eq; } if (m_manager.canceled()) { - return 0; + return nullptr; } } } while (simplified); TRACE("grobner", tout << "simplification result: "; display_equation(tout, *eq);); - return result ? eq : 0; + return result ? eq : nullptr; } /** @@ -732,7 +732,7 @@ bool grobner::is_better_choice(equation * eq1, equation * eq2) { \brief Pick next unprocessed equation */ grobner::equation * grobner::pick_next() { - equation * r = 0; + equation * r = nullptr; ptr_buffer to_delete; equation_set::iterator it = m_to_process.begin(); equation_set::iterator end = m_to_process.end(); @@ -767,7 +767,7 @@ bool grobner::simplify_processed(equation * eq) { m_changed_leading_term = false; // if the leading term is simplified, then the equation has to be moved to m_to_process equation * new_curr = simplify(eq, curr); - if (new_curr != 0) { + if (new_curr != nullptr) { if (new_curr != curr) { m_equations_to_unfreeze.push_back(curr); to_remove.push_back(curr); @@ -817,7 +817,7 @@ void grobner::simplify_to_process(equation * eq) { for (; it != end; ++it) { equation * curr = *it; equation * new_curr = simplify(eq, curr); - if (new_curr != 0 && new_curr != curr) { + if (new_curr != nullptr && new_curr != curr) { m_equations_to_unfreeze.push_back(curr); to_insert.push_back(new_curr); to_remove.push_back(curr); @@ -947,7 +947,7 @@ bool grobner::compute_basis_step() { } #endif equation * new_eq = simplify_using_processed(eq); - if (new_eq != 0 && eq != new_eq) { + if (new_eq != nullptr && eq != new_eq) { // equation was updated using non destructive updates m_equations_to_unfreeze.push_back(eq); eq = new_eq; diff --git a/src/math/grobner/grobner.h b/src/math/grobner/grobner.h index f024a33e4..9233866d5 100644 --- a/src/math/grobner/grobner.h +++ b/src/math/grobner/grobner.h @@ -220,25 +220,25 @@ public: \brief Assert the given equality. This method assumes eq is simplified. */ - void assert_eq(expr * eq, v_dependency * ex = 0); + void assert_eq(expr * eq, v_dependency * ex = nullptr); /** \brief Assert the equality monomials[0] + ... + monomials[num_monomials - 1] = 0. This method assumes the monomials were simplified. */ - void assert_eq_0(unsigned num_monomials, expr * const * monomials, v_dependency * ex = 0); + void assert_eq_0(unsigned num_monomials, expr * const * monomials, v_dependency * ex = nullptr); /** \brief Assert the equality monomials[0] + ... + monomials[num_monomials - 1] = 0. This method assumes the monomials were simplified. */ - void assert_eq_0(unsigned num_monomials, monomial * const * monomials, v_dependency * ex = 0); + void assert_eq_0(unsigned num_monomials, monomial * const * monomials, v_dependency * ex = nullptr); /** \brief Assert the equality coeffs[0] * monomials[0] + ... + coeffs[num_monomials-1] * monomials[num_monomials - 1] = 0. This method assumes the monomials were simplified. */ - void assert_eq_0(unsigned num_monomials, rational const * coeffs, expr * const * monomials, v_dependency * ex = 0); + void assert_eq_0(unsigned num_monomials, rational const * coeffs, expr * const * monomials, v_dependency * ex = nullptr); /** \brief Assert the monomial tautology (quote (x_1 * ... * x_n)) - x_1 * ... * x_n = 0 @@ -263,7 +263,7 @@ public: /** \brief Return true if an inconsistency was detected. */ - bool inconsistent() const { return m_unsat != 0; } + bool inconsistent() const { return m_unsat != nullptr; } /** \brief Simplify the given expression using the equalities asserted diff --git a/src/math/hilbert/heap_trie.h b/src/math/hilbert/heap_trie.h index e53f9e7dc..3c6ecd1cb 100644 --- a/src/math/hilbert/heap_trie.h +++ b/src/math/hilbert/heap_trie.h @@ -195,9 +195,9 @@ public: m_le(le), m_num_keys(0), m_do_reshuffle(4), - m_root(0), - m_spare_leaf(0), - m_spare_trie(0) + m_root(nullptr), + m_spare_leaf(nullptr), + m_spare_trie(nullptr) {} ~heap_trie() { @@ -283,7 +283,7 @@ public: ++m_stats.m_num_removes; // assumption: key is in table. node* n = m_root; - node* m = 0; + node* m = nullptr; for (unsigned i = 0; i < num_keys(); ++i) { n->dec_ref(); VERIFY (to_trie(n)->find(get_key(keys, i), m)); diff --git a/src/math/hilbert/hilbert_basis.cpp b/src/math/hilbert/hilbert_basis.cpp index bbc56bdd5..d6d4366db 100644 --- a/src/math/hilbert/hilbert_basis.cpp +++ b/src/math/hilbert/hilbert_basis.cpp @@ -174,7 +174,7 @@ class hilbert_basis::value_index2 { struct checker : public ht::check_value { hilbert_basis* hb; offset_t m_value; - checker(): hb(0) {} + checker(): hb(nullptr) {} bool operator()(unsigned const& v) override { if (m_value.m_offset != v) { // && hb->is_subsumed(m_value, offset_t(v))) { return true; @@ -278,7 +278,7 @@ public: m_zero.insert(idx, vs); } else { - value_index* map = 0; + value_index* map = nullptr; if (!m_neg.find(vs.weight(), map)) { map = alloc(value_index, hb); map->reset(m_num_ineqs); diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 8c42bb418..5811811fc 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -48,7 +48,7 @@ namespace algebraic_numbers { unsigned m_sign_lower:1; unsigned m_not_rational:1; // if true we know for sure it is not a rational unsigned m_i:29; // number is the i-th root of p, 0 if it is not known which root of p the number is. - algebraic_cell():m_p_sz(0), m_p(0), m_minimal(false), m_not_rational(false), m_i(0) {} + algebraic_cell():m_p_sz(0), m_p(nullptr), m_minimal(false), m_not_rational(false), m_i(0) {} bool is_minimal() const { return m_minimal != 0; } }; @@ -186,7 +186,7 @@ namespace algebraic_numbers { for (unsigned i = 0; i < c->m_p_sz; i++) qm().del(c->m_p[i]); m_allocator.deallocate(sizeof(mpz)*c->m_p_sz, c->m_p); - c->m_p = 0; + c->m_p = nullptr; c->m_p_sz = 0; } @@ -201,13 +201,13 @@ namespace algebraic_numbers { } void del(numeral & a) { - if (a.m_cell == 0) + if (a.m_cell == nullptr) return; if (a.is_basic()) del(a.to_basic()); else del(a.to_algebraic()); - a.m_cell = 0; + a.m_cell = nullptr; } void reset(numeral & a) { @@ -215,7 +215,7 @@ namespace algebraic_numbers { } bool is_zero(numeral const & a) { - return a.m_cell == 0; + return a.m_cell == nullptr; } bool is_pos(numeral const & a) { @@ -361,7 +361,7 @@ namespace algebraic_numbers { basic_cell * mk_basic_cell(mpq & n) { if (qm().is_zero(n)) - return 0; + return nullptr; void * mem = static_cast(m_allocator.allocate(sizeof(basic_cell))); basic_cell * c = new (mem) basic_cell(); qm().swap(c->m_value, n); @@ -1037,7 +1037,7 @@ namespace algebraic_numbers { unsigned target_i = UINT_MAX; // index of sequence that is isolating int target_lV = 0, target_uV = 0; for (unsigned i = 0; i < num_fs; i++) { - if (seqs[i] == 0) + if (seqs[i] == nullptr) continue; // sequence was discarded because it does not contain the root. TRACE("anum_mk_binary", tout << "sequence " << i << "\n"; upm().display(tout, *(seqs[i])); tout << "\n";); int lV = upm().sign_variations_at(*(seqs[i]), r_i.lower()); @@ -1050,7 +1050,7 @@ namespace algebraic_numbers { ); if (V <= 0) { // discard sequence, since factor does not contain the root - seqs.set(i, 0); + seqs.set(i, nullptr); } else if (V == 1) { target_i = i; @@ -1115,7 +1115,7 @@ namespace algebraic_numbers { unsigned target_i = UINT_MAX; // index of sequence that is isolating int target_lV = 0, target_uV = 0; for (unsigned i = 0; i < num_fs; i++) { - if (seqs[i] == 0) + if (seqs[i] == nullptr) continue; // sequence was discarded because it does not contain the root. int lV = upm().sign_variations_at(*(seqs[i]), r_i.lower()); int uV = upm().sign_variations_at(*(seqs[i]), r_i.upper()); @@ -1126,7 +1126,7 @@ namespace algebraic_numbers { ); if (V <= 0) { // discard sequence, since factor does not contain the root - seqs.set(i, 0); + seqs.set(i, nullptr); } else if (V == 1) { target_i = i; @@ -2772,7 +2772,7 @@ namespace algebraic_numbers { manager::manager(reslimit& lim, unsynch_mpq_manager & m, params_ref const & p, small_object_allocator * a) { m_own_allocator = false; m_allocator = a; - if (m_allocator == 0) { + if (m_allocator == nullptr) { m_own_allocator = true; m_allocator = alloc(small_object_allocator, "algebraic"); } diff --git a/src/math/polynomial/algebraic_numbers.h b/src/math/polynomial/algebraic_numbers.h index 3a8ee766b..fa9731b62 100644 --- a/src/math/polynomial/algebraic_numbers.h +++ b/src/math/polynomial/algebraic_numbers.h @@ -58,7 +58,7 @@ namespace algebraic_numbers { typedef _scoped_numeral scoped_numeral; typedef _scoped_numeral_vector scoped_numeral_vector; - manager(reslimit& rl, unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = 0); + manager(reslimit& rl, unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); ~manager(); static void get_param_descrs(param_descrs & r); @@ -372,7 +372,7 @@ namespace algebraic_numbers { basic_cell * to_basic() const { SASSERT(is_basic()); return UNTAG(basic_cell*, m_cell); } algebraic_cell * to_algebraic() const { SASSERT(!is_basic()); return UNTAG(algebraic_cell*, m_cell); } public: - anum():m_cell(0) {} + anum():m_cell(nullptr) {} }; }; diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index d6eafac05..a58f26597 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -510,7 +510,7 @@ namespace polynomial { monomial * allocate(unsigned capacity) { void * mem = memory::allocate(monomial::get_obj_size(capacity)); - return new (mem) monomial(UINT_MAX, 0, 0, 0); + return new (mem) monomial(UINT_MAX, 0, nullptr, 0); } void deallocate(monomial * ptr, unsigned capacity) { @@ -776,10 +776,10 @@ namespace polynomial { tmp_monomial m_tmp3; svector m_powers_tmp; public: - monomial_manager(small_object_allocator * a = 0) { + monomial_manager(small_object_allocator * a = nullptr) { m_ref_count = 0; m_next_var = 0; - if (a == 0) { + if (a == nullptr) { m_allocator = alloc(small_object_allocator, "polynomial"); m_own_allocator = true; } @@ -787,7 +787,7 @@ namespace polynomial { m_allocator = a; m_own_allocator = false; } - m_unit = mk_monomial(0, static_cast(0)); + m_unit = mk_monomial(0, static_cast(nullptr)); inc_ref(m_unit); } @@ -1185,7 +1185,7 @@ namespace polynomial { sqrt_tmp.reserve(sz); for (unsigned i = 0; i < sz; i++) { if (m->degree(i) % 2 == 1) - return 0; + return nullptr; sqrt_tmp.set_power(i, power(m->get_var(i), m->degree(i) / 2)); } sqrt_tmp.set_size(sz); @@ -1927,7 +1927,7 @@ namespace polynomial { } public: - som_buffer():m_owner(0) {} + som_buffer():m_owner(nullptr) {} void reset() { if (empty()) @@ -2173,7 +2173,7 @@ namespace polynomial { public: som_buffer_vector() { - m_owner = 0; + m_owner = nullptr; } ~som_buffer_vector() { @@ -2185,7 +2185,7 @@ namespace polynomial { void set_owner(imp * owner) { SASSERT(m_owner == owner || m_owner == 0); - if (m_owner == 0) { + if (m_owner == nullptr) { m_owner = owner; unsigned sz = m_buffers.size(); for (unsigned i = 0; i < sz; i++) { @@ -2222,7 +2222,7 @@ namespace polynomial { numeral_vector m_tmp_as; monomial_vector m_tmp_ms; public: - cheap_som_buffer():m_owner(0) {} + cheap_som_buffer():m_owner(nullptr) {} void set_owner(imp * o) { m_owner = o; } bool empty() const { return m_tmp_ms.empty(); } @@ -2306,12 +2306,12 @@ namespace polynomial { cheap_som_buffer m_cheap_som_buffer2; void init() { - m_del_eh = 0; + m_del_eh = nullptr; m_som_buffer.set_owner(this); m_som_buffer2.set_owner(this); m_cheap_som_buffer.set_owner(this); m_cheap_som_buffer2.set_owner(this); - m_zero = mk_polynomial_core(0, 0, 0); + m_zero = mk_polynomial_core(0, nullptr, nullptr); m().set(m_zero_numeral, 0); inc_ref(m_zero); numeral one(1); @@ -2326,7 +2326,7 @@ namespace polynomial { m_wrapper(w), m_manager(m), m_upm(lim, m) { - if (mm == 0) + if (mm == nullptr) mm = alloc(monomial_manager); m_monomial_manager = mm; m_monomial_manager->inc_ref(); @@ -2419,13 +2419,13 @@ namespace polynomial { void del(polynomial * p) { TRACE("polynomial", tout << "deleting: "; p->display(tout, m_manager); tout << "\n";); - if (m_del_eh != 0) { + if (m_del_eh != nullptr) { del_eh * curr = m_del_eh; do { (*curr)(p); curr = curr->m_next; } - while (curr != 0); + while (curr != nullptr); } unsigned sz = p->size(); unsigned obj_sz = polynomial::get_obj_size(sz); @@ -2924,7 +2924,7 @@ namespace polynomial { imp * m_imp; ptr_vector m_data; public: - newton_interpolator_vector():m_imp(0) {} + newton_interpolator_vector():m_imp(nullptr) {} ~newton_interpolator_vector() { flush(); @@ -2983,7 +2983,7 @@ namespace polynomial { ms.push_back(p->m(i)); } std::sort(ms.begin(), ms.end(), lex_lt2(x)); - monomial * prev = 0; + monomial * prev = nullptr; for (unsigned i = 0; i < sz; i++) { monomial * orig_m = ms[i]; monomial * m; @@ -3831,7 +3831,7 @@ namespace polynomial { r = mk_const(d_a); return; } - if (C_star.get() == 0) { + if (C_star.get() == nullptr) { C_star = q; m().set(bound, p); } @@ -4153,7 +4153,7 @@ namespace polynomial { counter = 0; min_deg_q = deg_q; // start from scratch - if (sk == 0) { + if (sk == nullptr) { interpolator.reset(); interpolator.add(val, q); } @@ -4165,7 +4165,7 @@ namespace polynomial { } else if (deg_q == min_deg_q) { TRACE("mgcd_detail", tout << "adding sample point...\n";); - if (sk == 0) { + if (sk == nullptr) { interpolator.add(val, q); } else { @@ -4178,7 +4178,7 @@ namespace polynomial { continue; } bool found_candidate = false; - if (sk == 0) { + if (sk == nullptr) { SASSERT(interpolator.num_sample_points() > 0); interpolator.mk(x, H); TRACE("mgcd_detail", tout << "idx: " << idx << "\ncandidate H: " << H << "\n";); @@ -4214,14 +4214,14 @@ namespace polynomial { r = mul(ci_g, r); done = true; } - else if (sk != 0) { + else if (sk != nullptr) { throw sparse_mgcd_failed(); } } if (done) { TRACE("mgcd", tout << "idx: " << idx << "\nresult: " << r << "\n";); - if (sk == 0 && m_use_sparse_gcd) { + if (sk == nullptr && m_use_sparse_gcd) { // save skeleton skeleton * new_sk = alloc(skeleton, *this, H, x); m_mgcd_skeletons.set(idx, new_sk); @@ -4255,7 +4255,7 @@ namespace polynomial { m_mgcd_skeletons.reset(); for (unsigned i = 0; i < num_vars; i++) { vars.push_back(var_min_degrees[i].get_var()); - m_mgcd_skeletons.push_back(0); + m_mgcd_skeletons.push_back(nullptr); } scoped_numeral c_u(m()), c_v(m()); @@ -4311,7 +4311,7 @@ namespace polynomial { r = mk_const(d_a); return; } - if (C_star.get() == 0) { + if (C_star.get() == nullptr) { C_star = q; m().set(bound, p); } @@ -4903,7 +4903,7 @@ namespace polynomial { */ template void pseudo_division_core(polynomial const * p, polynomial const * q, var x, unsigned & d, polynomial_ref & Q, polynomial_ref & R, - var2degree const * x2d = 0) { + var2degree const * x2d = nullptr) { SASSERT(is_valid(x)); SASSERT(!ModD || x2d != 0); TRACE("polynomial", tout << "pseudo_division\np: "; p->display(tout, m_manager); @@ -5138,7 +5138,7 @@ namespace polynomial { } monomial const * m_r = R.m(max_R); numeral const & a_r = R.a(max_R); - monomial * m_r_q = 0; + monomial * m_r_q = nullptr; VERIFY(div(m_r, m_q, m_r_q)); TRACE("polynomial", tout << "m_r: "; m_r->display(tout); tout << "\nm_q: "; m_q->display(tout); tout << "\n"; if (m_r_q) { tout << "m_r_q: "; m_r_q->display(tout); tout << "\n"; }); @@ -5175,7 +5175,7 @@ namespace polynomial { } monomial const * m_r = R.m(max_R); numeral const & a_r = R.a(max_R); - monomial * m_r_q = 0; + monomial * m_r_q = nullptr; bool q_div_r = div(m_r, m_q, m_r_q); m_r_q_ref = m_r_q; TRACE("polynomial", tout << "m_r: "; m_r->display(tout); tout << "\nm_q: "; m_q->display(tout); tout << "\n"; @@ -5639,7 +5639,7 @@ namespace polynomial { pw(h1, d1, hs1); hs1 = mul(g1, hs1); G3 = exact_div(Gh3, hs1); - hs1 = 0; + hs1 = nullptr; } // prepare for next iteration @@ -6083,7 +6083,7 @@ namespace polynomial { polynomial_vector::iterator end2 = m_polynomials.end(); for (; it2 != end2; ++it2) { polynomial * p = *it2; - if (p == 0) + if (p == nullptr) continue; p->make_first_maximal(); SASSERT(p->size() <= 1 || !p->lex_sorted()); @@ -6404,7 +6404,7 @@ namespace polynomial { result = const_cast(r); return; } - result = 0; + result = nullptr; polynomial_ref p1(pm()), q1(pm()); polynomial_ref_buffer ps(pm()); unsigned sz = r->size(); diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index c4dedb043..43774f0ac 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -192,7 +192,7 @@ namespace polynomial { private: imp * m_imp; public: - manager(reslimit& lim, numeral_manager & m, monomial_manager * mm = 0); + manager(reslimit& lim, numeral_manager & m, monomial_manager * mm = nullptr); manager(reslimit& lim, numeral_manager & m, small_object_allocator * a); ~manager(); @@ -227,7 +227,7 @@ namespace polynomial { friend class manager; del_eh * m_next; public: - del_eh():m_next(0) {} + del_eh():m_next(nullptr) {} virtual void operator()(polynomial * p) = 0; }; diff --git a/src/math/polynomial/polynomial_cache.cpp b/src/math/polynomial/polynomial_cache.cpp index 9a021ce36..a617e9412 100644 --- a/src/math/polynomial/polynomial_cache.cpp +++ b/src/math/polynomial/polynomial_cache.cpp @@ -47,7 +47,7 @@ namespace polynomial { m_x(x), m_hash(h), m_result_sz(0), - m_result(0) { + m_result(nullptr) { } struct hash_proc { unsigned operator()(psc_chain_entry const * entry) const { return entry->m_hash; } }; @@ -69,7 +69,7 @@ namespace polynomial { m_p(p), m_hash(h), m_result_sz(0), - m_result(0) { + m_result(nullptr) { } struct hash_proc { unsigned operator()(factor_entry const * entry) const { return entry->m_hash; } }; diff --git a/src/math/polynomial/rpolynomial.cpp b/src/math/polynomial/rpolynomial.cpp index 5e7a829f6..90db9c832 100644 --- a/src/math/polynomial/rpolynomial.cpp +++ b/src/math/polynomial/rpolynomial.cpp @@ -63,8 +63,8 @@ namespace rpolynomial { m_wrapper(w), m_manager(m), m_allocator(a), - m_own_allocator(a == 0) { - if (a == 0) + m_own_allocator(a == nullptr) { + if (a == nullptr) m_allocator = alloc(small_object_allocator, "rpolynomial"); } @@ -107,7 +107,7 @@ namespace rpolynomial { unsigned sz = p->size(); for (unsigned i = 0; i < sz; i++) { poly_or_num * pn = p->arg(i); - if (pn == 0) + if (pn == nullptr) continue; if (is_num(pn)) { del_numeral(to_num_ptr(pn)); @@ -141,11 +141,11 @@ namespace rpolynomial { static bool is_const(polynomial const * p) { SASSERT(p == 0 || (p->max_var() == null_var) == (p->size() == 1 && p->arg(0) != 0 && is_num(p->arg(0)))); - return p == 0 || p->max_var() == null_var; + return p == nullptr || p->max_var() == null_var; } bool is_zero(polynomial const * p) { - return p == 0; + return p == nullptr; } static bool is_univariate(polynomial const * p) { @@ -154,7 +154,7 @@ namespace rpolynomial { unsigned sz = p->size(); for (unsigned i = 0; i < sz; i++) { poly_or_num * pn = p->arg(i); - if (pn == 0) + if (pn == nullptr) continue; if (is_poly(pn)) return false; @@ -169,7 +169,7 @@ namespace rpolynomial { SASSERT(sz > 0); SASSERT(p->arg(sz - 1) != 0); for (unsigned i = 0; i < sz - 1; i++) { - if (p->arg(i) != 0) + if (p->arg(i) != nullptr) return false; } SASSERT(is_poly(p->arg(sz - 1))); @@ -179,13 +179,13 @@ namespace rpolynomial { unsigned degree(polynomial const * p) { SASSERT(p != 0); SASSERT(p->size() > 0); - return p == 0 ? 0 : p->size() - 1; + return p == nullptr ? 0 : p->size() - 1; } bool eq(polynomial const * p1, polynomial const * p2) { if (p1 == p2) return true; - if (p1 == 0 || p2 == 0) + if (p1 == nullptr || p2 == nullptr) return false; if (p1->size() != p2->size()) return false; @@ -195,9 +195,9 @@ namespace rpolynomial { for (unsigned i = 0; i < sz; i++) { poly_or_num * pn1 = p1->arg(i); poly_or_num * pn2 = p2->arg(i); - if (pn1 == 0 && pn2 == 0) + if (pn1 == nullptr && pn2 == nullptr) continue; - if (pn1 == 0 || pn2 == 0) + if (pn1 == nullptr || pn2 == nullptr) return false; if (is_num(pn1) && is_num(pn2)) { if (!m_manager.eq(to_num(pn1), to_num(pn2))) @@ -217,7 +217,7 @@ namespace rpolynomial { void inc_ref_args(unsigned sz, poly_or_num * const * args) { for (unsigned i = 0; i < sz; i++) { poly_or_num * pn = args[i]; - if (pn == 0 || is_num(pn)) + if (pn == nullptr || is_num(pn)) continue; inc_ref(to_poly(pn)); } @@ -226,7 +226,7 @@ namespace rpolynomial { void dec_ref_args(unsigned sz, poly_or_num * const * args) { for (unsigned i = 0; i < sz; i++) { poly_or_num * pn = args[i]; - if (pn == 0 || is_num(pn)) + if (pn == nullptr || is_num(pn)) continue; dec_ref(to_poly(pn)); } @@ -234,7 +234,7 @@ namespace rpolynomial { unsigned trim(unsigned sz, poly_or_num * const * args) { while (sz > 0) { - if (args[sz - 1] != 0) + if (args[sz - 1] != nullptr) return sz; sz--; } @@ -281,8 +281,8 @@ namespace rpolynomial { polynomial * mk_poly(unsigned sz, poly_or_num * const * args, var max_var) { poly_or_num * _p = mk_poly_core(sz, args, max_var); - if (_p == 0) - return 0; + if (_p == nullptr) + return nullptr; else if (is_num(_p)) return allocate_poly(1, &_p, null_var); else @@ -291,7 +291,7 @@ namespace rpolynomial { polynomial * mk_const(numeral const & n) { if (m_manager.is_zero(n)) - return 0; + return nullptr; numeral * a = mk_numeral(); m_manager.set(*a, n); poly_or_num * _a = to_poly_or_num(a); @@ -322,8 +322,8 @@ namespace rpolynomial { } poly_or_num * unpack(polynomial const * p) { - if (p == 0) { - return 0; + if (p == nullptr) { + return nullptr; } else if (is_const(p)) { SASSERT(p->size() == 1); @@ -336,8 +336,8 @@ namespace rpolynomial { } polynomial * pack(poly_or_num * p) { - if (p == 0) - return 0; + if (p == nullptr) + return nullptr; else if (is_num(p)) return mk_poly(1, &p, null_var); else @@ -345,8 +345,8 @@ namespace rpolynomial { } poly_or_num * mul_core(numeral const & c, poly_or_num * p) { - if (m_manager.is_zero(c) || p == 0) { - return 0; + if (m_manager.is_zero(c) || p == nullptr) { + return nullptr; } else if (is_num(p)) { numeral * r = mk_numeral(); @@ -379,7 +379,7 @@ namespace rpolynomial { if (m_manager.is_zero(c)) { return p; } - else if (p == 0) { + else if (p == nullptr) { numeral * r = mk_numeral(); m_manager.set(*r, c); return to_poly_or_num(r); @@ -388,7 +388,7 @@ namespace rpolynomial { numeral a; m_manager.add(c, to_num(p), a); if (m_manager.is_zero(a)) - return 0; + return nullptr; numeral * new_arg = mk_numeral(); m_manager.swap(*new_arg, a); return to_poly_or_num(new_arg); @@ -662,7 +662,7 @@ namespace rpolynomial { while (i > 0) { --i; poly_or_num * pn = p->arg(i); - if (pn == 0) + if (pn == nullptr) continue; if (first) first = false; @@ -730,7 +730,7 @@ namespace rpolynomial { } bool manager::is_zero(polynomial const * p) { - return p == 0; + return p == nullptr; } #if 0 diff --git a/src/math/polynomial/rpolynomial.h b/src/math/polynomial/rpolynomial.h index f2ba78894..ba51f785e 100644 --- a/src/math/polynomial/rpolynomial.h +++ b/src/math/polynomial/rpolynomial.h @@ -51,7 +51,7 @@ namespace rpolynomial { private: imp * m_imp; public: - manager(numeral_manager & m, small_object_allocator * a = 0); + manager(numeral_manager & m, small_object_allocator * a = nullptr); ~manager(); numeral_manager & m() const; diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index fe890b040..f7cc16de2 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -190,7 +190,7 @@ namespace upolynomial { // Copy elements from p to buffer. void core_manager::set(unsigned sz, numeral const * p, numeral_vector & buffer) { - if (p != 0 && buffer.c_ptr() == p) { + if (p != nullptr && buffer.c_ptr() == p) { SASSERT(buffer.size() == sz); return; } diff --git a/src/math/polynomial/upolynomial.h b/src/math/polynomial/upolynomial.h index f8efae465..6bd3e4a27 100644 --- a/src/math/polynomial/upolynomial.h +++ b/src/math/polynomial/upolynomial.h @@ -117,7 +117,7 @@ namespace upolynomial { numeral_vector m_sqf_tmp2; numeral_vector m_pw_tmp; - static bool is_alias(numeral const * p, numeral_vector & buffer) { return buffer.c_ptr() != 0 && buffer.c_ptr() == p; } + static bool is_alias(numeral const * p, numeral_vector & buffer) { return buffer.c_ptr() != nullptr && buffer.c_ptr() == p; } void neg_core(unsigned sz1, numeral const * p1, numeral_vector & buffer); void add_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer); void sub_core(unsigned sz1, numeral const * p1, unsigned sz2, numeral const * p2, numeral_vector & buffer); diff --git a/src/math/realclosure/mpz_matrix.cpp b/src/math/realclosure/mpz_matrix.cpp index 62a328b8d..3bbd387c6 100644 --- a/src/math/realclosure/mpz_matrix.cpp +++ b/src/math/realclosure/mpz_matrix.cpp @@ -49,7 +49,7 @@ void mpz_matrix_manager::mk(unsigned m, unsigned n, mpz_matrix & A) { } void mpz_matrix_manager::del(mpz_matrix & A) { - if (A.a_ij != 0) { + if (A.a_ij != nullptr) { for (unsigned i = 0; i < A.m; i++) for (unsigned j = 0; j < A.n; j++) nm().del(A(i,j)); @@ -57,7 +57,7 @@ void mpz_matrix_manager::del(mpz_matrix & A) { m_allocator.deallocate(sz, A.a_ij); A.m = 0; A.n = 0; - A.a_ij = 0; + A.a_ij = nullptr; } } @@ -208,7 +208,7 @@ bool mpz_matrix_manager::eliminate(mpz_matrix & A, mpz * b, unsigned k1, unsigne // a_ik <- 0 nm().set(A(i, k2), 0); // normalize row i - if (!normalize_row(A.row(i), A.n, b ? &(b[i]) : 0, int_solver)) + if (!normalize_row(A.row(i), A.n, b ? &(b[i]) : nullptr, int_solver)) return false; } SASSERT(nm().is_zero(A(i, k2))); @@ -386,7 +386,7 @@ unsigned mpz_matrix_manager::linear_independent_rows(mpz_matrix const & _A, unsi r_sz++; if (r_sz >= A.n()) break; - eliminate(A, 0, k1, k2, false); + eliminate(A, nullptr, k1, k2, false); k2++; } std::sort(r, r + r_sz); diff --git a/src/math/realclosure/mpz_matrix.h b/src/math/realclosure/mpz_matrix.h index f5d7358da..92716ec0d 100644 --- a/src/math/realclosure/mpz_matrix.h +++ b/src/math/realclosure/mpz_matrix.h @@ -45,7 +45,7 @@ class mpz_matrix { unsigned n; mpz * a_ij; public: - mpz_matrix():m(0), n(0), a_ij(0) {} + mpz_matrix():m(0), n(0), a_ij(nullptr) {} mpz const & operator()(unsigned i, unsigned j) const { SASSERT(i < m); SASSERT(j < n); diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 3f399990d..d41937c29 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -162,7 +162,7 @@ namespace realclosure { // To cope with this issue, we cache the value m_interval in m_old_interval whenever the width of m_interval is below // a give threshold. Then, after finishing OP, we restore the old_interval. mpbqi * m_old_interval; - value(bool rat):m_ref_count(0), m_rational(rat), m_old_interval(0) {} + value(bool rat):m_ref_count(0), m_rational(rat), m_old_interval(nullptr) {} bool is_rational() const { return m_rational; } mpbqi const & interval() const { return m_interval; } mpbqi & interval() { return m_interval; } @@ -220,7 +220,7 @@ namespace realclosure { mpbqi m_interval; mpbqi * m_old_interval; - extension(kind k, unsigned idx):m_ref_count(0), m_kind(k), m_idx(idx), m_old_interval(0) {} + extension(kind k, unsigned idx):m_ref_count(0), m_kind(k), m_idx(idx), m_old_interval(nullptr) {} unsigned idx() const { return m_idx; } kind knd() const { return static_cast(m_kind); } @@ -256,7 +256,7 @@ namespace realclosure { unsigned m_mark:1; // auxiliary mark used during deletion int m_sign; // Sign of the polynomial associated with m_q_idx sign_condition * m_prev; // Antecedent - sign_condition():m_q_idx(0), m_mark(false), m_sign(0), m_prev(0) {} + sign_condition():m_q_idx(0), m_mark(false), m_sign(0), m_prev(nullptr) {} sign_condition(unsigned qidx, int sign, sign_condition * prev):m_q_idx(qidx), m_mark(false), m_sign(sign), m_prev(prev) {} sign_condition * prev() const { return m_prev; } @@ -287,13 +287,13 @@ namespace realclosure { unsigned m_sc_idx; //!< != UINT_MAX if m_sign_det != 0, in this case m_sc_idx < m_sign_det->m_sign_conditions.size() bool m_depends_on_infinitesimals; //!< True if the polynomial p depends on infinitesimal extensions. - algebraic(unsigned idx):extension(ALGEBRAIC, idx), m_sign_det(0), m_sc_idx(0), m_depends_on_infinitesimals(false) {} + algebraic(unsigned idx):extension(ALGEBRAIC, idx), m_sign_det(nullptr), m_sc_idx(0), m_depends_on_infinitesimals(false) {} polynomial const & p() const { return m_p; } bool depends_on_infinitesimals() const { return m_depends_on_infinitesimals; } sign_det * sdt() const { return m_sign_det; } unsigned sc_idx() const { return m_sc_idx; } - unsigned num_roots_inside_interval() const { return m_sign_det == 0 ? 1 : m_sign_det->num_roots(); } + unsigned num_roots_inside_interval() const { return m_sign_det == nullptr ? 1 : m_sign_det->num_roots(); } mpbqi & iso_interval() { return m_iso_interval; } }; @@ -497,8 +497,8 @@ namespace realclosure { imp(reslimit& lim, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a): m_limit(lim), - m_allocator(a == 0 ? alloc(small_object_allocator, "realclosure") : a), - m_own_allocator(a == 0), + m_allocator(a == nullptr ? alloc(small_object_allocator, "realclosure") : a), + m_own_allocator(a == nullptr), m_qm(qm), m_mm(m_qm, *m_allocator), m_bqm(m_qm), @@ -509,8 +509,8 @@ namespace realclosure { mpq one(1); m_one = mk_rational(one); inc_ref(m_one); - m_pi = 0; - m_e = 0; + m_pi = nullptr; + m_e = nullptr; m_exec_depth = 0; @@ -657,7 +657,7 @@ namespace realclosure { */ template void save_interval(T * v, ptr_vector & to_restore) { - if (v->m_old_interval != 0) + if (v->m_old_interval != nullptr) return; // interval was already saved. to_restore.push_back(v); inc_ref(v); @@ -698,7 +698,7 @@ namespace realclosure { set_interval(v->m_interval, *(v->m_old_interval)); bqim().del(*(v->m_old_interval)); allocator().deallocate(sizeof(mpbqi), v->m_old_interval); - v->m_old_interval = 0; + v->m_old_interval = nullptr; dec_ref(v); } to_restore.reset(); @@ -811,12 +811,12 @@ namespace realclosure { } void inc_ref_sign_det(sign_det * sd) { - if (sd != 0) + if (sd != nullptr) sd->m_ref_count++; } void dec_ref_sign_det(sign_det * sd) { - if (sd != 0) { + if (sd != nullptr) { sd->m_ref_count--; if (sd->m_ref_count == 0) { del_sign_det(sd); @@ -887,7 +887,7 @@ namespace realclosure { void del(numeral & a) { dec_ref(a.m_value); - a.m_value = 0; + a.m_value = nullptr; } void del(numeral_vector & v) { @@ -910,7 +910,7 @@ namespace realclosure { \brief Return true if v is zero. */ static bool is_zero(value * v) { - return v == 0; + return v == nullptr; } /** @@ -1260,14 +1260,14 @@ namespace realclosure { } rational_function_value * mk_rational_function_value_core(algebraic * ext, unsigned num_sz, value * const * num) { - return mk_rational_function_value_core(ext, num_sz, num, 0, 0); + return mk_rational_function_value_core(ext, num_sz, num, 0, nullptr); } /** \brief Create a value using the given extension. */ rational_function_value * mk_rational_function_value(extension * ext) { - value * num[2] = { 0, one() }; + value * num[2] = { nullptr, one() }; value * den[1] = { one() }; rational_function_value * v = mk_rational_function_value_core(ext, 2, num, 1, den); set_interval(v->interval(), ext->interval()); @@ -1838,7 +1838,7 @@ namespace realclosure { interval contains only one root of p. */ void add_root(unsigned p_sz, value * const * p, mpbqi const & interval, mpbqi const & iso_interval, numeral_vector & roots) { - add_root(p_sz, p, interval, iso_interval, 0, UINT_MAX, roots); + add_root(p_sz, p, interval, iso_interval, nullptr, UINT_MAX, roots); } /** @@ -1965,7 +1965,7 @@ namespace realclosure { // Sequence of sign conditions associated with the columns of M_s // These are sign conditions on the polynomials in qs. scoped_sign_conditions scs(*this); - scs.push_back(0); + scs.push_back(nullptr); // Starting configuration // @@ -2322,7 +2322,7 @@ namespace realclosure { if (num_neg_roots > 0) { if (num_neg_roots == 1) { - add_root(n, p, neg_interval, minf_zero, 0, UINT_MAX, roots); + add_root(n, p, neg_interval, minf_zero, nullptr, UINT_MAX, roots); } else { if (has_neg_lower) { @@ -2336,7 +2336,7 @@ namespace realclosure { if (num_pos_roots > 0) { if (num_pos_roots == 1) { - add_root(n, p, pos_interval, zero_inf, 0, UINT_MAX, roots); + add_root(n, p, pos_interval, zero_inf, nullptr, UINT_MAX, roots); } else { if (has_pos_upper) { @@ -2668,7 +2668,7 @@ namespace realclosure { \brief Remove 0s */ void adjust_size(value_ref_buffer & r) { - while (!r.empty() && r.back() == 0) { + while (!r.empty() && r.back() == nullptr) { r.pop_back(); } } @@ -2753,7 +2753,7 @@ namespace realclosure { void mul(value * a, unsigned sz, value * const * p, value_ref_buffer & r) { SASSERT(p != r.c_ptr()); r.reset(); - if (a == 0) + if (a == nullptr) return; value_ref a_i(*this); for (unsigned i = 0; i < sz; i++) { @@ -2778,7 +2778,7 @@ namespace realclosure { value_ref tmp(*this); for (unsigned i = 0; i < sz1; i++) { checkpoint(); - if (p1[i] == 0) + if (p1[i] == nullptr) continue; for (unsigned j = 0; j < sz2; j++) { // r[i+j] <- r[i+j] + p1[i]*p2[j] @@ -3060,7 +3060,7 @@ namespace realclosure { bool struct_eq(value * a, value * b) const { if (a == b) return true; - else if (a == 0 || b == 0) + else if (a == nullptr || b == nullptr) return false; else if (is_nz_rational(a) && is_nz_rational(b)) return qm().eq(to_mpq(a), to_mpq(b)); @@ -3112,7 +3112,7 @@ namespace realclosure { - a is a rational_function_value of the form p_a(x)/1 where the coefficients of p_a also have clean denominators. */ bool has_clean_denominators(value * a) const { - if (a == 0) + if (a == nullptr) return true; else if (is_nz_rational(a)) return qm().is_int(to_mpq(a)); @@ -3150,7 +3150,7 @@ namespace realclosure { INC_DEPTH(); TRACE("rcf_clean", tout << "clean_denominators_core [" << m_exec_depth << "]\na: "; display(tout, a, false); tout << "\n";); p.reset(); q.reset(); - if (a == 0) { + if (a == nullptr) { p = a; q = one(); } @@ -3205,8 +3205,8 @@ namespace realclosure { dens.push_back(a_d); } else { - nums.push_back(0); - dens.push_back(0); + nums.push_back(nullptr); + dens.push_back(nullptr); } } if (all_one) { @@ -3258,7 +3258,7 @@ namespace realclosure { value_ref m(*this); for (unsigned i = 0; i < p_sz; i++) { if (!nums[i]) { - norm_p.push_back(0); + norm_p.push_back(nullptr); } else { SASSERT(dens[i]); @@ -3348,7 +3348,7 @@ namespace realclosure { If g != 0, then it will compute the gcd of g and the coefficients in a. */ bool gcd_int_coeffs(value * a, mpz & g) { - if (a == 0) { + if (a == nullptr) { return false; } else if (is_nz_rational(a)) { @@ -3410,7 +3410,7 @@ namespace realclosure { for (unsigned i = 0; i < p.size(); i++) { if (p[i]) { a = p[i]; - p.set(i, 0); + p.set(i, nullptr); exact_div_z(a, g); p.set(i, a); } @@ -3448,7 +3448,7 @@ namespace realclosure { new_ais.push_back(ai); } else { - new_ais.push_back(0); + new_ais.push_back(nullptr); } } rational_function_value * r = mk_rational_function_value_core(rf->ext(), new_ais.size(), new_ais.c_ptr(), 1, &m_one); @@ -3759,7 +3759,7 @@ namespace realclosure { while (i > 0) { checkpoint(); --i; - if (p[i] != 0) + if (p[i] != nullptr) bqim().add(r, interval(p[i]), r); if (i > 0) bqim().mul(r, bi, r); @@ -3772,7 +3772,7 @@ namespace realclosure { */ bool has_refineable_approx_coeffs(unsigned n, value * const * p) { for (unsigned i = 0; i < n; i++) { - if (p[i] != 0) { + if (p[i] != nullptr) { mpbqi & a_i = interval(p[i]); if (a_i.lower_is_inf() || a_i.upper_is_inf()) return false; @@ -3786,7 +3786,7 @@ namespace realclosure { */ void mk_polynomial_value(unsigned n, value * const * p, value * b, value_ref & r) { SASSERT(n > 0); - if (n == 1 || b == 0) { + if (n == 1 || b == nullptr) { r = p[0]; } else { @@ -3798,7 +3798,7 @@ namespace realclosure { unsigned i = n - 1; while (i > 0) { --i; - if (p[i] != 0) + if (p[i] != nullptr) add(r, p[i], r); // r <- r + a_i if (i > 0) mul(r, b, r); // r <- r * b @@ -3856,7 +3856,7 @@ namespace realclosure { int find_biggest_interval_magnitude(unsigned n, value * const * p) { int r = INT_MIN; for (unsigned i = 0; i < n; i++) { - if (p[i] != 0) { + if (p[i] != nullptr) { mpbqi & a_i = interval(p[i]); SASSERT(!a_i.lower_is_inf() && !a_i.upper_is_inf()); int m = magnitude(a_i); @@ -4089,7 +4089,7 @@ namespace realclosure { */ bool refine_coeffs_interval(unsigned n, value * const * p, unsigned prec) { for (unsigned i = 0; i < n; i++) { - if (p[i] != 0 && !refine_interval(p[i], prec)) + if (p[i] != nullptr && !refine_interval(p[i], prec)) return false; } return true; @@ -4243,7 +4243,7 @@ namespace realclosure { bool refine_algebraic_interval(algebraic * a, unsigned prec) { save_interval_if_too_small(a, prec); - if (a->sdt() != 0) { + if (a->sdt() != nullptr) { // We don't bisect the interval, since it contains more than one root. // To bisect this kind of interval we would have to use Tarski queries. return false; @@ -4941,7 +4941,7 @@ namespace realclosure { } else { // The new value is 0 - r = 0; + r = nullptr; } } } @@ -4979,7 +4979,7 @@ namespace realclosure { // num <- a + b * ad add(an.size(), an.c_ptr(), b_ad.size(), b_ad.c_ptr(), num); if (num.empty()) - r = 0; + r = nullptr; else { value_ref_buffer new_num(*this); value_ref_buffer new_den(*this); @@ -5003,7 +5003,7 @@ namespace realclosure { value_ref_buffer new_num(*this); add(an.size(), an.c_ptr(), bn.size(), bn.c_ptr(), new_num); if (new_num.empty()) - r = 0; + r = nullptr; else { // We don't need to invoke normalize_algebraic even if x (== a->ext()) is algebraic. // Reason: by construction the polynomials a->num() and b->num() are "normalized". @@ -5035,7 +5035,7 @@ namespace realclosure { value_ref_buffer num(*this); add(an_bd.size(), an_bd.c_ptr(), bn_ad.size(), bn_ad.c_ptr(), num); if (num.empty()) { - r = 0; + r = nullptr; } else { value_ref_buffer den(*this); @@ -5050,17 +5050,17 @@ namespace realclosure { } void add(value * a, value * b, value_ref & r) { - if (a == 0) { + if (a == nullptr) { r = b; } - else if (b == 0) { + else if (b == nullptr) { r = a; } else if (is_nz_rational(a) && is_nz_rational(b)) { scoped_mpq v(qm()); qm().add(to_mpq(a), to_mpq(b), v); if (qm().is_zero(v)) - r = 0; + r = nullptr; else r = mk_rational_and_swap(v); } @@ -5079,17 +5079,17 @@ namespace realclosure { } void sub(value * a, value * b, value_ref & r) { - if (a == 0) { + if (a == nullptr) { neg(b, r); } - else if (b == 0) { + else if (b == nullptr) { r = a; } else if (is_nz_rational(a) && is_nz_rational(b)) { scoped_mpq v(qm()); qm().sub(to_mpq(a), to_mpq(b), v); if (qm().is_zero(v)) - r = 0; + r = nullptr; else r = mk_rational_and_swap(v); } @@ -5118,8 +5118,8 @@ namespace realclosure { } void neg(value * a, value_ref & r) { - if (a == 0) { - r = 0; + if (a == nullptr) { + r = nullptr; } else if (is_nz_rational(a)) { scoped_mpq v(qm()); @@ -5155,7 +5155,7 @@ namespace realclosure { } else { // The new value is 0 - r = 0; + r = nullptr; } } } @@ -5252,8 +5252,8 @@ namespace realclosure { } void mul(value * a, value * b, value_ref & r) { - if (a == 0 || b == 0) { - r = 0; + if (a == nullptr || b == nullptr) { + r = nullptr; } else if (is_rational_one(a)) { r = b; @@ -5287,10 +5287,10 @@ namespace realclosure { } void div(value * a, value * b, value_ref & r) { - if (a == 0) { - r = 0; + if (a == nullptr) { + r = nullptr; } - else if (b == 0) { + else if (b == nullptr) { throw exception("division by zero"); } else if (is_rational_one(b)) { @@ -5461,7 +5461,7 @@ namespace realclosure { // r == 1/inv(new_a) inv(new_a, r); } - else if (alpha->sdt() == 0) { + else if (alpha->sdt() == nullptr) { // Another easy case: we just have to replace // alpha->p() with new_p. // The m_iso_interval for p() is also an isolating interval for new_p, @@ -5552,7 +5552,7 @@ namespace realclosure { } void inv(value * a, value_ref & r) { - if (a == 0) { + if (a == nullptr) { throw exception("division by zero"); } if (is_nz_rational(a)) { @@ -5644,7 +5644,7 @@ namespace realclosure { neg(a.m_value, neg_a); p.push_back(neg_a); for (unsigned i = 0; i < k - 1; i++) - p.push_back(0); + p.push_back(nullptr); p.push_back(one()); numeral_vector roots; @@ -5687,9 +5687,9 @@ namespace realclosure { // --------------------------------- int compare(value * a, value * b) { - if (a == 0) + if (a == nullptr) return -sign(b); - else if (b == 0) + else if (b == nullptr) return sign(a); else if (is_nz_rational(a) && is_nz_rational(b)) { if (qm().eq(to_mpq(a), to_mpq(b))) @@ -5744,7 +5744,7 @@ namespace realclosure { } void mark(value * v) { - if (v == 0 || is_nz_rational(v)) + if (v == nullptr || is_nz_rational(v)) return; rational_function_value * rf = to_rational_function(v); mark(rf->ext()); @@ -5779,7 +5779,7 @@ namespace realclosure { bool first = true; while (i > 0) { --i; - if (p[i] == 0) + if (p[i] == nullptr) continue; if (first) first = false; @@ -5893,7 +5893,7 @@ namespace realclosure { out << ", "; display_interval(out, a->iso_interval(), pp); out << ", "; - if (a->sdt() != 0) + if (a->sdt() != nullptr) display_sign_conditions(out, a->sdt()->sc(a->sc_idx()), a->sdt()->qs(), compact, pp); else out << "{}"; @@ -5931,7 +5931,7 @@ namespace realclosure { } void display(std::ostream & out, value * v, bool compact, bool pp=false) const { - if (v == 0) + if (v == nullptr) out << "0"; else if (is_nz_rational(v)) qm().display(out, to_mpq(v)); diff --git a/src/math/realclosure/realclosure.h b/src/math/realclosure/realclosure.h index c18f626a3..cfba0e99e 100644 --- a/src/math/realclosure/realclosure.h +++ b/src/math/realclosure/realclosure.h @@ -48,7 +48,7 @@ namespace realclosure { friend class save_interval_ctx; imp * m_imp; public: - manager(reslimit& lim, unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = 0); + manager(reslimit& lim, unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); ~manager(); typedef num numeral; typedef svector numeral_vector; @@ -271,7 +271,7 @@ namespace realclosure { friend struct manager::imp; value * m_value; public: - num():m_value(0) {} + num():m_value(nullptr) {} // Low level functions for implementing the C API void * c_ptr() { return m_value; } diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index ceec60622..89af0b3ad 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -745,7 +745,7 @@ namespace simplex { numeral const& base_coeff = vs.m_base_coeff; SASSERT(!m.is_zero(coeff)); bool base_to_lower = (m.is_pos(coeff) != m.is_pos(base_coeff)) == to_lower; - eps_numeral const* bound = 0; + eps_numeral const* bound = nullptr; if (!base_to_lower && vs.m_upper_valid) { bound = &vs.m_upper; } diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index be18a8702..0b48e0049 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -233,7 +233,7 @@ namespace simplex { return it; } } - return 0; + return nullptr; } template diff --git a/src/math/subpaving/subpaving.h b/src/math/subpaving/subpaving.h index 2c2c9978f..541f7ea7a 100644 --- a/src/math/subpaving/subpaving.h +++ b/src/math/subpaving/subpaving.h @@ -111,11 +111,11 @@ public: virtual void display_bounds(std::ostream & out) const = 0; }; - context * mk_mpq_context(reslimit& lim, unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = 0); -context * mk_mpf_context(reslimit& lim, f2n & m, params_ref const & p = params_ref(), small_object_allocator * a = 0); -context * mk_hwf_context(reslimit& lim, f2n & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = 0); -context * mk_mpff_context(reslimit& lim, mpff_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = 0); -context * mk_mpfx_context(reslimit& lim, mpfx_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = 0); + context * mk_mpq_context(reslimit& lim, unsynch_mpq_manager & m, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); +context * mk_mpf_context(reslimit& lim, f2n & m, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); +context * mk_hwf_context(reslimit& lim, f2n & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); +context * mk_mpff_context(reslimit& lim, mpff_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); +context * mk_mpfx_context(reslimit& lim, mpfx_manager & m, unsynch_mpq_manager & qm, params_ref const & p = params_ref(), small_object_allocator * a = nullptr); }; diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index a4bc02ff6..360b2a32f 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -210,7 +210,7 @@ public: bool inconsistent() const { return m_conflict != null_var; } void set_conflict(var x) { SASSERT(!inconsistent()); m_conflict = x; } bound * trail_stack() const { return m_trail; } - bound * parent_trail_stack() const { return m_parent == 0 ? 0 : m_parent->m_trail; } + bound * parent_trail_stack() const { return m_parent == nullptr ? nullptr : m_parent->m_trail; } bound * lower(var x) const { return bm().get(m_lowers, x); } bound * upper(var x) const { return bm().get(m_uppers, x); } node * parent() const { return m_parent; } @@ -221,7 +221,7 @@ public: /** \brief Return true if x is unbounded in this node */ - bool is_unbounded(var x) const { return lower(x) == 0 && upper(x) == 0; } + bool is_unbounded(var x) const { return lower(x) == nullptr && upper(x) == nullptr; } void push(bound * b); void set_first_child(node * n) { m_first_child = n; } @@ -275,32 +275,32 @@ public: numeral const & lower(interval const & a) const { if (a.m_constant) { bound * b = a.m_node->lower(a.m_x); - return b == 0 ? a.m_l_val /* don't care */ : b->value(); + return b == nullptr ? a.m_l_val /* don't care */ : b->value(); } return a.m_l_val; } numeral const & upper(interval const & a) const { if (a.m_constant) { bound * b = a.m_node->upper(a.m_x); - return b == 0 ? a.m_u_val /* don't care */ : b->value(); + return b == nullptr ? a.m_u_val /* don't care */ : b->value(); } return a.m_u_val; } numeral & lower(interval & a) { SASSERT(!a.m_constant); return a.m_l_val; } numeral & upper(interval & a) { SASSERT(!a.m_constant); return a.m_u_val; } - bool lower_is_inf(interval const & a) const { return a.m_constant ? a.m_node->lower(a.m_x) == 0 : a.m_l_inf; } - bool upper_is_inf(interval const & a) const { return a.m_constant ? a.m_node->upper(a.m_x) == 0 : a.m_u_inf; } + bool lower_is_inf(interval const & a) const { return a.m_constant ? a.m_node->lower(a.m_x) == nullptr : a.m_l_inf; } + bool upper_is_inf(interval const & a) const { return a.m_constant ? a.m_node->upper(a.m_x) == nullptr : a.m_u_inf; } bool lower_is_open(interval const & a) const { if (a.m_constant) { bound * b = a.m_node->lower(a.m_x); - return b == 0 || b->is_open(); + return b == nullptr || b->is_open(); } return a.m_l_open; } bool upper_is_open(interval const & a) const { if (a.m_constant) { bound * b = a.m_node->upper(a.m_x); - return b == 0 || b->is_open(); + return b == nullptr || b->is_open(); } return a.m_u_open; } @@ -367,7 +367,7 @@ public: private: void * m_data; public: - watched():m_data(0) {} + watched():m_data(nullptr) {} explicit watched(var x) { m_data = BOXTAGINT(void*, x, DEFINITION); } explicit watched(clause * c) { m_data = TAG(void*, c, CLAUSE); } kind get_kind() const { return static_cast(GET_TAG(m_data)); } @@ -563,7 +563,7 @@ private: void add_clause_core(unsigned sz, ineq * const * atoms, bool lemma, bool watched); void del_clause(clause * cls); - node * mk_node(node * parent = 0); + node * mk_node(node * parent = nullptr); void del_node(node * n); void del_nodes(); diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index 5729cbfa0..bb129fee7 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -93,7 +93,7 @@ public: if (!m_only_non_def || !this->ctx()->is_definition(x)) { bound * lower = n->lower(x); bound * upper = n->upper(x); - if (lower == 0 || upper == 0 || !nm.eq(lower->value(), upper->value())) { + if (lower == nullptr || upper == nullptr || !nm.eq(lower->value(), upper->value())) { return x; } } @@ -205,11 +205,11 @@ public: bound * lower = n->lower(x); bound * upper = n->upper(x); _scoped_numeral mid(nm); - if (lower == 0 && upper == 0) { + if (lower == nullptr && upper == nullptr) { nm.set(mid, 0); // mid == 0 } - else if (lower == 0) { + else if (lower == nullptr) { _scoped_numeral delta(nm); SASSERT(upper != 0); nm.set(delta, static_cast(m_delta)); @@ -218,7 +218,7 @@ public: nm.sub(mid, delta, mid); // mid == upper - delta } - else if (upper == 0) { + else if (upper == nullptr) { _scoped_numeral delta(nm); SASSERT(lower != 0); nm.set(delta, static_cast(m_delta)); @@ -294,17 +294,17 @@ context_t::node::node(context_t & s, unsigned id): m_depth = 0; unsigned num_vars = s.num_vars(); m_conflict = null_var; - m_trail = 0; - m_parent = 0; - m_first_child = 0; - m_next_sibling = 0; - m_prev = 0; - m_next = 0; + m_trail = nullptr; + m_parent = nullptr; + m_first_child = nullptr; + m_next_sibling = nullptr; + m_prev = nullptr; + m_next = nullptr; bm().mk(m_lowers); bm().mk(m_uppers); for (unsigned i = 0; i < num_vars; i++) { - bm().push_back(m_lowers, 0); - bm().push_back(m_uppers, 0); + bm().push_back(m_lowers, nullptr); + bm().push_back(m_uppers, nullptr); } } @@ -318,10 +318,10 @@ context_t::node::node(node * parent, unsigned id): m_conflict = parent->m_conflict; m_trail = parent->m_trail; m_parent = parent; - m_first_child = 0; + m_first_child = nullptr; m_next_sibling = parent->m_first_child; - m_prev = 0; - m_next = 0; + m_prev = nullptr; + m_next = nullptr; parent->m_first_child = this; } @@ -350,7 +350,7 @@ var context_t::splitting_var(node * n) const { if (n == m_root) return null_var; bound * b = n->trail_stack(); - while (b != 0) { + while (b != nullptr) { if (b->jst().is_axiom()) return b->x(); b = b->prev(); @@ -416,16 +416,16 @@ template context_t::context_t(reslimit& lim, C const & c, params_ref const & p, small_object_allocator * a): m_limit(lim), m_c(c), - m_own_allocator(a == 0), - m_allocator(a == 0 ? alloc(small_object_allocator, "subpaving") : a), + m_own_allocator(a == nullptr), + m_allocator(a == nullptr ? alloc(small_object_allocator, "subpaving") : a), m_bm(*this, *m_allocator), m_im(lim, interval_config(m_c.m())), m_num_buffer(nm()) { m_arith_failed = false; m_timestamp = 0; - m_root = 0; - m_leaf_head = 0; - m_leaf_tail = 0; + m_root = nullptr; + m_leaf_head = nullptr; + m_leaf_tail = nullptr; m_conflict = null_var; m_qhead = 0; m_display_proc = &m_default_display_proc; @@ -638,14 +638,14 @@ void context_t::display_bounds(std::ostream & out, node * n) const { for (unsigned x = 0; x < num; x++) { bound * l = n->lower(x); bound * u = n->upper(x); - if (l != 0) { + if (l != nullptr) { display(out, l); out << " "; } - if (u != 0) { + if (u != nullptr) { display(out, u); } - if (l != 0 || u != 0) + if (l != nullptr || u != nullptr) out << "\n"; } } @@ -878,7 +878,7 @@ template typename context_t::node * context_t::mk_node(node * parent) { void * mem = allocator().allocate(sizeof(node)); node * r; - if (parent == 0) + if (parent == nullptr) r = new (mem) node(*this, m_node_id_gen.mk()); else r = new (mem) node(parent, m_node_id_gen.mk()); @@ -910,7 +910,7 @@ void context_t::del_node(node * n) { node * p = n->parent(); bound * b = n->trail_stack(); bound * b_old; - if (p != 0) { + if (p != nullptr) { node * c = p->first_child(); if (c == n) { // n is the first child @@ -928,7 +928,7 @@ void context_t::del_node(node * n) { b_old = p->trail_stack(); } else { - b_old = 0; + b_old = nullptr; } while (b != b_old) { bound * old = b; @@ -944,18 +944,18 @@ void context_t::del_node(node * n) { template void context_t::del_nodes() { ptr_buffer todo; - if (m_root == 0) + if (m_root == nullptr) return; todo.push_back(m_root); while (!todo.empty()) { node * n = todo.back(); node * c = n->first_child(); - if (c == 0) { + if (c == nullptr) { del_node(n); todo.pop_back(); } else { - while (c != 0) { + while (c != nullptr) { todo.push_back(c); c = c->next_sibling(); } @@ -969,7 +969,7 @@ void context_t::push_front(node * n) { SASSERT(n->next() == 0); SASSERT(n->prev() == 0); n->set_next(m_leaf_head); - if (m_leaf_head != 0) { + if (m_leaf_head != nullptr) { SASSERT(m_leaf_head->prev() == 0); m_leaf_head->set_prev(n); } @@ -986,7 +986,7 @@ void context_t::push_back(node * n) { SASSERT(n->next() == 0); SASSERT(n->prev() == 0); n->set_prev(m_leaf_tail); - if (m_leaf_tail != 0) { + if (m_leaf_tail != nullptr) { SASSERT(m_leaf_tail->next() == 0); m_leaf_tail->set_next(n); } @@ -1001,14 +1001,14 @@ template void context_t::reset_leaf_dlist() { // Remove all nodes from the lead doubly linked list node * n = m_leaf_head; - while (n != 0) { + while (n != nullptr) { node * next = n->next(); - n->set_next(0); - n->set_prev(0); + n->set_next(nullptr); + n->set_prev(nullptr); n = next; } - m_leaf_head = 0; - m_leaf_tail = 0; + m_leaf_head = nullptr; + m_leaf_tail = nullptr; } template @@ -1016,18 +1016,18 @@ void context_t::rebuild_leaf_dlist(node * n) { reset_leaf_dlist(); // Reinsert all leaves in the leaf dlist. ptr_buffer todo; - if (m_root != 0) + if (m_root != nullptr) todo.push_back(m_root); while (!todo.empty()) { node * n = todo.back(); todo.pop_back(); node * c = n->first_child(); - if (c == 0) { + if (c == nullptr) { if (!n->inconsistent()) push_front(n); } else { - while (c != 0) { + while (c != nullptr) { SASSERT(c->parent() == n); todo.push_back(c); c = c->next_sibling(); @@ -1043,19 +1043,19 @@ void context_t::remove_from_leaf_dlist(node * n) { SASSERT(prev == 0 || prev != next); SASSERT(next == 0 || prev != next); SASSERT(prev != n); SASSERT(next != n); - if (prev != 0) { + if (prev != nullptr) { SASSERT(m_leaf_head != n); prev->set_next(next); - n->set_prev(0); + n->set_prev(nullptr); } else if (m_leaf_head == n) { m_leaf_head = next; } - if (next != 0) { + if (next != nullptr) { SASSERT(m_leaf_tail != n); next->set_prev(prev); - n->set_next(0); + n->set_next(nullptr); } else if (m_leaf_tail == n) { m_leaf_tail = prev; @@ -1067,18 +1067,18 @@ template void context_t::collect_leaves(ptr_vector & leaves) const { // Copy all leaves to the given vector. ptr_buffer todo; - if (m_root != 0) + if (m_root != nullptr) todo.push_back(m_root); while (!todo.empty()) { node * n = todo.back(); todo.pop_back(); node * c = n->first_child(); - if (c == 0) { + if (c == nullptr) { if (!n->inconsistent()) leaves.push_back(n); } else { - while (c != 0) { + while (c != nullptr) { SASSERT(c->parent() == n); todo.push_back(c); c = c->next_sibling(); @@ -1115,7 +1115,7 @@ void context_t::del_definitions() { unsigned sz = num_vars(); for (unsigned i = 0; i < sz; i++) { definition * d = m_defs[i]; - if (d == 0) + if (d == nullptr) continue; switch (d->get_kind()) { case constraint::MONOMIAL: @@ -1219,24 +1219,24 @@ bool context_t::relevant_new_bound(var x, numeral const & k, bool lower, bool return true; } // If m_epsilon is zero, then bound is relevant only if it improves existing bound. - if (m_zero_epsilon && curr_lower != 0 && (nm().lt(k, curr_lower->value()) || ((curr_lower->is_open() || !open) && nm().eq(k, curr_lower->value())))) { + if (m_zero_epsilon && curr_lower != nullptr && (nm().lt(k, curr_lower->value()) || ((curr_lower->is_open() || !open) && nm().eq(k, curr_lower->value())))) { // new lower bound does not improve existing bound TRACE("subpaving_relevant_bound", tout << "irrelevant because does not improve existing bound.\n";); return false; } - if (curr_upper == 0 && nm().lt(m_max_bound, k)) { + if (curr_upper == nullptr && nm().lt(m_max_bound, k)) { // new lower bound exceeds the :max-bound threshold TRACE("subpaving_relevant_bound", tout << "irrelevant because exceeds :max-bound threshold.\n";); return false; } - if (!m_zero_epsilon && curr_lower != 0) { + if (!m_zero_epsilon && curr_lower != nullptr) { // check if: // new-lower > lower + m_epsilon * max(min(upper - lower, |lower|), 1) numeral & min = m_tmp1; numeral & abs_lower = m_tmp2; nm().set(abs_lower, curr_lower->value()); nm().abs(abs_lower); - if (curr_upper != 0) { + if (curr_upper != nullptr) { nm().sub(curr_upper->value(), curr_lower->value(), min); if (nm().lt(abs_lower, min)) nm().set(min, abs_lower); @@ -1269,24 +1269,24 @@ bool context_t::relevant_new_bound(var x, numeral const & k, bool lower, bool return true; } // If m_epsilon is zero, then bound is relevant only if it improves existing bound. - if (m_zero_epsilon && curr_upper != 0 && (nm().lt(curr_upper->value(), k) || ((curr_upper->is_open() || !open) && nm().eq(k, curr_upper->value())))) { + if (m_zero_epsilon && curr_upper != nullptr && (nm().lt(curr_upper->value(), k) || ((curr_upper->is_open() || !open) && nm().eq(k, curr_upper->value())))) { // new upper bound does not improve existing bound TRACE("subpaving_relevant_bound", tout << "irrelevant because does not improve existing bound.\n";); return false; } - if (curr_lower == 0 && nm().lt(k, m_minus_max_bound)) { + if (curr_lower == nullptr && nm().lt(k, m_minus_max_bound)) { // new upper bound exceeds the -:max-bound threshold TRACE("subpaving_relevant_bound", tout << "irrelevant because exceeds -:max-bound threshold.\n";); return false; } - if (!m_zero_epsilon && curr_upper != 0) { + if (!m_zero_epsilon && curr_upper != nullptr) { // check if: // new-upper < upper - m_epsilon * max(min(upper - lower, |upper|), 1) numeral & min = m_tmp1; numeral & abs_upper = m_tmp2; nm().set(abs_upper, curr_upper->value()); nm().abs(abs_upper); - if (curr_lower != 0) { + if (curr_lower != nullptr) { nm().sub(curr_upper->value(), curr_lower->value(), min); if (nm().lt(abs_upper, min)) nm().set(min, abs_upper); @@ -1323,14 +1323,14 @@ bool context_t::is_zero(var x, node * n) const { // Return true if lower(x) == upper(x) == 0 at n bound * l = n->lower(x); bound * u = n->upper(x); - return l != 0 && u != 0 && nm().is_zero(l->value()) && nm().is_zero(u->value()) && !l->is_open() && !u->is_open(); + return l != nullptr && u != nullptr && nm().is_zero(l->value()) && nm().is_zero(u->value()) && !l->is_open() && !u->is_open(); } template bool context_t::is_upper_zero(var x, node * n) const { // Return true if upper(x) is zero at node n bound * u = n->upper(x); - return u != 0 && nm().is_zero(u->value()) && !u->is_open(); + return u != nullptr && nm().is_zero(u->value()) && !u->is_open(); } template @@ -1338,7 +1338,7 @@ bool context_t::conflicting_bounds(var x, node * n) const { // Return true if upper(x) < lower(x) at node n bound * l = n->lower(x); bound * u = n->upper(x); - return l != 0 && u != 0 && (nm().lt(u->value(), l->value()) || ((l->is_open() || u->is_open()) && nm().eq(u->value(), l->value()))); + return l != nullptr && u != nullptr && (nm().lt(u->value(), l->value()) || ((l->is_open() || u->is_open()) && nm().eq(u->value(), l->value()))); } /** @@ -1351,20 +1351,20 @@ lbool context_t::value(ineq * t, node * n) { var x = t->x(); bound * u = n->upper(x); bound * l = n->lower(x); - if (u == 0 && l == 0) + if (u == nullptr && l == nullptr) return l_undef; else if (t->is_lower()) { - if (u != 0 && (nm().lt(u->value(), t->value()) || ((u->is_open() || t->is_open()) && nm().eq(u->value(), t->value())))) + if (u != nullptr && (nm().lt(u->value(), t->value()) || ((u->is_open() || t->is_open()) && nm().eq(u->value(), t->value())))) return l_false; - else if (l != 0 && (nm().gt(l->value(), t->value()) || ((l->is_open() || !t->is_open()) && nm().eq(l->value(), t->value())))) + else if (l != nullptr && (nm().gt(l->value(), t->value()) || ((l->is_open() || !t->is_open()) && nm().eq(l->value(), t->value())))) return l_true; else return l_undef; } else { - if (l != 0 && (nm().gt(l->value(), t->value()) || ((l->is_open() || t->is_open()) && nm().eq(l->value(), t->value())))) + if (l != nullptr && (nm().gt(l->value(), t->value()) || ((l->is_open() || t->is_open()) && nm().eq(l->value(), t->value())))) return l_false; - else if (u != 0 && (nm().lt(u->value(), t->value()) || ((u->is_open() || !t->is_open()) && nm().eq(u->value(), t->value())))) + else if (u != nullptr && (nm().lt(u->value(), t->value()) || ((u->is_open() || !t->is_open()) && nm().eq(u->value(), t->value())))) return l_true; else return l_undef; @@ -1804,17 +1804,17 @@ void context_t::init() { template void context_t::operator()() { - if (m_root == 0) + if (m_root == nullptr) init(); TRACE("subpaving_stats", statistics st; collect_statistics(st); tout << "statistics:\n"; st.display_smt2(tout);); TRACE("subpaving_main", display_params(tout);); - while (m_leaf_head != 0) { + while (m_leaf_head != nullptr) { checkpoint(); SASSERT(m_queue.empty()); if (m_num_nodes > m_max_nodes) break; node * n = (*m_node_selector)(m_leaf_head, m_leaf_tail); - if (n == 0) + if (n == nullptr) break; TRACE("subpaving_main", tout << "selected node: #" << n->id() << ", depth: " << n->depth() << "\n";); remove_from_leaf_dlist(n); @@ -1892,7 +1892,7 @@ void context_t::collect_statistics(statistics & st) const { template bool context_t::is_bound_of(bound * b, node * n) const { bound * c = n->trail_stack(); - while (c != 0) { + while (c != nullptr) { if (c == b) return true; if (c->timestamp() <= b->timestamp()) @@ -1905,7 +1905,7 @@ bool context_t::is_bound_of(bound * b, node * n) const { template bool context_t::check_leaf_dlist() const { node * n = m_leaf_head; - while (n != 0) { + while (n != nullptr) { node * next = n->next(); SASSERT(next != 0 || m_leaf_tail == n); SASSERT(next == 0 || next->prev() == n); @@ -1917,13 +1917,13 @@ bool context_t::check_leaf_dlist() const { template bool context_t::check_tree() const { ptr_buffer todo; - if (m_root != 0) + if (m_root != nullptr) todo.push_back(m_root); while (!todo.empty()) { node * n = todo.back(); todo.pop_back(); node * c = n->first_child(); - while (c != 0) { + while (c != nullptr) { SASSERT(c->parent() == n); todo.push_back(c); c = c->next_sibling(); diff --git a/src/math/subpaving/tactic/expr2subpaving.cpp b/src/math/subpaving/tactic/expr2subpaving.cpp index b00c0007f..1eb4ad108 100644 --- a/src/math/subpaving/tactic/expr2subpaving.cpp +++ b/src/math/subpaving/tactic/expr2subpaving.cpp @@ -30,7 +30,7 @@ struct expr2subpaving::imp { struct frame { app * m_curr; unsigned m_idx; - frame():m_curr(0), m_idx(0) {} + frame():m_curr(nullptr), m_idx(0) {} frame(app * t):m_curr(t), m_idx(0) {} }; @@ -62,7 +62,7 @@ struct expr2subpaving::imp { m_cached_numerators(m_qm), m_cached_denominators(m_qm) { - if (e2v == 0) { + if (e2v == nullptr) { m_expr2var = alloc(expr2var, m); m_expr2var_owner = true; } @@ -107,7 +107,7 @@ struct expr2subpaving::imp { x = s().mk_var(is_int); m_expr2var->insert(t, x); if (x >= m_var2expr.size()) - m_var2expr.resize(x+1, 0); + m_var2expr.resize(x+1, nullptr); m_var2expr.set(x, t); } return x; diff --git a/src/math/subpaving/tactic/expr2subpaving.h b/src/math/subpaving/tactic/expr2subpaving.h index d95699759..32caf49a9 100644 --- a/src/math/subpaving/tactic/expr2subpaving.h +++ b/src/math/subpaving/tactic/expr2subpaving.h @@ -29,7 +29,7 @@ class expr2subpaving { struct imp; imp * m_imp; public: - expr2subpaving(ast_manager & m, subpaving::context & s, expr2var * e2v = 0); + expr2subpaving(ast_manager & m, subpaving::context & s, expr2var * e2v = nullptr); ~expr2subpaving(); ast_manager & m() const; diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index ebc9356d9..1f5f87eef 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -41,8 +41,8 @@ class subpaving_tactic : public tactic { ast_manager & m() const { return m_inv.get_manager(); } void operator()(std::ostream & out, subpaving::var x) const override { - expr * t = m_inv.get(x, 0); - if (t != 0) + expr * t = m_inv.get(x, nullptr); + if (t != nullptr) out << mk_ismt2_pp(t, m()); else out << "k!" << x; @@ -160,7 +160,7 @@ class subpaving_tactic : public tactic { } void process_clause(expr * c) { - expr * const * args = 0; + expr * const * args = nullptr; unsigned sz; if (m().is_or(c)) { args = to_app(c)->get_args(); @@ -251,9 +251,9 @@ public: m_imp->collect_statistics(m_stats); result.reset(); result.push_back(in.get()); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; } catch (z3_exception & ex) { // convert all Z3 exceptions into tactic exceptions diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp index e458cc4b0..accb45a25 100644 --- a/src/model/func_interp.cpp +++ b/src/model/func_interp.cpp @@ -71,9 +71,9 @@ void func_entry::deallocate(ast_manager & m, unsigned arity) { func_interp::func_interp(ast_manager & m, unsigned arity): m_manager(m), m_arity(arity), - m_else(0), + m_else(nullptr), m_args_are_values(true), - m_interp(0) { + m_interp(nullptr) { } func_interp::~func_interp() { @@ -102,7 +102,7 @@ func_interp * func_interp::copy() const { void func_interp::reset_interp_cache() { m_manager.dec_ref(m_interp); - m_interp = 0; + m_interp = nullptr; } bool func_interp::is_fi_entry_expr(expr * e, ptr_vector & args) { @@ -183,13 +183,13 @@ func_entry * func_interp::get_entry(expr * const * args) const { if (curr->eq_args(m(), m_arity, args)) return curr; } - return 0; + return nullptr; } void func_interp::insert_entry(expr * const * args, expr * r) { reset_interp_cache(); func_entry * entry = get_entry(args); - if (entry != 0) { + if (entry != nullptr) { entry->set_result(m_manager, r); return; } @@ -219,7 +219,7 @@ void func_interp::insert_new_entry(expr * const * args, expr * r) { } bool func_interp::eval_else(expr * const * args, expr_ref & result) const { - if (m_else == 0) + if (m_else == nullptr) return false; var_subst s(m_manager, false); SASSERT(!s.std_order()); // (VAR 0) <- args[0], (VAR 1) <- args[1], ... @@ -232,9 +232,9 @@ bool func_interp::eval_else(expr * const * args, expr_ref & result) const { */ expr * func_interp::get_max_occ_result() const { if (m_entries.empty()) - return 0; + return nullptr; obj_map num_occs; - expr * r_max = 0; + expr * r_max = nullptr; unsigned max = 0; ptr_vector::const_iterator it = m_entries.begin(); ptr_vector::const_iterator end = m_entries.end(); @@ -257,7 +257,7 @@ expr * func_interp::get_max_occ_result() const { \brief Remove entries e such that e.get_result() == m_else. */ void func_interp::compress() { - if (m_else == 0 || m_entries.empty()) + if (m_else == nullptr || m_entries.empty()) return; // nothing to be done if (!is_ground(m_else)) return; // forall entries e in m_entries e.get_result() is ground @@ -284,8 +284,8 @@ void func_interp::compress() { } expr * func_interp::get_interp_core() const { - if (m_else == 0) - return 0; + if (m_else == nullptr) + return nullptr; expr * r = m_else; ptr_buffer vars; ptr_vector::const_iterator it = m_entries.begin(); @@ -313,10 +313,10 @@ expr * func_interp::get_interp_core() const { } expr * func_interp::get_interp() const { - if (m_interp != 0) + if (m_interp != nullptr) return m_interp; expr * r = get_interp_core(); - if (r != 0) { + if (r != nullptr) { const_cast(this)->m_interp = r; m_manager.inc_ref(m_interp); } diff --git a/src/model/func_interp.h b/src/model/func_interp.h index 47eb0e82c..e2b98d6ea 100644 --- a/src/model/func_interp.h +++ b/src/model/func_interp.h @@ -86,7 +86,7 @@ public: unsigned get_arity() const { return m_arity; } - bool is_partial() const { return m_else == 0; } + bool is_partial() const { return m_else == nullptr; } // A function interpretation is said to be simple if m_else is ground. bool is_simple() const { return is_partial() || is_ground(m_else); } bool is_constant() const; diff --git a/src/model/model.cpp b/src/model/model.cpp index 7823a6f6b..486b1e92e 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -94,12 +94,12 @@ struct model::value_proc : public some_value_proc { model & m_model; value_proc(model & m):m_model(m) {} expr * operator()(sort * s) override { - ptr_vector * u = 0; + ptr_vector * u = nullptr; if (m_model.m_usort2universe.find(s, u)) { if (u->size() > 0) return u->get(0); } - return 0; + return nullptr; } }; @@ -109,16 +109,16 @@ expr * model::get_some_value(sort * s) { } ptr_vector const & model::get_universe(sort * s) const { - ptr_vector * u = 0; + ptr_vector * u = nullptr; m_usort2universe.find(s, u); SASSERT(u != 0); return *u; } bool model::has_uninterpreted_sort(sort * s) const { - ptr_vector * u = 0; + ptr_vector * u = nullptr; m_usort2universe.find(s, u); - return u != 0; + return u != nullptr; } unsigned model::get_num_uninterpreted_sorts() const { diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 833c254c3..648768bf3 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -37,7 +37,7 @@ bool model_core::eval(func_decl* f, expr_ref & r) const { } else { func_interp * fi = get_func_interp(f); - if (fi != 0) { + if (fi != nullptr) { r = fi->get_interp(); return r != 0; } diff --git a/src/model/model_core.h b/src/model/model_core.h index ec128c796..ce211c0b8 100644 --- a/src/model/model_core.h +++ b/src/model/model_core.h @@ -44,8 +44,8 @@ public: unsigned get_num_decls() const { return m_decls.size(); } func_decl * get_decl(unsigned i) const { return m_decls[i]; } bool has_interpretation(func_decl * d) const { return m_interp.contains(d) || m_finterp.contains(d); } - expr * get_const_interp(func_decl * d) const { expr * v; return m_interp.find(d, v) ? v : 0; } - func_interp * get_func_interp(func_decl * d) const { func_interp * fi; return m_finterp.find(d, fi) ? fi : 0; } + expr * get_const_interp(func_decl * d) const { expr * v; return m_interp.find(d, v) ? v : nullptr; } + func_interp * get_func_interp(func_decl * d) const { func_interp * fi; return m_finterp.find(d, fi) ? fi : nullptr; } bool eval(func_decl * f, expr_ref & r) const; diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 32ed1e236..fd2dc7656 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -91,7 +91,7 @@ struct evaluator_cfg : public default_rewriter_cfg { bool evaluate(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { func_interp * fi = m_model.get_func_interp(f); - return (fi != 0) && eval_fi(fi, num, args, result); + return (fi != nullptr) && eval_fi(fi, num, args, result); } // Try to use the entries to quickly evaluate the fi @@ -110,7 +110,7 @@ struct evaluator_cfg : public default_rewriter_cfg { return false; // let get_macro handle it func_entry * entry = fi->get_entry(args); - if (entry != 0) { + if (entry != nullptr) { result = entry->get_result(); return true; } @@ -119,12 +119,12 @@ struct evaluator_cfg : public default_rewriter_cfg { } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; family_id fid = f->get_family_id(); bool is_uninterp = fid != null_family_id && m.get_plugin(fid)->is_considered_uninterpreted(f); if (num == 0 && (fid == null_family_id || is_uninterp)) { expr * val = m_model.get_const_interp(f); - if (val != 0) { + if (val != nullptr) { result = val; return BR_DONE; } @@ -224,7 +224,7 @@ struct evaluator_cfg : public default_rewriter_cfg { func_interp * fi = m_model.get_func_interp(f); - if (fi != 0) { + if (fi != nullptr) { TRACE_MACRO; if (fi->is_partial()) { if (m_model_completion) { @@ -262,8 +262,8 @@ struct evaluator_cfg : public default_rewriter_cfg { expr_ref & result, proof_ref & result_pr) { SASSERT(f != 0); SASSERT(!m.is_builtin_family_id(f->get_family_id())); - result = 0; - result_pr = 0; + result = nullptr; + result_pr = nullptr; func_interp * fi = m_model.get_func_interp(f); if (fi) { @@ -382,7 +382,7 @@ struct evaluator_cfg : public default_rewriter_cfg { continue; } table2.insert(stores2[i].c_ptr()); - expr * const* args = 0; + expr * const* args = nullptr; expr* val = stores2[i][arity]; if (table1.find(stores2[i].c_ptr(), args)) { switch (compare(args[arity], val)) { diff --git a/src/model/model_implicant.cpp b/src/model/model_implicant.cpp index 6abdacfba..3456c2746 100644 --- a/src/model/model_implicant.cpp +++ b/src/model/model_implicant.cpp @@ -90,7 +90,7 @@ void model_implicant::reset() { m_visited.reset(); m_numbers.reset(); m_refs.reset(); - m_model = 0; + m_model = nullptr; } expr_ref_vector model_implicant::minimize_model(ptr_vector const & formulas, model_ref& mdl) { @@ -666,8 +666,8 @@ void model_implicant::eval_eq(app* e, expr* arg1, expr* arg2) { } void model_implicant::eval_basic(app* e) { - expr* arg1 = 0, *arg2 = 0; - expr *argCond = 0, *argThen = 0, *argElse = 0, *arg = 0; + expr* arg1 = nullptr, *arg2 = nullptr; + expr *argCond = nullptr, *argThen = nullptr, *argElse = nullptr, *arg = nullptr; bool has_x = false; unsigned arity = e->get_num_args(); switch(e->get_decl_kind()) { diff --git a/src/muz/base/dl_boogie_proof.h b/src/muz/base/dl_boogie_proof.h index f335159b6..ed2f5a801 100644 --- a/src/muz/base/dl_boogie_proof.h +++ b/src/muz/base/dl_boogie_proof.h @@ -82,7 +82,7 @@ namespace datalog { void get_labels(proof* p, labels&); public: - boogie_proof(ast_manager& m): m(m), m_proof(m), m_model(0) {} + boogie_proof(ast_manager& m): m(m), m_proof(m), m_model(nullptr) {} void set_proof(proof* p); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 106c15d5f..47d7cc357 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -154,7 +154,7 @@ namespace datalog { rule_set* m_old_rules; void reset() { dealloc(m_old_rules); - m_old_rules = 0; + m_old_rules = nullptr; } public: restore_rules(rule_set& r): m_old_rules(alloc(rule_set, r)) {} @@ -221,9 +221,9 @@ namespace datalog { m_rule_fmls_head(0), m_rule_fmls(m), m_background(m), - m_mc(0), - m_rel(0), - m_engine(0), + m_mc(nullptr), + m_rel(nullptr), + m_engine(nullptr), m_closed(false), m_saturation_was_run(false), m_enable_bind_variables(true), @@ -251,8 +251,8 @@ namespace datalog { m_preds.reset(); m_preds_by_name.reset(); reset_dealloc_values(m_sorts); - m_engine = 0; - m_rel = 0; + m_engine = nullptr; + m_rel = nullptr; } bool context::is_fact(app * head) const { @@ -465,7 +465,7 @@ namespace datalog { scoped_proof_mode _scp(m, generate_proof_trace()?PGM_ENABLED:PGM_DISABLED); while (m_rule_fmls_head < m_rule_fmls.size()) { expr* fml = m_rule_fmls[m_rule_fmls_head].get(); - proof* p = generate_proof_trace()?m.mk_asserted(fml):0; + proof* p = generate_proof_trace()?m.mk_asserted(fml):nullptr; rm.mk_rule(fml, p, m_rule_set, m_rule_names[m_rule_fmls_head]); ++m_rule_fmls_head; } @@ -478,7 +478,7 @@ namespace datalog { // void context::update_rule(expr* rl, symbol const& name) { datalog::rule_manager& rm = get_rule_manager(); - proof* p = 0; + proof* p = nullptr; if (generate_proof_trace()) { p = m.mk_asserted(rl); } @@ -493,7 +493,7 @@ namespace datalog { // The new rule is inserted last: rule_ref r(m_rule_set.get_rule(size_before), rm); rule_ref_vector const& rls = m_rule_set.get_rules(); - rule* old_rule = 0; + rule* old_rule = nullptr; for (unsigned i = 0; i < size_before; ++i) { if (rls[i]->name() == name) { if (old_rule) { @@ -861,8 +861,8 @@ namespace datalog { lbool context::query(expr* query) { m_mc = mk_skip_model_converter(); m_last_status = OK; - m_last_answer = 0; - m_last_ground_answer = 0; + m_last_answer = nullptr; + m_last_ground_answer = nullptr; switch (get_engine()) { case DATALOG_ENGINE: case SPACER_ENGINE: @@ -890,8 +890,8 @@ namespace datalog { lbool context::query_from_lvl (expr* query, unsigned lvl) { m_mc = mk_skip_model_converter(); m_last_status = OK; - m_last_answer = 0; - m_last_ground_answer = 0; + m_last_answer = nullptr; + m_last_ground_answer = nullptr; switch (get_engine()) { case DATALOG_ENGINE: case SPACER_ENGINE: @@ -933,7 +933,7 @@ namespace datalog { } lbool context::rel_query(unsigned num_rels, func_decl * const* rels) { - m_last_answer = 0; + m_last_answer = nullptr; ensure_engine(); return m_engine->query(num_rels, rels); } @@ -1059,7 +1059,7 @@ namespace datalog { for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { m_free_vars(m_rule_fmls[i].get()); if (!m_free_vars.empty()) { - rm.mk_rule(m_rule_fmls[i].get(), 0, m_rule_set, m_rule_names[i]); + rm.mk_rule(m_rule_fmls[i].get(), nullptr, m_rule_set, m_rule_names[i]); m_rule_fmls[i] = m_rule_fmls.back(); m_rule_names[i] = m_rule_names.back(); m_rule_fmls.pop_back(); diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 3051dbf86..f37826feb 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -331,7 +331,7 @@ namespace datalog { names. Generally, the names coming from the parses are registered here. */ func_decl * try_get_predicate_decl(symbol const& pred_name) const { - func_decl * res = 0; + func_decl * res = nullptr; m_preds_by_name.find(pred_name, res); return res; } @@ -341,7 +341,7 @@ namespace datalog { */ func_decl * mk_fresh_head_predicate(symbol const & prefix, symbol const & suffix, - unsigned arity, sort * const * domain, func_decl* orig_pred=0); + unsigned arity, sort * const * domain, func_decl* orig_pred=nullptr); /** diff --git a/src/muz/base/dl_costs.cpp b/src/muz/base/dl_costs.cpp index f97a4d451..d429af803 100644 --- a/src/muz/base/dl_costs.cpp +++ b/src/muz/base/dl_costs.cpp @@ -128,7 +128,7 @@ namespace datalog { // // ----------------------------------- - cost_recorder::cost_recorder() : m_obj(0) { + cost_recorder::cost_recorder() : m_obj(nullptr) { m_stopwatch = alloc(stopwatch); m_stopwatch->start(); } @@ -149,7 +149,7 @@ namespace datalog { c.milliseconds+=time_delta; m_obj->m_being_recorded = false; } - m_running = obj!=0; + m_running = obj!=nullptr; m_obj = obj; m_last_time = curr_time; if(obj) { diff --git a/src/muz/base/dl_costs.h b/src/muz/base/dl_costs.h index fd5a99f15..59d4fd8c1 100644 --- a/src/muz/base/dl_costs.h +++ b/src/muz/base/dl_costs.h @@ -63,7 +63,7 @@ namespace datalog { costs m_processed_cost; bool m_being_recorded; protected: - accounted_object() : m_context(0), m_parent_object(0), m_being_recorded(false) {} + accounted_object() : m_context(nullptr), m_parent_object(nullptr), m_being_recorded(false) {} ~accounted_object(); public: @@ -107,7 +107,7 @@ namespace datalog { before separately. */ void start(accounted_object *); - void finish() { start(0); } + void finish() { start(nullptr); } }; }; diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 4f832c4c9..68e0aca6b 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -81,7 +81,7 @@ namespace datalog { } var_idx_set& rule_manager::collect_vars(expr* e) { - return collect_vars(e, 0); + return collect_vars(e, nullptr); } var_idx_set& rule_manager::collect_vars(expr* e1, expr* e2) { @@ -274,11 +274,11 @@ namespace datalog { bind_variables(query, false, q); quantifier_hoister qh(m); - qh.pull_quantifier(false, q, 0, &names); + qh.pull_quantifier(false, q, nullptr, &names); // retrieve free variables. m_free_vars(q); vars.append(m_free_vars.size(), m_free_vars.c_ptr()); - if (vars.contains(static_cast(0))) { + if (vars.contains(static_cast(nullptr))) { var_subst sub(m, false); expr_ref_vector args(m); // [s0, 0, s2, ..] @@ -306,7 +306,7 @@ namespace datalog { } body.push_back(to_app(q)); flatten_body(body); - func_decl* body_pred = 0; + func_decl* body_pred = nullptr; for (unsigned i = 0; i < body.size(); i++) { if (is_uninterp(body[i].get())) { body_pred = body[i]->get_decl(); @@ -472,7 +472,7 @@ namespace datalog { r->m_head = head; r->m_name = name; r->m_tail_size = n; - r->m_proof = 0; + r->m_proof = nullptr; m.inc_ref(r->m_head); app * * uninterp_tail = r->m_tail; //grows upwards @@ -482,7 +482,7 @@ namespace datalog { bool has_neg = false; for (unsigned i = 0; i < n; i++) { - bool is_neg = (is_negated != 0 && is_negated[i]); + bool is_neg = (is_negated != nullptr && is_negated[i]); app * curr = tail[i]; if (is_neg && !m_ctx.is_predicate(curr)) { @@ -548,7 +548,7 @@ namespace datalog { r->m_tail_size = n; r->m_positive_cnt = source->m_positive_cnt; r->m_uninterp_cnt = source->m_uninterp_cnt; - r->m_proof = 0; + r->m_proof = nullptr; m.inc_ref(r->m_head); for (unsigned i = 0; i < n; i++) { r->m_tail[i] = source->m_tail[i]; @@ -978,7 +978,7 @@ namespace datalog { subst_vals.push_back(m.mk_var(next_fresh_var++, var_srt)); } else { - subst_vals.push_back(0); + subst_vals.push_back(nullptr); } } diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index ea0e64e4f..2537adbb0 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -54,7 +54,7 @@ namespace datalog { bool m_found; func_decl* m_func; uninterpreted_function_finder_proc(ast_manager& m): - m(m), m_dt(m), m_dl(m), m_found(false), m_func(0) {} + m(m), m_dt(m), m_dl(m), m_found(false), m_func(nullptr) {} void operator()(var * n) { } void operator()(quantifier * n) { } void operator()(app * n) { @@ -71,7 +71,7 @@ namespace datalog { } } } - void reset() { m_found = false; m_func = 0; } + void reset() { m_found = false; m_func = nullptr; } bool found(func_decl*& f) const { f = m_func; return m_found; } }; @@ -209,7 +209,7 @@ namespace datalog { \remark A tail may contain negation. tail[i] is assumed to be negated if is_neg != 0 && is_neg[i] == true */ - rule * mk(app * head, unsigned n, app * const * tail, bool const * is_neg = 0, + rule * mk(app * head, unsigned n, app * const * tail, bool const * is_neg = nullptr, symbol const& name = symbol::null, bool normalize = true); /** diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index 65c940091..acd200d44 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -282,7 +282,7 @@ namespace datalog { m_rule_manager(ctx.get_rule_manager()), m_rules(m_rule_manager), m_deps(ctx), - m_stratifier(0), + m_stratifier(nullptr), m_refs(ctx.get_manager()) { } @@ -291,7 +291,7 @@ namespace datalog { m_rule_manager(other.m_rule_manager), m_rules(m_rule_manager), m_deps(other.m_context), - m_stratifier(0), + m_stratifier(nullptr), m_refs(m_context.get_manager()) { add_rules(other); if (other.m_stratifier) { @@ -307,7 +307,7 @@ namespace datalog { m_rules.reset(); reset_dealloc_values(m_head2rules); m_deps.reset(); - m_stratifier = 0; + m_stratifier = nullptr; m_output_preds.reset(); m_orig2pred.reset(); m_pred2orig.reset(); @@ -401,7 +401,7 @@ namespace datalog { m_deps.populate(*this); m_stratifier = alloc(rule_stratifier, m_deps); if (!stratified_negation()) { - m_stratifier = 0; + m_stratifier = nullptr; m_deps.reset(); return false; } @@ -410,7 +410,7 @@ namespace datalog { void rule_set::reopen() { if (is_closed()) { - m_stratifier = 0; + m_stratifier = nullptr; m_deps.reset(); } } diff --git a/src/muz/base/dl_rule_transformer.h b/src/muz/base/dl_rule_transformer.h index dc930ae2b..2bcc1da5c 100644 --- a/src/muz/base/dl_rule_transformer.h +++ b/src/muz/base/dl_rule_transformer.h @@ -87,7 +87,7 @@ namespace datalog { (higher priority plugins will be applied first). */ plugin(unsigned priority, bool can_destratify_negation = false) : m_priority(priority), - m_can_destratify_negation(can_destratify_negation), m_transformer(0) {} + m_can_destratify_negation(can_destratify_negation), m_transformer(nullptr) {} public: virtual ~plugin() {} diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index aceeba364..c2622cec4 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -34,7 +34,7 @@ Revision History: namespace datalog { - verbose_action::verbose_action(char const* msg, unsigned lvl): m_lvl(lvl), m_sw(0) { + verbose_action::verbose_action(char const* msg, unsigned lvl): m_lvl(lvl), m_sw(nullptr) { IF_VERBOSE(m_lvl, (verbose_stream() << msg << "...").flush(); m_sw = alloc(stopwatch); @@ -87,7 +87,7 @@ namespace datalog { else { SASSERT(is_var(arg)); int vidx = to_var(arg)->get_idx(); - var * new_var = 0; + var * new_var = nullptr; if (!varidx2var.find(vidx, new_var)) { new_var = m.mk_var(next_idx, to_var(arg)->get_sort()); next_idx++; @@ -428,7 +428,7 @@ namespace datalog { unsigned tgt_sz = max_var_idx+1; unsigned tgt_ofs = tgt_sz-1; - tgt.resize(tgt_sz, 0); + tgt.resize(tgt_sz, nullptr); for(unsigned i=0; i=0; i--) { out << (len-1-i) <<"->"; - if(cont.get(i)==0) { + if(cont.get(i)==nullptr) { out << "{none}"; } else { diff --git a/src/muz/base/hnf.cpp b/src/muz/base/hnf.cpp index 7db30a9f0..f0cbc0620 100644 --- a/src/muz/base/hnf.cpp +++ b/src/muz/base/hnf.cpp @@ -153,7 +153,7 @@ public: m_fresh_predicates.reset(); m_todo.push_back(n); m_proofs.push_back(p); - m_produce_proofs = p != 0; + m_produce_proofs = p != nullptr; while (!m_todo.empty() && checkpoint()) { fml = m_todo.back(); pr = m_proofs.back(); @@ -269,7 +269,7 @@ private: expr* const* args = _or->get_args(); for (unsigned i = 0; i < sz; ++i) { m_todo.push_back(bind_variables(m.mk_implies(args[i], head))); - m_proofs.push_back(0); + m_proofs.push_back(nullptr); } if (premise) { @@ -284,7 +284,7 @@ private: m_proofs[m_proofs.size()-sz+i] = m.mk_and_elim(p2, i); } } - fml = 0; + fml = nullptr; return; } @@ -330,7 +330,7 @@ private: bool is_disj = false; expr_ref_vector _body(m); unsigned num_disj = 0; - expr* const* disjs = 0; + expr* const* disjs = nullptr; if (!contains_predicate(b)) { return; } @@ -356,7 +356,7 @@ private: negate_args = false; } if (is_disj) { - app* old_head = 0; + app* old_head = nullptr; if (m_memoize_disj.find(b, old_head)) { body = old_head; } @@ -369,7 +369,7 @@ private: e = m.mk_not(e); } m_todo.push_back(bind_variables(m.mk_implies(e, head))); - m_proofs.push_back(0); + m_proofs.push_back(nullptr); if (produce_proofs()) { defs.push_back(m.mk_def_intro(m_todo.back())); m_proofs[m_proofs.size()-1] = defs.back(); @@ -423,7 +423,7 @@ private: if (!is_predicate(e)) { app_ref head = mk_fresh_head(e); m_todo.push_back(bind_variables(m.mk_implies(e, head))); - m_proofs.push_back(0); + m_proofs.push_back(nullptr); body = m.update_quantifier(q, head); if (produce_proofs()) { proof* def_intro = m.mk_def_intro(m_todo.back()); diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 3368c7640..56b7e449d 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -270,7 +270,7 @@ namespace datalog { TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";); expr_ref_vector sub(m); rule_vector const& rls = b.m_rules.get_predicate_rules(pred); - rule* r = 0; + rule* r = nullptr; unsigned i = 0; for (; i < rls.size(); ++i) { rule_i = m.mk_app(mk_q_rule(pred, i), mk_q_num(level).get()); @@ -489,7 +489,7 @@ namespace datalog { proof_ref get_proof(model_ref& md, func_decl* pred, app* prop, unsigned level) { if (m.canceled()) { - return proof_ref(0, m); + return proof_ref(nullptr, m); } TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";); rule_manager& rm = b.m_ctx.get_rule_manager(); @@ -500,7 +500,7 @@ namespace datalog { // find the rule that was triggered by evaluating the arguments to prop. rule_vector const& rls = b.m_rules.get_predicate_rules(pred); - rule* r = 0; + rule* r = nullptr; for (unsigned i = 0; i < rls.size(); ++i) { func_decl_ref rule_i = mk_level_rule(pred, i, level); TRACE("bmc", rls[i]->display(b.m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " ");); @@ -606,7 +606,7 @@ namespace datalog { binding.push_back(m.mk_app(f, args.size(), args.c_ptr())); } else { - binding.push_back(0); + binding.push_back(nullptr); } } return binding; @@ -642,7 +642,7 @@ namespace datalog { names.push_back(symbol(i)); } else { - binding.push_back(0); + binding.push_back(nullptr); } } sorts.reverse(); @@ -686,7 +686,7 @@ namespace datalog { } else { expr * const * no_pats = &new_body; - result = n.m.update_quantifier(old_q, 0, 0, 1, no_pats, new_body); + result = n.m.update_quantifier(old_q, 0, nullptr, 1, no_pats, new_body); } return true; } @@ -986,7 +986,7 @@ namespace datalog { sort_ref_vector new_sorts(m); family_id dfid = m.mk_family_id("datatype"); datatype_decl_plugin* dtp = static_cast(m.get_plugin(dfid)); - VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), 0, 0, new_sorts)); + VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), 0, nullptr, new_sorts)); it = b.m_rules.begin_grouped_rules(); for (unsigned i = 0; it != end; ++it, ++i) { @@ -1012,7 +1012,7 @@ namespace datalog { unsigned sz = r->get_uninterpreted_tail_size(); max_arity = std::max(sz, max_arity); } - cnstrs.push_back(mk_constructor_decl(symbol("Z#"), symbol("Z#?"), 0, 0)); + cnstrs.push_back(mk_constructor_decl(symbol("Z#"), symbol("Z#?"), 0, nullptr)); for (unsigned i = 0; i + 1 < max_arity; ++i) { std::stringstream _name; @@ -1028,7 +1028,7 @@ namespace datalog { cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr())); } dts.push_back(mk_datatype_decl(dtu, symbol("Path"), 0, nullptr, cnstrs.size(), cnstrs.c_ptr())); - VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), 0, 0, new_sorts)); + VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), 0, nullptr, new_sorts)); m_path_sort = new_sorts[0].get(); } } @@ -1090,7 +1090,7 @@ namespace datalog { } } UNREACHABLE(); - return proof_ref(0, m); + return proof_ref(nullptr, m); } // instantiation of algebraic data-types takes care of the rest. @@ -1201,7 +1201,7 @@ namespace datalog { TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";); expr_ref_vector sub(m); rule_vector const& rls = b.m_rules.get_predicate_rules(pred); - rule* r = 0; + rule* r = nullptr; unsigned i = 0; for (; i < rls.size(); ++i) { expr_ref rule_i = mk_level_rule(pred, i, level); @@ -1446,7 +1446,7 @@ namespace datalog { lbool bmc::query(expr* query) { m_solver.reset(); - m_answer = 0; + m_answer = nullptr; m_ctx.ensure_opened(); m_rules.reset(); datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); diff --git a/src/muz/clp/clp_context.cpp b/src/muz/clp/clp_context.cpp index d1ce80e12..8ed017214 100644 --- a/src/muz/clp/clp_context.cpp +++ b/src/muz/clp/clp_context.cpp @@ -197,7 +197,7 @@ namespace datalog { proof_ref get_proof() const { - return proof_ref(0, m); + return proof_ref(nullptr, m); } }; diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index da1f5392b..6a42860e2 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -462,7 +462,7 @@ namespace datalog { private: ddnf_mgr* insert(unsigned n) { - ddnf_mgr* m = 0; + ddnf_mgr* m = nullptr; if (!m_mgrs.find(n, m)) { m = alloc(ddnf_mgr, n); m_mgrs.insert(n, m); @@ -673,7 +673,7 @@ namespace datalog { void dump_rules(rule_set& rules) { init_ctx(rules); - m_inner_ctx.display_smt2(0, 0, std::cout); + m_inner_ctx.display_smt2(0, nullptr, std::cout); } lbool execute_rules(rule_set& rules) { @@ -715,7 +715,7 @@ namespace datalog { compile_expr(r.get_tail(i), tmp); body.push_back(to_app(tmp)); } - rule* r_new = rm.mk(head, body.size(), body.c_ptr(), 0, r.name(), false); + rule* r_new = rm.mk(head, body.size(), body.c_ptr(), nullptr, r.name(), false); new_rules.add_rule(r_new); IF_VERBOSE(20, r_new->display(m_ctx, verbose_stream());); if (old_rules.is_output_predicate(r.get_decl())) { @@ -775,11 +775,11 @@ namespace datalog { return bv.mk_sort(nb); } UNREACHABLE(); - return 0; + return nullptr; } void compile_expr(expr* e, expr_ref& result) { - expr* r = 0; + expr* r = nullptr; if (m_cache.find(e, r)) { result = r; return; @@ -847,7 +847,7 @@ namespace datalog { } void compile_eq(expr* e, expr_ref& result, var* v, unsigned hi, unsigned lo, expr* c) { - tbv* t = 0; + tbv* t = nullptr; // TBD: hi, lo are ignored. VERIFY(m_expr2tbv.find(e, t)); var_ref w(m); diff --git a/src/muz/duality/duality_dl_interface.cpp b/src/muz/duality/duality_dl_interface.cpp old mode 100755 new mode 100644 index 15f7f84d8..60ed1755c --- a/src/muz/duality/duality_dl_interface.cpp +++ b/src/muz/duality/duality_dl_interface.cpp @@ -71,10 +71,10 @@ namespace Duality { Solver::Counterexample cex; duality_data(ast_manager &_m) : ctx(_m,config(params_ref())) { - ls = 0; - rpfp = 0; + ls = nullptr; + rpfp = nullptr; status = StatusNull; - old_rs = 0; + old_rs = nullptr; } ~duality_data(){ if(old_rs) @@ -92,7 +92,7 @@ namespace Duality { m_ctx(dl_ctx) { - _d = 0; + _d = nullptr; // dl_ctx.get_manager().toggle_proof_mode(PGM_FINE); } @@ -138,7 +138,7 @@ namespace Duality { // if there is old data, get the cex and dispose (later) duality_data *old_data = _d; - Solver *old_rs = 0; + Solver *old_rs = nullptr; if(old_data){ old_rs = old_data->old_rs; old_rs->GetCounterexample().swap(old_data->cex); diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index fd3eae944..956be52fc 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -104,7 +104,7 @@ public: m_ok = (m_file != NULL) && (err == 0); #else m_file = fopen(fname, "rb"); - m_ok = (m_file != NULL); + m_ok = (m_file != nullptr); #endif } ~line_reader() { @@ -171,7 +171,7 @@ class char_reader { public: char_reader(char const* file): m_line_reader(file), - m_line(0) + m_line(nullptr) {} bool operator()() { return m_line_reader(); } @@ -184,7 +184,7 @@ public: m_line = m_line_reader.get_line(); } if (!(m_line[0])) { - m_line = 0; + m_line = nullptr; return '\n'; } char result = m_line[0]; @@ -266,8 +266,8 @@ public: } dlexer(): - m_input(0), - m_reader(0), + m_input(nullptr), + m_reader(nullptr), m_prev_char(0), m_curr_char(0), m_line(1), @@ -496,17 +496,17 @@ public: bool parse_file(char const * filename) override { reset(); - if (filename != 0) { + if (filename != nullptr) { set_path(filename); char_reader reader(filename); if (!reader()) { get_err() << "ERROR: could not open file '" << filename << "'.\n"; return false; } - return parse_stream(0, &reader); + return parse_stream(nullptr, &reader); } else { - return parse_stream(&std::cin, 0); + return parse_stream(&std::cin, nullptr); } } @@ -514,7 +514,7 @@ public: reset(); std::string s(string); std::istringstream is(s); - return parse_stream(&is, 0); + return parse_stream(&is, nullptr); } protected: @@ -701,7 +701,7 @@ protected: if(is_predicate_declaration) { return unexpected(tok, "predicate declaration should not end with '.'"); } - add_rule(pred, 0, 0, 0); + add_rule(pred, 0, nullptr, nullptr); return m_lexer->next_token(); case TK_LEFT_ARROW: return parse_body(pred); @@ -777,7 +777,7 @@ protected: dtoken parse_infix(dtoken tok1, char const* td, app_ref& pred) { symbol td1(td); expr_ref v1(m_manager), v2(m_manager); - sort* s = 0; + sort* s = nullptr; dtoken tok2 = m_lexer->next_token(); if (tok2 != TK_NEQ && tok2 != TK_GT && tok2 != TK_LT && tok2 != TK_EQ) { return unexpected(tok2, "built-in infix operator"); @@ -790,12 +790,12 @@ protected: symbol td2(td); if (tok1 == TK_ID) { - expr* _v1 = 0; + expr* _v1 = nullptr; m_vars.find(td1.bare_str(), _v1); v1 = _v1; } if (tok3 == TK_ID) { - expr* _v2 = 0; + expr* _v2 = nullptr; m_vars.find(td2.bare_str(), _v2); v2 = _v2; } @@ -842,8 +842,8 @@ protected: svector arg_names; func_decl* f = m_context.try_get_predicate_decl(s); tok = parse_args(tok, f, args, arg_names); - is_predicate_declaration = f==0; - if (f==0) { + is_predicate_declaration = f==nullptr; + if (f==nullptr) { //we're in a declaration unsigned arity = args.size(); ptr_vector domain; @@ -884,7 +884,7 @@ protected: tok = m_lexer->next_token(); while (tok != TK_EOS && tok != TK_ERROR) { symbol alias; - sort* s = 0; + sort* s = nullptr; if(!f) { //we're in a predicate declaration @@ -951,7 +951,7 @@ protected: symbol data (m_lexer->get_token_data()); if (is_var(data.bare_str())) { unsigned idx = 0; - expr* v = 0; + expr* v = nullptr; if (!m_vars.find(data.bare_str(), v)) { idx = m_num_vars++; v = m_manager.mk_var(idx, s); @@ -1014,7 +1014,7 @@ protected: dlexer lexer; { flet lexer_let(m_lexer, &lexer); - m_lexer->set_stream(0, &stream); + m_lexer->set_stream(nullptr, &stream); tok = m_lexer->next_token(); if(parsing_domain) { tok = parse_domains(tok); @@ -1186,7 +1186,7 @@ class wpa_parser_impl : public wpa_parser, dparser { bool m_use_map_names; uint64_set& ensure_sort_content(symbol sort_name) { - sym2nums::entry * e = m_sort_contents.insert_if_not_there2(sort_name, 0); + sym2nums::entry * e = m_sort_contents.insert_if_not_there2(sort_name, nullptr); if(!e->get_data().m_value) { e->get_data().m_value = alloc(uint64_set); } @@ -1312,10 +1312,10 @@ private: dlexer lexer; m_lexer = &lexer; - m_lexer->set_stream(&stm, 0); + m_lexer->set_stream(&stm, nullptr); dtoken tok = m_lexer->next_token(); tok = parse_decls(tok); - m_lexer = 0; + m_lexer = nullptr; } bool parse_rel_line(char * full_line, uint64_vector & args) { diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index deb8887ec..ba12c849c 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -56,7 +56,7 @@ struct dl_context { m_cmd(ctx), m_collected_cmds(collected_cmds), m_ref_count(0), - m_decl_plugin(0), + m_decl_plugin(nullptr), m_trail(*this) {} void inc_ref() { @@ -88,7 +88,7 @@ struct dl_context { } void reset() { - m_context = 0; + m_context = nullptr; } void register_predicate(func_decl* pred, unsigned num_kinds, symbol const* kinds) { @@ -164,7 +164,7 @@ public: cmd("rule"), m_dl_ctx(dl_ctx), m_arg_idx(0), - m_t(0), + m_t(nullptr), m_bound(UINT_MAX) {} char const * get_usage() const override { return "(forall (q) (=> (and body) head)) :optional-name :optional-recursion-bound"; } char const * get_descr(cmd_context & ctx) const override { return "add a Horn rule."; } @@ -206,7 +206,7 @@ public: dl_query_cmd(dl_context * dl_ctx): parametric_cmd("query"), m_dl_ctx(dl_ctx), - m_target(0) { + m_target(nullptr) { } char const * get_usage() const override { return "predicate"; } char const * get_main_descr() const override { @@ -214,7 +214,7 @@ public: } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - if (m_target == 0) return CPK_FUNC_DECL; + if (m_target == nullptr) return CPK_FUNC_DECL; return parametric_cmd::next_arg_kind(ctx); } @@ -232,11 +232,11 @@ public: void prepare(cmd_context & ctx) override { ctx.m(); // ensure manager is initialized. parametric_cmd::prepare(ctx); - m_target = 0; + m_target = nullptr; } void execute(cmd_context& ctx) override { - if (m_target == 0) { + if (m_target == nullptr) { throw cmd_exception("invalid query command, argument expected"); } if (m_dl_ctx->collect_query(m_target)) { @@ -318,7 +318,7 @@ public: } dlctx.cleanup(); print_statistics(ctx); - m_target = 0; + m_target = nullptr; } void init_pdescrs(cmd_context & ctx, param_descrs & p) override { @@ -472,7 +472,7 @@ public: void execute(cmd_context & ctx) override { ast_manager& m = ctx.m(); - func_decl_ref var(m.mk_func_decl(m_var_name, 0, static_cast(0), m_var_sort), m); + func_decl_ref var(m.mk_func_decl(m_var_name, 0, static_cast(nullptr), m_var_sort), m); ctx.insert(var); m_dl_ctx->dlctx().register_variable(var); } @@ -528,7 +528,7 @@ static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_c } void install_dl_cmds(cmd_context & ctx) { - install_dl_cmds_aux(ctx, 0); + install_dl_cmds_aux(ctx, nullptr); } void install_dl_collect_cmds(dl_collected_cmds& collected_cmds, cmd_context & ctx) { diff --git a/src/muz/fp/dl_register_engine.cpp b/src/muz/fp/dl_register_engine.cpp index b56a07a7c..267bfc390 100644 --- a/src/muz/fp/dl_register_engine.cpp +++ b/src/muz/fp/dl_register_engine.cpp @@ -27,7 +27,7 @@ Revision History: #include "muz/spacer/spacer_dl_interface.h" namespace datalog { - register_engine::register_engine(): m_ctx(0) {} + register_engine::register_engine(): m_ctx(nullptr) {} engine_base* register_engine::mk_engine(DL_ENGINE engine_type) { switch(engine_type) { @@ -51,10 +51,10 @@ namespace datalog { return alloc(ddnf, *m_ctx); case LAST_ENGINE: UNREACHABLE(); - return 0; + return nullptr; } UNREACHABLE(); - return 0; + return nullptr; } } diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 273489164..88fb4e03d 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -65,7 +65,7 @@ class horn_tactic : public tactic { void normalize(expr_ref& f) { bool is_positive = true; - expr* e = 0; + expr* e = nullptr; while (true) { if (is_forall(f) && is_positive) { f = to_quantifier(f)->get_expr(); @@ -141,7 +141,7 @@ class horn_tactic : public tactic { ast_mark mark; expr_ref_vector args(m), body(m); expr_ref head(m); - expr* a = 0, *a1 = 0; + expr* a = nullptr, *a1 = nullptr; flatten_or(tmp, args); for (unsigned i = 0; i < args.size(); ++i) { a = args[i].get(); @@ -182,7 +182,7 @@ class horn_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("horn", *g); bool produce_proofs = g->proofs_enabled(); @@ -270,7 +270,7 @@ class horn_tactic : public tactic { if (produce_proofs) { proof_ref proof = m_ctx.get_proof(); pc = proof2proof_converter(m, proof); - g->assert_expr(m.mk_false(), proof, 0); + g->assert_expr(m.mk_false(), proof, nullptr); } else { g->assert_expr(m.mk_false()); diff --git a/src/muz/pdr/pdr_closure.h b/src/muz/pdr/pdr_closure.h index 8af53376b..c41e83389 100644 --- a/src/muz/pdr/pdr_closure.h +++ b/src/muz/pdr/pdr_closure.h @@ -35,8 +35,8 @@ namespace pdr { expr* m_k; obj_map* m_translate; public: - scaler(ast_manager& m): m(m), a(m), m_translate(0) {} - expr_ref operator()(expr* e, expr* k, obj_map* translate = 0); + scaler(ast_manager& m): m(m), a(m), m_translate(nullptr) {} + expr_ref operator()(expr* e, expr* k, obj_map* translate = nullptr); expr_ref undo_k(expr* e, expr* k); private: expr_ref scale(expr* e, bool is_mul); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 1d3232deb..971ec9193 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -128,7 +128,7 @@ namespace pdr { std::stringstream name_stm; name_stm << m_head->get_name() << '_' << i; func_decl_ref stm(m); - stm = m.mk_func_decl(symbol(name_stm.str().c_str()), 0, (sort*const*)0, arg_sort); + stm = m.mk_func_decl(symbol(name_stm.str().c_str()), 0, (sort*const*)nullptr, arg_sort); m_sig.push_back(pm.get_o_pred(stm, 0)); } } @@ -443,7 +443,7 @@ namespace pdr { else if (is_sat == l_false) { uses_level = m_solver.assumes_level(); } - m_solver.set_model(0); + m_solver.set_model(nullptr); return is_sat; } @@ -459,7 +459,7 @@ namespace pdr { tmp = pm.mk_and(conj); prop_solver::scoped_level _sl(m_solver, level); m_solver.set_core(core); - m_solver.set_model(0); + m_solver.set_model(nullptr); lbool r = m_solver.check_conjunction_as_assumptions(tmp); if (r == l_false) { assumes_level = m_solver.assumes_level(); @@ -477,7 +477,7 @@ namespace pdr { prop_solver::scoped_level _sl(m_solver, level); m_solver.set_core(&core); m_solver.set_subset_based_core(true); - m_solver.set_model(0); + m_solver.set_model(nullptr); lbool res = m_solver.check_assumptions_and_formula(lits, fml); if (res == l_false) { lits.reset(); @@ -649,7 +649,7 @@ namespace pdr { expr_free_vars fv; fv(e); while (vars.size() < fv.size()) { - vars.push_back(0); + vars.push_back(nullptr); } for (unsigned i = 0; i < fv.size(); ++i) { if (fv[i] && !vars[i].get()) { @@ -821,7 +821,7 @@ namespace pdr { datalog::rule const& rl2 = pt().find_rule(*mdl); SASSERT(is_ini(rl2)); set_rule(&rl2); - pt().get_solver().set_model(0); + pt().get_solver().set_model(nullptr); return const_cast(m_rule); } @@ -899,7 +899,7 @@ namespace pdr { if (this == m_next) { SASSERT(m_prev == this); if (root == this) { - root = 0; + root = nullptr; } } else { @@ -910,8 +910,8 @@ namespace pdr { } } TRACE("pdr", tout << "new root: " << root << "\n";); - m_prev = 0; - m_next = 0; + m_prev = nullptr; + m_next = nullptr; } @@ -938,7 +938,7 @@ namespace pdr { */ model_node* model_search::next() { if (!m_goal) { - return 0; + return nullptr; } else { model_node* result = m_goal; @@ -1161,7 +1161,7 @@ namespace pdr { todo.push_back(m_root); while (!todo.empty()) { model_node* n = todo.back(); - model* md = 0; + model* md = nullptr; if (!n->get_model_ptr()) { if (models.find(n->state(), md)) { TRACE("pdr", tout << n->state() << "\n";); @@ -1300,7 +1300,7 @@ namespace pdr { ptr_vector todo; proof_ref_vector trail(m); datalog::rule_ref_vector rules_trail(rm); - proof* pr = 0; + proof* pr = nullptr; unif.set_normalize(true); todo.push_back(m_root); update_models(); @@ -1416,7 +1416,7 @@ namespace pdr { erase_children(*m_root, false); remove_node(*m_root, false); dealloc(m_root); - m_root = 0; + m_root = nullptr; } m_cache.reset(); } @@ -1448,10 +1448,10 @@ namespace pdr { : m_fparams(fparams), m_params(params), m(m), - m_context(0), + m_context(nullptr), m_pm(m_fparams, params.pdr_max_num_contexts(), m), m_query_pred(m), - m_query(0), + m_query(nullptr), m_search(m_params.pdr_bfs_model_search()), m_last_result(l_undef), m_inductive_lvl(0), @@ -1479,7 +1479,7 @@ namespace pdr { reset(m_rels_tmp); } m_search.reset(); - m_query = 0; + m_query = nullptr; m_last_result = l_undef; m_inductive_lvl = 0; } @@ -1546,7 +1546,7 @@ namespace pdr { init_rules(rules, m_rels_tmp); decl2rel::iterator it = m_rels_tmp.begin(), end = m_rels_tmp.end(); for (; it != end; ++it) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (m_rels.find(it->m_key, pt)) { it->m_value->inherit_properties(*pt); } @@ -1561,7 +1561,7 @@ namespace pdr { } unsigned context::get_num_levels(func_decl* p) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (m_rels.find(p, pt)) { return pt->get_num_levels(); } @@ -1572,7 +1572,7 @@ namespace pdr { } expr_ref context::get_cover_delta(int level, func_decl* p_orig, func_decl* p) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (m_rels.find(p, pt)) { return pt->get_cover_delta(p_orig, level); } @@ -1583,7 +1583,7 @@ namespace pdr { } void context::add_cover(int level, func_decl* p, expr* property) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (!m_rels.find(p, pt)) { pt = alloc(pred_transformer, *this, get_pdr_manager(), p); m_rels.insert(p, pt); @@ -2026,7 +2026,7 @@ namespace pdr { // bool context::check_reachability(unsigned level) { expr_ref state(m.mk_true(), m); - model_node* root = alloc(model_node, 0, state, *m_query, level); + model_node* root = alloc(model_node, nullptr, state, *m_query, level); m_search.set_root(root); while (model_node* node = m_search.next()) { @@ -2403,7 +2403,7 @@ namespace pdr { if (m_params.print_boogie_certificate()) { datalog::boogie_proof bp(m); bp.set_proof(get_proof()); - bp.set_model(0); + bp.set_model(nullptr); bp.pp(strm); } else { diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index f160cff6a..ebaa3f257 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -143,7 +143,7 @@ namespace pdr { void add_property(expr * lemma, unsigned lvl); // add property 'p' to state at level. lbool is_reachable(model_node& n, expr_ref_vector* core, bool& uses_level); - bool is_invariant(unsigned level, expr* co_state, bool inductive, bool& assumes_level, expr_ref_vector* core = 0); + bool is_invariant(unsigned level, expr* co_state, bool inductive, bool& assumes_level, expr_ref_vector* core = nullptr); bool check_inductive(unsigned level, expr_ref_vector& state, bool& assumes_level); expr_ref get_formulas(unsigned level, bool add_axioms); @@ -199,8 +199,8 @@ namespace pdr { datalog::rule const* m_rule; public: model_node(model_node* parent, expr_ref& state, pred_transformer& pt, unsigned level): - m_parent(parent), m_next(0), m_prev(0), m_pt(pt), m_state(state), m_model(0), - m_level(level), m_orig_level(level), m_depth(0), m_closed(false), m_rule(0) { + m_parent(parent), m_next(nullptr), m_prev(nullptr), m_pt(pt), m_state(state), m_model(nullptr), + m_level(level), m_orig_level(level), m_depth(0), m_closed(false), m_rule(nullptr) { model_node* p = m_parent; if (p) { p->m_children.push_back(this); @@ -253,7 +253,7 @@ namespace pdr { void dequeue(model_node*& root); void enqueue(model_node* n); model_node* next() const { return m_next; } - bool is_goal() const { return 0 != next(); } + bool is_goal() const { return nullptr != next(); } }; class model_search { @@ -271,7 +271,7 @@ namespace pdr { unsigned num_goals() const; public: - model_search(bool bfs): m_bfs(bfs), m_root(0), m_goal(0) {} + model_search(bool bfs): m_bfs(bfs), m_root(nullptr), m_goal(nullptr) {} ~model_search(); void reset(); diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp index 87bc68bd9..27ce0500c 100644 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -38,7 +38,7 @@ dl_interface::dl_interface(datalog::context& ctx) : m_ctx(ctx), m_pdr_rules(ctx), m_old_rules(ctx), - m_context(0), + m_context(nullptr), m_refs(ctx.get_manager()) { m_context = alloc(pdr::context, ctx.get_fparams(), ctx.get_params(), ctx.get_manager()); } diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 4a77d2f5f..cb2d3529e 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -373,7 +373,7 @@ namespace pdr { farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr) : m_proof_params(get_proof_params(params)), m_pr(PGM_ENABLED), - m_constr(0), + m_constr(nullptr), m_combine_farkas_coefficients(true), p2o(m_pr, outer_mgr), o2p(outer_mgr, m_pr) diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index 094379a0b..8e52cb6f4 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -189,7 +189,7 @@ namespace pdr { expr_ref fml1 = mk_and(core); expr_ref fml2 = n.pt().get_formulas(n.level(), false); fml1_2.push_back(fml1); - fml1_2.push_back(0); + fml1_2.push_back(nullptr); flatten_and(fml2, fmls); for (unsigned i = 0; i < fmls.size(); ++i) { fml2 = m.mk_not(fmls[i].get()); @@ -199,7 +199,7 @@ namespace pdr { tout << "Check states:\n" << mk_pp(state, m) << "\n"; tout << "Old states:\n" << mk_pp(fml2, m) << "\n"; ); - model_node nd(0, state, n.pt(), n.level()); + model_node nd(nullptr, state, n.pt(), n.level()); pred_transformer::scoped_farkas sf(n.pt(), true); bool uses_level1 = uses_level; if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) { @@ -236,7 +236,7 @@ namespace pdr { n.pt().get_solver().set_consequences(&consequences); pred_transformer::scoped_farkas sf (n.pt(), true); VERIFY(l_false == n.pt().is_reachable(n, &core1, uses_level1)); - n.pt().get_solver().set_consequences(0); + n.pt().get_solver().set_consequences(nullptr); } IF_VERBOSE(0, verbose_stream() << "Consequences: " << consequences.size() << "\n"; @@ -257,7 +257,7 @@ namespace pdr { cstate.push_back(m.mk_not(consequences[i].get())); } tmp = m.mk_and(cstate.size(), cstate.c_ptr()); - model_node nd(0, tmp, n.pt(), n.level()); + model_node nd(nullptr, tmp, n.pt(), n.level()); pred_transformer::scoped_farkas sf (n.pt(), false); VERIFY(l_false == n.pt().is_reachable(nd, &core1, uses_level1)); } @@ -752,7 +752,7 @@ namespace pdr { // void core_induction_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { model_node* p = n.parent(); - if (p == 0) { + if (p == nullptr) { return; } unsigned depth = 2; diff --git a/src/muz/pdr/pdr_manager.h b/src/muz/pdr/pdr_manager.h index 9fc98940d..ccbbbe356 100644 --- a/src/muz/pdr/pdr_manager.h +++ b/src/muz/pdr/pdr_manager.h @@ -289,7 +289,7 @@ namespace pdr { bg is background knowledge and can be null */ - bool implication_surely_holds(expr * lhs, expr * rhs, expr * bg=0); + bool implication_surely_holds(expr * lhs, expr * rhs, expr * bg=nullptr); unsigned get_unique_num() { return m_next_unique_num++; } diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index 3055985f4..801d06e50 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -234,9 +234,9 @@ namespace pdr { m_pos_level_atoms(m), m_neg_level_atoms(m), m_proxies(m), - m_core(0), - m_model(0), - m_consequences(0), + m_core(nullptr), + m_model(nullptr), + m_consequences(nullptr), m_subset_based_core(false), m_use_farkas(false), m_in_level(false), @@ -249,7 +249,7 @@ namespace pdr { unsigned idx = level_cnt(); std::stringstream name; name << m_name << "#level_" << idx; - func_decl * lev_pred = m.mk_fresh_func_decl(name.str().c_str(), 0, 0,m.mk_bool_sort()); + func_decl * lev_pred = m.mk_fresh_func_decl(name.str().c_str(), 0, nullptr,m.mk_bool_sort()); m_aux_symbols.insert(lev_pred); m_level_preds.push_back(lev_pred); @@ -301,7 +301,7 @@ namespace pdr { safe_assumptions& safe, const expr_ref_vector& atoms) { - flet _model(m_fparams.m_model, m_model != 0); + flet _model(m_fparams.m_model, m_model != nullptr); expr_ref_vector expr_atoms(m); expr_atoms.append(atoms.size(), atoms.c_ptr()); @@ -342,8 +342,8 @@ namespace pdr { extract_subset_core(safe); SASSERT(expr_atoms.size() >= m_core->size()); } - m_core = 0; - m_model = 0; + m_core = nullptr; + m_model = nullptr; m_subset_based_core = false; return result; } diff --git a/src/muz/pdr/pdr_reachable_cache.cpp b/src/muz/pdr/pdr_reachable_cache.cpp index d28c1415b..5d553df4d 100644 --- a/src/muz/pdr/pdr_reachable_cache.cpp +++ b/src/muz/pdr/pdr_reachable_cache.cpp @@ -24,7 +24,7 @@ namespace pdr { reachable_cache::reachable_cache(pdr::manager & pm, datalog::PDR_CACHE_MODE cm) : m(pm.get_manager()), m_pm(pm), - m_ctx(0), + m_ctx(nullptr), m_ref_holder(m), m_disj_connector(m), m_cache_mode(cm) { diff --git a/src/muz/pdr/pdr_smt_context_manager.cpp b/src/muz/pdr/pdr_smt_context_manager.cpp index b87d1e451..88734049b 100644 --- a/src/muz/pdr/pdr_smt_context_manager.cpp +++ b/src/muz/pdr/pdr_smt_context_manager.cpp @@ -130,7 +130,7 @@ namespace pdr { smt_context* smt_context_manager::mk_fresh() { ++m_num_contexts; app_ref pred(m); - smt::kernel * ctx = 0; + smt::kernel * ctx = nullptr; if (m_max_num_contexts == 0) { m_contexts.push_back(alloc(smt::kernel, m, m_fparams)); pred = m.mk_true(); diff --git a/src/muz/pdr/pdr_sym_mux.h b/src/muz/pdr/pdr_sym_mux.h index 981dc9615..64a2878a9 100644 --- a/src/muz/pdr/pdr_sym_mux.h +++ b/src/muz/pdr/pdr_sym_mux.h @@ -122,7 +122,7 @@ public: func_decl * try_get_primary_by_prefix(func_decl* prefix) const { func_decl * res; if(!m_prefix2prim.find(prefix, res)) { - return 0; + return nullptr; } return res; } @@ -133,7 +133,7 @@ public: func_decl * try_get_by_prefix(func_decl* prefix, unsigned idx) { func_decl * prim = try_get_primary_by_prefix(prefix); if(!prim) { - return 0; + return nullptr; } return conv(prim, 0, idx); } diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp index 19ffdeeec..ad75ae799 100644 --- a/src/muz/pdr/pdr_util.cpp +++ b/src/muz/pdr/pdr_util.cpp @@ -244,7 +244,7 @@ namespace pdr { } bool test_eq(expr* e) const { - expr* lhs = 0, *rhs = 0; + expr* lhs = nullptr, *rhs = nullptr; VERIFY(m.is_eq(e, lhs, rhs)); if (!a.is_int_real(lhs)) { return true; diff --git a/src/muz/rel/aig_exporter.cpp b/src/muz/rel/aig_exporter.cpp index 3fed47f80..c38964be0 100644 --- a/src/muz/rel/aig_exporter.cpp +++ b/src/muz/rel/aig_exporter.cpp @@ -118,7 +118,7 @@ namespace datalog { } exprs.reset(); - assert_pred_id(numqs ? r->get_tail(0)->get_decl() : 0, m_ruleid_var_set, exprs); + assert_pred_id(numqs ? r->get_tail(0)->get_decl() : nullptr, m_ruleid_var_set, exprs); assert_pred_id(r->get_head()->get_decl(), m_ruleid_varp_set, exprs); subst.reset(); @@ -141,7 +141,7 @@ namespace datalog { if (m_facts) { for (fact_vector::const_iterator I = m_facts->begin(), E = m_facts->end(); I != E; ++I) { exprs.reset(); - assert_pred_id(0, m_ruleid_var_set, exprs); + assert_pred_id(nullptr, m_ruleid_var_set, exprs); assert_pred_id(I->first, m_ruleid_varp_set, exprs); for (unsigned i = 0; i < I->second.size(); ++i) { diff --git a/src/muz/rel/aig_exporter.h b/src/muz/rel/aig_exporter.h index ea241fe2b..aac139adb 100644 --- a/src/muz/rel/aig_exporter.h +++ b/src/muz/rel/aig_exporter.h @@ -23,7 +23,7 @@ Abstract: namespace datalog { class aig_exporter { public: - aig_exporter(const rule_set& rules, context& ctx, const fact_vector *facts = 0); + aig_exporter(const rule_set& rules, context& ctx, const fact_vector *facts = nullptr); void operator()(std::ostream& out); private: @@ -60,7 +60,7 @@ namespace datalog { unsigned mk_or(unsigned id1, unsigned id2); unsigned get_var(const expr *e); unsigned mk_var(const expr *e); - unsigned mk_input_var(const expr *e = 0); + unsigned mk_input_var(const expr *e = nullptr); unsigned mk_expr_id(); }; } diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index a6298cf22..bd8fb4778 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -150,7 +150,7 @@ namespace datalog { check_relation_plugin::check_relation_plugin(relation_manager& rm): relation_plugin(check_relation_plugin::get_name(), rm), m(rm.get_context().get_manager()), - m_base(0) { + m_base(nullptr) { } check_relation_plugin::~check_relation_plugin() { } @@ -158,7 +158,7 @@ namespace datalog { return dynamic_cast(r); } check_relation* check_relation_plugin::get(relation_base* r) { - return r?dynamic_cast(r):0; + return r?dynamic_cast(r):nullptr; } check_relation const & check_relation_plugin::get(relation_base const& r) { return dynamic_cast(r); @@ -207,7 +207,7 @@ namespace datalog { const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { relation_join_fn* j = m_base->mk_join_fn(get(t1).rb(), get(t2).rb(), col_cnt, cols1, cols2); - return j?alloc(join_fn, j, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2):0; + return j?alloc(join_fn, j, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2):nullptr; } class check_relation_plugin::join_project_fn : public convenient_relation_join_project_fn { @@ -239,7 +239,7 @@ namespace datalog { relation_join_fn* j = m_base->mk_join_project_fn(get(t1).rb(), get(t2).rb(), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); return j?alloc(join_project_fn, j, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, - removed_col_cnt, removed_cols):0; + removed_col_cnt, removed_cols):nullptr; } void check_relation_plugin::verify_filter_project( @@ -499,8 +499,8 @@ namespace datalog { expr_ref fml0 = r.m_fml; expr_ref delta0(r.m_fml.get_manager()); if (d) d->to_formula(delta0); - (*m_union)(r.rb(), src.rb(), d?(&d->rb()):0); - r.get_plugin().verify_union(fml0, src.rb(), r.rb(), delta0, d?(&d->rb()):0); + (*m_union)(r.rb(), src.rb(), d?(&d->rb()):nullptr); + r.get_plugin().verify_union(fml0, src.rb(), r.rb(), delta0, d?(&d->rb()):nullptr); r.rb().to_formula(r.m_fml); if (d) d->rb().to_formula(d->m_fml); } @@ -508,16 +508,16 @@ namespace datalog { relation_union_fn * check_relation_plugin::mk_union_fn( const relation_base & tgt, const relation_base & src, const relation_base * delta) { - relation_base const* d1 = delta?(&(get(*delta).rb())):0; + relation_base const* d1 = delta?(&(get(*delta).rb())):nullptr; relation_union_fn* u = m_base->mk_union_fn(get(tgt).rb(), get(src).rb(), d1); - return u?alloc(union_fn, u):0; + return u?alloc(union_fn, u):nullptr; } relation_union_fn * check_relation_plugin::mk_widen_fn( const relation_base & tgt, const relation_base & src, const relation_base * delta) { - relation_base const* d1 = delta?(&(get(*delta).rb())):0; + relation_base const* d1 = delta?(&(get(*delta).rb())):nullptr; relation_union_fn* u = m_base->mk_widen_fn(get(tgt).rb(), get(src).rb(), d1); - return u?alloc(union_fn, u):0; + return u?alloc(union_fn, u):nullptr; } class check_relation_plugin::filter_identical_fn : public relation_mutator_fn { @@ -553,7 +553,7 @@ namespace datalog { relation_mutator_fn * check_relation_plugin::mk_filter_identical_fn( const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { relation_mutator_fn* r = m_base->mk_filter_identical_fn(get(t).rb(), col_cnt, identical_cols); - return r?alloc(filter_identical_fn, r, col_cnt, identical_cols):0; + return r?alloc(filter_identical_fn, r, col_cnt, identical_cols):nullptr; } class check_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { @@ -579,7 +579,7 @@ namespace datalog { relation_mutator_fn * check_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { relation_mutator_fn* r = m_base->mk_filter_interpreted_fn(get(t).rb(), condition); app_ref cond(condition, m); - return r?alloc(filter_interpreted_fn, r, cond):0; + return r?alloc(filter_interpreted_fn, r, cond):nullptr; } class check_relation_plugin::project_fn : public convenient_relation_project_fn { @@ -608,7 +608,7 @@ namespace datalog { const relation_base & t, unsigned col_cnt, const unsigned * removed_cols) { relation_transformer_fn* p = m_base->mk_project_fn(get(t).rb(), col_cnt, removed_cols); - return p?alloc(project_fn, p, t, col_cnt, removed_cols):0; + return p?alloc(project_fn, p, t, col_cnt, removed_cols):nullptr; } class check_relation_plugin::rename_fn : public convenient_relation_rename_fn { @@ -635,7 +635,7 @@ namespace datalog { const relation_base & r, unsigned cycle_len, const unsigned * permutation_cycle) { relation_transformer_fn* p = m_base->mk_rename_fn(get(r).rb(), cycle_len, permutation_cycle); - return p?alloc(rename_fn, p, r, cycle_len, permutation_cycle):0; + return p?alloc(rename_fn, p, r, cycle_len, permutation_cycle):nullptr; } class check_relation_plugin::filter_equal_fn : public relation_mutator_fn { @@ -663,7 +663,7 @@ namespace datalog { relation_mutator_fn * check_relation_plugin::mk_filter_equal_fn( const relation_base & t, const relation_element & value, unsigned col) { relation_mutator_fn* r = m_base->mk_filter_equal_fn(get(t).rb(), value, col); - return r?alloc(filter_equal_fn, r, t, value, col):0; + return r?alloc(filter_equal_fn, r, t, value, col):nullptr; } @@ -700,7 +700,7 @@ namespace datalog { const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *negated_cols) { relation_intersection_filter_fn* f = m_base->mk_filter_by_negation_fn(get(t).rb(), get(neg).rb(), joined_col_cnt, t_cols, negated_cols); - return f?alloc(negation_filter_fn, f, joined_col_cnt, t_cols, negated_cols):0; + return f?alloc(negation_filter_fn, f, joined_col_cnt, t_cols, negated_cols):nullptr; } /* @@ -779,7 +779,7 @@ namespace datalog { unsigned removed_col_cnt, const unsigned * removed_cols) { relation_transformer_fn* r = m_base->mk_filter_interpreted_and_project_fn(get(t).rb(), condition, removed_col_cnt, removed_cols); app_ref cond(condition, m); - return r?alloc(filter_proj_fn, r, t, cond, removed_col_cnt, removed_cols):0; + return r?alloc(filter_proj_fn, r, t, cond, removed_col_cnt, removed_cols):nullptr; } diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index 5ca84c895..20418e3bb 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -51,7 +51,7 @@ namespace datalog { ast_manager & m = renaming_arg.get_manager(); unsigned sz = map.size(); unsigned ofs = sz-1; - renaming_arg.resize(sz, static_cast(0)); + renaming_arg.resize(sz, static_cast(nullptr)); for(unsigned i=0; i() { return m_t; } const T* operator->() const { return m_t; } T& operator*() { return *m_t; } const T& operator*() const { return *m_t; } - operator bool() const { return m_t!=0; } + operator bool() const { return m_t!=nullptr; } T* get() const { return m_t; } /** \brief Remove object from \c scoped_rel without deleting it. */ T* release() { T* res = m_t; - m_t = 0; + m_t = nullptr; return res; } }; @@ -202,7 +202,7 @@ namespace datalog { virtual void operator()(base_object & tgt, const base_object & src, base_object * delta) = 0; void operator()(base_object & tgt, const base_object & src) { - (*this)(tgt, src, static_cast(0)); + (*this)(tgt, src, static_cast(nullptr)); } }; @@ -335,55 +335,55 @@ namespace datalog { virtual join_fn * mk_join_fn(const base_object & t1, const base_object & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { return 0; } + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { return nullptr; } virtual transformer_fn * mk_project_fn(const base_object & t, unsigned col_cnt, - const unsigned * removed_cols) { return 0; } + const unsigned * removed_cols) { return nullptr; } virtual join_fn * mk_join_project_fn(const base_object & t1, const base_object & t2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { return 0; } + unsigned removed_col_cnt, const unsigned * removed_cols) { return nullptr; } virtual transformer_fn * mk_rename_fn(const base_object & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) { return 0; } + const unsigned * permutation_cycle) { return nullptr; } virtual transformer_fn * mk_permutation_rename_fn(const base_object & t, - const unsigned * permutation) { return 0; } + const unsigned * permutation) { return nullptr; } public: virtual union_fn * mk_union_fn(const base_object & tgt, const base_object & src, - const base_object * delta) { return 0; } + const base_object * delta) { return nullptr; } protected: virtual union_fn * mk_widen_fn(const base_object & tgt, const base_object & src, - const base_object * delta) { return 0; } + const base_object * delta) { return nullptr; } virtual mutator_fn * mk_filter_identical_fn(const base_object & t, unsigned col_cnt, - const unsigned * identical_cols) { return 0; } + const unsigned * identical_cols) { return nullptr; } virtual mutator_fn * mk_filter_equal_fn(const base_object & t, const element & value, - unsigned col) { return 0; } + unsigned col) { return nullptr; } virtual mutator_fn * mk_filter_interpreted_fn(const base_object & t, app * condition) - { return 0; } + { return nullptr; } virtual transformer_fn * mk_filter_interpreted_and_project_fn(const base_object & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) - { return 0; } + { return nullptr; } virtual transformer_fn * mk_select_equal_and_project_fn(const base_object & t, - const element & value, unsigned col) { return 0; } + const element & value, unsigned col) { return nullptr; } virtual intersection_filter_fn * mk_filter_by_intersection_fn(const base_object & t, const base_object & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) - { return 0; } + { return nullptr; } virtual intersection_filter_fn * mk_filter_by_negation_fn(const base_object & t, const base_object & negated_obj, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) - { return 0; } + { return nullptr; } virtual intersection_join_filter_fn * mk_filter_by_negated_join_fn( const base_object & t, @@ -393,7 +393,7 @@ namespace datalog { unsigned_vector const& src_cols, unsigned_vector const& src1_cols, unsigned_vector const& src2_cols) - { return 0; } + { return nullptr; } }; @@ -1029,14 +1029,14 @@ namespace datalog { If the returned value is non-zero, the returned object must take ownership of \c mapper. Otherwise \c mapper must remain unmodified. */ - virtual table_mutator_fn * mk_map_fn(const table_base & t, table_row_mutator_fn * mapper) { return 0; } + virtual table_mutator_fn * mk_map_fn(const table_base & t, table_row_mutator_fn * mapper) { return nullptr; } /** If the returned value is non-zero, the returned object must take ownership of \c reducer. Otherwise \c reducer must remain unmodified. */ virtual table_transformer_fn * mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) { return 0; } + const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) { return nullptr; } }; @@ -1047,7 +1047,7 @@ namespace datalog { ~table_base() override {} public: table_base * clone() const override; - virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; + virtual table_base * complement(func_decl* p, const table_element * func_columns = nullptr) const; bool empty() const override; /** diff --git a/src/muz/rel/dl_bound_relation.cpp b/src/muz/rel/dl_bound_relation.cpp index 74b87d96e..60358db48 100644 --- a/src/muz/rel/dl_bound_relation.cpp +++ b/src/muz/rel/dl_bound_relation.cpp @@ -83,7 +83,7 @@ namespace datalog { bound_relation const& r1 = get(_r1); bound_relation const& r2 = get(_r2); bound_relation_plugin& p = r1.get_plugin(); - bound_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + bound_relation* result = dynamic_cast(p.mk_full(nullptr, get_result_signature())); result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); return result; } @@ -92,7 +92,7 @@ namespace datalog { relation_join_fn * bound_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if (!check_kind(r1) || !check_kind(r2)) { - return 0; + return nullptr; } return alloc(join_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2); } @@ -107,7 +107,7 @@ namespace datalog { relation_base * operator()(const relation_base & _r) override { bound_relation const& r = get(_r); bound_relation_plugin& p = r.get_plugin(); - bound_relation* result = get(p.mk_full(0, get_result_signature())); + bound_relation* result = get(p.mk_full(nullptr, get_result_signature())); result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); return result; } @@ -127,7 +127,7 @@ namespace datalog { relation_base * operator()(const relation_base & _r) override { bound_relation const& r = get(_r); bound_relation_plugin& p = r.get_plugin(); - bound_relation* result = get(p.mk_full(0, get_result_signature())); + bound_relation* result = get(p.mk_full(nullptr, get_result_signature())); result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); return result; } @@ -138,7 +138,7 @@ namespace datalog { if(check_kind(r)) { return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); } - return 0; + return nullptr; } @@ -176,7 +176,7 @@ namespace datalog { if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { return alloc(union_fn, false); } - return 0; + return nullptr; } relation_union_fn * bound_relation_plugin::mk_widen_fn( @@ -188,7 +188,7 @@ namespace datalog { if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { return alloc(union_fn, true); } - return 0; + return nullptr; } class bound_relation_plugin::filter_identical_fn : public relation_mutator_fn { @@ -209,7 +209,7 @@ namespace datalog { if(check_kind(t)) { return alloc(filter_identical_fn, col_cnt, identical_cols); } - return 0; + return nullptr; } class bound_relation_plugin::filter_equal_fn : public relation_mutator_fn { @@ -224,7 +224,7 @@ namespace datalog { if (check_kind(r)) { return alloc(filter_equal_fn, value, col); } - return 0; + return nullptr; } class bound_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { @@ -280,7 +280,7 @@ namespace datalog { filter_interpreted_fn(ast_manager& m, app* cond) : m_cond(cond, m), - m_lt(m), m_arith(m), m_interval(0), m_kind(NOT_APPLICABLE) { + m_lt(m), m_arith(m), m_interval(nullptr), m_kind(NOT_APPLICABLE) { expr* l, *r, *r1, *r2, *c2; rational n1; if ((m_arith.is_lt(cond, l, r) || m_arith.is_gt(cond, r, l)) && @@ -592,7 +592,7 @@ namespace datalog { scoped_ptr fe = get_plugin().mk_filter_equal_fn(r, f[i], i); (*fe)(r); } - mk_union(r, 0, false); + mk_union(r, nullptr, false); } bool bound_relation::contains_fact(const relation_fact & f) const { @@ -604,12 +604,12 @@ namespace datalog { } bound_relation * bound_relation::clone() const { - bound_relation* result = 0; + bound_relation* result = nullptr; if (empty()) { result = bound_relation_plugin::get(get_plugin().mk_empty(get_signature())); } else { - result = bound_relation_plugin::get(get_plugin().mk_full(0, get_signature())); + result = bound_relation_plugin::get(get_plugin().mk_full(nullptr, get_signature())); result->copy(*this); } return result; @@ -647,7 +647,7 @@ namespace datalog { bound_relation * bound_relation::complement(func_decl* p) const { UNREACHABLE(); - return 0; + return nullptr; } void bound_relation::to_formula(expr_ref& fml) const { diff --git a/src/muz/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h index da1aad71a..6c613a472 100644 --- a/src/muz/rel/dl_bound_relation.h +++ b/src/muz/rel/dl_bound_relation.h @@ -69,7 +69,7 @@ namespace datalog { relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) override { return 0; } + unsigned removed_col_cnt, const unsigned * removed_cols) override { return nullptr; } #if 0 diff --git a/src/muz/rel/dl_check_table.cpp b/src/muz/rel/dl_check_table.cpp index b7d22159e..0a6d90027 100644 --- a/src/muz/rel/dl_check_table.cpp +++ b/src/muz/rel/dl_check_table.cpp @@ -40,12 +40,12 @@ namespace datalog { table_base& check_table_plugin::checker(table_base& r) { return *get(r).m_checker; } table_base const& check_table_plugin::checker(table_base const& r) { return *get(r).m_checker; } - table_base* check_table_plugin::checker(table_base* r) { return r?(get(*r).m_checker):0; } - table_base const* check_table_plugin::checker(table_base const* r) { return r?(get(*r).m_checker):0; } + table_base* check_table_plugin::checker(table_base* r) { return r?(get(*r).m_checker):nullptr; } + table_base const* check_table_plugin::checker(table_base const* r) { return r?(get(*r).m_checker):nullptr; } table_base& check_table_plugin::tocheck(table_base& r) { return *get(r).m_tocheck; } table_base const& check_table_plugin::tocheck(table_base const& r) { return *get(r).m_tocheck; } - table_base* check_table_plugin::tocheck(table_base* r) { return r?(get(*r).m_tocheck):0; } - table_base const* check_table_plugin::tocheck(table_base const* r) { return r?(get(*r).m_tocheck):0; } + table_base* check_table_plugin::tocheck(table_base* r) { return r?(get(*r).m_tocheck):nullptr; } + table_base const* check_table_plugin::tocheck(table_base const* r) { return r?(get(*r).m_tocheck):nullptr; } table_base * check_table_plugin::mk_empty(const table_signature & s) { IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); @@ -77,7 +77,7 @@ namespace datalog { table_join_fn * check_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if (!check_kind(t1) || !check_kind(t2)) { - return 0; + return nullptr; } return alloc(join_fn, *this, t1, t2, col_cnt, cols1, cols2); } @@ -105,7 +105,7 @@ namespace datalog { unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { if (!check_kind(t1) || !check_kind(t2)) { - return 0; + return nullptr; } return alloc(join_project_fn, *this, t1, t2, col_cnt, cols1, cols2, removed_col_cnt, removed_cols); } @@ -132,7 +132,7 @@ namespace datalog { table_union_fn * check_table_plugin::mk_union_fn(const table_base & tgt, const table_base & src, const table_base * delta) { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; + return nullptr; } return alloc(union_fn, *this, tgt, src, delta); @@ -157,7 +157,7 @@ namespace datalog { table_transformer_fn * check_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols) { if (!check_kind(t)) { - return 0; + return nullptr; } return alloc(project_fn, *this, t, col_cnt, removed_cols); } @@ -182,7 +182,7 @@ namespace datalog { table_transformer_fn * check_table_plugin::mk_select_equal_and_project_fn(const table_base & t, const table_element & value, unsigned col) { if (!check_kind(t)) { - return 0; + return nullptr; } return alloc(select_equal_and_project_fn, *this, t, value, col); } @@ -207,7 +207,7 @@ namespace datalog { table_transformer_fn * check_table_plugin::mk_rename_fn(const table_base & t, unsigned len, const unsigned * cycle) { if (!check_kind(t)) { - return 0; + return nullptr; } return alloc(rename_fn, *this, t, len, cycle); } @@ -234,7 +234,7 @@ namespace datalog { if (check_kind(t)) { return alloc(filter_identical_fn, *this, t, col_cnt, identical_cols); } - return 0; + return nullptr; } class check_table_plugin::filter_equal_fn : public table_mutator_fn { @@ -258,7 +258,7 @@ namespace datalog { if (check_kind(t)) { return alloc(filter_equal_fn, *this, t, value, col); } - return 0; + return nullptr; } class check_table_plugin::filter_interpreted_fn : public table_mutator_fn { @@ -282,7 +282,7 @@ namespace datalog { if (check_kind(t)) { return alloc(filter_interpreted_fn, *this, t, condition); } - return 0; + return nullptr; } class check_table_plugin::filter_interpreted_and_project_fn : public table_transformer_fn { @@ -309,7 +309,7 @@ namespace datalog { if (check_kind(t)) { return alloc(filter_interpreted_and_project_fn, *this, t, condition, removed_col_cnt, removed_cols); } - return 0; + return nullptr; } class check_table_plugin::filter_by_negation_fn : public table_intersection_filter_fn { @@ -340,7 +340,7 @@ namespace datalog { if (check_kind(t) && check_kind(negated_obj)) { return alloc(filter_by_negation_fn, *this, t, negated_obj, joined_col_cnt, t_cols, negated_cols); } - return 0; + return nullptr; } // ------------------ diff --git a/src/muz/rel/dl_check_table.h b/src/muz/rel/dl_check_table.h index 77d9d0cdf..7bd4cf12d 100644 --- a/src/muz/rel/dl_check_table.h +++ b/src/muz/rel/dl_check_table.h @@ -120,7 +120,7 @@ namespace datalog { void add_fact(const table_fact & f) override; void remove_fact(const table_element* fact) override; bool contains_fact(const table_fact & f) const override; - table_base * complement(func_decl* p, const table_element * func_columns = 0) const override; + table_base * complement(func_decl* p, const table_element * func_columns = nullptr) const override; table_base * clone() const override; iterator begin() const override { SASSERT(well_formed()); return m_tocheck->begin(); } diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 32bcfed50..2de0679a5 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -1120,7 +1120,7 @@ namespace datalog { //and clear local deltas make_inloop_delta_transition(global_head_deltas, global_tail_deltas, local_deltas, *loop_body); - loop_body->set_observer(0); + loop_body->set_observer(nullptr); acc.push_back(instruction::mk_while_loop(loop_control_regs.size(), loop_control_regs.c_ptr(), loop_body)); } @@ -1316,7 +1316,7 @@ namespace datalog { pred2idx empty_pred2idx_map; - compile_strats(m_rule_set.get_stratifier(), static_cast(0), + compile_strats(m_rule_set.get_stratifier(), static_cast(nullptr), empty_pred2idx_map, true, execution_code); @@ -1331,7 +1331,7 @@ namespace datalog { termination_code.push_back(instruction::mk_store(m_context.get_manager(), pred, reg)); } - acc.set_observer(0); + acc.set_observer(nullptr); TRACE("dl", execution_code.display(execution_context(m_context), tout);); } diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 51ec7643c..d7bdcad34 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -93,10 +93,10 @@ namespace datalog { compiler & m_parent; rule * m_current; public: - instruction_observer(compiler & parent) : m_parent(parent), m_current(0) {} + instruction_observer(compiler & parent) : m_parent(parent), m_current(nullptr) {} void start_rule(rule * r) { SASSERT(!m_current); m_current=r; } - void finish_rule() { m_current = 0; } + void finish_rule() { m_current = nullptr; } void notify(instruction * i) override { if(m_current) { i->set_accounting_parent_object(m_parent.m_context, m_current); diff --git a/src/muz/rel/dl_external_relation.cpp b/src/muz/rel/dl_external_relation.cpp index 403c5cbd3..88511530e 100644 --- a/src/muz/rel/dl_external_relation.cpp +++ b/src/muz/rel/dl_external_relation.cpp @@ -46,7 +46,7 @@ namespace datalog { args.push_back(f[i]); } if (!fn.get()) { - fn = m.mk_func_decl(fid, k, 0, 0, args.size(), args.c_ptr()); + fn = m.mk_func_decl(fid, k, 0, nullptr, args.size(), args.c_ptr()); } if (destructive) { get_plugin().reduce_assign(fn, args.size(), args.c_ptr(), 1, args.c_ptr()); @@ -63,7 +63,7 @@ namespace datalog { expr_ref res(m); if (!m_is_empty_fn.get()) { family_id fid = get_plugin().get_family_id(); - const_cast(m_is_empty_fn) = m.mk_func_decl(fid, OP_RA_IS_EMPTY, 0, 0, 1, &r); + const_cast(m_is_empty_fn) = m.mk_func_decl(fid, OP_RA_IS_EMPTY, 0, nullptr, 1, &r); } get_plugin().reduce(m_is_empty_fn, 1, &r, res); return m.is_true(res); @@ -86,7 +86,7 @@ namespace datalog { expr* rel = m_rel.get(); expr_ref res(m.mk_fresh_const("T", m.get_sort(rel)), m); expr* rel_out = res.get(); - func_decl_ref fn(m.mk_func_decl(fid, OP_RA_CLONE,0,0, 1, &rel), m); + func_decl_ref fn(m.mk_func_decl(fid, OP_RA_CLONE,0,nullptr, 1, &rel), m); get_plugin().reduce_assign(fn, 1, &rel, 1, &rel_out); return alloc(external_relation, get_plugin(), get_signature(), res); } @@ -96,7 +96,7 @@ namespace datalog { family_id fid = get_plugin().get_family_id(); expr_ref res(m); expr* rel = m_rel; - func_decl_ref fn(m.mk_func_decl(fid, OP_RA_COMPLEMENT,0,0, 1, &rel), m); + func_decl_ref fn(m.mk_func_decl(fid, OP_RA_COMPLEMENT,0,nullptr, 1, &rel), m); get_plugin().reduce(fn, 1, &rel, res); return alloc(external_relation, get_plugin(), get_signature(), res); } @@ -140,8 +140,8 @@ namespace datalog { family_id fid = get_family_id(); expr_ref e(m.mk_fresh_const("T", r_sort), m); expr* args[1] = { e.get() }; - func_decl_ref empty_decl(m.mk_func_decl(fid, OP_RA_EMPTY, 1, ¶m, 0, (sort*const*)0), m); - reduce_assign(empty_decl, 0, 0, 1, args); + func_decl_ref empty_decl(m.mk_func_decl(fid, OP_RA_EMPTY, 1, ¶m, 0, (sort*const*)nullptr), m); + reduce_assign(empty_decl, 0, nullptr, 1, args); return alloc(external_relation, *this, s, e); } @@ -207,7 +207,7 @@ namespace datalog { relation_join_fn * external_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if (!check_kind(r1) || !check_kind(r2)) { - return 0; + return nullptr; } return alloc(join_fn, *this, r1.get_signature(), r2.get_signature() , col_cnt, cols1, cols2); } @@ -277,7 +277,7 @@ namespace datalog { relation_transformer_fn * external_relation_plugin::mk_rename_fn(const relation_base & r, unsigned cycle_len, const unsigned * permutation_cycle) { if(!check_kind(r)) { - return 0; + return nullptr; } return alloc(rename_fn, *this, get(r).get_sort(), r.get_signature(), cycle_len, permutation_cycle); } @@ -295,7 +295,7 @@ namespace datalog { m_union_fn(p.get_ast_manager()) { ast_manager& m = p.get_ast_manager(); sort* domain[2] = { relation_sort, relation_sort }; - m_union_fn = m.mk_func_decl(p.get_family_id(), k, 0, 0, 2, domain); + m_union_fn = m.mk_func_decl(p.get_family_id(), k, 0, nullptr, 2, domain); } void operator()(relation_base & r, const relation_base & src, relation_base * delta) override { @@ -316,7 +316,7 @@ namespace datalog { relation_union_fn * external_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; + return nullptr; } return alloc(union_fn, *this, OP_RA_UNION, get(src).get_sort()); } @@ -324,7 +324,7 @@ namespace datalog { relation_union_fn * external_relation_plugin::mk_widen_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; + return nullptr; } return alloc(union_fn, *this, OP_RA_WIDEN, get(src).get_sort()); } @@ -351,7 +351,7 @@ namespace datalog { relation_mutator_fn * external_relation_plugin::mk_filter_interpreted_fn(const relation_base & r, app * condition) { if(!check_kind(r)) { - return 0; + return nullptr; } return alloc(filter_interpreted_fn, *this, get(r).get_sort(), condition); } @@ -359,7 +359,7 @@ namespace datalog { relation_mutator_fn * external_relation_plugin::mk_filter_equal_fn(const relation_base & r, const relation_element & value, unsigned col) { if(!check_kind(r)) { - return 0; + return nullptr; } ast_manager& m = get_ast_manager(); app_ref condition(m); @@ -407,7 +407,7 @@ namespace datalog { relation_mutator_fn * external_relation_plugin::mk_filter_identical_fn(const relation_base & r, unsigned col_cnt, const unsigned * identical_cols) { if (!check_kind(r)) { - return 0; + return nullptr; } return alloc(filter_identical_fn, *this, get(r).get_sort(), col_cnt, identical_cols); } @@ -447,7 +447,7 @@ namespace datalog { const relation_base & negated_obj, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) { if (!check_kind(t) || !check_kind(negated_obj)) { - return 0; + return nullptr; } return alloc(negation_filter_fn, *this, t, negated_obj, joined_col_cnt, t_cols, negated_cols); } diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 4cb683df1..030fc1327 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -245,14 +245,14 @@ namespace datalog { } finite_product_relation * finite_product_relation_plugin::mk_from_table_relation(const table_relation & r) { - func_decl* pred = 0; + func_decl* pred = nullptr; const relation_signature & sig = r.get_signature(); const table_base & t = r.get_table(); table_plugin & tplugin = r.get_table().get_plugin(); relation_signature inner_sig; //empty signature for the inner relation if(!get_inner_plugin().can_handle_signature(inner_sig)) { - return 0; + return nullptr; } table_signature idx_singleton_sig; @@ -270,7 +270,7 @@ namespace datalog { idx_singleton_fact.push_back(0); idx_singleton->add_fact(idx_singleton_fact); - scoped_ptr join_fun = get_manager().mk_join_fn(t, *idx_singleton, 0, 0, 0); + scoped_ptr join_fun = get_manager().mk_join_fn(t, *idx_singleton, 0, nullptr, nullptr); SASSERT(join_fun); scoped_rel res_table = (*join_fun)(t, *idx_singleton); @@ -513,7 +513,7 @@ namespace datalog { return alloc(converting_join_fn, *this, rb1.get_signature(), rb2.get_signature(), col_cnt, cols1, cols2); } - return 0; + return nullptr; } const finite_product_relation & r1 = get(rb1); const finite_product_relation & r2 = get(rb2); @@ -590,7 +590,7 @@ namespace datalog { unsigned orig_rel_cnt = r.m_others.size(); for(unsigned i=0; iclone() : 0); + res_relations.push_back(orig_rel ? orig_rel->clone() : nullptr); } SASSERT(res_relations.size()==orig_rel_cnt); @@ -608,7 +608,7 @@ namespace datalog { res_table = (*tproject)(rtable); } - relation_plugin * res_oplugin = 0; + relation_plugin * res_oplugin = nullptr; if(!m_removed_rel_cols.empty()) { unsigned res_rel_cnt = res_relations.size(); @@ -651,7 +651,7 @@ namespace datalog { relation_transformer_fn * finite_product_relation_plugin::mk_project_fn(const relation_base & rb, unsigned col_cnt, const unsigned * removed_cols) { if(&rb.get_plugin()!=this) { - return 0; + return nullptr; } return alloc(project_fn, get(rb), col_cnt, removed_cols); } @@ -705,7 +705,7 @@ namespace datalog { unsigned orig_rel_cnt = r.m_others.size(); for(unsigned i=0; iclone() : 0); + res_relations.push_back(orig_rel ? orig_rel->clone() : nullptr); } if(!m_rel_identity) { @@ -746,7 +746,7 @@ namespace datalog { unsigned permutation_cycle_len, const unsigned * permutation_cycle) { if(&rb.get_plugin()!=this) { - return 0; + return nullptr; } const finite_product_relation & r = get(rb); return alloc(rename_fn, r, permutation_cycle_len, permutation_cycle); @@ -771,7 +771,7 @@ namespace datalog { relation_union_fn & get_inner_rel_union_op(relation_base & r) { if(!m_rel_union) { - m_rel_union = r.get_manager().mk_union_fn(r, r, m_use_delta ? &r : 0); + m_rel_union = r.get_manager().mk_union_fn(r, r, m_use_delta ? &r : nullptr); } return *m_rel_union; } @@ -1104,19 +1104,19 @@ namespace datalog { relation_union_fn * finite_product_relation_plugin::mk_union_fn(const relation_base & tgtb, const relation_base & srcb, const relation_base * deltab) { if(&srcb.get_plugin()!=this) { - return 0; + return nullptr; } const finite_product_relation & src = get(srcb); if(&tgtb.get_plugin()!=this || (deltab && &deltab->get_plugin()!=this) ) { if(can_convert_to_table_relation(src)) { return alloc(converting_union_fn); } - return 0; + return nullptr; } const finite_product_relation * delta = get(deltab); - return alloc(union_fn, get(tgtb), delta!=0); + return alloc(union_fn, get(tgtb), delta!=nullptr); } @@ -1131,7 +1131,7 @@ namespace datalog { scoped_ptr m_tr_filter; public: filter_identical_fn(const finite_product_relation & r, unsigned col_cnt, const unsigned * identical_cols) - : m_table_filter(0), m_rel_filter(0), m_tr_filter(0) { + : m_table_filter(nullptr), m_rel_filter(nullptr), m_tr_filter(nullptr) { finite_product_relation_plugin & plugin = r.get_plugin(); for(unsigned i=0; i complement_table = m_table->complement(p, &full_rel_idx); - scoped_ptr u_fn = get_manager().mk_union_fn(*m_table, *complement_table, 0); + scoped_ptr u_fn = get_manager().mk_union_fn(*m_table, *complement_table, nullptr); SASSERT(u_fn); - (*u_fn)(*m_table, *complement_table, 0); + (*u_fn)(*m_table, *complement_table, nullptr); } finite_product_relation * finite_product_relation::complement(func_decl* p) const { diff --git a/src/muz/rel/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp index d82f42b19..f7d1665d2 100644 --- a/src/muz/rel/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -36,7 +36,7 @@ namespace datalog { execution_context::execution_context(context & context) : m_context(context), - m_stopwatch(0), + m_stopwatch(nullptr), m_timelimit_ms(0) {} execution_context::~execution_context() { @@ -271,10 +271,10 @@ namespace datalog { bool perform(execution_context & ctx) override { if (ctx.reg(m_src)) log_verbose(ctx); if (m_clone) { - ctx.set_reg(m_tgt, ctx.reg(m_src) ? ctx.reg(m_src)->clone() : 0); + ctx.set_reg(m_tgt, ctx.reg(m_src) ? ctx.reg(m_src)->clone() : nullptr); } else { - ctx.set_reg(m_tgt, ctx.reg(m_src) ? ctx.release_reg(m_src) : 0); + ctx.set_reg(m_tgt, ctx.reg(m_src) ? ctx.release_reg(m_src) : nullptr); } return true; } @@ -662,7 +662,7 @@ namespace datalog { relation_base * new_delta = r_tgt.get_plugin().mk_empty(r_tgt); ctx.set_reg(m_delta, new_delta); } - relation_base * r_delta = (m_delta!=execution_context::void_register) ? ctx.reg(m_delta) : 0; + relation_base * r_delta = (m_delta!=execution_context::void_register) ? ctx.reg(m_delta) : nullptr; relation_union_fn * fn; @@ -687,10 +687,10 @@ namespace datalog { else { if (!find_fn(r_tgt, r_src, fn)) { if (m_widen) { - fn = r_src.get_manager().mk_widen_fn(r_tgt, r_src, 0); + fn = r_src.get_manager().mk_widen_fn(r_tgt, r_src, nullptr); } else { - fn = r_src.get_manager().mk_union_fn(r_tgt, r_src, 0); + fn = r_src.get_manager().mk_union_fn(r_tgt, r_src, nullptr); } if (!fn) { std::stringstream sstm; @@ -1135,7 +1135,7 @@ namespace datalog { dealloc(*it); } m_data.reset(); - m_observer = 0; + m_observer = nullptr; } bool instruction_block::perform(execution_context & ctx) const { diff --git a/src/muz/rel/dl_instruction.h b/src/muz/rel/dl_instruction.h index d2e1c30f5..6e0b7bfe5 100644 --- a/src/muz/rel/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -107,7 +107,7 @@ namespace datalog { */ reg_type reg(reg_idx i) const { if (i >= m_registers.size()) { - return 0; + return nullptr; } return m_registers[i]; } @@ -138,7 +138,7 @@ namespace datalog { void make_empty(reg_idx i) { if (reg(i)) { - set_reg(i, 0); + set_reg(i, nullptr); } } @@ -326,7 +326,7 @@ namespace datalog { instr_seq_type m_data; instruction_observer* m_observer; public: - instruction_block() : m_observer(0) {} + instruction_block() : m_observer(nullptr) {} ~instruction_block(); void reset(); diff --git a/src/muz/rel/dl_interval_relation.cpp b/src/muz/rel/dl_interval_relation.cpp index 12b6815cc..75f9e7e42 100644 --- a/src/muz/rel/dl_interval_relation.cpp +++ b/src/muz/rel/dl_interval_relation.cpp @@ -63,7 +63,7 @@ namespace datalog { interval_relation const& r1 = get(_r1); interval_relation const& r2 = get(_r2); interval_relation_plugin& p = r1.get_plugin(); - interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + interval_relation* result = dynamic_cast(p.mk_full(nullptr, get_result_signature())); result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); return result; } @@ -72,7 +72,7 @@ namespace datalog { relation_join_fn * interval_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if (!check_kind(r1) || !check_kind(r2)) { - return 0; + return nullptr; } return alloc(join_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2); } @@ -87,7 +87,7 @@ namespace datalog { relation_base * operator()(const relation_base & _r) override { interval_relation const& r = get(_r); interval_relation_plugin& p = r.get_plugin(); - interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + interval_relation* result = dynamic_cast(p.mk_full(nullptr, get_result_signature())); result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); return result; } @@ -107,7 +107,7 @@ namespace datalog { relation_base * operator()(const relation_base & _r) override { interval_relation const& r = get(_r); interval_relation_plugin& p = r.get_plugin(); - interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + interval_relation* result = dynamic_cast(p.mk_full(nullptr, get_result_signature())); result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); return result; } @@ -116,7 +116,7 @@ namespace datalog { relation_transformer_fn * interval_relation_plugin::mk_rename_fn(const relation_base & r, unsigned cycle_len, const unsigned * permutation_cycle) { if(!check_kind(r)) { - return 0; + return nullptr; } return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); } @@ -134,7 +134,7 @@ namespace datalog { high = src2.sup(); r_open = src2.is_upper_open(); } - return interval(dep(), low, l_open, 0, high, r_open, 0); + return interval(dep(), low, l_open, nullptr, high, r_open, nullptr); } interval interval_relation_plugin::widen(interval const& src1, interval const& src2) { @@ -151,7 +151,7 @@ namespace datalog { high = ext_numeral(true); r_open = true; } - return interval(dep(), low, l_open, 0, high, r_open, 0); + return interval(dep(), low, l_open, nullptr, high, r_open, nullptr); } interval interval_relation_plugin::meet(interval const& src1, interval const& src2, bool& isempty) { @@ -179,7 +179,7 @@ namespace datalog { return interval(dep()); } else { - return interval(dep(), low, l_open, 0, high, r_open, 0); + return interval(dep(), low, l_open, nullptr, high, r_open, nullptr); } } @@ -209,7 +209,7 @@ namespace datalog { r.mk_union(src, &d, m_is_widen); } else { - r.mk_union(src, 0, m_is_widen); + r.mk_union(src, nullptr, m_is_widen); } } }; @@ -217,7 +217,7 @@ namespace datalog { relation_union_fn * interval_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; + return nullptr; } return alloc(union_fn, false); } @@ -226,7 +226,7 @@ namespace datalog { const relation_base & tgt, const relation_base & src, const relation_base * delta) { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; + return nullptr; } return alloc(union_fn, true); } @@ -250,7 +250,7 @@ namespace datalog { relation_mutator_fn * interval_relation_plugin::mk_filter_identical_fn( const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { if(!check_kind(t)) { - return 0; + return nullptr; } return alloc(filter_identical_fn, col_cnt, identical_cols); } @@ -279,7 +279,7 @@ namespace datalog { if(check_kind(r)) { return alloc(filter_equal_fn, get_manager(), value, col); } - return 0; + return nullptr; } @@ -300,7 +300,7 @@ namespace datalog { if (check_kind(t)) { return alloc(filter_interpreted_fn, get(t), condition); } - return 0; + return nullptr; } interval_relation& interval_relation_plugin::get(relation_base& r) { @@ -329,7 +329,7 @@ namespace datalog { eq = m.mk_eq(m.mk_var(i, m.get_sort(e)), e); r.filter_interpreted(eq.get()); } - mk_union(r, 0, false); + mk_union(r, nullptr, false); } bool interval_relation::contains_fact(const relation_fact & f) const { @@ -365,7 +365,7 @@ namespace datalog { interval_relation * interval_relation::complement(func_decl*) const { UNREACHABLE(); - return 0; + return nullptr; } void interval_relation::to_formula(expr_ref& fml) const { @@ -434,22 +434,22 @@ namespace datalog { // 0 < x - y + k if (x == UINT_MAX) { // y < k - mk_intersect(y, interval(p.dep(), k, true, false, 0)); + mk_intersect(y, interval(p.dep(), k, true, false, nullptr)); return; } if (y == UINT_MAX) { // -k < x - mk_intersect(x, interval(p.dep(), -k, true, true, 0)); + mk_intersect(x, interval(p.dep(), -k, true, true, nullptr)); return; } // y < x + k ext_numeral x_hi = (*this)[x].sup(); ext_numeral y_lo = (*this)[y].inf(); if (!x_hi.is_infinite()) { - mk_intersect(y, interval(p.dep(), k + x_hi.to_rational(), true, false, 0)); + mk_intersect(y, interval(p.dep(), k + x_hi.to_rational(), true, false, nullptr)); } if (!y_lo.is_infinite()) { - mk_intersect(x, interval(p.dep(), y_lo.to_rational() - k, true, true, 0)); + mk_intersect(x, interval(p.dep(), y_lo.to_rational() - k, true, true, nullptr)); } return; } @@ -458,21 +458,21 @@ namespace datalog { // 0 <= x - y + k if (x == UINT_MAX) { // y <= k - mk_intersect(y, interval(p.dep(), k, false, false, 0)); + mk_intersect(y, interval(p.dep(), k, false, false, nullptr)); return; } if (y == UINT_MAX) { // -k <= x - mk_intersect(x, interval(p.dep(), -k, false, true, 0)); + mk_intersect(x, interval(p.dep(), -k, false, true, nullptr)); return; } ext_numeral x_hi = (*this)[x].sup(); ext_numeral y_lo = (*this)[y].inf(); if (!x_hi.is_infinite()) { - mk_intersect(y, interval(p.dep(), k + x_hi.to_rational(), false, false, 0)); + mk_intersect(y, interval(p.dep(), k + x_hi.to_rational(), false, false, nullptr)); } if (!y_lo.is_infinite()) { - mk_intersect(x, interval(p.dep(), y_lo.to_rational() - k, false, true, 0)); + mk_intersect(x, interval(p.dep(), y_lo.to_rational() - k, false, true, nullptr)); } return; } diff --git a/src/muz/rel/dl_lazy_table.cpp b/src/muz/rel/dl_lazy_table.cpp index 1b8681ab0..53d099532 100644 --- a/src/muz/rel/dl_lazy_table.cpp +++ b/src/muz/rel/dl_lazy_table.cpp @@ -65,7 +65,7 @@ namespace datalog { return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); } else { - return 0; + return nullptr; } } @@ -81,7 +81,7 @@ namespace datalog { lazy_table* delta = get(_delta); table_base const* t_src = src.eval(); table_base * t_tgt = tgt.eval(); - table_base * t_delta = delta?delta->eval():0; + table_base * t_delta = delta?delta->eval():nullptr; verbose_action _t("union"); table_union_fn* m = tgt.get_lplugin().get_manager().mk_union_fn(*t_tgt, *t_src, t_delta); SASSERT(m); @@ -98,7 +98,7 @@ namespace datalog { return alloc(union_fn); } else { - return 0; + return nullptr; } } @@ -124,7 +124,7 @@ namespace datalog { return alloc(project_fn, t.get_signature(), col_cnt, removed_cols); } else { - return 0; + return nullptr; } } @@ -150,7 +150,7 @@ namespace datalog { return alloc(rename_fn, t.get_signature(), col_cnt, removed_cols); } else { - return 0; + return nullptr; } } @@ -175,7 +175,7 @@ namespace datalog { return alloc(filter_identical_fn, col_cnt, identical_cols); } else { - return 0; + return nullptr; } } @@ -201,7 +201,7 @@ namespace datalog { return alloc(filter_interpreted_fn, cond); } else { - return 0; + return nullptr; } } @@ -229,7 +229,7 @@ namespace datalog { return alloc(filter_by_negation_fn, joined_col_cnt, t_cols, negated_cols); } else { - return 0; + return nullptr; } } @@ -258,7 +258,7 @@ namespace datalog { return alloc(filter_equal_fn, value, col); } else { - return 0; + return nullptr; } } @@ -269,7 +269,7 @@ namespace datalog { return alloc(lazy_table_plugin, *sp); } else { - return 0; + return nullptr; } } @@ -397,7 +397,7 @@ namespace datalog { SASSERT(!m_table); m_table = m_src->eval(); m_src->release_table(); - m_src = 0; + m_src = nullptr; verbose_action _t("filter_identical"); table_mutator_fn* m = rm().mk_filter_identical_fn(*m_table, m_cols.size(), m_cols.c_ptr()); SASSERT(m); @@ -410,7 +410,7 @@ namespace datalog { SASSERT(!m_table); m_table = m_src->eval(); m_src->release_table(); - m_src = 0; + m_src = nullptr; verbose_action _t("filter_equal"); table_mutator_fn* m = rm().mk_filter_equal_fn(*m_table, m_value, m_col); SASSERT(m); @@ -423,7 +423,7 @@ namespace datalog { SASSERT(!m_table); m_table = m_src->eval(); m_src->release_table(); - m_src = 0; + m_src = nullptr; verbose_action _t("filter_interpreted"); table_mutator_fn* m = rm().mk_filter_interpreted_fn(*m_table, m_condition); SASSERT(m); @@ -436,7 +436,7 @@ namespace datalog { SASSERT(!m_table); m_table = m_tgt->eval(); m_tgt->release_table(); - m_tgt = 0; + m_tgt = nullptr; switch(m_src->kind()) { diff --git a/src/muz/rel/dl_lazy_table.h b/src/muz/rel/dl_lazy_table.h index 19ea6773e..7e5991a7a 100644 --- a/src/muz/rel/dl_lazy_table.h +++ b/src/muz/rel/dl_lazy_table.h @@ -136,7 +136,7 @@ namespace datalog { } table_base * clone() const override; - table_base * complement(func_decl* p, const table_element * func_columns = 0) const override; + table_base * complement(func_decl* p, const table_element * func_columns = nullptr) const override; bool empty() const override; bool contains_fact(const table_fact & f) const override; void remove_fact(table_element const* fact) override; diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 4823ffb9b..1a1a47f74 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -189,7 +189,7 @@ namespace datalog { } bool is_undefined(unsigned col_idx) const { - return m_data[col_idx]==0; + return m_data[col_idx]==nullptr; } bool no_undefined() const { if (empty()) { @@ -296,7 +296,7 @@ namespace datalog { class explanation_relation_plugin::join_fn : public convenient_relation_join_fn { public: join_fn(const relation_signature & sig1, const relation_signature & sig2) - : convenient_relation_join_fn(sig1, sig2, 0, 0, 0) {} + : convenient_relation_join_fn(sig1, sig2, 0, nullptr, nullptr) {} relation_base * operator()(const relation_base & r1_0, const relation_base & r2_0) override { const explanation_relation & r1 = static_cast(r1_0); @@ -317,10 +317,10 @@ namespace datalog { relation_join_fn * explanation_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if (&r1.get_plugin()!=this || &r2.get_plugin()!=this) { - return 0; + return nullptr; } if (col_cnt!=0) { - return 0; + return nullptr; } return alloc(join_fn, r1.get_signature(), r2.get_signature()); } @@ -348,7 +348,7 @@ namespace datalog { relation_transformer_fn * explanation_relation_plugin::mk_project_fn(const relation_base & r, unsigned col_cnt, const unsigned * removed_cols) { if (&r.get_plugin()!=this) { - return 0; + return nullptr; } return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); } @@ -385,7 +385,7 @@ namespace datalog { void operator()(relation_base & tgt0, const relation_base & src0, relation_base * delta0) override { explanation_relation & tgt = static_cast(tgt0); const explanation_relation & src = static_cast(src0); - explanation_relation * delta = delta0 ? static_cast(delta0) : 0; + explanation_relation * delta = delta0 ? static_cast(delta0) : nullptr; explanation_relation_plugin & plugin = tgt.get_plugin(); if (!src.no_undefined() || !tgt.no_undefined() || (delta && !delta->no_undefined())) { @@ -420,7 +420,7 @@ namespace datalog { public: void operator()(relation_base & tgt0, const relation_base & src, relation_base * delta0) override { explanation_relation & tgt = static_cast(tgt0); - explanation_relation * delta = delta0 ? static_cast(delta0) : 0; + explanation_relation * delta = delta0 ? static_cast(delta0) : nullptr; if (src.empty()) { return; @@ -435,7 +435,7 @@ namespace datalog { relation_union_fn * explanation_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { if (!check_kind(tgt) || (delta && !check_kind(*delta))) { - return 0; + return nullptr; } if (!check_kind(src)) { //this is to handle the product relation @@ -480,11 +480,11 @@ namespace datalog { relation_mutator_fn * explanation_relation_plugin::mk_filter_interpreted_fn(const relation_base & r, app * cond) { if (&r.get_plugin()!=this) { - return 0; + return nullptr; } ast_manager & m = get_ast_manager(); if (!m.is_eq(cond)) { - return 0; + return nullptr; } expr * arg1 = cond->get_arg(0); expr * arg2 = cond->get_arg(1); @@ -494,12 +494,12 @@ namespace datalog { } if (!is_var(arg1) || !is_app(arg2)) { - return 0; + return nullptr; } var * col_var = to_var(arg1); app * new_rule = to_app(arg2); if (!get_context().get_decl_util().is_rule_sort(col_var->get_sort())) { - return 0; + return nullptr; } unsigned col_idx = col_var->get_idx(); @@ -520,7 +520,7 @@ namespace datalog { const relation_base & neg, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) { if (&r.get_plugin()!=this || &neg.get_plugin()!=this) { - return 0; + return nullptr; } return alloc(negation_filter_fn); } @@ -569,18 +569,18 @@ namespace datalog { const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt, const unsigned * tgt_cols, const unsigned * src_cols) { if (&tgt.get_plugin()!=this || &src.get_plugin()!=this) { - return 0; + return nullptr; } //this checks the join is one to one on all columns if (tgt.get_signature()!=src.get_signature() || joined_col_cnt!=tgt.get_signature().size() || !containers_equal(tgt_cols, tgt_cols+joined_col_cnt, src_cols, src_cols+joined_col_cnt)) { - return 0; + return nullptr; } counter ctr; ctr.count(joined_col_cnt, tgt_cols); if (ctr.get_max_counter_value()>1 || (joined_col_cnt && ctr.get_max_positive()!=joined_col_cnt-1)) { - return 0; + return nullptr; } return alloc(intersection_filter_fn, *this); } @@ -776,7 +776,7 @@ namespace datalog { app_ref orig_lit(m_manager.mk_app(orig_decl, lit_args.c_ptr()), m_manager); app_ref e_lit(get_e_lit(orig_lit, arity), m_manager); app * tail[] = { e_lit.get() }; - dst.add_rule(m_context.get_rule_manager().mk(orig_lit, 1, tail, 0)); + dst.add_rule(m_context.get_rule_manager().mk(orig_lit, 1, tail, nullptr)); } } @@ -852,7 +852,7 @@ namespace datalog { translate_rel_level_relation(rmgr, orig_rel, e_rel); } else { - scoped_ptr product_fun = rmgr.mk_join_fn(orig_rel, *m_e_fact_relation, 0, 0, 0); + scoped_ptr product_fun = rmgr.mk_join_fn(orig_rel, *m_e_fact_relation, 0, nullptr, nullptr); SASSERT(product_fun); scoped_rel aux_extended_rel = (*product_fun)(orig_rel, *m_e_fact_relation); TRACE("dl", tout << aux_extended_rel << " " << aux_extended_rel->get_plugin().get_name() << "\n"; @@ -868,10 +868,10 @@ namespace datalog { rule_set * mk_explanations::operator()(rule_set const & source) { if (source.empty()) { - return 0; + return nullptr; } if (!m_context.generate_explanations()) { - return 0; + return nullptr; } rule_set * res = alloc(rule_set, m_context); transform_facts(m_context.get_rel_context()->get_rmanager(), source, *res); diff --git a/src/muz/rel/dl_mk_similarity_compressor.cpp b/src/muz/rel/dl_mk_similarity_compressor.cpp index c4abf326a..c6063772a 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.cpp +++ b/src/muz/rel/dl_mk_similarity_compressor.cpp @@ -531,7 +531,7 @@ namespace datalog { } } - rule_set * result = static_cast(0); + rule_set * result = static_cast(nullptr); if (m_modified) { result = alloc(rule_set, m_context); unsigned fin_rule_cnt = m_result_rules.size(); diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index 60eea2e53..ac3d30e9e 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -165,7 +165,7 @@ namespace datalog { SASSERT(is_var(t->get_arg(i))); var * v = to_var(t->get_arg(i)); unsigned var_idx = v->get_idx(); - if (result[res_ofs-var_idx]==0) { + if (result[res_ofs-var_idx]==nullptr) { result[res_ofs-var_idx]=m.mk_var(next_var, v->get_sort()); next_var++; } @@ -235,7 +235,7 @@ namespace datalog { //so the order should not matter } - result.resize(max_var_idx+1, static_cast(0)); + result.resize(max_var_idx+1, static_cast(nullptr)); unsigned next_var = 0; get_normalizer(t1, next_var, result); get_normalizer(t2, next_var, result); @@ -268,9 +268,9 @@ namespace datalog { */ void register_pair(app * t1, app * t2, rule * r, const var_idx_set & non_local_vars) { SASSERT(t1!=t2); - cost_map::entry * e = m_costs.insert_if_not_there2(get_key(t1, t2), 0); + cost_map::entry * e = m_costs.insert_if_not_there2(get_key(t1, t2), nullptr); pair_info * & ptr_inf = e->get_data().m_value; - if (ptr_inf==0) { + if (ptr_inf==nullptr) { ptr_inf = alloc(pair_info); } pair_info & inf = *ptr_inf; @@ -297,7 +297,7 @@ namespace datalog { } void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) { - pair_info * ptr = 0; + pair_info * ptr = nullptr; if (m_costs.find(key, ptr) && ptr && ptr->remove_rule(r, original_len)) { SASSERT(ptr->m_rules.empty()); @@ -354,7 +354,7 @@ namespace datalog { void join_pair(app_pair pair_key) { app * t1 = pair_key.first; app * t2 = pair_key.second; - pair_info* infp = 0; + pair_info* infp = nullptr; if (!m_costs.find(pair_key, infp) || !infp) { UNREACHABLE(); return; @@ -402,7 +402,7 @@ namespace datalog { app * tail[] = {t1, t2}; - rule * new_rule = m_context.get_rule_manager().mk(head, 2, tail, 0); + rule * new_rule = m_context.get_rule_manager().mk(head, 2, tail, nullptr); //TODO: update accounting so that it can handle multiple parents new_rule->set_accounting_parent_object(m_context, one_parent); @@ -702,7 +702,7 @@ namespace datalog { } if (!m_modified_rules) { - return 0; + return nullptr; } rule_set * result = alloc(rule_set, m_context); rule_pred_map::iterator rcit = m_rules_content.begin(); diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp index 56fd56505..c591b7186 100644 --- a/src/muz/rel/dl_product_relation.cpp +++ b/src/muz/rel/dl_product_relation.cpp @@ -261,7 +261,7 @@ namespace datalog { void init(relation_signature const& r1_sig, unsigned num_rels1, relation_base const* const* r1, relation_signature const& r2_sig, unsigned num_rels2, relation_base const* const* r2, unsigned col_cnt, unsigned const* cols1, unsigned const* cols2) { - func_decl* p = 0; + func_decl* p = nullptr; bit_vector bv; bv.resize(num_rels2); relation_manager& rmgr = m_plugin.get_manager(); @@ -453,7 +453,7 @@ namespace datalog { TRACE("dl", _r1.display(tout); _r2.display(tout);); ptr_vector relations; unsigned sz = m_joins.size(); - relation_base* result = 0; + relation_base* result = nullptr; for (unsigned i = 0; i < sz; ++i) { relation_base const& r1 = (m_kind1[i] == T_FULL)?(*m_full[m_offset1[i]]):access(m_offset1[i], _r1); relation_base const& r2 = (m_kind2[i] == T_FULL)?(*m_full[m_offset2[i]]):access(m_offset2[i], _r2); @@ -479,7 +479,7 @@ namespace datalog { if (r1.get_kind() != r2.get_kind()) { return alloc(join_fn, *this, r1, r2, col_cnt, cols1, cols2); } - return 0; + return nullptr; } @@ -519,7 +519,7 @@ namespace datalog { relation_signature::from_project(r.get_signature(), col_cnt, removed_cols, s); return alloc(transform_fn, s, projs.size(), projs.c_ptr()); } - return 0; + return nullptr; } relation_transformer_fn * product_relation_plugin::mk_rename_fn(const relation_base & _r, @@ -534,7 +534,7 @@ namespace datalog { relation_signature::from_rename(r.get_signature(), cycle_len, permutation_cycle, s); return alloc(transform_fn, s, trans.size(), trans.c_ptr()); } - return 0; + return nullptr; } class product_relation_plugin::aligned_union_fn : public relation_union_fn { @@ -549,7 +549,7 @@ namespace datalog { void mk_union_fn(unsigned i, unsigned j, relation_base const& r1, relation_base const& r2, const relation_base* delta) { relation_manager& rmgr = r1.get_manager(); - relation_union_fn* u = 0; + relation_union_fn* u = nullptr; if (m_is_widen) { u = rmgr.mk_widen_fn(r1, r2, delta); } @@ -596,7 +596,7 @@ namespace datalog { return; } do_intersection(*tgt, *src); - src = 0; + src = nullptr; } void do_intersection(relation_base& tgt, relation_base& src) { @@ -625,7 +625,7 @@ namespace datalog { m_is_widen(is_widen) { SASSERT(vectors_equal(tgt.m_spec, src.m_spec)); SASSERT(!delta || vectors_equal(tgt.m_spec, delta->m_spec)); - init(tgt.m_relations, src.m_relations, delta ? &delta->m_relations : 0); + init(tgt.m_relations, src.m_relations, delta ? &delta->m_relations : nullptr); } ~aligned_union_fn() override { @@ -650,9 +650,9 @@ namespace datalog { for (unsigned i = 0; i < num; ++i) { relation_base& itgt = tgt[i]; - relation_base* idelta = delta ? &(*delta)[i] : 0; + relation_base* idelta = delta ? &(*delta)[i] : nullptr; - scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : 0; + scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : nullptr; scoped_rel side_result; scoped_rel side_delta; @@ -665,7 +665,7 @@ namespace datalog { TRACE("dl", itgt.display(tout << "tgt:\n"); src[j].display(tout << "src:\n");); // union[i][j] scoped_rel one_side_union = itgt.clone(); - scoped_rel one_side_delta = fresh_delta ? fresh_delta->clone() : 0; + scoped_rel one_side_delta = fresh_delta ? fresh_delta->clone() : nullptr; TRACE("dl", one_side_union->display(tout << "union 1:\n"); src[j].display(tout);); do_inner_union(i, j, *one_side_union, src[j], one_side_delta.get()); TRACE("dl", one_side_union->display(tout << "union:\n");); @@ -679,7 +679,7 @@ namespace datalog { // union[j][i] one_side_union = src[i].clone(); - one_side_delta = fresh_delta ? fresh_delta->clone() : 0; + one_side_delta = fresh_delta ? fresh_delta->clone() : nullptr; TRACE("dl", one_side_union->display(tout << "union 2:\n"); tgt[j].display(tout);); do_inner_union(i, j, *one_side_union, tgt[j], one_side_delta.get()); TRACE("dl", one_side_union->display(tout << "union:\n");); @@ -697,8 +697,8 @@ namespace datalog { } for (unsigned i = 0; i < num; ++i) { relation_base& itgt = tgt[i]; - relation_base* idelta = delta ? &(*delta)[i] : 0; - scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : 0; + relation_base* idelta = delta ? &(*delta)[i] : nullptr; + scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : nullptr; scoped_rel side_result(side_results[i]); scoped_rel side_delta(side_deltas[i]); @@ -752,7 +752,7 @@ namespace datalog { TRACE("dl_verbose", _tgt.display(tout << "dst:\n"); _src.display(tout << "src:\n");); product_relation& tgt = get(_tgt); product_relation const& src0 = get(_src); - product_relation* delta = _delta ? get(_delta) : 0; + product_relation* delta = _delta ? get(_delta) : nullptr; tgt.convert_spec(m_common_spec); if(delta) { @@ -815,7 +815,7 @@ namespace datalog { } } } - return 0; + return nullptr; } relation_union_fn * product_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, @@ -867,7 +867,7 @@ namespace datalog { return alloc(mutator_fn, mutators.size(), mutators.c_ptr()); } } - return 0; + return nullptr; } relation_mutator_fn * product_relation_plugin::mk_filter_equal_fn(const relation_base & _t, @@ -885,7 +885,7 @@ namespace datalog { return alloc(mutator_fn, mutators.size(), mutators.c_ptr()); } } - return 0; + return nullptr; } class product_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { @@ -983,7 +983,7 @@ namespace datalog { void product_relation::convert_spec(const rel_spec & spec) { - func_decl* p = 0; + func_decl* p = nullptr; const relation_signature & sig = get_signature(); family_id new_kind = get_plugin().get_relation_kind(sig, spec); if (new_kind == get_kind()) { @@ -1008,7 +1008,7 @@ namespace datalog { //the loop is quadratic with the number of relations, maybe we want to fix it for(unsigned i=0; iget_kind()==ikind) { @@ -1096,7 +1096,7 @@ namespace datalog { return res; } UNREACHABLE(); - return 0; + return nullptr; } bool product_relation::empty() const { diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 8226d0198..deb289277 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -47,8 +47,8 @@ namespace datalog { void relation_manager::reset() { reset_relations(); - m_favourite_table_plugin = static_cast(0); - m_favourite_relation_plugin = static_cast(0); + m_favourite_table_plugin = static_cast(nullptr); + m_favourite_relation_plugin = static_cast(nullptr); dealloc_ptr_vector_content(m_table_plugins); m_table_plugins.reset(); dealloc_ptr_vector_content(m_relation_plugins); @@ -95,9 +95,9 @@ namespace datalog { } relation_base * relation_manager::try_get_relation(func_decl * pred) const { - relation_base * res = 0; + relation_base * res = nullptr; if(!m_relations.find(pred, res)) { - return 0; + return nullptr; } SASSERT(res); return res; @@ -217,7 +217,7 @@ namespace datalog { return *rpit; } } - return 0; + return nullptr; } relation_plugin & relation_manager::get_appropriate_plugin(const relation_signature & s) { @@ -239,7 +239,7 @@ namespace datalog { return *tpit; } } - return 0; + return nullptr; } table_plugin & relation_manager::get_appropriate_plugin(const table_signature & t) { @@ -258,13 +258,13 @@ namespace datalog { return *rpit; } } - return 0; + return nullptr; } relation_plugin & relation_manager::get_relation_plugin(family_id kind) { SASSERT(kind>=0); SASSERT(kind aux = (*m_join)(t1, t2); @@ -851,21 +851,21 @@ namespace datalog { scoped_rel join_fun = mk_join_project_fn(tgt, src, joined_col_cnt, tgt_cols, src_cols, join_removed_cols.size(), join_removed_cols.c_ptr(), false); if(!join_fun) { - return 0; + return nullptr; } //we perform the join operation here to see what the result is scoped_rel join_res = (*join_fun)(tgt, src); if(tgt.can_swap(*join_res)) { - return alloc(default_relation_intersection_filter_fn, join_fun.release(), 0); + return alloc(default_relation_intersection_filter_fn, join_fun.release(), nullptr); } if(join_res->get_plugin().is_product_relation()) { //we cannot have the product relation here, since it uses the intersection operation //for unions and therefore we would get into an infinite recursion - return 0; + return nullptr; } scoped_rel union_fun = mk_union_fn(tgt, *join_res); if(!union_fun) { - return 0; + return nullptr; } return alloc(default_relation_intersection_filter_fn, join_fun.release(), union_fun.release()); } @@ -1357,11 +1357,11 @@ namespace datalog { static table_mutator_fn* mk(context& ctx, expr* condition) { ast_manager& m = ctx.get_manager(); if (!m.is_not(condition)) { - return 0; + return nullptr; } condition = to_app(condition)->get_arg(0); if (!m.is_eq(condition)) { - return 0; + return nullptr; } expr* x = to_app(condition)->get_arg(0); expr* y = to_app(condition)->get_arg(1); @@ -1369,12 +1369,12 @@ namespace datalog { std::swap(x, y); } if (!is_var(x)) { - return 0; + return nullptr; } dl_decl_util decl_util(m); uint64 value = 0; if (!decl_util.is_numeral_ext(y, value)) { - return 0; + return nullptr; } return alloc(default_table_filter_not_equal_fn, ctx, to_var(x)->get_idx(), value); } @@ -1410,7 +1410,7 @@ namespace datalog { unsigned col_cnt = f.size(); for(int i=col_cnt-1;i>=0;i--) { if(!m_free_vars.contains(i)) { - args.push_back(0); + args.push_back(nullptr); continue; //this variable does not occur in the condition; } @@ -1502,7 +1502,7 @@ namespace datalog { default_table_negation_filter_fn(const table_base & tgt, const table_base & neg_t, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) : convenient_table_negation_filter_fn(tgt, neg_t, joined_col_cnt, t_cols, negated_cols), - m_negated_table(0) { + m_negated_table(nullptr) { m_aux_fact.resize(neg_t.get_signature().size()); } @@ -1603,7 +1603,7 @@ namespace datalog { SASSERT(t.get_signature().functional_columns()>0); table_plugin & plugin = t.get_plugin(); m_aux_table = plugin.mk_empty(t.get_signature()); - m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(0)); + m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(nullptr)); } ~default_table_map_fn() override {} @@ -1625,7 +1625,7 @@ namespace datalog { } t.reset(); - (*m_union_fn)(t, *m_aux_table, static_cast(0)); + (*m_union_fn)(t, *m_aux_table, static_cast(nullptr)); } }; diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 088b246e4..bd7b9ae8c 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -109,8 +109,8 @@ namespace datalog { public: relation_manager(context & ctx) : m_context(ctx), - m_favourite_table_plugin(0), - m_favourite_relation_plugin(0), + m_favourite_table_plugin(nullptr), + m_favourite_relation_plugin(nullptr), m_next_table_fid(0), m_next_relation_fid(0) {} @@ -331,7 +331,7 @@ namespace datalog { const relation_base * delta); relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src) { - return mk_union_fn(tgt, src, static_cast(0)); + return mk_union_fn(tgt, src, static_cast(nullptr)); } /** @@ -510,7 +510,7 @@ namespace datalog { const table_base * delta); table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src) { - return mk_union_fn(tgt, src, static_cast(0)); + return mk_union_fn(tgt, src, static_cast(nullptr)); } /** diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index 401d519d5..a5ad20059 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -226,7 +226,7 @@ namespace datalog { relation_base * sieve_relation_plugin::mk_empty(const relation_signature & s) { UNREACHABLE(); - return 0; + return nullptr; #if 0 svector inner_cols(s.size()); extract_inner_columns(s, inner_cols.c_ptr()); @@ -278,8 +278,8 @@ namespace datalog { m_inner_join_fun(inner_join_fun) { bool r1_sieved = r1.get_plugin().is_sieve_relation(); bool r2_sieved = r2.get_plugin().is_sieve_relation(); - const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; - const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; + const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : nullptr; + const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : nullptr; if(r1_sieved) { m_result_inner_cols.append(sr1->m_inner_cols); } @@ -298,8 +298,8 @@ namespace datalog { bool r1_sieved = r1.get_plugin().is_sieve_relation(); bool r2_sieved = r2.get_plugin().is_sieve_relation(); SASSERT(r1_sieved || r2_sieved); - const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; - const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; + const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : nullptr; + const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : nullptr; const relation_base & inner1 = r1_sieved ? sr1->get_inner() : r1; const relation_base & inner2 = r2_sieved ? sr2->get_inner() : r2; @@ -313,12 +313,12 @@ namespace datalog { unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if( &r1.get_plugin()!=this && &r2.get_plugin()!=this ) { //we create just operations that involve the current plugin - return 0; + return nullptr; } bool r1_sieved = r1.get_plugin().is_sieve_relation(); bool r2_sieved = r2.get_plugin().is_sieve_relation(); - const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; - const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; + const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : nullptr; + const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : nullptr; const relation_base & inner1 = r1_sieved ? sr1->get_inner() : r1; const relation_base & inner2 = r2_sieved ? sr2->get_inner() : r2; @@ -340,7 +340,7 @@ namespace datalog { relation_join_fn * inner_join_fun = get_manager().mk_join_fn(inner1, inner2, inner_cols1, inner_cols2, false); if(!inner_join_fun) { - return 0; + return nullptr; } return alloc(join_fn, *this, r1, r2, col_cnt, cols1, cols2, inner_join_fun); } @@ -371,7 +371,7 @@ namespace datalog { relation_transformer_fn * sieve_relation_plugin::mk_project_fn(const relation_base & r0, unsigned col_cnt, const unsigned * removed_cols) { if(&r0.get_plugin()!=this) { - return 0; + return nullptr; } const sieve_relation & r = static_cast(r0); unsigned_vector inner_removed_cols; @@ -398,7 +398,7 @@ namespace datalog { } if(!inner_fun) { - return 0; + return nullptr; } return alloc(transformer_fn, inner_fun, result_sig, result_inner_cols.c_ptr()); } @@ -406,7 +406,7 @@ namespace datalog { relation_transformer_fn * sieve_relation_plugin::mk_rename_fn(const relation_base & r0, unsigned cycle_len, const unsigned * permutation_cycle) { if(&r0.get_plugin()!=this) { - return 0; + return nullptr; } const sieve_relation & r = static_cast(r0); @@ -428,7 +428,7 @@ namespace datalog { relation_transformer_fn * inner_fun = get_manager().mk_permutation_rename_fn(r.get_inner(), inner_permutation); if(!inner_fun) { - return 0; + return nullptr; } return alloc(transformer_fn, inner_fun, result_sig, result_inner_cols.c_ptr()); } @@ -443,9 +443,9 @@ namespace datalog { bool tgt_sieved = tgt.get_plugin().is_sieve_relation(); bool src_sieved = src.get_plugin().is_sieve_relation(); bool delta_sieved = delta && delta->get_plugin().is_sieve_relation(); - sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : 0; - const sieve_relation * ssrc = src_sieved ? static_cast(&src) : 0; - sieve_relation * sdelta = delta_sieved ? static_cast(delta) : 0; + sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : nullptr; + const sieve_relation * ssrc = src_sieved ? static_cast(&src) : nullptr; + sieve_relation * sdelta = delta_sieved ? static_cast(delta) : nullptr; relation_base & itgt = tgt_sieved ? stgt->get_inner() : tgt; const relation_base & isrc = src_sieved ? ssrc->get_inner() : src; relation_base * idelta = delta_sieved ? &sdelta->get_inner() : delta; @@ -458,15 +458,15 @@ namespace datalog { const relation_base * delta) { if(&tgt.get_plugin()!=this && &src.get_plugin()!=this && (delta && &delta->get_plugin()!=this)) { //we create the operation only if it involves this plugin - return 0; + return nullptr; } bool tgt_sieved = tgt.get_plugin().is_sieve_relation(); bool src_sieved = src.get_plugin().is_sieve_relation(); bool delta_sieved = delta && delta->get_plugin().is_sieve_relation(); - const sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : 0; - const sieve_relation * ssrc = src_sieved ? static_cast(&src) : 0; - const sieve_relation * sdelta = delta_sieved ? static_cast(delta) : 0; + const sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : nullptr; + const sieve_relation * ssrc = src_sieved ? static_cast(&src) : nullptr; + const sieve_relation * sdelta = delta_sieved ? static_cast(delta) : nullptr; const relation_base & itgt = tgt_sieved ? stgt->get_inner() : tgt; const relation_base & isrc = src_sieved ? ssrc->get_inner() : src; const relation_base * idelta = delta_sieved ? &sdelta->get_inner() : delta; @@ -476,7 +476,7 @@ namespace datalog { if( tgt_sieved && src_sieved && (!delta || delta_sieved) ) { if( !vectors_equal(stgt->m_inner_cols, ssrc->m_inner_cols) || (delta && !vectors_equal(stgt->m_inner_cols, sdelta->m_inner_cols)) ) { - return 0; + return nullptr; } } else { @@ -485,13 +485,13 @@ namespace datalog { || (sdelta && !sdelta->no_sieved_columns()) ) { //We have an unsieved relation and then some relation with some sieved columns, //which means there is an misalignment. - return 0; + return nullptr; } } relation_union_fn * union_fun = get_manager().mk_union_fn(itgt, isrc, idelta); if(!union_fun) { - return 0; + return nullptr; } return alloc(union_fn, union_fun); @@ -515,7 +515,7 @@ namespace datalog { relation_mutator_fn * sieve_relation_plugin::mk_filter_identical_fn(const relation_base & r0, unsigned col_cnt, const unsigned * identical_cols) { if(&r0.get_plugin()!=this) { - return 0; + return nullptr; } const sieve_relation & r = static_cast(r0); unsigned_vector inner_icols; @@ -534,7 +534,7 @@ namespace datalog { relation_mutator_fn * inner_fun = get_manager().mk_filter_identical_fn(r.get_inner(), inner_icols); if(!inner_fun) { - return 0; + return nullptr; } return alloc(filter_fn, inner_fun); } @@ -542,7 +542,7 @@ namespace datalog { relation_mutator_fn * sieve_relation_plugin::mk_filter_equal_fn(const relation_base & r0, const relation_element & value, unsigned col) { if(&r0.get_plugin()!=this) { - return 0; + return nullptr; } const sieve_relation & r = static_cast(r0); if(!r.is_inner_col(col)) { @@ -553,7 +553,7 @@ namespace datalog { relation_mutator_fn * inner_fun = get_manager().mk_filter_equal_fn(r.get_inner(), value, inner_col); if(!inner_fun) { - return 0; + return nullptr; } return alloc(filter_fn, inner_fun); } @@ -561,7 +561,7 @@ namespace datalog { relation_mutator_fn * sieve_relation_plugin::mk_filter_interpreted_fn(const relation_base & rb, app * condition) { if(&rb.get_plugin()!=this) { - return 0; + return nullptr; } ast_manager & m = get_ast_manager(); const sieve_relation & r = static_cast(rb); @@ -589,7 +589,7 @@ namespace datalog { relation_mutator_fn * inner_fun = get_manager().mk_filter_interpreted_fn(r.get_inner(), to_app(inner_cond)); if(!inner_fun) { - return 0; + return nullptr; } return alloc(filter_fn, inner_fun); } @@ -604,8 +604,8 @@ namespace datalog { bool r_sieved = r.get_plugin().is_sieve_relation(); bool neg_sieved = neg.get_plugin().is_sieve_relation(); SASSERT(r_sieved || neg_sieved); - sieve_relation * sr = r_sieved ? static_cast(&r) : 0; - const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : 0; + sieve_relation * sr = r_sieved ? static_cast(&r) : nullptr; + const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : nullptr; relation_base & inner_r = r_sieved ? sr->get_inner() : r; const relation_base & inner_neg = neg_sieved ? sneg->get_inner() : neg; @@ -618,13 +618,13 @@ namespace datalog { const unsigned * neg_cols) { if(&r.get_plugin()!=this && &neg.get_plugin()!=this) { //we create just operations that involve the current plugin - return 0; + return nullptr; } bool r_sieved = r.get_plugin().is_sieve_relation(); bool neg_sieved = neg.get_plugin().is_sieve_relation(); SASSERT(r_sieved || neg_sieved); - const sieve_relation * sr = r_sieved ? static_cast(&r) : 0; - const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : 0; + const sieve_relation * sr = r_sieved ? static_cast(&r) : nullptr; + const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : nullptr; const relation_base & inner_r = r_sieved ? sr->get_inner() : r; const relation_base & inner_neg = neg_sieved ? sneg->get_inner() : neg; @@ -657,7 +657,7 @@ namespace datalog { relation_intersection_filter_fn * inner_fun = get_manager().mk_filter_by_negation_fn(inner_r, inner_neg, ir_cols, ineg_cols); if(!inner_fun) { - return 0; + return nullptr; } return alloc(negation_filter_fn, inner_fun); } diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index 50386152c..779172b0d 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -257,8 +257,8 @@ namespace datalog { \brief Empty result. */ query_result() : m_singleton(false) { - m_many.begin = 0; - m_many.end = 0; + m_many.begin = nullptr; + m_many.end = nullptr; } query_result(offset_iterator begin, offset_iterator end) : m_singleton(false) { m_many.begin = begin; @@ -327,7 +327,7 @@ namespace datalog { key_value key; key.resize(key_len); - offset_vector * index_entry = 0; + offset_vector * index_entry = nullptr; bool key_modified = true; for (; ofs!=after_last; ofs+=t.m_fact_size) { @@ -473,7 +473,7 @@ namespace datalog { #endif key_spec kspec; kspec.append(key_len, key_cols); - key_index_map::entry * key_map_entry = m_key_indexes.insert_if_not_there2(kspec, 0); + key_index_map::entry * key_map_entry = m_key_indexes.insert_if_not_there2(kspec, nullptr); if (!key_map_entry->get_data().m_value) { if (full_signature_key_indexer::can_handle(key_len, key_cols, *this)) { key_map_entry->get_data().m_value = alloc(full_signature_key_indexer, key_len, key_cols, *this); @@ -777,9 +777,9 @@ namespace datalog { const table_signature & sig = t->get_signature(); t->reset(); - table_pool::entry * e = m_pool.insert_if_not_there2(sig, 0); + table_pool::entry * e = m_pool.insert_if_not_there2(sig, nullptr); sp_table_vector * & vect = e->get_data().m_value; - if (vect == 0) { + if (vect == nullptr) { vect = alloc(sp_table_vector); } IF_VERBOSE(12, verbose_stream() << "Recycle: " << t->get_size_estimate_bytes() << "\n";); @@ -859,9 +859,9 @@ namespace datalog { if (t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind() || join_involves_functional(sig1, sig2, col_cnt, cols1, cols2)) { //We also don't allow indexes on functional columns (and they are needed for joins) - return 0; + return nullptr; } - return mk_join_project_fn(t1, t2, col_cnt, cols1, cols2, 0, static_cast(0)); + return mk_join_project_fn(t1, t2, col_cnt, cols1, cols2, 0, static_cast(nullptr)); } table_join_fn * sparse_table_plugin::mk_join_project_fn(const table_base & t1, const table_base & t2, @@ -874,7 +874,7 @@ namespace datalog { || join_involves_functional(sig1, sig2, col_cnt, cols1, cols2)) { //We don't allow sparse tables with zero signatures (and project on all columns leads to such) //We also don't allow indexes on functional columns. - return 0; + return nullptr; } return alloc(join_project_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); @@ -905,7 +905,7 @@ namespace datalog { || (delta && delta->get_kind()!=get_kind()) || tgt.get_signature()!=src.get_signature() || (delta && delta->get_signature()!=tgt.get_signature())) { - return 0; + return nullptr; } return alloc(union_fn); } @@ -969,7 +969,7 @@ namespace datalog { table_transformer_fn * sparse_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols) { if (col_cnt == t.get_signature().size()) { - return 0; + return nullptr; } return alloc(project_fn, t.get_signature(), col_cnt, removed_cols); } @@ -1032,7 +1032,7 @@ namespace datalog { //column table produces one). //We also don't allow indexes on functional columns. And our implementation of //select_equal_and_project uses index on \c col. - return 0; + return nullptr; } return alloc(select_equal_and_project_fn, t.get_signature(), value, col); } @@ -1113,7 +1113,7 @@ namespace datalog { table_transformer_fn * sparse_table_plugin::mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, const unsigned * permutation_cycle) { if (t.get_kind()!=get_kind()) { - return 0; + return nullptr; } return alloc(rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle); } @@ -1252,7 +1252,7 @@ namespace datalog { if (!check_kind(t) || !check_kind(negated_obj) || join_involves_functional(t.get_signature(), negated_obj.get_signature(), joined_col_cnt, t_cols, negated_cols) ) { - return 0; + return nullptr; } return alloc(negation_filter_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols); } @@ -1394,7 +1394,7 @@ namespace datalog { return alloc(negated_join_fn, src1, t_cols, src_cols, src1_cols, src2_cols); } else { - return 0; + return nullptr; } } diff --git a/src/muz/rel/dl_table.cpp b/src/muz/rel/dl_table.cpp index 963820c91..71ffd88f3 100644 --- a/src/muz/rel/dl_table.cpp +++ b/src/muz/rel/dl_table.cpp @@ -89,7 +89,7 @@ namespace datalog { table_join_fn * hashtable_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if(t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind()) { - return 0; + return nullptr; } return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); } diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp index d5d8fd3c9..de55998f8 100644 --- a/src/muz/rel/dl_table_relation.cpp +++ b/src/muz/rel/dl_table_relation.cpp @@ -48,7 +48,7 @@ namespace datalog { relation_base * table_relation_plugin::mk_empty(const relation_signature & s) { table_signature tsig; if (!get_manager().relation_signature_to_table(s, tsig)) { - return 0; + return nullptr; } table_base * t = m_table_plugin.mk_empty(tsig); return alloc(table_relation, *this, s, t); @@ -57,7 +57,7 @@ namespace datalog { relation_base * table_relation_plugin::mk_full_relation(const relation_signature & s, func_decl* p, family_id kind) { table_signature tsig; if(!get_manager().relation_signature_to_table(s, tsig)) { - return 0; + return nullptr; } table_base * t = m_table_plugin.mk_full(p, tsig, kind); return alloc(table_relation, *this, s, t); @@ -108,25 +108,25 @@ namespace datalog { relation_join_fn * table_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if(!r1.from_table() || !r2.from_table()) { - return 0; + return nullptr; } const table_relation & tr1 = static_cast(r1); const table_relation & tr2 = static_cast(r2); table_join_fn * tfun = get_manager().mk_join_fn(tr1.get_table(), tr2.get_table(), col_cnt, cols1, cols2); if(!tfun) { - return 0; + return nullptr; } return alloc(tr_join_project_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, - cols2, 0, static_cast(0), tfun); + cols2, 0, static_cast(nullptr), tfun); } relation_join_fn * table_relation_plugin::mk_join_project_fn(const relation_base & r1, const relation_base & r2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { if(!r1.from_table() || !r2.from_table()) { - return 0; + return nullptr; } const table_relation & tr1 = static_cast(r1); const table_relation & tr2 = static_cast(r2); @@ -168,7 +168,7 @@ namespace datalog { relation_transformer_fn * table_relation_plugin::mk_project_fn(const relation_base & t, unsigned col_cnt, const unsigned * removed_cols) { if(!t.from_table()) { - return 0; + return nullptr; } const table_relation & tr = static_cast(t); @@ -184,7 +184,7 @@ namespace datalog { relation_transformer_fn * table_relation_plugin::mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, const unsigned * permutation_cycle) { if(!t.from_table()) { - return 0; + return nullptr; } const table_relation & tr = static_cast(t); @@ -200,7 +200,7 @@ namespace datalog { relation_transformer_fn * table_relation_plugin::mk_permutation_rename_fn(const relation_base & t, const unsigned * permutation) { if(!t.from_table()) { - return 0; + return nullptr; } const table_relation & tr = static_cast(t); @@ -216,7 +216,7 @@ namespace datalog { relation_transformer_fn * table_relation_plugin::mk_select_equal_and_project_fn(const relation_base & t, const relation_element & value, unsigned col) { if(!t.from_table()) { - return 0; + return nullptr; } const table_relation & tr = static_cast(t); @@ -280,7 +280,7 @@ namespace datalog { const table_relation & tr_src = static_cast(src); table_relation * tr_delta = static_cast(delta); - (*m_tfun)(tr_tgt.get_table(), tr_src.get_table(), tr_delta ? &tr_delta->get_table() : 0); + (*m_tfun)(tr_tgt.get_table(), tr_src.get_table(), tr_delta ? &tr_delta->get_table() : nullptr); TRACE("dl_table_relation", tout << "# union => "; tr_tgt.get_table().display(tout);); } @@ -289,7 +289,7 @@ namespace datalog { relation_union_fn * table_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { if(!src.from_table()) { - return 0; + return nullptr; } if(!tgt.from_table() || (delta && !delta->from_table())) { return alloc(universal_target_union_fn); @@ -299,7 +299,7 @@ namespace datalog { const table_relation * tr_delta = static_cast(delta); table_union_fn * tfun = get_manager().mk_union_fn(tr_tgt.get_table(), tr_src.get_table(), - tr_delta ? &tr_delta->get_table() : 0); + tr_delta ? &tr_delta->get_table() : nullptr); SASSERT(tfun); return alloc(tr_union_fn, tfun); @@ -322,7 +322,7 @@ namespace datalog { relation_mutator_fn * table_relation_plugin::mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { if(!t.from_table()) { - return 0; + return nullptr; } const table_relation & tr = static_cast(t); @@ -334,7 +334,7 @@ namespace datalog { relation_mutator_fn * table_relation_plugin::mk_filter_equal_fn(const relation_base & t, const relation_element & value, unsigned col) { if(!t.from_table()) { - return 0; + return nullptr; } const table_relation & tr = static_cast(t); @@ -349,7 +349,7 @@ namespace datalog { relation_mutator_fn * table_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { bool condition_needs_transforming = false; if(!t.from_table() || condition_needs_transforming) { - return 0; + return nullptr; } const table_relation & tr = static_cast(t); table_mutator_fn * tfun = get_manager().mk_filter_interpreted_fn(tr.get_table(), condition); @@ -360,7 +360,7 @@ namespace datalog { relation_transformer_fn * table_relation_plugin::mk_filter_interpreted_and_project_fn(const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { if (!t.from_table()) - return 0; + return nullptr; const table_relation & tr = static_cast(t); table_transformer_fn * tfun = get_manager().mk_filter_interpreted_and_project_fn(tr.get_table(), @@ -392,14 +392,14 @@ namespace datalog { relation_intersection_filter_fn * table_relation_plugin::mk_filter_by_intersection_fn(const relation_base & r, const relation_base & src, unsigned joined_col_cnt, const unsigned * r_cols, const unsigned * src_cols) { if(!r.from_table() || !src.from_table()) { - return 0; + return nullptr; } const table_relation & tr = static_cast(r); const table_relation & tr_neg = static_cast(src); table_intersection_filter_fn * tfun = get_manager().mk_filter_by_intersection_fn(tr.get_table(), tr_neg.get_table(), joined_col_cnt, r_cols, src_cols); if(!tfun) { - return 0; + return nullptr; } return alloc(tr_intersection_filter_fn, tfun); @@ -410,7 +410,7 @@ namespace datalog { const relation_base & negated_rel, unsigned joined_col_cnt, const unsigned * r_cols, const unsigned * negated_cols) { if(!r.from_table() || !negated_rel.from_table()) { - return 0; + return nullptr; } const table_relation & tr = static_cast(r); const table_relation & tr_neg = static_cast(negated_rel); diff --git a/src/muz/rel/doc.cpp b/src/muz/rel/doc.cpp index 23d24dfc3..d205e7725 100644 --- a/src/muz/rel/doc.cpp +++ b/src/muz/rel/doc.cpp @@ -447,7 +447,7 @@ doc* doc_manager::join(const doc& d1, const doc& d2, doc_manager& dm1, } else if (v1 != v2) { // columns don't match - return 0; + return nullptr; } SASSERT(well_formed(*d)); } diff --git a/src/muz/rel/doc.h b/src/muz/rel/doc.h index 419081892..81f55497a 100644 --- a/src/muz/rel/doc.h +++ b/src/muz/rel/doc.h @@ -373,7 +373,7 @@ class doc_ref { doc_manager& dm; doc* d; public: - doc_ref(doc_manager& dm):dm(dm),d(0) {} + doc_ref(doc_manager& dm):dm(dm),d(nullptr) {} doc_ref(doc_manager& dm, doc* d):dm(dm),d(d) {} ~doc_ref() { if (d) dm.deallocate(d); @@ -385,8 +385,8 @@ public: } doc& operator*() { return *d; } doc* operator->() { return d; } - doc* detach() { doc* r = d; d = 0; return r; } - operator bool() const { return d != 0; } + doc* detach() { doc* r = d; d = nullptr; return r; } + operator bool() const { return d != nullptr; } }; #endif /* DOC_H_ */ diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index c73b8356d..956244b4f 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -90,7 +90,7 @@ namespace datalog { karr_relation * complement(func_decl*) const override { UNREACHABLE(); - return 0; + return nullptr; } void to_formula(expr_ref& fml) const override { @@ -111,8 +111,8 @@ namespace datalog { void filter_interpreted(app* cond) { rational one(1), mone(-1); - expr* e1 = 0, *e2 = 0, *en = 0; - var* v = 0, *w = 0; + expr* e1 = nullptr, *e2 = nullptr, *en = nullptr; + var* v = nullptr, *w = nullptr; rational n1, n2; expr_ref_vector conjs(m); flatten_and(cond, conjs); @@ -500,7 +500,7 @@ namespace datalog { } relation_base * karr_relation_plugin::mk_empty(const relation_signature & s) { - return alloc(karr_relation, *this, 0, s, true); + return alloc(karr_relation, *this, nullptr, s, true); } relation_base * karr_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { @@ -518,7 +518,7 @@ namespace datalog { karr_relation const& r1 = get(_r1); karr_relation const& r2 = get(_r2); karr_relation_plugin& p = r1.get_plugin(); - karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + karr_relation* result = dynamic_cast(p.mk_full(nullptr, get_result_signature())); result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); return result; } @@ -528,7 +528,7 @@ namespace datalog { const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if (!check_kind(t1) || !check_kind(t2)) { - return 0; + return nullptr; } return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); } @@ -543,7 +543,7 @@ namespace datalog { relation_base * operator()(const relation_base & _r) override { karr_relation const& r = get(_r); karr_relation_plugin& p = r.get_plugin(); - karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + karr_relation* result = dynamic_cast(p.mk_full(nullptr, get_result_signature())); result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); return result; } @@ -562,7 +562,7 @@ namespace datalog { relation_base * operator()(const relation_base & _r) override { karr_relation const& r = get(_r); karr_relation_plugin& p = r.get_plugin(); - karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + karr_relation* result = dynamic_cast(p.mk_full(nullptr, get_result_signature())); result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); return result; } @@ -571,7 +571,7 @@ namespace datalog { relation_transformer_fn * karr_relation_plugin::mk_rename_fn(const relation_base & r, unsigned cycle_len, const unsigned * permutation_cycle) { if (!check_kind(r)) { - return 0; + return nullptr; } return alloc(rename_fn, *this, r.get_signature(), cycle_len, permutation_cycle); } @@ -687,7 +687,7 @@ namespace datalog { r.mk_union(src, &d); } else { - r.mk_union(src, 0); + r.mk_union(src, nullptr); } TRACE("dl", r.display(tout << "result:\n");); } @@ -696,7 +696,7 @@ namespace datalog { relation_union_fn * karr_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; + return nullptr; } return alloc(union_fn); } @@ -730,7 +730,7 @@ namespace datalog { relation_mutator_fn * karr_relation_plugin::mk_filter_identical_fn( const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { if(!check_kind(t)) { - return 0; + return nullptr; } return alloc(filter_identical_fn, col_cnt, identical_cols); } @@ -768,7 +768,7 @@ namespace datalog { if (check_kind(r)) { return alloc(filter_equal_fn, get_manager(), value, col); } - return 0; + return nullptr; } @@ -789,6 +789,6 @@ namespace datalog { if (check_kind(t)) { return alloc(filter_interpreted_fn, get(t), condition); } - return 0; + return nullptr; } }; diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index 9fb1e89e0..dfef3ac73 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -96,7 +96,7 @@ namespace datalog { m(ctx.get_manager()), m_rmanager(ctx), m_answer(m), - m_last_result_relation(0), + m_last_result_relation(nullptr), m_ectx(ctx), m_sw(0) { @@ -121,7 +121,7 @@ namespace datalog { rel_context::~rel_context() { if (m_last_result_relation) { m_last_result_relation->deallocate(); - m_last_result_relation = 0; + m_last_result_relation = nullptr; } } diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index 1839700d6..22c25a5e9 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -130,7 +130,7 @@ class tbv_ref { tbv_manager& mgr; tbv* d; public: - tbv_ref(tbv_manager& mgr):mgr(mgr),d(0) {} + tbv_ref(tbv_manager& mgr):mgr(mgr),d(nullptr) {} tbv_ref(tbv_manager& mgr, tbv* d):mgr(mgr),d(d) {} ~tbv_ref() { if (d) mgr.deallocate(d); @@ -143,7 +143,7 @@ public: tbv& operator*() { return *d; } tbv* operator->() { return d; } tbv* get() { return d; } - tbv* detach() { tbv* result = d; d = 0; return result; } + tbv* detach() { tbv* result = d; d = nullptr; return result; } }; diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index a5b9a2084..ff23a5e53 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -203,7 +203,7 @@ namespace datalog { return dynamic_cast(r); } udoc_relation* udoc_plugin::get(relation_base* r) { - return r?dynamic_cast(r):0; + return r?dynamic_cast(r):nullptr; } udoc_relation const & udoc_plugin::get(relation_base const& r) { return dynamic_cast(r); @@ -351,7 +351,7 @@ namespace datalog { const relation_base & t1, const relation_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { if (!check_kind(t1) || !check_kind(t2)) { - return 0; + return nullptr; } return alloc(join_fn, *this, get(t1), get(t2), col_cnt, cols1, cols2); } @@ -394,7 +394,7 @@ namespace datalog { const relation_base & t, unsigned col_cnt, const unsigned * removed_cols) { if (!check_kind(t)) - return 0; + return nullptr; return alloc(project_fn, get(t), col_cnt, removed_cols); } @@ -487,7 +487,7 @@ namespace datalog { return alloc(rename_fn, get(r), cycle_len, permutation_cycle); } else { - return 0; + return nullptr; } } class udoc_plugin::union_fn : public relation_union_fn { @@ -500,7 +500,7 @@ namespace datalog { udoc_relation const& src = get(_src); udoc_relation* d = get(_delta); doc_manager& dm = r.get_dm(); - udoc* d1 = 0; + udoc* d1 = nullptr; if (d) d1 = &d->get_udoc(); IF_VERBOSE(3, r.display(verbose_stream() << "orig: ");); r.get_plugin().mk_union(dm, r.get_udoc(), src.get_udoc(), d1); @@ -539,7 +539,7 @@ namespace datalog { const relation_base & tgt, const relation_base & src, const relation_base * delta) { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; + return nullptr; } return alloc(union_fn); } @@ -585,7 +585,7 @@ namespace datalog { }; relation_mutator_fn * udoc_plugin::mk_filter_identical_fn( const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { - return check_kind(t)?alloc(filter_identical_fn, t, col_cnt, identical_cols):0; + return check_kind(t)?alloc(filter_identical_fn, t, col_cnt, identical_cols):nullptr; } class udoc_plugin::filter_equal_fn : public relation_mutator_fn { doc_manager& dm; @@ -614,7 +614,7 @@ namespace datalog { relation_mutator_fn * udoc_plugin::mk_filter_equal_fn( const relation_base & t, const relation_element & value, unsigned col) { if (!check_kind(t)) - return 0; + return nullptr; return alloc(filter_equal_fn, *this, get(t), value, col); } @@ -951,7 +951,7 @@ namespace datalog { } }; relation_mutator_fn * udoc_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):0; + return check_kind(t)?alloc(filter_interpreted_fn, get(t), get_ast_manager(), condition):nullptr; } class udoc_plugin::join_project_fn : public convenient_relation_join_project_fn { @@ -1055,7 +1055,7 @@ namespace datalog { unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { if (!check_kind(t1) || !check_kind(t2)) - return 0; + return nullptr; // special case where we have h(X) :- f(X), g(X). if (joined_col_cnt == removed_col_cnt && t1.get_signature().size() == joined_col_cnt && @@ -1183,7 +1183,7 @@ namespace datalog { const relation_base& neg, unsigned joined_col_cnt, const unsigned *t_cols, const unsigned *negated_cols) { if (!check_kind(t) || !check_kind(neg)) - return 0; + return nullptr; return alloc(negation_filter_fn, get(t), get(neg), joined_col_cnt, t_cols, negated_cols); } @@ -1250,7 +1250,7 @@ namespace datalog { relation_transformer_fn * udoc_plugin::mk_filter_interpreted_and_project_fn( const relation_base & t, app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { - return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):0; + return check_kind(t)?alloc(filter_proj_fn, get(t), get_ast_manager(), condition, removed_col_cnt, removed_cols):nullptr; } diff --git a/src/muz/rel/udoc_relation.h b/src/muz/rel/udoc_relation.h index 87755f75e..01b2e8b43 100644 --- a/src/muz/rel/udoc_relation.h +++ b/src/muz/rel/udoc_relation.h @@ -63,7 +63,7 @@ namespace datalog { unsigned get_num_cols() const { return m_column_info.size()-1; } unsigned column_idx(unsigned col) const { return m_column_info[col]; } unsigned column_num_bits(unsigned col) const { return m_column_info[col+1] - m_column_info[col]; } - void expand_column_vector(unsigned_vector& v, const udoc_relation* other = 0) const; + void expand_column_vector(unsigned_vector& v, const udoc_relation* other = nullptr) const; void extract_guard(expr* condition, expr_ref& guard, expr_ref& rest) const; bool is_guard(expr* g) const; bool is_guard(unsigned n, expr* const *g) const; diff --git a/src/muz/spacer/spacer_antiunify.cpp b/src/muz/spacer/spacer_antiunify.cpp index 7dae59b6a..6baf9e93d 100644 --- a/src/muz/spacer/spacer_antiunify.cpp +++ b/src/muz/spacer/spacer_antiunify.cpp @@ -441,7 +441,7 @@ struct subs_rewriter_cfg : public default_rewriter_cfg { bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { result = m_c; - result_pr = 0; + result_pr = nullptr; return true; } }; diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 28ff7d787..ae67d3793 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -127,7 +127,7 @@ void pred_transformer::init_sig() std::stringstream name_stm; name_stm << m_head->get_name() << '_' << i; func_decl_ref stm(m); - stm = m.mk_func_decl(symbol(name_stm.str().c_str()), 0, (sort*const*)0, arg_sort); + stm = m.mk_func_decl(symbol(name_stm.str().c_str()), 0, (sort*const*)nullptr, arg_sort); m_sig.push_back(pm.get_o_pred(stm, 0)); } } @@ -153,7 +153,7 @@ bool pred_transformer::is_must_reachable(expr* state, model_ref* model) m_reach_ctx->push (); m_reach_ctx->assert_expr (state); m_reach_ctx->assert_expr (m.mk_not (m_reach_case_vars.back ())); - lbool res = m_reach_ctx->check_sat (0, NULL); + lbool res = m_reach_ctx->check_sat (0, nullptr); if (model) { m_reach_ctx->get_model(*model); } m_reach_ctx->pop (1); return (res == l_true); @@ -176,14 +176,14 @@ reach_fact* pred_transformer::get_used_reach_fact (model_evaluator_util& mev, } UNREACHABLE (); - return NULL; + return nullptr; } reach_fact *pred_transformer::get_used_origin_reach_fact (model_evaluator_util& mev, unsigned oidx) { expr_ref b(m), v(m); - reach_fact *res = NULL; + reach_fact *res = nullptr; for (unsigned i = 0, sz = m_reach_case_vars.size (); i < sz; i++) { pm.formula_n2o (m_reach_case_vars.get (i), v, oidx); @@ -219,7 +219,7 @@ datalog::rule const* pred_transformer::find_rule(model &model, // prefer a rule where the model intersects with reach facts of all predecessors; // also find how many predecessors' reach facts are true in the model expr_ref vl(m); - datalog::rule const* r = ((datalog::rule*)0); + datalog::rule const* r = ((datalog::rule*)nullptr); tag2rule::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); for (; it != end; ++it) { expr* tag = it->m_key; @@ -392,7 +392,7 @@ expr* pred_transformer::mk_fresh_reach_case_var () name << head ()->get_name () << "#reach_case_" << m_reach_case_vars.size (); decl = m.mk_func_decl (symbol (name.str ().c_str ()), 0, - (sort*const*)0, m.mk_bool_sort ()); + (sort*const*)nullptr, m.mk_bool_sort ()); m_reach_case_vars.push_back (m.mk_const (pm.get_n_pred (decl))); return m_reach_case_vars.back (); } @@ -495,7 +495,7 @@ expr_ref pred_transformer::get_reachable() expr* pred_transformer::get_last_reach_case_var () const { - return m_reach_case_vars.empty () ? NULL : m_reach_case_vars.back (); + return m_reach_case_vars.empty () ? nullptr : m_reach_case_vars.back (); } expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) @@ -557,7 +557,7 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, if (!must) { // use may summary summary.push_back (get_formulas (level, false)); // -- no auxiliary variables in lemmas - *aux = NULL; + *aux = nullptr; } else { // find must summary to use reach_fact *f = get_used_origin_reach_fact (mev, oidx); summary.push_back (f->get ()); @@ -613,12 +613,12 @@ bool pred_transformer::is_blocked (pob &n, unsigned &uses_level) { ensure_level (n.level ()); prop_solver::scoped_level _sl (m_solver, n.level ()); - m_solver.set_core (NULL); - m_solver.set_model (NULL); + m_solver.set_core (nullptr); + m_solver.set_model (nullptr); expr_ref_vector post(m), aux(m); post.push_back (n.post ()); - lbool res = m_solver.check_assumptions (post, aux, 0, NULL, 0); + lbool res = m_solver.check_assumptions (post, aux, 0, nullptr, 0); if (res == l_false) { uses_level = m_solver.uses_level(); } return res == l_false; } @@ -775,7 +775,7 @@ bool pred_transformer::is_invariant(unsigned level, expr* lemma, prop_solver::scoped_level _sl(m_solver, level); prop_solver::scoped_subset_core _sc (m_solver, true); m_solver.set_core(core); - m_solver.set_model(0); + m_solver.set_model(nullptr); expr * bg = m_extend_lit.get (); lbool r = m_solver.check_assumptions (conj, aux, 1, &bg, 1); if (r == l_false) { @@ -799,7 +799,7 @@ bool pred_transformer::check_inductive(unsigned level, expr_ref_vector& state, prop_solver::scoped_level _sl(m_solver, level); prop_solver::scoped_subset_core _sc (m_solver, true); m_solver.set_core(&core); - m_solver.set_model (0); + m_solver.set_model (nullptr); expr_ref_vector aux (m); conj.push_back (m_extend_lit); lbool res = m_solver.check_assumptions (state, aux, conj.size (), conj.c_ptr (), 1); @@ -1023,7 +1023,7 @@ void pred_transformer::ground_free_vars(expr* e, app_ref_vector& vars, fv(e); while (vars.size() < fv.size()) { - vars.push_back(0); + vars.push_back(nullptr); } for (unsigned i = 0; i < fv.size(); ++i) { if (fv[i] && !vars[i].get()) { @@ -1110,7 +1110,7 @@ lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : m_ref_count(0), m(manager), m_body(body, m), m_cube(m), m_bindings(m), m_lvl(lvl), - m_pob(0), m_new_pob(false) { + m_pob(nullptr), m_new_pob(false) { SASSERT(m_body); normalize(m_body, m_body); } @@ -1579,7 +1579,7 @@ void derivation::add_premise (pred_transformer &pt, pob *derivation::create_first_child (model_evaluator_util &mev) { - if (m_premises.empty()) { return NULL; } + if (m_premises.empty()) { return nullptr; } m_active = 0; return create_next_child(mev); } @@ -1602,7 +1602,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) vars.append (m_premises[m_active].get_ovars ()); ++m_active; } - if (m_active >= m_premises.size()) { return NULL; } + if (m_active >= m_premises.size()) { return nullptr; } // -- update m_trans with the pre-image of m_trans over the must summaries summaries.push_back (m_trans); @@ -1621,7 +1621,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) if (!mev.is_true (m_premises[m_active].get_summary())) { IF_VERBOSE(1, verbose_stream() << "Summary unexpectendly not true\n";); - return NULL; + return nullptr; } @@ -1670,7 +1670,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) pob *derivation::create_next_child () { - if (m_active + 1 >= m_premises.size()) { return NULL; } + if (m_active + 1 >= m_premises.size()) { return nullptr; } bool use_native_mbp = get_context ().use_native_mbp (); bool ground = get_context ().use_ground_cti (); @@ -1697,7 +1697,7 @@ pob *derivation::create_next_child () // if not true, bail out, the must summary of m_active is not strong enough // this is possible if m_post was weakened for some reason - if (!pt.is_must_reachable(pm.mk_and(summaries), &model)) { return NULL; } + if (!pt.is_must_reachable(pm.mk_and(summaries), &model)) { return nullptr; } model_evaluator_util mev (m); mev.set_model (*model); @@ -1848,12 +1848,12 @@ void pob::get_skolems(app_ref_vector &v) { pob* pob_queue::top () { /// nothing in the queue - if (m_obligations.empty()) { return NULL; } + if (m_obligations.empty()) { return nullptr; } /// top queue element is above max level - if (m_obligations.top()->level() > m_max_level) { return NULL; } + if (m_obligations.top()->level() > m_max_level) { return nullptr; } /// top queue element is at the max level, but at a higher than base depth if (m_obligations.top ()->level () == m_max_level && - m_obligations.top()->depth() > m_min_depth) { return NULL; } + m_obligations.top()->depth() > m_min_depth) { return nullptr; } /// there is something good in the queue return m_obligations.top ().get (); @@ -1882,10 +1882,10 @@ context::context(fixedpoint_params const& params, ast_manager& m) : m_params(params), m(m), - m_context(0), + m_context(nullptr), m_pm(params.pdr_max_num_contexts(), m), m_query_pred(m), - m_query(0), + m_query(nullptr), m_pob_queue(), m_last_result(l_undef), m_inductive_lvl(0), @@ -1914,7 +1914,7 @@ void context::reset() dealloc(it->m_value); } m_rels.reset(); - m_query = 0; + m_query = nullptr; m_last_result = l_undef; m_inductive_lvl = 0; } @@ -1985,7 +1985,7 @@ void context::update_rules(datalog::rule_set& rules) init_rules(rules, rels); decl2rel::iterator it = rels.begin(), end = rels.end(); for (; it != end; ++it) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (m_rels.find(it->m_key, pt)) { it->m_value->inherit_properties(*pt); } @@ -1999,7 +1999,7 @@ void context::update_rules(datalog::rule_set& rules) unsigned context::get_num_levels(func_decl* p) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (m_rels.find(p, pt)) { return pt->get_num_levels(); } else { @@ -2010,7 +2010,7 @@ unsigned context::get_num_levels(func_decl* p) expr_ref context::get_cover_delta(int level, func_decl* p_orig, func_decl* p) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (m_rels.find(p, pt)) { return pt->get_cover_delta(p_orig, level); } else { @@ -2021,7 +2021,7 @@ expr_ref context::get_cover_delta(int level, func_decl* p_orig, func_decl* p) void context::add_cover(int level, func_decl* p, expr* property) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (!m_rels.find(p, pt)) { pt = alloc(pred_transformer, *this, get_manager(), p); m_rels.insert(p, pt); @@ -2036,7 +2036,7 @@ void context::add_invariant (func_decl *p, expr *property) expr_ref context::get_reachable(func_decl *p) { - pred_transformer* pt = 0; + pred_transformer* pt = nullptr; if (!m_rels.find(p, pt)) { return expr_ref(m.mk_false(), m); } return pt->get_reachable(); @@ -2300,7 +2300,7 @@ unsigned context::get_cex_depth() // get current pt and fact pt = pts.get (curr); // check for depth marker - if (pt == NULL) { + if (pt == nullptr) { ++cex_depth; // insert new marker if there are pts at higher depth if (curr + 1 < pts.size()) { pts.push_back(NULL); } @@ -2635,7 +2635,7 @@ bool context::check_reachability () while (last_reachable) { checkpoint (); node = last_reachable; - last_reachable = NULL; + last_reachable = nullptr; if (m_pob_queue.is_root(*node)) { return true; } if (is_reachable (*node->parent())) { last_reachable = node->parent (); @@ -2751,14 +2751,14 @@ bool context::is_reachable(pob &n) // used in case n is reachable bool is_concrete; - const datalog::rule * r = NULL; + const datalog::rule * r = nullptr; // denotes which predecessor's (along r) reach facts are used vector reach_pred_used; unsigned num_reuse_reach = 0; unsigned saved = n.level (); n.m_level = infty_level (); - lbool res = n.pt().is_reachable(n, NULL, &model, + lbool res = n.pt().is_reachable(n, nullptr, &model, uses_level, is_concrete, r, reach_pred_used, num_reuse_reach); n.m_level = saved; @@ -2782,7 +2782,7 @@ bool context::is_reachable(pob &n) // if n has a derivation, create a new child and report l_undef // otherwise if n has no derivation or no new children, report l_true - pob *next = NULL; + pob *next = nullptr; scoped_ptr deriv; if (n.has_derivation()) {deriv = n.detach_derivation();} @@ -2854,7 +2854,7 @@ lbool context::expand_node(pob& n) // used in case n is reachable bool is_concrete; - const datalog::rule * r = NULL; + const datalog::rule * r = nullptr; // denotes which predecessor's (along r) reach facts are used vector reach_pred_used; unsigned num_reuse_reach = 0; @@ -2899,7 +2899,7 @@ lbool context::expand_node(pob& n) // if n has a derivation, create a new child and report l_undef // otherwise if n has no derivation or no new children, report l_true - pob *next = NULL; + pob *next = nullptr; scoped_ptr deriv; if (n.has_derivation()) {deriv = n.detach_derivation();} @@ -3264,7 +3264,7 @@ bool context::create_children(pob& n, datalog::rule const& r, pred_transformer &pt = get_pred_transformer (preds [j]); - const ptr_vector *aux = NULL; + const ptr_vector *aux = nullptr; expr_ref sum(m); // XXX This is a bit confusing. The summary is returned over // XXX o-variables. But it is simpler if it is returned over n-variables instead. @@ -3432,7 +3432,7 @@ void context::add_constraints (unsigned level, const expr_ref& c) expr *e1, *e2; if (m.is_implies(c, e1, e2)) { SASSERT (is_app (e1)); - pred_transformer *r = 0; + pred_transformer *r = nullptr; if (m_rels.find (to_app (e1)->get_decl (), r)) { r->add_lemma(e2, level); } } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 898c1639e..a95b1bdb9 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -323,7 +323,7 @@ public: { for (unsigned i = 0, sz = m_reach_facts.size (); i < sz; ++i) if(v == m_reach_facts [i]->get()) { return m_reach_facts[i]; } - return NULL; + return nullptr; } void add_rule(datalog::rule* r) { m_rules.push_back(r); } @@ -348,7 +348,7 @@ public: void collect_statistics(statistics& st) const; void reset_statistics(); - bool is_must_reachable (expr* state, model_ref* model = 0); + bool is_must_reachable (expr* state, model_ref* model = nullptr); /// \brief Returns reachability fact active in the given model /// all determines whether initial reachability facts are included as well reach_fact *get_used_reach_fact (model_evaluator_util& mev, bool all = true); @@ -397,7 +397,7 @@ public: vector& reach_pred_used, unsigned& num_reuse_reach); bool is_invariant(unsigned level, expr* lemma, - unsigned& solver_level, expr_ref_vector* core = 0); + unsigned& solver_level, expr_ref_vector* core = nullptr); bool check_inductive(unsigned level, expr_ref_vector& state, unsigned& assumes_level); @@ -475,7 +475,7 @@ public: void set_derivation (derivation *d) {m_derivation = d;} bool has_derivation () const {return (bool)m_derivation;} derivation &get_derivation() const {return *m_derivation.get ();} - void reset_derivation () {set_derivation (NULL);} + void reset_derivation () {set_derivation (nullptr);} /// detaches derivation from the node without deallocating derivation* detach_derivation () {return m_derivation.detach ();} @@ -503,7 +503,7 @@ public: /// clean a dirty node void clean(); - void reset () {clean (); m_derivation = NULL; m_open = true;} + void reset () {clean (); m_derivation = nullptr; m_open = true;} bool is_closed () const { return !m_open; } void close(); @@ -563,7 +563,7 @@ class derivation { public: premise (pred_transformer &pt, unsigned oidx, expr *summary, bool must, - const ptr_vector *aux_vars = NULL); + const ptr_vector *aux_vars = nullptr); premise (const premise &p); bool is_must () {return m_must;} @@ -575,7 +575,7 @@ class derivation { /// \brief Updated the summary. /// The new summary is over n-variables. void set_summary (expr * summary, bool must, - const ptr_vector *aux_vars = NULL); + const ptr_vector *aux_vars = nullptr); }; @@ -600,7 +600,7 @@ public: derivation (pob& parent, datalog::rule const& rule, expr *trans, app_ref_vector const &evars); void add_premise (pred_transformer &pt, unsigned oidx, - expr * summary, bool must, const ptr_vector *aux_vars = NULL); + expr * summary, bool must, const ptr_vector *aux_vars = nullptr); /// creates the first child. Must be called after all the premises /// are added. The model must be valid for the premises @@ -628,7 +628,7 @@ class pob_queue { pob_ref_gt> m_obligations; public: - pob_queue(): m_root(NULL), m_max_level(0), m_min_depth(0) {} + pob_queue(): m_root(nullptr), m_max_level(0), m_min_depth(0) {} ~pob_queue(); void reset(); diff --git a/src/muz/spacer/spacer_dl_interface.cpp b/src/muz/spacer/spacer_dl_interface.cpp index 78776e074..52209454d 100644 --- a/src/muz/spacer/spacer_dl_interface.cpp +++ b/src/muz/spacer/spacer_dl_interface.cpp @@ -42,7 +42,7 @@ dl_interface::dl_interface(datalog::context& ctx) : m_ctx(ctx), m_spacer_rules(ctx), m_old_rules(ctx), - m_context(0), + m_context(nullptr), m_refs(ctx.get_manager()) { m_context = alloc(spacer::context, ctx.get_params(), ctx.get_manager()); diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 94c419493..19989e440 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -161,7 +161,7 @@ class collect_array_proc { sort *m_sort; public: collect_array_proc(ast_manager &m, func_decl_set& s) : - m_au(m), m_symbs(s), m_sort(NULL) {} + m_au(m), m_symbs(s), m_sort(nullptr) {} void operator()(app* a) { diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index bcf6b07ae..7ca66fbfd 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -146,7 +146,7 @@ app* itp_solver::def_manager::mk_proxy (expr *v) bool itp_solver::def_manager::is_proxy (app *k, app_ref &def) { - app *r = NULL; + app *r = nullptr; bool found = m_proxy2def.find (k, r); def = r; return found; diff --git a/src/muz/spacer/spacer_legacy_mev.cpp b/src/muz/spacer/spacer_legacy_mev.cpp index 16e2cc734..fc3eabc56 100644 --- a/src/muz/spacer/spacer_legacy_mev.cpp +++ b/src/muz/spacer/spacer_legacy_mev.cpp @@ -80,7 +80,7 @@ void model_evaluator::reset() m_visited.reset(); m_numbers.reset(); m_refs.reset(); - m_model = 0; + m_model = nullptr; } diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 19c5c3aa3..059374e39 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -43,10 +43,10 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m(pm.get_manager()), m_pm(pm), m_name(name), - m_ctx(NULL), + m_ctx(nullptr), m_pos_level_atoms(m), m_neg_level_atoms(m), - m_core(0), + m_core(nullptr), m_subset_based_core(false), m_uses_level(infty_level()), m_delta_level(false), @@ -72,7 +72,7 @@ void prop_solver::add_level() unsigned idx = level_cnt(); std::stringstream name; name << m_name << "#level_" << idx; - func_decl * lev_pred = m.mk_fresh_func_decl(name.str().c_str(), 0, 0, m.mk_bool_sort()); + func_decl * lev_pred = m.mk_fresh_func_decl(name.str().c_str(), 0, nullptr, m.mk_bool_sort()); m_level_preds.push_back(lev_pred); app_ref pos_la(m.mk_const(lev_pred), m); @@ -196,7 +196,7 @@ lbool prop_solver::internal_check_assumptions( // XXX Turn model generation if m_model != 0 SASSERT(m_ctx); SASSERT(m_ctx_fparams); - flet _model(m_ctx_fparams->m_model, m_model != 0); + flet _model(m_ctx_fparams->m_model, m_model != nullptr); if (m_in_level) { assert_level_atoms(m_current_level); } lbool result = maxsmt(hard_atoms, soft_atoms); @@ -280,8 +280,8 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, SASSERT(soft_sz >= soft.size()); // -- reset all parameters - m_core = 0; - m_model = 0; + m_core = nullptr; + m_model = nullptr; m_subset_based_core = false; return res; } diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index 1ddec91c6..0cbcecfbf 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -97,7 +97,7 @@ public: lbool check_assumptions(const expr_ref_vector & hard, expr_ref_vector & soft, unsigned num_bg = 0, - expr * const *bg = NULL, + expr * const *bg = nullptr, unsigned solver_id = 0); void collect_statistics(statistics& st) const; diff --git a/src/muz/spacer/spacer_qe_project.cpp b/src/muz/spacer/spacer_qe_project.cpp index cde188aac..753bb43b8 100644 --- a/src/muz/spacer/spacer_qe_project.cpp +++ b/src/muz/spacer/spacer_qe_project.cpp @@ -595,7 +595,7 @@ namespace qe { // c*x + t = 0 <=> x = -t/c expr_ref eq_term (mk_mul (-(rational::one ()/m_coeffs[eq_idx]), m_terms.get (eq_idx)), m); m_rw (eq_term); - map.insert (m_var->x (), eq_term, 0); + map.insert (m_var->x (), eq_term, nullptr); TRACE ("qe", tout << "Using equality term: " << mk_pp (eq_term, m) << "\n"; ); @@ -680,7 +680,7 @@ namespace qe { } else { new_lit = m.mk_true (); } - map.insert (m_lits.get (i), new_lit, 0); + map.insert (m_lits.get (i), new_lit, nullptr); TRACE ("qe", tout << "Old literal: " << mk_pp (m_lits.get (i), m) << "\n"; tout << "New literal: " << mk_pp (new_lit, m) << "\n"; @@ -722,7 +722,7 @@ namespace qe { } else { new_lit = m.mk_true (); } - map.insert (m_lits.get (i), new_lit, 0); + map.insert (m_lits.get (i), new_lit, nullptr); TRACE ("qe", tout << "Old literal: " << mk_pp (m_lits.get (i), m) << "\n"; tout << "New literal: " << mk_pp (new_lit, m) << "\n"; @@ -932,7 +932,7 @@ namespace qe { if (!all_done) continue; // all args so far have been processed // get the correct arg to use - proof* pr = 0; expr* new_arg = 0; + proof* pr = nullptr; expr* new_arg = nullptr; factored_terms.get (old_arg, new_arg, pr); if (new_arg) { // changed @@ -965,7 +965,7 @@ namespace qe { mdl.register_decl (new_var->get_decl (), val); } if (changed) { - factored_terms.insert (e, new_term, 0); + factored_terms.insert (e, new_term, nullptr); } done.mark (e, true); todo.pop_back (); @@ -973,7 +973,7 @@ namespace qe { } // mk new fml - proof* pr = 0; expr* new_fml = 0; + proof* pr = nullptr; expr* new_fml = nullptr; factored_terms.get (fml, new_fml, pr); if (new_fml) { fml = new_fml; @@ -994,9 +994,9 @@ namespace qe { * the divisibility atom is a special mod term ((t1-t2) % num == 0) */ void mod2div (expr_ref& fml, expr_map& map) { - expr* new_fml = 0; + expr* new_fml = nullptr; - proof *pr = 0; + proof *pr = nullptr; map.get (fml, new_fml, pr); if (new_fml) { fml = new_fml; @@ -1065,7 +1065,7 @@ namespace qe { new_fml = m.mk_app (a->get_decl (), children.size (), children.c_ptr ()); } - map.insert (fml, new_fml, 0); + map.insert (fml, new_fml, nullptr); fml = new_fml; } @@ -1133,7 +1133,7 @@ namespace qe { z); } } - map.insert (m_lits.get (i), new_lit, 0); + map.insert (m_lits.get (i), new_lit, nullptr); TRACE ("qe", tout << "Old literal: " << mk_pp (m_lits.get (i), m) << "\n"; tout << "New literal: " << mk_pp (new_lit, m) << "\n"; @@ -1145,7 +1145,7 @@ namespace qe { expr_substitution sub (m); // literals for (unsigned i = 0; i < lits.size (); i++) { - expr* new_lit = 0; proof* pr = 0; + expr* new_lit = nullptr; proof* pr = nullptr; app* old_lit = lits.get (i); map.get (old_lit, new_lit, pr); if (new_lit) { @@ -1157,7 +1157,7 @@ namespace qe { } } // substitute for x, if any - expr* x_term = 0; proof* pr = 0; + expr* x_term = nullptr; proof* pr = nullptr; map.get (m_var->x (), x_term, pr); if (x_term) { sub.insert (m_var->x (), x_term); @@ -1292,9 +1292,9 @@ namespace qe { model_evaluator_array_util m_mev; void reset_v () { - m_v = 0; + m_v = nullptr; m_has_stores_v.reset (); - m_subst_term_v = 0; + m_subst_term_v = nullptr; m_true_sub_v.reset (); m_false_sub_v.reset (); m_aux_lits_v.reset (); @@ -1302,7 +1302,7 @@ namespace qe { } void reset () { - M = 0; + M = nullptr; reset_v (); m_aux_vars.reset (); } @@ -1393,7 +1393,7 @@ namespace qe { todo.push_back (to_app (arg)); } else if (all_done) { // all done so far.. - expr* arg_new = 0; proof* pr; + expr* arg_new = nullptr; proof* pr; sel_cache.get (arg, arg_new, pr); if (!arg_new) { arg_new = arg; @@ -1423,12 +1423,12 @@ namespace qe { } if (a != a_new) { - sel_cache.insert (a, a_new, 0); + sel_cache.insert (a, a_new, nullptr); pinned.push_back (a_new); } done.mark (a, true); } - expr* res = 0; proof* pr; + expr* res = nullptr; proof* pr; sel_cache.get (fml, res, pr); if (res) { fml = to_app (res); @@ -1478,7 +1478,7 @@ namespace qe { void find_subst_term (app* eq) { app_ref p_exp (m); - mk_peq (eq->get_arg (0), eq->get_arg (1), 0, 0, p_exp); + mk_peq (eq->get_arg (0), eq->get_arg (1), 0, nullptr, p_exp); bool subst_eq_found = false; while (true) { TRACE ("qe", @@ -1672,7 +1672,7 @@ namespace qe { expr* rhs = eq->get_arg (1); bool lhs_has_v = (lhs == m_v || m_has_stores_v.is_marked (lhs)); bool rhs_has_v = (rhs == m_v || m_has_stores_v.is_marked (rhs)); - app* store = 0; + app* store = nullptr; SASSERT (lhs_has_v || rhs_has_v); @@ -1829,7 +1829,7 @@ namespace qe { m_cache.reset (); m_pinned.reset (); m_idx_lits.reset (); - M = 0; + M = nullptr; m_arr_test.reset (); m_has_stores.reset (); m_reduce_all_selects = false; @@ -1864,7 +1864,7 @@ namespace qe { bool reduce (expr_ref& e) { if (!is_app (e)) return true; - expr *r = 0; + expr *r = nullptr; if (m_cache.find (e, r)) { e = r; return true; @@ -1882,7 +1882,7 @@ namespace qe { for (unsigned i = 0; i < a->get_num_args (); ++i) { expr *arg = a->get_arg (i); - expr *narg = 0; + expr *narg = nullptr; if (!is_app (arg)) args.push_back (arg); else if (m_cache.find (arg, narg)) { @@ -2025,7 +2025,7 @@ namespace qe { m_idx_vals.reset (); m_sel_consts.reset (); m_idx_lits.reset (); - M = 0; + M = nullptr; m_sub.reset (); m_arr_test.reset (); } diff --git a/src/muz/spacer/spacer_smt_context_manager.cpp b/src/muz/spacer/spacer_smt_context_manager.cpp index e6ab2c883..e26381afd 100644 --- a/src/muz/spacer/spacer_smt_context_manager.cpp +++ b/src/muz/spacer/spacer_smt_context_manager.cpp @@ -50,7 +50,7 @@ smt_context_manager::~smt_context_manager() virtual_solver* smt_context_manager::mk_fresh() { ++m_num_contexts; - virtual_solver_factory *solver_factory = 0; + virtual_solver_factory *solver_factory = nullptr; if (m_max_num_contexts == 0 || m_solvers.size() < m_max_num_contexts) { m_solvers.push_back(alloc(spacer::virtual_solver_factory, m, m_fparams)); diff --git a/src/muz/spacer/spacer_sym_mux.h b/src/muz/spacer/spacer_sym_mux.h index 892542557..a4d10971a 100644 --- a/src/muz/spacer/spacer_sym_mux.h +++ b/src/muz/spacer/spacer_sym_mux.h @@ -126,7 +126,7 @@ public: { func_decl * res; if(!m_prefix2prim.find(prefix, res)) { - return 0; + return nullptr; } return res; } @@ -138,7 +138,7 @@ public: { func_decl * prim = try_get_primary_by_prefix(prefix); if(!prim) { - return 0; + return nullptr; } return conv(prim, 0, idx); } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index af9230713..a1a937de0 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -506,7 +506,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vectorcheck_sat(0,0); + lbool res = s->check_sat(0,nullptr); // if sat extract model and add corresponding linear combinations to core if (res == lbool::l_true) { diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 83042cd6d..cdec5d7eb 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -72,17 +72,17 @@ namespace spacer { // model_evaluator_util::model_evaluator_util(ast_manager& m) : - m(m), m_mev(nullptr) { - reset (nullptr); + m(m), m_mev(nullptr) { + reset (nullptr); } - model_evaluator_util::~model_evaluator_util() {reset (NULL);} + model_evaluator_util::~model_evaluator_util() {reset (nullptr);} void model_evaluator_util::reset(model* model) { if (m_mev) { dealloc(m_mev); - m_mev = NULL; + m_mev = nullptr; } m_model = model; if (!m_model) { return; } diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index 7fb17329e..7be2ee4b3 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -162,7 +162,7 @@ void find_decls (expr* fml, app_ref_vector& decls, std::string& prefix); struct mk_epp : public mk_pp { params_ref m_epp_params; expr_ref m_epp_expr; - mk_epp(ast *t, ast_manager &m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = 0); + mk_epp(ast *t, ast_manager &m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = nullptr); void rw(expr *e, expr_ref &out); }; diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 938e8cb94..562fc1ee0 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -257,14 +257,14 @@ void virtual_solver::get_labels(svector &r) { r.reset(); buffer tmp; - m_context.get_relevant_labels(0, tmp); + m_context.get_relevant_labels(nullptr, tmp); r.append(tmp.size(), tmp.c_ptr()); } solver* virtual_solver::translate(ast_manager& m, params_ref const& p) { UNREACHABLE(); - return 0; + return nullptr; } void virtual_solver::updt_params(params_ref const &p) { m_factory.updt_params(p); } diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index 8809c0dc7..da5a96e2c 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -1129,7 +1129,7 @@ namespace tb { } else { change = true; - m_rename.push_back(0); + m_rename.push_back(nullptr); } } if (change) { diff --git a/src/muz/transforms/dl_mk_array_blast.cpp b/src/muz/transforms/dl_mk_array_blast.cpp index 8fe3f0e43..6894cf4fa 100644 --- a/src/muz/transforms/dl_mk_array_blast.cpp +++ b/src/muz/transforms/dl_mk_array_blast.cpp @@ -176,7 +176,7 @@ namespace datalog { if (m_defs.find(e1, v)) { cache.insert(e, v); } - else if (!insert_def(r, e1, 0)) { + else if (!insert_def(r, e1, nullptr)) { return false; } else { @@ -320,7 +320,7 @@ namespace datalog { rule_set * mk_array_blast::operator()(rule_set const & source) { if (!m_ctx.array_blast ()) { - return 0; + return nullptr; } rule_set* rules = alloc(rule_set, m_ctx); rules->inherit_predicates(source); @@ -331,7 +331,7 @@ namespace datalog { } if (!change) { dealloc(rules); - rules = 0; + rules = nullptr; } return rules; } diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 8637af14f..a9461c1e3 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -138,8 +138,8 @@ namespace datalog { m_g_vars(m), m_old_funcs(m), m_new_funcs(m), - m_src(0), - m_dst(0) + m_src(nullptr), + m_dst(nullptr) {} ~expand_mkbv_cfg() {} @@ -186,7 +186,7 @@ namespace datalog { m_g_vars.push_back(m_f_vars.back()); } } - func_decl* g = 0; + func_decl* g = nullptr; if (!m_pred2blast.find(f, g)) { @@ -202,7 +202,7 @@ namespace datalog { m_dst->inherit_predicate(*m_src, f, g); } result = m.mk_app(g, m_args.size(), m_args.c_ptr()); - result_pr = 0; + result_pr = nullptr; return BR_DONE; } }; @@ -262,7 +262,7 @@ namespace datalog { rule_set * operator()(rule_set const & source) { // TODO pc if (!m_context.xform_bit_blast()) { - return 0; + return nullptr; } rule_manager& rm = m_context.get_rule_manager(); unsigned sz = source.get_num_rules(); diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 2ca64aa68..53722a22c 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -45,7 +45,7 @@ namespace datalog { for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) { func_decl* decl_i = r->get_decl(i); if (m_context.has_facts(decl_i)) { - return 0; + return nullptr; } bool reachable = engine.get_fact(decl_i).is_reachable(); @@ -93,7 +93,7 @@ namespace datalog { } if (res->get_num_rules() == source.get_num_rules()) { TRACE("dl", tout << "No transformation\n";); - res = 0; + res = nullptr; } else { res->close(); @@ -134,7 +134,7 @@ namespace datalog { if (res->get_num_rules() == source.get_num_rules()) { TRACE("dl", tout << "No transformation\n";); - res = 0; + res = nullptr; } if (res && m_context.get_model_converter()) { extension_model_converter* mc0 = alloc(extension_model_converter, m); diff --git a/src/muz/transforms/dl_mk_filter_rules.cpp b/src/muz/transforms/dl_mk_filter_rules.cpp index a8c13fc17..b5dfb84ec 100644 --- a/src/muz/transforms/dl_mk_filter_rules.cpp +++ b/src/muz/transforms/dl_mk_filter_rules.cpp @@ -29,7 +29,7 @@ namespace datalog { m_context(ctx), m(ctx.get_manager()), rm(ctx.get_rule_manager()), - m_result(0), + m_result(nullptr), m_pinned(m) { } @@ -89,7 +89,7 @@ namespace datalog { app_ref filter_head(m); filter_head = m.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr()); app * filter_tail = key->new_pred; - rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0); + rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)nullptr); filter_rule->set_accounting_parent_object(m_context, m_current); m_result->add_rule(filter_rule); m_context.get_rule_manager().mk_rule_asserted_proof(*filter_rule); @@ -161,7 +161,7 @@ namespace datalog { } if(!m_modified) { dealloc(m_result); - return static_cast(0); + return static_cast(nullptr); } m_result->inherit_predicates(source); return m_result; diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp index 8421a99ba..38000c65a 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp @@ -222,20 +222,20 @@ namespace datalog { */ app * detect_equivalence(const arg_pair& p1, const arg_pair& p2, bool inside_disjunction) { - if (m.is_not(p1.first)==m.is_not(p2.first)) { return 0; } - if (m.is_not(p1.second)==m.is_not(p2.second)) { return 0; } + if (m.is_not(p1.first)==m.is_not(p2.first)) { return nullptr; } + if (m.is_not(p1.second)==m.is_not(p2.second)) { return nullptr; } - expr * first_bare = 0; - if (m.is_not(p1.first, first_bare) && p2.first!=first_bare) { return 0; } - if (m.is_not(p2.first, first_bare) && p1.first!=first_bare) { return 0; } + expr * first_bare = nullptr; + if (m.is_not(p1.first, first_bare) && p2.first!=first_bare) { return nullptr; } + if (m.is_not(p2.first, first_bare) && p1.first!=first_bare) { return nullptr; } SASSERT(first_bare); - expr * second_bare = 0; - if (m.is_not(p1.second, second_bare) && p2.second!=second_bare) { return 0; } - if (m.is_not(p2.second, second_bare) && p1.second!=second_bare) { return 0; } + expr * second_bare = nullptr; + if (m.is_not(p1.second, second_bare) && p2.second!=second_bare) { return nullptr; } + if (m.is_not(p2.second, second_bare) && p1.second!=second_bare) { return nullptr; } SASSERT(second_bare); - if (!m.is_bool(first_bare) || !m.is_bool(second_bare)) { return 0; } + if (!m.is_bool(first_bare) || !m.is_bool(second_bare)) { return nullptr; } //both negations are in the same pair bool negs_together = m.is_not(p1.first)==m.is_not(p1.second); @@ -261,7 +261,7 @@ namespace datalog { arg_pair new_ap; if (match_arg_pair(e, new_ap, inside_disjunction)) { - app * neq = 0; + app * neq = nullptr; if (have_pair) { neq = detect_equivalence(ap, new_ap, inside_disjunction); } @@ -601,7 +601,7 @@ namespace datalog { rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source) { if (source.get_num_rules() == 0) { - return 0; + return nullptr; } rule_set * res = alloc(rule_set, m_context); @@ -612,7 +612,7 @@ namespace datalog { res->display(tout);); } else { dealloc(res); - res = 0; + res = nullptr; } return res; } diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.h b/src/muz/transforms/dl_mk_interp_tail_simplifier.h index e9120b9b1..713827588 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.h +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.h @@ -44,7 +44,7 @@ namespace datalog { void apply(app * a, app_ref& res); public: rule_substitution(context & ctx) - : m(ctx.get_manager()), m_context(ctx), m_subst(m), m_unif(m), m_head(m), m_tail(m), m_rule(0) {} + : m(ctx.get_manager()), m_context(ctx), m_subst(m), m_unif(m), m_head(m), m_tail(m), m_rule(nullptr) {} /** Reset substitution and get it ready for working with rule r. diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 5dafafb19..a17aecd15 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -191,13 +191,13 @@ namespace datalog { rule_set * mk_karr_invariants::operator()(rule_set const & source) { if (!m_ctx.karr()) { - return 0; + return nullptr; } rule_set::iterator it = source.begin(), end = source.end(); for (; it != end; ++it) { rule const& r = **it; if (r.has_negation()) { - return 0; + return nullptr; } } mk_loop_counter lc(m_ctx); @@ -209,7 +209,7 @@ namespace datalog { get_invariants(*src_loop); if (m.canceled()) { - return 0; + return nullptr; } // figure out whether to update same rules as used for saturation. @@ -248,7 +248,7 @@ namespace datalog { func_decl* p = dit->m_key; expr_ref fml = rctx.try_get_formula(p); if (fml && !m.is_true(fml)) { - expr* inv = 0; + expr* inv = nullptr; if (m_fun2inv.find(p, inv)) { fml = m.mk_and(inv, fml); } @@ -270,7 +270,7 @@ namespace datalog { rule_set::decl2rules::iterator gend = src.end_grouped_rules(); for (; git != gend; ++git) { func_decl* p = git->m_key; - expr* fml = 0; + expr* fml = nullptr; if (m_fun2inv.find(p, fml)) { kmc->add(p, fml); } @@ -292,7 +292,7 @@ namespace datalog { } for (unsigned i = 0; i < utsz; ++i) { func_decl* q = r.get_decl(i); - expr* fml = 0; + expr* fml = nullptr; if (m_fun2inv.find(q, fml)) { expr_safe_replace rep(m); for (unsigned j = 0; j < q->get_arity(); ++j) { @@ -306,7 +306,7 @@ namespace datalog { } rule* new_rule = &r; if (tail.size() != tsz) { - new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); + new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), nullptr, r.name()); } rules.add_rule(new_rule); rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. diff --git a/src/muz/transforms/dl_mk_loop_counter.cpp b/src/muz/transforms/dl_mk_loop_counter.cpp index 62568640c..1aea7be45 100644 --- a/src/muz/transforms/dl_mk_loop_counter.cpp +++ b/src/muz/transforms/dl_mk_loop_counter.cpp @@ -56,7 +56,7 @@ namespace datalog { app_ref mk_loop_counter::del_arg(app* fn) { expr_ref_vector args(m); - func_decl* old_fn = 0, *new_fn = fn->get_decl(); + func_decl* old_fn = nullptr, *new_fn = fn->get_decl(); SASSERT(fn->get_num_args() > 0); args.append(fn->get_num_args()-1, fn->get_args()); VERIFY (m_new2old.find(new_fn, old_fn)); diff --git a/src/muz/transforms/dl_mk_magic_sets.cpp b/src/muz/transforms/dl_mk_magic_sets.cpp index 15a4c1093..0de37a4ce 100644 --- a/src/muz/transforms/dl_mk_magic_sets.cpp +++ b/src/muz/transforms/dl_mk_magic_sets.cpp @@ -129,9 +129,9 @@ namespace datalog { SASSERT(m.is_bool(old_pred->get_range())); adornment_desc adn(old_pred); adn.m_adornment.populate(lit, bound_vars); - adornment_map::entry * e = m_adorned_preds.insert_if_not_there2(adn, 0); + adornment_map::entry * e = m_adorned_preds.insert_if_not_there2(adn, nullptr); func_decl * new_pred = e->get_data().m_value; - if (new_pred==0) { + if (new_pred==nullptr) { std::string suffix = "ad_"+adn.m_adornment.to_string(); new_pred = m_context.mk_fresh_head_predicate( old_pred->get_name(), symbol(suffix.c_str()), @@ -163,7 +163,7 @@ namespace datalog { pred2pred::obj_map_entry * e = m_magic_preds.insert_if_not_there2(l_pred, 0); func_decl * mag_pred = e->get_data().m_value; - if (mag_pred==0) { + if (mag_pred==nullptr) { unsigned mag_arity = bound_args.size(); ptr_vector mag_domain; @@ -264,7 +264,7 @@ namespace datalog { } - func_decl * new_head_pred = 0; + func_decl * new_head_pred = nullptr; VERIFY( m_adorned_preds.find(adornment_desc(head->get_decl(), head_adornment), new_head_pred) ); app * new_head = m.mk_app(new_head_pred, head->get_args()); @@ -301,14 +301,14 @@ namespace datalog { app * tail[] = {lit, mag_lit}; - rule * r = m_context.get_rule_manager().mk(adn_lit, 2, tail, 0); + rule * r = m_context.get_rule_manager().mk(adn_lit, 2, tail, nullptr); result.add_rule(r); } rule_set * mk_magic_sets::operator()(rule_set const & source) { if (!m_context.magic_sets_for_queries()) { - return 0; + return nullptr; } SASSERT(source.contains(m_goal)); SASSERT(source.get_predicate_rules(m_goal).size() == 1); @@ -372,10 +372,10 @@ namespace datalog { app * adn_goal_head = adorn_literal(goal_head, empty_var_idx_set); app * mag_goal_head = create_magic_literal(adn_goal_head); SASSERT(mag_goal_head->is_ground()); - rule * mag_goal_rule = m_context.get_rule_manager().mk(mag_goal_head, 0, 0, 0); + rule * mag_goal_rule = m_context.get_rule_manager().mk(mag_goal_head, 0, nullptr, nullptr); result->add_rule(mag_goal_rule); - rule * back_to_goal_rule = m_context.get_rule_manager().mk(goal_head, 1, &adn_goal_head, 0); + rule * back_to_goal_rule = m_context.get_rule_manager().mk(goal_head, 1, &adn_goal_head, nullptr); result->add_rule(back_to_goal_rule); return result; } diff --git a/src/muz/transforms/dl_mk_magic_symbolic.cpp b/src/muz/transforms/dl_mk_magic_symbolic.cpp index 2edc57375..0e2e4991a 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.cpp +++ b/src/muz/transforms/dl_mk_magic_symbolic.cpp @@ -68,7 +68,7 @@ namespace datalog { rule_set * mk_magic_symbolic::operator()(rule_set const & source) { if (!m_ctx.magic()) { - return 0; + return nullptr; } context& ctx = source.get_context(); rule_manager& rm = source.get_rule_manager(); @@ -98,7 +98,7 @@ namespace datalog { result->add_rule(new_rule); if (source.is_output_predicate(r.get_decl())) { result->set_output_predicate(new_rule->get_decl()); - new_rule = rm.mk(mk_query(r.get_head()), 0, 0, 0, r.name(), true); + new_rule = rm.mk(mk_query(r.get_head()), 0, nullptr, nullptr, r.name(), true); result->add_rule(new_rule); } diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index a4a5ac35f..744efdb93 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -143,7 +143,7 @@ namespace datalog { m_ctx(ctx), a(m), m_refs(m), - m_mc(NULL){ + m_mc(nullptr) { } mk_quantifier_abstraction::~mk_quantifier_abstraction() { @@ -153,7 +153,7 @@ namespace datalog { if (rules.is_output_predicate(old_p)) { dst.inherit_predicate(rules, old_p, old_p); - return 0; + return nullptr; } unsigned sz = old_p->get_arity(); @@ -164,10 +164,10 @@ namespace datalog { } } if (num_arrays == 0) { - return 0; + return nullptr; } - func_decl* new_p = 0; + func_decl* new_p = nullptr; if (!m_old2new.find(old_p, new_p)) { expr_ref_vector sub(m), vars(m); svector bound; @@ -281,7 +281,7 @@ namespace datalog { } args.push_back(arg); } - expr* pat = 0; + expr* pat = nullptr; expr_ref pattern(m); pattern = m.mk_pattern(pats.size(), pats.c_ptr()); pat = pattern.get(); @@ -301,13 +301,13 @@ namespace datalog { rule_set * mk_quantifier_abstraction::operator()(rule_set const & source) { if (!m_ctx.quantify_arrays()) { - return 0; + return nullptr; } unsigned sz = source.get_num_rules(); for (unsigned i = 0; i < sz; ++i) { rule& r = *source.get_rule(i); if (r.has_negation()) { - return 0; + return nullptr; } } @@ -351,12 +351,12 @@ namespace datalog { if (m_old2new.empty()) { dealloc(result); dealloc(m_mc); - result = 0; + result = nullptr; } else { m_ctx.add_model_converter(m_mc); } - m_mc = 0; + m_mc = nullptr; return result; } diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 8986bf506..4cbcc5712 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -139,7 +139,7 @@ namespace datalog { return; } expr* arg = pat->get_arg(i); - ptr_vector* terms = 0; + ptr_vector* terms = nullptr; if (m_funs.find(to_app(arg)->get_decl(), terms)) { for (unsigned k = 0; k < terms->size(); ++k) { @@ -185,7 +185,7 @@ namespace datalog { } if (is_app(e)) { app* ap = to_app(e); - ptr_vector* terms = 0; + ptr_vector* terms = nullptr; if (!m_funs.find(ap->get_decl(), terms)) { terms = alloc(ptr_vector); m_funs.insert(ap->get_decl(), terms); @@ -250,7 +250,7 @@ namespace datalog { rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) { if (!m_ctx.instantiate_quantifiers()) { - return 0; + return nullptr; } bool has_quantifiers = false; unsigned sz = source.get_num_rules(); @@ -259,11 +259,11 @@ namespace datalog { rule& r = *source.get_rule(i); has_quantifiers = has_quantifiers || rm.has_quantifiers(r); if (r.has_negation()) { - return 0; + return nullptr; } } if (!has_quantifiers) { - return 0; + return nullptr; } expr_ref_vector conjs(m); @@ -291,7 +291,7 @@ namespace datalog { } else { dealloc(result); - result = 0; + result = nullptr; } return result; } diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index f1a4eb32b..a9d2c7090 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -549,16 +549,16 @@ namespace datalog { const rule_vector& pred_rules = rules.get_predicate_rules(pred); - rule * inlining_candidate = 0; + rule * inlining_candidate = nullptr; unsigned rule_cnt = pred_rules.size(); if (rule_cnt == 0) { - inlining_candidate = 0; + inlining_candidate = nullptr; } else if (rule_cnt == 1) { inlining_candidate = pred_rules[0]; } else { - inlining_candidate = 0; + inlining_candidate = nullptr; for (unsigned ri = 0; ri < rule_cnt; ++ri) { rule * pred_rule = pred_rules[ri]; @@ -566,7 +566,7 @@ namespace datalog { //we skip rules which don't unify with the tail atom continue; } - if (inlining_candidate != 0) { + if (inlining_candidate != nullptr) { // We have two rules that can be inlined into the current // tail predicate. In this situation we don't do inlinning // on this tail atom, as we don't want the overall number @@ -576,10 +576,10 @@ namespace datalog { inlining_candidate = pred_rule; } } - if (inlining_candidate == 0) { + if (inlining_candidate == nullptr) { // nothing unifies with the tail atom, therefore the rule is unsatisfiable // (we can say this because relation pred doesn't have any ground facts either) - res = 0; + res = nullptr; datalog::del_rule(m_mc, *r, false); return true; } @@ -591,7 +591,7 @@ namespace datalog { } if (!try_to_inline_rule(*r, *inlining_candidate, ti, res)) { datalog::del_rule(m_mc, *r, false); - res = 0; + res = nullptr; } return true; @@ -852,13 +852,13 @@ namespace datalog { ref hsmc; if (source.get_num_rules() == 0) { - return 0; + return nullptr; } rule_set::iterator end = source.end(); for (rule_set::iterator it = source.begin(); it != end; ++ it) { if (has_quantifier(**it)) { - return 0; + return nullptr; } } @@ -893,7 +893,7 @@ namespace datalog { } if (!something_done) { - res = 0; + res = nullptr; } else { m_context.add_model_converter(hsmc.get()); diff --git a/src/muz/transforms/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h index 7b00d26ad..27b6dd418 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -186,7 +186,7 @@ namespace datalog { m_simp(m_context.get_rewriter()), m_pinned(m_rm), m_inlined_rules(m_context), - m_mc(0), + m_mc(nullptr), m_unifier(ctx), m_head_index(m), m_tail_index(m), diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index abc5d20e7..49a8ff423 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -97,7 +97,7 @@ namespace datalog { model_converter * translate(ast_translation & translator) override { UNREACHABLE(); - return 0; + return nullptr; } }; @@ -116,7 +116,7 @@ namespace datalog { rule_set * mk_scale::operator()(rule_set const & source) { if (!m_ctx.scale()) { - return 0; + return nullptr; } rule_manager& rm = source.get_rule_manager(); rule_set * result = alloc(rule_set, m_ctx); diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.cpp b/src/muz/transforms/dl_mk_separate_negated_tails.cpp index 3da759f9b..c50aba827 100644 --- a/src/muz/transforms/dl_mk_separate_negated_tails.cpp +++ b/src/muz/transforms/dl_mk_separate_negated_tails.cpp @@ -127,7 +127,7 @@ namespace datalog { } } if (!has_new_rule) { - return 0; + return nullptr; } else { result->inherit_predicates(src); diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index 3c5cf53c7..c6d08493c 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -155,8 +155,8 @@ namespace datalog { } bool translate_asserted(proof* p) { - expr* fact = 0; - rule* r = 0; + expr* fact = nullptr; + rule* r = nullptr; if (!m.is_asserted(p, fact)) { return false; } @@ -215,7 +215,7 @@ namespace datalog { proof* p1_new = m_new_proof.find(p1); expr* fact1 = m.get_fact(p1); TRACE("dl", tout << "fact1: " << mk_pp(fact1, m) << "\n";); - rule* orig1 = 0; + rule* orig1 = nullptr; if (!m_sliceform2rule.find(fact1, orig1)) { return false; } @@ -281,7 +281,7 @@ namespace datalog { proof_converter * translate(ast_translation & translator) override { UNREACHABLE(); // this would require implementing translation for the dl_context. - return 0; + return nullptr; } }; @@ -393,7 +393,7 @@ namespace datalog { model_converter * translate(ast_translation & translator) override { UNREACHABLE(); - return 0; + return nullptr; } }; @@ -405,8 +405,8 @@ namespace datalog { rm(ctx.get_rule_manager()), m_solved_vars(m), m_pinned(m), - m_pc(0), - m_mc(0) + m_pc(nullptr), + m_mc(nullptr) {} @@ -790,7 +790,7 @@ namespace datalog { tail.push_back(to_app(e)); } - new_rule = rm.mk(head.get(), tail.size(), tail.c_ptr(), (const bool*) 0, r.name()); + new_rule = rm.mk(head.get(), tail.size(), tail.c_ptr(), (const bool*) nullptr, r.name()); rm.fix_unbound_vars(new_rule, false); @@ -805,7 +805,7 @@ namespace datalog { dst.add_rule(new_rule.get()); if (m_pc) { - m_pc->insert(&r, new_rule.get(), 0, 0); + m_pc->insert(&r, new_rule.get(), 0, nullptr); } } @@ -819,7 +819,7 @@ namespace datalog { rule_manager& rm = m_ctx.get_rule_manager(); for (unsigned i = 0; i < src.get_num_rules(); ++i) { if (rm.has_quantifiers(*src.get_rule(i))) { - return 0; + return nullptr; } } ref spc; @@ -839,7 +839,7 @@ namespace datalog { if (m_predicates.empty()) { // nothing could be sliced. dealloc(result); - return 0; + return nullptr; } TRACE("dl", display(tout);); update_rules(src, *result); diff --git a/src/muz/transforms/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp index c6bb2864b..1280b3e4b 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -297,7 +297,7 @@ namespace datalog { SASSERT(total_size>=rel_sz); if(total_size==rel_sz) { - on_discovered_total_relation(pred, 0); + on_discovered_total_relation(pred, nullptr); } } next_pred:; @@ -335,7 +335,7 @@ namespace datalog { rule_set * mk_subsumption_checker::operator()(rule_set const & source) { // TODO mc if (!m_context.get_params ().xform_subsumption_checker()) - return 0; + return nullptr; m_have_new_total_rule = false; collect_ground_unconditional_rule_heads(source); @@ -348,7 +348,7 @@ namespace datalog { if (!m_have_new_total_rule && !modified) { dealloc(res); - return 0; + return nullptr; } diff --git a/src/muz/transforms/dl_mk_unbound_compressor.cpp b/src/muz/transforms/dl_mk_unbound_compressor.cpp index 47ce20a76..7844c3144 100644 --- a/src/muz/transforms/dl_mk_unbound_compressor.cpp +++ b/src/muz/transforms/dl_mk_unbound_compressor.cpp @@ -346,7 +346,7 @@ namespace datalog { // TODO mc if (!m_context.compress_unbound()) { - return 0; + return nullptr; } m_modified = false; @@ -387,7 +387,7 @@ namespace datalog { } } - rule_set * result = static_cast(0); + rule_set * result = static_cast(nullptr); if (m_modified) { result = alloc(rule_set, m_context); unsigned fin_rule_cnt = m_rules.size(); diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 8d32a0edf..ac16d9d68 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -146,7 +146,7 @@ namespace nlsat { m_todo(u), m_core1(s), m_core2(s), - m_result(0), + m_result(nullptr), m_evaluator(ev) { m_simplify_cores = false; m_full_dimensional = false; @@ -521,7 +521,7 @@ namespace nlsat { polynomial::var max_var(literal l) { atom * a = m_atoms[l.var()]; - if (a != 0) + if (a != nullptr) return a->max_var(); else return null_var; @@ -535,7 +535,7 @@ namespace nlsat { for (unsigned i = 0; i < sz; i++) { literal l = ls[i]; atom * a = m_atoms[l.var()]; - if (a != 0) { + if (a != nullptr) { var x = a->max_var(); SASSERT(x != null_var); if (max == null_var || x > max) @@ -705,7 +705,7 @@ namespace nlsat { m_result = &result; add_root_literal(k, y, i, p); reset_already_added(); - m_result = 0; + m_result = nullptr; } void add_root_literal(atom::kind k, var y, unsigned i, poly * p) { @@ -1232,7 +1232,7 @@ namespace nlsat { This method selects the equation of minimal degree in max. */ poly * select_eq(scoped_literal_vector & C, var max) { - poly * r = 0; + poly * r = nullptr; unsigned min_d = UINT_MAX; unsigned sz = C.size(); for (unsigned i = 0; i < sz; i++) { @@ -1289,7 +1289,7 @@ namespace nlsat { if (y >= max) continue; atom * eq = m_x2eq[y]; - if (eq == 0) + if (eq == nullptr) continue; SASSERT(eq->is_ineq_atom()); SASSERT(to_ineq_atom(eq)->size() == 1); @@ -1305,7 +1305,7 @@ namespace nlsat { } } } - return 0; + return nullptr; } /** @@ -1315,7 +1315,7 @@ namespace nlsat { // Simplify using equations in the core while (!C.empty()) { poly * eq = select_eq(C, max); - if (eq == 0) + if (eq == nullptr) break; TRACE("nlsat_simplify_core", tout << "using equality for simplifying core\n"; m_pm.display(tout, eq, m_solver.display_proc()); tout << "\n";); @@ -1325,7 +1325,7 @@ namespace nlsat { // Simplify using equations using variables from lower stages. while (!C.empty()) { ineq_atom * eq = select_lower_stage_eq(C, max); - if (eq == 0) + if (eq == nullptr) break; SASSERT(eq->size() == 1); SASSERT(!eq->is_even(0)); @@ -1456,7 +1456,7 @@ namespace nlsat { m_result = &result; process(num, ls); reset_already_added(); - m_result = 0; + m_result = nullptr; TRACE("nlsat_explain", tout << "[explain] result\n"; display(tout, result);); CASSERT("nlsat", check_already_added()); } @@ -1495,14 +1495,14 @@ namespace nlsat { project(m_ps, mx_var); } reset_already_added(); - m_result = 0; + m_result = nullptr; if (x != mx_var) { m_solver.restore_order(); } } else { reset_already_added(); - m_result = 0; + m_result = nullptr; } for (unsigned i = 0; i < result.size(); ++i) { result.set(i, ~result[i]); diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 090f94eeb..922440fea 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -122,7 +122,7 @@ namespace nlsat { } void interval_set_manager::del(interval_set * s) { - if (s == 0) + if (s == nullptr) return; unsigned num = s->m_num_intervals; unsigned obj_sz = interval_set::get_obj_size(num); @@ -270,9 +270,9 @@ namespace nlsat { interval_set * interval_set_manager::mk_union(interval_set const * s1, interval_set const * s2) { TRACE("nlsat_interval", tout << "mk_union\ns1: "; display(tout, s1); tout << "\ns2: "; display(tout, s2); tout << "\n";); - if (s1 == 0 || s1 == s2) + if (s1 == nullptr || s1 == s2) return const_cast(s2); - if (s2 == 0) + if (s2 == nullptr) return const_cast(s1); if (s1->m_full) return const_cast(s1); @@ -514,22 +514,22 @@ namespace nlsat { } bool interval_set_manager::is_full(interval_set const * s) { - if (s == 0) + if (s == nullptr) return false; return s->m_full == 1; } unsigned interval_set_manager::num_intervals(interval_set const * s) const { - if (s == 0) return 0; + if (s == nullptr) return 0; return s->m_num_intervals; } bool interval_set_manager::subset(interval_set const * s1, interval_set const * s2) { if (s1 == s2) return true; - if (s1 == 0) + if (s1 == nullptr) return true; - if (s2 == 0) + if (s2 == nullptr) return false; if (s2->m_full) return true; @@ -616,7 +616,7 @@ namespace nlsat { } bool interval_set_manager::set_eq(interval_set const * s1, interval_set const * s2) { - if (s1 == 0 || s2 == 0) + if (s1 == nullptr || s2 == nullptr) return s1 == s2; if (s1->m_full || s2->m_full) return s1->m_full == s2->m_full; @@ -625,7 +625,7 @@ namespace nlsat { } bool interval_set_manager::eq(interval_set const * s1, interval_set const * s2) { - if (s1 == 0 || s2 == 0) + if (s1 == nullptr || s2 == nullptr) return s1 == s2; if (s1->m_num_intervals != s2->m_num_intervals) return false; @@ -674,7 +674,7 @@ namespace nlsat { void interval_set_manager::peek_in_complement(interval_set const * s, bool is_int, anum & w, bool randomize) { SASSERT(!is_full(s)); - if (s == 0) { + if (s == nullptr) { if (randomize) { int num = m_rand() % 2 == 0 ? 1 : -1; #define MAX_RANDOM_DEN_K 4 @@ -744,7 +744,7 @@ namespace nlsat { } void interval_set_manager::display(std::ostream & out, interval_set const * s) const { - if (s == 0) { + if (s == nullptr) { out << "{}"; return; } diff --git a/src/nlsat/nlsat_interval_set.h b/src/nlsat/nlsat_interval_set.h index 363d48de9..22d04b86a 100644 --- a/src/nlsat/nlsat_interval_set.h +++ b/src/nlsat/nlsat_interval_set.h @@ -40,7 +40,7 @@ namespace nlsat { /** \brief Return the empty set. */ - interval_set * mk_empty() { return 0; } + interval_set * mk_empty() { return nullptr; } /** \brief Return a set of composed of a single interval. @@ -64,7 +64,7 @@ namespace nlsat { \brief Return true if s is the empty set. */ bool is_empty(interval_set const * s) { - return s == 0; + return s == nullptr; } /** diff --git a/src/nlsat/nlsat_justification.h b/src/nlsat/nlsat_justification.h index 13759e035..61c6f40e2 100644 --- a/src/nlsat/nlsat_justification.h +++ b/src/nlsat/nlsat_justification.h @@ -54,8 +54,8 @@ namespace nlsat { void * m_data; public: enum kind { NULL_JST = 0, DECISION, CLAUSE, LAZY }; - justification():m_data(TAG(void *, static_cast(0), NULL_JST)) { SASSERT(is_null()); } - justification(bool):m_data(TAG(void *, static_cast(0), DECISION)) { SASSERT(is_decision()); } + justification():m_data(TAG(void *, nullptr, NULL_JST)) { SASSERT(is_null()); } + justification(bool):m_data(TAG(void *, nullptr, DECISION)) { SASSERT(is_decision()); } justification(clause * c):m_data(TAG(void *, c, CLAUSE)) { SASSERT(is_clause()); } justification(lazy_justification * j):m_data(TAG(void *, j, LAZY)) { SASSERT(is_lazy()); } kind get_kind() const { return static_cast(GET_TAG(m_data)); } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 3358dd61a..9767448b1 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -110,10 +110,10 @@ namespace nlsat { display_var_proc const * m_proc; // display external var ids perm_display_var_proc(var_vector & perm): m_perm(perm), - m_proc(0) { + m_proc(nullptr) { } std::ostream& operator()(std::ostream & out, var x) const override { - if (m_proc == 0) + if (m_proc == nullptr) m_default_display_var(out, x); else (*m_proc)(out, m_perm[x]); @@ -197,7 +197,7 @@ namespace nlsat { bool_var b = mk_bool_var(); SASSERT(b == true_bool_var); literal true_lit(b, false); - mk_clause(1, &true_lit, false, 0); + mk_clause(1, &true_lit, false, nullptr); } void updt_params(params_ref const & _p) { @@ -259,11 +259,11 @@ namespace nlsat { void dec_ref(assumption) {} void inc_ref(_assumption_set a) { - if (a != 0) m_asm.inc_ref(a); + if (a != nullptr) m_asm.inc_ref(a); } void dec_ref(_assumption_set a) { - if (a != 0) m_asm.dec_ref(a); + if (a != nullptr) m_asm.dec_ref(a); } void inc_ref(bool_var b) { @@ -284,7 +284,7 @@ namespace nlsat { if (b == null_bool_var) return; atom * a = m_atoms[b]; - if (a == 0) + if (a == nullptr) return; SASSERT(a->ref_count() > 0); a->dec_ref(); @@ -377,7 +377,7 @@ namespace nlsat { unsigned max = 0; for (literal l : c) { atom const * a = m_atoms[l.var()]; - if (a == 0) + if (a == nullptr) continue; unsigned d = degree(a); if (d > max) @@ -429,7 +429,7 @@ namespace nlsat { void vars(literal l, var_vector& vs) { vs.reset(); atom * a = m_atoms[l.var()]; - if (a == 0) { + if (a == nullptr) { } else if (a->is_ineq_atom()) { @@ -492,7 +492,7 @@ namespace nlsat { } void del(atom * a) { - if (a == 0) + if (a == nullptr) return ; if (a->is_ineq_atom()) del(to_ineq_atom(a)); @@ -664,11 +664,11 @@ namespace nlsat { bool operator()(literal l1, literal l2) const { atom * a1 = m.m_atoms[l1.var()]; atom * a2 = m.m_atoms[l2.var()]; - if (a1 == 0 && a2 == 0) + if (a1 == nullptr && a2 == nullptr) return l1.index() < l2.index(); - if (a1 == 0) + if (a1 == nullptr) return true; - if (a2 == 0) + if (a2 == nullptr) return false; var x1 = a1->max_var(); var x2 = a2->max_var(); @@ -712,8 +712,8 @@ namespace nlsat { void mk_clause(unsigned num_lits, literal const * lits, assumption a) { SASSERT(num_lits > 0); - _assumption_set as = 0; - if (a != 0) + _assumption_set as = nullptr; + if (a != nullptr) as = m_asm.mk_leaf(a); mk_clause(num_lits, lits, false, as); } @@ -931,7 +931,7 @@ namespace nlsat { } bool_var b = l.var(); atom * a = m_atoms[b]; - if (a == 0) { + if (a == nullptr) { return l_undef; } var max = a->max_var(); @@ -1037,7 +1037,7 @@ namespace nlsat { if (m_bvalues[b] != l_true) return; atom * a = m_atoms[b]; - if (a == 0 || a->get_kind() != atom::EQ || to_ineq_atom(a)->size() > 1 || to_ineq_atom(a)->is_even(0)) + if (a == nullptr || a->get_kind() != atom::EQ || to_ineq_atom(a)->size() > 1 || to_ineq_atom(a)->is_even(0)) return; var x = m_xk; SASSERT(a->max_var() == x); @@ -1082,13 +1082,13 @@ namespace nlsat { TRACE("nlsat_inf_set", tout << "infeasible set for literal: "; display(tout, l); tout << "\n"; m_ism.display(tout, curr_set); tout << "\n";); if (m_ism.is_empty(curr_set)) { TRACE("nlsat_inf_set", tout << "infeasible set is empty, found literal\n";); - R_propagate(l, 0); + R_propagate(l, nullptr); SASSERT(is_satisfied(cls)); return true; } if (m_ism.is_full(curr_set)) { TRACE("nlsat_inf_set", tout << "infeasible set is R, skip literal\n";); - R_propagate(~l, 0); + R_propagate(~l, nullptr); continue; } if (m_ism.subset(curr_set, xk_set)) { @@ -1155,7 +1155,7 @@ namespace nlsat { if (!process_clause(*c, false)) return c; } - return 0; // succeeded + return nullptr; // succeeded } /** @@ -1235,7 +1235,7 @@ namespace nlsat { conflict_clause = process_clauses(m_bwatches[m_bk]); else conflict_clause = process_clauses(m_watches[m_xk]); - if (conflict_clause == 0) + if (conflict_clause == nullptr) break; if (!resolve(*conflict_clause)) return l_false; @@ -1299,7 +1299,7 @@ namespace nlsat { m_lemma.push_back(~mk_ineq_literal(atom::LT, 1, &p2, &is_even)); // perform branch and bound - clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, 0); + clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, nullptr); if (cls) { TRACE("nlsat", display(tout << "conflict " << lo << " " << hi, *cls); tout << "\n";); } @@ -1403,7 +1403,7 @@ namespace nlsat { unsigned sz = assumptions.size(); literal const* ptr = assumptions.c_ptr(); _assumption_set asms = static_cast<_assumption_set>(c.assumptions()); - if (asms == 0) { + if (asms == nullptr) { return false; } vector deps; @@ -1663,7 +1663,7 @@ namespace nlsat { m_num_marks = 0; m_lemma.reset(); - m_lemma_assumptions = 0; + m_lemma_assumptions = nullptr; resolve_clause(null_bool_var, *conflict_clause); @@ -1757,7 +1757,7 @@ namespace nlsat { // in a previous scope level. We may backjump many decisions. // unsigned sz = m_lemma.size(); - clause * new_cls = 0; + clause * new_cls = nullptr; if (!found_decision) { // Case 1) // We just have to find the maximal variable in m_lemma, and return to that stage @@ -1924,7 +1924,7 @@ namespace nlsat { void collect(literal l) { bool_var b = l.var(); atom * a = m_atoms[b]; - if (a == 0) + if (a == nullptr) return; if (a->is_ineq_atom()) { unsigned sz = to_ineq_atom(a)->size(); @@ -2123,7 +2123,7 @@ namespace nlsat { for (unsigned i = 0; i < sz; i++) { bool_var b = c[i].var(); atom * a = m_atoms[b]; - if (a == 0) + if (a == nullptr) continue; if (a->is_ineq_atom()) continue; @@ -2158,7 +2158,7 @@ namespace nlsat { reinit_cache(m_atoms[b]); } void reinit_cache(atom* a) { - if (a == 0) { + if (a == nullptr) { } else if (a->is_ineq_atom()) { @@ -2250,7 +2250,7 @@ namespace nlsat { bool is_full_dimensional(literal l) const { atom * a = m_atoms[l.var()]; - if (a == 0) + if (a == nullptr) return true; switch (a->get_kind()) { case atom::EQ: return l.sign(); @@ -2858,7 +2858,7 @@ namespace nlsat { } std::ostream& display(std::ostream & out, clause const & c, display_var_proc const & proc) const { - if (c.assumptions() != 0) { + if (c.assumptions() != nullptr) { display_assumptions(out, static_cast<_assumption_set>(c.assumptions())); out << " |- "; } diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index c632a0334..e7b250f64 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -108,7 +108,7 @@ namespace nlsat { /** \brief Create a new clause. */ - void mk_clause(unsigned num_lits, literal * lits, assumption a = 0); + void mk_clause(unsigned num_lits, literal * lits, assumption a = nullptr); // ----------------------- // diff --git a/src/nlsat/tactic/goal2nlsat.cpp b/src/nlsat/tactic/goal2nlsat.cpp index 51536e493..133652c1d 100644 --- a/src/nlsat/tactic/goal2nlsat.cpp +++ b/src/nlsat/tactic/goal2nlsat.cpp @@ -269,12 +269,12 @@ struct goal2nlsat::scoped_set_imp { } ~scoped_set_imp() { - m_owner.m_imp = 0; + m_owner.m_imp = nullptr; } }; goal2nlsat::goal2nlsat() { - m_imp = 0; + m_imp = nullptr; } goal2nlsat::~goal2nlsat() { diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 74531a9a7..92c6e0ffb 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -68,7 +68,7 @@ class nlsat_tactic : public tactic { } for (unsigned b = 0; b < b2a.size(); b++) { expr * a = b2a.get(b); - if (a == 0) + if (a == nullptr) continue; if (is_uninterp_const(a)) continue; @@ -116,7 +116,7 @@ class nlsat_tactic : public tactic { } for (unsigned b = 0; b < b2a.size(); b++) { expr * a = b2a.get(b); - if (a == 0 || !is_uninterp_const(a)) + if (a == nullptr || !is_uninterp_const(a)) continue; lbool val = m_solver.bvalue(b); if (val == l_undef) @@ -134,7 +134,7 @@ class nlsat_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("nlsat", *g); if (g->is_decided()) { @@ -173,7 +173,7 @@ class nlsat_tactic : public tactic { } } else { - expr_dependency* lcore = 0; + expr_dependency* lcore = nullptr; if (g->unsat_core_enabled()) { vector assumptions; m_solver.get_core(assumptions); @@ -182,7 +182,7 @@ class nlsat_tactic : public tactic { lcore = m.mk_join(lcore, d); } } - g->assert_expr(m.mk_false(), 0, lcore); + g->assert_expr(m.mk_false(), nullptr, lcore); } g->inc_depth(); @@ -204,14 +204,14 @@ class nlsat_tactic : public tactic { ~scoped_set_imp() { m_owner.m_imp->m_solver.collect_statistics(m_owner.m_stats); - m_owner.m_imp = 0; + m_owner.m_imp = nullptr; } }; public: nlsat_tactic(params_ref const & p): m_params(p) { - m_imp = 0; + m_imp = nullptr; } tactic * translate(ast_manager & m) override { diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 9d32d48e3..178b87037 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -243,7 +243,7 @@ public: case l_true: get_current_correction_set(cs); if (cs.empty()) { - m_found_feasible_optimum = m_model.get() != 0; + m_found_feasible_optimum = m_model.get() != nullptr; m_lower = m_upper; } else { @@ -443,7 +443,7 @@ public: rational w = split_core(corr_set); cs_max_resolve(corr_set, w); IF_VERBOSE(2, verbose_stream() << "(opt.maxres.correction-set " << corr_set.size() << ")\n";); - m_csmodel = 0; + m_csmodel = nullptr; m_correction_set_size = 0; } @@ -488,7 +488,7 @@ public: } void process_unsat(exprs const& core) { - IF_VERBOSE(3, verbose_stream() << "(maxres cs model valid: " << (m_csmodel.get() != 0) << " cs size:" << m_correction_set_size << " core: " << core.size() << ")\n";); + IF_VERBOSE(3, verbose_stream() << "(maxres cs model valid: " << (m_csmodel.get() != nullptr) << " cs size:" << m_correction_set_size << " core: " << core.size() << ")\n";); expr_ref fml(m); remove_core(core); SASSERT(!core.empty()); @@ -524,7 +524,7 @@ public: if (m_c.sat_enabled()) { // SAT solver core extracts some model // during unsat core computation. - mdl = 0; + mdl = nullptr; s().get_model(mdl); } else { @@ -533,7 +533,7 @@ public: if (mdl.get() && w < m_upper) { update_assignment(mdl.get()); } - return 0 != mdl.get(); + return nullptr != mdl.get(); } lbool minimize_core(exprs& core) { @@ -820,7 +820,7 @@ public: m_found_feasible_optimum = false; m_last_index = 0; add_upper_bound_block(); - m_csmodel = 0; + m_csmodel = nullptr; m_correction_set_size = 0; return l_true; } @@ -844,7 +844,7 @@ public: smt_solver->assert_expr(s().get_assertion(i)); } smt_solver->assert_expr(core); - lbool is_sat = smt_solver->check_sat(0, 0); + lbool is_sat = smt_solver->check_sat(0, nullptr); if (is_sat == l_true) { IF_VERBOSE(0, verbose_stream() << "not a core\n";); } @@ -864,7 +864,7 @@ public: } smt_solver->assert_expr(n); } - lbool is_sat = smt_solver->check_sat(0, 0); + lbool is_sat = smt_solver->check_sat(0, nullptr); if (is_sat == l_false) { IF_VERBOSE(0, verbose_stream() << "assignment is infeasible\n";); } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 6df375240..91e843ca0 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -116,7 +116,7 @@ namespace opt { return dynamic_cast(th); } else { - return 0; + return nullptr; } } @@ -228,7 +228,7 @@ namespace opt { lbool maxsmt::operator()() { lbool is_sat = l_undef; - m_msolver = 0; + m_msolver = nullptr; symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); TRACE("opt", tout << "maxsmt\n"; diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index 89264a9c8..4ff8fab71 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -52,7 +52,7 @@ public: assert_soft_cmd(opt::context* opt): parametric_cmd("assert-soft"), m_idx(0), - m_formula(0), + m_formula(nullptr), m_opt(opt) {} @@ -61,7 +61,7 @@ public: virtual void reset(cmd_context & ctx) { m_idx = 0; - m_formula = 0; + m_formula = nullptr; } virtual char const * get_usage() const { return " [:weight ] [:id ]"; } diff --git a/src/opt/opt_cmds.h b/src/opt/opt_cmds.h index 60f83d201..3ca8228df 100644 --- a/src/opt/opt_cmds.h +++ b/src/opt/opt_cmds.h @@ -23,7 +23,7 @@ Notes: class cmd_context; -void install_opt_cmds(cmd_context & ctx, opt::context* opt = 0); +void install_opt_cmds(cmd_context & ctx, opt::context* opt = nullptr); #endif diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2fdef6ca4..2f6bad9e8 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -121,7 +121,7 @@ namespace opt { m_arith(m), m_bv(m), m_hard_constraints(m), - m_solver(0), + m_solver(nullptr), m_pareto1(false), m_box_index(UINT_MAX), m_optsmt(m), @@ -274,7 +274,7 @@ namespace opt { s.assert_expr(m_hard_constraints); display_benchmark(); IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";); - lbool is_sat = s.check_sat(0,0); + lbool is_sat = s.check_sat(0,nullptr); TRACE("opt", tout << "initial search result: " << is_sat << "\n"; s.display(tout);); if (is_sat != l_false) { @@ -435,7 +435,7 @@ namespace opt { return l_true; } if (m_box_index < m_objectives.size()) { - m_model = 0; + m_model = nullptr; ++m_box_index; return l_undef; } @@ -553,7 +553,7 @@ namespace opt { } lbool is_sat = (*(m_pareto.get()))(); if (is_sat != l_true) { - set_pareto(0); + set_pareto(nullptr); } if (is_sat == l_true) { yield(); @@ -925,7 +925,7 @@ namespace opt { func_decl* f = m.mk_fresh_func_decl(name,"", domain.size(), domain.c_ptr(), m.mk_bool_sort()); m_objective_fns.insert(f, index); m_objective_refs.push_back(f); - m_objective_orig.insert(f, sz > 0 ? args[0] : 0); + m_objective_orig.insert(f, sz > 0 ? args[0] : nullptr); return m.mk_app(f, sz, args); } @@ -968,7 +968,7 @@ namespace opt { } mk_atomic(terms); SASSERT(obj.m_id == id); - obj.m_term = orig_term?to_app(orig_term):0; + obj.m_term = orig_term?to_app(orig_term):nullptr; obj.m_terms.reset(); obj.m_terms.append(terms); obj.m_weights.reset(); @@ -1384,7 +1384,7 @@ namespace opt { } void context::clear_state() { - set_pareto(0); + set_pareto(nullptr); m_box_index = UINT_MAX; m_model.reset(); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index c9e5ce3de..6af106ef3 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -191,14 +191,14 @@ namespace opt { void get_box_model(model_ref& _m, unsigned index) override; void fix_model(model_ref& _m) override; void collect_statistics(statistics& stats) const override; - proof* get_proof() override { return 0; } + proof* get_proof() override { return nullptr; } void get_labels(svector & r) override; void get_unsat_core(ptr_vector & r) override; std::string reason_unknown() const override; void set_reason_unknown(char const* msg) override { m_unknown = msg; } void display_assignment(std::ostream& out) override; - bool is_pareto() override { return m_pareto.get() != 0; } + bool is_pareto() override { return m_pareto.get() != nullptr; } void set_logic(symbol const& s) override { m_logic = s; } void set_clausal(bool f) { m_is_clausal = f; } @@ -223,7 +223,7 @@ namespace opt { smt::context& smt_context() override { return m_opt_solver->get_context(); } filter_model_converter& fm() override { return m_fm; } - bool sat_enabled() const override { return 0 != m_sat_solver.get(); } + bool sat_enabled() const override { return nullptr != m_sat_solver.get(); } solver& get_solver() override; ast_manager& get_manager() const override { return this->m; } params_ref& params() override { return m_params; } diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index 026d10abc..c316e697e 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -29,7 +29,7 @@ namespace opt { lbool gia_pareto::operator()() { expr_ref fml(m); - lbool is_sat = m_solver->check_sat(0, 0); + lbool is_sat = m_solver->check_sat(0, nullptr); if (is_sat == l_true) { { solver::scoped_push _s(*m_solver.get()); @@ -45,7 +45,7 @@ namespace opt { model_smt2_pp(verbose_stream() << "new model:\n", m, *mdl, 0);); // TBD: we can also use local search to tune solution coordinate-wise. mk_dominates(); - is_sat = m_solver->check_sat(0, 0); + is_sat = m_solver->check_sat(0, nullptr); } } if (is_sat == l_undef) { @@ -91,7 +91,7 @@ namespace opt { lbool oia_pareto::operator()() { solver::scoped_push _s(*m_solver.get()); - lbool is_sat = m_solver->check_sat(0, 0); + lbool is_sat = m_solver->check_sat(0, nullptr); if (m.canceled()) { is_sat = l_undef; } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 49b48e68f..715f45291 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -69,7 +69,7 @@ namespace opt { solver* opt_solver::translate(ast_manager& m, params_ref const& p) { UNREACHABLE(); - return 0; + return nullptr; } void opt_solver::collect_param_descrs(param_descrs & r) { @@ -261,7 +261,7 @@ namespace opt { expr_ref ge = mk_ge(i, val); TRACE("opt", tout << ge << "\n";); assert_expr(ge); - lbool is_sat = m_context.check(0, 0); + lbool is_sat = m_context.check(0, nullptr); is_sat = adjust_result(is_sat); if (is_sat == l_true) { set_model(i); @@ -316,7 +316,7 @@ namespace opt { void opt_solver::get_labels(svector & r) { r.reset(); buffer tmp; - m_context.get_relevant_labels(0, tmp); + m_context.get_relevant_labels(nullptr, tmp); r.append(tmp.size(), tmp.c_ptr()); } @@ -340,7 +340,7 @@ namespace opt { m_objective_values.push_back(inf_eps(rational(-1), inf_rational())); m_objective_terms.push_back(term); m_valid_objectives.push_back(true); - m_models.push_back(0); + m_models.push_back(nullptr); return v; } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 3258cb33d..66174a28b 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -112,7 +112,7 @@ namespace opt { while (!m.canceled()) { SASSERT(delta_per_step.is_int()); SASSERT(delta_per_step.is_pos()); - is_sat = m_s->check_sat(0, 0); + is_sat = m_s->check_sat(0, nullptr); if (is_sat == l_true) { bound = update_lower(); if (!get_max_delta(lower, delta_index)) { @@ -188,7 +188,7 @@ namespace opt { while (!m.canceled()) { SASSERT(delta_per_step.is_int()); SASSERT(delta_per_step.is_pos()); - is_sat = m_s->check_sat(0, 0); + is_sat = m_s->check_sat(0, nullptr); if (is_sat == l_true) { m_s->maximize_objective(obj_index, bound); m_s->get_model(m_model); @@ -416,7 +416,7 @@ namespace opt { bounds.push_back(bound); } else { - bounds.push_back(0); + bounds.push_back(nullptr); mid.push_back(inf_eps()); } } @@ -429,7 +429,7 @@ namespace opt { case l_true: IF_VERBOSE(2, verbose_stream() << "(optsmt lower bound for v" << m_vars[i] << " := " << m_upper[i] << ")\n";); m_lower[i] = mid[i]; - th.enable_record_conflict(0); + th.enable_record_conflict(nullptr); m_s->assert_expr(update_lower()); break; case l_false: @@ -444,10 +444,10 @@ namespace opt { } break; default: - th.enable_record_conflict(0); + th.enable_record_conflict(nullptr); return l_undef; } - th.enable_record_conflict(0); + th.enable_record_conflict(nullptr); progress = true; } } @@ -505,7 +505,7 @@ namespace opt { commit_assignment(i); } while (is_sat == l_true && !m.canceled()) { - is_sat = m_s->check_sat(0, 0); + is_sat = m_s->check_sat(0, nullptr); if (is_sat != l_true) break; m_s->maximize_objective(obj_index, bound); @@ -599,7 +599,7 @@ namespace opt { m_lower.push_back(inf_eps(rational(-1),inf_rational(0))); m_upper.push_back(inf_eps(rational(1), inf_rational(0))); m_lower_fmls.push_back(m.mk_true()); - m_models.push_back(0); + m_models.push_back(nullptr); return m_objs.size()-1; } @@ -615,7 +615,7 @@ namespace opt { m_vars.reset(); m_model.reset(); m_lower_fmls.reset(); - m_s = 0; + m_s = nullptr; } } diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index 93fa3f624..6db7eaadf 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -41,7 +41,7 @@ namespace opt { sref_vector m_models; public: optsmt(ast_manager& m): - m(m), m_s(0), m_objs(m), m_lower_fmls(m) {} + m(m), m_s(nullptr), m_objs(m), m_lower_fmls(m) {} void setup(opt_solver& solver); diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 00cab488c..1bbafc90b 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -89,7 +89,7 @@ namespace opt { while (l_true == is_sat && first < out.size() && m_lower < m_upper) { trace_bounds("sortmax"); s().assert_expr(out[first]); - is_sat = s().check_sat(0, 0); + is_sat = s().check_sat(0, nullptr); TRACE("opt", tout << is_sat << "\n"; s().display(tout); tout << "\n";); if (m.canceled()) { is_sat = l_undef; diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index afc0334eb..52b87e536 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -80,7 +80,7 @@ namespace opt { while (!m.canceled() && m_lower < m_upper) { //mk_assumptions(asms); //is_sat = s().preferred_sat(asms, cores); - is_sat = s().check_sat(0, 0); + is_sat = s().check_sat(0, nullptr); if (m.canceled()) { is_sat = l_undef; } @@ -162,7 +162,7 @@ namespace opt { void verify_core(expr_ref_vector const& core) { s().push(); s().assert_expr(core); - VERIFY(l_false == s().check_sat(0, 0)); + VERIFY(l_false == s().check_sat(0, nullptr)); s().pop(1); } @@ -216,7 +216,7 @@ namespace opt { rational remove_negations(smt::theory_wmaxsat& th, expr_ref_vector const& core, ptr_vector& keys, vector& weights) { rational min_weight(-1); for (unsigned i = 0; i < core.size(); ++i) { - expr* e = 0; + expr* e = nullptr; VERIFY(m.is_not(core[i], e)); keys.push_back(m_keys[e]); rational weight = m_weights[e]; diff --git a/src/parsers/smt2/marshal.cpp b/src/parsers/smt2/marshal.cpp index ae144e491..11244760a 100644 --- a/src/parsers/smt2/marshal.cpp +++ b/src/parsers/smt2/marshal.cpp @@ -36,7 +36,7 @@ std::string marshal(expr_ref e, ast_manager &m) { expr_ref unmarshal(std::istream &is, ast_manager &m) { cmd_context ctx(false, &m); ctx.set_ignore_check(true); - if (!parse_smt2_commands(ctx, is)) { return expr_ref(0, m); } + if (!parse_smt2_commands(ctx, is)) { return expr_ref(nullptr, m); } ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index a06438c73..0b0420873 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -46,7 +46,7 @@ namespace smt2 { struct local { expr * m_term; unsigned m_level; - local():m_term(0), m_level(0) {} + local():m_term(nullptr), m_level(0) {} local(expr * t, unsigned l):m_term(t), m_level(l) {} }; symbol_table m_env; @@ -222,31 +222,31 @@ namespace smt2 { } psort_ref_vector & psort_stack() { - if (m_psort_stack.get() == 0) + if (m_psort_stack.get() == nullptr) m_psort_stack = alloc(psort_ref_vector, pm()); return *(m_psort_stack.get()); } sort_ref_vector & sort_stack() { - if (m_sort_stack.get() == 0) + if (m_sort_stack.get() == nullptr) m_sort_stack = alloc(sort_ref_vector, m()); return *(m_sort_stack.get()); } expr_ref_vector & expr_stack() { - if (m_expr_stack.get() == 0) + if (m_expr_stack.get() == nullptr) m_expr_stack = alloc(expr_ref_vector, m()); return *(m_expr_stack.get()); } template static unsigned size(scoped_ptr & v) { - return v.get() == 0 ? 0 : v->size(); + return v.get() == nullptr ? 0 : v->size(); } template static void shrink(scoped_ptr & v, unsigned old_sz) { - if (v.get() == 0) { + if (v.get() == nullptr) { SASSERT(old_sz == 0); } else { @@ -255,13 +255,13 @@ namespace smt2 { } expr_ref_vector & pattern_stack() { - if (m_pattern_stack.get() == 0) + if (m_pattern_stack.get() == nullptr) m_pattern_stack = alloc(expr_ref_vector, m()); return *(m_pattern_stack.get()); } expr_ref_vector & nopattern_stack() { - if (m_nopattern_stack.get() == 0) + if (m_nopattern_stack.get() == nullptr) m_nopattern_stack = alloc(expr_ref_vector, m()); return *(m_nopattern_stack.get()); } @@ -271,44 +271,44 @@ namespace smt2 { } sexpr_ref_vector & sexpr_stack() { - if (m_sexpr_stack.get() == 0) + if (m_sexpr_stack.get() == nullptr) m_sexpr_stack = alloc(sexpr_ref_vector, sm()); return *(m_sexpr_stack.get()); } arith_util & autil() { - if (m_arith_util.get() == 0) + if (m_arith_util.get() == nullptr) m_arith_util = alloc(arith_util, m()); return *(m_arith_util.get()); } datatype_util & dtutil() { - if (m_datatype_util.get() == 0) + if (m_datatype_util.get() == nullptr) m_datatype_util = alloc(datatype_util, m()); return *(m_datatype_util.get()); } seq_util & sutil() { - if (m_seq_util.get() == 0) + if (m_seq_util.get() == nullptr) m_seq_util = alloc(seq_util, m()); return *(m_seq_util.get()); } bv_util & butil() { - if (m_bv_util.get() == 0) + if (m_bv_util.get() == nullptr) m_bv_util = alloc(bv_util, m()); return *(m_bv_util.get()); } pattern_validator & pat_validator() { - if (m_pattern_validator.get() == 0) { + if (m_pattern_validator.get() == nullptr) { m_pattern_validator = alloc(pattern_validator, m()); } return *(m_pattern_validator.get()); } var_shifter & shifter() { - if (m_var_shifter.get() == 0) + if (m_var_shifter.get() == nullptr) m_var_shifter = alloc(var_shifter, m()); return *(m_var_shifter.get()); } @@ -569,12 +569,12 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == nullptr) unknown_sort(id, context); if (!d->has_var_params() && d->get_num_params() != 0) throw parser_exception("sort constructor expects parameters"); sort * r = d->instantiate(pm()); - if (r == 0) + if (r == nullptr) throw parser_exception("invalid sort application"); next(); return r; @@ -584,7 +584,7 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d != 0) { + if (d != nullptr) { if (!d->has_var_params() && d->get_num_params() != 0) throw parser_exception("sort constructor expects parameters"); next(); @@ -601,7 +601,7 @@ namespace smt2 { unknown_sort(id); UNREACHABLE(); } - return 0; + return nullptr; } } } @@ -612,7 +612,7 @@ namespace smt2 { next(); symbol id = check_identifier_next("invalid indexed sort, symbol expected"); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == nullptr) unknown_sort(id); sbuffer args; while (!curr_is_rparen()) { @@ -624,7 +624,7 @@ namespace smt2 { if (args.empty()) throw parser_exception("invalid indexed sort, index expected"); sort * r = d->instantiate(pm(), args.size(), args.c_ptr()); - if (r == 0) + if (r == nullptr) throw parser_exception("invalid sort application"); next(); return r; @@ -634,7 +634,7 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) { + if (d == nullptr) { unknown_sort(id); } next(); @@ -697,7 +697,7 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - if (d == 0) + if (d == nullptr) unknown_sort(id); next(); void * mem = m_stack.allocate(sizeof(sort_frame)); @@ -717,7 +717,7 @@ namespace smt2 { throw parser_exception("invalid number of parameters to sort constructor"); } sort * r = d->instantiate(pm(), num, sort_stack().c_ptr() + spos); - if (r == 0) + if (r == nullptr) throw parser_exception("invalid sort application"); sort_stack().shrink(spos); sort_stack().push_back(r); @@ -783,7 +783,7 @@ namespace smt2 { SASSERT(curr_is_identifier()); psort * p = parse_psort_name(true); ptype result; - if (p != 0) { + if (p != nullptr) { result = ptype(p); } else { @@ -828,7 +828,7 @@ namespace smt2 { symbol r_name(r_str.c_str()); next(); TRACE("datatype_parser_bug", tout << ct_name << " " << r_name << "\n";); - ct_decls.push_back(pm().mk_pconstructor_decl(m_sort_id2param_idx.size(), ct_name, r_name, 0, 0)); + ct_decls.push_back(pm().mk_pconstructor_decl(m_sort_id2param_idx.size(), ct_name, r_name, 0, nullptr)); } else { check_lparen_next("invalid datatype declaration, '(' or ')' expected"); @@ -999,13 +999,13 @@ namespace smt2 { TRACE("name_expr", tout << "naming: " << s << " ->\n" << mk_pp(n, m()) << "\n";); if (!is_ground(n) && has_free_vars(n)) throw parser_exception("invalid named expression, expression contains free variables"); - m_ctx.insert(s, 0, 0, n); + m_ctx.insert(s, 0, nullptr, n); m_last_named_expr.first = s; m_last_named_expr.second = n; } bool in_quant_ctx(attr_expr_frame * fr) { - return fr != 0 && fr->m_prev != 0 && fr->m_prev->m_kind == EF_QUANT; + return fr != nullptr && fr->m_prev != nullptr && fr->m_prev->m_kind == EF_QUANT; } void check_in_quant_ctx(attr_expr_frame * fr) { @@ -1018,7 +1018,7 @@ namespace smt2 { return; if (fr->m_last_symbol == m_pattern) { expr * pat = expr_stack().back(); - if (pat == 0) { + if (pat == nullptr) { if (!ignore_bad_patterns()) throw parser_exception("invalid empty pattern"); } @@ -1191,7 +1191,7 @@ namespace smt2 { if (!ignore_bad_patterns()) throw parser_exception("invalid pattern, '(' expected"); consume_sexpr(); - expr_stack().push_back(0); // empty pattern + expr_stack().push_back(nullptr); // empty pattern return; } @@ -1203,7 +1203,7 @@ namespace smt2 { } else if (curr_is_rparen()) { next(); - expr_stack().push_back(0); // empty pattern + expr_stack().push_back(nullptr); // empty pattern } else { // unary pattern @@ -1211,7 +1211,7 @@ namespace smt2 { // when Simplify benchmarks were converted into SMT2 ones. if (curr_is_identifier()) { symbol id = curr_id(); - func_decl * f = 0; + func_decl * f = nullptr; try { f = m_ctx.find_func_decl(id); } @@ -1223,7 +1223,7 @@ namespace smt2 { while (!curr_is_rparen()) consume_sexpr(); next(); - expr_stack().push_back(0); // empty pattern + expr_stack().push_back(nullptr); // empty pattern return; // no frame is created } } @@ -1761,7 +1761,7 @@ namespace smt2 { return; } expr_ref t_ref(m()); - m_ctx.mk_app(r, 0, 0, num_indices, m_param_stack.c_ptr() + param_spos, has_as ? sort_stack().back() : 0, t_ref); + m_ctx.mk_app(r, 0, nullptr, num_indices, m_param_stack.c_ptr() + param_spos, has_as ? sort_stack().back() : nullptr, t_ref); m_param_stack.shrink(param_spos); expr_stack().push_back(t_ref.get()); if (has_as) { @@ -1851,7 +1851,7 @@ namespace smt2 { expr_stack().c_ptr() + fr->m_expr_spos, num_indices, m_param_stack.c_ptr() + fr->m_param_spos, - fr->m_as_sort ? sort_stack().back() : 0, + fr->m_as_sort ? sort_stack().back() : nullptr, t_ref); expr_stack().shrink(fr->m_expr_spos); m_param_stack.shrink(fr->m_param_spos); @@ -2050,7 +2050,7 @@ namespace smt2 { parse_bv_numeral(); break; case scanner::LEFT_PAREN: - push_expr_frame(m_num_expr_frames == 0 ? 0 : static_cast(m_stack.top())); + push_expr_frame(m_num_expr_frames == 0 ? nullptr : static_cast(m_stack.top())); break; case scanner::KEYWORD_TOKEN: throw parser_exception("invalid expression, unexpected keyword"); @@ -2149,17 +2149,17 @@ namespace smt2 { check_identifier("invalid sort declaration, symbol expected"); symbol id = curr_id(); - if (m_ctx.find_psort_decl(id) != 0) + if (m_ctx.find_psort_decl(id) != nullptr) throw parser_exception("invalid sort declaration, sort already declared/defined"); next(); if (curr_is_rparen()) { - psort_decl * decl = pm().mk_psort_user_decl(0, id, 0); + psort_decl * decl = pm().mk_psort_user_decl(0, id, nullptr); m_ctx.insert(decl); } else { check_int("invalid sort declaration, arity () or ')' expected"); unsigned u = curr_unsigned(); - psort_decl * decl = pm().mk_psort_user_decl(u, id, 0); + psort_decl * decl = pm().mk_psort_user_decl(u, id, nullptr); m_ctx.insert(decl); next(); check_rparen("invalid sort declaration, ')' expected"); @@ -2174,7 +2174,7 @@ namespace smt2 { next(); check_identifier("invalid sort definition, symbol expected"); symbol id = curr_id(); - if (m_ctx.find_psort_decl(id) != 0) + if (m_ctx.find_psort_decl(id) != nullptr) throw parser_exception("invalid sort definition, sort already declared/defined"); next(); parse_sort_decl_params(); @@ -2355,7 +2355,7 @@ namespace smt2 { parse_expr(); if (m().get_sort(expr_stack().back()) != sort_stack().back()) throw parser_exception("invalid constant definition, sort mismatch"); - m_ctx.insert(id, 0, 0, expr_stack().back()); + m_ctx.insert(id, 0, nullptr, expr_stack().back()); check_rparen("invalid constant definition, ')' expected"); expr_stack().pop_back(); sort_stack().pop_back(); @@ -2574,7 +2574,7 @@ namespace smt2 { } check_rparen("invalid get-value command, ')' expected"); - if (!m_ctx.is_model_available() || m_ctx.get_check_sat_result() == 0) + if (!m_ctx.is_model_available() || m_ctx.get_check_sat_result() == nullptr) throw cmd_exception("model is not available"); model_ref md; if (index == 0) { @@ -2804,7 +2804,7 @@ namespace smt2 { void parse_ext_cmd(int line, int pos) { symbol s = curr_id(); m_curr_cmd = m_ctx.find_cmd(s); - if (m_curr_cmd == 0) { + if (m_curr_cmd == nullptr) { parse_unknown_cmd(); return; } @@ -2823,7 +2823,7 @@ namespace smt2 { throw parser_exception("invalid command, argument(s) missing"); m_curr_cmd->execute(m_ctx); next(); - m_curr_cmd = 0; + m_curr_cmd = nullptr; shrink(m_sort_stack, sort_spos); shrink(m_expr_stack, expr_spos); shrink(m_sexpr_stack, sexpr_spos); @@ -2923,12 +2923,12 @@ namespace smt2 { } public: - parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p, char const * filename=0): + parser(cmd_context & ctx, std::istream & is, bool interactive, params_ref const & p, char const * filename=nullptr): m_ctx(ctx), m_params(p), m_scanner(ctx, is, interactive), m_curr(scanner::NULL_TOKEN), - m_curr_cmd(0), + m_curr_cmd(nullptr), m_num_bindings(0), m_let("let"), m_bang("!"), @@ -2988,23 +2988,23 @@ namespace smt2 { void reset() { reset_stack(); m_num_bindings = 0; - m_psort_stack = 0; - m_sort_stack = 0; - m_expr_stack = 0; - m_pattern_stack = 0; - m_nopattern_stack = 0; - m_sexpr_stack = 0; + m_psort_stack = nullptr; + m_sort_stack = nullptr; + m_expr_stack = nullptr; + m_pattern_stack = nullptr; + m_nopattern_stack = nullptr; + m_sexpr_stack = nullptr; m_symbol_stack .reset(); m_param_stack .reset(); m_env .reset(); m_sort_id2param_idx .reset(); m_dt_name2idx .reset(); - m_bv_util = 0; - m_arith_util = 0; - m_seq_util = 0; - m_pattern_validator = 0; - m_var_shifter = 0; + m_bv_util = nullptr; + m_arith_util = nullptr; + m_seq_util = nullptr; + m_pattern_validator = nullptr; + m_var_shifter = nullptr; } bool operator()() { diff --git a/src/parsers/smt2/smt2parser.h b/src/parsers/smt2/smt2parser.h index 0976fc5f4..70ea287e0 100644 --- a/src/parsers/smt2/smt2parser.h +++ b/src/parsers/smt2/smt2parser.h @@ -21,6 +21,6 @@ Revision History: #include "cmd_context/cmd_context.h" -bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & p = params_ref(), char const * filename = 0); +bool parse_smt2_commands(cmd_context & ctx, std::istream & is, bool interactive = false, params_ref const & p = params_ref(), char const * filename = nullptr); #endif diff --git a/src/parsers/util/simple_parser.cpp b/src/parsers/util/simple_parser.cpp index 770da9dbb..c9d00ebcc 100644 --- a/src/parsers/util/simple_parser.cpp +++ b/src/parsers/util/simple_parser.cpp @@ -87,7 +87,7 @@ expr * simple_parser::parse_expr(scanner & s) { } throw parser_error(); case scanner::RIGHT_PAREN: - return 0; + return nullptr; case scanner::ID_TOKEN: if (m_builtin.find(s.get_id(), op)) { expr * r = m_manager.mk_const(op.m_family_id, op.m_kind); @@ -123,7 +123,7 @@ bool simple_parser::parse(std::istream & in, expr_ref & result) { return false; } m_exprs.reset(); - return result.get() != 0; + return result.get() != nullptr; } bool simple_parser::parse_string(char const * str, expr_ref & result) { @@ -133,7 +133,7 @@ bool simple_parser::parse_string(char const * str, expr_ref & result) { } bool simple_parser::parse_file(char const * file, expr_ref & result) { - if (file != 0) { + if (file != nullptr) { std::ifstream stream(file); if (!stream) { warning_msg("ERROR: could not open file '%s'.", file); diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index 7d86860b3..12977b449 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -32,7 +32,7 @@ namespace nlarith { svector m_comps; public: - literal_set(ast_manager& m) : m_inf(m), m_sup(m), m_x(0), m_lits(m) {} + literal_set(ast_manager& m) : m_inf(m), m_sup(m), m_x(nullptr), m_lits(m) {} unsigned size() const { return m_lits.size(); } app_ref_vector& lits() { return m_lits; } @@ -123,7 +123,7 @@ namespace nlarith { return false; } - if (!get_polys(contains_x, num_lits, lits, polys, comps, &branch_conds, 0)) { + if (!get_polys(contains_x, num_lits, lits, polys, comps, &branch_conds, nullptr)) { TRACE("nlarith", tout << "could not extract polynomials " << mk_pp(x, m()) << "\n"; for (unsigned i = 0; i < num_lits; ++i) { @@ -1514,9 +1514,9 @@ namespace nlarith { new_atoms.reset(); app_ref tmp(m()); expr_ref_vector conjs(m()); - mk_exists_zero(literals, true, 0, conjs, new_atoms); + mk_exists_zero(literals, true, nullptr, conjs, new_atoms); mk_same_sign (literals, true, conjs, new_atoms); - mk_exists_zero(literals, false, 0, conjs, new_atoms); + mk_exists_zero(literals, false, nullptr, conjs, new_atoms); mk_same_sign (literals, false, conjs, new_atoms); mk_lt(literals.x(), literals.x_inf(), conjs, new_atoms); mk_lt(literals.x_sup(), literals.x(), conjs, new_atoms); @@ -1922,7 +1922,7 @@ namespace nlarith { } extract_non_linear(atms.size(), atms.begin(), nlvars); if (nlvars.empty()) { - lits = 0; + lits = nullptr; return true; } app* x = nlvars.back(); @@ -1930,11 +1930,11 @@ namespace nlarith { expr* const* _atoms = (expr*const*)atms.begin(); lits = alloc(util::literal_set, m()); lits->set_x(x); - if (get_polys(contains_x, atms.size(), _atoms, lits->polys(), lits->comps(), 0, &lits->lits())) { + if (get_polys(contains_x, atms.size(), _atoms, lits->polys(), lits->comps(), nullptr, &lits->lits())) { return true; } dealloc(lits); - lits = 0; + lits = nullptr; return false; } diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 0898afeda..c71e942a1 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -766,7 +766,7 @@ namespace qe { for (; it != end; ++it) { expr * a = it->m_key; nlsat::bool_var b = it->m_value; - if (a == 0 || !is_uninterp_const(a) || b == m_is_true.var() || !m_free_vars.contains(a) || m_aux_vars.contains(a)) + if (a == nullptr || !is_uninterp_const(a) || b == m_is_true.var() || !m_free_vars.contains(a) || m_aux_vars.contains(a)) continue; lbool val = m_bmodel0.get(b, l_undef); if (val == l_undef) @@ -783,7 +783,7 @@ namespace qe { m_mode(mode), m_params(p), m_solver(m.limit(), p, true), - m_nftactic(0), + m_nftactic(nullptr), m_rmodel(m_solver.am()), m_rmodel0(m_solver.am()), m_valid_model(false), @@ -821,7 +821,7 @@ namespace qe { ptr_vector fmls; expr_ref fml(m); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; in->get_formulas(fmls); fml = mk_and(m, fmls.size(), fmls.c_ptr()); if (m_mode == elim_t) { diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 08a0c44c0..daed18f7a 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -361,7 +361,7 @@ namespace qe { } app* ite; if (find_ite(fml, ite)) { - expr* cond = 0, *th = 0, *el = 0; + expr* cond = nullptr, *th = nullptr, *el = nullptr; VERIFY(m.is_ite(ite, cond, th, el)); expr_ref tmp1(fml, m), tmp2(fml, m); m_replace->apply_substitution(ite, th, tmp1); @@ -448,7 +448,7 @@ namespace qe { } expr* lookup(expr* e, bool p) { - expr* r = 0; + expr* r = nullptr; if (p && m_pos.find(e, r)) { return r; } @@ -457,7 +457,7 @@ namespace qe { } m_todo.push_back(e); m_pols.push_back(p); - return 0; + return nullptr; } void insert(expr* e, bool p, expr* r) { @@ -687,7 +687,7 @@ namespace qe { bool visit(app* e) { bool all_visit = true; - expr* f = 0; + expr* f = nullptr; expr_ref tmp(m); if (!m_is_relevant(e)) { m_cache.insert(e, e); @@ -970,7 +970,7 @@ namespace qe { app* var() const { SASSERT(has_var()); return m_var; } - bool has_var() const { return 0 != m_var.get(); } + bool has_var() const { return nullptr != m_var.get(); } search_tree* parent() const { return m_parent; } @@ -1025,7 +1025,7 @@ namespace qe { m_children.reset(); m_vars.reset(); m_branch_index.reset(); - m_var = 0; + m_var = nullptr; m_def.reset(); m_num_branches = rational::zero(); m_pure = true; @@ -1371,11 +1371,11 @@ namespace qe { m_trail(m), m_fml(m), m_subfml(m), - m_root(0, m, m.mk_true()), - m_current(0), + m_root(nullptr, m, m.mk_true()), + m_current(nullptr), m_new_vars(m), m_get_first(false), - m_defs(0), + m_defs(nullptr), m_nnf(m, get_is_relevant(), get_mk_atom()) { params_ref params; @@ -1398,8 +1398,8 @@ namespace qe { m_var2branch.reset(); m_root.reset(); m_new_vars.reset(); - m_fml = 0; - m_defs = 0; + m_fml = nullptr; + m_defs = nullptr; m_nnf.reset(); } @@ -1501,7 +1501,7 @@ namespace qe { } reset(); m_solver.pop(1); - f = 0; + f = nullptr; } void collect_statistics(statistics& st) { @@ -1571,7 +1571,7 @@ namespace qe { } contains_app* ca = alloc(contains_app, m, x); m_var2contains.insert(x, ca); - app* bv = 0; + app* bv = nullptr; if (m.is_bool(x) || m_bv.is_bv(x)) { bv = x; } @@ -1583,7 +1583,7 @@ namespace qe { m_var2branch.insert(x, bv); } - void add_constraint(bool use_current_val, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) override { + void add_constraint(bool use_current_val, expr* l1 = nullptr, expr* l2 = nullptr, expr* l3 = nullptr) override { search_tree* node = m_current; if (!use_current_val) { node = m_current->parent(); @@ -1603,7 +1603,7 @@ namespace qe { } void blast_or(app* var, expr_ref& fml) override { - m_qe.eliminate_exists(1, &var, fml, m_free_vars, false, 0); + m_qe.eliminate_exists(1, &var, fml, m_free_vars, false, nullptr); } lbool eliminate_exists(unsigned num_vars, app* const* vars, expr_ref& fml, bool get_first, guarded_defs* defs) { @@ -1613,7 +1613,7 @@ namespace qe { private: void add_literal(expr* l) { - if (l != 0) { + if (l != nullptr) { m_literals.push_back(l); } } @@ -1705,11 +1705,11 @@ namespace qe { return NEED_PROPAGATION; } m_current = m_current->child(branch); - if (m_current->fml() == 0) { + if (m_current->fml() == nullptr) { SASSERT(!m_current->has_var()); if (apply) { expr_ref def(m); - plugin(x).subst(contains(x), branch, fml, m_defs?&def:0); + plugin(x).subst(contains(x), branch, fml, m_defs?&def:nullptr); SASSERT(!contains(x)(fml)); m_current->consume_vars(m_new_vars); m_current->init(fml); @@ -2197,7 +2197,7 @@ namespace qe { void eliminate_exists_bind(unsigned num_vars, app* const* vars, expr_ref& fml) { checkpoint(); app_ref_vector free_vars(m); - eliminate_exists(num_vars, vars, fml, free_vars, false, 0); + eliminate_exists(num_vars, vars, fml, free_vars, false, nullptr); bind_variables(free_vars.size(), free_vars.c_ptr(), fml); } @@ -2219,7 +2219,7 @@ namespace qe { m_fparams(fp), m_params(p), m_trail(m), - m_qe(0), + m_qe(nullptr), m_assumption(m.mk_true()) { } @@ -2302,7 +2302,7 @@ namespace qe { m_trail.push_back(result); todo.push_back(result); - expr* e = 0, *r = 0; + expr* e = nullptr, *r = nullptr; while (!todo.empty()) { e = todo.back(); @@ -2472,8 +2472,8 @@ namespace qe { public: simplify_solver_context(ast_manager& m): m(m), - m_vars(0), - m_fml(0) + m_vars(nullptr), + m_fml(nullptr) { add_plugin(mk_bool_plugin(*this)); add_plugin(mk_arith_plugin(*this, false, m_fparams)); @@ -2543,7 +2543,7 @@ namespace qe { } // callback to add constraints in branch. - void add_constraint(bool use_var, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) override { + void add_constraint(bool use_var, expr* l1 = nullptr, expr* l2 = nullptr, expr* l3 = nullptr) override { UNREACHABLE(); } // eliminate finite domain variable 'var' from fml. @@ -2605,7 +2605,7 @@ namespace qe { } m_ctx.solve(result, vars); if (old_q->is_forall()) { - expr* e = 0; + expr* e = nullptr; result = m.is_not(result, e)?e:mk_not(m, result); } var_shifter shift(m); @@ -2621,7 +2621,7 @@ namespace qe { if (!vars.empty()) { result = m.mk_quantifier(old_q->is_forall(), vars.size(), sorts.c_ptr(), names.c_ptr(), result, 1); } - result_pr = 0; + result_pr = nullptr; return true; } diff --git a/src/qe/qe.h b/src/qe/qe.h index bdce4d159..1027f0b61 100644 --- a/src/qe/qe.h +++ b/src/qe/qe.h @@ -97,7 +97,7 @@ namespace qe { virtual void add_var(app* x) = 0; // callback to add constraints in branch. - virtual void add_constraint(bool use_var, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) = 0; + virtual void add_constraint(bool use_var, expr* l1 = nullptr, expr* l2 = nullptr, expr* l3 = nullptr) = 0; // eliminate finite domain variable 'var' from fml. virtual void blast_or(app* var, expr_ref& fml) = 0; diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 6b3b3a11f..6ea4118a0 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -126,7 +126,7 @@ namespace qe { map values; bool found_eq = false; for (unsigned i = 0; !found_eq && i < to_app(lit)->get_num_args(); ++i) { - expr* arg1 = to_app(lit)->get_arg(i), *arg2 = 0; + expr* arg1 = to_app(lit)->get_arg(i), *arg2 = nullptr; rational r; expr_ref val = eval(arg1); if (!a.is_numeral(val, r)) return false; diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 9e056cdc2..21e50182f 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -891,7 +891,7 @@ namespace qe { while (m_arith.is_add(p)) { bool found_x = false; - expr* next_p = 0; + expr* next_p = nullptr; for (unsigned i = 0; i < to_app(p)->get_num_args(); ++i) { expr* arg = to_app(p)->get_arg(i); if (contains_x(arg)) { @@ -1287,7 +1287,7 @@ namespace qe { m_div_coeffs.reset(); m_div_divisors.reset(); m_div_atoms.reset(); - m_div_z = 0; + m_div_z = nullptr; m_nested_div_terms.reset(); m_nested_div_coeffs.reset(); m_nested_div_divisors.reset(); @@ -1485,7 +1485,7 @@ public: expr* m_term; ptr_vector m_vars; - branch_formula(): m_fml(0), m_var(0), m_branch(0), m_result(0), m_term(0) {} + branch_formula(): m_fml(nullptr), m_var(nullptr), m_branch(0), m_result(nullptr), m_term(nullptr) {} branch_formula(expr* fml, app* var, unsigned b, expr* r, rational coeff, expr* term, app_ref_vector const& vars): m_fml(fml), @@ -1750,7 +1750,7 @@ public: x_subst x_t(m_util); bounds_proc& bounds = get_bounds(x, fml); branch_formula bf; - VERIFY (m_subst.find(branch_formula(fml, x, v, 0, rational::zero(), 0, m_util.m_vars_added), bf)); + VERIFY (m_subst.find(branch_formula(fml, x, v, nullptr, rational::zero(), nullptr, m_util.m_vars_added), bf)); x_t.set_term(bf.m_term); x_t.set_coeff(bf.m_coeff); @@ -1949,7 +1949,7 @@ public: } } assign(x, fml, vl); - subst(x, vl, fml, 0); + subst(x, vl, fml, nullptr); TRACE("qe", tout << mk_pp(fml, m) << "\n";); return true; } @@ -1972,7 +1972,7 @@ public: vl = numeral(0); } assign(x, fml, vl); - subst(x, vl, fml, 0); + subst(x, vl, fml, nullptr); TRACE("qe", tout << mk_pp(fml, m) << "\n";); return true; @@ -2037,7 +2037,7 @@ public: bool get_cache(app* x, expr* fml, unsigned v, expr_ref& result) { branch_formula bf; - if (!m_subst.find(branch_formula(fml, x, v, 0, rational::zero(), 0, m_util.m_vars_added), bf)) { + if (!m_subst.find(branch_formula(fml, x, v, nullptr, rational::zero(), nullptr, m_util.m_vars_added), bf)) { return false; } SASSERT(bf.m_result); @@ -2171,7 +2171,7 @@ public: } bounds_proc& get_bounds(app* x, expr* fml) { - bounds_proc* result = 0; + bounds_proc* result = nullptr; VERIFY (m_bounds_cache.find(x, fml, result)); return *result; } @@ -2407,7 +2407,7 @@ public: } bool update_bounds(contains_app& contains_x, expr* fml) { - bounds_proc* bounds = 0; + bounds_proc* bounds = nullptr; if (m_bounds_cache.find(contains_x.x(), fml, bounds)) { return true; } @@ -2479,7 +2479,7 @@ public: } void assign(contains_app& x, expr* fml, rational const& vl) override { - nlarith::branch_conditions *brs = 0; + nlarith::branch_conditions *brs = nullptr; VERIFY (m_cache.find(x.x(), fml, brs)); SASSERT(vl.is_unsigned()); SASSERT(vl.get_unsigned() < brs->size()); @@ -2516,7 +2516,7 @@ public: } void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override { - nlarith::branch_conditions *brs = 0; + nlarith::branch_conditions *brs = nullptr; VERIFY (m_cache.find(x.x(), fml, brs)); SASSERT(vl.is_unsigned()); SASSERT(vl.get_unsigned() < brs->size()); @@ -2535,7 +2535,7 @@ public: unsigned get_weight(contains_app& x, expr* fml) override { - obj_map* weights = 0; + obj_map* weights = nullptr; unsigned weight = 0; if (!m_weights.find(fml, weights)) { weights = alloc(weight_m); diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 6d0bf82bf..a227d755e 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -39,7 +39,7 @@ namespace qe { imp* m_imp; rw_cfg(ast_manager& m, array_util& a): - m(m), a(a), m_lits(m), m_model(0) {} + m(m), a(a), m_lits(m), m_model(nullptr) {} br_status reduce_app(func_decl* f, unsigned n, expr* const* args, expr_ref& result, proof_ref & pr) { if (a.is_select(f) && a.is_store(args[0])) { diff --git a/src/qe/qe_bool_plugin.cpp b/src/qe/qe_bool_plugin.cpp index eb0553a0e..fba76a7e6 100644 --- a/src/qe/qe_bool_plugin.cpp +++ b/src/qe/qe_bool_plugin.cpp @@ -65,7 +65,7 @@ namespace qe { CTRACE("qe", (!m.is_true(val_x) && !m.is_false(val_x)), tout << "Boolean is a don't care: " << mk_pp(x.x(), m) << "\n";); val = m.is_true(val_x)?rational::one():rational::zero(); - subst(x, val, fml, 0); + subst(x, val, fml, nullptr); return true; } diff --git a/src/qe/qe_bv_plugin.cpp b/src/qe/qe_bv_plugin.cpp index ef87f235f..603004020 100644 --- a/src/qe/qe_bv_plugin.cpp +++ b/src/qe/qe_bv_plugin.cpp @@ -61,7 +61,7 @@ namespace qe { unsigned bv_size; model_eval(x.x(), val_x); m_bv.is_numeral(val_x, val, bv_size); - subst(x, val, fml, 0); + subst(x, val, fml, nullptr); return true; } diff --git a/src/qe/qe_cmd.cpp b/src/qe/qe_cmd.cpp index eb119ce0b..f708d5223 100644 --- a/src/qe/qe_cmd.cpp +++ b/src/qe/qe_cmd.cpp @@ -31,11 +31,11 @@ public: void prepare(cmd_context & ctx) override { parametric_cmd::prepare(ctx); - m_target = 0; + m_target = nullptr; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - if (m_target == 0) return CPK_EXPR; + if (m_target == nullptr) return CPK_EXPR; return parametric_cmd::next_arg_kind(ctx); } diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index 0bfe82751..58878d067 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -389,7 +389,7 @@ namespace qe { conj.push_back(m.mk_eq(l_i, r_i)); } expr* e = m.mk_and(conj.size(), conj.c_ptr()); - m_map.insert(a, e, 0); + m_map.insert(a, e, nullptr); TRACE("qe", tout << "replace: " << mk_pp(a, m) << " ==> \n" << mk_pp(e, m) << "\n";); return true; } @@ -521,7 +521,7 @@ namespace qe { // replace x by C(y1,..,yn) where y1,..,yn are fresh variables. // void subst_constructor(contains_app& x, func_decl* c, expr_ref& fml, expr_ref* def) { - subst_clos* sub = 0; + subst_clos* sub = nullptr; if (m_subst_cache.find(x.x(), c, sub)) { m_replace.apply_substitution(x.x(), sub->first, fml); @@ -588,7 +588,7 @@ namespace qe { unsigned sz = m_datatype_util.get_datatype_num_constructors(s); num_branches = rational(sz); - func_decl* c = 0, *r = 0; + func_decl* c = nullptr, *r = nullptr; // // If 'x' does not yet have a recognizer, then branch according to recognizers. @@ -620,7 +620,7 @@ namespace qe { void assign_rec(contains_app& contains_x, expr* fml, rational const& vl) { app* x = contains_x.x(); sort* s = x->get_decl()->get_range(); - func_decl* c = 0, *r = 0; + func_decl* c = nullptr, *r = nullptr; // // If 'x' does not yet have a recognizer, then branch according to recognizers. @@ -665,7 +665,7 @@ namespace qe { app* x = contains_x.x(); sort* s = x->get_decl()->get_range(); SASSERT(m_datatype_util.is_datatype(s)); - func_decl* c = 0, *r = 0; + func_decl* c = nullptr, *r = nullptr; TRACE("qe", tout << mk_pp(x, m) << " " << vl << " " << mk_pp(fml, m) << " " << (def != 0) << "\n";); // @@ -748,7 +748,7 @@ namespace qe { sort* s = x.x()->get_decl()->get_range(); unsigned sz = m_datatype_util.get_datatype_num_constructors(s); num_branches = rational(sz); - func_decl* c = 0, *r = 0; + func_decl* c = nullptr, *r = nullptr; if (sz != 1 && has_recognizer(x.x(), fml, r, c)) { TRACE("qe", tout << mk_pp(x.x(), m) << " has a recognizer\n";); @@ -768,7 +768,7 @@ namespace qe { if (sz == 1) { return; } - func_decl* c = 0, *r = 0; + func_decl* c = nullptr, *r = nullptr; if (has_recognizer(x, fml, r, c)) { TRACE("qe", tout << mk_pp(x, m) << " has a recognizer\n";); return; @@ -787,7 +787,7 @@ namespace qe { sort* s = x.x()->get_decl()->get_range(); SASSERT(m_datatype_util.is_datatype(s)); SASSERT(!m_datatype_util.is_recursive(s)); - func_decl* c = 0, *r = 0; + func_decl* c = nullptr, *r = nullptr; if (has_recognizer(x.x(), fml, r, c)) { TRACE("qe", tout << mk_pp(x.x(), m) << " has a recognizer\n";); } @@ -824,13 +824,13 @@ namespace qe { } datatype_atoms& get_eqs(app* x, expr* fml) { - datatype_atoms* eqs = 0; + datatype_atoms* eqs = nullptr; VERIFY (m_eqs_cache.find(x, fml, eqs)); return *eqs; } bool update_eqs(contains_app& contains_x, expr* fml) { - datatype_atoms* eqs = 0; + datatype_atoms* eqs = nullptr; if (m_eqs_cache.find(contains_x.x(), fml, eqs)) { return true; } diff --git a/src/qe/qe_dl_plugin.cpp b/src/qe/qe_dl_plugin.cpp index 714540e41..8d688d80c 100644 --- a/src/qe/qe_dl_plugin.cpp +++ b/src/qe/qe_dl_plugin.cpp @@ -107,7 +107,7 @@ namespace qe { subst_large_domain(x, eqs, uv, fml); } if (def) { - *def = 0; // TBD + *def = nullptr; // TBD } } @@ -169,13 +169,13 @@ namespace qe { eq_atoms& get_eqs(app* x, expr* fml) { - eq_atoms* eqs = 0; + eq_atoms* eqs = nullptr; VERIFY(m_eqs_cache.find(x, fml, eqs)); return *eqs; } bool update_eqs(contains_app& contains_x, expr* fml) { - eq_atoms* eqs = 0; + eq_atoms* eqs = nullptr; if (m_eqs_cache.find(contains_x.x(), fml, eqs)) { return true; } diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 678c5e29b..8cbf6c70f 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -88,7 +88,7 @@ namespace eq { for (unsigned i = 0; i < definitions.size(); i++) { var * v = vars[i]; expr * t = definitions[i]; - if (t == 0 || has_quantifiers(t) || occurs_var(v->get_idx(), t)) + if (t == nullptr || has_quantifiers(t) || occurs_var(v->get_idx(), t)) definitions[i] = 0; else found = true; // found at least one candidate @@ -442,7 +442,7 @@ namespace eq { void create_substitution(unsigned sz) { m_subst_map.reset(); - m_subst_map.resize(sz, 0); + m_subst_map.resize(sz, nullptr); for (unsigned i = 0; i < m_order.size(); i++) { expr_ref cur(m_map[m_order[i]], m); // do all the previous substitutions before inserting @@ -544,7 +544,7 @@ namespace eq { } if (m.proofs_enabled()) { - pr = r == q ? 0 : m.mk_der(q, r); + pr = r == q ? nullptr : m.mk_der(q, r); } } @@ -776,7 +776,7 @@ namespace eq { m(m), a(m), dt(m), - m_is_variable(0), + m_is_variable(nullptr), m_subst(m), m_new_exprs(m), m_subst_map(m), @@ -788,7 +788,7 @@ namespace eq { void operator()(quantifier * q, expr_ref & r, proof_ref & pr) { TRACE("qe_lite", tout << mk_pp(q, m) << "\n";); - pr = 0; + pr = nullptr; r = q; reduce_quantifier(q, r, pr); if (r != q) { @@ -955,7 +955,7 @@ namespace ar { public: - der(ast_manager& m): m(m), a(m), m_is_variable(0) {} + der(ast_manager& m): m(m), a(m), m_is_variable(nullptr) {} void operator()(expr_ref_vector& fmls) { for (unsigned i = 0; i < fmls.size(); ++i) { @@ -1473,7 +1473,7 @@ namespace fm { fm(ast_manager & _m): m(_m), - m_is_variable(0), + m_is_variable(nullptr), m_allocator("fm-elim"), m_util(m), m_bvar2expr(m), @@ -1534,7 +1534,7 @@ namespace fm { reset_constraints(); m_bvar2expr.reset(); m_bvar2sign.reset(); - m_bvar2expr.push_back(0); // bvar 0 is not used + m_bvar2expr.push_back(nullptr); // bvar 0 is not used m_bvar2sign.push_back(0); m_expr2var.reset(); m_is_int.reset(); @@ -1547,7 +1547,7 @@ namespace fm { m_new_fmls.reset(); m_counter = 0; m_inconsistent = false; - m_inconsistent_core = 0; + m_inconsistent_core = nullptr; init_forbidden_set(g); } @@ -1583,7 +1583,7 @@ namespace fm { // 0 <= 0 -- > true if (c.m_c.is_pos() || (!c.m_strict && c.m_c.is_zero())) return m.mk_true(); - ineq = 0; + ineq = nullptr; } else { bool int_cnstr = all_int(c); @@ -1833,7 +1833,7 @@ namespace fm { for (unsigned i = 0; !m_inconsistent && i < sz; i++) { expr * f = g[i]; if (is_occ(f)) - add_constraint(f, 0); + add_constraint(f, nullptr); else m_new_fmls.push_back(f); } @@ -2065,7 +2065,7 @@ namespace fm { display(tout, l); tout << "\n"; display(tout, u); tout << "\n";); - return 0; // no constraint needs to be created. + return nullptr; // no constraint needs to be created. } new_lits.reset(); @@ -2109,7 +2109,7 @@ namespace fm { display(tout, l); tout << "\n"; display(tout, u); tout << "\n";); - return 0; + return nullptr; } expr_dependency * new_dep = m.mk_join(l.m_dep, u.m_dep); @@ -2121,7 +2121,7 @@ namespace fm { display(tout, u); tout << "\n";); m_inconsistent = true; m_inconsistent_core = new_dep; - return 0; + return nullptr; } constraint * new_cnstr = mk_constraint(new_lits.size(), @@ -2191,7 +2191,7 @@ namespace fm { constraint const & l_c = *(l[i]); constraint const & u_c = *(u[j]); constraint * new_c = resolve(l_c, u_c, x); - if (new_c != 0) { + if (new_c != nullptr) { num_new_cnstrs++; new_constraints.push_back(new_c); } @@ -2560,7 +2560,7 @@ class qe_lite_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("qe-lite", *g); proof_ref new_pr(m); expr_ref new_f(m); diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 329687a36..432569ff9 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -71,7 +71,7 @@ expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) { vals.push_back(val); } UNREACHABLE(); - return expr_ref(0, m); + return expr_ref(nullptr, m); } void project_plugin::partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits) { diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 547f6bad1..4c56b74a7 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -149,7 +149,7 @@ namespace qe { } // callback to add constraints in branch. - void add_constraint(bool use_var, expr* l1 = 0, expr* l2 = 0, expr* l3 = 0) override { + void add_constraint(bool use_var, expr* l1 = nullptr, expr* l2 = nullptr, expr* l3 = nullptr) override { ptr_buffer args; if (l1) args.push_back(l1); if (l2) args.push_back(l2); @@ -179,7 +179,7 @@ namespace qe { m_super.m_rewriter(m_fml); TRACE("qe", model_v2_pp(tout, *model); tout << "\n"; tout << mk_pp(m_fml, m) << "\n";); - elim_var(i, m_fml, 0); + elim_var(i, m_fml, nullptr); } void project_var_full(unsigned i) { @@ -191,7 +191,7 @@ namespace qe { m_fml = result; m_super.m_rewriter(m_fml); TRACE("qe", tout << mk_pp(m_fml, m) << "\n";); - elim_var(i, m_fml, 0); + elim_var(i, m_fml, nullptr); } void project_var(unsigned i) { @@ -329,7 +329,7 @@ namespace qe { for (unsigned i = 0; i < m_solvers.size(); ++i) { dealloc(m_solvers[i]); } - m_fml = 0; + m_fml = nullptr; m_Ms.reset(); m_fparamv.reset(); m_solvers.reset(); diff --git a/src/qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp index 5a8c3061c..fab1f3382 100644 --- a/src/qe/qe_tactic.cpp +++ b/src/qe/qe_tactic.cpp @@ -56,7 +56,7 @@ class qe_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("qe", *g); m_fparams.m_model = g->models_enabled(); proof_ref new_pr(m); @@ -72,7 +72,7 @@ class qe_tactic : public tactic { if (!has_quantifiers(f)) continue; m_qe(m.mk_true(), f, new_f); - new_pr = 0; + new_pr = nullptr; if (produce_proofs) { new_pr = m.mk_modus_ponens(g->pr(i), new_pr); } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 6d470c5de..f463a62e5 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -706,7 +706,7 @@ namespace qe { m_asms.reset(); m_pred_abs.reset(); m_vars.reset(); - m_model = 0; + m_model = nullptr; m_fa.reset(); m_ex.reset(); m_free_vars.reset(); @@ -956,7 +956,7 @@ namespace qe { ptr_vector todo; trail.push_back(fml); todo.push_back(fml); - expr* e = 0, *r = 0; + expr* e = nullptr, *r = nullptr; while (!todo.empty()) { check_cancel(); @@ -1196,8 +1196,8 @@ namespace qe { m_mode(mode), m_avars(m), m_free_vars(m), - m_objective(0), - m_value(0), + m_objective(nullptr), + m_value(nullptr), m_was_sat(false), m_gt(m) { @@ -1224,7 +1224,7 @@ namespace qe { ptr_vector fmls; expr_ref_vector defs(m); expr_ref fml(m); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; in->get_formulas(fmls); diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 76a1ee8c3..67f894566 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -105,7 +105,7 @@ namespace sat { void tmp_clause::set(unsigned num_lits, literal const * lits, bool learned) { if (m_clause && m_clause->m_capacity < num_lits) { dealloc_svect(m_clause); - m_clause = 0; + m_clause = nullptr; } if (!m_clause) { void * mem = alloc_svect(char, clause::get_obj_size(num_lits)); diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 5ad08e52a..b7cf5e577 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -115,7 +115,7 @@ namespace sat { class tmp_clause { clause * m_clause; public: - tmp_clause():m_clause(0) {} + tmp_clause():m_clause(nullptr) {} ~tmp_clause() { if (m_clause) dealloc_svect(m_clause); } clause * get() const { return m_clause; } void set(unsigned num_lits, literal const * lits, bool learned); diff --git a/src/sat/sat_probing.cpp b/src/sat/sat_probing.cpp index b23d57164..57b09c7f7 100644 --- a/src/sat/sat_probing.cpp +++ b/src/sat/sat_probing.cpp @@ -60,7 +60,7 @@ namespace sat { bool probing::try_lit(literal l, bool updt_cache) { SASSERT(s.m_qhead == s.m_trail.size()); SASSERT(s.value(l.var()) == l_undef); - literal_vector * implied_lits = updt_cache ? 0 : cached_implied_lits(l); + literal_vector * implied_lits = updt_cache ? nullptr : cached_implied_lits(l); if (implied_lits) { literal_vector::iterator it = implied_lits->begin(); literal_vector::iterator end = implied_lits->end(); diff --git a/src/sat/sat_probing.h b/src/sat/sat_probing.h index fb9b1dd30..2e1f97909 100644 --- a/src/sat/sat_probing.h +++ b/src/sat/sat_probing.h @@ -77,10 +77,10 @@ namespace sat { // return the literals implied by l. // return 0, if the cache is not available literal_vector * cached_implied_lits(literal l) { - if (!m_probing_cache) return 0; - if (l.index() >= m_cached_bins.size()) return 0; + if (!m_probing_cache) return nullptr; + if (l.index() >= m_cached_bins.size()) return nullptr; cache_entry & e = m_cached_bins[l.index()]; - if (!e.m_available) return 0; + if (!e.m_available) return nullptr; return &(e.m_lits); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 84534bf3f..432903b4c 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -949,7 +949,7 @@ namespace sat { void process(literal l) { TRACE("blocked_clause", tout << "processing: " << l << "\n";); - model_converter::entry * new_entry = 0; + model_converter::entry * new_entry = nullptr; if (!process_var(l.var())) { return; } @@ -965,7 +965,7 @@ namespace sat { s.mark_all_but(c, l); if (all_tautology(l)) { TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); - if (new_entry == 0) + if (new_entry == nullptr) new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); m_to_remove.push_back(&c); s.m_num_blocked_clauses++; @@ -1003,7 +1003,7 @@ namespace sat { literal l2 = it->get_literal(); s.mark_visited(l2); if (all_tautology(l)) { - if (new_entry == 0) + if (new_entry == nullptr) new_entry = &(mc.mk(model_converter::BLOCK_LIT, l.var())); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l << "\n";); s.remove_bin_clause_half(l2, l, it->is_learned()); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index dbd996cd0..a3d190854 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -36,7 +36,7 @@ namespace sat { m_checkpoint_enabled(true), m_config(p), m_ext(ext), - m_par(0), + m_par(nullptr), m_cleaner(*this), m_simplifier(*this, p), m_scc(*this, p), @@ -198,7 +198,7 @@ namespace sat { bool keep = simplify_clause(num_lits, lits); TRACE("sat_mk_clause", tout << "mk_clause (after simp), keep: " << keep << "\n" << mk_lits_pp(num_lits, lits) << "\n";); if (!keep) { - return 0; // clause is equivalent to true. + return nullptr; // clause is equivalent to true. } ++m_stats.m_non_learned_generation; } @@ -206,13 +206,13 @@ namespace sat { switch (num_lits) { case 0: set_conflict(justification()); - return 0; + return nullptr; case 1: assign(lits[0], justification()); - return 0; + return nullptr; case 2: mk_bin_clause(lits[0], lits[1], learned); - return 0; + return nullptr; case 3: return mk_ter_clause(lits, learned); default: @@ -815,7 +815,7 @@ namespace sat { if (i == 1 + num_threads/2) { m_params.set_sym("phase", symbol("random")); } - solvers[i] = alloc(sat::solver, m_params, rlims[i], 0); + solvers[i] = alloc(sat::solver, m_params, rlims[i], nullptr); solvers[i]->copy(*this); solvers[i]->set_par(&par); scoped_rlimit.push_child(&solvers[i]->rlimit()); @@ -874,7 +874,7 @@ namespace sat { } } } - set_par(0); + set_par(nullptr); if (finished_id != -1 && finished_id < num_extra_solvers) { m_stats = solvers[finished_id]->m_stats; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c275b8ee2..7f5a02ab3 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -315,7 +315,7 @@ namespace sat { // // ----------------------- public: - lbool check(unsigned num_lits = 0, literal const* lits = 0); + lbool check(unsigned num_lits = 0, literal const* lits = nullptr); model const & get_model() const { return m_model; } bool model_is_current() const { return m_model_is_current; } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0b0ef24d2..453fff417 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -68,7 +68,7 @@ class inc_sat_solver : public solver { typedef obj_map dep2asm_t; public: inc_sat_solver(ast_manager& m, params_ref const& p): - m(m), m_solver(p, m.limit(), 0), + m(m), m_solver(p, m.limit(), nullptr), m_optimize_model(false), m_fmls(m), m_asmsf(m), @@ -106,7 +106,7 @@ public: void set_progress_callback(progress_callback * callback) override {} void display_weighted(std::ostream& out, unsigned sz, expr * const * assumptions, unsigned const* weights) { - if (weights != 0) { + if (weights != nullptr) { for (unsigned i = 0; i < sz; ++i) m_weights.push_back(weights[i]); } init_preprocess(); @@ -155,7 +155,7 @@ public: TRACE("sat", tout << _assumptions << "\n";); dep2asm_t dep2asm; - m_model = 0; + m_model = nullptr; lbool r = internalize_formulas(); if (r != l_true) return r; r = internalize_assumptions(sz, _assumptions.c_ptr(), dep2asm); @@ -258,7 +258,7 @@ public: } proof * get_proof() override { UNREACHABLE(); - return 0; + return nullptr; } lbool get_consequences_core(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq) override { @@ -403,8 +403,8 @@ private: catch (tactic_exception & ex) { IF_VERBOSE(0, verbose_stream() << "exception in tactic " << ex.msg() << "\n";); TRACE("sat", tout << "exception: " << ex.msg() << "\n";); - m_preprocess = 0; - m_bb_rewriter = 0; + m_preprocess = nullptr; + m_bb_rewriter = nullptr; return l_undef; } if (m_subgoals.size() != 1) { @@ -515,7 +515,7 @@ private: expr_ref_vector conj(m); internalize_value(value, v, val); while (!premises.empty()) { - expr* e = 0; + expr* e = nullptr; VERIFY(asm2dep.find(premises.pop().index(), e)); conj.push_back(e); } @@ -616,7 +616,7 @@ private: m_core.reset(); for (unsigned i = 0; i < core.size(); ++i) { - expr* e = 0; + expr* e = nullptr; VERIFY(asm2dep.find(core[i].index(), e)); if (asm2fml.contains(e)) { e = asm2fml.find(e); @@ -643,7 +643,7 @@ private: void extract_model() { TRACE("sat", tout << "retrieve model " << (m_solver.model_is_current()?"present":"absent") << "\n";); if (!m_solver.model_is_current()) { - m_model = 0; + m_model = nullptr; return; } sat::model const & ll_m = m_solver.get_model(); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index bb5907003..5a16d5e8c 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -525,7 +525,7 @@ bool goal2sat::has_unsupported_bool(goal const & g) { return test(g); } -goal2sat::goal2sat():m_imp(0), m_interpreted_atoms(0) { +goal2sat::goal2sat():m_imp(nullptr), m_interpreted_atoms(nullptr) { } void goal2sat::collect_param_descrs(param_descrs & r) { @@ -539,7 +539,7 @@ struct goal2sat::scoped_set_imp { m_owner->m_imp = i; } ~scoped_set_imp() { - m_owner->m_imp = 0; + m_owner->m_imp = nullptr; } }; @@ -703,9 +703,9 @@ struct sat2goal::imp { for (sat::bool_var v = 0; v < num_vars; v++) { checkpoint(); sat::literal l(v, false); - if (m_lit2expr.get(l.index()) == 0) { + if (m_lit2expr.get(l.index()) == nullptr) { SASSERT(m_lit2expr.get((~l).index()) == 0); - app * aux = m.mk_fresh_const(0, b); + app * aux = m.mk_fresh_const(nullptr, b); if (_mc) _mc->insert(aux, true); m_lit2expr.set(l.index(), aux); @@ -776,7 +776,7 @@ struct sat2goal::imp { }; -sat2goal::sat2goal():m_imp(0) { +sat2goal::sat2goal():m_imp(nullptr) { } void sat2goal::collect_param_descrs(param_descrs & r) { @@ -790,7 +790,7 @@ struct sat2goal::scoped_set_imp { m_owner->m_imp = i; } ~scoped_set_imp() { - m_owner->m_imp = 0; + m_owner->m_imp = nullptr; } }; diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 3db379cb1..4bb644a43 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -34,7 +34,7 @@ class sat_tactic : public tactic { imp(ast_manager & _m, params_ref const & p): m(_m), - m_solver(p, m.limit(), 0), + m_solver(p, m.limit(), nullptr), m_params(p) { SASSERT(!m.proofs_enabled()); } @@ -44,7 +44,7 @@ class sat_tactic : public tactic { model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; fail_if_proof_generation("sat", g); bool produce_models = g->models_enabled(); bool produce_core = g->unsat_core_enabled(); @@ -74,7 +74,7 @@ class sat_tactic : public tactic { } } if (r == l_false) { - expr_dependency * lcore = 0; + expr_dependency * lcore = nullptr; if (produce_core) { sat::literal_vector const& ucore = m_solver.get_core(); u_map asm2dep; @@ -85,7 +85,7 @@ class sat_tactic : public tactic { lcore = m.mk_join(lcore, m.mk_leaf(dep)); } } - g->assert_expr(m.mk_false(), 0, lcore); + g->assert_expr(m.mk_false(), nullptr, lcore); } else if (r == l_true && !map.interpreted_atoms()) { // register model @@ -148,7 +148,7 @@ class sat_tactic : public tactic { } ~scoped_set_imp() { - m_owner->m_imp = 0; + m_owner->m_imp = nullptr; } }; @@ -158,7 +158,7 @@ class sat_tactic : public tactic { public: sat_tactic(ast_manager & m, params_ref const & p): - m_imp(0), + m_imp(nullptr), m_params(p) { } diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index b2b181977..427c1015f 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -41,7 +41,7 @@ static stopwatch g_overall_time; static stopwatch g_piece_timer; static unsigned t_parsing = 0; -static datalog::context * g_ctx = 0; +static datalog::context * g_ctx = nullptr; static datalog::rule_set * g_orig_rules; static datalog::instruction_block * g_code; static datalog::execution_context * g_ectx; @@ -257,7 +257,7 @@ unsigned read_datalog(char const * file) { true); return ERR_MEMOUT; } - register_on_timeout_proc(0); + register_on_timeout_proc(nullptr); return 0; } diff --git a/src/shell/dimacs_frontend.cpp b/src/shell/dimacs_frontend.cpp index 999574f1e..eafaa8960 100644 --- a/src/shell/dimacs_frontend.cpp +++ b/src/shell/dimacs_frontend.cpp @@ -26,7 +26,7 @@ Revision History: #include "util/gparams.h" extern bool g_display_statistics; -static sat::solver * g_solver = 0; +static sat::solver * g_solver = nullptr; static clock_t g_start_time; static void display_statistics() { @@ -134,7 +134,7 @@ unsigned read_dimacs(char const * file_name) { params_ref p = gparams::get_module("sat"); p.set_bool("produce_models", true); reslimit limit; - sat::solver solver(p, limit, 0); + sat::solver solver(p, limit, nullptr); g_solver = &solver; if (file_name) { @@ -152,7 +152,7 @@ unsigned read_dimacs(char const * file_name) { lbool r; vector tracking_clauses; - sat::solver solver2(p, limit, 0); + sat::solver solver2(p, limit, nullptr); if (p.get_bool("dimacs.core", false)) { g_solver = &solver2; sat::literal_vector assumptions; diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index c1afd5e13..c79396cd1 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -17,7 +17,7 @@ Author: #include "util/gparams.h" #include -static lp::lp_solver* g_solver = 0; +static lp::lp_solver* g_solver = nullptr; static void display_statistics() { if (g_solver && g_solver->settings().print_statistics) { @@ -95,8 +95,8 @@ void run_solver(lp_params & params, char const * mps_file_name) { // #pragma omp critical (g_display_stats) { display_statistics(); - register_on_timeout_proc(0); - g_solver = 0; + register_on_timeout_proc(nullptr); + g_solver = nullptr; } delete solver; } diff --git a/src/shell/main.cpp b/src/shell/main.cpp index f0e640d66..40c98a686 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -41,7 +41,7 @@ Revision History: typedef enum { IN_UNSPECIFIED, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_Z3_LOG, IN_MPS } input_kind; std::string g_aux_input_file; -char const * g_input_file = 0; +char const * g_input_file = nullptr; bool g_standard_input = false; input_kind g_input_kind = IN_UNSPECIFIED; bool g_display_statistics = false; @@ -113,7 +113,7 @@ void display_usage() { void parse_cmd_line_args(int argc, char ** argv) { int i = 1; - char * eq_pos = 0; + char * eq_pos = nullptr; while (i < argc) { char * arg = argv[i]; @@ -145,7 +145,7 @@ void parse_cmd_line_args(int argc, char ** argv) { // allow names such as --help if (*opt_name == '-') opt_name++; - char * opt_arg = 0; + char * opt_arg = nullptr; char * colon = strchr(arg, ':'); if (colon) { opt_arg = colon + 1; @@ -200,7 +200,7 @@ void parse_cmd_line_args(int argc, char ** argv) { else if (strcmp(opt_name, "v") == 0) { if (!opt_arg) error("option argument (-v:level) is missing."); - long lvl = strtol(opt_arg, 0, 10); + long lvl = strtol(opt_arg, nullptr, 10); set_verbosity_level(lvl); } else if (strcmp(opt_name, "file") == 0) { @@ -209,7 +209,7 @@ void parse_cmd_line_args(int argc, char ** argv) { else if (strcmp(opt_name, "T") == 0) { if (!opt_arg) error("option argument (-T:timeout) is missing."); - long tm = strtol(opt_arg, 0, 10); + long tm = strtol(opt_arg, nullptr, 10); set_timeout(tm * 1000); } else if (strcmp(opt_name, "t") == 0) { diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 8154cbde4..714188505 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -17,7 +17,7 @@ Copyright (c) 2015 Microsoft Corporation extern bool g_display_statistics; static bool g_first_interrupt = true; -static opt::context* g_opt = 0; +static opt::context* g_opt = nullptr; static double g_start_time = 0; static unsigned_vector g_handles; @@ -115,8 +115,8 @@ static unsigned parse_opt(std::istream& in, bool is_wcnf) { #pragma omp critical (g_display_stats) { display_statistics(); - register_on_timeout_proc(0); - g_opt = 0; + register_on_timeout_proc(nullptr); + g_opt = nullptr; } return 0; } diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 8c716a81a..7218558fa 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -34,7 +34,7 @@ Revision History: extern bool g_display_statistics; static clock_t g_start_time; -static cmd_context * g_cmd_context = 0; +static cmd_context * g_cmd_context = nullptr; static void display_statistics() { clock_t end_time = clock(); @@ -102,7 +102,7 @@ unsigned read_smtlib2_commands(char const * file_name) { #pragma omp critical (g_display_stats) { display_statistics(); - g_cmd_context = 0; + g_cmd_context = nullptr; } return result ? 0 : 1; } diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index febec9565..593eb1d71 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -154,8 +154,8 @@ namespace smt { // Requires that the theory arithmetic internalizer accept non simplified terms of the form t1 - t2 // if t1 and t2 already have slacks (theory variables) associated with them. // It also accepts terms with repeated variables (Issue #429). - app * le = 0; - app * ge = 0; + app * le = nullptr; + app * ge = nullptr; if (m_util.is_numeral(t1)) std::swap(t1, t2); if (m_util.is_numeral(t2)) { diff --git a/src/smt/arith_eq_adapter.h b/src/smt/arith_eq_adapter.h index 4a8a293e3..42aae6821 100644 --- a/src/smt/arith_eq_adapter.h +++ b/src/smt/arith_eq_adapter.h @@ -53,7 +53,7 @@ namespace smt { expr * m_t1_eq_t2; expr * m_le; expr * m_ge; - data():m_t1_eq_t2(0), m_le(0), m_ge(0) {} + data():m_t1_eq_t2(nullptr), m_le(nullptr), m_ge(nullptr) {} data(expr * t1_eq_t2, expr * le, expr * ge):m_t1_eq_t2(t1_eq_t2), m_le(le), m_ge(ge) {} }; diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 6ddce341d..465371434 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -90,7 +90,7 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vectorget_num_args(); ++i) { expr* arg = to_app(e)->get_arg(i); - proof_ref _pr(m.proofs_enabled() ? m.mk_and_elim(pr, i) : 0, m); + proof_ref _pr(m.proofs_enabled() ? m.mk_and_elim(pr, i) : nullptr, m); push_assertion(arg, _pr, result); } } else if (m.is_not(e, e1) && m.is_or(e1)) { for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { expr* arg = to_app(e1)->get_arg(i); - proof_ref _pr(m.proofs_enabled() ? m.mk_not_or_elim(pr, i) : 0, m); + proof_ref _pr(m.proofs_enabled() ? m.mk_not_or_elim(pr, i) : nullptr, m); expr_ref narg(mk_not(m, arg), m); push_assertion(narg, _pr, result); } @@ -376,7 +376,7 @@ void asserted_formulas::nnf_cnf() { unsigned sz2 = push_todo.size(); for (unsigned k = 0; k < sz2; k++) { expr * n = push_todo.get(k); - pr = 0; + pr = nullptr; m_rewriter(n, r1, pr1); CASSERT("well_sorted",is_well_sorted(m, r1)); if (canceled()) { @@ -598,15 +598,15 @@ void asserted_formulas::compute_depth(expr* e) { proof * asserted_formulas::get_inconsistency_proof() const { if (!inconsistent()) - return 0; + return nullptr; if (!m.proofs_enabled()) - return 0; + return nullptr; for (justified_expr const& j : m_formulas) { if (m.is_false(j.get_fml())) return j.get_proof(); } UNREACHABLE(); - return 0; + return nullptr; } void asserted_formulas::refine_inj_axiom_fn::simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { diff --git a/src/smt/cached_var_subst.cpp b/src/smt/cached_var_subst.cpp index 7c0997bc5..1f184c39c 100644 --- a/src/smt/cached_var_subst.cpp +++ b/src/smt/cached_var_subst.cpp @@ -44,7 +44,7 @@ void cached_var_subst::reset() { void cached_var_subst::operator()(quantifier * qa, unsigned num_bindings, smt::enode * const * bindings, expr_ref & result) { m_new_keys.reserve(num_bindings+1, 0); key * new_key = m_new_keys[num_bindings]; - if (new_key == 0) + if (new_key == nullptr) new_key = static_cast(m_region.allocate(sizeof(key) + sizeof(expr*)*num_bindings)); new_key->m_qa = qa; @@ -52,7 +52,7 @@ void cached_var_subst::operator()(quantifier * qa, unsigned num_bindings, smt::e for (unsigned i = 0; i < num_bindings; i++) new_key->m_bindings[i] = bindings[i]->get_owner(); - instances::entry * entry = m_instances.insert_if_not_there2(new_key, 0); + instances::entry * entry = m_instances.insert_if_not_there2(new_key, nullptr); if (entry->get_data().m_key != new_key) { SASSERT(entry->get_data().m_value != 0); // entry was already there diff --git a/src/smt/dyn_ack.cpp b/src/smt/dyn_ack.cpp index dd77640bc..a006c9dd5 100644 --- a/src/smt/dyn_ack.cpp +++ b/src/smt/dyn_ack.cpp @@ -299,7 +299,7 @@ namespace smt { TRACE("dyn_ack", tout << "del_clause_eh: "; m_context.display_clause(tout, cls); tout << "\n";); m_context.m_stats.m_num_del_dyn_ack++; - app_pair p((app*)0,(app*)0); + app_pair p((app*)nullptr,(app*)nullptr); if (m_clause2app_pair.find(cls, p)) { SASSERT(p.first && p.second); m_instantiated.erase(p); @@ -371,7 +371,7 @@ namespace smt { lits.push_back(mk_eq(n1, n2)); clause_del_eh * del_eh = alloc(dyn_ack_clause_del_eh, *this); - justification * js = 0; + justification * js = nullptr; if (m_manager.proofs_enabled()) js = alloc(dyn_ack_justification, n1, n2); clause * cls = m_context.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, del_eh); @@ -423,7 +423,7 @@ namespace smt { lits.push_back(mk_eq(n1, n2)); clause_del_eh * del_eh = alloc(dyn_ack_clause_del_eh, *this); - justification * js = 0; + justification * js = nullptr; if (m_manager.proofs_enabled()) js = alloc(dyn_ack_justification, n1, n2); clause * cls = m_context.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, del_eh); diff --git a/src/smt/expr_context_simplifier.cpp b/src/smt/expr_context_simplifier.cpp index c420543e1..bce28420d 100644 --- a/src/smt/expr_context_simplifier.cpp +++ b/src/smt/expr_context_simplifier.cpp @@ -311,7 +311,7 @@ bool expr_context_simplifier::is_false(expr* e) const { // expr_strong_context_simplifier::expr_strong_context_simplifier(smt_params& p, ast_manager& m): - m_manager(m), m_arith(m), m_fn(0,m), m_solver(m, p) { + m_manager(m), m_arith(m), m_fn(nullptr,m), m_solver(m, p) { sort* i_sort = m_arith.mk_int(); m_fn = m.mk_func_decl(symbol(0xbeef101), i_sort, m.mk_bool_sort()); } @@ -358,7 +358,7 @@ void expr_strong_context_simplifier::simplify_basic(expr* fml, expr_ref& result) m_solver.push(); while (!todo.empty()) { - r = 0; + r = nullptr; ptr_buffer args; expr* e = todo.back(); unsigned pos = parent_ids.back(); @@ -405,7 +405,7 @@ void expr_strong_context_simplifier::simplify_basic(expr* fml, expr_ref& result) self_pos = self_ids.back(); sz = a->get_num_args(); - n2 = 0; + n2 = nullptr; for (unsigned i = 0; i < sz; ++i) { expr* arg = a->get_arg(i); @@ -620,7 +620,7 @@ void expr_strong_context_simplifier::simplify_model_based(expr* fml, expr_ref& r m_solver.push(); while (!todo.empty()) { - r = 0; + r = nullptr; ptr_buffer args; expr* e = todo.back(); unsigned pos = parent_ids.back(); @@ -681,7 +681,7 @@ void expr_strong_context_simplifier::simplify_model_based(expr* fml, expr_ref& r self_pos = self_ids.back(); sz = a->get_num_args(); - n2 = 0; + n2 = nullptr; for (unsigned i = 0; i < sz; ++i) { expr* arg = a->get_arg(i); diff --git a/src/smt/fingerprints.cpp b/src/smt/fingerprints.cpp index 435350396..832f539df 100644 --- a/src/smt/fingerprints.cpp +++ b/src/smt/fingerprints.cpp @@ -24,7 +24,7 @@ namespace smt { m_data(d), m_data_hash(d_h), m_num_args(n), - m_args(0) { + m_args(nullptr) { m_args = new (r) enode*[n]; memcpy(m_args, args, sizeof(enode*) * n); } @@ -54,7 +54,7 @@ namespace smt { fingerprint * fingerprint_set::insert(void * data, unsigned data_hash, unsigned num_args, enode * const * args) { fingerprint * d = mk_dummy(data, data_hash, num_args, args); if (m_set.contains(d)) - return 0; + return nullptr; TRACE("fingerprint_bug", tout << "1) inserting: " << data_hash << " num_args: " << num_args; for (unsigned i = 0; i < num_args; i++) tout << " " << args[i]->get_owner_id(); tout << "\n";); @@ -64,7 +64,7 @@ namespace smt { TRACE("fingerprint_bug", tout << "failed: " << data_hash << " num_args: " << num_args; for (unsigned i = 0; i < num_args; i++) tout << " " << d->m_args[i]->get_owner_id(); tout << "\n";); - return 0; + return nullptr; } TRACE("fingerprint_bug", tout << "2) inserting: " << data_hash << " num_args: " << num_args; for (unsigned i = 0; i < num_args; i++) tout << " " << args[i]->get_owner_id(); diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 7fd1dd9d0..5c881684f 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -423,20 +423,20 @@ namespace smt { instruction * curr = head; out << *curr; curr = curr->m_next; - while (curr != 0 && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { + while (curr != nullptr && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { out << "\n"; out << *curr; curr = curr->m_next; } out << "\n"; - if (curr != 0) { + if (curr != nullptr) { display_children(out, static_cast(curr), indent + 1); } } void display_children(std::ostream & out, choose * first_child, unsigned indent) const { choose * curr = first_child; - while (curr != 0) { + while (curr != nullptr) { display_seq(out, curr, indent); curr = curr->m_alt; } @@ -485,7 +485,7 @@ namespace smt { m_filter_candidates(filter_candidates), m_num_regs(num_args + 1), m_num_choices(0), - m_root(0) { + m_root(nullptr) { DEBUG_CODE(m_context = 0;); #ifdef _PROFILE_MAM m_counter = 0; @@ -607,7 +607,7 @@ namespace smt { void * mem = m_region.allocate(size); OP * r = new (mem) OP; r->m_opcode = op; - r->m_next = 0; + r->m_next = nullptr; #ifdef _PROFILE_MAM r->m_counter = 0; #endif @@ -696,7 +696,7 @@ namespace smt { choose * mk_noop() { choose * r = mk_instr(NOOP, sizeof(choose)); - r->m_alt = 0; + r->m_alt = nullptr; return r; } @@ -923,7 +923,7 @@ namespace smt { */ void linearise_core() { m_aux.reset(); - app * first_app = 0; + app * first_app = nullptr; unsigned first_app_reg; unsigned first_app_sz; unsigned first_app_num_unbound_vars; @@ -1111,7 +1111,7 @@ namespace smt { // multi_pattern support for (unsigned i = 1; i < num_args; i++) { // select the pattern with the biggest number of bound variables - app * best = 0; + app * best = nullptr; unsigned best_num_bvars = 0; unsigned best_j = 0; bool found_bounded_mp = false; @@ -1127,7 +1127,7 @@ namespace smt { found_bounded_mp = true; break; } - if (best == 0 || (num_bvars > best_num_bvars)) { + if (best == nullptr || (num_bvars > best_num_bvars)) { best = p; best_num_bvars = num_bvars; best_j = j; @@ -1286,16 +1286,16 @@ namespace smt { choose * find_best_child(choose * first_child) { unsigned num_too_simple = 0; - choose * best_child = 0; + choose * best_child = nullptr; unsigned max_compatibility = 0; choose * curr_child = first_child; - while (curr_child != 0) { + while (curr_child != nullptr) { bool simple = false; unsigned curr_compatibility = get_compatibility_measure(curr_child, simple); if (simple) { num_too_simple++; if (num_too_simple > FIND_BEST_CHILD_THRESHOLD) - return 0; // it is unlikely we will find a compatible node + return nullptr; // it is unlikely we will find a compatible node } if (curr_compatibility > max_compatibility) { best_child = curr_child; @@ -1310,7 +1310,7 @@ namespace smt { unsigned ireg = instr->m_ireg; expr * n = m_registers[ireg]; return - n != 0 && + n != nullptr && is_app(n) && // It is wasteful to use a bind of a ground term. // Actually, in the rest of the code I assume that. @@ -1450,7 +1450,7 @@ namespace smt { unsigned weight = 0; unsigned num_instr = 0; instruction * curr = child->m_next; - while (curr != 0 && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { + while (curr != nullptr && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { num_instr++; switch (curr->m_opcode) { case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: @@ -1493,7 +1493,7 @@ namespace smt { } curr = curr->m_next; } - if (num_instr > SIMPLE_SEQ_THRESHOLD || (curr != 0 && curr->m_opcode == CHOOSE)) + if (num_instr > SIMPLE_SEQ_THRESHOLD || (curr != nullptr && curr->m_opcode == CHOOSE)) simple = false; unsigned_vector::iterator it = m_to_reset.begin(); unsigned_vector::iterator end = m_to_reset.end(); @@ -1509,7 +1509,7 @@ namespace smt { TRACE("mam_compiler_detail", tout << "processing head: " << *head << "\n";); instruction * curr = head->m_next; instruction * last = head; - while (curr != 0 && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { + while (curr != nullptr && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { TRACE("mam_compiler_detail", tout << "processing instr: " << *curr << "\n";); switch (curr->m_opcode) { case BIND1: case BIND2: case BIND3: case BIND4: case BIND5: case BIND6: case BINDN: @@ -1680,7 +1680,7 @@ namespace smt { SASSERT(curr->m_opcode == CHOOSE); choose * first_child = static_cast(curr); choose * best_child = find_best_child(first_child); - if (best_child == 0) { + if (best_child == nullptr) { // There is no compatible child // Suppose the sequence is: // head -> c1 -> ... -> (cn == last) -> first_child; @@ -1902,7 +1902,7 @@ namespace smt { curr = curr->get_next(); } while (curr != first); - return 0; + return nullptr; } enode * get_next_f_app(func_decl * lbl, unsigned num_expected_args, enode * first, enode * curr) { @@ -1914,7 +1914,7 @@ namespace smt { } curr = curr->get_next(); } - return 0; + return nullptr; } /** @@ -2094,7 +2094,7 @@ namespace smt { enode_vector * interpreter::mk_depth2_vector(joint2 * j2, func_decl * f, unsigned i) { enode * n = m_registers[j2->m_reg]->get_root(); if (n->get_num_parents() == 0) - return 0; + return nullptr; unsigned num_args = n->get_num_args(); enode_vector * v = mk_enode_vector(); enode_vector::const_iterator it1 = n->begin_parents(); @@ -2132,7 +2132,7 @@ namespace smt { // quick filter... check if any of the joint points have zero parents... for (unsigned i = 0; i < num_args; i++) { void * bare = c->m_joints[i]; - enode * n = 0; + enode * n = nullptr; switch (GET_TAG(bare)) { case NULL_TAG: goto non_depth1; @@ -2147,20 +2147,20 @@ namespace smt { } r = n->get_root(); if (m_use_filters && r->get_plbls().empty_intersection(c->m_lbl_set)) - return 0; + return nullptr; if (r->get_num_parents() == 0) - return 0; + return nullptr; non_depth1: ; } // traverse each joint and select the best one. - enode_vector * best_v = 0; + enode_vector * best_v = nullptr; for (unsigned i = 0; i < num_args; i++) { enode * bare = c->m_joints[i]; - enode_vector * curr_v = 0; + enode_vector * curr_v = nullptr; switch (GET_TAG(bare)) { case NULL_TAG: - curr_v = 0; + curr_v = nullptr; break; case GROUND_TERM_TAG: curr_v = mk_depth1_vector(UNTAG(enode *, bare), lbl, i); @@ -2172,14 +2172,14 @@ namespace smt { curr_v = mk_depth2_vector(UNTAG(joint2 *, bare), lbl, i); break; } - if (curr_v != 0) { - if (curr_v->size() < min_sz && (best_v == 0 || curr_v->size() < best_v->size())) { + if (curr_v != nullptr) { + if (curr_v->size() < min_sz && (best_v == nullptr || curr_v->size() < best_v->size())) { if (best_v) recycle_enode_vector(best_v); best_v = curr_v; if (best_v->empty()) { recycle_enode_vector(best_v); - return 0; + return nullptr; } } else { @@ -2191,10 +2191,10 @@ namespace smt { bp.m_instr = c; bp.m_old_max_generation = m_max_generation; bp.m_old_used_enodes_size = m_used_enodes.size(); - if (best_v == 0) { + if (best_v == nullptr) { TRACE("mam_bug", tout << "m_top: " << m_top << ", m_backtrack_stack.size(): " << m_backtrack_stack.size() << "\n"; tout << *c << "\n";); - bp.m_to_recycle = 0; + bp.m_to_recycle = nullptr; bp.m_it = m_context.begin_enodes_of(lbl); bp.m_end = m_context.end_enodes_of(lbl); } @@ -2211,7 +2211,7 @@ namespace smt { break; } if (bp.m_it == bp.m_end) - return 0; + return nullptr; m_top++; update_max_generation(*(bp.m_it)); return *(bp.m_it); @@ -2648,7 +2648,7 @@ namespace smt { m_num_args = static_cast(m_pc)->m_num_args; m_oreg = static_cast(m_pc)->m_oreg; m_app = init_continue(static_cast(m_pc), m_num_args); - if (m_app == 0) + if (m_app == nullptr) goto backtrack; m_pattern_instances.push_back(m_app); TRACE("mam_int", tout << "continue candidate:\n" << mk_ll_pp(m_app->get_owner(), m_ast_manager);); @@ -2911,7 +2911,7 @@ namespace smt { if (lbl_id < m_trees.size()) return m_trees[lbl_id]; else - return 0; + return nullptr; } ptr_vector::iterator begin_code_trees() { @@ -2974,11 +2974,11 @@ namespace smt { if (p1->m_label != p2->m_label || p1->m_arg_idx != p2->m_arg_idx || p1->m_pattern_idx != p2->m_pattern_idx || - (p1->m_child == 0) != (p2->m_child == 0)) { + (p1->m_child == nullptr) != (p2->m_child == nullptr)) { return false; } - if (p1->m_child == 0 && p2->m_child == 0) + if (p1->m_child == nullptr && p2->m_child == nullptr) return true; p1 = p1->m_child; @@ -3014,11 +3014,11 @@ namespace smt { m_arg_idx(p->m_arg_idx), m_ground_arg_idx(p->m_ground_arg_idx), m_ground_arg(p->m_ground_arg), - m_code(0), + m_code(nullptr), m_filter(h(p->m_label)), - m_sibling(0), - m_first_child(0), - m_todo(0) { + m_sibling(nullptr), + m_first_child(nullptr), + m_todo(nullptr) { #ifdef _PROFILE_PATH_TREE m_counter = 0; m_num_eq_visited = 0; @@ -3029,7 +3029,7 @@ namespace smt { void display(std::ostream & out, unsigned indent) { path_tree * curr = this; - while (curr != 0) { + while (curr != nullptr) { for (unsigned i = 0; i < indent; i++) out << " "; out << curr->m_label->get_name() << ":" << curr->m_arg_idx; if (curr->m_ground_arg) @@ -3122,7 +3122,7 @@ namespace smt { } void add_candidate(code_tree * t, enode * app) { - if (t != 0) { + if (t != nullptr) { TRACE("mam_candidate", tout << "adding candidate:\n" << mk_ll_pp(app->get_owner(), m_ast_manager);); if (!t->has_candidates()) m_to_match.push_back(t); @@ -3221,7 +3221,7 @@ namespace smt { for (unsigned j = 0; j < APPROX_SET_CAPACITY; j++) { m_pp[i][j].first = 0; m_pp[i][j].second = 0; - m_pc[i][j] = 0; + m_pc[i][j] = nullptr; } } } @@ -3240,10 +3240,10 @@ namespace smt { SASSERT(m_ast_manager.is_pattern(mp)); SASSERT(p != 0); unsigned pat_idx = p->m_pattern_idx; - path_tree * head = 0; - path_tree * curr = 0; - path_tree * prev = 0; - while (p != 0) { + path_tree * head = nullptr; + path_tree * curr = nullptr; + path_tree * prev = nullptr; + while (p != nullptr) { curr = new (m_region) path_tree(p, m_lbl_hasher); if (prev) prev->m_first_child = curr; @@ -3260,9 +3260,9 @@ namespace smt { void insert(path_tree * t, path * p, quantifier * qa, app * mp) { SASSERT(m_ast_manager.is_pattern(mp)); path_tree * head = t; - path_tree * prev_sibling = 0; + path_tree * prev_sibling = nullptr; bool found_label = false; - while (t != 0) { + while (t != nullptr) { if (t->m_label == p->m_label) { found_label = true; if (t->m_arg_idx == p->m_arg_idx && @@ -3270,8 +3270,8 @@ namespace smt { t->m_ground_arg_idx == p->m_ground_arg_idx ) { // found compatible node - if (t->m_first_child == 0) { - if (p->m_child == 0) { + if (t->m_first_child == nullptr) { + if (p->m_child == nullptr) { SASSERT(t->m_code != 0); insert_code(t, qa, mp, p->m_pattern_idx); } @@ -3281,7 +3281,7 @@ namespace smt { } } else { - if (p->m_child == 0) { + if (p->m_child == nullptr) { if (t->m_code) { insert_code(t, qa, mp, p->m_pattern_idx); } @@ -3393,7 +3393,7 @@ namespace smt { return mk_enode(m_context, qa, to_app(arg)); } } - return 0; + return nullptr; } /** @@ -3460,7 +3460,7 @@ namespace smt { unsigned num_patterns = mp->get_num_args(); for (unsigned i = 0; i < num_patterns; i++) { app * pat = to_app(mp->get_arg(i)); - update_filters(pat, 0, qa, mp, i); + update_filters(pat, nullptr, qa, mp, i); } } @@ -3496,7 +3496,7 @@ namespace smt { \brief Collect new E-matching candidates using the inverted path index t. */ void collect_parents(enode * r, path_tree * t) { - if (t == 0) + if (t == nullptr) return; #ifdef _PROFILE_PATH_TREE t->m_watch.start(); @@ -3604,7 +3604,7 @@ namespace smt { // Filter 2. ( // curr_tree has no support for the filter based on a ground argument. - curr_tree->m_ground_arg == 0 || + curr_tree->m_ground_arg == nullptr || // checks whether the child of the parent is equal to the expected ground argument. is_eq(curr_tree->m_ground_arg, curr_parent->get_arg(curr_tree->m_ground_arg_idx)) )) { @@ -3614,7 +3614,7 @@ namespace smt { } if (curr_tree->m_first_child) { path_tree * child = curr_tree->m_first_child; - if (child->m_todo == 0) { + if (child->m_todo == nullptr) { child->m_todo = mk_tmp_vector(); m_todo.push_back(child); } @@ -3636,7 +3636,7 @@ namespace smt { } } recycle(t->m_todo); - t->m_todo = 0; + t->m_todo = nullptr; // remove both marks. unmark_enodes(to_unmark->size(), to_unmark->c_ptr()); unmark_enodes2(to_unmark2->size(), to_unmark2->c_ptr()); @@ -3812,8 +3812,8 @@ namespace smt { m_interpreter(ctx, *this, use_filters), m_trees(m_ast_manager, m_compiler, m_trail_stack), m_region(m_trail_stack.get_region()), - m_r1(0), - m_r2(0) { + m_r1(nullptr), + m_r2(nullptr) { DEBUG_CODE(m_trees.set_context(&ctx);); DEBUG_CODE(m_check_missing_instances = false;); reset_pp_pc(); diff --git a/src/smt/old_interval.cpp b/src/smt/old_interval.cpp index d126c2f32..da589893b 100644 --- a/src/smt/old_interval.cpp +++ b/src/smt/old_interval.cpp @@ -157,8 +157,8 @@ interval::interval(v_dependency_manager & m): m_upper(true), m_lower_open(true), m_upper_open(true), - m_lower_dep(0), - m_upper_dep(0) { + m_lower_dep(nullptr), + m_upper_dep(nullptr) { } /** @@ -215,12 +215,12 @@ interval::interval(v_dependency_manager & m, rational const & val, bool open, bo m_lower_dep = d; m_upper = ext_numeral(true); m_upper_open = true; - m_upper_dep = 0; + m_upper_dep = nullptr; } else { m_lower = ext_numeral(false); m_lower_open = true; - m_lower_dep = 0; + m_lower_dep = nullptr; m_upper = ext_numeral(val); m_upper_open = open; m_upper_dep = d; @@ -252,8 +252,8 @@ interval & interval::operator+=(interval const & other) { m_upper += other.m_upper; m_lower_open |= other.m_lower_open; m_upper_open |= other.m_upper_open; - m_lower_dep = m_lower.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, other.m_lower_dep); - m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_upper_dep, other.m_upper_dep); + m_lower_dep = m_lower.is_infinite() ? nullptr : m_manager.mk_join(m_lower_dep, other.m_lower_dep); + m_upper_dep = m_upper.is_infinite() ? nullptr : m_manager.mk_join(m_upper_dep, other.m_upper_dep); return *this; } @@ -283,7 +283,7 @@ v_dependency * interval::join_opt(v_dependency * d1, v_dependency * d2, v_depend return join(d1, d2); if (opt2 == d1 || opt2 == d2) return join(d1, d2); - if (opt1 == 0 || opt2 == 0) + if (opt1 == nullptr || opt2 == nullptr) return join(d1, d2); // TODO: more opts... return join(d1, d2, opt1); @@ -331,8 +331,8 @@ interval & interval::operator*=(interval const & other) { m_upper_open = a_o || c_o; SASSERT(a.is_neg() && c.is_neg()); m_lower = new_lower; m_upper = new_upper; - m_lower_dep = m_lower.is_infinite() ? 0 : join(b_d, d_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join_opt(a_d, c_d, b_d, d_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join(b_d, d_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join_opt(a_d, c_d, b_d, d_d); } else if (other.is_M()) { // a <= x <= b <= 0, y <= d, d > 0 --> a*d <= x*y (uses the fact that b is not positive) @@ -344,8 +344,8 @@ interval & interval::operator*=(interval const & other) { m_upper_open = a_o || c_o; m_lower = new_lower; m_upper = new_upper; - m_lower_dep = m_lower.is_infinite() ? 0 : join(a_d, d_d, b_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join(a_d, c_d, b_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join(a_d, d_d, b_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join(a_d, c_d, b_d); } else { // a <= x <= b <= 0, 0 <= c <= y <= d --> a*d <= x*y (uses the fact that x is neg (b is not positive) or y is pos (c is not negative)) @@ -359,8 +359,8 @@ interval & interval::operator*=(interval const & other) { m_upper_open = (is_N0_old || other.is_P0()) ? false : (b_o || c_o); m_lower = new_lower; m_upper = new_upper; - m_lower_dep = m_lower.is_infinite() ? 0 : join_opt(a_d, d_d, b_d, c_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join(b_d, c_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join_opt(a_d, d_d, b_d, c_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join(b_d, c_d); } } else if (is_M()) { @@ -374,8 +374,8 @@ interval & interval::operator*=(interval const & other) { m_upper_open = a_o || c_o; SASSERT(a.is_neg() && c.is_neg()); m_lower = new_lower; m_upper = new_upper; - m_lower_dep = m_lower.is_infinite() ? 0 : join(b_d, c_d, d_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join(a_d, c_d, d_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join(b_d, c_d, d_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join(a_d, c_d, d_d); } else if (other.is_M()) { TRACE("interval_bug", tout << "(M, M)\n";); @@ -404,8 +404,8 @@ interval & interval::operator*=(interval const & other) { m_upper = bd; m_upper_open = bd_o; } - m_lower_dep = m_lower.is_infinite() ? 0 : join(a_d, b_d, c_d, d_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join(a_d, b_d, c_d, d_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join(a_d, b_d, c_d, d_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join(a_d, b_d, c_d, d_d); } else { // a < 0, a <= x, 0 <= c <= y <= d --> a*d <= x*y (uses the fact that c is not negative) @@ -418,8 +418,8 @@ interval & interval::operator*=(interval const & other) { m_upper_open = b_o || d_o; SASSERT(b.is_pos() && d.is_pos()); m_lower = new_lower; m_upper = new_upper; - m_lower_dep = m_lower.is_infinite() ? 0 : join(a_d, d_d, c_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join(b_d, d_d, c_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join(a_d, d_d, c_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join(b_d, d_d, c_d); } } else { @@ -435,8 +435,8 @@ interval & interval::operator*=(interval const & other) { m_upper_open = (is_P0_old || other.is_N0()) ? false : a_o || d_o; m_lower = new_lower; m_upper = new_upper; - m_lower_dep = m_lower.is_infinite() ? 0 : join_opt(b_d, c_d, a_d, d_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join(a_d, d_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join_opt(b_d, c_d, a_d, d_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join(a_d, d_d); } else if (other.is_M()) { // 0 <= a <= x <= b, c <= y --> b*c <= x*y (uses the fact that a is not negative) @@ -448,8 +448,8 @@ interval & interval::operator*=(interval const & other) { m_upper_open = b_o || d_o; m_lower = new_lower; m_upper = new_upper; - m_lower_dep = m_lower.is_infinite() ? 0 : join(b_d, c_d, a_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join(b_d, d_d, a_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join(b_d, c_d, a_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join(b_d, d_d, a_d); } else { // 0 <= a <= x, 0 <= c <= y --> a*c <= x*y @@ -462,8 +462,8 @@ interval & interval::operator*=(interval const & other) { m_upper_open = b_o || d_o; SASSERT(b.is_pos() && d.is_pos()); m_lower = new_lower; m_upper = new_upper; - m_lower_dep = m_lower.is_infinite() ? 0 : join(a_d, c_d); - m_upper_dep = m_upper.is_infinite() ? 0 : join_opt(b_d, d_d, a_d, c_d); + m_lower_dep = m_lower.is_infinite() ? nullptr : join(a_d, c_d); + m_upper_dep = m_upper.is_infinite() ? nullptr : join_opt(b_d, d_d, a_d, c_d); } } TRACE("interval_bug", tout << "operator*= result: " << *this << "\n";); @@ -590,7 +590,7 @@ void interval::expt(unsigned n) { // 0 < a <= x <= b --> x^n <= b^n (use lower and upper bound -- need the fact that x is positive) m_lower.expt(n); m_upper.expt(n); - m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, m_upper_dep); + m_upper_dep = m_upper.is_infinite() ? nullptr : m_manager.mk_join(m_lower_dep, m_upper_dep); } else if (m_upper.is_neg()) { // [l, u]^n = [u^n, l^n] if u < 0 @@ -601,7 +601,7 @@ void interval::expt(unsigned n) { std::swap(m_lower_dep, m_upper_dep); m_lower.expt(n); m_upper.expt(n); - m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, m_upper_dep); + m_upper_dep = m_upper.is_infinite() ? nullptr : m_manager.mk_join(m_lower_dep, m_upper_dep); } else { // [l, u]^n = [0, max{l^n, u^n}] otherwise @@ -614,10 +614,10 @@ void interval::expt(unsigned n) { m_upper = m_lower; m_upper_open = m_lower_open; } - m_upper_dep = m_upper.is_infinite() ? 0 : m_manager.mk_join(m_lower_dep, m_upper_dep); + m_upper_dep = m_upper.is_infinite() ? nullptr : m_manager.mk_join(m_lower_dep, m_upper_dep); m_lower = ext_numeral(0); m_lower_open = false; - m_lower_dep = 0; + m_lower_dep = nullptr; } } else { diff --git a/src/smt/old_interval.h b/src/smt/old_interval.h index e9cb73b8f..1928a1c70 100644 --- a/src/smt/old_interval.h +++ b/src/smt/old_interval.h @@ -80,7 +80,7 @@ class old_interval { public: explicit old_interval(v_dependency_manager & m); explicit old_interval(v_dependency_manager & m, rational const & lower, bool l_open, v_dependency * l_dep, rational const & upper, bool u_open, v_dependency * u_dep); - explicit old_interval(v_dependency_manager & m, rational const & val, v_dependency * l_dep = 0, v_dependency * u_dep = 0); + explicit old_interval(v_dependency_manager & m, rational const & val, v_dependency * l_dep = nullptr, v_dependency * u_dep = nullptr); explicit old_interval(v_dependency_manager & m, rational const & val, bool open, bool lower, v_dependency * d); explicit old_interval(v_dependency_manager & m, ext_numeral const& lower, bool l_open, v_dependency * l_dep, ext_numeral const & upper, bool u_open, v_dependency * u_dep); old_interval(old_interval const & other); diff --git a/src/smt/params/qi_params.h b/src/smt/params/qi_params.h index 2cee6dc72..cc1a30673 100644 --- a/src/smt/params/qi_params.h +++ b/src/smt/params/qi_params.h @@ -99,7 +99,7 @@ struct qi_params { m_mbqi_max_iterations(1000), m_mbqi_trace(false), m_mbqi_force_template(10), - m_mbqi_id(0) + m_mbqi_id(nullptr) { updt_params(p); } diff --git a/src/smt/proto_model/array_factory.cpp b/src/smt/proto_model/array_factory.cpp index d112331f0..919f18dc0 100644 --- a/src/smt/proto_model/array_factory.cpp +++ b/src/smt/proto_model/array_factory.cpp @@ -62,7 +62,7 @@ void array_factory::get_some_args_for(sort * s, ptr_buffer & args) { expr * array_factory::get_some_value(sort * s) { TRACE("array_factory", tout << mk_pp(s, m_manager) << "\n";); - value_set * set = 0; + value_set * set = nullptr; if (m_sort2value_set.find(s, set) && !set->empty()) return *(set->begin()); func_interp * fi; @@ -99,7 +99,7 @@ bool array_factory::mk_two_diff_values_for(sort * s) { } bool array_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { - value_set * set = 0; + value_set * set = nullptr; if (!m_sort2value_set.find(s, set) || set->size() == 0) { if (!mk_two_diff_values_for(s)) return false; @@ -111,7 +111,7 @@ bool array_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { if (set->size() == 1) { v1 = *(set->begin()); v2 = get_fresh_value(s); - return v2.get() != 0; + return v2.get() != nullptr; } else { SASSERT(set->size() >= 2); @@ -139,7 +139,7 @@ expr * array_factory::get_fresh_value(sort * s) { } sort * range = get_array_range(s); expr * range_val = m_model.get_fresh_value(range); - if (range_val != 0) { + if (range_val != nullptr) { // easy case func_interp * fi; expr * val = mk_array_interp(s, fi); @@ -170,7 +170,7 @@ expr * array_factory::get_fresh_value(sort * s) { if (!found) { expr * arg1 = m_model.get_fresh_value(d); expr * arg2 = m_model.get_fresh_value(d); - if (arg1 != 0 && arg2 != 0) { + if (arg1 != nullptr && arg2 != nullptr) { found = true; args1.push_back(arg1); args2.push_back(arg2); @@ -201,6 +201,6 @@ expr * array_factory::get_fresh_value(sort * s) { // failed to create a fresh array value TRACE("array_factory_bug", tout << "failed to build fresh array value\n";); - return 0; + return nullptr; } diff --git a/src/smt/proto_model/datatype_factory.cpp b/src/smt/proto_model/datatype_factory.cpp index 550b694da..eded55cc3 100644 --- a/src/smt/proto_model/datatype_factory.cpp +++ b/src/smt/proto_model/datatype_factory.cpp @@ -27,7 +27,7 @@ datatype_factory::datatype_factory(ast_manager & m, proto_model & md): } expr * datatype_factory::get_some_value(sort * s) { - value_set * set = 0; + value_set * set = nullptr; if (m_sort2value_set.find(s, set) && !set->empty()) return *(set->begin()); func_decl * c = m_util.get_non_rec_constructor(s); @@ -46,7 +46,7 @@ expr * datatype_factory::get_some_value(sort * s) { \brief Return the last fresh (or almost) fresh value of sort s. */ expr * datatype_factory::get_last_fresh_value(sort * s) { - expr * val = 0; + expr * val = nullptr; if (m_last_fresh_value.find(s, val)) { TRACE("datatype", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";); return val; @@ -98,7 +98,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { sort * s_arg = constructor->get_domain(i); if (!found_fresh_arg && (!m_util.is_datatype(s_arg) || !m_util.are_siblings(s, s_arg))) { expr * new_arg = m_model.get_fresh_value(s_arg); - if (new_arg != 0) { + if (new_arg != nullptr) { found_fresh_arg = true; args.push_back(new_arg); continue; @@ -131,7 +131,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { } } SASSERT(!m_util.is_recursive(s)); - return 0; + return nullptr; } @@ -160,7 +160,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { sort * s_arg = constructor->get_domain(i); if (!found_fresh_arg && (!m_util.is_recursive(s) || !m_util.is_datatype(s_arg) || !m_util.are_siblings(s, s_arg))) { expr * new_arg = m_model.get_fresh_value(s_arg); - if (new_arg != 0) { + if (new_arg != nullptr) { found_fresh_arg = true; args.push_back(new_arg); continue; @@ -204,7 +204,7 @@ expr * datatype_factory::get_fresh_value(sort * s) { << found_sibling << "\n";); if (!found_sibling && m_util.is_datatype(s_arg) && m_util.are_siblings(s, s_arg)) { found_sibling = true; - expr * maybe_new_arg = 0; + expr * maybe_new_arg = nullptr; if (num_iterations <= 1) { maybe_new_arg = get_almost_fresh_value(s_arg); } @@ -245,6 +245,6 @@ expr * datatype_factory::get_fresh_value(sort * s) { // Search for value that was not created before. SASSERT(!m_util.is_recursive(s)); - return 0; + return nullptr; } diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index 0a75ff700..688ded834 100644 --- a/src/smt/proto_model/proto_model.cpp +++ b/src/smt/proto_model/proto_model.cpp @@ -53,11 +53,11 @@ void proto_model::register_aux_decl(func_decl * d) { */ void proto_model::reregister_decl(func_decl * f, func_interp * new_fi, func_decl * f_aux) { func_interp * fi = get_func_interp(f); - if (fi == 0) { + if (fi == nullptr) { register_decl(f, new_fi); } else { - if (f_aux != 0) { + if (f_aux != nullptr) { register_decl(f_aux, fi); m_aux_decls.insert(f_aux); } @@ -135,7 +135,7 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au todo.pop_back(); func_decl * a_decl = to_app(a)->get_decl(); expr * ai = get_const_interp(a_decl); - if (ai == 0) { + if (ai == nullptr) { ai = get_some_value(a_decl->get_range()); register_decl(a_decl, ai); } @@ -148,7 +148,7 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au bool visited = true; args.reset(); for (expr* t_arg : *t) { - expr * arg = 0; + expr * arg = nullptr; if (!cache.find(t_arg, arg)) { visited = false; todo.push_back(t_arg); @@ -346,7 +346,7 @@ void proto_model::complete_partial_func(func_decl * f) { func_interp * fi = get_func_interp(f); if (fi && fi->is_partial()) { expr * else_value = fi->get_max_occ_result(); - if (else_value == 0) + if (else_value == nullptr) else_value = get_some_value(f->get_range()); fi->set_else(else_value); } diff --git a/src/smt/proto_model/struct_factory.cpp b/src/smt/proto_model/struct_factory.cpp index 8d85c6485..a31dd84dd 100644 --- a/src/smt/proto_model/struct_factory.cpp +++ b/src/smt/proto_model/struct_factory.cpp @@ -20,7 +20,7 @@ Revision History: #include "smt/proto_model/proto_model.h" struct_factory::value_set * struct_factory::get_value_set(sort * s) { - value_set * set = 0; + value_set * set = nullptr; if (!m_sort2value_set.find(s, set)) { set = alloc(value_set); m_sort2value_set.insert(s, set); diff --git a/src/smt/proto_model/value_factory.cpp b/src/smt/proto_model/value_factory.cpp index e41696165..5a0d012dc 100644 --- a/src/smt/proto_model/value_factory.cpp +++ b/src/smt/proto_model/value_factory.cpp @@ -34,7 +34,7 @@ basic_factory::basic_factory(ast_manager & m): expr * basic_factory::get_some_value(sort * s) { if (m_manager.is_bool(s)) return m_manager.mk_false(); - return 0; + return nullptr; } bool basic_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { @@ -47,7 +47,7 @@ bool basic_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { } expr * basic_factory::get_fresh_value(sort * s) { - return 0; + return nullptr; } user_sort_factory::user_sort_factory(ast_manager & m): @@ -56,7 +56,7 @@ user_sort_factory::user_sort_factory(ast_manager & m): void user_sort_factory::freeze_universe(sort * s) { if (!m_finite.contains(s)) { - value_set * set = 0; + value_set * set = nullptr; m_sort2value_set.find(s, set); if (!m_sort2value_set.find(s, set) || set->m_values.empty()) { // we cannot freeze an empty universe. @@ -68,7 +68,7 @@ void user_sort_factory::freeze_universe(sort * s) { } obj_hashtable const & user_sort_factory::get_known_universe(sort * s) const { - value_set * set = 0; + value_set * set = nullptr; if (m_sort2value_set.find(s, set)) { return set->m_values; } @@ -77,7 +77,7 @@ obj_hashtable const & user_sort_factory::get_known_universe(sort * s) cons expr * user_sort_factory::get_some_value(sort * s) { if (is_finite(s)) { - value_set * set = 0; + value_set * set = nullptr; m_sort2value_set.find(s, set); SASSERT(set != 0); SASSERT(!set->m_values.empty()); @@ -88,7 +88,7 @@ expr * user_sort_factory::get_some_value(sort * s) { bool user_sort_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { if (is_finite(s)) { - value_set * set = 0; + value_set * set = nullptr; if (m_sort2value_set.find(s, set) && set->m_values.size() >= 2) { obj_hashtable::iterator it = set->m_values.begin(); v1 = *it; @@ -103,7 +103,7 @@ bool user_sort_factory::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) expr * user_sort_factory::get_fresh_value(sort * s) { if (is_finite(s)) - return 0; + return nullptr; return simple_factory::get_fresh_value(s); } diff --git a/src/smt/proto_model/value_factory.h b/src/smt/proto_model/value_factory.h index 3979a47bb..77452d424 100644 --- a/src/smt/proto_model/value_factory.h +++ b/src/smt/proto_model/value_factory.h @@ -95,7 +95,7 @@ protected: ptr_vector m_sets; value_set * get_value_set(sort * s) { - value_set * set = 0; + value_set * set = nullptr; if (!m_sort2value_set.find(s, set)) { set = alloc(value_set); m_sort2value_set.insert(s, set); @@ -138,8 +138,8 @@ public: } expr * get_some_value(sort * s) override { - value_set * set = 0; - expr * result = 0; + value_set * set = nullptr; + expr * result = nullptr; if (m_sort2value_set.find(s, set) && !set->m_values.empty()) result = *(set->m_values.begin()); else @@ -148,7 +148,7 @@ public: } bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) override { - value_set * set = 0; + value_set * set = nullptr; if (m_sort2value_set.find(s, set)) { switch (set->m_values.size()) { case 0: @@ -179,9 +179,9 @@ public: expr * get_fresh_value(sort * s) override { value_set * set = get_value_set(s); bool is_new = false; - expr * result = 0; + expr * result = nullptr; sort_info* s_info = s->get_info(); - sort_size const* sz = s_info?&s_info->get_num_elements():0; + sort_size const* sz = s_info?&s_info->get_num_elements():nullptr; bool has_max = false; Number max_size(0); if (sz && sz->is_finite() && sz->size() < UINT_MAX) { @@ -195,7 +195,7 @@ public: result = mk_value(next, s, is_new); next++; if (has_max && next > max_size + start) { - return 0; + return nullptr; } } SASSERT(result != 0); diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 2a8d9d199..4e639a7b2 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -128,7 +128,7 @@ namespace smt { unsigned qi_queue::get_new_gen(quantifier * q, unsigned generation, float cost) { // max_top_generation and min_top_generation are not available for computing inc_gen - set_values(q, 0, generation, 0, 0, cost); + set_values(q, nullptr, generation, 0, 0, cost); float r = m_evaluator(m_new_gen_function, m_vals.size(), m_vals.c_ptr()); return static_cast(r); } diff --git a/src/smt/smt2_extra_cmds.cpp b/src/smt/smt2_extra_cmds.cpp index 238295a49..d66849338 100644 --- a/src/smt/smt2_extra_cmds.cpp +++ b/src/smt/smt2_extra_cmds.cpp @@ -23,7 +23,7 @@ Notes: class include_cmd : public cmd { char const * m_filename; public: - include_cmd() : cmd("include"), m_filename(0) {} + include_cmd() : cmd("include"), m_filename(nullptr) {} char const * get_usage() const override { return ""; } char const * get_descr(cmd_context & ctx) const override { return "include a file"; } unsigned get_arity() const override { return 1; } @@ -38,7 +38,7 @@ public: is.close(); } void prepare(cmd_context & ctx) override { reset(ctx); } - void reset(cmd_context & ctx) override { m_filename = 0; } + void reset(cmd_context & ctx) override { m_filename = nullptr; } void finalize(cmd_context & ctx) override { reset(ctx); } }; diff --git a/src/smt/smt_almost_cg_table.cpp b/src/smt/smt_almost_cg_table.cpp index 4d24ea0d0..b891c002d 100644 --- a/src/smt/smt_almost_cg_table.cpp +++ b/src/smt/smt_almost_cg_table.cpp @@ -108,8 +108,8 @@ namespace smt { void almost_cg_table::insert(enode * n) { table::entry * entry = m_table.find_core(n); - if (entry == 0) { - list * new_lst = new (m_region) list(n, 0); + if (entry == nullptr) { + list * new_lst = new (m_region) list(n, nullptr); m_table.insert(n, new_lst); } else { @@ -119,7 +119,7 @@ namespace smt { } list * almost_cg_table::find(enode * n) { - list * result = 0; + list * result = nullptr; m_table.find(n, result); return result; } diff --git a/src/smt/smt_almost_cg_table.h b/src/smt/smt_almost_cg_table.h index 7807f705a..d514f1478 100644 --- a/src/smt/smt_almost_cg_table.h +++ b/src/smt/smt_almost_cg_table.h @@ -57,7 +57,7 @@ namespace smt { table m_table; public: - almost_cg_table(enode * r1 = 0, enode * r2 = 0); + almost_cg_table(enode * r1 = nullptr, enode * r2 = nullptr); void reset(enode * r1, enode * r2) { m_r1 = r1->get_root(); m_r2 = r2->get_root(); reset(); } void reset(); void insert(enode *); diff --git a/src/smt/smt_b_justification.h b/src/smt/smt_b_justification.h index 55669a7ef..7aeb268cb 100644 --- a/src/smt/smt_b_justification.h +++ b/src/smt/smt_b_justification.h @@ -91,7 +91,7 @@ namespace smt { } }; - const b_justification null_b_justification(static_cast(0)); + const b_justification null_b_justification(static_cast(nullptr)); inline std::ostream& operator<<(std::ostream& out, b_justification::kind k) { switch (k) { diff --git a/src/smt/smt_case_split_queue.cpp b/src/smt/smt_case_split_queue.cpp index 3da6ce295..5c51b906f 100644 --- a/src/smt/smt_case_split_queue.cpp +++ b/src/smt/smt_case_split_queue.cpp @@ -419,7 +419,7 @@ namespace smt { val = l_true; } if ((is_or && val == l_true) || (is_and && val == l_false)) { - expr * undef_child = 0; + expr * undef_child = nullptr; if (!has_child_assigned_to(m_context, to_app(curr), val, undef_child, m_params.m_rel_case_split_order)) { if (m_manager.has_trace_stream()) { m_manager.trace_stream() << "[decide-and-or] #" << curr->get_id() << " #" << undef_child->get_id() << "\n"; @@ -611,7 +611,7 @@ namespace smt { val = l_true; } if ((is_or && val == l_true) || (is_and && val == l_false)) { - expr * undef_child = 0; + expr * undef_child = nullptr; if (!has_child_assigned_to(m_context, to_app(curr), val, undef_child, m_params.m_rel_case_split_order)) { TRACE("case_split", tout << "found AND/OR candidate: #" << curr->get_id() << " #" << undef_child->get_id() << "\n";); literal l = m_context.get_literal(undef_child); @@ -747,7 +747,7 @@ namespace smt { m_head(0), m_bs_num_bool_vars(UINT_MAX), m_priority_queue2(0, generation_lt(*this)), - m_current_goal(0) { + m_current_goal(nullptr) { set_global_generation(); } @@ -875,7 +875,7 @@ namespace smt { val = l_true; } if ((is_or && val == l_true) || (is_and && val == l_false)) { - expr * undef_child = 0; + expr * undef_child = nullptr; if (!has_child_assigned_to(m_context, to_app(curr), val, undef_child, m_params.m_rel_case_split_order)) { if (m_manager.has_trace_stream()) { m_manager.trace_stream() << "[decide-and-or] #" << curr->get_id() << " #" << undef_child->get_id() << "\n"; diff --git a/src/smt/smt_cg_table.h b/src/smt/smt_cg_table.h index 1e3fd8b83..64c8328d0 100644 --- a/src/smt/smt_cg_table.h +++ b/src/smt/smt_cg_table.h @@ -307,17 +307,17 @@ namespace smt { enode * find(enode * n) const { SASSERT(n->get_num_args() > 0); - enode * r = 0; + enode * r = nullptr; void * t = const_cast(this)->get_table(n); switch (static_cast(GET_TAG(t))) { case UNARY: - return UNTAG(unary_table*, t)->find(n, r) ? r : 0; + return UNTAG(unary_table*, t)->find(n, r) ? r : nullptr; case BINARY: - return UNTAG(binary_table*, t)->find(n, r) ? r : 0; + return UNTAG(binary_table*, t)->find(n, r) ? r : nullptr; case BINARY_COMM: - return UNTAG(comm_table*, t)->find(n, r) ? r : 0; + return UNTAG(comm_table*, t)->find(n, r) ? r : nullptr; default: - return UNTAG(table*, t)->find(n, r) ? r : 0; + return UNTAG(table*, t)->find(n, r) ? r : nullptr; } } diff --git a/src/smt/smt_checker.cpp b/src/smt/smt_checker.cpp index a7a25037c..ed80eaab7 100644 --- a/src/smt/smt_checker.cpp +++ b/src/smt/smt_checker.cpp @@ -125,28 +125,28 @@ namespace smt { unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { enode * arg = get_enode_eq_to(n->get_arg(i)); - if (arg == 0) - return 0; + if (arg == nullptr) + return nullptr; buffer.push_back(arg); } enode * e = m_context.get_enode_eq_to(n->get_decl(), num, buffer.c_ptr()); - if (e == 0) - return 0; - return m_context.is_relevant(e) ? e : 0; + if (e == nullptr) + return nullptr; + return m_context.is_relevant(e) ? e : nullptr; } enode * checker::get_enode_eq_to(expr * n) { if (is_var(n)) { unsigned idx = to_var(n)->get_idx(); if (idx >= m_num_bindings) - return 0; + return nullptr; return m_bindings[m_num_bindings - idx - 1]; } if (m_context.e_internalized(n) && m_context.is_relevant(n)) return m_context.get_enode(n); if (!is_app(n) || to_app(n)->get_num_args() == 0) - return 0; - enode * r = 0; + return nullptr; + enode * r = nullptr; if (n->get_ref_count() > 1 && m_to_enode_cache.find(n, r)) return r; r = get_enode_eq_to_core(to_app(n)); @@ -179,7 +179,7 @@ namespace smt { m_context(c), m_manager(c.get_manager()), m_num_bindings(0), - m_bindings(0) { + m_bindings(nullptr) { } }; diff --git a/src/smt/smt_checker.h b/src/smt/smt_checker.h index 5e841f572..beb32239c 100644 --- a/src/smt/smt_checker.h +++ b/src/smt/smt_checker.h @@ -47,8 +47,8 @@ namespace smt { public: checker(context & c); - bool is_sat(expr * n, unsigned num_bindings = 0, enode * const * bindings = 0); - bool is_unsat(expr * n, unsigned num_bindings = 0, enode * const * bindings = 0); + bool is_sat(expr * n, unsigned num_bindings = 0, enode * const * bindings = nullptr); + bool is_unsat(expr * n, unsigned num_bindings = 0, enode * const * bindings = nullptr); }; }; diff --git a/src/smt/smt_clause.cpp b/src/smt/smt_clause.cpp index ccb336941..a9365fffc 100644 --- a/src/smt/smt_clause.cpp +++ b/src/smt/smt_clause.cpp @@ -29,7 +29,7 @@ namespace smt { clause_del_eh * del_eh, bool save_atoms, expr * const * bool_var2expr_map) { SASSERT(k == CLS_AUX || js == 0 || !js->in_region()); SASSERT(num_lits >= 2); - unsigned sz = get_obj_size(num_lits, k, save_atoms, del_eh != 0, js != 0); + unsigned sz = get_obj_size(num_lits, k, save_atoms, del_eh != nullptr, js != nullptr); void * mem = m.get_allocator().allocate(sz); clause * cls = new (mem) clause(); cls->m_num_literals = num_lits; @@ -38,8 +38,8 @@ namespace smt { cls->m_reinit = save_atoms; cls->m_reinternalize_atoms = save_atoms; cls->m_has_atoms = save_atoms; - cls->m_has_del_eh = del_eh != 0; - cls->m_has_justification = js != 0; + cls->m_has_del_eh = del_eh != nullptr; + cls->m_has_justification = js != nullptr; cls->m_deleted = false; SASSERT(!m.proofs_enabled() || js != 0); memcpy(cls->m_lits, lits, sizeof(literal) * num_lits); @@ -92,7 +92,7 @@ namespace smt { unsigned num_atoms = get_num_atoms(); for (unsigned i = 0; i < num_atoms; i++) { m.dec_ref(get_atom(i)); - const_cast(get_atoms_addr())[i] = 0; + const_cast(get_atoms_addr())[i] = nullptr; } } diff --git a/src/smt/smt_clause.h b/src/smt/smt_clause.h index d4b9ee02f..8e843c4cf 100644 --- a/src/smt/smt_clause.h +++ b/src/smt/smt_clause.h @@ -149,8 +149,8 @@ namespace smt { void release_atoms(ast_manager & m); public: - static clause * mk(ast_manager & m, unsigned num_lits, literal * lits, clause_kind k, justification * js = 0, - clause_del_eh * del_eh = 0, bool save_atoms = false, expr * const * bool_var2expr_map = 0); + static clause * mk(ast_manager & m, unsigned num_lits, literal * lits, clause_kind k, justification * js = nullptr, + clause_del_eh * del_eh = nullptr, bool save_atoms = false, expr * const * bool_var2expr_map = nullptr); void deallocate(ast_manager & m); @@ -211,11 +211,11 @@ namespace smt { } clause_del_eh * get_del_eh() const { - return m_has_del_eh ? *(get_del_eh_addr()) : 0; + return m_has_del_eh ? *(get_del_eh_addr()) : nullptr; } justification * get_justification() const { - return m_has_justification ? *(get_justification_addr()) : 0; + return m_has_justification ? *(get_justification_addr()) : nullptr; } unsigned get_num_atoms() const { @@ -253,7 +253,7 @@ namespace smt { clause_del_eh * del_eh = get_del_eh(); if (del_eh) { (*del_eh)(m, this); - *(const_cast(get_del_eh_addr())) = 0; + *(const_cast(get_del_eh_addr())) = nullptr; } } diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index a6432c960..379846ed7 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -43,7 +43,7 @@ namespace smt { m_assigned_literals(assigned_literals), m_lemma_atoms(m), m_todo_js_qhead(0), - m_antecedents(0), + m_antecedents(nullptr), m_watches(watches), m_new_proofs(m), m_lemma_proof(m) @@ -204,7 +204,7 @@ namespace smt { eq2literals(p.first, p.second); } if (m_todo_js_qhead == m_todo_js.size()) { - m_antecedents = 0; + m_antecedents = nullptr; return; } } @@ -480,7 +480,7 @@ namespace smt { // save space for first uip m_lemma.push_back(null_literal); - m_lemma_atoms.push_back(0); + m_lemma_atoms.push_back(nullptr); unsigned num_marks = 0; if (not_l != null_literal) { @@ -758,7 +758,7 @@ namespace smt { return pr; } m_todo_pr.push_back(tp_elem(n1, n2)); - return 0; + return nullptr; } /** @@ -766,7 +766,7 @@ namespace smt { */ proof * conflict_resolution::norm_eq_proof(enode * n1, enode * n2, proof * pr) { if (!pr) - return 0; + return nullptr; SASSERT(m_manager.has_fact(pr)); app * fact = to_app(m_manager.get_fact(pr)); app * n1_owner = n1->get_owner(); @@ -814,7 +814,7 @@ namespace smt { switch (js.get_kind()) { case eq_justification::AXIOM: UNREACHABLE(); - return 0; + return nullptr; case eq_justification::EQUATION: TRACE("proof_gen_bug", tout << js.get_literal() << "\n"; m_ctx.display_literal_info(tout, js.get_literal());); return norm_eq_proof(n1, n2, get_proof(js.get_literal())); @@ -845,11 +845,11 @@ namespace smt { visited = false; } if (!visited) - return 0; + return nullptr; app * e1 = n1->get_owner(); app * e2 = n2->get_owner(); app * e2_prime = m_manager.mk_app(e2->get_decl(), e2->get_arg(1), e2->get_arg(0)); - proof * pr1 = 0; + proof * pr1 = nullptr; if (!prs.empty()) { pr1 = m_manager.mk_congruence(e1, e2_prime, prs.size(), prs.c_ptr()); m_new_proofs.push_back(pr1); @@ -877,14 +877,14 @@ namespace smt { } } if (!visited) - return 0; + return nullptr; proof * pr = m_manager.mk_congruence(n1->get_owner(), n2->get_owner(), prs.size(), prs.c_ptr()); m_new_proofs.push_back(pr); return pr; } default: UNREACHABLE(); - return 0; + return nullptr; } } @@ -899,7 +899,7 @@ namespace smt { return pr; } m_todo_pr.push_back(tp_elem(l)); - return 0; + return nullptr; } /** @@ -945,7 +945,7 @@ namespace smt { SASSERT(js); proof * pr = get_proof(js); ptr_buffer prs; - bool visited = pr != 0; + bool visited = pr != nullptr; TRACE("get_proof_bug", if (pr != 0) tout << js->get_name() << "\n";); CTRACE("get_proof_bug_after", invocation_counter >= DUMP_AFTER_NUM_INVOCATIONS, if (pr != 0) tout << js->get_name() << "\n";); CTRACE("get_proof_bug_after", invocation_counter >= DUMP_AFTER_NUM_INVOCATIONS, if (pr != 0) js->display_debug_info(*this, tout);); @@ -973,7 +973,7 @@ namespace smt { visited = false; } if (!visited) - return 0; + return nullptr; expr_ref l_exr(m_manager); m_ctx.literal2expr(l, l_exr); TRACE("get_proof_bug", @@ -1034,7 +1034,7 @@ namespace smt { } SASSERT(js != 0); m_todo_pr.push_back(tp_elem(js)); - return 0; + return nullptr; } void conflict_resolution::init_mk_proof() { @@ -1061,7 +1061,7 @@ namespace smt { SASSERT(js.get_kind() != b_justification::AXIOM); if (js.get_kind() == b_justification::CLAUSE) { clause * cls = js.get_clause(); - bool visited = get_proof(cls->get_justification()) != 0; + bool visited = get_proof(cls->get_justification()) != nullptr; unsigned num_lits = cls->get_num_literals(); unsigned i = 0; if (l != false_literal) { @@ -1070,20 +1070,20 @@ namespace smt { } else { SASSERT(cls->get_literal(1) == l); - if (get_proof(~cls->get_literal(0)) == 0) + if (get_proof(~cls->get_literal(0)) == nullptr) visited = false; i = 2; } } for (; i < num_lits; i++) { SASSERT(cls->get_literal(i) != l); - if (get_proof(~cls->get_literal(i)) == 0) + if (get_proof(~cls->get_literal(i)) == nullptr) visited = false; } return visited; } else - return get_proof(js.get_justification()) != 0; + return get_proof(js.get_justification()) != nullptr; } void conflict_resolution::mk_proof(literal l, b_justification js) { @@ -1114,11 +1114,11 @@ namespace smt { UNREACHABLE(); break; case eq_justification::EQUATION: - if (get_proof(js.get_literal()) == 0) + if (get_proof(js.get_literal()) == nullptr) visited = false; break; case eq_justification::JUSTIFICATION: - if (get_proof(js.get_justification()) == 0) + if (get_proof(js.get_justification()) == nullptr) visited = false; break; case eq_justification::CONGRUENCE: { @@ -1132,16 +1132,16 @@ namespace smt { enode * c1_2 = n1->get_arg(1); enode * c2_1 = n2->get_arg(0); enode * c2_2 = n2->get_arg(1); - if (c1_1 != c2_2 && get_proof(c1_1, c2_2) == 0) + if (c1_1 != c2_2 && get_proof(c1_1, c2_2) == nullptr) visited = false; - if (c1_2 != c2_1 && get_proof(c1_2, c2_1) == 0) + if (c1_2 != c2_1 && get_proof(c1_2, c2_1) == nullptr) visited = false; } else { for (unsigned i = 0; i < num_args; i++) { enode * c1 = n1->get_arg(i); enode * c2 = n2->get_arg(i); - if (c1 != c2 && get_proof(c1, c2) == 0) + if (c1 != c2 && get_proof(c1, c2) == nullptr) visited = false; } } @@ -1204,7 +1204,7 @@ namespace smt { } prs2.pop_back(); } - proof * pr = 0; + proof * pr = nullptr; SASSERT(!prs1.empty()); if (prs1.size() == 1) pr = prs1[0]; @@ -1290,13 +1290,13 @@ namespace smt { } SASSERT(visit_b_justification(consequent, conflict)); - proof * pr = 0; + proof * pr = nullptr; if (not_l == null_literal) { pr = get_proof(false_literal, conflict); SASSERT(pr); } else { - proof * prs[2] = { 0, 0}; + proof * prs[2] = { nullptr, nullptr}; m_lit2proof.find(not_l, prs[0]); SASSERT(prs[0]); prs[1] = get_proof(consequent, conflict); @@ -1310,13 +1310,13 @@ namespace smt { m_ctx.literal2expr(lit, l_expr); lits.push_back(l_expr); } - expr * fact = 0; + expr * fact = nullptr; switch (lits.size()) { - case 0: fact = 0; break; + case 0: fact = nullptr; break; case 1: fact = lits[0]; break; default: fact = m_manager.mk_or(lits.size(), lits.c_ptr()); } - if (fact == 0) + if (fact == nullptr) m_lemma_proof = pr; else m_lemma_proof = m_manager.mk_lemma(pr, fact); diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 0bf2a2939..13fd9e6ea 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -244,7 +244,7 @@ namespace smt { } literal lit = mk_diseq(k, v); literals.push_back(lit); - mk_clause(literals.size(), literals.c_ptr(), 0); + mk_clause(literals.size(), literals.c_ptr(), nullptr); TRACE("context", display_literals_verbose(tout, literals.size(), literals.c_ptr());); } } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 0f09f1f59..dd38776bc 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -51,7 +51,7 @@ namespace smt { m_relevancy_propagator(mk_relevancy_propagator(*this)), m_random(p.m_random_seed), m_flushing(false), - m_progress_callback(0), + m_progress_callback(nullptr), m_next_progress_sample(0), m_fingerprints(m_region), m_b_internalized_stack(m), @@ -59,7 +59,7 @@ namespace smt { m_final_check_idx(0), m_cg_table(m), m_dyn_ack_manager(*this, p), - m_is_diseq_tmp(0), + m_is_diseq_tmp(nullptr), m_units_to_reassert(m_manager), m_qhead(0), m_simp_qhead(0), @@ -176,7 +176,7 @@ namespace smt { for (unsigned i = 0; i < src_ctx.m_assigned_literals.size(); ++i) { literal lit; lit = TRANSLATE(src_ctx.m_assigned_literals[i]); - dst_ctx.mk_clause(1, &lit, 0, CLS_AUX, 0); + dst_ctx.mk_clause(1, &lit, nullptr, CLS_AUX, nullptr); } #if 0 literal_vector lits; @@ -232,8 +232,8 @@ namespace smt { } context * context::mk_fresh(symbol const * l, smt_params * p) { - context * new_ctx = alloc(context, m_manager, p == 0 ? m_fparams : *p); - new_ctx->set_logic(l == 0 ? m_setup.get_logic() : *l); + context * new_ctx = alloc(context, m_manager, p == nullptr ? m_fparams : *p); + new_ctx->set_logic(l == nullptr ? m_setup.get_logic() : *l); copy_plugins(*this, *new_ctx); return new_ctx; } @@ -741,9 +741,9 @@ namespace smt { enode * curr = n->m_trans.m_target; enode * prev = n; eq_justification js = n->m_trans.m_justification; - prev->m_trans.m_target = 0; + prev->m_trans.m_target = nullptr; prev->m_trans.m_justification = null_eq_justification; - while (curr != 0) { + 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; @@ -798,7 +798,7 @@ namespace smt { theory_var context::get_closest_var(enode * n, theory_id th_id) { if (th_id == null_theory_id) return null_theory_var; - while (n != 0) { + while (n != nullptr) { theory_var v = n->get_th_var(th_id); if (v != null_theory_var) return v; @@ -826,7 +826,7 @@ namespace smt { if (js.get_kind() == eq_justification::JUSTIFICATION) from_th = js.get_justification()->get_from_theory(); - if (r2->m_th_var_list.get_next() == 0 && r1->m_th_var_list.get_next() == 0) { + if (r2->m_th_var_list.get_next() == nullptr && r1->m_th_var_list.get_next() == nullptr) { // Common case: r2 and r1 have at most one theory var. theory_id t2 = r2->m_th_var_list.get_th_id(); theory_id t1 = r1->m_th_var_list.get_th_id(); @@ -1023,7 +1023,7 @@ namespace smt { } // restore theory vars - if (r2->m_th_var_list.get_next() == 0) { + if (r2->m_th_var_list.get_next() == nullptr) { // common case: r2 has at most one variable theory_var v2 = r2->m_th_var_list.get_th_var(); if (v2 != null_theory_var) { @@ -1043,7 +1043,7 @@ namespace smt { // r1 -> .. -> n1 -> n2 -> ... -> r2 SASSERT(r1->trans_reaches(r2)); SASSERT(r1->trans_reaches(n1)); - n1->m_trans.m_target = 0; + n1->m_trans.m_target = nullptr; n1->m_trans.m_justification = null_eq_justification; invert_trans(r1); // --------------- @@ -1067,7 +1067,7 @@ namespace smt { */ void context::restore_theory_vars(enode * r2, enode * r1) { SASSERT(r2->get_root() == r2); - theory_var_list * new_l2 = 0; + theory_var_list * new_l2 = nullptr; theory_var_list * l2 = r2->get_th_var_list(); while (l2) { theory_var v2 = l2->get_th_var(); @@ -1091,11 +1091,11 @@ namespace smt { } if (new_l2) { - new_l2->set_next(0); + new_l2->set_next(nullptr); } else { r2->m_th_var_list.set_th_var(null_theory_var); - r2->m_th_var_list.set_next(0); + r2->m_th_var_list.set_next(nullptr); } } @@ -1128,7 +1128,7 @@ namespace smt { } // Propagate disequalities to theories - if (r1->m_th_var_list.get_next() == 0 && r2->m_th_var_list.get_next() == 0) { + if (r1->m_th_var_list.get_next() == nullptr && r2->m_th_var_list.get_next() == nullptr) { // common case: r2 and r1 have at most one theory var. theory_id t1 = r1->m_th_var_list.get_th_id(); theory_var v1 = m_fparams.m_new_core2th_eq ? get_closest_var(n1, t1) : r1->m_th_var_list.get_th_var(); @@ -1646,11 +1646,11 @@ namespace smt { m_qmanager->relevant_eh(e); } - theory * propagated_th = 0; + theory * propagated_th = nullptr; family_id fid = to_app(n)->get_family_id(); if (fid != m_manager.get_basic_family_id()) { theory * th = get_theory(fid); - if (th != 0) { + if (th != nullptr) { th->relevant_eh(to_app(n)); propagated_th = th; // <<< mark that relevancy_eh was already invoked for theory th. } @@ -2412,7 +2412,7 @@ namespace smt { if (!bs.m_inconsistent) { m_conflict = null_b_justification; m_not_l = null_literal; - m_unsat_proof = 0; + m_unsat_proof = nullptr; } m_base_scopes.shrink(new_lvl); } @@ -2532,7 +2532,7 @@ namespace smt { if (m_manager.proofs_enabled() && !simp_lits.empty()) { SASSERT(m_scope_lvl == m_base_lvl); justification * js = cls->get_justification(); - justification * new_js = 0; + justification * new_js = nullptr; if (js->in_region()) new_js = mk_justification(unit_resolution_justification(m_region, js, @@ -2586,7 +2586,7 @@ namespace smt { } } justification * cls_js = cls->get_justification(); - justification * js = 0; + justification * js = nullptr; if (!cls_js || cls_js->in_region()) { // If cls_js is 0 or is allocated in a region, then // we can allocate the new justification in a region too. @@ -2598,7 +2598,7 @@ namespace smt { else { js = alloc(unit_resolution_justification, cls_js, simp_lits.size(), simp_lits.c_ptr()); // js took ownership of the justification object. - cls->set_justification(0); + cls->set_justification(nullptr); m_justifications.push_back(js); } set_justification(v0, m_bdata[v0], b_justification(js)); @@ -2851,7 +2851,7 @@ namespace smt { #endif void context::register_plugin(theory * th) { - if (m_theories.get_plugin(th->get_family_id()) != 0) { + if (m_theories.get_plugin(th->get_family_id()) != nullptr) { dealloc(th); return; // context already has a theory for the given family id. } @@ -2905,12 +2905,12 @@ namespace smt { void context::flush() { flet l1(m_flushing, true); TRACE("flush", tout << "m_scope_lvl: " << m_scope_lvl << "\n";); - m_relevancy_propagator = 0; + m_relevancy_propagator = nullptr; m_model_generator->reset(); for (theory* t : m_theory_set) t->flush_eh(); undo_trail_stack(0); - m_qmanager = 0; + m_qmanager = nullptr; del_clauses(m_aux_clauses, 0); del_clauses(m_lemmas, 0); del_justifications(m_justifications, 0); @@ -2918,7 +2918,7 @@ namespace smt { m_is_diseq_tmp->del_eh(m_manager, false); m_manager.dec_ref(m_is_diseq_tmp->get_owner()); enode::del_dummy(m_is_diseq_tmp); - m_is_diseq_tmp = 0; + m_is_diseq_tmp = nullptr; } std::for_each(m_almost_cg_tables.begin(), m_almost_cg_tables.end(), delete_proc()); } @@ -2929,7 +2929,7 @@ namespace smt { TRACE("begin_assert_expr", tout << mk_pp(e, m_manager) << "\n";); TRACE("begin_assert_expr_ll", tout << mk_ll_pp(e, m_manager) << "\n";); pop_to_base_lvl(); - if (pr == 0) + if (pr == nullptr) m_asserted_formulas.assert_expr(e); else m_asserted_formulas.assert_expr(e, pr); @@ -2937,7 +2937,7 @@ namespace smt { } void context::assert_expr(expr * e) { - assert_expr(e, 0); + assert_expr(e, nullptr); } void context::assert_expr(expr * e, proof * pr) { @@ -2966,7 +2966,7 @@ namespace smt { for (unsigned j = i+1; j < num_lits; ++j) { literal l1 = lits[i]; literal l2 = lits[j]; - mk_clause(~l1, ~l2, (justification*) 0); + mk_clause(~l1, ~l2, (justification*) nullptr); } } } else { @@ -3084,7 +3084,7 @@ namespace smt { } if (m_asserted_formulas.inconsistent() && !inconsistent()) { proof * pr = m_asserted_formulas.get_inconsistency_proof(); - if (pr == 0) { + if (pr == nullptr) { set_conflict(b_justification::mk_axiom()); } else { @@ -3404,7 +3404,7 @@ namespace smt { m_luby_idx = 1; m_lemma_gc_threshold = m_fparams.m_lemma_gc_initial; m_last_search_failure = OK; - m_unsat_proof = 0; + m_unsat_proof = nullptr; m_unsat_core .reset(); m_dyn_ack_manager .init_search_eh(); m_final_check_idx = 0; @@ -3866,7 +3866,7 @@ namespace smt { expr_signs.push_back(l.sign()); } #endif - proof * pr = 0; + proof * pr = nullptr; if (m_manager.proofs_enabled()) { pr = m_conflict_resolution->get_lemma_proof(); // check_proof(pr); @@ -3939,7 +3939,7 @@ namespace smt { } } #endif - justification * js = 0; + justification * js = nullptr; if (m_manager.proofs_enabled()) { js = alloc(justification_proof_wrapper, *this, pr, false); } @@ -4271,7 +4271,7 @@ namespace smt { sort * s = m_manager.get_sort(n->get_owner()); family_id fid = s->get_family_id(); theory * th = get_theory(fid); - if (th == 0) + if (th == nullptr) return false; return th->get_value(n, value); } @@ -4321,13 +4321,13 @@ namespace smt { proof * context::get_proof() { if (!m_manager.proofs_enabled()) - return 0; + return nullptr; return m_unsat_proof; } void context::get_model(model_ref & m) const { if (inconsistent()) - m = 0; + m = nullptr; else m = const_cast(m_model.get()); } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 3cd93fbe5..b637d8082 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -203,11 +203,11 @@ namespace smt { struct scoped_mk_model { context & m_ctx; scoped_mk_model(context & ctx):m_ctx(ctx) { - m_ctx.m_proto_model = 0; - m_ctx.m_model = 0; + m_ctx.m_proto_model = nullptr; + m_ctx.m_model = nullptr; } ~scoped_mk_model() { - if (m_ctx.m_proto_model.get() != 0) { + if (m_ctx.m_proto_model.get() != nullptr) { m_ctx.m_model = m_ctx.m_proto_model->mk_model(); try { m_ctx.add_rec_funs_to_model(); @@ -215,7 +215,7 @@ namespace smt { catch (...) { // no op } - m_ctx.m_proto_model = 0; // proto_model is not needed anymore. + m_ctx.m_proto_model = nullptr; // proto_model is not needed anymore. } } }; @@ -514,12 +514,12 @@ namespace smt { enode_vector::const_iterator begin_enodes_of(func_decl const * decl) const { unsigned id = decl->get_decl_id(); - return id < m_decl2enodes.size() ? m_decl2enodes[id].begin() : 0; + return id < m_decl2enodes.size() ? m_decl2enodes[id].begin() : nullptr; } enode_vector::const_iterator end_enodes_of(func_decl const * decl) const { unsigned id = decl->get_decl_id(); - return id < m_decl2enodes.size() ? m_decl2enodes[id].end() : 0; + return id < m_decl2enodes.size() ? m_decl2enodes[id].end() : nullptr; } ptr_vector::const_iterator begin_enodes() const { @@ -822,17 +822,17 @@ namespace smt { void internalize(expr * n, bool gate_ctx, unsigned generation); - clause * mk_clause(unsigned num_lits, literal * lits, justification * j, clause_kind k = CLS_AUX, clause_del_eh * del_eh = 0); + clause * mk_clause(unsigned num_lits, literal * lits, justification * j, clause_kind k = CLS_AUX, clause_del_eh * del_eh = nullptr); void mk_clause(literal l1, literal l2, justification * j); void mk_clause(literal l1, literal l2, literal l3, justification * j); - void mk_th_axiom(theory_id tid, unsigned num_lits, literal * lits, unsigned num_params = 0, parameter * params = 0); + void mk_th_axiom(theory_id tid, unsigned num_lits, literal * lits, unsigned num_params = 0, parameter * params = nullptr); - void mk_th_axiom(theory_id tid, literal l1, literal l2, unsigned num_params = 0, parameter * params = 0); + void mk_th_axiom(theory_id tid, literal l1, literal l2, unsigned num_params = 0, parameter * params = nullptr); - void mk_th_axiom(theory_id tid, literal l1, literal l2, literal l3, unsigned num_params = 0, parameter * params = 0); + void mk_th_axiom(theory_id tid, literal l1, literal l2, literal l3, unsigned num_params = 0, parameter * params = nullptr); /* * Provide a hint to the core solver that the specified literals form a "theory case split". @@ -1460,7 +1460,7 @@ namespace smt { If l == 0, then the logic of this context is used in the new context. If p == 0, then this->m_params is used */ - context * mk_fresh(symbol const * l = 0, smt_params * p = 0); + context * mk_fresh(symbol const * l = nullptr, smt_params * p = nullptr); static void copy(context& src, context& dst); @@ -1482,7 +1482,7 @@ namespace smt { void pop(unsigned num_scopes); - lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0, bool reset_cancel = true, bool already_did_theory_assumptions = false); + lbool check(unsigned num_assumptions = 0, expr * const * assumptions = nullptr, bool reset_cancel = true, bool already_did_theory_assumptions = false); lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index 1452dc610..e09e83f6b 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -32,7 +32,7 @@ namespace smt { n->m_owner = owner; n->m_root = n; n->m_next = n; - n->m_cg = 0; + n->m_cg = nullptr; n->m_class_size = 1; n->m_generation = generation; n->m_func_decl_id = UINT_MAX; @@ -130,11 +130,11 @@ namespace smt { if (m_th_var_list.get_th_var() == null_theory_var) { m_th_var_list.set_th_var(v); m_th_var_list.set_th_id(id); - m_th_var_list.set_next(0); + m_th_var_list.set_next(nullptr); } else { theory_var_list * l = &m_th_var_list; - while (l->get_next() != 0) { + while (l->get_next() != nullptr) { SASSERT(l->get_th_id() != id); l = l->get_next(); } @@ -172,11 +172,11 @@ namespace smt { SASSERT(get_th_var(id) != null_theory_var); if (m_th_var_list.get_th_id() == id) { theory_var_list * next = m_th_var_list.get_next(); - if (next == 0) { + if (next == nullptr) { // most common case m_th_var_list.set_th_var(null_theory_var); m_th_var_list.set_th_id(null_theory_id); - m_th_var_list.set_next(0); + m_th_var_list.set_next(nullptr); } else { m_th_var_list = *next; @@ -405,7 +405,7 @@ namespace smt { tmp_enode::tmp_enode(): m_app(0), m_capacity(0), - m_enode_data(0) { + m_enode_data(nullptr) { SASSERT(m_app.get_app()->get_decl() == 0); set_capacity(5); } diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index f471314fa..b216665e5 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -33,7 +33,7 @@ namespace smt { enode * m_target; eq_justification m_justification; trans_justification(): - m_target(0), + m_target(nullptr), m_justification(null_eq_justification) { } }; @@ -116,7 +116,7 @@ namespace smt { theory_var_list * get_th_var_list() { - return m_th_var_list.get_th_var() == null_theory_var ? 0 : &m_th_var_list; + return m_th_var_list.get_th_var() == null_theory_var ? nullptr : &m_th_var_list; } friend class set_merge_tf_trail; @@ -306,7 +306,7 @@ namespace smt { } theory_var_list const * get_th_var_list() const { - return m_th_var_list.get_th_var() == null_theory_var ? 0 : &m_th_var_list; + return m_th_var_list.get_th_var() == null_theory_var ? nullptr : &m_th_var_list; } bool has_th_vars() const { diff --git a/src/smt/smt_eq_justification.h b/src/smt/smt_eq_justification.h index af538a130..952caa2a5 100644 --- a/src/smt/smt_eq_justification.h +++ b/src/smt/smt_eq_justification.h @@ -78,7 +78,7 @@ namespace smt { } }; - const eq_justification null_eq_justification(static_cast(0)); + const eq_justification null_eq_justification(static_cast(nullptr)); }; #endif /* SMT_EQ_JUSTIFICATION_H_ */ diff --git a/src/smt/smt_implied_equalities.cpp b/src/smt/smt_implied_equalities.cpp index d021708fc..0b944c145 100644 --- a/src/smt/smt_implied_equalities.cpp +++ b/src/smt/smt_implied_equalities.cpp @@ -96,7 +96,7 @@ namespace smt { ++m_stats_calls; m_solver.push(); m_solver.assert_expr(m.mk_not(m.mk_eq(s, t))); - bool is_eq = l_false == m_solver.check_sat(0,0); + bool is_eq = l_false == m_solver.check_sat(0,nullptr); m_solver.pop(1); TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << (is_eq?"eq":"unrelated") << "\n";); if (is_eq) { @@ -123,7 +123,7 @@ namespace smt { m_stats_timer.start(); m_solver.push(); m_solver.assert_expr(m.mk_not(m.mk_eq(s, t))); - bool is_eq = l_false == m_solver.check_sat(0,0); + bool is_eq = l_false == m_solver.check_sat(0,nullptr); m_solver.pop(1); m_stats_timer.stop(); TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << (is_eq?"eq":"unrelated") << "\n";); @@ -155,7 +155,7 @@ namespace smt { m_solver.push(); unsigned arity = get_array_arity(srt); expr_ref_vector args(m); - args.push_back(0); + args.push_back(nullptr); for (unsigned i = 0; i < arity; ++i) { sort* srt_i = get_array_domain(srt, i); expr* idx = m.mk_fresh_const("index", srt_i); @@ -163,10 +163,10 @@ namespace smt { } for (unsigned i = 0; i < terms.size(); ++i) { args[0] = terms[i].term; - terms[i].term = m.mk_app(m_array_util.get_family_id(), OP_SELECT, 0, 0, args.size(), args.c_ptr()); + terms[i].term = m.mk_app(m_array_util.get_family_id(), OP_SELECT, 0, nullptr, args.size(), args.c_ptr()); } assert_relevant(terms); - VERIFY(m_solver.check_sat(0,0) != l_false); + VERIFY(m_solver.check_sat(0,nullptr) != l_false); model_ref model1; m_solver.get_model(model1); SASSERT(model1.get()); @@ -215,7 +215,7 @@ namespace smt { expr* s = terms[vec[j]].term; m_solver.push(); m_solver.assert_expr(m.mk_not(m.mk_eq(t, s))); - lbool is_sat = m_solver.check_sat(0,0); + lbool is_sat = m_solver.check_sat(0,nullptr); m_solver.pop(1); TRACE("get_implied_equalities", tout << mk_pp(t, m) << " = " << mk_pp(s, m) << " " << is_sat << "\n";); if (is_sat == l_false) { @@ -284,7 +284,7 @@ namespace smt { } lbool reduce_cond(model_ref& model, expr* e) { - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; if (m.is_eq(e, e1, e2) && m_array_util.is_as_array(e1) && m_array_util.is_as_array(e2)) { if (e1 == e2) { return l_true; @@ -335,7 +335,7 @@ namespace smt { m_solver.push(); assert_relevant(num_terms, terms); - lbool is_sat = m_solver.check_sat(0,0); + lbool is_sat = m_solver.check_sat(0,nullptr); if (is_sat != l_false) { model_ref model; diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 3c92b8318..3d999c3b7 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -121,7 +121,7 @@ namespace smt { bool visited = true; family_id fid = to_app(n)->get_family_id(); theory * th = m_theories.get_plugin(fid); - bool def_int = th == 0 || th->default_internalizer(); + bool def_int = th == nullptr || th->default_internalizer(); if (!def_int) { ptr_buffer descendants; get_foreign_descendants(to_app(n), fid, descendants); @@ -301,7 +301,7 @@ namespace smt { e->mark_as_interpreted(); app_ref eq(m_manager.mk_eq(fapp, val), m_manager); TRACE("assert_distinct", tout << "eq: " << mk_pp(eq, m_manager) << "\n";); - assert_default(eq, 0); + assert_default(eq, nullptr); mark_as_relevant(eq.get()); // TODO: we may want to hide the auxiliary values val and the function f from the model. } @@ -695,7 +695,7 @@ namespace smt { void context::internalize_term(app * n) { if (e_internalized(n)) { theory * th = m_theories.get_plugin(n->get_family_id()); - if (th != 0) { + if (th != nullptr) { // This code is necessary because some theories may decide // not to create theory variables for a nested application. // Example: @@ -1271,7 +1271,7 @@ namespace smt { case CLS_AUX: { literal_buffer simp_lits; if (!simplify_aux_clause_literals(num_lits, lits, simp_lits)) - return 0; // clause is equivalent to true; + return nullptr; // clause is equivalent to true; DEBUG_CODE({ for (unsigned i = 0; i < simp_lits.size(); i++) { SASSERT(get_assignment(simp_lits[i]) == l_true); @@ -1284,7 +1284,7 @@ namespace smt { } case CLS_AUX_LEMMA: { if (!simplify_aux_lemma_literals(num_lits, lits)) - return 0; // clause is equivalent to true + return nullptr; // clause is equivalent to true // simplify_aux_lemma_literals does not delete literals assigned to false, so // it is not necessary to create a unit_resolution_justification break; @@ -1303,14 +1303,14 @@ namespace smt { if (j && !j->in_region()) m_justifications.push_back(j); TRACE("mk_clause", tout << "empty clause... setting conflict\n";); - set_conflict(j == 0 ? b_justification::mk_axiom() : b_justification(j)); + set_conflict(j == nullptr ? b_justification::mk_axiom() : b_justification(j)); SASSERT(inconsistent()); - return 0; + return nullptr; case 1: if (j && !j->in_region()) m_justifications.push_back(j); assign(lits[0], j); - return 0; + return nullptr; case 2: if (use_binary_clause_opt(lits[0], lits[1], lemma)) { literal l1 = lits[0]; @@ -1321,7 +1321,7 @@ namespace smt { assign(l1, b_justification(~l2)); m_stats.m_num_mk_bin_clause++; - return 0; + return nullptr; } default: { m_stats.m_num_mk_clause++; @@ -1404,7 +1404,7 @@ namespace smt { } void context::mk_th_axiom(theory_id tid, unsigned num_lits, literal * lits, unsigned num_params, parameter * params) { - justification * js = 0; + justification * js = nullptr; TRACE("mk_th_axiom", display_literals_verbose(tout, num_lits, lits); tout << "\n";); @@ -1449,12 +1449,12 @@ namespace smt { void context::mk_gate_clause(unsigned num_lits, literal * lits) { if (m_manager.proofs_enabled()) { - proof * pr = mk_clause_def_axiom(num_lits, lits, 0); + proof * pr = mk_clause_def_axiom(num_lits, lits, nullptr); TRACE("gate_clause", tout << mk_ll_pp(pr, m_manager);); mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); } else { - mk_clause(num_lits, lits, 0); + mk_clause(num_lits, lits, nullptr); } } @@ -1487,7 +1487,7 @@ namespace smt { mk_clause(num_lits, lits, mk_justification(justification_proof_wrapper(*this, pr))); } else { - mk_clause(num_lits, lits, 0); + mk_clause(num_lits, lits, nullptr); } } diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index 440da7297..4ac176a2b 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -90,17 +90,17 @@ namespace smt { SASSERT(m_antecedent); ptr_buffer prs; proof * pr = cr.get_proof(m_antecedent); - bool visited = pr != 0; + bool visited = pr != nullptr; prs.push_back(pr); for (unsigned i = 0; i < m_num_literals; i++) { proof * pr = cr.get_proof(m_literals[i]); - if (pr == 0) + if (pr == nullptr) visited = false; else prs.push_back(pr); } if (!visited) - return 0; + return nullptr; ast_manager & m = cr.get_manager(); TRACE("unit_resolution_justification_bug", tout << "in mk_proof\n"; @@ -150,7 +150,7 @@ namespace smt { } if (!visited) - return 0; + return nullptr; expr * lhs = m_node1->get_root()->get_owner(); expr * rhs = m_node2->get_root()->get_owner(); @@ -178,7 +178,7 @@ namespace smt { proof * pr2 = m.mk_rewrite(m.get_fact(pr1), lit); return m.mk_modus_ponens(pr1, pr2); } - return 0; + return nullptr; } void eq_propagation_justification::get_antecedents(conflict_resolution & cr) { @@ -241,7 +241,7 @@ namespace smt { mk_pp(m.get_fact(pr), m) << "\n";); return pr; } - return 0; + return nullptr; } simple_justification::simple_justification(region & r, unsigned num_lits, literal const * lits): @@ -266,7 +266,7 @@ namespace smt { bool visited = true; for (unsigned i = 0; i < m_num_literals; i++) { proof * pr = cr.get_proof(m_literals[i]); - if (pr == 0) + if (pr == nullptr) visited = false; else result.push_back(pr); @@ -284,15 +284,15 @@ namespace smt { lits.push_back(l); } if (lits.size() == 1) - return m.mk_th_lemma(m_th_id, lits.get(0), 0, 0, m_params.size(), m_params.c_ptr()); + return m.mk_th_lemma(m_th_id, lits.get(0), 0, nullptr, m_params.size(), m_params.c_ptr()); else - return m.mk_th_lemma(m_th_id, m.mk_or(lits.size(), lits.c_ptr()), 0, 0, m_params.size(), m_params.c_ptr()); + return m.mk_th_lemma(m_th_id, m.mk_or(lits.size(), lits.c_ptr()), 0, nullptr, m_params.size(), m_params.c_ptr()); } proof * theory_propagation_justification::mk_proof(conflict_resolution & cr) { ptr_buffer prs; if (!antecedent2proof(cr, prs)) - return 0; + return nullptr; context & ctx = cr.get_context(); ast_manager & m = cr.get_manager(); expr_ref fact(m); @@ -303,7 +303,7 @@ namespace smt { proof * theory_conflict_justification::mk_proof(conflict_resolution & cr) { ptr_buffer prs; if (!antecedent2proof(cr, prs)) - return 0; + return nullptr; ast_manager & m = cr.get_manager(); return m.mk_th_lemma(m_th_id, m.mk_false(), prs.size(), prs.c_ptr(), m_params.size(), m_params.c_ptr()); } @@ -334,7 +334,7 @@ namespace smt { for (unsigned i = 0; i < m_num_eqs; i++) { enode_pair const & p = m_eqs[i]; proof * pr = cr.get_proof(p.first, p.second); - if (pr == 0) + if (pr == nullptr) visited = false; else result.push_back(pr); @@ -345,7 +345,7 @@ namespace smt { proof * ext_theory_propagation_justification::mk_proof(conflict_resolution & cr) { ptr_buffer prs; if (!antecedent2proof(cr, prs)) - return 0; + return nullptr; context & ctx = cr.get_context(); ast_manager & m = cr.get_manager(); expr_ref fact(m); @@ -356,7 +356,7 @@ namespace smt { proof * ext_theory_conflict_justification::mk_proof(conflict_resolution & cr) { ptr_buffer prs; if (!antecedent2proof(cr, prs)) - return 0; + return nullptr; ast_manager & m = cr.get_manager(); return m.mk_th_lemma(m_th_id, m.mk_false(), prs.size(), prs.c_ptr(), m_params.size(), m_params.c_ptr()); } @@ -364,7 +364,7 @@ namespace smt { proof * ext_theory_eq_propagation_justification::mk_proof(conflict_resolution & cr) { ptr_buffer prs; if (!antecedent2proof(cr, prs)) - return 0; + return nullptr; ast_manager & m = cr.get_manager(); context & ctx = cr.get_context(); expr * fact = ctx.mk_eq_atom(m_lhs->get_owner(), m_rhs->get_owner()); @@ -415,9 +415,9 @@ namespace smt { lits.push_back(l); } if (lits.size() == 1) - return m.mk_th_lemma(m_th_id, lits.get(0), 0, 0, m_params.size(), m_params.c_ptr()); + return m.mk_th_lemma(m_th_id, lits.get(0), 0, nullptr, m_params.size(), m_params.c_ptr()); else - return m.mk_th_lemma(m_th_id, m.mk_or(lits.size(), lits.c_ptr()), 0, 0, m_params.size(), m_params.c_ptr()); + return m.mk_th_lemma(m_th_id, m.mk_or(lits.size(), lits.c_ptr()), 0, nullptr, m_params.size(), m_params.c_ptr()); } }; diff --git a/src/smt/smt_justification.h b/src/smt/smt_justification.h index 1b5aecfe5..8354c8860 100644 --- a/src/smt/smt_justification.h +++ b/src/smt/smt_justification.h @@ -255,7 +255,7 @@ namespace smt { theory_axiom_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, - unsigned num_params = 0, parameter* params = 0): + unsigned num_params = 0, parameter* params = nullptr): simple_theory_justification(fid, r, num_lits, lits, num_params, params) {} void get_antecedents(conflict_resolution & cr) override {} @@ -269,7 +269,7 @@ namespace smt { literal m_consequent; public: theory_propagation_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, literal consequent, - unsigned num_params = 0, parameter* params = 0): + unsigned num_params = 0, parameter* params = nullptr): simple_theory_justification(fid, r, num_lits, lits, num_params, params), m_consequent(consequent) {} proof * mk_proof(conflict_resolution & cr) override; @@ -282,7 +282,7 @@ namespace smt { class theory_conflict_justification : public simple_theory_justification { public: theory_conflict_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, - unsigned num_params = 0, parameter* params = 0): + unsigned num_params = 0, parameter* params = nullptr): simple_theory_justification(fid, r, num_lits, lits, num_params, params) {} proof * mk_proof(conflict_resolution & cr) override; @@ -322,7 +322,7 @@ namespace smt { public: ext_theory_simple_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, - unsigned num_params = 0, parameter* params = 0): + unsigned num_params = 0, parameter* params = nullptr): ext_simple_justification(r, num_lits, lits, num_eqs, eqs), m_th_id(fid), m_params(num_params, params) {} ~ext_theory_simple_justification() override {} @@ -341,7 +341,7 @@ namespace smt { unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, literal consequent, - unsigned num_params = 0, parameter* params = 0): + unsigned num_params = 0, parameter* params = nullptr): ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params), m_consequent(consequent) {} @@ -354,7 +354,7 @@ namespace smt { public: ext_theory_conflict_justification(family_id fid, region & r, unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, - unsigned num_params = 0, parameter* params = 0): + unsigned num_params = 0, parameter* params = nullptr): ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params) {} proof * mk_proof(conflict_resolution & cr) override; @@ -371,7 +371,7 @@ namespace smt { unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, enode * lhs, enode * rhs, - unsigned num_params = 0, parameter* params = 0): + unsigned num_params = 0, parameter* params = nullptr): ext_theory_simple_justification(fid, r, num_lits, lits, num_eqs, eqs, num_params, params), m_lhs(lhs), m_rhs(rhs) {} proof * mk_proof(conflict_resolution & cr) override; @@ -392,7 +392,7 @@ namespace smt { public: theory_lemma_justification(family_id fid, context & ctx, unsigned num_lits, literal const * lits, - unsigned num_params = 0, parameter* params = 0); + unsigned num_params = 0, parameter* params = nullptr); ~theory_lemma_justification() override; diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index d10cab4f3..141ab1dae 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -126,7 +126,7 @@ namespace smt { /** \brief Satisfiability check. */ - lbool check(unsigned num_assumptions = 0, expr * const * assumptions = 0); + lbool check(unsigned num_assumptions = 0, expr * const * assumptions = nullptr); lbool check(expr_ref_vector const& asms) { return check(asms.size(), asms.c_ptr()); } diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index cd59014aa..765cc87f5 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -33,19 +33,19 @@ namespace smt { m(m), m_params(p), m_autil(m), - m_qm(0), - m_context(0), - m_root2value(0), + m_qm(nullptr), + m_context(nullptr), + m_root2value(nullptr), m_model_finder(mf), m_max_cexs(1), m_iteration_idx(0), - m_curr_model(0), + m_curr_model(nullptr), m_pinned_exprs(m) { } model_checker::~model_checker() { - m_aux_context = 0; // delete aux context before fparams - m_fparams = 0; + m_aux_context = nullptr; // delete aux context before fparams + m_fparams = nullptr; } quantifier * model_checker::get_flat_quantifier(quantifier * q) { @@ -72,7 +72,7 @@ namespace smt { m_value2expr.insert(val, n->get_owner()); } } - expr * t = 0; + expr * t = nullptr; m_value2expr.find(val, t); return t; } @@ -111,10 +111,10 @@ namespace smt { ptr_buffer subst_args; unsigned num_decls = q->get_num_decls(); subst_args.resize(num_decls, 0); - sks.resize(num_decls, 0); + sks.resize(num_decls, nullptr); for (unsigned i = 0; i < num_decls; i++) { sort * s = q->get_decl_sort(num_decls - i - 1); - expr * sk = m.mk_fresh_const(0, s); + expr * sk = m.mk_fresh_const(nullptr, s); sks[num_decls - i - 1] = sk; subst_args[num_decls - i - 1] = sk; if (m_curr_model->is_finite(s)) { @@ -132,7 +132,7 @@ namespace smt { } bool model_checker::add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv) { - if (cex == 0) { + if (cex == nullptr) { TRACE("model_checker", tout << "no model is available\n";); return false; } @@ -158,7 +158,7 @@ namespace smt { if (use_inv) { unsigned sk_term_gen; expr * sk_term = m_model_finder.get_inv(q, i, sk_value, sk_term_gen); - if (sk_term != 0) { + if (sk_term != nullptr) { TRACE("model_checker", tout << "Found inverse " << mk_pp(sk_term, m) << "\n";); SASSERT(!m.is_model_value(sk_term)); if (sk_term_gen > max_generation) @@ -172,7 +172,7 @@ namespace smt { } else { expr * sk_term = get_term_from_ctx(sk_value); - if (sk_term != 0) { + if (sk_term != nullptr) { sk_value = sk_term; } } @@ -323,7 +323,7 @@ namespace smt { bool is_undef = false; expr_ref_vector args(m); unsigned num_decls = q->get_num_decls(); - args.resize(num_decls, 0); + args.resize(num_decls, nullptr); var_subst sub(m); expr_ref tmp(m), result(m); for (; it != end; ++it) { @@ -502,7 +502,7 @@ namespace smt { expr_ref inst_expr(m); instantiate(m, q, inst->m_bindings, inst_expr); tout << "(assert " << mk_ismt2_pp(inst_expr, m) << ")\n";); - m_context->add_instance(q, 0, num_decls, bindings.c_ptr(), gen, gen, gen, dummy); + m_context->add_instance(q, nullptr, num_decls, bindings.c_ptr(), gen, gen, gen, dummy); TRACE("model_checker_bug_detail", tout << "after instantiating, inconsistent: " << m_context->inconsistent() << "\n";); } } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 447705572..778337697 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -120,7 +120,7 @@ namespace smt { } expr * get_inv(expr * v) const { - expr * t = 0; + expr * t = nullptr; m_inv.find(v, t); return t; } @@ -140,7 +140,7 @@ namespace smt { if (!t_val) break; TRACE("model_finder", tout << mk_pp(t, m_manager) << " " << mk_pp(t_val, m_manager) << "\n";); - expr * old_t = 0; + expr * old_t = nullptr; if (m_inv.find(t_val, old_t)) { unsigned old_t_gen = 0; SASSERT(m_elems.contains(old_t)); @@ -223,14 +223,14 @@ namespace smt { public: node(unsigned id, sort * s): m_id(id), - m_find(0), + m_find(nullptr), m_eqc_size(1), m_sort(s), m_mono_proj(false), m_signed_proj(false), - m_set(0), - m_else(0), - m_proj(0) { + m_set(nullptr), + m_else(nullptr), + m_proj(nullptr) { } ~node() { @@ -242,7 +242,7 @@ namespace smt { sort * get_sort() const { return m_sort; } - bool is_root() const { return m_find == 0; } + bool is_root() const { return m_find == nullptr; } node * get_root() const { node * curr = const_cast(this); @@ -428,7 +428,7 @@ namespace smt { } node * mk_node(key2node & m, ast * n, unsigned i, sort * s) { - node * r = 0; + node * r = nullptr; ast_idx_pair k(n, i); if (m.find(k, r)) { SASSERT(r->get_sort() == s); @@ -469,11 +469,11 @@ namespace smt { m_arith(m), m_bv(m), m_next_node_id(0), - m_context(0), + m_context(nullptr), m_ks(m), - m_model(0), + m_model(nullptr), m_eval_cache_range(m), - m_new_constraints(0) { + m_new_constraints(nullptr) { } virtual ~auf_solver() { @@ -523,10 +523,10 @@ namespace smt { instantiation_set const * get_uvar_inst_set(quantifier * q, unsigned i) const { SASSERT(!has_quantifiers(q->get_expr())); ast_idx_pair k(q, i); - node * r = 0; + node * r = nullptr; if (m_uvars.find(k, r)) return r->get_instantiation_set(); - return 0; + return nullptr; } void mk_instantiation_sets() { @@ -567,13 +567,13 @@ namespace smt { } expr * eval(expr * n, bool model_completion) override { - expr * r = 0; + expr * r = nullptr; if (m_eval_cache[model_completion].find(n, r)) { return r; } expr_ref tmp(m); if (!m_model->eval(n, tmp, model_completion)) { - r = 0; + r = nullptr; TRACE("model_finder", tout << "eval\n" << mk_pp(n, m) << "\n-----> null\n";); } else { @@ -602,7 +602,7 @@ namespace smt { for (node* a : avoid_set) { node * n = a->get_root(); - if (!n->is_mono_proj() && n->get_else() != 0) { + if (!n->is_mono_proj() && n->get_else() != nullptr) { expr * val = eval(n->get_else(), true); SASSERT(val != 0); r.push_back(val); @@ -621,7 +621,7 @@ namespace smt { instantiation_set const * s = n->get_instantiation_set(); obj_map const & elems = s->get_elems(); - expr * t_result = 0; + expr * t_result = nullptr; unsigned gen_result = UINT_MAX; for (auto const& kv : elems) { expr * t = kv.m_key; @@ -635,7 +635,7 @@ namespace smt { break; } } - if (!found && (t_result == 0 || gen < gen_result)) { + if (!found && (t_result == nullptr || gen < gen_result)) { t_result = t; gen_result = gen; } @@ -652,7 +652,7 @@ namespace smt { */ app * get_k_for(sort * s) { SASSERT(is_infinite(s)); - app * r = 0; + app * r = nullptr; if (m_sort2k.find(s, r)) return r; r = m.mk_fresh_const("k", s); @@ -674,11 +674,11 @@ namespace smt { SASSERT(is_infinite(s)); func_decl * k_decl = k->get_decl(); expr * r = m_model->get_const_interp(k_decl); - if (r != 0) + if (r != nullptr) return r; r = m_model->get_fresh_value(s); - if (r == 0) - return 0; + if (r == nullptr) + return nullptr; m_model->register_decl(k_decl, r); SASSERT(m_model->get_const_interp(k_decl) == r); TRACE("model_finder", tout << mk_pp(r, m) << "\n";); @@ -694,7 +694,7 @@ namespace smt { TRACE("assert_k_diseq_exceptions", tout << "assert_k_diseq_exceptions, " << "k: " << mk_pp(k, m) << "\nexceptions:\n"; for (expr * e : exceptions) tout << mk_pp(e, m) << "\n";); expr * k_interp = get_k_interp(k); - if (k_interp == 0) + if (k_interp == nullptr) return false; for (expr * ex : exceptions) { expr * ex_val = eval(ex, true); @@ -720,7 +720,7 @@ namespace smt { ptr_buffer ex_vals; collect_exceptions_values(n, ex_vals); expr * e = pick_instance_diff_exceptions(n, ex_vals); - if (e != 0) { + if (e != nullptr) { n->set_else(e); return; } @@ -912,7 +912,7 @@ namespace smt { func_decl * f = to_func_decl(kv.m_key.first); if (!r.contains(f)) { func_interp * fi = m_model->get_func_interp(f); - if (fi == 0) { + if (fi == nullptr) { fi = alloc(func_interp, m, f->get_arity()); m_model->register_decl(f, fi); SASSERT(fi->is_partial()); @@ -1013,10 +1013,10 @@ namespace smt { is irrelevant after the projections are applied. */ func_decl * get_f_i_proj(func_decl * f, unsigned i) { - node * r = 0; + node * r = nullptr; ast_idx_pair k(f, i); if (!m_A_f_is.find(k, r)) - return 0; + return nullptr; return r->get_proj(); } @@ -1039,7 +1039,7 @@ namespace smt { for (unsigned i = 0; i < arity; i++) { var * v = m.mk_var(i, f->get_domain(i)); func_decl * pi = get_f_i_proj(f, i); - if (pi != 0) { + if (pi != nullptr) { args.push_back(m.mk_app(pi, v)); has_proj = true; } @@ -1384,9 +1384,9 @@ namespace smt { func_decl * get_array_func_decl(app * ground_array, auf_solver & s) { expr * ground_array_interp = s.eval(ground_array, false); - if (ground_array_interp != 0 && m_array.is_as_array(ground_array_interp)) + if (ground_array_interp != nullptr && m_array.is_as_array(ground_array_interp)) return m_array.get_as_array_func_decl(ground_array_interp); - return 0; + return nullptr; } public: @@ -1656,7 +1656,7 @@ namespace smt { expr * get_cond() const { return m_cond; } - bool is_unconditional() const { return m_cond == 0 || m_manager.is_true(m_cond); } + bool is_unconditional() const { return m_cond == nullptr || m_manager.is_true(m_cond); } bool satisfy_atom() const { return m_satisfy_atom; } @@ -1736,8 +1736,8 @@ namespace smt { m_flat_q(m), m_is_auf(true), m_has_x_eq_y(false), - m_the_one(0), - m_uvar_inst_sets(0) { + m_the_one(nullptr), + m_uvar_inst_sets(nullptr) { if (has_quantifiers(q->get_expr())) { static bool displayed_flat_msg = false; if (!displayed_flat_msg) { @@ -1850,30 +1850,30 @@ namespace smt { void populate_macro_based_inst_sets(context * ctx, evaluator & ev) { SASSERT(m_the_one != 0); - if (m_uvar_inst_sets != 0) + if (m_uvar_inst_sets != nullptr) return; m_uvar_inst_sets = alloc(ptr_vector); for (qinfo* qi : m_qinfo_vect) qi->populate_inst_sets(m_flat_q, m_the_one, *m_uvar_inst_sets, ctx); for (instantiation_set * s : *m_uvar_inst_sets) { - if (s != 0) + if (s != nullptr) s->mk_inverse(ev); } } instantiation_set * get_macro_based_inst_set(unsigned vidx, context * ctx, evaluator & ev) { - if (m_the_one == 0) - return 0; + if (m_the_one == nullptr) + return nullptr; populate_macro_based_inst_sets(ctx, ev); return m_uvar_inst_sets->get(vidx, 0); } void reset_the_one() { - m_the_one = 0; + m_the_one = nullptr; if (m_uvar_inst_sets) { std::for_each(m_uvar_inst_sets->begin(), m_uvar_inst_sets->end(), delete_proc()); dealloc(m_uvar_inst_sets); - m_uvar_inst_sets = 0; + m_uvar_inst_sets = nullptr; } } }; @@ -2389,7 +2389,7 @@ namespace smt { m_array_util(m), m_arith_util(m), m_bv_util(m), - m_info(0) { + m_info(nullptr) { } @@ -2416,7 +2416,7 @@ namespace smt { collect_macro_candidates(q); - m_info = 0; + m_info = nullptr; } }; @@ -2431,7 +2431,7 @@ namespace smt { proto_model * m_model; quantifier_info * get_qinfo(quantifier * q) const { - quantifier_info * qi = 0; + quantifier_info * qi = nullptr; m_q2info.find(q, qi); SASSERT(qi != 0); return qi; @@ -2440,7 +2440,7 @@ namespace smt { void set_else_interp(func_decl * f, expr * f_else) { SASSERT(f_else != 0); func_interp * fi = m_model->get_func_interp(f); - if (fi == 0) { + if (fi == nullptr) { fi = alloc(func_interp, m_manager, f->get_arity()); m_model->register_decl(f, fi); } @@ -2453,7 +2453,7 @@ namespace smt { base_macro_solver(ast_manager & m, obj_map const & q2i): m_manager(m), m_q2info(q2i), - m_model(0) { + m_model(nullptr) { } virtual ~base_macro_solver() {} @@ -2596,7 +2596,7 @@ namespace smt { void insert_q_f(quantifier * q, func_decl * f) { SASSERT(!m_forbidden.contains(f)); - quantifier_set * s = 0; + quantifier_set * s = nullptr; if (!m_q_f.find(f, s)) { s = alloc(quantifier_set); m_q_f.insert(f, s); @@ -2607,7 +2607,7 @@ namespace smt { } void insert_f2def(func_decl * f, expr * def) { - expr_set * s = 0; + expr_set * s = nullptr; if (!m_f2defs.find(f, s)) { s = alloc(expr_set); m_f2defs.insert(f, s); @@ -2619,7 +2619,7 @@ namespace smt { void insert_q_f_def(quantifier * q, func_decl * f, expr * def) { SASSERT(!m_forbidden.contains(f)); - quantifier_set * s = 0; + quantifier_set * s = nullptr; if (!m_q_f_def.find(f, def, s)) { s = alloc(quantifier_set); m_q_f_def.insert(f, def, s); @@ -2631,21 +2631,21 @@ namespace smt { } quantifier_set * get_q_f(func_decl * f) { - quantifier_set * s = 0; + quantifier_set * s = nullptr; m_q_f.find(f, s); SASSERT(s != 0); return s; } quantifier_set * get_q_f_def(func_decl * f, expr * def) { - quantifier_set * s = 0; + quantifier_set * s = nullptr; m_q_f_def.find(f, def, s); SASSERT(s != 0); return s; } expr_set * get_f_defs(func_decl * f) { - expr_set * s = 0; + expr_set * s = nullptr; m_f2defs.find(f, s); SASSERT(s != 0); return s; @@ -2762,7 +2762,7 @@ namespace smt { void operator()(quantifier * q, bool ins) { quantifier_info * qi = m_owner->get_qinfo(q); - qi->set_the_one(0); + qi->set_the_one(nullptr); } ev_handler(hint_solver * o): @@ -3020,7 +3020,7 @@ namespace smt { // Return true if r1 is a better macro than r2. bool is_better_macro(cond_macro * r1, cond_macro * r2) { - if (r2 == 0 || !r1->is_hint()) + if (r2 == nullptr || !r1->is_hint()) return true; if (!r2->is_hint()) return false; @@ -3031,7 +3031,7 @@ namespace smt { } cond_macro * get_macro_for(func_decl * f, quantifier * q) { - cond_macro * r = 0; + cond_macro * r = nullptr; quantifier_info * qi = get_qinfo(q); quantifier_info::macro_iterator it = qi->begin_macros(); quantifier_info::macro_iterator end = qi->end_macros(); @@ -3094,14 +3094,14 @@ namespace smt { if (m->is_unconditional()) return; // f is part of a full macro... ignoring it. to_remove.push_back(q); - if (fi_else.get() == 0) { + if (fi_else.get() == nullptr) { fi_else = m->get_def(); } else { fi_else = m_manager.mk_ite(m->get_cond(), m->get_def(), fi_else); } } - if (fi_else.get() != 0 && add_macro(f, fi_else)) { + if (fi_else.get() != nullptr && add_macro(f, fi_else)) { for (quantifier * q : to_remove) { get_qinfo(q)->set_the_one(f); removed.insert(q); @@ -3139,7 +3139,7 @@ namespace smt { non_auf_macro_solver(ast_manager & m, obj_map const & q2i, func_decl_dependencies & d): base_macro_solver(m, q2i), m_dependencies(d), - m_qi_params(0) { + m_qi_params(nullptr) { } void set_params(qi_params const & p) { @@ -3157,7 +3157,7 @@ namespace smt { model_finder::model_finder(ast_manager & m): m_manager(m), - m_context(0), + m_context(nullptr), m_analyzer(alloc(quantifier_analyzer, *this, m)), m_auf_solver(alloc(auf_solver, m)), m_dependencies(m), @@ -3182,7 +3182,7 @@ namespace smt { } mf::quantifier_info * model_finder::get_quantifier_info(quantifier * q) const { - quantifier_info * info = 0; + quantifier_info * info = nullptr; m_q2info.find(q, info); SASSERT(info != 0); return info; @@ -3348,7 +3348,7 @@ namespace smt { instantiation_set const * r = m_auf_solver->get_uvar_inst_set(flat_q, flat_q->get_num_decls() - q->get_num_decls() + i); TRACE("model_finder", tout << "q: #" << q->get_id() << "\n" << mk_pp(q,m_manager) << "\nflat_q: " << mk_pp(flat_q, m_manager) << "\ni: " << i << " " << flat_q->get_num_decls() - q->get_num_decls() + i << "\n";); - if (r != 0) + if (r != nullptr) return r; // quantifier was not processed by AUF solver... // it must have been satisfied by "macro"/"hint". @@ -3368,10 +3368,10 @@ namespace smt { */ expr * model_finder::get_inv(quantifier * q, unsigned i, expr * val, unsigned & generation) const { instantiation_set const * s = get_uvar_inst_set(q, i); - if (s == 0) - return 0; + if (s == nullptr) + return nullptr; expr * t = s->get_inv(val); - if (t != 0) { + if (t != nullptr) { generation = s->get_generation(t); } return t; @@ -3399,7 +3399,7 @@ namespace smt { for (unsigned i = 0; i < num_decls; i++) { expr * sk = sks.get(num_decls - i - 1); instantiation_set const * s = get_uvar_inst_set(q, i); - if (s == 0) + if (s == nullptr) continue; // nothing to do obj_map const & inv = s->get_inv_map(); if (inv.empty()) diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index df6865f1e..98b55c3dd 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -29,10 +29,10 @@ namespace smt { model_generator::model_generator(ast_manager & m): m_manager(m), - m_context(0), + m_context(nullptr), m_fresh_idx(1), m_asts(m_manager), - m_model(0) { + m_model(nullptr) { } model_generator::~model_generator() { @@ -44,7 +44,7 @@ namespace smt { m_fresh_idx = 1; m_root2value.reset(); m_asts.reset(); - m_model = 0; + m_model = nullptr; } void model_generator::init_model() { @@ -89,7 +89,7 @@ namespace smt { if (r == r->get_root() && m_context->is_relevant(r)) { roots.push_back(r); sort * s = m_manager.get_sort(r->get_owner()); - model_value_proc * proc = 0; + model_value_proc * proc = nullptr; if (m_manager.is_bool(s)) { CTRACE("model", m_context->get_assignment(r) == l_undef, tout << mk_pp(r->get_owner(), m_manager) << "\n";); @@ -177,7 +177,7 @@ namespace smt { if (m_manager.get_sort(r->get_owner()) != s) continue; SASSERT(r == r->get_root()); - model_value_proc * proc = 0; + model_value_proc * proc = nullptr; root2proc.find(r, proc); SASSERT(proc); if (proc->is_fresh()) @@ -196,7 +196,7 @@ namespace smt { enode * n = src.get_enode(); SASSERT(n == n->get_root()); bool visited = true; - model_value_proc * proc = 0; + model_value_proc * proc = nullptr; root2proc.find(n, proc); SASSERT(proc); buffer dependencies; @@ -283,7 +283,7 @@ namespace smt { sz = roots.size(); for (unsigned i = 0; i < sz; i++) { enode * r = roots[i]; - model_value_proc * proc = 0; + model_value_proc * proc = nullptr; root2proc.find(r, proc); SASSERT(proc); if (!proc->is_fresh()) @@ -345,7 +345,7 @@ namespace smt { TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << "\n";); dependencies.reset(); dependency_values.reset(); - model_value_proc * proc = 0; + model_value_proc * proc = nullptr; VERIFY(root2proc.find(n, proc)); SASSERT(proc); proc->get_dependencies(dependencies); @@ -364,7 +364,7 @@ namespace smt { enode * child = d.get_enode(); TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " (" << mk_pp(n->get_owner(), m_manager) << "): " << mk_pp(child->get_owner(), m_manager) << " " << mk_pp(child->get_root()->get_owner(), m_manager) << "\n";); child = child->get_root(); - app * val = 0; + app * val = nullptr; m_root2value.find(child, val); SASSERT(val); dependency_values.push_back(val); @@ -395,7 +395,7 @@ namespace smt { } app * model_generator::get_value(enode * n) const { - app * val = 0; + app * val = nullptr; m_root2value.find(n->get_root(), val); SASSERT(val); return val; @@ -438,7 +438,7 @@ namespace smt { args.push_back(arg); } func_interp * fi = m_model->get_func_interp(f); - if (fi == 0) { + if (fi == nullptr) { fi = alloc(func_interp, m_manager, f->get_arity()); m_model->register_decl(f, fi); } @@ -454,7 +454,7 @@ namespace smt { tout << "value: #" << n->get_owner_id() << "\n" << mk_ismt2_pp(result, m_manager) << "\n";); if (m_context->get_last_search_failure() == smt::THEORY) { // if the theory solvers are incomplete, then we cannot assume the e-graph is close under congruence - if (fi->get_entry(args.c_ptr()) == 0) + if (fi->get_entry(args.c_ptr()) == nullptr) fi->insert_new_entry(args.c_ptr(), result); } else { diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index 2c86ff9ce..7466b8877 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -80,7 +80,7 @@ namespace smt { unsigned m_idx; expr * m_value; public: - extra_fresh_value(sort * s, unsigned idx):m_sort(s), m_idx(idx), m_value(0) {} + extra_fresh_value(sort * s, unsigned idx):m_sort(s), m_idx(idx), m_value(nullptr) {} sort * get_sort() const { return m_sort; } unsigned get_idx() const { return m_idx; } void set_value(expr * n) { SASSERT(m_value == 0); m_value = n; } @@ -100,7 +100,7 @@ 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(0) {} + 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) {} bool is_fresh_value() const { return m_fresh; } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 108ebfaf2..0ca244185 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -143,7 +143,7 @@ namespace smt { tout << "inserted: " << (f != 0) << "\n"; ); - return f != 0; + return f != nullptr; } void init_search_eh() { @@ -300,7 +300,7 @@ namespace smt { bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation) { ptr_vector tmp; - return add_instance(q, 0, num_bindings, bindings, generation, generation, generation, tmp); + return add_instance(q, nullptr, num_bindings, bindings, generation, generation, generation, tmp); } void quantifier_manager::init_search_eh() { @@ -408,8 +408,8 @@ namespace smt { bool m_active; public: default_qm_plugin(): - m_qm(0), - m_context(0), + m_qm(nullptr), + m_context(nullptr), m_new_enode_qhead(0), m_lazy_matching_idx(0), m_active(false) { diff --git a/src/smt/smt_quantifier_stat.h b/src/smt/smt_quantifier_stat.h index 308534833..5c31032f9 100644 --- a/src/smt/smt_quantifier_stat.h +++ b/src/smt/smt_quantifier_stat.h @@ -119,7 +119,7 @@ namespace smt { expr * m_expr; unsigned m_depth:31; bool m_depth_only:1; //!< track only the depth of this entry. - entry():m_expr(0), m_depth(0), m_depth_only(false) {} + entry():m_expr(nullptr), m_depth(0), m_depth_only(false) {} entry(expr * n, unsigned depth = 0, bool depth_only = false):m_expr(n), m_depth(depth), m_depth_only(depth_only) {} }; ast_manager & m_manager; diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index 72c28fd7d..64c791a0e 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -108,7 +108,7 @@ namespace smt { if (n->get_family_id() != m_manager.get_basic_family_id()) collect(arg, n->get_decl(), j); else - collect(arg, 0, 0); + collect(arg, nullptr, 0); } } } @@ -157,7 +157,7 @@ namespace smt { flet l(m_conservative, conservative); init(q); TRACE("collector", tout << "model checking: #" << q->get_id() << "\n" << mk_pp(q, m_manager) << "\n";); - collect(q->get_expr(), 0, 0); + collect(q->get_expr(), nullptr, 0); save_result(candidates); } @@ -251,7 +251,7 @@ namespace smt { TRACE("quick_checker_sizes", tout << "found new candidate\n"; for (unsigned i = 0; i < m_num_bindings; i++) tout << "#" << m_bindings[i]->get_owner_id() << " "; tout << "\n";); unsigned max_generation = get_max_generation(m_num_bindings, m_bindings.c_ptr()); - if (m_context.add_instance(q, 0 /* no pattern was used */, m_num_bindings, m_bindings.c_ptr(), max_generation, + if (m_context.add_instance(q, nullptr /* no pattern was used */, m_num_bindings, m_bindings.c_ptr(), max_generation, 0, // min_top_generation is only available for instances created by the MAM 0, // max_top_generation is only available for instances created by the MAM empty_used_enodes)) diff --git a/src/smt/smt_quick_checker.h b/src/smt/smt_quick_checker.h index 21a570c3c..d3af8e2e0 100644 --- a/src/smt/smt_quick_checker.h +++ b/src/smt/smt_quick_checker.h @@ -50,7 +50,7 @@ namespace smt { expr * m_expr; func_decl * m_parent; unsigned m_parent_pos; - entry(expr * n = 0, func_decl * d = 0, unsigned p = 0):m_expr(n), m_parent(d), m_parent_pos(p) {} + entry(expr * n = nullptr, func_decl * d = nullptr, unsigned p = 0):m_expr(n), m_parent(d), m_parent_pos(p) {} unsigned hash() const { return m_parent ? mk_mix(m_expr->get_id(), m_parent->get_id(), m_parent_pos) : m_expr->get_id(); } bool operator==(entry const & e) const { return m_expr == e.m_expr && m_parent == e.m_parent && m_parent_pos == e.m_parent_pos; } }; diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 7a2d4167f..9eabb8319 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -159,28 +159,28 @@ namespace smt { } relevancy_ehs * get_handlers(expr * n) { - relevancy_ehs * r = 0; + relevancy_ehs * r = nullptr; m_relevant_ehs.find(n, r); SASSERT(m_relevant_ehs.contains(n) || r == 0); return r; } void set_handlers(expr * n, relevancy_ehs * ehs) { - if (ehs == 0) + if (ehs == nullptr) m_relevant_ehs.erase(n); else m_relevant_ehs.insert(n, ehs); } relevancy_ehs * get_watches(expr * n, bool val) { - relevancy_ehs * r = 0; + relevancy_ehs * r = nullptr; m_watches[val ? 1 : 0].find(n, r); SASSERT(m_watches[val ? 1 : 0].contains(n) || r == 0); return r; } void set_watches(expr * n, bool val, relevancy_ehs * ehs) { - if (ehs == 0) + if (ehs == nullptr) m_watches[val ? 1 : 0].erase(n); else m_watches[val ? 1 : 0].insert(n, ehs); @@ -330,7 +330,7 @@ namespace smt { return; if (!is_relevant_core(n)) { enode * e = m_context.find_enode(n); - if (e != 0) { + if (e != nullptr) { enode * curr = e; do { set_relevant(curr->get_owner()); @@ -376,7 +376,7 @@ namespace smt { case l_undef: break; case l_true: { - expr * true_arg = 0; + expr * true_arg = nullptr; unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { expr * arg = n->get_arg(i); @@ -400,7 +400,7 @@ namespace smt { lbool val = m_context.find_assignment(n); switch (val) { case l_false: { - expr * false_arg = 0; + expr * false_arg = nullptr; unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { expr * arg = n->get_arg(i); @@ -487,7 +487,7 @@ namespace smt { } relevancy_ehs * ehs = get_handlers(n); - while (ehs != 0) { + while (ehs != nullptr) { ehs->head()->operator()(*this, n); ehs = ehs->tail(); } @@ -510,7 +510,7 @@ namespace smt { propagate_relevant_and(to_app(n)); } relevancy_ehs * ehs = get_watches(n, val); - while (ehs != 0) { + while (ehs != nullptr) { ehs->head()->operator()(*this, n, val); ehs = ehs->tail(); } diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index b805253d8..d813f249a 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -195,7 +195,7 @@ namespace smt { void get_labels(svector & r) override { buffer tmp; - m_context.get_relevant_labels(0, tmp); + m_context.get_relevant_labels(nullptr, tmp); r.append(tmp.size(), tmp.c_ptr()); } diff --git a/src/smt/smt_theory.cpp b/src/smt/smt_theory.cpp index 515503d41..b5ad68adc 100644 --- a/src/smt/smt_theory.cpp +++ b/src/smt/smt_theory.cpp @@ -130,8 +130,8 @@ namespace smt { theory::theory(family_id fid): m_id(fid), - m_context(0), - m_manager(0) { + m_context(nullptr), + m_manager(nullptr) { } theory::~theory() { diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index 2ee0db322..9d5a4f49f 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -235,7 +235,7 @@ namespace smt { disequality propagation. */ virtual justification * why_is_diseq(theory_var v1, theory_var v2) { - return 0; + return nullptr; } /** @@ -369,7 +369,7 @@ namespace smt { theory_var other = null_theory_var; TRACE("assume_eqs", tout << "#" << n->get_owner_id() << " is_relevant_and_shared: " << is_relevant_and_shared(n) << "\n";); - if (n != 0 && is_relevant_and_shared(n)) { + if (n != nullptr && is_relevant_and_shared(n)) { other = table.insert_if_not_there(v); if (other != v) { enode * n2 = get_enode(other); @@ -423,7 +423,7 @@ namespace smt { \brief Return a functor that can build the value (interpretation) for n. */ virtual model_value_proc * mk_value(enode * n, model_generator & mg) { - return 0; + return nullptr; } virtual bool include_func_interp(func_decl* f) { diff --git a/src/smt/smt_theory_var_list.h b/src/smt/smt_theory_var_list.h index aa2816786..69180ad66 100644 --- a/src/smt/smt_theory_var_list.h +++ b/src/smt/smt_theory_var_list.h @@ -32,10 +32,10 @@ namespace smt { theory_var_list(): m_th_id(null_theory_id), m_th_var(null_theory_var), - m_next(0) { + m_next(nullptr) { } - theory_var_list(theory_id t, theory_var v, theory_var_list * n = 0): + theory_var_list(theory_id t, theory_var v, theory_var_list * n = nullptr): m_th_id(t), m_th_var(v), m_next(n) { diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 98de6a79b..417922858 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -74,7 +74,7 @@ public: model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; reduce(*(in.get())); in->inc_depth(); result.push_back(in.get()); @@ -126,7 +126,7 @@ protected: m_solver.pop(1); }); g.reset(); - g.assert_expr(fml, 0, 0); + g.assert_expr(fml, nullptr, nullptr); IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(ctx-solver-simplify :num-steps " << m_num_steps << ")\n";); SASSERT(g.is_well_sorted()); } @@ -140,7 +140,7 @@ protected: m_parent(p), m_self(s), m_idx(i), m_expr(e) {} expr_pos(): - m_parent(0), m_self(0), m_idx(0), m_expr(0) + m_parent(0), m_self(0), m_idx(0), m_expr(nullptr) {} }; @@ -193,7 +193,7 @@ protected: a = to_app(e); sz = a->get_num_args(); - n2 = 0; + n2 = nullptr; for (unsigned i = 0; i < sz; ++i) { expr* arg = a->get_arg(i); diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index af717c807..14a9c3e11 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -47,8 +47,8 @@ class smt_tactic : public tactic { public: smt_tactic(params_ref const & p): m_params_ref(p), - m_ctx(0), - m_callback(0) { + m_ctx(nullptr), + m_callback(nullptr) { updt_params_core(p); TRACE("smt_tactic", tout << "p: " << p << "\n";); } @@ -136,7 +136,7 @@ public: ~scoped_init_ctx() { smt::kernel * d = m_owner.m_ctx; - m_owner.m_ctx = 0; + m_owner.m_ctx = nullptr; if (d) dealloc(d); @@ -151,7 +151,7 @@ public: expr_dependency_ref & core) override { try { IF_VERBOSE(10, verbose_stream() << "(smt.tactic start)\n";); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); TRACE("smt_tactic", tout << this << "\nAUTO_CONFIG: " << fparams().m_auto_config << " HIDIV0: " << fparams().m_hi_div0 << " " @@ -220,7 +220,7 @@ public: model_ref md; m_ctx->get_model(md); buffer r; - m_ctx->get_relevant_labels(0, r); + m_ctx->get_relevant_labels(nullptr, r); mc = model_and_labels2model_converter(md.get(), r); mc = concat(fmc.get(), mc.get()); } @@ -233,8 +233,8 @@ public: } // formula is unsat, reset the goal, and store false there. in->reset(); - proof * pr = 0; - expr_dependency * lcore = 0; + proof * pr = nullptr; + expr_dependency * lcore = nullptr; if (in->proofs_enabled()) pr = m_ctx->get_proof(); if (in->unsat_core_enabled()) { @@ -269,7 +269,7 @@ public: model_ref md; m_ctx->get_model(md); buffer r; - m_ctx->get_relevant_labels(0, r); + m_ctx->get_relevant_labels(nullptr, r); mc = model_and_labels2model_converter(md.get(), r); } return; diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 98bbefd42..5040f1034 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -561,16 +561,16 @@ namespace smt { bound * upper(theory_var v) const { return m_bounds[1][v]; } inf_numeral const & lower_bound(theory_var v) const { SASSERT(lower(v) != 0); return lower(v)->get_value(); } inf_numeral const & upper_bound(theory_var v) const { SASSERT(upper(v) != 0); return upper(v)->get_value(); } - bool below_lower(theory_var v) const { bound * l = lower(v); return l != 0 && get_value(v) < l->get_value(); } - bool above_upper(theory_var v) const { bound * u = upper(v); return u != 0 && get_value(v) > u->get_value(); } - bool below_upper(theory_var v) const { bound * u = upper(v); return u == 0 || get_value(v) < u->get_value(); } - bool above_lower(theory_var v) const { bound * l = lower(v); return l == 0 || get_value(v) > l->get_value(); } + bool below_lower(theory_var v) const { bound * l = lower(v); return l != nullptr && get_value(v) < l->get_value(); } + bool above_upper(theory_var v) const { bound * u = upper(v); return u != nullptr && get_value(v) > u->get_value(); } + bool below_upper(theory_var v) const { bound * u = upper(v); return u == nullptr || get_value(v) < u->get_value(); } + bool above_lower(theory_var v) const { bound * l = lower(v); return l == nullptr || get_value(v) > l->get_value(); } bool at_bound(theory_var v) const; - bool at_lower(theory_var v) const { bound * l = lower(v); return l != 0 && get_value(v) == l->get_value(); } - bool at_upper(theory_var v) const { bound * u = upper(v); return u != 0 && get_value(v) == u->get_value(); } - bool is_free(theory_var v) const { return lower(v) == 0 && upper(v) == 0; } - bool is_non_free(theory_var v) const { return lower(v) != 0 || upper(v) != 0; } - bool is_bounded(theory_var v) const { return lower(v) != 0 && upper(v) != 0; } + bool at_lower(theory_var v) const { bound * l = lower(v); return l != nullptr && get_value(v) == l->get_value(); } + bool at_upper(theory_var v) const { bound * u = upper(v); return u != nullptr && get_value(v) == u->get_value(); } + bool is_free(theory_var v) const { return lower(v) == nullptr && upper(v) == nullptr; } + bool is_non_free(theory_var v) const { return lower(v) != nullptr || upper(v) != nullptr; } + bool is_bounded(theory_var v) const { return lower(v) != nullptr && upper(v) != nullptr; } bool is_free(expr * n) const { SASSERT(get_context().e_internalized(n) && get_context().get_enode(n)->get_th_var(get_id()) != null_theory_var); return is_free(get_context().get_enode(n)->get_th_var(get_id())); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index a1558e5e5..6a19f2f6e 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -279,7 +279,7 @@ namespace smt { return it; } } - return 0; + return nullptr; } template @@ -357,7 +357,7 @@ namespace smt { template parameter * theory_arith::antecedents_t::params(char const* name) { - if (empty()) return 0; + if (empty()) return nullptr; init(); m_params[0] = parameter(symbol(name)); return m_params.c_ptr(); @@ -444,19 +444,19 @@ namespace smt { template bool theory_arith::at_bound(theory_var v) const { bound * l = lower(v); - if (l != 0 && get_value(v) == l->get_value()) + if (l != nullptr && get_value(v) == l->get_value()) return true; bound * u = upper(v); - return u != 0 && get_value(v) == u->get_value(); + return u != nullptr && get_value(v) == u->get_value(); } template bool theory_arith::is_fixed(theory_var v) const { bound * l = lower(v); - if (l == 0) + if (l == nullptr) return false; bound * u = upper(v); - if (u == 0) + if (u == nullptr) return false; return l->get_value() == u->get_value(); } @@ -483,7 +483,7 @@ namespace smt { while (true) { column const & c = m_columns[v]; if (c.size() == 0) - return 0; + return nullptr; int quasi_base_rid = -1; typename svector::const_iterator it = c.begin_entries(); typename svector::const_iterator end = c.end_entries(); @@ -533,7 +533,7 @@ namespace smt { typename theory_arith::col_entry const * theory_arith::get_row_for_eliminating(theory_var v) const { column const & c = m_columns[v]; if (c.size() == 0) - return 0; + return nullptr; typename svector::const_iterator it = c.begin_entries(); typename svector::const_iterator end = c.end_entries(); for (; it != end; ++it) { @@ -556,7 +556,7 @@ namespace smt { return it; } } - return 0; + return nullptr; } template diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 03830f7d0..fe62efbf4 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -472,7 +472,7 @@ namespace smt { tout << s_ante << "\n" << s_conseq << "\n";); // literal lits[2] = {l_ante, l_conseq}; - mk_clause(l_ante, l_conseq, 0, 0); + mk_clause(l_ante, l_conseq, 0, nullptr); if (ctx.relevancy()) { if (l_ante == false_literal) { ctx.mark_as_relevant(l_conseq); @@ -1347,8 +1347,8 @@ namespace smt { std::swap(n1, n2); } rational k; - bound * b1 = 0; - bound * b2 = 0; + bound * b1 = nullptr; + bound * b2 = nullptr; if (m_util.is_numeral(n2->get_owner(), k)) { inf_numeral val(k); b1 = alloc(eq_bound, v1, val, B_LOWER, n1, n2); @@ -2342,7 +2342,7 @@ namespace smt { row const & r = m_rows[get_var_row(x_i)]; int idx = r.get_idx_of(x_i); SASSERT(idx >= 0); - bound * b = 0; + bound * b = nullptr; // Remark: // if x_i is an integer variable, then delta can be negative: @@ -2616,7 +2616,7 @@ namespace smt { return; } bool is_pos = it->m_coeff.is_pos(); - if (lower(it->m_var) == 0) { + if (lower(it->m_var) == nullptr) { if (is_pos) { UPDATE_IDX(upper_idx); } @@ -2624,7 +2624,7 @@ namespace smt { UPDATE_IDX(lower_idx); } } - if (upper(it->m_var) == 0) { + if (upper(it->m_var) == nullptr) { if (is_pos) { UPDATE_IDX(lower_idx); } @@ -2661,7 +2661,7 @@ namespace smt { if (entry.m_coeff.is_pos() == is_lower) { // implied_k is a lower bound for entry.m_var bound * curr = lower(entry.m_var); - if (curr == 0 || implied_k > curr->get_value()) { + if (curr == nullptr || implied_k > curr->get_value()) { TRACE("arith_imply_bound", tout << "implying lower bound for v" << entry.m_var << " " << implied_k << " using row:\n"; display_row_info(tout, r); @@ -2672,7 +2672,7 @@ namespace smt { else { // implied_k is an upper bound for it->m_var bound * curr = upper(entry.m_var); - if (curr == 0 || implied_k < curr->get_value()) { + if (curr == nullptr || implied_k < curr->get_value()) { TRACE("arith_imply_bound", tout << "implying upper bound for v" << entry.m_var << " " << implied_k << " using row:\n"; display_row_info(tout, r); @@ -2722,7 +2722,7 @@ namespace smt { if (it->m_coeff.is_pos() == is_lower) { // implied_k is a lower bound for it->m_var bound * curr = lower(it->m_var); - if (curr == 0 || implied_k > curr->get_value()) { + if (curr == nullptr || implied_k > curr->get_value()) { // improved lower bound TRACE("arith_imply_bound", tout << "implying lower bound for v" << it->m_var << " " << implied_k << " using row:\n"; @@ -2734,7 +2734,7 @@ namespace smt { else { // implied_k is an upper bound for it->m_var bound * curr = upper(it->m_var); - if (curr == 0 || implied_k < curr->get_value()) { + if (curr == nullptr || implied_k < curr->get_value()) { // improved upper bound TRACE("arith_imply_bound", tout << "implying upper bound for v" << it->m_var << " " << implied_k << " using row:\n"; @@ -2809,7 +2809,7 @@ namespace smt { TRACE("propagate_bounds_bug", tout << "is_b_lower: " << is_b_lower << " k1: " << k_1 << " limit_k1: " << limit_k1 << " delta: " << delta << " coeff: " << coeff << "\n";); inf_numeral k_2 = k_1; - atom * new_atom = 0; + atom * new_atom = nullptr; atoms const & as = m_var_occs[it->m_var]; typename atoms::const_iterator it = as.begin(); typename atoms::const_iterator end = as.end(); @@ -2844,7 +2844,7 @@ namespace smt { } SASSERT(!is_b_lower || k_2 <= k_1); SASSERT(is_b_lower || k_2 >= k_1); - if (new_atom == 0) { + if (new_atom == nullptr) { b->push_justification(ante, coeff, coeffs_enabled()); continue; } @@ -2976,12 +2976,12 @@ namespace smt { literal_vector::const_iterator end = ante.lits().end(); for (; it != end; ++it) lits.push_back(~(*it)); - justification * js = 0; + justification * js = nullptr; if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr(), ante.num_params(), ante.params("assign-bounds")); } - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, nullptr); } else { region & r = ctx.get_region(); @@ -3169,9 +3169,9 @@ namespace smt { for (theory_var v = 0; v < num; v++) { bound * l = lower(v); bound * u = upper(v); - if (l != 0) + if (l != nullptr) update_epsilon(l->get_value(), get_value(v)); - if (u != 0) + if (u != nullptr) update_epsilon(get_value(v), u->get_value()); } TRACE("epsilon_bug", tout << "epsilon: " << m_epsilon << "\n";); @@ -3289,14 +3289,14 @@ namespace smt { template bool theory_arith::get_lower(enode * n, expr_ref & r) { theory_var v = n->get_th_var(get_id()); - bound* b = (v == null_theory_var) ? 0 : lower(v); + bound* b = (v == null_theory_var) ? nullptr : lower(v); return b && to_expr(b->get_value(), is_int(v), r); } template bool theory_arith::get_upper(enode * n, expr_ref & r) { theory_var v = n->get_th_var(get_id()); - bound* b = (v == null_theory_var) ? 0 : upper(v); + bound* b = (v == null_theory_var) ? nullptr : upper(v); return b && to_expr(b->get_value(), is_int(v), r); } @@ -3388,7 +3388,7 @@ namespace smt { bound * b = it->get_old_bound(); SASSERT(is_base(v) || is_non_base(v)); restore_bound(v, b, it->is_upper()); - if (lazy_pivoting_lvl() > 2 && b == 0 && is_base(v) && is_free(v)) { + if (lazy_pivoting_lvl() > 2 && b == nullptr && is_base(v) && is_free(v)) { SASSERT(!has_var_kind(get_var_row(v), BASE)); SASSERT(!has_var_kind(get_var_row(v), QUASI_BASE)); eliminate(v, false); diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index a7f7fae59..40879edd9 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -117,7 +117,7 @@ namespace smt { for (; it != end; ++it) { if (!it->is_dead()) { theory_var v = it->m_var; - if (lower(v) != 0 && upper(v) != 0) + if (lower(v) != nullptr && upper(v) != nullptr) continue; bad++; if (bad > 2) { diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 593b9c56b..528324040 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -50,15 +50,15 @@ namespace smt { bound * l = lower(v); bound * u = upper(v); const inf_numeral & val = get_value(v); - if (l != 0 && u != 0) { + if (l != nullptr && u != nullptr) { if (val != l->get_value() && val != u->get_value()) set_value(v, l->get_value()); } - else if (l != 0) { + else if (l != nullptr) { if (val != l->get_value()) set_value(v, l->get_value()); } - else if (u != 0) { + else if (u != nullptr) { if (val != u->get_value()) set_value(v, u->get_value()); } @@ -245,12 +245,12 @@ namespace smt { numeral const_coeff(0); bound* l = lower(b), *u = upper(b); - if (l != 0 && get_value(b) - inf_numeral(1) < l->get_value()) { + if (l != nullptr && get_value(b) - inf_numeral(1) < l->get_value()) { SASSERT(l->get_value() <= get_value(b)); is_tight = true; const_coeff = l->get_value().get_rational(); } - else if (u != 0 && get_value(b) + inf_numeral(1) > u->get_value()) { + else if (u != nullptr && get_value(b) + inf_numeral(1) > u->get_value()) { SASSERT(get_value(b) <= u->get_value()); is_tight = true; const_coeff = u->get_value().get_rational(); @@ -1074,7 +1074,7 @@ namespace smt { derived_bound * new_bound = alloc(derived_bound, v, inf_numeral(k), lower ? B_LOWER : B_UPPER); t.m_tmp_lit_set.reset(); t.m_tmp_eq_set.reset(); - if (old_bound != 0) { + if (old_bound != nullptr) { t.accumulate_justification(*old_bound, *new_bound, numeral(0) /* refine for proof gen */, t.m_tmp_lit_set, t.m_tmp_eq_set); } unsigned_vector::const_iterator it = js.begin(); @@ -1174,8 +1174,8 @@ namespace smt { c2 = rational(c); TRACE("euclidean_solver_new", tout << "new fixed: " << c2 << "\n";); propagated = true; - mk_lower(v, c2, 0, m_js); - mk_upper(v, c2, 0, m_js); + mk_lower(v, c2, nullptr, m_js); + mk_upper(v, c2, nullptr, m_js); } else { TRACE("euclidean_solver", tout << "inequality can be tightned, since all coefficients are multiple of: " << g << "\n";); @@ -1187,7 +1187,7 @@ namespace smt { bound * l = t.lower(v); bound * u = t.upper(v); c2 = rational(c); - if (l != 0) { + if (l != nullptr) { rational l_old = l->get_value().get_rational().to_rational(); rational l_new = g*ceil((l_old - c2)/g) + c2; TRACE("euclidean_solver_new", tout << "new lower: " << l_new << " old: " << l_old << "\n"; @@ -1197,7 +1197,7 @@ namespace smt { mk_lower(v, l_new, l, m_js); } } - if (u != 0) { + if (u != nullptr) { rational u_old = u->get_value().get_rational().to_rational(); rational u_new = g*floor((u_old - c2)/g) + c2; TRACE("euclidean_solver_new", tout << "new upper: " << u_new << " old: " << u_old << "\n";); @@ -1223,7 +1223,7 @@ namespace smt { continue; // skip equations... if (!t.is_int(v)) continue; // skip non integer definitions... - if (t.lower(v) == 0 && t.upper(v) == 0) + if (t.lower(v) == nullptr && t.upper(v) == nullptr) continue; // there is nothing to be tightned if (tight_bounds(v)) propagated = true; diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 7eee008e9..ba6648dac 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -161,14 +161,14 @@ namespace smt { template std::pair theory_arith::analyze_monomial(expr * m) const { SASSERT(is_pure_monomial(m)); - expr * var = 0; + expr * var = nullptr; unsigned power = 0; unsigned c = 0; int free_var_idx = -1; int idx = 0; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * arg = to_app(m)->get_arg(i); - if (var == 0) { + if (var == nullptr) { var = arg; power = 1; } @@ -227,7 +227,7 @@ namespace smt { SASSERT(!m_util.is_numeral(m)); if (m_util.is_mul(m)) { unsigned num_vars = 0; - expr * var = 0; + expr * var = nullptr; for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { expr * curr = to_app(m)->get_arg(i); if (var != curr) { @@ -252,12 +252,12 @@ namespace smt { m = get_monomial_body(m); if (m_util.is_mul(m)) { unsigned curr_idx = 0; - expr * var = 0; + expr * var = nullptr; unsigned power = 0; unsigned j; for (j = 0; j < to_app(m)->get_num_args(); j++) { expr * arg = to_app(m)->get_arg(j); - if (var == 0) { + if (var == nullptr) { var = arg; power = 1; } @@ -471,7 +471,7 @@ namespace smt { } } bound * old_lower = lower(v); - if (old_lower == 0 || new_lower > old_lower->get_value()) { + if (old_lower == nullptr || new_lower > old_lower->get_value()) { TRACE("non_linear", tout << "NEW lower bound for v" << v << " " << new_lower << "\n"; display_interval(tout, i); tout << "\n";); mk_derived_nl_bound(v, new_lower, B_LOWER, i.get_lower_dependencies()); @@ -494,7 +494,7 @@ namespace smt { } } bound * old_upper = upper(v); - if (old_upper == 0 || new_upper < old_upper->get_value()) { + if (old_upper == nullptr || new_upper < old_upper->get_value()) { TRACE("non_linear", tout << "NEW upper bound for v" << v << " " << new_upper << "\n"; display_interval(tout, i); tout << "\n";); mk_derived_nl_bound(v, new_upper, B_UPPER, i.get_upper_dependencies()); @@ -788,7 +788,7 @@ namespace smt { TRACE("non_linear", tout << "BRANCHING on v" << v << "\n";); m_stats.m_nl_branching++; SASSERT(is_int(v)); - expr * bound = 0; + expr * bound = nullptr; if (lower(v)) bound = m_util.mk_le(var2expr(v), m_util.mk_numeral(lower_bound(v).get_rational().to_rational(), true)); else if (upper(v)) @@ -857,7 +857,7 @@ namespace smt { if (!is_fixed(_var)) return arg; } - return 0; + return nullptr; } /** @@ -882,12 +882,12 @@ namespace smt { numeral k = get_monomial_fixed_var_product(m); TRACE("non_linear", tout << "new linear monomial... k: " << k << "\n";); - expr * x_n = k.is_zero() ? 0 : get_monomial_non_fixed_var(m); + expr * x_n = k.is_zero() ? nullptr : get_monomial_non_fixed_var(m); TRACE("non_linear_bug", if (x_n != 0) { tout << "x_n: " << mk_bounded_pp(x_n, get_manager()) << "\nx_n: #" << x_n->get_id() << "\n"; }); context & ctx = get_context(); - derived_bound * new_lower = 0; - derived_bound * new_upper = 0; - if (x_n != 0) { + derived_bound * new_lower = nullptr; + derived_bound * new_upper = nullptr; + if (x_n != nullptr) { // All but one of the x_i variables are assigned. // Let x_n be the unassigned variable. // Then, we know that x_1*...*x_n = k*x_n, where k is the product of beta(x_1)*...*beta(x_{n-1}) @@ -1267,7 +1267,7 @@ namespace smt { expr * var = ce.second; if (!c.is_one()) { rational c2; - expr * m = 0; + expr * m = nullptr; if (m_util.is_numeral(var, c2)) m = m_util.mk_numeral(c*c2, m_util.is_int(var) && c.is_int() && c2.is_int()); else @@ -1492,7 +1492,7 @@ namespace smt { r.push_back(coeff_expr(kv.first, f)); } } - expr * s = cross_nested(e, 0); + expr * s = cross_nested(e, nullptr); if (!r.empty()) { expr * q = horner(r, var); // TODO: improve here @@ -1519,7 +1519,7 @@ namespace smt { template expr * theory_arith::cross_nested(sbuffer & p, expr * var) { TRACE("non_linear", tout << "p.size: " << p.size() << "\n";); - if (var == 0) { + if (var == nullptr) { sbuffer varinfo; get_polynomial_info(p, varinfo); if (varinfo.empty()) @@ -1556,7 +1556,7 @@ namespace smt { tout << "b: " << b << "\n"; tout << "nm: " << nm << "\n";); SASSERT(n != nm); - expr * new_expr = 0; + expr * new_expr = nullptr; if (nm < n) { std::swap(n, nm); std::swap(a, b); @@ -1576,7 +1576,7 @@ namespace smt { expr * xm_a2b = m_util.mk_add(m_util.mk_numeral(a2b, m_util.is_int(var)), xm); expr * xm_a2b2 = m_util.mk_mul(xm_a2b, xm_a2b); expr * rhs = m_util.mk_add(xm_a2b2, m_util.mk_numeral(ma2b2, m_util.is_int(var))); - expr * rhs2 = 0; + expr * rhs2 = nullptr; if (n > m) rhs2 = m_util.mk_mul(power(var, n - m), rhs); else @@ -1593,7 +1593,7 @@ namespace smt { if (rest.empty()) return new_expr; TRACE("non_linear", tout << "rest size: " << rest.size() << ", i1: " << i1 << ", i2: " << i2 << "\n";); - expr * h = cross_nested(rest, 0); + expr * h = cross_nested(rest, nullptr); expr * r = m_util.mk_add(new_expr, h); m_nl_new_exprs.push_back(r); return r; @@ -1631,7 +1631,7 @@ namespace smt { tout << "c:\n" << mk_ismt2_pp(cn, get_manager()) << "\n";); interval i = evaluate_as_interval(cn); TRACE("cross_nested", tout << "interval: " << i << "\n";); - v_dependency * d = 0; + v_dependency * d = nullptr; if (!i.minus_infinity() && (i.get_lower_value().is_pos() || (i.get_lower_value().is_zero() && i.is_lower_open()))) d = i.get_lower_dependencies(); else if (!i.plus_infinity() && (i.get_upper_value().is_neg() || (i.get_upper_value().is_zero() && i.is_upper_open()))) @@ -1823,7 +1823,7 @@ namespace smt { if (!coeff.is_zero()) return gb.mk_monomial(coeff, vars.size(), vars.c_ptr()); else - return 0; + return nullptr; } /** @@ -1834,7 +1834,7 @@ namespace smt { void theory_arith::add_row_to_gb(row const & r, grobner & gb) { TRACE("non_linear", tout << "adding row to gb\n"; display_row(tout, r);); ptr_buffer monomials; - v_dependency * dep = 0; + v_dependency * dep = nullptr; m_tmp_var_set.reset(); typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); @@ -1860,7 +1860,7 @@ namespace smt { template void theory_arith::add_monomial_def_to_gb(theory_var v, grobner & gb) { ptr_buffer monomials; - v_dependency * dep = 0; + v_dependency * dep = nullptr; m_tmp_var_set.reset(); expr * m = var2expr(v); SASSERT(is_pure_monomial(m)); @@ -1872,7 +1872,7 @@ namespace smt { dep = m_dep_manager.mk_join(dep, m_dep_manager.mk_join(m_dep_manager.mk_leaf(lower(v)), m_dep_manager.mk_leaf(upper(v)))); coeff *= lower_bound(v).get_rational().to_rational(); if (!coeff.is_zero()) - monomials.push_back(gb.mk_monomial(coeff, 0, 0)); + monomials.push_back(gb.mk_monomial(coeff, 0, nullptr)); } else { monomials.push_back(gb.mk_monomial(coeff, 1, &m)); @@ -1904,12 +1904,12 @@ namespace smt { template interval theory_arith::mk_interval_for(grobner::monomial const * m) { interval r(m_dep_manager, rational(m->get_coeff())); - expr * var = 0; + expr * var = nullptr; unsigned power = 0; unsigned num_vars = m->get_degree(); for (unsigned i = 0; i < num_vars; i++) { expr * curr = m->get_var(i); - if (var == 0) { + if (var == nullptr) { var = curr; power = 1; } @@ -1922,7 +1922,7 @@ namespace smt { power = 1; } } - if (var != 0) + if (var != nullptr) mul_bound_of(var, power, r); return r; } @@ -1957,7 +1957,7 @@ namespace smt { return false; } TRACE("non_linear_bug", tout << "is_inconsistent, r: " << r << "\n";); - v_dependency * interval_deps = 0; + v_dependency * interval_deps = nullptr; bool conflict = false; if (!r.minus_infinity() && (r.get_lower_value().is_pos() || (r.get_lower_value().is_zero() && r.is_lower_open()))) { interval_deps = r.get_lower_dependencies(); @@ -2002,11 +2002,11 @@ namespace smt { return false; if (!m->get_coeff().is_perfect_square(r)) return false; - expr * var = 0; + expr * var = nullptr; unsigned power = 0; for (unsigned i = 0; i < num_vars; i++) { expr * curr = m->get_var(i); - if (var == 0) { + if (var == nullptr) { var = curr; power = 1; } @@ -2050,18 +2050,18 @@ namespace smt { unsigned i1, i2, i12; i1 = i2 = i12 = 0; while (true) { - expr * v1 = 0; - expr * v2 = 0; - expr * v12 = 0; + expr * v1 = nullptr; + expr * v2 = nullptr; + expr * v12 = nullptr; if (i1 < num1) v1 = m1_sq->get_var(i1); if (i2 < num2) v2 = m2_sq->get_var(i2); if (i12 < num12) v12 = m1m2->get_var(i12); - if (v1 == 0 && v2 == 0 && v12 == 0) + if (v1 == nullptr && v2 == nullptr && v12 == nullptr) return true; - if (v12 == 0) + if (v12 == nullptr) return false; if (v1 == v12) { SASSERT(m1_sq->get_var(i1+1) == v1); @@ -2162,7 +2162,7 @@ namespace smt { } if (monomials.size() == num) return false; // didn't find any perfect square. - interval ge_zero(m_dep_manager, rational(0), false, true, 0); + interval ge_zero(m_dep_manager, rational(0), false, true, nullptr); if (is_inconsistent(ge_zero, monomials.size(), monomials.c_ptr(), eq->get_dependency())) { TRACE("non_linear", tout << "found conflict\n"; gb.display_equation(tout, *eq);); return true; diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index 997698411..a218445f5 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -504,7 +504,7 @@ namespace smt { pp.add_assumption(eq); } else { - if (lower(v) != 0) { + if (lower(v) != nullptr) { inf_numeral k_inf = lower_bound(v); rational k = k_inf.get_rational().to_rational(); expr_ref ineq(m); @@ -514,7 +514,7 @@ namespace smt { ineq = m_util.mk_lt(m_util.mk_numeral(k, is_int(v)), n); pp.add_assumption(ineq); } - if (upper(v) != 0) { + if (upper(v) != nullptr) { inf_numeral k_inf = upper_bound(v); rational k = k_inf.get_rational().to_rational(); expr_ref ineq(m); diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 0aba7c2f2..a0e9fad2b 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -41,7 +41,7 @@ namespace smt { } app * theory_array_base::mk_select(unsigned num_args, expr * const * args) { - app * r = get_manager().mk_app(get_family_id(), OP_SELECT, 0, 0, num_args, args); + app * r = get_manager().mk_app(get_family_id(), OP_SELECT, 0, nullptr, num_args, args); TRACE("mk_var_bug", tout << "mk_select: " << r->get_id() << " num_args: " << num_args; for (unsigned i = 0; i < num_args; i++) tout << " " << args[i]->get_id(); tout << "\n";); @@ -49,7 +49,7 @@ namespace smt { } app * theory_array_base::mk_store(unsigned num_args, expr * const * args) { - return get_manager().mk_app(get_family_id(), OP_STORE, 0, 0, num_args, args); + return get_manager().mk_app(get_family_id(), OP_STORE, 0, nullptr, num_args, args); } app * theory_array_base::mk_default(expr * a) { @@ -152,7 +152,7 @@ namespace smt { expr_ref sel1(m), sel2(m); bool init = false; literal conseq = null_literal; - expr * conseq_expr = 0; + expr * conseq_expr = nullptr; for (unsigned i = 0; i < num_args; i++) { enode * idx1 = js[i]; @@ -212,7 +212,7 @@ namespace smt { func_decl_ref_vector * theory_array_base::register_sort(sort * s_array) { unsigned dimension = get_dimension(s_array); - func_decl_ref_vector * ext_skolems = 0; + func_decl_ref_vector * ext_skolems = nullptr; if (!m_sort2skolem.find(s_array, ext_skolems)) { array_util util(get_manager()); ast_manager & m = get_manager(); @@ -305,7 +305,7 @@ namespace smt { context & ctx = get_context(); ast_manager & m = get_manager(); - func_decl_ref_vector * funcs = 0; + func_decl_ref_vector * funcs = nullptr; sort * s = m.get_sort(e1); VERIFY(m_sort2skolem.find(s, funcs)); @@ -495,7 +495,7 @@ namespace smt { void theory_array_base::restore_sorts(unsigned old_size) { while (m_sorts_trail.size() > old_size) { sort * s = m_sorts_trail.back(); - func_decl_ref_vector * funcs = 0; + func_decl_ref_vector * funcs = nullptr; if (m_sort2skolem.find(s, funcs)) { m_sort2skolem.remove(s); dealloc(funcs); @@ -672,9 +672,9 @@ namespace smt { theory_array_base::select_set * theory_array_base::get_select_set(enode * n) { enode * r = n->get_root(); - select_set * set = 0; + select_set * set = nullptr; m_selects.find(r, set); - if (set == 0) { + if (set == nullptr) { set = alloc(select_set); m_selects.insert(r, set); m_selects_domain.push_back(r); @@ -795,7 +795,7 @@ namespace smt { m_sort(s), m_num_entries(0), m_dim(0), - m_else(0), + m_else(nullptr), m_unspecified_else(false) { m_dependencies.push_back(model_value_dependency(v)); } @@ -814,7 +814,7 @@ namespace smt { m_sort(s), m_num_entries(0), m_dim(0), - m_else(0), + m_else(nullptr), m_unspecified_else(false) { m_dependencies.push_back(model_value_dependency(else_value)); } @@ -824,7 +824,7 @@ namespace smt { m_sort(s), m_num_entries(0), m_dim(0), - m_else(0), + m_else(nullptr), m_unspecified_else(true) { } @@ -888,14 +888,14 @@ namespace smt { SASSERT(v != null_theory_var); sort * s = get_manager().get_sort(n->get_owner()); enode * else_val_n = get_default(v); - array_value_proc * result = 0; + array_value_proc * result = nullptr; if (m_use_unspecified_default) { SASSERT(else_val_n == 0); result = alloc(array_value_proc, get_id(), s); } else { - if (else_val_n != 0) { + if (else_val_n != nullptr) { SASSERT(get_context().is_relevant(else_val_n)); result = alloc(array_value_proc, get_id(), s, else_val_n); } @@ -905,7 +905,7 @@ namespace smt { // DISABLED. It seems wrong, since different nodes can share the same // else_val according to the mg class. // SASSERT(else_val == 0 || get_context().is_relevant(UNTAG(app*, else_val))); - if (else_val == 0) { + if (else_val == nullptr) { sort * range = to_sort(s->get_parameter(s->get_num_parameters() - 1).get_ast()); // IMPORTANT: // The implementation should not assume a fresh value is created for @@ -925,9 +925,9 @@ namespace smt { } } SASSERT(result != 0); - select_set * sel_set = 0; + select_set * sel_set = nullptr; m_selects.find(n->get_root(), sel_set); - if (sel_set != 0) { + if (sel_set != nullptr) { ptr_buffer args; select_set::iterator it = sel_set->begin(); select_set::iterator end = sel_set->end(); diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 274f89e8b..048e3f581 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -746,7 +746,7 @@ namespace smt { } app* theory_array_full::mk_epsilon(sort* s) { - app* eps = 0; + app* eps = nullptr; if (m_sort2epsilon.find(s, eps)) { return eps; } diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 0f5c235f3..873d1692d 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -373,7 +373,7 @@ namespace smt { void get_proof(conflict_resolution & cr, literal l, ptr_buffer & prs, bool & visited) { if (l.var() == true_bool_var) return; - proof * pr = 0; + proof * pr = nullptr; if (cr.get_context().get_assignment(l) == l_true) pr = cr.get_proof(l); else @@ -408,7 +408,7 @@ namespace smt { get_proof(cr, *it2, prs, visited); } if (!visited) - return 0; + return nullptr; expr * fact = ctx.mk_eq_atom(m_th.get_enode(m_var1)->get_owner(), m_th.get_enode(m_var2)->get_owner()); ast_manager & m = ctx.get_manager(); return m.mk_th_lemma(get_from_theory(), fact, prs.size(), prs.c_ptr()); @@ -1532,7 +1532,7 @@ namespace smt { visited = false; } if (!visited) - return 0; + return nullptr; context & ctx = cr.get_context(); ast_manager & m = cr.get_manager(); expr_ref fact(m); diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index ca3338cb7..f2e0f5bed 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -52,12 +52,12 @@ namespace smt { theory_var m_var; unsigned m_idx; var_pos_occ * m_next; - var_pos_occ(theory_var v = null_theory_var, unsigned idx = 0, var_pos_occ * next = 0):m_var(v), m_idx(idx), m_next(next) {} + var_pos_occ(theory_var v = null_theory_var, unsigned idx = 0, var_pos_occ * next = nullptr):m_var(v), m_idx(idx), m_next(next) {} }; struct bit_atom : public atom { var_pos_occ * m_occs; - bit_atom():m_occs(0) {} + bit_atom():m_occs(nullptr) {} ~bit_atom() override {} bool is_bit() const override { return true; } }; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index f9422ee8a..695d479f4 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -30,7 +30,7 @@ namespace smt { class dt_eq_justification : public ext_theory_eq_propagation_justification { public: dt_eq_justification(family_id fid, region & r, literal antecedent, enode * lhs, enode * rhs): - ext_theory_eq_propagation_justification(fid, r, 1, &antecedent, 0, 0, lhs, rhs) { + ext_theory_eq_propagation_justification(fid, r, 1, &antecedent, 0, nullptr, lhs, rhs) { } // Remark: the assignment must be propagated back to the datatype theory. theory_id get_from_theory() const override { return null_theory_id; } @@ -340,12 +340,12 @@ namespace smt { func_decl * c = m_util.get_recognizer_constructor(r); if (is_true) { SASSERT(tv != null_theory_var); - if (d->m_constructor != 0 && d->m_constructor->get_decl() == c) + if (d->m_constructor != nullptr && d->m_constructor->get_decl() == c) return; // do nothing assert_is_constructor_axiom(arg, c, literal(v)); } else { - if (d->m_constructor != 0) { + if (d->m_constructor != nullptr) { if (d->m_constructor->get_decl() == c) { // conflict sign_recognizer_conflict(d->m_constructor, n); @@ -400,7 +400,7 @@ namespace smt { if (m_params.m_dt_lazy_splits > 0) { // using lazy case splits... var_data * d = m_var_data[v]; - if (d->m_constructor == 0) { + if (d->m_constructor == nullptr) { mk_split(v); r = FC_CONTINUE; } @@ -427,7 +427,7 @@ namespace smt { if (res) { context & ctx = get_context(); region & r = ctx.get_region(); - ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, 0, m_used_eqs.size(), m_used_eqs.c_ptr()))); + ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, nullptr, m_used_eqs.size(), m_used_eqs.c_ptr()))); TRACE("occurs_check", tout << "occurs_check: true\n"; for (enode_pair const& p : m_used_eqs) { @@ -581,21 +581,21 @@ namespace smt { SASSERT(v1 == static_cast(m_find.find(v1))); var_data * d1 = m_var_data[v1]; var_data * d2 = m_var_data[v2]; - if (d2->m_constructor != 0) { + if (d2->m_constructor != nullptr) { context & ctx = get_context(); - if (d1->m_constructor != 0 && d1->m_constructor->get_decl() != d2->m_constructor->get_decl()) { + if (d1->m_constructor != nullptr && d1->m_constructor->get_decl() != d2->m_constructor->get_decl()) { region & r = ctx.get_region(); enode_pair p(d1->m_constructor, d2->m_constructor); SASSERT(d1->m_constructor->get_root() == d2->m_constructor->get_root()); - ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, 0, 1, &p))); + ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, nullptr, 1, &p))); } - if (d1->m_constructor == 0) { + if (d1->m_constructor == nullptr) { m_trail_stack.push(set_ptr_trail(d1->m_constructor)); // check whether there is a recognizer in d1 that conflicts with d2->m_constructor; if (!d1->m_recognizers.empty()) { unsigned c_idx = m_util.get_constructor_idx(d2->m_constructor->get_decl()); enode * recognizer = d1->m_recognizers[c_idx]; - if (recognizer != 0 && ctx.get_assignment(recognizer) == l_false) { + if (recognizer != nullptr && ctx.get_assignment(recognizer) == l_false) { sign_recognizer_conflict(d2->m_constructor, recognizer); return; } @@ -634,7 +634,7 @@ namespace smt { // Otherwise, it will be set when assign_eh is invoked. return; } - if (val == l_false && d->m_constructor != 0) { + if (val == l_false && d->m_constructor != nullptr) { func_decl * c_decl = m_util.get_recognizer_constructor(recognizer->get_decl()); if (d->m_constructor->get_decl() == c_decl) { // conflict @@ -747,7 +747,7 @@ namespace smt { unsigned non_rec_idx = m_util.get_constructor_idx(non_rec_c); var_data * d = m_var_data[v]; SASSERT(d->m_constructor == 0); - func_decl * r = 0; + func_decl * r = nullptr; m_stats.m_splits++; if (d->m_recognizers.empty()) { @@ -755,7 +755,7 @@ namespace smt { } else { enode * recognizer = d->m_recognizers[non_rec_idx]; - if (recognizer == 0) { + if (recognizer == nullptr) { r = m_util.get_constructor_recognizer(non_rec_c); } else if (!ctx.is_relevant(recognizer)) { @@ -773,7 +773,7 @@ namespace smt { ptr_vector::const_iterator end = d->m_recognizers.end(); for (unsigned idx = 0; it != end; ++it, ++idx) { enode * curr = *it; - if (curr == 0) { + if (curr == nullptr) { ptr_vector const & constructors = *m_util.get_datatype_constructors(s); // found empty slot... r = m_util.get_constructor_recognizer(constructors[idx]); @@ -787,7 +787,7 @@ namespace smt { return; } } - if (r == 0) + if (r == nullptr) return; // all recognizers are asserted to false... conflict will be detected... } } diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 3329c71cb..2337fd0ea 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -35,7 +35,7 @@ namespace smt { ptr_vector m_recognizers; //!< recognizers of this equivalence class that are being watched. enode * m_constructor; //!< constructor of this equivalence class, 0 if there is no constructor in the eqc. var_data(): - m_constructor(0) { + m_constructor(nullptr) { } }; diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 78fb4d03d..86e1fd5e8 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -867,7 +867,7 @@ namespace smt { } else { context& ctx = get_context(); - enode * e = 0; + enode * e = nullptr; theory_var v = 0; if (ctx.e_internalized(n)) { e = ctx.get_enode(to_app(n)); diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index ce0814f10..6090b2f5f 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -234,7 +234,7 @@ namespace smt { m_agility(0.5), m_is_lia(true), m_non_diff_logic_exprs(false), - m_factory(0), + m_factory(nullptr), m_nc_functor(*this), m_S(m.limit()), m_num_simplex_edges(0) { @@ -297,7 +297,7 @@ namespace smt { justification * why_is_diseq(theory_var v1, theory_var v2) override { NOT_IMPLEMENTED_YET(); - return 0; + return nullptr; } // virtual void flush_eh(); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 59f5521c5..fc4ff25c7 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -298,7 +298,7 @@ void theory_diff_logic::internalize_eq_eh(app * atom, bool_var v) { template void theory_diff_logic::assign_eh(bool_var v, bool is_true) { m_stats.m_num_assertions++; - atom * a = 0; + atom * a = nullptr; VERIFY (m_bool_var2atom.find(v, a)); SASSERT(a); SASSERT(get_context().get_assignment(v) != l_undef); @@ -602,7 +602,7 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges ctx.mark_as_relevant(le.get()); literal lit(ctx.get_literal(le)); bool_var bv = lit.var(); - atom* a = 0; + atom* a = nullptr; m_bool_var2atom.find(bv, a); SASSERT(a); @@ -619,7 +619,7 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges tout << "\n"; ); - justification * js = 0; + justification * js = nullptr; if (get_manager().proofs_enabled()) { vector params; params.push_back(parameter(symbol("farkas"))); @@ -628,7 +628,7 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges lits.size(), lits.c_ptr(), params.size(), params.c_ptr()); } - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, nullptr); if (dump_lemmas()) { symbol logic(m_is_lia ? "QF_LIA" : "QF_LRA"); ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic); @@ -692,7 +692,7 @@ void theory_diff_logic::set_neg_cycle_conflict() { ctx.mk_justification( ext_theory_conflict_justification( get_id(), ctx.get_region(), - lits.size(), lits.c_ptr(), 0, 0, params.size(), params.c_ptr()))); + lits.size(), lits.c_ptr(), 0, nullptr, params.size(), params.c_ptr()))); } @@ -774,7 +774,7 @@ theory_var theory_diff_logic::mk_term(app* n) { template theory_var theory_diff_logic::mk_num(app* n, rational const& r) { theory_var v = null_theory_var; - enode* e = 0; + enode* e = nullptr; context& ctx = get_context(); if (r.is_zero()) { v = get_zero(); @@ -813,7 +813,7 @@ theory_var theory_diff_logic::mk_var(enode* n) { template theory_var theory_diff_logic::mk_var(app* n) { context & ctx = get_context(); - enode* e = 0; + enode* e = nullptr; theory_var v = null_theory_var; if (ctx.e_internalized(n)) { e = ctx.get_enode(n); diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index 1e9df2973..285c03946 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -78,7 +78,7 @@ namespace smt { app * mk_value(smt::model_generator & mg, ptr_vector & ) override { smt::context& ctx = m_th.get_context(); - app* result = 0; + app* result = nullptr; expr* n = m_node->get_owner(); sort* s = m_th.m().get_sort(n); func_decl* r, *v; @@ -204,8 +204,8 @@ namespace smt { if(!m_reps.find(s, r) || !m_vals.find(s,v)) { SASSERT(!m_reps.contains(s)); sort* bv = b().mk_sort(64); - r = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_REP, 0, 0, 1, &s, bv); - v = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_ABS, 0, 0, 1, &bv, s); + r = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_REP, 0, nullptr, 1, &s, bv); + v = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_ABS, 0, nullptr, 1, &bv, s); m_reps.insert(s, r); m_vals.insert(s, v); add_trail(r); @@ -218,7 +218,7 @@ namespace smt { bool mk_rep(app* n) { context & ctx = get_context(); unsigned num_args = n->get_num_args(); - enode * e = 0; + enode * e = nullptr; for (unsigned i = 0; i < num_args; i++) { ctx.internalize(n->get_arg(i), false); } diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 36ee5c15a..b7aaff68a 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -38,7 +38,7 @@ namespace smt { m_map.remove(key); m.dec_ref(key); m.dec_ref(val); - key = 0; + key = nullptr; } }; @@ -208,7 +208,7 @@ namespace smt { for (unsigned i = 0; i < values.size(); i++) tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); - app * result = 0; + app * result = nullptr; unsigned bv_sz; rational val(0); @@ -256,7 +256,7 @@ namespace smt { } func_decl_ref wrap_fd(m); - wrap_fd = m.mk_func_decl(get_family_id(), OP_FPA_BVWRAP, 0, 0, 1, &es, bv_srt); + wrap_fd = m.mk_func_decl(get_family_id(), OP_FPA_BVWRAP, 0, nullptr, 1, &es, bv_srt); res = m.mk_app(wrap_fd, e); } @@ -705,7 +705,7 @@ namespace smt { m_trail_stack.pop_scope(m_trail_stack.get_num_scopes()); if (m_factory) { dealloc(m_factory); - m_factory = 0; + m_factory = nullptr; } ast_manager & m = get_manager(); dec_ref_map_key_values(m, m_conversions); @@ -743,7 +743,7 @@ namespace smt { return alloc(expr_wrapper_proc, owner); } - model_value_proc * res = 0; + model_value_proc * res = nullptr; app_ref wrapped(m); wrapped = wrap(owner); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index d369ddefa..f475a8279 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -658,12 +658,12 @@ namespace smt { m_internalize_head(0), m_delay_constraints(false), m_delayed_terms(m), - m_not_handled(0), + m_not_handled(nullptr), m_asserted_qhead(0), m_assume_eq_head(0), m_num_conflicts(0), m_model_eqs(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)), - m_solver(0), + m_solver(nullptr), m_resource_limit(*this) { } @@ -689,7 +689,7 @@ namespace smt { SASSERT(!ctx().b_internalized(atom)); bool_var bv = ctx().mk_bool_var(atom); ctx().set_var_theory(bv, get_id()); - expr* n1 = 0, *n2 = 0; + expr* n1 = nullptr, *n2 = nullptr; rational r; lra_lp::bound_kind k; theory_var v = null_theory_var; @@ -721,7 +721,7 @@ namespace smt { SASSERT(!ctx().b_internalized(atom)); bool_var bv = ctx().mk_bool_var(atom); ctx().set_var_theory(bv, get_id()); - expr* n1 = 0, *n2 = 0; + expr* n1 = nullptr, *n2 = nullptr; rational r; lra_lp::bound_kind k; theory_var v = null_theory_var; @@ -771,7 +771,7 @@ namespace smt { } void internalize_eq_eh(app * atom, bool_var) { - expr* lhs = 0, *rhs = 0; + expr* lhs = nullptr, *rhs = nullptr; VERIFY(m.is_eq(atom, lhs, rhs)); enode * n1 = get_enode(lhs); enode * n2 = get_enode(rhs); @@ -862,7 +862,7 @@ namespace smt { void relevant_eh(app* n) { TRACE("arith", tout << mk_pp(n, m) << "\n";); - expr* n1 = 0, *n2 = 0; + expr* n1 = nullptr, *n2 = nullptr; if (a.is_mod(n, n1, n2)) mk_idiv_mod_axioms(n1, n2); else if (a.is_rem(n, n1, n2)) @@ -898,7 +898,7 @@ namespace smt { // to_int (to_real x) = x // to_real(to_int(x)) <= x < to_real(to_int(x)) + 1 void mk_to_int_axiom(app* n) { - expr* x = 0, *y = 0; + expr* x = nullptr, *y = nullptr; VERIFY (a.is_to_int(n, x)); if (a.is_to_real(x, y)) { mk_axiom(th.mk_eq(y, n, false)); @@ -914,7 +914,7 @@ namespace smt { // is_int(x) <=> to_real(to_int(x)) = x void mk_is_int_axiom(app* n) { - expr* x = 0; + expr* x = nullptr; VERIFY(a.is_is_int(n, x)); literal eq = th.mk_eq(a.mk_to_real(a.mk_to_int(x)), x, false); literal is_int = ctx().get_literal(n); @@ -1180,7 +1180,7 @@ namespace smt { if (assume_eqs()) { return FC_CONTINUE; } - if (m_not_handled != 0) { + if (m_not_handled != nullptr) { return FC_GIVEUP; } return FC_DONE; @@ -1439,12 +1439,12 @@ namespace smt { m_core2.push_back(~m_core[i]); } m_core2.push_back(lit); - justification * js = 0; + justification * js = nullptr; if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx(), m_core2.size(), m_core2.c_ptr(), m_params.size(), m_params.c_ptr()); } - ctx().mk_clause(m_core2.size(), m_core2.c_ptr(), js, CLS_AUX_LEMMA, 0); + ctx().mk_clause(m_core2.size(), m_core2.c_ptr(), js, CLS_AUX_LEMMA, nullptr); } else { ctx().assign( @@ -1499,7 +1499,7 @@ namespace smt { rational const& k1 = b.get_value(); lp_bounds & bounds = m_bounds[v]; - lra_lp::bound* end = 0; + lra_lp::bound* end = nullptr; lra_lp::bound* lo_inf = end, *lo_sup = end; lra_lp::bound* hi_inf = end, *hi_sup = end; @@ -1764,7 +1764,7 @@ namespace smt { bool find_glb = (is_true == (k == lra_lp::lower_t)); if (find_glb) { rational glb; - lra_lp::bound* lb = 0; + lra_lp::bound* lb = nullptr; for (unsigned i = 0; i < bounds.size(); ++i) { lra_lp::bound* b2 = bounds[i]; if (b2 == &b) continue; @@ -1780,7 +1780,7 @@ namespace smt { } else { rational lub; - lra_lp::bound* ub = 0; + lra_lp::bound* ub = nullptr; for (unsigned i = 0; i < bounds.size(); ++i) { lra_lp::bound* b2 = bounds[i]; if (b2 == &b) continue; @@ -2111,7 +2111,7 @@ namespace smt { justification* js = ctx().mk_justification( ext_theory_eq_propagation_justification( - get_id(), ctx().get_region(), m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), x, y, 0, 0)); + get_id(), ctx().get_region(), m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), x, y, 0, nullptr)); TRACE("arith", for (unsigned i = 0; i < m_core.size(); ++i) { @@ -2236,12 +2236,12 @@ namespace smt { } justification * why_is_diseq(theory_var v1, theory_var v2) { - return 0; + return nullptr; } void reset_eh() { m_arith_eq_adapter.reset_eh(); - m_solver = 0; + m_solver = nullptr; m_not_handled = nullptr; del_bounds(0); m_unassigned_bounds.reset(); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index cc9b6b9b1..aca617daa 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -403,12 +403,12 @@ namespace smt { } m_stats.m_num_conflicts++; - justification* js = 0; + justification* js = nullptr; if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); } TRACE("pb", tout << lits << "\n";); - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, nullptr); return false; } @@ -697,7 +697,7 @@ namespace smt { void theory_pb::watch_literal(literal lit, ineq* c) { init_watch(lit.var()); ptr_vector* ineqs = m_var_infos[lit.var()].m_lit_watch[lit.sign()]; - if (ineqs == 0) { + if (ineqs == nullptr) { ineqs = alloc(ptr_vector); m_var_infos[lit.var()].m_lit_watch[lit.sign()] = ineqs; } @@ -707,7 +707,7 @@ namespace smt { void theory_pb::watch_var(bool_var v, ineq* c) { init_watch(v); ptr_vector* ineqs = m_var_infos[v].m_var_watch; - if (ineqs == 0) { + if (ineqs == nullptr) { ineqs = alloc(ptr_vector); m_var_infos[v].m_var_watch = ineqs; } @@ -770,12 +770,12 @@ namespace smt { } void theory_pb::assign_eh(bool_var v, bool is_true) { - ptr_vector* ineqs = 0; + ptr_vector* ineqs = nullptr; literal nlit(v, is_true); init_watch(v); TRACE("pb", tout << "assign: " << ~nlit << "\n";); ineqs = m_var_infos[v].m_lit_watch[nlit.sign()]; - if (ineqs != 0) { + if (ineqs != nullptr) { if (m_enable_simplex) { mpq_inf num(mpq(is_true?1:0),mpq(0)); if (!update_bound(v, ~nlit, is_true, num)) { @@ -796,14 +796,14 @@ namespace smt { } } ineqs = m_var_infos[v].m_var_watch; - if (ineqs != 0) { + if (ineqs != nullptr) { for (unsigned i = 0; i < ineqs->size(); ++i) { ineq* c = (*ineqs)[i]; assign_watch(v, is_true, *c); } } ineq* c = m_var_infos[v].m_ineq; - if (c != 0) { + if (c != nullptr) { if (m_enable_simplex) { row_info const& info = m_ineq_row_info.find(v); unsynch_mpq_manager mgr; @@ -1197,7 +1197,7 @@ namespace smt { void mk_clause(unsigned n, literal const* ls) { literal_vector tmp(n, ls); - ctx.mk_clause(n, tmp.c_ptr(), th.justify(tmp), CLS_AUX, 0); + ctx.mk_clause(n, tmp.c_ptr(), th.justify(tmp), CLS_AUX, nullptr); } literal mk_false() { return false_literal; } @@ -1319,7 +1319,7 @@ namespace smt { bool_var v = m_ineqs_trail.back(); ineq* c = m_var_infos[v].m_ineq; clear_watch(*c); - m_var_infos[v].m_ineq = 0; + m_var_infos[v].m_ineq = nullptr; m_ineqs_trail.pop_back(); if (m_enable_simplex) { row_info r_info; @@ -1449,7 +1449,7 @@ namespace smt { tout << "\n"; display(tout, c, true);); - justification* js = 0; + justification* js = nullptr; if (m_conflict_frequency == 0 || (m_conflict_frequency -1 == (c.m_num_propagations % m_conflict_frequency))) { resolve_conflict(c); @@ -1458,7 +1458,7 @@ namespace smt { js = alloc(theory_lemma_justification, get_id(), ctx, lits.size(), lits.c_ptr()); } TRACE("pb", tout << lits << "\n";); - ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, nullptr); } @@ -1702,18 +1702,18 @@ namespace smt { break; case b_justification::JUSTIFICATION: { justification* j = js.get_justification(); - pb_justification* pbj = 0; + pb_justification* pbj = nullptr; if (!conseq.sign() && j->get_from_theory() == get_id()) { pbj = dynamic_cast(j); } if (pbj && pbj->get_ineq().is_eq()) { // only resolve >= that are positive consequences. - pbj = 0; + pbj = nullptr; } if (pbj && pbj->get_ineq().lit() == conseq) { // can't resolve against literal representing inequality. - pbj = 0; + pbj = nullptr; } if (pbj) { // weaken the lemma and resolve. @@ -1765,7 +1765,7 @@ namespace smt { m_ineq_literals[i].neg(); } TRACE("pb", tout << m_ineq_literals << "\n";); - ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), justify(m_ineq_literals), CLS_AUX_LEMMA, 0); + ctx.mk_clause(m_ineq_literals.size(), m_ineq_literals.c_ptr(), justify(m_ineq_literals), CLS_AUX_LEMMA, nullptr); break; default: { app_ref tmp = m_lemma.to_expr(false, ctx, get_manager()); @@ -1785,7 +1785,7 @@ namespace smt { justification* theory_pb::justify(literal l1, literal l2) { literal lits[2] = { l1, l2 }; - justification* js = 0; + justification* js = nullptr; if (proofs_enabled()) { js = get_context().mk_justification(theory_axiom_justification(get_id(), get_context().get_region(), 2, lits)); } @@ -1793,7 +1793,7 @@ namespace smt { } justification* theory_pb::justify(literal_vector const& lits) { - justification* js = 0; + justification* js = nullptr; if (proofs_enabled()) { js = get_context().mk_justification(theory_axiom_justification(get_id(), get_context().get_region(), lits.size(), lits.c_ptr())); } @@ -2038,9 +2038,9 @@ namespace smt { return (sum >= k)?m.mk_true():m.mk_false(); default: UNREACHABLE(); - return 0; + return nullptr; } - return 0; + return nullptr; } }; @@ -2058,7 +2058,7 @@ namespace smt { return true; } expr * get_fresh_value(sort * s) override { - return 0; + return nullptr; } void register_value(expr * n) override { } }; diff --git a/src/smt/theory_pb.h b/src/smt/theory_pb.h index 5eb6e3312..07c763469 100644 --- a/src/smt/theory_pb.h +++ b/src/smt/theory_pb.h @@ -198,10 +198,10 @@ namespace smt { watch_list* m_var_watch; ineq* m_ineq; - var_info(): m_var_watch(0), m_ineq(0) + var_info(): m_var_watch(nullptr), m_ineq(nullptr) { - m_lit_watch[0] = 0; - m_lit_watch[1] = 0; + m_lit_watch[0] = nullptr; + m_lit_watch[1] = nullptr; } void reset() { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 6fabbf865..e92a25159 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -87,7 +87,7 @@ bool theory_seq::solution_map::is_root(expr* e) const { // e1 -> ... x, e2 -> ... x void theory_seq::solution_map::find_rec(expr* e, svector >& finds) { - dependency* d = 0; + dependency* d = nullptr; std::pair value(e, d); do { e = value.first; @@ -111,7 +111,7 @@ bool theory_seq::solution_map::find1(expr* e, expr*& r, dependency*& d) { expr* theory_seq::solution_map::find(expr* e, dependency*& d) { std::pair value; - d = 0; + d = nullptr; expr* result = e; while (m_map.find(result, value)) { d = m_dm.mk_join(d, value.second); @@ -199,12 +199,12 @@ theory_seq::theory_seq(ast_manager& m): m_reset_cache(false), m_eq_id(0), m_find(*this), - m_factory(0), + m_factory(nullptr), m_exclude(m), m_axioms(m), m_axioms_head(0), m_int_string(m), - m_mg(0), + m_mg(nullptr), m_rewrite(m), m_seq_rewrite(m), m_util(m), @@ -381,7 +381,7 @@ bool theory_seq::branch_binary_variable(eq const& e) { // |x| - |y| = |ys| - |xs| expr_ref a(mk_sub(m_util.str.mk_length(x), m_util.str.mk_length(y)), m); expr_ref b(m_autil.mk_int(ys.size()-xs.size()), m); - propagate_lit(e.dep(), 0, 0, mk_eq(a, b, false)); + propagate_lit(e.dep(), 0, nullptr, mk_eq(a, b, false)); return true; } if (lenX <= rational(ys.size())) { @@ -456,7 +456,7 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector if (lenX > rational(units.size())) { expr_ref le(m_autil.mk_le(m_util.str.mk_length(X), m_autil.mk_int(units.size())), m); TRACE("seq", tout << "propagate length on " << mk_pp(X, m) << "\n";); - propagate_lit(dep, 0, 0, mk_literal(le)); + propagate_lit(dep, 0, nullptr, mk_literal(le)); return; } SASSERT(lenX.is_unsigned()); @@ -1003,7 +1003,7 @@ bool theory_seq::fixed_length(expr* e) { */ void theory_seq::propagate_non_empty(literal lit, expr* s) { SASSERT(get_context().get_assignment(lit) == l_true); - propagate_lit(0, 1, &lit, ~mk_eq_empty(s)); + propagate_lit(nullptr, 1, &lit, ~mk_eq_empty(s)); } bool theory_seq::propagate_is_conc(expr* e, expr* conc) { @@ -1011,7 +1011,7 @@ bool theory_seq::propagate_is_conc(expr* e, expr* conc) { context& ctx = get_context(); literal lit = ~mk_eq_empty(e); if (ctx.get_assignment(lit) == l_true) { - propagate_lit(0, 1, &lit, mk_eq(e, conc, false)); + propagate_lit(nullptr, 1, &lit, mk_eq(e, conc, false)); expr_ref e1(e, m), e2(conc, m); new_eq_eh(m_dm.mk_leaf(assumption(lit)), ctx.get_enode(e1), ctx.get_enode(e2)); return true; @@ -1060,9 +1060,9 @@ bool theory_seq::is_post(expr* e, expr*& s, expr*& i) { expr_ref theory_seq::mk_nth(expr* s, expr* idx) { - sort* char_sort = 0; + sort* char_sort = nullptr; VERIFY(m_util.is_seq(m.get_sort(s), char_sort)); - return mk_skolem(m_nth, s, idx, 0, char_sort); + return mk_skolem(m_nth, s, idx, nullptr, char_sort); } expr_ref theory_seq::mk_sk_ite(expr* c, expr* t, expr* e) { @@ -1074,9 +1074,9 @@ expr_ref theory_seq::mk_last(expr* s) { if (m_util.str.is_string(s, str) && str.length() > 0) { return expr_ref(m_util.str.mk_char(str, str.length()-1), m); } - sort* char_sort = 0; + sort* char_sort = nullptr; VERIFY(m_util.is_seq(m.get_sort(s), char_sort)); - return mk_skolem(m_seq_last, s, 0, 0, char_sort); + return mk_skolem(m_seq_last, s, nullptr, nullptr, char_sort); } expr_ref theory_seq::mk_first(expr* s) { @@ -1089,7 +1089,7 @@ expr_ref theory_seq::mk_first(expr* s) { void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) { - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; zstring s; if (m_util.str.is_empty(e)) { head = m_util.str.mk_unit(mk_nth(e, m_autil.mk_int(0))); @@ -1136,7 +1136,7 @@ bool theory_seq::check_extensionality() { continue; } if (!seqs.empty() && ctx.is_relevant(n1) && m_util.is_seq(o1) && ctx.is_shared(n1)) { - dependency* dep = 0; + dependency* dep = nullptr; expr_ref e1 = canonize(o1, dep); for (unsigned i = 0; i < seqs.size(); ++i) { enode* n2 = get_enode(seqs[i]); @@ -1237,7 +1237,7 @@ bool theory_seq::linearize(dependency* dep, enode_pair_vector& eqs, literal_vect lits.push_back(a.lit); asserted &= ctx.get_assignment(a.lit) == l_true; } - if (a.n1 != 0) { + if (a.n1 != nullptr) { eqs.push_back(enode_pair(a.n1, a.n2)); } } @@ -1286,7 +1286,7 @@ void theory_seq::set_conflict(dependency* dep, literal_vector const& _lits) { ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), 0, 0))); + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), 0, nullptr))); } void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { @@ -1438,7 +1438,7 @@ bool theory_seq::occurs(expr* a, expr* b) { // true if a occurs under an interpreted function or under left/right selector. SASSERT(is_var(a)); SASSERT(m_todo.empty()); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; m_todo.push_back(b); while (!m_todo.empty()) { b = m_todo.back(); @@ -1508,7 +1508,7 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de expr_ref_vector& ls = m_ls; expr_ref_vector& rs = m_rs; rs.reset(); ls.reset(); - dependency* dep2 = 0; + dependency* dep2 = nullptr; bool change = canonize(l, ls, dep2); change = canonize(r, rs, dep2) || change; deps = m_dm.mk_join(dep2, deps); @@ -1545,7 +1545,7 @@ bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) { } rational hi; if (is_tail(l, s, idx) && has_length(s) && m_util.str.is_empty(r) && !upper_bound(s, hi)) { - propagate_lit(deps, 0, 0, mk_literal(m_autil.mk_le(m_util.str.mk_length(s), m_autil.mk_int(idx+1)))); + propagate_lit(deps, 0, nullptr, mk_literal(m_autil.mk_le(m_util.str.mk_length(s), m_autil.mk_int(idx+1)))); return true; } return false; @@ -1737,7 +1737,7 @@ bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector cons } ctx.mark_as_relevant(eq); if (sz == 1) { - propagate_lit(dep, 0, 0, eq); + propagate_lit(dep, 0, nullptr, eq); return true; } m_new_propagation = true; @@ -1885,7 +1885,7 @@ bool theory_seq::solve_ne(unsigned idx) { expr_ref_vector& lhs = m_lhs; expr_ref_vector& rhs = m_rhs; ls.reset(); rs.reset(); lhs.reset(); rhs.reset(); - dependency* deps = 0; + dependency* deps = nullptr; bool change = false; change = canonize(n.ls(i), ls, deps) || change; change = canonize(n.rs(i), rs, deps) || change; @@ -1991,7 +1991,7 @@ bool theory_seq::solve_ne(unsigned idx) { if (num_undef_lits == 0 && new_ls.empty()) { TRACE("seq", tout << "conflict\n";); - dependency* deps1 = 0; + dependency* deps1 = nullptr; if (explain_eq(n.l(), n.r(), deps1)) { literal diseq = mk_eq(n.l(), n.r(), false); if (ctx.get_assignment(diseq) == l_false) { @@ -2034,10 +2034,10 @@ bool theory_seq::solve_nc(unsigned idx) { return true; } - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; if (m.is_eq(c, e1, e2)) { literal eq = mk_eq(e1, e2, false); - propagate_lit(deps, 0, 0, ~eq); + propagate_lit(deps, 0, nullptr, ~eq); return true; } @@ -2059,7 +2059,7 @@ theory_seq::cell* theory_seq::mk_cell(cell* p, expr* e, dependency* d) { } void theory_seq::unfold(cell* c, ptr_vector& cons) { - dependency* dep = 0; + dependency* dep = nullptr; expr* a, *e1, *e2; if (m_rep.find1(c->m_expr, a, dep)) { cell* c1 = mk_cell(c, a, m_dm.mk_join(dep, c->m_dep)); @@ -2067,7 +2067,7 @@ void theory_seq::unfold(cell* c, ptr_vector& cons) { } else if (m_util.str.is_concat(c->m_expr, e1, e2)) { cell* c1 = mk_cell(c, e1, c->m_dep); - cell* c2 = mk_cell(0, e2, 0); + cell* c2 = mk_cell(nullptr, e2, nullptr); unfold(c1, cons); unfold(c2, cons); } @@ -2085,7 +2085,7 @@ void theory_seq::unfold(cell* c, ptr_vector& cons) { void theory_seq::display_explain(std::ostream& out, unsigned indent, expr* e) { expr* e1, *e2, *a; - dependency* dep = 0; + dependency* dep = nullptr; smt2_pp_environment_dbg env(m); params_ref p; for (unsigned i = 0; i < indent; ++i) out << " "; @@ -2109,8 +2109,8 @@ bool theory_seq::explain_eq(expr* e1, expr* e2, dependency*& dep) { expr* a1, *a2; ptr_vector v1, v2; unsigned cells_sz = m_all_cells.size(); - cell* c1 = mk_cell(0, e1, 0); - cell* c2 = mk_cell(0, e2, 0); + cell* c1 = mk_cell(nullptr, e1, nullptr); + cell* c2 = mk_cell(nullptr, e2, nullptr); unfold(c1, v1); unfold(c2, v2); unsigned i = 0, j = 0; @@ -2300,7 +2300,7 @@ bool theory_seq::internalize_term(app* term) { ctx.mark_as_relevant(bv); } - enode* e = 0; + enode* e = nullptr; if (ctx.e_internalized(term)) { e = ctx.get_enode(term); } @@ -2358,7 +2358,7 @@ bool theory_seq::check_int_string() { bool theory_seq::add_stoi_axiom(expr* e) { context& ctx = get_context(); - expr* n = 0; + expr* n = nullptr; rational val; TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_stoi(e, n)); @@ -2426,7 +2426,7 @@ bool theory_seq::add_stoi_axiom(expr* e) { literal theory_seq::is_digit(expr* ch) { bv_util bv(m); - literal isd = mk_literal(mk_skolem(symbol("seq.is_digit"), ch, 0, 0, m.mk_bool_sort())); + literal isd = mk_literal(mk_skolem(symbol("seq.is_digit"), ch, nullptr, nullptr, m.mk_bool_sort())); expr_ref d2i = digit2int(ch); expr_ref _lo(bv.mk_ule(bv.mk_numeral(rational('0'), bv.mk_sort(8)), ch), m); expr_ref _hi(bv.mk_ule(ch, bv.mk_numeral(rational('9'), bv.mk_sort(8))), m); @@ -2442,13 +2442,13 @@ literal theory_seq::is_digit(expr* ch) { } expr_ref theory_seq::digit2int(expr* ch) { - return expr_ref(mk_skolem(symbol("seq.digit2int"), ch, 0, 0, m_autil.mk_int()), m); + return expr_ref(mk_skolem(symbol("seq.digit2int"), ch, nullptr, nullptr, m_autil.mk_int()), m); } bool theory_seq::add_itos_axiom(expr* e) { context& ctx = get_context(); rational val; - expr* n = 0; + expr* n = nullptr; TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_itos(e, n)); if (get_num_value(n, val)) { @@ -2656,7 +2656,7 @@ void theory_seq::init_search_eh() { void theory_seq::init_model(expr_ref_vector const& es) { expr_ref new_s(m); for (expr* e : es) { - dependency* eqs = 0; + dependency* eqs = nullptr; expr_ref s = canonize(e, eqs); if (is_var(s)) { new_s = m_factory->get_fresh_value(m.get_sort(s)); @@ -2734,7 +2734,7 @@ public: break; } case string_source: { - dependency* deps = 0; + dependency* deps = nullptr; expr_ref tmp = th.canonize(m_strings[k], deps); zstring zs; if (th.m_util.str.is_string(tmp, zs)) { @@ -2848,7 +2848,7 @@ app* theory_seq::mk_value(app* e) { } m_factory->add_trail(result); TRACE("seq", tout << mk_pp(e, m) << " -> " << result << "\n";); - m_rep.update(e, result, 0); + m_rep.update(e, result, nullptr); return to_app(result); } @@ -2944,7 +2944,7 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) { expr_ref result(m); result = try_expand(e0, eqs); if (result) return result; - dependency* deps = 0; + dependency* deps = nullptr; expr* e = m_rep.find(e0, deps); expr* e1, *e2, *e3; expr_ref arg1(m), arg2(m); @@ -3074,7 +3074,7 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) { result = e; } if (result == e0) { - deps = 0; + deps = nullptr; } expr_dep edr(result, deps); m_rep.add_cache(e0, edr); @@ -3204,7 +3204,7 @@ void theory_seq::tightest_prefix(expr* s, expr* x) { (len(s) <= len(t) -> i <= len(t)-len(s)) */ void theory_seq::add_indexof_axiom(expr* i) { - expr* s = 0, *t = 0, *offset = 0; + expr* s = nullptr, *t = nullptr, *offset = nullptr; rational r; VERIFY(m_util.str.is_index(i, t, s) || m_util.str.is_index(i, t, s, offset)); @@ -3289,7 +3289,7 @@ void theory_seq::add_indexof_axiom(expr* i) { */ void theory_seq::add_replace_axiom(expr* r) { context& ctx = get_context(); - expr* a = 0, *s = 0, *t = 0; + expr* a = nullptr, *s = nullptr, *t = nullptr; VERIFY(m_util.str.is_replace(r, a, s, t)); expr_ref x = mk_skolem(m_indexof_left, a, s); expr_ref y = mk_skolem(m_indexof_right, a, s); @@ -3319,7 +3319,7 @@ void theory_seq::add_elim_string_axiom(expr* n) { result = mk_concat(m_util.str.mk_unit(m_util.str.mk_char(s, i)), result); } add_axiom(mk_eq(n, result, false)); - m_rep.update(n, result, 0); + m_rep.update(n, result, nullptr); m_new_solution = true; } @@ -3335,7 +3335,7 @@ void theory_seq::add_elim_string_axiom(expr* n) { */ void theory_seq::add_length_axiom(expr* n) { context& ctx = get_context(); - expr* x = 0; + expr* x = nullptr; VERIFY(m_util.str.is_length(n, x)); if (m_util.str.is_concat(x) || m_util.str.is_unit(x) || @@ -3358,7 +3358,7 @@ void theory_seq::add_length_axiom(expr* n) { } void theory_seq::add_itos_length_axiom(expr* len) { - expr* x = 0, *n = 0; + expr* x = nullptr, *n = nullptr; VERIFY(m_util.str.is_length(len, x)); VERIFY(m_util.str.is_itos(x, n)); @@ -3423,7 +3423,7 @@ void theory_seq::add_itos_length_axiom(expr* len) { void theory_seq::propagate_in_re(expr* n, bool is_true) { TRACE("seq", tout << mk_pp(n, m) << " <- " << (is_true?"true":"false") << "\n";); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; VERIFY(m_util.str.is_in_re(n, e1, e2)); expr_ref tmp(n, m); @@ -3432,7 +3432,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { if (!is_true) { literal_vector lits; lits.push_back(mk_literal(n)); - set_conflict(0, lits); + set_conflict(nullptr, lits); } return; } @@ -3440,7 +3440,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { if (is_true) { literal_vector lits; lits.push_back(~mk_literal(n)); - set_conflict(0, lits); + set_conflict(nullptr, lits); } return; } @@ -3474,7 +3474,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { lits.push_back(mk_accept(e1, zero, e3, states[i])); } if (lits.size() == 2) { - propagate_lit(0, 1, &lit, lits[1]); + propagate_lit(nullptr, 1, &lit, lits[1]); } else { TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); @@ -3506,7 +3506,7 @@ static T* get_th_arith(context& ctx, theory_id afid, expr* e) { return dynamic_cast(th); } else { - return 0; + return nullptr; } } @@ -3566,7 +3566,7 @@ bool theory_seq::get_length(expr* e, rational& val) const { context& ctx = get_context(); rational val1; expr_ref len(m), len_val(m); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; ptr_vector todo; todo.push_back(e); val.reset(); @@ -3638,7 +3638,7 @@ this translates to: void theory_seq::add_extract_axiom(expr* e) { TRACE("seq", tout << mk_pp(e, m) << "\n";); - expr* s = 0, *i = 0, *l = 0; + expr* s = nullptr, *i = nullptr, *l = nullptr; VERIFY(m_util.str.is_extract(e, s, i, l)); if (is_tail(s, i, l)) { add_tail_axiom(e, s); @@ -3769,7 +3769,7 @@ void theory_seq::add_extract_suffix_axiom(expr* e, expr* s, expr* i) { */ void theory_seq::add_at_axiom(expr* e) { - expr* s = 0, *i = 0; + expr* s = nullptr, *i = nullptr; VERIFY(m_util.str.is_at(e, s, i)); expr_ref len_e(m_util.str.mk_length(e), m); expr_ref len_s(m_util.str.mk_length(s), m); @@ -3798,17 +3798,17 @@ void theory_seq::add_at_axiom(expr* e) { */ void theory_seq::propagate_step(literal lit, expr* step) { SASSERT(get_context().get_assignment(lit) == l_true); - expr* re = 0, *acc = 0, *s = 0, *idx = 0, *i = 0, *j = 0; + expr* re = nullptr, *acc = nullptr, *s = nullptr, *idx = nullptr, *i = nullptr, *j = nullptr; VERIFY(is_step(step, s, idx, re, i, j, acc)); TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(acc, m) << "\n";); - propagate_lit(0, 1, &lit, mk_simplified_literal(acc)); + propagate_lit(nullptr, 1, &lit, mk_simplified_literal(acc)); rational lo; rational _idx; if (lower_bound(s, lo) && lo.is_unsigned() && m_autil.is_numeral(idx, _idx) && lo >= _idx) { // skip } else { - propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); + propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); } ensure_nth(lit, s, idx); } @@ -3854,7 +3854,7 @@ literal theory_seq::mk_literal(expr* _e) { literal theory_seq::mk_seq_eq(expr* a, expr* b) { SASSERT(m_util.is_seq(a)); - return mk_literal(mk_skolem(m_eq, a, b, 0, m.mk_bool_sort())); + return mk_literal(mk_skolem(m_eq, a, b, nullptr, m.mk_bool_sort())); } literal theory_seq::mk_eq_empty(expr* _e, bool phase) { @@ -3927,7 +3927,7 @@ theory_seq::dependency* theory_seq::mk_join(dependency* deps, literal_vector con void theory_seq::propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs) { literal_vector lits; lits.push_back(lit); - propagate_eq(0, lits, e1, e2, add_to_eqs); + propagate_eq(nullptr, lits, e1, e2, add_to_eqs); } void theory_seq::propagate_eq(dependency* deps, literal_vector const& _lits, expr* e1, expr* e2, bool add_to_eqs) { @@ -3966,7 +3966,7 @@ void theory_seq::propagate_eq(dependency* deps, literal_vector const& _lits, exp void theory_seq::assign_eh(bool_var v, bool is_true) { context & ctx = get_context(); expr* e = ctx.bool_var2expr(v); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; expr_ref f(m); bool change = false; literal lit(v, !is_true); @@ -4231,7 +4231,7 @@ void theory_seq::relevant_eh(app* n) { eautomaton* theory_seq::get_automaton(expr* re) { - eautomaton* result = 0; + eautomaton* result = nullptr; if (m_re2aut.find(re, result)) { return result; } @@ -4312,9 +4312,9 @@ expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned rej(s, idx, re, i) -> len(s) > idx if i is final */ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { - expr *s = 0, *idx = 0, *re = 0; + expr *s = nullptr, *idx = nullptr, *re = nullptr; unsigned src; - eautomaton* aut = 0; + eautomaton* aut = nullptr; bool is_acc; is_acc = is_accept(e, s, idx, re, src, aut); if (!is_acc) { @@ -4324,15 +4324,15 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { SASSERT(m_autil.is_numeral(idx)); SASSERT(get_context().get_assignment(lit) == l_true); if (aut->is_sink_state(src)) { - propagate_lit(0, 1, &lit, false_literal); + propagate_lit(nullptr, 1, &lit, false_literal); return; } bool is_final = aut->is_final_state(src); if (is_final == is_acc) { - propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); + propagate_lit(nullptr, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); } else { - propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); + propagate_lit(nullptr, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); } } @@ -4345,10 +4345,10 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { TRACE("seq", tout << mk_pp(acc, m) << "\n";); SASSERT(ctx.get_assignment(acc) == l_true); - expr *e = 0, *idx = 0, *re = 0; + expr *e = nullptr, *idx = nullptr, *re = nullptr; expr_ref step(m); unsigned src; - eautomaton* aut = 0; + eautomaton* aut = nullptr; VERIFY(is_accept(acc, e, idx, re, src, aut)); if (!aut || m_util.str.is_length(idx)) { return false; @@ -4401,7 +4401,7 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { for (unsigned i = 0; i < lits.size(); ++i) { lits[i].neg(); } - propagate_lit(0, lits.size(), lits.c_ptr(), lit); + propagate_lit(nullptr, lits.size(), lits.c_ptr(), lit); return false; } if (has_undef) { @@ -4412,7 +4412,7 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { SASSERT(ctx.get_assignment(lits[i]) == l_false); lits[i].neg(); } - set_conflict(0, lits); + set_conflict(nullptr, lits); return false; } @@ -4424,7 +4424,7 @@ bool theory_seq::add_accept2step(expr* acc, bool& change) { bool theory_seq::add_step2accept(expr* step, bool& change) { context& ctx = get_context(); SASSERT(ctx.get_assignment(step) == l_true); - expr* re = 0, *_acc = 0, *s = 0, *idx = 0, *i = 0, *j = 0; + expr* re = nullptr, *_acc = nullptr, *s = nullptr, *idx = nullptr, *i = nullptr, *j = nullptr; VERIFY(is_step(step, s, idx, re, i, j, _acc)); literal acc1 = mk_accept(s, idx, re, i); switch (ctx.get_assignment(acc1)) { @@ -4445,12 +4445,12 @@ bool theory_seq::add_step2accept(expr* step, bool& change) { lits.push_back(~acc2); switch (ctx.get_assignment(acc2)) { case l_undef: - propagate_lit(0, 2, lits.c_ptr(), acc2); + propagate_lit(nullptr, 2, lits.c_ptr(), acc2); break; case l_true: break; case l_false: - set_conflict(0, lits); + set_conflict(nullptr, lits); break; } break; @@ -4473,10 +4473,10 @@ Recall we also have: bool theory_seq::add_reject2reject(expr* rej, bool& change) { context& ctx = get_context(); SASSERT(ctx.get_assignment(rej) == l_true); - expr* s = 0, *idx = 0, *re = 0; + expr* s = nullptr, *idx = nullptr, *re = nullptr; unsigned src; rational r; - eautomaton* aut = 0; + eautomaton* aut = nullptr; VERIFY(is_reject(rej, s, idx, re, src, aut)); if (!aut || m_util.str.is_length(idx)) return false; VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); @@ -4535,7 +4535,7 @@ bool theory_seq::add_reject2reject(expr* rej, bool& change) { void theory_seq::propagate_not_prefix(expr* e) { context& ctx = get_context(); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; VERIFY(m_util.str.is_prefix(e, e1, e2)); literal lit = ctx.get_literal(e); SASSERT(ctx.get_assignment(lit) == l_false); @@ -4545,13 +4545,13 @@ void theory_seq::propagate_not_prefix(expr* e) { propagate_non_empty(~lit, e1); expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); literal e2_is_emp = mk_seq_eq(e2, emp); - sort* char_sort = 0; + sort* char_sort = nullptr; VERIFY(m_util.is_seq(m.get_sort(e1), char_sort)); expr_ref x = mk_skolem(symbol("seq.prefix.x"), e1, e2); expr_ref y = mk_skolem(symbol("seq.prefix.y"), e1, e2); expr_ref z = mk_skolem(symbol("seq.prefix.z"), e1, e2); - expr_ref c = mk_skolem(symbol("seq.prefix.c"), e1, e2, 0, char_sort); - expr_ref d = mk_skolem(symbol("seq.prefix.d"), e1, e2, 0, char_sort); + expr_ref c = mk_skolem(symbol("seq.prefix.c"), e1, e2, nullptr, char_sort); + expr_ref d = mk_skolem(symbol("seq.prefix.d"), e1, e2, nullptr, char_sort); add_axiom(lit, e2_is_emp, mk_seq_eq(e1, mk_concat(x, m_util.str.mk_unit(c), y))); add_axiom(lit, e2_is_emp, mk_seq_eq(e2, mk_concat(x, m_util.str.mk_unit(d), z)), mk_seq_eq(e2, x)); add_axiom(lit, e2_is_emp, ~mk_eq(c, d, false), mk_seq_eq(e2, x)); @@ -4564,7 +4564,7 @@ void theory_seq::propagate_not_prefix(expr* e) { void theory_seq::propagate_not_prefix2(expr* e) { context& ctx = get_context(); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; VERIFY(m_util.str.is_prefix(e, e1, e2)); literal lit = ctx.get_literal(e); SASSERT(ctx.get_assignment(lit) == l_false); @@ -4591,7 +4591,7 @@ void theory_seq::propagate_not_prefix2(expr* e) { void theory_seq::propagate_not_suffix(expr* e) { context& ctx = get_context(); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; VERIFY(m_util.str.is_suffix(e, e1, e2)); literal lit = ctx.get_literal(e); SASSERT(ctx.get_assignment(lit) == l_false); @@ -4602,13 +4602,13 @@ void theory_seq::propagate_not_suffix(expr* e) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); literal e2_is_emp = mk_seq_eq(e2, emp); - sort* char_sort = 0; + sort* char_sort = nullptr; VERIFY(m_util.is_seq(m.get_sort(e1), char_sort)); expr_ref x = mk_skolem(symbol("seq.suffix.x"), e1, e2); expr_ref y = mk_skolem(symbol("seq.suffix.y"), e1, e2); expr_ref z = mk_skolem(symbol("seq.suffix.z"), e1, e2); - expr_ref c = mk_skolem(symbol("seq.suffix.c"), e1, e2, 0, char_sort); - expr_ref d = mk_skolem(symbol("seq.suffix.d"), e1, e2, 0, char_sort); + expr_ref c = mk_skolem(symbol("seq.suffix.c"), e1, e2, nullptr, char_sort); + expr_ref d = mk_skolem(symbol("seq.suffix.d"), e1, e2, nullptr, char_sort); add_axiom(lit, e2_is_emp, mk_seq_eq(e1, mk_concat(y, m_util.str.mk_unit(c), x))); add_axiom(lit, e2_is_emp, mk_seq_eq(e2, mk_concat(z, m_util.str.mk_unit(d), x)), mk_seq_eq(e2, x)); add_axiom(lit, e2_is_emp, ~mk_eq(c, d, false), mk_seq_eq(e2, x)); @@ -4620,7 +4620,7 @@ void theory_seq::propagate_not_suffix(expr* e) { */ bool theory_seq::add_prefix2prefix(expr* e, bool& change) { context& ctx = get_context(); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; VERIFY(m_util.str.is_prefix(e, e1, e2)); SASSERT(ctx.get_assignment(e) == l_false); if (canonizes(false, e)) { @@ -4682,7 +4682,7 @@ bool theory_seq::add_prefix2prefix(expr* e, bool& change) { lits.push_back(~ctx.get_literal(e)); lits.push_back(~e2_is_emp); lits.push_back(lit); - propagate_lit(0, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_prefix(tail1, tail2))); + propagate_lit(nullptr, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_prefix(tail1, tail2))); TRACE("seq", tout << mk_pp(e, m) << " saturate: " << tail1 << " = " << tail2 << "\n";); return false; } @@ -4692,7 +4692,7 @@ bool theory_seq::add_prefix2prefix(expr* e, bool& change) { */ bool theory_seq::add_suffix2suffix(expr* e, bool& change) { context& ctx = get_context(); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; VERIFY(m_util.str.is_suffix(e, e1, e2)); SASSERT(ctx.get_assignment(e) == l_false); if (canonizes(false, e)) { @@ -4746,21 +4746,21 @@ bool theory_seq::add_suffix2suffix(expr* e, bool& change) { lits.push_back(~ctx.get_literal(e)); lits.push_back(~e2_is_emp); lits.push_back(last_eq); - propagate_lit(0, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_suffix(first1, first2))); + propagate_lit(nullptr, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_suffix(first1, first2))); TRACE("seq", tout << mk_pp(e, m) << " saturate\n";); return false; } bool theory_seq::canonizes(bool sign, expr* e) { context& ctx = get_context(); - dependency* deps = 0; + dependency* deps = nullptr; expr_ref cont = canonize(e, deps); TRACE("seq", tout << mk_pp(e, m) << " -> " << cont << "\n"; if (deps) display_deps(tout, deps);); if ((m.is_true(cont) && !sign) || (m.is_false(cont) && sign)) { TRACE("seq", display(tout); tout << ctx.get_assignment(ctx.get_literal(e)) << "\n";); - propagate_lit(deps, 0, 0, ctx.get_literal(e)); + propagate_lit(deps, 0, nullptr, ctx.get_literal(e)); return true; } if ((m.is_false(cont) && !sign) || @@ -4778,7 +4778,7 @@ bool theory_seq::canonizes(bool sign, expr* e) { bool theory_seq::add_contains2contains(expr* e, bool& change) { context& ctx = get_context(); - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; VERIFY(m_util.str.is_contains(e, e1, e2)); SASSERT(ctx.get_assignment(e) == l_false); if (canonizes(false, e)) { @@ -4803,7 +4803,7 @@ bool theory_seq::add_contains2contains(expr* e, bool& change) { propagate_eq(~e1_is_emp, e1, conc, true); literal lits[2] = { ~ctx.get_literal(e), ~e1_is_emp }; - propagate_lit(0, 2, lits, ~mk_literal(m_util.str.mk_contains(tail, e2))); + propagate_lit(nullptr, 2, lits, ~mk_literal(m_util.str.mk_contains(tail, e2))); return false; } @@ -4848,7 +4848,7 @@ bool theory_seq::propagate_automata() { } void theory_seq::get_concat(expr* e, ptr_vector& concats) { - expr* e1 = 0, *e2 = 0; + expr* e1 = nullptr, *e2 = nullptr; while (true) { e = m_rep.find(e); if (m_util.str.is_concat(e, e1, e2)) { diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 3cb1f1b4b..203dae633 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -37,7 +37,7 @@ namespace smt { enode* n1, *n2; literal lit; assumption(enode* n1, enode* n2): n1(n1), n2(n2), lit(null_literal) {} - assumption(literal lit): n1(0), n2(0), lit(lit) {} + assumption(literal lit): n1(nullptr), n2(nullptr), lit(lit) {} }; typedef scoped_dependency_manager dependency_manager; typedef dependency_manager::dependency dependency; @@ -434,7 +434,7 @@ namespace smt { // asserting consequences bool linearize(dependency* dep, enode_pair_vector& eqs, literal_vector& lits) const; - void propagate_lit(dependency* dep, literal lit) { propagate_lit(dep, 0, 0, lit); } + void propagate_lit(dependency* dep, literal lit) { propagate_lit(dep, 0, nullptr, lit); } void propagate_lit(dependency* dep, unsigned n, literal const* lits, literal lit); void propagate_eq(dependency* dep, enode* n1, enode* n2); void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs); @@ -531,7 +531,7 @@ namespace smt { bool get_length(expr* s, rational& val) const; void mk_decompose(expr* e, expr_ref& head, expr_ref& tail); - expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0); + expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = nullptr, expr* e3 = nullptr, sort* range = nullptr); bool is_skolem(symbol const& s, expr* e) const; void set_incomplete(app* term); diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index 647b54320..93b4be173 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -67,12 +67,12 @@ namespace smt { if (u.is_seq(s)) { return u.str.mk_empty(s); } - sort* seq = 0; + sort* seq = nullptr; if (u.is_re(s, seq)) { return u.re.mk_to_re(u.str.mk_empty(seq)); } UNREACHABLE(); - return 0; + return nullptr; } bool get_some_values(sort* s, expr_ref& v1, expr_ref& v2) override { if (u.is_string(s)) { @@ -105,7 +105,7 @@ namespace smt { return u.str.mk_string(sym); } } - sort* seq = 0, *ch = 0; + sort* seq = nullptr, *ch = nullptr; if (u.is_re(s, seq)) { expr* v0 = get_fresh_value(seq); return u.re.mk_to_re(v0); @@ -120,7 +120,7 @@ namespace smt { return u.str.mk_unit(v); } UNREACHABLE(); - return 0; + return nullptr; } void register_value(expr* n) override { symbol sym; @@ -150,7 +150,7 @@ namespace smt { bool m_used; final_check_status final_check_eh() override { return m_used?FC_GIVEUP:FC_DONE; } bool internalize_atom(app*, bool) override { if (!m_used) { get_context().push_trail(value_trail(m_used)); m_used = true; } return false; } - bool internalize_term(app*) override { return internalize_atom(0,false); } + bool internalize_term(app*) override { return internalize_atom(nullptr,false); } void new_eq_eh(theory_var, theory_var) override { } void new_diseq_eh(theory_var, theory_var) override {} theory* mk_fresh(context* new_ctx) override { return alloc(theory_seq_empty, new_ctx->get_manager()); } diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 56a54f964..c5058d00a 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -458,7 +458,7 @@ namespace smt { buffer << "!tmp"; buffer << m_fresh_id; m_fresh_id++; - return u.mk_skolem(symbol(buffer.c_str()), 0, 0, s); + return u.mk_skolem(symbol(buffer.c_str()), 0, nullptr, s); } @@ -617,7 +617,7 @@ namespace smt { ast_manager & m = get_manager(); expr * args[2] = {n, bound}; - app * unrollFunc = get_manager().mk_app(get_id(), _OP_RE_UNROLL, 0, 0, 2, args); + app * unrollFunc = get_manager().mk_app(get_id(), _OP_RE_UNROLL, 0, nullptr, 2, args); m_trail.push_back(unrollFunc); expr_ref_vector items(m); @@ -659,7 +659,7 @@ namespace smt { } else { if (false) { // use cache - app * lenTerm = NULL; + app * lenTerm = nullptr; if (!length_ast_map.find(e, lenTerm)) { lenTerm = u.str.mk_length(e); length_ast_map.insert(e, lenTerm); @@ -705,14 +705,14 @@ namespace smt { return n1; } } - return NULL; + return nullptr; } expr * theory_str::mk_concat(expr * n1, expr * n2) { context & ctx = get_context(); ast_manager & m = get_manager(); - ENSURE(n1 != NULL); - ENSURE(n2 != NULL); + ENSURE(n1 != nullptr); + ENSURE(n2 != nullptr); bool n1HasEqcValue = false; bool n2HasEqcValue = false; n1 = get_eqc_value(n1, n1HasEqcValue); @@ -770,7 +770,7 @@ namespace smt { // Z3 treats (ast1) and (ast2) as two different nodes. //------------------------------------------------------- - expr * concatAst = NULL; + expr * concatAst = nullptr; if (!concat_astNode_map.find(n1, n2, concatAst)) { concatAst = u.str.mk_concat(n1, n2); @@ -1424,9 +1424,9 @@ namespace smt { void theory_str::instantiate_axiom_Substr(enode * e) { context & ctx = get_context(); ast_manager & m = get_manager(); - expr* substrBase = 0; - expr* substrPos = 0; - expr* substrLen = 0; + expr* substrBase = nullptr; + expr* substrPos = nullptr; + expr* substrLen = nullptr; app * expr = e->get_owner(); if (axiomatized_terms.contains(expr)) { @@ -2001,7 +2001,7 @@ namespace smt { } } // give up - return NULL; + return nullptr; } // trace code helper @@ -2091,7 +2091,7 @@ namespace smt { // (Concat n_eqNode arg1) /\ arg1 has eq const expr * concatResult = eval_concat(eq_str, arg1); - if (concatResult != NULL) { + if (concatResult != nullptr) { bool arg1HasEqcValue = false; expr * arg1Value = get_eqc_value(arg1, arg1HasEqcValue); expr_ref implyL(m); @@ -2162,7 +2162,7 @@ namespace smt { // (Concat arg0 n_eqNode) /\ arg0 has eq const expr * concatResult = eval_concat(arg0, eq_str); - if (concatResult != NULL) { + if (concatResult != nullptr) { bool arg0HasEqcValue = false; expr * arg0Value = get_eqc_value(arg0, arg0HasEqcValue); expr_ref implyL(m); @@ -2846,8 +2846,8 @@ namespace smt { //************************************************************* if (is_concat_eq_type2(new_nn1, new_nn2)) { - expr * y = NULL; - expr * m = NULL; + expr * y = nullptr; + expr * m = nullptr; expr * v1_arg0 = to_app(new_nn1)->get_arg(0); expr * v1_arg1 = to_app(new_nn1)->get_arg(1); expr * v2_arg0 = to_app(new_nn2)->get_arg(0); @@ -2878,8 +2878,8 @@ namespace smt { expr * v2_arg0 = to_app(new_nn2)->get_arg(0); expr * v2_arg1 = to_app(new_nn2)->get_arg(1); - expr * x = NULL; - expr * n = NULL; + expr * x = nullptr; + expr * n = nullptr; if (u.str.is_string(v1_arg0) && !u.str.is_string(v2_arg0)) { n = v1_arg1; @@ -2920,8 +2920,8 @@ namespace smt { expr * v2_arg0 = to_app(new_nn2)->get_arg(0); expr * v2_arg1 = to_app(new_nn2)->get_arg(1); - expr * y = NULL; - expr * m = NULL; + expr * y = nullptr; + expr * m = nullptr; if (u.str.is_string(v1_arg0)) { y = v1_arg1; @@ -3020,9 +3020,9 @@ namespace smt { << "split type " << splitType << std::endl; ); - expr * t1 = NULL; - expr * t2 = NULL; - expr * xorFlag = NULL; + expr * t1 = nullptr; + expr * t2 = nullptr; + expr * xorFlag = nullptr; std::pair key1(concatAst1, concatAst2); std::pair key2(concatAst2, concatAst1); @@ -3390,10 +3390,10 @@ namespace smt { return; } - expr * x = NULL; - expr * y = NULL; - expr * strAst = NULL; - expr * m = NULL; + expr * x = nullptr; + expr * y = nullptr; + expr * strAst = nullptr; + expr * m = nullptr; expr * v1_arg0 = to_app(concatAst1)->get_arg(0); expr * v1_arg1 = to_app(concatAst1)->get_arg(1); @@ -3424,8 +3424,8 @@ namespace smt { // setup - expr * xorFlag = NULL; - expr * temp1 = NULL; + expr * xorFlag = nullptr; + expr * temp1 = nullptr; std::pair key1(concatAst1, concatAst2); std::pair key2(concatAst2, concatAst1); @@ -3758,10 +3758,10 @@ namespace smt { expr * v2_arg0 = to_app(concatAst2)->get_arg(0); expr * v2_arg1 = to_app(concatAst2)->get_arg(1); - expr * x = NULL; - expr * y = NULL; - expr * strAst = NULL; - expr * n = NULL; + expr * x = nullptr; + expr * y = nullptr; + expr * strAst = nullptr; + expr * n = nullptr; if (u.str.is_string(v1_arg0) && !u.str.is_string(v2_arg0)) { strAst = v1_arg0; @@ -4318,10 +4318,10 @@ namespace smt { expr * v2_arg1 = to_app(concatAst2)->get_arg(1); - expr * str1Ast = NULL; - expr * y = NULL; - expr * m = NULL; - expr * str2Ast = NULL; + expr * str1Ast = nullptr; + expr * y = nullptr; + expr * m = nullptr; + expr * str2Ast = nullptr; if (u.str.is_string(v1_arg0)) { str1Ast = v1_arg0; @@ -4362,8 +4362,8 @@ namespace smt { } //---------------------------------------------------------------- - expr * commonVar = NULL; - expr * xorFlag = NULL; + expr * commonVar = nullptr; + expr * xorFlag = nullptr; std::pair key1(concatAst1, concatAst2); std::pair key2(concatAst2, concatAst1); @@ -4674,7 +4674,7 @@ namespace smt { return dynamic_cast(th); } else { - return 0; + return nullptr; } } @@ -4846,7 +4846,7 @@ namespace smt { } expr * theory_str::collect_eq_nodes(expr * n, expr_ref_vector & eqcSet) { - expr * constStrNode = NULL; + expr * constStrNode = nullptr; expr * ex = n; do { @@ -4891,7 +4891,7 @@ namespace smt { expr * strAst = itor1->first; expr * substrAst = itor1->second; - expr * boolVar = NULL; + expr * boolVar = nullptr; if (!contain_pair_bool_map.find(strAst, substrAst, boolVar)) { TRACE("str", tout << "warning: no entry for boolVar in contain_pair_bool_map" << std::endl;); } @@ -5028,7 +5028,7 @@ namespace smt { expr * strAst = itor1->first; expr * substrAst = itor1->second; - expr * boolVar = NULL; + expr * boolVar = nullptr; if (!contain_pair_bool_map.find(strAst, substrAst, boolVar)) { TRACE("str", tout << "warning: no entry for boolVar in contain_pair_bool_map" << std::endl;); } @@ -5445,7 +5445,7 @@ namespace smt { expr_ref_vector willEqClass(m); expr * constStrAst_1 = collect_eq_nodes(n1, willEqClass); expr * constStrAst_2 = collect_eq_nodes(n2, willEqClass); - expr * constStrAst = (constStrAst_1 != NULL) ? constStrAst_1 : constStrAst_2; + expr * constStrAst = (constStrAst_1 != nullptr) ? constStrAst_1 : constStrAst_2; TRACE("str", tout << "eqc of n1 is {"; for (expr_ref_vector::iterator it = willEqClass.begin(); it != willEqClass.end(); ++it) { @@ -5461,7 +5461,7 @@ namespace smt { ); // step 1: we may have constant values for Contains checks now - if (constStrAst != NULL) { + if (constStrAst != nullptr) { expr_ref_vector::iterator itAst = willEqClass.begin(); for (; itAst != willEqClass.end(); itAst++) { if (*itAst == constStrAst) { @@ -6405,9 +6405,9 @@ namespace smt { expr * constStr_1 = collect_eq_nodes(nn1, eqNodeSet); expr * constStr_2 = collect_eq_nodes(nn2, eqNodeSet); - expr * constStr = (constStr_1 != NULL) ? constStr_1 : constStr_2; + expr * constStr = (constStr_1 != nullptr) ? constStr_1 : constStr_2; - if (constStr == NULL) { + if (constStr == nullptr) { return; } else { expr_ref_vector::iterator itor = eqNodeSet.begin(); @@ -6615,7 +6615,7 @@ namespace smt { } else { // Case 4: Concat(var, var) == const TRACE("str", tout << "Case 4: Concat(var, var) == const" << std::endl;); - if (eval_concat(arg1, arg2) == NULL) { + if (eval_concat(arg1, arg2) == nullptr) { rational arg1Len, arg2Len; bool arg1Len_exists = get_len_value(arg1, arg1Len); bool arg2Len_exists = get_len_value(arg2, arg2Len); @@ -6860,7 +6860,7 @@ namespace smt { } else { // start binary search as normal expr_ref implLhs(ctx.mk_eq_atom(testvar, str), m); - expr_ref implRhs(binary_search_length_test(v, NULL, ""), m); + expr_ref implRhs(binary_search_length_test(v, nullptr, ""), m); assert_implication(implLhs, implRhs); } } else { @@ -6992,14 +6992,14 @@ namespace smt { } expr * valueAssert = gen_free_var_options(fVar, effectiveLenInd, effectiveLenIndiStr, valTester, valTesterValue); TRACE("str", tout << "asserting more value tests for free variable " << mk_ismt2_pp(fVar, m) << std::endl;); - if (valueAssert != NULL) { + if (valueAssert != nullptr) { assert_axiom(valueAssert); } } } else { int lenTesterCount = fvar_lenTester_map[fVar].size(); - expr * effectiveLenInd = NULL; + expr * effectiveLenInd = nullptr; zstring effectiveLenIndiStr = ""; for (int i = 0; i < lenTesterCount; ++i) { expr * len_indicator_pre = fvar_lenTester_map[fVar][i]; @@ -7017,7 +7017,7 @@ namespace smt { } expr * valueAssert = gen_free_var_options(fVar, effectiveLenInd, effectiveLenIndiStr, valTester, valTesterValue); TRACE("str", tout << "asserting more value tests for free variable " << mk_ismt2_pp(fVar, m) << std::endl;); - if (valueAssert != NULL) { + if (valueAssert != nullptr) { assert_axiom(valueAssert); } } @@ -7262,20 +7262,20 @@ namespace smt { simplify_parent(lhs, nn2_value); } - expr * nn1EqConst = NULL; + expr * nn1EqConst = nullptr; std::set nn1EqUnrollFuncs; get_eqc_allUnroll(lhs, nn1EqConst, nn1EqUnrollFuncs); - expr * nn2EqConst = NULL; + expr * nn2EqConst = nullptr; std::set nn2EqUnrollFuncs; get_eqc_allUnroll(rhs, nn2EqConst, nn2EqUnrollFuncs); - if (nn2EqConst != NULL) { + if (nn2EqConst != nullptr) { for (std::set::iterator itor1 = nn1EqUnrollFuncs.begin(); itor1 != nn1EqUnrollFuncs.end(); itor1++) { process_unroll_eq_const_str(*itor1, nn2EqConst); } } - if (nn1EqConst != NULL) { + if (nn1EqConst != nullptr) { for (std::set::iterator itor2 = nn2EqUnrollFuncs.begin(); itor2 != nn2EqUnrollFuncs.end(); itor2++) { process_unroll_eq_const_str(*itor2, nn1EqConst); } @@ -7917,13 +7917,13 @@ namespace smt { if (aliasUnrollSet.find(unrollItor->first) != aliasUnrollSet.end()) { continue; } - expr * aRoot = NULL; + expr * aRoot = nullptr; enode * e_currEqc = ctx.get_enode(unrollItor->first); enode * e_curr = e_currEqc; do { app * curr = e_currEqc->get_owner(); if (u.re.is_unroll(curr)) { - if (aRoot == NULL) { + if (aRoot == nullptr) { aRoot = curr; } aliasUnrollSet[curr] = aRoot; @@ -7948,11 +7948,11 @@ namespace smt { if (aliasIndexMap.find(varItor->first) != aliasIndexMap.end()) { continue; } - expr * aRoot = NULL; + expr * aRoot = nullptr; expr * curr = varItor->first; do { if (variable_set.find(curr) != variable_set.end()) { - if (aRoot == NULL) { + if (aRoot == nullptr) { aRoot = curr; } else { aliasIndexMap[curr] = aRoot; @@ -8040,11 +8040,11 @@ namespace smt { if (concats_eq_index_map.find(concatItor->first) != concats_eq_index_map.end()) { continue; } - expr * aRoot = NULL; + expr * aRoot = nullptr; expr * curr = concatItor->first; do { if (u.str.is_concat(to_app(curr))) { - if (aRoot == NULL) { + if (aRoot == nullptr) { aRoot = curr; } else { concats_eq_index_map[curr] = aRoot; @@ -8056,7 +8056,7 @@ namespace smt { concatItor = concatMap.begin(); for(; concatItor != concatMap.end(); ++concatItor) { - expr * deAliasConcat = NULL; + expr * deAliasConcat = nullptr; if (concats_eq_index_map.find(concatItor->first) != concats_eq_index_map.end()) { deAliasConcat = concats_eq_index_map[concatItor->first]; } else { @@ -8194,15 +8194,15 @@ namespace smt { mostLeftNodes.clear(); mostRightNodes.clear(); - expr * mLConst = NULL; - expr * mRConst = NULL; + expr * mLConst = nullptr; + expr * mRConst = nullptr; for (std::map::iterator itor1 = itor->second.begin(); itor1 != itor->second.end(); itor1++) { expr * concatNode = itor1->first; expr * mLNode = getMostLeftNodeInConcat(concatNode); zstring strval; if (u.str.is_string(to_app(mLNode), strval)) { - if (mLConst == NULL && strval.empty()) { + if (mLConst == nullptr && strval.empty()) { mLConst = mLNode; } } else { @@ -8211,7 +8211,7 @@ namespace smt { expr * mRNode = getMostRightNodeInConcat(concatNode); if (u.str.is_string(to_app(mRNode), strval)) { - if (mRConst == NULL && strval.empty()) { + if (mRConst == nullptr && strval.empty()) { mRConst = mRNode; } } else { @@ -8219,7 +8219,7 @@ namespace smt { } } - if (mLConst != NULL) { + if (mLConst != nullptr) { // ------------------------------------------------------------------------------------- // The left most variable in a concat is constrained by a constant string in eqc concat // ------------------------------------------------------------------------------------- @@ -8273,7 +8273,7 @@ namespace smt { } } - if (mRConst != NULL) { + if (mRConst != nullptr) { for (std::map::iterator itor1 = mostRightNodes.begin(); itor1 != mostRightNodes.end(); itor1++) { expr * deVar = get_alias_index_ast(aliasIndexMap, itor1->first); @@ -8952,7 +8952,7 @@ namespace smt { // ----------------------------------------------------------- std::map > fv_unrolls_map; std::set tmpSet; - expr * constValue = NULL; + expr * constValue = nullptr; for (std::map::iterator fvIt2 = freeVar_map.begin(); fvIt2 != freeVar_map.end(); fvIt2++) { expr * var = fvIt2->first; tmpSet.clear(); @@ -9036,7 +9036,7 @@ namespace smt { // Assign free variables std::set fSimpUnroll; - constValue = NULL; + constValue = nullptr; { TRACE("str", tout << "free var map (#" << freeVar_map.size() << "):" << std::endl; @@ -9074,8 +9074,8 @@ namespace smt { continue; } */ - expr * toAssert = gen_len_val_options_for_free_var(freeVar, NULL, ""); - if (toAssert != NULL) { + expr * toAssert = gen_len_val_options_for_free_var(freeVar, nullptr, ""); + if (toAssert != nullptr) { assert_axiom(toAssert); } } @@ -9095,7 +9095,7 @@ namespace smt { gen_assign_unroll_reg(fv_unrolls_map[var]); } else { expr * toAssert = gen_assign_unroll_Str2Reg(var, fSimpUnroll); - if (toAssert != NULL) { + if (toAssert != nullptr) { assert_axiom(toAssert); } } @@ -9381,7 +9381,7 @@ namespace smt { } if (valTesterValueStr == "more") { - expr * valTester = NULL; + expr * valTester = nullptr; if (i + 1 < testerTotal) { valTester = fvar_valueTester_map[freeVar][len][i + 1].second; refresh_theory_var(valTester); @@ -9394,7 +9394,7 @@ namespace smt { return gen_val_options(freeVar, len_indicator, valTester, len_valueStr, i + 1); } - return NULL; + return nullptr; } } @@ -9627,14 +9627,14 @@ namespace smt { int lcm = 1; int coreValueCount = 0; - expr * oneUnroll = NULL; + expr * oneUnroll = nullptr; zstring oneCoreStr(""); for (std::set::iterator itor = unrolls.begin(); itor != unrolls.end(); itor++) { expr * str2RegFunc = to_app(*itor)->get_arg(0); expr * coreVal = to_app(str2RegFunc)->get_arg(0); zstring coreStr; u.str.is_string(coreVal, coreStr); - if (oneUnroll == NULL) { + if (oneUnroll == nullptr) { oneUnroll = *itor; oneCoreStr = coreStr; } @@ -10060,7 +10060,7 @@ namespace smt { TRACE("str", tout << "invoked with previousLenTester info matching top of stack" << std::endl;); } else { TRACE("str", tout << "WARNING: unexpected reordering of length testers!" << std::endl;); - UNREACHABLE(); return NULL; + UNREACHABLE(); return nullptr; } } else { u.str.is_string(lastTesterValue, lastTesterConstant); @@ -10076,7 +10076,7 @@ namespace smt { } TRACE("str", tout << "last bounds are [" << lastBounds.lowerBound << " | " << lastBounds.midPoint << " | " << lastBounds.upperBound << "]!" << lastBounds.windowSize << std::endl;); binary_search_info newBounds; - expr * newTester = 0; + expr * newTester = nullptr; if (lastTesterConstant == "more") { // special case: if the midpoint, upper bound, and window size are all equal, // we double the window size and adjust the bounds @@ -10144,7 +10144,7 @@ namespace smt { return axiom; } // length is fixed - expr * valueAssert = gen_free_var_options(freeVar, lastTester, lastTesterConstant, NULL, zstring("")); + expr * valueAssert = gen_free_var_options(freeVar, lastTester, lastTesterConstant, nullptr, zstring("")); return valueAssert; } } else { @@ -10254,7 +10254,7 @@ namespace smt { } else { TRACE("str", tout << "found previous in-scope length assertions" << std::endl;); - expr * effectiveLenInd = NULL; + expr * effectiveLenInd = nullptr; zstring effectiveLenIndiStr(""); int lenTesterCount = (int) fvar_lenTester_map[freeVar].size(); @@ -10355,7 +10355,7 @@ namespace smt { } else { TRACE("str", tout << "length is fixed; generating models for free var" << std::endl;); // length is fixed - expr * valueAssert = gen_free_var_options(freeVar, effectiveLenInd, effectiveLenIndiStr, NULL, zstring("")); + expr * valueAssert = gen_free_var_options(freeVar, effectiveLenInd, effectiveLenIndiStr, nullptr, zstring("")); return valueAssert; } } // fVarLenCountMap.find(...) @@ -10409,7 +10409,7 @@ namespace smt { std::set eqVarSet; get_var_in_eqc(freeVar, eqVarSet); bool duplicated = false; - expr * dupVar = NULL; + expr * dupVar = nullptr; for (std::set::iterator itorEqv = eqVarSet.begin(); itorEqv != eqVarSet.end(); itorEqv++) { if (eqcRepSet.find(*itorEqv) != eqcRepSet.end()) { duplicated = true; @@ -10417,7 +10417,7 @@ namespace smt { break; } } - if (duplicated && dupVar != NULL) { + if (duplicated && dupVar != nullptr) { TRACE("str", tout << "Duplicated free variable found:" << mk_pp(freeVar, get_manager()) << " = " << mk_ismt2_pp(dupVar, get_manager()) << " (SKIP)" << std::endl;); continue; @@ -10465,10 +10465,10 @@ namespace smt { for(std::set::iterator itor1 = leafVarSet.begin(); itor1 != leafVarSet.end(); ++itor1) { - expr * toAssert = gen_len_val_options_for_free_var(*itor1, NULL, ""); + expr * toAssert = gen_len_val_options_for_free_var(*itor1, nullptr, ""); // gen_len_val_options_for_free_var() can legally return NULL, // as methods that it calls may assert their own axioms instead. - if (toAssert != NULL) { + if (toAssert != nullptr) { assert_axiom(toAssert); } } @@ -10477,9 +10477,9 @@ namespace smt { mItor != aloneVars.end(); ++mItor) { std::set::iterator itor2 = mItor->second.begin(); for(; itor2 != mItor->second.end(); ++itor2) { - expr * toAssert = gen_len_val_options_for_free_var(*itor2, NULL, ""); + expr * toAssert = gen_len_val_options_for_free_var(*itor2, nullptr, ""); // same deal with returning a NULL axiom here - if(toAssert != NULL) { + if(toAssert != nullptr) { assert_axiom(toAssert); } } @@ -10491,7 +10491,7 @@ namespace smt { * and constant string in eqc of node n */ void theory_str::get_eqc_allUnroll(expr * n, expr * &constStr, std::set & unrollFuncSet) { - constStr = NULL; + constStr = nullptr; unrollFuncSet.clear(); expr * curr = n; @@ -10509,7 +10509,7 @@ namespace smt { // Collect simple Unroll functions (whose core is Str2Reg) and constant strings in the EQC of n. void theory_str::get_eqc_simpleUnroll(expr * n, expr * &constStr, std::set & unrollFuncSet) { - constStr = NULL; + constStr = nullptr; unrollFuncSet.clear(); expr * curr = n; @@ -10556,7 +10556,7 @@ namespace smt { app * a0_conststr = mk_value_helper(to_app(a0)); app * a1_conststr = mk_value_helper(to_app(a1)); - if (a0_conststr != NULL && a1_conststr != NULL) { + if (a0_conststr != nullptr && a1_conststr != nullptr) { zstring a0_s, a1_s; u.str.is_string(a0_conststr, a0_s); u.str.is_string(a1_conststr, a1_s); @@ -10571,7 +10571,7 @@ namespace smt { if (hasEqc) { return to_app(n_eqc); } else { - return NULL; + return nullptr; } } @@ -10586,7 +10586,7 @@ namespace smt { SASSERT(get_context().e_internalized(owner)); app * val = mk_value_helper(owner); - if (val != NULL) { + if (val != nullptr) { return alloc(expr_wrapper_proc, val); } else { TRACE("str", tout << "WARNING: failed to find a concrete value, falling back" << std::endl;); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 52d06efd1..3b71a2282 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -66,13 +66,13 @@ public: return u.str.mk_string(sym); } } - sort* seq = 0; + sort* seq = nullptr; if (u.is_re(s, seq)) { expr* v0 = get_fresh_value(seq); return u.re.mk_to_re(v0); } TRACE("t_str", tout << "unexpected sort in get_fresh_value(): " << mk_pp(s, m_manager) << std::endl;); - UNREACHABLE(); return NULL; + UNREACHABLE(); return nullptr; } void register_value(expr * n) override { /* Ignore */ } }; @@ -87,7 +87,7 @@ public: return value; } else { TRACE("t_str", tout << "WARNING: lookup miss in contain_pair_bool_map!" << std::endl;); - return NULL; + return nullptr; } } diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index ca4f4737e..64aa9f2c5 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -242,7 +242,7 @@ namespace smt { justification * why_is_diseq(th_var v1, th_var v2) override { UNREACHABLE(); - return 0; + return nullptr; } void reset_eh() override; diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 7c1edb585..b051c504a 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -70,7 +70,7 @@ namespace smt { m_lra(false), m_non_utvpi_exprs(false), m_test(m), - m_factory(0) { + m_factory(nullptr) { } template @@ -106,7 +106,7 @@ namespace smt { template theory_var theory_utvpi::mk_var(expr* n) { context & ctx = get_context(); - enode* e = 0; + enode* e = nullptr; th_var v = null_theory_var; m_lia |= a.is_int(n); m_lra |= a.is_real(n); @@ -239,7 +239,7 @@ namespace smt { ctx.mk_justification( ext_theory_conflict_justification( get_id(), ctx.get_region(), - lits.size(), lits.c_ptr(), 0, 0, params.size(), params.c_ptr()))); + lits.size(), lits.c_ptr(), 0, nullptr, params.size(), params.c_ptr()))); m_nc_functor.reset(); } diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 88ba89610..53116cb60 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -287,7 +287,7 @@ namespace smt { ctx.set_conflict( ctx.mk_justification( - ext_theory_conflict_justification(get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), 0, 0, 0, 0))); + ext_theory_conflict_justification(get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), 0, nullptr, 0, nullptr))); } bool theory_wmaxsat::max_unassigned_is_blocked() { @@ -337,7 +337,7 @@ namespace smt { region& r = ctx.get_region(); ctx.assign(lit, ctx.mk_justification( ext_theory_propagation_justification( - get_id(), r, lits.size(), lits.c_ptr(), 0, 0, lit, 0, 0))); + get_id(), r, lits.size(), lits.c_ptr(), 0, nullptr, lit, 0, nullptr))); } diff --git a/src/smt/theory_wmaxsat.h b/src/smt/theory_wmaxsat.h index 16dab488b..f2266a36f 100644 --- a/src/smt/theory_wmaxsat.h +++ b/src/smt/theory_wmaxsat.h @@ -96,7 +96,7 @@ namespace smt { } void reset_local(); void reset_eh() override; - theory * mk_fresh(context * new_ctx) override { return 0; } + theory * mk_fresh(context * new_ctx) override { return nullptr; } bool internalize_atom(app * atom, bool gate_ctx) override { return false; } bool internalize_term(app * term) override { return false; } void new_eq_eh(theory_var v1, theory_var v2) override { } diff --git a/src/smt/watch_list.cpp b/src/smt/watch_list.cpp index edd6923d7..9835142f6 100644 --- a/src/smt/watch_list.cpp +++ b/src/smt/watch_list.cpp @@ -35,7 +35,7 @@ namespace smt { } void watch_list::expand() { - if (m_data == 0) { + if (m_data == nullptr) { unsigned size = DEFAULT_WATCH_LIST_SIZE + HEADER_SIZE; unsigned * mem = reinterpret_cast(alloc_svect(char, size)); #ifdef _AMD64_ diff --git a/src/smt/watch_list.h b/src/smt/watch_list.h index 1cc29da5a..6d7a509d5 100644 --- a/src/smt/watch_list.h +++ b/src/smt/watch_list.h @@ -83,10 +83,10 @@ namespace smt { public: watch_list(): - m_data(0) { + m_data(nullptr) { } - watch_list(watch_list && other) : m_data(0) { + watch_list(watch_list && other) : m_data(nullptr) { std::swap(m_data, other.m_data); } @@ -115,7 +115,7 @@ namespace smt { void reset_and_release_memory() { destroy(); - m_data = 0; + m_data = nullptr; } clause_iterator begin_clause() { @@ -155,7 +155,7 @@ namespace smt { } void insert_clause(clause * c) { - if (m_data == 0 || end_cls_core() + sizeof(clause *) >= begin_lits_core()) { + if (m_data == nullptr || end_cls_core() + sizeof(clause *) >= begin_lits_core()) { expand(); } *(reinterpret_cast(m_data + end_cls_core())) = c; @@ -163,7 +163,7 @@ namespace smt { } void insert_literal(literal const & l) { - if (m_data == 0 || begin_lits_core() <= end_cls_core() + sizeof(literal)) { + if (m_data == nullptr || begin_lits_core() <= end_cls_core() + sizeof(literal)) { expand(); } SASSERT(begin_lits_core() >= sizeof(literal)); diff --git a/src/solver/check_sat_result.cpp b/src/solver/check_sat_result.cpp index f1bedfc08..e7c15964e 100644 --- a/src/solver/check_sat_result.cpp +++ b/src/solver/check_sat_result.cpp @@ -57,11 +57,11 @@ void simple_check_sat_result::get_model(model_ref & m) { if (m_status != l_false) m = m_model; else - m = 0; + m = nullptr; } proof * simple_check_sat_result::get_proof() { - return m_status == l_false ? m_proof.get() : 0; + return m_status == l_false ? m_proof.get() : nullptr; } std::string simple_check_sat_result::reason_unknown() const { diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index 7eb692567..e4ebd7e3b 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -136,7 +136,7 @@ struct mus::imp { // use correction sets lbool get_mus2(expr_ref_vector& mus) { - expr* lit = 0; + expr* lit = nullptr; lbool is_sat; ptr_vector unknown(m_lit2expr.size(), m_lit2expr.c_ptr()); while (!unknown.empty()) { @@ -163,7 +163,7 @@ struct mus::imp { expr_ref_vector nmcs(m); expr_set core, min_core, nmcs_set; bool min_core_valid = false; - expr* min_lit = 0; + expr* min_lit = nullptr; while (!unknown.empty()) { expr* lit = unknown.back(); unknown.pop_back(); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index bf53cb669..d49b3620f 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -31,7 +31,7 @@ unsigned solver::get_num_assertions() const { expr * solver::get_assertion(unsigned idx) const { NOT_IMPLEMENTED_YET(); - return 0; + return nullptr; } std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assumptions) const { @@ -156,7 +156,7 @@ lbool solver::find_mutexes(expr_ref_vector const& vars, vector& } lbool solver::preferred_sat(expr_ref_vector const& asms, vector& cores) { - return check_sat(0, 0); + return check_sat(0, nullptr); } bool solver::is_literal(ast_manager& m, expr* e) { diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 3bc66e3b4..8bb3fdf78 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -34,7 +34,7 @@ void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clause for (unsigned i = 0; i < sz; i++) { expr * f = g->form(i); expr_dependency * d = g->dep(i); - if (d == 0 || !g->unsat_core_enabled()) { + if (d == nullptr || !g->unsat_core_enabled()) { clauses.push_back(f); } else { @@ -58,9 +58,9 @@ void extract_clauses_and_dependencies(goal_ref const& g, expr_ref_vector& clause } else { // must normalize assumption - expr * b = 0; + expr * b = nullptr; if (!dep2bool.find(d, b)) { - b = m.mk_fresh_const(0, m.mk_bool_sort()); + b = m.mk_fresh_const(nullptr, m.mk_bool_sort()); dep2bool.insert(d, b); bool2dep.insert(b, d); assumptions.push_back(b); @@ -106,7 +106,7 @@ public: /* out */ model_converter_ref & mc, /* out */ proof_converter_ref & pc, /* out */ expr_dependency_ref & core) override { - pc = 0; mc = 0; core = 0; + pc = nullptr; mc = nullptr; core = nullptr; expr_ref_vector clauses(m); expr2expr_map bool2dep; ptr_vector assumptions; @@ -128,8 +128,8 @@ public: break; case l_false: { in->reset(); - proof* pr = 0; - expr_dependency* lcore = 0; + proof* pr = nullptr; + expr_dependency* lcore = nullptr; if (in->proofs_enabled()) { pr = local_solver->get_proof(); pc = proof2proof_converter(m, pr); diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 2628380c5..402edc19a 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -31,7 +31,7 @@ solver_na2as::solver_na2as(ast_manager & m): solver_na2as::~solver_na2as() {} void solver_na2as::assert_expr(expr * t, expr * a) { - if (a == 0) { + if (a == nullptr) { assert_expr(t); } else { diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 9dc4fe43d..5c3c6bc7a 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -105,12 +105,12 @@ void tactic2solver::collect_param_descrs(param_descrs & r) { void tactic2solver::assert_expr(expr * t) { m_assertions.push_back(t); - m_result = 0; + m_result = nullptr; } void tactic2solver::push_core() { m_scopes.push_back(m_assertions.size()); - m_result = 0; + m_result = nullptr; } void tactic2solver::pop_core(unsigned n) { @@ -118,11 +118,11 @@ void tactic2solver::pop_core(unsigned n) { unsigned old_sz = m_scopes[new_lvl]; m_assertions.shrink(old_sz); m_scopes.shrink(new_lvl); - m_result = 0; + m_result = nullptr; } lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * assumptions) { - if (m_tactic.get() == 0) + if (m_tactic.get() == nullptr) return l_false; ast_manager & m = m_assertions.m(); m_result = alloc(simple_check_sat_result, m); @@ -187,7 +187,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass solver* tactic2solver::translate(ast_manager& m, params_ref const& p) { tactic* t = m_tactic->translate(m); tactic2solver* r = alloc(tactic2solver, m, t, p, m_produce_proofs, m_produce_models, m_produce_unsat_cores, m_logic); - r->m_result = 0; + r->m_result = nullptr; if (!m_scopes.empty()) { throw default_exception("translation of contexts is only supported at base level"); } @@ -220,7 +220,7 @@ proof * tactic2solver::get_proof() { if (m_result.get()) return m_result->get_proof(); else - return 0; + return nullptr; } std::string tactic2solver::reason_unknown() const { diff --git a/src/solver/tactic2solver.h b/src/solver/tactic2solver.h index 2da0f69eb..ddab66dc5 100644 --- a/src/solver/tactic2solver.h +++ b/src/solver/tactic2solver.h @@ -30,7 +30,7 @@ class solver; class solver_factory; solver * mk_tactic2solver(ast_manager & m, - tactic * t = 0, + tactic * t = nullptr, params_ref const & p = params_ref(), bool produce_proofs = false, bool produce_models = true, diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index e8226e159..40c68f72a 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -30,13 +30,13 @@ class aig_lit { friend class aig_ref; aig * m_ref; public: - aig_lit(aig * n = 0):m_ref(n) {} + aig_lit(aig * n = nullptr):m_ref(n) {} aig_lit(aig_ref const & r):m_ref(static_cast(r.m_ref)) {} bool is_inverted() const { return (reinterpret_cast(m_ref) & static_cast(1)) == static_cast(1); } void invert() { m_ref = reinterpret_cast(reinterpret_cast(m_ref) ^ static_cast(1)); } aig * ptr() const { return reinterpret_cast(reinterpret_cast(m_ref) & ~static_cast(1)); } aig * ptr_non_inverted() const { SASSERT(!is_inverted()); return m_ref; } - bool is_null() const { return m_ref == 0; } + bool is_null() const { return m_ref == nullptr; } friend bool operator==(aig_lit const & r1, aig_lit const & r2) { return r1.m_ref == r2.m_ref; } friend bool operator!=(aig_lit const & r1, aig_lit const & r2) { return r1.m_ref != r2.m_ref; } aig_lit & operator=(aig_lit const & r) { m_ref = r.m_ref; return *this; } @@ -151,7 +151,7 @@ struct aig_manager::imp { m_num_aigs--; if (is_var(n)) { m_var_id_gen.recycle(n->m_id); - m_var2exprs.set(n->m_id, 0); + m_var2exprs.set(n->m_id, nullptr); } else { m_table.erase(n); @@ -797,7 +797,7 @@ struct aig_manager::imp { m_cache.resize(idx+1); return false; } - return m_cache.get(idx) != 0; + return m_cache.get(idx) != nullptr; } void cache_result(aig * n, expr * t) { @@ -960,14 +960,14 @@ struct aig_manager::imp { } unsigned idx = to_idx(t); cache.reserve(idx+1); - if (cache.get(idx) != 0) { + if (cache.get(idx) != nullptr) { todo.pop_back(); continue; } bool ok = true; for (unsigned i = 0; i < 2; i++) { aig * c = t->m_children[i].ptr(); - if (!is_var(c) && cache.get(to_idx(c), 0) == 0) { + if (!is_var(c) && cache.get(to_idx(c), nullptr) == nullptr) { todo.push_back(c); ok = false; } @@ -981,7 +981,7 @@ struct aig_manager::imp { if (is_var(c)) args[i] = m.m_var2exprs.get(c->m_id); else - args[i] = cache.get(to_idx(c), 0); + args[i] = cache.get(to_idx(c), nullptr); if (!l.is_inverted()) args[i] = invert(args[i]); } @@ -1009,16 +1009,16 @@ struct aig_manager::imp { aig_lit n = roots.back(); roots.pop_back(); if (n.is_inverted()) { - g.assert_expr(invert(process_root(n.ptr())), 0, 0); + g.assert_expr(invert(process_root(n.ptr())), nullptr, nullptr); continue; } aig * p = n.ptr(); if (m.is_ite(p)) { - g.assert_expr(process_root(p), 0, 0); + g.assert_expr(process_root(p), nullptr, nullptr); continue; } if (is_var(p)) { - g.assert_expr(m.var2expr(p), 0, 0); + g.assert_expr(m.var2expr(p), nullptr, nullptr); continue; } roots.push_back(left(p)); @@ -1081,7 +1081,7 @@ struct aig_manager::imp { bool visit(aig * p) { if (is_var(p)) { - push_result(0); + push_result(nullptr); return true; } if (is_cached(p)) @@ -1654,8 +1654,8 @@ public: aig_ref::aig_ref(): - m_manager(0), - m_ref(0) { + m_manager(nullptr), + m_ref(nullptr) { } aig_ref::aig_ref(aig_manager & m, aig_lit const & l): @@ -1665,15 +1665,15 @@ aig_ref::aig_ref(aig_manager & m, aig_lit const & l): } aig_ref::~aig_ref() { - if (m_ref != 0) { + if (m_ref != nullptr) { m_manager->m_imp->dec_ref(aig_lit(*this)); } } aig_ref & aig_ref::operator=(aig_ref const & r) { - if (r.m_ref != 0) + if (r.m_ref != nullptr) r.m_manager->m_imp->inc_ref(aig_lit(r)); - if (m_ref != 0) + if (m_ref != nullptr) m_manager->m_imp->dec_ref(aig_lit(*this)); m_ref = r.m_ref; m_manager = r.m_manager; diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index b6b5021a1..391d4b412 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -37,12 +37,12 @@ class aig_tactic : public tactic { ~mk_aig_manager() { dealloc(m_owner.m_aig_manager); - m_owner.m_aig_manager = 0; + m_owner.m_aig_manager = nullptr; } }; public: - aig_tactic(params_ref const & p = params_ref()):m_aig_manager(0) { + aig_tactic(params_ref const & p = params_ref()):m_aig_manager(nullptr) { updt_params(p); } @@ -77,7 +77,7 @@ public: expr_ref new_f(g->m()); m_aig_manager->to_formula(r, new_f); expr_dependency * ed = g->dep(i); - g->update(i, new_f, 0, ed); + g->update(i, new_f, nullptr, ed); } } else { @@ -96,7 +96,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { fail_if_proof_generation("aig", g); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; operator()(g); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index e71542532..5d64fff95 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -115,7 +115,7 @@ class add_bounds_tactic : public tactic { model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("add-bounds", *g); bound_manager bm(m); expr_fast_mark1 visited; diff --git a/src/tactic/arith/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp index 31e5d4fdc..bf5381a5b 100644 --- a/src/tactic/arith/arith_bounds_tactic.cpp +++ b/src/tactic/arith/arith_bounds_tactic.cpp @@ -50,7 +50,7 @@ struct arith_bounds_tactic : public tactic { void mk_proof(proof_ref& pr, goal_ref const& s, unsigned i, unsigned j) { if (s->proofs_enabled()) { - proof* th_lemma = m.mk_th_lemma(a.get_family_id(), m.mk_implies(s->form(i), s->form(j)), 0, 0); + proof* th_lemma = m.mk_th_lemma(a.get_family_id(), m.mk_implies(s->form(i), s->form(j)), 0, nullptr); pr = m.mk_modus_ponens(s->pr(i), th_lemma); } } diff --git a/src/tactic/arith/bound_manager.cpp b/src/tactic/arith/bound_manager.cpp index da507ea10..045d49f5b 100644 --- a/src/tactic/arith/bound_manager.cpp +++ b/src/tactic/arith/bound_manager.cpp @@ -201,22 +201,22 @@ bool bound_manager::is_disjunctive_bound(expr * f, expr_dependency * d) { if (!m().is_or(f)) return false; unsigned sz = to_app(f)->get_num_args(); if (sz == 0) return false; - expr * x, * y, * v = 0; + expr * x, * y, * v = nullptr; bool is_int; for (unsigned i = 0; i < sz; ++i) { expr * e = to_app(f)->get_arg(i); if (!m().is_eq(e, x, y)) return false; if (is_uninterp_const(x) && is_numeral(y, n, is_int) && is_int && - (x == v || v == 0)) { - if (v == 0) { v = x; lo = hi = n; } + (x == v || v == nullptr)) { + if (v == nullptr) { v = x; lo = hi = n; } if (n < lo) lo = n; if (n > hi) hi = n; } else if (is_uninterp_const(y) && is_numeral(x, n, is_int) && is_int && - (y == v || v == 0)) { - if (v == 0) { v = y; lo = hi = n; } + (y == v || v == nullptr)) { + if (v == nullptr) { v = y; lo = hi = n; } if (n < lo) lo = n; if (n > hi) hi = n; } diff --git a/src/tactic/arith/bound_manager.h b/src/tactic/arith/bound_manager.h index a08a53614..54a80ce5d 100644 --- a/src/tactic/arith/bound_manager.h +++ b/src/tactic/arith/bound_manager.h @@ -50,7 +50,7 @@ public: ast_manager & m() const { return m_util.get_manager(); } void operator()(goal const & g); - void operator()(expr * n, expr_dependency * d = 0); + void operator()(expr * n, expr_dependency * d = nullptr); bool has_lower(expr * c, numeral & v, bool & strict) const { limit l; @@ -76,14 +76,14 @@ public: expr_dependency * d; if (m_lower_deps.find(c, d)) return d; - return 0; + return nullptr; } expr_dependency * upper_dep(expr * c) const { expr_dependency * d; if (m_upper_deps.find(c, d)) return d; - return 0; + return nullptr; } bool has_lower(expr * c) const { diff --git a/src/tactic/arith/bound_propagator.cpp b/src/tactic/arith/bound_propagator.cpp index 51499674b..4ddfe9721 100644 --- a/src/tactic/arith/bound_propagator.cpp +++ b/src/tactic/arith/bound_propagator.cpp @@ -182,7 +182,7 @@ void bound_propagator::mk_eq(unsigned sz, mpz * as, var * xs) { } void bound_propagator::init_eq(linear_equation * eq) { - if (eq == 0) + if (eq == nullptr) return; unsigned c_idx = m_constraints.size(); m_constraints.push_back(constraint()); @@ -383,7 +383,7 @@ bool bound_propagator::relevant_bound(var x, double new_k) const { if (LOWER && has_lower(x)) tout << "old: " << m.to_string(m_lowers[x]->m_k) << " | " << m_lowers[x]->m_approx_k << "\n"; if (!LOWER && has_upper(x)) tout << "old: " << m.to_string(m_uppers[x]->m_k) << " | " << m_uppers[x]->m_approx_k << "\n";); bound * b = LOWER ? m_lowers[x] : m_uppers[x]; - if (b == 0) + if (b == nullptr) return true; // variable did not have a bound double interval_size; @@ -537,7 +537,7 @@ bool bound_propagator::propagate_eq(unsigned c_idx) { bound * u_i = m_uppers[x_i]; if (a_i < 0.0) { if (!ll_failed) { - if (l_i == 0) { + if (l_i == nullptr) { if (ll_i == UINT_MAX) ll_i = i; else @@ -549,7 +549,7 @@ bool bound_propagator::propagate_eq(unsigned c_idx) { } if (!uu_failed) { - if (u_i == 0) { + if (u_i == nullptr) { if (uu_i == UINT_MAX) uu_i = i; else @@ -562,7 +562,7 @@ bool bound_propagator::propagate_eq(unsigned c_idx) { } else { if (!ll_failed) { - if (u_i == 0) { + if (u_i == nullptr) { if (ll_i == UINT_MAX) ll_i = i; else @@ -574,7 +574,7 @@ bool bound_propagator::propagate_eq(unsigned c_idx) { } if (!uu_failed) { - if (l_i == 0) { + if (l_i == nullptr) { if (uu_i == UINT_MAX) uu_i = i; else @@ -780,7 +780,7 @@ bool bound_propagator::upper(var x, mpq & k, bool & strict, unsigned & ts) const bound_propagator::bound * bound_propagator::bound::at(unsigned timestamp) { bound * r = this; - while (r != 0 && r->m_timestamp >= timestamp) + while (r != nullptr && r->m_timestamp >= timestamp) r = r->m_prev; return r; } diff --git a/src/tactic/arith/bv2int_rewriter.cpp b/src/tactic/arith/bv2int_rewriter.cpp index 4315b0f5f..c4c13e316 100644 --- a/src/tactic/arith/bv2int_rewriter.cpp +++ b/src/tactic/arith/bv2int_rewriter.cpp @@ -38,7 +38,7 @@ void bv2int_rewriter_ctx::collect_power2(goal const& s) { expr* f = s.form(j); if (!m.is_or(f)) continue; unsigned sz = to_app(f)->get_num_args(); - expr* x, *y, *v = 0; + expr* x, *y, *v = nullptr; rational n; vector bounds; bool is_int, ok = true; @@ -50,12 +50,12 @@ void bv2int_rewriter_ctx::collect_power2(goal const& s) { break; } if (arith.is_numeral(y, n, is_int) && is_int && - (x == v || v == 0)) { + (x == v || v == nullptr)) { v = x; bounds.push_back(n); } else if (arith.is_numeral(x, n, is_int) && is_int && - (y == v || v == 0)) { + (y == v || v == nullptr)) { v = y; bounds.push_back(n); } diff --git a/src/tactic/arith/bv2int_rewriter.h b/src/tactic/arith/bv2int_rewriter.h index 9ef256197..89a572d12 100644 --- a/src/tactic/arith/bv2int_rewriter.h +++ b/src/tactic/arith/bv2int_rewriter.h @@ -103,7 +103,7 @@ struct bv2int_rewriter_cfg : public default_rewriter_cfg { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return m_r.mk_app_core(f, num, args, result); } bv2int_rewriter_cfg(ast_manager & m, bv2int_rewriter_ctx& ctx):m_r(m, ctx) {} diff --git a/src/tactic/arith/bv2real_rewriter.h b/src/tactic/arith/bv2real_rewriter.h index f020f9f1e..e03637453 100644 --- a/src/tactic/arith/bv2real_rewriter.h +++ b/src/tactic/arith/bv2real_rewriter.h @@ -181,7 +181,7 @@ struct bv2real_rewriter_cfg : public default_rewriter_cfg { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return m_r.mk_app_core(f, num, args, result); } bv2real_rewriter_cfg(ast_manager & m, bv2real_util& u):m_r(m, u) {} @@ -216,7 +216,7 @@ struct bv2real_elim_rewriter_cfg : public default_rewriter_cfg { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return m_r.mk_app_core(f, num, args, result); } bv2real_elim_rewriter_cfg(bv2real_util& u):m_r(u) {} diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index b268ea3de..b86628f0b 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -58,7 +58,7 @@ public: expr_dependency_ref & core) override { TRACE("card2bv-before", g->display(tout);); SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); tactic_report report("card2bv", *g); th_rewriter rw1(m, m_params); pb2bv_rewriter rw2(m, m_params); diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 287dfa27e..e11c78048 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -79,7 +79,7 @@ namespace pb { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return m_r.mk_app_core(f, num, args, result); } card2bv_rewriter_cfg(ast_manager & m):m_r(m) {} diff --git a/src/tactic/arith/degree_shift_tactic.cpp b/src/tactic/arith/degree_shift_tactic.cpp index 778a73ba5..59e83908f 100644 --- a/src/tactic/arith/degree_shift_tactic.cpp +++ b/src/tactic/arith/degree_shift_tactic.cpp @@ -94,7 +94,7 @@ class degree_shift_tactic : public tactic { m_autil(_m), m_pinned(_m), m_one(1), - m_rw(0) { + m_rw(nullptr) { } @@ -205,8 +205,8 @@ class degree_shift_tactic : public tactic { void prepare_substitution(model_converter_ref & mc) { SASSERT(!m_var2degree.empty()); - filter_model_converter * fmc = 0; - extension_model_converter * xmc = 0; + filter_model_converter * fmc = nullptr; + extension_model_converter * xmc = nullptr; if (m_produce_models) { fmc = alloc(filter_model_converter, m); xmc = alloc(extension_model_converter, m); @@ -217,7 +217,7 @@ class degree_shift_tactic : public tactic { for (; it != end; ++it) { SASSERT(it->m_value.is_int()); SASSERT(it->m_value >= rational(2)); - app * fresh = m.mk_fresh_const(0, it->m_key->get_decl()->get_range()); + app * fresh = m.mk_fresh_const(nullptr, it->m_key->get_decl()->get_range()); m_pinned.push_back(fresh); m_var2var.insert(it->m_key, fresh); if (m_produce_models) { @@ -241,7 +241,7 @@ class degree_shift_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; m_produce_proofs = g->proofs_enabled(); m_produce_models = g->models_enabled(); tactic_report report("degree_shift", *g); @@ -275,12 +275,12 @@ class degree_shift_tactic : public tactic { if (it->m_value.is_even()) { app * new_var = m_var2var.find(it->m_key); app * new_c = m_autil.mk_ge(new_var, m_autil.mk_numeral(rational(0), false)); - proof * new_pr = 0; + proof * new_pr = nullptr; if (m_produce_proofs) { proof * pr = m_var2pr.find(it->m_key); new_pr = m.mk_th_lemma(m_autil.get_family_id(), new_c, 1, &pr); } - g->assert_expr(new_c, new_pr, 0); + g->assert_expr(new_c, new_pr, nullptr); } } } diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index 90dcf099c..13f30e19d 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -319,7 +319,7 @@ class diff_neq_tactic : public tactic { expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); m_produce_models = g->models_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); tactic_report report("diff-neq", *g); fail_if_proof_generation("diff-neq", g); fail_if_unsat_core_generation("diff-neq", g); diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp index 7a923cf0a..46c6f1e1c 100644 --- a/src/tactic/arith/elim01_tactic.cpp +++ b/src/tactic/arith/elim01_tactic.cpp @@ -153,7 +153,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("elim01", *g); diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 1219b980e..2a1af28fc 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -59,7 +59,7 @@ class eq2bv_tactic : public tactic { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return mk_app_core(f, num, args, result); } eq_rewriter_cfg(eq2bv_tactic& t):m(t.m), t(t) {} @@ -149,7 +149,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; m_trail.reset(); m_fd.reset(); m_max.reset(); @@ -175,7 +175,7 @@ public: expr_ref new_curr(m); proof_ref new_pr(m); if (is_bound(g->form(i))) { - g->update(i, m.mk_true(), 0, 0); + g->update(i, m.mk_true(), nullptr, nullptr); continue; } m_rw(g->form(i), new_curr, new_pr); diff --git a/src/tactic/arith/factor_tactic.cpp b/src/tactic/arith/factor_tactic.cpp index ed49e11f7..d65d3abaf 100644 --- a/src/tactic/arith/factor_tactic.cpp +++ b/src/tactic/arith/factor_tactic.cpp @@ -262,7 +262,7 @@ class factor_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("factor", *g); bool produce_proofs = g->proofs_enabled(); diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index 0e0a15ba6..a9331c9a2 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -44,7 +44,7 @@ class fix_dl_var_tactic : public tactic { m_util(u) { } - void throw_failed(expr * ctx1, expr * ctx2 = 0) { + void throw_failed(expr * ctx1, expr * ctx2 = nullptr) { TRACE("fix_dl_var", tout << mk_ismt2_pp(ctx1, m) << "\n"; if (ctx2) tout << mk_ismt2_pp(ctx2, m) << "\n";); throw failed(); } @@ -178,7 +178,7 @@ class fix_dl_var_tactic : public tactic { } app * most_occs(obj_map & occs, unsigned & best) { - app * r = 0; + app * r = nullptr; best = 0; obj_map::iterator it = occs.begin(); obj_map::iterator end = occs.end(); @@ -227,7 +227,7 @@ class fix_dl_var_tactic : public tactic { return most_occs(); } catch (failed) { - return 0; + return nullptr; } } }; @@ -254,13 +254,13 @@ class fix_dl_var_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("fix-dl-var", *g); bool produce_proofs = g->proofs_enabled(); m_produce_models = g->models_enabled(); app * var = is_target(u)(*g); - if (var != 0) { + if (var != nullptr) { IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(fixing-at-zero " << var->get_decl()->get_name() << ")\n";); tactic_report report("fix-dl-var", *g); diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 9a27d6874..882836d3f 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -54,7 +54,7 @@ class fm_tactic : public tactic { bool is_false(model_ref & md, app * p) { SASSERT(is_uninterp_const(p)); expr * val = md->get_const_interp(p->get_decl()); - if (val == 0) { + if (val == nullptr) { // if it is don't care, then set to false md->register_decl(p->get_decl(), m.mk_false()); return true; @@ -828,7 +828,7 @@ class fm_tactic : public tactic { reset_constraints(); m_bvar2expr.reset(); m_bvar2sign.reset(); - m_bvar2expr.push_back(0); // bvar 0 is not used + m_bvar2expr.push_back(nullptr); // bvar 0 is not used m_bvar2sign.push_back(0); m_expr2var.reset(); m_is_int.reset(); @@ -838,11 +838,11 @@ class fm_tactic : public tactic { m_expr2var.reset(); m_lowers.reset(); m_uppers.reset(); - m_new_goal = 0; - m_mc = 0; + m_new_goal = nullptr; + m_mc = nullptr; m_counter = 0; m_inconsistent = false; - m_inconsistent_core = 0; + m_inconsistent_core = nullptr; init_forbidden_set(g); } @@ -878,7 +878,7 @@ class fm_tactic : public tactic { // 0 <= 0 -- > true if (c.m_c.is_pos() || (!c.m_strict && c.m_c.is_zero())) return m.mk_true(); - ineq = 0; + ineq = nullptr; } else { bool int_cnstr = all_int(c); @@ -1115,7 +1115,7 @@ class fm_tactic : public tactic { } else { TRACE("add_constraint_bug", tout << "all variables are forbidden "; display(tout, *c); tout << "\n";); - m_new_goal->assert_expr(to_expr(*c), 0, c->m_dep); + m_new_goal->assert_expr(to_expr(*c), nullptr, c->m_dep); del_constraint(c); return false; } @@ -1130,7 +1130,7 @@ class fm_tactic : public tactic { if (is_occ(f)) add_constraint(f, g.dep(i)); else - m_new_goal->assert_expr(f, 0, g.dep(i)); + m_new_goal->assert_expr(f, nullptr, g.dep(i)); } } @@ -1367,7 +1367,7 @@ class fm_tactic : public tactic { display(tout, l); tout << "\n"; display(tout, u); tout << "\n";); - return 0; // no constraint needs to be created. + return nullptr; // no constraint needs to be created. } new_lits.reset(); @@ -1411,7 +1411,7 @@ class fm_tactic : public tactic { display(tout, l); tout << "\n"; display(tout, u); tout << "\n";); - return 0; + return nullptr; } expr_dependency * new_dep = m.mk_join(l.m_dep, u.m_dep); @@ -1423,7 +1423,7 @@ class fm_tactic : public tactic { display(tout, u); tout << "\n";); m_inconsistent = true; m_inconsistent_core = new_dep; - return 0; + return nullptr; } constraint * new_cnstr = mk_constraint(new_lits.size(), @@ -1493,7 +1493,7 @@ class fm_tactic : public tactic { constraint const & l_c = *(l[i]); constraint const & u_c = *(u[j]); constraint * new_c = resolve(l_c, u_c, x); - if (new_c != 0) { + if (new_c != nullptr) { num_new_cnstrs++; new_constraints.push_back(new_c); } @@ -1528,7 +1528,7 @@ class fm_tactic : public tactic { c->m_dead = true; expr * new_f = to_expr(*c); TRACE("fm_bug", tout << "asserting...\n" << mk_ismt2_pp(new_f, m) << "\nnew_dep: " << c->m_dep << "\n";); - m_new_goal->assert_expr(new_f, 0, c->m_dep); + m_new_goal->assert_expr(new_f, nullptr, c->m_dep); } } } @@ -1555,7 +1555,7 @@ class fm_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("fm", *g); fail_if_proof_generation("fm", g); m_produce_models = g->models_enabled(); @@ -1571,7 +1571,7 @@ class fm_tactic : public tactic { if (m_inconsistent) { m_new_goal->reset(); - m_new_goal->assert_expr(m.mk_false(), 0, m_inconsistent_core); + m_new_goal->assert_expr(m.mk_false(), nullptr, m_inconsistent_core); } else { TRACE("fm", display(tout);); @@ -1595,7 +1595,7 @@ class fm_tactic : public tactic { eliminated++; if (m_inconsistent) { m_new_goal->reset(); - m_new_goal->assert_expr(m.mk_false(), 0, m_inconsistent_core); + m_new_goal->assert_expr(m.mk_false(), nullptr, m_inconsistent_core); break; } } diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 8b95d0781..7f005b4b3 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -112,7 +112,7 @@ class lia2card_tactic : public tactic { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return mk_app_core(f, num, args, result); } lia_rewriter_cfg(lia2card_tactic& t):m(t.m), t(t), a(m), args(m) {} @@ -164,7 +164,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; m_01s->reset(); tactic_report report("cardinality-intro", *g); diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index ce21aa824..48cbb76ef 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -197,7 +197,7 @@ class lia2pb_tactic : public tactic { fail_if_proof_generation("lia2pb", g); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); tactic_report report("lia2pb", *g); m_bm.reset(); m_rw.reset(); m_new_deps.reset(); @@ -224,8 +224,8 @@ class lia2pb_tactic : public tactic { if (!check_num_bits()) throw tactic_exception("lia2pb failed, number of necessary bits exceeds specified threshold (use option :lia2pb-total-bits to increase threshold)"); - extension_model_converter * mc1 = 0; - filter_model_converter * mc2 = 0; + extension_model_converter * mc1 = nullptr; + filter_model_converter * mc2 = nullptr; if (m_produce_models) { mc1 = alloc(extension_model_converter, m); mc2 = alloc(filter_model_converter, m); @@ -251,7 +251,7 @@ class lia2pb_tactic : public tactic { rational a(1); unsigned num_bits = u.get_num_bits(); for (unsigned i = 0; i < num_bits; i++) { - app * x_prime = m.mk_fresh_const(0, m_util.mk_int()); + app * x_prime = m.mk_fresh_const(nullptr, m_util.mk_int()); g->assert_expr(m_util.mk_le(zero, x_prime)); g->assert_expr(m_util.mk_le(x_prime, one)); if (a.is_one()) @@ -264,14 +264,14 @@ class lia2pb_tactic : public tactic { } SASSERT(def_args.size() > 1); expr * def = m_util.mk_add(def_args.size(), def_args.c_ptr()); - expr_dependency * dep = 0; + expr_dependency * dep = nullptr; if (m_produce_unsat_cores) { dep = m.mk_join(m_bm.lower_dep(x), m_bm.upper_dep(x)); - if (dep != 0) + if (dep != nullptr) m_new_deps.push_back(dep); } TRACE("lia2pb", tout << mk_ismt2_pp(x, m) << " -> " << dep << "\n";); - subst.insert(x, def, 0, dep); + subst.insert(x, def, nullptr, dep); if (m_produce_models) { mc1->insert(to_app(x)->get_decl(), def); } @@ -287,7 +287,7 @@ class lia2pb_tactic : public tactic { unsigned size = g->size(); for (unsigned idx = 0; idx < size; idx++) { expr * curr = g->form(idx); - expr_dependency * dep = 0; + expr_dependency * dep = nullptr; m_rw(curr, new_curr, new_pr); if (m_produce_unsat_cores) { dep = m.mk_join(m_rw.get_used_dependencies(), g->dep(idx)); diff --git a/src/tactic/arith/linear_equation.cpp b/src/tactic/arith/linear_equation.cpp index ed158b778..5db0a4cf9 100644 --- a/src/tactic/arith/linear_equation.cpp +++ b/src/tactic/arith/linear_equation.cpp @@ -174,7 +174,7 @@ linear_equation * linear_equation_manager::mk(unsigned sz, mpz * as, var * xs, b } sz = j; if (sz <= 1) - return 0; + return nullptr; } else { DEBUG_CODE({ @@ -265,7 +265,7 @@ linear_equation * linear_equation_manager::mk(mpz const & b1, linear_equation co m.del(new_a); SASSERT(m_int_buffer.size() == m_var_buffer.size()); if (m_int_buffer.empty()) - return 0; + return nullptr; return mk_core(m_int_buffer.size(), m_int_buffer.c_ptr(), m_var_buffer.c_ptr()); } diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 08eb97c4b..9a5c33ce6 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -75,7 +75,7 @@ class nla2bv_tactic : public tactic { m_vars(m), m_defs(m), m_trail(m), - m_fmc(0) { + m_fmc(nullptr) { m_default_bv_size = m_num_bits = p.get_uint("nla2bv_bv_size", 4); } @@ -408,14 +408,14 @@ class nla2bv_tactic : public tactic { } ~scoped_set_imp() { - m_owner.m_imp = 0; + m_owner.m_imp = nullptr; } }; public: nla2bv_tactic(params_ref const & p): m_params(p), - m_imp(0) { + m_imp(nullptr) { } tactic * translate(ast_manager & m) override { @@ -449,7 +449,7 @@ public: SASSERT(g->is_well_sorted()); fail_if_proof_generation("nla2bv", g); fail_if_unsat_core_generation("nla2bv", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); imp proc(g->m(), m_params); scoped_set_imp setter(*this, proc); diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index a9eeb3744..b7cc09e25 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -85,7 +85,7 @@ class normalize_bounds_tactic : public tactic { model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; bool produce_models = in->models_enabled(); bool produce_proofs = in->proofs_enabled(); tactic_report report("normalize-bounds", *in); @@ -98,8 +98,8 @@ class normalize_bounds_tactic : public tactic { return; } - extension_model_converter * mc1 = 0; - filter_model_converter * mc2 = 0; + extension_model_converter * mc1 = nullptr; + filter_model_converter * mc2 = nullptr; if (produce_models) { mc1 = alloc(extension_model_converter, m); mc2 = alloc(filter_model_converter, m); @@ -116,7 +116,7 @@ class normalize_bounds_tactic : public tactic { if (is_target(x, val)) { num_norm_bounds++; sort * s = m.get_sort(x); - app * x_prime = m.mk_fresh_const(0, s); + app * x_prime = m.mk_fresh_const(nullptr, s); expr * def = m_util.mk_add(x_prime, m_util.mk_numeral(val, s)); subst.insert(x, def); if (produce_models) { diff --git a/src/tactic/arith/pb2bv_model_converter.cpp b/src/tactic/arith/pb2bv_model_converter.cpp index df5bd5745..5dc4c1737 100644 --- a/src/tactic/arith/pb2bv_model_converter.cpp +++ b/src/tactic/arith/pb2bv_model_converter.cpp @@ -43,7 +43,7 @@ pb2bv_model_converter::pb2bv_model_converter(ast_manager & _m, obj_mapget_arity() == 0); m.inc_ref(d); - m_c2bit.push_back(func_decl_pair(d, static_cast(0))); + m_c2bit.push_back(func_decl_pair(d, static_cast(nullptr))); } } } @@ -71,7 +71,7 @@ void pb2bv_model_converter::operator()(model_ref & md, unsigned goal_idx) { for (; it != end; ++it) { if (it->second) { expr * val = md->get_const_interp(it->second); - if (val == 0 || m.is_false(val)) { + if (val == nullptr || m.is_false(val)) { /* false's and don't cares get the integer 0 solution*/ md->register_decl(it->first, a_util.mk_numeral(rational(0), true)); } diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index 05b91cf53..170a10f91 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -216,7 +216,7 @@ private: } bool get_subst(expr * s, expr * & t, proof * & t_pr) { - t_pr = 0; + t_pr = nullptr; if (owner.is_constraint_core(s)) { owner.convert(to_app(s), m_saved_res, true, false); t = m_saved_res; @@ -328,12 +328,12 @@ private: func_decl * fd = x->get_decl(); obj_map & const2lit = sign ? m_not_const2bit : m_const2bit; - expr * r = 0; + expr * r = nullptr; const2lit.find(fd, r); - if (r != 0) + if (r != nullptr) return r; - r = m.mk_fresh_const(0, m.mk_bool_sort()); + r = m.mk_fresh_const(nullptr, m.mk_bool_sort()); expr * not_r = m.mk_not(r); m_const2bit.insert(fd, r); m_not_const2bit.insert(fd, not_r); @@ -490,7 +490,7 @@ private: for (unsigned j = 0; j < i; j++) m_clause.push_back(monomial(numeral(1), m_p[j].m_lit)); - app * new_var = m.mk_fresh_const(0, m_arith_util.mk_int()); + app * new_var = m.mk_fresh_const(nullptr, m_arith_util.mk_int()); m_temporary_ints.push_back(new_var); m_clause.push_back(monomial(numeral(1), lit(new_var, true))); @@ -895,7 +895,7 @@ private: fail_if_proof_generation("pb2bv", g); m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); tactic_report report("pb2bv", *g); m_bm.reset(); m_rw.reset(); m_new_deps.reset(); @@ -946,7 +946,7 @@ private: } for (unsigned idx = 0; idx < size; idx++) - g->update(idx, new_exprs[idx].get(), 0, (m_produce_unsat_cores) ? new_deps[idx].get() : g->dep(idx)); + g->update(idx, new_exprs[idx].get(), nullptr, (m_produce_unsat_cores) ? new_deps[idx].get() : g->dep(idx)); if (m_produce_models) { filter_model_converter * mc1 = alloc(filter_model_converter, m); diff --git a/src/tactic/arith/propagate_ineqs_tactic.cpp b/src/tactic/arith/propagate_ineqs_tactic.cpp index cbb29f6b4..38bb38330 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.cpp +++ b/src/tactic/arith/propagate_ineqs_tactic.cpp @@ -354,7 +354,7 @@ struct propagate_ineqs_tactic::imp { void find_ite_bounds(expr * root) { TRACE("find_ite_bounds_bug", display_bounds(tout);); expr * n = root; - expr * target = 0; + expr * target = nullptr; expr * c, * t, * e; expr * x, * y; bool has_l, has_u; @@ -374,7 +374,7 @@ struct propagate_ineqs_tactic::imp { break; } else if (is_x_minus_y_eq_0(n, x, y)) { - n = 0; + n = nullptr; } else { break; @@ -394,7 +394,7 @@ struct propagate_ineqs_tactic::imp { break; } - if (target == 0) { + if (target == nullptr) { target = x; if (lower(y, curr, curr_strict)) { has_l = true; @@ -448,7 +448,7 @@ struct propagate_ineqs_tactic::imp { if (!has_l && !has_u) break; - if (n == 0) { + if (n == nullptr) { TRACE("find_ite_bounds", tout << "found bounds for: " << mk_ismt2_pp(target, m) << "\n"; tout << "has_l: " << has_l << " " << nm.to_string(l_min) << " l_strict: " << l_strict << "\n"; tout << "has_u: " << has_u << " " << nm.to_string(u_max) << " u_strict: " << u_strict << "\n"; @@ -484,7 +484,7 @@ struct propagate_ineqs_tactic::imp { m_new_goal->inc_depth(); r = m_new_goal.get(); if (!collect_bounds(*g)) { - m_new_goal = 0; + m_new_goal = nullptr; r = g; return; // nothing to be done } @@ -534,7 +534,7 @@ void propagate_ineqs_tactic::operator()(goal_ref const & g, SASSERT(g->is_well_sorted()); fail_if_proof_generation("propagate-ineqs", g); fail_if_unsat_core_generation("propagate-ineqs", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); goal_ref r; (*m_imp)(g.get(), r); result.push_back(r.get()); diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 38ea0a2b9..0774c036d 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -170,8 +170,8 @@ struct purify_arith_proc { } std::pair pair; if (!m_sin_cos.find(to_app(theta), pair)) { - pair.first = m().mk_fresh_const(0, u().mk_real()); - pair.second = m().mk_fresh_const(0, u().mk_real()); + pair.first = m().mk_fresh_const(nullptr, u().mk_real()); + pair.second = m().mk_fresh_const(nullptr, u().mk_real()); m_sin_cos.insert(to_app(theta), pair); m_pinned.push_back(pair.first); m_pinned.push_back(pair.second); @@ -214,7 +214,7 @@ struct purify_arith_proc { bool elim_inverses() const { return m_owner.m_elim_inverses; } expr * mk_fresh_var(bool is_int) { - expr * r = m().mk_fresh_const(0, is_int ? u().mk_int() : u().mk_real()); + expr * r = m().mk_fresh_const(nullptr, is_int ? u().mk_int() : u().mk_real()); m_new_vars.push_back(r); return r; } @@ -241,7 +241,7 @@ struct purify_arith_proc { } void mk_def_proof(expr * k, expr * def, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; if (produce_proofs()) { expr * eq = m().mk_eq(k, def); proof * pr1 = m().mk_def_intro(eq); @@ -691,7 +691,7 @@ struct purify_arith_proc { }; void process_quantifier(quantifier * q, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; rw r(*this); expr_ref new_body(m()); proof_ref new_body_pr(m()); @@ -761,7 +761,7 @@ struct purify_arith_proc { sz = r.cfg().m_new_cnstrs.size(); TRACE("purify_arith", tout << r.cfg().m_new_cnstrs << "\n";); for (unsigned i = 0; i < sz; i++) { - m_goal.assert_expr(r.cfg().m_new_cnstrs.get(i), m_produce_proofs ? r.cfg().m_new_cnstr_prs.get(i) : 0, 0); + m_goal.assert_expr(r.cfg().m_new_cnstrs.get(i), m_produce_proofs ? r.cfg().m_new_cnstr_prs.get(i) : nullptr, nullptr); } // add filter_model_converter to eliminate auxiliary variables from model @@ -830,7 +830,7 @@ public: expr_dependency_ref & core) override { try { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("purify-arith", *g); TRACE("purify_arith", g->display(tout);); bool produce_proofs = g->proofs_enabled(); diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index cf2beacb2..b1666eb7b 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -70,7 +70,7 @@ class recover_01_tactic : public tactic { bool save_clause(expr * c) { if (!m.is_or(c)) return false; - func_decl * x = 0; + func_decl * x = nullptr; app * cls = to_app(c); if (cls->get_num_args() <= 1 || cls->get_num_args() >= m_cls_max_size) return false; @@ -84,7 +84,7 @@ class recover_01_tactic : public tactic { else if (m.is_not(lit, arg) && is_uninterp_const(arg)) { // negative literal } - else if (x == 0 && m.is_eq(lit, lhs, rhs)) { + else if (x == nullptr && m.is_eq(lit, lhs, rhs)) { // x = k literal if (is_uninterp_const(lhs) && m_util.is_numeral(rhs)) { x = to_app(lhs)->get_decl(); @@ -101,7 +101,7 @@ class recover_01_tactic : public tactic { } } - if (x != 0) { + if (x != nullptr) { var2clauses::obj_map_entry * entry = m_var2clauses.insert_if_not_there2(x, ptr_vector()); if (entry->get_data().m_value.empty() || entry->get_data().m_value.back()->get_num_args() == cls->get_num_args()) { entry->get_data().m_value.push_back(cls); @@ -134,7 +134,7 @@ class recover_01_tactic : public tactic { } } } - return 0; + return nullptr; } // Find coeff (the k of literal (x = k)) of clause cls. @@ -199,7 +199,7 @@ class recover_01_tactic : public tactic { SASSERT(is_uninterp_const(atom)); expr * var; if (!bool2int.find(atom, var)) { - var = m.mk_fresh_const(0, m_util.mk_int()); + var = m.mk_fresh_const(nullptr, m_util.mk_int()); new_goal->assert_expr(m_util.mk_le(m_util.mk_numeral(rational(0), true), var)); new_goal->assert_expr(m_util.mk_le(var, m_util.mk_numeral(rational(1), true))); expr * bool_def = m.mk_eq(var, m_util.mk_numeral(rational(1), true)); @@ -225,7 +225,7 @@ class recover_01_tactic : public tactic { if (clauses.size() < expected_num_clauses) // using < instead of != because we tolerate duplicates return false; app * zero_cls = find_zero_cls(x, clauses); - if (zero_cls == 0) + if (zero_cls == nullptr) return false; buffer found; // marks which idx were found @@ -302,7 +302,7 @@ class recover_01_tactic : public tactic { fail_if_proof_generation("recover-01", g); fail_if_unsat_core_generation("recover-01", g); m_produce_models = g->models_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); tactic_report report("recover-01", *g); bool saved = false; @@ -357,7 +357,7 @@ class recover_01_tactic : public tactic { if (!recovered) { result.push_back(g.get()); - mc = 0; + mc = nullptr; return; } diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 2a1ddcd4a..027938752 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -118,7 +118,7 @@ struct bit_blaster_model_converter : public model_converter { func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); // remark: if old_model does not assign bit_val, then assume it is false. - if (bit_val != 0 && m().is_true(bit_val)) + if (bit_val != nullptr && m().is_true(bit_val)) val++; } } @@ -133,7 +133,7 @@ struct bit_blaster_model_converter : public model_converter { func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); // remark: if old_model does not assign bit_val, then assume it is false. - if (bit_val != 0 && !util.is_zero(bit_val)) + if (bit_val != nullptr && !util.is_zero(bit_val)) val++; } } diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index a44f32044..a8f302752 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -55,7 +55,7 @@ class bit_blaster_tactic : public tactic { model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; bool proofs_enabled = g->proofs_enabled(); if (proofs_enabled && m_blast_quant) @@ -90,7 +90,7 @@ class bit_blaster_tactic : public tactic { if (change && g->models_enabled()) mc = mk_bit_blaster_model_converter(m(), m_rewriter->const2bits()); else - mc = 0; + mc = nullptr; g->inc_depth(); result.push_back(g.get()); TRACE("after_bit_blaster", g->display(tout); if (mc) mc->display(tout); tout << "\n";); @@ -113,7 +113,7 @@ public: tactic * translate(ast_manager & m) override { SASSERT(!m_rewriter); // assume translation isn't used where rewriter is external. - return alloc(bit_blaster_tactic, m, 0, m_params); + return alloc(bit_blaster_tactic, m, nullptr, m_params); } ~bit_blaster_tactic() override { @@ -161,7 +161,7 @@ public: tactic * mk_bit_blaster_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(bit_blaster_tactic, m, 0, p)); + return clean(alloc(bit_blaster_tactic, m, nullptr, p)); } tactic * mk_bit_blaster_tactic(ast_manager & m, bit_blaster_rewriter* rw, params_ref const & p) { diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index 196835c51..e82948c16 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -106,7 +106,7 @@ class bv1_blaster_tactic : public tactic { sort * b = butil().mk_sort(1); ptr_buffer bits; for (unsigned i = 0; i < bv_size; i++) { - bits.push_back(m().mk_fresh_const(0, b)); + bits.push_back(m().mk_fresh_const(nullptr, b)); } r = butil().mk_concat(bits.size(), bits.c_ptr()); m_saved.push_back(r); @@ -253,7 +253,7 @@ class bv1_blaster_tactic : public tactic { } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; if (num == 0 && f->get_family_id() == null_family_id && butil().is_bv_sort(f->get_range())) { mk_const(f, result); return BR_DONE; @@ -383,7 +383,7 @@ class bv1_blaster_tactic : public tactic { model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; if (!is_target(*g)) throw tactic_exception("bv1 blaster cannot be applied to goal"); diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index 2d717c0ae..48201501e 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -68,7 +68,7 @@ struct bv_bound_chk_rewriter_cfg : public default_rewriter_cfg { } br_status reduce_app_core(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; const family_id fid = f->get_family_id(); if (fid != m_b_rw.get_fid()) return BR_FAILED; bv_bounds bvb(m()); @@ -206,7 +206,7 @@ void bv_bound_chk_tactic::operator()(goal_ref const & g, fail_if_proof_generation("bv-bound-chk", g); fail_if_unsat_core_generation("bv-bound-chk", g); TRACE("bv-bound-chk", g->display(tout << "before:"); tout << std::endl;); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); m_imp->operator()(g); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index 0628b4013..2cd6a5a1b 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -194,7 +194,7 @@ namespace { bool is_bound(expr *e, expr*& v, interval& b) const { uint64 n; - expr *lhs = 0, *rhs = 0; + expr *lhs = nullptr, *rhs = nullptr; unsigned sz; if (m_bv.is_bv_ule(e, lhs, rhs)) { @@ -382,7 +382,7 @@ namespace { } interval ctx, intr; - result = 0; + result = nullptr; if (b.is_full() && b.tight) { result = m.mk_true(); @@ -561,7 +561,7 @@ namespace { bool is_bound(expr *e, expr*& v, interval& b) const { uint64 n; - expr *lhs = 0, *rhs = 0; + expr *lhs = nullptr, *rhs = nullptr; unsigned sz = 0; if (m_bv.is_bv_ule(e, lhs, rhs)) { diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index 2c70e554f..3bcb2e02b 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -184,8 +184,8 @@ struct bv_size_reduction_tactic::imp { return; TRACE("before_bv_size_reduction", g.display(tout);); m_produce_models = g.models_enabled(); - mc = 0; - m_mc = 0; + mc = nullptr; + m_mc = nullptr; unsigned num_reduced = 0; { tactic_report report("bv-size-reduction", g); @@ -211,11 +211,11 @@ struct bv_size_reduction_tactic::imp { unsigned bv_sz = m_util.get_bv_size(v); numeral l = m_util.norm(it->m_value, bv_sz, true); obj_map::obj_map_entry * entry = m_signed_uppers.find_core(v); - if (entry != 0) { + if (entry != nullptr) { numeral u = m_util.norm(entry->get_data().m_value, bv_sz, true); TRACE("bv_size_reduction", tout << l << " <= " << v->get_decl()->get_name() << " <= " << u << "\n";); - expr * new_def = 0; - app * new_const = 0; + expr * new_def = nullptr; + app * new_const = nullptr; if (l > u) { g.assert_expr(m.mk_false()); return; @@ -235,7 +235,7 @@ struct bv_size_reduction_tactic::imp { unsigned i_nb = l_nb; TRACE("bv_size_reduction", tout << " l <= " << v->get_decl()->get_name() << " <= u <= 0 " << " --> " << i_nb << " bits\n";); if (i_nb < v_nb) { - new_const = m.mk_fresh_const(0, m_util.mk_sort(i_nb)); + new_const = m.mk_fresh_const(nullptr, m_util.mk_sort(i_nb)); new_def = m_util.mk_concat(m_util.mk_numeral(numeral(-1), v_nb - i_nb), new_const); } } @@ -245,7 +245,7 @@ struct bv_size_reduction_tactic::imp { unsigned i_nb = ((l_nb > u_nb) ? l_nb : u_nb) + 1; TRACE("bv_size_reduction", tout << " l <= " << v->get_decl()->get_name() << " <= 0 <= u " << " --> " << i_nb << " bits\n";); if (i_nb < v_nb) { - new_const = m.mk_fresh_const(0, m_util.mk_sort(i_nb)); + new_const = m.mk_fresh_const(nullptr, m_util.mk_sort(i_nb)); new_def = m_util.mk_sign_extend(v_nb - i_nb, new_const); } } @@ -256,7 +256,7 @@ struct bv_size_reduction_tactic::imp { unsigned v_nb = m_util.get_bv_size(v); TRACE("bv_size_reduction", tout << l << " <= " << v->get_decl()->get_name() << " <= " << u << " --> " << u_nb << " bits\n";); if (u_nb < v_nb) { - new_const = m.mk_fresh_const(0, m_util.mk_sort(u_nb)); + new_const = m.mk_fresh_const(nullptr, m_util.mk_sort(u_nb)); new_def = m_util.mk_concat(m_util.mk_numeral(numeral(0), v_nb - u_nb), new_const); } } @@ -365,8 +365,8 @@ struct bv_size_reduction_tactic::imp { if (m_fmc) { mc = concat(m_fmc.get(), mc.get()); } - m_mc = 0; - m_fmc = 0; + m_mc = nullptr; + m_fmc = nullptr; } report_tactic_progress(":bv-reduced", num_reduced); TRACE("after_bv_size_reduction", g.display(tout); if (m_mc) m_mc->display(tout);); @@ -390,7 +390,7 @@ void bv_size_reduction_tactic::operator()(goal_ref const & g, SASSERT(g->is_well_sorted()); fail_if_proof_generation("bv-size-reduction", g); fail_if_unsat_core_generation("bv-size-reduction", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); m_imp->operator()(*(g.get()), mc); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp index b92092739..a0f80f38b 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.cpp +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -37,8 +37,8 @@ bvarray2uf_rewriter_cfg::bvarray2uf_rewriter_cfg(ast_manager & m, params_ref con m_bindings(m), m_bv_util(m), m_array_util(m), - m_emc(0), - m_fmc(0), + m_emc(nullptr), + m_fmc(nullptr), extra_assertions(m) { updt_params(p); // We need to make sure that the mananger has the BV and array plugins loaded. @@ -108,7 +108,7 @@ func_decl_ref bvarray2uf_rewriter_cfg::mk_uf_for_array(expr * e) { if (m_array_util.is_as_array(e)) return func_decl_ref(static_cast(to_app(e)->get_decl()->get_parameter(0).get_ast()), m_manager); else { - func_decl * bv_f = 0; + func_decl * bv_f = nullptr; if (!m_arrays_fs.find(e, bv_f)) { sort * domain = get_index_sort(e); sort * range = get_value_sort(e); @@ -184,7 +184,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr func_decl_ref itefd(m_manager); e = m_manager.mk_ite(c, f_ta, f_fa); - func_decl * bv_f = 0; + func_decl * bv_f = nullptr; if (!m_arrays_fs.find(f_a, bv_f)) { sort * domain = get_index_sort(args[1]); sort * range = get_value_sort(args[1]); diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index 844d64429..6287181b1 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -61,7 +61,7 @@ class bvarray2uf_tactic : public tactic { { SASSERT(g->is_well_sorted()); tactic_report report("bvarray2uf", *g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); fail_if_unsat_core_generation("bvarray2uf", g); TRACE("bvarray2uf", tout << "Before: " << std::endl; g->display(tout); ); diff --git a/src/tactic/bv/dt2bv_tactic.cpp b/src/tactic/bv/dt2bv_tactic.cpp index 62093d191..8f164a921 100644 --- a/src/tactic/bv/dt2bv_tactic.cpp +++ b/src/tactic/bv/dt2bv_tactic.cpp @@ -122,7 +122,7 @@ public: model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; bool produce_proofs = g->proofs_enabled(); tactic_report report("dt2bv", *g); unsigned size = g->size(); diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index f5f0c2b88..17887d495 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -52,7 +52,7 @@ class elim_small_bv_tactic : public tactic { m_bindings(_m), m_num_eliminated(0) { updt_params(p); - m_goal = 0; + m_goal = nullptr; m_max_steps = UINT_MAX; } @@ -77,13 +77,13 @@ class elim_small_bv_tactic : public tactic { expr_ref res(m); expr_ref_vector substitution(m); - substitution.resize(num_decls, 0); + substitution.resize(num_decls, nullptr); substitution[num_decls - idx - 1] = replacement; // (VAR 0) is in the first position of substitution; (VAR num_decls-1) is in the last position. for (unsigned i = 0; i < max_var_idx_p1; i++) - substitution.push_back(0); + substitution.push_back(nullptr); // (VAR num_decls) ... (VAR num_decls+sz-1); are in positions num_decls .. num_decls+sz-1 @@ -175,7 +175,7 @@ class elim_small_bv_tactic : public tactic { TRACE("elim_small_bv", tout << "elimination result: " << mk_ismt2_pp(result, m) << std::endl; ); - result_pr = 0; // proofs NIY + result_pr = nullptr; // proofs NIY m_bindings.shrink(old_sz); return true; } @@ -230,7 +230,7 @@ class elim_small_bv_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("elim-small-bv", *g); bool produce_proofs = g->proofs_enabled(); fail_if_proof_generation("elim-small-bv", g); diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index 0b7d0d345..8054cfdd8 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -84,7 +84,7 @@ class max_bv_sharing_tactic : public tactic { return m().mk_app(f, arg1, arg2); if (s.contains(expr_pair(arg2, arg1))) return m().mk_app(f, arg2, arg1); - return 0; + return nullptr; } struct ref_count_lt { @@ -106,10 +106,10 @@ class max_bv_sharing_tactic : public tactic { ptr_buffer _args; bool first = false; - expr * num = 0; + expr * num = nullptr; for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; - if (num == 0 && m_util.is_numeral(arg)) { + if (num == nullptr && m_util.is_numeral(arg)) { if (i == 0) first = true; num = arg; } @@ -128,7 +128,7 @@ class max_bv_sharing_tactic : public tactic { for (unsigned i = 0; i < num_args - 1; i++) { for (unsigned j = i + 1; j < num_args; j++) { expr * r = reuse(s, f, _args[i], _args[j]); - if (r != 0) { + if (r != nullptr) { TRACE("bv_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); _args[i] = r; SASSERT(num_args > 1); @@ -186,7 +186,7 @@ class max_bv_sharing_tactic : public tactic { } num_args = j; if (num_args == 1) { - if (num == 0) { + if (num == nullptr) { result = _args[0]; } else { @@ -209,7 +209,7 @@ class max_bv_sharing_tactic : public tactic { case OP_BMUL: case OP_BOR: case OP_BXOR: - result_pr = 0; + result_pr = nullptr; return reduce_ac_app(f, num, args, result); default: return BR_FAILED; @@ -242,7 +242,7 @@ class max_bv_sharing_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("max-bv-sharing", *g); bool produce_proofs = g->proofs_enabled(); diff --git a/src/tactic/converter.h b/src/tactic/converter.h index 924971d27..d50458cf1 100644 --- a/src/tactic/converter.h +++ b/src/tactic/converter.h @@ -84,11 +84,11 @@ protected: template T * translate_core(ast_translation & translator) { - T * t1 = m_c1 ? m_c1->translate(translator) : 0; + T * t1 = m_c1 ? m_c1->translate(translator) : nullptr; ptr_buffer t2s; unsigned num = m_c2s.size(); for (unsigned i = 0; i < num; i++) - t2s.push_back(m_c2s[i] ? m_c2s[i]->translate(translator) : 0); + t2s.push_back(m_c2s[i] ? m_c2s[i]->translate(translator) : nullptr); return alloc(T2, t1, num, t2s.c_ptr(), m_szs.c_ptr()); } diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index 27d907b63..4082659df 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -120,7 +120,7 @@ class blast_term_ite_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("blast-term-ite", *g); bool produce_proofs = g->proofs_enabled(); diff --git a/src/tactic/core/cofactor_elim_term_ite.cpp b/src/tactic/core/cofactor_elim_term_ite.cpp index b90be82b5..2b3cb8414 100644 --- a/src/tactic/core/cofactor_elim_term_ite.cpp +++ b/src/tactic/core/cofactor_elim_term_ite.cpp @@ -219,7 +219,7 @@ struct cofactor_elim_term_ite::imp { break; } } - return 0; + return nullptr; } /** @@ -286,7 +286,7 @@ struct cofactor_elim_term_ite::imp { break; } } - expr * best = 0; + expr * best = nullptr; unsigned best_occs = 0; obj_map::iterator it = occs.begin(); obj_map::iterator end = occs.end(); @@ -329,7 +329,7 @@ struct cofactor_elim_term_ite::imp { bool m_strict_upper; app * m_upper; - cofactor_rw_cfg(ast_manager & _m, imp & owner, obj_hashtable * has_term_ite = 0): + cofactor_rw_cfg(ast_manager & _m, imp & owner, obj_hashtable * has_term_ite = nullptr): m(_m), m_owner(owner), m_has_term_ite(has_term_ite), @@ -349,13 +349,13 @@ struct cofactor_elim_term_ite::imp { if (m.is_not(t)) { m_atom = to_app(t)->get_arg(0); m_sign = true; - m_term = 0; + m_term = nullptr; // TODO: bounds } else { m_atom = t; m_sign = false; - m_term = 0; + m_term = nullptr; expr * lhs; expr * rhs; if (m_owner.m_cofactor_equalities && m.is_eq(t, lhs, rhs)) { @@ -377,19 +377,19 @@ struct cofactor_elim_term_ite::imp { bool rewrite_patterns() const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return m_mk_app.mk_core(f, num, args, result); } bool get_subst(expr * s, expr * & t, proof * & pr) { - pr = 0; + pr = nullptr; if (s == m_atom) { t = m_sign ? m.mk_false() : m.mk_true(); return true; } - if (s == m_term && m_value != 0) { + if (s == m_term && m_value != nullptr) { t = m_value; return true; } @@ -406,7 +406,7 @@ struct cofactor_elim_term_ite::imp { struct cofactor_rw : rewriter_tpl { cofactor_rw_cfg m_cfg; public: - cofactor_rw(ast_manager & m, imp & owner, obj_hashtable * has_term_ite = 0): + cofactor_rw(ast_manager & m, imp & owner, obj_hashtable * has_term_ite = nullptr): rewriter_tpl(m, false, m_cfg), m_cfg(m, owner, has_term_ite) { } @@ -444,7 +444,7 @@ struct cofactor_elim_term_ite::imp { bool get_subst(expr * s, expr * & t, proof * & t_pr) { if (m_candidates.contains(s)) { - t_pr = 0; + t_pr = nullptr; if (m_cache.find(s, t)) return true; @@ -455,7 +455,7 @@ struct cofactor_elim_term_ite::imp { while (true) { // expr * c = m_owner.get_best(curr); expr * c = m_owner.get_first(curr); - if (c == 0) { + if (c == nullptr) { m_cache.insert(s, curr); m_cache_domain.push_back(curr); t = curr.get(); @@ -532,7 +532,7 @@ struct cofactor_elim_term_ite::imp { while (true) { expr * c = m_owner.get_best(curr); // expr * c = m_owner.get_first(curr); - if (c == 0) { + if (c == nullptr) { r = curr.get(); return; } @@ -607,7 +607,7 @@ struct cofactor_elim_term_ite::imp { unsigned num = to_app(t)->get_num_args(); for (unsigned i = 0; i < num; i++) { expr * arg = to_app(t)->get_arg(i); - expr * new_arg = 0; + expr * new_arg = nullptr; TRACE("cofactor_bug", tout << "collecting child: " << arg->get_id() << "\n";); m_cache.find(arg, new_arg); SASSERT(new_arg != 0); @@ -645,7 +645,7 @@ struct cofactor_elim_term_ite::imp { m_cache_domain.push_back(new_t); m_frames.pop_back(); } - expr * result = 0; + expr * result = nullptr; m_cache.find(t, result); r = result; } diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index 64c2c0f66..30486358d 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -36,7 +36,7 @@ class cofactor_term_ite_tactic : public tactic { expr * f = g.form(i); expr_ref new_f(m); m_elim_ite(f, new_f); - g.update(i, new_f, 0, g.dep(i)); + g.update(i, new_f, nullptr, g.dep(i)); } } @@ -63,7 +63,7 @@ public: fail_if_proof_generation("cofactor-term-ite", g); fail_if_unsat_core_generation("cofactor-term-ite", g); tactic_report report("cofactor-term-ite", *g); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; process(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 166fb6036..0e08395ad 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -66,7 +66,7 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override { - mc = 0; + mc = nullptr; tactic_report report("collect-statistics", *g); collect_proc cp(m, m_stats); diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 89bdcca1c..6ad9c0812 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -148,7 +148,7 @@ struct ctx_simplify_tactic::imp { struct cache_cell { expr * m_from; cached_result * m_result; - cache_cell():m_from(0), m_result(0) {} + cache_cell():m_from(nullptr), m_result(nullptr) {} }; ast_manager & m; @@ -217,7 +217,7 @@ struct ctx_simplify_tactic::imp { bool check_cache() { for (unsigned i = 0; i < m_cache.size(); i++) { cache_cell & cell = m_cache[i]; - if (cell.m_from != 0) { + if (cell.m_from != nullptr) { SASSERT(cell.m_result != 0); cached_result * curr = cell.m_result; while (curr) { @@ -235,10 +235,10 @@ struct ctx_simplify_tactic::imp { m_cache.reserve(id+1); cache_cell & cell = m_cache[id]; void * mem = m_allocator.allocate(sizeof(cached_result)); - if (cell.m_from == 0) { + if (cell.m_from == nullptr) { // new_entry cell.m_from = from; - cell.m_result = new (mem) cached_result(to, scope_level(), 0); + cell.m_result = new (mem) cached_result(to, scope_level(), nullptr); m.inc_ref(from); m.inc_ref(to); } @@ -281,9 +281,9 @@ struct ctx_simplify_tactic::imp { if (to_delete->m_next) tout << mk_ismt2_pp(to_delete->m_next->m_to, m); else tout << ""; tout << "\n";); cell.m_result = to_delete->m_next; - if (cell.m_result == 0) { + if (cell.m_result == nullptr) { m.dec_ref(cell.m_from); - cell.m_from = 0; + cell.m_from = nullptr; } m_allocator.deallocate(sizeof(cached_result), to_delete); } @@ -316,7 +316,7 @@ struct ctx_simplify_tactic::imp { return false; cache_cell & cell = m_cache[id]; SASSERT(cell.m_result == 0 || cell.m_result->m_lvl <= scope_level()); - if (cell.m_result != 0 && cell.m_result->m_lvl == scope_level()) { + if (cell.m_result != nullptr && cell.m_result->m_lvl == scope_level()) { SASSERT(cell.m_from == t); SASSERT(cell.m_result->m_to != 0); r = cell.m_result->m_to; @@ -326,7 +326,7 @@ struct ctx_simplify_tactic::imp { } void simplify(expr * t, expr_ref & r) { - r = 0; + r = nullptr; if (m_depth >= m_max_depth || m_num_steps >= m_max_steps || !is_app(t) || !m_simp->may_simplify(t)) { r = t; return; @@ -534,7 +534,7 @@ struct ctx_simplify_tactic::imp { if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !assert_expr(r, false)) { r = m.mk_false(); } - g.update(i, r, 0, g.dep(i)); + g.update(i, r, nullptr, g.dep(i)); } pop(scope_level() - old_lvl); @@ -549,7 +549,7 @@ struct ctx_simplify_tactic::imp { if (i > 0 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !assert_expr(r, false)) { r = m.mk_false(); } - g.update(i, r, 0, g.dep(i)); + g.update(i, r, nullptr, g.dep(i)); } pop(scope_level() - old_lvl); SASSERT(scope_level() == 0); @@ -582,7 +582,7 @@ struct ctx_simplify_tactic::imp { for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { expr * t = g.form(i); process(t, r); - proof* new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(t, r, 0, 0)); // TODO :-) + proof* new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(t, r, 0, nullptr)); // TODO :-) g.update(i, r, new_pr, g.dep(i)); } } @@ -625,7 +625,7 @@ void ctx_simplify_tactic::operator()(goal_ref const & in, model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/tactic/core/der_tactic.cpp b/src/tactic/core/der_tactic.cpp index d4c20a065..f809f2a74 100644 --- a/src/tactic/core/der_tactic.cpp +++ b/src/tactic/core/der_tactic.cpp @@ -78,7 +78,7 @@ public: model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); diff --git a/src/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp index 9a5ef0c48..d8f613044 100644 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ b/src/tactic/core/distribute_forall_tactic.cpp @@ -93,7 +93,7 @@ class distribute_forall_tactic : public tactic { rw * m_rw; public: - distribute_forall_tactic():m_rw(0) {} + distribute_forall_tactic():m_rw(nullptr) {} tactic * translate(ast_manager & m) override { return alloc(distribute_forall_tactic); @@ -109,7 +109,7 @@ public: bool produce_proofs = g->proofs_enabled(); rw r(m, produce_proofs); m_rw = &r; - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); tactic_report report("distribute-forall", *g); expr_ref new_curr(m); @@ -131,7 +131,7 @@ public: result.push_back(g.get()); TRACE("distribute-forall", g->display(tout);); SASSERT(g->is_well_sorted()); - m_rw = 0; + m_rw = nullptr; } void cleanup() override {} diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 2099eebf0..e8d3150af 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -100,7 +100,7 @@ bool expr_dominators::compute_dominators() { for (unsigned i = 0; i + 1 < m_post2expr.size(); ++i) { expr * child = m_post2expr[i]; ptr_vector const& p = m_parents[child]; - expr * new_idom = 0, *idom2 = 0; + expr * new_idom = nullptr, *idom2 = nullptr; for (expr * pred : p) { if (m_doms.contains(pred)) { @@ -189,7 +189,7 @@ void dom_simplify_tactic::operator()( model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("dom-simplify", *in.get()); simplify_goal(*(in.get())); @@ -207,7 +207,7 @@ void dom_simplify_tactic::cleanup() { expr_ref dom_simplify_tactic::simplify_ite(app * ite) { expr_ref r(m); - expr * c = 0, *t = 0, *e = 0; + expr * c = nullptr, *t = nullptr, *e = nullptr; VERIFY(m.is_ite(ite, c, t, e)); unsigned old_lvl = scope_level(); expr_ref new_c = simplify_arg(c); @@ -262,7 +262,7 @@ expr_ref dom_simplify_tactic::simplify_arg(expr * e) { */ expr_ref dom_simplify_tactic::simplify_rec(expr * e0) { expr_ref r(m); - expr* e = 0; + expr* e = nullptr; TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << "\n";); if (!m_result.find(e0, e)) { @@ -380,9 +380,9 @@ void dom_simplify_tactic::simplify_goal(goal& g) { } CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); change |= r != g.form(i); - proof* new_pr = 0; + proof* new_pr = nullptr; if (g.proofs_enabled()) { - new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0)); + new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, nullptr)); } g.update(i, r, new_pr, g.dep(i)); } @@ -400,9 +400,9 @@ void dom_simplify_tactic::simplify_goal(goal& g) { } change |= r != g.form(i); CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); - proof* new_pr = 0; + proof* new_pr = nullptr; if (g.proofs_enabled()) { - new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0)); + new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, nullptr)); } g.update(i, r, new_pr, g.dep(i)); } @@ -448,14 +448,14 @@ bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) { m_scoped_substitution.push(); expr* tt; if (!sign) { - update_substitution(t, 0); + update_substitution(t, nullptr); } else if (m.is_not(t, tt)) { - update_substitution(tt, 0); + update_substitution(tt, nullptr); } else { expr_ref nt(m.mk_not(t), m); - update_substitution(nt, 0); + update_substitution(nt, nullptr); } return true; } diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 2b114bb71..9e1a41f8d 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -111,7 +111,7 @@ class dom_simplify_tactic : public tactic { bool is_subexpr(expr * a, expr * b); - expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(t, r)) r = t; return expr_ref(r, m); } + expr_ref get_cached(expr* t) { expr* r = nullptr; if (!m_result.find(t, r)) r = t; return expr_ref(r, m); } void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); } ptr_vector const & tree(expr * e); diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 522aa90c6..7691d3398 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -51,7 +51,7 @@ class elim_term_ite_tactic : public tactic { proof_ref new_def_pr(m); app_ref _result(m); if (m_defined_names.mk_name(new_ite, new_def, new_def_pr, _result, result_pr)) { - m_goal->assert_expr(new_def, new_def_pr, 0); + m_goal->assert_expr(new_def, new_def_pr, nullptr); m_num_fresh++; if (m_produce_models) { if (!m_mc) @@ -65,9 +65,9 @@ class elim_term_ite_tactic : public tactic { rw_cfg(ast_manager & _m, params_ref const & p): m(_m), - m_defined_names(m, 0 /* don't use prefix */) { + m_defined_names(m, nullptr /* don't use prefix */) { updt_params(p); - m_goal = 0; + m_goal = nullptr; m_num_fresh = 0; } @@ -105,7 +105,7 @@ class elim_term_ite_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("elim-term-ite", *g); bool produce_proofs = g->proofs_enabled(); m_rw.cfg().m_produce_models = g->models_enabled(); diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index a702ab18f..476ea03dd 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -95,7 +95,7 @@ class elim_uncnstr_tactic : public tactic { return false; // variable already existed for this application } - v = m().mk_fresh_const(0, m().get_sort(t)); + v = m().mk_fresh_const(nullptr, m().get_sort(t)); TRACE("elim_uncnstr_bug", tout << "eliminating:\n" << mk_ismt2_pp(t, m()) << "\n";); TRACE("elim_uncnstr_bug_ll", tout << "eliminating:\n" << mk_bounded_pp(t, m()) << "\n";); m_fresh_vars.push_back(v); @@ -220,7 +220,7 @@ class elim_uncnstr_tactic : public tactic { t = arg1; } else { - return 0; + return nullptr; } sort * s = m().get_sort(arg1); @@ -243,14 +243,14 @@ class elim_uncnstr_tactic : public tactic { // variables. // if (!m().is_fully_interp(s)) - return 0; + return nullptr; // If the interpreted sort has only one element, // then it is unsound to eliminate the unconstrained variable in the equality sort_size sz = s->get_num_elements(); if (sz.is_finite() && sz.size() <= 1) - return 0; + return nullptr; if (!m_mc) { // easy case, model generation is disabled. @@ -267,7 +267,7 @@ class elim_uncnstr_tactic : public tactic { add_def(v, m().mk_ite(u, t, d)); return u; } - return 0; + return nullptr; } app * process_basic_app(func_decl * f, unsigned num, expr * const * args) { @@ -299,7 +299,7 @@ class elim_uncnstr_tactic : public tactic { add_def(args[2], r); return r; } - return 0; + return nullptr; case OP_NOT: SASSERT(num == 1); if (uncnstr(args[0])) { @@ -310,7 +310,7 @@ class elim_uncnstr_tactic : public tactic { add_def(args[0], m().mk_not(r)); return r; } - return 0; + return nullptr; case OP_AND: if (num > 0 && uncnstr(num, args)) { app * r; @@ -320,7 +320,7 @@ class elim_uncnstr_tactic : public tactic { add_defs(num, args, r, m().mk_true()); return r; } - return 0; + return nullptr; case OP_OR: if (num > 0 && uncnstr(num, args)) { app * r; @@ -330,13 +330,13 @@ class elim_uncnstr_tactic : public tactic { add_defs(num, args, r, m().mk_false()); return r; } - return 0; + return nullptr; case OP_IFF: case OP_EQ: SASSERT(num == 2); return process_eq(f, args[0], args[1]); default: - return 0; + return nullptr; } } @@ -353,7 +353,7 @@ class elim_uncnstr_tactic : public tactic { le = !le; } else { - return 0; + return nullptr; } app * u; if (!mk_fresh_uncnstr_var_for(f, arg1, arg2, u)) @@ -368,9 +368,9 @@ class elim_uncnstr_tactic : public tactic { app * process_add(family_id fid, decl_kind add_k, decl_kind sub_k, unsigned num, expr * const * args) { if (num == 0) - return 0; + return nullptr; unsigned i; - expr * v = 0; + expr * v = nullptr; for (i = 0; i < num; i++) { expr * arg = args[i]; if (uncnstr(arg)) { @@ -378,8 +378,8 @@ class elim_uncnstr_tactic : public tactic { break; } } - if (v == 0) - return 0; + if (v == nullptr) + return nullptr; app * u; if (!mk_fresh_uncnstr_var_for(m().mk_app(fid, add_k, num, args), u)) return u; @@ -407,7 +407,7 @@ class elim_uncnstr_tactic : public tactic { app * process_arith_mul(func_decl * f, unsigned num, expr * const * args) { if (num == 0) - return 0; + return nullptr; sort * s = m().get_sort(args[0]); if (uncnstr(num, args)) { app * r; @@ -422,7 +422,7 @@ class elim_uncnstr_tactic : public tactic { rational val; if (num == 2 && uncnstr(args[1]) && m_a_util.is_numeral(args[0], val, is_int) && !is_int) { if (val.is_zero()) - return 0; + return nullptr; app * r; if (!mk_fresh_uncnstr_var_for(f, num, args, r)) return r; @@ -432,7 +432,7 @@ class elim_uncnstr_tactic : public tactic { } return r; } - return 0; + return nullptr; } app * process_arith_app(func_decl * f, unsigned num, expr * const * args) { @@ -450,13 +450,13 @@ class elim_uncnstr_tactic : public tactic { SASSERT(num == 2); return process_le_ge(f, args[0], args[1], false); default: - return 0; + return nullptr; } } app * process_bv_mul(func_decl * f, unsigned num, expr * const * args) { if (num == 0) - return 0; + return nullptr; if (uncnstr(num, args)) { sort * s = m().get_sort(args[0]); app * r; @@ -482,12 +482,12 @@ class elim_uncnstr_tactic : public tactic { add_def(args[1], m_bv_util.mk_bv_mul(m_bv_util.mk_numeral(inv, s), r)); return r; } - return 0; + return nullptr; } app * process_extract(func_decl * f, expr * arg) { if (!uncnstr(arg)) - return 0; + return nullptr; app * r; if (!mk_fresh_uncnstr_var_for(f, arg, r)) return r; @@ -523,14 +523,14 @@ class elim_uncnstr_tactic : public tactic { add_def(arg2, m_bv_util.mk_numeral(rational(1), s)); return r; } - return 0; + return nullptr; } app * process_concat(func_decl * f, unsigned num, expr * const * args) { if (num == 0) - return 0; + return nullptr; if (!uncnstr(num, args)) - return 0; + return nullptr; app * r; if (!mk_fresh_uncnstr_var_for(f, num, args, r)) return r; @@ -553,7 +553,7 @@ class elim_uncnstr_tactic : public tactic { // The result of bv_le is not just introducing a new fresh name, // we need a side condition. // TODO: the correct proof step - return 0; + return nullptr; } if (uncnstr(arg1)) { // v <= t @@ -593,7 +593,7 @@ class elim_uncnstr_tactic : public tactic { add_def(v, m().mk_ite(r, t, m_bv_util.mk_bv_sub(t, m_bv_util.mk_numeral(rational(1), bv_sz)))); return r; } - return 0; + return nullptr; } app * process_bv_app(func_decl * f, unsigned num, expr * const * args) { @@ -630,7 +630,7 @@ class elim_uncnstr_tactic : public tactic { add_def(args[0], m().mk_app(f, r)); return r; } - return 0; + return nullptr; case OP_BOR: if (num > 0 && uncnstr(num, args)) { sort * s = m().get_sort(args[0]); @@ -641,9 +641,9 @@ class elim_uncnstr_tactic : public tactic { add_defs(num, args, r, m_bv_util.mk_numeral(rational(0), s)); return r; } - return 0; + return nullptr; default: - return 0; + return nullptr; } } @@ -660,7 +660,7 @@ class elim_uncnstr_tactic : public tactic { add_def(args[0], m_ar_util.mk_const_array(s, r)); return r; } - return 0; + return nullptr; case OP_STORE: if (uncnstr(args[0]) && uncnstr(args[num-1])) { app * r; @@ -673,7 +673,7 @@ class elim_uncnstr_tactic : public tactic { return r; } default: - return 0; + return nullptr; } } @@ -700,7 +700,7 @@ class elim_uncnstr_tactic : public tactic { func_decl * c = m_dt_util.get_accessor_constructor(f); for (unsigned i = 0; i < c->get_arity(); i++) if (!m().is_fully_interp(c->get_domain(i))) - return 0; + return nullptr; app * u; if (!mk_fresh_uncnstr_var_for(f, num, args, u)) return u; @@ -730,7 +730,7 @@ class elim_uncnstr_tactic : public tactic { return u; } } - return 0; + return nullptr; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { @@ -745,7 +745,7 @@ class elim_uncnstr_tactic : public tactic { return BR_FAILED; // non-ground terms are not handled. } - app * u = 0; + app * u = nullptr; if (fid == m().get_basic_family_id()) u = process_basic_app(f, num, args); @@ -758,7 +758,7 @@ class elim_uncnstr_tactic : public tactic { else if (fid == m_dt_util.get_family_id()) u = process_datatype_app(f, num, args); - if (u == 0) + if (u == nullptr) return BR_FAILED; result = u; @@ -806,7 +806,7 @@ class elim_uncnstr_tactic : public tactic { void init_mc(bool produce_models) { if (!produce_models) { - m_mc = 0; + m_mc = nullptr; return; } m_mc = alloc(mc, m()); @@ -821,7 +821,7 @@ class elim_uncnstr_tactic : public tactic { model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); @@ -867,7 +867,7 @@ class elim_uncnstr_tactic : public tactic { } if (!modified) { if (round == 0) { - mc = 0; + mc = nullptr; } else { app_ref_vector & fresh_vars = m_rw->cfg().m_fresh_vars; @@ -879,11 +879,11 @@ class elim_uncnstr_tactic : public tactic { mc = concat(fmc, m_mc.get()); } else { - mc = 0; + mc = nullptr; } } - m_mc = 0; - m_rw = 0; + m_mc = nullptr; + m_rw = nullptr; TRACE("elim_uncnstr", if (mc) mc->display(tout);); result.push_back(g.get()); g->inc_depth(); diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp index e4c6408bd..342f16212 100644 --- a/src/tactic/core/injectivity_tactic.cpp +++ b/src/tactic/core/injectivity_tactic.cpp @@ -149,7 +149,7 @@ class injectivity_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(goal->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("injectivity", *goal); fail_if_unsat_core_generation("injectivity", goal); // TODO: Support UNSAT cores fail_if_proof_generation("injectivity", goal); diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index 1f2454d5e..4641023ad 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -33,13 +33,13 @@ class nnf_tactic : public tactic { } ~set_nnf() { - m_owner.m_nnf = 0; + m_owner.m_nnf = nullptr; } }; public: nnf_tactic(params_ref const & p): m_params(p), - m_nnf(0) { + m_nnf(nullptr) { TRACE("nnf", tout << "nnf_tactic constructor: " << p << "\n";); } @@ -60,7 +60,7 @@ public: expr_dependency_ref & core) override { TRACE("nnf", tout << "params: " << m_params << "\n"; g->display(tout);); SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("nnf", *g); bool produce_proofs = g->proofs_enabled(); @@ -89,9 +89,9 @@ public: sz = defs.size(); for (unsigned i = 0; i < sz; i++) { if (produce_proofs) - g->assert_expr(defs.get(i), def_prs.get(i), 0); + g->assert_expr(defs.get(i), def_prs.get(i), nullptr); else - g->assert_expr(defs.get(i), 0, 0); + g->assert_expr(defs.get(i), nullptr, nullptr); } g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/occf_tactic.cpp b/src/tactic/core/occf_tactic.cpp index 69e5e8fb2..519a4c580 100644 --- a/src/tactic/core/occf_tactic.cpp +++ b/src/tactic/core/occf_tactic.cpp @@ -68,7 +68,7 @@ class occf_tactic : public tactic { expr * m_bvar; unsigned m_gen_pos:1; unsigned m_gen_neg:1; - bvar_info():m_bvar(0), m_gen_pos(false), m_gen_neg(false) {} + bvar_info():m_bvar(nullptr), m_gen_pos(false), m_gen_neg(false) {} bvar_info(expr * var, bool sign): m_bvar(var), m_gen_pos(!sign), @@ -86,20 +86,20 @@ class occf_tactic : public tactic { } cnstr2bvar::obj_map_entry * entry = c2b.find_core(cnstr); - if (entry == 0) - return 0; + if (entry == nullptr) + return nullptr; bvar_info & info = entry->get_data().m_value; if (sign) { if (!info.m_gen_neg) { info.m_gen_neg = true; - g->assert_expr(m.mk_or(info.m_bvar, m.mk_not(cnstr)), 0, 0); + g->assert_expr(m.mk_or(info.m_bvar, m.mk_not(cnstr)), nullptr, nullptr); } return m.mk_not(info.m_bvar); } else { if (!info.m_gen_pos) { info.m_gen_pos = true; - g->assert_expr(m.mk_or(m.mk_not(info.m_bvar), cnstr), 0, 0); + g->assert_expr(m.mk_or(m.mk_not(info.m_bvar), cnstr), nullptr, nullptr); } return info.m_bvar; } @@ -113,16 +113,16 @@ class occf_tactic : public tactic { } SASSERT(!c2b.contains(cnstr)); - expr * bvar = m.mk_fresh_const(0, m.mk_bool_sort()); + expr * bvar = m.mk_fresh_const(nullptr, m.mk_bool_sort()); if (produce_models) m_mc->insert(to_app(bvar)->get_decl()); c2b.insert(cnstr, bvar_info(bvar, sign)); if (sign) { - g->assert_expr(m.mk_or(bvar, m.mk_not(cnstr)), 0, 0); + g->assert_expr(m.mk_or(bvar, m.mk_not(cnstr)), nullptr, nullptr); return m.mk_not(bvar); } else { - g->assert_expr(m.mk_or(m.mk_not(bvar), cnstr), 0, 0); + g->assert_expr(m.mk_or(m.mk_not(bvar), cnstr), nullptr, nullptr); return bvar; } } @@ -133,14 +133,14 @@ class occf_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; fail_if_proof_generation("occf", g); bool produce_models = g->models_enabled(); tactic_report report("occf", *g); - m_mc = 0; + m_mc = nullptr; ptr_vector new_lits; @@ -160,17 +160,17 @@ class occf_tactic : public tactic { m_mc = alloc(filter_model_converter, m); mc = m_mc; } - expr * keep = 0; + expr * keep = nullptr; new_lits.reset(); unsigned num = cls->get_num_args(); for (unsigned j = 0; j < num; j++) { expr * l = cls->get_arg(j); if (is_constraint(l)) { expr * new_l = get_aux_lit(c2b, l, g); - if (new_l != 0) { + if (new_l != nullptr) { new_lits.push_back(new_l); } - else if (keep == 0) { + else if (keep == nullptr) { keep = l; } else { @@ -182,9 +182,9 @@ class occf_tactic : public tactic { new_lits.push_back(l); } } - if (keep != 0) + if (keep != nullptr) new_lits.push_back(keep); - g->update(i, m.mk_or(new_lits.size(), new_lits.c_ptr()), 0, d); + g->update(i, m.mk_or(new_lits.size(), new_lits.c_ptr()), nullptr, d); } g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 5f128d378..8dfad6fe2 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -148,7 +148,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); - pc = 0; core = 0; + pc = nullptr; core = nullptr; if (g->proofs_enabled()) { throw tactic_exception("pb-preprocess does not support proofs"); @@ -250,7 +250,7 @@ public: if (!to_ge(g->form(k), args2, coeffs2, k2)) continue; if (subsumes(args1, coeffs1, k1, args2, coeffs2, k2)) { IF_VERBOSE(3, verbose_stream() << "replace " << mk_pp(g->form(k), m) << "\n";); - g->update(k, m.mk_true(), 0, m.mk_join(g->dep(m_ge[i]), g->dep(k))); + g->update(k, m.mk_true(), nullptr, m.mk_join(g->dep(m_ge[i]), g->dep(k))); m_progress = true; } } @@ -328,12 +328,12 @@ private: for (unsigned j = 0; j < cuts.size(); ++j) { unsigned end = cuts[j]; fml1 = decompose_cut(a, start, end, cut_args, cut_coeffs); - g->assert_expr(fml1, 0, g->dep(i)); + g->assert_expr(fml1, nullptr, g->dep(i)); start = end; TRACE("pb", tout << fml1 << "\n";); } fml2 = pb.mk_ge(cut_args.size(), cut_coeffs.c_ptr(), cut_args.c_ptr(), pb.get_k(e)); - g->update(i, fml2, 0, g->dep(i)); + g->update(i, fml2, nullptr, g->dep(i)); TRACE("pb", tout << fml2 << "\n";); } } @@ -578,8 +578,8 @@ private: tout << "resolve: " << mk_pp(fml1, m) << "\n" << mk_pp(fml2, m) << "\n" << tmp1 << "\n"; tout << "to\n" << mk_pp(fml2, m) << " -> " << tmp2 << "\n";); - g->update(idx2, tmp2, 0, m.mk_join(g->dep(idx1), g->dep(idx2))); - g->update(idx1, m.mk_true(), 0, 0); + g->update(idx2, tmp2, nullptr, m.mk_join(g->dep(idx1), g->dep(idx2))); + g->update(idx1, m.mk_true(), nullptr, nullptr); m_progress = true; //IF_VERBOSE(0, if (!g->inconsistent()) display_annotation(verbose_stream(), g);); } @@ -651,7 +651,7 @@ private: } } } - m_r.set_substitution(0); + m_r.set_substitution(nullptr); } bool subsumes(expr_ref_vector const& args1, diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 39333226b..e2a6e18de 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -38,7 +38,7 @@ class propagate_values_tactic : public tactic { imp(ast_manager & m, params_ref const & p): m(m), m_r(m, p), - m_goal(0), + m_goal(nullptr), m_occs(m, true /* track atoms */) { updt_params_core(p); } @@ -92,7 +92,7 @@ class propagate_values_tactic : public tactic { if (m_goal->unsat_core_enabled()) { new_d = m_goal->dep(m_idx); expr_dependency * used_d = m_r.get_used_dependencies(); - if (used_d != 0) { + if (used_d != nullptr) { new_d = m.mk_join(new_d, used_d); m_r.reset_used_dependencies(); } @@ -141,7 +141,7 @@ class propagate_values_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("propagate-values", *g); m_goal = g.get(); @@ -210,7 +210,7 @@ class propagate_values_tactic : public tactic { SASSERT(m_goal->is_well_sorted()); TRACE("propagate_values", tout << "end\n"; m_goal->display(tout);); TRACE("propagate_values_core", m_goal->display_with_dependencies(tout);); - m_goal = 0; + m_goal = nullptr; } }; diff --git a/src/tactic/core/reduce_args_tactic.cpp b/src/tactic/core/reduce_args_tactic.cpp index a7aadedbe..333e2638c 100644 --- a/src/tactic/core/reduce_args_tactic.cpp +++ b/src/tactic/core/reduce_args_tactic.cpp @@ -104,7 +104,7 @@ struct reduce_args_tactic::imp { } static bool may_be_unique(ast_manager& m, bv_util& bv, expr* e, expr*& base) { - base = 0; + base = nullptr; return m.is_unique_value(e) || is_var_plus_offset(m, bv, e, base); } @@ -341,7 +341,7 @@ struct reduce_args_tactic::imp { } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; if (f->get_arity() == 0) return BR_FAILED; // ignore constants if (f->get_family_id() != null_family_id) @@ -357,7 +357,7 @@ struct reduce_args_tactic::imp { } app_ref tmp(m.mk_app(f, num, args), m); - func_decl *& new_f = map->insert_if_not_there2(tmp, 0)->get_data().m_value; + func_decl *& new_f = map->insert_if_not_there2(tmp, nullptr)->get_data().m_value; if (!new_f) { // create fresh symbol ptr_buffer domain; @@ -401,7 +401,7 @@ struct reduce_args_tactic::imp { for (; it != end; ++it) { func_decl * f = it->m_key; arg2func * map = it->m_value; - expr * def = 0; + expr * def = nullptr; SASSERT(decl2args.contains(f)); bit_vector & bv = decl2args.find(f); new_vars.reset(); @@ -419,7 +419,7 @@ struct reduce_args_tactic::imp { f_mc->insert(new_def); SASSERT(new_def->get_arity() == new_args.size()); app * new_t = m_manager.mk_app(new_def, new_args.size(), new_args.c_ptr()); - if (def == 0) { + if (def == nullptr) { def = new_t; } else { @@ -494,7 +494,7 @@ void reduce_args_tactic::operator()(goal_ref const & g, SASSERT(g->is_well_sorted()); fail_if_proof_generation("reduce-args", g); fail_if_unsat_core_generation("reduce-args", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); m_imp->operator()(*(g.get()), mc); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/simplify_tactic.cpp b/src/tactic/core/simplify_tactic.cpp index de1fcc99c..842e1127d 100644 --- a/src/tactic/core/simplify_tactic.cpp +++ b/src/tactic/core/simplify_tactic.cpp @@ -101,7 +101,7 @@ void simplify_tactic::operator()(goal_ref const & in, (*m_imp)(*(in.get())); in->inc_depth(); result.push_back(in.get()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; } catch (rewriter_exception & ex) { throw tactic_exception(ex.msg()); diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index a6346185f..9253b7172 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -53,12 +53,12 @@ class solve_eqs_tactic : public tactic { imp(ast_manager & m, params_ref const & p, expr_replacer * r, bool owner): m_manager(m), m_r(r), - m_r_owner(r == 0 || owner), + m_r_owner(r == nullptr || owner), m_a_util(m), m_num_steps(0), m_num_eliminated_vars(0) { updt_params(p); - if (m_r == 0) + if (m_r == nullptr) m_r = mk_default_expr_replacer(m); } @@ -98,7 +98,7 @@ class solve_eqs_tactic : public tactic { if (is_uninterp_const(lhs) && !m_candidate_vars.is_marked(lhs) && !occurs(lhs, rhs) && check_occs(lhs)) { var = to_app(lhs); def = rhs; - pr = 0; + pr = nullptr; return true; } else { @@ -333,7 +333,7 @@ class solve_eqs_tactic : public tactic { } bool solve(expr * f, app_ref & var, expr_ref & def, proof_ref & pr) { - expr* arg1 = 0, *arg2 = 0; + expr* arg1 = nullptr, *arg2 = nullptr; if (m().is_eq(f, arg1, arg2)) { if (trivial_solve(arg1, arg2, var, def, pr)) return true; @@ -393,7 +393,7 @@ class solve_eqs_tactic : public tactic { void collect(goal const & g) { m_subst->reset(); m_norm_subst->reset(); - m_r->set_substitution(0); + m_r->set_substitution(nullptr); m_candidate_vars.reset(); m_candidate_set.reset(); m_candidates.reset(); @@ -499,7 +499,7 @@ class solve_eqs_tactic : public tactic { // Must save t and its definition. // See comment in the beginning of the function - expr * def = 0; + expr * def = nullptr; proof * pr; expr_dependency * dep; m_subst->find(to_app(t), def, pr, dep); @@ -513,7 +513,7 @@ class solve_eqs_tactic : public tactic { else { visiting.mark(t); fr.second = 1; - expr * def = 0; + expr * def = nullptr; proof * pr; expr_dependency * dep; m_subst->find(to_app(t), def, pr, dep); @@ -587,9 +587,9 @@ class solve_eqs_tactic : public tactic { for (unsigned idx = 0; idx < size; idx++) { checkpoint(); expr * v = m_ordered_vars[idx]; - expr * def = 0; - proof * pr = 0; - expr_dependency * dep = 0; + expr * def = nullptr; + proof * pr = nullptr; + expr_dependency * dep = nullptr; m_subst->find(v, def, pr, dep); SASSERT(def != 0); m_r->operator()(def, new_def, new_pr, new_dep); @@ -645,7 +645,7 @@ class solve_eqs_tactic : public tactic { // so, we must remove remove the mark before doing the update m_candidate_set.mark(f, false); SASSERT(!m_candidate_set.is_marked(f)); - g.update(idx, m().mk_true(), m().mk_true_proof(), 0); + g.update(idx, m().mk_true(), m().mk_true_proof(), nullptr); m_num_steps ++; continue; } @@ -681,10 +681,10 @@ class solve_eqs_tactic : public tactic { IF_VERBOSE(100, if (!m_ordered_vars.empty()) verbose_stream() << "num. eliminated vars: " << m_ordered_vars.size() << "\n";); m_num_eliminated_vars += m_ordered_vars.size(); if (m_produce_models) { - if (mc.get() == 0) + if (mc.get() == nullptr) mc = alloc(gmc, m()); for (app* v : m_ordered_vars) { - expr * def = 0; + expr * def = nullptr; proof * pr; expr_dependency * dep; m_norm_subst->find(v, def, pr, dep); @@ -748,7 +748,7 @@ class solve_eqs_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("solve_eqs", *g); m_produce_models = g->models_enabled(); m_produce_proofs = g->proofs_enabled(); @@ -768,7 +768,7 @@ class solve_eqs_tactic : public tactic { normalize(); substitute(*(g.get())); if (g->inconsistent()) { - mc = 0; + mc = nullptr; break; } save_elim_vars(mc); @@ -823,7 +823,7 @@ public: ast_manager & m = m_imp->m(); expr_replacer * r = m_imp->m_r; if (r) - r->set_substitution(0); + r->set_substitution(nullptr); bool owner = m_imp->m_r_owner; m_imp->m_r_owner = false; // stole replacer @@ -844,7 +844,7 @@ public: }; tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p, expr_replacer * r) { - if (r == 0) + if (r == nullptr) return clean(alloc(solve_eqs_tactic, m, p, mk_expr_simp_replacer(m, p), true)); else return clean(alloc(solve_eqs_tactic, m, p, r, false)); diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index 084942ed2..a84ffdd43 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -24,7 +24,7 @@ class ast_manager; class tactic; class expr_replacer; -tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref(), expr_replacer * r = 0); +tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p = params_ref(), expr_replacer * r = nullptr); /* ADD_TACTIC("solve-eqs", "eliminate variables by solving equations.", "mk_solve_eqs_tactic(m, p)") diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index 5986ca392..37d9e902e 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -111,7 +111,7 @@ public: SASSERT(in->is_well_sorted()); tactic_report report("split-clause", *in); TRACE("before_split_clause", in->display(tout);); - pc = 0; mc = 0; core = 0; + pc = nullptr; mc = nullptr; core = nullptr; ast_manager & m = in->m(); unsigned cls_pos = select_clause(m, in); if (cls_pos == UINT_MAX) { @@ -131,7 +131,7 @@ public: else subgoal_i = alloc(goal, *in); expr * lit_i = cls->get_arg(i); - proof * pr_i = 0; + proof * pr_i = nullptr; if (produce_proofs) pr_i = m.mk_hypothesis(lit_i); subgoal_i->update(cls_pos, lit_i, pr_i, cls_dep); diff --git a/src/tactic/core/symmetry_reduce_tactic.cpp b/src/tactic/core/symmetry_reduce_tactic.cpp index 1bc3fde60..81f626f38 100644 --- a/src/tactic/core/symmetry_reduce_tactic.cpp +++ b/src/tactic/core/symmetry_reduce_tactic.cpp @@ -88,7 +88,7 @@ struct ac_rewriter_cfg : public default_rewriter_cfg { bool rewrite_patterns() const { return false; } bool flat_assoc(func_decl * f) const { return false; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - result_pr = 0; + result_pr = nullptr; return m_r.mk_app_core(f, num, args, result); } ac_rewriter_cfg(ast_manager & m):m_r(m) {} @@ -475,7 +475,7 @@ private: T.reset(); ptr_vector todo; todo.push_back(fml); - app* t = 0; + app* t = nullptr; while (!todo.empty()) { fml = todo.back(); todo.pop_back(); @@ -490,24 +490,24 @@ private: bool is_range_restriction(expr* form, term_set const& C, app*& t) { if (!m().is_or(form)) return false; unsigned sz = to_app(form)->get_num_args(); - t = 0; + t = nullptr; for (unsigned i = 0; i < sz; ++i) { expr* e = to_app(form)->get_arg(i); expr* e1, *e2; if (!m().is_eq(e, e1, e2)) return false; if (!is_app(e1) || !is_app(e2)) return false; app* a1 = to_app(e1), *a2 = to_app(e2); - if (C.contains(a1) && (t == 0 || t == a2)) { + if (C.contains(a1) && (t == nullptr || t == a2)) { t = a2; } - else if (C.contains(a2) && (t == 0 || t == a1)) { + else if (C.contains(a2) && (t == nullptr || t == a1)) { t = a1; } else { return false; } } - return t != 0; + return t != nullptr; } @@ -641,7 +641,7 @@ void symmetry_reduce_tactic::operator()(goal_ref const & g, expr_dependency_ref & core) { fail_if_proof_generation("symmetry_reduce", g); fail_if_unsat_core_generation("symmetry_reduce", g); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); (*m_imp)(*(g.get())); g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index af0143488..6efce9d4e 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -177,7 +177,7 @@ class tseitin_cnf_tactic : public tactic { goto start; case OP_OR: case OP_IFF: - l = 0; + l = nullptr; m_cache.find(to_app(n), l); SASSERT(l != 0); mk_lit(l, sign, r); @@ -185,7 +185,7 @@ class tseitin_cnf_tactic : public tactic { case OP_ITE: case OP_EQ: if (m.is_bool(to_app(n)->get_arg(1))) { - l = 0; + l = nullptr; m_cache.find(to_app(n), l); SASSERT(l != 0); mk_lit(l, sign, r); @@ -341,7 +341,7 @@ class tseitin_cnf_tactic : public tactic { app * mk_fresh() { m_num_aux_vars++; - app * v = m.mk_fresh_const(0, m.mk_bool_sort()); + app * v = m.mk_fresh_const(nullptr, m.mk_bool_sort()); m_fresh_vars.push_back(v); if (m_mc) m_mc->insert(v->get_decl()); @@ -804,7 +804,7 @@ class tseitin_cnf_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("tseitin-cnf", *g); fail_if_proof_generation("tseitin-cnf", g); m_produce_models = g->models_enabled(); @@ -819,12 +819,12 @@ class tseitin_cnf_tactic : public tactic { if (m_produce_models) m_mc = alloc(filter_model_converter, m); else - m_mc = 0; + m_mc = nullptr; unsigned size = g->size(); for (unsigned idx = 0; idx < size; idx++) { process(g->form(idx), g->dep(idx)); - g->update(idx, m.mk_true(), 0, 0); // to save memory + g->update(idx, m.mk_true(), nullptr, nullptr); // to save memory } SASSERT(!m_produce_unsat_cores || m_clauses.size() == m_deps.size()); @@ -838,14 +838,14 @@ class tseitin_cnf_tactic : public tactic { continue; added.mark(cls); if (m_produce_unsat_cores) - g->assert_expr(cls, 0, m_deps.get(i)); + g->assert_expr(cls, nullptr, m_deps.get(i)); else g->assert_expr(cls); } if (m_produce_models && !m_fresh_vars.empty()) mc = m_mc.get(); else - mc = 0; + mc = nullptr; g->inc_depth(); result.push_back(g.get()); TRACE("tseitin_cnf", g->display(tout);); diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index cf26f53db..9fad9259d 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -55,7 +55,7 @@ public: protected: fpa2bv_model_converter(ast_manager & m) : m(m), - m_bv2fp(0) {} + m_bv2fp(nullptr) {} void convert(model_core * mc, model * float_mdl); }; diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 7cd4a404c..3c656c6b8 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -56,7 +56,7 @@ class fpa2bv_tactic : public tactic { m_produce_models = g->models_enabled(); m_produce_unsat_cores = g->unsat_core_enabled(); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); tactic_report report("fpa2bv", *g); m_rw.reset(); diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index ea8d14bd0..a8c2452e6 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -137,10 +137,10 @@ void goal::push_back(expr * f, proof * pr, expr_dependency * d) { } void goal::quick_process(bool save_first, expr_ref& f, expr_dependency * d) { - expr* g = 0; + expr* g = nullptr; if (!m().is_and(f) && !(m().is_not(f, g) && m().is_or(g))) { if (!save_first) { - push_back(f, 0, d); + push_back(f, nullptr, d); } return; } @@ -184,7 +184,7 @@ void goal::quick_process(bool save_first, expr_ref& f, expr_dependency * d) { save_first = false; } else { - push_back(curr, 0, d); + push_back(curr, nullptr, d); } } } @@ -253,7 +253,7 @@ void goal::assert_expr(expr * f, proof * pr, expr_dependency * d) { } void goal::assert_expr(expr * f, expr_dependency * d) { - assert_expr(f, proofs_enabled() ? m().mk_asserted(f) : 0, d); + assert_expr(f, proofs_enabled() ? m().mk_asserted(f) : nullptr, d); } void goal::get_formulas(ptr_vector & result) { @@ -289,7 +289,7 @@ void goal::update(unsigned i, expr * f, proof * pr, expr_dependency * d) { quick_process(true, fr, d); if (!m_inconsistent) { if (m().is_false(fr)) { - push_back(f, 0, d); + push_back(f, nullptr, d); } else { m().set(m_forms, i, fr); @@ -575,7 +575,7 @@ void goal::elim_redundancies() { if (neg_lits.is_marked(atom)) continue; if (pos_lits.is_marked(atom)) { - proof * p = 0; + proof * p = nullptr; if (proofs_enabled()) { proof * prs[2] = { pr(get_idx(atom)), pr(i) }; p = m().mk_unit_resolution(2, prs); @@ -592,7 +592,7 @@ void goal::elim_redundancies() { if (pos_lits.is_marked(f)) continue; if (neg_lits.is_marked(f)) { - proof * p = 0; + proof * p = nullptr; if (proofs_enabled()) { proof * prs[2] = { pr(get_not_idx(f)), pr(i) }; p = m().mk_unit_resolution(2, prs); diff --git a/src/tactic/goal.h b/src/tactic/goal.h index c9de9c037..529ece72c 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -107,17 +107,17 @@ public: void assert_expr(expr * f, proof * pr, expr_dependency * d); void assert_expr(expr * f, expr_dependency * d); void assert_expr(expr * f, expr * d) { assert_expr(f, m().mk_leaf(d)); } - void assert_expr(expr * f) { assert_expr(f, static_cast(0)); } + void assert_expr(expr * f) { assert_expr(f, static_cast(nullptr)); } unsigned size() const { return m().size(m_forms); } unsigned num_exprs() const; expr * form(unsigned i) const { return m().get(m_forms, i); } - proof * pr(unsigned i) const { return proofs_enabled() ? static_cast(m().get(m_proofs, i)) : 0; } - expr_dependency * dep(unsigned i) const { return unsat_core_enabled() ? m().get(m_dependencies, i) : 0; } + proof * pr(unsigned i) const { return proofs_enabled() ? static_cast(m().get(m_proofs, i)) : nullptr; } + expr_dependency * dep(unsigned i) const { return unsat_core_enabled() ? m().get(m_dependencies, i) : nullptr; } - void update(unsigned i, expr * f, proof * pr = 0, expr_dependency * dep = 0); + void update(unsigned i, expr * f, proof * pr = nullptr, expr_dependency * dep = nullptr); void get_formulas(ptr_vector & result); diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 351fbcce7..b295a98b7 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -47,9 +47,9 @@ public: }; model_converter * concat(model_converter * mc1, model_converter * mc2) { - if (mc1 == 0) + if (mc1 == nullptr) return mc2; - if (mc2 == 0) + if (mc2 == nullptr) return mc1; return alloc(concat_model_converter, mc1, mc2); } @@ -114,7 +114,7 @@ model_converter * concat(model_converter * mc1, unsigned num, model_converter * return concat(mc1, mc2s[0]); unsigned i; for (i = 0; i < num; i++) { - if (mc2s[i] != 0) + if (mc2s[i] != nullptr) break; } if (i == num) { @@ -162,14 +162,14 @@ public: }; model_converter * model2model_converter(model * m) { - if (m == 0) - return 0; + if (m == nullptr) + return nullptr; return alloc(model2mc, m); } model_converter * model_and_labels2model_converter(model * m, buffer & r) { - if (m == 0) - return 0; + if (m == nullptr) + return nullptr; return alloc(model2mc, m, r); } diff --git a/src/tactic/nlsat_smt/nl_purify_tactic.cpp b/src/tactic/nlsat_smt/nl_purify_tactic.cpp index 828758caa..745b0352d 100644 --- a/src/tactic/nlsat_smt/nl_purify_tactic.cpp +++ b/src/tactic/nlsat_smt/nl_purify_tactic.cpp @@ -131,7 +131,7 @@ public: m_interface_cache.insert(arg, arg); return arg; } - r = m.mk_fresh_const(0, u().mk_real()); + r = m.mk_fresh_const(nullptr, u().mk_real()); m_new_reals.push_back(to_app(r)); m_owner.m_fmc->insert(to_app(r)->get_decl()); m_interface_cache.insert(arg, r); @@ -156,7 +156,7 @@ public: void mk_interface_bool(func_decl * f, unsigned num, expr* const* args, expr_ref& result, proof_ref& pr) { expr_ref old_pred(m.mk_app(f, num, args), m); polarity_t pol = m_polarities.find(old_pred); - result = m.mk_fresh_const(0, m.mk_bool_sort()); + result = m.mk_fresh_const(nullptr, m.mk_bool_sort()); m_polarities.insert(result, pol); m_new_preds.push_back(to_app(result)); m_owner.m_fmc->insert(to_app(result)->get_decl()); @@ -425,8 +425,8 @@ private: void core2result(expr_dependency_ref & lcore, goal_ref const& g, goal_ref_buffer& result) { result.reset(); - proof * pr = 0; - lcore = 0; + proof * pr = nullptr; + lcore = nullptr; g->reset(); obj_hashtable::iterator it = m_used_asms.begin(), end = m_used_asms.end(); for (; it != end; ++it) { @@ -488,7 +488,7 @@ private: nums.push_back(r); if (num2var.find(r, v)) { if (!m_eq_pairs.find(v, w, pred)) { - pred = m.mk_fresh_const(0, m.mk_bool_sort()); + pred = m.mk_fresh_const(nullptr, m.mk_bool_sort()); m_eq_preds.push_back(pred); m_eq_values.push_back(l_true); m_fmc->insert(to_app(pred)->get_decl()); @@ -558,7 +558,7 @@ private: } void translate(expr_safe_replace& num2num, expr* e, expr_ref& result) { - result = 0; + result = nullptr; if (e) { num2num(e, result); } @@ -699,9 +699,9 @@ public: m(m), m_util(m), m_params(p), - m_fmc(0), + m_fmc(nullptr), m_nl_tac(mk_nlsat_tactic(m, p)), - m_nl_g(0), + m_nl_g(nullptr), m_solver(mk_smt_solver(m, p, symbol::null)), m_eq_preds(m), m_new_reals(m), @@ -754,7 +754,7 @@ public: TRACE("nlsat_smt", g->display(tout);); m_produce_proofs = g->proofs_enabled(); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; fail_if_proof_generation("qfufnra-purify", g); // fail_if_unsat_core_generation("qfufnra-purify", g); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 7b82772c5..170780ab0 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -167,7 +167,7 @@ public: // translate bit-vector consequences back to integer values for (unsigned i = 0; i < consequences.size(); ++i) { - expr* a = 0, *b = 0, *u = 0, *v = 0; + expr* a = nullptr, *b = nullptr, *u = nullptr, *v = nullptr; func_decl* f; rational num; unsigned bvsize; diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 029914b88..3f4a20774 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -114,7 +114,7 @@ public: // translate enumeration constants to bit-vectors. for (unsigned i = 0; i < vars.size(); ++i) { - func_decl* f = 0; + func_decl* f = nullptr; if (is_app(vars[i]) && is_uninterp_const(vars[i]) && m_rewriter.enum2bv().find(to_app(vars[i])->get_decl(), f)) { bvars.push_back(m.mk_const(f)); } @@ -126,7 +126,7 @@ public: // translate bit-vector consequences back to enumeration types for (unsigned i = 0; i < consequences.size(); ++i) { - expr* a = 0, *b = 0, *u = 0, *v = 0; + expr* a = nullptr, *b = nullptr, *u = nullptr, *v = nullptr; func_decl* f; rational num; unsigned bvsize; diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index aa699695e..e436b6143 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -104,7 +104,7 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const static solver* mk_special_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { if ((logic == "QF_FD" || logic == "SAT") && !m.proofs_enabled()) return mk_fd_solver(m, p); - return 0; + return nullptr; } static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) { diff --git a/src/tactic/probe.cpp b/src/tactic/probe.cpp index c9863c9b1..dcd1dc500 100644 --- a/src/tactic/probe.cpp +++ b/src/tactic/probe.cpp @@ -411,7 +411,7 @@ class num_consts_probe : public probe { family_id m_fid; unsigned m_counter; proc(ast_manager & _m, bool b, char const * family):m(_m), m_bool(b), m_counter(0) { - if (family != 0) + if (family != nullptr) m_fid = m.mk_family_id(family); else m_fid = null_family_id; @@ -454,11 +454,11 @@ public: }; probe * mk_num_consts_probe() { - return alloc(num_consts_probe, false, 0); + return alloc(num_consts_probe, false, nullptr); } probe * mk_num_bool_consts_probe() { - return alloc(num_consts_probe, true, 0); + return alloc(num_consts_probe, true, nullptr); } probe * mk_num_arith_consts_probe() { diff --git a/src/tactic/proof_converter.cpp b/src/tactic/proof_converter.cpp index 5ac48def0..26a87fe04 100644 --- a/src/tactic/proof_converter.cpp +++ b/src/tactic/proof_converter.cpp @@ -38,9 +38,9 @@ public: }; proof_converter * concat(proof_converter * pc1, proof_converter * pc2) { - if (pc1 == 0) + if (pc1 == nullptr) return pc2; - if (pc2 == 0) + if (pc2 == nullptr) return pc1; return alloc(concat_proof_converter, pc1, pc2); } @@ -97,7 +97,7 @@ proof_converter * concat(proof_converter * pc1, unsigned num, proof_converter * return concat(pc1, pc2s[0]); unsigned i; for (i = 0; i < num; i++) { - if (pc2s[i] != 0) + if (pc2s[i] != nullptr) break; } if (i == num) { @@ -128,8 +128,8 @@ public: }; proof_converter * proof2proof_converter(ast_manager & m, proof * pr) { - if (pr == 0) - return 0; + if (pr == nullptr) + return nullptr; return alloc(proof2pc, m, pr); } @@ -155,7 +155,7 @@ void apply(ast_manager & m, proof_converter_ref & pc1, proof_converter_ref_buffe for (unsigned i = 0; i < sz; i++) { proof_ref pr(m); SASSERT(pc2s[i]); // proof production is enabled - pc2s[i]->operator()(m, 0, 0, pr); + pc2s[i]->operator()(m, 0, nullptr, pr); prs.push_back(pr); } (*pc1)(m, sz, prs.c_ptr(), result); diff --git a/src/tactic/replace_proof_converter.cpp b/src/tactic/replace_proof_converter.cpp index 98f28bb1b..ba74452cf 100644 --- a/src/tactic/replace_proof_converter.cpp +++ b/src/tactic/replace_proof_converter.cpp @@ -39,7 +39,7 @@ public: replace_map(ast_manager& m): map_proc(m) {} void insert(expr* src, expr* dst) { - m_map.insert(src, dst, 0); + m_map.insert(src, dst, nullptr); } void operator()(var* v) { visit(v); } diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 4aecc0274..88792e955 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -53,7 +53,7 @@ public: model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; TRACE("sine", g->display(tout);); TRACE("sine", tout << g->size();); @@ -62,7 +62,7 @@ public: TRACE("sine", tout << new_forms.size();); g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) { - g->assert_expr(new_forms.get(i), 0, 0); + g->assert_expr(new_forms.get(i), nullptr, nullptr); } g->inc_depth(); g->updt_prec(goal::OVER); diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/tactic/sls/bvsls_opt_engine.cpp index 502bcbde6..37454ca72 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/tactic/sls/bvsls_opt_engine.cpp @@ -43,7 +43,7 @@ bvsls_opt_engine::optimization_result bvsls_opt_engine::optimize( m_hard_tracker.initialize(m_assertions); setup_opt_tracker(objective, _maximize); - if (initial_model.get() != 0) { + if (initial_model.get() != nullptr) { TRACE("sls_opt", tout << "Initial model provided: " << std::endl; for (unsigned i = 0; i < initial_model->get_num_constants(); i++) { func_decl * fd = initial_model->get_constant(i); diff --git a/src/tactic/sls/sls_engine.cpp b/src/tactic/sls/sls_engine.cpp index 4e1c6a693..7836ab70f 100644 --- a/src/tactic/sls/sls_engine.cpp +++ b/src/tactic/sls/sls_engine.cpp @@ -537,7 +537,7 @@ bailout: void sls_engine::operator()(goal_ref const & g, model_converter_ref & mc) { if (g->inconsistent()) { - mc = 0; + mc = nullptr; return; } @@ -565,7 +565,7 @@ void sls_engine::operator()(goal_ref const & g, model_converter_ref & mc) { g->reset(); } else - mc = 0; + mc = nullptr; } lbool sls_engine::operator()() { diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index aaf4c24c0..fa9ea4e4a 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -65,7 +65,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; result.reset(); + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); TRACE("sls", g->display(tout);); tactic_report report("sls", *g); diff --git a/src/tactic/sls/sls_tracker.h b/src/tactic/sls/sls_tracker.h index 15f06f096..b730e78da 100644 --- a/src/tactic/sls/sls_tracker.h +++ b/src/tactic/sls/sls_tracker.h @@ -40,7 +40,7 @@ class sls_tracker { mpz m_zero, m_one, m_two; struct value_score { - value_score() : m(0), value(unsynch_mpz_manager::mk_z(0)), score(0.0), score_prune(0.0), has_pos_occ(0), has_neg_occ(0), distance(0), touched(1) {}; + value_score() : m(nullptr), value(unsynch_mpz_manager::mk_z(0)), score(0.0), score_prune(0.0), has_pos_occ(0), has_neg_occ(0), distance(0), touched(1) {}; value_score(value_score && other) : m(other.m), value(std::move(other.value)), @@ -1038,7 +1038,7 @@ public: if (m_mpz_manager.neq(get_value(as[0]), m_one)) return as[0]; else - return 0; + return nullptr; } m_temp_constants.reset(); @@ -1061,7 +1061,7 @@ public: } } if (pos == static_cast(-1)) - return 0; + return nullptr; m_touched++; m_scores.find(as[pos]).touched++; @@ -1082,7 +1082,7 @@ public: for (unsigned i = 0; i < sz; i++) if (m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; if (pos == static_cast(-1)) - return 0; + return nullptr; } m_last_pos = pos; @@ -1092,7 +1092,7 @@ public: expr * get_new_unsat_assertion(ptr_vector const & as) { unsigned sz = as.size(); if (sz == 1) - return 0; + return nullptr; m_temp_constants.reset(); unsigned cnt_unsat = 0, pos = -1; @@ -1100,7 +1100,7 @@ public: if ((i != m_last_pos) && m_mpz_manager.neq(get_value(as[i]), m_one) && (get_random_uint(16) % ++cnt_unsat == 0)) pos = i; if (pos == static_cast(-1)) - return 0; + return nullptr; return as[pos]; } }; diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index 1d3f251a4..bc2f55061 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -58,7 +58,7 @@ public: model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override { - mc = 0; + mc = nullptr; ast_manager& m(g->m()); tactic_report report("qfufbv_ackr", *g); fail_if_unsat_core_generation("qfufbv_ackr", g); @@ -111,7 +111,7 @@ private: bool m_inc_use_sat; solver* setup_sat() { - solver * sat(NULL); + solver * sat(nullptr); if (m_use_sat) { if (m_inc_use_sat) { sat = mk_inc_sat_solver(m_m, m_p); diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index 7ccd44e7d..da063de39 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -53,7 +53,7 @@ tactic_report::tactic_report(char const * id, goal const & g) { if (get_verbosity_level() >= TACTIC_VERBOSITY_LVL) m_imp = alloc(imp, id, g); else - m_imp = 0; + m_imp = nullptr; } tactic_report::~tactic_report() { @@ -74,9 +74,9 @@ void skip_tactic::operator()(goal_ref const & in, expr_dependency_ref & core) { result.reset(); result.push_back(in.get()); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; } tactic * mk_skip_tactic() { @@ -179,9 +179,9 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p bool models_enabled = g->models_enabled(); bool proofs_enabled = g->proofs_enabled(); bool cores_enabled = g->unsat_core_enabled(); - md = 0; - pr = 0; - core = 0; + md = nullptr; + pr = nullptr; + core = nullptr; ast_manager & m = g->m(); goal_ref_buffer r; model_converter_ref mc; diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index fe0c7385f..8aa2f400a 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -122,9 +122,9 @@ public: proof_converter_ref pc1; expr_dependency_ref core1(m); result.reset(); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; m_t1->operator()(in, r1, mc1, pc1, core1); SASSERT(!is_decided(r1) || (!pc1 && !core1)); // the pc and core of decided goals is 0 unsigned r1_size = r1.size(); @@ -176,7 +176,7 @@ public: // pc2 and core2 must be 0. SASSERT(!pc2); SASSERT(!core2); - if (models_enabled) mc_buffer.push_back(0); + if (models_enabled) mc_buffer.push_back(nullptr); if (proofs_enabled) pc_buffer.push_back(proof2proof_converter(m, r2[0]->pr(0))); if (models_enabled || proofs_enabled) sz_buffer.push_back(0); if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); @@ -200,7 +200,7 @@ public: apply(m, pc1, pc_buffer, pr); SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); - core = 0; + core = nullptr; result.push_back(in.get()); SASSERT(!mc); SASSERT(!pc); SASSERT(!core); } @@ -380,9 +380,9 @@ public: for (i = 0; i < sz; i++) { tactic * t = m_ts[i]; result.reset(); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; SASSERT(sz > 0); if (i < sz - 1) { try { @@ -536,8 +536,8 @@ public: for (unsigned k = 0; k < _result.size(); k++) { result.push_back(_result[k]->translate(translator)); } - mc = _mc ? _mc->translate(translator) : 0; - pc = _pc ? _pc->translate(translator) : 0; + mc = _mc ? _mc->translate(translator) : nullptr; + pc = _pc ? _pc->translate(translator) : nullptr; expr_dependency_translation td(translator); core = td(_core); } @@ -562,7 +562,7 @@ public: } } if (finished_id == UINT_MAX) { - mc = 0; + mc = nullptr; switch (ex_kind) { case ERROR_EX: throw z3_error(error_code); case TACTIC_EX: throw tactic_exception(ex_msg.c_str()); @@ -626,9 +626,9 @@ public: proof_converter_ref pc1; expr_dependency_ref core1(m); result.reset(); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; m_t1->operator()(in, r1, mc1, pc1, core1); SASSERT(!is_decided(r1) || (!pc1 && !core1)); // the pc and core of decided goals is 0 unsigned r1_size = r1.size(); @@ -759,7 +759,7 @@ public: result.push_back(r2[0]->translate(translator)); if (models_enabled) { // mc2 contains the actual model - mc2 = mc2 ? mc2->translate(translator) : 0; + mc2 = mc2 ? mc2->translate(translator) : nullptr; model_ref md; md = alloc(model, m); apply(mc2, md, 0); @@ -776,12 +776,12 @@ public: SASSERT(!pc2); SASSERT(!core2); - if (models_enabled) mc_buffer.set(i, 0); + if (models_enabled) mc_buffer.set(i, nullptr); if (proofs_enabled) { proof * pr = r2[0]->pr(0); pc_buffer.push_back(proof2proof_converter(m, pr)); } - if (cores_enabled && r2[0]->dep(0) != 0) { + if (cores_enabled && r2[0]->dep(0) != nullptr) { expr_dependency_ref * new_dep = alloc(expr_dependency_ref, new_m); *new_dep = r2[0]->dep(0); core_buffer.set(i, new_dep); @@ -815,12 +815,12 @@ public: if (found_solution) return; - core = 0; + core = nullptr; sbuffer sz_buffer; for (unsigned i = 0; i < r1_size; i++) { ast_translation translator(*(managers[i]), m, false); goal_ref_buffer * r = goals_vect[i]; - if (r != 0) { + if (r != nullptr) { for (unsigned k = 0; k < r->size(); k++) { result.push_back((*r)[k]->translate(translator)); } @@ -829,12 +829,12 @@ public: else { sz_buffer.push_back(0); } - if (mc_buffer[i] != 0) + if (mc_buffer[i] != nullptr) mc_buffer.set(i, mc_buffer[i]->translate(translator)); - if (pc_buffer[i] != 0) + if (pc_buffer[i] != nullptr) pc_buffer.set(i, pc_buffer[i]->translate(translator)); expr_dependency_translation td(translator); - if (core_buffer[i] != 0) { + if (core_buffer[i] != nullptr) { expr_dependency_ref curr_core(m); curr_core = td(*(core_buffer[i])); core = m.mk_join(curr_core, core); @@ -850,7 +850,7 @@ public: apply(m, pc1, pc_buffer, pr); SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); - core = 0; + core = nullptr; result.push_back(in.get()); SASSERT(!mc); SASSERT(!pc); SASSERT(!core); } @@ -936,9 +936,9 @@ class repeat_tactical : public unary_tactical { // TODO: implement a non-recursive version. if (depth > m_max_depth) { result.push_back(in.get()); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; return; } @@ -952,9 +952,9 @@ class repeat_tactical : public unary_tactical { proof_converter_ref pc1; expr_dependency_ref core1(m); result.reset(); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; { goal orig_in(in->m(), proofs_enabled, models_enabled, cores_enabled); orig_in.copy_from(*(in.get())); @@ -1014,7 +1014,7 @@ class repeat_tactical : public unary_tactical { SASSERT(is_decided_unsat(r2)); SASSERT(!pc2); SASSERT(!core2); - if (models_enabled) mc_buffer.push_back(0); + if (models_enabled) mc_buffer.push_back(nullptr); if (proofs_enabled) pc_buffer.push_back(proof2proof_converter(m, r2[0]->pr(0))); if (models_enabled || proofs_enabled) sz_buffer.push_back(0); if (cores_enabled) core = m.mk_join(core.get(), r2[0]->dep(0)); @@ -1038,7 +1038,7 @@ class repeat_tactical : public unary_tactical { apply(m, pc1, pc_buffer, pr); SASSERT(cores_enabled || core == 0); in->assert_expr(m.mk_false(), pr, core); - core = 0; + core = nullptr; result.push_back(in.get()); SASSERT(!mc); SASSERT(!pc); SASSERT(!core); } @@ -1087,9 +1087,9 @@ public: m_t->operator()(in, result, mc, pc, core); if (result.size() > m_threshold) { result.reset(); - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; throw tactic_exception("failed-if-branching tactical"); } }; @@ -1282,9 +1282,9 @@ public: model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) override { - mc = 0; - pc = 0; - core = 0; + mc = nullptr; + pc = nullptr; + core = nullptr; if (m_p->operator()(*(in.get())).is_true()) { throw tactic_exception("fail-if tactic"); } @@ -1314,7 +1314,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { if (in->proofs_enabled()) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); result.push_back(in.get()); } @@ -1336,7 +1336,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { if (in->unsat_core_enabled()) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); result.push_back(in.get()); } @@ -1358,7 +1358,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) override { if (in->models_enabled()) { - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; result.reset(); result.push_back(in.get()); } diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index 88b1e6a67..5917136b6 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -43,7 +43,7 @@ class macro_finder_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("macro-finder", *g); bool produce_proofs = g->proofs_enabled(); @@ -66,8 +66,8 @@ class macro_finder_tactic : public tactic { g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) g->assert_expr(new_forms.get(i), - produce_proofs ? new_proofs.get(i) : 0, - unsat_core_enabled ? new_deps.get(i) : 0); + produce_proofs ? new_proofs.get(i) : nullptr, + unsat_core_enabled ? new_deps.get(i) : nullptr); extension_model_converter * evmc = alloc(extension_model_converter, mm.get_manager()); unsigned num = mm.get_num_macros(); diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index e9d081c53..7fbc3c7a5 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -41,7 +41,7 @@ class quasi_macros_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("quasi-macros", *g); bool produce_proofs = g->proofs_enabled(); @@ -78,8 +78,8 @@ class quasi_macros_tactic : public tactic { g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) g->assert_expr(forms.get(i), - produce_proofs ? proofs.get(i) : 0, - produce_unsat_cores ? deps.get(i) : 0); + produce_proofs ? proofs.get(i) : nullptr, + produce_unsat_cores ? deps.get(i) : nullptr); extension_model_converter * evmc = alloc(extension_model_converter, mm.get_manager()); unsigned num = mm.get_num_macros(); diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index 3dcc6d9a1..eed72a71e 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -37,7 +37,7 @@ class ufbv_rewriter_tactic : public tactic { proof_converter_ref & pc, expr_dependency_ref & core) { SASSERT(g->is_well_sorted()); - mc = 0; pc = 0; core = 0; + mc = nullptr; pc = nullptr; core = nullptr; tactic_report report("ufbv-rewriter", *g); fail_if_unsat_core_generation("ufbv-rewriter", g); @@ -58,9 +58,9 @@ class ufbv_rewriter_tactic : public tactic { g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) - g->assert_expr(new_forms.get(i), produce_proofs ? new_proofs.get(i) : 0, 0); + g->assert_expr(new_forms.get(i), produce_proofs ? new_proofs.get(i) : nullptr, nullptr); - mc = 0; // CMW: Remark: The demodulator could potentially remove all references to a variable. + mc = nullptr; // CMW: Remark: The demodulator could potentially remove all references to a variable. g->inc_depth(); result.push_back(g.get()); diff --git a/src/test/check_assumptions.cpp b/src/test/check_assumptions.cpp index 020b3e277..d1d81245e 100644 --- a/src/test/check_assumptions.cpp +++ b/src/test/check_assumptions.cpp @@ -20,13 +20,13 @@ void tst_check_assumptions() reg_decl_plugins(mgr); sort_ref b(mgr.mk_bool_sort(), mgr); - func_decl_ref pPred(mgr.mk_func_decl(symbol("p"), 0, static_cast(0), b), mgr); - func_decl_ref qPred(mgr.mk_func_decl(symbol("q"), 0, static_cast(0), b), mgr); - func_decl_ref rPred(mgr.mk_func_decl(symbol("r"), 0, static_cast(0), b), mgr); + func_decl_ref pPred(mgr.mk_func_decl(symbol("p"), 0, static_cast(nullptr), b), mgr); + func_decl_ref qPred(mgr.mk_func_decl(symbol("q"), 0, static_cast(nullptr), b), mgr); + func_decl_ref rPred(mgr.mk_func_decl(symbol("r"), 0, static_cast(nullptr), b), mgr); - app_ref p(mgr.mk_app(pPred,0,static_cast(0)), mgr); - app_ref q(mgr.mk_app(qPred,0,static_cast(0)), mgr); - app_ref r(mgr.mk_app(rPred,0,static_cast(0)), mgr); + app_ref p(mgr.mk_app(pPred,0,static_cast(nullptr)), mgr); + app_ref q(mgr.mk_app(qPred,0,static_cast(nullptr)), mgr); + app_ref r(mgr.mk_app(rPred,0,static_cast(nullptr)), mgr); app_ref pOqOr(mgr.mk_or(p,q,r), mgr); app_ref np(mgr.mk_not(p), mgr); diff --git a/src/test/cnf_backbones.cpp b/src/test/cnf_backbones.cpp index 3e9a106b5..27d175298 100644 --- a/src/test/cnf_backbones.cpp +++ b/src/test/cnf_backbones.cpp @@ -11,7 +11,7 @@ Copyright (c) 2017 Microsoft Corporation #include "sat/sat_solver.h" #include "util/gparams.h" -static sat::solver * g_solver = 0; +static sat::solver * g_solver = nullptr; static clock_t g_start_time; static void display_statistics() { @@ -228,8 +228,8 @@ static void cnf_backbones(bool use_chunk, char const* file_name) { params_ref p = gparams::get_module("sat"); p.set_bool("produce_models", true); reslimit limit; - sat::solver solver(p, limit, 0); - sat::solver solver2(p, limit, 0); + sat::solver solver(p, limit, nullptr); + sat::solver solver2(p, limit, nullptr); g_solver = &solver; if (file_name) { diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index c9eb6aa08..003e5bdb8 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -26,7 +26,7 @@ void read_nums(std::istream& is, unsigned & x, unsigned& y) { std::getline(is, line); } -static char const* g_file = 0; +static char const* g_file = nullptr; void create_forwarding( diff --git a/src/test/escaped.cpp b/src/test/escaped.cpp index fe8f733bf..9bc2aecec 100644 --- a/src/test/escaped.cpp +++ b/src/test/escaped.cpp @@ -30,6 +30,6 @@ void tst_escaped() { std::cout << "[" << escaped("\n") << "]\n"; std::cout << "[" << escaped("", true) << "]\n"; std::cout << "[" << escaped("") << "]\n"; - std::cout << "[" << escaped(0, true) << "]\n"; - std::cout << "[" << escaped(0) << "]\n"; + std::cout << "[" << escaped(nullptr, true) << "]\n"; + std::cout << "[" << escaped(nullptr) << "]\n"; } diff --git a/src/test/expr_rand.cpp b/src/test/expr_rand.cpp index e52bfbc1a..ecf0cbe4d 100644 --- a/src/test/expr_rand.cpp +++ b/src/test/expr_rand.cpp @@ -25,8 +25,8 @@ void tst_expr_arith(unsigned num_files) { er.initialize_arith(20); family_id fid = m.mk_family_id("arith"); - sort* int_ty = m.mk_sort(fid, INT_SORT, 0, 0); - sort* real_ty = m.mk_sort(fid, REAL_SORT, 0, 0); + sort* int_ty = m.mk_sort(fid, INT_SORT, 0, nullptr); + sort* real_ty = m.mk_sort(fid, REAL_SORT, 0, nullptr); er.initialize_array(3, int_ty, int_ty); er.initialize_array(3, int_ty, real_ty); diff --git a/src/test/fuzzing/expr_rand.cpp b/src/test/fuzzing/expr_rand.cpp index 1d425e9e1..a15c8e0e1 100644 --- a/src/test/fuzzing/expr_rand.cpp +++ b/src/test/fuzzing/expr_rand.cpp @@ -35,7 +35,7 @@ void expr_rand::add_func_decl(func_decl* f) { void expr_rand::add_expr(expr* t) { sort* s = m_manager.get_sort(t); - expr_ref_vector* vals = 0; + expr_ref_vector* vals = nullptr; if (!m_nodes.find(s, vals)) { vals = alloc(expr_ref_vector, m_manager); m_nodes.insert(s, vals); @@ -71,7 +71,7 @@ func_decl* expr_rand::choose_func_decl() { } expr* expr_rand::choose_expr(sort* s) { - expr_ref_vector* vals = 0; + expr_ref_vector* vals = nullptr; if (!m_nodes.find(s, vals)) { add_var(s); if (!m_nodes.find(s, vals)) { @@ -86,14 +86,14 @@ expr* expr_rand::choose_expr(sort* s) { void expr_rand::initialize_arith(unsigned num_vars) { arith_util u(m_manager); family_id afid = m_manager.mk_family_id("arith"); - sort* i_ty = m_manager.mk_sort(afid, INT_SORT, 0, 0); + sort* i_ty = m_manager.mk_sort(afid, INT_SORT, 0, nullptr); for(unsigned i = 0; i < num_vars; ++i) { add_var(i_ty); } sort* is[2] = { i_ty, i_ty }; decl_kind kinds[7] = {OP_ADD, OP_MUL, OP_SUB, OP_LE, OP_LT, OP_GE, OP_GT }; for (unsigned i = 0; i < 7; ++i) { - add_func_decl(m_manager.mk_func_decl(afid, kinds[i], 0, 0, 2, is)); + add_func_decl(m_manager.mk_func_decl(afid, kinds[i], 0, nullptr, 2, is)); } add_expr(u.mk_numeral(rational(0), true)); @@ -137,37 +137,37 @@ void expr_rand::initialize_bv(unsigned num_vars) { sort* s = m_manager.mk_sort(bvfid, BV_SORT, 1, ¶m); sort* ss[3] = { s, s, s }; - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNEG, 0, 0, 1, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BADD, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSUB, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BMUL, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSDIV, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BUDIV, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSREM, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BUREM, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSMOD, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_ULEQ, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_SLEQ, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_UGEQ, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_SGEQ, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_ULT, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_SLT, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_UGT, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_SGT, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BAND, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BOR, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNOT, 0, 0, 1, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BXOR, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BXNOR, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNAND, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BCOMP, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BREDAND, 0, 0, 1, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BREDOR, 0, 0, 1, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSHL, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BLSHR, 0, 0, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bvfid, OP_BASHR, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNEG, 0, nullptr, 1, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BADD, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSUB, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BMUL, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSDIV, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BUDIV, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSREM, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BUREM, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSMOD, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_ULEQ, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_SLEQ, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_UGEQ, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_SGEQ, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_ULT, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_SLT, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_UGT, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_SGT, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BAND, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BOR, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNOT, 0, nullptr, 1, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BXOR, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BXNOR, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BNAND, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BCOMP, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BREDAND, 0, nullptr, 1, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BREDOR, 0, nullptr, 1, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BSHL, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BLSHR, 0, nullptr, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_BASHR, 0, nullptr, 2, ss)); - add_func_decl(m_manager.mk_func_decl(bfid, OP_EQ, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bfid, OP_EQ, 0, nullptr, 2, ss)); add_func_decl(m_manager.mk_func_decl(bvfid, OP_ROTATE_LEFT, 1, &p1, 1, ss)); add_func_decl(m_manager.mk_func_decl(bvfid, OP_ROTATE_RIGHT, 1, &p1, 1, ss)); @@ -182,22 +182,22 @@ void expr_rand::initialize_bv(unsigned num_vars) { // OP_CONCAT: { sort* ss[2] = { b8, b8 }; - add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, nullptr, 2, ss)); ss[0] = b16; ss[1] = b8; - add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, nullptr, 2, ss)); ss[0] = b8; ss[1] = b16; - add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, nullptr, 2, ss)); ss[0] = b16; ss[1] = b16; - add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, nullptr, 2, ss)); ss[0] = b24; ss[1] = b8; - add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, nullptr, 2, ss)); ss[0] = b8; ss[1] = b24; - add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(bvfid, OP_CONCAT, 0, nullptr, 2, ss)); } @@ -246,8 +246,8 @@ void expr_rand::initialize_array(unsigned num_vars, sort* dom, sort* rng) { sort* a = m_manager.mk_sort(afid, ARRAY_SORT, 2, ps); sort* ss[3] = { a, dom, rng }; - add_func_decl(m_manager.mk_func_decl(afid, OP_STORE, 0, 0, 3, ss)); - add_func_decl(m_manager.mk_func_decl(afid, OP_SELECT, 0, 0, 2, ss)); + add_func_decl(m_manager.mk_func_decl(afid, OP_STORE, 0, nullptr, 3, ss)); + add_func_decl(m_manager.mk_func_decl(afid, OP_SELECT, 0, nullptr, 2, ss)); for (unsigned i = 0; i < num_vars; ++i) { add_var(a); @@ -258,14 +258,14 @@ void expr_rand::initialize_basic(unsigned amplification) { family_id bfid = m_manager.get_basic_family_id(); sort* bools[2] = { m_manager.mk_bool_sort(), m_manager.mk_bool_sort() }; for (unsigned i = 0; i < amplification; ++i) { - add_func_decl(m_manager.mk_func_decl(bfid, OP_OR, 0, 0, 2, bools)); - add_func_decl(m_manager.mk_func_decl(bfid, OP_NOT, 0, 0, 1, bools)); + add_func_decl(m_manager.mk_func_decl(bfid, OP_OR, 0, nullptr, 2, bools)); + add_func_decl(m_manager.mk_func_decl(bfid, OP_NOT, 0, nullptr, 1, bools)); } map_t::iterator it = m_nodes.begin(); map_t::iterator end = m_nodes.end(); for (; it != end; ++it) { sort* s = it->m_key; sort* ites[3] = { bools[0], s, s }; - add_func_decl(m_manager.mk_func_decl(bfid, OP_ITE, 0, 0, 3, ites)); + add_func_decl(m_manager.mk_func_decl(bfid, OP_ITE, 0, nullptr, 3, ites)); } } diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 6d600f594..767b07b6d 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -61,12 +61,12 @@ void test2() { datatype_decl_plugin & dt = *(static_cast(m.get_plugin(m.get_family_id("datatype")))); sort_ref_vector new_sorts(m); - constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, 0); - constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); - constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); + constructor_decl* R = mk_constructor_decl(symbol("R"), symbol("is-R"), 0, nullptr); + constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, nullptr); + constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, nullptr); constructor_decl* constrs[3] = { R, G, B }; datatype_decl * enum_sort = mk_datatype_decl(dtutil, symbol("RGB"), 0, nullptr, 3, constrs); - VERIFY(dt.mk_datatypes(1, &enum_sort, 0, nullptr, new_sorts)); + VERIFY(dt.mk_datatypes(1, &enum_sort, 0, nullptr, new_sorts)); sort* rgb = new_sorts[0].get(); expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); @@ -89,7 +89,7 @@ void test2() { fd_solver->push(); fd_solver->assert_expr(m.mk_not(m.mk_eq(x, g))); - VERIFY(l_false == fd_solver->check_sat(0,0)); + VERIFY(l_false == fd_solver->check_sat(0,nullptr)); fd_solver->pop(1); VERIFY(l_true == fd_solver->get_consequences(asms, vars, conseq)); @@ -101,7 +101,7 @@ void test2() { fd_solver->get_model(mr); model_smt2_pp(std::cout << "model:\n", m, *mr.get(), 0); - VERIFY(l_true == fd_solver->check_sat(0,0)); + VERIFY(l_true == fd_solver->check_sat(0,nullptr)); fd_solver->get_model(mr); ENSURE(mr.get()); model_smt2_pp(std::cout, m, *mr.get(), 0); diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 7329b1d3d..bf059ee10 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -210,7 +210,7 @@ expr_ref hilbert_basis_validate::mk_validate(hilbert_basis& hb) { } -hilbert_basis* g_hb = 0; +hilbert_basis* g_hb = nullptr; static double g_start_time; static void display_statistics(hilbert_basis& hb) { diff --git a/src/test/list.cpp b/src/test/list.cpp index 4cfa16801..956477237 100644 --- a/src/test/list.cpp +++ b/src/test/list.cpp @@ -27,10 +27,10 @@ static void tst1() { list * l2 = new (r) list(20, l1); list * l3 = new (r) list(30); list * l4 = new (r) list(40, l3); - ENSURE(append(r, l1, static_cast *>(0)) == l1); - ENSURE(append(r, l2, static_cast *>(0)) == l2); - ENSURE(append(r, static_cast *>(0), l2) == l2); - ENSURE(append(r, static_cast *>(0), static_cast *>(0)) == 0); + ENSURE(append(r, l1, static_cast *>(nullptr)) == l1); + ENSURE(append(r, l2, static_cast *>(nullptr)) == l2); + ENSURE(append(r, static_cast *>(nullptr), l2) == l2); + ENSURE(append(r, static_cast *>(nullptr), static_cast *>(nullptr)) == nullptr); TRACE("list", display(tout, l2->begin(), l2->end()); tout << "\n";); list * l5 = append(r, l4, l2); TRACE("list", display(tout, l5->begin(), l5->end()); tout << "\n";); diff --git a/src/test/main.cpp b/src/test/main.cpp index 98be722e3..ccdc77ec9 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -77,11 +77,11 @@ void display_usage() { void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& test_all) { int i = 1; while (i < argc) { - char * arg = argv[i], *eq_pos = 0; + char * arg = argv[i], *eq_pos = nullptr; if (arg[0] == '-' || arg[0] == '/') { char * opt_name = arg + 1; - char * opt_arg = 0; + char * opt_arg = nullptr; char * colon = strchr(arg, ':'); if (colon) { opt_arg = colon + 1; @@ -96,7 +96,7 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& t else if (strcmp(opt_name, "v") == 0) { if (!opt_arg) error("option argument (/v:level) is missing."); - long lvl = strtol(opt_arg, 0, 10); + long lvl = strtol(opt_arg, nullptr, 10); set_verbosity_level(lvl); } else if (strcmp(opt_name, "w") == 0) { diff --git a/src/test/nlsat.cpp b/src/test/nlsat.cpp index 19add1fab..1d69c8078 100644 --- a/src/test/nlsat.cpp +++ b/src/test/nlsat.cpp @@ -293,7 +293,7 @@ static void tst5() { bool is_even[1] = { false }; nlsat::bool_var b = s.mk_ineq_atom(nlsat::atom::GT, 1, _p, is_even); nlsat::atom * a = s.bool_var2atom(b); - ENSURE(a != 0); + ENSURE(a != nullptr); scoped_anum zero(am); am.set(zero, 0); as.set(0, zero); diff --git a/src/test/old_interval.cpp b/src/test/old_interval.cpp index 4ab8b0dd0..7ef9cdc87 100644 --- a/src/test/old_interval.cpp +++ b/src/test/old_interval.cpp @@ -120,10 +120,10 @@ class interval_tester { interval singleton(int i) { return interval(m, rational(i)); } interval all() { return interval(m); } - interval l(int i, bool o = false, size_t idx = 0) { return interval(m, rational(i), o, true, idx == 0 ? 0 : m.mk_leaf(reinterpret_cast(idx))); } - interval r(int i, bool o = false, size_t idx = 0) { return interval(m, rational(i), o, false, idx == 0 ? 0 : m.mk_leaf(reinterpret_cast(idx))); } + interval l(int i, bool o = false, size_t idx = 0) { return interval(m, rational(i), o, true, idx == 0 ? nullptr : m.mk_leaf(reinterpret_cast(idx))); } + interval r(int i, bool o = false, size_t idx = 0) { return interval(m, rational(i), o, false, idx == 0 ? nullptr : m.mk_leaf(reinterpret_cast(idx))); } interval b(int l, int u, bool lo = false, bool uo = false, size_t idx_l = 0, size_t idx_u = 0) { - return interval(m, rational(l), lo, idx_l == 0 ? 0 : m.mk_leaf(reinterpret_cast(idx_l)), rational(u), uo, idx_u == 0 ? 0 : m.mk_leaf(reinterpret_cast(idx_u))); + return interval(m, rational(l), lo, idx_l == 0 ? nullptr : m.mk_leaf(reinterpret_cast(idx_l)), rational(u), uo, idx_u == 0 ? nullptr : m.mk_leaf(reinterpret_cast(idx_u))); } void bugs() { diff --git a/src/test/pb2bv.cpp b/src/test/pb2bv.cpp index 632b2d642..35c444bae 100644 --- a/src/test/pb2bv.cpp +++ b/src/test/pb2bv.cpp @@ -151,10 +151,10 @@ static void test_solver_semantics(ast_manager& m, expr_ref_vector const& vars, v std::cout << fml1 << " " << fml2 << "\n"; th_rw(fml2, result2, proof); ENSURE(m.is_true(result2) || m.is_false(result2)); - lbool res = slv->check_sat(0,0); + lbool res = slv->check_sat(0,nullptr); VERIFY(res == l_true); slv->assert_expr(m.is_true(result2) ? m.mk_not(result1) : result1.get()); - res = slv->check_sat(0,0); + res = slv->check_sat(0,nullptr); VERIFY(res == l_false); } } diff --git a/src/test/pdr.cpp b/src/test/pdr.cpp index 7e2f1a5ad..45d9eea7e 100644 --- a/src/test/pdr.cpp +++ b/src/test/pdr.cpp @@ -103,7 +103,7 @@ struct test_model_search { unsigned level = 4; for(unsigned n = 0; n < 100; ++n) { state = mk_state(states, rand); - model_node* root = alloc(model_node, 0, state, pt, level); + model_node* root = alloc(model_node, nullptr, state, pt, level); search.set_root(root); add_tree(root, false); search.display(std::cout); diff --git a/src/test/polynorm.cpp b/src/test/polynorm.cpp index 22df91b45..ef01bd27d 100644 --- a/src/test/polynorm.cpp +++ b/src/test/polynorm.cpp @@ -172,7 +172,7 @@ static expr_ref mk_mul(arith_util& arith, unsigned num_args, expr* const* args) static void nf(expr_ref& term) { ast_manager& m = term.get_manager(); - expr *e1 = 0, *e2 = 0; + expr *e1 = nullptr, *e2 = nullptr; th_rewriter rw(m); arith_util arith(m); diff --git a/src/test/sat_user_scope.cpp b/src/test/sat_user_scope.cpp index 10abb44c3..703cf7e3a 100644 --- a/src/test/sat_user_scope.cpp +++ b/src/test/sat_user_scope.cpp @@ -55,7 +55,7 @@ static void init_vars(sat::solver& s) { static void check_coherence(sat::solver& s1, trail_t& t) { params_ref p; reslimit rlim; - sat::solver s2(p, rlim, 0); + sat::solver s2(p, rlim, nullptr); init_vars(s2); sat::literal_vector cls; for (unsigned i = 0; i < t.size(); ++i) { @@ -81,7 +81,7 @@ void tst_sat_user_scope() { trail_t trail; params_ref p; reslimit rlim; - sat::solver s(p, rlim, 0); // incremental solver + sat::solver s(p, rlim, nullptr); // incremental solver init_vars(s); while (true) { for (unsigned i = 0; i < s_num_frames; ++i) { diff --git a/src/test/smt2print_parse.cpp b/src/test/smt2print_parse.cpp index 80a57c7d5..9a8d7b788 100644 --- a/src/test/smt2print_parse.cpp +++ b/src/test/smt2print_parse.cpp @@ -12,7 +12,7 @@ Copyright (c) 2015 Microsoft Corporation void test_print(Z3_context ctx, Z3_ast a) { Z3_set_ast_print_mode(ctx, Z3_PRINT_SMTLIB2_COMPLIANT); - char const* spec1 = Z3_benchmark_to_smtlib_string(ctx, "test", 0, 0, 0, 0, 0, a); + char const* spec1 = Z3_benchmark_to_smtlib_string(ctx, "test", nullptr, nullptr, nullptr, 0, nullptr, a); std::cout << "spec1: benchmark->string\n" << spec1 << "\n"; std::cout << "attempting to parse spec1...\n"; @@ -20,29 +20,29 @@ void test_print(Z3_context ctx, Z3_ast a) { Z3_parse_smtlib2_string(ctx, spec1, 0, + nullptr, + nullptr, 0, - 0, - 0, - 0, - 0); + nullptr, + nullptr); std::cout << "parse successful, converting ast->string\n"; char const* spec2 = Z3_ast_to_string(ctx, b); std::cout << "spec2: string->ast->string\n" << spec2 << "\n"; } void test_parseprint(char const* spec) { - Z3_context ctx = Z3_mk_context(0); + Z3_context ctx = Z3_mk_context(nullptr); std::cout << "spec:\n" << spec << "\n"; Z3_ast a = Z3_parse_smtlib2_string(ctx, spec, 0, + nullptr, + nullptr, 0, - 0, - 0, - 0, - 0); + nullptr, + nullptr); std::cout << "done parsing\n"; diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 1062057f6..12964c192 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -28,7 +28,7 @@ struct ast_ext { return m.mk_implies(a, b); } UNREACHABLE(); - return 0; + return nullptr; } T mk_default() { return m.mk_false(); diff --git a/src/test/theory_pb.cpp b/src/test/theory_pb.cpp index 8fcbde706..7010b96d0 100644 --- a/src/test/theory_pb.cpp +++ b/src/test/theory_pb.cpp @@ -148,7 +148,7 @@ void tst_theory_pb() { ctx.push(); smt::literal l = smt::theory_pb::assert_ge(ctx, k+1, lits.size(), lits.c_ptr()); if (l != smt::false_literal) { - ctx.assign(l, 0, false); + ctx.assign(l, nullptr, false); TRACE("pb", tout << "assign: " << l << "\n"; ctx.display(tout);); VERIFY(l_false == ctx.check()); @@ -160,7 +160,7 @@ void tst_theory_pb() { ctx.push(); smt::literal l = smt::theory_pb::assert_ge(ctx, k, lits.size(), lits.c_ptr()); ENSURE(l != smt::false_literal); - ctx.assign(l, 0, false); + ctx.assign(l, nullptr, false); TRACE("pb", ctx.display(tout);); VERIFY(l_true == ctx.check()); ctx.pop(1); diff --git a/src/test/udoc_relation.cpp b/src/test/udoc_relation.cpp index 5f1bd7b36..4555d4ef0 100644 --- a/src/test/udoc_relation.cpp +++ b/src/test/udoc_relation.cpp @@ -89,7 +89,7 @@ class udoc_tester { for (unsigned i = 0; i < num_diff; ++i) { t = mk_rand_tbv(dm, result->pos()); if (dm.tbvm().equals(*t, result->pos())) { - return 0; + return nullptr; } if (!result->neg().is_empty() && dm.tbvm().equals(*t, result->neg()[0])) { @@ -278,7 +278,7 @@ public: t1->to_formula(t10); expr_ref delta0(m); delta->to_formula(delta0); - rel_union union_fn = p.mk_union_fn(*t1, *t2, 0); + rel_union union_fn = p.mk_union_fn(*t1, *t2, nullptr); t1->display(std::cout << "t1 before:"); std::cout << "\n"; (*union_fn)(*t1, *t2, delta); @@ -840,7 +840,7 @@ public: void set_random(udoc_relation& r, unsigned num_vals) { unsigned num_bits = r.get_dm().num_tbits(); udoc_relation* full = mk_full(r.get_signature()); - rel_union union_fn = p.mk_union_fn(r, r, 0); + rel_union union_fn = p.mk_union_fn(r, r, nullptr); (*union_fn)(r, *full); doc_manager& dm = r.get_dm(); ENSURE(r.get_udoc().size() == 1); @@ -905,8 +905,8 @@ public: void apply_filter(udoc_relation& t, app* cond) { udoc_relation* full = mk_full(t.get_signature()); - rel_union union_fn = p.mk_union_fn(t, *full, 0); - (*union_fn)(t, *full, 0); + rel_union union_fn = p.mk_union_fn(t, *full, nullptr); + (*union_fn)(t, *full, nullptr); expr_ref fml0(m); t.to_formula(fml0); rel_mut fint = p.mk_filter_interpreted_fn(t, cond); diff --git a/src/test/var_subst.cpp b/src/test/var_subst.cpp index 169b1e131..09535ae8c 100644 --- a/src/test/var_subst.cpp +++ b/src/test/var_subst.cpp @@ -27,7 +27,7 @@ Revision History: namespace find_q { struct proc { quantifier * m_q; - proc():m_q(0) {} + proc():m_q(nullptr) {} void operator()(var * n) {} void operator()(app * n) {} void operator()(quantifier * n) { m_q = n; } diff --git a/src/util/array.h b/src/util/array.h index f0c084b30..cf82e123c 100644 --- a/src/util/array.h +++ b/src/util/array.h @@ -74,7 +74,7 @@ public: typedef T * iterator; typedef const T * const_iterator; - array():m_data(0) {} + array():m_data(nullptr) {} /** \brief Store the array in the given chunk of memory (mem). @@ -123,7 +123,7 @@ public: if (CallDestructors) destroy_elements(); a.deallocate(space(size()), raw_ptr()); - m_data = 0; + m_data = nullptr; } } @@ -148,7 +148,7 @@ public: } unsigned size() const { - if (m_data == 0) { + if (m_data == nullptr) { return 0; } return static_cast(reinterpret_cast(m_data)[SIZE_IDX]); diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 2d42e35a2..5f21d2e59 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -62,7 +62,7 @@ public: bit_vector(): m_num_bits(0), m_capacity(0), - m_data(0) { + m_data(nullptr) { } bit_vector(unsigned reserve_num_bits) : @@ -75,7 +75,7 @@ public: bit_vector(bit_vector const & source): m_num_bits(source.m_num_bits), m_capacity(source.m_capacity), - m_data(0) { + m_data(nullptr) { if (source.m_data) { m_data = alloc_svect(unsigned, m_capacity); memcpy(m_data, source.m_data, m_capacity * sizeof(unsigned)); diff --git a/src/util/chashtable.h b/src/util/chashtable.h index 69c48207a..9bc5988e5 100644 --- a/src/util/chashtable.h +++ b/src/util/chashtable.h @@ -106,13 +106,13 @@ protected: SASSERT(target_it < target + target_slots); if (target_it->is_free()) { target_it->m_data = list_it->m_data; - target_it->m_next = 0; + target_it->m_next = nullptr; used_slots++; } else { SASSERT((get_hash(target_it->m_data) & target_mask) == idx); if (target_cellar == target_end) - return 0; // the cellar is too small... + return nullptr; // the cellar is too small... SASSERT(target_cellar >= target + target_slots); SASSERT(target_cellar < target_end); *target_cellar = *target_it; @@ -123,7 +123,7 @@ protected: SASSERT(!target_it->is_free()); list_it = list_it->m_next; } - while (list_it != 0); + while (list_it != nullptr); } } #if 0 @@ -164,13 +164,13 @@ protected: cell * next_cell = copy_table(m_table, m_slots, m_capacity, new_table, new_slots, new_capacity, m_used_slots); - if (next_cell != 0) { + if (next_cell != nullptr) { delete_table(); m_table = new_table; m_capacity = new_capacity; m_slots = new_slots; m_next_cell = next_cell; - m_free_cell = 0; + m_free_cell = nullptr; CASSERT("chashtable", check_invariant()); return; } @@ -180,11 +180,11 @@ protected: } bool has_free_cells() const { - return m_free_cell != 0 || m_next_cell < m_table + m_capacity; + return m_free_cell != nullptr || m_next_cell < m_table + m_capacity; } cell * get_free_cell() { - if (m_free_cell != 0) { + if (m_free_cell != nullptr) { cell * c = m_free_cell; m_free_cell = c->m_next; return c; @@ -211,7 +211,7 @@ protected: m_used_slots = 0; m_size = 0; m_next_cell = m_table + slots; - m_free_cell = 0; + m_free_cell = nullptr; } public: @@ -281,7 +281,7 @@ public: m_size++; m_used_slots++; c->m_data = d; - c->m_next = 0; + c->m_next = nullptr; CASSERT("chashtable_bug", check_invariant()); return; } @@ -297,7 +297,7 @@ public: CHS_CODE(m_collisions++;); it = it->m_next; } - while (it != 0); + while (it != nullptr); // d is not in the table. m_size++; cell * new_c = get_free_cell(); @@ -320,7 +320,7 @@ public: m_size++; m_used_slots++; c->m_data = d; - c->m_next = 0; + c->m_next = nullptr; CASSERT("chashtable_bug", check_invariant()); return c->m_data; } @@ -335,7 +335,7 @@ public: CHS_CODE(m_collisions++;); it = it->m_next; } - while (it != 0); + while (it != nullptr); // d is not in the table. m_size++; cell * new_c = get_free_cell(); @@ -358,7 +358,7 @@ public: m_size++; m_used_slots++; c->m_data = d; - c->m_next = 0; + c->m_next = nullptr; CASSERT("chashtable_bug", check_invariant()); return true; } @@ -373,7 +373,7 @@ public: CHS_CODE(m_collisions++;); it = it->m_next; } - while (it != 0); + while (it != nullptr); // d is not in the table. m_size++; cell * new_c = get_free_cell(); @@ -399,7 +399,7 @@ public: CHS_CODE(const_cast(this)->m_collisions++;); c = c->m_next; } - while (c != 0); + while (c != nullptr); return false; } @@ -409,7 +409,7 @@ public: unsigned idx = h & mask; cell * c = m_table + idx; if (c->is_free()) - return 0; + return nullptr; do { if (equals(c->m_data, d)) { return &(c->m_data); @@ -417,8 +417,8 @@ public: CHS_CODE(const_cast(this)->m_collisions++;); c = c->m_next; } - while (c != 0); - return 0; + while (c != nullptr); + return nullptr; } bool find(T const & d, T & r) { @@ -436,7 +436,7 @@ public: CHS_CODE(const_cast(this)->m_collisions++;); c = c->m_next; } - while (c != 0); + while (c != nullptr); return false; } @@ -447,13 +447,13 @@ public: cell * c = m_table + idx; if (c->is_free()) return; - cell * prev = 0; + cell * prev = nullptr; do { if (equals(c->m_data, d)) { m_size--; - if (prev == 0) { + if (prev == nullptr) { cell * next = c->m_next; - if (next == 0) { + if (next == nullptr) { m_used_slots--; c->mark_free(); SASSERT(c->is_free()); @@ -474,7 +474,7 @@ public: prev = c; c = c->m_next; } - while (c != 0); + while (c != nullptr); } class iterator { @@ -490,12 +490,12 @@ public: } m_it++; } - m_list_it = 0; + m_list_it = nullptr; } public: iterator(cell * start, cell * end): m_it(start), m_end(end) { move_to_used(); } - iterator():m_it(0), m_end(0), m_list_it(0) {} + iterator():m_it(nullptr), m_end(nullptr), m_list_it(nullptr) {} T & operator*() { return m_list_it->m_data; } @@ -506,7 +506,7 @@ public: T * operator->() { return &(operator*()); } iterator & operator++() { m_list_it = m_list_it->m_next; - if (m_list_it == 0) { + if (m_list_it == nullptr) { m_it++; move_to_used(); } @@ -658,7 +658,7 @@ public: bool find(Key const & k, Value & v) const { key_value * e = m_table.find_core(key_value(k)); - if (e == 0) + if (e == nullptr) return false; v = e->m_value; return true; diff --git a/src/util/cmd_context_types.h b/src/util/cmd_context_types.h index ae64e2de6..e82536704 100644 --- a/src/util/cmd_context_types.h +++ b/src/util/cmd_context_types.h @@ -91,8 +91,8 @@ public: virtual void reset(cmd_context & ctx) {} virtual void finalize(cmd_context & ctx) {} virtual symbol get_name() const { return m_name; } - virtual char const * get_usage() const { return 0; } - virtual char const * get_descr(cmd_context & ctx) const { return 0; } + virtual char const * get_usage() const { return nullptr; } + virtual char const * get_descr(cmd_context & ctx) const { return nullptr; } virtual unsigned get_arity() const { return 0; } // command invocation diff --git a/src/util/cooperate.cpp b/src/util/cooperate.cpp index 2ae250206..2b2e7958e 100644 --- a/src/util/cooperate.cpp +++ b/src/util/cooperate.cpp @@ -28,7 +28,7 @@ struct cooperation_lock { cooperation_lock() { omp_set_nested(1); omp_init_nest_lock(&m_lock); - m_task = 0; + m_task = nullptr; m_owner_thread = -1; } ~cooperation_lock() { diff --git a/src/util/debug.cpp b/src/util/debug.cpp index 5d39e7c02..4434cb19f 100644 --- a/src/util/debug.cpp +++ b/src/util/debug.cpp @@ -41,7 +41,7 @@ void notify_assertion_violation(const char * fileName, int line, const char * co std::cerr << condition << "\n"; } -static str_hashtable* g_enabled_debug_tags = 0; +static str_hashtable* g_enabled_debug_tags = nullptr; static void init_debug_table() { if (!g_enabled_debug_tags) { @@ -51,7 +51,7 @@ static void init_debug_table() { void finalize_debug() { dealloc(g_enabled_debug_tags); - g_enabled_debug_tags = 0; + g_enabled_debug_tags = nullptr; } void enable_debug(const char * tag) { @@ -72,7 +72,7 @@ bool is_debug_enabled(const char * tag) { #ifndef _WINDOWS void invoke_gdb() { char buffer[1024]; - int * x = 0; + int * x = nullptr; for (;;) { std::cerr << "(C)ontinue, (A)bort, (S)top, (T)hrow exception, Invoke (G)DB\n"; char result; @@ -103,7 +103,7 @@ void invoke_gdb() { else { std::cerr << "error starting GDB...\n"; // forcing seg fault. - int * x = 0; + int * x = nullptr; *x = 0; } return; diff --git a/src/util/dependency.h b/src/util/dependency.h index 5055399bc..0b6772852 100644 --- a/src/util/dependency.h +++ b/src/util/dependency.h @@ -138,7 +138,7 @@ public: } dependency * mk_empty() { - return 0; + return nullptr; } dependency * mk_leaf(value const & v) { @@ -148,10 +148,10 @@ public: } dependency * mk_join(dependency * d1, dependency * d2) { - if (d1 == 0) { + if (d1 == nullptr) { return d2; } - else if (d2 == 0) { + else if (d2 == nullptr) { return d1; } else if (d1 == d2) { diff --git a/src/util/file_path.h b/src/util/file_path.h index c34c8b408..dbd8130c7 100644 --- a/src/util/file_path.h +++ b/src/util/file_path.h @@ -21,12 +21,12 @@ Revision History: #include inline char const * get_extension(char const * file_name) { - if (file_name == 0) - return 0; - char const * last_dot = 0; + if (file_name == nullptr) + return nullptr; + char const * last_dot = nullptr; for (;;) { char const * tmp = strchr(file_name, '.'); - if (tmp == 0) { + if (tmp == nullptr) { return last_dot; } last_dot = tmp + 1; diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index e71594810..12c335cdf 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -23,7 +23,7 @@ Notes: extern void gparams_register_modules(); static char const * g_old_params_names[] = { - "arith_adaptive","arith_adaptive_assertion_threshold","arith_adaptive_gcd","arith_adaptive_propagation_threshold","arith_add_binary_bounds","arith_blands_rule_threshold","arith_branch_cut_ratio","arith_dump_lemmas","arith_eager_eq_axioms","arith_eager_gcd","arith_eq_bounds","arith_euclidean_solver","arith_expand_eqs","arith_force_simplex","arith_gcd_test","arith_ignore_int","arith_lazy_adapter","arith_lazy_pivoting","arith_max_lemma_size","arith_process_all_eqs","arith_propagate_eqs","arith_propagation_mode","arith_propagation_threshold","arith_prop_strategy","arith_random_initial_value","arith_random_lower","arith_random_seed","arith_random_upper","arith_reflect","arith_skip_big_coeffs","arith_small_lemma_size","arith_solver","arith_stronger_lemmas","array_always_prop_upward","array_canonize","array_cg","array_delay_exp_axiom","array_extensional","array_laziness","array_lazy_ieq","array_lazy_ieq_delay","array_solver","array_weak","async_commands","at_labels_cex","auto_config","bb_eager","bb_ext_gates","bb_quantifiers","bin_clauses","bit2int","bv2int_distribute","bv_blast_max_size","bv_cc","bv_enable_int2bv_propagation","bv_lazy_le","bv_max_sharing","bv_reflect","bv_solver","case_split","check_at_labels","check_proof","cnf_factor","cnf_mode","context_simplifier","dack","dack_eq","dack_factor","dack_gc","dack_gc_inv_decay","dack_threshold","default_qid","default_table","default_table_checked","delay_units","delay_units_threshold","der","display_config","display_dot_proof","display_error_for_visual_studio","display_features","display_proof","display_unsat_core","distribute_forall","dt_lazy_splits","dump_goal_as_smt","elim_and","elim_bounds","elim_nlarith_quantifiers","elim_quantifiers","elim_term_ite","ematching","engine","eq_propagation","hi_div0","ignore_bad_patterns","ignore_setparameter","instruction_max","inst_gen","interactive","internalizer_nnf","lemma_gc_factor","lemma_gc_half","lemma_gc_initial","lemma_gc_new_clause_activity","lemma_gc_new_clause_relevancy","lemma_gc_new_old_ratio","lemma_gc_old_clause_activity","lemma_gc_old_clause_relevancy","lemma_gc_strategy","lift_ite","lookahead_diseq","macro_finder","max_conflicts","max_counterexamples","mbqi","mbqi_force_template","mbqi_max_cexs","mbqi_max_cexs_incr","mbqi_max_iterations","mbqi_trace","minimize_lemmas","model","model_compact","model_completion","model_display_arg_sort","model_hide_unused_partitions","model_on_final_check","model_on_timeout","model_partial","model_v1","model_v2","model_validate","new_core2th_eq","ng_lift_ite","nl_arith","nl_arith_branching","nl_arith_gb","nl_arith_gb_eqs","nl_arith_gb_perturbate","nl_arith_gb_threshold","nl_arith_max_degree","nl_arith_rounds","nnf_factor","nnf_ignore_labels","nnf_mode","nnf_sk_hack","order","order_var_weight","order_weights","phase_selection","pi_arith","pi_arith_weight","pi_avoid_skolems","pi_block_looop_patterns","pi_max_multi_patterns","pi_non_nested_arith_weight","pi_nopat_weight","pi_pull_quantifiers","pi_use_database","pi_warnings","pp_bounded","pp_bv_literals","pp_bv_neg","pp_decimal","pp_decimal_precision","pp_fixed_indent","pp_flat_assoc","pp_max_depth","pp_max_indent","pp_max_num_lines","pp_max_ribbon","pp_max_width","pp_min_alias_size","pp_simplify_implies","pp_single_line","precedence","precedence_gen","pre_demodulator","pre_simplifier","pre_simplify_expr","profile_res_sub","progress_sampling_freq","proof_mode","propagate_booleans","propagate_values","pull_cheap_ite_trees","pull_nested_quantifiers","qi_conservative_final_check","qi_cost","qi_eager_threshold","qi_lazy_instantiation","qi_lazy_quick_checker","qi_lazy_threshold","qi_max_eager_multi_patterns","qi_max_instances","qi_max_lazy_multi_pattern_matching","qi_new_gen","qi_profile","qi_profile_freq","qi_promote_unsat","qi_quick_checker","quasi_macros","random_case_split_freq","random_initial_activity","random_seed","recent_lemma_threshold","reduce_args","refine_inj_axiom","relevancy","relevancy_lemma","rel_case_split_order","restart_adaptive","restart_agility_threshold","restart_factor","restart_initial","restart_strategy","restricted_quasi_macros","simplify_clauses","smtlib2_compliant","smtlib_category","smtlib_dump_lemmas","smtlib_logic","smtlib_source_info","smtlib_trace_path","soft_timeout","solver","spc_bs","spc_es","spc_factor_subsumption_index_opt","spc_initial_subsumption_index_opt","spc_max_subsumption_index_features","spc_min_func_freq_subsumption_index","spc_num_iterations","spc_trace","statistics","strong_context_simplifier","tick","trace","trace_file_name","type_check","user_theory_persist_axioms","user_theory_preprocess_axioms","verbose","warning","well_sorted_check","z3_solver_ll_pp","z3_solver_smt_pp", 0 }; + "arith_adaptive","arith_adaptive_assertion_threshold","arith_adaptive_gcd","arith_adaptive_propagation_threshold","arith_add_binary_bounds","arith_blands_rule_threshold","arith_branch_cut_ratio","arith_dump_lemmas","arith_eager_eq_axioms","arith_eager_gcd","arith_eq_bounds","arith_euclidean_solver","arith_expand_eqs","arith_force_simplex","arith_gcd_test","arith_ignore_int","arith_lazy_adapter","arith_lazy_pivoting","arith_max_lemma_size","arith_process_all_eqs","arith_propagate_eqs","arith_propagation_mode","arith_propagation_threshold","arith_prop_strategy","arith_random_initial_value","arith_random_lower","arith_random_seed","arith_random_upper","arith_reflect","arith_skip_big_coeffs","arith_small_lemma_size","arith_solver","arith_stronger_lemmas","array_always_prop_upward","array_canonize","array_cg","array_delay_exp_axiom","array_extensional","array_laziness","array_lazy_ieq","array_lazy_ieq_delay","array_solver","array_weak","async_commands","at_labels_cex","auto_config","bb_eager","bb_ext_gates","bb_quantifiers","bin_clauses","bit2int","bv2int_distribute","bv_blast_max_size","bv_cc","bv_enable_int2bv_propagation","bv_lazy_le","bv_max_sharing","bv_reflect","bv_solver","case_split","check_at_labels","check_proof","cnf_factor","cnf_mode","context_simplifier","dack","dack_eq","dack_factor","dack_gc","dack_gc_inv_decay","dack_threshold","default_qid","default_table","default_table_checked","delay_units","delay_units_threshold","der","display_config","display_dot_proof","display_error_for_visual_studio","display_features","display_proof","display_unsat_core","distribute_forall","dt_lazy_splits","dump_goal_as_smt","elim_and","elim_bounds","elim_nlarith_quantifiers","elim_quantifiers","elim_term_ite","ematching","engine","eq_propagation","hi_div0","ignore_bad_patterns","ignore_setparameter","instruction_max","inst_gen","interactive","internalizer_nnf","lemma_gc_factor","lemma_gc_half","lemma_gc_initial","lemma_gc_new_clause_activity","lemma_gc_new_clause_relevancy","lemma_gc_new_old_ratio","lemma_gc_old_clause_activity","lemma_gc_old_clause_relevancy","lemma_gc_strategy","lift_ite","lookahead_diseq","macro_finder","max_conflicts","max_counterexamples","mbqi","mbqi_force_template","mbqi_max_cexs","mbqi_max_cexs_incr","mbqi_max_iterations","mbqi_trace","minimize_lemmas","model","model_compact","model_completion","model_display_arg_sort","model_hide_unused_partitions","model_on_final_check","model_on_timeout","model_partial","model_v1","model_v2","model_validate","new_core2th_eq","ng_lift_ite","nl_arith","nl_arith_branching","nl_arith_gb","nl_arith_gb_eqs","nl_arith_gb_perturbate","nl_arith_gb_threshold","nl_arith_max_degree","nl_arith_rounds","nnf_factor","nnf_ignore_labels","nnf_mode","nnf_sk_hack","order","order_var_weight","order_weights","phase_selection","pi_arith","pi_arith_weight","pi_avoid_skolems","pi_block_looop_patterns","pi_max_multi_patterns","pi_non_nested_arith_weight","pi_nopat_weight","pi_pull_quantifiers","pi_use_database","pi_warnings","pp_bounded","pp_bv_literals","pp_bv_neg","pp_decimal","pp_decimal_precision","pp_fixed_indent","pp_flat_assoc","pp_max_depth","pp_max_indent","pp_max_num_lines","pp_max_ribbon","pp_max_width","pp_min_alias_size","pp_simplify_implies","pp_single_line","precedence","precedence_gen","pre_demodulator","pre_simplifier","pre_simplify_expr","profile_res_sub","progress_sampling_freq","proof_mode","propagate_booleans","propagate_values","pull_cheap_ite_trees","pull_nested_quantifiers","qi_conservative_final_check","qi_cost","qi_eager_threshold","qi_lazy_instantiation","qi_lazy_quick_checker","qi_lazy_threshold","qi_max_eager_multi_patterns","qi_max_instances","qi_max_lazy_multi_pattern_matching","qi_new_gen","qi_profile","qi_profile_freq","qi_promote_unsat","qi_quick_checker","quasi_macros","random_case_split_freq","random_initial_activity","random_seed","recent_lemma_threshold","reduce_args","refine_inj_axiom","relevancy","relevancy_lemma","rel_case_split_order","restart_adaptive","restart_agility_threshold","restart_factor","restart_initial","restart_strategy","restricted_quasi_macros","simplify_clauses","smtlib2_compliant","smtlib_category","smtlib_dump_lemmas","smtlib_logic","smtlib_source_info","smtlib_trace_path","soft_timeout","solver","spc_bs","spc_es","spc_factor_subsumption_index_opt","spc_initial_subsumption_index_opt","spc_max_subsumption_index_features","spc_min_func_freq_subsumption_index","spc_num_iterations","spc_trace","statistics","strong_context_simplifier","tick","trace","trace_file_name","type_check","user_theory_persist_axioms","user_theory_preprocess_axioms","verbose","warning","well_sorted_check","z3_solver_ll_pp","z3_solver_smt_pp", nullptr }; bool is_old_param_name(symbol const & name) { char const * const * it = g_old_params_names; @@ -64,7 +64,7 @@ static char const * g_params_renames[] = { "pp_bv_neg", "pp.bv_neg", "pp_max_depth", "pp.max_depth", "pp_min_alias_size", "pp.min_alias_size", - 0 }; + nullptr }; char const * get_new_param_name(symbol const & p) { char const * const * it = g_params_renames; @@ -75,7 +75,7 @@ char const * get_new_param_name(symbol const & p) { } it += 2; } - return 0; + return nullptr; } struct gparams::imp { @@ -191,7 +191,7 @@ public: return m_params; } else { - params_ref * p = 0; + params_ref * p = nullptr; if (!m_module_params.find(mod_name, p)) { p = alloc(params_ref); m_module_params.insert(mod_name, p); @@ -279,7 +279,7 @@ public: throw_unknown_parameter(param_name, d, mod_name); } else if (k == CPK_UINT) { - long val = strtol(value, 0, 10); + long val = strtol(value, nullptr, 10); ps.set_uint(param_name, static_cast(val)); } else if (k == CPK_DOUBLE) { @@ -374,7 +374,7 @@ public: throw_unknown_parameter(p, d, m); } char const * r = d.get_default(p); - if (r == 0) + if (r == nullptr) return "default"; return r; } @@ -397,7 +397,7 @@ public: } } else { - params_ref * ps = 0; + params_ref * ps = nullptr; if (m_module_params.find(m, ps) && ps->contains(p)) { r = get_value(*ps, p); } @@ -427,7 +427,7 @@ public: params_ref get_module(symbol const & module_name) { params_ref result; - params_ref * ps = 0; + params_ref * ps = nullptr; #pragma omp critical (gparams) { if (m_module_params.find(module_name, ps)) { @@ -468,7 +468,7 @@ public: dictionary::iterator end = get_module_param_descrs().end(); for (; it != end; ++it) { out << "[module] " << it->m_key; - char const * descr = 0; + char const * descr = nullptr; if (get_module_descrs().find(it->m_key, descr)) { out << ", description: " << descr; } @@ -485,7 +485,7 @@ public: dictionary::iterator end = get_module_param_descrs().end(); for (; it != end; ++it) { out << "[module] " << it->m_key; - char const * descr = 0; + char const * descr = nullptr; if (get_module_descrs().find(it->m_key, descr)) { out << ", description: " << descr; } @@ -500,14 +500,14 @@ public: #pragma omp critical (gparams) { try { - param_descrs * d = 0; + param_descrs * d = nullptr; if (!get_module_param_descrs().find(module_name, d)) { std::stringstream strm; strm << "unknown module '" << module_name << "'"; throw exception(strm.str()); } out << "[module] " << module_name; - char const * descr = 0; + char const * descr = nullptr; if (get_module_descrs().find(module_name, descr)) { out << ", description: " << descr; } @@ -566,7 +566,7 @@ public: } }; -gparams::imp * gparams::g_imp = 0; +gparams::imp * gparams::g_imp = nullptr; void gparams::reset() { SASSERT(g_imp != 0); @@ -651,9 +651,9 @@ void gparams::init() { void gparams::finalize() { TRACE("gparams", tout << "gparams::finalize()\n";); - if (g_imp != 0) { + if (g_imp != nullptr) { dealloc(g_imp); - g_imp = 0; + g_imp = nullptr; } } diff --git a/src/util/hashtable.h b/src/util/hashtable.h index fa9fef180..0421fd300 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -91,9 +91,9 @@ class ptr_hash_entry { T * m_ptr; public: typedef T * data; - ptr_hash_entry():m_ptr(0) {} + ptr_hash_entry():m_ptr(nullptr) {} unsigned get_hash() const { return m_hash; } - bool is_free() const { return m_ptr == 0; } + bool is_free() const { return m_ptr == nullptr; } bool is_deleted() const { return m_ptr == reinterpret_cast(1); } bool is_used() const { return m_ptr != reinterpret_cast(0) && m_ptr != reinterpret_cast(1); } T * get_data() const { return m_ptr; } @@ -101,7 +101,7 @@ public: void set_data(T * d) { m_ptr = d; } void set_hash(unsigned h) { m_hash = h; } void mark_as_deleted() { m_ptr = reinterpret_cast(1); } - void mark_as_free() { m_ptr = 0; } + void mark_as_free() { m_ptr = nullptr; } }; @@ -114,9 +114,9 @@ class ptr_addr_hash_entry : public ptr_hash_entry { T * m_ptr; public: typedef T * data; - ptr_addr_hash_entry():m_ptr(0) {} + ptr_addr_hash_entry():m_ptr(nullptr) {} unsigned get_hash() const { return get_ptr_hash(m_ptr); } - bool is_free() const { return m_ptr == 0; } + bool is_free() const { return m_ptr == nullptr; } bool is_deleted() const { return m_ptr == reinterpret_cast(1); } bool is_used() const { return m_ptr != reinterpret_cast(0) && m_ptr != reinterpret_cast(1); } T * get_data() const { return m_ptr; } @@ -145,7 +145,7 @@ protected: void delete_table() { dealloc_vect(m_table, m_capacity); - m_table = 0; + m_table = nullptr; } public: @@ -385,7 +385,7 @@ public: entry * begin = m_table + idx; entry * end = m_table + m_capacity; entry * curr = begin; - entry * del_entry = 0; + entry * del_entry = nullptr; for (; curr != end; ++curr) { INSERT_LOOP_BODY(); } @@ -441,7 +441,7 @@ public: entry * begin = m_table + idx; entry * end = m_table + m_capacity; entry * curr = begin; - entry * del_entry = 0; + entry * del_entry = nullptr; for (; curr != end; ++curr) { INSERT_LOOP_CORE_BODY(); } @@ -504,12 +504,12 @@ public: for (curr = m_table; curr != begin; ++curr) { FIND_LOOP_BODY(); } - return 0; + return nullptr; } bool find(data const & k, data & r) const { entry * e = find_core(k); - if (e != 0) { + if (e != nullptr) { r = e->get_data(); return true; } @@ -517,7 +517,7 @@ public: } bool contains(data const & e) const { - return find_core(e) != 0; + return find_core(e) != nullptr; } iterator find(data const & e) const { diff --git a/src/util/list.h b/src/util/list.h index efde5ada1..075d5a0e1 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -28,7 +28,7 @@ class list { list * m_tail; public: - list(T const & h, list * t = 0): + list(T const & h, list * t = nullptr): m_head(h), m_tail(t) { } @@ -73,7 +73,7 @@ unsigned length(list * l) { */ template list * append(region & r, list * l1, list * l2) { - if (l2 == 0) { + if (l2 == nullptr) { return l1; } ptr_buffer > buffer; diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 61b0d9b38..32229cf27 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -481,7 +481,7 @@ public: } bool no_r_lu() const { - return m_r_solver.m_factorization == nullptr || m_r_solver.m_factorization->get_status() == LU_status::Degenerated; + return m_r_solver.m_factorization == nullptr || m_r_solver.m_factorization->get_status() == LU_status::Degenerated; } void solve_on_signature_tableau(const lar_solution_signature & signature, const vector & changes_of_basis) { diff --git a/src/util/map.h b/src/util/map.h index 3a59c8975..2ee540932 100644 --- a/src/util/map.h +++ b/src/util/map.h @@ -129,7 +129,7 @@ public: if (e) { v = e->get_data().m_value; } - return (0 != e); + return (nullptr != e); } value const& get(key const& k, value const& default_value) const { @@ -164,7 +164,7 @@ public: bool contains(key const & k) const { - return find_core(k) != 0; + return find_core(k) != nullptr; } void remove(key const & k) { diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 44157aa65..833ac8cbd 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -342,7 +342,7 @@ void * memory::allocate(size_t s) { if (counts_exceeded) throw_alloc_counts_exceeded(); void * r = malloc(s); - if (r == 0) + if (r == nullptr) throw_out_of_memory(); *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field @@ -370,7 +370,7 @@ void* memory::reallocate(void *p, size_t s) { if (counts_exceeded) throw_alloc_counts_exceeded(); void *r = realloc(real_p, s); - if (r == 0) + if (r == nullptr) throw_out_of_memory(); *(static_cast(r)) = s; return static_cast(r) + 1; // we return a pointer to the location after the extra field diff --git a/src/util/memory_manager.h b/src/util/memory_manager.h index 5aa512018..273fadea9 100644 --- a/src/util/memory_manager.h +++ b/src/util/memory_manager.h @@ -90,7 +90,7 @@ void deallocf(char const* file, int line, T * ptr) { template void dealloc(T * ptr) { - if (ptr == 0) return; + if (ptr == nullptr) return; ptr->~T(); memory::deallocate(ptr); } @@ -111,7 +111,7 @@ T * alloc_vect(unsigned sz) { template void dealloc_vect(T * ptr, unsigned sz) { - if (ptr == 0) return; + if (ptr == nullptr) return; T * curr = ptr; for (unsigned i = 0; i < sz; i++, curr++) curr->~T(); @@ -122,7 +122,7 @@ void dealloc_vect(T * ptr, unsigned sz) { template void dealloc_svect(T * ptr) { - if (ptr == 0) return; + if (ptr == nullptr) return; memory::deallocate(ptr); } diff --git a/src/util/mpfx.cpp b/src/util/mpfx.cpp index 24ef4dc73..e46708341 100644 --- a/src/util/mpfx.cpp +++ b/src/util/mpfx.cpp @@ -201,7 +201,7 @@ void mpfx_manager::set(mpfx & n, uint64 v) { n.m_sign = 0; unsigned * w = words(n); uint64 * _vp = &v; - unsigned * _v = 0; + unsigned * _v = nullptr; memcpy(&_v, &_vp, sizeof(unsigned*)); for (unsigned i = 0; i < m_total_sz; i++) w[i] = 0; diff --git a/src/util/mpz.h b/src/util/mpz.h index f4629958f..f4c3f6f0d 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -92,9 +92,9 @@ class mpz { friend class mpbq_manager; mpz & operator=(mpz const & other) { UNREACHABLE(); return *this; } public: - mpz(int v):m_val(v), m_ptr(0) {} - mpz():m_val(0), m_ptr(0) {} - mpz(mpz && other) : m_val(other.m_val), m_ptr(0) { + mpz(int v):m_val(v), m_ptr(nullptr) {} + mpz():m_val(0), m_ptr(nullptr) {} + mpz(mpz && other) : m_val(other.m_val), m_ptr(nullptr) { std::swap(m_ptr, other.m_ptr); } void swap(mpz & other) { @@ -333,16 +333,16 @@ public: ~mpz_manager(); - static bool is_small(mpz const & a) { return a.m_ptr == 0; } + static bool is_small(mpz const & a) { return a.m_ptr == nullptr; } static mpz mk_z(int val) { return mpz(val); } void del(mpz & a) { - if (a.m_ptr != 0) { + if (a.m_ptr != nullptr) { MPZ_BEGIN_CRITICAL(); deallocate(a.m_ptr); MPZ_END_CRITICAL(); - a.m_ptr = 0; + a.m_ptr = nullptr; } } diff --git a/src/util/obj_hashtable.h b/src/util/obj_hashtable.h index df279383b..8826e8b76 100644 --- a/src/util/obj_hashtable.h +++ b/src/util/obj_hashtable.h @@ -33,9 +33,9 @@ class obj_hash_entry { T * m_ptr; public: typedef T * data; - obj_hash_entry():m_ptr(0) {} + obj_hash_entry():m_ptr(nullptr) {} unsigned get_hash() const { return m_ptr->hash(); } - bool is_free() const { return m_ptr == 0; } + bool is_free() const { return m_ptr == nullptr; } bool is_deleted() const { return m_ptr == reinterpret_cast(1); } bool is_used() const { return m_ptr != reinterpret_cast(0) && m_ptr != reinterpret_cast(1); } T * get_data() const { return m_ptr; } @@ -43,7 +43,7 @@ public: void set_data(T * d) { m_ptr = d; } void set_hash(unsigned h) { SASSERT(h == m_ptr->hash()); } void mark_as_deleted() { m_ptr = reinterpret_cast(1); } - void mark_as_free() { m_ptr = 0; } + void mark_as_free() { m_ptr = nullptr; } }; template @@ -60,7 +60,7 @@ public: struct key_data { Key * m_key; Value m_value; - key_data():m_key(0) { + key_data():m_key(nullptr) { } key_data(Key * k): m_key(k) { @@ -85,7 +85,7 @@ public: typedef key_data data; obj_map_entry() {} unsigned get_hash() const { return m_data.hash(); } - bool is_free() const { return m_data.m_key == 0; } + bool is_free() const { return m_data.m_key == nullptr; } bool is_deleted() const { return m_data.m_key == reinterpret_cast(1); } bool is_used() const { return m_data.m_key != reinterpret_cast(0) && m_data.m_key != reinterpret_cast(1); } key_data const & get_data() const { return m_data; } @@ -93,7 +93,7 @@ public: void set_data(key_data && d) { m_data = std::move(d); } void set_hash(unsigned h) { SASSERT(h == m_data.hash()); } void mark_as_deleted() { m_data.m_key = reinterpret_cast(1); } - void mark_as_free() { m_data.m_key = 0; } + void mark_as_free() { m_data.m_key = nullptr; } }; typedef core_hashtable, default_eq > table; @@ -163,7 +163,7 @@ public: if (e) { v = e->get_data().m_value; } - return (0 != e); + return (nullptr != e); } value const & find(key * k) const { @@ -191,7 +191,7 @@ public: } bool contains(Key * k) const { - return find_core(k) != 0; + return find_core(k) != nullptr; } void remove(Key * k) { diff --git a/src/util/obj_pair_hashtable.h b/src/util/obj_pair_hashtable.h index 2addc3902..f002a7807 100644 --- a/src/util/obj_pair_hashtable.h +++ b/src/util/obj_pair_hashtable.h @@ -34,7 +34,7 @@ class obj_pair_hash_entry { public: typedef std::pair data; - obj_pair_hash_entry():m_data(static_cast(0),static_cast(0)) {} + obj_pair_hash_entry():m_data(static_cast(nullptr),static_cast(nullptr)) {} unsigned get_hash() const { return m_hash; } bool is_free() const { return m_data.first == 0; } bool is_deleted() const { return m_data.first == reinterpret_cast(1); } @@ -68,8 +68,8 @@ public: friend class entry; public: key_data(): - m_key1(0), - m_key2(0), + m_key1(nullptr), + m_key2(nullptr), m_hash(0) { } key_data(Key1 * k1, Key2 * k2): @@ -96,7 +96,7 @@ protected: typedef key_data data; entry() {} unsigned get_hash() const { return m_data.hash(); } - bool is_free() const { return m_data.m_key1 == 0; } + bool is_free() const { return m_data.m_key1 == nullptr; } bool is_deleted() const { return m_data.m_key1 == reinterpret_cast(1); } bool is_used() const { return m_data.m_key1 != reinterpret_cast(0) && m_data.m_key1 != reinterpret_cast(1); } key_data const & get_data() const { return m_data; } @@ -104,7 +104,7 @@ protected: void set_data(key_data const & d) { m_data = d; } void set_hash(unsigned h) { SASSERT(h == m_data.hash()); } void mark_as_deleted() { m_data.m_key1 = reinterpret_cast(1); } - void mark_as_free() { m_data.m_key1 = 0; } + void mark_as_free() { m_data.m_key1 = nullptr; } }; typedef core_hashtable, default_eq > table; @@ -158,11 +158,11 @@ public: if (e) { v = e->get_data().get_value(); } - return (0 != e); + return (nullptr != e); } bool contains(Key1 * k1, Key2 * k2) const { - return find_core(k1, k2) != 0; + return find_core(k1, k2) != nullptr; } void erase(Key1 * k1, Key2 * k2) { diff --git a/src/util/obj_ref.h b/src/util/obj_ref.h index 72762ea5b..409a77fc0 100644 --- a/src/util/obj_ref.h +++ b/src/util/obj_ref.h @@ -43,7 +43,7 @@ public: } explicit obj_ref(TManager & m): - m_obj(0), + m_obj(nullptr), m_manager(m) { } @@ -53,7 +53,7 @@ public: inc_ref(); } - obj_ref(obj_ref && other) : m_obj(0), m_manager(other.m_manager) { + obj_ref(obj_ref && other) : m_obj(nullptr), m_manager(other.m_manager) { std::swap(m_obj, other.m_obj); } @@ -67,9 +67,9 @@ public: T * get() const { return m_obj; } - operator bool() const { return m_obj != 0; } + operator bool() const { return m_obj != nullptr; } - bool operator!() const { return m_obj == 0; } + bool operator!() const { return m_obj == nullptr; } operator T*() const { return m_obj; } @@ -94,7 +94,7 @@ public: void reset() { dec_ref(); - m_obj = 0; + m_obj = nullptr; } void swap(obj_ref & n) { diff --git a/src/util/obj_triple_hashtable.h b/src/util/obj_triple_hashtable.h index 316b63b93..d9034c2e3 100644 --- a/src/util/obj_triple_hashtable.h +++ b/src/util/obj_triple_hashtable.h @@ -70,9 +70,9 @@ public: friend class entry; public: key_data(): - m_key1(0), - m_key2(0), - m_key3(0), + m_key1(nullptr), + m_key2(nullptr), + m_key3(nullptr), m_hash(0) { } key_data(Key1 * k1, Key2 * k2, Key3 * k3): @@ -102,7 +102,7 @@ protected: typedef key_data data; entry() {} unsigned get_hash() const { return m_data.hash(); } - bool is_free() const { return m_data.m_key1 == 0; } + bool is_free() const { return m_data.m_key1 == nullptr; } bool is_deleted() const { return m_data.m_key1 == reinterpret_cast(1); } bool is_used() const { return m_data.m_key1 != reinterpret_cast(0) && m_data.m_key1 != reinterpret_cast(1); } key_data const & get_data() const { return m_data; } @@ -110,7 +110,7 @@ protected: void set_data(key_data const & d) { m_data = d; } void set_hash(unsigned h) { SASSERT(h == m_data.hash()); } void mark_as_deleted() { m_data.m_key1 = reinterpret_cast(1); } - void mark_as_free() { m_data.m_key1 = 0; } + void mark_as_free() { m_data.m_key1 = nullptr; } }; typedef core_hashtable, default_eq > table; @@ -164,7 +164,7 @@ public: if (e) { v = e->get_data().get_value(); } - return (0 != e); + return (nullptr != e); } bool contains(Key1 * k1, Key2 * k2, Key3 * k3) const { diff --git a/src/util/optional.h b/src/util/optional.h index 5b3753ac6..d496fd322 100644 --- a/src/util/optional.h +++ b/src/util/optional.h @@ -34,14 +34,14 @@ class optional { void destroy() { if (m_initialized == 1) { dealloc(m_obj); - m_obj = 0; + m_obj = nullptr; } m_initialized = 0; } public: optional(): - m_obj(0), m_initialized(0) {} + m_obj(nullptr), m_initialized(0) {} explicit optional(const T & val) { construct(val); @@ -128,7 +128,7 @@ class optional { public: - optional():m_ptr(0) {} + optional():m_ptr(nullptr) {} explicit optional(T * val):m_ptr(val) {} @@ -140,7 +140,7 @@ public: operator bool() const { return m_ptr != 0; } - bool operator!() const { return m_ptr == 0; } + bool operator!() const { return m_ptr == nullptr; } void reset() { m_ptr = 0; } diff --git a/src/util/page.cpp b/src/util/page.cpp index 4f6cea83c..ebf246fc1 100644 --- a/src/util/page.cpp +++ b/src/util/page.cpp @@ -31,7 +31,7 @@ inline char * alloc_page(size_t s) { char * r = alloc_svect(char, s+PAGE_HEADER_ inline void del_page(char * page) { dealloc_svect(page - PAGE_HEADER_SZ); } void del_pages(char * page) { - while (page != 0) { + while (page != nullptr) { char * prev = prev_page(page); del_page(page); page = prev; diff --git a/src/util/params.cpp b/src/util/params.cpp index ee6ce6627..5e1e517c1 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -24,7 +24,7 @@ Notes: params_ref params_ref::g_empty_params_ref; std::string norm_param_name(char const * n) { - if (n == 0) + if (n == nullptr) return "_"; if (*n == ':') n++; @@ -62,9 +62,9 @@ struct param_descrs::imp { info(): m_kind(CPK_INVALID), - m_descr(0), - m_default(0), - m_module(0) { + m_descr(nullptr), + m_default(nullptr), + m_module(nullptr) { } }; @@ -130,21 +130,21 @@ struct param_descrs::imp { info i; if (m_info.find(name, i)) return i.m_module; - return 0; + return nullptr; } char const * get_descr(symbol const & name) const { info i; if (m_info.find(name, i)) return i.m_descr; - return 0; + return nullptr; } char const * get_default(symbol const & name) const { info i; if (m_info.find(name, i)) return i.m_default; - return 0; + return nullptr; } unsigned size() const { @@ -191,7 +191,7 @@ struct param_descrs::imp { out << " (" << d.m_kind << ")"; if (include_descr) out << " " << d.m_descr; - if (d.m_default != 0) + if (d.m_default != nullptr) out << " (default: " << d.m_default << ")"; out << "\n"; } @@ -510,7 +510,7 @@ params_ref::~params_ref() { } params_ref::params_ref(params_ref const & p): - m_params(0) { + m_params(nullptr) { operator=(p); } @@ -554,7 +554,7 @@ params_ref & params_ref::operator=(params_ref const & p) { } void params_ref::copy(params_ref const & src) { - if (m_params == 0) + if (m_params == nullptr) operator=(src); else { init(); @@ -563,7 +563,7 @@ void params_ref::copy(params_ref const & src) { } void params_ref::copy_core(params const * src) { - if (src == 0) + if (src == nullptr) return; svector::const_iterator it = src->m_entries.begin(); svector::const_iterator end = src->m_entries.end(); diff --git a/src/util/params.h b/src/util/params.h index bad70a318..0a68a9606 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -37,7 +37,7 @@ class params_ref { void init(); void copy_core(params const * p); public: - params_ref():m_params(0) {} + params_ref():m_params(nullptr) {} params_ref(params_ref const & p); ~params_ref(); @@ -115,8 +115,8 @@ public: param_descrs(); ~param_descrs(); void copy(param_descrs & other); - void insert(char const * name, param_kind k, char const * descr, char const * def = 0, char const* module = 0); - void insert(symbol const & name, param_kind k, char const * descr, char const * def = 0, char const* module = 0); + void insert(char const * name, param_kind k, char const * descr, char const * def = nullptr, char const* module = nullptr); + void insert(symbol const & name, param_kind k, char const * descr, char const * def = nullptr, char const* module = nullptr); bool contains(char const * name) const; bool contains(symbol const & name) const; void erase(char const * name); diff --git a/src/util/parray.h b/src/util/parray.h index 44b075db9..38d6987d0 100644 --- a/src/util/parray.h +++ b/src/util/parray.h @@ -30,7 +30,7 @@ public: typedef typename C::allocator allocator; private: static size_t capacity(value * vs) { - return vs == 0 ? 0 : (reinterpret_cast(vs))[-1]; + return vs == nullptr ? 0 : (reinterpret_cast(vs))[-1]; } value * allocate_values(size_t c) { @@ -44,7 +44,7 @@ private: } void deallocate_values(value * vs) { - if (vs == 0) + if (vs == nullptr) return; size_t c = capacity(vs); TRACE("parray_mem", tout << "deallocated values[" << c << "]: " << vs << "\n";); @@ -73,7 +73,7 @@ private: unsigned size() const { SASSERT(kind() == ROOT); return m_size; } cell * next() const { SASSERT(kind() != ROOT); return m_next; } value const & elem() const { SASSERT(kind() == SET || kind() == PUSH_BACK); return m_elem; } - cell(ckind k):m_ref_count(1), m_kind(k), m_size(0), m_values(0) {} + cell(ckind k):m_ref_count(1), m_kind(k), m_size(0), m_values(nullptr) {} }; value_manager & m_vmanager; @@ -105,7 +105,7 @@ private: void del(cell * c) { while (true) { - cell * next = 0; + cell * next = nullptr; switch (c->kind()) { case SET: case PUSH_BACK: @@ -123,7 +123,7 @@ private: TRACE("parray_mem", tout << "deallocated cell: " << c << "\n";); c->~cell(); m_allocator.deallocate(sizeof(cell), c); - if (next == 0) + if (next == nullptr) return; SASSERT(next->m_ref_count > 0); next->m_ref_count--; @@ -214,7 +214,7 @@ private: } SASSERT(r->kind() == ROOT); unsigned sz = r->m_size; - vs = 0; + vs = nullptr; copy_values(r->m_values, sz, vs); unsigned i = cs.size(); while (i > 0) { @@ -246,7 +246,7 @@ private: dec_ref(c->m_next); if (c->kind() == SET || c->kind() == PUSH_BACK) dec_ref(c->m_elem); - c->m_next = 0; + c->m_next = nullptr; c->m_kind = ROOT; c->m_size = sz; c->m_values = vs; @@ -262,7 +262,7 @@ public: bool unshared() const { return m_ref->m_ref_count == 1; } friend class parray_manager; public: - ref():m_ref(0), m_updt_counter(0) {} + ref():m_ref(nullptr), m_updt_counter(0) {} }; public: @@ -283,7 +283,7 @@ public: void del(ref & r) { dec_ref(r.m_ref); - r.m_ref = 0; + r.m_ref = nullptr; r.m_updt_counter = 0; } @@ -296,7 +296,7 @@ public: unsigned size(ref const & r) const { cell * c = r.m_ref; - if (c == 0) return 0; + if (c == nullptr) return 0; while (true) { switch (c->kind()) { case SET: @@ -397,7 +397,7 @@ public: } void push_back(ref & r, value const & v) { - if (r.m_ref == 0) + if (r.m_ref == nullptr) mk(r); if (r.root()) { if (r.unshared()) { diff --git a/src/util/plugin_manager.h b/src/util/plugin_manager.h index da7017aa1..c8908fd57 100644 --- a/src/util/plugin_manager.h +++ b/src/util/plugin_manager.h @@ -48,7 +48,7 @@ public: Plugin * get_plugin(family_id fid) const { if (fid == null_family_id) { - return 0; + return nullptr; } return m_fid2plugins.get(fid, 0); } diff --git a/src/util/prime_generator.cpp b/src/util/prime_generator.cpp index eac47f61b..dbcccaaf7 100644 --- a/src/util/prime_generator.cpp +++ b/src/util/prime_generator.cpp @@ -99,7 +99,7 @@ uint64 prime_generator::operator()(unsigned idx) { prime_generator g_prime_generator; prime_iterator::prime_iterator(prime_generator * g):m_idx(0) { - if (g == 0) { + if (g == nullptr) { m_generator = &g_prime_generator; m_global = true; } diff --git a/src/util/prime_generator.h b/src/util/prime_generator.h index 6a284c57c..2e16ebfbe 100644 --- a/src/util/prime_generator.h +++ b/src/util/prime_generator.h @@ -45,7 +45,7 @@ class prime_iterator { prime_generator * m_generator; bool m_global; public: - prime_iterator(prime_generator * g = 0); + prime_iterator(prime_generator * g = nullptr); uint64 next(); static void finalize(); /* diff --git a/src/util/rational.cpp b/src/util/rational.cpp index ce38bcaa7..e8c2d52d1 100644 --- a/src/util/rational.cpp +++ b/src/util/rational.cpp @@ -23,7 +23,7 @@ Revision History: #include #endif -synch_mpq_manager * rational::g_mpq_manager = 0; +synch_mpq_manager * rational::g_mpq_manager = nullptr; rational rational::m_zero; rational rational::m_one; rational rational::m_minus_one; @@ -80,6 +80,6 @@ void rational::finalize() { m_one.~rational(); m_minus_one.~rational(); dealloc(g_mpq_manager); - g_mpq_manager = 0; + g_mpq_manager = nullptr; } diff --git a/src/util/ref.h b/src/util/ref.h index 811aba9af..ea6b7a624 100644 --- a/src/util/ref.h +++ b/src/util/ref.h @@ -37,7 +37,7 @@ class ref { public: ref(): - m_ptr(0) { + m_ptr(nullptr) { } ref(T * ptr): @@ -64,7 +64,7 @@ public: } operator bool() const { - return m_ptr != 0; + return m_ptr != nullptr; } const T & operator*() const { @@ -100,12 +100,12 @@ public: void reset() { dec_ref(); - m_ptr = 0; + m_ptr = nullptr; } T* detach() { T* tmp = m_ptr; - m_ptr = 0; + m_ptr = nullptr; return tmp; } diff --git a/src/util/region.cpp b/src/util/region.cpp index 4e5b5f2f2..3cf3f502f 100644 --- a/src/util/region.cpp +++ b/src/util/region.cpp @@ -38,11 +38,11 @@ inline void region::allocate_page() { } region::region() { - m_curr_page = 0; - m_curr_ptr = 0; - m_curr_end_ptr = 0; - m_free_pages = 0; - m_mark = 0; + m_curr_page = nullptr; + m_curr_ptr = nullptr; + m_curr_end_ptr = nullptr; + m_free_pages = nullptr; + m_mark = nullptr; allocate_page(); } @@ -81,13 +81,13 @@ inline void region::recycle_curr_page() { } void region::reset() { - while (m_curr_page != 0) { + while (m_curr_page != nullptr) { recycle_curr_page(); } SASSERT(m_curr_page == 0); - m_curr_ptr = 0; - m_curr_end_ptr = 0; - m_mark = 0; + m_curr_ptr = nullptr; + m_curr_end_ptr = nullptr; + m_mark = nullptr; allocate_page(); } @@ -113,7 +113,7 @@ void region::pop_scope() { void region::display_mem_stats(std::ostream & out) const { unsigned n = 0; char * page = m_curr_page; - while (page != 0) { + while (page != nullptr) { n++; page = prev_page(page); } diff --git a/src/util/s_integer.cpp b/src/util/s_integer.cpp index cfaf34fff..e76781388 100644 --- a/src/util/s_integer.cpp +++ b/src/util/s_integer.cpp @@ -24,7 +24,7 @@ s_integer s_integer::m_one(1); s_integer s_integer::m_minus_one(-1); s_integer::s_integer(const char * str) { - m_val = static_cast(strtol(str, 0, 10)); + m_val = static_cast(strtol(str, nullptr, 10)); } s_integer power(const s_integer & r, unsigned p) { diff --git a/src/util/scoped_ctrl_c.cpp b/src/util/scoped_ctrl_c.cpp index 1cb3a03c4..2dbbaec9b 100644 --- a/src/util/scoped_ctrl_c.cpp +++ b/src/util/scoped_ctrl_c.cpp @@ -20,7 +20,7 @@ Revision History: #include #include "util/scoped_ctrl_c.h" -scoped_ctrl_c * scoped_ctrl_c::g_obj = 0; +scoped_ctrl_c * scoped_ctrl_c::g_obj = nullptr; void scoped_ctrl_c::on_ctrl_c(int) { if (g_obj->m_first) { diff --git a/src/util/scoped_ptr_vector.h b/src/util/scoped_ptr_vector.h index 0bd0fd47e..920ecb2c9 100644 --- a/src/util/scoped_ptr_vector.h +++ b/src/util/scoped_ptr_vector.h @@ -30,7 +30,7 @@ public: ~scoped_ptr_vector() { reset(); } void reset() { std::for_each(m_vector.begin(), m_vector.end(), delete_proc()); m_vector.reset(); } void push_back(T * ptr) { m_vector.push_back(ptr); } - void pop_back() { SASSERT(!empty()); set(size()-1, 0); m_vector.pop_back(); } + void pop_back() { SASSERT(!empty()); set(size()-1, nullptr); m_vector.pop_back(); } T * operator[](unsigned idx) const { return m_vector[idx]; } void set(unsigned idx, T * ptr) { if (m_vector[idx] == ptr) @@ -48,7 +48,7 @@ public: } else { for (unsigned i = m_vector.size(); i < sz; i++) - push_back(0); + push_back(nullptr); } } }; diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 3991abd36..1ecca8ffe 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -157,9 +157,9 @@ struct scoped_timer::imp { m_interval = ms?ms:0xFFFFFFFF; if (pthread_attr_init(&m_attributes) != 0) throw default_exception("failed to initialize timer thread attributes"); - if (pthread_cond_init(&m_condition_var, NULL) != 0) + if (pthread_cond_init(&m_condition_var, nullptr) != 0) throw default_exception("failed to initialize timer condition variable"); - if (pthread_mutex_init(&m_mutex, NULL) != 0) + if (pthread_mutex_init(&m_mutex, nullptr) != 0) throw default_exception("failed to initialize timer mutex"); clock_serv_t host_clock; @@ -208,7 +208,7 @@ struct scoped_timer::imp { pthread_cond_signal(&m_condition_var); pthread_mutex_unlock(&m_mutex); - if (pthread_join(m_thread_id, NULL) != 0) + if (pthread_join(m_thread_id, nullptr) != 0) throw default_exception("failed to join thread"); if (pthread_mutex_destroy(&m_mutex) != 0) throw default_exception("failed to destroy pthread mutex"); @@ -248,7 +248,7 @@ scoped_timer::scoped_timer(unsigned ms, event_handler * eh) { if (ms != UINT_MAX && ms != 0) m_imp = alloc(imp, ms, eh); else - m_imp = 0; + m_imp = nullptr; } scoped_timer::~scoped_timer() { diff --git a/src/util/small_object_allocator.cpp b/src/util/small_object_allocator.cpp index 0eb7b9ec3..9f15aadaf 100644 --- a/src/util/small_object_allocator.cpp +++ b/src/util/small_object_allocator.cpp @@ -27,8 +27,8 @@ Revision History: small_object_allocator::small_object_allocator(char const * id) { for (unsigned i = 0; i < NUM_SLOTS; i++) { - m_chunks[i] = 0; - m_free_list[i] = 0; + m_chunks[i] = nullptr; + m_free_list[i] = nullptr; } DEBUG_CODE({ m_id = id; @@ -60,8 +60,8 @@ void small_object_allocator::reset() { dealloc(c); c = next; } - m_chunks[i] = 0; - m_free_list[i] = 0; + m_chunks[i] = nullptr; + m_free_list[i] = nullptr; } m_alloc_size = 0; } @@ -95,7 +95,7 @@ void small_object_allocator::deallocate(size_t size, void * p) { void * small_object_allocator::allocate(size_t size) { - if (size == 0) return 0; + if (size == 0) return nullptr; #if defined(Z3DEBUG) && !defined(_WINDOWS) // Valgrind friendly @@ -113,7 +113,7 @@ void * small_object_allocator::allocate(size_t size) { slot_id++; SASSERT(slot_id < NUM_SLOTS); SASSERT(slot_id > 0); - if (m_free_list[slot_id] != 0) { + if (m_free_list[slot_id] != nullptr) { void * r = m_free_list[slot_id]; m_free_list[slot_id] = *(reinterpret_cast(r)); return r; @@ -121,7 +121,7 @@ void * small_object_allocator::allocate(size_t size) { chunk * c = m_chunks[slot_id]; size = slot_id << PTR_ALIGNMENT; SASSERT(size >= osize); - if (c != 0) { + if (c != nullptr) { char * new_curr = c->m_curr + size; if (new_curr < c->m_data + CHUNK_SIZE) { void * r = c->m_curr; @@ -142,7 +142,7 @@ size_t small_object_allocator::get_wasted_size() const { for (unsigned slot_id = 0; slot_id < NUM_SLOTS; slot_id++) { size_t slot_obj_size = slot_id << PTR_ALIGNMENT; void ** ptr = reinterpret_cast(const_cast(this)->m_free_list[slot_id]); - while (ptr != 0) { + while (ptr != nullptr) { r += slot_obj_size; ptr = reinterpret_cast(*ptr); } @@ -154,7 +154,7 @@ size_t small_object_allocator::get_num_free_objs() const { size_t r = 0; for (unsigned slot_id = 0; slot_id < NUM_SLOTS; slot_id++) { void ** ptr = reinterpret_cast(const_cast(this)->m_free_list[slot_id]); - while (ptr != 0) { + while (ptr != nullptr) { r ++; ptr = reinterpret_cast(*ptr); } @@ -177,17 +177,17 @@ void small_object_allocator::consolidate() { ptr_vector chunks; ptr_vector free_objs; for (unsigned slot_id = 1; slot_id < NUM_SLOTS; slot_id++) { - if (m_free_list[slot_id] == 0) + if (m_free_list[slot_id] == nullptr) continue; chunks.reset(); free_objs.reset(); chunk * c = m_chunks[slot_id]; - while (c != 0) { + while (c != nullptr) { chunks.push_back(c); c = c->m_next; } char * ptr = static_cast(m_free_list[slot_id]); - while (ptr != 0) { + while (ptr != nullptr) { free_objs.push_back(ptr); ptr = *(reinterpret_cast(ptr)); } @@ -198,8 +198,8 @@ void small_object_allocator::consolidate() { SASSERT(!chunks.empty()); std::sort(chunks.begin(), chunks.end(), ptr_lt()); std::sort(free_objs.begin(), free_objs.end(), ptr_lt()); - chunk * last_chunk = 0; - void * last_free_obj = 0; + chunk * last_chunk = nullptr; + void * last_free_obj = nullptr; unsigned chunk_idx = 0; unsigned obj_idx = 0; unsigned num_chunks = chunks.size(); diff --git a/src/util/smt2_util.cpp b/src/util/smt2_util.cpp index 731c91848..8358c67ac 100644 --- a/src/util/smt2_util.cpp +++ b/src/util/smt2_util.cpp @@ -29,7 +29,7 @@ bool is_smt2_simple_symbol_char(char s) { } bool is_smt2_quoted_symbol(char const * s) { - if (s == 0) + if (s == nullptr) return false; if ('0' <= s[0] && s[0] <= '9') return true; diff --git a/src/util/stack.cpp b/src/util/stack.cpp index 81383e2fe..156436496 100644 --- a/src/util/stack.cpp +++ b/src/util/stack.cpp @@ -62,10 +62,10 @@ inline void stack::store_mark(void * ptr, bool external) { } stack::stack() { - m_curr_page = 0; - m_curr_ptr = 0; - m_curr_end_ptr = 0; - m_free_pages = 0; + m_curr_page = nullptr; + m_curr_ptr = nullptr; + m_curr_end_ptr = nullptr; + m_free_pages = nullptr; allocate_page(0); SASSERT(empty()); } diff --git a/src/util/symbol.cpp b/src/util/symbol.cpp index 8f46272f0..220711003 100644 --- a/src/util/symbol.cpp +++ b/src/util/symbol.cpp @@ -22,7 +22,7 @@ Revision History: #include "util/string_buffer.h" #include "util/z3_omp.h" -symbol symbol::m_dummy(TAG(void*, static_cast(0), 2)); +symbol symbol::m_dummy(TAG(void*, nullptr, 2)); const symbol symbol::null; /** @@ -60,7 +60,7 @@ public: } }; -internal_symbol_table* g_symbol_table = 0; +internal_symbol_table* g_symbol_table = nullptr; void initialize_symbols() { if (!g_symbol_table) { @@ -70,12 +70,12 @@ void initialize_symbols() { void finalize_symbols() { dealloc(g_symbol_table); - g_symbol_table = 0; + g_symbol_table = nullptr; } symbol::symbol(char const * d) { - if (d == 0) - m_data = 0; + if (d == nullptr) + m_data = nullptr; else m_data = g_symbol_table->get_str(d); } @@ -103,7 +103,7 @@ std::string symbol::str() const { bool symbol::contains(char ch) const { SASSERT(!is_marked()); if (GET_TAG(m_data) == 0) { - return strchr(m_data, ch) != 0; + return strchr(m_data, ch) != nullptr; } else { return false; diff --git a/src/util/symbol.h b/src/util/symbol.h index 874b258e9..6a6e93747 100644 --- a/src/util/symbol.h +++ b/src/util/symbol.h @@ -51,7 +51,7 @@ class symbol { static symbol m_dummy; public: symbol(): - m_data(0) { + m_data(nullptr) { } explicit symbol(char const * d); explicit symbol(unsigned idx): @@ -69,9 +69,9 @@ public: unsigned int get_num() const { SASSERT(is_numerical()); return UNBOXINT(m_data); } std::string str() const; friend bool operator==(symbol const & s1, char const * s2) { - if (s1.m_data == 0 && s2 == 0) + if (s1.m_data == nullptr && s2 == nullptr) return true; - if (s1.m_data == 0 || s2 == 0) + if (s1.m_data == nullptr || s2 == nullptr) return false; if (!s1.is_numerical()) return strcmp(s1.bare_str(), s2) == 0; @@ -87,7 +87,7 @@ public: return s; } unsigned hash() const { - if (m_data == 0) return 0x9e3779d9; + if (m_data == nullptr) return 0x9e3779d9; else if (is_numerical()) return get_num(); else return static_cast(reinterpret_cast(m_data)[-1]); } diff --git a/src/util/symbol_table.h b/src/util/symbol_table.h index 818cb7584..e3abd4051 100644 --- a/src/util/symbol_table.h +++ b/src/util/symbol_table.h @@ -121,7 +121,7 @@ public: bool find(symbol key, T & result) const { key_data dummy(key); hash_entry * e = m_sym_table.find_core(dummy); - if (e == 0) { + if (e == nullptr) { return false; } result = e->get_data().m_data; @@ -140,7 +140,7 @@ public: if (get_scope_level() > 0) { key_data dummy(key); hash_entry * e = m_sym_table.find_core(dummy); - if (e != 0) { + if (e != nullptr) { m_trail_stack.push_back(e->m_data); e->m_data.m_data = data; return; diff --git a/src/util/timeit.cpp b/src/util/timeit.cpp index 97df87ecd..2a78f08a3 100644 --- a/src/util/timeit.cpp +++ b/src/util/timeit.cpp @@ -49,7 +49,7 @@ timeit::timeit(bool enable, char const * msg, std::ostream & out) { if (enable) m_imp = alloc(imp, msg, out); else - m_imp = 0; + m_imp = nullptr; } timeit::~timeit() { diff --git a/src/util/timeout.cpp b/src/util/timeout.cpp index 496c5c859..283b4c206 100644 --- a/src/util/timeout.cpp +++ b/src/util/timeout.cpp @@ -27,8 +27,8 @@ Revision History: #include "util/event_handler.h" #include "util/scoped_timer.h" -scoped_timer * g_timeout = 0; -void (* g_on_timeout)() = 0; +scoped_timer * g_timeout = nullptr; +void (* g_on_timeout)() = nullptr; class g_timeout_eh : public event_handler { public: @@ -41,7 +41,7 @@ public: g_on_timeout(); if (g_timeout) delete g_timeout; - g_timeout = 0; + g_timeout = nullptr; throw z3_error(ERR_TIMEOUT); } } diff --git a/src/util/trace.cpp b/src/util/trace.cpp index d993ebd11..9571e99e6 100644 --- a/src/util/trace.cpp +++ b/src/util/trace.cpp @@ -24,7 +24,7 @@ std::ofstream tout(".z3-trace"); #endif static bool g_enable_all_trace_tags = false; -static str_hashtable* g_enabled_trace_tags = 0; +static str_hashtable* g_enabled_trace_tags = nullptr; static str_hashtable& get_enabled_trace_tags() { if (!g_enabled_trace_tags) { @@ -35,7 +35,7 @@ static str_hashtable& get_enabled_trace_tags() { void finalize_trace() { dealloc(g_enabled_trace_tags); - g_enabled_trace_tags = 0; + g_enabled_trace_tags = nullptr; } void enable_trace(const char * tag) { diff --git a/src/util/trail.h b/src/util/trail.h index adcd57860..b9f4602c7 100644 --- a/src/util/trail.h +++ b/src/util/trail.h @@ -77,7 +77,7 @@ public: } void undo(Ctx & ctx) override { - m_ptr = 0; + m_ptr = nullptr; } }; diff --git a/src/util/util.cpp b/src/util/util.cpp index b16dbe292..0b58419f8 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -40,7 +40,7 @@ std::ostream& verbose_stream() { } -static void (*g_fatal_error_handler)(int) = 0; +static void (*g_fatal_error_handler)(int) = nullptr; void fatal_error(int error_code) { if (g_fatal_error_handler) { @@ -120,7 +120,7 @@ bool product_iterator_next(unsigned n, unsigned const * sz, unsigned * it) { } char const * escaped::end() const { - if (m_str == 0) return 0; + if (m_str == nullptr) return nullptr; char const * it = m_str; char const * e = m_str; while (*it) { diff --git a/src/util/util.h b/src/util/util.h index 6d38231ba..ad427dfaf 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -222,7 +222,7 @@ template class scoped_ptr { T * m_ptr; public: - scoped_ptr(T * ptr=0): + scoped_ptr(T * ptr=nullptr): m_ptr(ptr) { } @@ -239,7 +239,7 @@ public: } operator bool() const { - return m_ptr != 0; + return m_ptr != nullptr; } const T & operator*() const { @@ -260,7 +260,7 @@ public: T * detach() { T* tmp = m_ptr; - m_ptr = 0; + m_ptr = nullptr; return tmp; } diff --git a/src/util/vector.h b/src/util/vector.h index f5792a5d3..85aeab3d3 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -57,7 +57,7 @@ class vector { } void expand_vector() { - if (m_data == 0) { + if (m_data == nullptr) { SZ capacity = 2; SZ * mem = reinterpret_cast(memory::allocate(sizeof(T) * capacity + sizeof(SZ) * 2)); *mem = capacity; @@ -132,12 +132,12 @@ public: typedef const T * const_iterator; vector(): - m_data(0) { + m_data(nullptr) { } vector(SZ s) { if (s == 0) { - m_data = 0; + m_data = nullptr; return; } SZ * mem = reinterpret_cast(memory::allocate(sizeof(T) * s + sizeof(SZ) * 2)); @@ -155,24 +155,24 @@ public: } vector(SZ s, T const & elem): - m_data(0) { + m_data(nullptr) { resize(s, elem); } vector(vector const & source): - m_data(0) { + m_data(nullptr) { if (source.m_data) { copy_core(source); } SASSERT(size() == source.size()); } - vector(vector&& other) : m_data(0) { + vector(vector&& other) : m_data(nullptr) { std::swap(m_data, other.m_data); } vector(SZ s, T const * data): - m_data(0) { + m_data(nullptr) { for (SZ i = 0; i < s; i++) { push_back(data[i]); } @@ -185,7 +185,7 @@ public: void finalize() { destroy(); - m_data = 0; + m_data = nullptr; } vector & operator=(vector const & source) { @@ -197,7 +197,7 @@ public: copy_core(source); } else { - m_data = 0; + m_data = nullptr; } return *this; } @@ -207,7 +207,7 @@ public: return *this; } destroy(); - m_data = 0; + m_data = nullptr; std::swap(m_data, source.m_data); return *this; } @@ -224,18 +224,18 @@ public: void clear() { reset(); } bool empty() const { - return m_data == 0 || reinterpret_cast(m_data)[SIZE_IDX] == 0; + return m_data == nullptr || reinterpret_cast(m_data)[SIZE_IDX] == 0; } SZ size() const { - if (m_data == 0) { + if (m_data == nullptr) { return 0; } return reinterpret_cast(m_data)[SIZE_IDX]; } SZ capacity() const { - if (m_data == 0) { + if (m_data == nullptr) { return 0; } return reinterpret_cast(m_data)[CAPACITY_IDX]; @@ -349,7 +349,7 @@ public: } void push_back(T const & elem) { - if (m_data == 0 || reinterpret_cast(m_data)[SIZE_IDX] == reinterpret_cast(m_data)[CAPACITY_IDX]) { + if (m_data == nullptr || reinterpret_cast(m_data)[SIZE_IDX] == reinterpret_cast(m_data)[CAPACITY_IDX]) { expand_vector(); } new (m_data + reinterpret_cast(m_data)[SIZE_IDX]) T(elem); @@ -357,7 +357,7 @@ public: } void push_back(T && elem) { - if (m_data == 0 || reinterpret_cast(m_data)[SIZE_IDX] == reinterpret_cast(m_data)[CAPACITY_IDX]) { + if (m_data == nullptr || reinterpret_cast(m_data)[SIZE_IDX] == reinterpret_cast(m_data)[CAPACITY_IDX]) { expand_vector(); } new (m_data + reinterpret_cast(m_data)[SIZE_IDX]) T(std::move(elem)); diff --git a/src/util/warning.cpp b/src/util/warning.cpp index a794b064a..6184db880 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -62,8 +62,8 @@ void STD_CALL myInvalidParameterHandler( static bool g_warning_msgs = true; static bool g_use_std_stdout = false; -static std::ostream* g_error_stream = 0; -static std::ostream* g_warning_stream = 0; +static std::ostream* g_error_stream = nullptr; +static std::ostream* g_warning_stream = nullptr; static bool g_show_error_msg_prefix = true; void send_warnings_to_stdout(bool flag) { From e1100af52c1ee4201cb7922e69dbffb02417fa72 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Feb 2018 12:04:24 -0800 Subject: [PATCH 0570/1283] ensure that final model is logged by the time it is produced fix #1463 Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 178b87037..f0345232d 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -718,7 +718,7 @@ public: } } - if (upper >= m_upper) { + if (upper > m_upper) { return; } From 792fdb915f7098177e6414e25a59373d3c7b9ca7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Feb 2018 13:07:09 -0800 Subject: [PATCH 0571/1283] remove deprecated comments about bv2int/int2bv being treated as uninterpreted, raise in #1481 Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 5e5b84450..ea0c1615f 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -2857,9 +2857,8 @@ extern "C" { /** \brief Create an \c n bit bit-vector from the integer argument \c t1. - NB. This function is essentially treated as uninterpreted. - So you cannot expect Z3 to precisely reflect the semantics of this function - when solving constraints with this function. + The resulting bit-vector has \c n bits, where the i'th bit (counting + from 0 to \c n-1) is 1 if \c (t1 div 2^i) mod 2 is 1. The node \c t1 must have integer sort. @@ -2874,9 +2873,6 @@ extern "C" { and in the range \ccode{[0..2^N-1]}, where N are the number of bits in \c t1. If \c is_signed is true, \c t1 is treated as a signed bit-vector. - This function is essentially treated as uninterpreted. - So you cannot expect Z3 to precisely reflect the semantics of this function - when solving constraints with this function. The node \c t1 must have a bit-vector sort. From 762129d4c7df6563cca451f3d33210cc094bae3d Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 12 Feb 2018 17:45:07 -0500 Subject: [PATCH 0572/1283] fixups to theory_str for regex --- src/smt/theory_str.cpp | 18 +++++++++++++----- src/smt/theory_str.h | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 8157ceea9..e68a7fa8a 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6571,7 +6571,7 @@ namespace smt { SASSERT(str1.length() == 1); SASSERT(str2.length() == 1); return 1 + str2[0] - str1[0]; - } else if (u.re.is_full(re)) { + } else if (u.re.is_full_char(re) || u.re.is_full_seq(re)) { return 1; } else { TRACE("str", tout << "WARNING: unknown regex term " << mk_pp(re, get_manager()) << std::endl;); @@ -6613,7 +6613,7 @@ namespace smt { SASSERT(str1.length() == 1); SASSERT(str2.length() == 1); return 1 + str2[0] - str1[0]; - } else if (u.re.is_full(re)) { + } else if (u.re.is_full_char(re) || u.re.is_full_seq(re)) { return 1; } else { TRACE("str", tout << "WARNING: unknown regex term " << mk_pp(re, get_manager()) << std::endl;); @@ -6649,8 +6649,10 @@ namespace smt { } } else if (u.re.is_range(re)) { return true; - } else if (u.re.is_full(re)) { + } else if (u.re.is_full_char(re)) { return true; + } else if (u.re.is_full_seq(re)) { + return false; // generally unbounded } else if (u.re.is_complement(re)) { // TODO can we do better? return false; @@ -6712,8 +6714,10 @@ namespace smt { SASSERT(str1.length() == 1); SASSERT(str2.length() == 1); lens.insert(1); - } else if (u.re.is_full(re)) { + } else if (u.re.is_full_char(re)) { lens.insert(1); + } else if (u.re.is_full_seq(re)) { + lens.reset(); } else if (u.re.is_complement(re)) { lens.reset(); } else { @@ -6828,9 +6832,13 @@ namespace smt { SASSERT(str2.length() == 1); expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_numeral(rational::one(), true)), m); return retval; - } else if (u.re.is_full(re)) { + } else if (u.re.is_full_char(re)) { expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_numeral(rational::one(), true)), m); return retval; + } else if (u.re.is_full_seq(re)) { + // match any unbounded string + expr_ref retval(m_autil.mk_ge(lenVar, m_autil.mk_numeral(rational::zero(), true)), m); + return retval; } else if (u.re.is_complement(re)) { // skip complement for now, in general this is difficult to predict expr_ref retval(m_autil.mk_ge(lenVar, m_autil.mk_numeral(rational::zero(), true)), m); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index ef0bbf0ee..506726bc6 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -745,6 +745,7 @@ protected: void new_diseq_eh(theory_var, theory_var) override; theory* mk_fresh(context*) override { return alloc(theory_str, get_manager(), m_params); } + void init(context * ctx) override; void init_search_eh() override; void add_theory_assumptions(expr_ref_vector & assumptions) override; lbool validate_unsat_core(expr_ref_vector & unsat_core) override; From eab7ae58bec086583f630d8d4e4a5b4b4ac294e1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Feb 2018 23:30:10 -0800 Subject: [PATCH 0573/1283] fix #1484 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 436e1b538..6d49d8883 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -320,7 +320,7 @@ bool cmd_context::macros_find(symbol const& s, unsigned n, expr*const* args, exp if (d.m_domain.size() != n) continue; bool eq = true; for (unsigned i = 0; eq && i < n; ++i) { - eq = d.m_domain[i] == m().get_sort(args[i]); + eq = m().compatible_sorts(d.m_domain[i], m().get_sort(args[i])); } if (eq) { t = d.m_body; From 7bf80c66d03f9961a0fab2317a2a610d4d712508 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 13 Feb 2018 18:51:47 +0700 Subject: [PATCH 0574/1283] Remove redundant void arg. While this was needed in ANSI C, it isn't in C++ and triggers a warning in clang-tidy when `modernize-redundant-void-arg` is enabled. --- src/ast/fpa/fpa2bv_converter.cpp | 2 +- src/ast/fpa/fpa2bv_converter.h | 2 +- src/ast/macros/quasi_macros.cpp | 2 +- src/smt/smt_context.h | 2 +- src/tactic/arith/nla2bv_tactic.cpp | 2 +- src/tactic/sls/bvsls_opt_engine.h | 2 +- src/tactic/sls/sls_engine.h | 4 ++-- src/tactic/tactical.cpp | 2 +- src/tactic/ufbv/ufbv_rewriter.cpp | 6 +++--- src/tactic/ufbv/ufbv_rewriter.h | 2 +- src/util/mpf.h | 4 ++-- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 5e7db2ca9..033d62825 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -4085,7 +4085,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & TRACE("fpa2bv_round", tout << "ROUND = " << mk_ismt2_pp(result, m) << std::endl; ); } -void fpa2bv_converter::reset(void) { +void fpa2bv_converter::reset() { dec_ref_map_key_values(m, m_const2bv); dec_ref_map_key_values(m, m_rm_const2bv); dec_ref_map_key_values(m, m_uf2bvuf); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 062f7afe9..7637317b0 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -150,7 +150,7 @@ public: void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result); expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); - void reset(void); + void reset(); void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index afef6c43f..a308b5b17 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -91,7 +91,7 @@ public: void operator()(var * n) { m_bitset.set(n->get_idx(), true); } void operator()(quantifier * n) {} void operator()(app * n) {} - bool all_used(void) { + bool all_used() { for (unsigned i = 0; i < m_bitset.size() ; i++) if (!m_bitset.get(i)) return false; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index b637d8082..a4581b020 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1387,7 +1387,7 @@ namespace smt { void flush(); config_mode get_config_mode(bool use_static_features) const; virtual void setup_context(bool use_static_features); - void setup_components(void); + void setup_components(); void pop_to_base_lvl(); void pop_to_search_lvl(); #ifdef Z3DEBUG diff --git a/src/tactic/arith/nla2bv_tactic.cpp b/src/tactic/arith/nla2bv_tactic.cpp index 9a5c33ce6..256fc9b16 100644 --- a/src/tactic/arith/nla2bv_tactic.cpp +++ b/src/tactic/arith/nla2bv_tactic.cpp @@ -459,7 +459,7 @@ public: SASSERT(g->is_well_sorted()); } - void cleanup(void) override { + void cleanup() override { } }; diff --git a/src/tactic/sls/bvsls_opt_engine.h b/src/tactic/sls/bvsls_opt_engine.h index 9487130d3..3acce8f0a 100644 --- a/src/tactic/sls/bvsls_opt_engine.h +++ b/src/tactic/sls/bvsls_opt_engine.h @@ -65,7 +65,7 @@ protected: unsigned & best_const, mpz & best_value, unsigned & new_bit, move_type & move, mpz const & max_score, expr * objective); - mpz top_score(void) { + mpz top_score() { mpz res(0); obj_hashtable const & top_exprs = m_obj_tracker.get_top_exprs(); for (obj_hashtable::iterator it = top_exprs.begin(); diff --git a/src/tactic/sls/sls_engine.h b/src/tactic/sls/sls_engine.h index 0c4fb4d39..da9a8a2c8 100644 --- a/src/tactic/sls/sls_engine.h +++ b/src/tactic/sls/sls_engine.h @@ -99,7 +99,7 @@ public: // stats const & get_stats(void) { return m_stats; } void collect_statistics(statistics & st) const; - void reset_statistics(void) { m_stats.reset(); } + void reset_statistics() { m_stats.reset(); } bool full_eval(model & mdl); @@ -109,7 +109,7 @@ public: void mk_inv(unsigned bv_sz, const mpz & old_value, mpz & inverted); void mk_flip(sort * s, const mpz & old_value, unsigned bit, mpz & flipped); - lbool search(void); + lbool search(); lbool operator()(); void operator()(goal_ref const & g, model_converter_ref & mc); diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 8aa2f400a..a9ada3a11 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -907,7 +907,7 @@ public: m_t->operator()(in, result, mc, pc, core); } - void cleanup(void) override { m_t->cleanup(); } + void cleanup() override { m_t->cleanup(); } void collect_statistics(statistics & st) const override { m_t->collect_statistics(st); } void reset_statistics() override { m_t->reset_statistics(); } void updt_params(params_ref const & p) override { m_t->updt_params(p); } diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/tactic/ufbv/ufbv_rewriter.cpp index 573873c89..875ef2edb 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/tactic/ufbv/ufbv_rewriter.cpp @@ -196,14 +196,14 @@ int ufbv_rewriter::is_smaller(expr * e1, expr * e2) const { class max_var_id_proc { unsigned m_max_var_id; public: - max_var_id_proc(void):m_max_var_id(0) {} + max_var_id_proc():m_max_var_id(0) {} void operator()(var * n) { if(n->get_idx() > m_max_var_id) m_max_var_id = n->get_idx(); } void operator()(quantifier * n) {} void operator()(app * n) {} - unsigned get_max(void) { return m_max_var_id; } + unsigned get_max() { return m_max_var_id; } }; unsigned ufbv_rewriter::max_var_id(expr * e) @@ -253,7 +253,7 @@ void ufbv_rewriter::remove_fwd_idx(func_decl * f, quantifier * demodulator) { } } -bool ufbv_rewriter::check_fwd_idx_consistency(void) { +bool ufbv_rewriter::check_fwd_idx_consistency() { for (fwd_idx_map::iterator it = m_fwd_idx.begin(); it != m_fwd_idx.end() ; it++ ) { quantifier_set * set = it->m_value; SASSERT(set); diff --git a/src/tactic/ufbv/ufbv_rewriter.h b/src/tactic/ufbv/ufbv_rewriter.h index af9888751..c6e01528c 100644 --- a/src/tactic/ufbv/ufbv_rewriter.h +++ b/src/tactic/ufbv/ufbv_rewriter.h @@ -173,7 +173,7 @@ class ufbv_rewriter { void insert_fwd_idx(expr * large, expr * small, quantifier * demodulator); void remove_fwd_idx(func_decl * f, quantifier * demodulator); - bool check_fwd_idx_consistency(void); + bool check_fwd_idx_consistency(); void show_fwd_idx(std::ostream & out); bool is_demodulator(expr * e, expr_ref & large, expr_ref & small) const; bool can_rewrite(expr * n, expr * lhs); diff --git a/src/util/mpf.h b/src/util/mpf.h index e679be558..27116e2de 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -190,8 +190,8 @@ public: void mk_pinf(unsigned ebits, unsigned sbits, mpf & o); void mk_ninf(unsigned ebits, unsigned sbits, mpf & o); - unsynch_mpz_manager & mpz_manager(void) { return m_mpz_manager; } - unsynch_mpq_manager & mpq_manager(void) { return m_mpq_manager; } + unsynch_mpz_manager & mpz_manager() { return m_mpz_manager; } + unsynch_mpq_manager & mpq_manager() { return m_mpq_manager; } unsigned hash(mpf const & a) { return hash_u_u(m_mpz_manager.hash(a.significand), From 971a5eddcbb54f8942a25f400fa6d53cb5c6008d Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 13 Feb 2018 19:19:24 +0700 Subject: [PATCH 0575/1283] Use bool literal `false` instead of `0`. --- src/ast/fpa_decl_plugin.cpp | 2 +- src/util/hashtable.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 419175a7f..c0caaa3ca 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -160,7 +160,7 @@ bool fpa_decl_plugin::is_rm_numeral(expr * n, mpf_rounding_mode & val) { return true; } - return 0; + return false; } bool fpa_decl_plugin::is_rm_numeral(expr * n) { diff --git a/src/util/hashtable.h b/src/util/hashtable.h index 0421fd300..742438814 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -449,7 +449,7 @@ public: INSERT_LOOP_CORE_BODY(); } UNREACHABLE(); - return 0; + return false; } bool insert_if_not_there_core(const data & e, entry * & et) { From 0ef33a98c40f76d564077e82353b43a73478c00d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 13 Feb 2018 14:08:55 +0000 Subject: [PATCH 0576/1283] Revert "Fix encoding error" --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 3a719d322..03256125c 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -889,7 +889,7 @@ def is_CXX_gpp(): return is_compiler(CXX, 'g++') def is_clang_in_gpp_form(cc): - version_string = check_output([cc, '--version']) + version_string = check_output([cc, '--version']).encode('utf-8').decode('utf-8') return version_string.find('clang') != -1 def is_CXX_clangpp(): From 0bbdee810d96357bd6e87f5b2477ec4c17764156 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Feb 2018 21:46:20 -0800 Subject: [PATCH 0577/1283] fix #1488 Signed-off-by: Nikolaj Bjorner --- src/ast/ast_pp_util.cpp | 1 + src/ast/decl_collector.cpp | 78 +++++++++++++++++++++------- src/ast/decl_collector.h | 10 ++++ src/util/top_sort.h | 101 +++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 18 deletions(-) create mode 100644 src/util/top_sort.h diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 4579f2ffc..37785e072 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -38,6 +38,7 @@ void ast_pp_util::collect(expr_ref_vector const& es) { void ast_pp_util::display_decls(std::ostream& out) { smt2_pp_environment_dbg env(m); ast_smt_pp pp(m); + coll.order_deps(); unsigned n = coll.get_num_sorts(); for (unsigned i = 0; i < n; ++i) { pp.display_ast_smt2(out, coll.get_sorts()[i], 0, 0, nullptr); diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index e000f43df..1baac4515 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include "ast/decl_collector.h" +#include "ast/ast_pp.h" void decl_collector::visit_sort(sort * n) { family_id fid = n->get_family_id(); @@ -25,19 +26,21 @@ void decl_collector::visit_sort(sort * n) { m_sorts.push_back(n); if (fid == m_dt_fid) { m_sorts.push_back(n); - unsigned num_cnstr = m_dt_util.get_datatype_num_constructors(n); for (unsigned i = 0; i < num_cnstr; i++) { func_decl * cnstr = m_dt_util.get_datatype_constructors(n)->get(i); - m_decls.push_back(cnstr); + m_todo.push_back(cnstr); ptr_vector const & cnstr_acc = *m_dt_util.get_constructor_accessors(cnstr); unsigned num_cas = cnstr_acc.size(); for (unsigned j = 0; j < num_cas; j++) { - func_decl * accsr = cnstr_acc.get(j); - m_decls.push_back(accsr); + m_todo.push_back(cnstr_acc.get(j)); } } } + for (unsigned i = n->get_num_parameters(); i-- > 0; ) { + parameter const& p = n->get_parameter(i); + if (p.is_ast()) m_todo.push_back(p.get_ast()); + } } bool decl_collector::is_bool(sort * s) { @@ -63,43 +66,43 @@ decl_collector::decl_collector(ast_manager & m, bool preds): } void decl_collector::visit(ast* n) { - ptr_vector todo; - todo.push_back(n); - while (!todo.empty()) { - n = todo.back(); - todo.pop_back(); + datatype_util util(m()); + m_todo.push_back(n); + while (!m_todo.empty()) { + n = m_todo.back(); + m_todo.pop_back(); if (!m_visited.is_marked(n)) { m_visited.mark(n, true); switch(n->get_kind()) { case AST_APP: { app * a = to_app(n); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - todo.push_back(a->get_arg(i)); + for (expr* arg : *a) { + m_todo.push_back(arg); } - todo.push_back(a->get_decl()); + m_todo.push_back(a->get_decl()); break; } case AST_QUANTIFIER: { quantifier * q = to_quantifier(n); unsigned num_decls = q->get_num_decls(); for (unsigned i = 0; i < num_decls; ++i) { - todo.push_back(q->get_decl_sort(i)); + m_todo.push_back(q->get_decl_sort(i)); } - todo.push_back(q->get_expr()); + m_todo.push_back(q->get_expr()); for (unsigned i = 0; i < q->get_num_patterns(); ++i) { - todo.push_back(q->get_pattern(i)); + m_todo.push_back(q->get_pattern(i)); } break; } - case AST_SORT: + case AST_SORT: visit_sort(to_sort(n)); break; case AST_FUNC_DECL: { func_decl * d = to_func_decl(n); for (unsigned i = 0; i < d->get_arity(); ++i) { - todo.push_back(d->get_domain(i)); + m_todo.push_back(d->get_domain(i)); } - todo.push_back(d->get_range()); + m_todo.push_back(d->get_range()); visit_func(d); break; } @@ -112,5 +115,44 @@ void decl_collector::visit(ast* n) { } } +void decl_collector::order_deps() { + top_sort st; + for (sort * s : m_sorts) st.insert(s, collect_deps(s)); + st.topological_sort(); + m_sorts.reset(); + for (sort* s : st.top_sorted()) m_sorts.push_back(s); +} + +decl_collector::sort_set* decl_collector::collect_deps(sort* s) { + sort_set* set = alloc(sort_set); + collect_deps(s, *set); + set->remove(s); + return set; +} + +void decl_collector::collect_deps(sort* s, sort_set& set) { + if (set.contains(s)) return; + set.insert(s); + if (s->is_sort_of(m_dt_util.get_family_id(), DATATYPE_SORT)) { + unsigned num_sorts = m_dt_util.get_datatype_num_parameter_sorts(s); + for (unsigned i = 0; i < num_sorts; ++i) { + set.insert(m_dt_util.get_datatype_parameter_sort(s, i)); + } + unsigned num_cnstr = m_dt_util.get_datatype_num_constructors(s); + for (unsigned i = 0; i < num_cnstr; i++) { + func_decl * cnstr = m_dt_util.get_datatype_constructors(s)->get(i); + set.insert(cnstr->get_range()); + for (unsigned j = 0; j < cnstr->get_arity(); ++j) + set.insert(cnstr->get_domain(j)); + } + } + + for (unsigned i = s->get_num_parameters(); i-- > 0; ) { + parameter const& p = s->get_parameter(i); + if (p.is_ast() && is_sort(p.get_ast())) { + set.insert(to_sort(p.get_ast())); + } + } +} diff --git a/src/ast/decl_collector.h b/src/ast/decl_collector.h index 053d6df41..041438864 100644 --- a/src/ast/decl_collector.h +++ b/src/ast/decl_collector.h @@ -20,6 +20,7 @@ Revision History: #ifndef SMT_DECL_COLLECTOR_H_ #define SMT_DECL_COLLECTOR_H_ +#include "util/top_sort.h" #include "ast/ast.h" #include "ast/datatype_decl_plugin.h" @@ -33,11 +34,17 @@ class decl_collector { family_id m_basic_fid; family_id m_dt_fid; datatype_util m_dt_util; + ptr_vector m_todo; void visit_sort(sort* n); bool is_bool(sort* s); void visit_func(func_decl* n); + typedef obj_hashtable sort_set; + sort_set* collect_deps(sort* s); + void collect_deps(top_sort& st); + void collect_deps(sort* s, sort_set& set); + public: // if preds == true, then predicates are stored in a separate collection. @@ -48,9 +55,12 @@ public: void visit(unsigned n, expr* const* es); void visit(expr_ref_vector const& es); + void order_deps(); + unsigned get_num_sorts() const { return m_sorts.size(); } unsigned get_num_decls() const { return m_decls.size(); } unsigned get_num_preds() const { return m_preds.size(); } + sort * const * get_sorts() const { return m_sorts.c_ptr(); } func_decl * const * get_func_decls() const { return m_decls.c_ptr(); } func_decl * const * get_pred_decls() const { return m_preds.c_ptr(); } diff --git a/src/util/top_sort.h b/src/util/top_sort.h new file mode 100644 index 000000000..d017d162b --- /dev/null +++ b/src/util/top_sort.h @@ -0,0 +1,101 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + top_sort.h + +Abstract: + Topological sort over objects + +Author: + + Nikolaj Bjorner (nbjorner) 2018-02-14 + +Revision History: + +--*/ + +#ifndef TOP_SORT_H_ +#define TOP_SORT_H_ + +#include "util/obj_hashtable.h" +#include "util/vector.h" +#include +#include +#include +#include "util/memory_manager.h" + + +template +class top_sort { + typedef obj_hashtable T_set; + obj_map m_partition_id; + obj_map m_dfs_num; + ptr_vector m_top_sorted; + ptr_vector m_stack_S; + ptr_vector m_stack_P; + unsigned m_next_preorder; + obj_map m_deps; + + void traverse(T* f) { + unsigned p_id = 0; + if (m_dfs_num.find(f, p_id)) { + if (!m_partition_id.contains(f)) { + while (!m_stack_P.empty() && m_partition_id[m_stack_P.back()] > p_id) { + m_stack_P.pop_back(); + } + } + } + else if (!m_deps.contains(f)) { + return; + } + else { + m_dfs_num.insert(f, m_next_preorder++); + m_stack_S.push_back(f); + m_stack_P.push_back(f); + for (T* g : *m_deps[f]) { + traverse(g); + } + if (f == m_stack_P.back()) { + + p_id = m_top_sorted.size(); + T* s_f; + do { + s_f = m_stack_S.back(); + m_stack_S.pop_back(); + m_top_sorted.push_back(s_f); + m_partition_id.insert(s_f, p_id); + } + while (s_f != f); + m_stack_P.pop_back(); + } + } + } + +public: + + ~top_sort() { + for (auto & kv : m_deps) dealloc(kv.m_value); + } + + void topological_sort() { + m_next_preorder = 0; + m_partition_id.reset(); + m_top_sorted.reset(); + for (auto & kv : m_deps) { + traverse(kv.m_key); + } + SASSERT(m_stack_S.empty()); + SASSERT(m_stack_P.empty()); + m_dfs_num.reset(); + } + + void insert(T* t, T_set* s) { + m_deps.insert(t, s); + } + + ptr_vector const& top_sorted() { return m_top_sorted; } +}; + +#endif /* TOP_SORT_H_ */ From fadcac8f6d0f119523e70cd893933466a2342298 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Feb 2018 12:39:08 -0800 Subject: [PATCH 0578/1283] fix #1491 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2f6bad9e8..1950a199d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -402,8 +402,8 @@ namespace opt { */ bool context::scoped_lex() { if (m_maxsat_engine == symbol("maxres")) { - for (unsigned i = 0; i < m_objectives.size(); ++i) { - if (m_objectives[i].m_type != O_MAXSMT) return true; + for (auto const& o : m_objectives) { + if (o.m_type != O_MAXSMT) return true; } return false; } @@ -413,14 +413,16 @@ namespace opt { lbool context::execute_lex() { lbool r = l_true; bool sc = scoped_lex(); - IF_VERBOSE(1, verbose_stream() << "(optsmt:lex)\n";); - for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) { - bool is_last = i + 1 == m_objectives.size(); - r = execute(m_objectives[i], i + 1 < m_objectives.size(), sc && !is_last); + IF_VERBOSE(1, verbose_stream() << "(opt :lex)\n";); + unsigned sz = m_objectives.size(); + for (unsigned i = 0; r == l_true && i < sz; ++i) { + objective const& o = m_objectives[i]; + bool is_last = i + 1 == sz; + r = execute(o, i + 1 < sz, sc && !is_last && o.m_type != O_MAXSMT); if (r == l_true && !get_lower_as_num(i).is_finite()) { return r; } - if (r == l_true && i + 1 < m_objectives.size()) { + if (r == l_true && i + 1 < sz) { update_lower(); } } From 3bbc09c1d2c800ea4ac646c66a886d25a87c4938 Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Fri, 16 Feb 2018 14:44:22 +0000 Subject: [PATCH 0579/1283] MSS based MaxSMT solver --- src/opt/maxsmt.cpp | 4 ++ src/opt/mss_solver.cpp | 156 +++++++++++++++++++++++++++++++++++++++++ src/opt/mss_solver.h | 12 ++++ src/opt/opt_params.pyg | 8 +-- 4 files changed, 176 insertions(+), 4 deletions(-) create mode 100755 src/opt/mss_solver.cpp create mode 100755 src/opt/mss_solver.h diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 91e843ca0..9bc4f4f14 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -21,6 +21,7 @@ Notes: #include "opt/maxsmt.h" #include "opt/maxres.h" #include "opt/wmax.h" +#include "opt/mss_solver.h" #include "ast/ast_pp.h" #include "util/uint_set.h" #include "opt/opt_context.h" @@ -240,6 +241,9 @@ namespace opt { else if (maxsat_engine == symbol("pd-maxres")) { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_weights, m_soft_constraints); } + else if (maxsat_engine == symbol("mss")) { + m_msolver = mk_mss_solver(m_c, m_index, m_weights, m_soft_constraints); + } else if (maxsat_engine == symbol("wmax")) { m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); } diff --git a/src/opt/mss_solver.cpp b/src/opt/mss_solver.cpp new file mode 100755 index 000000000..501b43ee4 --- /dev/null +++ b/src/opt/mss_solver.cpp @@ -0,0 +1,156 @@ +#include "solver/solver.h" +#include "opt/maxsmt.h" +#include "opt/mss_solver.h" +#include "opt/mss.h" +#include "opt/opt_context.h" +#include "opt/opt_params.hpp" + +using namespace opt; + +class mss_solver: public maxsmt_solver_base { + +private: + typedef ptr_vector exprs; + mss m_mss; + unsigned m_index; + expr_ref_vector m_asms; + unsigned m_max_mss; + +public: + mss_solver(maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft): + maxsmt_solver_base(c, ws, soft), + m_mss(c.get_solver(), m), + m_index(id), + m_asms(m), + m_max_mss(UINT_MAX) { + } + + virtual ~mss_solver() {} + + virtual lbool operator()() { + if (!init()) return l_undef; + init_asms(); + lbool is_sat = check_sat(m_asms); + if (is_sat == l_undef) return l_undef; + if (is_sat == l_true) { + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << m_asms.size() << " :mcs " << 0 << ")\n";); + model_ref mdl; + s().get_model(mdl); + update_assignment(mdl.get()); + return l_true; + } + return enumerate_mss(); + } + + virtual void updt_params(params_ref& p) { + maxsmt_solver_base::updt_params(p); + opt_params _p(p); + m_max_mss = _p.mss_max(); + } + +private: + void init_asms() { + m_asms.reset(); + for (unsigned i = 0; i < m_soft.size(); ++i) { + expr* e = m_soft[i]; + m_asms.push_back(relax_and_assert(e)); + } + } + + expr_ref relax_and_assert(expr* e) { + expr_ref asum(m); + if (is_literal(e)) { + asum = e; + } + else { + asum = mk_fresh_bool("r"); + e = m.mk_iff(asum, e); + s().assert_expr(e); + } + return asum; + } + + bool is_literal(expr* l) { + return is_uninterp_const(l) || (m.is_not(l, l) && is_uninterp_const(l)); + } + + lbool enumerate_mss() { + expr_ref_vector asms(m); + for (unsigned i = 0; i < m_max_mss; ++i) { + exprs mss, mcs; + lbool is_sat = next_mss(asms, mss, mcs); + if (is_sat == l_false && i == 0) return l_false; + if (is_sat == l_undef && i == 0) return l_undef; + if (is_sat == l_false || is_sat == l_undef) return l_true; + asms.push_back(relax_and_assert(m.mk_or(mcs.size(), mcs.c_ptr()))); + } + return l_true; + } + + lbool next_mss(expr_ref_vector const& asms, exprs& mss, exprs& mcs) { + mss.reset(); + mcs.reset(); + lbool is_sat = check_sat(asms); + if (is_sat != l_true) return is_sat; + model_ref mdl; + s().get_model(mdl); + update_assignment(mdl.get()); + vector dummy; + push_exprs(mss, m_asms); + push_exprs(mss, asms); + is_sat = m_mss(mdl.get(), dummy, mss, mcs); + SASSERT(is_sat == l_true); + mdl.reset(); + m_mss.get_model(mdl); + update_assignment(mdl.get()); + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); + return is_sat; + } + + void push_exprs(exprs& dst, expr_ref_vector const& src) { + for (unsigned i = 0; i < src.size(); ++i) { + dst.push_back(src[i]); + } + } + + lbool check_sat() { + expr_ref_vector dummy(m); + return check_sat(dummy); + } + + lbool check_sat(expr_ref_vector const& asms) { + return s().check_sat(asms); + } + + void update_assignment(model* mdl) { + rational upper(0); + for (unsigned i = 0; i < m_soft.size(); ++i) { + if (!is_true(mdl, m_soft[i])) { + upper += m_weights[i]; + } + } + if (upper > m_upper) return; + if (!m_c.verify_model(m_index, mdl, upper)) return; + m_model = mdl; + m_c.model_updated(mdl); + for (unsigned i = 0; i < m_soft.size(); ++i) { + m_assignment[i] = is_true(m_soft[i]); + } + // TODO: DEBUG verify assignment + m_upper = upper; + trace_bounds("mss-solver"); + } + + bool is_true(model* mdl, expr* e) { + expr_ref tmp(m); + return mdl->eval(e, tmp, true) && m.is_true(tmp); + } + + bool is_true(expr* e) { + return is_true(m_model.get(), e); + } +}; + +maxsmt_solver_base* opt::mk_mss_solver(maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft) { + return alloc(mss_solver, c, id, ws, soft); +} diff --git a/src/opt/mss_solver.h b/src/opt/mss_solver.h new file mode 100755 index 000000000..5c274cd4c --- /dev/null +++ b/src/opt/mss_solver.h @@ -0,0 +1,12 @@ +#ifndef MSS_SOLVER_H_ +#define MSS_SOLVER_H_ + +#include "opt/maxsmt.h" + +namespace opt { + + maxsmt_solver_base* mk_mss_solver(maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft); + +} + +#endif diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 1d6d7ee6a..4cb22389d 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,13 +2,13 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'mss'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('solution_prefix', SYMBOL, '', "path prefix to dump intermediary, but non-optimal, solutions"), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), - ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), + ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsat'), ('enable_sat', BOOL, True, 'enable the new SAT core for propositional constraints'), ('elim_01', BOOL, True, 'eliminate 01 variables'), ('pp.neat', BOOL, True, 'use neat (as opposed to less readable, but faster) pretty printer when displaying context'), @@ -20,8 +20,8 @@ def_module_params('opt', ('maxres.maximize_assignment', BOOL, False, 'find an MSS/MCS to improve current assignment'), ('maxres.max_correction_set_size', UINT, 3, 'allow generating correction set constraints up to maximal size'), ('maxres.wmax', BOOL, False, 'use weighted theory solver to constrain upper bounds'), - ('maxres.pivot_on_correction_set', BOOL, True, 'reduce soft constraints if the current correction set is smaller than current core') - + ('maxres.pivot_on_correction_set', BOOL, True, 'reduce soft constraints if the current correction set is smaller than current core'), + ('mss.max', UINT, UINT_MAX, 'maximum number of MSS to enumerate') )) From 3a7efb91ae073c346716b4213c06d32fc39510a6 Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Fri, 16 Feb 2018 19:48:29 +0000 Subject: [PATCH 0580/1283] implemented CLD --- src/opt/mss.cpp | 12 ++++---- src/opt/mss_solver.cpp | 62 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index cc0fa8d7d..47f4b6e02 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -155,10 +155,10 @@ namespace opt { lbool is_sat = l_true; for (unsigned i = 0; is_sat == l_true && i < m_cores.size(); ++i) { bool has_mcs = false; - bool is_last = i + 1 < m_cores.size(); + bool not_last = i + 1 < m_cores.size(); SASSERT(check_invariant()); update_core(m_cores[i]); // remove members of mss - is_sat = process_core(1, m_cores[i], has_mcs, is_last); + is_sat = process_core(1, m_cores[i], has_mcs, not_last); } if (is_sat == l_true) { SASSERT(check_invariant()); @@ -183,7 +183,7 @@ namespace opt { // at least one literal in core is false in current model. // pick literals in core that are not yet in mss. // - lbool mss::process_core(unsigned sz, exprs& core, bool& has_mcs, bool is_last) { + lbool mss::process_core(unsigned sz, exprs& core, bool& has_mcs, bool not_last) { SASSERT(sz > 0); if (core.empty()) { return l_true; @@ -191,7 +191,7 @@ namespace opt { if (m.canceled()) { return l_undef; } - if (sz == 1 && core.size() == 1 && is_last && !has_mcs) { + if (sz == 1 && core.size() == 1 && not_last && !has_mcs) { // there has to be at least one false // literal in the core. TRACE("opt", tout << "mcs: " << mk_pp(core[0], m) << "\n";); @@ -214,7 +214,7 @@ namespace opt { SASSERT(m_mss_set.contains(core[i])); }); update_core(core); - return process_core(2*sz, core, has_mcs, is_last); + return process_core(2*sz, core, has_mcs, not_last); case l_false: if (sz == 1) { has_mcs = true; @@ -232,7 +232,7 @@ namespace opt { } update_core(core); } - return process_core(1, core, has_mcs, is_last); + return process_core(1, core, has_mcs, not_last); case l_undef: return l_undef; } diff --git a/src/opt/mss_solver.cpp b/src/opt/mss_solver.cpp index 501b43ee4..d27b6300c 100755 --- a/src/opt/mss_solver.cpp +++ b/src/opt/mss_solver.cpp @@ -98,15 +98,61 @@ private: vector dummy; push_exprs(mss, m_asms); push_exprs(mss, asms); - is_sat = m_mss(mdl.get(), dummy, mss, mcs); - SASSERT(is_sat == l_true); - mdl.reset(); - m_mss.get_model(mdl); - update_assignment(mdl.get()); - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); + is_sat = cld(mdl.get(), mss, mcs); + if (is_sat == l_true) { + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); + } + /*is_sat = m_mss(mdl.get(), dummy, mss, mcs); + SASSERT(is_sat != l_false); + if (is_sat == l_true) { + mdl.reset(); + m_mss.get_model(mdl); + update_assignment(mdl.get()); + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); + }*/ return is_sat; } + lbool cld(model_ref initial_model, exprs& mss, exprs& mcs) { + exprs sat, undef; + undef.append(mss); + update_sat(initial_model, sat, undef); + lbool is_sat = l_true; + while (is_sat == l_true) { + expr_ref asum = relax_and_assert(m.mk_or(undef.size(), undef.c_ptr())); + sat.push_back(asum); + is_sat = check_sat(sat); + sat.pop_back(); + if (is_sat == l_true) { + model_ref mdl; + s().get_model(mdl); + update_sat(mdl, sat, undef); + update_assignment(mdl.get()); + } + } + if (is_sat == l_false) { + mss.reset(); + mcs.reset(); + mss.append(sat); + mcs.append(undef); + is_sat = l_true; + } + return is_sat; + } + + void update_sat(model_ref mdl, exprs& sat, exprs& undef) { + for (unsigned i = 0; i < undef.size();) { + if (is_true(mdl.get(), undef[i])) { + sat.push_back(undef[i]); + undef[i] = undef.back(); + undef.pop_back(); + } + else { + ++i; + } + } + } + void push_exprs(exprs& dst, expr_ref_vector const& src) { for (unsigned i = 0; i < src.size(); ++i) { dst.push_back(src[i]); @@ -122,6 +168,10 @@ private: return s().check_sat(asms); } + lbool check_sat(exprs const& asms) { + return s().check_sat(asms.size(), asms.c_ptr()); + } + void update_assignment(model* mdl) { rational upper(0); for (unsigned i = 0; i < m_soft.size(); ++i) { From c7063631e1dcea87928f82d93b3076809a35e2e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Feb 2018 12:07:23 -0800 Subject: [PATCH 0581/1283] remove unused code Signed-off-by: Nikolaj Bjorner --- src/opt/CMakeLists.txt | 1 - src/opt/maxres.cpp | 3 - src/opt/mss.cpp | 285 ----------------------------------------- src/opt/mss.h | 57 --------- 4 files changed, 346 deletions(-) delete mode 100644 src/opt/mss.cpp delete mode 100644 src/opt/mss.h diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index 28a14be2e..dcb13c062 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -2,7 +2,6 @@ z3_add_component(opt SOURCES maxres.cpp maxsmt.cpp - mss.cpp opt_cmds.cpp opt_context.cpp opt_pareto.cpp diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index f0345232d..6d91e70fc 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -57,7 +57,6 @@ Notes: #include "opt/maxres.h" #include "ast/ast_pp.h" #include "solver/mus.h" -#include "opt/mss.h" #include "sat/sat_solver/inc_sat_solver.h" #include "opt/opt_context.h" #include "ast/pb_decl_plugin.h" @@ -90,7 +89,6 @@ private: obj_map m_asm2weight; ptr_vector m_new_core; mus m_mus; - mss m_mss; expr_ref_vector m_trail; strategy_t m_st; rational m_max_upper; @@ -121,7 +119,6 @@ public: m_index(index), m_B(m), m_asms(m), m_defs(m), m_mus(c.get_solver()), - m_mss(c.get_solver(), m), m_trail(m), m_st(st), m_correction_set_size(0), diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp deleted file mode 100644 index cc0fa8d7d..000000000 --- a/src/opt/mss.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - mss.cpp - -Abstract: - - MSS/MCS extraction. - -Author: - - Nikolaj Bjorner (nbjorner) 2014-2-8 - -Notes: - - ---*/ - -#include "solver/solver.h" -#include "opt/mss.h" -#include "ast/ast_pp.h" -#include "model/model_smt2_pp.h" - -namespace opt { - - - mss::mss(solver& s, ast_manager& m): m_s(s), m(m) { - } - - mss::~mss() { - } - - bool mss::check_result() { - lbool is_sat = m_s.check_sat(m_mss.size(), m_mss.c_ptr()); - if (is_sat == l_undef) return true; - SASSERT(m_mss.empty() || is_sat == l_true); - if (is_sat == l_false) return false; - expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); - for (; it != end; ++it) { - m_mss.push_back(*it); - is_sat = m_s.check_sat(m_mss.size(), m_mss.c_ptr()); - m_mss.pop_back(); - if (is_sat == l_undef) return true; - SASSERT(is_sat == l_false); - if (is_sat == l_true) return false; - } - return true; - } - - void mss::initialize(exprs& literals) { - expr* n; - expr_set lits, core_lits; - for (unsigned i = 0; i < literals.size(); ++i) { - n = literals[i]; - lits.insert(n); - m.is_not(n, n); - if (!is_uninterp_const(n)) { - throw default_exception("arguments have to be uninterpreted literals"); - } - } - exprs rest_core; - expr_ref tmp(m); - // - // the last core is a dummy core. It contains literals that - // did not occur in previous cores and did not evaluate to true - // in the current model. - // - for (unsigned i = 0; i < m_cores.size(); ++i) { - exprs const& core = m_cores[i]; - for (unsigned j = 0; j < core.size(); ++j) { - expr* n = core[j]; - if (!core_lits.contains(n)) { - core_lits.insert(n); - if (m_model->eval(n, tmp) && m.is_true(tmp)) { - add_mss(n); - } - else { - m_todo.push_back(n); - } - } - } - } - for (unsigned i = 0; i < literals.size(); ++i) { - expr* n = literals[i]; - if (!core_lits.contains(n)) { - if (m_model->eval(n, tmp) && m.is_true(tmp)) { - m_mss.push_back(n); - } - else { - rest_core.push_back(n); - core_lits.insert(n); - m_todo.push_back(n); - } - } - } - m_cores.push_back(rest_core); - } - - void mss::add_mss(expr* n) { - if (!m_mss_set.contains(n)) { - m_mss_set.insert(n); - m_mss.push_back(n); - } - } - - void mss::update_core(exprs& core) { - unsigned j = 0; - for (unsigned i = 0; i < core.size(); ++i) { - expr* n = core[i]; - if (!m_mss_set.contains(n)) { - if (i != j) { - core[j] = core[i]; - } - ++j; - } - } - core.resize(j); - } - - void mss::update_mss() { - expr_ref tmp(m); - unsigned j = 0; - for (unsigned i = 0; i < m_todo.size(); ++i) { - expr* n = m_todo[i]; - SASSERT(!m_mss_set.contains(n)); - if (m_mcs.contains(n)) { - continue; // remove from cores. - } - if (m_model->eval(n, tmp) && m.is_true(tmp)) { - add_mss(n); - } - else { - if (j != i) { - m_todo[j] = m_todo[i]; - } - ++j; - } - } - m_todo.resize(j); - } - - lbool mss::operator()(model* initial_model, vector const& _cores, exprs& literals, exprs& mcs) { - m_mss.reset(); - m_todo.reset(); - m_model = initial_model; - m_cores.reset(); - SASSERT(m_model); - m_cores.append(_cores); - initialize(literals); - TRACE("opt", - display_vec(tout << "lits: ", literals.size(), literals.c_ptr()); - display(tout);); - lbool is_sat = l_true; - for (unsigned i = 0; is_sat == l_true && i < m_cores.size(); ++i) { - bool has_mcs = false; - bool is_last = i + 1 < m_cores.size(); - SASSERT(check_invariant()); - update_core(m_cores[i]); // remove members of mss - is_sat = process_core(1, m_cores[i], has_mcs, is_last); - } - if (is_sat == l_true) { - SASSERT(check_invariant()); - TRACE("opt", display(tout);); - literals.reset(); - literals.append(m_mss); - mcs.reset(); - expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); - for (; it != end; ++it) { - mcs.push_back(*it); - } - SASSERT(check_result()); - } - m_mcs.reset(); - m_mss_set.reset(); - IF_VERBOSE(2, display_vec(verbose_stream() << "mcs: ", mcs.size(), mcs.c_ptr());); - return is_sat; - } - - - // - // at least one literal in core is false in current model. - // pick literals in core that are not yet in mss. - // - lbool mss::process_core(unsigned sz, exprs& core, bool& has_mcs, bool is_last) { - SASSERT(sz > 0); - if (core.empty()) { - return l_true; - } - if (m.canceled()) { - return l_undef; - } - if (sz == 1 && core.size() == 1 && is_last && !has_mcs) { - // there has to be at least one false - // literal in the core. - TRACE("opt", tout << "mcs: " << mk_pp(core[0], m) << "\n";); - m_mcs.insert(core[0]); - return l_true; - } - sz = std::min(sz, core.size()); - TRACE("opt", display_vec(tout << "process (total " << core.size() << ") :", sz, core.c_ptr());); - unsigned sz_save = m_mss.size(); - m_mss.append(sz, core.c_ptr()); - lbool is_sat = m_s.check_sat(m_mss.size(), m_mss.c_ptr()); - IF_VERBOSE(3, display_vec(verbose_stream() << "mss: ", m_mss.size(), m_mss.c_ptr());); - m_mss.resize(sz_save); - switch (is_sat) { - case l_true: - m_s.get_model(m_model); - update_mss(); - DEBUG_CODE( - for (unsigned i = 0; i < sz; ++i) { - SASSERT(m_mss_set.contains(core[i])); - }); - update_core(core); - return process_core(2*sz, core, has_mcs, is_last); - case l_false: - if (sz == 1) { - has_mcs = true; - m_mcs.insert(core[0]); - core[0] = core.back(); - core.pop_back(); - } - else { - exprs core2; - core2.append(core.size()-sz, core.c_ptr()+sz); - core.resize(sz); - is_sat = process_core(sz, core2, has_mcs, false); - if (is_sat != l_true) { - return is_sat; - } - update_core(core); - } - return process_core(1, core, has_mcs, is_last); - case l_undef: - return l_undef; - } - - return l_true; - } - - void mss::display_vec(std::ostream& out, unsigned sz, expr* const* args) const { - for (unsigned i = 0; i < sz; ++i) { - out << mk_pp(args[i], m) << " "; - } - out << "\n"; - } - - void mss::display(std::ostream& out) const { - for (unsigned i = 0; i < m_cores.size(); ++i) { - display_vec(out << "core: ", m_cores[i].size(), m_cores[i].c_ptr()); - } - expr_set::iterator it = m_mcs.begin(), end = m_mcs.end(); - out << "mcs:\n"; - for (; it != end; ++it) { - out << mk_pp(*it, m) << "\n"; - } - out << "\n"; - out << "mss:\n"; - for (unsigned i = 0; i < m_mss.size(); ++i) { - out << mk_pp(m_mss[i], m) << "\n"; - } - out << "\n"; - if (m_model) { - model_smt2_pp(out, m, *(m_model.get()), 0); - } - } - - bool mss::check_invariant() const { - if (!m_model) return true; - expr_ref tmp(m); - for (unsigned i = 0; i < m_mss.size(); ++i) { - expr* n = m_mss[i]; - if (!m_model->eval(n, tmp)) return true; - CTRACE("opt", !m.is_true(tmp), tout << mk_pp(n, m) << " |-> " << mk_pp(tmp, m) << "\n";); - SASSERT(!m.is_false(tmp)); - } - return true; - } -} - - - - diff --git a/src/opt/mss.h b/src/opt/mss.h deleted file mode 100644 index af383634a..000000000 --- a/src/opt/mss.h +++ /dev/null @@ -1,57 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - mss.h - -Abstract: - - Maximal satisfying subset/minimal correction sets: MSS/MCS - -Author: - - Nikolaj Bjorner (nbjorner) 2014-2-8 - -Notes: - ---*/ -#ifndef MSS_H_ -#define MSS_H_ - -namespace opt { - class mss { - solver& m_s; - ast_manager& m; - typedef ptr_vector exprs; - typedef obj_hashtable expr_set; - exprs m_mss; - expr_set m_mcs; - expr_set m_mss_set; - vector m_cores; - exprs m_todo; - model_ref m_model; - public: - mss(solver& s, ast_manager& m); - ~mss(); - - lbool operator()(model* initial_model, vector const& cores, exprs& literals, exprs& mcs); - - - void get_model(model_ref& mdl) { mdl = m_model; } - - private: - void initialize(exprs& literals); - bool check_result(); - void add_mss(expr* n); - void update_mss(); - void update_core(exprs& core); - lbool process_core(unsigned sz, exprs& core, bool& has_mcs, bool is_last); - void display(std::ostream& out) const; - void display_vec(std::ostream& out, unsigned sz, expr* const* args) const; - bool check_invariant() const; - }; - -}; - -#endif From a2f907c7d168b265b2055cf179ce168914fb8dab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Feb 2018 13:20:15 -0800 Subject: [PATCH 0582/1283] fix #1492 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_model_finder.cpp | 109 ++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 48 deletions(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 778337697..5e21c0dcc 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -914,6 +914,7 @@ namespace smt { func_interp * fi = m_model->get_func_interp(f); if (fi == nullptr) { fi = alloc(func_interp, m, f->get_arity()); + TRACE("model_finder", tout << "register " << f->get_name() << "\n";); m_model->register_decl(f, fi); SASSERT(fi->is_partial()); } @@ -1784,13 +1785,8 @@ namespace smt { return !m_cond_macros.empty(); } - macro_iterator begin_macros() const { - return m_cond_macros.begin(); - } + ptr_vector const& macros() const { return m_cond_macros; } - macro_iterator end_macros() const { - return m_cond_macros.end(); - } void set_the_one(func_decl * m) { m_the_one = m; @@ -2445,6 +2441,7 @@ namespace smt { m_model->register_decl(f, fi); } fi->set_else(f_else); + TRACE("model_finder", tout << f->get_name() << " " << mk_pp(f_else, m_manager) << "\n";); } virtual bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) = 0; @@ -2499,10 +2496,7 @@ namespace smt { bool process(quantifier * q, ptr_vector const & qs) { quantifier_info * qi = get_qinfo(q); - quantifier_info::macro_iterator it = qi->begin_macros(); - quantifier_info::macro_iterator end = qi->end_macros(); - for (; it != end; ++it) { - cond_macro * m = *it; + for (cond_macro* m : qi->macros()) { if (!m->satisfy_atom()) continue; func_decl * f = m->get_f(); @@ -2548,10 +2542,10 @@ namespace smt { where Q_{f_i} is the set of quantifiers that contain the function f_i. Let f_i = def_i be macros (in this solver conditions are ignored). Let Q_{f_i = def_i} be the set of quantifiers where f_i = def_i is a macro. - Then, the set Q can be satisfied using f_1 = def_1 ... f_n = d_n + Then, the set Q can be satisfied using f_1 = def_1 ... f_n = def_n when - Q_{f_1} union ... union Q_{f_n} = Q_{f_1 = def_1} ... Q_{f_n = d_n} (*) + Q_{f_1} union ... union Q_{f_n} = Q_{f_1 = def_1} ... Q_{f_n = def_n} (*) So, given a set of macros f_1 = def_1, ..., f_n = d_n, it is very easy to check whether they can be used to satisfy all quantifiers that use f_1, ..., f_n in @@ -2630,12 +2624,7 @@ namespace smt { s->insert(q); } - quantifier_set * get_q_f(func_decl * f) { - quantifier_set * s = nullptr; - m_q_f.find(f, s); - SASSERT(s != 0); - return s; - } + quantifier_set * get_q_f(func_decl * f) { return m_q_f[f]; } quantifier_set * get_q_f_def(func_decl * f, expr * def) { quantifier_set * s = nullptr; @@ -2644,12 +2633,7 @@ namespace smt { return s; } - expr_set * get_f_defs(func_decl * f) { - expr_set * s = nullptr; - m_f2defs.find(f, s); - SASSERT(s != 0); - return s; - } + expr_set * get_f_defs(func_decl * f) { return m_f2defs[f]; } void reset_q_fs() { std::for_each(m_qsets.begin(), m_qsets.end(), delete_proc()); @@ -2666,10 +2650,7 @@ namespace smt { bool is_candidate(quantifier * q) const { quantifier_info * qi = get_qinfo(q); - quantifier_info::macro_iterator it = qi->begin_macros(); - quantifier_info::macro_iterator end = qi->end_macros(); - for (; it != end; ++it) { - cond_macro * m = *it; + for (cond_macro * m : qi->macros()) { if (m->satisfy_atom() && !m_forbidden.contains(m->get_f())) return true; } @@ -2712,10 +2693,7 @@ namespace smt { if (!m_forbidden.contains(f)) insert_q_f(q, f); } - quantifier_info::macro_iterator it3 = qi->begin_macros(); - quantifier_info::macro_iterator end3 = qi->end_macros(); - for (; it3 != end3; ++it3) { - cond_macro * m = *it3; + for (cond_macro * m : qi->macros()) { if (m->satisfy_atom() && !m_forbidden.contains(m->get_f())) { insert_q_f_def(q, m->get_f(), m->get_def()); m_candidates.insert(m->get_f()); @@ -2842,11 +2820,7 @@ namespace smt { void get_candidates_from_residue(func_decl_set & candidates) { for (quantifier * q : m_residue) { quantifier_info * qi = get_qinfo(q); - - quantifier_info::macro_iterator it2 = qi->begin_macros(); - quantifier_info::macro_iterator end2 = qi->end_macros(); - for (; it2 != end2; ++it2) { - cond_macro * m = *it2; + for (cond_macro * m : qi->macros()) { func_decl * f = m->get_f(); if (m->satisfy_atom() && !m_forbidden.contains(f) && !m_fs.contains(f)) { candidates.insert(f); @@ -2875,6 +2849,7 @@ namespace smt { m_satisfied.push_scope(); m_residue.push_scope(); + TRACE("model_finder", tout << f->get_name() << " " << mk_pp(def, m_manager) << "\n";); m_fs.insert(f, def); if (update_satisfied_residue(f, def)) { @@ -2889,12 +2864,56 @@ namespace smt { } } + /** + \brief check if satisfied subset introduces a cyclic dependency. + + f_1 = def_1(f_2), ..., f_n = def_n(f_1) + */ + + expr_mark m_visited; + obj_hashtable m_acyclic; + bool is_cyclic() { + m_acyclic.reset(); + while (true) { + unsigned sz = m_acyclic.size(); + if (sz == m_fs.size()) return false; // there are no cyclic dependencies + for (auto const& kv : m_fs) { + func_decl * f = kv.m_key; + if (m_acyclic.contains(f)) continue; + if (is_acyclic(kv.m_value)) + m_acyclic.insert(f); + } + if (sz == m_acyclic.size()) return true; // no progress, so dependency cycle found. + } + } + + struct occurs {}; + struct occurs_check { + hint_solver& m_cls; + occurs_check(hint_solver& hs): m_cls(hs) {} + void operator()(app* n) { if (m_cls.m_fs.contains(n->get_decl()) && !m_cls.m_acyclic.contains(n->get_decl())) throw occurs(); } + void operator()(var* n) {} + void operator()(quantifier* n) {} + }; + bool is_acyclic(expr* def) { + m_visited.reset(); + occurs_check oc(*this); + try { + for_each_expr(oc, m_visited, def); + } + catch (occurs) { + return false; + } + return true; + } + /** \brief Try to reduce m_residue (if not empty) by selecting a function f that is a macro in the residue. */ void greedy(unsigned depth) { if (m_residue.empty()) { + if (is_cyclic()) return; TRACE("model_finder_hint", tout << "found subset that is satisfied by macros\n"; display_search_state(tout);); @@ -3007,11 +3026,11 @@ namespace smt { qi_params const * m_qi_params; bool add_macro(func_decl * f, expr * f_else) { - TRACE("non_auf_macro_solver", tout << "trying to add macro for " << f->get_name() << "\n" << mk_pp(f_else, m_manager) << "\n";); + TRACE("model_finder", tout << "trying to add macro for " << f->get_name() << "\n" << mk_pp(f_else, m_manager) << "\n";); func_decl_set * s = m_dependencies.mk_func_decl_set(); m_dependencies.collect_ng_func_decls(f_else, s); if (!m_dependencies.insert(f, s)) { - TRACE("non_auf_macro_solver", tout << "failed to add macro\n";); + TRACE("model_finder", tout << "failed to add macro\n";); return false; // cyclic dependency } set_else_interp(f, f_else); @@ -3033,10 +3052,7 @@ namespace smt { cond_macro * get_macro_for(func_decl * f, quantifier * q) { cond_macro * r = nullptr; quantifier_info * qi = get_qinfo(q); - quantifier_info::macro_iterator it = qi->begin_macros(); - quantifier_info::macro_iterator end = qi->end_macros(); - for (; it != end; ++it) { - cond_macro * m = *it; + for (cond_macro * m : qi->macros()) { if (m->get_f() == f && !m->is_hint() && is_better_macro(m, r)) r = m; } @@ -3048,13 +3064,10 @@ namespace smt { void collect_candidates(ptr_vector const & qs, obj_map & full_macros, func_decl_set & cond_macros) { for (quantifier * q : qs) { quantifier_info * qi = get_qinfo(q); - quantifier_info::macro_iterator it2 = qi->begin_macros(); - quantifier_info::macro_iterator end2 = qi->end_macros(); - for (; it2 != end2; ++it2) { - cond_macro * m = *it2; + for (cond_macro * m : qi->macros()) { if (!m->is_hint()) { func_decl * f = m->get_f(); - TRACE("non_auf_macro_solver", tout << "considering macro for: " << f->get_name() << "\n"; + TRACE("model_finder", tout << "considering macro for: " << f->get_name() << "\n"; m->display(tout); tout << "\n";); SASSERT(m_qi_params != 0); if (m->is_unconditional() && (!qi->is_auf() || m->get_weight() >= m_qi_params->m_mbqi_force_template)) { From e5aa79ba6a1f1e5e5ba38716c71247ccb70c0391 Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Mon, 19 Feb 2018 13:29:15 +0000 Subject: [PATCH 0583/1283] disjoint cores --- src/opt/mss_solver.cpp | 221 +++++++++++++++++++++++++++++------------ src/opt/opt_params.pyg | 3 +- 2 files changed, 161 insertions(+), 63 deletions(-) diff --git a/src/opt/mss_solver.cpp b/src/opt/mss_solver.cpp index d27b6300c..1ac351855 100755 --- a/src/opt/mss_solver.cpp +++ b/src/opt/mss_solver.cpp @@ -11,45 +11,85 @@ class mss_solver: public maxsmt_solver_base { private: typedef ptr_vector exprs; + typedef obj_hashtable expr_set; mss m_mss; unsigned m_index; - expr_ref_vector m_asms; + exprs m_asms; + unsigned m_mss_found; + vector m_cores; + unsigned m_core_idx; + model_ref m_last_model; + exprs m_mss_trail; + exprs m_mcs_trail; + unsigned_vector m_mss_trail_lim; + unsigned_vector m_mcs_trail_lim; unsigned m_max_mss; + bool m_disjoint_cores; public: mss_solver(maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft), m_mss(c.get_solver(), m), m_index(id), - m_asms(m), - m_max_mss(UINT_MAX) { + m_mss_found(0), + m_core_idx(0), + m_max_mss(UINT_MAX), + m_disjoint_cores(false) { } virtual ~mss_solver() {} virtual lbool operator()() { if (!init()) return l_undef; - init_asms(); - lbool is_sat = check_sat(m_asms); - if (is_sat == l_undef) return l_undef; - if (is_sat == l_true) { - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << m_asms.size() << " :mcs " << 0 << ")\n";); - model_ref mdl; - s().get_model(mdl); - update_assignment(mdl.get()); - return l_true; + init_local(); + lbool is_sat = disjoint_cores(); + if (is_sat != l_true) return is_sat; + if (m_cores.size() == 0) return l_true; + update_model(); + exprs asms; + while (true) { + exprs mss, mcs; + mss.append(m_cores[m_core_idx]); + is_sat = cld(m_last_model, mss, mcs); + if (is_sat == l_undef || m.canceled()) return l_undef; + SASSERT(is_sat == l_true); + update_trails(mss, mcs); + if (m_core_idx < m_cores.size()-1) { + m_core_idx++; + } + else { + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << m_mss_trail.size() + m_asms.size() << " :mcs " << m_mcs_trail.size() << ")\n";); + if (++m_mss_found >= m_max_mss) return l_true; + asms.push_back(relax_and_assert(m.mk_or(m_mcs_trail.size(), m_mcs_trail.c_ptr()))); + is_sat = backtrack(asms); + if (is_sat == l_false) { + SASSERT(m_core_idx == 0); + is_sat = disjoint_cores(asms); + } + if (is_sat == l_undef) return l_undef; + if (is_sat == l_false) return l_true; + } } - return enumerate_mss(); + return l_true; } virtual void updt_params(params_ref& p) { maxsmt_solver_base::updt_params(p); opt_params _p(p); m_max_mss = _p.mss_max(); + m_disjoint_cores = _p.mss_disjoint_cores(); } private: - void init_asms() { + void init_local() { + m_cores.reset(); + m_core_idx = 0; + m_mss_found = 0; + m_last_model.reset(); + m_mss_trail.reset(); + m_mcs_trail.reset(); + m_mss_trail_lim.reset(); + m_mcs_trail_lim.reset(); m_asms.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { expr* e = m_soft[i]; @@ -74,42 +114,84 @@ private: return is_uninterp_const(l) || (m.is_not(l, l) && is_uninterp_const(l)); } - lbool enumerate_mss() { - expr_ref_vector asms(m); - for (unsigned i = 0; i < m_max_mss; ++i) { - exprs mss, mcs; - lbool is_sat = next_mss(asms, mss, mcs); - if (is_sat == l_false && i == 0) return l_false; - if (is_sat == l_undef && i == 0) return l_undef; - if (is_sat == l_false || is_sat == l_undef) return l_true; - asms.push_back(relax_and_assert(m.mk_or(mcs.size(), mcs.c_ptr()))); + lbool disjoint_cores(exprs const& asms) { + expr_set asm_lits, core_lits; + for (unsigned i = 0; i < asms.size(); ++i) { + asm_lits.insert(asms[i]); } - return l_true; + lbool is_sat = l_false; + exprs core; + while (is_sat == l_false) { + exprs tmp_asms; + tmp_asms.append(asms); + tmp_asms.append(m_asms); + is_sat = check_sat(tmp_asms); + if (is_sat == l_true) { + update_model(); + } + else if (is_sat == l_false) { + core.reset(); + s().get_unsat_core(core); + for (unsigned i = 0; i < core.size();) { + if (asm_lits.contains(core[i])) { + core[i] = core.back(); + core.pop_back(); + } + else { + core_lits.insert(core[i]); + ++i; + } + } + if (core.empty()) { + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver empty core)\n";); + return l_false; + } + if (m_disjoint_cores) { + m_cores.push_back(core); + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :core-size " << core.size() << " :num-cores " << m_cores.size() << ")\n";); + for (unsigned i = 0; i < m_asms.size();) { + if (core_lits.contains(m_asms[i]) || !m_disjoint_cores) { + m_asms[i] = m_asms.back(); + m_asms.pop_back(); + } + else { + ++i; + } + } + } + else { + m_cores.push_back(m_asms); + m_asms.reset(); + } + } + } + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :num-cores " << m_cores.size() << ")\n";); + // TODO: update m_lower? + return is_sat; } - lbool next_mss(expr_ref_vector const& asms, exprs& mss, exprs& mcs) { - mss.reset(); - mcs.reset(); - lbool is_sat = check_sat(asms); - if (is_sat != l_true) return is_sat; - model_ref mdl; - s().get_model(mdl); - update_assignment(mdl.get()); - vector dummy; - push_exprs(mss, m_asms); - push_exprs(mss, asms); - is_sat = cld(mdl.get(), mss, mcs); - if (is_sat == l_true) { - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); + lbool disjoint_cores() { + return disjoint_cores(exprs()); + } + + lbool backtrack(exprs& asms) { + SASSERT(m_mss_trail_lim.size() == m_mcs_trail_lim.size()); + lbool is_sat = l_false; + while (is_sat == l_false && m_core_idx > 0) { + m_core_idx--; + m_mss_trail.resize(m_mss_trail_lim.back()); + m_mss_trail_lim.pop_back(); + m_mcs_trail.resize(m_mcs_trail_lim.back()); + m_mcs_trail_lim.pop_back(); + exprs tmp_asms; + tmp_asms.append(asms); + get_trail_asms(tmp_asms); + is_sat = check_sat(tmp_asms); + if (is_sat == l_true) { + update_model(); + } } - /*is_sat = m_mss(mdl.get(), dummy, mss, mcs); - SASSERT(is_sat != l_false); - if (is_sat == l_true) { - mdl.reset(); - m_mss.get_model(mdl); - update_assignment(mdl.get()); - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); - }*/ + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :backtrack-lvl " << m_core_idx << ")\n";); return is_sat; } @@ -118,19 +200,19 @@ private: undef.append(mss); update_sat(initial_model, sat, undef); lbool is_sat = l_true; - while (is_sat == l_true) { + while (is_sat == l_true && !undef.empty()) { expr_ref asum = relax_and_assert(m.mk_or(undef.size(), undef.c_ptr())); - sat.push_back(asum); - is_sat = check_sat(sat); - sat.pop_back(); + exprs asms; + asms.append(sat); + get_trail_asms(asms); + asms.push_back(asum); + is_sat = check_sat(asms); if (is_sat == l_true) { - model_ref mdl; - s().get_model(mdl); - update_sat(mdl, sat, undef); - update_assignment(mdl.get()); + update_model(); + update_sat(m_last_model, sat, undef); } } - if (is_sat == l_false) { + if (is_sat == l_false || undef.empty()) { mss.reset(); mcs.reset(); mss.append(sat); @@ -140,6 +222,26 @@ private: return is_sat; } + void get_trail_asms(exprs& asms) { + asms.append(m_mss_trail); + for (unsigned i = 0; i < m_mcs_trail.size(); ++i) { + asms.push_back(m.mk_not(m_mcs_trail[i])); + } + } + + void update_trails(exprs const& mss, exprs const& mcs) { + m_mss_trail_lim.push_back(m_mss_trail.size()); + m_mcs_trail_lim.push_back(m_mcs_trail.size()); + m_mss_trail.append(mss); + m_mcs_trail.append(mcs); + } + + void update_model() { + m_last_model.reset(); + s().get_model(m_last_model); + update_assignment(m_last_model.get()); + } + void update_sat(model_ref mdl, exprs& sat, exprs& undef) { for (unsigned i = 0; i < undef.size();) { if (is_true(mdl.get(), undef[i])) { @@ -160,12 +262,7 @@ private: } lbool check_sat() { - expr_ref_vector dummy(m); - return check_sat(dummy); - } - - lbool check_sat(expr_ref_vector const& asms) { - return s().check_sat(asms); + return check_sat(exprs()); } lbool check_sat(exprs const& asms) { @@ -186,7 +283,7 @@ private: for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); } - // TODO: DEBUG verify assignment + // TODO: DEBUG verify assignment? m_upper = upper; trace_bounds("mss-solver"); } diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 4cb22389d..41548452a 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -21,7 +21,8 @@ def_module_params('opt', ('maxres.max_correction_set_size', UINT, 3, 'allow generating correction set constraints up to maximal size'), ('maxres.wmax', BOOL, False, 'use weighted theory solver to constrain upper bounds'), ('maxres.pivot_on_correction_set', BOOL, True, 'reduce soft constraints if the current correction set is smaller than current core'), - ('mss.max', UINT, UINT_MAX, 'maximum number of MSS to enumerate') + ('mss.max', UINT, UINT_MAX, 'maximum number of MSS to enumerate'), + ('mss.disjoint_cores', BOOL, True, 'partition soft based on disjoint cores') )) From b0997661ccfccc76e66e00740ed53249d4bf8dcc Mon Sep 17 00:00:00 2001 From: Moritz Kiefer Date: Mon, 19 Feb 2018 17:53:53 +0100 Subject: [PATCH 0584/1283] Insert sort declaration for nullary sorts declared using declare-datatype --- src/parsers/smt2/smt2parser.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 0b0420873..347cbbd68 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -970,6 +970,9 @@ namespace smt2 { check_rparen_next("invalid datatype declaration, ')' expected"); } else { + if (dt_name) { + m_ctx.insert(pm().mk_psort_dt_decl(0, *dt_name)); + } parse_constructor_decls(ct_decls); } check_rparen_next("invalid datatype declaration, ')' expected"); From 4c1379e8c9600462934a6792742cb66b2e289239 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Feb 2018 21:49:03 -0800 Subject: [PATCH 0585/1283] bug fixes Signed-off-by: Nikolaj Bjorner --- .../bit_blaster/bit_blaster_rewriter.cpp | 20 + .../bit_blaster/bit_blaster_rewriter.h | 4 +- src/opt/opt_parse.cpp | 34 +- src/sat/ba_solver.cpp | 460 +++--------------- src/sat/ba_solver.h | 87 +--- src/sat/sat_asymm_branch.cpp | 2 - src/sat/sat_asymm_branch_params.pyg | 2 +- src/sat/sat_big.cpp | 6 + src/sat/sat_config.cpp | 4 + src/sat/sat_config.h | 6 + src/sat/sat_elim_eqs.cpp | 2 + src/sat/sat_local_search.cpp | 35 +- src/sat/sat_local_search.h | 6 +- src/sat/sat_parallel.cpp | 7 +- src/sat/sat_parallel.h | 2 +- src/sat/sat_params.pyg | 1 + src/sat/sat_scc.cpp | 1 + src/sat/sat_simplifier.cpp | 4 +- src/sat/sat_solver.cpp | 19 +- src/sat/sat_solver/inc_sat_solver.cpp | 81 ++- src/sat/tactic/goal2sat.cpp | 23 - src/tactic/bv/bit_blaster_tactic.cpp | 12 +- 22 files changed, 238 insertions(+), 580 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index c47dacc96..3573d44f3 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -181,6 +181,17 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { } } + unsigned m_keypos; + + void start_rewrite() { + m_keypos = m_keys.size(); + } + void end_rewrite(obj_map& const2bits) { + for (unsigned i = m_keypos; i < m_keys.size(); ++i) { + const2bits.insert(m_keys[i].get(), m_values[i].get()); + } + } + template app * mk_mkbv(V const & bits) { return m().mk_app(butil().get_family_id(), OP_MKBV, bits.size(), bits.c_ptr()); @@ -635,6 +646,8 @@ struct bit_blaster_rewriter::imp : public rewriter_tpl { } void push() { m_cfg.push(); } void pop(unsigned s) { m_cfg.pop(s); } + void start_rewrite() { m_cfg.start_rewrite(); } + void end_rewrite(obj_map& const2bits) { m_cfg.end_rewrite(const2bits); } unsigned get_num_scopes() const { return m_cfg.get_num_scopes(); } }; @@ -683,3 +696,10 @@ unsigned bit_blaster_rewriter::get_num_scopes() const { return m_imp->get_num_scopes(); } +void bit_blaster_rewriter::start_rewrite() { + m_imp->start_rewrite(); +} + +void bit_blaster_rewriter::end_rewrite(obj_map& const2bits) { + m_imp->end_rewrite(const2bits); +} diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h index 6ffed00ae..2463bd086 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h @@ -33,7 +33,9 @@ public: ast_manager & m() const; unsigned get_num_steps() const; void cleanup(); - obj_map const& const2bits() const; + obj_map const& const2bits() const; + void start_rewrite(); + void end_rewrite(obj_map& const2bits); void operator()(expr * e, expr_ref & result, proof_ref & result_proof); void push(); void pop(unsigned num_scopes); diff --git a/src/opt/opt_parse.cpp b/src/opt/opt_parse.cpp index 666f79d97..2118c85eb 100644 --- a/src/opt/opt_parse.cpp +++ b/src/opt/opt_parse.cpp @@ -670,6 +670,14 @@ private: return peek(pos) == "<=" || peek(pos) == "=<"; } + bool peek_minus_infty(unsigned pos) { + return peek(pos) == "-" && (peek(pos+1) == "inf" || peek(pos+1) == "infinity"); + } + + bool peek_plus_infty(unsigned pos) { + return peek(pos) == "+" && (peek(pos+1) == "inf" || peek(pos+1) == "infinity"); + } + void parse_indicator(symbol& var, rational& val) { if (peek(1) == "=" && tok.peek_num(2) && peek(3) == "->") { var = peek(0); @@ -703,11 +711,15 @@ private: v = peek(2); update_lower(lhs, v); tok.next(3); - if (peek_le(0) && tok.peek_num(1)) { - rational rhs = tok.get_num(1); - update_upper(v, rhs); - tok.next(2); - } + parse_upper(v); + } + else if (peek_minus_infty(0) && peek_le(2)) { + v = peek(3); + tok.next(4); + parse_upper(v); + } + else if (peek_plus_infty(2) && peek_le(1)) { + tok.next(4); } else if (peek_le(1) && tok.peek_num(2)) { v = peek(0); @@ -721,6 +733,18 @@ private: } } + void parse_upper(symbol const& v) { + if (peek_le(0) && tok.peek_num(1)) { + rational rhs = tok.get_num(1); + update_upper(v, rhs); + tok.next(2); + } + else if (peek_le(0) && peek_plus_infty(1)) { + tok.next(3); + } + + } + void update_lower(rational const& r, symbol const& v) { bound b; m_bounds.find(v, b); diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 6adaa1ef6..d1a0c7403 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -47,16 +47,6 @@ namespace sat { return static_cast(*this); } - ba_solver::eq& ba_solver::constraint::to_eq() { - SASSERT(is_eq()); - return static_cast(*this); - } - - ba_solver::eq const& ba_solver::constraint::to_eq() const{ - SASSERT(is_eq()); - return static_cast(*this); - } - ba_solver::xr& ba_solver::constraint::to_xr() { SASSERT(is_xr()); return static_cast(*this); @@ -95,15 +85,6 @@ namespace sat { } break; } - case ba_solver::eq_t: { - ba_solver::eq const& e = cnstr.to_eq(); - for (ba_solver::eliteral wl : e) { - if (wl.weight != 1) out << wl.weight << " * "; - out << wl.lit << " "; - } - out << " = " << e.k(); - break; - } default: UNREACHABLE(); } @@ -205,33 +186,6 @@ namespace sat { } - // ----------------------------------- - // eq - - ba_solver::eq::eq(unsigned id, literal lit, svector const& wlits, unsigned k): - constraint(eq_t, id, lit, wlits.size(), eq::get_obj_size(wlits.size())), - m_lo(0), - m_hi(0), - m_max(0), - m_k(k) - { - unsigned i = 0; - for (wliteral const& w : wlits) { - m_wlits[i++] = eliteral(w.first, w.second); - m_max += w.first; - } - m_hi = m_max; - m_trail_sz = 0; - } - - unsigned ba_solver::eq::index(literal l) const { - for (unsigned i = 0; i < size(); ++i) { - if (l.var() == m_wlits[i].lit.var()) return i; - } - UNREACHABLE(); - return UINT_MAX; - } - // ----------------------------------- // xr @@ -271,7 +225,7 @@ namespace sat { } if (root != null_literal) { if (!is_watched(root, c)) watch_literal(root, c); - if (!is_watched(~root, c)) watch_literal(~root, c); + if (!c.is_pure() && !is_watched(~root, c)) watch_literal(~root, c); } TRACE("ba", display(tout << "init watch: ", c, true);); SASSERT(root == null_literal || value(root) == l_true); @@ -925,251 +879,6 @@ namespace sat { out << ">= " << p.k() << "\n"; } - // -------------------- - // eq: - - ba_solver::constraint* ba_solver::add_eq(literal lit, svector const& wlits, unsigned k, bool learned) { - void * mem = m_allocator.allocate(eq::get_obj_size(wlits.size())); - eq* e = new (mem) eq(next_id(), lit, wlits, k); - e->set_learned(learned); - add_constraint(e); - for (eliteral const& wl : *e) { - watch_literal(wl.lit, *e); - watch_literal(~(wl.lit), *e); - } - return e; - } - - void ba_solver::display(std::ostream& out, eq const& e, bool values) const { - display_lit(out, e.lit(), e.size(), values); - if (values) { - if (e.trail_sz() > 0) { - out << "trail: "; - for (unsigned i = 0; i < e.trail_sz(); ++i) { - out << e[i].tweight << " * " << e[i].tlit << " "; - } - } - out << "[" << e.lo() << ":" << e.hi() << "] "; - } - for (eliteral wl : e) { - literal l = wl.lit; - unsigned w = wl.weight; - if (w > 1) out << w << " * "; - out << l; - if (values) { - out << "@(" << value(l); - if (value(l) != l_undef) { - out << ":" << lvl(l); - } - out << ") "; - } - else { - out << " "; - } - } - out << "= " << e.k() << "\n"; - } - - bool ba_solver::init_watch(eq& e) { - return true; - } - - void ba_solver::clear_watch(eq& e) { - for (eliteral const& wl : e) { - unwatch_literal(wl.lit, e); - unwatch_literal(~(wl.lit), e); - } - if (e.lit() != null_literal) { - unwatch_literal(e.lit(), e); - unwatch_literal(~e.lit(), e); - } - } - - /* - * \update the bounds for [lo,hi] based on what is unassigned on the trail. - */ - void ba_solver::pop_eq(eq& e) { - unsigned idx = e.trail_sz() - 1; - literal tlit = e[idx].tlit; - if (tlit.sign()) { - e.inc_hi(e[idx].tweight); - } - else { - e.dec_lo(e[idx].tweight); - } - e.set_trail_sz(idx); - } - - lbool ba_solver::add_assign(eq& e, literal nl) { - //IF_VERBOSE(0, verbose_stream() << nl << "@" << lvl(nl) << ": " << e << "\n"); - SASSERT(value(nl) == l_false); - if (nl.var() == e.lit().var()) { - // no-op - } - else { - unsigned i = e.index(nl); - eliteral wl = e[i]; - if (wl.lit == nl) { - e.dec_hi(wl); - } - else { - SASSERT(wl.lit == ~nl); - e.inc_lo(wl); - } - m_eq_to_pop.push_back(&e); - } - if (e.lo() > e.k() || e.hi() < e.k()) { - if (e.lit() == null_literal || value(e.lit()) == l_true) { - set_conflict(e, nl); - return l_false; - } - if (e.lit() != null_literal && value(e.lit()) == l_undef) { - assign(e, ~e.lit()); - } - } - else if (e.lo() == e.hi()) { - SASSERT(e.lo() == e.k()); - if (e.lit() != null_literal && value(e.lit()) == l_false) { - set_conflict(e, nl); - return l_false; - } - if (e.lit() != null_literal && value(e.lit()) == l_undef) { - assign(e, e.lit()); - } - } - else if ((e.lit() == null_literal || value(e.lit()) == l_true)) { - if (e.lo() == e.k()) { - for (eliteral el : e) { - if (value(el.lit) == l_undef) { - //IF_VERBOSE(0, display(verbose_stream() << "proapgate " << ~el.lit << " ", e, true)); - assign(e, ~el.lit); - } - } - } - else if (e.hi() == e.k()) { - for (eliteral el : e) { - if (value(el.lit) == l_undef) { - //IF_VERBOSE(0, display(verbose_stream() << "proapgate " << el.lit << " ", e, true)); - assign(e, el.lit); - } - } - } - } - return l_true; - } - - void ba_solver::simplify(eq& e) { - // no-op for now - } - - void ba_solver::recompile(eq& e) { - for (eliteral const& el : e) { - m_weights[el.lit.index()] += el.weight; - } - unsigned k = e.k(), sz = e.size(); - unsigned j = 0; - bool is_false = false; - for (unsigned i = 0; i < sz; ++i) { - eliteral el = e[i]; - unsigned w1 = m_weights[el.lit.index()]; - unsigned w2 = m_weights[(~el.lit).index()]; - if (w1 == 0 || w1 < w2) continue; - if (k < w2) { - is_false = true; - break; - } - k -= w2; - w1 -= w2; - if (w1 == 0) continue; - e[j++] = eliteral(w1, el.lit); - } - sz = j; - for (eliteral const& el : e) { - m_weights[el.lit.index()] = 0; - m_weights[(~el.lit).index()] = 0; - } - if (is_false) { - if (e.lit() == null_literal) { - s().mk_clause(0, 0, true); - } - else { - literal lit = ~e.lit(); - s().mk_clause(1, &lit, true); - } - remove_constraint(e, "recompiled to false"); - return; - } - // update trail - e.set_size(sz); - e.set_k(k); - for (unsigned i = 0; i < sz; ++i) { - e[i].tlit = null_literal; - } - e.set_trail_sz(0); - e.reset_lo(); - e.reset_hi(); - for (eliteral const& el : e) { - switch (value(el.lit)) { - case l_true: e.inc_lo(el); break; - case l_false: e.dec_hi(el); break; - default: break; - } - } - } - - void ba_solver::split_root(eq& e) { - NOT_IMPLEMENTED_YET(); - } - - void ba_solver::get_antecedents(literal l, eq const& e, literal_vector& r) { - for (eliteral wl : e) { - if (wl.lit.var() == l.var()) continue; - switch (value(wl.lit)) { - case l_true: r.push_back(wl.lit); break; - case l_false: r.push_back(~wl.lit); break; - default: break; - } - } - if (e.lit() != null_literal && l.var() != e.lit().var()) { - switch (value(e.lit())) { - case l_true: r.push_back(e.lit()); break; - case l_false: r.push_back(~e.lit()); break; - default: break; - } - } - } - - lbool ba_solver::eval(eq const& e) const { - unsigned trues = 0, undefs = 0; - for (eliteral wl : e) { - switch (value(wl.lit)) { - case l_true: trues += wl.weight; break; - case l_undef: undefs += wl.weight; break; - default: break; - } - } - if (trues + undefs < e.k()) return l_false; - if (trues > e.k()) return l_false; - if (trues == e.k() && undefs == 0) return l_true; - return l_undef; - } - - lbool ba_solver::eval(model const& m, eq const& e) const { - unsigned trues = 0, undefs = 0; - for (eliteral wl : e) { - switch (value(m, wl.lit)) { - case l_true: trues += wl.weight; break; - case l_undef: undefs += wl.weight; break; - default: break; - } - } - if (trues + undefs < e.k()) return l_false; - if (trues > e.k()) return l_false; - if (trues == e.k() && undefs == 0) return l_true; - return l_undef; - } - - // -------------------- // xr: @@ -1512,17 +1221,6 @@ namespace sat { for (literal l : m_lemma) process_antecedent(~l, offset); break; } - case eq_t: { - eq& e = cnstr.to_eq(); - m_lemma.reset(); - inc_bound(offset); - inc_coeff(consequent, offset); - get_antecedents(consequent, e, m_lemma); - TRACE("ba", display(tout, e, true); tout << m_lemma << "\n";); - for (literal l : m_lemma) process_antecedent(~l, offset); - break; - - } default: UNREACHABLE(); break; @@ -1888,7 +1586,6 @@ namespace sat { case card_t: return init_watch(c.to_card()); case pb_t: return init_watch(c.to_pb()); case xr_t: return init_watch(c.to_xr()); - case eq_t: return init_watch(c.to_eq()); } UNREACHABLE(); return false; @@ -1899,7 +1596,6 @@ namespace sat { case card_t: return add_assign(c.to_card(), l); case pb_t: return add_assign(c.to_pb(), l); case xr_t: return add_assign(c.to_xr(), l); - case eq_t: return add_assign(c.to_eq(), l); } UNREACHABLE(); return l_undef; @@ -1950,7 +1646,7 @@ namespace sat { init_watch(c); return true; } - else if (c.lit() != null_literal && value(c.lit()) != l_true && c.tag() != eq_t) { + else if (c.lit() != null_literal && value(c.lit()) != l_true) { return true; } else { @@ -2005,7 +1701,6 @@ namespace sat { case card_t: return get_reward(c.to_card(), occs); case pb_t: return get_reward(c.to_pb(), occs); case xr_t: return 0; - case eq_t: return 1; default: UNREACHABLE(); return 0; } } @@ -2310,6 +2005,7 @@ namespace sat { } void ba_solver::watch_literal(literal lit, constraint& c) { + if (c.is_pure() && lit == ~c.lit()) return; get_wlist(~lit).push_back(watched(c.index())); } @@ -2318,7 +2014,6 @@ namespace sat { case card_t: get_antecedents(l, c.to_card(), r); break; case pb_t: get_antecedents(l, c.to_pb(), r); break; case xr_t: get_antecedents(l, c.to_xr(), r); break; - case eq_t: get_antecedents(l, c.to_eq(), r); break; default: UNREACHABLE(); break; } } @@ -2342,9 +2037,6 @@ namespace sat { case xr_t: clear_watch(c.to_xr()); break; - case eq_t: - clear_watch(c.to_eq()); - break; default: UNREACHABLE(); } @@ -2367,7 +2059,6 @@ namespace sat { case card_t: return validate_unit_propagation(c.to_card(), l); case pb_t: return validate_unit_propagation(c.to_pb(), l); case xr_t: return true; - case eq_t: return validate_unit_propagation(c.to_eq(), l); default: UNREACHABLE(); break; } return false; @@ -2383,7 +2074,6 @@ namespace sat { case card_t: return eval(v1, eval(c.to_card())); case pb_t: return eval(v1, eval(c.to_pb())); case xr_t: return eval(v1, eval(c.to_xr())); - case eq_t: return eval(v1, eval(c.to_eq())); default: UNREACHABLE(); break; } return l_undef; @@ -2395,7 +2085,6 @@ namespace sat { case card_t: return eval(v1, eval(m, c.to_card())); case pb_t: return eval(v1, eval(m, c.to_pb())); case xr_t: return eval(v1, eval(m, c.to_xr())); - case eq_t: return eval(v1, eval(m, c.to_eq())); default: UNREACHABLE(); break; } return l_undef; @@ -2730,7 +2419,6 @@ namespace sat { void ba_solver::push() { m_constraint_to_reinit_lim.push_back(m_constraint_to_reinit.size()); - m_eq_to_pop_lim.push_back(m_eq_to_pop.size()); } void ba_solver::pop(unsigned n) { @@ -2739,13 +2427,6 @@ namespace sat { m_constraint_to_reinit_last_sz = m_constraint_to_reinit_lim[new_lim]; m_constraint_to_reinit_lim.shrink(new_lim); m_num_propagations_since_pop = 0; - - new_lim = m_eq_to_pop_lim.size() - n; - for (unsigned i = m_eq_to_pop_lim[new_lim]; i < m_eq_to_pop.size(); ++i) { - pop_eq(*m_eq_to_pop[i]); - } - m_eq_to_pop.shrink(m_eq_to_pop_lim[new_lim]); - m_eq_to_pop_lim.shrink(new_lim); } void ba_solver::pop_reinit() { @@ -2772,9 +2453,6 @@ namespace sat { case xr_t: simplify(c.to_xr()); break; - case eq_t: - simplify(c.to_eq()); - break; default: UNREACHABLE(); } @@ -2798,6 +2476,7 @@ namespace sat { for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) subsumption(*m_learned[i]); cleanup_clauses(); cleanup_constraints(); + update_pure(); } while (m_simplify_change || trail_sz < s().init_trail_size()); @@ -2814,7 +2493,41 @@ namespace sat { // IF_VERBOSE(0, s().display(verbose_stream())); // mutex_reduction(); // if (s().m_clauses.size() < 80000) lp_lookahead_reduction(); + } + /* + * ~lit does not occur in clauses + * ~lit is only in one constraint use list + * lit == C + * -> ignore assignemnts to ~lit for C + * + * ~lit does not occur in clauses + * lit is only in one constraint use list + * lit == C + * -> negate: ~lit == ~C + */ + void ba_solver::update_pure() { + // return; + for (constraint* cp : m_constraints) { + literal lit = cp->lit(); + if (lit != null_literal && + !cp->is_pure() && + value(lit) == l_undef && + get_wlist(~lit).size() == 1 && + m_clause_use_list.get(lit).empty()) { + clear_watch(*cp); + cp->negate(); + lit.neg(); + } + if (lit != null_literal && + !cp->is_pure() && + m_cnstr_use_list[(~lit).index()].size() == 1 && + get_wlist(lit).size() == 1 && + m_clause_use_list.get(~lit).empty()) { + cp->set_pure(); + get_wlist(~lit).erase(watched(cp->index())); // just ignore assignments to false + } + } } void ba_solver::mutex_reduction() { @@ -2930,9 +2643,6 @@ namespace sat { case pb_t: recompile(c.to_pb()); break; - case eq_t: - recompile(c.to_eq()); - break; case xr_t: NOT_IMPLEMENTED_YET(); break; @@ -3144,7 +2854,6 @@ namespace sat { case card_t: split_root(c.to_card()); break; case pb_t: split_root(c.to_pb()); break; case xr_t: NOT_IMPLEMENTED_YET(); break; - case eq_t: split_root(c.to_eq()); break; } } @@ -3265,15 +2974,6 @@ namespace sat { } break; } - case eq_t: { - eq& e = cp->to_eq(); - for (eliteral wl : e) { - literal l = wl.lit; - m_cnstr_use_list[l.index()].push_back(&e); - m_cnstr_use_list[(~l).index()].push_back(&e); - } - break; - } } } } @@ -3296,8 +2996,6 @@ namespace sat { } break; } - case eq_t: - break; default: break; } @@ -3372,8 +3070,6 @@ namespace sat { if (p.k() > 1) subsumption(p); break; } - case eq_t: - break; default: break; } @@ -3464,30 +3160,32 @@ namespace sat { return c1_exclusive + c2.k() + comp.size() <= c1.k(); } - bool ba_solver::subsumes(card& c1, clause& c2, literal_vector & comp) { - unsigned c2_exclusive = 0; - unsigned common = 0; - comp.reset(); + /* + \brief L + A >= k subsumes L + C if |A| < k + A + L + B >= k self-subsumes A + ~L + C >= 1 + if k + 1 - |B| - |C| - |L| > 0 + */ + bool ba_solver::subsumes(card& c1, clause& c2, bool& self) { + unsigned common = 0, complement = 0, c2_exclusive = 0; + self = false; + for (literal l : c2) { if (is_marked(l)) { ++common; } else if (is_marked(~l)) { - comp.push_back(l); + ++complement; } else { ++c2_exclusive; } } - - unsigned c1_exclusive = c1.size() - common - comp.size(); - bool result = c1_exclusive + 1 <= c1.k(); - - if (!comp.empty() && result) { - IF_VERBOSE(10, verbose_stream() << "self-subsume clause " << c2 << " is TBD\n";); - return false; + unsigned c1_exclusive = c1.size() - common - complement; + if (complement > 0 && c1.k() + 1 > c1_exclusive + c2_exclusive + common) { + self = true; + return true; } - return result; + return c1.size() - common < c1.k(); } /* @@ -3517,8 +3215,6 @@ namespace sat { case pb_t: s = subsumes(p1, c->to_pb()); break; - case eq_t: - break; default: break; } @@ -3582,23 +3278,22 @@ namespace sat { void ba_solver::clause_subsumption(card& c1, literal lit, clause_vector& removed_clauses) { SASSERT(!c1.was_removed()); - literal_vector slit; - clause_use_list::iterator it = m_clause_use_list.get(lit).mk_iterator(); + clause_use_list& occurs = m_clause_use_list.get(lit); + clause_use_list::iterator it = occurs.mk_iterator(); while (!it.at_end()) { clause& c2 = it.curr(); - if (!c2.was_removed() && subsumes(c1, c2, slit)) { - if (slit.empty()) { + bool self; + if (!c2.was_removed() && subsumes(c1, c2, self)) { + if (self) { + // self-subsumption is TBD + } + else { TRACE("ba", tout << "remove\n" << c1 << "\n" << c2 << "\n";); removed_clauses.push_back(&c2); ++m_stats.m_num_clause_subsumes; c1.set_learned(false); - } - else { - IF_VERBOSE(11, verbose_stream() << "self-subsume clause is TBD\n";); - // remove literal slit from c2. - TRACE("ba", tout << "TBD remove literals " << slit << " from " << c2 << "\n";); - } - } + } + } it.next(); } } @@ -3615,7 +3310,7 @@ namespace sat { watched w = *it; if (w.is_binary_clause() && is_marked(w.get_literal())) { ++m_stats.m_num_bin_subsumes; - // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); + IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); if (!w.is_learned()) { c1.set_learned(false); } @@ -3745,15 +3440,6 @@ namespace sat { result->add_xr(lits, x.learned()); break; } - case eq_t: { - eq const& e = cp->to_eq(); - wlits.reset(); - for (eliteral w : e) { - wlits.push_back(wliteral(w.weight, w.lit)); - } - result->add_eq(e.lit(), wlits, e.k(), e.learned()); - break; - } default: UNREACHABLE(); } @@ -3791,14 +3477,6 @@ namespace sat { } break; } - case eq_t: { - eq const& e = cp->to_eq(); - for (eliteral w : e) { - ul.insert(w.lit, idx); - ul.insert(~(w.lit), idx); - } - break; - } default: UNREACHABLE(); } @@ -3840,8 +3518,6 @@ namespace sat { } return weight >= p.k(); } - case eq_t: - break; default: break; } @@ -3963,7 +3639,6 @@ namespace sat { case card_t: display(out, c.to_card(), values); break; case pb_t: display(out, c.to_pb(), values); break; case xr_t: display(out, c.to_xr(), values); break; - case eq_t: display(out, c.to_eq(), values); break; default: UNREACHABLE(); break; } } @@ -4280,13 +3955,6 @@ namespace sat { if (lxr != null_literal) ineq.push(~lxr, offset); break; } - case eq_t: { - eq& e = cnstr.to_eq(); - ineq.reset(e.k()); - for (eliteral wl : e) ineq.push(wl.lit, wl.weight); - if (e.lit() != null_literal) ineq.push(~e.lit(), e.k()); - break; - } default: UNREACHABLE(); break; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index e63cd5333..9b5a31774 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -51,14 +51,12 @@ namespace sat { enum tag_t { card_t, pb_t, - xr_t, - eq_t + xr_t }; class card; class pb; class xr; - class eq; class constraint { protected: @@ -72,9 +70,10 @@ namespace sat { size_t m_obj_size; bool m_learned; unsigned m_id; + bool m_pure; // is the constraint pure (only positive occurrences) public: constraint(tag_t t, unsigned id, literal l, unsigned sz, size_t osz): - m_tag(t), m_removed(false), m_lit(l), m_watch(null_literal), m_glue(0), m_psm(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id) {} + m_tag(t), m_removed(false), m_lit(l), m_watch(null_literal), m_glue(0), m_psm(0), m_size(sz), m_obj_size(osz), m_learned(false), m_id(id), m_pure(false) {} ext_constraint_idx index() const { return reinterpret_cast(this); } unsigned id() const { return m_id; } tag_t tag() const { return m_tag; } @@ -95,20 +94,19 @@ namespace sat { void set_watch() { m_watch = m_lit; } void clear_watch() { m_watch = null_literal; } bool is_clear() const { return m_watch == null_literal && m_lit != null_literal; } + bool is_pure() const { return m_pure; } + void set_pure() { m_pure = true; } size_t obj_size() const { return m_obj_size; } card& to_card(); pb& to_pb(); xr& to_xr(); - eq& to_eq(); card const& to_card() const; pb const& to_pb() const; xr const& to_xr() const; - eq const& to_eq() const; bool is_card() const { return m_tag == card_t; } bool is_pb() const { return m_tag == pb_t; } bool is_xr() const { return m_tag == xr_t; } - bool is_eq() const { return m_tag == eq_t; } virtual bool is_watching(literal l) const { UNREACHABLE(); return false; }; virtual literal_vector literals() const { UNREACHABLE(); return literal_vector(); } @@ -185,60 +183,6 @@ namespace sat { virtual unsigned get_coeff(unsigned i) const { return m_wlits[i].first; } }; - struct eliteral { - unsigned weight; - literal lit; - unsigned tweight; - literal tlit; - eliteral(unsigned w, literal lit): - weight(w), lit(lit), tweight(0), tlit(null_literal) - {} - eliteral(): weight(0), lit(null_literal), tweight(0), tlit(null_literal) {} - }; - class eq : public constraint { - unsigned m_lo, m_hi, m_max, m_k, m_trail_sz; - eliteral m_wlits[0]; - public: - static size_t get_obj_size(unsigned num_lits) { return sizeof(eq) + num_lits * sizeof(eliteral); } - eq(unsigned id, literal lit, svector const& wlits, unsigned k); - literal lit() const { return m_lit; } - eliteral operator[](unsigned i) const { return m_wlits[i]; } - eliteral& operator[](unsigned i) { return m_wlits[i]; } - eliteral const* begin() const { return m_wlits; } - eliteral const* end() const { return begin() + m_size; } - unsigned index(literal l) const; - unsigned k() const { return m_k; } - void reset_lo() { m_lo = 0; } - void reset_hi() { m_hi = m_max; } - unsigned lo() const { return m_lo; } - unsigned hi() const { return m_hi; } - void inc_hi(unsigned d) { m_hi += d; } - void dec_lo(unsigned d) { SASSERT(d <= m_lo); m_lo -= d; } - // increment/decrement lo/hi save delta and variable in a trail. - void inc_lo(eliteral const& e) { - m_lo += e.weight; - m_wlits[m_trail_sz].tlit = literal(e.lit.var(), false); - m_wlits[m_trail_sz++].tweight = e.weight; - } - void dec_hi(eliteral const& e) { - m_hi -= e.weight; - m_wlits[m_trail_sz].tlit = literal(e.lit.var(), true); - m_wlits[m_trail_sz++].tweight = e.weight; - } - unsigned trail_sz() const { return m_trail_sz; } - void set_trail_sz(unsigned sz) { m_trail_sz = sz; } - - virtual void negate() { SASSERT(lit() != null_literal); m_lit.neg(); } - virtual void set_k(unsigned k) { m_k = k; } - virtual void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } - virtual literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.lit); return lits; } - virtual bool is_watching(literal l) const { return true; } - virtual literal get_lit(unsigned i) const { return m_wlits[i].lit; } - virtual void set_lit(unsigned i, literal l) { m_wlits[i].lit = l; } - virtual unsigned get_coeff(unsigned i) const { return m_wlits[i].weight; } - - }; - class xr : public constraint { literal m_lits[0]; public: @@ -281,8 +225,6 @@ namespace sat { unsigned_vector m_constraint_to_reinit_lim; unsigned m_constraint_to_reinit_last_sz; unsigned m_constraint_id; - ptr_vector m_eq_to_pop; - unsigned_vector m_eq_to_pop_lim; // conflict resolution unsigned m_num_marks; @@ -340,7 +282,7 @@ namespace sat { unsigned_vector m_weights; svector m_wlits; bool subsumes(card& c1, card& c2, literal_vector& comp); - bool subsumes(card& c1, clause& c2, literal_vector& comp); + bool subsumes(card& c1, clause& c2, bool& self); bool subsumed(card& c1, literal l1, literal l2); bool subsumes(pb const& p1, pb_base const& p2); void subsumes(pb& p1, literal lit); @@ -363,6 +305,7 @@ namespace sat { void gc_half(char const* _method); void update_psm(constraint& c) const; void mutex_reduction(); + void update_pure(); unsigned use_count(literal lit) const { return m_cnstr_use_list[lit.index()].size() + m_clause_use_list.get(lit).size(); } @@ -451,19 +394,6 @@ namespace sat { lbool eval(model const& m, pb const& p) const; double get_reward(pb const& p, literal_occs_fun& occs) const; - // eq functionality - void pop_eq(eq& e); - bool init_watch(eq& e); - void clear_watch(eq& e); - lbool add_assign(eq& e, literal alit); - void get_antecedents(literal l, eq const& e, literal_vector& r); - void simplify(eq& e); - void recompile(eq& e); - void split_root(eq& e); - void calibrate(eq& e); - lbool eval(eq const& e) const; - lbool eval(model const& m, eq const& e) const; - // access solver inline lbool value(bool_var v) const { return value(literal(v, false)); } inline lbool value(literal lit) const { return m_lookahead ? m_lookahead->value(lit) : m_solver->value(lit); } @@ -541,13 +471,11 @@ namespace sat { void display(std::ostream& out, card const& c, bool values) const; void display(std::ostream& out, pb const& p, bool values) const; void display(std::ostream& out, xr const& c, bool values) const; - void display(std::ostream& out, eq const& e, bool values) const; void display_lit(std::ostream& out, literal l, unsigned sz, bool values) const; constraint* add_at_least(literal l, literal_vector const& lits, unsigned k, bool learned); constraint* add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); constraint* add_xr(literal_vector const& lits, bool learned); - constraint* add_eq(literal l, svector const& wlits, unsigned k, bool learned); void copy_core(ba_solver* result, bool learned); void copy_constraints(ba_solver* result, ptr_vector const& constraints); @@ -561,7 +489,6 @@ namespace sat { void add_at_least(bool_var v, literal_vector const& lits, unsigned k); void add_pb_ge(bool_var v, svector const& wlits, unsigned k); void add_xr(literal_vector const& lits); - void add_eq(literal l, svector const& wlits, unsigned k) { add_eq(l, wlits, k, false); } virtual bool propagate(literal l, ext_constraint_idx idx); virtual lbool resolve_conflict(); diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 64b1d5e67..8b7c55797 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -87,8 +87,6 @@ namespace sat { IF_VERBOSE(1, verbose_stream() << "(sat-asymm-branch-step :elim " << num_elim << ")\n";); if (num_elim == 0) break; - if (false && num_elim > 1000) - i = 0; } IF_VERBOSE(1, if (m_elim_learned_literals > eliml0) verbose_stream() << "(sat-asymm-branch :elim " << m_elim_learned_literals - eliml0 << ")\n";); diff --git a/src/sat/sat_asymm_branch_params.pyg b/src/sat/sat_asymm_branch_params.pyg index b04b5ff01..5ee140ab9 100644 --- a/src/sat/sat_asymm_branch_params.pyg +++ b/src/sat/sat_asymm_branch_params.pyg @@ -2,7 +2,7 @@ def_module_params(module_name='sat', class_name='sat_asymm_branch_params', export=True, params=(('asymm_branch', BOOL, True, 'asymmetric branching'), - ('asymm_branch.rounds', UINT, 10, 'maximal number of rounds to run asymmetric branch simplifications if progress is made'), + ('asymm_branch.rounds', UINT, 2, 'maximal number of rounds to run asymmetric branch simplifications if progress is made'), ('asymm_branch.delay', UINT, 1, 'number of simplification rounds to wait until invoking asymmetric branch simplification'), ('asymm_branch.sampled', BOOL, True, 'use sampling based asymmetric branching based on binary implication graph'), ('asymm_branch.limit', UINT, 100000000, 'approx. maximum number of literals visited during asymmetric branching'), diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index c820aa4f8..0acc5e7cb 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -169,6 +169,7 @@ namespace sat { unsigned idx = 0; unsigned elim = 0; for (watch_list & wlist : s.m_watches) { + if (s.inconsistent()) break; literal u = to_literal(idx++); watch_list::iterator it = wlist.begin(); watch_list::iterator itprev = it; @@ -179,6 +180,10 @@ namespace sat { literal v = w.get_literal(); if (reaches(u, v) && u != get_parent(v)) { ++elim; + if (find_binary_watch(wlist, ~v)) { + IF_VERBOSE(10, verbose_stream() << "binary: " << ~u << "\n"); + s.assign(~u, justification()); + } // could turn non-learned non-binary tautology into learned binary. s.get_wlist(~v).erase(watched(~u, w.is_learned())); continue; @@ -189,6 +194,7 @@ namespace sat { } wlist.set_end(itprev); } + s.propagate(false); return elim; } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 381692654..c37312ae7 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -72,6 +72,10 @@ namespace sat { m_num_threads = p.threads(); m_local_search = p.local_search(); m_local_search_threads = p.local_search_threads(); + if (p.local_search_mode() == symbol("gsat")) + m_local_search_mode = local_search_mode::gsat; + else + m_local_search_mode = local_search_mode::wsat; m_unit_walk = p.unit_walk(); m_unit_walk_threads = p.unit_walk_threads(); m_lookahead_simplify = p.lookahead_simplify(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index d70ae0cb7..b42761f4b 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -73,6 +73,11 @@ namespace sat { adaptive_psat_cutoff }; + enum local_search_mode { + gsat, + wsat + }; + struct config { unsigned long long m_max_memory; phase_selection m_phase; @@ -90,6 +95,7 @@ namespace sat { unsigned m_num_threads; unsigned m_local_search_threads; bool m_local_search; + local_search_mode m_local_search_mode; unsigned m_unit_walk_threads; bool m_unit_walk; bool m_lookahead_simplify; diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index b178c52e2..54a5d54ba 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -223,6 +223,7 @@ namespace sat { } void elim_eqs::operator()(literal_vector const & roots, bool_var_vector const & to_elim) { + TRACE("elim_eqs", tout << "before bin cleanup\n"; m_solver.display(tout);); cleanup_bin_watches(roots); TRACE("elim_eqs", tout << "after bin cleanup\n"; m_solver.display(tout);); cleanup_clauses(roots, m_solver.m_clauses); @@ -232,5 +233,6 @@ namespace sat { save_elim(roots, to_elim); m_solver.propagate(false); SASSERT(check_clauses(roots)); + TRACE("elim_eqs", tout << "after full cleanup\n"; m_solver.display(tout);); } }; diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 5e5f49eb4..1b5f09e4d 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -72,9 +72,12 @@ namespace sat { void local_search::init_cur_solution() { for (unsigned v = 0; v < num_vars(); ++v) { // use bias with a small probability - if (m_rand() % 100 < 2) { + if (m_rand() % 10 < 5) { m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); } + else { + m_vars[v].m_value = (m_rand() % 2) == 0; + } } } @@ -449,7 +452,6 @@ namespace sat { m_best_unsat_rate = 1; m_last_best_unsat_rate = 1; - reinit(); timer timer; timer.start(); @@ -457,20 +459,23 @@ namespace sat { PROGRESS(tries, total_flips); for (tries = 1; !m_unsat_stack.empty() && m_limit.inc(); ++tries) { - if (m_unsat_stack.size() < m_best_unsat) { - m_best_unsat = m_unsat_stack.size(); - m_last_best_unsat_rate = m_best_unsat_rate; - m_best_unsat_rate = (double)m_unsat_stack.size() / num_constraints(); - } for (step = 0; step < m_max_steps && !m_unsat_stack.empty(); ++step) { pick_flip_walksat(); + if (m_unsat_stack.size() < m_best_unsat) { + m_best_unsat = m_unsat_stack.size(); + m_last_best_unsat_rate = m_best_unsat_rate; + m_best_unsat_rate = (double)m_unsat_stack.size() / num_constraints(); + } } total_flips += step; PROGRESS(tries, total_flips); - if (m_par && tries % 1 == 0) { - m_par->get_phase(*this); + if (m_par && m_par->get_phase(*this)) { reinit(); } + if (tries % 10 == 0 && !m_unsat_stack.empty()) { + reinit(); + } + } } @@ -490,7 +495,10 @@ namespace sat { if (m_best_objective_value >= m_best_known_value) { break; } - } + } + if (m_unsat_stack.size() < m_best_unsat) { + m_best_unsat = m_unsat_stack.size(); + } flipvar = pick_var_gsat(); flip_gsat(flipvar); m_vars[flipvar].m_time_stamp = step++; @@ -563,6 +571,9 @@ namespace sat { unsigned num_unsat = m_unsat_stack.size(); constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; SASSERT(c.m_k < constraint_value(c)); + unsigned reflipped = 0; + bool is_core = m_unsat_stack.size() <= 10; + reflip: // TBD: dynamic noise strategy //if (m_rand() % 100 < 98) { if (m_rand() % 10000 <= m_noise) { @@ -635,6 +646,10 @@ namespace sat { } } flip_walksat(best_var); + if (false && is_core && c.m_k < constraint_value(c)) { + ++reflipped; + goto reflip; + } } void local_search::flip_walksat(bool_var flipvar) { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index b0483c5b9..475bd5f25 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -21,17 +21,13 @@ #include "util/vector.h" #include "sat/sat_types.h" +#include "sat/sat_config.h" #include "util/rlimit.h" namespace sat { class parallel; - enum local_search_mode { - gsat, - wsat - }; - class local_search_config { unsigned m_seed; unsigned m_strategy_id; diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 462439499..8e50a1f91 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -229,7 +229,6 @@ namespace sat { break; } } - IF_VERBOSE(1, verbose_stream() << "set phase: " << m_num_clauses << " " << s.m_clauses.size() << " " << m_solver_copy << "\n";); } if (m_consumer_ready && (m_num_clauses == 0 || (m_num_clauses > s.m_clauses.size()))) { // time to update local search with new clauses. @@ -268,10 +267,13 @@ namespace sat { } } - void parallel::get_phase(local_search& s) { + bool parallel::get_phase(local_search& s) { + bool copied = false; #pragma omp critical (par_solver) { + m_consumer_ready = true; if (m_solver_copy && s.num_non_binary_clauses() > m_solver_copy->m_clauses.size()) { + copied = true; s.import(*m_solver_copy.get(), true); } for (unsigned i = 0; i < m_phase.size(); ++i) { @@ -280,6 +282,7 @@ namespace sat { } m_phase.reserve(s.num_vars(), l_undef); } + return copied; } void parallel::set_phase(local_search& s) { diff --git a/src/sat/sat_parallel.h b/src/sat/sat_parallel.h index f37c99151..256623380 100644 --- a/src/sat/sat_parallel.h +++ b/src/sat/sat_parallel.h @@ -106,7 +106,7 @@ namespace sat { void set_phase(local_search& s); - void get_phase(local_search& s); + bool get_phase(local_search& s); bool copy_solver(solver& s); }; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index c702941f6..7f6d1f718 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -38,6 +38,7 @@ def_module_params('sat', ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), ('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'), ('unit_walk', BOOL, False, 'use unit-walk search instead of CDCL'), ('unit_walk_threads', UINT, 0, 'number of unit-walk search threads to find satisfiable solution'), ('lookahead.cube.cutoff', SYMBOL, 'adaptive_freevars', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 3010c92f2..7821b32ca 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -232,6 +232,7 @@ namespace sat { if (m_scc_tr) { reduce_tr(); } + TRACE("scc_detail", m_solver.display(tout);); return to_elim.size(); } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index c52b36417..be0222d3b 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -198,7 +198,7 @@ namespace sat { initialize(); CASSERT("sat_solver", s.check_invariant()); - TRACE("before_simplifier", s.display(tout);); + TRACE("sat_simplifier", s.display(tout);); s.m_cleaner(true); TRACE("after_cleanup", s.display(tout);); @@ -254,7 +254,7 @@ namespace sat { } CASSERT("sat_solver", s.check_invariant()); - TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); + TRACE("sat_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); finalize(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8c7450a61..4f2752fe6 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -332,6 +332,14 @@ namespace sat { } void solver::mk_bin_clause(literal l1, literal l2, bool learned) { + if (find_binary_watch(get_wlist(~l1), ~l2)) { + assign(l1, justification()); + return; + } + if (find_binary_watch(get_wlist(~l2), ~l1)) { + assign(l2, justification()); + return; + } watched* w0 = find_binary_watch(get_wlist(~l1), l2); if (w0) { if (w0->is_learned() && !learned) { @@ -355,7 +363,7 @@ namespace sat { } m_stats.m_mk_bin_clause++; get_wlist(~l1).push_back(watched(l2, learned)); - get_wlist(~l2).push_back(watched(l1, learned)); + get_wlist(~l2).push_back(watched(l1, learned)); } bool solver::propagate_bin_clause(literal l1, literal l2) { @@ -1023,6 +1031,7 @@ namespace sat { scoped_limits scoped_rl(rlimit()); local_search srch; srch.config().set_seed(m_config.m_random_seed); + srch.config().set_mode(m_config.m_local_search_mode); srch.import(*this, false); scoped_rl.push_child(&srch.rlimit()); lbool r = srch.check(num_lits, lits, 0); @@ -1047,6 +1056,7 @@ namespace sat { for (int i = 0; i < num_local_search; ++i) { local_search* l = alloc(local_search); l->config().set_seed(m_config.m_random_seed + i); + l->config().set_mode(m_config.m_local_search_mode); l->import(*this, false); ls.push_back(l); } @@ -1095,7 +1105,7 @@ namespace sat { r = par.get_solver(i).check(num_lits, lits); } else if (IS_LOCAL_SEARCH(i)) { - r = ls[i-local_search_offset]->check(num_lits, lits); + r = ls[i-local_search_offset]->check(num_lits, lits, &par); } else if (IS_UNIT_WALK(i)) { r = uw[i-unit_walk_offset]->check(num_lits, lits); @@ -1519,9 +1529,9 @@ namespace sat { m_scc(); CASSERT("sat_simplify_bug", check_invariant()); - - + m_simplifier(false); + CASSERT("sat_simplify_bug", check_invariant()); CASSERT("sat_missed_prop", check_missed_propagation()); if (!m_learned.empty()) { @@ -1536,6 +1546,7 @@ namespace sat { CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); m_asymm_branch(false); + CASSERT("sat_missed_prop", check_missed_propagation()); CASSERT("sat_simplify_bug", check_invariant()); if (m_ext) { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 0f74fac8b..ed8f48762 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -60,7 +60,8 @@ class inc_sat_solver : public solver { sat::literal_vector m_asms; goal_ref_buffer m_subgoals; proof_converter_ref m_pc; - mutable model_converter_ref m_mc0; + sref_vector m_mcs; + mutable model_converter_ref m_mc0; // TBD: should be saved/retained under push/pop mutable obj_hashtable m_inserted_const2bits; mutable ref m_sat_mc; mutable model_converter_ref m_cached_mc; @@ -88,6 +89,7 @@ public: m_internalized_converted(false), m_internalized_fmls(m) { updt_params(p); + m_mcs.push_back(nullptr); init_preprocess(); m_solver.set_incremental(incremental_mode && !override_incremental()); } @@ -119,7 +121,7 @@ public: for (unsigned a : m_asms_lim) result->m_asms_lim.push_back(a); for (unsigned h : m_fmls_head_lim) result->m_fmls_head_lim.push_back(h); for (expr* f : m_internalized_fmls) result->m_internalized_fmls.push_back(tr(f)); - if (m_mc0) result->m_mc0 = m_mc0->translate(tr); + if (m_mcs.back()) result->m_mcs.push_back(m_mcs.back()->translate(tr)); if (m_sat_mc) result->m_sat_mc = dynamic_cast(m_sat_mc->translate(tr)); // copy m_bb_rewriter? result->m_internalized_converted = m_internalized_converted; @@ -186,6 +188,7 @@ public: if (r != l_true) return r; init_reason_unknown(); + m_internalized_converted = false; try { // IF_VERBOSE(0, m_solver.display(verbose_stream())); r = m_solver.check(m_asms.size(), m_asms.c_ptr()); @@ -217,6 +220,7 @@ public: internalize_formulas(); m_solver.user_push(); ++m_num_scopes; + m_mcs.push_back(m_mcs.back()); m_fmls_lim.push_back(m_fmls.size()); m_asms_lim.push_back(m_asmsf.size()); m_fmls_head_lim.push_back(m_fmls_head); @@ -234,7 +238,9 @@ public: SASSERT(n <= m_num_scopes); m_solver.user_pop(n); m_num_scopes -= n; + // ? m_internalized_converted = false; while (n > 0) { + m_mcs.pop_back(); m_fmls_head = m_fmls_head_lim.back(); m_fmls.resize(m_fmls_lim.back()); m_fmls_lim.pop_back(); @@ -448,12 +454,10 @@ public: if (m_cached_mc) return m_cached_mc; if (is_internalized() && m_internalized_converted) { - insert_const2bits(); m_sat_mc->flush_smc(m_solver, m_map); - m_cached_mc = m_mc0.get(); + m_cached_mc = m_mcs.back(); m_cached_mc = concat(solver::get_model_converter().get(), m_cached_mc.get()); m_cached_mc = concat(m_cached_mc.get(), m_sat_mc.get()); - // IF_VERBOSE(0, m_cached_mc->display(verbose_stream() << "get-model-converter\n");); return m_cached_mc; } else { @@ -493,12 +497,10 @@ public: simp2_p.set_bool("elim_and", true); simp2_p.set_bool("blast_distinct", true); m_preprocess = - and_then(mk_card2bv_tactic(m, m_params), + and_then(mk_card2bv_tactic(m, m_params), // updates model converter using_params(mk_simplify_tactic(m), simp2_p), mk_max_bv_sharing_tactic(m), - mk_bit_blaster_tactic(m, m_bb_rewriter.get()), - //mk_aig_tactic(), - //mk_propagate_values_tactic(m, simp2_p), + mk_bit_blaster_tactic(m, m_bb_rewriter.get()), // updates model converter using_params(mk_simplify_tactic(m), simp2_p)); while (m_bb_rewriter->get_num_scopes() < m_num_scopes) { m_bb_rewriter->push(); @@ -508,22 +510,6 @@ public: private: - void insert_const2bits() const { - if (!m_bb_rewriter) return; - obj_map to_insert; - obj_map const& const2bits = m_bb_rewriter->const2bits(); - for (auto const& kv : const2bits) { - if (!m_inserted_const2bits.contains(kv.m_key)) { - m_inserted_const2bits.insert(kv.m_key); - to_insert.insert(kv.m_key, kv.m_value); - } - } - if (!to_insert.empty()) { - m_mc0 = concat(m_mc0.get(), mk_bit_blaster_model_converter(m, to_insert)); - } - } - - lbool internalize_goal(goal_ref& g, dep2asm_t& dep2asm, bool is_lemma) { m_pc.reset(); m_subgoals.reset(); @@ -543,15 +529,15 @@ private: m_preprocess = 0; m_bb_rewriter = 0; return l_undef; - } + } if (m_subgoals.size() != 1) { - IF_VERBOSE(0, verbose_stream() << "size of subgoals is not 1, it is: " << m_subgoals.size() << "\n";); + IF_VERBOSE(0, verbose_stream() << "size of subgoals is not 1, it is: " << m_subgoals.size() << "\n"); return l_undef; } g = m_subgoals[0]; expr_ref_vector atoms(m); m_pc = g->pc(); - m_mc0 = concat(m_mc0.get(), g->mc()); + m_mcs.set(m_mcs.size()-1, concat(m_mcs.back(), g->mc())); TRACE("sat", g->display_with_dependencies(tout);); // ensure that if goal is already internalized, then import mc from m_solver. @@ -591,8 +577,8 @@ private: } lbool internalize_vars(expr_ref_vector const& vars, sat::bool_var_vector& bvars) { - for (unsigned i = 0; i < vars.size(); ++i) { - internalize_var(vars[i], bvars); + for (expr* v : vars) { + internalize_var(v, bvars); } return l_true; } @@ -604,7 +590,6 @@ private: bool internalized = false; if (is_uninterp_const(v) && m.is_bool(v)) { sat::bool_var b = m_map.to_bool_var(v); - if (b != sat::null_bool_var) { bvars.push_back(b); internalized = true; @@ -614,10 +599,9 @@ private: SASSERT(bvutil.is_bv(bv)); app* abv = to_app(bv); internalized = true; - unsigned sz = abv->get_num_args(); - for (unsigned j = 0; j < sz; ++j) { - SASSERT(is_uninterp_const(abv->get_arg(j))); - sat::bool_var b = m_map.to_bool_var(abv->get_arg(j)); + for (expr* arg : *abv) { + SASSERT(is_uninterp_const(arg)); + sat::bool_var b = m_map.to_bool_var(arg); if (b == sat::null_bool_var) { internalized = false; } @@ -625,7 +609,7 @@ private: bvars.push_back(b); } } - CTRACE("sat", internalized, tout << "var: "; for (unsigned j = 0; j < sz; ++j) tout << bvars[bvars.size()-sz+j] << " "; tout << "\n";); + CTRACE("sat", internalized, tout << "var: " << bvars << "\n";); } else if (is_uninterp_const(v) && bvutil.is_bv(v)) { // variable does not occur in assertions, so is unconstrained. @@ -813,18 +797,18 @@ private: //IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "satmc\n");); (*m_sat_mc)(mdl); } - insert_const2bits(); - if (m_mc0) { + if (m_mcs.back()) { //IF_VERBOSE(0, m_mc0->display(verbose_stream() << "mc0\n");); - (*m_mc0)(mdl); + (*m_mcs.back())(mdl); } TRACE("sat", model_smt2_pp(tout, m, *mdl, 0);); // IF_VERBOSE(0, model_smt2_pp(verbose_stream() << "after\n", m, *mdl, 0);); #if 0 - IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); + IF_VERBOSE(0, verbose_streamm() << "Verifying solution\n";); model_evaluator eval(*mdl); + bool all_true = true; for (expr * f : m_fmls) { expr_ref tmp(m); eval(f, tmp); @@ -833,13 +817,20 @@ private: model_smt2_pp(tout, m, *(mdl.get()), 0);); if (!m.is_true(tmp)) { IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n";); - IF_VERBOSE(0, verbose_stream() << m_params << "\n";); - IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "sat mc\n");); - IF_VERBOSE(0, if (m_mc0) m_mc0->display(verbose_stream() << "mc0\n");); - break; + all_true = false; + } + else { + VERIFY(m.is_true(tmp)); } - VERIFY(m.is_true(tmp)); } + if (!all_true) { + IF_VERBOSE(0, verbose_stream() << m_params << "\n";); + IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "sat mc\n");); + IF_VERBOSE(0, if (m_mcs.back()) m_mcs.back()->display(verbose_stream() << "mc0\n");); + //IF_VERBOSE(0, m_solver.display(verbose_stream())); + IF_VERBOSE(0, for (auto const& kv : m_map) verbose_stream() << mk_pp(kv.m_key, m) << " |-> " << kv.m_value << "\n";); + } + #endif } }; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 7323dc6b8..305bed175 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -573,28 +573,6 @@ struct goal2sat::imp { void convert_eq_k(app* t, rational const& k, bool root, bool sign) { SASSERT(k.is_unsigned()); -#if 0 - IF_VERBOSE(0, verbose_stream() << t->get_id() << ": " << mk_pp(t, m) << "\n";); - svector wlits; - convert_pb_args(t, wlits); - if (root && !sign) { - m_ext->add_eq(sat::null_literal, wlits, k.get_unsigned()); - m_result_stack.reset(); - } - else { - sat::bool_var v = m_solver.mk_var(); - sat::literal l(v, false); - m_ext->add_eq(l, wlits, k.get_unsigned()); - m_result_stack.shrink(m_result_stack.size() - t->get_num_args()); - m_cache.insert(t, l); - if (sign) l.neg(); - m_result_stack.push_back(l); - if (root) { - mk_clause(l); - m_result_stack.reset(); - } - } -#else sat::literal_vector lits; convert_pb_args(t->get_num_args(), lits); sat::bool_var v1 = (root && !sign) ? sat::null_bool_var : m_solver.mk_var(true); @@ -625,7 +603,6 @@ struct goal2sat::imp { m_result_stack.reset(); } } -#endif } void ensure_extension() { diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 989427ee7..39300b7dc 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -62,6 +62,7 @@ class bit_blaster_tactic : public tactic { TRACE("before_bit_blaster", g->display(tout);); m_num_steps = 0; + m_rewriter->start_rewrite(); expr_ref new_curr(m()); proof_ref new_pr(m()); unsigned size = g->size(); @@ -78,13 +79,16 @@ class bit_blaster_tactic : public tactic { } if (curr != new_curr) { change = true; - TRACE("bit_blaster", tout << mk_pp(curr, m()) << " -> " << mk_pp(new_curr, m()) << "\n";); + TRACE("bit_blaster", tout << mk_pp(curr, m()) << " -> " << new_curr << "\n";); g->update(idx, new_curr, new_pr, g->dep(idx)); } } - if (change && g->models_enabled()) - g->add(mk_bit_blaster_model_converter(m(), m_rewriter->const2bits())); + if (change && g->models_enabled()) { + obj_map const2bits; + m_rewriter->end_rewrite(const2bits); + g->add(mk_bit_blaster_model_converter(m(), const2bits)); + } g->inc_depth(); result.push_back(g.get()); TRACE("after_bit_blaster", g->display(tout); if (g->mc()) g->mc()->display(tout); tout << "\n";); @@ -148,6 +152,7 @@ public: return m_imp->get_num_steps(); } + }; @@ -158,3 +163,4 @@ tactic * mk_bit_blaster_tactic(ast_manager & m, params_ref const & p) { tactic * mk_bit_blaster_tactic(ast_manager & m, bit_blaster_rewriter* rw, params_ref const & p) { return clean(alloc(bit_blaster_tactic, m, rw, p)); } + From 75ba65a18a319ad6d7d2ca41dafc286962fe1f7f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Feb 2018 01:46:35 -0800 Subject: [PATCH 0586/1283] working on propagation with undef main literal Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index d1a0c7403..3ef422d6a 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1647,6 +1647,7 @@ namespace sat { return true; } else if (c.lit() != null_literal && value(c.lit()) != l_true) { + // else if (c.lit() != null_literal && value(c.lit()) == l_false) { return true; } else { @@ -1954,6 +1955,13 @@ namespace sat { } void ba_solver::get_antecedents(literal l, card const& c, literal_vector& r) { + if (l == ~c.lit()) { + for (unsigned i = c.k() - 1; i < c.size(); ++i) { + VERIFY(value(c[i]) == l_false); + r.push_back(~c[i]); + } + return; + } DEBUG_CODE( bool found = false; for (unsigned i = 0; !found && i < c.k(); ++i) { @@ -1962,7 +1970,7 @@ namespace sat { SASSERT(found);); // IF_VERBOSE(0, if (_debug_conflict) verbose_stream() << "ante " << l << " " << c << "\n"); - SASSERT(c.lit() == null_literal || value(c.lit()) != l_false); + VERIFY(c.lit() == null_literal || value(c.lit()) != l_false); if (c.lit() != null_literal) r.push_back(value(c.lit()) == l_true ? c.lit() : ~c.lit()); for (unsigned i = c.k(); i < c.size(); ++i) { SASSERT(value(c[i]) == l_false); @@ -2349,7 +2357,7 @@ namespace sat { return l_false; } SASSERT(value(alit) == l_false); - SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); + VERIFY(c.lit() == null_literal || value(c.lit()) != l_false); unsigned index = 0; for (index = 0; index <= bound; ++index) { if (c[index] == alit) { @@ -2377,6 +2385,7 @@ namespace sat { if (bound != index && value(c[bound]) == l_false) { TRACE("ba", tout << "conflict " << c[bound] << " " << alit << "\n";); if (c.lit() != null_literal && value(c.lit()) == l_undef) { + if (index + 1 < bound) c.swap(index, bound - 1); assign(c, ~c.lit()); return inconsistent() ? l_false : l_true; } @@ -2384,14 +2393,15 @@ namespace sat { return l_false; } + if (index != bound) { + c.swap(index, bound); + } + // TRACE("ba", tout << "no swap " << index << " " << alit << "\n";); // there are no literals to swap with, // prepare for unit propagation by swapping the false literal into // position bound. Then literals in positions 0..bound-1 have to be // assigned l_true. - if (index != bound) { - c.swap(index, bound); - } if (c.lit() != null_literal && value(c.lit()) == l_undef) { return l_true; From 7b91195770479fd4d9e85ffa3d4fc702ad26e3e0 Mon Sep 17 00:00:00 2001 From: Angus Lepper Date: Tue, 20 Feb 2018 19:37:17 +0000 Subject: [PATCH 0587/1283] Fix Python FiniteDomainSortRef.size() --- src/api/python/z3/z3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 641dba59c..c8ad4e0b4 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6818,8 +6818,8 @@ class FiniteDomainSortRef(SortRef): def size(self): """Return the size of the finite domain sort""" - r = (ctype.c_ulonglong * 1)() - if Z3_get_finite_domain_sort_size(self.ctx_ref(), self.ast(), r): + r = (ctypes.c_ulonglong * 1)() + if Z3_get_finite_domain_sort_size(self.ctx_ref(), self.ast, r): return r[0] else: raise Z3Exception("Failed to retrieve finite domain sort size") From 54b00f357b8cd1277058fc1c6d88c5d7ebf977b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2018 21:57:54 +0900 Subject: [PATCH 0588/1283] fix rule inlining, add WithParams to pass parameters directly to python API Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 14 +++++++++ src/muz/transforms/dl_mk_rule_inliner.cpp | 38 +++++++---------------- src/muz/transforms/dl_transforms.cpp | 20 ++++++------ 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 641dba59c..d303b477d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7447,6 +7447,20 @@ def With(t, *args, **keys): p = args2params(args, keys, t.ctx) return Tactic(Z3_tactic_using_params(t.ctx.ref(), t.tactic, p.params), t.ctx) +def WithParams(t, p): + """Return a tactic that applies tactic `t` using the given configuration options. + + >>> x, y = Ints('x y') + >>> p = ParamsRef() + >>> p.set("som", True) + >>> t = With(Tactic('simplify'), p) + >>> t((x + 1)*(y + 2) == 0) + [[2*x + y + x*y == -2]] + """ + ctx = keys.pop('ctx', None) + t = _to_tactic(t, ctx) + return Tactic(Z3_tactic_using_params(t.ctx.ref(), t.tactic, p.params), t.ctx) + def Repeat(t, max=4294967295, ctx=None): """Return a tactic that keeps applying `t` until the goal is not modified anymore or the maximum number of iterations `max` is reached. diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index a9d2c7090..4088d607c 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -410,15 +410,11 @@ namespace datalog { const rule_stratifier::comp_vector& comps = candidate_inlined_set->get_stratifier().get_strats(); rule_stratifier::comp_vector::const_iterator cend = comps.end(); - for (rule_stratifier::comp_vector::const_iterator it = comps.begin(); it!=cend; ++it) { - rule_stratifier::item_set * stratum = *it; + for (rule_stratifier::item_set * stratum : comps) { SASSERT(stratum->size()==1); func_decl * pred = *stratum->begin(); - - const rule_vector& pred_rules = candidate_inlined_set->get_predicate_rules(pred); - rule_vector::const_iterator iend = pred_rules.end(); - for (rule_vector::const_iterator iit = pred_rules.begin(); iit!=iend; ++iit) { - transform_rule(orig, *iit, m_inlined_rules); + for (rule * r : candidate_inlined_set->get_predicate_rules(pred)) { + transform_rule(orig, r, m_inlined_rules); } } @@ -426,7 +422,7 @@ namespace datalog { for (unsigned i = 0; i < m_inlined_rules.get_num_rules(); ++i) { rule* r = m_inlined_rules.get_rule(i); - datalog::del_rule(m_mc, *r, true); + datalog::del_rule(m_mc, *r, false); } } @@ -455,9 +451,7 @@ namespace datalog { func_decl * pred = r->get_decl(i); const rule_vector& pred_rules = m_inlined_rules.get_predicate_rules(pred); - rule_vector::const_iterator iend = pred_rules.end(); - for (rule_vector::const_iterator iit = pred_rules.begin(); iit!=iend; ++iit) { - rule * inl_rule = *iit; + for (rule * inl_rule : pred_rules) { rule_ref inl_result(m_rm); if (try_to_inline_rule(*r.get(), *inl_rule, i, inl_result)) { todo.push_back(inl_result); @@ -475,9 +469,8 @@ namespace datalog { bool something_done = false; - rule_set::iterator rend = orig.end(); - for (rule_set::iterator rit = orig.begin(); rit!=rend; ++rit) { - rule_ref r(*rit, m_rm); + for (rule* rl : orig) { + rule_ref r(rl, m_rm); func_decl * pred = r->get_decl(); // if inlining is allowed, then we are eliminating @@ -508,15 +501,10 @@ namespace datalog { bool mk_rule_inliner::is_oriented_rewriter(rule * r, rule_stratifier const& strat) { func_decl * head_pred = r->get_decl(); unsigned head_strat = strat.get_predicate_strat(head_pred); - unsigned head_arity = head_pred->get_arity(); - - unsigned pt_len = r->get_positive_tail_size(); - for (unsigned ti=0; tiget_decl(ti); - unsigned pred_strat = strat.get_predicate_strat(pred); SASSERT(pred_strat<=head_strat); @@ -855,13 +843,9 @@ namespace datalog { return nullptr; } - rule_set::iterator end = source.end(); - for (rule_set::iterator it = source.begin(); it != end; ++ it) { - if (has_quantifier(**it)) { - return nullptr; - } - } - + for (rule const* r : source) + if (has_quantifier(*r)) + return nullptr; if (m_context.get_model_converter()) { hsmc = alloc(horn_subsume_model_converter, m); diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp index 95b0f6cd6..d456d95f9 100644 --- a/src/muz/transforms/dl_transforms.cpp +++ b/src/muz/transforms/dl_transforms.cpp @@ -59,7 +59,7 @@ namespace datalog { transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, ctx, 37000)); if (ctx.get_params().datalog_subsumption()) { - transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 35005)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 35005)); } transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 35000)); transf.register_plugin(alloc(datalog::mk_coi_filter, ctx, 34990)); @@ -67,20 +67,20 @@ namespace datalog { //and another round of inlining if (ctx.get_params().datalog_subsumption()) { - transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34975)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34975)); } transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34970)); transf.register_plugin(alloc(datalog::mk_coi_filter, ctx, 34960)); transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx, 34950)); - + if (ctx.get_params().datalog_subsumption()) { - transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34940)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34930)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34920)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34910)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34900)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34890)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34880)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34940)); + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34930)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34920)); + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34910)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34900)); + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34890)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34880)); } else { transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34930)); From 7b6f51941c8bee3a8b2da29ea9ffaecd25f428dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2018 22:18:47 +0900 Subject: [PATCH 0589/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- src/muz/transforms/dl_mk_rule_inliner.cpp | 17 ++++------------- src/util/lp/permutation_matrix.h | 10 +++++----- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index d303b477d..fbe112e4c 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7453,7 +7453,7 @@ def WithParams(t, p): >>> x, y = Ints('x y') >>> p = ParamsRef() >>> p.set("som", True) - >>> t = With(Tactic('simplify'), p) + >>> t = WithParams(Tactic('simplify'), p) >>> t((x + 1)*(y + 2) == 0) [[2*x + y + x*y == -2]] """ diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 4088d607c..b1f222f6e 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -210,8 +210,7 @@ namespace datalog { } rule_set::iterator rend = orig.end(); - for (rule_set::iterator rit = orig.begin(); rit!=rend; ++rit) { - rule * r = *rit; + for (rule * r : orig) { func_decl * head_pred = r->get_decl(); m_head_pred_ctr.inc(head_pred); @@ -283,9 +282,7 @@ namespace datalog { const rule_stratifier::comp_vector& comps = r.get_stratifier().get_strats(); - rule_stratifier::comp_vector::const_iterator cend = comps.end(); - for (rule_stratifier::comp_vector::const_iterator it = comps.begin(); it!=cend; ++it) { - rule_stratifier::item_set * stratum = *it; + for (rule_stratifier::item_set * stratum : comps) { if (stratum->size()==1) { continue; } @@ -307,9 +304,7 @@ namespace datalog { const rule_stratifier::comp_vector& comps = proposed_inlined_rules.get_stratifier().get_strats(); - rule_stratifier::comp_vector::const_iterator cend = comps.end(); - for (rule_stratifier::comp_vector::const_iterator it = comps.begin(); it!=cend; ++it) { - rule_stratifier::item_set * stratum = *it; + for (rule_stratifier::item_set * stratum : comps) { SASSERT(stratum->size()==1); func_decl * head_pred = *stratum->begin(); @@ -318,10 +313,7 @@ namespace datalog { bool is_multi_occurrence_pred = m_tail_pred_ctr.get(head_pred)>1; const rule_vector& pred_rules = proposed_inlined_rules.get_predicate_rules(head_pred); - rule_vector::const_iterator iend = pred_rules.end(); - for (rule_vector::const_iterator iit = pred_rules.begin(); iit!=iend; ++iit) { - rule * r = *iit; - + for (rule * r : pred_rules) { unsigned pt_len = r->get_positive_tail_size(); for (unsigned ti = 0; tiget_decl(ti); @@ -409,7 +401,6 @@ namespace datalog { const rule_stratifier::comp_vector& comps = candidate_inlined_set->get_stratifier().get_strats(); - rule_stratifier::comp_vector::const_iterator cend = comps.end(); for (rule_stratifier::item_set * stratum : comps) { SASSERT(stratum->size()==1); func_decl * pred = *stratum->begin(); diff --git a/src/util/lp/permutation_matrix.h b/src/util/lp/permutation_matrix.h index f080d45b9..3c89b3646 100644 --- a/src/util/lp/permutation_matrix.h +++ b/src/util/lp/permutation_matrix.h @@ -109,13 +109,13 @@ class permutation_matrix : public tail_matrix { void transpose_from_right(unsigned i, unsigned j); #ifdef Z3DEBUG - T get_elem(unsigned i, unsigned j) const{ + T get_elem(unsigned i, unsigned j) const override { return m_permutation[i] == j? numeric_traits::one() : numeric_traits::zero(); } - unsigned row_count() const{ return size(); } - unsigned column_count() const { return size(); } - virtual void set_number_of_rows(unsigned /*m*/) { } - virtual void set_number_of_columns(unsigned /*n*/) { } + unsigned row_count() const override { return size(); } + unsigned column_count() const override { return size(); } + void set_number_of_rows(unsigned /*m*/) override { } + void set_number_of_columns(unsigned /*n*/) override { } #endif void multiply_by_permutation_from_left(permutation_matrix & p); From 24f56fd74c87c6678ccff9a72e412acf6c0a1fed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2018 22:29:22 +0900 Subject: [PATCH 0590/1283] try another build fix Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 3 +-- src/util/lp/eta_matrix.h | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index fbe112e4c..dbf1252af 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7457,8 +7457,7 @@ def WithParams(t, p): >>> t((x + 1)*(y + 2) == 0) [[2*x + y + x*y == -2]] """ - ctx = keys.pop('ctx', None) - t = _to_tactic(t, ctx) + t = _to_tactic(t, None) return Tactic(Z3_tactic_using_params(t.ctx.ref(), t.tactic, p.params), t.ctx) def Repeat(t, max=4294967295, ctx=None): diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index 7224fa846..89d2e641d 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -83,12 +83,12 @@ public: void apply_from_right(vector & w) override; void apply_from_right(indexed_vector & w) override; - T get_elem(unsigned i, unsigned j) const; + T get_elem(unsigned i, unsigned j) const override; #ifdef Z3DEBUG - unsigned row_count() const { return m_length; } - unsigned column_count() const { return m_length; } - void set_number_of_rows(unsigned m) { m_length = m; } - void set_number_of_columns(unsigned n) { m_length = n; } + unsigned row_count() const override { return m_length; } + unsigned column_count() const override { return m_length; } + void set_number_of_rows(unsigned m) override { m_length = m; } + void set_number_of_columns(unsigned n) override { m_length = n; } #endif void divide_by_diagonal_element() { m_column_vector.divide(m_diagonal_element); From 763c250734f3fff0226e7e9b3b4775850143f9e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2018 22:33:44 +0900 Subject: [PATCH 0591/1283] try another build fix Signed-off-by: Nikolaj Bjorner --- src/util/lp/eta_matrix.h | 2 +- src/util/lp/sparse_matrix.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index 89d2e641d..eee4a2674 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -83,7 +83,7 @@ public: void apply_from_right(vector & w) override; void apply_from_right(indexed_vector & w) override; - T get_elem(unsigned i, unsigned j) const override; + T get_elem(unsigned i, unsigned j) const; #ifdef Z3DEBUG unsigned row_count() const override { return m_length; } unsigned column_count() const override { return m_length; } diff --git a/src/util/lp/sparse_matrix.h b/src/util/lp/sparse_matrix.h index 400f2bfc0..7db526bdd 100644 --- a/src/util/lp/sparse_matrix.h +++ b/src/util/lp/sparse_matrix.h @@ -302,11 +302,11 @@ public: 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 { return get(i, j); } - unsigned get_number_of_rows() const { return dimension(); } - unsigned get_number_of_columns() const { return dimension(); } - virtual void set_number_of_rows(unsigned /*m*/) { } - virtual void set_number_of_columns(unsigned /*n*/) { } + T get_elem(unsigned i, unsigned j) const override { return get(i, j); } + unsigned get_number_of_rows() const override { return dimension(); } + unsigned get_number_of_columns() const override { return dimension(); } + virtual void set_number_of_rows(unsigned /*m*/) override { } + virtual void set_number_of_columns(unsigned /*n*/) override { } #endif template L dot_product_with_row (unsigned row, const vector & y) const; From d70ee71a433f4176b786b48192244cc13958881a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2018 22:38:10 +0900 Subject: [PATCH 0592/1283] try another build fix Signed-off-by: Nikolaj Bjorner --- src/util/lp/sparse_matrix.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util/lp/sparse_matrix.h b/src/util/lp/sparse_matrix.h index 7db526bdd..400f2bfc0 100644 --- a/src/util/lp/sparse_matrix.h +++ b/src/util/lp/sparse_matrix.h @@ -302,11 +302,11 @@ public: 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 override { return dimension(); } - unsigned get_number_of_columns() const override { return dimension(); } - virtual void set_number_of_rows(unsigned /*m*/) override { } - virtual void set_number_of_columns(unsigned /*n*/) override { } + T get_elem(unsigned i, unsigned j) const { return get(i, j); } + unsigned get_number_of_rows() const { return dimension(); } + unsigned get_number_of_columns() const { return dimension(); } + virtual void set_number_of_rows(unsigned /*m*/) { } + virtual void set_number_of_columns(unsigned /*n*/) { } #endif template L dot_product_with_row (unsigned row, const vector & y) const; From a4c58ec4c21b5fcb082b3ce5044e756ea7bcd38d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2018 08:05:28 +0900 Subject: [PATCH 0593/1283] fix #1496 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 4 +--- src/ast/seq_decl_plugin.cpp | 8 ++------ src/muz/pdr/pdr_context.cpp | 8 ++++---- src/util/lp/dense_matrix.h | 4 ++-- src/util/lp/lu.h | 4 ++-- src/util/lp/sparse_matrix.h | 4 ++-- 6 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 387e5d6f2..89840ea43 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1475,9 +1475,7 @@ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) { return BR_DONE; } if (m_util.re.is_full_char(a)) { - sort* seq_sort = nullptr; - VERIFY(m_util.is_re(a, seq_sort)); - result = m_util.re.mk_full_seq(seq_sort); + result = m_util.re.mk_full_seq(m().get_sort(a)); return BR_DONE; } if (m_util.re.is_empty(a)) { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 91aeeac3b..c9dbc78f8 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -671,9 +671,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k)); case _OP_REGEXP_FULL_CHAR: - if (!range) { - range = m_re; - } + if (!range) range = m_re; match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(symbol("re.allchar"), arity, domain, rng, func_decl_info(m_family_id, OP_RE_FULL_CHAR_SET)); @@ -690,9 +688,7 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, range, func_decl_info(m_family_id, k)); case _OP_REGEXP_EMPTY: - if (!range) { - range = m_re; - } + if (!range) range = m_re; match(*m_sigs[k], arity, domain, range, rng); return m.mk_func_decl(symbol("re.nostr"), arity, domain, rng, func_decl_info(m_family_id, OP_RE_EMPTY_SET)); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 971ec9193..29d01d1f3 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -1736,6 +1736,7 @@ namespace pdr { } void context::validate_model() { + IF_VERBOSE(1, verbose_stream() << "(pdr.validate_model)\n";); std::stringstream msg; expr_ref_vector refs(m); expr_ref tmp(m); @@ -1745,11 +1746,10 @@ namespace pdr { get_level_property(m_inductive_lvl, refs, rs); inductive_property ex(m, mc, rs); ex.to_model(model); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); var_subst vs(m, false); expr_free_vars fv; - for (; it != end; ++it) { - ptr_vector const& rules = it->m_value->rules(); + for (auto const& kv : m_rels) { + ptr_vector const& rules = kv.m_value->rules(); for (unsigned i = 0; i < rules.size(); ++i) { datalog::rule& r = *rules[i]; model->eval(r.get_head(), tmp); @@ -1916,7 +1916,7 @@ namespace pdr { verbose_stream() << ex.to_string(); }); - // upgrade invariants that are known to be inductive. + // upgrade invariants that are known to be inductive. decl2rel::iterator it = m_rels.begin (), end = m_rels.end (); for (; m_inductive_lvl > 0 && it != end; ++it) { if (it->m_value->head() != m_query_pred) { diff --git a/src/util/lp/dense_matrix.h b/src/util/lp/dense_matrix.h index 6b157ffd4..31b6617ac 100644 --- a/src/util/lp/dense_matrix.h +++ b/src/util/lp/dense_matrix.h @@ -79,8 +79,8 @@ public: void apply_from_left_to_X(vector & w, lp_settings & ); - virtual void set_number_of_rows(unsigned /*m*/) {} - virtual void set_number_of_columns(unsigned /*n*/) { } + void set_number_of_rows(unsigned /*m*/) override {} + void set_number_of_columns(unsigned /*n*/) override {} T get_elem(unsigned i, unsigned j) const { return m_values[i * m_n + j]; } diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h index f9432c323..2f9a5ec38 100644 --- a/src/util/lp/lu.h +++ b/src/util/lp/lu.h @@ -74,8 +74,8 @@ public: #ifdef Z3DEBUG unsigned m_m; unsigned m_n; - virtual void set_number_of_rows(unsigned m) { m_m = m; m_n = m; } - virtual void set_number_of_columns(unsigned n) { m_m = n; m_n = n; } + void set_number_of_rows(unsigned m) override { m_m = m; m_n = m; } + void set_number_of_columns(unsigned n) override { m_m = n; m_n = n; } T m_one_over_val; T get_elem (unsigned i, unsigned j) const; diff --git a/src/util/lp/sparse_matrix.h b/src/util/lp/sparse_matrix.h index 400f2bfc0..7649e0983 100644 --- a/src/util/lp/sparse_matrix.h +++ b/src/util/lp/sparse_matrix.h @@ -305,8 +305,8 @@ public: T get_elem(unsigned i, unsigned j) const { return get(i, j); } unsigned get_number_of_rows() const { return dimension(); } unsigned get_number_of_columns() const { return dimension(); } - virtual void set_number_of_rows(unsigned /*m*/) { } - virtual void set_number_of_columns(unsigned /*n*/) { } + 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 919989cfe8e48adf2b4febca5868025d9ea2c8a0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2018 08:39:31 +0900 Subject: [PATCH 0594/1283] fix more warnings with override Signed-off-by: Nikolaj Bjorner --- src/util/lp/eta_matrix.h | 2 +- src/util/lp/sparse_matrix.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index eee4a2674..89d2e641d 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -83,7 +83,7 @@ public: void apply_from_right(vector & w) override; void apply_from_right(indexed_vector & w) override; - T get_elem(unsigned i, unsigned j) const; + T get_elem(unsigned i, unsigned j) const override; #ifdef Z3DEBUG unsigned row_count() const override { return m_length; } unsigned column_count() const override { return m_length; } diff --git a/src/util/lp/sparse_matrix.h b/src/util/lp/sparse_matrix.h index 7649e0983..44111a9fd 100644 --- a/src/util/lp/sparse_matrix.h +++ b/src/util/lp/sparse_matrix.h @@ -162,8 +162,8 @@ public: unsigned dimension() const {return static_cast(m_row_permutation.size());} #ifdef Z3DEBUG - unsigned row_count() const {return dimension();} - unsigned column_count() const {return dimension();} + unsigned row_count() const override {return dimension();} + unsigned column_count() const override {return dimension();} #endif void init_row_headers(); @@ -302,7 +302,7 @@ public: 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 { return get(i, j); } + 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 { } From 6ed95718ce7b7e60b30eb45c2b4b720cb2bffdf5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2018 08:53:17 +0900 Subject: [PATCH 0595/1283] fix more warnings with override Signed-off-by: Nikolaj Bjorner --- src/util/lp/row_eta_matrix.h | 10 +++++----- src/util/lp/square_dense_submatrix.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/util/lp/row_eta_matrix.h b/src/util/lp/row_eta_matrix.h index f6fb4537d..2bc0ac24e 100644 --- a/src/util/lp/row_eta_matrix.h +++ b/src/util/lp/row_eta_matrix.h @@ -79,11 +79,11 @@ public: void conjugate_by_permutation(permutation_matrix & p); #ifdef Z3DEBUG - T get_elem(unsigned row, unsigned col) const; - unsigned row_count() const { return m_dimension; } - unsigned column_count() const { return m_dimension; } - void set_number_of_rows(unsigned m) { m_dimension = m; } - void set_number_of_columns(unsigned n) { m_dimension = n; } + T get_elem(unsigned row, unsigned col) const override; + unsigned row_count() const override { return m_dimension; } + unsigned column_count() const override { return m_dimension; } + void set_number_of_rows(unsigned m) override { m_dimension = m; } + void set_number_of_columns(unsigned n) override { m_dimension = n; } #endif }; // end of row_eta_matrix } diff --git a/src/util/lp/square_dense_submatrix.h b/src/util/lp/square_dense_submatrix.h index a2cade85a..d43b2eadd 100644 --- a/src/util/lp/square_dense_submatrix.h +++ b/src/util/lp/square_dense_submatrix.h @@ -214,11 +214,11 @@ public: void apply_from_right(vector & w) override; #ifdef Z3DEBUG - T get_elem (unsigned i, unsigned j) const; - unsigned row_count() const { return m_parent->row_count();} - unsigned column_count() const { return row_count();} - void set_number_of_rows(unsigned) {} - void set_number_of_columns(unsigned) {}; + T get_elem (unsigned i, unsigned j) const override; + unsigned row_count() const override { return m_parent->row_count();} + unsigned column_count() const override { return row_count();} + void set_number_of_rows(unsigned) override {} + void set_number_of_columns(unsigned) override {} #endif void conjugate_by_permutation(permutation_matrix & q); }; From 41e0a1267854ef698908a1d025989108ad648c05 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2018 09:22:30 +0900 Subject: [PATCH 0596/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/util/lp/eta_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index 89d2e641d..eee4a2674 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -83,7 +83,7 @@ public: void apply_from_right(vector & w) override; void apply_from_right(indexed_vector & w) override; - T get_elem(unsigned i, unsigned j) const override; + T get_elem(unsigned i, unsigned j) const; #ifdef Z3DEBUG unsigned row_count() const override { return m_length; } unsigned column_count() const override { return m_length; } From dbe5df85c303a5b04e1922890d404f79b048e7fd Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 22 Feb 2018 08:44:50 -0800 Subject: [PATCH 0597/1283] fix the override warning Signed-off-by: Lev Nachmanson --- src/util/lp/dense_matrix.h | 6 +++--- src/util/lp/eta_matrix.h | 2 +- src/util/lp/lu.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/util/lp/dense_matrix.h b/src/util/lp/dense_matrix.h index 31b6617ac..e6663d705 100644 --- a/src/util/lp/dense_matrix.h +++ b/src/util/lp/dense_matrix.h @@ -82,10 +82,10 @@ public: void set_number_of_rows(unsigned /*m*/) override {} void set_number_of_columns(unsigned /*n*/) override {} - T get_elem(unsigned i, unsigned j) const { return m_values[i * m_n + j]; } + T get_elem(unsigned i, unsigned j) const override { return m_values[i * m_n + j]; } - unsigned row_count() const { return m_m; } - unsigned column_count() const { return m_n; } + unsigned row_count() const override { return m_m; } + unsigned column_count() const override { return m_n; } void set_elem(unsigned i, unsigned j, const T& val) { m_values[i * m_n + j] = val; } diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index eee4a2674..89d2e641d 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -83,7 +83,7 @@ public: void apply_from_right(vector & w) override; void apply_from_right(indexed_vector & w) override; - T get_elem(unsigned i, unsigned j) const; + T get_elem(unsigned i, unsigned j) const override; #ifdef Z3DEBUG unsigned row_count() const override { return m_length; } unsigned column_count() const override { return m_length; } diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h index 2f9a5ec38..f2cae7961 100644 --- a/src/util/lp/lu.h +++ b/src/util/lp/lu.h @@ -78,10 +78,10 @@ public: void set_number_of_columns(unsigned n) override { m_m = n; m_n = n; } T m_one_over_val; - T get_elem (unsigned i, unsigned j) const; + T get_elem (unsigned i, unsigned j) const override; - unsigned row_count() const { return m_m; } // not defined } - unsigned column_count() const { return m_m; } // not defined } + unsigned row_count() const override { return m_m; } // not defined } + unsigned column_count() const override { return m_m; } // not defined } #endif void apply_from_left(vector & w, lp_settings &) override { w[m_i] /= m_val; From a238a0a37da800238b6ade73a2b5f5994109529a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 22 Feb 2018 17:07:21 -0800 Subject: [PATCH 0598/1283] fix the build Signed-off-by: Lev Nachmanson --- src/util/lp/dense_matrix.h | 3 ++- src/util/lp/eta_matrix.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util/lp/dense_matrix.h b/src/util/lp/dense_matrix.h index e6663d705..e2ee54058 100644 --- a/src/util/lp/dense_matrix.h +++ b/src/util/lp/dense_matrix.h @@ -81,8 +81,9 @@ public: void set_number_of_rows(unsigned /*m*/) override {} void set_number_of_columns(unsigned /*n*/) override {} - +#ifdef Z3DEBUG T get_elem(unsigned i, unsigned j) const override { return m_values[i * m_n + j]; } +#endif unsigned row_count() const override { return m_m; } unsigned column_count() const override { return m_n; } diff --git a/src/util/lp/eta_matrix.h b/src/util/lp/eta_matrix.h index 89d2e641d..abed6d06b 100644 --- a/src/util/lp/eta_matrix.h +++ b/src/util/lp/eta_matrix.h @@ -83,8 +83,8 @@ public: void apply_from_right(vector & w) override; void apply_from_right(indexed_vector & w) override; - T get_elem(unsigned i, unsigned j) const override; #ifdef Z3DEBUG + T get_elem(unsigned i, unsigned j) const override; unsigned row_count() const override { return m_length; } unsigned column_count() const override { return m_length; } void set_number_of_rows(unsigned m) override { m_length = m; } From c5336f8003dbc23e94156fe4641e1bd9da442cb2 Mon Sep 17 00:00:00 2001 From: Mikhail Ramalho Date: Fri, 23 Feb 2018 14:48:20 +0000 Subject: [PATCH 0599/1283] Convert BVULT(X,Y) into !BVULE(Y,X) Signed-off-by: Mikhail Ramalho --- src/ast/fpa/fpa2bv_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 033d62825..c84af84d6 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -25,7 +25,7 @@ Notes: #include "ast/fpa/fpa2bv_converter.h" #include "ast/rewriter/fpa_rewriter.h" -#define BVULT(X,Y,R) { expr_ref bvult_eq(m), bvult_not(m); m_simp.mk_eq(X, Y, bvult_eq); m_simp.mk_not(bvult_eq, bvult_not); expr_ref t(m); t = m_bv_util.mk_ule(X,Y); m_simp.mk_and(t, bvult_not, R); } +#define BVULT(X,Y,R) { expr_ref t(m); t = m_bv_util.mk_ule(Y,X); m_simp.mk_not(t, R); } fpa2bv_converter::fpa2bv_converter(ast_manager & m) : m(m), From 5d0e33c9ad395fa5f0c4e43ed898b6a56f684ad3 Mon Sep 17 00:00:00 2001 From: Moritz Kiefer Date: Fri, 23 Feb 2018 20:22:07 +0100 Subject: [PATCH 0600/1283] Fix assignment of family ids --- src/ast/ast.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index b524cd8d4..c27651fca 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1532,6 +1532,17 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { tout << "fid: " << fid << " fidname: " << get_family_name(fid) << "\n"; }); ast_translation trans(const_cast(from), *this, false); + // Inheriting plugins can create new family ids. Since new family ids are + // assigned in the order that they are created, this can result in differing + // family ids. To avoid this, we first assign all family ids and only then inherit plugins. + for (family_id fid = 0; from.m_family_manager.has_family(fid); fid++) { + symbol fid_name = from.get_family_name(fid); + if (!m_family_manager.has_family(fid)) { + family_id new_fid = mk_family_id(fid_name); + (void)new_fid; + TRACE("copy_families_plugins", tout << "new target fid created: " << new_fid << " fid_name: " << fid_name << "\n";); + } + } for (family_id fid = 0; from.m_family_manager.has_family(fid); fid++) { SASSERT(from.is_builtin_family_id(fid) == is_builtin_family_id(fid)); SASSERT(!from.is_builtin_family_id(fid) || m_family_manager.has_family(fid)); @@ -1539,11 +1550,6 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { TRACE("copy_families_plugins", tout << "copying: " << fid_name << ", src fid: " << fid << ", target has_family: " << m_family_manager.has_family(fid) << "\n"; if (m_family_manager.has_family(fid)) tout << get_family_id(fid_name) << "\n";); - if (!m_family_manager.has_family(fid)) { - family_id new_fid = mk_family_id(fid_name); - (void)new_fid; - TRACE("copy_families_plugins", tout << "new target fid created: " << new_fid << " fid_name: " << fid_name << "\n";); - } TRACE("copy_families_plugins", tout << "target fid: " << get_family_id(fid_name) << "\n";); SASSERT(fid == get_family_id(fid_name)); if (from.has_plugin(fid) && !has_plugin(fid)) { From 9279cbfbacb12332cc1cd58fd45948cccc629c23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Feb 2018 16:30:08 +0900 Subject: [PATCH 0601/1283] don't reinit assumptions when the solver is unsat. fixes #1502 Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_rule_inliner.cpp | 22 ++++++++-------------- src/sat/sat_solver.cpp | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index b1f222f6e..584f44303 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -209,7 +209,6 @@ namespace datalog { rel->collect_non_empty_predicates(m_preds_with_facts); } - rule_set::iterator rend = orig.end(); for (rule * r : orig) { func_decl * head_pred = r->get_decl(); m_head_pred_ctr.inc(head_pred); @@ -257,9 +256,7 @@ namespace datalog { rule_set * mk_rule_inliner::create_allowed_rule_set(rule_set const & orig) { rule_set * res = alloc(rule_set, m_context); - unsigned rcnt = orig.get_num_rules(); - for (unsigned i=0; iget_decl())) { res->add_rule(r); } @@ -283,10 +280,10 @@ namespace datalog { const rule_stratifier::comp_vector& comps = r.get_stratifier().get_strats(); for (rule_stratifier::item_set * stratum : comps) { - if (stratum->size()==1) { + if (stratum->size() == 1) { continue; } - SASSERT(stratum->size()>1); + SASSERT(stratum->size() > 1); func_decl * first_stratum_pred = *stratum->begin(); //we're trying to break cycles by removing one predicate from each of them @@ -397,12 +394,12 @@ namespace datalog { // now we start filling in the set of the inlined rules in a topological order, // so that we inline rules into other rules - SASSERT(m_inlined_rules.get_num_rules()==0); + SASSERT(m_inlined_rules.get_num_rules() == 0); const rule_stratifier::comp_vector& comps = candidate_inlined_set->get_stratifier().get_strats(); for (rule_stratifier::item_set * stratum : comps) { - SASSERT(stratum->size()==1); + SASSERT(stratum->size() == 1); func_decl * pred = *stratum->begin(); for (rule * r : candidate_inlined_set->get_predicate_rules(pred)) { transform_rule(orig, r, m_inlined_rules); @@ -411,8 +408,7 @@ namespace datalog { TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; ); - for (unsigned i = 0; i < m_inlined_rules.get_num_rules(); ++i) { - rule* r = m_inlined_rules.get_rule(i); + for (rule * r : m_inlined_rules) { datalog::del_rule(m_mc, *r, false); } } @@ -426,9 +422,7 @@ namespace datalog { rule_ref r(todo.back(), m_rm); todo.pop_back(); unsigned pt_len = r->get_positive_tail_size(); - unsigned i = 0; - for (; i < pt_len && !inlining_allowed(orig, r->get_decl(i)); ++i) {}; SASSERT(!has_quantifier(*r.get())); @@ -497,9 +491,9 @@ namespace datalog { for (unsigned ti=0; ti < pt_len; ++ti) { func_decl * pred = r->get_decl(ti); unsigned pred_strat = strat.get_predicate_strat(pred); - SASSERT(pred_strat<=head_strat); + SASSERT(pred_strat <= head_strat); - if (pred_strat==head_strat) { + if (pred_strat == head_strat) { if (pred->get_arity()>head_arity || (pred->get_arity()==head_arity && pred->get_id()>=head_pred->get_id()) ) { return false; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a3d190854..135a7417d 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1139,7 +1139,7 @@ namespace sat { } void solver::reinit_assumptions() { - if (tracking_assumptions() && scope_lvl() == 0) { + if (tracking_assumptions() && scope_lvl() == 0 && !inconsistent()) { TRACE("sat", tout << m_assumptions << "\n";); push(); for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { From 7b68be75c9a2050ff43eba82f07a7a99ccaf0e84 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Feb 2018 13:11:20 +0900 Subject: [PATCH 0602/1283] fixes to #1500 and #1457 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 144 ++++++++++++++++++++++------------------- src/smt/theory_seq.h | 6 +- 2 files changed, 81 insertions(+), 69 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index e92a25159..42056ce5c 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2346,28 +2346,31 @@ bool theory_seq::check_int_string() { bool change = false; for (unsigned i = 0; i < m_int_string.size(); ++i) { expr* e = m_int_string[i].get(), *n; - if (m_util.str.is_itos(e) && add_itos_axiom(e)) { + if (m_util.str.is_itos(e) && add_itos_val_axiom(e)) { change = true; } - else if (m_util.str.is_stoi(e, n) && add_stoi_axiom(e)) { + else if (m_util.str.is_stoi(e, n) && add_stoi_val_axiom(e)) { change = true; } } return change; } -bool theory_seq::add_stoi_axiom(expr* e) { +void theory_seq::add_stoi_axiom(expr* e) { + TRACE("seq", tout << mk_pp(e, m) << "\n";); + SASSERT(m_util.str.is_stoi(e)); + literal l = mk_simplified_literal(m_autil.mk_ge(e, arith_util(m).mk_int(-1))); + add_axiom(l); +} + +bool theory_seq::add_stoi_val_axiom(expr* e) { context& ctx = get_context(); expr* n = nullptr; rational val; TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_stoi(e, n)); if (!get_num_value(e, val)) { - literal l = mk_simplified_literal(m_autil.mk_ge(e, arith_util(m).mk_int(-1))); - add_axiom(l); - TRACE("seq", tout << l << " " << ctx.get_assignment(l) << "\n"; - ctx.display(tout);); - return true; + return false; } if (!m_stoi_axioms.contains(val)) { m_stoi_axioms.insert(val); @@ -2445,54 +2448,61 @@ expr_ref theory_seq::digit2int(expr* ch) { return expr_ref(mk_skolem(symbol("seq.digit2int"), ch, nullptr, nullptr, m_autil.mk_int()), m); } -bool theory_seq::add_itos_axiom(expr* e) { +void theory_seq::add_itos_axiom(expr* e) { context& ctx = get_context(); rational val; expr* n = nullptr; TRACE("seq", tout << mk_pp(e, m) << "\n";); VERIFY(m_util.str.is_itos(e, n)); - if (get_num_value(n, val)) { - if (!m_itos_axioms.contains(val)) { - m_itos_axioms.insert(val); - app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); - expr_ref n1(arith_util(m).mk_numeral(val, true), m); - // itos(n) = "25" <=> n = 25 - literal eq1 = mk_eq(n1, n , false); - literal eq2 = mk_eq(e, e1, false); - add_axiom(~eq1, eq2); - add_axiom(~eq2, eq1); - ctx.force_phase(eq1); - ctx.force_phase(eq2); + // itos(n) = "" <=> n < 0 + app_ref e1(m_util.str.mk_empty(m.get_sort(e)), m); + expr_ref zero(arith_util(m).mk_int(0), m); + literal eq1 = mk_eq(e1, e, false); + literal ge0 = mk_literal(m_autil.mk_ge(n, zero)); + // n >= 0 => itos(n) != "" + // itos(n) = "" or n >= 0 + add_axiom(~eq1, ~ge0); + add_axiom(eq1, ge0); + + // n >= 0 => stoi(itos(n)) = n + app_ref stoi(m_util.str.mk_stoi(e), m); + add_axiom(~ge0, mk_eq(stoi, n, false)); - m_trail_stack.push(insert_map(m_itos_axioms, val)); - m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); - return true; - } + // n >= 0 => itos(n) in (0-9)+ + expr_ref num_re(m); + num_re = m_util.re.mk_range(m_util.str.mk_string(symbol("0")), m_util.str.mk_string(symbol("9"))); + num_re = m_util.re.mk_plus(num_re); + app_ref in_re(m_util.re.mk_in_re(e, num_re), m); + add_axiom(~ge0, mk_literal(in_re)); +} + +bool theory_seq::add_itos_val_axiom(expr* e) { + context& ctx = get_context(); + rational val; + expr* n = nullptr; + TRACE("seq", tout << mk_pp(e, m) << "\n";); + VERIFY(m_util.str.is_itos(e, n)); + bool change = false; + + if (get_num_value(n, val) && !val.is_neg() && !m_itos_axioms.contains(val)) { + m_itos_axioms.insert(val); + app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); + expr_ref n1(arith_util(m).mk_numeral(val, true), m); + + // itos(n) = "25" <=> n = 25 + literal eq1 = mk_eq(n1, n , false); + literal eq2 = mk_eq(e, e1, false); + add_axiom(~eq1, eq2); + add_axiom(~eq2, eq1); + ctx.force_phase(eq1); + ctx.force_phase(eq2); + + m_trail_stack.push(insert_map(m_itos_axioms, val)); + m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); + change = true; } - else { - // stoi(itos(n)) = n - app_ref e2(m_util.str.mk_stoi(e), m); - if (ctx.e_internalized(e2) && ctx.get_enode(e2)->get_root() == ctx.get_enode(n)->get_root()) { - return false; - } - add_axiom(mk_eq(e2, n, false)); - -#if 1 - expr_ref num_re(m), opt_re(m); - num_re = m_util.re.mk_range(m_util.str.mk_string(symbol("0")), m_util.str.mk_string(symbol("9"))); - num_re = m_util.re.mk_plus(num_re); - opt_re = m_util.re.mk_opt(m_util.re.mk_to_re(m_util.str.mk_string(symbol("-")))); - num_re = m_util.re.mk_concat(opt_re, num_re); - app_ref in_re(m_util.re.mk_in_re(e, num_re), m); - internalize_term(in_re); - propagate_in_re(in_re, true); -#endif - m_trail_stack.push(push_replay(alloc(replay_axiom, m, e))); - return true; - } - - return false; + return change; } void theory_seq::apply_sort_cnstr(enode* n, sort* s) { @@ -3048,8 +3058,11 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) { enode* n2 = ctx.get_enode(e1); res = m_util.str.mk_string(symbol(val.to_string().c_str())); #if 1 + if (val.is_neg()) { + result = e; + } // TBD remove this: using roots is unsound for propagation. - if (n1->get_root() == n2->get_root()) { + else if (n1->get_root() == n2->get_root()) { result = res; deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(n1, n2))); } @@ -3147,6 +3160,9 @@ void theory_seq::deque_axiom(expr* n) { else if (m_util.str.is_itos(n)) { add_itos_axiom(n); } + else if (m_util.str.is_stoi(n)) { + add_stoi_axiom(n); + } } @@ -3366,9 +3382,9 @@ void theory_seq::add_itos_length_axiom(expr* len) { rational len1, len2; rational ten(10); if (get_num_value(n, len1)) { - bool neg = len1.is_neg(); - if (neg) len1.neg(); - num_char1 = neg?2:1; + if (len1.is_neg()) { + return; + } // 0 <= x < 10 // 10 <= x < 100 // 100 <= x < 1000 @@ -3387,13 +3403,12 @@ void theory_seq::add_itos_length_axiom(expr* len) { literal len_le(mk_literal(m_autil.mk_le(len, m_autil.mk_int(num_char)))); literal len_ge(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(num_char)))); + literal n_ge_0(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); + add_axiom(~n_ge_0, mk_literal(m_autil.mk_ge(len, m_autil.mk_int(1)))); if (num_char == 1) { - add_axiom(len_ge); - literal n_ge_0(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); literal n_ge_10(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(10)))); add_axiom(~n_ge_0, n_ge_10, len_le); - add_axiom(~len_le, n_ge_0); add_axiom(~len_le, ~n_ge_10); return; } @@ -3401,22 +3416,13 @@ void theory_seq::add_itos_length_axiom(expr* len) { for (unsigned i = 2; i < num_char; ++i) { hi *= ten; } - // n <= -hi or n >= hi*10 <=> len >= num_chars - // -10*hi < n < 100*hi <=> len <= num_chars - literal n_le_hi = mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-hi, true))); + // n >= hi*10 <=> len >= num_chars + // n < 100*hi <=> len <= num_chars literal n_ge_10hi = mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(ten*hi, true))); - literal n_le_m10hi = mk_literal(m_autil.mk_le(n, m_autil.mk_numeral(-ten*hi, true))); literal n_ge_100hi = mk_literal(m_autil.mk_ge(n, m_autil.mk_numeral(ten*ten*hi, true))); - add_axiom(~n_le_hi, len_ge); add_axiom(~n_ge_10hi, len_ge); - add_axiom(n_le_hi, n_ge_10hi, ~len_ge); - - add_axiom(n_le_m10hi, n_ge_100hi, len_le); - add_axiom(~n_le_m10hi, ~len_le); add_axiom(~n_ge_100hi, ~len_le); - - add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(1)))); } @@ -3729,6 +3735,7 @@ bool theory_seq::is_extract_suffix(expr* s, expr* i, expr* l) { /* 0 <= l <= len(s) => s = ey & l = len(e) + len(s) < l => s = e */ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { TRACE("seq", tout << mk_pp(e, m) << " " << mk_pp(s, m) << " " << mk_pp(l, m) << "\n";); @@ -3743,6 +3750,7 @@ void theory_seq::add_extract_prefix_axiom(expr* e, expr* s, expr* l) { add_axiom(~l_ge_0, ~l_le_s, mk_seq_eq(s, ey)); add_axiom(~l_ge_0, ~l_le_s, mk_eq(l, le, false)); add_axiom(~l_ge_0, ~l_le_s, mk_eq(ls_minus_l, m_util.str.mk_length(y), false)); + add_axiom(l_le_s, mk_eq(e, s, false)); } /* @@ -4214,7 +4222,9 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_extract(n) || m_util.str.is_at(n) || m_util.str.is_empty(n) || - m_util.str.is_string(n)) { + m_util.str.is_string(n) || + m_util.str.is_itos(n) || + m_util.str.is_stoi(n)) { enque_axiom(n); } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 203dae633..21aedd7e3 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -507,8 +507,10 @@ namespace smt { void add_elim_string_axiom(expr* n); void add_at_axiom(expr* n); void add_in_re_axiom(expr* n); - bool add_stoi_axiom(expr* n); - bool add_itos_axiom(expr* n); + void add_itos_axiom(expr* n); + void add_stoi_axiom(expr* n); + bool add_stoi_val_axiom(expr* n); + bool add_itos_val_axiom(expr* n); literal is_digit(expr* ch); expr_ref digit2int(expr* ch); void add_itos_length_axiom(expr* n); From ce1b135ec388228352d4f9f4159d185378a6ac16 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Feb 2018 14:57:17 +0900 Subject: [PATCH 0603/1283] address accessor inconsistencies between - and from #1506 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 1 + src/api/python/z3/z3printer.py | 25 ++++++++++++++++++++++--- src/api/z3_api.h | 3 +++ src/ast/datatype_decl_plugin.cpp | 9 +++++++++ src/smt/smt_context.cpp | 4 +--- src/smt/theory_seq.cpp | 16 ++++++++-------- 6 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index f820b184b..3f5a0fcf1 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1059,6 +1059,7 @@ extern "C" { switch(_d->get_decl_kind()) { case OP_DT_CONSTRUCTOR: return Z3_OP_DT_CONSTRUCTOR; case OP_DT_RECOGNISER: return Z3_OP_DT_RECOGNISER; + case OP_DT_IS: return Z3_OP_DT_IS; case OP_DT_ACCESSOR: return Z3_OP_DT_ACCESSOR; case OP_DT_UPDATE_FIELD: return Z3_OP_DT_UPDATE_FIELD; default: diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index aef71be2f..3a6b7269e 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -485,7 +485,9 @@ class PP: raise StopPPException() def pp(self, f, indent): - if f.is_string(): + if isinstance(f, str): + sef.pp_string(f, indent) + elif f.is_string(): self.pp_string(f, indent) elif f.is_indent(): self.pp(f.child, min(indent + f.indent, self.max_indent)) @@ -846,10 +848,17 @@ class Formatter: else: return seq1('MultiPattern', [ self.pp_expr(arg, d+1, xs) for arg in a.children() ]) + def pp_is(self, a, d, xs): + f = a.params()[0] + return self.pp_fdecl(f, a, d, xs) + def pp_map(self, a, d, xs): + f = z3.get_map_func(a) + return self.pp_fdecl(f, a, d, xs) + + def pp_fdecl(self, f, a, d, xs): r = [] sz = 0 - f = z3.get_map_func(a) r.append(to_format(f.name())) for child in a.children(): r.append(self.pp_expr(child, d+1, xs)) @@ -909,6 +918,8 @@ class Formatter: return self.pp_unary_param(a, d, xs) elif k == Z3_OP_EXTRACT: return self.pp_extract(a, d, xs) + elif k == Z3_OP_DT_IS: + return self.pp_is(a, d, xs) elif k == Z3_OP_ARRAY_MAP: return self.pp_map(a, d, xs) elif k == Z3_OP_CONST_ARRAY: @@ -963,6 +974,14 @@ class Formatter: else: return to_format(self.pp_unknown()) + def pp_decl(self, f): + k = f.kind() + if k == Z3_OP_DT_IS or k == Z3_OP_ARRAY_MAP: + g = f.params()[0] + r = [ to_format(g.name()) ] + return seq1(self.pp_name(f), r) + return self.pp_name(f) + def pp_seq_core(self, f, a, d, xs): self.visited = self.visited + 1 if d > self.max_depth or self.visited > self.max_visited: @@ -1054,7 +1073,7 @@ class Formatter: elif z3.is_sort(a): return self.pp_sort(a) elif z3.is_func_decl(a): - return self.pp_name(a) + return self.pp_decl(a) elif isinstance(a, z3.Goal) or isinstance(a, z3.AstVector): return self.pp_seq(a, 0, []) elif isinstance(a, z3.Solver): diff --git a/src/api/z3_api.h b/src/api/z3_api.h index ea0c1615f..500533e91 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -876,6 +876,8 @@ typedef enum - Z3_OP_DT_RECOGNISER: datatype recognizer. + - Z3_OP_DT_IS: datatype recognizer. + - Z3_OP_DT_ACCESSOR: datatype accessor. - Z3_OP_DT_UPDATE_FIELD: datatype field update. @@ -1220,6 +1222,7 @@ typedef enum { // Datatypes Z3_OP_DT_CONSTRUCTOR=0x800, Z3_OP_DT_RECOGNISER, + Z3_OP_DT_IS, Z3_OP_DT_ACCESSOR, Z3_OP_DT_UPDATE_FIELD, diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 44752866c..722cb22b5 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -797,6 +797,7 @@ namespace datatype { if (m_constructor2recognizer.find(con, d)) return d; sort * datatype = con->get_range(); +#if 0 def const& dd = get_def(datatype); symbol r; for (constructor const* c : dd) { @@ -811,6 +812,14 @@ namespace datatype { m_asts.push_back(d); m_constructor2recognizer.insert(con, d); return d; +#else + parameter ps[1] = { parameter(con)}; + d = m.mk_func_decl(m_family_id, OP_DT_IS, 1, ps, 1, &datatype); + m_constructor2recognizer.insert(con, d); + m_asts.push_back(d); + m_asts.push_back(con); + return d; +#endif } func_decl * util::get_recognizer_constructor(func_decl * recognizer) const { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index dd38776bc..cccc2e7fb 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4313,9 +4313,7 @@ namespace smt { if (m_fparams.m_model_compact) m_proto_model->compress(); TRACE("mbqi_bug", tout << "after cleanup:\n"; model_pp(tout, *m_proto_model);); - } - else { - + IF_VERBOSE(11, model_pp(verbose_stream(), *m_proto_model);); } } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 42056ce5c..12764fd9d 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2731,13 +2731,12 @@ public: bool is_string = th.m_util.is_string(m_sort); expr_ref result(th.m); if (is_string) { - svector sbuffer; + unsigned_vector sbuffer; bv_util bv(th.m); rational val; unsigned sz; - - for (unsigned i = 0; i < m_source.size(); ++i) { - switch (m_source[i]) { + for (source_t src : m_source) { + switch (src) { case unit_source: { VERIFY(bv.is_numeral(values[j++], val, sz)); sbuffer.push_back(val.get_unsigned()); @@ -2767,12 +2766,13 @@ public: break; } } + // TRACE("seq", tout << src << " " << sbuffer << "\n";); } result = th.m_util.str.mk_string(zstring(sbuffer.size(), sbuffer.c_ptr())); } else { - for (unsigned i = 0; i < m_source.size(); ++i) { - switch (m_source[i]) { + for (source_t src : m_source) { + switch (src) { case unit_source: args.push_back(th.m_util.str.mk_unit(values[j++])); break; @@ -2814,8 +2814,8 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { seq_value_proc* sv = alloc(seq_value_proc, *this, srt); TRACE("seq", tout << mk_pp(e, m) << "\n";); - for (unsigned i = 0; i < concats.size(); ++i) { - expr* c = concats[i], *c1; + for (expr* c : concats) { + expr *c1; TRACE("seq", tout << mk_pp(c, m) << "\n";); if (m_util.str.is_unit(c, c1)) { if (ctx.e_internalized(c1)) { From 0199c7515f82025129072a485b0879a5be026580 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Feb 2018 19:49:13 +0900 Subject: [PATCH 0604/1283] fix z3.py Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index b5d35bd3f..785649e3d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -4451,7 +4451,7 @@ class Datatype: if __debug__: _z3_assert(isinstance(name, str), "String expected") _z3_assert(name != "", "Constructor name cannot be empty") - return self.declare_core(name, "is_" + name, *args) + return self.declare_core(name, "is-" + name, *args) def __repr__(self): return "Datatype(%s, %s)" % (self.name, self.constructors) @@ -4575,7 +4575,7 @@ def CreateDatatypes(*ds): cref = cref() setattr(dref, cref_name, cref) rref = dref.recognizer(j) - setattr(dref, rref.name(), rref) + setattr(dref, "is_" + cref_name, rref) for k in range(cref_arity): aref = dref.accessor(j, k) setattr(dref, aref.name(), aref) @@ -4629,16 +4629,16 @@ class DatatypeSortRef(SortRef): >>> List.num_constructors() 2 >>> List.recognizer(0) - is_cons + is(cons) >>> List.recognizer(1) - is_nil + is(nil) >>> simplify(List.is_nil(List.cons(10, List.nil))) False >>> simplify(List.is_cons(List.cons(10, List.nil))) True >>> l = Const('l', List) >>> simplify(List.is_cons(l)) - is_cons(l) + is(cons, l) """ if __debug__: _z3_assert(idx < self.num_constructors(), "Invalid recognizer index") From 5d457c95aa312c06342d6076a36133f1da812d88 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Feb 2018 21:00:41 +0900 Subject: [PATCH 0605/1283] update registration of built-ins Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 6d49d8883..3462d0cac 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -2013,9 +2013,10 @@ void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { for (func_decl * c : *m_dt_util.get_datatype_constructors(dt)) { TRACE("new_dt_eh", tout << "new constructor: " << c->get_name() << "\n";); m_owner.insert(c); - func_decl * r = m_dt_util.get_constructor_recognizer(c); - m_owner.insert(r); - TRACE("new_dt_eh", tout << "new recognizer: " << r->get_name() << "\n";); + // Don't insert recognizer any longer. It is a built-in function. + // func_decl * r = m_dt_util.get_constructor_recognizer(c); + // m_owner.insert(r); + // TRACE("new_dt_eh", tout << "new recognizer: " << r->get_name() << "\n";); for (func_decl * a : *m_dt_util.get_constructor_accessors(c)) { TRACE("new_dt_eh", tout << "new accessor: " << a->get_name() << "\n";); m_owner.insert(a); From ac9b03528acabba60810d97887b8b20a9cfdb372 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 26 Feb 2018 17:19:45 -0500 Subject: [PATCH 0606/1283] add re.allchar support in z3str3 --- src/smt/theory_str.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index c5058d00a..8567c6b30 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1812,8 +1812,11 @@ namespace smt { // trivially true for any string! assert_axiom(ex); } else if (u.re.is_full_char(regex)) { - TRACE("str", tout << "ERROR: unknown regex expression " << mk_pp(regex, m) << "!" << std::endl;); - NOT_IMPLEMENTED_YET(); + // any char = any string of length 1 + expr_ref rhs(ctx.mk_eq_atom(mk_strlen(str), mk_int(1)), m); + expr_ref finalAxiom(m.mk_iff(ex, rhs), m); + SASSERT(finalAxiom); + assert_axiom(finalAxiom); } else { TRACE("str", tout << "ERROR: unknown regex expression " << mk_pp(regex, m) << "!" << std::endl;); NOT_IMPLEMENTED_YET(); @@ -6327,6 +6330,13 @@ namespace smt { make_transition(tmp, ch, tmp); } TRACE("str", tout << "re.all NFA: start = " << start << ", end = " << end << std::endl;); + } else if (u.re.is_full_char(e)) { + // effectively . (match any one character) + for (unsigned int i = 0; i < 256; ++i) { + char ch = (char)i; + make_transition(start, ch, end); + } + TRACE("str", tout << "re.allchar NFA: start = " << start << ", end = " << end << std::endl;); } else { TRACE("str", tout << "invalid regular expression" << std::endl;); m_valid = false; From b79d1a6956a6a018280993fc103aea08330cc9bc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Feb 2018 09:22:20 +0900 Subject: [PATCH 0607/1283] fix #1488 for smtlib basic printer Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt_pp.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index ace0de2cc..b7404859f 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -952,6 +952,10 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { strm << "; " << m_attributes.c_str(); } +#if 0 + decls.display_decls(strm); +#else + decls.order_deps(); ast_mark sort_mark; for (unsigned i = 0; i < decls.get_num_sorts(); ++i) { sort* s = decls.get_sorts()[i]; @@ -978,18 +982,19 @@ void ast_smt_pp::display_smt2(std::ostream& strm, expr* n) { strm << "\n"; } } +#endif - for (unsigned i = 0; i < m_assumptions.size(); ++i) { + for (expr* a : m_assumptions) { smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1); strm << "(assert\n "; - p(m_assumptions[i].get()); + p(a); strm << ")\n"; } - for (unsigned i = 0; i < m_assumptions_star.size(); ++i) { + for (expr* a : m_assumptions_star) { smt_printer p(strm, m, ql, rn, m_logic, false, true, m_simplify_implies, 1); strm << "(assert\n "; - p(m_assumptions_star[i].get()); + p(a); strm << ")\n"; } From 30de514a8849fccec762bd5483068fc724b7029a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Feb 2018 11:59:17 +0900 Subject: [PATCH 0608/1283] fix topological traversal crash Signed-off-by: Nikolaj Bjorner --- src/test/heap.cpp | 17 ++++++++++------- src/util/top_sort.h | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/test/heap.cpp b/src/test/heap.cpp index 39353af76..08891ccaa 100644 --- a/src/test/heap.cpp +++ b/src/test/heap.cpp @@ -19,20 +19,19 @@ Revision History: #include #include "util/util.h" #include "util/heap.h" -#include "util/hashtable.h" #include "util/trace.h" +#include "util/uint_set.h" struct lt_proc { bool operator()(int v1, int v2) const { return v1 < v2; } }; typedef heap int_heap; struct int_hash_proc { unsigned operator()(int v) const { return v * 17; }}; -typedef int_hashtable > int_set; #define N 10000 static random_gen heap_rand(1); static void tst1() { int_heap h(N); - int_set t; + uint_set t; for (int i = 0; i < N * 3; i++) { int val = heap_rand() % N; if (!h.contains(val)) { @@ -41,14 +40,15 @@ static void tst1() { t.insert(val); } else { + if (!t.contains(val)) { + for (int v : t) std::cout << v << "\n"; + } ENSURE(t.contains(val)); } } ENSURE(h.check_invariant()); - int_set::iterator it = t.begin(); - int_set::iterator end = t.end(); - for (; it != end; ++it) { - ENSURE(h.contains(*it)); + for (int v : t) { + ENSURE(h.contains(v)); } while (!h.empty()) { int m1 = h.min_value(); @@ -84,6 +84,8 @@ static void dump_heap(const int_heap2 & h, std::ostream & out) { static void tst2() { int_heap2 h(N); for (int i = 0; i < N * 10; i++) { + + if (i % 1 == 0) std::cout << "i: " << i << std::endl; if (i % 1000 == 0) std::cout << "i: " << i << std::endl; int cmd = heap_rand() % 10; if (cmd <= 3) { @@ -134,6 +136,7 @@ void tst_heap() { enable_trace("heap"); unsigned i = 0; while (i < 3) { + IF_VERBOSE(1, verbose_stream() << "test\n";); heap_rand.set_seed(i++); tst1(); init_values(); diff --git a/src/util/top_sort.h b/src/util/top_sort.h index d017d162b..5f7db9c3e 100644 --- a/src/util/top_sort.h +++ b/src/util/top_sort.h @@ -42,7 +42,7 @@ class top_sort { unsigned p_id = 0; if (m_dfs_num.find(f, p_id)) { if (!m_partition_id.contains(f)) { - while (!m_stack_P.empty() && m_partition_id[m_stack_P.back()] > p_id) { + while (!m_stack_P.empty() && m_partition_id.contains(m_stack_P.back()) && m_partition_id[m_stack_P.back()] > p_id) { m_stack_P.pop_back(); } } From 00c3f4fdcd6153780b66f478918008e934de8318 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Feb 2018 22:35:41 +0900 Subject: [PATCH 0609/1283] fix bugs found while running sample from #1112 in debug mode Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 11 ++++++----- src/cmd_context/cmd_context.cpp | 4 +++- src/cmd_context/pdecl.cpp | 3 ++- src/smt/smt_context.cpp | 1 + src/solver/combined_solver.cpp | 5 +++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index aab783afa..1b2e9dcc3 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -17,6 +17,11 @@ Revision History: --*/ #include +#include "util/scoped_ctrl_c.h" +#include "util/cancel_eh.h" +#include "util/file_path.h" +#include "util/scoped_timer.h" +#include "ast/ast_pp.h" #include "api/z3.h" #include "api/api_log_macros.h" #include "api/api_context.h" @@ -26,14 +31,10 @@ Revision History: #include "api/api_stats.h" #include "api/api_ast_vector.h" #include "solver/tactic2solver.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "util/file_path.h" -#include "util/scoped_timer.h" +#include "solver/smt_logics.h" #include "tactic/portfolio/smt_strategic_solver.h" #include "smt/smt_solver.h" #include "smt/smt_implied_equalities.h" -#include "solver/smt_logics.h" #include "cmd_context/cmd_context.h" #include "parsers/smt2/smt2parser.h" #include "sat/dimacs.h" diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 3462d0cac..0be458b4a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -719,6 +719,7 @@ void cmd_context::init_manager_core(bool new_manager) { m_dt_eh = alloc(dt_eh, *this); m_pmanager->set_new_datatype_eh(m_dt_eh.get()); if (!has_logic()) { + TRACE("cmd_context", tout << "init manager\n";); // add list type only if the logic is not specified. // it prevents clashes with builtin types. insert(pm().mk_plist_decl()); @@ -1408,7 +1409,8 @@ void cmd_context::restore_assertions(unsigned old_sz) { SASSERT(m_assertions.empty()); return; } - SASSERT(old_sz <= m_assertions.size()); + if (old_sz == m_assertions.size()) return; + SASSERT(old_sz < m_assertions.size()); SASSERT(!m_interactive_mode || m_assertions.size() == m_assertion_strings.size()); restore(m(), m_assertions, old_sz); if (produce_unsat_cores()) diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 3a684b867..f9ba79f6d 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -852,7 +852,7 @@ pdecl_manager::pdecl_manager(ast_manager & m): pdecl_manager::~pdecl_manager() { dec_ref(m_list); reset_sort_info(); - SASSERT(m_sort2psort.empty()); + SASSERT(m_sort2psort.empty()); SASSERT(m_table.empty()); } @@ -946,6 +946,7 @@ void pdecl_manager::del_decl_core(pdecl * p) { } void pdecl_manager::del_decl(pdecl * p) { + TRACE("pdecl_manager", p->display(tout); tout << "\n";); if (p->is_psort()) { psort * _p = static_cast(p); if (_p->is_sort_wrapper()) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index cccc2e7fb..9c95ac7c3 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3143,6 +3143,7 @@ namespace smt { push_scope(); for (unsigned i = 0; i < num_assumptions; i++) { expr * curr_assumption = assumptions[i]; + if (m_manager.is_true(curr_assumption)) continue; SASSERT(is_valid_assumption(m_manager, curr_assumption)); proof * pr = m_manager.mk_asserted(curr_assumption); internalize_assertion(curr_assumption, pr, 0); diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 397f3bdb1..9d2d8aa46 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -18,10 +18,11 @@ Author: Notes: --*/ -#include "solver/solver.h" #include "util/scoped_timer.h" -#include "solver/combined_solver_params.hpp" #include "util/common_msgs.h" +#include "ast/ast_pp.h" +#include "solver/solver.h" +#include "solver/combined_solver_params.hpp" #define PS_VB_LVL 15 /** From a738f5af12ff14312254c7024dc253358e4b6f83 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Mar 2018 20:14:59 +0900 Subject: [PATCH 0610/1283] fix #1512 Signed-off-by: Nikolaj Bjorner --- src/model/func_interp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp index accb45a25..2eb687dae 100644 --- a/src/model/func_interp.cpp +++ b/src/model/func_interp.cpp @@ -112,7 +112,8 @@ bool func_interp::is_fi_entry_expr(expr * e, ptr_vector & args) { return false; } - if ((m_arity == 0) || + if (!is_ground(t) || + (m_arity == 0) || (m_arity == 1 && !m().is_eq(c, a0, a1)) || (m_arity > 1 && (!m().is_and(c) || to_app(c)->get_num_args() != m_arity))) return false; From 8e09a78c269d9c0a25f784dc0cc898ab24b1182d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Mar 2018 23:02:20 +0900 Subject: [PATCH 0611/1283] fix #1510 by reintroducing automatic declaration of recognizers Signed-off-by: Nikolaj Bjorner --- src/api/api_datatype.cpp | 10 +++++----- src/ast/datatype_decl_plugin.cpp | 27 +++++++++++---------------- src/ast/datatype_decl_plugin.h | 1 + src/cmd_context/cmd_context.cpp | 5 ++--- src/muz/pdr/pdr_prop_solver.cpp | 2 +- src/muz/spacer/spacer_util.cpp | 2 +- src/parsers/smt2/smt2parser.cpp | 2 +- src/qe/qe_datatype_plugin.cpp | 10 +++++----- src/qe/qe_datatypes.cpp | 4 ++-- src/qe/qe_lite.cpp | 2 +- src/smt/theory_datatype.cpp | 10 +++++----- 11 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index df0b2317f..799e537ea 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -137,7 +137,7 @@ extern "C" { func_decl* decl = (decls)[i]; mk_c(c)->save_multiple_ast_trail(decl); enum_consts[i] = of_func_decl(decl); - decl = dt_util.get_constructor_recognizer(decl); + decl = dt_util.get_constructor_is(decl); mk_c(c)->save_multiple_ast_trail(decl); enum_testers[i] = of_func_decl(decl); } @@ -196,7 +196,7 @@ extern "C" { *nil_decl = of_func_decl(f); } if (is_nil_decl) { - f = data_util.get_constructor_recognizer(cnstrs[0]); + f = data_util.get_constructor_is(cnstrs[0]); mk_c(c)->save_multiple_ast_trail(f); *is_nil_decl = of_func_decl(f); } @@ -206,7 +206,7 @@ extern "C" { *cons_decl = of_func_decl(f); } if (is_cons_decl) { - f = data_util.get_constructor_recognizer(cnstrs[1]); + f = data_util.get_constructor_is(cnstrs[1]); mk_c(c)->save_multiple_ast_trail(f); *is_cons_decl = of_func_decl(f); } @@ -290,7 +290,7 @@ extern "C" { *constructor_decl = of_func_decl(f); } if (tester) { - func_decl* f2 = data_util.get_constructor_recognizer(f); + func_decl* f2 = data_util.get_constructor_is(f); mk_c(c)->save_multiple_ast_trail(f2); *tester = of_func_decl(f2); } @@ -497,7 +497,7 @@ extern "C" { RETURN_Z3(nullptr); } func_decl* decl = (decls)[idx]; - decl = dt_util.get_constructor_recognizer(decl); + decl = dt_util.get_constructor_is(decl); mk_c(c)->save_ast_trail(decl); RETURN_Z3(of_func_decl(decl)); Z3_CATCH_RETURN(nullptr); diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 722cb22b5..44f824959 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -791,13 +791,20 @@ namespace datatype { return res; } + + func_decl * util::get_constructor_is(func_decl * con) { + SASSERT(is_constructor(con)); + sort * datatype = con->get_range(); + parameter ps[1] = { parameter(con)}; + return m.mk_func_decl(m_family_id, OP_DT_IS, 1, ps, 1, &datatype); + } + func_decl * util::get_constructor_recognizer(func_decl * con) { SASSERT(is_constructor(con)); func_decl * d = nullptr; if (m_constructor2recognizer.find(con, d)) return d; sort * datatype = con->get_range(); -#if 0 def const& dd = get_def(datatype); symbol r; for (constructor const* c : dd) { @@ -812,14 +819,6 @@ namespace datatype { m_asts.push_back(d); m_constructor2recognizer.insert(con, d); return d; -#else - parameter ps[1] = { parameter(con)}; - d = m.mk_func_decl(m_family_id, OP_DT_IS, 1, ps, 1, &datatype); - m_constructor2recognizer.insert(con, d); - m_asts.push_back(d); - m_asts.push_back(con); - return d; -#endif } func_decl * util::get_recognizer_constructor(func_decl * recognizer) const { @@ -1049,15 +1048,11 @@ namespace datatype { sort* s = todo.back(); todo.pop_back(); out << s->get_name() << " =\n"; - ptr_vector const& cnstrs = *get_datatype_constructors(s); - for (unsigned i = 0; i < cnstrs.size(); ++i) { - func_decl* cns = cnstrs[i]; - func_decl* rec = get_constructor_recognizer(cns); - out << " " << cns->get_name() << " :: " << rec->get_name() << " :: "; + for (func_decl * cns : cnstrs) { + out << " " << cns->get_name() << " :: "; ptr_vector const & accs = *get_constructor_accessors(cns); - for (unsigned j = 0; j < accs.size(); ++j) { - func_decl* acc = accs[j]; + for (func_decl* acc : accs) { sort* s1 = acc->get_range(); out << "(" << acc->get_name() << ": " << s1->get_name() << ") "; if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) { diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 81c2d09a5..e644ccbda 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -368,6 +368,7 @@ namespace datatype { sort* get_datatype_parameter_sort(sort * ty, unsigned idx); func_decl * get_non_rec_constructor(sort * ty); func_decl * get_constructor_recognizer(func_decl * constructor); + func_decl * get_constructor_is(func_decl * constructor); ptr_vector const * get_constructor_accessors(func_decl * constructor); func_decl * get_accessor_constructor(func_decl * accessor); func_decl * get_recognizer_constructor(func_decl * recognizer) const; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 0be458b4a..aabe43110 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -2015,9 +2015,8 @@ void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { for (func_decl * c : *m_dt_util.get_datatype_constructors(dt)) { TRACE("new_dt_eh", tout << "new constructor: " << c->get_name() << "\n";); m_owner.insert(c); - // Don't insert recognizer any longer. It is a built-in function. - // func_decl * r = m_dt_util.get_constructor_recognizer(c); - // m_owner.insert(r); + func_decl * r = m_dt_util.get_constructor_recognizer(c); + m_owner.insert(r); // TRACE("new_dt_eh", tout << "new recognizer: " << r->get_name() << "\n";); for (func_decl * a : *m_dt_util.get_constructor_accessors(c)) { TRACE("new_dt_eh", tout << "new accessor: " << a->get_name() << "\n";); diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index 801d06e50..8ebc9b9cb 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -133,7 +133,7 @@ namespace pdr { else if ((m.is_eq(e, c, val) && is_app(val) && dt.is_constructor(to_app(val))) || (m.is_eq(e, val, c) && is_app(val) && dt.is_constructor(to_app(val)))){ func_decl* f = to_app(val)->get_decl(); - func_decl* r = dt.get_constructor_recognizer(f); + func_decl* r = dt.get_constructor_is(f); conjs[i] = m.mk_app(r, c); ptr_vector const& acc = *dt.get_constructor_accessors(f); for (unsigned j = 0; j < acc.size(); ++j) { diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index cdec5d7eb..625ac4b7b 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -694,7 +694,7 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) } else if ((m.is_eq(e, c, val) && is_app(val) && dt.is_constructor(to_app(val))) || (m.is_eq(e, val, c) && is_app(val) && dt.is_constructor(to_app(val)))){ func_decl* f = to_app(val)->get_decl(); - func_decl* r = dt.get_constructor_recognizer(f); + func_decl* r = dt.get_constructor_is(f); conjs[i] = m.mk_app(r, c); ptr_vector const& acc = *dt.get_constructor_accessors(f); for (unsigned j = 0; j < acc.size(); ++j) { diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 347cbbd68..9265312d4 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1414,7 +1414,7 @@ namespace smt2 { else { SASSERT(is_app(pattern)); func_decl * f = to_app(pattern)->get_decl(); - func_decl * r = dtutil().get_constructor_recognizer(f); + func_decl * r = dtutil().get_constructor_is(f); ptr_vector const * acc = dtutil().get_constructor_accessors(f); shifter()(t, acc->size(), tsh); for (func_decl* a : *acc) { diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index 58878d067..81a402ba4 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -261,7 +261,7 @@ namespace qe { return false; } func_decl* c = a->get_decl(); - func_decl* r = m_util.get_constructor_recognizer(c); + func_decl_ref r(m_util.get_constructor_is(c), m); ptr_vector const & acc = *m_util.get_constructor_accessors(c); SASSERT(acc.size() == a->get_num_args()); // @@ -380,7 +380,7 @@ namespace qe { } func_decl* c = l->get_decl(); ptr_vector const& acc = *m_util.get_constructor_accessors(c); - func_decl* rec = m_util.get_constructor_recognizer(c); + func_decl* rec = m_util.get_constructor_is(c); expr_ref_vector conj(m); conj.push_back(m.mk_app(rec, r)); for (unsigned i = 0; i < acc.size(); ++i) { @@ -627,7 +627,7 @@ namespace qe { // if (!has_recognizer(x, fml, r, c)) { c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); - r = m_datatype_util.get_constructor_recognizer(c); + r = m_datatype_util.get_constructor_is(c); app* is_c = m.mk_app(r, x); // assert v => r(x) m_ctx.add_constraint(true, is_c); @@ -674,7 +674,7 @@ namespace qe { // if (!has_recognizer(x, fml, r, c)) { c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); - r = m_datatype_util.get_constructor_recognizer(c); + r = m_datatype_util.get_constructor_is(c); app* is_c = m.mk_app(r, x); fml = m.mk_and(is_c, fml); app_ref fresh_x(m.mk_fresh_const("x", s), m); @@ -775,7 +775,7 @@ namespace qe { } c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); - r = m_datatype_util.get_constructor_recognizer(c); + r = m_datatype_util.get_constructor_is(c); app* is_c = m.mk_app(r, x); // assert v => r(x) diff --git a/src/qe/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index db1e6ec85..770beb59d 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -151,7 +151,7 @@ namespace qe { return false; } func_decl* c = a->get_decl(); - func_decl* rec = dt.get_constructor_recognizer(c); + func_decl_ref rec(dt.get_constructor_is(c), m); ptr_vector const & acc = *dt.get_constructor_accessors(c); SASSERT(acc.size() == a->get_num_args()); // @@ -232,7 +232,7 @@ namespace qe { func_decl* c = to_app(l)->get_decl(); ptr_vector const& acc = *dt.get_constructor_accessors(c); if (!is_app_of(r, c)) { - lits.push_back(m.mk_app(dt.get_constructor_recognizer(c), r)); + lits.push_back(m.mk_app(dt.get_constructor_is(c), r)); } for (unsigned i = 0; i < acc.size(); ++i) { lits.push_back(m.mk_eq(to_app(l)->get_arg(i), access(c, i, acc, r))); diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 8cbf6c70f..e96626479 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -692,7 +692,7 @@ namespace eq { } } else { - func_decl* rec = dt.get_constructor_recognizer(d); + func_decl* rec = dt.get_constructor_is(d); conjs.push_back(m.mk_app(rec, r)); ptr_vector const& acc = *dt.get_constructor_accessors(d); for (unsigned i = 0; i < acc.size(); ++i) { diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 695d479f4..3d3d56055 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -167,7 +167,7 @@ namespace smt { func_decl * upd = n->get_decl(); func_decl * acc = to_func_decl(upd->get_parameter(0).get_ast()); func_decl * con = m_util.get_accessor_constructor(acc); - func_decl * rec = m_util.get_constructor_recognizer(con); + func_decl * rec = m_util.get_constructor_is(con); ptr_vector const & accessors = *m_util.get_constructor_accessors(con); app_ref rec_app(m.mk_app(rec, arg1), m); ctx.internalize(rec_app, false); @@ -710,7 +710,7 @@ namespace smt { literal consequent; if (!r) { ptr_vector const & constructors = *m_util.get_datatype_constructors(dt); - func_decl * rec = m_util.get_constructor_recognizer(constructors[unassigned_idx]); + func_decl * rec = m_util.get_constructor_is(constructors[unassigned_idx]); app * rec_app = get_manager().mk_app(rec, n->get_owner()); ctx.internalize(rec_app, false); consequent = literal(ctx.get_bool_var(rec_app)); @@ -751,12 +751,12 @@ namespace smt { m_stats.m_splits++; if (d->m_recognizers.empty()) { - r = m_util.get_constructor_recognizer(non_rec_c); + r = m_util.get_constructor_is(non_rec_c); } else { enode * recognizer = d->m_recognizers[non_rec_idx]; if (recognizer == nullptr) { - r = m_util.get_constructor_recognizer(non_rec_c); + r = m_util.get_constructor_is(non_rec_c); } else if (!ctx.is_relevant(recognizer)) { ctx.mark_as_relevant(recognizer); @@ -776,7 +776,7 @@ namespace smt { if (curr == nullptr) { ptr_vector const & constructors = *m_util.get_datatype_constructors(s); // found empty slot... - r = m_util.get_constructor_recognizer(constructors[idx]); + r = m_util.get_constructor_is(constructors[idx]); break; } else if (!ctx.is_relevant(curr)) { From 205d77d5919d5f3d25e68631d9a3dd2a252352b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Mar 2018 19:26:31 -0800 Subject: [PATCH 0612/1283] save last model to ensure it is available fixes #1514 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 7 ++++++- src/opt/opt_solver.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 715f45291..c5363816a 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -227,9 +227,13 @@ namespace opt { smt::theory_var v = m_objective_vars[i]; bool has_shared = false; inf_eps val = get_optimizer().maximize(v, blocker, has_shared); + get_model(m_model); inf_eps val2; m_valid_objectives[i] = true; TRACE("opt", tout << (has_shared?"has shared":"non-shared") << "\n";); + if (!m_models[i]) { + set_model(i); + } if (m_context.get_context().update_model(has_shared)) { if (has_shared && val != current_objective_value(i)) { decrement_value(i, val); @@ -247,7 +251,7 @@ namespace opt { tout << "objective: " << mk_pp(m_objective_terms[i].get(), m) << "\n"; tout << "maximal value: " << val << "\n"; tout << "new condition: " << blocker << "\n"; - model_smt2_pp(tout << "update model:\n", m, *m_models[i], 0); }); + if (m_models[i]) model_smt2_pp(tout << "update model:\n", m, *m_models[i], 0); }); } void opt_solver::set_model(unsigned i) { @@ -299,6 +303,7 @@ namespace opt { void opt_solver::get_model(model_ref & m) { m_context.get_model(m); + if (!m) m = m_model; else m_model = m; } proof * opt_solver::get_proof() { diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 41e9dee2d..ac9884770 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -73,6 +73,7 @@ namespace opt { filter_model_converter& m_fm; progress_callback * m_callback; symbol m_logic; + model_ref m_model; svector m_objective_vars; vector m_objective_values; sref_vector m_models; From a64fd7145c381eed2be11d68c190b65760fb4261 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Mar 2018 03:36:03 -0800 Subject: [PATCH 0613/1283] remove buggy legacy code, rely on pull_cheap_ite option in rewriter, #1511 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/CMakeLists.txt | 1 - src/ast/rewriter/pull_ite_tree.cpp | 221 ------------------------- src/ast/rewriter/pull_ite_tree.h | 113 ------------- src/smt/asserted_formulas.cpp | 4 +- src/smt/asserted_formulas.h | 4 - src/smt/params/preprocessor_params.cpp | 2 +- src/smt/params/preprocessor_params.h | 4 +- src/smt/smt_setup.cpp | 2 +- 8 files changed, 5 insertions(+), 346 deletions(-) delete mode 100644 src/ast/rewriter/pull_ite_tree.cpp delete mode 100644 src/ast/rewriter/pull_ite_tree.h diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index 57924b48a..f030e2704 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -25,7 +25,6 @@ z3_add_component(rewriter pb_rewriter.cpp pb2bv_rewriter.cpp push_app_ite.cpp - pull_ite_tree.cpp quant_hoist.cpp rewriter.cpp seq_rewriter.cpp diff --git a/src/ast/rewriter/pull_ite_tree.cpp b/src/ast/rewriter/pull_ite_tree.cpp deleted file mode 100644 index 61114387c..000000000 --- a/src/ast/rewriter/pull_ite_tree.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - pull_ite_tree.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2008-06-22. - -Revision History: - ---*/ -#include "ast/rewriter/pull_ite_tree.h" -#include "ast/recurse_expr_def.h" -#include "ast/for_each_expr.h" -#include "ast/ast_pp.h" - -pull_ite_tree::pull_ite_tree(ast_manager & m): - m_manager(m), - m_rewriter(m), - m_cache(m) { -} - -void pull_ite_tree::cache_result(expr * n, expr * r, proof * pr) { - m_cache.insert(n, r, pr); -} - -void pull_ite_tree::visit(expr * n, bool & visited) { - if (!is_cached(n)) { - m_todo.push_back(n); - visited = false; - } -} - -bool pull_ite_tree::visit_children(expr * n) { - if (m_manager.is_ite(n)) { - bool visited = true; - visit(to_app(n)->get_arg(1), visited); - visit(to_app(n)->get_arg(2), visited); - return visited; - } - else { - return true; - } -} - -void pull_ite_tree::reduce(expr * n) { - // Remark: invoking the simplifier to build the new expression saves a lot of memory. - if (m_manager.is_ite(n)) { - expr * c = to_app(n)->get_arg(0); - expr * t_old = to_app(n)->get_arg(1); - expr * e_old = to_app(n)->get_arg(2); - expr * t = nullptr; - proof * t_pr = nullptr; - expr * e = nullptr; - proof * e_pr = nullptr; - get_cached(t_old, t, t_pr); - get_cached(e_old, e, e_pr); - expr_ref r(m_manager); - expr * args[3] = {c, t, e}; - r = m_rewriter.mk_app(to_app(n)->get_decl(), 3, args); - if (!m_manager.proofs_enabled()) { - // expr * r = m_manager.mk_ite(c, t, e); - cache_result(n, r, nullptr); - } - else { - // t_pr is a proof for (m_p ... t_old ...) == t - // e_pr is a proof for (m_p ... e_old ...) == e - expr_ref old(m_manager); - expr_ref p_t_old(m_manager); - expr_ref p_e_old(m_manager); - old = mk_p_arg(n); // (m_p ... n ...) where n is (ite c t_old e_old) - p_t_old = mk_p_arg(t_old); // (m_p ... t_old ...) - p_e_old = mk_p_arg(e_old); // (m_p ... e_old ...) - expr_ref tmp1(m_manager); - tmp1 = m_manager.mk_ite(c, p_t_old, p_e_old); // (ite c (m_p ... t_old ...) (m_p ... e_old ...)) - proof * pr1 = m_manager.mk_rewrite(old, tmp1); // proof for (m_p ... (ite c t_old e_old) ...) = (ite c (m_p ... t_old ...) (m_p ... e_old ...)) - expr_ref tmp2(m_manager); - tmp2 = m_manager.mk_ite(c, t, e); // (ite c t e) - proof * pr2 = nullptr; // it will contain a proof for (ite c (m_p ... t_old ...) (m_p ... e_old ...)) = (ite c t e) - proof * pr3 = nullptr; // it will contain a proof for (m_p ... (ite c t_old e_old) ...) = (ite c t e) - proof * proofs[2]; - unsigned num_proofs = 0; - if (t_pr != nullptr) { - proofs[num_proofs] = t_pr; - num_proofs++; - } - if (e_pr != nullptr) { - proofs[num_proofs] = e_pr; - num_proofs++; - } - if (num_proofs > 0) { - pr2 = m_manager.mk_congruence(to_app(tmp1), to_app(tmp2), num_proofs, proofs); - pr3 = m_manager.mk_transitivity(pr1, pr2); - } - else { - pr3 = pr1; - } - proof * pr4 = nullptr; // it will contain a proof for (ite c t e) = r - proof * pr5 = nullptr; // it will contain a proof for (m_p ... (ite c t_old e_old) ...) = r - if (tmp2 != r) { - pr4 = m_manager.mk_rewrite(tmp2, r); - pr5 = m_manager.mk_transitivity(pr3, pr4); - } - else { - pr5 = pr3; - } - cache_result(n, r, pr5); - } - } - else { - expr_ref r(m_manager); - m_args[m_arg_idx] = n; - r = m_rewriter.mk_app(m_p, m_args.size(), m_args.c_ptr()); - if (!m_manager.proofs_enabled()) { - // expr * r = m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr()); - cache_result(n, r, nullptr); - } - else { - expr_ref old(m_manager); - proof * p; - old = mk_p_arg(n); - if (old == r) - p = nullptr; - else - p = m_manager.mk_rewrite(old, r); - cache_result(n, r, p); - } - } -} - -void pull_ite_tree::operator()(app * n, app_ref & r, proof_ref & pr) { - unsigned num_args = n->get_num_args(); - m_args.resize(num_args); - m_p = n->get_decl(); - expr * ite = nullptr; - for (unsigned i = 0; i < num_args; i++) { - expr * arg = n->get_arg(i); - if (ite) { - m_args[i] = arg; - } - else if (m_manager.is_ite(arg)) { - m_arg_idx = i; - m_args[i] = 0; - ite = arg; - } - else { - m_args[i] = arg; - } - } - if (!ite) { - r = n; - pr = nullptr; - return; - } - m_todo.push_back(ite); - while (!m_todo.empty()) { - expr * n = m_todo.back(); - if (is_cached(n)) - m_todo.pop_back(); - else if (visit_children(n)) { - m_todo.pop_back(); - reduce(n); - } - } - SASSERT(is_cached(ite)); - expr * _r = nullptr; - proof * _pr = nullptr; - get_cached(ite, _r, _pr); - r = to_app(_r); - pr = _pr; - m_cache.reset(); - m_todo.reset(); -} - - - -pull_ite_tree_cfg::pull_ite_tree_cfg(ast_manager & m): - m(m), - m_trail(m), - m_proc(m) { -} - -bool pull_ite_tree_cfg::get_subst(expr * n, expr* & r, proof* & p) { - if (is_app(n) && is_target(to_app(n))) { - app_ref tmp(m); - proof_ref pr(m); - m_proc(to_app(n), tmp, pr); - if (tmp != n) { - r = tmp; - p = pr; - m_trail.push_back(r); - m_trail.push_back(p); - return true; - } - } - return false; -} - -bool pull_cheap_ite_tree_cfg::is_target(app * n) const { - bool r = - n->get_num_args() == 2 && - n->get_family_id() != null_family_id && - m.is_bool(n) && - (m.is_value(n->get_arg(0)) || m.is_value(n->get_arg(1))) && - (m.is_term_ite(n->get_arg(0)) || m.is_term_ite(n->get_arg(1))); - TRACE("pull_ite_target", tout << mk_pp(n, m) << "\nresult: " << r << "\n";); - return r; -} - - - - - - diff --git a/src/ast/rewriter/pull_ite_tree.h b/src/ast/rewriter/pull_ite_tree.h deleted file mode 100644 index ea462315a..000000000 --- a/src/ast/rewriter/pull_ite_tree.h +++ /dev/null @@ -1,113 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - pull_ite_tree.h - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2008-06-22. - -Revision History: - ---*/ -#ifndef PULL_ITE_TREE_H_ -#define PULL_ITE_TREE_H_ - -#include "ast/ast.h" -#include "ast/rewriter/rewriter.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/expr_map.h" -#include "ast/recurse_expr.h" -#include "util/obj_hashtable.h" - -/** - \brief Functor for applying the following transformation - F[(p (ite c t1 t2) args)] = F'[(ite c t1 t2), p, args] - - F'[(ite c t1 t2), p, args] = (ite c F'[t1, p, args] F'[t2, p, args]) - F'[t, p, args] = (p t args) -*/ -class pull_ite_tree { - ast_manager & m_manager; - th_rewriter m_rewriter; - func_decl * m_p; - ptr_vector m_args; - unsigned m_arg_idx; //!< position of the ite argument - expr_map m_cache; - ptr_vector m_todo; - - bool is_cached(expr * n) const { return m_cache.contains(n); } - void get_cached(expr * n, expr * & r, proof * & p) const { m_cache.get(n, r, p); } - void cache_result(expr * n, expr * r, proof * pr); - void visit(expr * n, bool & visited); - bool visit_children(expr * n); - void reduce(expr * n); - /** - \brief Creante an application (m_p ... n ...) where n is the argument m_arg_idx and the other arguments - are in m_args. - */ - expr * mk_p_arg(expr * n) { - m_args[m_arg_idx] = n; - return m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr()); - } -public: - pull_ite_tree(ast_manager & m); - /** - \brief Apply the transformation above if n contains an ite-expression. - Store the result in r. If n does not contain an ite-expression, then - store n in r. - - When proof generation is enabled, pr is a proof for n = r. - */ - void operator()(app * n, app_ref & r, proof_ref & pr); -}; - -/** - \brief Functor for applying the pull_ite_tree on subexpressions n that - satisfy the is_target virtual predicate. -*/ -class pull_ite_tree_cfg : public default_rewriter_cfg { -protected: - ast_manager& m; - expr_ref_vector m_trail; - pull_ite_tree m_proc; -public: - pull_ite_tree_cfg(ast_manager & m); - virtual ~pull_ite_tree_cfg() {} - virtual bool is_target(app * n) const = 0; - bool get_subst(expr * n, expr* & r, proof* & p); -}; - -/** - \brief Apply pull_ite_tree on predicates of the form - (p ite v) and (p v ite) - - where: - - p is an interpreted predicate - - ite is an ite-term expression - - v is a value -*/ -class pull_cheap_ite_tree_cfg : public pull_ite_tree_cfg { -public: - pull_cheap_ite_tree_cfg(ast_manager & m):pull_ite_tree_cfg(m) {} - ~pull_cheap_ite_tree_cfg() override {} - bool is_target(app * n) const override; -}; - -class pull_cheap_ite_tree_rw : public rewriter_tpl { - pull_cheap_ite_tree_cfg m_cfg; -public: - pull_cheap_ite_tree_rw(ast_manager& m): - rewriter_tpl(m, m.proofs_enabled(), m_cfg), - m_cfg(m) - {} -}; - -#endif /* PULL_ITE_TREE_H_ */ - diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 465371434..5903fefcb 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -46,7 +46,6 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): m_refine_inj_axiom(*this), m_max_bv_sharing_fn(*this), m_elim_term_ite(*this), - m_pull_cheap_ite_trees(*this), m_pull_nested_quantifiers(*this), m_elim_bvs_from_quantifiers(*this), m_cheap_quant_fourier_motzkin(*this), @@ -122,7 +121,7 @@ void asserted_formulas::set_eliminate_and(bool flag) { if (flag == m_elim_and) return; m_elim_and = flag; params_ref p; - p.set_bool("pull_cheap_ite", false); + if (m_params.m_pull_cheap_ite) p.set_bool("pull_cheap_ite", true); p.set_bool("elim_and", flag); p.set_bool("arith_ineq_lhs", true); p.set_bool("sort_sums", true); @@ -241,7 +240,6 @@ void asserted_formulas::reduce() { if (!invoke(m_nnf_cnf)) return; set_eliminate_and(true); if (!invoke(m_reduce_asserted_formulas)) return; - if (!invoke(m_pull_cheap_ite_trees)) return; if (!invoke(m_pull_nested_quantifiers)) return; if (!invoke(m_lift_ite)) return; if (!invoke(m_ng_lift_ite)) return; diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index a67b975eb..275687adb 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -26,7 +26,6 @@ Revision History: #include "ast/rewriter/bit2int.h" #include "ast/rewriter/maximize_ac_sharing.h" #include "ast/rewriter/distribute_forall.h" -#include "ast/rewriter/pull_ite_tree.h" #include "ast/rewriter/push_app_ite.h" #include "ast/rewriter/inj_axiom.h" #include "ast/rewriter/bv_elim.h" @@ -172,7 +171,6 @@ class asserted_formulas { #define MK_SIMPLIFIERF(NAME, FUNCTOR, MSG, APP, REDUCE) MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, (af.m), REDUCE) - MK_SIMPLIFIERF(pull_cheap_ite_trees, pull_cheap_ite_tree_rw, "pull-cheap-ite-trees", af.m_params.m_pull_cheap_ite_trees, false); MK_SIMPLIFIERF(pull_nested_quantifiers, pull_nested_quant, "pull-nested-quantifiers", af.m_params.m_pull_nested_quantifiers && af.has_quantifiers(), false); MK_SIMPLIFIERF(cheap_quant_fourier_motzkin, elim_bounds_rw, "cheap-fourier-motzkin", af.m_params.m_eliminate_bounds && af.has_quantifiers(), true); MK_SIMPLIFIERF(elim_bvs_from_quantifiers, bv_elim_rw, "eliminate-bit-vectors-from-quantifiers", af.m_params.m_bb_quantifiers, true); @@ -187,7 +185,6 @@ class asserted_formulas { refine_inj_axiom_fn m_refine_inj_axiom; max_bv_sharing_fn m_max_bv_sharing_fn; elim_term_ite_fn m_elim_term_ite; - pull_cheap_ite_trees m_pull_cheap_ite_trees; pull_nested_quantifiers m_pull_nested_quantifiers; elim_bvs_from_quantifiers m_elim_bvs_from_quantifiers; cheap_quant_fourier_motzkin m_cheap_quant_fourier_motzkin; @@ -219,7 +216,6 @@ class asserted_formulas { bool is_gt(expr* lhs, expr* rhs); void compute_depth(expr* e); unsigned depth(expr* e) { return m_expr2depth[e]; } - bool pull_cheap_ite_trees(); void init(unsigned num_formulas, expr * const * formulas, proof * const * prs); diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index 93ea794fa..ee4b7c2e4 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -41,7 +41,7 @@ void preprocessor_params::display(std::ostream & out) const { DISPLAY_PARAM(m_lift_ite); DISPLAY_PARAM(m_ng_lift_ite); - DISPLAY_PARAM(m_pull_cheap_ite_trees); + DISPLAY_PARAM(m_pull_cheap_ite); DISPLAY_PARAM(m_pull_nested_quantifiers); DISPLAY_PARAM(m_eliminate_term_ite); DISPLAY_PARAM(m_macro_finder); diff --git a/src/smt/params/preprocessor_params.h b/src/smt/params/preprocessor_params.h index dc16d6244..be7fd4c01 100644 --- a/src/smt/params/preprocessor_params.h +++ b/src/smt/params/preprocessor_params.h @@ -32,7 +32,7 @@ struct preprocessor_params : public pattern_inference_params, public bit_blaster_params { lift_ite_kind m_lift_ite; lift_ite_kind m_ng_lift_ite; // lift ite for non ground terms - bool m_pull_cheap_ite_trees; + bool m_pull_cheap_ite; bool m_pull_nested_quantifiers; bool m_eliminate_term_ite; bool m_macro_finder; @@ -54,7 +54,7 @@ public: preprocessor_params(params_ref const & p = params_ref()): m_lift_ite(LI_NONE), m_ng_lift_ite(LI_NONE), - m_pull_cheap_ite_trees(false), + m_pull_cheap_ite(false), m_pull_nested_quantifiers(false), m_eliminate_term_ite(false), m_macro_finder(false), diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index bbc91e4c6..383d98e67 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -507,7 +507,7 @@ namespace smt { m_params.m_nnf_cnf = false; if (st.m_max_ite_tree_depth > 50) { m_params.m_arith_eq2ineq = false; - m_params.m_pull_cheap_ite_trees = true; + m_params.m_pull_cheap_ite = true; m_params.m_arith_propagate_eqs = true; m_params.m_relevancy_lvl = 2; m_params.m_relevancy_lemma = false; From 534a31f74e81ab880fbb28dbf829e036d7a3957c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Mar 2018 05:06:36 -0800 Subject: [PATCH 0614/1283] inherit solver parameters in asserted formulas rewriter. #1511 Signed-off-by: Nikolaj Bjorner --- src/smt/asserted_formulas.cpp | 4 ++++ src/smt/asserted_formulas.h | 1 + src/smt/params/preprocessor_params.cpp | 1 + src/smt/smt_context.cpp | 4 ++++ src/smt/smt_context.h | 2 ++ src/smt/smt_kernel.cpp | 10 +++------- src/test/heap.cpp | 5 ++++- 7 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 5903fefcb..444069d8c 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -117,6 +117,10 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vector& mutexes) { return m_kernel.find_mutexes(vars, mutexes); } @@ -196,9 +195,7 @@ namespace smt { } void updt_params(params_ref const & p) { - // We don't need params2smt_params anymore. smt_params has support for reading params_ref. - // The update is performed at smt_kernel "users". - // params2smt_params(p, fparams()); + m_kernel.updt_params(p); } }; @@ -218,7 +215,6 @@ namespace smt { imp::copy(*src.m_imp, *dst.m_imp); } - bool kernel::set_logic(symbol logic) { return m_imp->set_logic(logic); } @@ -263,9 +259,9 @@ namespace smt { } void kernel::reset() { - ast_manager & _m = m(); + ast_manager & _m = m(); smt_params & fps = m_imp->fparams(); - params_ref ps = m_imp->params(); + params_ref ps = m_imp->params(); #pragma omp critical (smt_kernel) { m_imp->~imp(); diff --git a/src/test/heap.cpp b/src/test/heap.cpp index 08891ccaa..2c77b939e 100644 --- a/src/test/heap.cpp +++ b/src/test/heap.cpp @@ -21,16 +21,19 @@ Revision History: #include "util/heap.h" #include "util/trace.h" #include "util/uint_set.h" +// include "util/hashtable.h" struct lt_proc { bool operator()(int v1, int v2) const { return v1 < v2; } }; +//struct int_hash_proc { unsigned operator()(int v) const { std::cout << "hash " << v << "\n"; VERIFY(v >= 0); return v; }}; +//typedef int_hashtable > int_set; typedef heap int_heap; -struct int_hash_proc { unsigned operator()(int v) const { return v * 17; }}; #define N 10000 static random_gen heap_rand(1); static void tst1() { int_heap h(N); +// int_set t; uint_set t; for (int i = 0; i < N * 3; i++) { int val = heap_rand() % N; From eb1122c5cb434338e25b87e7d94c7c6d56be02f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Mar 2018 21:57:08 -0800 Subject: [PATCH 0615/1283] delay updating parameters to ensure rewriting in asserted_formulas is applied using configuration overrides. Fixes build regression for tree_interpolation documentation test Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- src/smt/asserted_formulas.cpp | 44 +++++++++++++------------- src/smt/asserted_formulas.h | 37 +++++++++++----------- src/smt/mam.cpp | 2 +- src/smt/params/preprocessor_params.cpp | 1 - src/smt/smt_context.cpp | 2 +- src/smt/smt_relevancy.cpp | 6 ++-- src/smt/theory_seq.cpp | 1 - 8 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 785649e3d..1cfb10179 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8266,7 +8266,7 @@ def tree_interpolant(pat,p=None,ctx=None): solver that determines satisfiability. >>> x = Int('x') - >>> y = Int('y') + >>> y = Int('y') >>> print(tree_interpolant(And(Interpolant(x < 0), Interpolant(y > 2), x == y))) [Not(x >= 0), Not(y <= 2)] diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 444069d8c..ab9bb0895 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -27,8 +27,9 @@ Revision History: #include "ast/macros/quasi_macros.h" #include "smt/asserted_formulas.h" -asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): +asserted_formulas::asserted_formulas(ast_manager & m, smt_params & sp, params_ref const& p): m(m), + m_smt_params(sp), m_params(p), m_rewriter(m), m_substitution(m), @@ -65,20 +66,20 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): } void asserted_formulas::setup() { - switch (m_params.m_lift_ite) { + switch (m_smt_params.m_lift_ite) { case LI_FULL: - m_params.m_ng_lift_ite = LI_NONE; + m_smt_params.m_ng_lift_ite = LI_NONE; break; case LI_CONSERVATIVE: - if (m_params.m_ng_lift_ite == LI_CONSERVATIVE) - m_params.m_ng_lift_ite = LI_NONE; + if (m_smt_params.m_ng_lift_ite == LI_CONSERVATIVE) + m_smt_params.m_ng_lift_ite = LI_NONE; break; default: break; } - if (m_params.m_relevancy_lvl == 0) - m_params.m_relevancy_lemma = false; + if (m_smt_params.m_relevancy_lvl == 0) + m_smt_params.m_relevancy_lemma = false; } @@ -118,24 +119,23 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vector l(m_check_missing_instances, true); rematch(false); diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index 57b11e7fd..ee4b7c2e4 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -25,7 +25,6 @@ void preprocessor_params::updt_local_params(params_ref const & _p) { m_quasi_macros = p.quasi_macros(); m_restricted_quasi_macros = p.restricted_quasi_macros(); m_pull_nested_quantifiers = p.pull_nested_quantifiers(); -// m_pull_cheap_ite = _p.get_bool("pull_cheap_ite", m_pull_cheap_ite); m_refine_inj_axiom = p.refine_inj_axioms(); } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 513bf7665..e20eae0bd 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -45,7 +45,7 @@ namespace smt { m_fparams(p), m_params(_p), m_setup(*this, p), - m_asserted_formulas(m, p), + m_asserted_formulas(m, p, _p), m_qmanager(alloc(quantifier_manager, *this, p, _p)), m_model_generator(alloc(model_generator, m)), m_relevancy_propagator(mk_relevancy_propagator(*this)), diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 9eabb8319..7db5110ee 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -527,7 +527,7 @@ namespace smt { } #ifdef Z3DEBUG - bool check_relevancy_app(app * n) const { + bool check_relevancy_app(app * n) const { SASSERT(is_relevant(n)); unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { @@ -537,7 +537,7 @@ namespace smt { return true; } - virtual bool check_relevancy_or(app * n, bool root) const { + bool check_relevancy_or(app * n, bool root) const override { lbool val = root ? l_true : m_context.find_assignment(n); if (val == l_false) return check_relevancy_app(n); @@ -600,7 +600,7 @@ namespace smt { return true; } - bool check_relevancy(expr_ref_vector const & v) const { + bool check_relevancy(expr_ref_vector const & v) const override { SASSERT(!can_propagate()); ast_manager & m = get_manager(); unsigned sz = v.size(); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 12764fd9d..b90735a07 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2449,7 +2449,6 @@ expr_ref theory_seq::digit2int(expr* ch) { } void theory_seq::add_itos_axiom(expr* e) { - context& ctx = get_context(); rational val; expr* n = nullptr; TRACE("seq", tout << mk_pp(e, m) << "\n";); From 718e5a9b6c481f3c0f89389f7b740a8d909e9b9b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Mar 2018 01:08:17 -0800 Subject: [PATCH 0616/1283] add unit extraction Signed-off-by: Nikolaj Bjorner --- src/ackermannization/ackr_model_converter.cpp | 2 + .../lackr_model_converter_lazy.cpp | 2 + src/api/api_solver.cpp | 16 ++++ src/api/dotnet/Solver.cs | 14 +++ src/api/python/z3/z3.py | 5 ++ src/api/z3_api.h | 7 ++ src/muz/base/dl_util.cpp | 3 + src/muz/transforms/dl_mk_bit_blast.cpp | 2 + src/muz/transforms/dl_mk_karr_invariants.cpp | 2 + .../dl_mk_quantifier_abstraction.cpp | 2 + src/muz/transforms/dl_mk_scale.cpp | 10 +-- src/muz/transforms/dl_mk_slice.cpp | 2 + src/sat/tactic/goal2sat.cpp | 6 ++ src/sat/tactic/goal2sat.h | 2 +- src/solver/solver.cpp | 34 ++++++- src/solver/solver.h | 6 +- src/tactic/arith/eq2bv_tactic.cpp | 2 + src/tactic/arith/fm_tactic.cpp | 2 + src/tactic/arith/pb2bv_model_converter.cpp | 4 + src/tactic/arith/pb2bv_model_converter.h | 1 + src/tactic/bv/bit_blaster_model_converter.cpp | 4 + src/tactic/core/pb_preprocess_tactic.cpp | 90 ++++++------------- src/tactic/generic_model_converter.cpp | 47 ++++++++++ src/tactic/generic_model_converter.h | 2 + src/tactic/horn_subsume_model_converter.h | 3 + src/tactic/model_converter.cpp | 11 ++- src/tactic/model_converter.h | 2 + 27 files changed, 207 insertions(+), 76 deletions(-) diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index 3cd86d2f1..af728c789 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -39,6 +39,8 @@ public: virtual ~ackr_model_converter() { } + virtual void get_units(obj_map& units) { units.reset(); } + virtual void operator()(model_ref & md, unsigned goal_idx) { SASSERT(goal_idx == 0); SASSERT(!fixed_model || md.get() == 0 || (!md->get_num_constants() && !md->get_num_functions())); diff --git a/src/ackermannization/lackr_model_converter_lazy.cpp b/src/ackermannization/lackr_model_converter_lazy.cpp index ffb4cae9d..e6a98dba1 100644 --- a/src/ackermannization/lackr_model_converter_lazy.cpp +++ b/src/ackermannization/lackr_model_converter_lazy.cpp @@ -43,6 +43,8 @@ public: operator()(md, 0); } + virtual void get_units(obj_map& units) { units.reset(); } + //void display(std::ostream & out); virtual model_converter * translate(ast_translation & translator) { diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 4e7719f56..b3a97cf1a 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -347,6 +347,22 @@ extern "C" { Z3_CATCH_RETURN(0); } + + Z3_ast_vector Z3_API Z3_solver_get_units(Z3_context c, Z3_solver s) { + Z3_TRY; + LOG_Z3_solver_get_units(c, s); + RESET_ERROR_CODE(); + init_solver(c, s); + Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); + mk_c(c)->save_object(v); + expr_ref_vector fmls = to_solver_ref(s)->get_units(mk_c(c)->m()); + for (expr* f : fmls) { + v->m_ast_vector.push_back(f); + } + RETURN_Z3(of_ast_vector(v)); + Z3_CATCH_RETURN(0); + } + 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]))) { diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 1a62aa8e3..cdac4af38 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -265,6 +265,20 @@ namespace Microsoft.Z3 } } + /// + /// Currently inferred units. + /// + public BoolExpr[] Units + { + get + { + Contract.Ensures(Contract.Result() != null); + + ASTVector assertions = new ASTVector(Context, Native.Z3_solver_get_units(Context.nCtx, NativeObject)); + return assertions.ToBoolExprArray(); + } + } + /// /// Checks whether the assertions in the solver are consistent or not. /// diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index cf86ee03d..58ab7bf86 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -6369,6 +6369,11 @@ class Solver(Z3PPObject): """ return AstVector(Z3_solver_get_assertions(self.ctx.ref(), self.solver), self.ctx) + def units(self): + """Return an AST vector containing all currently inferred units. + """ + return AstVector(Z3_solver_get_units(self.ctx.ref(), self.solver), self.ctx) + def statistics(self): """Return statistics for the last `check()`. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 02ca43910..47bdee359 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -6163,6 +6163,13 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_solver_get_assertions(Z3_context c, Z3_solver s); + /** + \brief Return the set of units modulo model conversion. + + def_API('Z3_solver_get_units', AST_VECTOR, (_in(CONTEXT), _in(SOLVER))) + */ + Z3_ast_vector Z3_API Z3_solver_get_units(Z3_context c, Z3_solver s); + /** \brief Check whether the assertions in a given solver are consistent or not. diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index b781a8640..89eb45195 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -387,6 +387,9 @@ namespace datalog { void operator()(model_ref&) override {} void display(std::ostream & out) override { } + + void get_units(obj_map& units) override {} + }; model_converter* mk_skip_model_converter() { return alloc(skip_model_converter); } diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 4d4c22780..ffbf5fe92 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -63,6 +63,8 @@ namespace datalog { return alloc(bit_blast_model_converter, m); } + virtual void get_units(obj_map& units) {} + virtual void display(std::ostream& out) { out << "(bit-blast-model-converter)\n"; } virtual void operator()(model_ref & model) { diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 678c673a8..a9984ed8a 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -120,6 +120,8 @@ namespace datalog { } } + virtual void get_units(obj_map& units) {} + virtual void operator()(model_ref & mr) { for (unsigned i = 0; i < m_funcs.size(); ++i) { func_decl* p = m_funcs[i].get(); diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index 888e1ebb5..c2d1fe6c5 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -55,6 +55,8 @@ namespace datalog { virtual void display(std::ostream& out) { display_add(out, m); } + virtual void get_units(obj_map& units) { units.reset(); } + void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector const& bound) { m_old_funcs.push_back(old_p); m_new_funcs.push_back(new_p); diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index 5eeaaaeca..1ddf80383 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -38,13 +38,13 @@ namespace datalog { m_new2old.insert(new_f, old_f); } + virtual void get_units(obj_map& units) { units.reset(); } + virtual void operator()(model_ref& md) { model_ref old_model = alloc(model, m); - obj_map::iterator it = m_new2old.begin(); - obj_map::iterator end = m_new2old.end(); - for (; it != end; ++it) { - func_decl* old_p = it->m_value; - func_decl* new_p = it->m_key; + for (auto const& kv : m_new2old) { + func_decl* old_p = kv.m_value; + func_decl* new_p = kv.m_key; func_interp* old_fi = alloc(func_interp, m, old_p->get_arity()); if (new_p->get_arity() == 0) { diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index ce1b8e582..1182e8c61 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -308,6 +308,8 @@ namespace datalog { m_sliceable.insert(f, bv); } + void get_units(obj_map& units) override {} + void operator()(model_ref & md) override { if (m_slice2old.empty()) { return; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 305bed175..87742d27a 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -981,6 +981,12 @@ void sat2goal::mc::display(std::ostream& out) { if (m_gmc) m_gmc->display(out); } +void sat2goal::mc::get_units(obj_map& units) { + flush_gmc(); + if (m_gmc) m_gmc->get_units(units); +} + + void sat2goal::mc::operator()(model_ref & md) { model_evaluator ev(*md); ev.set_model_completion(false); diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 463a50ff6..32b89fe5d 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -94,7 +94,7 @@ public: model_converter* translate(ast_translation& translator) override; void collect(ast_pp_util& visitor) override; void display(std::ostream& out) override; - + void get_units(obj_map& units) override; app* var2expr(sat::bool_var v) const { return m_var2expr.get(v, nullptr); } expr_ref lit2expr(sat::literal l); void insert(sat::bool_var v, app * atom, bool aux); diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 3a772e7f2..980821695 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -211,7 +211,35 @@ void solver::updt_params(params_ref const & p) { m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); } -void solver::hoist_converter(model_converter_ref& mc) { - -} +expr_ref_vector solver::get_units(ast_manager& m) { + expr_ref_vector fmls(m), result(m), tmp(m); + get_assertions(fmls); + obj_map units; + for (expr* f : fmls) { + if (m.is_not(f, f) && is_literal(m, f)) { + m.inc_ref(f); + units.insert(f, false); + } + else if (is_literal(m, f)) { + m.inc_ref(f); + units.insert(f, true); + } + } + model_converter_ref mc = get_model_converter(); + if (mc) { + mc->get_units(units); + } + for (auto const& kv : units) { + tmp.push_back(kv.m_key); + if (kv.m_value) + result.push_back(kv.m_key); + else + result.push_back(m.mk_not(kv.m_key)); + } + for (expr* e : tmp) { + m.dec_ref(e); + } + + return result; +} diff --git a/src/solver/solver.h b/src/solver/solver.h index 5bd25d8a6..f7e622a8b 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -203,6 +203,11 @@ public: virtual model_converter_ref get_model_converter() const { return m_mc0; } + /** + \brief extract units from solver. + */ + expr_ref_vector get_units(ast_manager& m); + class scoped_push { solver& s; bool m_nopop; @@ -220,7 +225,6 @@ protected: bool is_literal(ast_manager& m, expr* e); - void hoist_converter(model_converter_ref& mc); }; typedef ref solver_ref; diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 50dd142e6..3fcc3c7e9 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -119,6 +119,8 @@ class eq2bv_tactic : public tactic { } } + virtual void get_units(obj_map& units) { units.reset(); } + }; public: diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index fac826811..8a65e1efc 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -180,6 +180,8 @@ class fm_tactic : public tactic { m_clauses.back().swap(c); } + virtual void get_units(obj_map& units) { units.reset(); } + virtual void operator()(model_ref & md) { TRACE("fm_mc", model_v2_pp(tout, *md); display(tout);); model_evaluator ev(*(md.get())); diff --git a/src/tactic/arith/pb2bv_model_converter.cpp b/src/tactic/arith/pb2bv_model_converter.cpp index 16deb7cd7..d7227b15b 100644 --- a/src/tactic/arith/pb2bv_model_converter.cpp +++ b/src/tactic/arith/pb2bv_model_converter.cpp @@ -50,6 +50,10 @@ pb2bv_model_converter::~pb2bv_model_converter() { } } +void pb2bv_model_converter::get_units(obj_map& units) { + if (!m_c2bit.empty()) units.reset(); +} + void pb2bv_model_converter::operator()(model_ref & md) { TRACE("pb2bv", tout << "converting model:\n"; model_v2_pp(tout, *md); display(tout);); diff --git a/src/tactic/arith/pb2bv_model_converter.h b/src/tactic/arith/pb2bv_model_converter.h index 59825b10f..7679112f8 100644 --- a/src/tactic/arith/pb2bv_model_converter.h +++ b/src/tactic/arith/pb2bv_model_converter.h @@ -33,6 +33,7 @@ public: virtual ~pb2bv_model_converter(); void operator()(model_ref & md) override; void display(std::ostream & out) override; + void get_units(obj_map& units) override; model_converter * translate(ast_translation & translator) override; }; diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 3ead0876a..6ace1300a 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -206,6 +206,10 @@ struct bit_blaster_model_converter : public model_converter { } } + void get_units(obj_map& units) override { + // no-op + } + protected: bit_blaster_model_converter(ast_manager & m):m_vars(m), m_bits(m) { } public: diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index 4ed55b0d2..cd6dc063c 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -33,60 +33,13 @@ Notes: --*/ #include "tactic/core/pb_preprocess_tactic.h" #include "tactic/tactical.h" +#include "tactic/generic_model_converter.h" #include "ast/for_each_expr.h" #include "ast/pb_decl_plugin.h" #include "ast/rewriter/th_rewriter.h" #include "ast/expr_substitution.h" #include "ast/ast_pp.h" -class pb_preproc_model_converter : public model_converter { - ast_manager& m; - pb_util pb; - expr_ref_vector m_refs; - svector > m_const; - -public: - pb_preproc_model_converter(ast_manager& m):m(m), pb(m), m_refs(m) {} - - virtual void operator()(model_ref & mdl) { - for (auto const& kv : m_const) { - mdl->register_decl(kv.first->get_decl(), kv.second); - } - } - - void set_value(expr* e, bool p) { - while (m.is_not(e, e)) { - p = !p; - } - SASSERT(is_app(e)); - set_value_p(to_app(e), p?m.mk_true():m.mk_false()); - } - - virtual model_converter * translate(ast_translation & translator) { - pb_preproc_model_converter* mc = alloc(pb_preproc_model_converter, translator.to()); - for (auto const& kv : m_const) { - mc->set_value_p(translator(kv.first), translator(kv.second)); - } - return mc; - } - - virtual void display(std::ostream & out) { - for (auto const& kv : m_const) { - out << "(model-set " << mk_pp(kv.first, m) << " " << mk_pp(kv.second, m) << ")\n"; - } - } - -private: - void set_value_p(app* e, expr* v) { - SASSERT(e->get_num_args() == 0); - SASSERT(is_uninterp_const(e)); - m_const.push_back(std::make_pair(e, v)); - m_refs.push_back(e); - m_refs.push_back(v); - } - -}; - class pb_preprocess_tactic : public tactic { struct rec { unsigned_vector pos, neg; rec() { } }; typedef obj_map var_map; @@ -119,24 +72,31 @@ class pb_preprocess_tactic : public tactic { for (unsigned i = 0; i < m_other.size(); ++i) { out << "ot " << m_other[i] << ": " << mk_pp(g->form(m_other[i]), m) << "\n"; } - - var_map::iterator it = m_vars.begin(); - var_map::iterator end = m_vars.end(); - for (; it != end; ++it) { - app* e = it->m_key; - unsigned_vector const& pos = it->m_value.pos; - unsigned_vector const& neg = it->m_value.neg; + + for (auto const& kv : m_vars) { + app* e = kv.m_key; + unsigned_vector const& pos = kv.m_value.pos; + unsigned_vector const& neg = kv.m_value.neg; out << mk_pp(e, m) << ": "; - for (unsigned i = 0; i < pos.size(); ++i) { - out << "p: " << pos[i] << " "; + for (unsigned p : pos) { + out << "p: " << p << " "; } - for (unsigned i = 0; i < neg.size(); ++i) { - out << "n: " << neg[i] << " "; + for (unsigned n : neg) { + out << "n: " << n << " "; } out << "\n"; } } + void set_value(generic_model_converter& mc, expr* e, bool p) { + while (m.is_not(e, e)) { + p = !p; + } + SASSERT(is_app(e)); + mc.add(to_app(e), p?m.mk_true():m.mk_false()); + } + + public: pb_preprocess_tactic(ast_manager& m, params_ref const& p = params_ref()): m(m), pb(m), m_r(m) {} @@ -156,7 +116,7 @@ public: throw tactic_exception("pb-preprocess does not support proofs"); } - pb_preproc_model_converter* pp = alloc(pb_preproc_model_converter, m); + generic_model_converter* pp = alloc(generic_model_converter, m, "pb-preprocess"); g->add(pp); g->inc_depth(); @@ -165,7 +125,7 @@ public: // decompose(g); } - bool simplify(goal_ref const& g, pb_preproc_model_converter& mc) { + bool simplify(goal_ref const& g, generic_model_converter& mc) { reset(); normalize(g); if (g->inconsistent()) { @@ -203,11 +163,11 @@ public: TRACE("pb", tout << mk_pp(e, m) << " " << r.pos.size() << " " << r.neg.size() << "\n";); if (r.pos.empty()) { replace(r.neg, e, m.mk_false(), g); - mc.set_value(e, false); + set_value(mc, e, false); } else if (r.neg.empty()) { replace(r.pos, e, m.mk_true(), g); - mc.set_value(e, true); + set_value(mc, e, true); } if (g->inconsistent()) return false; ++it; @@ -509,7 +469,7 @@ private: // Implement very special case of resolution. - void resolve(pb_preproc_model_converter& mc, unsigned idx1, + void resolve(generic_model_converter& mc, unsigned idx1, unsigned_vector const& positions, app* e, bool pos, goal_ref const& g) { if (positions.size() != 1) return; unsigned idx2 = positions[0]; @@ -558,7 +518,7 @@ private: else { args2[j] = m.mk_true(); } - mc.set_value(arg, j != min_index); + set_value(mc, arg, j != min_index); } tmp1 = pb.mk_ge(args2.size(), coeffs2.c_ptr(), args2.c_ptr(), k2); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 485682858..c51adf8da 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -181,6 +181,53 @@ void generic_model_converter::operator()(expr_ref& fml) { fml = mk_and(fmls); } +void generic_model_converter::get_units(obj_map& units) { + th_rewriter rw(m); + expr_safe_replace rep(m); + expr_ref tmp(m); + bool val = false; + expr* f = nullptr; + for (auto const& kv : units) { + rep.insert(kv.m_key, kv.m_value ? m.mk_true() : m.mk_false()); + } + for (unsigned i = m_entries.size(); i-- > 0;) { + entry const& e = m_entries[i]; + switch (e.m_instruction) { + case HIDE: + tmp = m.mk_const(e.m_f); + if (units.contains(tmp)) { + m.dec_ref(tmp); + units.remove(tmp); + } + break; + case ADD: + if (e.m_f->get_arity() == 0 && m.is_bool(e.m_f->get_range())) { + tmp = m.mk_const(e.m_f); + if (units.contains(tmp)) { + break; + } + tmp = e.m_def; + rep(tmp); + rw(tmp); + if (m.is_true(tmp)) { + tmp = m.mk_const(e.m_f); + m.inc_ref(tmp); + units.insert(tmp, true); + rep.insert(tmp, m.mk_true()); + } + else if (m.is_false(tmp)) { + tmp = m.mk_const(e.m_f); + m.inc_ref(tmp); + units.insert(tmp, false); + rep.insert(tmp, m.mk_false()); + } + } + break; + } + } +} + + /* \brief simplify definition expansion from model converter in the case they come from blocked clauses. In this case the definitions are of the form: diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index a85cc9766..ebac1f6d9 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -71,6 +71,8 @@ public: void collect(ast_pp_util& visitor) override; void operator()(expr_ref& fml) override; + + void get_units(obj_map& units) override; }; typedef ref generic_model_converter_ref; diff --git a/src/tactic/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h index 9b094e575..6d27ceec2 100644 --- a/src/tactic/horn_subsume_model_converter.h +++ b/src/tactic/horn_subsume_model_converter.h @@ -80,6 +80,9 @@ public: ast_manager& get_manager() { return m; } void display(std::ostream & out) override {} + + void get_units(obj_map& units) override { units.reset(); } + }; #endif diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index ef04af15f..296c2007b 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -71,14 +71,19 @@ public: } void operator()(expr_ref & fml) override { - this->m_c1->operator()(fml); this->m_c2->operator()(fml); + this->m_c1->operator()(fml); } void operator()(labels_vec & r) override { this->m_c2->operator()(r); this->m_c1->operator()(r); } + + void get_units(obj_map& fmls) override { + m_c2->get_units(fmls); + m_c1->get_units(fmls); + } char const * get_name() const override { return "concat-model-converter"; } @@ -125,6 +130,10 @@ public: fml = r; } + void get_units(obj_map& fmls) override { + // no-op + } + void cancel() override { } diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index d4991e672..cd8fb5ee3 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -88,6 +88,8 @@ public: formula and removing these definitions from the model converter. */ virtual void operator()(expr_ref& formula) { UNREACHABLE(); } + + virtual void get_units(obj_map& fmls) { UNREACHABLE(); } }; typedef ref model_converter_ref; From d3ceb8c7944124839d4a3473ccbea7c5b0eaf57d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Mar 2018 13:33:37 -0800 Subject: [PATCH 0617/1283] radix sort experiment Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 27 +++++++++++++++++++++++++++ src/sat/sat_asymm_branch.h | 3 +++ 2 files changed, 30 insertions(+) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 64b1d5e67..40bba0e93 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -224,6 +224,22 @@ namespace sat { sort(big, c.begin(), c.end()); } + void asymm_branch::radix_sort(big& big, literal_vector& lits) { + const unsigned d = 4; + const unsigned w = 20; // 1M variable cap + unsigned sz = lits.size(); + m_tmp.reserve(sz); + for (unsigned p = 0; p < w/d; ++p) { + unsigned on[16]; + memset(on, 0, 16*sizeof(unsigned)); + for (literal l : lits) on[(big.get_left(l) >> 4*p) & 15]++; + for (unsigned i = 1; i < 16; ++i) on[i] += on[i-1]; + for (unsigned i = sz; i-- > 0; ) + m_tmp[--on[(big.get_left(lits[i]) >> 4*p) & 15]] = lits[i]; + for (unsigned i = sz; i-- > 0; ) lits[i] = m_tmp[i]; + } + } + void asymm_branch::sort(big& big, literal const* begin, literal const* end) { m_pos.reset(); m_neg.reset(); for (; begin != end; ++begin) { @@ -231,9 +247,20 @@ namespace sat { m_pos.push_back(l); m_neg.push_back(~l); } +#if 0 compare_left cmp(big); std::sort(m_pos.begin(), m_pos.end(), cmp); std::sort(m_neg.begin(), m_neg.end(), cmp); +#else + radix_sort(big, m_pos); + radix_sort(big, m_neg); +#endif + IF_VERBOSE(100, + for (literal l : m_pos) verbose_stream() << big.get_left(l) << " "; + verbose_stream() << "\n"; + for (literal l : m_neg) verbose_stream() << big.get_left(l) << " "; + verbose_stream() << "\n"; + ); } bool asymm_branch::uhte(big& big, clause & c) { diff --git a/src/sat/sat_asymm_branch.h b/src/sat/sat_asymm_branch.h index cc354a5c8..6034ce5f3 100644 --- a/src/sat/sat_asymm_branch.h +++ b/src/sat/sat_asymm_branch.h @@ -51,12 +51,15 @@ namespace sat { unsigned m_tr; literal_vector m_pos, m_neg; // literals (complements of literals) in clauses sorted by discovery time (m_left in BIG). + svector> m_pos1, m_neg1; literal_vector m_to_delete; + literal_vector m_tmp; struct compare_left; void sort(big& big, literal const* begin, literal const* end); void sort(big & big, clause const& c); + void radix_sort(big & big, literal_vector& lits); bool uhle(scoped_detach& scoped_d, big & big, clause & c); From f04e805fa4da46c5a305fb6a6fab773c34140a61 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Mar 2018 18:02:37 -0800 Subject: [PATCH 0618/1283] add hiding to auxiliary declarations created in mc Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 4 +++- src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp | 3 +++ src/cmd_context/cmd_context.cpp | 3 ++- src/sat/sat_asymm_branch.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 8 ++++---- src/tactic/generic_model_converter.cpp | 7 +++++-- src/tactic/generic_model_converter.h | 2 +- src/tactic/model_converter.cpp | 2 +- 8 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index ba591083f..8d35ae8bb 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1718,11 +1718,13 @@ ast * ast_manager::register_node_core(ast * n) { n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); +#if 0 static unsigned count = 0; - if (n->m_id == 404) { + if (n->m_id == 1293522) { ++count; //if (count == 2) SASSERT(false); } +#endif 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/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index 3573d44f3..bcef44440 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -15,6 +15,9 @@ Author: Notes: + TBD: also keep track of which fresh constants are introduced + to instruct model converter to delete them. + --*/ #include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h" #include "ast/bv_decl_plugin.h" diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index f82f8868d..ddcaa0b03 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -870,11 +870,12 @@ void cmd_context::model_add(symbol const & s, unsigned arity, sort *const* domai dictionary::entry * e = m_func_decls.insert_if_not_there2(s, func_decls()); func_decls & fs = e->get_data().m_value; fs.insert(m(), fn); + VERIFY(fn->get_range() == m().get_sort(t)); m_mc0->add(fn, t); } void cmd_context::model_del(func_decl* f) { - if (!m_mc0.get()) m_mc0 = alloc(generic_model_converter, m(), "model_del"); + if (!m_mc0.get()) m_mc0 = alloc(generic_model_converter, m(), "cmd_context"); if (m_solver.get() && !m_solver->mc0()) m_solver->set_model_converter(m_mc0.get()); m_mc0->hide(f); } diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 5822d7cef..35d594b34 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -245,7 +245,7 @@ namespace sat { m_pos.push_back(l); m_neg.push_back(~l); } -#if 0 +#if 1 compare_left cmp(big); std::sort(m_pos.begin(), m_pos.end(), cmp); std::sort(m_neg.begin(), m_neg.end(), cmp); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 87742d27a..1b0e0ebae 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -142,7 +142,6 @@ struct goal2sat::imp { sat::bool_var v = m_solver.mk_var(ext); m_map.insert(t, v); l = sat::literal(v, sign); - // if (to_app(t)->get_decl()->get_name() == "XX") IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(t, m) << ": " << "v" << v << "\n";); TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";); if (ext && !is_uninterp_const(t)) { m_interpreted_atoms.push_back(t); @@ -1051,8 +1050,9 @@ void sat2goal::mc::insert(sat::bool_var v, app * atom, bool aux) { expr_ref sat2goal::mc::lit2expr(sat::literal l) { if (!m_var2expr.get(l.var())) { app* aux = m.mk_fresh_const(0, m.mk_bool_sort()); - // if (aux->get_decl()->get_name() == "k!81740") IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(aux, m) << ": " << "v" << l.var() << "\n";); m_var2expr.set(l.var(), aux); + if (!m_gmc) m_gmc = alloc(generic_model_converter, m, "sat2goal"); + m_gmc->hide(aux->get_decl()); } VERIFY(m_var2expr.get(l.var())); expr_ref result(m_var2expr.get(l.var()), m); @@ -1094,9 +1094,9 @@ struct sat2goal::imp { app* aux = mc ? mc->var2expr(l.var()) : nullptr; if (!aux) { aux = m.mk_fresh_const(0, m.mk_bool_sort()); - // if (aux->get_decl()->get_name() == "k!81740") IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(aux, m) << ": " << "v" << l.var() << "\n";); - if (mc) + if (mc) { mc->insert(l.var(), aux, true); + } } sat::literal lit(l.var(), false); m_lit2expr.set(lit.index(), aux); diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index c51adf8da..ddc396597 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -28,9 +28,12 @@ Notes: #include "model/model_evaluator.h" +generic_model_converter::~generic_model_converter() { +} + void generic_model_converter::add(func_decl * d, expr* e) { VERIFY(e); - struct entry et(d, e, m, ADD); + entry et(d, e, m, ADD); VERIFY(d->get_range() == m.get_sort(e)); m_first_idx.insert_if_not_there(et.m_f, m_entries.size()); m_entries.push_back(et); @@ -169,7 +172,7 @@ void generic_model_converter::operator()(expr_ref& fml) { } unsigned j = min_idx; for (unsigned i = min_idx; i < m_entries.size(); ++i) { - entry const& e = m_entries[i]; + entry& e = m_entries[i]; if (e.m_instruction == instruction::HIDE) { if (i != j) { m_entries[j] = e; diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index ebac1f6d9..d303fb2e3 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -48,7 +48,7 @@ class generic_model_converter : public model_converter { public: generic_model_converter(ast_manager & m, char const* orig) : m(m), m_orig(orig) {} - virtual ~generic_model_converter() { } + virtual ~generic_model_converter(); void hide(expr* e) { SASSERT(is_app(e) && to_app(e)->get_num_args() == 0); hide(to_app(e)->get_decl()); } diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 296c2007b..127b6f5a0 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -24,7 +24,7 @@ Notes: * Add or overwrite value in model. */ void model_converter::display_add(std::ostream& out, ast_manager& m, func_decl* f, expr* e) const { - VERIFY(e); + VERIFY(e); smt2_pp_environment_dbg env(m); smt2_pp_environment* _env = m_env ? m_env : &env; VERIFY(f->get_range() == m.get_sort(e)); From 4cc936285113df07f6492cf791f7850e933cda54 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 7 Mar 2018 13:18:39 +0700 Subject: [PATCH 0619/1283] Make proof_checker more const correct. --- src/ast/proofs/proof_checker.cpp | 52 ++++++++++++++++---------------- src/ast/proofs/proof_checker.h | 50 +++++++++++++++--------------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 9ba52a402..bd50e6c2a 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -922,7 +922,7 @@ void proof_checker::set_false(expr_ref& e, unsigned position, expr_ref& lit) { } } -bool proof_checker::match_fact(proof* p, expr_ref& fact) { +bool proof_checker::match_fact(proof const* p, expr_ref& fact) const { if (m.is_proof(p) && m.has_fact(p)) { fact = m.get_fact(p); @@ -938,13 +938,13 @@ void proof_checker::add_premise(proof* p) { } } -bool proof_checker::match_proof(proof* p) { +bool proof_checker::match_proof(proof const* p) const { return m.is_proof(p) && m.get_num_parents(p) == 0; } -bool proof_checker::match_proof(proof* p, proof_ref& p0) { +bool proof_checker::match_proof(proof const* p, proof_ref& p0) const { if (m.is_proof(p) && m.get_num_parents(p) == 1) { p0 = m.get_parent(p, 0); @@ -953,7 +953,7 @@ bool proof_checker::match_proof(proof* p, proof_ref& p0) { return false; } -bool proof_checker::match_proof(proof* p, proof_ref& p0, proof_ref& p1) { +bool proof_checker::match_proof(proof const* p, proof_ref& p0, proof_ref& p1) const { if (m.is_proof(p) && m.get_num_parents(p) == 2) { p0 = m.get_parent(p, 0); @@ -963,7 +963,7 @@ bool proof_checker::match_proof(proof* p, proof_ref& p0, proof_ref& p1) { return false; } -bool proof_checker::match_proof(proof* p, proof_ref_vector& parents) { +bool proof_checker::match_proof(proof const* p, proof_ref_vector& parents) const { if (m.is_proof(p)) { for (unsigned i = 0; i < m.get_num_parents(p); ++i) { parents.push_back(m.get_parent(p, i)); @@ -974,7 +974,7 @@ bool proof_checker::match_proof(proof* p, proof_ref_vector& parents) { } -bool proof_checker::match_binary(expr* e, func_decl_ref& d, expr_ref& t1, expr_ref& t2) { +bool proof_checker::match_binary(expr const* e, func_decl_ref& d, expr_ref& t1, expr_ref& t2) const { if (e->get_kind() == AST_APP && to_app(e)->get_num_args() == 2) { d = to_app(e)->get_decl(); @@ -986,7 +986,7 @@ bool proof_checker::match_binary(expr* e, func_decl_ref& d, expr_ref& t1, expr_r } -bool proof_checker::match_app(expr* e, func_decl_ref& d, expr_ref_vector& terms) { +bool proof_checker::match_app(expr const* e, func_decl_ref& d, expr_ref_vector& terms) const { if (e->get_kind() == AST_APP) { d = to_app(e)->get_decl(); for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { @@ -997,9 +997,9 @@ bool proof_checker::match_app(expr* e, func_decl_ref& d, expr_ref_vector& terms) return false; } -bool proof_checker::match_quantifier(expr* e, bool& is_univ, sort_ref_vector& sorts, expr_ref& body) { +bool proof_checker::match_quantifier(expr const* e, bool& is_univ, sort_ref_vector& sorts, expr_ref& body) const { if (is_quantifier(e)) { - quantifier* q = to_quantifier(e); + quantifier const* q = to_quantifier(e); is_univ = q->is_forall(); body = q->get_expr(); for (unsigned i = 0; i < q->get_num_decls(); ++i) { @@ -1010,7 +1010,7 @@ bool proof_checker::match_quantifier(expr* e, bool& is_univ, sort_ref_vector& so return false; } -bool proof_checker::match_op(expr* e, decl_kind k, expr_ref& t1, expr_ref& t2) { +bool proof_checker::match_op(expr const* e, decl_kind k, expr_ref& t1, expr_ref& t2) const { if (e->get_kind() == AST_APP && to_app(e)->get_family_id() == m.get_basic_family_id() && to_app(e)->get_decl_kind() == k && @@ -1022,7 +1022,7 @@ bool proof_checker::match_op(expr* e, decl_kind k, expr_ref& t1, expr_ref& t2) { return false; } -bool proof_checker::match_op(expr* e, decl_kind k, expr_ref_vector& terms) { +bool proof_checker::match_op(expr const* e, decl_kind k, expr_ref_vector& terms) const { if (e->get_kind() == AST_APP && to_app(e)->get_family_id() == m.get_basic_family_id() && to_app(e)->get_decl_kind() == k) { @@ -1035,7 +1035,7 @@ bool proof_checker::match_op(expr* e, decl_kind k, expr_ref_vector& terms) { } -bool proof_checker::match_op(expr* e, decl_kind k, expr_ref& t) { +bool proof_checker::match_op(expr const* e, decl_kind k, expr_ref& t) const { if (e->get_kind() == AST_APP && to_app(e)->get_family_id() == m.get_basic_family_id() && to_app(e)->get_decl_kind() == k && @@ -1046,39 +1046,39 @@ bool proof_checker::match_op(expr* e, decl_kind k, expr_ref& t) { return false; } -bool proof_checker::match_not(expr* e, expr_ref& t) { +bool proof_checker::match_not(expr const* e, expr_ref& t) const { return match_op(e, OP_NOT, t); } -bool proof_checker::match_or(expr* e, expr_ref_vector& terms) { +bool proof_checker::match_or(expr const* e, expr_ref_vector& terms) const { return match_op(e, OP_OR, terms); } -bool proof_checker::match_and(expr* e, expr_ref_vector& terms) { +bool proof_checker::match_and(expr const* e, expr_ref_vector& terms) const { return match_op(e, OP_AND, terms); } -bool proof_checker::match_iff(expr* e, expr_ref& t1, expr_ref& t2) { +bool proof_checker::match_iff(expr const* e, expr_ref& t1, expr_ref& t2) const { return match_op(e, OP_IFF, t1, t2); } -bool proof_checker::match_equiv(expr* e, expr_ref& t1, expr_ref& t2) { +bool proof_checker::match_equiv(expr const* e, expr_ref& t1, expr_ref& t2) const { return match_oeq(e, t1, t2) || match_eq(e, t1, t2); } -bool proof_checker::match_implies(expr* e, expr_ref& t1, expr_ref& t2) { +bool proof_checker::match_implies(expr const* e, expr_ref& t1, expr_ref& t2) const { return match_op(e, OP_IMPLIES, t1, t2); } -bool proof_checker::match_eq(expr* e, expr_ref& t1, expr_ref& t2) { +bool proof_checker::match_eq(expr const* e, expr_ref& t1, expr_ref& t2) const { return match_op(e, OP_EQ, t1, t2) || match_iff(e, t1, t2); } -bool proof_checker::match_oeq(expr* e, expr_ref& t1, expr_ref& t2) { +bool proof_checker::match_oeq(expr const* e, expr_ref& t1, expr_ref& t2) const { return match_op(e, OP_OEQ, t1, t2); } -bool proof_checker::match_negated(expr* a, expr* b) { +bool proof_checker::match_negated(expr const* a, expr* b) const { expr_ref t(m); return (match_not(a, t) && t.get() == b) || @@ -1186,14 +1186,14 @@ void proof_checker::get_hypotheses(proof* p, expr_ref_vector& ante) { } -bool proof_checker::match_nil(expr* e) const { +bool proof_checker::match_nil(expr const* e) const { return is_app(e) && to_app(e)->get_family_id() == m_hyp_fid && to_app(e)->get_decl_kind() == OP_NIL; } -bool proof_checker::match_cons(expr* e, expr_ref& a, expr_ref& b) const { +bool proof_checker::match_cons(expr const* e, expr_ref& a, expr_ref& b) const { if (is_app(e) && to_app(e)->get_family_id() == m_hyp_fid && to_app(e)->get_decl_kind() == OP_CONS) { @@ -1205,7 +1205,7 @@ bool proof_checker::match_cons(expr* e, expr_ref& a, expr_ref& b) const { } -bool proof_checker::match_atom(expr* e, expr_ref& a) const { +bool proof_checker::match_atom(expr const* e, expr_ref& a) const { if (is_app(e) && to_app(e)->get_family_id() == m_hyp_fid && to_app(e)->get_decl_kind() == OP_ATOM) { @@ -1227,7 +1227,7 @@ expr* proof_checker::mk_nil() { return m_nil.get(); } -bool proof_checker::is_hypothesis(proof* p) const { +bool proof_checker::is_hypothesis(proof const* p) const { return m.is_proof(p) && p->get_decl_kind() == PR_HYPOTHESIS; @@ -1253,7 +1253,7 @@ expr* proof_checker::mk_hyp(unsigned num_hyps, expr * const * hyps) { } } -void proof_checker::dump_proof(proof * pr) { +void proof_checker::dump_proof(proof const* pr) { if (!m_dump_lemmas) return; SASSERT(m.has_fact(pr)); diff --git a/src/ast/proofs/proof_checker.h b/src/ast/proofs/proof_checker.h index ccb815c61..ac0e31dbd 100644 --- a/src/ast/proofs/proof_checker.h +++ b/src/ast/proofs/proof_checker.h @@ -77,39 +77,39 @@ private: bool check1_spc(proof* p, expr_ref_vector& side_conditions); bool check_arith_proof(proof* p); bool check_arith_literal(bool is_pos, app* lit, rational const& coeff, expr_ref& sum, bool& is_strict); - bool match_fact(proof* p, expr_ref& fact); + bool match_fact(proof const* p, expr_ref& fact) const; void add_premise(proof* p); - bool match_proof(proof* p); - bool match_proof(proof* p, proof_ref& p0); - bool match_proof(proof* p, proof_ref& p0, proof_ref& p1); - bool match_proof(proof* p, proof_ref_vector& parents); - bool match_binary(expr* e, func_decl_ref& d, expr_ref& t1, expr_ref& t2); - bool match_op(expr* e, decl_kind k, expr_ref& t1, expr_ref& t2); - bool match_op(expr* e, decl_kind k, expr_ref& t); - bool match_op(expr* e, decl_kind k, expr_ref_vector& terms); - bool match_iff(expr* e, expr_ref& t1, expr_ref& t2); - bool match_implies(expr* e, expr_ref& t1, expr_ref& t2); - bool match_eq(expr* e, expr_ref& t1, expr_ref& t2); - bool match_oeq(expr* e, expr_ref& t1, expr_ref& t2); - bool match_not(expr* e, expr_ref& t); - bool match_or(expr* e, expr_ref_vector& terms); - bool match_and(expr* e, expr_ref_vector& terms); - bool match_app(expr* e, func_decl_ref& d, expr_ref_vector& terms); - bool match_quantifier(expr*, bool& is_univ, sort_ref_vector&, expr_ref& body); - bool match_negated(expr* a, expr* b); - bool match_equiv(expr* a, expr_ref& t1, expr_ref& t2); + bool match_proof(proof const* p) const; + bool match_proof(proof const* p, proof_ref& p0) const; + bool match_proof(proof const* p, proof_ref& p0, proof_ref& p1) const; + bool match_proof(proof const* p, proof_ref_vector& parents) const; + bool match_binary(expr const* e, func_decl_ref& d, expr_ref& t1, expr_ref& t2) const; + bool match_op(expr const* e, decl_kind k, expr_ref& t1, expr_ref& t2) const; + bool match_op(expr const* e, decl_kind k, expr_ref& t) const; + bool match_op(expr const* e, decl_kind k, expr_ref_vector& terms) const; + bool match_iff(expr const* e, expr_ref& t1, expr_ref& t2) const; + bool match_implies(expr const* e, expr_ref& t1, expr_ref& t2) const; + bool match_eq(expr const* e, expr_ref& t1, expr_ref& t2) const; + bool match_oeq(expr const* e, expr_ref& t1, expr_ref& t2) const; + bool match_not(expr const* e, expr_ref& t) const; + bool match_or(expr const* e, expr_ref_vector& terms) const; + bool match_and(expr const* e, expr_ref_vector& terms) const; + bool match_app(expr const* e, func_decl_ref& d, expr_ref_vector& terms) const; + bool match_quantifier(expr const*, bool& is_univ, sort_ref_vector&, expr_ref& body) const; + bool match_negated(expr const* a, expr* b) const; + bool match_equiv(expr const* a, expr_ref& t1, expr_ref& t2) const; void get_ors(expr* e, expr_ref_vector& ors); void get_hypotheses(proof* p, expr_ref_vector& ante); - bool match_nil(expr* e) const; - bool match_cons(expr* e, expr_ref& a, expr_ref& b) const; - bool match_atom(expr* e, expr_ref& a) const; + bool match_nil(expr const* e) const; + bool match_cons(expr const* e, expr_ref& a, expr_ref& b) const; + bool match_atom(expr const* e, expr_ref& a) const; expr* mk_nil(); expr* mk_cons(expr* a, expr* b); expr* mk_atom(expr* e); - bool is_hypothesis(proof* p) const; + bool is_hypothesis(proof const* p) const; expr* mk_hyp(unsigned num_hyps, expr * const * hyps); - void dump_proof(proof * pr); + void dump_proof(proof const* pr); void dump_proof(unsigned num_antecedents, expr * const * antecedents, expr * consequent); void set_false(expr_ref& e, unsigned idx, expr_ref& lit); From 0b54a915131526df59208def2fa097fd6fd1dbb1 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 7 Mar 2018 13:29:13 +0700 Subject: [PATCH 0620/1283] Force color output with Ninja. --- CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69a0ca123..a222551ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,6 +409,20 @@ list(APPEND Z3_DEPENDENT_LIBS ${CMAKE_THREAD_LIBS_INIT}) ################################################################################ include(${CMAKE_SOURCE_DIR}/cmake/compiler_warnings.cmake) +################################################################################ +# If using Ninja, force color output for Clang and gcc. +################################################################################ +if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja") + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics") + endif() + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color") + endif() +endif() + ################################################################################ # Option to control what type of library we build ################################################################################ From 246941f2d30b9865229759e0d8707fc8c7de6763 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Mar 2018 14:26:38 -0800 Subject: [PATCH 0621/1283] fix #1522 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 53 +++++++++++++++++++------------------ src/ast/ast_pp_util.cpp | 7 ++++- src/ast/ast_pp_util.h | 4 +++ src/muz/base/dl_context.cpp | 32 +++++++++++++--------- src/test/quant_elim.cpp | 2 ++ 5 files changed, 58 insertions(+), 40 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index c27651fca..127967374 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1536,34 +1536,35 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { // assigned in the order that they are created, this can result in differing // family ids. To avoid this, we first assign all family ids and only then inherit plugins. for (family_id fid = 0; from.m_family_manager.has_family(fid); fid++) { - symbol fid_name = from.get_family_name(fid); - if (!m_family_manager.has_family(fid)) { - family_id new_fid = mk_family_id(fid_name); - (void)new_fid; - TRACE("copy_families_plugins", tout << "new target fid created: " << new_fid << " fid_name: " << fid_name << "\n";); - } + symbol fid_name = from.get_family_name(fid); + if (!m_family_manager.has_family(fid)) { + family_id new_fid = mk_family_id(fid_name); + (void)new_fid; + TRACE("copy_families_plugins", tout << "new target fid created: " << new_fid << " fid_name: " << fid_name << "\n";); + } } for (family_id fid = 0; from.m_family_manager.has_family(fid); fid++) { - SASSERT(from.is_builtin_family_id(fid) == is_builtin_family_id(fid)); - SASSERT(!from.is_builtin_family_id(fid) || m_family_manager.has_family(fid)); - symbol fid_name = from.get_family_name(fid); - TRACE("copy_families_plugins", tout << "copying: " << fid_name << ", src fid: " << fid - << ", target has_family: " << m_family_manager.has_family(fid) << "\n"; - if (m_family_manager.has_family(fid)) tout << get_family_id(fid_name) << "\n";); - TRACE("copy_families_plugins", tout << "target fid: " << get_family_id(fid_name) << "\n";); - SASSERT(fid == get_family_id(fid_name)); - if (from.has_plugin(fid) && !has_plugin(fid)) { - decl_plugin * new_p = from.get_plugin(fid)->mk_fresh(); - register_plugin(fid, new_p); - SASSERT(new_p->get_family_id() == fid); - SASSERT(has_plugin(fid)); - } - if (from.has_plugin(fid)) { - get_plugin(fid)->inherit(from.get_plugin(fid), trans); - } - SASSERT(from.m_family_manager.has_family(fid) == m_family_manager.has_family(fid)); - SASSERT(from.get_family_id(fid_name) == get_family_id(fid_name)); - SASSERT(!from.has_plugin(fid) || has_plugin(fid)); + SASSERT(from.is_builtin_family_id(fid) == is_builtin_family_id(fid)); + SASSERT(!from.is_builtin_family_id(fid) || m_family_manager.has_family(fid)); + symbol fid_name = from.get_family_name(fid); + (void)fid_name; + TRACE("copy_families_plugins", tout << "copying: " << fid_name << ", src fid: " << fid + << ", target has_family: " << m_family_manager.has_family(fid) << "\n"; + if (m_family_manager.has_family(fid)) tout << get_family_id(fid_name) << "\n";); + TRACE("copy_families_plugins", tout << "target fid: " << get_family_id(fid_name) << "\n";); + SASSERT(fid == get_family_id(fid_name)); + if (from.has_plugin(fid) && !has_plugin(fid)) { + decl_plugin * new_p = from.get_plugin(fid)->mk_fresh(); + register_plugin(fid, new_p); + SASSERT(new_p->get_family_id() == fid); + SASSERT(has_plugin(fid)); + } + if (from.has_plugin(fid)) { + get_plugin(fid)->inherit(from.get_plugin(fid), trans); + } + SASSERT(from.m_family_manager.has_family(fid) == m_family_manager.has_family(fid)); + SASSERT(from.get_family_id(fid_name) == get_family_id(fid_name)); + SASSERT(!from.has_plugin(fid) || has_plugin(fid)); } } diff --git a/src/ast/ast_pp_util.cpp b/src/ast/ast_pp_util.cpp index 37785e072..23c9ebe51 100644 --- a/src/ast/ast_pp_util.cpp +++ b/src/ast/ast_pp_util.cpp @@ -46,13 +46,18 @@ void ast_pp_util::display_decls(std::ostream& out) { n = coll.get_num_decls(); for (unsigned i = 0; i < n; ++i) { func_decl* f = coll.get_func_decls()[i]; - if (f->get_family_id() == null_family_id) { + if (f->get_family_id() == null_family_id && !m_removed.contains(f)) { ast_smt2_pp(out, f, env); out << "\n"; } } } +void ast_pp_util::remove_decl(func_decl* f) { + m_removed.insert(f); +} + + void ast_pp_util::display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat) { if (neat) { smt2_pp_environment_dbg env(m); diff --git a/src/ast/ast_pp_util.h b/src/ast/ast_pp_util.h index 964a862a2..1b2686511 100644 --- a/src/ast/ast_pp_util.h +++ b/src/ast/ast_pp_util.h @@ -20,9 +20,11 @@ Revision History: #define AST_PP_UTIL_H_ #include "ast/decl_collector.h" +#include "util/obj_hashtable.h" class ast_pp_util { ast_manager& m; + obj_hashtable m_removed; public: decl_collector coll; @@ -35,6 +37,8 @@ class ast_pp_util { void collect(expr_ref_vector const& es); + void remove_decl(func_decl* f); + void display_decls(std::ostream& out); void display_asserts(std::ostream& out, expr_ref_vector const& fmls, bool neat = true); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 47d7cc357..521cf0dc9 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -1106,6 +1106,16 @@ namespace datalog { names.push_back(m_rule_names[i]); } } + + static std::ostream& display_symbol(std::ostream& out, symbol const& nm) { + if (is_smt2_quoted_symbol(nm)) { + out << mk_smt2_quoted_symbol(nm); + } + else { + out << nm; + } + return out; + } void context::display_smt2(unsigned num_queries, expr* const* qs, std::ostream& out) { ast_manager& m = get_manager(); @@ -1148,13 +1158,13 @@ namespace datalog { if (!use_fixedpoint_extensions) { out << "(set-logic HORN)\n"; } + for (func_decl * f : rels) + visitor.remove_decl(f); visitor.display_decls(out); - func_decl_set::iterator it = rels.begin(), end = rels.end(); - for (; it != end; ++it) { - func_decl* f = *it; + + for (func_decl * f : rels) display_rel_decl(out, f); - } if (use_fixedpoint_extensions && do_declare_vars) { declare_vars(rules, fresh_names, out); @@ -1185,13 +1195,7 @@ namespace datalog { nm = symbol(s.str().c_str()); } fresh_names.add(nm); - if (is_smt2_quoted_symbol(nm)) { - out << mk_smt2_quoted_symbol(nm); - } - else { - out << nm; - } - out << ")"; + display_symbol(out, nm) << ")"; } out << ")\n"; } @@ -1219,7 +1223,8 @@ namespace datalog { PP(qfn); out << ")\n"; } - out << "(query " << fn->get_name() << ")\n"; + out << "(query "; + display_symbol(out, fn->get_name()) << ")\n"; } } else { @@ -1238,7 +1243,8 @@ namespace datalog { void context::display_rel_decl(std::ostream& out, func_decl* f) { smt2_pp_environment_dbg env(m); - out << "(declare-rel " << f->get_name() << " ("; + out << "(declare-rel "; + display_symbol(out, f->get_name()) << " ("; for (unsigned i = 0; i < f->get_arity(); ++i) { ast_smt2_pp(out, f->get_domain(i), env); if (i + 1 < f->get_arity()) { diff --git a/src/test/quant_elim.cpp b/src/test/quant_elim.cpp index 12fca706d..f376e2c1d 100644 --- a/src/test/quant_elim.cpp +++ b/src/test/quant_elim.cpp @@ -13,6 +13,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/reg_decl_plugins.h" +#if 0 static void test_qe(ast_manager& m, lbool expected_outcome, expr* fml, char const* option) { // enable_trace("bit2int"); @@ -48,6 +49,7 @@ static void test_qe(ast_manager& m, lbool expected_outcome, expr* fml, char cons //exit(-1); } } +#endif static void test_formula(lbool expected_outcome, char const* fml) { ast_manager m; From a7caa2fd2a5b5d888956fcc0391ff034ce91b9b7 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Wed, 7 Mar 2018 18:16:11 -0500 Subject: [PATCH 0622/1283] remove useless get_assignments in theory_str final check --- src/smt/theory_str.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index b900f9368..e0f0909cc 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -8734,8 +8734,8 @@ namespace smt { context & ctx = get_context(); ast_manager & m = get_manager(); - expr_ref_vector assignments(m); - ctx.get_assignments(assignments); + //expr_ref_vector assignments(m); + //ctx.get_assignments(assignments); if (opt_VerifyFinalCheckProgress) { finalCheckProgressIndicator = false; From 02a969670124399e07c982b038cc861667e1b3ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Mar 2018 11:19:00 -0500 Subject: [PATCH 0623/1283] fix #1521 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_core.h | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index fe62efbf4..3393634b6 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -469,7 +469,8 @@ namespace smt { if (negated) l_conseq.neg(); TRACE("arith_axiom", tout << mk_pp(ante, m) << "\n" << mk_pp(conseq, m) << "\n"; - tout << s_ante << "\n" << s_conseq << "\n";); + tout << s_ante << "\n" << s_conseq << "\n"; + tout << l_ante << "\n" << l_conseq << "\n";); // literal lits[2] = {l_ante, l_conseq}; mk_clause(l_ante, l_conseq, 0, nullptr); @@ -589,13 +590,14 @@ namespace smt { } // - // create the term: s := to_real(to_int(x)) - x + // create the term: s := x - to_real(to_int(x)) // add the bounds 0 <= s < 1 // template void theory_arith::mk_to_int_axiom(app * n) { SASSERT(m_util.is_to_int(n)); - ast_manager & m = get_manager(); + ast_manager & m = get_manager(); + context & ctx = get_context(); expr* x = n->get_arg(0); // to_int (to_real x) = x @@ -603,11 +605,15 @@ namespace smt { mk_axiom(m.mk_false(), m.mk_eq(to_app(x)->get_arg(0), n)); return; } - expr* to_r = m_util.mk_to_real(n); - expr_ref lo(m_util.mk_le(to_r, x), m); - expr_ref hi(m_util.mk_lt(x, m_util.mk_add(to_r, m_util.mk_numeral(rational(1), false))), m); - mk_axiom(m.mk_false(), lo); - mk_axiom(m.mk_false(), hi); + expr_ref to_r(m_util.mk_to_real(n), m); + expr_ref diff(m_util.mk_add(x, m_util.mk_mul(m_util.mk_real(-1), to_r)), m); + + expr_ref lo(m_util.mk_ge(diff, m_util.mk_real(0)), m); + expr_ref hi(m_util.mk_ge(diff, m_util.mk_real(1)), m); + hi = m.mk_not(hi); + + mk_axiom(m.mk_false(), lo, false); + mk_axiom(m.mk_false(), hi, false); } template @@ -1202,7 +1208,7 @@ namespace smt { template bool theory_arith::internalize_atom(app * n, bool gate_ctx) { - TRACE("arith_internalize", tout << "internalising atom:\n" << mk_pp(n, this->get_manager()) << "\n";); + TRACE("arith_internalize", tout << "internalizing atom:\n" << mk_pp(n, this->get_manager()) << "\n";); context & ctx = get_context(); SASSERT(m_util.is_le(n) || m_util.is_ge(n) || m_util.is_is_int(n)); SASSERT(!ctx.b_internalized(n)); From bf6975122be10ec7d4e872a274bac525d33a03a9 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 8 Mar 2018 12:37:44 -0500 Subject: [PATCH 0624/1283] integrate contains and indexof in theory_str --- src/smt/theory_str.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index cb4a11c89..9dfd0475b 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1284,6 +1284,21 @@ namespace smt { expr_ref finalAxiom(m.mk_and(breakdownAssert, reduceToIndex), m); SASSERT(finalAxiom); assert_axiom(finalAxiom); + + { + // heuristic: integrate with str.contains information + // (but don't introduce it if it isn't already in the instance) + expr_ref haystack(ex->get_arg(0), m), needle(ex->get_arg(1), m), startIdx(ex->get_arg(2), m); + expr_ref zeroAst(mk_int(0), m); + // (H contains N) <==> (H indexof N, i) >= 0 + expr_ref premise(u.str.mk_contains(haystack, needle), m); + ctx.internalize(premise, false); + expr_ref conclusion(m_autil.mk_ge(ex, zeroAst), m); + expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m); + SASSERT(containsAxiom); + // we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent + m_delayed_axiom_setup_terms.push_back(containsAxiom); + } } void theory_str::instantiate_axiom_Indexof_extended(enode * e) { @@ -1353,6 +1368,20 @@ namespace smt { expr_ref reduceTerm(ctx.mk_eq_atom(expr, resAst), m); SASSERT(reduceTerm); assert_axiom(reduceTerm); + + { + // heuristic: integrate with str.contains information + // (but don't introduce it if it isn't already in the instance) + expr_ref haystack(expr->get_arg(0), m), needle(expr->get_arg(1), m), startIdx(expr->get_arg(2), m); + // (H contains N) <==> (H indexof N, i) >= 0 + expr_ref premise(u.str.mk_contains(haystack, needle), m); + ctx.internalize(premise, false); + expr_ref conclusion(m_autil.mk_ge(expr, zeroAst), m); + expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m); + SASSERT(containsAxiom); + // we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent + m_delayed_axiom_setup_terms.push_back(containsAxiom); + } } void theory_str::instantiate_axiom_LastIndexof(enode * e) { From 878a6ca14ffd1eb9f1b26083ebb16533019cca2f Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 9 Mar 2018 14:29:22 +0700 Subject: [PATCH 0625/1283] Fix typos. --- CMakeLists.txt | 2 +- scripts/mk_consts_files.py | 2 +- src/api/c++/z3++.h | 2 +- src/api/dotnet/Context.cs | 10 +++++----- src/api/java/Context.java | 10 +++++----- src/api/python/z3/z3.py | 12 ++++++------ src/api/z3_fpa.h | 8 ++++---- src/api/z3_interp.h | 4 ++-- src/ast/rewriter/rewriter_def.h | 2 +- src/interp/iz3checker.cpp | 2 +- src/muz/base/fixedpoint_params.pyg | 8 ++++---- src/muz/transforms/dl_mk_array_instantiation.h | 2 +- src/muz/transforms/dl_mk_interp_tail_simplifier.h | 2 +- src/muz/transforms/dl_mk_rule_inliner.h | 2 +- src/muz/transforms/dl_mk_scale.h | 2 +- src/tactic/aig/aig.cpp | 2 +- src/tactic/tactic_exception.h | 2 +- src/tactic/tactical.h | 2 +- 18 files changed, 38 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69a0ca123..7bc60e135 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -434,7 +434,7 @@ else() endif() ################################################################################ -# Postion independent code +# Position independent code ################################################################################ # This is required because code built in the components will end up in a shared # library. If not building a shared library ``-fPIC`` isn't needed and would add diff --git a/scripts/mk_consts_files.py b/scripts/mk_consts_files.py index d0502c19d..39d4e9439 100755 --- a/scripts/mk_consts_files.py +++ b/scripts/mk_consts_files.py @@ -72,7 +72,7 @@ def main(args): if count == 0: logging.info('No files generated. You need to specific an output directory' - ' for the relevant langauge bindings') + ' for the relevant language bindings') # TODO: Add support for other bindings return 0 diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 49f6cfbf3..42467cb22 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -989,7 +989,7 @@ namespace z3 { /** \brief sequence and regular expression operations. - + is overloaeded as sequence concatenation and regular expression union. + + is overloaded as sequence concatenation and regular expression union. concat is overloaded to handle sequences and regular expressions */ expr extract(expr const& offset, expr const& length) const { diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index cbd6a1bac..b3b24a6d1 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2515,7 +2515,7 @@ namespace Microsoft.Z3 /// - /// Concatentate sequences. + /// Concatenate sequences. /// public SeqExpr MkConcat(params SeqExpr[] t) { @@ -3597,7 +3597,7 @@ namespace Microsoft.Z3 } /// - /// Create a tactic that fails if the goal is not triviall satisfiable (i.e., empty) + /// Create a tactic that fails if the goal is not trivially satisfiable (i.e., empty) /// or trivially unsatisfiable (i.e., contains `false'). /// public Tactic FailIfNotDecided() @@ -4656,7 +4656,7 @@ namespace Microsoft.Z3 /// Conversion of a floating-point term into a bit-vector. /// /// - /// Produces a term that represents the conversion of the floating-poiunt term t into a + /// Produces a term that represents the conversion of the floating-point term t into a /// bit-vector term of size sz in 2's complement format (signed when signed==true). If necessary, /// the result will be rounded according to rounding mode rm. /// @@ -4677,7 +4677,7 @@ namespace Microsoft.Z3 /// Conversion of a floating-point term into a real-numbered term. /// /// - /// Produces a term that represents the conversion of the floating-poiunt term t into a + /// Produces a term that represents the conversion of the floating-point term t into a /// real number. Note that this type of conversion will often result in non-linear /// constraints over real terms. /// @@ -4696,7 +4696,7 @@ namespace Microsoft.Z3 /// /// The size of the resulting bit-vector is automatically determined. Note that /// IEEE 754-2008 allows multiple different representations of NaN. This conversion - /// knows only one NaN and it will always produce the same bit-vector represenatation of + /// knows only one NaN and it will always produce the same bit-vector representation of /// that NaN. /// /// FloatingPoint term. diff --git a/src/api/java/Context.java b/src/api/java/Context.java index ba96209b3..3c5caadee 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -1978,7 +1978,7 @@ public class Context implements AutoCloseable { } /** - * Concatentate sequences. + * Concatenate sequences. */ public SeqExpr mkConcat(SeqExpr... t) { @@ -2781,7 +2781,7 @@ public class Context implements AutoCloseable { } /** - * Create a tactic that fails if the goal is not triviall satisfiable (i.e., + * Create a tactic that fails if the goal is not trivially satisfiable (i.e., * empty) or trivially unsatisfiable (i.e., contains `false'). **/ public Tactic failIfNotDecided() @@ -3769,7 +3769,7 @@ public class Context implements AutoCloseable { * @param sz Size of the resulting bit-vector. * @param signed Indicates whether the result is a signed or unsigned bit-vector. * Remarks: - * Produces a term that represents the conversion of the floating-poiunt term t into a + * Produces a term that represents the conversion of the floating-point term t into a * bit-vector term of size sz in 2's complement format (signed when signed==true). If necessary, * the result will be rounded according to rounding mode rm. * @throws Z3Exception @@ -3786,7 +3786,7 @@ public class Context implements AutoCloseable { * Conversion of a floating-point term into a real-numbered term. * @param t FloatingPoint term * Remarks: - * Produces a term that represents the conversion of the floating-poiunt term t into a + * Produces a term that represents the conversion of the floating-point term t into a * real number. Note that this type of conversion will often result in non-linear * constraints over real terms. * @throws Z3Exception @@ -3802,7 +3802,7 @@ public class Context implements AutoCloseable { * Remarks: * The size of the resulting bit-vector is automatically determined. Note that * IEEE 754-2008 allows multiple different representations of NaN. This conversion - * knows only one NaN and it will always produce the same bit-vector represenatation of + * knows only one NaN and it will always produce the same bit-vector representation of * that NaN. * @throws Z3Exception **/ diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1cfb10179..e68d7280d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -2428,7 +2428,7 @@ def is_rational_value(a): return is_arith(a) and a.is_real() and _is_numeral(a.ctx, a.as_ast()) def is_algebraic_value(a): - """Return `True` if `a` is an algerbraic value of sort Real. + """Return `True` if `a` is an algebraic value of sort Real. >>> is_algebraic_value(RealVal("3/5")) False @@ -4437,7 +4437,7 @@ class Datatype: """Declare constructor named `name` with the given accessors `args`. Each accessor is a pair `(name, sort)`, where `name` is a string and `sort` a Z3 sort or a reference to the datatypes being declared. - In the followin example `List.declare('cons', ('car', IntSort()), ('cdr', List))` + In the following example `List.declare('cons', ('car', IntSort()), ('cdr', List))` declares the constructor named `cons` that builds a new List using an integer and a List. It also declares the accessors `car` and `cdr`. The accessor `car` extracts the integer of a `cons` cell, and `cdr` the list of a `cons` cell. After all constructors were declared, we use the method create() to create @@ -4457,7 +4457,7 @@ class Datatype: return "Datatype(%s, %s)" % (self.name, self.constructors) def create(self): - """Create a Z3 datatype based on the constructors declared using the mehtod `declare()`. + """Create a Z3 datatype based on the constructors declared using the method `declare()`. The function `CreateDatatypes()` must be used to define mutually recursive datatypes. @@ -8874,7 +8874,7 @@ class FPNumRef(FPRef): def isSubnormal(self): return Z3_fpa_is_numeral_subnormal(self.ctx.ref(), self.as_ast()) - """Indicates whether the numeral is postitive.""" + """Indicates whether the numeral is positive.""" def isPositive(self): return Z3_fpa_is_numeral_positive(self.ctx.ref(), self.as_ast()) @@ -9670,7 +9670,7 @@ def fpToIEEEBV(x, ctx=None): The size of the resulting bit-vector is automatically determined. Note that IEEE 754-2008 allows multiple different representations of NaN. This conversion - knows only one NaN and it will always produce the same bit-vector represenatation of + knows only one NaN and it will always produce the same bit-vector representation of that NaN. >>> x = FP('x', FPSort(8, 24)) @@ -9845,7 +9845,7 @@ def Empty(s): raise Z3Exception("Non-sequence, non-regular expression sort passed to Empty") def Full(s): - """Create the regular expression that accepts the universal langauge + """Create the regular expression that accepts the universal language >>> e = Full(ReSort(SeqSort(IntSort()))) >>> print(e) re.all diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 358a3c619..7d237c6e7 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -756,7 +756,7 @@ extern "C" { /** \brief Conversion of a floating-point term into an unsigned bit-vector. - Produces a term that represents the conversion of the floating-poiunt term t into a + Produces a term that represents the conversion of the floating-point term t into a bit-vector term of size sz in unsigned 2's complement format. If necessary, the result will be rounded according to rounding mode rm. @@ -772,7 +772,7 @@ extern "C" { /** \brief Conversion of a floating-point term into a signed bit-vector. - Produces a term that represents the conversion of the floating-poiunt term t into a + Produces a term that represents the conversion of the floating-point term t into a bit-vector term of size sz in signed 2's complement format. If necessary, the result will be rounded according to rounding mode rm. @@ -788,7 +788,7 @@ extern "C" { /** \brief Conversion of a floating-point term into a real-numbered term. - Produces a term that represents the conversion of the floating-poiunt term t into a + Produces a term that represents the conversion of the floating-point term t into a real number. Note that this type of conversion will often result in non-linear constraints over real terms. @@ -1011,7 +1011,7 @@ extern "C" { determined. Note that IEEE 754-2008 allows multiple different representations of NaN. This conversion - knows only one NaN and it will always produce the same bit-vector represenatation of + knows only one NaN and it will always produce the same bit-vector representation of that NaN. def_API('Z3_mk_fpa_to_ieee_bv', AST, (_in(CONTEXT),_in(AST))) diff --git a/src/api/z3_interp.h b/src/api/z3_interp.h index bcee0e22d..2441d4339 100644 --- a/src/api/z3_interp.h +++ b/src/api/z3_interp.h @@ -98,7 +98,7 @@ extern "C" { Interpolant may not necessarily be computable from all proofs. To be sure an interpolant can be computed, the proof - must be generated by an SMT solver for which interpoaltion is + must be generated by an SMT solver for which interpolation is supported, and the premises must be expressed using only theories and operators for which interpolation is supported. @@ -199,7 +199,7 @@ extern "C" { (implies (and c1 ... cn f) v) where c1 .. cn are the children of v (which must precede v in the file) - and f is the formula assiciated to node v. The last formula in the + and f is the formula associated to node v. The last formula in the file is the root vertex, and is represented by the predicate "false". A solution to a tree interpolation problem can be thought of as a diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 658fb2e05..878f4ef4c 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -358,7 +358,7 @@ void rewriter_tpl::process_app(app * t, frame & fr) { if (ProofGen) { NOT_IMPLEMENTED_YET(); // We do not support the use of bindings in proof generation mode. - // Thus we have to apply the subsitution here, and + // Thus we have to apply the substitution here, and // beta_reducer subst(m()); // subst.set_bindings(new_num_args, new_args); // expr_ref r2(m()); diff --git a/src/interp/iz3checker.cpp b/src/interp/iz3checker.cpp index cfea511ad..511342819 100644 --- a/src/interp/iz3checker.cpp +++ b/src/interp/iz3checker.cpp @@ -43,7 +43,7 @@ struct iz3checker : iz3base { /* HACK: for tree interpolants, we assume that uninterpreted functions are global. This is because in the current state of the tree interpolation code, symbols that appear in sibling sub-trees have to be global, and - we have no way to eliminate such function symbols. When tree interpoaltion is + we have no way to eliminate such function symbols. When tree interpolation is fixed, we can tree function symbols the same as constant symbols. */ bool is_tree; diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 0c2f03460..753a45e06 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -33,7 +33,7 @@ def_module_params('fixedpoint', "updated relation was modified or not"), ('datalog.compile_with_widening', BOOL, False, "widening will be used to compile recursive rules"), - ('datalog.default_table_checked', BOOL, False, "if true, the detault " + + ('datalog.default_table_checked', BOOL, False, "if true, the default " + 'table will be default_table inside a wrapper that checks that its results ' + 'are the same as of default_table_checker table'), ('datalog.default_table_checker', SYMBOL, 'null', "see default_table_checked"), @@ -59,7 +59,7 @@ def_module_params('fixedpoint', ('duality.full_expand', BOOL, False, 'Fully expand derivation trees'), ('duality.no_conj', BOOL, False, 'No forced covering (conjectures)'), ('duality.feasible_edges', BOOL, True, - 'Don\'t expand definitley infeasible edges'), + 'Don\'t expand definitely infeasible edges'), ('duality.use_underapprox', BOOL, False, 'Use underapproximations'), ('duality.stratified_inlining', BOOL, False, 'Use stratified inlining'), ('duality.recursion_bound', UINT, UINT_MAX, @@ -130,7 +130,7 @@ def_module_params('fixedpoint', ('xform.magic', BOOL, False, "perform symbolic magic set transformation"), ('xform.scale', BOOL, False, - "add scaling variable to linear real arithemtic clauses"), + "add scaling variable to linear real arithmetic clauses"), ('xform.inline_linear', BOOL, True, "try linear inlining method"), ('xform.inline_eager', BOOL, True, "try eager inlining of rules"), ('xform.inline_linear_branch', BOOL, False, @@ -176,7 +176,7 @@ def_module_params('fixedpoint', ('spacer.elim_aux', BOOL, True, "Eliminate auxiliary variables in reachability facts"), ('spacer.reach_as_init', BOOL, True, "Extend initial rules with computed reachability facts"), ('spacer.blast_term_ite', BOOL, True, "Expand non-Boolean ite-terms"), - ('spacer.nondet_tie_break', BOOL, False, "Break ties in obligation queue non-deterministicly"), + ('spacer.nondet_tie_break', BOOL, False, "Break ties in obligation queue non-deterministically"), ('spacer.reach_dnf', BOOL, True, "Restrict reachability facts to DNF"), ('bmc.linear_unrolling_depth', UINT, UINT_MAX, "Maximal level to explore"), ('spacer.split_farkas_literals', BOOL, False, "Split Farkas literals"), diff --git a/src/muz/transforms/dl_mk_array_instantiation.h b/src/muz/transforms/dl_mk_array_instantiation.h index cd5715a4f..b2e80ab84 100644 --- a/src/muz/transforms/dl_mk_array_instantiation.h +++ b/src/muz/transforms/dl_mk_array_instantiation.h @@ -26,7 +26,7 @@ Implementation: 1) Dealing with multiple quantifiers -> The options fixedpoint.xform.instantiate_arrays.nb_quantifier gives the number of quantifiers per array. - 2) Inforcing the instantiation -> We suggest an option (enforce_instantiation) to enforce this abstraction. This transforms + 2) Enforcing the instantiation -> We suggest an option (enforce_instantiation) to enforce this abstraction. This transforms P(a) into P(i, a[i]). This enforces the solver to limit the space search at the cost of imprecise results. This option corresponds to fixedpoint.xform.instantiate_arrays.enforce diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.h b/src/muz/transforms/dl_mk_interp_tail_simplifier.h index 713827588..0d4c65d11 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.h +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.h @@ -53,7 +53,7 @@ namespace datalog { */ void reset(rule * r); - /** Reset subtitution and unify tail tgt_idx of the target rule and the head of the src rule */ + /** Reset substitution and unify tail tgt_idx of the target rule and the head of the src rule */ bool unify(expr * e1, expr * e2); void get_result(rule_ref & res); diff --git a/src/muz/transforms/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h index 27b6dd418..9146343fa 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -45,7 +45,7 @@ namespace datalog { : m(ctx.get_manager()), m_rm(ctx.get_rule_manager()), m_context(ctx), m_interp_simplifier(ctx), m_subst(m), m_unif(m), m_ready(false), m_normalize(true) {} - /** Reset subtitution and unify tail tgt_idx of the target rule and the head of the src rule */ + /** Reset substitution and unify tail tgt_idx of the target rule and the head of the src rule */ bool unify_rules(rule const& tgt, unsigned tgt_idx, rule const& src); /** diff --git a/src/muz/transforms/dl_mk_scale.h b/src/muz/transforms/dl_mk_scale.h index c171a1d06..94090ec93 100644 --- a/src/muz/transforms/dl_mk_scale.h +++ b/src/muz/transforms/dl_mk_scale.h @@ -7,7 +7,7 @@ Module Name: Abstract: - Add scale factor to linear (Real) arithemetic Horn clauses. + Add scale factor to linear (Real) arithmetic Horn clauses. The transformation replaces occurrences of isolated constants by a scale multiplied to each constant. diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 40c68f72a..6afac32b8 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -267,7 +267,7 @@ struct aig_manager::imp { } if (b == r) { if (sign1) { - // subsitution + // substitution // not (a and b) and r --> (not a) and r IF b == r l = a; l.invert(); diff --git a/src/tactic/tactic_exception.h b/src/tactic/tactic_exception.h index 177524726..bdf2636a9 100644 --- a/src/tactic/tactic_exception.h +++ b/src/tactic/tactic_exception.h @@ -7,7 +7,7 @@ Module Name: Abstract: - Tactic expection object. + Tactic exception object. Author: diff --git a/src/tactic/tactical.h b/src/tactic/tactical.h index 169566f39..9ec2f901f 100644 --- a/src/tactic/tactical.h +++ b/src/tactic/tactical.h @@ -47,7 +47,7 @@ tactic * or_else(tactic * t1, tactic * t2, tactic * t3, tactic * t4, tactic * t5 tactic * repeat(tactic * t, unsigned max = UINT_MAX); /** - \brief Fails if \c t produeces more than \c threshold subgoals. + \brief Fails if \c t produces more than \c threshold subgoals. Otherwise, it behaves like \c t. */ tactic * fail_if_branching(tactic * t, unsigned threshold = 1); From ba603307fcb39cdc12a6d0283ddc9632ca436478 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Mar 2018 05:32:01 -0500 Subject: [PATCH 0626/1283] remove stale deprecated annotation #1525 Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 500533e91..f7c218963 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1477,7 +1477,6 @@ extern "C" { /*@{*/ /** - \deprecated \brief Create a configuration object for the Z3 context object. Configurations are created in order to assign parameters prior to creating @@ -1510,7 +1509,6 @@ extern "C" { Z3_config Z3_API Z3_mk_config(void); /** - \deprecated \brief Delete the given configuration object. \sa Z3_mk_config @@ -1520,7 +1518,6 @@ extern "C" { void Z3_API Z3_del_config(Z3_config c); /** - \deprecated \brief Set a configuration parameter. The following parameters can be set for @@ -1537,7 +1534,6 @@ extern "C" { /*@{*/ /** - \deprecated \brief Create a context using the given configuration. After a context is created, the configuration cannot be changed, @@ -1617,7 +1613,6 @@ extern "C" { void Z3_API Z3_dec_ref(Z3_context c, Z3_ast a); /** - \deprecated \brief Set a value of a context parameter. \sa Z3_global_param_set From ae165a539e476a032f83ce252582f7b94b644e20 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Fri, 9 Mar 2018 14:20:31 +0100 Subject: [PATCH 0627/1283] Fix parameter expansion when configuring Z3 --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 29408d3e7..807fba392 100755 --- a/configure +++ b/configure @@ -14,4 +14,4 @@ if ! $PYTHON -c "print('testing')" > /dev/null ; then exit 1 fi -$PYTHON scripts/mk_make.py $* +$PYTHON scripts/mk_make.py "$@" From e5a19816943fd1fdf3c93ff0ac7dfe1871fc1807 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Mar 2018 15:40:35 -0500 Subject: [PATCH 0628/1283] disable GCC flag change to see if this affects build Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f20c4fb10..62045016a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -410,17 +410,17 @@ list(APPEND Z3_DEPENDENT_LIBS ${CMAKE_THREAD_LIBS_INIT}) include(${CMAKE_SOURCE_DIR}/cmake/compiler_warnings.cmake) ################################################################################ -# If using Ninja, force color output for Clang and gcc. +# If using Ninja, force color output for Clang (and gcc, disabled to check build). ################################################################################ if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics") endif() - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color") - endif() +# if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color") +# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color") +# endif() endif() ################################################################################ From 6e87622c8a770c497cafbf972dbd96eaa34eb67c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Mar 2018 13:55:01 -0500 Subject: [PATCH 0629/1283] remove references to deprecated uses of PROOF_MODE #1531 Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 3 -- src/api/dotnet/Expr.cs | 38 +---------------- src/api/java/Expr.java | 55 ++----------------------- src/api/z3_api.h | 23 +---------- src/ast/ast.cpp | 31 -------------- src/ast/ast.h | 11 ++--- src/ast/proofs/proof_checker.cpp | 27 ------------ src/smt/theory_arith_core.h | 1 - src/smt/theory_str.cpp | 2 + src/tactic/core/ctx_simplify_tactic.cpp | 2 +- src/tactic/core/dom_simplify_tactic.cpp | 4 +- 11 files changed, 16 insertions(+), 181 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 3f5a0fcf1..1f4a86903 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -919,7 +919,6 @@ extern "C" { case PR_REWRITE: return Z3_OP_PR_REWRITE; case PR_REWRITE_STAR: return Z3_OP_PR_REWRITE_STAR; case PR_PULL_QUANT: return Z3_OP_PR_PULL_QUANT; - case PR_PULL_QUANT_STAR: return Z3_OP_PR_PULL_QUANT_STAR; case PR_PUSH_QUANT: return Z3_OP_PR_PUSH_QUANT; case PR_ELIM_UNUSED_VARS: return Z3_OP_PR_ELIM_UNUSED_VARS; case PR_DER: return Z3_OP_PR_DER; @@ -936,9 +935,7 @@ extern "C" { case PR_IFF_OEQ: return Z3_OP_PR_IFF_OEQ; case PR_NNF_POS: return Z3_OP_PR_NNF_POS; case PR_NNF_NEG: return Z3_OP_PR_NNF_NEG; - case PR_NNF_STAR: return Z3_OP_PR_NNF_STAR; case PR_SKOLEMIZE: return Z3_OP_PR_SKOLEMIZE; - case PR_CNF_STAR: return Z3_OP_PR_CNF_STAR; case PR_MODUS_PONENS_OEQ: return Z3_OP_PR_MODUS_PONENS_OEQ; case PR_TH_LEMMA: return Z3_OP_PR_TH_LEMMA; case PR_HYPER_RESOLVE: return Z3_OP_PR_HYPER_RESOLVE; diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 0726f9d53..9310d1e7d 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -932,7 +932,7 @@ namespace Microsoft.Z3 /// Indicates whether the term is a proof by condensed transitivity of a relation /// /// - /// Condensed transitivity proof. This proof object is only used if the parameter PROOF_MODE is 1. + /// Condensed transitivity proof. /// It combines several symmetry and transitivity proofs. /// Example: /// T1: (R a b) @@ -1035,14 +1035,11 @@ namespace Microsoft.Z3 /// /// /// A proof for rewriting an expression t into an expression s. - /// This proof object is used if the parameter PROOF_MODE is 1. /// This proof object can have n antecedents. /// The antecedents are proofs for equalities used as substitution rules. - /// The object is also used in a few cases if the parameter PROOF_MODE is 2. - /// The cases are: + /// The object is used in a few cases: /// - When applying contextual simplification (CONTEXT_SIMPLIFIER=true) /// - When converting bit-vectors to Booleans (BIT2BOOL=true) - /// - When pulling ite expression up (PULL_CHEAP_ITE_TREES=true) /// public bool IsProofRewriteStar { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_REWRITE_STAR; } } @@ -1054,15 +1051,6 @@ namespace Microsoft.Z3 /// public bool IsProofPullQuant { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_PULL_QUANT; } } - /// - /// Indicates whether the term is a proof for pulling quantifiers out. - /// - /// - /// A proof for (iff P Q) where Q is in prenex normal form. - /// This proof object is only used if the parameter PROOF_MODE is 1. - /// This proof object has no antecedents - /// - public bool IsProofPullQuantStar { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_PULL_QUANT_STAR; } } /// /// Indicates whether the term is a proof for pushing quantifiers in. @@ -1304,28 +1292,6 @@ namespace Microsoft.Z3 /// public bool IsProofNNFNeg { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_NNF_NEG; } } - /// - /// Indicates whether the term is a proof for (~ P Q) here Q is in negation normal form. - /// - /// - /// A proof for (~ P Q) where Q is in negation normal form. - /// - /// This proof object is only used if the parameter PROOF_MODE is 1. - /// - /// This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. - /// - public bool IsProofNNFStar { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_NNF_STAR; } } - - /// - /// Indicates whether the term is a proof for (~ P Q) where Q is in conjunctive normal form. - /// - /// - /// A proof for (~ P Q) where Q is in conjunctive normal form. - /// This proof object is only used if the parameter PROOF_MODE is 1. - /// This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. - /// - public bool IsProofCNFStar { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_CNF_STAR; } } - /// /// Indicates whether the term is a proof for a Skolemization step /// diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index 7b20b7993..db5c33e79 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1398,8 +1398,7 @@ public class Expr extends AST /** * Indicates whether the term is a proof by condensed transitivity of a * relation - * Remarks: Condensed transitivity proof. This proof object is - * only used if the parameter PROOF_MODE is 1. It combines several symmetry + * Remarks: Condensed transitivity proof. It combines several symmetry * and transitivity proofs. Example: T1: (R a b) T2: (R c b) T3: (R c d) * [trans* T1 T2 T3]: (R a d) R must be a symmetric and transitive relation. * @@ -1506,14 +1505,11 @@ public class Expr extends AST /** * Indicates whether the term is a proof by rewriting * Remarks: A proof for - * rewriting an expression t into an expression s. This proof object is used - * if the parameter PROOF_MODE is 1. This proof object can have n + * rewriting an expression t into an expression s. This proof object can have n * antecedents. The antecedents are proofs for equalities used as - * substitution rules. The object is also used in a few cases if the - * parameter PROOF_MODE is 2. The cases are: - When applying contextual + * substitution rules. The object is used in a few cases . The cases are: - When applying contextual * simplification (CONTEXT_SIMPLIFIER=true) - When converting bit-vectors to - * Booleans (BIT2BOOL=true) - When pulling ite expression up - * (PULL_CHEAP_ITE_TREES=true) + * Booleans (BIT2BOOL=true) * @throws Z3Exception on error * @return a boolean **/ @@ -1534,17 +1530,6 @@ public class Expr extends AST return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_PR_PULL_QUANT; } - /** - * Indicates whether the term is a proof for pulling quantifiers out. - * - * Remarks: A proof for (iff P Q) where Q is in prenex normal form. This * proof object is only used if the parameter PROOF_MODE is 1. This proof * object has no antecedents - * @throws Z3Exception on error - * @return a boolean - **/ - public boolean isProofPullQuantStar() - { - return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_PR_PULL_QUANT_STAR; - } /** * Indicates whether the term is a proof for pushing quantifiers in. @@ -1804,38 +1789,6 @@ public class Expr extends AST return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_PR_NNF_NEG; } - /** - * Indicates whether the term is a proof for (~ P Q) here Q is in negation - * normal form. - * Remarks: A proof for (~ P Q) where Q is in negation normal - * form. - * - * This proof object is only used if the parameter PROOF_MODE is 1. - * - * This proof object may have n antecedents. Each antecedent is a - * PR_DEF_INTRO. - * @throws Z3Exception on error - * @return a boolean - **/ - public boolean isProofNNFStar() - { - return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_PR_NNF_STAR; - } - - /** - * Indicates whether the term is a proof for (~ P Q) where Q is in - * conjunctive normal form. - * Remarks: A proof for (~ P Q) where Q is in - * conjunctive normal form. This proof object is only used if the parameter - * PROOF_MODE is 1. This proof object may have n antecedents. Each - * antecedent is a PR_DEF_INTRO. - * @throws Z3Exception on error - * @return a boolean - **/ - public boolean isProofCNFStar() - { - return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_PR_CNF_STAR; - } /** * Indicates whether the term is a proof for a Skolemization step diff --git a/src/api/z3_api.h b/src/api/z3_api.h index f7c218963..88d6aa1cf 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -459,7 +459,7 @@ typedef enum [trans T1 T2]: (R t u) } - - Z3_OP_PR_TRANSITIVITY_STAR: Condensed transitivity proof. This proof object is only used if the parameter PROOF_MODE is 1. + - Z3_OP_PR_TRANSITIVITY_STAR: Condensed transitivity proof. It combines several symmetry and transitivity proofs. Example: @@ -539,21 +539,14 @@ typedef enum } - Z3_OP_PR_REWRITE_STAR: A proof for rewriting an expression t into an expression s. - This proof object is used if the parameter PROOF_MODE is 1. This proof object can have n antecedents. The antecedents are proofs for equalities used as substitution rules. - The object is also used in a few cases if the parameter PROOF_MODE is 2. - The cases are: + The proof rule is used in a few cases. The cases are: - When applying contextual simplification (CONTEXT_SIMPLIFIER=true) - When converting bit-vectors to Booleans (BIT2BOOL=true) - - When pulling ite expression up (PULL_CHEAP_ITE_TREES=true) - Z3_OP_PR_PULL_QUANT: A proof for (iff (f (forall (x) q(x)) r) (forall (x) (f (q x) r))). This proof object has no antecedents. - - Z3_OP_PR_PULL_QUANT_STAR: A proof for (iff P Q) where Q is in prenex normal form. - This proof object is only used if the parameter PROOF_MODE is 1. - This proof object has no antecedents. - - Z3_OP_PR_PUSH_QUANT: A proof for: \nicebox{ @@ -726,15 +719,6 @@ typedef enum [nnf-neg T1 T2 T3 T4]: (~ (not (iff s_1 s_2)) (and (or r_1 r_2) (or r_1' r_2'))) } - - Z3_OP_PR_NNF_STAR: A proof for (~ P Q) where Q is in negation normal form. - - This proof object is only used if the parameter PROOF_MODE is 1. - - This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. - - - Z3_OP_PR_CNF_STAR: A proof for (~ P Q) where Q is in conjunctive normal form. - This proof object is only used if the parameter PROOF_MODE is 1. - This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. - Z3_OP_PR_SKOLEMIZE: Proof for: @@ -1142,7 +1126,6 @@ typedef enum { Z3_OP_PR_REWRITE, Z3_OP_PR_REWRITE_STAR, Z3_OP_PR_PULL_QUANT, - Z3_OP_PR_PULL_QUANT_STAR, Z3_OP_PR_PUSH_QUANT, Z3_OP_PR_ELIM_UNUSED_VARS, Z3_OP_PR_DER, @@ -1159,8 +1142,6 @@ typedef enum { Z3_OP_PR_IFF_OEQ, Z3_OP_PR_NNF_POS, Z3_OP_PR_NNF_NEG, - Z3_OP_PR_NNF_STAR, - Z3_OP_PR_CNF_STAR, Z3_OP_PR_SKOLEMIZE, Z3_OP_PR_MODUS_PONENS_OEQ, Z3_OP_PR_TH_LEMMA, diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 127967374..7e143e1a3 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -663,7 +663,6 @@ basic_decl_plugin::basic_decl_plugin(): m_not_or_elim_decl(nullptr), m_rewrite_decl(nullptr), m_pull_quant_decl(nullptr), - m_pull_quant_star_decl(nullptr), m_push_quant_decl(nullptr), m_elim_unused_vars_decl(nullptr), m_der_decl(nullptr), @@ -827,7 +826,6 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_paren case PR_REWRITE: return mk_proof_decl("rewrite", k, 0, m_rewrite_decl); case PR_REWRITE_STAR: return mk_proof_decl("rewrite*", k, num_parents, m_rewrite_star_decls); case PR_PULL_QUANT: return mk_proof_decl("pull-quant", k, 0, m_pull_quant_decl); - case PR_PULL_QUANT_STAR: return mk_proof_decl("pull-quant*", k, 0, m_pull_quant_star_decl); case PR_PUSH_QUANT: return mk_proof_decl("push-quant", k, 0, m_push_quant_decl); case PR_ELIM_UNUSED_VARS: return mk_proof_decl("elim-unused", k, 0, m_elim_unused_vars_decl); case PR_DER: return mk_proof_decl("der", k, 0, m_der_decl); @@ -844,8 +842,6 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_paren case PR_IFF_OEQ: return mk_proof_decl("iff~", k, 1, m_iff_oeq_decl); case PR_NNF_POS: return mk_proof_decl("nnf-pos", k, num_parents, m_nnf_pos_decls); case PR_NNF_NEG: return mk_proof_decl("nnf-neg", k, num_parents, m_nnf_neg_decls); - case PR_NNF_STAR: return mk_proof_decl("nnf*", k, num_parents, m_nnf_star_decls); - case PR_CNF_STAR: return mk_proof_decl("cnf*", k, num_parents, m_cnf_star_decls); case PR_SKOLEMIZE: return mk_proof_decl("sk", k, 0, m_skolemize_decl); case PR_MODUS_PONENS_OEQ: return mk_proof_decl("mp~", k, 2, m_mp_oeq_decl); case PR_TH_LEMMA: return mk_proof_decl("th-lemma", k, num_parents, m_th_lemma_decls); @@ -949,7 +945,6 @@ void basic_decl_plugin::finalize() { DEC_REF(m_not_or_elim_decl); DEC_REF(m_rewrite_decl); DEC_REF(m_pull_quant_decl); - DEC_REF(m_pull_quant_star_decl); DEC_REF(m_push_quant_decl); DEC_REF(m_elim_unused_vars_decl); DEC_REF(m_der_decl); @@ -975,8 +970,6 @@ void basic_decl_plugin::finalize() { DEC_ARRAY_REF(m_apply_def_decls); DEC_ARRAY_REF(m_nnf_pos_decls); DEC_ARRAY_REF(m_nnf_neg_decls); - DEC_ARRAY_REF(m_nnf_star_decls); - DEC_ARRAY_REF(m_cnf_star_decls); DEC_ARRAY_REF(m_th_lemma_decls); DEC_REF(m_hyper_res_decl0); @@ -2844,12 +2837,6 @@ proof * ast_manager::mk_pull_quant(expr * e, quantifier * q) { return mk_app(m_basic_family_id, PR_PULL_QUANT, mk_iff(e, q)); } -proof * ast_manager::mk_pull_quant_star(expr * e, quantifier * q) { - if (proofs_disabled()) - return nullptr; - return mk_app(m_basic_family_id, PR_PULL_QUANT_STAR, mk_iff(e, q)); -} - proof * ast_manager::mk_push_quant(quantifier * q, expr * e) { if (proofs_disabled()) return nullptr; @@ -3094,15 +3081,6 @@ proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * return mk_app(m_basic_family_id, PR_NNF_NEG, args.size(), args.c_ptr()); } -proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (proofs_disabled()) - return nullptr; - ptr_buffer args; - args.append(num_proofs, (expr**) proofs); - args.push_back(mk_oeq(s, t)); - return mk_app(m_basic_family_id, PR_NNF_STAR, args.size(), args.c_ptr()); -} - proof * ast_manager::mk_skolemization(expr * q, expr * e) { if (proofs_disabled()) return nullptr; @@ -3111,15 +3089,6 @@ proof * ast_manager::mk_skolemization(expr * q, expr * e) { return mk_app(m_basic_family_id, PR_SKOLEMIZE, mk_oeq(q, e)); } -proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (proofs_disabled()) - return nullptr; - ptr_buffer args; - args.append(num_proofs, (expr**) proofs); - args.push_back(mk_oeq(s, t)); - return mk_app(m_basic_family_id, PR_CNF_STAR, args.size(), args.c_ptr()); -} - proof * ast_manager::mk_and_elim(proof * p, unsigned i) { if (proofs_disabled()) return nullptr; diff --git a/src/ast/ast.h b/src/ast/ast.h index 55fea1b69..68e02d791 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1042,11 +1042,11 @@ enum basic_op_kind { PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO, PR_DISTRIBUTIVITY, PR_AND_ELIM, PR_NOT_OR_ELIM, PR_REWRITE, PR_REWRITE_STAR, PR_PULL_QUANT, - PR_PULL_QUANT_STAR, PR_PUSH_QUANT, PR_ELIM_UNUSED_VARS, PR_DER, PR_QUANT_INST, + PR_PUSH_QUANT, PR_ELIM_UNUSED_VARS, PR_DER, PR_QUANT_INST, PR_HYPOTHESIS, PR_LEMMA, PR_UNIT_RESOLUTION, PR_IFF_TRUE, PR_IFF_FALSE, PR_COMMUTATIVITY, PR_DEF_AXIOM, - PR_DEF_INTRO, PR_APPLY_DEF, PR_IFF_OEQ, PR_NNF_POS, PR_NNF_NEG, PR_NNF_STAR, PR_SKOLEMIZE, PR_CNF_STAR, + PR_DEF_INTRO, PR_APPLY_DEF, PR_IFF_OEQ, PR_NNF_POS, PR_NNF_NEG, PR_SKOLEMIZE, PR_MODUS_PONENS_OEQ, PR_TH_LEMMA, PR_HYPER_RESOLVE, LAST_BASIC_PR }; @@ -1080,7 +1080,6 @@ protected: func_decl * m_not_or_elim_decl; func_decl * m_rewrite_decl; func_decl * m_pull_quant_decl; - func_decl * m_pull_quant_star_decl; func_decl * m_push_quant_decl; func_decl * m_elim_unused_vars_decl; func_decl * m_der_decl; @@ -1106,8 +1105,6 @@ protected: ptr_vector m_apply_def_decls; ptr_vector m_nnf_pos_decls; ptr_vector m_nnf_neg_decls; - ptr_vector m_nnf_star_decls; - ptr_vector m_cnf_star_decls; ptr_vector m_th_lemma_decls; func_decl * m_hyper_res_decl0; @@ -2182,7 +2179,6 @@ public: proof * mk_oeq_rewrite(expr * s, expr * t); proof * mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs); proof * mk_pull_quant(expr * e, quantifier * q); - proof * mk_pull_quant_star(expr * e, quantifier * q); proof * mk_push_quant(quantifier * q, expr * e); proof * mk_elim_unused_vars(quantifier * q, expr * r); proof * mk_der(quantifier * q, expr * r); @@ -2201,9 +2197,8 @@ public: proof * mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * const * proofs); proof * mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * const * proofs); - proof * mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs); proof * mk_skolemization(expr * q, expr * e); - proof * mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs); + proof * mk_and_elim(proof * p, unsigned i); proof * mk_not_or_elim(proof * p, unsigned i); diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index bd50e6c2a..0e16abd11 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -440,16 +440,6 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { IF_VERBOSE(0, verbose_stream() << "Expected proof of equivalence with a quantifier:\n" << mk_bounded_pp(p, m);); return false; } - case PR_PULL_QUANT_STAR: { - if (match_proof(p) && - match_fact(p, fact) && - match_iff(fact.get(), t1, t2)) { - // TBD: check the enchilada. - return true; - } - IF_VERBOSE(0, verbose_stream() << "Expected proof of equivalence:\n" << mk_bounded_pp(p, m);); - return false; - } case PR_PUSH_QUANT: { if (match_proof(p) && match_fact(p, fact) && @@ -730,10 +720,6 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { // TBD: return true; } - case PR_NNF_STAR: { - // TBD: - return true; - } case PR_SKOLEMIZE: { // (exists ?x (p ?x y)) -> (p (sk y) y) // (not (forall ?x (p ?x y))) -> (not (p (sk y) y)) @@ -755,19 +741,6 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { UNREACHABLE(); return false; } - case PR_CNF_STAR: { - for (unsigned i = 0; i < proofs.size(); ++i) { - if (match_op(proofs[i].get(), PR_DEF_INTRO, terms)) { - // ok - } - else { - UNREACHABLE(); - return false; - } - } - // coarse grain CNF conversion. - return true; - } case PR_MODUS_PONENS_OEQ: { if (match_fact(p, fact) && match_proof(p, p0, p1) && diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 3393634b6..46388fcf4 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -597,7 +597,6 @@ namespace smt { void theory_arith::mk_to_int_axiom(app * n) { SASSERT(m_util.is_to_int(n)); ast_manager & m = get_manager(); - context & ctx = get_context(); expr* x = n->get_arg(0); // to_int (to_real x) = x diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 9dfd0475b..3335370eb 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -5595,6 +5595,8 @@ namespace smt { // merge arg0 and arg1 expr * arg0 = to_app(node)->get_arg(0); expr * arg1 = to_app(node)->get_arg(1); + SASSERT(arg0 != node); + SASSERT(arg1 != node); expr * arg0DeAlias = dealias_node(arg0, varAliasMap, concatAliasMap); expr * arg1DeAlias = dealias_node(arg1, varAliasMap, concatAliasMap); get_grounded_concats(arg0DeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 6ad9c0812..93a0b2e88 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -582,7 +582,7 @@ struct ctx_simplify_tactic::imp { for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { expr * t = g.form(i); process(t, r); - proof* new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(t, r, 0, nullptr)); // TODO :-) + proof* new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite(t, r)); g.update(i, r, new_pr, g.dep(i)); } } diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index e8d3150af..47f96a7d9 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -382,7 +382,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { change |= r != g.form(i); proof* new_pr = nullptr; if (g.proofs_enabled()) { - new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, nullptr)); + new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite(g.form(i), r)); } g.update(i, r, new_pr, g.dep(i)); } @@ -402,7 +402,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); proof* new_pr = nullptr; if (g.proofs_enabled()) { - new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, nullptr)); + new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite(g.form(i), r)); } g.update(i, r, new_pr, g.dep(i)); } From 0ce200144923fe5856054bcad11c9f5471f0d791 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Mar 2018 11:39:22 -0800 Subject: [PATCH 0630/1283] fix build Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 11 ----------- scripts/mk_util.py | 9 +++++++-- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index b2736df4c..772440b42 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -1609,7 +1609,6 @@ public: display_inference(out, "rewrite", "thm", p); break; case Z3_OP_PR_PULL_QUANT: - case Z3_OP_PR_PULL_QUANT_STAR: display_inference(out, "pull_quant", "thm", p); break; case Z3_OP_PR_PUSH_QUANT: @@ -1669,12 +1668,6 @@ public: case Z3_OP_PR_NNF_NEG: display_inference(out, "nnf_neg", "sab", p); break; - case Z3_OP_PR_NNF_STAR: - display_inference(out, "nnf", "sab", p); - break; - case Z3_OP_PR_CNF_STAR: - display_inference(out, "cnf", "sab", p); - break; case Z3_OP_PR_SKOLEMIZE: display_inference(out, "skolemize", "sab", p); break; @@ -1706,10 +1699,6 @@ public: return display_hyp_inference(out, "modus_ponens", "thm", conclusion, hyp, hyp2); } case Z3_OP_PR_NNF_POS: - case Z3_OP_PR_NNF_STAR: - return display_hyp_inference(out, "nnf", "sab", conclusion, hyp); - case Z3_OP_PR_CNF_STAR: - return display_hyp_inference(out, "cnf", "sab", conclusion, hyp); case Z3_OP_PR_SKOLEMIZE: return display_hyp_inference(out, "skolemize", "sab", conclusion, hyp); case Z3_OP_PR_TRANSITIVITY: diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 03256125c..fecc207d8 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -889,8 +889,13 @@ def is_CXX_gpp(): return is_compiler(CXX, 'g++') def is_clang_in_gpp_form(cc): - version_string = check_output([cc, '--version']).encode('utf-8').decode('utf-8') - return version_string.find('clang') != -1 + str = check_output([cc, '--version']) + try: + version_string = str.encode('utf-8') + except: + version_string = str + clang = 'clang'.encode('utf-8') + return version_string.find(clang) != -1 def is_CXX_clangpp(): if is_compiler(CXX, 'g++'): From 58544925048b8559880edb20ccca385c895f1acb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Mar 2018 11:59:42 -0800 Subject: [PATCH 0631/1283] add stdbool.h to see whether build system breaks #1526 Signed-off-by: Nikolaj Bjorner --- src/api/z3.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/z3.h b/src/api/z3.h index 99929f33b..b29f1d6ba 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -21,7 +21,8 @@ Notes: #ifndef Z3_H_ #define Z3_H_ -#include +#include +#include #include "z3_macros.h" #include "z3_api.h" #include "z3_ast_containers.h" From 3d9139f6efaf9f6fb4a2f6226384a5824ae986a6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Mar 2018 12:07:55 -0800 Subject: [PATCH 0632/1283] bump revision Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62045016a..4d8c15493 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 6) -set(Z3_VERSION_PATCH 1) +set(Z3_VERSION_PATCH 2) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 8f75e97ed..2f7402760 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 6, 1, 0) + set_version(4, 6, 2, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') From 11a339c490e06dc4a8342c11004e7909423c7e1b Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Sun, 11 Mar 2018 23:26:30 -0400 Subject: [PATCH 0633/1283] fix include path --- src/smt/theory_str.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 305f83df7..4ea96bd1f 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -25,7 +25,7 @@ #include "smt/theory_seq_empty.h" #include "smt/theory_arith.h" #include "ast/ast_util.h" -#include "seq_rewriter.h" +#include "ast/rewriter/seq_rewriter.h" #include "smt_kernel.h" namespace smt { From e7d43ed516ab4a233e48e8b0c9aadf67d872c106 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Mar 2018 11:22:05 -0700 Subject: [PATCH 0634/1283] fix pb rewriter Signed-off-by: Nikolaj Bjorner --- .../bit_blaster/bit_blaster_rewriter.cpp | 25 +++++-- .../bit_blaster/bit_blaster_rewriter.h | 6 +- src/ast/rewriter/pb_rewriter.cpp | 44 ++++++----- src/ast/rewriter/pb_rewriter_def.h | 16 ++-- src/opt/maxsmt.cpp | 2 +- src/opt/opt_context.cpp | 75 +++++++++++++------ src/opt/opt_context.h | 7 +- src/sat/ba_solver.cpp | 14 +++- src/sat/sat_solver.cpp | 8 ++ src/sat/sat_solver/inc_sat_solver.cpp | 32 ++++---- src/tactic/bv/bit_blaster_model_converter.cpp | 26 +++++-- src/tactic/bv/bit_blaster_model_converter.h | 4 +- src/tactic/bv/bit_blaster_tactic.cpp | 5 +- src/tactic/bv/bv1_blaster_tactic.cpp | 4 +- src/tactic/core/propagate_values_tactic.cpp | 21 +++++- src/tactic/core/solve_eqs_tactic.cpp | 55 +++++++------- 16 files changed, 215 insertions(+), 129 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index bcef44440..30cfddcd4 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -15,9 +15,6 @@ Author: Notes: - TBD: also keep track of which fresh constants are introduced - to instruct model converter to delete them. - --*/ #include "ast/rewriter/bit_blaster/bit_blaster_rewriter.h" #include "ast/bv_decl_plugin.h" @@ -95,6 +92,8 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { func_decl_ref_vector m_keys; expr_ref_vector m_values; unsigned_vector m_keyval_lim; + func_decl_ref_vector m_newbits; + unsigned_vector m_newbits_lim; bool m_blast_mul; bool m_blast_add; @@ -121,7 +120,8 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { m_out(m), m_bindings(m), m_keys(m), - m_values(m) { + m_values(m), + m_newbits(m) { updt_params(p); } @@ -163,6 +163,7 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { void push() { m_keyval_lim.push_back(m_keys.size()); + m_newbits_lim.push_back(m_newbits.size()); } unsigned get_num_scopes() const { @@ -181,6 +182,10 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { m_keys.resize(lim); m_values.resize(lim); m_keyval_lim.resize(new_sz); + + lim = m_newbits_lim[new_sz]; + m_newbits.shrink(lim); + m_newbits_lim.shrink(new_sz); } } @@ -189,10 +194,13 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { void start_rewrite() { m_keypos = m_keys.size(); } - void end_rewrite(obj_map& const2bits) { + + void end_rewrite(obj_map& const2bits, ptr_vector & newbits) { for (unsigned i = m_keypos; i < m_keys.size(); ++i) { const2bits.insert(m_keys[i].get(), m_values[i].get()); } + for (func_decl* f : m_newbits) newbits.push_back(f); + } template @@ -215,6 +223,7 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { m_out.reset(); for (unsigned i = 0; i < bv_size; i++) { m_out.push_back(m().mk_fresh_const(0, b)); + m_newbits.push_back(to_app(m_out.back())->get_decl()); } r = mk_mkbv(m_out); m_const2bits.insert(f, r); @@ -650,7 +659,7 @@ struct bit_blaster_rewriter::imp : public rewriter_tpl { void push() { m_cfg.push(); } void pop(unsigned s) { m_cfg.pop(s); } void start_rewrite() { m_cfg.start_rewrite(); } - void end_rewrite(obj_map& const2bits) { m_cfg.end_rewrite(const2bits); } + void end_rewrite(obj_map& const2bits, ptr_vector & newbits) { m_cfg.end_rewrite(const2bits, newbits); } unsigned get_num_scopes() const { return m_cfg.get_num_scopes(); } }; @@ -703,6 +712,6 @@ void bit_blaster_rewriter::start_rewrite() { m_imp->start_rewrite(); } -void bit_blaster_rewriter::end_rewrite(obj_map& const2bits) { - m_imp->end_rewrite(const2bits); +void bit_blaster_rewriter::end_rewrite(obj_map& const2bits, ptr_vector & newbits) { + m_imp->end_rewrite(const2bits, newbits); } diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h index 2463bd086..24b6b0c0a 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.h @@ -33,13 +33,15 @@ public: ast_manager & m() const; unsigned get_num_steps() const; void cleanup(); - obj_map const& const2bits() const; void start_rewrite(); - void end_rewrite(obj_map& const2bits); + void end_rewrite(obj_map& const2bits, ptr_vector & newbits); void operator()(expr * e, expr_ref & result, proof_ref & result_proof); void push(); void pop(unsigned num_scopes); unsigned get_num_scopes() const; +private: + obj_map const& const2bits() const; + }; #endif diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 42efb3c6c..f549b944b 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -255,11 +255,11 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons rational slack(0); m_args.reset(); m_coeffs.reset(); - for (unsigned i = 0; i < sz; ++i) { - m_args.push_back(vec[i].first); - m_coeffs.push_back(vec[i].second); - SASSERT(vec[i].second.is_pos()); - slack += vec[i].second; + for (auto const& kv : vec) { + m_args.push_back(kv.first); + m_coeffs.push_back(kv.second); + SASSERT(kv.second.is_pos()); + slack += kv.second; all_unit &= m_coeffs.back().is_one(); } if (is_eq) { @@ -287,7 +287,9 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons } else { expr_ref_vector conj(m), disj(m); - for (unsigned i = 0; i < m_args.size(); ++i) { + unsigned j = 0; + sz = m_args.size(); + for (unsigned i = 0; i < sz; ++i) { rational& c = m_coeffs[i]; if (slack < c + k) { conj.push_back(m_args[i]); @@ -299,29 +301,25 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons disj.push_back(m_args[i]); } else { - continue; + m_args[j] = m_args[i]; + m_coeffs[j] = m_coeffs[i]; + ++j; } - m_args[i] = m_args.back(); - m_coeffs[i] = m_coeffs.back(); - --i; - m_args.pop_back(); - m_coeffs.pop_back(); } - sz = m_coeffs.size(); - if (slack < k) { - conj.push_back(m.mk_false()); + m_args.shrink(j); + m_coeffs.shrink(j); + sz = j; + if (k.is_pos() && sz > 0 && slack >= k) { + disj.push_back(m_util.mk_ge(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k)); } - else if (k.is_pos() && sz > 0) { - conj.push_back(m_util.mk_ge(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k)); + if (!disj.empty()) { + conj.push_back(mk_or(disj)); } result = mk_and(conj); - if (!disj.empty()) { - disj.push_back(result); - result = mk_or(disj); - } - if (!disj.empty() || conj.size() > 1) { + + if (disj.size() > 1 || conj.size() > 1) { st = BR_REWRITE3; - } + } } break; } diff --git a/src/ast/rewriter/pb_rewriter_def.h b/src/ast/rewriter/pb_rewriter_def.h index aa2c2a61f..e4a7e012d 100644 --- a/src/ast/rewriter/pb_rewriter_def.h +++ b/src/ast/rewriter/pb_rewriter_def.h @@ -45,25 +45,25 @@ void pb_rewriter_util::unique(typename PBU::args_t& args, typename PBU::num } } // remove constants - for (unsigned i = 0; i < args.size(); ++i) { + unsigned j = 0, sz = args.size(); + for (unsigned i = 0; i < sz; ++i) { if (m_util.is_true(args[i].first)) { k -= args[i].second; - std::swap(args[i], args[args.size()-1]); - args.pop_back(); - --i; } else if (m_util.is_false(args[i].first)) { - std::swap(args[i], args[args.size()-1]); - args.pop_back(); - --i; + // no-op + } + else { + args[j++] = args[i]; } } + args.shrink(j); // sort and coalesce arguments: typename PBU::compare cmp; std::sort(args.begin(), args.end(), cmp); // coallesce - unsigned i, j; + unsigned i; for (i = 0, j = 1; j < args.size(); ++j) { if (args[i].first == args[j].first) { args[i].second += args[j].second; diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 636bbf9f9..ef264eb9e 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -266,7 +266,7 @@ namespace opt { } } - IF_VERBOSE(1, verbose_stream() << "is-sat: " << is_sat << "\n"; + IF_VERBOSE(5, verbose_stream() << "is-sat: " << is_sat << "\n"; if (is_sat == l_true) { verbose_stream() << "Satisfying soft constraints\n"; display_answer(verbose_stream()); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index ec2059642..8cbcbed5e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -17,6 +17,7 @@ Notes: --*/ +#include "util/gparams.h" #include "ast/for_each_expr.h" #include "ast/ast_pp.h" #include "ast/bv_decl_plugin.h" @@ -125,7 +126,7 @@ namespace opt { m_box_index(UINT_MAX), m_optsmt(m), m_scoped_state(m), - m_fm(m, "opt"), + m_fm(alloc(generic_model_converter, m, "opt")), m_objective_refs(m), m_enable_sat(false), m_is_clausal(false), @@ -277,9 +278,12 @@ namespace opt { if (is_sat != l_false) { s.get_model(m_model); s.get_labels(m_labels); + if (is_sat == l_true) { + validate_model(); + } } if (is_sat != l_true) { - TRACE("opt", tout << m_hard_constraints << "\n";); + TRACE("opt", tout << m_hard_constraints << "\n";); return is_sat; } IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n";); @@ -308,6 +312,7 @@ namespace opt { break; } } + if (is_sat == l_true) validate_model(); return adjust_unknown(is_sat); } @@ -324,8 +329,8 @@ namespace opt { void context::fix_model(model_ref& mdl) { if (mdl) { + (*m_fm)(mdl); apply(m_model_converter, mdl); - m_fm(mdl); } } @@ -568,7 +573,7 @@ namespace opt { void context::init_solver() { setup_arith_solver(); - m_opt_solver = alloc(opt_solver, m, m_params, m_fm); + m_opt_solver = alloc(opt_solver, m, m_params, *m_fm); m_opt_solver->set_logic(m_logic); m_solver = m_opt_solver.get(); m_opt_solver->ensure_pb(); @@ -792,13 +797,13 @@ namespace opt { offset -= weight; } if (m.is_true(arg)) { - IF_VERBOSE(1, verbose_stream() << weight << ": " << mk_pp(m_objectives[index].m_terms[i].get(), m) << " |-> true\n";); + IF_VERBOSE(5, verbose_stream() << weight << ": " << mk_pp(m_objectives[index].m_terms[i].get(), m) << " |-> true\n";); } else if (weight.is_zero()) { // skip } else if (m.is_false(arg)) { - IF_VERBOSE(1, verbose_stream() << weight << ": " << mk_pp(m_objectives[index].m_terms[i].get(), m) << " |-> false\n";); + IF_VERBOSE(5, verbose_stream() << weight << ": " << mk_pp(m_objectives[index].m_terms[i].get(), m) << " |-> false\n";); offset += weight; } else { @@ -924,8 +929,7 @@ namespace opt { TRACE("opt", tout << fmls << "\n";); m_hard_constraints.reset(); expr_ref orig_term(m); - for (unsigned i = 0; i < fmls.size(); ++i) { - expr* fml = fmls[i]; + for (expr * fml : fmls) { app_ref tr(m); expr_ref_vector terms(m); vector weights; @@ -1110,8 +1114,7 @@ namespace opt { } void context::internalize() { - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective & obj = m_objectives[i]; + for (objective & obj : m_objectives) { switch(obj.m_type) { case O_MINIMIZE: { app_ref tmp(m); @@ -1397,21 +1400,21 @@ namespace opt { } std::string context::to_string() const { - return to_string(m_scoped_state.m_hard, m_scoped_state.m_objectives); + return to_string(false, m_scoped_state.m_hard, m_scoped_state.m_objectives); } std::string context::to_string_internal() const { - return to_string(m_hard_constraints, m_objectives); + return to_string(true, m_hard_constraints, m_objectives); } - std::string context::to_string(expr_ref_vector const& hard, vector const& objectives) const { + std::string context::to_string(bool is_internal, expr_ref_vector const& hard, vector const& objectives) const { smt2_pp_environment_dbg env(m); ast_pp_util visitor(m); std::ostringstream out; visitor.collect(hard); + model_converter_ref mc = concat(m_model_converter.get(), m_fm.get()); - for (unsigned i = 0; i < objectives.size(); ++i) { - objective const& obj = objectives[i]; + for (objective const& obj : objectives) { switch(obj.m_type) { case O_MAXIMIZE: case O_MINIMIZE: @@ -1426,10 +1429,16 @@ namespace opt { } } + if (is_internal && mc) { + mc->collect(visitor); + } + + param_descrs descrs; + collect_param_descrs(descrs); + m_params.display_smt2(out, "opt", descrs); visitor.display_decls(out); visitor.display_asserts(out, hard, m_pp_neat); - for (unsigned i = 0; i < objectives.size(); ++i) { - objective const& obj = objectives[i]; + for (objective const& obj : objectives) { switch(obj.m_type) { case O_MAXIMIZE: out << "(maximize "; @@ -1464,15 +1473,33 @@ namespace opt { break; } } - - param_descrs descrs; - collect_param_descrs(descrs); - m_params.display_smt2(out, "opt", descrs); - + if (is_internal && mc) { + mc->display(out); + } + out << "(check-sat)\n"; return out.str(); } + void context::validate_model() { + if (!gparams::get().get_bool("model_validate", false)) return; + expr_ref_vector fmls(m); + get_hard_constraints(fmls); + expr_ref tmp(m); + model_ref mdl; + get_model(mdl); + for (expr * f : fmls) { + if (!mdl->eval(f, tmp) || !m.is_true(tmp)) { + //IF_VERBOSE(0, m_fm->display(verbose_stream() << "fm\n")); + //IF_VERBOSE(0, m_model_converter->display(verbose_stream() << "mc\n")); + IF_VERBOSE(0, verbose_stream() << "Failed to validate " << mk_pp(f, m) << "\n" << tmp << "\n"); + //IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *mdl, 0)); + IF_VERBOSE(11, verbose_stream() << to_string_internal() << "\n"); + exit(0); + } + } + } + void context::validate_maxsat(symbol const& id) { maxsmt& ms = *m_maxsmts.find(id); TRACE("opt", tout << "Validate: " << id << "\n";); @@ -1551,8 +1578,8 @@ namespace opt { if (!m_arith.is_real(m_objectives[0].m_term)) { return false; } - for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { - if (has_quantifiers(m_hard_constraints[i].get())) { + for (expr* fml : m_hard_constraints) { + if (has_quantifiers(fml)) { return true; } } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index be0ef873c..e4d1f8e2d 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -155,7 +155,7 @@ namespace opt { vector m_objectives; model_ref m_model; model_converter_ref m_model_converter; - generic_model_converter m_fm; + generic_model_converter_ref m_fm; obj_map m_objective_fns; obj_map m_objective_orig; func_decl_ref_vector m_objective_refs; @@ -219,7 +219,7 @@ namespace opt { virtual expr_ref mk_le(unsigned i, model_ref& model); virtual smt::context& smt_context() { return m_opt_solver->get_context(); } - virtual generic_model_converter& fm() { return m_fm; } + virtual generic_model_converter& fm() { return *m_fm; } virtual bool sat_enabled() const { return 0 != m_sat_solver.get(); } virtual solver& get_solver(); virtual ast_manager& get_manager() const { return this->m; } @@ -290,12 +290,13 @@ namespace opt { void display_objective(std::ostream& out, objective const& obj) const; void display_bounds(std::ostream& out, bounds_t const& b) const; - std::string to_string(expr_ref_vector const& hard, vector const& objectives) const; + std::string to_string(bool is_internal, expr_ref_vector const& hard, vector const& objectives) const; std::string to_string_internal() const; void validate_lex(); void validate_maxsat(symbol const& id); + void validate_model(); void display_benchmark(); diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 3ef422d6a..ebc198e61 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -20,6 +20,7 @@ Revision History: #include "sat/ba_solver.h" #include "sat/sat_types.h" #include "util/mpz.h" +#include "sat/sat_simplifier_params.hpp" namespace sat { @@ -3013,19 +3014,21 @@ namespace sat { } unsigned ba_solver::set_non_external() { + sat_simplifier_params p(s().m_params); // set variables to be non-external if they are not used in theory constraints. unsigned ext = 0; - for (unsigned v = 0; v < s().num_vars(); ++v) { + bool incremental_mode = s().get_config().m_incremental && !p.override_incremental(); + incremental_mode |= s().tracking_assumptions(); + for (unsigned v = 0; !incremental_mode && v < s().num_vars(); ++v) { literal lit(v, false); if (s().is_external(v) && m_cnstr_use_list[lit.index()].empty() && - m_cnstr_use_list[(~lit).index()].empty() && - !s().is_assumption(v)) { + m_cnstr_use_list[(~lit).index()].empty()) { s().set_non_external(v); ++ext; } } - // ensure that lemmas use only external variables. + // ensure that lemmas use only non-eliminated variables for (constraint* cp : m_learned) { constraint& c = *cp; if (c.was_removed()) continue; @@ -4182,6 +4185,9 @@ namespace sat { bool ba_solver::check_model(model const& m) const { bool ok = true; for (constraint const* c : m_constraints) { + if (c->is_pure() && c->lit() != null_literal && m[c->lit().var()] == (c->lit().sign() ? l_true : l_false)) { + continue; + } switch (eval(m, *c)) { case l_false: IF_VERBOSE(0, verbose_stream() << "failed checking " << c->id() << ": " << *c << "\n";); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4f2752fe6..5c937a5fb 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2358,6 +2358,14 @@ namespace sat { idx--; } reset_unmark(old_size); + if (m_core.size() > 1) { + unsigned j = 0; + for (unsigned i = 0; i < m_core.size(); ++i) { + if (lvl(m_core[i]) > 0) m_core[j++] = m_core[i]; + } + m_core.shrink(j); + } + if (m_config.m_core_minimize) { if (m_min_core_valid && m_min_core.size() < m_core.size()) { IF_VERBOSE(1, verbose_stream() << "(sat.updating core " << m_min_core.size() << " " << m_core.size() << ")\n";); diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index ed8f48762..4d7325ecb 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -18,6 +18,7 @@ Notes: --*/ +#include "util/gparams.h" #include "ast/ast_pp.h" #include "ast/ast_translation.h" #include "ast/ast_util.h" @@ -584,7 +585,9 @@ private: } bool internalize_var(expr* v, sat::bool_var_vector& bvars) { - obj_map const& const2bits = m_bb_rewriter->const2bits(); + obj_map const2bits; + ptr_vector newbits; + m_bb_rewriter->end_rewrite(const2bits, newbits); expr* bv; bv_util bvutil(m); bool internalized = false; @@ -803,12 +806,13 @@ private: } TRACE("sat", model_smt2_pp(tout, m, *mdl, 0);); - // IF_VERBOSE(0, model_smt2_pp(verbose_stream() << "after\n", m, *mdl, 0);); -#if 0 - IF_VERBOSE(0, verbose_streamm() << "Verifying solution\n";); + if (!gparams::get().get_bool("model_validate", false)) return; + IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); model_evaluator eval(*mdl); + eval.set_model_completion(false); bool all_true = true; + //unsigned i = 0; for (expr * f : m_fmls) { expr_ref tmp(m); eval(f, tmp); @@ -819,19 +823,21 @@ private: IF_VERBOSE(0, verbose_stream() << "failed to verify: " << mk_pp(f, m) << "\n";); all_true = false; } - else { - VERIFY(m.is_true(tmp)); - } + //IF_VERBOSE(0, verbose_stream() << (i++) << ": " << mk_pp(f, m) << "\n"); } if (!all_true) { - IF_VERBOSE(0, verbose_stream() << m_params << "\n";); - IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "sat mc\n");); - IF_VERBOSE(0, if (m_mcs.back()) m_mcs.back()->display(verbose_stream() << "mc0\n");); + IF_VERBOSE(0, verbose_stream() << m_params << "\n"); + IF_VERBOSE(0, m_sat_mc->display(verbose_stream() << "sat mc\n")); + IF_VERBOSE(0, if (m_mcs.back()) m_mcs.back()->display(verbose_stream() << "mc0\n")); //IF_VERBOSE(0, m_solver.display(verbose_stream())); - IF_VERBOSE(0, for (auto const& kv : m_map) verbose_stream() << mk_pp(kv.m_key, m) << " |-> " << kv.m_value << "\n";); + IF_VERBOSE(0, for (auto const& kv : m_map) verbose_stream() << mk_pp(kv.m_key, m) << " |-> " << kv.m_value << "\n"); + } + else { + IF_VERBOSE(0, verbose_stream() << "solution verified\n"); +// IF_VERBOSE(0, if (m_mcs.back()) m_mcs.back()->display(verbose_stream() << "mcs\n")); +// IF_VERBOSE(0, if (m_sat_mc) m_sat_mc->display(verbose_stream() << "sat_mc\n")); +// IF_VERBOSE(0, model_smt2_pp(verbose_stream() << "after\n", m, *mdl, 0);); } - -#endif } }; diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 6ace1300a..785ecb57e 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -31,10 +31,15 @@ template struct bit_blaster_model_converter : public model_converter { func_decl_ref_vector m_vars; expr_ref_vector m_bits; + func_decl_ref_vector m_newbits; ast_manager & m() const { return m_vars.get_manager(); } - bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits):m_vars(m), m_bits(m) { + bit_blaster_model_converter( + ast_manager & m, + obj_map const & const2bits, + ptr_vector const& newbits): + m_vars(m), m_bits(m), m_newbits(m) { for (auto const& kv : const2bits) { func_decl * v = kv.m_key; expr * bits = kv.m_value; @@ -43,6 +48,8 @@ struct bit_blaster_model_converter : public model_converter { m_vars.push_back(v); m_bits.push_back(bits); } + for (func_decl* f : newbits) + m_newbits.push_back(f); } virtual ~bit_blaster_model_converter() { @@ -200,10 +207,11 @@ struct bit_blaster_model_converter : public model_converter { } void display(std::ostream & out) override { + for (func_decl * f : m_newbits) + display_del(out, f); unsigned sz = m_vars.size(); - for (unsigned i = 0; i < sz; i++) { + for (unsigned i = 0; i < sz; i++) display_add(out, m(), m_vars.get(i), m_bits.get(i)); - } } void get_units(obj_map& units) override { @@ -211,7 +219,7 @@ struct bit_blaster_model_converter : public model_converter { } protected: - bit_blaster_model_converter(ast_manager & m):m_vars(m), m_bits(m) { } + bit_blaster_model_converter(ast_manager & m):m_vars(m), m_bits(m), m_newbits(m) { } public: model_converter * translate(ast_translation & translator) override { @@ -220,16 +228,18 @@ public: res->m_vars.push_back(translator(v)); for (expr* b : m_bits) res->m_bits.push_back(translator(b)); + for (func_decl* f : m_newbits) + res->m_newbits.push_back(translator(f)); return res; } }; -model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits) { - return const2bits.empty() ? nullptr : alloc(bit_blaster_model_converter, m, const2bits); +model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits, ptr_vector const& newbits) { + return const2bits.empty() ? nullptr : alloc(bit_blaster_model_converter, m, const2bits, newbits); } -model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map const & const2bits) { - return const2bits.empty() ? nullptr : alloc(bit_blaster_model_converter, m, const2bits); +model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map const & const2bits, ptr_vector const& newbits) { + return const2bits.empty() ? nullptr : alloc(bit_blaster_model_converter, m, const2bits, newbits); } diff --git a/src/tactic/bv/bit_blaster_model_converter.h b/src/tactic/bv/bit_blaster_model_converter.h index f7dd254b4..057891ec6 100644 --- a/src/tactic/bv/bit_blaster_model_converter.h +++ b/src/tactic/bv/bit_blaster_model_converter.h @@ -21,7 +21,7 @@ Notes: #include "tactic/model_converter.h" -model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits); -model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map const & const2bits); +model_converter * mk_bit_blaster_model_converter(ast_manager & m, obj_map const & const2bits, ptr_vector const& newbits); +model_converter * mk_bv1_blaster_model_converter(ast_manager & m, obj_map const & const2bits, ptr_vector const& newbits); #endif diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 39300b7dc..172768feb 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -86,8 +86,9 @@ class bit_blaster_tactic : public tactic { if (change && g->models_enabled()) { obj_map const2bits; - m_rewriter->end_rewrite(const2bits); - g->add(mk_bit_blaster_model_converter(m(), const2bits)); + ptr_vector newbits; + m_rewriter->end_rewrite(const2bits, newbits); + g->add(mk_bit_blaster_model_converter(m(), const2bits, newbits)); } g->inc_depth(); result.push_back(g.get()); diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index d23d7a308..a34f1eb15 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -36,6 +36,7 @@ class bv1_blaster_tactic : public tactic { ast_manager & m_manager; bv_util m_util; obj_map m_const2bits; + ptr_vector m_newbits; expr_ref_vector m_saved; expr_ref m_bit1; expr_ref m_bit0; @@ -107,6 +108,7 @@ class bv1_blaster_tactic : public tactic { ptr_buffer bits; for (unsigned i = 0; i < bv_size; i++) { bits.push_back(m().mk_fresh_const(0, b)); + m_newbits.push_back(to_app(bits.back())->get_decl()); } r = butil().mk_concat(bits.size(), bits.c_ptr()); m_saved.push_back(r); @@ -405,7 +407,7 @@ class bv1_blaster_tactic : public tactic { } if (g->models_enabled()) - g->add(mk_bv1_blaster_model_converter(m(), m_rw.cfg().m_const2bits)); + g->add(mk_bv1_blaster_model_converter(m(), m_rw.cfg().m_const2bits, m_rw.cfg().m_newbits)); g->inc_depth(); result.push_back(g.get()); m_rw.cfg().cleanup(); diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 45ff6250a..3f29005b3 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -23,6 +23,7 @@ Revision History: #include "ast/ast_smt2_pp.h" #include "ast/expr_substitution.h" #include "tactic/goal_shared_occs.h" +#include "ast/pb_decl_plugin.h" class propagate_values_tactic : public tactic { struct imp { @@ -129,10 +130,23 @@ class propagate_values_tactic : public tactic { } TRACE("shallow_context_simplifier_bug", tout << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n";); - push_result(new_curr, new_pr); - - if (new_curr != curr) + if (new_curr != curr) { m_modified = true; + //if (has_pb(curr)) + // IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(curr, m) << "\n---->\n" << mk_ismt2_pp(new_curr, m) << "\n"); + } + push_result(new_curr, new_pr); + } + + bool has_pb(expr* e) { + pb_util pb(m); + if (pb.is_ge(e)) return true; + if (m.is_or(e)) { + for (expr* a : *to_app(e)) { + if (pb.is_ge(a)) return true; + } + } + return false; } void operator()(goal_ref const & g, @@ -206,6 +220,7 @@ class propagate_values_tactic : public tactic { SASSERT(m_goal->is_well_sorted()); TRACE("propagate_values", tout << "end\n"; m_goal->display(tout);); TRACE("propagate_values_core", m_goal->display_with_dependencies(tout);); + //IF_VERBOSE(0, m_goal->display(verbose_stream())); m_goal = 0; } }; diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 5fbf9aaf5..08b771df5 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -23,6 +23,7 @@ Revision History: #include "util/cooperate.h" #include "tactic/goal_shared_occs.h" #include "ast/ast_pp.h" +#include "ast/pb_decl_plugin.h" class solve_eqs_tactic : public tactic { struct imp { @@ -347,10 +348,8 @@ class solve_eqs_tactic : public tactic { TRACE("solve_eqs", tout << "candidate vars:\n"; - ptr_vector::iterator it = m_vars.begin(); - ptr_vector::iterator end = m_vars.end(); - for (; it != end; ++it) { - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_vars) { + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); } @@ -492,11 +491,9 @@ class solve_eqs_tactic : public tactic { TRACE("solve_eqs", tout << "ordered vars:\n"; - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - SASSERT(m_candidate_vars.is_marked(*it)); - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_ordered_vars) { + SASSERT(m_candidate_vars.is_marked(v)); + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); m_candidate_vars.reset(); @@ -529,8 +526,7 @@ class solve_eqs_tactic : public tactic { m_subst->reset(); TRACE("solve_eqs", tout << "after normalizing variables\n"; - for (unsigned i = 0; i < m_ordered_vars.size(); i++) { - expr * v = m_ordered_vars[i]; + for (expr * v : m_ordered_vars) { expr * def = 0; proof * pr = 0; expr_dependency * dep = 0; @@ -539,16 +535,15 @@ class solve_eqs_tactic : public tactic { }); #if 0 DEBUG_CODE({ - for (unsigned i = 0; i < m_ordered_vars.size(); i++) { - expr * v = m_ordered_vars[i]; - expr * def = 0; - proof * pr = 0; - expr_dependency * dep = 0; - m_norm_subst->find(v, def, pr, dep); - SASSERT(def != 0); - CASSERT("solve_eqs_bug", !occurs(v, def)); - } - }); + for (expr * v : m_ordered_vars) { + expr * def = 0; + proof * pr = 0; + expr_dependency * dep = 0; + m_norm_subst->find(v, def, pr, dep); + SASSERT(def != 0); + CASSERT("solve_eqs_bug", !occurs(v, def)); + } + }); #endif } @@ -575,6 +570,13 @@ class solve_eqs_tactic : public tactic { } m_r->operator()(f, new_f, new_pr, new_dep); +#if 0 + pb_util pb(m()); + if (pb.is_ge(f) && f != new_f) { + IF_VERBOSE(0, verbose_stream() << mk_ismt2_pp(f, m()) << "\n--->\n" << mk_ismt2_pp(new_f, m()) << "\n"); + } +#endif + TRACE("solve_eqs_subst", tout << mk_ismt2_pp(f, m()) << "\n--->\n" << mk_ismt2_pp(new_f, m()) << "\n";); m_num_steps += m_r->get_num_steps() + 1; if (m_produce_proofs) @@ -592,12 +594,11 @@ class solve_eqs_tactic : public tactic { g.display(tout);); #if 0 DEBUG_CODE({ - for (unsigned i = 0; i < m_ordered_vars.size(); i++) { - expr * v = m_ordered_vars[i]; - for (unsigned j = 0; j < g.size(); j++) { - CASSERT("solve_eqs_bug", !occurs(v, g.form(j))); - } - }}); + for (expr* v : m_ordered_vars) { + for (unsigned j = 0; j < g.size(); j++) { + CASSERT("solve_eqs_bug", !occurs(v, g.form(j))); + } + }}); #endif } From 5651d00751a1eb40b94db86f00cb7d3ec9711c4d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Mar 2018 13:21:31 -0700 Subject: [PATCH 0635/1283] fix #1534 Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/upolynomial.cpp | 18 ++++++++---------- src/smt/theory_str.cpp | 18 ++++++++++-------- src/smt/theory_str.h | 9 +++++---- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index f7cc16de2..cc2442981 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -781,17 +781,15 @@ namespace upolynomial { set(q.size(), q.c_ptr(), C); m().set(bound, p); } + else if (q.size() < C.size() || m().m().is_even(p) || m().m().is_even(bound)) { + // discard accumulated image, it was affected by unlucky primes + TRACE("mgcd", tout << "discarding image\n";); + set(q.size(), q.c_ptr(), C); + m().set(bound, p); + } else { - if (q.size() < C.size()) { - // discard accumulated image, it was affected by unlucky primes - TRACE("mgcd", tout << "discarding image\n";); - set(q.size(), q.c_ptr(), C); - m().set(bound, p); - } - else { - CRA_combine_images(q, p, C, bound); - TRACE("mgcd", tout << "new combined:\n"; display_star(tout, C); tout << "\n";); - } + CRA_combine_images(q, p, C, bound); + TRACE("mgcd", tout << "new combined:\n"; display_star(tout, C); tout << "\n";); } numeral_vector & candidate = q; get_primitive(C, candidate); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 3335370eb..0016b8f36 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -5553,7 +5553,8 @@ namespace smt { return node; } - void theory_str::get_grounded_concats(expr* node, std::map & varAliasMap, + void theory_str::get_grounded_concats(unsigned depth, + expr* node, std::map & varAliasMap, std::map & concatAliasMap, std::map & varConstMap, std::map & concatConstMap, std::map > & varEqConcatMap, std::map, std::set > > & groundedMap) { @@ -5568,6 +5569,9 @@ namespace smt { if (groundedMap.find(node) != groundedMap.end()) { return; } + IF_VERBOSE(100, verbose_stream() << "concats " << depth << "\n"; + if (depth > 100) verbose_stream() << mk_pp(node, get_manager()) << "\n"; + ); // haven't computed grounded concats for "node" (de-aliased) // --------------------------------------------------------- @@ -5595,12 +5599,10 @@ namespace smt { // merge arg0 and arg1 expr * arg0 = to_app(node)->get_arg(0); expr * arg1 = to_app(node)->get_arg(1); - SASSERT(arg0 != node); - SASSERT(arg1 != node); expr * arg0DeAlias = dealias_node(arg0, varAliasMap, concatAliasMap); expr * arg1DeAlias = dealias_node(arg1, varAliasMap, concatAliasMap); - get_grounded_concats(arg0DeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); - get_grounded_concats(arg1DeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); + get_grounded_concats(depth + 1, arg0DeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); + get_grounded_concats(depth + 1, arg1DeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); std::map, std::set >::iterator arg0_grdItor = groundedMap[arg0DeAlias].begin(); std::map, std::set >::iterator arg1_grdItor; @@ -5650,7 +5652,7 @@ namespace smt { else if (varEqConcatMap.find(node) != varEqConcatMap.end()) { expr * eqConcat = varEqConcatMap[node].begin()->first; expr * deAliasedEqConcat = dealias_node(eqConcat, varAliasMap, concatAliasMap); - get_grounded_concats(deAliasedEqConcat, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); + get_grounded_concats(depth + 1, deAliasedEqConcat, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); std::map, std::set >::iterator grdItor = groundedMap[deAliasedEqConcat].begin(); for (; grdItor != groundedMap[deAliasedEqConcat].end(); grdItor++) { @@ -5859,8 +5861,8 @@ namespace smt { expr* strDeAlias = dealias_node(str, varAliasMap, concatAliasMap); expr* subStrDeAlias = dealias_node(subStr, varAliasMap, concatAliasMap); - get_grounded_concats(strDeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); - get_grounded_concats(subStrDeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); + get_grounded_concats(0, strDeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); + get_grounded_concats(0, subStrDeAlias, varAliasMap, concatAliasMap, varConstMap, concatConstMap, varEqConcatMap, groundedMap); // debugging print_grounded_concat(strDeAlias, groundedMap); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 9288bac7c..64ede71b5 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -495,10 +495,11 @@ protected: std::map & concatAliasMap, std::map & varConstMap, std::map & concatConstMap, std::map > & varEqConcatMap); expr * dealias_node(expr * node, std::map & varAliasMap, std::map & concatAliasMap); - void get_grounded_concats(expr* node, std::map & varAliasMap, - std::map & concatAliasMap, std::map & varConstMap, - std::map & concatConstMap, std::map > & varEqConcatMap, - std::map, std::set > > & groundedMap); + void get_grounded_concats(unsigned depth, + expr* node, std::map & varAliasMap, + std::map & concatAliasMap, std::map & varConstMap, + std::map & concatConstMap, std::map > & varEqConcatMap, + std::map, std::set > > & groundedMap); void print_grounded_concat(expr * node, std::map, std::set > > & groundedMap); void check_subsequence(expr* str, expr* strDeAlias, expr* subStr, expr* subStrDeAlias, expr* boolVar, std::map, std::set > > & groundedMap); From 73f7e301c3f60924a8d7e1518e714711eeb5f059 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 12 Mar 2018 17:09:55 -0400 Subject: [PATCH 0636/1283] preliminary refactoring to use obj_map --- src/smt/theory_str.cpp | 19 ++++++++++--------- src/smt/theory_str.h | 21 ++++++++++----------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 3335370eb..90eb01fa8 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -4582,8 +4582,9 @@ namespace smt { std::pair key = std::make_pair(concat, unroll); expr_ref toAssert(mgr); + expr * _toAssert; - if (concat_eq_unroll_ast_map.find(key) == concat_eq_unroll_ast_map.end()) { + if (!concat_eq_unroll_ast_map.find(concat, unroll, _toAssert)) { expr_ref arg1(to_app(concat)->get_arg(0), mgr); expr_ref arg2(to_app(concat)->get_arg(1), mgr); expr_ref r1(to_app(unroll)->get_arg(0), mgr); @@ -4634,9 +4635,9 @@ namespace smt { toAssert = mgr.mk_and(opAnd1, opAnd2); m_trail.push_back(toAssert); - concat_eq_unroll_ast_map[key] = toAssert; + concat_eq_unroll_ast_map.insert(concat, unroll, toAssert); } else { - toAssert = concat_eq_unroll_ast_map[key]; + toAssert = _toAssert; } assert_axiom(toAssert); @@ -4920,7 +4921,7 @@ namespace smt { expr_ref_vector litems(m); - if (contain_pair_idx_map.find(varNode) != contain_pair_idx_map.end()) { + if (contain_pair_idx_map.contains(varNode)) { std::set >::iterator itor1 = contain_pair_idx_map[varNode].begin(); for (; itor1 != contain_pair_idx_map[varNode].end(); ++itor1) { expr * strAst = itor1->first; @@ -5057,7 +5058,7 @@ namespace smt { ast_manager & m = get_manager(); expr_ref_vector litems(m); - if (contain_pair_idx_map.find(varNode) != contain_pair_idx_map.end()) { + if (contain_pair_idx_map.contains(varNode)) { std::set >::iterator itor1 = contain_pair_idx_map[varNode].begin(); for (; itor1 != contain_pair_idx_map[varNode].end(); ++itor1) { expr * strAst = itor1->first; @@ -5125,7 +5126,7 @@ namespace smt { } bool theory_str::in_contain_idx_map(expr * n) { - return contain_pair_idx_map.find(n) != contain_pair_idx_map.end(); + return contain_pair_idx_map.contains(n); } void theory_str::check_contain_by_eq_nodes(expr * n1, expr * n2) { @@ -6456,7 +6457,7 @@ namespace smt { } else { expr_ref_vector::iterator itor = eqNodeSet.begin(); for (; itor != eqNodeSet.end(); itor++) { - if (regex_in_var_reg_str_map.find(*itor) != regex_in_var_reg_str_map.end()) { + if (regex_in_var_reg_str_map.contains(*itor)) { std::set::iterator strItor = regex_in_var_reg_str_map[*itor].begin(); for (; strItor != regex_in_var_reg_str_map[*itor].end(); strItor++) { zstring regStr = *strItor; @@ -6469,7 +6470,7 @@ namespace smt { expr * regexTerm = a_regexIn->get_arg(1); // TODO figure out regex NFA stuff - if (regex_nfa_cache.find(regexTerm) == regex_nfa_cache.end()) { + if (!regex_nfa_cache.contains(regexTerm)) { TRACE("str", tout << "regex_nfa_cache: cache miss" << std::endl;); regex_nfa_cache[regexTerm] = nfa(u, regexTerm); } else { @@ -9596,7 +9597,7 @@ namespace smt { if (low.is_neg()) { toAssert = m_autil.mk_ge(cntInUnr, mk_int(0)); } else { - if (unroll_var_map.find(unrFunc) == unroll_var_map.end()) { + if (!unroll_var_map.contains(unrFunc)) { expr_ref newVar1(mk_regex_rep_var(), mgr); expr_ref newVar2(mk_regex_rep_var(), mgr); diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 9288bac7c..5a249f5dc 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -312,30 +312,29 @@ protected: obj_hashtable input_var_in_len; obj_map fvar_len_count_map; - std::map > fvar_lenTester_map; + obj_map > fvar_lenTester_map; obj_map lenTester_fvar_map; - std::map > > > fvar_valueTester_map; - std::map valueTester_fvar_map; + obj_map > > > fvar_valueTester_map; + obj_map valueTester_fvar_map; - std::map val_range_map; + obj_map val_range_map; // This can't be an expr_ref_vector because the constructor is wrong, // we would need to modify the allocator so we pass in ast_manager - std::map, ptr_vector > > unroll_tries_map; - std::map unroll_var_map; - std::map, expr*> concat_eq_unroll_ast_map; + obj_map, ptr_vector > > unroll_tries_map; + obj_map unroll_var_map; + obj_pair_map concat_eq_unroll_ast_map; expr_ref_vector contains_map; theory_str_contain_pair_bool_map_t contain_pair_bool_map; - //obj_map > contain_pair_idx_map; - std::map > > contain_pair_idx_map; + obj_map > > contain_pair_idx_map; std::map, expr*> regex_in_bool_map; - std::map > regex_in_var_reg_str_map; + obj_map > regex_in_var_reg_str_map; - std::map regex_nfa_cache; // Regex term --> NFA + obj_map regex_nfa_cache; // Regex term --> NFA svector char_set; std::map charSetLookupTable; From b5471e7fe06a2b7a14ccbcdb4273221f54fa8353 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 12 Mar 2018 20:04:04 -0400 Subject: [PATCH 0637/1283] refactor: use c++11 for (part 1) --- src/smt/theory_str.cpp | 167 ++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 95 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 90eb01fa8..139e25740 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -289,9 +289,8 @@ namespace smt { } static void cut_vars_map_copy(std::map & dest, std::map & src) { - std::map::iterator itor = src.begin(); - for (; itor != src.end(); itor++) { - dest[itor->first] = 1; + for (auto entry : src) { + dest[entry.first] = 1; } } @@ -306,9 +305,8 @@ namespace smt { return false; } - std::map::iterator itor = cut_var_map[n1].top()->vars.begin(); - for (; itor != cut_var_map[n1].top()->vars.end(); ++itor) { - if (cut_var_map[n2].top()->vars.find(itor->first) != cut_var_map[n2].top()->vars.end()) { + for (auto entry : cut_var_map[n1].top()->vars) { + if (cut_var_map[n2].top()->vars.find(entry.first) != cut_var_map[n2].top()->vars.end()) { return true; } } @@ -781,8 +779,8 @@ namespace smt { ptr_vector childrenVector; get_nodes_in_concat(concatAst, childrenVector); expr_ref_vector items(m); - for (unsigned int i = 0; i < childrenVector.size(); i++) { - items.push_back(mk_strlen(childrenVector.get(i))); + for (auto el : childrenVector) { + items.push_back(mk_strlen(el)); } expr_ref lenAssert(ctx.mk_eq_atom(concat_length, m_autil.mk_add(items.size(), items.c_ptr())), m); assert_axiom(lenAssert); @@ -802,32 +800,30 @@ namespace smt { context & ctx = get_context(); while (can_propagate()) { TRACE("str", tout << "propagating..." << std::endl;); - for (unsigned i = 0; i < m_basicstr_axiom_todo.size(); ++i) { - instantiate_basic_string_axioms(m_basicstr_axiom_todo[i]); + for (auto el : m_basicstr_axiom_todo) { + instantiate_basic_string_axioms(el); } m_basicstr_axiom_todo.reset(); TRACE("str", tout << "reset m_basicstr_axiom_todo" << std::endl;); - for (unsigned i = 0; i < m_str_eq_todo.size(); ++i) { - std::pair pair = m_str_eq_todo[i]; + for (auto pair : m_str_eq_todo) { enode * lhs = pair.first; enode * rhs = pair.second; handle_equality(lhs->get_owner(), rhs->get_owner()); } m_str_eq_todo.reset(); - for (unsigned i = 0; i < m_concat_axiom_todo.size(); ++i) { - instantiate_concat_axiom(m_concat_axiom_todo[i]); + for (auto el : m_concat_axiom_todo) { + instantiate_concat_axiom(el); } m_concat_axiom_todo.reset(); - for (unsigned i = 0; i < m_concat_eval_todo.size(); ++i) { - try_eval_concat(m_concat_eval_todo[i]); + for (auto el : m_concat_eval_todo) { + try_eval_concat(el); } m_concat_eval_todo.reset(); - for (unsigned i = 0; i < m_library_aware_axiom_todo.size(); ++i) { - enode * e = m_library_aware_axiom_todo[i]; + for (enode * e : m_library_aware_axiom_todo) { app * a = e->get_owner(); if (u.str.is_stoi(a)) { instantiate_axiom_str_to_int(e); @@ -856,10 +852,10 @@ namespace smt { } m_library_aware_axiom_todo.reset(); - for (unsigned i = 0; i < m_delayed_axiom_setup_terms.size(); ++i) { + for (auto el : m_delayed_axiom_setup_terms) { // I think this is okay - ctx.internalize(m_delayed_axiom_setup_terms[i].get(), false); - set_up_axioms(m_delayed_axiom_setup_terms[i].get()); + ctx.internalize(el, false); + set_up_axioms(el); } m_delayed_axiom_setup_terms.reset(); } @@ -2380,9 +2376,8 @@ namespace smt { } else { expr_ref_vector items(m); int pos = 0; - std::map::iterator itor = resolvedMap.begin(); - for (; itor != resolvedMap.end(); ++itor) { - items.push_back(ctx.mk_eq_atom(itor->first, itor->second)); + for (auto itor : resolvedMap) { + items.push_back(ctx.mk_eq_atom(itor.first, itor.second)); pos += 1; } expr_ref premise(mk_and(items), m); @@ -2558,8 +2553,7 @@ namespace smt { context & ctx = get_context(); // pull each literal out of the arrangement disjunction literal_vector ls; - for (unsigned i = 0; i < terms.size(); ++i) { - expr * e = terms.get(i); + for (expr * e : terms) { literal l = ctx.get_literal(e); ls.push_back(l); } @@ -2572,9 +2566,8 @@ namespace smt { if (cut_var_map.contains(node)) { if (!cut_var_map[node].empty()) { xout << "[" << cut_var_map[node].top()->level << "] "; - std::map::iterator itor = cut_var_map[node].top()->vars.begin(); - for (; itor != cut_var_map[node].top()->vars.end(); ++itor) { - xout << mk_pp(itor->first, m) << ", "; + for (auto entry : cut_var_map[node].top()->vars) { + xout << mk_pp(entry.first, m) << ", "; } xout << std::endl; } @@ -4498,8 +4491,7 @@ namespace smt { } } - for (std::list::iterator itor = overlapLen.begin(); itor != overlapLen.end(); itor++) { - unsigned int overLen = *itor; + for (unsigned int overLen : overlapLen) { zstring prefix = str1Value.extract(0, str1Len - overLen); zstring suffix = str2Value.extract(overLen, str2Len - overLen); @@ -4580,7 +4572,6 @@ namespace smt { TRACE("str", tout << "concat = " << mk_pp(concat, mgr) << ", unroll = " << mk_pp(unroll, mgr) << std::endl;); - std::pair key = std::make_pair(concat, unroll); expr_ref toAssert(mgr); expr * _toAssert; @@ -4922,10 +4913,9 @@ namespace smt { expr_ref_vector litems(m); if (contain_pair_idx_map.contains(varNode)) { - std::set >::iterator itor1 = contain_pair_idx_map[varNode].begin(); - for (; itor1 != contain_pair_idx_map[varNode].end(); ++itor1) { - expr * strAst = itor1->first; - expr * substrAst = itor1->second; + for (auto entry : contain_pair_idx_map[varNode]) { + expr * strAst = entry.first; + expr * substrAst = entry.second; expr * boolVar = nullptr; if (!contain_pair_bool_map.find(strAst, substrAst, boolVar)) { @@ -4983,23 +4973,19 @@ namespace smt { // collect eqc concat std::set eqcConcats; get_concats_in_eqc(substrAst, eqcConcats); - for (std::set::iterator concatItor = eqcConcats.begin(); - concatItor != eqcConcats.end(); concatItor++) { + for (expr * aConcat : eqcConcats) { expr_ref_vector constList(m); bool counterEgFound = false; - // get constant strings in concat - expr * aConcat = *concatItor; get_const_str_asts_in_node(aConcat, constList); - for (expr_ref_vector::iterator cstItor = constList.begin(); - cstItor != constList.end(); cstItor++) { + //for (expr_ref_vector::iterator cstItor = constList.begin(); cstItor != constList.end(); cstItor++) { + for (auto cst : constList) { zstring pieceStr; - u.str.is_string(*cstItor, pieceStr); + u.str.is_string(cst, pieceStr); if (!strConst.contains(pieceStr)) { counterEgFound = true; if (aConcat != substrAst) { litems.push_back(ctx.mk_eq_atom(substrAst, aConcat)); } - //implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); implyR = mk_not(m, boolVar); break; } @@ -5059,10 +5045,9 @@ namespace smt { expr_ref_vector litems(m); if (contain_pair_idx_map.contains(varNode)) { - std::set >::iterator itor1 = contain_pair_idx_map[varNode].begin(); - for (; itor1 != contain_pair_idx_map[varNode].end(); ++itor1) { - expr * strAst = itor1->first; - expr * substrAst = itor1->second; + for (auto entry : contain_pair_idx_map[varNode]) { + expr * strAst = entry.first; + expr * substrAst = entry.second; expr * boolVar = nullptr; if (!contain_pair_bool_map.find(strAst, substrAst, boolVar)) { @@ -5091,17 +5076,16 @@ namespace smt { zstring strConst; u.str.is_string(strValue, strConst); // iterate eqc (also eqc-to-be) of substr - for (expr_ref_vector::iterator itAst = willEqClass.begin(); itAst != willEqClass.end(); itAst++) { + for (auto itAst : willEqClass) { bool counterEgFound = false; - if (u.str.is_concat(to_app(*itAst))) { + if (u.str.is_concat(to_app(itAst))) { expr_ref_vector constList(m); // get constant strings in concat - app * aConcat = to_app(*itAst); + app * aConcat = to_app(itAst); get_const_str_asts_in_node(aConcat, constList); - for (expr_ref_vector::iterator cstItor = constList.begin(); - cstItor != constList.end(); cstItor++) { + for (auto cst : constList) { zstring pieceStr; - u.str.is_string(*cstItor, pieceStr); + u.str.is_string(cst, pieceStr); if (!strConst.contains(pieceStr)) { TRACE("str", tout << "Inconsistency found!" << std::endl;); counterEgFound = true; @@ -5134,12 +5118,13 @@ namespace smt { ast_manager & m = get_manager(); if (in_contain_idx_map(n1) && in_contain_idx_map(n2)) { - std::set >::iterator keysItor1 = contain_pair_idx_map[n1].begin(); - std::set >::iterator keysItor2; + //std::set >::iterator keysItor1 = contain_pair_idx_map[n1].begin(); + //std::set >::iterator keysItor2; - for (; keysItor1 != contain_pair_idx_map[n1].end(); keysItor1++) { + //for (; keysItor1 != contain_pair_idx_map[n1].end(); keysItor1++) { + for (auto key1 : contain_pair_idx_map[n1]) { // keysItor1 is on set {<.., n1>, ..., , ...} - std::pair key1 = *keysItor1; + //std::pair key1 = *keysItor1; if (key1.first == n1 && key1.second == n2) { expr_ref implyL(m); expr_ref implyR(contain_pair_bool_map[key1], m); @@ -5151,10 +5136,10 @@ namespace smt { } } - for (keysItor2 = contain_pair_idx_map[n2].begin(); - keysItor2 != contain_pair_idx_map[n2].end(); keysItor2++) { + //for (keysItor2 = contain_pair_idx_map[n2].begin(); keysItor2 != contain_pair_idx_map[n2].end(); keysItor2++) { + for (auto key2 : contain_pair_idx_map[n2]) { // keysItor2 is on set {<.., n2>, ..., , ...} - std::pair key2 = *keysItor2; + //std::pair key2 = *keysItor2; // skip if the pair is eq if (key1 == key2) { continue; @@ -5248,10 +5233,12 @@ namespace smt { // * key1.first = key2.first // check eqc(key1.second) and eqc(key2.second) // ----------------------------------------------------------- - expr_ref_vector::iterator eqItorSub1 = subAst1Eqc.begin(); - for (; eqItorSub1 != subAst1Eqc.end(); eqItorSub1++) { - expr_ref_vector::iterator eqItorSub2 = subAst2Eqc.begin(); - for (; eqItorSub2 != subAst2Eqc.end(); eqItorSub2++) { + //expr_ref_vector::iterator eqItorSub1 = subAst1Eqc.begin(); + //for (; eqItorSub1 != subAst1Eqc.end(); eqItorSub1++) { + for (auto eqSubVar1 : subAst1Eqc) { + //expr_ref_vector::iterator eqItorSub2 = subAst2Eqc.begin(); + //for (; eqItorSub2 != subAst2Eqc.end(); eqItorSub2++) { + for (auto eqSubVar2 : subAst2Eqc) { // ------------ // key1.first = key2.first /\ containPairBoolMap[] // ==> (containPairBoolMap[key1] --> containPairBoolMap[key2]) @@ -5261,11 +5248,11 @@ namespace smt { if (n1 != n2) { litems3.push_back(ctx.mk_eq_atom(n1, n2)); } - expr * eqSubVar1 = *eqItorSub1; + if (eqSubVar1 != subAst1) { litems3.push_back(ctx.mk_eq_atom(subAst1, eqSubVar1)); } - expr * eqSubVar2 = *eqItorSub2; + if (eqSubVar2 != subAst2) { litems3.push_back(ctx.mk_eq_atom(subAst2, eqSubVar2)); } @@ -5286,11 +5273,11 @@ namespace smt { if (n1 != n2) { litems4.push_back(ctx.mk_eq_atom(n1, n2)); } - expr * eqSubVar1 = *eqItorSub1; + if (eqSubVar1 != subAst1) { litems4.push_back(ctx.mk_eq_atom(subAst1, eqSubVar1)); } - expr * eqSubVar2 = *eqItorSub2; + if (eqSubVar2 != subAst2) { litems4.push_back(ctx.mk_eq_atom(subAst2, eqSubVar2)); } @@ -5398,20 +5385,18 @@ namespace smt { // * key1.second = key2.second // check eqc(key1.first) and eqc(key2.first) // ----------------------------------------------------------- - expr_ref_vector::iterator eqItorStr1 = str1Eqc.begin(); - for (; eqItorStr1 != str1Eqc.end(); eqItorStr1++) { - expr_ref_vector::iterator eqItorStr2 = str2Eqc.begin(); - for (; eqItorStr2 != str2Eqc.end(); eqItorStr2++) { + for (auto eqStrVar1 : str1Eqc) { + for (auto eqStrVar2 : str2Eqc) { { expr_ref_vector litems3(m); if (n1 != n2) { litems3.push_back(ctx.mk_eq_atom(n1, n2)); } - expr * eqStrVar1 = *eqItorStr1; + if (eqStrVar1 != str1) { litems3.push_back(ctx.mk_eq_atom(str1, eqStrVar1)); } - expr * eqStrVar2 = *eqItorStr2; + if (eqStrVar2 != str2) { litems3.push_back(ctx.mk_eq_atom(str2, eqStrVar2)); } @@ -5434,11 +5419,9 @@ namespace smt { if (n1 != n2) { litems4.push_back(ctx.mk_eq_atom(n1, n2)); } - expr * eqStrVar1 = *eqItorStr1; if (eqStrVar1 != str1) { litems4.push_back(ctx.mk_eq_atom(str1, eqStrVar1)); } - expr *eqStrVar2 = *eqItorStr2; if (eqStrVar2 != str2) { litems4.push_back(ctx.mk_eq_atom(str2, eqStrVar2)); } @@ -5484,8 +5467,7 @@ namespace smt { expr * constStrAst = (constStrAst_1 != nullptr) ? constStrAst_1 : constStrAst_2; TRACE("str", tout << "eqc of n1 is {"; - for (expr_ref_vector::iterator it = willEqClass.begin(); it != willEqClass.end(); ++it) { - expr * el = *it; + for (expr * el : willEqClass) { tout << " " << mk_pp(el, m); } tout << std::endl; @@ -5498,12 +5480,11 @@ namespace smt { // step 1: we may have constant values for Contains checks now if (constStrAst != nullptr) { - expr_ref_vector::iterator itAst = willEqClass.begin(); - for (; itAst != willEqClass.end(); itAst++) { - if (*itAst == constStrAst) { + for (auto a : willEqClass) { + if (a == constStrAst) { continue; } - check_contain_by_eqc_val(*itAst, constStrAst); + check_contain_by_eqc_val(a, constStrAst); } } else { // no concrete value to be put in eqc, solely based on context @@ -5515,9 +5496,8 @@ namespace smt { // * "EQC(M) U EQC(concat(..., "jio", ...))" as substr and // * If strAst registered has an eqc constant in the context // ------------------------------------------------------------- - expr_ref_vector::iterator itAst = willEqClass.begin(); - for (; itAst != willEqClass.end(); ++itAst) { - check_contain_by_substr(*itAst, willEqClass); + for (auto a : willEqClass) { + check_contain_by_substr(a, willEqClass); } } @@ -5534,12 +5514,8 @@ namespace smt { // (9) containPairBoolMap[] /\ m = n ==> (b1 -> b2) // ------------------------------------------ - expr_ref_vector::iterator varItor1 = willEqClass.begin(); - for (; varItor1 != willEqClass.end(); ++varItor1) { - expr * varAst1 = *varItor1; - expr_ref_vector::iterator varItor2 = varItor1; - for (; varItor2 != willEqClass.end(); ++varItor2) { - expr * varAst2 = *varItor2; + for (auto varAst1 : willEqClass) { + for (auto varAst2 : willEqClass) { check_contain_by_eq_nodes(varAst1, varAst2); } } @@ -7947,11 +7923,12 @@ namespace smt { // Step 1: get variables / concat AST appearing in the context // the thing we iterate over should just be variable_set - internal_variable_set // so we avoid computing the set difference (but this might be slower) - for(obj_hashtable::iterator it = variable_set.begin(); it != variable_set.end(); ++it) { - expr* var = *it; + for (expr* var : variable_set) { + //for(obj_hashtable::iterator it = variable_set.begin(); it != variable_set.end(); ++it) { + //expr* var = *it; if (internal_variable_set.find(var) == internal_variable_set.end()) { TRACE("str", tout << "new variable: " << mk_pp(var, m) << std::endl;); - strVarMap[*it] = 1; + strVarMap[var] = 1; } } classify_ast_by_type_in_positive_context(strVarMap, concatMap, unrollMap); From 64954cc5510619d1c114e728e5b2746b1be7f73b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Mar 2018 09:07:58 -0700 Subject: [PATCH 0638/1283] fix pbge and reduce_tr Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb_rewriter.cpp | 5 ++--- src/sat/sat_big.cpp | 29 +++++++++++++++++++++++-- src/sat/sat_big.h | 6 ++++++ src/sat/sat_elim_eqs.cpp | 36 +++++++++++++++++++++++--------- src/sat/sat_elim_eqs.h | 6 ++++++ src/sat/sat_scc.cpp | 2 +- src/sat/sat_solver.cpp | 21 ++++++++++++------- src/sat/sat_solver.h | 1 + 8 files changed, 83 insertions(+), 23 deletions(-) diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index f549b944b..cb42052b9 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -296,8 +296,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons slack -= c; k -= c; } - else if (c >= k) { - slack -= c; + else if (c >= k && k.is_pos()) { disj.push_back(m_args[i]); } else { @@ -309,7 +308,7 @@ br_status pb_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons m_args.shrink(j); m_coeffs.shrink(j); sz = j; - if (k.is_pos() && sz > 0 && slack >= k) { + if (sz > 0) { disj.push_back(m_util.mk_ge(sz, m_coeffs.c_ptr(), m_args.c_ptr(), k)); } if (!disj.empty()) { diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 0acc5e7cb..3443625cf 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -165,9 +165,11 @@ namespace sat { } unsigned big::reduce_tr(solver& s) { + unsigned num_lits = s.num_vars() * 2; unsigned idx = 0; unsigned elim = 0; + m_del_bin.reset(); for (watch_list & wlist : s.m_watches) { if (s.inconsistent()) break; literal u = to_literal(idx++); @@ -178,8 +180,9 @@ namespace sat { watched& w = *it; if (learned() ? w.is_binary_learned_clause() : w.is_binary_clause()) { literal v = w.get_literal(); - if (reaches(u, v) && u != get_parent(v)) { + if (u != get_parent(v) && safe_reach(u, v)) { ++elim; + m_del_bin.push_back(std::make_pair(~u, v)); if (find_binary_watch(wlist, ~v)) { IF_VERBOSE(10, verbose_stream() << "binary: " << ~u << "\n"); s.assign(~u, justification()); @@ -193,11 +196,33 @@ namespace sat { itprev++; } wlist.set_end(itprev); - } + } s.propagate(false); return elim; } + bool big::safe_reach(literal u, literal v) { + if (!reaches(u, v)) return false; + while (u != v) { + literal w = next(u, v); + if (m_del_bin.contains(std::make_pair(~u, w)) || + m_del_bin.contains(std::make_pair(~w, u))) { + return false; + } + u = w; + } + return true; + } + + literal big::next(literal u, literal v) const { + SASSERT(reaches(u, v)); + for (literal w : m_dag[u.index()]) { + if (reaches(u, w) && (w == v || reaches(w, v))) return w; + } + UNREACHABLE(); + return null_literal; + } + void big::display(std::ostream& out) const { unsigned idx = 0; for (auto& next : m_dag) { diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index cb3466d26..c9d47f82c 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -36,9 +36,15 @@ namespace sat { bool m_learned; bool m_binary; // is the BIG produced from binary clauses or hyper-binary resolution? + svector> m_del_bin; + + void init_dfs_num(); struct pframe; + bool safe_reach(literal u, literal v); + literal next(literal u, literal v) const; + public: big(random_gen& rand); diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 54a5d54ba..11c1d4780 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -33,17 +33,18 @@ namespace sat { return roots[l.var()]; } - void elim_eqs::cleanup_bin_watches(literal_vector const & roots) { + void elim_eqs::cleanup_bin_watches(literal_vector const & roots) { unsigned l_idx = 0; + m_new_bin.reset(); for (watch_list & wlist : m_solver.m_watches) { literal l1 = ~to_literal(l_idx++); literal r1 = norm(roots, l1); - watch_list::iterator it2 = wlist.begin(); - watch_list::iterator itprev = it2; - watch_list::iterator end2 = wlist.end(); - for (; it2 != end2; ++it2) { - if (it2->is_binary_clause()) { - literal l2 = it2->get_literal(); + watch_list::iterator it = wlist.begin(); + watch_list::iterator itprev = it; + watch_list::iterator end = wlist.end(); + for (; it != end; ++it) { + if (it->is_binary_clause()) { + literal l2 = it->get_literal(); literal r2 = norm(roots, l2); if (r1 == r2) { m_solver.assign(r1, justification()); @@ -56,18 +57,33 @@ namespace sat { // consume tautology continue; } +#if 0 if (l1 != r1) { // add half r1 => r2, the other half ~r2 => ~r1 is added when traversing l2 - m_solver.m_watches[(~r1).index()].push_back(watched(r2, it2->is_learned())); + m_solver.m_watches[(~r1).index()].push_back(watched(r2, it->is_learned())); continue; } - it2->set_literal(r2); // keep it + it->set_literal(r2); // keep it. +#else + if (l1 != r1 || l2 != r2) { + if (r1.index() < r2.index()) { + m_new_bin.push_back(bin(r1, r2, it->is_learned())); + } + continue; + } + // keep it +#endif } - *itprev = *it2; + *itprev = *it; itprev++; } wlist.set_end(itprev); } + + for (auto const& b : m_new_bin) { + m_solver.mk_bin_clause(b.l1, b.l2, b.learned); + } + m_new_bin.reset(); } void elim_eqs::cleanup_clauses(literal_vector const & roots, clause_vector & cs) { diff --git a/src/sat/sat_elim_eqs.h b/src/sat/sat_elim_eqs.h index 15c50097d..143fcbb3f 100644 --- a/src/sat/sat_elim_eqs.h +++ b/src/sat/sat_elim_eqs.h @@ -25,6 +25,12 @@ namespace sat { class solver; class elim_eqs { + struct bin { + literal l1, l2; + bool learned; + bin(literal l1, literal l2, bool learned): l1(l1), l2(l2), learned(learned) {} + }; + svector m_new_bin; solver & m_solver; void save_elim(literal_vector const & roots, bool_var_vector const & to_elim); void cleanup_clauses(literal_vector const & roots, clause_vector & cs); diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 7821b32ca..5fed5e0f6 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -222,7 +222,7 @@ namespace sat { } } TRACE("scc", for (unsigned i = 0; i < roots.size(); i++) { tout << i << " -> " << roots[i] << "\n"; } - tout << "to_elim: "; for (unsigned i = 0; i < to_elim.size(); i++) tout << to_elim[i] << " "; tout << "\n";); + tout << "to_elim: "; for (literal l : to_elim) tout << l << " "; tout << "\n";); m_num_elim += to_elim.size(); elim_eqs eliminator(m_solver); eliminator(roots, to_elim); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5c937a5fb..192951cba 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1632,7 +1632,6 @@ namespace sat { IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";); if (!check_clauses(m_model)) { - UNREACHABLE(); throw solver_exception("check model failed"); } @@ -1644,7 +1643,6 @@ namespace sat { if (!check_clauses(m_model)) { IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";); - UNREACHABLE(); throw solver_exception("check model failed"); } @@ -1652,8 +1650,12 @@ namespace sat { if (m_clone) { IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "\"checking model (on original set of clauses)\"\n";); - if (!m_clone->check_model(m_model)) + if (!m_clone->check_model(m_model)) { + //IF_VERBOSE(0, display(verbose_stream())); + //IF_VERBOSE(0, display_watches(verbose_stream())); + //IF_VERBOSE(0, m_mc.display(verbose_stream())); throw solver_exception("check model failed (for cloned solver)"); + } } } @@ -1683,8 +1685,11 @@ namespace sat { if (!w.is_binary_non_learned_clause()) continue; literal l2 = w.get_literal(); + if (l.index() > l2.index()) + continue; if (value_at(l2, m) != l_true) { - IF_VERBOSE(0, verbose_stream() << "failed binary: " << l << " " << l2 << "\n";); + IF_VERBOSE(0, verbose_stream() << "failed binary: " << l << " := " << value_at(l, m) << " " << l2 << " := " << value_at(l2, m) << "\n"); + IF_VERBOSE(0, verbose_stream() << "elim l1: " << was_eliminated(l.var()) << " elim l2: " << was_eliminated(l2) << "\n"); TRACE("sat", m_mc.display(tout << "failed binary: " << l << " " << l2 << "\n");); ok = false; } @@ -3399,14 +3404,16 @@ namespace sat { out.flush(); } + void solver::display_watches(std::ostream & out, literal lit) const { + sat::display_watch_list(out << lit << ": ", m_cls_allocator, get_wlist(lit)) << "\n"; + } void solver::display_watches(std::ostream & out) const { unsigned l_idx = 0; for (watch_list const& wlist : m_watches) { literal l = to_literal(l_idx++); - out << l << ": "; - sat::display_watch_list(out, m_cls_allocator, wlist); - out << "\n"; + if (!wlist.empty()) + sat::display_watch_list(out << l << ": ", m_cls_allocator, wlist) << "\n"; } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 824d728d6..c56c033a0 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -625,6 +625,7 @@ namespace sat { bool check_invariant() const; void display(std::ostream & out) const; void display_watches(std::ostream & out) const; + void display_watches(std::ostream & out, literal lit) const; void display_dimacs(std::ostream & out) const; void display_wcnf(std::ostream & out, unsigned sz, literal const* lits, unsigned const* weights) const; void display_assignment(std::ostream & out) const; From 4375f54c458d5d5996d30a23918e6006667ba2c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Mar 2018 13:31:27 -0700 Subject: [PATCH 0639/1283] adding lns Signed-off-by: Nikolaj Bjorner --- src/opt/CMakeLists.txt | 1 + src/opt/opt_context.cpp | 74 +++++++++++++++++++++----- src/opt/opt_context.h | 18 ++++--- src/opt/opt_lns.cpp | 115 ++++++++++++++++++++++++++++++++++++++++ src/opt/opt_lns.h | 66 +++++++++++++++++++++++ src/opt/opt_params.pyg | 2 +- src/sat/sat_scc.cpp | 2 +- 7 files changed, 257 insertions(+), 21 deletions(-) create mode 100644 src/opt/opt_lns.cpp create mode 100644 src/opt/opt_lns.h diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index 28a14be2e..3f1d8253c 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -5,6 +5,7 @@ z3_add_component(opt mss.cpp opt_cmds.cpp opt_context.cpp + opt_lns.cpp opt_pareto.cpp opt_parse.cpp optsmt.cpp diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8cbcbed5e..1396ae9c4 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -145,9 +145,8 @@ namespace opt { } void context::reset_maxsmts() { - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (auto& kv : m_maxsmts) { + dealloc(kv.m_value); } m_maxsmts.reset(); } @@ -255,6 +254,9 @@ namespace opt { if (m_pareto) { return execute_pareto(); } + if (m_lns) { + return execute_lns(); + } if (m_box_index != UINT_MAX) { return execute_box(); } @@ -271,10 +273,16 @@ namespace opt { #endif solver& s = get_solver(); s.assert_expr(m_hard_constraints); - IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n";); + + opt_params optp(m_params); + symbol pri = optp.priority(); + if (pri == symbol("lns")) { + return execute_lns(); + } + + IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n"); lbool is_sat = s.check_sat(0,0); - TRACE("opt", tout << "initial search result: " << is_sat << "\n"; - s.display(tout);); + TRACE("opt", s.display(tout << "initial search result: " << is_sat << "\n");); if (is_sat != l_false) { s.get_model(m_model); s.get_labels(m_labels); @@ -286,7 +294,7 @@ namespace opt { TRACE("opt", tout << m_hard_constraints << "\n";); return is_sat; } - IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n";); + IF_VERBOSE(1, verbose_stream() << "(optimize:sat)\n"); TRACE("opt", model_smt2_pp(tout, m, *m_model, 0);); m_optsmt.setup(*m_opt_solver.get()); update_lower(); @@ -303,6 +311,9 @@ namespace opt { if (pri == symbol("pareto")) { is_sat = execute_pareto(); } + else if (pri == symbol("lns")) { + is_sat = execute_lns(); + } else if (pri == symbol("box")) { is_sat = execute_box(); } @@ -525,7 +536,12 @@ namespace opt { } void context::yield() { - m_pareto->get_model(m_model, m_labels); + if (m_pareto) { + m_pareto->get_model(m_model, m_labels); + } + else if (m_lns) { + m_lns->get_model(m_model, m_labels); + } update_bound(true); update_bound(false); } @@ -536,7 +552,7 @@ namespace opt { } lbool is_sat = (*(m_pareto.get()))(); if (is_sat != l_true) { - set_pareto(0); + set_pareto(nullptr); } if (is_sat == l_true) { yield(); @@ -544,6 +560,20 @@ namespace opt { return is_sat; } + lbool context::execute_lns() { + if (!m_lns) { + m_lns = alloc(lns, *this, m_solver.get()); + } + lbool is_sat = (*(m_lns.get()))(); + if (is_sat != l_true) { + m_lns = nullptr; + } + if (is_sat == l_true) { + yield(); + } + return l_undef; + } + std::string context::reason_unknown() const { if (m.canceled()) { return Z3_CANCELED_MSG; @@ -990,6 +1020,24 @@ namespace opt { } } + /** + \brief retrieve literals used by the neighborhood search feature. + */ + + void context::get_lns_literals(expr_ref_vector& lits) { + for (objective & obj : m_objectives) { + switch(obj.m_type) { + case O_MAXSMT: + for (expr* f : obj.m_terms) { + lits.push_back(f); + } + break; + default: + break; + } + } + } + bool context::verify_model(unsigned index, model* md, rational const& _v) { rational r; app_ref term = m_objectives[index].m_term; @@ -1352,7 +1400,8 @@ namespace opt { } void context::clear_state() { - set_pareto(0); + m_pareto = nullptr; + m_lns = nullptr; m_box_index = UINT_MAX; m_model.reset(); } @@ -1388,9 +1437,8 @@ namespace opt { m_solver->updt_params(m_params); } m_optsmt.updt_params(m_params); - map_t::iterator it = m_maxsmts.begin(), end = m_maxsmts.end(); - for (; it != end; ++it) { - it->m_value->updt_params(m_params); + for (auto & kv : m_maxsmts) { + kv.m_value->updt_params(m_params); } opt_params _p(p); m_enable_sat = _p.enable_sat(); diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index e4d1f8e2d..9f55d5ca1 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -19,16 +19,18 @@ Notes: #define OPT_CONTEXT_H_ #include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "ast/bv_decl_plugin.h" +#include "tactic/model_converter.h" +#include "tactic/tactic.h" +#include "qe/qsat.h" #include "opt/opt_solver.h" #include "opt/opt_pareto.h" #include "opt/optsmt.h" +#include "opt/opt_lns.h" #include "opt/maxsmt.h" -#include "tactic/model_converter.h" -#include "tactic/tactic.h" -#include "ast/arith_decl_plugin.h" -#include "ast/bv_decl_plugin.h" #include "cmd_context/cmd_context.h" -#include "qe/qsat.h" + namespace opt { @@ -145,6 +147,7 @@ namespace opt { ref m_solver; ref m_sat_solver; scoped_ptr m_pareto; + scoped_ptr m_lns; scoped_ptr m_qmax; sref_vector m_box_models; unsigned m_box_index; @@ -231,6 +234,8 @@ namespace opt { virtual bool verify_model(unsigned id, model* mdl, rational const& v); + void get_lns_literals(expr_ref_vector& lits); + private: lbool execute(objective const& obj, bool committed, bool scoped); lbool execute_min_max(unsigned index, bool committed, bool scoped, bool is_max); @@ -238,6 +243,7 @@ namespace opt { lbool execute_lex(); lbool execute_box(); lbool execute_pareto(); + lbool execute_lns(); lbool adjust_unknown(lbool r); bool scoped_lex(); expr_ref to_expr(inf_eps const& n); @@ -282,7 +288,7 @@ namespace opt { void setup_arith_solver(); void add_maxsmt(symbol const& id, unsigned index); void set_simplify(tactic *simplify); - void set_pareto(pareto_base* p); + void set_pareto(pareto_base* p); void clear_state(); bool is_numeral(expr* e, rational& n) const; diff --git a/src/opt/opt_lns.cpp b/src/opt/opt_lns.cpp new file mode 100644 index 000000000..d8692ab59 --- /dev/null +++ b/src/opt/opt_lns.cpp @@ -0,0 +1,115 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + opt_lns.cpp + +Abstract: + + Large neighborhood search default implementation + based on phase saving and assumptions + +Author: + + Nikolaj Bjorner (nbjorner) 2018-3-13 + +Notes: + + +--*/ + +#include "opt/opt_lns.h" +#include "opt/opt_context.h" + +namespace opt { + + lns::lns(context& ctx, solver* s): + m(ctx.get_manager()), + m_ctx(ctx), + m_solver(s), + m_models_trail(m) + {} + + lns::~lns() {} + + void lns::display(std::ostream & out) const { + for (auto const& q : m_queue) { + out << q.m_index << ": " << q.m_assignment << "\n"; + } + } + + lbool lns::operator()() { + + if (m_queue.empty()) { + expr_ref_vector lits(m); + m_ctx.get_lns_literals(lits); + m_queue.push_back(queue_elem(lits)); + m_qhead = 0; + } + + params_ref p; + p.set_uint("sat.inprocess.max", 3); + p.set_uint("smt.max_conflicts", 10000); + m_solver->updt_params(p); + + while (m_qhead < m_queue.size()) { + unsigned index = m_queue[m_qhead].m_index; + if (index > m_queue[m_qhead].m_assignment.size()) { + ++m_qhead; + continue; + } + IF_VERBOSE(2, verbose_stream() << "(opt.lns :queue " << m_qhead << " :index " << index << ")\n"); + + // recalibrate state to an initial satisfying assignment + lbool is_sat = m_solver->check_sat(m_queue[m_qhead].m_assignment); + IF_VERBOSE(2, verbose_stream() << "(opt.lns :calibrate-status " << is_sat << ")\n"); + + expr_ref lit(m_queue[m_qhead].m_assignment[index].get(), m); + lit = mk_not(m, lit); + expr* lits[1] = { lit }; + ++m_queue[m_qhead].m_index; + if (!m.limit().inc()) { + return l_undef; + } + + // Update configuration for local search: + // p.set_uint("sat.local_search_threads", 2); + // p.set_uint("sat.unit_walk_threads", 1); + + is_sat = m_solver->check_sat(1, lits); + IF_VERBOSE(2, verbose_stream() << "(opt.lns :status " << is_sat << ")\n"); + if (is_sat == l_true && add_assignment()) { + return l_true; + } + } + return l_false; + } + + bool lns::add_assignment() { + model_ref mdl; + m_solver->get_model(mdl); + m_ctx.fix_model(mdl); + expr_ref tmp(m); + expr_ref_vector fmls(m); + for (expr* f : m_queue[0].m_assignment) { + mdl->eval(f, tmp); + if (m.is_false(tmp)) { + fmls.push_back(mk_not(m, tmp)); + } + else { + fmls.push_back(tmp); + } + } + tmp = mk_and(fmls); + if (m_models.contains(tmp)) { + return false; + } + else { + m_models.insert(tmp); + m_models_trail.push_back(tmp); + return true; + } + } +} + diff --git a/src/opt/opt_lns.h b/src/opt/opt_lns.h new file mode 100644 index 000000000..8033a8ea8 --- /dev/null +++ b/src/opt/opt_lns.h @@ -0,0 +1,66 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + opt_lns.h + +Abstract: + + Large neighborhood seearch + +Author: + + Nikolaj Bjorner (nbjorner) 2018-3-13 + +Notes: + + +--*/ +#ifndef OPT_LNS_H_ +#define OPT_LNS_H_ + +#include "solver/solver.h" +#include "model/model.h" + +namespace opt { + + class context; + + class lns { + struct queue_elem { + expr_ref_vector m_assignment; + unsigned m_index; + queue_elem(expr_ref_vector& assign): + m_assignment(assign), + m_index(0) + {} + }; + ast_manager& m; + context& m_ctx; + ref m_solver; + model_ref m_model; + svector m_labels; + vector m_queue; + unsigned m_qhead; + expr_ref_vector m_models_trail; + obj_hashtable m_models; + + bool add_assignment(); + public: + lns(context& ctx, solver* s); + + ~lns(); + + void display(std::ostream & out) const; + + lbool operator()(); + + void get_model(model_ref& mdl, svector& labels) { + mdl = m_model; + labels = m_labels; + } + }; +} + +#endif diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index cfcc5e47e..21845d38a 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,7 +3,7 @@ def_module_params('opt', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), - ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), + ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box', or 'lns' (large neighborhood search)"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 5fed5e0f6..8a2029df2 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -222,7 +222,7 @@ namespace sat { } } TRACE("scc", for (unsigned i = 0; i < roots.size(); i++) { tout << i << " -> " << roots[i] << "\n"; } - tout << "to_elim: "; for (literal l : to_elim) tout << l << " "; tout << "\n";); + tout << "to_elim: "; for (unsigned v : to_elim) tout << v << " "; tout << "\n";); m_num_elim += to_elim.size(); elim_eqs eliminator(m_solver); eliminator(roots, to_elim); From 5f7bd993de4b83d95e22921d424a7902d0480f83 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Tue, 13 Mar 2018 21:37:22 +0100 Subject: [PATCH 0640/1283] Add support for NetBSD Originally from David Holland . --- CMakeLists.txt | 3 +++ scripts/mk_util.py | 17 ++++++++++++++++- src/util/scoped_timer.cpp | 18 +++++++++--------- src/util/stopwatch.h | 5 +++++ 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d8c15493..c11c272be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -240,6 +240,9 @@ elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") message(STATUS "Platform: FreeBSD") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_FREEBSD_") +elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "NetBSD") + message(STATUS "Platform: NetBSD") + list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_NetBSD_") elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "OpenBSD") message(STATUS "Platform: OpenBSD") list(APPEND Z3_COMPONENT_CXX_DEFINES "-D_OPENBSD_") diff --git a/scripts/mk_util.py b/scripts/mk_util.py index fecc207d8..99de61703 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -69,6 +69,7 @@ IS_WINDOWS=False IS_LINUX=False IS_OSX=False IS_FREEBSD=False +IS_NETBSD=False IS_OPENBSD=False IS_CYGWIN=False IS_CYGWIN_MINGW=False @@ -141,6 +142,9 @@ def is_linux(): def is_freebsd(): return IS_FREEBSD +def is_netbsd(): + return IS_NETBSD + def is_openbsd(): return IS_OPENBSD @@ -604,6 +608,8 @@ elif os.name == 'posix': IS_LINUX=True elif os.uname()[0] == 'FreeBSD': IS_FREEBSD=True + elif os.uname()[0] == 'NetBSD': + IS_NETBSD=True elif os.uname()[0] == 'OpenBSD': IS_OPENBSD=True elif os.uname()[0][:6] == 'CYGWIN': @@ -1245,7 +1251,7 @@ def get_so_ext(): sysname = os.uname()[0] if sysname == 'Darwin': return 'dylib' - elif sysname == 'Linux' or sysname == 'FreeBSD' or sysname == 'OpenBSD': + elif sysname == 'Linux' or sysname == 'FreeBSD' or sysname == 'NetBSD' or sysname == 'OpenBSD': return 'so' elif sysname == 'CYGWIN' or sysname.startswith('MSYS_NT') or sysname.startswith('MINGW'): return 'dll' @@ -1795,6 +1801,8 @@ class JavaDLLComponent(Component): t = t.replace('PLATFORM', 'linux') elif IS_FREEBSD: t = t.replace('PLATFORM', 'freebsd') + elif IS_NETBSD: + t = t.replace('PLATFORM', 'netbsd') elif IS_OPENBSD: t = t.replace('PLATFORM', 'openbsd') elif IS_CYGWIN: @@ -2504,6 +2512,13 @@ def mk_config(): LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS + elif sysname == 'NetBSD': + CXXFLAGS = '%s -D_NETBSD_' % CXXFLAGS + OS_DEFINES = '-D_NETBSD_' + SO_EXT = '.so' + LDFLAGS = '%s -lrt' % LDFLAGS + SLIBFLAGS = '-shared' + SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS elif sysname == 'OpenBSD': CXXFLAGS = '%s -D_OPENBSD_' % CXXFLAGS OS_DEFINES = '-D_OPENBSD_' diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 1ecca8ffe..a2a0cc269 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -33,8 +33,8 @@ Revision History: #include #include #include -#elif defined(_LINUX_) || defined(_FREEBSD_) -// Linux +#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NetBSD_) +// Linux & FreeBSD & NetBSD #include #include #include @@ -66,8 +66,8 @@ struct scoped_timer::imp { pthread_mutex_t m_mutex; pthread_cond_t m_condition_var; struct timespec m_end_time; -#elif defined(_LINUX_) || defined(_FREEBSD_) - // Linux & FreeBSD +#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) + // Linux & FreeBSD & NetBSD pthread_t m_thread_id; pthread_mutex_t m_mutex; pthread_cond_t m_cond; @@ -104,7 +104,7 @@ struct scoped_timer::imp { return st; } -#elif defined(_LINUX_) || defined(_FREEBSD_) +#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) static void* thread_func(void *arg) { scoped_timer::imp *st = static_cast(arg); @@ -175,8 +175,8 @@ struct scoped_timer::imp { if (pthread_create(&m_thread_id, &m_attributes, &thread_func, this) != 0) throw default_exception("failed to start timer thread"); -#elif defined(_LINUX_) || defined(_FREEBSD_) - // Linux & FreeBSD +#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) + // Linux & FreeBSD & NetBSD m_ms = ms; m_initialized = false; m_signal_sent = false; @@ -216,8 +216,8 @@ struct scoped_timer::imp { throw default_exception("failed to destroy pthread condition variable"); if (pthread_attr_destroy(&m_attributes) != 0) throw default_exception("failed to destroy pthread attributes object"); -#elif defined(_LINUX_) || defined(_FREEBSD_) - // Linux & FreeBSD +#elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) + // Linux & FreeBSD & NetBSD bool init = false; // spin until timer thread has been created diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 9ba707af0..83e03a2f7 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -134,6 +134,11 @@ public: #include +#ifndef CLOCK_PROCESS_CPUTIME_ID +/* BSD */ +# define CLOCK_PROCESS_CPUTIME_ID CLOCK_MONOTONIC +#endif + class stopwatch { unsigned long long m_time; // elapsed time in ns bool m_running; From bf8ea92b992b64f0541a64fbeda127549455dfa3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Mar 2018 17:23:58 -0700 Subject: [PATCH 0641/1283] fixing nls Signed-off-by: Nikolaj Bjorner --- src/opt/opt_lns.cpp | 59 ++++++++++++++++++++++++++++++--------------- src/opt/opt_lns.h | 18 ++++++++------ 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/opt/opt_lns.cpp b/src/opt/opt_lns.cpp index d8692ab59..1fc6913e4 100644 --- a/src/opt/opt_lns.cpp +++ b/src/opt/opt_lns.cpp @@ -28,7 +28,8 @@ namespace opt { m(ctx.get_manager()), m_ctx(ctx), m_solver(s), - m_models_trail(m) + m_models_trail(m), + m_atoms(m) {} lns::~lns() {} @@ -42,9 +43,19 @@ namespace opt { lbool lns::operator()() { if (m_queue.empty()) { - expr_ref_vector lits(m); + expr_ref_vector lits(m), atoms(m); m_ctx.get_lns_literals(lits); - m_queue.push_back(queue_elem(lits)); + for (expr* l : lits) { + expr* nl = nullptr; + if (m.is_not(l, nl)) { + m_atoms.push_back(nl); + } + else { + atoms.push_back(l); + m_atoms.push_back(l); + } + } + m_queue.push_back(queue_elem(atoms)); m_qhead = 0; } @@ -54,34 +65,47 @@ namespace opt { m_solver->updt_params(p); while (m_qhead < m_queue.size()) { - unsigned index = m_queue[m_qhead].m_index; - if (index > m_queue[m_qhead].m_assignment.size()) { - ++m_qhead; + obj_hashtable atoms; + for (expr* f : m_queue[m_qhead].m_assignment) { + atoms.insert(f); + } + unsigned& index = m_queue[m_qhead].m_index; + expr* lit = nullptr; + for (; index < m_atoms.size() && (lit = m_atoms[index].get(), (atoms.contains(lit) || m_units.contains(lit))); ++index) ; + if (index == m_atoms.size()) { + m_qhead++; continue; } + IF_VERBOSE(2, verbose_stream() << "(opt.lns :queue " << m_qhead << " :index " << index << ")\n"); // recalibrate state to an initial satisfying assignment lbool is_sat = m_solver->check_sat(m_queue[m_qhead].m_assignment); IF_VERBOSE(2, verbose_stream() << "(opt.lns :calibrate-status " << is_sat << ")\n"); - - expr_ref lit(m_queue[m_qhead].m_assignment[index].get(), m); - lit = mk_not(m, lit); - expr* lits[1] = { lit }; - ++m_queue[m_qhead].m_index; if (!m.limit().inc()) { return l_undef; } + + expr* lit = m_atoms[index].get(); + expr_ref_vector lits(m); + lits.push_back(lit); + ++index; // Update configuration for local search: // p.set_uint("sat.local_search_threads", 2); // p.set_uint("sat.unit_walk_threads", 1); - is_sat = m_solver->check_sat(1, lits); - IF_VERBOSE(2, verbose_stream() << "(opt.lns :status " << is_sat << ")\n"); + is_sat = m_solver->check_sat(lits); + IF_VERBOSE(2, verbose_stream() << "(opt.lns :lookahead-status " << is_sat << " " << lit << ")\n"); if (is_sat == l_true && add_assignment()) { return l_true; } + if (is_sat == l_false) { + m_units.insert(lit); + } + if (!m.limit().inc()) { + return l_undef; + } } return l_false; } @@ -92,13 +116,10 @@ namespace opt { m_ctx.fix_model(mdl); expr_ref tmp(m); expr_ref_vector fmls(m); - for (expr* f : m_queue[0].m_assignment) { + for (expr* f : m_atoms) { mdl->eval(f, tmp); - if (m.is_false(tmp)) { - fmls.push_back(mk_not(m, tmp)); - } - else { - fmls.push_back(tmp); + if (m.is_true(tmp)) { + fmls.push_back(f); } } tmp = mk_and(fmls); diff --git a/src/opt/opt_lns.h b/src/opt/opt_lns.h index 8033a8ea8..29c2adc90 100644 --- a/src/opt/opt_lns.h +++ b/src/opt/opt_lns.h @@ -36,15 +36,17 @@ namespace opt { m_index(0) {} }; - ast_manager& m; - context& m_ctx; - ref m_solver; - model_ref m_model; - svector m_labels; - vector m_queue; - unsigned m_qhead; - expr_ref_vector m_models_trail; + ast_manager& m; + context& m_ctx; + ref m_solver; + model_ref m_model; + svector m_labels; + vector m_queue; + unsigned m_qhead; + expr_ref_vector m_models_trail; + expr_ref_vector m_atoms; obj_hashtable m_models; + obj_hashtable m_fixed; bool add_assignment(); public: From 2b2aee3c18bee27bee94908d650596e7e5424b64 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Mar 2018 07:29:26 -0700 Subject: [PATCH 0642/1283] remove unused operators #1530 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 120b0ddfd..5766c79f9 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1402,7 +1402,6 @@ struct let is_rewrite (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_REWRITE) let is_rewrite_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_REWRITE_STAR) let is_pull_quant (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_PULL_QUANT) - let is_pull_quant_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_PULL_QUANT_STAR) let is_push_quant (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_PUSH_QUANT) let is_elim_unused_vars (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_ELIM_UNUSED_VARS) let is_der (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_DER) @@ -1419,8 +1418,6 @@ struct let is_iff_oeq (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_IFF_OEQ) let is_nnf_pos (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_NNF_POS) let is_nnf_neg (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_NNF_NEG) - let is_nnf_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_NNF_STAR) - let is_cnf_star (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_CNF_STAR) let is_skolemize (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_SKOLEMIZE) let is_modus_ponens_oeq (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_MODUS_PONENS_OEQ) let is_theory_lemma (x:expr) = (AST.is_app x) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) = OP_PR_TH_LEMMA) From 5e2723a16ebf1603dc5a048ef98528e40d75d682 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Mar 2018 09:04:08 -0700 Subject: [PATCH 0643/1283] java Signed-off-by: Nikolaj Bjorner --- src/api/java/Context.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index ba96209b3..8720fd975 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2543,14 +2543,15 @@ public class Context implements AutoCloseable { /** * Parse the given string using the SMT-LIB2 parser. * - * @return A conjunction of assertions in the scope (up to push/pop) at the - * end of the string. + * @return A conjunction of assertions. + * + * If the string contains push/pop commands, the + * set of assertions returned are the ones in the + * last scope level. **/ public BoolExpr parseSMTLIB2String(String str, Symbol[] sortNames, - Sort[] sorts, Symbol[] declNames, FuncDecl[] decls) - + Sort[] sorts, Symbol[] declNames, FuncDecl[] decls) { - int csn = Symbol.arrayLength(sortNames); int cs = Sort.arrayLength(sorts); int cdn = Symbol.arrayLength(declNames); From 46048d51502c749e8a230e9a43e1afdeb439d2dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Mar 2018 12:15:13 -0700 Subject: [PATCH 0644/1283] change lemma display utility to use updated pretty printer Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context_pp.cpp | 52 ++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index f5ba52128..e883e0a09 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -19,7 +19,7 @@ Revision History: #include "smt/smt_context.h" #include "ast/ast_ll_pp.h" #include "ast/ast_pp.h" -#include "ast/ast_smt_pp.h" +#include "ast/ast_pp_util.h" #include "util/stats.h" namespace smt { @@ -413,19 +413,23 @@ namespace smt { } void context::display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, literal consequent, symbol const& logic) const { - ast_smt_pp pp(m_manager); - pp.set_benchmark_name("lemma"); - pp.set_status("unsat"); - pp.set_logic(logic); + ast_pp_util visitor(m_manager); + expr_ref_vector fmls(m_manager); + visitor.collect(fmls); + expr_ref n(m_manager); for (unsigned i = 0; i < num_antecedents; i++) { literal l = antecedents[i]; - expr_ref n(m_manager); literal2expr(l, n); - pp.add_assumption(n); + fmls.push_back(n); } - expr_ref n(m_manager); - literal2expr(~consequent, n); - pp.display_smt2(out, n); + if (consequent != false_literal) { + literal2expr(~consequent, n); + fmls.push_back(n); + } + if (logic != symbol::null) out << "(set-logic " << logic << ")\n"; + visitor.collect(fmls); + visitor.display_decls(out); + visitor.display_asserts(out, fmls, true); } static unsigned g_lemma_id = 0; @@ -448,25 +452,29 @@ namespace smt { void context::display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, unsigned num_eq_antecedents, enode_pair const * eq_antecedents, literal consequent, symbol const& logic) const { - ast_smt_pp pp(m_manager); - pp.set_benchmark_name("lemma"); - pp.set_status("unsat"); - pp.set_logic(logic); + ast_pp_util visitor(m_manager); + expr_ref_vector fmls(m_manager); + visitor.collect(fmls); + expr_ref n(m_manager); for (unsigned i = 0; i < num_antecedents; i++) { literal l = antecedents[i]; - expr_ref n(m_manager); literal2expr(l, n); - pp.add_assumption(n); + fmls.push_back(n); } for (unsigned i = 0; i < num_eq_antecedents; i++) { enode_pair const & p = eq_antecedents[i]; - expr_ref eq(m_manager); - eq = m_manager.mk_eq(p.first->get_owner(), p.second->get_owner()); - pp.add_assumption(eq); + n = m_manager.mk_eq(p.first->get_owner(), p.second->get_owner()); + fmls.push_back(n); } - expr_ref n(m_manager); - literal2expr(~consequent, n); - pp.display_smt2(out, n); + if (consequent != false_literal) { + literal2expr(~consequent, n); + fmls.push_back(n); + } + + if (logic != symbol::null) out << "(set-logic " << logic << ")\n"; + visitor.collect(fmls); + visitor.display_decls(out); + visitor.display_asserts(out, fmls, true); } void context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, From b1f05d8271e1773bb560c58daa2bf3180dacb419 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Mar 2018 18:14:29 -0700 Subject: [PATCH 0645/1283] fix #1539 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.mli | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 20a1e9c10..14d2ceac4 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2458,13 +2458,6 @@ sig A proof for (iff (f (forall (x) q(x)) r) (forall (x) (f (q x) r))). This proof object has no antecedents. *) val is_pull_quant : Expr.expr -> bool - (** Indicates whether the term is a proof for pulling quantifiers out. - - A proof for (iff P Q) where Q is in prenex normal form. - This proof object is only used if the parameter PROOF_MODE is 1. - This proof object has no antecedents *) - val is_pull_quant_star : Expr.expr -> bool - (** Indicates whether the term is a proof for pushing quantifiers in. A proof for: @@ -2658,22 +2651,6 @@ sig (and (or r_1 r_2) (or r_1' r_2'))) *) val is_nnf_neg : Expr.expr -> bool - (** Indicates whether the term is a proof for (~ P Q) here Q is in negation normal form. - - A proof for (~ P Q) where Q is in negation normal form. - - This proof object is only used if the parameter PROOF_MODE is 1. - - This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. *) - val is_nnf_star : Expr.expr -> bool - - (** Indicates whether the term is a proof for (~ P Q) where Q is in conjunctive normal form. - - A proof for (~ P Q) where Q is in conjunctive normal form. - This proof object is only used if the parameter PROOF_MODE is 1. - This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. *) - val is_cnf_star : Expr.expr -> bool - (** Indicates whether the term is a proof for a Skolemization step Proof for: From 59b142f8039763b4e1caa33258a86f767d94221a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Mar 2018 06:48:26 -0700 Subject: [PATCH 0646/1283] fixing local search Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 +++ src/opt/opt_lns.cpp | 39 ++++++++++++++++----------- src/opt/opt_lns.h | 2 +- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 1 + src/sat/sat_local_search.cpp | 52 +++++++++++++++++++++++++----------- src/sat/sat_local_search.h | 31 +++++++++++---------- src/sat/sat_params.pyg | 1 + src/sat/sat_solver.cpp | 19 +++++++------ src/sat/sat_unit_walk.cpp | 14 +++++++--- src/util/params.cpp | 1 - 11 files changed, 107 insertions(+), 57 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 1396ae9c4..33aaa0b27 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1436,6 +1436,9 @@ namespace opt { if (m_solver) { m_solver->updt_params(m_params); } + if (m_sat_solver) { + m_sat_solver->updt_params(m_params); + } m_optsmt.updt_params(m_params); for (auto & kv : m_maxsmts) { kv.m_value->updt_params(m_params); diff --git a/src/opt/opt_lns.cpp b/src/opt/opt_lns.cpp index 1fc6913e4..d5038dc29 100644 --- a/src/opt/opt_lns.cpp +++ b/src/opt/opt_lns.cpp @@ -14,11 +14,9 @@ Author: Nikolaj Bjorner (nbjorner) 2018-3-13 -Notes: - - --*/ +#include "ast/ast_pp.h" #include "opt/opt_lns.h" #include "opt/opt_context.h" @@ -36,12 +34,12 @@ namespace opt { void lns::display(std::ostream & out) const { for (auto const& q : m_queue) { - out << q.m_index << ": " << q.m_assignment << "\n"; + expr_ref tmp(mk_and(q.m_assignment)); + out << q.m_index << ": " << tmp << "\n"; } } lbool lns::operator()() { - if (m_queue.empty()) { expr_ref_vector lits(m), atoms(m); m_ctx.get_lns_literals(lits); @@ -60,8 +58,7 @@ namespace opt { } params_ref p; - p.set_uint("sat.inprocess.max", 3); - p.set_uint("smt.max_conflicts", 10000); + p.set_uint("inprocess.max", 3ul); m_solver->updt_params(p); while (m_qhead < m_queue.size()) { @@ -71,13 +68,20 @@ namespace opt { } unsigned& index = m_queue[m_qhead].m_index; expr* lit = nullptr; - for (; index < m_atoms.size() && (lit = m_atoms[index].get(), (atoms.contains(lit) || m_units.contains(lit))); ++index) ; + for (; index < m_atoms.size(); ++index) { + lit = m_atoms[index].get(); + if (!atoms.contains(lit) && !m_failed.contains(lit)) break; + } if (index == m_atoms.size()) { m_qhead++; continue; } IF_VERBOSE(2, verbose_stream() << "(opt.lns :queue " << m_qhead << " :index " << index << ")\n"); + + p.set_uint("local_search_threads", 0); + p.set_uint("unit_walk_threads", 0); + m_solver->updt_params(p); // recalibrate state to an initial satisfying assignment lbool is_sat = m_solver->check_sat(m_queue[m_qhead].m_assignment); @@ -86,22 +90,27 @@ namespace opt { return l_undef; } - expr* lit = m_atoms[index].get(); expr_ref_vector lits(m); lits.push_back(lit); ++index; - // Update configuration for local search: - // p.set_uint("sat.local_search_threads", 2); - // p.set_uint("sat.unit_walk_threads", 1); - + // freeze phase in both SAT solver and local search to current assignment + p.set_uint("inprocess.max", 3); + p.set_bool("phase.sticky", true); + p.set_uint("local_search_threads", 1); + p.set_uint("max_conflicts", 100000); + p.set_uint("unit_walk_threads", 1); + m_solver->updt_params(p); + is_sat = m_solver->check_sat(lits); - IF_VERBOSE(2, verbose_stream() << "(opt.lns :lookahead-status " << is_sat << " " << lit << ")\n"); + IF_VERBOSE(2, verbose_stream() << "(opt.lns :lookahead-status " << is_sat << " " << mk_pp(lit, m) << ")\n"); if (is_sat == l_true && add_assignment()) { return l_true; } if (is_sat == l_false) { - m_units.insert(lit); + m_failed.insert(lit); + expr_ref nlit(m.mk_not(lit), m); + m_solver->assert_expr(nlit); } if (!m.limit().inc()) { return l_undef; diff --git a/src/opt/opt_lns.h b/src/opt/opt_lns.h index 29c2adc90..827df3081 100644 --- a/src/opt/opt_lns.h +++ b/src/opt/opt_lns.h @@ -46,7 +46,7 @@ namespace opt { expr_ref_vector m_models_trail; expr_ref_vector m_atoms; obj_hashtable m_models; - obj_hashtable m_fixed; + obj_hashtable m_failed; bool add_assignment(); public: diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index c37312ae7..2439be36f 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -55,6 +55,7 @@ namespace sat { m_phase_caching_on = p.phase_caching_on(); m_phase_caching_off = p.phase_caching_off(); + m_phase_sticky = p.phase_sticky(); m_restart_initial = p.restart_initial(); m_restart_factor = p.restart_factor(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index b42761f4b..c70d52a90 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -83,6 +83,7 @@ namespace sat { phase_selection m_phase; unsigned m_phase_caching_on; unsigned m_phase_caching_off; + bool m_phase_sticky; restart_strategy m_restart; unsigned m_restart_initial; double m_restart_factor; // for geometric case diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 1b5f09e4d..5c2425578 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -34,8 +34,13 @@ namespace sat { // add sentinel variable. m_vars.push_back(var_info()); - for (unsigned v = 0; v < num_vars(); ++v) { - m_vars[v].m_value = (0 == (m_rand() % 2)); + if (m_config.phase_sticky()) { + for (var_info& vi : m_vars) + vi.m_value = vi.m_bias < 100; + } + else { + for (var_info& vi : m_vars) + vi.m_value = (0 == (m_rand() % 2)); } m_best_solution.resize(num_vars() + 1, false); @@ -70,13 +75,14 @@ namespace sat { } void local_search::init_cur_solution() { - for (unsigned v = 0; v < num_vars(); ++v) { + IF_VERBOSE(1, verbose_stream() << "(sat.local_search init-cur-solution)\n"); + for (var_info& vi : m_vars) { // use bias with a small probability - if (m_rand() % 10 < 5) { - m_vars[v].m_value = ((unsigned)(m_rand() % 100) < m_vars[v].m_bias); + if (m_rand() % 10 < 5 || m_config.phase_sticky()) { + vi.m_value = ((unsigned)(m_rand() % 100) < vi.m_bias); } else { - m_vars[v].m_value = (m_rand() % 2) == 0; + vi.m_value = (m_rand() % 2) == 0; } } } @@ -189,8 +195,15 @@ namespace sat { init_slack(); init_scores(); init_goodvars(); + set_best_unsat(); + } + void local_search::set_best_unsat() { m_best_unsat = m_unsat_stack.size(); + if (m_best_unsat == 1) { + constraint const& c = m_constraints[m_unsat_stack[0]]; + IF_VERBOSE(2, display(verbose_stream() << "single unsat:", c)); + } } void local_search::calculate_and_update_ob() { @@ -275,7 +288,9 @@ namespace sat { m_constraints.back().push(t); } if (sz == 1 && k == 0) { - m_vars[c[0].var()].m_bias = c[0].sign() ? 0 : 100; + literal lit = c[0]; + m_vars[lit.var()].m_bias = lit.sign() ? 100 : 0; + m_vars[lit.var()].m_value = lit.sign(); } } @@ -289,8 +304,10 @@ namespace sat { m_vars[t.var()].m_watch[is_pos(t)].push_back(pbcoeff(id, coeffs[i])); m_constraints.back().push(t); } - if (sz == 1 && k == 0) { - m_vars[c[0].var()].m_bias = c[0].sign() ? 0 : 100; + if (sz == 1 && k == 0) { + literal lit = c[0]; + m_vars[lit.var()].m_bias = lit.sign() ? 100 : 0; + m_vars[lit.var()].m_value = lit.sign(); } } @@ -304,6 +321,14 @@ namespace sat { m_constraints.reset(); m_vars.reserve(s.num_vars()); + if (m_config.phase_sticky()) { + unsigned v = 0; + for (var_info& vi : m_vars) { + if (vi.m_bias != 0 && vi.m_bias != 100) + vi.m_bias = s.m_phase[v] == POS_PHASE ? 100 : 0; + ++v; + } + } // copy units unsigned trail_sz = s.init_trail_size(); @@ -462,7 +487,7 @@ namespace sat { for (step = 0; step < m_max_steps && !m_unsat_stack.empty(); ++step) { pick_flip_walksat(); if (m_unsat_stack.size() < m_best_unsat) { - m_best_unsat = m_unsat_stack.size(); + set_best_unsat(); m_last_best_unsat_rate = m_best_unsat_rate; m_best_unsat_rate = (double)m_unsat_stack.size() / num_constraints(); } @@ -497,7 +522,7 @@ namespace sat { } } if (m_unsat_stack.size() < m_best_unsat) { - m_best_unsat = m_unsat_stack.size(); + set_best_unsat(); } flipvar = pick_var_gsat(); flip_gsat(flipvar); @@ -876,10 +901,7 @@ namespace sat { } void local_search::set_parameters() { - SASSERT(s_id == 0); - m_rand.set_seed(m_config.seed()); - //srand(m_config.seed()); - s_id = m_config.strategy_id(); + m_rand.set_seed(m_config.random_seed()); m_best_known_value = m_config.best_known_value(); switch (m_config.mode()) { diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 475bd5f25..0f9bc95d7 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -29,27 +29,31 @@ namespace sat { class parallel; class local_search_config { - unsigned m_seed; - unsigned m_strategy_id; - int m_best_known_value; + unsigned m_random_seed; + int m_best_known_value; local_search_mode m_mode; + bool m_phase_sticky; public: local_search_config() { - m_seed = 0; - m_strategy_id = 0; + m_random_seed = 0; m_best_known_value = INT_MAX; m_mode = local_search_mode::wsat; + m_phase_sticky = false; } - unsigned seed() const { return m_seed; } - unsigned strategy_id() const { return m_strategy_id; } + unsigned random_seed() const { return m_random_seed; } unsigned best_known_value() const { return m_best_known_value; } local_search_mode mode() const { return m_mode; } - - void set_seed(unsigned s) { m_seed = s; } - void set_strategy_id(unsigned i) { m_strategy_id = i; } + bool phase_sticky() const { return m_phase_sticky; } + + void set_random_seed(unsigned s) { m_random_seed = s; } void set_best_known_value(unsigned v) { m_best_known_value = v; } - void set_mode(local_search_mode m) { m_mode = m; } + + void set_config(config const& cfg) { + m_mode = cfg.m_local_search_mode; + m_random_seed = cfg.m_random_seed; + m_phase_sticky = cfg.m_phase_sticky; + } }; @@ -75,6 +79,7 @@ namespace sat { bool m_value; // current solution unsigned m_bias; // bias for current solution in percentage. // if bias is 0, then value is always false, if 100, then always true + // lbool m_unit; // if l_true, then unit atom, if l_false, then unit negative literal bool m_conf_change; // whether its configure changes since its last flip bool m_in_goodvar_stack; int m_score; @@ -135,6 +140,7 @@ namespace sat { inline bool cur_solution(bool_var v) const { return m_vars[v].m_value; } + inline void set_best_unsat(); /* TBD: other scores */ @@ -179,9 +185,6 @@ namespace sat { double m_noise = 9800; // normalized by 10000 double m_noise_delta = 0.05; - // for tuning - int s_id = 0; // strategy id - reslimit m_limit; random_gen m_rand; parallel* m_par; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 7f6d1f718..850a33cef 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -5,6 +5,7 @@ def_module_params('sat', ('phase', SYMBOL, 'caching', 'phase selection strategy: always_false, always_true, caching, random'), ('phase.caching.on', UINT, 400, 'phase caching on period (in number of conflicts)'), ('phase.caching.off', UINT, 100, 'phase caching off period (in number of conflicts)'), + ('phase.sticky', BOOL, False, 'use sticky phase caching for local search'), ('restart', SYMBOL, 'luby', 'restart strategy: luby or geometric'), ('restart.initial', UINT, 100, 'initial restart (number of conflicts)'), ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 192951cba..3dff97875 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1030,8 +1030,7 @@ namespace sat { lbool solver::do_local_search(unsigned num_lits, literal const* lits) { scoped_limits scoped_rl(rlimit()); local_search srch; - srch.config().set_seed(m_config.m_random_seed); - srch.config().set_mode(m_config.m_local_search_mode); + srch.config().set_config(m_config); srch.import(*this, false); scoped_rl.push_child(&srch.rlimit()); lbool r = srch.check(num_lits, lits, 0); @@ -1055,8 +1054,8 @@ namespace sat { int num_threads = num_extra_solvers + 1 + num_local_search + num_unit_walk; for (int i = 0; i < num_local_search; ++i) { local_search* l = alloc(local_search); - l->config().set_seed(m_config.m_random_seed + i); - l->config().set_mode(m_config.m_local_search_mode); + l->config().set_config(m_config); + l->config().set_random_seed(m_config.m_random_seed + i); l->import(*this, false); ls.push_back(l); } @@ -1277,10 +1276,12 @@ namespace sat { phase = l_false; break; case PS_CACHING: - if (m_phase_cache_on && m_phase[next] != PHASE_NOT_AVAILABLE) + if ((m_phase_cache_on || m_config.m_phase_sticky) && m_phase[next] != PHASE_NOT_AVAILABLE) { phase = m_phase[next] == POS_PHASE ? l_true : l_false; - else + } + else { phase = l_false; + } break; case PS_RANDOM: phase = to_lbool((m_rand() % 2) == 0); @@ -1486,7 +1487,7 @@ namespace sat { void solver::init_search() { m_model_is_current = false; m_phase_counter = 0; - m_phase_cache_on = false; + m_phase_cache_on = m_config.m_phase_sticky; m_conflicts_since_restart = 0; m_restart_threshold = m_config.m_restart_initial; m_luby_idx = 1; @@ -1625,8 +1626,10 @@ namespace sat { unsigned num = num_vars(); m_model.resize(num, l_undef); for (bool_var v = 0; v < num; v++) { - if (!was_eliminated(v)) + if (!was_eliminated(v)) { m_model[v] = value(v); + m_phase[v] = (value(v) == l_true) ? POS_PHASE : NEG_PHASE; + } } TRACE("sat_mc_bug", m_mc.display(tout);); diff --git a/src/sat/sat_unit_walk.cpp b/src/sat/sat_unit_walk.cpp index 7d556c740..4a3cda47c 100644 --- a/src/sat/sat_unit_walk.cpp +++ b/src/sat/sat_unit_walk.cpp @@ -43,9 +43,9 @@ namespace sat { m_runs = 0; m_periods = 0; m_max_runs = UINT_MAX; - m_max_periods = 100; // 5000; // UINT_MAX; // TBD configure + m_max_periods = 5000; // UINT_MAX; // TBD configure m_max_conflicts = 100; - m_sticky_phase = true; + m_sticky_phase = s.get_config().m_phase_sticky; m_flips = 0; } @@ -124,7 +124,15 @@ namespace sat { m_max_trail = 0; if (m_sticky_phase) { for (bool_var v : m_freevars) { - m_phase[v] = m_rand(100 * static_cast(m_phase_tf[v].t + m_phase_tf[v].f)) <= 100 * m_phase_tf[v].t; + if (s.m_phase[v] == POS_PHASE) { + m_phase[v] = true; + } + else if (s.m_phase[v] == NEG_PHASE) { + m_phase[v] = false; + } + else { + m_phase[v] = m_rand(100 * static_cast(m_phase_tf[v].t + m_phase_tf[v].f)) <= 100 * m_phase_tf[v].t; + } } } else { diff --git a/src/util/params.cpp b/src/util/params.cpp index 081b75aee..75dd91129 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -323,7 +323,6 @@ class params { typedef std::pair entry; svector m_entries; unsigned m_ref_count; - void del_value(entry & e); void del_values(); From 6bb9a82425e7d2b9a17dfe77a5ae250b11c17ab4 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 15 Mar 2018 13:56:44 -0400 Subject: [PATCH 0647/1283] experimental axiom-persist for regex conflict clauses --- src/smt/theory_str.cpp | 23 ++++++++++++++++++++--- src/smt/theory_str.h | 6 ++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 4ea96bd1f..c9e484b02 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -57,6 +57,8 @@ namespace smt { tmpXorVarCount(0), tmpLenTestVarCount(0), tmpValTestVarCount(0), + m_persisted_axioms(m), + m_persisted_axiom_todo(m), avoidLoopCut(true), loopDetected(false), m_theoryStrOverlapAssumption_term(m), @@ -827,7 +829,8 @@ namespace smt { return !m_basicstr_axiom_todo.empty() || !m_str_eq_todo.empty() || !m_concat_axiom_todo.empty() || !m_concat_eval_todo.empty() || !m_library_aware_axiom_todo.empty() - || !m_delayed_axiom_setup_terms.empty(); + || !m_delayed_axiom_setup_terms.empty() + || !m_persisted_axiom_todo.empty() ; } @@ -895,7 +898,11 @@ namespace smt { set_up_axioms(m_delayed_axiom_setup_terms[i].get()); } m_delayed_axiom_setup_terms.reset(); - } + for (expr * a : m_persisted_axiom_todo) { + assert_axiom(a); + } + m_persisted_axiom_todo.reset(); + } // can_propagate } /* @@ -6696,7 +6703,7 @@ namespace smt { } else if (u.re.is_full_char(re)) { return true; } else if (u.re.is_full_seq(re)) { - return false; // generally unbounded + return true; } else if (u.re.is_complement(re)) { // TODO can we do better? return false; @@ -8474,6 +8481,10 @@ namespace smt { } } + void theory_str::add_persisted_axiom(expr * a) { + m_persisted_axioms.push_back(a); + } + void theory_str::pop_scope_eh(unsigned num_scopes) { sLevel -= num_scopes; TRACE("str", tout << "pop " << num_scopes << " to " << sLevel << std::endl;); @@ -8519,6 +8530,11 @@ namespace smt { m_basicstr_axiom_todo.reset(); m_basicstr_axiom_todo = new_m_basicstr; + for (expr * e : m_persisted_axioms) { + TRACE("str", tout << "persist axiom: " << mk_pp(e, get_manager()) << std::endl;); + m_persisted_axiom_todo.push_back(e); + } + m_trail_stack.pop_scope(num_scopes); theory::pop_scope_eh(num_scopes); @@ -10574,6 +10590,7 @@ namespace smt { TRACE("str", tout << "product automaton is empty; asserting conflict clause" << std::endl;); expr_ref conflict_clause(m.mk_not(mk_and(conflict_terms)), m); assert_axiom(conflict_clause); + add_persisted_axiom(conflict_clause); regex_axiom_add = true; } } // foreach (entry in regex_terms_by_string) diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index da9ed663d..7188da25c 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -352,6 +352,10 @@ protected: // enode lists for library-aware/high-level string terms (e.g. substr, contains) ptr_vector m_library_aware_axiom_todo; + // list of axioms that are re-asserted every time the scope is popped + expr_ref_vector m_persisted_axioms; + expr_ref_vector m_persisted_axiom_todo; + // hashtable of all exprs for which we've already set up term-specific axioms -- // this prevents infinite recursive descent with respect to axioms that // include an occurrence of the term for which axioms are being generated @@ -545,6 +549,8 @@ protected: void instantiate_axiom_str_to_int(enode * e); void instantiate_axiom_int_to_str(enode * e); + void add_persisted_axiom(expr * a); + expr * mk_RegexIn(expr * str, expr * regexp); void instantiate_axiom_RegexIn(enode * e); app * mk_unroll(expr * n, expr * bound); From af96e4272403929969640cde16930e3f395ac82b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Mar 2018 21:11:55 -0700 Subject: [PATCH 0648/1283] fixing local search Signed-off-by: Nikolaj Bjorner --- src/opt/opt_lns.cpp | 4 +- src/sat/sat_local_search.cpp | 185 ++++++++++++++++++++++++++--------- src/sat/sat_local_search.h | 15 ++- 3 files changed, 156 insertions(+), 48 deletions(-) diff --git a/src/opt/opt_lns.cpp b/src/opt/opt_lns.cpp index d5038dc29..0cdcf19c4 100644 --- a/src/opt/opt_lns.cpp +++ b/src/opt/opt_lns.cpp @@ -95,11 +95,11 @@ namespace opt { ++index; // freeze phase in both SAT solver and local search to current assignment - p.set_uint("inprocess.max", 3); + p.set_uint("inprocess.max", 5); p.set_bool("phase.sticky", true); p.set_uint("local_search_threads", 1); p.set_uint("max_conflicts", 100000); - p.set_uint("unit_walk_threads", 1); + //p.set_uint("unit_walk_threads", 1); m_solver->updt_params(p); is_sat = m_solver->check_sat(lits); diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 5c2425578..35e371a9c 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -35,12 +35,14 @@ namespace sat { m_vars.push_back(var_info()); if (m_config.phase_sticky()) { - for (var_info& vi : m_vars) - vi.m_value = vi.m_bias < 100; + for (var_info& vi : m_vars) + if (!vi.m_unit) + vi.m_value = vi.m_bias < 100; } else { for (var_info& vi : m_vars) - vi.m_value = (0 == (m_rand() % 2)); + if (!vi.m_unit) + vi.m_value = (0 == (m_rand() % 2)); } m_best_solution.resize(num_vars() + 1, false); @@ -54,10 +56,10 @@ namespace sat { bool pol = true; var_info& vi = m_vars[v]; for (unsigned k = 0; k < 2; pol = !pol, k++) { - for (unsigned i = 0; i < m_vars[v].m_watch[pol].size(); ++i) { - constraint const& c = m_constraints[m_vars[v].m_watch[pol][i].m_constraint_id]; - for (unsigned j = 0; j < c.size(); ++j) { - bool_var w = c[j].var(); + for (auto const& wi : m_vars[v].m_watch[pol]) { + constraint const& c = m_constraints[wi.m_constraint_id]; + for (literal lit : c) { + bool_var w = lit.var(); if (w == v || is_neighbor.contains(w)) continue; is_neighbor.insert(w); vi.m_neighbors.push_back(w); @@ -75,7 +77,6 @@ namespace sat { } void local_search::init_cur_solution() { - IF_VERBOSE(1, verbose_stream() << "(sat.local_search init-cur-solution)\n"); for (var_info& vi : m_vars) { // use bias with a small probability if (m_rand() % 10 < 5 || m_config.phase_sticky()) { @@ -92,10 +93,10 @@ namespace sat { for (unsigned v = 0; v < num_vars(); ++v) { bool is_true = cur_solution(v); coeff_vector& truep = m_vars[v].m_watch[is_true]; - for (unsigned i = 0; i < truep.size(); ++i) { - unsigned c = truep[i].m_constraint_id; + for (auto const& coeff : truep) { + unsigned c = coeff.m_constraint_id; constraint& cn = m_constraints[c]; - cn.m_slack -= truep[i].m_coeff; + cn.m_slack -= coeff.m_coeff; } } for (unsigned c = 0; c < num_constraints(); ++c) { @@ -111,8 +112,8 @@ namespace sat { bool is_true = cur_solution(v); coeff_vector& truep = m_vars[v].m_watch[is_true]; coeff_vector& falsep = m_vars[v].m_watch[!is_true]; - for (unsigned i = 0; i < falsep.size(); ++i) { - constraint& c = m_constraints[falsep[i].m_constraint_id]; + for (auto const& coeff : falsep) { + constraint& c = m_constraints[coeff.m_constraint_id]; //SASSERT(falsep[i].m_coeff == 1); // will --slack if (c.m_slack <= 0) { @@ -121,9 +122,9 @@ namespace sat { dec_score(v); } } - for (unsigned i = 0; i < truep.size(); ++i) { - //SASSERT(truep[i].m_coeff == 1); - constraint& c = m_constraints[truep[i].m_constraint_id]; + for (auto const& coeff : truep) { + //SASSERT(coeff.m_coeff == 1); + constraint& c = m_constraints[coeff.m_constraint_id]; // will --true_terms_count[c] // will ++slack if (c.m_slack <= -1) { @@ -148,7 +149,7 @@ namespace sat { void local_search::reinit() { - IF_VERBOSE(10, verbose_stream() << "(sat-local-search reinit)\n";); + IF_VERBOSE(0, verbose_stream() << "(sat-local-search reinit)\n";); if (true || !m_is_pb) { // // the following methods does NOT converge for pseudo-boolean @@ -171,12 +172,13 @@ namespace sat { } // init unsat stack + m_is_unsat = false; m_unsat_stack.reset(); // init solution using the bias init_cur_solution(); - // init varibale information + // init variable information // the last variable is the virtual variable m_vars.back().m_score = INT_MIN; @@ -196,6 +198,49 @@ namespace sat { init_scores(); init_goodvars(); set_best_unsat(); + + for (bool_var v : m_units) { + propagate(literal(v, !cur_solution(v))); + if (m_is_unsat) break; + } + if (m_is_unsat) { + IF_VERBOSE(0, verbose_stream() << "unsat during reinit\n"); + } + } + + bool local_search::propagate(literal lit) { + bool unit = is_unit(lit); + VERIFY(is_true(lit)); + m_prop_queue.reset(); + add_propagation(lit); + for (unsigned i = 0; i < m_prop_queue.size() && i < m_vars.size(); ++i) { + literal lit2 = m_prop_queue[i]; + if (!is_true(lit2)) { + if (is_unit(lit2)) return false; + flip_walksat(lit2.var()); + add_propagation(lit2); + } + } + if (m_prop_queue.size() >= m_vars.size()) { + IF_VERBOSE(0, verbose_stream() << "failed literal\n"); + return false; + } + if (unit) { + for (literal lit : m_prop_queue) { + VERIFY(is_true(lit)); + add_unit(lit); + } + } + return true; + } + + void local_search::add_propagation(literal l) { + VERIFY(is_true(l)); + for (literal lit : m_vars[l.var()].m_bin[l.sign()]) { + if (!is_true(lit)) { + m_prop_queue.push_back(lit); + } + } } void local_search::set_best_unsat() { @@ -232,6 +277,7 @@ namespace sat { } void local_search::verify_solution() const { + IF_VERBOSE(0, verbose_stream() << "verifying solution\n"); for (constraint const& c : m_constraints) verify_constraint(c); } @@ -239,7 +285,7 @@ namespace sat { void local_search::verify_unsat_stack() const { for (unsigned i : m_unsat_stack) { constraint const& c = m_constraints[i]; - SASSERT(c.m_k < constraint_value(c)); + VERIFY(c.m_k < constraint_value(c)); } } @@ -254,8 +300,7 @@ namespace sat { unsigned local_search::constraint_value(constraint const& c) const { unsigned value = 0; - for (unsigned i = 0; i < c.size(); ++i) { - literal t = c[i]; + for (literal t : c) { if (is_true(t)) { value += constraint_coeff(c, t); } @@ -269,7 +314,6 @@ namespace sat { TRACE("sat", display(verbose_stream() << "verify ", c);); if (c.m_k < value) { IF_VERBOSE(0, display(verbose_stream() << "violated constraint: ", c) << "value: " << value << "\n";); - UNREACHABLE(); } } @@ -279,6 +323,17 @@ namespace sat { // ~c <= k void local_search::add_cardinality(unsigned sz, literal const* c, unsigned k) { + if (sz == 1 && k == 0) { + add_unit(c[0]); + return; + } + if (k == 1 && sz == 2) { + for (unsigned i = 0; i < 2; ++i) { + literal t(c[i]), s(c[1-i]); + m_vars.reserve(t.var() + 1); + m_vars[t.var()].m_bin[is_pos(t)].push_back(s); + } + } unsigned id = m_constraints.size(); m_constraints.push_back(constraint(k, id)); for (unsigned i = 0; i < sz; ++i) { @@ -287,15 +342,15 @@ namespace sat { m_vars[t.var()].m_watch[is_pos(t)].push_back(pbcoeff(id, 1)); m_constraints.back().push(t); } - if (sz == 1 && k == 0) { - literal lit = c[0]; - m_vars[lit.var()].m_bias = lit.sign() ? 100 : 0; - m_vars[lit.var()].m_value = lit.sign(); - } + } // c * coeffs <= k void local_search::add_pb(unsigned sz, literal const* c, unsigned const* coeffs, unsigned k) { + if (sz == 1 && k == 0) { + add_unit(~c[0]); + return; + } unsigned id = m_constraints.size(); m_constraints.push_back(constraint(k, id)); for (unsigned i = 0; i < sz; ++i) { @@ -304,27 +359,36 @@ namespace sat { m_vars[t.var()].m_watch[is_pos(t)].push_back(pbcoeff(id, coeffs[i])); m_constraints.back().push(t); } - if (sz == 1 && k == 0) { - literal lit = c[0]; - m_vars[lit.var()].m_bias = lit.sign() ? 100 : 0; - m_vars[lit.var()].m_value = lit.sign(); - } + } + + void local_search::add_unit(literal lit) { + bool_var v = lit.var(); + if (is_unit(lit)) return; + VERIFY(!m_units.contains(v)); + m_vars[v].m_bias = lit.sign() ? 0 : 100; + m_vars[v].m_value = !lit.sign(); + m_vars[v].m_unit = true; + m_units.push_back(v); + verify_unsat_stack(); } local_search::local_search() : - m_par(0) { + m_par(0), + m_is_unsat(false) { } void local_search::import(solver& s, bool _init) { m_is_pb = false; m_vars.reset(); m_constraints.reset(); + m_units.reset(); + m_unsat_stack.reset(); m_vars.reserve(s.num_vars()); if (m_config.phase_sticky()) { unsigned v = 0; for (var_info& vi : m_vars) { - if (vi.m_bias != 0 && vi.m_bias != 100) + if (!vi.m_unit) vi.m_bias = s.m_phase[v] == POS_PHASE ? 100 : 0; ++v; } @@ -491,6 +555,7 @@ namespace sat { m_last_best_unsat_rate = m_best_unsat_rate; m_best_unsat_rate = (double)m_unsat_stack.size() / num_constraints(); } + if (m_is_unsat) return; } total_flips += step; PROGRESS(tries, total_flips); @@ -499,8 +564,7 @@ namespace sat { } if (tries % 10 == 0 && !m_unsat_stack.empty()) { reinit(); - } - + } } } @@ -561,7 +625,11 @@ namespace sat { TRACE("sat", display(tout);); lbool result; - if (m_unsat_stack.empty() && all_objectives_are_met()) { + if (m_is_unsat) { + // result = l_false; + result = l_undef; + } + else if (m_unsat_stack.empty() && all_objectives_are_met()) { verify_solution(); extract_model(); result = l_true; @@ -590,15 +658,15 @@ namespace sat { } void local_search::pick_flip_walksat() { + reflip: bool_var best_var = null_bool_var; unsigned n = 1; bool_var v = null_bool_var; unsigned num_unsat = m_unsat_stack.size(); constraint const& c = m_constraints[m_unsat_stack[m_rand() % m_unsat_stack.size()]]; - SASSERT(c.m_k < constraint_value(c)); + // VERIFY(c.m_k < constraint_value(c)); unsigned reflipped = 0; bool is_core = m_unsat_stack.size() <= 10; - reflip: // TBD: dynamic noise strategy //if (m_rand() % 100 < 98) { if (m_rand() % 10000 <= m_noise) { @@ -607,7 +675,15 @@ namespace sat { unsigned best_bsb = 0; literal_vector::const_iterator cit = c.m_literals.begin(), cend = c.m_literals.end(); literal l; - for (; !is_true(*cit); ++cit) { SASSERT(cit != cend); } + for (; (cit != cend) && (!is_true(*cit) || is_unit(*cit)); ++cit) { } + if (cit == cend) { + if (c.m_k < constraint_value(c)) { + IF_VERBOSE(0, display(verbose_stream() << "unsat clause\n", c)); + m_is_unsat = true; + return; + } + goto reflip; + } l = *cit; best_var = v = l.var(); bool tt = cur_solution(v); @@ -622,7 +698,7 @@ namespace sat { ++cit; for (; cit != cend; ++cit) { l = *cit; - if (is_true(l)) { + if (is_true(l) && !is_unit(l)) { v = l.var(); unsigned bsb = 0; coeff_vector const& falsep = m_vars[v].m_watch[!cur_solution(v)]; @@ -662,7 +738,7 @@ namespace sat { } else { for (literal l : c) { - if (is_true(l)) { + if (is_true(l) && !is_unit(l)) { if (m_rand() % n == 0) { best_var = l.var(); } @@ -670,7 +746,27 @@ namespace sat { } } } + if (best_var == null_bool_var) { + IF_VERBOSE(1, verbose_stream() << "(sat.local_search :unsat)\n"); + return; + } + flip_walksat(best_var); + literal lit(best_var, !cur_solution(best_var)); + if (!propagate(lit)) { + IF_VERBOSE(0, verbose_stream() << "failed literal " << lit << "\n"); + if (is_true(lit)) { + flip_walksat(best_var); + } + add_unit(~lit); + if (!propagate(~lit)) { + IF_VERBOSE(0, verbose_stream() << "unsat\n"); + m_is_unsat = true; + return; + } + goto reflip; + } + if (false && is_core && c.m_k < constraint_value(c)) { ++reflipped; goto reflip; @@ -702,7 +798,7 @@ namespace sat { sat(ci); } } - + // verify_unsat_stack(); } @@ -914,8 +1010,7 @@ namespace sat { } TRACE("sat", - tout << "seed:\t" << m_config.seed() << '\n'; - tout << "strategy id:\t" << m_config.strategy_id() << '\n'; + tout << "seed:\t" << m_config.random_seed() << '\n'; tout << "best_known_value:\t" << m_config.best_known_value() << '\n'; tout << "max_steps:\t" << m_max_steps << '\n'; ); diff --git a/src/sat/sat_local_search.h b/src/sat/sat_local_search.h index 0f9bc95d7..8a63898c3 100644 --- a/src/sat/sat_local_search.h +++ b/src/sat/sat_local_search.h @@ -79,7 +79,7 @@ namespace sat { bool m_value; // current solution unsigned m_bias; // bias for current solution in percentage. // if bias is 0, then value is always false, if 100, then always true - // lbool m_unit; // if l_true, then unit atom, if l_false, then unit negative literal + bool m_unit; // is this a unit literal bool m_conf_change; // whether its configure changes since its last flip bool m_in_goodvar_stack; int m_score; @@ -88,9 +88,11 @@ namespace sat { int m_cscc; // how many times its constraint state configure changes since its last flip bool_var_vector m_neighbors; // neighborhood variables coeff_vector m_watch[2]; + literal_vector m_bin[2]; var_info(): m_value(true), m_bias(50), + m_unit(false), m_conf_change(true), m_in_goodvar_stack(false), m_score(0), @@ -123,6 +125,7 @@ namespace sat { vector m_vars; + svector m_units; inline int score(bool_var v) const { return m_vars[v].m_score; } inline void inc_score(bool_var v) { m_vars[v].m_score++; } @@ -147,6 +150,7 @@ namespace sat { vector m_constraints; literal_vector m_assumptions; + literal_vector m_prop_queue; unsigned m_num_non_binary_clauses; bool m_is_pb; @@ -155,6 +159,8 @@ namespace sat { inline bool is_true(bool_var v) const { return cur_solution(v); } inline bool is_true(literal l) const { return cur_solution(l.var()) != l.sign(); } inline bool is_false(literal l) const { return cur_solution(l.var()) == l.sign(); } + inline bool is_unit(bool_var v) const { return m_vars[v].m_unit; } + inline bool is_unit(literal l) const { return m_vars[l.var()].m_unit; } unsigned num_constraints() const { return m_constraints.size(); } // constraint index from 1 to num_constraint @@ -162,6 +168,7 @@ namespace sat { unsigned constraint_slack(unsigned ci) const { return m_constraints[ci].m_slack; } // unsat constraint stack + bool m_is_unsat; unsigned_vector m_unsat_stack; // store all the unsat constraits unsigned_vector m_index_in_unsat_stack; // which position is a contraint in the unsat_stack @@ -206,6 +213,10 @@ namespace sat { void flip_walksat(bool_var v); + bool propagate(literal lit); + + void add_propagation(literal lit); + void walksat(); void gsat(); @@ -242,6 +253,8 @@ namespace sat { void add_clause(unsigned sz, literal const* c); + void add_unit(literal lit); + std::ostream& display(std::ostream& out) const; std::ostream& display(std::ostream& out, constraint const& c) const; From e4cab7bc834b81c8f4d0dcf3fd62668f61e916a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filipe=20Gon=C3=A7alves?= Date: Fri, 16 Mar 2018 22:04:39 +1000 Subject: [PATCH 0649/1283] Fix #1540 Remove extraneous function Remove extra __deepcopy__ function definition that shadows working implementation. --- src/api/python/z3/z3.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index e68d7280d..d4ff556fe 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -368,9 +368,6 @@ class AstRef(Z3PPObject): def __copy__(self): return self.translate(self.ctx) - def __deepcopy__(self): - return self.translate(self.ctx) - def hash(self): """Return a hashcode for the `self`. From 0a0b7a9635d416d117b488639666d25d6b5491be Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 16 Mar 2018 20:56:06 +0700 Subject: [PATCH 0650/1283] Fix minor issues in docs. --- src/api/z3_algebraic.h | 2 +- src/api/z3_api.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/z3_algebraic.h b/src/api/z3_algebraic.h index faa41bfea..49c61afef 100644 --- a/src/api/z3_algebraic.h +++ b/src/api/z3_algebraic.h @@ -31,7 +31,7 @@ extern "C" { /** @name Algebraic Numbers */ /*@{*/ /** - \brief Return Z3_TRUE if \c can be used as value in the Z3 real algebraic + \brief Return Z3_TRUE if \c a can be used as value in the Z3 real algebraic number package. def_API('Z3_algebraic_is_value', BOOL, (_in(CONTEXT), _in(AST))) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 88d6aa1cf..87bb4d818 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4350,7 +4350,7 @@ extern "C" { Z3_bool Z3_API Z3_is_numeral_ast(Z3_context c, Z3_ast a); /** - \brief Return true if the give AST is a real algebraic number. + \brief Return true if the given AST is a real algebraic number. def_API('Z3_is_algebraic_number', BOOL, (_in(CONTEXT), _in(AST))) */ From 86d3bbe6cb8815a20bee5ee29caff12dac9f5202 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Mar 2018 07:46:27 -0700 Subject: [PATCH 0651/1283] added TODO markers in theory_str.h for moving to obj_map, remove include of stdbool for now Signed-off-by: Nikolaj Bjorner --- src/api/z3.h | 1 - src/smt/smt_context_pp.cpp | 50 ++++++++++++----------------------- src/smt/theory_str.cpp | 17 +++++------- src/smt/theory_str.h | 34 ++++++++---------------- src/util/obj_pair_hashtable.h | 13 +++++++++ 5 files changed, 48 insertions(+), 67 deletions(-) diff --git a/src/api/z3.h b/src/api/z3.h index b29f1d6ba..e08b0c073 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -22,7 +22,6 @@ Notes: #define Z3_H_ #include -#include #include "z3_macros.h" #include "z3_api.h" #include "z3_ast_containers.h" diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index e883e0a09..f072a1d13 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -43,11 +43,10 @@ namespace smt { return out << "RESOURCE_LIMIT"; case THEORY: if (!m_incomplete_theories.empty()) { - ptr_vector::const_iterator it = m_incomplete_theories.begin(); - ptr_vector::const_iterator end = m_incomplete_theories.end(); - for (bool first = true; it != end; ++it) { + bool first = true; + for (theory* th : m_incomplete_theories) { if (first) first = false; else out << " "; - out << (*it)->get_name(); + out << th->get_name(); } } else { @@ -173,12 +172,10 @@ namespace smt { void context::display_binary_clauses(std::ostream & out) const { bool first = true; - vector::const_iterator it = m_watches.begin(); - vector::const_iterator end = m_watches.end(); - for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - literal l1 = to_literal(l_idx); + unsigned l_idx = 0; + for (watch_list const& wl : m_watches) { + literal l1 = to_literal(l_idx++); literal neg_l1 = ~l1; - watch_list const & wl = *it; literal const * it2 = wl.begin_literals(); literal const * end2 = wl.end_literals(); for (; it2 != end2; ++it2) { @@ -291,10 +288,7 @@ namespace smt { } void context::display_theories(std::ostream & out) const { - ptr_vector::const_iterator it = m_theory_set.begin(); - ptr_vector::const_iterator end = m_theory_set.end(); - for (; it != end; ++it) { - theory * th = *it; + for (theory* th : m_theory_set) { th->display(out); } } @@ -393,10 +387,8 @@ namespace smt { #endif m_qmanager->collect_statistics(st); m_asserted_formulas.collect_statistics(st); - ptr_vector::const_iterator it = m_theory_set.begin(); - ptr_vector::const_iterator end = m_theory_set.end(); - for (; it != end; ++it) { - (*it)->collect_statistics(st); + for (theory* th : m_theory_set) { + th->collect_statistics(st); } } @@ -498,10 +490,7 @@ namespace smt { */ void context::display_normalized_enodes(std::ostream & out) const { out << "normalized enodes:\n"; - ptr_vector::const_iterator it = m_enodes.begin(); - ptr_vector::const_iterator end = m_enodes.end(); - for (; it != end; ++it) { - enode * n = *it; + for (enode * n : m_enodes) { out << "#"; out.width(5); out << std::left << n->get_owner_id() << " #"; @@ -532,28 +521,23 @@ namespace smt { } void context::display_enodes_lbls(std::ostream & out) const { - ptr_vector::const_iterator it = m_enodes.begin(); - ptr_vector::const_iterator end = m_enodes.end(); - for (; it != end; ++it) { - enode * n = *it; + for (enode* n : m_enodes) { n->display_lbls(out); } } void context::display_decl2enodes(std::ostream & out) const { out << "decl2enodes:\n"; - vector::const_iterator it1 = m_decl2enodes.begin(); - vector::const_iterator end1 = m_decl2enodes.end(); - for (unsigned id = 0; it1 != end1; ++it1, ++id) { - enode_vector const & v = *it1; + unsigned id = 0; + for (enode_vector const& v : m_decl2enodes) { if (!v.empty()) { out << "id " << id << " ->"; - enode_vector::const_iterator it2 = v.begin(); - enode_vector::const_iterator end2 = v.end(); - for (; it2 != end2; ++it2) - out << " #" << (*it2)->get_owner_id(); + for (enode* n : v) { + out << " #" << n->get_owner_id(); + } out << "\n"; } + ++id; } } diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0016b8f36..30092097a 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -288,10 +288,9 @@ namespace smt { } } - static void cut_vars_map_copy(std::map & dest, std::map & src) { - std::map::iterator itor = src.begin(); - for (; itor != src.end(); itor++) { - dest[itor->first] = 1; + static void cut_vars_map_copy(obj_map & dest, obj_map & src) { + for (auto const& kv : src) { + dest.insert(kv.m_key, 1); } } @@ -306,9 +305,8 @@ namespace smt { return false; } - std::map::iterator itor = cut_var_map[n1].top()->vars.begin(); - for (; itor != cut_var_map[n1].top()->vars.end(); ++itor) { - if (cut_var_map[n2].top()->vars.find(itor->first) != cut_var_map[n2].top()->vars.end()) { + for (auto const& kv : cut_var_map[n1].top()->vars) { + if (cut_var_map[n2].top()->vars.contains(kv.m_key)) { return true; } } @@ -2572,9 +2570,8 @@ namespace smt { if (cut_var_map.contains(node)) { if (!cut_var_map[node].empty()) { xout << "[" << cut_var_map[node].top()->level << "] "; - std::map::iterator itor = cut_var_map[node].top()->vars.begin(); - for (; itor != cut_var_map[node].top()->vars.end(); ++itor) { - xout << mk_pp(itor->first, m) << ", "; + for (auto const& kv : cut_var_map[node].top()->vars) { + xout << mk_pp(kv.m_key, m) << ", "; } xout << std::endl; } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 64ede71b5..09d6498a4 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -77,25 +77,8 @@ public: void register_value(expr * n) override { /* Ignore */ } }; -// rather than modify obj_pair_map I inherit from it and add my own helper methods -class theory_str_contain_pair_bool_map_t : public obj_pair_map { -public: - expr * operator[](std::pair key) const { - expr * value; - bool found = this->find(key.first, key.second, value); - if (found) { - return value; - } else { - TRACE("t_str", tout << "WARNING: lookup miss in contain_pair_bool_map!" << std::endl;); - return nullptr; - } - } - - bool contains(std::pair key) const { - expr * unused; - return this->find(key.first, key.second, unused); - } -}; +// NSB: added operator[] and contains to obj_pair_hashtable +class theory_str_contain_pair_bool_map_t : public obj_pair_map {}; template class binary_search_trail : public trail { @@ -169,7 +152,7 @@ class theory_str : public theory { struct T_cut { int level; - std::map vars; + obj_map vars; T_cut() { level = -100; @@ -292,8 +275,8 @@ protected: int tmpXorVarCount; int tmpLenTestVarCount; int tmpValTestVarCount; - std::map, std::map > varForBreakConcat; - + // obj_pair_map > varForBreakConcat; + std::map, std::map > varForBreakConcat; bool avoidLoopCut; bool loopDetected; obj_map > cut_var_map; @@ -312,9 +295,11 @@ protected: obj_hashtable input_var_in_len; obj_map fvar_len_count_map; + // TBD: need to replace by obj_map for determinism std::map > fvar_lenTester_map; obj_map lenTester_fvar_map; + // TBD: need to replace by obj_map for determinism std::map > > > fvar_valueTester_map; std::map valueTester_fvar_map; @@ -322,8 +307,10 @@ protected: // This can't be an expr_ref_vector because the constructor is wrong, // we would need to modify the allocator so we pass in ast_manager + // TBD: need to replace by obj_map for determinism std::map, ptr_vector > > unroll_tries_map; std::map unroll_var_map; + // TBD: need to replace by obj_pair_map for determinism std::map, expr*> concat_eq_unroll_ast_map; expr_ref_vector contains_map; @@ -332,9 +319,10 @@ protected: //obj_map > contain_pair_idx_map; std::map > > contain_pair_idx_map; + // TBD: do a curried map for determinism. std::map, expr*> regex_in_bool_map; + // TBD: need to replace by obj_map for determinism std::map > regex_in_var_reg_str_map; - std::map regex_nfa_cache; // Regex term --> NFA svector char_set; diff --git a/src/util/obj_pair_hashtable.h b/src/util/obj_pair_hashtable.h index f002a7807..2b8924e9f 100644 --- a/src/util/obj_pair_hashtable.h +++ b/src/util/obj_pair_hashtable.h @@ -160,10 +160,23 @@ public: } return (nullptr != e); } + + Value const & find(Key1 * k1, Key2 * k2) const { + entry * e = find_core(k1, k2); + return e->get_data().get_value(); + } + + Value const& operator[](std::pair const& key) const { + return find(key.first, key.second); + } bool contains(Key1 * k1, Key2 * k2) const { return find_core(k1, k2) != nullptr; } + + bool contains(std::pair const& key) const { + return contains(key.first, key.second); + } void erase(Key1 * k1, Key2 * k2) { m_table.remove(key_data(k1, k2)); From b12a1caa0759052380d60fbd1f71a5d8436ac047 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Mar 2018 09:05:44 -0700 Subject: [PATCH 0652/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/smt/theory_str.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 30092097a..e1340c301 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -321,7 +321,7 @@ namespace smt { T_cut * varInfo = alloc(T_cut); m_cut_allocs.push_back(varInfo); varInfo->level = slevel; - varInfo->vars[node] = 1; + varInfo->vars.insert(node, 1); cut_var_map.insert(baseNode, std::stack()); cut_var_map[baseNode].push(varInfo); TRACE("str", tout << "add var info for baseNode=" << mk_pp(baseNode, get_manager()) << ", node=" << mk_pp(node, get_manager()) << " [" << slevel << "]" << std::endl;); @@ -330,7 +330,7 @@ namespace smt { T_cut * varInfo = alloc(T_cut); m_cut_allocs.push_back(varInfo); varInfo->level = slevel; - varInfo->vars[node] = 1; + varInfo->vars.insert(node, 1); cut_var_map[baseNode].push(varInfo); TRACE("str", tout << "add var info for baseNode=" << mk_pp(baseNode, get_manager()) << ", node=" << mk_pp(node, get_manager()) << " [" << slevel << "]" << std::endl;); } else { @@ -339,11 +339,11 @@ namespace smt { m_cut_allocs.push_back(varInfo); varInfo->level = slevel; cut_vars_map_copy(varInfo->vars, cut_var_map[baseNode].top()->vars); - varInfo->vars[node] = 1; + varInfo->vars.insert(node, 1); cut_var_map[baseNode].push(varInfo); TRACE("str", tout << "add var info for baseNode=" << mk_pp(baseNode, get_manager()) << ", node=" << mk_pp(node, get_manager()) << " [" << slevel << "]" << std::endl;); } else if (cut_var_map[baseNode].top()->level == slevel) { - cut_var_map[baseNode].top()->vars[node] = 1; + cut_var_map[baseNode].top()->vars.insert(node, 1); TRACE("str", tout << "add var info for baseNode=" << mk_pp(baseNode, get_manager()) << ", node=" << mk_pp(node, get_manager()) << " [" << slevel << "]" << std::endl;); } else { get_manager().raise_exception("entered illegal state during add_cut_info_one_node()"); From 5dd7e2c520b37c75bfe3c22f1e81911373e1dfed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Mar 2018 19:30:13 -0700 Subject: [PATCH 0653/1283] fix #1544 Signed-off-by: Nikolaj Bjorner --- src/api/z3.h | 1 - src/ast/rewriter/rewriter_def.h | 2 ++ src/model/model_evaluator.cpp | 11 +++++------ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/api/z3.h b/src/api/z3.h index b29f1d6ba..e08b0c073 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -22,7 +22,6 @@ Notes: #define Z3_H_ #include -#include #include "z3_macros.h" #include "z3_api.h" #include "z3_ast_containers.h" diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 878f4ef4c..dfb6542d6 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -194,12 +194,14 @@ bool rewriter_tpl::constant_fold(app * t, frame & fr) { result_stack().shrink(fr.m_spos); result_stack().push_back(arg); fr.m_state = REWRITE_BUILTIN; + TRACE("rewriter_step", tout << "step\n" << mk_ismt2_pp(t, m()) << "\n";); if (visit(arg, fr.m_max_depth)) { m_r = result_stack().back(); result_stack().pop_back(); result_stack().pop_back(); result_stack().push_back(m_r); cache_result(t, m_r, m_pr, fr.m_cache_result); + TRACE("rewriter_step", tout << "step 1\n" << mk_ismt2_pp(m_r, m()) << "\n";); frame_stack().pop_back(); set_new_child_flag(t); } diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index fd2dc7656..227e14ca6 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -187,14 +187,14 @@ struct evaluator_cfg : public default_rewriter_cfg { TRACE("model_evaluator", tout << "reduce_app " << f->get_name() << "\n"; for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m) << "\n"; tout << "---->\n" << mk_ismt2_pp(result, m) << "\n";); - return BR_DONE; + return BR_REWRITE1; } if (st == BR_FAILED && !m.is_builtin_family_id(fid)) st = evaluate_partial_theory_func(f, num, args, result, result_pr); if (st == BR_DONE && is_app(result)) { app* a = to_app(result); if (evaluate(a->get_decl(), a->get_num_args(), a->get_args(), result)) { - return BR_DONE; + return BR_REWRITE1; } } CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); @@ -399,12 +399,11 @@ struct evaluator_cfg : public default_rewriter_cfg { } } } - args_table::iterator it = table1.begin(), end = table1.end(); - for (; it != end; ++it) { - switch (compare((*it)[arity], else2)) { + for (auto const& t : table1) { + switch (compare((t)[arity], else2)) { case l_true: break; case l_false: result = m.mk_false(); return BR_DONE; - default: conj.push_back(m.mk_eq((*it)[arity], else2)); break; + default: conj.push_back(m.mk_eq((t)[arity], else2)); break; } } result = mk_and(conj); From aa913c564c7b41fc1a2bb3a198b91f18ff717892 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Mar 2018 04:21:28 -0700 Subject: [PATCH 0654/1283] moving more std::map std::set to obj_*, #1529 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_str.cpp | 19 ++++++++++--------- src/smt/theory_str.h | 11 +++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index e1340c301..69cf80de6 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -441,7 +441,7 @@ namespace smt { void theory_str::track_variable_scope(expr * var) { if (internal_variable_scope_levels.find(sLevel) == internal_variable_scope_levels.end()) { - internal_variable_scope_levels[sLevel] = std::set(); + internal_variable_scope_levels[sLevel] = obj_hashtable(); } internal_variable_scope_levels[sLevel].insert(var); } @@ -6468,9 +6468,9 @@ namespace smt { expr * regexTerm = a_regexIn->get_arg(1); // TODO figure out regex NFA stuff - if (regex_nfa_cache.find(regexTerm) == regex_nfa_cache.end()) { + if (!regex_nfa_cache.contains(regexTerm)) { TRACE("str", tout << "regex_nfa_cache: cache miss" << std::endl;); - regex_nfa_cache[regexTerm] = nfa(u, regexTerm); + regex_nfa_cache.insert(regexTerm, nfa(u, regexTerm)); } else { TRACE("str", tout << "regex_nfa_cache: cache hit" << std::endl;); } @@ -9286,7 +9286,7 @@ namespace smt { h++; coverAll = get_next_val_encode(options[options.size() - 1], base); } - val_range_map[val_indicator] = options[options.size() - 1]; + val_range_map.insert(val_indicator, options[options.size() - 1]); TRACE("str", tout << "value tester encoding " << "{" << std::endl; @@ -9380,7 +9380,7 @@ namespace smt { TRACE("str", tout << "no previous value testers, or none of them were in scope" << std::endl;); int tries = 0; expr * val_indicator = mk_internal_valTest_var(freeVar, len, tries); - valueTester_fvar_map[val_indicator] = freeVar; + valueTester_fvar_map.insert(val_indicator, freeVar); fvar_valueTester_map[freeVar][len].push_back(std::make_pair(sLevel, val_indicator)); print_value_tester_list(fvar_valueTester_map[freeVar][len]); return gen_val_options(freeVar, len_indicator, val_indicator, len_valueStr, tries); @@ -9430,7 +9430,7 @@ namespace smt { refresh_theory_var(valTester); } else { valTester = mk_internal_valTest_var(freeVar, len, i + 1); - valueTester_fvar_map[valTester] = freeVar; + valueTester_fvar_map.insert(valTester, freeVar); fvar_valueTester_map[freeVar][len].push_back(std::make_pair(sLevel, valTester)); print_value_tester_list(fvar_valueTester_map[freeVar][len]); } @@ -9595,7 +9595,7 @@ namespace smt { if (low.is_neg()) { toAssert = m_autil.mk_ge(cntInUnr, mk_int(0)); } else { - if (unroll_var_map.find(unrFunc) == unroll_var_map.end()) { + if (!unroll_var_map.contains(unrFunc)) { expr_ref newVar1(mk_regex_rep_var(), mgr); expr_ref newVar2(mk_regex_rep_var(), mgr); @@ -9627,8 +9627,9 @@ namespace smt { // put together toAssert = mgr.mk_and(ctx.mk_eq_atom(op0, and1), toAssert); - unroll_var_map[unrFunc] = toAssert; - } else { + unroll_var_map.insert(unrFunc, toAssert); + } + else { toAssert = unroll_var_map[unrFunc]; } } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 09d6498a4..508a1c905 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -286,7 +286,7 @@ protected: obj_hashtable variable_set; obj_hashtable internal_variable_set; obj_hashtable regex_variable_set; - std::map > internal_variable_scope_levels; + std::map > internal_variable_scope_levels; obj_hashtable internal_lenTest_vars; obj_hashtable internal_valTest_vars; @@ -295,21 +295,20 @@ protected: obj_hashtable input_var_in_len; obj_map fvar_len_count_map; - // TBD: need to replace by obj_map for determinism std::map > fvar_lenTester_map; obj_map lenTester_fvar_map; // TBD: need to replace by obj_map for determinism std::map > > > fvar_valueTester_map; - std::map valueTester_fvar_map; + obj_map valueTester_fvar_map; - std::map val_range_map; + obj_map val_range_map; // This can't be an expr_ref_vector because the constructor is wrong, // we would need to modify the allocator so we pass in ast_manager // TBD: need to replace by obj_map for determinism std::map, ptr_vector > > unroll_tries_map; - std::map unroll_var_map; + obj_map unroll_var_map; // TBD: need to replace by obj_pair_map for determinism std::map, expr*> concat_eq_unroll_ast_map; @@ -323,7 +322,7 @@ protected: std::map, expr*> regex_in_bool_map; // TBD: need to replace by obj_map for determinism std::map > regex_in_var_reg_str_map; - std::map regex_nfa_cache; // Regex term --> NFA + obj_map regex_nfa_cache; // Regex term --> NFA svector char_set; std::map charSetLookupTable; From 72f8e408fc39afca1f5c690b20fd86e3518ac687 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Mar 2018 11:25:07 -0700 Subject: [PATCH 0655/1283] fix #1538 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context_pp.cpp | 6 +++--- src/smt/theory_seq.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index f072a1d13..f4f56df5d 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(out, l2); + display_literal_verbose(out, l2); break; } case b_justification::CLAUSE: { clause * cls = j.get_clause(); out << "clause "; - if (cls) display_literals(out, cls->get_num_literals(), cls->begin_literals()); + if (cls) display_literals_verbose(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(out, lits); + display_literals_verbose(out, lits); break; } default: diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index b90735a07..94841603d 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2404,8 +2404,7 @@ bool theory_seq::add_stoi_val_axiom(expr* e) { lits.push_back(~is_digit(ith_char)); nums.push_back(digit2int(ith_char)); } - for (unsigned i = sz-1, c = 1; i > 0; c *= 10) { - --i; + for (unsigned i = sz, c = 1; i-- > 0; c *= 10) { coeff = m_autil.mk_int(c); nums[i] = m_autil.mk_mul(coeff, nums[i].get()); } @@ -2414,9 +2413,10 @@ bool theory_seq::add_stoi_val_axiom(expr* e) { lits.push_back(mk_eq(e, num, false)); ++m_stats.m_add_axiom; m_new_propagation = true; - for (unsigned i = 0; i < lits.size(); ++i) { - ctx.mark_as_relevant(lits[i]); + for (literal lit : lits) { + ctx.mark_as_relevant(lit); } + TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); m_stoi_axioms.insert(val); m_trail_stack.push(insert_map(m_stoi_axioms, val)); From b572639fcdfc622a7615cea821a945f5499a4f08 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 17 Mar 2018 17:49:33 -0700 Subject: [PATCH 0656/1283] fix #1545 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 27 ++++++++++++++++++++------- src/api/python/z3/z3printer.py | 4 +++- src/smt/smt_quantifier.cpp | 2 +- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index d4ff556fe..36283356d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -114,15 +114,26 @@ def _symbol2py(ctx, s): # Hack for having nary functions that can receive one argument that is the # list of arguments. +# Use this when function takes a single list of arguments def _get_args(args): - try: - if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)): + try: + if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)): return args[0] - elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)): + elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)): return [arg for arg in args[0]] + else: + return args + except: # len is not necessarily defined when args is not a sequence (use reflection?) + return args + +# Use this when function takes multiple arguments +def _get_args_ast_list(args): + try: + if isinstance(args, set) or isinstance(args, AstVector) or isinstance(args, tuple): + return [arg for arg in args] else: return args - except: # len is not necessarily defined when args is not a sequence (use reflection?) + except: return args def _to_param_value(val): @@ -7943,8 +7954,10 @@ def AtLeast(*args): return BoolRef(Z3_mk_atleast(ctx.ref(), sz, _args, k), ctx) -def _pb_args_coeffs(args): - args = _get_args(args) +def _pb_args_coeffs(args, default_ctx = None): + args = _get_args_ast_list(args) + if len(args) == 0: + return _get_ctx(default_ctx), 0, (Ast * 0)(), (ctypes.c_int * 0)() args, coeffs = zip(*args) if __debug__: _z3_assert(len(args) > 0, "Non empty list of arguments expected") @@ -7976,7 +7989,7 @@ def PbGe(args, k): ctx, sz, _args, _coeffs = _pb_args_coeffs(args) return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx) -def PbEq(args, k): +def PbEq(args, k, ctx = None): """Create a Pseudo-Boolean inequality k constraint. >>> a, b, c = Bools('a b c') diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index 3a6b7269e..8fd0c182e 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -36,7 +36,7 @@ _z3_op_to_str = { Z3_OP_CONCAT : 'Concat', Z3_OP_EXTRACT : 'Extract', Z3_OP_BV2INT : 'BV2Int', Z3_OP_ARRAY_MAP : 'Map', Z3_OP_SELECT : 'Select', Z3_OP_STORE : 'Store', Z3_OP_CONST_ARRAY : 'K', Z3_OP_ARRAY_EXT : 'Ext', - Z3_OP_PB_AT_MOST : 'AtMost', Z3_OP_PB_LE : 'PbLe', Z3_OP_PB_GE : 'PbGe' + Z3_OP_PB_AT_MOST : 'AtMost', Z3_OP_PB_LE : 'PbLe', Z3_OP_PB_GE : 'PbGe', Z3_OP_PB_EQ : 'PbEq' } # List of infix operators @@ -930,6 +930,8 @@ class Formatter: return self.pp_pbcmp(a, d, f, xs) elif k == Z3_OP_PB_GE: return self.pp_pbcmp(a, d, f, xs) + elif k == Z3_OP_PB_EQ: + return self.pp_pbcmp(a, d, f, xs) elif z3.is_pattern(a): return self.pp_pattern(a, d, xs) elif self.is_infix(k): diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 0ca244185..1f6811a0f 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -222,7 +222,7 @@ namespace smt { final_check_status final_check_eh(bool full) { if (full) { - IF_VERBOSE(100, verbose_stream() << "(smt.final-check \"quantifiers\")\n";); + IF_VERBOSE(100, if (!m_quantifiers.empty()) verbose_stream() << "(smt.final-check \"quantifiers\")\n";); final_check_status result = m_qi_queue.final_check_eh() ? FC_DONE : FC_CONTINUE; final_check_status presult = m_plugin->final_check_eh(full); if (presult != FC_DONE) From a7e0f18482e69a2eb8c78e91f6f59f1c40310800 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Mar 2018 16:53:04 -0700 Subject: [PATCH 0657/1283] vsts cmd Signed-off-by: Nikolaj Bjorner --- vsts.cmd | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 vsts.cmd diff --git a/vsts.cmd b/vsts.cmd new file mode 100644 index 000000000..7dbd84cd1 --- /dev/null +++ b/vsts.cmd @@ -0,0 +1,5 @@ +md build +cd build +set +cmake -G "NMake Makefiles" ../ +nmake From b82214ef0de966bd919ef1d58ba461dfa50a1953 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Mar 2018 16:59:41 -0700 Subject: [PATCH 0658/1283] try paths to vsvars Signed-off-by: Nikolaj Bjorner --- vsts.cmd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vsts.cmd b/vsts.cmd index 7dbd84cd1..8d715f6a0 100644 --- a/vsts.cmd +++ b/vsts.cmd @@ -1,5 +1,7 @@ md build cd build set +"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" +%VS140COMNTOOLS%\vcvars64.bat cmake -G "NMake Makefiles" ../ nmake From 785b7f3e6a3f3e2a05421d68cc2b75f6a88004d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Mar 2018 17:03:06 -0700 Subject: [PATCH 0659/1283] vsts cmd Signed-off-by: Nikolaj Bjorner --- vsts.cmd | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vsts.cmd b/vsts.cmd index 8d715f6a0..8ef516423 100644 --- a/vsts.cmd +++ b/vsts.cmd @@ -1,7 +1,6 @@ md build cd build set -"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" -%VS140COMNTOOLS%\vcvars64.bat +call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cmake -G "NMake Makefiles" ../ nmake From afb12fe6c352867da96d3993ef12df1fec27e599 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Mar 2018 17:22:58 -0700 Subject: [PATCH 0660/1283] move script Signed-off-by: Nikolaj Bjorner --- vsts.cmd => scripts/vsts.cmd | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename vsts.cmd => scripts/vsts.cmd (100%) diff --git a/vsts.cmd b/scripts/vsts.cmd similarity index 100% rename from vsts.cmd rename to scripts/vsts.cmd From a988d015374869c91302b45f43ff01877817d016 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 19 Mar 2018 12:25:44 -0400 Subject: [PATCH 0661/1283] add const to iterator loops where it can be used --- src/smt/theory_str.cpp | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 144ddb9c9..a985ca678 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -800,25 +800,25 @@ namespace smt { context & ctx = get_context(); while (can_propagate()) { TRACE("str", tout << "propagating..." << std::endl;); - for (auto el : m_basicstr_axiom_todo) { + for (auto const& el : m_basicstr_axiom_todo) { instantiate_basic_string_axioms(el); } m_basicstr_axiom_todo.reset(); TRACE("str", tout << "reset m_basicstr_axiom_todo" << std::endl;); - for (auto pair : m_str_eq_todo) { + for (auto const& pair : m_str_eq_todo) { enode * lhs = pair.first; enode * rhs = pair.second; handle_equality(lhs->get_owner(), rhs->get_owner()); } m_str_eq_todo.reset(); - for (auto el : m_concat_axiom_todo) { + for (auto const& el : m_concat_axiom_todo) { instantiate_concat_axiom(el); } m_concat_axiom_todo.reset(); - for (auto el : m_concat_eval_todo) { + for (auto const& el : m_concat_eval_todo) { try_eval_concat(el); } m_concat_eval_todo.reset(); @@ -4977,8 +4977,7 @@ namespace smt { expr_ref_vector constList(m); bool counterEgFound = false; get_const_str_asts_in_node(aConcat, constList); - //for (expr_ref_vector::iterator cstItor = constList.begin(); cstItor != constList.end(); cstItor++) { - for (auto cst : constList) { + for (auto const& cst : constList) { zstring pieceStr; u.str.is_string(cst, pieceStr); if (!strConst.contains(pieceStr)) { @@ -5118,11 +5117,7 @@ namespace smt { ast_manager & m = get_manager(); if (in_contain_idx_map(n1) && in_contain_idx_map(n2)) { - //std::set >::iterator keysItor1 = contain_pair_idx_map[n1].begin(); - //std::set >::iterator keysItor2; - - //for (; keysItor1 != contain_pair_idx_map[n1].end(); keysItor1++) { - for (auto key1 : contain_pair_idx_map[n1]) { + for (auto const& key1 : contain_pair_idx_map[n1]) { // keysItor1 is on set {<.., n1>, ..., , ...} //std::pair key1 = *keysItor1; if (key1.first == n1 && key1.second == n2) { @@ -5137,7 +5132,7 @@ namespace smt { } //for (keysItor2 = contain_pair_idx_map[n2].begin(); keysItor2 != contain_pair_idx_map[n2].end(); keysItor2++) { - for (auto key2 : contain_pair_idx_map[n2]) { + for (auto const& key2 : contain_pair_idx_map[n2]) { // keysItor2 is on set {<.., n2>, ..., , ...} //std::pair key2 = *keysItor2; // skip if the pair is eq @@ -5385,8 +5380,8 @@ namespace smt { // * key1.second = key2.second // check eqc(key1.first) and eqc(key2.first) // ----------------------------------------------------------- - for (auto eqStrVar1 : str1Eqc) { - for (auto eqStrVar2 : str2Eqc) { + for (auto const& eqStrVar1 : str1Eqc) { + for (auto const& eqStrVar2 : str2Eqc) { { expr_ref_vector litems3(m); if (n1 != n2) { @@ -6944,7 +6939,7 @@ namespace smt { } // now create a fake length tester over this finite disjunction of lengths - fvar_len_count_map[v] = 1; + fvar_len_count_map.insert(v, 1); unsigned int testNum = fvar_len_count_map[v]; expr_ref indicator(mk_internal_lenTest_var(v, testNum), m); From 8602c52bc93045133880ee547cba344223949665 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 10:41:42 -0700 Subject: [PATCH 0662/1283] fix test build Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 3 +++ src/test/sat_local_search.cpp | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index 8ef516423..6f15e1bc3 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -4,3 +4,6 @@ set call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cmake -G "NMake Makefiles" ../ nmake +nmake test-z3 +git pull https://github.com/z3prover/z3test z3test +cd z3test diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index fc1445e34..c9e3a18ec 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -92,16 +92,12 @@ void tst_sat_local_search(char ** argv, int argc, int& i) { switch (argv[i + 1][1]) { case 's': // seed v = atoi(argv[i + 2]); - local_search.config().set_seed(v); + local_search.config().set_random_seed(v); break; case 't': // cutoff_time v = atoi(argv[i + 2]); cutoff_time = v; break; - case 'i': // strategy_id - v = atoi(argv[i + 2]); - local_search.config().set_strategy_id(v); - break; case 'b': // best_known_value v = atoi(argv[i + 2]); local_search.config().set_best_known_value(v); From a873cc41bfa56109a8280fcbcec30342f57a4567 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 10:43:59 -0700 Subject: [PATCH 0663/1283] update vsts script Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index 6f15e1bc3..09480038a 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -1,9 +1,15 @@ +rem Build md build cd build -set call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cmake -G "NMake Makefiles" ../ nmake + +rem Run unit tests nmake test-z3 +test-z3.exe -a + +cd .. +rem Run regression tests git pull https://github.com/z3prover/z3test z3test cd z3test From 7a64c82d994ec9788745d297a3893df481dc0916 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 11:15:49 -0700 Subject: [PATCH 0664/1283] comment out pull Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index 09480038a..4f0b3a9b5 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -11,5 +11,5 @@ test-z3.exe -a cd .. rem Run regression tests -git pull https://github.com/z3prover/z3test z3test -cd z3test +rem git pull https://github.com/z3prover/z3test z3test +rem cd z3test From 7ded2a90e6271758804422f417138fb42292d993 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 11:55:18 -0700 Subject: [PATCH 0665/1283] remove unreachable from vector Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 15 +++++++++++++-- src/util/vector.h | 1 - 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index 4f0b3a9b5..0257fd929 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -2,13 +2,24 @@ rem Build md build cd build call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" -cmake -G "NMake Makefiles" ../ +cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ nmake -rem Run unit tests +rem test python bindings +pushd python +python z3test.py z3 +python z3test.py z3num +popd + +rem Build and run examples + + + +rem Build and run unit tests nmake test-z3 test-z3.exe -a + cd .. rem Run regression tests rem git pull https://github.com/z3prover/z3test z3test diff --git a/src/util/vector.h b/src/util/vector.h index d2beacfb4..bdde50f83 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -73,7 +73,6 @@ class vector { SZ new_capacity = (3 * old_capacity + 1) >> 1; SZ new_capacity_T = sizeof(T) * new_capacity + sizeof(SZ) * 2; if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) { - UNREACHABLE(); throw default_exception("Overflow encountered when expanding vector"); } SZ *mem, *old_mem = reinterpret_cast(m_data) - 2; From ebc6ec2eb5348b438b154f531791e8cab5deeb07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 13:33:58 -0700 Subject: [PATCH 0666/1283] fix #1547 by rewriting legacy recognizers to SMT-LIB2.6 style recognizers which are assumed by theory_datatype Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.cpp | 4 ++++ src/ast/datatype_decl_plugin.h | 1 + src/ast/rewriter/datatype_rewriter.cpp | 3 +++ src/interp/iz3interp.cpp | 12 ++++++------ src/interp/iz3translate.cpp | 4 ++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 44f824959..f685c70d5 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -821,6 +821,10 @@ namespace datatype { return d; } + app* util::mk_is(func_decl * c, expr *f) { + return m.mk_app(get_constructor_is(c), 1, &f); + } + func_decl * util::get_recognizer_constructor(func_decl * recognizer) const { SASSERT(is_recognizer(recognizer)); return to_func_decl(recognizer->get_parameter(0).get_ast()); diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index e644ccbda..f32e9990d 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -362,6 +362,7 @@ namespace datatype { bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); } bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } + app* mk_is(func_decl * c, expr *f); ptr_vector const * get_datatype_constructors(sort * ty); unsigned get_datatype_num_constructors(sort * ty); unsigned get_datatype_num_parameter_sorts(sort * ty); diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index f0a95929b..194668b9c 100644 --- a/src/ast/rewriter/datatype_rewriter.cpp +++ b/src/ast/rewriter/datatype_rewriter.cpp @@ -23,6 +23,9 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr switch(f->get_decl_kind()) { case OP_DT_CONSTRUCTOR: return BR_FAILED; case OP_DT_RECOGNISER: + SASSERT(num_args == 1); + result = m_util.mk_is(m_util.get_recognizer_constructor(f), args[0]); + return BR_REWRITE1; case OP_DT_IS: // // simplify is_cons(cons(x,y)) -> true diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp index 3d1d84f3c..41c968bd8 100644 --- a/src/interp/iz3interp.cpp +++ b/src/interp/iz3interp.cpp @@ -255,12 +255,12 @@ public: catch (const char *msg) { throw interpolation_failure(msg); } - catch (const iz3translation::unsupported &) { - TRACE("iz3", tout << "unsupported\n";); + catch (const iz3translation::unsupported & ex) { + TRACE("iz3", tout << "unsupported " << "\n";); throw interpolation_error(); } - catch (const iz3proof::proof_error &) { - TRACE("iz3", tout << "proof error\n";); + catch (const iz3proof::proof_error & ex) { + TRACE("iz3", tout << "proof error " << "\n";); throw interpolation_error(); } profiling::timer_stop("Proof translation"); @@ -306,8 +306,8 @@ public: catch (const char *msg) { throw interpolation_failure(msg); } - catch (const iz3translation::unsupported &) { - TRACE("iz3", tout << "unsupported\n";); + catch (const iz3translation::unsupported & ex) { + TRACE("iz3", tout << "unsupported " << "\n";); throw interpolation_error(); } catch (const iz3proof::proof_error &) { diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index 9680ec95e..44bac0643 100644 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -2029,8 +2029,8 @@ public: case PR_IFF_FALSE: { // turns ~p into p <-> false, noop for us if(is_local(con)) res = args[0]; - else - throw_unsupported(con); + else + throw_unsupported(proof); break; } case PR_COMMUTATIVITY: { From 84c30e0b60e795c212bdafa41c18d1609112fb32 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 19 Mar 2018 17:03:01 -0400 Subject: [PATCH 0667/1283] theory_str fixups for new collections --- src/smt/theory_str.cpp | 85 ++++++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 23 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index a985ca678..ec7406d8a 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -967,6 +967,15 @@ namespace smt { TRACE("str", tout << "set up basic string axioms on " << mk_pp(str->get_owner(), m) << std::endl;); + { + sort * a_sort = m.get_sort(str->get_owner()); + sort * str_sort = u.str.mk_string_sort(); + if (a_sort != str_sort) { + TRACE("str", tout << "WARNING: not setting up string axioms on non-string term " << mk_pp(str->get_owner(), m) << std::endl;); + return; + } + } + // TESTING: attempt to avoid a crash here when a variable goes out of scope if (str->get_iscope_lvl() > ctx.get_scope_level()) { TRACE("str", tout << "WARNING: skipping axiom setup on out-of-scope string term" << std::endl;); @@ -975,6 +984,7 @@ namespace smt { // generate a stronger axiom for constant strings app * a_str = str->get_owner(); + if (u.str.is_string(a_str)) { expr_ref len_str(m); len_str = mk_strlen(a_str); @@ -1202,6 +1212,12 @@ namespace smt { contains_map.push_back(ex); std::pair key = std::pair(str, substr); contain_pair_bool_map.insert(str, substr, ex); + if (!contain_pair_idx_map.contains(str)) { + contain_pair_idx_map.insert(str, std::set>()); + } + if (!contain_pair_idx_map.contains(substr)) { + contain_pair_idx_map.insert(substr, std::set>()); + } contain_pair_idx_map[str].insert(key); contain_pair_idx_map[substr].insert(key); } @@ -5824,11 +5840,10 @@ namespace smt { std::map & concatAliasMap, std::map & varConstMap, std::map & concatConstMap, std::map > & varEqConcatMap) { std::map, std::set > > groundedMap; - theory_str_contain_pair_bool_map_t::iterator containItor = contain_pair_bool_map.begin(); - for (; containItor != contain_pair_bool_map.end(); containItor++) { - expr* containBoolVar = containItor->get_value(); - expr* str = containItor->get_key1(); - expr* subStr = containItor->get_key2(); + for (auto const& kv : contain_pair_bool_map) { + expr* containBoolVar = kv.get_value(); + expr* str = kv.get_key1(); + expr* subStr = kv.get_key2(); expr* strDeAlias = dealias_node(str, varAliasMap, concatAliasMap); expr* subStrDeAlias = dealias_node(subStr, varAliasMap, concatAliasMap); @@ -6889,12 +6904,14 @@ namespace smt { if (!map_effectively_empty) { map_effectively_empty = true; - ptr_vector indicator_set = fvar_lenTester_map[v]; - for (ptr_vector::iterator it = indicator_set.begin(); it != indicator_set.end(); ++it) { - expr * indicator = *it; - if (internal_variable_set.find(indicator) != internal_variable_set.end()) { - map_effectively_empty = false; - break; + if (fvar_lenTester_map.contains(v)) { + ptr_vector indicator_set = fvar_lenTester_map[v]; + for (ptr_vector::iterator it = indicator_set.begin(); it != indicator_set.end(); ++it) { + expr * indicator = *it; + if (internal_variable_set.find(indicator) != internal_variable_set.end()) { + map_effectively_empty = false; + break; + } } } } @@ -6946,9 +6963,12 @@ namespace smt { SASSERT(indicator); m_trail.push_back(indicator); + if (!fvar_lenTester_map.contains(v)) { + fvar_lenTester_map.insert(v, ptr_vector()); + } fvar_lenTester_map[v].shrink(0); fvar_lenTester_map[v].push_back(indicator); - lenTester_fvar_map[indicator] = v; + lenTester_fvar_map.insert(indicator, v); expr_ref_vector orList(m); expr_ref_vector andList(m); @@ -7015,7 +7035,12 @@ namespace smt { } } } else { - int lenTesterCount = fvar_lenTester_map[fVar].size(); + int lenTesterCount; + if (fvar_lenTester_map.contains(fVar)) { + lenTesterCount = fvar_lenTester_map[fVar].size(); + } else { + lenTesterCount = 0; + } expr * effectiveLenInd = nullptr; zstring effectiveLenIndiStr = ""; @@ -9336,7 +9361,8 @@ namespace smt { // check whether any value tester is actually in scope TRACE("str", tout << "checking scope of previous value testers" << std::endl;); bool map_effectively_empty = true; - if (fvar_valueTester_map[freeVar].find(len) != fvar_valueTester_map[freeVar].end()) { + if (fvar_valueTester_map.contains(freeVar) && + fvar_valueTester_map[freeVar].find(len) != fvar_valueTester_map[freeVar].end()) { // there's *something* in the map, but check its scope svector > entries = fvar_valueTester_map[freeVar][len]; for (svector >::iterator it = entries.begin(); it != entries.end(); ++it) { @@ -9357,6 +9383,9 @@ namespace smt { int tries = 0; expr * val_indicator = mk_internal_valTest_var(freeVar, len, tries); valueTester_fvar_map.insert(val_indicator, freeVar); + if (!fvar_valueTester_map.contains(freeVar)) { + fvar_valueTester_map.insert(freeVar, std::map > >()); + } fvar_valueTester_map[freeVar][len].push_back(std::make_pair(sLevel, val_indicator)); print_value_tester_list(fvar_valueTester_map[freeVar][len]); return gen_val_options(freeVar, len_indicator, val_indicator, len_valueStr, tries); @@ -10240,14 +10269,16 @@ namespace smt { // assume empty and find a counterexample map_effectively_empty = true; - ptr_vector indicator_set = fvar_lenTester_map[freeVar]; - for (ptr_vector::iterator it = indicator_set.begin(); it != indicator_set.end(); ++it) { - expr * indicator = *it; - if (internal_variable_set.find(indicator) != internal_variable_set.end()) { - TRACE("str", tout <<"found active internal variable " << mk_ismt2_pp(indicator, m) - << " in fvar_lenTester_map[freeVar]" << std::endl;); - map_effectively_empty = false; - break; + if (fvar_lenTester_map.contains(freeVar)) { + ptr_vector indicator_set = fvar_lenTester_map[freeVar]; + for (ptr_vector::iterator it = indicator_set.begin(); it != indicator_set.end(); ++it) { + expr * indicator = *it; + if (internal_variable_set.find(indicator) != internal_variable_set.end()) { + TRACE("str", tout <<"found active internal variable " << mk_ismt2_pp(indicator, m) + << " in fvar_lenTester_map[freeVar]" << std::endl;); + map_effectively_empty = false; + break; + } } } CTRACE("str", map_effectively_empty, tout << "all variables in fvar_lenTester_map[freeVar] out of scope" << std::endl;); @@ -10264,6 +10295,9 @@ namespace smt { SASSERT(indicator); // since the map is "effectively empty", we can remove those variables that have left scope... + if (!fvar_lenTester_map.contains(freeVar)) { + fvar_lenTester_map.insert(freeVar, ptr_vector()); + } fvar_lenTester_map[freeVar].shrink(0); fvar_lenTester_map[freeVar].push_back(indicator); lenTester_fvar_map.insert(indicator, freeVar); @@ -10276,7 +10310,12 @@ namespace smt { expr * effectiveLenInd = nullptr; zstring effectiveLenIndiStr(""); - int lenTesterCount = (int) fvar_lenTester_map[freeVar].size(); + int lenTesterCount; + if (fvar_lenTester_map.contains(freeVar)) { + lenTesterCount = fvar_lenTester_map[freeVar].size(); + } else { + lenTesterCount = 0; + } TRACE("str", tout << lenTesterCount << " length testers in fvar_lenTester_map[" << mk_pp(freeVar, m) << "]:" << std::endl; From ba2e28fa0e9766b02a4840888ee1d57298c45ce2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 14:55:38 -0700 Subject: [PATCH 0668/1283] update build script Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index 0257fd929..639e2f82d 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -17,7 +17,7 @@ rem Build and run examples rem Build and run unit tests nmake test-z3 -test-z3.exe -a +rem test-z3.exe -a cd .. From 5c692dc79dccb1866e5c2a402128ffe33ec14c7e Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 19 Mar 2018 18:06:42 -0400 Subject: [PATCH 0669/1283] fixups to theory_str indexof and axiom handling loop --- src/smt/theory_str.cpp | 190 ++++++++++++++++++++++++----------------- 1 file changed, 110 insertions(+), 80 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index ec7406d8a..534acf785 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -638,6 +638,7 @@ namespace smt { return contains; } + // note, this invokes "special-case" handling for the start index being 0 app * theory_str::mk_indexof(expr * haystack, expr * needle) { app * indexof = u.str.mk_index(haystack, needle, mk_int(0)); m_trail.push_back(indexof); @@ -823,31 +824,49 @@ namespace smt { } m_concat_eval_todo.reset(); - for (enode * e : m_library_aware_axiom_todo) { - app * a = e->get_owner(); - if (u.str.is_stoi(a)) { - instantiate_axiom_str_to_int(e); - } else if (u.str.is_itos(a)) { - instantiate_axiom_int_to_str(e); - } else if (u.str.is_at(a)) { - instantiate_axiom_CharAt(e); - } else if (u.str.is_prefix(a)) { - instantiate_axiom_prefixof(e); - } else if (u.str.is_suffix(a)) { - instantiate_axiom_suffixof(e); - } else if (u.str.is_contains(a)) { - instantiate_axiom_Contains(e); - } else if (u.str.is_index(a)) { - instantiate_axiom_Indexof(e); - } else if (u.str.is_extract(a)) { - instantiate_axiom_Substr(e); - } else if (u.str.is_replace(a)) { - instantiate_axiom_Replace(e); - } else if (u.str.is_in_re(a)) { - instantiate_axiom_RegexIn(e); + while(true) { + // Special handling: terms can recursively set up other terms + // (e.g. indexof can instantiate other indexof terms). + // - Copy the list so it can potentially be modified during setup. + // - Don't clear this list if new ones are added in the process; + // instead, set up all the new terms before proceeding. + // TODO see if any other propagate() worklists need this kind of handling + // TODO we really only need to check the new ones on each pass + unsigned start_count = m_library_aware_axiom_todo.size(); + ptr_vector axioms_tmp(m_library_aware_axiom_todo); + for (auto const& e : axioms_tmp) { + app * a = e->get_owner(); + if (u.str.is_stoi(a)) { + instantiate_axiom_str_to_int(e); + } else if (u.str.is_itos(a)) { + instantiate_axiom_int_to_str(e); + } else if (u.str.is_at(a)) { + instantiate_axiom_CharAt(e); + } else if (u.str.is_prefix(a)) { + instantiate_axiom_prefixof(e); + } else if (u.str.is_suffix(a)) { + instantiate_axiom_suffixof(e); + } else if (u.str.is_contains(a)) { + instantiate_axiom_Contains(e); + } else if (u.str.is_index(a)) { + instantiate_axiom_Indexof(e); + } else if (u.str.is_extract(a)) { + instantiate_axiom_Substr(e); + } else if (u.str.is_replace(a)) { + instantiate_axiom_Replace(e); + } else if (u.str.is_in_re(a)) { + instantiate_axiom_RegexIn(e); + } else { + TRACE("str", tout << "BUG: unhandled library-aware term " << mk_pp(e->get_owner(), get_manager()) << std::endl;); + NOT_IMPLEMENTED_YET(); + } + } + unsigned end_count = m_library_aware_axiom_todo.size(); + if (end_count > start_count) { + TRACE("str", tout << "new library-aware terms added during axiom setup -- checking again" << std::endl;); + continue; } else { - TRACE("str", tout << "BUG: unhandled library-aware term " << mk_pp(e->get_owner(), get_manager()) << std::endl;); - NOT_IMPLEMENTED_YET(); + break; } } m_library_aware_axiom_todo.reset(); @@ -1313,74 +1332,85 @@ namespace smt { } } - void theory_str::instantiate_axiom_Indexof_extended(enode * e) { + void theory_str::instantiate_axiom_Indexof_extended(enode * _e) { context & ctx = get_context(); ast_manager & m = get_manager(); - app * expr = e->get_owner(); - if (axiomatized_terms.contains(expr)) { - TRACE("str", tout << "already set up extended str.indexof axiom for " << mk_pp(expr, m) << std::endl;); + app * e = _e->get_owner(); + if (axiomatized_terms.contains(e)) { + TRACE("str", tout << "already set up extended str.indexof axiom for " << mk_pp(e, m) << std::endl;); return; } - SASSERT(expr->get_num_args() == 3); - axiomatized_terms.insert(expr); + SASSERT(e->get_num_args() == 3); + axiomatized_terms.insert(e); - TRACE("str", tout << "instantiate extended str.indexof axiom for " << mk_pp(expr, m) << std::endl;); + TRACE("str", tout << "instantiate extended str.indexof axiom for " << mk_pp(e, m) << std::endl;); - // ------------------------------------------------------------------------------- - // if (arg[2] >= length(arg[0])) // ite2 - // resAst = -1 - // else - // args[0] = prefix . suffix - // /\ indexAst = indexof(suffix, arg[1]) - // /\ args[2] = len(prefix) - // /\ if (indexAst == -1) resAst = indexAst // ite3 - // else resAst = args[2] + indexAst - // ------------------------------------------------------------------------------- + // str.indexof(H, N, i): + // i < 0 --> -1 + // i == 0 --> str.indexof(H, N, 0) + // i >= len(H) --> -1 + // 0 < i < len(H) --> + // H = hd ++ tl + // len(hd) = i + // str.indexof(tl, N, 0) - expr_ref resAst(mk_int_var("res"), m); - expr_ref indexAst(mk_int_var("index"), m); - expr_ref prefix(mk_str_var("prefix"), m); - expr_ref suffix(mk_str_var("suffix"), m); - expr_ref prefixLen(mk_strlen(prefix), m); - expr_ref zeroAst(mk_int(0), m); - expr_ref negOneAst(mk_int(-1), m); + expr * H; // "haystack" + expr * N; // "needle" + expr * i; // start index + u.str.is_index(e, H, N, i); - expr_ref ite3(m.mk_ite( - ctx.mk_eq_atom(indexAst, negOneAst), - ctx.mk_eq_atom(resAst, negOneAst), - ctx.mk_eq_atom(resAst, m_autil.mk_add(expr->get_arg(2), indexAst)) - ),m); + expr_ref minus_one(m_autil.mk_numeral(rational::minus_one(), true), m); + expr_ref zero(m_autil.mk_numeral(rational::zero(), true), m); - expr_ref_vector ite2ElseItems(m); - ite2ElseItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(prefix, suffix))); - ite2ElseItems.push_back(ctx.mk_eq_atom(indexAst, mk_indexof(suffix, expr->get_arg(1)))); - ite2ElseItems.push_back(ctx.mk_eq_atom(expr->get_arg(2), prefixLen)); - ite2ElseItems.push_back(ite3); - expr_ref ite2Else(mk_and(ite2ElseItems), m); - SASSERT(ite2Else); + // case split - expr_ref ite2(m.mk_ite( - //m_autil.mk_ge(expr->get_arg(2), mk_strlen(expr->get_arg(0))), - m_autil.mk_ge(m_autil.mk_add(expr->get_arg(2), m_autil.mk_mul(mk_int(-1), mk_strlen(expr->get_arg(0)))), zeroAst), - ctx.mk_eq_atom(resAst, negOneAst), - ite2Else - ), m); - SASSERT(ite2); + // case 1: i < 0 + { + expr_ref premise(m_autil.mk_le(i, minus_one), m); + expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m); + assert_implication(premise, conclusion); + } - expr_ref ite1(m.mk_ite( - //m_autil.mk_lt(expr->get_arg(2), zeroAst), - mk_not(m, m_autil.mk_ge(expr->get_arg(2), zeroAst)), - ctx.mk_eq_atom(resAst, mk_indexof(expr->get_arg(0), expr->get_arg(1))), - ite2 - ), m); - SASSERT(ite1); - assert_axiom(ite1); + // case 2: i = 0 + { + expr_ref premise(ctx.mk_eq_atom(i, zero), m); + // reduction to simpler case + expr_ref conclusion(ctx.mk_eq_atom(e, mk_indexof(H, N)), m); + assert_implication(premise, conclusion); + } + // case 3: i >= len(H) + { + //expr_ref _premise(m_autil.mk_ge(i, mk_strlen(H)), m); + //expr_ref premise(_premise); + //th_rewriter rw(m); + //rw(premise); + expr_ref premise(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero), m); + expr_ref conclusion(ctx.mk_eq_atom(e, minus_one), m); + assert_implication(premise, conclusion); + } + // case 4: 0 < i < len(H) + { + expr_ref premise1(m_autil.mk_gt(i, zero), m); + expr_ref premise2(m_autil.mk_lt(i, mk_strlen(H)), m); + expr_ref _premise(m.mk_and(premise1, premise2), m); + expr_ref premise(_premise); + th_rewriter rw(m); + rw(premise); - expr_ref reduceTerm(ctx.mk_eq_atom(expr, resAst), m); - SASSERT(reduceTerm); - assert_axiom(reduceTerm); + expr_ref hd(mk_str_var("hd"), m); + expr_ref tl(mk_str_var("tl"), m); + expr_ref_vector conclusion_terms(m); + conclusion_terms.push_back(ctx.mk_eq_atom(H, mk_concat(hd, tl))); + conclusion_terms.push_back(ctx.mk_eq_atom(mk_strlen(hd), i)); + conclusion_terms.push_back(ctx.mk_eq_atom(e, mk_indexof(tl, N))); + + expr_ref conclusion(mk_and(conclusion_terms), m); + assert_implication(premise, conclusion); + } + + /* { // heuristic: integrate with str.contains information // (but don't introduce it if it isn't already in the instance) @@ -1394,6 +1424,7 @@ namespace smt { // we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent m_delayed_axiom_setup_terms.push_back(containsAxiom); } + */ } void theory_str::instantiate_axiom_LastIndexof(enode * e) { @@ -7411,8 +7442,7 @@ namespace smt { if (is_app(ex)) { app * ap = to_app(ex); - // TODO indexof2/lastindexof - if (u.str.is_index(ap) /* || is_Indexof2(ap) || is_LastIndexof(ap) */) { + if (u.str.is_index(ap)) { m_library_aware_axiom_todo.push_back(n); } else if (u.str.is_stoi(ap)) { TRACE("str", tout << "found string-integer conversion term: " << mk_pp(ex, get_manager()) << std::endl;); From 1f4bfcb4e5a6dee0e4e5df70f288c6b9a44fd3a1 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 19 Mar 2018 18:10:06 -0400 Subject: [PATCH 0670/1283] fix indexof subterm --- src/smt/theory_str.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 534acf785..16fd28d79 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1392,7 +1392,8 @@ namespace smt { // case 4: 0 < i < len(H) { expr_ref premise1(m_autil.mk_gt(i, zero), m); - expr_ref premise2(m_autil.mk_lt(i, mk_strlen(H)), m); + //expr_ref premise2(m_autil.mk_lt(i, mk_strlen(H)), m); + expr_ref premise2(m.mk_not(m_autil.mk_ge(m_autil.mk_add(i, m_autil.mk_mul(minus_one, mk_strlen(H))), zero)), m); expr_ref _premise(m.mk_and(premise1, premise2), m); expr_ref premise(_premise); th_rewriter rw(m); From d26eddf77671dfefb4832c7455077a191751736d Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 19 Mar 2018 18:31:26 -0400 Subject: [PATCH 0671/1283] re-add indexof-contains heuristic --- src/smt/theory_str.cpp | 23 +++++++++++++++-------- src/smt/theory_str.h | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 16fd28d79..ec554df7b 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -50,6 +50,7 @@ namespace smt { m_factory(nullptr), m_unused_id(0), m_delayed_axiom_setup_terms(m), + m_delayed_assertions_todo(m), tmpStringVarCount(0), tmpXorVarCount(0), tmpLenTestVarCount(0), @@ -793,7 +794,8 @@ namespace smt { return !m_basicstr_axiom_todo.empty() || !m_str_eq_todo.empty() || !m_concat_axiom_todo.empty() || !m_concat_eval_todo.empty() || !m_library_aware_axiom_todo.empty() - || !m_delayed_axiom_setup_terms.empty(); + || !m_delayed_axiom_setup_terms.empty() + || (search_started && !m_delayed_assertions_todo.empty()) ; } @@ -877,6 +879,13 @@ namespace smt { set_up_axioms(el); } m_delayed_axiom_setup_terms.reset(); + + if (search_started) { + for (auto const& el : m_delayed_assertions_todo) { + assert_axiom(el); + } + m_delayed_assertions_todo.reset(); + } } } @@ -1327,8 +1336,9 @@ namespace smt { expr_ref conclusion(m_autil.mk_ge(ex, zeroAst), m); expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m); SASSERT(containsAxiom); + // we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent - m_delayed_axiom_setup_terms.push_back(containsAxiom); + //m_delayed_axiom_setup_terms.push_back(containsAxiom); } } @@ -1411,21 +1421,18 @@ namespace smt { assert_implication(premise, conclusion); } - /* { // heuristic: integrate with str.contains information // (but don't introduce it if it isn't already in the instance) - expr_ref haystack(expr->get_arg(0), m), needle(expr->get_arg(1), m), startIdx(expr->get_arg(2), m); // (H contains N) <==> (H indexof N, i) >= 0 - expr_ref premise(u.str.mk_contains(haystack, needle), m); + expr_ref premise(u.str.mk_contains(H, N), m); ctx.internalize(premise, false); - expr_ref conclusion(m_autil.mk_ge(expr, zeroAst), m); + expr_ref conclusion(m_autil.mk_ge(e, zero), m); expr_ref containsAxiom(ctx.mk_eq_atom(premise, conclusion), m); SASSERT(containsAxiom); // we can't assert this during init_search as it breaks an invariant if the instance becomes inconsistent - m_delayed_axiom_setup_terms.push_back(containsAxiom); + m_delayed_assertions_todo.push_back(containsAxiom); } - */ } void theory_str::instantiate_axiom_LastIndexof(enode * e) { diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index cd491ac55..5378b05f3 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -262,6 +262,7 @@ protected: ptr_vector m_concat_axiom_todo; ptr_vector m_string_constant_length_todo; ptr_vector m_concat_eval_todo; + expr_ref_vector m_delayed_assertions_todo; // enode lists for library-aware/high-level string terms (e.g. substr, contains) ptr_vector m_library_aware_axiom_todo; From 95980454359a7e2c8da1659fa3180e03f4259294 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 15:49:28 -0700 Subject: [PATCH 0672/1283] fix java Signed-off-by: Nikolaj Bjorner --- src/api/java/InterpolationContext.java | 49 ++++++++++++++------------ 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 99a63821f..b285fe654 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -176,30 +176,35 @@ public class InterpolationContext extends Context /// Remarks: For more information on interpolation please refer /// too the function Z3_read_interpolation_problem in the C/C++ API, which is /// well documented. - public ReadInterpolationProblemResult ReadInterpolationProblem(String filename, Expr[] cnsts, int[] parents, String error, Expr[] theory) + public ReadInterpolationProblemResult ReadInterpolationProblem(String filename) { ReadInterpolationProblemResult res = new ReadInterpolationProblemResult(); - - Native.IntPtr n_num = new Native.IntPtr(); - Native.IntPtr n_num_theory = new Native.IntPtr(); - Native.ObjArrayPtr n_cnsts = new Native.ObjArrayPtr(); - Native.UIntArrayPtr n_parents = new Native.UIntArrayPtr(); - Native.ObjArrayPtr n_theory = new Native.ObjArrayPtr(); - Native.StringPtr n_err_str = new Native.StringPtr(); - res.return_value = Native.readInterpolationProblem(nCtx(), n_num, n_cnsts, n_parents, filename, n_err_str, n_num_theory, n_theory); - int num = n_num.value; - int num_theory = n_num_theory.value; - res.error = n_err_str.value; - res.cnsts = new Expr[num]; - res.parents = new int[num]; - theory = new Expr[num_theory]; - for (int i = 0; i < num; i++) - { - res.cnsts[i] = Expr.create(this, n_cnsts.value[i]); - res.parents[i] = n_parents.value[i]; - } - for (int i = 0; i < num_theory; i++) - res.theory[i] = Expr.create(this, n_theory.value[i]); + + +// TBD: update to AstVector based API + Native.UIntArrayPtr n_parents = new Native.UIntArrayPtr(); + ASTVector _cnsts = new ASTVector(this); + ASTVector _theory = new ASTVector(this); + Native.StringPtr n_err_str = new Native.StringPtr(); + res.return_value = Native.readInterpolationProblem(nCtx(), _cnsts, n_parents, filename, n_err_str, _theory); + +// Native.IntPtr n_num = new Native.IntPtr(); +// Native.IntPtr n_num_theory = new Native.IntPtr(); +// Native.ObjArrayPtr n_cnsts = new Native.ObjArrayPtr(); +// +// int num = n_num.value; +// int num_theory = _theory.n_num_theory.value; + res.error = n_err_str.value; +// res.cnsts = new Expr[num]; +// res.parents = new int[num]; +// theory = new Expr[num_theory]; +// for (int i = 0; i < num; i++) +// { +// res.cnsts[i] = Expr.create(this, n_cnsts.value[i]); +// res.parents[i] = n_parents.value[i]; +// } +// for (int i = 0; i < num_theory; i++) +// res.theory[i] = Expr.create(this, n_theory.value[i]); return res; } From ac2fe879ae4321e91d91af2e42c607e3a7e8bd8a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 15:55:00 -0700 Subject: [PATCH 0673/1283] update script Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index 639e2f82d..6e8eba43f 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -1,26 +1,28 @@ -rem Build +echo "Build" md build cd build call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ nmake +rem TBD: test error level -rem test python bindings +echo "Test python bindings" pushd python python z3test.py z3 python z3test.py z3num popd -rem Build and run examples +echo "Build and run examples" -rem Build and run unit tests +echo "Build and run unit tests" nmake test-z3 +rem TBD: test error level rem test-z3.exe -a cd .. -rem Run regression tests +echo "Run regression tests" rem git pull https://github.com/z3prover/z3test z3test rem cd z3test From b002477d1af3e9dba06c9a113730f57555a3769c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 18:10:57 -0700 Subject: [PATCH 0674/1283] fix java API Signed-off-by: Nikolaj Bjorner --- src/api/java/InterpolationContext.java | 45 ++++++++++---------------- 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index b285fe654..bce789807 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -178,34 +178,23 @@ public class InterpolationContext extends Context /// well documented. public ReadInterpolationProblemResult ReadInterpolationProblem(String filename) { - ReadInterpolationProblemResult res = new ReadInterpolationProblemResult(); - - -// TBD: update to AstVector based API - Native.UIntArrayPtr n_parents = new Native.UIntArrayPtr(); - ASTVector _cnsts = new ASTVector(this); - ASTVector _theory = new ASTVector(this); - Native.StringPtr n_err_str = new Native.StringPtr(); - res.return_value = Native.readInterpolationProblem(nCtx(), _cnsts, n_parents, filename, n_err_str, _theory); - -// Native.IntPtr n_num = new Native.IntPtr(); -// Native.IntPtr n_num_theory = new Native.IntPtr(); -// Native.ObjArrayPtr n_cnsts = new Native.ObjArrayPtr(); -// -// int num = n_num.value; -// int num_theory = _theory.n_num_theory.value; - res.error = n_err_str.value; -// res.cnsts = new Expr[num]; -// res.parents = new int[num]; -// theory = new Expr[num_theory]; -// for (int i = 0; i < num; i++) -// { -// res.cnsts[i] = Expr.create(this, n_cnsts.value[i]); -// res.parents[i] = n_parents.value[i]; -// } -// for (int i = 0; i < num_theory; i++) -// res.theory[i] = Expr.create(this, n_theory.value[i]); - return res; + ReadInterpolationProblemResult res = new ReadInterpolationProblemResult(); + Native.UIntArrayPtr n_parents = new Native.UIntArrayPtr(); + ASTVector _cnsts = new ASTVector(this); + ASTVector _theory = new ASTVector(this); + Native.StringPtr n_err_str = new Native.StringPtr(); + Native.IntPtr n_num = new Native.IntPtr(); + res.return_value = Native.readInterpolationProblem(nCtx(), _cnsts.getNativeObject(), n_num, + n_parents, filename, n_err_str, _theory.getNativeObject()); + res.error = n_err_str.value; + res.theory = _theory.ToExprArray(); + res.cnsts = _cnsts.ToExprArray(); + int num = n_num.value; + res.parents = new int[num]; + for (int i = 0; i < num; i++) { + res.parents[i] = n_parents.value[i]; + } + return res; } /// From b727a3463d78c8beeded87158e33e32d50220953 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 18:21:34 -0700 Subject: [PATCH 0675/1283] update vsts Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index 6e8eba43f..e628e00ba 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -13,7 +13,17 @@ python z3test.py z3num popd echo "Build and run examples" +nmake cpp_example +cpp_example.exe +nmake c_example +c_example.exe + +nmake java_example +java_example.exe + +nmake dotnet_example +dotnet_example.exe echo "Build and run unit tests" @@ -24,5 +34,6 @@ rem test-z3.exe -a cd .. echo "Run regression tests" -rem git pull https://github.com/z3prover/z3test z3test -rem cd z3test +git pull https://github.com/z3prover/z3test z3test +cd z3test + From d5811a13ebbeec6c9842950fa15a970b3b9e6a26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 19:18:05 -0700 Subject: [PATCH 0676/1283] add test-benchmarks Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index e628e00ba..7f457392e 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -34,6 +34,7 @@ rem test-z3.exe -a cd .. echo "Run regression tests" -git pull https://github.com/z3prover/z3test z3test -cd z3test +git clone https://github.com/z3prover/z3test z3test +z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2 + From d5bd7878b331209b631a4fd75252a41f1b0fa672 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 20:03:47 -0700 Subject: [PATCH 0677/1283] fix example test Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index 7f457392e..f597e45ea 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -14,17 +14,16 @@ popd echo "Build and run examples" nmake cpp_example -cpp_example.exe +examples\cpp_example_build_dir\cpp_example.exe nmake c_example -c_example.exe +examples\c_example_build_dir\c_example.exe -nmake java_example -java_example.exe - -nmake dotnet_example -dotnet_example.exe +rem nmake java_example +rem java_example.exe +rem nmake dotnet_example +rem dotnet_example.exe echo "Build and run unit tests" nmake test-z3 From 7759d05efee280bd2360584cab43ec33a1d328ba Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 19 Mar 2018 23:09:07 -0400 Subject: [PATCH 0678/1283] fix use-after-free --- src/smt/theory_str.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index ec554df7b..5a39659e8 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -803,8 +803,20 @@ namespace smt { context & ctx = get_context(); while (can_propagate()) { TRACE("str", tout << "propagating..." << std::endl;); - for (auto const& el : m_basicstr_axiom_todo) { - instantiate_basic_string_axioms(el); + while(true) { + // this can potentially recursively activate itself + unsigned start_count = m_basicstr_axiom_todo.size(); + ptr_vector axioms_tmp(m_basicstr_axiom_todo); + for (auto const& el : axioms_tmp) { + instantiate_basic_string_axioms(el); + } + unsigned end_count = m_basicstr_axiom_todo.size(); + if (end_count > start_count) { + TRACE("str", tout << "new basic string axiom terms added -- checking again" << std::endl;); + continue; + } else { + break; + } } m_basicstr_axiom_todo.reset(); TRACE("str", tout << "reset m_basicstr_axiom_todo" << std::endl;); From dc01266354c38470cce566ba0e962ceda01a89ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 20:50:24 -0700 Subject: [PATCH 0679/1283] fixing after clone Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd index f597e45ea..3b3a60231 100644 --- a/scripts/vsts.cmd +++ b/scripts/vsts.cmd @@ -34,6 +34,7 @@ rem test-z3.exe -a cd .. echo "Run regression tests" git clone https://github.com/z3prover/z3test z3test -z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2 - +echo "test-benchmarks" +python z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2 +echo "benchmarks tested" From eb6bbd390a93b125a70e4b554b83357dca31e05d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 08:33:09 -0700 Subject: [PATCH 0680/1283] vsts script Signed-off-by: Nikolaj Bjorner --- scripts/vsts-vs2017.cmd | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 scripts/vsts-vs2017.cmd diff --git a/scripts/vsts-vs2017.cmd b/scripts/vsts-vs2017.cmd new file mode 100644 index 000000000..3b3a60231 --- /dev/null +++ b/scripts/vsts-vs2017.cmd @@ -0,0 +1,40 @@ +echo "Build" +md build +cd build +call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" +cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ +nmake +rem TBD: test error level + +echo "Test python bindings" +pushd python +python z3test.py z3 +python z3test.py z3num +popd + +echo "Build and run examples" +nmake cpp_example +examples\cpp_example_build_dir\cpp_example.exe + +nmake c_example +examples\c_example_build_dir\c_example.exe + +rem nmake java_example +rem java_example.exe + +rem nmake dotnet_example +rem dotnet_example.exe + +echo "Build and run unit tests" +nmake test-z3 +rem TBD: test error level +rem test-z3.exe -a + + +cd .. +echo "Run regression tests" +git clone https://github.com/z3prover/z3test z3test +echo "test-benchmarks" +python z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2 +echo "benchmarks tested" + From 0d13a2812ee06d2cf3c489e3b40434f5f3e0ec55 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 09:26:39 -0700 Subject: [PATCH 0681/1283] add error checking and command argument Signed-off-by: Nikolaj Bjorner --- scripts/vsts-vs2017.cmd | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts/vsts-vs2017.cmd b/scripts/vsts-vs2017.cmd index 3b3a60231..d4c1e34b4 100644 --- a/scripts/vsts-vs2017.cmd +++ b/scripts/vsts-vs2017.cmd @@ -1,29 +1,37 @@ +rem Supply argument x64 or x86 + echo "Build" md build cd build -call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" +call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars.bat" %1 cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ nmake -rem TBD: test error level +if ERRORLEVEL 1 exit 1 echo "Test python bindings" pushd python python z3test.py z3 +if ERRORLEVEL 1 exit 1 python z3test.py z3num +if ERRORLEVEL 1 exit 1 popd echo "Build and run examples" nmake cpp_example examples\cpp_example_build_dir\cpp_example.exe +if ERRORLEVEL 1 exit 1 nmake c_example examples\c_example_build_dir\c_example.exe +if ERRORLEVEL 1 exit 1 rem nmake java_example rem java_example.exe +if ERRORLEVEL 1 exit 1 rem nmake dotnet_example rem dotnet_example.exe +if ERRORLEVEL 1 exit 1 echo "Build and run unit tests" nmake test-z3 @@ -36,5 +44,6 @@ echo "Run regression tests" git clone https://github.com/z3prover/z3test z3test echo "test-benchmarks" python z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2 +if ERRORLEVEL 1 exit 1 echo "benchmarks tested" From db7844bef733d3f225d90988034f974945983c91 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 09:33:23 -0700 Subject: [PATCH 0682/1283] adding build definition Signed-off-by: Nikolaj Bjorner --- README.md | 6 +++--- scripts/vsts-vs2017.cmd | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 70956d439..899d23385 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z ## Build status -| Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | -| ----------- | ----------- | ---------- | ---------- | --- | -------- | -[![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) +| Windows x64 | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | +| ----------- | ----------- | ----------- | ---------- | ---------- | --- | -------- | +[![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=2) [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang diff --git a/scripts/vsts-vs2017.cmd b/scripts/vsts-vs2017.cmd index d4c1e34b4..fe2f55bca 100644 --- a/scripts/vsts-vs2017.cmd +++ b/scripts/vsts-vs2017.cmd @@ -3,7 +3,7 @@ rem Supply argument x64 or x86 echo "Build" md build cd build -call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars.bat" %1 +call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %1 cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ nmake if ERRORLEVEL 1 exit 1 From d8462807c3bae35368f07f954189e279ca7a3f2a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 09:35:51 -0700 Subject: [PATCH 0683/1283] add missin bar Signed-off-by: Nikolaj Bjorner --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 899d23385..d501c5d5c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z | Windows x64 | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | | ----------- | ----------- | ----------- | ---------- | ---------- | --- | -------- | -[![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=2) [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) +[![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=2) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang From f7dfc39984f2f86ea31e719d2de5a371a08c8777 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 12:20:40 -0700 Subject: [PATCH 0684/1283] add vstsvs2013 outline Signed-off-by: Nikolaj Bjorner --- scripts/vsts-vs2013.cmd | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 scripts/vsts-vs2013.cmd diff --git a/scripts/vsts-vs2013.cmd b/scripts/vsts-vs2013.cmd new file mode 100644 index 000000000..baf9f4bb4 --- /dev/null +++ b/scripts/vsts-vs2013.cmd @@ -0,0 +1,49 @@ + +set +echo "Build" +md build +cd build +call "C:\Program Files (x86)\Microsoft Visual Studio\2013\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 +cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ +nmake +if ERRORLEVEL 1 exit 1 + +echo "Test python bindings" +pushd python +python z3test.py z3 +if ERRORLEVEL 1 exit 1 +python z3test.py z3num +if ERRORLEVEL 1 exit 1 +popd + +echo "Build and run examples" +nmake cpp_example +examples\cpp_example_build_dir\cpp_example.exe +if ERRORLEVEL 1 exit 1 + +nmake c_example +examples\c_example_build_dir\c_example.exe +if ERRORLEVEL 1 exit 1 + +rem nmake java_example +rem java_example.exe +if ERRORLEVEL 1 exit 1 + +rem nmake dotnet_example +rem dotnet_example.exe +if ERRORLEVEL 1 exit 1 + +echo "Build and run unit tests" +nmake test-z3 +rem TBD: test error level +rem test-z3.exe -a + + +cd .. +echo "Run regression tests" +git clone https://github.com/z3prover/z3test z3test +echo "test-benchmarks" +python z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2 +if ERRORLEVEL 1 exit 1 +echo "benchmarks tested" + From 6ee4efe93a027abc705c9cd756f2c3e4ea308602 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 12:48:21 -0700 Subject: [PATCH 0685/1283] remove python tests from x86 build Signed-off-by: Nikolaj Bjorner --- scripts/vsts-vs2017.cmd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/vsts-vs2017.cmd b/scripts/vsts-vs2017.cmd index fe2f55bca..4ec4deca9 100644 --- a/scripts/vsts-vs2017.cmd +++ b/scripts/vsts-vs2017.cmd @@ -8,6 +8,7 @@ cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BIN nmake if ERRORLEVEL 1 exit 1 +if %1 == "x86" goto :BUILD_EXAMPLES echo "Test python bindings" pushd python python z3test.py z3 @@ -16,6 +17,7 @@ python z3test.py z3num if ERRORLEVEL 1 exit 1 popd +:BUILD_EXAMPLES echo "Build and run examples" nmake cpp_example examples\cpp_example_build_dir\cpp_example.exe From 8c4ea7983f5acc24204daab2658f6fc9d45a6015 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 12:59:42 -0700 Subject: [PATCH 0686/1283] use vc path in 2013 Signed-off-by: Nikolaj Bjorner --- scripts/vsts-vs2013.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts-vs2013.cmd b/scripts/vsts-vs2013.cmd index baf9f4bb4..203c2668e 100644 --- a/scripts/vsts-vs2013.cmd +++ b/scripts/vsts-vs2013.cmd @@ -3,7 +3,7 @@ set echo "Build" md build cd build -call "C:\Program Files (x86)\Microsoft Visual Studio\2013\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 +call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64 cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ nmake if ERRORLEVEL 1 exit 1 From 931dbd5933d77ba4a63b63259a339fa03410f661 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 13:37:04 -0700 Subject: [PATCH 0687/1283] remove python doc test Signed-off-by: Nikolaj Bjorner --- scripts/vsts-vs2013.cmd | 14 +++---- src/smt/theory_str.cpp | 87 +++++++++++++++++----------------------- src/smt/theory_str.h | 3 +- src/util/hashtable.h | 17 ++++---- src/util/obj_hashtable.h | 3 ++ 5 files changed, 55 insertions(+), 69 deletions(-) diff --git a/scripts/vsts-vs2013.cmd b/scripts/vsts-vs2013.cmd index 203c2668e..1676f3e2d 100644 --- a/scripts/vsts-vs2013.cmd +++ b/scripts/vsts-vs2013.cmd @@ -8,13 +8,13 @@ cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BIN nmake if ERRORLEVEL 1 exit 1 -echo "Test python bindings" -pushd python -python z3test.py z3 -if ERRORLEVEL 1 exit 1 -python z3test.py z3num -if ERRORLEVEL 1 exit 1 -popd +rem echo "Test python bindings" +rem pushd python +rem python z3test.py z3 +rem if ERRORLEVEL 1 exit 1 +rem python z3test.py z3num +rem if ERRORLEVEL 1 exit 1 +rem popd echo "Build and run examples" nmake cpp_example diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 69cf80de6..f61293a5f 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -169,6 +169,8 @@ namespace smt { } void theory_str::assert_axiom(expr * _e) { + if (_e == nullptr) + return; if (opt_VerifyFinalCheckProgress) { finalCheckProgressIndicator = true; } @@ -6914,10 +6916,8 @@ namespace smt { if (!map_effectively_empty) { map_effectively_empty = true; - ptr_vector indicator_set = fvar_lenTester_map[v]; - for (ptr_vector::iterator it = indicator_set.begin(); it != indicator_set.end(); ++it) { - expr * indicator = *it; - if (internal_variable_set.find(indicator) != internal_variable_set.end()) { + for (expr * indicator : fvar_lenTester_map[v]) { + if (internal_variable_set.contains(indicator)) { map_effectively_empty = false; break; } @@ -8977,12 +8977,12 @@ namespace smt { CTRACE("str", needToAssignFreeVars, tout << "Need to assign values to the following free variables:" << std::endl; - for (std::set::iterator itx = free_variables.begin(); itx != free_variables.end(); ++itx) { - tout << mk_ismt2_pp(*itx, m) << std::endl; + for (expr* v : free_variables) { + tout << mk_ismt2_pp(v, m) << std::endl; } tout << "freeVar_map has the following entries:" << std::endl; - for (std::map::iterator fvIt = freeVar_map.begin(); fvIt != freeVar_map.end(); fvIt++) { - expr * var = fvIt->first; + for (auto const& kv : freeVar_map) { + expr * var = kv.first; tout << mk_ismt2_pp(var, m) << std::endl; } ); @@ -9360,7 +9360,7 @@ namespace smt { // check whether any value tester is actually in scope TRACE("str", tout << "checking scope of previous value testers" << std::endl;); bool map_effectively_empty = true; - if (fvar_valueTester_map[freeVar].find(len) != fvar_valueTester_map[freeVar].end()) { + if (fvar_valueTester_map[freeVar].find(len) != fvar_valueTester_map[freeVar].end()) { // there's *something* in the map, but check its scope svector > entries = fvar_valueTester_map[freeVar][len]; for (svector >::iterator it = entries.begin(); it != entries.end(); ++it) { @@ -9721,8 +9721,8 @@ namespace smt { int dist = opt_LCMUnrollStep; expr_ref_vector litems(mgr); expr_ref moreAst(mk_string("more"), mgr); - for (std::set::iterator itor = unrolls.begin(); itor != unrolls.end(); itor++) { - expr_ref item(ctx.mk_eq_atom(var, *itor), mgr); + for (expr * e : unrolls) { + expr_ref item(ctx.mk_eq_atom(var, e), mgr); TRACE("str", tout << "considering unroll " << mk_pp(item, mgr) << std::endl;); litems.push_back(item); } @@ -9731,10 +9731,8 @@ namespace smt { ptr_vector outOfScopeTesters; - for (ptr_vector::iterator it = unroll_tries_map[var][unrolls].begin(); - it != unroll_tries_map[var][unrolls].end(); ++it) { - expr * tester = *it; - bool inScope = (internal_unrollTest_vars.find(tester) != internal_unrollTest_vars.end()); + for (expr * tester : unroll_tries_map[var][unrolls]) { + bool inScope = internal_unrollTest_vars.contains(tester); TRACE("str", tout << "unroll test var " << mk_pp(tester, mgr) << (inScope ? " in scope" : " out of scope") << std::endl;); @@ -9743,12 +9741,10 @@ namespace smt { } } - for (ptr_vector::iterator it = outOfScopeTesters.begin(); - it != outOfScopeTesters.end(); ++it) { - unroll_tries_map[var][unrolls].erase(*it); + for (expr* e : outOfScopeTesters) { + unroll_tries_map[var][unrolls].erase(e); } - if (unroll_tries_map[var][unrolls].size() == 0) { unroll_tries_map[var][unrolls].push_back(mk_unroll_test_var()); } @@ -10265,9 +10261,8 @@ namespace smt { // assume empty and find a counterexample map_effectively_empty = true; ptr_vector indicator_set = fvar_lenTester_map[freeVar]; - for (ptr_vector::iterator it = indicator_set.begin(); it != indicator_set.end(); ++it) { - expr * indicator = *it; - if (internal_variable_set.find(indicator) != internal_variable_set.end()) { + for (expr * indicator : indicator_set) { + if (internal_variable_set.contains(indicator)) { TRACE("str", tout <<"found active internal variable " << mk_ismt2_pp(indicator, m) << " in fvar_lenTester_map[freeVar]" << std::endl;); map_effectively_empty = false; @@ -10437,14 +10432,14 @@ namespace smt { void theory_str::process_free_var(std::map & freeVar_map) { context & ctx = get_context(); - std::set eqcRepSet; - std::set leafVarSet; - std::map > aloneVars; + obj_hashtable eqcRepSet; + obj_hashtable leafVarSet; + std::map > aloneVars; - for (std::map::iterator fvIt = freeVar_map.begin(); fvIt != freeVar_map.end(); fvIt++) { - expr * freeVar = fvIt->first; + for (auto const& kv : freeVar_map) { + expr * freeVar = kv.first; // skip all regular expression vars - if (regex_variable_set.find(freeVar) != regex_variable_set.end()) { + if (regex_variable_set.contains(freeVar)) { continue; } @@ -10454,10 +10449,10 @@ namespace smt { get_var_in_eqc(freeVar, eqVarSet); bool duplicated = false; expr * dupVar = nullptr; - for (std::set::iterator itorEqv = eqVarSet.begin(); itorEqv != eqVarSet.end(); itorEqv++) { - if (eqcRepSet.find(*itorEqv) != eqcRepSet.end()) { + for (expr* eq : eqVarSet) { + if (eqcRepSet.contains(eq)) { duplicated = true; - dupVar = *itorEqv; + dupVar = eq; break; } } @@ -10470,13 +10465,9 @@ namespace smt { } } - for (std::set::iterator fvIt = eqcRepSet.begin(); fvIt != eqcRepSet.end(); fvIt++) { - bool standAlone = true; - expr * freeVar = *fvIt; + for (expr * freeVar : eqcRepSet) { // has length constraint initially - if (input_var_in_len.find(freeVar) != input_var_in_len.end()) { - standAlone = false; - } + bool standAlone = !input_var_in_len.contains(freeVar); // iterate parents if (standAlone) { // I hope this works! @@ -10507,25 +10498,19 @@ namespace smt { } } - for(std::set::iterator itor1 = leafVarSet.begin(); - itor1 != leafVarSet.end(); ++itor1) { - expr * toAssert = gen_len_val_options_for_free_var(*itor1, nullptr, ""); + for (expr* lv : leafVarSet) { + expr * toAssert = gen_len_val_options_for_free_var(lv, nullptr, ""); // gen_len_val_options_for_free_var() can legally return NULL, // as methods that it calls may assert their own axioms instead. - if (toAssert != nullptr) { - assert_axiom(toAssert); - } + if (toAssert) assert_axiom(toAssert); + } - for (std::map >::iterator mItor = aloneVars.begin(); - mItor != aloneVars.end(); ++mItor) { - std::set::iterator itor2 = mItor->second.begin(); - for(; itor2 != mItor->second.end(); ++itor2) { - expr * toAssert = gen_len_val_options_for_free_var(*itor2, nullptr, ""); + for (auto const& kv : aloneVars) { + for (expr* av : kv.second) { + expr * toAssert = gen_len_val_options_for_free_var(av, nullptr, ""); // same deal with returning a NULL axiom here - if(toAssert != nullptr) { - assert_axiom(toAssert); - } + if (toAssert) assert_axiom(toAssert); } } } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 508a1c905..0a8495b14 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -295,7 +295,8 @@ protected: obj_hashtable input_var_in_len; obj_map fvar_len_count_map; - std::map > fvar_lenTester_map; + // std::map > fvar_lenTester_map; + obj_map > fvar_lenTester_map; obj_map lenTester_fvar_map; // TBD: need to replace by obj_map for determinism diff --git a/src/util/hashtable.h b/src/util/hashtable.h index 742438814..4dc05fe4d 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -600,9 +600,8 @@ public: core_hashtable& operator|=(core_hashtable const& other) { if (this == &other) return *this; - iterator i = other.begin(), e = other.end(); - for (; i != e; ++i) { - insert(*i); + for (const data& d : other) { + insert(d); } return *this; } @@ -610,10 +609,9 @@ public: core_hashtable& operator&=(core_hashtable const& other) { if (this == &other) return *this; core_hashtable copy(*this); - iterator i = copy.begin(), e = copy.end(); - for (; i != e; ++i) { - if (!other.contains(*i)) { - remove(*i); + for (const data& d : copy) { + if (!other.contains(d)) { + remove(d); } } return *this; @@ -622,9 +620,8 @@ public: core_hashtable& operator=(core_hashtable const& other) { if (this == &other) return *this; reset(); - iterator i = other.begin(), e = other.end(); - for (; i != e; ++i) { - insert(*i); + for (const data& d : e) { + insert(d); } return *this; } diff --git a/src/util/obj_hashtable.h b/src/util/obj_hashtable.h index 8826e8b76..d042779a8 100644 --- a/src/util/obj_hashtable.h +++ b/src/util/obj_hashtable.h @@ -174,6 +174,9 @@ public: value & find(key * k) { obj_map_entry * e = find_core(k); + if (!e) { + e = insert_if_not_there2(k, value()); + } SASSERT(e); return e->get_data().m_value; } From 4529ad933ac92737e51fb90fbd3b9bdb9e100840 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 15:19:05 -0700 Subject: [PATCH 0688/1283] add vstsmac Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 scripts/vsts-mac.sh diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh new file mode 100644 index 000000000..807631bba --- /dev/null +++ b/scripts/vsts-mac.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +mkdir build +CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py -x --dotnet --java --python +cd build +make + + + From 76eae5fa5c4c04f6bd3d8fbe419d063c441b293d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 16:57:01 -0700 Subject: [PATCH 0689/1283] add mac build Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 scripts/vsts-mac.sh diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh new file mode 100644 index 000000000..807631bba --- /dev/null +++ b/scripts/vsts-mac.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +mkdir build +CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py -x --dotnet --java --python +cd build +make + + + From 971f83997cefb92060c1d68f83a9417b239efa8d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 17:02:19 -0700 Subject: [PATCH 0690/1283] add ls Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 807631bba..a1d3d70e6 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -1,6 +1,7 @@ #!/bin/sh mkdir build +ls CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py -x --dotnet --java --python cd build make From 116f0e0c705c63261dbc54bd8473b205abc8ecb3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 17:05:12 -0700 Subject: [PATCH 0691/1283] cd below Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index a1d3d70e6..974f343e6 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -1,7 +1,7 @@ #!/bin/sh +cd .. mkdir build -ls CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py -x --dotnet --java --python cd build make From 16d2c2c506c7d7185de53241cfd79619a3bde3f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 17:06:54 -0700 Subject: [PATCH 0692/1283] mac Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 974f343e6..652a68656 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -2,7 +2,7 @@ cd .. mkdir build -CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py -x --dotnet --java --python +CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py --dotnet --java --python cd build make From 6304578111b04aaaf7e3d22dc92b848b1b5f31e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 17:08:26 -0700 Subject: [PATCH 0693/1283] mac Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 652a68656..a38ad86b2 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -2,7 +2,7 @@ cd .. mkdir build -CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py --dotnet --java --python +CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py --java --python cd build make From ff2924e83b8155eadb52afeeb4fb199b4dfc0bde Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 17:19:40 -0700 Subject: [PATCH 0694/1283] fix mac build error Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 7 +++++++ src/smt/theory_pb.cpp | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index a38ad86b2..522559b7c 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -5,6 +5,13 @@ mkdir build CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py --java --python cd build make +make test-z3 +make cpp_example +make c_example +make java_example +make python_example +./cpp_example +./c_example diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 92f66f4b6..f10be2291 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -2185,6 +2185,7 @@ namespace smt { unsigned idx = lits.size()-1; b_justification js; literal conseq = ~confl[2]; + int bound = 1; while (m_num_marks > 0) { @@ -2221,8 +2222,8 @@ namespace smt { // // Resolve selected conseq with antecedents. // - - int bound = 1; + + bound = 1; switch(js.get_kind()) { From 4b71bfc95d67d263095132ac099357817722b8ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 19:19:42 -0700 Subject: [PATCH 0695/1283] mac build Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 1 + src/test/sat_local_search.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index ebc198e61..0ead8bb40 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -17,6 +17,7 @@ Revision History: --*/ +#include #include "sat/ba_solver.h" #include "sat/sat_types.h" #include "util/mpz.h" diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index c9e3a18ec..3e137c0b7 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -18,7 +18,11 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea } infile.getline(line, 16383); int num_vars, num_constraints; +#ifdef _WINDOWS sscanf_s(line, "%d %d", &num_vars, &num_constraints); +#else + return false; +#endif //std::cout << "number of variables: " << num_vars << '\n'; //std::cout << "number of constraints: " << num_constraints << '\n'; From 81260c7ffb27ee1c775d47a10afa93dce796ce54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 19:53:25 -0700 Subject: [PATCH 0696/1283] fix mac build error Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 460695edd..5b89b4dfd 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -17,6 +17,8 @@ Author: Notes: --*/ + +#include #include "sat/sat_solver.h" #include "sat/sat_extension.h" #include "sat/sat_lookahead.h" From bd7ba4b61289baa7aef7d15fdd185b587fd78765 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 20:16:47 -0700 Subject: [PATCH 0697/1283] fix mac build error Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 1 + src/tactic/model_converter.cpp | 2 +- src/tactic/sine_filter.cpp | 8 ++++---- src/tactic/tactical.cpp | 8 +++++--- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3dff97875..47a456b24 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" #include "sat/sat_lookahead.h" diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index 127b6f5a0..cab5ef0c5 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -120,7 +120,7 @@ public: m = m_model; } - void operator()(labels_vec & r) { + void operator()(labels_vec & r) override { r.append(m_labels.size(), m_labels.c_ptr()); } diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 7099f0fdf..f2f7e00c8 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -36,14 +36,14 @@ public: sine_tactic(ast_manager& m, params_ref const& p): m(m), m_params(p) {} - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(sine_tactic, m, m_params); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } void operator()(goal_ref const & g, goal_ref_buffer& result) override { @@ -63,7 +63,7 @@ public: SASSERT(g->is_well_sorted()); } - virtual void cleanup() { + void cleanup() override { } private: diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 1899876df..738a3b367 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -1040,7 +1040,7 @@ public: virtual ~fail_if_tactic() {} - void cleanup() {} + void cleanup() override {} void operator()(goal_ref const & in, goal_ref_buffer& result) override { if (m_p->operator()(*(in.get())).is_true()) { @@ -1093,7 +1093,7 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { return translate_core(m); } }; class if_no_models_tactical : public unary_tactical { @@ -1109,7 +1109,9 @@ public: } } - virtual tactic * translate(ast_manager & m) { return translate_core(m); } + tactic * translate(ast_manager & m) override { + return translate_core(m); + } }; tactic * if_no_proofs(tactic * t) { From d27527d4df51ca4e4d56a9744323661db681caf7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 20:49:57 -0700 Subject: [PATCH 0698/1283] fix mac build error Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 6 ++++-- src/tactic/core/solve_eqs_tactic.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 270a98ca9..de239a804 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1939,8 +1939,10 @@ namespace z3 { void add(expr const & e, char const * p) { add(e, ctx().bool_const(p)); } - void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } - void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); check_error(); } + // fails for some compilers: + // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } + void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); ctx().check_parser_error(); } + void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); ctx().check_parser_error(); } check_result check() { Z3_lbool r = Z3_solver_check(ctx(), m_solver); check_error(); return to_check_result(r); } check_result check(unsigned n, expr * const assumptions) { array _assumptions(n); diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 08b771df5..1b99cf0df 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -711,7 +711,7 @@ public: m_imp = alloc(imp, m, p, r, owner); } - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(solve_eqs_tactic, m, m_params, mk_expr_simp_replacer(m, m_params), true); } @@ -719,12 +719,12 @@ public: dealloc(m_imp); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { m_params = p; m_imp->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { r.insert("solve_eqs_max_occs", CPK_UINT, "(default: infty) maximum number of occurrences for considering a variable for gaussian eliminations."); r.insert("theory_solver", CPK_BOOL, "(default: true) use theory solvers."); r.insert("ite_solver", CPK_BOOL, "(default: true) use if-then-else solver."); @@ -736,7 +736,7 @@ public: report_tactic_progress(":num-elim-vars", m_imp->get_num_eliminated_vars()); } - virtual void cleanup() { + void cleanup() override { unsigned num_elim_vars = m_imp->m_num_eliminated_vars; ast_manager & m = m_imp->m(); expr_replacer * r = m_imp->m_r; @@ -751,11 +751,11 @@ public: dealloc(d); } - virtual void collect_statistics(statistics & st) const { + void collect_statistics(statistics & st) const override { st.update("eliminated vars", m_imp->get_num_eliminated_vars()); } - virtual void reset_statistics() { + void reset_statistics() override { m_imp->m_num_eliminated_vars = 0; } From f86a9b4b70a3972da1a9be13d203e7878bce7907 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Mar 2018 02:44:53 -0700 Subject: [PATCH 0699/1283] check-error Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index de239a804..adc5bbbcf 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1941,8 +1941,8 @@ namespace z3 { } // fails for some compilers: // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } - void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); ctx().check_parser_error(); } - void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); ctx().check_parser_error(); } + void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); check_error(); } + void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); check_error(); } check_result check() { Z3_lbool r = Z3_solver_check(ctx(), m_solver); check_error(); return to_check_result(r); } check_result check(unsigned n, expr * const assumptions) { array _assumptions(n); From fe30b7edb66cd1700e595c7ae097d0a403255b47 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Mar 2018 03:16:58 -0700 Subject: [PATCH 0700/1283] fix mac build error Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index adc5bbbcf..0d55d326e 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2114,7 +2114,7 @@ namespace z3 { return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } - void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } + // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } From 9765a6d0d3aafd5f4ac2ecc2a4aeea35a0a65690 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Mar 2018 09:23:01 -0700 Subject: [PATCH 0701/1283] updated script Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 522559b7c..545f6e4f1 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -8,10 +8,11 @@ make make test-z3 make cpp_example make c_example -make java_example -make python_example +# make java_example +# make python_example ./cpp_example -./c_example - +./test_capi +git clone https://github.com/z3prover/z3test.git z3test +python z3test/scripts/test_benchmarks.py z3 z3test/regressions/smt2 From ba30365e2ddcd7702d25f5ccdc3939513a021546 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Mar 2018 10:26:09 -0700 Subject: [PATCH 0702/1283] updated script Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 545f6e4f1..2b24f6459 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -14,5 +14,5 @@ make c_example ./test_capi git clone https://github.com/z3prover/z3test.git z3test -python z3test/scripts/test_benchmarks.py z3 z3test/regressions/smt2 +python z3test/scripts/test_benchmarks.py z3 ../regressions/smt2 From 1470dbf517a2b3939f6d03f931f0a926d9914044 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Mar 2018 10:57:40 -0700 Subject: [PATCH 0703/1283] back to path Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 2b24f6459..24553cd60 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -14,5 +14,5 @@ make c_example ./test_capi git clone https://github.com/z3prover/z3test.git z3test -python z3test/scripts/test_benchmarks.py z3 ../regressions/smt2 +python z3test/scripts/test_benchmarks.py z3 ./z3test/regressions/smt2 From 5d68a09233f0304fa45c9554d91bbd3f06b535f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Mar 2018 11:25:38 -0700 Subject: [PATCH 0704/1283] update script Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 24553cd60..3a5a86b47 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -14,5 +14,5 @@ make c_example ./test_capi git clone https://github.com/z3prover/z3test.git z3test -python z3test/scripts/test_benchmarks.py z3 ./z3test/regressions/smt2 +python z3test/scripts/test_benchmarks.py ./z3.bin ./z3test/regressions/smt2 From 12f147403c98a802ec0edf6f66ea389e3619c0a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Mar 2018 14:13:27 -0700 Subject: [PATCH 0705/1283] update script Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 3a5a86b47..6c588a1e3 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -14,5 +14,6 @@ make c_example ./test_capi git clone https://github.com/z3prover/z3test.git z3test -python z3test/scripts/test_benchmarks.py ./z3.bin ./z3test/regressions/smt2 +ls +python z3test/scripts/test_benchmarks.py ./z3.exe ./z3test/regressions/smt2 From bfc0b214ab6a17b37298e804dbe5b47966aab40c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Mar 2018 14:49:36 -0700 Subject: [PATCH 0706/1283] update script Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 6c588a1e3..9be53967f 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -15,5 +15,5 @@ make c_example git clone https://github.com/z3prover/z3test.git z3test ls -python z3test/scripts/test_benchmarks.py ./z3.exe ./z3test/regressions/smt2 +python z3test/scripts/test_benchmarks.py ./z3 ./z3test/regressions/smt2 From 3765bde5e993d78cfbcf43a2999b45b18ed7866d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Mar 2018 20:19:08 -0700 Subject: [PATCH 0707/1283] updated OSX build Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh index 807631bba..9be53967f 100644 --- a/scripts/vsts-mac.sh +++ b/scripts/vsts-mac.sh @@ -1,9 +1,19 @@ #!/bin/sh +cd .. mkdir build -CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py -x --dotnet --java --python +CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py --java --python cd build make +make test-z3 +make cpp_example +make c_example +# make java_example +# make python_example +./cpp_example +./test_capi - +git clone https://github.com/z3prover/z3test.git z3test +ls +python z3test/scripts/test_benchmarks.py ./z3 ./z3test/regressions/smt2 From 705439cb85d00453a2f3ed446d965de34393688e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Mar 2018 20:22:42 -0700 Subject: [PATCH 0708/1283] update build definition to 4 Signed-off-by: Nikolaj Bjorner --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d501c5d5c..e3ef58b70 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z | Windows x64 | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | | ----------- | ----------- | ----------- | ---------- | ---------- | --- | -------- | -[![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=2) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) +[![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=4) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang From 966a8f73d33d9ed011286c6fb62fbf6f5449112f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Mar 2018 16:26:20 -0700 Subject: [PATCH 0709/1283] add eval feature #1553 Signed-off-by: Nikolaj Bjorner --- src/api/api_context.h | 3 +++ src/api/api_parsers.cpp | 27 +++++++++++++++++++++++++++ src/api/z3_api.h | 11 +++++++++++ 3 files changed, 41 insertions(+) diff --git a/src/api/api_context.h b/src/api/api_context.h index 7009250cc..185eb9e0f 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -34,6 +34,7 @@ Revision History: #include "util/event_handler.h" #include "cmd_context/tactic_manager.h" #include "cmd_context/context_params.h" +#include "cmd_context/cmd_context.h" #include "api/api_polynomial.h" #include "util/hashtable.h" @@ -53,6 +54,7 @@ namespace api { context_params m_params; bool m_user_ref_count; //!< if true, the user is responsible for managing reference counters. scoped_ptr m_manager; + scoped_ptr m_cmd; add_plugins m_plugins; arith_util m_arith_util; @@ -114,6 +116,7 @@ namespace api { ast_manager & m() const { return *(m_manager.get()); } context_params & params() { return m_params; } + scoped_ptr& cmd() { return m_cmd; } bool produce_proofs() const { return m().proofs_enabled(); } bool produce_models() const { return m_params.m_model; } bool produce_unsat_cores() const { return m_params.m_unsat_core; } diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 2e33c1a13..830bef7a8 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -117,4 +117,31 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(nullptr); } + + Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context c, Z3_string str) { + Z3_TRY; + LOG_Z3_eval_smtlib2_string(c, str); + if (!mk_c(c)->cmd()) { + mk_c(c)->cmd() = alloc(cmd_context, false, &(mk_c(c)->m())); + } + scoped_ptr& ctx = mk_c(c)->cmd(); + std::string s(str); + std::istringstream is(s); + std::stringstream ous; + ctx->set_regular_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); + RETURN_Z3(nullptr); + } + } + catch (z3_exception& e) { + mk_c(c)->m_parser_error_buffer = e.msg(); + SET_ERROR_CODE(Z3_PARSER_ERROR); + RETURN_Z3(nullptr); + } + RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); + Z3_CATCH_RETURN(nullptr); + } }; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 87bb4d818..50ed85c70 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5209,6 +5209,17 @@ extern "C" { Z3_func_decl const decls[]); + /** + \brief Parse and evaluate and SMT-LIB2 command sequence. The state from a previous call is saved so the next + evaluation builds on top of the previous call. + + \returns output generated from processing commands. + + def_API('Z3_eval_smtlib2_string', STRING, (_in(CONTEXT), _in(STRING),)) + */ + + Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context, Z3_string str); + /** \brief Retrieve that last error message information generated from parsing. From 753f2c89ef70890253b930ec74220aafc209dcbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 23 Mar 2018 18:54:06 -0700 Subject: [PATCH 0710/1283] initialize solvers to ensure that eval mode has a solver Signed-off-by: Nikolaj Bjorner --- src/api/api_parsers.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 830bef7a8..3af2e567c 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -21,8 +21,11 @@ Revision History: #include "api/api_context.h" #include "api/api_util.h" #include "cmd_context/cmd_context.h" +#include "smt/smt_solver.h" #include "parsers/smt2/smt2parser.h" #include "solver/solver_na2as.h" +#include "tactic/portfolio/smt_strategic_solver.h" + extern "C" { @@ -123,6 +126,7 @@ extern "C" { LOG_Z3_eval_smtlib2_string(c, str); if (!mk_c(c)->cmd()) { mk_c(c)->cmd() = alloc(cmd_context, false, &(mk_c(c)->m())); + mk_c(c)->cmd()->set_solver_factory(mk_smt_strategic_solver_factory()); } scoped_ptr& ctx = mk_c(c)->cmd(); std::string s(str); From fc719a5ee82361ffedb9ef46793e3401fdc32cc5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Mar 2018 10:37:05 -0700 Subject: [PATCH 0711/1283] fix diagnostic output #1553 Signed-off-by: Nikolaj Bjorner --- src/api/api_parsers.cpp | 12 +++++++----- src/cmd_context/cmd_context.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 3af2e567c..28db62cc3 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -122,6 +122,7 @@ extern "C" { } Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context c, Z3_string str) { + std::stringstream ous; Z3_TRY; LOG_Z3_eval_smtlib2_string(c, str); if (!mk_c(c)->cmd()) { @@ -131,21 +132,22 @@ extern "C" { scoped_ptr& ctx = mk_c(c)->cmd(); std::string s(str); std::istringstream is(s); - std::stringstream ous; ctx->set_regular_stream(ous); + 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); - RETURN_Z3(nullptr); + RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); } } catch (z3_exception& e) { - mk_c(c)->m_parser_error_buffer = e.msg(); + if (ous.str().empty()) ous << e.msg(); + mk_c(c)->m_parser_error_buffer = ous.str(); SET_ERROR_CODE(Z3_PARSER_ERROR); - RETURN_Z3(nullptr); + RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); } RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); - Z3_CATCH_RETURN(nullptr); + Z3_CATCH_RETURN(mk_c(c)->mk_external_string(ous.str())); } }; diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index d1e470c3b..90b3f6c56 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -406,6 +406,7 @@ public: void reset_user_tactics(); void set_regular_stream(char const * name) { m_regular.set(name); } void set_regular_stream(std::ostream& out) { m_regular.set(out); } + void set_diagnostic_stream(std::ostream& out) { m_diagnostic.set(out); } void set_diagnostic_stream(char const * name); std::ostream & regular_stream() override { return *m_regular; } std::ostream & diagnostic_stream() override { return *m_diagnostic; } From a79400a01bae238be7100bb36b7a10fcfb7f6dd6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Mar 2018 14:55:42 -0700 Subject: [PATCH 0712/1283] fix bugs in scc_tr Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 19 ----------- src/sat/sat_asymm_branch.cpp | 10 +++--- src/sat/sat_big.cpp | 64 ++++++++++++++++++++++++++++++++---- src/sat/sat_big.h | 7 ++++ src/sat/sat_cleaner.cpp | 11 ++----- src/sat/sat_params.pyg | 4 +-- src/sat/sat_solver.cpp | 9 +++++ 7 files changed, 83 insertions(+), 41 deletions(-) delete mode 100644 scripts/vsts-mac.sh diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh deleted file mode 100644 index 9be53967f..000000000 --- a/scripts/vsts-mac.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -cd .. -mkdir build -CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py --java --python -cd build -make -make test-z3 -make cpp_example -make c_example -# make java_example -# make python_example -./cpp_example -./test_capi - -git clone https://github.com/z3prover/z3test.git z3test -ls -python z3test/scripts/test_benchmarks.py ./z3 ./z3test/regressions/smt2 - diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 35d594b34..a6e036408 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -245,14 +245,14 @@ namespace sat { m_pos.push_back(l); m_neg.push_back(~l); } -#if 1 compare_left cmp(big); std::sort(m_pos.begin(), m_pos.end(), cmp); std::sort(m_neg.begin(), m_neg.end(), cmp); -#else - radix_sort(big, m_pos); - radix_sort(big, m_neg); -#endif + + // alternative: worse + // radix_sort(big, m_pos); + // radix_sort(big, m_neg); + IF_VERBOSE(100, for (literal l : m_pos) verbose_stream() << big.get_left(l) << " "; verbose_stream() << "\n"; diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 3443625cf..2f1a3727f 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -164,8 +164,19 @@ namespace sat { DEBUG_CODE(for (unsigned i = 0; i < num_lits; ++i) { VERIFY(m_left[i] < m_right[i]);}); } - unsigned big::reduce_tr(solver& s) { + // svector> big::s_del_bin; + bool big::in_del(literal u, literal v) const { + if (u.index() > v.index()) std::swap(u, v); + return m_del_bin.contains(std::make_pair(u, v)); + } + + void big::add_del(literal u, literal v) { + if (u.index() > v.index()) std::swap(u, v); + m_del_bin.push_back(std::make_pair(u, v)); + } + + unsigned big::reduce_tr(solver& s) { unsigned num_lits = s.num_vars() * 2; unsigned idx = 0; unsigned elim = 0; @@ -182,7 +193,8 @@ namespace sat { literal v = w.get_literal(); if (u != get_parent(v) && safe_reach(u, v)) { ++elim; - m_del_bin.push_back(std::make_pair(~u, v)); + add_del(~u, v); + // IF_VERBOSE(1, verbose_stream() << "remove " << u << " -> " << v << "\n"); if (find_binary_watch(wlist, ~v)) { IF_VERBOSE(10, verbose_stream() << "binary: " << ~u << "\n"); s.assign(~u, justification()); @@ -197,6 +209,23 @@ namespace sat { } wlist.set_end(itprev); } + +#if 0 + s_del_bin.append(m_del_bin); + IF_VERBOSE(1, + display(verbose_stream() << "Learned: " << learned() << ":"); + verbose_stream() << "del-bin\n"; + for (auto p : m_del_bin) { + verbose_stream() << p.first << " " << p.second << "\n"; + if (safe_reach(~p.first, p.second)) { + display_path(verbose_stream(), ~p.first, p.second) << " " << "\n"; + } + else { + display_path(verbose_stream(), ~p.second, p.first) << " " << "\n"; + } + } + ); +#endif s.propagate(false); return elim; } @@ -205,8 +234,7 @@ namespace sat { if (!reaches(u, v)) return false; while (u != v) { literal w = next(u, v); - if (m_del_bin.contains(std::make_pair(~u, w)) || - m_del_bin.contains(std::make_pair(~w, u))) { + if (in_del(~u, w)) { return false; } u = w; @@ -216,11 +244,27 @@ namespace sat { literal big::next(literal u, literal v) const { SASSERT(reaches(u, v)); + literal result = null_literal; + int left = m_right[u.index()]; + // identify the path from the reachability graph for (literal w : m_dag[u.index()]) { - if (reaches(u, w) && (w == v || reaches(w, v))) return w; + if (reaches(u, w) && + (w == v || reaches(w, v)) && + m_left[w.index()] < left) { + left = m_left[w.index()]; + result = w; + } } - UNREACHABLE(); - return null_literal; + SASSERT(result != null_literal); + return result; + } + + std::ostream& big::display_path(std::ostream& out, literal u, literal v) const { + while (u != v) { + out << u << " -> "; + u = next(u, v); + } + return out << v; } void big::display(std::ostream& out) const { @@ -228,6 +272,12 @@ namespace sat { for (auto& next : m_dag) { if (!next.empty()) { out << to_literal(idx) << " : " << m_left[idx] << ":" << m_right[idx] << " -> " << next << "\n"; +#if 0 + for (literal n : next) { + out << n << "[" << m_left[n.index()] << ":" << m_right[n.index()] << "] "; + } + out << "\n"; +#endif } ++idx; } diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index c9d47f82c..f2adf9ad8 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -45,8 +45,15 @@ namespace sat { bool safe_reach(literal u, literal v); literal next(literal u, literal v) const; + std::ostream& display_path(std::ostream& out, literal u, literal v) const; + + void add_del(literal u, literal v); + bool in_del(literal u, literal v) const; + public: + // static svector> s_del_bin; + big(random_gen& rand); /** \brief initialize a BIG from a solver. diff --git a/src/sat/sat_cleaner.cpp b/src/sat/sat_cleaner.cpp index 3d0899692..c0c6fabe4 100644 --- a/src/sat/sat_cleaner.cpp +++ b/src/sat/sat_cleaner.cpp @@ -117,19 +117,13 @@ namespace sat { else { unsigned new_sz = j; CTRACE("sat_cleaner_bug", new_sz < 2, tout << "new_sz: " << new_sz << "\n"; - if (c.size() > 0) tout << "unit: " << c[0] << "\n";); - SASSERT(c.frozen() || new_sz >= 2); + if (c.size() > 0) tout << "unit: " << c[0] << "\n"; + s.display_watches(tout);); if (new_sz == 0) { - // It can only happen with frozen clauses. - // active clauses would have signed the conflict. - SASSERT(c.frozen()); s.set_conflict(justification()); s.del_clause(c); } else if (new_sz == 1) { - // It can only happen with frozen clauses. - // active clauses would have propagated the literal - SASSERT(c.frozen()); s.assign(c[0], justification()); s.del_clause(c); } @@ -188,6 +182,7 @@ namespace sat { CASSERT("cleaner_bug", s.check_invariant()); unsigned trail_sz = s.m_trail.size(); s.propagate(false); // make sure that everything was propagated. + TRACE("sat_cleaner_bug", s.display(tout); s.display_watches(tout);); if (s.m_inconsistent) return false; if (m_last_num_units == trail_sz) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 850a33cef..56a5b6e6c 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -33,8 +33,8 @@ def_module_params('sat', ('drat.file', SYMBOL, '', 'file to dump DRAT proofs'), ('drat.check_unsat', BOOL, False, 'build up internal proof and check'), ('drat.check_sat', BOOL, False, 'build up internal trace, check satisfying model'), - ('cardinality.solver', BOOL, False, 'use cardinality solver'), - ('pb.solver', SYMBOL, 'circuit', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use SMT solver)'), + ('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'), ('local_search', BOOL, False, 'use local search instead of CDCL'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 47a456b24..a2ef176a1 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1634,6 +1634,15 @@ namespace sat { } TRACE("sat_mc_bug", m_mc.display(tout);); +#if 0 + IF_VERBOSE(0, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";); + for (auto p : big::s_del_bin) { + if (value(p.first) != l_true && value(p.second) != l_true) { + IF_VERBOSE(0, verbose_stream() << "binary violation: " << p.first << " " << p.second << "\n"); + } + } +#endif + IF_VERBOSE(10, verbose_stream() << "\"checking model\"\n";); if (!check_clauses(m_model)) { throw solver_exception("check model failed"); From c4ff5c7ac7b6f3542242a1533a6f52b5c2e1fa23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Mar 2018 18:32:16 -0700 Subject: [PATCH 0713/1283] remove lns code Signed-off-by: Nikolaj Bjorner --- src/opt/CMakeLists.txt | 1 - src/opt/opt_context.cpp | 48 +------------ src/opt/opt_context.h | 5 -- src/opt/opt_lns.cpp | 145 ---------------------------------------- src/opt/opt_lns.h | 68 ------------------- src/opt/opt_params.pyg | 2 +- 6 files changed, 3 insertions(+), 266 deletions(-) delete mode 100644 src/opt/opt_lns.cpp delete mode 100644 src/opt/opt_lns.h diff --git a/src/opt/CMakeLists.txt b/src/opt/CMakeLists.txt index 3f1d8253c..28a14be2e 100644 --- a/src/opt/CMakeLists.txt +++ b/src/opt/CMakeLists.txt @@ -5,7 +5,6 @@ z3_add_component(opt mss.cpp opt_cmds.cpp opt_context.cpp - opt_lns.cpp opt_pareto.cpp opt_parse.cpp optsmt.cpp diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 33aaa0b27..0793e5c53 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -254,9 +254,6 @@ namespace opt { if (m_pareto) { return execute_pareto(); } - if (m_lns) { - return execute_lns(); - } if (m_box_index != UINT_MAX) { return execute_box(); } @@ -276,9 +273,6 @@ namespace opt { opt_params optp(m_params); symbol pri = optp.priority(); - if (pri == symbol("lns")) { - return execute_lns(); - } IF_VERBOSE(1, verbose_stream() << "(optimize:check-sat)\n"); lbool is_sat = s.check_sat(0,0); @@ -311,9 +305,6 @@ namespace opt { if (pri == symbol("pareto")) { is_sat = execute_pareto(); } - else if (pri == symbol("lns")) { - is_sat = execute_lns(); - } else if (pri == symbol("box")) { is_sat = execute_box(); } @@ -536,12 +527,8 @@ namespace opt { } void context::yield() { - if (m_pareto) { - m_pareto->get_model(m_model, m_labels); - } - else if (m_lns) { - m_lns->get_model(m_model, m_labels); - } + SASSERT (m_pareto); + m_pareto->get_model(m_model, m_labels); update_bound(true); update_bound(false); } @@ -560,19 +547,6 @@ namespace opt { return is_sat; } - lbool context::execute_lns() { - if (!m_lns) { - m_lns = alloc(lns, *this, m_solver.get()); - } - lbool is_sat = (*(m_lns.get()))(); - if (is_sat != l_true) { - m_lns = nullptr; - } - if (is_sat == l_true) { - yield(); - } - return l_undef; - } std::string context::reason_unknown() const { if (m.canceled()) { @@ -1020,23 +994,6 @@ namespace opt { } } - /** - \brief retrieve literals used by the neighborhood search feature. - */ - - void context::get_lns_literals(expr_ref_vector& lits) { - for (objective & obj : m_objectives) { - switch(obj.m_type) { - case O_MAXSMT: - for (expr* f : obj.m_terms) { - lits.push_back(f); - } - break; - default: - break; - } - } - } bool context::verify_model(unsigned index, model* md, rational const& _v) { rational r; @@ -1401,7 +1358,6 @@ namespace opt { void context::clear_state() { m_pareto = nullptr; - m_lns = nullptr; m_box_index = UINT_MAX; m_model.reset(); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 9f55d5ca1..abc6268dd 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -27,7 +27,6 @@ Notes: #include "opt/opt_solver.h" #include "opt/opt_pareto.h" #include "opt/optsmt.h" -#include "opt/opt_lns.h" #include "opt/maxsmt.h" #include "cmd_context/cmd_context.h" @@ -147,7 +146,6 @@ namespace opt { ref m_solver; ref m_sat_solver; scoped_ptr m_pareto; - scoped_ptr m_lns; scoped_ptr m_qmax; sref_vector m_box_models; unsigned m_box_index; @@ -234,8 +232,6 @@ namespace opt { virtual bool verify_model(unsigned id, model* mdl, rational const& v); - void get_lns_literals(expr_ref_vector& lits); - private: lbool execute(objective const& obj, bool committed, bool scoped); lbool execute_min_max(unsigned index, bool committed, bool scoped, bool is_max); @@ -243,7 +239,6 @@ namespace opt { lbool execute_lex(); lbool execute_box(); lbool execute_pareto(); - lbool execute_lns(); lbool adjust_unknown(lbool r); bool scoped_lex(); expr_ref to_expr(inf_eps const& n); diff --git a/src/opt/opt_lns.cpp b/src/opt/opt_lns.cpp deleted file mode 100644 index 0cdcf19c4..000000000 --- a/src/opt/opt_lns.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/*++ -Copyright (c) 2018 Microsoft Corporation - -Module Name: - - opt_lns.cpp - -Abstract: - - Large neighborhood search default implementation - based on phase saving and assumptions - -Author: - - Nikolaj Bjorner (nbjorner) 2018-3-13 - ---*/ - -#include "ast/ast_pp.h" -#include "opt/opt_lns.h" -#include "opt/opt_context.h" - -namespace opt { - - lns::lns(context& ctx, solver* s): - m(ctx.get_manager()), - m_ctx(ctx), - m_solver(s), - m_models_trail(m), - m_atoms(m) - {} - - lns::~lns() {} - - void lns::display(std::ostream & out) const { - for (auto const& q : m_queue) { - expr_ref tmp(mk_and(q.m_assignment)); - out << q.m_index << ": " << tmp << "\n"; - } - } - - lbool lns::operator()() { - if (m_queue.empty()) { - expr_ref_vector lits(m), atoms(m); - m_ctx.get_lns_literals(lits); - for (expr* l : lits) { - expr* nl = nullptr; - if (m.is_not(l, nl)) { - m_atoms.push_back(nl); - } - else { - atoms.push_back(l); - m_atoms.push_back(l); - } - } - m_queue.push_back(queue_elem(atoms)); - m_qhead = 0; - } - - params_ref p; - p.set_uint("inprocess.max", 3ul); - m_solver->updt_params(p); - - while (m_qhead < m_queue.size()) { - obj_hashtable atoms; - for (expr* f : m_queue[m_qhead].m_assignment) { - atoms.insert(f); - } - unsigned& index = m_queue[m_qhead].m_index; - expr* lit = nullptr; - for (; index < m_atoms.size(); ++index) { - lit = m_atoms[index].get(); - if (!atoms.contains(lit) && !m_failed.contains(lit)) break; - } - if (index == m_atoms.size()) { - m_qhead++; - continue; - } - - IF_VERBOSE(2, verbose_stream() << "(opt.lns :queue " << m_qhead << " :index " << index << ")\n"); - - p.set_uint("local_search_threads", 0); - p.set_uint("unit_walk_threads", 0); - m_solver->updt_params(p); - - // recalibrate state to an initial satisfying assignment - lbool is_sat = m_solver->check_sat(m_queue[m_qhead].m_assignment); - IF_VERBOSE(2, verbose_stream() << "(opt.lns :calibrate-status " << is_sat << ")\n"); - if (!m.limit().inc()) { - return l_undef; - } - - expr_ref_vector lits(m); - lits.push_back(lit); - ++index; - - // freeze phase in both SAT solver and local search to current assignment - p.set_uint("inprocess.max", 5); - p.set_bool("phase.sticky", true); - p.set_uint("local_search_threads", 1); - p.set_uint("max_conflicts", 100000); - //p.set_uint("unit_walk_threads", 1); - m_solver->updt_params(p); - - is_sat = m_solver->check_sat(lits); - IF_VERBOSE(2, verbose_stream() << "(opt.lns :lookahead-status " << is_sat << " " << mk_pp(lit, m) << ")\n"); - if (is_sat == l_true && add_assignment()) { - return l_true; - } - if (is_sat == l_false) { - m_failed.insert(lit); - expr_ref nlit(m.mk_not(lit), m); - m_solver->assert_expr(nlit); - } - if (!m.limit().inc()) { - return l_undef; - } - } - return l_false; - } - - bool lns::add_assignment() { - model_ref mdl; - m_solver->get_model(mdl); - m_ctx.fix_model(mdl); - expr_ref tmp(m); - expr_ref_vector fmls(m); - for (expr* f : m_atoms) { - mdl->eval(f, tmp); - if (m.is_true(tmp)) { - fmls.push_back(f); - } - } - tmp = mk_and(fmls); - if (m_models.contains(tmp)) { - return false; - } - else { - m_models.insert(tmp); - m_models_trail.push_back(tmp); - return true; - } - } -} - diff --git a/src/opt/opt_lns.h b/src/opt/opt_lns.h deleted file mode 100644 index 827df3081..000000000 --- a/src/opt/opt_lns.h +++ /dev/null @@ -1,68 +0,0 @@ -/*++ -Copyright (c) 2018 Microsoft Corporation - -Module Name: - - opt_lns.h - -Abstract: - - Large neighborhood seearch - -Author: - - Nikolaj Bjorner (nbjorner) 2018-3-13 - -Notes: - - ---*/ -#ifndef OPT_LNS_H_ -#define OPT_LNS_H_ - -#include "solver/solver.h" -#include "model/model.h" - -namespace opt { - - class context; - - class lns { - struct queue_elem { - expr_ref_vector m_assignment; - unsigned m_index; - queue_elem(expr_ref_vector& assign): - m_assignment(assign), - m_index(0) - {} - }; - ast_manager& m; - context& m_ctx; - ref m_solver; - model_ref m_model; - svector m_labels; - vector m_queue; - unsigned m_qhead; - expr_ref_vector m_models_trail; - expr_ref_vector m_atoms; - obj_hashtable m_models; - obj_hashtable m_failed; - - bool add_assignment(); - public: - lns(context& ctx, solver* s); - - ~lns(); - - void display(std::ostream & out) const; - - lbool operator()(); - - void get_model(model_ref& mdl, svector& labels) { - mdl = m_model; - labels = m_labels; - } - }; -} - -#endif diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 21845d38a..911b0a694 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,7 +3,7 @@ def_module_params('opt', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), - ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box', or 'lns' (large neighborhood search)"), + ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), From bd2ed196e3afde3d575affd127c42503dfde04c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Mar 2018 19:36:21 -0700 Subject: [PATCH 0714/1283] add correct badge Signed-off-by: Nikolaj Bjorner --- README.md | 2 +- src/opt/opt_solver.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e3ef58b70..8ebf6a078 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z | Windows x64 | Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | | ----------- | ----------- | ----------- | ---------- | ---------- | --- | -------- | -[![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=4) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) +[![win64-badge](https://z3build.visualstudio.com/_apis/public/build/definitions/2e0aa542-a22c-4b1a-8dcd-3ebae8e12db4/4/badge)](https://z3build.visualstudio.com/Z3Build/_build/index?definitionId=4) | [![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index c5363816a..785836f56 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -229,6 +229,7 @@ namespace opt { inf_eps val = get_optimizer().maximize(v, blocker, has_shared); get_model(m_model); inf_eps val2; + std::cout << m_valid_objectives.size() << " " << i << "\n"; m_valid_objectives[i] = true; TRACE("opt", tout << (has_shared?"has shared":"non-shared") << "\n";); if (!m_models[i]) { @@ -341,6 +342,7 @@ namespace opt { smt::theory_var opt_solver::add_objective(app* term) { smt::theory_var v = get_optimizer().add_objective(term); + std::cout << "add objective " << v << "\n"; m_objective_vars.push_back(v); m_objective_values.push_back(inf_eps(rational(-1), inf_rational())); m_objective_terms.push_back(term); @@ -436,6 +438,7 @@ namespace opt { } void opt_solver::reset_objectives() { + std::cout << "reset-objectives\n"; m_objective_vars.reset(); m_objective_values.reset(); m_objective_terms.reset(); From 88e777748ad94c097ff8d2e00359107a9f4aba76 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Mar 2018 19:37:19 -0700 Subject: [PATCH 0715/1283] remove stdout Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 785836f56..c5363816a 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -229,7 +229,6 @@ namespace opt { inf_eps val = get_optimizer().maximize(v, blocker, has_shared); get_model(m_model); inf_eps val2; - std::cout << m_valid_objectives.size() << " " << i << "\n"; m_valid_objectives[i] = true; TRACE("opt", tout << (has_shared?"has shared":"non-shared") << "\n";); if (!m_models[i]) { @@ -342,7 +341,6 @@ namespace opt { smt::theory_var opt_solver::add_objective(app* term) { smt::theory_var v = get_optimizer().add_objective(term); - std::cout << "add objective " << v << "\n"; m_objective_vars.push_back(v); m_objective_values.push_back(inf_eps(rational(-1), inf_rational())); m_objective_terms.push_back(term); @@ -438,7 +436,6 @@ namespace opt { } void opt_solver::reset_objectives() { - std::cout << "reset-objectives\n"; m_objective_vars.reset(); m_objective_values.reset(); m_objective_terms.reset(); From 7063ad81cce2d6020c2495ca96d938ff504efb02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Mar 2018 19:42:06 -0700 Subject: [PATCH 0716/1283] updates Signed-off-by: Nikolaj Bjorner --- scripts/vsts-mac.sh | 18 ++++++++++++++++++ src/opt/opt_solver.h | 2 +- src/opt/optsmt.cpp | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 scripts/vsts-mac.sh diff --git a/scripts/vsts-mac.sh b/scripts/vsts-mac.sh new file mode 100644 index 000000000..959dccbbd --- /dev/null +++ b/scripts/vsts-mac.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +cd .. +mkdir build +CSC=/usr/bin/csc GACUTIL=/usr/bin/gacutil CXX=clang++ CC=clang python scripts/mk_make.py --java --python +cd build +make +make test-z3 +make cpp_example +make c_example +# make java_example +# make python_example +./cpp_example +./test_capi + +git clone https://github.com/z3prover/z3test.git z3test +ls +python z3test/scripts/test_benchmarks.py ./z3 ./z3test/regressions/smt2 \ No newline at end of file diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 4d2f39416..af4be915d 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -117,7 +117,7 @@ namespace opt { void maximize_objectives(expr_ref_vector& blockers); inf_eps const & saved_objective_value(unsigned obj_index); inf_eps current_objective_value(unsigned obj_index); - model* get_model(unsigned obj_index) { return m_models[obj_index]; } + model* get_model_idx(unsigned obj_index) { return m_models[obj_index]; } bool objective_is_model_valid(unsigned obj_index) const { return m_valid_objectives[obj_index]; } diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index f8f75fbfd..dd396126d 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -46,7 +46,7 @@ namespace opt { for (unsigned i = 0; i < src.size(); ++i) { if (src[i] >= dst[i]) { dst[i] = src[i]; - m_models.set(i, m_s->get_model(i)); + m_models.set(i, m_s->get_model_idx(i)); m_s->get_labels(m_labels); m_lower_fmls[i] = fmls[i].get(); if (dst[i].is_pos() && !dst[i].is_finite()) { // review: likely done already. From 96b717f494e02c7e510995d36f156b2546c2f84c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Mar 2018 15:17:41 -0700 Subject: [PATCH 0717/1283] propagate during asymmetric branching Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 14 +++----------- src/sat/sat_solver.cpp | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index a6e036408..3e306370d 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -108,7 +108,6 @@ namespace sat { int64 limit = -m_asymm_branch_limit; std::stable_sort(clauses.begin(), clauses.end(), clause_size_lt()); m_counter -= clauses.size(); - SASSERT(s.m_qhead == s.m_trail.size()); clause_vector::iterator it = clauses.begin(); clause_vector::iterator it2 = it; clause_vector::iterator end = clauses.end(); @@ -120,7 +119,6 @@ namespace sat { } break; } - SASSERT(s.m_qhead == s.m_trail.size()); clause & c = *(*it); if (m_counter < limit || s.inconsistent() || c.was_removed()) { *it2 = *it; @@ -414,19 +412,16 @@ namespace sat { s.assign(c[0], justification()); s.propagate_core(false); scoped_d.del_clause(); - SASSERT(s.inconsistent() || s.m_qhead == s.m_trail.size()); return false; // check_missed_propagation() may fail, since m_clauses is not in a consistent state. case 2: SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); s.mk_bin_clause(c[0], c[1], c.is_learned()); scoped_d.del_clause(); - SASSERT(s.m_qhead == s.m_trail.size()); return false; default: c.shrink(new_sz); if (s.m_config.m_drat) s.m_drat.add(c, true); // if (s.m_config.m_drat) s.m_drat.del(c0); // TBD - SASSERT(s.m_qhead == s.m_trail.size()); return true; } } @@ -445,12 +440,8 @@ namespace sat { bool asymm_branch::process(clause & c) { TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";); SASSERT(s.scope_lvl() == 0); - SASSERT(s.m_qhead == s.m_trail.size()); SASSERT(!s.inconsistent()); -#ifdef Z3DEBUG - unsigned trail_sz = s.m_trail.size(); -#endif unsigned sz = c.size(); SASSERT(sz > 0); unsigned i; @@ -468,14 +459,15 @@ namespace sat { // try asymmetric branching // clause must not be used for propagation + s.propagate(false); + if (s.inconsistent()) + return true; scoped_detach scoped_d(s, c); unsigned new_sz = c.size(); unsigned flip_position = m_rand(c.size()); bool found_conflict = flip_literal_at(c, flip_position, new_sz); SASSERT(!s.inconsistent()); SASSERT(s.scope_lvl() == 0); - SASSERT(trail_sz == s.m_trail.size()); - SASSERT(s.m_qhead == s.m_trail.size()); if (!found_conflict) { // clause size can't be reduced. return true; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a2ef176a1..10b813fc9 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -324,7 +324,7 @@ namespace sat { case 2: mk_bin_clause(lits[0], lits[1], learned); if (learned && m_par) m_par->share_clause(*this, lits[0], lits[1]); - return 0; + return nullptr; case 3: return mk_ter_clause(lits, learned); default: From d60d0b8a7ab5645619c41ca6cbffa3933e438cbf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Mar 2018 15:19:14 -0700 Subject: [PATCH 0718/1283] fix indent Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 3e306370d..d6932c9c0 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -459,9 +459,9 @@ namespace sat { // try asymmetric branching // clause must not be used for propagation - s.propagate(false); - if (s.inconsistent()) - return true; + s.propagate(false); + if (s.inconsistent()) + return true; scoped_detach scoped_d(s, c); unsigned new_sz = c.size(); unsigned flip_position = m_rand(c.size()); From 51d62684e1c94349496513232346e3af114147f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Mar 2018 15:51:00 -0700 Subject: [PATCH 0719/1283] move propagation to after binary clause addition Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 3e306370d..ae6db1f6c 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -416,6 +416,7 @@ namespace sat { case 2: SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); s.mk_bin_clause(c[0], c[1], c.is_learned()); + if (s.m_trail.size() > s.m_qhead) s.propagate_core(false); scoped_d.del_clause(); return false; default: @@ -459,9 +460,7 @@ namespace sat { // try asymmetric branching // clause must not be used for propagation - s.propagate(false); - if (s.inconsistent()) - return true; + scoped_detach scoped_d(s, c); unsigned new_sz = c.size(); unsigned flip_position = m_rand(c.size()); From 78744e589c5a3213929b09174fb19bfb0abf6ee0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Mar 2018 12:19:24 -0700 Subject: [PATCH 0720/1283] add stdbool.h Signed-off-by: Nikolaj Bjorner --- src/api/z3.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/z3.h b/src/api/z3.h index e08b0c073..b29f1d6ba 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -22,6 +22,7 @@ Notes: #define Z3_H_ #include +#include #include "z3_macros.h" #include "z3_api.h" #include "z3_ast_containers.h" From 76dec85c93233922d4c79eb98c2b6c237e8c3b15 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Mar 2018 15:41:53 -0700 Subject: [PATCH 0721/1283] use stdbool #1526 instead of int Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 7 ++++++- src/api/z3_api.h | 2 +- src/api/z3_replayer.cpp | 10 ++++++++++ src/api/z3_replayer.h | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 18878d6ea..0a86db18d 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -957,11 +957,16 @@ def def_API(name, result, params): log_c.write(" }\n") log_c.write(" Au(a%s);\n" % sz) exe_c.write("in.get_uint_array(%s)" % i) - elif ty == INT or ty == BOOL: + elif ty == INT: log_c.write("U(a%s[i]);" % i) log_c.write(" }\n") log_c.write(" Au(a%s);\n" % sz) exe_c.write("in.get_int_array(%s)" % i) + elif ty == BOOL: + log_c.write("U(a%s[i]);" % i) + log_c.write(" }\n") + log_c.write(" Au(a%s);\n" % sz) + exe_c.write("in.get_bool_array(%s)" % i) else: error ("unsupported parameter for %s, %s, %s" % (ty, name, p)) elif kind == OUT_ARRAY: diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 50ed85c70..ab570581b 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -82,7 +82,7 @@ DEFINE_TYPE(Z3_rcf_num); /** \brief Z3 Boolean type. It is just an alias for \c int. */ -typedef int Z3_bool; +typedef bool Z3_bool; /** \brief Z3 string type. It is just an alias for \ccode{const char *}. diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 1515e6df7..fde9b1f48 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -630,6 +630,12 @@ struct z3_replayer::imp { return m_int_arrays[idx].c_ptr(); } + bool * get_bool_array(unsigned pos) const { + check_arg(pos, UINT_ARRAY); + unsigned idx = static_cast(m_args[pos].m_uint); + return reinterpret_cast(m_unsigned_arrays[idx].c_ptr()); + } + Z3_symbol * get_symbol_array(unsigned pos) const { check_arg(pos, SYMBOL_ARRAY); unsigned idx = static_cast(m_args[pos].m_uint); @@ -761,6 +767,10 @@ int * z3_replayer::get_int_array(unsigned pos) const { return m_imp->get_int_array(pos); } +bool * z3_replayer::get_bool_array(unsigned pos) const { + return m_imp->get_bool_array(pos); +} + Z3_symbol * z3_replayer::get_symbol_array(unsigned pos) const { return m_imp->get_symbol_array(pos); } diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h index e1b32af75..b81659945 100644 --- a/src/api/z3_replayer.h +++ b/src/api/z3_replayer.h @@ -51,6 +51,7 @@ public: unsigned * get_uint_array(unsigned pos) const; int * get_int_array(unsigned pos) const; + bool * get_bool_array(unsigned pos) const; Z3_symbol * get_symbol_array(unsigned pos) const; void ** get_obj_array(unsigned pos) const; From 32c9af5e5a4b119dc09eaae2bd05acf5ec7859db Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Mar 2018 16:16:25 -0700 Subject: [PATCH 0722/1283] fix use of Z3_bool -> Z3_lbool Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index b947928a7..c2b1f0af9 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2452,7 +2452,6 @@ Z3_lbool ext_check(Z3_ext_context ctx) { } printf("\n"); } - return result; } @@ -2464,7 +2463,7 @@ void incremental_example1() { Z3_context ctx = ext_ctx->m_context; Z3_ast x, y, z, two, one; unsigned c1, c2, c3, c4; - Z3_bool result; + Z3_lbool result; printf("\nincremental_example1\n"); LOG_MSG("incremental_example1"); @@ -2485,7 +2484,7 @@ void incremental_example1() { c4 = assert_retractable_cnstr(ext_ctx, Z3_mk_lt(ctx, y, one)); result = ext_check(ext_ctx); - if (result != Z3_L_FALSE) + if (result != Z3_L_FALSE) exitf("bug in Z3"); printf("unsat\n"); From b9f2188fc02c0e171103b383a8684a5199a3c232 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Mar 2018 22:34:07 +0700 Subject: [PATCH 0723/1283] Update Z3_bool doc. --- src/api/z3_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index ab570581b..2b46127fa 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -80,7 +80,7 @@ DEFINE_TYPE(Z3_rcf_num); */ /** - \brief Z3 Boolean type. It is just an alias for \c int. + \brief Z3 Boolean type. It is just an alias for \c bool. */ typedef bool Z3_bool; From 16a2ad9afd8bed86fc7d5d2f40ca3d48b7fedd07 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 30 Mar 2018 23:06:24 +0700 Subject: [PATCH 0724/1283] Use stdint.h for int64_t / uint64_t in API. Now that we can use stdint.h, we can use it to portably define 64 bit integer types for use in the API. --- scripts/update_api.py | 5 +---- src/api/api_datalog.cpp | 4 ++-- src/api/api_fpa.cpp | 6 +++--- src/api/api_numeral.cpp | 16 +++++++------- src/api/api_stats.cpp | 2 +- src/api/c++/z3++.h | 48 ++++++++++++++++++++--------------------- src/api/z3.h | 1 + src/api/z3_api.h | 36 ++++++++++++------------------- src/api/z3_fpa.h | 6 +++--- src/api/z3_logger.h | 4 ++-- src/api/z3_replayer.cpp | 32 +++++++++++++-------------- src/api/z3_replayer.h | 8 +++---- 12 files changed, 79 insertions(+), 89 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 0a86db18d..8a7b33efd 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -60,7 +60,7 @@ FIRST_OBJ_ID = 100 def is_obj(ty): return ty >= FIRST_OBJ_ID -Type2Str = { VOID : 'void', VOID_PTR : 'void*', INT : 'int', UINT : 'unsigned', INT64 : '__int64', UINT64 : '__uint64', DOUBLE : 'double', +Type2Str = { VOID : 'void', VOID_PTR : 'void*', INT : 'int', UINT : 'unsigned', INT64 : 'int64_t', UINT64 : 'uint64_t', DOUBLE : 'double', FLOAT : 'float', STRING : 'Z3_string', STRING_PTR : 'Z3_string_ptr', BOOL : 'Z3_bool', SYMBOL : 'Z3_symbol', PRINT_MODE : 'Z3_ast_print_mode', ERROR_CODE : 'Z3_error_code' } @@ -577,9 +577,6 @@ def mk_java(java_dir, package_name): java_wrapper = open(java_wrapperf, 'w') pkg_str = package_name.replace('.', '_') java_wrapper.write('// Automatically generated file\n') - java_wrapper.write('#ifdef _CYGWIN\n') - java_wrapper.write('typedef long long __int64;\n') - java_wrapper.write('#endif\n') java_wrapper.write('#include\n') java_wrapper.write('#include\n') java_wrapper.write('#include"z3.h"\n') diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 5e0082f09..ce2373498 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -189,7 +189,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, __uint64 size) { + Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, uint64_t size) { Z3_TRY; LOG_Z3_mk_finite_domain_sort(c, name, size); RESET_ERROR_CODE(); @@ -199,7 +199,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, __uint64 * out) { + Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, uint64_t * out) { Z3_TRY; if (out) { *out = 0; diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 972505ca2..261198354 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -358,7 +358,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, Z3_bool sgn, __int64 exp, __uint64 sig, Z3_sort ty) { + Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, Z3_bool sgn, int64_t exp, uint64_t sig, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_fpa_numeral_int64_uint64(c, sgn, exp, sig, ty); RESET_ERROR_CODE(); @@ -1035,7 +1035,7 @@ extern "C" { Z3_CATCH_RETURN(""); } - Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, __uint64 * n) { + Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, uint64_t * n) { Z3_TRY; LOG_Z3_fpa_get_numeral_significand_uint64(c, t, n); RESET_ERROR_CODE(); @@ -1113,7 +1113,7 @@ extern "C" { Z3_CATCH_RETURN(""); } - Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, __int64 * n, Z3_bool biased) { + Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, int64_t * n, Z3_bool biased) { Z3_TRY; LOG_Z3_fpa_get_numeral_exponent_int64(c, t, n, biased); RESET_ERROR_CODE(); diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 5aa762a96..ab379c3de 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -116,7 +116,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_int64(Z3_context c, long long value, Z3_sort ty) { + Z3_ast Z3_API Z3_mk_int64(Z3_context c, int64_t value, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_int64(c, value, ty); RESET_ERROR_CODE(); @@ -129,7 +129,7 @@ extern "C" { Z3_CATCH_RETURN(nullptr); } - Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, unsigned long long value, Z3_sort ty) { + Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, uint64_t value, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_unsigned_int64(c, value, ty); RESET_ERROR_CODE(); @@ -262,7 +262,7 @@ extern "C" { Z3_CATCH_RETURN(""); } - Z3_bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, long long* num, long long* den) { + Z3_bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, int64_t* num, int64_t* den) { Z3_TRY; // 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_small(c, a, num, den); @@ -296,7 +296,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return Z3_FALSE; } - long long l; + int64_t l; if (Z3_get_numeral_int64(c, v, &l) && l >= INT_MIN && l <= INT_MAX) { *i = static_cast(l); return Z3_TRUE; @@ -314,7 +314,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return Z3_FALSE; } - unsigned long long l; + uint64_t l; if (Z3_get_numeral_uint64(c, v, &l) && (l <= 0xFFFFFFFF)) { *u = static_cast(l); return Z3_TRUE; @@ -323,7 +323,7 @@ extern "C" { Z3_CATCH_RETURN(Z3_FALSE); } - Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, unsigned long long* u) { + Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, uint64_t* u) { Z3_TRY; // 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_uint64(c, v, u); @@ -343,7 +343,7 @@ extern "C" { Z3_CATCH_RETURN(Z3_FALSE); } - Z3_bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, long long* i) { + Z3_bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, int64_t* i) { Z3_TRY; // 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_int64(c, v, i); @@ -362,7 +362,7 @@ extern "C" { Z3_CATCH_RETURN(Z3_FALSE); } - Z3_bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, long long* num, long long* den) { + Z3_bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, int64_t* num, int64_t* den) { Z3_TRY; // 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_rational_int64(c, v, num, den); diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index a92b908dc..2e1dac4de 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -130,7 +130,7 @@ extern "C" { Z3_CATCH_RETURN(0.0); } - __uint64 Z3_API Z3_get_estimated_alloc_size(void) { + uint64_t Z3_API Z3_get_estimated_alloc_size(void) { return memory::get_allocation_size(); } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 42467cb22..b3df2d53a 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -294,21 +294,21 @@ namespace z3 { expr int_val(int n); expr int_val(unsigned n); - expr int_val(__int64 n); - expr int_val(__uint64 n); + expr int_val(int64_t n); + expr int_val(uint64_t n); expr int_val(char const * n); expr real_val(int n, int d); expr real_val(int n); expr real_val(unsigned n); - expr real_val(__int64 n); - expr real_val(__uint64 n); + expr real_val(int64_t n); + expr real_val(uint64_t n); expr real_val(char const * n); expr bv_val(int n, unsigned sz); expr bv_val(unsigned n, unsigned sz); - expr bv_val(__int64 n, unsigned sz); - expr bv_val(__uint64 n, unsigned sz); + expr bv_val(int64_t n, unsigned sz); + expr bv_val(uint64_t n, unsigned sz); expr bv_val(char const * n, unsigned sz); expr bv_val(unsigned n, bool const* bits); @@ -660,8 +660,8 @@ namespace z3 { small integers, 64 bit integers or rational or decimal strings. */ bool is_numeral() const { return kind() == Z3_NUMERAL_AST; } - bool is_numeral_i64(__int64& i) const { bool r = 0 != Z3_get_numeral_int64(ctx(), m_ast, &i); check_error(); return r;} - bool is_numeral_u64(__uint64& i) const { bool r = 0 != Z3_get_numeral_uint64(ctx(), m_ast, &i); check_error(); return r;} + bool is_numeral_i64(int64_t& i) const { bool r = 0 != Z3_get_numeral_int64(ctx(), m_ast, &i); check_error(); return r;} + bool is_numeral_u64(uint64_t& i) const { bool r = 0 != Z3_get_numeral_uint64(ctx(), m_ast, &i); check_error(); return r;} bool is_numeral_i(int& i) const { bool r = 0 != Z3_get_numeral_int(ctx(), m_ast, &i); check_error(); return r;} bool is_numeral_u(unsigned& i) const { bool r = 0 != Z3_get_numeral_uint(ctx(), m_ast, &i); check_error(); return r;} bool is_numeral(std::string& s) const { if (!is_numeral()) return false; s = Z3_get_numeral_string(ctx(), m_ast); check_error(); return true; } @@ -744,35 +744,35 @@ namespace z3 { } /** - \brief Return __int64 value of numeral, throw if result cannot fit in - __int64 + \brief Return \c int64_t value of numeral, throw if result cannot fit in + \c int64_t. \pre is_numeral() */ - __int64 get_numeral_int64() const { + int64_t get_numeral_int64() const { assert(is_numeral()); - __int64 result = 0; + int64_t result = 0; if (!is_numeral_i64(result)) { assert(ctx().enable_exceptions()); if (!ctx().enable_exceptions()) return 0; - Z3_THROW(exception("numeral does not fit in machine __int64")); + Z3_THROW(exception("numeral does not fit in machine int64_t")); } return result; } /** - \brief Return __uint64 value of numeral, throw if result cannot fit in - __uint64 + \brief Return \c uint64_t value of numeral, throw if result cannot fit in + \c uint64_t. \pre is_numeral() */ - __uint64 get_numeral_uint64() const { + uint64_t get_numeral_uint64() const { assert(is_numeral()); - __uint64 result = 0; + uint64_t result = 0; if (!is_numeral_u64(result)) { assert(ctx().enable_exceptions()); if (!ctx().enable_exceptions()) return 0; - Z3_THROW(exception("numeral does not fit in machine __uint64")); + Z3_THROW(exception("numeral does not fit in machine uint64_t")); } return result; } @@ -2526,21 +2526,21 @@ namespace z3 { inline expr context::int_val(int n) { Z3_ast r = Z3_mk_int(m_ctx, n, int_sort()); check_error(); return expr(*this, r); } inline expr context::int_val(unsigned n) { Z3_ast r = Z3_mk_unsigned_int(m_ctx, n, int_sort()); check_error(); return expr(*this, r); } - inline expr context::int_val(__int64 n) { Z3_ast r = Z3_mk_int64(m_ctx, n, int_sort()); check_error(); return expr(*this, r); } - inline expr context::int_val(__uint64 n) { Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, int_sort()); check_error(); return expr(*this, r); } + inline expr context::int_val(int64_t n) { Z3_ast r = Z3_mk_int64(m_ctx, n, int_sort()); check_error(); return expr(*this, r); } + inline expr context::int_val(uint64_t n) { Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, int_sort()); check_error(); return expr(*this, r); } inline expr context::int_val(char const * n) { Z3_ast r = Z3_mk_numeral(m_ctx, n, int_sort()); check_error(); return expr(*this, r); } inline expr context::real_val(int n, int d) { Z3_ast r = Z3_mk_real(m_ctx, n, d); check_error(); return expr(*this, r); } inline expr context::real_val(int n) { Z3_ast r = Z3_mk_int(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } inline expr context::real_val(unsigned n) { Z3_ast r = Z3_mk_unsigned_int(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } - inline expr context::real_val(__int64 n) { Z3_ast r = Z3_mk_int64(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } - inline expr context::real_val(__uint64 n) { Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } + inline expr context::real_val(int64_t n) { Z3_ast r = Z3_mk_int64(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } + inline expr context::real_val(uint64_t n) { Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } inline expr context::real_val(char const * n) { Z3_ast r = Z3_mk_numeral(m_ctx, n, real_sort()); check_error(); return expr(*this, r); } inline expr context::bv_val(int n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_int(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr context::bv_val(unsigned n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_unsigned_int(m_ctx, n, s); check_error(); return expr(*this, r); } - inline expr context::bv_val(__int64 n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_int64(m_ctx, n, s); check_error(); return expr(*this, r); } - inline expr context::bv_val(__uint64 n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, s); check_error(); return expr(*this, r); } + inline expr context::bv_val(int64_t n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_int64(m_ctx, n, s); check_error(); return expr(*this, r); } + inline expr context::bv_val(uint64_t n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr context::bv_val(char const * n, unsigned sz) { sort s = bv_sort(sz); Z3_ast r = Z3_mk_numeral(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr context::bv_val(unsigned n, bool const* bits) { array _bits(n); diff --git a/src/api/z3.h b/src/api/z3.h index b29f1d6ba..37ea68f84 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -23,6 +23,7 @@ Notes: #include #include +#include #include "z3_macros.h" #include "z3_api.h" #include "z3_ast_containers.h" diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 2b46127fa..ac6c39137 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -36,14 +36,6 @@ DEFINE_TYPE(Z3_fixedpoint); DEFINE_TYPE(Z3_optimize); DEFINE_TYPE(Z3_rcf_num); -#ifndef __int64 -#define __int64 long long -#endif - -#ifndef __uint64 -#define __uint64 unsigned long long -#endif - /** \defgroup capi C API */ /*@{*/ @@ -1843,7 +1835,7 @@ extern "C" { def_API('Z3_mk_finite_domain_sort', SORT, (_in(CONTEXT), _in(SYMBOL), _in(UINT64))) */ - Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, __uint64 size); + Z3_sort Z3_API Z3_mk_finite_domain_sort(Z3_context c, Z3_symbol name, uint64_t size); /** \brief Create an array type. @@ -3200,26 +3192,26 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be used to create numerals that fit in a machine __int64 integer. + This function can be used to create numerals that fit in a machine \c int64_t integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral def_API('Z3_mk_int64', AST, (_in(CONTEXT), _in(INT64), _in(SORT))) */ - Z3_ast Z3_API Z3_mk_int64(Z3_context c, __int64 v, Z3_sort ty); + Z3_ast Z3_API Z3_mk_int64(Z3_context c, int64_t v, Z3_sort ty); /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be used to create numerals that fit in a machine __uint64 integer. + This function can be used to create numerals that fit in a machine \c uint64_t integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral def_API('Z3_mk_unsigned_int64', AST, (_in(CONTEXT), _in(UINT64), _in(SORT))) */ - Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, __uint64 v, Z3_sort ty); + Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, uint64_t v, Z3_sort ty); /** \brief create a bit-vector numeral from a vector of Booleans. @@ -3868,7 +3860,7 @@ extern "C" { def_API('Z3_get_finite_domain_sort_size', BOOL, (_in(CONTEXT), _in(SORT), _out(UINT64))) */ - Z3_bool_opt Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, __uint64* r); + Z3_bool_opt Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, uint64_t* r); /** \brief Return the domain of the given array sort. @@ -4425,7 +4417,7 @@ extern "C" { def_API('Z3_get_numeral_small', BOOL, (_in(CONTEXT), _in(AST), _out(INT64), _out(INT64))) */ - Z3_bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, __int64* num, __int64* den); + Z3_bool Z3_API Z3_get_numeral_small(Z3_context c, Z3_ast a, int64_t* num, int64_t* den); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if @@ -4453,7 +4445,7 @@ extern "C" { /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit in a machine __uint64 int. Return Z3_TRUE if the call succeeded. + the value can fit in a machine \c uint64_t int. Return Z3_TRUE if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4461,11 +4453,11 @@ extern "C" { def_API('Z3_get_numeral_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) */ - Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, __uint64* u); + Z3_bool Z3_API Z3_get_numeral_uint64(Z3_context c, Z3_ast v, uint64_t* u); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit in a machine __int64 int. Return Z3_TRUE if the call succeeded. + the value can fit in a machine \c int64_t int. Return Z3_TRUE if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4473,11 +4465,11 @@ extern "C" { def_API('Z3_get_numeral_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64))) */ - Z3_bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, __int64* i); + Z3_bool Z3_API Z3_get_numeral_int64(Z3_context c, Z3_ast v, int64_t* i); /** \brief Similar to #Z3_get_numeral_string, but only succeeds if - the value can fit as a rational number as machine __int64 int. Return Z3_TRUE if the call succeeded. + the value can fit as a rational number as machine \c int64_t int. Return Z3_TRUE if the call succeeded. \pre Z3_get_ast_kind(c, v) == Z3_NUMERAL_AST @@ -4485,7 +4477,7 @@ extern "C" { def_API('Z3_get_numeral_rational_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64), _out(INT64))) */ - Z3_bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, __int64* num, __int64* den); + Z3_bool Z3_API Z3_get_numeral_rational_int64(Z3_context c, Z3_ast v, int64_t* num, int64_t* den); /** \brief Return a lower bound for the given real algebraic number. @@ -6248,7 +6240,7 @@ extern "C" { def_API('Z3_get_estimated_alloc_size', UINT64, ()) */ - __uint64 Z3_API Z3_get_estimated_alloc_size(void); + uint64_t Z3_API Z3_get_estimated_alloc_size(void); /*@}*/ diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 7d237c6e7..f6001e87d 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -349,7 +349,7 @@ extern "C" { def_API('Z3_mk_fpa_numeral_int64_uint64', AST, (_in(CONTEXT), _in(BOOL), _in(INT64), _in(UINT64), _in(SORT))) */ - Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, Z3_bool sgn, __int64 exp, __uint64 sig, Z3_sort ty); + Z3_ast Z3_API Z3_mk_fpa_numeral_int64_uint64(Z3_context c, Z3_bool sgn, int64_t exp, uint64_t sig, Z3_sort ty); /** \brief Floating-point absolute value @@ -956,7 +956,7 @@ extern "C" { def_API('Z3_fpa_get_numeral_significand_uint64', BOOL, (_in(CONTEXT), _in(AST), _out(UINT64))) */ - Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, __uint64 * n); + Z3_bool Z3_API Z3_fpa_get_numeral_significand_uint64(Z3_context c, Z3_ast t, uint64_t * n); /** \brief Return the exponent value of a floating-point numeral as a string. @@ -985,7 +985,7 @@ extern "C" { def_API('Z3_fpa_get_numeral_exponent_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64), _in(BOOL))) */ - Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, __int64 * n, Z3_bool biased); + Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(Z3_context c, Z3_ast t, int64_t * n, Z3_bool biased); /** \brief Retrieves the exponent of a floating-point literal as a bit-vector expression. diff --git a/src/api/z3_logger.h b/src/api/z3_logger.h index dd2816bff..357d79bcb 100644 --- a/src/api/z3_logger.h +++ b/src/api/z3_logger.h @@ -23,8 +23,8 @@ static std::ostream & operator<<(std::ostream & out, ll_escaped const & d); static void __declspec(noinline) R() { *g_z3_log << "R\n"; g_z3_log->flush(); } static void __declspec(noinline) P(void * obj) { *g_z3_log << "P " << obj << "\n"; g_z3_log->flush(); } -static void __declspec(noinline) I(__int64 i) { *g_z3_log << "I " << i << "\n"; g_z3_log->flush(); } -static void __declspec(noinline) U(__uint64 u) { *g_z3_log << "U " << u << "\n"; g_z3_log->flush(); } +static void __declspec(noinline) I(int64_t i) { *g_z3_log << "I " << i << "\n"; g_z3_log->flush(); } +static void __declspec(noinline) U(uint64_t u) { *g_z3_log << "U " << u << "\n"; g_z3_log->flush(); } static void __declspec(noinline) D(double d) { *g_z3_log << "D " << d << "\n"; g_z3_log->flush(); } static void __declspec(noinline) S(Z3_string str) { *g_z3_log << "S \"" << ll_escaped(str) << "\"\n"; g_z3_log->flush(); } static void __declspec(noinline) Sy(Z3_symbol sym) { diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index fde9b1f48..0e8297879 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -40,8 +40,8 @@ struct z3_replayer::imp { int m_line; // line svector m_string; symbol m_id; - __int64 m_int64; - __uint64 m_uint64; + int64_t m_int64; + uint64_t m_uint64; double m_double; float m_float; size_t m_ptr; @@ -85,8 +85,8 @@ struct z3_replayer::imp { struct value { value_kind m_kind; union { - __int64 m_int; - __uint64 m_uint; + int64_t m_int; + uint64_t m_uint; double m_double; char const * m_str; void * m_obj; @@ -95,8 +95,8 @@ struct z3_replayer::imp { value():m_kind(OBJECT), m_int(0) {} value(void * obj):m_kind(OBJECT), m_obj(obj) {} value(value_kind k, char const * str):m_kind(k), m_str(str) {} - value(value_kind k, __uint64 u):m_kind(k), m_uint(u) {} - value(value_kind k, __int64 i):m_kind(k), m_int(i) {} + value(value_kind k, uint64_t u):m_kind(k), m_uint(u) {} + value(value_kind k, int64_t i):m_kind(k), m_int(i) {} value(value_kind k, double d):m_kind(k), m_double(d) {} value(value_kind k, float f):m_kind(k), m_float(f) {} }; @@ -342,7 +342,7 @@ struct z3_replayer::imp { unsigned asz = m_args.size(); if (sz > asz) throw z3_replayer_exception("invalid array size"); - __uint64 aidx; + uint64_t aidx; value_kind nk; for (unsigned i = asz - sz; i < asz; i++) { if (m_args[i].m_kind != k) @@ -400,7 +400,7 @@ struct z3_replayer::imp { #define TICK_FREQUENCY 100000 void parse() { - unsigned long long counter = 0; + uint64_t counter = 0; unsigned tick = 0; while (true) { IF_VERBOSE(1, { @@ -577,7 +577,7 @@ struct z3_replayer::imp { return static_cast(m_args[pos].m_int); } - __int64 get_int64(unsigned pos) const { + int64_t get_int64(unsigned pos) const { check_arg(pos, INT64); return m_args[pos].m_int; } @@ -587,7 +587,7 @@ struct z3_replayer::imp { return static_cast(m_args[pos].m_uint); } - __uint64 get_uint64(unsigned pos) const { + uint64_t get_uint64(unsigned pos) const { check_arg(pos, UINT64); return m_args[pos].m_uint; } @@ -656,7 +656,7 @@ struct z3_replayer::imp { return reinterpret_cast(&(m_args[pos].m_int)); } - __int64 * get_int64_addr(unsigned pos) { + int64_t * get_int64_addr(unsigned pos) { check_arg(pos, INT64); return &(m_args[pos].m_int); } @@ -666,7 +666,7 @@ struct z3_replayer::imp { return reinterpret_cast(&(m_args[pos].m_uint)); } - __uint64 * get_uint64_addr(unsigned pos) { + uint64_t * get_uint64_addr(unsigned pos) { check_arg(pos, UINT64); return &(m_args[pos].m_uint); } @@ -731,11 +731,11 @@ unsigned z3_replayer::get_uint(unsigned pos) const { return m_imp->get_uint(pos); } -__int64 z3_replayer::get_int64(unsigned pos) const { +int64_t z3_replayer::get_int64(unsigned pos) const { return m_imp->get_int64(pos); } -__uint64 z3_replayer::get_uint64(unsigned pos) const { +uint64_t z3_replayer::get_uint64(unsigned pos) const { return m_imp->get_uint64(pos); } @@ -783,7 +783,7 @@ int * z3_replayer::get_int_addr(unsigned pos) { return m_imp->get_int_addr(pos); } -__int64 * z3_replayer::get_int64_addr(unsigned pos) { +int64_t * z3_replayer::get_int64_addr(unsigned pos) { return m_imp->get_int64_addr(pos); } @@ -791,7 +791,7 @@ unsigned * z3_replayer::get_uint_addr(unsigned pos) { return m_imp->get_uint_addr(pos); } -__uint64 * z3_replayer::get_uint64_addr(unsigned pos) { +uint64_t * z3_replayer::get_uint64_addr(unsigned pos) { return m_imp->get_uint64_addr(pos); } diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h index b81659945..8e423cc09 100644 --- a/src/api/z3_replayer.h +++ b/src/api/z3_replayer.h @@ -40,8 +40,8 @@ public: int get_int(unsigned pos) const; unsigned get_uint(unsigned pos) const; - __int64 get_int64(unsigned pos) const; - __uint64 get_uint64(unsigned pos) const; + int64_t get_int64(unsigned pos) const; + uint64_t get_uint64(unsigned pos) const; float get_float(unsigned pos) const; double get_double(unsigned pos) const; bool get_bool(unsigned pos) const; @@ -56,9 +56,9 @@ public: void ** get_obj_array(unsigned pos) const; int * get_int_addr(unsigned pos); - __int64 * get_int64_addr(unsigned pos); + int64_t * get_int64_addr(unsigned pos); unsigned * get_uint_addr(unsigned pos); - __uint64 * get_uint64_addr(unsigned pos); + uint64_t * get_uint64_addr(unsigned pos); Z3_string * get_str_addr(unsigned pos); void ** get_obj_addr(unsigned pos); From aa2721517ba17938f257e678debda78f87d3d456 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Mar 2018 16:24:22 -0700 Subject: [PATCH 0725/1283] model conversion and acce tracking Signed-off-by: Nikolaj Bjorner --- .../ackermannize_bv_tactic.cpp | 2 +- src/sat/sat_asymm_branch.cpp | 22 +++++++--- src/sat/sat_model_converter.cpp | 10 ++--- src/sat/sat_simplifier.cpp | 43 +++++++++++++++---- src/sat/sat_solver.cpp | 8 ++++ src/tactic/goal.cpp | 3 ++ 6 files changed, 67 insertions(+), 21 deletions(-) diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index f0e960644..df230a7e2 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -52,7 +52,7 @@ public: result.push_back(resg.get()); // report model if (g->models_enabled()) { - g->add(mk_ackermannize_bv_model_converter(m, lackr.get_info())); + resg->add(mk_ackermannize_bv_model_converter(m, lackr.get_info())); } resg->inc_depth(); diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 971e86d95..65003a6e4 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -333,13 +333,18 @@ namespace sat { if (!m_to_delete.empty()) { unsigned j = 0; for (unsigned i = 0; i < c.size(); ++i) { - if (!m_to_delete.contains(c[i])) { - c[j] = c[i]; - ++j; - } - else { - m_pos.erase(c[i]); - m_neg.erase(~c[i]); + literal lit = c[i]; + switch (s.value(lit)) { + case l_true: + scoped_d.del_clause(); + return false; + case l_false: + break; + default: + if (!m_to_delete.contains(lit)) { + c[j++] = lit; + } + break; } } return re_attach(scoped_d, c, j); @@ -359,6 +364,7 @@ namespace sat { } bool asymm_branch::flip_literal_at(clause const& c, unsigned flip_index, unsigned& new_sz) { + VERIFY(s.m_trail.size() == s.m_qhead); bool found_conflict = false; unsigned i = 0, sz = c.size(); s.push(); @@ -399,6 +405,7 @@ namespace sat { } bool asymm_branch::re_attach(scoped_detach& scoped_d, clause& c, unsigned new_sz) { + VERIFY(s.m_trail.size() == s.m_qhead); m_elim_literals += c.size() - new_sz; if (c.is_learned()) { m_elim_learned_literals += c.size() - new_sz; @@ -415,6 +422,7 @@ namespace sat { return false; // check_missed_propagation() may fail, since m_clauses is not in a consistent state. case 2: SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); + VERIFY(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); s.mk_bin_clause(c[0], c[1], c.is_learned()); if (s.m_trail.size() > s.m_qhead) s.propagate_core(false); scoped_d.del_clause(); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 9bda5cf3d..6b0eb1a7c 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -75,7 +75,7 @@ namespace sat { void model_converter::operator()(model & m) const { vector::const_iterator begin = m_entries.begin(); vector::const_iterator it = m_entries.end(); - bool first = true; + bool first = false; // true; //SASSERT(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; @@ -99,8 +99,8 @@ namespace sat { process_stack(m, clause, st->stack()); } sat = false; - if (false && first && m_solver && !m_solver->check_clauses(m)) { - display(std::cout, *it) << "\n"; + if (first && m_solver && !m_solver->check_clauses(m)) { + IF_VERBOSE(0, display(verbose_stream() << "after processing stack\n", *it) << "\n"); first = false; } ++index; @@ -125,8 +125,8 @@ namespace sat { m[v] = sign ? l_false : l_true; // if (first) std::cout << "set: " << l << "\n"; sat = true; - if (false && first && m_solver && !m_solver->check_clauses(m)) { - display(std::cout, *it) << "\n";; + if (first && m_solver && !m_solver->check_clauses(m)) { + IF_VERBOSE(0, display(verbose_stream() << "after flipping undef\n", *it) << "\n"); first = false; } } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index be0222d3b..6ef0be83a 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -939,6 +939,19 @@ namespace sat { bool operator==(clause_ante const& a) const { return a.m_lit1 == m_lit1 && a.m_lit2 == m_lit2 && a.m_clause == m_clause; } + std::ostream& display(std::ostream& out) const { + if (cls()) { + out << *cls() << " "; + } + if (lit1() != null_literal) { + out << lit1() << " "; + } + if (lit2() != null_literal) { + out << lit2() << " "; + } + out << "\n"; + return out; + } }; class queue { @@ -1154,10 +1167,14 @@ namespace sat { \brief idx is the index of the blocked literal. m_tautology contains literals that were used to establish that the current members of m_covered_clause is blocked. This routine removes literals that were not relevant to establishing it was blocked. + + It has a bug: literals that are used to prune tautologies during resolution intersection should be included + in the dependencies. */ void minimize_covered_clause(unsigned idx) { // IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause // << " @ " << idx << "\n" << "tautology: " << m_tautology << "\n";); + literal _blocked = m_covered_clause[idx]; for (literal l : m_tautology) VERIFY(s.is_marked(l)); for (literal l : m_covered_clause) s.unmark_visited(l); for (literal l : m_tautology) s.mark_visited(l); @@ -1167,8 +1184,18 @@ namespace sat { if (m_covered_antecedent[i] == clause_ante()) s.mark_visited(lit); if (s.is_marked(lit)) idx = i; } + if (_blocked.var() == 16774 && false) { + IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n"; + verbose_stream() << "tautology: " << m_tautology << "\n"; + verbose_stream() << "index: " << idx << "\n"; + for (unsigned i = idx; i > 0; --i) { + m_covered_antecedent[i].display(verbose_stream() << "ante " << m_covered_clause[i] << ":"); + }); + } for (unsigned i = idx; i > 0; --i) { literal lit = m_covered_clause[i]; + s.mark_visited(lit); + continue; if (!s.is_marked(lit)) continue; clause_ante const& ante = m_covered_antecedent[i]; if (ante.cls()) { @@ -1205,6 +1232,9 @@ namespace sat { // unsigned sz0 = m_covered_clause.size(); m_covered_clause.resize(j); VERIFY(j >= m_clause.size()); + if (_blocked.var() == 16774 && false) { + IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n"); + } // IF_VERBOSE(0, verbose_stream() << "reduced from size " << sz0 << " to " << m_covered_clause << "\n" << m_clause << "\n";); } @@ -1282,7 +1312,7 @@ namespace sat { for (unsigned i = 0; i < m_covered_clause.size(); ++i) { literal lit = m_covered_clause[i]; if (resolution_intersection(lit, false)) { - blocked = m_covered_clause[i]; + blocked = m_covered_clause[i]; minimize_covered_clause(i); return true; } @@ -1531,13 +1561,10 @@ namespace sat { return; } for (literal l2 : m_intersection) { - l2.neg(); - watched* w = find_binary_watch(s.get_wlist(~l), l2); + watched* w = find_binary_watch(s.get_wlist(~l), ~l2); if (!w) { - IF_VERBOSE(100, verbose_stream() << "bca " << l << " " << l2 << "\n";); - s.get_wlist(~l).push_back(watched(l2, true)); - VERIFY(!find_binary_watch(s.get_wlist(~l2), l)); - s.get_wlist(~l2).push_back(watched(l, true)); + IF_VERBOSE(10, verbose_stream() << "bca " << l << " " << ~l2 << "\n";); + s.s.mk_bin_clause(l, ~l2, true); ++s.m_num_bca; } } @@ -1997,7 +2024,7 @@ namespace sat { sat_simplifier_params p(_p); m_cce = p.cce(); m_acce = p.acce(); - m_bca = p.bca(); + m_bca = false && p.bca(); // disabled m_abce = p.abce(); m_ate = p.ate(); m_bce_delay = p.bce_delay(); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 10b813fc9..1617b487b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -333,6 +333,13 @@ namespace sat { } void solver::mk_bin_clause(literal l1, literal l2, bool learned) { +#if 0 + if ((l1 == literal(5981, false) && l2 == literal(16764, false)) || + (l2 == literal(5981, false) && l1 == literal(16764, false))) { + IF_VERBOSE(0, display(verbose_stream())); + //VERIFY(false); + } +#endif if (find_binary_watch(get_wlist(~l1), ~l2)) { assign(l1, justification()); return; @@ -1656,6 +1663,7 @@ namespace sat { if (!check_clauses(m_model)) { IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";); + IF_VERBOSE(10, m_mc.display(verbose_stream())); throw solver_exception("check model failed"); } diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index c7b730099..5252a410d 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -85,6 +85,9 @@ goal::goal(goal const & src, bool): m_core_enabled(src.unsat_core_enabled()), m_inconsistent(false), m_precision(src.m_precision) { + m_mc = src.m_mc.get(); + m_pc = src.m_pc.get(); + m_dc = src.m_dc.get(); } goal::~goal() { From 2fa304d8dea48687cdc6dec79b81323a7ea85825 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Sat, 31 Mar 2018 14:45:04 +0700 Subject: [PATCH 0726/1283] Remove int64, uint64 typedefs in favor of int64_t / uint64_t. --- src/api/api_context.cpp | 2 +- src/api/api_numeral.cpp | 2 +- src/ast/ast.h | 12 +-- src/ast/ast_smt2_pp.cpp | 2 +- src/ast/bv_decl_plugin.h | 2 +- src/ast/dl_decl_plugin.cpp | 12 +-- src/ast/dl_decl_plugin.h | 12 +-- src/ast/fpa/fpa2bv_converter.cpp | 2 +- src/ast/rewriter/bv_rewriter.cpp | 26 +++--- src/ast/rewriter/dl_rewriter.cpp | 2 +- src/math/hilbert/hilbert_basis.h | 2 +- src/math/polynomial/polynomial.cpp | 4 +- src/math/polynomial/polynomial.h | 4 +- src/math/polynomial/upolynomial.h | 4 +- .../polynomial/upolynomial_factorization.cpp | 6 +- src/math/subpaving/subpaving.cpp | 4 +- src/math/subpaving/subpaving_t.h | 16 ++-- src/muz/base/dl_context.cpp | 20 ++--- src/muz/base/dl_context.h | 10 +-- src/muz/base/dl_costs.cpp | 2 +- src/muz/base/dl_costs.h | 2 +- src/muz/base/dl_util.cpp | 12 +-- src/muz/base/dl_util.h | 6 +- src/muz/ddnf/ddnf.cpp | 4 +- src/muz/fp/datalog_parser.cpp | 32 +++---- src/muz/rel/dl_base.cpp | 2 +- src/muz/rel/dl_base.h | 2 +- src/muz/rel/dl_relation_manager.cpp | 10 +-- src/muz/rel/dl_sparse_table.cpp | 4 +- src/muz/rel/dl_sparse_table.h | 18 ++-- src/muz/rel/doc.cpp | 4 +- src/muz/rel/doc.h | 4 +- src/muz/rel/rel_context.cpp | 2 +- src/muz/rel/tbv.cpp | 6 +- src/muz/rel/tbv.h | 6 +- src/muz/rel/udoc_relation.cpp | 4 +- src/qe/qe_dl_plugin.cpp | 8 +- src/shell/datalog_frontend.cpp | 2 +- src/smt/smt_context.cpp | 2 +- src/smt/theory_dl.cpp | 6 +- src/tactic/bv/bv_bounds_tactic.cpp | 14 +-- src/test/algebraic.cpp | 2 +- src/test/dl_query.cpp | 6 +- src/test/mpff.cpp | 30 +++---- src/test/mpfx.cpp | 2 +- src/test/mpq.cpp | 2 +- src/test/mpz.cpp | 6 +- src/test/prime_generator.cpp | 6 +- src/test/rational.cpp | 4 +- src/util/checked_int64.h | 22 ++--- src/util/double_manager.h | 8 +- src/util/hash.h | 4 +- src/util/hwf.cpp | 36 ++++---- src/util/hwf.h | 8 +- src/util/inf_eps_rational.h | 4 +- src/util/inf_int_rational.h | 4 +- src/util/inf_rational.h | 4 +- src/util/inf_s_integer.h | 4 +- src/util/mpbq.cpp | 2 +- src/util/mpbq.h | 2 +- src/util/mpf.cpp | 16 ++-- src/util/mpf.h | 4 +- src/util/mpff.cpp | 76 ++++++++-------- src/util/mpff.h | 22 ++--- src/util/mpfx.cpp | 32 +++---- src/util/mpfx.h | 14 +-- src/util/mpn.cpp | 2 +- src/util/mpq.h | 18 ++-- src/util/mpz.cpp | 90 +++++++++---------- src/util/mpz.h | 32 +++---- src/util/mpzzp.h | 16 ++-- src/util/prime_generator.cpp | 20 ++--- src/util/prime_generator.h | 8 +- src/util/rational.h | 10 +-- src/util/rlimit.cpp | 4 +- src/util/rlimit.h | 8 +- src/util/s_integer.h | 8 +- src/util/total_order.h | 30 +++---- src/util/util.cpp | 2 +- src/util/util.h | 22 ++--- 80 files changed, 437 insertions(+), 449 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 12a4642c1..c8b365f22 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -184,7 +184,7 @@ namespace api { e = m_bv_util.mk_numeral(n, s); } else if (fid == get_datalog_fid() && n.is_uint64()) { - uint64 sz; + uint64_t sz; if (m_datalog_util.try_get_size(s, sz) && sz <= n.get_uint64()) { invoke_error_handler(Z3_INVALID_ARG); diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index ab379c3de..de9886571 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -172,7 +172,7 @@ extern "C" { if (mk_c(c)->bvutil().is_numeral(e, r, bv_size)) { return Z3_TRUE; } - uint64 v; + uint64_t v; if (mk_c(c)->datalog_util().is_numeral(e, v)) { r = rational(v, rational::ui64()); return Z3_TRUE; diff --git a/src/ast/ast.h b/src/ast/ast.h index 68e02d791..35e9a1cbb 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -298,11 +298,11 @@ class sort_size { SS_FINITE_VERY_BIG, SS_INFINITE } m_kind; - uint64 m_size; // It is only meaningful if m_kind == SS_FINITE - sort_size(kind_t k, uint64 r):m_kind(k), m_size(r) {} + uint64_t m_size; // It is only meaningful if m_kind == SS_FINITE + sort_size(kind_t k, uint64_t r):m_kind(k), m_size(r) {} public: sort_size():m_kind(SS_INFINITE) {} - sort_size(uint64 const & sz):m_kind(SS_FINITE), m_size(sz) {} + sort_size(uint64_t const & sz):m_kind(SS_FINITE), m_size(sz) {} sort_size(sort_size const& other): m_kind(other.m_kind), m_size(other.m_size) {} explicit sort_size(rational const& r) { if (r.is_uint64()) { @@ -316,7 +316,7 @@ public: } static sort_size mk_infinite() { return sort_size(SS_INFINITE, 0); } static sort_size mk_very_big() { return sort_size(SS_FINITE_VERY_BIG, 0); } - static sort_size mk_finite(uint64 r) { return sort_size(SS_FINITE, r); } + static sort_size mk_finite(uint64_t r) { return sort_size(SS_FINITE, r); } bool is_infinite() const { return m_kind == SS_INFINITE; } bool is_very_big() const { return m_kind == SS_FINITE_VERY_BIG; } @@ -324,7 +324,7 @@ public: static bool is_very_big_base2(unsigned power) { return power >= 64; } - uint64 size() const { SASSERT(is_finite()); return m_size; } + uint64_t size() const { SASSERT(is_finite()); return m_size; } }; std::ostream& operator<<(std::ostream& out, sort_size const & ss); @@ -346,7 +346,7 @@ public: decl_info(family_id, k, num_parameters, parameters, private_parameters) { } - sort_info(family_id family_id, decl_kind k, uint64 num_elements, + sort_info(family_id family_id, decl_kind k, uint64_t num_elements, unsigned num_parameters = 0, parameter const * parameters = nullptr, bool private_parameters = false): decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) { } diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 8ad7c27f1..aeaebc6bf 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -387,7 +387,7 @@ format * smt2_pp_environment::pp_string_literal(app * t) { } format * smt2_pp_environment::pp_datalog_literal(app * t) { - uint64 v; + uint64_t v; VERIFY (get_dlutil().is_numeral(t, v)); std::ostringstream buffer; buffer << v; diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 4aff8cd06..e128f2c03 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -384,7 +384,7 @@ public: app * mk_numeral(rational const & val, sort* s) const; app * mk_numeral(rational const & val, unsigned bv_size) const; - app * mk_numeral(uint64 u, unsigned bv_size) const { return mk_numeral(rational(u, rational::ui64()), bv_size); } + app * mk_numeral(uint64_t u, unsigned bv_size) const { return mk_numeral(rational(u, rational::ui64()), bv_size); } sort * mk_sort(unsigned bv_size); unsigned get_bv_size(sort const * s) const { diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index e5b9ed930..f4a538abd 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -652,9 +652,9 @@ namespace datalog { // create a constant belonging to a given finite domain. - app* dl_decl_util::mk_numeral(uint64 value, sort* s) { + app* dl_decl_util::mk_numeral(uint64_t value, sort* s) { if (is_finite_sort(s)) { - uint64 sz = 0; + uint64_t sz = 0; if (try_get_size(s, sz) && sz <= value) { m.raise_exception("value is out of bounds"); } @@ -680,7 +680,7 @@ namespace datalog { return nullptr; } - bool dl_decl_util::is_numeral(const expr* e, uint64& v) const { + bool dl_decl_util::is_numeral(const expr* e, uint64_t& v) const { if (is_numeral(e)) { const app* c = to_app(e); SASSERT(c->get_decl()->get_num_parameters() == 2); @@ -693,7 +693,7 @@ namespace datalog { return false; } - bool dl_decl_util::is_numeral_ext(expr* e, uint64& v) const { + bool dl_decl_util::is_numeral_ext(expr* e, uint64_t& v) const { if (is_numeral(e, v)) { return true; } @@ -724,7 +724,7 @@ namespace datalog { return m.is_true(c) || m.is_false(c); } - sort* dl_decl_util::mk_sort(const symbol& name, uint64 domain_size) { + sort* dl_decl_util::mk_sort(const symbol& name, uint64_t domain_size) { if (domain_size == 0) { std::stringstream sstm; sstm << "Domain size of sort '" << name << "' may not be 0"; @@ -734,7 +734,7 @@ namespace datalog { return m.mk_sort(m_fid, DL_FINITE_SORT, 2, params); } - bool dl_decl_util::try_get_size(const sort * s, uint64& size) const { + bool dl_decl_util::try_get_size(const sort * s, uint64_t& size) const { sort_size sz = s->get_info()->get_num_elements(); if (sz.is_finite()) { size = sz.size(); diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 03b9d1fd8..257404f70 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -122,7 +122,7 @@ namespace datalog { // Contract for func_decl: // parameters[0] - array sort // Contract for OP_DL_CONSTANT: - // parameters[0] - rational containing uint64 with constant value + // parameters[0] - rational containing uint64_t with constant value // parameters[1] - a DL_FINITE_SORT sort of the constant // Contract for others: // no parameters @@ -166,7 +166,7 @@ namespace datalog { dl_decl_util(ast_manager& m); // create a constant belonging to a given finite domain. // the options include the DL_FINITE_SORT, BV_SORT, and BOOL_SORT - app* mk_numeral(uint64 value, sort* s); + app* mk_numeral(uint64_t value, sort* s); app* mk_lt(expr* a, expr* b); @@ -176,19 +176,19 @@ namespace datalog { bool is_numeral(const expr* c) const { return is_app_of(c, m_fid, OP_DL_CONSTANT); } - bool is_numeral(const expr* e, uint64& v) const; + bool is_numeral(const expr* e, uint64_t& v) const; // // Utilities for extracting constants // from bit-vectors and finite domains. // - bool is_numeral_ext(expr* c, uint64& v) const; + bool is_numeral_ext(expr* c, uint64_t& v) const; bool is_numeral_ext(expr* c) const; - sort* mk_sort(const symbol& name, uint64 domain_size); + sort* mk_sort(const symbol& name, uint64_t domain_size); - bool try_get_size(const sort *, uint64& size) const; + bool try_get_size(const sort *, uint64_t& size) const; bool is_finite_sort(sort* s) const { return is_sort_of(s, m_fid, DL_FINITE_SORT); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index c84af84d6..b7b0b6f08 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1071,7 +1071,7 @@ void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & r SASSERT(m_mpz_manager.is_int64(max_exp_diff)); SASSERT(m_mpz_manager.get_uint64(max_exp_diff) <= UINT_MAX); - uint64 max_exp_diff_ui64 = m_mpz_manager.get_uint64(max_exp_diff); + uint64_t max_exp_diff_ui64 = m_mpz_manager.get_uint64(max_exp_diff); SASSERT(max_exp_diff_ui64 <= UINT_MAX); unsigned max_exp_diff_ui = (unsigned)max_exp_diff_ui64; m_mpz_manager.del(max_exp_diff); diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index e327df452..a0adb6398 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -680,8 +680,8 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_ if (v.is_neg()) mod(v, rational::power_of_two(sz), v); if (v.is_uint64()) { - uint64 u = v.get_uint64(); - uint64 e = shift_right(u, low) & (shift_left(1ull, sz) - 1ull); + uint64_t u = v.get_uint64(); + uint64_t e = shift_right(u, low) & (shift_left(1ull, sz) - 1ull); result = mk_numeral(numeral(e, numeral::ui64()), sz); return BR_DONE; } @@ -811,7 +811,7 @@ br_status bv_rewriter::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result) { SASSERT(r1.is_uint64() && r2.is_uint64()); SASSERT(r2.get_uint64() < bv_size); - uint64 r = shift_left(r1.get_uint64(), r2.get_uint64()); + uint64_t r = shift_left(r1.get_uint64(), r2.get_uint64()); numeral rn(r, numeral::ui64()); rn = m_util.norm(rn, bv_size); result = mk_numeral(rn, bv_size); @@ -860,7 +860,7 @@ br_status bv_rewriter::mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result) { if (bv_size <= 64) { SASSERT(r1.is_uint64()); SASSERT(r2.is_uint64()); - uint64 r = shift_right(r1.get_uint64(), r2.get_uint64()); + uint64_t r = shift_right(r1.get_uint64(), r2.get_uint64()); numeral rn(r, numeral::ui64()); rn = m_util.norm(rn, bv_size); result = mk_numeral(rn, bv_size); @@ -902,11 +902,11 @@ br_status bv_rewriter::mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result) { bool is_num1 = is_numeral(arg1, r1, bv_size); if (bv_size <= 64 && is_num1 && is_num2) { - uint64 n1 = r1.get_uint64(); - uint64 n2_orig = r2.get_uint64(); - uint64 n2 = n2_orig % bv_size; + uint64_t n1 = r1.get_uint64(); + uint64_t n2_orig = r2.get_uint64(); + uint64_t n2 = n2_orig % bv_size; SASSERT(n2 < bv_size); - uint64 r = shift_right(n1, n2); + uint64_t r = shift_right(n1, n2); bool sign = (n1 & shift_left(1ull, bv_size - 1ull)) != 0; if (n2_orig > n2) { if (sign) { @@ -917,9 +917,9 @@ br_status bv_rewriter::mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result) { } } else if (sign) { - uint64 allone = shift_left(1ull, bv_size) - 1ull; - uint64 mask = ~(shift_left(1ull, bv_size - n2) - 1ull); - mask &= allone; + uint64_t allone = shift_left(1ull, bv_size) - 1ull; + uint64_t mask = ~(shift_left(1ull, bv_size - n2) - 1ull); + mask &= allone; r |= mask; } result = mk_numeral(numeral(r, numeral::ui64()), bv_size); @@ -2021,7 +2021,7 @@ br_status bv_rewriter::mk_bv_ext_rotate_left(expr * arg1, expr * arg2, expr_ref numeral r2; unsigned bv_size; if (is_numeral(arg2, r2, bv_size)) { - unsigned shift = static_cast((r2 % numeral(bv_size)).get_uint64() % static_cast(bv_size)); + unsigned shift = static_cast((r2 % numeral(bv_size)).get_uint64() % static_cast(bv_size)); return mk_bv_rotate_left(shift, arg1, result); } return BR_FAILED; @@ -2031,7 +2031,7 @@ br_status bv_rewriter::mk_bv_ext_rotate_right(expr * arg1, expr * arg2, expr_ref numeral r2; unsigned bv_size; if (is_numeral(arg2, r2, bv_size)) { - unsigned shift = static_cast((r2 % numeral(bv_size)).get_uint64() % static_cast(bv_size)); + unsigned shift = static_cast((r2 % numeral(bv_size)).get_uint64() % static_cast(bv_size)); return mk_bv_rotate_right(shift, arg1, result); } return BR_FAILED; diff --git a/src/ast/rewriter/dl_rewriter.cpp b/src/ast/rewriter/dl_rewriter.cpp index 74ea7814e..73944085b 100644 --- a/src/ast/rewriter/dl_rewriter.cpp +++ b/src/ast/rewriter/dl_rewriter.cpp @@ -22,7 +22,7 @@ Revision History: br_status dl_rewriter::mk_app_core( func_decl * f, unsigned num_args, expr* const* args, expr_ref& result) { ast_manager& m = result.get_manager(); - uint64 v1, v2; + uint64_t v1, v2; switch(f->get_decl_kind()) { case datalog::OP_DL_LT: if (m_util.is_numeral_ext(args[0], v1) && diff --git a/src/math/hilbert/hilbert_basis.h b/src/math/hilbert/hilbert_basis.h index a0350492a..54208d268 100644 --- a/src/math/hilbert/hilbert_basis.h +++ b/src/math/hilbert/hilbert_basis.h @@ -20,7 +20,7 @@ Revision History: Hilbert basis can be templatized based on traits that define numeral: - as rational, mpz, checked_int64 + as rational, mpz, checked_int64 (checked or unchecked). --*/ diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index a58f26597..35a95ce82 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -5479,7 +5479,7 @@ namespace polynomial { } p_prime = derivative(p, x); resultant(p, p_prime, x, r); - bool sign = (static_cast(m) * static_cast(m-1))%4 != 0; + bool sign = (static_cast(m) * static_cast(m-1))%4 != 0; TRACE("resultant", tout << "discriminant sign: " << sign << "\n";); scoped_numeral lc(m_manager); if (const_coeff(p, x, m, lc)) { @@ -6963,7 +6963,7 @@ namespace polynomial { return m_imp->m().set_zp(p); } - void manager::set_zp(uint64 p) { + void manager::set_zp(uint64_t p) { return m_imp->m().set_zp(p); } diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 43774f0ac..374a51084 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -218,7 +218,7 @@ namespace polynomial { \brief Set manager as Z_p[X1, ..., Xn] */ void set_zp(numeral const & p); - void set_zp(uint64 p); + void set_zp(uint64_t p); /** \brief Abstract event handler. @@ -1043,7 +1043,7 @@ namespace polynomial { scoped_numeral m_p; public: scoped_set_zp(manager & _m, numeral const & p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } - scoped_set_zp(manager & _m, uint64 p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } + scoped_set_zp(manager & _m, uint64_t p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } ~scoped_set_zp() { if (m_modular) m.set_zp(m_p); else m.set_z(); } }; }; diff --git a/src/math/polynomial/upolynomial.h b/src/math/polynomial/upolynomial.h index 6bd3e4a27..439b4be9f 100644 --- a/src/math/polynomial/upolynomial.h +++ b/src/math/polynomial/upolynomial.h @@ -153,7 +153,7 @@ namespace upolynomial { \brief Set manager as Z_p[X] */ void set_zp(numeral const & p) { m().set_zp(p); } - void set_zp(uint64 p) { m().set_zp(p); } + void set_zp(uint64_t p) { m().set_zp(p); } void checkpoint(); @@ -486,7 +486,7 @@ namespace upolynomial { core_manager::scoped_numeral m_p; public: scoped_set_zp(core_manager & _m, numeral const & p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } - scoped_set_zp(core_manager & _m, uint64 p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } + scoped_set_zp(core_manager & _m, uint64_t p):m(_m), m_modular(m.modular()), m_p(m.m()) { m_p = m.p(); m.set_zp(p); } ~scoped_set_zp() { if (m_modular) m.set_zp(m_p); else m.set_z(); } }; diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index a1f6e6ec1..5d9d3f1f1 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -38,9 +38,9 @@ unsigned get_p_from_manager(zp_numeral_manager const & zp_nm) { if (!nm.is_uint64(p)) { throw upolynomial_exception("The prime number attempted in factorization is too big!"); } - uint64 p_uint64 = nm.get_uint64(p); + uint64_t p_uint64 = nm.get_uint64(p); unsigned p_uint = static_cast(p_uint64); - if (((uint64)p_uint) != p_uint64) { + if (((uint64_t)p_uint) != p_uint64) { throw upolynomial_exception("The prime number attempted in factorization is too big!"); } return p_uint; @@ -1075,7 +1075,7 @@ bool factor_square_free(z_manager & upm, numeral_vector const & f, factors & fs, while (trials < params.m_p_trials) { upm.checkpoint(); // construct prime to check - uint64 next_prime = prime_it.next(); + uint64_t next_prime = prime_it.next(); if (next_prime > params.m_max_p) { fs.push_back(f_pp, k); return false; diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index 1f32a6189..16a9a9a9e 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -150,12 +150,12 @@ namespace subpaving { void int2hwf(mpz const & a, hwf & o) { if (!m_qm.is_int64(a)) throw subpaving::exception(); - int64 val = m_qm.get_int64(a); + int64_t val = m_qm.get_int64(a); double dval = static_cast(val); m_ctx.nm().set(o, dval); double _dval = m_ctx.nm().m().to_double(o); // TODO check the following test - if (static_cast(_dval) != val) + if (static_cast(_dval) != val) throw subpaving::exception(); } diff --git a/src/math/subpaving/subpaving_t.h b/src/math/subpaving/subpaving_t.h index 360b2a32f..02c538828 100644 --- a/src/math/subpaving/subpaving_t.h +++ b/src/math/subpaving/subpaving_t.h @@ -73,17 +73,17 @@ public: // TODO: add SIN, COS, TAN, ... }; protected: - kind m_kind; - uint64 m_timestamp; + kind m_kind; + uint64_t m_timestamp; public: constraint(kind k):m_kind(k), m_timestamp(0) {} kind get_kind() const { return m_kind; } // Return the timestamp of the last propagation visit - uint64 timestamp() const { return m_timestamp; } + uint64_t timestamp() const { return m_timestamp; } // Reset propagation visit time - void set_visited(uint64 ts) { m_timestamp = ts; } + void set_visited(uint64_t ts) { m_timestamp = ts; } }; /** @@ -149,17 +149,17 @@ public: unsigned m_lower:1; unsigned m_open:1; unsigned m_mark:1; - uint64 m_timestamp; + uint64_t m_timestamp; bound * m_prev; justification m_jst; - void set_timestamp(uint64 ts) { m_timestamp = ts; } + void set_timestamp(uint64_t ts) { m_timestamp = ts; } public: var x() const { return static_cast(m_x); } numeral const & value() const { return m_val; } numeral & value() { return m_val; } bool is_lower() const { return m_lower; } bool is_open() const { return m_open; } - uint64 timestamp() const { return m_timestamp; } + uint64_t timestamp() const { return m_timestamp; } bound * prev() const { return m_prev; } justification jst() const { return m_jst; } void display(std::ostream & out, numeral_manager & nm, display_var_proc const & proc = display_var_proc()); @@ -486,7 +486,7 @@ private: id_gen m_node_id_gen; - uint64 m_timestamp; + uint64_t m_timestamp; node * m_root; // m_leaf_head is the head of a doubly linked list of leaf nodes to be processed. node * m_leaf_head; diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 521cf0dc9..54c07da28 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -45,7 +45,7 @@ namespace datalog { protected: sort_ref m_sort; bool m_limited_size; - uint64 m_size; + uint64_t m_size; sort_domain(sort_kind k, context & ctx, sort * s) : m_kind(k), m_sort(s, ctx.get_manager()) { @@ -103,15 +103,15 @@ namespace datalog { }; class context::uint64_sort_domain : public sort_domain { - typedef map > el2num; - typedef svector num2el; + typedef map > el2num; + typedef svector num2el; el2num m_el_numbers; num2el m_el_names; public: uint64_sort_domain(context & ctx, sort * s) : sort_domain(SK_UINT64, ctx, s) {} - finite_element get_number(uint64 el) { + finite_element get_number(uint64_t el) { //we number symbols starting from zero, so table->size() is equal to the //index of the symbol to be added next @@ -368,14 +368,14 @@ namespace datalog { return dom.get_number(sym); } - context::finite_element context::get_constant_number(relation_sort srt, uint64 el) { + context::finite_element context::get_constant_number(relation_sort srt, uint64_t el) { sort_domain & dom0 = get_sort_domain(srt); SASSERT(dom0.get_kind()==SK_UINT64); uint64_sort_domain & dom = static_cast(dom0); return dom.get_number(el); } - void context::print_constant_name(relation_sort srt, uint64 num, std::ostream & out) + void context::print_constant_name(relation_sort srt, uint64_t num, std::ostream & out) { if (has_sort_domain(srt)) { SASSERT(num<=UINT_MAX); @@ -386,7 +386,7 @@ namespace datalog { } } - bool context::try_get_sort_constant_count(relation_sort srt, uint64 & constant_count) { + bool context::try_get_sort_constant_count(relation_sort srt, uint64_t & constant_count) { if (!has_sort_domain(srt)) { return false; } @@ -394,18 +394,18 @@ namespace datalog { return true; } - uint64 context::get_sort_size_estimate(relation_sort srt) { + uint64_t context::get_sort_size_estimate(relation_sort srt) { if (get_decl_util().is_rule_sort(srt)) { return 1; } - uint64 res; + uint64_t res; if (!try_get_sort_constant_count(srt, res)) { const sort_size & sz = srt->get_num_elements(); if (sz.is_finite()) { res = sz.size(); } else { - res = std::numeric_limits::max(); + res = std::numeric_limits::max(); } } return res; diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index f37826feb..865c746db 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -61,7 +61,7 @@ namespace datalog { class relation_manager; typedef sort * relation_sort; - typedef uint64 table_element; + typedef uint64_t table_element; typedef svector table_fact; typedef app * relation_element; @@ -351,16 +351,16 @@ namespace datalog { /** \brief Return number of a symbol in a DK_UINT64 kind sort (\see register_sort() ) */ - finite_element get_constant_number(relation_sort srt, uint64 el); + finite_element get_constant_number(relation_sort srt, uint64_t el); /** \brief Output name of constant with number \c num in sort \c sort. */ - void print_constant_name(relation_sort sort, uint64 num, std::ostream & out); + void print_constant_name(relation_sort sort, uint64_t num, std::ostream & out); - bool try_get_sort_constant_count(relation_sort srt, uint64 & constant_count); + bool try_get_sort_constant_count(relation_sort srt, uint64_t & constant_count); - uint64 get_sort_size_estimate(relation_sort srt); + uint64_t get_sort_size_estimate(relation_sort srt); /** \brief Assign names of variables used in the declaration of a predicate. diff --git a/src/muz/base/dl_costs.cpp b/src/muz/base/dl_costs.cpp index d429af803..70688cd59 100644 --- a/src/muz/base/dl_costs.cpp +++ b/src/muz/base/dl_costs.cpp @@ -141,7 +141,7 @@ namespace datalog { } void cost_recorder::start(accounted_object * obj) { - uint64 curr_time = static_cast(m_stopwatch->get_current_seconds()*1000); + uint64_t curr_time = static_cast(m_stopwatch->get_current_seconds()*1000); if(m_obj) { costs::time_type time_delta = static_cast(curr_time-m_last_time); costs & c = m_obj->get_current_costs(); diff --git a/src/muz/base/dl_costs.h b/src/muz/base/dl_costs.h index 59d4fd8c1..6a5b5e5d6 100644 --- a/src/muz/base/dl_costs.h +++ b/src/muz/base/dl_costs.h @@ -95,7 +95,7 @@ namespace datalog { stopwatch * m_stopwatch; bool m_running; - uint64 m_last_time; + uint64_t m_last_time; public: cost_recorder(); ~cost_recorder(); diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index c2622cec4..7cc9d4b03 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -165,7 +165,7 @@ namespace datalog { } expr * arg = f->get_arg(i); - uint64 sym_num; + uint64_t sym_num; SASSERT(is_app(arg)); VERIFY( ctx.get_decl_util().is_numeral_ext(to_app(arg), sym_num) ); relation_sort sort = pred_decl->get_domain(i); @@ -621,7 +621,7 @@ namespace datalog { return name.substr(ofs, count); } - bool string_to_uint64(const char * s, uint64 & res) { + bool string_to_uint64(const char * s, uint64_t & res) { #if _WINDOWS int converted = sscanf_s(s, "%I64u", &res); #else @@ -634,9 +634,9 @@ namespace datalog { return true; } - bool read_uint64(const char * & s, uint64 & res) { - static const uint64 max_but_one_digit = ULLONG_MAX/10; - static const uint64 max_but_one_digit_safe = (ULLONG_MAX-9)/10; + bool read_uint64(const char * & s, uint64_t & res) { + static const uint64_t max_but_one_digit = ULLONG_MAX/10; + static const uint64_t max_but_one_digit_safe = (ULLONG_MAX-9)/10; if(*s<'0' || *s>'9') { return false; @@ -664,7 +664,7 @@ namespace datalog { return true; } - std::string to_string(uint64 num) { + std::string to_string(uint64_t num) { std::stringstream stm; stm< uint64_vector; - typedef hashtable > uint64_set; - typedef map > num2sym; + typedef svector uint64_vector; + typedef hashtable > uint64_set; + typedef map > num2sym; typedef map sym2nums; num2sym m_number_names; @@ -1261,7 +1261,7 @@ private: return true; } - bool inp_num_to_element(sort * s, uint64 num, table_element & res) { + bool inp_num_to_element(sort * s, uint64_t num, table_element & res) { if(s==m_bool_sort.get() || s==m_short_sort.get()) { res = mk_table_const(num, s); return true; @@ -1332,7 +1332,7 @@ private: if(*ptr==0) { break; } - uint64 num; + uint64_t num; if(!read_uint64(ptr, num)) { throw default_exception(default_exception::fmt(), "number expected on line %d in file %s", m_current_line, m_current_file.c_str()); @@ -1389,7 +1389,7 @@ private: bool fact_fail = false; fact.reset(); for(unsigned i=0;im_key; uint64_set & sort_content = *sit->m_value; //the +1 is for a zero element which happens to appear in the problem files - uint64 domain_size = sort_content.size()+1; + uint64_t domain_size = sort_content.size()+1; // sort * s; if(!m_use_map_names) { /* s = */ register_finite_sort(sort_name, domain_size, context::SK_UINT64); @@ -1428,7 +1428,7 @@ private: uint64_set::iterator cit = sort_content.begin(); uint64_set::iterator cend = sort_content.end(); for(; cit!=cend; ++cit) { - uint64 const_num = *cit; + uint64_t const_num = *cit; inp_num_to_element(s, const_num); } */ @@ -1443,7 +1443,7 @@ private: *ptr=0; } - bool parse_map_line(char * full_line, uint64 & num, symbol & name) { + bool parse_map_line(char * full_line, uint64_t & num, symbol & name) { cut_off_comment(full_line); if(full_line[0]==0) { return false; @@ -1515,7 +1515,7 @@ private: m_current_line++; char * full_line = rdr.get_line(); - uint64 num; + uint64_t num; symbol el_name; if(!parse_map_line(full_line, num, el_name)) { diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp index 20418e3bb..5dd21a9f0 100644 --- a/src/muz/rel/dl_base.cpp +++ b/src/muz/rel/dl_base.cpp @@ -384,7 +384,7 @@ namespace datalog { VERIFY(sig.first_functional() == 1); - uint64 upper_bound = get_signature()[0]; + uint64_t upper_bound = get_signature()[0]; bool empty_table = empty(); if (upper_bound > (1 << 18)) { diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index dfdcb304d..4d202f2a2 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -832,7 +832,7 @@ namespace datalog { class table_plugin; class table_base; - typedef uint64 table_sort; + typedef uint64_t table_sort; typedef svector table_signature_base0; typedef uint64_hash table_sort_hash; diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index deb289277..c9fc4f173 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -448,7 +448,7 @@ namespace datalog { } std::string relation_manager::to_nice_string(const relation_element & el) const { - uint64 val; + uint64_t val; std::stringstream stm; if(get_context().get_decl_util().is_numeral_ext(el, val)) { stm << val; @@ -461,7 +461,7 @@ namespace datalog { std::string relation_manager::to_nice_string(const relation_sort & s, const relation_element & el) const { std::stringstream stm; - uint64 val; + uint64_t val; if(get_context().get_decl_util().is_numeral_ext(el, val)) { get_context().print_constant_name(s, val, stm); } @@ -1339,9 +1339,9 @@ namespace datalog { class relation_manager::default_table_filter_not_equal_fn : public table_mutator_fn, auxiliary_table_filter_fn { unsigned m_column; - uint64 m_value; + uint64_t m_value; public: - default_table_filter_not_equal_fn(context & ctx, unsigned column, uint64 value) + default_table_filter_not_equal_fn(context & ctx, unsigned column, uint64_t value) : m_column(column), m_value(value) { } @@ -1372,7 +1372,7 @@ namespace datalog { return nullptr; } dl_decl_util decl_util(m); - uint64 value = 0; + uint64_t value = 0; if (!decl_util.is_numeral_ext(y, value)) { return nullptr; } diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index 779172b0d..bb48211c7 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -93,7 +93,7 @@ namespace datalog { // // ----------------------------------- - unsigned get_domain_length(uint64 dom_size) { + unsigned get_domain_length(uint64_t dom_size) { SASSERT(dom_size>0); unsigned length = 0; @@ -128,7 +128,7 @@ namespace datalog { unsigned sig_sz = sig.size(); unsigned first_functional = sig_sz-m_functional_col_cnt; for (unsigned i=0; i0); SASSERT(length<=64); diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index a9f3b31a4..fbbbd12f8 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -153,7 +153,7 @@ namespace datalog { variable. Otherwise \c m_reserve==NO_RESERVE. The size of m_data is actually 8 bytes larger than stated in m_data_size, so that we may - deref an uint64 pointer at the end of the array. + deref an uint64_t pointer at the end of the array. */ storage m_data; storage_indexer m_data_indexer; @@ -290,10 +290,10 @@ namespace datalog { //the following two operations allow breaking of the object invariant! void resize_data(size_t sz) { m_data_size = sz; - if (sz + sizeof(uint64) < sz) { + if (sz + sizeof(uint64_t) < sz) { throw default_exception("overflow resizing data section for sparse table"); } - m_data.resize(sz + sizeof(uint64)); + m_data.resize(sz + sizeof(uint64_t)); } bool insert_offset(store_offset ofs) { @@ -321,8 +321,8 @@ namespace datalog { class column_info { unsigned m_big_offset; unsigned m_small_offset; - uint64 m_mask; - uint64 m_write_mask; + uint64_t m_mask; + uint64_t m_write_mask; public: unsigned m_offset; //!< in bits unsigned m_length; //!< in bits @@ -330,7 +330,7 @@ namespace datalog { column_info(unsigned offset, unsigned length) \ : m_big_offset(offset/8), m_small_offset(offset%8), - m_mask( length==64 ? ULLONG_MAX : (static_cast(1)<(1)<(rec+m_big_offset); - uint64 res = *ptr; + const uint64_t * ptr = reinterpret_cast(rec+m_big_offset); + uint64_t res = *ptr; res>>=m_small_offset; res&=m_mask; return res; } void set(char * rec, table_element val) const { SASSERT( (val&~m_mask)==0 ); //the value fits into the column - uint64 * ptr = reinterpret_cast(rec+m_big_offset); + uint64_t * ptr = reinterpret_cast(rec+m_big_offset); *ptr&=m_write_mask; *ptr|=val<restart_time); remaining_time_limit -= restart_time; } - uint64 new_restart_time = static_cast(restart_time)*m_context.initial_restart_timeout(); + uint64_t new_restart_time = static_cast(restart_time)*m_context.initial_restart_timeout(); if (new_restart_time > UINT_MAX) { restart_time = UINT_MAX; } diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 69cc4819a..b96f32114 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -72,7 +72,7 @@ tbv* tbv_manager::allocate(tbv const& bv) { copy(*r, bv); return r; } -tbv* tbv_manager::allocate(uint64 val) { +tbv* tbv_manager::allocate(uint64_t val) { tbv* v = allocate0(); for (unsigned bit = std::min(64u, num_tbits()); bit-- > 0;) { if (val & (1ULL << bit)) { @@ -84,7 +84,7 @@ tbv* tbv_manager::allocate(uint64 val) { return v; } -tbv* tbv_manager::allocate(uint64 val, unsigned hi, unsigned lo) { +tbv* tbv_manager::allocate(uint64_t val, unsigned hi, unsigned lo) { tbv* v = allocateX(); SASSERT(64 >= num_tbits() && num_tbits() > hi && hi >= lo); set(*v, val, hi, lo); @@ -134,7 +134,7 @@ void tbv_manager::set(tbv& dst, unsigned index, tbit value) { } -void tbv_manager::set(tbv& dst, uint64 val, unsigned hi, unsigned lo) { +void tbv_manager::set(tbv& dst, uint64_t val, unsigned hi, unsigned lo) { SASSERT(lo <= hi && hi < num_tbits()); for (unsigned i = 0; i < hi - lo + 1; ++i) { set(dst, lo + i, (val & (1ULL << i))?BIT_1:BIT_0); diff --git a/src/muz/rel/tbv.h b/src/muz/rel/tbv.h index 22c25a5e9..346208a3f 100644 --- a/src/muz/rel/tbv.h +++ b/src/muz/rel/tbv.h @@ -51,9 +51,9 @@ public: tbv* allocate0(); tbv* allocateX(); tbv* allocate(tbv const& bv); - tbv* allocate(uint64 n); + tbv* allocate(uint64_t n); tbv* allocate(rational const& r); - tbv* allocate(uint64 n, unsigned hi, unsigned lo); + tbv* allocate(uint64_t n, unsigned hi, unsigned lo); tbv* allocate(tbv const& bv, unsigned const* permutation); tbv* allocate(char const* bv); @@ -80,7 +80,7 @@ public: std::ostream& display(std::ostream& out, tbv const& b, unsigned hi, unsigned lo) const; tbv* project(bit_vector const& to_delete, tbv const& src); bool is_well_formed(tbv const& b) const; // - does not contain BIT_z; - void set(tbv& dst, uint64 n, unsigned hi, unsigned lo); + void set(tbv& dst, uint64_t n, unsigned hi, unsigned lo); void set(tbv& dst, rational const& r, unsigned hi, unsigned lo); void set(tbv& dst, tbv const& other, unsigned hi, unsigned lo); void set(tbv& dst, unsigned index, tbit value); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index ff23a5e53..2e9ab693c 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -261,7 +261,7 @@ namespace datalog { num_bits = 1; return true; } - uint64 n, sz; + uint64_t n, sz; ast_manager& m = get_ast_manager(); if (dl.is_numeral(e, n) && dl.try_get_size(m.get_sort(e), sz)) { num_bits = 0; @@ -277,7 +277,7 @@ namespace datalog { return bv.get_bv_size(s); if (m.is_bool(s)) return 1; - uint64 sz; + uint64_t sz; if (dl.try_get_size(s, sz)) { while (sz > 0) ++num_bits, sz /= 2; return num_bits; diff --git a/src/qe/qe_dl_plugin.cpp b/src/qe/qe_dl_plugin.cpp index 8d688d80c..6e411511d 100644 --- a/src/qe/qe_dl_plugin.cpp +++ b/src/qe/qe_dl_plugin.cpp @@ -70,7 +70,7 @@ namespace qe { return false; } eq_atoms& eqs = get_eqs(x.x(), fml); - uint64 domain_size; + uint64_t domain_size; if (is_small_domain(x, eqs, domain_size)) { num_branches = rational(domain_size, rational::ui64()); } @@ -84,7 +84,7 @@ namespace qe { SASSERT(v.is_unsigned()); eq_atoms& eqs = get_eqs(x.x(), fml); unsigned uv = v.get_unsigned(); - uint64 domain_size; + uint64_t domain_size; if (is_small_domain(x, eqs, domain_size)) { SASSERT(v < rational(domain_size, rational::ui64())); assign_small_domain(x, eqs, uv); @@ -98,7 +98,7 @@ namespace qe { SASSERT(v.is_unsigned()); eq_atoms& eqs = get_eqs(x.x(), fml); unsigned uv = v.get_unsigned(); - uint64 domain_size; + uint64_t domain_size; if (is_small_domain(x, eqs, domain_size)) { SASSERT(uv < domain_size); subst_small_domain(x, eqs, uv, fml); @@ -115,7 +115,7 @@ namespace qe { private: - bool is_small_domain(contains_app& x, eq_atoms& eqs, uint64& domain_size) { + bool is_small_domain(contains_app& x, eq_atoms& eqs, uint64_t& domain_size) { VERIFY(m_util.try_get_size(m.get_sort(x.x()), domain_size)); return domain_size < eqs.num_eqs() + eqs.num_neqs(); } diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 427c1015f..9cc13b897 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -212,7 +212,7 @@ unsigned read_datalog(char const * file) { if (early_termination) { IF_VERBOSE(1, verbose_stream() << "restarting saturation\n";); - uint64 new_timeout = static_cast(timeout)*ctx.initial_restart_timeout(); + uint64_t new_timeout = static_cast(timeout)*ctx.initial_restart_timeout(); if(new_timeout>UINT_MAX) { timeout=UINT_MAX; } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index e20eae0bd..608b7c63e 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3951,7 +3951,7 @@ namespace smt { #if 0 { static unsigned counter = 0; - static uint64 total = 0; + static uint64_t total = 0; static unsigned max = 0; counter++; total += num_lits; diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index 285c03946..824bd1d9e 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -182,7 +182,7 @@ namespace smt { if (n->get_decl() != v) { expr* rep = m().mk_app(r, n); - uint64 vl; + uint64_t vl; if (u().is_numeral_ext(n, vl)) { assert_cnstr(m().mk_eq(rep, mk_bv_constant(vl, s))); } @@ -237,12 +237,12 @@ namespace smt { return true; } - app* mk_bv_constant(uint64 val, sort* s) { + app* mk_bv_constant(uint64_t val, sort* s) { return b().mk_numeral(rational(val, rational::ui64()), 64); } app* max_value(sort* s) { - uint64 sz; + uint64_t sz; VERIFY(u().try_get_size(s, sz)); SASSERT(sz > 0); return mk_bv_constant(sz-1, s); diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index 2cd6a5a1b..2704d92ff 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -25,7 +25,7 @@ Author: #include "ast/ast_pp.h" #include -static uint64 uMaxInt(unsigned sz) { +static uint64_t uMaxInt(unsigned sz) { SASSERT(sz <= 64); return ULLONG_MAX >> (64u - sz); } @@ -35,12 +35,12 @@ namespace { struct interval { // l < h: [l, h] // l > h: [0, h] U [l, UMAX_INT] - uint64 l, h; + uint64_t l, h; unsigned sz; bool tight; interval() {} - interval(uint64 l, uint64 h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { + interval(uint64_t l, uint64_t h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { // canonicalize full set if (is_wrapped() && l == h + 1) { this->l = 0; @@ -183,7 +183,7 @@ namespace { svector m_expr_vars; svector m_bound_exprs; - bool is_number(expr *e, uint64& n, unsigned& sz) const { + bool is_number(expr *e, uint64_t& n, unsigned& sz) const { rational r; if (m_bv.is_numeral(e, r, sz) && sz <= 64) { n = r.get_uint64(); @@ -193,7 +193,7 @@ namespace { } bool is_bound(expr *e, expr*& v, interval& b) const { - uint64 n; + uint64_t n; expr *lhs = nullptr, *rhs = nullptr; unsigned sz; @@ -550,7 +550,7 @@ namespace { svector m_expr_vars; svector m_bound_exprs; - bool is_number(expr *e, uint64& n, unsigned& sz) const { + bool is_number(expr *e, uint64_t& n, unsigned& sz) const { rational r; if (m_bv.is_numeral(e, r, sz) && sz <= 64) { n = r.get_uint64(); @@ -560,7 +560,7 @@ namespace { } bool is_bound(expr *e, expr*& v, interval& b) const { - uint64 n; + uint64_t n; expr *lhs = nullptr, *rhs = nullptr; unsigned sz = 0; diff --git a/src/test/algebraic.cpp b/src/test/algebraic.cpp index b893b5ee2..38948c0d7 100644 --- a/src/test/algebraic.cpp +++ b/src/test/algebraic.cpp @@ -278,7 +278,7 @@ static void tst_select_small(mpbq_manager & m, scoped_mpbq const & l, scoped_mpb std::cout << "choice: " << r << " as decimal: "; m.display_decimal(std::cout, r); std::cout << std::endl; } -static void tst_select_small(mpbq_manager & m, int64 n1, unsigned k1, int64 n2, unsigned k2, bool expected) { +static void tst_select_small(mpbq_manager & m, int64_t n1, unsigned k1, int64_t n2, unsigned k2, bool expected) { scoped_mpbq l(m); scoped_mpbq u(m); m.set(l, n1, k1); diff --git a/src/test/dl_query.cpp b/src/test/dl_query.cpp index c5765bd6b..3dc99e33c 100644 --- a/src/test/dl_query.cpp +++ b/src/test/dl_query.cpp @@ -95,12 +95,12 @@ void dl_query_test(ast_manager & m, smt_params & fparams, params_ref& params, f_b.reset(); f_q.reset(); for(unsigned col=0; colget_domain(0); - uint64 var_sz; + uint64_t var_sz; TRUSTME( ctx.try_get_sort_constant_count(var_sort, var_sz) ); for(unsigned attempt=0; attempt(100)); - m.set(b, static_cast(-100)); + m.set(a, static_cast(100)); + m.set(b, static_cast(-100)); std::cout << "[test2], a: " << a << ", b: " << b << "\n"; } @@ -75,7 +75,7 @@ static void tst4() { static void tst5() { mpff_manager m; scoped_mpff a(m), b(m); - m.set(a, static_cast(1) << 63); + m.set(a, static_cast(1) << 63); m.display_raw(std::cout, a); std::cout << "\n"; ENSURE(m.is_zero(b)); ENSURE(m.lt(b, a)); @@ -117,7 +117,7 @@ static void tst7() { #define MK_BIN_OP(OP) \ -static void tst_ ## OP ## _core(int64 n1, uint64 d1, int64 n2, uint64 d2, unsigned precision = 2, unsigned exp = 0) { \ +static void tst_ ## OP ## _core(int64_t n1, uint64_t d1, int64_t n2, uint64_t d2, unsigned precision = 2, unsigned exp = 0) { \ TRACE("mpff_bug", tout << n1 << "/" << d1 << ", " << n2 << "/" << d2 << "\n";); \ unsynch_mpq_manager qm; \ scoped_mpq qa(qm), qb(qm), qc(qm), qt(qm); \ @@ -207,7 +207,7 @@ static void tst_set64(unsigned N, unsigned prec) { mpff_manager fm(prec); scoped_mpff a(fm); - fm.set(a, static_cast(INT64_MAX)); + fm.set(a, static_cast(INT64_MAX)); ENSURE(fm.is_int64(a)); ENSURE(fm.is_uint64(a)); fm.inc(a); @@ -221,7 +221,7 @@ static void tst_set64(unsigned N, unsigned prec) { ENSURE(fm.is_int64(a)); ENSURE(fm.is_uint64(a)); - fm.set(a, static_cast(INT64_MIN)); + fm.set(a, static_cast(INT64_MIN)); ENSURE(fm.is_int64(a)); ENSURE(!fm.is_uint64(a)); fm.dec(a); @@ -235,7 +235,7 @@ static void tst_set64(unsigned N, unsigned prec) { ENSURE(fm.is_int64(a)); ENSURE(!fm.is_uint64(a)); - fm.set(a, static_cast(UINT64_MAX)); + fm.set(a, static_cast(UINT64_MAX)); ENSURE(fm.is_uint64(a)); ENSURE(!fm.is_int64(a)); fm.inc(a); @@ -250,23 +250,23 @@ static void tst_set64(unsigned N, unsigned prec) { for (unsigned i = 0; i < N; i++) { { - uint64 v = (static_cast(rand()) << 32) + static_cast(rand()); + uint64_t v = (static_cast(rand()) << 32) + static_cast(rand()); fm.set(a, v); ENSURE(fm.is_uint64(a)); - v = (static_cast(rand() % 3) << 32) + static_cast(rand()); + v = (static_cast(rand() % 3) << 32) + static_cast(rand()); fm.set(a, v); ENSURE(fm.is_uint64(a)); } { - int64 v = (static_cast(rand() % INT_MAX) << 32) + static_cast(rand()); + int64_t v = (static_cast(rand() % INT_MAX) << 32) + static_cast(rand()); if (rand()%2 == 0) v = -v; fm.set(a, v); ENSURE(fm.is_int64(a)); - v = (static_cast(rand() % 3) << 32) + static_cast(rand()); + v = (static_cast(rand() % 3) << 32) + static_cast(rand()); if (rand()%2 == 0) v = -v; fm.set(a, v); @@ -336,7 +336,7 @@ static void tst_power(unsigned prec = 2) { m.set(a, UINT_MAX); m.inc(a); ENSURE(m.is_power_of_two(a, k) && k == 32); - ENSURE(m.get_uint64(a) == static_cast(UINT_MAX) + 1); + ENSURE(m.get_uint64(a) == static_cast(UINT_MAX) + 1); m.power(a, 2, a); ENSURE(m.is_power_of_two(a, k) && k == 64); m.power(a, 4, a); @@ -538,7 +538,7 @@ static void tst_add_corner(unsigned prec) { } #endif -static void tst_decimal(int64 n, uint64 d, bool to_plus_inf, unsigned prec, char const * expected, unsigned decimal_places = UINT_MAX) { +static void tst_decimal(int64_t n, uint64_t d, bool to_plus_inf, unsigned prec, char const * expected, unsigned decimal_places = UINT_MAX) { mpff_manager m(prec); scoped_mpff a(m); m.set_rounding(to_plus_inf); @@ -567,7 +567,7 @@ static void tst_decimal() { tst_decimal(-32, 5, true, 2, "-6.39999999999999999965305530480463858111761510372161865234375"); } -static void tst_prev_power_2(int64 n, uint64 d, unsigned expected) { +static void tst_prev_power_2(int64_t n, uint64_t d, unsigned expected) { mpff_manager m; scoped_mpff a(m); m.set(a, n, d); @@ -598,7 +598,7 @@ static void tst_div(unsigned prec) { scoped_mpff a(m), b(m), c(m); m.round_to_plus_inf(); m.set(a, 1); - m.set(b, static_cast(UINT64_MAX)); + m.set(b, static_cast(UINT64_MAX)); m.div(a, b, c); m.display_raw(std::cout, a); std::cout << "\n"; m.display_raw(std::cout, b); std::cout << "\n"; diff --git a/src/test/mpfx.cpp b/src/test/mpfx.cpp index f9dc123f5..f5cf7e2fb 100644 --- a/src/test/mpfx.cpp +++ b/src/test/mpfx.cpp @@ -35,7 +35,7 @@ static void tst1() { m.display_decimal(std::cout, a); std::cout << "\n"; } -static void tst_prev_power_2(int64 n, uint64 d, unsigned expected) { +static void tst_prev_power_2(int64_t n, uint64_t d, unsigned expected) { mpfx_manager m; scoped_mpfx a(m); m.set(a, n, d); diff --git a/src/test/mpq.cpp b/src/test/mpq.cpp index 7b60d9dcb..6294a97f7 100644 --- a/src/test/mpq.cpp +++ b/src/test/mpq.cpp @@ -133,7 +133,7 @@ static void set_str_bug() { ENSURE(a == b); } -static void tst_prev_power_2(int64 n, uint64 d, unsigned expected) { +static void tst_prev_power_2(int64_t n, uint64_t d, unsigned expected) { unsynch_mpq_manager m; scoped_mpq a(m); m.set(a, n, d); diff --git a/src/test/mpz.cpp b/src/test/mpz.cpp index 7926388df..cf7f3d8e6 100644 --- a/src/test/mpz.cpp +++ b/src/test/mpz.cpp @@ -50,7 +50,7 @@ static void tst1() { static void tst2() { synch_mpz_manager m; mpz v1, v2, v3; - m.set(v1, static_cast(UINT_MAX)); + m.set(v1, static_cast(UINT_MAX)); m.add(v1, m.mk_z(1), v2); m.mul(v2, v2, v3); std::cout << "v2:\n" << m.to_string(v2) << "\n"; @@ -63,7 +63,7 @@ static void tst2() { static void tst2b() { synch_mpz_manager m; mpz v1, v2, v3; - m.set(v1, static_cast(UINT_MAX)); + m.set(v1, static_cast(UINT_MAX)); m.add(v1, m.mk_z(1), v2); m.mul(v2, v2, v3); std::cout << "v2:\n" << m.to_string(v2) << "\n"; @@ -282,7 +282,7 @@ void tst_int_min_bug() { mpz big; mpz expected; mpz r; - m.set(big, static_cast(UINT64_MAX)); + m.set(big, static_cast(UINT64_MAX)); m.set(expected, "18446744075857035263"); m.sub(big, intmin, r); std::cout << "r: " << m.to_string(r) << "\nexpected: " << m.to_string(expected) << "\n"; diff --git a/src/test/prime_generator.cpp b/src/test/prime_generator.cpp index 12c38ef78..3820959d9 100644 --- a/src/test/prime_generator.cpp +++ b/src/test/prime_generator.cpp @@ -25,7 +25,7 @@ void tst_prime_generator() { prime_generator gen; for (unsigned i = 0; i < 10000; i++) { - uint64 p = gen(i); + uint64_t p = gen(i); std::cout << p << ", "; if (i % 11 == 0) std::cout << "\n"; std::cout.flush(); @@ -33,8 +33,8 @@ void tst_prime_generator() { continue; m.set(sqrt_p, p); m.root(sqrt_p, 2); - uint64 k = m.get_uint64(sqrt_p); - for (uint64 i = 2; i <= k; i++) { + uint64_t k = m.get_uint64(sqrt_p); + for (uint64_t i = 2; i <= k; i++) { ENSURE(p % i != 0); } } diff --git a/src/test/rational.cpp b/src/test/rational.cpp index 0618a01fb..ac477a02f 100644 --- a/src/test/rational.cpp +++ b/src/test/rational.cpp @@ -194,8 +194,8 @@ static void tst2() { ENSURE(uint64_max.is_uint64()); // get_int64, get_uint64 - uint64 u1 = uint64_max.get_uint64(); - uint64 u2 = UINT64_MAX; + uint64_t u1 = uint64_max.get_uint64(); + uint64_t u2 = UINT64_MAX; VERIFY(u1 == u2); std::cout << "int64_max: " << int64_max << ", INT64_MAX: " << INT64_MAX << ", int64_max.get_int64(): " << int64_max.get_int64() << ", int64_max.get_uint64(): " << int64_max.get_uint64() << "\n"; ENSURE(int64_max.get_int64() == INT64_MAX); diff --git a/src/util/checked_int64.h b/src/util/checked_int64.h index e5a88fb31..507564a2e 100644 --- a/src/util/checked_int64.h +++ b/src/util/checked_int64.h @@ -7,7 +7,7 @@ Module Name: Abstract: - A class for wrapping checked (and unchecked) int64 operations. + A class for wrapping checked (and unchecked) int64_t operations. Note: the mpfx class defines a more general class of fixed-point operations. A tradeoff is that it relies on a manager. This class several of the most common operations from rational, so @@ -29,15 +29,15 @@ Revision History: template class checked_int64 { - int64 m_value; + int64_t m_value; typedef checked_int64 ci; - rational r64(int64 i) { return rational(i, rational::i64()); } + rational r64(int64_t i) { return rational(i, rational::i64()); } public: checked_int64(): m_value(0) {} - checked_int64(int64 v): m_value(v) {} + checked_int64(int64_t v): m_value(v) {} checked_int64(checked_int64 const& other) { m_value = other.m_value; } class overflow_exception : public z3_exception { @@ -57,7 +57,7 @@ public: static checked_int64 one() { return ci(1); } static checked_int64 minus_one() { return ci(-1);} - int64 get_int64() const { return m_value; } + int64_t get_int64() const { return m_value; } checked_int64 abs() const { if (m_value >= 0) { @@ -117,9 +117,9 @@ public: checked_int64& operator+=(checked_int64 const& other) { if (CHECK) { - uint64 x = static_cast(m_value); - uint64 y = static_cast(other.m_value); - int64 r = static_cast(x + y); + uint64_t x = static_cast(m_value); + uint64_t y = static_cast(other.m_value); + int64_t r = static_cast(x + y); if (m_value > 0 && other.m_value > 0 && r <= 0) throw overflow_exception(); if (m_value < 0 && other.m_value < 0 && r >= 0) throw overflow_exception(); m_value = r; @@ -132,9 +132,9 @@ public: checked_int64& operator-=(checked_int64 const& other) { if (CHECK) { - uint64 x = static_cast(m_value); - uint64 y = static_cast(other.m_value); - int64 r = static_cast(x - y); + uint64_t x = static_cast(m_value); + uint64_t y = static_cast(other.m_value); + int64_t r = static_cast(x - y); if (m_value > 0 && other.m_value < 0 && r <= 0) throw overflow_exception(); if (m_value < 0 && other.m_value > 0 && r >= 0) throw overflow_exception(); m_value = r; diff --git a/src/util/double_manager.h b/src/util/double_manager.h index 7532a3b8b..481701f42 100644 --- a/src/util/double_manager.h +++ b/src/util/double_manager.h @@ -75,8 +75,8 @@ public: static void set(double & a, char const * val) { a = atof(val); } static void set(double & a, int val) { a = static_cast(val); } static void set(double & a, unsigned val) { a = static_cast(val); } - static void set(double & a, int64 val) { a = static_cast(val); } - static void set(double & a, uint64 val) { a = static_cast(val); } + static void set(double & a, int64_t val) { a = static_cast(val); } + static void set(double & a, uint64_t val) { a = static_cast(val); } static void swap(double & a, double & b) { std::swap(a, b); } bool is_pos(double a) const { return a > m_zero_tolerance; } bool is_neg(double a) const { return a < m_zero_tolerance; } @@ -93,11 +93,11 @@ public: } static unsigned hash(double a) { - return hash_ull(static_cast(a)); + return hash_ull(static_cast(a)); } }; -static_assert(sizeof(uint64) == sizeof(double), ""); +static_assert(sizeof(uint64_t) == sizeof(double), ""); #endif /* DOUBLE_MANAGER_H_ */ diff --git a/src/util/hash.h b/src/util/hash.h index bc6117cac..a2af8253f 100644 --- a/src/util/hash.h +++ b/src/util/hash.h @@ -140,8 +140,8 @@ struct size_t_hash { }; struct uint64_hash { - typedef uint64 data; - unsigned operator()(uint64 x) const { return static_cast(x); } + typedef uint64_t data; + unsigned operator()(uint64_t x) const { return static_cast(x); } }; struct bool_hash { diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 014e62625..c59621b6b 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -91,8 +91,8 @@ hwf_manager::~hwf_manager() { } -uint64 RAW(double X) { uint64 tmp; memcpy(&tmp, &(X), sizeof(uint64)); return tmp; } -double DBL(uint64 X) { double tmp; memcpy(&tmp, &(X), sizeof(double)); return tmp; } +uint64_t RAW(double X) { uint64_t tmp; memcpy(&tmp, &(X), sizeof(uint64_t)); return tmp; } +double DBL(uint64_t X) { double tmp; memcpy(&tmp, &(X), sizeof(double)); return tmp; } void hwf_manager::set(hwf & o, int value) { o.value = (double) value; @@ -147,7 +147,7 @@ void hwf_manager::set(hwf & o, mpf_rounding_mode rm, mpq const & significand, mp mpq sig; m_mpq_manager.set(sig, significand); - int64 exp = m_mpz_manager.get_int64(exponent); + int64_t exp = m_mpz_manager.get_int64(exponent); if (m_mpq_manager.is_zero(significand)) o.value = 0.0; @@ -160,17 +160,17 @@ void hwf_manager::set(hwf & o, mpf_rounding_mode rm, mpq const & significand, mp } hwf s; s.value = m_mpq_manager.get_double(sig); - uint64 r = (RAW(s.value) & 0x800FFFFFFFFFFFFFull) | ((exp + 1023) << 52); + uint64_t r = (RAW(s.value) & 0x800FFFFFFFFFFFFFull) | ((exp + 1023) << 52); o.value = DBL(r); } } -void hwf_manager::set(hwf & o, bool sign, uint64 significand, int exponent) { +void hwf_manager::set(hwf & o, bool sign, uint64_t significand, int exponent) { // Assumption: this represents (sign * -1) * (significand/2^sbits) * 2^exponent. SASSERT(significand <= 0x000FFFFFFFFFFFFFull); SASSERT(-1022 <= exponent && exponent <= 1023); - uint64 raw = (sign?0x8000000000000000ull:0); - raw |= (((uint64)exponent) + 1023) << 52; + uint64_t raw = (sign?0x8000000000000000ull:0); + raw |= (((uint64_t)exponent) + 1023) << 52; raw |= significand; memcpy(&o.value, &raw, sizeof(double)); } @@ -428,7 +428,7 @@ void hwf_manager::to_rational(hwf const & x, unsynch_mpq_manager & qm, mpq & o) } bool hwf_manager::is_zero(hwf const & x) { - uint64 t = RAW(x.value) & 0x7FFFFFFFFFFFFFFFull; + uint64_t t = RAW(x.value) & 0x7FFFFFFFFFFFFFFFull; return (t == 0x0ull); // CMW: I tried, and these are slower: // return (t != 0x0ull) ? false : true; @@ -483,12 +483,12 @@ bool hwf_manager::is_ninf(hwf const & x) { } bool hwf_manager::is_normal(hwf const & x) { - uint64 t = RAW(x.value) & 0x7FF0000000000000ull; + uint64_t t = RAW(x.value) & 0x7FF0000000000000ull; return (t != 0x0ull && t != 0x7FF0000000000000ull); } bool hwf_manager::is_denormal(hwf const & x) { - uint64 t = RAW(x.value); + uint64_t t = RAW(x.value); return ((t & 0x7FF0000000000000ull) == 0x0 && (t & 0x000FFFFFFFFFFFFFull) != 0x0); } @@ -498,7 +498,7 @@ bool hwf_manager::is_regular(hwf const & x) { // Note that +-0.0 and denormal numbers have exponent==0; these are regular. // All normal numbers are also regular. What remains is +-Inf and NaN, they are // not regular and they are the only numbers that have exponent 7FF. - uint64 e = RAW(x.value) & 0x7FF0000000000000ull; // the exponent + uint64_t e = RAW(x.value) & 0x7FF0000000000000ull; // the exponent return (e != 0x7FF0000000000000ull); } @@ -513,15 +513,15 @@ bool hwf_manager::is_int(hwf const & x) { return false; else { - uint64 t = sig(x); + uint64_t t = sig(x); unsigned shift = 52 - ((unsigned)e); - uint64 mask = (0x1ull << shift) - 1; + uint64_t mask = (0x1ull << shift) - 1; return (t & mask) == 0; } } void hwf_manager::mk_nzero(hwf & o) { - uint64 raw = 0x8000000000000000ull; + uint64_t raw = 0x8000000000000000ull; o.value = DBL(raw); } @@ -537,22 +537,22 @@ void hwf_manager::mk_zero(bool sign, hwf & o) { } void hwf_manager::mk_nan(hwf & o) { - uint64 raw = 0x7FF0000000000001ull; + uint64_t raw = 0x7FF0000000000001ull; o.value = DBL(raw); } void hwf_manager::mk_inf(bool sign, hwf & o) { - uint64 raw = (sign) ? 0xFFF0000000000000ull : 0x7FF0000000000000ull; + uint64_t raw = (sign) ? 0xFFF0000000000000ull : 0x7FF0000000000000ull; o.value = DBL(raw); } void hwf_manager::mk_pinf(hwf & o) { - uint64 raw = 0x7FF0000000000000ull; + uint64_t raw = 0x7FF0000000000000ull; o.value = DBL(raw); } void hwf_manager::mk_ninf(hwf & o) { - uint64 raw = 0xFFF0000000000000ull; + uint64_t raw = 0xFFF0000000000000ull; o.value = DBL(raw); } diff --git a/src/util/hwf.h b/src/util/hwf.h index 5f7692204..21e7655ea 100644 --- a/src/util/hwf.h +++ b/src/util/hwf.h @@ -28,8 +28,8 @@ class hwf { friend class hwf_manager; double value; hwf & operator=(hwf const & other) { UNREACHABLE(); return *this; } - uint64 get_raw() const { - uint64 n; + uint64_t get_raw() const { + uint64_t n; SASSERT(sizeof(n) == sizeof(value)); memcpy(&n, &value, sizeof(value)); return n; @@ -60,7 +60,7 @@ public: void set(hwf & o, mpf_rounding_mode rm, mpq const & value); void set(hwf & o, mpf_rounding_mode rm, char const * value); void set(hwf & o, mpf_rounding_mode rm, mpq const & significand, mpz const & exponent); - void set(hwf & o, bool sign, uint64 significand, int exponent); + void set(hwf & o, bool sign, uint64_t significand, int exponent); void set(hwf & o, hwf const & x); // auxiliary methods to make the interface compatible with mpf @@ -128,7 +128,7 @@ public: return (x.get_raw() & 0x8000000000000000ull) != 0; } - uint64 sig(hwf const & x) const { + uint64_t sig(hwf const & x) const { return x.get_raw() & 0x000FFFFFFFFFFFFFull; } diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h index c184623ca..d0b6f2d99 100644 --- a/src/util/inf_eps_rational.h +++ b/src/util/inf_eps_rational.h @@ -118,12 +118,12 @@ class inf_eps_rational { bool is_rational() const { return m_infty.is_zero() && m_r.is_rational(); } - int64 get_int64() const { + int64_t get_int64() const { SASSERT(is_int64()); return m_r.get_int64(); } - uint64 get_uint64() const { + uint64_t get_uint64() const { SASSERT(is_uint64()); return m_r.get_uint64(); } diff --git a/src/util/inf_int_rational.h b/src/util/inf_int_rational.h index c9c82052e..44ed76ebd 100644 --- a/src/util/inf_int_rational.h +++ b/src/util/inf_int_rational.h @@ -109,12 +109,12 @@ class inf_int_rational { bool is_rational() const { return m_second == 0; } - int64 get_int64() const { + int64_t get_int64() const { SASSERT(is_int64()); return m_first.get_int64(); } - uint64 get_uint64() const { + uint64_t get_uint64() const { SASSERT(is_uint64()); return m_first.get_uint64(); } diff --git a/src/util/inf_rational.h b/src/util/inf_rational.h index d49e45f50..c3f4160ba 100644 --- a/src/util/inf_rational.h +++ b/src/util/inf_rational.h @@ -122,12 +122,12 @@ class inf_rational { bool is_rational() const { return m_second.is_zero(); } - int64 get_int64() const { + int64_t get_int64() const { SASSERT(is_int64()); return m_first.get_int64(); } - uint64 get_uint64() const { + uint64_t get_uint64() const { SASSERT(is_uint64()); return m_first.get_uint64(); } diff --git a/src/util/inf_s_integer.h b/src/util/inf_s_integer.h index 067000202..dd136d1b9 100644 --- a/src/util/inf_s_integer.h +++ b/src/util/inf_s_integer.h @@ -60,8 +60,8 @@ class inf_s_integer { bool is_int64() const { return m_second == 0; } bool is_uint64() const { return m_second == 0; } bool is_rational() const { return m_second == 0; } - int64 get_int64() const { return m_first; } - uint64 get_uint64() const { return m_first; } + int64_t get_int64() const { return m_first; } + uint64_t get_uint64() const { return m_first; } s_integer get_rational() const { return s_integer(m_first); } s_integer get_infinitesimal() const { return s_integer(m_second); } inf_s_integer & operator=(const inf_s_integer & r) { diff --git a/src/util/mpbq.cpp b/src/util/mpbq.cpp index 9fcd1b58f..3edbdab67 100644 --- a/src/util/mpbq.cpp +++ b/src/util/mpbq.cpp @@ -250,7 +250,7 @@ void mpbq_manager::mul(mpbq const & a, mpz const & b, mpbq & r) { } void mpbq_manager::power(mpbq & a, unsigned k) { - SASSERT(static_cast(k) * static_cast(a.k()) <= static_cast(UINT_MAX)); + SASSERT(static_cast(k) * static_cast(a.k()) <= static_cast(UINT_MAX)); // We don't need to normalize because: // If a.m_k == 0, then a is an integer, and the result be an integer // If a.m_k > 0, then a.m_num must be odd, and the (a.m_num)^k will also be odd diff --git a/src/util/mpbq.h b/src/util/mpbq.h index 61ef2b0e2..ed8a8c523 100644 --- a/src/util/mpbq.h +++ b/src/util/mpbq.h @@ -84,7 +84,7 @@ public: void set(mpbq & a, mpz const & n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); } void set(mpbq & a, mpz const & n) { m_manager.set(a.m_num, n); a.m_k = 0; } void set(mpbq & a, mpbq const & b) { m_manager.set(a.m_num, b.m_num); a.m_k = b.m_k; } - void set(mpbq & a, int64 n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); } + void set(mpbq & a, int64_t n, unsigned k) { m_manager.set(a.m_num, n); a.m_k = k; normalize(a); } bool is_int(mpbq const & a) const { return a.m_k == 0; } void get_numerator(mpbq const & a, mpz & n) { m_manager.set(n, a.m_num); } diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index b9829f02d..17705cc34 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -115,11 +115,11 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { // double === mpf(11, 53) static_assert(sizeof(double) == 8, "doubles are 8 bytes"); - uint64 raw; + uint64_t raw; memcpy(&raw, &value, sizeof(double)); bool sign = (raw >> 63) != 0; - int64 e = ((raw & 0x7FF0000000000000ull) >> 52) - 1023; - uint64 s = raw & 0x000FFFFFFFFFFFFFull; + int64_t e = ((raw & 0x7FF0000000000000ull) >> 52) - 1023; + uint64_t s = raw & 0x000FFFFFFFFFFFFFull; TRACE("mpf_dbg", tout << "set: " << value << " is: raw=" << raw << " (double)" << " sign=" << sign << " s=" << s << " e=" << e << std::endl;); @@ -300,7 +300,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;); } -void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, uint64 significand) { +void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, uint64_t significand) { // Assumption: this represents (sign * -1) * (significand/2^sbits) * 2^exponent. o.ebits = ebits; o.sbits = sbits; @@ -1711,8 +1711,8 @@ void mpf_manager::to_rational(mpf const & x, unsynch_mpq_manager & qm, mpq & o) double mpf_manager::to_double(mpf const & x) { SASSERT(x.ebits <= 11 && x.sbits <= 53); - uint64 raw = 0; - int64 sig = 0, exp = 0; + uint64_t raw = 0; + int64_t sig = 0, exp = 0; sig = m_mpz_manager.get_uint64(x.significand); sig <<= 53 - x.sbits; @@ -1741,7 +1741,7 @@ float mpf_manager::to_float(mpf const & x) { unsigned int raw = 0; unsigned int sig = 0, exp = 0; - uint64 q = m_mpz_manager.get_uint64(x.significand); + uint64_t q = m_mpz_manager.get_uint64(x.significand); SASSERT(q < 4294967296ull); sig = q & 0x00000000FFFFFFFF; sig <<= 24 - x.sbits; @@ -1751,7 +1751,7 @@ float mpf_manager::to_float(mpf const & x) { else if (has_bot_exp(x)) exp = -127; else { - int64 q = x.exponent; + int64_t q = x.exponent; SASSERT(q < 4294967296ll); exp = q & 0x00000000FFFFFFFF; } diff --git a/src/util/mpf.h b/src/util/mpf.h index 27116e2de..107ada0bd 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -35,7 +35,7 @@ typedef enum { MPF_ROUND_TOWARD_ZERO } mpf_rounding_mode; -typedef int64 mpf_exp_t; +typedef int64_t mpf_exp_t; class mpf { friend class mpf_manager; @@ -80,7 +80,7 @@ public: void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & value); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, char const * value); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpz const & exponent, mpq const & significand); - void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, uint64 significand); + void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, uint64_t significand); void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, mpz const & significand); void set(mpf & o, mpf const & x); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpf const & x); diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index eac9cc80c..64e07f9f0 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -155,27 +155,27 @@ bool mpff_manager::is_uint64(mpff const & n) const { !has_one_at_first_k_bits(m_precision, sig(n), -n.m_exponent); } -uint64 mpff_manager::get_uint64(mpff const & a) const { +uint64_t mpff_manager::get_uint64(mpff const & a) const { SASSERT(is_uint64(a)); if (is_zero(a)) return 0; int exp = -a.m_exponent - sizeof(unsigned) * 8 * (m_precision - 2); SASSERT(exp >= 0); - uint64 * s = reinterpret_cast(sig(a) + (m_precision - 2)); + uint64_t * s = reinterpret_cast(sig(a) + (m_precision - 2)); return *s >> exp; } -int64 mpff_manager::get_int64(mpff const & a) const { +int64_t mpff_manager::get_int64(mpff const & a) const { SASSERT(is_int64(a)); if (is_zero(a)) return 0; int exp = -a.m_exponent - sizeof(unsigned) * 8 * (m_precision - 2); SASSERT(exp >= 0); - uint64 * s = reinterpret_cast(sig(a) + (m_precision - 2)); + uint64_t * s = reinterpret_cast(sig(a) + (m_precision - 2)); // INT64_MIN case if (exp == 0 && *s == 0x8000000000000000ull && is_neg(a)) { return INT64_MIN; } else { - int64 r = *s >> exp; + int64_t r = *s >> exp; if (is_neg(a)) r = -r; return r; @@ -249,26 +249,26 @@ void mpff_manager::set(mpff & n, unsigned v) { SASSERT(check(n)); } -void mpff_manager::set(mpff & n, int64 v) { +void mpff_manager::set(mpff & n, int64_t v) { if (v == 0) { reset(n); } else { if (v < 0) { - set(n, 1 + static_cast(-(1+v))); + set(n, 1 + static_cast(-(1+v))); n.m_sign = 1; } else { - set(n, static_cast(v)); + set(n, static_cast(v)); } } SASSERT(check(n)); SASSERT(get_int64(n) == v); } -void mpff_manager::set(mpff & n, uint64 v) { +void mpff_manager::set(mpff & n, uint64_t v) { #ifdef Z3DEBUG - uint64 old_v = v; + uint64_t old_v = v; #endif if (v == 0) { reset(n); @@ -278,7 +278,7 @@ void mpff_manager::set(mpff & n, uint64 v) { n.m_sign = 0; unsigned * _v = reinterpret_cast(&v); int num_leading_zeros = nlz(2, _v); - n.m_exponent = static_cast(8 * sizeof(uint64)) - num_leading_zeros - static_cast(m_precision_bits); + n.m_exponent = static_cast(8 * sizeof(uint64_t)) - num_leading_zeros - static_cast(m_precision_bits); v <<= num_leading_zeros; SASSERT(m_precision >= 2); unsigned * s = sig(n); @@ -299,7 +299,7 @@ void mpff_manager::set(mpff & n, int num, unsigned den) { SASSERT(check(n)); } -void mpff_manager::set(mpff & n, int64 num, uint64 den) { +void mpff_manager::set(mpff & n, int64_t num, uint64_t den) { scoped_mpff a(*this), b(*this); set(a, num); set(b, den); @@ -470,7 +470,7 @@ bool mpff_manager::lt(mpff const & a, mpff const & b) const { } } -void mpff_manager::inc_significand(unsigned * s, int64 & exp) { +void mpff_manager::inc_significand(unsigned * s, int64_t & exp) { if (!::inc(m_precision, s)) { SASSERT(::is_zero(m_precision, s)); s[m_precision - 1] = MIN_MSW; @@ -597,7 +597,7 @@ void mpff_manager::prev(mpff & a) { SASSERT(check(a)); } -void mpff_manager::set_big_exponent(mpff & a, int64 e) { +void mpff_manager::set_big_exponent(mpff & a, int64_t e) { SASSERT(e > INT_MAX || e < INT_MIN); if (e > INT_MAX) { if (a.m_sign == 1) { @@ -715,7 +715,7 @@ void mpff_manager::add_sub(bool is_sub, mpff const & a, mpff const & b, mpff & c else if (num_leading_zeros == sizeof(unsigned) * 8 - 1) { // shift 1 right bool _inc_significand = ((c.m_sign == 1) != m_to_plus_inf) && has_one_at_first_k_bits(m_precision*2, sig_r, 1); - int64 exp_c = exp_a; + int64_t exp_c = exp_a; exp_c++; shr(m_precision + 1, sig_r, 1, m_precision, sig_c); if (_inc_significand) @@ -728,7 +728,7 @@ void mpff_manager::add_sub(bool is_sub, mpff const & a, mpff const & b, mpff & c // Now, we can assume sig_r has size m_precision SASSERT(num_leading_zeros > 0); // shift left num_leading_zeros - int64 exp_c = exp_a; + int64_t exp_c = exp_a; exp_c -= num_leading_zeros; shl(m_precision, sig_r, num_leading_zeros, m_precision, sig_c); set_exponent(c, exp_c); @@ -752,7 +752,7 @@ void mpff_manager::add_sub(bool is_sub, mpff const & a, mpff const & b, mpff & c reset(c); } else if (num_leading_zeros > 0) { - int64 exp_c = exp_a; + int64_t exp_c = exp_a; exp_c -= num_leading_zeros; shl(m_precision, sig_c, num_leading_zeros, m_precision, sig_c); set_exponent(c, exp_c); @@ -787,10 +787,10 @@ void mpff_manager::mul(mpff const & a, mpff const & b, mpff & c) { allocate_if_needed(c); TRACE("mpff", tout << "mul("; display(tout, a); tout << ", "; display(tout, b); tout << ")\n";); c.m_sign = a.m_sign ^ b.m_sign; - // use int64 to make sure we do not have overflows - int64 exp_a = a.m_exponent; - int64 exp_b = b.m_exponent; - int64 exp_c = exp_a + exp_b; + // use int64_t to make sure we do not have overflows + int64_t exp_a = a.m_exponent; + int64_t exp_b = b.m_exponent; + int64_t exp_c = exp_a + exp_b; // store result in m_buffers[0] unsigned * r = m_buffers[0].c_ptr(); m_mpn_manager.mul(sig(a), m_precision, sig(b), m_precision, r); @@ -834,7 +834,7 @@ void mpff_manager::div(mpff const & a, mpff const & b, mpff & c) { #if 1 else if (is_two(b)) { set(c, a); - int64 exp_c = a.m_exponent; + int64_t exp_c = a.m_exponent; exp_c--; set_exponent(c, exp_c); } @@ -842,10 +842,10 @@ void mpff_manager::div(mpff const & a, mpff const & b, mpff & c) { else { allocate_if_needed(c); c.m_sign = a.m_sign ^ b.m_sign; - // use int64 to make sure we do not have overflows - int64 exp_a = a.m_exponent; - int64 exp_b = b.m_exponent; - int64 exp_c = exp_a - exp_b; + // use int64_t to make sure we do not have overflows + int64_t exp_a = a.m_exponent; + int64_t exp_b = b.m_exponent; + int64_t exp_c = exp_a - exp_b; exp_c -= m_precision_bits; // we will multiplying (shifting) a by 2^m_precision_bits. // copy a to buffer 0, and shift by m_precision_bits @@ -1023,7 +1023,7 @@ void mpff_manager::power(mpff const & a, unsigned p, mpff & b) { b.m_sign = 0; else b.m_sign = a.m_sign; - int64 exp = a.m_exponent; + int64_t exp = a.m_exponent; exp *= p; if (exp > INT_MAX || exp < INT_MIN) throw overflow_exception(); @@ -1057,7 +1057,7 @@ void mpff_manager::power(mpff const & a, unsigned p, mpff & b) { bool mpff_manager::is_power_of_two(mpff const & a, unsigned & k) const { if (!is_power_of_two(a)) return false; - int64 exp = a.m_exponent + m_precision_bits - 1; + int64_t exp = a.m_exponent + m_precision_bits - 1; SASSERT(exp >= 0); k = static_cast(exp); return true; @@ -1132,7 +1132,7 @@ void mpff_manager::to_mpq_core(mpff const & n, mpq_manager & m, mpq & t) if (exp < 0) { // Avoid -INT_MIN == INT_MIN issue. It is not really useful, since we will run out of memory anyway. if (exp == INT_MIN) - abs_exp = static_cast(-static_cast(INT_MIN)); + abs_exp = static_cast(-static_cast(INT_MIN)); else abs_exp = -exp; } @@ -1177,7 +1177,7 @@ void mpff_manager::display(std::ostream & out, mpff const & n) const { svector & u_buffer = const_cast(this)->m_buffers[0]; int num_trailing_zeros = ntz(m_precision, u_buffer.c_ptr()); int shift = 0; - int64 exp = n.m_exponent; // use int64 to avoid -INT_MIN == INT_MIN issue + int64_t exp = n.m_exponent; // use int64_t to avoid -INT_MIN == INT_MIN issue if (exp < 0) { if (num_trailing_zeros >= -exp) { shift = static_cast(-exp); @@ -1194,7 +1194,7 @@ void mpff_manager::display(std::ostream & out, mpff const & n) const { out << m_mpn_manager.to_string(u_buffer.c_ptr(), m_precision, str_buffer.begin(), str_buffer.size()); if (exp > 0) { if (exp <= 63) { - uint64 _exp = 1; + uint64_t _exp = 1; _exp <<= exp; out << "*" << _exp; } @@ -1209,7 +1209,7 @@ void mpff_manager::display(std::ostream & out, mpff const & n) const { else if (exp < 0) { exp = -exp; if (exp <= 63) { - uint64 _exp = 1; + uint64_t _exp = 1; _exp <<= exp; out << "/" << _exp; } @@ -1225,8 +1225,8 @@ void mpff_manager::display(std::ostream & out, mpff const & n) const { void mpff_manager::display_decimal(std::ostream & out, mpff const & n, unsigned prec, unsigned min_exponent) { // The result in scientific notation when n.m_exponent >= min_exponent or n.m_exponent <= - min_exponent - m_precision_bits - int64 exp = n.m_exponent; - if (exp >= min_exponent || exp <= -static_cast(min_exponent) - m_precision_bits || is_int(n)) { + int64_t exp = n.m_exponent; + if (exp >= min_exponent || exp <= -static_cast(min_exponent) - m_precision_bits || is_int(n)) { display(out, n); return; } @@ -1327,7 +1327,7 @@ void mpff_manager::display_smt2(std::ostream & out, mpff const & n, bool decimal svector & u_buffer = const_cast(this)->m_buffers[0]; int num_trailing_zeros = ntz(m_precision, u_buffer.c_ptr()); int shift = 0; - int64 exp = n.m_exponent; + int64_t exp = n.m_exponent; if (exp < 0) { if (num_trailing_zeros >= -exp) { shift = static_cast(-exp); @@ -1353,7 +1353,7 @@ void mpff_manager::display_smt2(std::ostream & out, mpff const & n, bool decimal if (exp != 0) { if (exp < 0) exp = -exp; if (exp <= 63) { - uint64 _exp = 1; + uint64_t _exp = 1; _exp <<= exp; out << _exp; if (decimal) out << ".0"; @@ -1387,8 +1387,8 @@ unsigned mpff_manager::prev_power_of_two(mpff const & a) { return 0; if (a.m_exponent <= -static_cast(m_precision_bits)) return 0; // Number is smaller than 1 - SASSERT(static_cast(a.m_exponent) + static_cast(m_precision_bits) - 1 >= 0); - SASSERT(static_cast(a.m_exponent) + static_cast(m_precision_bits) - 1 <= static_cast(static_cast(UINT_MAX))); + SASSERT(static_cast(a.m_exponent) + static_cast(m_precision_bits) - 1 >= 0); + SASSERT(static_cast(a.m_exponent) + static_cast(m_precision_bits) - 1 <= static_cast(static_cast(UINT_MAX))); return m_precision_bits + a.m_exponent - 1; } diff --git a/src/util/mpff.h b/src/util/mpff.h index e34f2cb41..8023053d2 100644 --- a/src/util/mpff.h +++ b/src/util/mpff.h @@ -92,7 +92,7 @@ class mpff_manager { // // Remarks: // - // - All values of type int, unsigned, int64 and uint64 can be precisely represented as mpff numerals. + // - All values of type int, unsigned, int64_t and uint64_t can be precisely represented as mpff numerals. // // - Hardware float and double values (corresponding to rationals) can also be precisely represented as mpff numerals. // That is, NaN, +oo and -oo are not supported by this module. @@ -141,14 +141,14 @@ class mpff_manager { // copy (and shift by m_precision_bits) n to buffer idx void to_buffer_shifting(unsigned idx, mpff const & n) const; - void inc_significand(unsigned * s, int64 & exp); + void inc_significand(unsigned * s, int64_t & exp); void inc_significand(mpff & a); void dec_significand(mpff & a); bool min_significand(mpff const & a) const; void set_min_significand(mpff & a); void set_max_significand(mpff & a); - void set_big_exponent(mpff & a, int64 e); - void set_exponent(mpff & a, int64 e) { + void set_big_exponent(mpff & a, int64_t e); + void set_exponent(mpff & a, int64_t e) { if (e > INT_MAX || e < INT_MIN) set_big_exponent(a, e); else @@ -286,12 +286,12 @@ public: bool is_plus_epsilon(mpff const & a) const; /** - \brief Return true if \c a is an integer and fits in an int64 machine integer. + \brief Return true if \c a is an integer and fits in an int64_t machine integer. */ bool is_int64(mpff const & a) const; /** - \brief Return true if \c a is a non-negative integer and fits in an int64 machine integer. + \brief Return true if \c a is a non-negative integer and fits in an int64_t machine integer. */ bool is_uint64(mpff const & a) const; @@ -372,10 +372,10 @@ public: void set(mpff & n, int v); void set(mpff & n, unsigned v); - void set(mpff & n, int64 v); - void set(mpff & n, uint64 v); + void set(mpff & n, int64_t v); + void set(mpff & n, uint64_t v); void set(mpff & n, int num, unsigned den); - void set(mpff & n, int64 num, uint64 den); + 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); @@ -448,14 +448,14 @@ public: \pre is_int64(n) */ - int64 get_int64(mpff const & n) const; + int64_t get_int64(mpff const & n) const; /** \brief Return n as an uint64. \pre is_uint64(n) */ - uint64 get_uint64(mpff const & n) const; + uint64_t get_uint64(mpff const & n) const; /** \brief Return the biggest k s.t. 2^k <= a. diff --git a/src/util/mpfx.cpp b/src/util/mpfx.cpp index e46708341..e17a5e766 100644 --- a/src/util/mpfx.cpp +++ b/src/util/mpfx.cpp @@ -164,10 +164,10 @@ void mpfx_manager::set(mpfx & n, unsigned v) { SASSERT(check(n)); } -void mpfx_manager::set(mpfx & n, int64 v) { +void mpfx_manager::set(mpfx & n, int64_t v) { if (m_int_part_sz == 1) { - if (v < -static_cast(static_cast(UINT_MAX)) || - v > static_cast(static_cast(UINT_MAX))) + if (v < -static_cast(static_cast(UINT_MAX)) || + v > static_cast(static_cast(UINT_MAX))) throw overflow_exception(); } if (v == 0) { @@ -175,11 +175,11 @@ void mpfx_manager::set(mpfx & n, int64 v) { } else { if (v < 0) { - set(n, static_cast(-v)); + set(n, static_cast(-v)); n.m_sign = 1; } else { - set(n, static_cast(v)); + set(n, static_cast(v)); } } SASSERT(is_int(n)); @@ -187,9 +187,9 @@ void mpfx_manager::set(mpfx & n, int64 v) { SASSERT(check(n)); } -void mpfx_manager::set(mpfx & n, uint64 v) { +void mpfx_manager::set(mpfx & n, uint64_t v) { if (m_int_part_sz == 1) { - if (v > static_cast(UINT_MAX)) + if (v > static_cast(UINT_MAX)) throw overflow_exception(); } @@ -200,7 +200,7 @@ void mpfx_manager::set(mpfx & n, uint64 v) { allocate_if_needed(n); n.m_sign = 0; unsigned * w = words(n); - uint64 * _vp = &v; + uint64_t * _vp = &v; unsigned * _v = nullptr; memcpy(&_v, &_vp, sizeof(unsigned*)); for (unsigned i = 0; i < m_total_sz; i++) @@ -226,7 +226,7 @@ void mpfx_manager::set(mpfx & n, int num, unsigned den) { SASSERT(check(n)); } -void mpfx_manager::set(mpfx & n, int64 num, uint64 den) { +void mpfx_manager::set(mpfx & n, int64_t num, uint64_t den) { scoped_mpfx a(*this), b(*this); set(a, num); set(b, den); @@ -677,27 +677,27 @@ bool mpfx_manager::is_power_of_two(mpfx const & a) const { return is_power_of_two(a, k); } -int64 mpfx_manager::get_int64(mpfx const & n) const { +int64_t mpfx_manager::get_int64(mpfx const & n) const { SASSERT(is_int64(n)); unsigned * w = words(n); w += m_frac_part_sz; - uint64 r = 0; - memcpy(&r, w, sizeof(uint64)); + uint64_t r = 0; + memcpy(&r, w, sizeof(uint64_t)); if (r == 0x8000000000000000ull) { SASSERT(is_neg(n)); return INT64_MIN; } else { - return is_neg(n) ? -static_cast(r) : r; + return is_neg(n) ? -static_cast(r) : r; } } -uint64 mpfx_manager::get_uint64(mpfx const & n) const { +uint64_t mpfx_manager::get_uint64(mpfx const & n) const { SASSERT(is_uint64(n)); unsigned * w = words(n); w += m_frac_part_sz; - uint64 r = 0; - memcpy(&r, w, sizeof(uint64)); + uint64_t r = 0; + memcpy(&r, w, sizeof(uint64_t)); return r; } diff --git a/src/util/mpfx.h b/src/util/mpfx.h index 03a805f69..a8e93f0b0 100644 --- a/src/util/mpfx.h +++ b/src/util/mpfx.h @@ -200,12 +200,12 @@ public: bool is_minus_one(mpfx const & n) const { return is_neg(n) && is_abs_one(n); } /** - \brief Return true if \c a is an integer and fits in an int64 machine integer. + \brief Return true if \c a is an integer and fits in an \c int64_t machine integer. */ bool is_int64(mpfx const & a) const; /** - \brief Return true if \c a is a non-negative integer and fits in an int64 machine integer. + \brief Return true if \c a is a non-negative integer and fits in an \c int64_t machine integer. */ bool is_uint64(mpfx const & a) const; @@ -306,10 +306,10 @@ public: void set(mpfx & n, int v); void set(mpfx & n, unsigned v); - void set(mpfx & n, int64 v); - void set(mpfx & n, uint64 v); + void set(mpfx & n, int64_t v); + void set(mpfx & n, uint64_t v); void set(mpfx & n, int num, unsigned den); - void set(mpfx & n, int64 num, uint64 den); + 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); @@ -343,14 +343,14 @@ public: \pre is_int64(n) */ - int64 get_int64(mpfx const & n) const; + int64_t get_int64(mpfx const & n) const; /** \brief Return n as an uint64. \pre is_uint64(n) */ - uint64 get_uint64(mpfx const & n) const; + uint64_t get_uint64(mpfx const & n) const; /** \brief Convert n into a mpz numeral. diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index 2059ea6fd..b8cab4a9f 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -23,7 +23,7 @@ Revision History: #define max(a,b) (((a) > (b)) ? (a) : (b)) -typedef uint64 mpn_double_digit; +typedef uint64_t mpn_double_digit; static_assert(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit), "size alignment"); const mpn_digit mpn_manager::zero = 0; diff --git a/src/util/mpq.h b/src/util/mpq.h index fd0ae13d4..f1b261278 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -686,7 +686,7 @@ public: normalize(a); } - void set(mpq & a, int64 n, uint64 d) { + void set(mpq & a, int64_t n, uint64_t d) { SASSERT(d != 0); set(a.m_num, n); set(a.m_den, d); @@ -718,16 +718,16 @@ public: void set(mpq & a, char const * val); - void set(mpz & a, int64 val) { mpz_manager::set(a, val); } + void set(mpz & a, int64_t val) { mpz_manager::set(a, val); } - void set(mpq & a, int64 val) { + void set(mpq & a, int64_t val) { set(a.m_num, val); reset_denominator(a); } - void set(mpz & a, uint64 val) { mpz_manager::set(a, val); } + void set(mpz & a, uint64_t val) { mpz_manager::set(a, val); } - void set(mpq & a, uint64 val) { + void set(mpq & a, uint64_t val) { set(a.m_num, val); reset_denominator(a); } @@ -765,17 +765,17 @@ public: bool is_int64(mpz const & a) const { return mpz_manager::is_int64(a); } - uint64 get_uint64(mpz const & a) const { return mpz_manager::get_uint64(a); } + uint64_t get_uint64(mpz const & a) const { return mpz_manager::get_uint64(a); } - int64 get_int64(mpz const & a) const { return mpz_manager::get_int64(a); } + int64_t get_int64(mpz const & a) const { return mpz_manager::get_int64(a); } bool is_uint64(mpq const & a) const { return is_int(a) && is_uint64(a.m_num); } bool is_int64(mpq const & a) const { return is_int(a) && is_int64(a.m_num); } - uint64 get_uint64(mpq const & a) const { SASSERT(is_uint64(a)); return get_uint64(a.m_num); } + uint64_t get_uint64(mpq const & a) const { SASSERT(is_uint64(a)); return get_uint64(a.m_num); } - int64 get_int64(mpq const & a) const { SASSERT(is_int64(a)); return get_int64(a.m_num); } + int64_t get_int64(mpq const & a) const { SASSERT(is_int64(a)); return get_int64(a.m_num); } double get_double(mpz const & a) const { return mpz_manager::get_double(a); } diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 7ad472ef1..39ea428a7 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -81,7 +81,7 @@ static T gcd_core(T u, T v) { } unsigned u_gcd(unsigned u, unsigned v) { return gcd_core(u, v); } -uint64 u64_gcd(uint64 u, uint64 v) { return gcd_core(u, v); } +uint64_t u64_gcd(uint64_t u, uint64_t v) { return gcd_core(u, v); } template mpz_manager::mpz_manager(): @@ -89,7 +89,7 @@ mpz_manager::mpz_manager(): if (SYNCH) omp_init_nest_lock(&m_lock); #ifndef _MP_GMP - if (sizeof(digit_t) == sizeof(uint64)) { + if (sizeof(digit_t) == sizeof(uint64_t)) { // 64-bit machine m_init_cell_capacity = 4; } @@ -101,7 +101,7 @@ mpz_manager::mpz_manager(): m_arg[i] = allocate(m_init_cell_capacity); m_arg[i]->m_size = 1; } - set(m_int_min, -static_cast(INT_MIN)); + set(m_int_min, -static_cast(INT_MIN)); #else // GMP mpz_init(m_tmp); @@ -122,8 +122,8 @@ mpz_manager::mpz_manager(): mpz_init(m_int64_max); mpz_init(m_int64_min); - max_l = static_cast(INT64_MAX % static_cast(UINT_MAX)); - max_h = static_cast(INT64_MAX / static_cast(UINT_MAX)); + max_l = static_cast(INT64_MAX % static_cast(UINT_MAX)); + max_h = static_cast(INT64_MAX / static_cast(UINT_MAX)); mpz_set_ui(m_int64_max, max_h); mpz_set_ui(m_tmp, UINT_MAX); mpz_mul(m_int64_max, m_tmp, m_int64_max); @@ -134,7 +134,7 @@ mpz_manager::mpz_manager(): #endif mpz one(1); - set(m_two64, (uint64)UINT64_MAX); + set(m_two64, (uint64_t)UINT64_MAX); add(m_two64, one, m_two64); } @@ -162,13 +162,13 @@ mpz_manager::~mpz_manager() { } template -void mpz_manager::set_big_i64(mpz & c, int64 v) { +void mpz_manager::set_big_i64(mpz & c, int64_t v) { #ifndef _MP_GMP if (is_small(c)) { c.m_ptr = allocate(m_init_cell_capacity); } SASSERT(capacity(c) >= m_init_cell_capacity); - uint64 _v; + uint64_t _v; if (v < 0) { _v = -v; c.m_val = -1; @@ -177,7 +177,7 @@ void mpz_manager::set_big_i64(mpz & c, int64 v) { _v = v; c.m_val = 1; } - if (sizeof(digit_t) == sizeof(uint64)) { + if (sizeof(digit_t) == sizeof(uint64_t)) { // 64-bit machine digits(c)[0] = static_cast(_v); c.m_ptr->m_size = 1; @@ -192,7 +192,7 @@ void mpz_manager::set_big_i64(mpz & c, int64 v) { if (is_small(c)) { c.m_ptr = allocate(); } - uint64 _v; + uint64_t _v; bool sign; if (v < 0) { _v = -v; @@ -212,14 +212,14 @@ void mpz_manager::set_big_i64(mpz & c, int64 v) { } template -void mpz_manager::set_big_ui64(mpz & c, uint64 v) { +void mpz_manager::set_big_ui64(mpz & c, uint64_t v) { #ifndef _MP_GMP if (is_small(c)) { c.m_ptr = allocate(m_init_cell_capacity); } SASSERT(capacity(c) >= m_init_cell_capacity); c.m_val = 1; - if (sizeof(digit_t) == sizeof(uint64)) { + if (sizeof(digit_t) == sizeof(uint64_t)) { // 64-bit machine digits(c)[0] = static_cast(v); c.m_ptr->m_size = 1; @@ -726,7 +726,7 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { // For now, it only works if sizeof(digit_t) == sizeof(unsigned) static_assert(sizeof(digit_t) == sizeof(unsigned), ""); - int64 a_hat, b_hat, A, B, C, D, T, q, a_sz, b_sz; + int64_t a_hat, b_hat, A, B, C, D, T, q, a_sz, b_sz; mpz a1, b1, t, r, tmp; set(a1, a); set(b1, b); @@ -766,10 +766,10 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { D = 1; while (true) { // Loop invariants - SASSERT(a_hat + A <= static_cast(UINT_MAX) + 1); - SASSERT(a_hat + B < static_cast(UINT_MAX) + 1); - SASSERT(b_hat + C < static_cast(UINT_MAX) + 1); - SASSERT(b_hat + D <= static_cast(UINT_MAX) + 1); + SASSERT(a_hat + A <= static_cast(UINT_MAX) + 1); + SASSERT(a_hat + B < static_cast(UINT_MAX) + 1); + SASSERT(b_hat + C < static_cast(UINT_MAX) + 1); + SASSERT(b_hat + D <= static_cast(UINT_MAX) + 1); // overflows can't happen since I'm using int64 if (b_hat + C == 0 || b_hat + D == 0) break; @@ -1035,7 +1035,7 @@ void mpz_manager::bitwise_or(mpz const & a, mpz const & b, mpz & c) { mod(a1, m_two64, a2); mod(b1, m_two64, b2); TRACE("mpz", tout << "a2: " << to_string(a2) << ", b2: " << to_string(b2) << "\n";); - uint64 v = get_uint64(a2) | get_uint64(b2); + uint64_t v = get_uint64(a2) | get_uint64(b2); TRACE("mpz", tout << "uint(a2): " << get_uint64(a2) << ", uint(b2): " << get_uint64(b2) << "\n";); set(tmp, v); mul(tmp, m, tmp); @@ -1082,7 +1082,7 @@ void mpz_manager::bitwise_and(mpz const & a, mpz const & b, mpz & c) { while (!is_zero(a1) && !is_zero(b1)) { mod(a1, m_two64, a2); mod(b1, m_two64, b2); - uint64 v = get_uint64(a2) & get_uint64(b2); + uint64_t v = get_uint64(a2) & get_uint64(b2); set(tmp, v); mul(tmp, m, tmp); add(c, tmp, c); // c += m * v @@ -1119,7 +1119,7 @@ void mpz_manager::bitwise_xor(mpz const & a, mpz const & b, mpz & c) { while (!is_zero(a1) && !is_zero(b1)) { mod(a1, m_two64, a2); mod(b1, m_two64, b2); - uint64 v = get_uint64(a2) ^ get_uint64(b2); + uint64_t v = get_uint64(a2) ^ get_uint64(b2); set(tmp, v); mul(tmp, m, tmp); add(c, tmp, c); // c += m * v @@ -1151,7 +1151,7 @@ template void mpz_manager::bitwise_not(unsigned sz, mpz const & a, mpz & c) { SASSERT(is_nonneg(a)); if (is_small(a) && sz <= 63) { - int64 mask = (static_cast(1) << sz) - static_cast(1); + int64_t mask = (static_cast(1) << sz) - static_cast(1); set_i64(c, (~ i64(a)) & mask); } else { @@ -1161,11 +1161,11 @@ void mpz_manager::bitwise_not(unsigned sz, mpz const & a, mpz & c) { set(c, 0); while (sz > 0) { mod(a1, m_two64, a2); - uint64 n = get_uint64(a2); - uint64 v = ~n; + uint64_t n = get_uint64(a2); + uint64_t v = ~n; SASSERT(~v == n); if (sz < 64) { - uint64 mask = (1ull << static_cast(sz)) - 1ull; + uint64_t mask = (1ull << static_cast(sz)) - 1ull; v = mask & v; } TRACE("bitwise_not", tout << "sz: " << sz << ", v: " << v << ", n: " << n << "\n";); @@ -1265,7 +1265,7 @@ bool mpz_manager::is_uint64(mpz const & a) const { return false; if (is_small(a)) return true; - if (sizeof(digit_t) == sizeof(uint64)) { + if (sizeof(digit_t) == sizeof(uint64_t)) { return size(a) <= 1; } else { @@ -1286,9 +1286,9 @@ bool mpz_manager::is_int64(mpz const & a) const { #ifndef _MP_GMP if (!is_abs_uint64(a)) return false; - uint64 num = big_abs_to_uint64(a); - uint64 msb = static_cast(1) << 63; - uint64 msb_val = msb & num; + uint64_t num = big_abs_to_uint64(a); + uint64_t msb = static_cast(1) << 63; + uint64_t msb_val = msb & num; if (a.m_val >= 0) { // non-negative number. return (0 == msb_val); @@ -1307,54 +1307,54 @@ bool mpz_manager::is_int64(mpz const & a) const { } template -uint64 mpz_manager::get_uint64(mpz const & a) const { +uint64_t mpz_manager::get_uint64(mpz const & a) const { if (is_small(a)) - return static_cast(a.m_val); + return static_cast(a.m_val); #ifndef _MP_GMP SASSERT(a.m_ptr->m_size > 0); return big_abs_to_uint64(a); #else // GMP version - if (sizeof(uint64) == sizeof(unsigned long)) { + if (sizeof(uint64_t) == sizeof(unsigned long)) { return mpz_get_ui(*a.m_ptr); } else { mpz_manager * _this = const_cast(this); mpz_set(_this->m_tmp, *a.m_ptr); mpz_mod(_this->m_tmp, m_tmp, m_two32); - uint64 r = static_cast(mpz_get_ui(m_tmp)); + uint64_t r = static_cast(mpz_get_ui(m_tmp)); mpz_set(_this->m_tmp, *a.m_ptr); mpz_div(_this->m_tmp, m_tmp, m_two32); - r += static_cast(mpz_get_ui(m_tmp)) << static_cast(32); + r += static_cast(mpz_get_ui(m_tmp)) << static_cast(32); return r; } #endif } template -int64 mpz_manager::get_int64(mpz const & a) const { +int64_t mpz_manager::get_int64(mpz const & a) const { if (is_small(a)) - return static_cast(a.m_val); + return static_cast(a.m_val); #ifndef _MP_GMP SASSERT(is_int64(a)); - uint64 num = big_abs_to_uint64(a); + uint64_t num = big_abs_to_uint64(a); if (a.m_val < 0) { if (num != 0 && (num << 1) == 0) return INT64_MIN; - return -static_cast(num); + return -static_cast(num); } - return static_cast(num); + return static_cast(num); #else // GMP - if (sizeof(int64) == sizeof(long) || mpz_fits_slong_p(*a.m_ptr)) { + if (sizeof(int64_t) == sizeof(long) || mpz_fits_slong_p(*a.m_ptr)) { return mpz_get_si(*a.m_ptr); } else { mpz_manager * _this = const_cast(this); mpz_mod(_this->m_tmp, *a.m_ptr, m_two32); - int64 r = static_cast(mpz_get_ui(m_tmp)); + int64_t r = static_cast(mpz_get_ui(m_tmp)); mpz_div(_this->m_tmp, *a.m_ptr, m_two32); - r += static_cast(mpz_get_si(m_tmp)) << static_cast(32); + r += static_cast(mpz_get_si(m_tmp)) << static_cast(32); return r; } #endif @@ -1370,7 +1370,7 @@ double mpz_manager::get_double(mpz const & a) const { unsigned sz = size(a); for (unsigned i = 0; i < sz; i++) { r += d * static_cast(digits(a)[i]); - if (sizeof(digit_t) == sizeof(uint64)) + if (sizeof(digit_t) == sizeof(uint64_t)) d *= static_cast(UINT64_MAX); // 64-bit version else d *= static_cast(UINT_MAX); // 32-bit version @@ -1696,7 +1696,7 @@ void mpz_manager::mul2k(mpz & a, unsigned k) { if (k == 0 || is_zero(a)) return; if (is_small(a) && k < 32) { - set_i64(a, i64(a) * (static_cast(1) << k)); + set_i64(a, i64(a) * (static_cast(1) << k)); return; } #ifndef _MP_GMP @@ -1798,9 +1798,9 @@ unsigned mpz_manager::power_of_two_multiple(mpz const & a) { if (sizeof(digit_t) == 8) { // TODO: we can remove this if after we move to MPN // In MPN the digit_t is always an unsigned integer - if (static_cast(v) % (static_cast(1) << 32) == 0) { + if (static_cast(v) % (static_cast(1) << 32) == 0) { r += 32; - v = static_cast(static_cast(v) / (static_cast(1) << 32)); + v = static_cast(static_cast(v) / (static_cast(1) << 32)); } } COUNT_DIGIT_RIGHT_ZEROS(); diff --git a/src/util/mpz.h b/src/util/mpz.h index f4c3f6f0d..92c6d0d10 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -30,7 +30,7 @@ Revision History: #include "util/mpn.h" unsigned u_gcd(unsigned u, unsigned v); -uint64 u64_gcd(uint64 u, uint64 v); +uint64_t u64_gcd(uint64_t u, uint64_t v); #ifdef _MP_GMP typedef unsigned digit_t; @@ -192,11 +192,11 @@ class mpz_manager { template void set(mpz & a, int sign, unsigned sz); - static int64 i64(mpz const & a) { return static_cast(a.m_val); } + static int64_t i64(mpz const & a) { return static_cast(a.m_val); } - void set_big_i64(mpz & c, int64 v); + void set_big_i64(mpz & c, int64_t v); - void set_i64(mpz & c, int64 v) { + void set_i64(mpz & c, int64_t v) { if (v >= INT_MIN && v <= INT_MAX) { del(c); c.m_val = static_cast(v); @@ -208,7 +208,7 @@ class mpz_manager { } } - void set_big_ui64(mpz & c, uint64 v); + void set_big_ui64(mpz & c, uint64_t v); #ifndef _MP_GMP static unsigned capacity(mpz const & c) { return c.m_ptr->m_capacity; } @@ -221,24 +221,24 @@ class mpz_manager { static bool is_abs_uint64(mpz const & a) { if (is_small(a)) return true; - if (sizeof(digit_t) == sizeof(uint64)) + if (sizeof(digit_t) == sizeof(uint64_t)) return size(a) <= 1; else return size(a) <= 2; } // CAST the absolute value into a UINT64 - static uint64 big_abs_to_uint64(mpz const & a) { + static uint64_t big_abs_to_uint64(mpz const & a) { SASSERT(is_abs_uint64(a)); SASSERT(!is_small(a)); if (a.m_ptr->m_size == 1) return digits(a)[0]; - if (sizeof(digit_t) == sizeof(uint64)) + if (sizeof(digit_t) == sizeof(uint64_t)) // 64-bit machine return digits(a)[0]; else // 32-bit machine - return ((static_cast(digits(a)[1]) << 32) | (static_cast(digits(a)[0]))); + return ((static_cast(digits(a)[1]) << 32) | (static_cast(digits(a)[0]))); } template @@ -426,8 +426,8 @@ public: void machine_div_rem(mpz const & a, mpz const & b, mpz & q, mpz & r) { STRACE("mpz", tout << "[mpz-ext] divrem(" << to_string(a) << ", " << to_string(b) << ") == ";); if (is_small(a) && is_small(b)) { - int64 _a = i64(a); - int64 _b = i64(b); + int64_t _a = i64(a); + int64_t _b = i64(b); set_i64(q, _a / _b); set_i64(r, _a % _b); } @@ -686,16 +686,16 @@ public: if (val <= INT_MAX) set(a, static_cast(val)); else - set(a, static_cast(static_cast(val))); + set(a, static_cast(static_cast(val))); } void set(mpz & a, char const * val); - void set(mpz & a, int64 val) { + void set(mpz & a, int64_t val) { set_i64(a, val); } - void set(mpz & a, uint64 val) { + void set(mpz & a, uint64_t val) { if (val < INT_MAX) { del(a); a.m_val = static_cast(val); @@ -729,9 +729,9 @@ public: bool is_int64(mpz const & a) const; - uint64 get_uint64(mpz const & a) const; + uint64_t get_uint64(mpz const & a) const; - int64 get_int64(mpz const & a) const; + int64_t get_int64(mpz const & a) const; bool is_uint(mpz const & a) const { return is_uint64(a) && get_uint64(a) < UINT_MAX; } diff --git a/src/util/mpzzp.h b/src/util/mpzzp.h index a30eff7b6..82ed55bbc 100644 --- a/src/util/mpzzp.h +++ b/src/util/mpzzp.h @@ -87,7 +87,7 @@ public: setup_p(); } - mpzzp_manager(numeral_manager & _m, uint64 p, bool prime = true): + mpzzp_manager(numeral_manager & _m, uint64_t p, bool prime = true): m_manager(_m), m_z(false) { m().set(m_p, p); @@ -120,7 +120,7 @@ public: void set_z() { m_z = true; } void set_zp(mpz const & new_p) { m_z = false; m_p_prime = true; m().set(m_p, new_p); setup_p(); } - void set_zp(uint64 new_p) { m_z = false; m_p_prime = true; m().set(m_p, new_p); setup_p(); } + void set_zp(uint64_t new_p) { m_z = false; m_p_prime = true; m().set(m_p, new_p); setup_p(); } // p = p^2 void set_p_sq() { SASSERT(!m_z); m_p_prime = false; m().mul(m_p, m_p, m_p); setup_p(); } void set_zp_swap(mpz & new_p) { SASSERT(!m_z); m().swap(m_p, new_p); setup_p(); } @@ -230,14 +230,14 @@ public: void set(mpz & a, int val) { m().set(a, val); p_normalize(a); } void set(mpz & a, unsigned val) { m().set(a, val); p_normalize(a); } void set(mpz & a, char const * val) { m().set(a, val); p_normalize(a); } - void set(mpz & a, int64 val) { m().set(a, val); p_normalize(a); } - void set(mpz & a, uint64 val) { m().set(a, val); p_normalize(a); } + void set(mpz & a, int64_t val) { m().set(a, val); p_normalize(a); } + void set(mpz & a, uint64_t val) { m().set(a, val); p_normalize(a); } void set(mpz & a, mpz const & val) { m().set(a, val); p_normalize(a); } bool is_uint64(mpz & a) const { const_cast(this)->p_normalize(a); return m().is_uint64(a); } bool is_int64(mpz & a) const { const_cast(this)->p_normalize(a); return m().is_int64(a); } - uint64 get_uint64(mpz & a) const { const_cast(this)->p_normalize(a); return m().get_uint64(a); } - int64 get_int64(mpz & a) const { const_cast(this)->p_normalize(a); return m().get_int64(a); } + uint64_t get_uint64(mpz & a) const { const_cast(this)->p_normalize(a); return m().get_uint64(a); } + int64_t get_int64(mpz & a) const { const_cast(this)->p_normalize(a); return m().get_int64(a); } double get_double(mpz & a) const { const_cast(this)->p_normalize(a); return m().get_double(a); } void power(mpz const & a, unsigned k, mpz & b) { SASSERT(is_p_normalized(a)); @@ -265,8 +265,8 @@ public: bool is_uint64(mpz const & a) const { return m().is_uint64(a); } bool is_int64(mpz const & a) const { return m().is_int64(a); } - uint64 get_uint64(mpz const & a) const { return m().get_uint64(a); } - int64 get_int64(mpz const & a) const { return m().get_int64(a); } + uint64_t get_uint64(mpz const & a) const { return m().get_uint64(a); } + int64_t get_int64(mpz const & a) const { return m().get_int64(a); } void mul2k(mpz & a, unsigned k) { m().mul2k(a, k); p_normalize(a); } void mul2k(mpz const & a, unsigned k, mpz & r) { m().mul2k(a, k, r); p_normalize(r); } diff --git a/src/util/prime_generator.cpp b/src/util/prime_generator.cpp index dbcccaaf7..6c0376e52 100644 --- a/src/util/prime_generator.cpp +++ b/src/util/prime_generator.cpp @@ -26,11 +26,11 @@ prime_generator::prime_generator() { process_next_k_numbers(128); } -void prime_generator::process_next_k_numbers(uint64 k) { - svector todo; - uint64 begin = m_primes.back() + 2; - uint64 end = begin + k; - for (uint64 i = begin; i < end; i+=2) { +void prime_generator::process_next_k_numbers(uint64_t k) { + svector todo; + uint64_t begin = m_primes.back() + 2; + uint64_t end = begin + k; + for (uint64_t i = begin; i < end; i+=2) { todo.push_back(i); } unsigned j = 1; @@ -38,7 +38,7 @@ void prime_generator::process_next_k_numbers(uint64 k) { while (!todo.empty()) { unsigned sz = m_primes.size(); for (; j < sz; j++) { - uint64 p = m_primes[j]; + uint64_t p = m_primes[j]; unsigned todo_sz = todo.size(); unsigned k1 = 0; unsigned k2 = 0; @@ -59,7 +59,7 @@ void prime_generator::process_next_k_numbers(uint64 k) { return; } } - uint64 p = m_primes.back(); + uint64_t p = m_primes.back(); p = p*p; unsigned todo_sz = todo.size(); unsigned k1 = 0; @@ -83,7 +83,7 @@ void prime_generator::finalize() { m_primes.finalize(); } -uint64 prime_generator::operator()(unsigned idx) { +uint64_t prime_generator::operator()(unsigned idx) { if (idx < m_primes.size()) return m_primes[idx]; if (idx > PRIME_LIST_MAX_SIZE) @@ -109,14 +109,14 @@ prime_iterator::prime_iterator(prime_generator * g):m_idx(0) { } } -uint64 prime_iterator::next() { +uint64_t prime_iterator::next() { unsigned idx = m_idx; m_idx++; if (!m_global) { return (*m_generator)(idx); } else { - uint64 r; + uint64_t r; #pragma omp critical (prime_iterator) { r = (*m_generator)(idx); diff --git a/src/util/prime_generator.h b/src/util/prime_generator.h index 2e16ebfbe..bd388954c 100644 --- a/src/util/prime_generator.h +++ b/src/util/prime_generator.h @@ -32,11 +32,11 @@ public: \brief Prime generator */ class prime_generator { - svector m_primes; - void process_next_k_numbers(uint64 k); + svector m_primes; + void process_next_k_numbers(uint64_t k); public: prime_generator(); - uint64 operator()(unsigned idx); + uint64_t operator()(unsigned idx); void finalize(); }; @@ -46,7 +46,7 @@ class prime_iterator { bool m_global; public: prime_iterator(prime_generator * g = nullptr); - uint64 next(); + uint64_t next(); static void finalize(); /* ADD_FINALIZER('prime_iterator::finalize();') diff --git a/src/util/rational.h b/src/util/rational.h index 392a1982b..dc7b79419 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -59,10 +59,10 @@ public: explicit rational(char const * v) { m().set(m_val, v); } struct i64 {}; - rational(int64 i, i64) { m().set(m_val, i); } + rational(int64_t i, i64) { m().set(m_val, i); } struct ui64 {}; - rational(uint64 i, ui64) { m().set(m_val, i); } + rational(uint64_t i, ui64) { m().set(m_val, i); } ~rational() { m().del(m_val); } @@ -98,9 +98,9 @@ public: bool is_int64() const { return m().is_int64(m_val); } - uint64 get_uint64() const { return m().get_uint64(m_val); } + uint64_t get_uint64() const { return m().get_uint64(m_val); } - int64 get_int64() const { return m().get_int64(m_val); } + int64_t get_int64() const { return m().get_int64(m_val); } bool is_unsigned() const { return is_uint64() && (get_uint64() < (1ull << 32)); } @@ -113,7 +113,7 @@ public: if (is_small() && is_int()) return true; // we don't assume that if it is small, then it is int32. if (!is_int64()) return false; - int64 v = get_int64(); + int64_t v = get_int64(); return INT_MIN <= v && v <= INT_MAX; } diff --git a/src/util/rlimit.cpp b/src/util/rlimit.cpp index e625cab95..e3afd0d92 100644 --- a/src/util/rlimit.cpp +++ b/src/util/rlimit.cpp @@ -26,7 +26,7 @@ reslimit::reslimit(): m_limit(0) { } -uint64 reslimit::count() const { +uint64_t reslimit::count() const { return m_count; } @@ -41,7 +41,7 @@ bool reslimit::inc(unsigned offset) { } void reslimit::push(unsigned delta_limit) { - uint64 new_limit = delta_limit + m_count; + uint64_t new_limit = delta_limit + m_count; if (new_limit <= m_count) { new_limit = 0; } diff --git a/src/util/rlimit.h b/src/util/rlimit.h index 0c81f9449..60d26be7f 100644 --- a/src/util/rlimit.h +++ b/src/util/rlimit.h @@ -24,9 +24,9 @@ Revision History: class reslimit { volatile unsigned m_cancel; bool m_suspend; - uint64 m_count; - uint64 m_limit; - svector m_limits; + uint64_t m_count; + uint64_t m_limit; + svector m_limits; ptr_vector m_children; void set_cancel(unsigned f); @@ -41,7 +41,7 @@ public: bool inc(); bool inc(unsigned offset); - uint64 count() const; + uint64_t count() const; bool get_cancel_flag() const { return m_cancel > 0 && !m_suspend; } diff --git a/src/util/s_integer.h b/src/util/s_integer.h index 658ae8eea..80310368d 100644 --- a/src/util/s_integer.h +++ b/src/util/s_integer.h @@ -46,9 +46,9 @@ public: s_integer(const s_integer & r):m_val(r.m_val) {} explicit s_integer(int n):m_val(n) {} struct i64 {}; - explicit s_integer(int64 i, i64):m_val(static_cast(i)) {} + explicit s_integer(int64_t i, i64):m_val(static_cast(i)) {} struct ui64 {}; - explicit s_integer(uint64 i, ui64):m_val(static_cast(i)) {} + explicit s_integer(uint64_t i, ui64):m_val(static_cast(i)) {} explicit s_integer(const char * str); explicit s_integer(const rational & r):m_val(static_cast(r.get_int64())) {} @@ -60,8 +60,8 @@ public: static bool is_int64() { return true; } static bool is_uint64() { return true; } int get_int() const { return m_val; } - int64 get_int64() const { return m_val; } - uint64 get_uint64() const { return m_val; } + int64_t get_int64() const { return m_val; } + uint64_t get_uint64() const { return m_val; } static bool is_unsigned() { return true; } unsigned get_unsigned() const { return static_cast(m_val); } s_integer const& get_s_integer() const { return *this; } diff --git a/src/util/total_order.h b/src/util/total_order.h index a309b63a1..44ab6f749 100644 --- a/src/util/total_order.h +++ b/src/util/total_order.h @@ -35,7 +35,7 @@ class total_order { struct cell { cell * m_next; cell * m_prev; - uint64 m_val; + uint64_t m_val; T m_data; }; @@ -53,11 +53,11 @@ class total_order { m_base.m_val = 0; } - uint64 v(cell * a) const { return a->m_val; } + uint64_t v(cell * a) const { return a->m_val; } - uint64 vb(cell * a) const { return v(a) - v(base()); } + uint64_t vb(cell * a) const { return v(a) - v(base()); } - uint64 vbn(cell * a) const { return a->m_next == base() ? UINT64_MAX : vb(a->m_next); } + uint64_t vbn(cell * a) const { return a->m_next == base() ? UINT64_MAX : vb(a->m_next); } cell * mk_cell(T const & a) { SASSERT(!m_map.contains(a)); @@ -84,18 +84,18 @@ class total_order { } void _insert_after(cell * a, cell * b) { - uint64 vb_a = vb(a); - uint64 vbn_a = vbn(a); + uint64_t vb_a = vb(a); + uint64_t vbn_a = vbn(a); SASSERT(vb_a < vbn_a); if (vbn_a < 2 || (vb_a > vbn_a - 2)) { TRACE("total_order", tout << "relabeling...\n"; tout << "\n";); - uint64 v0 = v(a); - unsigned sz = size(); - uint64 ideal_gap = UINT64_MAX / sz; - uint64 goal_gap = ideal_gap / 32; - cell * c = a->m_next->m_next; - unsigned j = 2; - uint64 curr_gap = (v(c) - v0) / j; + uint64_t v0 = v(a); + unsigned sz = size(); + uint64_t ideal_gap = UINT64_MAX / sz; + uint64_t goal_gap = ideal_gap / 32; + cell * c = a->m_next->m_next; + unsigned j = 2; + uint64_t curr_gap = (v(c) - v0) / j; while (j < sz && curr_gap < goal_gap) { j++; c = c->m_next; @@ -105,7 +105,7 @@ class total_order { if (j == sz) curr_gap = ideal_gap; c = a->m_next; - uint64 inc = curr_gap; + uint64_t inc = curr_gap; for (unsigned i = 0; i < j; i++) { c->m_val = v0 + inc; c = c->m_next; @@ -116,7 +116,7 @@ class total_order { vbn_a = vbn(a); } SASSERT(vb_a <= vbn_a - 2); - uint64 vb_b = vb_a + ((vbn_a - vb_a)/2); + uint64_t vb_b = vb_a + ((vbn_a - vb_a)/2); SASSERT(vb_b > vb_a); SASSERT(vb_b < vbn_a); b->m_val = vb_b + v(base()); diff --git a/src/util/util.cpp b/src/util/util.cpp index 0b58419f8..8ffa89877 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -80,7 +80,7 @@ unsigned log2(unsigned v) { return r; } -unsigned uint64_log2(uint64 v) { +unsigned uint64_log2(uint64_t v) { unsigned r = 0; if (v & 0xFFFFFFFF00000000ull) { v >>= 32; diff --git a/src/util/util.h b/src/util/util.h index ad427dfaf..3fc6f6510 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -29,23 +29,11 @@ Revision History: #define SIZE_MAX std::numeric_limits::max() #endif -#ifndef uint64 -typedef unsigned long long uint64; -#endif - -static_assert(sizeof(uint64) == 8, "64 bits please"); - -#ifndef int64 -typedef long long int64; -#endif - -static_assert(sizeof(int64) == 8, "64 bits"); - #ifndef INT64_MIN -#define INT64_MIN static_cast(0x8000000000000000ull) +#define INT64_MIN static_cast(0x8000000000000000ull) #endif #ifndef INT64_MAX -#define INT64_MAX static_cast(0x7fffffffffffffffull) +#define INT64_MAX static_cast(0x7fffffffffffffffull) #endif #ifndef UINT64_MAX #define UINT64_MAX 0xffffffffffffffffull @@ -110,7 +98,7 @@ inline unsigned next_power_of_two(unsigned v) { \brief Return the position of the most significant bit. */ unsigned log2(unsigned v); -unsigned uint64_log2(uint64 v); +unsigned uint64_log2(uint64_t v); static_assert(sizeof(unsigned) == 4, "unsigned are 32 bits"); @@ -136,11 +124,11 @@ static inline unsigned get_num_1bits(unsigned v) { // Remark: on gcc, the operators << and >> do not produce zero when the second argument >= 64. // So, I'm using the following two definitions to fix the problem -static inline uint64 shift_right(uint64 x, uint64 y) { +static inline uint64_t shift_right(uint64_t x, uint64_t y) { return y < 64ull ? (x >> y) : 0ull; } -static inline uint64 shift_left(uint64 x, uint64 y) { +static inline uint64_t shift_left(uint64_t x, uint64_t y) { return y < 64ull ? (x << y) : 0ull; } From 21a3b9c8e2d61af7b0b71260430402c68bbf2585 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Mar 2018 05:20:47 -0700 Subject: [PATCH 0727/1283] increment version number due to ABI/API breaking change #1556 Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- src/api/dotnet/AlgebraicNum.cs | 4 ++-- src/api/dotnet/BitVecNum.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c11c272be..bd3774ac7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 6) -set(Z3_VERSION_PATCH 2) +set(Z3_VERSION_PATCH 3) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 2f7402760..b77975dfa 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 6, 2, 0) + set_version(4, 6, 3, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') diff --git a/src/api/dotnet/AlgebraicNum.cs b/src/api/dotnet/AlgebraicNum.cs index 66552f1a0..3687e1f83 100644 --- a/src/api/dotnet/AlgebraicNum.cs +++ b/src/api/dotnet/AlgebraicNum.cs @@ -3,11 +3,11 @@ Copyright (c) 2012 Microsoft Corporation Module Name: - IntNum.cs + AlgebraicNum.cs Abstract: - Z3 Managed API: Int Numerals + Z3 Managed API: Algebraic Numerals Author: diff --git a/src/api/dotnet/BitVecNum.cs b/src/api/dotnet/BitVecNum.cs index c6ac471f6..66054761a 100644 --- a/src/api/dotnet/BitVecNum.cs +++ b/src/api/dotnet/BitVecNum.cs @@ -3,11 +3,11 @@ Copyright (c) 2012 Microsoft Corporation Module Name: - IntNum.cs + BitVecNum.cs Abstract: - Z3 Managed API: Int Numerals + Z3 Managed API: BitVec Numerals Author: From a914142c7c6caf89dca96f99c211f449d9725b26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Mar 2018 05:34:11 -0700 Subject: [PATCH 0728/1283] bit-blaster Signed-off-by: Nikolaj Bjorner --- src/tactic/aig/aig_tactic.cpp | 3 ++- src/tactic/bv/bit_blaster_model_converter.cpp | 10 ++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/tactic/aig/aig_tactic.cpp b/src/tactic/aig/aig_tactic.cpp index 25c693fde..720c799e0 100644 --- a/src/tactic/aig/aig_tactic.cpp +++ b/src/tactic/aig/aig_tactic.cpp @@ -67,7 +67,6 @@ public: void operator()(goal_ref const & g) { SASSERT(g->is_well_sorted()); - tactic_report report("aig", *g); mk_aig_manager mk(*this, g->m()); if (m_aig_per_assertion) { @@ -92,8 +91,10 @@ public: void operator()(goal_ref const & g, goal_ref_buffer & result) override { fail_if_proof_generation("aig", g); + tactic_report report("aig", *g); operator()(g); g->inc_depth(); + TRACE("aig", g->display(tout);); result.push_back(g.get()); } diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 406781c1f..4fb66b05d 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -123,10 +123,7 @@ struct bit_blaster_model_converter : public model_converter { SASSERT(is_uninterp_const(bit)); func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); - if (bit_val == nullptr) { - goto bail; - } - if (m().is_true(bit_val)) + if (bit_val != nullptr && m().is_true(bit_val)) val++; } } @@ -141,10 +138,7 @@ struct bit_blaster_model_converter : public model_converter { func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); // remark: if old_model does not assign bit_val, then assume it is false. - if (bit_val == nullptr) { - goto bail; - } - if (!util.is_zero(bit_val)) + if (bit_val != nullptr && !util.is_zero(bit_val)) val++; } } From 55eb11d91b853dc1a3234b706a538b8f10228d2e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Mar 2018 13:26:20 -0700 Subject: [PATCH 0729/1283] fix bug in blocked clause elimination: it was ignoring unit literals Signed-off-by: Nikolaj Bjorner --- src/sat/sat_model_converter.cpp | 20 ++++++++++++------- src/sat/sat_simplifier.cpp | 6 +++--- src/sat/sat_solver.cpp | 13 +++++------- src/tactic/bv/bit_blaster_model_converter.cpp | 15 +++----------- src/tactic/smtlogics/qfufbv_tactic.cpp | 16 ++++++++------- 5 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 6b0eb1a7c..c9d046197 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -79,21 +79,27 @@ namespace sat { //SASSERT(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; - SASSERT(it->get_kind() != ELIM_VAR || m[it->var()] == l_undef); - // if it->get_kind() == BLOCK_LIT, then it might be the case that m[it->var()] != l_undef, + bool_var v0 = it->var(); + SASSERT(it->get_kind() != ELIM_VAR || m[v0] == l_undef); + // if it->get_kind() == BLOCK_LIT, then it might be the case that m[v] != l_undef, // and the following procedure flips its value. bool sat = false; bool var_sign = false; unsigned index = 0; literal_vector clause; - VERIFY(legal_to_flip(it->var())); + VERIFY(legal_to_flip(v0)); for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause + if (v0 == 36858) + IF_VERBOSE(0, verbose_stream() << "clause: " << clause << "\n"; + for (literal lit : clause) verbose_stream() << m[lit.var()] << " "; + verbose_stream() << "\n";); + elim_stack* st = it->m_elim_stack[index]; if (!sat) { - VERIFY(legal_to_flip(it->var())); - m[it->var()] = var_sign ? l_false : l_true; + VERIFY(legal_to_flip(v0)); + m[v0] = var_sign ? l_false : l_true; } if (st) { process_stack(m, clause, st->stack()); @@ -115,11 +121,11 @@ namespace sat { bool_var v = l.var(); if (v >= m.size()) std::cout << v << " model size: " << m.size() << "\n"; VERIFY(v < m.size()); - if (v == it->var()) + if (v == v0) var_sign = sign; if (value_at(l, m) == l_true) sat = true; - else if (!sat && v != it->var() && m[v] == l_undef) { + else if (!sat && v != v0 && m[v] == l_undef) { VERIFY(legal_to_flip(v)); // clause can be satisfied by assigning v. m[v] = sign ? l_false : l_true; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 6ef0be83a..642fca348 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1007,7 +1007,7 @@ namespace sat { } bool process_var(bool_var v) { - return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v); + return !s.s.is_assumption(v) && !s.was_eliminated(v) && !s.is_external(v) && s.value(v) == l_undef; } enum elim_type { @@ -1184,7 +1184,7 @@ namespace sat { if (m_covered_antecedent[i] == clause_ante()) s.mark_visited(lit); if (s.is_marked(lit)) idx = i; } - if (_blocked.var() == 16774 && false) { + if (false && _blocked.var() == 16774) { IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n"; verbose_stream() << "tautology: " << m_tautology << "\n"; verbose_stream() << "index: " << idx << "\n"; @@ -1232,7 +1232,7 @@ namespace sat { // unsigned sz0 = m_covered_clause.size(); m_covered_clause.resize(j); VERIFY(j >= m_clause.size()); - if (_blocked.var() == 16774 && false) { + if (false && _blocked.var() == 16774) { IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n"); } // IF_VERBOSE(0, verbose_stream() << "reduced from size " << sz0 << " to " << m_covered_clause << "\n" << m_clause << "\n";); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1617b487b..7def379e0 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -333,13 +333,6 @@ namespace sat { } void solver::mk_bin_clause(literal l1, literal l2, bool learned) { -#if 0 - if ((l1 == literal(5981, false) && l2 == literal(16764, false)) || - (l2 == literal(5981, false) && l1 == literal(16764, false))) { - IF_VERBOSE(0, display(verbose_stream())); - //VERIFY(false); - } -#endif if (find_binary_watch(get_wlist(~l1), ~l2)) { assign(l1, justification()); return; @@ -487,6 +480,8 @@ namespace sat { return reinit; } + static unsigned s_count = 0; + void solver::attach_clause(clause & c, bool & reinit) { SASSERT(c.size() > 2); reinit = false; @@ -1674,7 +1669,9 @@ namespace sat { if (!m_clone->check_model(m_model)) { //IF_VERBOSE(0, display(verbose_stream())); //IF_VERBOSE(0, display_watches(verbose_stream())); - //IF_VERBOSE(0, m_mc.display(verbose_stream())); + IF_VERBOSE(0, m_mc.display(verbose_stream())); + IF_VERBOSE(0, display_units(verbose_stream())); + //IF_VERBOSE(0, m_clone->display(verbose_stream() << "clone\n")); throw solver_exception("check model failed (for cloned solver)"); } } diff --git a/src/tactic/bv/bit_blaster_model_converter.cpp b/src/tactic/bv/bit_blaster_model_converter.cpp index 785ecb57e..5474700c3 100644 --- a/src/tactic/bv/bit_blaster_model_converter.cpp +++ b/src/tactic/bv/bit_blaster_model_converter.cpp @@ -52,7 +52,7 @@ struct bit_blaster_model_converter : public model_converter { m_newbits.push_back(f); } - virtual ~bit_blaster_model_converter() { + ~bit_blaster_model_converter() override { } void collect_bits(obj_hashtable & bits) { @@ -123,10 +123,7 @@ struct bit_blaster_model_converter : public model_converter { SASSERT(is_uninterp_const(bit)); func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); - if (bit_val == 0) { - goto bail; - } - if (m().is_true(bit_val)) + if (bit_val != nullptr && m().is_true(bit_val)) val++; } } @@ -141,18 +138,12 @@ struct bit_blaster_model_converter : public model_converter { func_decl * bit_decl = to_app(bit)->get_decl(); expr * bit_val = old_model->get_const_interp(bit_decl); // remark: if old_model does not assign bit_val, then assume it is false. - if (bit_val == 0) { - goto bail; - } - if (!util.is_zero(bit_val)) + if (bit_val != nullptr && !util.is_zero(bit_val)) val++; } } new_val = util.mk_numeral(val, bv_sz); new_model->register_decl(m_vars.get(i), new_val); - continue; - bail: - new_model->register_decl(m_vars.get(i), mk_bv(bs, *old_model)); } } diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index 7e64b9c2c..b762f6b09 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -40,6 +40,7 @@ Notes: #include "tactic/smtlogics/qfbv_tactic.h" #include "solver/tactic2solver.h" #include "tactic/bv/bv_bound_chk_tactic.h" +#include "ackermannization/ackermannize_bv_tactic.h" /////////////// class qfufbv_ackr_tactic : public tactic { @@ -158,13 +159,14 @@ static tactic * mk_qfufbv_preamble1(ast_manager & m, params_ref const & p) { static tactic * mk_qfufbv_preamble(ast_manager & m, params_ref const & p) { return and_then(mk_simplify_tactic(m), - mk_propagate_values_tactic(m), - mk_solve_eqs_tactic(m), - mk_elim_uncnstr_tactic(m), - if_no_proofs(if_no_unsat_cores(mk_reduce_args_tactic(m))), - if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), - mk_max_bv_sharing_tactic(m) - ); + mk_propagate_values_tactic(m), + mk_solve_eqs_tactic(m), + mk_elim_uncnstr_tactic(m), + if_no_proofs(if_no_unsat_cores(mk_reduce_args_tactic(m))), + if_no_proofs(if_no_unsat_cores(mk_bv_size_reduction_tactic(m))), + mk_max_bv_sharing_tactic(m), + if_no_proofs(if_no_unsat_cores(mk_ackermannize_bv_tactic(m,p))) + ); } tactic * mk_qfufbv_tactic(ast_manager & m, params_ref const & p) { From 528dc8a3f8cbbd9f3d4fb017cf87d13fedb810af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Mar 2018 17:05:22 -0700 Subject: [PATCH 0730/1283] disable bdd variable elimination Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause_use_list.h | 9 +++++ src/sat/sat_elim_eqs.cpp | 2 +- src/sat/sat_elim_vars.cpp | 9 ++--- src/sat/sat_elim_vars.h | 2 +- src/sat/sat_model_converter.cpp | 5 --- src/sat/sat_simplifier.cpp | 12 +++++-- src/sat/sat_simplifier.h | 1 + src/sat/sat_solver.cpp | 3 +- src/tactic/portfolio/parallel_tactic.cpp | 45 +++++++++++++++--------- src/tactic/smtlogics/qfbv_tactic.cpp | 2 ++ 10 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/sat/sat_clause_use_list.h b/src/sat/sat_clause_use_list.h index c028ad713..90c2d7779 100644 --- a/src/sat/sat_clause_use_list.h +++ b/src/sat/sat_clause_use_list.h @@ -124,6 +124,15 @@ namespace sat { }; iterator mk_iterator() const { return iterator(const_cast(this)->m_clauses); } + + std::ostream& display(std::ostream& out) const { + iterator it = mk_iterator(); + while (!it.at_end()) { + out << it.curr() << "\n"; + it.next(); + } + return out; + } }; }; diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 11c1d4780..870aa7fe2 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -199,7 +199,7 @@ namespace sat { literal r = roots[v]; SASSERT(v != r.var()); bool root_ok = !m_solver.is_external(v) || m_solver.set_root(l, r); - if (m_solver.is_external(v) && (m_solver.is_incremental() || !root_ok)) { + if (m_solver.is_assumption(v) || (m_solver.is_external(v) && (m_solver.is_incremental() || !root_ok))) { // cannot really eliminate v, since we have to notify extension of future assignments m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(l, ~r, false); diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index 34f871a8f..a80807450 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -101,7 +101,7 @@ namespace sat{ pos_occs.reset(); neg_occs.reset(); literal_vector lits; - add_clauses(b, lits); + add_clauses(v, b, lits); return true; } @@ -157,7 +157,7 @@ namespace sat{ return b; } - void elim_vars::add_clauses(bdd const& b, literal_vector& lits) { + void elim_vars::add_clauses(bool_var v0, bdd const& b, literal_vector& lits) { if (b.is_true()) { // no-op } @@ -167,6 +167,7 @@ namespace sat{ if (simp.cleanup_clause(c)) return; + if (v0 == 39063) IF_VERBOSE(0, verbose_stream() << "bdd: " << c << "\n"); switch (c.size()) { case 0: s.set_conflict(justification()); @@ -198,10 +199,10 @@ namespace sat{ else { unsigned v = m_vars[b.var()]; lits.push_back(literal(v, false)); - add_clauses(b.lo(), lits); + add_clauses(v0, b.lo(), lits); lits.pop_back(); lits.push_back(literal(v, true)); - add_clauses(b.hi(), lits); + add_clauses(v0, b.hi(), lits); lits.pop_back(); } } diff --git a/src/sat/sat_elim_vars.h b/src/sat/sat_elim_vars.h index ba5a02d67..b62fdc5db 100644 --- a/src/sat/sat_elim_vars.h +++ b/src/sat/sat_elim_vars.h @@ -57,7 +57,7 @@ namespace sat { bdd make_clauses(literal lit); bdd mk_literal(literal l); void get_clauses(bdd const& b, literal_vector& lits, clause_vector& clauses, literal_vector& units); - void add_clauses(bdd const& b, literal_vector& lits); + void add_clauses(bool_var v, bdd const& b, literal_vector& lits); bool elim_var(bool_var v, bdd const& b); bdd elim_var(bool_var v); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index c9d046197..c2a4858f7 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -91,11 +91,6 @@ namespace sat { for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause - if (v0 == 36858) - IF_VERBOSE(0, verbose_stream() << "clause: " << clause << "\n"; - for (literal lit : clause) verbose_stream() << m[lit.var()] << " "; - verbose_stream() << "\n";); - elim_stack* st = it->m_elim_stack[index]; if (!sat) { VERIFY(legal_to_flip(v0)); diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 642fca348..bac790698 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1518,6 +1518,14 @@ namespace sat { } void block_covered_clause(clause& c, literal l, model_converter::kind k) { + if (false && l.var() == 39021) { + IF_VERBOSE(0, verbose_stream() << "blocked: " << l << " @ " << c << " :covered " << m_covered_clause << "\n"; + s.m_use_list.display(verbose_stream() << "use " << l << ":", l); + s.m_use_list.display(verbose_stream() << "use " << ~l << ":", ~l); + /*s.s.display(verbose_stream());*/ + ); + + } TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); SASSERT(!s.is_external(l)); model_converter::entry& new_entry = mc.mk(k, l.var()); @@ -1563,7 +1571,6 @@ namespace sat { for (literal l2 : m_intersection) { watched* w = find_binary_watch(s.get_wlist(~l), ~l2); if (!w) { - IF_VERBOSE(10, verbose_stream() << "bca " << l << " " << ~l2 << "\n";); s.s.mk_bin_clause(l, ~l2, true); ++s.m_num_bca; } @@ -1934,6 +1941,7 @@ namespace sat { m_new_cls.reset(); if (!resolve(c1, c2, pos_l, m_new_cls)) continue; + // if (v == 39063) IF_VERBOSE(0, verbose_stream() << "elim: " << c1 << " + " << c2 << " -> " << m_new_cls << "\n"); TRACE("resolution_new_cls", tout << c1 << "\n" << c2 << "\n-->\n" << m_new_cls << "\n";); if (cleanup_clause(m_new_cls)) continue; // clause is already satisfied. @@ -2045,7 +2053,7 @@ namespace sat { m_subsumption = p.subsumption(); m_subsumption_limit = p.subsumption_limit(); m_elim_vars = p.elim_vars(); - m_elim_vars_bdd = p.elim_vars_bdd(); + m_elim_vars_bdd = false && p.elim_vars_bdd(); // buggy m_elim_vars_bdd_delay = p.elim_vars_bdd_delay(); m_incremental_mode = s.get_config().m_incremental && !p.override_incremental(); } diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 086111f84..a777e07a4 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -47,6 +47,7 @@ namespace sat { clause_use_list & get(literal l) { return m_use_list[l.index()]; } clause_use_list const & get(literal l) const { return m_use_list[l.index()]; } void finalize() { m_use_list.finalize(); } + std::ostream& display(std::ostream& out, literal l) const { return m_use_list[l.index()].display(out); } }; class simplifier { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 7def379e0..299b1f704 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1654,11 +1654,10 @@ namespace sat { // m_mc.set_solver(nullptr); m_mc(m_model); - if (!check_clauses(m_model)) { IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";); - IF_VERBOSE(10, m_mc.display(verbose_stream())); + // IF_VERBOSE(10, m_mc.display(verbose_stream())); throw solver_exception("check model failed"); } diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 4a5af3679..b19bab487 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -114,10 +114,10 @@ class parallel_tactic : public tactic { dec_wait(); return st; } - { - std::unique_lock lock(m_mutex); - m_cond.wait(lock); - } + { + std::unique_lock lock(m_mutex); + m_cond.wait(lock); + } dec_wait(); } return nullptr; @@ -233,7 +233,9 @@ class parallel_tactic : public tactic { void inc_depth(unsigned inc) { m_depth += inc; } - void inc_width(unsigned w) { m_width *= w; } + void inc_width(unsigned w) { + m_width *= w; + } double get_width() const { return m_width; } @@ -280,14 +282,14 @@ class parallel_tactic : public tactic { void set_cube_params() { unsigned cutoff = m_cube_cutoff; double fraction = m_cube_fraction; - if (m_depth == 1 && cutoff > 0) { - fraction = 0; // use fixed cubing at depth 1. + if (true || (m_depth == 1 && cutoff > 0)) { + m_params.set_sym("lookahead.cube.cutoff", symbol("depth")); + m_params.set_uint("lookahead.cube.depth", std::max(m_depth, 10u)); } else { - cutoff = 0; // use dynamic cubing beyond depth 1 + m_params.set_sym("lookahead.cube.cutoff", symbol("adaptive_psat")); + m_params.set_double("lookahead.cube.fraction", fraction); } - m_params.set_uint ("lookahead.cube.cutoff", cutoff); - m_params.set_double("lookahead.cube.fraction", fraction); get_solver().updt_params(m_params); } @@ -329,6 +331,7 @@ private: task_queue m_queue; std::mutex m_mutex; double m_progress; + unsigned m_branches; bool m_has_undef; bool m_allsat; unsigned m_num_unsat; @@ -341,20 +344,27 @@ private: m_has_undef = false; m_allsat = false; m_num_unsat = 0; + m_branches = 0; m_exn_code = 0; m_params.set_bool("override_incremental", true); } + void add_branches(unsigned b) { + std::lock_guard lock(m_mutex); + m_branches += b; + } + void close_branch(solver_state& s, lbool status) { double f = 100.0 / s.get_width(); { std::lock_guard lock(m_mutex); m_progress += f; + --m_branches; } - IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; + IF_VERBOSE(0, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; if (status == l_true) verbose_stream() << ":status sat "; if (status == l_undef) verbose_stream() << ":status unknown "; - verbose_stream() << ":unsat " << m_num_unsat << ")\n";); + verbose_stream() << ":unsat " << m_num_unsat << " :branches " << m_branches << ")\n";); } void report_sat(solver_state& s) { @@ -401,7 +411,7 @@ private: cube.reset(); cube.append(s.split_cubes(1)); SASSERT(cube.size() <= 1); - IF_VERBOSE(2, verbose_stream() << "(sat.parallel :split-cube " << cube.size() << ")\n";); + IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :split-cube " << cube.size() << ")\n";); if (!s.cubes().empty()) m_queue.add_task(s.clone()); if (!cube.empty()) s.assert_cube(cube.get(0)); s.inc_depth(1); @@ -430,8 +440,8 @@ private: cubes.push_back(mk_and(c)); } - IF_VERBOSE(1, verbose_stream() << "(parallel_tactic :cubes " << cubes.size() << ")\n";); - IF_VERBOSE(10, verbose_stream() << "(parallel_tactic :cubes " << cubes << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :cubes " << cubes.size() << ")\n";); + IF_VERBOSE(12, verbose_stream() << "(tactic.parallel :cubes " << cubes << ")\n";); if (cubes.empty()) { report_unsat(s); @@ -439,6 +449,7 @@ private: } else { s.inc_width(cubes.size()); + add_branches(cubes.size()); s.set_cubes(cubes); s.set_type(conquer_task); goto conquer; @@ -462,7 +473,7 @@ private: } if (canceled(s)) return; } - IF_VERBOSE(1, verbose_stream() << "(parallel_tactic :cubes " << cubes.size() << " :hard-cubes " << hard_cubes.size() << ")\n";); + IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :cubes " << cubes.size() << " :hard-cubes " << hard_cubes.size() << ")\n";); if (hard_cubes.empty()) return; s.set_cubes(hard_cubes); @@ -534,7 +545,7 @@ private: m_stats.display(out); m_queue.display(out); std::lock_guard lock(m_mutex); - out << "(parallel_tactic :unsat " << m_num_unsat << " :progress " << m_progress << "% :models " << m_models.size() << ")\n"; + out << "(tactic.parallel :unsat " << m_num_unsat << " :progress " << m_progress << "% :models " << m_models.size() << ")\n"; return out; } diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index b69069864..f28129a52 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -28,6 +28,7 @@ Notes: #include "tactic/bv/bv_size_reduction_tactic.h" #include "tactic/aig/aig_tactic.h" #include "sat/tactic/sat_tactic.h" +#include "tactic/portfolio/parallel_tactic.h" #include "ackermannization/ackermannize_bv_tactic.h" #define MEMLIMIT 300 @@ -130,6 +131,7 @@ tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { tactic * new_sat = cond(mk_produce_proofs_probe(), and_then(mk_simplify_tactic(m), mk_smt_tactic()), + //mk_parallel_tactic(m, p)); mk_sat_tactic(m)); return mk_qfbv_tactic(m, p, new_sat, mk_smt_tactic()); From 6b38edf102a84e9b6da62f8700107276a9791502 Mon Sep 17 00:00:00 2001 From: Moritz Kiefer Date: Tue, 3 Apr 2018 11:57:31 +0200 Subject: [PATCH 0731/1283] Fix buffering issue in print_success for declare-datatype --- src/parsers/smt2/smt2parser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 9265312d4..e72b9ad79 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -949,8 +949,9 @@ namespace smt2 { check_duplicate(d, line, pos); d->commit(pm()); - check_rparen_next("invalid end of datatype declaration, ')' expected"); + check_rparen("invalid end of datatype declaration, ')' expected"); m_ctx.print_success(); + next(); } From 6a3ce301b748280f6bb8c1eef959382848b83bf8 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Tue, 3 Apr 2018 12:51:03 -0400 Subject: [PATCH 0732/1283] fix collection error --- src/smt/theory_str.cpp | 3 +++ src/smt/theory_str.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 21b6e7b26..811b66798 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1854,6 +1854,9 @@ namespace smt { std::pair key1(ex->get_arg(0), regexStr); // skip Z3str's map check, because we already check if we set up axioms on this term regex_in_bool_map[key1] = ex; + if (!regex_in_var_reg_str_map.contains(ex->get_arg(0))) { + regex_in_var_reg_str_map.insert(ex->get_arg(0), std::set()); + } regex_in_var_reg_str_map[ex->get_arg(0)].insert(regexStr); } diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index d68d99abc..e9607585f 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -399,7 +399,7 @@ protected: obj_hashtable regex_terms; obj_map > regex_terms_by_string; // S --> [ (str.in.re S *) ] obj_map > regex_automaton_assumptions; // RegEx --> [ aut+assumptions ] - std::map regex_nfa_cache; // Regex term --> NFA + obj_map regex_nfa_cache; // Regex term --> NFA obj_hashtable regex_terms_with_path_constraints; // set of string terms which have had path constraints asserted in the current scope obj_hashtable regex_terms_with_length_constraints; // set of regex terms which had had length constraints asserted in the current scope obj_map regex_term_to_length_constraint; // (str.in.re S R) -> (length constraint over S wrt. R) From 5ba939ad5eabac44317ecd24867b00d0a632be9a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Apr 2018 12:40:18 -0700 Subject: [PATCH 0733/1283] add tuple shortcut and example to C++ API Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 11 +++++++++++ src/api/c++/z3++.h | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index df977268a..ed5bf7086 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -920,6 +920,16 @@ void enum_sort_example() { std::cout << "2: " << result_goal.as_expr() << std::endl; } +void tuple_example() { + std::cout << "tuple example\n"; + context ctx; + const char * names[] = { "first", "second" }; + sort sorts[2] = { ctx.int_sort(), ctx.bool_sort() }; + func_decl_vector projs(ctx); + func_decl pair = ctx.tuple_sort("pair", 2, names, sorts, projs); + std::cout << pair << "\n"; +} + void expr_vector_example() { std::cout << "expr_vector example\n"; context c; @@ -1179,6 +1189,7 @@ int main() { incremental_example2(); std::cout << "\n"; incremental_example3(); std::cout << "\n"; enum_sort_example(); std::cout << "\n"; + tuple_example(); std::cout << "\n"; expr_vector_example(); std::cout << "\n"; exists_expr_vector_example(); std::cout << "\n"; substitute_example(); std::cout << "\n"; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 42467cb22..6f46f9440 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -267,6 +267,15 @@ namespace z3 { and in \c ts the predicates for testing if terms of the enumeration sort correspond to an enumeration. */ sort enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts); + + /** + \brief Return a tuple constructor. + \c name is the name of the returned constructor, + \c n are the number of arguments, \c names and \c sorts are their projected sorts. + \c projs is an output paramter. It contains the set of projection functions. + */ + func_decl tuple_sort(char const * name, unsigned n, char const * const * names, sort const* sorts, func_decl_vector & projs); + /** \brief create an uninterpreted sort with the name given by the string or symbol. */ @@ -2432,6 +2441,19 @@ namespace z3 { for (unsigned i = 0; i < n; i++) { cs.push_back(func_decl(*this, _cs[i])); ts.push_back(func_decl(*this, _ts[i])); } return s; } + inline func_decl context::tuple_sort(char const * name, unsigned n, char const * const * names, sort const* sorts, func_decl_vector & projs) { + array _names(n); + array _sorts(n); + for (unsigned i = 0; i < n; i++) { _names[i] = Z3_mk_string_symbol(*this, names[i]); _sorts[i] = sorts[i]; } + array _projs(n); + Z3_symbol _name = Z3_mk_string_symbol(*this, name); + Z3_func_decl tuple; + sort _ignore_s = to_sort(*this, Z3_mk_tuple_sort(*this, _name, n, _names.ptr(), _sorts.ptr(), &tuple, _projs.ptr())); + check_error(); + for (unsigned i = 0; i < n; i++) { projs.push_back(func_decl(*this, _projs[i])); } + return func_decl(*this, tuple); + } + inline sort context::uninterpreted_sort(char const* name) { Z3_symbol _name = Z3_mk_string_symbol(*this, name); return to_sort(*this, Z3_mk_uninterpreted_sort(*this, _name)); From 793642f48dd602f6532a6f94d63d1c9b08528f7b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 5 Apr 2018 15:23:16 +0100 Subject: [PATCH 0734/1283] Fixed MPF to_sbv. Thanks to Florian Schanda for reporting this bug. --- src/util/mpf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index b9829f02d..bfa6f4726 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1194,7 +1194,7 @@ void mpf_manager::to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o m_mpz_manager.set(z, t.significand()); mpf_exp_t e = (mpf_exp_t)t.exponent() - t.sbits() + 1; if (e < 0) { - bool last = false, round = false, sticky = m_mpz_manager.is_odd(z); + bool last = m_mpz_manager.is_odd(z), round = false, sticky = false; for (; e != 0; e++) { m_mpz_manager.machine_div2k(z, 1); sticky |= round; @@ -1204,7 +1204,7 @@ void mpf_manager::to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o bool inc = false; switch (rm) { case MPF_ROUND_NEAREST_TEVEN: inc = round && (last || sticky); break; - case MPF_ROUND_NEAREST_TAWAY: inc = round && (!last || sticky); break; // CMW: Check! + case MPF_ROUND_NEAREST_TAWAY: inc = round; break; case MPF_ROUND_TOWARD_POSITIVE: inc = (!x.sign && (round || sticky)); break; case MPF_ROUND_TOWARD_NEGATIVE: inc = (x.sign && (round || sticky)); break; case MPF_ROUND_TOWARD_ZERO: inc = false; break; From 328ad248b67f3cce4ad4fbc619d0e22624c06c0b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 5 Apr 2018 15:26:25 +0100 Subject: [PATCH 0735/1283] Fixed overflow problem in fp.to_?bv. Thanks to Florian Schanda for reporting this bug. --- src/ast/fpa/fpa2bv_converter.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index df5d56505..7344f6f2f 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3241,18 +3241,20 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args dbg_decouple("fpa2bv_to_bv_inc", inc); dbg_decouple("fpa2bv_to_bv_pre_rounded", pre_rounded); - pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded); - - expr_ref ll(m), ul(m), in_range(m); + expr_ref ul(m), ovfl(m), in_range(m); if (!is_signed) { - ll = m_bv_util.mk_numeral(0, bv_sz+3); ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_numeral(-1, bv_sz)); + in_range = m.mk_and(m.mk_not(x_is_neg), m_bv_util.mk_ule(pre_rounded, ul)); } else { + expr_ref ll(m); ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1))); ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_numeral(-1, bv_sz-1)); + pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded); + in_range = m.mk_and(m.mk_not(ovfl), m_bv_util.mk_sle(ll, pre_rounded), m_bv_util.mk_sle(pre_rounded, ul)); + dbg_decouple("fpa2bv_to_bv_in_range_ll", ll); } - in_range = m.mk_and(m_bv_util.mk_sle(ll, pre_rounded), m_bv_util.mk_sle(pre_rounded, ul)); + dbg_decouple("fpa2bv_to_bv_in_range_ul", ul); dbg_decouple("fpa2bv_to_bv_in_range", in_range); expr_ref rounded(m); From 3de41e5179a33753d4ce6d3831cdb95e8e96fea2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 5 Apr 2018 15:27:02 +0100 Subject: [PATCH 0736/1283] Fixed model completion for unspecified cases of floating-point functions. Thanks to Florian Schanda for reporting this bug. --- src/ast/fpa/bv2fpa_converter.cpp | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index d87929864..86a5b80c9 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -262,11 +262,11 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * unsigned arity = bv_f->get_arity(); func_interp * bv_fi = mc->get_func_interp(bv_f); + result = alloc(func_interp, m, arity); if (bv_fi) { fpa_rewriter rw(m); expr_ref ai(m); - result = alloc(func_interp, m, arity); for (unsigned i = 0; i < bv_fi->num_entries(); i++) { func_entry const * bv_fe = bv_fi->get_entry(i); @@ -311,6 +311,8 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * result->set_else(ft_els); } } + else + result->set_else(m.get_some_value(f->get_range())); return result; } @@ -467,24 +469,18 @@ void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_mode // it->m_value contains the model for the unspecified cases of it->m_key. func_interp * fmv = convert_func_interp(mc, f, it->m_value); - if (fmv) { + SASSERT(fmv); #if 0 - // Upon request, add this 'recursive' definition? - unsigned n = fmv->get_arity(); - expr_ref_vector args(m); - for (unsigned i = 0; i < n; i++) - args.push_back(m.mk_var(i, f->get_domain()[i])); - fmv->set_else(m.mk_app(it->m_key, n, args.c_ptr())); + // Upon request, add this 'recursive' definition? + unsigned n = fmv->get_arity(); + expr_ref_vector args(m); + for (unsigned i = 0; i < n; i++) + args.push_back(m.mk_var(i, f->get_domain()[i])); + fmv->set_else(m.mk_app(it->m_key, n, args.c_ptr())); #else - - fmv->set_else(0); + fmv->set_else(0); // Make sure it's not left open. #endif - target_model->register_decl(f, fmv); - } - } - else { - func_interp * fmv = convert_func_interp(mc, f, it->m_value); - if (fmv) target_model->register_decl(f, fmv); + target_model->register_decl(f, fmv); } } } From bd00d98398b8dbeb45a78fb128e7e5dddb324fc3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 5 Apr 2018 17:21:17 +0100 Subject: [PATCH 0737/1283] Fixed overflow bug in fp.to_ubv. Thanks to Florian Schanda for reporting this bug. --- src/ast/fpa/fpa2bv_converter.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 7344f6f2f..2b09dfe8c 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3243,8 +3243,13 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args expr_ref ul(m), ovfl(m), in_range(m); if (!is_signed) { + expr_ref incd(m), pr_is_zero(m); + incd = m.mk_eq(rounding_decision, bv1); + pr_is_zero = m.mk_eq(pre_rounded, m_bv_util.mk_numeral(0, bv_sz + 3)); ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_numeral(-1, bv_sz)); - in_range = m.mk_and(m.mk_not(x_is_neg), m_bv_util.mk_ule(pre_rounded, ul)); + in_range = m.mk_and(m.mk_not(x_is_neg), + m.mk_not(m.mk_and(incd, pr_is_zero)), + m_bv_util.mk_ule(pre_rounded, ul)); } else { expr_ref ll(m); From 724f86d43e23a7230277dcb53a4d27d9db66c473 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 5 Apr 2018 19:55:04 +0100 Subject: [PATCH 0738/1283] Bugfix for unspecified semantics of some fp.* operators. --- src/ast/fpa/bv2fpa_converter.cpp | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 86a5b80c9..2bacae12a 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -311,8 +311,6 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * result->set_else(ft_els); } } - else - result->set_else(m.get_some_value(f->get_range())); return result; } @@ -467,20 +465,7 @@ void bv2fpa_converter::convert_uf2bvuf(model_core * mc, model_core * target_mode else { if (it->get_key().get_family_id() == m_fpa_util.get_fid()) { // it->m_value contains the model for the unspecified cases of it->m_key. - - func_interp * fmv = convert_func_interp(mc, f, it->m_value); - SASSERT(fmv); -#if 0 - // Upon request, add this 'recursive' definition? - unsigned n = fmv->get_arity(); - expr_ref_vector args(m); - for (unsigned i = 0; i < n; i++) - args.push_back(m.mk_var(i, f->get_domain()[i])); - fmv->set_else(m.mk_app(it->m_key, n, args.c_ptr())); -#else - fmv->set_else(0); // Make sure it's not left open. -#endif - target_model->register_decl(f, fmv); + target_model->register_decl(f, convert_func_interp(mc, f, it->m_value)); } } } From 02bf2530b5eff6eec23bc0a2b5499998e65771f7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 5 Apr 2018 19:55:41 +0100 Subject: [PATCH 0739/1283] Bugfix for fp.to_sbv. Thanks to Florian Schanda for reporting this bug. --- src/ast/fpa/fpa2bv_converter.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 2b09dfe8c..9d8576203 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3241,24 +3241,29 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args dbg_decouple("fpa2bv_to_bv_inc", inc); dbg_decouple("fpa2bv_to_bv_pre_rounded", pre_rounded); - expr_ref ul(m), ovfl(m), in_range(m); + expr_ref incd(m), pr_is_zero(m), ovfl(m); + incd = m.mk_eq(rounding_decision, bv1); + pr_is_zero = m.mk_eq(pre_rounded, m_bv_util.mk_numeral(0, bv_sz + 3)); + ovfl = m.mk_and(incd, pr_is_zero); + + expr_ref ul(m), in_range(m); if (!is_signed) { - expr_ref incd(m), pr_is_zero(m); - incd = m.mk_eq(rounding_decision, bv1); - pr_is_zero = m.mk_eq(pre_rounded, m_bv_util.mk_numeral(0, bv_sz + 3)); ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_numeral(-1, bv_sz)); - in_range = m.mk_and(m.mk_not(x_is_neg), - m.mk_not(m.mk_and(incd, pr_is_zero)), + in_range = m.mk_and(m.mk_not(x_is_neg), m.mk_not(ovfl), m_bv_util.mk_ule(pre_rounded, ul)); } else { expr_ref ll(m); ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1))); ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_numeral(-1, bv_sz-1)); - pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded); - in_range = m.mk_and(m.mk_not(ovfl), m_bv_util.mk_sle(ll, pre_rounded), m_bv_util.mk_sle(pre_rounded, ul)); + ovfl = m.mk_or(ovfl, m_bv_util.mk_sle(pre_rounded, m_bv_util.mk_numeral(-1, bv_sz + 3))); + in_range = m.mk_and(m.mk_not(ovfl), + m_bv_util.mk_sle(ll, pre_rounded), + m_bv_util.mk_sle(pre_rounded, ul)); dbg_decouple("fpa2bv_to_bv_in_range_ll", ll); + pre_rounded = m.mk_ite(x_is_neg, m_bv_util.mk_bv_neg(pre_rounded), pre_rounded); } + dbg_decouple("fpa2bv_to_bv_in_range_ovfl", ovfl); dbg_decouple("fpa2bv_to_bv_in_range_ul", ul); dbg_decouple("fpa2bv_to_bv_in_range", in_range); From 287c6f08e1250a610ad8d3a4e4821218a8652800 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 5 Apr 2018 20:31:45 +0100 Subject: [PATCH 0740/1283] Resolved merge conflict --- src/tactic/sine_filter.cpp | 149 ++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 70 deletions(-) diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 88792e955..e67169a8e 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -35,25 +35,25 @@ class sine_tactic : public tactic { public: - sine_tactic(ast_manager& m, params_ref const& p): + sine_tactic(ast_manager& m, params_ref const& p): m(m), m_params(p) {} - - tactic * translate(ast_manager & m) override { + + virtual tactic * translate(ast_manager & m) { return alloc(sine_tactic, m, m_params); } - void updt_params(params_ref const & p) override { + virtual void updt_params(params_ref const & p) { } - void collect_param_descrs(param_descrs & r) override { + virtual void collect_param_descrs(param_descrs & r) { } - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) override { - mc = nullptr; pc = nullptr; core = nullptr; + virtual void operator()(goal_ref const & g, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + mc = 0; pc = 0; core = 0; TRACE("sine", g->display(tout);); TRACE("sine", tout << g->size();); @@ -62,7 +62,7 @@ public: TRACE("sine", tout << new_forms.size();); g->reset(); for (unsigned i = 0; i < new_forms.size(); i++) { - g->assert_expr(new_forms.get(i), nullptr, nullptr); + g->assert_expr(new_forms.get(i), 0, 0); } g->inc_depth(); g->updt_prec(goal::OVER); @@ -72,115 +72,120 @@ public: filter_model_converter * fmc = alloc(filter_model_converter, m); mc = fmc; } - - void cleanup() override { + + virtual void cleanup() { } private: typedef std::pair t_work_item; - t_work_item work_item(expr *e, expr *root) { + t_work_item work_item(expr * e, expr * root) { return std::pair(e, root); } - void find_constants(expr *e, obj_hashtable &consts) { + void find_constants(expr * e, obj_hashtable &consts) { ptr_vector stack; stack.push_back(e); - expr *curr; + expr * curr; while (!stack.empty()) { curr = stack.back(); stack.pop_back(); - if (is_app(curr)) { + if (is_app(curr) && is_uninterp(curr)) { app *a = to_app(curr); - if (is_uninterp(a)) { - func_decl *f = a->get_decl(); - consts.insert_if_not_there(f); - } + func_decl *f = a->get_decl(); + consts.insert_if_not_there(f); } } } - bool quantifier_matches(quantifier *q, + bool quantifier_matches(quantifier * q, obj_hashtable const & consts, ptr_vector & next_consts) { - TRACE("sine", tout << "size of consts is "; tout << consts.size(); tout << "\n";); - for (obj_hashtable::iterator constit = consts.begin(), constend = consts.end(); constit != constend; constit++) { - TRACE("sine", tout << *constit; tout << "\n";); - } + TRACE("sine", + tout << "size of consts is "; tout << consts.size(); tout << "\n"; + obj_hashtable::iterator it = consts.begin(); + obj_hashtable::iterator end = consts.end(); + for (; it != end; it++) + tout << *it << "\n"; ); + bool matched = false; for (unsigned i = 0; i < q->get_num_patterns(); i++) { bool p_matched = true; ptr_vector stack; - expr *curr; + expr * curr; + // patterns are wrapped with "pattern" - if (!m.is_pattern(q->get_pattern(i), stack)) { + if (!m.is_pattern(q->get_pattern(i), stack)) continue; - } + while (!stack.empty()) { curr = stack.back(); stack.pop_back(); + if (is_app(curr)) { - app *a = to_app(curr); - func_decl *f = a->get_decl(); + app * a = to_app(curr); + func_decl * f = a->get_decl(); if (!consts.contains(f)) { TRACE("sine", tout << mk_pp(f, m) << "\n";); p_matched = false; next_consts.push_back(f); break; } - for (unsigned j = 0; j < a->get_num_args(); j++) { + for (unsigned j = 0; j < a->get_num_args(); j++) stack.push_back(a->get_arg(j)); - } } } + if (p_matched) { matched = true; break; } } + return matched; } - + void filter_expressions(goal_ref const & g, ptr_vector & new_exprs) { obj_map > const2exp; obj_map > exp2const; obj_map > const2quantifier; obj_hashtable consts; vector stack; - for (unsigned i = 0; i < g->size(); i++) { - stack.push_back(work_item(g->form(i), g->form(i))); - } t_work_item curr; + + for (unsigned i = 0; i < g->size(); i++) + stack.push_back(work_item(g->form(i), g->form(i))); + while (!stack.empty()) { curr = stack.back(); stack.pop_back(); - if (is_app(curr.first)) { - app *a = to_app(curr.first); - if (is_uninterp(a)) { - func_decl *f = a->get_decl(); - if (!consts.contains(f)) { - consts.insert(f); - if (const2quantifier.contains(f)) { - for (obj_pair_hashtable::iterator it = const2quantifier[f].begin(), end = const2quantifier[f].end(); it != end; it++) { - stack.push_back(*it); - } - const2quantifier.remove(f); - } - } - if (!const2exp.contains(f)) { - const2exp.insert(f, obj_hashtable()); - } - if (!const2exp[f].contains(curr.second)) { - const2exp[f].insert(curr.second); - } - if (!exp2const.contains(curr.second)) { - exp2const.insert(curr.second, obj_hashtable()); - } - if (!exp2const[curr.second].contains(f)) { - exp2const[curr.second].insert(f); + if (is_app(curr.first) && is_uninterp(curr.first)) { + app * a = to_app(curr.first); + func_decl * f = a->get_decl(); + if (!consts.contains(f)) { + consts.insert(f); + if (const2quantifier.contains(f)) { + obj_pair_hashtable::iterator it = const2quantifier[f].begin(); + obj_pair_hashtable::iterator end = const2quantifier[f].end(); + for (; it != end; it++) + stack.push_back(*it); + const2quantifier.remove(f); } } + if (!const2exp.contains(f)) { + const2exp.insert(f, obj_hashtable()); + } + if (!const2exp[f].contains(curr.second)) { + const2exp[f].insert(curr.second); + } + if (!exp2const.contains(curr.second)) { + exp2const.insert(curr.second, obj_hashtable()); + } + if (!exp2const[curr.second].contains(f)) { + exp2const[curr.second].insert(f); + } + for (unsigned i = 0; i < a->get_num_args(); i++) { stack.push_back(work_item(a->get_arg(i), curr.second)); } @@ -214,28 +219,32 @@ private: } } } + // ok, now we just need to find the connected component of the last term - obj_hashtable visited; ptr_vector to_visit; to_visit.push_back(g->form(g->size() - 1)); - expr *visiting; + expr * visiting; + while (!to_visit.empty()) { visiting = to_visit.back(); to_visit.pop_back(); visited.insert(visiting); - for (obj_hashtable::iterator constit = exp2const[visiting].begin(), constend = exp2const[visiting].end(); constit != constend; constit++) { - for (obj_hashtable::iterator exprit = const2exp[*constit].begin(), exprend = const2exp[*constit].end(); exprit != exprend; exprit++) { - if (!visited.contains(*exprit)) { + obj_hashtable::iterator it = exp2const[visiting].begin(); + obj_hashtable::iterator end = exp2const[visiting].end(); + for (; it != end; it++) { + obj_hashtable::iterator exprit = const2exp[*it].begin(); + obj_hashtable::iterator exprend = const2exp[*it].end(); + for (; exprit != exprend; exprit++) { + if (!visited.contains(*exprit)) to_visit.push_back(*exprit); - } } } } + for (unsigned i = 0; i < g->size(); i++) { - if (visited.contains(g->form(i))) { + if (visited.contains(g->form(i))) new_exprs.push_back(g->form(i)); - } } } }; From a954ab7d8db1c62a6bcb295da21e63a821b69248 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Apr 2018 08:38:01 -0700 Subject: [PATCH 0741/1283] flip literals in ATEs produced using RI Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 1 + src/sat/sat_big.cpp | 4 +- src/sat/sat_model_converter.cpp | 76 ++++++++++---- src/sat/sat_model_converter.h | 23 +++-- src/sat/sat_simplifier.cpp | 172 +++++++++++++++++++++++--------- src/sat/sat_solver.cpp | 29 ++++-- src/sat/sat_solver.h | 4 + 7 files changed, 224 insertions(+), 85 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 65003a6e4..b2053c68f 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -410,6 +410,7 @@ namespace sat { if (c.is_learned()) { m_elim_learned_literals += c.size() - new_sz; } + switch(new_sz) { case 0: s.set_conflict(justification()); diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 2f1a3727f..27b87d4c9 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -194,7 +194,9 @@ namespace sat { if (u != get_parent(v) && safe_reach(u, v)) { ++elim; add_del(~u, v); - // IF_VERBOSE(1, verbose_stream() << "remove " << u << " -> " << v << "\n"); + if (s.get_config().m_drat) s.m_drat.del(~u, v); + s.m_mc.stackv().reset(); // TBD: brittle code + s.add_ate(~u, v); if (find_binary_watch(wlist, ~v)) { IF_VERBOSE(10, verbose_stream() << "binary: " << ~u << "\n"); s.assign(~u, justification()); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index c2a4858f7..bebb3e384 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -75,33 +75,41 @@ namespace sat { void model_converter::operator()(model & m) const { vector::const_iterator begin = m_entries.begin(); vector::const_iterator it = m_entries.end(); - bool first = false; // true; + bool first = true; // false; // true; // false; // true; //SASSERT(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; bool_var v0 = it->var(); - SASSERT(it->get_kind() != ELIM_VAR || m[v0] == l_undef); - // if it->get_kind() == BLOCK_LIT, then it might be the case that m[v] != l_undef, + SASSERT(it->get_kind() != ELIM_VAR || v0 == null_bool_var || m[v0] == l_undef); + // if it->get_kind() == BCE, then it might be the case that m[v] != l_undef, // and the following procedure flips its value. bool sat = false; bool var_sign = false; unsigned index = 0; literal_vector clause; - VERIFY(legal_to_flip(v0)); + VERIFY(v0 == null_bool_var || legal_to_flip(v0)); for (literal l : it->m_clauses) { if (l == null_literal) { // end of clause - elim_stack* st = it->m_elim_stack[index]; - if (!sat) { + if (!sat && it->get_kind() == ATE) { + IF_VERBOSE(0, display(verbose_stream() << "violated ate\n", *it) << "\n"); + IF_VERBOSE(0, for (unsigned v = 0; v < m.size(); ++v) verbose_stream() << v << " := " << m[v] << "\n";); + IF_VERBOSE(0, display(verbose_stream())); + exit(0); + first = false; + } + if (!sat && it->get_kind() != ATE && v0 != null_bool_var) { VERIFY(legal_to_flip(v0)); m[v0] = var_sign ? l_false : l_true; } + elim_stack* st = it->m_elim_stack[index]; if (st) { process_stack(m, clause, st->stack()); } sat = false; if (first && m_solver && !m_solver->check_clauses(m)) { IF_VERBOSE(0, display(verbose_stream() << "after processing stack\n", *it) << "\n"); + IF_VERBOSE(0, display(verbose_stream())); first = false; } ++index; @@ -191,17 +199,43 @@ namespace sat { entry & e = m_entries.back(); SASSERT(e.var() == v); SASSERT(e.get_kind() == k); - VERIFY(legal_to_flip(v)); + VERIFY(v == null_bool_var || legal_to_flip(v)); return e; } + void model_converter::add_ate(clause const& c) { + if (stackv().empty()) return; + insert(mk(ATE, null_bool_var), c); + } + + void model_converter::add_ate(literal_vector const& lits) { + if (stackv().empty()) return; + insert(mk(ATE, null_bool_var), lits); + } + + void model_converter::add_ate(literal l1, literal l2) { + if (stackv().empty()) return; + insert(mk(ATE, null_bool_var), l1, l2); + } + + void model_converter::add_elim_stack(entry & e) { + e.m_elim_stack.push_back(stackv().empty() ? nullptr : alloc(elim_stack, stackv())); +#if 0 + if (!stackv().empty() && e.get_kind() == ATE) { + IF_VERBOSE(0, display(verbose_stream(), e) << "\n"); + } +#endif + for (auto const& s : stackv()) VERIFY(legal_to_flip(s.second.var())); + stackv().reset(); + } + void model_converter::insert(entry & e, clause const & c) { SASSERT(c.contains(e.var())); SASSERT(m_entries.begin() <= &e); SASSERT(&e < m_entries.end()); for (literal l : c) e.m_clauses.push_back(l); e.m_clauses.push_back(null_literal); - e.m_elim_stack.push_back(nullptr); + add_elim_stack(e); TRACE("sat_mc_bug", tout << "adding: " << c << "\n";); } @@ -212,7 +246,7 @@ namespace sat { e.m_clauses.push_back(l1); e.m_clauses.push_back(l2); e.m_clauses.push_back(null_literal); - e.m_elim_stack.push_back(nullptr); + add_elim_stack(e); TRACE("sat_mc_bug", tout << "adding (binary): " << l1 << " " << l2 << "\n";); } @@ -224,18 +258,17 @@ namespace sat { for (unsigned i = 0; i < sz; ++i) e.m_clauses.push_back(c[i]); e.m_clauses.push_back(null_literal); - e.m_elim_stack.push_back(nullptr); + add_elim_stack(e); // TRACE("sat_mc_bug", tout << "adding (wrapper): "; for (literal l : c) tout << l << " "; tout << "\n";); } - void model_converter::insert(entry & e, literal_vector const& c, elim_stackv const& elims) { + void model_converter::insert(entry & e, literal_vector const& c) { SASSERT(c.contains(literal(e.var(), false)) || c.contains(literal(e.var(), true))); SASSERT(m_entries.begin() <= &e); SASSERT(&e < m_entries.end()); for (literal l : c) e.m_clauses.push_back(l); e.m_clauses.push_back(null_literal); - e.m_elim_stack.push_back(elims.empty() ? nullptr : alloc(elim_stack, elims)); - for (auto const& s : elims) VERIFY(legal_to_flip(s.second.var())); + add_elim_stack(e); TRACE("sat_mc_bug", tout << "adding: " << c << "\n";); } @@ -246,7 +279,7 @@ namespace sat { vector::const_iterator it = m_entries.begin(); vector::const_iterator end = m_entries.end(); for (; it != end; ++it) { - SASSERT(it->var() < num_vars); + SASSERT(it->var() == null_bool_var || it->var() < num_vars); if (it->get_kind() == ELIM_VAR) { svector::const_iterator it2 = it; it2++; @@ -276,7 +309,8 @@ namespace sat { } std::ostream& model_converter::display(std::ostream& out, entry const& entry) const { - out << " (" << entry.get_kind() << " " << entry.var(); + out << " (" << entry.get_kind() << " "; + if (entry.var() != null_bool_var) out << entry.var(); bool start = true; unsigned index = 0; for (literal l : entry.m_clauses) { @@ -306,7 +340,7 @@ namespace sat { } out << ")"; for (literal l : entry.m_clauses) { - if (l != null_literal) { + if (l != null_literal && l.var() != null_bool_var) { if (false && m_solver && m_solver->was_eliminated(l.var())) out << "\neliminated: " << l; } } @@ -333,7 +367,7 @@ namespace sat { for (entry const& e : m_entries) { for (literal l : e.m_clauses) { if (l != null_literal) { - if (l.var() > result) + if (l.var() != null_bool_var && l.var() > result) result = l.var(); } } @@ -372,9 +406,11 @@ namespace sat { update_stack.push_back(null_literal); } } - swap(e.var(), clause.size(), clause); - update_stack.append(clause); - update_stack.push_back(null_literal); + if (e.var() != null_bool_var) { + swap(e.var(), clause.size(), clause); + update_stack.append(clause); + update_stack.push_back(null_literal); + } clause.reset(); } else { diff --git a/src/sat/sat_model_converter.h b/src/sat/sat_model_converter.h index bc60844ca..65e132729 100644 --- a/src/sat/sat_model_converter.h +++ b/src/sat/sat_model_converter.h @@ -66,11 +66,11 @@ namespace sat { unsigned ref_count() const { return m_refcount; } }; - enum kind { ELIM_VAR = 0, BLOCK_LIT, CCE, ACCE }; + enum kind { ELIM_VAR = 0, BCE, CCE, ACCE, ABCE, ATE }; class entry { friend class model_converter; - unsigned m_var:30; - unsigned m_kind:2; + bool_var m_var; + kind m_kind; literal_vector m_clauses; // the different clauses are separated by null_literal sref_vector m_elim_stack; entry(kind k, bool_var v): m_var(v), m_kind(k) {} @@ -82,11 +82,12 @@ namespace sat { m_elim_stack.append(src.m_elim_stack); } bool_var var() const { return m_var; } - kind get_kind() const { return static_cast(m_kind); } + kind get_kind() const { return m_kind; } }; private: vector m_entries; solver const* m_solver; + elim_stackv m_elim_stack; void process_stack(model & m, literal_vector const& clause, elim_stackv const& stack) const; @@ -96,6 +97,8 @@ namespace sat { void swap(bool_var v, unsigned sz, literal_vector& clause); + void add_elim_stack(entry & e); + public: model_converter(); ~model_converter(); @@ -103,11 +106,17 @@ namespace sat { void operator()(model & m) const; model_converter& operator=(model_converter const& other); + elim_stackv& stackv() { return m_elim_stack; } + entry & mk(kind k, bool_var v); void insert(entry & e, clause const & c); void insert(entry & e, literal l1, literal l2); void insert(entry & e, clause_wrapper const & c); - void insert(entry & c, literal_vector const& covered_clause, elim_stackv const& elim_stack); + void insert(entry & c, literal_vector const& covered_clause); + + void add_ate(literal_vector const& lits); + void add_ate(literal l1, literal l2); + void add_ate(clause const& c); bool empty() const { return m_entries.empty(); } @@ -137,9 +146,11 @@ namespace sat { inline std::ostream& operator<<(std::ostream& out, model_converter::kind k) { switch (k) { case model_converter::ELIM_VAR: out << "elim"; break; - case model_converter::BLOCK_LIT: out << "blocked"; break; + case model_converter::BCE: out << "bce"; break; case model_converter::CCE: out << "cce"; break; case model_converter::ACCE: out << "acce"; break; + case model_converter::ABCE: out << "abce"; break; + case model_converter::ATE: out << "ate"; break; } return out; } diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index bac790698..52c7236a0 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -939,16 +939,21 @@ namespace sat { bool operator==(clause_ante const& a) const { return a.m_lit1 == m_lit1 && a.m_lit2 == m_lit2 && a.m_clause == m_clause; } - std::ostream& display(std::ostream& out) const { + std::ostream& display(std::ostream& out, literal lit) const { if (cls()) { out << *cls() << " "; } + else { + out << "(" << ~lit; + } if (lit1() != null_literal) { - out << lit1() << " "; + out << " " << lit1(); } if (lit2() != null_literal) { - out << lit2() << " "; + out << " " << lit2(); } + if (!cls()) out << ")"; + if (from_ri()) out << "ri"; out << "\n"; return out; } @@ -978,7 +983,7 @@ namespace sat { simplifier & s; int m_counter; - model_converter & mc; + model_converter & m_mc; queue m_queue; literal_vector m_covered_clause; // covered clause @@ -987,7 +992,6 @@ namespace sat { literal_vector m_tautology; // literals that are used in blocking tautology literal_vector m_new_intersection; svector m_in_intersection; - sat::model_converter::elim_stackv m_elim_stack; unsigned m_ala_qhead; clause_wrapper m_clause; @@ -995,7 +999,7 @@ namespace sat { vector & wlist): s(_s), m_counter(limit), - mc(_mc), + m_mc(_mc), m_queue(l, wlist), m_clause(null_literal, null_literal) { m_in_intersection.resize(s.s.num_vars() * 2, false); @@ -1069,6 +1073,7 @@ namespace sat { m_tautology.reset(); if (!process_var(l.var())) return false; bool first = true; + VERIFY(s.value(l) == l_undef); for (watched & w : s.get_wlist(l)) { // when adding a blocked clause, then all non-learned clauses have to be considered for the // resolution intersection. @@ -1184,18 +1189,18 @@ namespace sat { if (m_covered_antecedent[i] == clause_ante()) s.mark_visited(lit); if (s.is_marked(lit)) idx = i; } - if (false && _blocked.var() == 16774) { + if (false) { IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n"; verbose_stream() << "tautology: " << m_tautology << "\n"; verbose_stream() << "index: " << idx << "\n"; for (unsigned i = idx; i > 0; --i) { - m_covered_antecedent[i].display(verbose_stream() << "ante " << m_covered_clause[i] << ":"); + m_covered_antecedent[i].display(verbose_stream(), m_covered_clause[i]); }); } for (unsigned i = idx; i > 0; --i) { literal lit = m_covered_clause[i]; - s.mark_visited(lit); - continue; + //s.mark_visited(lit); + //continue; if (!s.is_marked(lit)) continue; clause_ante const& ante = m_covered_antecedent[i]; if (ante.cls()) { @@ -1222,13 +1227,16 @@ namespace sat { clause_ante const& ante = m_covered_antecedent[i]; if (ante.from_ri() && blocked != ante.lit1()) { blocked = ante.lit1(); - m_elim_stack.push_back(std::make_pair(j, blocked)); + VERIFY(s.value(blocked) == l_undef); + m_mc.stackv().push_back(std::make_pair(j, blocked)); } m_covered_clause[j++] = lit; s.unmark_visited(lit); } } for (literal l : m_covered_clause) VERIFY(!s.is_marked(l)); + for (bool_var v = 0; v < s.s.num_vars(); ++v) VERIFY(!s.is_marked(literal(v, true)) && !s.is_marked(literal(v, false))); + // unsigned sz0 = m_covered_clause.size(); m_covered_clause.resize(j); VERIFY(j >= m_clause.size()); @@ -1263,6 +1271,7 @@ namespace sat { return true; } if (!s.is_marked(~lit)) { + // if (m_covered_clause[0].var() == 10219) IF_VERBOSE(0, verbose_stream() << "ala: " << l << " " << lit << "\n"); m_covered_clause.push_back(~lit); m_covered_antecedent.push_back(clause_ante(l, false)); s.mark_visited(~lit); @@ -1292,6 +1301,7 @@ namespace sat { if (lit1 == null_literal) { return true; } + // if (m_covered_clause[0].var() == 10219) IF_VERBOSE(0, verbose_stream() << "ala: " << c << " " << lit1 << "\n"); m_covered_clause.push_back(~lit1); m_covered_antecedent.push_back(clause_ante(c)); s.mark_visited(~lit1); @@ -1332,13 +1342,17 @@ namespace sat { return sz0 * 400 < m_covered_clause.size(); } + void reset_mark() { + for (literal l : m_covered_clause) s.unmark_visited(l); + } + template elim_type cce(literal& blocked, model_converter::kind& k) { - bool is_tautology = false, first = true; + bool first = true; unsigned sz = 0, sz0 = m_covered_clause.size(); for (literal l : m_covered_clause) s.mark_visited(l); shuffle(m_covered_clause.size(), m_covered_clause.c_ptr(), s.s.m_rand); - m_elim_stack.reset(); + m_mc.stackv().reset(); m_ala_qhead = 0; switch (et) { @@ -1349,7 +1363,7 @@ namespace sat { k = model_converter::ACCE; break; default: - k = model_converter::BLOCK_LIT; + k = model_converter::BCE; break; } @@ -1361,48 +1375,77 @@ namespace sat { * and then check if any of the first sz0 literals are blocked. */ - while (!is_tautology && m_covered_clause.size() > sz && !above_threshold(sz0)) { - SASSERT(!is_tautology); + if (et == ate_t) { + bool ala = add_ala(); + reset_mark(); + m_covered_clause.shrink(sz0); + return ala ? ate_t : no_t; + } - if ((et == abce_t || et == acce_t || et == ate_t) && add_ala()) { - for (literal l : m_covered_clause) s.unmark_visited(l); + while (m_covered_clause.size() > sz && !above_threshold(sz0)) { + + if ((et == abce_t || et == acce_t) && add_ala()) { + reset_mark(); + if (first) { + m_covered_clause.shrink(sz0); + } + else { + /* + * tautology depends on resolution intersection. + * literals used for resolution intersection may have to be flipped. + */ + m_tautology.reset(); + for (literal l : m_covered_clause) { + m_tautology.push_back(l); + s.mark_visited(l); + } + minimize_covered_clause(m_covered_clause.size()-1); + } return ate_t; } - if (et == ate_t) { - for (literal l : m_covered_clause) s.unmark_visited(l); - return no_t; - } - if (first) { for (unsigned i = 0; i < sz0; ++i) { if (check_abce_tautology(m_covered_clause[i])) { blocked = m_covered_clause[i]; - is_tautology = true; - break; + reset_mark(); +#if 0 + if (sz0 == 3 && blocked.var() == 10219) { + IF_VERBOSE(0, verbose_stream() << "abce: " << m_covered_clause << "\n"; + for (literal l : m_covered_clause) verbose_stream() << s.value(l) << "\n"; + ); + literal l = blocked; + clause_use_list & neg_occs = s.m_use_list.get(~l); + for (auto it = neg_occs.mk_iterator(); !it.at_end(); it.next()) { + clause & c = it.curr(); + IF_VERBOSE(0, verbose_stream() << c << "\n"); + } + } +#endif + m_covered_clause.shrink(sz0); + if (et == bce_t) return bce_t; + k = model_converter::ABCE; + return abce_t; } } - first = false; } + first = false; - if (is_tautology || et == abce_t || et == bce_t) { - for (literal l : m_covered_clause) s.unmark_visited(l); - m_covered_clause.shrink(sz0); - if (!is_tautology) return no_t; - if (et == bce_t) return bce_t; - return abce_t; + if (et == abce_t || et == bce_t) { + break; } /* * Add resolution intersection while checking if the clause becomes a tautology. */ sz = m_covered_clause.size(); - if (et == cce_t || et == acce_t) { - is_tautology = add_cla(blocked); + if ((et == cce_t || et == acce_t) && add_cla(blocked)) { + reset_mark(); + return et; } } - for (literal l : m_covered_clause) s.unmark_visited(l); - return is_tautology ? et : no_t; + reset_mark(); + return no_t; } // perform covered clause elimination. @@ -1463,13 +1506,14 @@ namespace sat { case ate_t: w.set_learned(true); s.s.set_learned1(l2, l, true); + m_mc.add_ate(m_covered_clause); break; case no_t: break; default: - block_covered_binary(w, l, blocked, k); w.set_learned(true); s.s.set_learned1(l2, l, true); + block_covered_binary(w, l, blocked, k); break; } } @@ -1487,7 +1531,8 @@ namespace sat { inc_bc(r); switch (r) { case ate_t: - s.set_learned(c); + m_mc.add_ate(m_covered_clause); + s.set_learned(c); break; case no_t: break; @@ -1518,32 +1563,33 @@ namespace sat { } void block_covered_clause(clause& c, literal l, model_converter::kind k) { - if (false && l.var() == 39021) { + if (false) { IF_VERBOSE(0, verbose_stream() << "blocked: " << l << " @ " << c << " :covered " << m_covered_clause << "\n"; s.m_use_list.display(verbose_stream() << "use " << l << ":", l); s.m_use_list.display(verbose_stream() << "use " << ~l << ":", ~l); - /*s.s.display(verbose_stream());*/ + display_watch_list(verbose_stream() << ~l << ": ", s.s.m_cls_allocator, s.get_wlist(l)) << "\n"; + display_watch_list(verbose_stream() << l << ": ", s.s.m_cls_allocator, s.get_wlist(~l)) << "\n"; ); } TRACE("blocked_clause", tout << "new blocked clause: " << c << "\n";); SASSERT(!s.is_external(l)); - model_converter::entry& new_entry = mc.mk(k, l.var()); + model_converter::entry& new_entry = m_mc.mk(k, l.var()); for (literal lit : c) { if (lit != l && process_var(lit.var())) { m_queue.decreased(~lit); } } - mc.insert(new_entry, m_covered_clause, m_elim_stack); + m_mc.insert(new_entry, m_covered_clause); } void block_covered_binary(watched const& w, literal l1, literal blocked, model_converter::kind k) { SASSERT(!s.is_external(blocked)); - model_converter::entry& new_entry = mc.mk(k, blocked.var()); + model_converter::entry& new_entry = m_mc.mk(k, blocked.var()); literal l2 = w.get_literal(); TRACE("blocked_clause", tout << "new blocked clause: " << l2 << " " << l1 << "\n";); s.set_learned(l1, l2); - mc.insert(new_entry, m_covered_clause, m_elim_stack); + m_mc.insert(new_entry, m_covered_clause); m_queue.decreased(~l2); } @@ -1571,6 +1617,13 @@ namespace sat { for (literal l2 : m_intersection) { watched* w = find_binary_watch(s.get_wlist(~l), ~l2); if (!w) { +#if 0 + IF_VERBOSE(0, verbose_stream() << "bca " << l << " " << ~l2 << "\n"); + if (l.var() == 10219 && l2.var() == 10202) { + IF_VERBOSE(0, s.s.display(verbose_stream())); + exit(0); + } +#endif s.s.mk_bin_clause(l, ~l2, true); ++s.m_num_bca; } @@ -1777,13 +1830,19 @@ namespace sat { } void simplifier::save_clauses(model_converter::entry & mc_entry, clause_wrapper_vector const & cs) { - model_converter & mc = s.m_mc; for (auto & e : cs) { - mc.insert(mc_entry, e); + s.m_mc.insert(mc_entry, e); } } void simplifier::add_non_learned_binary_clause(literal l1, literal l2) { +#if 0 + if ((l1.var() == 2039 || l2.var() == 2039) && + (l1.var() == 27042 || l2.var() == 27042)) { + IF_VERBOSE(1, verbose_stream() << "add_bin: " << l1 << " " << l2 << "\n"); + } +#endif +#if 0 watched* w; watch_list & wlist1 = get_wlist(~l1); watch_list & wlist2 = get_wlist(~l2); @@ -1804,6 +1863,9 @@ namespace sat { else { wlist2.push_back(watched(l1, false)); } +#else + s.mk_bin_clause(l1, l2, false); +#endif } /** @@ -1820,6 +1882,11 @@ namespace sat { watch_list::iterator end2 = wlist2.end(); for (; it2 != end2; ++it2) { if (it2->is_binary_clause() && it2->get_literal() == l) { + if ((l.var() == 2039 || l2.var() == 2039) && + (l.var() == 27042 || l2.var() == 27042)) { + IF_VERBOSE(1, verbose_stream() << "remove_bin: " << l << " " << l2 << "\n"); + } + TRACE("bin_clause_bug", tout << "removing: " << l << " " << it2->get_literal() << "\n";); m_sub_bin_todo.erase(bin_clause(l2, l, it2->is_learned())); continue; @@ -1920,6 +1987,13 @@ namespace sat { m_elim_counter -= num_pos * num_neg + before_lits; + if (false) { + literal l(v, false); + IF_VERBOSE(0, + verbose_stream() << "elim: " << l << "\n"; + display_watch_list(verbose_stream() << ~l << ": ", s.m_cls_allocator, get_wlist(l)) << "\n"; + display_watch_list(verbose_stream() << l << ": ", s.m_cls_allocator, get_wlist(~l)) << "\n";); + } // eliminate variable ++s.m_stats.m_elim_var_res; VERIFY(!is_external(v)); @@ -1936,12 +2010,14 @@ namespace sat { m_elim_counter -= num_pos * num_neg + before_lits; + + for (auto & c1 : m_pos_cls) { for (auto & c2 : m_neg_cls) { m_new_cls.reset(); if (!resolve(c1, c2, pos_l, m_new_cls)) continue; - // if (v == 39063) IF_VERBOSE(0, verbose_stream() << "elim: " << c1 << " + " << c2 << " -> " << m_new_cls << "\n"); + if (false && v == 27041) IF_VERBOSE(0, verbose_stream() << "elim: " << c1 << " + " << c2 << " -> " << m_new_cls << "\n"); TRACE("resolution_new_cls", tout << c1 << "\n" << c2 << "\n-->\n" << m_new_cls << "\n";); if (cleanup_clause(m_new_cls)) continue; // clause is already satisfied. @@ -2053,7 +2129,7 @@ namespace sat { m_subsumption = p.subsumption(); m_subsumption_limit = p.subsumption_limit(); m_elim_vars = p.elim_vars(); - m_elim_vars_bdd = false && p.elim_vars_bdd(); // buggy + m_elim_vars_bdd = false && p.elim_vars_bdd(); // buggy? m_elim_vars_bdd_delay = p.elim_vars_bdd_delay(); m_incremental_mode = s.get_config().m_incremental && !p.override_incremental(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 299b1f704..da11ed3a1 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -333,6 +333,12 @@ namespace sat { } void solver::mk_bin_clause(literal l1, literal l2, bool learned) { +#if 0 + if ((l1.var() == 2039 || l2.var() == 2039) && + (l1.var() == 27042 || l2.var() == 27042)) { + IF_VERBOSE(1, verbose_stream() << "mk_bin: " << l1 << " " << l2 << " " << learned << "\n"); + } +#endif if (find_binary_watch(get_wlist(~l1), ~l2)) { assign(l1, justification()); return; @@ -345,13 +351,13 @@ namespace sat { if (w0) { if (w0->is_learned() && !learned) { w0->set_learned(false); - } - w0 = find_binary_watch(get_wlist(~l2), l1); - } - if (w0) { - if (w0->is_learned() && !learned) { - w0->set_learned(false); - } + } + else { + return; + } + w0 = find_binary_watch(get_wlist(~l2), l1); + VERIFY(w0); + w0->set_learned(false); return; } if (m_config.m_drat) @@ -671,7 +677,6 @@ namespace sat { TRACE("sat_assign_core", tout << l << " " << j << " level: " << scope_lvl() << "\n";); if (at_base_lvl()) { if (m_config.m_drat) m_drat.add(l, !j.is_none()); - j = justification(); // erase justification for level 0 } m_assignment[l.index()] = l_true; @@ -1215,7 +1220,7 @@ namespace sat { } } if (num_in > 0 || num_out > 0) { - IF_VERBOSE(1, verbose_stream() << "(sat-sync out: " << num_out << " in: " << num_in << ")\n";); + IF_VERBOSE(2, verbose_stream() << "(sat-sync out: " << num_out << " in: " << num_in << ")\n";); } } } @@ -1657,7 +1662,11 @@ namespace sat { if (!check_clauses(m_model)) { IF_VERBOSE(0, verbose_stream() << "failure checking clauses on transformed model\n";); - // IF_VERBOSE(10, m_mc.display(verbose_stream())); + IF_VERBOSE(10, m_mc.display(verbose_stream())); + //IF_VERBOSE(0, display_units(verbose_stream())); + //IF_VERBOSE(0, display(verbose_stream())); + IF_VERBOSE(0, for (bool_var v = 0; v < num; v++) verbose_stream() << v << ": " << m_model[v] << "\n";); + throw solver_exception("check model failed"); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c56c033a0..1bf78ab8c 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -236,6 +236,10 @@ namespace sat { void set_learned(clause& c, bool learned); void set_learned(literal l1, literal l2, bool learned); void set_learned1(literal l1, literal l2, bool learned); + void add_ate(clause& c) { m_mc.add_ate(c); } + void add_ate(literal l1, literal l2) { m_mc.add_ate(l1, l2); } + void add_ate(literal_vector const& lits) { m_mc.add_ate(lits); } + class scoped_disable_checkpoint { solver& s; public: From 45f48123e76b6e5717927b24d54db51d467b276d Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Fri, 6 Apr 2018 11:39:08 -0400 Subject: [PATCH 0742/1283] add re.plus length enumeration; fix reordering warning --- src/smt/theory_str.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 811b66798..64cba43fb 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -54,12 +54,12 @@ namespace smt { m_unused_id(0), m_delayed_axiom_setup_terms(m), m_delayed_assertions_todo(m), + m_persisted_axioms(m), + m_persisted_axiom_todo(m), tmpStringVarCount(0), tmpXorVarCount(0), tmpLenTestVarCount(0), tmpValTestVarCount(0), - m_persisted_axioms(m), - m_persisted_axiom_todo(m), avoidLoopCut(true), loopDetected(false), m_theoryStrOverlapAssumption_term(m), @@ -6865,7 +6865,7 @@ namespace smt { finalResult.push_back(r2); expr_ref retval(mk_and(finalResult), m); return retval; - } else if (u.re.is_star(re, sub1)) { + } else if (u.re.is_star(re, sub1) || u.re.is_plus(re, sub1)) { // stars are generated as a linear combination of all possible subterm lengths; // this requires that there are no stars under this one /* @@ -6898,27 +6898,16 @@ namespace smt { expr * n = mk_int_var("rstar"); freeVariables.push_back(n); expr_ref term(m_autil.mk_mul(m_autil.mk_numeral(lenOption, true), n), m); - sum_terms.push_back(term); + expr_ref term2(term, m); + if (u.re.is_plus(re)) { + // n effectively starts at 1 + term2 = m_autil.mk_add(m_autil.mk_numeral(lenOption, true), term); + } + sum_terms.push_back(term2); } expr_ref retval(ctx.mk_eq_atom(lenVar, m_autil.mk_add_simplify(sum_terms)), m); return retval; } - } else if (u.re.is_plus(re, sub1)) { - /* - expr * v = mk_int_var("rlen"); - expr * n = mk_int_var("rstar"); - freeVariables.push_back(v); - freeVariables.push_back(n); - expr_ref rsub = infer_all_regex_lengths(v, sub1, freeVariables); - expr_ref_vector finalResult(m); - finalResult.push_back(rsub); - finalResult.push_back(ctx.mk_eq_atom(lenVar, m_autil.mk_mul(v, n))); - finalResult.push_back(m_autil.mk_ge(n, m_autil.mk_numeral(rational::one(), true))); - expr_ref retval(mk_and(finalResult), m); - return retval; - */ - // TODO this should really be done as a sub-case of star - NOT_IMPLEMENTED_YET(); } else if (u.re.is_range(re, sub1, sub2)) { SASSERT(u.str.is_string(sub1)); SASSERT(u.str.is_string(sub2)); From be4edddd2b0e81693ef5fefd53aa597428443e8f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 6 Apr 2018 17:08:29 +0100 Subject: [PATCH 0743/1283] Fixed bug in to_fp/to_fp_unsigned. Thanks to Florian Schanda for reporting this bug. --- src/ast/fpa/fpa2bv_converter.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 9b9f0b427..66b912eb8 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2845,7 +2845,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const expr_ref is_neg(m), x_abs(m), neg_x(m); is_neg_bit = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, x); is_neg = m.mk_eq(is_neg_bit, bv1_1); - neg_x = m_bv_util.mk_bv_neg(x); + neg_x = m_bv_util.mk_bv_neg(x); // overflow problem? x_abs = m.mk_ite(is_neg, neg_x, x); dbg_decouple("fpa2bv_to_fp_signed_is_neg", is_neg); // x_abs has an extra bit in the front. @@ -2882,11 +2882,13 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const SASSERT(is_well_sorted(m, lz)); } SASSERT(m_bv_util.get_bv_size(sig_4) == sig_sz); + dbg_decouple("fpa2bv_to_fp_signed_sig_4", sig_4); expr_ref s_exp(m), exp_rest(m); s_exp = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(bv_sz - 2, bv_sz), lz); // s_exp = (bv_sz-2) + (-lz) signed SASSERT(m_bv_util.get_bv_size(s_exp) == bv_sz); + dbg_decouple("fpa2bv_to_fp_signed_s_exp", s_exp); unsigned exp_sz = ebits + 2; // (+2 for rounder) exp_2 = m_bv_util.mk_extract(exp_sz - 1, 0, s_exp); @@ -2907,10 +2909,9 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const mk_max_exp(exp_sz, max_exp); max_exp_bvsz = m_bv_util.mk_zero_extend(bv_sz - exp_sz, max_exp); - exp_too_large = m_bv_util.mk_ule(m_bv_util.mk_bv_add( - max_exp_bvsz, - m_bv_util.mk_numeral(1, bv_sz)), - s_exp); + exp_too_large = m_bv_util.mk_sle( + m_bv_util.mk_bv_add(max_exp_bvsz, m_bv_util.mk_numeral(1, bv_sz)), + s_exp); zero_sig_sz = m_bv_util.mk_numeral(0, sig_sz); sig_4 = m.mk_ite(exp_too_large, zero_sig_sz, sig_4); exp_2 = m.mk_ite(exp_too_large, max_exp, exp_2); @@ -3040,7 +3041,7 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con mk_max_exp(exp_sz, max_exp); max_exp_bvsz = m_bv_util.mk_zero_extend(bv_sz - exp_sz, max_exp); - exp_too_large = m_bv_util.mk_ule(m_bv_util.mk_bv_add( + exp_too_large = m_bv_util.mk_sle(m_bv_util.mk_bv_add( max_exp_bvsz, m_bv_util.mk_numeral(1, bv_sz)), s_exp); From 27f2b542df088f060fff7540703896e32e284cb8 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Fri, 6 Apr 2018 12:13:53 -0400 Subject: [PATCH 0744/1283] remove comment --- src/smt/theory_str.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 64cba43fb..0a3089c62 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6831,8 +6831,6 @@ namespace smt { * In some cases, the returned formula requires one or more free integer variables to be created. * These variables are returned in the reference parameter `freeVariables`. * Extra assertions should be made for these free variables constraining them to be non-negative. - * - * TODO: star unrolling? */ expr_ref theory_str::infer_all_regex_lengths(expr * lenVar, expr * re, expr_ref_vector & freeVariables) { ENSURE(u.is_re(re)); From 3b78bdc8e5250617fe9c527c589845453852c43f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Apr 2018 14:01:09 -0700 Subject: [PATCH 0745/1283] shorthands in enode to access args and partents Signed-off-by: Nikolaj Bjorner --- examples/c++/example.cpp | 5 ++++- src/smt/smt_enode.h | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index ed5bf7086..b25507885 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -927,7 +927,10 @@ void tuple_example() { sort sorts[2] = { ctx.int_sort(), ctx.bool_sort() }; func_decl_vector projs(ctx); func_decl pair = ctx.tuple_sort("pair", 2, names, sorts, projs); - std::cout << pair << "\n"; + sorts[1] = pair.range(); + func_decl pair2 = ctx.tuple_sort("pair2", 2, names, sorts, projs); + + std::cout << pair2 << "\n"; } void expr_vector_example() { diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index b216665e5..df6309424 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -216,6 +216,15 @@ namespace smt { return m_args; } + class args { + enode const& n; + public: + args(enode const& n):n(n) {} + args(enode const* n):n(*n) {} + enode_vector::const_iterator begin() const { return n.get_args(); } + enode_vector::const_iterator end() const { return n.get_args() + n.get_num_args(); } + }; + // unsigned get_id() const { // return m_id; // } @@ -285,6 +294,16 @@ namespace smt { return m_commutative; } + class parents { + enode const& n; + public: + parents(enode const& _n):n(_n) {} + parents(enode const* _n):n(*_n) {} + enode_vector::const_iterator begin() const { return n.begin_parents(); } + enode_vector::const_iterator end() const { return n.end_parents(); } + }; + + unsigned get_num_parents() const { return m_parents.size(); } From b5d531f079d6b678dc8accf6fd165185361c18d6 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 2 Apr 2018 13:37:12 -0500 Subject: [PATCH 0746/1283] perf(datatype): improve caching in occurs_check --- src/smt/theory_datatype.cpp | 10 +++++++--- src/smt/theory_datatype.h | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 3d3d56055..a3c0ecc96 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -389,12 +389,14 @@ namespace smt { final_check_status theory_datatype::final_check_eh() { int num_vars = get_num_vars(); final_check_status r = FC_DONE; + init_final_check(); for (int v = 0; v < num_vars; v++) { if (v == static_cast(m_find.find(v))) { enode * node = get_enode(v); if (occurs_check(node)) { // conflict was detected... // return... + cleanup_final_check(); return FC_CONTINUE; } if (m_params.m_dt_lazy_splits > 0) { @@ -407,6 +409,7 @@ namespace smt { } } } + cleanup_final_check(); return r; } @@ -434,6 +437,8 @@ namespace smt { tout << "eq: #" << p.first->get_owner_id() << " #" << p.second->get_owner_id() << "\n"; tout << mk_bounded_pp(p.first->get_owner(), get_manager()) << " " << mk_bounded_pp(p.second->get_owner(), get_manager()) << "\n"; }); + } else { + oc_mark_cycle_free(n); } return res; } @@ -443,12 +448,11 @@ namespace smt { TODO: improve performance. */ bool theory_datatype::occurs_check_core(enode * app) { - if (app->is_marked()) + if (oc_cycle_free(app) || oc_explored(app)) return false; m_stats.m_occurs_check++; - app->set_mark(); - m_to_unmark.push_back(app); + oc_mark_explore(app); TRACE("datatype", tout << "occurs check_core: #" << app->get_owner_id() << " #" << m_main->get_owner_id() << "\n";); diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 2337fd0ea..1ccc15314 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -74,8 +74,24 @@ namespace smt { void sign_recognizer_conflict(enode * c, enode * r); ptr_vector m_to_unmark; + ptr_vector m_to_unmark2; enode_pair_vector m_used_eqs; enode * m_main; + + void oc_mark_explore(enode * n) { n->set_mark(); m_to_unmark.push_back(n); } + bool oc_explored(enode * n) const { n->is_marked(); } + + void oc_mark_cycle_free(enode * n) { n->set_mark2(); m_to_unmark2.push_back(n); } + bool oc_cycle_free(enode * n) const { n->is_marked2(); } + + void init_final_check() { + m_to_unmark2.reset(); + } + void cleanup_final_check() { + unmark_enodes2(m_to_unmark2.size(), m_to_unmark2.c_ptr()); + m_to_unmark2.reset(); + } + bool occurs_check(enode * n); bool occurs_check_core(enode * n); From 2ee1e358b6cb3aa03c63580d656499106ae4c4a2 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 2 Apr 2018 15:10:08 -0500 Subject: [PATCH 0747/1283] chore: add definition for `enode_tbl` --- src/smt/smt_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smt/smt_types.h b/src/smt/smt_types.h index 6300bd43c..17b99c8b2 100644 --- a/src/smt/smt_types.h +++ b/src/smt/smt_types.h @@ -21,6 +21,7 @@ Revision History: #include "util/list.h" #include "util/vector.h" +#include "util/hashtable.h" #include "util/lbool.h" class model; @@ -46,6 +47,7 @@ namespace smt { typedef ptr_vector enode_vector; typedef std::pair enode_pair; typedef svector enode_pair_vector; + typedef ptr_hashtable, deref_eq > enode_tbl; class context; From 9df140343a9565cbdae2fdf39b876882add46933 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 2 Apr 2018 17:17:21 -0500 Subject: [PATCH 0748/1283] perf(datatype): whole-graph implementation of occurs_check --- src/smt/smt_enode.h | 7 ++ src/smt/smt_types.h | 1 - src/smt/theory_datatype.cpp | 136 ++++++++++++++++++++++-------------- src/smt/theory_datatype.h | 61 +++++++++++----- 4 files changed, 135 insertions(+), 70 deletions(-) diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index df6309424..ba13a31bb 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -171,6 +171,9 @@ namespace smt { m_interpreted = true; } + inline bool equal(const enode & other) const { + return m_owner == other.m_owner; + } void del_eh(ast_manager & m, bool update_children_parent = true); @@ -423,5 +426,9 @@ namespace smt { }; +inline bool operator==(const smt::enode & e1, const smt::enode & e2) { + return e1.equal(e2); +} + #endif /* SMT_ENODE_H_ */ diff --git a/src/smt/smt_types.h b/src/smt/smt_types.h index 17b99c8b2..e062a4ad6 100644 --- a/src/smt/smt_types.h +++ b/src/smt/smt_types.h @@ -47,7 +47,6 @@ namespace smt { typedef ptr_vector enode_vector; typedef std::pair enode_pair; typedef svector enode_pair_vector; - typedef ptr_hashtable, deref_eq > enode_tbl; class context; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index a3c0ecc96..b3c6ffadf 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -389,14 +389,13 @@ namespace smt { final_check_status theory_datatype::final_check_eh() { int num_vars = get_num_vars(); final_check_status r = FC_DONE; - init_final_check(); + final_check_st _guard(this); // RAII for managing state for (int v = 0; v < num_vars; v++) { if (v == static_cast(m_find.find(v))) { enode * node = get_enode(v); if (occurs_check(node)) { // conflict was detected... // return... - cleanup_final_check(); return FC_CONTINUE; } if (m_params.m_dt_lazy_splits > 0) { @@ -409,10 +408,62 @@ namespace smt { } } } - cleanup_final_check(); return r; } + // explain the cycle root -> … -> app -> root + void theory_datatype::occurs_check_explain(enode * app, enode * const root) { + TRACE("datatype", tout << "occurs_check_explain " << mk_bounded_pp(app->get_owner(), get_manager()) << " <-> " << mk_bounded_pp(root->get_owner(), get_manager()) << "\n";); + enode* app_parent = nullptr; + + while (app->get_root() != root->get_root()) { + theory_var v = app->get_root()->get_th_var(get_id()); + SASSERT(v != null_theory_var); + v = m_find.find(v); + var_data * d = m_var_data[v]; + SASSERT(d->m_constructor); + if (app != d->m_constructor) + m_used_eqs.push_back(enode_pair(app, d->m_constructor)); + bool found = m_parent.find(app, app_parent); + SASSERT(found); + app = app_parent; + } + + SASSERT(app->get_root() == root->get_root()); + if (app != root) + m_used_eqs.push_back(enode_pair(app, root)); + } + + // start exploring subgraph below `app` + bool theory_datatype::occurs_check_enter(enode * app) { + oc_mark_on_stack(app); + theory_var v = app->get_root()->get_th_var(get_id()); + if (v != null_theory_var) { + v = m_find.find(v); + var_data * d = m_var_data[v]; + if (d->m_constructor) { + unsigned num_args = d->m_constructor->get_num_args(); + for (unsigned i = 0; i < num_args; i++) { + enode * arg = d->m_constructor->get_arg(i); + if (oc_cycle_free(arg)) { + return false; + } + if (oc_on_stack(arg)) { + // arg was explored before app, and is still on the stack: cycle + occurs_check_explain(app, arg); + return true; + } + // explore `arg` (with parent `app`) + if (m_util.is_datatype(get_manager().get_sort(arg->get_owner()))) { + m_parent.insert(arg, app); + oc_push_stack(arg); + } + } + } + } + return false; + } + /** \brief Check if n can be reached starting from n and following equalities and constructors. For example, occur_check(a1) returns true in the following set of equalities: @@ -421,68 +472,47 @@ namespace smt { a3 = cons(v3, a1) */ bool theory_datatype::occurs_check(enode * n) { - TRACE("datatype", tout << "occurs check: #" << n->get_owner_id() << "\n";); - m_to_unmark.reset(); - m_used_eqs.reset(); - m_main = n; - bool res = occurs_check_core(m_main); - unmark_enodes(m_to_unmark.size(), m_to_unmark.c_ptr()); + TRACE("datatype", tout << "occurs check: #" << n->get_owner_id() << " " << mk_bounded_pp(n->get_owner(), get_manager()) << "\n";); + m_stats.m_occurs_check++; + + bool res = false; + oc_push_stack(n); + + // DFS traversal from `n`. Look at top element and explore it. + while (!res && !m_stack.empty()) { + stack_op op = m_stack.back().first; + enode * app = m_stack.back().second; + m_stack.pop_back(); + + if (oc_cycle_free(app)) continue; + + TRACE("datatype", tout << "occurs check loop: #" << app->get_owner_id() << " " << mk_bounded_pp(app->get_owner(), get_manager()) << (op==ENTER?" enter":" exit")<< "\n";); + + switch (op) { + case ENTER: + res = occurs_check_enter(app) || res; + break; + + case EXIT: + oc_mark_cycle_free(app); + break; + } + } + if (res) { + // m_used_eqs should contain conflict context & ctx = get_context(); region & r = ctx.get_region(); ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, nullptr, m_used_eqs.size(), m_used_eqs.c_ptr()))); - TRACE("occurs_check", + TRACE("datatype", tout << "occurs_check: true\n"; for (enode_pair const& p : m_used_eqs) { tout << "eq: #" << p.first->get_owner_id() << " #" << p.second->get_owner_id() << "\n"; tout << mk_bounded_pp(p.first->get_owner(), get_manager()) << " " << mk_bounded_pp(p.second->get_owner(), get_manager()) << "\n"; }); - } else { - oc_mark_cycle_free(n); } return res; } - - /** - \brief Auxiliary method for occurs_check. - TODO: improve performance. - */ - bool theory_datatype::occurs_check_core(enode * app) { - if (oc_cycle_free(app) || oc_explored(app)) - return false; - - m_stats.m_occurs_check++; - oc_mark_explore(app); - - TRACE("datatype", tout << "occurs check_core: #" << app->get_owner_id() << " #" << m_main->get_owner_id() << "\n";); - - theory_var v = app->get_root()->get_th_var(get_id()); - if (v != null_theory_var) { - v = m_find.find(v); - var_data * d = m_var_data[v]; - if (d->m_constructor) { - if (app != d->m_constructor) - m_used_eqs.push_back(enode_pair(app, d->m_constructor)); - unsigned num_args = d->m_constructor->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - enode * arg = d->m_constructor->get_arg(i); - if (arg->get_root() == m_main->get_root()) { - if (arg != m_main) - m_used_eqs.push_back(enode_pair(arg, m_main)); - return true; - } - if (m_util.is_datatype(get_manager().get_sort(arg->get_owner())) && occurs_check_core(arg)) - return true; - } - if (app != d->m_constructor) { - SASSERT(m_used_eqs.back().first == app); - SASSERT(m_used_eqs.back().second == d->m_constructor); - m_used_eqs.pop_back(); - } - } - } - return false; - } void theory_datatype::reset_eh() { m_trail_stack.reset(); diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 1ccc15314..fe8396fc5 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -26,7 +26,6 @@ Revision History: #include "smt/proto_model/datatype_factory.h" namespace smt { - class theory_datatype : public theory { typedef trail_stack th_trail_stack; typedef union_find th_union_find; @@ -73,27 +72,57 @@ namespace smt { void propagate_recognizer(theory_var v, enode * r); void sign_recognizer_conflict(enode * c, enode * r); - ptr_vector m_to_unmark; - ptr_vector m_to_unmark2; - enode_pair_vector m_used_eqs; - enode * m_main; + typedef enum { ENTER, EXIT } stack_op; + typedef map, deref_eq > parent_tbl; + typedef std::pair stack_entry; - void oc_mark_explore(enode * n) { n->set_mark(); m_to_unmark.push_back(n); } - bool oc_explored(enode * n) const { n->is_marked(); } + ptr_vector m_to_unmark; + ptr_vector m_to_unmark2; + enode_pair_vector m_used_eqs; // conflict, if any + parent_tbl m_parent; // parent explanation for occurs_check + svector m_stack; // stack for DFS for occurs_check - void oc_mark_cycle_free(enode * n) { n->set_mark2(); m_to_unmark2.push_back(n); } - bool oc_cycle_free(enode * n) const { n->is_marked2(); } + void oc_mark_on_stack(enode * n) { + n = n->get_root(); + n->set_mark(); + m_to_unmark.push_back(n); } + bool oc_on_stack(enode * n) const { return n->get_root()->is_marked(); } - void init_final_check() { - m_to_unmark2.reset(); - } - void cleanup_final_check() { - unmark_enodes2(m_to_unmark2.size(), m_to_unmark2.c_ptr()); - m_to_unmark2.reset(); + void oc_mark_cycle_free(enode * n) { + n = n->get_root(); + n->set_mark2(); + m_to_unmark2.push_back(n); } + bool oc_cycle_free(enode * n) const { return n->get_root()->is_marked2(); } + + void oc_push_stack(enode * n) { + m_stack.push_back(std::make_pair(EXIT, n)); + m_stack.push_back(std::make_pair(ENTER, n)); } + // class for managing state of final_check + class final_check_st { + theory_datatype * th; + public: + final_check_st(theory_datatype * th) : th(th) { + th->m_to_unmark2.reset(); + th->m_to_unmark.reset(); + th->m_used_eqs.reset(); + th->m_stack.reset(); + th->m_parent.reset(); + } + ~final_check_st() { + unmark_enodes(th->m_to_unmark.size(), th->m_to_unmark.c_ptr()); + unmark_enodes2(th->m_to_unmark2.size(), th->m_to_unmark2.c_ptr()); + th->m_to_unmark.reset(); + th->m_to_unmark2.reset(); + th->m_stack.reset(); + th->m_parent.reset(); + } + }; + bool occurs_check(enode * n); - bool occurs_check_core(enode * n); + bool occurs_check_enter(enode * n); + void occurs_check_explain(enode * top, enode * root); void mk_split(theory_var v); From fa10e510bba1647a00807a04cb7bdff73acf0dea Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 3 Apr 2018 11:53:29 -0500 Subject: [PATCH 0749/1283] fix(datatype): only use pointer equality for enode_tbl --- src/smt/smt_enode.h | 7 ------- src/smt/theory_datatype.h | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index ba13a31bb..df6309424 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -171,9 +171,6 @@ namespace smt { m_interpreted = true; } - inline bool equal(const enode & other) const { - return m_owner == other.m_owner; - } void del_eh(ast_manager & m, bool update_children_parent = true); @@ -426,9 +423,5 @@ namespace smt { }; -inline bool operator==(const smt::enode & e1, const smt::enode & e2) { - return e1.equal(e2); -} - #endif /* SMT_ENODE_H_ */ diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index fe8396fc5..4dc99f774 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -73,7 +73,7 @@ namespace smt { void sign_recognizer_conflict(enode * c, enode * r); typedef enum { ENTER, EXIT } stack_op; - typedef map, deref_eq > parent_tbl; + typedef map, ptr_eq > parent_tbl; typedef std::pair stack_entry; ptr_vector m_to_unmark; From e535cad48004e027f97f1d37bf341c61ec4eab4b Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 3 Apr 2018 12:12:09 -0500 Subject: [PATCH 0750/1283] chore(datatype): small improvements --- src/smt/theory_datatype.cpp | 2 +- src/smt/theory_datatype.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index b3c6ffadf..fb817502b 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -393,7 +393,7 @@ namespace smt { for (int v = 0; v < num_vars; v++) { if (v == static_cast(m_find.find(v))) { enode * node = get_enode(v); - if (occurs_check(node)) { + if (!oc_cycle_free(node) && occurs_check(node)) { // conflict was detected... // return... return FC_CONTINUE; diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 4dc99f774..29799910b 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -104,8 +104,8 @@ namespace smt { theory_datatype * th; public: final_check_st(theory_datatype * th) : th(th) { - th->m_to_unmark2.reset(); th->m_to_unmark.reset(); + th->m_to_unmark2.reset(); th->m_used_eqs.reset(); th->m_stack.reset(); th->m_parent.reset(); @@ -115,6 +115,7 @@ namespace smt { unmark_enodes2(th->m_to_unmark2.size(), th->m_to_unmark2.c_ptr()); th->m_to_unmark.reset(); th->m_to_unmark2.reset(); + th->m_used_eqs.reset(); th->m_stack.reset(); th->m_parent.reset(); } From 433f487ff2d2dcb8d4c4427169b46e8db3b34c82 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 3 Apr 2018 18:30:09 -0500 Subject: [PATCH 0751/1283] fix(datatype): always use root nodes for the `parent` table --- src/smt/theory_datatype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index fb817502b..68ebb60e6 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -424,7 +424,7 @@ namespace smt { SASSERT(d->m_constructor); if (app != d->m_constructor) m_used_eqs.push_back(enode_pair(app, d->m_constructor)); - bool found = m_parent.find(app, app_parent); + bool found = m_parent.find(app->get_root(), app_parent); SASSERT(found); app = app_parent; } @@ -455,7 +455,7 @@ namespace smt { } // explore `arg` (with parent `app`) if (m_util.is_datatype(get_manager().get_sort(arg->get_owner()))) { - m_parent.insert(arg, app); + m_parent.insert(arg->get_root(), app); oc_push_stack(arg); } } From d973b0824745ba97ebeb0259d250cc1ad78a4899 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 4 Apr 2018 10:41:40 -0500 Subject: [PATCH 0752/1283] fix(datatypes): update following @nikolajbjorner 's review --- src/smt/theory_datatype.cpp | 5 ++--- src/smt/theory_datatype.h | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 68ebb60e6..e21067a56 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -412,7 +412,7 @@ namespace smt { } // explain the cycle root -> … -> app -> root - void theory_datatype::occurs_check_explain(enode * app, enode * const root) { + void theory_datatype::occurs_check_explain(enode * app, enode * root) { TRACE("datatype", tout << "occurs_check_explain " << mk_bounded_pp(app->get_owner(), get_manager()) << " <-> " << mk_bounded_pp(root->get_owner(), get_manager()) << "\n";); enode* app_parent = nullptr; @@ -424,8 +424,7 @@ namespace smt { SASSERT(d->m_constructor); if (app != d->m_constructor) m_used_eqs.push_back(enode_pair(app, d->m_constructor)); - bool found = m_parent.find(app->get_root(), app_parent); - SASSERT(found); + app_parent = m_parent[app->get_root()]; app = app_parent; } diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 29799910b..77da52360 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -104,8 +104,8 @@ namespace smt { theory_datatype * th; public: final_check_st(theory_datatype * th) : th(th) { - th->m_to_unmark.reset(); - th->m_to_unmark2.reset(); + SASSERT(th->m_to_unmark.empty()); + SASSERT(th->m_to_unmark2.empty()); th->m_used_eqs.reset(); th->m_stack.reset(); th->m_parent.reset(); From bf6928fec0bfa273201ecc6d3c0f07706e82a9b5 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 6 Apr 2018 11:13:53 -0500 Subject: [PATCH 0753/1283] fix(datatypes): additional explanation in occurs_check --- src/smt/theory_datatype.cpp | 36 +++++++++++++++++++++++++++++------- src/smt/theory_datatype.h | 1 + 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index e21067a56..f17bdc3d6 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -411,19 +411,41 @@ namespace smt { return r; } + // Assuming `app` is equal to a constructor term, return the constructor enode + inline enode * theory_datatype::oc_get_cstor(enode * app) { + theory_var v = app->get_root()->get_th_var(get_id()); + SASSERT(v != null_theory_var); + v = m_find.find(v); + var_data * d = m_var_data[v]; + SASSERT(d->m_constructor); + return d->m_constructor; + } + // explain the cycle root -> … -> app -> root void theory_datatype::occurs_check_explain(enode * app, enode * root) { TRACE("datatype", tout << "occurs_check_explain " << mk_bounded_pp(app->get_owner(), get_manager()) << " <-> " << mk_bounded_pp(root->get_owner(), get_manager()) << "\n";); enode* app_parent = nullptr; + // first: explain that root=v, given that app=cstor(…,v,…) + { + enode * app_cstor = oc_get_cstor(app); + unsigned n_args_app = app_cstor->get_num_args(); + for (unsigned i=0; i < n_args_app; ++i) { + enode * arg = app_cstor->get_arg(i); + // found an argument which is equal to root + if (arg->get_root() == root->get_root()) { + if (arg != root) + m_used_eqs.push_back(enode_pair(arg, root)); + break; + } + } + } + + // now explain app=cstor(…,v,…) where v=root, and recurse with parent of app while (app->get_root() != root->get_root()) { - theory_var v = app->get_root()->get_th_var(get_id()); - SASSERT(v != null_theory_var); - v = m_find.find(v); - var_data * d = m_var_data[v]; - SASSERT(d->m_constructor); - if (app != d->m_constructor) - m_used_eqs.push_back(enode_pair(app, d->m_constructor)); + enode * app_cstor = oc_get_cstor(app); + if (app != app_cstor) + m_used_eqs.push_back(enode_pair(app, app_cstor)); app_parent = m_parent[app->get_root()]; app = app_parent; } diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 77da52360..020949296 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -121,6 +121,7 @@ namespace smt { } }; + enode * oc_get_cstor(enode * n); bool occurs_check(enode * n); bool occurs_check_enter(enode * n); void occurs_check_explain(enode * top, enode * root); From 8fd2d8a636b65ca9e5d13bcc7f327e34ec40a09f Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 6 Apr 2018 15:56:05 -0500 Subject: [PATCH 0754/1283] chore(datatype): small fixes --- src/smt/theory_datatype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index f17bdc3d6..825856e37 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -452,7 +452,7 @@ namespace smt { SASSERT(app->get_root() == root->get_root()); if (app != root) - m_used_eqs.push_back(enode_pair(app, root)); + m_used_eqs.push_back(enode_pair(app, root)); } // start exploring subgraph below `app` @@ -511,7 +511,7 @@ namespace smt { switch (op) { case ENTER: - res = occurs_check_enter(app) || res; + res = occurs_check_enter(app); break; case EXIT: From ac881d949d69db7bf83df9dd861526f64c5a3deb Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 6 Apr 2018 17:19:06 -0500 Subject: [PATCH 0755/1283] style(datatype): use modern iteration --- src/smt/theory_datatype.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 825856e37..147067d61 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -429,9 +429,7 @@ namespace smt { // first: explain that root=v, given that app=cstor(…,v,…) { enode * app_cstor = oc_get_cstor(app); - unsigned n_args_app = app_cstor->get_num_args(); - for (unsigned i=0; i < n_args_app; ++i) { - enode * arg = app_cstor->get_arg(i); + for (enode * arg : enode::args(app_cstor)) { // found an argument which is equal to root if (arg->get_root() == root->get_root()) { if (arg != root) @@ -463,9 +461,7 @@ namespace smt { v = m_find.find(v); var_data * d = m_var_data[v]; if (d->m_constructor) { - unsigned num_args = d->m_constructor->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - enode * arg = d->m_constructor->get_arg(i); + for (enode * arg : enode::args(d->m_constructor)) { if (oc_cycle_free(arg)) { return false; } From 21738d9750aa5902173ad47df61f5f4c7dcaf9d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Apr 2018 15:59:55 -0700 Subject: [PATCH 0756/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_model_converter.cpp | 3 ++- src/sat/sat_simplifier.cpp | 14 ++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index bebb3e384..b097b3462 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -75,7 +75,7 @@ namespace sat { void model_converter::operator()(model & m) const { vector::const_iterator begin = m_entries.begin(); vector::const_iterator it = m_entries.end(); - bool first = true; // false; // true; // false; // true; + bool first = false; // true; // false; // // true; //SASSERT(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; @@ -101,6 +101,7 @@ namespace sat { if (!sat && it->get_kind() != ATE && v0 != null_bool_var) { VERIFY(legal_to_flip(v0)); m[v0] = var_sign ? l_false : l_true; + //IF_VERBOSE(0, verbose_stream() << "assign " << v0 << " "<< m[v0] << "\n"); } elim_stack* st = it->m_elim_stack[index]; if (st) { diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 52c7236a0..3f6c2d6ca 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1174,7 +1174,8 @@ namespace sat { This routine removes literals that were not relevant to establishing it was blocked. It has a bug: literals that are used to prune tautologies during resolution intersection should be included - in the dependencies. + in the dependencies. They may get used in some RI prunings and then they have to be included to avoid flipping + RI literals. */ void minimize_covered_clause(unsigned idx) { // IF_VERBOSE(0, verbose_stream() << "minimize: " << m_covered_clause @@ -1199,8 +1200,8 @@ namespace sat { } for (unsigned i = idx; i > 0; --i) { literal lit = m_covered_clause[i]; - //s.mark_visited(lit); - //continue; + s.mark_visited(lit); + continue; if (!s.is_marked(lit)) continue; clause_ante const& ante = m_covered_antecedent[i]; if (ante.cls()) { @@ -1617,13 +1618,6 @@ namespace sat { for (literal l2 : m_intersection) { watched* w = find_binary_watch(s.get_wlist(~l), ~l2); if (!w) { -#if 0 - IF_VERBOSE(0, verbose_stream() << "bca " << l << " " << ~l2 << "\n"); - if (l.var() == 10219 && l2.var() == 10202) { - IF_VERBOSE(0, s.s.display(verbose_stream())); - exit(0); - } -#endif s.s.mk_bin_clause(l, ~l2, true); ++s.m_num_bca; } From cfd9785025e7995cc7622abe258c1271dd85bf89 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Apr 2018 19:32:01 -0700 Subject: [PATCH 0757/1283] replace by int64_t and uint64_t Signed-off-by: Nikolaj Bjorner --- src/util/util.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/util/util.h b/src/util/util.h index ad427dfaf..067c2b2f4 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -24,19 +24,22 @@ Revision History: #include #include #include +#include #ifndef SIZE_MAX #define SIZE_MAX std::numeric_limits::max() #endif +#undef uint64 #ifndef uint64 -typedef unsigned long long uint64; +typedef uint64_t uint64; #endif static_assert(sizeof(uint64) == 8, "64 bits please"); +#undef int64 #ifndef int64 -typedef long long int64; +typedef int64_t int64; #endif static_assert(sizeof(int64) == 8, "64 bits"); From 66b85e000b419ba414939eeb9fa4e146bbebdfd0 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sat, 7 Apr 2018 01:25:19 -0500 Subject: [PATCH 0758/1283] fix in occurs_check (early exit) --- src/smt/theory_datatype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 147067d61..da18460f4 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -463,7 +463,7 @@ namespace smt { if (d->m_constructor) { for (enode * arg : enode::args(d->m_constructor)) { if (oc_cycle_free(arg)) { - return false; + continue; } if (oc_on_stack(arg)) { // arg was explored before app, and is still on the stack: cycle From 4f5133cf72e98453a8faab089fba720438cbc0c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Apr 2018 10:16:46 -0700 Subject: [PATCH 0759/1283] disambiguate calls to set Signed-off-by: Nikolaj Bjorner --- src/util/hwf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/hwf.cpp b/src/util/hwf.cpp index 014e62625..0768eac41 100644 --- a/src/util/hwf.cpp +++ b/src/util/hwf.cpp @@ -413,12 +413,12 @@ void hwf_manager::to_rational(hwf const & x, unsynch_mpq_manager & qm, mpq & o) scoped_mpz n(qm), d(qm); if (is_normal(x)) - qm.set(n, sig(x) | 0x0010000000000000ull); + qm.set(n, (uint64)(sig(x) | 0x0010000000000000ull)); else qm.set(n, sig(x)); if (sgn(x)) qm.neg(n); - qm.set(d, 0x0010000000000000ull); + qm.set(d, (uint64)0x0010000000000000ull); int e = exp(x); if (e >= 0) qm.mul2k(n, (unsigned)e); From 65834661a8369bcb0fda19dd129a194e751a7f0c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Apr 2018 10:53:52 -0700 Subject: [PATCH 0760/1283] disambiguate calls to set Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 5e0082f09..0e3ae4a74 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -213,7 +213,9 @@ extern "C" { // must start loggging here, since function uses Z3_get_sort_kind above LOG_Z3_get_finite_domain_sort_size(c, s, out); RESET_ERROR_CODE(); - VERIFY(mk_c(c)->datalog_util().try_get_size(to_sort(s), *out)); + uint64 _out = 0; + VERIFY(mk_c(c)->datalog_util().try_get_size(to_sort(s), _out)); + *out = static_cast<__uint64>(_out); return Z3_TRUE; Z3_CATCH_RETURN(Z3_FALSE); From 187ba6a5617a346ca7ce981955578d6e41beac28 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Apr 2018 13:31:23 -0700 Subject: [PATCH 0761/1283] fix cast in tests Signed-off-by: Nikolaj Bjorner --- src/test/mpz.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/mpz.cpp b/src/test/mpz.cpp index 7926388df..3fd8cf51b 100644 --- a/src/test/mpz.cpp +++ b/src/test/mpz.cpp @@ -127,8 +127,8 @@ static void bug3() { static void bug4() { synch_mpz_manager m; mpz x, y; - m.set(y, 4294967295ull); - m.set(x, 4026531839ull); + m.set(y, static_cast(4294967295ull)); + m.set(x, static_cast(4026531839ull)); mpz result1; m.bitwise_or(x, y, result1); From bab87bfb9b0b2fd2a1b15c5ab9e61c829d021412 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Apr 2018 17:34:46 -0700 Subject: [PATCH 0762/1283] move some methods from header to cpp, format fixing, remove special characters Signed-off-by: Nikolaj Bjorner --- src/smt/theory_datatype.cpp | 56 +++++++++++++++++++++++++++++-------- src/smt/theory_datatype.h | 35 ++++------------------- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index da18460f4..9ff81fa08 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -36,6 +36,41 @@ namespace smt { theory_id get_from_theory() const override { return null_theory_id; } }; + theory_datatype::final_check_st::final_check_st(theory_datatype * th) : th(th) { + SASSERT(th->m_to_unmark.empty()); + SASSERT(th->m_to_unmark2.empty()); + th->m_used_eqs.reset(); + th->m_stack.reset(); + th->m_parent.reset(); + } + + theory_datatype::final_check_st::~final_check_st() { + unmark_enodes(th->m_to_unmark.size(), th->m_to_unmark.c_ptr()); + unmark_enodes2(th->m_to_unmark2.size(), th->m_to_unmark2.c_ptr()); + th->m_to_unmark.reset(); + th->m_to_unmark2.reset(); + th->m_used_eqs.reset(); + th->m_stack.reset(); + th->m_parent.reset(); + } + + void theory_datatype::oc_mark_on_stack(enode * n) { + n = n->get_root(); + n->set_mark(); + m_to_unmark.push_back(n); + } + + void theory_datatype::oc_mark_cycle_free(enode * n) { + n = n->get_root(); + n->set_mark2(); + m_to_unmark2.push_back(n); + } + + void theory_datatype::oc_push_stack(enode * n) { + m_stack.push_back(std::make_pair(EXIT, n)); + m_stack.push_back(std::make_pair(ENTER, n)); + } + theory* theory_datatype::mk_fresh(context* new_ctx) { return alloc(theory_datatype, new_ctx->get_manager(), m_params); @@ -421,25 +456,22 @@ namespace smt { return d->m_constructor; } - // explain the cycle root -> … -> app -> root + // explain the cycle root -> ... -> app -> root void theory_datatype::occurs_check_explain(enode * app, enode * root) { TRACE("datatype", tout << "occurs_check_explain " << mk_bounded_pp(app->get_owner(), get_manager()) << " <-> " << mk_bounded_pp(root->get_owner(), get_manager()) << "\n";); enode* app_parent = nullptr; // first: explain that root=v, given that app=cstor(…,v,…) - { - enode * app_cstor = oc_get_cstor(app); - for (enode * arg : enode::args(app_cstor)) { - // found an argument which is equal to root - if (arg->get_root() == root->get_root()) { - if (arg != root) - m_used_eqs.push_back(enode_pair(arg, root)); - break; - } + for (enode * arg : enode::args(oc_get_cstor(app))) { + // found an argument which is equal to root + if (arg->get_root() == root->get_root()) { + if (arg != root) + m_used_eqs.push_back(enode_pair(arg, root)); + break; } } - // now explain app=cstor(…,v,…) where v=root, and recurse with parent of app + // now explain app=cstor(..,v,..) where v=root, and recurse with parent of app while (app->get_root() != root->get_root()) { enode * app_cstor = oc_get_cstor(app); if (app != app_cstor) @@ -447,7 +479,7 @@ namespace smt { app_parent = m_parent[app->get_root()]; app = app_parent; } - + SASSERT(app->get_root() == root->get_root()); if (app != root) m_used_eqs.push_back(enode_pair(app, root)); diff --git a/src/smt/theory_datatype.h b/src/smt/theory_datatype.h index 020949296..010e78cb3 100644 --- a/src/smt/theory_datatype.h +++ b/src/smt/theory_datatype.h @@ -82,43 +82,20 @@ namespace smt { parent_tbl m_parent; // parent explanation for occurs_check svector m_stack; // stack for DFS for occurs_check - void oc_mark_on_stack(enode * n) { - n = n->get_root(); - n->set_mark(); - m_to_unmark.push_back(n); } + void oc_mark_on_stack(enode * n); bool oc_on_stack(enode * n) const { return n->get_root()->is_marked(); } - void oc_mark_cycle_free(enode * n) { - n = n->get_root(); - n->set_mark2(); - m_to_unmark2.push_back(n); } + void oc_mark_cycle_free(enode * n); bool oc_cycle_free(enode * n) const { return n->get_root()->is_marked2(); } - void oc_push_stack(enode * n) { - m_stack.push_back(std::make_pair(EXIT, n)); - m_stack.push_back(std::make_pair(ENTER, n)); - } + void oc_push_stack(enode * n); // class for managing state of final_check class final_check_st { theory_datatype * th; - public: - final_check_st(theory_datatype * th) : th(th) { - SASSERT(th->m_to_unmark.empty()); - SASSERT(th->m_to_unmark2.empty()); - th->m_used_eqs.reset(); - th->m_stack.reset(); - th->m_parent.reset(); - } - ~final_check_st() { - unmark_enodes(th->m_to_unmark.size(), th->m_to_unmark.c_ptr()); - unmark_enodes2(th->m_to_unmark2.size(), th->m_to_unmark2.c_ptr()); - th->m_to_unmark.reset(); - th->m_to_unmark2.reset(); - th->m_used_eqs.reset(); - th->m_stack.reset(); - th->m_parent.reset(); - } + public: + final_check_st(theory_datatype * th); + ~final_check_st(); }; enode * oc_get_cstor(enode * n); From 5cff0de844998b7b20eb174560c7aed12a909af1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Apr 2018 11:19:00 -0700 Subject: [PATCH 0763/1283] fix #1567 Signed-off-by: Nikolaj Bjorner --- src/model/model_evaluator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 227e14ca6..0b25a250b 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -454,6 +454,7 @@ struct evaluator_cfg : public default_rewriter_cfg { func_decl* f = m_ar.get_as_array_func_decl(to_app(a)); func_interp* g = m_model.get_func_interp(f); + if (!g) return false; unsigned sz = g->num_entries(); unsigned arity = f->get_arity(); unsigned base_sz = stores.size(); From b373bf4252513e8bab760c82bfe7b97059f28714 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 8 Apr 2018 21:51:27 +0100 Subject: [PATCH 0764/1283] Bugfixes for fpa2bv_converter. Fixes #1564. --- src/ast/fpa/fpa2bv_converter.cpp | 16 +++++++++------- src/ast/rewriter/fpa_rewriter.cpp | 2 +- src/tactic/fpa/fpa2bv_tactic.cpp | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 66b912eb8..025d12cc6 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1919,7 +1919,7 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & expr_ref pow_2_sbitsm1(m), m1(m); pow_2_sbitsm1 = m_bv_util.mk_numeral(fu().fm().m_powers2(sbits - 1), sbits); - m1 = m_bv_util.mk_numeral(-1, ebits); + m1 = m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, ebits)); m_simp.mk_eq(a_sig, pow_2_sbitsm1, t1); m_simp.mk_eq(a_exp, m1, t2); m_simp.mk_and(t1, t2, tie); @@ -1927,7 +1927,7 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & m_simp.mk_and(tie, rm_is_rte, c421); m_simp.mk_and(tie, rm_is_rta, c422); - c423 = m_bv_util.mk_sle(a_exp, m_bv_util.mk_numeral(-2, ebits)); + c423 = m_bv_util.mk_sle(a_exp, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(2, ebits))); dbg_decouple("fpa2bv_r2i_c421", c421); dbg_decouple("fpa2bv_r2i_c422", c422); @@ -2452,7 +2452,7 @@ void fpa2bv_converter::mk_to_fp_float(sort * to_srt, expr * rm, expr * x, expr_r const mpz & ovft = m_mpf_manager.m_powers2.m1(to_ebits+1, false); first_ovf_exp = m_bv_util.mk_numeral(ovft, from_ebits+2); first_udf_exp = m_bv_util.mk_concat( - m_bv_util.mk_numeral(-1, ebits_diff + 3), + m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, ebits_diff + 3)), m_bv_util.mk_numeral(1, to_ebits + 1)); dbg_decouple("fpa2bv_to_float_first_ovf_exp", first_ovf_exp); dbg_decouple("fpa2bv_to_float_first_udf_exp", first_udf_exp); @@ -3107,7 +3107,7 @@ void fpa2bv_converter::mk_to_ieee_bv_unspecified(func_decl * f, unsigned num, ex expr_ref exp_bv(m), exp_all_ones(m); exp_bv = m_bv_util.mk_extract(ebits+sbits-2, sbits-1, result); - exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_numeral(-1, ebits)); + exp_all_ones = m.mk_eq(exp_bv, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, ebits))); m_extra_assertions.push_back(exp_all_ones); expr_ref sig_bv(m), sig_is_non_zero(m); @@ -3246,18 +3246,20 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args incd = m.mk_eq(rounding_decision, bv1); pr_is_zero = m.mk_eq(pre_rounded, m_bv_util.mk_numeral(0, bv_sz + 3)); ovfl = m.mk_and(incd, pr_is_zero); + dbg_decouple("fpa2bv_to_bv_incd", incd); + dbg_decouple("fpa2bv_to_bv_ovfl", ovfl); expr_ref ul(m), in_range(m); if (!is_signed) { - ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_numeral(-1, bv_sz)); + ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz))); in_range = m.mk_and(m.mk_not(x_is_neg), m.mk_not(ovfl), m_bv_util.mk_ule(pre_rounded, ul)); } else { expr_ref ll(m); ll = m_bv_util.mk_sign_extend(3, m_bv_util.mk_concat(bv1, m_bv_util.mk_numeral(0, bv_sz-1))); - ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_numeral(-1, bv_sz-1)); - ovfl = m.mk_or(ovfl, m_bv_util.mk_sle(pre_rounded, m_bv_util.mk_numeral(-1, bv_sz + 3))); + ul = m_bv_util.mk_zero_extend(4, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz-1))); + ovfl = m.mk_or(ovfl, m_bv_util.mk_sle(pre_rounded, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz + 3)))); in_range = m.mk_and(m.mk_not(ovfl), m_bv_util.mk_sle(ll, pre_rounded), m_bv_util.mk_sle(pre_rounded, ul)); diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 162f9d5c7..d978779aa 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -773,7 +773,7 @@ br_status fpa_rewriter::mk_to_ieee_bv(func_decl * f, expr * arg, expr_ref & resu if (m_fm.is_nan(v)) { if (m_hi_fp_unspecified) { expr * args[4] = { bu.mk_numeral(0, 1), - bu.mk_numeral(-1, x.get_ebits()), + bu.mk_bv_neg(bu.mk_numeral(1, x.get_ebits())), bu.mk_numeral(0, x.get_sbits() - 2), bu.mk_numeral(1, 1) }; result = bu.mk_concat(4, args); diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 3c656c6b8..41802c7d3 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -93,7 +93,7 @@ class fpa2bv_tactic : public tactic { expr * sgn, *sig, *exp; m_conv.split_fp(new_curr, sgn, exp, sig); result.back()->assert_expr(m.mk_eq(sgn, m_conv.bu().mk_numeral(0, 1))); - result.back()->assert_expr(m.mk_eq(exp, m_conv.bu().mk_numeral(-1, m_conv.bu().get_bv_size(exp)))); + result.back()->assert_expr(m.mk_eq(exp, m_conv.bu().mk_bv_neg(m_conv.bu().mk_numeral(1, m_conv.bu().get_bv_size(exp))))); result.back()->assert_expr(m.mk_eq(sig, m_conv.bu().mk_numeral(1, m_conv.bu().get_bv_size(sig)))); } } From f2dfc0dc24c8594ae4d1181bfbb4b1848d057a94 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Apr 2018 15:46:21 -0700 Subject: [PATCH 0765/1283] including all touched tautology literals each round Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 25 ++++++++++++++++++------ src/tactic/portfolio/CMakeLists.txt | 2 ++ src/tactic/portfolio/parallel_tactic.cpp | 16 +-------------- src/tactic/smtlogics/qfbv_tactic.cpp | 7 ++++--- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 52c7236a0..ae156cb4b 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1069,8 +1069,8 @@ namespace sat { // Find literals that are in the intersection of all resolvents with l. // bool resolution_intersection(literal l, bool adding) { + unsigned tsz = m_tautology.size(); reset_intersection(); - m_tautology.reset(); if (!process_var(l.var())) return false; bool first = true; VERIFY(s.value(l) == l_undef); @@ -1086,6 +1086,7 @@ namespace sat { } if (!first || s.is_marked(lit)) { reset_intersection(); + m_tautology.shrink(tsz); return false; // intersection is empty or does not add anything new. } first = false; @@ -1122,22 +1123,30 @@ namespace sat { for (literal lit : m_new_intersection) add_intersection(lit); } - if (m_intersection.empty()) + if (m_intersection.empty()) { + m_tautology.shrink(tsz); return false; + } } } + if (m_intersection.empty()) { + m_tautology.shrink(tsz); + } // if (first) IF_VERBOSE(0, verbose_stream() << "taut: " << m_tautology << "\n";); return first; } bool check_abce_tautology(literal l) { - m_tautology.reset(); + unsigned tsz = m_tautology.size(); if (!process_var(l.var())) return false; for (watched & w : s.get_wlist(l)) { if (w.is_binary_non_learned_clause()) { literal lit = w.get_literal(); VERIFY(lit != ~l); - if (!s.is_marked(~lit)) return false; + if (!s.is_marked(~lit)) { + m_tautology.shrink(tsz); + return false; + } m_tautology.push_back(~lit); } } @@ -1153,7 +1162,10 @@ namespace sat { break; } } - if (!tautology) return false; + if (!tautology) { + m_tautology.shrink(tsz); + return false; + } } return true; } @@ -1352,6 +1364,7 @@ namespace sat { unsigned sz = 0, sz0 = m_covered_clause.size(); for (literal l : m_covered_clause) s.mark_visited(l); shuffle(m_covered_clause.size(), m_covered_clause.c_ptr(), s.s.m_rand); + m_tautology.reset(); m_mc.stackv().reset(); m_ala_qhead = 0; @@ -1394,7 +1407,6 @@ namespace sat { * tautology depends on resolution intersection. * literals used for resolution intersection may have to be flipped. */ - m_tautology.reset(); for (literal l : m_covered_clause) { m_tautology.push_back(l); s.mark_visited(l); @@ -1610,6 +1622,7 @@ namespace sat { Then the following binary clause is blocked: l \/ ~l' */ void bca(literal l) { + m_tautology.reset(); if (resolution_intersection(l, true)) { // this literal is pure. return; diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index 055251467..ed5ec8cf7 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -18,6 +18,8 @@ z3_add_component(portfolio smtlogic_tactics subpaving_tactic ufbv_tactic + PYG_FILES + parallel_params.pyg TACTIC_HEADERS default_tactic.h fd_solver.h diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index b19bab487..e01e58051 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -159,8 +159,6 @@ class parallel_tactic : public tactic { ref m_solver; // solver state unsigned m_depth; // number of nested calls to cubing double m_width; // estimate of fraction of problem handled by state - unsigned m_cube_cutoff; // saved configuration value - double m_cube_fraction; // saved configuration value unsigned m_restart_max; // saved configuration value expr_ref_vector cube_literals(expr* cube) { @@ -185,8 +183,6 @@ class parallel_tactic : public tactic { m_depth(0), m_width(1.0) { - m_cube_cutoff = p.get_uint("sat.lookahead.cube.cutoff", 8); - m_cube_fraction = p.get_double("sat.lookahead.cube.fraction", 0.4); m_restart_max = p.get_uint("sat.restart.max", 10); } @@ -280,17 +276,7 @@ class parallel_tactic : public tactic { } void set_cube_params() { - unsigned cutoff = m_cube_cutoff; - double fraction = m_cube_fraction; - if (true || (m_depth == 1 && cutoff > 0)) { - m_params.set_sym("lookahead.cube.cutoff", symbol("depth")); - m_params.set_uint("lookahead.cube.depth", std::max(m_depth, 10u)); - } - else { - m_params.set_sym("lookahead.cube.cutoff", symbol("adaptive_psat")); - m_params.set_double("lookahead.cube.fraction", fraction); - } - get_solver().updt_params(m_params); + // get_solver().updt_params(m_params); } void set_conquer_params() { diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index f28129a52..0eb235791 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -29,6 +29,7 @@ Notes: #include "tactic/aig/aig_tactic.h" #include "sat/tactic/sat_tactic.h" #include "tactic/portfolio/parallel_tactic.h" +#include "tactic/portfolio/parallel_params.hpp" #include "ackermannization/ackermannize_bv_tactic.h" #define MEMLIMIT 300 @@ -128,11 +129,11 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { - + parallel_params pp(p); + bool use_parallel = pp.enable(); tactic * new_sat = cond(mk_produce_proofs_probe(), and_then(mk_simplify_tactic(m), mk_smt_tactic()), - //mk_parallel_tactic(m, p)); - mk_sat_tactic(m)); + use_parallel ? mk_parallel_tactic(m, p): mk_sat_tactic(m)); return mk_qfbv_tactic(m, p, new_sat, mk_smt_tactic()); From d57bca8f8cd7cd0de8c14b76a28c131085c9a213 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Apr 2018 10:43:55 +0800 Subject: [PATCH 0766/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_model_converter.cpp | 2 +- src/sat/sat_simplifier.cpp | 9 +-- src/tactic/core/elim_uncnstr_tactic.cpp | 33 +++------ src/tactic/portfolio/CMakeLists.txt | 2 - src/tactic/portfolio/parallel_tactic.cpp | 88 ++++++++++++++++-------- src/tactic/smtlogics/CMakeLists.txt | 1 + src/tactic/smtlogics/qfbv_tactic.cpp | 2 +- 8 files changed, 78 insertions(+), 61 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 5b89b4dfd..0d737500a 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1832,7 +1832,7 @@ namespace sat { unsigned dl_truth = base + m_lookahead.size() * m_config.m_dl_max_iterations; scoped_level _sl(*this, dl_truth); //SASSERT(get_level(m_trail.back()) == dl_truth); - IF_VERBOSE(2, verbose_stream() << "(sat-lookahead :double " << l << " :depth " << m_trail_lim.size() << ")\n";); + IF_VERBOSE(3, verbose_stream() << "(sat-lookahead :double " << l << " :depth " << m_trail_lim.size() << ")\n";); lookahead_backtrack(); assign(l); propagate(); diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index b097b3462..22cab35ea 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -75,7 +75,7 @@ namespace sat { void model_converter::operator()(model & m) const { vector::const_iterator begin = m_entries.begin(); vector::const_iterator it = m_entries.end(); - bool first = false; // true; // false; // // true; + bool first = false; // true; // false; // // true; //SASSERT(!m_solver || m_solver->check_clauses(m)); while (it != begin) { --it; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index c048740ac..9c57c79ed 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -1129,7 +1129,8 @@ namespace sat { } } } - if (m_intersection.empty()) { + // remove tautology literals if literal has no resolution intersection + if (m_intersection.empty() && !first) { m_tautology.shrink(tsz); } // if (first) IF_VERBOSE(0, verbose_stream() << "taut: " << m_tautology << "\n";); @@ -1202,7 +1203,7 @@ namespace sat { if (m_covered_antecedent[i] == clause_ante()) s.mark_visited(lit); if (s.is_marked(lit)) idx = i; } - if (false) { + if (false && _blocked.var() == 8074) { IF_VERBOSE(0, verbose_stream() << "covered: " << m_covered_clause << "\n"; verbose_stream() << "tautology: " << m_tautology << "\n"; verbose_stream() << "index: " << idx << "\n"; @@ -1212,8 +1213,8 @@ namespace sat { } for (unsigned i = idx; i > 0; --i) { literal lit = m_covered_clause[i]; - s.mark_visited(lit); - continue; + //s.mark_visited(lit); + //continue; if (!s.is_marked(lit)) continue; clause_ante const& ante = m_covered_antecedent[i]; if (ante.cls()) { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 2f961f9bc..0fd25100e 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -552,7 +552,7 @@ class elim_uncnstr_tactic : public tactic { // The result of bv_le is not just introducing a new fresh name, // we need a side condition. // TODO: the correct proof step - return 0; + return nullptr; } if (uncnstr(arg1)) { // v <= t @@ -804,20 +804,17 @@ class elim_uncnstr_tactic : public tactic { ast_manager & m() { return m_manager; } void init_mc(bool produce_models) { - if (!produce_models) { - m_mc = 0; - return; + m_mc = nullptr; + if (produce_models) { + m_mc = alloc(mc, m(), "elim_uncstr"); } - m_mc = alloc(mc, m(), "elim_uncstr"); } void init_rw(bool produce_proofs) { m_rw = alloc(rw, m(), produce_proofs, m_vars, m_mc.get(), m_max_memory, m_max_steps); } - void operator()(goal_ref const & g, - goal_ref_buffer & result) { - bool produce_models = g->models_enabled(); + void operator()(goal_ref const & g, goal_ref_buffer & result) { bool produce_proofs = g->proofs_enabled(); TRACE("elim_uncnstr_bug", g->display(tout);); @@ -832,14 +829,9 @@ class elim_uncnstr_tactic : public tactic { } bool modified = true; TRACE("elim_uncnstr", tout << "unconstrained variables...\n"; - obj_hashtable::iterator it = m_vars.begin(); - obj_hashtable::iterator end = m_vars.end(); - for (; it != end; ++it) { - expr * v = *it; - tout << mk_ismt2_pp(v, m()) << " "; - } + for (expr * v : m_vars) tout << mk_ismt2_pp(v, m()) << " "; tout << "\n";); - init_mc(produce_models); + init_mc(g->models_enabled()); init_rw(produce_proofs); expr_ref new_f(m()); @@ -866,14 +858,9 @@ class elim_uncnstr_tactic : public tactic { else { app_ref_vector & fresh_vars = m_rw->cfg().m_fresh_vars; m_num_elim_apps = fresh_vars.size(); - if (produce_models && !fresh_vars.empty()) { - generic_model_converter * fmc = alloc(generic_model_converter, m(), "elim_uncnstr"); - for (app * f : fresh_vars) - fmc->hide(f); - g->add(concat(fmc, m_mc.get())); - } - else { - g->set((model_converter*)nullptr); + if (m_mc.get()) { + for (app * f : fresh_vars) m_mc->hide(f); + g->add(m_mc.get()); } } m_mc = 0; diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index ed5ec8cf7..055251467 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -18,8 +18,6 @@ z3_add_component(portfolio smtlogic_tactics subpaving_tactic ufbv_tactic - PYG_FILES - parallel_params.pyg TACTIC_HEADERS default_tactic.h fd_solver.h diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index e01e58051..999dbc2e0 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -42,6 +42,7 @@ Notes: #include "solver/solver2tactic.h" #include "tactic/tactic.h" #include "tactic/portfolio/fd_solver.h" +#include "tactic/smtlogics/parallel_params.hpp" class parallel_tactic : public tactic { @@ -150,10 +151,27 @@ class parallel_tactic : public tactic { }; + class cube_var { + expr_ref_vector m_vars; + expr_ref m_cube; + public: + cube_var(expr* c, expr_ref_vector& vs): + m_vars(vs), m_cube(c, vs.get_manager()) {} + + cube_var operator()(ast_translation& tr) { + expr_ref_vector vars(tr.to()); + for (expr* v : m_vars) vars.push_back(tr(v)); + return cube_var(tr(m_cube.get()), vars); + } + + expr* cube() const { return m_cube; } + expr_ref_vector const& vars() { return m_vars; } + }; + class solver_state { task_type m_type; // current work role of the task scoped_ptr m_manager; // ownership handle to ast_manager - expr_ref_vector m_cubes; // set of cubes to process by task + vector m_cubes; // set of cubes to process by task expr_ref_vector m_asserted_cubes; // set of cubes asserted on the current solver params_ref m_params; // configuration parameters ref m_solver; // solver state @@ -176,14 +194,14 @@ class parallel_tactic : public tactic { solver_state(ast_manager* m, solver* s, params_ref const& p, task_type t): m_type(t), m_manager(m), - m_cubes(s->get_manager()), m_asserted_cubes(s->get_manager()), m_params(p), m_solver(s), m_depth(0), m_width(1.0) { - m_restart_max = p.get_uint("sat.restart.max", 10); + parallel_params pp(p); + m_restart_max = pp.restart_max(); } ast_manager& m() { return m_solver->get_manager(); } @@ -199,7 +217,7 @@ class parallel_tactic : public tactic { ast_translation tr(m, *new_m); solver* s = m_solver->translate(*new_m, m_params); solver_state* st = alloc(solver_state, new_m, s, m_params, m_type); - for (expr* c : m_cubes) st->m_cubes.push_back(tr(c)); + for (auto & c : m_cubes) st->m_cubes.push_back(c(tr)); for (expr* c : m_asserted_cubes) st->m_asserted_cubes.push_back(tr(c)); st->m_depth = m_depth; st->m_width = m_width; @@ -210,11 +228,11 @@ class parallel_tactic : public tactic { void set_type(task_type t) { m_type = t; } - expr_ref_vector const& cubes() const { SASSERT(m_type == conquer_task); return m_cubes; } + vector const& cubes() const { SASSERT(m_type == conquer_task); return m_cubes; } // remove up to n cubes from list of cubes. - expr_ref_vector split_cubes(unsigned n) { - expr_ref_vector result(m()); + vector split_cubes(unsigned n) { + vector result; while (n-- > 0 && !m_cubes.empty()) { result.push_back(m_cubes.back()); m_cubes.pop_back(); @@ -222,7 +240,7 @@ class parallel_tactic : public tactic { return result; } - void set_cubes(expr_ref_vector const& c) { + void set_cubes(vector& c) { m_cubes.reset(); m_cubes.append(c); } @@ -280,16 +298,18 @@ class parallel_tactic : public tactic { } void set_conquer_params() { + m_params.set_bool("gc.initial", true); m_params.set_bool("lookahead_simplify", false); m_params.set_uint("restart.max", m_restart_max); get_solver().updt_params(m_params); } void set_simplify_params(bool pb_simp, bool retain_blocked) { + parallel_params pp(m_params); m_params.set_bool("cardinality.solver", pb_simp); m_params.set_sym ("pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); if (m_params.get_uint("inprocess.max", UINT_MAX) == UINT_MAX) - m_params.set_uint("inprocess.max", 2); + m_params.set_uint("inprocess.max", pp.inprocess_max()); m_params.set_bool("lookahead_simplify", true); m_params.set_uint("restart.max", UINT_MAX); m_params.set_bool("retain_blocked_clauses", retain_blocked); @@ -350,7 +370,7 @@ private: IF_VERBOSE(0, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; if (status == l_true) verbose_stream() << ":status sat "; if (status == l_undef) verbose_stream() << ":status unknown "; - verbose_stream() << ":unsat " << m_num_unsat << " :branches " << m_branches << ")\n";); + verbose_stream() << ":unsat " << m_num_unsat << " :open-branches " << m_branches << ")\n";); } void report_sat(solver_state& s) { @@ -371,9 +391,11 @@ private: } void report_unsat(solver_state& s) { + { + std::lock_guard lock(m_mutex); + ++m_num_unsat; + } close_branch(s, l_false); - std::lock_guard lock(m_mutex); - ++m_num_unsat; } void report_undef(solver_state& s) { @@ -383,7 +405,11 @@ private: void cube_and_conquer(solver_state& s) { ast_manager& m = s.m(); - expr_ref_vector cubes(m), cube(m), hard_cubes(m); + // expr_ref_vector cube(m), hard_cubes(m); + vector cube, hard_cubes, cubes; + expr_ref_vector vars(m); + + add_branches(1); switch (s.type()) { case cube_task: goto cube; @@ -399,7 +425,11 @@ private: SASSERT(cube.size() <= 1); IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :split-cube " << cube.size() << ")\n";); if (!s.cubes().empty()) m_queue.add_task(s.clone()); - if (!cube.empty()) s.assert_cube(cube.get(0)); + if (!cube.empty()) { + s.assert_cube(cube.get(0).cube()); + vars.reset(); + vars.append(cube.get(0).vars()); + } s.inc_depth(1); // simplify @@ -414,7 +444,6 @@ private: cubes.reset(); s.set_cube_params(); while (true) { - expr_ref_vector vars(m); expr_ref_vector c = s.get_solver().cube(vars, UINT_MAX); // TBD tune this if (c.empty()) { report_undef(s); @@ -423,11 +452,11 @@ private: if (m.is_false(c.back())) { break; } - cubes.push_back(mk_and(c)); + cubes.push_back(cube_var(mk_and(c), vars)); + IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :cube " << cubes.size() << " :vars " << vars.size() << ")\n"); } IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :cubes " << cubes.size() << ")\n";); - IF_VERBOSE(12, verbose_stream() << "(tactic.parallel :cubes " << cubes << ")\n";); if (cubes.empty()) { report_unsat(s); @@ -435,7 +464,7 @@ private: } else { s.inc_width(cubes.size()); - add_branches(cubes.size()); + add_branches(cubes.size() - 1); s.set_cubes(cubes); s.set_type(conquer_task); goto conquer; @@ -451,9 +480,9 @@ private: s.set_conquer_params(); hard_cubes.reset(); - for (expr * c : cubes) { - switch (s.solve(c)) { - case l_undef: hard_cubes.push_back(c); break; + for (cube_var& cv : cubes) { + switch (s.solve(cv.cube())) { + case l_undef: hard_cubes.push_back(cv); break; case l_true: report_sat(s); break; case l_false: report_unsat(s); break; } @@ -580,6 +609,15 @@ public: result.push_back(g.get()); } + virtual void collect_param_descrs(param_descrs & r) { + r.insert("conquer_batch_size", CPK_UINT, "(default: 1000) batch size of cubes to conquer"); + } + + unsigned conquer_batch_size() const { + parallel_params pp(m_params); + return pp.conquer_batch_size(); + } + void cleanup() { m_queue.reset(); init(); @@ -593,14 +631,6 @@ public: m_params.copy(p); } - virtual void collect_param_descrs(param_descrs & r) { - r.insert("conquer_batch_size", CPK_UINT, "(default: 1000) batch size of cubes to conquer"); - } - - unsigned conquer_batch_size() const { - return m_params.get_uint("conquer_batch_size", 1000); - } - virtual void collect_statistics(statistics & st) const { st.copy(m_stats); st.update("par unsat", m_num_unsat); diff --git a/src/tactic/smtlogics/CMakeLists.txt b/src/tactic/smtlogics/CMakeLists.txt index 2741334b4..09b145316 100644 --- a/src/tactic/smtlogics/CMakeLists.txt +++ b/src/tactic/smtlogics/CMakeLists.txt @@ -26,6 +26,7 @@ z3_add_component(smtlogic_tactics smt_tactic PYG_FILES qfufbv_tactic_params.pyg + parallel_params.pyg TACTIC_HEADERS nra_tactic.h qfaufbv_tactic.h diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 0eb235791..25741c09e 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -29,7 +29,7 @@ Notes: #include "tactic/aig/aig_tactic.h" #include "sat/tactic/sat_tactic.h" #include "tactic/portfolio/parallel_tactic.h" -#include "tactic/portfolio/parallel_params.hpp" +#include "tactic/smtlogics/parallel_params.hpp" #include "ackermannization/ackermannize_bv_tactic.h" #define MEMLIMIT 300 From aef3de5fca6fd7ae07bb9223eaf71783ce257909 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Apr 2018 15:05:35 +0800 Subject: [PATCH 0767/1283] escape ascii above 127, issue #1571 Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index c9dbc78f8..b592b719a 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -213,6 +213,9 @@ std::string zstring::encode() const { else if (ch == '\\') { strm << "\\\\"; } + else if (ch >= 128) { + strm << "\\x" << std::hex << (unsigned)ch << std::dec; + } else { strm << (char)(ch); } From 28fbcd7687b2aba2712fa2c556a734f8269bf256 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Apr 2018 15:59:06 +0800 Subject: [PATCH 0768/1283] fix #1571 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index aca617daa..25868e944 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -446,7 +446,16 @@ namespace smt { expr* arg = atom->get_arg(i); literal l = compile_arg(arg); numeral c = m_util.get_coeff(atom, i); - args.push_back(std::make_pair(l, c)); + switch (ctx.get_assignment(l)) { + case l_true: + k -= c; + break; + case l_false: + break; + default: + args.push_back(std::make_pair(l, c)); + break; + } } if (m_util.is_at_most_k(atom) || m_util.is_le(atom)) { // turn W <= k into -W >= -k @@ -458,7 +467,7 @@ namespace smt { else { SASSERT(m_util.is_at_least_k(atom) || m_util.is_ge(atom) || m_util.is_eq(atom)); } - TRACE("pb", display(tout, *c);); + TRACE("pb", display(tout, *c, true);); //app_ref fml1(m), fml2(m); //fml1 = c->to_expr(ctx, m); c->unique(); From 3cfb32cd2d18acaca3b5cf5449c8c2c7c090aad9 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 12 Apr 2018 14:35:29 -0400 Subject: [PATCH 0769/1283] fix regex automata leaked memory --- src/smt/theory_str.cpp | 5 +++++ src/smt/theory_str.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0a3089c62..60b365d20 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -77,6 +77,9 @@ namespace smt { theory_str::~theory_str() { m_trail_stack.reset(); + for (eautomaton * aut : regex_automata) { + dealloc(aut); + } regex_automata.clear(); } @@ -10559,6 +10562,7 @@ namespace smt { if ( (current_assignment == l_true && aut.get_polarity()) || (current_assignment == l_false && !aut.get_polarity())) { aut_inter = m_mk_aut.mk_product(aut_inter, aut.get_automaton()); + m_automata.push_back(aut_inter); } else { // need to complement first expr_ref rc(u.re.mk_complement(aut.get_regex_term()), m); @@ -10567,6 +10571,7 @@ namespace smt { // TODO is there any way to build a complement automaton from an existing one? // this discards length information aut_inter = m_mk_aut.mk_product(aut_inter, aut_c); + m_automata.push_back(aut_inter); } used_intersect_constraints.push_back(aut); if (aut_inter->is_empty()) { diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index e9607585f..419084091 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -395,6 +395,7 @@ protected: obj_map > regex_in_var_reg_str_map; // regex automata + scoped_ptr_vector m_automata; ptr_vector regex_automata; obj_hashtable regex_terms; obj_map > regex_terms_by_string; // S --> [ (str.in.re S *) ] From f7e49501af7c87f25109de4430214349c7ec479a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Apr 2018 16:22:36 -0700 Subject: [PATCH 0770/1283] updates Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 156 +++++++++++++++++--------- src/sat/sat_config.cpp | 4 +- src/sat/sat_config.h | 3 +- src/sat/sat_solver/inc_sat_solver.cpp | 3 + 4 files changed, 109 insertions(+), 57 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 179773c34..9fc6bf7b3 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -56,9 +56,7 @@ struct pb2bv_rewriter::imp { rational m_k; vector m_coeffs; bool m_keep_cardinality_constraints; - bool m_keep_pb_constraints; - bool m_pb_num_system; - bool m_pb_totalizer; + symbol m_pb_solver; unsigned m_min_arity; template @@ -85,7 +83,7 @@ struct pb2bv_rewriter::imp { struct compare_coeffs { bool operator()(ca const& x, ca const& y) const { - return x.first < y.first; + return x.first > y.first; } }; @@ -126,11 +124,12 @@ struct pb2bv_rewriter::imp { if (i + 1 < sz && !m_coeffs[i+1].is_neg()) tout << "+ "; } switch (is_le) { - case l_true: tout << "<= "; break; + case l_true: tout << "<= "; break; case l_undef: tout << "= "; break; case l_false: tout << ">= "; break; } tout << k << "\n";); + if (k.is_zero()) { if (is_le != l_false) { return expr_ref(m.mk_not(::mk_or(m_args)), m); @@ -143,7 +142,7 @@ struct pb2bv_rewriter::imp { return expr_ref((is_le == l_false)?m.mk_true():m.mk_false(), m); } - if (m_pb_totalizer) { + if (m_pb_solver == "totalizer") { expr_ref result(m); switch (is_le) { case l_true: if (mk_le_tot(sz, args, k, result)) return result; else break; @@ -152,7 +151,7 @@ struct pb2bv_rewriter::imp { } } - if (m_pb_num_system) { + if (m_pb_solver == "sorting") { expr_ref result(m); switch (is_le) { case l_true: if (mk_le(sz, args, k, result)) return result; else break; @@ -161,6 +160,15 @@ struct pb2bv_rewriter::imp { } } + if (m_pb_solver == "segmented") { + expr_ref result(m); + switch (is_le) { + case l_true: return mk_seg_le(k); + case l_false: return mk_seg_ge(k); + case l_undef: break; + } + } + // fall back to divide and conquer encoding. SASSERT(k.is_pos()); expr_ref zero(m), bound(m); @@ -486,14 +494,82 @@ struct pb2bv_rewriter::imp { return true; } - expr_ref mk_and(expr_ref& a, expr_ref& b) { + /** + \brief Segment based encoding. + The PB terms are partitoned into segments, such that each segment contains arguments with the same cofficient. + The segments are sorted, such that the segment with highest coefficient is first. + Then for each segment create circuits based on sorting networks the arguments of the segment. + */ + + expr_ref mk_seg_ge(rational const& k) { + rational bound(-k); + for (unsigned i = 0; i < m_args.size(); ++i) { + m_args[i] = mk_not(m_args[i].get()); + bound += m_coeffs[i]; + } + return mk_seg_le(bound); + } + + expr_ref mk_seg_le(rational const& k) { + sort_args(); + unsigned sz = m_args.size(); + expr* const* args = m_args.c_ptr(); + + // Create sorted entries. + vector> outs; + vector coeffs; + for (unsigned i = 0, seg_size = 0; i < sz; i += seg_size) { + seg_size = segment_size(i); + ptr_vector out; + m_sort.sorting(seg_size, args + i, out); + out.push_back(m.mk_false()); + outs.push_back(out); + coeffs.push_back(m_coeffs[i]); + } + return mk_seg_le_rec(outs, coeffs, 0, k); + } + + expr_ref mk_seg_le_rec(vector> const& outs, vector const& coeffs, unsigned i, rational const& k) { + rational const& c = coeffs[i]; + ptr_vector const& out = outs[i]; + if (k.is_neg()) { + return expr_ref(m.mk_false(), m); + } + if (i == outs.size()) { + return expr_ref(m.mk_true(), m); + } + if (i + 1 == outs.size() && k >= rational(out.size()-1)*c) { + return expr_ref(m.mk_true(), m); + } + expr_ref_vector fmls(m); + fmls.push_back(m.mk_implies(m.mk_not(out[0]), mk_seg_le_rec(outs, coeffs, i + 1, k))); + rational k1; + for (unsigned j = 0; j + 1 < out.size(); ++j) { + k1 = k - rational(j+1)*c; + if (k1.is_neg()) { + fmls.push_back(m.mk_not(out[j])); + break; + } + fmls.push_back(m.mk_implies(m.mk_and(out[j], m.mk_not(out[j+1])), mk_seg_le_rec(outs, coeffs, i + 1, k1))); + } + return ::mk_and(fmls); + } + + // The number of arguments with the same coefficient. + unsigned segment_size(unsigned start) const { + unsigned i = start; + while (i < m_args.size() && m_coeffs[i] == m_coeffs[start]) ++i; + return i - start; + } + + expr_ref mk_and(expr_ref& a, expr_ref& b) { if (m.is_true(a)) return b; if (m.is_true(b)) return a; if (m.is_false(a)) return a; if (m.is_false(b)) return b; return expr_ref(m.mk_and(a, b), m); } - + expr_ref mk_or(expr_ref& a, expr_ref& b) { if (m.is_true(a)) return a; if (m.is_true(b)) return b; @@ -607,12 +683,12 @@ struct pb2bv_rewriter::imp { m_trail(m), m_args(m), m_keep_cardinality_constraints(false), - m_keep_pb_constraints(false), - m_pb_num_system(false), - m_pb_totalizer(false), + m_pb_solver(symbol("solver")), m_min_arity(9) {} + void set_pb_solver(symbol const& s) { m_pb_solver = s; } + bool mk_app(bool full, func_decl * f, unsigned sz, expr * const* args, expr_ref & result) { if (f->get_family_id() == pb.get_family_id() && mk_pb(full, f, sz, args, result)) { // skip @@ -756,13 +832,13 @@ struct pb2bv_rewriter::imp { result = m_sort.ge(full, pb.get_k(f).get_unsigned(), sz, args); ++m_imp.m_compile_card; } - else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) { + else if (pb.is_eq(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_pb_solver == "solver") { return false; } - else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) { + else if (pb.is_le(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_pb_solver == "solver") { return false; } - else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_keep_pb_constraints) { + else if (pb.is_ge(f) && pb.get_k(f).is_unsigned() && has_small_coefficients(f) && m_pb_solver == "solver") { return false; } else { @@ -811,17 +887,6 @@ struct pb2bv_rewriter::imp { m_keep_cardinality_constraints = f; } - void keep_pb_constraints(bool f) { - m_keep_pb_constraints = f; - } - - void pb_num_system(bool f) { - m_pb_num_system = f; - } - - void pb_totalizer(bool f) { - m_pb_totalizer = f; - } void set_at_most1(sorting_network_encoding enc) { m_sort.cfg().m_encoding = enc; } }; @@ -836,9 +901,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 keep_pb_constraints(bool f) { m_r.keep_pb_constraints(f); } - void pb_num_system(bool f) { m_r.pb_num_system(f); } - void pb_totalizer(bool f) { m_r.pb_totalizer(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); } }; @@ -850,9 +913,7 @@ struct pb2bv_rewriter::imp { rewriter_tpl(m, false, m_cfg), m_cfg(i, m) {} void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); } - void keep_pb_constraints(bool f) { m_cfg.keep_pb_constraints(f); } - void pb_num_system(bool f) { m_cfg.pb_num_system(f); } - void pb_totalizer(bool f) { m_cfg.pb_totalizer(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 rewrite(expr* e, expr_ref& r, proof_ref& p) { expr_ref ee(e, m()); @@ -875,26 +936,15 @@ struct pb2bv_rewriter::imp { gparams::get_module("sat").get_bool("cardinality.solver", false); } - bool keep_pb() const { + symbol pb_solver() const { params_ref const& p = m_params; - return - p.get_bool("keep_pb_constraints", false) || - p.get_bool("sat.pb.solver", false) || - p.get_bool("pb.solver", false) || - gparams::get_module("sat").get_sym("pb.solver", symbol()) == symbol("solver") ; + symbol s = p.get_sym("sat.pb.solver", symbol()); + if (s != symbol()) return s; + s = p.get_sym("pb.solver", symbol()); + if (s != symbol()) return s; + return gparams::get_module("sat").get_sym("pb.solver", symbol("solver")); } - bool pb_num_system() const { - return m_params.get_bool("pb_num_system", false) || - gparams::get_module("sat").get_sym("pb.solver", symbol()) == symbol("sorting"); - } - - bool pb_totalizer() const { - return m_params.get_bool("pb_totalizer", false) || - gparams::get_module("sat").get_sym("pb.solver", symbol()) == symbol("totalizer"); - } - - sorting_network_encoding atmost1_encoding() const { symbol enc = m_params.get_sym("atmost1_encoding", symbol()); if (enc == symbol()) { @@ -920,16 +970,12 @@ struct pb2bv_rewriter::imp { void updt_params(params_ref const & p) { m_params.append(p); m_rw.keep_cardinality_constraints(keep_cardinality()); - m_rw.keep_pb_constraints(keep_pb()); - m_rw.pb_num_system(pb_num_system()); - m_rw.pb_totalizer(pb_totalizer()); + m_rw.set_pb_solver(pb_solver()); m_rw.set_at_most1(atmost1_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_pb_constraints", CPK_BOOL, "(default: true) retain pb constraints (don't bit-blast them) and use built-in pb solver"); - r.insert("pb_num_system", CPK_BOOL, "(default: false) use pb number system encoding"); - r.insert("pb_totalizer", CPK_BOOL, "(default: false) use pb totalizer encoding"); + r.insert("pb.solver", CPK_SYMBOL, "(default: solver) retain pb constraints (don't bit-blast them) and use built-in pb solver"); } unsigned get_num_steps() const { return m_rw.get_num_steps(); } diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 2439be36f..812e65abf 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -178,8 +178,10 @@ namespace sat { m_pb_solver = PB_TOTALIZER; else if (s == symbol("solver")) m_pb_solver = PB_SOLVER; + else if (s == symbol("segmented")) + m_pb_solver = PB_SEGMENTED; else - throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting"); + throw sat_param_exception("invalid PB solver: solver, totalizer, circuit, sorting, segmented"); m_card_solver = p.cardinality_solver(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index c70d52a90..6a704ab44 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -54,7 +54,8 @@ namespace sat { PB_SOLVER, PB_CIRCUIT, PB_SORTING, - PB_TOTALIZER + PB_TOTALIZER, + PB_SEGMENTED }; enum reward_t { diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 4d7325ecb..a7499590b 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -281,9 +281,12 @@ public: m_params.append(p); sat_params p1(p); m_params.set_bool("keep_cardinality_constraints", p1.cardinality_solver()); + m_params.set_sym("pb.solver", p1.pb_solver()); + m_params.set_bool("keep_pb_constraints", m_solver.get_config().m_pb_solver == sat::PB_SOLVER); m_params.set_bool("pb_num_system", m_solver.get_config().m_pb_solver == sat::PB_SORTING); m_params.set_bool("pb_totalizer", m_solver.get_config().m_pb_solver == sat::PB_TOTALIZER); + m_params.set_bool("xor_solver", p1.xor_solver()); m_solver.updt_params(m_params); m_solver.set_incremental(is_incremental() && !override_incremental()); From a3e651156af910705a7c8b70e10cfc960e533a54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Apr 2018 16:23:35 -0700 Subject: [PATCH 0771/1283] parallel params Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/parallel_params.pyg | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/tactic/smtlogics/parallel_params.pyg diff --git a/src/tactic/smtlogics/parallel_params.pyg b/src/tactic/smtlogics/parallel_params.pyg new file mode 100644 index 000000000..70c4ccdd0 --- /dev/null +++ b/src/tactic/smtlogics/parallel_params.pyg @@ -0,0 +1,10 @@ +def_module_params('parallel', + description='parameters for parallel solver', + class_name='parallel_params', + export=True, + params=( + ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), + ('conquer_batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), + ('inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), + ('restart.max', UINT, 100, 'maximal number of restarts during conquer phase'), + )) From c5a30285a8100dbd1f0569a8d887f78eeada713e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Apr 2018 17:03:49 -0700 Subject: [PATCH 0772/1283] add filter cubes parameter Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/parallel_tactic.cpp | 8 +++++++- src/tactic/smtlogics/parallel_params.pyg | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 999dbc2e0..bc28a7b37 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -443,8 +443,9 @@ private: // extract cubes. cubes.reset(); s.set_cube_params(); + unsigned cutoff = UINT_MAX; while (true) { - expr_ref_vector c = s.get_solver().cube(vars, UINT_MAX); // TBD tune this + expr_ref_vector c = s.get_solver().cube(vars, cutoff); if (c.empty()) { report_undef(s); return; @@ -618,6 +619,11 @@ public: return pp.conquer_batch_size(); } + bool filter_cubes() const { + parallel_params pp(m_params); + return pp.filter_cubes(); + } + void cleanup() { m_queue.reset(); init(); diff --git a/src/tactic/smtlogics/parallel_params.pyg b/src/tactic/smtlogics/parallel_params.pyg index 70c4ccdd0..58da305f4 100644 --- a/src/tactic/smtlogics/parallel_params.pyg +++ b/src/tactic/smtlogics/parallel_params.pyg @@ -7,4 +7,5 @@ def_module_params('parallel', ('conquer_batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), ('inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), ('restart.max', UINT, 100, 'maximal number of restarts during conquer phase'), + ('filter_cubes', BOOL, False, 'filter cubes using a short running check'), )) From d58a9d25284b52af7ca5e0d304504c5fcca52e85 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Apr 2018 22:04:14 -0700 Subject: [PATCH 0773/1283] fix accounting for branches Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/parallel_tactic.cpp | 142 ++++++++++++++++++++++- 1 file changed, 139 insertions(+), 3 deletions(-) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index bc28a7b37..9b9e74629 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -208,6 +208,8 @@ class parallel_tactic : public tactic { solver& get_solver() { return *m_solver; } + solver* copy_solver() { return m_solver->translate(m_solver->get_manager(), m_params); } + solver const& get_solver() const { return *m_solver; } solver_state* clone() { @@ -405,12 +407,9 @@ private: void cube_and_conquer(solver_state& s) { ast_manager& m = s.m(); - // expr_ref_vector cube(m), hard_cubes(m); vector cube, hard_cubes, cubes; expr_ref_vector vars(m); - add_branches(1); - switch (s.type()) { case cube_task: goto cube; case conquer_task: goto conquer; @@ -497,6 +496,142 @@ private: goto cube; } + void cube_and_conquer2(solver_state& s) { + ast_manager& m = s.m(); + vector cube, hard_cubes, cubes; + expr_ref_vector vars(m); + SASSERT(s.type() == cube_task); + + // extract up to one cube and add it. + cube.reset(); + cube.append(s.split_cubes(1)); + SASSERT(cube.size() <= 1); + IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :split-cube " << cube.size() << ")\n";); + if (!s.cubes().empty()) m_queue.add_task(s.clone()); + if (!cube.empty()) { + s.assert_cube(cube.get(0).cube()); + vars.reset(); + vars.append(cube.get(0).vars()); + } + s.inc_depth(1); + + // simplify + switch (s.simplify()) { + case l_undef: break; + case l_true: report_sat(s); return; + case l_false: report_unsat(s); return; + } + if (canceled(s)) return; + + // extract cubes. + cubes.reset(); + s.set_cube_params(); + solver_ref conquer = s.copy_solver(); + unsigned cutoff = UINT_MAX; + while (true) { + expr_ref_vector c = s.get_solver().cube(vars, cutoff); + if (c.empty()) { + report_undef(s); + return; + } + if (m.is_false(c.back())) { + break; + } + lbool is_sat = conquer->check_sat(c); + switch (is_sat) { + case l_false: { + // TBD: minimize core instead. + expr_ref_vector core(m); + conquer->get_unsat_core(core); + obj_hashtable hcore; + for (expr* e : core) hcore.insert(e); + for (unsigned i = c.size(); i-- > 0; ) { + if (hcore.contains(c[i].get())) { + cutoff = i; + break; + } + } + break; + } + case l_true: + report_sat(s); + return; + case l_undef: + IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :cube " << cubes.size() << " :vars " << vars.size() << ")\n"); + cubes.push_back(cube_var(mk_and(c), vars)); + cutoff = UINT_MAX; + break; + } + // TBD flush cube task early + } + + IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :cubes " << cubes.size() << ")\n";); + + if (cubes.empty()) { + report_unsat(s); + return; + } + else { + s.inc_width(cubes.size()); + add_branches(cubes.size() - 1); + NOT_IMPLEMENTED_YET(); + // TBD add as a cube task. + } + } + + expr_ref_vector baktrack(expr_ref_vector const& c) { + + } + +#if 0 + public BoolExpr[] Backtrack(Statistics stats, BoolExpr[] _asms) + { + int count = _asms.Count(); + stats.Stopwatch.Start(); + var asms = new List(_asms); + _Backtrack(stats, asms); + stats.AddBacktrackStats((uint)(count - asms.Count()), stats.Stopwatch.Elapsed()); + return asms.ToArray(); + } + + public void _Backtrack(Statistics stats, List asms) + { + HashSet core = new HashSet(Solver.UnsatCore); + while (asms.Count > 0 && !core.Contains(asms.Last())) + { + asms.RemoveAt(asms.Count - 1); + } + stats.Cores++; + Solver.Add(!Context.MkAnd(core)); + if (asms.Count > 0) + { + BoolExpr last = asms.Last(); + BoolExpr not_last = last.IsNot ? (BoolExpr)last.Args[0] : Context.MkNot(last); + asms.RemoveAt(asms.Count - 1); + asms.Add(not_last); + Status status = CheckSat(null, asms); + asms.RemoveAt(asms.Count - 1); + if (status != Status.UNSATISFIABLE) + { + asms.Add(last); + return; + } + core = new HashSet(Solver.UnsatCore); + if (core.Contains(not_last)) + { + stats.Cores++; + Solver.Add(!Context.MkAnd(core)); + status = CheckSat(null, asms); + } + if (status == Status.UNSATISFIABLE) + { + _Backtrack(stats, asms); + } + } + } + +#endif + bool canceled(solver_state& s) { if (s.canceled()) { m_has_undef = true; @@ -509,6 +644,7 @@ private: void run_solver() { try { + add_branches(1); while (solver_state* st = m_queue.get_task()) { cube_and_conquer(*st); collect_statistics(*st); From 6078d24016e274cbf5b05c2b0e74f46b2000c373 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Apr 2018 23:04:20 -0700 Subject: [PATCH 0774/1283] adding orphaned function declaration #1574 --- src/api/c++/z3++.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 3a788da6d..0ddebf75c 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2680,6 +2680,9 @@ namespace z3 { inline func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range) { return range.ctx().function(name, d1, d2, d3, d4, d5, range); } + inline func_decl function(char const& name, sort_vector const& domain, sort const& range) { + return range.ctx().function(name, domain, range); + } inline expr select(expr const & a, expr const & i) { check_context(a, i); From 56827d572519524b940785c4e377e93297b768d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Apr 2018 23:10:21 -0700 Subject: [PATCH 0775/1283] adding the orphaned shorthand #1574 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 0ddebf75c..b81927474 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2680,9 +2680,12 @@ namespace z3 { inline func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range) { return range.ctx().function(name, d1, d2, d3, d4, d5, range); } - inline func_decl function(char const& name, sort_vector const& domain, sort const& range) { + inline func_decl function(char const* name, sort_vector const& domain, sort const& range) { return range.ctx().function(name, domain, range); } + inline func_decl function(std::string const& name, sort_vector const& domain, sort const& range) { + return range.ctx().function(name.c_str(), domain, range); + } inline expr select(expr const & a, expr const & i) { check_context(a, i); From d939c05e72e445aaa5005026fede0d97eca67a86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Apr 2018 08:27:40 -0700 Subject: [PATCH 0776/1283] fix build warnings Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_util.cpp | 2 +- src/smt/theory_str.cpp | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 7cc9d4b03..2dbf844a8 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -622,7 +622,7 @@ namespace datalog { } bool string_to_uint64(const char * s, uint64_t & res) { -#if _WINDOWS +#if 1 int converted = sscanf_s(s, "%I64u", &res); #else int converted = sscanf(s, "%llu", &res); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 60b365d20..0f9d42b3d 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -10130,10 +10130,11 @@ namespace smt { // increment LengthAttemptCount regex_inc_counter(regex_length_attempt_count, re); - { - unsigned v = regex_get_counter(regex_length_attempt_count, re); - TRACE("str", tout << "length attempt count for " << mk_pp(re, m) << " is " << v << std::endl;); - } + TRACE("str", + { + unsigned v = regex_get_counter(regex_length_attempt_count, re); + tout << "length attempt count for " << mk_pp(re, m) << " is " << v << std::endl; + }); continue; } @@ -10541,11 +10542,12 @@ namespace smt { continue; } - { - unsigned v = regex_get_counter(regex_length_attempt_count, aut.get_regex_term()); - TRACE("str", tout << "length attempt count of " << mk_pp(aut.get_regex_term(), m) << " is " << v - << ", threshold is " << m_params.m_RegexAutomata_LengthAttemptThreshold << std::endl;); - } + TRACE("str", + { + unsigned v = regex_get_counter(regex_length_attempt_count, aut.get_regex_term()); + tout << "length attempt count of " << mk_pp(aut.get_regex_term(), m) << " is " << v + << ", threshold is " << m_params.m_RegexAutomata_LengthAttemptThreshold << std::endl; + }); if (regex_get_counter(regex_length_attempt_count, aut.get_regex_term()) >= m_params.m_RegexAutomata_LengthAttemptThreshold) { unsigned intersectionDifficulty = estimate_automata_intersection_difficulty(aut_inter, aut.get_automaton()); From 098bce0f462e4ee7b90acadf997465aacb52eb86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Apr 2018 08:44:20 -0700 Subject: [PATCH 0777/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_util.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 2dbf844a8..e8a1c5139 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -622,10 +622,10 @@ namespace datalog { } bool string_to_uint64(const char * s, uint64_t & res) { -#if 1 +#if _WINDOWS int converted = sscanf_s(s, "%I64u", &res); #else - int converted = sscanf(s, "%llu", &res); + int converted = sscanf(s, "%I64u", &res); #endif if(converted==0) { return false; From 252fb4af6e6689adf9756a0ab31033d3cc9e6550 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Apr 2018 15:34:33 -0700 Subject: [PATCH 0778/1283] add backtracking conquer Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 1 + src/sat/sat_config.h | 2 + src/sat/sat_params.pyg | 5 +- src/sat/sat_solver.cpp | 2 +- src/tactic/portfolio/parallel_tactic.cpp | 331 +++++++++++++---------- src/tactic/smtlogics/parallel_params.pyg | 4 +- 6 files changed, 192 insertions(+), 153 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 812e65abf..2597967df 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -119,6 +119,7 @@ namespace sat { m_simplify_mult2 = _p.get_double("simplify_mult2", 1.5); m_simplify_max = _p.get_uint("simplify_max", 500000); // -------------------------------- + m_simplify_delay = p.simplify_delay(); s = p.gc(); if (s == symbol("dyn_psm")) diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 6a704ab44..20d966dd1 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -116,6 +116,7 @@ namespace sat { unsigned m_simplify_mult1; double m_simplify_mult2; unsigned m_simplify_max; + unsigned m_simplify_delay; unsigned m_variable_decay; @@ -126,6 +127,7 @@ namespace sat { unsigned m_gc_k; bool m_gc_burst; + bool m_minimize_lemmas; bool m_dyn_sub_res; bool m_core_minimize; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 56a5b6e6c..320ddaf9e 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -24,6 +24,7 @@ def_module_params('sat', ('gc.small_lbd', UINT, 3, 'learned clauses with small LBD are never deleted (only used in dyn_psm)'), ('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'), ('gc.burst', BOOL, True, 'perform eager garbage collection during initialization'), + ('simplify.delay', UINT, 0, 'set initial delay of simplification by a conflict count'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), ('core.minimize', BOOL, False, 'minimize computed core'), @@ -42,9 +43,9 @@ def_module_params('sat', ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), ('unit_walk', BOOL, False, 'use unit-walk search instead of CDCL'), ('unit_walk_threads', UINT, 0, 'number of unit-walk search threads to find satisfiable solution'), - ('lookahead.cube.cutoff', SYMBOL, 'adaptive_freevars', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), + ('lookahead.cube.cutoff', SYMBOL, 'depth', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), ('lookahead.cube.fraction', DOUBLE, 0.4, 'adaptive fraction to create lookahead cubes. Used when lookahead.cube.cutoff is adaptive_freevars or adaptive_psat'), - ('lookahead.cube.depth', UINT, 10, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'), + ('lookahead.cube.depth', UINT, 1, 'cut-off depth to create cubes. Used when lookahead.cube.cutoff is depth.'), ('lookahead.cube.freevars', DOUBLE, 0.8, 'cube free fariable fraction. Used when lookahead.cube.cutoff is freevars'), ('lookahead.cube.psat.var_exp', DOUBLE, 1, 'free variable exponent for PSAT cutoff'), ('lookahead.cube.psat.clause_base', DOUBLE, 2, 'clause base for PSAT cutoff'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index da11ed3a1..fb992d57e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1503,7 +1503,7 @@ namespace sat { m_restarts = 0; m_simplifications = 0; m_conflicts_since_init = 0; - m_next_simplify = 0; + m_next_simplify = m_config.m_simplify_delay; m_min_d_tk = 1.0; m_search_lvl = 0; m_conflicts_since_gc = 0; diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 9b9e74629..988ab2ec4 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -107,6 +107,11 @@ class parallel_tactic : public tactic { } } + bool is_idle() { + std::lock_guard lock(m_mutex); + return m_tasks.empty() && m_num_waiters > 0; + } + solver_state* get_task() { while (!m_shutdown) { inc_wait(); @@ -153,19 +158,21 @@ class parallel_tactic : public tactic { class cube_var { expr_ref_vector m_vars; - expr_ref m_cube; + expr_ref_vector m_cube; public: - cube_var(expr* c, expr_ref_vector& vs): - m_vars(vs), m_cube(c, vs.get_manager()) {} + cube_var(expr_ref_vector& c, expr_ref_vector& vs): + m_vars(vs), m_cube(c) {} cube_var operator()(ast_translation& tr) { expr_ref_vector vars(tr.to()); + expr_ref_vector cube(tr.to()); for (expr* v : m_vars) vars.push_back(tr(v)); - return cube_var(tr(m_cube.get()), vars); + for (expr* c : m_cube) cube.push_back(tr(c)); + return cube_var(cube, vars); } - expr* cube() const { return m_cube; } - expr_ref_vector const& vars() { return m_vars; } + expr_ref_vector const& cube() const { return m_cube; } + expr_ref_vector const& vars() const { return m_vars; } }; class solver_state { @@ -179,17 +186,6 @@ class parallel_tactic : public tactic { double m_width; // estimate of fraction of problem handled by state unsigned m_restart_max; // saved configuration value - expr_ref_vector cube_literals(expr* cube) { - expr_ref_vector literals(m()); - if (m().is_and(cube)) { - literals.append(to_app(cube)->get_num_args(), to_app(cube)->get_args()); - } - else { - literals.push_back(cube); - } - return literals; - } - public: solver_state(ast_manager* m, solver* s, params_ref const& p, task_type t): m_type(t), @@ -212,12 +208,12 @@ class parallel_tactic : public tactic { solver const& get_solver() const { return *m_solver; } - solver_state* clone() { + solver_state* clone(solver* s0 = nullptr) { SASSERT(!m_cubes.empty()); ast_manager& m = m_solver->get_manager(); ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); ast_translation tr(m, *new_m); - solver* s = m_solver->translate(*new_m, m_params); + solver* s = (s0 ? s0 : m_solver.get())->translate(*new_m, m_params); solver_state* st = alloc(solver_state, new_m, s, m_params, m_type); for (auto & c : m_cubes) st->m_cubes.push_back(c(tr)); for (expr* c : m_asserted_cubes) st->m_asserted_cubes.push_back(tr(c)); @@ -284,15 +280,14 @@ class parallel_tactic : public tactic { return r; } - void assert_cube(expr* cube) { + void assert_cube(expr_ref_vector const& cube) { get_solver().assert_expr(cube); - m_asserted_cubes.append(cube_literals(cube)); + m_asserted_cubes.append(cube); } - lbool solve(expr* cube) { + lbool solve(expr_ref_vector const& cube) { set_conquer_params(); - expr_ref_vector literals = cube_literals(cube); - return get_solver().check_sat(literals); + return get_solver().check_sat(cube); } void set_cube_params() { @@ -300,22 +295,33 @@ class parallel_tactic : public tactic { } void set_conquer_params() { - m_params.set_bool("gc.initial", true); - m_params.set_bool("lookahead_simplify", false); - m_params.set_uint("restart.max", m_restart_max); - get_solver().updt_params(m_params); + set_conquer_params(get_solver()); + } + + void set_conquer_params(solver& s) { + params_ref p; + p.copy(m_params); + p.set_bool("gc.burst", true); // apply eager gc + p.set_uint("simplify.delay", 1000); // delay simplification by 1000 conflicts + p.set_bool("lookahead_simplify", false); + p.set_uint("restart.max", m_restart_max); + p.set_uint("inprocess.max", UINT_MAX); // base bounds on restart.max + s.updt_params(p); } void set_simplify_params(bool pb_simp, bool retain_blocked) { parallel_params pp(m_params); - m_params.set_bool("cardinality.solver", pb_simp); - m_params.set_sym ("pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); - if (m_params.get_uint("inprocess.max", UINT_MAX) == UINT_MAX) - m_params.set_uint("inprocess.max", pp.inprocess_max()); - m_params.set_bool("lookahead_simplify", true); - m_params.set_uint("restart.max", UINT_MAX); - m_params.set_bool("retain_blocked_clauses", retain_blocked); - get_solver().updt_params(m_params); + params_ref p; + p.copy(m_params); + + p.set_bool("cardinality.solver", pb_simp); + p.set_sym ("pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); + if (p.get_uint("inprocess.max", UINT_MAX) == UINT_MAX) + p.set_uint("inprocess.max", pp.inprocess_max()); + p.set_bool("lookahead_simplify", true); + p.set_uint("restart.max", UINT_MAX); + p.set_bool("retain_blocked_clauses", retain_blocked); + get_solver().updt_params(p); } bool canceled() { @@ -340,6 +346,8 @@ private: std::mutex m_mutex; double m_progress; unsigned m_branches; + unsigned m_backtrack_frequency; + unsigned m_conquer_threshold; bool m_has_undef; bool m_allsat; unsigned m_num_unsat; @@ -351,15 +359,32 @@ private: m_progress = 0; m_has_undef = false; m_allsat = false; - m_num_unsat = 0; - m_branches = 0; + m_branches = 0; + m_num_unsat = 0; + m_backtrack_frequency = 10; + m_conquer_threshold = 10; m_exn_code = 0; m_params.set_bool("override_incremental", true); } + void log_branches(lbool status) { + IF_VERBOSE(0, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; + if (status == l_true) verbose_stream() << ":status sat "; + if (status == l_undef) verbose_stream() << ":status unknown "; + verbose_stream() << ":closed " << m_num_unsat << " :open " << m_branches << ")\n";); + } + void add_branches(unsigned b) { + { + std::lock_guard lock(m_mutex); + m_branches += b; + } + log_branches(l_false); + } + + void dec_branch() { std::lock_guard lock(m_mutex); - m_branches += b; + --m_branches; } void close_branch(solver_state& s, lbool status) { @@ -369,10 +394,7 @@ private: m_progress += f; --m_branches; } - IF_VERBOSE(0, verbose_stream() << "(tactic.parallel :progress " << m_progress << "% "; - if (status == l_true) verbose_stream() << ":status sat "; - if (status == l_undef) verbose_stream() << ":status unknown "; - verbose_stream() << ":unsat " << m_num_unsat << " :open-branches " << m_branches << ")\n";); + log_branches(status); } void report_sat(solver_state& s) { @@ -392,11 +414,13 @@ private: } } + void inc_unsat() { + std::lock_guard lock(m_mutex); + ++m_num_unsat; + } + void report_unsat(solver_state& s) { - { - std::lock_guard lock(m_mutex); - ++m_num_unsat; - } + inc_unsat(); close_branch(s, l_false); } @@ -405,7 +429,7 @@ private: close_branch(s, l_undef); } - void cube_and_conquer(solver_state& s) { + void cube_and_conquer1(solver_state& s) { ast_manager& m = s.m(); vector cube, hard_cubes, cubes; expr_ref_vector vars(m); @@ -452,7 +476,7 @@ private: if (m.is_false(c.back())) { break; } - cubes.push_back(cube_var(mk_and(c), vars)); + cubes.push_back(cube_var(c, vars)); IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :cube " << cubes.size() << " :vars " << vars.size() << ")\n"); } @@ -500,8 +524,9 @@ private: ast_manager& m = s.m(); vector cube, hard_cubes, cubes; expr_ref_vector vars(m); - SASSERT(s.type() == cube_task); + cube_again: + SASSERT(s.type() == cube_task); // extract up to one cube and add it. cube.reset(); cube.append(s.split_cubes(1)); @@ -515,7 +540,9 @@ private: } s.inc_depth(1); + simplify_again: // simplify + if (canceled(s)) return; switch (s.simplify()) { case l_undef: break; case l_true: report_sat(s); return; @@ -526,112 +553,124 @@ private: // extract cubes. cubes.reset(); s.set_cube_params(); - solver_ref conquer = s.copy_solver(); + solver_ref conquer; + unsigned cutoff = UINT_MAX; - while (true) { + bool first = true; + unsigned num_backtracks = 0, width = 0; + while (cutoff > 0 && !canceled(s)) { expr_ref_vector c = s.get_solver().cube(vars, cutoff); if (c.empty()) { - report_undef(s); - return; + goto simplify_again; } if (m.is_false(c.back())) { break; } - lbool is_sat = conquer->check_sat(c); - switch (is_sat) { - case l_false: { - // TBD: minimize core instead. - expr_ref_vector core(m); - conquer->get_unsat_core(core); - obj_hashtable hcore; - for (expr* e : core) hcore.insert(e); - for (unsigned i = c.size(); i-- > 0; ) { - if (hcore.contains(c[i].get())) { - cutoff = i; - break; - } - } - break; + lbool is_sat = l_undef; + if (width >= m_conquer_threshold && !conquer) { + conquer = s.copy_solver(); + s.set_conquer_params(*conquer.get()); } + if (conquer) { + is_sat = conquer->check_sat(c); + } + switch (is_sat) { + case l_false: + cutoff = c.size(); + backtrack(*conquer.get(), c, (num_backtracks++) % m_backtrack_frequency == 0); + if (cutoff != c.size()) { + IF_VERBOSE(0, verbose_stream() << "(tactic.parallel :backtrack " << cutoff << " -> " << c.size() << ")\n"); + cutoff = c.size(); + } + inc_unsat(); + log_branches(l_false); + break; + case l_true: report_sat(s); + if (conquer) { + collect_statistics(*conquer.get()); + } return; + case l_undef: - IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :cube " << cubes.size() << " :vars " << vars.size() << ")\n"); - cubes.push_back(cube_var(mk_and(c), vars)); + ++width; + IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :cube " << c.size() << " :vars " << vars.size() << ")\n"); + cubes.push_back(cube_var(c, vars)); cutoff = UINT_MAX; break; - } - // TBD flush cube task early - } - - IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :cubes " << cubes.size() << ")\n";); - if (cubes.empty()) { + } + if (cubes.size() >= conquer_batch_size() || (!cubes.empty() && m_queue.is_idle())) { + spawn_cubes(s, std::max(2u, width), cubes); + first = false; + cubes.reset(); + } + } + + if (conquer) { + collect_statistics(*conquer.get()); + } + + if (cubes.empty() && first) { report_unsat(s); + } + else if (cubes.empty()) { + dec_branch(); return; } else { - s.inc_width(cubes.size()); - add_branches(cubes.size() - 1); - NOT_IMPLEMENTED_YET(); - // TBD add as a cube task. + s.inc_width(width); + add_branches(cubes.size()-1); + s.set_cubes(cubes); + goto cube_again; + } + } + + void spawn_cubes(solver_state& s, unsigned width, vector& cubes) { + if (cubes.empty()) return; + add_branches(cubes.size()); + s.set_cubes(cubes); + solver_state* s1 = s.clone(); + s1->inc_width(width); + m_queue.add_task(s1); + } + + /* + * \brief backtrack from unsatisfiable core + */ + void backtrack(solver& s, expr_ref_vector& asms, bool full) { + ast_manager& m = s.get_manager(); + expr_ref_vector core(m); + obj_hashtable hcore; + s.get_unsat_core(core); + while (!asms.empty() && !core.contains(asms.back())) asms.pop_back(); + if (!full) return; + + //s.assert_expr(m.mk_not(mk_and(core))); + if (!asms.empty()) { + expr* last = asms.back(); + expr_ref not_last(mk_not(m, last), m); + asms.pop_back(); + asms.push_back(not_last); + lbool r = s.check_sat(asms); + asms.pop_back(); + if (r != l_false) { + asms.push_back(last); + return; + } + core.reset(); + s.get_unsat_core(core); + if (core.contains(not_last)) { + //s.assert_expr(m.mk_not(mk_and(core))); + r = s.check_sat(asms); + } + if (r == l_false) { + backtrack(s, asms, full); + } } } - expr_ref_vector baktrack(expr_ref_vector const& c) { - - } - -#if 0 - public BoolExpr[] Backtrack(Statistics stats, BoolExpr[] _asms) - { - int count = _asms.Count(); - stats.Stopwatch.Start(); - var asms = new List(_asms); - _Backtrack(stats, asms); - stats.AddBacktrackStats((uint)(count - asms.Count()), stats.Stopwatch.Elapsed()); - return asms.ToArray(); - } - - public void _Backtrack(Statistics stats, List asms) - { - HashSet core = new HashSet(Solver.UnsatCore); - while (asms.Count > 0 && !core.Contains(asms.Last())) - { - asms.RemoveAt(asms.Count - 1); - } - stats.Cores++; - Solver.Add(!Context.MkAnd(core)); - if (asms.Count > 0) - { - BoolExpr last = asms.Last(); - BoolExpr not_last = last.IsNot ? (BoolExpr)last.Args[0] : Context.MkNot(last); - asms.RemoveAt(asms.Count - 1); - asms.Add(not_last); - Status status = CheckSat(null, asms); - asms.RemoveAt(asms.Count - 1); - if (status != Status.UNSATISFIABLE) - { - asms.Add(last); - return; - } - core = new HashSet(Solver.UnsatCore); - if (core.Contains(not_last)) - { - stats.Cores++; - Solver.Add(!Context.MkAnd(core)); - status = CheckSat(null, asms); - } - if (status == Status.UNSATISFIABLE) - { - _Backtrack(stats, asms); - } - } - } - -#endif - bool canceled(solver_state& s) { if (s.canceled()) { m_has_undef = true; @@ -644,9 +683,8 @@ private: void run_solver() { try { - add_branches(1); while (solver_state* st = m_queue.get_task()) { - cube_and_conquer(*st); + cube_and_conquer2(*st); collect_statistics(*st); m_queue.task_done(st); if (st->m().canceled()) m_queue.shutdown(); @@ -669,11 +707,16 @@ private: } void collect_statistics(solver_state& s) { + collect_statistics(s.get_solver()); + } + + void collect_statistics(solver& s) { std::lock_guard lock(m_mutex); - s.get_solver().collect_statistics(m_stats); + s.collect_statistics(m_stats); } lbool solve(model_ref& mdl) { + add_branches(1); vector threads; for (unsigned i = 0; i < m_num_threads; ++i) threads.push_back(std::thread([this]() { run_solver(); })); @@ -706,7 +749,7 @@ public: parallel_tactic(ast_manager& m, params_ref const& p) : m_manager(m), m_params(p) { - init(); + init(); } void operator ()(const goal_ref & g,goal_ref_buffer & result) { @@ -746,23 +789,13 @@ public: result.push_back(g.get()); } - virtual void collect_param_descrs(param_descrs & r) { - r.insert("conquer_batch_size", CPK_UINT, "(default: 1000) batch size of cubes to conquer"); - } - unsigned conquer_batch_size() const { parallel_params pp(m_params); return pp.conquer_batch_size(); } - bool filter_cubes() const { - parallel_params pp(m_params); - return pp.filter_cubes(); - } - void cleanup() { m_queue.reset(); - init(); } tactic* translate(ast_manager& m) { @@ -771,6 +804,8 @@ public: virtual void updt_params(params_ref const & p) { m_params.copy(p); + parallel_params pp(p); + m_conquer_threshold = pp.conquer_threshold(); } virtual void collect_statistics(statistics & st) const { diff --git a/src/tactic/smtlogics/parallel_params.pyg b/src/tactic/smtlogics/parallel_params.pyg index 58da305f4..84f4eb2c4 100644 --- a/src/tactic/smtlogics/parallel_params.pyg +++ b/src/tactic/smtlogics/parallel_params.pyg @@ -6,6 +6,6 @@ def_module_params('parallel', ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), ('conquer_batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), ('inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), - ('restart.max', UINT, 100, 'maximal number of restarts during conquer phase'), - ('filter_cubes', BOOL, False, 'filter cubes using a short running check'), + ('restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), + ('conquer_threshold', UINT, 10, 'number of cubes generated before simple conquer solver is created'), )) From 012a96fd81b0ff75cde519f6ab85dd113e8094e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Apr 2018 16:16:48 -0700 Subject: [PATCH 0779/1283] adding smt parallel solving Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_lookahead.h | 2 +- src/smt/params/smt_params.cpp | 1 + src/smt/params/smt_params.h | 1 + src/smt/params/smt_params_helper.pyg | 1 + src/smt/smt_context.cpp | 20 ++++- src/smt/smt_context.h | 4 + src/smt/smt_kernel.cpp | 12 ++- src/smt/smt_kernel.h | 5 ++ src/smt/smt_solver.cpp | 54 +++++++++++-- src/tactic/portfolio/CMakeLists.txt | 1 + src/tactic/portfolio/parallel_tactic.cpp | 96 ++++++++++++++---------- src/tactic/portfolio/parallel_tactic.h | 13 +++- src/tactic/smtlogics/nra_tactic.cpp | 6 +- src/tactic/smtlogics/parallel_params.pyg | 11 ++- src/tactic/smtlogics/qfbv_tactic.cpp | 7 +- src/tactic/smtlogics/qflia_tactic.cpp | 11 +-- 17 files changed, 174 insertions(+), 73 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 0d737500a..d4d1e615f 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1034,7 +1034,7 @@ namespace sat { } if (m_s.m_ext) { - m_ext = m_s.m_ext->copy(this, learned); + // m_ext = m_s.m_ext->copy(this, learned); } propagate(); m_qhead = m_trail.size(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index b86b7cb14..3213c5a80 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -247,7 +247,7 @@ namespace sat { stats m_stats; model m_model; cube_state m_cube_state; - scoped_ptr m_ext; + //scoped_ptr m_ext; // --------------------------------------- // truth values diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index a8eb81a2e..3ad20cf90 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -39,6 +39,7 @@ void smt_params::updt_local_params(params_ref const & _p) { m_timeout = p.timeout(); m_rlimit = p.rlimit(); m_max_conflicts = p.max_conflicts(); + m_restart_max = p.restart_max(); m_core_validate = p.core_validate(); m_logic = _p.get_sym("logic", m_logic); m_string_solver = p.string_solver(); diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index b01499c04..32b634626 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -99,6 +99,7 @@ struct smt_params : public preprocessor_params, unsigned m_phase_caching_off; bool m_minimize_lemmas; unsigned m_max_conflicts; + unsigned m_restart_max; bool m_simplify_clauses; unsigned m_tick; bool m_display_features; diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index c6749f678..2f16c5798 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -21,6 +21,7 @@ def_module_params(module_name='smt', ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), ('max_conflicts', UINT, UINT_MAX, 'maximum number of conflicts before giving up.'), + ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), ('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'), ('mbqi.max_cexs', UINT, 1, 'initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation'), ('mbqi.max_cexs_incr', UINT, 0, 'increment for MBQI_MAX_CEXS, the increment is performed after each round of MBQI'), diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 4535b29c2..cdfdd208f 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1829,6 +1829,15 @@ namespace smt { m_bvar_inc *= INV_ACTIVITY_LIMIT; } + expr* context::next_decision() { + bool_var var; + lbool phase; + m_case_split_queue->next_case_split(var, phase); + if (var == null_bool_var) return m_manager.mk_true(); + m_case_split_queue->unassign_var_eh(var); + return bool_var2expr(var); + } + /** \brief Execute next clase split, return false if there are no more case splits to be performed. @@ -3433,6 +3442,7 @@ namespace smt { m_num_conflicts = 0; m_num_conflicts_since_restart = 0; m_num_conflicts_since_lemma_gc = 0; + m_num_restarts = 0; m_restart_threshold = m_fparams.m_restart_initial; m_restart_outer_threshold = m_fparams.m_restart_initial; m_agility = 0.0; @@ -3564,7 +3574,7 @@ namespace smt { inc_limits(); if (status == l_true || !m_fparams.m_restart_adaptive || m_agility < m_fparams.m_restart_agility_threshold) { SASSERT(!inconsistent()); - IF_VERBOSE(2, verbose_stream() << "(smt.restarting :propagations " << m_stats.m_num_propagations + IF_VERBOSE(2, verbose_stream() << "(smt.restarting :propagations " << m_stats.m_num_propagations << " :decisions " << m_stats.m_num_decisions << " :conflicts " << m_stats.m_num_conflicts << " :restart " << m_restart_threshold; if (m_fparams.m_restart_strategy == RS_IN_OUT_GEOMETRIC) { @@ -3573,9 +3583,10 @@ namespace smt { if (m_fparams.m_restart_adaptive) { verbose_stream() << " :agility " << m_agility; } - verbose_stream() << ")" << std::endl; verbose_stream().flush();); + verbose_stream() << ")\n"); // execute the restart m_stats.m_num_restarts++; + m_num_restarts++; if (m_scope_lvl > curr_lvl) { pop_scope(m_scope_lvl - curr_lvl); SASSERT(at_search_level()); @@ -3593,6 +3604,11 @@ namespace smt { status = l_false; return false; } + if (m_num_restarts >= m_fparams.m_restart_max) { + status = l_undef; + m_last_search_failure = NUM_CONFLICTS; + return false; + } } if (m_fparams.m_simplify_clauses) simplify_clauses(); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 8a4fc9471..ed78b9825 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -889,6 +889,8 @@ namespace smt { unsigned m_num_conflicts; unsigned m_num_conflicts_since_restart; unsigned m_num_conflicts_since_lemma_gc; + unsigned m_num_restarts; + unsigned m_num_simplifications; unsigned m_restart_threshold; unsigned m_restart_outer_threshold; unsigned m_luby_idx; @@ -1030,6 +1032,8 @@ namespace smt { enode * get_enode_eq_to(func_decl * f, unsigned num_args, enode * const * args); + expr* next_decision(); + protected: bool decide(); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index a7948725c..78e33c7dd 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -175,11 +175,15 @@ namespace smt { void get_guessed_literals(expr_ref_vector & result) { m_kernel.get_guessed_literals(result); } - + + expr* next_decision() { + return m_kernel.next_decision(); + } + void collect_statistics(::statistics & st) const { m_kernel.collect_statistics(st); } - + void reset_statistics() { } @@ -347,6 +351,10 @@ namespace smt { m_imp->get_guessed_literals(result); } + expr* kernel::next_decision() { + return m_imp->next_decision(); + } + void kernel::display(std::ostream & out) const { m_imp->display(out); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index d10cab4f3..d15790429 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -212,6 +212,11 @@ namespace smt { */ void get_guessed_literals(expr_ref_vector & result); + /** + \brief return the next case split literal. + */ + expr* next_decision(); + /** \brief (For debubbing purposes) Prints the state of the kernel */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 780495e9c..2a7d52a48 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -30,9 +30,35 @@ Notes: namespace smt { class smt_solver : public solver_na2as { + + struct cuber { + smt_solver& m_solver; + unsigned m_round; + expr_ref m_result; + cuber(smt_solver& s): + m_solver(s), + m_round(0), + m_result(s.get_manager()) {} + expr_ref cube() { + switch (m_round) { + case 0: + m_result = m_solver.m_context.next_decision(); + break; + case 1: + m_result = m_solver.get_manager().mk_not(m_result); + break; + default: + m_result = m_solver.get_manager().mk_false(); + break; + } + ++m_round; + return m_result; + } + }; + smt_params m_smt_params; smt::kernel m_context; - progress_callback * m_callback; + cuber* m_cuber; symbol m_logic; bool m_minimizing_core; bool m_core_extend_patterns; @@ -45,6 +71,7 @@ namespace smt { solver_na2as(m), m_smt_params(p), m_context(m, m_smt_params), + m_cuber(nullptr), m_minimizing_core(false), m_core_extend_patterns(false), m_core_extend_patterns_max_distance(UINT_MAX), @@ -72,6 +99,7 @@ namespace smt { virtual ~smt_solver() { dec_ref_values(get_manager(), m_name2assertion); + dealloc(m_cuber); } virtual void updt_params(params_ref const & p) { @@ -204,7 +232,6 @@ namespace smt { virtual ast_manager & get_manager() const { return m_context.m(); } virtual void set_progress_callback(progress_callback * callback) { - m_callback = callback; m_context.set_progress_callback(callback); } @@ -217,13 +244,24 @@ namespace smt { return m_context.get_formula(idx); } - virtual expr_ref lookahead(expr_ref_vector const& assumptions, expr_ref_vector const& candidates) { + virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned cutoff) { ast_manager& m = get_manager(); - return expr_ref(m.mk_true(), m); - } - - virtual expr_ref_vector cube(expr_ref_vector&, unsigned) { - return expr_ref_vector(get_manager()); + if (!m_cuber) { + m_cuber = alloc(cuber, *this); + } + expr_ref result = m_cuber->cube(); + expr_ref_vector lits(m); + if (m.is_false(result)) { + dealloc(m_cuber); + m_cuber = nullptr; + } + if (m.is_true(result)) { + dealloc(m_cuber); + m_cuber = nullptr; + return lits; + } + lits.push_back(result); + return lits; } struct collect_fds_proc { diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index 055251467..e16992f9a 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -8,6 +8,7 @@ z3_add_component(portfolio pb2bv_solver.cpp smt_strategic_solver.cpp solver2lookahead.cpp + solver_sat_extension.cpp COMPONENT_DEPENDENCIES aig_tactic fp diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 988ab2ec4..fed4bde0a 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -41,8 +41,13 @@ Notes: #include "solver/solver.h" #include "solver/solver2tactic.h" #include "tactic/tactic.h" +#include "tactic/tactical.h" #include "tactic/portfolio/fd_solver.h" #include "tactic/smtlogics/parallel_params.hpp" +#include "smt/tactic/smt_tactic.h" +#include "smt/smt_solver.h" +#include "sat/sat_solver/inc_sat_solver.h" +#include "sat/tactic/sat_tactic.h" class parallel_tactic : public tactic { @@ -184,7 +189,6 @@ class parallel_tactic : public tactic { ref m_solver; // solver state unsigned m_depth; // number of nested calls to cubing double m_width; // estimate of fraction of problem handled by state - unsigned m_restart_max; // saved configuration value public: solver_state(ast_manager* m, solver* s, params_ref const& p, task_type t): @@ -196,8 +200,6 @@ class parallel_tactic : public tactic { m_depth(0), m_width(1.0) { - parallel_params pp(p); - m_restart_max = pp.restart_max(); } ast_manager& m() { return m_solver->get_manager(); } @@ -255,27 +257,12 @@ class parallel_tactic : public tactic { lbool simplify() { lbool r = l_undef; - if (m_depth == 1) { - IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-1)\n";); - set_simplify_params(true, true); // retain PB, retain blocked - r = get_solver().check_sat(0,0); - if (r != l_undef) return r; - - // copy over the resulting clauses with a configuration that blasts PB constraints - set_simplify_params(false, true); - expr_ref_vector fmls(m()); - get_solver().get_assertions(fmls); - model_converter_ref mc = get_solver().get_model_converter(); - m_solver = mk_fd_solver(m(), m_params); - m_solver->set_model_converter(mc.get()); - m_solver->assert_expr(fmls); - } - IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-2)\n";); - set_simplify_params(false, true); // remove PB, retain blocked + IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-1)\n";); + set_simplify_params(true); // retain blocked r = get_solver().check_sat(0,0); if (r != l_undef) return r; - IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-3)\n";); - set_simplify_params(false, false); // remove any PB, remove blocked + IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-2)\n";); + set_simplify_params(false); // remove blocked r = get_solver().check_sat(0,0); return r; } @@ -299,27 +286,26 @@ class parallel_tactic : public tactic { } void set_conquer_params(solver& s) { + parallel_params pp(m_params); params_ref p; p.copy(m_params); p.set_bool("gc.burst", true); // apply eager gc p.set_uint("simplify.delay", 1000); // delay simplification by 1000 conflicts p.set_bool("lookahead_simplify", false); - p.set_uint("restart.max", m_restart_max); + p.set_uint("restart.max", pp.conquer_restart_max()); p.set_uint("inprocess.max", UINT_MAX); // base bounds on restart.max s.updt_params(p); } - void set_simplify_params(bool pb_simp, bool retain_blocked) { + void set_simplify_params(bool retain_blocked) { parallel_params pp(m_params); + double mul = pp.simplify_multiplier(); + unsigned mult = (mul == 0 ? 1 : std::max((unsigned)1, static_cast(m_depth * mul))); params_ref p; p.copy(m_params); - - p.set_bool("cardinality.solver", pb_simp); - p.set_sym ("pb.solver", pb_simp ? symbol("solver") : symbol("circuit")); - if (p.get_uint("inprocess.max", UINT_MAX) == UINT_MAX) - p.set_uint("inprocess.max", pp.inprocess_max()); + p.set_uint("inprocess.max", pp.simplify_inprocess_max() * mult); + p.set_uint("restart.max", pp.simplify_restart_max() * mult); p.set_bool("lookahead_simplify", true); - p.set_uint("restart.max", UINT_MAX); p.set_bool("retain_blocked_clauses", retain_blocked); get_solver().updt_params(p); } @@ -337,6 +323,7 @@ class parallel_tactic : public tactic { private: + solver_ref m_solver; ast_manager& m_manager; params_ref m_params; sref_vector m_models; @@ -355,7 +342,8 @@ private: std::string m_exn_msg; void init() { - m_num_threads = omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. + parallel_params pp(m_params); + m_num_threads = std::min((unsigned)omp_get_num_procs(), pp.threads_max()); m_progress = 0; m_has_undef = false; m_allsat = false; @@ -375,6 +363,7 @@ private: } void add_branches(unsigned b) { + if (b == 0) return; { std::lock_guard lock(m_mutex); m_branches += b; @@ -617,7 +606,6 @@ private: } else if (cubes.empty()) { dec_branch(); - return; } else { s.inc_width(width); @@ -746,15 +734,16 @@ private: public: - parallel_tactic(ast_manager& m, params_ref const& p) : - m_manager(m), + parallel_tactic(solver* s, params_ref const& p) : + m_solver(s), + m_manager(s->get_manager()), m_params(p) { init(); } void operator ()(const goal_ref & g,goal_ref_buffer & result) { ast_manager& m = g->m(); - solver* s = mk_fd_solver(m, m_params); + solver* s = m_solver->translate(m, m_params); solver_state* st = alloc(solver_state, 0, s, m_params, cube_task); m_queue.add_task(st); expr_ref_vector clauses(m); @@ -799,7 +788,8 @@ public: } tactic* translate(ast_manager& m) { - return alloc(parallel_tactic, m, m_params); + solver* s = m_solver->translate(m, m_params); + return alloc(parallel_tactic, s, m_params); } virtual void updt_params(params_ref const & p) { @@ -817,12 +807,40 @@ public: virtual void reset_statistics() { m_stats.reset(); } - }; -tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p) { - return alloc(parallel_tactic, m, p); +tactic * mk_parallel_qffd_tactic(ast_manager& m, params_ref const& p) { + solver* s = mk_fd_solver(m, p); + return alloc(parallel_tactic, s, p); } +tactic * mk_parallel_tactic(solver* s, params_ref const& p) { + return alloc(parallel_tactic, s, p); +} + + +tactic * mk_psat_tactic(ast_manager& m, params_ref const& p) { + parallel_params pp(p); + bool use_parallel = pp.enable(); + return pp.enable() ? mk_parallel_tactic(mk_inc_sat_solver(m, p), p) : mk_sat_tactic(m); +} + +tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic) { + parallel_params pp(p); + bool use_parallel = pp.enable(); + return pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p); +} + +tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& _p, symbol const& logic) { + parallel_params pp(_p); + bool use_parallel = pp.enable(); + params_ref p = _p; + p.set_bool("auto_config", auto_config); + return using_params(pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p), p); +} + +tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p) { + return mk_parallel_tactic(mk_smt_solver(m, p, symbol::null), p); +} diff --git a/src/tactic/portfolio/parallel_tactic.h b/src/tactic/portfolio/parallel_tactic.h index 8fd9a29fa..f3dc36d0e 100644 --- a/src/tactic/portfolio/parallel_tactic.h +++ b/src/tactic/portfolio/parallel_tactic.h @@ -21,11 +21,20 @@ Notes: class solver; class tactic; +class solver; -tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p); +tactic * mk_parallel_tactic(solver* s, params_ref const& p); +tactic * mk_parallel_qffd_tactic(ast_manager& m, params_ref const& p); +tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p); + +// create parallel sat/smt tactics if parallel.enable=true, otherwise return sequential versions. +tactic * mk_psat_tactic(ast_manager& m, params_ref const& p); +tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic = symbol::null); +tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& p, symbol const& logic = symbol::null); /* - ADD_TACTIC("qffdp", "builtin strategy for solving QF_FD problems in parallel.", "mk_parallel_tactic(m, p)") + ADD_TACTIC("pqffd", "builtin strategy for solving QF_FD problems in parallel.", "mk_parallel_qffd_tactic(m, p)") + ADD_TACTIC("psmt", "builtin strategy for SMT tactic in parallel.", "mk_parallel_smt_tactic(m, p)") */ #endif diff --git a/src/tactic/smtlogics/nra_tactic.cpp b/src/tactic/smtlogics/nra_tactic.cpp index 381bc4bb6..a9b32e5a8 100644 --- a/src/tactic/smtlogics/nra_tactic.cpp +++ b/src/tactic/smtlogics/nra_tactic.cpp @@ -19,13 +19,13 @@ Notes: #include "tactic/tactical.h" #include "tactic/core/simplify_tactic.h" #include "tactic/core/propagate_values_tactic.h" -#include "smt/tactic/smt_tactic.h" #include "tactic/core/nnf_tactic.h" +#include "tactic/arith/probe_arith.h" +#include "smt/tactic/smt_tactic.h" #include "qe/qe_tactic.h" #include "qe/nlqsat.h" -#include "nlsat/tactic/qfnra_nlsat_tactic.h" #include "qe/qe_lite.h" -#include "tactic/arith/probe_arith.h" +#include "nlsat/tactic/qfnra_nlsat_tactic.h" tactic * mk_nra_tactic(ast_manager & m, params_ref const& p) { params_ref p1 = p; diff --git a/src/tactic/smtlogics/parallel_params.pyg b/src/tactic/smtlogics/parallel_params.pyg index 84f4eb2c4..590fc02d2 100644 --- a/src/tactic/smtlogics/parallel_params.pyg +++ b/src/tactic/smtlogics/parallel_params.pyg @@ -4,8 +4,11 @@ def_module_params('parallel', export=True, params=( ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), - ('conquer_batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), - ('inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), - ('restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), - ('conquer_threshold', UINT, 10, 'number of cubes generated before simple conquer solver is created'), + ('threads.max', UINT, 10000, 'caps maximal number of threads below the number of processors'), + ('simplify.multiplier', DOUBLE, 0, 'restart and inprocess max is increased by depth * simplify.multipler, unless the multiplier is 0'), + ('conquer.batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), + ('conquer.threshold', UINT, 10, 'number of cubes generated before simple conquer solver is created'), + ('conquer.restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), + ('simplify.restart.max', UINT, 5000, 'maximal number of restarts during simplification phase'), + ('simplify.inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), )) diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 25741c09e..68f054640 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -28,6 +28,7 @@ Notes: #include "tactic/bv/bv_size_reduction_tactic.h" #include "tactic/aig/aig_tactic.h" #include "sat/tactic/sat_tactic.h" +#include "sat/sat_solver/inc_sat_solver.h" #include "tactic/portfolio/parallel_tactic.h" #include "tactic/smtlogics/parallel_params.hpp" #include "ackermannization/ackermannize_bv_tactic.h" @@ -129,12 +130,10 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat tactic * mk_qfbv_tactic(ast_manager & m, params_ref const & p) { - parallel_params pp(p); - bool use_parallel = pp.enable(); tactic * new_sat = cond(mk_produce_proofs_probe(), and_then(mk_simplify_tactic(m), mk_smt_tactic()), - use_parallel ? mk_parallel_tactic(m, p): mk_sat_tactic(m)); + mk_psat_tactic(m, p)); - return mk_qfbv_tactic(m, p, new_sat, mk_smt_tactic()); + return mk_qfbv_tactic(m, p, new_sat, mk_psmt_tactic(m, p)); } diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index 248829c49..b30103f43 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -24,7 +24,6 @@ Notes: #include "tactic/core/solve_eqs_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "smt/tactic/smt_tactic.h" -// include"mip_tactic.h" #include "tactic/arith/add_bounds_tactic.h" #include "tactic/arith/pb2bv_tactic.h" #include "tactic/arith/lia2pb_tactic.h" @@ -35,6 +34,7 @@ Notes: #include "sat/tactic/sat_tactic.h" #include "tactic/arith/bound_manager.h" #include "tactic/arith/probe_arith.h" +#include "tactic/portfolio/parallel_tactic.h" struct quasi_pb_probe : public probe { virtual result operator()(goal const & g) { @@ -42,10 +42,7 @@ struct quasi_pb_probe : public probe { bound_manager bm(g.m()); bm(g); rational l, u; bool st; - bound_manager::iterator it = bm.begin(); - bound_manager::iterator end = bm.end(); - for (; it != end; ++it) { - expr * t = *it; + for (expr * t : bm) { if (bm.has_lower(t, l, st) && bm.has_upper(t, u, st) && (l.is_zero() || l.is_one()) && (u.is_zero() || u.is_one())) continue; if (found_non_01) @@ -93,7 +90,7 @@ static tactic * mk_bv2sat_tactic(ast_manager & m) { mk_max_bv_sharing_tactic(m), mk_bit_blaster_tactic(m), mk_aig_tactic(), - mk_sat_tactic(m)), + mk_sat_tactic(m, solver_p)), solver_p); } @@ -224,7 +221,7 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { using_params(mk_lia2sat_tactic(m), quasi_pb_p), mk_fail_if_undecided_tactic()), mk_bounded_tactic(m), - mk_smt_tactic())), + mk_psmt_tactic(m, p))), main_p); st->updt_params(p); From cd35caff5237c1e6d24f069cb2e3a144b76595a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Apr 2018 03:18:57 -0700 Subject: [PATCH 0780/1283] clean up parallel tactic Signed-off-by: Nikolaj Bjorner --- src/ast/ast_translation.h | 14 ++ src/sat/sat_solver/inc_sat_solver.cpp | 9 +- src/tactic/portfolio/parallel_tactic.cpp | 216 ++++++----------------- src/tactic/smtlogics/parallel_params.pyg | 5 +- 4 files changed, 81 insertions(+), 163 deletions(-) diff --git a/src/ast/ast_translation.h b/src/ast/ast_translation.h index 47517a073..d5e29e785 100644 --- a/src/ast/ast_translation.h +++ b/src/ast/ast_translation.h @@ -71,6 +71,11 @@ public: template T * operator()(T const * n) { + return translate(n); + } + + template + T * translate(T const * n) { if (&from() == &to()) return const_cast(n); SASSERT(!n || from().contains(const_cast(n))); ast * r = process(n); @@ -78,9 +83,17 @@ public: return static_cast(r); } + ast_manager & from() const { return m_from_manager; } ast_manager & to() const { return m_to_manager; } + template + ref_vector operator()(ref_vector const& src) { + ref_vector dst(to()); + for (expr* v : src) dst.push_back(translate(v)); + return dst; + } + void reset_cache(); void cleanup(); @@ -100,6 +113,7 @@ inline expr * translate(expr const * e, ast_manager & from, ast_manager & to) { return ast_translation(from, to)(e); } + class expr_dependency_translation { ast_translation & m_translation; ptr_vector m_buffer; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index a7499590b..760110e82 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -31,11 +31,11 @@ Notes: #include "tactic/arith/card2bv_tactic.h" #include "tactic/bv/bit_blaster_tactic.h" #include "tactic/core/simplify_tactic.h" +#include "tactic/core/solve_eqs_tactic.h" +#include "tactic/bv/bit_blaster_model_converter.h" #include "model/model_smt2_pp.h" #include "model/model_v2_pp.h" #include "model/model_evaluator.h" -#include "tactic/bv/bit_blaster_model_converter.h" -#include "tactic/core/propagate_values_tactic.h" #include "sat/sat_solver.h" #include "sat/sat_params.hpp" #include "sat/tactic/goal2sat.h" @@ -501,7 +501,10 @@ public: simp2_p.set_bool("elim_and", true); simp2_p.set_bool("blast_distinct", true); m_preprocess = - and_then(mk_card2bv_tactic(m, m_params), // updates model converter + and_then(mk_simplify_tactic(m), + mk_propagate_values_tactic(m), + //time consuming if done in inner loop: mk_solve_eqs_tactic(m, simp2_p), + mk_card2bv_tactic(m, m_params), // updates model converter using_params(mk_simplify_tactic(m), simp2_p), mk_max_bv_sharing_tactic(m), mk_bit_blaster_tactic(m, m_bb_rewriter.get()), // updates model converter diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index fed4bde0a..b3f5dfc30 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -16,20 +16,16 @@ Author: Miguel Neves Notes: - A task comprises of a non-empty sequence of cubes, a type and parameters - - If in the cube state, the solver performs the following: + + It invokes the following procedure: 1. Clone the state with the remaining cubes if there is more than one cube. Re-enqueue the remaining cubes. 2. Apply simplifications and pre-processing according to configuration. 3. Cube using the parameter settings prescribed in m_params. - 4. Create a conquer state with the produced cubes. - If in the conquer state, the solver performs the following - 1. Pass the cubes as assumptions and solve each sub-cube with a prescribed resource bound. - 2. Assemble cubes that could not be solved and create a cube state. + 4. Optionally pass the cubes as assumptions and solve each sub-cube with a prescribed resource bound. + 5. Assemble cubes that could not be solved and create a cube state. - --*/ #include @@ -52,8 +48,6 @@ Notes: class parallel_tactic : public tactic { - enum task_type { cube_task, conquer_task }; - class solver_state; class task_queue { @@ -169,11 +163,7 @@ class parallel_tactic : public tactic { m_vars(vs), m_cube(c) {} cube_var operator()(ast_translation& tr) { - expr_ref_vector vars(tr.to()); - expr_ref_vector cube(tr.to()); - for (expr* v : m_vars) vars.push_back(tr(v)); - for (expr* c : m_cube) cube.push_back(tr(c)); - return cube_var(cube, vars); + return cube_var(tr(m_cube), tr(m_vars)); } expr_ref_vector const& cube() const { return m_cube; } @@ -181,9 +171,8 @@ class parallel_tactic : public tactic { }; class solver_state { - task_type m_type; // current work role of the task scoped_ptr m_manager; // ownership handle to ast_manager - vector m_cubes; // set of cubes to process by task + vector m_cubes; // set of cubes to process by task expr_ref_vector m_asserted_cubes; // set of cubes asserted on the current solver params_ref m_params; // configuration parameters ref m_solver; // solver state @@ -191,8 +180,7 @@ class parallel_tactic : public tactic { double m_width; // estimate of fraction of problem handled by state public: - solver_state(ast_manager* m, solver* s, params_ref const& p, task_type t): - m_type(t), + solver_state(ast_manager* m, solver* s, params_ref const& p): m_manager(m), m_asserted_cubes(s->get_manager()), m_params(p), @@ -210,13 +198,13 @@ class parallel_tactic : public tactic { solver const& get_solver() const { return *m_solver; } - solver_state* clone(solver* s0 = nullptr) { + solver_state* clone() { SASSERT(!m_cubes.empty()); ast_manager& m = m_solver->get_manager(); - ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); + ast_manager* new_m = alloc(ast_manager, m, m.proof_mode()); ast_translation tr(m, *new_m); - solver* s = (s0 ? s0 : m_solver.get())->translate(*new_m, m_params); - solver_state* st = alloc(solver_state, new_m, s, m_params, m_type); + solver* s = m_solver.get()->translate(*new_m, m_params); + solver_state* st = alloc(solver_state, new_m, s, m_params); for (auto & c : m_cubes) st->m_cubes.push_back(c(tr)); for (expr* c : m_asserted_cubes) st->m_asserted_cubes.push_back(tr(c)); st->m_depth = m_depth; @@ -224,11 +212,7 @@ class parallel_tactic : public tactic { return st; } - task_type type() const { return m_type; } - - void set_type(task_type t) { m_type = t; } - - vector const& cubes() const { SASSERT(m_type == conquer_task); return m_cubes; } + vector const& cubes() const { return m_cubes; } // remove up to n cubes from list of cubes. vector split_cubes(unsigned n) { @@ -247,9 +231,7 @@ class parallel_tactic : public tactic { void inc_depth(unsigned inc) { m_depth += inc; } - void inc_width(unsigned w) { - m_width *= w; - } + void inc_width(unsigned w) { m_width *= w; } double get_width() const { return m_width; } @@ -272,13 +254,7 @@ class parallel_tactic : public tactic { m_asserted_cubes.append(cube); } - lbool solve(expr_ref_vector const& cube) { - set_conquer_params(); - return get_solver().check_sat(cube); - } - - void set_cube_params() { - // get_solver().updt_params(m_params); + void set_cube_params() { } void set_conquer_params() { @@ -299,10 +275,11 @@ class parallel_tactic : public tactic { void set_simplify_params(bool retain_blocked) { parallel_params pp(m_params); - double mul = pp.simplify_multiplier(); - unsigned mult = (mul == 0 ? 1 : std::max((unsigned)1, static_cast(m_depth * mul))); params_ref p; p.copy(m_params); + double exp = pp.simplify_exp(); + exp = std::max(exp, 1.0); + unsigned mult = static_cast(pow(exp, m_depth - 1)); p.set_uint("inprocess.max", pp.simplify_inprocess_max() * mult); p.set_uint("restart.max", pp.simplify_restart_max() * mult); p.set_bool("lookahead_simplify", true); @@ -323,23 +300,23 @@ class parallel_tactic : public tactic { private: - solver_ref m_solver; - ast_manager& m_manager; - params_ref m_params; + solver_ref m_solver; + ast_manager& m_manager; + params_ref m_params; sref_vector m_models; - unsigned m_num_threads; - statistics m_stats; - task_queue m_queue; - std::mutex m_mutex; - double m_progress; - unsigned m_branches; - unsigned m_backtrack_frequency; - unsigned m_conquer_threshold; - bool m_has_undef; - bool m_allsat; - unsigned m_num_unsat; - int m_exn_code; - std::string m_exn_msg; + unsigned m_num_threads; + statistics m_stats; + task_queue m_queue; + std::mutex m_mutex; + double m_progress; + unsigned m_branches; + unsigned m_backtrack_frequency; + unsigned m_conquer_delay; + volatile bool m_has_undef; + bool m_allsat; + unsigned m_num_unsat; + int m_exn_code; + std::string m_exn_msg; void init() { parallel_params pp(m_params); @@ -349,8 +326,8 @@ private: m_allsat = false; m_branches = 0; m_num_unsat = 0; - m_backtrack_frequency = 10; - m_conquer_threshold = 10; + m_backtrack_frequency = pp.conquer_backtrack_frequency(); + m_conquer_delay = pp.conquer_delay(); m_exn_code = 0; m_params.set_bool("override_incremental", true); } @@ -418,104 +395,12 @@ private: close_branch(s, l_undef); } - void cube_and_conquer1(solver_state& s) { - ast_manager& m = s.m(); - vector cube, hard_cubes, cubes; - expr_ref_vector vars(m); - - switch (s.type()) { - case cube_task: goto cube; - case conquer_task: goto conquer; - } - - cube: - SASSERT(s.type() == cube_task); - - // extract up to one cube and add it. - cube.reset(); - cube.append(s.split_cubes(1)); - SASSERT(cube.size() <= 1); - IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :split-cube " << cube.size() << ")\n";); - if (!s.cubes().empty()) m_queue.add_task(s.clone()); - if (!cube.empty()) { - s.assert_cube(cube.get(0).cube()); - vars.reset(); - vars.append(cube.get(0).vars()); - } - s.inc_depth(1); - - // simplify - switch (s.simplify()) { - case l_undef: break; - case l_true: report_sat(s); return; - case l_false: report_unsat(s); return; - } - if (canceled(s)) return; - - // extract cubes. - cubes.reset(); - s.set_cube_params(); - unsigned cutoff = UINT_MAX; - while (true) { - expr_ref_vector c = s.get_solver().cube(vars, cutoff); - if (c.empty()) { - report_undef(s); - return; - } - if (m.is_false(c.back())) { - break; - } - cubes.push_back(cube_var(c, vars)); - IF_VERBOSE(2, verbose_stream() << "(tactic.parallel :cube " << cubes.size() << " :vars " << vars.size() << ")\n"); - } - - IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :cubes " << cubes.size() << ")\n";); - - if (cubes.empty()) { - report_unsat(s); - return; - } - else { - s.inc_width(cubes.size()); - add_branches(cubes.size() - 1); - s.set_cubes(cubes); - s.set_type(conquer_task); - goto conquer; - } - - conquer: - SASSERT(s.type() == conquer_task); - - // extract a batch of cubes - cubes.reset(); - cubes.append(s.split_cubes(conquer_batch_size())); - if (!s.cubes().empty()) m_queue.add_task(s.clone()); - - s.set_conquer_params(); - hard_cubes.reset(); - for (cube_var& cv : cubes) { - switch (s.solve(cv.cube())) { - case l_undef: hard_cubes.push_back(cv); break; - case l_true: report_sat(s); break; - case l_false: report_unsat(s); break; - } - if (canceled(s)) return; - } - IF_VERBOSE(1, verbose_stream() << "(tactic.parallel :cubes " << cubes.size() << " :hard-cubes " << hard_cubes.size() << ")\n";); - if (hard_cubes.empty()) return; - - s.set_cubes(hard_cubes); - s.set_type(cube_task); - goto cube; - } - - void cube_and_conquer2(solver_state& s) { + void cube_and_conquer(solver_state& s) { ast_manager& m = s.m(); vector cube, hard_cubes, cubes; expr_ref_vector vars(m); cube_again: - SASSERT(s.type() == cube_task); // extract up to one cube and add it. cube.reset(); cube.append(s.split_cubes(1)); @@ -527,9 +412,9 @@ private: vars.reset(); vars.append(cube.get(0).vars()); } - s.inc_depth(1); simplify_again: + s.inc_depth(1); // simplify if (canceled(s)) return; switch (s.simplify()) { @@ -539,6 +424,9 @@ private: } if (canceled(s)) return; + if (memory_pressure()) { + goto simplify_again; + } // extract cubes. cubes.reset(); s.set_cube_params(); @@ -556,7 +444,7 @@ private: break; } lbool is_sat = l_undef; - if (width >= m_conquer_threshold && !conquer) { + if (width >= m_conquer_delay && !conquer) { conquer = s.copy_solver(); s.set_conquer_params(*conquer.get()); } @@ -669,10 +557,14 @@ private: } } + bool memory_pressure() { + return memory::above_high_watermark(); + } + void run_solver() { try { while (solver_state* st = m_queue.get_task()) { - cube_and_conquer2(*st); + cube_and_conquer(*st); collect_statistics(*st); m_queue.task_done(st); if (st->m().canceled()) m_queue.shutdown(); @@ -725,10 +617,17 @@ private: } std::ostream& display(std::ostream& out) { + unsigned n_models, n_unsat; + double n_progress; + { + std::lock_guard lock(m_mutex); + n_models = m_models.size(); + n_unsat = m_num_unsat; + n_progress = m_progress; + } m_stats.display(out); m_queue.display(out); - std::lock_guard lock(m_mutex); - out << "(tactic.parallel :unsat " << m_num_unsat << " :progress " << m_progress << "% :models " << m_models.size() << ")\n"; + out << "(tactic.parallel :unsat " << n_unsat << " :progress " << n_progress << "% :models " << n_models << ")\n"; return out; } @@ -744,7 +643,7 @@ public: void operator ()(const goal_ref & g,goal_ref_buffer & result) { ast_manager& m = g->m(); solver* s = m_solver->translate(m, m_params); - solver_state* st = alloc(solver_state, 0, s, m_params, cube_task); + solver_state* st = alloc(solver_state, 0, s, m_params); m_queue.add_task(st); expr_ref_vector clauses(m); ptr_vector assumptions; @@ -795,7 +694,7 @@ public: virtual void updt_params(params_ref const & p) { m_params.copy(p); parallel_params pp(p); - m_conquer_threshold = pp.conquer_threshold(); + m_conquer_delay = pp.conquer_delay(); } virtual void collect_statistics(statistics & st) const { @@ -804,6 +703,7 @@ public: st.update("par models", m_models.size()); st.update("par progress", m_progress); } + virtual void reset_statistics() { m_stats.reset(); } diff --git a/src/tactic/smtlogics/parallel_params.pyg b/src/tactic/smtlogics/parallel_params.pyg index 590fc02d2..58c00aa97 100644 --- a/src/tactic/smtlogics/parallel_params.pyg +++ b/src/tactic/smtlogics/parallel_params.pyg @@ -5,10 +5,11 @@ def_module_params('parallel', params=( ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), ('threads.max', UINT, 10000, 'caps maximal number of threads below the number of processors'), - ('simplify.multiplier', DOUBLE, 0, 'restart and inprocess max is increased by depth * simplify.multipler, unless the multiplier is 0'), ('conquer.batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), - ('conquer.threshold', UINT, 10, 'number of cubes generated before simple conquer solver is created'), ('conquer.restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), + ('conquer.delay', UINT, 10, 'delay of cubes until applying conquer'), + ('conquer.backtrack_frequency', UINT, 10, 'frequency to apply core minimization during conquer'), + ('simplify.exp', DOUBLE, 1, 'restart and inprocess max is multipled by simplify.exp ^ depth'), ('simplify.restart.max', UINT, 5000, 'maximal number of restarts during simplification phase'), ('simplify.inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), )) From a37303a045c298a96c9b32573a596f81fea42d38 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Apr 2018 08:21:21 -0700 Subject: [PATCH 0781/1283] move parallel-tactic to solver level Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver/inc_sat_solver.cpp | 9 +++++ src/sat/sat_solver/inc_sat_solver.h | 4 ++ src/sat/tactic/sat_tactic.cpp | 3 ++ src/smt/tactic/smt_tactic.cpp | 33 +++++++++++---- src/smt/tactic/smt_tactic.h | 5 +++ src/solver/CMakeLists.txt | 3 ++ .../portfolio => solver}/parallel_tactic.cpp | 33 +-------------- src/solver/parallel_tactic.h | 27 +++++++++++++ .../parallel_tactic_params.pyg} | 2 +- src/tactic/portfolio/CMakeLists.txt | 3 -- src/tactic/portfolio/fd_solver.cpp | 7 ++++ src/tactic/portfolio/fd_solver.h | 2 + src/tactic/portfolio/parallel_tactic.h | 40 ------------------- src/tactic/smtlogics/CMakeLists.txt | 1 - src/tactic/smtlogics/qfbv_tactic.cpp | 2 - src/tactic/smtlogics/qflia_tactic.cpp | 1 - 16 files changed, 89 insertions(+), 86 deletions(-) rename src/{tactic/portfolio => solver}/parallel_tactic.cpp (95%) create mode 100644 src/solver/parallel_tactic.h rename src/{tactic/smtlogics/parallel_params.pyg => solver/parallel_tactic_params.pyg} (95%) delete mode 100644 src/tactic/portfolio/parallel_tactic.h diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 760110e82..7c0b6cae5 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -24,6 +24,8 @@ Notes: #include "ast/ast_util.h" #include "solver/solver.h" #include "solver/tactic2solver.h" +#include "solver/parallel_params.hpp" +#include "solver/parallel_tactic.h" #include "tactic/tactical.h" #include "tactic/aig/aig_tactic.h" #include "tactic/core/propagate_values_tactic.h" @@ -39,6 +41,7 @@ Notes: #include "sat/sat_solver.h" #include "sat/sat_params.hpp" #include "sat/tactic/goal2sat.h" +#include "sat/tactic/sat_tactic.h" #include "sat/sat_simplifier_params.hpp" // incremental SAT solver. @@ -865,3 +868,9 @@ void inc_sat_display(std::ostream& out, solver& _s, unsigned sz, expr*const* sof s.display_weighted(out, sz, soft, weights.c_ptr()); } + +tactic * mk_psat_tactic(ast_manager& m, params_ref const& p) { + parallel_params pp(p); + bool use_parallel = pp.enable(); + return pp.enable() ? mk_parallel_tactic(mk_inc_sat_solver(m, p, false), p) : mk_sat_tactic(m); +} diff --git a/src/sat/sat_solver/inc_sat_solver.h b/src/sat/sat_solver/inc_sat_solver.h index fb4b05b91..71ec48b99 100644 --- a/src/sat/sat_solver/inc_sat_solver.h +++ b/src/sat/sat_solver/inc_sat_solver.h @@ -22,8 +22,12 @@ Notes: #include "solver/solver.h" +class tactic; + solver* mk_inc_sat_solver(ast_manager& m, params_ref const& p, bool incremental_mode = true); +tactic* mk_psat_tactic(ast_manager& m, params_ref const& p); + void inc_sat_display(std::ostream& out, solver& s, unsigned sz, expr*const* soft, rational const* _weights); diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 6beec79c9..d810c76bb 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -20,6 +20,8 @@ Notes: #include "tactic/tactical.h" #include "sat/tactic/goal2sat.h" #include "sat/sat_solver.h" +#include "solver/parallel_tactic.h" +#include "solver/parallel_params.hpp" #include "model/model_v2_pp.h" class sat_tactic : public tactic { @@ -215,3 +217,4 @@ tactic * mk_sat_preprocessor_tactic(ast_manager & m, params_ref const & p) { return t; } + diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 97b6d89d7..0359e2031 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -16,19 +16,21 @@ Author: Notes: --*/ -#include "tactic/tactic.h" -#include "tactic/tactical.h" +#include "util/lp/lp_params.hpp" +#include "ast/rewriter/rewriter_types.h" +#include "ast/ast_util.h" #include "smt/smt_kernel.h" #include "smt/params/smt_params.h" #include "smt/params/smt_params_helper.hpp" -#include "util/lp/lp_params.hpp" -#include "ast/rewriter/rewriter_types.h" -#include "tactic/generic_model_converter.h" -#include "ast/ast_util.h" -#include "solver/solver2tactic.h" #include "smt/smt_solver.h" +#include "tactic/tactic.h" +#include "tactic/tactical.h" +#include "tactic/generic_model_converter.h" +#include "solver/solver2tactic.h" #include "solver/solver.h" #include "solver/mus.h" +#include "solver/parallel_tactic.h" +#include "solver/parallel_params.hpp" typedef obj_map expr2expr_map; @@ -301,3 +303,20 @@ tactic * mk_smt_tactic_using(bool auto_config, params_ref const & _p) { return using_params(r, p); } +tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic) { + parallel_params pp(p); + bool use_parallel = pp.enable(); + return pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p); +} + +tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& _p, symbol const& logic) { + parallel_params pp(_p); + bool use_parallel = pp.enable(); + params_ref p = _p; + p.set_bool("auto_config", auto_config); + return using_params(pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p), p); +} + +tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p) { + return mk_parallel_tactic(mk_smt_solver(m, p, symbol::null), p); +} diff --git a/src/smt/tactic/smt_tactic.h b/src/smt/tactic/smt_tactic.h index c7b91d032..fbee950c2 100644 --- a/src/smt/tactic/smt_tactic.h +++ b/src/smt/tactic/smt_tactic.h @@ -31,8 +31,13 @@ tactic * mk_smt_tactic(params_ref const & p = params_ref()); // syntax sugar for using_params(mk_smt_tactic(), p) where p = (:auto_config, auto_config) tactic * mk_smt_tactic_using(bool auto_config = true, params_ref const & p = params_ref()); +tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic = symbol::null); +tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& p, symbol const& logic = symbol::null); +tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p); + /* ADD_TACTIC("smt", "apply a SAT based SMT solver.", "mk_smt_tactic(p)") + ADD_TACTIC("psmt", "builtin strategy for SMT tactic in parallel.", "mk_parallel_smt_tactic(m, p)") */ #endif diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 1ffdc35e1..c8e206f7f 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(solver check_sat_result.cpp combined_solver.cpp mus.cpp + parallel_tactic.cpp smt_logics.cpp solver.cpp solver_na2as.cpp @@ -14,4 +15,6 @@ z3_add_component(solver tactic PYG_FILES combined_solver_params.pyg + parallel_params.pyg + ) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp similarity index 95% rename from src/tactic/portfolio/parallel_tactic.cpp rename to src/solver/parallel_tactic.cpp index b3f5dfc30..748ee5d64 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -39,7 +39,8 @@ Notes: #include "tactic/tactic.h" #include "tactic/tactical.h" #include "tactic/portfolio/fd_solver.h" -#include "tactic/smtlogics/parallel_params.hpp" +#include "solver/parallel_tactic.h" +#include "solver/parallel_params.hpp" #include "smt/tactic/smt_tactic.h" #include "smt/smt_solver.h" #include "sat/sat_solver/inc_sat_solver.h" @@ -710,37 +711,7 @@ public: }; - -tactic * mk_parallel_qffd_tactic(ast_manager& m, params_ref const& p) { - solver* s = mk_fd_solver(m, p); - return alloc(parallel_tactic, s, p); -} - tactic * mk_parallel_tactic(solver* s, params_ref const& p) { return alloc(parallel_tactic, s, p); } - -tactic * mk_psat_tactic(ast_manager& m, params_ref const& p) { - parallel_params pp(p); - bool use_parallel = pp.enable(); - return pp.enable() ? mk_parallel_tactic(mk_inc_sat_solver(m, p), p) : mk_sat_tactic(m); -} - -tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic) { - parallel_params pp(p); - bool use_parallel = pp.enable(); - return pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p); -} - -tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& _p, symbol const& logic) { - parallel_params pp(_p); - bool use_parallel = pp.enable(); - params_ref p = _p; - p.set_bool("auto_config", auto_config); - return using_params(pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p), p); -} - -tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p) { - return mk_parallel_tactic(mk_smt_solver(m, p, symbol::null), p); -} diff --git a/src/solver/parallel_tactic.h b/src/solver/parallel_tactic.h new file mode 100644 index 000000000..ae8fb6041 --- /dev/null +++ b/src/solver/parallel_tactic.h @@ -0,0 +1,27 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + parallel_tactic.h + +Abstract: + + Parallel tactic in the style of Treengeling. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ +#ifndef PARALLEL_TACTIC_H_ +#define PARALLEL_TACTIC_H_ + +class tactic; +class solver; + +tactic * mk_parallel_tactic(solver* s, params_ref const& p); + +#endif diff --git a/src/tactic/smtlogics/parallel_params.pyg b/src/solver/parallel_tactic_params.pyg similarity index 95% rename from src/tactic/smtlogics/parallel_params.pyg rename to src/solver/parallel_tactic_params.pyg index 58c00aa97..6d633a6af 100644 --- a/src/tactic/smtlogics/parallel_params.pyg +++ b/src/solver/parallel_tactic_params.pyg @@ -1,6 +1,6 @@ def_module_params('parallel', description='parameters for parallel solver', - class_name='parallel_params', + class_name='parallel_tactic_params', export=True, params=( ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index e16992f9a..2b714cc2c 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -4,11 +4,9 @@ z3_add_component(portfolio default_tactic.cpp enum2bv_solver.cpp fd_solver.cpp - parallel_tactic.cpp pb2bv_solver.cpp smt_strategic_solver.cpp solver2lookahead.cpp - solver_sat_extension.cpp COMPONENT_DEPENDENCIES aig_tactic fp @@ -22,5 +20,4 @@ z3_add_component(portfolio TACTIC_HEADERS default_tactic.h fd_solver.h - parallel_tactic.h ) diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/portfolio/fd_solver.cpp index 946b3b30c..b0d95baee 100644 --- a/src/tactic/portfolio/fd_solver.cpp +++ b/src/tactic/portfolio/fd_solver.cpp @@ -24,6 +24,8 @@ Notes: #include "tactic/portfolio/pb2bv_solver.h" #include "tactic/portfolio/bounded_int2bv_solver.h" #include "solver/solver2tactic.h" +#include "solver/parallel_tactic.h" +#include "solver/parallel_params.hpp" solver * mk_fd_solver(ast_manager & m, params_ref const & p, bool incremental_mode) { solver* s = mk_inc_sat_solver(m, p, incremental_mode); @@ -36,3 +38,8 @@ solver * mk_fd_solver(ast_manager & m, params_ref const & p, bool incremental_mo tactic * mk_fd_tactic(ast_manager & m, params_ref const& p) { return mk_solver2tactic(mk_fd_solver(m, p, false)); } + +tactic * mk_parallel_qffd_tactic(ast_manager& m, params_ref const& p) { + solver* s = mk_fd_solver(m, p); + return mk_parallel_tactic(s, p); +} diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/portfolio/fd_solver.h index 1e107ac20..e1c5b909c 100644 --- a/src/tactic/portfolio/fd_solver.h +++ b/src/tactic/portfolio/fd_solver.h @@ -27,9 +27,11 @@ class tactic; solver * mk_fd_solver(ast_manager & m, params_ref const & p, bool incremental_mode = true); tactic * mk_fd_tactic(ast_manager & m, params_ref const & p); +tactic * mk_parallel_qffd_tactic(ast_manager& m, params_ref const& p); /* ADD_TACTIC("qffd", "builtin strategy for solving QF_FD problems.", "mk_fd_tactic(m, p)") + ADD_TACTIC("pqffd", "builtin strategy for solving QF_FD problems in parallel.", "mk_parallel_qffd_tactic(m, p)") */ #endif diff --git a/src/tactic/portfolio/parallel_tactic.h b/src/tactic/portfolio/parallel_tactic.h deleted file mode 100644 index f3dc36d0e..000000000 --- a/src/tactic/portfolio/parallel_tactic.h +++ /dev/null @@ -1,40 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - parallel_tactic.h - -Abstract: - - Parallel tactic in the style of Treengeling. - -Author: - - Nikolaj Bjorner (nbjorner) 2017-10-9 - -Notes: - ---*/ -#ifndef PARALLEL_TACTIC_H_ -#define PARALLEL_TACTIC_H_ - -class solver; -class tactic; -class solver; - -tactic * mk_parallel_tactic(solver* s, params_ref const& p); -tactic * mk_parallel_qffd_tactic(ast_manager& m, params_ref const& p); -tactic * mk_parallel_smt_tactic(ast_manager& m, params_ref const& p); - -// create parallel sat/smt tactics if parallel.enable=true, otherwise return sequential versions. -tactic * mk_psat_tactic(ast_manager& m, params_ref const& p); -tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic = symbol::null); -tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& p, symbol const& logic = symbol::null); - -/* - ADD_TACTIC("pqffd", "builtin strategy for solving QF_FD problems in parallel.", "mk_parallel_qffd_tactic(m, p)") - ADD_TACTIC("psmt", "builtin strategy for SMT tactic in parallel.", "mk_parallel_smt_tactic(m, p)") -*/ - -#endif diff --git a/src/tactic/smtlogics/CMakeLists.txt b/src/tactic/smtlogics/CMakeLists.txt index 09b145316..2741334b4 100644 --- a/src/tactic/smtlogics/CMakeLists.txt +++ b/src/tactic/smtlogics/CMakeLists.txt @@ -26,7 +26,6 @@ z3_add_component(smtlogic_tactics smt_tactic PYG_FILES qfufbv_tactic_params.pyg - parallel_params.pyg TACTIC_HEADERS nra_tactic.h qfaufbv_tactic.h diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index 68f054640..bc93b4e7b 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -29,8 +29,6 @@ Notes: #include "tactic/aig/aig_tactic.h" #include "sat/tactic/sat_tactic.h" #include "sat/sat_solver/inc_sat_solver.h" -#include "tactic/portfolio/parallel_tactic.h" -#include "tactic/smtlogics/parallel_params.hpp" #include "ackermannization/ackermannize_bv_tactic.h" #define MEMLIMIT 300 diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index b30103f43..60210259d 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -34,7 +34,6 @@ Notes: #include "sat/tactic/sat_tactic.h" #include "tactic/arith/bound_manager.h" #include "tactic/arith/probe_arith.h" -#include "tactic/portfolio/parallel_tactic.h" struct quasi_pb_probe : public probe { virtual result operator()(goal const & g) { From 0150a4bf3feacf71d06c29f81ab5e2f13987d23a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Apr 2018 10:08:10 -0700 Subject: [PATCH 0782/1283] add params Signed-off-by: Nikolaj Bjorner --- src/solver/parallel_params.pyg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/solver/parallel_params.pyg diff --git a/src/solver/parallel_params.pyg b/src/solver/parallel_params.pyg new file mode 100644 index 000000000..58c00aa97 --- /dev/null +++ b/src/solver/parallel_params.pyg @@ -0,0 +1,15 @@ +def_module_params('parallel', + description='parameters for parallel solver', + class_name='parallel_params', + export=True, + params=( + ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), + ('threads.max', UINT, 10000, 'caps maximal number of threads below the number of processors'), + ('conquer.batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), + ('conquer.restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), + ('conquer.delay', UINT, 10, 'delay of cubes until applying conquer'), + ('conquer.backtrack_frequency', UINT, 10, 'frequency to apply core minimization during conquer'), + ('simplify.exp', DOUBLE, 1, 'restart and inprocess max is multipled by simplify.exp ^ depth'), + ('simplify.restart.max', UINT, 5000, 'maximal number of restarts during simplification phase'), + ('simplify.inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), + )) From 8ccec28cb9923b9f7dcfc1d56865d50dfe6c75e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Apr 2018 10:08:55 -0700 Subject: [PATCH 0783/1283] remove extra file Signed-off-by: Nikolaj Bjorner --- src/solver/parallel_tactic_params.pyg | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/solver/parallel_tactic_params.pyg diff --git a/src/solver/parallel_tactic_params.pyg b/src/solver/parallel_tactic_params.pyg deleted file mode 100644 index 6d633a6af..000000000 --- a/src/solver/parallel_tactic_params.pyg +++ /dev/null @@ -1,15 +0,0 @@ -def_module_params('parallel', - description='parameters for parallel solver', - class_name='parallel_tactic_params', - export=True, - params=( - ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), - ('threads.max', UINT, 10000, 'caps maximal number of threads below the number of processors'), - ('conquer.batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), - ('conquer.restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), - ('conquer.delay', UINT, 10, 'delay of cubes until applying conquer'), - ('conquer.backtrack_frequency', UINT, 10, 'frequency to apply core minimization during conquer'), - ('simplify.exp', DOUBLE, 1, 'restart and inprocess max is multipled by simplify.exp ^ depth'), - ('simplify.restart.max', UINT, 5000, 'maximal number of restarts during simplification phase'), - ('simplify.inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), - )) From dab8e49e2240bc5144940b9df2689967b78136ca Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 16 Apr 2018 18:28:13 +0100 Subject: [PATCH 0784/1283] Fixed corner-case in fp.to_ubv. --- src/ast/fpa/fpa2bv_converter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d23794e54..b079fc2ca 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3252,7 +3252,9 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args expr_ref ul(m), in_range(m); if (!is_signed) { ul = m_bv_util.mk_zero_extend(3, m_bv_util.mk_bv_neg(m_bv_util.mk_numeral(1, bv_sz))); - in_range = m.mk_and(m.mk_not(x_is_neg), m.mk_not(ovfl), + in_range = m.mk_and(m.mk_or(m.mk_not(x_is_neg), + m.mk_eq(pre_rounded, m_bv_util.mk_numeral(0, bv_sz+3))), + m.mk_not(ovfl), m_bv_util.mk_ule(pre_rounded, ul)); } else { From 6224db71f32db0ff2308fb0c993f556e7b595f41 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Apr 2018 07:18:33 -0700 Subject: [PATCH 0785/1283] fix #1579 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index aabe43110..6ae63a1a6 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1350,9 +1350,10 @@ void cmd_context::restore_func_decls(unsigned old_sz) { } void cmd_context::restore_psort_inst(unsigned old_sz) { - for (unsigned i = old_sz; i < m_psort_inst_stack.size(); ++i) { + for (unsigned i = m_psort_inst_stack.size(); i-- > old_sz; ) { pdecl * s = m_psort_inst_stack[i]; - s->reset_cache(*m_pmanager); + s->reset_cache(pm()); + pm().dec_ref(s); } m_psort_inst_stack.resize(old_sz); } @@ -2024,8 +2025,8 @@ void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { } } if (m_owner.m_scopes.size() > 0) { + m_owner.pm().inc_ref(pd); m_owner.m_psort_inst_stack.push_back(pd); - } } From 97cee7d0a46b2b26d2d15d62ebee791096ecbe58 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Apr 2018 07:30:26 -0700 Subject: [PATCH 0786/1283] fix #1576, hopefully Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_util.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index e8a1c5139..88b4c398d 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -31,6 +31,7 @@ Revision History: #include "muz/base/dl_rule.h" #include "muz/base/dl_util.h" #include "util/stopwatch.h" +#include namespace datalog { @@ -623,9 +624,9 @@ namespace datalog { bool string_to_uint64(const char * s, uint64_t & res) { #if _WINDOWS - int converted = sscanf_s(s, "%I64u", &res); + int converted = sscanf_s(s, "%" SCNu64, &res); #else - int converted = sscanf(s, "%I64u", &res); + int converted = sscanf(s, "%" SCNu64, &res); #endif if(converted==0) { return false; From 393d25f661024677fd5d80b8fd3a3e476de8afd6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Apr 2018 21:12:43 -0700 Subject: [PATCH 0787/1283] add web assembly link Signed-off-by: Nikolaj Bjorner --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 8ebf6a078..54804175d 100644 --- a/README.md +++ b/README.md @@ -189,3 +189,7 @@ python -c 'import z3; print(z3.get_version_string())' See [``examples/python``](examples/python) for examples. +### ``Web Assembly`` + +[WebAssembly](https://github.com/cpitclaudel/z3.wasm) +Web Assembly bindings are provided by Clément Pit-Claudel. From b79440a21d404bcf0c2e34e83f1c04555342cfb9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 18 Apr 2018 21:13:24 -0700 Subject: [PATCH 0788/1283] add web assembly link Signed-off-by: Nikolaj Bjorner --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 54804175d..447034a84 100644 --- a/README.md +++ b/README.md @@ -191,5 +191,4 @@ See [``examples/python``](examples/python) for examples. ### ``Web Assembly`` -[WebAssembly](https://github.com/cpitclaudel/z3.wasm) -Web Assembly bindings are provided by Clément Pit-Claudel. +[WebAssembly](https://github.com/cpitclaudel/z3.wasm) bindings are provided by Clément Pit-Claudel. From f22abaa7135f46953211fc304aa51e938e0d0948 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 20 Apr 2018 11:44:30 +0300 Subject: [PATCH 0789/1283] enable patterns on equality, add trace for variables for axiom profiling. Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 7 ++++++- src/parsers/util/pattern_validation.cpp | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 7e143e1a3..12ca136c5 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2254,7 +2254,12 @@ var * ast_manager::mk_var(unsigned idx, sort * s) { unsigned sz = var::get_obj_size(); void * mem = allocate_node(sz); var * new_node = new (mem) var(idx, s); - return register_node(new_node); + var * r = register_node(new_node); + + if (m_trace_stream && r == new_node) { + *m_trace_stream << "[mk-var] #" << r->get_id() << "\n"; + } + return r; } app * ast_manager::mk_label(bool pos, unsigned num_names, symbol const * names, expr * n) { diff --git a/src/parsers/util/pattern_validation.cpp b/src/parsers/util/pattern_validation.cpp index 0d076aadd..df1f6cd00 100644 --- a/src/parsers/util/pattern_validation.cpp +++ b/src/parsers/util/pattern_validation.cpp @@ -48,7 +48,7 @@ struct pattern_validation_functor { bool is_forbidden(func_decl const * decl) { family_id fid = decl->get_family_id(); - if (fid == m_bfid && decl->get_decl_kind() != OP_TRUE && decl->get_decl_kind() != OP_FALSE) + if (fid == m_bfid && decl->get_decl_kind() != OP_EQ && decl->get_decl_kind() != OP_TRUE && decl->get_decl_kind() != OP_FALSE) return true; if (fid == m_lfid) return true; From 279f1986a6e2d337c7ed5eb2d5033696906e846c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Apr 2018 07:11:15 +0200 Subject: [PATCH 0790/1283] fix #1575, fix #1585 Signed-off-by: Nikolaj Bjorner --- src/ast/pattern/expr_pattern_match.cpp | 2 +- src/cmd_context/cmd_context.cpp | 7 ++++--- src/smt/theory_seq.cpp | 11 +++++++++-- src/smt/theory_seq.h | 13 +++++++------ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/ast/pattern/expr_pattern_match.cpp b/src/ast/pattern/expr_pattern_match.cpp index d688c840c..c441fb4ce 100644 --- a/src/ast/pattern/expr_pattern_match.cpp +++ b/src/ast/pattern/expr_pattern_match.cpp @@ -387,7 +387,7 @@ expr_pattern_match::initialize(char const * spec_string) { m_instrs.push_back(instr(BACKTRACK)); std::istringstream is(spec_string); - cmd_context ctx(true, &m_manager); + cmd_context ctx(true, &m_manager); bool ps = ctx.print_success_enabled(); ctx.set_print_success(false); VERIFY(parse_smt2_commands(ctx, is)); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 6ae63a1a6..11f800b25 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -718,8 +718,8 @@ void cmd_context::init_manager_core(bool new_manager) { } m_dt_eh = alloc(dt_eh, *this); m_pmanager->set_new_datatype_eh(m_dt_eh.get()); - if (!has_logic()) { - TRACE("cmd_context", tout << "init manager\n";); + if (!has_logic() && new_manager) { + TRACE("cmd_context", tout << "init manager " << m_logic << "\n";); // add list type only if the logic is not specified. // it prevents clashes with builtin types. insert(pm().mk_plist_decl()); @@ -757,6 +757,7 @@ void cmd_context::init_external_manager() { } bool cmd_context::set_logic(symbol const & s) { + TRACE("cmd_context", tout << s << "\n";); if (has_logic()) throw cmd_exception("the logic has already been set"); if (has_manager() && m_main_ctx) @@ -1240,7 +1241,7 @@ void cmd_context::insert_aux_pdecl(pdecl * p) { m_aux_pdecls.push_back(p); } -void cmd_context::reset(bool finalize) { +void cmd_context::reset(bool finalize) { m_processing_pareto = false; m_logic = symbol::null; m_check_sat_result = nullptr; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 94841603d..ff5bb4486 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1473,7 +1473,7 @@ bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) { if (l == r) { return false; } - TRACE("seq", tout << mk_pp(l, m) << " ==> " << mk_pp(r, m) << "\n";); + TRACE("seq", tout << mk_pp(l, m) << " ==> " << mk_pp(r, m) << "\n"; display_deps(tout, deps);); m_new_solution = true; m_rep.update(l, r, deps); enode* n1 = ensure_enode(l); @@ -1513,7 +1513,9 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de change = canonize(r, rs, dep2) || change; deps = m_dm.mk_join(dep2, deps); TRACE("seq", tout << l << " = " << r << " ==> "; - tout << ls << " = " << rs << "\n";); + tout << ls << " = " << rs << "\n"; + display_deps(tout, deps); + ); if (!ctx.inconsistent() && simplify_eq(ls, rs, deps)) { return true; } @@ -2674,7 +2676,12 @@ void theory_seq::init_model(expr_ref_vector const& es) { } } +void theory_seq::finalize_model(model_generator& mg) { + m_rep.pop_scope(1); +} + void theory_seq::init_model(model_generator & mg) { + m_rep.push_scope(); m_factory = alloc(seq_factory, get_manager(), get_family_id(), mg.get_model()); mg.register_factory(m_factory); for (ne const& n : m_nqs) { diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 21aedd7e3..a17b29eba 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -64,14 +64,14 @@ namespace smt { // + a cache for normalization. class solution_map { enum map_update { INS, DEL }; - ast_manager& m; + ast_manager& m; dependency_manager& m_dm; - eqdep_map_t m_map; - eval_cache m_cache; - expr_ref_vector m_lhs, m_rhs; + eqdep_map_t m_map; + eval_cache m_cache; + expr_ref_vector m_lhs, m_rhs; ptr_vector m_deps; - svector m_updates; - unsigned_vector m_limit; + svector m_updates; + unsigned_vector m_limit; void add_trail(map_update op, expr* l, expr* r, dependency* d); public: @@ -362,6 +362,7 @@ namespace smt { void collect_statistics(::statistics & st) const override; model_value_proc * mk_value(enode * n, model_generator & mg) override; void init_model(model_generator & mg) override; + void finalize_model(model_generator & mg) override; void init_search_eh() override; void init_model(expr_ref_vector const& es); From 0b4e54be38c73c65bf51184828fae54f07f162cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Apr 2018 07:15:04 +0200 Subject: [PATCH 0791/1283] fix #1583 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 186abda48..e5cac969f 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -367,6 +367,9 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con SASSERT(num_args == 2); return mk_re_concat(args[0], args[1], result); case OP_RE_UNION: + if (num_args == 1) { + result = args[0]; return BR_DONE; + } SASSERT(num_args == 2); return mk_re_union(args[0], args[1], result); case OP_RE_RANGE: From 480e1c4daba6a9f5cae5a7c12010613e88584cae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Apr 2018 07:20:24 +0200 Subject: [PATCH 0792/1283] add warning message for optimization with quantifiers. Fix #1580 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 1950a199d..69177e290 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -265,6 +265,9 @@ namespace opt { normalize(); internalize(); update_solver(); + if (contains_quantifiers()) { + warning_msg("optimization with quantified constraints is not supported"); + } #if 0 if (is_qsat_opt()) { return run_qsat_opt(); @@ -368,7 +371,6 @@ namespace opt { if (result == l_true && committed) m_optsmt.commit_assignment(index); if (result == l_true && m_optsmt.is_unbounded(index, is_max) && contains_quantifiers()) { throw default_exception("unbounded objectives on quantified constraints is not supported"); - result = l_undef; } return result; } From 19bb883263d6c38fe6e8af85fcbc0a9c32f27149 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Apr 2018 12:12:39 +0200 Subject: [PATCH 0793/1283] fix #1581 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ff5bb4486..db8dbd340 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2360,9 +2360,21 @@ bool theory_seq::check_int_string() { void theory_seq::add_stoi_axiom(expr* e) { TRACE("seq", tout << mk_pp(e, m) << "\n";); - SASSERT(m_util.str.is_stoi(e)); - literal l = mk_simplified_literal(m_autil.mk_ge(e, arith_util(m).mk_int(-1))); + expr* s = nullptr; + VERIFY (m_util.str.is_stoi(e, s)); + + // stoi(s) >= -1 + literal l = mk_simplified_literal(m_autil.mk_ge(e, m_autil.mk_int(-1))); add_axiom(l); + + // stoi(s) >= 0 <=> s in (0-9)+ + expr_ref num_re(m); + num_re = m_util.re.mk_range(m_util.str.mk_string(symbol("0")), m_util.str.mk_string(symbol("9"))); + num_re = m_util.re.mk_plus(num_re); + app_ref in_re(m_util.re.mk_in_re(s, num_re), m); + literal ge0 = mk_simplified_literal(m_autil.mk_ge(e, m_autil.mk_int(0))); + add_axiom(~ge0, mk_literal(in_re)); + add_axiom(ge0, ~mk_literal(in_re)); } bool theory_seq::add_stoi_val_axiom(expr* e) { @@ -2406,8 +2418,9 @@ bool theory_seq::add_stoi_val_axiom(expr* e) { lits.push_back(~is_digit(ith_char)); nums.push_back(digit2int(ith_char)); } - for (unsigned i = sz, c = 1; i-- > 0; c *= 10) { - coeff = m_autil.mk_int(c); + rational c(1); + for (unsigned i = sz; i-- > 0; c *= rational(10)) { + coeff = m_autil.mk_numeral(c, true); nums[i] = m_autil.mk_mul(coeff, nums[i].get()); } num = m_autil.mk_add(nums.size(), nums.c_ptr()); @@ -3482,8 +3495,8 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { literal_vector lits; lits.push_back(~lit); - for (unsigned i = 0; i < states.size(); ++i) { - lits.push_back(mk_accept(e1, zero, e3, states[i])); + for (unsigned s : states) { + lits.push_back(mk_accept(e1, zero, e3, s)); } if (lits.size() == 2) { propagate_lit(nullptr, 1, &lit, lits[1]); From 5166b96d206dcb03e358d3aaeaae06123f8281cd Mon Sep 17 00:00:00 2001 From: bannsec Date: Mon, 23 Apr 2018 17:17:51 -0400 Subject: [PATCH 0794/1283] Fancy dots are not allowed here!! --- src/smt/theory_datatype.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 9ff81fa08..049555297 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -461,7 +461,7 @@ namespace smt { TRACE("datatype", tout << "occurs_check_explain " << mk_bounded_pp(app->get_owner(), get_manager()) << " <-> " << mk_bounded_pp(root->get_owner(), get_manager()) << "\n";); enode* app_parent = nullptr; - // first: explain that root=v, given that app=cstor(…,v,…) + // first: explain that root=v, given that app=cstor(...,v,...) for (enode * arg : enode::args(oc_get_cstor(app))) { // found an argument which is equal to root if (arg->get_root() == root->get_root()) { From a1d870f19f6638432eb5f15f0f1a59319a9927ab Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 24 Apr 2018 12:43:11 +0100 Subject: [PATCH 0795/1283] Added tactic for QF_FPLRA --- src/solver/smt_logics.cpp | 11 ++-- src/tactic/fpa/qffplra_tactic.cpp | 72 +++++++++++++++++++++++++ src/tactic/fpa/qffplra_tactic.h | 38 +++++++++++++ src/tactic/portfolio/default_tactic.cpp | 12 +++-- 4 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 src/tactic/fpa/qffplra_tactic.cpp create mode 100644 src/tactic/fpa/qffplra_tactic.h diff --git a/src/solver/smt_logics.cpp b/src/solver/smt_logics.cpp index 874f1cfcc..7ed2b0445 100644 --- a/src/solver/smt_logics.cpp +++ b/src/solver/smt_logics.cpp @@ -22,14 +22,14 @@ Revision History: bool smt_logics::supported_logic(symbol const & s) { - return logic_has_uf(s) || logic_is_all(s) || logic_has_fd(s) || + return logic_has_uf(s) || logic_is_all(s) || logic_has_fd(s) || logic_has_arith(s) || logic_has_bv(s) || logic_has_array(s) || logic_has_seq(s) || logic_has_str(s) || logic_has_horn(s) || logic_has_fpa(s); } bool smt_logics::logic_has_reals_only(symbol const& s) { - return + return s == "QF_RDL" || s == "QF_LRA" || s == "UFLRA" || @@ -84,8 +84,9 @@ bool smt_logics::logic_has_arith(symbol const & s) { s == "QF_BVFP" || s == "QF_S" || s == "ALL" || - s == "QF_FD" || - s == "HORN"; + s == "QF_FD" || + s == "HORN" || + s == "QF_FPLRA"; } bool smt_logics::logic_has_bv(symbol const & s) { @@ -137,7 +138,7 @@ bool smt_logics::logic_has_str(symbol const & s) { } bool smt_logics::logic_has_fpa(symbol const & s) { - return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || s == "ALL"; + return s == "QF_FP" || s == "QF_FPBV" || s == "QF_BVFP" || s == "QF_FPLRA" || s == "ALL"; } bool smt_logics::logic_has_uf(symbol const & s) { diff --git a/src/tactic/fpa/qffplra_tactic.cpp b/src/tactic/fpa/qffplra_tactic.cpp new file mode 100644 index 000000000..947a41111 --- /dev/null +++ b/src/tactic/fpa/qffplra_tactic.cpp @@ -0,0 +1,72 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + qffpalra_tactic.cpp + +Abstract: + + Tactic for QF_FPLRA benchmarks. + +Author: + + Christoph (cwinter) 2018-04-24 + +Notes: + +--*/ +#include "tactic/tactical.h" +#include "tactic/fpa/qffp_tactic.h" +#include "tactic/fpa/qffplra_tactic.h" + +tactic * mk_qffplra_tactic(ast_manager & m, params_ref const & p) { + tactic * st = mk_qffp_tactic(m, p); + st->updt_params(p); + return st; +} + +struct is_non_qffplra_predicate { + struct found {}; + ast_manager & m; + bv_util bu; + fpa_util fu; + arith_util au; + + is_non_qffplra_predicate(ast_manager & _m) : m(_m), bu(m), fu(m), au(m) {} + + void operator()(var *) { throw found(); } + + void operator()(quantifier *) { throw found(); } + + void operator()(app * n) { + sort * s = get_sort(n); + if (!m.is_bool(s) && !fu.is_float(s) && !fu.is_rm(s) && !bu.is_bv_sort(s) && !au.is_real(s)) + throw found(); + family_id fid = n->get_family_id(); + if (fid == m.get_basic_family_id() || + fid == fu.get_family_id() || + fid == bu.get_family_id() || + fid == au.get_family_id()) + return; + if (is_uninterp_const(n)) + return; + if (au.is_real(s)) + return; + + throw found(); + } +}; + +class is_qffplra_probe : public probe { +public: + result operator()(goal const & g) override { + return !test(g); + } + + ~is_qffplra_probe() override {} +}; + +probe * mk_is_qffplra_probe() { + return alloc(is_qffplra_probe); +} diff --git a/src/tactic/fpa/qffplra_tactic.h b/src/tactic/fpa/qffplra_tactic.h new file mode 100644 index 000000000..b5a741ac3 --- /dev/null +++ b/src/tactic/fpa/qffplra_tactic.h @@ -0,0 +1,38 @@ +#pragma once +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + qffplra_tactic.h + +Abstract: + + Tactic for QF_FPLRA benchmarks. + +Author: + + Christoph (cwinter) 2018-04-24 + +Notes: + + +--*/ +#ifndef QFFPLRA_TACTIC_H_ +#define QFFPLRA_TACTIC_H_ + +#include "util/params.h" +class ast_manager; +class tactic; + +tactic * mk_qffplra_tactic(ast_manager & m, params_ref const & p = params_ref()); +/* +ADD_TACTIC("qffplra", "(try to) solve goal using the tactic for QF_FPLRA.", "mk_qffplra_tactic(m, p)") +*/ + +probe * mk_is_qffplra_probe(); +/* +ADD_PROBE("is-qffplra", "true if the goal is in QF_FPLRA.", "mk_is_qffplra_probe()") +*/ + +#endif diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 09052869b..5cf06ca86 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -28,24 +28,26 @@ Notes: #include "tactic/arith/probe_arith.h" #include "tactic/smtlogics/quant_tactics.h" #include "tactic/fpa/qffp_tactic.h" +#include "tactic/fpa/qffplra_tactic.h" #include "tactic/smtlogics/qfaufbv_tactic.h" #include "tactic/smtlogics/qfauflia_tactic.h" #include "tactic/smtlogics/qfufnra_tactic.h" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), - cond(mk_is_qfbv_probe(), mk_qfbv_tactic(m), - cond(mk_is_qfaufbv_probe(), mk_qfaufbv_tactic(m), + cond(mk_is_qfbv_probe(), mk_qfbv_tactic(m), + cond(mk_is_qfaufbv_probe(), mk_qfaufbv_tactic(m), cond(mk_is_qflia_probe(), mk_qflia_tactic(m), cond(mk_is_qfauflia_probe(), mk_qfauflia_tactic(m), cond(mk_is_qflra_probe(), mk_qflra_tactic(m), cond(mk_is_qfnra_probe(), mk_qfnra_tactic(m), cond(mk_is_qfnia_probe(), mk_qfnia_tactic(m), - cond(mk_is_lira_probe(), mk_lira_tactic(m, p), - cond(mk_is_nra_probe(), mk_nra_tactic(m), + cond(mk_is_lira_probe(), mk_lira_tactic(m, p), + cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), + cond(mk_is_qffplra_probe(), mk_qffplra_tactic(m, p), //cond(mk_is_qfufnra_probe(), mk_qfufnra_tactic(m, p), - mk_smt_tactic()))))))))))), + mk_smt_tactic())))))))))))), p); return st; } From e13f3d92af517c6caeceec77f7bdaf4560323a17 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 24 Apr 2018 15:01:05 +0100 Subject: [PATCH 0796/1283] Updated CMakelists.txt --- src/tactic/fpa/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tactic/fpa/CMakeLists.txt b/src/tactic/fpa/CMakeLists.txt index a54212235..c647df7fc 100644 --- a/src/tactic/fpa/CMakeLists.txt +++ b/src/tactic/fpa/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(fpa_tactics fpa2bv_model_converter.cpp fpa2bv_tactic.cpp qffp_tactic.cpp + qffplra_tactic.cpp COMPONENT_DEPENDENCIES arith_tactics bv_tactics @@ -14,4 +15,5 @@ z3_add_component(fpa_tactics TACTIC_HEADERS fpa2bv_tactic.h qffp_tactic.h + qffplra_tactic.h ) From f7bcf0fd585e3fd7c294d63307356d7357ea3383 Mon Sep 17 00:00:00 2001 From: yxliang01 <13267.okk@gmail.com> Date: Tue, 24 Apr 2018 08:17:20 -0700 Subject: [PATCH 0797/1283] Z3 now will also try to find libz3 in PYTHONPATH --- scripts/update_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 8a7b33efd..78fad45be 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1657,7 +1657,7 @@ else: if hasattr(builtins, "Z3_LIB_DIRS"): _all_dirs = builtins.Z3_LIB_DIRS -for v in ('Z3_LIBRARY_PATH', 'PATH'): +for v in ('Z3_LIBRARY_PATH', 'PATH', 'PYTHONPATH'): if v in os.environ: lp = os.environ[v]; lds = lp.split(';') if sys.platform in ('win32') else lp.split(':') From ab8d3cdc447e278465563294d44c73ea29d098af Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Tue, 24 Apr 2018 17:59:21 +0100 Subject: [PATCH 0798/1283] WMax conflict budget bug fix --- src/opt/opt_context.cpp | 4 ++-- src/opt/opt_params.pyg | 2 +- src/opt/wmax.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2f6bad9e8..4bbbc3865 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -398,10 +398,10 @@ namespace opt { /** \brief there is no need to use push/pop when all objectives are maxsat and engine - is maxres. + is maxres or mss. */ bool context::scoped_lex() { - if (m_maxsat_engine == symbol("maxres")) { + if (m_maxsat_engine == symbol("maxres") || m_maxsat_engine == symbol("mss")) { for (unsigned i = 0; i < m_objectives.size(); ++i) { if (m_objectives[i].m_type != O_MAXSMT) return true; } diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 41548452a..e06836f61 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,7 +3,7 @@ def_module_params('opt', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'mss'"), - ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), + ('priority', SYMBOL, 'lex', "select how to prioritize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('solution_prefix', SYMBOL, '', "path prefix to dump intermediary, but non-optimal, solutions"), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 52b87e536..513c68d6e 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -84,6 +84,9 @@ namespace opt { if (m.canceled()) { is_sat = l_undef; } + if (is_sat == l_undef) { + break; + } if (is_sat == l_false) { TRACE("opt", tout << "Unsat\n";); break; @@ -97,9 +100,6 @@ namespace opt { //DEBUG_CODE(verify_cores(cores);); s().assert_expr(fml); } - else { - //DEBUG_CODE(verify_cores(cores);); - } update_cores(wth(), cores); wth().init_min_cost(m_upper - m_lower); trace_bounds("wmax"); From b5f067bec539b6cad0987b7b0edb8a1bb721ac61 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Apr 2018 11:18:24 +0200 Subject: [PATCH 0799/1283] fix #1592 #1587 Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_util.cpp | 3 + src/smt/theory_seq.cpp | 143 ++++++-------------------------------- src/smt/theory_seq.h | 1 - src/util/scoped_timer.cpp | 24 ++++--- 4 files changed, 42 insertions(+), 129 deletions(-) diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 88b4c398d..87cfac04c 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -31,6 +31,9 @@ Revision History: #include "muz/base/dl_rule.h" #include "muz/base/dl_util.h" #include "util/stopwatch.h" +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif #include namespace datalog { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index db8dbd340..95f804863 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -134,8 +134,7 @@ void theory_seq::solution_map::pop_scope(unsigned num_scopes) { if (num_scopes == 0) return; m_cache.reset(); unsigned start = m_limit[m_limit.size() - num_scopes]; - for (unsigned i = m_updates.size(); i > start; ) { - --i; + for (unsigned i = m_updates.size(); i-- > start; ) { if (m_updates[i] == INS) { m_map.remove(m_lhs[i].get()); } @@ -436,8 +435,8 @@ bool theory_seq::is_unit_eq(expr_ref_vector const& ls, expr_ref_vector const& rs if (ls.empty() || !is_var(ls[0])) { return false; } - for (unsigned i = 0; i < rs.size(); ++i) { - if (!m_util.str.is_unit(rs[i])) { + for (expr* r : rs) { + if (!m_util.str.is_unit(r)) { return false; } } @@ -482,8 +481,7 @@ void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector bool theory_seq::branch_variable_mb() { bool change = false; - for (unsigned i = 0; i < m_eqs.size(); ++i) { - eq const& e = m_eqs[i]; + for (eq const& e : m_eqs) { vector len1, len2; if (!is_complex(e)) { continue; @@ -2226,63 +2224,7 @@ void theory_seq::internalize_eq_eh(app * atom, bool_var v) { } bool theory_seq::internalize_atom(app* a, bool) { -#if 1 return internalize_term(a); -#else - if (is_skolem(m_eq, a)) { - return internalize_term(a); - } - context & ctx = get_context(); - bool_var bv = ctx.mk_bool_var(a); - ctx.set_var_theory(bv, get_id()); - ctx.mark_as_relevant(bv); - - expr* e1, *e2; - if (m_util.str.is_in_re(a, e1, e2)) { - return internalize_term(to_app(e1)) && internalize_re(e2); - } - if (m_util.str.is_contains(a, e1, e2) || - m_util.str.is_prefix(a, e1, e2) || - m_util.str.is_suffix(a, e1, e2)) { - return internalize_term(to_app(e1)) && internalize_term(to_app(e2)); - } - if (is_accept(a) || is_reject(a) || is_step(a) || is_skolem(symbol("seq.is_digit"), a)) { - return true; - } - UNREACHABLE(); - return internalize_term(a); -#endif -} - -bool theory_seq::internalize_re(expr* e) { - expr* e1, *e2; - unsigned lc, uc; - if (m_util.re.is_to_re(e, e1)) { - return internalize_term(to_app(e1)); - } - if (m_util.re.is_star(e, e1) || - m_util.re.is_plus(e, e1) || - m_util.re.is_opt(e, e1) || - m_util.re.is_loop(e, e1, lc) || - m_util.re.is_loop(e, e1, lc, uc) || - m_util.re.is_complement(e, e1)) { - return internalize_re(e1); - } - if (m_util.re.is_union(e, e1, e2) || - m_util.re.is_intersection(e, e1, e2) || - m_util.re.is_concat(e, e1, e2)) { - return internalize_re(e1) && internalize_re(e2); - } - if (m_util.re.is_full_seq(e) || - m_util.re.is_full_char(e) || - m_util.re.is_empty(e)) { - return true; - } - if (m_util.re.is_range(e, e1, e2)) { - return internalize_term(to_app(e1)) && internalize_term(to_app(e2)); - } - UNREACHABLE(); - return internalize_term(to_app(e)); } bool theory_seq::internalize_term(app* term) { @@ -2346,8 +2288,8 @@ void theory_seq::add_int_string(expr* e) { bool theory_seq::check_int_string() { bool change = false; - for (unsigned i = 0; i < m_int_string.size(); ++i) { - expr* e = m_int_string[i].get(), *n; + for (expr * e : m_int_string) { + expr* n = nullptr; if (m_util.str.is_itos(e) && add_itos_val_axiom(e)) { change = true; } @@ -3448,8 +3390,8 @@ void theory_seq::add_itos_length_axiom(expr* len) { void theory_seq::propagate_in_re(expr* n, bool is_true) { TRACE("seq", tout << mk_pp(n, m) << " <- " << (is_true?"true":"false") << "\n";); - expr* e1 = nullptr, *e2 = nullptr; - VERIFY(m_util.str.is_in_re(n, e1, e2)); + expr* s = nullptr, *re = nullptr; + VERIFY(m_util.str.is_in_re(n, s, re)); expr_ref tmp(n, m); m_rewrite(tmp); @@ -3470,21 +3412,21 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { return; } - expr_ref e3(e2, m); + expr_ref e3(re, m); context& ctx = get_context(); literal lit = ctx.get_literal(n); if (!is_true) { - e3 = m_util.re.mk_complement(e2); + e3 = m_util.re.mk_complement(re); lit.neg(); } eautomaton* a = get_automaton(e3); if (!a) return; - expr_ref len(m_util.str.mk_length(e1), m); + expr_ref len(m_util.str.mk_length(s), m); for (unsigned i = 0; i < a->num_states(); ++i) { - literal acc = mk_accept(e1, len, e3, i); - literal rej = mk_reject(e1, len, e3, i); + literal acc = mk_accept(s, len, e3, i); + literal rej = mk_reject(s, len, e3, i); add_axiom(a->is_final_state(i)?acc:~acc); add_axiom(a->is_final_state(i)?~rej:rej); } @@ -3495,8 +3437,8 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { literal_vector lits; lits.push_back(~lit); - for (unsigned s : states) { - lits.push_back(mk_accept(e1, zero, e3, s)); + for (unsigned st : states) { + lits.push_back(mk_accept(s, zero, e3, st)); } if (lits.size() == 2) { propagate_lit(nullptr, 1, &lit, lits[1]); @@ -3547,8 +3489,8 @@ static bool get_arith_value(context& ctx, theory_id afid, expr* e, expr_ref& v) bool theory_seq::get_num_value(expr* e, rational& val) const { context& ctx = get_context(); expr_ref _val(m); - if (!ctx.e_internalized(e)) - return false; + if (!ctx.e_internalized(e)) + return false; enode* next = ctx.get_enode(e), *n = next; do { if (get_arith_value(ctx, m_autil.get_family_id(), next->get_owner(), _val) && m_autil.is_numeral(_val, val) && val.is_int()) { @@ -3945,8 +3887,8 @@ theory_seq::dependency* theory_seq::mk_join(dependency* deps, literal lit) { } theory_seq::dependency* theory_seq::mk_join(dependency* deps, literal_vector const& lits) { - for (unsigned i = 0; i < lits.size(); ++i) { - deps = mk_join(deps, lits[i]); + for (literal l : lits) { + deps = mk_join(deps, l); } return deps; } @@ -4151,53 +4093,15 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { TRACE("seq", tout << "new disequality " << get_context().get_scope_level() << ": " << eq << "\n";); m_rewrite(eq); if (!m.is_false(eq)) { - literal lit = mk_eq(e1, e2, false); - if (m_util.str.is_empty(e2)) { std::swap(e1, e2); } - if (false && m_util.str.is_empty(e1)) { - expr_ref head(m), tail(m), conc(m); - mk_decompose(e2, head, tail); - conc = mk_concat(head, tail); - propagate_eq(~lit, e2, conc, true); - } -#if 0 - - // (e1 = "" & e2 = xdz) or (e2 = "" & e1 = xcy) or (e1 = xcy & e2 = xdz & c != d) or (e1 = x & e2 = xdz) or (e2 = x & e1 = xcy) - // e1 = "" or e1 = xcy or e1 = x - // e2 = "" or e2 = xdz or e2 = x - // e1 = xcy or e2 = xdz - // c != d - - sort* char_sort = 0; - expr_ref emp(m); - VERIFY(m_util.is_seq(m.get_sort(e1), char_sort)); - emp = m_util.str.mk_empty(m.get_sort(e1)); - - expr_ref x = mk_skolem(symbol("seq.ne.x"), e1, e2); - expr_ref y = mk_skolem(symbol("seq.ne.y"), e1, e2); - expr_ref z = mk_skolem(symbol("seq.ne.z"), e1, e2); - expr_ref c = mk_skolem(symbol("seq.ne.c"), e1, e2, 0, char_sort); - expr_ref d = mk_skolem(symbol("seq.ne.d"), e1, e2, 0, char_sort); - literal e1_is_emp = mk_seq_eq(e1, emp); - literal e2_is_emp = mk_seq_eq(e2, emp); - literal e1_is_xcy = mk_seq_eq(e1, mk_concat(x, m_util.str.mk_unit(c), y)); - literal e2_is_xdz = mk_seq_eq(e2, mk_concat(x, m_util.str.mk_unit(d), z)); - add_axiom(lit, e1_is_emp, e1_is_xcy, mk_seq_eq(e1, x)); - add_axiom(lit, e2_is_emp, e2_is_xdz, mk_seq_eq(e2, x)); - add_axiom(lit, e1_is_xcy, e2_is_xdz); - add_axiom(lit, ~mk_eq(c, d, false)); -#else - else { - dependency* dep = m_dm.mk_leaf(assumption(~lit)); - m_nqs.push_back(ne(e1, e2, dep)); - solve_nqs(m_nqs.size() - 1); - } -#endif + dependency* dep = m_dm.mk_leaf(assumption(~lit)); + m_nqs.push_back(ne(e1, e2, dep)); + solve_nqs(m_nqs.size() - 1); } } @@ -4528,8 +4432,7 @@ bool theory_seq::add_reject2reject(expr* rej, bool& change) { ensure_nth(~len_le_idx, s, idx); literal_vector eqs; bool has_undef = false; - for (unsigned i = 0; i < mvs.size(); ++i) { - eautomaton::move const& mv = mvs[i]; + for (eautomaton::move const& mv : mvs) { literal eq = mk_literal(mv.t()->accept(nth)); switch (ctx.get_assignment(eq)) { case l_false: diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index a17b29eba..b6b553dec 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -390,7 +390,6 @@ namespace smt { vector const& ll, vector const& rl); bool set_empty(expr* x); bool is_complex(eq const& e); - bool internalize_re(expr* e); bool check_extensionality(); bool check_contains(); diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index a2a0cc269..56d40c47a 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -208,14 +208,22 @@ struct scoped_timer::imp { pthread_cond_signal(&m_condition_var); pthread_mutex_unlock(&m_mutex); - if (pthread_join(m_thread_id, nullptr) != 0) - throw default_exception("failed to join thread"); - if (pthread_mutex_destroy(&m_mutex) != 0) - throw default_exception("failed to destroy pthread mutex"); - if (pthread_cond_destroy(&m_condition_var) != 0) - throw default_exception("failed to destroy pthread condition variable"); - if (pthread_attr_destroy(&m_attributes) != 0) - throw default_exception("failed to destroy pthread attributes object"); + if (pthread_join(m_thread_id, nullptr) != 0) { + warning_msg("failed to join thread"); + return; + } + if (pthread_mutex_destroy(&m_mutex) != 0) { + warning_msg("failed to destroy pthread mutex"); + return; + } + if (pthread_cond_destroy(&m_condition_var) != 0) { + warning_msg("failed to destroy pthread condition variable"); + return; + } + if (pthread_attr_destroy(&m_attributes) != 0) { + warning_msg("failed to destroy pthread attributes object"); + return; + } #elif defined(_LINUX_) || defined(_FREEBSD_) || defined(_NETBSD_) // Linux & FreeBSD & NetBSD bool init = false; From cf2258a536287cb13cefb882e1277a035d715996 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Apr 2018 08:39:35 +0200 Subject: [PATCH 0800/1283] fix #1594 Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index b592b719a..381339768 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -256,6 +256,7 @@ bool zstring::contains(zstring const& other) const { int zstring::indexof(zstring const& other, int offset) const { SASSERT(offset >= 0); + if (static_cast(offset) <= length() && other.length() == 0) return offset; if (static_cast(offset) == length()) return -1; if (other.length() + offset > length()) return -1; unsigned last = length() - other.length(); From a04921dafe04c3be3a02ca8ba2a90d8213c1309a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Apr 2018 08:47:05 +0200 Subject: [PATCH 0801/1283] fix #1595 Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 381339768..cd8571a95 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -177,7 +177,7 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const { return zstring(*this); } if (src.length() == 0) { - return zstring(*this); + return dst + zstring(*this); } bool found = false; for (unsigned i = 0; i < length(); ++i) { From 74292a48e5b8e0a6ebfa47b5f42ea67f13bd602c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Apr 2018 09:08:34 +0200 Subject: [PATCH 0802/1283] change order of concatentation for empty string, #1595 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index e5cac969f..3ead59833 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -856,7 +856,7 @@ br_status seq_rewriter::mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& resu return BR_DONE; } if (m_util.str.is_string(b, s2) && s2.length() == 0) { - result = m_util.str.mk_concat(a, c); + result = m_util.str.mk_concat(c, a); return BR_REWRITE1; } if (m_util.str.is_string(a, s1) && s1.length() == 0) { From 047f6c558c156ebe5e116c7d9f26e70026007336 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 26 Apr 2018 16:36:14 -0400 Subject: [PATCH 0803/1283] fix memory leak related to #1575 --- src/smt/theory_str.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0f9d42b3d..126594b06 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -8096,7 +8096,7 @@ namespace smt { rational nn1Len, nn2Len; bool nn1Len_exists = get_len_value(lhs, nn1Len); bool nn2Len_exists = get_len_value(rhs, nn2Len); - expr * emptyStr = mk_string(""); + expr_ref emptyStr(mk_string(""), m); if (nn1Len_exists && nn1Len.is_zero()) { if (!in_same_eqc(lhs, emptyStr) && rhs != emptyStr) { From 37852807b0fa0fb0ee1799dbc2c46df46b89ac47 Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Thu, 26 Apr 2018 22:39:45 +0100 Subject: [PATCH 0804/1283] Revert "WMax conflict budget bug fix" This reverts commit ab8d3cdc447e278465563294d44c73ea29d098af. --- src/opt/opt_context.cpp | 4 ++-- src/opt/opt_params.pyg | 2 +- src/opt/wmax.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 4bbbc3865..2f6bad9e8 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -398,10 +398,10 @@ namespace opt { /** \brief there is no need to use push/pop when all objectives are maxsat and engine - is maxres or mss. + is maxres. */ bool context::scoped_lex() { - if (m_maxsat_engine == symbol("maxres") || m_maxsat_engine == symbol("mss")) { + if (m_maxsat_engine == symbol("maxres")) { for (unsigned i = 0; i < m_objectives.size(); ++i) { if (m_objectives[i].m_type != O_MAXSMT) return true; } diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index e06836f61..41548452a 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,7 +3,7 @@ def_module_params('opt', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'mss'"), - ('priority', SYMBOL, 'lex', "select how to prioritize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), + ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('solution_prefix', SYMBOL, '', "path prefix to dump intermediary, but non-optimal, solutions"), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 513c68d6e..52b87e536 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -84,9 +84,6 @@ namespace opt { if (m.canceled()) { is_sat = l_undef; } - if (is_sat == l_undef) { - break; - } if (is_sat == l_false) { TRACE("opt", tout << "Unsat\n";); break; @@ -100,6 +97,9 @@ namespace opt { //DEBUG_CODE(verify_cores(cores);); s().assert_expr(fml); } + else { + //DEBUG_CODE(verify_cores(cores);); + } update_cores(wth(), cores); wth().init_min_cost(m_upper - m_lower); trace_bounds("wmax"); From bf2a031f7bb728aaabbc2103df75f684c516c0f6 Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Thu, 26 Apr 2018 22:39:55 +0100 Subject: [PATCH 0805/1283] Revert "disjoint cores" This reverts commit e5aa79ba6a1f1e5e5ba38716c71247ccb70c0391. --- src/opt/mss_solver.cpp | 221 ++++++++++++----------------------------- src/opt/opt_params.pyg | 3 +- 2 files changed, 63 insertions(+), 161 deletions(-) diff --git a/src/opt/mss_solver.cpp b/src/opt/mss_solver.cpp index 1ac351855..d27b6300c 100755 --- a/src/opt/mss_solver.cpp +++ b/src/opt/mss_solver.cpp @@ -11,85 +11,45 @@ class mss_solver: public maxsmt_solver_base { private: typedef ptr_vector exprs; - typedef obj_hashtable expr_set; mss m_mss; unsigned m_index; - exprs m_asms; - unsigned m_mss_found; - vector m_cores; - unsigned m_core_idx; - model_ref m_last_model; - exprs m_mss_trail; - exprs m_mcs_trail; - unsigned_vector m_mss_trail_lim; - unsigned_vector m_mcs_trail_lim; + expr_ref_vector m_asms; unsigned m_max_mss; - bool m_disjoint_cores; public: mss_solver(maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft): maxsmt_solver_base(c, ws, soft), m_mss(c.get_solver(), m), m_index(id), - m_mss_found(0), - m_core_idx(0), - m_max_mss(UINT_MAX), - m_disjoint_cores(false) { + m_asms(m), + m_max_mss(UINT_MAX) { } virtual ~mss_solver() {} virtual lbool operator()() { if (!init()) return l_undef; - init_local(); - lbool is_sat = disjoint_cores(); - if (is_sat != l_true) return is_sat; - if (m_cores.size() == 0) return l_true; - update_model(); - exprs asms; - while (true) { - exprs mss, mcs; - mss.append(m_cores[m_core_idx]); - is_sat = cld(m_last_model, mss, mcs); - if (is_sat == l_undef || m.canceled()) return l_undef; - SASSERT(is_sat == l_true); - update_trails(mss, mcs); - if (m_core_idx < m_cores.size()-1) { - m_core_idx++; - } - else { - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << m_mss_trail.size() + m_asms.size() << " :mcs " << m_mcs_trail.size() << ")\n";); - if (++m_mss_found >= m_max_mss) return l_true; - asms.push_back(relax_and_assert(m.mk_or(m_mcs_trail.size(), m_mcs_trail.c_ptr()))); - is_sat = backtrack(asms); - if (is_sat == l_false) { - SASSERT(m_core_idx == 0); - is_sat = disjoint_cores(asms); - } - if (is_sat == l_undef) return l_undef; - if (is_sat == l_false) return l_true; - } + init_asms(); + lbool is_sat = check_sat(m_asms); + if (is_sat == l_undef) return l_undef; + if (is_sat == l_true) { + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << m_asms.size() << " :mcs " << 0 << ")\n";); + model_ref mdl; + s().get_model(mdl); + update_assignment(mdl.get()); + return l_true; } - return l_true; + return enumerate_mss(); } virtual void updt_params(params_ref& p) { maxsmt_solver_base::updt_params(p); opt_params _p(p); m_max_mss = _p.mss_max(); - m_disjoint_cores = _p.mss_disjoint_cores(); } private: - void init_local() { - m_cores.reset(); - m_core_idx = 0; - m_mss_found = 0; - m_last_model.reset(); - m_mss_trail.reset(); - m_mcs_trail.reset(); - m_mss_trail_lim.reset(); - m_mcs_trail_lim.reset(); + void init_asms() { m_asms.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { expr* e = m_soft[i]; @@ -114,84 +74,42 @@ private: return is_uninterp_const(l) || (m.is_not(l, l) && is_uninterp_const(l)); } - lbool disjoint_cores(exprs const& asms) { - expr_set asm_lits, core_lits; - for (unsigned i = 0; i < asms.size(); ++i) { - asm_lits.insert(asms[i]); + lbool enumerate_mss() { + expr_ref_vector asms(m); + for (unsigned i = 0; i < m_max_mss; ++i) { + exprs mss, mcs; + lbool is_sat = next_mss(asms, mss, mcs); + if (is_sat == l_false && i == 0) return l_false; + if (is_sat == l_undef && i == 0) return l_undef; + if (is_sat == l_false || is_sat == l_undef) return l_true; + asms.push_back(relax_and_assert(m.mk_or(mcs.size(), mcs.c_ptr()))); } - lbool is_sat = l_false; - exprs core; - while (is_sat == l_false) { - exprs tmp_asms; - tmp_asms.append(asms); - tmp_asms.append(m_asms); - is_sat = check_sat(tmp_asms); - if (is_sat == l_true) { - update_model(); - } - else if (is_sat == l_false) { - core.reset(); - s().get_unsat_core(core); - for (unsigned i = 0; i < core.size();) { - if (asm_lits.contains(core[i])) { - core[i] = core.back(); - core.pop_back(); - } - else { - core_lits.insert(core[i]); - ++i; - } - } - if (core.empty()) { - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver empty core)\n";); - return l_false; - } - if (m_disjoint_cores) { - m_cores.push_back(core); - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :core-size " << core.size() << " :num-cores " << m_cores.size() << ")\n";); - for (unsigned i = 0; i < m_asms.size();) { - if (core_lits.contains(m_asms[i]) || !m_disjoint_cores) { - m_asms[i] = m_asms.back(); - m_asms.pop_back(); - } - else { - ++i; - } - } - } - else { - m_cores.push_back(m_asms); - m_asms.reset(); - } - } - } - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :num-cores " << m_cores.size() << ")\n";); - // TODO: update m_lower? - return is_sat; + return l_true; } - lbool disjoint_cores() { - return disjoint_cores(exprs()); - } - - lbool backtrack(exprs& asms) { - SASSERT(m_mss_trail_lim.size() == m_mcs_trail_lim.size()); - lbool is_sat = l_false; - while (is_sat == l_false && m_core_idx > 0) { - m_core_idx--; - m_mss_trail.resize(m_mss_trail_lim.back()); - m_mss_trail_lim.pop_back(); - m_mcs_trail.resize(m_mcs_trail_lim.back()); - m_mcs_trail_lim.pop_back(); - exprs tmp_asms; - tmp_asms.append(asms); - get_trail_asms(tmp_asms); - is_sat = check_sat(tmp_asms); - if (is_sat == l_true) { - update_model(); - } + lbool next_mss(expr_ref_vector const& asms, exprs& mss, exprs& mcs) { + mss.reset(); + mcs.reset(); + lbool is_sat = check_sat(asms); + if (is_sat != l_true) return is_sat; + model_ref mdl; + s().get_model(mdl); + update_assignment(mdl.get()); + vector dummy; + push_exprs(mss, m_asms); + push_exprs(mss, asms); + is_sat = cld(mdl.get(), mss, mcs); + if (is_sat == l_true) { + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); } - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :backtrack-lvl " << m_core_idx << ")\n";); + /*is_sat = m_mss(mdl.get(), dummy, mss, mcs); + SASSERT(is_sat != l_false); + if (is_sat == l_true) { + mdl.reset(); + m_mss.get_model(mdl); + update_assignment(mdl.get()); + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); + }*/ return is_sat; } @@ -200,19 +118,19 @@ private: undef.append(mss); update_sat(initial_model, sat, undef); lbool is_sat = l_true; - while (is_sat == l_true && !undef.empty()) { + while (is_sat == l_true) { expr_ref asum = relax_and_assert(m.mk_or(undef.size(), undef.c_ptr())); - exprs asms; - asms.append(sat); - get_trail_asms(asms); - asms.push_back(asum); - is_sat = check_sat(asms); + sat.push_back(asum); + is_sat = check_sat(sat); + sat.pop_back(); if (is_sat == l_true) { - update_model(); - update_sat(m_last_model, sat, undef); + model_ref mdl; + s().get_model(mdl); + update_sat(mdl, sat, undef); + update_assignment(mdl.get()); } } - if (is_sat == l_false || undef.empty()) { + if (is_sat == l_false) { mss.reset(); mcs.reset(); mss.append(sat); @@ -222,26 +140,6 @@ private: return is_sat; } - void get_trail_asms(exprs& asms) { - asms.append(m_mss_trail); - for (unsigned i = 0; i < m_mcs_trail.size(); ++i) { - asms.push_back(m.mk_not(m_mcs_trail[i])); - } - } - - void update_trails(exprs const& mss, exprs const& mcs) { - m_mss_trail_lim.push_back(m_mss_trail.size()); - m_mcs_trail_lim.push_back(m_mcs_trail.size()); - m_mss_trail.append(mss); - m_mcs_trail.append(mcs); - } - - void update_model() { - m_last_model.reset(); - s().get_model(m_last_model); - update_assignment(m_last_model.get()); - } - void update_sat(model_ref mdl, exprs& sat, exprs& undef) { for (unsigned i = 0; i < undef.size();) { if (is_true(mdl.get(), undef[i])) { @@ -262,7 +160,12 @@ private: } lbool check_sat() { - return check_sat(exprs()); + expr_ref_vector dummy(m); + return check_sat(dummy); + } + + lbool check_sat(expr_ref_vector const& asms) { + return s().check_sat(asms); } lbool check_sat(exprs const& asms) { @@ -283,7 +186,7 @@ private: for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); } - // TODO: DEBUG verify assignment? + // TODO: DEBUG verify assignment m_upper = upper; trace_bounds("mss-solver"); } diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 41548452a..4cb22389d 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -21,8 +21,7 @@ def_module_params('opt', ('maxres.max_correction_set_size', UINT, 3, 'allow generating correction set constraints up to maximal size'), ('maxres.wmax', BOOL, False, 'use weighted theory solver to constrain upper bounds'), ('maxres.pivot_on_correction_set', BOOL, True, 'reduce soft constraints if the current correction set is smaller than current core'), - ('mss.max', UINT, UINT_MAX, 'maximum number of MSS to enumerate'), - ('mss.disjoint_cores', BOOL, True, 'partition soft based on disjoint cores') + ('mss.max', UINT, UINT_MAX, 'maximum number of MSS to enumerate') )) From 7e8ed0762d29bbfc80716937183772e388802f1c Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Thu, 26 Apr 2018 22:39:58 +0100 Subject: [PATCH 0806/1283] Revert "implemented CLD" This reverts commit 3a7efb91ae073c346716b4213c06d32fc39510a6. --- src/opt/mss.cpp | 12 ++++---- src/opt/mss_solver.cpp | 62 ++++-------------------------------------- 2 files changed, 12 insertions(+), 62 deletions(-) diff --git a/src/opt/mss.cpp b/src/opt/mss.cpp index 47f4b6e02..cc0fa8d7d 100644 --- a/src/opt/mss.cpp +++ b/src/opt/mss.cpp @@ -155,10 +155,10 @@ namespace opt { lbool is_sat = l_true; for (unsigned i = 0; is_sat == l_true && i < m_cores.size(); ++i) { bool has_mcs = false; - bool not_last = i + 1 < m_cores.size(); + bool is_last = i + 1 < m_cores.size(); SASSERT(check_invariant()); update_core(m_cores[i]); // remove members of mss - is_sat = process_core(1, m_cores[i], has_mcs, not_last); + is_sat = process_core(1, m_cores[i], has_mcs, is_last); } if (is_sat == l_true) { SASSERT(check_invariant()); @@ -183,7 +183,7 @@ namespace opt { // at least one literal in core is false in current model. // pick literals in core that are not yet in mss. // - lbool mss::process_core(unsigned sz, exprs& core, bool& has_mcs, bool not_last) { + lbool mss::process_core(unsigned sz, exprs& core, bool& has_mcs, bool is_last) { SASSERT(sz > 0); if (core.empty()) { return l_true; @@ -191,7 +191,7 @@ namespace opt { if (m.canceled()) { return l_undef; } - if (sz == 1 && core.size() == 1 && not_last && !has_mcs) { + if (sz == 1 && core.size() == 1 && is_last && !has_mcs) { // there has to be at least one false // literal in the core. TRACE("opt", tout << "mcs: " << mk_pp(core[0], m) << "\n";); @@ -214,7 +214,7 @@ namespace opt { SASSERT(m_mss_set.contains(core[i])); }); update_core(core); - return process_core(2*sz, core, has_mcs, not_last); + return process_core(2*sz, core, has_mcs, is_last); case l_false: if (sz == 1) { has_mcs = true; @@ -232,7 +232,7 @@ namespace opt { } update_core(core); } - return process_core(1, core, has_mcs, not_last); + return process_core(1, core, has_mcs, is_last); case l_undef: return l_undef; } diff --git a/src/opt/mss_solver.cpp b/src/opt/mss_solver.cpp index d27b6300c..501b43ee4 100755 --- a/src/opt/mss_solver.cpp +++ b/src/opt/mss_solver.cpp @@ -98,61 +98,15 @@ private: vector dummy; push_exprs(mss, m_asms); push_exprs(mss, asms); - is_sat = cld(mdl.get(), mss, mcs); - if (is_sat == l_true) { - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); - } - /*is_sat = m_mss(mdl.get(), dummy, mss, mcs); - SASSERT(is_sat != l_false); - if (is_sat == l_true) { - mdl.reset(); - m_mss.get_model(mdl); - update_assignment(mdl.get()); - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); - }*/ + is_sat = m_mss(mdl.get(), dummy, mss, mcs); + SASSERT(is_sat == l_true); + mdl.reset(); + m_mss.get_model(mdl); + update_assignment(mdl.get()); + IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); return is_sat; } - lbool cld(model_ref initial_model, exprs& mss, exprs& mcs) { - exprs sat, undef; - undef.append(mss); - update_sat(initial_model, sat, undef); - lbool is_sat = l_true; - while (is_sat == l_true) { - expr_ref asum = relax_and_assert(m.mk_or(undef.size(), undef.c_ptr())); - sat.push_back(asum); - is_sat = check_sat(sat); - sat.pop_back(); - if (is_sat == l_true) { - model_ref mdl; - s().get_model(mdl); - update_sat(mdl, sat, undef); - update_assignment(mdl.get()); - } - } - if (is_sat == l_false) { - mss.reset(); - mcs.reset(); - mss.append(sat); - mcs.append(undef); - is_sat = l_true; - } - return is_sat; - } - - void update_sat(model_ref mdl, exprs& sat, exprs& undef) { - for (unsigned i = 0; i < undef.size();) { - if (is_true(mdl.get(), undef[i])) { - sat.push_back(undef[i]); - undef[i] = undef.back(); - undef.pop_back(); - } - else { - ++i; - } - } - } - void push_exprs(exprs& dst, expr_ref_vector const& src) { for (unsigned i = 0; i < src.size(); ++i) { dst.push_back(src[i]); @@ -168,10 +122,6 @@ private: return s().check_sat(asms); } - lbool check_sat(exprs const& asms) { - return s().check_sat(asms.size(), asms.c_ptr()); - } - void update_assignment(model* mdl) { rational upper(0); for (unsigned i = 0; i < m_soft.size(); ++i) { From e1d7f5deba5398e8471ae53d63fce59c690c731e Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Thu, 26 Apr 2018 22:40:00 +0100 Subject: [PATCH 0807/1283] Revert "MSS based MaxSMT solver" This reverts commit 3bbc09c1d2c800ea4ac646c66a886d25a87c4938. --- src/opt/maxsmt.cpp | 4 -- src/opt/mss_solver.cpp | 156 ----------------------------------------- src/opt/mss_solver.h | 12 ---- src/opt/opt_params.pyg | 8 +-- 4 files changed, 4 insertions(+), 176 deletions(-) delete mode 100755 src/opt/mss_solver.cpp delete mode 100755 src/opt/mss_solver.h diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 9bc4f4f14..91e843ca0 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -21,7 +21,6 @@ Notes: #include "opt/maxsmt.h" #include "opt/maxres.h" #include "opt/wmax.h" -#include "opt/mss_solver.h" #include "ast/ast_pp.h" #include "util/uint_set.h" #include "opt/opt_context.h" @@ -241,9 +240,6 @@ namespace opt { else if (maxsat_engine == symbol("pd-maxres")) { m_msolver = mk_primal_dual_maxres(m_c, m_index, m_weights, m_soft_constraints); } - else if (maxsat_engine == symbol("mss")) { - m_msolver = mk_mss_solver(m_c, m_index, m_weights, m_soft_constraints); - } else if (maxsat_engine == symbol("wmax")) { m_msolver = mk_wmax(m_c, m_weights, m_soft_constraints); } diff --git a/src/opt/mss_solver.cpp b/src/opt/mss_solver.cpp deleted file mode 100755 index 501b43ee4..000000000 --- a/src/opt/mss_solver.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "solver/solver.h" -#include "opt/maxsmt.h" -#include "opt/mss_solver.h" -#include "opt/mss.h" -#include "opt/opt_context.h" -#include "opt/opt_params.hpp" - -using namespace opt; - -class mss_solver: public maxsmt_solver_base { - -private: - typedef ptr_vector exprs; - mss m_mss; - unsigned m_index; - expr_ref_vector m_asms; - unsigned m_max_mss; - -public: - mss_solver(maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft): - maxsmt_solver_base(c, ws, soft), - m_mss(c.get_solver(), m), - m_index(id), - m_asms(m), - m_max_mss(UINT_MAX) { - } - - virtual ~mss_solver() {} - - virtual lbool operator()() { - if (!init()) return l_undef; - init_asms(); - lbool is_sat = check_sat(m_asms); - if (is_sat == l_undef) return l_undef; - if (is_sat == l_true) { - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << m_asms.size() << " :mcs " << 0 << ")\n";); - model_ref mdl; - s().get_model(mdl); - update_assignment(mdl.get()); - return l_true; - } - return enumerate_mss(); - } - - virtual void updt_params(params_ref& p) { - maxsmt_solver_base::updt_params(p); - opt_params _p(p); - m_max_mss = _p.mss_max(); - } - -private: - void init_asms() { - m_asms.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - expr* e = m_soft[i]; - m_asms.push_back(relax_and_assert(e)); - } - } - - expr_ref relax_and_assert(expr* e) { - expr_ref asum(m); - if (is_literal(e)) { - asum = e; - } - else { - asum = mk_fresh_bool("r"); - e = m.mk_iff(asum, e); - s().assert_expr(e); - } - return asum; - } - - bool is_literal(expr* l) { - return is_uninterp_const(l) || (m.is_not(l, l) && is_uninterp_const(l)); - } - - lbool enumerate_mss() { - expr_ref_vector asms(m); - for (unsigned i = 0; i < m_max_mss; ++i) { - exprs mss, mcs; - lbool is_sat = next_mss(asms, mss, mcs); - if (is_sat == l_false && i == 0) return l_false; - if (is_sat == l_undef && i == 0) return l_undef; - if (is_sat == l_false || is_sat == l_undef) return l_true; - asms.push_back(relax_and_assert(m.mk_or(mcs.size(), mcs.c_ptr()))); - } - return l_true; - } - - lbool next_mss(expr_ref_vector const& asms, exprs& mss, exprs& mcs) { - mss.reset(); - mcs.reset(); - lbool is_sat = check_sat(asms); - if (is_sat != l_true) return is_sat; - model_ref mdl; - s().get_model(mdl); - update_assignment(mdl.get()); - vector dummy; - push_exprs(mss, m_asms); - push_exprs(mss, asms); - is_sat = m_mss(mdl.get(), dummy, mss, mcs); - SASSERT(is_sat == l_true); - mdl.reset(); - m_mss.get_model(mdl); - update_assignment(mdl.get()); - IF_VERBOSE(2, verbose_stream() << "(opt.mss-solver :mss " << mss.size() - asms.size() << " :mcs " << mcs.size() << ")\n";); - return is_sat; - } - - void push_exprs(exprs& dst, expr_ref_vector const& src) { - for (unsigned i = 0; i < src.size(); ++i) { - dst.push_back(src[i]); - } - } - - lbool check_sat() { - expr_ref_vector dummy(m); - return check_sat(dummy); - } - - lbool check_sat(expr_ref_vector const& asms) { - return s().check_sat(asms); - } - - void update_assignment(model* mdl) { - rational upper(0); - for (unsigned i = 0; i < m_soft.size(); ++i) { - if (!is_true(mdl, m_soft[i])) { - upper += m_weights[i]; - } - } - if (upper > m_upper) return; - if (!m_c.verify_model(m_index, mdl, upper)) return; - m_model = mdl; - m_c.model_updated(mdl); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = is_true(m_soft[i]); - } - // TODO: DEBUG verify assignment - m_upper = upper; - trace_bounds("mss-solver"); - } - - bool is_true(model* mdl, expr* e) { - expr_ref tmp(m); - return mdl->eval(e, tmp, true) && m.is_true(tmp); - } - - bool is_true(expr* e) { - return is_true(m_model.get(), e); - } -}; - -maxsmt_solver_base* opt::mk_mss_solver(maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft) { - return alloc(mss_solver, c, id, ws, soft); -} diff --git a/src/opt/mss_solver.h b/src/opt/mss_solver.h deleted file mode 100755 index 5c274cd4c..000000000 --- a/src/opt/mss_solver.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef MSS_SOLVER_H_ -#define MSS_SOLVER_H_ - -#include "opt/maxsmt.h" - -namespace opt { - - maxsmt_solver_base* mk_mss_solver(maxsat_context& c, unsigned id, weights_t& ws, expr_ref_vector const& soft); - -} - -#endif diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 4cb22389d..1d6d7ee6a 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -2,13 +2,13 @@ def_module_params('opt', description='optimization parameters', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'farkas', 'symba'"), - ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'mss'"), + ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres'"), ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', or 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('solution_prefix', SYMBOL, '', "path prefix to dump intermediary, but non-optimal, solutions"), ('timeout', UINT, UINT_MAX, 'timeout (in milliseconds) (UINT_MAX and 0 mean no timeout)'), ('rlimit', UINT, 0, 'resource limit (0 means no limit)'), - ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsat'), + ('enable_sls', BOOL, False, 'enable SLS tuning during weighted maxsast'), ('enable_sat', BOOL, True, 'enable the new SAT core for propositional constraints'), ('elim_01', BOOL, True, 'eliminate 01 variables'), ('pp.neat', BOOL, True, 'use neat (as opposed to less readable, but faster) pretty printer when displaying context'), @@ -20,8 +20,8 @@ def_module_params('opt', ('maxres.maximize_assignment', BOOL, False, 'find an MSS/MCS to improve current assignment'), ('maxres.max_correction_set_size', UINT, 3, 'allow generating correction set constraints up to maximal size'), ('maxres.wmax', BOOL, False, 'use weighted theory solver to constrain upper bounds'), - ('maxres.pivot_on_correction_set', BOOL, True, 'reduce soft constraints if the current correction set is smaller than current core'), - ('mss.max', UINT, UINT_MAX, 'maximum number of MSS to enumerate') + ('maxres.pivot_on_correction_set', BOOL, True, 'reduce soft constraints if the current correction set is smaller than current core') + )) From 24b35fb9256f2bf799cadae819334d8d52a3e686 Mon Sep 17 00:00:00 2001 From: TheRealNebus Date: Thu, 26 Apr 2018 22:42:55 +0100 Subject: [PATCH 0808/1283] WMax conflict budget bug fix --- src/opt/wmax.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 52b87e536..513c68d6e 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -84,6 +84,9 @@ namespace opt { if (m.canceled()) { is_sat = l_undef; } + if (is_sat == l_undef) { + break; + } if (is_sat == l_false) { TRACE("opt", tout << "Unsat\n";); break; @@ -97,9 +100,6 @@ namespace opt { //DEBUG_CODE(verify_cores(cores);); s().assert_expr(fml); } - else { - //DEBUG_CODE(verify_cores(cores);); - } update_cores(wth(), cores); wth().init_min_cost(m_upper - m_lower); trace_bounds("wmax"); From 5dbba8bd5364b72ec9824f1c50d94b241b9cc218 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Apr 2018 17:48:04 +0200 Subject: [PATCH 0809/1283] fix #1599. fix #1600 Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 1 - src/api/api_context.h | 5 ++--- src/ast/datatype_decl_plugin.cpp | 2 ++ src/ast/datatype_decl_plugin.h | 3 ++- src/cmd_context/basic_cmds.cpp | 2 +- src/cmd_context/cmd_context.cpp | 10 +++++++--- src/cmd_context/context_params.h | 5 ++++- src/cmd_context/tactic_cmds.cpp | 4 ++-- src/opt/opt_context.h | 14 +++++++------- 9 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index c8b365f22..5993e9fdd 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -78,7 +78,6 @@ namespace api { m_bv_util(m()), m_datalog_util(m()), m_fpa_util(m()), - m_dtutil(m()), m_sutil(m()), m_last_result(m()), m_ast_trail(m()), diff --git a/src/api/api_context.h b/src/api/api_context.h index 185eb9e0f..72a0e4bbb 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -61,7 +61,6 @@ namespace api { bv_util m_bv_util; datalog::dl_decl_util m_datalog_util; fpa_util m_fpa_util; - datatype_util m_dtutil; seq_util m_sutil; // Support for old solver API @@ -122,12 +121,12 @@ namespace api { bool produce_unsat_cores() const { return m_params.m_unsat_core; } bool use_auto_config() const { return m_params.m_auto_config; } unsigned get_timeout() const { return m_params.m_timeout; } - unsigned get_rlimit() const { return m_params.m_rlimit; } + unsigned get_rlimit() const { return m_params.rlimit(); } arith_util & autil() { return m_arith_util; } bv_util & bvutil() { return m_bv_util; } datalog::dl_decl_util & datalog_util() { return m_datalog_util; } fpa_util & fpautil() { return m_fpa_util; } - datatype_util& dtutil() { return m_dtutil; } + datatype_util& dtutil() { return m_dt_plugin->u(); } seq_util& sutil() { return m_sutil; } family_id get_basic_fid() const { return m_basic_fid; } family_id get_array_fid() const { return m_array_fid; } diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index f685c70d5..dfeaef9f8 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -390,6 +390,8 @@ namespace datatype { TRACE("datatype", tout << "declaring " << datatypes[i]->name() << "\n";); if (m_defs.find(datatypes[i]->name(), d)) { TRACE("datatype", tout << "delete previous version for " << datatypes[i]->name() << "\n";); + sort_ref_vector srts(*m_manager); + u().reset(); dealloc(d); } m_defs.insert(datatypes[i]->name(), datatypes[i]); diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index f32e9990d..88b50af82 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -239,7 +239,6 @@ namespace datatype { map m_defs; svector m_def_block; unsigned m_class_id; - util & u() const; void inherit(decl_plugin* other_p, ast_translation& tr) override; @@ -279,6 +278,8 @@ namespace datatype { def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); } def& get_def(symbol const& s) { return *(m_defs[s]); } bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); } + util & u() const; + private: bool is_value_visit(expr * arg, ptr_buffer & todo) const; diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 0c9c5360c..4e8806d62 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -503,7 +503,7 @@ public: ctx.set_random_seed(to_unsigned(val)); } else if (m_option == m_reproducible_resource_limit) { - ctx.params().m_rlimit = to_unsigned(val); + ctx.params().set_rlimit(to_unsigned(val)); } else if (m_option == m_verbosity) { set_verbosity_level(to_unsigned(val)); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 11f800b25..9f93e1b93 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1328,7 +1328,8 @@ void cmd_context::push() { s.m_macros_stack_lim = m_macros_stack.size(); s.m_aux_pdecls_lim = m_aux_pdecls.size(); s.m_assertions_lim = m_assertions.size(); - if (m_solver) + m().limit().push(m_params.rlimit()); + if (m_solver) m_solver->push(); if (m_opt) m_opt->push(); @@ -1443,6 +1444,9 @@ void cmd_context::pop(unsigned n) { restore_assertions(s.m_assertions_lim); restore_psort_inst(s.m_psort_inst_stack_lim); m_scopes.shrink(new_lvl); + while (n--) { + m().limit().pop(); + } } @@ -1453,7 +1457,7 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions TRACE("before_check_sat", dump_assertions(tout);); init_manager(); unsigned timeout = m_params.m_timeout; - unsigned rlimit = m_params.m_rlimit; + unsigned rlimit = m_params.rlimit(); scoped_watch sw(*this); lbool r; bool was_opt = false; @@ -1530,7 +1534,7 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions void cmd_context::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector & conseq) { unsigned timeout = m_params.m_timeout; - unsigned rlimit = m_params.m_rlimit; + unsigned rlimit = m_params.rlimit(); lbool r; m_check_sat_result = m_solver.get(); // solver itself stores the result. m_solver->set_progress_callback(this); diff --git a/src/cmd_context/context_params.h b/src/cmd_context/context_params.h index df62057fe..3d2947b7a 100644 --- a/src/cmd_context/context_params.h +++ b/src/cmd_context/context_params.h @@ -27,6 +27,8 @@ class context_params { void set_bool(bool & opt, char const * param, char const * value); void set_uint(unsigned & opt, char const * param, char const * value); + unsigned m_rlimit; + public: bool m_auto_config; bool m_proof; @@ -42,10 +44,11 @@ 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; - unsigned m_rlimit; + unsigned rlimit() const { return m_rlimit; } context_params(); void set(char const * param, char const * value); + void set_rlimit(unsigned lim) { m_rlimit = lim; } void updt_params(); void updt_params(params_ref const & p); static void collect_param_descrs(param_descrs & d); diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 32a92ea59..78187ebe1 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -205,7 +205,7 @@ public: tref->set_logic(ctx.get_logic()); ast_manager & m = ctx.m(); unsigned timeout = p.get_uint("timeout", ctx.params().m_timeout); - unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit); + unsigned rlimit = p.get_uint("rlimit", ctx.params().rlimit()); labels_vec labels; goal_ref g = alloc(goal, m, ctx.produce_proofs(), ctx.produce_models(), ctx.produce_unsat_cores()); assert_exprs_from(ctx, *g); @@ -321,7 +321,7 @@ public: assert_exprs_from(ctx, *g); unsigned timeout = p.get_uint("timeout", ctx.params().m_timeout); - unsigned rlimit = p.get_uint("rlimit", ctx.params().m_rlimit); + unsigned rlimit = p.get_uint("rlimit", ctx.params().rlimit()); goal_ref_buffer result_goals; model_converter_ref mc; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 6af106ef3..e97fabbe4 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -283,13 +283,13 @@ namespace opt { struct is_propositional_fn; bool is_propositional(expr* e); - void init_solver(); - void update_solver(); - void setup_arith_solver(); - void add_maxsmt(symbol const& id, unsigned index); - void set_simplify(tactic *simplify); - void set_pareto(pareto_base* p); - void clear_state(); + void init_solver(); + void update_solver(); + void setup_arith_solver(); + void add_maxsmt(symbol const& id, unsigned index); + void set_simplify(tactic *simplify); + void set_pareto(pareto_base* p); + void clear_state(); bool is_numeral(expr* e, rational& n) const; From f234bb348bb33dc97dce2751a241bdbf96a46814 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Apr 2018 17:49:20 +0200 Subject: [PATCH 0810/1283] fix #1599. fix #1600 Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index dfeaef9f8..d3704a84a 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -390,7 +390,6 @@ namespace datatype { TRACE("datatype", tout << "declaring " << datatypes[i]->name() << "\n";); if (m_defs.find(datatypes[i]->name(), d)) { TRACE("datatype", tout << "delete previous version for " << datatypes[i]->name() << "\n";); - sort_ref_vector srts(*m_manager); u().reset(); dealloc(d); } From 563f337997a0e684c20eee62e6862dd73e3cd91d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Apr 2018 17:59:03 +0200 Subject: [PATCH 0811/1283] testing memory defragmentation, prefetch, delay ate Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 1 + src/sat/ba_solver.cpp | 4 +- src/sat/sat_allocator.h | 101 ++++++++++++++++++ src/sat/sat_clause.cpp | 17 ++- src/sat/sat_clause.h | 10 +- src/sat/sat_config.cpp | 3 + src/sat/sat_config.h | 3 + src/sat/sat_drat.cpp | 10 +- src/sat/sat_elim_vars.cpp | 4 +- src/sat/sat_iff3_finder.cpp | 4 +- src/sat/sat_integrity_checker.cpp | 8 +- src/sat/sat_params.pyg | 3 + src/sat/sat_simplifier.cpp | 14 ++- src/sat/sat_solver.cpp | 165 +++++++++++++++++++++++++----- src/sat/sat_solver.h | 27 +++-- src/sat/sat_var_queue.h | 2 + src/util/heap.h | 8 +- 17 files changed, 320 insertions(+), 64 deletions(-) create mode 100644 src/sat/sat_allocator.h diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 7cc0ccb12..0106554fc 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -253,6 +253,7 @@ bool zstring::contains(zstring const& other) const { int zstring::indexof(zstring const& other, int offset) const { SASSERT(offset >= 0); + if (static_cast(offset) <= length() && other.length() == 0) return offset; if (static_cast(offset) == length()) return -1; if (other.length() + offset > length()) return -1; unsigned last = length() - other.length(); diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 0ead8bb40..9340ac635 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2245,8 +2245,8 @@ namespace sat { IF_VERBOSE(0, verbose_stream() << "Discrepancy of watched literal: " << l << " id: " << c.id() << " clause: " << c << (found?" is watched, but shouldn't be":" not watched, but should be") << "\n"; - display_watch_list(verbose_stream() << l << ": ", s().m_cls_allocator, get_wlist(l)) << "\n"; - display_watch_list(verbose_stream() << ~l << ": ", s().m_cls_allocator, get_wlist(~l)) << "\n"; + s().display_watch_list(verbose_stream() << l << ": ", get_wlist(l)) << "\n"; + s().display_watch_list(verbose_stream() << ~l << ": ", get_wlist(~l)) << "\n"; verbose_stream() << "value: " << value(l) << " level: " << lvl(l) << "\n"; display(verbose_stream(), c, true); if (c.lit() != null_literal) verbose_stream() << value(c.lit()) << "\n";); diff --git a/src/sat/sat_allocator.h b/src/sat/sat_allocator.h new file mode 100644 index 000000000..1cbef04e0 --- /dev/null +++ b/src/sat/sat_allocator.h @@ -0,0 +1,101 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + sat_allocator.h + +Abstract: + + Small object allocator suitable for clauses + +Author: + + Nikolaj bjorner (nbjorner) 2018-04-26. + +Revision History: +--*/ + +#ifndef SAT_ALLOCATOR_H_ +#define SAT_ALLOCATOR_H_ + +#include "util/vector.h" +#include "util/machine.h" + +class sat_allocator { + static const unsigned CHUNK_SIZE = (1 << 16); + 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); + struct chunk { + char * m_curr; + char m_data[CHUNK_SIZE]; + chunk():m_curr(m_data) {} + }; + ptr_vector m_chunks; + void * m_chunk_ptr; + ptr_vector m_free[NUM_FREE]; + size_t m_alloc_size; + char const * m_id; + + unsigned align_size(size_t sz) const { + return free_slot_id(sz) << PTR_ALIGNMENT; + } + unsigned free_slot_id(size_t size) const { + return (static_cast(size >> PTR_ALIGNMENT) + ((0 != (size & MASK)) ? 1u : 0u)); + } +public: + sat_allocator(char const * id = "unknown"): m_id(id), m_alloc_size(0), m_chunk_ptr(nullptr) {} + ~sat_allocator() { reset(); } + void reset() { + for (chunk * ch : m_chunks) dealloc(ch); + m_chunks.reset(); + for (unsigned i = 0; i < NUM_FREE; ++i) m_free[i].reset(); + m_alloc_size = 0; + m_chunk_ptr = nullptr; + } + void * allocate(size_t size) { + m_alloc_size += size; + if (size >= SMALL_OBJ_SIZE) { + return memory::allocate(size); + } + unsigned slot_id = free_slot_id(size); + if (!m_free[slot_id].empty()) { + void* result = m_free[slot_id].back(); + m_free[slot_id].pop_back(); + return result; + } + if (m_chunks.empty()) { + m_chunks.push_back(alloc(chunk)); + m_chunk_ptr = m_chunks.back(); + } + + unsigned sz = align_size(size); + if ((char*)m_chunk_ptr + sz > (char*)m_chunks.back() + CHUNK_SIZE) { + m_chunks.push_back(alloc(chunk)); + m_chunk_ptr = m_chunks.back(); + } + void * result = m_chunk_ptr; + m_chunk_ptr = (char*)m_chunk_ptr + sz; + return result; + } + + void deallocate(size_t size, void * p) { + m_alloc_size -= size; + if (size >= SMALL_OBJ_SIZE) { + memory::deallocate(p); + } + else { + m_free[free_slot_id(size)].push_back(p); + } + } + size_t get_allocation_size() const { return m_alloc_size; } +}; + +inline void * operator new(size_t s, sat_allocator & r) { return r.allocate(s); } +inline void * operator new[](size_t s, sat_allocator & r) { return r.allocate(s); } +inline void operator delete(void * p, sat_allocator & r) { UNREACHABLE(); } +inline void operator delete[](void * p, sat_allocator & r) { UNREACHABLE(); } + +#endif /* SAT_ALLOCATOR_H_ */ + diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index f433f884d..f9caffe94 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -135,12 +135,15 @@ namespace sat { m_allocator("clause-allocator") { } + void clause_allocator::finalize() { + m_allocator.reset(); + } + clause * clause_allocator::get_clause(clause_offset cls_off) const { SASSERT(cls_off == reinterpret_cast(reinterpret_cast(cls_off))); return reinterpret_cast(cls_off); } - clause_offset clause_allocator::get_offset(clause const * cls) const { SASSERT(cls == reinterpret_cast(reinterpret_cast(cls))); return reinterpret_cast(cls); @@ -155,6 +158,18 @@ namespace sat { return cls; } + clause * clause_allocator::copy_clause(clause const& other) { + size_t size = clause::get_obj_size(other.size()); + void * mem = m_allocator.allocate(size); + clause * cls = new (mem) clause(m_id_gen.mk(), other.size(), other.m_lits, other.is_learned()); + cls->m_reinit_stack = other.on_reinit_stack(); + cls->m_glue = other.glue(); + cls->m_psm = other.psm(); + cls->m_frozen = other.frozen(); + cls->m_approx = other.approx(); + return cls; + } + void clause_allocator::del_clause(clause * cls) { TRACE("sat_clause", tout << "delete: " << cls->id() << " " << *cls << "\n";); m_id_gen.recycle(cls->id()); diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index c7273f57d..c42427afb 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -19,10 +19,11 @@ Revision History: #ifndef SAT_CLAUSE_H_ #define SAT_CLAUSE_H_ -#include "sat/sat_types.h" #include "util/small_object_allocator.h" #include "util/id_gen.h" #include "util/map.h" +#include "sat/sat_types.h" +#include "sat/sat_allocator.h" #ifdef _MSC_VER #pragma warning(disable : 4200) @@ -133,13 +134,16 @@ namespace sat { \brief Simple clause allocator that allows uint (32bit integers) to be used to reference clauses (even in 64bit machines). */ class clause_allocator { - small_object_allocator m_allocator; - id_gen m_id_gen; + small_object_allocator m_allocator; + id_gen m_id_gen; public: clause_allocator(); + void finalize(); + size_t get_allocation_size() const { return m_allocator.get_allocation_size(); } clause * get_clause(clause_offset cls_off) const; clause_offset get_offset(clause const * ptr) const; clause * mk_clause(unsigned num_lits, literal const * lits, bool learned); + clause * copy_clause(clause const& other); void del_clause(clause * cls); }; diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 2597967df..f7e2e2404 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -41,6 +41,7 @@ namespace sat { else throw sat_param_exception("invalid restart strategy"); + m_restart_fast = p.restart_fast(); s = p.phase(); if (s == symbol("always_false")) m_phase = PS_ALWAYS_FALSE; @@ -60,6 +61,7 @@ namespace sat { m_restart_initial = p.restart_initial(); m_restart_factor = p.restart_factor(); m_restart_max = p.restart_max(); + m_propagate_prefetch = p.propagate_prefetch(); m_inprocess_max = p.inprocess_max(); m_random_freq = p.random_freq(); @@ -139,6 +141,7 @@ namespace sat { m_gc_small_lbd = p.gc_small_lbd(); m_gc_k = std::min(255u, p.gc_k()); m_gc_burst = p.gc_burst(); + m_gc_defrag = p.gc_defrag(); m_minimize_lemmas = p.minimize_lemmas(); m_core_minimize = p.core_minimize(); diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 20d966dd1..f04973d13 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -85,7 +85,9 @@ namespace sat { unsigned m_phase_caching_on; unsigned m_phase_caching_off; bool m_phase_sticky; + bool m_propagate_prefetch; restart_strategy m_restart; + bool m_restart_fast; unsigned m_restart_initial; double m_restart_factor; // for geometric case unsigned m_restart_max; @@ -126,6 +128,7 @@ namespace sat { unsigned m_gc_small_lbd; unsigned m_gc_k; bool m_gc_burst; + bool m_gc_defrag; bool m_minimize_lemmas; diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index fd2b6fa79..00a3fa076 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -42,7 +42,7 @@ namespace sat { for (unsigned i = 0; i < m_proof.size(); ++i) { clause* c = m_proof[i]; if (c && (c->size() == 2 || m_status[i] == status::deleted || m_status[i] == status::external)) { - s.m_cls_allocator.del_clause(c); + s.dealloc_clause(c); } } } @@ -118,7 +118,7 @@ namespace sat { if (st == status::learned) { verify(2, lits); } - clause* c = s.m_cls_allocator.mk_clause(2, lits, st == status::learned); + clause* c = s.alloc_clause(2, lits, st == status::learned); m_proof.push_back(c); m_status.push_back(st); unsigned idx = m_watched_clauses.size(); @@ -452,7 +452,7 @@ namespace sat { case 0: add(); break; case 1: append(lits[0], status::external); break; default: { - clause* c = s.m_cls_allocator.mk_clause(lits.size(), lits.c_ptr(), true); + clause* c = s.alloc_clause(lits.size(), lits.c_ptr(), true); append(*c, status::external); break; } @@ -468,7 +468,7 @@ namespace sat { case 1: append(c[0], status::learned); break; default: { verify(c.size(), c.begin()); - clause* cl = s.m_cls_allocator.mk_clause(c.size(), c.c_ptr(), true); + clause* cl = s.alloc_clause(c.size(), c.c_ptr(), true); append(*cl, status::external); break; } @@ -490,7 +490,7 @@ namespace sat { TRACE("sat", tout << "del: " << c << "\n";); if (m_out) dump(c.size(), c.begin(), status::deleted); if (m_check) { - clause* c1 = s.m_cls_allocator.mk_clause(c.size(), c.begin(), c.is_learned()); + clause* c1 = s.alloc_clause(c.size(), c.begin(), c.is_learned()); append(*c1, status::deleted); } } diff --git a/src/sat/sat_elim_vars.cpp b/src/sat/sat_elim_vars.cpp index a80807450..299fbace1 100644 --- a/src/sat/sat_elim_vars.cpp +++ b/src/sat/sat_elim_vars.cpp @@ -185,7 +185,7 @@ namespace sat{ s.m_stats.m_mk_ter_clause++; else s.m_stats.m_mk_clause++; - clause* cp = s.m_cls_allocator.mk_clause(c.size(), c.c_ptr(), false); + clause* cp = s.alloc_clause(c.size(), c.c_ptr(), false); s.m_clauses.push_back(cp); simp.m_use_list.insert(*cp); if (simp.m_sub_counter > 0) @@ -214,7 +214,7 @@ namespace sat{ } if (b.is_false()) { if (lits.size() > 1) { - clause* c = s.m_cls_allocator.mk_clause(lits.size(), lits.c_ptr(), false); + clause* c = s.alloc_clause(lits.size(), lits.c_ptr(), false); clauses.push_back(c); } else { diff --git a/src/sat/sat_iff3_finder.cpp b/src/sat/sat_iff3_finder.cpp index af7a6f438..32bf70414 100644 --- a/src/sat/sat_iff3_finder.cpp +++ b/src/sat/sat_iff3_finder.cpp @@ -136,9 +136,9 @@ namespace sat { TRACE("iff3_finder", tout << "visiting: " << x << "\n"; tout << "pos:\n"; - display_watch_list(tout, s.m_cls_allocator, pos_wlist); + s.display_watch_list(tout, pos_wlist); tout << "\nneg:\n"; - display_watch_list(tout, s.m_cls_allocator, neg_wlist); + s.display_watch_list(tout, neg_wlist); tout << "\n--------------\n";); // traverse the ternary clauses x \/ l1 \/ l2 bool_var curr_v1 = null_bool_var; diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index 7f56e2b36..32feaa2c7 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -66,7 +66,7 @@ namespace sat { if (c.size() == 3) { CTRACE("sat_ter_watch_bug", !contains_watched(s.get_wlist(~c[0]), c[1], c[2]), tout << c << "\n"; tout << "watch_list:\n"; - sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~c[0])); + s.display_watch_list(tout, s.get_wlist(~c[0])); tout << "\n";); VERIFY(contains_watched(s.get_wlist(~c[0]), c[1], c[2])); VERIFY(contains_watched(s.get_wlist(~c[1]), c[0], c[2])); @@ -164,9 +164,9 @@ namespace sat { tout << "was_eliminated1: " << s.was_eliminated(l.var()); tout << " was_eliminated2: " << s.was_eliminated(w.get_literal().var()); tout << " learned: " << w.is_learned() << "\n"; - sat::display_watch_list(tout, s.m_cls_allocator, wlist); + s.display_watch_list(tout, wlist); tout << "\n"; - sat::display_watch_list(tout, s.m_cls_allocator, s.get_wlist(~(w.get_literal()))); + s.display_watch_list(tout, s.get_wlist(~(w.get_literal()))); tout << "\n";); VERIFY(find_binary_watch(s.get_wlist(~(w.get_literal())), l)); break; @@ -176,7 +176,7 @@ namespace sat { VERIFY(w.get_literal1().index() < w.get_literal2().index()); break; case watched::CLAUSE: - VERIFY(!s.m_cls_allocator.get_clause(w.get_clause_offset())->was_removed()); + VERIFY(!s.get_clause(w.get_clause_offset()).was_removed()); break; default: break; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 320ddaf9e..cf6ecc4f5 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -6,9 +6,11 @@ def_module_params('sat', ('phase.caching.on', UINT, 400, 'phase caching on period (in number of conflicts)'), ('phase.caching.off', UINT, 100, 'phase caching off period (in number of conflicts)'), ('phase.sticky', BOOL, False, 'use sticky phase caching for local search'), + ('propagate.prefetch', BOOL, True, 'prefetch watch lists for assigned literals'), ('restart', SYMBOL, 'luby', 'restart strategy: luby or geometric'), ('restart.initial', UINT, 100, 'initial restart (number of conflicts)'), ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), + ('restart.fast', BOOL, False, 'use fast restart strategy.'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), ('variable_decay', UINT, 120, 'multiplier (divided by 100) for the VSIDS activity increement'), ('inprocess.max', UINT, UINT_MAX, 'maximal number of inprocessing passes'), @@ -24,6 +26,7 @@ def_module_params('sat', ('gc.small_lbd', UINT, 3, 'learned clauses with small LBD are never deleted (only used in dyn_psm)'), ('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'), ('gc.burst', BOOL, True, 'perform eager garbage collection during initialization'), + ('gc.defrag', BOOL, True, 'defragment clauses when garbage collecting'), ('simplify.delay', UINT, 0, 'set initial delay of simplification by a conflict count'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), ('dyn_sub_res', BOOL, True, 'dynamic subsumption resolution for minimizing learned clauses'), diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 9c57c79ed..314b661ea 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -100,7 +100,7 @@ namespace sat { !m_learned_in_use_lists && m_num_calls >= m_bce_delay && single_threaded(); } - bool simplifier::ate_enabled() const { return m_ate; } + bool simplifier::ate_enabled() const { return m_num_calls >= m_bce_delay && m_ate; } bool simplifier::bce_enabled() const { return bce_enabled_base() && (m_bce || m_bce_at == m_num_calls || m_acce || m_abce || m_cce); } bool simplifier::acce_enabled() const { return bce_enabled_base() && m_acce; } bool simplifier::cce_enabled() const { return bce_enabled_base() && (m_cce || m_acce); } @@ -1581,8 +1581,8 @@ namespace sat { IF_VERBOSE(0, verbose_stream() << "blocked: " << l << " @ " << c << " :covered " << m_covered_clause << "\n"; s.m_use_list.display(verbose_stream() << "use " << l << ":", l); s.m_use_list.display(verbose_stream() << "use " << ~l << ":", ~l); - display_watch_list(verbose_stream() << ~l << ": ", s.s.m_cls_allocator, s.get_wlist(l)) << "\n"; - display_watch_list(verbose_stream() << l << ": ", s.s.m_cls_allocator, s.get_wlist(~l)) << "\n"; + s.s.display_watch_list(verbose_stream() << ~l << ": ", s.get_wlist(l)) << "\n"; + s.s.display_watch_list(verbose_stream() << l << ": ", s.get_wlist(~l)) << "\n"; ); } @@ -1999,8 +1999,8 @@ namespace sat { literal l(v, false); IF_VERBOSE(0, verbose_stream() << "elim: " << l << "\n"; - display_watch_list(verbose_stream() << ~l << ": ", s.m_cls_allocator, get_wlist(l)) << "\n"; - display_watch_list(verbose_stream() << l << ": ", s.m_cls_allocator, get_wlist(~l)) << "\n";); + s.display_watch_list(verbose_stream() << ~l << ": ", get_wlist(l)) << "\n"; + s.display_watch_list(verbose_stream() << l << ": ", get_wlist(~l)) << "\n";); } // eliminate variable ++s.m_stats.m_elim_var_res; @@ -2018,8 +2018,6 @@ namespace sat { m_elim_counter -= num_pos * num_neg + before_lits; - - for (auto & c1 : m_pos_cls) { for (auto & c2 : m_neg_cls) { m_new_cls.reset(); @@ -2046,7 +2044,7 @@ namespace sat { s.m_stats.m_mk_ter_clause++; else s.m_stats.m_mk_clause++; - clause * new_c = s.m_cls_allocator.mk_clause(m_new_cls.size(), m_new_cls.c_ptr(), false); + clause * new_c = s.alloc_clause(m_new_cls.size(), m_new_cls.c_ptr(), false); if (s.m_config.m_drat) s.m_drat.add(*new_c, true); s.m_clauses.push_back(new_c); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index fb992d57e..792883977 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -36,7 +36,8 @@ namespace sat { m_rlimit(l), m_checkpoint_enabled(true), m_config(p), - m_par(0), + m_par(nullptr), + m_cls_allocator_idx(false), m_par_syncing_clauses(false), m_par_id(0), m_cleaner(*this), @@ -78,7 +79,7 @@ namespace sat { void solver::del_clauses(clause_vector& clauses) { for (clause * cp : clauses) - m_cls_allocator.del_clause(cp); + dealloc_clause(cp); clauses.reset(); ++m_stats.m_non_learned_generation; } @@ -298,7 +299,7 @@ namespace sat { if (m_config.m_drat && !m_drat.is_cleaned(c)) { m_drat.del(c); } - m_cls_allocator.del_clause(&c); + dealloc_clause(&c); m_stats.m_del_clause++; } @@ -396,7 +397,7 @@ namespace sat { clause * solver::mk_ter_clause(literal * lits, bool learned) { m_stats.m_mk_ter_clause++; - clause * r = m_cls_allocator.mk_clause(3, lits, learned); + clause * r = alloc_clause(3, lits, learned); bool reinit = attach_ter_clause(*r); if (reinit && !learned) push_reinit_stack(*r); if (m_config.m_drat) m_drat.add(*r, learned); @@ -435,7 +436,7 @@ namespace sat { clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, bool learned) { m_stats.m_mk_clause++; - clause * r = m_cls_allocator.mk_clause(num_lits, lits, learned); + clause * r = alloc_clause(num_lits, lits, learned); SASSERT(!learned || r->is_learned()); bool reinit = attach_nary_clause(*r); if (reinit && !learned) push_reinit_stack(*r); @@ -452,7 +453,7 @@ namespace sat { bool solver::attach_nary_clause(clause & c) { bool reinit = false; - clause_offset cls_off = m_cls_allocator.get_offset(&c); + clause_offset cls_off = cls_allocator().get_offset(&c); if (!at_base_lvl()) { if (c.is_learned()) { unsigned w2_idx = select_learned_watch_lit(c); @@ -511,6 +512,85 @@ namespace sat { } } + bool solver::memory_pressure() { + return 3*cls_allocator().get_allocation_size()/2 + memory::get_allocation_size() > memory::get_max_memory_size(); + } + + struct solver::cmp_activity { + solver& s; + cmp_activity(solver& s):s(s) {} + bool operator()(bool_var v1, bool_var v2) const { + return s.m_activity[v1] > s.m_activity[v2]; + } + }; + + void solver::defrag_clauses() { + if (memory_pressure()) return; + IF_VERBOSE(1, verbose_stream() << "(sat-defrag)\n"); + clause_allocator& alloc = m_cls_allocator[!m_cls_allocator_idx]; + ptr_vector new_clauses, new_learned; + ptr_addr_map cls2offset; + for (clause* c : m_clauses) c->unmark_used(); + for (clause* c : m_learned) c->unmark_used(); + + svector vars; + for (unsigned i = 0; i < num_vars(); ++i) vars.push_back(i); + std::stable_sort(vars.begin(), vars.end(), cmp_activity(*this)); + literal_vector lits; + for (bool_var v : vars) lits.push_back(to_literal(v)), lits.push_back(~to_literal(v)); + + // walk clauses, reallocate them in an order that defragments memory and creates locality. + //for (literal lit : lits) { + //watch_list& wlist = m_watches[lit.index()]; + for (watch_list& wlist : m_watches) { + for (watched& w : wlist) { + if (w.is_clause()) { + clause& c1 = get_clause(w); + clause_offset offset; + if (c1.was_used()) { + offset = cls2offset[&c1]; + } + else { + clause* c2 = alloc.copy_clause(c1); + c1.mark_used(); + if (c1.is_learned()) { + new_learned.push_back(c2); + } + else { + new_clauses.push_back(c2); + } + offset = get_offset(*c2); + cls2offset.insert(&c1, offset); + } + w = watched(w.get_blocked_literal(), offset); + } + } + } + + // reallocate ternary clauses. + for (clause* c : m_clauses) { + if (!c->was_used()) { + SASSERT(c->size() == 3); + new_clauses.push_back(alloc.copy_clause(*c)); + } + dealloc_clause(c); + } + + for (clause* c : m_learned) { + if (!c->was_used()) { + SASSERT(c->size() == 3); + new_learned.push_back(alloc.copy_clause(*c)); + } + dealloc_clause(c); + } + m_clauses.swap(new_clauses); + m_learned.swap(new_learned); + + cls_allocator().finalize(); + m_cls_allocator_idx = !m_cls_allocator_idx; + } + + void solver::set_learned(literal l1, literal l2, bool learned) { set_learned1(l1, l2, learned); set_learned1(l2, l1, learned); @@ -702,6 +782,7 @@ namespace sat { m_reasoned[v] = 0; break; } + if (m_config.m_anti_exploration) { uint64 age = m_stats.m_conflict - m_canceled[v]; if (age > 0) { @@ -712,7 +793,10 @@ namespace sat { m_case_split_queue.activity_changed_eh(v, false); } } - + + if (m_config.m_propagate_prefetch) { + _mm_prefetch((char const*)(m_watches.c_ptr() + l.index()), 0); + } SASSERT(!l.sign() || m_phase[v] == NEG_PHASE); SASSERT(l.sign() || m_phase[v] == POS_PHASE); @@ -725,9 +809,8 @@ namespace sat { lbool solver::status(clause const & c) const { bool found_undef = false; - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - switch (value(c[i])) { + for (literal lit : c) { + switch (value(lit)) { case l_true: return l_true; case l_undef: @@ -1006,7 +1089,7 @@ namespace sat { return l_undef; } - restart(); + restart(!m_config.m_restart_fast); simplify_problem(); if (check_inconsistent()) return l_false; gc(); @@ -1507,6 +1590,7 @@ namespace sat { m_min_d_tk = 1.0; m_search_lvl = 0; m_conflicts_since_gc = 0; + m_restart_next_out = 0; m_asymm_branch.init_search(); m_stopwatch.reset(); m_stopwatch.start(); @@ -1752,15 +1836,34 @@ namespace sat { return ok; } - void solver::restart() { + void solver::restart(bool to_base) { m_stats.m_restart++; m_restarts++; - IF_VERBOSE(1, - verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision - << " :restarts " << m_stats.m_restart << mk_stat(*this) - << " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";); + if (m_conflicts_since_init > m_restart_next_out + 500) { + m_restart_next_out = m_conflicts_since_init; + IF_VERBOSE(1, + verbose_stream() << "(sat-restart :conflicts " << m_stats.m_conflict << " :decisions " << m_stats.m_decision + << " :restarts " << m_stats.m_restart << mk_stat(*this) + << " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";); + } IF_VERBOSE(30, display_status(verbose_stream());); - pop_reinit(scope_lvl() - search_lvl()); + unsigned num_scopes = 0; + if (to_base || scope_lvl() == search_lvl()) { + num_scopes = scope_lvl() - search_lvl(); + } + else { + bool_var next = m_case_split_queue.min_var(); + do { + scope& s = m_scopes[scope_lvl() - num_scopes - 1]; + bool_var prev = m_trail[s.m_trail_lim].var(); + //IF_VERBOSE(0, verbose_stream() << "more active: " << m_case_split_queue.more_active(next, prev) << "\n"); + if (!m_case_split_queue.more_active(next, prev)) break; + ++num_scopes; + } + while (num_scopes < scope_lvl() - search_lvl()); + //IF_VERBOSE(0, verbose_stream() << "backtrack " << num_scopes << " " << scope_lvl() - search_lvl() << "\n"); + } + pop_reinit(num_scopes); m_conflicts_since_restart = 0; switch (m_config.m_restart) { case RS_GEOMETRIC: @@ -1788,6 +1891,7 @@ namespace sat { return; if (m_config.m_gc_strategy == GC_DYN_PSM && !at_base_lvl()) return; + unsigned gc = m_stats.m_gc_clause; IF_VERBOSE(10, verbose_stream() << "(sat.gc)\n";); CASSERT("sat_gc_bug", check_invariant()); switch (m_config.m_gc_strategy) { @@ -1813,6 +1917,11 @@ namespace sat { break; } if (m_ext) m_ext->gc(); + if (gc > 0 && m_config.m_gc_defrag && !memory_pressure()) { + pop(scope_lvl()); + defrag_clauses(); + reinit_assumptions(); + } m_conflicts_since_gc = 0; m_gc_threshold += m_config.m_gc_increment; CASSERT("sat_gc_bug", check_invariant()); @@ -2320,8 +2429,7 @@ namespace sat { void solver::resolve_conflict_for_unsat_core() { TRACE("sat", display(tout); unsigned level = 0; - for (unsigned i = 0; i < m_trail.size(); ++i) { - literal l = m_trail[i]; + for (literal l : m_trail) { if (level != m_level[l.var()]) { level = m_level[l.var()]; tout << level << ": "; @@ -2341,8 +2449,8 @@ namespace sat { } SASSERT(m_unmark.empty()); DEBUG_CODE({ - for (unsigned i = 0; i < m_trail.size(); ++i) { - SASSERT(!is_marked(m_trail[i].var())); + for (literal lit : m_trail) { + SASSERT(!is_marked(lit.var())); }}); unsigned old_size = m_unmark.size(); @@ -2798,8 +2906,7 @@ namespace sat { } } reset_mark(m_lemma[0].var()); - for (unsigned i = m_lemma.size(); i > sz; ) { - --i; + for (unsigned i = m_lemma.size(); i-- > sz; ) { reset_mark(m_lemma[i].var()); } m_lemma.shrink(sz); @@ -3431,7 +3538,7 @@ namespace sat { } void solver::display_watches(std::ostream & out, literal lit) const { - sat::display_watch_list(out << lit << ": ", m_cls_allocator, get_wlist(lit)) << "\n"; + display_watch_list(out << lit << ": ", get_wlist(lit)) << "\n"; } void solver::display_watches(std::ostream & out) const { @@ -3439,10 +3546,14 @@ namespace sat { for (watch_list const& wlist : m_watches) { literal l = to_literal(l_idx++); if (!wlist.empty()) - sat::display_watch_list(out << l << ": ", m_cls_allocator, wlist) << "\n"; + display_watch_list(out << l << ": ", wlist) << "\n"; } } + std::ostream& solver::display_watch_list(std::ostream& out, watch_list const& wl) const { + return sat::display_watch_list(out, cls_allocator(), wl); + } + void solver::display_assignment(std::ostream & out) const { out << m_trail << "\n"; } @@ -3774,7 +3885,7 @@ namespace sat { return l_undef; } - restart(); + restart(true); simplify_problem(); if (check_inconsistent()) { fixup_consequence_core(); @@ -3867,7 +3978,7 @@ namespace sat { else { is_sat = bounded_search(); if (is_sat == l_undef) { - restart(); + restart(true); } extract_fixed_consequences(unfixed_lits, assumptions, unfixed_vars, conseq); } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 1bf78ab8c..606907f54 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -86,7 +86,8 @@ namespace sat { scoped_ptr m_ext; parallel* m_par; random_gen m_rand; - clause_allocator m_cls_allocator; + clause_allocator m_cls_allocator[2]; + bool m_cls_allocator_idx; cleaner m_cleaner; model m_model; model_converter m_mc; @@ -217,9 +218,16 @@ namespace sat { void mk_clause(literal_vector const& lits, bool learned = false) { mk_clause(lits.size(), lits.c_ptr(), learned); } void mk_clause(unsigned num_lits, literal * lits, bool learned = false); void mk_clause(literal l1, literal l2, bool learned = false); - void mk_clause(literal l1, literal l2, literal l3, bool learned = false); + void mk_clause(literal l1, literal l2, literal l3, bool learned = false); protected: + inline clause_allocator& cls_allocator() { return m_cls_allocator[m_cls_allocator_idx]; } + inline clause_allocator const& cls_allocator() const { return m_cls_allocator[m_cls_allocator_idx]; } + inline clause * alloc_clause(unsigned num_lits, literal const * lits, bool learned) { return cls_allocator().mk_clause(num_lits, lits, learned); } + inline void dealloc_clause(clause* c) { cls_allocator().del_clause(c); } + struct cmp_activity; + void defrag_clauses(); + bool memory_pressure(); void del_clause(clause & c); clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned); clause * mk_clause_core(literal_vector const& lits) { return mk_clause_core(lits.size(), lits.c_ptr()); } @@ -301,7 +309,7 @@ namespace sat { void set_conflict(justification c, literal not_l); void set_conflict(justification c) { set_conflict(c, null_literal); } lbool status(clause const & c) const; - clause_offset get_offset(clause const & c) const { return m_cls_allocator.get_offset(&c); } + clause_offset get_offset(clause const & c) const { return cls_allocator().get_offset(&c); } void checkpoint() { if (!m_checkpoint_enabled) return; if (!m_rlimit.inc()) { @@ -373,6 +381,7 @@ namespace sat { unsigned m_conflicts_since_init; unsigned m_restarts; + unsigned m_restart_next_out; unsigned m_conflicts_since_restart; unsigned m_simplifications; unsigned m_restart_threshold; @@ -405,7 +414,7 @@ namespace sat { void simplify_problem(); void mk_model(); bool check_model(model const & m) const; - void restart(); + void restart(bool to_base); void sort_watch_lits(); void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); @@ -437,7 +446,7 @@ namespace sat { if (value(l0) != l_true) return true; justification const & jst = m_justification[l0.var()]; - return !jst.is_clause() || m_cls_allocator.get_clause(jst.get_clause_offset()) != &c; + return !jst.is_clause() || cls_allocator().get_clause(jst.get_clause_offset()) != &c; } clause& get_clause(watch_list::iterator it) const { @@ -445,13 +454,18 @@ namespace sat { return get_clause(it->get_clause_offset()); } + clause& get_clause(watched const& w) const { + SASSERT(w.get_kind() == watched::CLAUSE); + return get_clause(w.get_clause_offset()); + } + clause& get_clause(justification const& j) const { SASSERT(j.is_clause()); return get_clause(j.get_clause_offset()); } clause& get_clause(clause_offset cls_off) const { - return *(m_cls_allocator.get_clause(cls_off)); + return *(cls_allocator().get_clause(cls_off)); } // ----------------------- @@ -634,6 +648,7 @@ namespace sat { void display_wcnf(std::ostream & out, unsigned sz, literal const* lits, unsigned const* weights) const; void display_assignment(std::ostream & out) const; std::ostream& display_justification(std::ostream & out, justification const& j) const; + std::ostream& display_watch_list(std::ostream& out, watch_list const& wl) const; protected: void display_binary(std::ostream & out) const; diff --git a/src/sat/sat_var_queue.h b/src/sat/sat_var_queue.h index 656e4b071..0c22766ba 100644 --- a/src/sat/sat_var_queue.h +++ b/src/sat/sat_var_queue.h @@ -72,6 +72,8 @@ namespace sat { bool_var next_var() { SASSERT(!empty()); return m_queue.erase_min(); } bool_var min_var() { SASSERT(!empty()); return m_queue.min_value(); } + + bool more_active(bool_var v1, bool_var v2) const { return m_queue.less_than(v1, v2); } }; }; diff --git a/src/util/heap.h b/src/util/heap.h index 02e30bf04..182932fd0 100644 --- a/src/util/heap.h +++ b/src/util/heap.h @@ -27,10 +27,6 @@ class heap : private LT { int_vector m_values; int_vector m_value2indices; - bool less_than(int v1, int v2) const { - return LT::operator()(v1, v2); - } - static int left(int i) { return i << 1; } @@ -126,6 +122,10 @@ public: CASSERT("heap", check_invariant()); } + bool less_than(int v1, int v2) const { + return LT::operator()(v1, v2); + } + bool empty() const { return m_values.size() == 1; } From 2f025f52c0452d299afdc6925b6ea352ec01337c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 Apr 2018 22:26:01 +0200 Subject: [PATCH 0812/1283] fix local search initialization of units, encode offset in clauses Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.cpp | 18 +++++++++++++++++- src/sat/sat_clause.h | 2 ++ src/sat/sat_local_search.cpp | 27 +++++++++++++++++---------- src/sat/sat_solver.cpp | 8 ++++---- src/solver/parallel_params.pyg | 2 +- src/solver/parallel_tactic.cpp | 8 ++++++-- 6 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index f9caffe94..78d62bac0 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -95,7 +95,6 @@ namespace sat { } } - bool clause::satisfied_by(model const & m) const { for (literal l : *this) { if (l.sign()) { @@ -110,6 +109,23 @@ namespace sat { return false; } + clause_offset clause::get_new_offset() const { + unsigned o1 = m_lits[0].index(); + if (sizeof(clause_offset) == 8) { + unsigned o2 = m_lits[1].index(); + return (clause_offset)o1 + (((clause_offset)o2) << 32); + } + return (clause_offset)o1; + } + + void clause::set_new_offset(clause_offset offset) { + m_lits[0] = to_literal(static_cast(offset)); + if (sizeof(offset) == 8) { + m_lits[1] = to_literal(static_cast(offset >> 32)); + } + } + + void tmp_clause::set(unsigned num_lits, literal const * lits, bool learned) { if (m_clause && m_clause->m_capacity < num_lits) { dealloc_svect(m_clause); diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index c42427afb..8b2d113c8 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -98,6 +98,8 @@ namespace sat { unsigned glue() const { return m_glue; } void set_psm(unsigned psm) { m_psm = psm > 255 ? 255 : psm; } unsigned psm() const { return m_psm; } + clause_offset get_new_offset() const; + void set_new_offset(clause_offset off); bool on_reinit_stack() const { return m_reinit_stack; } void set_reinit_stack(bool f) { m_reinit_stack = f; } diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 35e371a9c..e02560e5f 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -79,11 +79,13 @@ namespace sat { void local_search::init_cur_solution() { for (var_info& vi : m_vars) { // use bias with a small probability - if (m_rand() % 10 < 5 || m_config.phase_sticky()) { - vi.m_value = ((unsigned)(m_rand() % 100) < vi.m_bias); - } - else { - vi.m_value = (m_rand() % 2) == 0; + if (!vi.m_unit) { + if (m_rand() % 10 < 5 || m_config.phase_sticky()) { + vi.m_value = ((unsigned)(m_rand() % 100) < vi.m_bias); + } + else { + vi.m_value = (m_rand() % 2) == 0; + } } } } @@ -149,7 +151,7 @@ namespace sat { void local_search::reinit() { - IF_VERBOSE(0, verbose_stream() << "(sat-local-search reinit)\n";); + IF_VERBOSE(1, verbose_stream() << "(sat-local-search reinit)\n";); if (true || !m_is_pb) { // // the following methods does NOT converge for pseudo-boolean @@ -216,13 +218,15 @@ namespace sat { for (unsigned i = 0; i < m_prop_queue.size() && i < m_vars.size(); ++i) { literal lit2 = m_prop_queue[i]; if (!is_true(lit2)) { - if (is_unit(lit2)) return false; + if (is_unit(lit2)) { + return false; + } flip_walksat(lit2.var()); add_propagation(lit2); } } if (m_prop_queue.size() >= m_vars.size()) { - IF_VERBOSE(0, verbose_stream() << "failed literal\n"); + IF_VERBOSE(0, verbose_stream() << "propagation loop\n"); return false; } if (unit) { @@ -328,6 +332,7 @@ namespace sat { return; } if (k == 1 && sz == 2) { + // IF_VERBOSE(0, verbose_stream() << "bin: " << ~c[0] << " + " << ~c[1] << " <= 1\n"); for (unsigned i = 0; i < 2; ++i) { literal t(c[i]), s(c[1-i]); m_vars.reserve(t.var() + 1); @@ -750,11 +755,12 @@ namespace sat { IF_VERBOSE(1, verbose_stream() << "(sat.local_search :unsat)\n"); return; } - + if (is_unit(best_var)) { + goto reflip; + } flip_walksat(best_var); literal lit(best_var, !cur_solution(best_var)); if (!propagate(lit)) { - IF_VERBOSE(0, verbose_stream() << "failed literal " << lit << "\n"); if (is_true(lit)) { flip_walksat(best_var); } @@ -774,6 +780,7 @@ namespace sat { } void local_search::flip_walksat(bool_var flipvar) { + VERIFY(!is_unit(flipvar)); m_vars[flipvar].m_value = !cur_solution(flipvar); bool flip_is_true = cur_solution(flipvar); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 792883977..90ac876d2 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -529,26 +529,26 @@ namespace sat { IF_VERBOSE(1, verbose_stream() << "(sat-defrag)\n"); clause_allocator& alloc = m_cls_allocator[!m_cls_allocator_idx]; ptr_vector new_clauses, new_learned; - ptr_addr_map cls2offset; for (clause* c : m_clauses) c->unmark_used(); for (clause* c : m_learned) c->unmark_used(); +#if 0 svector vars; for (unsigned i = 0; i < num_vars(); ++i) vars.push_back(i); std::stable_sort(vars.begin(), vars.end(), cmp_activity(*this)); literal_vector lits; for (bool_var v : vars) lits.push_back(to_literal(v)), lits.push_back(~to_literal(v)); - // walk clauses, reallocate them in an order that defragments memory and creates locality. //for (literal lit : lits) { //watch_list& wlist = m_watches[lit.index()]; +#endif for (watch_list& wlist : m_watches) { for (watched& w : wlist) { if (w.is_clause()) { clause& c1 = get_clause(w); clause_offset offset; if (c1.was_used()) { - offset = cls2offset[&c1]; + offset = c1.get_new_offset(); } else { clause* c2 = alloc.copy_clause(c1); @@ -560,7 +560,7 @@ namespace sat { new_clauses.push_back(c2); } offset = get_offset(*c2); - cls2offset.insert(&c1, offset); + c1.set_new_offset(offset); } w = watched(w.get_blocked_literal(), offset); } diff --git a/src/solver/parallel_params.pyg b/src/solver/parallel_params.pyg index 58c00aa97..2d58cbb81 100644 --- a/src/solver/parallel_params.pyg +++ b/src/solver/parallel_params.pyg @@ -5,7 +5,7 @@ def_module_params('parallel', params=( ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), ('threads.max', UINT, 10000, 'caps maximal number of threads below the number of processors'), - ('conquer.batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), + ('conquer.batch_size', UINT, 100, 'number of cubes to batch together for fast conquer'), ('conquer.restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), ('conquer.delay', UINT, 10, 'delay of cubes until applying conquer'), ('conquer.backtrack_frequency', UINT, 10, 'frequency to apply core minimization during conquer'), diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index 748ee5d64..ac147672e 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -99,6 +99,8 @@ class parallel_tactic : public tactic { } } + bool in_shutdown() const { return m_shutdown; } + void add_task(solver_state* task) { std::lock_guard lock(m_mutex); m_tasks.push_back(task); @@ -285,6 +287,7 @@ class parallel_tactic : public tactic { p.set_uint("restart.max", pp.simplify_restart_max() * mult); p.set_bool("lookahead_simplify", true); p.set_bool("retain_blocked_clauses", retain_blocked); + if (m_depth > 1) p.set_uint("bce_delay", 0); get_solver().updt_params(p); } @@ -479,8 +482,8 @@ private: break; } - if (cubes.size() >= conquer_batch_size() || (!cubes.empty() && m_queue.is_idle())) { - spawn_cubes(s, std::max(2u, width), cubes); + if (cubes.size() >= conquer_batch_size()) { + spawn_cubes(s, 10*width, cubes); first = false; cubes.reset(); } @@ -575,6 +578,7 @@ private: } catch (z3_exception& ex) { IF_VERBOSE(1, verbose_stream() << ex.msg() << "\n";); + if (m_queue.in_shutdown()) return; m_queue.shutdown(); std::lock_guard lock(m_mutex); if (ex.has_error_code()) { From b8193a0ae62e9abc6a1c887b177d4bfec2757a5b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 Apr 2018 10:04:42 -0700 Subject: [PATCH 0813/1283] fix #1604 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/context_params.cpp | 2 +- src/cmd_context/extra_cmds/dbg_cmds.cpp | 2 +- src/shell/lp_frontend.cpp | 4 +-- src/util/env_params.cpp | 2 +- src/util/gparams.cpp | 46 +++++++++---------------- src/util/gparams.h | 3 +- src/util/params.cpp | 23 +++++++------ 7 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index 85ac2274b..ff39907da 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -135,7 +135,7 @@ void context_params::set(char const * param, char const * value) { } void context_params::updt_params() { - updt_params(gparams::get()); + updt_params(gparams::get_ref()); } void context_params::updt_params(params_ref const & p) { diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 465bcb956..fa1d56fe2 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -271,7 +271,7 @@ UNARY_CMD(elim_unused_vars_cmd, "dbg-elim-unused-vars", "", "eliminate unu return; } expr_ref r(ctx.m()); - elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get(), r); + elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get_ref(), r); SASSERT(!is_quantifier(r) || !to_quantifier(r)->may_have_unused_vars()); ctx.display(ctx.regular_stream(), r); ctx.regular_stream() << std::endl; diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index c79396cd1..ad9bcbd54 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -55,8 +55,8 @@ struct front_end_resource_limit : public lp::lp_resource_limit { void run_solver(lp_params & params, char const * mps_file_name) { reslimit rlim; - unsigned timeout = gparams::get().get_uint("timeout", 0); - unsigned rlimit = gparams::get().get_uint("rlimit", 0); + unsigned timeout = gparams::get_ref().get_uint("timeout", 0); + unsigned rlimit = gparams::get_ref().get_uint("rlimit", 0); front_end_resource_limit lp_limit(rlim); scoped_rlimit _rlimit(rlim, rlimit); diff --git a/src/util/env_params.cpp b/src/util/env_params.cpp index c2b5f7974..3ba6df735 100644 --- a/src/util/env_params.cpp +++ b/src/util/env_params.cpp @@ -23,7 +23,7 @@ Notes: #include "util/memory_manager.h" void env_params::updt_params() { - params_ref p = gparams::get(); + params_ref const& p = gparams::get_ref(); set_verbosity_level(p.get_uint("verbose", get_verbosity_level())); enable_warning_messages(p.get_bool("warning", true)); memory::set_max_size(megabytes_to_bytes(p.get_uint("memory_max_size", 0))); diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 12c335cdf..183525320 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -104,10 +104,8 @@ public: ~imp() { reset(); - dictionary::iterator it = m_module_param_descrs.begin(); - dictionary::iterator end = m_module_param_descrs.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (auto & kv : m_module_param_descrs) { + dealloc(kv.m_value); } } @@ -115,10 +113,8 @@ public: #pragma omp critical (gparams) { m_params.reset(); - dictionary::iterator it = m_module_params.begin(); - dictionary::iterator end = m_module_params.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (auto & kv : m_module_params) { + dealloc(kv.m_value); } m_module_params.reset(); } @@ -437,14 +433,8 @@ public: return result; } - params_ref get() { - params_ref result; - TRACE("gparams", tout << "get() m_params: " << m_params << "\n";); - #pragma omp critical (gparams) - { - result = m_params; - } - return result; + params_ref const& get_ref() { + return m_params; } // ----------------------------------------------- @@ -464,16 +454,14 @@ public: out << "Example: pp.decimal=true\n"; out << "\n"; } - dictionary::iterator it = get_module_param_descrs().begin(); - dictionary::iterator end = get_module_param_descrs().end(); - for (; it != end; ++it) { - out << "[module] " << it->m_key; + for (auto & kv : get_module_param_descrs()) { + out << "[module] " << kv.m_key; char const * descr = nullptr; - if (get_module_descrs().find(it->m_key, descr)) { + if (get_module_descrs().find(kv.m_key, descr)) { out << ", description: " << descr; } out << "\n"; - it->m_value->display(out, indent + 4, smt2_style, include_descr); + kv.m_value->display(out, indent + 4, smt2_style, include_descr); } } } @@ -481,12 +469,10 @@ public: void display_modules(std::ostream & out) { #pragma omp critical (gparams) { - dictionary::iterator it = get_module_param_descrs().begin(); - dictionary::iterator end = get_module_param_descrs().end(); - for (; it != end; ++it) { - out << "[module] " << it->m_key; + for (auto & kv : get_module_param_descrs()) { + out << "[module] " << kv.m_key; char const * descr = nullptr; - if (get_module_descrs().find(it->m_key, descr)) { + if (get_module_descrs().find(kv.m_key, descr)) { out << ", description: " << descr; } out << "\n"; @@ -618,10 +604,10 @@ params_ref gparams::get_module(symbol const & module_name) { return g_imp->get_module(module_name); } -params_ref gparams::get() { - TRACE("gparams", tout << "gparams::get()\n";); +params_ref const& gparams::get_ref() { + TRACE("gparams", tout << "gparams::get_ref()\n";); SASSERT(g_imp != 0); - return g_imp->get(); + return g_imp->get_ref(); } void gparams::display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr) { diff --git a/src/util/gparams.h b/src/util/gparams.h index 7ddaf0ccb..5334b28d0 100644 --- a/src/util/gparams.h +++ b/src/util/gparams.h @@ -106,7 +106,8 @@ public: /** \brief Return the global parameter set (i.e., parameters that are not associated with any particular module). */ - static params_ref get(); + + static params_ref const& get_ref(); /** \brief Dump information about available parameters in the given output stream. diff --git a/src/util/params.cpp b/src/util/params.cpp index 5e1e517c1..6bb6678cc 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -334,7 +334,10 @@ public: } void inc_ref() { m_ref_count++; } - void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); } + void dec_ref() { + SASSERT(m_ref_count > 0); + if (--m_ref_count == 0) dealloc(this); + } bool empty() const { return m_entries.empty(); } bool contains(symbol const & k) const; @@ -565,27 +568,25 @@ void params_ref::copy(params_ref const & src) { void params_ref::copy_core(params const * src) { if (src == nullptr) return; - svector::const_iterator it = src->m_entries.begin(); - svector::const_iterator end = src->m_entries.end(); - for (; it != end; ++it) { - switch (it->second.m_kind) { + for (auto const& p : src->m_entries) { + switch (p.second.m_kind) { case CPK_BOOL: - m_params->set_bool(it->first, it->second.m_bool_value); + m_params->set_bool(p.first, p.second.m_bool_value); break; case CPK_UINT: - m_params->set_uint(it->first, it->second.m_uint_value); + m_params->set_uint(p.first, p.second.m_uint_value); break; case CPK_DOUBLE: - m_params->set_double(it->first, it->second.m_double_value); + m_params->set_double(p.first, p.second.m_double_value); break; case CPK_NUMERAL: - m_params->set_rat(it->first, *(it->second.m_rat_value)); + m_params->set_rat(p.first, *(p.second.m_rat_value)); break; case CPK_SYMBOL: - m_params->set_sym(it->first, symbol::mk_symbol_from_c_ptr(it->second.m_sym_value)); + m_params->set_sym(p.first, symbol::mk_symbol_from_c_ptr(p.second.m_sym_value)); break; case CPK_STRING: - m_params->set_str(it->first, it->second.m_str_value); + m_params->set_str(p.first, p.second.m_str_value); break; default: UNREACHABLE(); From e940f53e9c58df2c1ca239bc3352dcf29b3a1caf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Apr 2018 07:57:33 -0700 Subject: [PATCH 0814/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/sat/sat_config.cpp | 4 ++- src/sat/sat_config.h | 3 ++- src/sat/sat_lookahead.cpp | 2 +- src/sat/sat_params.pyg | 3 ++- src/sat/sat_solver.cpp | 53 +++++++++++++++++++++------------------ src/sat/sat_solver.h | 1 + 6 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index f7e2e2404..2bf20100b 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -115,9 +115,11 @@ namespace sat { m_lookahead_cube_psat_clause_base = p.lookahead_cube_psat_clause_base(); m_lookahead_cube_psat_trigger = p.lookahead_cube_psat_trigger(); m_lookahead_global_autarky = p.lookahead_global_autarky(); + m_lookahead_use_learned = p.lookahead_use_learned(); + // These parameters are not exposed - m_simplify_mult1 = _p.get_uint("simplify_mult1", 300); + m_next_simplify1 = _p.get_uint("next_simplify", 30000); m_simplify_mult2 = _p.get_double("simplify_mult2", 1.5); m_simplify_max = _p.get_uint("simplify_max", 500000); // -------------------------------- diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index f04973d13..9153f8b14 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -113,9 +113,10 @@ namespace sat { double m_lookahead_cube_psat_trigger; reward_t m_lookahead_reward; bool m_lookahead_global_autarky; + bool m_lookahead_use_learned; bool m_incremental; - unsigned m_simplify_mult1; + unsigned m_next_simplify1; double m_simplify_mult2; unsigned m_simplify_max; unsigned m_simplify_delay; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index d4d1e615f..57ef90af9 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -2227,7 +2227,7 @@ namespace sat { void lookahead::init_search() { m_search_mode = lookahead_mode::searching; scoped_level _sl(*this, c_fixed_truth); - init(true); + init(m_s.m_config.m_lookahead_use_learned); } void lookahead::checkpoint() { diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index cf6ecc4f5..324882894 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -12,7 +12,7 @@ def_module_params('sat', ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), ('restart.fast', BOOL, False, 'use fast restart strategy.'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), - ('variable_decay', UINT, 120, 'multiplier (divided by 100) for the VSIDS activity increement'), + ('variable_decay', UINT, 110, 'multiplier (divided by 100) for the VSIDS activity increement'), ('inprocess.max', UINT, UINT_MAX, 'maximal number of inprocessing passes'), ('branching.heuristic', SYMBOL, 'vsids', 'branching heuristic vsids, lrb or chb'), ('branching.anti_exploration', BOOL, False, 'apply anti-exploration heuristic for branch selection'), @@ -56,6 +56,7 @@ def_module_params('sat', ('lookahead_search', BOOL, False, 'use lookahead solver'), ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), + ('lookahead.use_learned', BOOL, False, 'use learned clauses when selecting lookahead literal'), ('lookahead_simplify.bca', BOOL, True, 'add learned binary clauses as part of lookahead simplification'), ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), ('lookahead.reward', SYMBOL, 'march_cu', 'select lookahead heuristic: ternary, heule_schur (Heule Schur), heuleu (Heule Unit), unit, or march_cu'))) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 90ac876d2..f91dedeb5 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -532,17 +532,15 @@ namespace sat { for (clause* c : m_clauses) c->unmark_used(); for (clause* c : m_learned) c->unmark_used(); -#if 0 svector vars; for (unsigned i = 0; i < num_vars(); ++i) vars.push_back(i); std::stable_sort(vars.begin(), vars.end(), cmp_activity(*this)); literal_vector lits; - for (bool_var v : vars) lits.push_back(to_literal(v)), lits.push_back(~to_literal(v)); + for (bool_var v : vars) lits.push_back(literal(v, false)), lits.push_back(literal(v, true)); // walk clauses, reallocate them in an order that defragments memory and creates locality. - //for (literal lit : lits) { - //watch_list& wlist = m_watches[lit.index()]; -#endif - for (watch_list& wlist : m_watches) { + for (literal lit : lits) { + watch_list& wlist = m_watches[lit.index()]; + // for (watch_list& wlist : m_watches) { for (watched& w : wlist) { if (w.is_clause()) { clause& c1 = get_clause(w); @@ -795,7 +793,7 @@ namespace sat { } if (m_config.m_propagate_prefetch) { - _mm_prefetch((char const*)(m_watches.c_ptr() + l.index()), 0); + _mm_prefetch((const char*)(m_watches[l.index()].c_ptr()), 1); } SASSERT(!l.sign() || m_phase[v] == NEG_PHASE); @@ -1502,7 +1500,6 @@ namespace sat { SASSERT(m_search_lvl == 1); } - void solver::update_min_core() { if (!m_min_core_valid || m_core.size() < m_min_core.size()) { m_min_core.reset(); @@ -1533,8 +1530,7 @@ namespace sat { push(); reset_assumptions(); TRACE("sat", tout << "reassert: " << m_min_core << "\n";); - for (unsigned i = 0; i < m_min_core.size(); ++i) { - literal lit = m_min_core[i]; + for (literal lit : m_min_core) { SASSERT(is_external(lit.var())); add_assumption(lit); assign(lit, justification()); @@ -1554,12 +1550,12 @@ namespace sat { assign(m_assumptions[i], justification()); } TRACE("sat", - for (unsigned i = 0; i < m_assumptions.size(); ++i) { - index_set s; - if (m_antecedents.find(m_assumptions[i].var(), s)) { - tout << m_assumptions[i] << ": "; display_index_set(tout, s) << "\n"; - } - }); + for (literal a : m_assumptions) { + index_set s; + if (m_antecedents.find(a.var(), s)) { + tout << a << ": "; display_index_set(tout, s) << "\n"; + } + }); } } @@ -1602,7 +1598,6 @@ namespace sat { /** \brief Apply all simplifications. - */ void solver::simplify_problem() { if (m_conflicts_since_init < m_next_simplify) { @@ -1657,7 +1652,7 @@ namespace sat { reinit_assumptions(); if (m_next_simplify == 0) { - m_next_simplify = m_config.m_restart_initial * m_config.m_simplify_mult1; + m_next_simplify = m_config.m_next_simplify1; } else { m_next_simplify = static_cast(m_conflicts_since_init * m_config.m_simplify_mult2); @@ -1853,15 +1848,23 @@ namespace sat { } else { bool_var next = m_case_split_queue.min_var(); + + // Implementations of Marijn's idea of reusing the + // trail when the next decision literal has lower precedence. +#if 0 + // pop the trail from top do { - scope& s = m_scopes[scope_lvl() - num_scopes - 1]; - bool_var prev = m_trail[s.m_trail_lim].var(); - //IF_VERBOSE(0, verbose_stream() << "more active: " << m_case_split_queue.more_active(next, prev) << "\n"); - if (!m_case_split_queue.more_active(next, prev)) break; + bool_var prev = scope_literal(scope_lvl() - num_scopes - 1).var(); + if (m_case_split_queue.more_active(prev, next)) break; ++num_scopes; } while (num_scopes < scope_lvl() - search_lvl()); - //IF_VERBOSE(0, verbose_stream() << "backtrack " << num_scopes << " " << scope_lvl() - search_lvl() << "\n"); +#else + // pop the trail from bottom + unsigned n = search_lvl(); + for (; n < scope_lvl() && m_case_split_queue.more_active(scope_literal(n).var(), next); ++n) ; + num_scopes = n - search_lvl(); +#endif } pop_reinit(num_scopes); m_conflicts_since_restart = 0; @@ -2860,7 +2863,8 @@ namespace sat { \brief Reset the mark of the variables in the current lemma. */ void solver::reset_lemma_var_marks() { - if (m_config.m_branching_heuristic == BH_LRB) { + if (m_config.m_branching_heuristic == BH_LRB || + m_config.m_branching_heuristic == BH_VSIDS) { update_lrb_reasoned(); } literal_vector::iterator it = m_lemma.begin(); @@ -2917,6 +2921,7 @@ namespace sat { if (!is_marked(v)) { mark(v); m_reasoned[v]++; + inc_activity(v); m_lemma.push_back(lit); } } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 606907f54..15ac4df29 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -297,6 +297,7 @@ namespace sat { unsigned lvl(literal l) const { return m_level[l.var()]; } unsigned init_trail_size() const { return at_base_lvl() ? m_trail.size() : m_scopes[0].m_trail_lim; } literal trail_literal(unsigned i) const { return m_trail[i]; } + literal scope_literal(unsigned n) const { return m_trail[m_scopes[n].m_trail_lim]; } void assign(literal l, justification j) { TRACE("sat_assign", tout << l << " previous value: " << value(l) << "\n";); switch (value(l)) { From ef31b27d5ef497e4f00eec20dfead0a54ff431c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Apr 2018 14:36:45 -0700 Subject: [PATCH 0815/1283] merge Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Params.cs | 8 ------- src/api/dotnet/Solver.cs | 46 ---------------------------------------- 2 files changed, 54 deletions(-) diff --git a/src/api/dotnet/Params.cs b/src/api/dotnet/Params.cs index 3bd22e5b0..5b143d525 100644 --- a/src/api/dotnet/Params.cs +++ b/src/api/dotnet/Params.cs @@ -91,11 +91,7 @@ namespace Microsoft.Z3 public Params Add(string name, bool value) { Native.Z3_params_set_bool(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, (value) ? 1 : 0); -<<<<<<< HEAD return this; -======= - return this; ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 } /// @@ -104,11 +100,7 @@ namespace Microsoft.Z3 public Params Add(string name, uint value) { Native.Z3_params_set_uint(Context.nCtx, NativeObject, Context.MkSymbol(name).NativeObject, value); -<<<<<<< HEAD return this; -======= - return this; ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 } /// diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 77480f693..a288990a2 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -99,48 +99,6 @@ namespace Microsoft.Z3 public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(string name, bool value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(string name, uint value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(string name, double value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(string name, string value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(string name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, bool value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, uint value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, double value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, string value) { Parameters = Context.MkParams().Add(name, value); } - /// - /// Sets parameter on the solver - /// - public void Set(Symbol name, Symbol value) { Parameters = Context.MkParams().Add(name, value); } - - /// /// Retrieves parameter descriptions for solver. @@ -359,10 +317,6 @@ namespace Microsoft.Z3 return lboolToStatus(r); } -<<<<<<< HEAD - -======= ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 /// /// Retrieve fixed assignments to the set of variables in the form of consequences. /// Each consequence is an implication of the form From 832803b213e4f4854b719305d02272ea87b2b04e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Apr 2018 15:59:01 -0700 Subject: [PATCH 0816/1283] merge Signed-off-by: Nikolaj Bjorner --- src/api/java/Context.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 7037814c2..dee9dbaf6 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2549,14 +2549,9 @@ public class Context implements AutoCloseable { * set of assertions returned are the ones in the * last scope level. **/ -<<<<<<< HEAD public BoolExpr[] parseSMTLIB2String(String str, Symbol[] sortNames, Sort[] sorts, Symbol[] declNames, FuncDecl[] decls) -======= - public BoolExpr parseSMTLIB2String(String str, Symbol[] sortNames, - Sort[] sorts, Symbol[] declNames, FuncDecl[] decls) ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 { int csn = Symbol.arrayLength(sortNames); int cs = Sort.arrayLength(sorts); From 6807210c8b49933ee7b432e958040c7a26d4825b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Apr 2018 16:00:07 -0700 Subject: [PATCH 0817/1283] merge Signed-off-by: Nikolaj Bjorner --- src/api/java/Solver.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index a1a852791..0370a9571 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -121,22 +121,6 @@ public class Solver extends Z3Object { } } - /** - * Load solver assertions from a file. - */ - public void fromFile(String file) - { - Native.solverFromFile(getContext().nCtx(), getNativeObject(), file); - } - - /** - * Load solver assertions from a string. - */ - public void fromString(String str) - { - Native.solverFromString(getContext().nCtx(), getNativeObject(), str); - } - /** * Assert multiple constraints into the solver, and track them (in the From 371880da04b0260c0db1bf5f4c3c6975fd8cfc70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 07:13:03 -0700 Subject: [PATCH 0818/1283] n/a Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 54 ++++++++------------------------------ src/smt/smt_context_pp.cpp | 5 +--- src/smt/smt_enode.h | 41 +++++++++++++++++++++++------ 3 files changed, 45 insertions(+), 55 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index e20eae0bd..177dbb355 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -627,10 +627,7 @@ namespace smt { */ void context::remove_parents_from_cg_table(enode * r1) { // Remove parents from the congruence table - enode_vector::iterator it = r1->begin_parents(); - enode_vector::iterator end = r1->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r1->get_parents()) { #if 0 { static unsigned num_eqs = 0; @@ -675,10 +672,7 @@ namespace smt { */ void context::reinsert_parents_into_cg_table(enode * r1, enode * r2, enode * n1, enode * n2, eq_justification js) { enode_vector & r2_parents = r2->m_parents; - enode_vector::iterator it = r1->begin_parents(); - enode_vector::iterator end = r1->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r1->get_parents()) { if (!parent->is_marked()) continue; parent->unset_mark(); @@ -1008,10 +1002,7 @@ namespace smt { r2->m_parents.shrink(r2_num_parents); // try to reinsert parents of r1 that are not cgr - it = r1->begin_parents(); - end = r1->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r1->get_parents()) { TRACE("add_eq_parents", tout << "visiting: #" << parent->get_owner_id() << "\n";); if (parent->is_cgc_enabled()) { enode * cg = parent->m_cg; @@ -1206,10 +1197,7 @@ namespace smt { bool context::is_diseq_slow(enode * n1, enode * n2) const { if (n1->get_num_parents() > n2->get_num_parents()) std::swap(n1, n2); - enode_vector::iterator it = n1->begin_parents(); - enode_vector::iterator end = n1->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : n1->get_parents()) { if (parent->is_eq() && is_relevant(parent->get_owner()) && get_assignment(enode2bool_var(parent)) == l_false && ((parent->get_arg(0)->get_root() == n1->get_root() && parent->get_arg(1)->get_root() == n2->get_root()) || (parent->get_arg(1)->get_root() == n1->get_root() && parent->get_arg(0)->get_root() == n2->get_root()))) { @@ -1241,10 +1229,7 @@ namespace smt { return false; if (r1->get_num_parents() < SMALL_NUM_PARENTS) { TRACE("is_ext_diseq", tout << mk_bounded_pp(n1->get_owner(), m_manager) << " " << mk_bounded_pp(n2->get_owner(), m_manager) << " " << depth << "\n";); - enode_vector::iterator it1 = r1->begin_parents(); - enode_vector::iterator end1 = r1->end_parents(); - for (; it1 != end1; ++it1) { - enode * p1 = *it1; + for (enode* p1 : r1->get_parents()) { if (!is_relevant(p1)) continue; if (p1->is_eq()) @@ -1254,10 +1239,7 @@ namespace smt { func_decl * f = p1->get_decl(); TRACE("is_ext_diseq", tout << "p1: " << mk_bounded_pp(p1->get_owner(), m_manager) << "\n";); unsigned num_args = p1->get_num_args(); - enode_vector::iterator it2 = r2->begin_parents(); - enode_vector::iterator end2 = r2->end_parents(); - for (; it2 != end2; ++it2) { - enode * p2 = *it2; + for (enode * p2 : r2->get_parents()) { if (!is_relevant(p2)) continue; if (p2->is_eq()) @@ -1295,10 +1277,7 @@ namespace smt { } almost_cg_table & table = *(m_almost_cg_tables[depth]); table.reset(r1, r2); - enode_vector::iterator it1 = r1->begin_parents(); - enode_vector::iterator end1 = r1->end_parents(); - for (; it1 != end1; ++it1) { - enode * p1 = *it1; + for (enode* p1 : r1->get_parents()) { if (!is_relevant(p1)) continue; if (p1->is_eq()) @@ -1309,10 +1288,7 @@ namespace smt { } if (table.empty()) return false; - enode_vector::iterator it2 = r2->begin_parents(); - enode_vector::iterator end2 = r2->end_parents(); - for (; it2 != end2; ++it2) { - enode * p2 = *it2; + for (enode * p2 : r2->get_parents()) { if (!is_relevant(p2)) continue; if (p2->is_eq()) @@ -1519,10 +1495,7 @@ namespace smt { } TRACE("push_new_th_diseqs", tout << "#" << r->get_owner_id() << " v" << v << "\n";); theory_id th_id = th->get_id(); - enode_vector::iterator it = r->begin_parents(); - enode_vector::iterator end = r->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r->get_parents()) { CTRACE("parent_bug", parent == 0, tout << "#" << r->get_owner_id() << ", num_parents: " << r->get_num_parents() << "\n"; display(tout);); if (parent->is_eq()) { bool_var bv = get_bool_var_of_id(parent->get_owner_id()); @@ -2197,9 +2170,7 @@ namespace smt { TRACE("cached_generation", tout << "caching: #" << n->get_id() << " " << e->get_generation() << "\n";); m_cached_generation.insert(n, e->get_generation()); } - unsigned num_args = to_app(n)->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(n)->get_arg(i); + for (expr * arg : *to_app(n)) { if (is_app(arg) || is_quantifier(arg)) todo.push_back(arg); } @@ -4228,10 +4199,7 @@ namespace smt { theory_var_list * l = n->get_th_var_list(); theory_id th_id = l->get_th_id(); - enode_vector::const_iterator it = n->begin_parents(); - enode_vector::const_iterator end = n->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode* parent : n->get_parents()) { family_id fid = parent->get_owner()->get_family_id(); if (fid != th_id && fid != m_manager.get_basic_family_id()) { TRACE("is_shared", tout << mk_pp(n->get_owner(), m_manager) << "\nis shared because of:\n" << mk_pp(parent->get_owner(), m_manager) << "\n";); diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index f4f56df5d..615cd2512 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -341,10 +341,7 @@ namespace smt { } void context::display_parent_eqs(std::ostream & out, enode * n) const { - enode_vector::iterator it = n->begin_parents(); - enode_vector::iterator end = n->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode* parent : n->get_parents()) { if (parent->is_eq()) display_eq_detail(out, parent); } diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index df6309424..6c8d156b4 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -216,15 +216,28 @@ namespace smt { return m_args; } - class args { + class const_args { enode const& n; public: - args(enode const& n):n(n) {} - args(enode const* n):n(*n) {} - enode_vector::const_iterator begin() const { return n.get_args(); } - enode_vector::const_iterator end() const { return n.get_args() + n.get_num_args(); } + const_args(enode const& n):n(n) {} + const_args(enode const* n):n(*n) {} + enode_vector::const_iterator begin() const { return n.m_args; } + enode_vector::const_iterator end() const { return n.m_args + n.get_num_args(); } }; + class args { + enode & n; + public: + args(enode & n):n(n) {} + args(enode * n):n(*n) {} + enode_vector::iterator begin() const { return n.m_args; } + enode_vector::iterator end() const { return n.m_args + n.get_num_args(); } + }; + + const_args get_const_args() const { return const_args(this); } + + // args get_args() { return args(this); } + // unsigned get_id() const { // return m_id; // } @@ -294,15 +307,27 @@ namespace smt { return m_commutative; } - class parents { + class const_parents { enode const& n; public: - parents(enode const& _n):n(_n) {} - parents(enode const* _n):n(*_n) {} + const_parents(enode const& _n):n(_n) {} + const_parents(enode const* _n):n(*_n) {} enode_vector::const_iterator begin() const { return n.begin_parents(); } enode_vector::const_iterator end() const { return n.end_parents(); } }; + class parents { + enode& n; + public: + parents(enode & _n):n(_n) {} + parents(enode * _n):n(*_n) {} + enode_vector::iterator begin() const { return n.begin_parents(); } + enode_vector::iterator end() const { return n.end_parents(); } + }; + + parents get_parents() { return parents(this); } + + const_parents get_const_parents() const { return const_parents(this); } unsigned get_num_parents() const { return m_parents.size(); From 78b9f0686a8fa8c03e7a9d6f17794fdb73d05ce2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 07:43:29 -0700 Subject: [PATCH 0819/1283] merge Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- src/api/api_model.cpp | 30 +------------- src/api/c++/z3++.h | 63 +---------------------------- src/ast/ast_smt2_pp.cpp | 6 --- src/ast/rewriter/pb2bv_rewriter.cpp | 2 +- src/util/gparams.cpp | 2 +- 7 files changed, 6 insertions(+), 101 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4732ef67..b109eb50b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ endif() # Project version ################################################################################ set(Z3_VERSION_MAJOR 4) -set(Z3_VERSION_MINOR 7) +set(Z3_VERSION_MINOR 8) set(Z3_VERSION_PATCH 0) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 3a2f30938..0590a8693 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 7, 0, 0) + set_version(4, 8, 0, 0) add_lib('util', []) add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index d1231c615..6318283c6 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -421,35 +421,7 @@ extern "C" { expr * r = to_func_entry(e)->m_func_entry->get_arg(i); RETURN_Z3(of_expr(r)); Z3_CATCH_RETURN(nullptr); - } - - // ---------------------------- - // - // DEPRECATED API - // - // ---------------------------- - -#if 0 - void Z3_API Z3_del_model(Z3_context c, Z3_model m) { - Z3_model_dec_ref(c, m); - } - unsigned Z3_API Z3_get_model_num_constants(Z3_context c, Z3_model m) { - return Z3_model_get_num_consts(c, m); - } - - Z3_func_decl Z3_API Z3_get_model_constant(Z3_context c, Z3_model m, unsigned i) { - return Z3_model_get_const_decl(c, m, i); - } - - unsigned Z3_API Z3_get_model_num_funcs(Z3_context c, Z3_model m) { - return Z3_model_get_num_funcs(c, m); - } - - Z3_func_decl Z3_API Z3_get_model_func_decl(Z3_context c, Z3_model m, unsigned i) { - return Z3_model_get_func_decl(c, m, i); - } -#endif - + } unsigned get_model_func_num_entries_core(Z3_context c, Z3_model m, unsigned i) { RESET_ERROR_CODE(); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index c17d71518..b4dab6926 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1555,12 +1555,6 @@ namespace z3 { m_vector = s.m_vector; return *this; } -<<<<<<< HEAD - bool contains(T const& x) const { - for (auto y : *this) if (eq(x, y)) return true; - return false; - } -======= /* Disabled pending C++98 build upgrade bool contains(T const& x) const { @@ -1568,7 +1562,6 @@ namespace z3 { return false; } */ ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 class iterator { ast_vector_tpl const* m_vector; @@ -1990,14 +1983,9 @@ namespace z3 { } // fails for some compilers: // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } -<<<<<<< HEAD - void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); check_error(); } - void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); check_error(); } -======= void from_file(char const* file) { Z3_solver_from_file(ctx(), m_solver, file); ctx().check_parser_error(); } void from_string(char const* s) { Z3_solver_from_string(ctx(), m_solver, s); ctx().check_parser_error(); } ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 check_result check() { Z3_lbool r = Z3_solver_check(ctx(), m_solver); check_error(); return to_check_result(r); } check_result check(unsigned n, expr * const assumptions) { array _assumptions(n); @@ -2169,10 +2157,6 @@ namespace z3 { return *this; } void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } -<<<<<<< HEAD -======= - // fails for some compilers: ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 // void add(expr_vector const& v) { check_context(*this, v); for (expr e : v) add(e); } unsigned size() const { return Z3_goal_size(ctx(), m_goal); } expr operator[](int i) const { assert(0 <= i); Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } @@ -2232,28 +2216,6 @@ namespace z3 { } unsigned size() const { return Z3_apply_result_get_num_subgoals(ctx(), m_apply_result); } goal operator[](int i) const { assert(0 <= i); Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); } -<<<<<<< HEAD -======= - model convert_model(model const & m, unsigned i = 0) const { - check_context(*this, m); - Z3_model new_m = Z3_apply_result_convert_model(ctx(), m_apply_result, i, m); - check_error(); - return model(ctx(), new_m); - } - expr as_expr() const { - unsigned n = size(); - if (n == 0) - return ctx().bool_val(true); - else if (n == 1) - return operator[](0).as_expr(); - else { - array args(n); - for (unsigned i = 0; i < n; i++) - args[i] = operator[](i).as_expr(); - return expr(ctx(), Z3_mk_or(ctx(), n, args.ptr())); - } - } ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 friend std::ostream & operator<<(std::ostream & out, apply_result const & r); }; inline std::ostream & operator<<(std::ostream & out, apply_result const & r) { out << Z3_apply_result_to_string(r.ctx(), r); return out; } @@ -2999,7 +2961,6 @@ namespace z3 { return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a)); } -<<<<<<< HEAD inline expr_vector context::parse_string(char const* s) { Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); check_error(); @@ -3010,17 +2971,6 @@ namespace z3 { Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); check_error(); return expr_vector(*this, r); -======= - inline expr context::parse_string(char const* s) { - Z3_ast r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); - check_parser_error(); - return expr(*this, r); - } - inline expr context::parse_file(char const* s) { - Z3_ast r = Z3_parse_smtlib2_file(*this, s, 0, 0, 0, 0, 0, 0); - check_parser_error(); - return expr(*this, r); ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 } inline expr_vector context::parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls) { @@ -3034,15 +2984,10 @@ namespace z3 { for (unsigned i = 0; i < decls.size(); ++i) { decl_names[i] = decls[i].name(); } -<<<<<<< HEAD + Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); check_error(); return expr_vector(*this, r); -======= - Z3_ast r = Z3_parse_smtlib2_string(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); - check_parser_error(); - return expr(*this, r); ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 } inline expr_vector context::parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls) { @@ -3056,15 +3001,9 @@ namespace z3 { for (unsigned i = 0; i < decls.size(); ++i) { decl_names[i] = decls[i].name(); } -<<<<<<< HEAD Z3_ast_vector r = Z3_parse_smtlib2_file(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); check_error(); return expr_vector(*this, r); -======= - Z3_ast r = Z3_parse_smtlib2_file(*this, s, sorts.size(), sort_names.ptr(), sorts1.ptr(), decls.size(), decl_names.ptr(), decls1.ptr()); - check_parser_error(); - return expr(*this, r); ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 } diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 5906281df..4f9a72174 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -33,11 +33,6 @@ using namespace format_ns; format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len, bool is_skolem) const { ast_manager & m = get_manager(); -#if 0 - symbol s1 = m_renaming.get_symbol(s, is_skolem); - len = static_cast(strlen(s1.bare_str())); - return mk_string(m, s1.bare_str()); -#else if (is_smt2_quoted_symbol(s)) { std::string str = mk_smt2_quoted_symbol(s); len = static_cast(str.length()); @@ -56,7 +51,6 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len, bo len = static_cast(strlen(s.bare_str())); return mk_string(m, s.bare_str()); } -#endif } format * smt2_pp_environment::pp_fdecl_name(func_decl * f, unsigned & len) const { diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 4e1024202..47a8a044a 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -5,7 +5,7 @@ Module Name: pb2bv_rewriter.cpp -Abstralct: +Abstract: Conversion from pseudo-booleans to bit-vectors. diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index cf8ed5087..5ee49ef16 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -429,7 +429,7 @@ public: #pragma omp critical (gparams) { if (m_module_params.find(module_name, ps)) { - result = *ps; + result.copy(*ps); } } return result; From 812c913cdd01bdb8cfd44284b808012cb7e9f72c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 08:34:28 -0700 Subject: [PATCH 0820/1283] use C99 pragma Signed-off-by: Nikolaj Bjorner --- src/util/util.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/util/util.h b/src/util/util.h index e087f552c..a9f28e133 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -191,16 +191,22 @@ bool is_threaded(); } \ } } ((void) 0) +#ifdef _MSC_VER +#define DO_PRAGMA(x) __pragma(x) +#else +#define DO_PRAGMA(x) _Pragma(x) +#endif + #ifdef _NO_OMP_ #define LOCK_CODE(CODE) CODE; #else #define LOCK_CODE(CODE) \ { \ - __pragma(omp critical (verbose_lock)) \ + DO_PRAGMA(omp critical (verbose_lock)) \ { \ CODE; \ } \ - } + } #endif template From 42c9394c6d06b49a24917e6bf2b77d62b5bbf677 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 08:49:48 -0700 Subject: [PATCH 0821/1283] pragma Signed-off-by: Nikolaj Bjorner --- src/util/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/util.h b/src/util/util.h index a9f28e133..bebf17f28 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -194,7 +194,7 @@ bool is_threaded(); #ifdef _MSC_VER #define DO_PRAGMA(x) __pragma(x) #else -#define DO_PRAGMA(x) _Pragma(x) +#define DO_PRAGMA(x) _Pragma((x)) #endif #ifdef _NO_OMP_ From 5ba814b14f420524f641b373f381b5dc0d349b61 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 08:54:05 -0700 Subject: [PATCH 0822/1283] try string in pragma Signed-off-by: Nikolaj Bjorner --- src/util/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/util.h b/src/util/util.h index bebf17f28..6e7ee5ce5 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -194,7 +194,7 @@ bool is_threaded(); #ifdef _MSC_VER #define DO_PRAGMA(x) __pragma(x) #else -#define DO_PRAGMA(x) _Pragma((x)) +#define DO_PRAGMA(x) _Pragma(#x) #endif #ifdef _NO_OMP_ From a91d7a71894dab192005634f4df5b0bb194bdf56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 09:05:20 -0700 Subject: [PATCH 0823/1283] fix build errors Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 4 ++-- src/sat/sat_allocator.h | 4 ++-- src/sat/sat_lookahead.h | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 90f737109..d94b02c8d 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1035,10 +1035,10 @@ namespace sat { } if (coeff0 > 0 && inc < 0) { - inc_bound(std::max(0LL, coeff1) - coeff0); + inc_bound(std::max((int64_t)0, coeff1) - coeff0); } else if (coeff0 < 0 && inc > 0) { - inc_bound(coeff0 - std::min(0LL, coeff1)); + inc_bound(coeff0 - std::min((int64_t)0, coeff1)); } int64_t lbound = static_cast(m_bound); diff --git a/src/sat/sat_allocator.h b/src/sat/sat_allocator.h index 1cbef04e0..b4e9f82e6 100644 --- a/src/sat/sat_allocator.h +++ b/src/sat/sat_allocator.h @@ -32,11 +32,11 @@ class sat_allocator { char m_data[CHUNK_SIZE]; chunk():m_curr(m_data) {} }; + char const * m_id; + size_t m_alloc_size; ptr_vector m_chunks; void * m_chunk_ptr; ptr_vector m_free[NUM_FREE]; - size_t m_alloc_size; - char const * m_id; unsigned align_size(size_t sz) const { return free_slot_id(sz) << PTR_ALIGNMENT; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index d03ceb64a..78cd32082 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -33,7 +33,6 @@ namespace sat { }; inline std::ostream& operator<<(std::ostream& out, pp_prefix const& p) { - uint64_t q = p.m_prefix; unsigned d = std::min(63u, p.m_depth); for (unsigned i = 0; i <= d; ++i) { if (0 != (p.m_prefix & (1ull << i))) out << "1"; else out << "0"; From bfac44f7ed6076307847c56ae10ccf5d6cb4d6ce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 09:15:53 -0700 Subject: [PATCH 0824/1283] fix build errors Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 8 ++------ src/sat/ba_solver.h | 6 ++++-- src/sat/sat_lookahead.h | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index d94b02c8d..4fbf7570d 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1125,8 +1125,6 @@ namespace sat { unsigned offset = 1; DEBUG_CODE(active2pb(m_A);); - unsigned init_marks = m_num_marks; - do { if (m_overflow || offset > (1 << 12)) { @@ -1361,10 +1359,9 @@ namespace sat { int64_t coeff = get_coeff(v); lbool val = value(v); bool is_true = val == l_true; - bool append = coeff != 0 && val != l_undef && (coeff < 0 == is_true); + bool append = coeff != 0 && val != l_undef && ((coeff < 0) == is_true); if (append) { literal lit(v, !is_true); - unsigned acoeff = get_abs_coeff(v); if (lvl(lit) == m_conflict_lvl) { if (m_lemma[0] == null_literal) { asserting_coeff = std::abs(coeff); @@ -1699,7 +1696,6 @@ namespace sat { double ba_solver::get_reward(literal l, ext_justification_idx idx, literal_occs_fun& occs) const { constraint const& c = index2constraint(idx); - unsigned sz = c.size(); switch (c.tag()) { case card_t: return get_reward(c.to_card(), occs); case pb_t: return get_reward(c.to_pb(), occs); @@ -2264,7 +2260,7 @@ namespace sat { bool ba_solver::validate_watch(pb const& p, literal alit) const { for (unsigned i = 0; i < p.size(); ++i) { literal l = p[i].second; - if (l != alit && lvl(l) != 0 && is_watched(l, p) != i < p.num_watch()) { + if (l != alit && lvl(l) != 0 && is_watched(l, p) != (i < p.num_watch())) { IF_VERBOSE(0, display(verbose_stream(), p, true); verbose_stream() << "literal " << l << " at position " << i << " " << is_watched(l, p) << "\n";); UNREACHABLE(); diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index c565c362e..303329594 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -243,11 +243,13 @@ namespace sat { struct ba_sort { ba_solver& s; + typedef typename sat::literal literal; + typedef typename sat::literal_vector literal_vector; + literal m_true; literal_vector m_lits; + - typedef sat::literal literal; - typedef sat::literal_vector literal_vector; ba_sort(ba_solver& s): s(s), m_true(null_literal) {} literal mk_false(); literal mk_true(); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 78cd32082..df954bdf1 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -90,7 +90,7 @@ namespace sat { double m_cube_psat_trigger; config() { - memset(this, sizeof(*this), 0); + memset(this, 0, sizeof(*this)); m_dl_success = 0.8; m_alpha = 3.5; m_max_score = 20.0; From e4d24fd2c35e2310318a4234a6b0c6bd2e51841c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 09:39:19 -0700 Subject: [PATCH 0825/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/CMakeLists.txt | 6 +++--- src/sat/ba_solver.h | 2 +- src/sat/sat_allocator.h | 2 ++ src/sat/sat_solver.cpp | 7 ++----- src/sat/tactic/CMakeLists.txt | 1 + src/tactic/core/split_clause_tactic.cpp | 3 +-- src/tactic/generic_model_converter.cpp | 2 -- src/tactic/sine_filter.cpp | 8 ++++---- src/tactic/tactical.cpp | 2 -- src/util/util.cpp | 7 +++++++ 10 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ed95b827..d8a773747 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -56,12 +56,12 @@ add_subdirectory(parsers/util) add_subdirectory(math/grobner) add_subdirectory(math/euclid) add_subdirectory(tactic/core) -add_subdirectory(sat/tactic) -add_subdirectory(tactic/arith) -add_subdirectory(nlsat/tactic) add_subdirectory(math/subpaving/tactic) add_subdirectory(tactic/aig) add_subdirectory(solver) +add_subdirectory(sat/tactic) +add_subdirectory(tactic/arith) +add_subdirectory(nlsat/tactic) add_subdirectory(ackermannization) add_subdirectory(interp) add_subdirectory(cmd_context) diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 303329594..14482eabb 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -242,10 +242,10 @@ namespace sat { unsigned_vector m_pb_undef; struct ba_sort { - ba_solver& s; typedef typename sat::literal literal; typedef typename sat::literal_vector literal_vector; + ba_solver& s; literal m_true; literal_vector m_lits; diff --git a/src/sat/sat_allocator.h b/src/sat/sat_allocator.h index b4e9f82e6..06585ebed 100644 --- a/src/sat/sat_allocator.h +++ b/src/sat/sat_allocator.h @@ -90,6 +90,8 @@ public: } } size_t get_allocation_size() const { return m_alloc_size; } + + char const* id() const { return m_id; } }; inline void * operator new(size_t s, sat_allocator & r) { return r.allocate(s); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 1f3995d49..5b6fb628a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -38,9 +38,9 @@ namespace sat { m_config(p), m_par(nullptr), m_cls_allocator_idx(false), - m_par_syncing_clauses(false), - m_par_id(0), m_cleaner(*this), + m_par_id(0), + m_par_syncing_clauses(false), m_simplifier(*this, p), m_scc(*this, p), m_asymm_branch(*this, p), @@ -487,8 +487,6 @@ namespace sat { return reinit; } - static unsigned s_count = 0; - void solver::attach_clause(clause & c, bool & reinit) { SASSERT(c.size() > 2); reinit = false; @@ -1332,7 +1330,6 @@ namespace sat { next = m_case_split_queue.min_var(); auto age = m_stats.m_conflict - m_canceled[next]; while (age > 0) { - double decay = pow(0.95, age); m_activity[next] = static_cast(m_activity[next] * pow(0.95, age)); m_case_split_queue.activity_changed_eh(next, false); m_canceled[next] = m_stats.m_conflict; diff --git a/src/sat/tactic/CMakeLists.txt b/src/sat/tactic/CMakeLists.txt index fed6a89c8..dbbfbe753 100644 --- a/src/sat/tactic/CMakeLists.txt +++ b/src/sat/tactic/CMakeLists.txt @@ -6,6 +6,7 @@ z3_add_component(sat_tactic COMPONENT_DEPENDENCIES sat tactic + solver TACTIC_HEADERS sat_tactic.h ) diff --git a/src/tactic/core/split_clause_tactic.cpp b/src/tactic/core/split_clause_tactic.cpp index e8b3bcff0..138bc91ec 100644 --- a/src/tactic/core/split_clause_tactic.cpp +++ b/src/tactic/core/split_clause_tactic.cpp @@ -46,11 +46,10 @@ class split_clause_tactic : public tactic { } class split_pc : public proof_converter { - ast_manager & m; app_ref m_clause; proof_ref m_clause_pr; public: - split_pc(ast_manager & m, app * cls, proof * pr):m(m), m_clause(cls, m), m_clause_pr(pr, m) { + split_pc(ast_manager & m, app * cls, proof * pr):m_clause(cls, m), m_clause_pr(pr, m) { } ~split_pc() override { } diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index ddc396597..9e2a7b9b2 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -188,8 +188,6 @@ void generic_model_converter::get_units(obj_map& units) { th_rewriter rw(m); expr_safe_replace rep(m); expr_ref tmp(m); - bool val = false; - expr* f = nullptr; for (auto const& kv : units) { rep.insert(kv.m_key, kv.m_value ? m.mk_true() : m.mk_false()); } diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index c5242e237..0ac726986 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -36,14 +36,14 @@ public: sine_tactic(ast_manager& m, params_ref const& p): m(m), m_params(p) {} - virtual tactic * translate(ast_manager & m) { + tactic * translate(ast_manager & m) override { return alloc(sine_tactic, m, m_params); } - virtual void updt_params(params_ref const & p) { + void updt_params(params_ref const & p) override { } - virtual void collect_param_descrs(param_descrs & r) { + void collect_param_descrs(param_descrs & r) override { } void operator()(goal_ref const & g, goal_ref_buffer& result) override { @@ -63,7 +63,7 @@ public: SASSERT(g->is_well_sorted()); } - virtual void cleanup() { + void cleanup() override { } private: diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index 0b54037da..bb04a2be7 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -103,7 +103,6 @@ public: void operator()(goal_ref const & in, goal_ref_buffer& result) override { - bool models_enabled = in->models_enabled(); bool proofs_enabled = in->proofs_enabled(); bool cores_enabled = in->unsat_core_enabled(); @@ -513,7 +512,6 @@ public: // enabling proofs is possible, but requires translating subgoals back. fail_if_proof_generation("par_and_then", in); - bool models_enabled = in->models_enabled(); bool proofs_enabled = in->proofs_enabled(); bool cores_enabled = in->unsat_core_enabled(); diff --git a/src/util/util.cpp b/src/util/util.cpp index 913191e87..59d6d752c 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -20,6 +20,7 @@ Revision History: #ifdef _WINDOWS #include #endif +#include #include "util/util.h" static unsigned g_verbosity_level = 0; @@ -38,7 +39,11 @@ void set_verbose_stream(std::ostream& str) { g_verbose_stream = &str; } +#ifdef _WINDOWS static int g_thread_id = 0; +#else +static std::thread::id g_thread_id = std::this_thread::get_id(); +#endif static bool g_is_threaded = false; bool is_threaded() { @@ -47,6 +52,8 @@ bool is_threaded() { int thid = GetCurrentThreadId(); g_is_threaded = g_thread_id != thid && g_thread_id != 0; g_thread_id = thid; +#else + g_is_threaded = std::this_thread::get_id() != g_thread_id; #endif return g_is_threaded; } From 3de2feb84af3a7af66dfc17c66302170285e931c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 09:46:54 -0700 Subject: [PATCH 0826/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/sat/sat_local_search.cpp | 8 +++----- src/sat/sat_lookahead.cpp | 7 +++---- src/sat/sat_model_converter.cpp | 3 +-- src/sat/sat_parallel.cpp | 2 +- src/sat/sat_solver.cpp | 2 +- 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index e02560e5f..af2447fc2 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -377,9 +377,9 @@ namespace sat { verify_unsat_stack(); } - local_search::local_search() : - m_par(0), - m_is_unsat(false) { + local_search::local_search() : + m_is_unsat(false), + m_par(nullptr) { } void local_search::import(solver& s, bool _init) { @@ -575,7 +575,6 @@ namespace sat { void local_search::gsat() { reinit(); - bool reach_known_best_value = false; bool_var flipvar; timer timer; timer.start(); @@ -925,7 +924,6 @@ namespace sat { // update all flipvar's neighbor's conf_change to true, add goodvar/okvar var_info& vi = m_vars[flipvar]; - unsigned sz = vi.m_neighbors.size(); for (auto v : vi.m_neighbors) { m_vars[v].m_conf_change = true; if (score(v) > 0 && !already_in_goodvar_stack(v)) { diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 122c628a0..3833e2a52 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -41,6 +41,7 @@ namespace sat { } lookahead::scoped_assumptions::~scoped_assumptions() { for (auto l : lits) { + (void)l; p.pop(); } } @@ -2070,7 +2071,7 @@ namespace sat { scoped_level _sl(*this, c_fixed_truth); m_search_mode = lookahead_mode::searching; unsigned depth = 0; - unsigned init_trail = m_trail.size(); + // unsigned init_trail = m_trail.size(); m_cube_state.reset_stats(); if (!is_first) { @@ -2184,8 +2185,6 @@ namespace sat { } std::ostream& lookahead::display_clauses(std::ostream& out) const { - bool first = true; - for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); unsigned sz = m_ternary_count[idx]; @@ -2268,7 +2267,7 @@ namespace sat { init(learned); if (inconsistent()) return; inc_istamp(); - literal l = choose(); + choose(); if (inconsistent()) return; SASSERT(m_trail_lim.empty()); unsigned num_units = 0; diff --git a/src/sat/sat_model_converter.cpp b/src/sat/sat_model_converter.cpp index 22cab35ea..d132f1cd4 100644 --- a/src/sat/sat_model_converter.cpp +++ b/src/sat/sat_model_converter.cpp @@ -290,7 +290,7 @@ namespace sat { for (literal l : it2->m_clauses) { CTRACE("sat_model_converter", l.var() == it->var(), tout << "var: " << it->var() << "\n"; display(tout);); SASSERT(l.var() != it->var()); - SASSERT(l == null_literal || l.var() < num_vars); + VERIFY(l == null_literal || l.var() < num_vars); if (it2->var() == it->var()) return false; } } @@ -391,7 +391,6 @@ namespace sat { sat::literal_vector clause; for (entry const& e : m_entries) { unsigned index = 0; - bool var_sign = false; clause.reset(); for (literal l : e.m_clauses) { if (l == null_literal) { diff --git a/src/sat/sat_parallel.cpp b/src/sat/sat_parallel.cpp index 8e50a1f91..c6e29f64c 100644 --- a/src/sat/sat_parallel.cpp +++ b/src/sat/sat_parallel.cpp @@ -91,7 +91,7 @@ namespace sat { return false; } - parallel::parallel(solver& s): m_scoped_rlimit(s.rlimit()), m_num_clauses(0), m_consumer_ready(false) {} + parallel::parallel(solver& s): m_num_clauses(0), m_consumer_ready(false), m_scoped_rlimit(s.rlimit()) {} parallel::~parallel() { for (unsigned i = 0; i < m_solvers.size(); ++i) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 5b6fb628a..825a1170a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -791,7 +791,7 @@ namespace sat { } if (m_config.m_propagate_prefetch) { - _mm_prefetch((const char*)(m_watches[l.index()].c_ptr()), 1); + _mm_prefetch((const char*)(m_watches[l.index()].c_ptr()), _MM_HINT_T1); } SASSERT(!l.sign() || m_phase[v] == NEG_PHASE); From 454d20d23e85fbe9535c6dd46ff650d783b95e59 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 10:06:54 -0700 Subject: [PATCH 0827/1283] fix build errors Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 1 - src/sat/sat_big.cpp | 1 - src/sat/sat_big.h | 1 - src/sat/sat_scc.cpp | 1 - src/solver/parallel_tactic.cpp | 9 +++++++-- src/tactic/arith/eq2bv_tactic.cpp | 4 ++-- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 4f9a72174..a2958e3c9 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1146,7 +1146,6 @@ public: void operator()(func_decl * f, expr * e, format_ref & r, char const* cmd) { - unsigned arity = f->get_arity(); unsigned len; format * fname = m_env.pp_fdecl_name(f, len); register_var_names(f->get_arity()); diff --git a/src/sat/sat_big.cpp b/src/sat/sat_big.cpp index 27b87d4c9..35898a110 100644 --- a/src/sat/sat_big.cpp +++ b/src/sat/sat_big.cpp @@ -177,7 +177,6 @@ namespace sat { } unsigned big::reduce_tr(solver& s) { - unsigned num_lits = s.num_vars() * 2; unsigned idx = 0; unsigned elim = 0; m_del_bin.reset(); diff --git a/src/sat/sat_big.h b/src/sat/sat_big.h index f2adf9ad8..898ddd1e8 100644 --- a/src/sat/sat_big.h +++ b/src/sat/sat_big.h @@ -34,7 +34,6 @@ namespace sat { svector m_left, m_right; literal_vector m_root, m_parent; bool m_learned; - bool m_binary; // is the BIG produced from binary clauses or hyper-binary resolution? svector> m_del_bin; diff --git a/src/sat/sat_scc.cpp b/src/sat/sat_scc.cpp index 8a2029df2..e430bcb47 100644 --- a/src/sat/sat_scc.cpp +++ b/src/sat/sat_scc.cpp @@ -237,7 +237,6 @@ namespace sat { } unsigned scc::reduce_tr(bool learned) { - unsigned num_lits = m_solver.num_vars() * 2; init_big(learned); unsigned num_elim = m_big.reduce_tr(m_solver); m_num_elim_bin += num_elim; diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index ac147672e..61e97e040 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -162,11 +162,16 @@ class parallel_tactic : public tactic { expr_ref_vector m_vars; expr_ref_vector m_cube; public: - cube_var(expr_ref_vector& c, expr_ref_vector& vs): + cube_var(expr_ref_vector const& c, expr_ref_vector const& vs): m_vars(vs), m_cube(c) {} + cube_var(cube_var const& other): + m_vars(other.m_vars), m_cube(other.m_cube) {} + cube_var operator()(ast_translation& tr) { - return cube_var(tr(m_cube), tr(m_vars)); + expr_ref_vector vars(tr(m_vars)); + expr_ref_vector cube(tr(m_cube)); + return cube_var(cube, vars); } expr_ref_vector const& cube() const { return m_cube; } diff --git a/src/tactic/arith/eq2bv_tactic.cpp b/src/tactic/arith/eq2bv_tactic.cpp index 57fd51271..616ba69c9 100644 --- a/src/tactic/arith/eq2bv_tactic.cpp +++ b/src/tactic/arith/eq2bv_tactic.cpp @@ -113,13 +113,13 @@ class eq2bv_tactic : public tactic { return v; } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { for (auto const& kv : m_map) { out << "(model-set " << kv.m_key->get_name() << " " << kv.m_value->get_name() << ")\n"; } } - virtual void get_units(obj_map& units) { units.reset(); } + void get_units(obj_map& units) override { units.reset(); } }; From fa93bc419d31fde6bfc7f4a8b42b384de1ec22e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 10:53:36 -0700 Subject: [PATCH 0828/1283] fix build Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 24 ++++++++------ src/ackermannization/ackr_model_converter.cpp | 2 +- .../lackr_model_converter_lazy.cpp | 2 +- src/muz/spacer/spacer_itp_solver.h | 4 +-- src/muz/transforms/dl_mk_karr_invariants.cpp | 4 ++- .../dl_mk_quantifier_abstraction.cpp | 4 +-- src/muz/transforms/dl_mk_scale.cpp | 2 +- src/sat/sat_solver.cpp | 6 ++-- src/smt/smt_solver.cpp | 2 +- src/smt/tactic/smt_tactic.cpp | 2 -- src/smt/theory_pb.cpp | 8 ++--- src/tactic/aig/aig.cpp | 2 +- .../portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 32 +++++++++---------- 14 files changed, 47 insertions(+), 49 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index e49b2991f..6761b3f8d 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -378,7 +378,7 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) { Z3_sort t; Z3_symbol f_name, t_name; - Z3_ast q; + Z3_ast_vector q; t = Z3_get_range(ctx, f); @@ -394,13 +394,14 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) /* Inside the parser, type t will be referenced using the symbol 'T'. */ t_name = Z3_mk_string_symbol(ctx, "T"); - q = Z3_parse_smtlib2_string(ctx, "(assert (forall ((x T) (y T)) (= (f x y) (f y x))))", 1, &t_name, &t, 1, &f_name, &f); - printf("assert axiom:\n%s\n", Z3_ast_to_string(ctx, q)); - Z3_solver_assert(ctx, s, q); + printf("assert axiom:\n%s\n", Z3_ast_vector_to_string(ctx, q)); + for (unsigned i = 0; i < Z3_ast_vector_size(ctx, q); ++i) { + Z3_solver_assert(ctx, s, Z3_ast_vector_get(ctx, q, i)); + } } /** @@ -1642,7 +1643,7 @@ void parser_example2() Z3_ast x, y; Z3_symbol names[2]; Z3_func_decl decls[2]; - Z3_ast f; + Z3_ast_vector f; printf("\nparser_example2\n"); LOG_MSG("parser_example2"); @@ -1665,8 +1666,11 @@ void parser_example2() 0, 0, 0, /* 'x' and 'y' declarations are inserted as 'a' and 'b' into the parser symbol table. */ 2, names, decls); - printf("formula: %s\n", Z3_ast_to_string(ctx, f)); - Z3_solver_assert(ctx, s, f); + printf("formula: %s\n", Z3_ast_vector_to_string(ctx, f)); + printf("assert axiom:\n%s\n", Z3_ast_vector_to_string(ctx, f)); + for (unsigned i = 0; i < Z3_ast_vector_size(ctx, f); ++i) { + Z3_solver_assert(ctx, s, Z3_ast_vector_get(ctx, f, i)); + } check(ctx, s, Z3_L_TRUE); del_solver(ctx, s); @@ -1685,7 +1689,7 @@ void parser_example3() Z3_symbol g_name; Z3_sort g_domain[2]; Z3_func_decl g; - Z3_ast thm; + Z3_ast_vector thm; printf("\nparser_example3\n"); LOG_MSG("parser_example3"); @@ -1710,8 +1714,8 @@ void parser_example3() "(assert (forall ((x Int) (y Int)) (=> (= x y) (= (g x 0) (g 0 y)))))", 0, 0, 0, 1, &g_name, &g); - printf("formula: %s\n", Z3_ast_to_string(ctx, thm)); - prove(ctx, s, thm, Z3_TRUE); + printf("formula: %s\n", Z3_ast_vector_to_string(ctx, thm)); + prove(ctx, s, Z3_ast_vector_get(ctx, thm, 0), Z3_TRUE); del_solver(ctx, s); Z3_del_context(ctx); diff --git a/src/ackermannization/ackr_model_converter.cpp b/src/ackermannization/ackr_model_converter.cpp index 8b43d5e71..9e87a1a69 100644 --- a/src/ackermannization/ackr_model_converter.cpp +++ b/src/ackermannization/ackr_model_converter.cpp @@ -61,7 +61,7 @@ public: } } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(ackr-model-converter)\n"; } diff --git a/src/ackermannization/lackr_model_converter_lazy.cpp b/src/ackermannization/lackr_model_converter_lazy.cpp index 5d0fff59f..a37373aab 100644 --- a/src/ackermannization/lackr_model_converter_lazy.cpp +++ b/src/ackermannization/lackr_model_converter_lazy.cpp @@ -46,7 +46,7 @@ public: NOT_IMPLEMENTED_YET(); } - virtual void display(std::ostream & out) { + void display(std::ostream & out) override { out << "(lackr-model-converter)\n"; } diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 99bf08871..466e0a2f1 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -110,9 +110,7 @@ public: void set_produce_models(bool f) override { m_solver.set_produce_models(f);} void assert_expr_core(expr *t) override { m_solver.assert_expr(t);} void assert_expr_core2(expr *t, expr *a) override { NOT_IMPLEMENTED_YET();} - virtual void assert_lemma(expr* e) { NOT_IMPLEMENTED_YET(); } - virtual expr_ref lookahead(const expr_ref_vector &,const expr_ref_vector &) { return expr_ref(m.mk_true(), m); } - virtual expr_ref_vector cube(expr_ref_vector&, unsigned) { return expr_ref_vector(m); } + expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void push() override; void pop(unsigned n) override; diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 68a13818c..fd14538c5 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -152,7 +152,9 @@ namespace datalog { return mc; } - virtual void display(std::ostream& out) { out << "(add-invariant-model-converter)\n"; } + void display(std::ostream& out) override { + out << "(add-invariant-model-converter)\n"; + } private: void mk_body(matrix const& M, expr_ref& body) { diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index 2d0cb9146..e9a4f2f54 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -53,9 +53,9 @@ namespace datalog { return alloc(qa_model_converter, m); } - virtual void display(std::ostream& out) { display_add(out, m); } + void display(std::ostream& out) override { display_add(out, m); } - virtual void get_units(obj_map& units) { units.reset(); } + void get_units(obj_map& units) override { units.reset(); } void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector const& bound) { m_old_funcs.push_back(old_p); diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index b73e7e55e..0144948bd 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -100,7 +100,7 @@ namespace datalog { return nullptr; } - virtual void display(std::ostream& out) { out << "(scale-model-converter)\n"; } + void display(std::ostream& out) override { out << "(scale-model-converter)\n"; } }; diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 825a1170a..673afeab0 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -39,8 +39,6 @@ namespace sat { m_par(nullptr), m_cls_allocator_idx(false), m_cleaner(*this), - m_par_id(0), - m_par_syncing_clauses(false), m_simplifier(*this, p), m_scc(*this, p), m_asymm_branch(*this, p), @@ -55,7 +53,9 @@ namespace sat { m_qhead(0), m_scope_lvl(0), m_search_lvl(0), - m_params(p) { + m_params(p), + m_par_id(0), + m_par_syncing_clauses(false) { init_reason_unknown(); updt_params(p); m_conflicts_since_gc = 0; diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index b493f9df3..378e56314 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -244,7 +244,7 @@ namespace smt { return m_context.get_formula(idx); } - virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned cutoff) { + expr_ref_vector cube(expr_ref_vector& vars, unsigned cutoff) override { ast_manager& m = get_manager(); if (!m_cuber) { m_cuber = alloc(cuber, *this); diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index 8d052ccf2..cc0f0f207 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -305,13 +305,11 @@ tactic * mk_smt_tactic_using(bool auto_config, params_ref const & _p) { tactic * mk_psmt_tactic(ast_manager& m, params_ref const& p, symbol const& logic) { parallel_params pp(p); - bool use_parallel = pp.enable(); return pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p); } tactic * mk_psmt_tactic_using(ast_manager& m, bool auto_config, params_ref const& _p, symbol const& logic) { parallel_params pp(_p); - bool use_parallel = pp.enable(); params_ref p = _p; p.set_bool("auto_config", auto_config); return using_params(pp.enable() ? mk_parallel_tactic(mk_smt_solver(m, p, logic), p) : mk_smt_tactic(p), p); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 40965ee82..e34a16eec 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -317,6 +317,7 @@ namespace smt { void theory_pb::card::set_conflict(theory_pb& th, literal l) { SASSERT(validate_conflict(th)); context& ctx = th.get_context(); + (void)ctx; literal_vector& lits = th.get_literals(); SASSERT(ctx.get_assignment(l) == l_false); SASSERT(ctx.get_assignment(lit()) == l_true); @@ -343,7 +344,7 @@ namespace smt { bool theory_pb::card::validate_assign(theory_pb& th, literal_vector const& lits, literal l) { context& ctx = th.get_context(); - SASSERT(ctx.get_assignment(l) == l_undef); + VERIFY(ctx.get_assignment(l) == l_undef); for (unsigned i = 0; i < lits.size(); ++i) { SASSERT(ctx.get_assignment(lits[i]) == l_true); } @@ -906,7 +907,6 @@ namespace smt { } std::ostream& theory_pb::display(std::ostream& out, card const& c, bool values) const { - ast_manager& m = get_manager(); context& ctx = get_context(); out << c.lit(); if (c.lit() != null_literal) { @@ -1494,12 +1494,10 @@ namespace smt { if (v == null_bool_var) continue; card* c = m_var_infos[v].m_card; if (c) { - unsigned np = c->num_propagations(); c->reset_propagations(); literal lit = c->lit(); if (c->is_aux() && ctx.get_assign_level(lit) > ctx.get_search_level()) { double activity = ctx.get_activity(v); - // std::cout << "activity: " << ctx.get_activity(v) << " " << np << "\n"; if (activity <= 0) { nz++; } @@ -2528,7 +2526,6 @@ namespace smt { normalize_active_coeffs(); for (unsigned i = 0; i < m_active_vars.size(); ++i) { bool_var v = m_active_vars[i]; - int coeff = get_coeff(v); literal lit(v, get_coeff(v) < 0); args.push_back(literal2expr(lit)); coeffs.push_back(rational(get_abs_coeff(v))); @@ -2541,7 +2538,6 @@ namespace smt { void theory_pb::display_resolved_lemma(std::ostream& out) const { context& ctx = get_context(); - literal_vector const& lits = ctx.assigned_literals(); bool_var v; unsigned lvl; out << "num marks: " << m_num_marks << "\n"; diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 1c23faba5..805a8321a 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -636,7 +636,7 @@ struct aig_manager::imp { bool check_cache() const { for (auto const& kv : m_cache) { - SASSERT(ref_count(kv.m_value) > 0); + VERIFY(ref_count(kv.m_value) > 0); } return true; } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index a659e5803..8767644f3 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -177,7 +177,7 @@ public: return mc; } - virtual model_converter_ref get_model_converter() const { + model_converter_ref get_model_converter() const override { model_converter_ref mc = external_model_converter(); mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 030453759..6b5fe9056 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -83,13 +83,13 @@ public: return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } - virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } - virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } - virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } - virtual void collect_statistics(statistics & st) const { m_solver->collect_statistics(st); } - virtual void get_unsat_core(ptr_vector & r) { m_solver->get_unsat_core(r); } - virtual void get_model_core(model_ref & mdl) { + void updt_params(params_ref const & p) override { solver::updt_params(p); m_solver->updt_params(p); } + void collect_param_descrs(param_descrs & r) override { m_solver->collect_param_descrs(r); } + void set_produce_models(bool f) override { m_solver->set_produce_models(f); } + void set_progress_callback(progress_callback * callback) override { m_solver->set_progress_callback(callback); } + void collect_statistics(statistics & st) const override { m_solver->collect_statistics(st); } + void get_unsat_core(ptr_vector & r) override { m_solver->get_unsat_core(r); } + void get_model_core(model_ref & mdl) override { m_solver->get_model(mdl); if (mdl) { model_converter_ref mc = local_model_converter(); @@ -113,24 +113,24 @@ public: return concat(mc0(), local_model_converter()); } - virtual model_converter_ref get_model_converter() const { + model_converter_ref get_model_converter() const override { model_converter_ref mc = external_model_converter(); mc = concat(mc.get(), m_solver->get_model_converter().get()); return mc; } - virtual proof * get_proof() { return m_solver->get_proof(); } - virtual std::string reason_unknown() const { return m_solver->reason_unknown(); } - virtual void set_reason_unknown(char const* msg) { m_solver->set_reason_unknown(msg); } - virtual void get_labels(svector & r) { m_solver->get_labels(r); } - virtual ast_manager& get_manager() const { return m; } - virtual lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) { + proof * get_proof() override { return m_solver->get_proof(); } + std::string reason_unknown() const override { return m_solver->reason_unknown(); } + void set_reason_unknown(char const* msg) override { m_solver->set_reason_unknown(msg); } + void get_labels(svector & r) override { m_solver->get_labels(r); } + ast_manager& get_manager() const override { return m; } + lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override { return m_solver->find_mutexes(vars, mutexes); } - virtual expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) { + expr_ref_vector cube(expr_ref_vector& vars, unsigned backtrack_level) override { return m_solver->cube(vars, backtrack_level); } - virtual lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { + lbool get_consequences_core(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override { datatype_util dt(m); bv_util bv(m); expr_ref_vector bvars(m), conseq(m), bounds(m); From ef6339f14ccd3e727b140cd2a39b1a72cf874e4a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 12:00:03 -0700 Subject: [PATCH 0829/1283] fix build issues Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 5 ++--- src/smt/theory_pb.cpp | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 772440b42..facbf6c0a 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -2203,9 +2203,8 @@ static void check_error(z3::context& ctx) { static void display_tptp(std::ostream& out) { // run SMT2 parser, pretty print TFA format. z3::context ctx; - Z3_ast _fml = Z3_parse_smtlib2_file(ctx, g_input_file, 0, 0, 0, 0, 0, 0); - check_error(ctx); - z3::expr fml(ctx, _fml); + z3::expr_vector fmls = ctx.parse_file(g_input_file); + z3::expr fml = z3::mk_and(fmls); pp_tptp pp(ctx); pp.collect_decls(fml); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index e34a16eec..4c2d8e8c6 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1830,8 +1830,9 @@ namespace smt { ast_manager& m = get_manager(); smt_params fp; kernel k(m, fp); + expr_ref notB(m.mk_not(B), m); k.assert_expr(A); - k.assert_expr(m.mk_not(B)); + k.assert_expr(notB); lbool is_sat = k.check(); validating = false; std::cout << is_sat << "\n"; From a07c6e479364099e9b09b1d68197b55f37d25930 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 15:02:04 -0700 Subject: [PATCH 0830/1283] resolve Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 14 +++----------- src/util/mpq.h | 7 +++++++ src/util/rational.h | 6 ++++++ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index fa8feb2fc..809e32644 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8251,14 +8251,10 @@ 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) -<<<<<<< HEAD - return AstVector(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) -======= try: - return _to_expr_ref(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) + 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) ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 def parse_smt2_file(f, sorts={}, decls={}, ctx=None): """Parse a file in SMT 2.0 format using the given sorts and decls. @@ -8268,14 +8264,10 @@ 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) -<<<<<<< HEAD - return AstVector(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) -======= - try: - return _to_expr_ref(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), 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) ->>>>>>> fc719a5ee82361ffedb9ef46793e3401fdc32cc5 def Interpolant(a,ctx=None): """Create an interpolation operator. diff --git a/src/util/mpq.h b/src/util/mpq.h index f1b261278..16b57237e 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -515,6 +515,13 @@ public: reset_denominator(c); } + void machine_idiv_rem(mpq const & a, mpq const & b, mpq & c, mpq & d) { + SASSERT(is_int(a) && is_int(b)); + machine_div_rem(a.m_num, b.m_num, c.m_num, d.m_num); + reset_denominator(c); + reset_denominator(d); + } + void machine_idiv(mpq const & a, mpq const & b, mpz & c) { SASSERT(is_int(a) && is_int(b)); machine_div(a.m_num, b.m_num, c); diff --git a/src/util/rational.h b/src/util/rational.h index dc7b79419..644ca4342 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -189,6 +189,12 @@ public: return r; } + friend inline rational machine_div_rem(rational const & r1, rational const & r2, rational & rem) { + rational r; + rational::m().machine_idiv(r1.m_val, r2.m_val, r.m_val, rem.m_val); + return r; + } + friend inline rational mod(rational const & r1, rational const & r2) { rational r; rational::m().mod(r1.m_val, r2.m_val, r.m_val); From c2bf8ef410c17cd67ee1505df0ba49ab542b497c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 15:03:15 -0700 Subject: [PATCH 0831/1283] resolve Signed-off-by: Nikolaj Bjorner --- src/util/rational.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/util/rational.h b/src/util/rational.h index 644ca4342..dc7b79419 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -189,12 +189,6 @@ public: return r; } - friend inline rational machine_div_rem(rational const & r1, rational const & r2, rational & rem) { - rational r; - rational::m().machine_idiv(r1.m_val, r2.m_val, r.m_val, rem.m_val); - return r; - } - friend inline rational mod(rational const & r1, rational const & r2) { rational r; rational::m().mod(r1.m_val, r2.m_val, r.m_val); From dd6e76478da61583dbaf2ce90428a2345ef13f5d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 08:51:33 -0700 Subject: [PATCH 0832/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/util/mpq.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/mpq.h b/src/util/mpq.h index 16b57237e..010bb2c8a 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -501,6 +501,8 @@ public: void machine_div(mpz const & a, mpz const & b, mpz & c) { mpz_manager::machine_div(a, b, c); } + void machine_div_rem(mpz const & a, mpz const & b, mpz & c, mpz& d) { mpz_manager::machine_div_rem(a, b, c, d); } + void div(mpz const & a, mpz const & b, mpz & c) { mpz_manager::div(a, b, c); } void rat_div(mpz const & a, mpz const & b, mpq & c) { From 6bff15e12efbadeb553dcc80bf1b5f5e3bd33536 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 10:38:46 -0700 Subject: [PATCH 0833/1283] fix #1609 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 8 ++++++++ src/smt/smt_solver.cpp | 11 +++++++---- src/solver/combined_solver.cpp | 4 +++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 36283356d..3eaf20763 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -9826,6 +9826,14 @@ def String(name, ctx=None): ctx = _get_ctx(ctx) return SeqRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), StringSort(ctx).ast), ctx) +def SubString(s, offset, length): + """Extract substring or subsequence starting at offset""" + return Extract(s, offset, length) + +def SubSeq(s, offset, length): + """Extract substring or subsequence starting at offset""" + return Extract(s, offset, length) + def Strings(names, ctx=None): """Return a tuple of String constants. """ ctx = _get_ctx(ctx) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index d813f249a..a5f9e0c34 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -61,10 +61,13 @@ namespace smt { smt_solver * result = alloc(smt_solver, m, p, m_logic); smt::kernel::copy(m_context, result->m_context); - for (auto & kv : m_name2assertion) - result->m_name2assertion.insert(translator(kv.m_key), - translator(kv.m_value)); - + for (auto & kv : m_name2assertion) { + expr* val = translator(kv.m_value); + expr* t = translator(kv.m_key); + result->m_name2assertion.insert(t, val); + result->solver_na2as::assert_expr(val, t); + m.inc_ref(val); + } return result; } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 9d2d8aa46..6469ab065 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -59,7 +59,8 @@ private: ref m_solver2; // We delay sending assertions to solver 2 // This is relevant for big benchmarks that are meant to be solved - // by a non-incremental solver. + // by a non-incremental solver. ); + bool m_solver2_initialized; bool m_ignore_solver1; @@ -137,6 +138,7 @@ public: } solver* translate(ast_manager& m, params_ref const& p) override { + TRACE("solver", tout << "translate\n";); solver* s1 = m_solver1->translate(m, p); solver* s2 = m_solver2->translate(m, p); combined_solver* r = alloc(combined_solver, s1, s2, p); From 1fc1249befedf49347cc606101af0021a2e0ff7c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 11:28:13 -0700 Subject: [PATCH 0834/1283] create empty model Signed-off-by: Nikolaj Bjorner --- src/tactic/tactic.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tactic/tactic.cpp b/src/tactic/tactic.cpp index a77864c7a..4fa9ca43f 100644 --- a/src/tactic/tactic.cpp +++ b/src/tactic/tactic.cpp @@ -176,10 +176,10 @@ lbool check_sat(tactic & t, goal_ref & g, model_ref & md, labels_vec & labels, p if (mc.get()) { (*mc)(labels); model_converter2model(m, mc.get(), md); - if (!md) { - // create empty model. - md = alloc(model, m); - } + } + if (!md) { + // create empty model. + md = alloc(model, m); } return l_true; } From 9e59bba80ee1a4b939592094e70c11d2130faec3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 13:20:51 -0700 Subject: [PATCH 0835/1283] fix dotnet example Signed-off-by: Nikolaj Bjorner --- examples/dotnet/Program.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index aec3bdcc5..1ed7b108a 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -175,7 +175,7 @@ namespace test_mapi string bench = string.Format("(assert (forall ((x {0}) (y {1})) (= ({2} x y) ({3} y x))))", t.Name, t.Name, f.Name, f.Name); - return ctx.ParseSMTLIB2String(bench, new Symbol[] { t.Name }, new Sort[] { t }, new Symbol[] { f.Name }, new FuncDecl[] { f }); + return ctx.ParseSMTLIB2String(bench, new Symbol[] { t.Name }, new Sort[] { t }, new Symbol[] { f.Name }, new FuncDecl[] { f })[0]; } /// @@ -322,7 +322,6 @@ namespace test_mapi Status q = s.Check(); Console.WriteLine("Solver says: " + q); Console.WriteLine("Model: \n" + s.Model); - Console.WriteLine("Converted Model: \n" + ar.ConvertModel(0, s.Model)); if (q != Status.SATISFIABLE) throw new TestFailedException(); } @@ -1383,7 +1382,9 @@ namespace test_mapi { Console.WriteLine("ParserExample1"); - var fml = ctx.ParseSMTLIB2String("(declare-const x Int) (declare-const y Int) (assert (> x y)) (assert (> x 0))"); + var fmls = ctx.ParseSMTLIB2String("(declare-const x Int) (declare-const y Int) (assert (> x y)) (assert (> x 0))"); + var fml = ctx.MkAnd(fmls); + Console.WriteLine("formula {0}", fml); Model m = Check(ctx, fml, Status.SATISFIABLE); @@ -1399,7 +1400,7 @@ namespace test_mapi FuncDecl a = ctx.MkConstDecl(declNames[0], ctx.MkIntSort()); FuncDecl b = ctx.MkConstDecl(declNames[1], ctx.MkIntSort()); FuncDecl[] decls = new FuncDecl[] { a, b }; - BoolExpr f = ctx.ParseSMTLIB2String("(assert (> a b))", null, null, declNames, decls); + BoolExpr f = ctx.ParseSMTLIB2String("(assert (> a b))", null, null, declNames, decls)[0]; Console.WriteLine("formula: {0}", f); Check(ctx, f, Status.SATISFIABLE); } @@ -1420,7 +1421,7 @@ namespace test_mapi BoolExpr thm = ctx.ParseSMTLIB2String("(assert (forall ((x Int) (y Int)) (=> (= x y) (= (gg x 0) (gg 0 y)))))", null, null, new Symbol[] { ctx.MkSymbol("gg") }, - new FuncDecl[] { g }); + new FuncDecl[] { g })[0]; Console.WriteLine("formula: {0}", thm); Prove(ctx, thm, false, ca); From 14d780fb2b3054e74bd853946df3961aaae30eac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 13:21:42 -0700 Subject: [PATCH 0836/1283] fix dotnet example Signed-off-by: Nikolaj Bjorner --- examples/dotnet/Program.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 1ed7b108a..0c2ce66c8 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -976,7 +976,8 @@ namespace test_mapi using (Context ctx = new Context(new Dictionary() { { "MODEL", "true" } })) { - Expr a = ctx.ParseSMTLIB2File(filename); + BoolExpr[] fmls = ctx.ParseSMTLIB2File(filename); + BoolExpr a = ctx.MkAnd(fmls); Console.WriteLine("SMT2 file read time: " + (System.DateTime.Now - before).TotalSeconds + " sec"); From bb041495e39f8e7ac384554962168c355c3c288a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 14:00:37 -0700 Subject: [PATCH 0837/1283] fix java Signed-off-by: Nikolaj Bjorner --- examples/java/JavaExample.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 7b8902768..90460de05 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -167,12 +167,12 @@ class JavaExample "function must be binary, and argument types must be equal to return type"); } - String bench = "(benchmark comm :formula (forall (x " + t.getName() + String bench = "(assert (forall (x " + t.getName() + ") (y " + t.getName() + ") (= (" + f.getName() + " x y) (" + f.getName() + " y x))))"; return ctx.parseSMTLIB2String(bench, new Symbol[] { t.getName() }, new Sort[] { t }, new Symbol[] { f.getName() }, - new FuncDecl[] { f }); + new FuncDecl[] { f })[0]; } // / "Hello world" example: create a Z3 logical context, and delete it. @@ -1041,7 +1041,7 @@ class JavaExample HashMap cfg = new HashMap(); cfg.put("model", "true"); Context ctx = new Context(cfg); - Expr a = ctx.parseSMTLIB2File(filename, null, null, null, null); + Expr a = ctx.MkAnd(ctx.parseSMTLIB2File(filename, null, null, null, null)); long t_diff = ((new Date()).getTime() - before.getTime()) / 1000; @@ -1445,7 +1445,7 @@ class JavaExample BoolExpr f = ctx.parseSMTLIB2String( "(declare-const x Int) (declare-const y Int) (assert (and (> x y) (> x 0)))", - null, null, null, null); + null, null, null, null)[0]; System.out.println("formula " + f); @SuppressWarnings("unused") @@ -1465,7 +1465,7 @@ class JavaExample FuncDecl[] decls = new FuncDecl[] { a, b }; BoolExpr f = ctx.parseSMTLIB2String("(assert (> a b))", null, null, - declNames, decls); + declNames, decls)[0]; System.out.println("formula: " + f); check(ctx, f, Status.SATISFIABLE); } @@ -1486,7 +1486,7 @@ class JavaExample BoolExpr thm = ctx.parseSMTLIB2String( "(assert (forall ((x Int) (y Int)) (=> (= x y) (= (gg x 0) (gg 0 y)))))", null, null, new Symbol[] { ctx.mkSymbol("gg") }, - new FuncDecl[] { g }); + new FuncDecl[] { g })[0]; System.out.println("formula: " + thm); prove(ctx, thm, false, ca); } @@ -1508,7 +1508,7 @@ class JavaExample * parenthesis */ "(declare-const x Int (declare-const y Int)) (assert (> x y))", - null, null, null, null); + null, null, null, null)[0]; } catch (Z3Exception e) { System.out.println("Z3 error: " + e); From c279fd9f2e7409842d25f0995cbfa381d1683548 Mon Sep 17 00:00:00 2001 From: Carsten Varming Date: Thu, 3 May 2018 03:06:58 +0000 Subject: [PATCH 0838/1283] Specify encoding of source files in mk_util.py --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 99de61703..3e40187c3 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -780,7 +780,7 @@ def extract_c_includes(fname): # We should generate and error for any occurrence of #include that does not match the previous pattern. non_std_inc_pat = re.compile(".*#include.*") - f = open(fname, 'r') + f = open(fname, encoding='utf-8', mode='r') linenum = 1 for line in f: m1 = std_inc_pat.match(line) From e98c808f47e767f498d7b9325a59cb46de3d020d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 03:18:29 -0700 Subject: [PATCH 0839/1283] fixing compilation errors Signed-off-by: Nikolaj Bjorner --- examples/dotnet/Program.cs | 5 +---- examples/java/JavaExample.java | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 0c2ce66c8..06cc66150 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -611,7 +611,6 @@ namespace test_mapi Expr f_x = ctx.MkApp(f, x); Expr f_y = ctx.MkApp(f, y); Expr g_y = ctx.MkApp(g, y); - Pattern[] pats = new Pattern[] { ctx.MkPattern(new Expr[] { f_x, g_y }) }; Expr[] no_pats = new Expr[] { f_y }; Expr[] bound = new Expr[2] { x, y }; Expr body = ctx.MkAnd(ctx.MkEq(f_x, f_y), ctx.MkEq(f_y, g_y)); @@ -628,7 +627,6 @@ namespace test_mapi Expr f_x = ctx.MkApp(f, x); Expr f_y = ctx.MkApp(f, y); Expr g_y = ctx.MkApp(g, y); - Pattern[] pats = new Pattern[] { ctx.MkPattern(new Expr[] { f_x, g_y }) }; Expr[] no_pats = new Expr[] { f_y }; Symbol[] names = new Symbol[] { ctx.MkSymbol("x"), ctx.MkSymbol("y") }; Sort[] sorts = new Sort[] { ctx.IntSort, ctx.IntSort }; @@ -729,7 +727,6 @@ namespace test_mapi { Console.WriteLine("BasicTests"); - Symbol qi = ctx.MkSymbol(1); Symbol fname = ctx.MkSymbol("f"); Symbol x = ctx.MkSymbol("x"); Symbol y = ctx.MkSymbol("y"); @@ -1319,7 +1316,7 @@ namespace test_mapi new Sort[] { int_type, int_type } // types of projection operators ); FuncDecl first = tuple.FieldDecls[0]; // declarations are for projections - FuncDecl second = tuple.FieldDecls[1]; + // FuncDecl second = tuple.FieldDecls[1]; Expr x = ctx.MkConst("x", int_type); Expr y = ctx.MkConst("y", int_type); Expr n1 = tuple.MkDecl[x, y]; diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 90460de05..d4d8bb1ac 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -1508,7 +1508,7 @@ class JavaExample * parenthesis */ "(declare-const x Int (declare-const y Int)) (assert (> x y))", - null, null, null, null)[0]; + null, null, null, null); } catch (Z3Exception e) { System.out.println("Z3 error: " + e); From 6e03c7a54216f9da0a5cdbfb29a3a131a2b1ae09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 03:23:54 -0700 Subject: [PATCH 0840/1283] fix #1607 by filtering exceptions when the context is canceled Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 4 +++- src/api/api_solver.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 2712eef6f..7b8866b59 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -139,7 +139,9 @@ extern "C" { r = to_optimize_ptr(o)->optimize(); } catch (z3_exception& ex) { - mk_c(c)->handle_exception(ex); + if (!mk_c(c)->m().canceled()) { + mk_c(c)->handle_exception(ex); + } r = l_undef; } // to_optimize_ref(d).cleanup(); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 1b2e9dcc3..88ce8b144 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -361,7 +361,9 @@ extern "C" { } catch (z3_exception & ex) { to_solver_ref(s)->set_reason_unknown(eh); - mk_c(c)->handle_exception(ex); + if (!mk_c(c)->m().canceled()) { + mk_c(c)->handle_exception(ex); + } return Z3_L_UNDEF; } } From 8ecff9e5ee3323db1ccfc831c03bba92c7db7a06 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 08:04:10 -0700 Subject: [PATCH 0841/1283] fix java Signed-off-by: Nikolaj Bjorner --- examples/java/JavaExample.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index d4d8bb1ac..d085b3b72 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -344,8 +344,6 @@ class JavaExample Status q = s.check(); System.out.println("Solver says: " + q); System.out.println("Model: \n" + s.getModel()); - System.out.println("Converted Model: \n" - + ar.convertModel(0, s.getModel())); if (q != Status.SATISFIABLE) throw new TestFailedException(); } @@ -1041,7 +1039,7 @@ class JavaExample HashMap cfg = new HashMap(); cfg.put("model", "true"); Context ctx = new Context(cfg); - Expr a = ctx.MkAnd(ctx.parseSMTLIB2File(filename, null, null, null, null)); + Expr a = ctx.mkAnd(ctx.parseSMTLIB2File(filename, null, null, null, null)); long t_diff = ((new Date()).getTime() - before.getTime()) / 1000; From 3736c0ae8bce989710ce0488868da169a5006a54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 08:52:25 -0700 Subject: [PATCH 0842/1283] touch Signed-off-by: Nikolaj Bjorner --- examples/java/JavaExample.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index d085b3b72..0ad9a8d10 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -1039,7 +1039,7 @@ class JavaExample HashMap cfg = new HashMap(); cfg.put("model", "true"); Context ctx = new Context(cfg); - Expr a = ctx.mkAnd(ctx.parseSMTLIB2File(filename, null, null, null, null)); + BoolExpr a = ctx.mkAnd(ctx.parseSMTLIB2File(filename, null, null, null, null)); long t_diff = ((new Date()).getTime() - before.getTime()) / 1000; From 96914d85780b401f66c16961f0369758d460236c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 11:46:26 -0700 Subject: [PATCH 0843/1283] update model conversion Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 5 +++-- src/sat/sat_solver/inc_sat_solver.cpp | 4 ++-- src/solver/tactic2solver.cpp | 4 +++- src/tactic/core/elim_uncnstr_tactic.cpp | 12 +++++------- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 237cd132f..e5f4bc133 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1527,6 +1527,7 @@ namespace opt { } void context::validate_model() { + return; if (!gparams::get_ref().get_bool("model_validate", false)) return; expr_ref_vector fmls(m); get_hard_constraints(fmls); @@ -1536,9 +1537,9 @@ namespace opt { for (expr * f : fmls) { if (!mdl->eval(f, tmp) || !m.is_true(tmp)) { //IF_VERBOSE(0, m_fm->display(verbose_stream() << "fm\n")); - //IF_VERBOSE(0, m_model_converter->display(verbose_stream() << "mc\n")); + IF_VERBOSE(0, m_model_converter->display(verbose_stream() << "mc\n")); IF_VERBOSE(0, verbose_stream() << "Failed to validate " << mk_pp(f, m) << "\n" << tmp << "\n"); - //IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *mdl, 0)); + IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *mdl, 0)); IF_VERBOSE(11, verbose_stream() << to_string_internal() << "\n"); exit(0); } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6107e5252..2e16bc33e 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -817,7 +817,7 @@ private: if (!gparams::get_ref().get_bool("model_validate", false)) return; - IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); + IF_VERBOSE(1, verbose_stream() << "Verifying solution\n";); model_evaluator eval(*mdl); eval.set_model_completion(false); bool all_true = true; @@ -842,7 +842,7 @@ private: IF_VERBOSE(0, for (auto const& kv : m_map) verbose_stream() << mk_pp(kv.m_key, m) << " |-> " << kv.m_value << "\n"); } else { - IF_VERBOSE(0, verbose_stream() << "solution verified\n"); + IF_VERBOSE(1, verbose_stream() << "solution verified\n"); // IF_VERBOSE(0, if (m_mcs.back()) m_mcs.back()->display(verbose_stream() << "mcs\n")); // IF_VERBOSE(0, if (m_sat_mc) m_sat_mc->display(verbose_stream() << "sat_mc\n")); // IF_VERBOSE(0, model_smt2_pp(verbose_stream() << "after\n", m, *mdl, 0);); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 8d7ab6a06..9118bb658 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -173,6 +173,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass break; } m_mc = g->mc(); + TRACE("tactic", if (m_mc) m_mc->display(tout);); } catch (z3_error & ex) { TRACE("tactic2solver", tout << "exception: " << ex.msg() << "\n";); @@ -225,8 +226,9 @@ void tactic2solver::get_unsat_core(ptr_vector & r) { } void tactic2solver::get_model_core(model_ref & m) { - if (m_result.get()) + if (m_result.get()) { m_result->get_model_core(m); + } } proof * tactic2solver::get_proof() { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 0f5e870f3..ce77f89d9 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -98,6 +98,7 @@ class elim_uncnstr_tactic : public tactic { TRACE("elim_uncnstr_bug", tout << "eliminating:\n" << mk_ismt2_pp(t, m()) << "\n";); TRACE("elim_uncnstr_bug_ll", tout << "eliminating:\n" << mk_bounded_pp(t, m()) << "\n";); m_fresh_vars.push_back(v); + if (m_mc) m_mc->hide(v); m_cache_domain.push_back(t); m_cache.insert(t, v); return true; @@ -856,15 +857,12 @@ class elim_uncnstr_tactic : public tactic { if (round == 0) { } else { - app_ref_vector & fresh_vars = m_rw->cfg().m_fresh_vars; - m_num_elim_apps = fresh_vars.size(); - if (m_mc.get()) { - for (app * f : fresh_vars) m_mc->hide(f); - g->add(m_mc.get()); - } + m_num_elim_apps = m_rw->cfg().m_fresh_vars.size(); + g->add(m_mc.get()); } + TRACE("elim_uncnstr", if (m_mc) m_mc->display(tout); else tout << "no mc\n";); m_mc = nullptr; - m_rw = nullptr; + m_rw = nullptr; result.push_back(g.get()); g->inc_depth(); return; From 888699548d4dea5b6729aa2b91a63ebb551df12d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 11:59:49 -0700 Subject: [PATCH 0844/1283] Revert "Specify encoding of source files in mk_util.py" --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 3e40187c3..99de61703 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -780,7 +780,7 @@ def extract_c_includes(fname): # We should generate and error for any occurrence of #include that does not match the previous pattern. non_std_inc_pat = re.compile(".*#include.*") - f = open(fname, encoding='utf-8', mode='r') + f = open(fname, 'r') linenum = 1 for line in f: m1 = std_inc_pat.match(line) From 43403fafcd33ade94f66d13f1eb93a3b0ffe6b80 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 13:23:59 -0700 Subject: [PATCH 0845/1283] adding ema Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 6 ++++- src/sat/sat_solver.h | 1 + src/test/sat_local_search.cpp | 4 ++-- src/util/ema.h | 44 +++++++++++++++++++++++++++++++++++ src/util/sorting_network.h | 3 +++ 5 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/util/ema.h diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 673afeab0..d69a9cb4a 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1415,7 +1415,7 @@ namespace sat { return l_false; if (m_conflicts_since_init > m_config.m_max_conflicts) return l_undef; - if (m_conflicts_since_restart > m_restart_threshold) + if (should_restart()) return l_undef; if (at_base_lvl()) { cleanup(); // cleaner may propagate frozen clauses @@ -1828,6 +1828,10 @@ namespace sat { return ok; } + bool solver::should_restart() const { + return m_conflicts_since_restart > m_restart_threshold; + } + void solver::restart(bool to_base) { m_stats.m_restart++; m_restarts++; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index a3d6ea527..634bf2788 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -416,6 +416,7 @@ namespace sat { void mk_model(); bool check_model(model const & m) const; void restart(bool to_base); + bool should_restart() const; void sort_watch_lits(); void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 3e137c0b7..25fa59c95 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -17,12 +17,11 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea return false; } infile.getline(line, 16383); - int num_vars, num_constraints; #ifdef _WINDOWS + int num_vars = 0, num_constraints = 0; sscanf_s(line, "%d %d", &num_vars, &num_constraints); #else return false; -#endif //std::cout << "number of variables: " << num_vars << '\n'; //std::cout << "number of constraints: " << num_constraints << '\n'; @@ -70,6 +69,7 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea infile.close(); return true; +#endif } void tst_sat_local_search(char ** argv, int argc, int& i) { diff --git a/src/util/ema.h b/src/util/ema.h new file mode 100644 index 000000000..9d5e33a34 --- /dev/null +++ b/src/util/ema.h @@ -0,0 +1,44 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + ema.h + +Abstract: + + Exponential moving average in the style of CaDiCal. + +Author: + + Nikolaj Bjorner (nbjorner) 2018-05-03 + +Revision History: + +--*/ +#ifndef EMA_H_ +#define EMA_H_ + +class ema { + double m_alpha, m_beta, m_value; + unsigned m_period, m_wait; + + public: + ema() { memset(this, 0, sizeof(*this)); } + + ema(double alpha): + m_alpha(alpha), m_beta(1), m_value(0), + m_period(0), m_wait(0) {} + + double operator() const { return m_value; } + + void update(double x) { + m_value += m_beta * (x - m_value); + if (m_beta <= m_alpha || m_wait--) return; + m_wait = m_period = 2*(m_period + 1) - 1; + m_beta *= 0.5; + if (m_beta < m_alpha) m_beta = m_alpha; + } +}; + +#endif diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index ab0d69791..38c595125 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -371,6 +371,9 @@ Notes: break; case ordered_at_most_1: return mk_ordered_exactly_1(full, n, xs); + default: + UNREACHABLE(); + return mk_ordered_exactly_1(full, n, xs); } if (full) { From 13b54f379cee69b9d1d8254ebe4ca186aad1996c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 5 May 2018 13:58:47 +0200 Subject: [PATCH 0846/1283] fix ema Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.h | 2 +- src/sat/sat_config.cpp | 7 ++++ src/sat/sat_config.h | 7 +++- src/sat/sat_params.pyg | 11 +++--- src/sat/sat_solver.cpp | 80 ++++++++++++++++++++++++++++-------------- src/sat/sat_solver.h | 6 ++++ src/smt/theory_pb.cpp | 15 +++----- src/util/ema.h | 22 +++++++++--- 8 files changed, 103 insertions(+), 47 deletions(-) diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index 4eeb5dc4a..f95696b3d 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -136,7 +136,7 @@ namespace sat { \brief Simple clause allocator that allows uint (32bit integers) to be used to reference clauses (even in 64bit machines). */ class clause_allocator { - small_object_allocator m_allocator; + sat_allocator m_allocator; id_gen m_id_gen; public: clause_allocator(); diff --git a/src/sat/sat_config.cpp b/src/sat/sat_config.cpp index 2bf20100b..c7f2377c9 100644 --- a/src/sat/sat_config.cpp +++ b/src/sat/sat_config.cpp @@ -38,9 +38,16 @@ namespace sat { m_restart = RS_LUBY; else if (s == symbol("geometric")) m_restart = RS_GEOMETRIC; + else if (s == symbol("ema")) + m_restart = RS_EMA; + else if (s == symbol("static")) + m_restart = RS_STATIC; else throw sat_param_exception("invalid restart strategy"); + m_fast_glue_avg = p.restart_emafastglue(); + m_slow_glue_avg = p.restart_emaslowglue(); + m_restart_margin = p.restart_margin(); m_restart_fast = p.restart_fast(); s = p.phase(); if (s == symbol("always_false")) diff --git a/src/sat/sat_config.h b/src/sat/sat_config.h index 9153f8b14..37efe69ed 100644 --- a/src/sat/sat_config.h +++ b/src/sat/sat_config.h @@ -33,7 +33,9 @@ namespace sat { enum restart_strategy { RS_GEOMETRIC, - RS_LUBY + RS_LUBY, + RS_EMA, + RS_STATIC }; enum gc_strategy { @@ -90,7 +92,10 @@ namespace sat { bool m_restart_fast; unsigned m_restart_initial; double m_restart_factor; // for geometric case + double m_restart_margin; // for ema unsigned m_restart_max; + double m_fast_glue_avg; + double m_slow_glue_avg; unsigned m_inprocess_max; double m_random_freq; unsigned m_random_seed; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 324882894..ce40949da 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -7,11 +7,14 @@ def_module_params('sat', ('phase.caching.off', UINT, 100, 'phase caching off period (in number of conflicts)'), ('phase.sticky', BOOL, False, 'use sticky phase caching for local search'), ('propagate.prefetch', BOOL, True, 'prefetch watch lists for assigned literals'), - ('restart', SYMBOL, 'luby', 'restart strategy: luby or geometric'), - ('restart.initial', UINT, 100, 'initial restart (number of conflicts)'), - ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), - ('restart.fast', BOOL, False, 'use fast restart strategy.'), + ('restart', SYMBOL, 'ema', 'restart strategy: static, luby, ema or geometric'), + ('restart.initial', UINT, 2, 'initial restart (number of conflicts)'), + ('restart.max', UINT, UINT_MAX, 'maximal number of restarts.'), + ('restart.fast', BOOL, True, 'use fast restart approach only removing less active literals.'), ('restart.factor', DOUBLE, 1.5, 'restart increment factor for geometric strategy'), + ('restart.margin', DOUBLE, 1.1, 'margin between fast and slow restart factors. For ema'), + ('restart.emafastglue', DOUBLE, 3e-2, 'ema alpha factor for fast moving average'), + ('restart.emaslowglue', DOUBLE, 1e-5, 'ema alpha factor for slow moving average'), ('variable_decay', UINT, 110, 'multiplier (divided by 100) for the VSIDS activity increement'), ('inprocess.max', UINT, UINT_MAX, 'maximal number of inprocessing passes'), ('branching.heuristic', SYMBOL, 'vsids', 'branching heuristic vsids, lrb or chb'), diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index d69a9cb4a..ee194721e 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -53,6 +53,8 @@ namespace sat { m_qhead(0), m_scope_lvl(0), m_search_lvl(0), + m_fast_glue_avg(), + m_slow_glue_avg(), m_params(p), m_par_id(0), m_par_syncing_clauses(false) { @@ -538,7 +540,6 @@ namespace sat { // walk clauses, reallocate them in an order that defragments memory and creates locality. for (literal lit : lits) { watch_list& wlist = m_watches[lit.index()]; - // for (watch_list& wlist : m_watches) { for (watched& w : wlist) { if (w.is_clause()) { clause& c1 = get_clause(w); @@ -791,12 +792,11 @@ namespace sat { } if (m_config.m_propagate_prefetch) { - _mm_prefetch((const char*)(m_watches[l.index()].c_ptr()), _MM_HINT_T1); + _mm_prefetch((const char*)(&*(m_watches[l.index()].c_ptr())), _MM_HINT_T1); } SASSERT(!l.sign() || m_phase[v] == NEG_PHASE); SASSERT(l.sign() || m_phase[v] == POS_PHASE); - SASSERT(!l.sign() || value(v) == l_false); SASSERT(l.sign() || value(v) == l_true); SASSERT(value(l) == l_true); @@ -1059,16 +1059,14 @@ namespace sat { return r; pop_reinit(scope_lvl()); m_conflicts_since_restart = 0; - m_restart_threshold = m_config.m_restart_initial; + m_restart_threshold = m_config.m_restart_initial; } // iff3_finder(*this)(); simplify_problem(); if (check_inconsistent()) return l_false; - if (m_config.m_max_conflicts == 0) { - m_reason_unknown = "sat.max.conflicts"; - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = 0\")\n";); + if (reached_max_conflicts()) { return l_undef; } @@ -1079,9 +1077,7 @@ namespace sat { if (r != l_undef) return r; - if (m_conflicts_since_init > m_config.m_max_conflicts) { - m_reason_unknown = "sat.max.conflicts"; - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts_since_init << "\")\n";); + if (reached_max_conflicts()) { return l_undef; } @@ -1413,7 +1409,7 @@ namespace sat { return l_true; if (!resolve_conflict()) return l_false; - if (m_conflicts_since_init > m_config.m_max_conflicts) + if (reached_max_conflicts()) return l_undef; if (should_restart()) return l_undef; @@ -1829,7 +1825,12 @@ namespace sat { } bool solver::should_restart() const { - return m_conflicts_since_restart > m_restart_threshold; + if (m_conflicts_since_restart <= m_restart_threshold) return false; + if (scope_lvl() < 2 + search_lvl()) return false; + if (m_config.m_restart != RS_EMA) return true; + return + m_fast_glue_avg + search_lvl() <= scope_lvl() && + m_config.m_restart_margin * m_slow_glue_avg <= m_fast_glue_avg; } void solver::restart(bool to_base) { @@ -1843,31 +1844,39 @@ namespace sat { << " :time " << std::fixed << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n";); } IF_VERBOSE(30, display_status(verbose_stream());); - unsigned num_scopes = 0; + pop_reinit(restart_level(to_base)); + set_next_restart(); + } + + unsigned solver::restart_level(bool to_base) { if (to_base || scope_lvl() == search_lvl()) { - num_scopes = scope_lvl() - search_lvl(); + return scope_lvl() - search_lvl(); } else { bool_var next = m_case_split_queue.min_var(); // Implementations of Marijn's idea of reusing the // trail when the next decision literal has lower precedence. + // pop trail from top #if 0 - // pop the trail from top + unsigned n = 0; do { - bool_var prev = scope_literal(scope_lvl() - num_scopes - 1).var(); + bool_var prev = scope_literal(scope_lvl() - n - 1).var(); if (m_case_split_queue.more_active(prev, next)) break; - ++num_scopes; + ++n; } - while (num_scopes < scope_lvl() - search_lvl()); -#else - // pop the trail from bottom - unsigned n = search_lvl(); - for (; n < scope_lvl() && m_case_split_queue.more_active(scope_literal(n).var(), next); ++n) ; - num_scopes = n - search_lvl(); + while (n < scope_lvl() - search_lvl()); + return n; #endif + // pop trail from bottom + unsigned n = search_lvl(); + for (; n < scope_lvl() && m_case_split_queue.more_active(scope_literal(n).var(), next); ++n) { + } + return n - search_lvl(); } - pop_reinit(num_scopes); + } + + void solver::set_next_restart() { m_conflicts_since_restart = 0; switch (m_config.m_restart) { case RS_GEOMETRIC: @@ -1877,6 +1886,11 @@ namespace sat { m_luby_idx++; m_restart_threshold = m_config.m_restart_initial * get_luby(m_luby_idx); break; + case RS_EMA: + m_restart_threshold = m_config.m_restart_initial; + break; + case RS_STATIC: + break; default: UNREACHABLE(); break; @@ -2356,6 +2370,8 @@ namespace sat { } unsigned glue = num_diff_levels(m_lemma.size(), m_lemma.c_ptr()); + m_fast_glue_avg.update(glue); + m_slow_glue_avg.update(glue); pop_reinit(m_scope_lvl - new_scope_lvl); TRACE("sat_conflict_detail", tout << new_scope_lvl << "\n"; display(tout);); @@ -3303,6 +3319,8 @@ namespace sat { m_rand.set_seed(m_config.m_random_seed); m_step_size = m_config.m_step_size_init; m_drat.updt_config(); + m_fast_glue_avg.set_alpha(m_config.m_fast_glue_avg); + m_slow_glue_avg.set_alpha(m_config.m_slow_glue_avg); } void solver::collect_param_descrs(param_descrs & d) { @@ -3849,6 +3867,17 @@ namespace sat { TRACE("sat", tout << m_core << "\n";); } + bool solver::reached_max_conflicts() { + if (m_config.m_max_conflicts == 0 || m_conflicts_since_init > m_config.m_max_conflicts) { + if (m_reason_unknown != "sat.max.conflicts") { + m_reason_unknown = "sat.max.conflicts"; + IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts_since_init << "\")\n";); + } + return true; + } + return false; + } + lbool solver::get_bounded_consequences(literal_vector const& asms, bool_var_vector const& vars, vector& conseq) { bool_var_set unfixed_vars; @@ -3894,8 +3923,7 @@ namespace sat { extract_fixed_consequences(num_units, asms, unfixed_vars, conseq); - if (m_conflicts_since_init > m_config.m_max_conflicts) { - IF_VERBOSE(SAT_VB_LVL, verbose_stream() << "(sat \"abort: max-conflicts = " << m_conflicts_since_init << "\")\n";); + if (reached_max_conflicts()) { return l_undef; } diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 634bf2788..1c5e10616 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -41,6 +41,7 @@ Revision History: #include "util/params.h" #include "util/statistics.h" #include "util/stopwatch.h" +#include "util/ema.h" #include "util/trace.h" #include "util/rlimit.h" #include "util/scoped_ptr_vector.h" @@ -137,6 +138,8 @@ namespace sat { unsigned m_qhead; unsigned m_scope_lvl; unsigned m_search_lvl; + ema m_fast_glue_avg; + ema m_slow_glue_avg; literal_vector m_trail; clause_wrapper_vector m_clauses_to_reinit; std::string m_reason_unknown; @@ -416,7 +419,10 @@ namespace sat { void mk_model(); bool check_model(model const & m) const; void restart(bool to_base); + unsigned restart_level(bool to_base); bool should_restart() const; + void set_next_restart(); + bool reached_max_conflicts(); void sort_watch_lits(); void exchange_par(); lbool check_par(unsigned num_lits, literal const* lits); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 4c2d8e8c6..b93de3073 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -782,7 +782,6 @@ namespace smt { if (pb.is_at_least_k(atom)) { return true; } - // TBD: other conditions return false; } @@ -791,7 +790,6 @@ namespace smt { if (ctx.b_internalized(atom)) { return true; } - if (!is_cardinality_constraint(atom)) { return false; } @@ -816,8 +814,7 @@ namespace smt { card* c = alloc(card, lit, bound, aux); - for (unsigned i = 0; i < num_args; ++i) { - expr* arg = atom->get_arg(i); + for (expr* arg : *atom) { c->add_arg(compile_arg(arg)); } @@ -2432,9 +2429,9 @@ namespace smt { void theory_pb::validate_assign(ineq const& c, literal_vector const& lits, literal l) const { uint_set nlits; - for (unsigned i = 0; i < lits.size(); ++i) { - SASSERT(get_context().get_assignment(lits[i]) == l_true); - nlits.insert((~lits[i]).index()); + for (literal lit : lits) { + SASSERT(get_context().get_assignment(lit) == l_true); + nlits.insert((~lit).index()); } SASSERT(get_context().get_assignment(l) == l_undef); SASSERT(get_context().get_assignment(c.lit()) == l_true); @@ -2448,9 +2445,7 @@ namespace smt { } CTRACE("pb", (sum >= c.k()), display(tout << "invalid assign" , c, true); - for (unsigned i = 0; i < lits.size(); ++i) { - tout << lits[i] << " "; - } + for (literal lit : lits) tout << lit << " "; tout << " => " << l << "\n";); SASSERT(sum < c.k()); } diff --git a/src/util/ema.h b/src/util/ema.h index 9d5e33a34..5a32e021c 100644 --- a/src/util/ema.h +++ b/src/util/ema.h @@ -7,7 +7,9 @@ Module Name: Abstract: - Exponential moving average in the style of CaDiCal. + Exponential moving average based on CaDiCal. + The exponential scheme used to adjust beta to alpha is + described in Biere & Froelich, POS (Pragmatics of SAT) 2016. Author: @@ -22,17 +24,27 @@ Revision History: class ema { double m_alpha, m_beta, m_value; unsigned m_period, m_wait; - + bool invariant() const { return 0 <= m_alpha && m_alpha <= m_beta && m_beta <= 1; } public: - ema() { memset(this, 0, sizeof(*this)); } + ema(): m_alpha(0), m_beta(1), m_value(0), m_period(0), m_wait(0) { + SASSERT(invariant()); + } ema(double alpha): m_alpha(alpha), m_beta(1), m_value(0), - m_period(0), m_wait(0) {} + m_period(0), m_wait(0) { + SASSERT(invariant()); + } - double operator() const { return m_value; } + void set_alpha(double alpha) { + m_alpha = alpha; + SASSERT(invariant()); + } + + operator double () const { return m_value; } void update(double x) { + SASSERT(invariant()); m_value += m_beta * (x - m_value); if (m_beta <= m_alpha || m_wait--) return; m_wait = m_period = 2*(m_period + 1) - 1; From ad6e128cab49b39211d6bce97b3a3c7a13c5492a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 7 May 2018 17:04:02 +0100 Subject: [PATCH 0847/1283] fix if-def Signed-off-by: Nikolaj Bjorner --- src/test/sat_local_search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 25fa59c95..4828046be 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -20,8 +20,6 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea #ifdef _WINDOWS int num_vars = 0, num_constraints = 0; sscanf_s(line, "%d %d", &num_vars, &num_constraints); -#else - return false; //std::cout << "number of variables: " << num_vars << '\n'; //std::cout << "number of constraints: " << num_constraints << '\n'; @@ -69,6 +67,8 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea infile.close(); return true; +#else + return false; #endif } From 2d5dd802386d78117d5ed9ddcbf8bc22ab3cb461 Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Mon, 7 May 2018 23:33:04 +0200 Subject: [PATCH 0848/1283] The Permutation Matrix' `values` function attempted an incorrect conversion. This causes compilation with GCC 8 to fail. I suspect it worked previously due to SFINAE. --- src/util/lp/permutation_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/lp/permutation_matrix.h b/src/util/lp/permutation_matrix.h index 3c89b3646..8e664bba0 100644 --- a/src/util/lp/permutation_matrix.h +++ b/src/util/lp/permutation_matrix.h @@ -132,7 +132,7 @@ class permutation_matrix : public tail_matrix { unsigned size() const { return static_cast(m_rev.size()); } - unsigned * values() const { return m_permutation; } + unsigned * values() const { return m_permutation.c_ptr(); } void resize(unsigned size) { unsigned old_size = m_permutation.size(); From d097d90731a954f29937facbab9b1fcf17134363 Mon Sep 17 00:00:00 2001 From: corrodedHash Date: Tue, 8 May 2018 19:26:14 +0200 Subject: [PATCH 0849/1283] Fixed Segfault when failing to load datalog file --- src/muz/fp/datalog_parser.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index dddca492b..a23d654b0 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -108,7 +108,9 @@ public: #endif } ~line_reader() { - fclose(m_file); + if (m_file != nullptr){ + fclose(m_file); + } } bool operator()() { return m_ok; } From 41072e3125f492ef5e1b47f08bfefbde9c2f74ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 May 2018 19:09:59 +0100 Subject: [PATCH 0850/1283] use __builtin_prefetch for clang/gcc Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index ee194721e..c75e74942 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -792,7 +792,11 @@ namespace sat { } if (m_config.m_propagate_prefetch) { +#if defined(__GLUC__) || defined(__clang__) + __builtin_prefetch((const char*)(&*(m_watches[l.index()].c_ptr())); +#else _mm_prefetch((const char*)(&*(m_watches[l.index()].c_ptr())), _MM_HINT_T1); +#endif } SASSERT(!l.sign() || m_phase[v] == NEG_PHASE); From 75ae58f49e85b10cde84ca0e79711fe2c7f75d37 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 May 2018 09:25:01 +0100 Subject: [PATCH 0851/1283] fix parenthesis Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c75e74942..c8173d1e7 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -793,7 +793,7 @@ namespace sat { if (m_config.m_propagate_prefetch) { #if defined(__GLUC__) || defined(__clang__) - __builtin_prefetch((const char*)(&*(m_watches[l.index()].c_ptr())); + __builtin_prefetch((const char*)(&*(m_watches[l.index()].c_ptr()))); #else _mm_prefetch((const char*)(&*(m_watches[l.index()].c_ptr())), _MM_HINT_T1); #endif From ad571510f3e44b57a67372a8e46675eba3a84f5e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 May 2018 10:49:32 +0100 Subject: [PATCH 0852/1283] disable slow validation code Signed-off-by: Nikolaj Bjorner --- src/smt/theory_pb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index b93de3073..d1ac608ea 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1820,8 +1820,8 @@ namespace smt { return value < 0; } - bool theory_pb::validate_implies(app_ref& A, app_ref& B) { - static bool validating = false; + bool theory_pb::validate_implies(app_ref& A, app_ref& B) { + static bool validating = true; // false; if (validating) return true; validating = true; ast_manager& m = get_manager(); From 2aedaf315a3fca530322381a43525ac473fcae4c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 May 2018 16:32:38 +0100 Subject: [PATCH 0853/1283] fix removal bug, tune all-interval usage Signed-off-by: Nikolaj Bjorner --- examples/python/all_interval_series.py | 2 ++ src/sat/sat_params.pyg | 2 +- src/sat/sat_simplifier.cpp | 5 +++-- src/sat/sat_simplifier.h | 2 ++ src/sat/sat_solver.cpp | 15 ++++++++++++--- src/sat/sat_solver.h | 2 ++ 6 files changed, 22 insertions(+), 6 deletions(-) diff --git a/examples/python/all_interval_series.py b/examples/python/all_interval_series.py index 216941451..8269303d3 100644 --- a/examples/python/all_interval_series.py +++ b/examples/python/all_interval_series.py @@ -8,6 +8,8 @@ from __future__ import print_function from z3 import * import time +set_option("sat.gc.burst", False) # disable GC at every search. It is wasteful for these small queries. + def diff_at_j_is_i(xs, j, i): assert(0 <= j and j + 1 < len(xs)) assert(1 <= i and i < len(xs)) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index ce40949da..dd840468e 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -28,7 +28,7 @@ def_module_params('sat', ('gc.increment', UINT, 500, 'increment to the garbage collection threshold'), ('gc.small_lbd', UINT, 3, 'learned clauses with small LBD are never deleted (only used in dyn_psm)'), ('gc.k', UINT, 7, 'learned clauses that are inactive for k gc rounds are permanently deleted (only used in dyn_psm)'), - ('gc.burst', BOOL, True, 'perform eager garbage collection during initialization'), + ('gc.burst', BOOL, False, 'perform eager garbage collection during initialization'), ('gc.defrag', BOOL, True, 'defragment clauses when garbage collecting'), ('simplify.delay', UINT, 0, 'set initial delay of simplification by a conflict count'), ('minimize_lemmas', BOOL, True, 'minimize learned clauses'), diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 314b661ea..efdf8a39a 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -664,8 +664,9 @@ namespace sat { m_sub_todo.insert(it.curr()); } clause_use_list& cs = m_use_list.get(l); - for (auto it = cs.mk_iterator(); !it.at_end(); it.next()) { + for (auto it = cs.mk_iterator(); !it.at_end(); ) { clause & c = it.curr(); + it.next(); remove_clause(c, l); } cs.reset(); @@ -2023,7 +2024,7 @@ namespace sat { m_new_cls.reset(); if (!resolve(c1, c2, pos_l, m_new_cls)) continue; - if (false && v == 27041) IF_VERBOSE(0, verbose_stream() << "elim: " << c1 << " + " << c2 << " -> " << m_new_cls << "\n"); + if (false && v == 767) IF_VERBOSE(0, verbose_stream() << "elim: " << c1 << " + " << c2 << " -> " << m_new_cls << "\n"); TRACE("resolution_new_cls", tout << c1 << "\n" << c2 << "\n-->\n" << m_new_cls << "\n";); if (cleanup_clause(m_new_cls)) continue; // clause is already satisfied. diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index a777e07a4..3787b5894 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -219,6 +219,8 @@ namespace sat { simplifier(solver & s, params_ref const & p); ~simplifier(); + void init_search() { m_num_calls = 0; } + void insert_elim_todo(bool_var v) { m_elim_todo.insert(v); } void reset_todos() { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c8173d1e7..c55383a57 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -524,8 +524,15 @@ namespace sat { } }; + bool solver::should_defrag() { + if (m_defrag_threshold > 0) --m_defrag_threshold; + return m_defrag_threshold == 0 && m_config.m_gc_defrag; + } + void solver::defrag_clauses() { + return; if (memory_pressure()) return; + pop(scope_lvl()); IF_VERBOSE(1, verbose_stream() << "(sat-defrag)\n"); clause_allocator& alloc = m_cls_allocator[!m_cls_allocator_idx]; ptr_vector new_clauses, new_learned; @@ -585,6 +592,8 @@ namespace sat { cls_allocator().finalize(); m_cls_allocator_idx = !m_cls_allocator_idx; + + reinit_assumptions(); } @@ -1576,6 +1585,7 @@ namespace sat { m_restart_threshold = m_config.m_restart_initial; m_luby_idx = 1; m_gc_threshold = m_config.m_gc_initial; + m_defrag_threshold = 2; m_restarts = 0; m_simplifications = 0; m_conflicts_since_init = 0; @@ -1590,6 +1600,7 @@ namespace sat { m_core.reset(); m_min_core_valid = false; m_min_core.reset(); + m_simplifier.init_search(); TRACE("sat", display(tout);); } @@ -1939,10 +1950,8 @@ namespace sat { break; } if (m_ext) m_ext->gc(); - if (gc > 0 && m_config.m_gc_defrag && !memory_pressure()) { - pop(scope_lvl()); + if (gc > 0 && should_defrag()) { defrag_clauses(); - reinit_assumptions(); } m_conflicts_since_gc = 0; m_gc_threshold += m_config.m_gc_increment; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index 1c5e10616..b44c04604 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -230,6 +230,7 @@ namespace sat { inline void dealloc_clause(clause* c) { cls_allocator().del_clause(c); } struct cmp_activity; void defrag_clauses(); + bool should_defrag(); bool memory_pressure(); void del_clause(clause & c); clause * mk_clause_core(unsigned num_lits, literal * lits, bool learned); @@ -392,6 +393,7 @@ namespace sat { unsigned m_luby_idx; unsigned m_conflicts_since_gc; unsigned m_gc_threshold; + unsigned m_defrag_threshold; unsigned m_num_checkpoints; double m_min_d_tk; unsigned m_next_simplify; From c151ae98f885d765b93d32d96981a31a44bec982 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 9 May 2018 18:20:37 +0100 Subject: [PATCH 0854/1283] fix osx build Signed-off-by: Nikolaj Bjorner --- src/solver/parallel_tactic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index 61e97e040..c5b10b9b2 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -30,6 +30,7 @@ Notes: #include #include +#include #include #include "util/scoped_ptr_vector.h" #include "ast/ast_util.h" From 618d394ab59f14860939f1ccfdc5cf9ffc229b72 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 10 May 2018 09:41:12 +0100 Subject: [PATCH 0855/1283] unreferenced variables Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver/inc_sat_solver.cpp | 1 - src/smt/theory_pb.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 2e16bc33e..e1e0e0b0a 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -871,6 +871,5 @@ void inc_sat_display(std::ostream& out, solver& _s, unsigned sz, expr*const* sof tactic * mk_psat_tactic(ast_manager& m, params_ref const& p) { parallel_params pp(p); - bool use_parallel = pp.enable(); return pp.enable() ? mk_parallel_tactic(mk_inc_sat_solver(m, p, false), p) : mk_sat_tactic(m); } diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index d1ac608ea..1e5b35fbf 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -2504,7 +2504,7 @@ namespace smt { bool theory_pb::validate_unit_propagation(card const& c) { context& ctx = get_context(); for (unsigned i = c.k(); i < c.size(); ++i) { - SASSERT(ctx.get_assignment(c.lit(i)) == l_false); + VERIFY(ctx.get_assignment(c.lit(i)) == l_false); } return true; } From 9e2625e629222fc4f6b7f55c904086e37ecdd7b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 May 2018 07:49:11 +0200 Subject: [PATCH 0856/1283] add support for core extraction in parallel mode Signed-off-by: Nikolaj Bjorner --- src/solver/parallel_tactic.cpp | 53 +++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index c5b10b9b2..4bb994bb8 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -183,6 +183,7 @@ class parallel_tactic : public tactic { scoped_ptr m_manager; // ownership handle to ast_manager vector m_cubes; // set of cubes to process by task expr_ref_vector m_asserted_cubes; // set of cubes asserted on the current solver + expr_ref_vector m_assumptions; // set of auxiliary assumptions passed in params_ref m_params; // configuration parameters ref m_solver; // solver state unsigned m_depth; // number of nested calls to cubing @@ -192,6 +193,7 @@ class parallel_tactic : public tactic { solver_state(ast_manager* m, solver* s, params_ref const& p): m_manager(m), m_asserted_cubes(s->get_manager()), + m_assumptions(s->get_manager()), m_params(p), m_solver(s), m_depth(0), @@ -207,6 +209,12 @@ class parallel_tactic : public tactic { solver const& get_solver() const { return *m_solver; } + void set_assumptions(ptr_vector const& asms) { + m_assumptions.append(asms.size(), asms.c_ptr()); + } + + bool has_assumptions() const { return !m_assumptions.empty(); } + solver_state* clone() { SASSERT(!m_cubes.empty()); ast_manager& m = m_solver->get_manager(); @@ -214,8 +222,9 @@ class parallel_tactic : public tactic { ast_translation tr(m, *new_m); solver* s = m_solver.get()->translate(*new_m, m_params); solver_state* st = alloc(solver_state, new_m, s, m_params); - for (auto & c : m_cubes) st->m_cubes.push_back(c(tr)); + for (auto& c : m_cubes) st->m_cubes.push_back(c(tr)); for (expr* c : m_asserted_cubes) st->m_asserted_cubes.push_back(tr(c)); + for (expr* c : m_assumptions) st->m_assumptions.push_back(tr(c)); st->m_depth = m_depth; st->m_width = m_width; return st; @@ -250,11 +259,11 @@ class parallel_tactic : public tactic { lbool r = l_undef; IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-1)\n";); set_simplify_params(true); // retain blocked - r = get_solver().check_sat(0,0); + r = get_solver().check_sat(m_assumptions); if (r != l_undef) return r; IF_VERBOSE(2, verbose_stream() << "(parallel.tactic simplify-2)\n";); set_simplify_params(false); // remove blocked - r = get_solver().check_sat(0,0); + r = get_solver().check_sat(m_assumptions); return r; } @@ -314,6 +323,7 @@ private: ast_manager& m_manager; params_ref m_params; sref_vector m_models; + expr_ref_vector m_core; unsigned m_num_threads; statistics m_stats; task_queue m_queue; @@ -340,6 +350,7 @@ private: m_conquer_delay = pp.conquer_delay(); m_exn_code = 0; m_params.set_bool("override_incremental", true); + m_core.reset(); } void log_branches(lbool status) { @@ -363,6 +374,15 @@ private: --m_branches; } + void collect_core(expr_ref_vector const& core) { + std::lock_guard lock(m_mutex); + ast_translation tr(core.get_manager(), m_manager); + expr_ref_vector core1(tr(core)); + for (expr* c : core1) { + if (!m_core.contains(c)) m_core.push_back(c); + } + } + void close_branch(solver_state& s, lbool status) { double f = 100.0 / s.get_width(); { @@ -398,6 +418,11 @@ private: void report_unsat(solver_state& s) { inc_unsat(); close_branch(s, l_false); + if (s.has_assumptions()) { + expr_ref_vector core(s.m()); + s.get_solver().get_unsat_core(core); + collect_core(core); + } } void report_undef(solver_state& s) { @@ -454,7 +479,7 @@ private: break; } lbool is_sat = l_undef; - if (width >= m_conquer_delay && !conquer) { + if (!s.has_assumptions() && width >= m_conquer_delay && !conquer) { conquer = s.copy_solver(); s.set_conquer_params(*conquer.get()); } @@ -647,37 +672,43 @@ public: parallel_tactic(solver* s, params_ref const& p) : m_solver(s), m_manager(s->get_manager()), - m_params(p) { + m_params(p), + m_core(m_manager) { init(); } void operator ()(const goal_ref & g,goal_ref_buffer & result) { - ast_manager& m = g->m(); + fail_if_proof_generation("parallel-tactic", g); + ast_manager& m = g->m(); solver* s = m_solver->translate(m, m_params); solver_state* st = alloc(solver_state, 0, s, m_params); m_queue.add_task(st); - expr_ref_vector clauses(m); + expr_ref_vector clauses(m);o ptr_vector assumptions; obj_map bool2dep; ref fmc; + expr_dependency * lcore = nullptr; + proof* pr = nullptr; extract_clauses_and_dependencies(g, clauses, assumptions, bool2dep, fmc); for (expr * clause : clauses) { s->assert_expr(clause); } - SASSERT(assumptions.empty()); + st->set_assumptions(assumptions); model_ref mdl; lbool is_sat = solve(mdl); switch (is_sat) { case l_true: + g->reset(); if (g->models_enabled()) { g->add(concat(fmc.get(), model2model_converter(mdl.get()))); } - g->reset(); break; case l_false: SASSERT(!g->proofs_enabled()); - SASSERT(!g->unsat_core_enabled()); - g->assert_expr(m.mk_false(), nullptr, nullptr); + for (expr * c : m_core) { + lcore = m.mk_join(lcore, m.mk_leaf(bool2dep.find(c))); + } + g->assert_expr(m.mk_false(), pr, lcore); break; case l_undef: if (m.canceled()) { From f2bee7f16a831019f390bf5fbda6df09f1b4d949 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 12 May 2018 10:03:20 -0700 Subject: [PATCH 0857/1283] fix build Signed-off-by: Nikolaj Bjorner --- src/solver/parallel_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index 4bb994bb8..fb1001f32 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -683,7 +683,7 @@ public: solver* s = m_solver->translate(m, m_params); solver_state* st = alloc(solver_state, 0, s, m_params); m_queue.add_task(st); - expr_ref_vector clauses(m);o + expr_ref_vector clauses(m); ptr_vector assumptions; obj_map bool2dep; ref fmc; From 1e143971c3018857b79cc844cc2584c8c24a5bd1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 13 May 2018 11:49:33 -0700 Subject: [PATCH 0858/1283] tune for unit test, delay initialize re-solver Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.h | 1 + src/smt/theory_seq.cpp | 6 ++++-- src/test/get_implied_equalities.cpp | 6 +++--- src/test/sat_local_search.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 95b043bd7..c96096c65 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -89,6 +89,7 @@ public: ~re2automaton(); eautomaton* operator()(expr* e); void set_solver(expr_solver* solver); + bool has_solver() const { return m_solver; } eautomaton* mk_product(eautomaton *a1, eautomaton *a2); }; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 95f804863..b704795b2 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -238,8 +238,7 @@ theory_seq::~theory_seq() { } void theory_seq::init(context* ctx) { - theory::init(ctx); - m_mk_aut.set_solver(alloc(seq_expr_solver, m, get_context().get_fparams())); + theory::init(ctx); } final_check_status theory_seq::final_check_eh() { @@ -4168,6 +4167,9 @@ eautomaton* theory_seq::get_automaton(expr* re) { if (m_re2aut.find(re, result)) { return result; } + if (!m_mk_aut.has_solver()) { + m_mk_aut.set_solver(alloc(seq_expr_solver, m, get_context().get_fparams())); + } result = m_mk_aut(re); if (result) { display_expr disp(m); diff --git a/src/test/get_implied_equalities.cpp b/src/test/get_implied_equalities.cpp index 952fb121a..dae182a34 100644 --- a/src/test/get_implied_equalities.cpp +++ b/src/test/get_implied_equalities.cpp @@ -75,9 +75,9 @@ static void tst_get_implied_equalities1() { } static void tst_get_implied_equalities2() { - enable_trace("after_search"); - enable_trace("get_implied_equalities"); - enable_trace("implied_equalities"); + //enable_trace("after_search"); + //enable_trace("get_implied_equalities"); + //enable_trace("implied_equalities"); Z3_config cfg = Z3_mk_config(); Z3_context ctx = Z3_mk_context(cfg); Z3_del_config(cfg); diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 4828046be..1116c5420 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -7,7 +7,6 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_search& local_search) { char line[16383]; - int cur_term; // for temperally storage std::ifstream infile(filename); @@ -18,6 +17,7 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea } infile.getline(line, 16383); #ifdef _WINDOWS + int cur_term; int num_vars = 0, num_constraints = 0; sscanf_s(line, "%d %d", &num_vars, &num_constraints); //std::cout << "number of variables: " << num_vars << '\n'; From c198b12743c10934c15d7574b13634f0f0d51b21 Mon Sep 17 00:00:00 2001 From: Sapan Bhatia Date: Tue, 15 May 2018 04:55:57 +0530 Subject: [PATCH 0859/1283] Big_int is no longer a part of OCaml's standard library and must be included via the num package: https://github.com/ocaml/num --- scripts/mk_util.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 99de61703..aab4bcb21 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1932,8 +1932,14 @@ class MLComponent(Component): OCAML_FLAGS = '' if DEBUG_MODE: OCAML_FLAGS += '-g' - OCAMLCF = OCAMLC + ' ' + OCAML_FLAGS - OCAMLOPTF = OCAMLOPT + ' ' + OCAML_FLAGS + + if OCAMLFIND: + # Load Big_int, which is no longer part of the standard library, via the num package: https://github.com/ocaml/num + OCAMLCF = OCAMLFIND + ' ' + 'ocamlc -package num' + ' ' + OCAML_FLAGS + OCAMLOPTF = OCAMLFIND + ' ' + 'ocamlopt -package num' + ' ' + OCAML_FLAGS + else: + OCAMLCF = OCAMLC + ' ' + OCAML_FLAGS + OCAMLOPTF = OCAMLOPT + ' ' + OCAML_FLAGS src_dir = self.to_src_dir mk_dir(os.path.join(BUILD_DIR, self.sub_dir)) From dfeb4b5235f4cc42062011632c97d6ab095593a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 May 2018 16:45:12 -0700 Subject: [PATCH 0860/1283] updated sat state Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 3 --- src/sat/sat_solver.cpp | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index efdf8a39a..4fd9b08be 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -192,8 +192,6 @@ namespace sat { return; if (!m_subsumption && !bce_enabled() && !bca_enabled() && !elim_vars_enabled()) return; - - // solver::scoped_disable_checkpoint _scoped_disable_checkpoint(s); initialize(); @@ -257,7 +255,6 @@ namespace sat { TRACE("sat_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); finalize(); - } /** diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c55383a57..09fe08f18 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -530,7 +530,6 @@ namespace sat { } void solver::defrag_clauses() { - return; if (memory_pressure()) return; pop(scope_lvl()); IF_VERBOSE(1, verbose_stream() << "(sat-defrag)\n"); @@ -802,9 +801,9 @@ namespace sat { if (m_config.m_propagate_prefetch) { #if defined(__GLUC__) || defined(__clang__) - __builtin_prefetch((const char*)(&*(m_watches[l.index()].c_ptr()))); + __builtin_prefetch((const char*)((m_watches[l.index()].c_ptr()))); #else - _mm_prefetch((const char*)(&*(m_watches[l.index()].c_ptr())), _MM_HINT_T1); + _mm_prefetch((const char*)((m_watches[l.index()].c_ptr())), _MM_HINT_T1); #endif } From e5b14ab6825f48fffd09c758066b6a0b7b930f2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 May 2018 14:03:32 -0700 Subject: [PATCH 0861/1283] fix #1625 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b81927474..4bb1acded 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2292,6 +2292,7 @@ namespace z3 { class optimize : public object { Z3_optimize m_opt; + public: class handle { unsigned m_h; @@ -2300,6 +2301,17 @@ namespace z3 { unsigned h() const { return m_h; } }; optimize(context& c):object(c) { m_opt = Z3_mk_optimize(c); Z3_optimize_inc_ref(c, m_opt); } + optimize(optimize& o):object(c) { + Z3_optimize_inc_ref(o.ctx(), o.m_opt); + m_opt = o.m_opt; + } + optimize& operator=(optimize const& o) { + Z3_optimize_inc_rec(o.ctx(), o.m_opt); + Z3_optimize_dec_ref(ctx(), m_opt); + m_opt = o.m_opt; + m_ctx = o.m_ctx; + return *this; + } ~optimize() { Z3_optimize_dec_ref(ctx(), m_opt); } operator Z3_optimize() const { return m_opt; } void add(expr const& e) { From 925867dc3ee4e4f0085d07d912cd9f7b7b904fa9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 May 2018 14:14:00 -0700 Subject: [PATCH 0862/1283] fix #1621 Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 2 +- src/util/smt2_util.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index aeaebc6bf..ade12de62 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -912,7 +912,7 @@ class smt2_printer { var_name = mk_smt2_quoted_symbol (*it); } else { - var_name = it->str ();\ + var_name = it->str (); } buf.push_back(mk_seq1(m(), fs, fs+1, f2f(), var_name.c_str ())); } diff --git a/src/util/smt2_util.cpp b/src/util/smt2_util.cpp index 8358c67ac..a218f0c27 100644 --- a/src/util/smt2_util.cpp +++ b/src/util/smt2_util.cpp @@ -34,6 +34,12 @@ bool is_smt2_quoted_symbol(char const * s) { if ('0' <= s[0] && s[0] <= '9') return true; unsigned len = static_cast(strlen(s)); + if (len > 2 && s[0] == '|' && s[len-1] == '|') { + for (unsigned i = 1; i + 1 < len; i++) + if (!is_smt2_simple_symbol_char(s[i])) + return true; + return false; + } for (unsigned i = 0; i < len; i++) if (!is_smt2_simple_symbol_char(s[i])) return true; From 83023603213157c06ad9eaf77b4f5eb96262bd1c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 May 2018 14:24:12 -0700 Subject: [PATCH 0863/1283] fix #1625 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4bb1acded..903086daa 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2301,12 +2301,12 @@ namespace z3 { unsigned h() const { return m_h; } }; optimize(context& c):object(c) { m_opt = Z3_mk_optimize(c); Z3_optimize_inc_ref(c, m_opt); } - optimize(optimize& o):object(c) { + optimize(optimize& o):object(o) { Z3_optimize_inc_ref(o.ctx(), o.m_opt); m_opt = o.m_opt; } optimize& operator=(optimize const& o) { - Z3_optimize_inc_rec(o.ctx(), o.m_opt); + Z3_optimize_inc_ref(o.ctx(), o.m_opt); Z3_optimize_dec_ref(ctx(), m_opt); m_opt = o.m_opt; m_ctx = o.m_ctx; From d462ed3f0057a24fc1872a6a7a1e6ead34c970e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 May 2018 14:30:27 -0700 Subject: [PATCH 0864/1283] fix #1621 Signed-off-by: Nikolaj Bjorner --- src/util/smt2_util.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/util/smt2_util.cpp b/src/util/smt2_util.cpp index a218f0c27..365d8fe70 100644 --- a/src/util/smt2_util.cpp +++ b/src/util/smt2_util.cpp @@ -34,10 +34,14 @@ bool is_smt2_quoted_symbol(char const * s) { if ('0' <= s[0] && s[0] <= '9') return true; unsigned len = static_cast(strlen(s)); - if (len > 2 && s[0] == '|' && s[len-1] == '|') { - for (unsigned i = 1; i + 1 < len; i++) - if (!is_smt2_simple_symbol_char(s[i])) + if (len >= 2 && s[0] == '|' && s[len-1] == '|') { + for (unsigned i = 1; i + 1 < len; i++) { + if (s[i] == '\\' && i + 2 < len && (s[i+1] == '\\' || s[i+1] == '|')) { + i++; + } + else if (s[i] == '\\' || s[i] == '|') return true; + } return false; } for (unsigned i = 0; i < len; i++) From 1cc4a4ccc5ac7eb8a9e669ace3db89b9e0d607ff Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 02:56:46 +0200 Subject: [PATCH 0865/1283] remove unused constructor that would construct lar_constraint in an partly initialized state. Fixes: variable may be used uninitialized --- src/util/lp/lar_constraints.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/lp/lar_constraints.h b/src/util/lp/lar_constraints.h index 9d3a0e0aa..5c33db8c6 100644 --- a/src/util/lp/lar_constraints.h +++ b/src/util/lp/lar_constraints.h @@ -84,7 +84,6 @@ struct lar_term_constraint: public lar_base_constraint { class lar_constraint : public lar_base_constraint { public: vector> m_coeffs; - lar_constraint() {} lar_constraint(const vector> & left_side, lconstraint_kind kind, const mpq & right_side) : lar_base_constraint(kind, right_side), m_coeffs(left_side) {} From 5134c168332147029a4d0fdb7cf945e0be18354f Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 03:19:57 +0200 Subject: [PATCH 0866/1283] NULL-initialize pointers to help GCC static analyzer Fixes: variable may be used uninitialized --- src/ast/rewriter/poly_rewriter_def.h | 3 ++- src/ast/rewriter/rewriter_def.h | 6 +++--- src/smt/theory_str.cpp | 20 ++++++++++---------- src/tactic/core/solve_eqs_tactic.cpp | 4 ++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index f27c9ffcf..d65960857 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -431,7 +431,8 @@ struct poly_rewriter::hoist_cmul_lt { hoist_cmul_lt(poly_rewriter & r):m_r(r) {} bool operator()(expr * t1, expr * t2) const { - expr * pp1, * pp2; + expr * pp1 = nullptr; + expr * pp2 = nullptr; numeral c1, c2; bool is_mul1 = m_r.is_mul(t1, c1, pp1); bool is_mul2 = m_r.is_mul(t2, c2, pp2); diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index dfb6542d6..4d4c4f708 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -336,9 +336,9 @@ void rewriter_tpl::process_app(app * t, frame & fr) { UNREACHABLE(); } // TODO: add rewrite rules support - expr * def; - proof * def_pr; - quantifier * def_q; + expr * def = nullptr; + proof * def_pr = nullptr; + quantifier * def_q = nullptr; // When get_macro succeeds, then // we know that: // forall X. f(X) = def[X] diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 126594b06..0c4d11420 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1423,9 +1423,9 @@ namespace smt { // len(hd) = i // str.indexof(tl, N, 0) - expr * H; // "haystack" - expr * N; // "needle" - expr * i; // start index + expr * H = nullptr; // "haystack" + expr * N = nullptr; // "needle" + expr * i = nullptr; // start index u.str.is_index(e, H, N, i); expr_ref minus_one(m_autil.mk_numeral(rational::minus_one(), true), m); @@ -6951,8 +6951,8 @@ namespace smt { ast_manager & m = get_manager(); expr_ref_vector rhs(m); - expr * str; - expr * re; + expr * str = nullptr; + expr * re = nullptr; u.str.is_in_re(str_in_re, str, re); expr_ref strlen(mk_strlen(str), m); @@ -9929,8 +9929,8 @@ namespace smt { bool regex_axiom_add = false; for (obj_hashtable::iterator it = regex_terms.begin(); it != regex_terms.end(); ++it) { expr * str_in_re = *it; - expr * str; - expr * re; + expr * str = nullptr; + expr * re = nullptr; u.str.is_in_re(str_in_re, str, re); lbool current_assignment = ctx.get_assignment(str_in_re); TRACE("str", tout << "regex term: " << mk_pp(str, m) << " in " << mk_pp(re, m) << " : " << current_assignment << std::endl;); @@ -9944,7 +9944,7 @@ namespace smt { if (regex_term_to_length_constraint.contains(str_in_re)) { // use existing length constraint - expr * top_level_length_constraint; + expr * top_level_length_constraint = nullptr; regex_term_to_length_constraint.find(str_in_re, top_level_length_constraint); ptr_vector extra_length_vars; @@ -10473,8 +10473,8 @@ namespace smt { // that's consistent with the current length information for (ptr_vector::iterator term_it = str_in_re_terms.begin(); term_it != str_in_re_terms.end(); ++term_it) { - expr * _unused; - expr * re; + expr * _unused = nullptr; + expr * re = nullptr; SASSERT(u.str.is_in_re(*term_it)); u.str.is_in_re(*term_it, _unused, re); diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 9253b7172..c95a79ff7 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -263,8 +263,8 @@ class solve_eqs_tactic : public tactic { bool solve_arith_core(app * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { SASSERT(m_a_util.is_add(lhs)); bool is_int = m_a_util.is_int(lhs); - expr * a; - expr * v; + expr * a = nullptr; + expr * v = nullptr; rational a_val; unsigned num = lhs->get_num_args(); unsigned i; From f02d031d119c413cebd3432a644206caed0459e6 Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 03:47:11 +0200 Subject: [PATCH 0867/1283] As of GCC8, the throw by value, catch by reference idiom is enforced via -Wcatch-value --- src/cmd_context/basic_cmds.cpp | 4 ++-- src/interp/iz3translate_direct.cpp | 8 ++++---- src/math/subpaving/subpaving.cpp | 12 ++++++------ src/math/subpaving/subpaving_t_def.h | 4 ++-- src/shell/datalog_frontend.cpp | 2 +- src/tactic/aig/aig.cpp | 2 +- src/test/mpff.cpp | 6 +++--- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 4e8806d62..56a354ee8 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -395,7 +395,7 @@ class set_option_cmd : public set_get_option_cmd { env_params::updt_params(); ctx.global_params_updated(); } - catch (gparams::exception ex) { + catch (const gparams::exception & ex) { throw cmd_exception(ex.msg()); } } @@ -620,7 +620,7 @@ public: try { ctx.regular_stream() << gparams::get_value(opt) << std::endl; } - catch (gparams::exception ex) { + catch (const gparams::exception & ex) { ctx.print_unsupported(opt, m_line, m_pos); } } diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index 8c2016149..9efb1a383 100644 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -912,7 +912,7 @@ public: if(!add_local_antes(arg, hyps, dk == PR_UNIT_RESOLUTION && i == 0)) return false; } - catch (non_lit_local_ante) { + catch (const non_lit_local_ante &) { std::cout << "\n"; show_step(proof); show(conc(proof)); @@ -1138,7 +1138,7 @@ public: try { res = iproof->make_resolution(pnode,neg,pos); } - catch (const iz3proof::proof_error){ + catch (const iz3proof::proof_error &){ std::cout << "\nresolution error in theory lemma\n"; std::cout << "lits:\n"; for(unsigned j = 0; j < lits.size(); j++) @@ -1212,7 +1212,7 @@ public: try { res = iproof->make_resolution(pnode,neg,pos); } - catch (const iz3proof::proof_error){ + catch (const iz3proof::proof_error &){ std::cout << "\nresolution error in theory lemma\n"; std::cout << "lits:\n"; for(unsigned j = 0; j < lits.size(); j++) @@ -1418,7 +1418,7 @@ public: try { return iproof->make_resolution(pnode,neg,pos); } - catch (const iz3proof::proof_error){ + catch (const iz3proof::proof_error &){ std::cout << "resolution error in unit_resolution, position" << position << "\n"; show_step(proof); throw invalid_lemma(); diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index 16a9a9a9e..c43b74f0d 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -121,7 +121,7 @@ namespace subpaving { int2mpf(c, m_c); return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs); } - catch (f2n::exception) { + catch (const f2n::exception &) { throw subpaving::exception(); } } @@ -135,7 +135,7 @@ namespace subpaving { m.set(m_c, k); return reinterpret_cast(m_ctx.mk_ineq(x, m_c, lower, open)); } - catch (f2n::exception) { + catch (const f2n::exception &) { throw subpaving::exception(); } } @@ -178,7 +178,7 @@ namespace subpaving { int2hwf(c, m_c); return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs); } - catch (f2n::exception) { + catch (const f2n::exception &) { throw subpaving::exception(); } } @@ -192,7 +192,7 @@ namespace subpaving { m.set(m_c, k); return reinterpret_cast(m_ctx.mk_ineq(x, m_c, lower, open)); } - catch (f2n::exception) { + catch (const f2n::exception &) { throw subpaving::exception(); } } @@ -236,7 +236,7 @@ namespace subpaving { int2fpoint(c, m_c); return this->m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs); } - catch (typename context_fpoint::numeral_manager::exception) { + catch (const typename context_fpoint::numeral_manager::exception &) { throw subpaving::exception(); } } @@ -251,7 +251,7 @@ namespace subpaving { m.set(m_c, m_qm, k); return reinterpret_cast(this->m_ctx.mk_ineq(x, m_c, lower, open)); } - catch (typename context_fpoint::numeral_manager::exception) { + catch (const typename context_fpoint::numeral_manager::exception &) { throw subpaving::exception(); } } diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index bb129fee7..cf93fbfad 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -1310,7 +1310,7 @@ bool context_t::relevant_new_bound(var x, numeral const & k, bool lower, bool TRACE("subpaving_relevant_bound", tout << "new bound is relevant\n";); return true; } - catch (typename C::exception) { + catch (const typename C::exception &) { // arithmetic module failed. set_arith_failed(); return false; @@ -1722,7 +1722,7 @@ void context_t::propagate(node * n, bound * b) { } } } - catch (typename C::exception) { + catch (const typename C::exception &) { // arithmetic module failed, ignore constraint set_arith_failed(); } diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 9cc13b897..6596cc3b7 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -246,7 +246,7 @@ unsigned read_datalog(char const * file) { false); } - catch (out_of_memory_error) { + catch (const out_of_memory_error &) { std::cout << "\n\nOUT OF MEMORY!\n\n"; display_statistics( std::cout, diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 6afac32b8..f6e12275f 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -1522,7 +1522,7 @@ public: } SASSERT(ref_count(r) >= 1); } - catch (aig_exception ex) { + catch (const aig_exception & ex) { dec_ref(r); throw ex; } diff --git a/src/test/mpff.cpp b/src/test/mpff.cpp index dd934831c..c78489f21 100644 --- a/src/test/mpff.cpp +++ b/src/test/mpff.cpp @@ -35,7 +35,7 @@ static void tst1() { std::cout << i << ": " << a << "\n"; } } - catch (z3_exception & ex) { + catch (const z3_exception & ex) { std::cout << ex.msg() << "\n"; } } @@ -432,7 +432,7 @@ static void tst_limits(unsigned prec) { m.round_to_plus_inf(); bool overflow = false; try { m.inc(a); } - catch (mpff_manager::overflow_exception) { overflow = true; } + catch (const mpff_manager::overflow_exception &) { overflow = true; } VERIFY(overflow); m.set_max(a); m.dec(a); @@ -446,7 +446,7 @@ static void tst_limits(unsigned prec) { ENSURE(m.eq(a, b)); overflow = true; try { m.dec(a); } - catch (mpff_manager::overflow_exception) { overflow = true; } + catch (const mpff_manager::overflow_exception &) { overflow = true; } ENSURE(overflow); m.round_to_plus_inf(); m.set_min(a); From 7d51353b8b097a22b0278cb50006c6b4ff5e0fe1 Mon Sep 17 00:00:00 2001 From: Joran Honig Date: Sat, 19 May 2018 11:13:53 +0200 Subject: [PATCH 0868/1283] Implement parallel python example --- examples/python/parallel.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 examples/python/parallel.py diff --git a/examples/python/parallel.py b/examples/python/parallel.py new file mode 100644 index 000000000..7903f58c9 --- /dev/null +++ b/examples/python/parallel.py @@ -0,0 +1,33 @@ +from z3 import * +from multiprocessing.pool import ThreadPool +from copy import deepcopy + +pool = ThreadPool(8) +x = Int('x') + +assert x.ctx == main_ctx() + + +def calculate(x, n, ctx): + """ Do a simple computation with a context""" + assert x.ctx == ctx + assert x.ctx != main_ctx() + + condition = And(x < 2, x > n, ctx) + solver = Solver(ctx=ctx) + solver.add(condition) + solver.check() + + +for i in range(100): + # Create new context for the computation + # Note that we need to do this sequentially, as parallel access to the current context or its objects + # will result in a segfault + i_context = Context() + x_i = deepcopy(x).translate(i_context) + + # Kick off parallel computation + pool.apply_async(calculate, [x_i, i, i_context]) + +pool.close() +pool.join() From e32dfad81e7fc14816c034d1a527975d0cc97138 Mon Sep 17 00:00:00 2001 From: Joran Honig Date: Sat, 19 May 2018 11:16:20 +0200 Subject: [PATCH 0869/1283] Add comments --- examples/python/parallel.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/python/parallel.py b/examples/python/parallel.py index 7903f58c9..42ff50927 100644 --- a/examples/python/parallel.py +++ b/examples/python/parallel.py @@ -13,7 +13,10 @@ def calculate(x, n, ctx): assert x.ctx == ctx assert x.ctx != main_ctx() + # Parallel creation of z3 object condition = And(x < 2, x > n, ctx) + + # Parallel solving solver = Solver(ctx=ctx) solver.add(condition) solver.check() From 9c5a0ee8102dc248b29fbb930ecdb8158965ca21 Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 04:17:52 +0200 Subject: [PATCH 0870/1283] Remove unnecessary (and confusing) parantheses around variable name in its declaration. Also fixes GCC warning [-Wparentheses]. --- src/interp/iz3base.cpp | 2 +- src/smt/theory_str.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp index 43e7bdff8..773f328ab 100644 --- a/src/interp/iz3base.cpp +++ b/src/interp/iz3base.cpp @@ -281,7 +281,7 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v _proof = cook(proof); } else if(vars.size()) { - model_ref(_m); + model_ref _m; s.get_model(_m); if (!_m.get()) { SASSERT(l_undef == res); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0c4d11420..dde75c4bc 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6768,7 +6768,7 @@ namespace smt { expr * sub2; if (u.re.is_to_re(re, sub1)) { SASSERT(u.str.is_string(sub1)); - zstring(str); + zstring str; u.str.is_string(sub1, str); lens.insert(str.length()); } else if (u.re.is_concat(re, sub1, sub2)) { From 78087483ca065c6518b3b09e2b945c9041862624 Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 04:25:43 +0200 Subject: [PATCH 0871/1283] Add missing include The code should not have compiled previously, as smt::context was only forward declared at this point. --- src/smt/theory_arith.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 5040f1034..944efe6ce 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -31,6 +31,7 @@ Revision History: #include "smt/params/theory_arith_params.h" #include "smt/arith_eq_adapter.h" #include "smt/proto_model/numeral_factory.h" +#include "smt/smt_context.h" #include "util/obj_pair_hashtable.h" #include "smt/old_interval.h" #include "math/grobner/grobner.h" From 7467368266629486b3e11698f6e52ad8dd4a256f Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Mon, 21 May 2018 07:26:29 +0200 Subject: [PATCH 0872/1283] Use CMake's own mechanism for selecting language version if CMake version is new enough --- CMakeLists.txt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4732ef67..420c1a122 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,12 +218,17 @@ include(${CMAKE_SOURCE_DIR}/cmake/z3_add_cxx_flag.cmake) ################################################################################ # C++ language version ################################################################################ -# FIXME: Use CMake's own mechanism for selecting language version -if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) - z3_add_cxx_flag("-std=c++11" REQUIRED) -else() - message(AUTHOR_WARNING "Not setting C++ language version for compiler") -endif() +if ("${CMAKE_VERSION}" VERSION_LESS "3.1") + # FIXME: Drop this when we upgrade to newer CMake versions. + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + z3_add_cxx_flag("-std=c++11" REQUIRED) + else() + message(AUTHOR_WARNING "Not setting C++ language version for compiler") + endif() +else () + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif () ################################################################################ # Platform detection From 3b1b82bef05a1b5fd69ece79c80a95fb6d72a990 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 10:19:38 -0700 Subject: [PATCH 0873/1283] bumping version number by 1 for release tagging Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 420c1a122..afea250cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 7) -set(Z3_VERSION_PATCH 0) +set(Z3_VERSION_PATCH 1) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 8f601f4fe..af4c92658 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 7, 0, 0) + set_version(4, 7, 1, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') From f2aae7cffa58686a8d251c87301c82cd4c2db200 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 16:59:11 -0700 Subject: [PATCH 0874/1283] release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 86e7039dd..a99ec6b1e 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,22 @@ RELEASE NOTES +Version 4.7.1 +============= + +- New requirements: + - uses stdbool and stdint as part of z3.h + +- New features: + - none + +- Removed features: + - none + +- Notes: + This is a minor release prior to a set of planned major updates. + It uses minor version 7 to indicate that the use of stdbool and + stdint are breaking changes to consumers of the C-based API. + Version 4.6.0 ============= From 87ae679db61e7d3fbe3ffc7f07dd5f06f5409277 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 17:03:35 -0700 Subject: [PATCH 0875/1283] delay dereferencing justification Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 09fe08f18..2c05cc52c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2761,7 +2761,7 @@ namespace sat { while (!m_lemma_min_stack.empty()) { bool_var var = m_lemma_min_stack.back(); m_lemma_min_stack.pop_back(); - justification js = m_justification[var]; + justification const& js = m_justification[var]; switch(js.get_kind()) { case justification::NONE: // it is a decision variable from a previous scope level From 363d7aad2ad243e8f871891322995830634b84f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 20:02:08 -0700 Subject: [PATCH 0876/1283] fix bug reported in #1637 Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_explain.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index ac16d9d68..2278e53dd 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1463,6 +1463,7 @@ namespace nlsat { void project(var x, unsigned num, literal const * ls, scoped_literal_vector & result) { + m_result = &result; svector lits; TRACE("nlsat", tout << "project x" << x << "\n"; m_solver.display(tout);); @@ -1643,6 +1644,7 @@ namespace nlsat { ++num_lub; } } + TRACE("nlsat_explain", tout << ps << "\n";); if (num_lub == 0) { project_plus_infinity(x, ps); @@ -1668,7 +1670,7 @@ namespace nlsat { unsigned d = degree(p, x); lc = m_pm.coeff(p, x, d); if (!is_const(lc)) { - unsigned s = sign(p); + int s = sign(p); SASSERT(s != 0); atom::kind k = (s > 0)?(atom::GT):(atom::LT); add_simple_assumption(k, lc); @@ -1683,7 +1685,8 @@ namespace nlsat { unsigned d = degree(p, x); lc = m_pm.coeff(p, x, d); if (!is_const(lc)) { - unsigned s = sign(p); + int s = sign(p); + TRACE("nlsat_explain", tout << "degree: " << d << " " << lc << " sign: " << s << "\n";); SASSERT(s != 0); atom::kind k; if (s > 0) { From c963f6f2df8a113522173fe2cf024aa5962ac5b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 08:02:16 -0700 Subject: [PATCH 0877/1283] merge with master Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 40 -- src/api/api_solver.cpp | 2 +- .../simplifier/arith_simplifier_plugin.cpp | 496 ------------------ src/ast/simplifier/arith_simplifier_plugin.h | 97 ---- src/cmd_context/basic_cmds.cpp | 2 +- src/cmd_context/cmd_context.cpp | 7 +- src/opt/maxres.cpp | 1 - src/opt/opt_context.h | 31 -- src/solver/combined_solver.cpp | 2 +- 9 files changed, 9 insertions(+), 669 deletions(-) delete mode 100644 scripts/vsts.cmd delete mode 100644 src/ast/simplifier/arith_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/arith_simplifier_plugin.h diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd deleted file mode 100644 index 3b3a60231..000000000 --- a/scripts/vsts.cmd +++ /dev/null @@ -1,40 +0,0 @@ -echo "Build" -md build -cd build -call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" -cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ -nmake -rem TBD: test error level - -echo "Test python bindings" -pushd python -python z3test.py z3 -python z3test.py z3num -popd - -echo "Build and run examples" -nmake cpp_example -examples\cpp_example_build_dir\cpp_example.exe - -nmake c_example -examples\c_example_build_dir\c_example.exe - -rem nmake java_example -rem java_example.exe - -rem nmake dotnet_example -rem dotnet_example.exe - -echo "Build and run unit tests" -nmake test-z3 -rem TBD: test error level -rem test-z3.exe -a - - -cd .. -echo "Run regression tests" -git clone https://github.com/z3prover/z3test z3test -echo "test-benchmarks" -python z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2 -echo "benchmarks tested" - diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index ab1ea4a8e..657ff025c 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -152,7 +152,7 @@ extern "C" { return; } - bool initialized = to_solver(s)->m_solver.get() != 0; + bool initialized = to_solver(s)->m_solver.get() != nullptr; if (!initialized) init_solver(c, s); ptr_vector::const_iterator it = ctx->begin_assertions(); diff --git a/src/ast/simplifier/arith_simplifier_plugin.cpp b/src/ast/simplifier/arith_simplifier_plugin.cpp deleted file mode 100644 index 52f36ab04..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.cpp +++ /dev/null @@ -1,496 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - arith_simplifier_plugin.cpp - -Abstract: - - Simplifier for the arithmetic family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#include"arith_simplifier_plugin.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" - -arith_simplifier_plugin::~arith_simplifier_plugin() { -} - -arith_simplifier_plugin::arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p): - poly_simplifier_plugin(symbol("arith"), m, OP_ADD, OP_MUL, OP_UMINUS, OP_SUB, OP_NUM), - m_params(p), - m_util(m), - m_bsimp(b), - m_int_zero(m), - m_real_zero(m) { - m_int_zero = m_util.mk_numeral(rational(0), true); - m_real_zero = m_util.mk_numeral(rational(0), false); -} - -/** - \brief Return true if the first monomial of t is negative. -*/ -bool arith_simplifier_plugin::is_neg_poly(expr * t) const { - if (m_util.is_add(t)) { - t = to_app(t)->get_arg(0); - } - if (m_util.is_mul(t)) { - t = to_app(t)->get_arg(0); - rational r; - if (is_numeral(t, r)) - return r.is_neg(); - } - return false; -} - -void arith_simplifier_plugin::get_monomial_gcd(expr_ref_vector& monomials, numeral& g) { - g = numeral::zero(); - numeral n; - for (unsigned i = 0; !g.is_one() && i < monomials.size(); ++i) { - expr* e = monomials[i].get(); - if (is_numeral(e, n)) { - g = gcd(abs(n), g); - } - else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) { - g = gcd(abs(n), g); - } - else { - g = numeral::one(); - return; - } - } - if (g.is_zero()) { - g = numeral::one(); - } -} - -void arith_simplifier_plugin::div_monomial(expr_ref_vector& monomials, numeral const& g) { - numeral n; - for (unsigned i = 0; i < monomials.size(); ++i) { - expr* e = monomials[i].get(); - if (is_numeral(e, n)) { - SASSERT((n/g).is_int()); - monomials[i] = mk_numeral(n/g); - } - else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) { - SASSERT((n/g).is_int()); - monomials[i] = mk_mul(n/g, to_app(e)->get_arg(1)); - } - else { - UNREACHABLE(); - } - } -} - -void arith_simplifier_plugin::gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k) { - numeral g, n; - - get_monomial_gcd(monomials, g); - g = gcd(abs(k), g); - - if (g.is_one()) { - return; - } - SASSERT(g.is_pos()); - - k = k / g; - div_monomial(monomials, g); - -} - -template -void arith_simplifier_plugin::mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - bool is_int = m_curr_sort->get_decl_kind() == INT_SORT; - expr_ref_vector monomials(m_manager); - rational k; - TRACE("arith_eq_bug", tout << mk_ismt2_pp(arg1, m_manager) << "\n" << mk_ismt2_pp(arg2, m_manager) << "\n";); - process_sum_of_monomials(false, arg1, monomials, k); - process_sum_of_monomials(true, arg2, monomials, k); - k.neg(); - if (is_int) { - numeral g; - get_monomial_gcd(monomials, g); - if (!g.is_one()) { - div_monomial(monomials, g); - switch(Kind) { - case LE: - // - // g*monmials' <= k - // <=> - // monomials' <= floor(k/g) - // - k = floor(k/g); - break; - case GE: - // - // g*monmials' >= k - // <=> - // monomials' >= ceil(k/g) - // - k = ceil(k/g); - break; - case EQ: - k = k/g; - if (!k.is_int()) { - result = m_manager.mk_false(); - return; - } - break; - } - } - } - expr_ref lhs(m_manager); - mk_sum_of_monomials(monomials, lhs); - if (m_util.is_numeral(lhs)) { - SASSERT(lhs == mk_zero()); - if (( Kind == LE && numeral::zero() <= k) || - ( Kind == GE && numeral::zero() >= k) || - ( Kind == EQ && numeral::zero() == k)) - result = m_manager.mk_true(); - else - result = m_manager.mk_false(); - } - else { - - if (is_neg_poly(lhs)) { - expr_ref neg_lhs(m_manager); - mk_uminus(lhs, neg_lhs); - lhs = neg_lhs; - k.neg(); - expr * rhs = m_util.mk_numeral(k, is_int); - switch (Kind) { - case LE: - result = m_util.mk_ge(lhs, rhs); - break; - case GE: - result = m_util.mk_le(lhs, rhs); - break; - case EQ: - result = m_manager.mk_eq(lhs, rhs); - break; - } - } - else { - expr * rhs = m_util.mk_numeral(k, is_int); - switch (Kind) { - case LE: - result = m_util.mk_le(lhs, rhs); - break; - case GE: - result = m_util.mk_ge(lhs, rhs); - break; - case EQ: - result = m_manager.mk_eq(lhs, rhs); - break; - } - } - } -} - -void arith_simplifier_plugin::mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_le(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_lt(expr * arg1, expr * arg2, expr_ref & result) { - expr_ref tmp(m_manager); - mk_le(arg2, arg1, tmp); - m_bsimp.mk_not(tmp, result); -} - -void arith_simplifier_plugin::mk_gt(expr * arg1, expr * arg2, expr_ref & result) { - expr_ref tmp(m_manager); - mk_le(arg1, arg2, tmp); - m_bsimp.mk_not(tmp, result); -} - -void arith_simplifier_plugin::gcd_normalize(numeral & coeff, expr_ref& term) { - if (!abs(coeff).is_one()) { - set_curr_sort(term); - SASSERT(m_curr_sort->get_decl_kind() == INT_SORT); - expr_ref_vector monomials(m_manager); - rational k; - monomials.push_back(mk_numeral(numeral(coeff), true)); - process_sum_of_monomials(false, term, monomials, k); - gcd_reduce_monomial(monomials, k); - numeral coeff1; - if (!is_numeral(monomials[0].get(), coeff1)) { - UNREACHABLE(); - } - if (coeff1 == coeff) { - return; - } - monomials[0] = mk_numeral(k, true); - coeff = coeff1; - mk_sum_of_monomials(monomials, term); - } -} - - -void arith_simplifier_plugin::mk_div(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - SASSERT(!is_int); - if (m_util.is_numeral(arg1, v1, is_int)) - result = m_util.mk_numeral(v1/v2, false); - else { - numeral k(1); - k /= v2; - - expr_ref inv_arg2(m_util.mk_numeral(k, false), m_manager); - mk_mul(inv_arg2, arg1, result); - } - } - else - result = m_util.mk_div(arg1, arg2); -} - -void arith_simplifier_plugin::mk_idiv(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) - result = m_util.mk_numeral(div(v1, v2), is_int); - else if (divides(arg2, arg1, result)) { - result = m_util.mk_mul(result, m_util.mk_idiv(arg2, arg2)); - } - else - result = m_util.mk_idiv(arg1, arg2); -} - -bool arith_simplifier_plugin::divides(expr* d, expr* n, expr_ref& quot) { - ast_manager& m = m_manager; - if (d == n) { - quot = m_util.mk_numeral(rational(1), m_util.is_int(d)); - return true; - } - if (m_util.is_mul(n)) { - expr_ref_vector muls(m); - muls.push_back(n); - expr* n1, *n2; - rational r1, r2; - for (unsigned i = 0; i < muls.size(); ++i) { - if (m_util.is_mul(muls[i].get(), n1, n2)) { - muls[i] = n1; - muls.push_back(n2); - --i; - } - } - if (m_util.is_numeral(d, r1) && !r1.is_zero()) { - for (unsigned i = 0; i < muls.size(); ++i) { - if (m_util.is_numeral(muls[i].get(), r2) && (r2 / r1).is_int()) { - muls[i] = m_util.mk_numeral(r2 / r1, m_util.is_int(d)); - quot = m_util.mk_mul(muls.size(), muls.c_ptr()); - return true; - } - } - } - else { - for (unsigned i = 0; i < muls.size(); ++i) { - if (d == muls[i].get()) { - muls[i] = muls.back(); - muls.pop_back(); - quot = m_util.mk_mul(muls.size(), muls.c_ptr()); - return true; - } - } - } - } - return false; -} - - -void arith_simplifier_plugin::prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result) { - SASSERT(m_util.is_int(e)); - SASSERT(k.is_int() && k.is_pos()); - numeral n; - bool is_int; - - if (depth == 0) { - result = e; - } - else if (is_add(e) || is_mul(e)) { - expr_ref_vector args(m_manager); - expr_ref tmp(m_manager); - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - prop_mod_const(a->get_arg(i), depth - 1, k, tmp); - args.push_back(tmp); - } - reduce(a->get_decl(), args.size(), args.c_ptr(), result); - } - else if (m_util.is_numeral(e, n, is_int) && is_int) { - result = mk_numeral(mod(n, k), true); - } - else { - result = e; - } -} - -void arith_simplifier_plugin::mk_mod(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - result = m_util.mk_numeral(mod(v1, v2), is_int); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) { - result = m_util.mk_numeral(numeral(0), true); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos()) { - expr_ref tmp(m_manager); - prop_mod_const(arg1, 5, v2, tmp); - result = m_util.mk_mod(tmp, arg2); - } - else { - result = m_util.mk_mod(arg1, arg2); - } -} - -void arith_simplifier_plugin::mk_rem(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - numeral m = mod(v1, v2); - // - // rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2) - // - if (v2.is_neg()) { - m.neg(); - } - result = m_util.mk_numeral(m, is_int); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) { - result = m_util.mk_numeral(numeral(0), true); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) { - expr_ref tmp(m_manager); - prop_mod_const(arg1, 5, v2, tmp); - result = m_util.mk_mod(tmp, arg2); - if (v2.is_neg()) { - result = m_util.mk_uminus(result); - } - } - else { - result = m_util.mk_rem(arg1, arg2); - } -} - -void arith_simplifier_plugin::mk_to_real(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = m_util.mk_numeral(v, false); - else - result = m_util.mk_to_real(arg); -} - -void arith_simplifier_plugin::mk_to_int(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = m_util.mk_numeral(floor(v), true); - else if (m_util.is_to_real(arg)) - result = to_app(arg)->get_arg(0); - else - result = m_util.mk_to_int(arg); -} - -void arith_simplifier_plugin::mk_is_int(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = v.is_int()?m_manager.mk_true():m_manager.mk_false(); - else if (m_util.is_to_real(arg)) - result = m_manager.mk_true(); - else - result = m_util.mk_is_int(arg); -} - -bool arith_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - SASSERT(f->get_family_id() == m_fid); - TRACE("arith_simplifier_plugin", tout << mk_pp(f, m_manager) << "\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_pp(args[i], m_manager) << "\n";); - arith_op_kind k = static_cast(f->get_decl_kind()); - switch (k) { - case OP_NUM: return false; - case OP_LE: if (m_presimp) return false; SASSERT(num_args == 2); mk_le(args[0], args[1], result); break; - case OP_GE: if (m_presimp) return false; SASSERT(num_args == 2); mk_ge(args[0], args[1], result); break; - case OP_LT: if (m_presimp) return false; SASSERT(num_args == 2); mk_lt(args[0], args[1], result); break; - case OP_GT: if (m_presimp) return false; SASSERT(num_args == 2); mk_gt(args[0], args[1], result); break; - case OP_ADD: mk_add(num_args, args, result); break; - case OP_SUB: mk_sub(num_args, args, result); break; - case OP_UMINUS: SASSERT(num_args == 1); mk_uminus(args[0], result); break; - case OP_MUL: - mk_mul(num_args, args, result); - TRACE("arith_simplifier_plugin", tout << mk_pp(result, m_manager) << "\n";); - break; - case OP_DIV: SASSERT(num_args == 2); mk_div(args[0], args[1], result); break; - case OP_IDIV: SASSERT(num_args == 2); mk_idiv(args[0], args[1], result); break; - case OP_REM: SASSERT(num_args == 2); mk_rem(args[0], args[1], result); break; - case OP_MOD: SASSERT(num_args == 2); mk_mod(args[0], args[1], result); break; - case OP_TO_REAL: SASSERT(num_args == 1); mk_to_real(args[0], result); break; - case OP_TO_INT: SASSERT(num_args == 1); mk_to_int(args[0], result); break; - case OP_IS_INT: SASSERT(num_args == 1); mk_is_int(args[0], result); break; - case OP_POWER: return false; - case OP_ABS: SASSERT(num_args == 1); mk_abs(args[0], result); break; - case OP_IRRATIONAL_ALGEBRAIC_NUM: return false; - case OP_DIV_0: return false; - case OP_IDIV_0: return false; - default: - return false; - } - TRACE("arith_simplifier_plugin", tout << mk_pp(result.get(), m_manager) << "\n";); - return true; -} - -void arith_simplifier_plugin::mk_abs(expr * arg, expr_ref & result) { - expr_ref c(m_manager); - expr_ref m_arg(m_manager); - mk_uminus(arg, m_arg); - mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg)), c); - m_bsimp.mk_ite(c, arg, m_arg, result); -} - -bool arith_simplifier_plugin::is_arith_term(expr * n) const { - return n->get_kind() == AST_APP && to_app(n)->get_family_id() == m_fid; -} - -bool arith_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - TRACE("reduce_eq_bug", tout << mk_ismt2_pp(lhs, m_manager) << "\n" << mk_ismt2_pp(rhs, m_manager) << "\n";); - set_reduce_invoked(); - if (m_presimp) { - return false; - } - if (m_params.m_arith_expand_eqs) { - expr_ref le(m_manager), ge(m_manager); - mk_le_ge_eq_core(lhs, rhs, le); - mk_le_ge_eq_core(lhs, rhs, ge); - m_bsimp.mk_and(le, ge, result); - return true; - } - - if (m_params.m_arith_process_all_eqs || is_arith_term(lhs) || is_arith_term(rhs)) { - mk_arith_eq(lhs, rhs, result); - return true; - } - return false; -} - - - diff --git a/src/ast/simplifier/arith_simplifier_plugin.h b/src/ast/simplifier/arith_simplifier_plugin.h deleted file mode 100644 index 045ee0e71..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.h +++ /dev/null @@ -1,97 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - arith_simplifier_plugin.h - -Abstract: - - Simplifier for the arithmetic family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#ifndef ARITH_SIMPLIFIER_PLUGIN_H_ -#define ARITH_SIMPLIFIER_PLUGIN_H_ - -#include"basic_simplifier_plugin.h" -#include"poly_simplifier_plugin.h" -#include"arith_decl_plugin.h" -#include"arith_simplifier_params.h" - -/** - \brief Simplifier for the arith family. -*/ -class arith_simplifier_plugin : public poly_simplifier_plugin { -public: - enum op_kind { - LE, GE, EQ - }; -protected: - arith_simplifier_params & m_params; - arith_util m_util; - basic_simplifier_plugin & m_bsimp; - expr_ref m_int_zero; - expr_ref m_real_zero; - - bool is_neg_poly(expr * t) const; - - template - void mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result); - - void prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result); - - void gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k); - - void div_monomial(expr_ref_vector& monomials, numeral const& g); - void get_monomial_gcd(expr_ref_vector& monomials, numeral& g); - bool divides(expr* d, expr* n, expr_ref& quot); - -public: - arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p); - ~arith_simplifier_plugin(); - arith_util & get_arith_util() { return m_util; } - virtual numeral norm(const numeral & n) { return n; } - virtual bool is_numeral(expr * n, rational & val) const { bool f; return m_util.is_numeral(n, val, f); } - bool is_numeral(expr * n) const { return m_util.is_numeral(n); } - virtual bool is_minus_one(expr * n) const { numeral tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); } - virtual expr * get_zero(sort * s) const { return m_util.is_int(s) ? m_int_zero.get() : m_real_zero.get(); } - - virtual app * mk_numeral(numeral const & n) { return m_util.mk_numeral(n, m_curr_sort->get_decl_kind() == INT_SORT); } - app * mk_numeral(numeral const & n, bool is_int) { return m_util.mk_numeral(n, is_int); } - bool is_int_sort(sort const * s) const { return m_util.is_int(s); } - bool is_real_sort(sort const * s) const { return m_util.is_real(s); } - bool is_arith_sort(sort const * s) const { return is_int_sort(s) || is_real_sort(s); } - bool is_int(expr const * n) const { return m_util.is_int(n); } - bool is_le(expr const * n) const { return m_util.is_le(n); } - bool is_ge(expr const * n) const { return m_util.is_ge(n); } - - virtual bool is_le_ge(expr * n) const { return is_le(n) || is_ge(n); } - - void mk_le(expr * arg1, expr * arg2, expr_ref & result); - void mk_ge(expr * arg1, expr * arg2, expr_ref & result); - void mk_lt(expr * arg1, expr * arg2, expr_ref & result); - void mk_gt(expr * arg1, expr * arg2, expr_ref & result); - void mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result); - void mk_div(expr * arg1, expr * arg2, expr_ref & result); - void mk_idiv(expr * arg1, expr * arg2, expr_ref & result); - void mk_mod(expr * arg1, expr * arg2, expr_ref & result); - void mk_rem(expr * arg1, expr * arg2, expr_ref & result); - void mk_to_real(expr * arg, expr_ref & result); - void mk_to_int(expr * arg, expr_ref & result); - void mk_is_int(expr * arg, expr_ref & result); - void mk_abs(expr * arg, expr_ref & result); - - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - - bool is_arith_term(expr * n) const; - - void gcd_normalize(numeral & coeff, expr_ref& term); - -}; - -#endif /* ARITH_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 981fd801f..1d8fdb3de 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -619,7 +619,7 @@ public: try { ctx.regular_stream() << gparams::get_value(opt) << std::endl; } - catch (const gparams::exception & ex) { + catch (const gparams::exception &) { ctx.print_unsupported(opt, m_line, m_pos); } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 20b28ecc1..e42f884d6 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1525,7 +1525,12 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions throw ex; } catch (z3_exception & ex) { - m_solver->set_reason_unknown(ex.msg()); + if (m().canceled()) { + m_solver->set_reason_unknown(eh); + } + else { + m_solver->set_reason_unknown(ex.msg()); + } r = l_undef; } m_solver->set_status(r); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index dd93ec74b..d49044d8d 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -64,7 +64,6 @@ Notes: #include "opt/opt_params.hpp" #include "opt/maxsmt.h" #include "opt/maxres.h" -// #include "opt/mss.h" using namespace opt; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 0f02dfb1c..b642f1d7a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -182,27 +182,6 @@ namespace opt { void get_hard_constraints(expr_ref_vector& hard); expr_ref get_objective(unsigned i); -#if 0 - virtual void push(); - virtual void pop(unsigned n); - virtual bool empty() { return m_scoped_state.m_objectives.empty(); } - virtual void set_hard_constraints(ptr_vector & hard); - virtual lbool optimize(); - virtual void set_model(model_ref& _m) { m_model = _m; } - virtual void get_model_core(model_ref& _m); - virtual void get_box_model(model_ref& _m, unsigned index); - virtual void fix_model(model_ref& _m); - virtual void collect_statistics(statistics& stats) const; - virtual proof* get_proof() { return 0; } - virtual void get_labels(svector & r); - virtual void get_unsat_core(ptr_vector & r); - virtual std::string reason_unknown() const; - virtual void set_reason_unknown(char const* msg) { m_unknown = msg; } - - virtual void display_assignment(std::ostream& out); - virtual bool is_pareto() { return m_pareto.get() != 0; } - virtual void set_logic(symbol const& s) { m_logic = s; } -#endif void push() override; void pop(unsigned n) override; bool empty() override { return m_scoped_state.m_objectives.empty(); } @@ -244,16 +223,6 @@ namespace opt { expr_ref mk_ge(unsigned i, model_ref& model) override; expr_ref mk_le(unsigned i, model_ref& model) override; -#if 0 - virtual smt::context& smt_context() { return m_opt_solver->get_context(); } - virtual bool sat_enabled() const { return 0 != m_sat_solver.get(); } - virtual solver& get_solver(); - virtual ast_manager& get_manager() const { return this->m; } - virtual params_ref& params() { return m_params; } - virtual void enable_sls(bool force); - virtual symbol const& maxsat_engine() const { return m_maxsat_engine; } - virtual void get_base_model(model_ref& _m); -#endif generic_model_converter& fm() override { return *m_fm; } smt::context& smt_context() override { return m_opt_solver->get_context(); } bool sat_enabled() const override { return nullptr != m_sat_solver.get(); } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 6ce8a6ae0..a47302f5d 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -207,7 +207,7 @@ public: } catch (z3_exception& ex) { if (get_manager().canceled()) { - set_reason_unknown(Z3_CANCELED_MSG); + throw; } else { set_reason_unknown(ex.msg()); From 2800049dd4562359d400f00a2b57d6c6325eb4e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 08:49:49 -0700 Subject: [PATCH 0878/1283] stale files Signed-off-by: Nikolaj Bjorner --- src/util/lp/nra_solver.cpp2 | 264 ------------------------------------ src/util/lp/nra_solver.h | 70 ---------- 2 files changed, 334 deletions(-) delete mode 100644 src/util/lp/nra_solver.cpp2 delete mode 100644 src/util/lp/nra_solver.h diff --git a/src/util/lp/nra_solver.cpp2 b/src/util/lp/nra_solver.cpp2 deleted file mode 100644 index 327d2b70f..000000000 --- a/src/util/lp/nra_solver.cpp2 +++ /dev/null @@ -1,264 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Nikolaj Bjorner -*/ - -#include "util/lp/lar_solver.h" -#include "util/lp/nra_solver.h" -#include "nlsat/nlsat_solver.h" -#include "math/polynomial/polynomial.h" -#include "math/polynomial/algebraic_numbers.h" -#include "util/map.h" - - -namespace nra { - - struct mon_eq { - mon_eq(lp::var_index v, unsigned sz, lp::var_index const* vs): - m_v(v), m_vs(sz, vs) {} - lp::var_index m_v; - svector m_vs; - }; - - struct solver::imp { - lp::lar_solver& s; - reslimit& m_limit; - params_ref m_params; - u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables - scoped_ptr m_nlsat; - vector m_monomials; - unsigned_vector m_monomials_lim; - mutable std::unordered_map m_variable_values; // current model - - imp(lp::lar_solver& s, reslimit& lim, params_ref const& p): - s(s), - m_limit(lim), - m_params(p) { - } - - bool need_check() { - return !m_monomials.empty() && !check_assignments(); - } - - void add(lp::var_index v, unsigned sz, lp::var_index const* vs) { - m_monomials.push_back(mon_eq(v, sz, vs)); - } - - void push() { - m_monomials_lim.push_back(m_monomials.size()); - } - - void pop(unsigned n) { - if (n == 0) return; - m_monomials.shrink(m_monomials_lim[m_monomials_lim.size() - n]); - m_monomials_lim.shrink(m_monomials_lim.size() - n); - } - - /* - \brief Check if polynomials are well defined. - multiply values for vs and check if they are equal to value for v. - epsilon has been computed. - */ - bool check_assignment(mon_eq const& m) const { - rational r1 = m_variable_values[m.m_v]; - rational r2(1); - for (auto w : m.m_vs) { - r2 *= m_variable_values[w]; - } - return r1 == r2; - } - - bool check_assignments() const { - s.get_model(m_variable_values); - for (auto const& m : m_monomials) { - if (!check_assignment(m)) return false; - } - return true; - } - - /** - \brief one-shot nlsat check. - A one shot checker is the least functionality that can - enable non-linear reasoning. - In addition to checking satisfiability we would also need - to identify equalities in the model that should be assumed - with the remaining solver. - - TBD: use partial model from lra_solver to prime the state of nlsat_solver. - TBD: explore more incremental ways of applying nlsat (using assumptions) - */ - lbool check(lp::explanation_t& ex) { - SASSERT(need_check()); - m_nlsat = alloc(nlsat::solver, m_limit, m_params); - m_lp2nl.reset(); - vector core; - - // add linear inequalities from lra_solver - for (unsigned i = 0; i < s.constraint_count(); ++i) { - add_constraint(i); - } - - // add polynomial definitions. - for (auto const& m : m_monomials) { - add_monomial_eq(m); - } - // TBD: add variable bounds? - - lbool r = m_nlsat->check(); - TRACE("arith", m_nlsat->display(tout << r << "\n");); - switch (r) { - case l_true: - break; - case l_false: - ex.reset(); - m_nlsat->get_core(core); - for (auto c : core) { - unsigned idx = static_cast(static_cast(c) - this); - ex.push_back(std::pair(rational(1), idx)); - TRACE("arith", tout << "ex: " << idx << "\n";); - } - break; - - case l_undef: - break; - } - return r; - } - - void add_monomial_eq(mon_eq const& m) { - polynomial::manager& pm = m_nlsat->pm(); - svector vars; - for (auto v : m.m_vs) { - vars.push_back(lp2nl(v)); - } - polynomial::monomial_ref m1(pm.mk_monomial(vars.size(), vars.c_ptr()), pm); - polynomial::monomial_ref m2(pm.mk_monomial(lp2nl(m.m_v), 1), pm); - polynomial::monomial* mls[2] = { m1, m2 }; - polynomial::scoped_numeral_vector coeffs(pm.m()); - coeffs.push_back(mpz(1)); - coeffs.push_back(mpz(-1)); - polynomial::polynomial_ref p(pm.mk_polynomial(2, coeffs.c_ptr(), mls), pm); - polynomial::polynomial* ps[1] = { p }; - bool even[1] = { false }; - nlsat::literal lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, even); - m_nlsat->mk_clause(1, &lit, 0); - } - - void add_constraint(unsigned idx) { - auto& c = s.get_constraint(idx); - auto& pm = m_nlsat->pm(); - auto k = c.m_kind; - auto rhs = c.m_right_side; - auto lhs = c.get_left_side_coefficients(); - auto sz = lhs.size(); - svector vars; - rational den = denominator(rhs); - for (auto kv : lhs) { - vars.push_back(lp2nl(kv.second)); - den = lcm(den, denominator(kv.first)); - } - vector coeffs; - for (auto kv : lhs) { - coeffs.push_back(den * kv.first); - } - rhs *= den; - polynomial::polynomial_ref p(pm.mk_linear(sz, coeffs.c_ptr(), vars.c_ptr(), -rhs), pm); - polynomial::polynomial* ps[1] = { p }; - bool is_even[1] = { false }; - nlsat::literal lit; - nlsat::assumption a = this + idx; - switch (k) { - case lp::lconstraint_kind::LE: - lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); - break; - case lp::lconstraint_kind::GE: - lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); - break; - case lp::lconstraint_kind::LT: - lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); - break; - case lp::lconstraint_kind::GT: - lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); - break; - case lp::lconstraint_kind::EQ: - lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); - break; - } - m_nlsat->mk_clause(1, &lit, a); - } - - bool is_int(lp::var_index v) { - return s.var_is_int(v); - } - - - polynomial::var lp2nl(lp::var_index v) { - polynomial::var r; - if (!m_lp2nl.find(v, r)) { - r = m_nlsat->mk_var(is_int(v)); - m_lp2nl.insert(v, r); - } - return r; - } - - nlsat::anum const& value(lp::var_index v) const { - return m_nlsat->value(m_lp2nl.find(v)); - } - - nlsat::anum_manager& am() { - return m_nlsat->am(); - } - - std::ostream& display(std::ostream& out) const { - for (auto m : m_monomials) { - out << "v" << m.m_v << " = "; - for (auto v : m.m_vs) { - out << "v" << v << " "; - } - out << "\n"; - } - return out; - } - }; - - solver::solver(lp::lar_solver& s, reslimit& lim, params_ref const& p) { - m_imp = alloc(imp, s, lim, p); - } - - solver::~solver() { - dealloc(m_imp); - } - - void solver::add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs) { - m_imp->add(v, sz, vs); - } - - lbool solver::check(lp::explanation_t& ex) { - return m_imp->check(ex); - } - - bool solver::need_check() { - return m_imp->need_check(); - } - - void solver::push() { - m_imp->push(); - } - - void solver::pop(unsigned n) { - m_imp->pop(n); - } - - std::ostream& solver::display(std::ostream& out) const { - return m_imp->display(out); - } - - nlsat::anum const& solver::value(lp::var_index v) const { - return m_imp->value(v); - } - - nlsat::anum_manager& solver::am() { - return m_imp->am(); - } - -} diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h deleted file mode 100644 index 70e614e91..000000000 --- a/src/util/lp/nra_solver.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Nikolaj Bjorner -*/ - -#pragma once -#include "util/vector.h" -#include "util/lp/lp_settings.h" -#include "util/rlimit.h" -#include "util/params.h" -#include "nlsat/nlsat_solver.h" - -namespace lp { - class lar_solver; -} - - -namespace nra { - - - - class solver { - struct imp; - imp* m_imp; - - public: - - solver(lp::lar_solver& s, reslimit& lim, params_ref const& p = params_ref()); - - ~solver(); - - /* - \brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1] - The variable v is equal to the product of variables vs. - */ - void add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs); - - /* - \brief Check feasiblity of linear constraints augmented by polynomial definitions - that are added. - */ - lbool check(lp::explanation_t& ex); - - /* - \brief determine whether nra check is needed. - */ - bool need_check(); - - /* - \brief Access model. - */ - nlsat::anum const& value(lp::var_index v) const; - - nlsat::anum_manager& am(); - - /* - \brief push and pop scope. - Monomial definitions are retraced when popping scope. - */ - void push(); - - void pop(unsigned n); - - /* - \brief display state - */ - std::ostream& display(std::ostream& out) const; - - }; -} From 0708ecb543072f91219a27be229c4d1fee865a11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 09:11:33 -0700 Subject: [PATCH 0879/1283] dealing with compilers that don't take typename in non-template classes Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 22 +-- src/opt/sortmax.cpp | 22 +-- src/sat/ba_solver.h | 22 +-- src/smt/theory_pb.cpp | 4 +- src/tactic/arith/card2bv_tactic.h | 24 ++-- src/test/sorting_network.cpp | 20 +-- src/util/lp/cut_solver.h | 201 ---------------------------- src/util/lp/int_solver.h | 157 ---------------------- src/util/sorting_network.h | 4 +- 9 files changed, 59 insertions(+), 417 deletions(-) delete mode 100644 src/util/lp/cut_solver.h delete mode 100644 src/util/lp/int_solver.h diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 47a8a044a..7da8b2d3f 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -43,8 +43,8 @@ struct pb2bv_rewriter::imp { unsigned m_compile_card; struct card2bv_rewriter { - typedef expr* literal; - typedef ptr_vector literal_vector; + typedef expr* pliteral; + typedef ptr_vector pliteral_vector; psort_nw m_sort; ast_manager& m; imp& m_imp; @@ -861,25 +861,25 @@ struct pb2bv_rewriter::imp { } // definitions used for sorting network - literal mk_false() { return m.mk_false(); } - literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } - literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } + 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_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } - std::ostream& pp(std::ostream& out, literal lit) { return out << mk_ismt2_pp(lit, m); } + std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_ismt2_pp(lit, m); } - literal trail(literal l) { + pliteral trail(pliteral l) { m_trail.push_back(l); return l; } - literal fresh(char const* n) { + pliteral fresh(char const* n) { expr_ref fr(m.mk_fresh_const(n, m.mk_bool_sort()), m); m_imp.m_fresh.push_back(to_app(fr)->get_decl()); return trail(fr); } - void mk_clause(unsigned n, literal const* lits) { + void mk_clause(unsigned n, pliteral const* lits) { m_imp.m_lemmas.push_back(::mk_or(m, n, lits)); } diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 6ea7feaad..9c45e42a2 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -30,8 +30,8 @@ namespace opt { class sortmax : public maxsmt_solver_base { public: - typedef expr* literal; - typedef ptr_vector literal_vector; + typedef expr* pliteral; + typedef ptr_vector pliteral_vector; psort_nw m_sort; expr_ref_vector m_trail; func_decl_ref_vector m_fresh; @@ -126,19 +126,19 @@ namespace opt { } // definitions used for sorting network - literal mk_false() { return m.mk_false(); } - literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } - literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } + 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_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } - std::ostream& pp(std::ostream& out, literal lit) { return out << mk_pp(lit, m); } + std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_pp(lit, m); } - literal trail(literal l) { + pliteral trail(pliteral l) { m_trail.push_back(l); return l; } - literal fresh(char const* n) { + pliteral fresh(char const* n) { expr_ref fr(m.mk_fresh_const(n, m.mk_bool_sort()), m); func_decl* f = to_app(fr)->get_decl(); m_fresh.push_back(f); @@ -146,7 +146,7 @@ namespace opt { return trail(fr); } - void mk_clause(unsigned n, literal const* lits) { + void mk_clause(unsigned n, pliteral const* lits) { s().assert_expr(mk_or(m, n, lits)); } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 14482eabb..07e7cfd58 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -242,23 +242,23 @@ namespace sat { unsigned_vector m_pb_undef; struct ba_sort { - typedef typename sat::literal literal; - typedef typename sat::literal_vector literal_vector; + typedef sat::literal pliteral; + typedef sat::literal_vector pliteral_vector; ba_solver& s; - literal m_true; - literal_vector m_lits; + pliteral m_true; + pliteral_vector m_lits; ba_sort(ba_solver& s): s(s), m_true(null_literal) {} - literal mk_false(); - literal mk_true(); - literal mk_not(literal l); - literal fresh(char const*); - literal mk_max(literal l1, literal l2); - literal mk_min(literal l1, literal l2); + pliteral mk_false(); + 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); void mk_clause(unsigned n, literal const* lits); - std::ostream& pp(std::ostream& out, literal l) const; + std::ostream& pp(std::ostream& out, pliteral l) const; }; ba_sort m_ba; psort_nw m_sort; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 1e5b35fbf..9fc33a6a9 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1392,8 +1392,8 @@ namespace smt { ast_manager& m; theory_pb& th; pb_util pb; - typedef smt::literal literal; - typedef smt::literal_vector literal_vector; + typedef smt::literal pliteral; + typedef smt::literal_vector pliteral_vector; psort_expr(context& c, theory_pb& th): ctx(c), diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index e11c78048..5e2051b50 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -34,8 +34,8 @@ namespace pb { class card2bv_rewriter { public: - typedef expr* literal; - typedef ptr_vector literal_vector; + typedef expr* pliteral; + typedef ptr_vector pliteral_vector; private: ast_manager& m; arith_util au; @@ -54,7 +54,7 @@ namespace pb { bool is_and(func_decl* f); bool is_atmost1(func_decl* f, unsigned sz, expr * const* args, expr_ref& result); expr_ref mk_atmost1(unsigned sz, expr * const* args); - void mk_at_most_1_small(bool last, unsigned n, literal const* xs, expr_ref_vector& result, expr_ref_vector& ors); + void mk_at_most_1_small(bool last, unsigned n, pliteral const* xs, expr_ref_vector& result, expr_ref_vector& ors); public: card2bv_rewriter(ast_manager& m); @@ -62,15 +62,15 @@ namespace pb { void mk_assert(func_decl * f, unsigned sz, expr * const* args, expr_ref & result, expr_ref_vector& lemmas); // definitions used for sorting network - literal mk_false() { return m.mk_false(); } - literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } - literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } - std::ostream& pp(std::ostream& out, literal lit); - literal fresh(); - literal trail(literal l); - void mk_clause(unsigned n, literal const* lits); + 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_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); + pliteral fresh(); + pliteral trail(pliteral l); + void mk_clause(unsigned n, pliteral const* lits); }; diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index e3bf2d653..f5c415c04 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -152,30 +152,30 @@ struct ast_ext2 { expr_ref_vector m_clauses; expr_ref_vector m_trail; ast_ext2(ast_manager& m):m(m), m_clauses(m), m_trail(m) {} - typedef expr* literal; - typedef ptr_vector literal_vector; + typedef expr* pliteral; + typedef ptr_vector pliteral_vector; expr* trail(expr* e) { m_trail.push_back(e); return e; } - literal mk_false() { return m.mk_false(); } - literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { + 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)); } - literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; + 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)); } - std::ostream& pp(std::ostream& out, literal lit) { + std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_pp(lit, m); } - literal fresh(char const* n) { + pliteral fresh(char const* n) { return trail(m.mk_fresh_const(n, m.mk_bool_sort())); } - void mk_clause(unsigned n, literal const* lits) { + void mk_clause(unsigned n, pliteral const* lits) { m_clauses.push_back(mk_or(m, n, lits)); } }; diff --git a/src/util/lp/cut_solver.h b/src/util/lp/cut_solver.h deleted file mode 100644 index 18da0b88b..000000000 --- a/src/util/lp/cut_solver.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Nikolaj Bjorner, Lev Nachmanson -*/ -#pragma once -#include "util/vector.h" -#include "util/trace.h" -#include "util/lp/lp_settings.h" -namespace lp { -template -class cut_solver { - - struct ineq { // we only have less or equal, which is enough for integral variables - mpq m_bound; - vector> m_term; - ineq(vector>& term, mpq bound):m_bound(bound),m_term(term) { - } - }; - - vector m_ineqs; - - enum class lbool { - l_false, // false - l_true, // true - l_undef // undef - }; - - enum class literal_type { - BOOL, - INEQ, - BOUND - }; - - struct literal { - literal_type m_tag; - bool m_sign; // true means the pointed inequality is negated, or bound is negated, or boolean value is negated - - unsigned m_id; - unsigned m_index_of_ineq; // index into m_ineqs - bool m_bool_val; // used if m_tag is equal to BOOL - mpq m_bound; // used if m_tag is BOUND - literal(bool sign, bool val): m_tag(literal_type::BOOL), - m_bool_val(val){ - } - literal(bool sign, unsigned index_of_ineq) : m_tag(literal_type::INEQ), m_index_of_ineq(index_of_ineq) {} - }; - - bool lhs_is_int(const vector> & lhs) const { - for (auto & p : lhs) - if (p.first.is_int() == false) return false; - return true; - } - - public: - void add_ineq(vector> & lhs, mpq rhs) { - lp_assert(lhs_is_int(lhs)); - lp_assert(rhs.is_int()); - m_ineqs.push_back(ineq(lhs, rhs)); - } - - - bool m_inconsistent; // tracks if state is consistent - unsigned m_scope_lvl; // tracks the number of case splits - - svector m_trail; - // backtracking state from the SAT solver: - struct scope { - unsigned m_trail_lim; // pointer into assignment stack - unsigned m_clauses_to_reinit_lim; // ignore for now - bool m_inconsistent; // really needed? - }; - - svector m_scopes; - - bool at_base_lvl() const { return m_scope_lvl == 0; } - - lbool check() { - init_search(); - propagate(); - while (true) { - lbool r = bounded_search(); - if (r != lbool::l_undef) - return r; - - restart(); - simplify_problem(); - if (check_inconsistent()) return lbool::l_false; - gc(); - } - } - - cut_solver() { - } - - void init_search() { - // TBD - // initialize data-structures - } - - void simplify_problem() { - // no-op - } - - void gc() { - // no-op - } - - void restart() { - // no-op for now - } - - bool check_inconsistent() { - // TBD - return false; - } - - lbool bounded_search() { - while (true) { - checkpoint(); - bool done = false; - while (!done) { - lbool is_sat = propagate_and_backjump_step(done); - if (is_sat != lbool::l_true) return is_sat; - } - - gc(); - - if (!decide()) { - lbool is_sat = final_check(); - if (is_sat != lbool::l_undef) { - return is_sat; - } - } - } - } - - void checkpoint() { - // check for cancelation - } - - void cleanup() { - } - - lbool propagate_and_backjump_step(bool& done) { - done = true; - propagate(); - if (!inconsistent()) - return lbool::l_true; - if (!resolve_conflict()) - return lbool::l_false; - if (at_base_lvl()) { - cleanup(); // cleaner may propagate frozen clauses - if (inconsistent()) { - TRACE("sat", tout << "conflict at level 0\n";); - return lbool::l_false; - } - gc(); - } - done = false; - return lbool::l_true; - } - - lbool final_check() { - // there are no more case splits, and all clauses are satisfied. - // prepare the model for external consumption. - return lbool::l_true; - } - - - bool resolve_conflict() { - while (true) { - bool r = resolve_conflict_core(); - // after pop, clauses are reinitialized, - // this may trigger another conflict. - if (!r) - return false; - if (!inconsistent()) - return true; - } - } - - bool resolve_conflict_core() { - // this is where the main action is. - return true; - } - - void propagate() { - // this is where the main action is. - } - - bool decide() { - // this is where the main action is. - // pick the next variable and bound or value on the variable. - // return false if all variables have been assigned. - return false; - } - - bool inconsistent() const { return m_inconsistent; } - -}; -} diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h deleted file mode 100644 index 56ddf16fd..000000000 --- a/src/util/lp/int_solver.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -#pragma once -#include "util/lp/lp_settings.h" -#include "util/lp/static_matrix.h" -#include "util/lp/iterator_on_row.h" -#include "util/lp/int_set.h" -#include "util/lp/lar_term.h" -#include "util/lp/cut_solver.h" -#include "util/lp/lar_constraints.h" - -namespace lp { -class lar_solver; -template -struct lp_constraint; -enum class lia_move { - ok, - branch, - cut, - conflict, - continue_with_check, - give_up -}; - -struct explanation { - vector> m_explanation; - void push_justification(constraint_index j, const mpq& v) { - m_explanation.push_back(std::make_pair(v, j)); - } -}; - -class int_solver { -public: - // fields - lar_solver *m_lar_solver; - int_set m_old_values_set; - vector m_old_values_data; - unsigned m_branch_cut_counter; - - // methods - int_solver(lar_solver* lp); - int_set& inf_int_set(); - const int_set& inf_int_set() const; - // main function to check that 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 move_non_basic_column_to_bounds(unsigned j); - lia_move check_wrapper(lar_term& t, mpq& k, explanation& ex); -private: - - // how to tighten bounds for integer variables. - - bool gcd_test_for_row(static_matrix> & A, unsigned i, explanation &); - - // gcd test - // 5*x + 3*y + 6*z = 5 - // suppose x is fixed at 2. - // so we have 10 + 3(y + 2z) = 5 - // 5 = -3(y + 2z) - // this is unsolvable because 5/3 is not an integer. - // so we create a lemma that rules out this condition. - // - bool gcd_test(explanation & ); // returns false in case of failure. Creates a theory lemma in case of failure. - - // create goromy cuts - // either creates a conflict or a bound. - - // branch and bound: - // decide what to branch and bound on - // creates a fresh inequality. - - bool branch(const lp_constraint & new_inequality); - bool ext_gcd_test(iterator_on_row & it, - mpq const & least_coeff, - mpq const & lcm_den, - mpq const & consts, - explanation & ex); - void fill_explanation_from_fixed_columns(iterator_on_row & it, explanation &); - void add_to_explanation_from_fixed_or_boxed_column(unsigned j, explanation &); - void patch_int_infeasible_non_basic_column(unsigned j); - void patch_int_infeasible_nbasic_columns(); - bool get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m); - linear_combination_iterator * get_column_iterator(unsigned j); - const impq & low_bound(unsigned j) const; - const impq & upper_bound(unsigned j) const; - bool is_int(unsigned j) const; - bool is_real(unsigned j) const; - bool is_base(unsigned j) const; - bool is_boxed(unsigned j) const; - bool is_fixed(unsigned j) const; - bool is_free(unsigned j) const; - bool value_is_int(unsigned j) const; - void set_value_for_nbasic_column(unsigned j, const impq & new_val); - void set_value_for_nbasic_column_ignore_old_values(unsigned j, const impq & new_val); - bool non_basic_columns_are_at_bounds() const; - void failed(); - bool is_feasible() const; - const impq & get_value(unsigned j) const; - void display_column(std::ostream & out, unsigned j) const; - bool inf_int_set_is_correct() const; - void update_column_in_int_inf_set(unsigned j); - bool column_is_int_inf(unsigned j) const; - void trace_inf_rows() const; - int find_inf_int_base_column(); - int find_inf_int_boxed_base_column_with_smallest_range(); - lp_settings& settings(); - bool move_non_basic_columns_to_bounds(); - void branch_infeasible_int_var(unsigned); - lia_move mk_gomory_cut(lar_term& t, mpq& k,explanation & ex, unsigned inf_col, linear_combination_iterator& iter); - lia_move report_conflict_from_gomory_cut(mpq & k); - void adjust_term_and_k_for_some_ints_case_gomory(lar_term& t, mpq& k, mpq& lcm_den); - void init_check_data(); - bool constrain_free_vars(linear_combination_iterator * r); - lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex, unsigned j); - int find_free_var_in_gomory_row(linear_combination_iterator& iter); - bool is_gomory_cut_target(linear_combination_iterator &iter); - bool at_bound(unsigned j) const; - bool at_low(unsigned j) const; - bool at_upper(unsigned j) const; - bool has_low(unsigned j) const; - bool has_upper(unsigned j) const; - unsigned row_of_basic_column(unsigned j) const; - inline static bool is_rational(const impq & n) { - return is_zero(n.y); - } - - inline static - mpq fractional_part(const impq & n) { - lp_assert(is_rational(n)); - return n.x - floor(n.x); - } - void real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation & ex, unsigned inf_column); - void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation& ex, mpq & lcm_den, unsigned inf_column); - constraint_index column_upper_bound_constraint(unsigned j) const; - constraint_index column_low_bound_constraint(unsigned j) const; - void display_row_info(std::ostream & out, unsigned row_index) const; - void gomory_cut_adjust_t_and_k(vector> & pol, lar_term & t, mpq &k, bool num_ints, mpq &lcm_den); - bool current_solution_is_inf_on_cut(const lar_term& t, const mpq& k) const; -public: - bool shift_var(unsigned j, unsigned range); -private: - unsigned random(); - bool has_inf_int() const; - lia_move create_branch_on_column(int j, lar_term& t, mpq& k, bool free_column) const; -public: - void display_inf_or_int_inf_columns(std::ostream & out) const; - template - void fill_cut_solver(cut_solver & cs); - template - void fill_cut_solver_for_constraint(const lar_base_constraint*, cut_solver& ); - template - void get_int_coeffs_from_constraint(const lar_base_constraint* c, vector>& coeff, T & rs); - -}; -} diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 38c595125..f2906b00c 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -141,8 +141,8 @@ Notes: // Described in Abio et.al. CP 2013. template class psort_nw { - typedef typename psort_expr::literal literal; - typedef typename psort_expr::literal_vector literal_vector; + typedef typename psort_expr::pliteral literal; + typedef typename psort_expr::pliteral_vector literal_vector; sorting_network_config m_cfg; class vc { From f5775f265a3414972161fb86eefd2913c65cbf21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 09:21:33 -0700 Subject: [PATCH 0880/1283] fix python build script dependencies Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 6 +- src/solver/parallel_tactic.cpp | 5 - src/tactic/arith/elim01_tactic.cpp | 267 ----------------------------- 3 files changed, 3 insertions(+), 275 deletions(-) delete mode 100644 src/tactic/arith/elim01_tactic.cpp diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 0590a8693..b03ced763 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -32,13 +32,13 @@ def init_project_def(): add_lib('grobner', ['ast'], 'math/grobner') add_lib('euclid', ['util'], 'math/euclid') add_lib('core_tactics', ['tactic', 'macros', 'normal_forms', 'rewriter'], 'tactic/core') - add_lib('sat_tactic', ['tactic', 'sat'], 'sat/tactic') + add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') + add_lib('solver', ['model', 'tactic', 'proofs']) + add_lib('sat_tactic', ['tactic', 'sat', 'solver'], 'sat/tactic') add_lib('arith_tactics', ['core_tactics', 'sat'], 'tactic/arith') add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('aig_tactic', ['tactic'], 'tactic/aig') - add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') - add_lib('solver', ['model', 'tactic', 'proofs']) add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') add_lib('interp', ['solver']) add_lib('cmd_context', ['solver', 'rewriter', 'interp']) diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index fb1001f32..451a62064 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -39,13 +39,8 @@ Notes: #include "solver/solver2tactic.h" #include "tactic/tactic.h" #include "tactic/tactical.h" -#include "tactic/portfolio/fd_solver.h" #include "solver/parallel_tactic.h" #include "solver/parallel_params.hpp" -#include "smt/tactic/smt_tactic.h" -#include "smt/smt_solver.h" -#include "sat/sat_solver/inc_sat_solver.h" -#include "sat/tactic/sat_tactic.h" class parallel_tactic : public tactic { diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp deleted file mode 100644 index 46c6f1e1c..000000000 --- a/src/tactic/arith/elim01_tactic.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - elim01_tactic.cpp - -Abstract: - - Replace 0-1 integer variables by Booleans. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-12-7 - -Notes: - ---*/ -#include "tactic/tactical.h" -#include "util/cooperate.h" -#include "tactic/arith/bound_manager.h" -#include "ast/ast_pp.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/arith_decl_plugin.h" -#include "tactic/arith/elim01_tactic.h" -#include "model/model_smt2_pp.h" -#include "ast/rewriter/th_rewriter.h" - -class bool2int_model_converter : public model_converter { - ast_manager& m; - arith_util a; - func_decl_ref_vector m_refs; - obj_hashtable m_bools; - vector > m_nums_as_bool; - ptr_vector m_nums_as_int; -public: - - bool2int_model_converter(ast_manager& m): - m(m), - a(m), - m_refs(m) - {} - - void operator()(model_ref & old_model, unsigned goal_idx) override { - SASSERT(goal_idx == 0); - model * new_model = alloc(model, m); - unsigned num = old_model->get_num_constants(); - for (unsigned i = 0; i < m_nums_as_int.size(); ++i) { - func_decl* f_old = m_nums_as_int[i]; - rational val(0); - rational po(1); - bool is_value = true; - for (unsigned j = 0; is_value && j < m_nums_as_bool[i].size(); ++j) { - func_decl* f = m_nums_as_bool[i][j]; - expr* fi = old_model->get_const_interp(f); - if (!fi) { - is_value = false; - } - else if (m.is_true(fi)) { - val += po; - } - else if (!m.is_false(fi)) { - is_value = false; - } - po *= rational(2); - } - if (is_value) { - expr* fi = a.mk_numeral(val, true); - new_model->register_decl(f_old, fi); - } - } - for (unsigned i = 0; i < num; ++i) { - func_decl* f = old_model->get_constant(i); - expr* fi = old_model->get_const_interp(f); - if (!m_bools.contains(f)) { - new_model->register_decl(f, fi); - } - } - num = old_model->get_num_functions(); - for (unsigned i = 0; i < num; i++) { - func_decl * f = old_model->get_function(i); - func_interp * fi = old_model->get_func_interp(f); - new_model->register_decl(f, fi->copy()); - } - new_model->copy_usort_interps(*old_model); - old_model = new_model; - } - - void insert(func_decl* x_new, func_decl* x_old) { - m_refs.push_back(x_new); - m_refs.push_back(x_old); - m_bools.insert(x_new); - m_nums_as_int.push_back(x_old); - m_nums_as_bool.push_back(ptr_vector()); - m_nums_as_bool.back().push_back(x_new); - } - - void insert(func_decl* x_old, unsigned sz, func_decl * const* x_new) { - m_nums_as_int.push_back(x_old); - m_nums_as_bool.push_back(ptr_vector()); - m_refs.push_back(x_old); - for (unsigned i = 0; i < sz; ++i) { - m_refs.push_back(x_new[i]); - m_nums_as_bool.back().push_back(x_new[i]); - m_bools.insert(x_new[i]); - } - } - - model_converter * translate(ast_translation & translator) override { - bool2int_model_converter* mc = alloc(bool2int_model_converter, translator.to()); - for (unsigned i = 0; i < m_nums_as_int.size(); ++i) { - mc->insert(m_nums_as_int[i], m_nums_as_bool[i].size(), m_nums_as_bool[i].c_ptr()); - } - return mc; - } -}; - - -class elim01_tactic : public tactic { -public: - typedef obj_hashtable expr_set; - ast_manager & m; - arith_util a; - th_rewriter m_rewriter; - params_ref m_params; - unsigned m_max_hi_default; - rational m_max_hi; - - elim01_tactic(ast_manager & _m, params_ref const & p): - m(_m), - a(m), - m_rewriter(m), - m_max_hi_default(8), - m_max_hi(rational(m_max_hi_default)) { - } - - ~elim01_tactic() override { - } - - void updt_params(params_ref const & p) override { - m_max_hi = rational(p.get_uint("max_coefficient", m_max_hi_default)); - m_params = p; - } - - void collect_param_descrs(param_descrs & r) override { - r.insert("max_coefficient", CPK_UINT, "(default: 1) maximal upper bound for finite range -> Bool conversion"); - } - - - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) override { - SASSERT(g->is_well_sorted()); - mc = nullptr; pc = nullptr; core = nullptr; - - tactic_report report("elim01", *g); - - expr_safe_replace sub(m); - bool2int_model_converter* b2i = alloc(bool2int_model_converter, m); - mc = b2i; - bound_manager bounds(m); - expr_ref_vector axioms(m); - bounds(*g); - - rational zero(0); - bound_manager::iterator bit = bounds.begin(), bend = bounds.end(); - for (; bit != bend; ++bit) { - if (!is_app(*bit)) continue; - app* x = to_app(*bit); - bool s1 = false, s2 = false; - rational lo, hi; - if (a.is_int(x) && - bounds.has_lower(x, lo, s1) && !s1 && zero <= lo && - bounds.has_upper(x, hi, s2) && !s2 && hi <= m_max_hi && lo <= hi) { - add_variable(b2i, sub, x, lo.get_unsigned(), hi.get_unsigned(), axioms); - } - else if (a.is_int(x)) { - TRACE("pb", tout << "Not adding variable " << mk_pp(x, m) << " has lower: " - << bounds.has_lower(x, lo, s1) << " " << lo << " has upper: " - << bounds.has_upper(x, hi, s2) << " " << hi << "\n";); - } - } - - if (sub.empty()) { - result.push_back(g.get()); - return; - } - - expr_ref new_curr(m), tmp_curr(m); - proof_ref new_pr(m); - for (unsigned i = 0; i < g->size(); i++) { - expr * curr = g->form(i); - sub(curr, tmp_curr); - m_rewriter(tmp_curr, new_curr); - if (m.proofs_enabled()) { - new_pr = m.mk_rewrite(curr, new_curr); - new_pr = m.mk_modus_ponens(g->pr(i), new_pr); - } - g->update(i, new_curr, new_pr, g->dep(i)); - } - for (unsigned i = 0; i < axioms.size(); ++i) { - g->assert_expr(axioms[i].get()); - } - g->inc_depth(); - result.push_back(g.get()); - TRACE("pb", g->display(tout);); - SASSERT(g->is_well_sorted()); - - // TBD: support proof conversion (or not..) - } - - tactic * translate(ast_manager & m) override { - return alloc(elim01_tactic, m, m_params); - } - - void cleanup() override {} - - void add_variable(bool2int_model_converter* b2i, - expr_safe_replace& sub, - app* x, - unsigned min_value, - unsigned max_value, - expr_ref_vector& axioms) { - std::string name = x->get_decl()->get_name().str(); - unsigned sh = 0; - app_ref_vector xs(m), ites(m); - func_decl_ref_vector xfs(m); - app_ref zero(m), sum(m); - zero = a.mk_numeral(rational(0), true); - while (max_value >= (1ul << sh)) { - xs.push_back(m.mk_fresh_const(name.c_str(), m.mk_bool_sort())); - xfs.push_back(xs.back()->get_decl()); - ites.push_back(m.mk_ite(xs.back(), a.mk_numeral(rational(1 << sh), true), zero)); - ++sh; - } - switch (ites.size()) { - case 0: - sum = zero; - break; - case 1: - sum = ites[0].get(); - break; - default: - sum = a.mk_add(ites.size(), (expr*const*)ites.c_ptr()); - break; - } - TRACE("pb", tout << mk_pp(x, m) << " " << sum << " max: " << max_value << "\n";); - - sub.insert(x, sum); - b2i->insert(x->get_decl(), xfs.size(), xfs.c_ptr()); - // if max_value+1 is not a power of two: - if ((max_value & (max_value + 1)) != 0) { - axioms.push_back(a.mk_le(sum, a.mk_numeral(rational(max_value), true))); - } - if (min_value > 0) { - axioms.push_back(a.mk_ge(sum, a.mk_numeral(rational(min_value), true))); - } - } - -}; - -tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(elim01_tactic, m, p)); -} - From 510cb5ee6e9e8e7120b2112707e0ad3535e2f896 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 23 May 2018 23:51:36 +0700 Subject: [PATCH 0881/1283] Z3_TRUE/Z3_FALSE should be true/false, not 1/0. Now that Z3_bool is a C bool, the associated constants should be as well. --- src/api/z3_api.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 0825f27a0..d5c279d63 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -83,14 +83,14 @@ typedef const char * Z3_string; typedef Z3_string * Z3_string_ptr; /** - \brief True value. It is just an alias for \c 1. + \brief True value. It is just an alias for \c true. */ -#define Z3_TRUE 1 +#define Z3_TRUE true /** - \brief False value. It is just an alias for \c 0. + \brief False value. It is just an alias for \c false. */ -#define Z3_FALSE 0 +#define Z3_FALSE false /** \brief Lifted Boolean type: \c false, \c undefined, \c true. From a3facc82fb61888557980b392431e298c9add8e3 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 23 May 2018 23:52:51 +0700 Subject: [PATCH 0882/1283] Update OCaml docs for changes made elsewhere. This removes references to the PROOF_MODE that have been removed elsewhere. --- src/api/ml/z3.mli | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 14d2ceac4..0fd1242ee 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2362,7 +2362,7 @@ sig (** Indicates whether the term is a proof by condensed transitivity of a relation - Condensed transitivity proof. This proof object is only used if the parameter PROOF_MODE is 1. + Condensed transitivity proof. It combines several symmetry and transitivity proofs. Example: T1: (R a b) @@ -2443,14 +2443,11 @@ sig (** Indicates whether the term is a proof by rewriting A proof for rewriting an expression t into an expression s. - This proof object is used if the parameter PROOF_MODE is 1. This proof object can have n antecedents. The antecedents are proofs for equalities used as substitution rules. - The object is also used in a few cases if the parameter PROOF_MODE is 2. - The cases are: + The object is also used in a few cases. The cases are: - When applying contextual simplification (CONTEXT_SIMPLIFIER=true) - When converting bit-vectors to Booleans (BIT2BOOL=true) - - When pulling ite expression up (PULL_CHEAP_ITE_TREES=true) *) val is_rewrite_star : Expr.expr -> bool (** Indicates whether the term is a proof for pulling quantifiers out. From 6db90a9333c0e44fca53cfb4d463c1a5189de6cb Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 23 May 2018 23:58:08 +0700 Subject: [PATCH 0883/1283] Fix missing word in C++ API docs. --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8d7825335..eef5d7904 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -187,7 +187,7 @@ namespace z3 { \brief The C++ API uses by defaults exceptions on errors. For applications that don't work well with exceptions (there should be only few) you have the ability to turn off exceptions. The tradeoffs are that applications - have to very careful about using check_error() after calls that may result in an + have to be very careful about using check_error() after calls that may result in an erroneous state. */ void set_enable_exceptions(bool f) { m_enable_exceptions = f; } From f9bdfe297853f3a318bbbd9e8485cf2759204afd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 10:30:14 -0700 Subject: [PATCH 0884/1283] fix x86 warning Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 70378d9c6..3cbd3015b 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -111,18 +111,22 @@ namespace sat { clause_offset clause::get_new_offset() const { unsigned o1 = m_lits[0].index(); +#if defined(_AMD64_) || defined(_M_IA64) if (sizeof(clause_offset) == 8) { unsigned o2 = m_lits[1].index(); return (clause_offset)o1 + (((clause_offset)o2) << 32); } +#endif return (clause_offset)o1; } void clause::set_new_offset(clause_offset offset) { m_lits[0] = to_literal(static_cast(offset)); +#if defined(_AMD64_) || defined(_M_IA64) if (sizeof(offset) == 8) { m_lits[1] = to_literal(static_cast(offset >> 32)); } +#endif } From 278fd03f196db4972352aa8f26c0f98077872888 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 13:31:26 -0700 Subject: [PATCH 0885/1283] GLU -> GNU fix #1643 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2c05cc52c..15d941b5b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -800,7 +800,7 @@ namespace sat { } if (m_config.m_propagate_prefetch) { -#if defined(__GLUC__) || defined(__clang__) +#if defined(__GNUC__) || defined(__clang__) __builtin_prefetch((const char*)((m_watches[l.index()].c_ptr()))); #else _mm_prefetch((const char*)((m_watches[l.index()].c_ptr())), _MM_HINT_T1); From 2e4fb8d356005a41a93a75707e47fa4c38106566 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 16:33:27 -0700 Subject: [PATCH 0886/1283] work around VS2012 compiler bug Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 15d941b5b..a59dd2b46 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3241,9 +3241,10 @@ namespace sat { bool_var solver::max_var(clause_vector& clauses, bool_var v) { for (clause* cp : clauses) - for (literal l : *cp) - if (l.var() > v) - v = l.var(); + for (auto it = cp->begin(), end = cp->end(); it != end; ++it) { + if (it->var() > v) + v = it->var(); + } return v; } From d088a1b9f6697d9663fe3ee3afad7a8bad06875e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 18:25:14 -0700 Subject: [PATCH 0887/1283] updated release notes for merge Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 31 +++++++++++++++++++++++++++++++ src/util/lp/bound_propagator.h | 27 --------------------------- 2 files changed, 31 insertions(+), 27 deletions(-) delete mode 100644 src/util/lp/bound_propagator.h diff --git a/RELEASE_NOTES b/RELEASE_NOTES index a99ec6b1e..67aa3d810 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,36 @@ RELEASE NOTES +Version 4.8.0 +============= + +- New requirements: + - A breaking change to the API is that parsers for SMT-LIB2 formulas return a vector of + formulas as opposed to a conjunction of formulas. The vector of formulas correspond to + the set of "assert" instructions in the SMT-LIB input. + +- New features + - A parallel mode is available for select theories, including QF_BV. + By setting parallel.enable=true Z3 will spawn a number of worker threads proportional to the + number of available CPU cores to apply cube and conquer solving on the goal. + - The SAT solver by default handle cardinality and PB constraints using a custom plugin + that operates directly on cardinality and PB constraints. + - A "cube" interface is exposed over the solver API. + - Model conversion is first class over the textual API, such that subgoals created from running a + solver can be passed in text files and a model for the original formula can be recreated from the result. + - This has also led to changes in how models are tracked over tactic subgoals. The API for + extracting models from apply_result have been replaced. + - An optional mode handles xor constraints using a custom xor propagator. + It is off by default and its value not demonstrated. + - The SAT solver includes new inprocessing technques that are available during simplification. + It performs asymmetric tautology elimination by default, and one can turn on more powerful inprocessing techniques + (known as ACCE, ABCE, CCE). Asymmetric branching also uses features introduced in Lingeling by exploiting binary implication graphs. + Use sat.acce=true to enable the full repertoire of inprocessing methods. By default, clauses that are "eliminated" by acce are tagged + as lemmas (redundant) and are garbage collected if their glue level is high. + +- Removed features: + - long deprecated API functions have been removed from z3_api.h + + Version 4.7.1 ============= diff --git a/src/util/lp/bound_propagator.h b/src/util/lp/bound_propagator.h deleted file mode 100644 index 128973c12..000000000 --- a/src/util/lp/bound_propagator.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -#pragma once -#include "util/lp/lp_settings.h" -namespace lp { -class lar_solver; -class bound_propagator { - std::unordered_map m_improved_low_bounds; // these maps map a column index to the corresponding index in ibounds - std::unordered_map m_improved_upper_bounds; - lar_solver & m_lar_solver; -public: - vector m_ibounds; -public: - bound_propagator(lar_solver & ls); - column_type get_column_type(unsigned) const; - const impq & get_low_bound(unsigned) const; - const impq & get_upper_bound(unsigned) const; - void try_add_bound(mpq v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict); - virtual bool bound_is_interesting(unsigned vi, - lp::lconstraint_kind kind, - const rational & bval) {return true;} - unsigned number_of_found_bounds() const { return m_ibounds.size(); } - virtual void consume(mpq const& v, unsigned j) { std::cout << "doh\n"; } -}; -} From 4f5775c531dff15dd5ecfca02651766b29c8c04f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 08:33:19 -0700 Subject: [PATCH 0888/1283] remove interpolation and duality dependencies Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 2 +- src/CMakeLists.txt | 5 - src/api/CMakeLists.txt | 2 - src/api/api_ast.cpp | 2 - src/api/dotnet/CMakeLists.txt | 1 - src/api/dotnet/InterpolationContext.cs | 161 - src/api/java/CMakeLists.txt | 1 - src/api/java/InterpolationContext.java | 210 -- src/api/z3.h | 1 - src/api/z3_api.h | 3 - src/api/z3_interp.h | 283 -- src/ast/ast.cpp | 7 - src/ast/ast.h | 4 +- src/cmd_context/CMakeLists.txt | 2 - src/cmd_context/cmd_context.cpp | 2 - src/cmd_context/interpolant_cmds.cpp | 263 -- src/cmd_context/interpolant_cmds.h | 24 - src/duality/CMakeLists.txt | 11 - src/duality/duality.h | 1365 ------- src/duality/duality_profiling.cpp | 144 - src/duality/duality_profiling.h | 38 - src/duality/duality_rpfp.cpp | 4250 ---------------------- src/duality/duality_solver.cpp | 3601 ------------------ src/duality/duality_wrapper.cpp | 744 ---- src/duality/duality_wrapper.h | 1489 -------- src/interp/CMakeLists.txt | 18 - src/interp/interp_params.pyg | 6 - src/interp/iz3base.cpp | 372 -- src/interp/iz3base.h | 195 - src/interp/iz3checker.cpp | 227 -- src/interp/iz3checker.h | 49 - src/interp/iz3exception.h | 28 - src/interp/iz3hash.h | 479 --- src/interp/iz3interp.cpp | 578 --- src/interp/iz3interp.h | 123 - src/interp/iz3mgr.cpp | 969 ----- src/interp/iz3mgr.h | 738 ---- src/interp/iz3pp.cpp | 185 - src/interp/iz3pp.h | 36 - src/interp/iz3profiling.cpp | 153 - src/interp/iz3profiling.h | 37 - src/interp/iz3proof.cpp | 628 ---- src/interp/iz3proof.h | 274 -- src/interp/iz3proof_itp.cpp | 3117 ---------------- src/interp/iz3proof_itp.h | 143 - src/interp/iz3scopes.cpp | 321 -- src/interp/iz3scopes.h | 222 -- src/interp/iz3secondary.h | 40 - src/interp/iz3translate.cpp | 2200 ----------- src/interp/iz3translate.h | 63 - src/interp/iz3translate_direct.cpp | 1717 --------- src/muz/base/dl_context.cpp | 15 +- src/muz/base/dl_engine_base.h | 1 - src/muz/duality/CMakeLists.txt | 8 - src/muz/duality/duality_dl_interface.cpp | 623 ---- src/muz/duality/duality_dl_interface.h | 80 - src/muz/fp/CMakeLists.txt | 1 - src/muz/fp/dl_register_engine.cpp | 3 - src/smt/smt_internalizer.cpp | 1 - 59 files changed, 3 insertions(+), 26262 deletions(-) delete mode 100644 src/api/dotnet/InterpolationContext.cs delete mode 100644 src/api/java/InterpolationContext.java delete mode 100644 src/api/z3_interp.h delete mode 100644 src/cmd_context/interpolant_cmds.cpp delete mode 100644 src/cmd_context/interpolant_cmds.h delete mode 100644 src/duality/CMakeLists.txt delete mode 100644 src/duality/duality.h delete mode 100644 src/duality/duality_profiling.cpp delete mode 100755 src/duality/duality_profiling.h delete mode 100644 src/duality/duality_rpfp.cpp delete mode 100644 src/duality/duality_solver.cpp delete mode 100644 src/duality/duality_wrapper.cpp delete mode 100644 src/duality/duality_wrapper.h delete mode 100644 src/interp/CMakeLists.txt delete mode 100644 src/interp/interp_params.pyg delete mode 100644 src/interp/iz3base.cpp delete mode 100755 src/interp/iz3base.h delete mode 100644 src/interp/iz3checker.cpp delete mode 100644 src/interp/iz3checker.h delete mode 100644 src/interp/iz3exception.h delete mode 100644 src/interp/iz3hash.h delete mode 100644 src/interp/iz3interp.cpp delete mode 100644 src/interp/iz3interp.h delete mode 100644 src/interp/iz3mgr.cpp delete mode 100644 src/interp/iz3mgr.h delete mode 100644 src/interp/iz3pp.cpp delete mode 100644 src/interp/iz3pp.h delete mode 100644 src/interp/iz3profiling.cpp delete mode 100755 src/interp/iz3profiling.h delete mode 100755 src/interp/iz3proof.cpp delete mode 100644 src/interp/iz3proof.h delete mode 100755 src/interp/iz3proof_itp.cpp delete mode 100644 src/interp/iz3proof_itp.h delete mode 100755 src/interp/iz3scopes.cpp delete mode 100755 src/interp/iz3scopes.h delete mode 100755 src/interp/iz3secondary.h delete mode 100644 src/interp/iz3translate.cpp delete mode 100755 src/interp/iz3translate.h delete mode 100644 src/interp/iz3translate_direct.cpp delete mode 100644 src/muz/duality/CMakeLists.txt delete mode 100644 src/muz/duality/duality_dl_interface.cpp delete mode 100644 src/muz/duality/duality_dl_interface.h diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 67aa3d810..a2b526550 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -35,7 +35,7 @@ Version 4.7.1 ============= - New requirements: - - uses stdbool and stdint as part of z3.h + - uses stdbool and stdint as part of z3. - New features: - none diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d8a773747..9020c9e4b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,7 +12,6 @@ set(Z3_API_HEADER_FILES_TO_SCAN z3_rcf.h z3_fixedpoint.h z3_optimization.h - z3_interp.h z3_fpa.h z3_spacer.h ) @@ -63,7 +62,6 @@ add_subdirectory(sat/tactic) add_subdirectory(tactic/arith) add_subdirectory(nlsat/tactic) add_subdirectory(ackermannization) -add_subdirectory(interp) add_subdirectory(cmd_context) add_subdirectory(cmd_context/extra_cmds) add_subdirectory(parsers/smt2) @@ -79,7 +77,6 @@ add_subdirectory(tactic/bv) add_subdirectory(smt/tactic) add_subdirectory(tactic/sls) add_subdirectory(qe) -add_subdirectory(duality) add_subdirectory(muz/base) add_subdirectory(muz/dataflow) add_subdirectory(muz/transforms) @@ -89,7 +86,6 @@ add_subdirectory(muz/clp) add_subdirectory(muz/tab) add_subdirectory(muz/bmc) add_subdirectory(muz/ddnf) -add_subdirectory(muz/duality) add_subdirectory(muz/spacer) add_subdirectory(muz/fp) add_subdirectory(tactic/ufbv) @@ -159,7 +155,6 @@ set (libz3_public_headers z3_fpa.h z3.h c++/z3++.h - z3_interp.h z3_macros.h z3_optimization.h z3_polynomial.h diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index fcdbb1651..4a5514a7b 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -48,7 +48,6 @@ z3_add_component(api api_datatype.cpp api_fpa.cpp api_goal.cpp - api_interp.cpp api_log.cpp api_model.cpp api_numeral.cpp @@ -67,7 +66,6 @@ z3_add_component(api z3_replayer.cpp ${full_path_generated_files} COMPONENT_DEPENDENCIES - interp opt portfolio realclosure diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 1f4a86903..536b94fb2 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -195,7 +195,6 @@ extern "C" { MK_BINARY(Z3_mk_xor, mk_c(c)->get_basic_fid(), OP_XOR, SKIP); MK_NARY(Z3_mk_and, mk_c(c)->get_basic_fid(), OP_AND, SKIP); MK_NARY(Z3_mk_or, mk_c(c)->get_basic_fid(), OP_OR, SKIP); - MK_UNARY(Z3_mk_interpolant, mk_c(c)->get_basic_fid(), OP_INTERP, SKIP); Z3_ast mk_ite_core(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_ast t3) { expr * result = mk_c(c)->m().mk_ite(to_expr(t1), to_expr(t2), to_expr(t3)); @@ -900,7 +899,6 @@ extern "C" { case OP_NOT: return Z3_OP_NOT; case OP_IMPLIES: return Z3_OP_IMPLIES; case OP_OEQ: return Z3_OP_OEQ; - case OP_INTERP: return Z3_OP_INTERP; case PR_UNDEF: return Z3_OP_PR_UNDEF; case PR_TRUE: return Z3_OP_PR_TRUE; diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index add1b0ded..76516bf39 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -80,7 +80,6 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE Global.cs Goal.cs IDecRefQueue.cs - InterpolationContext.cs IntExpr.cs IntNum.cs IntSort.cs diff --git a/src/api/dotnet/InterpolationContext.cs b/src/api/dotnet/InterpolationContext.cs deleted file mode 100644 index e2b814983..000000000 --- a/src/api/dotnet/InterpolationContext.cs +++ /dev/null @@ -1,161 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics.Contracts; -using System.Runtime.InteropServices; - -namespace Microsoft.Z3 -{ - /// - /// The InterpolationContext is suitable for generation of interpolants. - /// - /// For more information on interpolation please refer - /// too the C/C++ API, which is well documented. - [ContractVerification(true)] - public class InterpolationContext : Context - { - - /// - /// Constructor. - /// - public InterpolationContext() : base() { } - - /// - /// Constructor. - /// - /// - public InterpolationContext(Dictionary settings) : base(settings) { } - - #region Terms - /// - /// Create an expression that marks a formula position for interpolation. - /// - public BoolExpr MkInterpolant(BoolExpr a) - { - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - - CheckContextMatch(a); - return new BoolExpr(this, Native.Z3_mk_interpolant(nCtx, a.NativeObject)); - } - #endregion - - /// - /// Computes an interpolant. - /// - /// For more information on interpolation please refer - /// too the function Z3_get_interpolant in the C/C++ API, which is - /// well documented. - public BoolExpr[] GetInterpolant(Expr pf, Expr pat, Params p) - { - Contract.Requires(pf != null); - Contract.Requires(pat != null); - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); - - CheckContextMatch(pf); - CheckContextMatch(pat); - CheckContextMatch(p); - - ASTVector seq = new ASTVector(this, Native.Z3_get_interpolant(nCtx, pf.NativeObject, pat.NativeObject, p.NativeObject)); - return seq.ToBoolExprArray(); - } - - /// - /// Computes an interpolant. - /// - /// For more information on interpolation please refer - /// too the function Z3_compute_interpolant in the C/C++ API, which is - /// well documented. - public Z3_lbool ComputeInterpolant(Expr pat, Params p, out BoolExpr[] interp, out Model model) - { - Contract.Requires(pat != null); - Contract.Requires(p != null); - Contract.Ensures(Contract.ValueAtReturn(out interp) != null); - Contract.Ensures(Contract.ValueAtReturn(out model) != null); - - CheckContextMatch(pat); - CheckContextMatch(p); - - IntPtr i = IntPtr.Zero, m = IntPtr.Zero; - int r = Native.Z3_compute_interpolant(nCtx, pat.NativeObject, p.NativeObject, ref i, ref m); - interp = new ASTVector(this, i).ToBoolExprArray(); - model = new Model(this, m); - return (Z3_lbool)r; - } - - /// - /// Return a string summarizing cumulative time used for interpolation. - /// - /// For more information on interpolation please refer - /// too the function Z3_interpolation_profile in the C/C++ API, which is - /// well documented. - public string InterpolationProfile() - { - return Native.Z3_interpolation_profile(nCtx); - } - - /// - /// Checks the correctness of an interpolant. - /// - /// For more information on interpolation please refer - /// too the function Z3_check_interpolant in the C/C++ API, which is - /// well documented. - public int CheckInterpolant(Expr[] cnsts, uint[] parents, BoolExpr[] interps, out string error, Expr[] theory) - { - Contract.Requires(cnsts.Length == parents.Length); - Contract.Requires(cnsts.Length == interps.Length + 1); - IntPtr n_err_str; - int r = Native.Z3_check_interpolant(nCtx, - (uint)cnsts.Length, - Expr.ArrayToNative(cnsts), - parents, - Expr.ArrayToNative(interps), - out n_err_str, - (uint)theory.Length, - Expr.ArrayToNative(theory)); - error = Marshal.PtrToStringAnsi(n_err_str); - return r; - } - - /// - /// Reads an interpolation problem from a file. - /// - /// For more information on interpolation please refer - /// too the function Z3_read_interpolation_problem in the C/C++ API, which is - /// well documented. - public int ReadInterpolationProblem(string filename, out Expr[] cnsts, out uint[] parents, out string error, out Expr[] theory) - { - uint num = 0; - IntPtr n_err_str; - ASTVector _cnsts = new ASTVector(this); - ASTVector _theory = new ASTVector(this); - - int r = Native.Z3_read_interpolation_problem(nCtx, _cnsts.NativeObject, ref num, out parents, filename, out n_err_str, _theory.NativeObject); - error = Marshal.PtrToStringAnsi(n_err_str); - cnsts = _cnsts.ToExprArray(); - parents = new uint[num]; - theory = _theory.ToExprArray(); - return r; - } - - /// - /// Writes an interpolation problem to a file. - /// - /// For more information on interpolation please refer - /// too the function Z3_write_interpolation_problem in the C/C++ API, which is - /// well documented. - public void WriteInterpolationProblem(string filename, Expr[] cnsts, uint[] parents, Expr[] theory) - { - Contract.Requires(cnsts.Length == parents.Length); - Native.Z3_write_interpolation_problem(nCtx, (uint)cnsts.Length, Expr.ArrayToNative(cnsts), parents, filename, (uint)theory.Length, Expr.ArrayToNative(theory)); - } - } -} diff --git a/src/api/java/CMakeLists.txt b/src/api/java/CMakeLists.txt index dce2bc4ea..7f0774955 100644 --- a/src/api/java/CMakeLists.txt +++ b/src/api/java/CMakeLists.txt @@ -137,7 +137,6 @@ set(Z3_JAVA_JAR_SOURCE_FILES GoalDecRefQueue.java Goal.java IDecRefQueue.java - InterpolationContext.java IntExpr.java IntNum.java IntSort.java diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java deleted file mode 100644 index bce789807..000000000 --- a/src/api/java/InterpolationContext.java +++ /dev/null @@ -1,210 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - InterpolationContext.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -import com.microsoft.z3.enumerations.Z3_lbool; - -import java.util.Map; - -/** - * The InterpolationContext is suitable for generation of interpolants. - * - * Remarks: For more information on interpolation please refer - * too the C/C++ API, which is well documented. - **/ -public class InterpolationContext extends Context -{ - /** - * Constructor. - **/ - public static InterpolationContext mkContext() - { - long m_ctx; - synchronized(creation_lock) { - m_ctx = Native.mkInterpolationContext(0); - } - return new InterpolationContext(m_ctx); - } - - /** - * Constructor. - * - * - * Remarks: - * @see Context#Context - **/ - public static InterpolationContext mkContext(Map settings) - { - long m_ctx; - synchronized(creation_lock) { - long cfg = Native.mkConfig(); - for (Map.Entry kv : settings.entrySet()) - Native.setParamValue(cfg, kv.getKey(), kv.getValue()); - m_ctx = Native.mkInterpolationContext(cfg); - Native.delConfig(cfg); - } - return new InterpolationContext(m_ctx); - } - - private InterpolationContext(long m_ctx) { - super(m_ctx); - } - - /** - * Create an expression that marks a formula position for interpolation. - * @throws Z3Exception - **/ - public BoolExpr MkInterpolant(BoolExpr a) - { - checkContextMatch(a); - return new BoolExpr(this, Native.mkInterpolant(nCtx(), a.getNativeObject())); - } - - /** - * Computes an interpolant. - * Remarks: For more information on interpolation please refer - * too the function Z3_get_interpolant in the C/C++ API, which is - * well documented. - * @throws Z3Exception - **/ - public BoolExpr[] GetInterpolant(Expr pf, Expr pat, Params p) - { - checkContextMatch(pf); - checkContextMatch(pat); - checkContextMatch(p); - - ASTVector seq = new ASTVector(this, Native.getInterpolant(nCtx(), pf.getNativeObject(), pat.getNativeObject(), p.getNativeObject())); - return seq.ToBoolExprArray(); - } - - public class ComputeInterpolantResult - { - public Z3_lbool status = Z3_lbool.Z3_L_UNDEF; - public BoolExpr[] interp = null; - public Model model = null; - }; - - /** - * Computes an interpolant. - * Remarks: For more information on interpolation please refer - * too the function Z3_compute_interpolant in the C/C++ API, which is - * well documented. - * @throws Z3Exception - **/ - public ComputeInterpolantResult ComputeInterpolant(Expr pat, Params p) - { - checkContextMatch(pat); - checkContextMatch(p); - - ComputeInterpolantResult res = new ComputeInterpolantResult(); - Native.LongPtr n_i = new Native.LongPtr(); - Native.LongPtr n_m = new Native.LongPtr(); - res.status = Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); - if (res.status == Z3_lbool.Z3_L_FALSE) - res.interp = (new ASTVector(this, n_i.value)).ToBoolExprArray(); - if (res.status == Z3_lbool.Z3_L_TRUE) - res.model = new Model(this, n_m.value); - return res; - } - - /// - /// Return a string summarizing cumulative time used for interpolation. - /// - /// Remarks: For more information on interpolation please refer - /// too the function Z3_interpolation_profile in the C/C++ API, which is - /// well documented. - public String InterpolationProfile() - { - return Native.interpolationProfile(nCtx()); - } - - public class CheckInterpolantResult - { - public int return_value = 0; - public String error = null; - } - - /// - /// Checks the correctness of an interpolant. - /// - /// Remarks: For more information on interpolation please refer - /// too the function Z3_check_interpolant in the C/C++ API, which is - /// well documented. - public CheckInterpolantResult CheckInterpolant(Expr[] cnsts, int[] parents, BoolExpr[] interps, String error, Expr[] theory) - { - CheckInterpolantResult res = new CheckInterpolantResult(); - Native.StringPtr n_err_str = new Native.StringPtr(); - res.return_value = Native.checkInterpolant(nCtx(), - cnsts.length, - Expr.arrayToNative(cnsts), - parents, - Expr.arrayToNative(interps), - n_err_str, - theory.length, - Expr.arrayToNative(theory)); - res.error = n_err_str.value; - return res; - } - - public class ReadInterpolationProblemResult - { - public int return_value = 0; - public Expr[] cnsts; - public int[] parents; - public String error; - public Expr[] theory; - }; - - /// - /// Reads an interpolation problem from a file. - /// - /// Remarks: For more information on interpolation please refer - /// too the function Z3_read_interpolation_problem in the C/C++ API, which is - /// well documented. - public ReadInterpolationProblemResult ReadInterpolationProblem(String filename) - { - ReadInterpolationProblemResult res = new ReadInterpolationProblemResult(); - Native.UIntArrayPtr n_parents = new Native.UIntArrayPtr(); - ASTVector _cnsts = new ASTVector(this); - ASTVector _theory = new ASTVector(this); - Native.StringPtr n_err_str = new Native.StringPtr(); - Native.IntPtr n_num = new Native.IntPtr(); - res.return_value = Native.readInterpolationProblem(nCtx(), _cnsts.getNativeObject(), n_num, - n_parents, filename, n_err_str, _theory.getNativeObject()); - res.error = n_err_str.value; - res.theory = _theory.ToExprArray(); - res.cnsts = _cnsts.ToExprArray(); - int num = n_num.value; - res.parents = new int[num]; - for (int i = 0; i < num; i++) { - res.parents[i] = n_parents.value[i]; - } - return res; - } - - /// - /// Writes an interpolation problem to a file. - /// - /// Remarks: For more information on interpolation please refer - /// too the function Z3_write_interpolation_problem in the C/C++ API, which is - /// well documented. - public void WriteInterpolationProblem(String filename, Expr[] cnsts, int[] parents, String error, Expr[] theory) - { - Native.writeInterpolationProblem(nCtx(), cnsts.length, Expr.arrayToNative(cnsts), parents, filename, theory.length, Expr.arrayToNative(theory)); - } -} diff --git a/src/api/z3.h b/src/api/z3.h index 37ea68f84..382bc4b07 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -32,7 +32,6 @@ Notes: #include "z3_rcf.h" #include "z3_fixedpoint.h" #include "z3_optimization.h" -#include "z3_interp.h" #include "z3_fpa.h" #include "z3_spacer.h" #endif diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d5c279d63..3e47833b4 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -212,8 +212,6 @@ typedef enum - Z3_OP_OEQ Binary equivalence modulo namings. This binary predicate is used in proof terms. It captures equisatisfiability and equivalence modulo renamings. - - Z3_OP_INTERP Marks a sub-formula for interpolation. - - Z3_OP_ANUM Arithmetic numeral. - Z3_OP_AGNUM Arithmetic algebraic numeral. Algebraic numbers are used to represent irrational numbers in Z3. @@ -991,7 +989,6 @@ typedef enum { Z3_OP_NOT, Z3_OP_IMPLIES, Z3_OP_OEQ, - Z3_OP_INTERP, // Arithmetic Z3_OP_ANUM = 0x200, diff --git a/src/api/z3_interp.h b/src/api/z3_interp.h deleted file mode 100644 index 765870bd5..000000000 --- a/src/api/z3_interp.h +++ /dev/null @@ -1,283 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - z3_interp.h - -Abstract: - - API for interpolation - -Author: - - Kenneth McMillan (kenmcmil) - -Notes: - ---*/ -#ifndef Z3_INTERPOLATION_H_ -#define Z3_INTERPOLATION_H_ - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - - /** \defgroup capi C API */ - /*@{*/ - - /** @name Interpolation facilities */ - /*@{*/ - /** - \brief Create an AST node marking a formula position for interpolation. - - The node \c a must have Boolean sort. - - def_API('Z3_mk_interpolant', AST, (_in(CONTEXT), _in(AST))) - */ - Z3_ast Z3_API Z3_mk_interpolant(Z3_context c, Z3_ast a); - - - /** \brief This function generates a Z3 context suitable for generation of - interpolants. Formulas can be generated as abstract syntax trees in - this context using the Z3 C API. - - Interpolants are also generated as AST's in this context. - - If cfg is non-null, it will be used as the base configuration - for the Z3 context. This makes it possible to set Z3 options - to be used during interpolation. This feature should be used - with some caution however, as it may be that certain Z3 options - are incompatible with interpolation. - - def_API('Z3_mk_interpolation_context', CONTEXT, (_in(CONFIG),)) - - */ - - Z3_context Z3_API Z3_mk_interpolation_context(Z3_config cfg); - - /** Compute an interpolant from a refutation. This takes a proof of - "false" from a set of formulas C, and an interpolation - pattern. The pattern pat is a formula combining the formulas in C - using logical conjunction and the "interp" operator (see - #Z3_mk_interpolant). This interp operator is logically the identity - operator. It marks the sub-formulas of the pattern for which interpolants should - be computed. The interpolant is a map sigma from marked subformulas to - formulas, such that, for each marked subformula phi of pat (where phi sigma - is phi with sigma(psi) substituted for each subformula psi of phi such that - psi in dom(sigma)): - - 1) phi sigma implies sigma(phi), and - - 2) sigma(phi) is in the common uninterpreted vocabulary between - the formulas of C occurring in phi and those not occurring in - phi - - and moreover pat sigma implies false. In the simplest case - an interpolant for the pattern "(and (interp A) B)" maps A - to an interpolant for A /\ B. - - The return value is a vector of formulas representing sigma. The - vector contains sigma(phi) for each marked subformula of pat, in - pre-order traversal. This means that subformulas of phi occur before phi - in the vector. Also, subformulas that occur multiply in pat will - occur multiply in the result vector. - - In particular, calling Z3_get_interpolant on a pattern of the - form (interp ... (interp (and (interp A_1) A_2)) ... A_N) will - result in a sequence interpolant for A_1, A_2,... A_N. - - Neglecting interp markers, the pattern must be a conjunction of - formulas in C, the set of premises of the proof. Otherwise an - error is flagged. - - Any premises of the proof not present in the pattern are - treated as "background theory". Predicate and function symbols - occurring in the background theory are treated as interpreted and - thus always allowed in the interpolant. - - Interpolant may not necessarily be computable from all - proofs. To be sure an interpolant can be computed, the proof - must be generated by an SMT solver for which interpolation is - supported, and the premises must be expressed using only - theories and operators for which interpolation is supported. - - Currently, the only SMT solver that is supported is the legacy - SMT solver. Such a solver is available as the default solver in - \c Z3_context objects produced by #Z3_mk_interpolation_context. - Currently, the theories supported are equality with - uninterpreted functions, linear integer arithmetic, and the - theory of arrays (in SMT-LIB terms, this is AUFLIA). - Quantifiers are allowed. Use of any other operators (including - "labels") may result in failure to compute an interpolant from a - proof. - - Parameters: - - \param c logical context. - \param pf a refutation from premises (assertions) C - \param pat an interpolation pattern over C - \param p parameters - - def_API('Z3_get_interpolant', AST_VECTOR, (_in(CONTEXT), _in(AST), _in(AST), _in(PARAMS))) - */ - - Z3_ast_vector Z3_API Z3_get_interpolant(Z3_context c, Z3_ast pf, Z3_ast pat, Z3_params p); - - /* Compute an interpolant for an unsatisfiable conjunction of formulas. - - This takes as an argument an interpolation pattern as in - #Z3_get_interpolant. This is a conjunction, some subformulas of - which are marked with the "interp" operator (see #Z3_mk_interpolant). - - The conjunction is first checked for unsatisfiability. The result - of this check is returned in the out parameter "status". If the result - is unsat, an interpolant is computed from the refutation as in #Z3_get_interpolant - and returned as a vector of formulas. Otherwise the return value is - an empty formula. - - See #Z3_get_interpolant for a discussion of supported theories. - - The advantage of this function over #Z3_get_interpolant is that - it is not necessary to create a suitable SMT solver and generate - a proof. The disadvantage is that it is not possible to use the - solver incrementally. - - Parameters: - - \param c logical context. - \param pat an interpolation pattern - \param p parameters for solver creation - \param status returns the status of the sat check - \param model returns model if satisfiable - - Return value: status of SAT check - - def_API('Z3_compute_interpolant', INT, (_in(CONTEXT), _in(AST), _in(PARAMS), _out(AST_VECTOR), _out(MODEL))) - */ - - Z3_lbool Z3_API Z3_compute_interpolant(Z3_context c, - Z3_ast pat, - Z3_params p, - Z3_ast_vector *interp, - Z3_model *model); - - /** Return a string summarizing cumulative time used for - interpolation. This string is purely for entertainment purposes - and has no semantics. - - \param ctx The context (currently ignored) - - - def_API('Z3_interpolation_profile', STRING, (_in(CONTEXT),)) - */ - - Z3_string Z3_API Z3_interpolation_profile(Z3_context ctx); - - /** - \brief Read an interpolation problem from file. - - \param ctx The Z3 context. This resets the error handler of ctx. - \param filename The file name to read. - \param num Returns length of sequence. - \param cnsts Returns sequence of formulas (do not free) - \param parents Returns the parents vector (or NULL for sequence) - \param error Returns an error message in case of failure (do not free the string) - \param num_theory Number of theory terms - \param theory Theory terms - - Returns true on success. - - File formats: Currently two formats are supported, based on - SMT-LIB2. For sequence interpolants, the sequence of constraints is - represented by the sequence of "assert" commands in the file. - - For tree interpolants, one symbol of type bool is associated to - each vertex of the tree. For each vertex v there is an "assert" - of the form: - - (implies (and c1 ... cn f) v) - - where c1 .. cn are the children of v (which must precede v in the file) - and f is the formula associated to node v. The last formula in the - file is the root vertex, and is represented by the predicate "false". - - A solution to a tree interpolation problem can be thought of as a - valuation of the vertices that makes all the implications true - where each value is represented using the common symbols between - the formulas in the subtree and the remainder of the formulas. - - def_API('Z3_read_interpolation_problem', INT, (_in(CONTEXT), _in(AST_VECTOR), _out(UINT), _out_managed_array(2, UINT), _in(STRING), _out(STRING), _in(AST_VECTOR))) - - */ - - int Z3_API Z3_read_interpolation_problem(Z3_context ctx, - Z3_ast_vector cnsts, - unsigned* num, - unsigned* parents[], - Z3_string filename, - Z3_string_ptr error, - Z3_ast_vector theory); - - - - /** Check the correctness of an interpolant. The Z3 context must - have no constraints asserted when this call is made. That means - that after interpolating, you must first fully pop the Z3 - context before calling this. See Z3_interpolate for meaning of parameters. - - \param ctx The Z3 context. Must be generated by Z3_mk_interpolation_context - \param num The number of constraints in the sequence - \param cnsts Array of constraints (AST's in context ctx) - \param parents The parents vector (or NULL for sequence) - \param interps The interpolant to check - \param error Returns an error message if interpolant incorrect (do not free the string) - \param num_theory Number of theory terms - \param theory Theory terms - - Return value is Z3_L_TRUE if interpolant is verified, Z3_L_FALSE if - incorrect, and Z3_L_UNDEF if unknown. - - def_API('Z3_check_interpolant', INT, (_in(CONTEXT), _in(UINT), _in_array(1, AST), _in_array(1, UINT), _in_array(1, AST), _out(STRING), _in(UINT), _in_array(6, AST))) - */ - - int Z3_API Z3_check_interpolant(Z3_context ctx, - unsigned num, - Z3_ast cnsts[], - unsigned parents[], - Z3_ast *interps, - Z3_string_ptr error, - unsigned num_theory, - Z3_ast theory[]); - - /** Write an interpolation problem to file suitable for reading with - Z3_read_interpolation_problem. The output file is a sequence - of SMT-LIB2 format commands, suitable for reading with command-line Z3 - or other interpolating solvers. - - \param ctx The Z3 context. Must be generated by z3_mk_interpolation_context - \param num The number of constraints in the sequence - \param cnsts Array of constraints - \param parents The parents vector (or NULL for sequence) - \param filename The file name to write - \param num_theory Number of theory terms - \param theory Theory terms - - def_API('Z3_write_interpolation_problem', VOID, (_in(CONTEXT), _in(UINT), _in_array(1, AST), _in_array(1, UINT), _in(STRING), _in(UINT), _in_array(5, AST))) - */ - - void Z3_API Z3_write_interpolation_problem(Z3_context ctx, - unsigned num, - Z3_ast cnsts[], - unsigned parents[], - Z3_string filename, - unsigned num_theory, - Z3_ast theory[]); - /*@}*/ - /*@}*/ - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index a07be0b22..cae1618c0 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -646,7 +646,6 @@ basic_decl_plugin::basic_decl_plugin(): m_iff_decl(nullptr), m_xor_decl(nullptr), m_not_decl(nullptr), - m_interp_decl(nullptr), m_implies_decl(nullptr), m_proof_sort(nullptr), @@ -865,7 +864,6 @@ void basic_decl_plugin::set_manager(ast_manager * m, family_id id) { m_iff_decl = mk_bool_op_decl("iff", OP_IFF, 2, false, true, false, false, true); m_xor_decl = mk_bool_op_decl("xor", OP_XOR, 2, true, true); m_not_decl = mk_bool_op_decl("not", OP_NOT, 1); - m_interp_decl = mk_bool_op_decl("interp", OP_INTERP, 1); m_implies_decl = mk_implies_decl(); m_proof_sort = m->mk_sort(symbol("Proof"), sort_info(id, PROOF_SORT)); @@ -890,7 +888,6 @@ void basic_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("or", OP_OR)); op_names.push_back(builtin_name("xor", OP_XOR)); op_names.push_back(builtin_name("not", OP_NOT)); - op_names.push_back(builtin_name("interp", OP_INTERP)); op_names.push_back(builtin_name("=>", OP_IMPLIES)); if (logic == symbol::null) { // user friendly aliases @@ -902,7 +899,6 @@ void basic_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("||", OP_OR)); op_names.push_back(builtin_name("equals", OP_EQ)); op_names.push_back(builtin_name("equiv", OP_IFF)); - op_names.push_back(builtin_name("@@", OP_INTERP)); } } @@ -923,7 +919,6 @@ void basic_decl_plugin::finalize() { DEC_REF(m_and_decl); DEC_REF(m_or_decl); DEC_REF(m_not_decl); - DEC_REF(m_interp_decl); DEC_REF(m_iff_decl); DEC_REF(m_xor_decl); DEC_REF(m_implies_decl); @@ -1056,7 +1051,6 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_AND: return m_and_decl; case OP_OR: return m_or_decl; case OP_NOT: return m_not_decl; - case OP_INTERP: return m_interp_decl; case OP_IFF: return m_iff_decl; case OP_IMPLIES: return m_implies_decl; case OP_XOR: return m_xor_decl; @@ -1099,7 +1093,6 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_AND: return m_and_decl; case OP_OR: return m_or_decl; case OP_NOT: return m_not_decl; - case OP_INTERP: return m_interp_decl; case OP_IFF: return m_iff_decl; case OP_IMPLIES: return m_implies_decl; case OP_XOR: return m_xor_decl; diff --git a/src/ast/ast.h b/src/ast/ast.h index 2db0fde04..e85f164e1 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1041,7 +1041,7 @@ enum basic_sort_kind { }; enum basic_op_kind { - OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_IFF, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, OP_INTERP, LAST_BASIC_OP, + OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_IFF, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, LAST_BASIC_OP, PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO, PR_DISTRIBUTIVITY, PR_AND_ELIM, PR_NOT_OR_ELIM, PR_REWRITE, PR_REWRITE_STAR, PR_PULL_QUANT, @@ -1063,7 +1063,6 @@ protected: func_decl * m_iff_decl; func_decl * m_xor_decl; func_decl * m_not_decl; - func_decl * m_interp_decl; func_decl * m_implies_decl; ptr_vector m_eq_decls; // cached eqs ptr_vector m_ite_decls; // cached ites @@ -2054,7 +2053,6 @@ public: app * mk_true() const { return m_true; } app * mk_false() const { return m_false; } app * mk_bool_val(bool b) { return b?m_true:m_false; } - app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); } func_decl* mk_and_decl() { diff --git a/src/cmd_context/CMakeLists.txt b/src/cmd_context/CMakeLists.txt index f7b888343..8da871f9a 100644 --- a/src/cmd_context/CMakeLists.txt +++ b/src/cmd_context/CMakeLists.txt @@ -8,14 +8,12 @@ z3_add_component(cmd_context context_params.cpp echo_tactic.cpp eval_cmd.cpp - interpolant_cmds.cpp parametric_cmd.cpp pdecl.cpp simplify_cmd.cpp tactic_cmds.cpp tactic_manager.cpp COMPONENT_DEPENDENCIES - interp rewriter solver EXTRA_REGISTER_MODULE_HEADERS diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index e42f884d6..7d2b2f17a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -46,7 +46,6 @@ Notes: #include "tactic/generic_model_converter.h" #include "solver/smt_logics.h" #include "cmd_context/basic_cmds.h" -#include "cmd_context/interpolant_cmds.h" #include "cmd_context/cmd_context.h" func_decls::func_decls(ast_manager & m, func_decl * f): @@ -484,7 +483,6 @@ cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l): install_basic_cmds(*this); install_ext_basic_cmds(*this); install_core_tactic_cmds(*this); - install_interpolant_cmds(*this); SASSERT(m != 0 || !has_manager()); if (m_main_ctx) { set_verbose_stream(diagnostic_stream()); diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp deleted file mode 100644 index dd1d0acec..000000000 --- a/src/cmd_context/interpolant_cmds.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - interpolant_cmds.cpp - - Abstract: - Commands for interpolation. - - Author: - - Leonardo (leonardo) 2011-12-23 - - Notes: - - --*/ -#include -#include "cmd_context/cmd_context.h" -#include "cmd_context/cmd_util.h" -#include "util/scoped_timer.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "ast/ast_pp.h" -#include "ast/ast_smt_pp.h" -#include "ast/ast_smt2_pp.h" -#include "cmd_context/parametric_cmd.h" -#include "util/mpq.h" -#include "ast/expr2var.h" -#include "ast/pp.h" -#include "interp/iz3interp.h" -#include "interp/iz3checker.h" -#include "interp/iz3profiling.h" -#include "interp/interp_params.hpp" -#include "ast/scoped_proof.h" - -static void show_interpolant_and_maybe_check(cmd_context & ctx, - ptr_vector &cnsts, - expr *t, - ptr_vector &interps, - params_ref &m_params, - bool check) -{ - - if (m_params.get_bool("som", false)) - m_params.set_bool("flat", true); - th_rewriter s(ctx.m(), m_params); - - ctx.regular_stream() << "(interpolants"; - for(unsigned i = 0; i < interps.size(); i++){ - expr_ref r(ctx.m()); - proof_ref pr(ctx.m()); - s(to_expr(interps[i]),r,pr); - ctx.regular_stream() << "\n " << r; - } - ctx.regular_stream() << ")\n"; - - s.cleanup(); - - // verify, for the paranoid... - if(check || interp_params(m_params).check()){ - std::ostringstream err; - ast_manager &_m = ctx.m(); - - // need a solver -- make one here FIXME is this right? - bool proofs_enabled, models_enabled, unsat_core_enabled; - params_ref p; - ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled); - scoped_ptr sp = (ctx.get_solver_factory())(_m, p, false, true, false, ctx.get_logic()); - - if(iz3check(_m,sp.get(),err,cnsts,t,interps)) - ctx.regular_stream() << "correct\n"; - else - ctx.regular_stream() << "incorrect: " << err.str().c_str() << "\n"; - } - - for(unsigned i = 0; i < interps.size(); i++){ - ctx.m().dec_ref(interps[i]); - } - - interp_params itp_params(m_params); - if(itp_params.profile()) - profiling::print(ctx.regular_stream()); - -} - -static void check_can_interpolate(cmd_context & ctx){ - if (!ctx.produce_interpolants()) - throw cmd_exception("interpolation is not enabled, use command (set-option :produce-interpolants true)"); -} - - -static void get_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_ref &m_params, bool check) { - - check_can_interpolate(ctx); - - // get the proof, if there is one - - if (!ctx.has_manager() || - ctx.cs_state() != cmd_context::css_unsat) - throw cmd_exception("proof is not available"); - expr_ref pr(ctx.m()); - pr = ctx.get_check_sat_result()->get_proof(); - if (pr == 0) - throw cmd_exception("proof is not available"); - - // get the assertions from the context - - ptr_vector::const_iterator it = ctx.begin_assertions(); - ptr_vector::const_iterator end = ctx.end_assertions(); - ptr_vector cnsts((unsigned)(end - it)); - for (int i = 0; it != end; ++it, ++i) - cnsts[i] = *it; - - // compute an interpolant - - ptr_vector interps; - - try { - iz3interpolate(ctx.m(),pr.get(),cnsts,t,interps,nullptr); - } - catch (iz3_bad_tree &) { - throw cmd_exception("interpolation pattern contains non-asserted formula"); - } - catch (iz3_incompleteness &) { - throw cmd_exception("incompleteness in interpolator"); - } - - show_interpolant_and_maybe_check(ctx, cnsts, t, interps, m_params, check); -} - -static void get_interpolant(cmd_context & ctx, expr * t, params_ref &m_params) { - get_interpolant_and_maybe_check(ctx,t,m_params,false); -} - -#if 0 -static void get_and_check_interpolant(cmd_context & ctx, params_ref &m_params, expr * t) { - get_interpolant_and_maybe_check(ctx,t,m_params,true); -} -#endif - -static void compute_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_ref &m_params, bool check){ - - // create a fresh solver suitable for interpolation - bool proofs_enabled, models_enabled, unsat_core_enabled; - params_ref p; - ast_manager &_m = ctx.m(); - // TODO: the following is a HACK to enable proofs in the old smt solver - // When we stop using that solver, this hack can be removed - scoped_proof_mode spm(_m,PGM_ENABLED); - ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled); - p.set_bool("proof", true); - scoped_ptr sp = (ctx.get_interpolating_solver_factory())(_m, p, true, models_enabled, false, ctx.get_logic()); - - ptr_vector cnsts; - ptr_vector interps; - model_ref m; - - // compute an interpolant - - lbool res; - try { - res = iz3interpolate(_m, *sp.get(), t, cnsts, interps, m, nullptr); - } - catch (iz3_incompleteness &) { - throw cmd_exception("incompleteness in interpolator"); - } - - switch(res){ - case l_false: - ctx.regular_stream() << "unsat\n"; - show_interpolant_and_maybe_check(ctx, cnsts, t, interps, m_params, check); - break; - - case l_true: - ctx.regular_stream() << "sat\n"; - // TODO: how to return the model to the context, if it exists? - break; - - case l_undef: - ctx.regular_stream() << "unknown\n"; - // TODO: how to return the model to the context, if it exists? - break; - } - - for(unsigned i = 0; i < cnsts.size(); i++) - ctx.m().dec_ref(cnsts[i]); - -} - -static expr *make_tree(cmd_context & ctx, const ptr_vector &exprs){ - if(exprs.size() == 0) - throw cmd_exception("not enough arguments"); - expr *foo = exprs[0]; - for(unsigned i = 1; i < exprs.size(); i++){ - foo = ctx.m().mk_and(ctx.m().mk_interp(foo),exprs[i]); - } - return foo; -} - -static void get_interpolant(cmd_context & ctx, const ptr_vector &exprs, params_ref &m_params) { - expr_ref foo(make_tree(ctx, exprs),ctx.m()); - get_interpolant(ctx,foo.get(),m_params); -} - -static void compute_interpolant(cmd_context & ctx, const ptr_vector &exprs, params_ref &m_params) { - expr_ref foo(make_tree(ctx, exprs),ctx.m()); - compute_interpolant_and_maybe_check(ctx,foo.get(),m_params,false); -} - - -// UNARY_CMD(get_interpolant_cmd, "get-interpolant", "", "get interpolant for marked positions in fmla", CPK_EXPR, expr *, get_interpolant(ctx, arg);); - -// UNARY_CMD(get_and_check_interpolant_cmd, "get-and-check-interpolant", "", "get and check interpolant for marked positions in fmla", CPK_EXPR, expr *, get_and_check_interpolant(ctx, arg);); - -class get_interpolant_cmd : public parametric_cmd { -protected: - ptr_vector m_targets; -public: - get_interpolant_cmd(char const * name = "get-interpolant"):parametric_cmd(name) {} - - char const * get_usage() const override { return "+"; } - - char const * get_main_descr() const override { - return "get interpolant for formulas"; - } - - void init_pdescrs(cmd_context & ctx, param_descrs & p) override { - } - - void prepare(cmd_context & ctx) override { - parametric_cmd::prepare(ctx); - m_targets.resize(0); - } - - cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - return CPK_EXPR; - } - - void set_next_arg(cmd_context & ctx, expr * arg) override { - m_targets.push_back(arg); - } - - void execute(cmd_context & ctx) override { - get_interpolant(ctx,m_targets,m_params); - } -}; - -class compute_interpolant_cmd : public get_interpolant_cmd { -public: - compute_interpolant_cmd(char const * name = "compute-interpolant"):get_interpolant_cmd(name) {} - - void execute(cmd_context & ctx) override { - compute_interpolant(ctx,m_targets,m_params); - } - -}; - -void install_interpolant_cmds(cmd_context & ctx) { - ctx.insert(alloc(get_interpolant_cmd)); - ctx.insert(alloc(compute_interpolant_cmd)); - // ctx.insert(alloc(get_and_check_interpolant_cmd)); -} diff --git a/src/cmd_context/interpolant_cmds.h b/src/cmd_context/interpolant_cmds.h deleted file mode 100644 index daef70926..000000000 --- a/src/cmd_context/interpolant_cmds.h +++ /dev/null @@ -1,24 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - interpolant_cmds.h - - Abstract: - Commands for interpolation. - - Author: - - Leonardo (leonardo) 2011-12-23 - - Notes: - - --*/ -#ifndef INTERPOLANT_CMDS_H_ -#define INTERPOLANT_CMDS_H_ - -class cmd_context; -void install_interpolant_cmds(cmd_context & ctx); - -#endif diff --git a/src/duality/CMakeLists.txt b/src/duality/CMakeLists.txt deleted file mode 100644 index eb2d5c4f2..000000000 --- a/src/duality/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -z3_add_component(duality - SOURCES - duality_profiling.cpp - duality_rpfp.cpp - duality_solver.cpp - duality_wrapper.cpp - COMPONENT_DEPENDENCIES - interp - qe - smt -) diff --git a/src/duality/duality.h b/src/duality/duality.h deleted file mode 100644 index 9bf323d8b..000000000 --- a/src/duality/duality.h +++ /dev/null @@ -1,1365 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - duality.h - - Abstract: - - main header for duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - -#pragma once - -#include "duality/duality_wrapper.h" -#include -#include -#include - -// make hash_map and hash_set available -using namespace stl_ext; - -namespace Duality { - - struct implicant_solver; - - /* Generic operations on Z3 formulas */ - - struct Z3User { - - context &ctx; - - typedef func_decl FuncDecl; - typedef expr Term; - - Z3User(context &_ctx) : ctx(_ctx){} - - const char *string_of_int(int n); - - Term conjoin(const std::vector &args); - - Term sum(const std::vector &args); - - Term CloneQuantifier(const Term &t, const Term &new_body); - - Term SubstRec(hash_map &memo, const Term &t); - - Term SubstRec(hash_map &memo, hash_map &map, const Term &t); - - void Strengthen(Term &x, const Term &y); - - // return the func_del of an app if it is uninterpreted - - bool get_relation(const Term &t, func_decl &R); - - // return true if term is an individual variable - // TODO: have to check that it is not a background symbol - - bool is_variable(const Term &t); - - FuncDecl SuffixFuncDecl(const Term &t, int n); - - - Term SubstRecHide(hash_map &memo, const Term &t, int number); - - void CollectConjuncts(const Term &f, std::vector &lits, bool pos = true); - - void SortTerms(std::vector &terms); - - Term SortSum(const Term &t); - - void Summarize(const Term &t); - - int CountOperators(const Term &t); - - Term SubstAtom(hash_map &memo, const expr &t, const expr &atom, const expr &val); - - Term CloneQuantAndSimp(const expr &t, const expr &body); - - Term RemoveRedundancy(const Term &t); - - Term IneqToEq(const Term &t); - - bool IsLiteral(const expr &lit, expr &atom, expr &val); - - expr Negate(const expr &f); - - expr SimplifyAndOr(const std::vector &args, bool is_and); - - expr ReallySimplifyAndOr(const std::vector &args, bool is_and); - - int MaxIndex(hash_map &memo, const Term &t); - - bool IsClosedFormula(const Term &t); - - Term AdjustQuantifiers(const Term &t); - - FuncDecl RenumberPred(const FuncDecl &f, int n); - - FuncDecl NumberPred(const FuncDecl &f, int n); - - Term ExtractStores(hash_map &memo, const Term &t, std::vector &cnstrs, hash_map &renaming); - - - protected: - - void SummarizeRec(hash_set &memo, std::vector &lits, int &ops, const Term &t); - int CountOperatorsRec(hash_set &memo, const Term &t); - void RemoveRedundancyOp(bool pol, std::vector &args, hash_map &smemo); - Term RemoveRedundancyRec(hash_map &memo, hash_map &smemo, const Term &t); - Term SubstAtomTriv(const expr &foo, const expr &atom, const expr &val); - expr ReduceAndOr(const std::vector &args, bool is_and, std::vector &res); - expr FinishAndOr(const std::vector &args, bool is_and); - expr PullCommonFactors(std::vector &args, bool is_and); - Term IneqToEqRec(hash_map &memo, const Term &t); - Term CloneQuantAndSimp(const expr &t, const expr &body, bool is_forall); - Term PushQuantifier(const expr &t, const expr &body, bool is_forall); - void CollectJuncts(const Term &f, std::vector &lits, decl_kind op, bool negate); - Term DeleteBoundRec(hash_map > &memo, int level, int num, const Term &t); - Term DeleteBound(int level, int num, const Term &t); - - }; - - /** This class represents a relation post-fixed point (RPFP) problem as - * a "problem graph". The graph consists of Nodes and hyper-edges. - * - * A node consists of - * - Annotation, a symbolic relation - * - Bound, a symbolic relation giving an upper bound on Annotation - * - * - * A hyper-edge consists of: - * - Children, a sequence of children Nodes, - * - F, a symbolic relational transformer, - * - Parent, a single parent Node. - * - * The graph is "solved" when: - * - For every Node n, n.Annotation subseteq n.Bound - * - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation - * - * where, if x is a sequence of Nodes, x.Annotation is the sequences - * of Annotations of the nodes in the sequence. - * - * A symbolic Transformer consists of - * - RelParams, a sequence of relational symbols - * - IndParams, a sequence of individual symbols - * - Formula, a formula over RelParams and IndParams - * - * A Transformer t represents a function that takes sequence R of relations - * and yields the relation lambda (t.Indparams). Formula(R/RelParams). - * - * As a special case, a nullary Transformer (where RelParams is the empty sequence) - * represents a fixed relation. - * - * An RPFP consists of - * - Nodes, a set of Nodes - * - Edges, a set of hyper-edges - * - Context, a prover context that contains formula AST's - * - * Multiple RPFP's can use the same Context, but you should be careful - * that only one RPFP asserts constraints in the context at any time. - * - * */ - class RPFP : public Z3User - { - public: - - class Edge; - class Node; - bool HornClauses; - - - /** Interface class for interpolating solver. */ - - class LogicSolver { - public: - - context *ctx; /** Z3 context for formulas */ - solver *slvr; /** Z3 solver */ - bool need_goals; /** Can the solver use the goal tree to optimize interpolants? */ - solver aux_solver; /** For temporary use -- don't leave assertions here. */ - - /** Tree interpolation. This method assumes the formulas in TermTree - "assumptions" are currently asserted in the solver. The return - value indicates whether the assertions are satisfiable. In the - UNSAT case, a tree interpolant is returned in "interpolants". - In the SAT case, a model is returned. - */ - - virtual - lbool interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals = nullptr, - bool weak = false - ) = 0; - - /** Declare a constant in the background theory. */ - virtual void declare_constant(const func_decl &f) = 0; - - /** Is this a background constant? */ - virtual bool is_constant(const func_decl &f) = 0; - - /** Get the constants in the background vocabulary */ - virtual hash_set &get_constants() = 0; - - /** Assert a background axiom. */ - virtual void assert_axiom(const expr &axiom) = 0; - - /** Get the background axioms. */ - virtual const std::vector &get_axioms() = 0; - - /** Return a string describing performance. */ - virtual std::string profile() = 0; - - virtual void write_interpolation_problem(const std::string &file_name, - const std::vector &assumptions, - const std::vector &theory - ){} - - /** Cancel, throw Canceled object if possible. */ - virtual void cancel(){ } - - /* Note: aux solver uses extensional array theory, since it - needs to be able to produce counter-models for - interpolants the have array equalities in them. - */ - LogicSolver(context &c) : aux_solver(c,true){} - - virtual ~LogicSolver(){} - }; - - /** This solver uses iZ3. */ - class iZ3LogicSolver : public LogicSolver { - public: - interpolating_context *ictx; /** iZ3 context for formulas */ - interpolating_solver *islvr; /** iZ3 solver */ - - lbool interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals = nullptr, - bool weak = false) override - { - literals _labels; - islvr->SetWeakInterpolants(weak); - return islvr->interpolate_tree(assumptions,interpolants,_model,_labels,true); - } - - void assert_axiom(const expr &axiom) override { -#if 1 - // HACK: large "distict" predicates can kill the legacy SMT solver. - // encode them with a UIF - if(axiom.is_app() && axiom.decl().get_decl_kind() == Distinct) - if(axiom.num_args() > 10){ - sort s = axiom.arg(0).get_sort(); - std::vector sv; - sv.push_back(s); - int nargs = axiom.num_args(); - std::vector args(nargs); - func_decl f = ctx->fresh_func_decl("@distinct",sv,ctx->int_sort()); - for(int i = 0; i < nargs; i++){ - expr a = axiom.arg(i); - expr new_cnstr = f(a) == ctx->int_val(i); - args[i] = new_cnstr; - } - expr cnstr = ctx->make(And,args); - islvr->AssertInterpolationAxiom(cnstr); - return; - } -#endif - islvr->AssertInterpolationAxiom(axiom); - } - - const std::vector &get_axioms() override { - return islvr->GetInterpolationAxioms(); - } - - std::string profile() override { - return islvr->profile(); - } - -#if 0 - iZ3LogicSolver(config &_config){ - ctx = ictx = new interpolating_context(_config); - slvr = islvr = new interpolating_solver(*ictx); - need_goals = false; - islvr->SetWeakInterpolants(true); - } -#endif - - iZ3LogicSolver(context &c, bool models = true) : LogicSolver(c) { - ctx = ictx = &c; - slvr = islvr = new interpolating_solver(*ictx, models); - need_goals = false; - islvr->SetWeakInterpolants(true); - } - - void write_interpolation_problem(const std::string &file_name, - const std::vector &assumptions, - const std::vector &theory - ) override { -#if 0 - islvr->write_interpolation_problem(file_name,assumptions,theory); -#endif - - } - - void cancel() override {islvr->cancel();} - - /** Declare a constant in the background theory. */ - void declare_constant(const func_decl &f) override { - bckg.insert(f); - } - - /** Is this a background constant? */ - bool is_constant(const func_decl &f) override { - return bckg.find(f) != bckg.end(); - } - - /** Get the constants in the background vocabulary */ - hash_set &get_constants() override { - return bckg; - } - - ~iZ3LogicSolver() override { - // delete ictx; - delete islvr; - } - private: - hash_set bckg; - - }; - -#if 0 - /** Create a logic solver from a Z3 configuration. */ - static iZ3LogicSolver *CreateLogicSolver(config &_config){ - return new iZ3LogicSolver(_config); - } -#endif - - /** Create a logic solver from a low-level Z3 context. - Only use this if you know what you're doing. */ - static iZ3LogicSolver *CreateLogicSolver(context c){ - return new iZ3LogicSolver(c); - } - - LogicSolver *ls; - - protected: - int nodeCount; - int edgeCount; - - class stack_entry - { - public: - std::list edges; - std::list nodes; - std::list > constraints; - }; - - - public: - model dualModel; - protected: - literals dualLabels; - std::list stack; - std::vector axioms; // only saved here for printing purposes - solver &aux_solver; - hash_set *proof_core; - - public: - - /** Construct an RPFP graph with a given interpolating prover context. It is allowed to - have multiple RPFP's use the same context, but you should never have teo RPFP's - with the same conext asserting nodes or edges at the same time. Note, if you create - axioms in one RPFP, them create a second RPFP with the same context, the second will - inherit the axioms. - */ - - RPFP(LogicSolver *_ls) : Z3User(*(_ls->ctx)), dualModel(*(_ls->ctx)), aux_solver(_ls->aux_solver) - { - ls = _ls; - nodeCount = 0; - edgeCount = 0; - stack.push_back(stack_entry()); - HornClauses = false; - proof_core = nullptr; - } - - virtual ~RPFP(); - - /** Symbolic representation of a relational transformer */ - class Transformer - { - public: - std::vector RelParams; - std::vector IndParams; - Term Formula; - RPFP *owner; - hash_map labels; - - Transformer *Clone() - { - return new Transformer(*this); - } - - void SetEmpty(){ - Formula = owner->ctx.bool_val(false); - } - - void SetFull(){ - Formula = owner->ctx.bool_val(true); - } - - bool IsEmpty(){ - return eq(Formula,owner->ctx.bool_val(false)); - } - - bool IsFull(){ - return eq(Formula,owner->ctx.bool_val(true)); - } - - void UnionWith(const Transformer &other){ - Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula); - Formula = Formula || t; - } - - void IntersectWith(const Transformer &other){ - Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula); - Formula = Formula && t; - } - - bool SubsetEq(const Transformer &other){ - Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula); - expr test = Formula && !t; - owner->aux_solver.push(); - owner->aux_solver.add(test); - check_result res = owner->aux_solver.check(); - owner->aux_solver.pop(1); - return res == unsat; - } - - void Complement(){ - Formula = !Formula; - } - - void Simplify(){ - Formula = Formula.simplify(); - } - - Transformer(const std::vector &_RelParams, const std::vector &_IndParams, const Term &_Formula, RPFP *_owner) - : RelParams(_RelParams), IndParams(_IndParams), Formula(_Formula) {owner = _owner;} - }; - - /** Create a symbolic transformer. */ - Transformer CreateTransformer(const std::vector &_RelParams, const std::vector &_IndParams, const Term &_Formula) - { - // var ops = new Util.ContextOps(ctx); - // var foo = ops.simplify_lhs(_Formula); - // t.Formula = foo.Item1; - // t.labels = foo.Item2; - return Transformer(_RelParams,_IndParams,_Formula,this); - } - - /** Create a relation (nullary relational transformer) */ - Transformer CreateRelation(const std::vector &_IndParams, const Term &_Formula) - { - return CreateTransformer(std::vector(), _IndParams, _Formula); - } - - /** A node in the RPFP graph */ - class Node - { - public: - FuncDecl Name; - Transformer Annotation; - Transformer Bound; - Transformer Underapprox; - RPFP *owner; - int number; - Edge *Outgoing; - std::vector Incoming; - Term dual; - Node *map; - unsigned recursion_bound; - - Node(const FuncDecl &_Name, const Transformer &_Annotation, const Transformer &_Bound, const Transformer &_Underapprox, const Term &_dual, RPFP *_owner, int _number) - : Name(_Name), Annotation(_Annotation), Bound(_Bound), Underapprox(_Underapprox), dual(_dual) {owner = _owner; number = _number; Outgoing = nullptr; recursion_bound = UINT_MAX;} - }; - - /** Create a node in the graph. The input is a term R(v_1...v_n) - * where R is an arbitrary relational symbol and v_1...v_n are - * arbitary distinct variables. The names are only of mnemonic value, - * however, the number and type of arguments determine the type - * of the relation at this node. */ - - Node *CreateNode(const Term &t) - { - std::vector _IndParams; - int nargs = t.num_args(); - _IndParams.reserve(nargs); - for(int i = 0; i < nargs; i++) - _IndParams.push_back(t.arg(i)); - Node *n = new Node(t.decl(), - CreateRelation(_IndParams,ctx.bool_val(true)), - CreateRelation(_IndParams,ctx.bool_val(true)), - CreateRelation(_IndParams,ctx.bool_val(false)), - expr(ctx), this, ++nodeCount - ); - nodes.push_back(n); - return n; - } - - /** Clone a node (can be from another graph). */ - - Node *CloneNode(Node *old) - { - Node *n = new Node(old->Name, - old->Annotation, - old->Bound, - old->Underapprox, - expr(ctx), - this, - ++nodeCount - ); - nodes.push_back(n); - n->map = old; - return n; - } - - /** Delete a node. You can only do this if not connected to any edges.*/ - void DeleteNode(Node *node){ - if(node->Outgoing || !node->Incoming.empty()) - throw "cannot delete RPFP node"; - for(std::vector::iterator it = nodes.end(), en = nodes.begin(); it != en;){ - if(*(--it) == node){ - nodes.erase(it); - break; - } - } - delete node; - } - - /** This class represents a hyper-edge in the RPFP graph */ - - class Edge - { - public: - Transformer F; - Node *Parent; - std::vector Children; - RPFP *owner; - int number; - // these should be internal... - Term dual; - hash_map relMap; - hash_map varMap; - Edge *map; - Term labeled; - std::vector constraints; - - Edge(Node *_Parent, const Transformer &_F, const std::vector &_Children, RPFP *_owner, int _number) - : F(_F), Parent(_Parent), Children(_Children), dual(expr(_owner->ctx)) { - owner = _owner; - number = _number; - } - }; - - - /** Create a hyper-edge. */ - Edge *CreateEdge(Node *_Parent, const Transformer &_F, const std::vector &_Children) - { - Edge *e = new Edge(_Parent,_F,_Children,this,++edgeCount); - _Parent->Outgoing = e; - for(unsigned i = 0; i < _Children.size(); i++) - _Children[i]->Incoming.push_back(e); - edges.push_back(e); - return e; - } - - - /** Delete a hyper-edge and unlink it from any nodes. */ - void DeleteEdge(Edge *edge){ - if(edge->Parent) - edge->Parent->Outgoing = nullptr; - for(unsigned int i = 0; i < edge->Children.size(); i++){ - std::vector &ic = edge->Children[i]->Incoming; - for(std::vector::iterator it = ic.begin(), en = ic.end(); it != en; ++it){ - if(*it == edge){ - ic.erase(it); - break; - } - } - } - for(std::vector::iterator it = edges.end(), en = edges.begin(); it != en;){ - if(*(--it) == edge){ - edges.erase(it); - break; - } - } - delete edge; - } - - /** Create an edge that lower-bounds its parent. */ - Edge *CreateLowerBoundEdge(Node *_Parent) - { - return CreateEdge(_Parent, _Parent->Annotation, std::vector()); - } - - - /** For incremental solving, asserts the constraint associated - * with this edge in the SMT context. If this edge is removed, - * you must pop the context accordingly. The second argument is - * the number of pushes we are inside. */ - - virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false); - - /* Constrain an edge by the annotation of one of its children. */ - - void ConstrainParent(Edge *parent, Node *child); - - /** For incremental solving, asserts the negation of the upper bound associated - * with a node. - * */ - - void AssertNode(Node *n); - - /** Assert a constraint on an edge in the SMT context. - */ - void ConstrainEdge(Edge *e, const Term &t); - - /** Fix the truth values of atomic propositions in the given - edge to their values in the current assignment. */ - void FixCurrentState(Edge *root); - - void FixCurrentStateFull(Edge *edge, const expr &extra); - - void FixCurrentStateFull(Edge *edge, const std::vector &assumps, const hash_map &renaming); - - /** Declare a constant in the background theory. */ - - void DeclareConstant(const FuncDecl &f); - - /** Assert a background axiom. Background axioms can be used to provide the - * theory of auxilliary functions or relations. All symbols appearing in - * background axioms are considered global, and may appear in both transformer - * and relational solutions. Semantically, a solution to the RPFP gives - * an interpretation of the unknown relations for each interpretation of the - * auxilliary symbols that is consistent with the axioms. Axioms should be - * asserted before any calls to Push. They cannot be de-asserted by Pop. */ - - void AssertAxiom(const Term &t); - -#if 0 - /** Do not call this. */ - - void RemoveAxiom(const Term &t); -#endif - - /** Solve an RPFP graph. This means either strengthen the annotation - * so that the bound at the given root node is satisfied, or - * show that this cannot be done by giving a dual solution - * (i.e., a counterexample). - * - * In the current implementation, this only works for graphs that - * are: - * - tree-like - * - * - closed. - * - * In a tree-like graph, every nod has out most one incoming and one out-going edge, - * and there are no cycles. In a closed graph, every node has exactly one out-going - * edge. This means that the leaves of the tree are all hyper-edges with no - * children. Such an edge represents a relation (nullary transformer) and thus - * a lower bound on its parent. The parameter root must be the root of this tree. - * - * If Solve returns LBool.False, this indicates success. The annotation of the tree - * has been updated to satisfy the upper bound at the root. - * - * If Solve returns LBool.True, this indicates a counterexample. For each edge, - * you can then call Eval to determine the values of symbols in the transformer formula. - * You can also call Empty on a node to determine if its value in the counterexample - * is the empty relation. - * - * \param root The root of the tree - * \param persist Number of context pops through which result should persist - * - * - */ - - lbool Solve(Node *root, int persist); - - /** Same as Solve, but annotates only a single node. */ - - lbool SolveSingleNode(Node *root, Node *node); - - /** Get the constraint tree (but don't solve it) */ - - TermTree *GetConstraintTree(Node *root, Node *skip_descendant = nullptr); - - /** Dispose of the dual model (counterexample) if there is one. */ - - void DisposeDualModel(); - - /** Check satisfiability of asserted edges and nodes. Same functionality as - * Solve, except no primal solution (interpolant) is generated in the unsat case. */ - - check_result Check(Node *root, std::vector underapproxes = std::vector(), - std::vector *underapprox_core = nullptr); - - /** Update the model, attempting to make the propositional literals in assumps true. If possible, - return sat, else return unsat and keep the old model. */ - - check_result CheckUpdateModel(Node *root, std::vector assumps); - - /** Determines the value in the counterexample of a symbol occurring in the transformer formula of - * a given edge. */ - - Term Eval(Edge *e, const Term& t); - - /** Return the fact derived at node p in a counterexample. */ - - Term EvalNode(Node *p); - - /** Returns true if the given node is empty in the primal solution. For procedure summaries, - this means that the procedure is not called in the current counter-model. */ - - bool Empty(Node *p); - - /** Compute an underapproximation of every node in a tree rooted at "root", - based on a previously computed counterexample. */ - - Term ComputeUnderapprox(Node *root, int persist); - - /** Try to strengthen the annotation of a node by removing disjuncts. */ - void Generalize(Node *root, Node *node); - - - /** Compute disjunctive interpolant for node by case splitting */ - void InterpolateByCases(Node *root, Node *node); - - /** Push a scope. Assertions made after Push can be undone by Pop. */ - - void Push(); - - /** Exception thrown when bad clause is encountered */ - - struct bad_clause { - std::string msg; - int i; - bad_clause(const std::string &_msg, int _i){ - msg = _msg; - i = _i; - } - }; - - struct parse_error { - std::string msg; - parse_error(const std::string &_msg){ - msg = _msg; - } - }; - - struct file_not_found { - }; - - struct bad_format { - }; - - // thrown on internal error - struct Bad { - }; - - // thrown on more serious internal error - struct ReallyBad { - }; - - // throw when greedy reduction fails - struct greedy_reduce_failed {}; - - /** Pop a scope (see Push). Note, you cannot pop axioms. */ - - void Pop(int num_scopes); - - /** Erase the proof by performing a Pop, Push and re-assertion of - all the popped constraints */ - void PopPush(); - - /** Return true if the given edge is used in the proof of unsat. - Can be called only after Solve or Check returns an unsat result. */ - - bool EdgeUsedInProof(Edge *edge); - - - /** Convert a collection of clauses to Nodes and Edges in the RPFP. - - Predicate unknowns are uninterpreted predicates not - occurring in the background theory. - - Clauses are of the form - - B => P(t_1,...,t_k) - - where P is a predicate unknown and predicate unknowns - occur only positivey in H and only under existential - quantifiers in prenex form. - - Each predicate unknown maps to a node. Each clause maps to - an edge. Let C be a clause B => P(t_1,...,t_k) where the - sequence of predicate unknowns occurring in B (in order - of occurrence) is P_1..P_n. The clause maps to a transformer - T where: - - T.Relparams = P_1..P_n - T.Indparams = x_1...x+k - T.Formula = B /\ t_1 = x_1 /\ ... /\ t_k = x_k - - Throws exception bad_clause(msg,i) if a clause i is - in the wrong form. - - */ - - struct label_struct { - symbol name; - expr value; - bool pos; - label_struct(const symbol &s, const expr &e, bool b) - : name(s), value(e), pos(b) {} - }; - - -#ifdef _WINDOWS - __declspec(dllexport) -#endif - void FromClauses(const std::vector &clauses, const std::vector *bounds = nullptr); - - void FromFixpointContext(fixedpoint fp, std::vector &queries); - - void WriteSolution(std::ostream &s); - - void WriteCounterexample(std::ostream &s, Node *node); - - enum FileFormat {DualityFormat, SMT2Format, HornFormat}; - - /** Write the RPFP to a file (currently in SMTLIB 1.2 format) */ - void WriteProblemToFile(std::string filename, FileFormat format = DualityFormat); - - /** Read the RPFP from a file (in specified format) */ - void ReadProblemFromFile(std::string filename, FileFormat format = DualityFormat); - - /** Translate problem to Horn clause form */ - void ToClauses(std::vector &cnsts, FileFormat format = DualityFormat); - - /** Translate the RPFP to a fixed point context, with queries */ - fixedpoint ToFixedPointProblem(std::vector &queries); - - /** Nodes of the graph. */ - std::vector nodes; - - /** Edges of the graph. */ - std::vector edges; - - /** Fuse a vector of transformers. If the total number of inputs of the transformers - is N, then the result is an N-ary transformer whose output is the union of - the outputs of the given transformers. The is, suppose we have a vector of transformers - {T_i(r_i1,...,r_iN(i) : i=1..M}. The result is a transformer - - F(r_11,...,r_iN(1),...,r_M1,...,r_MN(M)) = - T_1(r_11,...,r_iN(1)) U ... U T_M(r_M1,...,r_MN(M)) - */ - - Transformer Fuse(const std::vector &trs); - - /** Fuse edges so that each node is the output of at most one edge. This - transformation is solution-preserving, but changes the numbering of edges in - counterexamples. - */ - void FuseEdges(); - - void RemoveDeadNodes(); - - Term SubstParams(const std::vector &from, - const std::vector &to, const Term &t); - - Term SubstParamsNoCapture(const std::vector &from, - const std::vector &to, const Term &t); - - Term Localize(Edge *e, const Term &t); - - void EvalNodeAsConstraint(Node *p, Transformer &res); - - TermTree *GetGoalTree(Node *root); - - int EvalTruth(hash_map &memo, Edge *e, const Term &f); - - void GetLabels(Edge *e, std::vector &labels); - - // int GetLabelsRec(hash_map *memo, const Term &f, std::vector &labels, bool labpos); - - /** Compute and save the proof core for future calls to - EdgeUsedInProof. You only need to call this if you will pop - the solver before calling EdgeUsedInProof. - */ - void ComputeProofCore(); - - int CumulativeDecisions(); - - void GreedyReduceNodes(std::vector &nodes); - - check_result CheckWithConstrainedNodes(std::vector &posnodes,std::vector &negnodes); - - solver &slvr(){ - return *ls->slvr; - } - - protected: - - void ClearProofCore(){ - if(proof_core) - delete proof_core; - proof_core = nullptr; - } - - Term SuffixVariable(const Term &t, int n); - - Term HideVariable(const Term &t, int n); - - void RedVars(Node *node, Term &b, std::vector &v); - - Term RedDualRela(Edge *e, std::vector &args, int idx); - - Term LocalizeRec(Edge *e, hash_map &memo, const Term &t); - - void SetEdgeMaps(Edge *e); - - Term ReducedDualEdge(Edge *e); - - TermTree *ToTermTree(Node *root, Node *skip_descendant = nullptr); - - TermTree *ToGoalTree(Node *root); - - void CollapseTermTreeRec(TermTree *root, TermTree *node); - - TermTree *CollapseTermTree(TermTree *node); - - void DecodeTree(Node *root, TermTree *interp, int persist); - - Term GetUpperBound(Node *n); - - TermTree *AddUpperBound(Node *root, TermTree *t); - -#if 0 - void WriteInterps(System.IO.StreamWriter f, TermTree t); -#endif - - void WriteEdgeVars(Edge *e, hash_map &memo, const Term &t, std::ostream &s); - - void WriteEdgeAssignment(std::ostream &s, Edge *e); - - - // Scan the clause body for occurrences of the predicate unknowns - - Term ScanBody(hash_map &memo, - const Term &t, - hash_map &pmap, - std::vector &res, - std::vector &nodes); - - Term RemoveLabelsRec(hash_map &memo, const Term &t, std::vector &lbls); - - Term RemoveLabels(const Term &t, std::vector &lbls); - - Term GetAnnotation(Node *n); - - - Term GetUnderapprox(Node *n); - - Term UnderapproxFlag(Node *n); - - hash_map underapprox_flag_rev; - - Node *UnderapproxFlagRev(const Term &flag); - - Term ProjectFormula(std::vector &keep_vec, const Term &f); - - int SubtermTruth(hash_map &memo, const Term &); - - void ImplicantRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set *done, bool truth, hash_set &dont_cares); - - void Implicant(hash_map &memo, const Term &f, std::vector &lits, hash_set &dont_cares); - - Term UnderapproxFormula(const Term &f, hash_set &dont_cares); - - void ImplicantFullRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set &done, hash_set &dont_cares, bool extensional = true); - - public: - Term UnderapproxFullFormula(const Term &f, bool extensional = true); - - protected: - Term ToRuleRec(Edge *e, hash_map &memo, const Term &t, std::vector &quants); - - hash_map resolve_ite_memo; - - Term ResolveIte(hash_map &memo, const Term &t, std::vector &lits, - hash_set *done, hash_set &dont_cares); - - struct ArrayValue { - bool defined; - std::map entries; - expr def_val; - }; - - void EvalArrayTerm(const Term &t, ArrayValue &res); - - Term EvalArrayEquality(const Term &f); - - Term ModelValueAsConstraint(const Term &t); - - void GetLabelsRec(hash_map &memo, const Term &f, std::vector &labels, - hash_set *done, bool truth); - - Term SubstBoundRec(hash_map > &memo, hash_map &subst, int level, const Term &t); - - Term SubstBound(hash_map &subst, const Term &t); - - void ConstrainEdgeLocalized(Edge *e, const Term &t); - - void GreedyReduce(solver &s, std::vector &conjuncts); - - void NegateLits(std::vector &lits); - - expr SimplifyOr(std::vector &lits); - - expr SimplifyAnd(std::vector &lits); - - void SetAnnotation(Node *root, const expr &t); - - void AddEdgeToSolver(Edge *edge); - - void AddEdgeToSolver(implicant_solver &aux_solver, Edge *edge); - - void AddToProofCore(hash_set &core); - - void GetGroundLitsUnderQuants(hash_set *memo, const Term &f, std::vector &res, int under); - - Term StrengthenFormulaByCaseSplitting(const Term &f, std::vector &case_lits); - - expr NegateLit(const expr &f); - - expr GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox); - - bool IsVar(const expr &t); - - void GetVarsRec(hash_set &memo, const expr &cnst, std::vector &vars); - - expr UnhoistPullRec(hash_map & memo, const expr &w, hash_map & init_defs, hash_map & const_params, hash_map &const_params_inv, std::vector &new_params); - - void AddParamsToTransformer(Transformer &trans, const std::vector ¶ms); - - expr AddParamsToApp(const expr &app, const func_decl &new_decl, const std::vector ¶ms); - - expr GetRelRec(hash_set &memo, const expr &t, const func_decl &rel); - - expr GetRel(Edge *edge, int child_idx); - - void GetDefs(const expr &cnst, hash_map &defs); - - void GetDefsRec(const expr &cnst, hash_map &defs); - - void AddParamsToNode(Node *node, const std::vector ¶ms); - - void UnhoistLoop(Edge *loop_edge, Edge *init_edge); - - void Unhoist(); - - Term ElimIteRec(hash_map &memo, const Term &t, std::vector &cnsts); - - Term ElimIte(const Term &t); - - void MarkLiveNodes(hash_map > &outgoing, hash_set &live_nodes, Node *node); - - virtual void slvr_add(const expr &e); - - virtual void slvr_pop(int i); - - virtual void slvr_push(); - - virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = nullptr, unsigned *core_size = nullptr, expr *core = nullptr); - - virtual lbool ls_interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals = nullptr, - bool weak = false); - - virtual bool proof_core_contains(const expr &e); - - }; - - - /** RPFP solver base class. */ - - class Solver { - - public: - - class Counterexample { - private: - RPFP *tree; - RPFP::Node *root; - public: - Counterexample(){ - tree = nullptr; - root = nullptr; - } - Counterexample(RPFP *_tree, RPFP::Node *_root){ - tree = _tree; - root = _root; - } - ~Counterexample(){ - if(tree) delete tree; - } - void swap(Counterexample &other){ - std::swap(tree,other.tree); - std::swap(root,other.root); - } - void set(RPFP *_tree, RPFP::Node *_root){ - if(tree) delete tree; - tree = _tree; - root = _root; - } - void clear(){ - if(tree) delete tree; - tree = nullptr; - } - RPFP *get_tree() const {return tree;} - RPFP::Node *get_root() const {return root;} - private: - Counterexample &operator=(const Counterexample &); - Counterexample(const Counterexample &); - }; - - /** Solve the problem. You can optionally give an old - counterexample to use as a guide. This is chiefly useful for - abstraction refinement metholdologies, and is only used as a - heuristic. */ - - virtual bool Solve() = 0; - - virtual Counterexample &GetCounterexample() = 0; - - virtual bool SetOption(const std::string &option, const std::string &value) = 0; - - /** Learn heuristic information from another solver. This - is chiefly useful for abstraction refinement, when we want to - solve a series of similar problems. */ - - virtual void LearnFrom(Solver *old_solver) = 0; - - /** Return true if the solution be incorrect due to recursion bounding. - That is, the returned "solution" might contain all derivable facts up to the - given recursion bound, but not be actually a fixed point. - */ - - virtual bool IsResultRecursionBounded() = 0; - - virtual ~Solver(){} - - static Solver *Create(const std::string &solver_class, RPFP *rpfp); - - /** This can be called asynchrnously to cause Solve to throw a - Canceled exception at some time in the future. - */ - virtual void Cancel() = 0; - - /** Object thrown on cancellation */ - struct Canceled {}; - - /** Object thrown on incompleteness */ - struct Incompleteness {}; - }; -} - - -// Allow to hash on nodes and edges in deterministic way - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Duality::RPFP::Node *p) const { - return p->number; - } - }; -} - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Duality::RPFP::Edge *p) const { - return p->number; - } - }; -} - -// allow to walk sets of nodes without address dependency - -namespace std { - template <> - class less { - public: - bool operator()(Duality::RPFP::Node * const &s, Duality::RPFP::Node * const &t) const { - return s->number < t->number; // s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - -// #define LIMIT_STACK_WEIGHT 5 - - -namespace Duality { - /** Caching version of RPFP. Instead of asserting constraints, returns assumption literals */ - - class RPFP_caching : public RPFP { - public: - - /** appends assumption literals for edge to lits. if with_children is true, - includes that annotation of the edge's children. - */ - void AssertEdgeCache(Edge *e, std::vector &lits, bool with_children = false); - - /** appends assumption literals for node to lits */ - void AssertNodeCache(Node *, std::vector lits); - - /** check assumption lits, and return core */ - check_result CheckCore(const std::vector &assumps, std::vector &core); - - /** Clone another RPFP into this one, keeping a map */ - void Clone(RPFP *other); - - /** Get the clone of a node */ - Node *GetNodeClone(Node *other_node); - - /** Get the clone of an edge */ - Edge *GetEdgeClone(Edge *other_edge); - - /** Try to strengthen the parent of an edge */ - void GeneralizeCache(Edge *edge); - - /** Try to propagate some facts from children to parents of edge. - Return true if success. */ - bool PropagateCache(Edge *edge); - - /** Construct a caching RPFP using a LogicSolver */ - RPFP_caching(LogicSolver *_ls) : RPFP(_ls) {} - - /** Constraint an edge by its child's annotation. Return - assumption lits. */ - void ConstrainParentCache(Edge *parent, Node *child, std::vector &lits); - -#ifdef LIMIT_STACK_WEIGHT - virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false); -#endif - - ~RPFP_caching() override {} - - protected: - hash_map AssumptionLits; - hash_map NodeCloneMap; - hash_map EdgeCloneMap; - std::vector alit_stack; - std::vector alit_stack_sizes; - - // to let us use one solver per edge - struct edge_solver { - hash_map AssumptionLits; - uptr slvr; - }; - hash_map edge_solvers; - -#ifdef LIMIT_STACK_WEIGHT - struct weight_counter { - int val; - weight_counter(){val = 0;} - void swap(weight_counter &other){ - std::swap(val,other.val); - } - }; - - struct big_stack_entry { - weight_counter weight_added; - std::vector new_alits; - std::vector alit_stack; - std::vector alit_stack_sizes; - }; - - std::vector new_alits; - weight_counter weight_added; - std::vector big_stack; -#endif - - - - void GetAssumptionLits(const expr &fmla, std::vector &lits, hash_map *opt_map = nullptr); - - void GreedyReduceCache(std::vector &assumps, std::vector &core); - - void FilterCore(std::vector &core, std::vector &full_core); - void ConstrainEdgeLocalizedCache(Edge *e, const Term &tl, std::vector &lits); - - void slvr_add(const expr &e) override; - - void slvr_pop(int i) override; - - void slvr_push() override; - - check_result slvr_check(unsigned n = 0, expr * const assumptions = nullptr, unsigned *core_size = nullptr, expr *core = nullptr) override; - - lbool ls_interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals = nullptr, - bool weak = false) override; - - bool proof_core_contains(const expr &e) override; - - void GetTermTreeAssertionLiterals(TermTree *assumptions); - - void GetTermTreeAssertionLiteralsRec(TermTree *assumptions); - - edge_solver &SolverForEdge(Edge *edge, bool models, bool axioms); - - public: - struct scoped_solver_for_edge { - solver *orig_slvr; - RPFP_caching *rpfp; - edge_solver *es; - scoped_solver_for_edge(RPFP_caching *_rpfp, Edge *edge, bool models = false, bool axioms = false){ - rpfp = _rpfp; - orig_slvr = rpfp->ls->slvr; - es = &(rpfp->SolverForEdge(edge,models,axioms)); - rpfp->ls->slvr = es->slvr.get(); - rpfp->AssumptionLits.swap(es->AssumptionLits); - } - ~scoped_solver_for_edge(){ - rpfp->ls->slvr = orig_slvr; - rpfp->AssumptionLits.swap(es->AssumptionLits); - } - }; - - }; - -} diff --git a/src/duality/duality_profiling.cpp b/src/duality/duality_profiling.cpp deleted file mode 100644 index 6bb995e2d..000000000 --- a/src/duality/duality_profiling.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - duality_profiling.cpp - - Abstract: - - collection performance information for duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - - -#include -#include -#include -#include -#include - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#endif - -#include "duality/duality_wrapper.h" -#include "interp/iz3profiling.h" - -namespace Duality { - - void show_time(){ - output_time(std::cout,current_time()); - std::cout << "\n"; - } - - typedef std::map nmap; - - struct node { - std::string name; - clock_t time; - clock_t start_time; - nmap sub; - struct node *parent; - - node(); - } top; - - node::node(){ - time = 0; - parent = nullptr; - } - - struct node *current; - - struct init { - init(){ - top.name = "TOTAL"; - current = ⊤ - } - } initializer; - - struct time_entry { - clock_t t; - time_entry(){t = 0;}; - void add(clock_t incr){t += incr;} - }; - - struct ltstr - { - bool operator()(const char* s1, const char* s2) const - { - return strcmp(s1, s2) < 0; - } - }; - - typedef std::map tmap; - - static std::ostream *pfs; - - void print_node(node &top, int indent, tmap &totals){ - for(int i = 0; i < indent; i++) (*pfs) << " "; - (*pfs) << top.name; - int dots = 70 - 2 * indent - top.name.size(); - for(int i = 0; i second,indent+1,totals); - } - - void print_profile(std::ostream &os) { - pfs = &os; - top.time = 0; - for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++) - top.time += it->second.time; - tmap totals; - print_node(top,0,totals); - (*pfs) << "TOTALS:" << std::endl; - for(tmap::iterator it = totals.begin(); it != totals.end(); it++){ - (*pfs) << (it->first) << " "; - output_time(*pfs, it->second.t); - (*pfs) << std::endl; - } - profiling::print(os); // print the interpolation stats - } - - void timer_start(const char *name){ - node &child = current->sub[name]; - if(child.name.empty()){ // a new node - child.parent = current; - child.name = name; - } - child.start_time = current_time(); - current = &child; - } - - void timer_stop(const char *name){ - if (current->name != name || !current->parent) { -#if 0 - std::cerr << "imbalanced timer_start and timer_stop"; - exit(1); -#endif - // in case we lost a timer stop due to an exception - while (current->name != name && current->parent) - current = current->parent; - if (current->parent) { - current->time += (current_time() - current->start_time); - current = current->parent; - } - return; - } - current->time += (current_time() - current->start_time); - current = current->parent; - } -} diff --git a/src/duality/duality_profiling.h b/src/duality/duality_profiling.h deleted file mode 100755 index 5f0e5120c..000000000 --- a/src/duality/duality_profiling.h +++ /dev/null @@ -1,38 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - duality_profiling.h - - Abstract: - - collection performance information for duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - -#ifndef DUALITYPROFILING_H -#define DUALITYPROFILING_H - -#include - -namespace Duality { - /** Start a timer with given name */ - void timer_start(const char *); - /** Stop a timer with given name */ - void timer_stop(const char *); - /** Print out timings */ - void print_profile(std::ostream &s); - /** Show the current time. */ - void show_time(); -} - -#endif - diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp deleted file mode 100644 index 3358eb45e..000000000 --- a/src/duality/duality_rpfp.cpp +++ /dev/null @@ -1,4250 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - duality_rpfp.h - - Abstract: - - implements relational post-fixedpoint problem - (RPFP) data structure. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - - - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#endif - -#include -#include -#include -#include - - -#include "duality/duality.h" -#include "duality/duality_profiling.h" - -// TODO: do we need these? -#ifdef Z3OPS - -class Z3_subterm_truth { -public: - virtual bool eval(Z3_ast f) = 0; - ~Z3_subterm_truth(){} -}; - -Z3_subterm_truth *Z3_mk_subterm_truth(Z3_context ctx, Z3_model model); - -#endif - -#include - -// TODO: use something official for this -int debug_gauss = 0; - -namespace Duality { - - static char string_of_int_buffer[20]; - - const char *Z3User::string_of_int(int n){ - sprintf(string_of_int_buffer,"%d",n); - return string_of_int_buffer; - } - - RPFP::Term RPFP::SuffixVariable(const Term &t, int n) - { - std::string name = t.decl().name().str() + "_" + string_of_int(n); - return ctx.constant(name.c_str(), t.get_sort()); - } - - RPFP::Term RPFP::HideVariable(const Term &t, int n) - { - std::string name = std::string("@p_") + t.decl().name().str() + "_" + string_of_int(n); - return ctx.constant(name.c_str(), t.get_sort()); - } - - void RPFP::RedVars(Node *node, Term &b, std::vector &v) - { - int idx = node->number; - if(HornClauses) - b = ctx.bool_val(true); - else { - std::string name = std::string("@b_") + string_of_int(idx); - symbol sym = ctx.str_symbol(name.c_str()); - b = ctx.constant(sym,ctx.bool_sort()); - } - // ctx.constant(name.c_str(), ctx.bool_sort()); - v = node->Annotation.IndParams; - for(unsigned i = 0; i < v.size(); i++) - v[i] = SuffixVariable(v[i],idx); - } - - void Z3User::SummarizeRec(hash_set &memo, std::vector &lits, int &ops, const Term &t){ - if(memo.find(t) != memo.end()) - return; - memo.insert(t); - if(t.is_app()){ - decl_kind k = t.decl().get_decl_kind(); - if (k == And || k == Or || k == Not || k == Implies || k == Iff) { - ops++; - int nargs = t.num_args(); - for (int i = 0; i < nargs; i++) - SummarizeRec(memo, lits, ops, t.arg(i)); - return; - } - } - lits.push_back(t); - } - - int RPFP::CumulativeDecisions(){ -#if 0 - std::string stats = Z3_statistics_to_string(ctx); - int pos = stats.find("decisions:"); - pos += 10; - int end = stats.find('\n',pos); - std::string val = stats.substr(pos,end-pos); - return atoi(val.c_str()); -#endif - return slvr().get_num_decisions(); - } - - - void Z3User::Summarize(const Term &t){ - hash_set memo; std::vector lits; int ops = 0; - SummarizeRec(memo, lits, ops, t); - std::cout << ops << ": "; - for(unsigned i = 0; i < lits.size(); i++){ - if(i > 0) std::cout << ", "; - std::cout << lits[i]; - } - } - - int Z3User::CountOperatorsRec(hash_set &memo, const Term &t){ - if(memo.find(t) != memo.end()) - return 0; - memo.insert(t); - if(t.is_app()){ - decl_kind k = t.decl().get_decl_kind(); - if (k == And || k == Or) { - int count = 1; - int nargs = t.num_args(); - for (int i = 0; i < nargs; i++) - count += CountOperatorsRec(memo, t.arg(i)); - return count; - } - return 0; - } - if(t.is_quantifier()){ - int nbv = t.get_quantifier_num_bound(); - return CountOperatorsRec(memo,t.body()) + 2 * nbv; // count 2 for each quantifier - } - return 0; - } - - int Z3User::CountOperators(const Term &t){ - hash_set memo; - return CountOperatorsRec(memo,t); - } - - - Z3User::Term Z3User::conjoin(const std::vector &args){ - return ctx.make(And,args); - } - - Z3User::Term Z3User::sum(const std::vector &args){ - return ctx.make(Plus,args); - } - - RPFP::Term RPFP::RedDualRela(Edge *e, std::vector &args, int idx){ - Node *child = e->Children[idx]; - Term b(ctx); - std::vector v; - RedVars(child, b, v); - for (unsigned i = 0; i < args.size(); i++) { - if (eq(args[i].get_sort(), ctx.bool_sort())) - args[i] = ctx.make(Iff, args[i], v[i]); - else - args[i] = args[i] == v[i]; - } - return args.size() > 0 ? (b && conjoin(args)) : b; - } - - Z3User::Term Z3User::CloneQuantifier(const Term &t, const Term &new_body){ -#if 0 - Z3_context c = ctx; - Z3_ast a = t; - std::vector pats; - int num_pats = Z3_get_quantifier_num_patterns(c,a); - for(int i = 0; i < num_pats; i++) - pats.push_back(Z3_get_quantifier_pattern_ast(c,a,i)); - std::vector no_pats; - int num_no_pats = Z3_get_quantifier_num_patterns(c,a); - for(int i = 0; i < num_no_pats; i++) - no_pats.push_back(Z3_get_quantifier_no_pattern_ast(c,a,i)); - int bound = Z3_get_quantifier_num_bound(c,a); - std::vector sorts; - std::vector names; - for(int i = 0; i < bound; i++){ - sorts.push_back(Z3_get_quantifier_bound_sort(c,a,i)); - names.push_back(Z3_get_quantifier_bound_name(c,a,i)); - } - Z3_ast foo = Z3_mk_quantifier_ex(c, - Z3_is_quantifier_forall(c,a), - Z3_get_quantifier_weight(c,a), - 0, - 0, - num_pats, - VEC2PTR(pats), - num_no_pats, - VEC2PTR(no_pats), - bound, - VEC2PTR(sorts), - VEC2PTR(names), - new_body); - return expr(ctx,foo); -#endif - return clone_quantifier(t,new_body); - } - - - RPFP::Term RPFP::LocalizeRec(Edge *e, hash_map &memo, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - hash_map::iterator it = e->varMap.find(t); - if (it != e->varMap.end()){ - res = it->second; - return res; - } - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(LocalizeRec(e, memo, t.arg(i))); - hash_map::iterator rit = e->relMap.find(f); - if (rit != e->relMap.end()) - res = RedDualRela(e, args, (rit->second)); - else { - if (args.size() == 0 && f.get_decl_kind() == Uninterpreted && !ls->is_constant(f)) { - res = HideVariable(t, e->number); - } - else { - res = f(args.size(), VEC2PTR(args)); - } - } - } - else if (t.is_quantifier()) { - std::vector pats; - t.get_patterns(pats); - for (unsigned i = 0; i < pats.size(); i++) - pats[i] = LocalizeRec(e, memo, pats[i]); - Term body = LocalizeRec(e, memo, t.body()); - res = clone_quantifier(t, body, pats); - } - else res = t; - return res; - } - - void RPFP::SetEdgeMaps(Edge *e){ - timer_start("SetEdgeMaps"); - e->relMap.clear(); - e->varMap.clear(); - for(unsigned i = 0; i < e->F.RelParams.size(); i++){ - e->relMap[e->F.RelParams[i]] = i; - } - Term b(ctx); - std::vector v; - RedVars(e->Parent, b, v); - for(unsigned i = 0; i < e->F.IndParams.size(); i++){ - // func_decl parentParam = e->Parent.Annotation.IndParams[i]; - expr oldname = e->F.IndParams[i]; - expr newname = v[i]; - e->varMap[oldname] = newname; - } - timer_stop("SetEdgeMaps"); - - } - - - RPFP::Term RPFP::Localize(Edge *e, const Term &t){ - timer_start("Localize"); - hash_map memo; - if(e->F.IndParams.size() > 0 && e->varMap.empty()) - SetEdgeMaps(e); // TODO: why is this needed? - Term res = LocalizeRec(e,memo,t); - timer_stop("Localize"); - return res; - } - - - RPFP::Term RPFP::ReducedDualEdge(Edge *e) - { - SetEdgeMaps(e); - timer_start("RedVars"); - Term b(ctx); - std::vector v; - RedVars(e->Parent, b, v); - timer_stop("RedVars"); - // ast_to_track = (ast)b; - return implies(b, Localize(e, e->F.Formula)); - } - - TermTree *RPFP::ToTermTree(Node *root, Node *skip_descendant) - { - if(skip_descendant && root == skip_descendant) - return new TermTree(ctx.bool_val(true)); - Edge *e = root->Outgoing; - if(!e) return new TermTree(ctx.bool_val(true), std::vector()); - std::vector children(e->Children.size()); - for(unsigned i = 0; i < children.size(); i++) - children[i] = ToTermTree(e->Children[i],skip_descendant); - // Term top = ReducedDualEdge(e); - Term top = e->dual.null() ? ctx.bool_val(true) : e->dual; - TermTree *res = new TermTree(top, children); - for(unsigned i = 0; i < e->constraints.size(); i++) - res->addTerm(e->constraints[i]); - return res; - } - - TermTree *RPFP::GetGoalTree(Node *root){ - std::vector children(1); - children[0] = ToGoalTree(root); - return new TermTree(ctx.bool_val(false),children); - } - - TermTree *RPFP::ToGoalTree(Node *root) - { - Term b(ctx); - std::vector v; - RedVars(root, b, v); - Term goal = root->Name(v); - Edge *e = root->Outgoing; - if(!e) return new TermTree(goal, std::vector()); - std::vector children(e->Children.size()); - for(unsigned i = 0; i < children.size(); i++) - children[i] = ToGoalTree(e->Children[i]); - // Term top = ReducedDualEdge(e); - return new TermTree(goal, children); - } - - Z3User::Term Z3User::SubstRec(hash_map &memo, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(SubstRec(memo, t.arg(i))); - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()) { - std::vector pats; - t.get_patterns(pats); - for (unsigned i = 0; i < pats.size(); i++) - pats[i] = SubstRec(memo, pats[i]); - Term body = SubstRec(memo, t.body()); - res = clone_quantifier(t, body, pats); - } - // res = CloneQuantifier(t,SubstRec(memo, t.body())); - else res = t; - return res; - } - - Z3User::Term Z3User::SubstRec(hash_map &memo, hash_map &map, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(SubstRec(memo, map, t.arg(i))); - hash_map::iterator it = map.find(f); - if (it != map.end()) - f = it->second; - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()) { - std::vector pats; - t.get_patterns(pats); - for (unsigned i = 0; i < pats.size(); i++) - pats[i] = SubstRec(memo, map, pats[i]); - Term body = SubstRec(memo, map, t.body()); - res = clone_quantifier(t, body, pats); - } - // res = CloneQuantifier(t,SubstRec(memo, t.body())); - else res = t; - return res; - } - - Z3User::Term Z3User::ExtractStores(hash_map &memo, const Term &t, std::vector &cnstrs, hash_map &renaming) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(ExtractStores(memo, t.arg(i), cnstrs, renaming)); - res = f(args.size(), VEC2PTR(args)); - if (f.get_decl_kind() == Store) { - func_decl fresh = ctx.fresh_func_decl("@arr", res.get_sort()); - expr y = fresh(); - expr equ = ctx.make(Equal, y, res); - cnstrs.push_back(equ); - renaming[y] = res; - res = y; - } - } - else res = t; - return res; - } - - - bool Z3User::IsLiteral(const expr &lit, expr &atom, expr &val){ - if (!(lit.is_quantifier() && IsClosedFormula(lit))) { - if (!lit.is_app()) - return false; - decl_kind k = lit.decl().get_decl_kind(); - if (k == Not) { - if (IsLiteral(lit.arg(0), atom, val)) { - val = eq(val, ctx.bool_val(true)) ? ctx.bool_val(false) : ctx.bool_val(true); - return true; - } - return false; - } - if (k == And || k == Or || k == Iff || k == Implies) - return false; - } - atom = lit; - val = ctx.bool_val(true); - return true; - } - - expr Z3User::Negate(const expr &f){ - if(f.is_app() && f.decl().get_decl_kind() == Not) - return f.arg(0); - else if(eq(f,ctx.bool_val(true))) - return ctx.bool_val(false); - else if(eq(f,ctx.bool_val(false))) - return ctx.bool_val(true); - return !f; - } - - expr Z3User::ReduceAndOr(const std::vector &args, bool is_and, std::vector &res){ - for(unsigned i = 0; i < args.size(); i++) - if (!eq(args[i], ctx.bool_val(is_and))) { - if (eq(args[i], ctx.bool_val(!is_and))) - return ctx.bool_val(!is_and); - res.push_back(args[i]); - } - return expr(); - } - - expr Z3User::FinishAndOr(const std::vector &args, bool is_and){ - if(args.size() == 0) - return ctx.bool_val(is_and); - if(args.size() == 1) - return args[0]; - return ctx.make(is_and ? And : Or,args); - } - - expr Z3User::SimplifyAndOr(const std::vector &args, bool is_and){ - std::vector sargs; - expr res = ReduceAndOr(args,is_and,sargs); - if(!res.null()) return res; - return FinishAndOr(sargs,is_and); - } - - expr Z3User::PullCommonFactors(std::vector &args, bool is_and){ - - // first check if there's anything to do... - if(args.size() < 2) - return FinishAndOr(args,is_and); - for (unsigned i = 0; i < args.size(); i++) { - const expr &a = args[i]; - if (!(a.is_app() && a.decl().get_decl_kind() == (is_and ? Or : And))) - return FinishAndOr(args, is_and); - } - std::vector common; - for (unsigned i = 0; i < args.size(); i++) { - unsigned n = args[i].num_args(); - std::vector v(n), w; - for (unsigned j = 0; j < n; j++) - v[j] = args[i].arg(j); - std::less comp; - std::sort(v.begin(), v.end(), comp); - if (i == 0) - common.swap(v); - else { - std::set_intersection(common.begin(), common.end(), v.begin(), v.end(), std::inserter(w, w.begin()), comp); - common.swap(w); - } - } - if(common.empty()) - return FinishAndOr(args,is_and); - std::set common_set(common.begin(),common.end()); - for(unsigned i = 0; i < args.size(); i++){ - unsigned n = args[i].num_args(); - std::vector lits; - for (unsigned j = 0; j < n; j++) { - const expr b = args[i].arg(j); - if (common_set.find(b) == common_set.end()) - lits.push_back(b); - } - args[i] = SimplifyAndOr(lits,!is_and); - } - common.push_back(SimplifyAndOr(args,is_and)); - return SimplifyAndOr(common,!is_and); - } - - expr Z3User::ReallySimplifyAndOr(const std::vector &args, bool is_and){ - std::vector sargs; - expr res = ReduceAndOr(args,is_and,sargs); - if(!res.null()) return res; - return PullCommonFactors(sargs,is_and); - } - - Z3User::Term Z3User::SubstAtomTriv(const expr &foo, const expr &atom, const expr &val){ - if(eq(foo,atom)) - return val; - else if(foo.is_app() && foo.decl().get_decl_kind() == Not && eq(foo.arg(0),atom)) - return Negate(val); - else - return foo; - } - - Z3User::Term Z3User::PushQuantifier(const expr &t, const expr &body, bool is_forall){ - if (t.get_quantifier_num_bound() == 1) { - std::vector fmlas, free, not_free; - CollectJuncts(body, fmlas, is_forall ? Or : And, false); - for (unsigned i = 0; i < fmlas.size(); i++) { - const expr &fmla = fmlas[i]; - if (fmla.has_free(0)) - free.push_back(fmla); - else - not_free.push_back(fmla); - } - decl_kind op = is_forall ? Or : And; - if (free.empty()) - return DeleteBound(0, 1, SimplifyAndOr(not_free, op == And)); - expr q = clone_quantifier(is_forall ? Forall : Exists, t, SimplifyAndOr(free, op == And)); - if (!not_free.empty()) - q = ctx.make(op, q, DeleteBound(0, 1, SimplifyAndOr(not_free, op == And))); - return q; - } - return clone_quantifier(is_forall ? Forall : Exists,t,body); - } - - Z3User::Term Z3User::CloneQuantAndSimp(const expr &t, const expr &body, bool is_forall) { - if (body.is_app()) { - if (body.decl().get_decl_kind() == (is_forall ? And : Or)) { // quantifier distributes - int nargs = body.num_args(); - std::vector args(nargs); - for (int i = 0; i < nargs; i++) - args[i] = CloneQuantAndSimp(t, body.arg(i), is_forall); - return SimplifyAndOr(args, body.decl().get_decl_kind() == And); - } - else if (body.decl().get_decl_kind() == (is_forall ? Or : And)) { // quantifier distributes - return PushQuantifier(t, body, is_forall); // may distribute partially - } - else if (body.decl().get_decl_kind() == Not) { - return ctx.make(Not, CloneQuantAndSimp(t, body.arg(0), !is_forall)); - } - } - if (t.get_quantifier_num_bound() == 1 && !body.has_free(0)) - return DeleteBound(0, 1, body); // drop the quantifier - return clone_quantifier(is_forall ? Forall : Exists, t, body); - } - - Z3User::Term Z3User::CloneQuantAndSimp(const expr &t, const expr &body){ - return CloneQuantAndSimp(t,body,t.is_quantifier_forall()); - } - - Z3User::Term Z3User::SubstAtom(hash_map &memo, const expr &t, const expr &atom, const expr &val) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - decl_kind k = f.get_decl_kind(); - - // TODO: recur here, but how much? We don't want to be quadractic in formula size - - if (k == And || k == Or) { - int nargs = t.num_args(); - std::vector args(nargs); - for (int i = 0; i < nargs; i++) - args[i] = SubstAtom(memo, t.arg(i), atom, val); - res = ReallySimplifyAndOr(args, k == And); - return res; - } - } - else if (t.is_quantifier() && atom.is_quantifier()) { - if (eq(t, atom)) - res = val; - else - res = clone_quantifier(t, SubstAtom(memo, t.body(), atom, val)); - return res; - } - res = SubstAtomTriv(t, atom, val); - return res; - } - - void Z3User::RemoveRedundancyOp(bool pol, std::vector &args, hash_map &smemo) { - for (unsigned i = 0; i < args.size(); i++) { - const expr &lit = args[i]; - expr atom, val; - if (IsLiteral(lit, atom, val)) { - if (atom.is_app() && atom.decl().get_decl_kind() == Equal) - if (pol ? eq(val, ctx.bool_val(true)) : eq(val, ctx.bool_val(false))) { - expr lhs = atom.arg(0), rhs = atom.arg(1); - if (lhs.is_numeral()) - std::swap(lhs, rhs); - if (rhs.is_numeral() && lhs.is_app()) { - for (unsigned j = 0; j < args.size(); j++) - if (j != i) { - smemo.clear(); - smemo[lhs] = rhs; - args[j] = SubstRec(smemo, args[j]); - } - } - } - for (unsigned j = 0; j < args.size(); j++) - if (j != i) { - smemo.clear(); - args[j] = SubstAtom(smemo, args[j], atom, pol ? val : !val); - } - } - } - } - - - Z3User::Term Z3User::RemoveRedundancyRec(hash_map &memo, hash_map &smemo, const Term &t) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(RemoveRedundancyRec(memo, smemo, t.arg(i))); - - decl_kind k = f.get_decl_kind(); - if (k == And) { - RemoveRedundancyOp(true, args, smemo); - res = ReallySimplifyAndOr(args, true); - } - else if (k == Or) { - RemoveRedundancyOp(false, args, smemo); - res = ReallySimplifyAndOr(args, false); - } - else { - if (k == Equal && args[0].get_id() > args[1].get_id()) - std::swap(args[0], args[1]); - res = f(args.size(), VEC2PTR(args)); - } - } - else if (t.is_quantifier()) { - Term body = RemoveRedundancyRec(memo, smemo, t.body()); - res = CloneQuantAndSimp(t, body); - } - else res = t; - return res; - } - - Z3User::Term Z3User::RemoveRedundancy(const Term &t){ - hash_map memo; - hash_map smemo; - return RemoveRedundancyRec(memo,smemo,t); - } - - Z3User::Term Z3User::AdjustQuantifiers(const Term &t) - { - if(t.is_quantifier() || (t.is_app() && t.has_quantifiers())) - return t.qe_lite(); - return t; - } - - Z3User::Term Z3User::IneqToEqRec(hash_map &memo, const Term &t) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(IneqToEqRec(memo, t.arg(i))); - - decl_kind k = f.get_decl_kind(); - if (k == And) { - for (int i = 0; i < nargs - 1; i++) { - if ((args[i].is_app() && args[i].decl().get_decl_kind() == Geq && - args[i + 1].is_app() && args[i + 1].decl().get_decl_kind() == Leq) - || - (args[i].is_app() && args[i].decl().get_decl_kind() == Leq && - args[i + 1].is_app() && args[i + 1].decl().get_decl_kind() == Geq)) - if (eq(args[i].arg(0), args[i + 1].arg(0)) && eq(args[i].arg(1), args[i + 1].arg(1))) { - args[i] = ctx.make(Equal, args[i].arg(0), args[i].arg(1)); - args[i + 1] = ctx.bool_val(true); - } - } - } - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()) { - Term body = IneqToEqRec(memo, t.body()); - res = clone_quantifier(t, body); - } - else res = t; - return res; - } - - Z3User::Term Z3User::IneqToEq(const Term &t){ - hash_map memo; - return IneqToEqRec(memo,t); - } - - Z3User::Term Z3User::SubstRecHide(hash_map &memo, const Term &t, int number) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - if (nargs == 0 && f.get_decl_kind() == Uninterpreted) { - std::string name = std::string("@q_") + t.decl().name().str() + "_" + string_of_int(number); - res = ctx.constant(name.c_str(), t.get_sort()); - return res; - } - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(SubstRec(memo, t.arg(i))); - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()) - res = CloneQuantifier(t, SubstRec(memo, t.body())); - else res = t; - return res; - } - - RPFP::Term RPFP::SubstParams(const std::vector &from, - const std::vector &to, const Term &t) { - hash_map memo; - bool some_diff = false; - for (unsigned i = 0; i < from.size(); i++) - if (i < to.size() && !eq(from[i], to[i])) { - memo[from[i]] = to[i]; - some_diff = true; - } - return some_diff ? SubstRec(memo, t) : t; - } - - RPFP::Term RPFP::SubstParamsNoCapture(const std::vector &from, - const std::vector &to, const Term &t) { - hash_map memo; - bool some_diff = false; - for (unsigned i = 0; i < from.size(); i++) - if (i < to.size() && !eq(from[i], to[i])) { - memo[from[i]] = to[i]; - // if the new param is not being mapped to anything else, we need to rename it to prevent capture - // note, if the new param *is* mapped later in the list, it will override this substitution - const expr &w = to[i]; - if (memo.find(w) == memo.end()) { - std::string old_name = w.decl().name().str(); - func_decl fresh = ctx.fresh_func_decl(old_name.c_str(), w.get_sort()); - expr y = fresh(); - memo[w] = y; - } - some_diff = true; - } - return some_diff ? SubstRec(memo, t) : t; - } - - - - RPFP::Transformer RPFP::Fuse(const std::vector &trs) { - assert(!trs.empty()); - const std::vector ¶ms = trs[0]->IndParams; - std::vector fmlas(trs.size()); - fmlas[0] = trs[0]->Formula; - for (unsigned i = 1; i < trs.size(); i++) - fmlas[i] = SubstParamsNoCapture(trs[i]->IndParams, params, trs[i]->Formula); - std::vector rel_params = trs[0]->RelParams; - for (unsigned i = 1; i < trs.size(); i++) { - const std::vector ¶ms2 = trs[i]->RelParams; - hash_map map; - for (unsigned j = 0; j < params2.size(); j++) { - func_decl rel = RenumberPred(params2[j], rel_params.size()); - rel_params.push_back(rel); - map[params2[j]] = rel; - } - hash_map memo; - fmlas[i] = SubstRec(memo, map, fmlas[i]); - } - return Transformer(rel_params, params, ctx.make(Or, fmlas), trs[0]->owner); - } - - - void Z3User::Strengthen(Term &x, const Term &y) - { - if (eq(x,ctx.bool_val(true))) - x = y; - else - x = x && y; - } - - void RPFP::SetAnnotation(Node *root, const expr &t){ - hash_map memo; - Term b; - std::vector v; - RedVars(root, b, v); - memo[b] = ctx.bool_val(true); - for (unsigned i = 0; i < v.size(); i++) - memo[v[i]] = root->Annotation.IndParams[i]; - Term annot = SubstRec(memo, t); - // Strengthen(ref root.Annotation.Formula, annot); - root->Annotation.Formula = annot; - } - - void RPFP::DecodeTree(Node *root, TermTree *interp, int persist) { - std::vector &ic = interp->getChildren(); - if (ic.size() > 0) { - std::vector &nc = root->Outgoing->Children; - for (unsigned i = 0; i < nc.size(); i++) - DecodeTree(nc[i], ic[i], persist); - } - SetAnnotation(root, interp->getTerm()); -#if 0 - if(persist != 0) - Z3_persist_ast(ctx,root->Annotation.Formula,persist); -#endif - } - - RPFP::Term RPFP::GetUpperBound(Node *n) - { - // TODO: cache this - Term b(ctx); std::vector v; - RedVars(n, b, v); - hash_map memo; - for (unsigned int i = 0; i < v.size(); i++) - memo[n->Bound.IndParams[i]] = v[i]; - Term cnst = SubstRec(memo, n->Bound.Formula); - return b && !cnst; - } - - RPFP::Term RPFP::GetAnnotation(Node *n) - { - if(eq(n->Annotation.Formula,ctx.bool_val(true))) - return n->Annotation.Formula; - // TODO: cache this - Term b(ctx); std::vector v; - RedVars(n, b, v); - hash_map memo; - for (unsigned i = 0; i < v.size(); i++) - memo[n->Annotation.IndParams[i]] = v[i]; - Term cnst = SubstRec(memo, n->Annotation.Formula); - return !b || cnst; - } - - RPFP::Term RPFP::GetUnderapprox(Node *n) - { - // TODO: cache this - Term b(ctx); std::vector v; - RedVars(n, b, v); - hash_map memo; - for (unsigned i = 0; i < v.size(); i++) - memo[n->Underapprox.IndParams[i]] = v[i]; - Term cnst = SubstRecHide(memo, n->Underapprox.Formula, n->number); - return !b || cnst; - } - - TermTree *RPFP::AddUpperBound(Node *root, TermTree *t) - { - Term f = !((ast)(root->dual)) ? ctx.bool_val(true) : root->dual; - std::vector c(1); c[0] = t; - return new TermTree(f, c); - } - -#if 0 - void RPFP::WriteInterps(System.IO.StreamWriter f, TermTree t) - { - foreach (var c in t.getChildren()) - WriteInterps(f, c); - f.WriteLine(t.getTerm()); - } -#endif - - - expr RPFP::GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox) { - if (e->dual.null()) { - timer_start("ReducedDualEdge"); - e->dual = ReducedDualEdge(e); - timer_stop("ReducedDualEdge"); - timer_start("getting children"); - if (underapprox) { - std::vector cus(e->Children.size()); - for (unsigned i = 0; i < e->Children.size(); i++) - cus[i] = !UnderapproxFlag(e->Children[i]) || GetUnderapprox(e->Children[i]); - expr cnst = conjoin(cus); - e->dual = e->dual && cnst; - } - timer_stop("getting children"); - timer_start("Persisting"); - std::list::reverse_iterator it = stack.rbegin(); - for (int i = 0; i < persist && it != stack.rend(); i++) - it++; - if (it != stack.rend()) - it->edges.push_back(e); - timer_stop("Persisting"); - //Console.WriteLine("{0}", cnst); - } - return e->dual; - } - - /** For incremental solving, asserts the constraint associated - * with this edge in the SMT context. If this edge is removed, - * you must pop the context accordingly. The second argument is - * the number of pushes we are inside. The constraint formula - * will survive "persist" pops of the context. If you plan - * to reassert the edge after popping the context once, - * you can save time re-constructing the formula by setting - * "persist" to one. If you set "persist" too high, however, - * you could have a memory leak. - * - * The flag "with children" causes the annotations of the children - * to be asserted. The flag underapprox causes the underapproximations - * of the children to be asserted *conditionally*. See Check() on - * how to actually enforce these constraints. - * - */ - - void RPFP::AssertEdge(Edge *e, int persist, bool with_children, bool underapprox) { - if (eq(e->F.Formula, ctx.bool_val(true)) && (!with_children || e->Children.empty())) - return; - expr fmla = GetEdgeFormula(e, persist, with_children, underapprox); - timer_start("solver add"); - slvr_add(e->dual); - timer_stop("solver add"); - if (with_children) - for (unsigned i = 0; i < e->Children.size(); i++) - ConstrainParent(e, e->Children[i]); - } - - -#ifdef LIMIT_STACK_WEIGHT - void RPFP_caching::AssertEdge(Edge *e, int persist, bool with_children, bool underapprox) - { - unsigned old_new_alits = new_alits.size(); - if(eq(e->F.Formula,ctx.bool_val(true)) && (!with_children || e->Children.empty())) - return; - expr fmla = GetEdgeFormula(e, persist, with_children, underapprox); - timer_start("solver add"); - slvr_add(e->dual); - timer_stop("solver add"); - if(old_new_alits < new_alits.size()) - weight_added.val++; - if(with_children) - for(unsigned i = 0; i < e->Children.size(); i++) - ConstrainParent(e,e->Children[i]); - } -#endif - - // caching verion of above - void RPFP_caching::AssertEdgeCache(Edge *e, std::vector &lits, bool with_children) { - if (eq(e->F.Formula, ctx.bool_val(true)) && (!with_children || e->Children.empty())) - return; - expr fmla = GetEdgeFormula(e, 0, with_children, false); - GetAssumptionLits(fmla, lits); - if (with_children) - for (unsigned i = 0; i < e->Children.size(); i++) - ConstrainParentCache(e, e->Children[i], lits); - } - - void RPFP::slvr_add(const expr &e){ - slvr().add(e); - } - - void RPFP_caching::slvr_add(const expr &e){ - GetAssumptionLits(e,alit_stack); - } - - void RPFP::slvr_pop(int i){ - slvr().pop(i); - } - - void RPFP::slvr_push(){ - slvr().push(); - } - - void RPFP_caching::slvr_pop(int i){ - for(int j = 0; j < i; j++){ -#ifdef LIMIT_STACK_WEIGHT - if(alit_stack_sizes.empty()){ - if(big_stack.empty()) - throw "stack underflow"; - for(unsigned k = 0; k < new_alits.size(); k++){ - if(AssumptionLits.find(new_alits[k]) == AssumptionLits.end()) - throw "foo!"; - AssumptionLits.erase(new_alits[k]); - } - big_stack_entry &bsb = big_stack.back(); - bsb.alit_stack_sizes.swap(alit_stack_sizes); - bsb.alit_stack.swap(alit_stack); - bsb.new_alits.swap(new_alits); - bsb.weight_added.swap(weight_added); - big_stack.pop_back(); - slvr().pop(1); - continue; - } -#endif - alit_stack.resize(alit_stack_sizes.back()); - alit_stack_sizes.pop_back(); - } - } - - void RPFP_caching::slvr_push(){ -#ifdef LIMIT_STACK_WEIGHT - if(weight_added.val > LIMIT_STACK_WEIGHT){ - big_stack.resize(big_stack.size()+1); - big_stack_entry &bsb = big_stack.back(); - bsb.alit_stack_sizes.swap(alit_stack_sizes); - bsb.alit_stack.swap(alit_stack); - bsb.new_alits.swap(new_alits); - bsb.weight_added.swap(weight_added); - slvr().push(); - for(unsigned i = 0; i < bsb.alit_stack.size(); i++) - slvr().add(bsb.alit_stack[i]); - return; - } -#endif - alit_stack_sizes.push_back(alit_stack.size()); - } - - check_result RPFP::slvr_check(unsigned n, expr * const assumptions, unsigned *core_size, expr *core){ - return slvr().check(n, assumptions, core_size, core); - } - - check_result RPFP_caching::slvr_check(unsigned n, expr * const assumptions, unsigned *core_size, expr *core){ - unsigned oldsiz = alit_stack.size(); - if(n && assumptions) - std::copy(assumptions,assumptions+n,std::inserter(alit_stack,alit_stack.end())); - check_result res; - if (core_size && core) { - std::vector full_core(alit_stack.size()), core1(n); - std::copy(assumptions, assumptions + n, core1.begin()); - res = slvr().check(alit_stack.size(), VEC2PTR(alit_stack), core_size, VEC2PTR(full_core)); - full_core.resize(*core_size); - if (res == unsat) { - FilterCore(core1, full_core); - *core_size = core1.size(); - std::copy(core1.begin(), core1.end(), core); - } - } - else - res = slvr().check(alit_stack.size(), VEC2PTR(alit_stack)); - alit_stack.resize(oldsiz); - return res; - } - - lbool RPFP::ls_interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals, - bool weak) { - return ls->interpolate_tree(assumptions, interpolants, _model, goals, weak); - } - - lbool RPFP_caching::ls_interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals, - bool weak) { - GetTermTreeAssertionLiterals(assumptions); - return ls->interpolate_tree(assumptions, interpolants, _model, goals, weak); - } - - void RPFP_caching::GetTermTreeAssertionLiteralsRec(TermTree *assumptions){ - std::vector alits; - hash_map map; - GetAssumptionLits(assumptions->getTerm(),alits,&map); - std::vector &ts = assumptions->getTerms(); - for(unsigned i = 0; i < ts.size(); i++) - GetAssumptionLits(ts[i],alits,&map); - assumptions->setTerm(ctx.bool_val(true)); - ts = alits; - for(unsigned i = 0; i < alits.size(); i++) - ts.push_back(ctx.make(Implies,alits[i],map[alits[i]])); - for(unsigned i = 0; i < assumptions->getChildren().size(); i++) - GetTermTreeAssertionLiterals(assumptions->getChildren()[i]); - return; - } - - void RPFP_caching::GetTermTreeAssertionLiterals(TermTree *assumptions) { - // optimize binary case - if (assumptions->getChildren().size() == 1 - && assumptions->getChildren()[0]->getChildren().size() == 0) { - hash_map map; - TermTree *child = assumptions->getChildren()[0]; - std::vector dummy; - GetAssumptionLits(child->getTerm(), dummy, &map); - std::vector &ts = child->getTerms(); - for (unsigned i = 0; i < ts.size(); i++) - GetAssumptionLits(ts[i], dummy, &map); - std::vector assumps; - slvr().get_proof().get_assumptions(assumps); - if (!proof_core) { // save the proof core for later use - proof_core = new hash_set < ast > ; - for (unsigned i = 0; i < assumps.size(); i++) - proof_core->insert(assumps[i]); - } - std::vector *cnsts[2] = { &child->getTerms(), &assumptions->getTerms() }; - for (unsigned i = 0; i < assumps.size(); i++) { - expr &as = assumps[i]; - expr alit = (as.is_app() && as.decl().get_decl_kind() == Implies) ? as.arg(0) : as; - bool isA = map.find(alit) != map.end(); - cnsts[isA ? 0 : 1]->push_back(as); - } - } - else - GetTermTreeAssertionLiteralsRec(assumptions); - } - - void RPFP::AddToProofCore(hash_set &core){ - std::vector assumps; - slvr().get_proof().get_assumptions(assumps); - for(unsigned i = 0; i < assumps.size(); i++) - core.insert(assumps[i]); - } - - void RPFP::ComputeProofCore(){ - if(!proof_core){ - proof_core = new hash_set; - AddToProofCore(*proof_core); - } - } - - - void RPFP_caching::GetAssumptionLits(const expr &fmla, std::vector &lits, hash_map *opt_map) { - std::vector conjs; - CollectConjuncts(fmla, conjs); - for (unsigned i = 0; i < conjs.size(); i++) { - const expr &conj = conjs[i]; - std::pair foo(conj, expr(ctx)); - std::pair::iterator, bool> bar = AssumptionLits.insert(foo); - Term &res = bar.first->second; - if (bar.second) { - func_decl pred = ctx.fresh_func_decl("@alit", ctx.bool_sort()); - res = pred(); -#ifdef LIMIT_STACK_WEIGHT - new_alits.push_back(conj); -#endif - slvr().add(ctx.make(Implies, res, conj)); - // std::cout << res << ": " << conj << "\n"; - } - if (opt_map) - (*opt_map)[res] = conj; - lits.push_back(res); - } - } - - void RPFP::ConstrainParent(Edge *parent, Node *child){ - ConstrainEdgeLocalized(parent,GetAnnotation(child)); - } - - void RPFP_caching::ConstrainParentCache(Edge *parent, Node *child, std::vector &lits){ - ConstrainEdgeLocalizedCache(parent,GetAnnotation(child),lits); - } - - - /** For incremental solving, asserts the negation of the upper bound associated - * with a node. - * */ - - void RPFP::AssertNode(Node *n) - { - if (n->dual.null()) { - n->dual = GetUpperBound(n); - stack.back().nodes.push_back(n); - slvr_add(n->dual); - } - } - - // caching version of above - void RPFP_caching::AssertNodeCache(Node *n, std::vector lits){ - if (n->dual.null()) { - n->dual = GetUpperBound(n); - stack.back().nodes.push_back(n); - GetAssumptionLits(n->dual, lits); - } - } - - /** Clone another RPFP into this one, keeping a map */ - void RPFP_caching::Clone(RPFP *other) { -#if 0 - for(unsigned i = 0; i < other->nodes.size(); i++) - NodeCloneMap[other->nodes[i]] = CloneNode(other->nodes[i]); -#endif - for (unsigned i = 0; i < other->edges.size(); i++) { - Edge *edge = other->edges[i]; - Node *parent = CloneNode(edge->Parent); - std::vector cs; - for (unsigned j = 0; j < edge->Children.size(); j++) - // cs.push_back(NodeCloneMap[edge->Children[j]]); - cs.push_back(CloneNode(edge->Children[j])); - EdgeCloneMap[edge] = CreateEdge(parent, edge->F, cs); - } - } - - /** Get the clone of a node */ - RPFP::Node *RPFP_caching::GetNodeClone(Node *other_node){ - return NodeCloneMap[other_node]; - } - - /** Get the clone of an edge */ - RPFP::Edge *RPFP_caching::GetEdgeClone(Edge *other_edge){ - return EdgeCloneMap[other_edge]; - } - - /** check assumption lits, and return core */ - check_result RPFP_caching::CheckCore(const std::vector &assumps, std::vector &core){ - core.resize(assumps.size()); - unsigned core_size; - check_result res = slvr().check(assumps.size(),(expr *)VEC2PTR(assumps),&core_size, VEC2PTR(core)); - if(res == unsat) - core.resize(core_size); - else - core.clear(); - return res; - } - - - /** Assert a constraint on an edge in the SMT context. - */ - - void RPFP::ConstrainEdge(Edge *e, const Term &t) - { - Term tl = Localize(e, t); - ConstrainEdgeLocalized(e,tl); - } - - void RPFP::ConstrainEdgeLocalized(Edge *e, const Term &tl) - { - e->constraints.push_back(tl); - stack.back().constraints.push_back(std::pair(e,tl)); - slvr_add(tl); - } - - void RPFP_caching::ConstrainEdgeLocalizedCache(Edge *e, const Term &tl, std::vector &lits) - { - e->constraints.push_back(tl); - stack.back().constraints.push_back(std::pair(e,tl)); - GetAssumptionLits(tl,lits); - } - - - /** Declare a constant in the background theory. */ - - void RPFP::DeclareConstant(const FuncDecl &f){ - ls->declare_constant(f); - } - - /** Assert a background axiom. Background axioms can be used to provide the - * theory of auxilliary functions or relations. All symbols appearing in - * background axioms are considered global, and may appear in both transformer - * and relational solutions. Semantically, a solution to the RPFP gives - * an interpretation of the unknown relations for each interpretation of the - * auxilliary symbols that is consistent with the axioms. Axioms should be - * asserted before any calls to Push. They cannot be de-asserted by Pop. */ - - void RPFP::AssertAxiom(const Term &t) - { - ls->assert_axiom(t); - axioms.push_back(t); // for printing only - } - -#if 0 - /** Do not call this. */ - - void RPFP::RemoveAxiom(const Term &t) - { - slvr().RemoveInterpolationAxiom(t); - } -#endif - - /** Solve an RPFP graph. This means either strengthen the annotation - * so that the bound at the given root node is satisfied, or - * show that this cannot be done by giving a dual solution - * (i.e., a counterexample). - * - * In the current implementation, this only works for graphs that - * are: - * - tree-like - * - * - closed. - * - * In a tree-like graph, every nod has out most one incoming and one out-going edge, - * and there are no cycles. In a closed graph, every node has exactly one out-going - * edge. This means that the leaves of the tree are all hyper-edges with no - * children. Such an edge represents a relation (nullary transformer) and thus - * a lower bound on its parent. The parameter root must be the root of this tree. - * - * If Solve returns LBool.False, this indicates success. The annotation of the tree - * has been updated to satisfy the upper bound at the root. - * - * If Solve returns LBool.True, this indicates a counterexample. For each edge, - * you can then call Eval to determine the values of symbols in the transformer formula. - * You can also call Empty on a node to determine if its value in the counterexample - * is the empty relation. - * - * \param root The root of the tree - * \param persist Number of context pops through which result should persist - * - * - */ - - lbool RPFP::Solve(Node *root, int persist) - { - timer_start("Solve"); - TermTree *tree = GetConstraintTree(root); - TermTree *interpolant = nullptr; - TermTree *goals = nullptr; - if(ls->need_goals) - goals = GetGoalTree(root); - ClearProofCore(); - - // if (dualModel != null) dualModel.Dispose(); - // if (dualLabels != null) dualLabels.Dispose(); - - timer_start("interpolate_tree"); - lbool res = ls_interpolate_tree(tree, interpolant, dualModel,goals,true); - timer_stop("interpolate_tree"); - if (res == l_false) { - DecodeTree(root, interpolant->getChildren()[0], persist); - delete interpolant; - } - - delete tree; - if(goals) - delete goals; - - timer_stop("Solve"); - return res; - } - - void RPFP::CollapseTermTreeRec(TermTree *root, TermTree *node){ - root->addTerm(node->getTerm()); - std::vector &cnsts = node->getTerms(); - for(unsigned i = 0; i < cnsts.size(); i++) - root->addTerm(cnsts[i]); - std::vector &chs = node->getChildren(); - for(unsigned i = 0; i < chs.size(); i++){ - CollapseTermTreeRec(root,chs[i]); - } - } - - TermTree *RPFP::CollapseTermTree(TermTree *node){ - std::vector &chs = node->getChildren(); - for(unsigned i = 0; i < chs.size(); i++) - CollapseTermTreeRec(node,chs[i]); - for(unsigned i = 0; i < chs.size(); i++) - delete chs[i]; - chs.clear(); - return node; - } - - lbool RPFP::SolveSingleNode(Node *root, Node *node) - { - timer_start("Solve"); - TermTree *tree = CollapseTermTree(GetConstraintTree(root,node)); - tree->getChildren().push_back(CollapseTermTree(ToTermTree(node))); - TermTree *interpolant = nullptr; - ClearProofCore(); - - timer_start("interpolate_tree"); - lbool res = ls_interpolate_tree(tree, interpolant, dualModel,nullptr,true); - timer_stop("interpolate_tree"); - if (res == l_false) { - DecodeTree(node, interpolant->getChildren()[0], 0); - delete interpolant; - } - - delete tree; - timer_stop("Solve"); - return res; - } - - /** Get the constraint tree (but don't solve it) */ - - TermTree *RPFP::GetConstraintTree(Node *root, Node *skip_descendant) - { - return AddUpperBound(root, ToTermTree(root,skip_descendant)); - } - - /** Dispose of the dual model (counterexample) if there is one. */ - - void RPFP::DisposeDualModel() - { - dualModel = model(ctx,nullptr); - } - - RPFP::Term RPFP::UnderapproxFlag(Node *n){ - expr flag = ctx.constant((std::string("@under") + string_of_int(n->number)).c_str(), ctx.bool_sort()); - underapprox_flag_rev[flag] = n; - return flag; - } - - RPFP::Node *RPFP::UnderapproxFlagRev(const Term &flag){ - return underapprox_flag_rev[flag]; - } - - /** Check satisfiability of asserted edges and nodes. Same functionality as - * Solve, except no primal solution (interpolant) is generated in the unsat case. - * The vector underapproxes gives the set of node underapproximations to be enforced - * (assuming these were conditionally asserted by AssertEdge). - * - */ - - check_result RPFP::Check(Node *root, std::vector underapproxes, std::vector *underapprox_core) { - timer_start("Check"); - ClearProofCore(); - // if (dualModel != null) dualModel.Dispose(); - check_result res; - if (!underapproxes.size()) - res = slvr_check(); - else { - std::vector us(underapproxes.size()); - for (unsigned i = 0; i < underapproxes.size(); i++) - us[i] = UnderapproxFlag(underapproxes[i]); - slvr_check(); // TODO: no idea why I need to do this - if (underapprox_core) { - std::vector unsat_core(us.size()); - unsigned core_size = 0; - res = slvr_check(us.size(), VEC2PTR(us), &core_size, VEC2PTR(unsat_core)); - underapprox_core->resize(core_size); - for (unsigned i = 0; i < core_size; i++) - (*underapprox_core)[i] = UnderapproxFlagRev(unsat_core[i]); - } - else { - res = slvr_check(us.size(), VEC2PTR(us)); - bool dump = false; - if (dump) { - std::vector cnsts; - // cnsts.push_back(axioms[0]); - cnsts.push_back(root->dual); - cnsts.push_back(root->Outgoing->dual); - ls->write_interpolation_problem("temp.smt", cnsts, std::vector()); - } - } - // check_result temp = slvr_check(); - } - dualModel = slvr().get_model(); - timer_stop("Check"); - return res; - } - - check_result RPFP::CheckUpdateModel(Node *root, std::vector assumps){ - // check_result temp1 = slvr_check(); // no idea why I need to do this - ClearProofCore(); - check_result res = slvr_check(assumps.size(), VEC2PTR(assumps)); - model mod = slvr().get_model(); - if(!mod.null()) - dualModel = mod;; - return res; - } - - /** Determines the value in the counterexample of a symbol occurring in the transformer formula of - * a given edge. */ - - RPFP::Term RPFP::Eval(Edge *e, const Term& t) - { - Term tl = Localize(e, t); - return dualModel.eval(tl); - } - - /** Returns true if the given node is empty in the primal solution. For proceudure summaries, - this means that the procedure is not called in the current counter-model. */ - - bool RPFP::Empty(Node *p) - { - Term b; std::vector v; - RedVars(p, b, v); - // dualModel.show_internals(); - // std::cout << "b: " << b << std::endl; - expr bv = dualModel.eval(b); - // std::cout << "bv: " << bv << std::endl; - bool res = !eq(bv,ctx.bool_val(true)); - return res; - } - - RPFP::Term RPFP::EvalNode(Node *p) - { - Term b; std::vector v; - RedVars(p, b, v); - std::vector args; - for(unsigned i = 0; i < v.size(); i++) - args.push_back(dualModel.eval(v[i])); - return (p->Name)(args); - } - - void RPFP::EvalArrayTerm(const RPFP::Term &t, ArrayValue &res){ - if (t.is_app()) { - decl_kind k = t.decl().get_decl_kind(); - if (k == AsArray) { - func_decl fd = t.decl().get_func_decl_parameter(0); - func_interp r = dualModel.get_func_interp(fd); - int num = r.num_entries(); - res.defined = true; - for (int i = 0; i < num; i++) { - expr arg = r.get_arg(i, 0); - expr value = r.get_value(i); - res.entries[arg] = value; - } - res.def_val = r.else_value(); - return; - } - else if (k == Store) { - EvalArrayTerm(t.arg(0), res); - if (!res.defined)return; - expr addr = t.arg(1); - expr val = t.arg(2); - if (addr.is_numeral() && val.is_numeral()) { - if (eq(val, res.def_val)) - res.entries.erase(addr); - else - res.entries[addr] = val; - } - else - res.defined = false; - return; - } - } - res.defined = false; - } - - int eae_count = 0; - - RPFP::Term RPFP::EvalArrayEquality(const RPFP::Term &f) { - ArrayValue lhs, rhs; - eae_count++; - EvalArrayTerm(f.arg(0), lhs); - EvalArrayTerm(f.arg(1), rhs); - if (lhs.defined && rhs.defined) { - if (eq(lhs.def_val, rhs.def_val)) - if (lhs.entries == rhs.entries) - return ctx.bool_val(true); - return ctx.bool_val(false); - } - return f; - } - - /** Compute truth values of all boolean subterms in current model. - Assumes formulas has been simplified by Z3, so only boolean ops - ands and, or, not. Returns result in memo. - */ - - int RPFP::SubtermTruth(hash_map &memo, const Term &f) { - TRACE("duality", tout << f << "\n";); - if (memo.find(f) != memo.end()) { - return memo[f]; - } - int res; - if (f.is_app()) { - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if (k == Implies) { - res = SubtermTruth(memo, !f.arg(0) || f.arg(1)); - goto done; - } - if (k == And) { - res = 1; - for (int i = 0; i < nargs; i++) { - int ar = SubtermTruth(memo, f.arg(i)); - if (ar == 0) { - res = 0; - goto done; - } - if (ar == 2)res = 2; - } - goto done; - } - else if (k == Or) { - res = 0; - for (int i = 0; i < nargs; i++) { - int ar = SubtermTruth(memo, f.arg(i)); - if (ar == 1) { - res = 1; - goto done; - } - if (ar == 2)res = 2; - } - goto done; - } - else if (k == Not) { - int ar = SubtermTruth(memo, f.arg(0)); - res = (ar == 0) ? 1 : ((ar == 1) ? 0 : 2); - goto done; - } - } - { - bool pos; std::vector names; - if (f.is_label(pos, names)) { - res = SubtermTruth(memo, f.arg(0)); - goto done; - } - } - { - expr bv = dualModel.eval(f); - if (bv.is_app() && bv.decl().get_decl_kind() == Equal && - bv.arg(0).is_array()) { - bv = EvalArrayEquality(bv); - } - // Hack!!!! array equalities can occur negatively! - if (bv.is_app() && bv.decl().get_decl_kind() == Not && - bv.arg(0).decl().get_decl_kind() == Equal && - bv.arg(0).arg(0).is_array()) { - bv = dualModel.eval(!EvalArrayEquality(bv.arg(0))); - } - if (eq(bv, ctx.bool_val(true))) - res = 1; - else if (eq(bv, ctx.bool_val(false))) - res = 0; - else - res = 2; - } - done: - memo[f] = res; - return res; - } - - int RPFP::EvalTruth(hash_map &memo, Edge *e, const Term &f){ - Term tl = Localize(e, f); - return SubtermTruth(memo,tl); - } - - /** Compute truth values of all boolean subterms in current model. - Assumes formulas has been simplified by Z3, so only boolean ops - ands and, or, not. Returns result in memo. - */ - - - void RPFP::GetLabelsRec(hash_map &memo, const Term &f, std::vector &labels, - hash_set *done, bool truth) { - if (done[truth].find(f) != done[truth].end()) - return; /* already processed */ - if (f.is_app()) { - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if (k == Implies) { - GetLabelsRec(memo, f.arg(1) || !f.arg(0), labels, done, truth); - goto done; - } - if (k == Iff) { - int b = SubtermTruth(memo, f.arg(0)); - if (b == 2) { - goto done; - // bypass error - std::ostringstream os; - os << "disaster in SubtermTruth processing " << f; - throw default_exception(os.str()); - } - GetLabelsRec(memo, f.arg(1), labels, done, truth ? b : !b); - goto done; - } - if (truth ? k == And : k == Or) { - for (int i = 0; i < nargs; i++) - GetLabelsRec(memo, f.arg(i), labels, done, truth); - goto done; - } - if (truth ? k == Or : k == And) { - for (int i = 0; i < nargs; i++) { - Term a = f.arg(i); - timer_start("SubtermTruth"); - int b = SubtermTruth(memo, a); - timer_stop("SubtermTruth"); - if (truth ? (b == 1) : (b == 0)) { - GetLabelsRec(memo, a, labels, done, truth); - goto done; - } - } - /* Unreachable! */ - // throw "error in RPFP::GetLabelsRec"; - goto done; - } - else if (k == Not) { - GetLabelsRec(memo, f.arg(0), labels, done, !truth); - goto done; - } - else { - bool pos; std::vector names; - if (f.is_label(pos, names)) { - GetLabelsRec(memo, f.arg(0), labels, done, truth); - if (pos == truth) - for (unsigned i = 0; i < names.size(); i++) - labels.push_back(names[i]); - goto done; - } - } - } - done: - done[truth].insert(f); - } - - void RPFP::GetLabels(Edge *e, std::vector &labels){ - if(!e->map || e->map->labeled.null()) - return; - Term tl = Localize(e, e->map->labeled); - hash_map memo; - hash_set done[2]; - GetLabelsRec(memo,tl,labels,done,true); - } - -#ifdef Z3OPS - static Z3_subterm_truth *stt; -#endif - - int ir_count = 0; - - void RPFP::ImplicantRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set *done, bool truth, hash_set &dont_cares) { - if (done[truth].find(f) != done[truth].end()) - return; /* already processed */ -#if 0 - int this_count = ir_count++; - if(this_count == 50092) - std::cout << "foo!\n"; -#endif - if (f.is_app()) { - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if (k == Implies) { - ImplicantRed(memo, f.arg(1) || !f.arg(0), lits, done, truth, dont_cares); - goto done; - } - if (k == Iff) { - int b = SubtermTruth(memo, f.arg(0)); - if (b == 2) { - std::ostringstream os; - os << "disaster in SubtermTruth processing " << f; - throw default_exception(os.str()); - } - ImplicantRed(memo, f.arg(1), lits, done, truth ? b : !b, dont_cares); - goto done; - } - if (truth ? k == And : k == Or) { - for (int i = 0; i < nargs; i++) - ImplicantRed(memo, f.arg(i), lits, done, truth, dont_cares); - goto done; - } - if (truth ? k == Or : k == And) { - for (int i = 0; i < nargs; i++) { - Term a = f.arg(i); -#if 0 - if(i == nargs - 1){ // last chance! - ImplicantRed(memo,a,lits,done,truth,dont_cares); - goto done; - } -#endif - timer_start("SubtermTruth"); -#ifdef Z3OPS - bool b = stt->eval(a); -#else - int b = SubtermTruth(memo, a); -#endif - timer_stop("SubtermTruth"); - if (truth ? (b == 1) : (b == 0)) { - ImplicantRed(memo, a, lits, done, truth, dont_cares); - goto done; - } - } - /* Unreachable! */ - // TODO: need to indicate this failure to caller - // std::cerr << "error in RPFP::ImplicantRed"; - goto done; - } - else if (k == Not) { - ImplicantRed(memo, f.arg(0), lits, done, !truth, dont_cares); - goto done; - } - } - { - if (dont_cares.find(f) == dont_cares.end()) { - expr rf = ResolveIte(memo, f, lits, done, dont_cares); - expr bv = truth ? rf : !rf; - lits.push_back(bv); - } - } - done: - done[truth].insert(f); - } - - void RPFP::ImplicantFullRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set &done, hash_set &dont_cares, bool extensional) { - if (done.find(f) != done.end()) - return; /* already processed */ - if (f.is_app()) { - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if (k == Implies || k == Iff || k == And || k == Or || k == Not) { - for (int i = 0; i < nargs; i++) - ImplicantFullRed(memo, f.arg(i), lits, done, dont_cares, extensional); - goto done; - } - } - { - if (dont_cares.find(f) == dont_cares.end()) { - int b = SubtermTruth(memo, f); - if (b != 0 && b != 1) goto done; - if (f.is_app() && f.decl().get_decl_kind() == Equal && f.arg(0).is_array()) { - if (b == 1 && !extensional) { - expr x = dualModel.eval(f.arg(0)); expr y = dualModel.eval(f.arg(1)); - if (!eq(x, y)) - b = 0; - } - if (b == 0) - goto done; - } - expr bv = (b == 1) ? f : !f; - lits.push_back(bv); - } - } - done: - done.insert(f); - } - - RPFP::Term RPFP::ResolveIte(hash_map &memo, const Term &t, std::vector &lits, - hash_set *done, hash_set &dont_cares) { - if (resolve_ite_memo.find(t) != resolve_ite_memo.end()) - return resolve_ite_memo[t]; - Term res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - if (f.get_decl_kind() == Ite) { - timer_start("SubtermTruth"); -#ifdef Z3OPS - bool sel = stt->eval(t.arg(0)); -#else - int xval = SubtermTruth(memo, t.arg(0)); - bool sel; - if (xval == 0)sel = false; - else if (xval == 1)sel = true; - else - throw "unresolved ite in model"; -#endif - timer_stop("SubtermTruth"); - ImplicantRed(memo, t.arg(0), lits, done, sel, dont_cares); - res = ResolveIte(memo, t.arg(sel ? 1 : 2), lits, done, dont_cares); - } - else { - for (int i = 0; i < nargs; i++) - args.push_back(ResolveIte(memo, t.arg(i), lits, done, dont_cares)); - res = f(args.size(), VEC2PTR(args)); - } - } - else res = t; - resolve_ite_memo[t] = res; - return res; - } - - RPFP::Term RPFP::ElimIteRec(hash_map &memo, const Term &t, std::vector &cnsts) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (bar.second) { - if (t.is_app()) { - int nargs = t.num_args(); - std::vector args; - if (t.decl().get_decl_kind() == Equal) { - expr lhs = t.arg(0); - expr rhs = t.arg(1); - if (rhs.decl().get_decl_kind() == Ite) { - expr rhs_args[3]; - lhs = ElimIteRec(memo, lhs, cnsts); - for (int i = 0; i < 3; i++) - rhs_args[i] = ElimIteRec(memo, rhs.arg(i), cnsts); - res = (rhs_args[0] && (lhs == rhs_args[1])) || ((!rhs_args[0]) && (lhs == rhs_args[2])); - goto done; - } - } - if (t.decl().get_decl_kind() == Ite) { - func_decl sym = ctx.fresh_func_decl("@ite", t.get_sort()); - res = sym(); - cnsts.push_back(ElimIteRec(memo, ctx.make(Equal, res, t), cnsts)); - } - else { - for (int i = 0; i < nargs; i++) - args.push_back(ElimIteRec(memo, t.arg(i), cnsts)); - res = t.decl()(args.size(), VEC2PTR(args)); - } - } - else if (t.is_quantifier()) - res = clone_quantifier(t, ElimIteRec(memo, t.body(), cnsts)); - else - res = t; - } - done: - return res; - } - - RPFP::Term RPFP::ElimIte(const Term &t){ - hash_map memo; - std::vector cnsts; - expr res = ElimIteRec(memo,t,cnsts); - if(!cnsts.empty()){ - cnsts.push_back(res); - res = ctx.make(And,cnsts); - } - return res; - } - - void RPFP::Implicant(hash_map &memo, const Term &f, std::vector &lits, hash_set &dont_cares){ - hash_set done[2]; - ImplicantRed(memo,f,lits,done,true, dont_cares); - } - - - /** Underapproximate a formula using current counterexample. */ - - RPFP::Term RPFP::UnderapproxFormula(const Term &f, hash_set &dont_cares){ - /* first compute truth values of subterms */ - hash_map memo; -#ifdef Z3OPS - stt = Z3_mk_subterm_truth(ctx,dualModel); -#endif - // SubtermTruth(memo,f); - /* now compute an implicant */ - std::vector lits; - Implicant(memo,f,lits, dont_cares); -#ifdef Z3OPS - delete stt; stt = 0; -#endif - /* return conjunction of literals */ - return conjoin(lits); - } - - RPFP::Term RPFP::UnderapproxFullFormula(const Term &f, bool extensional){ - hash_set dont_cares; - resolve_ite_memo.clear(); - timer_start("UnderapproxFormula"); - /* first compute truth values of subterms */ - hash_map memo; - hash_set done; - std::vector lits; - ImplicantFullRed(memo,f,lits,done,dont_cares, extensional); - timer_stop("UnderapproxFormula"); - /* return conjunction of literals */ - return conjoin(lits); - } - - struct VariableProjector : Z3User { - - struct elim_cand { - Term var; - int sup; - Term val; - }; - - typedef expr Term; - - hash_set keep; - hash_map var_ord; - int num_vars; - std::vector elim_cands; - hash_map > sup_map; - hash_map elim_map; - std::vector ready_cands; - hash_map cand_map; - params simp_params; - - VariableProjector(Z3User &_user, std::vector &keep_vec) : - Z3User(_user), simp_params() { - num_vars = 0; - for (unsigned i = 0; i < keep_vec.size(); i++) { - keep.insert(keep_vec[i]); - var_ord[keep_vec[i]] = num_vars++; - } - } - int VarNum(const Term &v) { - if (var_ord.find(v) == var_ord.end()) - var_ord[v] = num_vars++; - return var_ord[v]; - } - - bool IsVar(const Term &t){ - return t.is_app() && t.num_args() == 0 && t.decl().get_decl_kind() == Uninterpreted; - } - - bool IsPropLit(const Term &t, Term &a) { - if (IsVar(t)) { - a = t; - return true; - } - else if (t.is_app() && t.decl().get_decl_kind() == Not) - return IsPropLit(t.arg(0), a); - return false; - } - - void CountOtherVarsRec(hash_map &memo, - const Term &t, - int id, - int &count) { - std::pair foo(t, 0); - std::pair::iterator, bool> bar = memo.insert(foo); - // int &res = bar.first->second; - if (!bar.second) return; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - if (nargs == 0 && f.get_decl_kind() == Uninterpreted) { - if (cand_map.find(t) != cand_map.end()) { - count++; - sup_map[t].push_back(id); - } - } - for (int i = 0; i < nargs; i++) - CountOtherVarsRec(memo, t.arg(i), id, count); - } - else if (t.is_quantifier()) - CountOtherVarsRec(memo, t.body(), id, count); - } - - void NewElimCand(const Term &lhs, const Term &rhs) { - if (debug_gauss) { - std::cout << "mapping " << lhs << " to " << rhs << std::endl; - } - elim_cand cand; - cand.var = lhs; - cand.sup = 0; - cand.val = rhs; - elim_cands.push_back(cand); - cand_map[lhs] = elim_cands.size() - 1; - } - - void MakeElimCand(const Term &lhs, const Term &rhs) { - if (eq(lhs, rhs)) - return; - if (!IsVar(lhs)) { - if (IsVar(rhs)) { - MakeElimCand(rhs, lhs); - return; - } - else { - std::cout << "would have mapped a non-var\n"; - return; - } - } - if (IsVar(rhs) && VarNum(rhs) > VarNum(lhs)) { - MakeElimCand(rhs, lhs); - return; - } - if (keep.find(lhs) != keep.end()) - return; - if (cand_map.find(lhs) == cand_map.end()) - NewElimCand(lhs, rhs); - else { - int cand_idx = cand_map[lhs]; - if (IsVar(rhs) && cand_map.find(rhs) == cand_map.end() - && keep.find(rhs) == keep.end()) - NewElimCand(rhs, elim_cands[cand_idx].val); - elim_cands[cand_idx].val = rhs; - } - } - - Term FindRep(const Term &t) { - if (cand_map.find(t) == cand_map.end()) - return t; - Term &res = elim_cands[cand_map[t]].val; - if (IsVar(res)) { - assert(VarNum(res) < VarNum(t)); - res = FindRep(res); - return res; - } - return t; - } - - void GaussElimCheap(const std::vector &lits_in, - std::vector &lits_out) { - for (unsigned i = 0; i < lits_in.size(); i++) { - Term lit = lits_in[i]; - if (lit.is_app()) { - decl_kind k = lit.decl().get_decl_kind(); - if (k == Equal || k == Iff) - MakeElimCand(FindRep(lit.arg(0)), FindRep(lit.arg(1))); - } - } - - for (unsigned i = 0; i < elim_cands.size(); i++) { - elim_cand &cand = elim_cands[i]; - hash_map memo; - CountOtherVarsRec(memo, cand.val, i, cand.sup); - if (cand.sup == 0) - ready_cands.push_back(i); - } - - while (!ready_cands.empty()) { - elim_cand &cand = elim_cands[ready_cands.back()]; - ready_cands.pop_back(); - Term rep = FindRep(cand.var); - if (!eq(rep, cand.var)) - if (cand_map.find(rep) != cand_map.end()) { - int rep_pos = cand_map[rep]; - cand.val = elim_cands[rep_pos].val; - } - Term val = SubstRec(elim_map, cand.val); - if (debug_gauss) { - std::cout << "subbing " << cand.var << " --> " << val << std::endl; - } - elim_map[cand.var] = val; - std::vector &sup = sup_map[cand.var]; - for (unsigned i = 0; i < sup.size(); i++) { - int c = sup[i]; - if ((--elim_cands[c].sup) == 0) - ready_cands.push_back(c); - } - } - - for (unsigned i = 0; i < lits_in.size(); i++) { - Term lit = lits_in[i]; - lit = SubstRec(elim_map, lit); - lit = lit.simplify(); - if (eq(lit, ctx.bool_val(true))) - continue; - Term a; - if (IsPropLit(lit, a)) - if (keep.find(lit) == keep.end()) - continue; - lits_out.push_back(lit); - } - } - - // maps variables to constrains in which the occur pos, neg - hash_map la_index[2]; - hash_map la_coeffs[2]; - std::vector la_pos_vars; - bool fixing; - - void IndexLAcoeff(const Term &coeff1, const Term &coeff2, const Term &t, int id) { - Term coeff = coeff1 * coeff2; - coeff = coeff.simplify(); - Term is_pos = (coeff >= ctx.int_val(0)); - is_pos = is_pos.simplify(); - if (eq(is_pos, ctx.bool_val(true))) - IndexLA(true, coeff, t, id); - else - IndexLA(false, coeff, t, id); - } - - void IndexLAremove(const Term &t) { - if (IsVar(t)) { - la_index[0][t] = -1; // means ineligible to be eliminated - la_index[1][t] = -1; // (more that one occurrence, or occurs not in linear comb) - } - else if (t.is_app()) { - int nargs = t.num_args(); - for (int i = 0; i < nargs; i++) - IndexLAremove(t.arg(i)); - } - // TODO: quantifiers? - } - - - void IndexLA(bool pos, const Term &coeff, const Term &t, int id) { - if (t.is_numeral()) - return; - if (t.is_app()) { - int nargs = t.num_args(); - switch (t.decl().get_decl_kind()) { - case Plus: - for (int i = 0; i < nargs; i++) - IndexLA(pos, coeff, t.arg(i), id); - break; - case Sub: - IndexLA(pos, coeff, t.arg(0), id); - IndexLA(!pos, coeff, t.arg(1), id); - break; - case Times: - if (t.arg(0).is_numeral()) - IndexLAcoeff(coeff, t.arg(0), t.arg(1), id); - else if (t.arg(1).is_numeral()) - IndexLAcoeff(coeff, t.arg(1), t.arg(0), id); - break; - default: - if (IsVar(t) && (fixing || la_index[pos].find(t) == la_index[pos].end())) { - la_index[pos][t] = id; - la_coeffs[pos][t] = coeff; - if (pos && !fixing) - la_pos_vars.push_back(t); // this means we only add a var once - } - else - IndexLAremove(t); - } - } - } - - void IndexLAstart(bool pos, const Term &t, int id){ - IndexLA(pos,(pos ? ctx.int_val(1) : ctx.int_val(-1)), t, id); - } - - void IndexLApred(bool pos, const Term &p, int id) { - if (p.is_app()) { - switch (p.decl().get_decl_kind()) { - case Not: - IndexLApred(!pos, p.arg(0), id); - break; - case Leq: - case Lt: - IndexLAstart(!pos, p.arg(0), id); - IndexLAstart(pos, p.arg(1), id); - break; - case Geq: - case Gt: - IndexLAstart(pos, p.arg(0), id); - IndexLAstart(!pos, p.arg(1), id); - break; - default: - IndexLAremove(p); - } - } - } - - void IndexLAfix(const Term &p, int id){ - fixing = true; - IndexLApred(true,p,id); - fixing = false; - } - - bool IsCanonIneq(const Term &lit, Term &term, Term &bound) { - // std::cout << Z3_simplify_get_help(ctx) << std::endl; - bool pos = lit.decl().get_decl_kind() != Not; - Term atom = pos ? lit : lit.arg(0); - if (atom.decl().get_decl_kind() == Leq) { - if (pos) { - bound = atom.arg(0); - term = atom.arg(1).simplify(simp_params); -#if Z3_MAJOR_VERSION < 4 - term = SortSum(term); -#endif - } - else { - bound = (atom.arg(1) + ctx.int_val(1)); - term = atom.arg(0); - // std::cout << "simplifying bound: " << bound << std::endl; - bound = bound.simplify(); - term = term.simplify(simp_params); -#if Z3_MAJOR_VERSION < 4 - term = SortSum(term); -#endif - } - return true; - } - else if (atom.decl().get_decl_kind() == Geq) { - if (pos) { - bound = atom.arg(1); // integer axiom - term = atom.arg(0).simplify(simp_params); -#if Z3_MAJOR_VERSION < 4 - term = SortSum(term); -#endif - return true; - } - else { - bound = -(atom.arg(1) - ctx.int_val(1)); // integer axiom - term = -atom.arg(0); - bound = bound.simplify(); - term = term.simplify(simp_params); -#if Z3_MAJOR_VERSION < 4 - term = SortSum(term); -#endif - } - return true; - } - return false; - } - - Term CanonIneqTerm(const Term &p){ - Term term,bound; - Term ps = p.simplify(); - VERIFY(IsCanonIneq(ps,term,bound)); - return term - bound; - } - - void ElimRedundantBounds(std::vector &lits) { - hash_map best_bound; - for (unsigned i = 0; i < lits.size(); i++) { - lits[i] = lits[i].simplify(simp_params); - Term term, bound; - if (IsCanonIneq(lits[i], term, bound)) { - if (best_bound.find(term) == best_bound.end()) - best_bound[term] = i; - else { - int best = best_bound[term]; - Term bterm, bbound; - IsCanonIneq(lits[best], bterm, bbound); - Term comp = bound > bbound; - comp = comp.simplify(); - if (eq(comp, ctx.bool_val(true))) { - lits[best] = ctx.bool_val(true); - best_bound[term] = i; - } - else { - lits[i] = ctx.bool_val(true); - } - } - } - } - } - - void FourierMotzkinCheap(const std::vector &lits_in, - std::vector &lits_out) { - simp_params.set(":som", true); - simp_params.set(":sort-sums", true); - fixing = false; lits_out = lits_in; - ElimRedundantBounds(lits_out); - for (unsigned i = 0; i < lits_out.size(); i++) - IndexLApred(true, lits_out[i], i); - - for (unsigned i = 0; i < la_pos_vars.size(); i++) { - Term var = la_pos_vars[i]; - if (la_index[false].find(var) != la_index[false].end()) { - int pos_idx = la_index[true][var]; - int neg_idx = la_index[false][var]; - if (pos_idx >= 0 && neg_idx >= 0) { - if (keep.find(var) != keep.end()) { - std::cout << "would have eliminated keep var\n"; - continue; - } - Term tpos = CanonIneqTerm(lits_out[pos_idx]); - Term tneg = CanonIneqTerm(lits_out[neg_idx]); - Term pos_coeff = la_coeffs[true][var]; - Term neg_coeff = -la_coeffs[false][var]; - Term comb = neg_coeff * tpos + pos_coeff * tneg; - Term ineq = ctx.int_val(0) <= comb; - ineq = ineq.simplify(); - lits_out[pos_idx] = ineq; - lits_out[neg_idx] = ctx.bool_val(true); - IndexLAfix(ineq, pos_idx); - } - } - } - } - - Term ProjectFormula(const Term &f){ - std::vector lits, new_lits1, new_lits2; - CollectConjuncts(f,lits); - timer_start("GaussElimCheap"); - GaussElimCheap(lits,new_lits1); - timer_stop("GaussElimCheap"); - timer_start("FourierMotzkinCheap"); - FourierMotzkinCheap(new_lits1,new_lits2); - timer_stop("FourierMotzkinCheap"); - return conjoin(new_lits2); - } - }; - - void Z3User::CollectConjuncts(const Term &f, std::vector &lits, bool pos) { - if (f.is_app() && f.decl().get_decl_kind() == Not) - CollectConjuncts(f.arg(0), lits, !pos); - else if (pos && f.is_app() && f.decl().get_decl_kind() == And) { - int num_args = f.num_args(); - for (int i = 0; i < num_args; i++) - CollectConjuncts(f.arg(i), lits, true); - } - else if (!pos && f.is_app() && f.decl().get_decl_kind() == Or) { - int num_args = f.num_args(); - for (int i = 0; i < num_args; i++) - CollectConjuncts(f.arg(i), lits, false); - } - else if (pos) { - if (!eq(f, ctx.bool_val(true))) - lits.push_back(f); - } - else { - if (!eq(f, ctx.bool_val(false))) - lits.push_back(!f); - } - } - - void Z3User::CollectJuncts(const Term &f, std::vector &lits, decl_kind op, bool negate) { - if (f.is_app() && f.decl().get_decl_kind() == Not) - CollectJuncts(f.arg(0), lits, (op == And) ? Or : And, !negate); - else if (f.is_app() && f.decl().get_decl_kind() == op) { - int num_args = f.num_args(); - for (int i = 0; i < num_args; i++) - CollectJuncts(f.arg(i), lits, op, negate); - } - else { - expr junct = negate ? Negate(f) : f; - lits.push_back(junct); - } - } - - struct TermLt { - bool operator()(const expr &x, const expr &y){ - unsigned xid = x.get_id(); - unsigned yid = y.get_id(); - return xid < yid; - } - }; - - void Z3User::SortTerms(std::vector &terms){ - TermLt foo; - std::sort(terms.begin(),terms.end(),foo); - } - - Z3User::Term Z3User::SortSum(const Term &t){ - if(!(t.is_app() && t.decl().get_decl_kind() == Plus)) - return t; - int nargs = t.num_args(); - if(nargs < 2) return t; - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = t.arg(i); - SortTerms(args); - if(nargs == 2) - return args[0] + args[1]; - return sum(args); - } - - - RPFP::Term RPFP::ProjectFormula(std::vector &keep_vec, const Term &f){ - VariableProjector vp(*this,keep_vec); - return vp.ProjectFormula(f); - } - - /** Compute an underapproximation of every node in a tree rooted at "root", - based on a previously computed counterexample. The underapproximation - may contain free variables that are implicitly existentially quantified. - */ - - RPFP::Term RPFP::ComputeUnderapprox(Node *root, int persist){ - /* if terminated underapprox is empty set (false) */ - bool show_model = false; - if(show_model) - std::cout << dualModel << std::endl; - if(!root->Outgoing){ - root->Underapprox.SetEmpty(); - return ctx.bool_val(true); - } - /* if not used in cex, underapprox is empty set (false) */ - if(Empty(root)){ - root->Underapprox.SetEmpty(); - return ctx.bool_val(true); - } - /* compute underapprox of children first */ - std::vector &chs = root->Outgoing->Children; - std::vector chu(chs.size()); - for(unsigned i = 0; i < chs.size(); i++) - chu[i] = ComputeUnderapprox(chs[i],persist); - - Term b; std::vector v; - RedVars(root, b, v); - /* underapproximate the edge formula */ - hash_set dont_cares; - dont_cares.insert(b); - resolve_ite_memo.clear(); - timer_start("UnderapproxFormula"); - Term dual = root->Outgoing->dual.null() ? ctx.bool_val(true) : root->Outgoing->dual; - Term eu = UnderapproxFormula(dual,dont_cares); - timer_stop("UnderapproxFormula"); - /* combine with children */ - chu.push_back(eu); - eu = conjoin(chu); - /* project onto appropriate variables */ - eu = ProjectFormula(v,eu); - eu = eu.simplify(); - -#if 0 - /* check the result is consistent */ - { - hash_map memo; - int res = SubtermTruth(memo, eu); - if(res != 1) - throw "inconsistent projection"; - } -#endif - - /* rename to appropriate variable names */ - hash_map memo; - for (unsigned i = 0; i < v.size(); i++) - memo[v[i]] = root->Annotation.IndParams[i]; /* copy names from annotation */ - Term funder = SubstRec(memo, eu); - root->Underapprox = CreateRelation(root->Annotation.IndParams,funder); -#if 0 - if(persist) - Z3_persist_ast(ctx,root->Underapprox.Formula,persist); -#endif - return eu; - } - - void RPFP::FixCurrentState(Edge *edge){ - hash_set dont_cares; - resolve_ite_memo.clear(); - timer_start("UnderapproxFormula"); - Term dual = edge->dual.null() ? ctx.bool_val(true) : edge->dual; - Term eu = UnderapproxFormula(dual,dont_cares); - timer_stop("UnderapproxFormula"); - ConstrainEdgeLocalized(edge,eu); - } - - void RPFP::GetGroundLitsUnderQuants(hash_set *memo, const Term &f, std::vector &res, int under){ - if(memo[under].find(f) != memo[under].end()) - return; - memo[under].insert(f); - if (f.is_app()) { - if (!under && !f.has_quantifiers()) - return; - decl_kind k = f.decl().get_decl_kind(); - if (k == And || k == Or || k == Implies || k == Iff) { - int num_args = f.num_args(); - for (int i = 0; i < num_args; i++) - GetGroundLitsUnderQuants(memo, f.arg(i), res, under); - return; - } - } - else if (f.is_quantifier()){ -#if 0 - // treat closed quantified formula as a literal 'cause we hate nested quantifiers - if(under && IsClosedFormula(f)) - res.push_back(f); - else -#endif - GetGroundLitsUnderQuants(memo,f.body(),res,1); - return; - } - if(f.is_var()){ - // std::cout << "foo!\n"; - return; - } - if(under && f.is_ground()) - res.push_back(f); - } - - RPFP::Term RPFP::StrengthenFormulaByCaseSplitting(const Term &f, std::vector &case_lits){ - hash_set memo[2]; - std::vector lits; - GetGroundLitsUnderQuants(memo, f, lits, 0); - hash_set lits_hash; - for(unsigned i = 0; i < lits.size(); i++) - lits_hash.insert(lits[i]); - hash_map subst; - hash_map stt_memo; - std::vector conjuncts; - for(unsigned i = 0; i < lits.size(); i++){ - const expr &lit = lits[i]; - if(lits_hash.find(NegateLit(lit)) == lits_hash.end()){ - case_lits.push_back(lit); - bool tval = false; - expr atom = lit; - if(lit.is_app() && lit.decl().get_decl_kind() == Not){ - tval = true; - atom = lit.arg(0); - } - expr etval = ctx.bool_val(tval); - if(atom.is_quantifier()) - subst[atom] = etval; // this is a bit desperate, since we can't eval quants - else { - int b = SubtermTruth(stt_memo,atom); - if(b == (tval ? 1 : 0)) - subst[atom] = etval; - else { - if(b == 0 || b == 1){ - etval = ctx.bool_val(b ? true : false); - subst[atom] = etval; - conjuncts.push_back(b ? atom : !atom); - } - } - } - } - } - expr g = f; - if(!subst.empty()){ - g = SubstRec(subst,f); - if(conjuncts.size()) - g = g && ctx.make(And,conjuncts); - g = g.simplify(); - } -#if 1 - expr g_old = g; - g = RemoveRedundancy(g); - bool changed = !eq(g,g_old); - g = g.simplify(); - if(changed) { // a second pass can get some more simplification - g = RemoveRedundancy(g); - g = g.simplify(); - } -#else - g = RemoveRedundancy(g); - g = g.simplify(); -#endif - g = AdjustQuantifiers(g); - return g; - } - - RPFP::Term RPFP::ModelValueAsConstraint(const Term &t) { - if (t.is_array()) { - ArrayValue arr; - Term e = dualModel.eval(t); - EvalArrayTerm(e, arr); - if (arr.defined) { - std::vector cs; - for (std::map::iterator it = arr.entries.begin(), en = arr.entries.end(); it != en; ++it) { - expr foo = select(t, expr(ctx, it->first)) == expr(ctx, it->second); - cs.push_back(foo); - } - return conjoin(cs); - } - } - else { - expr r = dualModel.get_const_interp(t.decl()); - if (!r.null()) { - expr res = t == expr(ctx, r); - return res; - } - } - return ctx.bool_val(true); - } - - void RPFP::EvalNodeAsConstraint(Node *p, Transformer &res) - { - Term b; std::vector v; - RedVars(p, b, v); - std::vector args; - for(unsigned i = 0; i < v.size(); i++){ - expr val = ModelValueAsConstraint(v[i]); - if(!eq(val,ctx.bool_val(true))) - args.push_back(val); - } - expr cnst = conjoin(args); - hash_map memo; - for (unsigned i = 0; i < v.size(); i++) - memo[v[i]] = p->Annotation.IndParams[i]; /* copy names from annotation */ - Term funder = SubstRec(memo, cnst); - res = CreateRelation(p->Annotation.IndParams,funder); - } - -#if 0 - void RPFP::GreedyReduce(solver &s, std::vector &conjuncts){ - // verify - s.push(); - expr conj = ctx.make(And,conjuncts); - s.add(conj); - check_result res = s.check(); - if(res != unsat) - throw "should be unsat"; - s.pop(1); - - for(unsigned i = 0; i < conjuncts.size(); ){ - std::swap(conjuncts[i],conjuncts.back()); - expr save = conjuncts.back(); - conjuncts.pop_back(); - s.push(); - expr conj = ctx.make(And,conjuncts); - s.add(conj); - check_result res = s.check(); - s.pop(1); - if(res != unsat){ - conjuncts.push_back(save); - std::swap(conjuncts[i],conjuncts.back()); - i++; - } - } - } -#endif - - void RPFP::GreedyReduce(solver &s, std::vector &conjuncts){ - std::vector lits(conjuncts.size()); - for(unsigned i = 0; i < lits.size(); i++){ - func_decl pred = ctx.fresh_func_decl("@alit", ctx.bool_sort()); - lits[i] = pred(); - s.add(ctx.make(Implies,lits[i],conjuncts[i])); - } - - // verify - check_result res = s.check(lits.size(), VEC2PTR(lits)); - if(res != unsat){ - // add the axioms in the off chance they are useful - const std::vector &theory = ls->get_axioms(); - for(unsigned i = 0; i < theory.size(); i++) - s.add(theory[i]); - for(int k = 0; k < 100; k++) // keep trying, maybe MBQI will do something! - if(s.check(lits.size(), VEC2PTR(lits)) == unsat) - goto is_unsat; - throw "should be unsat"; - } - is_unsat: - for(unsigned i = 0; i < conjuncts.size(); ){ - std::swap(conjuncts[i],conjuncts.back()); - std::swap(lits[i],lits.back()); - check_result res = s.check(lits.size()-1, VEC2PTR(lits)); - if(res != unsat){ - std::swap(conjuncts[i],conjuncts.back()); - std::swap(lits[i],lits.back()); - i++; - } - else { - conjuncts.pop_back(); - lits.pop_back(); - } - } - } - - void foobar(){ - } - - void RPFP::GreedyReduceNodes(std::vector &nodes){ - std::vector lits; - for(unsigned i = 0; i < nodes.size(); i++){ - Term b; std::vector v; - RedVars(nodes[i], b, v); - lits.push_back(!b); - expr bv = dualModel.eval(b); - if(eq(bv,ctx.bool_val(true))){ - check_result res = slvr_check(lits.size(), VEC2PTR(lits)); - if(res == unsat) - lits.pop_back(); - else - foobar(); - } - } - } - - check_result RPFP::CheckWithConstrainedNodes(std::vector &posnodes,std::vector &negnodes){ - timer_start("Check"); - std::vector lits; - for(unsigned i = 0; i < posnodes.size(); i++){ - Term b; std::vector v; - RedVars(posnodes[i], b, v); - lits.push_back(b); - } - for(unsigned i = 0; i < negnodes.size(); i++){ - Term b; std::vector v; - RedVars(negnodes[i], b, v); - lits.push_back(!b); - } - check_result res = slvr_check(lits.size(), VEC2PTR(lits)); - if(res == unsat && posnodes.size()){ - lits.resize(posnodes.size()); - res = slvr_check(lits.size(), VEC2PTR(lits)); - } - dualModel = slvr().get_model(); -#if 0 - if(!dualModel.null()){ - std::cout << "posnodes called:\n"; - for(unsigned i = 0; i < posnodes.size(); i++) - if(!Empty(posnodes[i])) - std::cout << posnodes[i]->Name.name() << "\n"; - std::cout << "negnodes called:\n"; - for(unsigned i = 0; i < negnodes.size(); i++) - if(!Empty(negnodes[i])) - std::cout << negnodes[i]->Name.name() << "\n"; - } -#endif - timer_stop("Check"); - return res; - } - - - void RPFP_caching::FilterCore(std::vector &core, std::vector &full_core){ - hash_set core_set; - std::copy(full_core.begin(),full_core.end(),std::inserter(core_set,core_set.begin())); - std::vector new_core; - for(unsigned i = 0; i < core.size(); i++) - if(core_set.find(core[i]) != core_set.end()) - new_core.push_back(core[i]); - core.swap(new_core); - } - - void RPFP_caching::GreedyReduceCache(std::vector &assumps, std::vector &core){ - std::vector lits = assumps, full_core; - std::copy(core.begin(),core.end(),std::inserter(lits,lits.end())); - - // verify - check_result res = CheckCore(lits,full_core); - if(res != unsat){ - // add the axioms in the off chance they are useful - const std::vector &theory = ls->get_axioms(); - for(unsigned i = 0; i < theory.size(); i++) - GetAssumptionLits(theory[i],assumps); - lits = assumps; - std::copy(core.begin(),core.end(),std::inserter(lits,lits.end())); - - for(int k = 0; k < 4; k++) // keep trying, maybe MBQI will do something! - if((res = CheckCore(lits,full_core)) == unsat) - goto is_unsat; - throw greedy_reduce_failed(); - } - is_unsat: - FilterCore(core,full_core); - - std::vector dummy; - if(CheckCore(full_core,dummy) != unsat) - throw "should be unsat"; - - for(unsigned i = 0; i < core.size(); ){ - expr temp = core[i]; - std::swap(core[i],core.back()); - core.pop_back(); - lits.resize(assumps.size()); - std::copy(core.begin(),core.end(),std::inserter(lits,lits.end())); - res = CheckCore(lits,full_core); - if(res != unsat){ - core.push_back(temp); - std::swap(core[i],core.back()); - i++; - } - } - } - - expr RPFP::NegateLit(const expr &f){ - if(f.is_app() && f.decl().get_decl_kind() == Not) - return f.arg(0); - else - return !f; - } - - void RPFP::NegateLits(std::vector &lits){ - for(unsigned i = 0; i < lits.size(); i++){ - expr &f = lits[i]; - if(f.is_app() && f.decl().get_decl_kind() == Not) - f = f.arg(0); - else - f = !f; - } - } - - expr RPFP::SimplifyOr(std::vector &lits){ - if(lits.size() == 0) - return ctx.bool_val(false); - if(lits.size() == 1) - return lits[0]; - return ctx.make(Or,lits); - } - - expr RPFP::SimplifyAnd(std::vector &lits){ - if(lits.size() == 0) - return ctx.bool_val(true); - if(lits.size() == 1) - return lits[0]; - return ctx.make(And,lits); - } - - - /* This is a wrapper for a solver that is intended to compute - implicants from models. It works around a problem in Z3 with - models in the non-extensional array theory. It does this by - naming all of the store terms in a formula. That is, (store ...) - is replaced by "name" with an added constraint name = (store - ...). This allows us to determine from the model whether an array - equality is true or false (it is false if the two sides are - mapped to different function symbols, even if they have the same - contents). - */ - - struct implicant_solver { - RPFP *owner; - solver &aux_solver; - std::vector assumps, namings; - std::vector assump_stack, naming_stack; - hash_map renaming, renaming_memo; - - void add(const expr &e){ - expr t = e; - if(!aux_solver.extensional_array_theory()){ - unsigned i = namings.size(); - t = owner->ExtractStores(renaming_memo,t,namings,renaming); - for(; i < namings.size(); i++) - aux_solver.add(namings[i]); - } - assumps.push_back(t); - aux_solver.add(t); - } - - void push() { - assump_stack.push_back(assumps.size()); - naming_stack.push_back(namings.size()); - aux_solver.push(); - } - - // When we pop the solver, we have to re-add any namings that were lost - - void pop(int n) { - aux_solver.pop(n); - int new_assumps = assump_stack[assump_stack.size()-n]; - int new_namings = naming_stack[naming_stack.size()-n]; - for(unsigned i = new_namings; i < namings.size(); i++) - aux_solver.add(namings[i]); - assumps.resize(new_assumps); - namings.resize(new_namings); - assump_stack.resize(assump_stack.size()-1); - naming_stack.resize(naming_stack.size()-1); - } - - check_result check() { - return aux_solver.check(); - } - - model get_model() { - return aux_solver.get_model(); - } - - expr get_implicant() { - owner->dualModel = aux_solver.get_model(); - expr dual = owner->ctx.make(And,assumps); - bool ext = aux_solver.extensional_array_theory(); - expr eu = owner->UnderapproxFullFormula(dual,ext); - // if we renamed store terms, we have to undo - if(!ext) - eu = owner->SubstRec(renaming,eu); - return eu; - } - - implicant_solver(RPFP *_owner, solver &_aux_solver) - : owner(_owner), aux_solver(_aux_solver) - {} - }; - - // set up edge constraint in aux solver - void RPFP::AddEdgeToSolver(implicant_solver &aux_solver, Edge *edge){ - if(!edge->dual.null()) - aux_solver.add(edge->dual); - for(unsigned i = 0; i < edge->constraints.size(); i++){ - expr tl = edge->constraints[i]; - aux_solver.add(tl); - } - } - - void RPFP::AddEdgeToSolver(Edge *edge){ - if(!edge->dual.null()) - aux_solver.add(edge->dual); - for(unsigned i = 0; i < edge->constraints.size(); i++){ - expr tl = edge->constraints[i]; - aux_solver.add(tl); - } - } - - static int by_case_counter = 0; - - void RPFP::InterpolateByCases(Node *root, Node *node){ - timer_start("InterpolateByCases"); - bool axioms_added = false; - hash_set axioms_needed; - const std::vector &theory = ls->get_axioms(); - for(unsigned i = 0; i < theory.size(); i++) - axioms_needed.insert(theory[i]); - implicant_solver is(this,aux_solver); - is.push(); - AddEdgeToSolver(is,node->Outgoing); - node->Annotation.SetEmpty(); - hash_set *core = new hash_set; - core->insert(node->Outgoing->dual); - expr prev_annot = ctx.bool_val(false); - expr prev_impl = ctx.bool_val(false); - int repeated_case_count = 0; - while(1){ - by_case_counter++; - is.push(); - expr annot = !GetAnnotation(node); - Transformer old_annot = node->Annotation; - is.add(annot); - if(is.check() == unsat){ - is.pop(1); - break; - } - is.pop(1); - Push(); - expr the_impl = is.get_implicant(); - if(eq(the_impl,prev_impl)){ - // std::cout << "got old implicant\n"; - repeated_case_count++; - } - prev_impl = the_impl; - ConstrainEdgeLocalized(node->Outgoing,the_impl); - ConstrainEdgeLocalized(node->Outgoing,!GetAnnotation(node)); //TODO: need this? - - { - check_result foo = Check(root); - if(foo != unsat){ - Pop(1); - is.pop(1); - delete core; - timer_stop("InterpolateByCases"); - throw ReallyBad(); - // slvr().print("should_be_unsat.smt2"); - // throw "should be unsat"; - } - std::vector assumps, axioms_to_add; - slvr().get_proof().get_assumptions(assumps); - for(unsigned i = 0; i < assumps.size(); i++){ - (*core).insert(assumps[i]); - if(axioms_needed.find(assumps[i]) != axioms_needed.end()){ - axioms_to_add.push_back(assumps[i]); - axioms_needed.erase(assumps[i]); - } - } - // AddToProofCore(*core); - - try { - SolveSingleNode(root,node); - } - catch (char const *msg){ - // This happens if interpolation fails - Pop(1); - is.pop(1); - delete core; - timer_stop("InterpolateByCases"); - throw msg; - } - { - expr itp = GetAnnotation(node); - dualModel = is.get_model(); // TODO: what does this mean? - std::vector case_lits; - itp = StrengthenFormulaByCaseSplitting(itp, case_lits); - SetAnnotation(node,itp); - node->Annotation.Formula = node->Annotation.Formula.simplify(); - } - - for(unsigned i = 0; i < axioms_to_add.size(); i++) - is.add(axioms_to_add[i]); - -#define TEST_BAD -#ifdef TEST_BAD - { - static int bad_count = 0, num_bads = 1; - if(bad_count >= num_bads){ - bad_count = 0; - num_bads = num_bads * 2; - Pop(1); - is.pop(1); - delete core; - timer_stop("InterpolateByCases"); - throw Bad(); - } - bad_count++; - } -#endif - } - - if(node->Annotation.IsEmpty() || eq(node->Annotation.Formula,prev_annot) || (repeated_case_count > 0 && !axioms_added) || (repeated_case_count >= 10)){ - //looks_bad: - if(!axioms_added){ - // add the axioms in the off chance they are useful - const std::vector &theory = ls->get_axioms(); - for(unsigned i = 0; i < theory.size(); i++) - is.add(theory[i]); - axioms_added = true; - } - else { - //#define KILL_ON_BAD_INTERPOLANT -#ifdef KILL_ON_BAD_INTERPOLANT - std::cout << "bad in InterpolateByCase -- core:\n"; -#if 0 - std::vector assumps; - slvr().get_proof().get_assumptions(assumps); - for(unsigned i = 0; i < assumps.size(); i++) - assumps[i].show(); -#endif - std::cout << "checking for inconsistency\n"; - std::cout << "model:\n"; - is.get_model().show(); - expr impl = is.get_implicant(); - std::vector conjuncts; - CollectConjuncts(impl,conjuncts,true); - std::cout << "impl:\n"; - for(unsigned i = 0; i < conjuncts.size(); i++) - conjuncts[i].show(); - std::cout << "annot:\n"; - annot.show(); - is.add(annot); - for(unsigned i = 0; i < conjuncts.size(); i++) - is.add(conjuncts[i]); - if(is.check() == unsat){ - std::cout << "inconsistent!\n"; - std::vector is_assumps; - is.aux_solver.get_proof().get_assumptions(is_assumps); - std::cout << "core:\n"; - for(unsigned i = 0; i < is_assumps.size(); i++) - is_assumps[i].show(); - } - else { - std::cout << "consistent!\n"; - is.aux_solver.print("should_be_inconsistent.smt2"); - } - std::cout << "by_case_counter = " << by_case_counter << "\n"; - throw "ack!"; -#endif - Pop(1); - is.pop(1); - delete core; - timer_stop("InterpolateByCases"); - throw ReallyBad(); - } - } - Pop(1); - prev_annot = node->Annotation.Formula; - node->Annotation.UnionWith(old_annot); - } - if(proof_core) - delete proof_core; // shouldn't happen - proof_core = core; - is.pop(1); - timer_stop("InterpolateByCases"); - } - - void RPFP::Generalize(Node *root, Node *node){ - timer_start("Generalize"); - aux_solver.push(); - AddEdgeToSolver(node->Outgoing); - expr fmla = GetAnnotation(node); - std::vector conjuncts; - CollectConjuncts(fmla,conjuncts,false); - GreedyReduce(aux_solver,conjuncts); // try to remove conjuncts one at a tme - aux_solver.pop(1); - NegateLits(conjuncts); - SetAnnotation(node,SimplifyOr(conjuncts)); - timer_stop("Generalize"); - } - - RPFP_caching::edge_solver &RPFP_caching::SolverForEdge(Edge *edge, bool models, bool axioms){ - edge_solver &es = edge_solvers[edge]; - uptr &p = es.slvr; - if(!p.get()){ - scoped_no_proof no_proofs_please(ctx.m()); // no proofs - p.set(new solver(ctx,true,models)); // no models - if(axioms){ - RPFP::LogicSolver *ls = edge->owner->ls; - const std::vector &axs = ls->get_axioms(); - for(unsigned i = 0; i < axs.size(); i++) - p.get()->add(axs[i]); - } - } - return es; - } - - - // caching version of above - void RPFP_caching::GeneralizeCache(Edge *edge){ - timer_start("Generalize"); - scoped_solver_for_edge ssfe(this,edge); - Node *node = edge->Parent; - std::vector assumps, core, conjuncts; - AssertEdgeCache(edge,assumps); - for(unsigned i = 0; i < edge->Children.size(); i++){ - expr as = GetAnnotation(edge->Children[i]); - std::vector clauses; - if(!as.is_true()){ - CollectConjuncts(as.arg(1),clauses); - for(unsigned j = 0; j < clauses.size(); j++) - GetAssumptionLits(as.arg(0) || clauses[j],assumps); - } - } - expr fmla = GetAnnotation(node); - std::vector lits; - if(fmla.is_true()){ - timer_stop("Generalize"); - return; - } - assumps.push_back(fmla.arg(0).arg(0)); - CollectConjuncts(!fmla.arg(1),lits); -#if 0 - for(unsigned i = 0; i < lits.size(); i++){ - const expr &lit = lits[i]; - if(lit.is_app() && lit.decl().get_decl_kind() == Equal){ - lits[i] = ctx.make(Leq,lit.arg(0),lit.arg(1)); - lits.push_back(ctx.make(Leq,lit.arg(1),lit.arg(0))); - } - } -#endif - hash_map lit_map; - for(unsigned i = 0; i < lits.size(); i++) - GetAssumptionLits(lits[i],core,&lit_map); - GreedyReduceCache(assumps,core); - for(unsigned i = 0; i < core.size(); i++) - conjuncts.push_back(lit_map[core[i]]); - NegateLits(conjuncts); - SetAnnotation(node,SimplifyOr(conjuncts)); - timer_stop("Generalize"); - } - - // caching version of above - bool RPFP_caching::PropagateCache(Edge *edge){ - timer_start("PropagateCache"); - scoped_solver_for_edge ssfe(this,edge); - bool some = false; - { - std::vector candidates, skip; - Node *node = edge->Parent; - CollectConjuncts(node->Annotation.Formula,skip); - for(unsigned i = 0; i < edge->Children.size(); i++){ - Node *child = edge->Children[i]; - if(child->map == node->map){ - CollectConjuncts(child->Annotation.Formula,candidates); - break; - } - } - if(candidates.empty()) goto done; - hash_set skip_set; - std::copy(skip.begin(),skip.end(),std::inserter(skip_set,skip_set.begin())); - std::vector new_candidates; - for(unsigned i = 0; i < candidates.size(); i++) - if(skip_set.find(candidates[i]) == skip_set.end()) - new_candidates.push_back(candidates[i]); - candidates.swap(new_candidates); - if(candidates.empty()) goto done; - std::vector assumps, core, conjuncts; - AssertEdgeCache(edge,assumps); - for(unsigned i = 0; i < edge->Children.size(); i++){ - expr ass = GetAnnotation(edge->Children[i]); - if(eq(ass,ctx.bool_val(true))) - continue; - std::vector clauses; - CollectConjuncts(ass.arg(1),clauses); - for(unsigned j = 0; j < clauses.size(); j++) - GetAssumptionLits(ass.arg(0) || clauses[j],assumps); - } - for(unsigned i = 0; i < candidates.size(); i++){ - unsigned old_size = assumps.size(); - node->Annotation.Formula = candidates[i]; - expr fmla = GetAnnotation(node); - assumps.push_back(fmla.arg(0).arg(0)); - GetAssumptionLits(!fmla.arg(1),assumps); - std::vector full_core; - check_result res = CheckCore(assumps,full_core); - if(res == unsat) - conjuncts.push_back(candidates[i]); - assumps.resize(old_size); - } - if(conjuncts.empty()) - goto done; - SetAnnotation(node,SimplifyAnd(conjuncts)); - some = true; - } - done: - timer_stop("PropagateCache"); - return some; - } - - - /** Push a scope. Assertions made after Push can be undone by Pop. */ - - void RPFP::Push() - { - stack.push_back(stack_entry()); - slvr_push(); - } - - /** Pop a scope (see Push). Note, you cannot pop axioms. */ - - void RPFP::Pop(int num_scopes) - { - slvr_pop(num_scopes); - for (int i = 0; i < num_scopes; i++) - { - stack_entry &back = stack.back(); - for(std::list::iterator it = back.edges.begin(), en = back.edges.end(); it != en; ++it) - (*it)->dual = expr(ctx,nullptr); - for(std::list::iterator it = back.nodes.begin(), en = back.nodes.end(); it != en; ++it) - (*it)->dual = expr(ctx,nullptr); - for(std::list >::iterator it = back.constraints.begin(), en = back.constraints.end(); it != en; ++it) - (*it).first->constraints.pop_back(); - stack.pop_back(); - } - } - - /** Erase the proof by performing a Pop, Push and re-assertion of - all the popped constraints */ - - void RPFP::PopPush(){ - slvr_pop(1); - slvr_push(); - stack_entry &back = stack.back(); - for(std::list::iterator it = back.edges.begin(), en = back.edges.end(); it != en; ++it) - slvr_add((*it)->dual); - for(std::list::iterator it = back.nodes.begin(), en = back.nodes.end(); it != en; ++it) - slvr_add((*it)->dual); - for(std::list >::iterator it = back.constraints.begin(), en = back.constraints.end(); it != en; ++it) - slvr_add((*it).second); - } - - - - // This returns a new FuncDel with same sort as top-level function - // of term t, but with numeric suffix appended to name. - - Z3User::FuncDecl Z3User::SuffixFuncDecl(const Term &t, int n) - { - std::string name = t.decl().name().str() + "_" + string_of_int(n); - std::vector sorts; - int nargs = t.num_args(); - sorts.reserve(nargs); - for(int i = 0; i < nargs; i++) - sorts.push_back(t.arg(i).get_sort()); - return ctx.function(name.c_str(), nargs, VEC2PTR(sorts), t.get_sort()); - } - - Z3User::FuncDecl Z3User::RenumberPred(const FuncDecl &f, int n) - { - std::string name = f.name().str(); - name = name.substr(0,name.rfind('_')) + "_" + string_of_int(n); - int arity = f.arity(); - std::vector domain; - domain.reserve(arity); - for(int i = 0; i < arity; i++) - domain.push_back(f.domain(i)); - return ctx.function(name.c_str(), arity, VEC2PTR(domain), f.range()); - } - - Z3User::FuncDecl Z3User::NumberPred(const FuncDecl &f, int n) - { - std::string name = f.name().str(); - name = name + "_" + string_of_int(n); - int arity = f.arity(); - std::vector domain; - domain.reserve(arity); - for(int i = 0; i < arity; i++) - domain.push_back(f.domain(i)); - return ctx.function(name.c_str(), arity, VEC2PTR(domain), f.range()); - } - - // Scan the clause body for occurrences of the predicate unknowns - - RPFP::Term RPFP::ScanBody(hash_map &memo, - const Term &t, - hash_map &pmap, - std::vector &parms, - std::vector &nodes) - { - if(memo.find(t) != memo.end()) - return memo[t]; - Term res(ctx); - if (t.is_app()) { - func_decl f = t.decl(); - if(pmap.find(f) != pmap.end()){ - nodes.push_back(pmap[f]); - f = SuffixFuncDecl(t,parms.size()); - parms.push_back(f); - } - int nargs = t.num_args(); - std::vector args; - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(ScanBody(memo,t.arg(i),pmap,parms,nodes)); - res = f(nargs, VEC2PTR(args)); - } - else if (t.is_quantifier()) - res = CloneQuantifier(t,ScanBody(memo,t.body(),pmap,parms,nodes)); - else - res = t; - memo[t] = res; - return res; - } - - // return the func_del of an app if it is uninterpreted - - bool Z3User::get_relation(const Term &t, func_decl &R){ - if(!t.is_app()) - return false; - R = t.decl(); - return R.get_decl_kind() == Uninterpreted; - } - - // return true if term is an individual variable - // TODO: have to check that it is not a background symbol - - bool Z3User::is_variable(const Term &t){ - if(!t.is_app()) - return t.is_var(); - return t.decl().get_decl_kind() == Uninterpreted - && t.num_args() == 0; - } - - RPFP::Term RPFP::RemoveLabelsRec(hash_map &memo, const Term &t, - std::vector &lbls){ - if(memo.find(t) != memo.end()) - return memo[t]; - Term res(ctx); - if (t.is_app()){ - func_decl f = t.decl(); - std::vector names; - bool pos; - if(t.is_label(pos,names)){ - res = RemoveLabelsRec(memo,t.arg(0),lbls); - for(unsigned i = 0; i < names.size(); i++) - lbls.push_back(label_struct(names[i],res,pos)); - } - else { - int nargs = t.num_args(); - std::vector args; - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(RemoveLabelsRec(memo,t.arg(i),lbls)); - res = f(nargs, VEC2PTR(args)); - } - } - else if (t.is_quantifier()) - res = CloneQuantifier(t,RemoveLabelsRec(memo,t.body(),lbls)); - else - res = t; - memo[t] = res; - return res; - } - - RPFP::Term RPFP::RemoveLabels(const Term &t, std::vector &lbls){ - hash_map memo ; - return RemoveLabelsRec(memo,t,lbls); - } - - RPFP::Term RPFP::SubstBoundRec(hash_map > &memo, hash_map &subst, int level, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo[level].insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) - { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - if(nargs == 0 && f.get_decl_kind() == Uninterpreted) - ls->declare_constant(f); // keep track of background constants - for(int i = 0; i < nargs; i++) - args.push_back(SubstBoundRec(memo, subst, level, t.arg(i))); - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()){ - int bound = t.get_quantifier_num_bound(); - std::vector pats; - t.get_patterns(pats); - for(unsigned i = 0; i < pats.size(); i++) - pats[i] = SubstBoundRec(memo, subst, level + bound, pats[i]); - res = clone_quantifier(t, SubstBoundRec(memo, subst, level + bound, t.body()), pats); - } - else if (t.is_var()) { - int idx = t.get_index_value(); - if(idx >= level && subst.find(idx-level) != subst.end()){ - res = subst[idx-level]; - } - else res = t; - } - else res = t; - return res; - } - - RPFP::Term RPFP::SubstBound(hash_map &subst, const Term &t){ - hash_map > memo; - return SubstBoundRec(memo, subst, 0, t); - } - - // Eliminate the deBruijn indices from level to level+num-1 - Z3User::Term Z3User::DeleteBoundRec(hash_map > &memo, int level, int num, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo[level].insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) - { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(DeleteBoundRec(memo, level, num, t.arg(i))); - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()){ - int bound = t.get_quantifier_num_bound(); - std::vector pats; - t.get_patterns(pats); - for(unsigned i = 0; i < pats.size(); i++) - pats[i] = DeleteBoundRec(memo, level + bound, num, pats[i]); - res = clone_quantifier(t, DeleteBoundRec(memo, level + bound, num, t.body()), pats); - } - else if (t.is_var()) { - int idx = t.get_index_value(); - if(idx >= level){ - res = ctx.make_var(idx-num,t.get_sort()); - } - else res = t; - } - else res = t; - return res; - } - - Z3User::Term Z3User::DeleteBound(int level, int num, const Term &t){ - hash_map > memo; - return DeleteBoundRec(memo, level, num, t); - } - - int Z3User::MaxIndex(hash_map &memo, const Term &t) - { - std::pair foo(t,-1); - std::pair::iterator, bool> bar = memo.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()){ - func_decl f = t.decl(); - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++){ - int m = MaxIndex(memo, t.arg(i)); - if(m > res) - res = m; - } - } - else if (t.is_quantifier()){ - int bound = t.get_quantifier_num_bound(); - res = MaxIndex(memo,t.body()) - bound; - } - else if (t.is_var()) { - res = t.get_index_value(); - } - return res; - } - - bool Z3User::IsClosedFormula(const Term &t){ - hash_map memo; - return MaxIndex(memo,t) < 0; - } - - - /** Convert a collection of clauses to Nodes and Edges in the RPFP. - - Predicate unknowns are uninterpreted predicates not - occurring in the background theory. - - Clauses are of the form - - B => P(t_1,...,t_k) - - where P is a predicate unknown and predicate unknowns - occur only positivey in H and only under existential - quantifiers in prenex form. - - Each predicate unknown maps to a node. Each clause maps to - an edge. Let C be a clause B => P(t_1,...,t_k) where the - sequence of predicate unknowns occurring in B (in order - of occurrence) is P_1..P_n. The clause maps to a transformer - T where: - - T.Relparams = P_1..P_n - T.Indparams = x_1...x+k - T.Formula = B /\ t_1 = x_1 /\ ... /\ t_k = x_k - - Throws exception bad_clause(msg,i) if a clause i is - in the wrong form. - - */ - - - static bool canonical_clause(const expr &clause){ - if(clause.decl().get_decl_kind() != Implies) - return false; - expr arg = clause.arg(1); - return arg.is_app() && (arg.decl().get_decl_kind() == False || - arg.decl().get_decl_kind() == Uninterpreted); - } - -#define USE_QE_LITE - - void RPFP::FromClauses(const std::vector &unskolemized_clauses, const std::vector *bounds){ - hash_map pmap; - func_decl fail_pred = ctx.fresh_func_decl("@Fail", ctx.bool_sort()); - - std::vector clauses(unskolemized_clauses); - // first, skolemize the clauses - -#ifndef USE_QE_LITE - for(unsigned i = 0; i < clauses.size(); i++){ - expr &t = clauses[i]; - if (t.is_quantifier() && t.is_quantifier_forall()) { - int bound = t.get_quantifier_num_bound(); - std::vector sorts; - std::vector names; - hash_map subst; - for(int j = 0; j < bound; j++){ - sort the_sort = t.get_quantifier_bound_sort(j); - symbol name = t.get_quantifier_bound_name(j); - expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort)); - subst[bound-1-j] = skolem; - } - t = SubstBound(subst,t.body()); - } - } -#else - std::vector > substs(clauses.size()); -#endif - - // create the nodes from the heads of the clauses - - for(unsigned i = 0; i < clauses.size(); i++){ - Term &clause = clauses[i]; - -#ifdef USE_QE_LITE - Term &t = clause; - if (t.is_quantifier() && t.is_quantifier_forall()) { - int bound = t.get_quantifier_num_bound(); - std::vector sorts; - std::vector names; - for(int j = 0; j < bound; j++){ - sort the_sort = t.get_quantifier_bound_sort(j); - symbol name = t.get_quantifier_bound_name(j); - expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort)); - substs[i][bound-1-j] = skolem; - } - clause = t.body(); - } - -#endif - - if(clause.is_app() && clause.decl().get_decl_kind() == Uninterpreted) - clause = implies(ctx.bool_val(true),clause); - if(!canonical_clause(clause)) - clause = implies((!clause).simplify(),ctx.bool_val(false)); - Term head = clause.arg(1); - func_decl R(ctx); - bool is_query = false; - if (eq(head,ctx.bool_val(false))){ - R = fail_pred; - // R = ctx.constant("@Fail", ctx.bool_sort()).decl(); - is_query = true; - } - else if(!get_relation(head,R)) - throw bad_clause("rhs must be a predicate application",i); - if(pmap.find(R) == pmap.end()){ - - // If the node doesn't exitst, create it. The Indparams - // are arbitrary, but we use the rhs arguments if they - // are variables for mnomonic value. - - hash_set seen; - std::vector Indparams; - for(unsigned j = 0; j < head.num_args(); j++){ - Term arg = head.arg(j); - if(!is_variable(arg) || seen.find(arg) != seen.end()){ - std::string name = std::string("@a_") + string_of_int(j); - arg = ctx.constant(name.c_str(),arg.get_sort()); - } - seen.insert(arg); - Indparams.push_back(arg); - } -#ifdef USE_QE_LITE - { - hash_map > sb_memo; - for(unsigned j = 0; j < Indparams.size(); j++) - Indparams[j] = SubstBoundRec(sb_memo, substs[i], 0, Indparams[j]); - } -#endif - Node *node = CreateNode(R(Indparams.size(),VEC2PTR(Indparams))); - //nodes.push_back(node); - pmap[R] = node; - if (is_query) - node->Bound = CreateRelation(std::vector(), ctx.bool_val(false)); - node->recursion_bound = bounds ? 0 : UINT_MAX; - } - } - - bool some_labels = false; - - // create the edges - - for(unsigned i = 0; i < clauses.size(); i++){ - Term clause = clauses[i]; - Term body = clause.arg(0); - Term head = clause.arg(1); - func_decl R(ctx); - if (eq(head,ctx.bool_val(false))) - R = fail_pred; - //R = ctx.constant("@Fail", ctx.bool_sort()).decl(); - else get_relation(head,R); - Node *Parent = pmap[R]; - std::vector Indparams; - hash_set seen; - for(unsigned j = 0; j < head.num_args(); j++){ - Term arg = head.arg(j); - if(!is_variable(arg) || seen.find(arg) != seen.end()){ - std::string name = std::string("@a_") + string_of_int(j); - Term var = ctx.constant(name.c_str(),arg.get_sort()); - body = body && (arg == var); - arg = var; - } - seen.insert(arg); - Indparams.push_back(arg); - } - - // We extract the relparams positionally - - std::vector Relparams; - hash_map scan_memo; - std::vector Children; - body = ScanBody(scan_memo,body,pmap,Relparams,Children); - Term labeled = body; - std::vector lbls; // TODO: throw this away for now - body = RemoveLabels(body,lbls); - if(!eq(labeled,body)) - some_labels = true; // remember if there are labels, as we then can't do qe_lite - // body = IneqToEq(body); // UFO converts x=y to (x<=y & x >= y). Undo this. - body = body.simplify(); - -#ifdef USE_QE_LITE - std::set idxs; - if(!some_labels){ // can't do qe_lite if we have to reconstruct labels - for(unsigned j = 0; j < Indparams.size(); j++) - if(Indparams[j].is_var()) - idxs.insert(Indparams[j].get_index_value()); - body = body.qe_lite(idxs,false); - } - hash_map > sb_memo; - body = SubstBoundRec(sb_memo,substs[i],0,body); - if(some_labels) - labeled = SubstBoundRec(sb_memo,substs[i],0,labeled); - for(unsigned j = 0; j < Indparams.size(); j++) - Indparams[j] = SubstBoundRec(sb_memo, substs[i], 0, Indparams[j]); -#endif - - // Create the edge - Transformer T = CreateTransformer(Relparams,Indparams,body); - Edge *edge = CreateEdge(Parent,T,Children); - edge->labeled = labeled;; // remember for label extraction - if(bounds) - Parent->recursion_bound = std::max(Parent->recursion_bound,(*bounds)[i]); - // edges.push_back(edge); - } - - // undo hoisting of expressions out of loops - RemoveDeadNodes(); - Unhoist(); - // FuseEdges(); - } - - - // The following mess is used to undo hoisting of expressions outside loops by compilers - - expr RPFP::UnhoistPullRec(hash_map & memo, const expr &w, hash_map & init_defs, hash_map & const_params, hash_map &const_params_inv, std::vector &new_params){ - if(memo.find(w) != memo.end()) - return memo[w]; - expr res; - if(init_defs.find(w) != init_defs.end()){ - expr d = init_defs[w]; - std::vector vars; - hash_set get_vars_memo; - GetVarsRec(get_vars_memo,d,vars); - hash_map map; - for(unsigned j = 0; j < vars.size(); j++){ - expr x = vars[j]; - map[x] = UnhoistPullRec(memo,x,init_defs,const_params,const_params_inv,new_params); - } - expr defn = SubstRec(map,d); - res = defn; - } - else if(const_params_inv.find(w) == const_params_inv.end()){ - std::string old_name = w.decl().name().str(); - func_decl fresh = ctx.fresh_func_decl(old_name.c_str(), w.get_sort()); - expr y = fresh(); - const_params[y] = w; - const_params_inv[w] = y; - new_params.push_back(y); - res = y; - } - else - res = const_params_inv[w]; - memo[w] = res; - return res; - } - - void RPFP::AddParamsToTransformer(Transformer &trans, const std::vector ¶ms){ - std::copy(params.begin(),params.end(),std::inserter(trans.IndParams,trans.IndParams.end())); - } - - expr RPFP::AddParamsToApp(const expr &app, const func_decl &new_decl, const std::vector ¶ms){ - int n = app.num_args(); - std::vector args(n); - for (int i = 0; i < n; i++) - args[i] = app.arg(i); - std::copy(params.begin(),params.end(),std::inserter(args,args.end())); - return new_decl(args); - } - - expr RPFP::GetRelRec(hash_set &memo, const expr &t, const func_decl &rel){ - if(memo.find(t) != memo.end()) - return expr(); - memo.insert(t); - if (t.is_app()) - { - func_decl f = t.decl(); - if(f == rel) - return t; - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++){ - expr res = GetRelRec(memo,t.arg(i),rel); - if(!res.null()) - return res; - } - } - else if (t.is_quantifier()) - return GetRelRec(memo,t.body(),rel); - return expr(); - } - - expr RPFP::GetRel(Edge *edge, int child_idx){ - func_decl &rel = edge->F.RelParams[child_idx]; - hash_set memo; - return GetRelRec(memo,edge->F.Formula,rel); - } - - void RPFP::GetDefsRec(const expr &cnst, hash_map &defs){ - if(cnst.is_app()){ - switch(cnst.decl().get_decl_kind()){ - case And: { - int n = cnst.num_args(); - for(int i = 0; i < n; i++) - GetDefsRec(cnst.arg(i),defs); - break; - } - case Equal: { - expr lhs = cnst.arg(0); - expr rhs = cnst.arg(1); - if(IsVar(lhs)) - defs[lhs] = rhs; - break; - } - default: - break; - } - } - } - - void RPFP::GetDefs(const expr &cnst, hash_map &defs){ - // GetDefsRec(IneqToEq(cnst),defs); - GetDefsRec(cnst,defs); - } - - bool RPFP::IsVar(const expr &t){ - return t.is_app() && t.num_args() == 0 && t.decl().get_decl_kind() == Uninterpreted; - } - - void RPFP::GetVarsRec(hash_set &memo, const expr &t, std::vector &vars){ - if(memo.find(t) != memo.end()) - return; - memo.insert(t); - if (t.is_app()) - { - if(IsVar(t)){ - vars.push_back(t); - return; - } - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++){ - GetVarsRec(memo,t.arg(i),vars); - } - } - else if (t.is_quantifier()) - GetVarsRec(memo,t.body(),vars); - } - - void RPFP::AddParamsToNode(Node *node, const std::vector ¶ms){ - int arity = node->Annotation.IndParams.size(); - std::vector domain; - domain.reserve(arity + params.size()); - for(int i = 0; i < arity; i++) - domain.push_back(node->Annotation.IndParams[i].get_sort()); - for(unsigned i = 0; i < params.size(); i++) - domain.push_back(params[i].get_sort()); - std::string old_name = node->Name.name().str(); - func_decl fresh = ctx.fresh_func_decl(old_name.c_str(), domain, ctx.bool_sort()); - node->Name = fresh; - AddParamsToTransformer(node->Annotation,params); - AddParamsToTransformer(node->Bound,params); - AddParamsToTransformer(node->Underapprox,params); - } - - void RPFP::UnhoistLoop(Edge *loop_edge, Edge *init_edge){ - loop_edge->F.Formula = IneqToEq(loop_edge->F.Formula); - init_edge->F.Formula = IneqToEq(init_edge->F.Formula); - expr pre = GetRel(loop_edge,0); - if(pre.null()) - return; // this means the loop got simplified away - int nparams = loop_edge->F.IndParams.size(); - hash_map const_params, const_params_inv; - std::vector work_list; - // find the parameters that are constant in the loop - for(int i = 0; i < nparams; i++){ - if(eq(pre.arg(i),loop_edge->F.IndParams[i])){ - const_params[pre.arg(i)] = init_edge->F.IndParams[i]; - const_params_inv[init_edge->F.IndParams[i]] = pre.arg(i); - work_list.push_back(pre.arg(i)); - } - } - // get the definitions in the initialization - hash_map defs,memo,subst; - GetDefs(init_edge->F.Formula,defs); - // try to pull them inside the loop - std::vector new_params; - for(unsigned i = 0; i < work_list.size(); i++){ - expr v = work_list[i]; - expr w = const_params[v]; - expr def = UnhoistPullRec(memo,w,defs,const_params,const_params_inv,new_params); - if(!eq(def,v)) - subst[v] = def; - } - // do the substitutions - if(subst.empty()) - return; - subst[pre] = pre; // don't substitute inside the precondition itself - loop_edge->F.Formula = SubstRec(subst,loop_edge->F.Formula); - loop_edge->F.Formula = ElimIte(loop_edge->F.Formula); - init_edge->F.Formula = ElimIte(init_edge->F.Formula); - // add the new parameters - if(new_params.empty()) - return; - Node *parent = loop_edge->Parent; - AddParamsToNode(parent,new_params); - AddParamsToTransformer(loop_edge->F,new_params); - AddParamsToTransformer(init_edge->F,new_params); - std::vector &incoming = parent->Incoming; - for(unsigned i = 0; i < incoming.size(); i++){ - Edge *in_edge = incoming[i]; - std::vector &chs = in_edge->Children; - for(unsigned j = 0; j < chs.size(); j++) - if(chs[j] == parent){ - expr lit = GetRel(in_edge,j); - expr new_lit = AddParamsToApp(lit,parent->Name,new_params); - func_decl fd = SuffixFuncDecl(new_lit,j); - int nargs = new_lit.num_args(); - std::vector args; - args.reserve(nargs); - for(int k = 0; k < nargs; k++) - args.push_back(new_lit.arg(k)); - new_lit = fd(nargs, VEC2PTR(args)); - in_edge->F.RelParams[j] = fd; - hash_map map; - map[lit] = new_lit; - in_edge->F.Formula = SubstRec(map,in_edge->F.Formula); - } - } - } - - void RPFP::Unhoist(){ - hash_map > outgoing; - for(unsigned i = 0; i < edges.size(); i++) - outgoing[edges[i]->Parent].push_back(edges[i]); - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - std::vector &outs = outgoing[node]; - // if we're not a simple loop with one entry, give up - if(outs.size() == 2){ - for(int j = 0; j < 2; j++){ - Edge *loop_edge = outs[j]; - Edge *init_edge = outs[1-j]; - if(loop_edge->Children.size() == 1 && loop_edge->Children[0] == loop_edge->Parent){ - UnhoistLoop(loop_edge,init_edge); - break; - } - } - } - } - } - - void RPFP::FuseEdges(){ - hash_map > outgoing; - for(unsigned i = 0; i < edges.size(); i++){ - outgoing[edges[i]->Parent].push_back(edges[i]); - } - hash_set edges_to_delete; - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - std::vector &outs = outgoing[node]; - if(outs.size() > 1 && outs.size() <= 16){ - std::vector trs(outs.size()); - for(unsigned j = 0; j < outs.size(); j++) - trs[j] = &outs[j]->F; - Transformer tr = Fuse(trs); - std::vector chs; - for(unsigned j = 0; j < outs.size(); j++) - for(unsigned k = 0; k < outs[j]->Children.size(); k++) - chs.push_back(outs[j]->Children[k]); - CreateEdge(node,tr,chs); - for(unsigned j = 0; j < outs.size(); j++) - edges_to_delete.insert(outs[j]); - } - } - std::vector new_edges; - hash_set all_nodes; - for(unsigned j = 0; j < edges.size(); j++){ - if(edges_to_delete.find(edges[j]) == edges_to_delete.end()){ -#if 0 - if(all_nodes.find(edges[j]->Parent) != all_nodes.end()) - throw "help!"; - all_nodes.insert(edges[j]->Parent); -#endif - new_edges.push_back(edges[j]); - } - else - delete edges[j]; - } - edges.swap(new_edges); - } - - void RPFP::MarkLiveNodes(hash_map > &outgoing, hash_set &live_nodes, Node *node){ - if(live_nodes.find(node) != live_nodes.end()) - return; - live_nodes.insert(node); - std::vector &outs = outgoing[node]; - for(unsigned i = 0; i < outs.size(); i++) - for(unsigned j = 0; j < outs[i]->Children.size(); j++) - MarkLiveNodes(outgoing, live_nodes,outs[i]->Children[j]); - } - - void RPFP::RemoveDeadNodes(){ - hash_map > outgoing; - for(unsigned i = 0; i < edges.size(); i++) - outgoing[edges[i]->Parent].push_back(edges[i]); - hash_set live_nodes; - for(unsigned i = 0; i < nodes.size(); i++) - if(!nodes[i]->Bound.IsFull()) - MarkLiveNodes(outgoing,live_nodes,nodes[i]); - std::vector new_edges; - for(unsigned j = 0; j < edges.size(); j++){ - if(live_nodes.find(edges[j]->Parent) != live_nodes.end()) - new_edges.push_back(edges[j]); - else { - Edge *edge = edges[j]; - for(unsigned int i = 0; i < edge->Children.size(); i++){ - std::vector &ic = edge->Children[i]->Incoming; - for(std::vector::iterator it = ic.begin(), en = ic.end(); it != en; ++it){ - if(*it == edge){ - ic.erase(it); - break; - } - } - } - delete edge; - } - } - edges.swap(new_edges); - std::vector new_nodes; - for(unsigned j = 0; j < nodes.size(); j++){ - if(live_nodes.find(nodes[j]) != live_nodes.end()) - new_nodes.push_back(nodes[j]); - else - delete nodes[j]; - } - nodes.swap(new_nodes); - } - - void RPFP::WriteSolution(std::ostream &s){ - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - Term asgn = (node->Name)(node->Annotation.IndParams) == node->Annotation.Formula; - s << asgn << std::endl; - } - } - - void RPFP::WriteEdgeVars(Edge *e, hash_map &memo, const Term &t, std::ostream &s) - { - std::pair foo(t,0); - std::pair::iterator, bool> bar = memo.insert(foo); - // int &res = bar.first->second; - if(!bar.second) return; - hash_map::iterator it = e->varMap.find(t); - if (it != e->varMap.end()){ - return; - } - if (t.is_app()) - { - func_decl f = t.decl(); - // int idx; - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++) - WriteEdgeVars(e, memo, t.arg(i),s); - if (nargs == 0 && f.get_decl_kind() == Uninterpreted && !ls->is_constant(f)){ - Term rename = HideVariable(t,e->number); - Term value = dualModel.eval(rename); - s << " (= " << t << " " << value << ")\n"; - } - } - else if (t.is_quantifier()) - WriteEdgeVars(e,memo,t.body(),s); - return; - } - - void RPFP::WriteEdgeAssignment(std::ostream &s, Edge *e){ - s << "(\n"; - hash_map memo; - WriteEdgeVars(e, memo, e->F.Formula ,s); - s << ")\n"; - } - - void RPFP::WriteCounterexample(std::ostream &s, Node *node){ - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++){ - Node *child = node->Outgoing->Children[i]; - if(!Empty(child)) - WriteCounterexample(s,child); - } - s << "(" << node->number << " : " << EvalNode(node) << " <- "; - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++){ - Node *child = node->Outgoing->Children[i]; - if(!Empty(child)) - s << " " << node->Outgoing->Children[i]->number; - } - s << ")" << std::endl; - WriteEdgeAssignment(s,node->Outgoing); - } - - RPFP::Term RPFP::ToRuleRec(Edge *e, hash_map &memo, const Term &t, std::vector &quants) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) - { - func_decl f = t.decl(); - // int idx; - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(ToRuleRec(e, memo, t.arg(i),quants)); - hash_map::iterator rit = e->relMap.find(f); - if(rit != e->relMap.end()){ - Node* child = e->Children[rit->second]; - FuncDecl op = child->Name; - res = op(args.size(), VEC2PTR(args)); - } - else { - res = f(args.size(), VEC2PTR(args)); - if(nargs == 0 && t.decl().get_decl_kind() == Uninterpreted) - quants.push_back(t); - } - } - else if (t.is_quantifier()) - { - Term body = ToRuleRec(e,memo,t.body(),quants); - res = CloneQuantifier(t,body); - } - else res = t; - return res; - } - - - void RPFP::ToClauses(std::vector &cnsts, FileFormat format){ - cnsts.resize(edges.size()); - for(unsigned i = 0; i < edges.size(); i++){ - Edge *edge = edges[i]; - SetEdgeMaps(edge); - std::vector quants; - hash_map memo; - Term lhs = ToRuleRec(edge, memo, edge->F.Formula,quants); - Term rhs = (edge->Parent->Name)(edge->F.IndParams.size(),&edge->F.IndParams[0]); - for(unsigned j = 0; j < edge->F.IndParams.size(); j++) - ToRuleRec(edge,memo,edge->F.IndParams[j],quants); // just to get quants - Term cnst = implies(lhs,rhs); -#if 0 - for(unsigned i = 0; i < quants.size(); i++){ - std::cout << expr(ctx,(Z3_ast)quants[i]) << " : " << sort(ctx,Z3_get_sort(ctx,(Z3_ast)quants[i])) << std::endl; - } -#endif - if(format != DualityFormat) - cnst= forall(quants,cnst); - cnsts[i] = cnst; - } - // int num_rules = cnsts.size(); - - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - if(!node->Bound.IsFull()){ - Term lhs = (node->Name)(node->Bound.IndParams) && !node->Bound.Formula; - Term cnst = implies(lhs,ctx.bool_val(false)); - if(format != DualityFormat){ - std::vector quants; - for(unsigned j = 0; j < node->Bound.IndParams.size(); j++) - quants.push_back(node->Bound.IndParams[j]); - if(format == HornFormat) - cnst= exists(quants,!cnst); - else - cnst= forall(quants, cnst); - } - cnsts.push_back(cnst); - } - } - - } - - - bool RPFP::proof_core_contains(const expr &e){ - return proof_core->find(e) != proof_core->end(); - } - - bool RPFP_caching::proof_core_contains(const expr &e){ - std::vector foo; - GetAssumptionLits(e,foo); - for(unsigned i = 0; i < foo.size(); i++) - if(proof_core->find(foo[i]) != proof_core->end()) - return true; - return false; - } - - bool RPFP::EdgeUsedInProof(Edge *edge){ - ComputeProofCore(); - if(!edge->dual.null() && proof_core_contains(edge->dual)) - return true; - for(unsigned i = 0; i < edge->constraints.size(); i++) - if(proof_core_contains(edge->constraints[i])) - return true; - return false; - } - - RPFP::~RPFP(){ - ClearProofCore(); - for(unsigned i = 0; i < nodes.size(); i++) - delete nodes[i]; - for(unsigned i = 0; i < edges.size(); i++) - delete edges[i]; - } -} - -#if 0 -void show_ast(expr *a){ - std::cout << *a; -} -#endif diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp deleted file mode 100644 index 7782f4a8b..000000000 --- a/src/duality/duality_solver.cpp +++ /dev/null @@ -1,3601 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - duality_solver.h - - Abstract: - - implements relational post-fixedpoint problem - (RPFP) solver - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#endif - -#include "duality/duality.h" -#include "duality/duality_profiling.h" - -#include -#include -#include -#include -#include -#include - -// TODO: make these official options or get rid of them - -#define NEW_CAND_SEL -// #define LOCALIZE_CONJECTURES -// #define CANDS_FROM_UPDATES -#define CANDS_FROM_COVER_FAIL -#define DEPTH_FIRST_EXPAND -#define MINIMIZE_CANDIDATES -// #define MINIMIZE_CANDIDATES_HARDER -#define BOUNDED -// #define CHECK_CANDS_FROM_IND_SET -#define UNDERAPPROX_NODES -#define NEW_EXPAND -#define EARLY_EXPAND -// #define TOP_DOWN -// #define EFFORT_BOUNDED_STRAT -#define SKIP_UNDERAPPROX_NODES -// #define KEEP_EXPANSIONS -// #define USE_CACHING_RPFP -// #define PROPAGATE_BEFORE_CHECK -#define NEW_STRATIFIED_INLINING - -#define USE_RPFP_CLONE -#define USE_NEW_GEN_CANDS - -//#define NO_PROPAGATE -//#define NO_GENERALIZE -//#define NO_DECISIONS - -namespace Duality { - - // TODO: must be a better place for this... - static char string_of_int_buffer[20]; - - static const char *string_of_int(int n){ - sprintf(string_of_int_buffer,"%d",n); - return string_of_int_buffer; - } - - /** Generic object for producing diagnostic output. */ - - class Reporter { - protected: - RPFP *rpfp; - public: - Reporter(RPFP *_rpfp){ - rpfp = _rpfp; - } - virtual void Extend(RPFP::Node *node){} - virtual void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager){} - virtual void Bound(RPFP::Node *node){} - virtual void Expand(RPFP::Edge *edge){} - virtual void AddCover(RPFP::Node *covered, std::vector &covering){} - virtual void RemoveCover(RPFP::Node *covered, RPFP::Node *covering){} - virtual void Conjecture(RPFP::Node *node, const RPFP::Transformer &t){} - virtual void Forcing(RPFP::Node *covered, RPFP::Node *covering){} - virtual void Dominates(RPFP::Node *node, RPFP::Node *other){} - virtual void InductionFailure(RPFP::Edge *edge, const std::vector &children){} - virtual void UpdateUnderapprox(RPFP::Node *node, const RPFP::Transformer &update){} - virtual void Reject(RPFP::Edge *edge, const std::vector &Children){} - virtual void Message(const std::string &msg){} - virtual void Depth(int){} - virtual ~Reporter(){} - }; - - Reporter *CreateStdoutReporter(RPFP *rpfp); - Reporter *CreateConjectureFileReporter(RPFP *rpfp, const std::string &fname); - - /** Object we throw in case of catastrophe. */ - - struct InternalError { - std::string msg; - InternalError(const std::string & _msg) - : msg(_msg) {} - }; - - - /** This is the main solver. It takes an arbitrary (possibly cyclic) - RPFP and either annotates it with a solution, or returns a - counterexample derivation in the form of an embedded RPFP tree. */ - - class Duality : public Solver { - - public: - Duality(RPFP *_rpfp) - : ctx(_rpfp->ctx), - slvr(_rpfp->slvr()), - nodes(_rpfp->nodes), - edges(_rpfp->edges) - { - rpfp = _rpfp; - reporter = nullptr; - conj_reporter = nullptr; - heuristic = nullptr; - unwinding = nullptr; - FullExpand = false; - NoConj = false; - FeasibleEdges = true; - UseUnderapprox = true; - Report = false; - StratifiedInlining = false; - RecursionBound = -1; - BatchExpand = false; - { - scoped_no_proof no_proofs_please(ctx.m()); -#ifdef USE_RPFP_CLONE - clone_rpfp = new RPFP_caching(rpfp->ls); - clone_rpfp->Clone(rpfp); -#endif -#ifdef USE_NEW_GEN_CANDS - gen_cands_rpfp = new RPFP_caching(rpfp->ls); - gen_cands_rpfp->Clone(rpfp); -#endif - } - } - - ~Duality() override { -#ifdef USE_RPFP_CLONE - delete clone_rpfp; -#endif -#ifdef USE_NEW_GEN_CANDS - delete gen_cands_rpfp; -#endif - if(unwinding) delete unwinding; - } - -#ifdef USE_RPFP_CLONE - RPFP_caching *clone_rpfp; -#endif -#ifdef USE_NEW_GEN_CANDS - RPFP_caching *gen_cands_rpfp; -#endif - - - typedef RPFP::Node Node; - typedef RPFP::Edge Edge; - - /** This struct represents a candidate for extending the - unwinding. It consists of an edge to instantiate - and a vector of children for the new instance. */ - - struct Candidate { - Edge *edge; std::vector - Children; - }; - - /** Comparison operator, allowing us to sort Nodes - by their number field. */ - - struct lnode - { - bool operator()(const Node* s1, const Node* s2) const - { - return s1->number < s2->number; - } - }; - - typedef std::set Unexpanded; // sorted set of Nodes - - /** This class provides a heuristic for expanding a derivation - tree. */ - - class Heuristic { - RPFP *rpfp; - - /** Heuristic score for unwinding nodes. Currently this - counts the number of updates. */ - struct score { - int updates; - score() : updates(0) {} - }; - hash_map scores; - - public: - Heuristic(RPFP *_rpfp){ - rpfp = _rpfp; - } - - virtual ~Heuristic(){} - - virtual void Update(RPFP::Node *node){ - scores[node].updates++; - } - - /** Heuristic choice of nodes to expand. Takes a set "choices" - and returns a subset "best". We currently choose the - nodes with the fewest updates. - */ -#if 0 - virtual void ChooseExpand(const std::set &choices, std::set &best){ - int best_score = INT_MAX; - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it){ - Node *node = (*it)->map; - int score = scores[node].updates; - best_score = std::min(best_score,score); - } - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it) - if(scores[(*it)->map].updates == best_score) - best.insert(*it); - } -#else - virtual void ChooseExpand(const std::set &choices, std::set &best, bool high_priority=false, bool best_only=false){ - if(high_priority) return; - int best_score = INT_MAX; - int worst_score = 0; - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it){ - Node *node = (*it)->map; - int score = scores[node].updates; - best_score = std::min(best_score,score); - worst_score = std::max(worst_score,score); - } - int cutoff = best_only ? best_score : (best_score + (worst_score-best_score)/2); - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it) - if(scores[(*it)->map].updates <= cutoff) - best.insert(*it); - } -#endif - - /** Called when done expanding a tree */ - virtual void Done() {} - - /** Ask whether a node should be used/unused in the tree. Returns, - 1 if yes, -1 if no, and 0 if don't care. */ - - virtual int UseNode(Node *node){ - return 0; - } - }; - - /** The Proposer class proposes conjectures eagerly. These can come - from any source, including predicate abstraction, templates, or - previous solver runs. The proposed conjectures are checked - with low effort when the unwinding is expanded. - */ - - class Proposer { - public: - /** Given a node in the unwinding, propose some conjectures */ - virtual std::vector &Propose(Node *node) = 0; - virtual ~Proposer(){}; - }; - - - class Covering; // see below - - // These members represent the state of the algorithm. - - RPFP *rpfp; // the input RPFP - Reporter *reporter; // object for logging - Reporter *conj_reporter; // object for logging conjectures - Heuristic *heuristic; // expansion heuristic - context &ctx; // Z3 context - solver &slvr; // Z3 solver - std::vector &nodes; // Nodes of input RPFP - std::vector &edges; // Edges of input RPFP - std::vector leaves; // leaf nodes of unwinding (unused) - Unexpanded unexpanded; // unexpanded nodes - std::list candidates; // candidates for expansion - // maps children to edges in input RPFP - hash_map > edges_by_child; - // maps each node in input RPFP to its expanded instances - hash_map > insts_of_node; - // maps each node in input RPFP to all its instances - hash_map > all_of_node; - RPFP *unwinding; // the unwinding - Covering *indset; // proposed inductive subset - Counterexample cex; // counterexample - std::list to_expand; - hash_set updated_nodes; - hash_map underapprox_map; // maps underapprox nodes to the nodes they approximate - int last_decisions; - hash_set overapproxes; - std::vector proposers; - std::string ConjectureFile; - bool stratified_inlining_done; - -#ifdef BOUNDED - struct Counter { - unsigned val; - Counter(){val = 0;} - }; - typedef std::map NodeToCounter; - hash_map back_edges; // counts of back edges -#endif - - /** Solve the problem. */ - bool Solve() override { - PreSolve(); - bool res = SolveMain(); // does the actual work - PostSolve(); - return res; - } - - void PreSolve(){ - reporter = Report ? CreateStdoutReporter(rpfp) : new Reporter(rpfp); - conj_reporter = ConjectureFile.empty() ? nullptr : CreateConjectureFileReporter(rpfp,ConjectureFile); -#ifndef LOCALIZE_CONJECTURES - heuristic = !cex.get_tree() ? new Heuristic(rpfp) : new ReplayHeuristic(rpfp,cex); -#else - heuristic = !cex.get_tree() ? (Heuristic *)(new LocalHeuristic(rpfp)) - : (Heuristic *)(new ReplayHeuristic(rpfp,cex)); -#endif - // determine if we are recursion bounded - for(unsigned i = 0; i < rpfp->nodes.size(); i++) - if(rpfp->nodes[i]->recursion_bound < UINT_MAX) - RecursionBound = 0; - cex.clear(); // in case we didn't use it for heuristic - if(unwinding) delete unwinding; - unwinding = new RPFP(rpfp->ls); - unwinding->HornClauses = rpfp->HornClauses; - indset = new Covering(this); - last_decisions = 0; - CreateEdgesByChildMap(); -#ifndef TOP_DOWN - CreateInitialUnwinding(); -#else - CreateLeaves(); - for(unsigned i = 0; i < leaves.size(); i++) - if(!SatisfyUpperBound(leaves[i])) - return false; -#endif - StratifiedLeafCount = -1; - stratified_inlining_done = false; - } - - void PostSolve(){ - // print_profile(std::cout); - delete indset; - delete heuristic; - // delete unwinding; // keep the unwinding for future mining of predicates - delete reporter; - if(conj_reporter) - delete conj_reporter; - for(unsigned i = 0; i < proposers.size(); i++) - delete proposers[i]; - } - - bool RecheckBounds(){ - for(unsigned i = 0; i < unwinding->nodes.size(); i++){ - Node *node = unwinding->nodes[i]; - node->Bound = node->map->Bound; - if(!SatisfyUpperBound(node)) - return false; - } - return true; - } - - void CreateInitialUnwinding(){ - if(!StratifiedInlining){ - CreateLeaves(); - if(FeasibleEdges)NullaryCandidates(); - else InstantiateAllEdges(); - } - else { -#ifdef NEW_STRATIFIED_INLINING - -#else - CreateLeaves(); -#endif - } - - } - - void Cancel() override { - // TODO - } - -#if 0 - virtual void Restart(RPFP *_rpfp){ - rpfp = _rpfp; - delete unwinding; - nodes = _rpfp->nodes; - edges = _rpfp->edges; - leaves.clear(); - unexpanded.clear(); // unexpanded nodes - candidates.clear(); // candidates for expansion - edges_by_child.clear(); - insts_of_node.clear(); - all_of_node.clear(); - to_expand.clear(); - } -#endif - - void LearnFrom(Solver *other_solver) override { - // get the counterexample as a guide - cex.swap(other_solver->GetCounterexample()); - - // propose conjectures based on old unwinding - Duality *old_duality = dynamic_cast(other_solver); - if(old_duality) - proposers.push_back(new HistoryProposer(old_duality,this)); - } - - /** Return a reference to the counterexample */ - Counterexample &GetCounterexample() override { - return cex; - } - - // options - bool FullExpand; // do not use partial expansion of derivation tree - bool NoConj; // do not use conjectures (no forced covering) - bool FeasibleEdges; // use only feasible edges in unwinding - bool UseUnderapprox; // use underapproximations - bool Report; // spew on stdout - bool StratifiedInlining; // Do stratified inlining as preprocessing step - int RecursionBound; // Recursion bound for bounded verification - bool BatchExpand; - bool EnableRestarts; - - bool SetBoolOption(bool &opt, const std::string &value){ - if(value == "0") { - opt = false; - return true; - } - if(value == "1") { - opt = true; - return true; - } - return false; - } - - bool SetIntOption(int &opt, const std::string &value){ - opt = atoi(value.c_str()); - return true; - } - - /** Set options (not currently used) */ - bool SetOption(const std::string &option, const std::string &value) override { - if(option == "full_expand"){ - return SetBoolOption(FullExpand,value); - } - if(option == "no_conj"){ - return SetBoolOption(NoConj,value); - } - if(option == "feasible_edges"){ - return SetBoolOption(FeasibleEdges,value); - } - if(option == "use_underapprox"){ - return SetBoolOption(UseUnderapprox,value); - } - if(option == "report"){ - return SetBoolOption(Report,value); - } - if(option == "stratified_inlining"){ - return SetBoolOption(StratifiedInlining,value); - } - if(option == "batch_expand"){ - return SetBoolOption(BatchExpand,value); - } - if(option == "recursion_bound"){ - return SetIntOption(RecursionBound,value); - } - if(option == "conjecture_file"){ - ConjectureFile = value; - } - if(option == "enable_restarts"){ - return SetBoolOption(EnableRestarts,value); - } - return false; - } - - /** Create an instance of a node in the unwinding. Set its - annotation to true, and mark it unexpanded. */ - Node* CreateNodeInstance(Node *node, int number = 0){ - RPFP::Node *inst = unwinding->CloneNode(node); - inst->Annotation.SetFull(); - if(number < 0) inst->number = number; - unexpanded.insert(inst); - all_of_node[node].push_back(inst); - return inst; - } - - /** Create an instance of an edge in the unwinding, with given - parent and children. */ - void CreateEdgeInstance(Edge *edge, Node *parent, const std::vector &children){ - RPFP::Edge *inst = unwinding->CreateEdge(parent,edge->F,children); - inst->map = edge; - } - - void MakeLeaf(Node *node, bool do_not_expand = false){ - node->Annotation.SetEmpty(); - Edge *e = unwinding->CreateLowerBoundEdge(node); -#ifdef TOP_DOWN - node->Annotation.SetFull(); // allow this node to cover others -#endif - if(StratifiedInlining) - node->Annotation.SetFull(); // allow this node to cover others - else - updated_nodes.insert(node); - e->map = nullptr; - reporter->Extend(node); -#ifdef EARLY_EXPAND - if(!do_not_expand) - TryExpandNode(node); -#endif - // e->F.SetEmpty(); - } - - void MakeOverapprox(Node *node){ - node->Annotation.SetFull(); - Edge *e = unwinding->CreateLowerBoundEdge(node); - overapproxes.insert(node); - e->map = nullptr; - } - - /** We start the unwinding with leaves that under-approximate - each relation with false. */ - void CreateLeaves(){ - unexpanded.clear(); - leaves.clear(); - for(unsigned i = 0; i < nodes.size(); i++){ - RPFP::Node *node = CreateNodeInstance(nodes[i]); - if(0 && nodes[i]->Outgoing->Children.size() == 0) - CreateEdgeInstance(nodes[i]->Outgoing,node,std::vector()); - else { - if(!StratifiedInlining) - MakeLeaf(node); - else { - MakeOverapprox(node); - LeafMap[nodes[i]] = node; - } - } - leaves.push_back(node); - } - } - - /** Create the map from children to edges in the input RPFP. This - is used to generate candidates for expansion. */ - void CreateEdgesByChildMap(){ - edges_by_child.clear(); - for(unsigned i = 0; i < edges.size(); i++){ - Edge *e = edges[i]; - std::set done; - for(unsigned j = 0; j < e->Children.size(); j++){ - Node *c = e->Children[j]; - if(done.find(c) == done.end()) // avoid duplicates - edges_by_child[c].push_back(e); - done.insert(c); - } - } - } - - void NullaryCandidates(){ - for(unsigned i = 0; i < edges.size(); i++){ - RPFP::Edge *edge = edges[i]; - if(edge->Children.size() == 0){ - Candidate cand; - cand.edge = edge; - candidates.push_back(cand); - } - } - } - - void InstantiateAllEdges(){ - hash_map leaf_map; - for(unsigned i = 0; i < leaves.size(); i++){ - leaf_map[leaves[i]->map] = leaves[i]; - insts_of_node[leaves[i]->map].push_back(leaves[i]); - } - unexpanded.clear(); - for(unsigned i = 0; i < edges.size(); i++){ - Edge *edge = edges[i]; - Candidate c; c.edge = edge; - c.Children.resize(edge->Children.size()); - for(unsigned j = 0; j < c.Children.size(); j++) - c.Children[j] = leaf_map[edge->Children[j]]; - Node *new_node; - Extend(c,new_node); -#ifdef EARLY_EXPAND - TryExpandNode(new_node); -#endif - } - for(Unexpanded::iterator it = unexpanded.begin(), en = unexpanded.end(); it != en; ++it) - indset->Add(*it); - for(unsigned i = 0; i < leaves.size(); i++){ - std::vector &foo = insts_of_node[leaves[i]->map]; - foo.erase(foo.begin()); - } - } - - bool ProducedBySI(Edge *edge, std::vector &children){ - if(LeafMap.find(edge->Parent) == LeafMap.end()) return false; - Node *other = LeafMap[edge->Parent]; - if(other->Outgoing->map != edge) return false; - std::vector &ochs = other->Outgoing->Children; - for(unsigned i = 0; i < children.size(); i++) - if(ochs[i] != children[i]) return false; - return true; - } - - /** Add a candidate for expansion, but not if Stratified inlining has already - produced it */ - - void AddCandidate(Edge *edge, std::vector &children){ - if(StratifiedInlining && ProducedBySI(edge,children)) - return; - candidates.push_back(Candidate()); - candidates.back().edge = edge; - candidates.back().Children = children; - } - - /** Generate candidates for expansion, given a vector of candidate - sets for each argument position. This recursively produces - the cross product. - */ - void GenCandidatesRec(int pos, Edge *edge, - const std::vector > &vec, - std::vector &children){ - if(pos == (int)vec.size()){ - AddCandidate(edge,children); - } - else { - for(unsigned i = 0; i < vec[pos].size(); i++){ - children[pos] = vec[pos][i]; - GenCandidatesRec(pos+1,edge,vec,children); - } - } - } - - /** Setup for above recursion. */ - void GenCandidates(int pos, Edge *edge, - const std::vector > &vec){ - std::vector children(vec.size()); - GenCandidatesRec(0,edge,vec,children); - } - - /** Expand a node. We find all the candidates for expansion using - this node and other already expanded nodes. This is a little - tricky, since a node may be used for multiple argument - positions of an edge, and we don't want to produce duplicates. - */ - -#ifndef NEW_EXPAND - void ExpandNode(Node *node){ - std::vector &nedges = edges_by_child[node->map]; - for(unsigned i = 0; i < nedges.size(); i++){ - Edge *edge = nedges[i]; - for(unsigned npos = 0; npos < edge->Children.size(); ++npos){ - if(edge->Children[npos] == node->map){ - std::vector > vec(edge->Children.size()); - vec[npos].push_back(node); - for(unsigned j = 0; j < edge->Children.size(); j++){ - if(j != npos){ - std::vector &insts = insts_of_node[edge->Children[j]]; - for(unsigned k = 0; k < insts.size(); k++) - if(indset->Candidate(insts[k])) - vec[j].push_back(insts[k]); - } - if(j < npos && edge->Children[j] == node->map) - vec[j].push_back(node); - } - GenCandidates(0,edge,vec); - } - } - } - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); - } -#else - /** If the current proposed solution is not inductive, - use the induction failure to generate candidates for extension. */ - void ExpandNode(Node *node){ - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); - timer_start("GenCandIndFailUsing"); - std::vector &nedges = edges_by_child[node->map]; - for(unsigned i = 0; i < nedges.size(); i++){ - Edge *edge = nedges[i]; - slvr.push(); - RPFP *checker = new RPFP(rpfp->ls); - Node *root = CheckerJustForEdge(edge,checker,true); - if(root){ - expr using_cond = ctx.bool_val(false); - for(unsigned npos = 0; npos < edge->Children.size(); ++npos) - if(edge->Children[npos] == node->map) - using_cond = using_cond || checker->Localize(root->Outgoing->Children[npos]->Outgoing,NodeMarker(node)); - slvr.add(using_cond); - if(checker->Check(root) != unsat){ - Candidate candidate; - ExtractCandidateFromCex(edge,checker,root,candidate); - reporter->InductionFailure(edge,candidate.Children); - candidates.push_back(candidate); - } - } - slvr.pop(1); - delete checker; - } - timer_stop("GenCandIndFailUsing"); - } -#endif - - void ExpandNodeFromOther(Node *node, Node *other){ - std::vector &in = other->Incoming; - for(unsigned i = 0; i < in.size(); i++){ - Edge *edge = in[i]; - Candidate cand; - cand.edge = edge->map; - cand.Children = edge->Children; - for(unsigned j = 0; j < cand.Children.size(); j++) - if(cand.Children[j] == other) - cand.Children[j] = node; - candidates.push_front(cand); - } - // unexpanded.erase(node); - // insts_of_node[node->map].push_back(node); - } - - /** Expand a node based on some uncovered node it dominates. - This pushes cahdidates onto the *front* of the candidate - queue, so these expansions are done depth-first. */ - bool ExpandNodeFromCoverFail(Node *node){ - if(!node->Outgoing || node->Outgoing->Children.size() == 0) - return false; - Node *other = indset->GetSimilarNode(node); - if(!other) - return false; -#ifdef UNDERAPPROX_NODES - Node *under_node = CreateUnderapproxNode(node); - underapprox_map[under_node] = node; - indset->CoverByNode(node,under_node); - ExpandNodeFromOther(under_node,other); - ExpandNode(under_node); -#else - ExpandNodeFromOther(node,other); - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); -#endif - return true; - } - - - /** Make a boolean variable to act as a "marker" for a node. */ - expr NodeMarker(Node *node){ - std::string name = std::string("@m_") + string_of_int(node->number); - return ctx.constant(name.c_str(),ctx.bool_sort()); - } - - /** Make a boolean variable to act as a "marker" for a pair of nodes. */ - expr NodeMarker(Node *node1, Node *node2){ - std::string name = std::string("@m_") + string_of_int(node1->number); - name += std::string("_") + string_of_int(node2->number); - return ctx.constant(name.c_str(),ctx.bool_sort()); - } - - /** Union the annotation of dst into src. If with_markers is - true, we conjoin the annotation formula of dst with its - marker. This allows us to discover which disjunct is - true in a satisfying assignment. */ - void UnionAnnotations(RPFP::Transformer &dst, Node *src, bool with_markers = false){ - if(!with_markers) - dst.UnionWith(src->Annotation); - else { - RPFP::Transformer t = src->Annotation; - t.Formula = t.Formula && NodeMarker(src); - dst.UnionWith(t); - } - } - - void GenNodeSolutionFromIndSet(Node *node, RPFP::Transformer &annot, bool with_markers = false){ - annot.SetEmpty(); - std::vector &insts = insts_of_node[node]; - for(unsigned j = 0; j < insts.size(); j++) - if(indset->Contains(insts[j])) - UnionAnnotations(annot,insts[j],with_markers); - annot.Simplify(); - } - - bool NodeSolutionFromIndSetFull(Node *node){ - std::vector &insts = insts_of_node[node]; - for(unsigned j = 0; j < insts.size(); j++) - if(indset->Contains(insts[j])) - if(insts[j]->Annotation.IsFull()) - return true; - return false; - } - - bool recursionBounded; - - /** See if the solution might be bounded. */ - void TestRecursionBounded(){ - recursionBounded = false; - if(RecursionBound == -1) - return; - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - std::vector &insts = insts_of_node[node]; - for(unsigned j = 0; j < insts.size(); j++) - if(indset->Contains(insts[j])) - if(NodePastRecursionBound(insts[j],true)) - recursionBounded = true; - } - } - - bool IsResultRecursionBounded() override { - return recursionBounded; - } - - /** Generate a proposed solution of the input RPFP from - the unwinding, by unioning the instances of each node. */ - void GenSolutionFromIndSet(bool with_markers = false){ - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - GenNodeSolutionFromIndSet(node,node->Annotation,with_markers); - } - } - -#ifdef BOUNDED - bool NodePastRecursionBound(Node *node, bool report = false){ - if(RecursionBound < 0) return false; - NodeToCounter &backs = back_edges[node]; - for(NodeToCounter::iterator it = backs.begin(), en = backs.end(); it != en; ++it){ - if(it->second.val > it->first->recursion_bound){ - if(report){ - std::ostringstream os; - os << "cut off " << it->first->Name.name() << " at depth " << it->second.val; - reporter->Message(os.str()); - } - return true; - } - } - return false; - } -#endif - - /** Test whether a given extension candidate actually represents - an induction failure. Right now we approximate this: if - the resulting node in the unwinding could be labeled false, - it clearly is not an induction failure. */ - - bool CandidateFeasible(const Candidate &cand){ - if(!FeasibleEdges) return true; - timer_start("CandidateFeasible"); - RPFP *checker = new RPFP(rpfp->ls); - // std::cout << "Checking feasibility of extension " << cand.edge->Parent->number << std::endl; - checker->Push(); - std::vector chs(cand.Children.size()); - Node *root = checker->CloneNode(cand.edge->Parent); -#ifdef BOUNDED - for(unsigned i = 0; i < cand.Children.size(); i++) - if(NodePastRecursionBound(cand.Children[i])){ - timer_stop("CandidateFeasible"); - return false; - } -#endif -#ifdef NEW_CAND_SEL - GenNodeSolutionFromIndSet(cand.edge->Parent,root->Bound); -#else - root->Bound.SetEmpty(); -#endif - checker->AssertNode(root); - for(unsigned i = 0; i < cand.Children.size(); i++) - chs[i] = checker->CloneNode(cand.Children[i]); - Edge *e = checker->CreateEdge(root,cand.edge->F,chs); - checker->AssertEdge(e,0,true); - // std::cout << "Checking SAT: " << e->dual << std::endl; - bool res = checker->Check(root) != unsat; - // std::cout << "Result: " << res << std::endl; - if(!res)reporter->Reject(cand.edge,cand.Children); - checker->Pop(1); - delete checker; - timer_stop("CandidateFeasible"); - return res; - } - - - hash_map TopoSort; - int TopoSortCounter; - std::vector SortedEdges; - - void DoTopoSortRec(Node *node){ - if(TopoSort.find(node) != TopoSort.end()) - return; - TopoSort[node] = INT_MAX; // just to break cycles - Edge *edge = node->Outgoing; // note, this is just *one* outgoing edge - if(edge){ - std::vector &chs = edge->Children; - for(unsigned i = 0; i < chs.size(); i++) - DoTopoSortRec(chs[i]); - } - TopoSort[node] = TopoSortCounter++; - SortedEdges.push_back(edge); - } - - void DoTopoSort(){ - TopoSort.clear(); - SortedEdges.clear(); - TopoSortCounter = 0; - for(unsigned i = 0; i < nodes.size(); i++) - DoTopoSortRec(nodes[i]); - } - - - int StratifiedLeafCount; - -#ifdef NEW_STRATIFIED_INLINING - - /** Stratified inlining builds an initial layered unwinding before - switching to the LAWI strategy. Currently the number of layers - is one. Only nodes that are the targets of back edges are - consider to be leaves. This assumes we have already computed a - topological sort. - */ - - bool DoStratifiedInlining(){ - if(stratified_inlining_done) - return true; - stratified_inlining_done = true; - DoTopoSort(); - int depth = 1; // TODO: make this an option - std::vector > unfolding_levels(depth+1); - for(int level = 1; level <= depth; level++) - for(unsigned i = 0; i < SortedEdges.size(); i++){ - Edge *edge = SortedEdges[i]; - Node *parent = edge->Parent; - std::vector &chs = edge->Children; - std::vector my_chs(chs.size()); - for(unsigned j = 0; j < chs.size(); j++){ - Node *child = chs[j]; - int ch_level = TopoSort[child] >= TopoSort[parent] ? level-1 : level; - if(unfolding_levels[ch_level].find(child) == unfolding_levels[ch_level].end()){ - if(ch_level == 0) - unfolding_levels[0][child] = CreateLeaf(child); - else - throw InternalError("in levelized unwinding"); - } - my_chs[j] = unfolding_levels[ch_level][child]; - } - Candidate cand; cand.edge = edge; cand.Children = my_chs; - Node *new_node; - bool ok = Extend(cand,new_node); - MarkExpanded(new_node); // we don't expand here -- just mark it done - if(!ok) return false; // got a counterexample - unfolding_levels[level][parent] = new_node; - } - return true; - } - - Node *CreateLeaf(Node *node){ - RPFP::Node *nchild = CreateNodeInstance(node); - MakeLeaf(nchild, /* do_not_expand = */ true); - nchild->Annotation.SetEmpty(); - return nchild; - } - - void MarkExpanded(Node *node){ - if(unexpanded.find(node) != unexpanded.end()){ - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); - } - } - -#else - - /** In stratified inlining, we build the unwinding from the bottom - down, trying to satisfy the node bounds. We do this as a pre-pass, - limiting the expansion. If we get a counterexample, we are done, - else we continue as usual expanding the unwinding upward. - */ - - bool DoStratifiedInlining(){ - timer_start("StratifiedInlining"); - DoTopoSort(); - for(unsigned i = 0; i < leaves.size(); i++){ - Node *node = leaves[i]; - bool res = SatisfyUpperBound(node); - if(!res){ - timer_stop("StratifiedInlining"); - return false; - } - } - // don't leave any dangling nodes! -#ifndef EFFORT_BOUNDED_STRAT - for(unsigned i = 0; i < leaves.size(); i++) - if(!leaves[i]->Outgoing) - MakeLeaf(leaves[i],true); -#endif - timer_stop("StratifiedInlining"); - return true; - } - -#endif - - /** Here, we do the downward expansion for stratified inlining */ - - hash_map LeafMap, StratifiedLeafMap; - - Edge *GetNodeOutgoing(Node *node, int last_decs = 0){ - if(overapproxes.find(node) == overapproxes.end()) return node->Outgoing; /* already expanded */ - overapproxes.erase(node); -#ifdef EFFORT_BOUNDED_STRAT - if(last_decs > 5000){ - // RPFP::Transformer save = node->Annotation; - node->Annotation.SetEmpty(); - Edge *e = unwinding->CreateLowerBoundEdge(node); - // node->Annotation = save; - insts_of_node[node->map].push_back(node); - // std::cout << "made leaf: " << node->number << std::endl; - return e; - } -#endif - Edge *edge = node->map->Outgoing; - std::vector &chs = edge->Children; - - // make sure we don't create a covered node in this process! - - for(unsigned i = 0; i < chs.size(); i++){ - Node *child = chs[i]; - if(TopoSort[child] < TopoSort[node->map]){ - Node *leaf = LeafMap[child]; - if(!indset->Contains(leaf)){ - node->Outgoing->F.Formula = ctx.bool_val(false); // make this a proper leaf, else bogus cex - return node->Outgoing; - } - } - } - - std::vector nchs(chs.size()); - for(unsigned i = 0; i < chs.size(); i++){ - Node *child = chs[i]; - if(TopoSort[child] < TopoSort[node->map]){ - Node *leaf = LeafMap[child]; - nchs[i] = leaf; - if(unexpanded.find(leaf) != unexpanded.end()){ - unexpanded.erase(leaf); - insts_of_node[child].push_back(leaf); - } - } - else { - if(StratifiedLeafMap.find(child) == StratifiedLeafMap.end()){ - RPFP::Node *nchild = CreateNodeInstance(child,StratifiedLeafCount--); - MakeLeaf(nchild); - nchild->Annotation.SetEmpty(); - StratifiedLeafMap[child] = nchild; - indset->SetDominated(nchild); - } - nchs[i] = StratifiedLeafMap[child]; - } - } - CreateEdgeInstance(edge,node,nchs); - reporter->Extend(node); - return node->Outgoing; - } - - void SetHeuristicOldNode(Node *node){ - LocalHeuristic *h = dynamic_cast(heuristic); - if(h) - h->SetOldNode(node); - } - - bool SolveMain(){ - timer_start("SolveMain"); - bool res = SolveMainInt(); // does the actual work - timer_stop("SolveMain"); - return res; - } - - /** This does the actual solving work. We try to generate - candidates for extension. If we succed, we extend the - unwinding. If we fail, we have a solution. */ - bool SolveMainInt(){ - if(StratifiedInlining && !DoStratifiedInlining()) - return false; -#ifdef BOUNDED - DoTopoSort(); -#endif - while(true){ - timer_start("ProduceCandidatesForExtension"); - ProduceCandidatesForExtension(); - timer_stop("ProduceCandidatesForExtension"); - if(candidates.empty()){ - GenSolutionFromIndSet(); - TestRecursionBounded(); - return true; - } - Candidate cand = candidates.front(); - candidates.pop_front(); - if(CandidateFeasible(cand)){ - Node *new_node; - if(!Extend(cand,new_node)) - return false; -#ifdef EARLY_EXPAND - TryExpandNode(new_node); -#endif - } - } - } - - // hack: put something local into the underapproximation formula - // without this, interpolants can be pretty bad - void AddThing(expr &conj){ - std::string name = "@thing"; - expr thing = ctx.constant(name.c_str(),ctx.bool_sort()); - if(conj.is_app() && conj.decl().get_decl_kind() == And){ - std::vector conjs(conj.num_args()+1); - for(unsigned i = 0; i+1 < conjs.size(); i++) - conjs[i] = conj.arg(i); - conjs[conjs.size()-1] = thing; - conj = rpfp->conjoin(conjs); - } - } - - Node *CreateUnderapproxNode(Node *node){ - // cex.get_tree()->ComputeUnderapprox(cex.get_root(),0); - RPFP::Node *under_node = CreateNodeInstance(node->map /* ,StratifiedLeafCount-- */); - under_node->Annotation.IntersectWith(cex.get_root()->Underapprox); - AddThing(under_node->Annotation.Formula); - Edge *e = unwinding->CreateLowerBoundEdge(under_node); - under_node->Annotation.SetFull(); // allow this node to cover others - back_edges[under_node] = back_edges[node]; - e->map = nullptr; - reporter->Extend(under_node); - return under_node; - } - - /** Try to prove a conjecture about a node. If successful - update the unwinding annotation appropriately. */ - bool ProveConjecture(Node *node, const RPFP::Transformer &t,Node *other = nullptr, Counterexample *_cex = nullptr){ - reporter->Conjecture(node,t); - timer_start("ProveConjecture"); - RPFP::Transformer save = node->Bound; - node->Bound.IntersectWith(t); - -#ifndef LOCALIZE_CONJECTURES - bool ok = SatisfyUpperBound(node); -#else - SetHeuristicOldNode(other); - bool ok = SatisfyUpperBound(node); - SetHeuristicOldNode(0); -#endif - - if(ok){ - timer_stop("ProveConjecture"); - return true; - } -#ifdef UNDERAPPROX_NODES - if(UseUnderapprox && last_decisions > 500){ - std::cout << "making an underapprox\n"; - ExpandNodeFromCoverFail(node); - } -#endif - if(_cex) (*_cex).swap(cex); // return the cex if asked - cex.clear(); // throw away the useless cex - node->Bound = save; // put back original bound - timer_stop("ProveConjecture"); - return false; - } - - /** If a node is part of the inductive subset, expand it. - We ask the inductive subset to exclude the node if possible. - */ - void TryExpandNode(RPFP::Node *node){ - if(indset->Close(node)) return; - if(!NoConj && indset->Conjecture(node)){ -#ifdef UNDERAPPROX_NODES - /* TODO: temporary fix. this prevents an infinite loop in case - the node is covered by multiple others. This should be - removed when covering by a set is implemented. - */ - if(indset->Contains(node)){ - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); - } -#endif - return; - } -#ifdef UNDERAPPROX_NODES - if(!indset->Contains(node)) - return; // could be covered by an underapprox node -#endif - indset->Add(node); -#if defined(CANDS_FROM_COVER_FAIL) && !defined(UNDERAPPROX_NODES) - if(ExpandNodeFromCoverFail(node)) - return; -#endif - ExpandNode(node); - } - - /** Make the conjunction of markers for all (expanded) instances of - a node in the input RPFP. */ - expr AllNodeMarkers(Node *node){ - expr res = ctx.bool_val(true); - std::vector &insts = insts_of_node[node]; - for(int k = insts.size()-1; k >= 0; k--) - res = res && NodeMarker(insts[k]); - return res; - } - - void RuleOutNodesPastBound(Node *node, RPFP::Transformer &t){ -#ifdef BOUNDED - if(RecursionBound < 0)return; - std::vector &insts = insts_of_node[node]; - for(unsigned i = 0; i < insts.size(); i++) - if(NodePastRecursionBound(insts[i])) - t.Formula = t.Formula && !NodeMarker(insts[i]); -#endif - } - - - void GenNodeSolutionWithMarkersAux(Node *node, RPFP::Transformer &annot, expr &marker_disjunction, Node *other_node){ -#ifdef BOUNDED - if(RecursionBound >= 0 && NodePastRecursionBound(node)) - return; -#endif - RPFP::Transformer temp = node->Annotation; - expr marker = (!other_node) ? NodeMarker(node) : NodeMarker(node, other_node); - temp.Formula = (!marker || temp.Formula); - annot.IntersectWith(temp); - marker_disjunction = marker_disjunction || marker; - } - - bool GenNodeSolutionWithMarkers(Node *node, RPFP::Transformer &annot, bool expanded_only = false, Node *other_node = nullptr){ - bool res = false; - annot.SetFull(); - expr marker_disjunction = ctx.bool_val(false); - std::vector &insts = expanded_only ? insts_of_node[node] : all_of_node[node]; - for(unsigned j = 0; j < insts.size(); j++){ - Node *node = insts[j]; - if(indset->Contains(insts[j])){ - GenNodeSolutionWithMarkersAux(node, annot, marker_disjunction, other_node); res = true; - } - } - annot.Formula = annot.Formula && marker_disjunction; - annot.Simplify(); - return res; - } - - /** Make a checker to determine if an edge in the input RPFP - is satisfied. */ - Node *CheckerJustForEdge(Edge *edge, RPFP *checker, bool expanded_only = false){ - Node *root = checker->CloneNode(edge->Parent); - GenNodeSolutionFromIndSet(edge->Parent, root->Bound); - if(root->Bound.IsFull()) - return nullptr; - checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - if(!GenNodeSolutionWithMarkers(oc,nc->Annotation,expanded_only)) - return nullptr; - Edge *e = checker->CreateLowerBoundEdge(nc); - checker->AssertEdge(e); - cs.push_back(nc); - } - checker->AssertEdge(checker->CreateEdge(root,edge->F,cs)); - return root; - } - -#ifndef MINIMIZE_CANDIDATES_HARDER - -#if 0 - /** Make a checker to detheermine if an edge in the input RPFP - is satisfied. */ - Node *CheckerForEdge(Edge *edge, RPFP *checker){ - Node *root = checker->CloneNode(edge->Parent); - root->Bound = edge->Parent->Annotation; - root->Bound.Formula = (!AllNodeMarkers(edge->Parent)) || root->Bound.Formula; - checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - nc->Annotation = oc->Annotation; - RuleOutNodesPastBound(oc,nc->Annotation); - Edge *e = checker->CreateLowerBoundEdge(nc); - checker->AssertEdge(e); - cs.push_back(nc); - } - checker->AssertEdge(checker->CreateEdge(root,edge->F,cs)); - return root; - } - -#else - /** Make a checker to determine if an edge in the input RPFP - is satisfied. */ - Node *CheckerForEdge(Edge *edge, RPFP *checker){ - Node *root = checker->CloneNode(edge->Parent); - GenNodeSolutionFromIndSet(edge->Parent, root->Bound); -#if 0 - if(root->Bound.IsFull()) - return = 0; -#endif - checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - GenNodeSolutionWithMarkers(oc,nc->Annotation,true); - Edge *e = checker->CreateLowerBoundEdge(nc); - checker->AssertEdge(e); - cs.push_back(nc); - } - checker->AssertEdge(checker->CreateEdge(root,edge->F,cs)); - return root; - } -#endif - - /** If an edge is not satisfied, produce an extension candidate - using instances of its children that violate the parent annotation. - We find these using the marker predicates. */ - void ExtractCandidateFromCex(Edge *edge, RPFP *checker, Node *root, Candidate &candidate){ - candidate.edge = edge; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *node = root->Outgoing->Children[j]; - Edge *lb = node->Outgoing; - std::vector &insts = insts_of_node[edge->Children[j]]; -#ifndef MINIMIZE_CANDIDATES - for(int k = insts.size()-1; k >= 0; k--) -#else - for(unsigned k = 0; k < insts.size(); k++) -#endif - { - Node *inst = insts[k]; - if(indset->Contains(inst)){ - if(checker->Empty(node) || - eq(lb ? checker->Eval(lb,NodeMarker(inst)) : checker->dualModel.eval(NodeMarker(inst,node)),ctx.bool_val(true))){ - candidate.Children.push_back(inst); - goto next_child; - } - } - } - throw InternalError("No candidate from induction failure"); - next_child:; - } - } -#else - - - /** Make a checker to determine if an edge in the input RPFP - is satisfied. */ - Node *CheckerForEdge(Edge *edge, RPFP *checker){ - Node *root = checker->CloneNode(edge->Parent); - GenNodeSolutionFromIndSet(edge->Parent, root->Bound); - if(root->Bound.IsFull()) - return = 0; - checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - GenNodeSolutionWithMarkers(oc,nc->Annotation,true); - Edge *e = checker->CreateLowerBoundEdge(nc); - checker->AssertEdge(e); - cs.push_back(nc); - } - checker->AssertEdge(checker->CreateEdge(root,edge->F,cs)); - return root; - } - - /** If an edge is not satisfied, produce an extension candidate - using instances of its children that violate the parent annotation. - We find these using the marker predicates. */ - void ExtractCandidateFromCex(Edge *edge, RPFP *checker, Node *root, Candidate &candidate){ - candidate.edge = edge; - std::vector assumps; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Edge *lb = root->Outgoing->Children[j]->Outgoing; - std::vector &insts = insts_of_node[edge->Children[j]]; - for(unsigned k = 0; k < insts.size(); k++) - { - Node *inst = insts[k]; - expr marker = NodeMarker(inst); - if(indset->Contains(inst)){ - if(checker->Empty(lb->Parent) || - eq(checker->Eval(lb,marker),ctx.bool_val(true))){ - candidate.Children.push_back(inst); - assumps.push_back(checker->Localize(lb,marker)); - goto next_child; - } - assumps.push_back(checker->Localize(lb,marker)); - if(checker->CheckUpdateModel(root,assumps) != unsat){ - candidate.Children.push_back(inst); - goto next_child; - } - assumps.pop_back(); - } - } - throw InternalError("No candidate from induction failure"); - next_child:; - } - } - -#endif - - - Node *CheckerForEdgeClone(Edge *edge, RPFP_caching *checker){ - Edge *gen_cands_edge = checker->GetEdgeClone(edge); - Node *root = gen_cands_edge->Parent; - root->Outgoing = gen_cands_edge; - GenNodeSolutionFromIndSet(edge->Parent, root->Bound); -#if 0 - if(root->Bound.IsFull()) - return = 0; -#endif - checker->AssertNode(root); - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = gen_cands_edge->Children[j]; - GenNodeSolutionWithMarkers(oc,nc->Annotation,true,nc); - } - checker->AssertEdge(gen_cands_edge,1,true); - return root; - } - - /** If the current proposed solution is not inductive, - use the induction failure to generate candidates for extension. */ - void GenCandidatesFromInductionFailure(bool full_scan = false){ - timer_start("GenCandIndFail"); - GenSolutionFromIndSet(true /* add markers */); - for(unsigned i = 0; i < edges.size(); i++){ - Edge *edge = edges[i]; - if(!full_scan && updated_nodes.find(edge->Parent) == updated_nodes.end()) - continue; -#ifndef USE_NEW_GEN_CANDS - slvr.push(); - RPFP *checker = new RPFP(rpfp->ls); - Node *root = CheckerForEdge(edge,checker); - if(checker->Check(root) != unsat){ - Candidate candidate; - ExtractCandidateFromCex(edge,checker,root,candidate); - reporter->InductionFailure(edge,candidate.Children); - candidates.push_back(candidate); - } - slvr.pop(1); - delete checker; -#else - if(!NodeSolutionFromIndSetFull(edge->Parent)){ - RPFP_caching::scoped_solver_for_edge ssfe(gen_cands_rpfp,edge,true /* models */, true /*axioms*/); - gen_cands_rpfp->Push(); - Node *root = CheckerForEdgeClone(edge,gen_cands_rpfp); - if(gen_cands_rpfp->Check(root) != unsat){ - Candidate candidate; - ExtractCandidateFromCex(edge,gen_cands_rpfp,root,candidate); - reporter->InductionFailure(edge,candidate.Children); - candidates.push_back(candidate); - } - gen_cands_rpfp->Pop(1); - } -#endif - } - updated_nodes.clear(); - timer_stop("GenCandIndFail"); -#ifdef CHECK_CANDS_FROM_IND_SET - for(std::list::iterator it = candidates.begin(), en = candidates.end(); it != en; ++it){ - if(!CandidateFeasible(*it)) - throw "produced infeasible candidate"; - } -#endif - if(!full_scan && candidates.empty()){ - reporter->Message("No candidates from updates. Trying full scan."); - GenCandidatesFromInductionFailure(true); - } - } - -#ifdef CANDS_FROM_UPDATES - /** If the given edge is not inductive in the current proposed solution, - use the induction failure to generate candidates for extension. */ - void GenCandidatesFromEdgeInductionFailure(RPFP::Edge *edge){ - GenSolutionFromIndSet(true /* add markers */); - for(unsigned i = 0; i < edges.size(); i++){ - slvr.push(); - Edge *edge = edges[i]; - RPFP *checker = new RPFP(rpfp->ls); - Node *root = CheckerForEdge(edge,checker); - if(checker->Check(root) != unsat){ - Candidate candidate; - ExtractCandidateFromCex(edge,checker,root,candidate); - reporter->InductionFailure(edge,candidate.Children); - candidates.push_back(candidate); - } - slvr.pop(1); - delete checker; - } - } -#endif - - /** Find the unexpanded nodes in the inductive subset. */ - void FindNodesToExpand(){ - for(Unexpanded::iterator it = unexpanded.begin(), en = unexpanded.end(); it != en; ++it){ - Node *node = *it; - if(indset->Candidate(node)) - to_expand.push_back(node); - } - } - - /** Try to create some extension candidates from the unexpanded - nodes. */ - void ProduceSomeCandidates(){ - while(candidates.empty() && !to_expand.empty()){ - Node *node = to_expand.front(); - to_expand.pop_front(); - TryExpandNode(node); - } - } - - std::list postponed_candidates; - - /** Try to produce some extension candidates, first from unexpanded - nides, and if this fails, from induction failure. */ - void ProduceCandidatesForExtension(){ - if(candidates.empty()) - ProduceSomeCandidates(); - while(candidates.empty()){ - FindNodesToExpand(); - if(to_expand.empty()) break; - ProduceSomeCandidates(); - } - if(candidates.empty()){ -#ifdef DEPTH_FIRST_EXPAND - if(postponed_candidates.empty()){ - GenCandidatesFromInductionFailure(); - postponed_candidates.swap(candidates); - } - if(!postponed_candidates.empty()){ - candidates.push_back(postponed_candidates.front()); - postponed_candidates.pop_front(); - } -#else - GenCandidatesFromInductionFailure(); -#endif - } - } - - bool Update(Node *node, const RPFP::Transformer &fact, bool eager=false){ - if(!node->Annotation.SubsetEq(fact)){ - reporter->Update(node,fact,eager); - if(conj_reporter) - conj_reporter->Update(node,fact,eager); - indset->Update(node,fact); - updated_nodes.insert(node->map); - node->Annotation.IntersectWith(fact); - return true; - } - return false; - } - - bool UpdateNodeToNode(Node *node, Node *top){ - return Update(node,top->Annotation); - } - - /** Update the unwinding solution, using an interpolant for the - derivation tree. */ - void UpdateWithInterpolant(Node *node, RPFP *tree, Node *top){ - if(top->Outgoing) - for(unsigned i = 0; i < top->Outgoing->Children.size(); i++) - UpdateWithInterpolant(node->Outgoing->Children[i],tree,top->Outgoing->Children[i]); - UpdateNodeToNode(node, top); - heuristic->Update(node); - } - - /** Update unwinding lower bounds, using a counterexample. */ - - void UpdateWithCounterexample(Node *node, RPFP *tree, Node *top){ - if(top->Outgoing) - for(unsigned i = 0; i < top->Outgoing->Children.size(); i++) - UpdateWithCounterexample(node->Outgoing->Children[i],tree,top->Outgoing->Children[i]); - if(!top->Underapprox.SubsetEq(node->Underapprox)){ - reporter->UpdateUnderapprox(node,top->Underapprox); - // indset->Update(node,top->Annotation); - node->Underapprox.UnionWith(top->Underapprox); - heuristic->Update(node); - } - } - - /** Try to update the unwinding to satisfy the upper bound of a - node. */ - bool SatisfyUpperBound(Node *node){ - if(node->Bound.IsFull()) return true; -#ifdef PROPAGATE_BEFORE_CHECK - Propagate(); -#endif - reporter->Bound(node); - int start_decs = rpfp->CumulativeDecisions(); - DerivationTree *dtp = new DerivationTreeSlow(this,unwinding,reporter,heuristic,FullExpand); - DerivationTree &dt = *dtp; - bool res = dt.Derive(unwinding,node,UseUnderapprox); - int end_decs = rpfp->CumulativeDecisions(); - // std::cout << "decisions: " << (end_decs - start_decs) << std::endl; - last_decisions = end_decs - start_decs; - if(res){ - cex.set(dt.tree,dt.top); // note tree is now owned by cex - if(UseUnderapprox){ - UpdateWithCounterexample(node,dt.tree,dt.top); - } - } - else { - UpdateWithInterpolant(node,dt.tree,dt.top); - delete dt.tree; - } - delete dtp; - return !res; - } - - /* For a given nod in the unwinding, get conjectures from the - proposers and check them locally. Update the node with any true - conjectures. - */ - - void DoEagerDeduction(Node *node){ - for(unsigned i = 0; i < proposers.size(); i++){ - const std::vector &conjectures = proposers[i]->Propose(node); - for(unsigned j = 0; j < conjectures.size(); j++){ - const RPFP::Transformer &conjecture = conjectures[j]; - RPFP::Transformer bound(conjecture); - std::vector conj_vec; - unwinding->CollectConjuncts(bound.Formula,conj_vec); - for(unsigned k = 0; k < conj_vec.size(); k++){ - bound.Formula = conj_vec[k]; - if(CheckEdgeCaching(node->Outgoing,bound) == unsat) - Update(node,bound, /* eager = */ true); - //else - //std::cout << "conjecture failed\n"; - } - } - } - } - - - check_result CheckEdge(RPFP *checker, Edge *edge){ - Node *root = edge->Parent; - checker->Push(); - checker->AssertNode(root); - checker->AssertEdge(edge,1,true); - check_result res = checker->Check(root); - checker->Pop(1); - return res; - } - - check_result CheckEdgeCaching(Edge *unwinding_edge, const RPFP::Transformer &bound){ - - // use a dedicated solver for this edge - // TODO: can this mess be hidden somehow? - - RPFP_caching *checker = gen_cands_rpfp; // TODO: a good choice? - Edge *edge = unwinding_edge->map; // get the edge in the original RPFP - RPFP_caching::scoped_solver_for_edge ssfe(checker,edge,true /* models */, true /*axioms*/); - Edge *checker_edge = checker->GetEdgeClone(edge); - - // copy the annotations and bound to the clone - Node *root = checker_edge->Parent; - root->Bound = bound; - for(unsigned j = 0; j < checker_edge->Children.size(); j++){ - Node *oc = unwinding_edge->Children[j]; - Node *nc = checker_edge->Children[j]; - nc->Annotation = oc->Annotation; - } - - return CheckEdge(checker,checker_edge); - } - - - /* If the counterexample derivation is partial due to - use of underapproximations, complete it. */ - - void BuildFullCex(Node *node){ - DerivationTree dt(this,unwinding,reporter,heuristic,FullExpand); - bool res = dt.Derive(unwinding,node,UseUnderapprox,true); // build full tree - if(!res) throw "Duality internal error in BuildFullCex"; - cex.set(dt.tree,dt.top); - } - - void UpdateBackEdges(Node *node){ -#ifdef BOUNDED - std::vector &chs = node->Outgoing->Children; - for(unsigned i = 0; i < chs.size(); i++){ - Node *child = chs[i]; - bool is_back = TopoSort[child->map] >= TopoSort[node->map]; - NodeToCounter &nov = back_edges[node]; - NodeToCounter chv = back_edges[child]; - if(is_back) - chv[child->map].val++; - for(NodeToCounter::iterator it = chv.begin(), en = chv.end(); it != en; ++it){ - Node *back = it->first; - Counter &c = nov[back]; - c.val = std::max(c.val,it->second.val); - } - } -#endif - } - - /** Extend the unwinding, keeping it solved. */ - bool Extend(Candidate &cand, Node *&node){ - timer_start("Extend"); - node = CreateNodeInstance(cand.edge->Parent); - CreateEdgeInstance(cand.edge,node,cand.Children); - UpdateBackEdges(node); - reporter->Extend(node); - DoEagerDeduction(node); // first be eager... - bool res = SatisfyUpperBound(node); // then be lazy - if(res) indset->CloseDescendants(node); - else { -#ifdef UNDERAPPROX_NODES - ExpandUnderapproxNodes(cex.get_tree(), cex.get_root()); -#endif - if(UseUnderapprox) BuildFullCex(node); - timer_stop("Extend"); - return res; - } - timer_stop("Extend"); - return res; - } - - void ExpandUnderapproxNodes(RPFP *tree, Node *root){ - Node *node = root->map; - if(underapprox_map.find(node) != underapprox_map.end()){ - RPFP::Transformer cnst = root->Annotation; - tree->EvalNodeAsConstraint(root, cnst); - cnst.Complement(); - Node *orig = underapprox_map[node]; - RPFP::Transformer save = orig->Bound; - orig->Bound = cnst; - DerivationTree dt(this,unwinding,reporter,heuristic,FullExpand); - bool res = dt.Derive(unwinding,orig,UseUnderapprox,true,tree); - if(!res){ - UpdateWithInterpolant(orig,dt.tree,dt.top); - throw "bogus underapprox!"; - } - ExpandUnderapproxNodes(tree,dt.top); - } - else if(root->Outgoing){ - std::vector &chs = root->Outgoing->Children; - for(unsigned i = 0; i < chs.size(); i++) - ExpandUnderapproxNodes(tree,chs[i]); - } - } - - // Propagate conjuncts up the unwinding - void Propagate(){ - reporter->Message("beginning propagation"); - timer_start("Propagate"); - std::vector sorted_nodes = unwinding->nodes; - std::sort(sorted_nodes.begin(),sorted_nodes.end(),std::less()); // sorts by sequence number - hash_map > facts; - for(unsigned i = 0; i < sorted_nodes.size(); i++){ - Node *node = sorted_nodes[i]; - std::set &node_facts = facts[node->map]; - if(!(node->Outgoing && indset->Contains(node))) - continue; - std::vector conj_vec; - unwinding->CollectConjuncts(node->Annotation.Formula,conj_vec); - std::set conjs; - std::copy(conj_vec.begin(),conj_vec.end(),std::inserter(conjs,conjs.begin())); - if(!node_facts.empty()){ - RPFP *checker = new RPFP(rpfp->ls); - slvr.push(); - Node *root = checker->CloneNode(node); - Edge *edge = node->Outgoing; - // checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - nc->Annotation = oc->Annotation; // is this needed? - cs.push_back(nc); - } - Edge *checker_edge = checker->CreateEdge(root,edge->F,cs); - checker->AssertEdge(checker_edge, 0, true, false); - std::vector propagated; - for(std::set ::iterator it = node_facts.begin(), en = node_facts.end(); it != en;){ - const expr &fact = *it; - if(conjs.find(fact) == conjs.end()){ - root->Bound.Formula = fact; - slvr.push(); - checker->AssertNode(root); - check_result res = checker->Check(root); - slvr.pop(); - if(res != unsat){ - std::set ::iterator victim = it; - ++it; - node_facts.erase(victim); // if it ain't true, nix it - continue; - } - propagated.push_back(fact); - } - ++it; - } - slvr.pop(); - for(unsigned i = 0; i < propagated.size(); i++){ - root->Annotation.Formula = propagated[i]; - UpdateNodeToNode(node,root); - } - delete checker; - } - for(std::set ::iterator it = conjs.begin(), en = conjs.end(); it != en; ++it){ - expr foo = *it; - node_facts.insert(foo); - } - } - timer_stop("Propagate"); - } - - - /** This class represents a derivation tree. */ - class DerivationTree { - public: - - virtual ~DerivationTree(){} - - DerivationTree(Duality *_duality, RPFP *rpfp, Reporter *_reporter, Heuristic *_heuristic, bool _full_expand) - : slvr(rpfp->slvr()), - ctx(rpfp->ctx) - { - duality = _duality; - reporter = _reporter; - heuristic = _heuristic; - full_expand = _full_expand; - } - - Duality *duality; - Reporter *reporter; - Heuristic *heuristic; - solver &slvr; - context &ctx; - RPFP *tree; - RPFP::Node *top; - std::list leaves; - bool full_expand; - bool underapprox; - bool constrained; - bool false_approx; - std::vector underapprox_core; - int start_decs, last_decs; - - /* We build derivation trees in one of three modes: - - 1) In normal mode, we build the full tree without considering - underapproximations. - - 2) In underapprox mode, we use underapproximations to cut off - the tree construction. THis means the resulting tree may not - be complete. - - 3) In constrained mode, we build the full tree but use - underapproximations as upper bounds. This mode is used to - complete the partial derivation constructed in underapprox - mode. - */ - - bool Derive(RPFP *rpfp, RPFP::Node *root, bool _underapprox, bool _constrained = false, RPFP *_tree = nullptr){ - underapprox = _underapprox; - constrained = _constrained; - false_approx = true; - timer_start("Derive"); -#ifndef USE_CACHING_RPFP - tree = _tree ? _tree : new RPFP(rpfp->ls); -#else - RPFP::LogicSolver *cache_ls = new RPFP::iZ3LogicSolver(ctx); - cache_ls->slvr->push(); - tree = _tree ? _tree : new RPFP_caching(cache_ls); -#endif - tree->HornClauses = rpfp->HornClauses; - tree->Push(); // so we can clear out the solver later when finished - top = CreateApproximatedInstance(root); - tree->AssertNode(top); // assert the negation of the top-level spec - timer_start("Build"); - bool res = Build(); - heuristic->Done(); - timer_stop("Build"); - timer_start("Pop"); - tree->Pop(1); - timer_stop("Pop"); -#ifdef USE_CACHING_RPFP - cache_ls->slvr->pop(1); - delete cache_ls; - tree->ls = rpfp->ls; -#endif - timer_stop("Derive"); - return res; - } - -#define WITH_CHILDREN - - void InitializeApproximatedInstance(RPFP::Node *to){ - to->Annotation = to->map->Annotation; -#ifndef WITH_CHILDREN - tree->CreateLowerBoundEdge(to); -#endif - leaves.push_back(to); - } - - Node *CreateApproximatedInstance(RPFP::Node *from){ - Node *to = tree->CloneNode(from); - InitializeApproximatedInstance(to); - return to; - } - - bool CheckWithUnderapprox(){ - timer_start("CheckWithUnderapprox"); - std::vector leaves_vector(leaves.size()); - std::copy(leaves.begin(),leaves.end(),leaves_vector.begin()); - check_result res = tree->Check(top,leaves_vector); - timer_stop("CheckWithUnderapprox"); - return res != unsat; - } - - virtual bool Build(){ -#ifdef EFFORT_BOUNDED_STRAT - start_decs = tree->CumulativeDecisions(); -#endif - while(ExpandSomeNodes(true)); // do high-priority expansions - while (true) - { -#ifndef WITH_CHILDREN - timer_start("asserting leaves"); - timer_start("pushing"); - tree->Push(); - timer_stop("pushing"); - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it) - tree->AssertEdge((*it)->Outgoing,1); // assert the overapproximation, and keep it past pop - timer_stop("asserting leaves"); - lbool res = tree->Solve(top, 2); // incremental solve, keep interpolants for two pops - timer_start("popping leaves"); - tree->Pop(1); - timer_stop("popping leaves"); -#else - lbool res; - if((underapprox || false_approx) && top->Outgoing && CheckWithUnderapprox()){ - if(constrained) goto expand_some_nodes; // in constrained mode, keep expanding - goto we_are_sat; // else if underapprox is sat, we stop - } - // tree->Check(top); - res = tree->Solve(top, 1); // incremental solve, keep interpolants for one pop -#endif - if (res == l_false) - return false; - - expand_some_nodes: - if(ExpandSomeNodes()) - continue; - - we_are_sat: - if(underapprox && !constrained){ - timer_start("ComputeUnderapprox"); - tree->ComputeUnderapprox(top,1); - timer_stop("ComputeUnderapprox"); - } - else { -#ifdef UNDERAPPROX_NODES -#ifndef SKIP_UNDERAPPROX_NODES - timer_start("ComputeUnderapprox"); - tree->ComputeUnderapprox(top,1); - timer_stop("ComputeUnderapprox"); -#endif -#endif - } - return true; - } - } - - virtual void ExpandNode(RPFP::Node *p){ - // tree->RemoveEdge(p->Outgoing); - Edge *ne = p->Outgoing; - if(ne) { - // reporter->Message("Recycling edge..."); - std::vector &cs = ne->Children; - for(unsigned i = 0; i < cs.size(); i++) - InitializeApproximatedInstance(cs[i]); - // ne->dual = expr(); - } - else { - Edge *edge = duality->GetNodeOutgoing(p->map,last_decs); - std::vector &cs = edge->Children; - std::vector children(cs.size()); - for(unsigned i = 0; i < cs.size(); i++) - children[i] = CreateApproximatedInstance(cs[i]); - ne = tree->CreateEdge(p, p->map->Outgoing->F, children); - ne->map = p->map->Outgoing->map; - } -#ifndef WITH_CHILDREN - tree->AssertEdge(ne); // assert the edge in the solver -#else - tree->AssertEdge(ne,0,!full_expand,(underapprox || false_approx)); // assert the edge in the solver -#endif - reporter->Expand(ne); - } - -#define UNDERAPPROXCORE -#ifndef UNDERAPPROXCORE - void ExpansionChoices(std::set &best){ - std::set choices; - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it) - if (!tree->Empty(*it)) // if used in the counter-model - choices.insert(*it); - heuristic->ChooseExpand(choices, best); - } -#else -#if 0 - - void ExpansionChoices(std::set &best){ - std::vector unused_set, used_set; - std::set choices; - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it){ - Node *n = *it; - if (!tree->Empty(n)) - used_set.push_back(n); - else - unused_set.push_back(n); - } - if(tree->Check(top,unused_set) == unsat) - throw "error in ExpansionChoices"; - for(unsigned i = 0; i < used_set.size(); i++){ - Node *n = used_set[i]; - unused_set.push_back(n); - if(!top->Outgoing || tree->Check(top,unused_set) == unsat){ - unused_set.pop_back(); - choices.insert(n); - } - else - std::cout << "Using underapprox of " << n->number << std::endl; - } - heuristic->ChooseExpand(choices, best); - } -#else - void ExpansionChoicesFull(std::set &best, bool high_priority, bool best_only = false){ - std::set choices; - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it) - if (high_priority || !tree->Empty(*it)) // if used in the counter-model - choices.insert(*it); - heuristic->ChooseExpand(choices, best, high_priority, best_only); - } - - void ExpansionChoicesRec(std::vector &unused_set, std::vector &used_set, - std::set &choices, int from, int to){ - if(from == to) return; - int orig_unused = unused_set.size(); - unused_set.resize(orig_unused + (to - from)); - std::copy(used_set.begin()+from,used_set.begin()+to,unused_set.begin()+orig_unused); - if(!top->Outgoing || tree->Check(top,unused_set) == unsat){ - unused_set.resize(orig_unused); - if(to - from == 1){ -#if 1 - std::cout << "Not using underapprox of " << used_set[from] ->number << std::endl; -#endif - choices.insert(used_set[from]); - } - else { - int mid = from + (to - from)/2; - ExpansionChoicesRec(unused_set, used_set, choices, from, mid); - ExpansionChoicesRec(unused_set, used_set, choices, mid, to); - } - } - else { -#if 1 - std::cout << "Using underapprox of "; - for(int i = from; i < to; i++){ - std::cout << used_set[i]->number << " "; - if(used_set[i]->map->Underapprox.IsEmpty()) - std::cout << "(false!) "; - } - std::cout << std::endl; -#endif - } - } - - std::set old_choices; - - void ExpansionChoices(std::set &best, bool high_priority, bool best_only = false){ - if(!underapprox || constrained || high_priority){ - ExpansionChoicesFull(best, high_priority,best_only); - return; - } - std::vector unused_set, used_set; - std::set choices; - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it){ - Node *n = *it; - if (!tree->Empty(n)){ - if(old_choices.find(n) != old_choices.end() || n->map->Underapprox.IsEmpty()) - choices.insert(n); - else - used_set.push_back(n); - } - else - unused_set.push_back(n); - } - if(tree->Check(top,unused_set) == unsat) - throw "error in ExpansionChoices"; - ExpansionChoicesRec(unused_set, used_set, choices, 0, used_set.size()); - old_choices = choices; - heuristic->ChooseExpand(choices, best, high_priority); - } -#endif -#endif - - bool ExpandSomeNodes(bool high_priority = false, int max = INT_MAX){ -#ifdef EFFORT_BOUNDED_STRAT - last_decs = tree->CumulativeDecisions() - start_decs; -#endif - timer_start("ExpandSomeNodes"); - timer_start("ExpansionChoices"); - std::set choices; - ExpansionChoices(choices,high_priority,max != INT_MAX); - timer_stop("ExpansionChoices"); - std::list leaves_copy = leaves; // copy so can modify orig - leaves.clear(); - int count = 0; - for(std::list::iterator it = leaves_copy.begin(), en = leaves_copy.end(); it != en; ++it){ - if(choices.find(*it) != choices.end() && count < max){ - count++; - ExpandNode(*it); - } - else leaves.push_back(*it); - } - timer_stop("ExpandSomeNodes"); - return !choices.empty(); - } - - void RemoveExpansion(RPFP::Node *p){ - Edge *edge = p->Outgoing; - Node *parent = edge->Parent; -#ifndef KEEP_EXPANSIONS - std::vector cs = edge->Children; - tree->DeleteEdge(edge); - for(unsigned i = 0; i < cs.size(); i++) - tree->DeleteNode(cs[i]); -#endif - leaves.push_back(parent); - } - - // remove all the descendants of tree root (but not root itself) - void RemoveTree(RPFP *tree, RPFP::Node *root){ - Edge *edge = root->Outgoing; - std::vector cs = edge->Children; - tree->DeleteEdge(edge); - for(unsigned i = 0; i < cs.size(); i++){ - RemoveTree(tree,cs[i]); - tree->DeleteNode(cs[i]); - } - } - }; - - class DerivationTreeSlow : public DerivationTree { - public: - - struct stack_entry { - unsigned level; // SMT solver stack level - std::vector expansions; - }; - - std::vector stack; - - hash_map updates; - - int restart_interval; - - DerivationTreeSlow(Duality *_duality, RPFP *rpfp, Reporter *_reporter, Heuristic *_heuristic, bool _full_expand) - : DerivationTree(_duality, rpfp, _reporter, _heuristic, _full_expand) { - stack.push_back(stack_entry()); - } - - struct DoRestart {}; - - bool Build() override { - restart_interval = 3; - while (true) { - try { - return BuildMain(); - } - catch (const DoRestart &) { - // clear the statck and try again - updated_nodes.clear(); - while(stack.size() > 1) - PopLevel(); - reporter->Message("restarted"); - restart_interval += 1; - } - } - } - - - // When we check, try to use the same children that were used in the - // previous counterexample. - check_result Check(){ -#if 0 - std::vector posnodes, negnodes; - std::vector &expansions = stack.back().expansions; - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - std::vector &chs = node->Outgoing->Children; - for(unsigned j = 0; j < chs.size(); j++){ - Node *ch = chs[j]; - int use = heuristic->UseNode(ch); - if(use == 1) - posnodes.push_back(ch); - else if (use == -1) - negnodes.push_back(ch); - } - } - if(!(posnodes.empty() && negnodes.empty())){ - check_result res = tree->CheckWithConstrainedNodes(posnodes,negnodes); - if(res != unsat){ - reporter->Message("matched previous counterexample"); - return res; - } - } -#endif - return tree->Check(top); - } - - bool BuildMain(){ - - stack.back().level = tree->slvr().get_scope_level(); - bool was_sat = true; - int update_failures = 0; - int total_updates = 0; - - while (true) - { - lbool res; - - unsigned slvr_level = tree->slvr().get_scope_level(); - if(slvr_level != stack.back().level) - throw "stacks out of sync!"; - reporter->Depth(stack.size()); - - // res = tree->Solve(top, 1); // incremental solve, keep interpolants for one pop - check_result foo = Check(); - res = foo == unsat ? l_false : l_true; - - if (res == l_false) { - if (stack.empty()) // should never happen - return false; - - { - std::vector &expansions = stack.back().expansions; - int update_count = 0; - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - try { - tree->SolveSingleNode(top,node); -#ifdef NO_GENERALIZE - node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); -#else - if(expansions.size() == 1 && NodeTooComplicated(node)) - SimplifyNode(node); - else - node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); - Generalize(node); -#endif - } - catch(const RPFP::Bad &){ - // bad interpolants can get us here - throw DoRestart(); - } - catch(const RPFP::ReallyBad &){ - // this could be caused by incompleteness - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - node->map->Annotation.SetFull(); - std::vector &chs = node->map->Outgoing->Children; - for(unsigned j = 0; j < chs.size(); j++) - chs[j]->Annotation.SetFull(); - reporter->Message("incompleteness: cleared annotation and child annotations"); - } - throw DoRestart(); - } - catch(char const *msg){ - // bad interpolants can get us here - reporter->Message(std::string("interpolation failure:") + msg); - throw DoRestart(); - } - catch(const RPFP::greedy_reduce_failed &){ - // if we couldn't reduce, just continue (maybe should restart?) - reporter->Message("interpolant verification failed"); - } - if(RecordUpdate(node)){ - update_count++; - total_updates++; - } - else - heuristic->Update(node->map); // make it less likely to expand this node in future - } -#if 1 - if(duality->EnableRestarts) - if(total_updates >= restart_interval) - throw DoRestart(); -#endif - if(update_count == 0){ - if(was_sat){ - update_failures++; - if(update_failures > 10){ - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - node->map->Annotation.SetFull(); - reporter->Message("incompleteness: cleared annotation"); - } - throw DoRestart(); - } - } - reporter->Message("backtracked without learning"); - } - else update_failures = 0; - } - tree->ComputeProofCore(); // need to compute the proof core before popping solver - bool propagated = false; - while(1) { - bool prev_level_used = LevelUsedInProof(stack.size()-2); // need to compute this before pop - PopLevel(); - if(stack.size() == 1)break; - if(prev_level_used){ - Node *node = stack.back().expansions[0]; -#ifndef NO_PROPAGATE - if(!Propagate(node)) break; -#endif - if(!RecordUpdate(node)) break; // shouldn't happen! - RemoveUpdateNodesAtCurrentLevel(); // this level is about to be deleted -- remove its children from update list - propagated = true; - continue; - } - if(propagated) break; // propagation invalidates the proof core, so disable non-chron backtrack - RemoveUpdateNodesAtCurrentLevel(); // this level is about to be deleted -- remove its children from update list - std::vector &unused_ex = stack.back().expansions; - for(unsigned i = 0; i < unused_ex.size(); i++) - heuristic->Update(unused_ex[i]->map); // make it less likely to expand this node in future - } - HandleUpdatedNodes(); - if(stack.size() == 1){ - if(top->Outgoing) - tree->DeleteEdge(top->Outgoing); // in case we kept the tree - return false; - } - was_sat = false; - } - else { - was_sat = true; - tree->Push(); - std::vector &expansions = stack.back().expansions; -#ifndef NO_DECISIONS -#if 0 - if(expansions.size() > 0) - tree->GreedyReduceNodes(expansions[0]->Outgoing->Children); // try to reduce number of children -#endif - for(unsigned i = 0; i < expansions.size(); i++){ - tree->FixCurrentState(expansions[i]->Outgoing); - } -#endif -#if 0 - if(tree->slvr().check() == unsat) - throw "help!"; -#endif - int expand_max = 1; - if(0&&duality->BatchExpand){ - int thing = stack.size() / 10; // * 0.1; - expand_max = std::max(1,thing); - if(expand_max > 1) - std::cout << "foo!\n"; - } - - if(ExpandSomeNodes(false,expand_max)) - continue; - tree->Pop(1); - node_order.clear(); - while(stack.size() > 1){ - tree->Pop(1); - std::vector &expansions = stack.back().expansions; - for(unsigned i = 0; i < expansions.size(); i++) - node_order.push_back(expansions[i]); - stack.pop_back(); - } -#if 0 - Reduce(); -#endif - return true; - } - } - } - - std::vector node_order; - - void Reduce(){ - tree->Push(); - // tree->AssertNode(top); // assert the negation of the top-level spec - for(int i = node_order.size()-1; i >= 0; --i){ - Edge *edge = node_order[i]->Outgoing; - if(edge){ - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *ch = edge->Children[j]; - if(!ch->Outgoing) - ch->Annotation.SetEmpty(); - } - tree->AssertEdge(edge,0,true); - } - } - tree->GreedyReduceNodes(node_order); // try to reduce the counterexample size - tree->Pop(1); - } - - void PopLevel(){ - std::vector &expansions = stack.back().expansions; - tree->Pop(1); - hash_set leaves_to_remove; - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - // if(node != top) - //tree->ConstrainParent(node->Incoming[0],node); - std::vector &cs = node->Outgoing->Children; - for(unsigned i = 0; i < cs.size(); i++){ - leaves_to_remove.insert(cs[i]); - UnmapNode(cs[i]); - if(std::find(updated_nodes.begin(),updated_nodes.end(),cs[i]) != updated_nodes.end()) - throw "help!"; - } - } - RemoveLeaves(leaves_to_remove); // have to do this before actually deleting the children - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - RemoveExpansion(node); - } - stack.pop_back(); - } - - bool NodeTooComplicated(Node *node){ - int ops = tree->CountOperators(node->Annotation.Formula); - if(ops > 10) return true; - node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); - return tree->CountOperators(node->Annotation.Formula) > 3; - } - - void SimplifyNode(Node *node){ - // have to destroy the old proof to get a new interpolant - timer_start("SimplifyNode"); - tree->PopPush(); - try { - tree->InterpolateByCases(top,node); - } - catch(const RPFP::Bad&){ - timer_stop("SimplifyNode"); - throw RPFP::Bad(); - } - timer_stop("SimplifyNode"); - } - - bool LevelUsedInProof(unsigned level){ - std::vector &expansions = stack[level].expansions; - for(unsigned i = 0; i < expansions.size(); i++) - if(tree->EdgeUsedInProof(expansions[i]->Outgoing)) - return true; - return false; - } - - void RemoveUpdateNodesAtCurrentLevel() { - for(std::list::iterator it = updated_nodes.begin(), en = updated_nodes.end(); it != en;){ - Node *node = *it; - if(AtCurrentStackLevel(node->Incoming[0]->Parent)){ - std::list::iterator victim = it; - ++it; - updated_nodes.erase(victim); - } - else - ++it; - } - } - - void RemoveLeaves(hash_set &leaves_to_remove){ - std::list leaves_copy; - leaves_copy.swap(leaves); - for(std::list::iterator it = leaves_copy.begin(), en = leaves_copy.end(); it != en; ++it){ - if(leaves_to_remove.find(*it) == leaves_to_remove.end()) - leaves.push_back(*it); - } - } - - hash_map > node_map; - std::list updated_nodes; - - void ExpandNode(RPFP::Node *p) override { - stack.push_back(stack_entry()); - stack.back().level = tree->slvr().get_scope_level(); - stack.back().expansions.push_back(p); - DerivationTree::ExpandNode(p); - std::vector &new_nodes = p->Outgoing->Children; - for(unsigned i = 0; i < new_nodes.size(); i++){ - Node *n = new_nodes[i]; - node_map[n->map].push_back(n); - } - } - - bool RecordUpdate(Node *node){ - bool res = duality->UpdateNodeToNode(node->map,node); - if(res){ - std::vector to_update = node_map[node->map]; - for(unsigned i = 0; i < to_update.size(); i++){ - Node *node2 = to_update[i]; - // maintain invariant that no nodes on updated list are created at current stack level - if(node2 == node || !(node->Incoming.size() > 0 && AtCurrentStackLevel(node2->Incoming[0]->Parent))){ - updated_nodes.push_back(node2); - if(node2 != node) - node2->Annotation = node->Annotation; - } - } - } - return res; - } - - void HandleUpdatedNodes(){ - for(std::list::iterator it = updated_nodes.begin(), en = updated_nodes.end(); it != en;){ - Node *node = *it; - node->Annotation = node->map->Annotation; - if(node->Incoming.size() > 0) - tree->ConstrainParent(node->Incoming[0],node); - if(AtCurrentStackLevel(node->Incoming[0]->Parent)){ - std::list::iterator victim = it; - ++it; - updated_nodes.erase(victim); - } - else - ++it; - } - } - - bool AtCurrentStackLevel(Node *node){ - std::vector vec = stack.back().expansions; - for(unsigned i = 0; i < vec.size(); i++) - if(vec[i] == node) - return true; - return false; - } - - void UnmapNode(Node *node){ - std::vector &vec = node_map[node->map]; - for(unsigned i = 0; i < vec.size(); i++){ - if(vec[i] == node){ - std::swap(vec[i],vec.back()); - vec.pop_back(); - return; - } - } - throw "can't unmap node"; - } - - void Generalize(Node *node){ -#ifndef USE_RPFP_CLONE - tree->Generalize(top,node); -#else - RPFP_caching *clone_rpfp = duality->clone_rpfp; - if(!node->Outgoing->map) return; - Edge *clone_edge = clone_rpfp->GetEdgeClone(node->Outgoing->map); - Node *clone_node = clone_edge->Parent; - clone_node->Annotation = node->Annotation; - for(unsigned i = 0; i < clone_edge->Children.size(); i++) - clone_edge->Children[i]->Annotation = node->map->Outgoing->Children[i]->Annotation; - clone_rpfp->GeneralizeCache(clone_edge); - node->Annotation = clone_node->Annotation; -#endif - } - - bool Propagate(Node *node){ -#ifdef USE_RPFP_CLONE - RPFP_caching *clone_rpfp = duality->clone_rpfp; - Edge *clone_edge = clone_rpfp->GetEdgeClone(node->Outgoing->map); - Node *clone_node = clone_edge->Parent; - clone_node->Annotation = node->map->Annotation; - for(unsigned i = 0; i < clone_edge->Children.size(); i++) - clone_edge->Children[i]->Annotation = node->map->Outgoing->Children[i]->Annotation; - bool res = clone_rpfp->PropagateCache(clone_edge); - if(res) - node->Annotation = clone_node->Annotation; - return res; -#else - return false; -#endif - } - - }; - - - class Covering { - - struct cover_info { - Node *covered_by; - std::list covers; - bool dominated; - std::set dominates; - cover_info(){ - covered_by = nullptr; - dominated = false; - } - }; - - typedef hash_map cover_map; - cover_map cm; - Duality *parent; - bool some_updates; - -#define NO_CONJ_ON_SIMPLE_LOOPS -#ifdef NO_CONJ_ON_SIMPLE_LOOPS - hash_set simple_loops; -#endif - - Node *&covered_by(Node *node){ - return cm[node].covered_by; - } - - std::list &covers(Node *node){ - return cm[node].covers; - } - - std::vector &insts_of_node(Node *node){ - return parent->insts_of_node[node]; - } - - Reporter *reporter(){ - return parent->reporter; - } - - std::set &dominates(Node *x){ - return cm[x].dominates; - } - - bool dominates(Node *x, Node *y){ - std::set &d = cm[x].dominates; - return d.find(y) != d.end(); - } - - bool &dominated(Node *x){ - return cm[x].dominated; - } - - public: - - Covering(Duality *_parent){ - parent = _parent; - some_updates = false; - -#ifdef NO_CONJ_ON_SIMPLE_LOOPS - hash_map > outgoing; - for(unsigned i = 0; i < parent->rpfp->edges.size(); i++) - outgoing[parent->rpfp->edges[i]->Parent].push_back(parent->rpfp->edges[i]); - for(unsigned i = 0; i < parent->rpfp->nodes.size(); i++){ - Node * node = parent->rpfp->nodes[i]; - std::vector &outs = outgoing[node]; - if(outs.size() == 2){ - for(int j = 0; j < 2; j++){ - Edge *loop_edge = outs[j]; - if(loop_edge->Children.size() == 1 && loop_edge->Children[0] == loop_edge->Parent) - simple_loops.insert(node); - } - } - } -#endif - - } - - bool IsCoveredRec(hash_set &memo, Node *node){ - if(memo.find(node) != memo.end()) - return false; - memo.insert(node); - if(covered_by(node)) return true; - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++) - if(IsCoveredRec(memo,node->Outgoing->Children[i])) - return true; - return false; - } - - bool IsCovered(Node *node){ - hash_set memo; - return IsCoveredRec(memo,node); - } - -#ifndef UNDERAPPROX_NODES - void RemoveCoveringsBy(Node *node){ - std::list &cs = covers(node); - for(std::list::iterator it = cs.begin(), en = cs.end(); it != en; it++){ - covered_by(*it) = 0; - reporter()->RemoveCover(*it,node); - } - cs.clear(); - } -#else - void RemoveCoveringsBy(Node *node){ - std::vector &cs = parent->all_of_node[node->map]; - for(std::vector::iterator it = cs.begin(), en = cs.end(); it != en; it++){ - Node *other = *it; - if(covered_by(other) && CoverOrder(node,other)){ - covered_by(other) = nullptr; - reporter()->RemoveCover(*it,node); - } - } - } -#endif - - void RemoveAscendantCoveringsRec(hash_set &memo, Node *node){ - if(memo.find(node) != memo.end()) - return; - memo.insert(node); - RemoveCoveringsBy(node); - for(std::vector::iterator it = node->Incoming.begin(), en = node->Incoming.end(); it != en; ++it) - RemoveAscendantCoveringsRec(memo,(*it)->Parent); - } - - void RemoveAscendantCoverings(Node *node){ - hash_set memo; - RemoveAscendantCoveringsRec(memo,node); - } - - bool CoverOrder(Node *covering, Node *covered){ -#ifdef UNDERAPPROX_NODES - if(parent->underapprox_map.find(covered) != parent->underapprox_map.end()) - return false; - if(parent->underapprox_map.find(covering) != parent->underapprox_map.end()) - return covering->number < covered->number || parent->underapprox_map[covering] == covered; -#endif - return covering->number < covered->number; - } - - bool CheckCover(Node *covered, Node *covering){ - return - CoverOrder(covering,covered) - && covered->Annotation.SubsetEq(covering->Annotation) - && !IsCovered(covering); - } - - bool CoverByNode(Node *covered, Node *covering){ - if(CheckCover(covered,covering)){ - covered_by(covered) = covering; - covers(covering).push_back(covered); - std::vector others; others.push_back(covering); - reporter()->AddCover(covered,others); - RemoveAscendantCoverings(covered); - return true; - } - else - return false; - } - -#ifdef UNDERAPPROX_NODES - bool CoverByAll(Node *covered){ - RPFP::Transformer all = covered->Annotation; - all.SetEmpty(); - std::vector &insts = parent->insts_of_node[covered->map]; - std::vector others; - for(unsigned i = 0; i < insts.size(); i++){ - Node *covering = insts[i]; - if(CoverOrder(covering,covered) && !IsCovered(covering)){ - others.push_back(covering); - all.UnionWith(covering->Annotation); - } - } - if(others.size() && covered->Annotation.SubsetEq(all)){ - covered_by(covered) = covered; // anything non-null will do - reporter()->AddCover(covered,others); - RemoveAscendantCoverings(covered); - return true; - } - else - return false; - } -#endif - - bool Close(Node *node){ - if(covered_by(node)) - return true; -#ifndef UNDERAPPROX_NODES - std::vector &insts = insts_of_node(node->map); - for(unsigned i = 0; i < insts.size(); i++) - if(CoverByNode(node,insts[i])) - return true; -#else - if(CoverByAll(node)) - return true; -#endif - return false; - } - - bool CloseDescendantsRec(hash_set &memo, Node *node){ - if(memo.find(node) != memo.end()) - return false; - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++) - if(CloseDescendantsRec(memo,node->Outgoing->Children[i])) - return true; - if(Close(node)) - return true; - memo.insert(node); - return false; - } - - bool CloseDescendants(Node *node){ - timer_start("CloseDescendants"); - hash_set memo; - bool res = CloseDescendantsRec(memo,node); - timer_stop("CloseDescendants"); - return res; - } - - bool Contains(Node *node){ - timer_start("Contains"); - bool res = !IsCovered(node); - timer_stop("Contains"); - return res; - } - - bool Candidate(Node *node){ - timer_start("Candidate"); - bool res = !IsCovered(node) && !dominated(node); - timer_stop("Candidate"); - return res; - } - - void SetDominated(Node *node){ - dominated(node) = true; - } - - bool CouldCover(Node *covered, Node *covering){ -#ifdef NO_CONJ_ON_SIMPLE_LOOPS - // Forsimple loops, we rely on propagation, not covering - if(simple_loops.find(covered->map) != simple_loops.end()) - return false; -#endif -#ifdef UNDERAPPROX_NODES - // if(parent->underapprox_map.find(covering) != parent->underapprox_map.end()) - // return parent->underapprox_map[covering] == covered; -#endif - if(CoverOrder(covering,covered) - && !IsCovered(covering)){ - RPFP::Transformer f(covering->Annotation); f.SetEmpty(); -#if defined(TOP_DOWN) || defined(EFFORT_BOUNDED_STRAT) - if(parent->StratifiedInlining) - return true; -#endif - return !covering->Annotation.SubsetEq(f); - } - return false; - } - - bool ContainsCex(Node *node, Counterexample &cex){ - expr val = cex.get_tree()->Eval(cex.get_root()->Outgoing,node->Annotation.Formula); - return eq(val,parent->ctx.bool_val(true)); - } - - /** We conjecture that the annotations of similar nodes may be - true of this one. We start with later nodes, on the - principle that their annotations are likely weaker. We save - a counterexample -- if annotations of other nodes are true - in this counterexample, we don't need to check them. - */ - -#ifndef UNDERAPPROX_NODES - bool Conjecture(Node *node){ - std::vector &insts = insts_of_node(node->map); - Counterexample cex; - for(int i = insts.size() - 1; i >= 0; i--){ - Node *other = insts[i]; - if(CouldCover(node,other)){ - reporter()->Forcing(node,other); - if(cex.get_tree() && !ContainsCex(other,cex)) - continue; - cex.clear(); - if(parent->ProveConjecture(node,other->Annotation,other,&cex)) - if(CloseDescendants(node)) - return true; - } - } - cex.clear(); - return false; - } -#else - bool Conjecture(Node *node){ - std::vector &insts = insts_of_node(node->map); - Counterexample cex; - RPFP::Transformer Bound = node->Annotation; - Bound.SetEmpty(); - bool some_other = false; - for(int i = insts.size() - 1; i >= 0; i--){ - Node *other = insts[i]; - if(CouldCover(node,other)){ - reporter()->Forcing(node,other); - Bound.UnionWith(other->Annotation); - some_other = true; - } - } - if(some_other && parent->ProveConjecture(node,Bound)){ - CloseDescendants(node); - return true; - } - return false; - } -#endif - - void Update(Node *node, const RPFP::Transformer &update){ - RemoveCoveringsBy(node); - some_updates = true; - } - -#ifndef UNDERAPPROX_NODES - Node *GetSimilarNode(Node *node){ - if(!some_updates) - return 0; - std::vector &insts = insts_of_node(node->map); - for(int i = insts.size()-1; i >= 0; i--){ - Node *other = insts[i]; - if(dominates(node,other)) - if(CoverOrder(other,node) - && !IsCovered(other)) - return other; - } - return 0; - } -#else - Node *GetSimilarNode(Node *node){ - if(!some_updates) - return nullptr; - std::vector &insts = insts_of_node(node->map); - for(int i = insts.size() - 1; i >= 0; i--){ - Node *other = insts[i]; - if(CoverOrder(other,node) - && !IsCovered(other)) - return other; - } - return nullptr; - } -#endif - - bool Dominates(Node * node, Node *other){ - if(node == other) return false; - if(other->Outgoing->map == nullptr) return true; - if(node->Outgoing->map == other->Outgoing->map){ - assert(node->Outgoing->Children.size() == other->Outgoing->Children.size()); - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++){ - Node *nc = node->Outgoing->Children[i]; - Node *oc = other->Outgoing->Children[i]; - if(!(nc == oc || oc->Outgoing->map ==nullptr || dominates(nc,oc))) - return false; - } - return true; - } - return false; - } - - void Add(Node *node){ - std::vector &insts = insts_of_node(node->map); - for(unsigned i = 0; i < insts.size(); i++){ - Node *other = insts[i]; - if(Dominates(node,other)){ - cm[node].dominates.insert(other); - cm[other].dominated = true; - reporter()->Dominates(node, other); - } - } - } - - }; - - /* This expansion heuristic makes use of a previuosly obtained - counterexample as a guide. This is for use in abstraction - refinement schemes.*/ - - class ReplayHeuristic : public Heuristic { - - Counterexample old_cex; - public: - ReplayHeuristic(RPFP *_rpfp, Counterexample &_old_cex) - : Heuristic(_rpfp) - { - old_cex.swap(_old_cex); // take ownership from caller - } - - ~ReplayHeuristic() override { - } - - // Maps nodes of derivation tree into old cex - hash_map cex_map; - - void Done() override { - cex_map.clear(); - old_cex.clear(); - } - - void ShowNodeAndChildren(Node *n){ - std::cout << n->Name.name() << ": "; - std::vector &chs = n->Outgoing->Children; - for(unsigned i = 0; i < chs.size(); i++) - std::cout << chs[i]->Name.name() << " " ; - std::cout << std::endl; - } - - // HACK: When matching relation names, we drop suffixes used to - // make the names unique between runs. For compatibility - // with boggie, we drop suffixes beginning with @@ - std::string BaseName(const std::string &name){ - int pos = name.find("@@"); - if(pos >= 1) - return name.substr(0,pos); - return name; - } - - Node *MatchNode(Node *node){ - if(cex_map.find(node) == cex_map.end()){ // try to match an unmatched node - Node *parent = node->Incoming[0]->Parent; // assumes we are a tree! - if(cex_map.find(parent) == cex_map.end()) - throw "catastrophe in ReplayHeuristic::ChooseExpand"; - Node *old_parent = cex_map[parent]; - std::vector &chs = parent->Outgoing->Children; - if(old_parent && old_parent->Outgoing){ - std::vector &old_chs = old_parent->Outgoing->Children; - for(unsigned i = 0, j=0; i < chs.size(); i++){ - if(j < old_chs.size() && BaseName(chs[i]->Name.name().str()) == BaseName(old_chs[j]->Name.name().str())) - cex_map[chs[i]] = old_chs[j++]; - else { - std::cerr << "WARNING: duality: unmatched child: " << chs[i]->Name.name() << std::endl; - cex_map[chs[i]] = 0; - } - } - goto matching_done; - } - for(unsigned i = 0; i < chs.size(); i++) - cex_map[chs[i]] = 0; - } - matching_done: - return cex_map[node]; - } - - int UseNode(Node *node) override { - if (!old_cex.get_tree()) - return 0; - Node *old_node = MatchNode(node); - if(!old_node) - return 0; - return old_cex.get_tree()->Empty(old_node) ? -1 : 1; - } - - void ChooseExpand(const std::set &choices, std::set &best, bool high_priority, bool best_only) override { - if(cex_map.empty()) - cex_map[*(choices.begin())] = old_cex.get_root(); // match the root nodes - if(!high_priority || !old_cex.get_tree()){ - Heuristic::ChooseExpand(choices,best,false); - return; - } - // first, try to match the derivatino tree nodes to the old cex - std::set matched, unmatched; - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it){ - Node *node = (*it); - Node *old_node = MatchNode(node); - if(!old_node) - unmatched.insert(node); - else if(old_cex.get_tree()->Empty(old_node)) - unmatched.insert(node); - else - matched.insert(node); - } - if (matched.empty() && !high_priority) - Heuristic::ChooseExpand(unmatched,best,false); - else - Heuristic::ChooseExpand(matched,best,false); - } - }; - - - class LocalHeuristic : public Heuristic { - - RPFP::Node *old_node; - public: - LocalHeuristic(RPFP *_rpfp) - : Heuristic(_rpfp) - { - old_node = nullptr; - } - - void SetOldNode(RPFP::Node *_old_node){ - old_node = _old_node; - cex_map.clear(); - } - - // Maps nodes of derivation tree into old subtree - hash_map cex_map; - - void ChooseExpand(const std::set &choices, std::set &best, bool, bool) override { - if(old_node == nullptr){ - Heuristic::ChooseExpand(choices,best); - return; - } - // first, try to match the derivatino tree nodes to the old cex - std::set matched, unmatched; - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it){ - Node *node = (*it); - if(cex_map.empty()) - cex_map[node] = old_node; // match the root nodes - if(cex_map.find(node) == cex_map.end()){ // try to match an unmatched node - Node *parent = node->Incoming[0]->Parent; // assumes we are a tree! - if(cex_map.find(parent) == cex_map.end()) - throw "catastrophe in ReplayHeuristic::ChooseExpand"; - Node *old_parent = cex_map[parent]; - std::vector &chs = parent->Outgoing->Children; - if(old_parent && old_parent->Outgoing){ - std::vector &old_chs = old_parent->Outgoing->Children; - if(chs.size() == old_chs.size()){ - for(unsigned i = 0; i < chs.size(); i++) - cex_map[chs[i]] = old_chs[i]; - goto matching_done; - } - else - std::cout << "derivation tree does not match old cex" << std::endl; - } - for(unsigned i = 0; i < chs.size(); i++) - cex_map[chs[i]] = 0; - } - matching_done: - Node *old_node = cex_map[node]; - if(!old_node) - unmatched.insert(node); - else if(old_node != node->map) - unmatched.insert(node); - else - matched.insert(node); - } - Heuristic::ChooseExpand(unmatched,best); - } - }; - - /** This proposer class generates conjectures based on the - unwinding generated by a previous solver. The assumption is - that the provious solver was working on a different - abstraction of the same system. The trick is to adapt the - annotations in the old unwinding to the new predicates. We - start by generating a map from predicates and parameters in - the old problem to the new. - - HACK: mapping is done by cheesy name comparison. - */ - - class HistoryProposer : public Proposer - { - Duality *old_solver; - Duality *new_solver; - hash_map > conjectures; - - public: - /** Construct a history solver. */ - HistoryProposer(Duality *_old_solver, Duality *_new_solver) - : old_solver(_old_solver), new_solver(_new_solver) { - - // tricky: names in the axioms may have changed -- map them - hash_set &old_constants = old_solver->unwinding->ls->get_constants(); - hash_set &new_constants = new_solver->rpfp->ls->get_constants(); - hash_map cmap; - for(hash_set::iterator it = new_constants.begin(), en = new_constants.end(); it != en; ++it) - cmap[GetKey(*it)] = *it; - hash_map bckg_map; - for(hash_set::iterator it = old_constants.begin(), en = old_constants.end(); it != en; ++it){ - func_decl f = new_solver->ctx.translate(*it); // move to new context - if(cmap.find(GetKey(f)) != cmap.end()) - bckg_map[f] = cmap[GetKey(f)]; - // else - // std::cout << "constant not matched\n"; - } - - RPFP *old_unwinding = old_solver->unwinding; - hash_map > pred_match; - - // index all the predicates in the old unwinding - for(unsigned i = 0; i < old_unwinding->nodes.size(); i++){ - Node *node = old_unwinding->nodes[i]; - std::string key = GetKey(node); - pred_match[key].push_back(node); - } - - // match with predicates in the new RPFP - RPFP *rpfp = new_solver->rpfp; - for(unsigned i = 0; i < rpfp->nodes.size(); i++){ - Node *node = rpfp->nodes[i]; - std::string key = GetKey(node); - std::vector &matches = pred_match[key]; - for(unsigned j = 0; j < matches.size(); j++) - MatchNodes(node,matches[j],bckg_map); - } - } - - std::vector &Propose(Node *node) override { - return conjectures[node->map]; - } - - ~HistoryProposer() override { - }; - - private: - void MatchNodes(Node *new_node, Node *old_node, hash_map &bckg_map){ - if(old_node->Annotation.IsFull()) - return; // don't conjecture true! - hash_map var_match; - std::vector &new_params = new_node->Annotation.IndParams; - // Index the new parameters by their keys - for(unsigned i = 0; i < new_params.size(); i++) - var_match[GetKey(new_params[i])] = new_params[i]; - RPFP::Transformer &old = old_node->Annotation; - std::vector from_params = old.IndParams; - for(unsigned j = 0; j < from_params.size(); j++) - from_params[j] = new_solver->ctx.translate(from_params[j]); // get in new context - std::vector to_params = from_params; - for(unsigned j = 0; j < to_params.size(); j++){ - std::string key = GetKey(to_params[j]); - if(var_match.find(key) == var_match.end()){ - // std::cout << "unmatched parameter!\n"; - return; - } - to_params[j] = var_match[key]; - } - expr fmla = new_solver->ctx.translate(old.Formula); // get in new context - fmla = new_solver->rpfp->SubstParams(old.IndParams,to_params,fmla); // substitute parameters - hash_map memo; - fmla = new_solver->rpfp->SubstRec(memo,bckg_map,fmla); // substitute background constants - RPFP::Transformer new_annot = new_node->Annotation; - new_annot.Formula = fmla; - conjectures[new_node].push_back(new_annot); - } - - // We match names by removing suffixes beginning with double at sign - - std::string GetKey(Node *node){ - return GetKey(node->Name); - } - - std::string GetKey(const expr &var){ - return GetKey(var.decl()); - } - - std::string GetKey(const func_decl &f){ - std::string name = f.name().str(); - int idx = name.find("@@"); - if(idx >= 0) - name.erase(idx); - return name; - } - }; - }; - - static int stop_event = -1; - - class StreamReporter : public Reporter { - std::ostream &s; - public: - StreamReporter(RPFP *_rpfp, std::ostream &_s) - : Reporter(_rpfp), s(_s) {event = 0; depth = -1;} - int event; - int depth; - void ev(){ - if(stop_event == event){ - std::cout << "stop!\n"; - } - s << "[" << event++ << "]" ; - } - void Extend(RPFP::Node *node) override { - ev(); s << "node " << node->number << ": " << node->Name.name(); - std::vector &rps = node->Outgoing->Children; - for(unsigned i = 0; i < rps.size(); i++) - s << " " << rps[i]->number; - s << std::endl; - } - void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager) override { - ev(); s << "update " << node->number << " " << node->Name.name() << ": "; - rpfp->Summarize(update.Formula); - if(depth > 0) s << " (depth=" << depth << ")"; - if(eager) s << " (eager)"; - s << std::endl; - } - void Bound(RPFP::Node *node) override { - ev(); s << "check " << node->number << std::endl; - } - void Expand(RPFP::Edge *edge) override { - RPFP::Node *node = edge->Parent; - ev(); s << "expand " << node->map->number << " " << node->Name.name(); - if(depth > 0) s << " (depth=" << depth << ")"; - s << std::endl; - } - void Depth(int d) override { - depth = d; - } - void AddCover(RPFP::Node *covered, std::vector &covering) override { - ev(); s << "cover " << covered->Name.name() << ": " << covered->number << " by "; - for(unsigned i = 0; i < covering.size(); i++) - s << covering[i]->number << " "; - s << std::endl; - } - void RemoveCover(RPFP::Node *covered, RPFP::Node *covering) override { - ev(); s << "uncover " << covered->Name.name() << ": " << covered->number << " by " << covering->number << std::endl; - } - void Forcing(RPFP::Node *covered, RPFP::Node *covering) override { - ev(); s << "forcing " << covered->Name.name() << ": " << covered->number << " by " << covering->number << std::endl; - } - void Conjecture(RPFP::Node *node, const RPFP::Transformer &t) override { - ev(); s << "conjecture " << node->number << " " << node->Name.name() << ": "; - rpfp->Summarize(t.Formula); - s << std::endl; - } - void Dominates(RPFP::Node *node, RPFP::Node *other) override { - ev(); s << "dominates " << node->Name.name() << ": " << node->number << " > " << other->number << std::endl; - } - void InductionFailure(RPFP::Edge *edge, const std::vector &children) override { - ev(); s << "induction failure: " << edge->Parent->Name.name() << ", children ="; - for(unsigned i = 0; i < children.size(); i++) - s << " " << children[i]->number; - s << std::endl; - } - void UpdateUnderapprox(RPFP::Node *node, const RPFP::Transformer &update) override { - ev(); s << "underapprox " << node->number << " " << node->Name.name() << ": " << update.Formula << std::endl; - } - void Reject(RPFP::Edge *edge, const std::vector &children) override { - ev(); s << "reject " << edge->Parent->number << " " << edge->Parent->Name.name() << ": "; - for(unsigned i = 0; i < children.size(); i++) - s << " " << children[i]->number; - s << std::endl; - } - void Message(const std::string &msg) override { - ev(); s << "msg " << msg << std::endl; - } - - }; - - - class DualityDepthBounded : public Solver { - - Duality *duality; - context &ctx; // Z3 context - solver &slvr; // Z3 solver - - public: - DualityDepthBounded(RPFP *_rpfp) : - ctx(_rpfp->ctx), - slvr(_rpfp->slvr()){ - rpfp = _rpfp; - DepthBoundRPFP(); - duality = alloc(Duality,drpfp); - } - - ~DualityDepthBounded() override { - dealloc(duality); - delete drpfp; - } - - bool Solve() override { - int depth_bound = 10; - bool res; - SetMaxDepthRPFP(depth_bound); - duality->PreSolve(); - while(true){ - res = duality->SolveMain(); - if(!res || GetSolution()) - break; - depth_bound++; - SetMaxDepthRPFP(depth_bound); - res = duality->RecheckBounds(); - if(!res) - break; - } - duality->PostSolve(); - if(!res) - ConvertCex(); - return res; - } - - Counterexample &GetCounterexample() override { - return cex; - } - - bool SetOption(const std::string &option, const std::string &value) override { - return duality->SetOption(option,value); - } - - void LearnFrom(Solver *old_solver) override { - DualityDepthBounded *old = dynamic_cast(old_solver); - if(old){ - duality->LearnFrom(old->duality); - } - } - - bool IsResultRecursionBounded() override { - return duality->IsResultRecursionBounded(); - } - - void Cancel() override { - duality->Cancel(); - } - - typedef RPFP::Node Node; - typedef RPFP::Edge Edge; - RPFP *rpfp, *drpfp; - hash_map db_map, db_rev_map; - hash_map db_edge_rev_map; - std::vector db_saved_bounds; - Counterexample cex; - - expr AddParamToRels(hash_map &memo, hash_map &rmap, const expr &p, const expr &t) { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - expr &res = bar.first->second; - if(!bar.second) return res; - - if (t.is_app()) - { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(AddParamToRels(memo, rmap, p, t.arg(i))); - hash_map::iterator rit = rmap.find(f); - if(rit != rmap.end()){ - args.push_back(p); - res = (rit->second)(args); - res = ctx.make(And,res,ctx.make(Geq,p,ctx.int_val(0))); - } - else - res = f(args); - } - else if (t.is_quantifier()) - { - expr body = AddParamToRels(memo, rmap, p, t.body()); - res = clone_quantifier(t, body); - } - else res = t; - return res; - } - - - void DepthBoundRPFP(){ - drpfp = new RPFP(rpfp->ls); - expr dvar = ctx.int_const("@depth"); - expr dmax = ctx.int_const("@depth_max"); - for(unsigned i = 0; i < rpfp->nodes.size(); i++){ - Node *node = rpfp->nodes[i]; - std::vector arg_sorts; - const std::vector ¶ms = node->Annotation.IndParams; - for(unsigned j = 0; j < params.size(); j++) - arg_sorts.push_back(params[j].get_sort()); - arg_sorts.push_back(ctx.int_sort()); - std::string new_name = std::string("@db@") + node->Name.name().str(); - func_decl f = ctx.function(new_name.c_str(),arg_sorts.size(), VEC2PTR(arg_sorts),ctx.bool_sort()); - std::vector args = params; - args.push_back(dvar); - expr pat = f(args); - Node *dnode = drpfp->CreateNode(pat); - db_map[node] = dnode; - db_rev_map[dnode] = node; - expr bound_fmla = node->Bound.Formula; - if(!eq(bound_fmla,ctx.bool_val(true))){ - bound_fmla = implies(dvar == dmax,bound_fmla); - dnode->Bound.Formula = bound_fmla; - } - db_saved_bounds.push_back(bound_fmla); - // dnode->Annotation.Formula = ctx.make(And,node->Annotation.Formula,ctx.make(Geq,dvar,ctx.int_val(0))); - } - for(unsigned i = 0; i < rpfp->edges.size(); i++){ - Edge *edge = rpfp->edges[i]; - std::vector new_children; - std::vector new_relparams; - hash_map rmap; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *ch = edge->Children[j]; - Node *nch = db_map[ch]; - func_decl f = nch->Name; - func_decl sf = drpfp->NumberPred(f,j); - new_children.push_back(nch); - new_relparams.push_back(sf); - rmap[edge->F.RelParams[j]] = sf; - } - std::vector new_indparams = edge->F.IndParams; - new_indparams.push_back(dvar); - hash_map memo; - expr new_fmla = AddParamToRels(memo,rmap,ctx.make(Sub,dvar,ctx.int_val(1)),edge->F.Formula); - RPFP::Transformer new_t = drpfp->CreateTransformer(new_relparams,new_indparams,new_fmla); - Node *new_parent = db_map[edge->Parent]; - db_edge_rev_map[drpfp->CreateEdge(new_parent,new_t,new_children)] = edge; - } - } - - void SetMaxDepthRPFP(int depth){ - hash_map subst; - expr dmax = ctx.int_const("@depth_max"); - subst[dmax] = ctx.int_val(depth); - for(unsigned i = 0; i < drpfp->nodes.size(); i++){ - Node *node = drpfp->nodes[i]; - expr fmla = db_saved_bounds[i]; - fmla = drpfp->SubstRec(subst,fmla); - node->Bound.Formula = fmla; - } - } - - void ConvertCex(){ - cex.clear(); - RPFP *tree = new RPFP(rpfp->ls); - Node *root; - Counterexample &dctx = duality->GetCounterexample(); - hash_map ctx_node_map; - for(unsigned i = 0; i < dctx.get_tree()->nodes.size(); i++){ - Node *dnode = dctx.get_tree()->nodes[i]; - Node *onode = db_rev_map[dnode->map->map]; - Node *node = tree->CloneNode(onode); - node->number = dnode->number; // numbers have to match for model to make sense - ctx_node_map[dnode] = node; - if(dnode == dctx.get_root()) - root = node; - } - for(unsigned i = 0; i < dctx.get_tree()->edges.size(); i++){ - Edge *dedge = dctx.get_tree()->edges[i]; - Edge *oedge = db_edge_rev_map[dedge->map]; - Node *parent = ctx_node_map[dedge->Parent]; - std::vector chs; - for(unsigned j = 0; j < dedge->Children.size(); j++) - chs.push_back(ctx_node_map[dedge->Children[j]]); - Edge *edge = tree->CreateEdge(parent,oedge->F,chs); - edge->number = dedge->number; // numbers have to match for model to make sense - edge->map = oedge; - } - tree->dualModel = dctx.get_tree()->dualModel; - cex.set(tree,root); - } - - bool GetSolution(){ - for(unsigned i = 0; i < rpfp->nodes.size(); i++) - if(!drpfp->nodes[i]->Annotation.SubsetEq(rpfp->nodes[i]->Bound)) - return false; - expr dvar = ctx.int_const("@depth"); - hash_map subst; - subst[dvar] = ctx.int_val(INT_MAX); - for(unsigned i = 0; i < rpfp->nodes.size(); i++){ - expr fmla = drpfp->nodes[i]->Annotation.Formula; - fmla = drpfp->SubstRec(subst,fmla); - fmla = fmla.simplify(); - rpfp->nodes[i]->Annotation.Formula = fmla; - } - return true; - } - - void UndoDepthBoundRPFP(){ -#if 0 - if(cex.get_tree()){ - // here, need to map the cex back... - } - // also need to map the proof back, but we don't... -#endif - } - }; - - Solver *Solver::Create(const std::string &solver_class, RPFP *rpfp){ - // Solver *s = alloc(DualityDepthBounded,rpfp); - Solver *s = alloc(Duality,rpfp); - return s; - } - - Reporter *CreateStdoutReporter(RPFP *rpfp){ - return new StreamReporter(rpfp, std::cout); - } - - class ConjectureFileReporter : public Reporter { - std::ofstream s; - public: - ConjectureFileReporter(RPFP *_rpfp, const std::string &fname) - : Reporter(_rpfp), s(fname.c_str()) {} - void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager) override { - s << "(define-fun " << node->Name.name() << " ("; - for(unsigned i = 0; i < update.IndParams.size(); i++){ - if(i != 0) - s << " "; - s << "(" << update.IndParams[i] << " " << update.IndParams[i].get_sort() << ")"; - } - s << ") Bool \n"; - s << update.Formula << ")\n"; - s << std::endl; - } - }; - - Reporter *CreateConjectureFileReporter(RPFP *rpfp, const std::string &fname){ - return new ConjectureFileReporter(rpfp, fname); - } - -} - diff --git a/src/duality/duality_wrapper.cpp b/src/duality/duality_wrapper.cpp deleted file mode 100644 index 17adbdcea..000000000 --- a/src/duality/duality_wrapper.cpp +++ /dev/null @@ -1,744 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - wrapper.cpp - - Abstract: - - wrap various objects in the style expected by duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "duality/duality_wrapper.h" -#include -#include "smt/smt_solver.h" -#include "interp/iz3interp.h" -#include "util/statistics.h" -#include "ast/expr_abstract.h" -#include "util/stopwatch.h" -#include "model/model_smt2_pp.h" -#include "qe/qe_lite.h" - -namespace Duality { - - solver::solver(Duality::context& c, bool _extensional, bool models) : object(c), the_model(c) { - params_ref p; - p.set_bool("proof", true); // this is currently useless - if(models) - p.set_bool("model", true); - p.set_bool("unsat_core", true); - bool mbqi = c.get_config().get().get_bool("mbqi",true); - p.set_bool("mbqi",mbqi); // just to test - p.set_str("mbqi.id","itp"); // use mbqi for quantifiers in interpolants - p.set_uint("mbqi.max_iterations",1); // use mbqi for quantifiers in interpolants - extensional = mbqi && (true || _extensional); - if(extensional) - p.set_bool("array.extensional",true); - scoped_ptr sf = mk_smt_solver_factory(); - m_solver = (*sf)(m(), p, true, true, true, ::symbol::null); - m_solver->updt_params(p); // why do we have to do this? - canceled = false; - m_mode = m().proof_mode(); - } - - expr context::constant(const std::string &name, const sort &ty){ - symbol s = str_symbol(name.c_str()); - return cook(m().mk_const(m().mk_const_decl(s, ty))); - } - - expr context::make(decl_kind op, int n, ::expr **args){ - switch(op) { - case True: return mki(m_basic_fid,OP_TRUE,n,args); - case False: return mki(m_basic_fid,OP_FALSE,n,args); - case Equal: return mki(m_basic_fid,OP_EQ,n,args); - case Distinct: return mki(m_basic_fid,OP_DISTINCT,n,args); - case Ite: return mki(m_basic_fid,OP_ITE,n,args); - case And: return mki(m_basic_fid,OP_AND,n,args); - case Or: return mki(m_basic_fid,OP_OR,n,args); - case Iff: return mki(m_basic_fid,OP_IFF,n,args); - case Xor: return mki(m_basic_fid,OP_XOR,n,args); - case Not: return mki(m_basic_fid,OP_NOT,n,args); - case Implies: return mki(m_basic_fid,OP_IMPLIES,n,args); - case Oeq: return mki(m_basic_fid,OP_OEQ,n,args); - case Interp: return mki(m_basic_fid,OP_INTERP,n,args); - case Leq: return mki(m_arith_fid,OP_LE,n,args); - case Geq: return mki(m_arith_fid,OP_GE,n,args); - case Lt: return mki(m_arith_fid,OP_LT,n,args); - case Gt: return mki(m_arith_fid,OP_GT,n,args); - case Plus: return mki(m_arith_fid,OP_ADD,n,args); - case Sub: return mki(m_arith_fid,OP_SUB,n,args); - case Uminus: return mki(m_arith_fid,OP_UMINUS,n,args); - case Times: return mki(m_arith_fid,OP_MUL,n,args); - case Div: return mki(m_arith_fid,OP_DIV,n,args); - case Idiv: return mki(m_arith_fid,OP_IDIV,n,args); - case Rem: return mki(m_arith_fid,OP_REM,n,args); - case Mod: return mki(m_arith_fid,OP_MOD,n,args); - case Power: return mki(m_arith_fid,OP_POWER,n,args); - case ToReal: return mki(m_arith_fid,OP_TO_REAL,n,args); - case ToInt: return mki(m_arith_fid,OP_TO_INT,n,args); - case IsInt: return mki(m_arith_fid,OP_IS_INT,n,args); - case Store: return mki(m_array_fid,OP_STORE,n,args); - case Select: return mki(m_array_fid,OP_SELECT,n,args); - case ConstArray: return mki(m_array_fid,OP_CONST_ARRAY,n,args); - case ArrayDefault: return mki(m_array_fid,OP_ARRAY_DEFAULT,n,args); - case ArrayMap: return mki(m_array_fid,OP_ARRAY_MAP,n,args); - case SetUnion: return mki(m_array_fid,OP_SET_UNION,n,args); - case SetIntersect: return mki(m_array_fid,OP_SET_INTERSECT,n,args); - case SetDifference: return mki(m_array_fid,OP_SET_DIFFERENCE,n,args); - case SetComplement: return mki(m_array_fid,OP_SET_COMPLEMENT,n,args); - case SetSubSet: return mki(m_array_fid,OP_SET_SUBSET,n,args); - case AsArray: return mki(m_array_fid,OP_AS_ARRAY,n,args); - default: - assert(0); - return expr(*this); - } - } - - expr context::mki(family_id fid, ::decl_kind dk, int n, ::expr **args){ - return cook(m().mk_app(fid, dk, 0, nullptr, n, (::expr **)args)); - } - - expr context::make(decl_kind op, const std::vector &args){ - static std::vector< ::expr*> a(10); - if(a.size() < args.size()) - a.resize(args.size()); - for(unsigned i = 0; i < args.size(); i++) - a[i] = to_expr(args[i].raw()); - return make(op,args.size(), args.size() ? VEC2PTR(a) : nullptr); - } - - expr context::make(decl_kind op){ - return make(op,0,nullptr); - } - - expr context::make(decl_kind op, const expr &arg0){ - ::expr *a = to_expr(arg0.raw()); - return make(op,1,&a); - } - - expr context::make(decl_kind op, const expr &arg0, const expr &arg1){ - ::expr *args[2]; - args[0] = to_expr(arg0.raw()); - args[1] = to_expr(arg1.raw()); - return make(op,2,args); - } - - expr context::make(decl_kind op, const expr &arg0, const expr &arg1, const expr &arg2){ - ::expr *args[3]; - args[0] = to_expr(arg0.raw()); - args[1] = to_expr(arg1.raw()); - args[2] = to_expr(arg2.raw()); - return make(op,3,args); - } - - expr context::make_quant(decl_kind op, const std::vector &bvs, const expr &body){ - if(bvs.size() == 0) return body; - std::vector< ::expr *> foo(bvs.size()); - - - std::vector< ::symbol> names; - std::vector< ::sort *> types; - std::vector< ::expr *> bound_asts; - unsigned num_bound = bvs.size(); - - for (unsigned i = 0; i < num_bound; ++i) { - app* a = to_app(bvs[i].raw()); - ::symbol s(to_app(a)->get_decl()->get_name()); - names.push_back(s); - types.push_back(m().get_sort(a)); - bound_asts.push_back(a); - } - expr_ref abs_body(m()); - expr_abstract(m(), 0, num_bound, VEC2PTR(bound_asts), to_expr(body.raw()), abs_body); - expr_ref result(m()); - result = m().mk_quantifier( - op == Forall, - names.size(), VEC2PTR(types), VEC2PTR(names), abs_body.get(), - 0, - ::symbol(), - ::symbol(), - 0, nullptr, - 0, nullptr - ); - return cook(result.get()); - } - - expr context::make_quant(decl_kind op, const std::vector &_sorts, const std::vector &_names, const expr &body){ - if(_sorts.size() == 0) return body; - - - std::vector< ::symbol> names; - std::vector< ::sort *> types; - std::vector< ::expr *> bound_asts; - unsigned num_bound = _sorts.size(); - - for (unsigned i = 0; i < num_bound; ++i) { - names.push_back(_names[i]); - types.push_back(to_sort(_sorts[i].raw())); - } - expr_ref result(m()); - result = m().mk_quantifier( - op == Forall, - names.size(), VEC2PTR(types), VEC2PTR(names), to_expr(body.raw()), - 0, - ::symbol(), - ::symbol(), - 0, nullptr, - 0, nullptr - ); - return cook(result.get()); - } - - - decl_kind func_decl::get_decl_kind() const { - return ctx().get_decl_kind(*this); - } - - decl_kind context::get_decl_kind(const func_decl &t){ - ::func_decl *d = to_func_decl(t.raw()); - if (null_family_id == d->get_family_id()) - return Uninterpreted; - // return (opr)d->get_decl_kind(); - if (m_basic_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_TRUE: return True; - case OP_FALSE: return False; - case OP_EQ: return Equal; - case OP_DISTINCT: return Distinct; - case OP_ITE: return Ite; - case OP_AND: return And; - case OP_OR: return Or; - case OP_IFF: return Iff; - case OP_XOR: return Xor; - case OP_NOT: return Not; - case OP_IMPLIES: return Implies; - case OP_OEQ: return Oeq; - case OP_INTERP: return Interp; - default: - return OtherBasic; - } - } - if (m_arith_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_LE: return Leq; - case OP_GE: return Geq; - case OP_LT: return Lt; - case OP_GT: return Gt; - case OP_ADD: return Plus; - case OP_SUB: return Sub; - case OP_UMINUS: return Uminus; - case OP_MUL: return Times; - case OP_DIV: return Div; - case OP_IDIV: return Idiv; - case OP_REM: return Rem; - case OP_MOD: return Mod; - case OP_POWER: return Power; - case OP_TO_REAL: return ToReal; - case OP_TO_INT: return ToInt; - case OP_IS_INT: return IsInt; - default: - return OtherArith; - } - } - if (m_array_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_STORE: return Store; - case OP_SELECT: return Select; - case OP_CONST_ARRAY: return ConstArray; - case OP_ARRAY_DEFAULT: return ArrayDefault; - case OP_ARRAY_MAP: return ArrayMap; - case OP_SET_UNION: return SetUnion; - case OP_SET_INTERSECT: return SetIntersect; - case OP_SET_DIFFERENCE: return SetDifference; - case OP_SET_COMPLEMENT: return SetComplement; - case OP_SET_SUBSET: return SetSubSet; - case OP_AS_ARRAY: return AsArray; - default: - return OtherArray; - } - } - - return Other; - } - - - sort_kind context::get_sort_kind(const sort &s){ - family_id fid = to_sort(s.raw())->get_family_id(); - ::decl_kind k = to_sort(s.raw())->get_decl_kind(); - if (m().is_uninterp(to_sort(s.raw()))) { - return UninterpretedSort; - } - else if (fid == m_basic_fid && k == BOOL_SORT) { - return BoolSort; - } - else if (fid == m_arith_fid && k == INT_SORT) { - return IntSort; - } - else if (fid == m_arith_fid && k == REAL_SORT) { - return RealSort; - } - else if (fid == m_array_fid && k == ARRAY_SORT) { - return ArraySort; - } - else { - return UnknownSort; - } - } - - expr func_decl::operator()(unsigned n, expr const * args) const { - std::vector< ::expr *> _args(n); - for(unsigned i = 0; i < n; i++) - _args[i] = to_expr(args[i].raw()); - return ctx().cook(m().mk_app(to_func_decl(raw()),n,VEC2PTR(_args))); - } - - int solver::get_num_decisions(){ - ::statistics st; - m_solver->collect_statistics(st); - std::ostringstream ss; - st.display(ss); - std::string stats = ss.str(); - int pos = stats.find("decisions:"); - if(pos < 0) return 0; // for some reason, decisions are not reported if there are none - pos += 10; - int end = stats.find('\n',pos); - std::string val = stats.substr(pos,end-pos); - return atoi(val.c_str()); - } - - void context::print_expr(std::ostream &s, const ast &e){ - s << mk_pp(e.raw(), m()); - } - - - expr expr::simplify(const params &_p) const { - ::expr * a = to_expr(raw()); - params_ref p = _p.get(); - th_rewriter m_rw(m(), p); - expr_ref result(m()); - m_rw(a, result); - return ctx().cook(result); - } - - expr expr::simplify() const { - params p; - return simplify(p); - } - - expr context::make_var(int idx, const sort &s){ - ::sort * a = to_sort(s.raw()); - return cook(m().mk_var(idx,a)); - } - - - expr expr::qe_lite() const { - ::qe_lite qe(m(), params_ref()); - expr_ref result(to_expr(raw()),m()); - proof_ref pf(m()); - qe(result,pf); - return ctx().cook(result); - } - - expr expr::qe_lite(const std::set &idxs, bool index_of_bound) const { - ::qe_lite qe(m(), params_ref()); - expr_ref result(to_expr(raw()),m()); - proof_ref pf(m()); - uint_set uis; - for(std::set::const_iterator it=idxs.begin(), en = idxs.end(); it != en; ++it) - uis.insert(*it); - qe(uis,index_of_bound,result); - return ctx().cook(result); - } - - expr clone_quantifier(const expr &q, const expr &b){ - return q.ctx().cook(q.m().update_quantifier(to_quantifier(q.raw()), to_expr(b.raw()))); - } - - expr clone_quantifier(const expr &q, const expr &b, const std::vector &patterns){ - quantifier *thing = to_quantifier(q.raw()); - bool is_forall = thing->is_forall(); - unsigned num_patterns = patterns.size(); - std::vector< ::expr *> _patterns(num_patterns); - for(unsigned i = 0; i < num_patterns; i++) - _patterns[i] = to_expr(patterns[i].raw()); - return q.ctx().cook(q.m().update_quantifier(thing, is_forall, num_patterns, VEC2PTR(_patterns), to_expr(b.raw()))); - } - - expr clone_quantifier(decl_kind dk, const expr &q, const expr &b){ - quantifier *thing = to_quantifier(q.raw()); - bool is_forall = dk == Forall; - return q.ctx().cook(q.m().update_quantifier(thing, is_forall, to_expr(b.raw()))); - } - - void expr::get_patterns(std::vector &pats) const { - quantifier *thing = to_quantifier(raw()); - unsigned num_patterns = thing->get_num_patterns(); - :: expr * const *it = thing->get_patterns(); - pats.resize(num_patterns); - for(unsigned i = 0; i < num_patterns; i++) - pats[i] = expr(ctx(),it[i]); - } - - - unsigned func_decl::arity() const { - return (to_func_decl(raw())->get_arity()); - } - - sort func_decl::domain(unsigned i) const { - return sort(ctx(),(to_func_decl(raw())->get_domain(i))); - } - - sort func_decl::range() const { - return sort(ctx(),(to_func_decl(raw())->get_range())); - } - - func_decl context::fresh_func_decl(char const * prefix, const std::vector &domain, sort const & range){ - std::vector < ::sort * > _domain(domain.size()); - for(unsigned i = 0; i < domain.size(); i++) - _domain[i] = to_sort(domain[i].raw()); - ::func_decl* d = m().mk_fresh_func_decl(prefix, - _domain.size(), - VEC2PTR(_domain), - to_sort(range.raw())); - return func_decl(*this,d); - } - - func_decl context::fresh_func_decl(char const * prefix, sort const & range){ - ::func_decl* d = m().mk_fresh_func_decl(prefix, - 0, - nullptr, - to_sort(range.raw())); - return func_decl(*this,d); - } - - - -#if 0 - - - lbool interpolating_solver::interpolate( - const std::vector &assumptions, - std::vector &interpolants, - model &model, - Z3_literals &labels, - bool incremental) - { - Z3_model _model = 0; - Z3_literals _labels = 0; - Z3_lbool lb; - std::vector _assumptions(assumptions.size()); - std::vector _interpolants(assumptions.size()-1); - for(unsigned i = 0; i < assumptions.size(); i++) - _assumptions[i] = assumptions[i]; - std::vector _theory(theory.size()); - for(unsigned i = 0; i < theory.size(); i++) - _theory[i] = theory[i]; - - lb = Z3_interpolate( - ctx(), - _assumptions.size(), - VEC2PTR(_assumptions), - 0, - 0, - VEC2PTR(_interpolants), - &_model, - &_labels, - incremental, - _theory.size(), - VEC2PTR(_theory)); - - if(lb == Z3_L_FALSE){ - interpolants.resize(_interpolants.size()); - for (unsigned i = 0; i < _interpolants.size(); ++i) { - interpolants[i] = expr(ctx(),_interpolants[i]); - } - } - - if (_model) { - model = iz3wrapper::model(ctx(), _model); - } - - if(_labels){ - labels = _labels; - } - - return lb; - } - -#endif - - static int linearize_assumptions(int num, - TermTree *assumptions, - std::vector > &linear_assumptions, - std::vector &parents){ - for(unsigned i = 0; i < assumptions->getChildren().size(); i++) - num = linearize_assumptions(num, assumptions->getChildren()[i], linear_assumptions, parents); - // linear_assumptions[num].push_back(assumptions->getTerm()); - for(unsigned i = 0; i < assumptions->getChildren().size(); i++) - parents[assumptions->getChildren()[i]->getNumber()] = num; - parents[num] = SHRT_MAX; // in case we have no parent - linear_assumptions[num].push_back(assumptions->getTerm()); - std::vector &ts = assumptions->getTerms(); - for(unsigned i = 0; i < ts.size(); i++) - linear_assumptions[num].push_back(ts[i]); - return num + 1; - } - - static int unlinearize_interpolants(int num, - TermTree* assumptions, - const std::vector &interpolant, - TermTree * &tree_interpolant) - { - std::vector chs(assumptions->getChildren().size()); - for(unsigned i = 0; i < assumptions->getChildren().size(); i++) - num = unlinearize_interpolants(num, assumptions->getChildren()[i], interpolant,chs[i]); - expr f; - if(num < (int)interpolant.size()) // last interpolant is missing, presumed false - f = interpolant[num]; - tree_interpolant = new TermTree(f,chs); - return num + 1; - } - - - lbool interpolating_solver::interpolate_tree(TermTree *assumptions, - TermTree *&interpolant, - model &model, - literals &labels, - bool incremental - ) - - { - int size = assumptions->number(0); - std::vector > linear_assumptions(size); - std::vector parents(size); - linearize_assumptions(0,assumptions,linear_assumptions,parents); - - ptr_vector< ::ast> _interpolants(size-1); - vector >_assumptions(size); - for(int i = 0; i < size; i++) - for(unsigned j = 0; j < linear_assumptions[i].size(); j++) - _assumptions[i].push_back(linear_assumptions[i][j]); - ::vector _parents; _parents.resize(parents.size()); - for(unsigned i = 0; i < parents.size(); i++) - _parents[i] = parents[i]; - ptr_vector< ::ast> _theory(theory.size()); - for(unsigned i = 0; i < theory.size(); i++) - _theory[i] = theory[i]; - - - if(!incremental){ - push(); - for(unsigned i = 0; i < linear_assumptions.size(); i++) - for(unsigned j = 0; j < linear_assumptions[i].size(); j++) - add(linear_assumptions[i][j]); - } - - check_result res = unsat; - - if(!m_solver->get_proof()) - res = check(); - - if(res == unsat){ - - interpolation_options_struct opts; - if(weak_mode) - opts.set("weak","1"); - - ::ast *proof = m_solver->get_proof(); - try { - iz3interpolate(m(),proof,_assumptions,_parents,_interpolants,_theory,&opts); - } - // If there's an interpolation bug, throw a char * - // exception so duality can catch it and restart. - catch (const interpolation_failure &f) { - throw f.msg(); - } - - std::vector linearized_interpolants(_interpolants.size()); - for(unsigned i = 0; i < _interpolants.size(); i++) - linearized_interpolants[i] = expr(ctx(),_interpolants[i]); - - // since iz3interpolant returns interpolants with one ref count, we decrement here - for(unsigned i = 0; i < _interpolants.size(); i++) - m().dec_ref(_interpolants[i]); - - unlinearize_interpolants(0,assumptions,linearized_interpolants,interpolant); - interpolant->setTerm(ctx().bool_val(false)); - } - - model_ref _m; - m_solver->get_model(_m); - model = Duality::model(ctx(),_m.get()); - -#if 0 - if(_labels){ - labels = _labels; - } -#endif - - if(!incremental) - pop(); - - return (res == unsat) ? l_false : ((res == sat) ? l_true : l_undef); - - } - - - void interpolating_solver::SetWeakInterpolants(bool weak){ - weak_mode = weak; - } - - - void interpolating_solver::SetPrintToFile(const std::string &filename){ - print_filename = filename; - } - - void interpolating_solver::AssertInterpolationAxiom(const expr & t){ - add(t); - theory.push_back(t); - } - - - void interpolating_solver::RemoveInterpolationAxiom(const expr & t){ - // theory.remove(t); - } - - - const char *interpolating_solver::profile(){ - // return Z3_interpolation_profile(ctx()); - return ""; - } - - - static void get_assumptions_rec(stl_ext::hash_set &memo, const proof &pf, std::vector &assumps){ - if(memo.find(pf) != memo.end())return; - memo.insert(pf); - pfrule dk = pf.rule(); - if(dk == PR_ASSERTED){ - expr con = pf.conc(); - assumps.push_back(con); - } - else { - unsigned nprems = pf.num_prems(); - for(unsigned i = 0; i < nprems; i++){ - proof arg = pf.prem(i); - get_assumptions_rec(memo,arg,assumps); - } - } - } - - void proof::get_assumptions(std::vector &assumps){ - stl_ext::hash_set memo; - get_assumptions_rec(memo,*this,assumps); - } - - - void ast::show() const{ - std::cout << mk_pp(raw(), m()) << std::endl; - } - - void model::show() const { - model_smt2_pp(std::cout, m(), *m_model, 0); - std::cout << std::endl; - } - - void model::show_hash() const { - std::ostringstream ss; - model_smt2_pp(ss, m(), *m_model, 0); - hash_space::hash hasher; - unsigned h = hasher(ss.str()); - std::cout << "model hash: " << h << "\n"; - } - - void solver::show() { - unsigned n = m_solver->get_num_assertions(); - if(!n) - return; - ast_smt_pp pp(m()); - for (unsigned i = 0; i < n-1; ++i) - pp.add_assumption(m_solver->get_assertion(i)); - pp.display_smt2(std::cout, m_solver->get_assertion(n-1)); - } - - void solver::print(const char *filename) { - std::ofstream f(filename); - unsigned n = m_solver->get_num_assertions(); - if(!n) - return; - ast_smt_pp pp(m()); - for (unsigned i = 0; i < n-1; ++i) - pp.add_assumption(m_solver->get_assertion(i)); - pp.display_smt2(f, m_solver->get_assertion(n-1)); - } - - - void solver::show_assertion_ids() { -#if 0 - unsigned n = m_solver->get_num_assertions(); - std::cerr << "assertion ids: "; - for (unsigned i = 0; i < n-1; ++i) - std::cerr << " " << m_solver->get_assertion(i)->get_id(); - std::cerr << "\n"; -#else - unsigned n = m_solver->get_num_assertions(); - std::cerr << "assertion ids hash: "; - unsigned h = 0; - for (unsigned i = 0; i < n-1; ++i) - h += m_solver->get_assertion(i)->get_id(); - std::cerr << h << "\n"; -#endif - } - - void include_ast_show(ast &a){ - a.show(); - } - - void include_model_show(model &a){ - a.show(); - } - - void show_ast(::ast *a, ast_manager &m) { - std::cout << mk_pp(a, m) << std::endl; - } - - bool expr::is_label (bool &pos,std::vector &names) const { - buffer< ::symbol> _names; - bool res = m().is_label(to_expr(raw()),pos,_names); - if(res) - for(unsigned i = 0; i < _names.size(); i++) - names.push_back(symbol(ctx(),_names[i])); - return res; - } - - double current_time() - { - static stopwatch sw; - static bool started = false; - if(!started){ - sw.start(); - started = true; - } - return sw.get_current_seconds(); - } - -} - - - - diff --git a/src/duality/duality_wrapper.h b/src/duality/duality_wrapper.h deleted file mode 100644 index 69f821a08..000000000 --- a/src/duality/duality_wrapper.h +++ /dev/null @@ -1,1489 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - duality_wrapper.h - - Abstract: - - wrap various Z3 classes in the style expected by duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ -#ifndef DUALITY_WRAPPER_H_ -#define DUALITY_WRAPPER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include "util/version.h" -#include - -#include "interp/iz3hash.h" -#include "model/model.h" -#include "solver/solver.h" - -#include "ast/well_sorted.h" -#include "ast/arith_decl_plugin.h" -#include "ast/bv_decl_plugin.h" -#include "ast/datatype_decl_plugin.h" -#include "ast/array_decl_plugin.h" -#include "ast/ast_translation.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_smt_pp.h" -#include "ast/ast_smt2_pp.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/rewriter/var_subst.h" -#include "ast/expr_substitution.h" -#include "ast/pp.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" -#include "ast/scoped_proof.h" - -namespace Duality { - - class exception; - class config; - class context; - class symbol; - class params; - class ast; - class sort; - class func_decl; - class expr; - class solver; - class goal; - class tactic; - class probe; - class model; - class func_interp; - class func_entry; - class statistics; - class apply_result; - class fixedpoint; - class literals; - - /** - Duality global configuration object. - */ - - class config { - params_ref m_params; - config & operator=(config const & s); - public: - config(config const & s) : m_params(s.m_params) {} - config(const params_ref &_params) : m_params(_params) {} - config() { } // TODO: create a new params object here - ~config() { } - void set(char const * param, char const * value) { m_params.set_str(param,value); } - void set(char const * param, bool value) { m_params.set_bool(param,value); } - void set(char const * param, int value) { m_params.set_uint(param,value); } - params_ref &get() {return m_params;} - const params_ref &get() const {return m_params;} - }; - - enum decl_kind { - True, - False, - And, - Or, - Not, - Iff, - Ite, - Equal, - Implies, - Distinct, - Xor, - Oeq, - Interp, - Leq, - Geq, - Lt, - Gt, - Plus, - Sub, - Uminus, - Times, - Div, - Idiv, - Rem, - Mod, - Power, - ToReal, - ToInt, - IsInt, - Select, - Store, - ConstArray, - ArrayDefault, - ArrayMap, - SetUnion, - SetIntersect, - SetDifference, - SetComplement, - SetSubSet, - AsArray, - Numeral, - Forall, - Exists, - Variable, - Uninterpreted, - OtherBasic, - OtherArith, - OtherArray, - Other - }; - - enum sort_kind {BoolSort,IntSort,RealSort,ArraySort,UninterpretedSort,UnknownSort}; - - /** - A context has an ast manager global configuration options, etc. - */ - - class context { - protected: - ast_manager &mgr; - config m_config; - - family_id m_basic_fid; - family_id m_array_fid; - family_id m_arith_fid; - family_id m_bv_fid; - family_id m_dt_fid; - family_id m_datalog_fid; - arith_util m_arith_util; - - public: - context(ast_manager &_manager, const config &_config) : mgr(_manager), m_config(_config), m_arith_util(_manager) { - m_basic_fid = m().get_basic_family_id(); - m_arith_fid = m().mk_family_id("arith"); - m_bv_fid = m().mk_family_id("bv"); - m_array_fid = m().mk_family_id("array"); - m_dt_fid = m().mk_family_id("datatype"); - m_datalog_fid = m().mk_family_id("datalog_relation"); - } - ~context() { } - - ast_manager &m() const {return *(ast_manager *)&mgr;} - - void set(char const * param, char const * value) { m_config.set(param,value); } - void set(char const * param, bool value) { m_config.set(param,value); } - void set(char const * param, int value) { m_config.set(param,value); } - config &get_config() {return m_config;} - - symbol str_symbol(char const * s); - symbol int_symbol(int n); - - sort bool_sort(); - sort int_sort(); - sort real_sort(); - sort bv_sort(unsigned sz); - sort array_sort(const sort & d, const sort & r); - - func_decl function(symbol const & name, unsigned arity, sort const * domain, sort const & range); - func_decl function(char const * name, unsigned arity, sort const * domain, sort const & range); - func_decl function(char const * name, sort const & domain, sort const & range); - func_decl function(char const * name, sort const & d1, sort const & d2, sort const & range); - func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & range); - func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & range); - func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range); - func_decl fresh_func_decl(char const * name, const std::vector &domain, sort const & range); - func_decl fresh_func_decl(char const * name, sort const & range); - - expr constant(symbol const & name, sort const & s); - expr constant(char const * name, sort const & s); - expr constant(const std::string &name, sort const & s); - expr bool_const(char const * name); - expr int_const(char const * name); - expr real_const(char const * name); - expr bv_const(char const * name, unsigned sz); - - expr bool_val(bool b); - - expr int_val(int n); - expr int_val(unsigned n); - expr int_val(char const * n); - - expr real_val(int n, int d); - expr real_val(int n); - expr real_val(unsigned n); - expr real_val(char const * n); - - expr bv_val(int n, unsigned sz); - expr bv_val(unsigned n, unsigned sz); - expr bv_val(char const * n, unsigned sz); - - expr num_val(int n, sort const & s); - - expr mki(family_id fid, ::decl_kind dk, int n, ::expr **args); - expr make(decl_kind op, int n, ::expr **args); - expr make(decl_kind op, const std::vector &args); - expr make(decl_kind op); - expr make(decl_kind op, const expr &arg0); - expr make(decl_kind op, const expr &arg0, const expr &arg1); - expr make(decl_kind op, const expr &arg0, const expr &arg1, const expr &arg2); - - expr make_quant(decl_kind op, const std::vector &bvs, const expr &body); - expr make_quant(decl_kind op, const std::vector &_sorts, const std::vector &_names, const expr &body); - expr make_var(int idx, const sort &s); - - decl_kind get_decl_kind(const func_decl &t); - - sort_kind get_sort_kind(const sort &s); - - expr translate(const expr &e); - func_decl translate(const func_decl &); - - void print_expr(std::ostream &s, const ast &e); - - fixedpoint mk_fixedpoint(); - - expr cook(::expr *a); - std::vector cook(ptr_vector< ::expr> v); - ::expr *uncook(const expr &a); - }; - - template - class z3array { - T * m_array; - unsigned m_size; - z3array(z3array const & s); - z3array & operator=(z3array const & s); - public: - z3array(unsigned sz):m_size(sz) { m_array = new T[sz]; } - ~z3array() { delete[] m_array; } - unsigned size() const { return m_size; } - T & operator[](unsigned i) { assert(i < m_size); return m_array[i]; } - T const & operator[](unsigned i) const { assert(i < m_size); return m_array[i]; } - T const * ptr() const { return m_array; } - T * ptr() { return m_array; } - }; - - class object { - protected: - context * m_ctx; - public: - object(): m_ctx((context *)nullptr) {} - object(context & c):m_ctx(&c) {} - object(object const & s):m_ctx(s.m_ctx) {} - context & ctx() const { return *m_ctx; } - friend void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); } - ast_manager &m() const {return m_ctx->m();} - }; - - class symbol : public object { - ::symbol m_sym; - public: - symbol(context & c, ::symbol s):object(c), m_sym(s) {} - symbol(symbol const & s):object(s), m_sym(s.m_sym) {} - symbol & operator=(symbol const & s) { m_ctx = s.m_ctx; m_sym = s.m_sym; return *this; } - operator ::symbol() const {return m_sym;} - std::string str() const { - if (m_sym.is_numerical()) { - std::ostringstream buffer; - buffer << m_sym.get_num(); - return buffer.str(); - } - else { - return m_sym.bare_str(); - } - } - friend std::ostream & operator<<(std::ostream & out, symbol const & s) { - return out << s.str(); - } - friend bool operator==(const symbol &x, const symbol &y) { - return x.m_sym == y.m_sym; - } - }; - - class params : public config {}; - - /** Wrapper around an ast pointer */ - class ast_i : public object { - protected: - ::ast *_ast; - public: - ::ast * const &raw() const {return _ast;} - ast_i(context & c, ::ast *a = nullptr) : object(c) {_ast = a;} - - ast_i(){_ast = nullptr;} - bool eq(const ast_i &other) const { - return _ast == other._ast; - } - bool lt(const ast_i &other) const { - return _ast < other._ast; - } - friend bool operator==(const ast_i &x, const ast_i&y){ - return x.eq(y); - } - friend bool operator!=(const ast_i &x, const ast_i&y){ - return !x.eq(y); - } - friend bool operator<(const ast_i &x, const ast_i&y){ - return x.lt(y); - } - size_t hash() const {return (size_t)_ast;} - bool null() const {return !_ast;} - }; - - /** Reference counting verison of above */ - class ast : public ast_i { - public: - operator ::ast*() const { return raw(); } - friend bool eq(ast const & a, ast const & b) { return a.raw() == b.raw(); } - - - ast(context &c, ::ast *a = nullptr) : ast_i(c,a) { - if(_ast) - m().inc_ref(a); - } - - ast() {} - - ast(const ast &other) : ast_i(other) { - if(_ast) - m().inc_ref(_ast); - } - - ast &operator=(const ast &other) { - if(_ast) - m().dec_ref(_ast); - _ast = other._ast; - m_ctx = other.m_ctx; - if(_ast) - m().inc_ref(_ast); - return *this; - } - - ~ast(){ - if(_ast) - m().dec_ref(_ast); - } - - void show() const; - - }; - - class sort : public ast { - public: - sort(context & c):ast(c) {} - sort(context & c, ::sort *s):ast(c, s) {} - sort(sort const & s):ast(s) {} - operator ::sort*() const { return to_sort(raw()); } - sort & operator=(sort const & s) { return static_cast(ast::operator=(s)); } - - bool is_bool() const { return m().is_bool(*this); } - bool is_int() const { return ctx().get_sort_kind(*this) == IntSort; } - bool is_real() const { return ctx().get_sort_kind(*this) == RealSort; } - bool is_arith() const; - bool is_array() const { return ctx().get_sort_kind(*this) == ArraySort; } - bool is_datatype() const; - bool is_relation() const; - bool is_finite_domain() const; - - - sort array_domain() const; - sort array_range() const; - - friend std::ostream & operator<<(std::ostream & out, sort const & m){ - m.ctx().print_expr(out,m); - return out; - } - }; - - - class func_decl : public ast { - public: - func_decl() : ast() {} - func_decl(context & c):ast(c) {} - func_decl(context & c, ::func_decl *n):ast(c, n) {} - func_decl(func_decl const & s):ast(s) {} - operator ::func_decl*() const { return to_func_decl(*this); } - func_decl & operator=(func_decl const & s) { return static_cast(ast::operator=(s)); } - - unsigned arity() const; - sort domain(unsigned i) const; - sort range() const; - symbol name() const {return symbol(ctx(),to_func_decl(raw())->get_name());} - decl_kind get_decl_kind() const; - - bool is_const() const { return arity() == 0; } - - expr operator()(unsigned n, expr const * args) const; - expr operator()(const std::vector &args) const; - expr operator()() const; - expr operator()(expr const & a) const; - expr operator()(int a) const; - expr operator()(expr const & a1, expr const & a2) const; - expr operator()(expr const & a1, int a2) const; - expr operator()(int a1, expr const & a2) const; - expr operator()(expr const & a1, expr const & a2, expr const & a3) const; - expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const; - expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5) const; - - func_decl get_func_decl_parameter(unsigned idx){ - return func_decl(ctx(),to_func_decl(to_func_decl(raw())->get_parameters()[idx].get_ast())); - } - - }; - - class expr : public ast { - public: - expr() : ast() {} - expr(context & c):ast(c) {} - expr(context & c, ::ast *n):ast(c, n) {} - expr(expr const & n):ast(n) {} - expr & operator=(expr const & n) { return static_cast(ast::operator=(n)); } - operator ::expr*() const { return to_expr(raw()); } - unsigned get_id() const {return to_expr(raw())->get_id();} - - sort get_sort() const { return sort(ctx(),m().get_sort(to_expr(raw()))); } - - bool is_bool() const { return get_sort().is_bool(); } - bool is_int() const { return get_sort().is_int(); } - bool is_real() const { return get_sort().is_real(); } - bool is_arith() const { return get_sort().is_arith(); } - bool is_array() const { return get_sort().is_array(); } - bool is_datatype() const { return get_sort().is_datatype(); } - bool is_relation() const { return get_sort().is_relation(); } - bool is_finite_domain() const { return get_sort().is_finite_domain(); } - bool is_true() const {return is_app() && decl().get_decl_kind() == True; } - - bool is_numeral() const { - return is_app() && decl().get_decl_kind() == OtherArith && m().is_unique_value(to_expr(raw())); - } - bool is_app() const {return raw()->get_kind() == AST_APP;} - bool is_quantifier() const {return raw()->get_kind() == AST_QUANTIFIER;} - bool is_var() const {return raw()->get_kind() == AST_VAR;} - bool is_label (bool &pos,std::vector &names) const ; - bool is_ground() const {return to_app(raw())->is_ground();} - bool has_quantifiers() const {return to_app(raw())->has_quantifiers();} - bool has_free(int idx) const { - used_vars proc; - proc.process(to_expr(raw())); - return proc.contains(idx); - } - unsigned get_max_var_idx_plus_1() const { - used_vars proc; - proc.process(to_expr(raw())); - return proc.get_max_found_var_idx_plus_1(); - } - - // operator Z3_app() const { assert(is_app()); return reinterpret_cast(m_ast); } - func_decl decl() const {return func_decl(ctx(),to_app(raw())->get_decl());} - unsigned num_args() const { - ast_kind dk = raw()->get_kind(); - switch(dk){ - case AST_APP: - return to_app(raw())->get_num_args(); - case AST_QUANTIFIER: - return 1; - case AST_VAR: - return 0; - default:; - } - SASSERT(0); - return 0; - } - expr arg(unsigned i) const { - ast_kind dk = raw()->get_kind(); - switch(dk){ - case AST_APP: - return ctx().cook(to_app(raw())->get_arg(i)); - case AST_QUANTIFIER: - return ctx().cook(to_quantifier(raw())->get_expr()); - default:; - } - assert(0); - return expr(); - } - - expr body() const { - return ctx().cook(to_quantifier(raw())->get_expr()); - } - - friend expr operator!(expr const & a) { - // ::expr *e = a; - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_NOT,a)); - } - - friend expr operator&&(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_AND,a,b)); - } - - friend expr operator||(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_OR,a,b)); - } - - friend expr implies(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_IMPLIES,a,b)); - } - - friend expr operator==(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_EQ,a,b)); - } - - friend expr operator!=(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_DISTINCT,a,b)); - } - - friend expr operator+(expr const & a, expr const & b) { - return a.ctx().make(Plus,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_ADD,a,b)); - } - - friend expr operator*(expr const & a, expr const & b) { - return a.ctx().make(Times,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_MUL,a,b)); - } - - friend expr operator/(expr const & a, expr const & b) { - return a.ctx().make(Div,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_DIV,a,b)); - } - - friend expr operator-(expr const & a) { - return a.ctx().make(Uminus,a); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_UMINUS,a)); - } - - friend expr operator-(expr const & a, expr const & b) { - return a.ctx().make(Sub,a,b); // expr(a.ctx(),a.m().mk_app(a.ctx().m_arith_fid,OP_SUB,a,b)); - } - - friend expr operator<=(expr const & a, expr const & b) { - return a.ctx().make(Leq,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_LE,a,b)); - } - - friend expr operator>=(expr const & a, expr const & b) { - return a.ctx().make(Geq,a,b); //expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_GE,a,b)); - } - - friend expr operator<(expr const & a, expr const & b) { - return a.ctx().make(Lt,a,b); expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_LT,a,b)); - } - - friend expr operator>(expr const & a, expr const & b) { - return a.ctx().make(Gt,a,b); expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_GT,a,b)); - } - - expr simplify() const; - - expr simplify(params const & p) const; - - expr qe_lite() const; - - expr qe_lite(const std::set &idxs, bool index_of_bound) const; - - friend expr clone_quantifier(const expr &, const expr &); - - friend expr clone_quantifier(const expr &q, const expr &b, const std::vector &patterns); - - friend expr clone_quantifier(decl_kind, const expr &, const expr &); - - friend std::ostream & operator<<(std::ostream & out, expr const & m){ - m.ctx().print_expr(out,m); - return out; - } - - void get_patterns(std::vector &pats) const ; - - unsigned get_quantifier_num_bound() const { - return to_quantifier(raw())->get_num_decls(); - } - - unsigned get_index_value() const { - var* va = to_var(raw()); - return va->get_idx(); - } - - bool is_quantifier_forall() const { - return to_quantifier(raw())->is_forall(); - } - - sort get_quantifier_bound_sort(unsigned n) const { - return sort(ctx(),to_quantifier(raw())->get_decl_sort(n)); - } - - symbol get_quantifier_bound_name(unsigned n) const { - return symbol(ctx(),to_quantifier(raw())->get_decl_names()[n]); - } - - friend expr forall(const std::vector &quants, const expr &body); - - friend expr exists(const std::vector &quants, const expr &body); - - }; - - - typedef ::decl_kind pfrule; - - class proof : public ast { - public: - proof(context & c):ast(c) {} - proof(context & c, ::proof *s):ast(c, s) {} - proof(proof const & s):ast(s) {} - operator ::proof*() const { return to_app(raw()); } - proof & operator=(proof const & s) { return static_cast(ast::operator=(s)); } - - pfrule rule() const { - ::func_decl *d = to_app(raw())->get_decl(); - return d->get_decl_kind(); - } - - unsigned num_prems() const { - return to_app(raw())->get_num_args() - 1; - } - - expr conc() const { - return ctx().cook(to_app(raw())->get_arg(num_prems())); - } - - proof prem(unsigned i) const { - return proof(ctx(),to_app(to_app(raw())->get_arg(i))); - } - - void get_assumptions(std::vector &assumps); - }; - -#if 0 - -#if Z3_MAJOR_VERSION > 4 || Z3_MAJOR_VERSION == 4 && Z3_MINOR_VERSION >= 3 - template - class ast_vector_tpl : public object { - Z3_ast_vector m_vector; - void init(Z3_ast_vector v) { Z3_ast_vector_inc_ref(ctx(), v); m_vector = v; } - public: - ast_vector_tpl(context & c):object(c) { init(Z3_mk_ast_vector(c)); } - ast_vector_tpl(context & c, Z3_ast_vector v):object(c) { init(v); } - ast_vector_tpl(ast_vector_tpl const & s):object(s), m_vector(s.m_vector) { Z3_ast_vector_inc_ref(ctx(), m_vector); } - ~ast_vector_tpl() { /* Z3_ast_vector_dec_ref(ctx(), m_vector); */ } - operator Z3_ast_vector() const { return m_vector; } - unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); } - T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast()(ctx(), r); } - void push_back(T const & e) { Z3_ast_vector_push(ctx(), m_vector, e); check_error(); } - void resize(unsigned sz) { Z3_ast_vector_resize(ctx(), m_vector, sz); check_error(); } - T back() const { return operator[](size() - 1); } - void pop_back() { assert(size() > 0); resize(size() - 1); } - bool empty() const { return size() == 0; } - ast_vector_tpl & operator=(ast_vector_tpl const & s) { - Z3_ast_vector_inc_ref(s.ctx(), s.m_vector); - // Z3_ast_vector_dec_ref(ctx(), m_vector); - m_ctx = s.m_ctx; - m_vector = s.m_vector; - return *this; - } - friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; } - }; - - typedef ast_vector_tpl ast_vector; - typedef ast_vector_tpl expr_vector; - typedef ast_vector_tpl sort_vector; - typedef ast_vector_tpl func_decl_vector; - -#endif - -#endif - - class func_interp : public object { - ::func_interp * m_interp; - void init(::func_interp * e) { - m_interp = e; - } - public: - func_interp(context & c, ::func_interp * e):object(c) { init(e); } - func_interp(func_interp const & s):object(s) { init(s.m_interp); } - ~func_interp() { } - operator ::func_interp *() const { return m_interp; } - func_interp & operator=(func_interp const & s) { - m_ctx = s.m_ctx; - m_interp = s.m_interp; - return *this; - } - unsigned num_entries() const { return m_interp->num_entries(); } - expr get_arg(unsigned ent, unsigned arg) const { - return expr(ctx(),m_interp->get_entry(ent)->get_arg(arg)); - } - expr get_value(unsigned ent) const { - return expr(ctx(),m_interp->get_entry(ent)->get_result()); - } - expr else_value() const { - return expr(ctx(),m_interp->get_else()); - } - }; - - - - class model : public object { - model_ref m_model; - void init(::model *m) { - m_model = m; - } - public: - model(context & c, ::model * m = nullptr):object(c), m_model(m) { } - model(model const & s):object(s), m_model(s.m_model) { } - ~model() { } - operator ::model *() const { return m_model.get(); } - model & operator=(model const & s) { - // ::model *_inc_ref(s.ctx(), s.m_model); - // ::model *_dec_ref(ctx(), m_model); - m_ctx = s.m_ctx; - m_model = s.m_model.get(); - return *this; - } - model & operator=(::model *s) { - m_model = s; - return *this; - } - bool null() const {return !m_model;} - - expr eval(expr const & n, bool model_completion=true) const { - ::model * _m = m_model.get(); - expr_ref result(ctx().m()); - _m->eval(n, result, model_completion); - return expr(ctx(), result); - } - - void show() const; - void show_hash() const; - - unsigned num_consts() const {return m_model.get()->get_num_constants();} - unsigned num_funcs() const {return m_model.get()->get_num_functions();} - func_decl get_const_decl(unsigned i) const {return func_decl(ctx(),m_model.get()->get_constant(i));} - func_decl get_func_decl(unsigned i) const {return func_decl(ctx(),m_model.get()->get_function(i));} - unsigned size() const; - func_decl operator[](unsigned i) const; - - expr get_const_interp(const func_decl & f) const { - return ctx().cook(m_model->get_const_interp(to_func_decl(f.raw()))); - } - - func_interp get_func_interp(const func_decl & f) const { - return func_interp(ctx(),m_model->get_func_interp(to_func_decl(f.raw()))); - } - -#if 0 - friend std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; } -#endif - }; - -#if 0 - class stats : public object { - Z3_stats m_stats; - void init(Z3_stats e) { - m_stats = e; - Z3_stats_inc_ref(ctx(), m_stats); - } - public: - stats(context & c):object(c), m_stats(0) {} - stats(context & c, Z3_stats e):object(c) { init(e); } - stats(stats const & s):object(s) { init(s.m_stats); } - ~stats() { if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); } - operator Z3_stats() const { return m_stats; } - stats & operator=(stats const & s) { - Z3_stats_inc_ref(s.ctx(), s.m_stats); - if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); - m_ctx = s.m_ctx; - m_stats = s.m_stats; - return *this; - } - unsigned size() const { return Z3_stats_size(ctx(), m_stats); } - std::string key(unsigned i) const { Z3_string s = Z3_stats_get_key(ctx(), m_stats, i); check_error(); return s; } - bool is_uint(unsigned i) const { Z3_bool r = Z3_stats_is_uint(ctx(), m_stats, i); check_error(); return r != 0; } - bool is_double(unsigned i) const { Z3_bool r = Z3_stats_is_double(ctx(), m_stats, i); check_error(); return r != 0; } - unsigned uint_value(unsigned i) const { unsigned r = Z3_stats_get_uint_value(ctx(), m_stats, i); check_error(); return r; } - double double_value(unsigned i) const { double r = Z3_stats_get_double_value(ctx(), m_stats, i); check_error(); return r; } - friend std::ostream & operator<<(std::ostream & out, stats const & s) { out << Z3_stats_to_string(s.ctx(), s); return out; } - }; -#endif - - enum check_result { - unsat, sat, unknown - }; - - class fixedpoint : public object { - - public: - void get_rules(std::vector &rules); - void get_assertions(std::vector &rules); - void register_relation(const func_decl &rela); - void add_rule(const expr &clause, const symbol &name); - void assert_cnst(const expr &cnst); - }; - - inline std::ostream & operator<<(std::ostream & out, check_result r) { - if (r == unsat) out << "unsat"; - else if (r == sat) out << "sat"; - else out << "unknown"; - return out; - } - - inline check_result to_check_result(lbool l) { - if (l == l_true) return sat; - else if (l == l_false) return unsat; - return unknown; - } - - class solver : public object { - protected: - ::solver *m_solver; - model the_model; - bool canceled; - proof_gen_mode m_mode; - bool extensional; - public: - solver(context & c, bool extensional = false, bool models = true); - solver(context & c, ::solver *s):object(c),the_model(c) { m_solver = s; canceled = false;} - solver(solver const & s):object(s), the_model(s.the_model) { m_solver = s.m_solver; canceled = false;} - ~solver() { - if(m_solver) - dealloc(m_solver); - } - operator ::solver*() const { return m_solver; } - solver & operator=(solver const & s) { - m_ctx = s.m_ctx; - m_solver = s.m_solver; - the_model = s.the_model; - m_mode = s.m_mode; - return *this; - } - struct cancel_exception {}; - void checkpoint(){ - if(canceled) - throw(cancel_exception()); - } - // void set(params const & p) { Z3_solver_set_params(ctx(), m_solver, p); check_error(); } - void push() { scoped_proof_mode spm(m(),m_mode); m_solver->push(); } - void pop(unsigned n = 1) { scoped_proof_mode spm(m(),m_mode); m_solver->pop(n); } - // void reset() { Z3_solver_reset(ctx(), m_solver); check_error(); } - void add(expr const & e) { scoped_proof_mode spm(m(),m_mode); m_solver->assert_expr(e); } - check_result check() { - scoped_proof_mode spm(m(),m_mode); - checkpoint(); - lbool r = m_solver->check_sat(0,nullptr); - model_ref m; - m_solver->get_model(m); - the_model = m.get(); - return to_check_result(r); - } - check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = nullptr, expr *core = nullptr) { - scoped_proof_mode spm(m(),m_mode); - model old_model(the_model); - check_result res = check(n,assumptions,core_size,core); - if(the_model == nullptr) - the_model = old_model; - return res; - } - check_result check(unsigned n, expr * const assumptions, unsigned *core_size = nullptr, expr *core = nullptr) { - scoped_proof_mode spm(m(),m_mode); - checkpoint(); - std::vector< ::expr *> _assumptions(n); - for (unsigned i = 0; i < n; i++) { - _assumptions[i] = to_expr(assumptions[i]); - } - the_model = nullptr; - lbool r = m_solver->check_sat(n, VEC2PTR(_assumptions)); - - if(core_size && core){ - ptr_vector< ::expr> _core; - m_solver->get_unsat_core(_core); - *core_size = _core.size(); - for(unsigned i = 0; i < *core_size; i++) - core[i] = expr(ctx(),_core[i]); - } - - model_ref m; - m_solver->get_model(m); - the_model = m.get(); - - return to_check_result(r); - } -#if 0 - check_result check(expr_vector assumptions) { - scoped_proof_mode spm(m(),m_mode); - unsigned n = assumptions.size(); - z3array _assumptions(n); - for (unsigned i = 0; i < n; i++) { - check_context(*this, assumptions[i]); - _assumptions[i] = assumptions[i]; - } - Z3_lbool r = Z3_check_assumptions(ctx(), m_solver, n, _assumptions.ptr()); - check_error(); - return to_check_result(r); - } -#endif - model get_model() const { return model(ctx(), the_model); } - // std::string reason_unknown() const { Z3_string r = Z3_solver_get_reason_unknown(ctx(), m_solver); check_error(); return r; } - // stats statistics() const { Z3_stats r = Z3_solver_get_statistics(ctx(), m_solver); check_error(); return stats(ctx(), r); } -#if 0 - expr_vector unsat_core() const { Z3_ast_vector r = Z3_solver_get_unsat_core(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); } - expr_vector assertions() const { Z3_ast_vector r = Z3_solver_get_assertions(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); } -#endif - // expr proof() const { Z3_ast r = Z3_solver_proof(ctx(), m_solver); check_error(); return expr(ctx(), r); } - // friend std::ostream & operator<<(std::ostream & out, solver const & s) { out << Z3_solver_to_string(s.ctx(), s); return out; } - int get_num_decisions(); - - void cancel(){ - scoped_proof_mode spm(m(),m_mode); - canceled = true; - m().limit().cancel(); - } - - unsigned get_scope_level(){ scoped_proof_mode spm(m(),m_mode); return m_solver->get_scope_level();} - - void show(); - void print(const char *filename); - void show_assertion_ids(); - - proof get_proof(){ - scoped_proof_mode spm(m(),m_mode); - return proof(ctx(),m_solver->get_proof()); - } - - bool extensional_array_theory() {return extensional;} - }; - -#if 0 - class goal : public object { - Z3_goal m_goal; - void init(Z3_goal s) { - m_goal = s; - Z3_goal_inc_ref(ctx(), s); - } - public: - goal(context & c, bool models=true, bool unsat_cores=false, bool proofs=false):object(c) { init(Z3_mk_goal(c, models, unsat_cores, proofs)); } - goal(context & c, Z3_goal s):object(c) { init(s); } - goal(goal const & s):object(s) { init(s.m_goal); } - ~goal() { Z3_goal_dec_ref(ctx(), m_goal); } - operator Z3_goal() const { return m_goal; } - goal & operator=(goal const & s) { - Z3_goal_inc_ref(s.ctx(), s.m_goal); - Z3_goal_dec_ref(ctx(), m_goal); - m_ctx = s.m_ctx; - m_goal = s.m_goal; - return *this; - } - void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } - unsigned size() const { return Z3_goal_size(ctx(), m_goal); } - expr operator[](unsigned i) const { Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } - Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } - bool inconsistent() const { return Z3_goal_inconsistent(ctx(), m_goal) != 0; } - unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); } - void reset() { Z3_goal_reset(ctx(), m_goal); } - unsigned num_exprs() const { Z3_goal_num_exprs(ctx(), m_goal); } - bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; } - bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; } - friend std::ostream & operator<<(std::ostream & out, goal const & g) { out << Z3_goal_to_string(g.ctx(), g); return out; } - }; - - class apply_result : public object { - Z3_apply_result m_apply_result; - void init(Z3_apply_result s) { - m_apply_result = s; - Z3_apply_result_inc_ref(ctx(), s); - } - public: - apply_result(context & c, Z3_apply_result s):object(c) { init(s); } - apply_result(apply_result const & s):object(s) { init(s.m_apply_result); } - ~apply_result() { Z3_apply_result_dec_ref(ctx(), m_apply_result); } - operator Z3_apply_result() const { return m_apply_result; } - apply_result & operator=(apply_result const & s) { - Z3_apply_result_inc_ref(s.ctx(), s.m_apply_result); - Z3_apply_result_dec_ref(ctx(), m_apply_result); - m_ctx = s.m_ctx; - m_apply_result = s.m_apply_result; - return *this; - } - unsigned size() const { return Z3_apply_result_get_num_subgoals(ctx(), m_apply_result); } - goal operator[](unsigned i) const { Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); } - goal operator[](int i) const { assert(i >= 0); return this->operator[](static_cast(i)); } - model convert_model(model const & m, unsigned i = 0) const { - check_context(*this, m); - Z3_model new_m = Z3_apply_result_convert_model(ctx(), m_apply_result, i, m); - check_error(); - return model(ctx(), new_m); - } - friend std::ostream & operator<<(std::ostream & out, apply_result const & r) { out << Z3_apply_result_to_string(r.ctx(), r); return out; } - }; - - class tactic : public object { - Z3_tactic m_tactic; - void init(Z3_tactic s) { - m_tactic = s; - Z3_tactic_inc_ref(ctx(), s); - } - public: - tactic(context & c, char const * name):object(c) { Z3_tactic r = Z3_mk_tactic(c, name); check_error(); init(r); } - tactic(context & c, Z3_tactic s):object(c) { init(s); } - tactic(tactic const & s):object(s) { init(s.m_tactic); } - ~tactic() { Z3_tactic_dec_ref(ctx(), m_tactic); } - operator Z3_tactic() const { return m_tactic; } - tactic & operator=(tactic const & s) { - Z3_tactic_inc_ref(s.ctx(), s.m_tactic); - Z3_tactic_dec_ref(ctx(), m_tactic); - m_ctx = s.m_ctx; - m_tactic = s.m_tactic; - return *this; - } - solver mk_solver() const { Z3_solver r = Z3_mk_solver_from_tactic(ctx(), m_tactic); check_error(); return solver(ctx(), r); } - apply_result apply(goal const & g) const { - check_context(*this, g); - Z3_apply_result r = Z3_tactic_apply(ctx(), m_tactic, g); - check_error(); - return apply_result(ctx(), r); - } - apply_result operator()(goal const & g) const { - return apply(g); - } - std::string help() const { char const * r = Z3_tactic_get_help(ctx(), m_tactic); check_error(); return r; } - friend tactic operator&(tactic const & t1, tactic const & t2) { - check_context(t1, t2); - Z3_tactic r = Z3_tactic_and_then(t1.ctx(), t1, t2); - t1.check_error(); - return tactic(t1.ctx(), r); - } - friend tactic operator|(tactic const & t1, tactic const & t2) { - check_context(t1, t2); - Z3_tactic r = Z3_tactic_or_else(t1.ctx(), t1, t2); - t1.check_error(); - return tactic(t1.ctx(), r); - } - friend tactic repeat(tactic const & t, unsigned max=UINT_MAX) { - Z3_tactic r = Z3_tactic_repeat(t.ctx(), t, max); - t.check_error(); - return tactic(t.ctx(), r); - } - friend tactic with(tactic const & t, params const & p) { - Z3_tactic r = Z3_tactic_using_params(t.ctx(), t, p); - t.check_error(); - return tactic(t.ctx(), r); - } - friend tactic try_for(tactic const & t, unsigned ms) { - Z3_tactic r = Z3_tactic_try_for(t.ctx(), t, ms); - t.check_error(); - return tactic(t.ctx(), r); - } - }; - - class probe : public object { - Z3_probe m_probe; - void init(Z3_probe s) { - m_probe = s; - Z3_probe_inc_ref(ctx(), s); - } - public: - probe(context & c, char const * name):object(c) { Z3_probe r = Z3_mk_probe(c, name); check_error(); init(r); } - probe(context & c, double val):object(c) { Z3_probe r = Z3_probe_const(c, val); check_error(); init(r); } - probe(context & c, Z3_probe s):object(c) { init(s); } - probe(probe const & s):object(s) { init(s.m_probe); } - ~probe() { Z3_probe_dec_ref(ctx(), m_probe); } - operator Z3_probe() const { return m_probe; } - probe & operator=(probe const & s) { - Z3_probe_inc_ref(s.ctx(), s.m_probe); - Z3_probe_dec_ref(ctx(), m_probe); - m_ctx = s.m_ctx; - m_probe = s.m_probe; - return *this; - } - double apply(goal const & g) const { double r = Z3_probe_apply(ctx(), m_probe, g); check_error(); return r; } - double operator()(goal const & g) const { return apply(g); } - friend probe operator<=(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_le(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator<=(probe const & p1, double p2) { return p1 <= probe(p1.ctx(), p2); } - friend probe operator<=(double p1, probe const & p2) { return probe(p2.ctx(), p1) <= p2; } - friend probe operator>=(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_ge(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator>=(probe const & p1, double p2) { return p1 >= probe(p1.ctx(), p2); } - friend probe operator>=(double p1, probe const & p2) { return probe(p2.ctx(), p1) >= p2; } - friend probe operator<(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_lt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator<(probe const & p1, double p2) { return p1 < probe(p1.ctx(), p2); } - friend probe operator<(double p1, probe const & p2) { return probe(p2.ctx(), p1) < p2; } - friend probe operator>(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_gt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator>(probe const & p1, double p2) { return p1 > probe(p1.ctx(), p2); } - friend probe operator>(double p1, probe const & p2) { return probe(p2.ctx(), p1) > p2; } - friend probe operator==(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_eq(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator==(probe const & p1, double p2) { return p1 == probe(p1.ctx(), p2); } - friend probe operator==(double p1, probe const & p2) { return probe(p2.ctx(), p1) == p2; } - friend probe operator&&(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_and(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator||(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_or(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator!(probe const & p) { - Z3_probe r = Z3_probe_not(p.ctx(), p); p.check_error(); return probe(p.ctx(), r); - } - }; - - inline tactic fail_if(probe const & p) { - Z3_tactic r = Z3_tactic_fail_if(p.ctx(), p); - p.check_error(); - return tactic(p.ctx(), r); - } - inline tactic when(probe const & p, tactic const & t) { - check_context(p, t); - Z3_tactic r = Z3_tactic_when(t.ctx(), p, t); - t.check_error(); - return tactic(t.ctx(), r); - } - inline tactic cond(probe const & p, tactic const & t1, tactic const & t2) { - check_context(p, t1); check_context(p, t2); - Z3_tactic r = Z3_tactic_cond(t1.ctx(), p, t1, t2); - t1.check_error(); - return tactic(t1.ctx(), r); - } - -#endif - - inline expr context::bool_val(bool b){return b ? make(True) : make(False);} - - inline symbol context::str_symbol(char const * s) { ::symbol r = ::symbol(s); return symbol(*this, r); } - inline symbol context::int_symbol(int n) { ::symbol r = ::symbol(n); return symbol(*this, r); } - - inline sort context::bool_sort() { - ::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT); - return sort(*this, s); - } - inline sort context::int_sort() { - ::sort *s = m().mk_sort(m_arith_fid, INT_SORT); - return sort(*this, s); - } - inline sort context::real_sort() { - ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); - return sort(*this, s); - } - inline sort context::array_sort(const sort & d, const sort & r) { - parameter params[2] = { parameter(d), parameter(to_sort(r)) }; - ::sort * s = m().mk_sort(m_array_fid, ARRAY_SORT, 2, params); - return sort(*this, s); - } - - - inline func_decl context::function(symbol const & name, unsigned arity, sort const * domain, sort const & range) { - std::vector< ::sort *> sv(arity); - for(unsigned i = 0; i < arity; i++) - sv[i] = domain[i]; - ::func_decl* d = m().mk_func_decl(name,arity, VEC2PTR(sv),range); - return func_decl(*this,d); - } - - inline func_decl context::function(char const * name, unsigned arity, sort const * domain, sort const & range) { - return function(str_symbol(name), arity, domain, range); - } - - inline func_decl context::function(char const * name, sort const & domain, sort const & range) { - sort args[1] = { domain }; - return function(name, 1, args, range); - } - - inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & range) { - sort args[2] = { d1, d2 }; - return function(name, 2, args, range); - } - - inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & range) { - sort args[3] = { d1, d2, d3 }; - return function(name, 3, args, range); - } - - inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & range) { - sort args[4] = { d1, d2, d3, d4 }; - return function(name, 4, args, range); - } - - inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range) { - sort args[5] = { d1, d2, d3, d4, d5 }; - return function(name, 5, args, range); - } - - - inline expr context::constant(symbol const & name, sort const & s) { - ::expr *r = m().mk_const(m().mk_const_decl(name, s)); - return expr(*this, r); - } - inline expr context::constant(char const * name, sort const & s) { return constant(str_symbol(name), s); } - inline expr context::bool_const(char const * name) { return constant(name, bool_sort()); } - inline expr context::int_const(char const * name) { return constant(name, int_sort()); } - inline expr context::real_const(char const * name) { return constant(name, real_sort()); } - inline expr context::bv_const(char const * name, unsigned sz) { return constant(name, bv_sort(sz)); } - - inline expr func_decl::operator()(const std::vector &args) const { - return operator()(args.size(), VEC2PTR(args)); - } - inline expr func_decl::operator()() const { - return operator()(0,nullptr); - } - inline expr func_decl::operator()(expr const & a) const { - return operator()(1,&a); - } - inline expr func_decl::operator()(expr const & a1, expr const & a2) const { - expr args[2] = {a1,a2}; - return operator()(2,args); - } - inline expr func_decl::operator()(expr const & a1, expr const & a2, expr const & a3) const { - expr args[3] = {a1,a2,a3}; - return operator()(3,args); - } - inline expr func_decl::operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const { - expr args[4] = {a1,a2,a3,a4}; - return operator()(4,args); - } - inline expr func_decl::operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5) const { - expr args[5] = {a1,a2,a3,a4,a5}; - return operator()(5,args); - } - - - inline expr select(expr const & a, expr const & i) { return a.ctx().make(Select,a,i); } - inline expr store(expr const & a, expr const & i, expr const & v) { return a.ctx().make(Store,a,i,v); } - - inline expr forall(const std::vector &quants, const expr &body){ - return body.ctx().make_quant(Forall,quants,body); - } - - inline expr exists(const std::vector &quants, const expr &body){ - return body.ctx().make_quant(Exists,quants,body); - } - - inline expr context::int_val(int n){ - :: sort *r = m().mk_sort(m_arith_fid, INT_SORT); - return cook(m_arith_util.mk_numeral(rational(n),r)); - } - - - class literals : public object { - }; - - class TermTree { - public: - - TermTree(const expr &_term){ - term = _term; - } - - TermTree(const expr &_term, const std::vector &_children){ - term = _term; - children = _children; - } - - inline expr getTerm(){return term;} - - inline std::vector &getTerms(){return terms;} - - inline std::vector &getChildren(){ - return children; - } - - inline int number(int from){ - for(unsigned i = 0; i < children.size(); i++) - from = children[i]->number(from); - num = from; - return from + 1; - } - - inline int getNumber(){ - return num; - } - - inline void setTerm(const expr &t){term = t;} - - inline void addTerm(const expr &t){terms.push_back(t);} - - inline void setChildren(const std::vector & _children){ - children = _children; - } - - inline void setNumber(int _num){ - num = _num; - } - - ~TermTree(){ - for(unsigned i = 0; i < children.size(); i++) - delete children[i]; - } - - private: - expr term; - std::vector terms; - std::vector children; - int num; - }; - - typedef context interpolating_context; - - class interpolating_solver : public solver { - public: - interpolating_solver(context &ctx, bool models = true) - : solver(ctx, true, models) - { - weak_mode = false; - } - - public: - lbool interpolate(const std::vector &assumptions, - std::vector &interpolants, - model &_model, - literals &lits, - bool incremental - ); - - lbool interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - literals &lits, - bool incremental - ); - - bool read_interpolation_problem(const std::string &file_name, - std::vector &assumptions, - std::vector &theory, - std::string &error_message - ); - - void write_interpolation_problem(const std::string &file_name, - const std::vector &assumptions, - const std::vector &theory - ); - - void AssertInterpolationAxiom(const expr &expr); - void RemoveInterpolationAxiom(const expr &expr); - - void SetWeakInterpolants(bool weak); - void SetPrintToFile(const std::string &file_name); - - const std::vector &GetInterpolationAxioms() {return theory;} - const char *profile(); - - private: - bool weak_mode; - std::string print_filename; - std::vector theory; - }; - - - inline expr context::cook(::expr *a) {return expr(*this,a);} - - inline std::vector context::cook(ptr_vector< ::expr> v) { - std::vector _v(v.size()); - for(unsigned i = 0; i < v.size(); i++) - _v[i] = cook(v[i]); - return _v; - } - - inline ::expr *context::uncook(const expr &a) { - m().inc_ref(a.raw()); - return to_expr(a.raw()); - } - - inline expr context::translate(const expr &e) { - ::expr *f = to_expr(e.raw()); - if(&e.ctx().m() != &m()) // same ast manager -> no translation - throw "ast manager mismatch"; - return cook(f); - } - - inline func_decl context::translate(const func_decl &e) { - ::func_decl *f = to_func_decl(e.raw()); - if(&e.ctx().m() != &m()) // same ast manager -> no translation - throw "ast manager mismatch"; - return func_decl(*this,f); - } - - typedef double clock_t; - clock_t current_time(); - inline void output_time(std::ostream &os, clock_t time){os << time;} - - template class uptr { - public: - X *ptr; - uptr(){ptr = nullptr;} - void set(X *_ptr){ - if(ptr) delete ptr; - ptr = _ptr; - } - X *get(){ return ptr;} - ~uptr(){ - if(ptr) delete ptr; - } - }; - -}; - -// to make Duality::ast hashable -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Duality::ast &s) const { - return s.raw()->get_id(); - } - }; -} - - -// to make Duality::ast usable in ordered collections -namespace std { - template <> - class less { - public: - bool operator()(const Duality::ast &s, const Duality::ast &t) const { - // return s.raw() < t.raw(); - return s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - -// to make Duality::ast usable in ordered collections -namespace std { - template <> - class less { - public: - bool operator()(const Duality::expr &s, const Duality::expr &t) const { - // return s.raw() < t.raw(); - return s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - -// to make Duality::func_decl hashable -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Duality::func_decl &s) const { - return s.raw()->get_id(); - } - }; -} - - -// to make Duality::func_decl usable in ordered collections -namespace std { - template <> - class less { - public: - bool operator()(const Duality::func_decl &s, const Duality::func_decl &t) const { - // return s.raw() < t.raw(); - return s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - -#endif diff --git a/src/interp/CMakeLists.txt b/src/interp/CMakeLists.txt deleted file mode 100644 index c3d8e3d5e..000000000 --- a/src/interp/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -z3_add_component(interp - SOURCES - iz3base.cpp - iz3checker.cpp - iz3interp.cpp - iz3mgr.cpp - iz3pp.cpp - iz3profiling.cpp - iz3proof.cpp - iz3proof_itp.cpp - iz3scopes.cpp - iz3translate.cpp - iz3translate_direct.cpp - COMPONENT_DEPENDENCIES - solver - PYG_FILES - interp_params.pyg -) diff --git a/src/interp/interp_params.pyg b/src/interp/interp_params.pyg deleted file mode 100644 index 3116a18db..000000000 --- a/src/interp/interp_params.pyg +++ /dev/null @@ -1,6 +0,0 @@ -def_module_params('interp', - description='interpolation parameters', - export=True, - params=(('profile', BOOL, False, '(INTERP) profile interpolation'), - ('check', BOOL, False, '(INTERP) check interpolants'), - )) diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp deleted file mode 100644 index 773f328ab..000000000 --- a/src/interp/iz3base.cpp +++ /dev/null @@ -1,372 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3base.cpp - - Abstract: - - Base class for interpolators. Includes an AST manager and a scoping - object as bases. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3base.h" -#include -#include -#include -#include -#include "solver/solver.h" -#include "../smt/smt_solver.h" - - -using namespace stl_ext; - - -iz3base::range &iz3base::ast_range(ast t){ - return ast_ranges_hash[t].rng; -} - -iz3base::range &iz3base::sym_range(symb d){ - return sym_range_hash[d]; -} - -void iz3base::add_frame_range(int frame, ast t){ - range &rng = ast_range(t); - if(!in_range(frame,rng)){ - range_add(frame,rng); - for(int i = 0, n = num_args(t); i < n; ++i) - add_frame_range(frame,arg(t,i)); - if(op(t) == Uninterpreted) - range_add(frame,sym_range(sym(t))); - } -} - -#if 1 -iz3base::range &iz3base::ast_scope(ast t){ - ranges &rngs = ast_ranges_hash[t]; - range &rng = rngs.scp; - if(!rngs.scope_computed){ // not computed yet - rng = range_full(); - for(int i = 0, n = num_args(t); i < n; ++i) - rng = range_glb(rng,ast_scope(arg(t,i))); - if(op(t) == Uninterpreted) - if(parents.empty() || num_args(t) == 0) // in tree mode, all function syms are global - rng = range_glb(rng,sym_range(sym(t))); - rngs.scope_computed = true; - } - return rng; -} -#else -iz3base::range &iz3base::ast_scope(ast t){ - ranges &rngs = ast_ranges_hash[t]; - if(rngs.scope_computed) return rngs.scp; - range rng = range_full(); - for(int i = 0, n = num_args(t); i < n; ++i) - rng = range_glb(rng,ast_scope(arg(t,i))); - if(op(t) == Uninterpreted) - if(parents.empty() || num_args(t) == 0) // in tree mode, all function syms are global - rng = range_glb(rng,sym_range(sym(t))); - rngs = ast_ranges_hash[t]; - rngs.scope_computed = true; - rngs.scp = rng; - return rngs.scp; -} -#endif - -void iz3base::print(const std::string &filename){ - ast t = make(And,cnsts); - std::ofstream f(filename.c_str()); - print_sat_problem(f,t); - f.close(); -} - - -void iz3base::gather_conjuncts_rec(ast n, std::vector &conjuncts, stl_ext::hash_set &memo){ - if(memo.find(n) == memo.end()){ - memo.insert(n); - if(op(n) == And){ - int nargs = num_args(n); - for(int i = 0; i < nargs; i++) - gather_conjuncts_rec(arg(n,i),conjuncts,memo); - } - else - conjuncts.push_back(n); - } -} - -void iz3base::gather_conjuncts(ast n, std::vector &conjuncts){ - hash_set memo; - gather_conjuncts_rec(n,conjuncts,memo); -} - -bool iz3base::is_literal(ast n){ - if(is_not(n))n = arg(n,0); - if(is_true(n) || is_false(n)) return false; - if(op(n) == And) return false; - return true; -} - -iz3base::ast iz3base::simplify_and(std::vector &conjuncts){ - hash_set memo; - for(unsigned i = 0; i < conjuncts.size(); i++){ - if(is_false(conjuncts[i])) - return conjuncts[i]; - if(is_true(conjuncts[i]) || memo.find(conjuncts[i]) != memo.end()){ - std::swap(conjuncts[i],conjuncts.back()); - conjuncts.pop_back(); - } - else if(memo.find(mk_not(conjuncts[i])) != memo.end()) - return mk_false(); // contradiction! - else - memo.insert(conjuncts[i]); - } - if(conjuncts.empty())return mk_true(); - return make(And,conjuncts); -} - -iz3base::ast iz3base::simplify_with_lit_rec(ast n, ast lit, stl_ext::hash_map &memo, int depth){ - if(is_not(n))return mk_not(simplify_with_lit_rec(mk_not(n),lit,memo,depth)); - if(n == lit) return mk_true(); - ast not_lit = mk_not(lit); - if(n == not_lit) return mk_false(); - if(op(n) != And || depth <= 0) return n; - std::pair foo(n,ast()); - std::pair::iterator,bool> bar = memo.insert(foo); - ast &res = bar.first->second; - if(!bar.second) return res; - int nargs = num_args(n); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = simplify_with_lit_rec(arg(n,i),lit,memo,depth-1); - res = simplify_and(args); - return res; -} - -iz3base::ast iz3base::simplify_with_lit(ast n, ast lit){ - hash_map memo; - return simplify_with_lit_rec(n,lit,memo,1); -} - -iz3base::ast iz3base::simplify(ast n){ - if(is_not(n)) return mk_not(simplify(mk_not(n))); - std::pair memo_obj(n,ast()); - std::pair::iterator,bool> memo = simplify_memo.insert(memo_obj); - ast &res = memo.first->second; - if(!memo.second) return res; - switch(op(n)){ - case And: { - std::vector conjuncts; - gather_conjuncts(n,conjuncts); - for(unsigned i = 0; i < conjuncts.size(); i++) - conjuncts[i] = simplify(conjuncts[i]); -#if 0 - for(unsigned i = 0; i < conjuncts.size(); i++) - if(is_literal(conjuncts[i])) - for(unsigned j = 0; j < conjuncts.size(); j++) - if(j != i) - conjuncts[j] = simplify_with_lit(conjuncts[j],conjuncts[i]); -#endif - res = simplify_and(conjuncts); - } - break; - case Equal: { - ast x = arg(n,0); - ast y = arg(n,1); - if(ast_id(x) > ast_id(y)) - std::swap(x,y); - res = make(Equal,x,y); - break; - } - default: - res = n; - } - return res; -} - -void iz3base::initialize(const std::vector &_parts, const std::vector &_parents, const std::vector &_theory){ - cnsts = _parts; - theory = _theory; - for(unsigned i = 0; i < cnsts.size(); i++) - add_frame_range(i, cnsts[i]); - for(unsigned i = 0; i < _theory.size(); i++){ - add_frame_range(SHRT_MIN, _theory[i]); - add_frame_range(SHRT_MAX, _theory[i]); - } - for(unsigned i = 0; i < cnsts.size(); i++) - frame_map[cnsts[i]] = i; - for(unsigned i = 0; i < theory.size(); i++) - frame_map[theory[i]] = INT_MAX; -} - -void iz3base::initialize(const std::vector > &_parts, const std::vector &_parents, const std::vector &_theory){ - cnsts.resize(_parts.size()); - theory = _theory; - for(unsigned i = 0; i < _parts.size(); i++) - for(unsigned j = 0; j < _parts[i].size(); j++){ - cnsts[i] = make(And,_parts[i]); - add_frame_range(i, _parts[i][j]); - frame_map[_parts[i][j]] = i; - } - for(unsigned i = 0; i < _theory.size(); i++){ - add_frame_range(SHRT_MIN, _theory[i]); - add_frame_range(SHRT_MAX, _theory[i]); - frame_map[theory[i]] = INT_MAX; - } -} - -void iz3base::check_interp(const std::vector &itps, std::vector &theory){ -#if 0 - Z3_config config = Z3_mk_config(); - Z3_context vctx = Z3_mk_context(config); - int frames = cnsts.size(); - std::vector foocnsts(cnsts); - for(unsigned i = 0; i < frames; i++) - foocnsts[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),cnsts[i]); - Z3_write_interpolation_problem(ctx,frames,&foocnsts[0],0, "temp_lemma.smt", theory.size(), &theory[0]); - int vframes,*vparents; - Z3_ast *vcnsts; - const char *verror; - bool ok = Z3_read_interpolation_problem(vctx,&vframes,&vcnsts,0,"temp_lemma.smt",&verror); - assert(ok); - std::vector vvcnsts(vframes); - std::copy(vcnsts,vcnsts+vframes,vvcnsts.begin()); - std::vector vitps(itps.size()); - for(unsigned i = 0; i < itps.size(); i++) - vitps[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),itps[i]); - Z3_write_interpolation_problem(ctx,itps.size(),&vitps[0],0,"temp_interp.smt"); - int iframes,*iparents; - Z3_ast *icnsts; - const char *ierror; - ok = Z3_read_interpolation_problem(vctx,&iframes,&icnsts,0,"temp_interp.smt",&ierror); - assert(ok); - const char *error = 0; - bool iok = Z3_check_interpolant(vctx, frames, &vvcnsts[0], parents.size() ? &parents[0] : 0, icnsts, &error); - assert(iok); -#endif -} - -bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &vars){ - - params_ref p; - p.set_bool("proof", true); // this is currently useless - p.set_bool("model", true); - p.set_bool("unsat_core", true); - scoped_ptr sf = mk_smt_solver_factory(); - scoped_ptr< ::solver > solver = (*sf)(m(), p, true, true, true, ::symbol::null); - ::solver &s = *solver.get(); - - for(unsigned i = 0; i < q.size(); i++) - s.assert_expr(to_expr(q[i].raw())); - lbool res = s.check_sat(0,nullptr); - if (m().canceled()) { - throw iz3_exception(Z3_CANCELED_MSG); - } - if(res == l_false){ - ::ast *proof = s.get_proof(); - _proof = cook(proof); - } - else if(vars.size()) { - model_ref _m; - s.get_model(_m); - if (!_m.get()) { - SASSERT(l_undef == res); - throw iz3_exception("interpolation cannot proceed without a model"); - } - for(unsigned i = 0; i < vars.size(); i++){ - expr_ref r(m()); - _m.get()->eval(to_expr(vars[i].raw()),r,true); - vars[i] = cook(r.get()); - } - } - solver = nullptr; - return res != l_false; -} - - -void iz3base::find_children(const stl_ext::hash_set &cnsts_set, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &conjuncts, - std::vector &children, - std::vector &pos_map, - bool merge - ){ - std::vector my_children; - std::vector my_conjuncts; - if(op(tree) == Interp){ // if we've hit an interpolation position... - find_children(cnsts_set,arg(tree,0),cnsts,parents,my_conjuncts,my_children,pos_map,merge); - if(my_conjuncts.empty()) - my_conjuncts.push_back(mk_true()); // need at least one conjunct - int root = cnsts.size() + my_conjuncts.size() - 1; - for(unsigned i = 0; i < my_conjuncts.size(); i++){ - parents.push_back(root); - cnsts.push_back(my_conjuncts[i]); - } - for(unsigned i = 0; i < my_children.size(); i++) - parents[my_children[i]] = root; - children.push_back(root); - pos_map.push_back(root); - } - else { - if(op(tree) == And){ - int nargs = num_args(tree); - for(int i = 0; i < nargs; i++) - find_children(cnsts_set,arg(tree,i),cnsts,parents,my_conjuncts,my_children,pos_map,merge); - } - if(cnsts_set.find(tree) != cnsts_set.end()){ - if(merge && !my_conjuncts.empty()) - my_conjuncts.back() = mk_and(my_conjuncts.back(),tree); - else - my_conjuncts.push_back(tree); - } - for(unsigned i = 0; i < my_children.size(); i++) - children.push_back(my_children[i]); - for(unsigned i = 0; i < my_conjuncts.size(); i++) - conjuncts.push_back(my_conjuncts[i]); - } -} - -void iz3base::to_parents_vec_representation(const std::vector &_cnsts, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &theory, - std::vector &pos_map, - bool merge - ){ - std::vector my_children; - std::vector my_conjuncts; - hash_set cnsts_set; - for(unsigned i = 0; i < _cnsts.size(); i++) - cnsts_set.insert(_cnsts[i]); - ast _tree = (op(tree) != Interp) ? make(Interp,tree) : tree; - find_children(cnsts_set,_tree,cnsts,parents,my_conjuncts,my_children,pos_map,merge); - if(op(tree) != Interp) pos_map.pop_back(); - parents[parents.size()-1] = SHRT_MAX; - - // rest of the constraints are the background theory - - hash_set used_set; - for(unsigned i = 0; i < cnsts.size(); i++) - used_set.insert(cnsts[i]); - for(unsigned i = 0; i < _cnsts.size(); i++) - if(used_set.find(_cnsts[i]) == used_set.end()) - theory.push_back(_cnsts[i]); -} - diff --git a/src/interp/iz3base.h b/src/interp/iz3base.h deleted file mode 100755 index 15f613730..000000000 --- a/src/interp/iz3base.h +++ /dev/null @@ -1,195 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3base.h - - Abstract: - - Base class for interpolators. Includes an AST manager and a scoping - object as bases. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3BASE_H -#define IZ3BASE_H - -#include "interp/iz3mgr.h" -#include "interp/iz3scopes.h" - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(func_decl * const &s) const { - return (size_t) s; - } - }; -} - -/* Base class for interpolators. Includes an AST manager and a scoping - object as bases. */ - -class iz3base : public iz3mgr, public scopes { - - public: - - /** Get the range in which an expression occurs. This is the - smallest subtree containing all occurrences of the - expression. */ - range &ast_range(ast); - - /** Get the scope of an expression. This is the set of tree nodes in - which all of the expression's symbols are in scope. */ - range &ast_scope(ast); - - /** Get the range of a symbol. This is the smallest subtree containing - all occurrences of the symbol. */ - range &sym_range(symb); - - /** Is an expression local (in scope in some frame)? */ - - bool is_local(ast node){ - return !range_is_empty(ast_scope(node)); - } - - /** Simplify an expression */ - - ast simplify(ast); - - /** Constructor */ - - iz3base(ast_manager &_m_manager, - const std::vector &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(_m_manager), scopes(_parents) { - initialize(_cnsts,_parents,_theory); - weak = false; - } - - iz3base(const iz3mgr& other, - const std::vector &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(other), scopes(_parents) { - initialize(_cnsts,_parents,_theory); - weak = false; - } - - iz3base(const iz3mgr& other, - const std::vector > &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(other), scopes(_parents) { - initialize(_cnsts,_parents,_theory); - weak = false; - } - - iz3base(const iz3mgr& other) - : iz3mgr(other), scopes() { - weak = false; - } - - /* Set our options */ - void set_option(const std::string &name, const std::string &value){ - if(name == "weak" && value == "1") weak = true; - } - - /* Are we doing weak interpolants? */ - bool weak_mode(){return weak;} - - /** Print interpolation problem to an SMTLIB format file */ - void print(const std::string &filename); - - /** Check correctness of a solutino to this problem. */ - void check_interp(const std::vector &itps, std::vector &theory); - - /** For convenience -- is this formula SAT? */ - bool is_sat(const std::vector &consts, ast &_proof, std::vector &vars); - - /** Interpolator for clauses, to be implemented */ - virtual void interpolate_clause(std::vector &lits, std::vector &itps){ - throw iz3_exception("no interpolator"); - } - - ast get_proof_check_assump(range &rng){ - std::vector cs(theory); - cs.push_back(cnsts[rng.hi]); - return make(And,cs); - } - - int frame_of_assertion(const ast &ass){ - stl_ext::hash_map::iterator it = frame_map.find(ass); - if(it == frame_map.end()) - throw iz3_exception("unknown assertion"); - return it->second; - } - - - void to_parents_vec_representation(const std::vector &_cnsts, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &theory, - std::vector &pos_map, - bool merge = false - ); - - protected: - std::vector cnsts; - std::vector theory; - - private: - - struct ranges { - range rng; - range scp; - bool scope_computed; - ranges(){scope_computed = false;} - }; - - stl_ext::hash_map sym_range_hash; - stl_ext::hash_map ast_ranges_hash; - stl_ext::hash_map simplify_memo; - stl_ext::hash_map frame_map; // map assertions to frames - - // int frames; // number of frames - - protected: - void add_frame_range(int frame, ast t); - - private: - void initialize(const std::vector &_parts, const std::vector &_parents, const std::vector &_theory); - - void initialize(const std::vector > &_parts, const std::vector &_parents, const std::vector &_theory); - - bool is_literal(ast n); - void gather_conjuncts_rec(ast n, std::vector &conjuncts, stl_ext::hash_set &memo); - void gather_conjuncts(ast n, std::vector &conjuncts); - ast simplify_and(std::vector &conjuncts); - ast simplify_with_lit_rec(ast n, ast lit, stl_ext::hash_map &memo, int depth); - ast simplify_with_lit(ast n, ast lit); - void find_children(const stl_ext::hash_set &cnsts_set, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &conjuncts, - std::vector &children, - std::vector &pos_map, - bool merge - ); - bool weak; - -}; - - - -#endif diff --git a/src/interp/iz3checker.cpp b/src/interp/iz3checker.cpp deleted file mode 100644 index 511342819..000000000 --- a/src/interp/iz3checker.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3checker.cpp - - Abstract: - - check correctness of interpolant - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3base.h" -#include "interp/iz3checker.h" - -#include -#include -#include -#include -#include -#include -#include - - -using namespace stl_ext; - -struct iz3checker : iz3base { - - /* HACK: for tree interpolants, we assume that uninterpreted functions - are global. This is because in the current state of the tree interpolation - code, symbols that appear in sibling sub-trees have to be global, and - we have no way to eliminate such function symbols. When tree interpolation is - fixed, we can tree function symbols the same as constant symbols. */ - - bool is_tree; - - void support(const ast &t, std::set &res, hash_set &memo){ - if(memo.find(t) != memo.end()) return; - memo.insert(t); - - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - support(arg(t,i),res,memo); - - switch(op(t)){ - case Uninterpreted: - if(nargs == 0 || !is_tree) { - std::string name = string_of_symbol(sym(t)); - res.insert(name); - } - break; - case Forall: - case Exists: - support(get_quantifier_body(t),res,memo); - break; - default:; - } - } - - bool check(solver *s, std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &itp, - const std::vector &theory){ - - is_tree = !parents.empty(); - int num = cnsts.size(); - std::vector > children(num); - - for(int i = 0; i < num-1; i++){ - if(parents.size()) - children[parents[i]].push_back(i); - else - children[i+1].push_back(i); - } - - for(int i = 0; i < num; i++){ - s->push(); - for(unsigned j = 0; j < theory.size(); j++) - s->assert_expr(to_expr(theory[j].raw())); - s->assert_expr(to_expr(cnsts[i].raw())); - std::vector &cs = children[i]; - for(unsigned j = 0; j < cs.size(); j++) - s->assert_expr(to_expr(itp[cs[j]].raw())); - if(i != num-1) - s->assert_expr(to_expr(mk_not(itp[i]).raw())); - lbool result = s->check_sat(0,nullptr); - if(result != l_false){ - err << "interpolant " << i << " is incorrect"; - - s->pop(1); - for(unsigned j = 0; j < theory.size(); j++) - s->assert_expr(to_expr(theory[j].raw())); - for(unsigned j = 0; j < cnsts.size(); j++) - if(in_range(j,range_downward(i))) - s->assert_expr(to_expr(cnsts[j].raw())); - if(i != num-1) - s->assert_expr(to_expr(mk_not(itp[i]).raw())); - lbool result = s->check_sat(0,nullptr); - if(result != l_false) - err << "interpolant " << i << " is not implied by its downeard closurn"; - - return false; - } - s->pop(1); - } - - std::vector > supports(num); - for(int i = 0; i < num; i++){ - hash_set memo; - support(cnsts[i],supports[i],memo); - } - for(int i = 0; i < num-1; i++){ - std::vector Bside(num); - for(int j = num-1; j >= 0; j--) - Bside[j] = j != i; - for(int j = num-1; j >= 0; j--) - if(!Bside[j]){ - std::vector &cs = children[i]; - for(unsigned k = 0; k < cs.size(); k++) - Bside[cs[k]] = false; - } - std::set Asup, Bsup,common,Isup,bad; - for(int j = num-1; j >= 0; j--){ - std::set &side = Bside[j] ? Bsup : Asup; - side.insert(supports[j].begin(),supports[j].end()); - } - std::set_intersection(Asup.begin(),Asup.end(),Bsup.begin(),Bsup.end(),std::inserter(common,common.begin())); - { - hash_set tmemo; - for(unsigned j = 0; j < theory.size(); j++) - support(theory[j],common,tmemo); // all theory symbols allowed in interps - } - hash_set memo; - support(itp[i],Isup,memo); - std::set_difference(Isup.begin(),Isup.end(),common.begin(),common.end(),std::inserter(bad,bad.begin())); - if(!bad.empty()){ - err << "bad symbols in interpolant " << i << ":"; - std::copy(bad.begin(),bad.end(),std::ostream_iterator(err,",")); - return false; - } - } - return true; - } - - bool check(solver *s, std::ostream &err, - const std::vector &_cnsts, - const ast &tree, - const std::vector &itp){ - - std::vector pos_map; - - // convert to the parents vector representation - - to_parents_vec_representation(_cnsts, tree, cnsts, parents, theory, pos_map); - - //use the parents vector representation to compute interpolant - return check(s,err,cnsts,parents,itp,theory); - } - - iz3checker(ast_manager &_m) - : iz3base(_m) { - } - - iz3checker(iz3mgr &_m) - : iz3base(_m) { - } - -}; - -template -std::vector to_std_vector(const ::vector &v){ - std::vector _v(v.size()); - for(unsigned i = 0; i < v.size(); i++) - _v[i] = v[i]; - return _v; -} - - -bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - const ::vector &parents, - const ptr_vector &interps, - const ptr_vector &theory) -{ - iz3checker chk(_m_manager); - return chk.check(s,err,chk.cook(cnsts),to_std_vector(parents),chk.cook(interps),chk.cook(theory)); -} - -bool iz3check(iz3mgr &mgr, - solver *s, - std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &interps, - const std::vector &theory) -{ - iz3checker chk(mgr); - return chk.check(s,err,cnsts,parents,interps,theory); -} - -bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &_cnsts, - ast *tree, - const ptr_vector &interps) -{ - iz3checker chk(_m_manager); - return chk.check(s,err,chk.cook(_cnsts),chk.cook(tree),chk.cook(interps)); -} diff --git a/src/interp/iz3checker.h b/src/interp/iz3checker.h deleted file mode 100644 index d89db3011..000000000 --- a/src/interp/iz3checker.h +++ /dev/null @@ -1,49 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3checker.h - - Abstract: - - check correctness of an interpolant - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3_CHECKER_H -#define IZ3_CHECKER_H - -#include "interp/iz3mgr.h" -#include "solver/solver.h" - -bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - const ::vector &parents, - const ptr_vector &interps, - const ptr_vector &theory); - -bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - ast *tree, - const ptr_vector &interps); - -bool iz3check(iz3mgr &mgr, - solver *s, - std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &interps, - const ptr_vector &theory); - -#endif diff --git a/src/interp/iz3exception.h b/src/interp/iz3exception.h deleted file mode 100644 index b3f841565..000000000 --- a/src/interp/iz3exception.h +++ /dev/null @@ -1,28 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - iz3exception.h - -Abstract: - - Base class for exceptions raised by interpolation routines - -Author: - -Notes: - ---*/ -#ifndef _IZ3EXCEPTION_H_ -#define _IZ3EXCEPTION_H_ - -#include "util/z3_exception.h" -#include "util/error_codes.h" - -class iz3_exception: public default_exception { -public: - iz3_exception(const std::string &msg): default_exception(msg) {} -}; - -#endif diff --git a/src/interp/iz3hash.h b/src/interp/iz3hash.h deleted file mode 100644 index f85242ed1..000000000 --- a/src/interp/iz3hash.h +++ /dev/null @@ -1,479 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3hash.h - - Abstract: - - Simple implementation of bucket-list hash tables conforming to SGI - hash_map and hash_set interfaces. Just enough members are - implemented to support iz3 and duality. - - iz3 and duality need this package because they assume that insert - preserves iterators and references to elements, which is not true - of the hashtable packages in util. - - This package lives in namespace hash_space. Specializations of - class "hash" should be made in this namespace. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3_HASH_H -#define IZ3_HASH_H - -#ifdef _WINDOWS -#pragma warning(disable:4267) -#endif - -#include -#include -#include -#include "util/hash.h" - -#define stl_ext hash_space - -namespace hash_space { - - template class hash {}; - - - template <> - class hash { - public: - size_t operator()(const int &s) const { - return s; - } - }; - - template <> - class hash { - public: - size_t operator()(const std::string &s) const { - return string_hash(s.c_str(), s.size(), 0); - } - }; - - template <> - class hash > { - public: - size_t operator()(const std::pair &p) const { - return p.first + p.second; - } - }; - - template - class hash > { - public: - size_t operator()(const std::pair &p) const { - return (size_t)p.first + (size_t)p.second; - } - }; - - enum { num_primes = 29 }; - - static const unsigned long primes[num_primes] = - { - 7ul, - 53ul, - 97ul, - 193ul, - 389ul, - 769ul, - 1543ul, - 3079ul, - 6151ul, - 12289ul, - 24593ul, - 49157ul, - 98317ul, - 196613ul, - 393241ul, - 786433ul, - 1572869ul, - 3145739ul, - 6291469ul, - 12582917ul, - 25165843ul, - 50331653ul, - 100663319ul, - 201326611ul, - 402653189ul, - 805306457ul, - 1610612741ul, - 3221225473ul, - 4294967291ul - }; - - inline unsigned long next_prime(unsigned long n) { - const unsigned long* to = primes + (int)num_primes; - for(const unsigned long* p = primes; p < to; p++) - if(*p >= n) return *p; - return primes[num_primes-1]; - } - - template - class hashtable - { - public: - - typedef Value &reference; - typedef const Value &const_reference; - - struct Entry - { - Entry* next; - Value val; - - Entry(const Value &_val) : val(_val) {next = nullptr;} - }; - - - struct iterator - { - Entry* ent; - hashtable* tab; - - typedef std::forward_iterator_tag iterator_category; - typedef Value value_type; - typedef std::ptrdiff_t difference_type; - typedef size_t size_type; - typedef Value& reference; - typedef Value* pointer; - - iterator(Entry* _ent, hashtable* _tab) : ent(_ent), tab(_tab) { } - - iterator() { } - - Value &operator*() const { return ent->val; } - - Value *operator->() const { return &(operator*()); } - - iterator &operator++() { - Entry *old = ent; - ent = ent->next; - if (!ent) { - size_t bucket = tab->get_bucket(old->val); - while (!ent && ++bucket < tab->buckets.size()) - ent = tab->buckets[bucket]; - } - return *this; - } - - iterator operator++(int) { - iterator tmp = *this; - operator++(); - return tmp; - } - - - bool operator==(const iterator& it) const { - return ent == it.ent; - } - - bool operator!=(const iterator& it) const { - return ent != it.ent; - } - }; - - struct const_iterator - { - const Entry* ent; - const hashtable* tab; - - typedef std::forward_iterator_tag iterator_category; - typedef Value value_type; - typedef std::ptrdiff_t difference_type; - typedef size_t size_type; - typedef const Value& reference; - typedef const Value* pointer; - - const_iterator(const Entry* _ent, const hashtable* _tab) : ent(_ent), tab(_tab) { } - - const_iterator() { } - - const Value &operator*() const { return ent->val; } - - const Value *operator->() const { return &(operator*()); } - - const_iterator &operator++() { - Entry *old = ent; - ent = ent->next; - if (!ent) { - size_t bucket = tab->get_bucket(old->val); - while (!ent && ++bucket < tab->buckets.size()) - ent = tab->buckets[bucket]; - } - return *this; - } - - const_iterator operator++(int) { - const_iterator tmp = *this; - operator++(); - return tmp; - } - - - bool operator==(const const_iterator& it) const { - return ent == it.ent; - } - - bool operator!=(const const_iterator& it) const { - return ent != it.ent; - } - }; - - private: - - typedef std::vector Table; - - Table buckets; - size_t entries; - HashFun hash_fun ; - GetKey get_key; - KeyEqFun key_eq_fun; - - public: - - hashtable(size_t init_size) : buckets(init_size,(Entry *)nullptr) { - entries = 0; - } - - hashtable(const hashtable& other) { - dup(other); - } - - hashtable& operator= (const hashtable& other) { - if (&other != this) - dup(other); - return *this; - } - - ~hashtable() { - clear(); - } - - size_t size() const { - return entries; - } - - bool empty() const { - return size() == 0; - } - - void swap(hashtable& other) { - buckets.swap(other.buckets); - std::swap(entries, other.entries); - } - - iterator begin() { - for (size_t i = 0; i < buckets.size(); ++i) - if (buckets[i]) - return iterator(buckets[i], this); - return end(); - } - - iterator end() { - return iterator(nullptr, this); - } - - const_iterator begin() const { - for (size_t i = 0; i < buckets.size(); ++i) - if (buckets[i]) - return const_iterator(buckets[i], this); - return end(); - } - - const_iterator end() const { - return const_iterator(nullptr, this); - } - - size_t get_bucket(const Value& val, size_t n) const { - return hash_fun(get_key(val)) % n; - } - - size_t get_key_bucket(const Key& key) const { - return hash_fun(key) % buckets.size(); - } - - size_t get_bucket(const Value& val) const { - return get_bucket(val,buckets.size()); - } - - Entry *lookup(const Value& val, bool ins = false) - { - resize(entries + 1); - - size_t n = get_bucket(val); - Entry* from = buckets[n]; - - for (Entry* ent = from; ent; ent = ent->next) - if (key_eq_fun(get_key(ent->val), get_key(val))) - return ent; - - if(!ins) return nullptr; - - Entry* tmp = new Entry(val); - tmp->next = from; - buckets[n] = tmp; - ++entries; - return tmp; - } - - Entry *lookup_key(const Key& key) const - { - size_t n = get_key_bucket(key); - Entry* from = buckets[n]; - - for (Entry* ent = from; ent; ent = ent->next) - if (key_eq_fun(get_key(ent->val), key)) - return ent; - - return nullptr; - } - - const_iterator find(const Key& key) const { - return const_iterator(lookup_key(key),this); - } - - iterator find(const Key& key) { - return iterator(lookup_key(key),this); - } - - std::pair insert(const Value& val){ - size_t old_entries = entries; - Entry *ent = lookup(val,true); - return std::pair(iterator(ent,this),entries > old_entries); - } - - iterator insert(const iterator &it, const Value& val){ - Entry *ent = lookup(val,true); - return iterator(ent,this); - } - - size_t erase(const Key& key) - { - Entry** p = &(buckets[get_key_bucket(key)]); - size_t count = 0; - while(*p){ - Entry *q = *p; - if (key_eq_fun(get_key(q->val), key)) { - ++count; - *p = q->next; - delete q; - } - else - p = &(q->next); - } - entries -= count; - return count; - } - - void resize(size_t new_size) { - const size_t old_n = buckets.size(); - if (new_size <= old_n) return; - const size_t n = next_prime(new_size); - if (n <= old_n) return; - Table tmp(n, (Entry*)nullptr); - for (size_t i = 0; i < old_n; ++i) { - Entry* ent = buckets[i]; - while (ent) { - size_t new_bucket = get_bucket(ent->val, n); - buckets[i] = ent->next; - ent->next = tmp[new_bucket]; - tmp[new_bucket] = ent; - ent = buckets[i]; - } - } - buckets.swap(tmp); - } - - void clear() - { - for (size_t i = 0; i < buckets.size(); ++i) { - for (Entry* ent = buckets[i]; ent != nullptr;) { - Entry* next = ent->next; - delete ent; - ent = next; - } - buckets[i] = nullptr; - } - entries = 0; - } - - void dup(const hashtable& other) - { - buckets.resize(other.buckets.size()); - for (size_t i = 0; i < other.buckets.size(); ++i) { - Entry** to = &buckets[i]; - for (Entry* from = other.buckets[i]; from; from = from->next) - to = &((*to = new Entry(from->val))->next); - } - entries = other.entries; - } - }; - - template - class equal { - public: - bool operator()(const T& x, const T &y) const { - return x == y; - } - }; - - template - class identity { - public: - const T &operator()(const T &x) const { - return x; - } - }; - - template - class proj1 { - public: - const T &operator()(const std::pair &x) const { - return x.first; - } - }; - - template , - class EqFun = equal > - class hash_set - : public hashtable,EqFun> { - - public: - - typedef Element value_type; - - hash_set() - : hashtable,EqFun>(7) {} - }; - - template , - class EqFun = equal > - class hash_map - : public hashtable,Key,HashFun,proj1,EqFun> { - - public: - - hash_map() - : hashtable,Key,HashFun,proj1,EqFun>(7) {} - - Value &operator[](const Key& key) { - std::pair kvp(key,Value()); - return - hashtable,Key,HashFun,proj1,EqFun>:: - lookup(kvp,true)->val.second; - } - }; - -} -#endif diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp deleted file mode 100644 index 41c968bd8..000000000 --- a/src/interp/iz3interp.cpp +++ /dev/null @@ -1,578 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3interp.cpp - - Abstract: - - Interpolation based on proof translation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -/* Copyright 2011 Microsoft Research. */ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include -#include -#include -#include -#include -#include - -#include "interp/iz3profiling.h" -#include "interp/iz3translate.h" -#include "interp/iz3proof.h" -#include "interp/iz3hash.h" -#include "interp/iz3interp.h" - -#include "ast/scoped_proof.h" - - -using namespace stl_ext; - - - -#if 1 - -struct frame_reducer : public iz3mgr { - - int frames; - hash_map frame_map; - std::vector assertions_map; - std::vector orig_parents_copy; - std::vector used_frames; - - - frame_reducer(const iz3mgr &other) - : iz3mgr(other) {} - - void get_proof_assumptions_rec(z3pf proof, hash_set &memo, std::vector &used_frames){ - if(memo.find(proof) != memo.end())return; - memo.insert(proof); - pfrule dk = pr(proof); - if(dk == PR_ASSERTED){ - ast con = conc(proof); - if(frame_map.find(con) != frame_map.end()){ // false for theory facts - int frame = frame_map[con]; - used_frames[frame] = true; - } - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - z3pf arg = prem(proof,i); - get_proof_assumptions_rec(arg,memo,used_frames); - } - } - } - - void get_frames(const std::vector >&z3_preds, - const std::vector &orig_parents, - std::vector >&assertions, - std::vector &parents, - z3pf proof){ - frames = z3_preds.size(); - orig_parents_copy = orig_parents; - for(unsigned i = 0; i < z3_preds.size(); i++) - for(unsigned j = 0; j < z3_preds[i].size(); j++) - frame_map[z3_preds[i][j]] = i; - used_frames.resize(frames); - hash_set memo; - get_proof_assumptions_rec(proof,memo,used_frames); - std::vector assertions_back_map(frames); - - // if multiple children of a tree node are used, we can't delete it - std::vector used_children; - used_children.reserve(frames); - for(int i = 0; i < frames; i++) - used_children.push_back(0); - for(int i = 0; i < frames; i++) - if(orig_parents[i] != SHRT_MAX) - if(used_frames[i] || used_children[i]){ - if(used_children[i] > 1) - used_frames[i] = true; - used_children[orig_parents[i]]++; - } - - for(unsigned i = 0; i < z3_preds.size(); i++) - if(used_frames[i] || i == z3_preds.size() - 1){ - assertions.push_back(z3_preds[i]); - assertions_map.push_back(i); - assertions_back_map[i] = assertions.size() - 1; - } - - if(orig_parents.size()){ - parents.resize(assertions.size()); - for(unsigned i = 0; i < assertions.size(); i++){ - int p = orig_parents[assertions_map[i]]; - while(p != SHRT_MAX && !used_frames[p]) - p = orig_parents[p]; - parents[i] = p == SHRT_MAX ? p : assertions_back_map[p]; - } - } - - // std::cout << "used frames = " << frames << "\n"; - } - - void fix_interpolants(std::vector &interpolants){ - std::vector unfixed = interpolants; - interpolants.resize(frames - 1); - for(int i = 0; i < frames - 1; i++) - interpolants[i] = mk_true(); - for(unsigned i = 0; i < unfixed.size(); i++) - interpolants[assertions_map[i]] = unfixed[i]; - for(int i = 0; i < frames-2; i++){ - int p = orig_parents_copy.size() == 0 ? i+1 : orig_parents_copy[i]; - if(p < frames - 1 && !used_frames[p]) - interpolants[p] = mk_and(interpolants[i],interpolants[p]); - } - } -}; - -#else -struct frame_reducer { - - - - frame_reducer(context _ctx){ - } - - void get_frames(const std::vector &z3_preds, - const std::vector &orig_parents, - std::vector &assertions, - std::vector &parents, - ast proof){ - assertions = z3_preds; - parents = orig_parents; - } - - void fix_interpolants(std::vector &interpolants){ - } -}; - -#endif - - - -template -struct killme { - T *p; - killme(){p = nullptr;} - void set(T *_p) {p = _p;} - ~killme(){ - if(p) - delete p; - } -}; - - -class iz3interp : public iz3base { -public: - - killme sp_killer; - killme tr_killer; - - bool is_linear(std::vector &parents){ - for(int i = 0; i < ((int)parents.size())-1; i++) - if(parents[i] != i+1) - return false; - return true; - } - - void test_secondary(const std::vector &cnsts, - const std::vector &parents, - std::vector &interps - ){ - throw iz3_exception("secondary interpolating prover not supported"); - } - - void proof_to_interpolant(z3pf proof, - const std::vector > &cnsts, - const std::vector &parents, - std::vector &interps, - const std::vector &theory, - interpolation_options_struct *options = nullptr - ){ -#if 0 - test_secondary(cnsts,parents,interps); - return; -#endif - - profiling::timer_start("Interpolation prep"); - - // get rid of frames not used in proof - - std::vector > cnsts_vec; - std::vector parents_vec; - frame_reducer fr(*this); - fr.get_frames(cnsts,parents,cnsts_vec,parents_vec,proof); - - int num = cnsts_vec.size(); - std::vector interps_vec(num-1); - - // if this is really a sequence problem, we can make it easier - if(is_linear(parents_vec)) - parents_vec.clear(); - - // secondary prover no longer supported - iz3secondary *sp = nullptr; - -#define BINARY_INTERPOLATION -#ifndef BINARY_INTERPOLATION - // create a translator - iz3translation *tr = iz3translation::create(*this,sp,cnsts_vec,parents_vec,theory); - tr_killer.set(tr); - - // set the translation options, if needed - if(options) - for(hash_map::iterator it = options->map.begin(), en = options->map.end(); it != en; ++it) - tr->set_option(it->first, it->second); - - // create a proof object to hold the translation - iz3proof pf(tr); - - profiling::timer_stop("Interpolation prep"); - - // translate into an interpolatable proof - profiling::timer_start("Proof translation"); - try { - tr->translate(proof,pf); - } - catch (const char *msg) { - throw interpolation_failure(msg); - } - catch (const iz3translation::unsupported & ex) { - TRACE("iz3", tout << "unsupported " << "\n";); - throw interpolation_error(); - } - catch (const iz3proof::proof_error & ex) { - TRACE("iz3", tout << "proof error " << "\n";); - throw interpolation_error(); - } - profiling::timer_stop("Proof translation"); - - // translate the proof into interpolants - profiling::timer_start("Proof interpolation"); - for(int i = 0; i < num-1; i++){ - interps_vec[i] = pf.interpolate(tr->range_downward(i),tr->weak_mode()); - interps_vec[i] = tr->quantify(interps_vec[i],tr->range_downward(i)); - } - profiling::timer_stop("Proof interpolation"); -#else - iz3base the_base(*this,cnsts_vec,parents_vec,theory); - - profiling::timer_stop("Interpolation prep"); - - for(int i = 0; i < num-1; i++){ - range rng = the_base.range_downward(i); - std::vector > cnsts_vec_vec(2); - for(unsigned j = 0; j < cnsts_vec.size(); j++){ - bool is_A = the_base.in_range(j,rng); - for(unsigned k = 0; k < cnsts_vec[j].size(); k++) - cnsts_vec_vec[is_A ? 0 : 1].push_back(cnsts_vec[j][k]); - } - - killme tr_killer_i; - iz3translation *tr = iz3translation::create(*this,sp,cnsts_vec_vec,std::vector(),theory); - tr_killer_i.set(tr); - - // set the translation options, if needed - if(options) - for(hash_map::iterator it = options->map.begin(), en = options->map.end(); it != en; ++it) - tr->set_option(it->first, it->second); - - // create a proof object to hold the translation - iz3proof pf(tr); - - // translate into an interpolatable proof - profiling::timer_start("Proof translation"); - try { - tr->translate(proof,pf); - } - catch (const char *msg) { - throw interpolation_failure(msg); - } - catch (const iz3translation::unsupported & ex) { - TRACE("iz3", tout << "unsupported " << "\n";); - throw interpolation_error(); - } - catch (const iz3proof::proof_error &) { - TRACE("iz3", tout << "proof error\n";); - throw interpolation_error(); - } - profiling::timer_stop("Proof translation"); - - // translate the proof into interpolants - profiling::timer_start("Proof interpolation"); - interps_vec[i] = pf.interpolate(tr->range_downward(0),tr->weak_mode()); - interps_vec[i] = tr->quantify(interps_vec[i],tr->range_downward(0)); - profiling::timer_stop("Proof interpolation"); - } -#endif - // put back in the removed frames - fr.fix_interpolants(interps_vec); - - interps = interps_vec; - - } - - - void proof_to_interpolant(z3pf proof, - std::vector &cnsts, - const std::vector &parents, - std::vector &interps, - const std::vector &theory, - interpolation_options_struct *options = nullptr - ){ - std::vector > cnsts_vec(cnsts.size()); - for(unsigned i = 0; i < cnsts.size(); i++) - cnsts_vec[i].push_back(cnsts[i]); - proof_to_interpolant(proof,cnsts_vec,parents,interps,theory,options); - } - - // same as above, but represents the tree using an ast - - void proof_to_interpolant(const z3pf &proof, - const std::vector &_cnsts, - const ast &tree, - std::vector &interps, - interpolation_options_struct *options = nullptr - ){ - std::vector pos_map; - - // convert to the parents vector representation - - to_parents_vec_representation(_cnsts, tree, cnsts, parents, theory, pos_map); - - //use the parents vector representation to compute interpolant - proof_to_interpolant(proof,cnsts,parents,interps,theory,options); - - // get the interps for the tree positions - std::vector _interps = interps; - interps.resize(pos_map.size()); - for(unsigned i = 0; i < pos_map.size(); i++){ - unsigned j = pos_map[i]; - interps[i] = j < _interps.size() ? _interps[j] : mk_false(); - } - } - - bool has_interp(hash_map &memo, const ast &t){ - if(memo.find(t) != memo.end()) - return memo[t]; - bool res = false; - if(op(t) == Interp) - res = true; - else if(op(t) == And){ - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - res |= has_interp(memo, arg(t,i)); - } - memo[t] = res; - return res; - } - - void collect_conjuncts(std::vector &cnsts, hash_map &memo, const ast &t){ - if(!has_interp(memo,t)) - cnsts.push_back(t); - else { - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - collect_conjuncts(cnsts, memo, arg(t,i)); - } - } - - void assert_conjuncts(solver &s, std::vector &cnsts, const ast &t){ - hash_map memo; - collect_conjuncts(cnsts,memo,t); - for(unsigned i = 0; i < cnsts.size(); i++) - s.assert_expr(to_expr(cnsts[i].raw())); - } - - void get_proof_assumptions(z3pf proof, std::vector &cnsts, hash_set &memo){ - if(memo.find(proof) != memo.end())return; - memo.insert(proof); - pfrule dk = pr(proof); - if(dk == PR_ASSERTED) - cnsts.push_back(conc(proof)); - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - z3pf arg = prem(proof,i); - get_proof_assumptions(arg,cnsts,memo); - } - } - } - - iz3interp(ast_manager &_m_manager) - : iz3base(_m_manager) {} -}; - - - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options) -{ - iz3interp itp(_m_manager); - if(options) - options->apply(itp); - std::vector _cnsts(cnsts.size()); - std::vector _parents(parents.size()); - std::vector _interps; - std::vector _theory(theory.size()); - for(unsigned i = 0; i < cnsts.size(); i++) - _cnsts[i] = itp.cook(cnsts[i]); - for(unsigned i = 0; i < parents.size(); i++) - _parents[i] = parents[i]; - for(unsigned i = 0; i < theory.size(); i++) - _theory[i] = itp.cook(theory[i]); - iz3mgr::ast _proof = itp.cook(proof); - itp.proof_to_interpolant(_proof,_cnsts,_parents,_interps,_theory,options); - interps.resize(_interps.size()); - for(unsigned i = 0; i < interps.size(); i++) - interps[i] = itp.uncook(_interps[i]); -} - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ::vector > &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options) -{ - iz3interp itp(_m_manager); - if(options) - options->apply(itp); - std::vector > _cnsts(cnsts.size()); - std::vector _parents(parents.size()); - std::vector _interps; - std::vector _theory(theory.size()); - for(unsigned i = 0; i < cnsts.size(); i++) - for(unsigned j = 0; j < cnsts[i].size(); j++) - _cnsts[i].push_back(itp.cook(cnsts[i][j])); - for(unsigned i = 0; i < parents.size(); i++) - _parents[i] = parents[i]; - for(unsigned i = 0; i < theory.size(); i++) - _theory[i] = itp.cook(theory[i]); - iz3mgr::ast _proof = itp.cook(proof); - itp.proof_to_interpolant(_proof,_cnsts,_parents,_interps,_theory,options); - interps.resize(_interps.size()); - for(unsigned i = 0; i < interps.size(); i++) - interps[i] = itp.uncook(_interps[i]); -} - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - ast *tree, - ptr_vector &interps, - interpolation_options_struct * options) -{ - iz3interp itp(_m_manager); - if(options) - options->apply(itp); - std::vector _cnsts(cnsts.size()); - std::vector _interps; - for(unsigned i = 0; i < cnsts.size(); i++) - _cnsts[i] = itp.cook(cnsts[i]); - iz3mgr::ast _proof = itp.cook(proof); - iz3mgr::ast _tree = itp.cook(tree); - - // if consts isn't provided, we can reconstruct it - if(_cnsts.empty()){ - hash_set memo; - itp.get_proof_assumptions(_proof,_cnsts,memo); - } - - itp.proof_to_interpolant(_proof,_cnsts,_tree,_interps,options); - interps.resize(_interps.size()); - for(unsigned i = 0; i < interps.size(); i++) - interps[i] = itp.uncook(_interps[i]); -} - -lbool iz3interpolate(ast_manager &_m_manager, - solver &s, - ast *tree, - ptr_vector &cnsts, - ptr_vector &interps, - model_ref &m, - interpolation_options_struct * options) -{ - iz3interp itp(_m_manager); - if(options) - options->apply(itp); - iz3mgr::ast _tree = itp.cook(tree); - std::vector _cnsts; - itp.assert_conjuncts(s,_cnsts,_tree); - profiling::timer_start("solving"); - lbool res = s.check_sat(0,nullptr); - profiling::timer_stop("solving"); - if(res == l_false){ - ast *proof = s.get_proof(); - iz3mgr::ast _proof = itp.cook(proof); - std::vector _interps; - itp.proof_to_interpolant(_proof,_cnsts,_tree,_interps,options); - interps.resize(_interps.size()); - for(unsigned i = 0; i < interps.size(); i++) - interps[i] = itp.uncook(_interps[i]); - } - else if(m){ - s.get_model(m); - } - cnsts.resize(_cnsts.size()); - for(unsigned i = 0; i < cnsts.size(); i++) - cnsts[i] = itp.uncook(_cnsts[i]); - return res; -} - - - -void interpolation_options_struct::apply(iz3base &b){ - for(stl_ext::hash_map::iterator it = map.begin(), en = map.end(); - it != en; - ++it) - b.set_option((*it).first,(*it).second); -} - -// On linux and mac, unlimit stack space so we get recursion - -#if defined(_WINDOWS) || defined(_CYGWIN) || defined(_MINGW) - -#else - -#include -#include - -class iz3stack_unlimiter { -public: - iz3stack_unlimiter() { - struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY}; - setrlimit(RLIMIT_STACK, &rl); - // nothing to be done if above fails - } -}; - -// initializing this will unlimit stack - -iz3stack_unlimiter the_iz3stack_unlimiter; - -#endif diff --git a/src/interp/iz3interp.h b/src/interp/iz3interp.h deleted file mode 100644 index 909703bed..000000000 --- a/src/interp/iz3interp.h +++ /dev/null @@ -1,123 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3interp.h - - Abstract: - - Interpolation based on proof translation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3_INTERP_H -#define IZ3_INTERP_H - -#include "interp/iz3hash.h" -#include "interp/iz3exception.h" -#include "solver/solver.h" - -class iz3base; - -struct interpolation_options_struct { - stl_ext::hash_map map; -public: - void set(const std::string &name, const std::string &value){ - map[name] = value; - } - void apply(iz3base &b); -}; - -/** This object is thrown if a tree interpolation problem is mal-formed */ -struct iz3_bad_tree: public iz3_exception { - iz3_bad_tree(): iz3_exception("iz3_bad_tree") {} -}; - -/** This object is thrown when iz3 fails due to an incompleteness in - the secondary solver. */ -struct iz3_incompleteness: public iz3_exception { - iz3_incompleteness(): iz3_exception("iz3_incompleteness") {} -}; - -// This is thrown if there is some bug in the -// interpolation procedure -class interpolation_failure : public default_exception { - public: - interpolation_failure(const char *msg) - : default_exception(msg) - { - } -}; - -// This is thrown if we cannot derive an interpolant from a proof -// because it contains unsupported theories or if the proof contains -// errors -class interpolation_error : public default_exception { - public: - interpolation_error() - : default_exception("theory not supported by interpolation or bad proof" ) - { - } -}; - -typedef interpolation_options_struct *interpolation_options; - -/* Compute an interpolant from a proof. This version uses the parents vector - representation, for compatibility with the old API. */ - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options = nullptr); - -/* Same as above, but each constraint is a vector of formulas. */ - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const vector > &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options = nullptr); - -/* Compute an interpolant from a proof. This version uses the ast - representation, for compatibility with the new API. Here, cnsts is - a vector of all the assertions in the proof. This can be - over-approximated by the set of all assertions in the - solver. However, if it is empty it will be reconstructed from the - proof, so it can be considered a hint. */ - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - ast *tree, - ptr_vector &interps, - interpolation_options_struct * options); - - -/* Compute an interpolant from an ast representing an interpolation - problem, if unsat, else return a model (if enabled). Uses the - given solver to produce the proof/model. Also returns a vector - of the constraints in the problem, helpful for checking correctness. -*/ - -lbool iz3interpolate(ast_manager &_m_manager, - solver &s, - ast *tree, - ptr_vector &cnsts, - ptr_vector &interps, - model_ref &m, - interpolation_options_struct * options); - - -#endif diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp deleted file mode 100644 index bb37d7f48..000000000 --- a/src/interp/iz3mgr.cpp +++ /dev/null @@ -1,969 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3mgr.cpp - - Abstract: - - A wrapper around an ast manager, providing convenience methods. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#pragma warning(disable:4805) -#pragma warning(disable:4800) -#endif - -#include "interp/iz3mgr.h" - -#include -#include -#include -#include -#include - -#include "ast/expr_abstract.h" -#include "util/params.h" -#include "ast/used_vars.h" - - -using namespace stl_ext; - - -std::ostream &operator <<(std::ostream &s, const iz3mgr::ast &a){ - return s; -} - - -iz3mgr::ast iz3mgr::make_var(const std::string &name, type ty){ - symbol s = symbol(name.c_str()); - return cook(m().mk_const(m().mk_const_decl(s, ty))); -} - -iz3mgr::ast iz3mgr::make(opr op, int n, raw_ast **args){ - switch(op) { - case True: return mki(m_basic_fid,OP_TRUE,n,args); - case False: return mki(m_basic_fid,OP_FALSE,n,args); - case Equal: return mki(m_basic_fid,OP_EQ,n,args); - case Distinct: return mki(m_basic_fid,OP_DISTINCT,n,args); - case Ite: return mki(m_basic_fid,OP_ITE,n,args); - case And: return mki(m_basic_fid,OP_AND,n,args); - case Or: return mki(m_basic_fid,OP_OR,n,args); - case Iff: return mki(m_basic_fid,OP_IFF,n,args); - case Xor: return mki(m_basic_fid,OP_XOR,n,args); - case Not: return mki(m_basic_fid,OP_NOT,n,args); - case Implies: return mki(m_basic_fid,OP_IMPLIES,n,args); - case Oeq: return mki(m_basic_fid,OP_OEQ,n,args); - case Interp: return mki(m_basic_fid,OP_INTERP,n,args); - case Leq: return mki(m_arith_fid,OP_LE,n,args); - case Geq: return mki(m_arith_fid,OP_GE,n,args); - case Lt: return mki(m_arith_fid,OP_LT,n,args); - case Gt: return mki(m_arith_fid,OP_GT,n,args); - case Plus: return mki(m_arith_fid,OP_ADD,n,args); - case Sub: return mki(m_arith_fid,OP_SUB,n,args); - case Uminus: return mki(m_arith_fid,OP_UMINUS,n,args); - case Times: return mki(m_arith_fid,OP_MUL,n,args); - case Div: return mki(m_arith_fid,OP_DIV,n,args); - case Idiv: return mki(m_arith_fid,OP_IDIV,n,args); - case Rem: return mki(m_arith_fid,OP_REM,n,args); - case Mod: return mki(m_arith_fid,OP_MOD,n,args); - case Power: return mki(m_arith_fid,OP_POWER,n,args); - case ToReal: return mki(m_arith_fid,OP_TO_REAL,n,args); - case ToInt: return mki(m_arith_fid,OP_TO_INT,n,args); - case IsInt: return mki(m_arith_fid,OP_IS_INT,n,args); - case Store: return mki(m_array_fid,OP_STORE,n,args); - case Select: return mki(m_array_fid,OP_SELECT,n,args); - case ConstArray: return mki(m_array_fid,OP_CONST_ARRAY,n,args); - case ArrayDefault: return mki(m_array_fid,OP_ARRAY_DEFAULT,n,args); - case ArrayMap: return mki(m_array_fid,OP_ARRAY_MAP,n,args); - case SetUnion: return mki(m_array_fid,OP_SET_UNION,n,args); - case SetIntersect: return mki(m_array_fid,OP_SET_INTERSECT,n,args); - case SetDifference: return mki(m_array_fid,OP_SET_DIFFERENCE,n,args); - case SetComplement: return mki(m_array_fid,OP_SET_COMPLEMENT,n,args); - case SetSubSet: return mki(m_array_fid,OP_SET_SUBSET,n,args); - case AsArray: return mki(m_array_fid,OP_AS_ARRAY,n,args); - default: - assert(0); - return ast(); - } -} - -iz3mgr::ast iz3mgr::mki(family_id fid, decl_kind dk, int n, raw_ast **args){ - return cook(m().mk_app(fid, dk, 0, nullptr, n, (expr **)args)); -} - -iz3mgr::ast iz3mgr::make(opr op, const std::vector &args){ - static std::vector a(10); - if(a.size() < args.size()) - a.resize(args.size()); - for(unsigned i = 0; i < args.size(); i++) - a[i] = args[i].raw(); - return make(op,args.size(), args.size() ? &a[0] : nullptr); -} - -iz3mgr::ast iz3mgr::make(opr op){ - return make(op,0,nullptr); -} - -iz3mgr::ast iz3mgr::make(opr op, const ast &arg0){ - raw_ast *a = arg0.raw(); - return make(op,1,&a); -} - -iz3mgr::ast iz3mgr::make(opr op, const ast &arg0, const ast &arg1){ - raw_ast *args[2]; - args[0] = arg0.raw(); - args[1] = arg1.raw(); - return make(op,2,args); -} - -iz3mgr::ast iz3mgr::make(opr op, const ast &arg0, const ast &arg1, const ast &arg2){ - raw_ast *args[3]; - args[0] = arg0.raw(); - args[1] = arg1.raw(); - args[2] = arg2.raw(); - return make(op,3,args); -} - -iz3mgr::ast iz3mgr::make(symb sym, int n, raw_ast **args){ - return cook(m().mk_app(sym, n, (expr **) args)); -} - -iz3mgr::ast iz3mgr::make(symb sym, const std::vector &args){ - static std::vector a(10); - if(a.size() < args.size()) - a.resize(args.size()); - for(unsigned i = 0; i < args.size(); i++) - a[i] = args[i].raw(); - return make(sym,args.size(), args.size() ? &a[0] : nullptr); -} - -iz3mgr::ast iz3mgr::make(symb sym){ - return make(sym,0,nullptr); -} - -iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0){ - raw_ast *a = arg0.raw(); - return make(sym,1,&a); -} - -iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0, const ast &arg1){ - raw_ast *args[2]; - args[0] = arg0.raw(); - args[1] = arg1.raw(); - return make(sym,2,args); -} - -iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0, const ast &arg1, const ast &arg2){ - raw_ast *args[3]; - args[0] = arg0.raw(); - args[1] = arg1.raw(); - args[2] = arg2.raw(); - return make(sym,3,args); -} - -iz3mgr::ast iz3mgr::make_quant(opr op, const std::vector &bvs, ast &body){ - if(bvs.size() == 0) return body; - std::vector foo(bvs.size()); - - - std::vector names; - std::vector types; - std::vector bound_asts; - unsigned num_bound = bvs.size(); - - for (unsigned i = 0; i < num_bound; ++i) { - app* a = to_app(bvs[i].raw()); - symbol s(to_app(a)->get_decl()->get_name()); - names.push_back(s); - types.push_back(m().get_sort(a)); - bound_asts.push_back(a); - } - expr_ref abs_body(m()); - expr_abstract(m(), 0, num_bound, &bound_asts[0], to_expr(body.raw()), abs_body); - expr_ref result(m()); - result = m().mk_quantifier( - op == Forall, - names.size(), &types[0], &names[0], abs_body.get(), - 0, - symbol("itp"), - symbol(), - 0, nullptr, - 0, nullptr - ); - return cook(result.get()); -} - -// FIXME replace this with existing Z3 functionality - -iz3mgr::ast iz3mgr::clone(const ast &t, const std::vector &_args){ - if(_args.size() == 0) - return t; - - ast_manager& m = m_manager; - expr* a = to_expr(t.raw()); - static std::vector rargs(10); - if(rargs.size() < _args.size()) - rargs.resize(_args.size()); - for(unsigned i = 0; i < _args.size(); i++) - rargs[i] = _args[i].raw(); - expr* const* args = (expr **)&rargs[0]; - switch(a->get_kind()) { - case AST_APP: { - app* e = to_app(a); - if (e->get_num_args() != _args.size()) { - assert(0); - } - else { - a = m.mk_app(e->get_decl(), _args.size(), args); - } - break; - } - case AST_QUANTIFIER: { - if (_args.size() != 1) { - assert(0); - } - else { - a = m.update_quantifier(to_quantifier(a), args[0]); - } - break; - } - default: - break; - } - return cook(a); -} - - -void iz3mgr::show(ast t){ - if(t.null()){ - std::cout << "(null)" << std::endl; - } - params_ref p; - p.set_bool("flat_assoc",false); - std::cout << mk_pp(t.raw(), m(), p) << std::endl; -} - -void iz3mgr::show_symb(symb s){ - std::cout << mk_pp(s, m()) << std::endl; -} - -void iz3mgr::print_expr(std::ostream &s, const ast &e){ - params_ref p; - p.set_bool("flat_assoc",false); - s << mk_pp(e.raw(), m(), p); -} - - -void iz3mgr::print_clause(std::ostream &s, std::vector &cls){ - s << "("; - for(unsigned i = 0; i < cls.size(); i++){ - if(i > 0) s << ","; - print_expr(s,cls[i]); - } - s << ")"; -} - -void iz3mgr::show_clause(std::vector &cls){ - print_clause(std::cout,cls); - std::cout << std::endl; -} - -void iz3mgr::print_lit(ast lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - int f = op(abslit); - if(f == And || f == Or || f == Iff){ - if(is_not(lit)) std::cout << "~"; - std::cout << "[" << abslit << "]"; - } - else - std::cout << lit; -} - - -static int pretty_cols = 79; -static int pretty_indent_chars = 2; - -static int pretty_find_delim(const std::string &s, int pos){ - int level = 0; - int end = s.size(); - for(; pos < end; pos++){ - int ch = s[pos]; - if(ch == '(')level++; - if(ch == ')')level--; - if(level < 0 || (level == 0 && ch == ','))break; - } - return pos; -} - -static void pretty_newline(std::ostream &f, int indent){ - f << std::endl; - for(int i = 0; i < indent; i++) - f << " "; -} - -void iz3mgr::pretty_print(std::ostream &f, const std::string &s){ - int cur_indent = 0; - int indent = 0; - int col = 0; - int pos = 0; - while(pos < (int)s.size()){ - int delim = pretty_find_delim(s,pos); - if(s[pos] != ')' && s[pos] != ',' && cur_indent > indent){ - pretty_newline(f,indent); - cur_indent = indent; - col = indent; - continue; - } - if (col + delim - pos > pretty_cols) { - if (col > indent) { - pretty_newline(f,indent); - cur_indent = indent; - col = indent; - continue; - } - int paren = s.find('(',pos); - if(paren != (int)std::string::npos){ - int chars = paren - pos + 1; - f << s.substr(pos,chars); - indent += pretty_indent_chars; - if(col) pretty_newline(f,indent); - cur_indent = indent; - pos += chars; - col = indent; - continue; - } - } - int chars = delim - pos + 1; - f << s.substr(pos,chars); - pos += chars; - col += chars; - if(s[delim] == ')') - indent -= pretty_indent_chars; - } -} - - -iz3mgr::opr iz3mgr::op(const ast &t){ - ast_kind dk = t.raw()->get_kind(); - switch(dk){ - case AST_APP: { - expr * e = to_expr(t.raw()); - func_decl *d = to_app(t.raw())->get_decl(); - if (null_family_id == d->get_family_id()) - return Uninterpreted; - // return (opr)d->get_decl_kind(); - if (m_basic_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_TRUE: return True; - case OP_FALSE: return False; - case OP_EQ: return Equal; - case OP_DISTINCT: return Distinct; - case OP_ITE: return Ite; - case OP_AND: return And; - case OP_OR: return Or; - case OP_IFF: return Iff; - case OP_XOR: return Xor; - case OP_NOT: return Not; - case OP_IMPLIES: return Implies; - case OP_OEQ: return Oeq; - case OP_INTERP: return Interp; - default: - return Other; - } - } - if (m_arith_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_LE: return Leq; - case OP_GE: return Geq; - case OP_LT: return Lt; - case OP_GT: return Gt; - case OP_ADD: return Plus; - case OP_SUB: return Sub; - case OP_UMINUS: return Uminus; - case OP_MUL: return Times; - case OP_DIV: return Div; - case OP_IDIV: return Idiv; - case OP_REM: return Rem; - case OP_MOD: return Mod; - case OP_POWER: return Power; - case OP_TO_REAL: return ToReal; - case OP_TO_INT: return ToInt; - case OP_IS_INT: return IsInt; - default: - if (m().is_unique_value(e)) - return Numeral; - return Other; - } - } - if (m_array_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_STORE: return Store; - case OP_SELECT: return Select; - case OP_CONST_ARRAY: return ConstArray; - case OP_ARRAY_DEFAULT: return ArrayDefault; - case OP_ARRAY_MAP: return ArrayMap; - case OP_SET_UNION: return SetUnion; - case OP_SET_INTERSECT: return SetIntersect; - case OP_SET_DIFFERENCE: return SetDifference; - case OP_SET_COMPLEMENT: return SetComplement; - case OP_SET_SUBSET: return SetSubSet; - case OP_AS_ARRAY: return AsArray; - default: - return Other; - } - } - - return Other; - } - - - case AST_QUANTIFIER: - return to_quantifier(t.raw())->is_forall() ? Forall : Exists; - case AST_VAR: - return Variable; - default:; - } - return Other; -} - - -iz3mgr::pfrule iz3mgr::pr(const ast &t){ - func_decl *d = to_app(t.raw())->get_decl(); - assert(m_basic_fid == d->get_family_id()); - return d->get_decl_kind(); -} - -void iz3mgr::print_sat_problem(std::ostream &out, const ast &t){ - ast_smt_pp pp(m()); - pp.set_simplify_implies(false); - pp.display_smt2(out, to_expr(t.raw())); -} - -iz3mgr::ast iz3mgr::z3_simplify(const ast &e){ - ::expr * a = to_expr(e.raw()); - params_ref p; - th_rewriter m_rw(m(), p); - expr_ref result(m()); - m_rw(a, result); - return cook(result); -} - -iz3mgr::ast iz3mgr::z3_really_simplify(const ast &e){ - ::expr * a = to_expr(e.raw()); - params_ref simp_params; - simp_params.set_bool(":som",true); - simp_params.set_bool(":sort-sums",true); - th_rewriter m_rw(m(), simp_params); - expr_ref result(m()); - m_rw(a, result); - return cook(result); -} - - -#if 0 -static rational lcm(const rational &x, const rational &y){ - int a = x.numerator(); - int b = y.numerator(); - return rational(a * b / gcd(a, b)); -} -#endif - -static rational extract_lcd(std::vector &res){ - if(res.size() == 0) return rational(1); // shouldn't happen - rational lcd = denominator(res[0]); - for(unsigned i = 1; i < res.size(); i++) - lcd = lcm(lcd,denominator(res[i])); - for(unsigned i = 0; i < res.size(); i++) - res[i] *= lcd; - return lcd; -} - -void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector& coeffs){ - std::vector rats; - get_farkas_coeffs(proof,rats); - coeffs.resize(rats.size()); - for(unsigned i = 0; i < rats.size(); i++){ - class sort *is = m().mk_sort(m_arith_fid, INT_SORT); - ast coeff = cook(m_arith_util.mk_numeral(rats[i],is)); - coeffs[i] = coeff; - } -} - -static void abs_rat(std::vector &rats){ - // check that they are all non-neg -- if neg, take abs val and warn! - for(unsigned i = 0; i < rats.size(); i++) - if(rats[i].is_neg()){ - // std::cout << "negative Farkas coeff!\n"; - rats[i] = -rats[i]; - } -} - -bool iz3mgr::is_farkas_coefficient_negative(const ast &proof, int n){ - rational r; - symb s = sym(proof); - bool ok = s->get_parameter(n+2).is_rational(r); - if(!ok) - throw iz3_exception("Bad Farkas coefficient"); - return r.is_neg(); -} - -void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-2); -#if 0 - if(num_prems(proof) < numps-2){ - std::cout << "bad farkas rule: " << num_prems(proof) << " premises should be " << numps-2 << "\n"; - } -#endif - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw iz3_exception("Bad Farkas coefficient"); -#if 0 - { - ast con = conc(prem(proof,i-2)); - ast temp = make_real(r); // for debugging - opr o = is_not(con) ? op(arg(con,0)) : op(con); - if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt)) - r = -r; - } -#endif - rats[i-2] = r; - } -#if 0 - if(rats.size() != 0 && rats[0].is_neg()){ - for(unsigned i = 0; i < rats.size(); i++){ - assert(rats[i].is_neg()); - rats[i] = -rats[i]; - } - } -#endif - abs_rat(rats); - extract_lcd(rats); -} - -void iz3mgr::get_broken_gcd_test_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-2); - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw "Bad Farkas coefficient"; - rats[i-2] = r; - } - extract_lcd(rats); -} - -void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector& coeffs){ - std::vector rats; - get_assign_bounds_coeffs(proof,rats); - coeffs.resize(rats.size()); - for(unsigned i = 0; i < rats.size(); i++){ - coeffs[i] = make_int(rats[i]); - } -} - -void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-1); - rats[0] = rational(1); - ast conseq = arg(conc(proof),0); - opr conseq_o = is_not(conseq) ? op(arg(conseq,0)) : op(conseq); - bool conseq_neg = is_not(conseq) ? (conseq_o == Leq || conseq_o == Lt) : (conseq_o == Geq || conseq_o == Gt); - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw iz3_exception("Bad Farkas coefficient"); - { - ast con = arg(conc(proof),i-1); - ast temp = make_real(r); // for debugging - opr o = is_not(con) ? op(arg(con,0)) : op(con); - if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt)) - r = -r; - if(conseq_neg) - r = -r; - } - rats[i-1] = r; - } -#if 0 - if(rats[1].is_neg()){ // work around bug -- if all coeffs negative, negate them - for(unsigned i = 1; i < rats.size(); i++){ - if(!rats[i].is_neg()) - throw iz3_exception("Bad Farkas coefficients"); - rats[i] = -rats[i]; - } - } -#endif - abs_rat(rats); - extract_lcd(rats); -} - -void iz3mgr::get_gomory_cut_coeffs(const ast &proof, std::vector& coeffs){ - std::vector rats; - get_gomory_cut_coeffs(proof,rats); - coeffs.resize(rats.size()); - for(unsigned i = 0; i < rats.size(); i++){ - coeffs[i] = make_int(rats[i]); - } -} - -void iz3mgr::get_gomory_cut_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-2); - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw "Bad Farkas coefficient"; - rats[i-2] = r; - } - abs_rat(rats); - extract_lcd(rats); -} - -void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector& coeffs){ - std::vector rats; - get_assign_bounds_rule_coeffs(proof,rats); - coeffs.resize(rats.size()); - for(unsigned i = 0; i < rats.size(); i++){ - coeffs[i] = make_int(rats[i]); - } -} - -void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-1); - rats[0] = rational(1); - ast conseq = arg(conc(proof),0); - opr conseq_o = is_not(conseq) ? op(arg(conseq,0)) : op(conseq); - bool conseq_neg = is_not(conseq) ? (conseq_o == Leq || conseq_o == Lt) : (conseq_o == Geq || conseq_o == Gt); - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw iz3_exception("Bad Farkas coefficient"); - { - ast con = conc(prem(proof,i-2)); - ast temp = make_real(r); // for debugging - opr o = is_not(con) ? op(arg(con,0)) : op(con); - if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt)) - r = -r; - if(conseq_neg) - r = -r; - } - rats[i-1] = r; - } -#if 0 - if(rats[1].is_neg()){ // work around bug -- if all coeffs negative, negate them - for(unsigned i = 1; i < rats.size(); i++){ - if(!rats[i].is_neg()) - throw iz3_exception("Bad Farkas coefficients"); - rats[i] = -rats[i]; - } - } -#endif - abs_rat(rats); - extract_lcd(rats); -} - -/** Set P to P + cQ, where P and Q are linear inequalities. Assumes P is 0 <= y or 0 < y. */ - -void iz3mgr::linear_comb(ast &P, const ast &c, const ast &Q, bool round_off){ - ast Qrhs; - bool qstrict = false; - if(is_not(Q)){ - ast nQ = arg(Q,0); - switch(op(nQ)){ - case Gt: - Qrhs = make(Sub,arg(nQ,1),arg(nQ,0)); - break; - case Lt: - Qrhs = make(Sub,arg(nQ,0),arg(nQ,1)); - break; - case Geq: - Qrhs = make(Sub,arg(nQ,1),arg(nQ,0)); - qstrict = true; - break; - case Leq: - Qrhs = make(Sub,arg(nQ,0),arg(nQ,1)); - qstrict = true; - break; - default: - throw iz3_exception("not an inequality"); - } - } - else { - switch(op(Q)){ - case Leq: - Qrhs = make(Sub,arg(Q,1),arg(Q,0)); - break; - case Geq: - Qrhs = make(Sub,arg(Q,0),arg(Q,1)); - break; - case Lt: - Qrhs = make(Sub,arg(Q,1),arg(Q,0)); - qstrict = true; - break; - case Gt: - Qrhs = make(Sub,arg(Q,0),arg(Q,1)); - qstrict = true; - break; - default: - throw iz3_exception("not an inequality"); - } - } - bool pstrict = op(P) == Lt; - if (round_off && get_type(Qrhs) != int_type()) - round_off = false; - if(qstrict && round_off && (pstrict || !(c == make_int(rational(1))))){ - Qrhs = make(Sub,Qrhs,make_int(rational(1))); - qstrict = false; - } - Qrhs = make(Times,c,Qrhs); - bool strict = pstrict || qstrict; - if(strict) - P = make(Lt,arg(P,0),make(Plus,arg(P,1),Qrhs)); - else - P = make(Leq,arg(P,0),make(Plus,arg(P,1),Qrhs)); -} - -iz3mgr::ast iz3mgr::sum_inequalities(const std::vector &coeffs, const std::vector &ineqs, bool round_off){ - ast zero = make_int("0"); - ast thing = make(Leq,zero,zero); - for(unsigned i = 0; i < ineqs.size(); i++){ - linear_comb(thing,coeffs[i],ineqs[i], round_off); - } - thing = simplify_ineq(thing); - return thing; -} - -void iz3mgr::mk_idiv(const ast& t, const rational &d, ast &whole, ast &frac){ - opr o = op(t); - if(o == Plus){ - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - mk_idiv(arg(t,i),d,whole,frac); - return; - } - else if(o == Times){ - rational coeff; - if(is_numeral(arg(t,0),coeff)){ - if(gcd(coeff,d) == d){ - whole = make(Plus,whole,make(Times,make_int(coeff/d),arg(t,1))); - return; - } - } - } - frac = make(Plus,frac,t); -} - -iz3mgr::ast iz3mgr::mk_idiv(const ast& q, const rational &d){ - ast t = z3_simplify(q); - if(d == rational(1)) - return t; - else { - ast whole = make_int("0"); - ast frac = whole; - mk_idiv(t,d,whole,frac); - return z3_simplify(make(Plus,whole,make(Idiv,z3_simplify(frac),make_int(d)))); - } -} - -iz3mgr::ast iz3mgr::mk_idiv(const ast& t, const ast &d){ - rational r; - if(is_numeral(d,r)) - return mk_idiv(t,r); - return make(Idiv,t,d); -} - - -// does variable occur in expression? -int iz3mgr::occurs_in1(stl_ext::hash_map &occurs_in_memo,ast var, ast e){ - std::pair foo(e,false); - std::pair::iterator,bool> bar = occurs_in_memo.insert(foo); - bool &res = bar.first->second; - if(bar.second){ - if(e == var) res = true; - int nargs = num_args(e); - for(int i = 0; i < nargs; i++) - res |= occurs_in1(occurs_in_memo,var,arg(e,i)); - } - return res; -} - -int iz3mgr::occurs_in(ast var, ast e){ - hash_map memo; - return occurs_in1(memo,var,e); -} - - -bool iz3mgr::solve_arith(const ast &v, const ast &x, const ast &y, ast &res){ - if(occurs_in(v,y)) - return false; - if(op(x) == Plus){ - int n = num_args(x); - for(int i = 0; i < n; i++){ - if(arg(x,i) == v){ - res = z3_simplify(make(Sub, y, make(Sub, x, v))); - return true; - } - } - } - return false; -} - -// find a controlling equality for a given variable v in a term -// a controlling equality is of the form v = t, which, being -// false would force the formula to have the specifid truth value -// returns t, or null if no such - -iz3mgr::ast iz3mgr::cont_eq(stl_ext::hash_set &cont_eq_memo, bool truth, ast v, ast e){ - if(is_not(e)) return cont_eq(cont_eq_memo, !truth,v,arg(e,0)); - if(cont_eq_memo.find(e) != cont_eq_memo.end()) - return ast(); - cont_eq_memo.insert(e); - if(!truth && op(e) == Equal){ - if(arg(e,0) == v && !occurs_in(v,arg(e,1))) return(arg(e,1)); - if(arg(e,1) == v && !occurs_in(v,arg(e,0))) return(arg(e,0)); - ast res; - if(solve_arith(v,arg(e,0),arg(e,1),res)) return res; - if(solve_arith(v,arg(e,1),arg(e,0),res)) return res; - } - if((!truth && op(e) == And) || (truth && op(e) == Or)){ - int nargs = num_args(e); - for(int i = 0; i < nargs; i++){ - ast res = cont_eq(cont_eq_memo, truth, v, arg(e,i)); - if(!res.null()) return res; - } - } - if(truth && op(e) == Implies){ - ast res = cont_eq(cont_eq_memo, !truth, v, arg(e,0)); - if(!res.null()) return res; - res = cont_eq(cont_eq_memo, truth, v, arg(e,1)); - if(!res.null()) return res; - } - return ast(); -} - -// substitute a term t for unbound occurrences of variable v in e - -iz3mgr::ast iz3mgr::subst(stl_ext::hash_map &subst_memo, ast var, ast t, ast e){ - if(e == var) return t; - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = subst_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - int nargs = num_args(e); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = subst(subst_memo,var,t,arg(e,i)); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else res = clone(e,args); - } - return res; -} - -iz3mgr::ast iz3mgr::subst(ast var, ast t, ast e){ - hash_map memo; - return subst(memo,var,t,e); -} - -iz3mgr::ast iz3mgr::subst(stl_ext::hash_map &subst_memo,ast e){ - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = subst_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - int nargs = num_args(e); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = subst(subst_memo,arg(e,i)); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else res = clone(e,args); - } - return res; -} - -// apply a quantifier to a formula, with some optimizations -// 1) bound variable does not occur -> no quantifier -// 2) bound variable must be equal to some term -> substitute - -iz3mgr::ast iz3mgr::apply_quant(opr quantifier, ast var, ast e){ - if((quantifier == Forall && op(e) == And) - || (quantifier == Exists && op(e) == Or)){ - int n = num_args(e); - std::vector args(n); - for(int i = 0; i < n; i++) - args[i] = apply_quant(quantifier,var,arg(e,i)); - return make(op(e),args); - } - if(!occurs_in(var,e))return e; - hash_set cont_eq_memo; - ast cterm = cont_eq(cont_eq_memo, quantifier == Forall, var, e); - if(!cterm.null()){ - return subst(var,cterm,e); - } - std::vector bvs; bvs.push_back(var); - return make_quant(quantifier,bvs,e); -} - -#if 0 -void iz3mgr::get_bound_substitutes(stl_ext::hash_map &memo, const ast &e, const ast &var, std::vector &substs){ - std::pair foo(e,false); - std::pair::iterator,bool> bar = memo.insert(foo); - if(bar.second){ - if(op(e) == - } - - } -#endif - -unsigned iz3mgr::num_free_variables(const ast &e){ - used_vars uv; - uv(to_expr(e.raw())); - return uv.get_num_vars(); -} - -iz3mgr::ast iz3mgr::close_universally (ast e){ - used_vars uv; - uv(to_expr(e.raw())); - std::vector bvs; - stl_ext::hash_map subst_memo; - for (unsigned i = 0; i < uv.get_max_found_var_idx_plus_1(); i++){ - if (uv.get(i)) { - std::ostringstream os; - os << "%%" << i; - ast c = make_var(os.str(),uv.get(i)); - ast v = cook(m().mk_var(i,uv.get(i))); - subst_memo[v] = c; - bvs.push_back(c); - } - } - e = subst(subst_memo,e); - for (unsigned i = 0; i < bvs.size(); i++) - e = apply_quant(Forall,bvs[i],e); - return e; -} diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h deleted file mode 100644 index 49552f92f..000000000 --- a/src/interp/iz3mgr.h +++ /dev/null @@ -1,738 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3mgr.h - - Abstract: - - A wrapper around an ast manager, providing convenience methods. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3MGR_H -#define IZ3MGR_H - - -#include -#include -#include - -#include "interp/iz3hash.h" -#include "interp/iz3exception.h" - -#include "ast/well_sorted.h" -#include "ast/arith_decl_plugin.h" -#include "ast/bv_decl_plugin.h" -#include "ast/datatype_decl_plugin.h" -#include "ast/array_decl_plugin.h" -#include "ast/ast_translation.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_smt_pp.h" -#include "ast/ast_smt2_pp.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/rewriter/var_subst.h" -#include "ast/expr_substitution.h" -#include "ast/pp.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" - -/* A wrapper around an ast manager, providing convenience methods. */ - -/** Shorthands for some built-in operators. */ - - - -// rename this to keep it accessible, as we use ast for something else -typedef ast raw_ast; - -/** Wrapper around an ast pointer */ -class ast_i { -protected: - raw_ast *_ast; -public: - raw_ast * const &raw() const {return _ast;} - ast_i(raw_ast *a){_ast = a;} - - ast_i(){_ast = nullptr;} - bool eq(const ast_i &other) const { - return _ast == other._ast; - } - bool lt(const ast_i &other) const { - return _ast->get_id() < other._ast->get_id(); - } - friend bool operator==(const ast_i &x, const ast_i&y){ - return x.eq(y); - } - friend bool operator!=(const ast_i &x, const ast_i&y){ - return !x.eq(y); - } - friend bool operator<(const ast_i &x, const ast_i&y){ - return x.lt(y); - } - size_t hash() const {return _ast->get_id();} - bool null() const {return !_ast;} -}; - -/** Reference counting verison of above */ -class ast_r : public ast_i { - ast_manager *_m; -public: - ast_r(ast_manager *m, raw_ast *a) : ast_i(a) { - _m = m; - m->inc_ref(a); - } - - ast_r() {_m = nullptr;} - - ast_r(const ast_r &other) : ast_i(other) { - _m = other._m; - if (_m) _m->inc_ref(_ast); - } - - ast_r &operator=(const ast_r &other) { - if(_ast) - _m->dec_ref(_ast); - _ast = other._ast; - _m = other._m; - if (_m) _m->inc_ref(_ast); - return *this; - } - - ~ast_r() { - if(_ast) - _m->dec_ref(_ast); - } - - ast_manager *mgr() const {return _m;} - -}; - -// to make ast_r hashable -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const ast_r &s) const { - return s.raw()->get_id(); - } - }; -} - - -// to make ast_r usable in ordered collections -namespace std { - template <> - class less { - public: - bool operator()(const ast_r &s, const ast_r &t) const { - // return s.raw() < t.raw(); - return s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - - -/** Wrapper around an AST manager, providing convenience methods. */ - -class iz3mgr { - - public: - typedef ast_r ast; - // typedef decl_kind opr; - typedef func_decl *symb; - typedef sort *type; - typedef ast_r z3pf; - typedef decl_kind pfrule; - - enum opr { - True, - False, - And, - Or, - Not, - Iff, - Ite, - Equal, - Implies, - Distinct, - Xor, - Oeq, - Interp, - Leq, - Geq, - Lt, - Gt, - Plus, - Sub, - Uminus, - Times, - Div, - Idiv, - Rem, - Mod, - Power, - ToReal, - ToInt, - IsInt, - Select, - Store, - ConstArray, - ArrayDefault, - ArrayMap, - SetUnion, - SetIntersect, - SetDifference, - SetComplement, - SetSubSet, - AsArray, - Numeral, - Forall, - Exists, - Variable, - Uninterpreted, - Other - }; - - opr op(const ast &t); - - unsigned ast_id(const ast &x) - { - return to_expr(x.raw())->get_id(); - } - - /** Overloads for constructing ast. */ - - ast make_var(const std::string &name, type ty); - ast make(opr op, const std::vector &args); - ast make(opr op); - ast make(opr op, const ast &arg0); - ast make(opr op, const ast &arg0, const ast &arg1); - ast make(opr op, const ast &arg0, const ast &arg1, const ast &arg2); - ast make(symb sym, const std::vector &args); - ast make(symb sym); - ast make(symb sym, const ast &arg0); - ast make(symb sym, const ast &arg0, const ast &arg1); - ast make(symb sym, const ast &arg0, const ast &arg1, const ast &arg2); - ast make_quant(opr op, const std::vector &bvs, ast &body); - ast clone(const ast &t, const std::vector &args); - - ast_manager &m() {return m_manager;} - - ast cook(raw_ast *a) {return ast(&m_manager,a);} - - std::vector cook(ptr_vector v) { - std::vector _v(v.size()); - for(unsigned i = 0; i < v.size(); i++) - _v[i] = cook(v[i]); - return _v; - } - - raw_ast *uncook(const ast &a) { - m_manager.inc_ref(a.raw()); - return a.raw(); - } - - /** Methods for destructing ast. */ - - - int num_args(const ast& t){ - ast_kind dk = t.raw()->get_kind(); - switch(dk){ - case AST_APP: - return to_app(t.raw())->get_num_args(); - case AST_QUANTIFIER: - return 1; - case AST_VAR: - return 0; - default:; - } - assert(0); - return 0; - } - - ast arg(const ast &t, int i){ - ast_kind dk = t.raw()->get_kind(); - switch(dk){ - case AST_APP: - return cook(to_app(t.raw())->get_arg(i)); - case AST_QUANTIFIER: - return cook(to_quantifier(t.raw())->get_expr()); - default:; - } - assert(0); - return ast(); - } - - void get_args(const ast &t, std::vector &res){ - res.resize(num_args(t)); - for(unsigned i = 0; i < res.size(); i++) - res[i] = arg(t,i); - } - - std::vector args(const ast &t){ - std::vector res; - get_args(t,res); - return res; - } - - symb sym(const ast& t){ - raw_ast *_ast = t.raw(); - return is_app(_ast) ? to_app(_ast)->get_decl() : nullptr; - } - - std::string string_of_symbol(symb s){ - symbol _s = s->get_name(); - if (_s.is_numerical()) { - std::ostringstream buffer; - buffer << _s.get_num(); - return buffer.str(); - } - else { - return _s.bare_str(); - } - } - - type get_type(const ast& t){ - return m().get_sort(to_expr(t.raw())); - } - - std::string string_of_numeral(const ast& t){ - rational r; - expr* e = to_expr(t.raw()); - assert(e); - if (m_arith_util.is_numeral(e, r)) - return r.to_string(); - assert(0); - return "NaN"; - } - - bool is_numeral(const ast& t, rational &r){ - expr* e = to_expr(t.raw()); - assert(e); - return m_arith_util.is_numeral(e, r); - } - - rational get_coeff(const ast& t){ - rational res; - if(op(t) == Times && is_numeral(arg(t,0),res)) - return res; - return rational(1); - } - - ast get_linear_var(const ast& t){ - rational res; - if(op(t) == Times && is_numeral(arg(t,0),res)) - return arg(t,1); - return t; - } - - int get_quantifier_num_bound(const ast &t) { - return to_quantifier(t.raw())->get_num_decls(); - } - - std::string get_quantifier_bound_name(const ast &t, unsigned i) { - return to_quantifier(t.raw())->get_decl_names()[i].bare_str(); - } - - type get_quantifier_bound_type(const ast &t, unsigned i) { - return to_quantifier(t.raw())->get_decl_sort(i); - } - - ast get_quantifier_body(const ast &t) { - return cook(to_quantifier(t.raw())->get_expr()); - } - - unsigned get_variable_index_value(const ast &t) { - var* va = to_var(t.raw()); - return va->get_idx(); - } - - bool is_bool_type(type t){ - family_id fid = to_sort(t)->get_family_id(); - decl_kind k = to_sort(t)->get_decl_kind(); - return fid == m().get_basic_family_id() && k == BOOL_SORT; - } - - bool is_array_type(type t){ - family_id fid = to_sort(t)->get_family_id(); - decl_kind k = to_sort(t)->get_decl_kind(); - return fid == m_array_fid && k == ARRAY_SORT; - } - - type get_range_type(symb s){ - return to_func_decl(s)->get_range(); - } - - int get_num_parameters(const symb &s){ - return to_func_decl(s)->get_num_parameters(); - } - - ast get_ast_parameter(const symb &s, int idx){ - return cook(to_func_decl(s)->get_parameters()[idx].get_ast()); - } - - enum lemma_theory {ArithTheory,ArrayTheory,UnknownTheory}; - - lemma_theory get_theory_lemma_theory(const ast &proof){ - symb s = sym(proof); - ::symbol p0; - bool ok = s->get_parameter(0).is_symbol(p0); - if(!ok) return UnknownTheory; - std::string foo(p0.bare_str()); - if(foo == "arith") - return ArithTheory; - if(foo == "array") - return ArrayTheory; - return UnknownTheory; - } - - enum lemma_kind {FarkasKind,Leq2EqKind,Eq2LeqKind,GCDTestKind,AssignBoundsKind,EqPropagateKind,GomoryCutKind,ArithMysteryKind,UnknownKind}; - - lemma_kind get_theory_lemma_kind(const ast &proof){ - symb s = sym(proof); - if(s->get_num_parameters() < 2) { - return ArithMysteryKind; // Bad -- Z3 hasn't told us - } - ::symbol p0; - bool ok = s->get_parameter(1).is_symbol(p0); - if(!ok) return UnknownKind; - std::string foo(p0.bare_str()); - if(foo == "farkas") - return FarkasKind; - if(foo == "triangle-eq") - return is_not(arg(conc(proof),0)) ? Eq2LeqKind : Leq2EqKind; - if(foo == "gcd-test") - return GCDTestKind; - if(foo == "assign-bounds") - return AssignBoundsKind; - if(foo == "eq-propagate") - return EqPropagateKind; - if(foo == "gomory-cut") - return GomoryCutKind; - return UnknownKind; - } - - void get_farkas_coeffs(const ast &proof, std::vector& coeffs); - - void get_farkas_coeffs(const ast &proof, std::vector& rats); - - void get_broken_gcd_test_coeffs(const ast &proof, std::vector& rats); - - void get_assign_bounds_coeffs(const ast &proof, std::vector& rats); - - void get_assign_bounds_coeffs(const ast &proof, std::vector& rats); - - void get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats); - - void get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats); - - void get_gomory_cut_coeffs(const ast &proof, std::vector& rats); - - void get_gomory_cut_coeffs(const ast &proof, std::vector& rats); - - bool is_farkas_coefficient_negative(const ast &proof, int n); - - bool is_true(const ast& t){ - return op(t) == True; - } - - bool is_false(const ast& t){ - return op(t) == False; - } - - bool is_iff(const ast& t){ - return op(t) == Iff; - } - - bool is_or(const ast& t){ - return op(t) == Or; - } - - bool is_not(const ast& t){ - return op(t) == Not; - } - - /** Simplify an expression using z3 simplifier */ - - ast z3_simplify(const ast& e); - - /** Simplify, sorting sums */ - ast z3_really_simplify(const ast &e); - - - // Some constructors that simplify things - - ast mk_not(const ast& x){ - opr o = op(x); - if(o == True) return make(False); - if(o == False) return make(True); - if(o == Not) return arg(x,0); - return make(Not,x); - } - - ast mk_and(const ast& x, const ast& y){ - opr ox = op(x); - opr oy = op(y); - if(ox == True) return y; - if(oy == True) return x; - if(ox == False) return x; - if(oy == False) return y; - if(x == y) return x; - return make(And,x,y); - } - - ast mk_or(const ast& x, const ast& y){ - opr ox = op(x); - opr oy = op(y); - if(ox == False) return y; - if(oy == False) return x; - if(ox == True) return x; - if(oy == True) return y; - if(x == y) return x; - return make(Or,x,y); - } - - ast mk_implies(const ast& x, const ast& y){ - opr ox = op(x); - opr oy = op(y); - if(ox == True) return y; - if(oy == False) return mk_not(x); - if(ox == False) return mk_true(); - if(oy == True) return y; - if(x == y) return mk_true(); - return make(Implies,x,y); - } - - ast mk_or(const std::vector &x){ - ast res = mk_false(); - for(unsigned i = 0; i < x.size(); i++) - res = mk_or(res,x[i]); - return res; - } - - ast mk_and(const std::vector &x){ - std::vector conjs; - for(unsigned i = 0; i < x.size(); i++){ - const ast &e = x[i]; - opr o = op(e); - if(o == False) - return mk_false(); - if(o != True) - conjs.push_back(e); - } - if(conjs.size() == 0) - return mk_true(); - if(conjs.size() == 1) - return conjs[0]; - return make(And,conjs); - } - - ast mk_equal(const ast& x, const ast& y){ - if(x == y) return make(True); - opr ox = op(x); - opr oy = op(y); - if(ox == True) return y; - if(oy == True) return x; - if(ox == False) return mk_not(y); - if(oy == False) return mk_not(x); - if(ox == False && oy == True) return make(False); - if(oy == False && ox == True) return make(False); - return make(Equal,x,y); - } - - ast z3_ite(const ast& x, const ast& y, const ast& z){ - opr ox = op(x); - opr oy = op(y); - opr oz = op(z); - if(ox == True) return y; - if(ox == False) return z; - if(y == z) return y; - if(oy == True && oz == False) return x; - if(oz == True && oy == False) return mk_not(x); - return make(Ite,x,y,z); - } - - ast make_int(const std::string &s) { - sort *r = m().mk_sort(m_arith_fid, INT_SORT); - return cook(m_arith_util.mk_numeral(rational(s.c_str()),r)); - } - - ast make_int(const rational &s) { - sort *r = m().mk_sort(m_arith_fid, INT_SORT); - return cook(m_arith_util.mk_numeral(s,r)); - } - - ast make_real(const std::string &s) { - sort *r = m().mk_sort(m_arith_fid, REAL_SORT); - return cook(m_arith_util.mk_numeral(rational(s.c_str()),r)); - } - - ast make_real(const rational &s) { - sort *r = m().mk_sort(m_arith_fid, REAL_SORT); - return cook(m_arith_util.mk_numeral(s,r)); - } - - ast mk_false() { return make(False); } - - ast mk_true() { return make(True); } - - ast mk_fresh_constant(char const * prefix, type s){ - return cook(m().mk_fresh_const(prefix, s)); - } - - type bool_type() { - ::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT); - return s; - } - - type int_type() { - ::sort *s = m().mk_sort(m_arith_fid, INT_SORT); - return s; - } - - type real_type() { - ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); - return s; - } - - type array_type(type d, type r) { - parameter params[2] = { parameter(d), parameter(to_sort(r)) }; - ::sort * s = m().mk_sort(m_array_fid, ARRAY_SORT, 2, params); - return s; - } - - symb function(const std::string &str_name, unsigned arity, type *domain, type range) { - ::symbol name = ::symbol(str_name.c_str()); - std::vector< ::sort *> sv(arity); - for(unsigned i = 0; i < arity; i++) - sv[i] = domain[i]; - ::func_decl* d = m().mk_func_decl(name,arity,&sv[0],range); - return d; - } - - void linear_comb(ast &P, const ast &c, const ast &Q, bool round_off = false); - - ast sum_inequalities(const std::vector &coeffs, const std::vector &ineqs, bool round_off = false); - - ast simplify_ineq(const ast &ineq){ - ast res = make(op(ineq),arg(ineq,0),z3_simplify(arg(ineq,1))); - return res; - } - - void mk_idiv(const ast& t, const rational &d, ast &whole, ast &frac); - - ast mk_idiv(const ast& t, const rational &d); - - ast mk_idiv(const ast& t, const ast &d); - - /** methods for destructing proof terms */ - - pfrule pr(const z3pf &t); - - int num_prems(const z3pf &t){return to_app(t.raw())->get_num_args()-1;} - - z3pf prem(const z3pf &t, int n){return arg(t,n);} - - z3pf conc(const z3pf &t){return arg(t,num_prems(t));} - - - /* quantifier handling */ - - // substitute a term t for unbound occurrences of variable v in e - - ast subst(ast var, ast t, ast e); - - // apply a substitution defined by a map - ast subst(stl_ext::hash_map &map, ast e); - - // apply a quantifier to a formula, with some optimizations - // 1) bound variable does not occur -> no quantifier - // 2) bound variable must be equal to some term -> substitute - - ast apply_quant(opr quantifier, ast var, ast e); - - // Universally quantify all the free variables in a formula. - // Makes up names for the quntifiers. - - ast close_universally (ast e); - - unsigned num_free_variables(const ast &e); - - /** For debugging */ - void show(ast); - - void show_symb(symb s); - - /** Constructor */ - - void print_lit(ast lit); - - void print_expr(std::ostream &s, const ast &e); - - void print_clause(std::ostream &s, std::vector &cls); - - void print_sat_problem(std::ostream &out, const ast &t); - - void show_clause(std::vector &cls); - - static void pretty_print(std::ostream &f, const std::string &s); - - iz3mgr(ast_manager &_m_manager) - : m_manager(_m_manager), - m_arith_util(_m_manager) - { - m_basic_fid = m().get_basic_family_id(); - m_arith_fid = m().mk_family_id("arith"); - m_bv_fid = m().mk_family_id("bv"); - m_array_fid = m().mk_family_id("array"); - m_dt_fid = m().mk_family_id("datatype"); - m_datalog_fid = m().mk_family_id("datalog_relation"); - } - - iz3mgr(const iz3mgr& other) - : m_manager(other.m_manager), - m_arith_util(other.m_manager) - { - m_basic_fid = m().get_basic_family_id(); - m_arith_fid = m().mk_family_id("arith"); - m_bv_fid = m().mk_family_id("bv"); - m_array_fid = m().mk_family_id("array"); - m_dt_fid = m().mk_family_id("datatype"); - m_datalog_fid = m().mk_family_id("datalog_relation"); - } - - protected: - ast_manager &m_manager; - int occurs_in(ast var, ast e); - - private: - ast mki(family_id fid, decl_kind sk, int n, raw_ast **args); - ast make(opr op, int n, raw_ast **args); - ast make(symb sym, int n, raw_ast **args); - int occurs_in1(stl_ext::hash_map &occurs_in_memo, ast var, ast e); - bool solve_arith(const ast &v, const ast &x, const ast &y, ast &res); - ast cont_eq(stl_ext::hash_set &cont_eq_memo, bool truth, ast v, ast e); - ast subst(stl_ext::hash_map &subst_memo, ast var, ast t, ast e); - - - family_id m_basic_fid; - family_id m_array_fid; - family_id m_arith_fid; - family_id m_bv_fid; - family_id m_dt_fid; - family_id m_datalog_fid; - arith_util m_arith_util; -}; - -#endif - diff --git a/src/interp/iz3pp.cpp b/src/interp/iz3pp.cpp deleted file mode 100644 index 787fa4ec7..000000000 --- a/src/interp/iz3pp.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - iz3pp.cpp - - Abstract: - - Pretty-print interpolation problems - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -/* Copyright 2011 Microsoft Research. */ -#include -#include -#include -#include -#include -#include -#include - -#include "interp/iz3mgr.h" -#include "interp/iz3pp.h" -#include "ast/func_decl_dependencies.h" -#include "ast/for_each_expr.h" -#include "ast/ast_smt_pp.h" -#include "ast/ast_smt2_pp.h" -#include "ast/expr_functors.h" -#include "ast/expr_abstract.h" - - -using namespace stl_ext; - -// We promise not to use this for hash_map with range destructor -namespace stl_ext { - template <> - class hash { - public: - size_t operator()(const expr *p) const { - return (size_t) p; - } - }; -} - - -// TBD: algebraic data-types declarations will not be printed. -class free_func_visitor { - ast_manager& m; - func_decl_set m_funcs; - obj_hashtable m_sorts; -public: - free_func_visitor(ast_manager& m): m(m) {} - void operator()(var * n) { } - void operator()(app * n) { - m_funcs.insert(n->get_decl()); - class sort* s = m.get_sort(n); - if (s->get_family_id() == null_family_id) { - m_sorts.insert(s); - } - } - void operator()(quantifier * n) { } - func_decl_set& funcs() { return m_funcs; } - obj_hashtable& sorts() { return m_sorts; } -}; - -class iz3pp_helper : public iz3mgr { -public: - - void print_tree(const ast &tree, hash_map &cnames, std::ostream &out){ - hash_map::iterator foo = cnames.find(to_expr(tree.raw())); - if(foo != cnames.end()){ - symbol nm = foo->second; - if (is_smt2_quoted_symbol(nm)) { - out << mk_smt2_quoted_symbol(nm); - } - else { - out << nm; - } - } - else if(op(tree) == And){ - out << "(and"; - int nargs = num_args(tree); - for(int i = 0; i < nargs; i++){ - out << " "; - print_tree(arg(tree,i), cnames, out); - } - out << ")"; - } - else if(op(tree) == Interp){ - out << "(interp "; - print_tree(arg(tree,0), cnames, out); - out << ")"; - } - else throw iz3pp_bad_tree(); - } - - - iz3pp_helper(ast_manager &_m_manager) - : iz3mgr(_m_manager) {} -}; - -void iz3pp(ast_manager &m, - const ptr_vector &cnsts_vec, - expr *tree, - std::ostream& out) { - - unsigned sz = cnsts_vec.size(); - expr* const* cnsts = &cnsts_vec[0]; - - out << "(set-option :produce-interpolants true)\n"; - - free_func_visitor visitor(m); - expr_mark visited; - bool print_low_level = true; // m_params.print_low_level_smt2(); - -#define PP(_e_) if (print_low_level) out << mk_smt_pp(_e_, m); else ast_smt2_pp(out, _e_, env); - - smt2_pp_environment_dbg env(m); - - for (unsigned i = 0; i < sz; ++i) { - expr* e = cnsts[i]; - for_each_expr(visitor, visited, e); - } - - // name all the constraints - hash_map cnames; - int ctr = 1; - for(unsigned i = 0; i < sz; i++){ - symbol nm; - std::ostringstream s; - s << "f!" << (ctr++); - cnames[cnsts[i]] = symbol(s.str().c_str()); - } - - func_decl_set &funcs = visitor.funcs(); - func_decl_set::iterator it = funcs.begin(), end = funcs.end(); - - obj_hashtable& sorts = visitor.sorts(); - obj_hashtable::iterator sit = sorts.begin(), send = sorts.end(); - - - - for (; sit != send; ++sit) { - PP(*sit); - } - - for (; it != end; ++it) { - func_decl* f = *it; - if(f->get_family_id() == null_family_id){ - PP(f); - out << "\n"; - } - } - - for (unsigned i = 0; i < sz; ++i) { - out << "(assert "; - expr* r = cnsts[i]; - symbol nm = cnames[r]; - out << "(! "; - PP(r); - out << " :named "; - if (is_smt2_quoted_symbol(nm)) { - out << mk_smt2_quoted_symbol(nm); - } - else { - out << nm; - } - out << ")"; - out << ")\n"; - } - out << "(check-sat)\n"; - out << "(get-interpolant "; - iz3pp_helper pp(m); - pp.print_tree(pp.cook(tree),cnames,out); - out << ")\n"; -} - - diff --git a/src/interp/iz3pp.h b/src/interp/iz3pp.h deleted file mode 100644 index 7b3405f9b..000000000 --- a/src/interp/iz3pp.h +++ /dev/null @@ -1,36 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - iz3pp.cpp - - Abstract: - - Pretty-print interpolation problems - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3_PP_H -#define IZ3_PP_H - -#include "interp/iz3mgr.h" - -/** Exception thrown in case of mal-formed tree interpoloation - specification */ - -struct iz3pp_bad_tree: public iz3_exception { - iz3pp_bad_tree(): iz3_exception("iz3pp_bad_tree") {} -}; - -void iz3pp(ast_manager &m, - const ptr_vector &cnsts_vec, - expr *tree, - std::ostream& out); -#endif diff --git a/src/interp/iz3profiling.cpp b/src/interp/iz3profiling.cpp deleted file mode 100644 index ba4fd0206..000000000 --- a/src/interp/iz3profiling.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3profiling.h - - Abstract: - - Some routines for measuring performance. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3profiling.h" - -#include -#include -#include -#include -#include -#include "util/stopwatch.h" - - -// FIXME fill in these stubs - -#define clock_t double - -static double current_time() -{ - static stopwatch sw; - static bool started = false; - if(!started){ - sw.start(); - started = true; - } - return sw.get_current_seconds(); -} - -static void output_time(std::ostream &os, clock_t time){ - os << time; -} - - -namespace profiling { - - void show_time(){ - output_time(std::cout,current_time()); - std::cout << "\n"; - } - - typedef std::map nmap; - - struct node { - std::string name; - clock_t time; - clock_t start_time; - nmap sub; - struct node *parent; - - node(); - } top; - - node::node(){ - time = 0; - parent = nullptr; - } - - struct node *current; - - struct init { - init(){ - top.name = "TOTAL"; - current = ⊤ - } - } initializer; - - struct time_entry { - clock_t t; - time_entry(){t = 0;}; - void add(clock_t incr){t += incr;} - }; - - struct ltstr - { - bool operator()(const char* s1, const char* s2) const - { - return strcmp(s1, s2) < 0; - } - }; - - typedef std::map tmap; - - static std::ostream *pfs; - - void print_node(node &top, int indent, tmap &totals){ - for(int i = 0; i < indent; i++) (*pfs) << " "; - (*pfs) << top.name; - int dots = 70 - 2 * indent - top.name.size(); - for(int i = 0; i second,indent+1,totals); - } - - void print(std::ostream &os) { - pfs = &os; - top.time = 0; - for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++) - top.time += it->second.time; - tmap totals; - print_node(top,0,totals); - (*pfs) << "TOTALS:" << std::endl; - for(tmap::iterator it = totals.begin(); it != totals.end(); it++){ - (*pfs) << (it->first) << " "; - output_time(*pfs, it->second.t); - (*pfs) << std::endl; - } - } - - void timer_start(const char *name){ - node &child = current->sub[name]; - if(child.name.empty()){ // a new node - child.parent = current; - child.name = name; - } - child.start_time = current_time(); - current = &child; - } - - void timer_stop(const char *name){ - if(current->name != name || !current->parent){ - std::cerr << "imbalanced timer_start and timer_stop"; - exit(1); - } - current->time += (current_time() - current->start_time); - current = current->parent; - } -} diff --git a/src/interp/iz3profiling.h b/src/interp/iz3profiling.h deleted file mode 100755 index 6b9b07f25..000000000 --- a/src/interp/iz3profiling.h +++ /dev/null @@ -1,37 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3profiling.h - - Abstract: - - Some routines for measuring performance. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3PROFILING_H -#define IZ3PROFILING_H - -#include - -namespace profiling { - /** Start a timer with given name */ - void timer_start(const char *); - /** Stop a timer with given name */ - void timer_stop(const char *); - /** Print out timings */ - void print(std::ostream &s); - /** Show the current time. */ - void show_time(); -} - -#endif - diff --git a/src/interp/iz3proof.cpp b/src/interp/iz3proof.cpp deleted file mode 100755 index bc046ceff..000000000 --- a/src/interp/iz3proof.cpp +++ /dev/null @@ -1,628 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3proof.cpp - - Abstract: - - This class defines a simple interpolating proof system. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3proof.h" -#include "interp/iz3profiling.h" - -#include -#include -#include -#include - -// #define FACTOR_INTERPS -// #define CHECK_PROOFS - - -void iz3proof::resolve(ast pivot, std::vector &cls1, const std::vector &cls2){ -#ifdef CHECK_PROOFS - std::vector orig_cls1 = cls1; -#endif - ast neg_pivot = pv->mk_not(pivot); - bool found_pivot1 = false, found_pivot2 = false; - for(unsigned i = 0; i < cls1.size(); i++){ - if(cls1[i] == neg_pivot){ - cls1[i] = cls1.back(); - cls1.pop_back(); - found_pivot1 = true; - break; - } - } - { - std::set memo; - memo.insert(cls1.begin(),cls1.end()); - for(unsigned j = 0; j < cls2.size(); j++){ - if(cls2[j] == pivot) - found_pivot2 = true; - else - if(memo.find(cls2[j]) == memo.end()) - cls1.push_back(cls2[j]); - } - } - if(found_pivot1 && found_pivot2) - return; - -#ifdef CHECK_PROOFS - std::cerr << "resolution anomaly: " << nodes.size()-1 << "\n"; -#if 0 - std::cerr << "pivot: "; {pv->print_lit(pivot); std::cout << "\n";} - std::cerr << "left clause:\n"; - for(unsigned i = 0; i < orig_cls1.size(); i++) - {pv->print_lit(orig_cls1[i]); std::cout << "\n";} - std::cerr << "right clause:\n"; - for(unsigned i = 0; i < cls2.size(); i++) - {pv->print_lit(cls2[i]); std::cout << "\n";} - throw proof_error(); -#endif -#endif -} - -iz3proof::node iz3proof::make_resolution(ast pivot, node premise1, node premise2) -{ - if(nodes[premise1].rl == Hypothesis) return premise2; // resolve with hyp is noop - if(nodes[premise2].rl == Hypothesis) return premise1; - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Resolution; - n.aux = pivot; - n.premises.resize(2); - n.premises[0] = (premise1); - n.premises[1] = (premise2); -#ifdef CHECK_PROOFS - n.conclusion = nodes[premise1].conclusion; - resolve(pivot,n.conclusion,nodes[premise2].conclusion); - n.frame = 1; -#else - n.frame = 0; // compute conclusion lazily -#endif - return res; -} - -iz3proof::node iz3proof::resolve_lemmas(ast pivot, node premise1, node premise2) -{ - std::vector lits(nodes[premise1].conclusion), itp; // no interpolant - resolve(pivot,lits,nodes[premise2].conclusion); - return make_lemma(lits,itp); -} - - -iz3proof::node iz3proof::make_assumption(int frame, const std::vector &assumption){ -#if 0 - std::cout << "assumption: \n"; - for(unsigned i = 0; i < assumption.size(); i++) - pv->show(assumption[i]); - std::cout << "\n"; -#endif - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Assumption; - n.conclusion.resize(1); - n.conclusion = assumption; - n.frame = frame; - return res; -} - -iz3proof::node iz3proof::make_hypothesis(ast hypothesis){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Hypothesis; - n.conclusion.resize(2); - n.conclusion[0] = hypothesis; - n.conclusion[1] = pv->mk_not(hypothesis); - return res; -} - -iz3proof::node iz3proof::make_theory(const std::vector &conclusion, std::vector premises){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Theory; - n.conclusion = conclusion; - n.premises = premises; - return res; -} - -iz3proof::node iz3proof::make_axiom(const std::vector &conclusion){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Axiom; - n.conclusion = conclusion; - return res; -} - -iz3proof::node iz3proof::make_contra(node prem, const std::vector &conclusion){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Contra; - n.conclusion = conclusion; -#ifdef CHECK_PROOFS - //if(!(conclusion == nodes[prem].conclusion)){ - //std::cerr << "internal error: proof error\n"; - //assert(0 && "proof error"); - //} -#endif - n.premises.push_back(prem); - return res; -} - - -iz3proof::node iz3proof::make_lemma(const std::vector &conclusion, const std::vector &interpolation){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Lemma; - n.conclusion = conclusion; - n.frame = interps.size(); - interps.push_back(interpolation); - return res; -} - -/** Make a Reflexivity node. This rule produces |- x = x */ - -iz3proof::node iz3proof::make_reflexivity(ast con){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Reflexivity; - n.conclusion.push_back(con); - return res; -} - -/** Make a Symmetry node. This takes a derivation of |- x = y and - produces | y = x */ - -iz3proof::node iz3proof::make_symmetry(ast con, node prem){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Reflexivity; - n.conclusion.push_back(con); - n.premises.push_back(prem); - return res; -} - -/** Make a transitivity node. This takes derivations of |- x = y - and |- y = z produces | x = z */ - -iz3proof::node iz3proof::make_transitivity(ast con, node prem1, node prem2){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Transitivity; - n.conclusion.push_back(con); - n.premises.push_back(prem1); - n.premises.push_back(prem2); - return res; -} - - -/** Make a congruence node. This takes derivations of |- x_i = y_i - and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */ - -iz3proof::node iz3proof::make_congruence(ast con, const std::vector &prems){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Congruence; - n.conclusion.push_back(con); - n.premises = prems; - return res; -} - - -/** Make an equality contradicition node. This takes |- x = y - and |- !(x = y) and produces false. */ - -iz3proof::node iz3proof::make_eqcontra(node prem1, node prem2){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = EqContra; - n.premises.push_back(prem1); - n.premises.push_back(prem2); - return res; -} - -iz3proof::node iz3proof::copy_rec(stl_ext::hash_map &memo, iz3proof &src, node n){ - stl_ext::hash_map::iterator it = memo.find(n); - if(it != memo.end()) return (*it).second; - node_struct &ns = src.nodes[n]; - std::vector prems(ns.premises.size()); - for(unsigned i = 0; i < prems.size(); i++) - prems[i] = copy_rec(memo,src,ns.premises[i]); - nodes.push_back(ns); - nodes.back().premises.swap(prems); - if(ns.rl == Lemma){ - nodes.back().frame = interps.size(); - interps.push_back(src.interps[ns.frame]); - } - int res = nodes.size()-1; - memo[n] = res; - return res; -} - -iz3proof::node iz3proof::copy(iz3proof &src, node n){ - stl_ext::hash_map memo; - return copy_rec(memo, src, n); -} - -bool iz3proof::pred_in_A(ast id){ - return weak - ? pv->ranges_intersect(pv->ast_range(id),rng) : - pv->range_contained(pv->ast_range(id),rng); -} - -bool iz3proof::term_in_B(ast id){ - prover::range r = pv->ast_scope(id); - if(weak) { - if(pv->range_min(r) == SHRT_MIN) - return !pv->range_contained(r,rng); - else - return !pv->ranges_intersect(r,rng); - } - else - return !pv->range_contained(r,rng); -} - -bool iz3proof::frame_in_A(int frame){ - return pv->in_range(frame,rng); -} - -bool iz3proof::lit_in_B(ast lit){ - return - b_lits.find(lit) != b_lits.end() - || b_lits.find(pv->mk_not(lit)) != b_lits.end(); -} - -iz3proof::ast iz3proof::my_or(ast x, ast y){ - return pv->mk_not(pv->mk_and(pv->mk_not(x),pv->mk_not(y))); -} - -iz3proof::ast iz3proof::get_A_lits(std::vector &cls){ - ast foo = pv->mk_false(); - for(unsigned i = 0; i < cls.size(); i++){ - ast lit = cls[i]; - if(b_lits.find(pv->mk_not(lit)) == b_lits.end()){ - if(pv->range_max(pv->ast_scope(lit)) == pv->range_min(pv->ast_scope(lit))){ - std::cout << "bad lit: " << pv->range_max(rng) << " : " << pv->range_max(pv->ast_scope(lit)) << " : " << (pv->ast_id(lit)) << " : "; - pv->show(lit); - } - foo = my_or(foo,lit); - } - } - return foo; -} - -iz3proof::ast iz3proof::get_B_lits(std::vector &cls){ - ast foo = pv->mk_false(); - for(unsigned i = 0; i < cls.size(); i++){ - ast lit = cls[i]; - if(b_lits.find(pv->mk_not(lit)) != b_lits.end()) - foo = my_or(foo,lit); - } - return foo; -} - -void iz3proof::set_of_B_lits(std::vector &cls, std::set &res){ - for(unsigned i = 0; i < cls.size(); i++){ - ast lit = cls[i]; - if(b_lits.find(pv->mk_not(lit)) != b_lits.end()) - res.insert(lit); - } -} - -void iz3proof::set_of_A_lits(std::vector &cls, std::set &res){ - for(unsigned i = 0; i < cls.size(); i++){ - ast lit = cls[i]; - if(b_lits.find(pv->mk_not(lit)) == b_lits.end()) - res.insert(lit); - } -} - -void iz3proof::find_B_lits(){ - b_lits.clear(); - for(unsigned i = 0; i < nodes.size(); i++){ - node_struct &n = nodes[i]; - std::vector &cls = n.conclusion; - if(n.rl == Assumption){ - if(weak) goto lemma; - if(!frame_in_A(n.frame)) - for(unsigned j = 0; j < cls.size(); j++) - b_lits.insert(cls[j]); - } - else if(n.rl == Lemma) { - lemma: - for(unsigned j = 0; j < cls.size(); j++) - if(term_in_B(cls[j])) - b_lits.insert(cls[j]); - } - } -} - -iz3proof::ast iz3proof::disj_of_set(std::set &s){ - ast res = pv->mk_false(); - for(std::set::iterator it = s.begin(), en = s.end(); it != en; ++it) - res = my_or(*it,res); - return res; -} - -void iz3proof::mk_and_factor(int p1, int p2, int i, std::vector &itps, std::vector > &disjs){ -#ifdef FACTOR_INTERPS - std::set &d1 = disjs[p1]; - std::set &d2 = disjs[p2]; - if(!weak){ - if(pv->is_true(itps[p1])){ - itps[i] = itps[p2]; - disjs[i] = disjs[p2]; - } - else if(pv->is_true(itps[p2])){ - itps[i] = itps[p1]; - disjs[i] = disjs[p1]; - } - else { - std::set p1only,p2only; - std::insert_iterator > p1o(p1only,p1only.begin()); - std::insert_iterator > p2o(p2only,p2only.begin()); - std::insert_iterator > dio(disjs[i],disjs[i].begin()); - std::set_difference(d1.begin(),d1.end(),d2.begin(),d2.end(),p1o); - std::set_difference(d2.begin(),d2.end(),d1.begin(),d1.end(),p2o); - std::set_intersection(d1.begin(),d1.end(),d2.begin(),d2.end(),dio); - ast p1i = my_or(itps[p1],disj_of_set(p1only)); - ast p2i = my_or(itps[p2],disj_of_set(p2only)); - itps[i] = pv->mk_and(p1i,p2i); - } - } - else { - itps[i] = pv->mk_and(itps[p1],itps[p2]); - std::insert_iterator > dio(disjs[i],disjs[i].begin()); - std::set_union(d1.begin(),d1.end(),d2.begin(),d2.end(),dio); - } -#endif -} - -void iz3proof::mk_or_factor(int p1, int p2, int i, std::vector &itps, std::vector > &disjs){ -#ifdef FACTOR_INTERPS - std::set &d1 = disjs[p1]; - std::set &d2 = disjs[p2]; - if(weak){ - if(pv->is_false(itps[p1])){ - itps[i] = itps[p2]; - disjs[i] = disjs[p2]; - } - else if(pv->is_false(itps[p2])){ - itps[i] = itps[p1]; - disjs[i] = disjs[p1]; - } - else { - std::set p1only,p2only; - std::insert_iterator > p1o(p1only,p1only.begin()); - std::insert_iterator > p2o(p2only,p2only.begin()); - std::insert_iterator > dio(disjs[i],disjs[i].begin()); - std::set_difference(d1.begin(),d1.end(),d2.begin(),d2.end(),p1o); - std::set_difference(d2.begin(),d2.end(),d1.begin(),d1.end(),p2o); - std::set_intersection(d1.begin(),d1.end(),d2.begin(),d2.end(),dio); - ast p1i = pv->mk_and(itps[p1],pv->mk_not(disj_of_set(p1only))); - ast p2i = pv->mk_and(itps[p2],pv->mk_not(disj_of_set(p2only))); - itps[i] = my_or(p1i,p2i); - } - } - else { - itps[i] = my_or(itps[p1],itps[p2]); - std::insert_iterator > dio(disjs[i],disjs[i].begin()); - std::set_union(d1.begin(),d1.end(),d2.begin(),d2.end(),dio); - } -#endif -} - -void iz3proof::interpolate_lemma(node_struct &n){ - if(interps[n.frame].size()) - return; // already computed - pv->interpolate_clause(n.conclusion,interps[n.frame]); -} - -iz3proof::ast iz3proof::interpolate(const prover::range &_rng, bool _weak -#ifdef CHECK_PROOFS - , ast assump - , std::vector *parents -#endif - ){ - // std::cout << "proof size: " << nodes.size() << "\n"; - rng = _rng; - weak = _weak; -#ifdef CHECK_PROOFS - if(nodes[nodes.size()-1].conclusion.size() != 0) - std::cerr << "internal error: proof conclusion is not empty clause\n"; - if(!child_interps.size()){ - child_interps.resize(nodes.size()); - for(unsigned j = 0; j < nodes.size(); j++) - child_interps[j] = pv->mk_true(); - } -#endif - std::vector itps(nodes.size()); -#ifdef FACTOR_INTERPS - std::vector > disjs(nodes.size()); -#endif - profiling::timer_start("Blits"); - find_B_lits(); - profiling::timer_stop("Blits"); - profiling::timer_start("interp_proof"); - // strengthen(); - for(unsigned i = 0; i < nodes.size(); i++){ - node_struct &n = nodes[i]; - ast &q = itps[i]; - switch(n.rl){ - case Assumption: { - - if(frame_in_A(n.frame)){ - /* HypC-A */ - if(!weak) -#ifdef FACTOR_INTERPS - { - q = pv->mk_false(); - set_of_B_lits(n.conclusion,disjs[i]); - } -#else - q = get_B_lits(n.conclusion); -#endif - else - q = pv->mk_false(); - } - else { - /* HypEq-B */ - if(!weak) - q = pv->mk_true(); - else -#ifdef FACTOR_INTERPS - { - q = pv->mk_true(); - set_of_A_lits(n.conclusion,disjs[i]); - } -#else - q = pv->mk_not(get_A_lits(n.conclusion)); -#endif - } - break; - } - case Resolution: { - ast p = n.aux; - p = pv->is_not(p) ? pv->mk_not(p) : p; // should be positive, but just in case - if(lit_in_B(p)) -#ifdef FACTOR_INTERPS - mk_and_factor(n.premises[0],n.premises[1],i,itps,disjs); -#else - q = pv->mk_and(itps[n.premises[0]],itps[n.premises[1]]); -#endif - else -#ifdef FACTOR_INTERPS - mk_or_factor(n.premises[0],n.premises[1],i,itps,disjs); -#else - q = my_or(itps[n.premises[0]],itps[n.premises[1]]); -#endif - break; - } - case Lemma: { - interpolate_lemma(n); // make sure lemma interpolants have been computed - q = interps[n.frame][pv->range_max(rng)]; - break; - } - case Contra: { - q = itps[n.premises[0]]; -#ifdef FACTOR_INTERPS - disjs[i] = disjs[n.premises[0]]; -#endif - break; - } - default: - assert(0 && "rule not allowed in interpolated proof"); - } -#ifdef CHECK_PROOFS - int this_frame = pv->range_max(rng); - if(0 && this_frame == 39) { - std::vector alits; - ast s = pv->mk_true(); - for(unsigned j = 0; j < n.conclusion.size(); j++) - if(pred_in_A(n.conclusion[j])){ - int scpmax = pv->range_max(pv->ast_scope(n.conclusion[j])); - if(scpmax == this_frame) - s = pv->mk_and(s,pv->mk_not(n.conclusion[j])); - } - ast ci = child_interps[i]; - s = pv->mk_and(pv->mk_and(s,pv->mk_and(assump,pv->mk_not(q))),ci); - if(pv->is_sat(s)){ - std::cout << "interpolation invariant violated at step " << i << "\n"; - assert(0 && "interpolation invariant violated"); - } - } - if((*parents)[this_frame] == 39) - child_interps[i] = pv->mk_and(child_interps[i],q); -#endif - } - ast &bar = itps[nodes.size()-1]; -#ifdef FACTOR_INTERPS - if(!weak) - bar = my_or(bar,disj_of_set(disjs[nodes.size()-1])); - else - bar = pv->mk_and(bar,pv->mk_not(disj_of_set(disjs[nodes.size()-1]))); -#endif - profiling::timer_stop("interp_proof"); - profiling::timer_start("simplifying"); - bar = pv->simplify(bar); - profiling::timer_stop("simplifying"); - return bar; -} - - -void iz3proof::print(std::ostream &s, int id){ - node_struct &n = nodes[id]; - switch(n.rl){ - case Assumption: - s << "Assumption("; - pv->print_clause(s,n.conclusion); - s << ")"; - break; - case Hypothesis: - s << "Hyp("; pv->print_expr(s,n.conclusion[0]); s << ")"; break; - case Reflexivity: - s << "Refl("; pv->print_expr(s,n.conclusion[0]); s << ")"; break; - case Symmetry: - s << "Symm("; print(s,n.premises[0]); s << ")"; break; - case Transitivity: - s << "Trans("; print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")"; break; - case Congruence: - s << "Cong("; pv->print_expr(s,n.conclusion[0]); - for(unsigned i = 0; i < n.premises.size(); i++){ - s << ","; - print(s,n.premises[i]); - } - s << ")"; break; - case EqContra: - s << "EqContra("; print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")"; break; - case Resolution: - s << "Res("; - pv->print_expr(s,n.aux); s << ","; - print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")"; - break; - case Lemma: - s << "Lemma("; - pv->print_clause(s,n.conclusion); - for(unsigned i = 0; i < n.premises.size(); i++){ - s << ","; - print(s,n.premises[i]); - } - s << ")"; - break; - case Contra: - s << "Contra("; - print(s,n.premises[0]); - s << ")"; - break; - default:; - } -} - - -void iz3proof::show(int id){ - std::ostringstream ss; - print(ss,id); - iz3base::pretty_print(std::cout,ss.str()); - // std::cout << ss.str(); - std::cout << "\n"; -} - - diff --git a/src/interp/iz3proof.h b/src/interp/iz3proof.h deleted file mode 100644 index a7dcb9b75..000000000 --- a/src/interp/iz3proof.h +++ /dev/null @@ -1,274 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3proof.h - - Abstract: - - This class defines a simple interpolating proof system. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3PROOF_H -#define IZ3PROOF_H - -#include - -#include "interp/iz3base.h" -#include "interp/iz3secondary.h" - -// #define CHECK_PROOFS - -/** This class defines a simple proof system. - - A proof is a dag consisting of "nodes". The children of each node - are its "premises". Each node has a "conclusion" that is a clause, - represented as a vector of literals. - - The literals are represented by abstract syntax trees. Operations - on these, including computation of scopes are provided by iz3base. - - A proof can be interpolated, provided it is restricted to the - rules Resolution, Assumption, Contra and Lemma, and that all - clauses are strict (i.e., each literal in each clause is local). - -*/ - -class iz3proof { - public: - /** The type of proof nodes (nodes in the derivation tree). */ - typedef int node; - - /** Enumeration of proof rules. */ - enum rule {Resolution,Assumption,Hypothesis,Theory,Axiom,Contra,Lemma,Reflexivity,Symmetry,Transitivity,Congruence,EqContra}; - - /** Interface to prover. */ - typedef iz3base prover; - - /** Ast type. */ - typedef prover::ast ast; - - /** Object thrown in case of a proof error. */ - struct proof_error: public iz3_exception { - proof_error(): iz3_exception("proof_error") {} - }; - - /* Null proof node */ - static const node null = -1; - - /** Make a resolution node with given pivot liter and premises. - The conclusion of premise1 should contain the negation of the - pivot literal, while the conclusion of premise2 should containe the - pivot literal. - */ - node make_resolution(ast pivot, node premise1, node premise2); - - /** Make an assumption node. The given clause is assumed in the given frame. */ - node make_assumption(int frame, const std::vector &assumption); - - /** Make a hypothesis node. If phi is the hypothesis, this is - effectively phi |- phi. */ - node make_hypothesis(ast hypothesis); - - /** Make a theory node. This can be any inference valid in the theory. */ - node make_theory(const std::vector &conclusion, std::vector premises); - - /** Make an axiom node. The conclusion must be an instance of an axiom. */ - node make_axiom(const std::vector &conclusion); - - /** Make a Contra node. This rule takes a derivation of the form - Gamma |- False and produces |- \/~Gamma. */ - - node make_contra(node prem, const std::vector &conclusion); - - /** Make a lemma node. A lemma node must have an interpolation. */ - node make_lemma(const std::vector &conclusion, const std::vector &interpolation); - - /** Make a Reflexivity node. This rule produces |- x = x */ - - node make_reflexivity(ast con); - - /** Make a Symmetry node. This takes a derivation of |- x = y and - produces | y = x */ - - node make_symmetry(ast con, node prem); - - /** Make a transitivity node. This takes derivations of |- x = y - and |- y = z produces | x = z */ - - node make_transitivity(ast con, node prem1, node prem2); - - /** Make a congruence node. This takes derivations of |- x_i = y_i - and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */ - - node make_congruence(ast con, const std::vector &prems); - - /** Make an equality contradicition node. This takes |- x = y - and |- !(x = y) and produces false. */ - - node make_eqcontra(node prem1, node prem2); - - /** Get the rule of a node in a proof. */ - rule get_rule(node n){ - return nodes[n].rl; - } - - /** Get the pivot of a resolution node. */ - ast get_pivot(node n){ - return nodes[n].aux; - } - - /** Get the frame of an assumption node. */ - int get_frame(node n){ - return nodes[n].frame; - } - - /** Get the number of literals of the conclusion of a node. */ - int get_num_conclusion_lits(node n){ - return get_conclusion(n).size(); - } - - /** Get the nth literal of the conclusion of a node. */ - ast get_nth_conclusion_lit(node n, int i){ - return get_conclusion(n)[i]; - } - - /** Get the conclusion of a node. */ - void get_conclusion(node n, std::vector &result){ - result = get_conclusion(n); - } - - /** Get the number of premises of a node. */ - int get_num_premises(node n){ - return nodes[n].premises.size(); - } - - /** Get the nth premise of a node. */ - int get_nth_premise(node n, int i){ - return nodes[n].premises[i]; - } - - /** Get all the premises of a node. */ - void get_premises(node n, std::vector &result){ - result = nodes[n].premises; - } - - /** Create a new proof node, replacing the premises of an old - one. */ - - node clone(node n, std::vector &premises){ - if(premises == nodes[n].premises) - return n; - nodes.push_back(nodes[n]); - nodes.back().premises = premises; - return nodes.size()-1; - } - - /** Copy a proof node from src */ - node copy(iz3proof &src, node n); - - /** Resolve two lemmas on a given literal. */ - - node resolve_lemmas(ast pivot, node left, node right); - - /** Swap two proofs. */ - void swap(iz3proof &other){ - std::swap(pv,other.pv); - nodes.swap(other.nodes); - interps.swap(other.interps); - } - - /** Compute an interpolant for a proof, where the "A" side is defined by - the given range of frames. Parameter "weak", when true, uses different - interpolation system that resutls in generally weaker interpolants. - */ - ast interpolate(const prover::range &_rng, bool weak = false -#ifdef CHECK_PROOFS - , Z3_ast assump = (Z3_ast)0, std::vector *parents = 0 - -#endif - ); - - /** print proof node to a stream */ - - void print(std::ostream &s, node n); - - /** show proof node on stdout */ - void show(node n); - - /** Construct a proof, with a given prover. */ - iz3proof(prover *p){ - pv = p; - } - - /** Default constructor */ - iz3proof(){pv = nullptr;} - - - protected: - - struct node_struct { - rule rl; - ast aux; - int frame; - std::vector conclusion; - std::vector premises; - }; - - std::vector nodes; - std::vector > interps; // interpolations of lemmas - prover *pv; - - node make_node(){ - nodes.push_back(node_struct()); - return nodes.size()-1; - } - - void resolve(ast pivot, std::vector &cls1, const std::vector &cls2); - - node copy_rec(stl_ext::hash_map &memo, iz3proof &src, node n); - - void interpolate_lemma(node_struct &n); - - // lazily compute the result of resolution - // the node member "frame" indicates result is computed - const std::vector &get_conclusion(node x){ - node_struct &n = nodes[x]; - if(n.rl == Resolution && !n.frame){ - n.conclusion = get_conclusion(n.premises[0]); - resolve(n.aux,n.conclusion,get_conclusion(n.premises[1])); - n.frame = 1; - } - return n.conclusion; - } - - prover::range rng; - bool weak; - stl_ext::hash_set b_lits; - ast my_or(ast x, ast y); -#ifdef CHECK_PROOFS - std::vector child_interps; -#endif - bool pred_in_A(ast id); - bool term_in_B(ast id); - bool frame_in_A(int frame); - bool lit_in_B(ast lit); - ast get_A_lits(std::vector &cls); - ast get_B_lits(std::vector &cls); - void find_B_lits(); - ast disj_of_set(std::set &s); - void mk_or_factor(int p1, int p2, int i, std::vector &itps, std::vector > &disjs); - void mk_and_factor(int p1, int p2, int i, std::vector &itps, std::vector > &disjs); - void set_of_B_lits(std::vector &cls, std::set &res); - void set_of_A_lits(std::vector &cls, std::set &res); -}; - -#endif diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp deleted file mode 100755 index bbeb8d072..000000000 --- a/src/interp/iz3proof_itp.cpp +++ /dev/null @@ -1,3117 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3proof.cpp - - Abstract: - - This class defines a simple interpolating proof system. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3proof_itp.h" - -using namespace stl_ext; - -// #define INVARIANT_CHECKING - -class iz3proof_itp_impl : public iz3proof_itp { - - prover *pv; - prover::range rng; - bool weak; - - enum LitType {LitA,LitB,LitMixed}; - - hash_map placeholders; - - // These symbols represent deduction rules - - /* This symbol represents a proof by contradiction. That is, - contra(p,l1 /\ ... /\ lk) takes a proof p of - - l1,...,lk |- false - - and returns a proof of - - |- ~l1,...,~l2 - */ - symb contra; - - /* The summation rule. The term sum(p,c,i) takes a proof p of an - inequality i', an integer coefficient c and an inequality i, and - yields a proof of i' + ci. */ - symb sum; - - /* Proof rotation. The proof term rotate(q,p) takes a - proof p of: - - Gamma, q |- false - - and yields a proof of: - - Gamma |- ~q - */ - symb rotate_sum; - - /* Inequalities to equality. leq2eq(p, q, r) takes a proof - p of ~x=y, a proof q of x <= y and a proof r of y <= x - and yields a proof of false. */ - symb leq2eq; - - /* Equality to inequality. eq2leq(p, q) takes a proof p of x=y, and - a proof q ~(x <= y) and yields a proof of false. */ - symb eq2leq; - - /* Proof term cong(p,q) takes a proof p of x=y and a proof - q of t != t and returns a proof of false. */ - symb cong; - - - /* Excluded middle. exmid(phi,p,q) takes a proof p of phi and a - proof q of ~\phi and returns a proof of false. */ - symb exmid; - - /* Symmetry. symm(p) takes a proof p of x=y and produces - a proof of y=x. */ - symb symm; - - /* Modus ponens. modpon(p,e,q) takes proofs p of P, e of P=Q - and q of ~Q and returns a proof of false. */ - symb modpon; - - /* This oprerator represents a concatenation of rewrites. The term - a=b;c=d represents an A rewrite from a to b, followed by a B - rewrite from b to c, followed by an A rewrite from c to d. - */ - symb concat; - - /* This represents a lack of a proof */ - ast no_proof; - - // This is used to represent an infinitessimal value - ast epsilon; - - // Represents the top position of a term - ast top_pos; - - // add_pos(i,pos) represents position pos if the ith argument - symb add_pos; - - // rewrite proof rules - - /* rewrite_A(pos,cond,x=y) derives A |- cond => t[x]_p = t[y]_p - where t is an arbitrary term */ - symb rewrite_A; - - /* rewrite_B(pos,cond,x=y) derives B |- cond => t[x]_p = t[y]_p, - where t is an arbitrary term */ - symb rewrite_B; - - /* a normalization step is of the form (lhs=rhs) : proof, where "proof" - is a proof of lhs=rhs and lhs is a mixed term. If rhs is a mixed term - then it must have a greater index than lhs. */ - symb normal_step; - - /* A chain of normalization steps is either "true" (the null chain) - or normal_chain( ), where step is a normalization step - and tail is a normalization chain. The lhs of must have - a less term index than any lhs in the chain. Moreover, the rhs of - may not occur as the lhs of step in . If we wish to - add lhs=rhs to the beginning of and rhs=rhs' occurs in - we must apply transitivity, transforming to lhs=rhs'. */ - - symb normal_chain; - - /* If p is a proof of Q and c is a normalization chain, then normal(p,c) - is a proof of Q(c) (that is, Q with all substitutions in c performed). */ - - symb normal; - - /** Stand-ins for quantifiers */ - - symb sforall, sexists; - - - ast get_placeholder(ast t){ - hash_map::iterator it = placeholders.find(t); - if(it != placeholders.end()) - return it->second; - ast &res = placeholders[t]; - res = mk_fresh_constant("@p",get_type(t)); -#if 0 - std::cout << "placeholder "; - print_expr(std::cout,res); - std::cout << " = "; - print_expr(std::cout,t); - std::cout << std::endl; -#endif - return res; - } - - ast make_contra_node(const ast &pf, const std::vector &lits, int pfok = -1){ - if(lits.size() == 0) - return pf; - std::vector reslits; - reslits.push_back(make(contra,pf,mk_false())); - for(unsigned i = 0; i < lits.size(); i++){ - ast bar; - if(pfok & (1 << i)) bar = make(rotate_sum,lits[i],pf); - else bar = no_proof; - ast foo = make(contra,bar,lits[i]); - reslits.push_back(foo); - } - return make(And,reslits); - } - - LitType get_term_type(const ast &lit){ - prover::range r = pv->ast_scope(lit); - if(pv->range_is_empty(r)) - return LitMixed; - if(weak) { - if(pv->range_min(r) == SHRT_MIN) - return pv->range_contained(r,rng) ? LitA : LitB; - else - return pv->ranges_intersect(r,rng) ? LitA : LitB; - } - else - return pv->range_contained(r,rng) ? LitA : LitB; - } - - bool term_common(const ast &t){ - prover::range r = pv->ast_scope(t); - return pv->ranges_intersect(r,rng) && !pv->range_contained(r,rng); - } - - bool term_in_vocab(LitType ty, const ast &lit){ - prover::range r = pv->ast_scope(lit); - if(ty == LitA){ - return pv->ranges_intersect(r,rng); - } - return !pv->range_contained(r,rng); - } - - /** Make a resolution node with given pivot literal and premises. - The conclusion of premise1 should contain the negation of the - pivot literal, while the conclusion of premise2 should contain the - pivot literal. - */ - node make_resolution(ast pivot, const std::vector &conc, node premise1, node premise2) override { - LitType lt = get_term_type(pivot); - if(lt == LitA) - return my_or(premise1,premise2); - if(lt == LitB) - return my_and(premise1,premise2); - - /* the mixed case is a bit complicated */ - - static int non_local_count = 0; - ast res = resolve_arith(pivot,conc,premise1,premise2); -#ifdef INVARIANT_CHECKING - check_contra(conc,res); -#endif - non_local_count++; - return res; - } - - - /* Handles the case of resolution on a mixed arith atom. */ - - ast resolve_arith(const ast &pivot, const std::vector &conc, node premise1, node premise2){ - ast atom = get_lit_atom(pivot); - hash_map memo; - ast neg_pivot_lit = mk_not(atom); - if(op(pivot) != Not) - std::swap(premise1,premise2); - if(op(pivot) == Equal && op(arg(pivot,0)) == Select && op(arg(pivot,1)) == Select){ - neg_pivot_lit = mk_not(neg_pivot_lit); - std::swap(premise1,premise2); - } - return resolve_arith_rec1(memo, neg_pivot_lit, premise1, premise2); - } - - - ast apply_coeff(const ast &coeff, const ast &t){ -#if 0 - rational r; - if(!is_integer(coeff,r)) - throw iz3_exception("ack!"); - ast n = make_int(r.numerator()); - ast res = make(Times,n,t); - if(!r.is_int()) { - ast d = make_int(r.numerator()); - res = mk_idiv(res,d); - } - return res; -#endif - return make(Times,coeff,t); - } - - ast sum_ineq(const ast &coeff1, const ast &ineq1, const ast &coeff2, const ast &ineq2){ - opr sum_op = Leq; - if(op(ineq1) == Lt || op(ineq2) == Lt) - sum_op = Lt; - ast sum_sides[2]; - for(int i = 0; i < 2; i++){ - sum_sides[i] = make(Plus,apply_coeff(coeff1,arg(ineq1,i)),apply_coeff(coeff2,arg(ineq2,i))); - sum_sides[i] = z3_simplify(sum_sides[i]); - } - return make(sum_op,sum_sides[0],sum_sides[1]); - } - - - void collect_contra_resolvents(int from, const ast &pivot1, const ast &pivot, const ast &conj, std::vector &res){ - int nargs = num_args(conj); - for(int i = from; i < nargs; i++){ - ast f = arg(conj,i); - if(!(f == pivot)){ - ast ph = get_placeholder(mk_not(arg(pivot1,1))); - ast pf = arg(pivot1,0); - ast thing = pf == no_proof ? no_proof : subst_term_and_simp(ph,pf,arg(f,0)); - ast newf = make(contra,thing,arg(f,1)); - res.push_back(newf); - } - } - } - - bool is_negative_equality(const ast &e){ - if(op(e) == Not){ - opr o = op(arg(e,0)); - return o == Equal || o == Iff; - } - return false; - } - - int count_negative_equalities(const std::vector &resolvent){ - int res = 0; - for(unsigned i = 0; i < resolvent.size(); i++) - if(is_negative_equality(arg(resolvent[i],1))) - res++; - return res; - } - - ast resolve_contra_nf(const ast &pivot1, const ast &conj1, - const ast &pivot2, const ast &conj2){ - std::vector resolvent; - collect_contra_resolvents(0,pivot1,pivot2,conj2,resolvent); - collect_contra_resolvents(1,pivot2,pivot1,conj1,resolvent); - if(count_negative_equalities(resolvent) > 1) - throw proof_error(); - if(resolvent.size() == 1) // we have proved a contradiction - return simplify(arg(resolvent[0],0)); // this is the proof -- get interpolant - return make(And,resolvent); - } - - ast resolve_contra(const ast &pivot1, const ast &conj1, - const ast &pivot2, const ast &conj2){ - if(arg(pivot1,0) != no_proof) - return resolve_contra_nf(pivot1, conj1, pivot2, conj2); - if(arg(pivot2,0) != no_proof) - return resolve_contra_nf(pivot2, conj2, pivot1, conj1); - return resolve_with_quantifier(pivot1, conj1, pivot2, conj2); - } - - - bool is_contra_itp(const ast &pivot1, ast itp2, ast &pivot2){ - if(op(itp2) == And){ - int nargs = num_args(itp2); - for(int i = 1; i < nargs; i++){ - ast foo = arg(itp2,i); - if(op(foo) == Uninterpreted && sym(foo) == contra){ - if(arg(foo,1) == pivot1){ - pivot2 = foo; - return true; - } - } - else break; - } - } - return false; - } - - ast resolve_arith_rec2(hash_map &memo, const ast &pivot1, const ast &conj1, const ast &itp2){ - ast &res = memo[itp2]; - if(!res.null()) - return res; - - ast pivot2; - if(is_contra_itp(mk_not(arg(pivot1,1)),itp2,pivot2)) - res = resolve_contra(pivot1,conj1,pivot2,itp2); - else { - switch(op(itp2)){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(itp2); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = resolve_arith_rec2(memo, pivot1, conj1, arg(itp2,i)); - ast foo = itp2; // get rid of const - res = clone(foo,args); - break; - } - default: - { - opr o = op(itp2); - if(o == Uninterpreted){ - symb s = sym(itp2); - if(s == sforall || s == sexists) - res = make(s,arg(itp2,0),resolve_arith_rec2(memo, pivot1, conj1, arg(itp2,1))); - else - res = itp2; - } - else { - res = itp2; - } - } - } - } - return res; - } - - - ast resolve_arith_rec1(hash_map &memo, const ast &neg_pivot_lit, const ast &itp1, const ast &itp2){ - ast &res = memo[itp1]; - if(!res.null()) - return res; - ast pivot1; - if(is_contra_itp(neg_pivot_lit,itp1,pivot1)){ - hash_map memo2; - res = resolve_arith_rec2(memo2,pivot1,itp1,itp2); - } - else { - switch(op(itp1)){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(itp1); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = resolve_arith_rec1(memo, neg_pivot_lit, arg(itp1,i), itp2); - ast foo = itp1; // get rid of const - res = clone(foo,args); - break; - } - default: - { - opr o = op(itp1); - if(o == Uninterpreted){ - symb s = sym(itp1); - if(s == sforall || s == sexists) - res = make(s,arg(itp1,0),resolve_arith_rec1(memo, neg_pivot_lit, arg(itp1,1), itp2)); - else - res = itp1; - } - else { - res = itp1; - } - } - } - } - return res; - } - - void check_contra(hash_set &memo, hash_set &neg_lits, const ast &foo){ - if(memo.find(foo) != memo.end()) - return; - memo.insert(foo); - if(op(foo) == Uninterpreted && sym(foo) == contra){ - ast neg_lit = arg(foo,1); - if(!is_false(neg_lit) && neg_lits.find(neg_lit) == neg_lits.end()) - throw iz3_exception("lost a literal"); - return; - } - else { - switch(op(foo)){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(foo); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - check_contra(memo, neg_lits, arg(foo,i)); - break; - } - default: break; - } - } - } - - void check_contra(const std::vector &neg_lits, const ast &foo){ - hash_set memo; - hash_set neg_lits_set; - for(unsigned i = 0; i < neg_lits.size(); i++) - if(get_term_type(neg_lits[i]) == LitMixed) - neg_lits_set.insert(mk_not(neg_lits[i])); - check_contra(memo,neg_lits_set,foo); - } - - hash_map subst_memo; // memo of subst function - - ast subst_term_and_simp(const ast &var, const ast &t, const ast &e){ - subst_memo.clear(); - return subst_term_and_simp_rec(var,t,e); - } - - ast subst_term_and_simp_rec(const ast &var, const ast &t, const ast &e){ - if(e == var) return t; - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = subst_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - if(op(e) == Uninterpreted){ - symb g = sym(e); - if(g == rotate_sum){ - if(var == get_placeholder(arg(e,0))){ - res = e; - } - else - res = make(rotate_sum,arg(e,0),subst_term_and_simp_rec(var,t,arg(e,1))); - return res; - } - if(g == concat){ - res = e; - return res; - } - } - int nargs = num_args(e); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = subst_term_and_simp_rec(var,t,arg(e,i)); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else if(f == And) res = my_and(args); - else if(f == Or) res = my_or(args); - else if(f == Idiv) res = mk_idiv(args[0],args[1]); - else res = clone(e,args); - } - return res; - } - - /* This is where the real work happens. Here, we simplify the - proof obtained by cut elimination, obtaining an interpolant. */ - - struct cannot_simplify: public iz3_exception { - cannot_simplify(): iz3_exception("cannot_simplify") {} - }; - hash_map simplify_memo; - - ast simplify(const ast &t){ - ast res = normalize(simplify_rec(t)); -#ifdef BOGUS_QUANTS - if(localization_vars.size()) - res = add_quants(z3_simplify(res)); -#endif - return res; - } - - ast simplify_rec(const ast &e){ - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = simplify_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - int nargs = num_args(e); - std::vector args(nargs); - bool placeholder_arg = false; - symb g = sym(e); - if(g == concat){ - res = e; - return res; - } - for(int i = 0; i < nargs; i++){ - if(i == 0 && g == rotate_sum) - args[i] = arg(e,i); - else - args[i] = simplify_rec(arg(e,i)); - placeholder_arg |= is_placeholder(args[i]); - } - try { - TRACE("duality", print_expr(tout, e); tout << "\n";); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else if(f == And) res = my_and(args); - else if(f == Or) - res = my_or(args); - else if(f == Idiv) res = mk_idiv(args[0],args[1]); - else if(f == Uninterpreted && !placeholder_arg){ - if(g == rotate_sum) res = simplify_rotate(args); - else if(g == symm) res = simplify_symm(args); - else if(g == modpon) res = simplify_modpon(args); - else if(g == sum) res = simplify_sum(args); - else if(g == exmid) res = simplify_exmid(args); - else if(g == cong) res = simplify_cong(args); -#if 0 - else if(g == modpon) res = simplify_modpon(args); - else if(g == leq2eq) res = simplify_leq2eq(args); - else if(g == eq2leq) res = simplify_eq2leq(args); -#endif - else res = clone(e,args); - } - else res = clone(e,args); - } - catch (const cannot_simplify &){ - if(g == sum) - res = clone(e,args); - else - throw "interpolation failure"; - } - } - return res; - } - - - ast simplify_rotate(const std::vector &args){ - const ast &pf = args[1]; - ast pl = get_placeholder(args[0]); - if(op(pf) == Uninterpreted){ - symb g = sym(pf); - if(g == sum) return simplify_rotate_sum(pl,pf); - if(g == leq2eq) return simplify_rotate_leq2eq(pl,args[0],pf); - if(g == eq2leq) return simplify_rotate_eq2leq(pl,args[0],pf); - if(g == cong) return simplify_rotate_cong(pl,args[0],pf); - if(g == modpon) return simplify_rotate_modpon(pl,args[0],pf); - // if(g == symm) return simplify_rotate_symm(pl,args[0],pf); - } - if(op(pf) == Leq) - throw iz3_exception("foo!"); - throw cannot_simplify(); - } - - bool is_normal_ineq(const ast &ineq){ - if(sym(ineq) == normal) - return is_ineq(arg(ineq,0)); - return is_ineq(ineq); - } - - ast destruct_cond_ineq(const ast &ineq, ast &Aproves, ast &Bproves){ - ast res = ineq; - opr o = op(res); - if(o == And){ - Aproves = my_and(Aproves,arg(res,0)); - res = arg(res,1); - o = op(res); - } - if(o == Implies){ - Bproves = my_and(Bproves,arg(res,0)); - res = arg(res,1); - } - return res; - } - - ast distribute_coeff(const ast &coeff, const ast &s){ - if(sym(s) == sum){ - if(sym(arg(s,2)) == sum) - return make(sum, - distribute_coeff(coeff,arg(s,0)), - make_int(rational(1)), - distribute_coeff(make(Times,coeff,arg(s,1)), arg(s,2))); - else - return make(sum, - distribute_coeff(coeff,arg(s,0)), - make(Times,coeff,arg(s,1)), - arg(s,2)); - } - if(op(s) == Leq && arg(s,1) == make_int(rational(0)) && arg(s,2) == make_int(rational(0))) - return s; - return make(sum,make(Leq,make_int(rational(0)),make_int(rational(0))),coeff,s); - } - - ast simplify_sum(std::vector &args){ - if(args[1] != make_int(rational(1))){ - if(sym(args[2]) == sum) - return make(sum,args[0],make_int(rational(1)),distribute_coeff(args[1],args[2])); - } - ast Aproves = mk_true(), Bproves = mk_true(); - ast ineq = destruct_cond_ineq(args[0],Aproves,Bproves); - if(!is_normal_ineq(ineq)) throw cannot_simplify(); - sum_cond_ineq(ineq,args[1],args[2],Aproves,Bproves); - return my_and(Aproves,my_implies(Bproves,ineq)); - } - - ast simplify_rotate_sum(const ast &pl, const ast &pf){ - ast Aproves = mk_true(), Bproves = mk_true(); - ast ineq = make(Leq,make_int("0"),make_int("0")); - ineq = rotate_sum_rec(pl,pf,Aproves,Bproves,ineq); - if(is_true(Aproves) && is_true(Bproves)) - return ineq; - return my_and(Aproves,my_implies(Bproves,ineq)); - } - - bool is_rewrite_chain(const ast &chain){ - return sym(chain) == concat; - } - -#if 0 - ast ineq_from_chain_simple(const ast &chain, ast &cond){ - if(is_true(chain)) - return chain; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_true(rest) && is_rewrite_side(LitA,last) - && is_true(rewrite_lhs(last))){ - cond = my_and(cond,rewrite_cond(last)); - return rewrite_rhs(last); - } - if(is_rewrite_side(LitB,last) && is_true(rewrite_cond(last))) - return ineq_from_chain_simple(rest,cond); - return chain; - } -#endif - - ast ineq_from_chain(const ast &chain, ast &Aproves, ast &Bproves){ - if(is_rewrite_chain(chain)) - return rewrite_chain_to_normal_ineq(chain,Aproves,Bproves); - return chain; - } - - - void sum_cond_ineq(ast &ineq, const ast &coeff2, const ast &ineq2, ast &Aproves, ast &Bproves){ - opr o = op(ineq2); - if(o == And){ - sum_cond_ineq(ineq,coeff2,arg(ineq2,1),Aproves,Bproves); - Aproves = my_and(Aproves,arg(ineq2,0)); - } - else if(o == Implies){ - sum_cond_ineq(ineq,coeff2,arg(ineq2,1),Aproves,Bproves); - Bproves = my_and(Bproves,arg(ineq2,0)); - } - else { - ast the_ineq = ineq_from_chain(ineq2,Aproves,Bproves); - if(sym(ineq) == normal || sym(the_ineq) == normal){ - sum_normal_ineq(ineq,coeff2,the_ineq,Aproves,Bproves); - return; - } - if(is_ineq(the_ineq)) - linear_comb(ineq,coeff2,the_ineq); - else - throw cannot_simplify(); - } - } - - void destruct_normal(const ast &pf, ast &p, ast &n){ - if(sym(pf) == normal){ - p = arg(pf,0); - n = arg(pf,1); - } - else { - p = pf; - n = mk_true(); - } - } - - void sum_normal_ineq(ast &ineq, const ast &coeff2, const ast &ineq2, ast &Aproves, ast &Bproves){ - ast in1,in2,n1,n2; - destruct_normal(ineq,in1,n1); - destruct_normal(ineq2,in2,n2); - ast dummy1, dummy2; - sum_cond_ineq(in1,coeff2,in2,dummy1,dummy2); - n1 = merge_normal_chains(n1,n2, Aproves, Bproves); - ineq = is_true(n1) ? in1 : make_normal(in1,n1); - } - - bool is_ineq(const ast &ineq){ - opr o = op(ineq); - if(o == Not) o = op(arg(ineq,0)); - return o == Leq || o == Lt || o == Geq || o == Gt; - } - - // divide both sides of inequality by a non-negative integer divisor - ast idiv_ineq(const ast &ineq1, const ast &divisor){ - if(sym(ineq1) == normal){ - ast in1,n1; - destruct_normal(ineq1,in1,n1); - in1 = idiv_ineq(in1,divisor); - return make_normal(in1,n1); - } - if(divisor == make_int(rational(1))) - return ineq1; - ast ineq = ineq1; - if(op(ineq) == Lt) - ineq = simplify_ineq(make(Leq,arg(ineq,0),make(Sub,arg(ineq,1),make_int("1")))); - return make(op(ineq),mk_idiv(arg(ineq,0),divisor),mk_idiv(arg(ineq,1),divisor)); - } - - ast rotate_sum_rec(const ast &pl, const ast &pf, ast &Aproves, ast &Bproves, ast &ineq){ - if(pf == pl){ - if(sym(ineq) == normal) - return ineq; - return simplify_ineq(ineq); - } - if(op(pf) == Uninterpreted && sym(pf) == sum){ - if(arg(pf,2) == pl){ - sum_cond_ineq(ineq,make_int("1"),arg(pf,0),Aproves,Bproves); - ineq = idiv_ineq(ineq,arg(pf,1)); - return ineq; - } - sum_cond_ineq(ineq,arg(pf,1),arg(pf,2),Aproves,Bproves); - return rotate_sum_rec(pl,arg(pf,0),Aproves,Bproves,ineq); - } - throw cannot_simplify(); - } - - ast simplify_rotate_leq2eq(const ast &pl, const ast &neg_equality, const ast &pf){ - if(pl == arg(pf,0)){ - ast equality = arg(neg_equality,0); - ast x = arg(equality,0); - ast y = arg(equality,1); - ast Aproves1 = mk_true(), Bproves1 = mk_true(); - ast pf1 = destruct_cond_ineq(arg(pf,1), Aproves1, Bproves1); - ast pf2 = destruct_cond_ineq(arg(pf,2), Aproves1, Bproves1); - ast xleqy = round_ineq(ineq_from_chain(pf1,Aproves1,Bproves1)); - ast yleqx = round_ineq(ineq_from_chain(pf2,Aproves1,Bproves1)); - ast ineq1 = make(Leq,make_int("0"),make_int("0")); - sum_cond_ineq(ineq1,make_int("-1"),xleqy,Aproves1,Bproves1); - sum_cond_ineq(ineq1,make_int("-1"),yleqx,Aproves1,Bproves1); - ast Acond = my_implies(Aproves1,my_and(Bproves1,z3_simplify(ineq1))); - ast Aproves2 = mk_true(), Bproves2 = mk_true(); - ast ineq2 = make(Leq,make_int("0"),make_int("0")); - sum_cond_ineq(ineq2,make_int("1"),xleqy,Aproves2,Bproves2); - sum_cond_ineq(ineq2,make_int("1"),yleqx,Aproves2,Bproves2); - ast Bcond = my_implies(Bproves1,my_and(Aproves1,z3_simplify(ineq2))); - // if(!is_true(Aproves1) || !is_true(Bproves1)) - // std::cout << "foo!\n";; - if(y == make_int(rational(0)) && op(x) == Plus && num_args(x) == 2){ - if(get_term_type(arg(x,0)) == LitA){ - ast iter = z3_simplify(make(Plus,arg(x,0),get_ineq_rhs(xleqy))); - ast rewrite1 = make_rewrite(LitA,pos_add(0,top_pos),Acond,make(Equal,arg(x,0),iter)); - iter = make(Plus,iter,arg(x,1)); - ast rewrite2 = make_rewrite(LitB,top_pos,Bcond,make(Equal,iter,y)); - return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2); - } - if(get_term_type(arg(x,1)) == LitA){ - ast iter = z3_simplify(make(Plus,arg(x,1),get_ineq_rhs(xleqy))); - ast rewrite1 = make_rewrite(LitA,pos_add(1,top_pos),Acond,make(Equal,arg(x,1),iter)); - iter = make(Plus,arg(x,0),iter); - ast rewrite2 = make_rewrite(LitB,top_pos,Bcond,make(Equal,iter,y)); - return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2); - } - } - if(get_term_type(x) == LitA){ - ast iter = z3_simplify(make(Plus,x,get_ineq_rhs(xleqy))); - ast rewrite1 = make_rewrite(LitA,top_pos,Acond,make(Equal,x,iter)); - ast rewrite2 = make_rewrite(LitB,top_pos,Bcond,make(Equal,iter,y)); - return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2); - } - if(get_term_type(y) == LitA){ - ast iter = z3_simplify(make(Plus,y,get_ineq_rhs(yleqx))); - ast rewrite2 = make_rewrite(LitA,top_pos,Acond,make(Equal,iter,y)); - ast rewrite1 = make_rewrite(LitB,top_pos,Bcond,make(Equal,x,iter)); - return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2); - } - throw cannot_simplify(); - } - throw cannot_simplify(); - } - - ast round_ineq(const ast &ineq){ - if(sym(ineq) == normal) - return make_normal(round_ineq(arg(ineq,0)),arg(ineq,1)); - if(!is_ineq(ineq)) - throw cannot_simplify(); - ast res = simplify_ineq(ineq); - if(op(res) == Lt) - res = make(Leq,arg(res,0),make(Sub,arg(res,1),make_int("1"))); - return res; - } - - ast unmixed_eq2ineq(const ast &lhs, const ast &rhs, opr comp_op, const ast &equa, ast &cond){ - ast ineqs= chain_ineqs(comp_op,LitA,equa,lhs,rhs); // chain must be from lhs to rhs - cond = my_and(cond,chain_conditions(LitA,equa)); - ast Bconds = z3_simplify(chain_conditions(LitB,equa)); - if(is_true(Bconds) && op(ineqs) != And) - return my_implies(cond,ineqs); - if(op(ineqs) != And) - return my_and(Bconds,my_implies(cond,ineqs)); - throw iz3_exception("help!"); - } - - ast add_mixed_eq2ineq(const ast &lhs, const ast &rhs, const ast &equa, const ast &itp){ - if(is_true(equa)) - return itp; - std::vector args(3); - args[0] = itp; - args[1] = make_int("1"); - ast ineq = make(Leq,make_int(rational(0)),make_int(rational(0))); - args[2] = make_normal(ineq,cons_normal(fix_normal(lhs,rhs,equa),mk_true())); - return simplify_sum(args); - } - - - ast simplify_rotate_eq2leq(const ast &pl, const ast &neg_equality, const ast &pf){ - if(pl == arg(pf,1)){ - TRACE("duality", print_expr(tout, pl); print_expr(tout << "\n", neg_equality); print_expr(tout << "\n", pf); tout << "\n";); - ast cond = mk_true(); - ast equa = sep_cond(arg(pf,0),cond); - if(is_equivrel_chain(equa)){ - ast lhs,rhs; eq_from_ineq(arg(neg_equality,0),lhs,rhs); // get inequality we need to prove - if(!rewrites_from_to(equa,lhs,rhs)){ - lhs = arg(arg(neg_equality,0),0); // the equality proved is ambiguous, sadly - rhs = arg(arg(neg_equality,0),1); - } - LitType lhst = get_term_type(lhs), rhst = get_term_type(rhs); - if(lhst != LitMixed && rhst != LitMixed) - return unmixed_eq2ineq(lhs, rhs, op(arg(neg_equality,0)), equa, cond); - else { - ast left, left_term, middle, right_term, right; - left = get_left_movers(equa,lhs,middle,left_term); - middle = get_right_movers(middle,rhs,right,right_term); - ast itp = unmixed_eq2ineq(left_term, right_term, op(arg(neg_equality,0)), middle, cond); - // itp = my_implies(cond,itp); - itp = add_mixed_eq2ineq(lhs, left_term, left, itp); - itp = add_mixed_eq2ineq(right_term, rhs, right, itp); - return itp; - } - } - } - throw iz3_exception("help!"); - } - - void reverse_modpon(std::vector &args){ - std::vector sargs(1); sargs[0] = args[1]; - args[1] = simplify_symm(sargs); - if(is_equivrel_chain(args[2])) - args[1] = down_chain(args[1]); - std::swap(args[0],args[2]); - } - - ast simplify_rotate_modpon(const ast &pl, const ast &neg_equality, const ast &pf){ - std::vector args; args.resize(3); - args[0] = arg(pf,0); - args[1] = arg(pf,1); - args[2] = arg(pf,2); - if(pl == args[0]) - reverse_modpon(args); - if(pl == args[2]){ - ast cond = mk_true(); - ast chain = simplify_modpon_fwd(args, cond); - return my_implies(cond,chain); - } - throw cannot_simplify(); - } - - ast get_ineq_rhs(const ast &ineq2){ - opr o = op(ineq2); - if(o == Implies) - return get_ineq_rhs(arg(ineq2,1)); - else if(o == Leq || o == Lt) - return arg(ineq2,1); - throw cannot_simplify(); - } - - ast simplify_rotate_cong(const ast &pl, const ast &neg_equality, const ast &pf){ - if(pl == arg(pf,2)){ - if(op(arg(pf,0)) == True) - return mk_true(); - rational pos; - if(is_numeral(arg(pf,1),pos)){ - int ipos = pos.get_unsigned(); - ast cond = mk_true(); - ast equa = sep_cond(arg(pf,0),cond); -#if 0 - if(op(equa) == Equal){ - ast pe = mk_not(neg_equality); - ast lhs = subst_in_arg_pos(ipos,arg(equa,0),arg(pe,0)); - ast rhs = subst_in_arg_pos(ipos,arg(equa,1),arg(pe,1)); - ast res = make(Equal,lhs,rhs); - return my_implies(cond,res); - } -#endif - ast res = chain_pos_add(ipos,equa); - return my_implies(cond,res); - } - } - throw cannot_simplify(); - } - - ast simplify_symm(const std::vector &args){ - if(op(args[0]) == True) - return mk_true(); - ast cond = mk_true(); - ast equa = sep_cond(args[0],cond); - if(is_equivrel_chain(equa)) - return my_implies(cond,reverse_chain(equa)); - if(is_negation_chain(equa)) - return commute_negation_chain(equa); - throw cannot_simplify(); - } - - ast simplify_modpon_fwd(const std::vector &args, ast &cond){ - ast P = sep_cond(args[0],cond); - ast PeqQ = sep_cond(args[1],cond); - ast chain; - if(is_equivrel_chain(P)){ - try { - ast split[2]; - split_chain(PeqQ,split); - chain = reverse_chain(split[0]); - chain = concat_rewrite_chain(chain,P); - chain = concat_rewrite_chain(chain,split[1]); - } - catch(const cannot_split &){ - static int this_count = 0; - this_count++; - ast tail, pref = get_head_chain(PeqQ,tail,false); // pref is x=y, tail is x=y -> x'=y' - ast split[2]; split_chain(tail,split); // rewrites from x to x' and y to y' - ast head = chain_last(pref); - ast prem = make_rewrite(rewrite_side(head),top_pos,rewrite_cond(head),make(Iff,mk_true(),mk_not(rewrite_lhs(head)))); - ast back_chain = chain_cons(mk_true(),prem); - back_chain = concat_rewrite_chain(back_chain,chain_pos_add(0,reverse_chain(chain_rest(pref)))); - ast cond = contra_chain(back_chain,P); - if(is_rewrite_side(LitA,head)) - cond = mk_not(cond); - ast fwd_rewrite = make_rewrite(rewrite_side(head),top_pos,cond,rewrite_rhs(head)); - P = chain_cons(mk_true(),fwd_rewrite); - chain = reverse_chain(split[0]); - chain = concat_rewrite_chain(chain,P); - chain = concat_rewrite_chain(chain,split[1]); - } - } - else { // if not an equivalence, must be of form T <-> pred - chain = concat_rewrite_chain(P,PeqQ); - } - return chain; - } - - struct subterm_normals_failed: public iz3_exception { - subterm_normals_failed(): iz3_exception("subterm_normals_failed") {} - }; - - void get_subterm_normals(const ast &ineq1, const ast &ineq2, const ast &chain, ast &normals, - const ast &pos, hash_set &memo, ast &Aproves, ast &Bproves){ - opr o1 = op(ineq1); - opr o2 = op(ineq2); - if(o1 == Not || o1 == Leq || o1 == Lt || o1 == Geq || o1 == Gt || o1 == Plus || o1 == Times){ - int n = num_args(ineq1); - if(o2 != o1 || num_args(ineq2) != n) - throw iz3_exception("bad inequality rewriting"); - for(int i = 0; i < n; i++){ - ast new_pos = add_pos_to_end(pos,i); - get_subterm_normals(arg(ineq1,i), arg(ineq2,i), chain, normals, new_pos, memo, Aproves, Bproves); - } - } - else if(get_term_type(ineq2) == LitMixed){ - if(memo.find(ineq2) == memo.end()){ - memo.insert(ineq2); - ast sub_chain = extract_rewrites(chain,pos); - if(is_true(sub_chain)) - throw iz3_exception("bad inequality rewriting"); - ast new_normal = make_normal_step(ineq2,ineq1,reverse_chain(sub_chain)); - normals = merge_normal_chains(normals,cons_normal(new_normal,mk_true()), Aproves, Bproves); - } - } - else if(!(ineq1 == ineq2)) - throw subterm_normals_failed(); - } - - ast rewrites_to_normals(const ast &ineq1, const ast &chain, ast &normals, ast &Aproves, ast &Bproves, ast &Aineqs){ - if(is_true(chain)) - return ineq1; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast new_ineq1 = rewrites_to_normals(ineq1, rest, normals, Aproves, Bproves, Aineqs); - ast p1 = rewrite_pos(last); - ast term1; - ast coeff = arith_rewrite_coeff(new_ineq1,p1,term1); - ast res = subst_in_pos(new_ineq1,rewrite_pos(last),rewrite_rhs(last)); - ast rpos; - pos_diff(p1,rewrite_pos(last),rpos); - ast term2 = subst_in_pos(term1,rpos,rewrite_rhs(last)); - if(get_term_type(term1) != LitMixed && get_term_type(term2) != LitMixed){ - if(is_rewrite_side(LitA,last)) - linear_comb(Aineqs,coeff,make(Leq,make_int(rational(0)),make(Sub,term2,term1))); - } - else { - ast pf = extract_rewrites(make(concat,mk_true(),last),p1); - ast new_normal = fix_normal(term1,term2,pf); - normals = merge_normal_chains(normals,cons_normal(new_normal,mk_true()), Aproves, Bproves); - } - return res; - } - - ast arith_rewrite_coeff(const ast &ineq, ast &p1, ast &term){ - ast coeff = make_int(rational(1)); - if(p1 == top_pos){ - term = ineq; - return coeff; - } - int argpos = pos_arg(p1); - opr o = op(ineq); - switch(o){ - case Leq: - case Lt: - coeff = argpos ? make_int(rational(1)) : make_int(rational(-1)); - break; - case Geq: - case Gt: - coeff = argpos ? make_int(rational(-1)) : make_int(rational(1)); - break; - case Not: - coeff = make_int(rational(-1)); - case Plus: - break; - case Times: - coeff = arg(ineq,0); - break; - default: - p1 = top_pos; - term = ineq; - return coeff; - } - p1 = arg(p1,1); - ast res = arith_rewrite_coeff(arg(ineq,argpos),p1,term); - p1 = pos_add(argpos,p1); - return coeff == make_int(rational(1)) ? res : make(Times,coeff,res); - } - - ast rewrite_chain_to_normal_ineq(const ast &chain, ast &Aproves, ast &Bproves){ - ast tail, pref = get_head_chain(chain,tail,false); // pref is x=y, tail is x=y -> x'=y' - ast head = chain_last(pref); - ast ineq1 = rewrite_rhs(head); - ast ineq2 = apply_rewrite_chain(ineq1,tail); - ast nc = mk_true(); - hash_set memo; - ast itp = make(Leq,make_int(rational(0)),make_int(rational(0))); - ast Aproves_save = Aproves, Bproves_save = Bproves; try { - get_subterm_normals(ineq1,ineq2,tail,nc,top_pos,memo, Aproves, Bproves); - } - catch (const subterm_normals_failed &){ Aproves = Aproves_save; Bproves = Bproves_save; nc = mk_true(); - rewrites_to_normals(ineq1, tail, nc, Aproves, Bproves, itp); - } - if(is_rewrite_side(LitA,head)){ - linear_comb(itp,make_int("1"),ineq1); // make sure it is normal form - //itp = ineq1; - ast mc = z3_simplify(chain_side_proves(LitB,pref)); - Bproves = my_and(Bproves,mc); - } - else { - ast mc = z3_simplify(chain_side_proves(LitA,pref)); - Aproves = my_and(Aproves,mc); - } - if(is_true(nc)) - return itp; - return make_normal(itp,nc); - } - - /* Given a chain rewrite chain deriving not P and a rewrite chain deriving P, return an interpolant. */ - ast contra_chain(const ast &neg_chain, const ast &pos_chain){ - // equality is a special case. we use the derivation of x=y to rewrite not(x=y) to not(y=y) - if(is_equivrel_chain(pos_chain)){ - ast tail, pref = get_head_chain(neg_chain,tail); // pref is not(x=y), tail is not(x,y) -> not(x',y') - ast split[2]; split_chain(down_chain(tail),split); // rewrites from x to x' and y to y' - ast chain = split[0]; - chain = concat_rewrite_chain(chain,pos_chain); // rewrites from x to y' - chain = concat_rewrite_chain(chain,reverse_chain(split[1])); // rewrites from x to y - chain = concat_rewrite_chain(pref,chain_pos_add(0,chain_pos_add(0,chain))); // rewrites t -> not(y=y) - ast head = chain_last(pref); - if(is_rewrite_side(LitB,head)){ - ast condition = chain_conditions(LitB,chain); - return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),condition); - } - else { - ast condition = chain_conditions(LitA,chain); - return my_and(chain_conditions(LitB,chain),my_implies(condition,mk_not(chain_formulas(LitB,chain)))); - } - // ast chain = concat_rewrite_chain(neg_chain,chain_pos_add(0,chain_pos_add(0,pos_chain))); - // return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),chain_conditions(LitB,chain)); - } - // otherwise, we reverse the derivation of t = P and use it to rewrite not(P) to not(t) - ast chain = concat_rewrite_chain(neg_chain,chain_pos_add(0,reverse_chain(pos_chain))); - return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),chain_conditions(LitB,chain)); - } - - ast simplify_modpon(const std::vector &args){ - ast Aproves = mk_true(), Bproves = mk_true(); - ast chain = simplify_modpon_fwd(args,Bproves); - ast Q2 = destruct_cond_ineq(args[2],Aproves,Bproves); - ast interp; - if(is_normal_ineq(Q2)){ // inequalities are special - ast nQ2 = rewrite_chain_to_normal_ineq(chain,Aproves,Bproves); - sum_cond_ineq(nQ2,make_int(rational(1)),Q2,Aproves,Bproves); - interp = normalize(nQ2); - } - else - interp = is_negation_chain(chain) ? contra_chain(chain,Q2) : contra_chain(Q2,chain); - return my_and(Aproves,my_implies(Bproves,interp)); - } - - - ast simplify_exmid(const std::vector &args){ - if(is_equivrel(args[0])){ - ast Aproves = mk_true(), Bproves = mk_true(); - ast chain = destruct_cond_ineq(args[1],Aproves,Bproves); - ast Q2 = destruct_cond_ineq(args[2],Aproves,Bproves); - ast interp = contra_chain(Q2,chain); - return my_and(Aproves,my_implies(Bproves,interp)); - } - throw iz3_exception("bad exmid"); - } - - ast simplify_cong(const std::vector &args){ - ast Aproves = mk_true(), Bproves = mk_true(); - ast chain = destruct_cond_ineq(args[0],Aproves,Bproves); - rational pos; - if(is_numeral(args[1],pos)){ - int ipos = pos.get_unsigned(); - chain = chain_pos_add(ipos,chain); - ast Q2 = destruct_cond_ineq(args[2],Aproves,Bproves); - ast interp = contra_chain(Q2,chain); - return my_and(Aproves,my_implies(Bproves,interp)); - } - throw iz3_exception("bad cong"); - } - - bool is_equivrel(const ast &p){ - opr o = op(p); - return o == Equal || o == Iff; - } - - struct rewrites_failed: public iz3_exception { - rewrites_failed(): iz3_exception("rewrites_failed") {} - }; - - /* Suppose p in Lang(B) and A |- p -> q and B |- q -> r. Return a z in Lang(B) such that - B |- p -> z and A |- z -> q. Collect any side conditions in "rules". */ - - ast commute_rewrites(const ast &p, const ast &q, const ast &r, ast &rules){ - if(q == r) - return p; - if(p == q) - return r; - else { - ast rew = make(Equal,q,r); - if(get_term_type(rew) == LitB){ - apply_common_rewrites(p,p,q,rules); // A rewrites must be over comon vocab - return r; - } - } - if(sym(p) != sym(q) || sym(q) != sym(r)) - throw rewrites_failed(); - int nargs = num_args(p); - if(nargs != num_args(q) || nargs != num_args(r)) - throw rewrites_failed(); - std::vector args; args.resize(nargs); - for(int i = 0; i < nargs; i++) - args[i] = commute_rewrites(arg(p,i),arg(q,i),arg(r,i),rules); - return clone(p,args); - } - - ast apply_common_rewrites(const ast &p, const ast &q, const ast &r, ast &rules){ - if(q == r) - return p; - ast rew = make(Equal,q,r); - if(term_common(rew)){ - if(p != q) - throw rewrites_failed(); - rules = my_and(rules,rew); - return r; - } - if(sym(p) != sym(q) || sym(q) != sym(r)) - return p; - int nargs = num_args(p); - if(nargs != num_args(q) || nargs != num_args(r)) - return p; - std::vector args; args.resize(nargs); - for(int i = 0; i < nargs; i++) - args[i] = apply_common_rewrites(arg(p,i),arg(q,i),arg(r,i),rules); - return clone(p,args); - } - - ast apply_all_rewrites(const ast &p, const ast &q, const ast &r){ - if(q == r) - return p; - if(p == q) - return r; - if(sym(p) != sym(q) || sym(q) != sym(r)) - throw rewrites_failed(); - int nargs = num_args(p); - if(nargs != num_args(q) || nargs != num_args(r)) - throw rewrites_failed(); - std::vector args; args.resize(nargs); - for(int i = 0; i < nargs; i++) - args[i] = apply_all_rewrites(arg(p,i),arg(q,i),arg(r,i)); - return clone(p,args); - } - - ast delta(const ast &x, const ast &y){ - if(op(x) != op(y) || (op(x) == Uninterpreted && sym(x) != sym(y)) || num_args(x) != num_args(y)) - return make(Equal,x,y); - ast res = mk_true(); - int nargs = num_args(x); - for(int i = 0; i < nargs; i++) - res = my_and(res,delta(arg(x,i),arg(y,i))); - return res; - } - - bool diff_rec(LitType t, const ast &p, const ast &q, ast &pd, ast &qd){ - if(p == q) - return false; - if(term_in_vocab(t,p) && term_in_vocab(t,q)){ - pd = p; - qd = q; - return true; - } - else { - if(sym(p) != sym(q)) return false; - int nargs = num_args(p); - if(num_args(q) != nargs) return false; - for(int i = 0; i < nargs; i++) - if(diff_rec(t,arg(p,i),arg(q,i),pd,qd)) - return true; - return false; - } - } - - void diff(LitType t, const ast &p, const ast &q, ast &pd, ast &qd){ - if(!diff_rec(t,p,q,pd,qd)) - throw cannot_simplify(); - } - - bool apply_diff_rec(LitType t, const ast &inp, const ast &p, const ast &q, ast &out){ - if(p == q) - return false; - if(term_in_vocab(t,p) && term_in_vocab(t,q)){ - if(inp != p) - throw cannot_simplify(); - out = q; - return true; - } - else { - int nargs = num_args(p); - if(sym(p) != sym(q)) throw cannot_simplify(); - if(num_args(q) != nargs) throw cannot_simplify(); - if(sym(p) != sym(inp)) throw cannot_simplify(); - if(num_args(inp) != nargs) throw cannot_simplify(); - for(int i = 0; i < nargs; i++) - if(apply_diff_rec(t,arg(inp,i),arg(p,i),arg(q,i),out)) - return true; - return false; - } - } - - ast apply_diff(LitType t, const ast &inp, const ast &p, const ast &q){ - ast out; - if(!apply_diff_rec(t,inp,p,q,out)) - throw cannot_simplify(); - return out; - } - - bool merge_A_rewrites(const ast &A1, const ast &A2, ast &merged) { - if(arg(A1,1) == arg(A2,0)){ - merged = make(op(A1),arg(A1,0),arg(A2,1)); - return true; - } - ast diff1l, diff1r, diff2l, diff2r,diffBl,diffBr; - diff(LitA,arg(A1,0),arg(A1,1),diff1l,diff1r); - diff(LitA,arg(A2,0),arg(A2,1),diff2l,diff2r); - diff(LitB,arg(A1,1),arg(A2,0),diffBl,diffBr); - if(!term_common(diff2l) && !term_common(diffBr)){ - ast A1r = apply_diff(LitB,arg(A2,1),arg(A2,0),arg(A1,1)); - merged = make(op(A1),arg(A1,0),A1r); - return true; - } - if(!term_common(diff1r) && !term_common(diffBl)){ - ast A2l = apply_diff(LitB,arg(A1,0),arg(A1,1),arg(A2,0)); - merged = make(op(A1),A2l,arg(A2,1)); - return true; - } - return false; - } - - void collect_A_rewrites(const ast &t, std::vector &res){ - if(is_true(t)) - return; - if(sym(t) == concat){ - res.push_back(arg(t,0)); - collect_A_rewrites(arg(t,0),res); - return; - } - res.push_back(t); - } - - ast concat_A_rewrites(const std::vector &rew){ - if(rew.size() == 0) - return mk_true(); - ast res = rew[0]; - for(unsigned i = 1; i < rew.size(); i++) - res = make(concat,res,rew[i]); - return res; - } - - ast merge_concat_rewrites(const ast &A1, const ast &A2){ - std::vector rew; - collect_A_rewrites(A1,rew); - int first = rew.size(), last = first; // range that might need merging - collect_A_rewrites(A2,rew); - while(first > 0 && first < (int)rew.size() && first <= last){ - ast merged; - if(merge_A_rewrites(rew[first-1],rew[first],merged)){ - rew[first] = merged; - first--; - rew.erase(rew.begin()+first); - last--; - if(first >= last) last = first+1; - } - else - first++; - } - return concat_A_rewrites(rew); - } - - ast sep_cond(const ast &t, ast &cond){ - if(op(t) == Implies){ - cond = my_and(cond,arg(t,0)); - return arg(t,1); - } - return t; - } - - - /* operations on term positions */ - - /** Finds the difference between two positions. If p1 < p2 (p1 is a - position below p2), returns -1 and sets diff to p2-p1 (the psath - from position p2 to position p1). If p2 < p1 (p2 is a position - below p1), returns 1 and sets diff to p1-p2 (the psath from - position p1 to position p2). If equal, return 0 and set diff to - top_pos. Else (if p1 and p2 are independent) returns 2 and - leaves diff unchanged. */ - - int pos_diff(const ast &p1, const ast &p2, ast &diff){ - if(p1 == top_pos && p2 != top_pos){ - diff = p2; - return 1; - } - if(p2 == top_pos && p1 != top_pos){ - diff = p1; - return -1; - } - if(p1 == top_pos && p2 == top_pos){ - diff = p1; - return 0; - } - if(arg(p1,0) == arg(p2,0)) // same argument position, recur - return pos_diff(arg(p1,1),arg(p2,1),diff); - return 2; - } - - /* return the position of pos in the argth argument */ - ast pos_add(int arg, const ast &pos){ - return make(add_pos,make_int(rational(arg)),pos); - } - - ast add_pos_to_end(const ast &pos, int i){ - if(pos == top_pos) - return pos_add(i,pos); - return make(add_pos,arg(pos,0),add_pos_to_end(arg(pos,1),i)); - } - - /* return the argument number of position, if not top */ - int pos_arg(const ast &pos){ - rational r; - if(is_numeral(arg(pos,0),r)) - return r.get_unsigned(); - throw iz3_exception("bad position!"); - } - - /* substitute y into position pos in x */ - ast subst_in_pos(const ast &x, const ast &pos, const ast &y){ - if(pos == top_pos) - return y; - int p = pos_arg(pos); - int nargs = num_args(x); - if(p >= 0 && p < nargs){ - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = i == p ? subst_in_pos(arg(x,i),arg(pos,1),y) : arg(x,i); - return clone(x,args); - } - throw iz3_exception("bad term position!"); - } - - ast diff_chain(LitType t, const ast &pos, const ast &x, const ast &y, const ast &prefix){ - int nargs = num_args(x); - if(x == y) return prefix; - if(sym(x) == sym(y) && nargs == num_args(y)){ - ast res = prefix; - for(int i = 0; i < nargs; i++) - res = diff_chain(t,pos_add(i,pos),arg(x,i),arg(y,i),res); - return res; - } - return chain_cons(prefix,make_rewrite(t,pos,mk_true(),make_equiv_rel(x,y))); - } - - /* operations on rewrites */ - ast make_rewrite(LitType t, const ast &pos, const ast &cond, const ast &equality){ -#if 0 - if(pos == top_pos && op(equality) == Iff && !is_true(arg(equality,0))) - throw iz3_exception("bad rewrite"); -#endif - if(!is_equivrel(equality)) - throw iz3_exception("bad rewrite"); - return make(t == LitA ? rewrite_A : rewrite_B, pos, cond, equality); - } - - ast rewrite_pos(const ast &rew){ - return arg(rew,0); - } - - ast rewrite_cond(const ast &rew){ - return arg(rew,1); - } - - ast rewrite_equ(const ast &rew){ - return arg(rew,2); - } - - ast rewrite_lhs(const ast &rew){ - return arg(arg(rew,2),0); - } - - ast rewrite_rhs(const ast &rew){ - return arg(arg(rew,2),1); - } - - /* operations on rewrite chains */ - - ast chain_cons(const ast &chain, const ast &elem){ - return make(concat,chain,elem); - } - - ast chain_rest(const ast &chain){ - return arg(chain,0); - } - - ast chain_last(const ast &chain){ - return arg(chain,1); - } - - ast rewrite_update_rhs(const ast &rew, const ast &pos, const ast &new_rhs, const ast &new_cond){ - ast foo = subst_in_pos(rewrite_rhs(rew),pos,new_rhs); - ast equality = arg(rew,2); - return make(sym(rew),rewrite_pos(rew),my_and(rewrite_cond(rew),new_cond),make(op(equality),arg(equality,0),foo)); - } - - ast rewrite_update_lhs(const ast &rew, const ast &pos, const ast &new_lhs, const ast &new_cond){ - ast foo = subst_in_pos(rewrite_lhs(rew),pos,new_lhs); - ast equality = arg(rew,2); - return make(sym(rew),rewrite_pos(rew),my_and(rewrite_cond(rew),new_cond),make(op(equality),foo,arg(equality,1))); - } - - bool is_common_rewrite(const ast &rew){ - return term_common(arg(rew,2)); - } - - bool is_right_mover(const ast &rew){ - return term_common(rewrite_lhs(rew)) && !term_common(rewrite_rhs(rew)); - } - - bool is_left_mover(const ast &rew){ - return term_common(rewrite_rhs(rew)) && !term_common(rewrite_lhs(rew)); - } - - bool same_side(const ast &rew1, const ast &rew2){ - return sym(rew1) == sym(rew2); - } - - bool is_rewrite_side(LitType t, const ast &rew){ - if(t == LitA) - return sym(rew) == rewrite_A; - return sym(rew) == rewrite_B; - } - - LitType rewrite_side(const ast &rew){ - return (sym(rew) == rewrite_A) ? LitA : LitB; - } - - ast rewrite_to_formula(const ast &rew){ - return my_implies(arg(rew,1),arg(rew,2)); - } - - // make rewrite rew condition on rewrite cond - ast rewrite_conditional(const ast &cond, const ast &rew){ - ast cf = rewrite_to_formula(cond); - return make(sym(rew),arg(rew,0),my_and(arg(rew,1),cf),arg(rew,2)); - } - - ast reverse_rewrite(const ast &rew){ - ast equ = arg(rew,2); - return make(sym(rew),arg(rew,0),arg(rew,1),make(op(equ),arg(equ,1),arg(equ,0))); - } - - ast rewrite_pos_add(int apos, const ast &rew){ - return make(sym(rew),pos_add(apos,arg(rew,0)),arg(rew,1),arg(rew,2)); - } - - ast rewrite_pos_set(const ast &pos, const ast &rew){ - return make(sym(rew),pos,arg(rew,1),arg(rew,2)); - } - - ast rewrite_up(const ast &rew){ - return make(sym(rew),arg(arg(rew,0),1),arg(rew,1),arg(rew,2)); - } - - /** Adds a rewrite to a chain of rewrites, keeping the chain in - normal form. An empty chain is represented by true.*/ - - ast add_rewrite_to_chain(const ast &chain, const ast &rewrite){ - if(is_true(chain)) - return chain_cons(chain,rewrite); - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(same_side(last,rewrite)){ - ast p1 = rewrite_pos(last); - ast p2 = rewrite_pos(rewrite); - ast diff; - switch(pos_diff(p1,p2,diff)){ - case 1: { - ast absorb = rewrite_update_rhs(last,diff,rewrite_rhs(rewrite),rewrite_cond(rewrite)); - return add_rewrite_to_chain(rest,absorb); - } - case 0: - case -1: { - ast absorb = rewrite_update_lhs(rewrite,diff,rewrite_lhs(last),rewrite_cond(last)); - return add_rewrite_to_chain(rest,absorb); - } - default: {// independent case - bool rm = is_right_mover(last); - bool lm = is_left_mover(rewrite); - if((lm && !rm) || (rm && !lm)) - return chain_swap(rest,last,rewrite); - } - } - } - else { - if(is_left_mover(rewrite)){ - if(is_common_rewrite(last)) - return add_rewrite_to_chain(chain_cons(rest,flip_rewrite(last)),rewrite); - if(!is_left_mover(last)) - return chain_swap(rest,last,rewrite); - } - if(is_right_mover(last)){ - if(is_common_rewrite(rewrite)) - return add_rewrite_to_chain(chain,flip_rewrite(rewrite)); - if(!is_right_mover(rewrite)) - return chain_swap(rest,last,rewrite); - } - } - return chain_cons(chain,rewrite); - } - - ast chain_swap(const ast &rest, const ast &last, const ast &rewrite){ - return chain_cons(add_rewrite_to_chain(rest,rewrite),last); - } - - ast flip_rewrite(const ast &rew){ - symb flip_sym = (sym(rew) == rewrite_A) ? rewrite_B : rewrite_A; - ast cf = rewrite_to_formula(rew); - return make(flip_sym,arg(rew,0),my_implies(arg(rew,1),cf),arg(rew,2)); - } - - /** concatenates two rewrite chains, keeping result in normal form. */ - - ast concat_rewrite_chain(const ast &chain1, const ast &chain2){ - if(is_true(chain2)) return chain1; - if(is_true(chain1)) return chain2; - ast foo = concat_rewrite_chain(chain1,chain_rest(chain2)); - return add_rewrite_to_chain(foo,chain_last(chain2)); - } - - /** reverse a chain of rewrites */ - - ast reverse_chain_rec(const ast &chain, const ast &prefix){ - if(is_true(chain)) - return prefix; - ast last = reverse_rewrite(chain_last(chain)); - ast rest = chain_rest(chain); - return reverse_chain_rec(rest,chain_cons(prefix,last)); - } - - ast reverse_chain(const ast &chain){ - return reverse_chain_rec(chain,mk_true()); - } - - bool is_equivrel_chain(const ast &chain){ - if(is_true(chain)) - return true; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_true(rest)) - return !is_true(rewrite_lhs(last)); - return is_equivrel_chain(rest); - } - - bool is_negation_chain(const ast &chain){ - if(is_true(chain)) - return false; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_true(rest)) - return op(rewrite_rhs(last)) == Not; - return is_negation_chain(rest); - } - - ast commute_negation_chain(const ast &chain){ - if(is_true(chain)) - return chain; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_true(rest)){ - ast old = rewrite_rhs(last); - if(!(op(old) == Not)) - throw iz3_exception("bad negative equality chain"); - ast equ = arg(old,0); - if(!is_equivrel(equ)) - throw iz3_exception("bad negative equality chain"); - last = rewrite_update_rhs(last,top_pos,make(Not,make(op(equ),arg(equ,1),arg(equ,0))),make(True)); - return chain_cons(rest,last); - } - ast pos = rewrite_pos(last); - if(pos == top_pos) - throw iz3_exception("bad negative equality chain"); - int idx = pos_arg(pos); - if(idx != 0) - throw iz3_exception("bad negative equality chain"); - pos = arg(pos,1); - if(pos == top_pos){ - ast lhs = rewrite_lhs(last); - ast rhs = rewrite_rhs(last); - if(op(lhs) != Equal || op(rhs) != Equal) - throw iz3_exception("bad negative equality chain"); - last = make_rewrite(rewrite_side(last),rewrite_pos(last),rewrite_cond(last), - make(Iff,make(Equal,arg(lhs,1),arg(lhs,0)),make(Equal,arg(rhs,1),arg(rhs,0)))); - } - else { - idx = pos_arg(pos); - if(idx == 0) - idx = 1; - else if(idx == 1) - idx = 0; - else - throw iz3_exception("bad negative equality chain"); - pos = pos_add(0,pos_add(idx,arg(pos,1))); - last = make_rewrite(rewrite_side(last),pos,rewrite_cond(last),rewrite_equ(last)); - } - return chain_cons(commute_negation_chain(rest),last); - } - - // split a rewrite chain into head and tail at last top-level rewrite - ast get_head_chain(const ast &chain, ast &tail, bool is_not = true){ - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast pos = rewrite_pos(last); - if(pos == top_pos || (is_not && arg(pos,1) == top_pos)){ - tail = mk_true(); - return chain; - } - if(is_true(rest)) - throw iz3_exception("bad rewrite chain"); - ast head = get_head_chain(rest,tail,is_not); - tail = chain_cons(tail,last); - return head; - } - - bool has_mixed_summands(const ast &e){ - if(op(e) == Plus){ - int nargs = num_args(e); - for(int i = 0; i < nargs; i++) - if(has_mixed_summands(arg(e,i))) - return true; - return false; - } - return get_term_type(e) == LitMixed; - } - - // split a rewrite chain into head and tail at last sum with no mixed sumands - ast get_right_movers(const ast &chain, const ast &rhs, ast &tail, ast &mid){ - if(is_true(chain) || !has_mixed_summands(rhs)){ - mid = rhs; - tail = mk_true(); - return chain; - } - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast mm = subst_in_pos(rhs,rewrite_pos(last),rewrite_lhs(last)); - ast res = get_right_movers(rest,mm,tail,mid); - tail = chain_cons(tail,last); - return res; - } - - // split a rewrite chain into head and tail at first sum with no mixed sumands - ast get_left_movers(const ast &chain, const ast &lhs, ast &tail, ast &mid){ - if(is_true(chain)){ - mid = lhs; - if(!has_mixed_summands(lhs)){ - tail = mk_true(); - return chain; - } - return ast(); - } - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast res = get_left_movers(rest,lhs,tail,mid); - if(res.null()){ - mid = subst_in_pos(mid,rewrite_pos(last),rewrite_rhs(last)); - if(get_term_type(mid) != LitMixed){ - tail = mk_true(); - return chain; - } - return ast(); - } - tail = chain_cons(tail,last); - return res; - } - - - struct cannot_split: public iz3_exception { - cannot_split(): iz3_exception("cannot_split") {} - }; - - /** Split a chain of rewrites two chains, operating on positions 0 and 1. - Fail if any rewrite in the chain operates on top position. */ - void split_chain_rec(const ast &chain, ast *res){ - if(is_true(chain)) - return; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - split_chain_rec(rest,res); - ast pos = rewrite_pos(last); - if(pos == top_pos){ - if(rewrite_lhs(last) == rewrite_rhs(last)) - return; // skip if it's a noop - throw cannot_split(); - } - int arg = pos_arg(pos); - if(arg<0 || arg > 1) - throw cannot_split(); - res[arg] = chain_cons(res[arg],rewrite_up(last)); - } - - void split_chain(const ast &chain, ast *res){ - res[0] = res[1] = mk_true(); - split_chain_rec(chain,res); - } - - ast extract_rewrites(const ast &chain, const ast &pos){ - if(is_true(chain)) - return chain; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast new_rest = extract_rewrites(rest,pos); - ast p1 = rewrite_pos(last); - ast diff; - switch(pos_diff(p1,pos,diff)){ - case -1: { - ast new_last = rewrite_pos_set(diff, last); - return chain_cons(new_rest,new_last); - } - case 1: - if(rewrite_lhs(last) != rewrite_rhs(last)) - throw iz3_exception("bad rewrite chain"); - break; - default:; - } - return new_rest; - } - - ast down_chain(const ast &chain){ - ast split[2]; - split_chain(chain,split); - return split[0]; - } - - ast chain_conditions(LitType t, const ast &chain){ - if(is_true(chain)) - return mk_true(); - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast cond = chain_conditions(t,rest); - if(is_rewrite_side(t,last)) - cond = my_and(cond,rewrite_cond(last)); - return cond; - } - - ast chain_formulas(LitType t, const ast &chain){ - if(is_true(chain)) - return mk_true(); - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast cond = chain_formulas(t,rest); - if(is_rewrite_side(t,last)) - cond = my_and(cond,rewrite_equ(last)); - return cond; - } - - - bool rewrites_from_to(const ast &chain, const ast &lhs, const ast &rhs){ - if(is_true(chain)) - return lhs == rhs; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast mid = subst_in_pos(rhs,rewrite_pos(last),rewrite_lhs(last)); - return rewrites_from_to(rest,lhs,mid); - } - - struct bad_ineq_inference: public iz3_exception { - bad_ineq_inference(): iz3_exception("bad_ineq_inference") {} - }; - - ast chain_ineqs(opr comp_op, LitType t, const ast &chain, const ast &lhs, const ast &rhs){ - if(is_true(chain)){ - if (lhs != rhs) { - TRACE("duality", print_expr(tout, lhs); tout << " "; print_expr(tout, rhs); tout << "\n";); - throw bad_ineq_inference(); - } - return make(Leq,make_int(rational(0)),make_int(rational(0))); - } - TRACE("duality", print_expr(tout, chain); print_expr(tout << "\n", lhs); tout << " "; print_expr(tout, rhs); tout << "\n";); - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast mid = subst_in_pos(rhs,rewrite_pos(last),rewrite_lhs(last)); - ast cond = chain_ineqs(comp_op,t,rest,lhs,mid); - if(is_rewrite_side(t,last)){ - ast diff; - if(comp_op == Leq) diff = make(Sub,rhs,mid); - else diff = make(Sub,mid,rhs); - ast foo = make(Leq,make_int("0"),z3_simplify(diff)); - if(is_true(cond)) - cond = foo; - else { - linear_comb(cond,make_int(rational(1)),foo); - cond = simplify_ineq(cond); - } - } - return cond; - } - - ast ineq_to_lhs(const ast &ineq){ - ast s = make(Leq,make_int(rational(0)),make_int(rational(0))); - linear_comb(s,make_int(rational(1)),ineq); - return simplify_ineq(s); - } - - void eq_from_ineq(const ast &ineq, ast &lhs, ast &rhs){ - // ast s = ineq_to_lhs(ineq); - // ast srhs = arg(s,1); - ast srhs = arg(ineq,0); - if(op(srhs) == Plus && num_args(srhs) == 2 && arg(ineq,1) == make_int(rational(0))){ - lhs = arg(srhs,0); - rhs = arg(srhs,1); - // if(op(lhs) == Times) - // std::swap(lhs,rhs); - if(op(rhs) == Times){ - rhs = arg(rhs,1); - // if(op(ineq) == Leq) - // std::swap(lhs,rhs); - return; - } - } - if(op(ineq) == Leq || op(ineq) == Geq){ - lhs = srhs; - rhs = arg(ineq,1); - return; - } - throw iz3_exception("bad ineq"); - } - - ast chain_pos_add(int arg, const ast &chain){ - if(is_true(chain)) - return mk_true(); - ast last = rewrite_pos_add(arg,chain_last(chain)); - ast rest = chain_pos_add(arg,chain_rest(chain)); - return chain_cons(rest,last); - } - - ast apply_rewrite_chain(const ast &t, const ast &chain){ - if(is_true(chain)) - return t; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast mid = apply_rewrite_chain(t,rest); - ast res = subst_in_pos(mid,rewrite_pos(last),rewrite_rhs(last)); - return res; - } - - ast drop_rewrites(LitType t, const ast &chain, ast &remainder){ - if(!is_true(chain)){ - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_rewrite_side(t,last)){ - ast res = drop_rewrites(t,rest,remainder); - remainder = chain_cons(remainder,last); - return res; - } - } - remainder = mk_true(); - return chain; - } - - // Normalization chains - - ast cons_normal(const ast &first, const ast &rest){ - return make(normal_chain,first,rest); - } - - ast normal_first(const ast &t){ - return arg(t,0); - } - - ast normal_rest(const ast &t){ - return arg(t,1); - } - - ast normal_lhs(const ast &t){ - return arg(arg(t,0),0); - } - - ast normal_rhs(const ast &t){ - return arg(arg(t,0),1); - } - - ast normal_proof(const ast &t){ - return arg(t,1); - } - - ast make_normal_step(const ast &lhs, const ast &rhs, const ast &proof){ - return make(normal_step,make_equiv(lhs,rhs),proof); - } - - ast make_normal(const ast &ineq, const ast &nrml){ - if(!is_ineq(ineq)) - throw iz3_exception("what?"); - return make(normal,ineq,nrml); - } - - ast fix_normal(const ast &lhs, const ast &rhs, const ast &proof){ - LitType lhst = get_term_type(lhs); - LitType rhst = get_term_type(rhs); - if(lhst == LitMixed && (rhst != LitMixed || ast_id(lhs) < ast_id(rhs))) - return make_normal_step(lhs,rhs,proof); - if(rhst == LitMixed && (lhst != LitMixed || ast_id(rhs) < ast_id(lhs))) - return make_normal_step(rhs,lhs,reverse_chain(proof)); - throw iz3_exception("help!"); - } - - ast chain_side_proves(LitType side, const ast &chain){ - LitType other_side = side == LitA ? LitB : LitA; - return my_and(chain_conditions(other_side,chain),my_implies(chain_conditions(side,chain),chain_formulas(side,chain))); - } - - // Merge two normalization chains - ast merge_normal_chains_rec(const ast &chain1, const ast &chain2, hash_map &trans, ast &Aproves, ast &Bproves){ - if(is_true(chain1)) - return chain2; - if(is_true(chain2)) - return chain1; - ast f1 = normal_first(chain1); - ast f2 = normal_first(chain2); - ast lhs1 = normal_lhs(f1); - ast lhs2 = normal_lhs(f2); - int id1 = ast_id(lhs1); - int id2 = ast_id(lhs2); - if(id1 < id2) - return cons_normal(f1,merge_normal_chains_rec(normal_rest(chain1),chain2,trans,Aproves,Bproves)); - if(id2 < id1) - return cons_normal(f2,merge_normal_chains_rec(chain1,normal_rest(chain2),trans,Aproves,Bproves)); - ast rhs1 = normal_rhs(f1); - ast rhs2 = normal_rhs(f2); - LitType t1 = get_term_type(rhs1); - LitType t2 = get_term_type(rhs2); - int tid1 = ast_id(rhs1); - int tid2 = ast_id(rhs2); - ast pf1 = normal_proof(f1); - ast pf2 = normal_proof(f2); - ast new_normal; - if(t1 == LitMixed && (t2 != LitMixed || tid2 > tid1)){ - ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2); - new_normal = f2; - trans[rhs1] = make_normal_step(rhs1,rhs2,new_proof); - } - else if(t2 == LitMixed && (t1 != LitMixed || tid1 > tid2)) - return merge_normal_chains_rec(chain2,chain1,trans,Aproves,Bproves); - else if(t1 == LitA && t2 == LitB){ - ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2); - ast Bproof, Aproof = drop_rewrites(LitB,new_proof,Bproof); - ast mcA = chain_side_proves(LitB,Aproof); - Bproves = my_and(Bproves,mcA); - ast mcB = chain_side_proves(LitA,Bproof); - Aproves = my_and(Aproves,mcB); - ast rep = apply_rewrite_chain(rhs1,Aproof); - new_proof = concat_rewrite_chain(pf1,Aproof); - new_normal = make_normal_step(lhs1,rep,new_proof); - ast A_normal = make_normal_step(rhs1,rep,Aproof); - ast res = cons_normal(new_normal,merge_normal_chains_rec(normal_rest(chain1),normal_rest(chain2),trans,Aproves,Bproves)); - res = merge_normal_chains_rec(res,cons_normal(A_normal,make(True)),trans,Aproves,Bproves); - return res; - } - else if(t1 == LitB && t2 == LitA) - return merge_normal_chains_rec(chain2,chain1,trans,Aproves,Bproves); - else if(t1 == LitA) { - ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2); - ast mc = chain_side_proves(LitB,new_proof); - Bproves = my_and(Bproves,mc); - new_normal = f1; // choice is arbitrary - } - else { /* t1 = t2 = LitB */ - ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2); - ast mc = chain_side_proves(LitA,new_proof); - Aproves = my_and(Aproves,mc); - new_normal = f1; // choice is arbitrary - } - return cons_normal(new_normal,merge_normal_chains_rec(normal_rest(chain1),normal_rest(chain2),trans,Aproves,Bproves)); - } - - ast trans_normal_chain(const ast &chain, hash_map &trans){ - if(is_true(chain)) - return chain; - ast f = normal_first(chain); - ast r = normal_rest(chain); - r = trans_normal_chain(r,trans); - ast rhs = normal_rhs(f); - hash_map::iterator it = trans.find(rhs); - ast new_normal; - if(it != trans.end() && get_term_type(normal_lhs(f)) == LitMixed){ - const ast &f2 = it->second; - ast pf = concat_rewrite_chain(normal_proof(f),normal_proof(f2)); - new_normal = make_normal_step(normal_lhs(f),normal_rhs(f2),pf); - } - else - new_normal = f; - if(get_term_type(normal_lhs(f)) == LitMixed) - trans[normal_lhs(f)] = new_normal; - return cons_normal(new_normal,r); - } - - ast merge_normal_chains(const ast &chain1, const ast &chain2, ast &Aproves, ast &Bproves){ - hash_map trans; - ast res = merge_normal_chains_rec(chain1,chain2,trans,Aproves,Bproves); - res = trans_normal_chain(res,trans); - return res; - } - - bool destruct_cond_ineq(ast t, ast &Aproves, ast &Bproves, ast&ineq){ - if(op(t) == And){ - Aproves = arg(t,0); - t = arg(t,1); - } - else - Aproves = mk_true(); - if(op(t) == Implies){ - Bproves = arg(t,0); - t = arg(t,1); - } - else - Bproves = mk_true(); - if(is_normal_ineq(t)){ - ineq = t; - return true; - } - return false; - } - - ast cons_cond_ineq(const ast &Aproves, const ast &Bproves, const ast &ineq){ - return my_and(Aproves,my_implies(Bproves,ineq)); - } - - ast normalize(const ast &ct){ - ast Aproves,Bproves,t; - if(!destruct_cond_ineq(ct,Aproves,Bproves,t)) - return ct; - if(sym(t) != normal) - return ct; - ast chain = arg(t,1); - hash_map map; - for(ast c = chain; !is_true(c); c = normal_rest(c)){ - ast first = normal_first(c); - ast lhs = normal_lhs(first); - ast rhs = normal_rhs(first); - map[lhs] = rhs; - } - ast res = subst(map,arg(t,0)); - return cons_cond_ineq(Aproves,Bproves,res); - } - - /** Make an assumption node. The given clause is assumed in the given frame. */ - node make_assumption(int frame, const std::vector &assumption) override { - if(!weak){ - if(pv->in_range(frame,rng)){ - std::vector itp_clause; - for(unsigned i = 0; i < assumption.size(); i++) - if(get_term_type(assumption[i]) != LitA) - itp_clause.push_back(assumption[i]); - ast res = my_or(itp_clause); - return res; - } - else { - return mk_true(); - } - } - else { - if(pv->in_range(frame,rng)){ - return mk_false(); - } - else { - std::vector itp_clause; - for(unsigned i = 0; i < assumption.size(); i++) - if(get_term_type(assumption[i]) != LitB) - itp_clause.push_back(assumption[i]); - ast res = my_or(itp_clause); - return mk_not(res); - } - } - } - - ast make_local_rewrite(LitType t, const ast &p){ - ast rew = is_equivrel(p) ? p : make(Iff,mk_true(),p); -#if 0 - if(op(rew) == Iff && !is_true(arg(rew,0))) - return diff_chain(t,top_pos,arg(rew,0),arg(rew,1), mk_true()); -#endif - return chain_cons(mk_true(),make_rewrite(t, top_pos, mk_true(), rew)); - } - - ast triv_interp(const symb &rule, const std::vector &premises, int mask_in){ - std::vector ps; ps.resize(premises.size()); - std::vector conjs; - int mask = 0; - for(unsigned i = 0; i < ps.size(); i++){ - ast p = premises[i]; - LitType t = get_term_type(p); - switch(t){ - case LitA: - case LitB: - ps[i] = make_local_rewrite(t,p); - break; - default: - ps[i] = get_placeholder(p); // can only prove consequent! - if(mask_in & (1 << i)) - mask |= (1 << conjs.size()); - conjs.push_back(p); - } - } - ast ref = make(rule,ps); - ast res = make_contra_node(ref,conjs,mask); - return res; - } - - ast triv_interp(const symb &rule, const ast &p0, const ast &p1, const ast &p2, int mask){ - std::vector ps; ps.resize(3); - ps[0] = p0; - ps[1] = p1; - ps[2] = p2; - return triv_interp(rule,ps,mask); - } - - /** Make a modus-ponens node. This takes derivations of |- x - and |- x = y and produces |- y */ - - node make_mp(const ast &p_eq_q, const ast &prem1, const ast &prem2) override { - - /* Interpolate the axiom p, p=q -> q */ - ast p = arg(p_eq_q,0); - ast q = arg(p_eq_q,1); - ast itp; - if(get_term_type(p_eq_q) == LitMixed){ - int mask = 1 << 2; - if(op(p) == Not && is_equivrel(arg(p,0))) - mask |= 1; // we may need to run this rule backward if first premise is negative equality - itp = triv_interp(modpon,p,p_eq_q,mk_not(q),mask); - } - else { - if(get_term_type(p) == LitA){ - if(get_term_type(q) == LitA){ - if(op(q) == Or) - itp = make_assumption(rng.hi,args(q)); - else - itp = mk_false(); - } - else { - if(get_term_type(p_eq_q) == LitA) - itp = q; - else - throw proof_error(); - } - } - else { - if(get_term_type(q) == LitA){ - if(get_term_type(make(Equal,p,q)) == LitA) - itp = mk_not(p); - else - throw proof_error(); - } - else - itp = mk_true(); - } - } - - /* Resolve it with the premises */ - std::vector conc; conc.push_back(q); conc.push_back(mk_not(p_eq_q)); - itp = make_resolution(p,conc,itp,prem1); - conc.pop_back(); - itp = make_resolution(p_eq_q,conc,itp,prem2); - return itp; - } - - ast capture_localization(ast e){ - // #define CAPTURE_LOCALIZATION -#ifdef CAPTURE_LOCALIZATION - for(int i = localization_vars.size() - 1; i >= 0; i--){ - LocVar &lv = localization_vars[i]; - if(occurs_in(lv.var,e)){ - symb q = (pv->in_range(lv.frame,rng)) ? sexists : sforall; - e = make(q,make(Equal,lv.var,lv.term),e); // use Equal because it is polymorphic - } - } -#endif - return e; - } - - /** Make an axiom node. The conclusion must be an instance of an axiom. */ - node make_axiom(const std::vector &conclusion, prover::range frng) override { - int nargs = conclusion.size(); - std::vector largs(nargs); - std::vector eqs; - std::vector pfs; - - for(int i = 0; i < nargs; i++){ - ast argpf; - ast lit = conclusion[i]; - largs[i] = localize_term(lit,frng,argpf); - frng = pv->range_glb(frng,pv->ast_scope(largs[i])); - if(largs[i] != lit){ - eqs.push_back(make_equiv(largs[i],lit)); - pfs.push_back(argpf); - } - } - - int frame = pv->range_max(frng); - ast itp = make_assumption(frame,largs); - - for(unsigned i = 0; i < eqs.size(); i++) - itp = make_mp(eqs[i],itp,pfs[i]); - return capture_localization(itp); - } - - node make_axiom(const std::vector &conclusion) override { - return make_axiom(conclusion,pv->range_full()); - } - - /** Make a Contra node. This rule takes a derivation of the form - Gamma |- False and produces |- \/~Gamma. */ - - node make_contra(node prem, const std::vector &conclusion) override { - return prem; - } - - /** Make hypothesis. Creates a node of the form P |- P. */ - - node make_hypothesis(const ast &P) override { - if(is_not(P)) - return make_hypothesis(arg(P,0)); - switch(get_term_type(P)){ - case LitA: - return mk_false(); - case LitB: - return mk_true(); - default: // mixed hypothesis - switch(op(P)){ - case Geq: - case Leq: - case Gt: - case Lt: { - ast zleqz = make(Leq,make_int("0"),make_int("0")); - ast fark1 = make(sum,zleqz,make_int("1"),get_placeholder(P)); - ast fark2 = make(sum,fark1,make_int("1"),get_placeholder(mk_not(P))); - ast res = make(And,make(contra,fark2,mk_false()), - make(contra,get_placeholder(mk_not(P)),P), - make(contra,get_placeholder(P),mk_not(P))); - return res; - } - default: { - ast em = make(exmid,P,get_placeholder(P),get_placeholder(mk_not(P))); - ast res = make(And,make(contra,em,mk_false()), - make(contra,get_placeholder(mk_not(P)),P), - make(contra,get_placeholder(P),mk_not(P))); - return res; - } - } - } - } - - /** Make a Reflexivity node. This rule produces |- x = x */ - - node make_reflexivity(ast con) override { - if(get_term_type(con) == LitA) - return mk_false(); - if(get_term_type(con) == LitB) - return mk_true(); - ast itp = make(And,make(contra,no_proof,mk_false()), - make(contra,mk_true(),mk_not(con))); - return itp; - } - - /** Make a Symmetry node. This takes a derivation of |- x = y and - produces | y = x. Ditto for ~(x=y) */ - - node make_symmetry(ast con, const ast &premcon, node prem) override { -#if 0 - ast x = arg(con,0); - ast y = arg(con,1); - ast p = make(op(con),y,x); -#endif - if(get_term_type(con) != LitMixed) - return prem; // symmetry shmymmetry... - ast em = make(exmid,con,make(symm,get_placeholder(premcon)),get_placeholder(mk_not(con))); - ast itp = make(And,make(contra,em,mk_false()), - make(contra,make(symm,get_placeholder(mk_not(con))),premcon), - make(contra,make(symm,get_placeholder(premcon)),mk_not(con))); - - std::vector conc; conc.push_back(con); - itp = make_resolution(premcon,conc,itp,prem); - return itp; - } - - ast make_equiv_rel(const ast &x, const ast &y){ - if(is_bool_type(get_type(x))) - return make(Iff,x,y); - return make(Equal,x,y); - } - - /** Make a transitivity node. This takes derivations of |- x = y - and |- y = z produces | x = z */ - - node make_transitivity(const ast &x, const ast &y, const ast &z, node prem1, node prem2) override { - - /* Interpolate the axiom x=y,y=z,-> x=z */ - ast p = make_equiv_rel(x,y); - ast q = make_equiv_rel(y,z); - ast r = make_equiv_rel(x,z); - ast equiv = make(Iff,p,r); - ast itp; - - itp = make_congruence(q,equiv,prem2); - itp = make_mp(equiv,prem1,itp); - - return itp; - - } - - /** Make a congruence node. This takes derivations of |- x_i = y_i - and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */ - - node make_congruence(const ast &p, const ast &con, const ast &prem1) override { - ast x = arg(p,0), y = arg(p,1); - ast itp; - LitType con_t = get_term_type(con); - if(get_term_type(p) == LitA){ - if(con_t == LitA) - itp = mk_false(); - else if(con_t == LitB) - itp = p; - else - itp = make_mixed_congruence(x, y, p, con, prem1); - } - else { - if(con_t == LitA) - itp = mk_not(p); - else{ - if(con_t == LitB) - itp = mk_true(); - else - itp = make_mixed_congruence(x, y, p, con, prem1); - } - } - std::vector conc; conc.push_back(con); - itp = make_resolution(p,conc,itp,prem1); - return itp; - } - - int find_congruence_position(const ast &p, const ast &con){ - // find the argument position of x and y - const ast &x = arg(p,0); - const ast &y = arg(p,1); - int nargs = num_args(arg(con,0)); - for(int i = 0; i < nargs; i++) - if(x == arg(arg(con,0),i) && y == arg(arg(con,1),i)) - return i; - throw proof_error(); - } - - /** Make a congruence node. This takes derivations of |- x_i1 = y_i1, |- x_i2 = y_i2,... - and produces |- f(...x_i1...x_i2...) = f(...y_i1...y_i2...) */ - - node make_congruence(const std::vector &p, const ast &con, const std::vector &prems) override { - if(p.size() == 0) - throw proof_error(); - if(p.size() == 1) - return make_congruence(p[0],con,prems[0]); - ast thing = con; - ast res = mk_true(); - for(unsigned i = 0; i < p.size(); i++){ - int pos = find_congruence_position(p[i],thing); - ast next = subst_in_arg_pos(pos,arg(p[i],1),arg(thing,0)); - ast goal = make(op(thing),arg(thing,0),next); - ast equa = make_congruence(p[i],goal,prems[i]); - if(i == 0) - res = equa; - else { - ast trace = make(op(con),arg(con,0),arg(thing,0)); - ast equiv = make(Iff,trace,make(op(trace),arg(trace,0),next)); - ast foo = make_congruence(goal,equiv,equa); - res = make_mp(equiv,res,foo); - } - thing = make(op(thing),next,arg(thing,1)); - } - return res; - } - - /* Interpolate a mixed congruence axiom. */ - - virtual ast make_mixed_congruence(const ast &x, const ast &y, const ast &p, const ast &con, const ast &prem1){ - ast foo = p; - std::vector conjs; - LitType t = get_term_type(foo); - switch(t){ - case LitA: - case LitB: - foo = make_local_rewrite(t,foo); - break; - case LitMixed: - conjs.push_back(foo); - foo = get_placeholder(foo); - } - // find the argument position of x and y - int pos = -1; - int nargs = num_args(arg(con,0)); - for(int i = 0; i < nargs; i++) - if(x == arg(arg(con,0),i) && y == arg(arg(con,1),i)) - pos = i; - if(pos == -1) - throw proof_error(); - ast bar = make(cong,foo,make_int(rational(pos)),get_placeholder(mk_not(con))); - conjs.push_back(mk_not(con)); - return make_contra_node(bar,conjs); - } - - ast subst_in_arg_pos(int pos, ast term, ast app){ - std::vector args; - get_args(app,args); - args[pos] = term; - return clone(app,args); - } - - /** Make a farkas proof node. */ - - node make_farkas(ast con, const std::vector &prems, const std::vector &prem_cons, - const std::vector &coeffs) override { - - /* Compute the interpolant for the clause */ - - ast zero = make_int("0"); - std::vector conjs; - ast thing = make(Leq,zero,zero); - for(unsigned i = 0; i < prem_cons.size(); i++){ - const ast &lit = prem_cons[i]; - if(get_term_type(lit) == LitA) - // Farkas rule seems to assume strict integer inequalities are rounded - linear_comb(thing,coeffs[i],lit,true /*round_off*/); - } - thing = simplify_ineq(thing); - for(unsigned i = 0; i < prem_cons.size(); i++){ - const ast &lit = prem_cons[i]; - if(get_term_type(lit) == LitMixed){ - thing = make(sum,thing,coeffs[i],get_placeholder(lit)); - conjs.push_back(lit); - } - } - thing = make_contra_node(thing,conjs); - - /* Resolve it with the premises */ - std::vector conc; conc.resize(prem_cons.size()); - for(unsigned i = 0; i < prem_cons.size(); i++) - conc[prem_cons.size()-i-1] = prem_cons[i]; - for(unsigned i = 0; i < prem_cons.size(); i++){ - thing = make_resolution(prem_cons[i],conc,thing,prems[i]); - conc.pop_back(); - } - return thing; - } - - /** Set P to P + cQ, where P and Q are linear inequalities. Assumes P is 0 <= y or 0 < y. */ - - void linear_comb(ast &P, const ast &c, const ast &Q, bool round_off = false){ - ast Qrhs; - bool qstrict = false; - if(is_not(Q)){ - ast nQ = arg(Q,0); - switch(op(nQ)){ - case Gt: - Qrhs = make(Sub,arg(nQ,1),arg(nQ,0)); - break; - case Lt: - Qrhs = make(Sub,arg(nQ,0),arg(nQ,1)); - break; - case Geq: - Qrhs = make(Sub,arg(nQ,1),arg(nQ,0)); - qstrict = true; - break; - case Leq: - Qrhs = make(Sub,arg(nQ,0),arg(nQ,1)); - qstrict = true; - break; - default: - throw proof_error(); - } - } - else { - switch(op(Q)){ - case Leq: - Qrhs = make(Sub,arg(Q,1),arg(Q,0)); - break; - case Geq: - Qrhs = make(Sub,arg(Q,0),arg(Q,1)); - break; - case Lt: - Qrhs = make(Sub,arg(Q,1),arg(Q,0)); - qstrict = true; - break; - case Gt: - Qrhs = make(Sub,arg(Q,0),arg(Q,1)); - qstrict = true; - break; - default: - throw proof_error(); - } - } -#if 0 - bool pstrict = op(P) == Lt, strict = pstrict || qstrict; - if(pstrict && qstrict && round_off) - Qrhs = make(Sub,Qrhs,make_int(rational(1))); -#else - if (round_off && get_type(Qrhs) != int_type()) - round_off = false; - bool pstrict = op(P) == Lt; - if(qstrict && round_off && (pstrict || !(c == make_int(rational(1))))){ - Qrhs = make(Sub,Qrhs,make_int(rational(1))); - qstrict = false; - } - Qrhs = make(Times,c,Qrhs); - bool strict = pstrict || qstrict; -#endif - if(strict) - P = make(Lt,arg(P,0),make(Plus,arg(P,1),Qrhs)); - else - P = make(Leq,arg(P,0),make(Plus,arg(P,1),Qrhs)); - } - - /* Make an axiom instance of the form |- x<=y, y<= x -> x =y */ - node make_leq2eq(ast x, ast y, const ast &xleqy, const ast &yleqx) override { - ast con = make(Equal,x,y); - ast itp; - switch(get_term_type(con)){ - case LitA: - itp = mk_false(); - break; - case LitB: - itp = mk_true(); - break; - default: { // mixed equality - if(get_term_type(x) == LitMixed || get_term_type(y) == LitMixed){ - if(y == make_int(rational(0)) && op(x) == Plus && num_args(x) == 2){ - // std::cerr << "WARNING: untested case in leq2eq\n"; - } - else { - // std::cerr << "WARNING: mixed term in leq2eq\n"; - std::vector lits; - lits.push_back(con); - lits.push_back(make(Not,xleqy)); - lits.push_back(make(Not,yleqx)); - return make_axiom(lits); - } - } - std::vector conjs; conjs.resize(3); - conjs[0] = mk_not(con); - conjs[1] = xleqy; - conjs[2] = yleqx; - itp = make_contra_node(make(leq2eq, - get_placeholder(mk_not(con)), - get_placeholder(xleqy), - get_placeholder(yleqx)), - conjs,1); - } - } - return itp; - } - - /* Make an axiom instance of the form |- x = y -> x <= y */ - node make_eq2leq(ast x, ast y, const ast &xleqy) override { - ast itp; - switch(get_term_type(xleqy)){ - case LitA: - itp = mk_false(); - break; - case LitB: - itp = mk_true(); - break; - default: { // mixed equality - std::vector conjs; conjs.resize(2); - conjs[0] = make(Equal,x,y); - conjs[1] = mk_not(xleqy); - itp = make(eq2leq,get_placeholder(conjs[0]),get_placeholder(conjs[1])); - itp = make_contra_node(itp,conjs,2); - } - } - return itp; - } - - - /* Make an inference of the form t <= c |- t/d <= floor(c/d) where t - is an affine term divisble by d and c is an integer constant */ - node make_cut_rule(const ast &tleqc, const ast &d, const ast &con, const ast &prem) override { - ast itp = mk_false(); - switch(get_term_type(con)){ - case LitA: - itp = mk_false(); - break; - case LitB: - itp = mk_true(); - break; - default: { - std::vector conjs; conjs.resize(2); - conjs[0] = tleqc; - conjs[1] = mk_not(con); - itp = make(sum,get_placeholder(conjs[0]),d,get_placeholder(conjs[1])); - itp = make_contra_node(itp,conjs); - } - } - std::vector conc; conc.push_back(con); - itp = make_resolution(tleqc,conc,itp,prem); - return itp; - } - - - - // create a fresh variable for localization - ast fresh_localization_var(const ast &term, int frame){ - std::ostringstream s; - s << "%" << (localization_vars.size()); - ast var = make_var(s.str().c_str(),get_type(term)); - pv->sym_range(sym(var)) = pv->range_full(); // make this variable global - localization_vars.push_back(LocVar(var,term,frame)); - return var; - } - - struct LocVar { // localization vars - ast var; // a fresh variable - ast term; // term it represents - int frame; // frame in which it's defined - LocVar(ast v, ast t, int f){var=v;term=t;frame=f;} - }; - - std::vector localization_vars; // localization vars in order of creation - - struct locmaps { - hash_map localization_map; // maps terms to their localization vars - hash_map localization_pf_map; // maps terms to proofs of their localizations - }; - - hash_map localization_maps_per_range; - - /* "localize" a term e to a given frame range, creating new symbols to - represent non-local subterms. This returns the localized version e_l, - as well as a proof thet e_l = l. - */ - - ast make_refl(const ast &e){ - if(get_term_type(e) == LitA) - return mk_false(); - return mk_true(); // TODO: is this right? - } - - - ast make_equiv(const ast &x, const ast &y){ - if(get_type(x) == bool_type()) - return make(Iff,x,y); - else - return make(Equal,x,y); - } - - bool range_is_global(const prover::range &r){ - if(pv->range_contained(r,rng)) - return false; - if(!pv->ranges_intersect(r,rng)) - return false; - return true; - } - - ast localize_term(ast e, const prover::range &rng, ast &pf){ - - // we need to memoize this function separately for A, B and global - prover::range map_range = rng; - if(range_is_global(map_range)) - map_range = pv->range_full(); - locmaps &maps = localization_maps_per_range[map_range]; - hash_map &localization_map = maps.localization_map; - hash_map &localization_pf_map = maps.localization_pf_map; - - ast orig_e = e; - pf = make_refl(e); // proof that e = e - - // prover::range erng = - pv->ast_scope(e); -#if 0 - if(!(erng.lo > erng.hi) && pv->ranges_intersect(pv->ast_scope(e),rng)){ - return e; // this term occurs in range, so it's O.K. - } -#endif - - hash_map::iterator it = localization_map.find(e); - - if(it != localization_map.end() && is_bool_type(get_type(e)) - && !pv->ranges_intersect(pv->ast_scope(it->second),rng)) - it = localization_map.end(); // prevent quantifiers over booleans - - if(it != localization_map.end()){ - pf = localization_pf_map[e]; - e = it->second; - } - - else { - // if it is non-local, we must first localize the arguments to - // the range of its function symbol - - int nargs = num_args(e); - if(nargs > 0 /* && (!is_local(e) || flo <= hi || fhi >= lo) */){ - prover::range frng = rng; - opr o = op(e); - if(o == Uninterpreted){ - symb f = sym(e); - prover::range srng = pv->sym_range(f); - if(pv->ranges_intersect(srng,rng)) // localize to desired range if possible - frng = pv->range_glb(srng,rng); - else - frng = srng; // this term will be localized - } - else if(o == Plus || o == Times){ // don't want bound variables inside arith ops - // std::cout << "WARNING: non-local arithmetic\n"; - // frng = erng; // this term will be localized - } - else if(o == Select){ // treat the array term like a function symbol - prover::range srng = pv->ast_scope(arg(e,0)); - if(!(srng.lo > srng.hi) && pv->ranges_intersect(srng,rng)) // localize to desired range if possible - frng = pv->range_glb(srng,rng); - else - frng = srng; // this term will be localized - } - std::vector largs(nargs); - std::vector eqs; - std::vector pfs; - for(int i = 0; i < nargs; i++){ - ast argpf; - largs[i] = localize_term(arg(e,i),frng,argpf); - frng = pv->range_glb(frng,pv->ast_scope(largs[i])); - if(largs[i] != arg(e,i)){ - eqs.push_back(make_equiv(largs[i],arg(e,i))); - pfs.push_back(argpf); - } - } - - e = clone(e,largs); - if(pfs.size()) - pf = make_congruence(eqs,make_equiv(e,orig_e),pfs); - // assert(is_local(e)); - } - - localization_pf_map[orig_e] = pf; - localization_map[orig_e] = e; - } - - if(pv->ranges_intersect(pv->ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - - if(is_array_type(get_type(e))) - std::cerr << "WARNING: array quantifier\n"; - - // choose a frame for the constraint that is close to range - int frame = pv->range_near(pv->ast_scope(e),rng); - - ast new_var = fresh_localization_var(e,frame); - localization_map[orig_e] = new_var; - std::vector foo; foo.push_back(make_equiv(new_var,e)); - ast bar = make_assumption(frame,foo); - pf = make_transitivity(new_var,e,orig_e,bar,pf); - localization_pf_map[orig_e] = pf; - - // HACK: try to bias this term in the future - if(!pv->range_is_full(rng)){ - prover::range rf = pv->range_full(); - locmaps &fmaps = localization_maps_per_range[rf]; - hash_map &flocalization_map = fmaps.localization_map; - hash_map &flocalization_pf_map = fmaps.localization_pf_map; - // if(flocalization_map.find(orig_e) == flocalization_map.end()) - { - flocalization_map[orig_e] = new_var; - flocalization_pf_map[orig_e] = pf; - } - } - - - return new_var; - } - - ast delete_quant(hash_map &memo, const ast &v, const ast &e){ - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - opr o = op(e); - switch(o){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(e); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = delete_quant(memo, v, arg(e,i)); - res = make(o,args); - break; - } - case Uninterpreted: { - symb s = sym(e); - ast w = arg(arg(e,0),0); - if(s == sforall || s == sexists){ - res = delete_quant(memo,v,arg(e,1)); - if(w != v) - res = make(s,w,res); - break; - } - } - default: - res = e; - } - } - return res; - } - - ast insert_quants(hash_map &memo, const ast &e){ - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - opr o = op(e); - switch(o){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(e); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = insert_quants(memo, arg(e,i)); - res = make(o,args); - break; - } - case Uninterpreted: { - symb s = sym(e); - if(s == sforall || s == sexists){ - opr q = (s == sforall) ? Forall : Exists; - ast v = arg(arg(e,0),0); - hash_map dmemo; - ast body = delete_quant(dmemo,v,arg(e,1)); - body = insert_quants(memo,body); - res = apply_quant(q,v,body); - break; - } - } - default: - res = e; - } - } - return res; - } - - ast add_quants(ast e){ -#ifdef CAPTURE_LOCALIZATION - if(!localization_vars.empty()){ - hash_map memo; - e = insert_quants(memo,e); - } -#else - for(int i = localization_vars.size() - 1; i >= 0; i--){ - LocVar &lv = localization_vars[i]; - opr quantifier = (pv->in_range(lv.frame,rng)) ? Exists : Forall; - e = apply_quant(quantifier,lv.var,e); - } -#endif - return e; - } - - node make_resolution(ast pivot, node premise1, node premise2) { - std::vector lits; - return make_resolution(pivot,lits,premise1,premise2); - } - - /* Return an interpolant from a proof of false */ - ast interpolate(const node &pf) override { - // proof of false must be a formula, with quantified symbols -#ifndef BOGUS_QUANTS - return close_universally(add_quants(z3_simplify(pf))); -#else - return close_universally(z3_simplify(pf)); -#endif - } - - ast resolve_with_quantifier(const ast &pivot1, const ast &conj1, - const ast &pivot2, const ast &conj2){ - if(is_not(arg(pivot1,1))) - return resolve_with_quantifier(pivot2,conj2,pivot1,conj1); - ast eqpf; - ast P = arg(pivot1,1); - ast Ploc = localize_term(P, rng, eqpf); - ast pPloc = make_hypothesis(Ploc); - ast pP = make_mp(make(Iff,Ploc,P),pPloc,eqpf); - ast rP = make_resolution(P,conj1,pP); - ast nP = mk_not(P); - ast nPloc = mk_not(Ploc); - ast neqpf = make_congruence(make(Iff,Ploc,P),make(Iff,nPloc,nP),eqpf); - ast npPloc = make_hypothesis(nPloc); - ast npP = make_mp(make(Iff,nPloc,nP),npPloc,neqpf); - ast nrP = make_resolution(nP,conj2,npP); - ast res = make_resolution(Ploc,rP,nrP); - return capture_localization(res); - } - - ast get_contra_coeff(const ast &f){ - ast c = arg(f,0); - // if(!is_not(arg(f,1))) - // c = make(Uminus,c); - return c; - } - - ast my_or(const ast &a, const ast &b){ - return mk_or(a,b); - } - - ast my_and(const ast &a, const ast &b){ - return mk_and(a,b); - } - - ast my_implies(const ast &a, const ast &b){ - return mk_implies(a,b); - } - - ast my_or(const std::vector &a){ - return mk_or(a); - } - - ast my_and(const std::vector &a){ - return mk_and(a); - } - - ast get_lit_atom(const ast &l){ - if(op(l) == Not) - return arg(l,0); - return l; - } - - bool is_placeholder(const ast &e){ - if(op(e) == Uninterpreted){ - std::string name = string_of_symbol(sym(e)); - if(name.size() > 2 && name[0] == '@' && name[1] == 'p') - return true; - } - return false; - } - -public: - iz3proof_itp_impl(prover *p, const prover::range &r, bool w) - : iz3proof_itp(*p) - { - pv = p; - rng = r; - weak = false ; //w; - type boolintbooldom[3] = {bool_type(),int_type(),bool_type()}; - type booldom[1] = {bool_type()}; - type boolbooldom[2] = {bool_type(),bool_type()}; - type boolboolbooldom[3] = {bool_type(),bool_type(),bool_type()}; - type intbooldom[2] = {int_type(),bool_type()}; - contra = function("@contra",2,boolbooldom,bool_type()); - m().inc_ref(contra); - sum = function("@sum",3,boolintbooldom,bool_type()); - m().inc_ref(sum); - rotate_sum = function("@rotsum",2,boolbooldom,bool_type()); - m().inc_ref(rotate_sum); - leq2eq = function("@leq2eq",3,boolboolbooldom,bool_type()); - m().inc_ref(leq2eq); - eq2leq = function("@eq2leq",2,boolbooldom,bool_type()); - m().inc_ref(eq2leq); - cong = function("@cong",3,boolintbooldom,bool_type()); - m().inc_ref(cong); - exmid = function("@exmid",3,boolboolbooldom,bool_type()); - m().inc_ref(exmid); - symm = function("@symm",1,booldom,bool_type()); - m().inc_ref(symm); - epsilon = make_var("@eps",int_type()); - modpon = function("@mp",3,boolboolbooldom,bool_type()); - m().inc_ref(modpon); - no_proof = make_var("@nop",bool_type()); - concat = function("@concat",2,boolbooldom,bool_type()); - m().inc_ref(concat); - top_pos = make_var("@top_pos",bool_type()); - add_pos = function("@add_pos",2,intbooldom,bool_type()); - m().inc_ref(add_pos); - rewrite_A = function("@rewrite_A",3,boolboolbooldom,bool_type()); - m().inc_ref(rewrite_A); - rewrite_B = function("@rewrite_B",3,boolboolbooldom,bool_type()); - m().inc_ref(rewrite_B); - normal_step = function("@normal_step",2,boolbooldom,bool_type()); - m().inc_ref(normal_step); - normal_chain = function("@normal_chain",2,boolbooldom,bool_type()); - m().inc_ref(normal_chain); - normal = function("@normal",2,boolbooldom,bool_type()); - m().inc_ref(normal); - sforall = function("@sforall",2,boolbooldom,bool_type()); - m().inc_ref(sforall); - sexists = function("@sexists",2,boolbooldom,bool_type()); - m().inc_ref(sexists); - } - - ~iz3proof_itp_impl() override { - m().dec_ref(contra); - m().dec_ref(sum); - m().dec_ref(rotate_sum); - m().dec_ref(leq2eq); - m().dec_ref(eq2leq); - m().dec_ref(cong); - m().dec_ref(exmid); - m().dec_ref(symm); - m().dec_ref(modpon); - m().dec_ref(concat); - m().dec_ref(add_pos); - m().dec_ref(rewrite_A); - m().dec_ref(rewrite_B); - m().dec_ref(normal_step); - m().dec_ref(normal_chain); - m().dec_ref(normal); - m().dec_ref(sforall); - m().dec_ref(sexists); - } -}; - -iz3proof_itp *iz3proof_itp::create(prover *p, const prover::range &r, bool w){ - return new iz3proof_itp_impl(p,r,w); -} - diff --git a/src/interp/iz3proof_itp.h b/src/interp/iz3proof_itp.h deleted file mode 100644 index c9a36e9b1..000000000 --- a/src/interp/iz3proof_itp.h +++ /dev/null @@ -1,143 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3proof.h - - Abstract: - - This class defines a simple interpolating proof system. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3PROOF_ITP_H -#define IZ3PROOF_ITP_H - -#include - -#include "interp/iz3base.h" -#include "interp/iz3secondary.h" - -// #define CHECK_PROOFS - -/** This class defines a simple proof system. - - As opposed to iz3proof, this class directly computes interpolants, - so the proof representation is just the interpolant itself. - -*/ - -class iz3proof_itp : public iz3mgr { - public: - - /** Enumeration of proof rules. */ - enum rule {Resolution,Assumption,Hypothesis,Theory,Axiom,Contra,Lemma,Reflexivity,Symmetry,Transitivity,Congruence,EqContra}; - - /** Interface to prover. */ - typedef iz3base prover; - - /** Ast type. */ - typedef prover::ast ast; - - /** The type of proof nodes (just interpolants). */ - typedef ast node; - - /** Object thrown in case of a proof error. */ - struct proof_error: public iz3_exception { - proof_error(): iz3_exception("proof_error") {} - }; - - - /** Make a resolution node with given pivot literal and premises. - The conclusion of premise1 should contain the negation of the - pivot literal, while the conclusion of premise2 should containe the - pivot literal. - */ - virtual node make_resolution(ast pivot, const std::vector &conc, node premise1, node premise2) = 0; - - /** Make an assumption node. The given clause is assumed in the given frame. */ - virtual node make_assumption(int frame, const std::vector &assumption) = 0; - - /** Make a hypothesis node. If phi is the hypothesis, this is - effectively phi |- phi. */ - virtual node make_hypothesis(const ast &hypothesis) = 0; - - /** Make an axiom node. The conclusion must be an instance of an axiom. */ - virtual node make_axiom(const std::vector &conclusion) = 0; - - /** Make an axiom node. The conclusion must be an instance of an axiom. Localize axiom instance to range*/ - virtual node make_axiom(const std::vector &conclusion, prover::range) = 0; - - /** Make a Contra node. This rule takes a derivation of the form - Gamma |- False and produces |- \/~Gamma. */ - - virtual node make_contra(node prem, const std::vector &conclusion) = 0; - - /** Make a Reflexivity node. This rule produces |- x = x */ - - virtual node make_reflexivity(ast con) = 0; - - /** Make a Symmetry node. This takes a derivation of |- x = y and - produces | y = x */ - - virtual node make_symmetry(ast con, const ast &premcon, node prem) = 0; - - /** Make a transitivity node. This takes derivations of |- x = y - and |- y = z produces | x = z */ - - virtual node make_transitivity(const ast &x, const ast &y, const ast &z, node prem1, node prem2) = 0; - - /** Make a congruence node. This takes a derivation of |- x_i = y_i - and produces |- f(...x_i,...) = f(...,y_i,...) */ - - virtual node make_congruence(const ast &xi_eq_yi, const ast &con, const ast &prem1) = 0; - - /** Make a congruence node. This takes derivations of |- x_i1 = y_i1, |- x_i2 = y_i2,... - and produces |- f(...x_i1...x_i2...) = f(...y_i1...y_i2...) */ - - virtual node make_congruence(const std::vector &xi_eq_yi, const ast &con, const std::vector &prems) = 0; - - /** Make a modus-ponens node. This takes derivations of |- x - and |- x = y and produces |- y */ - - virtual node make_mp(const ast &x_eq_y, const ast &prem1, const ast &prem2) = 0; - - /** Make a farkas proof node. */ - - virtual node make_farkas(ast con, const std::vector &prems, const std::vector &prem_cons, const std::vector &coeffs) = 0; - - /* Make an axiom instance of the form |- x<=y, y<= x -> x =y */ - virtual node make_leq2eq(ast x, ast y, const ast &xleqy, const ast &yleqx) = 0; - - /* Make an axiom instance of the form |- x = y -> x <= y */ - virtual node make_eq2leq(ast x, ast y, const ast &xeqy) = 0; - - /* Make an inference of the form t <= c |- t/d <= floor(c/d) where t - is an affine term divisble by d and c is an integer constant */ - virtual node make_cut_rule(const ast &tleqc, const ast &d, const ast &con, const ast &prem) = 0; - - /* Return an interpolant from a proof of false */ - virtual ast interpolate(const node &pf) = 0; - - /** Create proof object to construct an interpolant. */ - static iz3proof_itp *create(prover *p, const prover::range &r, bool _weak); - - protected: - iz3proof_itp(iz3mgr &m) - : iz3mgr(m) - { - } - - public: - virtual ~iz3proof_itp(){ - } -}; - -#endif diff --git a/src/interp/iz3scopes.cpp b/src/interp/iz3scopes.cpp deleted file mode 100755 index e3a28abdd..000000000 --- a/src/interp/iz3scopes.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3scopes.cpp - - Abstract: - - Calculations with scopes, for both sequence and tree interpolation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#include - -#include - -#include "interp/iz3scopes.h" - - -/** computes the least common ancestor of two nodes in the tree, or SHRT_MAX if none */ -int scopes::tree_lca(int n1, int n2){ - if(!tree_mode()) - return std::max(n1,n2); - if(n1 == SHRT_MIN) return n2; - if(n2 == SHRT_MIN) return n1; - if(n1 == SHRT_MAX || n2 == SHRT_MAX) return SHRT_MAX; - while(n1 != n2){ - if(n1 == SHRT_MAX || n2 == SHRT_MAX) return SHRT_MAX; - assert(n1 >= 0 && n2 >= 0 && n1 < (int)parents.size() && n2 < (int)parents.size()); - if(n1 < n2) n1 = parents[n1]; - else n2 = parents[n2]; - } - return n1; -} - -/** computes the greatest common descendant two nodes in the tree, or SHRT_MIN if none */ -int scopes::tree_gcd(int n1, int n2){ - if(!tree_mode()) - return std::min(n1,n2); - int foo = tree_lca(n1,n2); - if(foo == n1) return n2; - if(foo == n2) return n1; - return SHRT_MIN; -} - -#ifndef FULL_TREE - -/** test whether a tree node is contained in a range */ -bool scopes::in_range(int n, const range &rng){ - return tree_lca(rng.lo,n) == n && tree_gcd(rng.hi,n) == n; -} - -/** test whether two ranges of tree nodes intersect */ -bool scopes::ranges_intersect(const range &rng1, const range &rng2){ - return tree_lca(rng1.lo,rng2.hi) == rng2.hi && tree_lca(rng1.hi,rng2.lo) == rng1.hi; -} - - -bool scopes::range_contained(const range &rng1, const range &rng2){ - return tree_lca(rng2.lo,rng1.lo) == rng1.lo - && tree_lca(rng1.hi,rng2.hi) == rng2.hi; -} - -scopes::range scopes::range_lub(const range &rng1, const range &rng2){ - range res; - res.lo = tree_gcd(rng1.lo,rng2.lo); - res.hi = tree_lca(rng1.hi,rng2.hi); - return res; -} - -scopes::range scopes::range_glb(const range &rng1, const range &rng2){ - range res; - res.lo = tree_lca(rng1.lo,rng2.lo); - res.hi = tree_gcd(rng1.hi,rng2.hi); - return res; -} - -#else - - -namespace std { - template <> - class hash { - public: - size_t operator()(const scopes::range_lo &p) const { - return p.lo + (size_t)p.next; - } - }; -} - -template <> inline -size_t stdext::hash_value(const scopes::range_lo& p) -{ - std::hash h; - return h(p); -} - -namespace std { - template <> - class less { - public: - bool operator()(const scopes::range_lo &x, const scopes::range_lo &y) const { - return x.lo < y.lo || x.lo == y.lo && (size_t)x.next < (size_t)y.next; - } - }; -} - - -struct range_op { - scopes::range_lo *x, *y; - int hi; - range_op(scopes::range_lo *_x, scopes::range_lo *_y, int _hi){ - x = _x; y = _y; hi = _hi; - } -}; - -namespace std { - template <> - class hash { - public: - size_t operator()(const range_op &p) const { - return (size_t) p.x + (size_t)p.y + p.hi; - } - }; -} - -template <> inline -size_t stdext::hash_value(const range_op& p) -{ - std::hash h; - return h(p); -} - -namespace std { - template <> - class less { - public: - bool operator()(const range_op &x, const range_op &y) const { - return (size_t)x.x < (size_t)y.x || x.x == y.x && - ((size_t)x.y < (size_t)y.y || x.y == y.y && x.hi < y.hi); - } - }; -} - -struct range_tables { - hash_map unique; - hash_map lub; - hash_map glb; -}; - - -scopes::range_lo *scopes::find_range_lo(int lo, range_lo *next){ - range_lo foo(lo,next); - std::pair baz(foo,(range_lo *)0); - std::pair::iterator,bool> bar = rt->unique.insert(baz); - if(bar.second) - bar.first->second = new range_lo(lo,next); - return bar.first->second; - //std::pair::iterator,bool> bar = rt->unique.insert(foo); - // const range_lo *baz = &*(bar.first); - // return (range_lo *)baz; // coerce const -} - -scopes::range_lo *scopes::range_lub_lo(range_lo *rng1, range_lo *rng2){ - if(!rng1) return rng2; - if(!rng2) return rng1; - if(rng1->lo > rng2->lo) - std::swap(rng1,rng2); - std::pair foo(range_op(rng1,rng2,0),(range_lo *)0); - std::pair::iterator,bool> bar = rt->lub.insert(foo); - range_lo *&res = bar.first->second; - if(!bar.second) return res; - if(!(rng1->next && rng1->next->lo <= rng2->lo)){ - for(int lo = rng1->lo; lo <= rng2->lo; lo = parents[lo]) - if(lo == rng2->lo) - {rng2 = rng2->next; break;} - } - range_lo *baz = range_lub_lo(rng1->next,rng2); - res = find_range_lo(rng1->lo,baz); - return res; -} - - -scopes::range_lo *scopes::range_glb_lo(range_lo *rng1, range_lo *rng2, int hi){ - if(!rng1) return rng1; - if(!rng2) return rng2; - if(rng1->lo > rng2->lo) - std::swap(rng1,rng2); - std::pair cand(range_op(rng1,rng2,hi),(range_lo *)0); - std::pair::iterator,bool> bar = rt->glb.insert(cand); - range_lo *&res = bar.first->second; - if(!bar.second) return res; - range_lo *foo; - if(!(rng1->next && rng1->next->lo <= rng2->lo)){ - int lim = hi; - if(rng1->next) lim = std::min(lim,rng1->next->lo); - int a = rng1->lo, b = rng2->lo; - while(a != b && b <= lim){ - a = parents[a]; - if(a > b)std::swap(a,b); - } - if(a == b && b <= lim){ - foo = range_glb_lo(rng1->next,rng2->next,hi); - foo = find_range_lo(b,foo); - } - else - foo = range_glb_lo(rng2,rng1->next,hi); - } - else foo = range_glb_lo(rng1->next,rng2,hi); - res = foo; - return res; -} - -/** computes the lub (smallest containing subtree) of two ranges */ -scopes::range scopes::range_lub(const range &rng1, const range &rng2){ - int hi = tree_lca(rng1.hi,rng2.hi); - if(hi == SHRT_MAX) return range_full(); - range_lo *lo = range_lub_lo(rng1.lo,rng2.lo); - return range(hi,lo); -} - -/** computes the glb (intersection) of two ranges */ -scopes::range scopes::range_glb(const range &rng1, const range &rng2){ - if(rng1.hi == SHRT_MAX) return rng2; - if(rng2.hi == SHRT_MAX) return rng1; - int hi = tree_gcd(rng1.hi,rng2.hi); - range_lo *lo = hi == SHRT_MIN ? 0 : range_glb_lo(rng1.lo,rng2.lo,hi); - if(!lo) hi = SHRT_MIN; - return range(hi,lo); -} - -/** is this range empty? */ -bool scopes::range_is_empty(const range &rng){ - return rng.hi == SHRT_MIN; -} - -/** return an empty range */ -scopes::range scopes::range_empty(){ - return range(SHRT_MIN,0); -} - -/** return a full range */ -scopes::range scopes::range_full(){ - return range(SHRT_MAX,0); -} - -/** return the maximal element of a range */ -int scopes::range_max(const range &rng){ - return rng.hi; -} - -/** return a minimal (not necessarily unique) element of a range */ -int scopes::range_min(const range &rng){ - if(rng.hi == SHRT_MAX) return SHRT_MIN; - return rng.lo ? rng.lo->lo : SHRT_MAX; -} - - -/** return range consisting of downward closure of a point */ -scopes::range scopes::range_downward(int _hi){ - std::vector descendants(parents.size()); - for(int i = descendants.size() - 1; i >= 0 ; i--) - descendants[i] = i == _hi || parents[i] < parents.size() && descendants[parents[i]]; - for(unsigned i = 0; i < descendants.size() - 1; i++) - if(parents[i] < parents.size()) - descendants[parents[i]] = false; - range_lo *foo = 0; - for(int i = descendants.size() - 1; i >= 0; --i) - if(descendants[i]) foo = find_range_lo(i,foo); - return range(_hi,foo); -} - -/** add an element to a range */ -void scopes::range_add(int i, range &n){ - range foo = range(i, find_range_lo(i,0)); - n = range_lub(foo,n); -} - -/** Choose an element of rng1 that is near to rng2 */ -int scopes::range_near(const range &rng1, const range &rng2){ - - int frame; - int thing = tree_lca(rng1.hi,rng2.hi); - if(thing != rng1.hi) return rng1.hi; - range line = range(rng1.hi,find_range_lo(rng2.hi,(range_lo *)0)); - line = range_glb(line,rng1); - return range_min(line); -} - - -/** test whether a tree node is contained in a range */ -bool scopes::in_range(int n, const range &rng){ - range r = range_empty(); - range_add(n,r); - r = range_glb(rng,r); - return !range_is_empty(r); -} - -/** test whether two ranges of tree nodes intersect */ -bool scopes::ranges_intersect(const range &rng1, const range &rng2){ - range r = range_glb(rng1,rng2); - return !range_is_empty(r); -} - - -bool scopes::range_contained(const range &rng1, const range &rng2){ - range r = range_glb(rng1,rng2); - return r.hi == rng1.hi && r.lo == rng1.lo; -} - - -#endif - - diff --git a/src/interp/iz3scopes.h b/src/interp/iz3scopes.h deleted file mode 100755 index ece30dc25..000000000 --- a/src/interp/iz3scopes.h +++ /dev/null @@ -1,222 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3scopes.h - - Abstract: - - Calculations with scopes, for both sequence and tree interpolation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifndef IZ3SOPES_H -#define IZ3SOPES_H - -#include -#include -#include "interp/iz3hash.h" - -class scopes { - - public: - /** Construct from parents vector. */ - scopes(const std::vector &_parents){ - parents = _parents; - } - - scopes(){ - } - - void initialize(const std::vector &_parents){ - parents = _parents; - } - - /** The parents vector defining the tree structure */ - std::vector parents; - - // #define FULL_TREE -#ifndef FULL_TREE - struct range { - range(){ - lo = SHRT_MAX; - hi = SHRT_MIN; - } - short lo, hi; - }; - - /** computes the lub (smallest containing subtree) of two ranges */ - range range_lub(const range &rng1, const range &rng2); - - /** computes the glb (intersection) of two ranges */ - range range_glb(const range &rng1, const range &rng2); - - /** is this range empty? */ - bool range_is_empty(const range &rng){ - return rng.hi < rng.lo; - } - - /** is this range full? */ - bool range_is_full(const range &rng){ - return rng.lo == SHRT_MIN && rng.hi == SHRT_MAX; - } - - /** return an empty range */ - range range_empty(){ - range res; - res.lo = SHRT_MAX; - res.hi = SHRT_MIN; - return res; - } - - /** return an empty range */ - range range_full(){ - range res; - res.lo = SHRT_MIN; - res.hi = SHRT_MAX; - return res; - } - - /** return the maximal element of a range */ - int range_max(const range &rng){ - return rng.hi; - } - - /** return a minimal (not necessarily unique) element of a range */ - int range_min(const range &rng){ - return rng.lo; - } - - /** return range consisting of downward closure of a point */ - range range_downward(int _hi){ - range foo; - foo.lo = SHRT_MIN; - foo.hi = _hi; - return foo; - } - - void range_add(int i, range &n){ -#if 0 - if(i < n.lo) n.lo = i; - if(i > n.hi) n.hi = i; -#else - range rng; rng.lo = i; rng.hi = i; - n = range_lub(rng,n); -#endif - } - - /** Choose an element of rng1 that is near to rng2 */ - int range_near(const range &rng1, const range &rng2){ - int frame; - int thing = tree_lca(rng1.lo,rng2.hi); - if(thing == rng1.lo) frame = rng1.lo; - else frame = tree_gcd(thing,rng1.hi); - return frame; - } -#else - - struct range_lo { - int lo; - range_lo *next; - range_lo(int _lo, range_lo *_next){ - lo = _lo; - next = _next; - } - }; - - struct range { - int hi; - range_lo *lo; - range(int _hi, range_lo *_lo){ - hi = _hi; - lo = _lo; - } - range(){ - hi = SHRT_MIN; - lo = 0; - } - }; - - range_tables *rt; - - /** computes the lub (smallest containing subtree) of two ranges */ - range range_lub(const range &rng1, const range &rng2); - - /** computes the glb (intersection) of two ranges */ - range range_glb(const range &rng1, const range &rng2); - - /** is this range empty? */ - bool range_is_empty(const range &rng); - - /** return an empty range */ - range range_empty(); - - /** return a full range */ - range range_full(); - - /** return the maximal element of a range */ - int range_max(const range &rng); - - /** return a minimal (not necessarily unique) element of a range */ - int range_min(const range &rng); - - /** return range consisting of downward closure of a point */ - range range_downward(int _hi); - - /** add an element to a range */ - void range_add(int i, range &n); - - /** Choose an element of rng1 that is near to rng2 */ - int range_near(const range &rng1, const range &rng2); - - range_lo *find_range_lo(int lo, range_lo *next); - range_lo *range_lub_lo(range_lo *rng1, range_lo *rng2); - range_lo *range_glb_lo(range_lo *rng1, range_lo *rng2, int lim); - -#endif - - /** test whether a tree node is contained in a range */ - bool in_range(int n, const range &rng); - - /** test whether two ranges of tree nodes intersect */ - bool ranges_intersect(const range &rng1, const range &rng2); - - /** test whether range rng1 contained in range rng2 */ - bool range_contained(const range &rng1, const range &rng2); - - private: - int tree_lca(int n1, int n2); - int tree_gcd(int n1, int n2); - bool tree_mode(){return parents.size() != 0;} - - - -}; - -// let us hash on ranges - -#ifndef FULL_TREE -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const scopes::range &p) const { - return (size_t)p.lo + (size_t)p.hi; - } - }; -} - -inline bool operator==(const scopes::range &x, const scopes::range &y){ - return x.lo == y.lo && x.hi == y.hi; -} -#endif - -#endif diff --git a/src/interp/iz3secondary.h b/src/interp/iz3secondary.h deleted file mode 100755 index a5a949b54..000000000 --- a/src/interp/iz3secondary.h +++ /dev/null @@ -1,40 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3secondary - - Abstract: - - Interface for secondary provers. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifndef IZ3SECONDARY_H -#define IZ3SECONDARY_H - -/** Interface class for secondary provers. */ - -#include "interp/iz3base.h" -#include - -class iz3secondary : public iz3mgr { - public: - virtual int interpolate(const std::vector &frames, std::vector &interpolants) = 0; - virtual ~iz3secondary(){} - - protected: - iz3secondary(const iz3mgr &mgr) : iz3mgr(mgr) {} -}; - - - -#endif diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp deleted file mode 100644 index 44bac0643..000000000 --- a/src/interp/iz3translate.cpp +++ /dev/null @@ -1,2200 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3translate.cpp - - Abstract: - - Translate a Z3 proof to in interpolated proof. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3translate.h" -#include "interp/iz3proof.h" -#include "interp/iz3profiling.h" -#include "interp/iz3interp.h" -#include "interp/iz3proof_itp.h" -#include "ast/ast_pp.h" - -#include -#include -#include -#include -#include -#include -#include - -//using std::vector; -using namespace stl_ext; - - - -/* This translator goes directly from Z3 proofs to interpolated - proofs without an intermediate representation. No secondary - prover is used. -*/ - - -#define throw_unsupported(_e_) { TRACE("iz3", tout << expr_ref((expr*)_e_.raw(), *_e_.mgr()) << "\n";); throw unsupported(_e_); } - -class iz3translation_full : public iz3translation { -public: - - - typedef iz3proof_itp Iproof; - - Iproof *iproof; - - /* Here we have lots of hash tables for memoizing various methods and - other such global data structures. - */ - - typedef hash_map AstToInt; - AstToInt locality; // memoizes locality of Z3 proof terms - - typedef std::pair EquivEntry; - typedef hash_map EquivTab; - EquivTab equivs; // maps non-local terms to equivalent local terms, with proof - - typedef hash_set AstHashSet; - AstHashSet equivs_visited; // proofs already checked for equivalences - - typedef std::pair, hash_map > AstToIpf; - AstToIpf translation; // Z3 proof nodes to Iproof nodes - - int frames; // number of frames - - typedef std::set AstSet; - typedef hash_map AstToAstSet; - AstToAstSet hyp_map; // map proof terms to hypothesis set - - struct LocVar { // localization vars - ast var; // a fresh variable - ast term; // term it represents - int frame; // frame in which it's defined - LocVar(ast v, ast t, int f){var=v;term=t;frame=f;} - }; - - std::vector localization_vars; // localization vars in order of creation - typedef hash_map AstToAst; - AstToAst localization_map; // maps terms to their localization vars - - typedef hash_map AstToBool; - AstToBool occurs_in_memo; // memo of occurs_in function - - AstHashSet cont_eq_memo; // memo of cont_eq function - - AstToAst subst_memo; // memo of subst function - - symb commute; - -public: - - -#define from_ast(x) (x) - - // #define NEW_LOCALITY - -#ifdef NEW_LOCALITY - range rng; // the range of frames in the "A" part of the interpolant -#endif - - /* To handle skolemization, we have to scan the proof for skolem - symbols and assign each to a frame. THe assignment is heuristic. - */ - - int scan_skolems_rec(hash_map &memo, const ast &proof, int frame){ - std::pair foo(proof,INT_MAX); - std::pair bar = memo.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - pfrule dk = pr(proof); - if(dk == PR_ASSERTED){ - ast ass = conc(proof); - res = frame_of_assertion(ass); - } - else if(dk == PR_SKOLEMIZE){ - ast quanted = arg(conc(proof),0); - if(op(quanted) == Not) - quanted = arg(quanted,0); - // range r = ast_range(quanted); - // if(range_is_empty(r)) - range r = ast_scope(quanted); - if(range_is_empty(r)) - throw iz3_exception("can't skolemize"); - if(frame == INT_MAX || !in_range(frame,r)) - frame = range_max(r); // this is desperation -- may fail - if(frame >= frames) frame = frames - 1; - add_frame_range(frame,arg(conc(proof),1)); - r = ast_scope(arg(conc(proof),1)); - } - else if(dk==PR_MODUS_PONENS_OEQ){ - frame = scan_skolems_rec(memo,prem(proof,0),frame); - scan_skolems_rec(memo,prem(proof,1),frame); - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - int bar = scan_skolems_rec(memo,prem(proof,i),frame); - if(res == INT_MAX || res == bar) res = bar; - else if(bar != INT_MAX) res = -1; - } - } - return res; - } - - void scan_skolems(const ast &proof) { - hash_map memo; - scan_skolems_rec(memo,proof, INT_MAX); - } - - // determine locality of a proof term - // return frame of derivation if local, or -1 if not - // result INT_MAX means the proof term is a tautology - // memoized in hash_map "locality" - - int get_locality_rec(ast proof){ - std::pair foo(proof,INT_MAX); - std::pair bar = locality.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - pfrule dk = pr(proof); - if(dk == PR_ASSERTED){ - ast ass = conc(proof); - res = frame_of_assertion(ass); -#ifdef NEW_LOCALITY - if(in_range(res,rng)) - res = range_max(rng); - else - res = frames-1; -#endif - } - else if(dk == PR_QUANT_INST){ - std::vector lits; - ast con = conc(proof); - get_Z3_lits(con, lits); - iproof->make_axiom(lits); - } -#ifdef LOCALIZATION_KLUDGE - else if(dk == PR_MODUS_PONENS && pr(prem(proof,0)) == PR_QUANT_INST - && get_locality_rec(prem(proof,1)) == INT_MAX){ - std::vector lits; - ast con = conc(proof); - get_Z3_lits(con, lits); - iproof->make_axiom(lits); - } -#endif - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - int bar = get_locality_rec(arg); - if(res == INT_MAX || res == bar) res = bar; - else if(bar != INT_MAX) res = -1; - } - } - return res; - } - - - int get_locality(ast proof){ - // if(lia_z3_axioms_only) return -1; - int res = get_locality_rec(proof); - if(res != -1){ - ast con = conc(proof); - range rng = ast_scope(con); - - // hack: if a clause contains "true", it reduces to "true", - // which means we won't compute the range correctly. we handle - // this case by computing the ranges of the literals separately - - if(is_true(con)){ - std::vector lits; - get_Z3_lits(conc(proof),lits); - for(unsigned i = 0; i < lits.size(); i++) - rng = range_glb(rng,ast_scope(lits[i])); - } - - if(!range_is_empty(rng)){ - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - ast hyp = *it; - rng = range_glb(rng,ast_scope(hyp)); - } - } - - // if(!range_is_empty(rng)){ - // if (num_free_variables(con) > 0) - // rng = range_empty(); - // } - - if(res == INT_MAX){ - if(range_is_empty(rng)) - res = -1; - else res = range_max(rng); - } - else { - if(!in_range(res,rng)) - res = -1; - } - } - return res; - } - - - AstSet &get_hyps(ast proof){ - std::pair foo(proof,AstSet()); - std::pair bar = hyp_map.insert(foo); - AstSet &res = bar.first->second; - if(!bar.second) return res; - pfrule dk = pr(proof); - if(dk == PR_HYPOTHESIS){ - ast con = conc(proof); - res.insert(con); - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - AstSet &arg_hyps = get_hyps(arg); - res.insert(arg_hyps.begin(),arg_hyps.end()); - } - if(dk == PR_LEMMA){ - ast con = conc(proof); - res.erase(mk_not(con)); - if(is_or(con)){ - int clause_size = num_args(con); - for(int i = 0; i < clause_size; i++){ - ast neglit = mk_not(arg(con,i)); - res.erase(neglit); - } - } - } - } -#if 0 - AstSet::iterator it = res.begin(), en = res.end(); - if(it != en){ - AstSet::iterator old = it; - ++it; - for(; it != en; ++it, ++old) - if(!(*old < *it)) - std::cout << "foo!"; - } -#endif - return res; - } - - // Find all the judgements of the form p <-> q, where - // p is local and q is non-local, recording them in "equivs" - // the map equivs_visited is used to record the already visited proof terms - - void find_equivs(ast proof){ - if(equivs_visited.find(proof) != equivs_visited.end()) - return; - equivs_visited.insert(proof); - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++) // do all the sub_terms - find_equivs(prem(proof,i)); - ast con = conc(proof); // get the conclusion - if(is_iff(con)){ - ast iff = con; - for(int i = 0; i < 2; i++) - if(!is_local(arg(iff,i)) && is_local(arg(iff,1-i))){ - std::pair > foo(arg(iff,i),std::pair(arg(iff,1-i),proof)); - equivs.insert(foo); - } - } - } - - // get the lits of a Z3 clause - void get_Z3_lits(ast t, std::vector &lits){ - opr dk = op(t); - if(dk == False) - return; // false = empty clause - if(dk == Or){ - unsigned nargs = num_args(t); - lits.resize(nargs); - for(unsigned i = 0; i < nargs; i++) // do all the sub_terms - lits[i] = arg(t,i); - } - else { - lits.push_back(t); - } - } - - // resolve two clauses represented as vectors of lits. replace first clause - void resolve(ast pivot, std::vector &cls1, std::vector &cls2){ - ast neg_pivot = mk_not(pivot); - for(unsigned i = 0; i < cls1.size(); i++){ - if(cls1[i] == pivot){ - cls1[i] = cls1.back(); - cls1.pop_back(); - bool found_pivot2 = false; - for(unsigned j = 0; j < cls2.size(); j++){ - if(cls2[j] == neg_pivot) - found_pivot2 = true; - else - cls1.push_back(cls2[j]); - } - (void)found_pivot2; - assert(found_pivot2); - return; - } - } - assert(0 && "resolve failed"); - } - - // get lits resulting from unit resolution up to and including "position" - // TODO: this is quadratic -- fix it - void do_unit_resolution(ast proof, int position, std::vector &lits){ - ast orig_clause = conc(prem(proof,0)); - get_Z3_lits(orig_clause,lits); - for(int i = 1; i <= position; i++){ - std::vector unit(1); - unit[0] = conc(prem(proof,i)); - resolve(mk_not(unit[0]),lits,unit); - } - } - -#if 0 - // clear the localization variables - void clear_localization(){ - localization_vars.clear(); - localization_map.clear(); - } - - // create a fresh variable for localization - ast fresh_localization_var(ast term, int frame){ - std::ostringstream s; - s << "%" << (localization_vars.size()); - ast var = make_var(s.str().c_str(),get_type(term)); - sym_range(sym(var)) = range_full(); // make this variable global - localization_vars.push_back(LocVar(var,term,frame)); - return var; - } - - - // "localize" a term to a given frame range by - // creating new symbols to represent non-local subterms - - ast localize_term(ast e, const range &rng){ - if(ranges_intersect(ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - AstToAst::iterator it = localization_map.find(e); - if(it != localization_map.end()) - return it->second; - - // if is is non-local, we must first localize the arguments to - // the range of its function symbol - - int nargs = num_args(e); - if(nargs > 0 /* && (!is_local(e) || flo <= hi || fhi >= lo) */){ - range frng = rng; - if(op(e) == Uninterpreted){ - symb f = sym(e); - range srng = sym_range(f); - if(ranges_intersect(srng,rng)) // localize to desired range if possible - frng = range_glb(srng,rng); - } - std::vector largs(nargs); - for(int i = 0; i < nargs; i++){ - largs[i] = localize_term(arg(e,i),frng); - frng = range_glb(frng,ast_scope(largs[i])); - } - e = clone(e,largs); - assert(is_local(e)); - } - - - if(ranges_intersect(ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - - // choose a frame for the constraint that is close to range - int frame = range_near(ast_scope(e),rng); - - ast new_var = fresh_localization_var(e,frame); - localization_map[e] = new_var; - ast cnst = make(Equal,new_var,e); - // antes.push_back(std::pair(cnst,frame)); - return new_var; - } - - // some patterm matching functions - - // match logical or with nargs arguments - // assumes AIG form - bool match_or(ast e, ast *args, int nargs){ - if(op(e) != Or) return false; - int n = num_args(e); - if(n != nargs) return false; - for(int i = 0; i < nargs; i++) - args[i] = arg(e,i); - return true; - } - - // match operator f with exactly nargs arguments - bool match_op(ast e, opr f, ast *args, int nargs){ - if(op(e) != f) return false; - int n = num_args(e); - if(n != nargs) return false; - for(int i = 0; i < nargs; i++) - args[i] = arg(e,i); - return true; - } - - // see if the given formula can be interpreted as - // an axiom instance (e.g., an array axiom instance). - // if so, add it to "antes" in an appropriate frame. - // this may require "localization" - - void get_axiom_instance(ast e){ - - // "store" axiom - // (or (= w q) (= (select (store a1 w y) q) (select a1 q))) - // std::cout << "ax: "; show(e); - ast lits[2],eq_ops_l[2],eq_ops_r[2],sel_ops[2], sto_ops[3], sel_ops2[2] ; - if(match_or(e,lits,2)) - if(match_op(lits[0],Equal,eq_ops_l,2)) - if(match_op(lits[1],Equal,eq_ops_r,2)) - for(int i = 0; i < 2; i++){ // try the second equality both ways - if(match_op(eq_ops_r[0],Select,sel_ops,2)) - if(match_op(sel_ops[0],Store,sto_ops,3)) - if(match_op(eq_ops_r[1],Select,sel_ops2,2)) - for(int j = 0; j < 2; j++){ // try the first equality both ways - if(eq_ops_l[0] == sto_ops[1] - && eq_ops_l[1] == sel_ops[1] - && eq_ops_l[1] == sel_ops2[1] - && sto_ops[0] == sel_ops2[0]) - if(is_local(sel_ops[0])) // store term must be local - { - ast sto = sel_ops[0]; - ast addr = localize_term(eq_ops_l[1],ast_scope(sto)); - ast res = make(Or, - make(Equal,eq_ops_l[0],addr), - make(Equal, - make(Select,sto,addr), - make(Select,sel_ops2[0],addr))); - // int frame = range_min(ast_scope(res)); TODO - // antes.push_back(std::pair(res,frame)); - return; - } - std::swap(eq_ops_l[0],eq_ops_l[1]); - } - std::swap(eq_ops_r[0],eq_ops_r[1]); - } - } - - // a quantifier instantation looks like (~ forall x. P) \/ P[z/x] - // we need to find a time frame for P, then localize P[z/x] in this frame - - void get_quantifier_instance(ast e){ - ast disjs[2]; - if(match_or(e,disjs,2)){ - if(is_local(disjs[0])){ - ast res = localize_term(disjs[1], ast_scope(disjs[0])); - // int frame = range_min(ast_scope(res)); TODO - // antes.push_back(std::pair(res,frame)); - return; - } - } - } - - ast get_judgement(ast proof){ - ast con = from_ast(conc(proof)); - AstSet &hyps = get_hyps(proof); - std::vector hyps_vec; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - hyps_vec.push_back(*it); - if(hyps_vec.size() == 0) return con; - con = make(Or,mk_not(make(And,hyps_vec)),con); - return con; - } - - // does variable occur in expression? - int occurs_in1(ast var, ast e){ - std::pair foo(e,false); - std::pair bar = occurs_in_memo.insert(foo); - bool &res = bar.first->second; - if(bar.second){ - if(e == var) res = true; - int nargs = num_args(e); - for(int i = 0; i < nargs; i++) - res |= occurs_in1(var,arg(e,i)); - } - return res; - } - - int occurs_in(ast var, ast e){ - occurs_in_memo.clear(); - return occurs_in1(var,e); - } - - // find a controlling equality for a given variable v in a term - // a controlling equality is of the form v = t, which, being - // false would force the formula to have the specifid truth value - // returns t, or null if no such - - ast cont_eq(bool truth, ast v, ast e){ - if(is_not(e)) return cont_eq(!truth,v,arg(e,0)); - if(cont_eq_memo.find(e) != cont_eq_memo.end()) - return ast(); - cont_eq_memo.insert(e); - if(!truth && op(e) == Equal){ - if(arg(e,0) == v) return(arg(e,1)); - if(arg(e,1) == v) return(arg(e,0)); - } - if((!truth && op(e) == And) || (truth && op(e) == Or)){ - int nargs = num_args(e); - for(int i = 0; i < nargs; i++){ - ast res = cont_eq(truth, v, arg(e,i)); - if(!res.null()) return res; - } - } - return ast(); - } - - // substitute a term t for unbound occurrences of variable v in e - - ast subst(ast var, ast t, ast e){ - if(e == var) return t; - std::pair foo(e,ast()); - std::pair bar = subst_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - int nargs = num_args(e); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = subst(var,t,arg(e,i)); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else res = clone(e,args); - } - return res; - } - - // apply a quantifier to a formula, with some optimizations - // 1) bound variable does not occur -> no quantifier - // 2) bound variable must be equal to some term -> substitute - - ast apply_quant(opr quantifier, ast var, ast e){ - if(!occurs_in(var,e))return e; - cont_eq_memo.clear(); - ast cterm = cont_eq(quantifier == Forall, var, e); - if(!cterm.null()){ - subst_memo.clear(); - return subst(var,cterm,e); - } - std::vector bvs; bvs.push_back(var); - return make_quant(quantifier,bvs,e); - } - - // add quantifiers over the localization vars - // to an interpolant for frames lo-hi - - ast add_quants(ast e, int lo, int hi){ - for(int i = localization_vars.size() - 1; i >= 0; i--){ - LocVar &lv = localization_vars[i]; - opr quantifier = (lv.frame >= lo && lv.frame <= hi) ? Exists : Forall; - e = apply_quant(quantifier,lv.var,e); - } - return e; - } - - int get_lits_locality(std::vector &lits){ - range rng = range_full(); - for(std::vector::iterator it = lits.begin(), en = lits.end(); it != en; ++it){ - ast lit = *it; - rng = range_glb(rng,ast_scope(lit)); - } - if(range_is_empty(rng)) return -1; - int hi = range_max(rng); - if(hi >= frames) return frames - 1; - return hi; - } -#endif - - int num_lits(ast ast){ - opr dk = op(ast); - if(dk == False) - return 0; - if(dk == Or){ - unsigned nargs = num_args(ast); - int n = 0; - for(unsigned i = 0; i < nargs; i++) // do all the sub_terms - n += num_lits(arg(ast,i)); - return n; - } - else - return 1; - } - - void symbols_out_of_scope_rec(hash_set &memo, hash_set &symb_memo, int frame, const ast &t){ - if(memo.find(t) != memo.end()) - return; - memo.insert(t); - if(op(t) == Uninterpreted){ - symb s = sym(t); - range r = sym_range(s); - if(!in_range(frame,r) && symb_memo.find(s) == symb_memo.end()){ - std::cout << string_of_symbol(s) << "\n"; - symb_memo.insert(s); - } - } - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - symbols_out_of_scope_rec(memo,symb_memo,frame,arg(t,i)); - } - - void symbols_out_of_scope(int frame, const ast &t){ - hash_set memo; - hash_set symb_memo; - symbols_out_of_scope_rec(memo,symb_memo,frame,t); - } - - void conc_symbols_out_of_scope(int frame, const ast &t){ - symbols_out_of_scope(frame,conc(t)); - } - - std::vector lit_trace; - hash_set marked_proofs; - - bool proof_has_lit(const ast &proof, const ast &lit){ - AstSet &hyps = get_hyps(proof); - if(hyps.find(mk_not(lit)) != hyps.end()) - return true; - std::vector lits; - ast con = conc(proof); - get_Z3_lits(con, lits); - for(unsigned i = 0; i < lits.size(); i++) - if(lits[i] == lit) - return true; - return false; - } - - - void trace_lit_rec(const ast &lit, const ast &proof, AstHashSet &memo){ - if(memo.find(proof) == memo.end()){ - memo.insert(proof); - AstSet &hyps = get_hyps(proof); - std::vector lits; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - lits.push_back(mk_not(*it)); - ast con = conc(proof); - get_Z3_lits(con, lits); - for(unsigned i = 0; i < lits.size(); i++){ - if(lits[i] == lit){ - print_expr(std::cout,proof); - std::cout << "\n"; - marked_proofs.insert(proof); - pfrule dk = pr(proof); - if(dk == PR_UNIT_RESOLUTION || dk == PR_LEMMA){ - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - trace_lit_rec(lit,arg,memo); - } - } - else - lit_trace.push_back(proof); - } - } - } - } - - ast traced_lit; - - int trace_lit(const ast &lit, const ast &proof){ - marked_proofs.clear(); - lit_trace.clear(); - traced_lit = lit; - AstHashSet memo; - trace_lit_rec(lit,proof,memo); - return lit_trace.size(); - } - - bool is_literal_or_lit_iff(const ast &lit){ - if(my_is_literal(lit)) return true; - if(op(lit) == Iff){ - return my_is_literal(arg(lit,0)) && my_is_literal(arg(lit,1)); - } - return false; - } - - bool my_is_literal(const ast &lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - int f = op(abslit); - return !(f == And || f == Or || f == Iff); - } - - hash_map asts_by_id; - - void print_lit(const ast &lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - if(!is_literal_or_lit_iff(lit)){ - if(is_not(lit)) std::cout << "~"; - int id = ast_id(abslit); - asts_by_id[id] = abslit; - std::cout << "[" << id << "]"; - } - else - print_expr(std::cout,lit); - } - - void expand(int id){ - if(asts_by_id.find(id) == asts_by_id.end()) - std::cout << "undefined\n"; - else { - ast lit = asts_by_id[id]; - std::string s = string_of_symbol(sym(lit)); - std::cout << "(" << s; - unsigned nargs = num_args(lit); - for(unsigned i = 0; i < nargs; i++){ - std::cout << " "; - print_lit(arg(lit,i)); - } - std::cout << ")\n";; - } - } - - void show_lit(const ast &lit){ - print_lit(lit); - std::cout << "\n"; - } - - void print_z3_lit(const ast &a){ - print_lit(from_ast(a)); - } - - void show_z3_lit(const ast &a){ - print_z3_lit(a); - std::cout << "\n"; - } - - - void show_con(const ast &proof, bool brief){ - if(!traced_lit.null() && proof_has_lit(proof,traced_lit)) - std::cout << "(*) "; - ast con = conc(proof); - AstSet &hyps = get_hyps(proof); - int count = 0; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - if(brief && ++count > 5){ - std::cout << "... "; - break; - } - print_lit(*it); - std::cout << " "; - } - std::cout << "|- "; - std::vector lits; - get_Z3_lits(con,lits); - for(unsigned i = 0; i < lits.size(); i++){ - print_lit(lits[i]); - std::cout << " "; - } - range r = ast_scope(con); - std::cout << " {" << r.lo << "," << r.hi << "}"; - std::cout << "\n"; - } - - void show_step(const ast &proof){ - std::cout << "\n"; - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - std::cout << "(" << i << ") "; - ast arg = prem(proof,i); - show_con(arg,true); - } - std::cout << "|------ "; - std::cout << string_of_symbol(sym(proof)) << "\n"; - show_con(proof,false); - } - - void show_marked( const ast &proof){ - std::cout << "\n"; - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - if(!traced_lit.null() && proof_has_lit(arg,traced_lit)){ - std::cout << "(" << i << ") "; - show_con(arg,true); - } - } - } - - std::vector pfhist; - int pfhist_pos; - - void pfgoto(const ast &proof){ - if(pfhist.size() == 0) - pfhist_pos = 0; - else pfhist_pos++; - pfhist.resize(pfhist_pos); - pfhist.push_back(proof); - show_step(proof); - } - - - void pfback(){ - if(pfhist_pos > 0){ - pfhist_pos--; - show_step(pfhist[pfhist_pos]); - } - } - - void pffwd(){ - if(pfhist_pos < ((int)pfhist.size()) - 1){ - pfhist_pos++; - show_step(pfhist[pfhist_pos]); - } - } - - void pfprem(int i){ - if(pfhist.size() > 0){ - ast proof = pfhist[pfhist_pos]; - unsigned nprems = num_prems(proof); - if(i >= 0 && i < (int)nprems) - pfgoto(prem(proof,i)); - } - } - - - - // translate a unit resolution sequence - Iproof::node translate_ur(ast proof){ - ast prem0 = prem(proof,0); - Iproof::node itp = translate_main(prem0,true); - std::vector clause; - ast conc0 = conc(prem0); - int nprems = num_prems(proof); - if(nprems == 2 && conc0 == mk_not(conc(prem(proof,1)))) - clause.push_back(conc0); - else - get_Z3_lits(conc0,clause); - for(int position = 1; position < nprems; position++){ - ast ante = prem(proof,position); - ast pnode = conc(ante); - ast pnode_abs = !is_not(pnode) ? pnode : mk_not(pnode); - Iproof::node neg = itp; - Iproof::node pos = translate_main(ante, false); - if(is_not(pnode)){ - pnode = mk_not(pnode); - std::swap(neg,pos); - } - std::vector unit(1); - unit[0] = conc(ante); - resolve(mk_not(conc(ante)),clause,unit); - itp = iproof->make_resolution(pnode,clause,neg,pos); - } - return itp; - } - - // get an inequality in the form 0 <= t where t is a linear term - ast rhs_normalize_inequality(const ast &ineq){ - ast zero = make_int("0"); - ast thing = make(Leq,zero,zero); - linear_comb(thing,make_int("1"),ineq); - thing = simplify_ineq(thing); - return thing; - } - - bool check_farkas(const std::vector &prems, const ast &con){ - ast zero = make_int("0"); - ast thing = make(Leq,zero,zero); - for(unsigned i = 0; i < prems.size(); i++) - linear_comb(thing,make_int(rational(1)),prems[i]); - linear_comb(thing,make_int(rational(-1)),con); - thing = simplify_ineq(thing); - return arg(thing,1) == make_int(rational(0)); - } - - // get an inequality in the form t <= c or t < c, there t is affine and c constant - ast normalize_inequality(const ast &ineq){ - ast zero = make_int("0"); - ast thing = make(Leq,zero,zero); - linear_comb(thing,make_int("1"),ineq); - thing = simplify_ineq(thing); - ast lhs = arg(thing,0); - ast rhs = arg(thing,1); - opr o = op(rhs); - if(o != Numeral){ - if(op(rhs) == Plus){ - int nargs = num_args(rhs); - ast const_term = zero; - int i = 0; - if(nargs > 0 && op(arg(rhs,0)) == Numeral){ - const_term = arg(rhs,0); - i++; - } - if(i < nargs){ - std::vector non_const; - for(; i < nargs; i++) - non_const.push_back(arg(rhs,i)); - lhs = make(Sub,lhs,make(Plus,non_const)); - } - rhs = const_term; - } - else { - lhs = make(Sub,lhs,make(Plus,rhs)); - rhs = zero; - } - lhs = z3_simplify(lhs); - rhs = z3_simplify(rhs); - thing = make(op(thing),lhs,rhs); - } - return thing; - } - - void get_linear_coefficients(const ast &t, std::vector &coeffs){ - if(op(t) == Plus){ - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - coeffs.push_back(get_coeff(arg(t,i))); - } - else - coeffs.push_back(get_coeff(t)); - } - - /* given an affine term t, get the GCD of the coefficients in t. */ - ast gcd_of_coefficients(const ast &t){ - std::vector coeffs; - get_linear_coefficients(t,coeffs); - if(coeffs.size() == 0) - return make_int("1"); // arbitrary - rational d = abs(coeffs[0]); - for(unsigned i = 1; i < coeffs.size(); i++){ - d = gcd(d,coeffs[i]); - } - return make_int(d); - } - - ast get_bounded_variable(const ast &ineq, bool &lb){ - ast nineq = normalize_inequality(ineq); - ast lhs = arg(nineq,0); - lhs.raw(); - switch(op(lhs)){ - case Uninterpreted: - lb = false; - return lhs; - case Times: - if(arg(lhs,0) == make_int(rational(1))) - lb = false; - else if(arg(lhs,0) == make_int(rational(-1))) - lb = true; - else - throw_unsupported(lhs); - return arg(lhs,1); - default: - throw_unsupported(lhs); - } - } - - rational get_term_coefficient(const ast &t1, const ast &v){ - ast t = arg(normalize_inequality(t1),0); - if(op(t) == Plus){ - int nargs = num_args(t); - for(int i = 0; i < nargs; i++){ - if(get_linear_var(arg(t,i)) == v) - return get_coeff(arg(t,i)); - } - } - else - if(get_linear_var(t) == v) - return get_coeff(t); - return rational(0); - } - - - Iproof::node GCDtoDivRule(const ast &proof, bool pol, std::vector &coeffs, std::vector &prems, ast &cut_con){ - // gather the summands of the desired polarity - std::vector my_prems; - std::vector my_coeffs; - std::vector my_prem_cons; - for(unsigned i = pol ? 0 : 1; i < coeffs.size(); i+= 2){ - rational &c = coeffs[i]; - if(c.is_pos()){ - my_prems.push_back(prems[i]); - my_coeffs.push_back(make_int(c)); - my_prem_cons.push_back(conc(prem(proof,i))); - } - else if(c.is_neg()){ - int j = (i % 2 == 0) ? i + 1 : i - 1; - my_prems.push_back(prems[j]); - my_coeffs.push_back(make_int(-coeffs[j])); - my_prem_cons.push_back(conc(prem(proof,j))); - } - } - ast my_con = sum_inequalities(my_coeffs,my_prem_cons); - - // handle generalized GCD test. sadly, we dont' get the coefficients... - if(coeffs[0].is_zero()){ - bool lb; - int xtra_prem = 0; - ast bv = get_bounded_variable(conc(prem(proof,0)),lb); - rational bv_coeff = get_term_coefficient(my_con,bv); - if(bv_coeff.is_pos() != lb) - xtra_prem = 1; - if(bv_coeff.is_neg()) - bv_coeff = -bv_coeff; - - my_prems.push_back(prems[xtra_prem]); - my_coeffs.push_back(make_int(bv_coeff)); - my_prem_cons.push_back(conc(prem(proof,xtra_prem))); - my_con = sum_inequalities(my_coeffs,my_prem_cons); - } - - my_con = normalize_inequality(my_con); - Iproof::node hyp = iproof->make_hypothesis(mk_not(my_con)); - my_prems.push_back(hyp); - my_coeffs.push_back(make_int("1")); - my_prem_cons.push_back(mk_not(my_con)); - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_prem_cons,my_coeffs); - - ast t = arg(my_con,0); - ast c = arg(my_con,1); - ast d = gcd_of_coefficients(t); - t = z3_simplify(mk_idiv(t,d)); - c = z3_simplify(mk_idiv(c,d)); - cut_con = make(op(my_con),t,c); - return iproof->make_cut_rule(my_con,d,cut_con,res); - } - - - rational get_first_coefficient(const ast &t, ast &v){ - if(op(t) == Plus){ - unsigned best_id = UINT_MAX; - rational best_coeff(0); - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - if(op(arg(t,i)) != Numeral){ - ast lv = get_linear_var(arg(t,i)); - unsigned id = ast_id(lv); - if(id < best_id) { - v = lv; - best_id = id; - best_coeff = get_coeff(arg(t,i)); - } - } - return best_coeff; - } - else - if(op(t) != Numeral){ - v = get_linear_var(t); - return(get_coeff(t)); - } - return rational(0); - } - - ast divide_inequalities(const ast &x, const ast&y){ - ast xvar, yvar; - rational xcoeff = get_first_coefficient(arg(x,0),xvar); - rational ycoeff = get_first_coefficient(arg(y,0),yvar); - if(xcoeff == rational(0) || ycoeff == rational(0) || xvar != yvar) - throw_unsupported(x); // can be caused by non-linear arithmetic - rational ratio = xcoeff/ycoeff; - if(denominator(ratio) != rational(1)) - throw_unsupported(y); // can this ever happen? - return make_int(ratio); // better be integer! - } - - ast AssignBounds2Farkas(const ast &proof, const ast &con){ - std::vector farkas_coeffs; - get_assign_bounds_coeffs(proof,farkas_coeffs); - int nargs = num_args(con); - if(nargs != (int)(farkas_coeffs.size())) - throw_unsupported(proof); // should never happen -#if 0 - if(farkas_coeffs[0] != make_int(rational(1))) - farkas_coeffs[0] = make_int(rational(1)); -#else - std::vector lits, lit_coeffs; - for(int i = 1; i < nargs; i++){ - lits.push_back(mk_not(arg(con,i))); - lit_coeffs.push_back(farkas_coeffs[i]); - } - ast sum = normalize_inequality(sum_inequalities(lit_coeffs,lits)); - ast conseq = normalize_inequality(arg(con,0)); - ast d = divide_inequalities(sum,conseq); -#if 0 - if(d != farkas_coeffs[0]) - std::cout << "wow!\n"; -#endif - farkas_coeffs[0] = d; -#endif - std::vector my_coeffs; - std::vector my_cons; - for(int i = 1; i < nargs; i++){ - my_cons.push_back(mk_not(arg(con,i))); - my_coeffs.push_back(farkas_coeffs[i]); - } - ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons,true /* round_off */)); - my_cons.push_back(mk_not(farkas_con)); - my_coeffs.push_back(make_int("1")); - std::vector my_hyps; - my_hyps.reserve(nargs); - for(int i = 0; i < nargs; i++) - my_hyps.push_back(iproof->make_hypothesis(my_cons[i])); - ast res = iproof->make_farkas(mk_false(),my_hyps,my_cons,my_coeffs); - res = iproof->make_cut_rule(farkas_con,farkas_coeffs[0],arg(con,0),res); - return res; - } - - ast AssignBoundsRule2Farkas(const ast &proof, const ast &con, std::vector prems){ - std::vector farkas_coeffs; - get_assign_bounds_rule_coeffs(proof,farkas_coeffs); - int nargs = num_prems(proof)+1; - if(nargs != (int)(farkas_coeffs.size())) - throw iz3_exception("bad assign-bounds theory lemma"); -#if 0 - if(farkas_coeffs[0] != make_int(rational(1))) - farkas_coeffs[0] = make_int(rational(1)); -#else - std::vector lits, lit_coeffs; - for(int i = 1; i < nargs; i++){ - lits.push_back(conc(prem(proof,i-1))); - lit_coeffs.push_back(farkas_coeffs[i]); - } - ast sum = normalize_inequality(sum_inequalities(lit_coeffs,lits)); - ast conseq = normalize_inequality(con); - ast d = divide_inequalities(sum,conseq); -#if 0 - if(d != farkas_coeffs[0]) - std::cout << "wow!\n"; -#endif - farkas_coeffs[0] = d; -#endif - std::vector my_coeffs; - std::vector my_cons; - for(int i = 1; i < nargs; i++){ - my_cons.push_back(conc(prem(proof,i-1))); - my_coeffs.push_back(farkas_coeffs[i]); - } - ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons,true /* round_off */)); - std::vector my_hyps; - for(int i = 1; i < nargs; i++) - my_hyps.push_back(prems[i-1]); - my_cons.push_back(mk_not(farkas_con)); - my_coeffs.push_back(make_int("1")); - my_hyps.push_back(iproof->make_hypothesis(mk_not(farkas_con))); - ast res = iproof->make_farkas(mk_false(),my_hyps,my_cons,my_coeffs); - res = iproof->make_cut_rule(farkas_con,farkas_coeffs[0],conc(proof),res); - return res; - } - - ast GomoryCutRule2Farkas(const ast &proof, const ast &con, std::vector prems){ - std::vector my_prems = prems; - std::vector my_coeffs; - std::vector my_prem_cons; - get_gomory_cut_coeffs(proof,my_coeffs); - int nargs = num_prems(proof); - if(nargs != (int)(my_coeffs.size())) - throw "bad gomory-cut theory lemma"; - my_prem_cons.reserve(nargs); - for(int i = 0; i < nargs; i++) - my_prem_cons.push_back(conc(prem(proof,i))); - ast my_con = normalize_inequality(sum_inequalities(my_coeffs,my_prem_cons)); - Iproof::node hyp = iproof->make_hypothesis(mk_not(my_con)); - my_prems.push_back(hyp); - my_coeffs.push_back(make_int("1")); - my_prem_cons.push_back(mk_not(my_con)); - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_prem_cons,my_coeffs); - ast t = arg(my_con,0); - ast c = arg(my_con,1); - ast d = gcd_of_coefficients(t); - /* - t = z3_simplify(mk_idiv(t,d)); - c = z3_simplify(mk_idiv(c,d)); - ast cut_con = make(op(my_con),t,c); - */ - ast cut_con = con; - return iproof->make_cut_rule(my_con,d,cut_con,res); - } - - Iproof::node RewriteClause(Iproof::node clause, const ast &rew){ - if(pr(rew) == PR_MONOTONICITY){ - int nequivs = num_prems(rew); - for(int i = 0; i < nequivs; i++){ - Iproof::node equiv_pf = translate_main(prem(rew,i),false); - ast equiv = conc(prem(rew,i)); - clause = iproof->make_mp(equiv,clause,equiv_pf); - } - return clause; - } - if(pr(rew) == PR_TRANSITIVITY){ - clause = RewriteClause(clause,prem(rew,0)); - clause = RewriteClause(clause,prem(rew,1)); - return clause; - } - if(pr(rew) == PR_REWRITE){ - return clause; // just hope the rewrite does nothing! - } - throw_unsupported(rew); - } - - - // Following code is for elimination of "commutativity" axiom - - Iproof::node make_commuted_modus_ponens(const ast &proof, const std::vector &args){ - ast pf = arg(args[1],0); - ast comm_equiv = arg(args[1],1); // equivalence relation with possible commutations - ast P = conc(prem(proof,0)); - ast Q = conc(proof); - Iproof::node P_pf = args[0]; - ast P_comm = arg(comm_equiv,0); - ast Q_comm = arg(comm_equiv,1); - if(P != P_comm) - P_pf = iproof->make_symmetry(P_comm,P,P_pf); - Iproof::node res = iproof->make_mp(comm_equiv,P_pf,pf); - if(Q != Q_comm) - res = iproof->make_symmetry(Q,Q_comm,res); - return res; - } - - Iproof::node make_commuted_monotonicity(const ast &proof, const std::vector &args){ - ast pf = arg(args[0],0); - ast comm_equiv = arg(args[0],1); // equivalence relation with possible commutations - ast con = make(Iff,make(Not,arg(comm_equiv,0)),make(Not,arg(comm_equiv,1))); - std::vector eqs; eqs.push_back(comm_equiv); - std::vector pfs; pfs.push_back(pf); - ast res = iproof->make_congruence(eqs,con,pfs); - res = make(commute,res,con); - return res; - } - - Iproof::node make_commuted_symmetry(const ast &proof, const std::vector &args){ - ast pf = arg(args[0],0); - ast comm_equiv = arg(args[0],1); // equivalence relation with possible commutations - ast con = make(Iff,arg(comm_equiv,1),arg(comm_equiv,0)); - ast res = iproof->make_symmetry(con,comm_equiv,pf); - res = make(commute,res,con); - return res; - } - - void unpack_commuted(const ast &proof, const ast &cm, ast &pf, ast &comm_equiv){ - if(sym(cm) == commute){ - pf = arg(cm,0); - comm_equiv = arg(cm,1); - } - else { - pf = cm; - comm_equiv = conc(proof); - } - } - - Iproof::node make_commuted_transitivity(const ast &proof, const std::vector &args){ - ast pf[2], comm_equiv[2]; - for(int i = 0; i < 2; i++) - unpack_commuted(prem(proof,i),args[i],pf[i],comm_equiv[i]); - if(!(arg(comm_equiv[0],1) == arg(comm_equiv[1],0))){ - ast tw = twist(prem(proof,1)); - ast np = translate_main(tw,false); - unpack_commuted(tw,np,pf[1],comm_equiv[1]); - } - ast con = make(Iff,arg(comm_equiv[0],0),arg(comm_equiv[1],1)); - ast res = iproof->make_transitivity(arg(comm_equiv[0],0),arg(comm_equiv[0],1),arg(comm_equiv[1],1),pf[0],pf[1]); - res = make(commute,res,con); - return res; - } - - ast commute_equality(const ast &eq){ - return make(Equal,arg(eq,1),arg(eq,0)); - } - - ast commute_equality_iff(const ast &con){ - if(op(con) != Iff || op(arg(con,0)) != Equal) - throw_unsupported(con); - return make(Iff,commute_equality(arg(con,0)),commute_equality(arg(con,1))); - } - - // convert a proof of a=b <-> c=d into a proof of b=a <-> d=c - // TODO: memoize this? - ast twist(const ast &proof){ - pfrule dk = pr(proof); - ast con = commute_equality_iff(conc(proof)); - int n = num_prems(proof); - std::vector prs(n); - if(dk == PR_MONOTONICITY){ - for(int i = 0; i < n; i++) - prs[i] = prem(proof,i); - } - else - for(int i = 0; i < n; i++) - prs[i] = twist(prem(proof,i)); - switch(dk){ - case PR_MONOTONICITY: - case PR_SYMMETRY: - case PR_TRANSITIVITY: - case PR_COMMUTATIVITY: - prs.push_back(con); - return clone(proof,prs); - default: - throw_unsupported(proof); - } - } - - struct TermLt { - iz3mgr &m; - bool operator()(const ast &x, const ast &y){ - unsigned xid = m.ast_id(x); - unsigned yid = m.ast_id(y); - return xid < yid; - } - TermLt(iz3mgr &_m) : m(_m) {} - }; - - void SortTerms(std::vector &terms){ - TermLt foo(*this); - std::sort(terms.begin(),terms.end(),foo); - } - - ast SortSum(const ast &t){ - if(!(op(t) == Plus)) - return t; - int nargs = num_args(t); - if(nargs < 2) return t; - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = arg(t,i); - SortTerms(args); - return make(Plus,args); - } - - void get_sum_as_vector(const ast &t, std::vector &coeffs, std::vector &vars){ - if(!(op(t) == Plus)){ - coeffs.push_back(get_coeff(t)); - vars.push_back(get_linear_var(t)); - } - else { - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - get_sum_as_vector(arg(t,i),coeffs,vars); - } - } - - ast replace_summands_with_fresh_vars(const ast &t, hash_map &map){ - if(op(t) == Plus){ - int nargs = num_args(t); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = replace_summands_with_fresh_vars(arg(t,i),map); - return make(Plus,args); - } - if(op(t) == Times) - return make(Times,arg(t,0),replace_summands_with_fresh_vars(arg(t,1),map)); - if(map.find(t) == map.end()) - map[t] = mk_fresh_constant("@s",get_type(t)); - return map[t]; - } - - rational lcd(const std::vector &rats){ - rational res = rational(1); - for(unsigned i = 0; i < rats.size(); i++){ - res = lcm(res,denominator(rats[i])); - } - return res; - } - - Iproof::node reconstruct_farkas_with_dual(const std::vector &prems, const std::vector &pfs, const ast &con){ - int nprems = prems.size(); - std::vector npcons(nprems); - hash_map pain_map; // not needed - for(int i = 0; i < nprems; i++){ - npcons[i] = painfully_normalize_ineq(conc(prems[i]),pain_map); - if(op(npcons[i]) == Lt){ - ast constval = z3_simplify(make(Sub,arg(npcons[i],1),make_int(rational(1)))); - npcons[i] = make(Leq,arg(npcons[i],0),constval); - } - } - ast ncon = painfully_normalize_ineq(mk_not(con),pain_map); - npcons.push_back(ncon); - - hash_map dual_map; - std::vector cvec, vars_seen; - m().enable_int_real_coercions(true); - ast rhs = make_real(rational(0)); - for(unsigned i = 0; i < npcons.size(); i++){ - ast c= mk_fresh_constant("@c",real_type()); - cvec.push_back(c); - ast lhs = arg(npcons[i],0); - std::vector coeffs; - std::vector vars; - get_sum_as_vector(lhs,coeffs,vars); - for(unsigned j = 0; j < coeffs.size(); j++){ - rational coeff = coeffs[j]; - ast var = vars[j]; - if(dual_map.find(var) == dual_map.end()){ - dual_map[var] = make_real(rational(0)); - vars_seen.push_back(var); - } - ast foo = make(Plus,dual_map[var],make(Times,make_real(coeff),c)); - dual_map[var] = foo; - } - rhs = make(Plus,rhs,make(Times,c,arg(npcons[i],1))); - } - std::vector cnstrs; - for(unsigned i = 0; i < vars_seen.size(); i++) - cnstrs.push_back(make(Equal,dual_map[vars_seen[i]],make_real(rational(0)))); - cnstrs.push_back(make(Leq,rhs,make_real(rational(0)))); - for(unsigned i = 0; i < cvec.size() - 1; i++) - cnstrs.push_back(make(Geq,cvec[i],make_real(rational(0)))); - cnstrs.push_back(make(Equal,cvec.back(),make_real(rational(1)))); - ast new_proof; - - // greedily reduce the core - for(unsigned i = 0; i < cvec.size() - 1; i++){ - std::vector dummy; - cnstrs.push_back(make(Equal,cvec[i],make_real(rational(0)))); - if(!is_sat(cnstrs,new_proof,dummy)) - cnstrs.pop_back(); - } - - std::vector vals = cvec; - if(!is_sat(cnstrs,new_proof,vals)) - throw iz3_exception("Proof error!"); - std::vector rat_farkas_coeffs; - for(unsigned i = 0; i < cvec.size(); i++){ - ast bar = vals[i]; - rational r; - if(is_numeral(bar,r)) - rat_farkas_coeffs.push_back(r); - else - throw iz3_exception("Proof error!"); - } - rational the_lcd = lcd(rat_farkas_coeffs); - std::vector farkas_coeffs; - std::vector my_prems; - std::vector my_pcons; - for(unsigned i = 0; i < prems.size(); i++){ - ast fc = make_int(rat_farkas_coeffs[i] * the_lcd); - if(!(fc == make_int(rational(0)))){ - farkas_coeffs.push_back(fc); - my_prems.push_back(pfs[i]); - my_pcons.push_back(conc(prems[i])); - } - } - farkas_coeffs.push_back(make_int(the_lcd)); - my_prems.push_back(iproof->make_hypothesis(mk_not(con))); - my_pcons.push_back(mk_not(con)); - - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs); - return res; - } - - ast painfully_normalize_ineq(const ast &ineq, hash_map &map){ - ast res = normalize_inequality(ineq); - ast lhs = arg(res,0); - lhs = replace_summands_with_fresh_vars(lhs,map); - res = make(op(res),SortSum(lhs),arg(res,1)); - return res; - } - - Iproof::node painfully_reconstruct_farkas(const std::vector &prems, const std::vector &pfs, const ast &con){ - int nprems = prems.size(); - std::vector pcons(nprems),npcons(nprems); - hash_map pcon_to_pf, npcon_to_pcon, pain_map; - for(int i = 0; i < nprems; i++){ - pcons[i] = conc(prems[i]); - npcons[i] = painfully_normalize_ineq(pcons[i],pain_map); - pcon_to_pf[npcons[i]] = pfs[i]; - npcon_to_pcon[npcons[i]] = pcons[i]; - } - // ast leq = make(Leq,arg(con,0),arg(con,1)); - ast ncon = painfully_normalize_ineq(mk_not(con),pain_map); - pcons.push_back(mk_not(con)); - npcons.push_back(ncon); - // ast assumps = make(And,pcons); - ast new_proof; - std::vector dummy; - if(is_sat(npcons,new_proof,dummy)) - throw iz3_exception("Proof error!"); - pfrule dk = pr(new_proof); - int nnp = num_prems(new_proof); - std::vector my_prems; - std::vector farkas_coeffs, my_pcons; - - if(dk == PR_TH_LEMMA - && get_theory_lemma_theory(new_proof) == ArithTheory - && get_theory_lemma_kind(new_proof) == FarkasKind) - get_farkas_coeffs(new_proof,farkas_coeffs); - else if(dk == PR_UNIT_RESOLUTION && nnp == 2){ - for(int i = 0; i < nprems; i++) - farkas_coeffs.push_back(make_int(rational(1))); - } - else - return reconstruct_farkas_with_dual(prems,pfs,con); - - for(int i = 0; i < nnp; i++){ - ast p = conc(prem(new_proof,i)); - p = really_normalize_ineq(p); - if(pcon_to_pf.find(p) != pcon_to_pf.end()){ - my_prems.push_back(pcon_to_pf[p]); - my_pcons.push_back(npcon_to_pcon[p]); - } - else if(p == ncon){ - my_prems.push_back(iproof->make_hypothesis(mk_not(con))); - my_pcons.push_back(mk_not(con)); - } - else - return reconstruct_farkas_with_dual(prems,pfs,con); - } - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs); - return res; - } - - - - ast really_normalize_ineq(const ast &ineq){ - ast res = normalize_inequality(ineq); - res = make(op(res),SortSum(arg(res,0)),arg(res,1)); - return res; - } - - Iproof::node reconstruct_farkas(const std::vector &prems, const std::vector &pfs, const ast &con){ - int nprems = prems.size(); - std::vector pcons(nprems),npcons(nprems); - hash_map pcon_to_pf, npcon_to_pcon; - for(int i = 0; i < nprems; i++){ - pcons[i] = conc(prems[i]); - npcons[i] = really_normalize_ineq(pcons[i]); - pcon_to_pf[npcons[i]] = pfs[i]; - npcon_to_pcon[npcons[i]] = pcons[i]; - } - // ast leq = make(Leq,arg(con,0),arg(con,1)); - ast ncon = really_normalize_ineq(mk_not(con)); - pcons.push_back(mk_not(con)); - npcons.push_back(ncon); - // ast assumps = make(And,pcons); - ast new_proof; - std::vector dummy; - if(is_sat(npcons,new_proof,dummy)) - throw iz3_exception("Proof error!"); - pfrule dk = pr(new_proof); - int nnp = num_prems(new_proof); - std::vector my_prems; - std::vector farkas_coeffs, my_pcons; - - if(dk == PR_TH_LEMMA - && get_theory_lemma_theory(new_proof) == ArithTheory - && get_theory_lemma_kind(new_proof) == FarkasKind) - get_farkas_coeffs(new_proof,farkas_coeffs); - else if(dk == PR_UNIT_RESOLUTION && nnp == 2){ - for(int i = 0; i < nprems; i++) - farkas_coeffs.push_back(make_int(rational(1))); - } - else - return painfully_reconstruct_farkas(prems,pfs,con); - - for(int i = 0; i < nnp; i++){ - ast p = conc(prem(new_proof,i)); - p = really_normalize_ineq(p); - if(pcon_to_pf.find(p) != pcon_to_pf.end()){ - my_prems.push_back(pcon_to_pf[p]); - my_pcons.push_back(npcon_to_pcon[p]); - } - else if(p == ncon){ - my_prems.push_back(iproof->make_hypothesis(mk_not(con))); - my_pcons.push_back(mk_not(con)); - } - else - return painfully_reconstruct_farkas(prems,pfs,con); - } - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs); - return res; - } - - bool is_eq_propagate(const ast &proof){ - return pr(proof) == PR_TH_LEMMA && get_theory_lemma_theory(proof) == ArithTheory && get_theory_lemma_kind(proof) == EqPropagateKind; - } - - ast EqPropagate(const ast &con, const std::vector &prems, const std::vector &args){ - Iproof::node fps[2]; - ast ineq_con[2]; - for(int i = 0; i < 2; i++){ - opr o = i == 0 ? Leq : Geq; - ineq_con[i] = make(o, arg(con,0), arg(con,1)); - fps[i] = reconstruct_farkas(prems,args,ineq_con[i]); - } - ast res = iproof->make_leq2eq(arg(con,0), arg(con,1), ineq_con[0], ineq_con[1]); - std::vector dummy_clause; - for(int i = 0; i < 2; i++) - res = iproof->make_resolution(ineq_con[i],dummy_clause,res,fps[i]); - return res; - } - - ast ArithMysteryRule(const ast &con, const std::vector &prems, const std::vector &args){ - // Hope for the best! - Iproof::node guess = reconstruct_farkas(prems,args,con); - return guess; - } - - struct CannotCombineEqPropagate {}; - - void CombineEqPropagateRec(const ast &proof, std::vector &prems, std::vector &args, ast &eqprem){ - if(pr(proof) == PR_TRANSITIVITY && is_eq_propagate(prem(proof,1))){ - CombineEqPropagateRec(prem(proof,0), prems, args, eqprem); - ast dummy; - CombineEqPropagateRec(prem(proof,1), prems, args, dummy); - return; - } - if(is_eq_propagate(proof)){ - int nprems = num_prems(proof); - for(int i = 0; i < nprems; i++){ - prems.push_back(prem(proof,i)); - ast ppf = translate_main(prem(proof,i),false); - args.push_back(ppf); - } - return; - } - eqprem = proof; - } - - ast CombineEqPropagate(const ast &proof){ - std::vector prems, args; - ast eq1; - CombineEqPropagateRec(proof, prems, args, eq1); - ast eq2con = conc(proof); - if(!eq1.null()) - eq2con = make(Equal,arg(conc(eq1),1),arg(conc(proof),1)); - ast eq2 = EqPropagate(eq2con,prems,args); - if(!eq1.null()){ - Iproof::node foo = translate_main(eq1,false); - eq2 = iproof->make_transitivity(arg(conc(eq1),0), arg(conc(eq1),1), arg(conc(proof),1), foo, eq2); - } - return eq2; - } - - bool get_store_array(const ast &t, ast &res){ - if(op(t) == Store){ - res = t; - return true; - } - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - if(get_store_array(arg(t,i),res)) - return true; - return false; - } - - // translate a Z3 proof term into interpolating proof system - - Iproof::node translate_main(ast proof, bool expect_clause = true){ - AstToIpf &tr = translation; - hash_map &trc = expect_clause ? tr.first : tr.second; - std::pair foo(proof,Iproof::node()); - std::pair::iterator, bool> bar = trc.insert(foo); - Iproof::node &res = bar.first->second; - if(!bar.second) return res; - - // Try the locality rule first - - int frame = get_locality(proof); - if(frame != -1){ - ast e = from_ast(conc(proof)); - if(frame >= frames) frame = frames - 1; - std::vector foo; - if(expect_clause) - get_Z3_lits(conc(proof),foo); - else - foo.push_back(e); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - foo.push_back(mk_not(*it)); - res = iproof->make_assumption(frame,foo); - return res; - } - - // If the proof is not local, break it down by proof rule - - pfrule dk = pr(proof); - unsigned nprems = num_prems(proof); - if(dk == PR_UNIT_RESOLUTION){ - res = translate_ur(proof); - } - else if(dk == PR_LEMMA){ - ast contra = prem(proof,0); // this is a proof of false from some hyps - res = translate_main(contra); - if(!expect_clause){ - std::vector foo; // the negations of the hyps form a clause - foo.push_back(from_ast(conc(proof))); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - foo.push_back(mk_not(*it)); - res = iproof->make_contra(res,foo); - } - } - else { - std::vector lits; - ast con = conc(proof); - if(expect_clause) - get_Z3_lits(con, lits); - else - lits.push_back(from_ast(con)); - - // pattern match some idioms - if(dk == PR_MODUS_PONENS && pr(prem(proof,0)) == PR_QUANT_INST){ - if(get_locality_rec(prem(proof,1)) == INT_MAX) { - res = iproof->make_axiom(lits); - return res; - } - } - if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or && op(conc(prem(proof,0))) == Or){ - Iproof::node clause = translate_main(prem(proof,0),true); - res = RewriteClause(clause,prem(proof,1)); - return res; - } - -#if 0 - if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or) - std::cout << "foo!\n"; -#endif - - // no idea why this shows up - if(dk == PR_MODUS_PONENS_OEQ){ - if(conc(prem(proof,0)) == con){ - res = translate_main(prem(proof,0),expect_clause); - return res; - } - if(expect_clause && op(con) == Or){ // skolemization does this - Iproof::node clause = translate_main(prem(proof,0),true); - res = RewriteClause(clause,prem(proof,1)); - return res; - } - } - -#if 0 - if(1 && dk == PR_TRANSITIVITY && pr(prem(proof,1)) == PR_COMMUTATIVITY){ - Iproof::node clause = translate_main(prem(proof,0),true); - res = make(commute,clause,conc(prem(proof,0))); // HACK -- we depend on Iproof::node being same as ast. - return res; - } - - if(1 && dk == PR_TRANSITIVITY && pr(prem(proof,0)) == PR_COMMUTATIVITY){ - Iproof::node clause = translate_main(prem(proof,1),true); - res = make(commute,clause,conc(prem(proof,1))); // HACK -- we depend on Iproof::node being same as ast. - return res; - } -#endif - - if(dk == PR_TRANSITIVITY && is_eq_propagate(prem(proof,1))){ - try { - res = CombineEqPropagate(proof); - return res; - } - catch(const CannotCombineEqPropagate &){ - } - } - - /* this is the symmetry rule for ~=, that is, takes x ~= y and yields y ~= x. - the proof idiom uses commutativity, monotonicity and mp, but we replace it here - with symmtrey and resolution, that is, we prove y = x |- x = y, then resolve - with the proof of ~(x=y) to get ~y=x. */ - if(dk == PR_MODUS_PONENS && pr(prem(proof,1)) == PR_MONOTONICITY && pr(prem(prem(proof,1),0)) == PR_COMMUTATIVITY && num_prems(prem(proof,1)) == 1){ - Iproof::node ante = translate_main(prem(proof,0),false); - ast eq0 = arg(conc(prem(prem(proof,1),0)),0); - ast eq1 = arg(conc(prem(prem(proof,1),0)),1); - Iproof::node eq1hy = iproof->make_hypothesis(eq1); - Iproof::node eq0pf = iproof->make_symmetry(eq0,eq1,eq1hy); - std::vector clause; // just a dummy - res = iproof->make_resolution(eq0,clause,ante,eq0pf); - return res; - } - - /* This idiom takes ~P and Q=P, yielding ~Q. It uses a "rewrite" - (Q=false) = ~Q. We eliminate the rewrite by using symmetry, - congruence and modus ponens. */ - - if(dk == PR_MODUS_PONENS && pr(prem(proof,1)) == PR_REWRITE && pr(prem(proof,0)) == PR_TRANSITIVITY && pr(prem(prem(proof,0),1)) == PR_IFF_FALSE){ - if(op(con) == Not && arg(con,0) == arg(conc(prem(proof,0)),0)){ - Iproof::node ante1 = translate_main(prem(prem(proof,0),0),false); - Iproof::node ante2 = translate_main(prem(prem(prem(proof,0),1),0),false); - ast ante1_con = conc(prem(prem(proof,0),0)); - ast eq0 = arg(ante1_con,0); - ast eq1 = arg(ante1_con,1); - ast symm_con = make(Iff,eq1,eq0); - Iproof::node ante1s = iproof->make_symmetry(symm_con,ante1_con,ante1); - ast cong_con = make(Iff,make(Not,eq1),make(Not,eq0)); - Iproof::node ante1sc = iproof->make_congruence(symm_con,cong_con,ante1s); - res = iproof->make_mp(cong_con,ante2,ante1sc); - return res; - } - } - - - // translate all the premises - std::vector args(nprems); - for(unsigned i = 0; i < nprems; i++) - args[i] = translate_main(prem(proof,i),false); - - for(unsigned i = 0; i < nprems; i++) - if(sym(args[i]) == commute - && !(dk == PR_TRANSITIVITY || dk == PR_MODUS_PONENS || dk == PR_SYMMETRY || (dk == PR_MONOTONICITY && op(arg(con,0)) == Not))) - throw_unsupported(proof); - - switch(dk){ - case PR_TRANSITIVITY: { - if(sym(args[0]) == commute || sym(args[1]) == commute) - res = make_commuted_transitivity(proof,args); - else { - // assume the premises are x = y, y = z - ast x = arg(conc(prem(proof,0)),0); - ast y = arg(conc(prem(proof,0)),1); - ast z = arg(conc(prem(proof,1)),1); - res = iproof->make_transitivity(x,y,z,args[0],args[1]); - } - break; - } - case PR_TRANSITIVITY_STAR: { - // assume the premises are x = y, y = z, z = u, u = v, .. - - ast x = arg(conc(prem(proof,0)),0); - ast y = arg(conc(prem(proof,0)),1); - ast z = arg(conc(prem(proof,1)),1); - res = iproof->make_transitivity(x,y,z,args[0],args[1]); - - for (unsigned i = 2; i < nprems; ++i) { - y = z; - z = arg(conc(prem(proof,i)),1); - res = iproof->make_transitivity(x,y,z,res,args[i]); - } - break; - } - case PR_QUANT_INTRO: - case PR_MONOTONICITY: - { - std::vector eqs; eqs.resize(args.size()); - for(unsigned i = 0; i < args.size(); i++) - eqs[i] = conc(prem(proof,i)); - if(op(arg(con,0)) == Not && sym(args[0]) == commute) - res = make_commuted_monotonicity(proof,args); - else - res = iproof->make_congruence(eqs,con,args); - break; - } - case PR_REFLEXIVITY: { - res = iproof->make_reflexivity(con); - break; - } - case PR_SYMMETRY: { - if(sym(args[0]) == commute) - res = make_commuted_symmetry(proof,args); - else - res = iproof->make_symmetry(con,conc(prem(proof,0)),args[0]); - break; - } - case PR_MODUS_PONENS: { - if(sym(args[1]) == commute) - res = make_commuted_modus_ponens(proof,args); - else - res = iproof->make_mp(conc(prem(proof,1)),args[0],args[1]); - break; - } - case PR_TH_LEMMA: { - switch(get_theory_lemma_theory(proof)){ - case ArithTheory: - switch(get_theory_lemma_kind(proof)){ - case FarkasKind: { - std::vector farkas_coeffs, prem_cons; - get_farkas_coeffs(proof,farkas_coeffs); - if(nprems == 0) {// axiom, not rule - int nargs = num_args(con); - if(farkas_coeffs.size() != (unsigned)nargs){ - pfgoto(proof); - throw_unsupported(proof); - } - for(int i = 0; i < nargs; i++){ - ast lit = mk_not(arg(con,i)); - prem_cons.push_back(lit); - args.push_back(iproof->make_hypothesis(lit)); - } - } - else { // rule version (proves false) - prem_cons.resize(nprems); - for(unsigned i = 0; i < nprems; i++) - prem_cons[i] = conc(prem(proof,i)); - } - res = iproof->make_farkas(con,args,prem_cons,farkas_coeffs); - break; - } - case Leq2EqKind: { - // conc should be (or x = y (not (leq x y)) (not(leq y z)) ) - ast xeqy = arg(conc(proof),0); - ast x = arg(xeqy,0); - ast y = arg(xeqy,1); - res = iproof->make_leq2eq(x,y,arg(arg(conc(proof),1),0),arg(arg(conc(proof),2),0)); - break; - } - case Eq2LeqKind: { - // conc should be (or (not (= x y)) (leq x y)) - ast xeqy = arg(arg(conc(proof),0),0); - ast xleqy = arg(conc(proof),1); - ast x = arg(xeqy,0); - ast y = arg(xeqy,1); - res = iproof->make_eq2leq(x,y,xleqy); - break; - } - case GCDTestKind: { - std::vector farkas_coeffs; - get_broken_gcd_test_coeffs(proof,farkas_coeffs); - if(farkas_coeffs.size() != nprems){ - pfgoto(proof); - throw_unsupported(proof); - } - std::vector my_prems; my_prems.resize(2); - std::vector my_prem_cons; my_prem_cons.resize(2); - std::vector my_farkas_coeffs; my_farkas_coeffs.resize(2); - my_prems[0] = GCDtoDivRule(proof, true, farkas_coeffs, args, my_prem_cons[0]); - my_prems[1] = GCDtoDivRule(proof, false, farkas_coeffs, args, my_prem_cons[1]); - ast con = mk_false(); - my_farkas_coeffs[0] = my_farkas_coeffs[1] = make_int("1"); - res = iproof->make_farkas(con,my_prems,my_prem_cons,my_farkas_coeffs); - break; - } - case AssignBoundsKind: { - if(args.size() > 0) - res = AssignBoundsRule2Farkas(proof, conc(proof), args); - else - res = AssignBounds2Farkas(proof,conc(proof)); - break; - } - case GomoryCutKind: { - if(args.size() > 0) - res = GomoryCutRule2Farkas(proof, conc(proof), args); - else - throw_unsupported(proof); - break; - } - case EqPropagateKind: { - std::vector prems(nprems); - for(unsigned i = 0; i < nprems; i++) - prems[i] = prem(proof,i); - res = EqPropagate(con,prems,args); - break; - } - case ArithMysteryKind: { - // Z3 hasn't told us what kind of lemma this is -- maybe we can guess - std::vector prems(nprems); - for(unsigned i = 0; i < nprems; i++) - prems[i] = prem(proof,i); - res = ArithMysteryRule(con,prems,args); - break; - } - default: - throw_unsupported(proof); - } - break; - case ArrayTheory: {// nothing fancy for this - ast store_array; - if(get_store_array(con,store_array)) - res = iproof->make_axiom(lits,ast_scope(store_array)); - else - res = iproof->make_axiom(lits); // for array extensionality axiom - break; - } - default: - throw_unsupported(proof); - } - break; - } - case PR_HYPOTHESIS: { - res = iproof->make_hypothesis(conc(proof)); - break; - } - case PR_QUANT_INST: { - res = iproof->make_axiom(lits); - break; - } - case PR_DEF_AXIOM: { // this should only happen for formulas resulting from quantifier instantiation - res = iproof->make_axiom(lits); - break; - } - case PR_IFF_TRUE: { // turns p into p <-> true, noop for us - res = args[0]; - break; - } - case PR_IFF_FALSE: { // turns ~p into p <-> false, noop for us - if(is_local(con)) - res = args[0]; - else - throw_unsupported(proof); - break; - } - case PR_COMMUTATIVITY: { - ast comm_equiv = make(op(con),arg(con,0),arg(con,0)); - ast pf = iproof->make_reflexivity(comm_equiv); - res = make(commute,pf,comm_equiv); - break; - } - case PR_NOT_OR_ELIM: - case PR_AND_ELIM: { - std::vector rule_ax, res_conc; - ast piv = conc(prem(proof,0)); - rule_ax.push_back(make(Not,piv)); - rule_ax.push_back(con); - ast pf = iproof->make_axiom(rule_ax); - res_conc.push_back(con); - res = iproof->make_resolution(piv,res_conc,pf,args[0]); - break; - } - default: - IF_VERBOSE(0, verbose_stream() << "Unsupported proof rule: " << expr_ref((expr*)proof.raw(), *proof.mgr()) << "\n";); - // pfgoto(proof); - // SASSERT(0 && "translate_main: unsupported proof rule"); - throw_unsupported(proof); - } - } - - return res; - } - - void clear_translation(){ - translation.first.clear(); - translation.second.clear(); - } - - // We actually compute the interpolant here and then produce a proof consisting of just a lemma - - iz3proof::node translate(ast proof, iz3proof &dst) override { - std::vector itps; - scan_skolems(proof); - for(int i = 0; i < frames -1; i++){ -#ifdef NEW_LOCALITY - rng = range_downward(i); - locality.clear(); -#endif - iproof = iz3proof_itp::create(this,range_downward(i),weak_mode()); - try { - Iproof::node ipf = translate_main(proof); - ast itp = iproof->interpolate(ipf); - itps.push_back(itp); - delete iproof; - clear_translation(); - } - catch (const iz3proof_itp::proof_error &) { - delete iproof; - clear_translation(); - throw iz3proof::proof_error(); - } - catch (const unsupported &exc) { - delete iproof; - clear_translation(); - throw exc; - } - } - // Very simple proof -- lemma of the empty clause with computed interpolation - iz3proof::node Ipf = dst.make_lemma(std::vector(),itps); // builds result in dst - return Ipf; - } - - iz3translation_full(iz3mgr &mgr, - iz3secondary *_secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory) - : iz3translation(mgr, cnsts, parents, theory) - { - frames = cnsts.size(); - traced_lit = ast(); - type boolbooldom[2] = {bool_type(),bool_type()}; - commute = function("@commute",2,boolbooldom,bool_type()); - m().inc_ref(commute); - } - - ~iz3translation_full() override { - m().dec_ref(commute); - } -}; - - - - -#ifdef IZ3_TRANSLATE_FULL - -iz3translation *iz3translation::create(iz3mgr &mgr, - iz3secondary *secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory){ - return new iz3translation_full(mgr,secondary,cnsts,parents,theory); -} - - -#if 1 - -// This is just to make sure certain methods are compiled, so we can call then from the debugger. - -void iz3translation_full_trace_lit(iz3translation_full *p, iz3mgr::ast lit, iz3mgr::ast proof){ - p->trace_lit(lit, proof); -} - -void iz3translation_full_show_step(iz3translation_full *p, iz3mgr::ast proof){ - p->show_step(proof); -} - -void iz3translation_full_show_marked(iz3translation_full *p, iz3mgr::ast proof){ - p->show_marked(proof); -} - -void iz3translation_full_show_lit(iz3translation_full *p, iz3mgr::ast lit){ - p->show_lit(lit); -} - -void iz3translation_full_show_z3_lit(iz3translation_full *p, iz3mgr::ast a){ - p->show_z3_lit(a); -} - -void iz3translation_full_pfgoto(iz3translation_full *p, iz3mgr::ast proof){ - p->pfgoto(proof); -} - - -void iz3translation_full_pfback(iz3translation_full *p ){ - p->pfback(); -} - -void iz3translation_full_pffwd(iz3translation_full *p ){ - p->pffwd(); -} - -void iz3translation_full_pfprem(iz3translation_full *p, int i){ - p->pfprem(i); -} - -void iz3translation_full_expand(iz3translation_full *p, int i){ - p->expand(i); -} - -void iz3translation_full_symbols_out_of_scope(iz3translation_full *p, int i, const iz3mgr::ast &t){ - p->symbols_out_of_scope(i,t); -} - -void iz3translation_full_conc_symbols_out_of_scope(iz3translation_full *p, int i, const iz3mgr::ast &t){ - p->conc_symbols_out_of_scope(i,t); -} - -struct stdio_fixer { - stdio_fixer(){ - std::cout.rdbuf()->pubsetbuf(nullptr,0); - } - -} my_stdio_fixer; - -#endif - -#endif - - diff --git a/src/interp/iz3translate.h b/src/interp/iz3translate.h deleted file mode 100755 index d80c3b3fe..000000000 --- a/src/interp/iz3translate.h +++ /dev/null @@ -1,63 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3translate.h - - Abstract: - - Interface for proof translations from Z3 proofs to interpolatable - proofs. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifndef IZ3TRANSLATION_H -#define IZ3TRANSLATION_H - -#include "interp/iz3proof.h" -#include "interp/iz3secondary.h" - -// This is a interface class for translation from Z3 proof terms to -// an interpolatable proof - -class iz3translation : public iz3base { - public: - virtual iz3proof::node translate(ast, iz3proof &) = 0; - virtual ast quantify(ast e, const range &rng){return e;} - virtual ~iz3translation(){} - - /** This is thrown when the proof cannot be translated. */ - struct unsupported: public iz3_exception { - raw_ast* m_ast; - unsupported(ast const& a): iz3_exception("unsupported"), m_ast(a.raw()) { } - }; - - static iz3translation *create(iz3mgr &mgr, - iz3secondary *secondary, - const std::vector > &frames, - const std::vector &parents, - const std::vector &theory); - - protected: - iz3translation(iz3mgr &mgr, - const std::vector > &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3base(mgr,_cnsts,_parents,_theory) {} -}; - -// To use a secondary prover, define IZ3_TRANSLATE_DIRECT instead of this -#define IZ3_TRANSLATE_FULL - -#endif - - - diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp deleted file mode 100644 index 9efb1a383..000000000 --- a/src/interp/iz3translate_direct.cpp +++ /dev/null @@ -1,1717 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3translate_direct.cpp - - Abstract: - - Translate a Z3 proof into the interpolating proof calculus. - Translation is direct, without transformations on the target proof - representation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#pragma warning(disable:4390) -#endif - -#include "interp/iz3translate.h" -#include "interp/iz3proof.h" -#include "interp/iz3profiling.h" -#include "interp/iz3interp.h" - -#include -#include -#include -#include -#include -#include -#include - -//using std::vector; -using namespace stl_ext; - -/* This can introduce an address dependency if the range type of hash_map has - a destructor. Since the code in this file is not used and only here for - historical comparisons, we allow this non-determinism. -*/ -namespace stl_ext { - template - class hash { - public: - size_t operator()(const T *p) const { - return (size_t) p; - } - }; -} - -static int lemma_count = 0; -#if 0 -static int nll_lemma_count = 0; -#endif -#define SHOW_LEMMA_COUNT -1 - -// One half of a resolution. We need this to distinguish -// between resolving as a clause and as a unit clause. -// if pivot == conclusion(proof) it is unit. - -struct Z3_resolvent { - iz3base::ast proof; - bool is_unit; - iz3base::ast pivot; - Z3_resolvent(const iz3base::ast &_proof, bool _is_unit, const iz3base::ast &_pivot){ - proof = _proof; - is_unit = _is_unit; - pivot = _pivot; - } -}; - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Z3_resolvent &p) const { - return (p.proof.hash() + p.pivot.hash()); - } - }; -} - - -bool operator==(const Z3_resolvent &x, const Z3_resolvent &y) { - return x.proof == y.proof && x.pivot == y.pivot; -} - - - -typedef std::vector ResolventAppSet; - -struct non_local_lits { - ResolventAppSet proofs; // the proof nodes being raised - non_local_lits(ResolventAppSet &_proofs){ - proofs.swap(_proofs); - } -}; - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const non_local_lits &p) const { - size_t h = 0; - for(ResolventAppSet::const_iterator it = p.proofs.begin(), en = p.proofs.end(); it != en; ++it) - h += (size_t)*it; - return h; - } - }; -} - - -bool operator==(const non_local_lits &x, const non_local_lits &y) { - ResolventAppSet::const_iterator itx = x.proofs.begin(); - ResolventAppSet::const_iterator ity = y.proofs.begin(); - while(true){ - if(ity == y.proofs.end()) return itx == x.proofs.end(); - if(itx == x.proofs.end()) return ity == y.proofs.end(); - if(*itx != *ity) return false; - ++itx; ++ity; - } -} - - -/* This translator goes directly from Z3 proofs to interpolatable - proofs without an intermediate representation as an iz3proof. */ - -class iz3translation_direct : public iz3translation { -public: - - typedef ast Zproof; // type of non-interpolating proofs - typedef iz3proof Iproof; // type of interpolating proofs - - /* Here we have lots of hash tables for memoizing various methods and - other such global data structures. - */ - - typedef hash_map AstToInt; - AstToInt locality; // memoizes locality of Z3 proof terms - - typedef std::pair EquivEntry; - typedef hash_map EquivTab; - EquivTab equivs; // maps non-local terms to equivalent local terms, with proof - - typedef hash_set AstHashSet; - AstHashSet equivs_visited; // proofs already checked for equivalences - - - typedef std::pair, hash_map > AstToIpf; - AstToIpf translation; // Zproof nodes to Iproof nodes - - AstHashSet antes_added; // Z3 proof terms whose antecedents have been added to the list - std::vector > antes; // list of antecedent/frame pairs - std::vector local_antes; // list of local antecedents - - Iproof *iproof; // the interpolating proof we are constructing - - int frames; // number of frames - - typedef std::set AstSet; - typedef hash_map AstToAstSet; - AstToAstSet hyp_map; // map proof terms to hypothesis set - - struct LocVar { // localization vars - ast var; // a fresh variable - ast term; // term it represents - int frame; // frame in which it's defined - LocVar(ast v, ast t, int f){var=v;term=t;frame=f;} - }; - - std::vector localization_vars; // localization vars in order of creation - typedef hash_map AstToAst; - AstToAst localization_map; // maps terms to their localization vars - - typedef hash_map AstToBool; - - - - iz3secondary *secondary; // the secondary prover - - // Unique table for sets of non-local resolutions - hash_map non_local_lits_unique; - - // Unique table for resolvents - hash_map Z3_resolvent_unique; - - // Translation memo for case of non-local resolutions - hash_map non_local_translation; - -public: - - -#define from_ast(x) (x) - - // determine locality of a proof term - // return frame of derivation if local, or -1 if not - // result INT_MAX means the proof term is a tautology - // memoized in hash_map "locality" - - int get_locality_rec(ast proof){ - std::pair foo(proof,INT_MAX); - std::pair bar = locality.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - if(pr(proof) == PR_ASSERTED){ - ast ass = conc(proof); - res = frame_of_assertion(ass); - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - int bar = get_locality_rec(arg); - if(res == INT_MAX || res == bar) res = bar; - else if(bar != INT_MAX) res = -1; - } - } - return res; - } - - - int get_locality(ast proof){ - // if(lia_z3_axioms_only) return -1; - int res = get_locality_rec(proof); - if(res != -1){ - ast con = conc(proof); - range rng = ast_scope(con); - - // hack: if a clause contains "true", it reduces to "true", - // which means we won't compute the range correctly. we handle - // this case by computing the ranges of the literals separately - - if(is_true(con)){ - std::vector lits; - get_Z3_lits(conc(proof),lits); - for(unsigned i = 0; i < lits.size(); i++) - rng = range_glb(rng,ast_scope(lits[i])); - } - - if(!range_is_empty(rng)){ - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - ast hyp = *it; - rng = range_glb(rng,ast_scope(hyp)); - } - } - - if(res == INT_MAX){ - if(range_is_empty(rng)) - res = -1; - else res = range_max(rng); - } - else { - if(!in_range(res,rng)) - res = -1; - } - } - return res; - } - - AstSet &get_hyps(ast proof){ - std::pair foo(proof,AstSet()); - std::pair bar = hyp_map.insert(foo); - AstSet &res = bar.first->second; - if(!bar.second) return res; - pfrule dk = pr(proof); - if(dk == PR_HYPOTHESIS){ - ast con = conc(proof); - res.insert(con); - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - AstSet &arg_hyps = get_hyps(arg); - res.insert(arg_hyps.begin(),arg_hyps.end()); - } - if(dk == PR_LEMMA){ - ast con = conc(proof); - res.erase(mk_not(con)); - if(is_or(con)){ - int clause_size = num_args(con); - for(int i = 0; i < clause_size; i++){ - ast neglit = mk_not(arg(con,i)); - res.erase(neglit); - } - } - } - } -#if 0 - AstSet::iterator it = res.begin(), en = res.end(); - if(it != en){ - AstSet::iterator old = it; - ++it; - for(; it != en; ++it, ++old) - if(!(*old < *it)) - std::cout << "foo!"; - } -#endif - return res; - } - - - // Find all the judgements of the form p <-> q, where - // p is local and q is non-local, recording them in "equivs" - // the map equivs_visited is used to record the already visited proof terms - - void find_equivs(ast proof){ - if(equivs_visited.find(proof) != equivs_visited.end()) - return; - equivs_visited.insert(proof); - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++) // do all the sub_terms - find_equivs(prem(proof,i)); - ast con = conc(proof); // get the conclusion - if(is_iff(con)){ - ast iff = con; - for(int i = 0; i < 2; i++) - if(!is_local(arg(iff,i)) && is_local(arg(iff,1-i))){ - std::pair > foo(arg(iff,i),std::pair(arg(iff,1-i),proof)); - equivs.insert(foo); - } - } - } - - // get the lits of a Z3 clause as secondary prover terms - void get_Z3_lits(ast t, std::vector &lits){ - opr dk = op(t); - if(dk == False) - return; // false = empty clause - if(dk == Or){ - unsigned nargs = num_args(t); - lits.resize(nargs); - for(unsigned i = 0; i < nargs; i++) // do all the sub_terms - lits[i] = arg(t,i); - } - else { - lits.push_back(t); - } - } - - // resolve two clauses represented as vectors of lits. replace first clause - void resolve(ast pivot, std::vector &cls1, std::vector &cls2){ - ast neg_pivot = mk_not(pivot); - for(unsigned i = 0; i < cls1.size(); i++){ - if(cls1[i] == pivot){ - cls1[i] = cls1.back(); - cls1.pop_back(); - bool found_pivot2 = false; - for(unsigned j = 0; j < cls2.size(); j++){ - if(cls2[j] == neg_pivot) - found_pivot2 = true; - else - cls1.push_back(cls2[j]); - } - (void)found_pivot2; - assert(found_pivot2); - return; - } - } - assert(0 && "resolve failed"); - } - - // get lits resulting from unit resolution up to and including "position" - // TODO: this is quadratic -- fix it - void do_unit_resolution(ast proof, int position, std::vector &lits){ - ast orig_clause = conc(prem(proof,0)); - get_Z3_lits(orig_clause,lits); - for(int i = 1; i <= position; i++){ - std::vector unit(1); - unit[0] = conc(prem(proof,i)); - resolve(mk_not(unit[0]),lits,unit); - } - } - - - // clear the localization variables - void clear_localization(){ - localization_vars.clear(); - localization_map.clear(); - } - - // create a fresh variable for localization - ast fresh_localization_var(ast term, int frame){ - std::ostringstream s; - s << "%" << (localization_vars.size()); - ast var = make_var(s.str().c_str(),get_type(term)); - sym_range(sym(var)) = range_full(); // make this variable global - localization_vars.push_back(LocVar(var,term,frame)); - return var; - } - - - // "localize" a term to a given frame range by - // creating new symbols to represent non-local subterms - - ast localize_term(ast e, const range &rng){ - if(ranges_intersect(ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - AstToAst::iterator it = localization_map.find(e); - if(it != localization_map.end()) - return it->second; - - // if is is non-local, we must first localize the arguments to - // the range of its function symbol - - int nargs = num_args(e); - if(nargs > 0 /* && (!is_local(e) || flo <= hi || fhi >= lo) */){ - range frng = rng; - if(op(e) == Uninterpreted){ - symb f = sym(e); - range srng = sym_range(f); - if(ranges_intersect(srng,rng)) // localize to desired range if possible - frng = range_glb(srng,rng); - } - std::vector largs(nargs); - for(int i = 0; i < nargs; i++){ - largs[i] = localize_term(arg(e,i),frng); - frng = range_glb(frng,ast_scope(largs[i])); - } - e = clone(e,largs); - assert(is_local(e)); - } - - - if(ranges_intersect(ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - - // choose a frame for the constraint that is close to range - int frame = range_near(ast_scope(e),rng); - - ast new_var = fresh_localization_var(e,frame); - localization_map[e] = new_var; - ast cnst = make(Equal,new_var,e); - antes.push_back(std::pair(cnst,frame)); - return new_var; - } - - // some patterm matching functions - - // match logical or with nargs arguments - // assumes AIG form - bool match_or(ast e, ast *args, int nargs){ - if(op(e) != Or) return false; - int n = num_args(e); - if(n != nargs) return false; - for(int i = 0; i < nargs; i++) - args[i] = arg(e,i); - return true; - } - - // match operator f with exactly nargs arguments - bool match_op(ast e, opr f, ast *args, int nargs){ - if(op(e) != f) return false; - int n = num_args(e); - if(n != nargs) return false; - for(int i = 0; i < nargs; i++) - args[i] = arg(e,i); - return true; - } - - // see if the given formula can be interpreted as - // an axiom instance (e.g., an array axiom instance). - // if so, add it to "antes" in an appropriate frame. - // this may require "localization" - - void get_axiom_instance(ast e){ - - // "store" axiom - // (or (= w q) (= (select (store a1 w y) q) (select a1 q))) - // std::cout << "ax: "; show(e); - ast lits[2],eq_ops_l[2],eq_ops_r[2],sel_ops[2], sto_ops[3], sel_ops2[2] ; - if(match_or(e,lits,2)) - if(match_op(lits[0],Equal,eq_ops_l,2)) - if(match_op(lits[1],Equal,eq_ops_r,2)) - for(int i = 0; i < 2; i++){ // try the second equality both ways - if(match_op(eq_ops_r[0],Select,sel_ops,2)) - if(match_op(sel_ops[0],Store,sto_ops,3)) - if(match_op(eq_ops_r[1],Select,sel_ops2,2)) - for(int j = 0; j < 2; j++){ // try the first equality both ways - if(eq_ops_l[0] == sto_ops[1] - && eq_ops_l[1] == sel_ops[1] - && eq_ops_l[1] == sel_ops2[1] - && sto_ops[0] == sel_ops2[0]) - if(is_local(sel_ops[0])) // store term must be local - { - ast sto = sel_ops[0]; - ast addr = localize_term(eq_ops_l[1],ast_scope(sto)); - ast res = make(Or, - make(Equal,eq_ops_l[0],addr), - make(Equal, - make(Select,sto,addr), - make(Select,sel_ops2[0],addr))); - int frame = range_min(ast_scope(res)); - antes.push_back(std::pair(res,frame)); - return; - } - std::swap(eq_ops_l[0],eq_ops_l[1]); - } - std::swap(eq_ops_r[0],eq_ops_r[1]); - } - } - - // a quantifier instantation looks like (~ forall x. P) \/ P[z/x] - // we need to find a time frame for P, then localize P[z/x] in this frame - - void get_quantifier_instance(ast e){ - ast disjs[2]; - if(match_or(e,disjs,2)){ - if(is_local(disjs[0])){ - ast res = localize_term(disjs[1], ast_scope(disjs[0])); - int frame = range_min(ast_scope(res)); - antes.push_back(std::pair(res,frame)); - return; - } - } - } - - ast get_judgement(ast proof){ - ast con = from_ast(conc(proof)); - AstSet &hyps = get_hyps(proof); - std::vector hyps_vec; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - hyps_vec.push_back(*it); - if(hyps_vec.size() == 0) return con; - con = make(Or,mk_not(make(And,hyps_vec)),con); - return con; - } - - // add the premises of a proof term to the "antes" list - - void add_antes(ast proof){ - if(antes_added.find(proof) != antes_added.end()) return; - antes_added.insert(proof); - int frame = get_locality(proof); - if(frame != -1) - if(1){ - ast e = get_judgement(proof); - if(frame >= frames) frame = frames-1; // can happen if there are no symbols - antes.push_back(std::pair(e,frame)); - return; - } - pfrule dk = pr(proof); - if(dk == PR_ASSERTED){ - ast ass = conc(proof); - frame = frame_of_assertion(ass); - if(frame >= frames) frame = frames-1; // can happen if a theory fact - antes.push_back(std::pair(ass,frame)); - return; - } - if(dk == PR_TH_LEMMA && num_prems(proof) == 0){ - get_axiom_instance(conc(proof)); - } - if(dk == PR_QUANT_INST && num_prems(proof) == 0){ - get_quantifier_instance(conc(proof)); - } - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - add_antes(arg); - } - } - - - // add quantifiers over the localization vars - // to an interpolant for frames lo-hi - - ast add_quants(ast e, int lo, int hi){ - for(int i = localization_vars.size() - 1; i >= 0; i--){ - LocVar &lv = localization_vars[i]; - opr quantifier = (lv.frame >= lo && lv.frame <= hi) ? Exists : Forall; - e = apply_quant(quantifier,lv.var,e); - } - return e; - } - - int get_lits_locality(std::vector &lits){ - range rng = range_full(); - for(std::vector::iterator it = lits.begin(), en = lits.end(); it != en; ++it){ - ast lit = *it; - rng = range_glb(rng,ast_scope(lit)); - } - if(range_is_empty(rng)) return -1; - int hi = range_max(rng); - if(hi >= frames) return frames - 1; - return hi; - } - - - struct invalid_lemma: public iz3_exception { - invalid_lemma(): iz3_exception("invalid_lemma") {} - }; - - - - - // prove a lemma (clause) using current antes list - // return proof of the lemma - // use the secondary prover - - int prove_lemma(std::vector &lits){ - - - // first try localization - if(antes.size() == 0){ - int local_frame = get_lits_locality(lits); - if(local_frame != -1) - return iproof->make_assumption(local_frame,lits); // no proof needed for purely local fact - } - - // group the assumptions by frame - std::vector preds(frames); - for(unsigned i = 0; i < preds.size(); i++) - preds[i] = mk_true(); - for(unsigned i = 0; i < antes.size(); i++){ - int frame = antes[i].second; - preds[frame] = mk_and(preds[frame],antes[i].first); // conjoin it to frame - } - - for(unsigned i = 0; i < lits.size(); i++){ - int frame; - if(!weak_mode()){ - frame = range_max(ast_scope(lits[i])); - if(frame >= frames) frame = frames-1; // could happen if contains no symbols - } - else { - frame = range_min(ast_scope(lits[i])); - if(frame < 0){ - frame = range_max(ast_scope(lits[i])); // could happen if contains no symbols - if(frame >= frames) frame = frames-1; - } - } - preds[frame] = mk_and(preds[frame],mk_not(lits[i])); - } - - - std::vector itps; // holds interpolants - - -#if 1 - ++lemma_count; - // std::cout << "lemma: " << lemma_count << std::endl; - if(lemma_count == SHOW_LEMMA_COUNT){ - for(unsigned i = 0; i < lits.size(); i++) - show_lit(lits[i]); - std::cerr << "lemma written to file lemma.smt:\n"; - iz3base foo(*this,preds,std::vector(),std::vector()); - foo.print("lemma.smt"); - throw invalid_lemma(); - } -#endif - -#if 0 - std::cout << "\nLemma:\n"; - for(unsigned i = 0; i < lits.size(); i++) - show_lit(lits[i]); -#endif - - // interpolate using secondary prover - profiling::timer_start("secondary prover"); - int sat = secondary->interpolate(preds,itps); - profiling::timer_stop("secondary prover"); - - std::cout << "lemma done" << std::endl; - - // if sat, lemma isn't valid, something is wrong - if(sat){ -#if 1 - std::cerr << "invalid lemma written to file invalid_lemma.smt:\n"; - iz3base foo(*this,preds,std::vector(),std::vector()); - foo.print("invalid_lemma.smt"); -#endif - throw iz3_incompleteness(); - } - assert(sat == 0); // if sat, lemma doesn't hold! - - // quantifiy the localization vars - for(unsigned i = 0; i < itps.size(); i++) - itps[i] = add_quants(itps[i],0,i); - - // Make a lemma, storing interpolants - Iproof::node res = iproof->make_lemma(lits,itps); - -#if 0 - std::cout << "Lemma interps\n"; - for(unsigned i = 0; i < itps.size(); i++) - show(itps[i]); -#endif - - // Reset state for the next lemma - antes.clear(); - antes_added.clear(); - clear_localization(); // use a fresh localization for each lemma - - return res; - } - - // sanity check: make sure that any non-local lit is really resolved - // with something in the non_local_lits set - - void check_non_local(ast lit, non_local_lits *nll){ - if(nll) - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - ast con = (*it)->pivot; - if(con == mk_not(lit)) return; - } - assert(0 && "bug in non-local resolution handling"); - } - - - void get_local_conclusion_lits(ast proof, bool expect_clause, AstSet &lits){ - std::vector reslits; - if(expect_clause) - get_Z3_lits(conc(proof),reslits); - else reslits.push_back(conc(proof)); - for(unsigned i = 0; i < reslits.size(); i++) - if(is_local(reslits[i])) - lits.insert(reslits[i]); - AstSet &pfhyps = get_hyps(proof); - for(AstSet::iterator hit = pfhyps.begin(), hen = pfhyps.end(); hit != hen; ++hit) - if(is_local(*hit)) - lits.insert(mk_not(*hit)); - } - - - void collect_resolvent_lits(Z3_resolvent *res, const AstSet &hyps, std::vector &lits){ - if(!res->is_unit){ - std::vector reslits; - get_Z3_lits(conc(res->proof),reslits); - for(unsigned i = 0; i < reslits.size(); i++) - if(reslits[i] != res->pivot) - lits.push_back(reslits[i]); - } - AstSet &pfhyps = get_hyps(res->proof); - for(AstSet::iterator hit = pfhyps.begin(), hen = pfhyps.end(); hit != hen; ++hit) - if(hyps.find(*hit) == hyps.end()) - lits.push_back(mk_not(*hit)); - } - - void filter_resolvent_lits(non_local_lits *nll, std::vector &lits){ - std::vector orig_lits; orig_lits.swap(lits); - std::set pivs; - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - pivs.insert(res->pivot); - pivs.insert(mk_not(res->pivot)); - } - for(unsigned i = 0; i < orig_lits.size(); i++) - if(pivs.find(orig_lits[i]) == pivs.end()) - lits.push_back(orig_lits[i]); - } - - void collect_all_resolvent_lits(non_local_lits *nll, std::vector &lits){ - if(nll){ - std::vector orig_lits; orig_lits.swap(lits); - std::set pivs; - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - pivs.insert(res->pivot); - pivs.insert(mk_not(res->pivot)); - } - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - { - std::vector reslits; - if(!res->is_unit) get_Z3_lits(conc(res->proof),reslits); - else reslits.push_back(conc(res->proof)); - for(unsigned i = 0; i < reslits.size(); i++) -#if 0 - if(reslits[i] != res->pivot && pivs.find(reslits[i]) == pivs.end()) -#endif - if(is_local(reslits[i])) - lits.push_back(reslits[i]); - } - } - for(unsigned i = 0; i < orig_lits.size(); i++) - if(pivs.find(orig_lits[i]) == pivs.end()) - lits.push_back(orig_lits[i]); - } - } - - void collect_proof_clause(ast proof, bool expect_clause, std::vector &lits){ - if(expect_clause) - get_Z3_lits(conc(proof),lits); - else - lits.push_back(from_ast(conc(proof))); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator hit = hyps.begin(), hen = hyps.end(); hit != hen; ++hit) - lits.push_back(mk_not(*hit)); - } - - - // turn a bunch of literals into a lemma, replacing - // non-local lits with their local equivalents - // adds the accumulated antecedents (antes) as - // proof obligations of the lemma - - Iproof::node fix_lemma(std::vector &con_lits, AstSet &hyps, non_local_lits *nll){ - std::vector lits(con_lits); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - lits.push_back(mk_not(*it)); - if(nll){ - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - collect_resolvent_lits(res,hyps,lits); - add_antes(res->proof); - } - filter_resolvent_lits(nll,lits); - } - for(unsigned int i = 0; i < lits.size(); i++){ - EquivTab::iterator it = equivs.find(lits[i]); - if(it != equivs.end()){ - lits[i] = it->second.first; // replace with local equivalent - add_antes(it->second.second); // collect the premises that prove this - } - else { - if(!is_local(lits[i])){ - check_non_local(lits[i],nll); - lits[i] = mk_false(); - } - } - } - // TODO: should check here that derivation is local? - Iproof::node res = prove_lemma(lits); - return res; - } - - int num_lits(ast ast){ - opr dk = op(ast); - if(dk == False) - return 0; - if(dk == Or){ - unsigned nargs = num_args(ast); - int n = 0; - for(unsigned i = 0; i < nargs; i++) // do all the sub_terms - n += num_lits(arg(ast,i)); - return n; - } - else - return 1; - } - - struct non_lit_local_ante: public iz3_exception { - non_lit_local_ante(): iz3_exception("non_lit_local_ante") {} - }; - - bool local_antes_simple; - - bool add_local_antes(ast proof, AstSet &hyps, bool expect_clause = false){ - if(antes_added.find(proof) != antes_added.end()) return true; - antes_added.insert(proof); - ast con = from_ast(conc(proof)); - pfrule dk = pr(proof); - if(is_local(con) || equivs.find(con) != equivs.end()){ - if(!expect_clause || num_lits(conc(proof)) == 1){ - AstSet &this_hyps = get_hyps(proof); - if(std::includes(hyps.begin(),hyps.end(),this_hyps.begin(),this_hyps.end())){ - // if(hyps.find(con) == hyps.end()) -#if 0 - if(/* lemma_count == SHOW_LEMMA_COUNT - 1 && */ !is_literal_or_lit_iff(conc(proof))){ - std::cout << "\nnon-lit local ante\n"; - show_step(proof); - show(conc(proof)); - throw non_lit_local_ante(); - } -#endif - local_antes.push_back(proof); - return true; - } - else - ; //std::cout << "bar!\n"; - } - } - if(dk == PR_ASSERTED - //|| dk == PR_HYPOTHESIS - //|| dk == PR_TH_LEMMA - || dk == PR_QUANT_INST - //|| dk == PR_UNIT_RESOLUTION - //|| dk == PR_LEMMA - ) - return false; - if(dk == PR_HYPOTHESIS && hyps.find(con) != hyps.end()) - ; //std::cout << "blif!\n"; - if(dk == PR_HYPOTHESIS - || dk == PR_LEMMA) - ; //std::cout << "foo!\n"; - if(dk == PR_TH_LEMMA && num_prems(proof) == 0){ - // Check if this is an axiom instance - get_axiom_instance(conc(proof)); - } - - // #define SIMPLE_PROOFS -#ifdef SIMPLE_PROOFS - if(!(dk == PR_TRANSITIVITY - || dk == PR_MONOTONICITY)) - local_antes_simple = false; -#endif - - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - try { - if(!add_local_antes(arg, hyps, dk == PR_UNIT_RESOLUTION && i == 0)) - return false; - } - catch (const non_lit_local_ante &) { - std::cout << "\n"; - show_step(proof); - show(conc(proof)); - throw non_lit_local_ante(); - } - } - return true; - } - - std::vector lit_trace; - hash_set marked_proofs; - - bool proof_has_lit(const ast &proof, const ast &lit){ - AstSet &hyps = get_hyps(proof); - if(hyps.find(mk_not(lit)) != hyps.end()) - return true; - std::vector lits; - ast con = conc(proof); - get_Z3_lits(con, lits); - for(unsigned i = 0; i < lits.size(); i++) - if(lits[i] == lit) - return true; - return false; - } - - - void trace_lit_rec(const ast &lit, const ast &proof, AstHashSet &memo){ - if(memo.find(proof) == memo.end()){ - memo.insert(proof); - AstSet &hyps = get_hyps(proof); - std::vector lits; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - lits.push_back(mk_not(*it)); - ast con = conc(proof); - get_Z3_lits(con, lits); - for(unsigned i = 0; i < lits.size(); i++){ - if(lits[i] == lit){ - print_expr(std::cout,proof); - std::cout << "\n"; - marked_proofs.insert(proof); - pfrule dk = pr(proof); - if(dk == PR_UNIT_RESOLUTION || dk == PR_LEMMA){ - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - trace_lit_rec(lit,arg,memo); - } - } - else - lit_trace.push_back(proof); - } - } - } - } - - ast traced_lit; - - int trace_lit(const ast &lit, const ast &proof){ - marked_proofs.clear(); - lit_trace.clear(); - traced_lit = lit; - AstHashSet memo; - trace_lit_rec(lit,proof,memo); - return lit_trace.size(); - } - - bool is_literal_or_lit_iff(const ast &lit){ - if(my_is_literal(lit)) return true; - if(op(lit) == Iff){ - return my_is_literal(arg(lit,0)) && my_is_literal(arg(lit,1)); - } - return false; - } - - bool my_is_literal(const ast &lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - int f = op(abslit); - return !(f == And || f == Or || f == Iff); - } - - void print_lit(const ast &lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - if(!is_literal_or_lit_iff(lit)){ - if(is_not(lit)) std::cout << "~"; - std::cout << "["; - print_expr(std::cout,abslit); - std::cout << "]"; - } - else - print_expr(std::cout,lit); - } - - void show_lit(const ast &lit){ - print_lit(lit); - std::cout << "\n"; - } - - void print_z3_lit(const ast &a){ - print_lit(from_ast(a)); - } - - void show_z3_lit(const ast &a){ - print_z3_lit(a); - std::cout << "\n"; - } - - - void show_con(const ast &proof, bool brief){ - if(!traced_lit.null() && proof_has_lit(proof,traced_lit)) - std::cout << "(*) "; - ast con = conc(proof); - AstSet &hyps = get_hyps(proof); - int count = 0; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - if(brief && ++count > 5){ - std::cout << "... "; - break; - } - print_lit(*it); - std::cout << " "; - } - std::cout << "|- "; - std::vector lits; - get_Z3_lits(con,lits); - for(unsigned i = 0; i < lits.size(); i++){ - print_lit(lits[i]); - std::cout << " "; - } - std::cout << "\n"; - } - - void show_step(const ast &proof){ - std::cout << "\n"; - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - std::cout << "(" << i << ") "; - ast arg = prem(proof,i); - show_con(arg,true); - } - std::cout << "|------ "; - std::cout << string_of_symbol(sym(proof)) << "\n"; - show_con(proof,false); - } - - void show_marked( const ast &proof){ - std::cout << "\n"; - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - if(!traced_lit.null() && proof_has_lit(arg,traced_lit)){ - std::cout << "(" << i << ") "; - show_con(arg,true); - } - } - } - - std::vector pfhist; - int pfhist_pos; - - void pfgoto(const ast &proof){ - if(pfhist.size() == 0) - pfhist_pos = 0; - else pfhist_pos++; - pfhist.resize(pfhist_pos); - pfhist.push_back(proof); - show_step(proof); - } - - void show_nll(non_local_lits *nll){ - if(!nll)return; - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - show_step(res->proof); - std::cout << "Pivot: "; - show(res->pivot); - std::cout << std::endl; - } - } - - void pfback(){ - if(pfhist_pos > 0){ - pfhist_pos--; - show_step(pfhist[pfhist_pos]); - } - } - - void pffwd(){ - if(pfhist_pos < ((int)pfhist.size()) - 1){ - pfhist_pos++; - show_step(pfhist[pfhist_pos]); - } - } - - void pfprem(int i){ - if(pfhist.size() > 0){ - ast proof = pfhist[pfhist_pos]; - unsigned nprems = num_prems(proof); - if(i >= 0 && i < (int)nprems) - pfgoto(prem(proof,i)); - } - } - - int extract_th_lemma_common(std::vector &lits, non_local_lits *nll, bool lemma_nll = true){ - std::vector la = local_antes; - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - // std::vector lits; - AstSet hyps; // no hyps - for(unsigned i = 0; i < la.size(); i++) - lits.push_back(mk_not(from_ast(conc(la[i])))); - // lits.push_back(from_ast(conc(proof))); - Iproof::node res =fix_lemma(lits,hyps, lemma_nll ? nll : nullptr); - for(unsigned i = 0; i < la.size(); i++){ - Iproof::node q = translate_main(la[i],nll,false); - ast pnode = from_ast(conc(la[i])); - assert(is_local(pnode) || equivs.find(pnode) != equivs.end()); - Iproof::node neg = res; - Iproof::node pos = q; - if(is_not(pnode)){ - pnode = mk_not(pnode); - std::swap(neg,pos); - } - try { - res = iproof->make_resolution(pnode,neg,pos); - } - catch (const iz3proof::proof_error &){ - std::cout << "\nresolution error in theory lemma\n"; - std::cout << "lits:\n"; - for(unsigned j = 0; j < lits.size(); j++) - show_lit(lits[j]); - std::cout << "\nstep:\n"; - show_step(la[i]); - throw invalid_lemma(); - } - } - return res; - } - - Iproof::node extract_simple_proof(const ast &proof, hash_set &leaves){ - if(leaves.find(proof) != leaves.end()) - return iproof->make_hypothesis(conc(proof)); - ast con = from_ast(conc(proof)); - pfrule dk = pr(proof); - unsigned nprems = num_prems(proof); - std::vector args(nprems); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - args[i] = extract_simple_proof(arg,leaves); - } - - switch(dk){ - case PR_TRANSITIVITY: - return iproof->make_transitivity(con,args[0],args[1]); - case PR_MONOTONICITY: - return iproof->make_congruence(con,args); - case PR_REFLEXIVITY: - return iproof->make_reflexivity(con); - case PR_SYMMETRY: - return iproof->make_symmetry(con,args[0]); - } - assert(0 && "extract_simple_proof: unknown op"); - return 0; - } - - int extract_th_lemma_simple(const ast &proof, std::vector &lits){ - std::vector la = local_antes; - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - - hash_set leaves; - for(unsigned i = 0; i < la.size(); i++) - leaves.insert(la[i]); - - Iproof::node ipf = extract_simple_proof(proof,leaves); - ast con = from_ast(conc(proof)); - Iproof::node hyp = iproof->make_hypothesis(mk_not(con)); - ipf = iproof->make_eqcontra(ipf,hyp); - - // std::vector lits; - AstSet hyps; // no hyps - for(unsigned i = 0; i < la.size(); i++) - lits.push_back(mk_not(from_ast(conc(la[i])))); - // lits.push_back(from_ast(conc(proof))); - - Iproof::node res = iproof->make_contra(ipf,lits); - - for(unsigned i = 0; i < la.size(); i++){ - Iproof::node q = translate_main(la[i],nullptr,false); - ast pnode = from_ast(conc(la[i])); - assert(is_local(pnode) || equivs.find(pnode) != equivs.end()); - Iproof::node neg = res; - Iproof::node pos = q; - if(is_not(pnode)){ - pnode = mk_not(pnode); - std::swap(neg,pos); - } - try { - res = iproof->make_resolution(pnode,neg,pos); - } - catch (const iz3proof::proof_error &){ - std::cout << "\nresolution error in theory lemma\n"; - std::cout << "lits:\n"; - for(unsigned j = 0; j < lits.size(); j++) - show_lit(lits[j]); - std::cout << "\nstep:\n"; - show_step(la[i]); - throw invalid_lemma(); - } - } - return res; - } - - // #define NEW_EXTRACT_TH_LEMMA - - void get_local_hyps(const ast &proof, std::set &res){ - std::set hyps = get_hyps(proof); - for(std::set::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - ast hyp = *it; - if(is_local(hyp)) - res.insert(hyp); - } - } - - int extract_th_lemma(ast proof, std::vector &lits, non_local_lits *nll){ - pfrule dk = pr(proof); - unsigned nprems = num_prems(proof); -#ifdef NEW_EXTRACT_TH_LEMMA - if(nprems == 0 && !nll) -#else - if(nprems == 0) -#endif - return 0; - if(nprems == 0 && dk == PR_TH_LEMMA) - // Check if this is an axiom instance - get_axiom_instance(conc(proof)); - - local_antes_simple = true; - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - if(!add_local_antes(arg,get_hyps(proof))){ - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - antes.clear(); - return 0; - } - } -#ifdef NEW_EXTRACT_TH_LEMMA - bool lemma_nll = nprems > 1; - if(nll && !lemma_nll){ - lemma_nll = false; - // std::cout << "lemma count = " << nll_lemma_count << "\n"; - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - ast arg = res->proof; - std::set loc_hyps; get_local_hyps(arg,loc_hyps); - if(!add_local_antes(arg,loc_hyps)){ - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - antes.clear(); - return 0; - } - } - collect_all_resolvent_lits(nll,lits); - } - int my_count = nll_lemma_count++; - int res; - try { - res = extract_th_lemma_common(lits,nll,lemma_nll); - } -#if 1 - catch (const invalid_lemma &) { - std::cout << "\n\nlemma: " << my_count; - std::cout << "\n\nproof node: \n"; - show_step(proof); - std::cout << "\n\nnon-local: \n"; - show_nll(nll); - pfgoto(nll->proofs[0]->proof); - show(conc(pfhist.back())); - pfprem(1); - show(conc(pfhist.back())); - pfprem(0); - show(conc(pfhist.back())); - pfprem(0); - show(conc(pfhist.back())); - pfprem(0); - show(conc(pfhist.back())); - std::cout << "\n\nliterals: \n"; - for(int i = 0; i < lits.size(); i++) - show_lit(lits[i]); - throw invalid_lemma(); - } -#endif - - return res; -#else -#ifdef SIMPLE_PROOFS - if(local_antes_simple && !nll) - return extract_th_lemma_simple(proof, lits); -#endif - return extract_th_lemma_common(lits,nll); -#endif - } - - int extract_th_lemma_ur(ast proof, int position, std::vector &lits, non_local_lits *nll){ - for(int i = 0; i <= position; i++){ - ast arg = prem(proof,i); - if(!add_local_antes(arg,get_hyps(proof),i==0)){ - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - antes.clear(); - return 0; - } - } - return extract_th_lemma_common(lits,nll); - } - - // see if any of the pushed resolvents are resolutions - // push the current proof into the latest such - int push_into_resolvent(ast proof, std::vector &lits, non_local_lits *nll, bool expect_clause){ - if(!nll) return 0; - if(num_args(proof) > 1) return 0; - ResolventAppSet resos = nll->proofs; - int pos = resos.size()-1; - for( ResolventAppSet::reverse_iterator it = resos.rbegin(), en = resos.rend(); it != en; ++it, --pos){ - Z3_resolvent *reso = *it; - ast ante = reso->proof; - ast pivot = reso->pivot; - bool is_unit = reso->is_unit; - pfrule dk = pr(ante); - bool pushable = dk == PR_UNIT_RESOLUTION || dk == PR_LEMMA; - if(!pushable && num_args(ante) > 1){ -#if 0 - if (!is_local(conc(ante))) - std::cout << "non-local "; - std::cout << "pushable!\n"; -#endif - pushable = true; - } - if(pushable){ - // remove the resolvent from list and add new clause as resolvent - resos.erase((++it).base()); - for(; pos < (int)resos.size(); pos++){ - Z3_resolvent *r = resos[pos]; - resos[pos] = find_resolvent(r->proof,r->is_unit,mk_not(pivot)); - } - resos.push_back(find_resolvent(proof,!expect_clause,mk_not(pivot))); - non_local_lits *new_nll = find_nll(resos); - try { - int res = translate_main(ante,new_nll,!is_unit); - return res; - } - catch (const invalid_lemma &) { - std::cout << "\n\npushing: \n"; - std::cout << "nproof node: \n"; - show_step(proof); - std::cout << "\n\nold non-local: \n"; - show_nll(nll); - std::cout << "\n\nnew non-local: \n"; - show_nll(new_nll); - throw invalid_lemma(); - } - } - } - return 0; // no pushed resolvents are resolution steps - } - - non_local_lits *find_nll(ResolventAppSet &proofs){ - if(proofs.empty()) - return (non_local_lits *)nullptr; - std::pair foo(non_local_lits(proofs),(non_local_lits *)nullptr); - std::pair::iterator,bool> bar = - non_local_lits_unique.insert(foo); - non_local_lits *&res = bar.first->second; - if(bar.second) - res = new non_local_lits(bar.first->first); - return res; - } - - Z3_resolvent *find_resolvent(ast proof, bool unit, ast pivot){ - std::pair foo(Z3_resolvent(proof,unit,pivot),(Z3_resolvent *)nullptr); - std::pair::iterator,bool> bar = - Z3_resolvent_unique.insert(foo); - Z3_resolvent *&res = bar.first->second; - if(bar.second) - res = new Z3_resolvent(bar.first->first); - return res; - } - - // translate a unit resolution at position pos of given app - int translate_ur(ast proof, int position, non_local_lits *nll){ - ast ante = prem(proof,position); - if(position <= 0) - return translate_main(ante, nll); - ast pnode = conc(ante); - ast pnode_abs = !is_not(pnode) ? pnode : mk_not(pnode); - if(is_local(pnode) || equivs.find(pnode) != equivs.end()){ - Iproof::node neg = translate_ur(proof,position-1,nll); - Iproof::node pos = translate_main(ante, nll, false); - if(is_not(pnode)){ - pnode = mk_not(pnode); - std::swap(neg,pos); - } - try { - return iproof->make_resolution(pnode,neg,pos); - } - catch (const iz3proof::proof_error &){ - std::cout << "resolution error in unit_resolution, position" << position << "\n"; - show_step(proof); - throw invalid_lemma(); - } - } - else { - // non-local pivot we have no local equivalent for - if(true){ - // try pushing the non-local resolution up - pfrule dk = pr(ante); - non_local_lits *old_nll = nll; - if(dk == PR_HYPOTHESIS) - ; //std::cout << "non-local hyp!\n"; // resolving with a hyp is a no-op - else { - ResolventAppSet new_proofs; - if(nll) new_proofs = nll->proofs; - Z3_resolvent *reso = find_resolvent(ante,true,pnode); - new_proofs.push_back(reso); - nll = find_nll(new_proofs); - } - try { - return translate_ur(proof,position-1,nll); - } - catch (const invalid_lemma &) { - if(old_nll != nll){ - std::cout << "\n\nadded_nll: \n"; - std::cout << "nproof node: \n"; - show_step(proof); - std::cout << "\n\new non-local step: \n"; - show_step(nll->proofs.back()->proof); - } - throw invalid_lemma(); - } - - } - else { - // just make a lemma - std::vector lits; - do_unit_resolution(proof,position,lits); - int res; - if(!(res = extract_th_lemma_ur(proof,position,lits,nll))){ - for(int i = 0; i <= position; i++){ - z3pf p = prem(proof,i); - add_antes(p); - } - res = fix_lemma(lits,get_hyps(proof),nll); - } - return res; - } - } - } - - non_local_lits *update_nll(ast proof, bool expect_clause, non_local_lits *nll){ - std::vector lits; - collect_proof_clause(proof,expect_clause,lits); - AstSet litset; - litset.insert(lits.begin(),lits.end()); - ResolventAppSet to_keep; - for(int i = nll->proofs.size()-1; i >= 0; --i){ - ast traced_lit = (nll->proofs[i])->pivot; - ast traced_lit_neg = mk_not(traced_lit); - if(litset.find(traced_lit) != litset.end() || litset.find(traced_lit_neg) != litset.end()){ - to_keep.push_back(nll->proofs[i]); - std::vector reslits; - AstSet dummy; - collect_resolvent_lits(nll->proofs[i],dummy,reslits); - litset.insert(reslits.begin(),reslits.end()); - } - } - if(to_keep.size() == nll->proofs.size()) return nll; - ResolventAppSet new_proofs; - for(int i = to_keep.size() - 1; i >= 0; --i) - new_proofs.push_back(to_keep[i]); - return find_nll(new_proofs); - } - - // translate a Z3 proof term into a secondary prover proof term - - Iproof::node translate_main(ast proof, non_local_lits *nll, bool expect_clause = true){ - non_local_lits *old_nll = nll; - if(nll) nll = update_nll(proof,expect_clause,nll); - AstToIpf &tr = nll ? non_local_translation[nll] : translation; - hash_map &trc = expect_clause ? tr.first : tr.second; - std::pair foo(proof,INT_MAX); - std::pair bar = trc.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - - - try { - int frame = get_locality(proof); - if(frame != -1){ - ast e = from_ast(conc(proof)); - if(frame >= frames) frame = frames - 1; - std::vector foo; - if(expect_clause) - get_Z3_lits(conc(proof),foo); - else - foo.push_back(e); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - foo.push_back(mk_not(*it)); - res = iproof->make_assumption(frame,foo); - return res; - } - - pfrule dk = pr(proof); - unsigned nprems = num_prems(proof); - if(dk == PR_UNIT_RESOLUTION){ - res = translate_ur(proof, nprems - 1, nll); - } - else if(dk == PR_LEMMA){ - ast contra = prem(proof,0); // this is a proof of false from some hyps - res = translate_main(contra, nll); - if(!expect_clause){ - std::vector foo; // the negations of the hyps form a clause - foo.push_back(from_ast(conc(proof))); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - foo.push_back(mk_not(*it)); - res = iproof->make_contra(res,foo); - } - } - else { - std::vector lits; - ast con = conc(proof); - if(expect_clause) - get_Z3_lits(con, lits); - else - lits.push_back(from_ast(con)); -#ifdef NEW_EXTRACT_TH_LEMMA - if(!(res = push_into_resolvent(proof,lits,nll,expect_clause))){ - if(!(res = extract_th_lemma(proof,lits,nll))){ -#else - if(!(res = extract_th_lemma(proof,lits,nll))){ - if(!(res = push_into_resolvent(proof,lits,nll,expect_clause))){ -#endif - // std::cout << "extract theory lemma failed\n"; - add_antes(proof); - res = fix_lemma(lits,get_hyps(proof),nll); - } - } - } -#ifdef CHECK_PROOFS - - if(0){ - AstSet zpf_con_lits, ipf_con_lits; - get_local_conclusion_lits(proof, expect_clause, zpf_con_lits); - if(nll){ - for(unsigned i = 0; i < nll->proofs.size(); i++) - get_local_conclusion_lits(nll->proofs[i]->proof,!nll->proofs[i]->is_unit,zpf_con_lits); - } - std::vector ipf_con; - iproof->get_conclusion(res,ipf_con); - for(unsigned i = 0; i < ipf_con.size(); i++) - ipf_con_lits.insert(ipf_con[i]); - if(!(ipf_con_lits == zpf_con_lits)){ - std::cout << "proof error:\n"; - std::cout << "expected lits:\n"; - for(AstSet::iterator hit = zpf_con_lits.begin(), hen = zpf_con_lits.end(); hit != hen; ++hit) - show_lit(*hit); - std::cout << "got lits:\n"; - for(AstSet::iterator hit = ipf_con_lits.begin(), hen = ipf_con_lits.end(); hit != hen; ++hit) - show_lit(*hit); - std::cout << "\nproof step:"; - show_step(proof); - std::cout << "\n"; - throw invalid_lemma(); - } - } -#endif - - return res; - } - - catch (const invalid_lemma &) { - if(old_nll != nll){ - std::cout << "\n\nupdated nll: \n"; - std::cout << "nproof node: \n"; - show_step(proof); - std::cout << "\n\new non-local: \n"; - show_nll(nll); - } - throw invalid_lemma(); - } - - } - - // Proof translation is in two stages: - // 1) Translate ast proof term to Zproof - // 2) Translate Zproof to Iproof - - Iproof::node translate(ast proof, Iproof &dst) override { - iproof = &dst; - Iproof::node Ipf = translate_main(proof,nullptr); // builds result in dst - return Ipf; - } - - iz3translation_direct(iz3mgr &mgr, - iz3secondary *_secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory) - : iz3translation(mgr, cnsts, parents, theory) - { - secondary = _secondary; - frames = cnsts.size(); - traced_lit = ast(); - } - - ~iz3translation_direct() override { - for(hash_map::iterator - it = non_local_lits_unique.begin(), - en = non_local_lits_unique.end(); - it != en; - ++it) - delete it->second; - - for(hash_map::iterator - it = Z3_resolvent_unique.begin(), - en = Z3_resolvent_unique.end(); - it != en; - ++it) - delete it->second; - } - }; - - - - -#ifdef IZ3_TRANSLATE_DIRECT - - iz3translation *iz3translation::create(iz3mgr &mgr, - iz3secondary *secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory){ - return new iz3translation_direct(mgr,secondary,cnsts,parents,theory); - } - - -#if 1 - - void iz3translation_direct_trace_lit(iz3translation_direct *p, iz3mgr::ast lit, iz3mgr::ast proof){ - p->trace_lit(lit, proof); - } - - void iz3translation_direct_show_step(iz3translation_direct *p, iz3mgr::ast proof){ - p->show_step(proof); - } - - void iz3translation_direct_show_marked(iz3translation_direct *p, iz3mgr::ast proof){ - p->show_marked(proof); - } - - void iz3translation_direct_show_lit(iz3translation_direct *p, iz3mgr::ast lit){ - p->show_lit(lit); - } - - void iz3translation_direct_show_z3_lit(iz3translation_direct *p, iz3mgr::ast a){ - p->show_z3_lit(a); - } - - void iz3translation_direct_pfgoto(iz3translation_direct *p, iz3mgr::ast proof){ - p->pfgoto(proof); - } - - void iz3translation_direct_show_nll(iz3translation_direct *p, non_local_lits *nll){ - p->show_nll(nll); - } - - void iz3translation_direct_pfback(iz3translation_direct *p ){ - p->pfback(); - } - - void iz3translation_direct_pffwd(iz3translation_direct *p ){ - p->pffwd(); - } - - void iz3translation_direct_pfprem(iz3translation_direct *p, int i){ - p->pfprem(i); - } - - - struct stdio_fixer { - stdio_fixer(){ - std::cout.rdbuf()->pubsetbuf(0,0); - } - - } my_stdio_fixer; - -#endif - -#endif - - diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 54c07da28..cc14de5ce 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -188,7 +188,7 @@ namespace datalog { if (m_trail.get_num_scopes() == 0) { throw default_exception("there are no backtracking points to pop to"); } - if (m_engine.get() && get_engine() != DUALITY_ENGINE) { + if (m_engine.get()) { throw default_exception("pop operation is only supported by duality engine"); } m_trail.pop_scope(1); @@ -601,11 +601,6 @@ namespace datalog { m_rule_properties.check_existential_tail(); m_rule_properties.check_for_negated_predicates(); break; - case DUALITY_ENGINE: - m_rule_properties.collect(r); - m_rule_properties.check_existential_tail(); - m_rule_properties.check_for_negated_predicates(); - break; case CLP_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_existential_tail(); @@ -828,9 +823,6 @@ namespace datalog { else if (e == symbol("clp")) { m_engine_type = CLP_ENGINE; } - else if (e == symbol("duality")) { - m_engine_type = DUALITY_ENGINE; - } else if (e == symbol("ddnf")) { m_engine_type = DDNF_ENGINE; } @@ -875,11 +867,6 @@ namespace datalog { case DDNF_ENGINE: flush_add_rules(); break; - case DUALITY_ENGINE: - // this lets us use duality with SAS 2013 abstraction - if(quantify_arrays()) - flush_add_rules(); - break; default: UNREACHABLE(); } diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index 576ed7f6b..b9ac6e7b5 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -32,7 +32,6 @@ namespace datalog { QBMC_ENGINE, TAB_ENGINE, CLP_ENGINE, - DUALITY_ENGINE, DDNF_ENGINE, LAST_ENGINE }; diff --git a/src/muz/duality/CMakeLists.txt b/src/muz/duality/CMakeLists.txt deleted file mode 100644 index f005b88b1..000000000 --- a/src/muz/duality/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -z3_add_component(duality_intf - SOURCES - duality_dl_interface.cpp - COMPONENT_DEPENDENCIES - duality - muz - transforms -) diff --git a/src/muz/duality/duality_dl_interface.cpp b/src/muz/duality/duality_dl_interface.cpp deleted file mode 100644 index 60ed1755c..000000000 --- a/src/muz/duality/duality_dl_interface.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - duality_dl_interface.cpp - - Abstract: - - SMT2 interface for Duality - - Author: - - Krystof Hoder (t-khoder) 2011-9-22. - Modified by Ken McMIllan (kenmcmil) 2013-4-18. - - Revision History: - - --*/ - -#include "muz/base/dl_context.h" -#include "muz/transforms/dl_mk_coi_filter.h" -#include "muz/transforms/dl_mk_interp_tail_simplifier.h" -#include "muz/transforms/dl_mk_subsumption_checker.h" -#include "muz/transforms/dl_mk_rule_inliner.h" -#include "muz/base/dl_rule.h" -#include "muz/base/dl_rule_transformer.h" -#include "parsers/smt2/smt2parser.h" -#include "muz/duality/duality_dl_interface.h" -#include "muz/base/dl_rule_set.h" -#include "muz/transforms/dl_mk_slice.h" -#include "muz/transforms/dl_mk_unfold.h" -#include "muz/transforms/dl_mk_coalesce.h" -#include "ast/expr_abstract.h" -#include "model/model_smt2_pp.h" -#include "model/model_v2_pp.h" -#include "muz/base/fixedpoint_params.hpp" -#include "ast/used_vars.h" -#include "ast/func_decl_dependencies.h" -#include "muz/transforms/dl_transforms.h" - -// template class symbol_table; - -#ifdef WIN32 -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "duality/duality.h" -#include "duality/duality_profiling.h" - -// using namespace Duality; - -namespace Duality { - - enum DualityStatus {StatusModel, StatusRefutation, StatusUnknown, StatusNull}; - - class duality_data { - public: - context ctx; - RPFP::LogicSolver *ls; - RPFP *rpfp; - - DualityStatus status; - std::vector clauses; - std::vector > clause_labels; - hash_map map; // edges to clauses - Solver *old_rs; - Solver::Counterexample cex; - - duality_data(ast_manager &_m) : ctx(_m,config(params_ref())) { - ls = nullptr; - rpfp = nullptr; - status = StatusNull; - old_rs = nullptr; - } - ~duality_data(){ - if(old_rs) - dealloc(old_rs); - if(rpfp) - dealloc(rpfp); - if(ls) - dealloc(ls); - } - }; - - - dl_interface::dl_interface(datalog::context& dl_ctx) : - engine_base(dl_ctx.get_manager(), "duality"), - m_ctx(dl_ctx) - - { - _d = nullptr; - // dl_ctx.get_manager().toggle_proof_mode(PGM_FINE); - } - - - dl_interface::~dl_interface() { - if(_d) - dealloc(_d); - } - - - // - // Check if the new rules are weaker so that we can - // re-use existing context. - // -#if 0 - void dl_interface::check_reset() { - // TODO - datalog::rule_ref_vector const& new_rules = m_ctx.get_rules().get_rules(); - datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules(); - bool is_subsumed = !old_rules.empty(); - for (unsigned i = 0; is_subsumed && i < new_rules.size(); ++i) { - is_subsumed = false; - for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) { - if (m_ctx.check_subsumes(*old_rules[j], *new_rules[i])) { - is_subsumed = true; - } - } - if (!is_subsumed) { - TRACE("pdr", new_rules[i]->display(m_ctx, tout << "Fresh rule ");); - m_context->reset(); - } - } - m_old_rules.reset(); - m_old_rules.add_rules(new_rules.size(), new_rules.c_ptr()); - } -#endif - - - lbool dl_interface::query(::expr * query) { - - // we restore the initial state in the datalog context - m_ctx.ensure_opened(); - - // if there is old data, get the cex and dispose (later) - duality_data *old_data = _d; - Solver *old_rs = nullptr; - if(old_data){ - old_rs = old_data->old_rs; - old_rs->GetCounterexample().swap(old_data->cex); - } - - scoped_proof generate_proofs_please(m_ctx.get_manager()); - - // make a new problem and solver - _d = alloc(duality_data,m_ctx.get_manager()); - _d->ctx.set("mbqi",m_ctx.get_params().duality_mbqi()); - _d->ls = alloc(RPFP::iZ3LogicSolver,_d->ctx); - _d->rpfp = alloc(RPFP,_d->ls); - - - - expr_ref_vector rules(m_ctx.get_manager()); - svector< ::symbol> names; - unsigned_vector bounds; - // m_ctx.get_rules_as_formulas(rules, names); - - - // If using SAS 2013 abstractiion, we need to perform some transforms - expr_ref query_ref(m_ctx.get_manager()); - if(m_ctx.quantify_arrays()){ - datalog::rule_manager& rm = m_ctx.get_rule_manager(); - rm.mk_query(query, m_ctx.get_rules()); - apply_default_transformation(m_ctx); - datalog::rule_set &rs = m_ctx.get_rules(); - if(m_ctx.get_rules().get_output_predicates().empty()) - query_ref = m_ctx.get_manager().mk_false(); - else { - func_decl_ref query_pred(m_ctx.get_manager()); - query_pred = m_ctx.get_rules().get_output_predicate(); - ptr_vector sorts; - unsigned nargs = query_pred.get()->get_arity(); - expr_ref_vector vars(m_ctx.get_manager()); - for(unsigned i = 0; i < nargs; i++){ - ::sort *s = query_pred.get()->get_domain(i); - vars.push_back(m_ctx.get_manager().mk_var(nargs-1-i,s)); - } - query_ref = m_ctx.get_manager().mk_app(query_pred.get(),nargs,vars.c_ptr()); - query = query_ref.get(); - } - unsigned nrules = rs.get_num_rules(); - for(unsigned i = 0; i < nrules; i++){ - expr_ref f(m_ctx.get_manager()); - rm.to_formula(*rs.get_rule(i), f); - rules.push_back(f); - } - } - else - m_ctx.get_raw_rule_formulas(rules, names, bounds); - - // get all the rules as clauses - std::vector &clauses = _d->clauses; - clauses.clear(); - for (unsigned i = 0; i < rules.size(); ++i) { - expr e(_d->ctx,rules[i].get()); - clauses.push_back(e); - } - - std::vector b_sorts; - std::vector b_names; - used_vars uv; - uv.process(query); - unsigned nuv = uv.get_max_found_var_idx_plus_1(); - for(int i = nuv-1; i >= 0; i--){ // var indices are backward - ::sort * s = uv.get(i); - if(!s) - s = _d->ctx.m().mk_bool_sort(); // missing var, whatever - b_sorts.push_back(sort(_d->ctx,s)); - b_names.push_back(symbol(_d->ctx,::symbol(i))); // names? - } - -#if 0 - // turn the query into a clause - expr q(_d->ctx,m_ctx.bind_variables(query,false)); - - std::vector b_sorts; - std::vector b_names; - if (q.is_quantifier() && !q.is_quantifier_forall()) { - int bound = q.get_quantifier_num_bound(); - for(int j = 0; j < bound; j++){ - b_sorts.push_back(q.get_quantifier_bound_sort(j)); - b_names.push_back(q.get_quantifier_bound_name(j)); - } - q = q.arg(0); - } -#else - expr q(_d->ctx,query); -#endif - - expr qc = implies(q,_d->ctx.bool_val(false)); - qc = _d->ctx.make_quant(Forall,b_sorts,b_names,qc); - clauses.push_back(qc); - bounds.push_back(UINT_MAX); - - // get the background axioms - unsigned num_asserts = m_ctx.get_num_assertions(); - for (unsigned i = 0; i < num_asserts; ++i) { - expr e(_d->ctx,m_ctx.get_assertion(i)); - _d->rpfp->AssertAxiom(e); - } - - // make sure each predicate is the head of at least one clause - func_decl_set heads; - for(unsigned i = 0; i < clauses.size(); i++){ - expr cl = clauses[i]; - - while(true){ - if(cl.is_app()){ - decl_kind k = cl.decl().get_decl_kind(); - if(k == Implies) - cl = cl.arg(1); - else { - heads.insert(cl.decl()); - break; - } - } - else if(cl.is_quantifier()) - cl = cl.body(); - else break; - } - } - ast_ref_vector const &pinned = m_ctx.get_pinned(); - for(unsigned i = 0; i < pinned.size(); i++){ - ::ast *fa = pinned[i]; - if(is_func_decl(fa)){ - ::func_decl *fd = to_func_decl(fa); - if (m_ctx.is_predicate(fd)) { - func_decl f(_d->ctx, fd); - if (!heads.contains(fd)) { - int arity = f.arity(); - std::vector args; - args.reserve(arity); - for (int j = 0; j < arity; j++) - args.push_back(_d->ctx.fresh_func_decl("X", f.domain(j))()); - expr c = implies(_d->ctx.bool_val(false), f(args)); - c = _d->ctx.make_quant(Forall, args, c); - clauses.push_back(c); - bounds.push_back(UINT_MAX); - } - } - } - } - unsigned rb = m_ctx.get_params().duality_recursion_bound(); - std::vector std_bounds; - for(unsigned i = 0; i < bounds.size(); i++){ - unsigned b = bounds[i]; - if (b == UINT_MAX) b = rb; - std_bounds.push_back(b); - } - - // creates 1-1 map between clauses and rpfp edges - _d->rpfp->FromClauses(clauses,&std_bounds); - - // populate the edge-to-clause map - for(unsigned i = 0; i < _d->rpfp->edges.size(); ++i) - _d->map[_d->rpfp->edges[i]] = i; - - // create a solver object - - Solver *rs = Solver::Create("duality", _d->rpfp); - - if(old_rs) - rs->LearnFrom(old_rs); // new solver gets hints from old solver - - // set its options - IF_VERBOSE(1, rs->SetOption("report","1");); - rs->SetOption("full_expand",m_ctx.get_params().duality_full_expand() ? "1" : "0"); - rs->SetOption("no_conj",m_ctx.get_params().duality_no_conj() ? "1" : "0"); - rs->SetOption("feasible_edges",m_ctx.get_params().duality_feasible_edges() ? "1" : "0"); - rs->SetOption("use_underapprox",m_ctx.get_params().duality_use_underapprox() ? "1" : "0"); - rs->SetOption("stratified_inlining",m_ctx.get_params().duality_stratified_inlining() ? "1" : "0"); - rs->SetOption("batch_expand",m_ctx.get_params().duality_batch_expand() ? "1" : "0"); - rs->SetOption("conjecture_file",m_ctx.get_params().duality_conjecture_file()); - rs->SetOption("enable_restarts",m_ctx.get_params().duality_enable_restarts() ? "1" : "0"); -#if 0 - if(rb != UINT_MAX){ - std::ostringstream os; os << rb; - rs->SetOption("recursion_bound", os.str()); - } -#endif - - // Solve! - bool ans; - try { - ans = rs->Solve(); - } - catch (Duality::solver::cancel_exception &exn){ - throw default_exception(Z3_CANCELED_MSG); - } - catch (Duality::Solver::Incompleteness &exn){ - throw default_exception("incompleteness"); - } - - // profile! - - if(m_ctx.get_params().duality_profile()) - print_profile(std::cout); - - // save the result and counterexample if there is one - _d->status = ans ? StatusModel : StatusRefutation; - _d->cex.swap(rs->GetCounterexample()); // take ownership of cex - _d->old_rs = rs; // save this for later hints - - if(old_data){ - dealloc(old_data); // this deallocates the old solver if there is one - } - - // dealloc(rs); this is now owned by data - - // true means the RPFP problem is SAT, so the query is UNSAT - // but we return undef if the UNSAT result is bounded - if(ans){ - if(rs->IsResultRecursionBounded()){ -#if 0 - m_ctx.set_status(datalog::BOUNDED); - return l_undef; -#else - return l_false; -#endif - } - return l_false; - } - return l_true; - } - - expr_ref dl_interface::get_cover_delta(int level, ::func_decl* pred_orig) { - SASSERT(false); - return expr_ref(m_ctx.get_manager()); - } - - void dl_interface::add_cover(int level, ::func_decl* pred, ::expr* property) { - SASSERT(false); - } - - unsigned dl_interface::get_num_levels(::func_decl* pred) { - SASSERT(false); - return 0; - } - - void dl_interface::collect_statistics(::statistics& st) const { - } - - void dl_interface::reset_statistics() { - } - - static hash_set *local_func_decls; - - static void print_proof(dl_interface *d, std::ostream& out, RPFP *tree, RPFP::Node *root) { - context &ctx = d->dd()->ctx; - RPFP::Node &node = *root; - RPFP::Edge &edge = *node.Outgoing; - - // first, prove the children (that are actually used) - - for(unsigned i = 0; i < edge.Children.size(); i++){ - if(!tree->Empty(edge.Children[i])){ - print_proof(d,out,tree,edge.Children[i]); - } - } - - // print the label and the proved fact - - out << "(step s!" << node.number; - out << " (" << node.Name.name(); - for(unsigned i = 0; i < edge.F.IndParams.size(); i++) - out << " " << tree->Eval(&edge,edge.F.IndParams[i]); - out << ")\n"; - - // print the rule number - - out << " rule!" << node.Outgoing->map->number; - - // print the substitution - - out << " (subst\n"; - RPFP::Edge *orig_edge = edge.map; - int orig_clause = d->dd()->map[orig_edge]; - expr &t = d->dd()->clauses[orig_clause]; - if (t.is_quantifier() && t.is_quantifier_forall()) { - int bound = t.get_quantifier_num_bound(); - std::vector sorts; - std::vector names; - hash_map subst; - for(int j = 0; j < bound; j++){ - sort the_sort = t.get_quantifier_bound_sort(j); - symbol name = t.get_quantifier_bound_name(j); - expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort)); - out << " (= " << skolem << " " << tree->Eval(&edge,skolem) << ")\n"; - expr local_skolem = tree->Localize(&edge,skolem); - (*local_func_decls).insert(local_skolem.decl()); - } - } - out << " )\n"; - - out << " (labels"; - std::vector labels; - tree->GetLabels(&edge,labels); - for(unsigned j = 0; j < labels.size(); j++){ - out << " " << labels[j]; - } - - out << " )\n"; - - // reference the proofs of all the children, in syntactic order - // "true" means the child is not needed - - out << " (ref "; - for(unsigned i = 0; i < edge.Children.size(); i++){ - if(!tree->Empty(edge.Children[i])) - out << " s!" << edge.Children[i]->number; - else - out << " true"; - } - out << " )"; - out << ")\n"; - } - - - void dl_interface::display_certificate(std::ostream& out) const { - ((dl_interface *)this)->display_certificate_non_const(out); - } - - void dl_interface::display_certificate_non_const(std::ostream& out) { - if(_d->status == StatusModel){ - ast_manager &m = m_ctx.get_manager(); - model_ref md = get_model(); - out << "(fixedpoint \n"; - model_smt2_pp(out, m, *md.get(), 0); - out << ")\n"; - } - else if(_d->status == StatusRefutation){ - out << "(derivation\n"; - // negation of the query is the last clause -- prove it - hash_set locals; - local_func_decls = &locals; - print_proof(this,out,_d->cex.get_tree(),_d->cex.get_root()); - out << ")\n"; - out << "(model \n\""; - ::model mod(m_ctx.get_manager()); - model orig_model = _d->cex.get_tree()->dualModel; - for(unsigned i = 0; i < orig_model.num_consts(); i++){ - func_decl cnst = orig_model.get_const_decl(i); - if (locals.find(cnst) == locals.end()) { - expr thing = orig_model.get_const_interp(cnst); - mod.register_decl(to_func_decl(cnst.raw()), to_expr(thing.raw())); - } - } - for(unsigned i = 0; i < orig_model.num_funcs(); i++){ - func_decl cnst = orig_model.get_func_decl(i); - if (locals.find(cnst) == locals.end()) { - func_interp thing = orig_model.get_func_interp(cnst); - ::func_interp *thing_raw = thing; - mod.register_decl(to_func_decl(cnst.raw()), thing_raw->copy()); - } - } - model_v2_pp(out,mod); - out << "\")\n"; - } - } - - expr_ref dl_interface::get_answer() { - SASSERT(false); - return expr_ref(m_ctx.get_manager()); - } - - void dl_interface::cancel() { -#if 0 - if(_d && _d->ls) - _d->ls->cancel(); -#else - // HACK: duality can't cancel at all times, we just exit here - std::cout << "(error \"duality canceled\")\nunknown\n"; - abort(); -#endif - } - - void dl_interface::cleanup() { - } - - void dl_interface::updt_params() { - } - - model_ref dl_interface::get_model() { - ast_manager &m = m_ctx.get_manager(); - model_ref md(alloc(::model, m)); - std::vector &nodes = _d->rpfp->nodes; - expr_ref_vector conjs(m); - for (unsigned i = 0; i < nodes.size(); ++i) { - RPFP::Node *node = nodes[i]; - func_decl &pred = node->Name; - expr_ref prop(m); - prop = to_expr(node->Annotation.Formula); - std::vector ¶ms = node->Annotation.IndParams; - expr_ref q(m); - expr_ref_vector sig_vars(m); - for (unsigned j = 0; j < params.size(); ++j) - sig_vars.push_back(params[params.size()-j-1]); // TODO: why backwards? - expr_abstract(m, 0, sig_vars.size(), sig_vars.c_ptr(), prop, q); - if (params.empty()) { - md->register_decl(pred, q); - } - else { - ::func_interp* fi = alloc(::func_interp, m, params.size()); - fi->set_else(q); - md->register_decl(pred, fi); - } - } - return md; - } - - static proof_ref extract_proof(dl_interface *d, RPFP *tree, RPFP::Node *root) { - context &ctx = d->dd()->ctx; - ast_manager &mgr = ctx.m(); - RPFP::Node &node = *root; - RPFP::Edge &edge = *node.Outgoing; - RPFP::Edge *orig_edge = edge.map; - - // first, prove the children (that are actually used) - - proof_ref_vector prems(mgr); - ::vector substs; - int orig_clause = d->dd()->map[orig_edge]; - expr &t = d->dd()->clauses[orig_clause]; - prems.push_back(mgr.mk_asserted(ctx.uncook(t))); - - substs.push_back(expr_ref_vector(mgr)); - if (t.is_quantifier() && t.is_quantifier_forall()) { - int bound = t.get_quantifier_num_bound(); - std::vector sorts; - std::vector names; - hash_map subst; - for(int j = 0; j < bound; j++){ - sort the_sort = t.get_quantifier_bound_sort(j); - symbol name = t.get_quantifier_bound_name(j); - expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort)); - expr val = tree->Eval(&edge,skolem); - expr_ref thing(ctx.uncook(val),mgr); - substs[0].push_back(thing); - expr local_skolem = tree->Localize(&edge,skolem); - (*local_func_decls).insert(local_skolem.decl()); - } - } - - svector > pos; - for(unsigned i = 0; i < edge.Children.size(); i++){ - if(!tree->Empty(edge.Children[i])){ - pos.push_back(std::pair(i+1,0)); - proof_ref prem = extract_proof(d,tree,edge.Children[i]); - prems.push_back(prem); - substs.push_back(expr_ref_vector(mgr)); - } - } - - func_decl f = node.Name; - std::vector args; - for(unsigned i = 0; i < edge.F.IndParams.size(); i++) - args.push_back(tree->Eval(&edge,edge.F.IndParams[i])); - expr conc = f(args); - - - ::vector< ::proof *> pprems; - for(unsigned i = 0; i < prems.size(); i++) - pprems.push_back(prems[i].get()); - - proof_ref res(mgr.mk_hyper_resolve(pprems.size(),&pprems[0], ctx.uncook(conc), pos, substs),mgr); - return res; - - } - - proof_ref dl_interface::get_proof() { - if(_d->status == StatusRefutation){ - hash_set locals; - local_func_decls = &locals; - return extract_proof(this,_d->cex.get_tree(),_d->cex.get_root()); - } - else - return proof_ref(m_ctx.get_manager()); - } -} diff --git a/src/muz/duality/duality_dl_interface.h b/src/muz/duality/duality_dl_interface.h deleted file mode 100644 index 8178618ae..000000000 --- a/src/muz/duality/duality_dl_interface.h +++ /dev/null @@ -1,80 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - duality_dl_interface.h - - Abstract: - - SMT2 interface for Duality - - Author: - - Krystof Hoder (t-khoder) 2011-9-22. - Modified by Ken McMIllan (kenmcmil) 2013-4-18. - - Revision History: - - --*/ - -#ifndef DUALITY_DL_INTERFACE_H_ -#define DUALITY_DL_INTERFACE_H_ - -#include "util/lbool.h" -#include "muz/base/dl_rule.h" -#include "muz/base/dl_rule_set.h" -#include "muz/base/dl_engine_base.h" -#include "util/statistics.h" - -namespace datalog { - class context; -} - -namespace Duality { - - class duality_data; - - class dl_interface : public datalog::engine_base { - duality_data *_d; - datalog::context &m_ctx; - - public: - dl_interface(datalog::context& ctx); - ~dl_interface() override; - - lbool query(expr* query) override; - - void cancel() override; - - void cleanup() override; - - void display_certificate(std::ostream& out) const override; - - void collect_statistics(statistics& st) const override; - - void reset_statistics() override; - - expr_ref get_answer() override; - - unsigned get_num_levels(func_decl* pred) override; - - expr_ref get_cover_delta(int level, func_decl* pred) override; - - void add_cover(int level, func_decl* pred, expr* property) override; - - void updt_params() override; - - model_ref get_model() override; - - proof_ref get_proof() override; - - duality_data *dd(){return _d;} - - private: - void display_certificate_non_const(std::ostream& out); - }; -} - - -#endif diff --git a/src/muz/fp/CMakeLists.txt b/src/muz/fp/CMakeLists.txt index 0c5f5e915..41262813a 100644 --- a/src/muz/fp/CMakeLists.txt +++ b/src/muz/fp/CMakeLists.txt @@ -8,7 +8,6 @@ z3_add_component(fp bmc clp ddnf - duality_intf muz pdr rel diff --git a/src/muz/fp/dl_register_engine.cpp b/src/muz/fp/dl_register_engine.cpp index 267bfc390..a2270d774 100644 --- a/src/muz/fp/dl_register_engine.cpp +++ b/src/muz/fp/dl_register_engine.cpp @@ -23,7 +23,6 @@ Revision History: #include "muz/rel/rel_context.h" #include "muz/pdr/pdr_dl_interface.h" #include "muz/ddnf/ddnf.h" -#include "muz/duality/duality_dl_interface.h" #include "muz/spacer/spacer_dl_interface.h" namespace datalog { @@ -45,8 +44,6 @@ namespace datalog { return alloc(tab, *m_ctx); case CLP_ENGINE: return alloc(clp, *m_ctx); - case DUALITY_ENGINE: - return alloc(Duality::dl_interface, *m_ctx); case DDNF_ENGINE: return alloc(ddnf, *m_ctx); case LAST_ENGINE: diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index c6672c2b8..dc7c32cc1 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -611,7 +611,6 @@ namespace smt { case OP_XOR: UNREACHABLE(); case OP_OEQ: - case OP_INTERP: UNREACHABLE(); default: break; From 6ecae2b9863c64c824e6d65003b56f0edd5e13fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 09:21:20 -0700 Subject: [PATCH 0889/1283] fix #1645 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e5f4bc133..1ebbc9ebc 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -319,8 +319,7 @@ namespace opt { is_sat = execute_box(); } else { - m_pareto1 = (pri == symbol("pareto")); - is_sat = execute(m_objectives[0], true, false); + is_sat = execute_lex(); } } } @@ -425,7 +424,10 @@ namespace opt { objective const& o = m_objectives[i]; bool is_last = i + 1 == sz; r = execute(o, i + 1 < sz, sc && !is_last && o.m_type != O_MAXSMT); - if (r == l_true && !get_lower_as_num(i).is_finite()) { + if (r == l_true && o.m_type == O_MINIMIZE && !get_lower_as_num(i).is_finite()) { + return r; + } + if (r == l_true && o.m_type == O_MAXIMIZE && !get_upper_as_num(i).is_finite()) { return r; } if (r == l_true && i + 1 < sz) { From da32997f937dc933b638f87ba68dcb6054d3a2ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 10:15:36 -0700 Subject: [PATCH 0890/1283] fix #1638 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index e42f884d6..b3ad7dc01 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1520,6 +1520,9 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions scoped_rlimit _rlimit(m().limit(), rlimit); try { r = m_solver->check_sat(num_assumptions, assumptions); + if (r == l_undef && m().canceled()) { + m_solver->set_reason_unknown(eh); + } } catch (z3_error & ex) { throw ex; From a9ca01d8d3257f1f13ded3d6ebdc3e754a6876fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 13:12:07 -0700 Subject: [PATCH 0891/1283] deprecating interp Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 4 +- src/api/dotnet/Expr.cs | 8 -- src/api/python/z3/z3.py | 140 ----------------------------- src/muz/base/fixedpoint_params.pyg | 15 +--- 4 files changed, 4 insertions(+), 163 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index a2b526550..7439342de 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -28,8 +28,10 @@ Version 4.8.0 as lemmas (redundant) and are garbage collected if their glue level is high. - Removed features: + - interpolation API + - duality engine for constrained Horn clauses. - long deprecated API functions have been removed from z3_api.h - + Version 4.7.1 ============= diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 9310d1e7d..f09eecbdd 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -317,14 +317,6 @@ namespace Microsoft.Z3 #endregion - #region Interpolation - /// - /// Indicates whether the term is marked for interpolation. - /// - /// - public bool IsInterpolant { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_INTERP; } } - #endregion - #region Arithmetic Terms /// /// Indicates whether the term is of integer sort. diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 978141de9..784228120 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8269,146 +8269,6 @@ def parse_smt2_file(f, sorts={}, decls={}, ctx=None): except Z3Exception as e: _handle_parse_error(e, ctx) -def Interpolant(a,ctx=None): - """Create an interpolation operator. - - The argument is an interpolation pattern (see tree_interpolant). - - >>> x = Int('x') - >>> print(Interpolant(x>0)) - interp(x > 0) - """ - ctx = _get_ctx(_ctx_from_ast_arg_list([a], ctx)) - s = BoolSort(ctx) - a = s.cast(a) - return BoolRef(Z3_mk_interpolant(ctx.ref(), a.as_ast()), ctx) - -def tree_interpolant(pat,p=None,ctx=None): - """Compute interpolant for a tree of formulas. - - The input is an interpolation pattern over a set of formulas C. - The pattern pat is a formula combining the formulas in C using - logical conjunction and the "interp" operator (see Interp). This - interp operator is logically the identity operator. It marks the - sub-formulas of the pattern for which interpolants should be - computed. The interpolant is a map sigma from marked subformulas - to formulas, such that, for each marked subformula phi of pat - (where phi sigma is phi with sigma(psi) substituted for each - subformula psi of phi such that psi in dom(sigma)): - - 1) phi sigma implies sigma(phi), and - - 2) sigma(phi) is in the common uninterpreted vocabulary between - the formulas of C occurring in phi and those not occurring in - phi - - and moreover pat sigma implies false. In the simplest case - an interpolant for the pattern "(and (interp A) B)" maps A - to an interpolant for A /\ B. - - The return value is a vector of formulas representing sigma. This - vector contains sigma(phi) for each marked subformula of pat, in - pre-order traversal. This means that subformulas of phi occur before phi - in the vector. Also, subformulas that occur multiply in pat will - occur multiply in the result vector. - - If pat is satisfiable, raises an object of class ModelRef - that represents a model of pat. - - If neither a proof of unsatisfiability nor a model is obtained - (for example, because of a timeout, or because models are disabled) - then None is returned. - - If parameters p are supplied, these are used in creating the - solver that determines satisfiability. - - >>> x = Int('x') - >>> y = Int('y') - >>> print(tree_interpolant(And(Interpolant(x < 0), Interpolant(y > 2), x == y))) - [Not(x >= 0), Not(y <= 2)] - - # >>> g = And(Interpolant(x<0),x<2) - # >>> try: - # ... print tree_interpolant(g).sexpr() - # ... except ModelRef as m: - # ... print m.sexpr() - (define-fun x () Int - (- 1)) - """ - f = pat - ctx = _get_ctx(_ctx_from_ast_arg_list([f], ctx)) - ptr = (AstVectorObj * 1)() - mptr = (Model * 1)() - if p is None: - p = ParamsRef(ctx) - res = Z3_compute_interpolant(ctx.ref(),f.as_ast(),p.params,ptr,mptr) - if res == Z3_L_FALSE: - return AstVector(ptr[0],ctx) - if mptr[0]: - raise ModelRef(mptr[0], ctx) - return None - -def binary_interpolant(a,b,p=None,ctx=None): - """Compute an interpolant for a binary conjunction. - - If a & b is unsatisfiable, returns an interpolant for a & b. - This is a formula phi such that - - 1) a implies phi - 2) b implies not phi - 3) All the uninterpreted symbols of phi occur in both a and b. - - If a & b is satisfiable, raises an object of class ModelRef - that represents a model of a &b. - - If neither a proof of unsatisfiability nor a model is obtained - (for example, because of a timeout, or because models are disabled) - then None is returned. - - If parameters p are supplied, these are used in creating the - solver that determines satisfiability. - - x = Int('x') - print(binary_interpolant(x<0,x>2)) - Not(x >= 0) - """ - f = And(Interpolant(a),b) - ti = tree_interpolant(f,p,ctx) - return ti[0] if ti is not None else None - -def sequence_interpolant(v,p=None,ctx=None): - """Compute interpolant for a sequence of formulas. - - If len(v) == N, and if the conjunction of the formulas in v is - unsatisfiable, the interpolant is a sequence of formulas w - such that len(w) = N-1 and v[0] implies w[0] and for i in 0..N-1: - - 1) w[i] & v[i+1] implies w[i+1] (or false if i+1 = N) - 2) All uninterpreted symbols in w[i] occur in both v[0]..v[i] - and v[i+1]..v[n] - - Requires len(v) >= 1. - - If a & b is satisfiable, raises an object of class ModelRef - that represents a model of a & b. - - If neither a proof of unsatisfiability nor a model is obtained - (for example, because of a timeout, or because models are disabled) - then None is returned. - - If parameters p are supplied, these are used in creating the - solver that determines satisfiability. - - x = Int('x') - y = Int('y') - print(sequence_interpolant([x < 0, y == x , y > 2])) - [Not(x >= 0), Not(y >= 0)] - """ - f = v[0] - for i in range(1,len(v)): - f = And(Interpolant(f),v[i]) - return tree_interpolant(f,p,ctx) - ######################################### # diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 753a45e06..8d6c750d5 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -3,7 +3,7 @@ def_module_params('fixedpoint', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'auto-config', - 'Select: auto-config, datalog, duality, pdr, bmc, spacer'), + 'Select: auto-config, datalog, spacer, pdr, bmc'), ('datalog.default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), ('datalog.default_relation', SYMBOL, 'pentagon', @@ -56,18 +56,6 @@ def_module_params('fixedpoint', "table columns, if it would have been empty otherwise"), ('datalog.subsumption', BOOL, True, "if true, removes/filters predicates with total transitions"), - ('duality.full_expand', BOOL, False, 'Fully expand derivation trees'), - ('duality.no_conj', BOOL, False, 'No forced covering (conjectures)'), - ('duality.feasible_edges', BOOL, True, - 'Don\'t expand definitely infeasible edges'), - ('duality.use_underapprox', BOOL, False, 'Use underapproximations'), - ('duality.stratified_inlining', BOOL, False, 'Use stratified inlining'), - ('duality.recursion_bound', UINT, UINT_MAX, - 'Recursion bound for stratified inlining'), - ('duality.profile', BOOL, False, 'profile run time'), - ('duality.mbqi', BOOL, True, 'use model-based quantifier instantiation'), - ('duality.batch_expand', BOOL, False, 'use batch expansion'), - ('duality.conjecture_file', STRING, '', 'save conjectures to file'), ('pdr.bfs_model_search', BOOL, True, "use BFS strategy for expanding model search"), ('pdr.farkas', BOOL, True, @@ -161,7 +149,6 @@ def_module_params('fixedpoint', ('xform.tail_simplifier_pve', BOOL, True, "propagate_variable_equivalences"), ('xform.subsumption_checker', BOOL, True, "Enable subsumption checker (no support for model conversion)"), ('xform.coi', BOOL, True, "use cone of influence simplification"), - ('duality.enable_restarts', BOOL, False, 'DUALITY: enable restarts'), ('spacer.order_children', UINT, 0, 'SPACER: order of enqueuing children in non-linear rules : 0 (original), 1 (reverse)'), ('spacer.eager_reach_check', BOOL, True, 'SPACER: eagerly check if a query is reachable using reachability facts of predecessors'), ('spacer.use_lemma_as_cti', BOOL, False, 'SPACER: use a lemma instead of a CTI in flexible_trace'), From 9f3da32a77263ee6fab4d7f22adc212686137f68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 16:28:23 -0700 Subject: [PATCH 0892/1283] remove interpolation from test_capi Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 6761b3f8d..a6937f293 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2290,46 +2290,6 @@ void unsat_core_and_proof_example() { Z3_del_context(ctx); } -void interpolation_example() { - Z3_context ctx = mk_context(); - Z3_ast pa = mk_bool_var(ctx, "PredA"); - Z3_ast pb = mk_bool_var(ctx, "PredB"); - Z3_ast pc = mk_bool_var(ctx, "PredC"); - Z3_ast args1[2] = {pa,pb}, args2[2] = {Z3_mk_not(ctx,pb),pc}; - Z3_ast args3[2] = {Z3_mk_interpolant(ctx,Z3_mk_and(ctx,2,args1)),Z3_mk_and(ctx,2,args2)}; - Z3_ast f = Z3_mk_and(ctx,2,args3); - Z3_ast_vector interpolant = 0; - Z3_model m = 0; - Z3_lbool result = Z3_L_UNDEF; - - printf("\ninterpolation_example\n"); - LOG_MSG("interpolation_example"); - - result = Z3_compute_interpolant(ctx,f,0,&interpolant,&m); - - switch (result) { - case Z3_L_FALSE: - printf("unsat\n"); - printf("interpolant: %s\n", Z3_ast_to_string(ctx, Z3_ast_vector_get(ctx, interpolant, 0))); - printf("\n"); - break; - case Z3_L_UNDEF: - printf("unknown\n"); - printf("potential model:\n"); - if (m) Z3_model_inc_ref(ctx, m); - display_model(ctx, stdout, m); - break; - case Z3_L_TRUE: - printf("sat\n"); - if (m) Z3_model_inc_ref(ctx, m); - display_model(ctx, stdout, m); - break; - } - - /* delete logical context */ - if (m) Z3_model_dec_ref(ctx, m); - Z3_del_context(ctx); -} #define MAX_RETRACTABLE_ASSERTIONS 1024 @@ -3014,7 +2974,6 @@ int main() { binary_tree_example(); enum_example(); unsat_core_and_proof_example(); - interpolation_example(); incremental_example1(); reference_counter_example(); smt2parser_example(); From 6b700f1f5f0026b27940ac518519ad03d2ec354d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 20:32:04 -0700 Subject: [PATCH 0893/1283] remove interpolation from test_capi Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index eef5d7904..665ffb438 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -147,20 +147,12 @@ namespace z3 { Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } - void init_interp(config & c) { - m_ctx = Z3_mk_interpolation_context(c); - m_enable_exceptions = true; - Z3_set_error_handler(m_ctx, 0); - Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); - } context(context const & s); context & operator=(context const & s); public: - struct interpolation {}; context() { config c; init(c); } context(config & c) { init(c); } - context(config & c, interpolation) { init_interp(c); } ~context() { Z3_del_context(m_ctx); } operator Z3_context() const { return m_ctx; } @@ -335,11 +327,6 @@ namespace z3 { expr_vector parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls); expr_vector parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls); - /** - \brief Interpolation support - */ - check_result compute_interpolant(expr const& pat, params const& p, expr_vector& interp, model& m); - expr_vector get_interpolant(expr const& proof, expr const& pat, params const& p); }; @@ -2969,10 +2956,6 @@ namespace z3 { - inline expr interpolant(expr const& a) { - return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a)); - } - inline expr_vector context::parse_string(char const* s) { Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); check_error(); @@ -3019,27 +3002,6 @@ namespace z3 { } - inline check_result context::compute_interpolant(expr const& pat, params const& p, expr_vector& i, model& m) { - Z3_ast_vector interp = 0; - Z3_model mdl = 0; - Z3_lbool r = Z3_compute_interpolant(*this, pat, p, &interp, &mdl); - switch (r) { - case Z3_L_FALSE: - i = expr_vector(*this, interp); - break; - case Z3_L_TRUE: - m = model(*this, mdl); - break; - case Z3_L_UNDEF: - break; - } - return to_check_result(r); - } - - inline expr_vector context::get_interpolant(expr const& proof, expr const& pat, params const& p) { - return expr_vector(*this, Z3_get_interpolant(*this, proof, pat, p)); - } - inline expr expr::substitute(expr_vector const& src, expr_vector const& dst) { assert(src.size() == dst.size()); array _src(src.size()); From 3e0506a71bb4ba9f770105374af7f147c34a3ea7 Mon Sep 17 00:00:00 2001 From: Philipp Wendler Date: Fri, 25 May 2018 14:54:44 +0200 Subject: [PATCH 0894/1283] Set the SONAME field of libz3.so to libz3.so. This fixes a problem when loading libz3java from Java, where the dependency on libz3 is not detected as fulfilled if the latter does not have SONAME set. --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 1391eee87..87d766e55 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2460,7 +2460,7 @@ def mk_config(): check_ar() CXX = find_cxx_compiler() CC = find_c_compiler() - SLIBEXTRAFLAGS = '' + SLIBEXTRAFLAGS = '-Wl,-soname,libz3.so' EXE_EXT = '' LIB_EXT = '.a' if GPROF: From 8eeaa27cf34eeba7e8c832e83362e11f439ff282 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 07:33:43 -0700 Subject: [PATCH 0895/1283] remove interp from documentation Signed-off-by: Nikolaj Bjorner --- doc/mk_api_doc.py | 1 - src/opt/opt_context.cpp | 9 ++++++--- src/opt/opt_pareto.cpp | 7 ++++--- src/smt/theory_pb.cpp | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index a1a9e64bd..bfe865e06 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -272,7 +272,6 @@ try: cleanup_API(doc_path('../src/api/z3_rcf.h'), temp_path('z3_rcf.h')) cleanup_API(doc_path('../src/api/z3_fixedpoint.h'), temp_path('z3_fixedpoint.h')) cleanup_API(doc_path('../src/api/z3_optimization.h'), temp_path('z3_optimization.h')) - cleanup_API(doc_path('../src/api/z3_interp.h'), temp_path('z3_interp.h')) cleanup_API(doc_path('../src/api/z3_fpa.h'), temp_path('z3_fpa.h')) print("Removed annotations from z3_api.h.") diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e5f4bc133..004a83a14 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -497,7 +497,7 @@ namespace opt { case O_MINIMIZE: is_ge = !is_ge; case O_MAXIMIZE: - if (mdl->eval(obj.m_term, val) && is_numeral(val, k)) { + if (mdl->eval(obj.m_term, val, true) && is_numeral(val, k)) { if (is_ge) { result = mk_ge(obj.m_term, val); } @@ -517,9 +517,12 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { terms.push_back(obj.m_terms[i]); coeffs.push_back(obj.m_weights[i]); - if (mdl->eval(obj.m_terms[i], val) && m.is_true(val)) { + if (mdl->eval(obj.m_terms[i], val, true) && m.is_true(val)) { k += obj.m_weights[i]; } + else { + TRACE("opt", tout << val << "\n";); + } } if (is_ge) { result = pb.mk_ge(sz, coeffs.c_ptr(), terms.c_ptr(), k); @@ -1044,7 +1047,7 @@ namespace opt { model_ref mdl = md->copy(); fix_model(mdl); - if (!mdl->eval(term, val)) { + if (!mdl->eval(term, val, true)) { TRACE("opt", tout << "Term does not evaluate " << term << "\n";); return false; } diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index c316e697e..56eed72ac 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -20,6 +20,7 @@ Notes: #include "opt/opt_pareto.h" #include "ast/ast_pp.h" +#include "ast/ast_util.h" #include "model/model_smt2_pp.h" namespace opt { @@ -66,8 +67,8 @@ namespace opt { fmls.push_back(cb.mk_ge(i, m_model)); gt.push_back(cb.mk_gt(i, m_model)); } - fmls.push_back(m.mk_or(gt.size(), gt.c_ptr())); - fml = m.mk_and(fmls.size(), fmls.c_ptr()); + fmls.push_back(mk_or(gt)); + fml = mk_and(fmls); IF_VERBOSE(10, verbose_stream() << "dominates: " << fml << "\n";); TRACE("opt", tout << fml << "\n"; model_smt2_pp(tout, m, *m_model, 0);); m_solver->assert_expr(fml); @@ -80,7 +81,7 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { le.push_back(cb.mk_le(i, m_model)); } - fml = m.mk_not(m.mk_and(le.size(), le.c_ptr())); + fml = m.mk_not(mk_and(le)); IF_VERBOSE(10, verbose_stream() << "not dominated by: " << fml << "\n";); TRACE("opt", tout << fml << "\n";); m_solver->assert_expr(fml); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 9fc33a6a9..d45590bff 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -2007,7 +2007,7 @@ namespace smt { if (m_bound > static_cast(m_active_vars.size())) { return; } - if (m_bound == m_active_vars.size()) { + if (m_bound == static_cast(m_active_vars.size())) { return; } From 7145a9ac41f80551f911a2bf8f78a5500b1636d7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 07:38:30 -0700 Subject: [PATCH 0896/1283] fix #1647 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 1ebbc9ebc..1ba107b19 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -499,7 +499,7 @@ namespace opt { case O_MINIMIZE: is_ge = !is_ge; case O_MAXIMIZE: - if (mdl->eval(obj.m_term, val) && is_numeral(val, k)) { + if (mdl->eval(obj.m_term, val, true) && is_numeral(val, k)) { if (is_ge) { result = mk_ge(obj.m_term, val); } @@ -519,7 +519,7 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { terms.push_back(obj.m_terms[i]); coeffs.push_back(obj.m_weights[i]); - if (mdl->eval(obj.m_terms[i], val) && m.is_true(val)) { + if (mdl->eval(obj.m_terms[i], val, true) && m.is_true(val)) { k += obj.m_weights[i]; } } @@ -1046,7 +1046,7 @@ namespace opt { model_ref mdl = md->copy(); fix_model(mdl); - if (!mdl->eval(term, val)) { + if (!mdl->eval(term, val, true)) { TRACE("opt", tout << "Term does not evaluate " << term << "\n";); return false; } From 2b73b7c7f371309f415d1e95f620f5c8a46c135c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 08:43:35 -0700 Subject: [PATCH 0897/1283] Revert "Fix missing SONAME in libz3.so, which breaks loading from Java" --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 87d766e55..1391eee87 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2460,7 +2460,7 @@ def mk_config(): check_ar() CXX = find_cxx_compiler() CC = find_c_compiler() - SLIBEXTRAFLAGS = '-Wl,-soname,libz3.so' + SLIBEXTRAFLAGS = '' EXE_EXT = '' LIB_EXT = '.a' if GPROF: From 753b9dd734305bd6211bc8f90e8b558d1775bae2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 08:56:13 -0700 Subject: [PATCH 0898/1283] fix #1650 fix #1648 Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 3 ++- src/ast/rewriter/pb2bv_rewriter.cpp | 16 +++++++++------- src/ast/rewriter/pb2bv_rewriter.h | 2 +- src/tactic/arith/card2bv_tactic.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- src/test/pb2bv.cpp | 13 ++++++++++--- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 87d766e55..d51735255 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2460,7 +2460,7 @@ def mk_config(): check_ar() CXX = find_cxx_compiler() CC = find_c_compiler() - SLIBEXTRAFLAGS = '-Wl,-soname,libz3.so' + SLIBEXTRAFLAGS = '' EXE_EXT = '' LIB_EXT = '.a' if GPROF: @@ -2511,6 +2511,7 @@ def mk_config(): LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS + SLIBEXTRAFLAGS = '%s -Wl,-soname,libz3.so' % SLIBEXTRAFLAGS elif sysname == 'FreeBSD': CXXFLAGS = '%s -D_FREEBSD_' % CXXFLAGS OS_DEFINES = '-D_FREEBSD_' diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 7da8b2d3f..e4a34fc93 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -726,9 +726,9 @@ struct pb2bv_rewriter::imp { } } - bool mk_app(expr* e, expr_ref& r) { + bool mk_app(bool full, expr* e, expr_ref& r) { app* a; - return (is_app(e) && (a = to_app(e), mk_app(false, a->get_decl(), a->get_num_args(), a->get_args(), r))); + return (is_app(e) && (a = to_app(e), mk_app(full, a->get_decl(), a->get_num_args(), a->get_args(), r))); } bool is_pb(expr* x, expr* y) { @@ -844,6 +844,8 @@ struct pb2bv_rewriter::imp { else { result = mk_bv(f, sz, args); } + TRACE("pb", tout << "full: " << full << " " << expr_ref(m.mk_app(f, sz, args), m) << " " << result << "\n"; + ); return true; } @@ -915,9 +917,9 @@ struct pb2bv_rewriter::imp { 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 rewrite(expr* e, expr_ref& r, proof_ref& p) { + void rewrite(bool full, expr* e, expr_ref& r, proof_ref& p) { expr_ref ee(e, m()); - if (m_cfg.m_r.mk_app(e, r)) { + if (m_cfg.m_r.mk_app(full, e, r)) { ee = r; // mp proof? } @@ -980,9 +982,9 @@ struct pb2bv_rewriter::imp { unsigned get_num_steps() const { return m_rw.get_num_steps(); } void cleanup() { m_rw.cleanup(); } - void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { + void operator()(bool full, expr * e, expr_ref & result, proof_ref & result_proof) { // m_rw(e, result, result_proof); - m_rw.rewrite(e, result, result_proof); + m_rw.rewrite(full, e, result, result_proof); } void push() { m_fresh_lim.push_back(m_fresh.size()); @@ -1023,7 +1025,7 @@ ast_manager & pb2bv_rewriter::m() const { return m_imp->m; } unsigned pb2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } void pb2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } func_decl_ref_vector const& pb2bv_rewriter::fresh_constants() const { return m_imp->m_fresh; } -void pb2bv_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } +void pb2bv_rewriter::operator()(bool full, expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(full, e, result, result_proof); } void pb2bv_rewriter::push() { m_imp->push(); } void pb2bv_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } void pb2bv_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } diff --git a/src/ast/rewriter/pb2bv_rewriter.h b/src/ast/rewriter/pb2bv_rewriter.h index 9e3785649..3460f08ab 100644 --- a/src/ast/rewriter/pb2bv_rewriter.h +++ b/src/ast/rewriter/pb2bv_rewriter.h @@ -36,7 +36,7 @@ public: unsigned get_num_steps() const; void cleanup(); func_decl_ref_vector const& fresh_constants() const; - void operator()(expr * e, expr_ref & result, proof_ref & result_proof); + void operator()(bool full, expr * e, expr_ref & result, proof_ref & result_proof); void push(); void pop(unsigned num_scopes); void flush_side_constraints(expr_ref_vector& side_constraints); diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 63d034374..97649cc2f 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -71,7 +71,7 @@ public: for (unsigned idx = 0; !g->inconsistent() && idx < g->size(); idx++) { rw1(g->form(idx), new_f1, new_pr1); TRACE("card2bv", tout << "Rewriting " << mk_ismt2_pp(new_f1.get(), m) << std::endl;); - rw2(new_f1, new_f2, new_pr2); + rw2(false, new_f1, new_f2, new_pr2); if (m.proofs_enabled()) { new_pr1 = m.mk_modus_ponens(g->pr(idx), new_pr1); new_pr1 = m.mk_modus_ponens(new_pr1, new_pr2); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 0f2311233..f8794ca41 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -147,7 +147,7 @@ private: expr_ref_vector fmls(m); for (expr* a : m_assertions) { m_th_rewriter(a, fml1, proof); - m_rewriter(fml1, fml, proof); + m_rewriter(false, fml1, fml, proof); m_solver->assert_expr(fml); } m_rewriter.flush_side_constraints(fmls); diff --git a/src/test/pb2bv.cpp b/src/test/pb2bv.cpp index 35c444bae..d58bf61ee 100644 --- a/src/test/pb2bv.cpp +++ b/src/test/pb2bv.cpp @@ -37,7 +37,7 @@ static void test1() { expr_ref fml(m), result(m); proof_ref proof(m); fml = pb.mk_at_least_k(vars.size(), vars.c_ptr(), k); - rw(fml, result, proof); + rw(true, fml, result, proof); std::cout << fml << " |-> " << result << "\n"; } expr_ref_vector lemmas(m); @@ -60,9 +60,10 @@ static void test_semantics(ast_manager& m, expr_ref_vector const& vars, vector(1 << N); ++values) { smt_params fp; smt::kernel solver(m, fp); @@ -86,6 +87,12 @@ static void test_semantics(ast_manager& m, expr_ref_vector const& vars, vector Date: Fri, 25 May 2018 10:27:12 -0700 Subject: [PATCH 0899/1283] clean up python build files Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index b03ced763..f2720c893 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -40,8 +40,7 @@ def init_project_def(): add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('aig_tactic', ['tactic'], 'tactic/aig') add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') - add_lib('interp', ['solver']) - add_lib('cmd_context', ['solver', 'rewriter', 'interp']) + add_lib('cmd_context', ['solver', 'rewriter']) add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds') add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') @@ -56,7 +55,6 @@ 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('duality', ['smt', 'interp', 'qe']) 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') @@ -67,16 +65,15 @@ def init_project_def(): add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf') - add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality') - add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf', 'spacer'], 'muz/fp') + add_lib('fp', ['muz', 'pdr', '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('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_interp.h', 'z3_fpa.h', 'z3_spacer.h'] - add_lib('api', ['portfolio', 'realclosure', 'interp', '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'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3') add_exe('test', ['api', 'fuzzing', 'simplex'], exe_name='test-z3', install=False) From a06926915dbc4925f07bbc7eee95e3115b46774b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 10:47:54 -0700 Subject: [PATCH 0900/1283] remove stale file Signed-off-by: Nikolaj Bjorner --- src/api/api_interp.cpp | 725 ----------------------------------------- 1 file changed, 725 deletions(-) delete mode 100644 src/api/api_interp.cpp diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp deleted file mode 100644 index 2b461e991..000000000 --- a/src/api/api_interp.cpp +++ /dev/null @@ -1,725 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - api_interp.cpp - - Abstract: - API for interpolation - - Author: - - Ken McMillan - - Revision History: - - --*/ -#include -#include -#include "api/z3.h" -#include "api/api_log_macros.h" -#include "api/api_context.h" -#include "api/api_tactic.h" -#include "api/api_solver.h" -#include "api/api_model.h" -#include "api/api_stats.h" -#include "api/api_ast_vector.h" -#include "solver/tactic2solver.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" -#include "tactic/portfolio/smt_strategic_solver.h" -#include "smt/smt_solver.h" -#include "smt/smt_implied_equalities.h" -#include "interp/iz3interp.h" -#include "interp/iz3profiling.h" -#include "interp/iz3hash.h" -#include "interp/iz3pp.h" -#include "interp/iz3checker.h" -#include "ast/scoped_proof.h" - -using namespace stl_ext; - -// WARNING: don't make a hash_map with this if the range type -// has a destructor: you'll get an address dependency!!! -namespace stl_ext { - template <> - class hash < Z3_ast > { - public: - size_t operator()(const Z3_ast p) const { - return (size_t)p; - } - }; -} - -typedef interpolation_options_struct *Z3_interpolation_options; - -extern "C" { - - Z3_context Z3_mk_interpolation_context(Z3_config cfg){ - if (!cfg) cfg = Z3_mk_config(); - Z3_set_param_value(cfg, "PROOF", "true"); - Z3_set_param_value(cfg, "MODEL", "true"); - // Z3_set_param_value(cfg, "PRE_SIMPLIFIER","false"); - // Z3_set_param_value(cfg, "SIMPLIFY_CLAUSES","false"); - - Z3_context ctx = Z3_mk_context(cfg); - return ctx; - } - - void Z3_interpolate_proof(Z3_context ctx, - Z3_ast proof, - int num, - Z3_ast *cnsts, - unsigned *parents, - Z3_params options, - Z3_ast *interps, - int num_theory, - Z3_ast *theory) - { - - if (num > 1){ // if we have interpolants to compute - - ptr_vector pre_cnsts_vec(num); // get constraints in a vector - for (int i = 0; i < num; i++){ - ast *a = to_ast(cnsts[i]); - pre_cnsts_vec[i] = a; - } - - ::vector pre_parents_vec; // get parents in a vector - if (parents){ - pre_parents_vec.resize(num); - for (int i = 0; i < num; i++) - pre_parents_vec[i] = parents[i]; - } - - ptr_vector theory_vec; // get background theory in a vector - if (theory){ - theory_vec.resize(num_theory); - for (int i = 0; i < num_theory; i++) - theory_vec[i] = to_ast(theory[i]); - } - - ptr_vector interpolants(num - 1); // make space for result - - ast_manager &_m = mk_c(ctx)->m(); - iz3interpolate(_m, - to_ast(proof), - pre_cnsts_vec, - pre_parents_vec, - interpolants, - theory_vec, - nullptr); // ignore params for now FIXME - - // copy result back - for (unsigned i = 0; i < interpolants.size(); i++){ - mk_c(ctx)->save_ast_trail(interpolants[i]); - interps[i] = of_ast(interpolants[i]); - _m.dec_ref(interpolants[i]); - } - } - } - - static std::ostringstream itp_err; - - int Z3_check_interpolant(Z3_context ctx, - unsigned num, - Z3_ast *cnsts, - unsigned *parents, - Z3_ast *itp, - Z3_string *error, - unsigned num_theory, - Z3_ast *theory){ - - ast_manager &_m = mk_c(ctx)->m(); - itp_err.clear(); - - // need a solver -- make one here, but how? - params_ref p = params_ref::get_empty(); //FIXME - scoped_ptr sf(mk_smt_solver_factory()); - scoped_ptr sp((*(sf))(_m, p, false, true, false, symbol("AUFLIA"))); - - ptr_vector cnsts_vec(num); // get constraints in a vector - for (unsigned i = 0; i < num; i++){ - ast *a = to_ast(cnsts[i]); - cnsts_vec[i] = a; - } - - ptr_vector itp_vec(num); // get interpolants in a vector - for (unsigned i = 0; i < num - 1; i++){ - ast *a = to_ast(itp[i]); - itp_vec[i] = a; - } - - ::vector parents_vec; // get parents in a vector - if (parents){ - parents_vec.resize(num); - for (unsigned i = 0; i < num; i++) - parents_vec[i] = parents[i]; - } - - ptr_vector theory_vec; // get background theory in a vector - if (theory){ - theory_vec.resize(num_theory); - for (unsigned i = 0; i < num_theory; i++) - theory_vec[i] = to_ast(theory[i]); - } - - bool res = iz3check(_m, - sp.get(), - itp_err, - cnsts_vec, - parents_vec, - itp_vec, - theory_vec); - - *error = res ? nullptr : itp_err.str().c_str(); - return res; - } - - - static std::string Z3_profile_string; - - Z3_string Z3_interpolation_profile(Z3_context ctx){ - std::ostringstream f; - profiling::print(f); - Z3_profile_string = f.str(); - return Z3_profile_string.c_str(); - } - - - Z3_interpolation_options - Z3_mk_interpolation_options(){ - return (Z3_interpolation_options) new interpolation_options_struct; - } - - void - Z3_del_interpolation_options(Z3_interpolation_options opts){ - delete opts; - } - - void - Z3_set_interpolation_option(Z3_interpolation_options opts, - Z3_string name, - Z3_string value){ - opts->map[name] = value; - } - - Z3_ast_vector Z3_API Z3_get_interpolant(Z3_context c, Z3_ast pf, Z3_ast pat, Z3_params p){ - Z3_TRY; - LOG_Z3_get_interpolant(c, pf, pat, p); - RESET_ERROR_CODE(); - - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); - mk_c(c)->save_object(v); - - ast *_pf = to_ast(pf); - ast *_pat = to_ast(pat); - - ptr_vector interp; - ptr_vector cnsts; // to throw away - - ast_manager &_m = mk_c(c)->m(); - - iz3interpolate(_m, - _pf, - cnsts, - _pat, - interp, - (interpolation_options_struct *)nullptr // ignore params for now - ); - - // copy result back - for (unsigned i = 0; i < interp.size(); i++){ - v->m_ast_vector.push_back(interp[i]); - _m.dec_ref(interp[i]); - } - RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(nullptr); - } - - Z3_lbool Z3_API Z3_compute_interpolant(Z3_context c, Z3_ast pat, Z3_params p, Z3_ast_vector *out_interp, Z3_model *model){ - Z3_TRY; - LOG_Z3_compute_interpolant(c, pat, p, out_interp, model); - RESET_ERROR_CODE(); - - - // params_ref &_p = to_params(p)->m_params; - params_ref _p; - _p.set_bool("proof", true); // this is currently useless - - scoped_proof_mode spm(mk_c(c)->m(), PGM_ENABLED); - scoped_ptr sf = mk_smt_solver_factory(); - scoped_ptr m_solver((*sf)(mk_c(c)->m(), _p, true, true, true, ::symbol::null)); - m_solver.get()->updt_params(_p); // why do we have to do this? - - - // some boilerplate stolen from Z3_solver_check - unsigned timeout = p?to_params(p)->m_params.get_uint("timeout", mk_c(c)->get_timeout()):UINT_MAX; - unsigned rlimit = p?to_params(p)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()):0; - bool use_ctrl_c = p?to_params(p)->m_params.get_bool("ctrl_c", false): false; - cancel_eh eh(mk_c(c)->m().limit()); - api::context::set_interruptable si(*(mk_c(c)), eh); - - ast *_pat = to_ast(pat); - - ptr_vector interp; - ptr_vector cnsts; // to throw away - - ast_manager &_m = mk_c(c)->m(); - - model_ref m; - lbool _status; - - { - scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); - scoped_timer timer(timeout, &eh); - scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); - try { - _status = iz3interpolate(_m, - *(m_solver.get()), - _pat, - cnsts, - interp, - m, - nullptr // ignore params for now - ); - } - catch (z3_exception & ex) { - mk_c(c)->handle_exception(ex); - RETURN_Z3_compute_interpolant Z3_L_UNDEF; - } - } - - for (unsigned i = 0; i < cnsts.size(); i++) - _m.dec_ref(cnsts[i]); - - Z3_lbool status = of_lbool(_status); - - Z3_ast_vector_ref *v = nullptr; - *model = nullptr; - - if (_status == l_false){ - // copy result back - v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); - mk_c(c)->save_object(v); - for (unsigned i = 0; i < interp.size(); i++){ - v->m_ast_vector.push_back(interp[i]); - _m.dec_ref(interp[i]); - } - } - else { - model_ref mr; - m_solver.get()->get_model(mr); - if(mr.get()){ - Z3_model_ref *tmp_val = alloc(Z3_model_ref, *mk_c(c)); - tmp_val->m_model = mr.get(); - mk_c(c)->save_object(tmp_val); - *model = of_model(tmp_val); - } - } - - *out_interp = of_ast_vector(v); - - RETURN_Z3_compute_interpolant status; - Z3_CATCH_RETURN(Z3_L_UNDEF); - } - - -}; - - -static void tokenize(const std::string &str, std::vector &tokens){ - for (unsigned i = 0; i < str.size();){ - if (str[i] == ' '){ i++; continue; } - unsigned beg = i; - while (i < str.size() && str[i] != ' ')i++; - if (i > beg) - tokens.push_back(str.substr(beg, i - beg)); - } -} - -static void get_file_params(const char *filename, hash_map ¶ms){ - std::ifstream f(filename); - if (f){ - std::string first_line; - std::getline(f, first_line); - // std::cout << "first line: '" << first_line << "'" << std::endl; - if (first_line.size() >= 2 && first_line[0] == ';' && first_line[1] == '!'){ - std::vector tokens; - tokenize(first_line.substr(2, first_line.size() - 2), tokens); - for (unsigned i = 0; i < tokens.size(); i++){ - std::string &tok = tokens[i]; - size_t eqpos = tok.find('='); - if (eqpos != std::string::npos){ - std::string left = tok.substr(0, eqpos); - std::string right = tok.substr(eqpos + 1, tok.size() - eqpos - 1); - params[left] = right; - } - } - } - f.close(); - } -} - -extern "C" { - -#if 0 - static void iZ3_write_seq(Z3_context ctx, int num, Z3_ast *cnsts, const char *filename, int num_theory, Z3_ast *theory){ - int num_fmlas = num+num_theory; - std::vector fmlas(num_fmlas); - if(num_theory) - std::copy(theory,theory+num_theory,fmlas.begin()); - for(int i = 0; i < num_theory; i++) - fmlas[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),fmlas[i]); - std::copy(cnsts,cnsts+num,fmlas.begin()+num_theory); - Z3_string smt = Z3_benchmark_to_smtlib_string(ctx,"none","AUFLIA","unknown","",num_fmlas-1,&fmlas[0],fmlas[num_fmlas-1]); - std::ofstream f(filename); - if(num_theory) - f << ";! THEORY=" << num_theory << "\n"; - f << smt; - f.close(); - } - - void Z3_write_interpolation_problem(Z3_context ctx, int num, Z3_ast *cnsts, unsigned *parents, const char *filename, int num_theory, Z3_ast *theory){ - if(!parents){ - iZ3_write_seq(ctx,num,cnsts,filename,num_theory,theory); - return; - } - std::vector tcnsts(num); - hash_map syms; - for(int j = 0; j < num - 1; j++){ - std::ostringstream oss; - oss << "$P" << j; - std::string name = oss.str(); - Z3_symbol s = Z3_mk_string_symbol(ctx, name.c_str()); - Z3_ast symbol = Z3_mk_const(ctx, s, Z3_mk_bool_sort(ctx)); - syms[j] = symbol; - tcnsts[j] = Z3_mk_implies(ctx,cnsts[j],symbol); - } - tcnsts[num-1] = Z3_mk_implies(ctx,cnsts[num-1],Z3_mk_false(ctx)); - for(int j = num-2; j >= 0; j--){ - int parent = parents[j]; - // assert(parent >= 0 && parent < num); - tcnsts[parent] = Z3_mk_implies(ctx,syms[j],tcnsts[parent]); - } - iZ3_write_seq(ctx,num,&tcnsts[0],filename,num_theory,theory); - } -#else - - - static Z3_ast and_vec(Z3_context ctx, svector &c){ - return (c.size() > 1) ? Z3_mk_and(ctx, c.size(), &c[0]) : c[0]; - } - - static Z3_ast parents_vector_to_tree(Z3_context ctx, int num, Z3_ast *cnsts, unsigned *parents){ - Z3_ast res; - if (!parents){ - res = Z3_mk_interpolant(ctx, cnsts[0]); - for (int i = 1; i < num - 1; i++){ - Z3_ast bar[2] = { res, cnsts[i] }; - res = Z3_mk_interpolant(ctx, Z3_mk_and(ctx, 2, bar)); - } - if (num > 1){ - Z3_ast bar[2] = { res, cnsts[num - 1] }; - res = Z3_mk_and(ctx, 2, bar); - } - } - else { - std::vector > chs(num); - for (int i = 0; i < num - 1; i++){ - svector &c = chs[i]; - c.push_back(cnsts[i]); - Z3_ast foo = Z3_mk_interpolant(ctx, and_vec(ctx, c)); - chs[parents[i]].push_back(foo); - } - { - svector &c = chs[num - 1]; - c.push_back(cnsts[num - 1]); - res = and_vec(ctx, c); - } - } - Z3_inc_ref(ctx, res); - return res; - } - - void Z3_write_interpolation_problem(Z3_context ctx, unsigned num, Z3_ast *cnsts, unsigned *parents, const char *filename, unsigned num_theory, Z3_ast *theory){ - std::ofstream f(filename); - if (num > 0){ -#if 0 - // Suggested shorthand: - ptr_vector cnsts_vec; - cnsts_vec.append(num, to_exprs(cnsts)); - cnsts_vec.append(num_theory, to_exprs(theory)); -#endif - ptr_vector cnsts_vec(num); // get constraints in a vector - for (unsigned i = 0; i < num; i++){ - expr *a = to_expr(cnsts[i]); - cnsts_vec[i] = a; - } - for (unsigned i = 0; i < num_theory; i++){ - expr *a = to_expr(theory[i]); - cnsts_vec.push_back(a); - } - Z3_ast tree = parents_vector_to_tree(ctx, num, cnsts, parents); - iz3pp(mk_c(ctx)->m(), cnsts_vec, to_expr(tree), f); - Z3_dec_ref(ctx, tree); - } - f.close(); - -#if 0 - - - if(!parents){ - iZ3_write_seq(ctx,num,cnsts,filename,num_theory,theory); - return; - } - std::vector tcnsts(num); - hash_map syms; - for(int j = 0; j < num - 1; j++){ - std::ostringstream oss; - oss << "$P" << j; - std::string name = oss.str(); - Z3_symbol s = Z3_mk_string_symbol(ctx, name.c_str()); - Z3_ast symbol = Z3_mk_const(ctx, s, Z3_mk_bool_sort(ctx)); - syms[j] = symbol; - tcnsts[j] = Z3_mk_implies(ctx,cnsts[j],symbol); - } - tcnsts[num-1] = Z3_mk_implies(ctx,cnsts[num-1],Z3_mk_false(ctx)); - for(int j = num-2; j >= 0; j--){ - int parent = parents[j]; - // assert(parent >= 0 && parent < num); - tcnsts[parent] = Z3_mk_implies(ctx,syms[j],tcnsts[parent]); - } - iZ3_write_seq(ctx,num,&tcnsts[0],filename,num_theory,theory); -#endif - - } - - -#endif - - static std::vector read_cnsts; - static std::vector read_parents; - static std::ostringstream read_error; - static std::string read_msg; - static std::vector read_theory; - - static Z3_ast_vector iZ3_parse(Z3_context ctx, const char *filename, const char ** error){ - return nullptr; -#if 0 - read_error.clear(); - try { - Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, nullptr, nullptr, 0, nullptr, nullptr); - Z3_app app = Z3_to_app(ctx, assrts); - int nconjs = Z3_get_app_num_args(ctx, app); - assertions.resize(nconjs); - for (int k = 0; k < nconjs; k++) - assertions[k] = Z3_get_app_arg(ctx, app, k); - } - catch (...) { - read_error << "SMTLIB parse error: " << Z3_get_parser_error(ctx); - read_msg = read_error.str(); - *error = read_msg.c_str(); - return nullptr; - } - Z3_set_error_handler(ctx, nullptr); - return nullptr; -#endif - } - - - int Z3_read_interpolation_problem(Z3_context ctx, Z3_ast_vector cnsts, unsigned* _num, unsigned* parents[], const char *filename, Z3_string_ptr error, Z3_ast_vector theory){ - - hash_map file_params; - get_file_params(filename, file_params); - - unsigned num_theory = 0; - if (file_params.find("THEORY") != file_params.end()) { - num_theory = atoi(file_params["THEORY"].c_str()); - } - - Z3_ast_vector assertions = iZ3_parse(ctx, filename, error); - if (assertions == 0) - return false; - - if (num_theory > Z3_ast_vector_size(ctx, assertions)) - num_theory = Z3_ast_vector_size(ctx, assertions); - unsigned num = Z3_ast_vector_size(ctx, assertions) - num_theory; - - read_parents.resize(num); - - for (unsigned j = 0; theory && j < num_theory; j++) - Z3_ast_vector_push(ctx, theory, Z3_ast_vector_get(ctx, assertions, j)); - - for (unsigned j = 0; j < num; j++) - Z3_ast_vector_push(ctx, cnsts, Z3_ast_vector_get(ctx, assertions, j + num_theory)); - - if (!parents){ - Z3_ast_vector_dec_ref(ctx, assertions); - return true; - } - - for (unsigned j = 0; j < num; j++) - read_parents[j] = SHRT_MAX; - - hash_map pred_map; - - for (unsigned j = 0; j < num; j++){ - Z3_ast lhs = nullptr, rhs = Z3_ast_vector_get(ctx, cnsts, j); - - if (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, rhs))) == Z3_OP_IMPLIES){ - Z3_app app1 = Z3_to_app(ctx, rhs); - Z3_ast lhs1 = Z3_get_app_arg(ctx, app1, 0); - Z3_ast rhs1 = Z3_get_app_arg(ctx, app1, 1); - if (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, lhs1))) == Z3_OP_AND){ - Z3_app app2 = Z3_to_app(ctx, lhs1); - int nconjs = Z3_get_app_num_args(ctx, app2); - for (int k = nconjs - 1; k >= 0; --k) - rhs1 = Z3_mk_implies(ctx, Z3_get_app_arg(ctx, app2, k), rhs1); - rhs = rhs1; - } - } - - while (1){ - Z3_app app = Z3_to_app(ctx, rhs); - Z3_func_decl func = Z3_get_app_decl(ctx, app); - Z3_decl_kind dk = Z3_get_decl_kind(ctx, func); - if (dk == Z3_OP_IMPLIES){ - if (lhs){ - Z3_ast child = lhs; - if (pred_map.find(child) == pred_map.end()){ - read_error << "formula " << j + 1 << ": unknown: " << Z3_ast_to_string(ctx, child); - goto fail; - } - int child_num = pred_map[child]; - if (read_parents[child_num] != SHRT_MAX){ - read_error << "formula " << j + 1 << ": multiple reference: " << Z3_ast_to_string(ctx, child); - goto fail; - } - read_parents[child_num] = j; - } - lhs = Z3_get_app_arg(ctx, app, 0); - rhs = Z3_get_app_arg(ctx, app, 1); - } - else { - if (!lhs){ - read_error << "formula " << j + 1 << ": should be (implies {children} fmla parent)"; - goto fail; - } - Z3_ast_vector_set(ctx, cnsts, j, lhs); - Z3_ast name = rhs; - if (pred_map.find(name) != pred_map.end()){ - read_error << "formula " << j + 1 << ": duplicate symbol"; - goto fail; - } - pred_map[name] = j; - break; - } - } - } - - for (unsigned j = 0; j < num - 1; j++) - if (read_parents[j] == SHRT_MAX){ - read_error << "formula " << j + 1 << ": unreferenced"; - goto fail; - } - - *_num = num; - *parents = &read_parents[0]; - Z3_ast_vector_dec_ref(ctx, assertions); - return true; - - fail: - Z3_ast_vector_dec_ref(ctx, assertions); - read_msg = read_error.str(); - *error = read_msg.c_str(); - return false; - - } -} - - -#if 0 -/** Constant reprepresenting a root of a formula tree for tree interpolation */ -#define IZ3_ROOT SHRT_MAX - -/** This function uses Z3 to determine satisfiability of a set of - constraints. If UNSAT, an interpolant is returned, based on the - refutation generated by Z3. If SAT, a model is returned. - - If "parents" is non-null, computes a tree interpolant. The tree is - defined by the array "parents". This array maps each formula in - the tree to its parent, where formulas are indicated by their - integer index in "cnsts". The parent of formula n must have index - greater than n. The last formula is the root of the tree. Its - parent entry should be the constant IZ3_ROOT. - - If "parents" is null, computes a sequence interpolant. - - \param ctx The Z3 context. Must be generated by iz3_mk_context - \param num The number of constraints in the sequence - \param cnsts Array of constraints (AST's in context ctx) - \param parents The parents vector defining the tree structure - \param options Interpolation options (may be NULL) - \param interps Array to return interpolants (size at least num-1, may be NULL) - \param model Returns a Z3 model if constraints SAT (may be NULL) - \param labels Returns relevant labels if SAT (may be NULL) - \param incremental - - VERY IMPORTANT: All the Z3 formulas in cnsts must be in Z3 - context ctx. The model and interpolants returned are also - in this context. - - The return code is as in Z3_check_assumptions, that is, - - Z3_L_FALSE = constraints UNSAT (interpolants returned) - Z3_L_TRUE = constraints SAT (model returned) - Z3_L_UNDEF = Z3 produced no result, or interpolation not possible - - Currently, this function supports integer and boolean variables, - as well as arrays over these types, with linear arithmetic, - uninterpreted functions and quantifiers over integers (that is - AUFLIA). Interpolants are produced in AULIA. However, some - uses of array operations may cause quantifiers to appear in the - interpolants even when there are no quantifiers in the input formulas. - Although quantifiers may appear in the input formulas, Z3 may give up in - this case, returning Z3_L_UNDEF. - - If "incremental" is true, cnsts must contain exactly the set of - formulas that are currently asserted in the context. If false, - there must be no formulas currently asserted in the context. - Setting "incremental" to true makes it posisble to incrementally - add and remove constraints from the context until the context - becomes UNSAT, at which point an interpolant is computed. Caution - must be used, however. Before popping the context, if you wish to - keep the interolant formulas, you *must* preserve them by using - Z3_persist_ast. Also, if you want to simplify the interpolant - formulas using Z3_simplify, you must first pop all of the - assertions in the context (or use a different context). Otherwise, - the formulas will be simplified *relative* to these constraints, - which is almost certainly not what you want. - - - Current limitations on tree interpolants. In a tree interpolation - problem, each constant (0-ary function symbol) must occur only - along one path from root to leaf. Function symbols (of arity > 0) - are considered to have global scope (i.e., may appear in any - interpolant formula). - - def_API('Z3_interpolate', BOOL, (_in(CONTEXT), _in(UINT), _in_array(1, AST), _in_array(1, UINT), _in(PARAMS), _out_array(1, AST), _out(MODEL), _out(LITERALS), _in(UINT), _in(UINT), _in_array(9, AST))) -*/ - -Z3_lbool Z3_API Z3_interpolate(Z3_context ctx, - unsigned num, - Z3_ast *cnsts, - unsigned *parents, - Z3_params options, - Z3_ast *interps, - Z3_model *model, - Z3_literals *labels, - unsigned incremental, - unsigned num_theory, - Z3_ast *theory); -#endif From 727ba13566932a5f531241c4f33a4e1bade0080a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 12:55:04 -0700 Subject: [PATCH 0901/1283] fix #1653 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 21 +++++++++++++++------ src/opt/opt_context.h | 3 ++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 52048386d..8fc74ec83 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -128,6 +128,7 @@ namespace opt { m_optsmt(m), m_scoped_state(m), m_fm(alloc(generic_model_converter, m, "opt")), + m_model_fixed(false), m_objective_refs(m), m_enable_sat(false), m_is_clausal(false), @@ -339,15 +340,17 @@ namespace opt { } void context::fix_model(model_ref& mdl) { - if (mdl) { + if (mdl && !m_model_fixed) { (*m_fm)(mdl); apply(m_model_converter, mdl); + m_model_fixed = true; } } void context::get_model_core(model_ref& mdl) { mdl = m_model; fix_model(mdl); + TRACE("opt", model_smt2_pp(tout, m, *mdl.get(), 0);); } void context::get_box_model(model_ref& mdl, unsigned index) { @@ -441,11 +444,13 @@ namespace opt { lbool context::execute_box() { if (m_box_index < m_box_models.size()) { m_model = m_box_models[m_box_index]; + m_model_fixed = false; ++m_box_index; return l_true; } if (m_box_index < m_objectives.size()) { m_model = nullptr; + m_model_fixed = false; ++m_box_index; return l_undef; } @@ -470,6 +475,7 @@ namespace opt { } if (r == l_true && m_box_models.size() > 0) { m_model = m_box_models[0]; + m_model_fixed = false; } return r; } @@ -557,8 +563,10 @@ namespace opt { void context::yield() { SASSERT (m_pareto); m_pareto->get_model(m_model, m_labels); + m_model_fixed = false; update_bound(true); update_bound(false); + TRACE("opt", model_smt2_pp(tout, m, *m_model.get(), 0);); } lbool context::execute_pareto() { @@ -1191,7 +1199,7 @@ namespace opt { rational r; switch(obj.m_type) { case O_MINIMIZE: { - bool evaluated = m_model->eval(obj.m_term, val); + bool evaluated = m_model->eval(obj.m_term, val, true); TRACE("opt", tout << obj.m_term << " " << val << " " << evaluated << " " << is_numeral(val, r) << "\n";); if (evaluated && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); @@ -1206,7 +1214,7 @@ namespace opt { break; } case O_MAXIMIZE: { - bool evaluated = m_model->eval(obj.m_term, val); + bool evaluated = m_model->eval(obj.m_term, val, true); TRACE("opt", tout << obj.m_term << " " << val << "\n";); if (evaluated && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); @@ -1223,7 +1231,7 @@ namespace opt { case O_MAXSMT: { bool ok = true; for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { - bool evaluated = m_model->eval(obj.m_terms[j], val); + bool evaluated = m_model->eval(obj.m_terms[j], val, true); TRACE("opt", tout << mk_pp(obj.m_terms[j], m) << " " << val << "\n";); if (evaluated) { if (!m.is_true(val)) { @@ -1238,11 +1246,11 @@ namespace opt { maxsmt& ms = *m_maxsmts.find(obj.m_id); if (is_lower) { ms.update_upper(r); - TRACE("opt", tout << r << " " << ms.get_upper() << "\n";); + TRACE("opt", tout << "update upper from " << r << " to " << ms.get_upper() << "\n";); } else { ms.update_lower(r); - TRACE("opt", tout << r << " " << ms.get_lower() << "\n";); + TRACE("opt", tout << "update lower from " << r << " to " << ms.get_lower() << "\n";); } } break; @@ -1402,6 +1410,7 @@ namespace opt { m_pareto = nullptr; m_box_index = UINT_MAX; m_model.reset(); + m_model_fixed = false; } void context::set_pareto(pareto_base* p) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index b642f1d7a..51ea6cc71 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -156,9 +156,10 @@ namespace opt { map_t m_maxsmts; scoped_state m_scoped_state; vector m_objectives; - model_ref m_model; + model_ref m_model; model_converter_ref m_model_converter; generic_model_converter_ref m_fm; + bool m_model_fixed; unsigned m_model_counter; obj_map m_objective_fns; obj_map m_objective_orig; From da0239d20026051cdf952725101e9639e6152e35 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 21:21:27 -0700 Subject: [PATCH 0902/1283] fix #1655 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 12 ++++-------- src/opt/opt_context.h | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8fc74ec83..2850dd59c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -128,7 +128,7 @@ namespace opt { m_optsmt(m), m_scoped_state(m), m_fm(alloc(generic_model_converter, m, "opt")), - m_model_fixed(false), + m_model_fixed(), m_objective_refs(m), m_enable_sat(false), m_is_clausal(false), @@ -340,10 +340,10 @@ namespace opt { } void context::fix_model(model_ref& mdl) { - if (mdl && !m_model_fixed) { + if (mdl && !m_model_fixed.contains(mdl.get())) { (*m_fm)(mdl); apply(m_model_converter, mdl); - m_model_fixed = true; + m_model_fixed.push_back(mdl.get()); } } @@ -444,13 +444,11 @@ namespace opt { lbool context::execute_box() { if (m_box_index < m_box_models.size()) { m_model = m_box_models[m_box_index]; - m_model_fixed = false; ++m_box_index; return l_true; } if (m_box_index < m_objectives.size()) { m_model = nullptr; - m_model_fixed = false; ++m_box_index; return l_undef; } @@ -475,7 +473,6 @@ namespace opt { } if (r == l_true && m_box_models.size() > 0) { m_model = m_box_models[0]; - m_model_fixed = false; } return r; } @@ -563,7 +560,6 @@ namespace opt { void context::yield() { SASSERT (m_pareto); m_pareto->get_model(m_model, m_labels); - m_model_fixed = false; update_bound(true); update_bound(false); TRACE("opt", model_smt2_pp(tout, m, *m_model.get(), 0);); @@ -1410,7 +1406,7 @@ namespace opt { m_pareto = nullptr; m_box_index = UINT_MAX; m_model.reset(); - m_model_fixed = false; + m_model_fixed.reset(); } void context::set_pareto(pareto_base* p) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 51ea6cc71..29b327855 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -159,7 +159,7 @@ namespace opt { model_ref m_model; model_converter_ref m_model_converter; generic_model_converter_ref m_fm; - bool m_model_fixed; + sref_vector m_model_fixed; unsigned m_model_counter; obj_map m_objective_fns; obj_map m_objective_orig; From 6dc9c3a5870e55a93ae2a923a8e514ac176e4435 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 May 2018 07:37:27 -0700 Subject: [PATCH 0903/1283] fix ml build breakd #1659, #1660 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 47 ------------------------------------------ src/api/ml/z3.mli | 52 +---------------------------------------------- 2 files changed, 1 insertion(+), 98 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 5766c79f9..a676f8c43 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1654,7 +1654,6 @@ struct mk_list f n let get_subgoal (x:apply_result) (i:int) = Z3native.apply_result_get_subgoal (gc x) x i - let convert_model (x:apply_result) (i:int) (m:Model.model) = Z3native.apply_result_convert_model (gc x) x i m let to_string (x:apply_result) = Z3native.apply_result_to_string (gc x) x end @@ -1995,52 +1994,6 @@ struct cs sort_names sorts cd decl_names decls end -module Interpolation = -struct - let mk_interpolant = Z3native.mk_interpolant - - let mk_interpolation_context (settings:(string * string) list) = - let cfg = Z3native.mk_config () in - let f e = Z3native.set_param_value cfg (fst e) (snd e) in - List.iter f settings; - let res = Z3native.mk_interpolation_context cfg in - Z3native.del_config cfg; - Z3native.set_ast_print_mode res (int_of_ast_print_mode PRINT_SMTLIB2_COMPLIANT); - Z3native.set_internal_error_handler res; - res - - let get_interpolant (ctx:context) (pf:expr) (pat:expr) (p:Params.params) = - let av = Z3native.get_interpolant ctx pf pat p in - AST.ASTVector.to_expr_list av - - let compute_interpolant (ctx:context) (pat:expr) (p:Params.params) = - let (r, interp, model) = Z3native.compute_interpolant ctx pat p in - let res = lbool_of_int r in - match res with - | L_TRUE -> (res, None, Some model) - | L_FALSE -> (res, Some (AST.ASTVector.to_expr_list interp), None) - | _ -> (res, None, None) - - let get_interpolation_profile = Z3native.interpolation_profile - - let read_interpolation_problem (ctx:context) (filename:string) = - let (r, num, cnsts, parents, error, num_theory, theory) = - Z3native.read_interpolation_problem ctx filename - in - match r with - | 0 -> raise (Error "Interpolation problem could not be read.") - | _ -> (cnsts, parents, theory) - - let check_interpolant (ctx:context) (num:int) (cnsts:Expr.expr list) (parents:int list) (interps:Expr.expr list) (num_theory:int) (theory:Expr.expr list) = - let (r, str) = Z3native.check_interpolant ctx num cnsts parents interps num_theory theory in - match (lbool_of_int r) with - | L_UNDEF -> raise (Error "Interpolant could not be verified.") - | L_FALSE -> raise (Error "Interpolant could not be verified.") - | _ -> () - - let write_interpolation_problem (ctx:context) (num:int) (cnsts:Expr.expr list) (parents:int list) (filename:string) (num_theory:int) (theory:Expr.expr list) = - Z3native.write_interpolation_problem ctx num cnsts parents filename num_theory theory -end let set_global_param = Z3native.global_param_set diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 0fd1242ee..9b424b508 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2447,7 +2447,7 @@ sig The antecedents are proofs for equalities used as substitution rules. The object is also used in a few cases. The cases are: - When applying contextual simplification (CONTEXT_SIMPLIFIER=true) - - When converting bit-vectors to Booleans (BIT2BOOL=true) + - When converting bit-vectors to Booleans (BIT2BOOL=true) *) val is_rewrite_star : Expr.expr -> bool (** Indicates whether the term is a proof for pulling quantifiers out. @@ -2964,11 +2964,6 @@ sig (** Retrieves a subgoal from the apply_result. *) val get_subgoal : apply_result -> int -> Goal.goal - (** Convert a model for a subgoal into a model for the original - goal [g], that the ApplyResult was obtained from. - #return A model for [g] *) - val convert_model : apply_result -> int -> Model.model -> Model.model - (** A string representation of the ApplyResult. *) val to_string : apply_result -> string end @@ -3424,51 +3419,6 @@ sig val parse_smtlib2_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr end -(** Interpolation *) -module Interpolation : -sig - - (** Create an AST node marking a formula position for interpolation. - The expression must have Boolean sort. *) - val mk_interpolant : context -> Expr.expr -> Expr.expr - - (** The interpolation context is suitable for generation of interpolants. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val mk_interpolation_context : (string * string) list -> context - - (** Gets an interpolant. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val get_interpolant : context -> Expr.expr -> Expr.expr -> Params.params -> Expr.expr list - - (** Computes an interpolant. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val compute_interpolant : context -> Expr.expr -> Params.params -> (Z3enums.lbool * Expr.expr list option * Model.model option) - - (** Retrieves an interpolation profile. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val get_interpolation_profile : context -> string - - (** Read an interpolation problem from file. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val read_interpolation_problem : context -> string -> (Expr.expr list * int list * Expr.expr list) - - (** Check the correctness of an interpolant. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val check_interpolant : context -> int -> Expr.expr list -> int list -> Expr.expr list -> int -> Expr.expr list -> unit - - (** Write an interpolation problem to file suitable for reading with - Z3_read_interpolation_problem. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val write_interpolation_problem : context -> int -> Expr.expr list -> int list -> string -> int -> Expr.expr list -> unit - -end (** Set a global (or module) parameter, which is shared by all Z3 contexts. From db3f439e88c5696011da8beb3f7c363b686182aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 May 2018 20:55:30 -0700 Subject: [PATCH 0904/1283] fix memory leak from Arie Signed-off-by: Nikolaj Bjorner --- src/smt/asserted_formulas.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 605c447bd..c00fb93b1 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -500,6 +500,7 @@ unsigned asserted_formulas::propagate_values(unsigned i) { void asserted_formulas::update_substitution(expr* n, proof* pr) { expr* lhs, *rhs, *n1; + proof_ref pr1(m); if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { compute_depth(lhs); compute_depth(rhs); @@ -510,12 +511,12 @@ void asserted_formulas::update_substitution(expr* n, proof* pr) { } if (is_gt(rhs, lhs)) { TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); - m_scoped_substitution.insert(rhs, lhs, m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr); + pr1 = m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr; + m_scoped_substitution.insert(rhs, lhs, pr1); return; } TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); } - proof_ref pr1(m); if (m.is_not(n, n1)) { pr1 = m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr; m_scoped_substitution.insert(n1, m.mk_false(), pr1); From 0d668e14289c0728b65bbcc214749ac865297507 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 May 2018 03:18:22 -0700 Subject: [PATCH 0905/1283] fix #1661 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index e4a34fc93..3862aecae 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -357,8 +357,8 @@ struct pb2bv_rewriter::imp { /** \brief MiniSat+ based encoding of PB constraints. - The procedure is described in "Translating Pseudo-Boolean Constraints into SAT " -         Niklas Een, Niklas Sörensson, JSAT 2006. + Translating Pseudo-Boolean Constraints into SAT, + Niklas Een, Niklas Soerensson, JSAT 2006. */ From b9637924c44bf47b06643b728044bd48d2927e26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 May 2018 16:47:17 -0700 Subject: [PATCH 0906/1283] fix #1662 Signed-off-by: Nikolaj Bjorner --- src/qe/qe_lite.cpp | 42 +++++++++++++++++++----------------------- src/qe/qe_lite.h | 1 - src/smt/theory_str.cpp | 6 ++++-- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index ae969a99e..6ecdfd835 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -89,7 +89,7 @@ namespace eq { var * v = vars[i]; expr * t = definitions[i]; if (t == nullptr || has_quantifiers(t) || occurs_var(v->get_idx(), t)) - definitions[i] = 0; + definitions[i] = nullptr; else found = true; // found at least one candidate } @@ -106,7 +106,7 @@ namespace eq { unsigned vidx, num; for (unsigned i = 0; i < definitions.size(); i++) { - if (definitions[i] == 0) + if (definitions[i] == nullptr) continue; var * v = vars[i]; SASSERT(v->get_idx() == i); @@ -116,7 +116,7 @@ namespace eq { start: frame & fr = todo.back(); expr * t = fr.first; - if (t->get_ref_count() > 1 && done.is_marked(t)) { + if (done.is_marked(t)) { todo.pop_back(); continue; } @@ -126,11 +126,11 @@ namespace eq { if (fr.second == 0) { CTRACE("der_bug", vidx >= definitions.size(), tout << "vidx: " << vidx << "\n";); // Remark: The size of definitions may be smaller than the number of variables occurring in the quantified formula. - if (definitions.get(vidx, 0) != 0) { + if (definitions.get(vidx, nullptr) != nullptr) { if (visiting.is_marked(t)) { // cycle detected: remove t visiting.reset_mark(t); - definitions[vidx] = 0; + definitions[vidx] = nullptr; } else { visiting.mark(t); @@ -142,17 +142,14 @@ namespace eq { } else { SASSERT(fr.second == 1); - if (definitions.get(vidx, 0) != 0) { - visiting.reset_mark(t); - order.push_back(vidx); - } - else { - // var was removed from the list of candidate vars to elim cycle - // do nothing + visiting.reset_mark(t); + if (!done.is_marked(t)) { + if (definitions.get(vidx, nullptr) != nullptr) + order.push_back(vidx); + done.mark(t); } } - if (t->get_ref_count() > 1) - done.mark(t); + done.mark(t); todo.pop_back(); break; case AST_QUANTIFIER: @@ -164,13 +161,11 @@ namespace eq { while (fr.second < num) { expr * arg = to_app(t)->get_arg(fr.second); fr.second++; - if (arg->get_ref_count() > 1 && done.is_marked(arg)) - continue; + if (done.is_marked(arg)) continue; todo.push_back(frame(arg, 0)); goto start; } - if (t->get_ref_count() > 1) - done.mark(t); + done.mark(t); todo.pop_back(); break; default: @@ -574,12 +569,15 @@ namespace eq { checkpoint(); ptr_vector vs; expr_ref_vector ts(m); + expr_ref t(m); if (is_var_def(is_exists, args[i], vs, ts)) { for (unsigned j = 0; j < vs.size(); ++j) { var* v = vs[j]; - expr* t = ts[j].get(); + t = ts.get(j); + m_rewriter(t); + if (t != ts.get(j)) m_new_exprs.push_back(t); unsigned idx = v->get_idx(); - if (m_map.get(idx, 0) == 0) { + if (m_map.get(idx, nullptr) == nullptr) { m_map.reserve(idx + 1, 0); m_inx2var.reserve(idx + 1, 0); m_map[idx] = t; @@ -2461,9 +2459,7 @@ public: fmls[index] = fml; return; } - TRACE("qe_lite", for (unsigned i = 0; i < fmls.size(); ++i) { - tout << mk_pp(fmls[i].get(), m) << "\n"; - }); + TRACE("qe_lite", tout << fmls << "\n";); is_variable_test is_var(index_set, index_of_bound); m_der.set_is_variable_proc(is_var); m_fm.set_is_variable_proc(is_var); diff --git a/src/qe/qe_lite.h b/src/qe/qe_lite.h index 4fc5572a2..63ad8bedd 100644 --- a/src/qe/qe_lite.h +++ b/src/qe/qe_lite.h @@ -57,7 +57,6 @@ public: void operator()(uint_set const& index_set, bool index_of_bound, expr_ref& fml); void operator()(uint_set const& index_set, bool index_of_bound, expr_ref_vector& conjs); - /** \brief full rewriting based light-weight quantifier elimination round. */ diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index dde75c4bc..0ef008927 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6645,7 +6645,8 @@ namespace smt { expr * sub1; expr * sub2; if (u.re.is_to_re(re, sub1)) { - SASSERT(u.str.is_string(sub1)); + if (!u.str.is_string(sub1)) + throw default_exception("regular expressions must be built from string literals"); zstring str; u.str.is_string(sub1, str); return str.length(); @@ -6842,7 +6843,8 @@ namespace smt { expr * sub1; expr * sub2; if (u.re.is_to_re(re, sub1)) { - SASSERT(u.str.is_string(sub1)); + if (!u.str.is_string(sub1)) + throw default_exception("regular expressions must be built from string literals"); zstring str; u.str.is_string(sub1, str); rational strlen(str.length()); From fee4f91e2d598270f16cbfd68e9728dd8368d837 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Jun 2018 08:07:06 -0700 Subject: [PATCH 0907/1283] add set operations to python request by Francois Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 113 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 784228120..7657fb347 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -2765,6 +2765,8 @@ def _py2expr(a, ctx=None): return IntVal(a, ctx) if isinstance(a, float): return RealVal(a, ctx) + if is_expr(a): + return a if __debug__: _z3_assert(False, "Python bool, int, long or float expected") @@ -4399,6 +4401,117 @@ def is_store(a): """ return is_app_of(a, Z3_OP_STORE) +######################################### +# +# Sets +# +######################################### + + +def SetSort(s): + """ Create a set sort over element sort s""" + return ArraySort(s, BoolSort()) + +def EmptySet(s): + """Create the empty set + >>> EmptySet(IntSort()) + K(Int, False) + """ + ctx = s.ctx + return ArrayRef(Z3_mk_empty_set(ctx.ref(), s.ast), ctx) + +def FullSet(s): + """Create the full set + >>> FullSet(IntSort()) + K(Int, True) + """ + ctx = s.ctx + return ArrayRef(Z3_mk_full_set(ctx.ref(), s.ast), ctx) + +def SetUnion(*args): + """ Take the union of sets + >>> a = Const('a', SetSort(IntSort())) + >>> b = Const('b', SetSort(IntSort())) + >>> SetUnion(a, b) + union(a, b) + """ + args = _get_args(args) + ctx = _ctx_from_ast_arg_list(args) + _args, sz = _to_ast_array(args) + return ArrayRef(Z3_mk_set_union(ctx.ref(), sz, _args), ctx) + +def SetIntersect(*args): + """ Take the union of sets + >>> a = Const('a', SetSort(IntSort())) + >>> b = Const('b', SetSort(IntSort())) + >>> SetIntersect(a, b) + intersect(a, b) + """ + args = _get_args(args) + ctx = _ctx_from_ast_arg_list(args) + _args, sz = _to_ast_array(args) + return ArrayRef(Z3_mk_set_intersect(ctx.ref(), sz, _args), ctx) + +def SetAdd(s, e): + """ Add element e to set s + >>> a = Const('a', SetSort(IntSort())) + >>> SetAdd(a, 1) + Store(a, 1, True) + """ + ctx = _ctx_from_ast_arg_list([s,e]) + e = _py2expr(e, ctx) + return ArrayRef(Z3_mk_set_add(ctx.ref(), s.as_ast(), e.as_ast()), ctx) + +def SetDel(s, e): + """ Remove element e to set s + >>> a = Const('a', SetSort(IntSort())) + >>> SetDel(a, 1) + Store(a, 1, False) + """ + ctx = _ctx_from_ast_arg_list([s,e]) + e = _py2expr(e, ctx) + return ArrayRef(Z3_mk_set_del(ctx.ref(), s.as_ast(), e.as_ast()), ctx) + +def SetComplement(s): + """ The complement of set s + >>> a = Const('a', SetSort(IntSort())) + >>> SetComplement(a) + complement(a) + """ + ctx = s.ctx + return ArrayRef(Z3_mk_set_complement(ctx.ref(), s.as_ast()), ctx) + +def SetDifference(a, b): + """ The set difference of a and b + >>> a = Const('a', SetSort(IntSort())) + >>> b = Const('b', SetSort(IntSort())) + >>> SetDifference(a, b) + difference(a, b) + """ + ctx = _ctx_from_ast_arg_list([a, b]) + return ArrayRef(Z3_mk_set_difference(ctx.ref(), a.as_ast(), b.as_ast()), ctx) + +def IsMember(e, s): + """ Check if e is a member of set s + >>> a = Const('a', SetSort(IntSort())) + >>> IsMember(1, a) + a[1] + """ + ctx = _ctx_from_ast_arg_list([s,e]) + e = _py2expr(e, ctx) + return BoolRef(Z3_mk_set_member(ctx.ref(), e.as_ast(), s.as_ast()), ctx) + +def IsSubset(a, b): + """ Check if a is a subset of b + >>> a = Const('a', SetSort(IntSort())) + >>> b = Const('b', SetSort(IntSort())) + >>> IsSubset(a, b) + subset(a, b) + """ + ctx = _ctx_from_ast_arg_list([a, b]) + return BoolRef(Z3_mk_set_subset(ctx.ref(), a.as_ast(), b.as_ast()), ctx) + + ######################################### # # Datatypes From 8ab428b6600e0d0263b2986aea02553dc3fc931d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 17:42:44 -0700 Subject: [PATCH 0908/1283] try new gcd Signed-off-by: Nikolaj Bjorner --- src/util/mpz.cpp | 120 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 33 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 39ea428a7..409ca325f 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -45,43 +45,97 @@ Revision History: #define LEHMER_GCD #endif -template -static T gcd_core(T u, T v) { - if (u == 0) - return v; - if (v == 0) - return u; - int k; - - for (k = 0; ((u | v) & 1) == 0; ++k) { - u >>= 1; - v >>= 1; - } - - while ((u & 1) == 0) - u >>= 1; - +#if 1 +#include + +#define _trailing_zeros32(x) _tzcnt_u32(x) + +#ifdef _AMD64_ +#define _trailing_zeros64(x) _tzcnt_u64(x) +#else +inline uint64 _trailing_zeros64(uint64 x) { + uint64 r = 0; + for (; 0 == (x & 1) && r < 64; ++r, x >>= 1); + return r; +} +#endif + +#else + +inline unsigned _trailing_zeros32(unsigned x) { + unsigned r = 0; + for (; 0 == (x & 1) && r < 32; ++r, x >>= 1); + return r; +} +#endif + +#define _bit_min(x, y) (y + ((x - y) & ((int)(x - y) >> 31))) +#define _bit_max(x, y) (x - ((x - y) & ((int)(x - y) >> 31))) + + + +unsigned u_gcd(unsigned u, unsigned v) { + if (u == 0) return v; + if (v == 0) return u; + unsigned shift = _trailing_zeros32(u | v); + u >>= _trailing_zeros32(u); + v >>= _trailing_zeros32(v); + if (u == 1 || v == 1) return 1 << shift; + if (u == v) return u << shift; do { - while ((v & 1) == 0) - v >>= 1; - - if (u < v) { - v -= u; - } - else { - T diff = u - v; - u = v; - v = diff; - } - v >>= 1; - } while (v != 0); - - return u << k; +#if 1 + unsigned diff = u - v; + unsigned mdiff = diff & (unsigned)((int)diff >> 31); + u = v + mdiff; // min + v = diff - 2 * mdiff; // if v <= u: u - v, if v > u: v - u = u - v - 2 * (u - v) +#endif +#if 0 + unsigned t = _bit_max(u, v); + u = _bit_min(u, v); + v = t; + v -= u; +#endif +#if 0 + unsigned t = std::max(u, v); + u = std::min(u,v); + v = t; + v -= u; +#endif +#if 0 + if (u > v) std::swap(u, v); + v -= u; +#endif +#if 0 + unsigned d1 = u - v; + unsigned d2 = v - u; + unsigned md21 = d2 & (unsigned)((int)d1 >> 31); + unsigned md12 = d1 & (unsigned)((int)d2 >> 31); + u = _bit_min(u, v); + v = md12 | md21; +#endif + + v >>= _trailing_zeros32(v); + } + while (v != 0); + return u << shift; +} + +uint64 u64_gcd(uint64 u, uint64 v) { + if (u == 0) return v; + if (v == 0) return u; + if (u == 1 || v == 1) return 1; + uint64 shift = _trailing_zeros64(u | v); + u >>= _trailing_zeros64(u); + do { + v >>= _trailing_zeros64(v); + if (u > v) std::swap(u, v); + v -= u; + } + while (v != 0); + return u << shift; } -unsigned u_gcd(unsigned u, unsigned v) { return gcd_core(u, v); } -uint64_t u64_gcd(uint64_t u, uint64_t v) { return gcd_core(u, v); } template mpz_manager::mpz_manager(): From 99bdb461583e34f16df6b7f6508eebeafaf9d893 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 17:48:30 -0700 Subject: [PATCH 0909/1283] int64_t Signed-off-by: Nikolaj Bjorner --- src/util/mpz.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 409ca325f..8f65a3602 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -74,7 +74,6 @@ inline unsigned _trailing_zeros32(unsigned x) { #define _bit_max(x, y) (x - ((x - y) & ((int)(x - y) >> 31))) - unsigned u_gcd(unsigned u, unsigned v) { if (u == 0) return v; if (v == 0) return u; @@ -121,11 +120,11 @@ unsigned u_gcd(unsigned u, unsigned v) { return u << shift; } -uint64 u64_gcd(uint64 u, uint64 v) { +uint64_t u64_gcd(uint64_t u, uint64_t v) { if (u == 0) return v; if (v == 0) return u; if (u == 1 || v == 1) return 1; - uint64 shift = _trailing_zeros64(u | v); + auto shift = _trailing_zeros64(u | v); u >>= _trailing_zeros64(u); do { v >>= _trailing_zeros64(v); From d7f51f2443edd5ee57255fc652a2da5e7f990aae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 18:20:23 -0700 Subject: [PATCH 0910/1283] try flags to fix gcc build Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a086afd71..f34e400f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,7 +381,7 @@ endif() # FIXME: Support ARM "-mfpu=vfp -mfloat-abi=hard" if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" STREQUAL "i686")) if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) - set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2") + set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2" "-mfsr") # FIXME: Remove "x.." when CMP0054 is set to NEW elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") set(SSE_FLAGS "/arch:SSE2") From ad67424987aeae720054b21f3196471dac08f474 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 18:23:04 -0700 Subject: [PATCH 0911/1283] deal with shift exponent error Signed-off-by: Nikolaj Bjorner --- src/util/mpz.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 8f65a3602..6387fccd9 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -79,10 +79,10 @@ unsigned u_gcd(unsigned u, unsigned v) { if (v == 0) return u; unsigned shift = _trailing_zeros32(u | v); u >>= _trailing_zeros32(u); - v >>= _trailing_zeros32(v); if (u == 1 || v == 1) return 1 << shift; if (u == v) return u << shift; do { + v >>= _trailing_zeros32(v); #if 1 unsigned diff = u - v; unsigned mdiff = diff & (unsigned)((int)diff >> 31); @@ -113,8 +113,6 @@ unsigned u_gcd(unsigned u, unsigned v) { u = _bit_min(u, v); v = md12 | md21; #endif - - v >>= _trailing_zeros32(v); } while (v != 0); return u << shift; From 8565de2c5b38cd355ea15f1da3f460f352162f86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 19:17:37 -0700 Subject: [PATCH 0912/1283] deal with shift exponent error Signed-off-by: Nikolaj Bjorner --- src/util/mpz.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 6387fccd9..2a85320a5 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -49,9 +49,13 @@ Revision History: #if 1 #include -#define _trailing_zeros32(x) _tzcnt_u32(x) +#if defined(__GNUC__) +#define _trailing_zeros32(X) __builtin_ctz(X) +#else +#define _trailing_zeros32(X) _tzcnt_u32(X) +#endif -#ifdef _AMD64_ +#if defined(_AMD64_) && !defined(__GNUC__) #define _trailing_zeros64(x) _tzcnt_u64(x) #else inline uint64 _trailing_zeros64(uint64 x) { From bb5306031369dd22cfcc291ea7aeeb83b2c8fc63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 19:26:40 -0700 Subject: [PATCH 0913/1283] int64_t Signed-off-by: Nikolaj Bjorner --- src/util/mpz.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 2a85320a5..50f0d68e7 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -58,8 +58,8 @@ Revision History: #if defined(_AMD64_) && !defined(__GNUC__) #define _trailing_zeros64(x) _tzcnt_u64(x) #else -inline uint64 _trailing_zeros64(uint64 x) { - uint64 r = 0; +inline uint64_t _trailing_zeros64(uint64_t x) { + uint64_t r = 0; for (; 0 == (x & 1) && r < 64; ++r, x >>= 1); return r; } From 88ead235f0f8ab16e90efc52bc4b2b5df7269123 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 19:30:56 -0700 Subject: [PATCH 0914/1283] gcc mode Signed-off-by: Nikolaj Bjorner --- src/util/mpz.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 50f0d68e7..ddca84922 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -55,8 +55,12 @@ Revision History: #define _trailing_zeros32(X) _tzcnt_u32(X) #endif -#if defined(_AMD64_) && !defined(__GNUC__) -#define _trailing_zeros64(x) _tzcnt_u64(x) +#if defined(_AMD64_) + #if defined(__GNUC__) + #define _trailing_zeros64(X) __builtin_ctzll(X) + #else + #define _trailing_zeros64(X) _tzcnt_u64(X) + #endif #else inline uint64_t _trailing_zeros64(uint64_t x) { uint64_t r = 0; From 9e916edcb04e35bb39a43a42911f3e062f003bcc Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 7 Jun 2018 15:40:04 +0100 Subject: [PATCH 0915/1283] z3.py: add overflow checks to PB API --- src/api/python/z3/z3.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 7657fb347..ab2217e13 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -90,6 +90,9 @@ def _z3_assert(cond, msg): if not cond: raise Z3Exception(msg) +def _z3_check_cint_overflow(n, name): + _z3_assert(ctypes.c_int(n).value == n, name + " is too large") + def open_log(fname): """Log interaction to a file. This function must be invoked immediately after init(). """ Z3_open_log(fname) @@ -8128,6 +8131,7 @@ def _pb_args_coeffs(args, default_ctx = None): _args, sz = _to_ast_array(args) _coeffs = (ctypes.c_int * len(coeffs))() for i in range(len(coeffs)): + _z3_check_cint_overflow(coeffs[i], "coefficient") _coeffs[i] = coeffs[i] return ctx, sz, _args, _coeffs @@ -8137,6 +8141,7 @@ def PbLe(args, k): >>> a, b, c = Bools('a b c') >>> f = PbLe(((a,1),(b,3),(c,2)), 3) """ + _z3_check_cint_overflow(k, "k") ctx, sz, _args, _coeffs = _pb_args_coeffs(args) return BoolRef(Z3_mk_pble(ctx.ref(), sz, _args, _coeffs, k), ctx) @@ -8146,6 +8151,7 @@ def PbGe(args, k): >>> a, b, c = Bools('a b c') >>> f = PbGe(((a,1),(b,3),(c,2)), 3) """ + _z3_check_cint_overflow(k, "k") ctx, sz, _args, _coeffs = _pb_args_coeffs(args) return BoolRef(Z3_mk_pbge(ctx.ref(), sz, _args, _coeffs, k), ctx) @@ -8155,6 +8161,7 @@ def PbEq(args, k, ctx = None): >>> a, b, c = Bools('a b c') >>> f = PbEq(((a,1),(b,3),(c,2)), 3) """ + _z3_check_cint_overflow(k, "k") ctx, sz, _args, _coeffs = _pb_args_coeffs(args) return BoolRef(Z3_mk_pbeq(ctx.ref(), sz, _args, _coeffs, k), ctx) From 29c26724071362cc87c23f9e9cad6a63b3334f68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Jun 2018 21:43:37 -0700 Subject: [PATCH 0916/1283] fix bugs exposed by Nuno's PB example Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 25 ++++++++++++++++++++----- src/sat/ba_solver.h | 8 ++++---- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 4fbf7570d..669389d2a 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -166,10 +166,11 @@ namespace sat { unsigned w = 0; for (unsigned i = 0; i < m_size; ++i) { m_wlits[i].second.neg(); + VERIFY(w + m_wlits[i].first >= w); w += m_wlits[i].first; - } + } m_k = w - m_k + 1; - SASSERT(w >= m_k && m_k > 0); + VERIFY(w >= m_k && m_k > 0); } bool ba_solver::pb::is_watching(literal l) const { @@ -526,11 +527,13 @@ namespace sat { bool ba_solver::init_watch(pb& p) { clear_watch(p); if (p.lit() != null_literal && value(p.lit()) == l_false) { + //IF_VERBOSE(0, verbose_stream() << "negate: " << p.k() << "\n"); p.negate(); } VERIFY(p.lit() == null_literal || value(p.lit()) == l_true); unsigned sz = p.size(), bound = p.k(); + //IF_VERBOSE(0, verbose_stream() << "bound: " << p.k() << "\n"); // put the non-false literals into the head. unsigned slack = 0, slack1 = 0, num_watch = 0, j = 0; @@ -833,9 +836,19 @@ namespace sat { remove_constraint(p, "recompiled to cardinality"); return; } - else { p.set_size(sz); + p.update_max_sum(); + if (p.max_sum() < k) { + if (p.lit() == null_literal) { + s().set_conflict(justification()); + } + else { + s().assign(~p.lit(), justification()); + } + remove_constraint(p, "recompiled to false"); + return; + } p.set_k(k); SASSERT(p.well_formed()); @@ -3210,6 +3223,7 @@ namespace sat { if (is_marked(l) && m_weights[l.index()] <= p2.get_coeff(i)) { ++num_sub; } + if (p1.size() + i > p2.size() + num_sub) return false; } return num_sub == p1.size(); } @@ -3364,8 +3378,9 @@ namespace sat { m_weights.setx(l.second.index(), l.first, 0); mark_visited(l.second); } - for (unsigned i = 0; i < p1.num_watch(); ++i) { - subsumes(p1, p1[i].second); + for (unsigned i = 0; i < std::min(10u, p1.num_watch()); ++i) { + unsigned j = s().m_rand() % p1.num_watch(); + subsumes(p1, p1[j].second); } for (wliteral l : p1) { m_weights[l.second.index()] = 0; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 07e7cfd58..e947cee96 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -124,8 +124,8 @@ namespace sat { protected: unsigned m_k; public: - pb_base(tag_t t, unsigned id, literal l, unsigned sz, size_t osz, unsigned k): constraint(t, id, l, sz, osz), m_k(k) {} - virtual void set_k(unsigned k) { m_k = k; } + pb_base(tag_t t, unsigned id, literal l, unsigned sz, size_t osz, unsigned k): constraint(t, id, l, sz, osz), m_k(k) { VERIFY(k < 4000000000); } + virtual void set_k(unsigned k) { VERIFY(k < 4000000000); m_k = k; } virtual unsigned get_coeff(unsigned i) const { UNREACHABLE(); return 0; } unsigned k() const { return m_k; } virtual bool well_formed() const; @@ -157,7 +157,6 @@ namespace sat { unsigned m_num_watch; unsigned m_max_sum; wliteral m_wlits[0]; - void update_max_sum(); public: static size_t get_obj_size(unsigned num_lits) { return sizeof(pb) + num_lits * sizeof(wliteral); } pb(unsigned id, literal lit, svector const& wlits, unsigned k); @@ -171,10 +170,11 @@ namespace sat { void set_slack(unsigned s) { m_slack = s; } unsigned num_watch() const { return m_num_watch; } unsigned max_sum() const { return m_max_sum; } + void update_max_sum(); void set_num_watch(unsigned s) { m_num_watch = s; } bool is_cardinality() const; virtual void negate(); - virtual void set_k(unsigned k) { m_k = k; update_max_sum(); } + virtual void set_k(unsigned k) { m_k = k; VERIFY(k < 4000000000); update_max_sum(); } virtual void swap(unsigned i, unsigned j) { std::swap(m_wlits[i], m_wlits[j]); } virtual literal_vector literals() const { literal_vector lits; for (auto wl : *this) lits.push_back(wl.second); return lits; } virtual bool is_watching(literal l) const; From 4547f2c001d894808987487a5e98c713debff411 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Jun 2018 22:03:03 -0700 Subject: [PATCH 0917/1283] enable non-expression bodies of quantifiers to fix #1667 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 10 +++++++--- src/util/mpz.cpp | 9 --------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 7657fb347..89615e11e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1898,13 +1898,17 @@ def is_quantifier(a): def _mk_quantifier(is_forall, vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]): if __debug__: - _z3_assert(is_bool(body), "Z3 expression expected") + _z3_assert(is_bool(body) or is_app(vs) or (len(vs) > 0 and is_app(vs[0])), "Z3 expression expected") _z3_assert(is_const(vs) or (len(vs) > 0 and all([ is_const(v) for v in vs])), "Invalid bounded variable(s)") _z3_assert(all([is_pattern(a) or is_expr(a) for a in patterns]), "Z3 patterns expected") - _z3_assert(all([is_expr(p) for p in no_patterns]), "no patterns are Z3 expressions") - ctx = body.ctx + _z3_assert(all([is_expr(p) for p in no_patterns]), "no patterns are Z3 expressions") if is_app(vs): + ctx = vs.ctx vs = [vs] + else: + ctx = vs[0].ctx + if not is_expr(body): + body = BoolVal(body, ctx) num_vars = len(vs) if num_vars == 0: return body diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index ddca84922..861a31cfb 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -46,7 +46,6 @@ Revision History: #endif -#if 1 #include #if defined(__GNUC__) @@ -69,14 +68,6 @@ inline uint64_t _trailing_zeros64(uint64_t x) { } #endif -#else - -inline unsigned _trailing_zeros32(unsigned x) { - unsigned r = 0; - for (; 0 == (x & 1) && r < 32; ++r, x >>= 1); - return r; -} -#endif #define _bit_min(x, y) (y + ((x - y) & ((int)(x - y) >> 31))) #define _bit_max(x, y) (x - ((x - y) & ((int)(x - y) >> 31))) From 0520d1a1f694339039a68796353c4ee040b94e46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Jun 2018 07:38:30 -0700 Subject: [PATCH 0918/1283] remove trial with mfsr flag Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f34e400f5..a086afd71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,7 +381,7 @@ endif() # FIXME: Support ARM "-mfpu=vfp -mfloat-abi=hard" if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" STREQUAL "i686")) if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) - set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2" "-mfsr") + set(SSE_FLAGS "-mfpmath=sse" "-msse" "-msse2") # FIXME: Remove "x.." when CMP0054 is set to NEW elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") set(SSE_FLAGS "/arch:SSE2") From 63a1b2e7147ac2cd447c1ef3a3565bcc389eb4b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Jun 2018 10:30:20 -0700 Subject: [PATCH 0919/1283] fix #1665 Signed-off-by: Nikolaj Bjorner --- src/ast/static_features.cpp | 6 +++++- src/ast/static_features.h | 1 + src/smt/smt_setup.cpp | 21 +++++++++++---------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index 9f52ea9a5..c8a1adcbe 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -81,6 +81,7 @@ void static_features::reset() { m_has_str = false; m_has_seq_non_str = false; m_has_arrays = false; + m_has_ext_arrays = false; m_arith_k_sum .reset(); m_num_arith_terms = 0; m_num_arith_eqs = 0; @@ -271,8 +272,11 @@ void static_features::update_core(expr * e) { m_has_bv = true; if (!m_has_fpa && (m_fpautil.is_float(e) || m_fpautil.is_rm(e))) m_has_fpa = true; - if (!m_has_arrays && m_arrayutil.is_array(e)) + if (!m_has_arrays && m_arrayutil.is_array(e)) m_has_arrays = true; + if (!m_has_ext_arrays && m_arrayutil.is_array(e) && + !m_arrayutil.is_select(e) && !m_arrayutil.is_store(e)) + m_has_ext_arrays = true; if (!m_has_str && m_sequtil.str.is_string_term(e)) m_has_str = true; if (!m_has_seq_non_str && m_sequtil.str.is_non_string_sequence(e)) { diff --git a/src/ast/static_features.h b/src/ast/static_features.h index 5473ba0ff..197947026 100644 --- a/src/ast/static_features.h +++ b/src/ast/static_features.h @@ -82,6 +82,7 @@ struct static_features { bool m_has_str; // has String-typed terms bool m_has_seq_non_str; // has non-String-typed Sequence terms bool m_has_arrays; // + bool m_has_ext_arrays; // does this use extended array theory. rational m_arith_k_sum; // sum of the numerals in arith atoms. unsigned m_num_arith_terms; unsigned m_num_arith_eqs; // equalities of the form t = k where k is a numeral diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 83b15fd90..55ea55663 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -576,17 +576,18 @@ namespace smt { m_params.m_nnf_cnf = false; m_params.m_propagate_booleans = true; m_context.register_plugin(alloc(smt::theory_bv, m_manager, m_params, m_params)); - m_context.register_plugin(alloc(smt::theory_array, m_manager, m_params)); + setup_arrays(); } void setup::setup_QF_AX() { + TRACE("setup", tout << "QF_AX\n";); m_params.m_array_mode = AR_SIMPLE; m_params.m_nnf_cnf = false; - m_context.register_plugin(alloc(smt::theory_array, m_manager, m_params)); + setup_arrays(); } void setup::setup_QF_AX(static_features const & st) { - m_params.m_array_mode = AR_SIMPLE; + m_params.m_array_mode = st.m_has_ext_arrays ? AR_FULL : AR_SIMPLE; m_params.m_nnf_cnf = false; if (st.m_num_clauses == st.m_num_units) { m_params.m_relevancy_lvl = 0; @@ -595,7 +596,7 @@ namespace smt { else { m_params.m_relevancy_lvl = 2; } - m_context.register_plugin(alloc(smt::theory_array, m_manager, m_params)); + setup_arrays(); } void setup::setup_QF_AUFLIA() { @@ -607,11 +608,11 @@ namespace smt { m_params.m_restart_factor = 1.5; m_params.m_phase_selection = PS_CACHING_CONSERVATIVE2; setup_i_arith(); - m_context.register_plugin(alloc(smt::theory_array, m_manager, m_params)); + setup_arrays(); } void setup::setup_QF_AUFLIA(static_features const & st) { - m_params.m_array_mode = AR_SIMPLE; + m_params.m_array_mode = st.m_has_ext_arrays ? AR_FULL : AR_SIMPLE; if (st.m_has_real) throw default_exception("Benchmark has real variables but it is marked as QF_AUFLIA (arrays, uninterpreted functions and linear integer arithmetic)."); m_params.m_nnf_cnf = false; @@ -631,7 +632,7 @@ namespace smt { // m_context.register_plugin(new smt::theory_si_arith(m_manager, m_params)); // else setup_i_arith(); - m_context.register_plugin(alloc(smt::theory_array, m_manager, m_params)); + setup_arrays(); } void setup::setup_AUFLIA(bool simple_array) { @@ -992,17 +993,17 @@ namespace smt { } if (st.num_theories() == 1 && st.m_has_arrays) { - setup_QF_AX(); + setup_QF_AX(st); return; } - if (st.num_theories() == 2 && st.has_uf() && st.m_has_arrays && st.m_has_bv) { + if (st.num_theories() == 2 && st.has_uf() && st.m_has_arrays && !st.m_has_ext_arrays && st.m_has_bv) { setup_QF_AUFBV(); return; } if (st.num_theories() == 2 && st.has_uf() && st.m_has_arrays && st.m_has_int) { - setup_QF_AUFLIA(); + setup_QF_AUFLIA(st); return; } From e94b97376c50b80fea4b8c8b01e8c29ee27d8f0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Jun 2018 10:16:03 -0700 Subject: [PATCH 0920/1283] fix memory leak in relation_manager, use for loops Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_relation_manager.cpp | 102 ++++++++++------------------ 1 file changed, 36 insertions(+), 66 deletions(-) diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index c9fc4f173..ff12e66c9 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -210,11 +210,9 @@ namespace datalog { if(m_favourite_relation_plugin && m_favourite_relation_plugin->can_handle_signature(s)) { return m_favourite_relation_plugin; } - relation_plugin_vector::iterator rpit = m_relation_plugins.begin(); - relation_plugin_vector::iterator rpend = m_relation_plugins.end(); - for(; rpit!=rpend; ++rpit) { - if((*rpit)->can_handle_signature(s)) { - return *rpit; + for (auto * r : m_relation_plugins) { + if (r->can_handle_signature(s)) { + return r; } } return nullptr; @@ -232,11 +230,9 @@ namespace datalog { if (m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) { return m_favourite_table_plugin; } - table_plugin_vector::iterator tpit = m_table_plugins.begin(); - table_plugin_vector::iterator tpend = m_table_plugins.end(); - for(; tpit!=tpend; ++tpit) { - if((*tpit)->can_handle_signature(t)) { - return *tpit; + for (auto * a : m_table_plugins) { + if (a->can_handle_signature(t)) { + return a; } } return nullptr; @@ -251,11 +247,9 @@ namespace datalog { } relation_plugin * relation_manager::get_relation_plugin(symbol const& s) { - relation_plugin_vector::iterator rpit = m_relation_plugins.begin(); - relation_plugin_vector::iterator rpend = m_relation_plugins.end(); - for(; rpit!=rpend; ++rpit) { - if((*rpit)->get_name()==s) { - return *rpit; + for (auto* r : m_relation_plugins) { + if(r->get_name() == s) { + return r; } } return nullptr; @@ -480,46 +474,37 @@ namespace datalog { std::string relation_manager::to_nice_string(const relation_signature & s) const { std::string res("["); bool first = true; - relation_signature::const_iterator it = s.begin(); - relation_signature::const_iterator end = s.end(); - for(; it!=end; ++it) { - if(first) { + for (auto const& sig : s) { + if (first) { first = false; } else { - res+=','; + res += ','; } - res+=to_nice_string(*it); + res += to_nice_string(sig); } - res+=']'; + res += ']'; return res; } void relation_manager::display(std::ostream & out) const { - relation_map::iterator it=m_relations.begin(); - relation_map::iterator end=m_relations.end(); - for(;it!=end;++it) { - out << "Table " << it->m_key->get_name() << "\n"; - it->m_value->display(out); + for (auto const& kv : m_relations) { + out << "Table " << kv.m_key->get_name() << "\n"; + kv.m_value->display(out); } } void relation_manager::display_relation_sizes(std::ostream & out) const { - relation_map::iterator it=m_relations.begin(); - relation_map::iterator end=m_relations.end(); - for(;it!=end;++it) { - out << "Relation " << it->m_key->get_name() << " has size " - << it->m_value->get_size_estimate_rows() << "\n"; + for (auto const& kv : m_relations) { + out << "Relation " << kv.m_key->get_name() << " has size " + << kv.m_value->get_size_estimate_rows() << "\n"; } } void relation_manager::display_output_tables(rule_set const& rules, std::ostream & out) const { const decl_set & output_preds = rules.get_output_predicates(); - decl_set::iterator it=output_preds.begin(); - decl_set::iterator end=output_preds.end(); - for(; it!=end; ++it) { - func_decl * pred = *it; + for (func_decl * pred : output_preds) { relation_base * rel = try_get_relation(pred); if (!rel) { out << "Tuples in " << pred->get_name() << ": \n"; @@ -1016,11 +1001,8 @@ namespace datalog { SASSERT(plugin.can_handle_signature(res_sign)); table_base * res = plugin.mk_empty(res_sign); - table_base::iterator it = t.begin(); - table_base::iterator end = t.end(); - - for(; it!=end; ++it) { - it->get_fact(m_row); + for (table_base::row_interface& a : t) { + a.get_fact(m_row); modify_fact(m_row); res->add_fact(m_row); } @@ -1191,13 +1173,10 @@ namespace datalog { table_fact m_row; public: void operator()(table_base & tgt, const table_base & src, table_base * delta) override { - table_base::iterator it = src.begin(); - table_base::iterator iend = src.end(); + for (table_base::row_interface& a : src) { + a.get_fact(m_row); - for(; it!=iend; ++it) { - it->get_fact(m_row); - - if(delta) { + if (delta) { if(!tgt.contains_fact(m_row)) { tgt.add_new_fact(m_row); delta->add_fact(m_row); @@ -1260,11 +1239,9 @@ namespace datalog { void operator()(table_base & r) { m_to_remove.reset(); unsigned sz = 0; - table_base::iterator it = r.begin(); - table_base::iterator iend = r.end(); - for(; it!=iend; ++it) { - it->get_fact(m_row); - if(should_remove(m_row)) { + for (table_base::row_interface& a : r) { + a.get_fact(m_row); + if (should_remove(m_row)) { m_to_remove.append(m_row.size(), m_row.c_ptr()); ++sz; } @@ -1456,7 +1433,7 @@ namespace datalog { m_removed_cols(removed_col_cnt, removed_cols) {} table_base* operator()(const table_base & tb) override { - table_base *t2 = tb.clone(); + scoped_rel t2 = tb.clone(); (*m_filter)(*t2); if (!m_project) { relation_manager & rmgr = t2->get_plugin().get_manager(); @@ -1572,8 +1549,7 @@ namespace datalog { TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); scoped_rel aux = t1.clone(); (*m_filter)(*aux); - table_base * res = (*m_project)(*aux); - return res; + return (*m_project)(*aux); } }; @@ -1614,11 +1590,8 @@ namespace datalog { m_aux_table->reset(); } - - table_base::iterator it = t.begin(); - table_base::iterator iend = t.end(); - for(; it!=iend; ++it) { - it->get_fact(m_curr_fact); + for (table_base::row_interface& a : t) { + a.get_fact(m_curr_fact); if((*m_mapper)(m_curr_fact.c_ptr()+m_first_functional)) { m_aux_table->add_fact(m_curr_fact); } @@ -1699,13 +1672,10 @@ namespace datalog { SASSERT(plugin.can_handle_signature(res_sign)); table_base * res = plugin.mk_empty(res_sign); - table_base::iterator it = t.begin(); - table_base::iterator end = t.end(); - - - for(; it!=end; ++it) { + table_base::iterator it = t.begin(), end = t.end(); + for (; it != end; ++it) { mk_project(it); - if(!res->suggest_fact(m_former_row)) { + if (!res->suggest_fact(m_former_row)) { (*m_reducer)(m_former_row.c_ptr()+m_res_first_functional, m_row.c_ptr()+m_res_first_functional); res->ensure_fact(m_former_row); } From 5da07532691df81889c1ee6c8ac469560b618e1f Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 3 Aug 2017 19:49:50 -0400 Subject: [PATCH 0921/1283] (spacer) add instances even when a q-lemma already exists It is possible that a new instance of a quantified lemma is discovered even though a quantified lemma it already known. In this case, the instance should be added to a corresponding context, even though the lemma is not new. --- src/muz/spacer/spacer_context.cpp | 38 +++++++++++++++++++------------ src/muz/spacer/spacer_context.h | 5 ++-- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 7995f030c..4a61688f8 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -314,7 +314,8 @@ bool pred_transformer::propagate_to_next_level (unsigned src_level) /// \brief adds a lema to the solver and to child solvers -void pred_transformer::add_lemma_core(lemma* lemma) +void pred_transformer::add_lemma_core(lemma* lemma, + bool ground_only) { unsigned lvl = lemma->level(); expr* l = lemma->get_expr(); @@ -346,7 +347,8 @@ void pred_transformer::add_lemma_core(lemma* lemma) } for (unsigned i = 0, sz = m_use.size (); i < sz; ++i) - { m_use [i]->add_lemma_from_child(*this, lemma, next_level(lvl)); } + { m_use [i]->add_lemma_from_child(*this, lemma, + next_level(lvl), ground_only); } } bool pred_transformer::add_lemma (expr *e, unsigned lvl) { @@ -355,7 +357,8 @@ bool pred_transformer::add_lemma (expr *e, unsigned lvl) { } void pred_transformer::add_lemma_from_child (pred_transformer& child, - lemma* lemma, unsigned lvl) + lemma* lemma, unsigned lvl, + bool ground_only) { ensure_level(lvl); expr_ref_vector fmls(m); @@ -365,21 +368,25 @@ void pred_transformer::add_lemma_from_child (pred_transformer& child, expr_ref_vector inst(m); expr* a = to_app(fmls.get(i))->get_arg(0); expr* l = to_app(fmls.get(i))->get_arg(1); - if (get_context().use_instantiate()) - { lemma->mk_insts(inst, l); } + if (get_context().use_instantiate()) { + lemma->mk_insts(inst, l); + } for (unsigned j=0; j < inst.size(); j++) { inst.set(j, m.mk_implies(a, inst.get(j))); } - if (lemma->is_ground() || get_context().use_qlemmas()) - { inst.push_back(fmls.get(i)); } + if (lemma->is_ground() || (get_context().use_qlemmas() && !ground_only)) { + inst.push_back(fmls.get(i)); + } SASSERT (!inst.empty ()); for (unsigned j = 0; j < inst.size(); ++j) { TRACE("spacer_detail", tout << "child property: " << mk_pp(inst.get (j), m) << "\n";); - if (is_infty_level(lvl)) - { m_solver.assert_expr(inst.get(j)); } - else - { m_solver.assert_expr(inst.get(j), lvl); } + if (is_infty_level(lvl)) { + m_solver.assert_expr(inst.get(j)); + } + else { + m_solver.assert_expr(inst.get(j), lvl); + } } } @@ -1263,18 +1270,21 @@ bool pred_transformer::frames::add_lemma(lemma *lem) if (!lem->get_bindings().empty()) { m_lemmas [i]->add_binding(lem->get_bindings()); } - // if the lemma is at a higher level, skip it - // XXX if there are new bindings, we need to assert new instances + // if the lemma is at a higher level, skip it, + // but still assert any new instances if (m_lemmas [i]->level() >= lem->level()) { TRACE("spacer", tout << "Already at a higher level: " << pp_level(m_lemmas [i]->level()) << "\n";); + if (!lem->get_bindings().empty()) { + m_pt.add_lemma_core(m_lemmas[i], true); + } return false; } // update level of the existing lemma m_lemmas [i]->set_level(lem->level()); // assert lemma in the solver - m_pt.add_lemma_core(m_lemmas[i]); + m_pt.add_lemma_core(m_lemmas[i], false); // move the lemma to its new place to maintain sortedness for (unsigned j = i; (j + 1) < sz && m_lt(m_lemmas [j + 1], m_lemmas[j]); ++j) { m_lemmas.swap (j, j+1); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index a95b1bdb9..421d9e8c8 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -294,8 +294,9 @@ class pred_transformer { void init_sig(); void ensure_level(unsigned level); - void add_lemma_core (lemma *lemma); - void add_lemma_from_child (pred_transformer &child, lemma *lemma, unsigned lvl); + void add_lemma_core (lemma *lemma, bool ground_only = false); + void add_lemma_from_child (pred_transformer &child, lemma *lemma, + unsigned lvl, bool ground_only = false); void mk_assumptions(func_decl* head, expr* fml, expr_ref_vector& result); From 9f0eb367b17ca7082cb174ca660fee16b3028cdd Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 4 Aug 2017 16:12:32 -0400 Subject: [PATCH 0922/1283] ground lemmas during propagation when qlemmas are disabled When asserting quantified lemmas are disabled, ground a lemma explicitly during propagate to make sure that it is ground using our local set of skolem constants. --- src/muz/spacer/spacer_context.cpp | 2 +- src/muz/spacer/spacer_util.cpp | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 4a61688f8..1ab15ae34 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -769,7 +769,7 @@ bool pred_transformer::is_invariant(unsigned level, expr* lemma, expr_ref_vector conj(m), aux(m); expr_ref glemma(m); - if (false && is_quantifier(lemma)) { + if (!get_context().use_qlemmas() && is_quantifier(lemma)) { SASSERT(is_forall(lemma)); app_ref_vector tmp(m); ground_expr(to_quantifier(lemma)->get_expr (), glemma, tmp); diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 8b8da8a69..1156b2f9e 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -1166,21 +1166,21 @@ void mk_epp::rw(expr *e, expr_ref &out) arw(e, out); } - void ground_expr (expr *e, expr_ref &out, app_ref_vector &vars) - { - expr_free_vars fv; - ast_manager &m = out.get_manager (); - fv (e); - if (vars.size () < fv.size ()) - { vars.resize(fv.size()); } - for (unsigned i = 0, sz = fv.size (); i < sz; ++i) { - SASSERT (fv[i]); - std::string str = "zk!" + datalog::to_string(sz - 1 - i); - vars [i] = m.mk_const (symbol(str.c_str()), fv [i]); - } - var_subst vs(m); - vs (e, vars.size (), (expr**) vars.c_ptr (), out); +void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { + expr_free_vars fv; + ast_manager &m = out.get_manager(); + + fv(e); + if (vars.size() < fv.size()) { + vars.resize(fv.size()); } + for (unsigned i = 0, sz = fv.size(); i < sz; ++i) { + sort *s = fv[i] ? fv[i] : m.mk_bool_sort(); + vars[i] = mk_zk_const(m, i, s); + var_subst vs(m, false); + vs(e, vars.size(), (expr * *) vars.c_ptr(), out); + } +} struct index_term_finder { From 6cf68bee80461a88048146cdc02dd7123e38d6f2 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 7 Aug 2017 11:47:57 +0200 Subject: [PATCH 0923/1283] app ordering that puts special skolem constants first --- src/muz/spacer/spacer_manager.cpp | 22 ++++++++++++++++++++++ src/muz/spacer/spacer_manager.h | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index ba4ca0da7..d583813a8 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -384,4 +384,26 @@ bool has_zk_const(expr *e){ return false; } +bool is_zk_const (const app *a, int &n) { + if (!is_uninterp_const(a)) return false; + + const symbol &name = a->get_decl()->get_name(); + if (name.str().compare (0, 3, "sk!") != 0) { + return false; + } + + n = std::stoi(name.str().substr(3)); + return true; +} +bool sk_lt_proc::operator()(const app *a1, const app *a2) { + if (a1 == a2) return false; + int n1, n2; + bool z1, z2; + z1 = is_zk_const(a1, n1); + z2 = is_zk_const(a2, n2); + if (z1 && z2) return n1 < n2; + if (z1 != z2) return z1; + return ast_lt_proc()(a1, a2); +} + } diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index f2382c15d..f49aa63fc 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -341,6 +341,10 @@ public: app* mk_zk_const (ast_manager &m, unsigned idx, sort *s); void find_zk_const(expr* e, app_ref_vector &out); bool has_zk_const(expr* e); + +struct sk_lt_proc { + bool operator()(const app* a1, const app* a2); +}; } #endif From 1d478bd8d37719a2e22a2a50c5faa2c29bfdc3c1 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 7 Aug 2017 11:49:05 +0200 Subject: [PATCH 0924/1283] using sk_lt_proc order instead of ast_lt_proc when creating a lemma --- src/muz/spacer/spacer_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 1ab15ae34..6be4b78a3 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1787,7 +1787,7 @@ void pob::set_post(expr* post, app_ref_vector const &b) { m_binding.append(b); - std::sort (m_binding.c_ptr(), m_binding.c_ptr() + m_binding.size(), ast_lt_proc()); + std::sort (m_binding.c_ptr(), m_binding.c_ptr() + m_binding.size(), sk_lt_proc()); // skolemize implicit existential quantifier ast_manager &m = get_ast_manager(); From 6917aa3eb9accc51984edf76ca631ce0a4e01fef Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 7 Aug 2017 11:49:43 +0200 Subject: [PATCH 0925/1283] debug print --- src/muz/spacer/spacer_context.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 6be4b78a3..29cc39851 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -333,7 +333,18 @@ void pred_transformer::add_lemma_core(lemma* lemma, STRACE ("spacer.expand-add", tout << "add-lemma: " << pp_level (lvl) << " " << head ()->get_name () << " " - << mk_epp (l, m) << "\n\n";); + << mk_epp (l, m) << "\n"; + + if (!lemma->is_ground()) { + expr_ref_vector inst(m); + lemma->mk_insts(inst); + for (unsigned i = 0, sz = inst.size(); i < sz; ++i) { + tout << mk_epp(inst.get(i), m) << "\n"; + } + + } + tout << "\n"; + ); if (is_infty_level(lvl)) { m_stats.m_num_invariants++; } @@ -3046,6 +3057,8 @@ bool context::propagate(unsigned min_prop_lvl, if (m_params.pdr_simplify_formulas_pre()) { simplify_formulas(); } + STRACE ("spacer.expand-add", tout << "Propagating\n";); + IF_VERBOSE (1, verbose_stream () << "Propagating: " << std::flush;); for (unsigned lvl = min_prop_lvl; lvl <= full_prop_lvl; lvl++) { From e8befc072c9470a6c579567231a614f2051c32f1 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 7 Aug 2017 11:51:21 +0200 Subject: [PATCH 0926/1283] cleaned up lemma instantiation code --- src/muz/spacer/spacer_context.cpp | 54 ++++++++++++++++++++++++------- src/muz/spacer/spacer_context.h | 4 ++- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 29cc39851..7c4afa3f7 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1248,27 +1248,59 @@ void lemma::update_cube (pob_ref const &p, expr_ref_vector &cube) { if (m_cube.empty()) {m_cube.push_back(m.mk_true());} } -void lemma::mk_insts(expr_ref_vector &out, expr* e) -{ +bool lemma::has_binding(app_ref_vector const &binding) { + expr *lem = get_expr(); + unsigned num_decls = to_quantifier(lem)->get_num_decls(); + + SASSERT(bindings.size() == num_decls); + + for (unsigned off = 0, sz = m_bindings.size(); off < sz; off += num_decls) { + unsigned i = 0; + for (; i < num_decls; ++i) { + if (m_bindings.get(off + i) != binding.get(i)) { + break; + } + } + if (i == num_decls) return true; + } + return false; +} +void lemma::add_binding(app_ref_vector const &binding) { + if (!has_binding(binding)) { + m_bindings.append(binding); + + TRACE("spacer", + tout << "new binding: "; + for (unsigned i = 0; i < binding.size(); i++) + tout << mk_pp(binding.get(i), m) << " "; + tout << "\n";); + } +} +void lemma::instantiate(expr * const * exprs, expr_ref &result, expr *e) { expr *lem = e == nullptr ? get_expr() : e; if (!is_quantifier (lem) || m_bindings.empty()) {return;} expr *body = to_quantifier(lem)->get_expr(); unsigned num_decls = to_quantifier(lem)->get_num_decls(); - expr_ref inst(m); var_subst vs(m, false); - for (unsigned i = 0, - sz = m_bindings.size() / num_decls, - off = 0; - i < sz; - ++i, off += num_decls) { - inst.reset(); - vs.reset(); - vs(body, num_decls, (expr**) m_bindings.c_ptr() + off, inst); + vs(body, num_decls, exprs, result); +} + +void lemma::mk_insts(expr_ref_vector &out, expr* e) +{ + expr *lem = e == nullptr ? get_expr() : e; + if (!is_quantifier (lem) || m_bindings.empty()) {return;} + + unsigned num_decls = to_quantifier(lem)->get_num_decls(); + expr_ref inst(m); + for (unsigned off = 0, sz = m_bindings.size(); off < sz; off += num_decls) { + instantiate((expr * const *) m_bindings.c_ptr() + off, inst, e); out.push_back(inst); + inst.reset(); } } + bool pred_transformer::frames::add_lemma(lemma *lem) { TRACE("spacer", tout << "add-lemma: " << pp_level(lem->level()) << " " diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 421d9e8c8..a18855afe 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -135,7 +135,9 @@ public: unsigned level () const {return m_lvl;} void set_level (unsigned lvl) {m_lvl = lvl;} app_ref_vector& get_bindings() {return m_bindings;} - void add_binding(app_ref_vector const &binding) {m_bindings.append(binding);} + bool has_binding(app_ref_vector const &binding); + void add_binding(app_ref_vector const &binding); + void instantiate(expr * const * exprs, expr_ref &result, expr *e = nullptr); void mk_insts(expr_ref_vector& inst, expr* e = nullptr); bool is_ground () {return !is_quantifier (get_expr());} From 135a4a765fed0ccf7f391974e8303ee5751fd185 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 Aug 2017 17:23:55 -0400 Subject: [PATCH 0927/1283] Adding grounding of the current lemma In addition to adding the necessary instance of a quantified lemma, add its grounding over the global set of skolems. --- src/muz/spacer/spacer_context.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 7c4afa3f7..4968a44e4 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -379,8 +379,15 @@ void pred_transformer::add_lemma_from_child (pred_transformer& child, expr_ref_vector inst(m); expr* a = to_app(fmls.get(i))->get_arg(0); expr* l = to_app(fmls.get(i))->get_arg(1); - if (get_context().use_instantiate()) { + if (!lemma->is_ground() && get_context().use_instantiate()) { + expr_ref grnd_lemma(m); + app_ref_vector tmp(m); lemma->mk_insts(inst, l); + // -- take ground instance of the current lemma + ground_expr(to_quantifier(l)->get_expr(), grnd_lemma, tmp); + STRACE("spacer.expand-add", + tout << "Adding instance: " << mk_epp(grnd_lemma, m) << "\n";); + inst.push_back(grnd_lemma); } for (unsigned j=0; j < inst.size(); j++) { inst.set(j, m.mk_implies(a, inst.get(j))); From 27d8fa4a34468e4048ccdacd946311b6288d51b0 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 Aug 2017 17:18:09 -0400 Subject: [PATCH 0928/1283] hard-code quantifier weight to 15 With default settings, the eager threshold is 10 and lazy is 20. 15 puts us in the middle ensuring that lemmas are instantiated when UNSAT and otherwise delayed. --- src/muz/spacer/spacer_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 4968a44e4..ba4958d06 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1183,7 +1183,7 @@ void lemma::mk_expr_core() { m_body = m.mk_quantifier(true, zks.size(), sorts.c_ptr(), names.c_ptr(), - m_body, 0, symbol(m_body->get_id())); + m_body, 15, symbol(m_body->get_id())); if (m_new_pob) { add_binding(m_pob->get_binding()); } From 371ba4fbc0a06710d9946cec7c411077892be5c7 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 Aug 2017 17:50:47 -0400 Subject: [PATCH 0929/1283] added parameters that seem to work well with quantifiers and arith --- src/muz/spacer/spacer_context.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index ba4958d06..c42bfbbc3 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2212,6 +2212,19 @@ void context::init_lemma_generalizers(datalog::rule_set& rules) fparams.m_mbqi = m_params.spacer_mbqi(); + if (!m_params.spacer_ground_cti()) { + fparams.m_pi_use_database = true; + fparams.m_phase_selection = PS_CACHING_CONSERVATIVE2; + fparams.m_restart_strategy = RS_GEOMETRIC; + fparams.m_restart_factor = 1.5; + fparams.m_eliminate_bounds = true; + fparams.m_qi_quick_checker = MC_UNSAT; + fparams.m_propagate_booleans = true; + fparams.m_qi_eager_threshold = 10; + fparams.m_qi_lazy_threshold = 20; + fparams.m_ng_lift_ite = LI_FULL; + } + if (get_params().spacer_use_eqclass()) { m_lemma_generalizers.push_back (alloc(lemma_eq_generalizer, *this)); } From b8b3703511a1224cd681ff4362baf9b0e7fe3bb7 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 Aug 2017 17:51:54 -0400 Subject: [PATCH 0930/1283] improved implementation of is_qblocked() Disabled by default. Has no effect if ran with the default set of options where qlemmas=true and instantiate=true --- src/muz/spacer/spacer_context.cpp | 46 +++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index c42bfbbc3..12ab70351 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -51,6 +51,7 @@ Notes: #include "ast/rewriter/expr_safe_replace.h" #include "ast/expr_abstract.h" +#include "smt/smt_solver.h" namespace spacer { // ---------------- @@ -648,20 +649,44 @@ bool pred_transformer::is_blocked (pob &n, unsigned &uses_level) return res == l_false; } -bool pred_transformer::is_qblocked (pob &n) -{ - // XXX Trivial implementation to get us started - smt::kernel solver (m, get_manager ().fparams2()); + +bool pred_transformer::is_qblocked (pob &n) { + // XXX currently disabled + return false; + params_ref p; + p.set_bool("arith.ignore_int", true); + p.set_bool("array.weak", true); + p.set_bool("mbqi", false); + scoped_ptr s; + s = mk_smt_solver(m, p, symbol::null); + s->updt_params(p); + // XXX force parameters to be set + s->push(); + s->pop(1); + expr_ref_vector frame_lemmas(m); m_frames.get_frame_geq_lemmas (n.level (), frame_lemmas); // assert all lemmas + bool has_quant = false; for (unsigned i = 0, sz = frame_lemmas.size (); i < sz; ++i) - { solver.assert_expr(frame_lemmas.get(i)); } - // assert cti - solver.assert_expr (n.post ()); - lbool res = solver.check (); + { + has_quant = has_quant || is_quantifier(frame_lemmas.get(i)); + s->assert_expr(frame_lemmas.get(i)); + } + if (!has_quant) return false; + // assert cti + s->assert_expr(n.post()); + lbool res = s->check_sat(0, 0); + + // if (res == l_false) { + // expr_ref_vector core(m); + // solver->get_itp_core(core); + // expr_ref c(m); + // c = mk_and(core); + // STRACE("spacer.expand-add", tout << "core: " << mk_epp(c,m) << "\n";); + // } return res == l_false; } @@ -2939,6 +2964,11 @@ lbool context::expand_node(pob& n) return l_false; } + if (n.pt().is_qblocked(n)) { + STRACE("spacer.expand-add", + tout << "This pob can be blocked by instantiation\n";); + } + smt_params &fparams = m_pm.fparams(); flet _arith_ignore_int_(fparams.m_arith_ignore_int, m_weak_abs && n.weakness() < 1); From 68518b0e320b01f6bf22375675980a790fad65f0 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 Aug 2017 22:37:45 -0400 Subject: [PATCH 0931/1283] propagate weakness from pob down to all related checks If a pob was discharged with a weak solver, propagate the level of weakness to inductive generalization and to lemma propagation. --- src/muz/spacer/spacer_context.cpp | 36 ++++++++++++++------------ src/muz/spacer/spacer_context.h | 13 +++++++--- src/muz/spacer/spacer_generalizers.cpp | 13 +++++++--- src/muz/spacer/spacer_prop_solver.h | 15 +++++++++++ 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 12ab70351..772eca1e1 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -715,6 +715,8 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, // prepare the solver prop_solver::scoped_level _sl(m_solver, n.level()); prop_solver::scoped_subset_core _sc (m_solver, !n.use_farkas_generalizer ()); + prop_solver::scoped_weakness _sw(m_solver, 0, + ctx.weak_abs() ? n.weakness() : UINT_MAX); m_solver.set_core(core); m_solver.set_model(model); @@ -806,17 +808,20 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, return l_undef; } -bool pred_transformer::is_invariant(unsigned level, expr* lemma, +bool pred_transformer::is_invariant(unsigned level, lemma* lem, unsigned& solver_level, expr_ref_vector* core) { - expr_ref_vector conj(m), aux(m); - expr_ref glemma(m); + expr_ref lemma(m); + lemma = lem->get_expr(); - if (!get_context().use_qlemmas() && is_quantifier(lemma)) { - SASSERT(is_forall(lemma)); + expr_ref_vector conj(m), aux(m); + expr_ref gnd_lemma(m); + + + if (!get_context().use_qlemmas() && !lem->is_ground()) { app_ref_vector tmp(m); - ground_expr(to_quantifier(lemma)->get_expr (), glemma, tmp); - lemma = glemma.get(); + ground_expr(to_quantifier(lemma)->get_expr (), gnd_lemma, tmp); + lemma = gnd_lemma.get(); } conj.push_back(mk_not(m, lemma)); @@ -824,6 +829,8 @@ bool pred_transformer::is_invariant(unsigned level, expr* lemma, prop_solver::scoped_level _sl(m_solver, level); prop_solver::scoped_subset_core _sc (m_solver, true); + prop_solver::scoped_weakness _sw (m_solver, 1, + ctx.weak_abs() ? lem->weakness() : UINT_MAX); m_solver.set_core(core); m_solver.set_model(nullptr); expr * bg = m_extend_lit.get (); @@ -839,7 +846,7 @@ bool pred_transformer::is_invariant(unsigned level, expr* lemma, } bool pred_transformer::check_inductive(unsigned level, expr_ref_vector& state, - unsigned& uses_level) + unsigned& uses_level, unsigned weakness) { manager& pm = get_manager(); expr_ref_vector conj(m), core(m); @@ -848,6 +855,8 @@ bool pred_transformer::check_inductive(unsigned level, expr_ref_vector& state, mk_assumptions(head(), states, conj); prop_solver::scoped_level _sl(m_solver, level); prop_solver::scoped_subset_core _sc (m_solver, true); + prop_solver::scoped_weakness _sw (m_solver, 1, + ctx.weak_abs() ? weakness : UINT_MAX); m_solver.set_core(&core); m_solver.set_model (nullptr); expr_ref_vector aux (m); @@ -1412,10 +1421,9 @@ bool pred_transformer::frames::propagate_to_next_level (unsigned level) unsigned solver_level; - expr * curr = m_lemmas [i]->get_expr (); - if (m_pt.is_invariant(tgt_level, curr, solver_level)) { + if (m_pt.is_invariant(tgt_level, m_lemmas.get(i), solver_level)) { m_lemmas [i]->set_level (solver_level); - m_pt.add_lemma_core (m_lemmas [i]); + m_pt.add_lemma_core (m_lemmas.get(i)); // percolate the lemma up to its new place for (unsigned j = i; (j+1) < sz && m_lt (m_lemmas[j+1], m_lemmas[j]); ++j) { @@ -2969,12 +2977,6 @@ lbool context::expand_node(pob& n) tout << "This pob can be blocked by instantiation\n";); } - smt_params &fparams = m_pm.fparams(); - flet _arith_ignore_int_(fparams.m_arith_ignore_int, - m_weak_abs && n.weakness() < 1); - flet _array_weak_(fparams.m_array_weak, - m_weak_abs && n.weakness() < 2); - lbool res = n.pt ().is_reachable (n, &cube, &model, uses_level, is_concrete, r, reach_pred_used, num_reuse_reach); checkpoint (); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index a18855afe..61317e93b 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -131,6 +131,7 @@ public: bool has_pob() {return m_pob;} pob_ref &get_pob() {return m_pob;} + inline unsigned weakness(); unsigned level () const {return m_lvl;} void set_level (unsigned lvl) {m_lvl = lvl;} @@ -399,10 +400,15 @@ public: datalog::rule const*& r, vector& reach_pred_used, unsigned& num_reuse_reach); - bool is_invariant(unsigned level, expr* lemma, + bool is_invariant(unsigned level, lemma* lem, unsigned& solver_level, expr_ref_vector* core = nullptr); + + bool is_invariant(unsigned level, expr* lem, + unsigned& solver_level, expr_ref_vector* core = nullptr) + { UNREACHABLE();} + bool check_inductive(unsigned level, expr_ref_vector& state, - unsigned& assumes_level); + unsigned& assumes_level, unsigned weakness = UINT_MAX); expr_ref get_formulas(unsigned level, bool add_axioms); @@ -549,7 +555,7 @@ struct pob_ref_gt : {return gt (n1.get (), n2.get ());} }; - +inline unsigned lemma::weakness() {return m_pob ? m_pob->weakness() : UINT_MAX;} /** */ class derivation { @@ -774,6 +780,7 @@ public: bool use_native_mbp () {return m_use_native_mbp;} bool use_ground_cti () {return m_ground_cti;} bool use_instantiate () { return m_instantiate; } + bool weak_abs() {return m_weak_abs;} bool use_qlemmas () {return m_use_qlemmas; } ast_manager& get_ast_manager() const { return m; } diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 19989e440..e2058e93f 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -33,7 +33,8 @@ void lemma_sanity_checker::operator()(lemma_ref &lemma) { expr_ref_vector cube(lemma->get_ast_manager()); cube.append(lemma->get_cube()); ENSURE(lemma->get_pob()->pt().check_inductive(lemma->level(), - cube, uses_level)); + cube, uses_level, + lemma->weakness())); } @@ -58,6 +59,8 @@ void lemma_bool_inductive_generalizer::operator()(lemma_ref &lemma) { ptr_vector processed; expr_ref_vector extra_lits(m); + unsigned weakness = lemma->weakness(); + unsigned i = 0, num_failures = 0; while (i < cube.size() && (!m_failure_limit || num_failures < m_failure_limit)) { @@ -65,7 +68,7 @@ void lemma_bool_inductive_generalizer::operator()(lemma_ref &lemma) { lit = cube.get(i); cube[i] = true_expr; if (cube.size() > 1 && - pt.check_inductive(lemma->level(), cube, uses_level)) { + pt.check_inductive(lemma->level(), cube, uses_level, weakness)) { num_failures = 0; dirty = true; for (i = 0; i < cube.size() && @@ -82,7 +85,7 @@ void lemma_bool_inductive_generalizer::operator()(lemma_ref &lemma) { SASSERT(extra_lits.size() > 1); for (unsigned j = 0, sz = extra_lits.size(); !found && j < sz; ++j) { cube[i] = extra_lits.get(j); - if (pt.check_inductive(lemma->level(), cube, uses_level)) { + if (pt.check_inductive(lemma->level(), cube, uses_level, weakness)) { num_failures = 0; dirty = true; found = true; @@ -185,6 +188,8 @@ void lemma_array_eq_generalizer::operator() (lemma_ref &lemma) manager &pm = m_ctx.get_manager(); (void)pm; + unsigned weakness = lemma->weakness(); + expr_ref_vector core(m); expr_ref v(m); func_decl_set symb; @@ -264,7 +269,7 @@ void lemma_array_eq_generalizer::operator() (lemma_ref &lemma) pred_transformer &pt = lemma->get_pob()->pt(); // -- check if it is consistent with the transition relation unsigned uses_level1; - if (pt.check_inductive(lemma->level(), lits, uses_level1)) { + if (pt.check_inductive(lemma->level(), lits, uses_level1, weakness)) { TRACE("core_array_eq", tout << "Inductive!\n";); lemma->update_cube(lemma->get_pob(),lits); lemma->set_level(uses_level1); diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index 0cbcecfbf..c46063137 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -136,7 +136,22 @@ public: ~scoped_delta_level() {m_delta = false;} }; + class scoped_weakness { + smt_params &m_params; + bool m_arith_ignore_int; + bool m_array_weak; + public: + scoped_weakness(prop_solver &ps, unsigned solver_id, unsigned weakness) : + m_params(*ps.m_fparams[solver_id == 0 ? 0 : 0 /*1*/]) { + m_params.m_arith_ignore_int = weakness < 1; + m_params.m_array_weak = weakness < 2; + } + ~scoped_weakness() { + m_params.m_arith_ignore_int = m_arith_ignore_int; + m_params.m_array_weak = m_array_weak; + } + }; }; } From 890bc0f7c9f318852d2ec216418d8b93f968db79 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 6 Sep 2017 14:51:53 -0400 Subject: [PATCH 0932/1283] fix scoped_weakness forgot to save current state of params before resetting them --- src/muz/spacer/spacer_prop_solver.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index c46063137..e01dfba2e 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -144,6 +144,9 @@ public: public: scoped_weakness(prop_solver &ps, unsigned solver_id, unsigned weakness) : m_params(*ps.m_fparams[solver_id == 0 ? 0 : 0 /*1*/]) { + m_arith_ignore_int = m_params.m_arith_ignore_int; + m_array_weak = m_params.m_array_weak; + m_params.m_arith_ignore_int = weakness < 1; m_params.m_array_weak = weakness < 2; } From 321cad70d6854211f8acbd7d13d11feff9275be6 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 6 Sep 2017 17:39:13 -0400 Subject: [PATCH 0933/1283] improve comments for scoped_weakness --- src/muz/spacer/spacer_prop_solver.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index e01dfba2e..4aedb9676 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -144,9 +144,11 @@ public: public: scoped_weakness(prop_solver &ps, unsigned solver_id, unsigned weakness) : m_params(*ps.m_fparams[solver_id == 0 ? 0 : 0 /*1*/]) { + // save current values m_arith_ignore_int = m_params.m_arith_ignore_int; m_array_weak = m_params.m_array_weak; + // set values based on weakness score m_params.m_arith_ignore_int = weakness < 1; m_params.m_array_weak = weakness < 2; } From e7815c703cedc43e09d8b4f4375b6d86a0354c85 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 29 Sep 2017 16:19:48 -0400 Subject: [PATCH 0934/1283] Fix a typo --- src/muz/spacer/spacer_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 772eca1e1..81120cea2 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1293,7 +1293,7 @@ bool lemma::has_binding(app_ref_vector const &binding) { expr *lem = get_expr(); unsigned num_decls = to_quantifier(lem)->get_num_decls(); - SASSERT(bindings.size() == num_decls); + SASSERT(binding.size() == num_decls); for (unsigned off = 0, sz = m_bindings.size(); off < sz; off += num_decls) { unsigned i = 0; From 9b050e8d307888905ff74413e08dd1d56538577a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 29 Sep 2017 16:23:22 -0400 Subject: [PATCH 0935/1283] Fix benign warning --- src/muz/spacer/spacer_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 61317e93b..3dd26db9a 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -405,7 +405,7 @@ public: bool is_invariant(unsigned level, expr* lem, unsigned& solver_level, expr_ref_vector* core = nullptr) - { UNREACHABLE();} + { UNREACHABLE(); return false; } bool check_inductive(unsigned level, expr_ref_vector& state, unsigned& assumes_level, unsigned weakness = UINT_MAX); From 4148ee128cbe4cbbc4dd57ac05c4fc4887a7570c Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Thu, 12 Oct 2017 16:05:31 +0200 Subject: [PATCH 0936/1283] fixed bug, which added too many edges between super-source and source in the case where the source was used by multiple inferences --- src/muz/spacer/spacer_unsat_core_plugin.cpp | 18 ++++++++++++++---- src/muz/spacer/spacer_unsat_core_plugin.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index a1a937de0..0323fff0a 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -707,6 +707,8 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector j (only relevant if i is the supersource)) + if (!(i == nullptr && m_connected_to_s.is_marked(j))) + { + m_min_cut.add_edge(node_i, node_j, 1); + } + + if (i == nullptr) + { + m_connected_to_s.mark(j, true); + } } /* diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index 2ea4b4b51..6b679f3f2 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -108,6 +108,7 @@ private: void add_edge(proof* i, proof* j); vector m_node_to_formula; // maps each node to the corresponding formula in the original proof + ast_mark m_connected_to_s; // remember which nodes have already been connected to the supersource, in order to avoid multiple edges. min_cut m_min_cut; }; From 56fcb8e6fdb94e036d8a2654b96d2db50cb2b2f6 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Thu, 12 Oct 2017 16:36:11 +0200 Subject: [PATCH 0937/1283] added option fixedpoint.spacer.print_farkas_stats to print number of Farkas lemmas in each proof --- src/muz/base/fixedpoint_params.pyg | 1 + src/muz/spacer/spacer_itp_solver.cpp | 2 +- src/muz/spacer/spacer_itp_solver.h | 6 ++- src/muz/spacer/spacer_prop_solver.cpp | 2 +- src/muz/spacer/spacer_unsat_core_learner.cpp | 46 ++++++++++++++++++++ src/muz/spacer/spacer_unsat_core_learner.h | 4 +- 6 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 8d6c750d5..94c5a8989 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -187,6 +187,7 @@ def_module_params('fixedpoint', ('spacer.farkas_a_const', BOOL, True, 'if the unoptimized farkas plugin is used, use the constants from A while constructing unsat_cores'), ('spacer.lemma_sanity_check', BOOL, False, 'check during generalization whether lemma is actually correct'), ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), + ('spacer.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints') )) diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index 7ca66fbfd..cf481f179 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -274,7 +274,7 @@ void itp_solver::get_itp_core (expr_ref_vector &core) simplify_bounds (core); // XXX potentially redundant } else { // new code - unsat_core_learner learner(m); + unsat_core_learner learner(m,m_print_farkas_stats); if (m_farkas_optimized) { if (true) // TODO: proper options diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 466e0a2f1..4245332d2 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -62,6 +62,7 @@ private: bool m_minimize_unsat_core; bool m_farkas_optimized; bool m_farkas_a_const; + bool m_print_farkas_stats; bool is_proxy(expr *e, app_ref &def); void undo_proxies_in_core(ptr_vector &v); @@ -69,7 +70,7 @@ private: app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - itp_solver(solver &solver, bool new_unsat_core, bool minimize_unsat_core, bool farkas_optimized, bool farkas_a_const, bool split_literals = false) : + itp_solver(solver &solver, bool new_unsat_core, bool minimize_unsat_core, bool farkas_optimized, bool farkas_a_const, bool print_farkas_stats, bool split_literals = false) : m(solver.get_manager()), m_solver(solver), m_proxies(m), @@ -83,7 +84,8 @@ public: m_new_unsat_core(new_unsat_core), m_minimize_unsat_core(minimize_unsat_core), m_farkas_optimized(farkas_optimized), - m_farkas_a_const(farkas_a_const) + m_farkas_a_const(farkas_a_const), + m_print_farkas_stats(print_farkas_stats) {} ~itp_solver() override {} diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 059374e39..239e8d7f0 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -60,7 +60,7 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_solvers[1] = pm.mk_fresh2(); m_fparams[1] = &pm.fparams2(); - m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_optimized(), p.spacer_farkas_a_const(), p.spacer_split_farkas_literals()); + m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_optimized(), p.spacer_farkas_a_const(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_optimized(), p.spacer_farkas_a_const(), p.spacer_split_farkas_literals()); for (unsigned i = 0; i < 2; ++i) diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index f36143c5f..cf1eb979f 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -130,6 +130,52 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e // TODO: remove duplicates from unsat core? + // count both number of all Farkas lemmas and number of Farkas lemmas in the cut + if (m_print_farkas_stats) + { + unsigned farkas_counter = 0; + unsigned farkas_counter2 = 0; + + ProofIteratorPostOrder it3(root, m); + while (it3.hasNext()) + { + proof* currentNode = it3.next(); + + // if node is theory lemma + if (currentNode->get_decl_kind() == PR_TH_LEMMA) + { + func_decl* d = currentNode->get_decl(); + symbol sym; + // and theory lemma is Farkas lemma + if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas") + { + farkas_counter++; + + // check whether farkas lemma is to be interpolated (could potentially miss farkas lemmas, which are interpolated, because we potentially don't want to use the lowest cut) + bool has_no_mixed_parents = true; + for (int i = 0; i < m.get_num_parents(currentNode); ++i) + { + proof* premise = to_app(currentNode->get_arg(i)); + if (is_a_marked(premise) && is_b_marked(premise)) + { + has_no_mixed_parents = false; + } + } + if (has_no_mixed_parents && is_a_marked(currentNode) && is_b_marked(currentNode)) + { + farkas_counter2++; + } + + } + } + } + + verbose_stream() << "\nThis proof contains " << farkas_counter << " Farkas lemmas. " << farkas_counter2 << " Farkas lemmas participate in the lowest cut\n"; + } + + bool debug_proof = false; if(debug_proof) { diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 87238b5fd..2f04a9e06 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -31,7 +31,7 @@ namespace spacer { typedef obj_hashtable expr_set; public: - unsat_core_learner(ast_manager& m) : m(m), m_unsat_core(m) {}; + unsat_core_learner(ast_manager& m, bool print_farkas_stats = false) : m(m), m_unsat_core(m), m_print_farkas_stats(print_farkas_stats) {}; virtual ~unsat_core_learner(); ast_manager& m; @@ -100,6 +100,8 @@ namespace spacer { * finalize computation of unsat-core */ void finalize(); + + bool m_print_farkas_stats; }; } From fba995294d8b288643c09b3cb1a5f3fabbc48343 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Thu, 12 Oct 2017 17:01:30 +0200 Subject: [PATCH 0938/1283] refactored options regarding farkas lemma handling --- src/muz/base/fixedpoint_params.pyg | 3 +-- src/muz/spacer/spacer_itp_solver.cpp | 34 +++++++++++++++------------ src/muz/spacer/spacer_itp_solver.h | 8 +++---- src/muz/spacer/spacer_prop_solver.cpp | 4 ++-- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 94c5a8989..d1a23dcdd 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -183,8 +183,7 @@ def_module_params('fixedpoint', ('spacer.qlemmas', BOOL, True, 'allow quantified lemmas in frames'), ('spacer.new_unsat_core', BOOL, True, 'use the new implementation of unsat-core-generation'), ('spacer.minimize_unsat_core', BOOL, False, 'compute unsat-core by min-cut'), - ('spacer.farkas_optimized', BOOL, True, 'use the optimized farkas plugin, which performs gaussian elimination'), - ('spacer.farkas_a_const', BOOL, True, 'if the unoptimized farkas plugin is used, use the constants from A while constructing unsat_cores'), + ('spacer.farkas_plugin', UINT, 2, '0 = use unoptimized Farkas plugin, 1 = use unoptimized Farkas plugin with flipped polarity, 2 = use Gaussian elimination ideas, 3 = use additive IUC plugin'), ('spacer.lemma_sanity_check', BOOL, False, 'check during generalization whether lemma is actually correct'), ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), ('spacer.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index cf481f179..7af5c21fc 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -276,23 +276,27 @@ void itp_solver::get_itp_core (expr_ref_vector &core) // new code unsat_core_learner learner(m,m_print_farkas_stats); - if (m_farkas_optimized) { - if (true) // TODO: proper options - { - unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); - learner.register_plugin(plugin_farkas_lemma_optimized); - } - else - { - unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); - learner.register_plugin(plugin_farkas_lemma_bounded); - } - - } else { - unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, m_farkas_a_const); + if (m_farkas_plugin == 0 || m_farkas_plugin > 3) + { + unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, false); learner.register_plugin(plugin_farkas_lemma); } - + else if (m_farkas_plugin == 1) + { + unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, true); + learner.register_plugin(plugin_farkas_lemma); + } + else if (m_farkas_plugin == 2) + { + unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); + learner.register_plugin(plugin_farkas_lemma_optimized); + } + else if(m_farkas_plugin == 3) + { + unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); + learner.register_plugin(plugin_farkas_lemma_bounded); + } + if (m_minimize_unsat_core) { unsat_core_plugin_min_cut* plugin_min_cut = alloc(unsat_core_plugin_min_cut, learner, m); learner.register_plugin(plugin_min_cut); diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 4245332d2..719eb3f7c 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -60,8 +60,7 @@ private: bool m_split_literals; bool m_new_unsat_core; bool m_minimize_unsat_core; - bool m_farkas_optimized; - bool m_farkas_a_const; + unsigned m_farkas_plugin; bool m_print_farkas_stats; bool is_proxy(expr *e, app_ref &def); @@ -70,7 +69,7 @@ private: app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - itp_solver(solver &solver, bool new_unsat_core, bool minimize_unsat_core, bool farkas_optimized, bool farkas_a_const, bool print_farkas_stats, bool split_literals = false) : + itp_solver(solver &solver, bool new_unsat_core, bool minimize_unsat_core, unsigned farkas_plugin, bool print_farkas_stats, bool split_literals = false) : m(solver.get_manager()), m_solver(solver), m_proxies(m), @@ -83,8 +82,7 @@ public: m_split_literals(split_literals), m_new_unsat_core(new_unsat_core), m_minimize_unsat_core(minimize_unsat_core), - m_farkas_optimized(farkas_optimized), - m_farkas_a_const(farkas_a_const), + m_farkas_plugin(farkas_plugin), m_print_farkas_stats(print_farkas_stats) {} diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 239e8d7f0..1e44921f1 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -60,8 +60,8 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_solvers[1] = pm.mk_fresh2(); m_fparams[1] = &pm.fparams2(); - m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_optimized(), p.spacer_farkas_a_const(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); - m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_optimized(), p.spacer_farkas_a_const(), p.spacer_split_farkas_literals()); + m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_plugin(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); + m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_plugin(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); for (unsigned i = 0; i < 2; ++i) { m_contexts[i]->assert_expr(m_pm.get_background()); } From 00a99f01b4e0bba92c665584dc04e842f23b882f Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Thu, 12 Oct 2017 17:31:39 +0200 Subject: [PATCH 0939/1283] improved options for IUC computation --- src/muz/base/fixedpoint_params.pyg | 5 ++--- src/muz/spacer/spacer_itp_solver.cpp | 22 ++++++++++++++-------- src/muz/spacer/spacer_itp_solver.h | 12 +++++------- src/muz/spacer/spacer_prop_solver.cpp | 4 ++-- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index d1a23dcdd..a46d06245 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -181,9 +181,8 @@ def_module_params('fixedpoint', ('spacer.keep_proxy', BOOL, True, 'keep proxy variables (internal parameter)'), ('spacer.instantiate', BOOL, True, 'instantiate quantified lemmas'), ('spacer.qlemmas', BOOL, True, 'allow quantified lemmas in frames'), - ('spacer.new_unsat_core', BOOL, True, 'use the new implementation of unsat-core-generation'), - ('spacer.minimize_unsat_core', BOOL, False, 'compute unsat-core by min-cut'), - ('spacer.farkas_plugin', UINT, 2, '0 = use unoptimized Farkas plugin, 1 = use unoptimized Farkas plugin with flipped polarity, 2 = use Gaussian elimination ideas, 3 = use additive IUC plugin'), + ('spacer.iuc', UINT, 1, '0 = use old implementation of unsat-core-generation, 1 = use new implementation of IUC generation, 2 = use new implementation of IUC + min-cut optimization'), + ('spacer.iuc.arith', UINT, 2, '0 = use simple Farkas plugin, 1 = use simple Farkas plugin with constant from other partition (like old unsat-core-generation), 2 = use Gaussian elimination optimization, 3 = use additive IUC plugin'), ('spacer.lemma_sanity_check', BOOL, False, 'check during generalization whether lemma is actually correct'), ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), ('spacer.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index 7af5c21fc..c9bf3c443 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -264,7 +264,8 @@ void itp_solver::get_itp_core (expr_ref_vector &core) proof_ref pr(m); pr = get_proof (); - if (!m_new_unsat_core) { + if (m_iuc == 0) + { // old code farkas_learner learner_old; learner_old.set_split_literals(m_split_literals); @@ -272,35 +273,40 @@ void itp_solver::get_itp_core (expr_ref_vector &core) learner_old.get_lemmas (pr, B, core); elim_proxies (core); simplify_bounds (core); // XXX potentially redundant - } else { + } + else + { // new code unsat_core_learner learner(m,m_print_farkas_stats); - if (m_farkas_plugin == 0 || m_farkas_plugin > 3) + if (m_iuc_arith == 0 || m_iuc_arith > 3) { unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, false); learner.register_plugin(plugin_farkas_lemma); } - else if (m_farkas_plugin == 1) + else if (m_iuc_arith == 1) { unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, true); learner.register_plugin(plugin_farkas_lemma); } - else if (m_farkas_plugin == 2) + else if (m_iuc_arith == 2) { unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); learner.register_plugin(plugin_farkas_lemma_optimized); } - else if(m_farkas_plugin == 3) + else if(m_iuc_arith == 3) { unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); learner.register_plugin(plugin_farkas_lemma_bounded); } - if (m_minimize_unsat_core) { + if (m_iuc == 2) + { unsat_core_plugin_min_cut* plugin_min_cut = alloc(unsat_core_plugin_min_cut, learner, m); learner.register_plugin(plugin_min_cut); - } else { + } + else + { unsat_core_plugin_lemma* plugin_lemma = alloc(unsat_core_plugin_lemma, learner); learner.register_plugin(plugin_lemma); } diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 719eb3f7c..0b01f0032 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -58,9 +58,8 @@ private: expr_substitution m_elim_proxies_sub; bool m_split_literals; - bool m_new_unsat_core; - bool m_minimize_unsat_core; - unsigned m_farkas_plugin; + unsigned m_iuc; + unsigned m_iuc_arith; bool m_print_farkas_stats; bool is_proxy(expr *e, app_ref &def); @@ -69,7 +68,7 @@ private: app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - itp_solver(solver &solver, bool new_unsat_core, bool minimize_unsat_core, unsigned farkas_plugin, bool print_farkas_stats, bool split_literals = false) : + itp_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool split_literals = false) : m(solver.get_manager()), m_solver(solver), m_proxies(m), @@ -80,9 +79,8 @@ public: m_is_proxied(false), m_elim_proxies_sub(m, false, true), m_split_literals(split_literals), - m_new_unsat_core(new_unsat_core), - m_minimize_unsat_core(minimize_unsat_core), - m_farkas_plugin(farkas_plugin), + m_iuc(iuc), + m_iuc_arith(iuc_arith), m_print_farkas_stats(print_farkas_stats) {} diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 1e44921f1..cf981cfeb 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -60,8 +60,8 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_solvers[1] = pm.mk_fresh2(); m_fparams[1] = &pm.fparams2(); - m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_plugin(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); - m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_new_unsat_core(), p.spacer_minimize_unsat_core(), p.spacer_farkas_plugin(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); + m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); + m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); for (unsigned i = 0; i < 2; ++i) { m_contexts[i]->assert_expr(m_pm.get_background()); } From 5a37518e581ef1826efa6a31d06d7f4eda146965 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 18 Oct 2017 13:55:22 -0400 Subject: [PATCH 0940/1283] Improve statistics from spacer --- src/muz/spacer/spacer_context.cpp | 35 ++++++++++++++++++++++++++++--- src/muz/spacer/spacer_context.h | 1 + 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 81120cea2..8f4b63224 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -103,11 +103,20 @@ std::ostream& pred_transformer::display(std::ostream& out) const void pred_transformer::collect_statistics(statistics& st) const { m_solver.collect_statistics(st); - st.update("SPACER num propagations", m_stats.m_num_propagations); - st.update("SPACER num properties", m_frames.lemma_size ()); - st.update("SPACER num invariants", m_stats.m_num_invariants); + // -- number of times a lemma has been propagated to a higher level + // -- during push + st.update("SPACER num propagations", m_stats.m_num_propagations); + // -- number of lemmas in all current frames + st.update("SPACER num active lemmas", m_frames.lemma_size ()); + // -- number of lemmas that are inductive invariants + st.update("SPACER num invariants", m_stats.m_num_invariants); + // -- number of proof obligations (0 if pobs are not reused) + st.update("SPACER num pobs", m_pobs.size()); + + // -- time in rule initialization st.update ("time.spacer.init_rules.pt.init", m_initialize_watch.get_seconds ()); + // -- time is must_reachable() st.update ("time.spacer.solve.pt.must_reachable", m_must_reachable_watch.get_seconds ()); } @@ -1429,6 +1438,7 @@ bool pred_transformer::frames::propagate_to_next_level (unsigned level) for (unsigned j = i; (j+1) < sz && m_lt (m_lemmas[j+1], m_lemmas[j]); ++j) { m_lemmas.swap(j, j + 1); } + ++m_pt.m_stats.m_num_propagations; } else { all = false; ++i; @@ -3412,22 +3422,40 @@ void context::collect_statistics(statistics& st) const for (it = m_rels.begin(); it != end; ++it) { it->m_value->collect_statistics(st); } + + // -- number of times a pob for some predicate transformer has + // -- been created st.update("SPACER num queries", m_stats.m_num_queries); + // -- number of reach facts created st.update("SPACER num reach queries", m_stats.m_num_reach_queries); + // -- number of times a reach fact was true in some model st.update("SPACER num reuse reach facts", m_stats.m_num_reuse_reach); + // -- maximum level at which any query was asked st.update("SPACER max query lvl", m_stats.m_max_query_lvl); + // -- maximum depth st.update("SPACER max depth", m_stats.m_max_depth); + // -- level at which safe inductive invariant was found st.update("SPACER inductive level", m_inductive_lvl); + // -- length of the counterexample st.update("SPACER cex depth", m_stats.m_cex_depth); + // -- number of times expand_node resulted in undef st.update("SPACER expand node undef", m_stats.m_expand_node_undef); + // -- number of distinct lemmas constructed st.update("SPACER num lemmas", m_stats.m_num_lemmas); + // -- number of restarts taken st.update("SPACER restarts", m_stats.m_num_restarts); + // -- time to initialize the rules st.update ("time.spacer.init_rules", m_init_rules_watch.get_seconds ()); + // -- time in the main solve loop st.update ("time.spacer.solve", m_solve_watch.get_seconds ()); + // -- time in lemma propagation (i.e., pushing) st.update ("time.spacer.solve.propagate", m_propagate_watch.get_seconds ()); + // -- time in reachability (i.e., blocking) st.update ("time.spacer.solve.reach", m_reach_watch.get_seconds ()); + // -- time in deciding whether a pob is must-reachable st.update ("time.spacer.solve.reach.is-reach", m_is_reach_watch.get_seconds ()); + // -- time in creating new predecessors st.update ("time.spacer.solve.reach.children", m_create_children_watch.get_seconds ()); m_pm.collect_statistics(st); @@ -3439,6 +3467,7 @@ void context::collect_statistics(statistics& st) const // brunch out verbose_stream () << "BRUNCH_STAT max_query_lvl " << m_stats.m_max_query_lvl << "\n"; verbose_stream () << "BRUNCH_STAT num_queries " << m_stats.m_num_queries << "\n"; + verbose_stream () << "BRUNCH_STAT num_lemmas " << m_stats.m_num_lemmas << "\n"; verbose_stream () << "BRUNCH_STAT num_reach_queries " << m_stats.m_num_reach_queries << "\n"; verbose_stream () << "BRUNCH_STAT num_reach_reuse " << m_stats.m_num_reuse_reach << "\n"; verbose_stream () << "BRUNCH_STAT inductive_lvl " << m_inductive_lvl << "\n"; diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 3dd26db9a..181a55142 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -253,6 +253,7 @@ class pred_transformer { app_ref_vector b(m_pt.get_ast_manager()); return mk_pob (parent, level, depth, post, b); } + unsigned size() const {return m_pinned.size();} }; From 6818eb3340a9f99a17d46773b45013c206b6d2e4 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 22 Nov 2017 18:29:08 -0500 Subject: [PATCH 0941/1283] Improve factor equalities --- src/ast/factor_equivs.cpp | 55 ++++++++++++++++++++++++++++++++------- src/ast/factor_equivs.h | 7 +++++ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/ast/factor_equivs.cpp b/src/ast/factor_equivs.cpp index c33b3a18e..be402e628 100644 --- a/src/ast/factor_equivs.cpp +++ b/src/ast/factor_equivs.cpp @@ -27,7 +27,9 @@ Revision History: #include "ast/factor_equivs.h" #include "ast/arith_decl_plugin.h" - +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "ast/rewriter/expr_safe_replace.h" /** Factors input vector v into equivalence classes and the rest */ @@ -59,8 +61,8 @@ void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv) { equiv.merge(e1, e2); } else { - if (j < i) { - v[j] = v.get(i); + if (j < i) { + v[j] = v.get(i); } j++; } @@ -68,19 +70,52 @@ void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv) { v.shrink(j); } +/** + * Chooses a representative of an equivalence class + */ +expr *choose_rep(expr_equiv_class::eq_class &clazz, ast_manager &m) { + expr *rep = nullptr; + unsigned rep_sz, elem_sz; + for (expr *elem : clazz) { + if (!m.is_value(elem)) { + elem_sz = get_num_exprs(elem); + if (!rep || (rep && rep_sz > elem_sz)) { + rep = elem; + rep_sz = elem_sz; + } + } + } + TRACE("equiv", + tout << "Rep: " << mk_pp(rep, m) << "\n"; + for (expr *el : clazz) + tout << mk_pp(el, m) << "\n"; + tout << "RepEnd\n";); + + return rep; +} + +void rewrite_eqs (expr_ref_vector &v, expr_equiv_class &equiv) { + ast_manager &m = v.m(); + expr_safe_replace sub(m); + for (auto eq_class : equiv) { + expr *rep = choose_rep(eq_class, m); + for (expr *el : eq_class) { + if (el != rep) { + sub.insert (el, rep); + } + } + } + sub(v); +} + + /** * converts equivalence classes to equalities */ void equiv_to_expr(expr_equiv_class &equiv, expr_ref_vector &out) { ast_manager &m = out.get_manager(); for (auto eq_class : equiv) { - expr *rep = nullptr; - for (expr *elem : eq_class) { - if (!m.is_value(elem)) { - rep = elem; - break; - } - } + expr *rep = choose_rep(eq_class, m); SASSERT(rep); for (expr *elem : eq_class) { if (rep != elem) { diff --git a/src/ast/factor_equivs.h b/src/ast/factor_equivs.h index f0ce1608d..5d306bad8 100644 --- a/src/ast/factor_equivs.h +++ b/src/ast/factor_equivs.h @@ -60,6 +60,8 @@ public: obj_equiv_class(Manager& m) : m_to_obj(m) {} + Manager &m() const {return m_to_obj.m();} + void add_elem(OBJ*o) { SASSERT(!m_to_int.find(o)); add_elem_impl(o); @@ -169,6 +171,11 @@ typedef obj_equiv_class expr_equiv_class; * Factors input vector v into equivalence classes and the rest */ void factor_eqs(expr_ref_vector &v, expr_equiv_class &equiv); +/** + * Rewrite expressions in v by choosing a representative from the + * equivalence class. + */ +void rewrite_eqs(expr_ref_vector &v, expr_equiv_class &equiv); /** * converts equivalence classes to equalities */ From 880fc776559adbccc4ed48cc43c92b289903ccf8 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 22 Nov 2017 18:29:22 -0500 Subject: [PATCH 0942/1283] Further rewrite equalities --- src/muz/spacer/spacer_util.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 1156b2f9e..1d8a59d36 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -1065,6 +1065,7 @@ void normalize (expr *e, expr_ref &out, // equivalence classes expr_equiv_class eq_classes(out.m()); factor_eqs(v, eq_classes); + rewrite_eqs(v, eq_classes); equiv_to_expr(eq_classes, v); } From 370667722dd4bf3ff676aa200ac31a2c9c53e534 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Thu, 12 Oct 2017 16:36:11 +0200 Subject: [PATCH 0943/1283] New option fixedpoint.spacer.print_farkas_stats Prints the number of Farkas lemmas in each proof --- src/muz/spacer/spacer_itp_solver.cpp | 18 +++++++++--------- src/muz/spacer/spacer_itp_solver.h | 1 + 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index c9bf3c443..c2c5dbe0d 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -290,16 +290,16 @@ void itp_solver::get_itp_core (expr_ref_vector &core) learner.register_plugin(plugin_farkas_lemma); } else if (m_iuc_arith == 2) - { - unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); - learner.register_plugin(plugin_farkas_lemma_optimized); - } + { + unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); + learner.register_plugin(plugin_farkas_lemma_optimized); + } else if(m_iuc_arith == 3) - { - unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); - learner.register_plugin(plugin_farkas_lemma_bounded); - } - + { + unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); + learner.register_plugin(plugin_farkas_lemma_bounded); + } + if (m_iuc == 2) { unsat_core_plugin_min_cut* plugin_min_cut = alloc(unsat_core_plugin_min_cut, learner, m); diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 0b01f0032..d81a9764d 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -61,6 +61,7 @@ private: unsigned m_iuc; unsigned m_iuc_arith; bool m_print_farkas_stats; + bool m_print_farkas_stats; bool is_proxy(expr *e, app_ref &def); void undo_proxies_in_core(ptr_vector &v); From c3a66217e1c22b22ccc1a4f9ad98bc356bb3359d Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Thu, 12 Oct 2017 17:31:39 +0200 Subject: [PATCH 0944/1283] improved options for IUC computation --- src/muz/spacer/spacer_itp_solver.cpp | 18 +++++++++--------- src/muz/spacer/spacer_itp_solver.h | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index c2c5dbe0d..c9bf3c443 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -290,16 +290,16 @@ void itp_solver::get_itp_core (expr_ref_vector &core) learner.register_plugin(plugin_farkas_lemma); } else if (m_iuc_arith == 2) - { - unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); - learner.register_plugin(plugin_farkas_lemma_optimized); - } + { + unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); + learner.register_plugin(plugin_farkas_lemma_optimized); + } else if(m_iuc_arith == 3) - { - unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); - learner.register_plugin(plugin_farkas_lemma_bounded); - } - + { + unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); + learner.register_plugin(plugin_farkas_lemma_bounded); + } + if (m_iuc == 2) { unsat_core_plugin_min_cut* plugin_min_cut = alloc(unsat_core_plugin_min_cut, learner, m); diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index d81a9764d..0b01f0032 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -61,7 +61,6 @@ private: unsigned m_iuc; unsigned m_iuc_arith; bool m_print_farkas_stats; - bool m_print_farkas_stats; bool is_proxy(expr *e, app_ref &def); void undo_proxies_in_core(ptr_vector &v); From 25fad153d11736393c4c5baa80854622dd1139a3 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Mon, 23 Oct 2017 15:39:59 +0200 Subject: [PATCH 0945/1283] added option fixedpoint.spacer.iuc.debug_proof to debug proof which is used for generation of iuc --- src/muz/base/fixedpoint_params.pyg | 1 + src/muz/spacer/spacer_itp_solver.cpp | 2 +- src/muz/spacer/spacer_itp_solver.h | 7 ++-- src/muz/spacer/spacer_prop_solver.cpp | 4 +-- src/muz/spacer/spacer_unsat_core_learner.cpp | 35 +++++++++++++++----- src/muz/spacer/spacer_unsat_core_learner.h | 3 +- 6 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index a46d06245..f0f4e0881 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -186,6 +186,7 @@ def_module_params('fixedpoint', ('spacer.lemma_sanity_check', BOOL, False, 'check during generalization whether lemma is actually correct'), ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), ('spacer.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), + ('spacer.iuc.debug_proof', BOOL, False, 'prints proof used by unsat-core-learner for debugging purposes'), ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints') )) diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index c9bf3c443..9cccdf43c 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -277,7 +277,7 @@ void itp_solver::get_itp_core (expr_ref_vector &core) else { // new code - unsat_core_learner learner(m,m_print_farkas_stats); + unsat_core_learner learner(m, m_print_farkas_stats, m_iuc_debug_proof); if (m_iuc_arith == 0 || m_iuc_arith > 3) { diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 0b01f0032..5e5c2d39e 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -61,14 +61,14 @@ private: unsigned m_iuc; unsigned m_iuc_arith; bool m_print_farkas_stats; - + bool m_iuc_debug_proof; bool is_proxy(expr *e, app_ref &def); void undo_proxies_in_core(ptr_vector &v); app* mk_proxy(expr *v); app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - itp_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool split_literals = false) : + itp_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool iuc_debug_proof, bool split_literals = false) : m(solver.get_manager()), m_solver(solver), m_proxies(m), @@ -81,7 +81,8 @@ public: m_split_literals(split_literals), m_iuc(iuc), m_iuc_arith(iuc_arith), - m_print_farkas_stats(print_farkas_stats) + m_print_farkas_stats(print_farkas_stats), + m_iuc_debug_proof(iuc_debug_proof) {} ~itp_solver() override {} diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index cf981cfeb..60deac214 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -60,8 +60,8 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_solvers[1] = pm.mk_fresh2(); m_fparams[1] = &pm.fparams2(); - m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); - m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_split_farkas_literals()); + m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_iuc_debug_proof(), p.spacer_split_farkas_literals()); + m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_iuc_debug_proof(), p.spacer_split_farkas_literals()); for (unsigned i = 0; i < 2; ++i) { m_contexts[i]->assert_expr(m_pm.get_background()); } diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index cf1eb979f..4adf67209 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -174,13 +174,11 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e verbose_stream() << "\nThis proof contains " << farkas_counter << " Farkas lemmas. " << farkas_counter2 << " Farkas lemmas participate in the lowest cut\n"; } - - bool debug_proof = false; - if(debug_proof) + if(m_iuc_debug_proof) { // print proof for debugging - verbose_stream() << "\n\nProof:\n"; + verbose_stream() << "Proof:\n"; std::unordered_map id_to_small_id; unsigned counter = 0; @@ -223,8 +221,23 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e verbose_stream() << "hypothesis"; break; default: - verbose_stream() << "unknown axiom-type"; - break; + if (currentNode->get_decl_kind() == PR_TH_LEMMA) + { + verbose_stream() << "th_axiom"; + func_decl* d = currentNode->get_decl(); + symbol sym; + if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas") + { + verbose_stream() << "(farkas)"; + } + } + else + { + verbose_stream() << "unknown axiom-type"; + break; + } } } else @@ -269,17 +282,21 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e } } - if (currentNode->get_decl_kind() == PR_TH_LEMMA || (is_a_marked(currentNode) && is_b_marked(currentNode)) || is_h_marked(currentNode) || (!is_a_marked(currentNode) && !is_b_marked(currentNode))) +// if (currentNode->get_decl_kind() == PR_TH_LEMMA || (is_a_marked(currentNode) && is_b_marked(currentNode)) || is_h_marked(currentNode) || (!is_a_marked(currentNode) && !is_b_marked(currentNode))) + if (false) { - verbose_stream() << std::endl; + verbose_stream() << "\n"; } else { - verbose_stream() << ": " << mk_pp(m.get_fact(currentNode), m) << std::endl; + verbose_stream() << ": " << mk_pp(m.get_fact(currentNode), m) << "\n"; } ++counter; } } + + verbose_stream() << std::endl; + // move all lemmas into vector for (expr* const* it = m_unsat_core.begin(); it != m_unsat_core.end(); ++it) { diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 2f04a9e06..4b5ca981d 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -31,7 +31,7 @@ namespace spacer { typedef obj_hashtable expr_set; public: - unsat_core_learner(ast_manager& m, bool print_farkas_stats = false) : m(m), m_unsat_core(m), m_print_farkas_stats(print_farkas_stats) {}; + unsat_core_learner(ast_manager& m, bool print_farkas_stats = false, bool iuc_debug_proof = false) : m(m), m_unsat_core(m), m_print_farkas_stats(print_farkas_stats), m_iuc_debug_proof(iuc_debug_proof) {}; virtual ~unsat_core_learner(); ast_manager& m; @@ -102,6 +102,7 @@ namespace spacer { void finalize(); bool m_print_farkas_stats; + bool m_iuc_debug_proof; }; } From 088bd3ed8ecdf385f3ac8f0eb4fd05f844128c87 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 12 Oct 2017 12:40:42 -0400 Subject: [PATCH 0946/1283] Fix compiler warning --- src/muz/spacer/spacer_unsat_core_learner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index 4adf67209..12b2a5614 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -155,7 +155,7 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e // check whether farkas lemma is to be interpolated (could potentially miss farkas lemmas, which are interpolated, because we potentially don't want to use the lowest cut) bool has_no_mixed_parents = true; - for (int i = 0; i < m.get_num_parents(currentNode); ++i) + for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) { proof* premise = to_app(currentNode->get_arg(i)); if (is_a_marked(premise) && is_b_marked(premise)) @@ -267,11 +267,11 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e verbose_stream() << "step"; } verbose_stream() << " from "; - for (int i = m.get_num_parents(currentNode) - 1; i >= 0 ; --i) + for (unsigned i = m.get_num_parents(currentNode); i > 0 ; --i) { proof* premise = to_app(currentNode->get_arg(i)); unsigned premise_small_id = id_to_small_id[premise->get_id()]; - if (i > 0) + if (i > 1) { verbose_stream() << premise_small_id << ", "; } From 6407ec872533a2787744243e867a3d3581762837 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 12 Dec 2017 22:13:58 -0500 Subject: [PATCH 0947/1283] spacer_term_graph: an egraph of terms Used to determine and factor out equalities --- src/muz/spacer/CMakeLists.txt | 1 + src/muz/spacer/spacer_term_graph.cpp | 449 +++++++++++++++++++++++++++ src/muz/spacer/spacer_term_graph.h | 91 ++++++ 3 files changed, 541 insertions(+) create mode 100644 src/muz/spacer/spacer_term_graph.cpp create mode 100644 src/muz/spacer/spacer_term_graph.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 37bc7f352..f27f6e726 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -20,6 +20,7 @@ z3_add_component(spacer spacer_antiunify.cpp spacer_mev_array.cpp spacer_qe_project.cpp + spacer_term_graph.cpp COMPONENT_DEPENDENCIES arith_tactics core_tactics diff --git a/src/muz/spacer/spacer_term_graph.cpp b/src/muz/spacer/spacer_term_graph.cpp new file mode 100644 index 000000000..c34022d48 --- /dev/null +++ b/src/muz/spacer/spacer_term_graph.cpp @@ -0,0 +1,449 @@ +#include "muz/spacer/spacer_term_graph.h" +#include "util/util.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/for_each_expr.h" + +namespace spacer { + +class term { + // -- an app represented by this term + app* m_app; + // -- root of the equivalence class + term* m_root; + // -- next element in the equivalence class (cyclic linked list) + term* m_next; + // -- eq class size + unsigned m_class_size; + + // -- general purpose mark + unsigned m_mark:1; + // -- general purpose second mark + unsigned m_mark2:1; + // -- is an interpreted constant + unsigned m_interpreted:1; + + // -- terms that contain this term as a child + //ptr_vector m_uses; + + // ptr_vector m_args; + +public: + term(app* a) : m_app(a), m_root(this), m_next(this), + m_class_size(1), m_mark(false), m_mark2(false), + m_interpreted(false) {} + + ~term() {} + + unsigned get_id() const {return m_app->get_id();} + + bool is_marked() const {return m_mark;} + void set_mark(bool v){m_mark = v;} + bool is_marked2() const {return m_mark2;} + void set_mark2(bool v){m_mark2 = v;} + + bool is_interpreted() const {return m_interpreted;} + void mark_as_interpreted() {m_interpreted=true;} + app* get_app() const {return m_app;} + + term &get_root() const {return *m_root;} + bool is_root() const {return m_root == this;} + void set_root(term &r) {m_root = &r;} + term &get_next() const {return *m_next;} + + unsigned get_class_size() const {return m_class_size;} + + void merge_eq_class(term &b) { + std::swap(this->m_next, b.m_next); + m_class_size += b.get_class_size(); + // -- reset (useful for debugging) + b.m_class_size = 0; + } + + // -- make this term the root of its equivalence class + void mk_root() { + if (is_root()) return; + + term *curr = this; + do { + if (curr->is_root()) { + // found previous root + SASSERT(curr != this); + m_class_size = curr->get_class_size(); + curr->m_class_size = 0; + } + curr->set_root(*this); + curr = &curr->get_next(); + } + while (curr != this); + } +}; + +class arith_term_graph_plugin : public term_graph_plugin { + term_graph &m_g; + ast_manager &m; + arith_util m_arith; + +public: + arith_term_graph_plugin(term_graph &g) : + term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), + m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} + + virtual ~arith_term_graph_plugin() {} + + bool mk_eq_core (expr *_e1, expr *_e2, app* &res) { + expr *e1, *e2; + e1 = _e1; + e2 = _e2; + + if (m_arith.is_zero(e1)) { + std::swap(e1, e2); + } + // y + -1*x == 0 --> y = x + expr *a0 = 0, *a1 = 0, *x = 0; + if (m_arith.is_zero(e2) && m_arith.is_add(e1, a0, a1)) { + if (m_arith.is_times_minus_one(a1, x)) { + e1 = a0; + e2 = x; + } + else if (m_arith.is_times_minus_one(a0, x)) { + e1 = a1; + e2 = x; + } + } + res = m.mk_eq(e1, e2); + return true; + } + + bool mk_le_core (expr *arg1, expr * arg2, app* &result) { + // t <= -1 ==> t < 0 ==> ! (t >= 0) + if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { + result = m.mk_not (m_arith.mk_ge (arg1, mk_zero ())); + return true; + } + return false; + } + + expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} + bool is_one (expr const * n) const { + rational val; + return m_arith.is_numeral (n, val) && val.is_one (); + } + + bool mk_ge_core (expr * arg1, expr * arg2, app* &result) { + // t >= 1 ==> t > 0 ==> ! (t <= 0) + if (m_arith.is_int (arg1) && is_one (arg2)) { + result = m.mk_not (m_arith.mk_le (arg1, mk_zero ())); + return true; + } + return false; + } + + virtual app* process_lit (app *lit) { + expr *e1, *e2; + + + app *res = lit; + if (m.is_eq (lit, e1, e2)) { + mk_eq_core(e1, e2, res); + } + else if (m_arith.is_le(lit, e1, e2)) { + mk_le_core(e1, e2, res); + } + else if (m_arith.is_ge(lit, e1, e2)) { + mk_ge_core(e1, e2, res); + } + return res; + } +}; + +term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { + m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); +} +term_graph::~term_graph() { + std::for_each(m_terms.begin(), m_terms.end(), delete_proc()); +} + +static family_id get_family_id(ast_manager &m, app *lit) { + family_id fid = null_family_id; + + expr *e1, *e2, *e3; + // strip negation + if (!m.is_not (lit, e1)) { e1 = lit; } + + // deal with equality using sort of range + if (m.is_eq (e1, e2, e3)) { + fid = get_sort (e2)->get_family_id(); + } + // extract family_id of top level app + else { + fid = to_app(e1)->get_decl()->get_family_id(); + } + + return fid; +} + +void term_graph::add_lit(app *l) { + app_ref lit(m); + + family_id fid = get_family_id (m, l); + term_graph_plugin *pin = m_plugins.get_plugin(fid); + if (pin) { + lit = pin->process_lit(l); + } else { + lit = l; + } + m_lits.push_back(lit); + internalize_lit(lit); +} + +bool term_graph::is_internalized(app *a) { + return m_app2term.contains(a->get_id()); +} + +term* term_graph::get_term(app *a) { + term *res; + return m_app2term.find (a->get_id(), res) ? res : nullptr; +} + +term *term_graph::mk_term(app *a) { + term *t; + t = alloc(term, a); + if (a->get_num_args() == 0 && m.is_unique_value(a)){ + t->mark_as_interpreted(); + } + + m_terms.push_back(t); + m_app2term.insert(a->get_id(), t); + return t; +} + +term *term_graph::internalize_term(app *t) { + term *res = get_term(t); + + if (!res) { + for (unsigned i=0, sz=t->get_num_args(); i < sz; ++i) { + expr *arg = t->get_arg(i); + SASSERT(is_app(arg)); + internalize_term(::to_app(arg)); + } + res = mk_term(t); + } + return res; +} + +void term_graph::internalize_eq(app *a1, app* a2) { + internalize_lit(a1); + internalize_lit(a2); + + term *t1, *t2; + t1 = get_term(a1); + t2 = get_term(a2); + SASSERT(t1); + SASSERT(t2); + + merge(t1->get_root(), t2->get_root()); +} + +void term_graph::internalize_lit(app* lit) { + if (is_internalized(lit)) return; + + expr *e1, *e2; + if (m.is_eq (lit, e1, e2)) { + SASSERT(is_app(e1)); + SASSERT(is_app(e2)); + internalize_eq (::to_app(e1), ::to_app(e2)); + } + else { + internalize_term(lit); + } +} + +void term_graph::merge (term &t1, term &t2) { + SASSERT(t1.is_root()); + SASSERT(t2.is_root()); + + if (&t1 == &t2) return; + + term *a = &t1; + term *b = &t2; + if (a->get_class_size() > b->get_class_size()) { + std::swap(a, b); + } + + // make 'a' be the root of the equivalence class of 'b' + b->set_root(*a); + for (term *it = &b->get_next(); it != b; it = &it->get_next()) { + it->set_root(*a); + } + + // merge equivalence classes + a->merge_eq_class(*b); + + // -- merge might have invalidated term2map cache + m_term2app.reset(); + m_pinned.reset(); +} + +app* term_graph::mk_app_core (app *a) { + expr_ref_vector kids(m); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + kids.push_back (mk_app(::to_app(a->get_arg(i)))); + } + + app* res = m.mk_app(a->get_decl(), kids.c_ptr()); + m_pinned.push_back(res); + + return res; +} + +app_ref term_graph::mk_app(term const &r) { + SASSERT(r.is_root()); + + if (r.get_app()->get_num_args() == 0) { + return app_ref(r.get_app(), m); + } + + app* res; + if (m_term2app.find(r.get_id(), res)) { + return app_ref(res, m); + } + + res = mk_app_core (r.get_app()); + m_term2app.insert(r.get_id(), res); + return app_ref(res, m); + +} +app_ref term_graph::mk_app(app *a) { + term *t = get_term(a); + if (!t) {return app_ref(a, m);} + + term &r = t->get_root(); + return mk_app(r); + +} + +void term_graph::mk_equalities(term const &t, app_ref_vector &out) { + SASSERT(t.is_root()); + app_ref rep(m); + rep = mk_app(t); + + for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { + app* mem; + mem = mk_app_core(it->get_app()); + out.push_back (m.mk_eq (rep, mem)); + } +} + +void term_graph::mk_all_equalities(term const &t, app_ref_vector &out) { + mk_equalities(t, out); + + for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { + app* a1; + a1 = mk_app_core (it->get_app()); + for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { + app *a2; + a2 = mk_app_core(it2->get_app()); + out.push_back (m.mk_eq (a1, a2)); + } + } +} + +void term_graph::reset_marks() { + for (unsigned i = 0, sz = m_terms.size(); i < sz; ++i) { + term *t = m_terms.get(i); + t->set_mark(false); + } +} + +/// Order of preference for roots of equivalence classes +/// XXX This should be factored out to let clients control the preference +bool term_graph::term_le(term const &t1, term const &t2) { + + // prefer constants over applications + // prefer uninterpreted constants over values + // prefer smaller expressions over larger ones + app *a1, *a2; + a1 = t1.get_app(); + a2 = t2.get_app(); + if (a1->get_num_args() == 0 && a2->get_num_args() > 0) { + return true; + } + if (a1->get_num_args() == a2->get_num_args()) { + return m.is_value(a2); + } + + unsigned sz1 = get_num_exprs(a1); + unsigned sz2 = get_num_exprs(a2); + return sz1 < sz2; +} + +void term_graph::pick_root (term &t) { + term *r = &t; + for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { + it->set_mark(true); + if (term_le(*it, *r)) { r = it; } + } + + // -- if found something better, make it the new root + if (r != &t) { + r->mk_root(); + } +} +/// Choose better roots for equivalence classes +void term_graph::pick_roots() { + for (unsigned i = 0, sz = m_terms.size(); i < sz; ++i) { + term *t = m_terms.get(i); + if (t->is_marked() || !t->is_root()) {continue;} + pick_root(*t); + } + reset_marks(); +} + +void term_graph::display(std::ostream &out) { + for (unsigned i = 0, sz = m_terms.size(); i < sz; ++i) { + term *t = m_terms.get(i); + out << mk_pp(t->get_app(), m) << " is root " << t->is_root() + << " cls sz " << t->get_class_size() + << " term " << t + << "\n"; + } +} +void term_graph::to_lits (app_ref_vector &lits, bool all_equalities) { + pick_roots(); + + for (unsigned i = 0, sz = m_lits.size(); i < sz; ++i) { + app *a = m_lits.get(i); + if (is_internalized(a)) { + lits.push_back (mk_app(a)); + } + } + + for (unsigned i = 0, sz = m_terms.size(); i < sz; ++i) { + term *t = m_terms.get(i); + if (!t->is_root()) {continue;} + + if (all_equalities) { + mk_all_equalities (*t, lits); + } else { + mk_equalities(*t, lits); + } + } + +} + +app_ref term_graph::to_app() { + app_ref_vector lits(m); + to_lits(lits); + return mk_and(lits); +} + +void term_graph::reset() { + m_term2app.reset(); + m_pinned.reset(); + m_app2term.reset(); + m_terms.reset(); + m_lits.reset(); +} + +} diff --git a/src/muz/spacer/spacer_term_graph.h b/src/muz/spacer/spacer_term_graph.h new file mode 100644 index 000000000..6e5ea9a6a --- /dev/null +++ b/src/muz/spacer/spacer_term_graph.h @@ -0,0 +1,91 @@ +/**++ +Copyright (c) Arie Gurfinkel + +Module Name: + + spacer_term_graph.h + +Abstract: + + Equivalence graph of terms + +Author: + + Arie Gurfinkel + +Notes: + +--*/ +#ifndef _SPACER_TERM_GRAPH_H_ +#define _SPACER_TERM_GRAPH_H_ + +#include "ast/ast.h" + +#include "util/plugin_manager.h" + +namespace spacer { + +class term; + +class term_graph_plugin { + family_id m_id; +public: + term_graph_plugin(family_id fid) : m_id(fid) {} + virtual ~term_graph_plugin() {} + + family_id get_family_id() const {return m_id;} + + /// Process (and potentially augment) a literal + virtual app* process_lit (app *lit) {return lit;} +}; + +class term_graph { + ast_manager &m; + ptr_vector m_terms; + app_ref_vector m_lits; + u_map m_app2term; + + app_ref_vector m_pinned; + u_map m_term2app; + + plugin_manager m_plugins; + + void merge(term &t1, term &t2); + + term *mk_term(app *t); + term *get_term(app *t); + + term *internalize_term(app *t); + void internalize_eq(app *a1, app *a2); + void internalize_lit(app *lit); + + bool is_internalized(app *a); + + bool term_le(term const &t1, term const &t2); + void pick_root (term &t); + void pick_roots(); + + void reset_marks(); + + app *mk_app_core(app* a); + app_ref mk_app(term const &t); + app_ref mk_app(app *a); + void mk_equalities(term const &t, app_ref_vector &out); + void mk_all_equalities(term const &t, app_ref_vector &out); + void display(std::ostream &out); +public: + term_graph(ast_manager &man); + ~term_graph(); + + ast_manager &get_ast_manager() const {return m;} + + void add_lit(app *lit); + + void reset(); + void to_lits (app_ref_vector &lits, bool all_equalities = false); + app_ref to_app(); + +}; + +} +#endif From be77b1de394ea45e781477181ffc4e5cc70a21df Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Dec 2017 16:24:33 -0500 Subject: [PATCH 0948/1283] Improve interface of term_graph --- src/muz/spacer/spacer_term_graph.cpp | 19 +++++++++++++------ src/muz/spacer/spacer_term_graph.h | 10 ++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/muz/spacer/spacer_term_graph.cpp b/src/muz/spacer/spacer_term_graph.cpp index c34022d48..61f7fb369 100644 --- a/src/muz/spacer/spacer_term_graph.cpp +++ b/src/muz/spacer/spacer_term_graph.cpp @@ -91,7 +91,7 @@ public: virtual ~arith_term_graph_plugin() {} - bool mk_eq_core (expr *_e1, expr *_e2, app* &res) { + bool mk_eq_core (expr *_e1, expr *_e2, app_ref &res) { expr *e1, *e2; e1 = _e1; e2 = _e2; @@ -115,7 +115,7 @@ public: return true; } - bool mk_le_core (expr *arg1, expr * arg2, app* &result) { + bool mk_le_core (expr *arg1, expr * arg2, app_ref &result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { result = m.mk_not (m_arith.mk_ge (arg1, mk_zero ())); @@ -130,7 +130,7 @@ public: return m_arith.is_numeral (n, val) && val.is_one (); } - bool mk_ge_core (expr * arg1, expr * arg2, app* &result) { + bool mk_ge_core (expr * arg1, expr * arg2, app_ref &result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) if (m_arith.is_int (arg1) && is_one (arg2)) { result = m.mk_not (m_arith.mk_le (arg1, mk_zero ())); @@ -139,11 +139,12 @@ public: return false; } - virtual app* process_lit (app *lit) { + virtual app_ref process_lit (app *lit) { expr *e1, *e2; - app *res = lit; + app_ref res(m); + res = lit; if (m.is_eq (lit, e1, e2)) { mk_eq_core(e1, e2, res); } @@ -429,7 +430,13 @@ void term_graph::to_lits (app_ref_vector &lits, bool all_equalities) { mk_equalities(*t, lits); } } - +} +void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { + app_ref_vector out(m); + to_lits (out, all_equalities); + for (unsigned i = 0, sz = out.size(); i < sz; ++i) { + lits.push_back(out.get(i)); + } } app_ref term_graph::to_app() { diff --git a/src/muz/spacer/spacer_term_graph.h b/src/muz/spacer/spacer_term_graph.h index 6e5ea9a6a..b547adef3 100644 --- a/src/muz/spacer/spacer_term_graph.h +++ b/src/muz/spacer/spacer_term_graph.h @@ -36,7 +36,7 @@ public: family_id get_family_id() const {return m_id;} /// Process (and potentially augment) a literal - virtual app* process_lit (app *lit) {return lit;} + virtual app_ref process_lit (app *lit) = 0; }; class term_graph { @@ -80,9 +80,15 @@ public: ast_manager &get_ast_manager() const {return m;} void add_lit(app *lit); + void add_lits(expr_ref_vector const &lits) { + for (unsigned i = 0, sz = lits.size(); i < sz; ++i) { + add_lit(::to_app(lits.get(i))); + } + } void reset(); - void to_lits (app_ref_vector &lits, bool all_equalities = false); + void to_lits(app_ref_vector &lits, bool all_equalities = false); + void to_lits(expr_ref_vector &lits, bool all_equalities = false); app_ref to_app(); }; From 09d54c10a67235296d4335ec68933f0d2aa0d1ce Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Dec 2017 16:25:00 -0500 Subject: [PATCH 0949/1283] Wire term graph into spacer normalizer --- src/muz/spacer/spacer_util.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 1d8a59d36..9a0148784 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -9,6 +9,7 @@ Abstract: Utility functions for SPACER. + Author: Krystof Hoder (t-khoder) 2011-8-19. @@ -64,6 +65,7 @@ Notes: #include "tactic/arith/arith_bounds_tactic.h" #include "ast/factor_equivs.h" +#include "muz/spacer/spacer_term_graph.h" namespace spacer { @@ -1061,14 +1063,24 @@ void normalize (expr *e, expr_ref &out, simplify_bounds (v); } if (use_factor_eqs) { - // pick non-constant value representative for - // equivalence classes - expr_equiv_class eq_classes(out.m()); - factor_eqs(v, eq_classes); - rewrite_eqs(v, eq_classes); - equiv_to_expr(eq_classes, v); + // -- refactor equivalence classes and choose a representative + spacer::term_graph egraph(out.m()); + egraph.add_lits (v); + v.reset(); + egraph.to_lits(v); } + TRACE("spacer_normalize", + tout << "Normalized:\n" + << out << "\n" + << "to\n" + << mk_and(v) << "\n";); + TRACE("spacer_normalize", + spacer::term_graph egraph(out.m()); + for (unsigned i = 0, sz = v.size(); i < sz; ++i) + egraph.add_lit (to_app(v.get(i))); + tout << "Reduced app:\n" + << mk_pp(egraph.to_app(), out.m()) << "\n";); out = mk_and (v); } } From 9bc11b2122a618209d6fb8c90f3b33c81729ac10 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Dec 2017 16:25:14 -0500 Subject: [PATCH 0950/1283] Wire term graph into eq_generalizer --- src/muz/spacer/spacer_generalizers.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index e2058e93f..dd75f5974 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -24,8 +24,7 @@ Revision History: #include "ast/expr_abstract.h" #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" -#include "ast/factor_equivs.h" - +#include "muz/spacer/spacer_term_graph.h" namespace spacer { void lemma_sanity_checker::operator()(lemma_ref &lemma) { @@ -282,16 +281,20 @@ void lemma_eq_generalizer::operator() (lemma_ref &lemma) { TRACE("core_eq", tout << "Transforming equivalence classes\n";); - ast_manager &m = m_ctx.get_ast_manager(); - expr_ref_vector core(m); - core.append (lemma->get_cube()); + if (lemma->get_cube().empty()) return; - bool dirty; - expr_equiv_class eq_classes(m); - factor_eqs(core, eq_classes); - // create all possible equalities to allow for simple inductive generalization - dirty = equiv_to_expr_full(eq_classes, core); - if (dirty) { + ast_manager &m = m_ctx.get_ast_manager(); + spacer::term_graph egraph(m); + egraph.add_lits(lemma->get_cube()); + + // -- expand the cube with all derived equalities + expr_ref_vector core(m); + egraph.to_lits(core, true); + + // -- if the core looks different from the original cube + if (core.size() != lemma->get_cube().size() || + core.get(0) != lemma->get_cube().get(0)) { + // -- update the lemma lemma->update_cube(lemma->get_pob(), core); } } From ea73acef45e937d2ee76b23f2d8fd2389b912525 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 14 Dec 2017 17:05:25 -0500 Subject: [PATCH 0951/1283] Implements mk_num_pat Abstracts interpreted numeric constants with variables in a ground expression --- src/muz/spacer/spacer_antiunify.cpp | 77 +++++++++++++++++++++++++++++ src/muz/spacer/spacer_antiunify.h | 3 ++ 2 files changed, 80 insertions(+) diff --git a/src/muz/spacer/spacer_antiunify.cpp b/src/muz/spacer/spacer_antiunify.cpp index 6baf9e93d..6c38e4898 100644 --- a/src/muz/spacer/spacer_antiunify.cpp +++ b/src/muz/spacer/spacer_antiunify.cpp @@ -28,6 +28,7 @@ Revision History: namespace spacer { + // Abstracts numeric values by variables struct var_abs_rewriter : public default_rewriter_cfg { ast_manager &m; @@ -453,7 +454,83 @@ void naive_convex_closure::substitute_vars_by_const(ast_manager& m, expr* t, subs_rw (t, res); } + +/// Construct a pattern by abstracting all numbers by variables +struct mk_num_pat_rewriter : public default_rewriter_cfg { + ast_manager &m; + arith_util m_arith; + + // -- mark already seen expressions + ast_mark m_seen; + // -- true if the expression is known to have a number as a sub-expression + ast_mark m_has_num; + // -- expressions created during the transformation + expr_ref_vector m_pinned; + // -- map from introduced variables to expressions they replace + app_ref_vector &m_subs; + + + // -- stack of expressions being processed to have access to expressions + // -- before rewriting + ptr_buffer m_stack; + + mk_num_pat_rewriter (ast_manager &manager, app_ref_vector& subs) : + m(manager), m_arith(m), m_pinned(m), m_subs(subs) {} + + bool pre_visit(expr * t) { + // -- don't touch multiplication + if (m_arith.is_mul(t)) return false; + + bool r = (!m_seen.is_marked(t) || m_has_num.is_marked(t)); + if (r) {m_stack.push_back (t);} + return r; + } + + + br_status reduce_app (func_decl * f, unsigned num, expr * const * args, + expr_ref & result, proof_ref & result_pr) { + expr *s; + s = m_stack.back(); + m_stack.pop_back(); + if (is_app(s)) { + app *a = to_app(s); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + if (m_has_num.is_marked(a->get_arg(i))) { + m_has_num.mark(a, true); + break; + } + } + } + return BR_FAILED; + } + + bool cache_all_results() const { return false; } + bool cache_results() const { return false; } + + bool get_subst(expr * s, expr * & t, proof * & t_pr) { + if (m_arith.is_numeral(s)) { + t = m.mk_var(m_subs.size(), m.get_sort(s)); + m_pinned.push_back(t); + m_subs.push_back(to_app(s)); + + m_has_num.mark(t, true); + m_seen.mark(t, true); + return true; + } + return false; + } + +}; + +void mk_num_pat(expr *e, expr_ref &result, app_ref_vector &subs) { + SASSERT(subs.empty()); + mk_num_pat_rewriter rw_cfg(result.m(), subs); + rewriter_tpl rw(result.m(), false, rw_cfg); + rw(e, result); +} + } template class rewriter_tpl; template class rewriter_tpl; +template class rewriter_tpl; diff --git a/src/muz/spacer/spacer_antiunify.h b/src/muz/spacer/spacer_antiunify.h index 2b86f67ec..fb0933f0d 100644 --- a/src/muz/spacer/spacer_antiunify.h +++ b/src/muz/spacer/spacer_antiunify.h @@ -63,5 +63,8 @@ private: expr_ref& res); }; +/// Abstracts numbers in the given ground expression by variables +/// Returns the created pattern and the corresponding substitution. +void mk_num_pat(expr *e, expr_ref &result, app_ref_vector &subs); } #endif From f51c07adf6c1781e6cd75062fa08c3df02942ba2 Mon Sep 17 00:00:00 2001 From: Yakir Vizel Date: Mon, 18 Dec 2017 09:14:38 -0500 Subject: [PATCH 0952/1283] Moving skolems to lemma --- src/muz/spacer/spacer_context.cpp | 17 +++++++++-------- src/muz/spacer/spacer_context.h | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 8f4b63224..ac5dc7477 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -40,7 +40,7 @@ Notes: #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" #include "ast/ast_util.h" -#include "ast/proofs/proof_checker.h" +#include "ast/proof_checker/proof_checker.h" #include "smt/smt_value_sort.h" #include "ast/scoped_proof.h" #include "muz/spacer/spacer_qe_project.h" @@ -1177,7 +1177,7 @@ void pred_transformer::inherit_properties(pred_transformer& other) lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : m_ref_count(0), m(manager), m_body(body, m), m_cube(m), - m_bindings(m), m_lvl(lvl), + m_bindings(m), m_zks(m), m_lvl(lvl), m_pob(nullptr), m_new_pob(false) { SASSERT(m_body); normalize(m_body, m_body); @@ -1186,16 +1186,17 @@ lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : lemma::lemma(pob_ref const &p) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), - m_bindings(m), m_lvl(p->level()), - m_pob(p), m_new_pob(m_pob) {SASSERT(m_pob);} + m_bindings(m), m_zks(m), m_lvl(p->level()), + m_pob(p), m_new_pob(m_pob) {SASSERT(m_pob); m_pob->get_skolems(m_zks);} lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), - m_bindings(m), m_lvl(p->level()), + m_bindings(m), m_zks(m), m_lvl(p->level()), m_pob(p), m_new_pob(m_pob) { + m_pob->get_skolems(m_zks); update_cube(p, cube); set_level(lvl); } @@ -1210,9 +1211,9 @@ void lemma::mk_expr_core() { m_body = ::push_not(::mk_and(m_cube)); normalize(m_body, m_body); - if (!m_pob->is_ground() && has_zk_const(m_body)) { + if (!m_zks.empty() && has_zk_const(m_body)) { app_ref_vector zks(m); - m_pob->get_skolems(zks); + zks.append(m_zks); zks.reverse(); expr_abstract(m, 0, zks.size(), (expr* const*)zks.c_ptr(), m_body, @@ -2163,8 +2164,8 @@ bool context::validate() expr_ref_vector refs(m); expr_ref tmp(m); model_ref model; - model_converter_ref mc; vector rs; + model_converter_ref mc; get_level_property(m_inductive_lvl, refs, rs); inductive_property ex(m, mc, rs); ex.to_model(model); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 181a55142..708497460 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -111,6 +111,7 @@ class lemma { expr_ref m_body; expr_ref_vector m_cube; app_ref_vector m_bindings; + app_ref_vector m_zks; unsigned m_lvl; pob_ref m_pob; bool m_new_pob; @@ -133,6 +134,7 @@ public: pob_ref &get_pob() {return m_pob;} inline unsigned weakness(); + void set_skolems(app_ref_vector &zks) { m_zks.append(zks); } unsigned level () const {return m_lvl;} void set_level (unsigned lvl) {m_lvl = lvl;} app_ref_vector& get_bindings() {return m_bindings;} From 981e521b18648c0f1408fc02e77082d7ab1915eb Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 18 Dec 2017 12:06:10 -0500 Subject: [PATCH 0953/1283] Cleanup lemma definition exposes a potential bug. See comments in code. --- src/muz/spacer/spacer_context.cpp | 11 +++++++---- src/muz/spacer/spacer_context.h | 6 ++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index ac5dc7477..9d1aafc9a 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1177,7 +1177,7 @@ void pred_transformer::inherit_properties(pred_transformer& other) lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : m_ref_count(0), m(manager), m_body(body, m), m_cube(m), - m_bindings(m), m_zks(m), m_lvl(lvl), + m_zks(m), m_bindings(m), m_lvl(lvl), m_pob(nullptr), m_new_pob(false) { SASSERT(m_body); normalize(m_body, m_body); @@ -1186,17 +1186,17 @@ lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : lemma::lemma(pob_ref const &p) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), - m_bindings(m), m_zks(m), m_lvl(p->level()), + m_zks(m), m_bindings(m), m_lvl(p->level()), m_pob(p), m_new_pob(m_pob) {SASSERT(m_pob); m_pob->get_skolems(m_zks);} lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), - m_bindings(m), m_zks(m), m_lvl(p->level()), + m_zks(m), m_bindings(m), m_lvl(p->level()), m_pob(p), m_new_pob(m_pob) { - m_pob->get_skolems(m_zks); + if (m_pob) {m_pob->get_skolems(m_zks);} update_cube(p, cube); set_level(lvl); } @@ -1229,6 +1229,9 @@ void lemma::mk_expr_core() { names.c_ptr(), m_body, 15, symbol(m_body->get_id())); if (m_new_pob) { + // XXX This assertion will fail when a lemma is + // XXX generalized with additional quantified variables + SASSERT(m_pob->get_binding().size() == m_zks.size()); add_binding(m_pob->get_binding()); } } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 708497460..b90d84793 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -110,8 +110,8 @@ class lemma { ast_manager &m; expr_ref m_body; expr_ref_vector m_cube; - app_ref_vector m_bindings; app_ref_vector m_zks; + app_ref_vector m_bindings; unsigned m_lvl; pob_ref m_pob; bool m_new_pob; @@ -134,7 +134,9 @@ public: pob_ref &get_pob() {return m_pob;} inline unsigned weakness(); - void set_skolems(app_ref_vector &zks) { m_zks.append(zks); } + void add_skolems(app_ref_vector &zks) {m_zks.append(zks);} + void add_skolem(app *zk) {m_zks.push_back(zk);} + unsigned level () const {return m_lvl;} void set_level (unsigned lvl) {m_lvl = lvl;} app_ref_vector& get_bindings() {return m_bindings;} From 7b82ec1beef79b0c13bdfc07ffc284a98f91a20f Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 18 Dec 2017 13:04:19 -0500 Subject: [PATCH 0954/1283] Attempt bug fix --- src/muz/spacer/spacer_context.cpp | 80 +++++++++++++++---------------- src/muz/spacer/spacer_context.h | 4 +- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 9d1aafc9a..80c21d61c 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1178,7 +1178,7 @@ lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : m_ref_count(0), m(manager), m_body(body, m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(lvl), - m_pob(nullptr), m_new_pob(false) { + m_pob(nullptr) { SASSERT(m_body); normalize(m_body, m_body); } @@ -1187,64 +1187,64 @@ lemma::lemma(pob_ref const &p) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(p->level()), - m_pob(p), m_new_pob(m_pob) {SASSERT(m_pob); m_pob->get_skolems(m_zks);} + m_pob(p) { + SASSERT(m_pob); + m_pob->get_skolems(m_zks); + add_binding(m_pob->get_binding()); +} lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(p->level()), - m_pob(p), m_new_pob(m_pob) + m_pob(p) { - if (m_pob) {m_pob->get_skolems(m_zks);} + if (m_pob) { + m_pob->get_skolems(m_zks); + add_binding(m_pob->get_binding()); + } update_cube(p, cube); set_level(lvl); } +void lemma::add_skolem(app *zk, app *b) { + SASSERT(m_bindings.size() == m_zks.size()); + // extend bindings + m_bindings.push_back(b); + // extend skolems + m_zks.push_back(zk); +} + + void lemma::mk_expr_core() { if (m_body) return; if (m_pob) { mk_cube_core(); + } - // make a clause by negating the cube - m_body = ::push_not(::mk_and(m_cube)); - normalize(m_body, m_body); + SASSERT(!m_cube.empty()); + m_body = ::push_not(::mk_and(m_cube)); + normalize(m_body, m_body); - if (!m_zks.empty() && has_zk_const(m_body)) { - app_ref_vector zks(m); - zks.append(m_zks); - zks.reverse(); - expr_abstract(m, 0, - zks.size(), (expr* const*)zks.c_ptr(), m_body, - m_body); - ptr_buffer sorts; - svector names; - for (unsigned i=0, sz=zks.size(); i < sz; ++i) { - sorts.push_back(get_sort(zks.get(i))); - names.push_back(zks.get(i)->get_decl()->get_name()); - } - m_body = m.mk_quantifier(true, zks.size(), - sorts.c_ptr(), - names.c_ptr(), - m_body, 15, symbol(m_body->get_id())); - if (m_new_pob) { - // XXX This assertion will fail when a lemma is - // XXX generalized with additional quantified variables - SASSERT(m_pob->get_binding().size() == m_zks.size()); - add_binding(m_pob->get_binding()); - } + if (!m_zks.empty() && has_zk_const(m_body)) { + app_ref_vector zks(m); + zks.append(m_zks); + zks.reverse(); + expr_abstract(m, 0, + zks.size(), (expr* const*)zks.c_ptr(), m_body, + m_body); + ptr_buffer sorts; + svector names; + for (unsigned i=0, sz=zks.size(); i < sz; ++i) { + sorts.push_back(get_sort(zks.get(i))); + names.push_back(zks.get(i)->get_decl()->get_name()); } - m_new_pob = false; - return; - } - else if (!m_cube.empty()) { - m_body = ::push_not(::mk_and(m_cube)); - normalize(m_body, m_body); - return; - } - else { - UNREACHABLE(); + m_body = m.mk_quantifier(true, zks.size(), + sorts.c_ptr(), + names.c_ptr(), + m_body, 15, symbol(m_body->get_id())); } SASSERT(m_body); } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index b90d84793..10bb06317 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -114,7 +114,6 @@ class lemma { app_ref_vector m_bindings; unsigned m_lvl; pob_ref m_pob; - bool m_new_pob; void mk_expr_core(); void mk_cube_core(); @@ -134,8 +133,7 @@ public: pob_ref &get_pob() {return m_pob;} inline unsigned weakness(); - void add_skolems(app_ref_vector &zks) {m_zks.append(zks);} - void add_skolem(app *zk) {m_zks.push_back(zk);} + void add_skolem(app *zk, app* b); unsigned level () const {return m_lvl;} void set_level (unsigned lvl) {m_lvl = lvl;} From 05e876d6842e904d93629e2f1f3ed1c9b21274c8 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 19 Dec 2017 15:03:52 -0500 Subject: [PATCH 0955/1283] Fix n-arry applications in spacer_term_graph --- src/muz/spacer/spacer_term_graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_term_graph.cpp b/src/muz/spacer/spacer_term_graph.cpp index 61f7fb369..7c2b64a50 100644 --- a/src/muz/spacer/spacer_term_graph.cpp +++ b/src/muz/spacer/spacer_term_graph.cpp @@ -292,7 +292,7 @@ app* term_graph::mk_app_core (app *a) { kids.push_back (mk_app(::to_app(a->get_arg(i)))); } - app* res = m.mk_app(a->get_decl(), kids.c_ptr()); + app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); m_pinned.push_back(res); return res; From ec179da0fa3a260bb61524d7569b14dd48ed9f3d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 4 Jan 2018 13:43:20 -0500 Subject: [PATCH 0956/1283] API to get num of free variables in a pob --- src/muz/spacer/spacer_context.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 10bb06317..494da06a7 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -524,6 +524,7 @@ public: void erase_child (pob &v) {m_kids.erase (&v);} bool is_ground () { return m_binding.empty (); } + unsigned get_free_vars_size() { return m_binding.size(); } app_ref_vector const &get_binding() const {return m_binding;} /* * Return skolem variables that appear in post From a8318b8822da5d56f0859a9fdc84196e2a3e3984 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 19 Dec 2017 09:38:35 -0500 Subject: [PATCH 0957/1283] Fix lemma::has_binding() --- src/muz/spacer/spacer_context.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 80c21d61c..c7f9f448f 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1303,8 +1303,7 @@ void lemma::update_cube (pob_ref const &p, expr_ref_vector &cube) { } bool lemma::has_binding(app_ref_vector const &binding) { - expr *lem = get_expr(); - unsigned num_decls = to_quantifier(lem)->get_num_decls(); + unsigned num_decls = m_zks.size(); SASSERT(binding.size() == num_decls); From ecf9c629b044c7fa8cf0ca40cdec9a144285dbf7 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 26 Dec 2017 16:48:37 -0500 Subject: [PATCH 0958/1283] Fix binding handling for quantifier free lemmas --- src/muz/spacer/spacer_context.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index c7f9f448f..1151909f1 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1307,6 +1307,8 @@ bool lemma::has_binding(app_ref_vector const &binding) { SASSERT(binding.size() == num_decls); + if (num_decls == 0) return true; + for (unsigned off = 0, sz = m_bindings.size(); off < sz; off += num_decls) { unsigned i = 0; for (; i < num_decls; ++i) { From 0c1ef7155ac165c1dffdbd9f41e79c2886149a29 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 22 Dec 2017 23:15:10 -0500 Subject: [PATCH 0959/1283] Option to rewrite expression in term_graph Rewrite expressions to minimize uses of constants 0 and 1 Currently disabled due to interaction with quic --- src/muz/spacer/spacer_term_graph.cpp | 57 ++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_term_graph.cpp b/src/muz/spacer/spacer_term_graph.cpp index 7c2b64a50..859111c6c 100644 --- a/src/muz/spacer/spacer_term_graph.cpp +++ b/src/muz/spacer/spacer_term_graph.cpp @@ -115,10 +115,45 @@ public: return true; } + app* mk_le_zero(expr *arg) { + expr *e1, *e2, *e3; + // XXX currently disabled + if (false && m_arith.is_add(arg, e1, e2)) { + // e1-e2<=0 --> e1<=e2 + if (m_arith.is_times_minus_one(e2, e3)) { + return m_arith.mk_le(e1, e3); + } + // -e1+e2<=0 --> e2<=e1 + else if (m_arith.is_times_minus_one(e1, e3)) { + return m_arith.mk_le(e2, e3); + } + } + return m_arith.mk_le(arg, mk_zero()); + } + app* mk_ge_zero(expr *arg) { + expr *e1, *e2, *e3; + // XXX currently disabled + if (false && m_arith.is_add(arg, e1, e2)) { + // e1-e2>=0 --> e1>=e2 + if (m_arith.is_times_minus_one(e2, e3)) { + return m_arith.mk_ge(e1, e3); + } + // -e1+e2>=0 --> e2>=e1 + else if (m_arith.is_times_minus_one(e1, e3)) { + return m_arith.mk_ge(e2, e3); + } + } + return m_arith.mk_ge(arg, mk_zero()); + } + bool mk_le_core (expr *arg1, expr * arg2, app_ref &result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { - result = m.mk_not (m_arith.mk_ge (arg1, mk_zero ())); + result = m.mk_not (mk_ge_zero (arg1)); + return true; + } + else if (m_arith.is_zero(arg2)) { + result = mk_le_zero(arg1); return true; } return false; @@ -133,15 +168,25 @@ public: bool mk_ge_core (expr * arg1, expr * arg2, app_ref &result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) if (m_arith.is_int (arg1) && is_one (arg2)) { - result = m.mk_not (m_arith.mk_le (arg1, mk_zero ())); + result = m.mk_not (mk_le_zero (arg1)); + return true; + } + else if (m_arith.is_zero(arg2)) { + result = mk_ge_zero(arg1); return true; } return false; } - virtual app_ref process_lit (app *lit) { + virtual app_ref process_lit (app *_lit) { + app *lit = _lit; expr *e1, *e2; + // strip negation + bool is_neg = m.is_not(lit); + if (is_neg) { + lit = to_app(to_app(lit)->get_arg(0)); + } app_ref res(m); res = lit; @@ -154,6 +199,12 @@ public: else if (m_arith.is_ge(lit, e1, e2)) { mk_ge_core(e1, e2, res); } + + // restore negation + if (is_neg) { + res = m.mk_not(res); + } + return res; } }; From 068b77d43a96acc33dd92e13a69b09a153eb76df Mon Sep 17 00:00:00 2001 From: Yakir Vizel Date: Wed, 27 Dec 2017 12:44:20 -0500 Subject: [PATCH 0960/1283] Normalizing LE and GE with constants --- src/muz/spacer/spacer_term_graph.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_term_graph.cpp b/src/muz/spacer/spacer_term_graph.cpp index 859111c6c..5cd531870 100644 --- a/src/muz/spacer/spacer_term_graph.cpp +++ b/src/muz/spacer/spacer_term_graph.cpp @@ -118,7 +118,7 @@ public: app* mk_le_zero(expr *arg) { expr *e1, *e2, *e3; // XXX currently disabled - if (false && m_arith.is_add(arg, e1, e2)) { + if (m_arith.is_add(arg, e1, e2)) { // e1-e2<=0 --> e1<=e2 if (m_arith.is_times_minus_one(e2, e3)) { return m_arith.mk_le(e1, e3); @@ -133,7 +133,7 @@ public: app* mk_ge_zero(expr *arg) { expr *e1, *e2, *e3; // XXX currently disabled - if (false && m_arith.is_add(arg, e1, e2)) { + if (m_arith.is_add(arg, e1, e2)) { // e1-e2>=0 --> e1>=e2 if (m_arith.is_times_minus_one(e2, e3)) { return m_arith.mk_ge(e1, e3); @@ -148,6 +148,7 @@ public: bool mk_le_core (expr *arg1, expr * arg2, app_ref &result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) + rational n; if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { result = m.mk_not (mk_ge_zero (arg1)); return true; @@ -156,6 +157,11 @@ public: result = mk_le_zero(arg1); return true; } + else if (m_arith.is_numeral(arg2, n)) { + // t <= n ==> t < n + 1 ==> ! (t >= n + 1) + result = m.mk_not(m_arith.mk_ge(arg1, m_arith.mk_numeral(n+1, true))); + return true; + } return false; } @@ -167,6 +173,7 @@ public: bool mk_ge_core (expr * arg1, expr * arg2, app_ref &result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) + rational n; if (m_arith.is_int (arg1) && is_one (arg2)) { result = m.mk_not (mk_le_zero (arg1)); return true; @@ -175,6 +182,11 @@ public: result = mk_ge_zero(arg1); return true; } + else if (m_arith.is_numeral(arg2, n)) { + // t >= n ==> t > n - 1 ==> ! (t <= n - 1) + result = m.mk_not(m_arith.mk_le(arg1, m_arith.mk_numeral(n-1, true))); + return true; + } return false; } From 46fb0d928a4585ab9fc3eae3d945f70c576cad08 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 27 Dec 2017 13:01:54 -0500 Subject: [PATCH 0961/1283] Fix in spacer_term_graph --- src/muz/spacer/spacer_term_graph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_term_graph.cpp b/src/muz/spacer/spacer_term_graph.cpp index 5cd531870..0dc29a7c5 100644 --- a/src/muz/spacer/spacer_term_graph.cpp +++ b/src/muz/spacer/spacer_term_graph.cpp @@ -157,7 +157,7 @@ public: result = mk_le_zero(arg1); return true; } - else if (m_arith.is_numeral(arg2, n)) { + else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n < 0) { // t <= n ==> t < n + 1 ==> ! (t >= n + 1) result = m.mk_not(m_arith.mk_ge(arg1, m_arith.mk_numeral(n+1, true))); return true; @@ -182,7 +182,7 @@ public: result = mk_ge_zero(arg1); return true; } - else if (m_arith.is_numeral(arg2, n)) { + else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n > 0) { // t >= n ==> t > n - 1 ==> ! (t <= n - 1) result = m.mk_not(m_arith.mk_le(arg1, m_arith.mk_numeral(n-1, true))); return true; From 7dee36358df189a3f50d3612bc84b8c8c24ccc82 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 26 Dec 2017 16:49:48 -0500 Subject: [PATCH 0962/1283] Allow bool_ind_generalizer to skip non-array literals Currently a hack to skip generalizing some literals. Used together with quic generalizer to remove all array terms if possible before quic generalization --- src/muz/spacer/spacer_generalizers.cpp | 28 ++++++++++++++++++++++++++ src/muz/spacer/spacer_generalizers.h | 7 +++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index dd75f5974..c87bdc892 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -24,8 +24,15 @@ Revision History: #include "ast/expr_abstract.h" #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" + #include "muz/spacer/spacer_term_graph.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/substitution/matcher.h" + +#include "ast/expr_functors.h" + + namespace spacer { void lemma_sanity_checker::operator()(lemma_ref &lemma) { unsigned uses_level; @@ -36,6 +43,19 @@ void lemma_sanity_checker::operator()(lemma_ref &lemma) { lemma->weakness())); } +namespace{ + class contains_array_op_proc : public i_expr_pred { + ast_manager &m; + family_id m_array_fid; + public: + contains_array_op_proc(ast_manager &manager) : + m(manager), m_array_fid(m.mk_family_id("array")) + {} + virtual bool operator()(expr *e) { + return is_app(e) && to_app(e)->get_family_id() == m_array_fid; + } + }; +} // ------------------------ // lemma_bool_inductive_generalizer @@ -50,6 +70,9 @@ void lemma_bool_inductive_generalizer::operator()(lemma_ref &lemma) { pred_transformer &pt = lemma->get_pob()->pt(); ast_manager &m = pt.get_ast_manager(); + contains_array_op_proc has_array_op(m); + check_pred has_arrays(has_array_op, m); + expr_ref_vector cube(m); cube.append(lemma->get_cube()); @@ -65,6 +88,11 @@ void lemma_bool_inductive_generalizer::operator()(lemma_ref &lemma) { (!m_failure_limit || num_failures < m_failure_limit)) { expr_ref lit(m); lit = cube.get(i); + if (m_array_only && !has_arrays(lit)) { + processed.push_back(lit); + ++i; + continue; + } cube[i] = true_expr; if (cube.size() > 1 && pt.check_inductive(lemma->level(), cube, uses_level, weakness)) { diff --git a/src/muz/spacer/spacer_generalizers.h b/src/muz/spacer/spacer_generalizers.h index 1962e74e0..17298495c 100644 --- a/src/muz/spacer/spacer_generalizers.h +++ b/src/muz/spacer/spacer_generalizers.h @@ -48,11 +48,14 @@ class lemma_bool_inductive_generalizer : public lemma_generalizer { }; unsigned m_failure_limit; + bool m_array_only; stats m_st; public: - lemma_bool_inductive_generalizer(context& ctx, unsigned failure_limit) : - lemma_generalizer(ctx), m_failure_limit(failure_limit) {} + lemma_bool_inductive_generalizer(context& ctx, unsigned failure_limit, + bool array_only = false) : + lemma_generalizer(ctx), m_failure_limit(failure_limit), + m_array_only(array_only) {} ~lemma_bool_inductive_generalizer() override {} void operator()(lemma_ref &lemma) override; From a1efb88318ec7182b0845db5be465d1856af39c9 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 27 Dec 2017 12:54:35 -0500 Subject: [PATCH 0963/1283] Semantic matcher Extends matcher with rewrites based on semantics of arithmetic operations Like matcher, but uses arithmetic and logic rewrites to try to get a semantic match. --- src/muz/spacer/CMakeLists.txt | 2 + src/muz/spacer/spacer_sem_matcher.cpp | 147 ++++++++++++++++++++++++++ src/muz/spacer/spacer_sem_matcher.h | 69 ++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 src/muz/spacer/spacer_sem_matcher.cpp create mode 100644 src/muz/spacer/spacer_sem_matcher.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index f27f6e726..16ce3e4f9 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -21,6 +21,8 @@ z3_add_component(spacer spacer_mev_array.cpp spacer_qe_project.cpp spacer_term_graph.cpp + spacer_sem_matcher.cpp + spacer_quant_generalizer.cpp COMPONENT_DEPENDENCIES arith_tactics core_tactics diff --git a/src/muz/spacer/spacer_sem_matcher.cpp b/src/muz/spacer/spacer_sem_matcher.cpp new file mode 100644 index 000000000..f3c2af8a9 --- /dev/null +++ b/src/muz/spacer/spacer_sem_matcher.cpp @@ -0,0 +1,147 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + sem_matcher.cpp + +Abstract: + + + +Author: + + Leonardo de Moura (leonardo) 2008-02-02. + Arie Gurfinkel + +Revision History: + +--*/ +#include "muz/spacer/spacer_sem_matcher.h" + +namespace spacer { + +sem_matcher::sem_matcher(ast_manager &man) : m(man), m_arith(m), m_pinned(m) {} + +bool sem_matcher::match_var (var *v, expr *e) { + expr_offset r; + if (m_subst->find(v, 0, r)) { + if (!m.are_equal(r.get_expr(), e)) { + return false; + } + } + else { + m_subst->insert(v, 0, expr_offset(e, 1)); + } + return true; +} +bool sem_matcher::operator()(expr * e1, expr * e2, substitution & s, bool &pos) { + reset(); + m_subst = &s; + m_todo.push_back(expr_pair(e1, e2)); + + // true on the first run through the loop + bool top = true; + pos = true; + while (!m_todo.empty()) { + expr_pair const & p = m_todo.back(); + + if (is_var(p.first)) { + if (!match_var(to_var(p.first), p.second)) { + return false; + } + m_todo.pop_back(); + top = false; + continue; + } + + + if (is_var(p.second)) + return false; + if (!is_app(p.first)) + return false; + if (!is_app(p.second)) + return false; + + app * n1 = to_app(p.first); + app * n2 = to_app(p.second); + + expr *t = nullptr; + + // strip negation + if (top && n1->get_decl() != n2->get_decl()) { + if (m.is_not(n1, t) && !m.is_not(n2) && is_app(t) && + to_app(t)->get_decl() == n2->get_decl()) { + pos = false; + n1 = to_app(e1); + } + else if (!m.is_not(n1) && m.is_not(n2, t) && is_app(t) && + to_app(t)->get_decl() == n1->get_decl()) { + pos = false; + n2 = to_app(t); + } + } + top = false; + + if (n1->get_decl() != n2->get_decl()) { + expr *e1 = nullptr, *e2 = nullptr; + rational val1, val2; + + // x<=y == !(x>y) + if (m_arith.is_le(n1) && m.is_not(n2, t) && m_arith.is_gt(t)) { + n2 = to_app(t); + } + else if (m_arith.is_le(n2) && m.is_not(n1, t) && m_arith.is_gt(t)) { + n1 = to_app(t); + } + // x>=y == !(xget_num_args(); + if (num_args1 != n2->get_num_args()) + return false; + + m_todo.pop_back(); + + if (num_args1 == 0) + continue; + + unsigned j = num_args1; + while (j > 0) { + --j; + m_todo.push_back(expr_pair(n1->get_arg(j), n2->get_arg(j))); + } + } + return true; +} + +void sem_matcher::reset() { + m_todo.reset(); + m_pinned.reset(); +} +} diff --git a/src/muz/spacer/spacer_sem_matcher.h b/src/muz/spacer/spacer_sem_matcher.h new file mode 100644 index 000000000..7d169166e --- /dev/null +++ b/src/muz/spacer/spacer_sem_matcher.h @@ -0,0 +1,69 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + sem_matcher.h + +Abstract: + + Semantic matcher + +Author: + + Leonardo de Moura (leonardo) 2008-02-02. + Arie Gurfinkel + +Revision History: + +--*/ +#ifndef SPACER_SEM_MATCHER_H_ +#define SPACER_SEM_MATCHER_H_ + +#include "ast/substitution/substitution.h" +#include "ast/arith_decl_plugin.h" +#include "util/hashtable.h" + +namespace spacer { +/** + \brief Functor for matching expressions. +*/ +class sem_matcher { + typedef std::pair expr_pair; + typedef pair_hash, obj_ptr_hash > expr_pair_hash; + typedef hashtable > cache; + + ast_manager &m; + arith_util m_arith; + expr_ref_vector m_pinned; + substitution * m_subst; + svector m_todo; + + void reset(); + + bool match_var(var *v, expr *e); +public: + sem_matcher(ast_manager &man); + + /** + \brief Return true if e2 is an instance of e1. + In case of success (result is true), it will store the substitution that makes e1 equals to e2 into s. + Sets pos to true if the match is positive and to false if it is negative (i.e., e1 equals !e2) + + For example: + 1) e1 = f(g(x), x), e2 = f(g(h(a)), h(a)) + The result is true, and s will contain x -> h(a) + + 2) e1 = f(a, x) e2 = f(x, a) + The result is false. + + 3) e1 = f(x, x) e2 = f(y, a) + The result is false + + 4) e1 = f(x, y) e2 = f(h(z), a) + The result is true, and s contains x->h(z) and y->a + */ + bool operator()(expr * e1, expr * e2, substitution & s, bool &pos); +}; +} +#endif /* SPACER_SEM_MATCHER_H_ */ From 23a8e59493f95a18e62bdeebe007700ae29d6be3 Mon Sep 17 00:00:00 2001 From: Yakir Vizel Date: Mon, 18 Dec 2017 13:52:53 -0500 Subject: [PATCH 0964/1283] Initial commit of QGen Controlled by fixedpoint.spacer.use_quanti_generalizer measure cumulative time, number of invocations, and number of failed SMT calls Relaxing equality in a pattern: if a variable equals a numeral, relax with GE pob::get_skolems() returns all skolems that might appear in the pob. New skolems must be added above the largest index in that map, even if they are not used in the pob itself. pattern generalization should be done before the pattern is skolemized and added into the new cube. --- src/muz/base/fixedpoint_params.pyg | 3 +- src/muz/spacer/spacer_context.cpp | 7 +- src/muz/spacer/spacer_context.h | 4 +- src/muz/spacer/spacer_generalizers.cpp | 2 + src/muz/spacer/spacer_generalizers.h | 48 ++ src/muz/spacer/spacer_manager.cpp | 21 +- src/muz/spacer/spacer_manager.h | 6 +- src/muz/spacer/spacer_quant_generalizer.cpp | 499 ++++++++++++++++++++ src/muz/spacer/spacer_util.cpp | 4 +- src/muz/spacer/spacer_util.h | 5 +- 10 files changed, 583 insertions(+), 16 deletions(-) create mode 100644 src/muz/spacer/spacer_quant_generalizer.cpp diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index f0f4e0881..e91eb86fe 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -187,7 +187,8 @@ def_module_params('fixedpoint', ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), ('spacer.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), ('spacer.iuc.debug_proof', BOOL, False, 'prints proof used by unsat-core-learner for debugging purposes'), - ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints') + ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints'), + ('spacer.use_quant_generalizer', BOOL, False, 'use quantified lemma generalizer'), )) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 1151909f1..607bf2018 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1894,7 +1894,6 @@ void pob::set_post(expr* post, app_ref_vector const &b) { expr_safe_replace sub(m); for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { expr* e; - e = m_binding.get(i); pinned.push_back (mk_zk_const (m, i, get_sort(e))); sub.insert (e, pinned.back()); @@ -1939,7 +1938,6 @@ void pob::close () { void pob::get_skolems(app_ref_vector &v) { for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { expr* e; - e = m_binding.get(i); v.push_back (mk_zk_const (get_ast_manager(), i, get_sort(e))); } @@ -2273,6 +2271,11 @@ void context::init_lemma_generalizers(datalog::rule_set& rules) fparams.m_ng_lift_ite = LI_FULL; } + if (m_params.spacer_use_quant_generalizer()) { + m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0, false)); + m_lemma_generalizers.push_back(alloc(lemma_quantifier_generalizer, *this)); + } + if (get_params().spacer_use_eqclass()) { m_lemma_generalizers.push_back (alloc(lemma_eq_generalizer, *this)); } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 494da06a7..e909cd9ad 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -527,7 +527,9 @@ public: unsigned get_free_vars_size() { return m_binding.size(); } app_ref_vector const &get_binding() const {return m_binding;} /* - * Return skolem variables that appear in post + * Returns a map from variable id to skolems that implicitly + * represent them in the pob. Note that only some (or none) of the + * skolems returned actually appear in the post of the pob. */ void get_skolems(app_ref_vector& v); diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index c87bdc892..342e43ad3 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -326,4 +326,6 @@ void lemma_eq_generalizer::operator() (lemma_ref &lemma) lemma->update_cube(lemma->get_pob(), core); } } + + }; diff --git a/src/muz/spacer/spacer_generalizers.h b/src/muz/spacer/spacer_generalizers.h index 17298495c..46ad0c4a3 100644 --- a/src/muz/spacer/spacer_generalizers.h +++ b/src/muz/spacer/spacer_generalizers.h @@ -97,6 +97,54 @@ public: void operator()(lemma_ref &lemma) override; }; +class lemma_quantifier_generalizer : public lemma_generalizer { + struct stats { + unsigned count; + unsigned num_failures; + stopwatch watch; + stats() {reset();} + void reset() {count = 0; num_failures = 0; watch.reset();} + }; + ast_manager &m; + arith_util m_arith; + stats m_st; +public: + lemma_quantifier_generalizer(context &ctx); + virtual ~lemma_quantifier_generalizer() {} + virtual void operator()(lemma_ref &lemma); + + virtual void collect_statistics(statistics& st) const; + virtual void reset_statistics() {m_st.reset();} +private: + bool match_sk_idx(expr *e, app_ref_vector const &zks, expr *&idx, app *&sk); + void cleanup(expr_ref_vector& cube, app_ref_vector const &zks, expr_ref &bind); + void generalize_pattern_lits(expr_ref_vector &pats); + void find_candidates( + expr *e, + app_ref_vector &candidate); + void generate_patterns( + expr_ref_vector const &cube, + app_ref_vector const &candidates, + var_ref_vector &subs, + expr_ref_vector &patterns, + unsigned offset); + void find_matching_expressions( + expr_ref_vector const &cube, + var_ref_vector const &subs, + expr_ref_vector &patterns, + vector &idx_instances, + vector &dirty); + void find_guards( + expr_ref_vector const &indices, + expr_ref &lower, + expr_ref &upper); + void add_lower_bounds( + var_ref_vector const &subs, + app_ref_vector const &zks, + vector const &idx_instances, + expr_ref_vector &cube); }; +} + #endif diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index d583813a8..c46c31924 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -340,22 +340,27 @@ app* mk_zk_const(ast_manager &m, unsigned idx, sort *s) { namespace find_zk_const_ns { struct proc { + int m_max; app_ref_vector &m_out; - proc (app_ref_vector &out) : m_out(out) {} + proc (app_ref_vector &out) : m_max(-1), m_out(out) {} void operator() (var const * n) const {} - void operator() (app *n) const { - if (is_uninterp_const(n) && - n->get_decl()->get_name().str().compare (0, 3, "sk!") == 0) { - m_out.push_back (n); + void operator() (app *n) { + int idx; + if (is_zk_const(n, idx)) { + m_out.push_back(n); + if (idx > m_max) { + m_max = idx; + } } } void operator() (quantifier const *n) const {} }; } -void find_zk_const(expr *e, app_ref_vector &res) { +int find_zk_const(expr *e, app_ref_vector &res) { find_zk_const_ns::proc p(res); for_each_expr (p, e); + return p.m_max; } namespace has_zk_const_ns { @@ -363,8 +368,8 @@ struct found {}; struct proc { void operator() (var const *n) const {} void operator() (app const *n) const { - if (is_uninterp_const(n) && - n->get_decl()->get_name().str().compare(0, 3, "sk!") == 0) { + int idx; + if (is_zk_const(n, idx)) { throw found(); } } diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index f49aa63fc..32cf61d57 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -339,8 +339,12 @@ public: }; app* mk_zk_const (ast_manager &m, unsigned idx, sort *s); -void find_zk_const(expr* e, app_ref_vector &out); +int find_zk_const(expr* e, app_ref_vector &out); +inline int find_zk_const(expr_ref_vector const &v, app_ref_vector &out) { + return find_zk_const (mk_and(v), out); +} bool has_zk_const(expr* e); +bool is_zk_const (const app *a, int &n); struct sk_lt_proc { bool operator()(const app* a1, const app* a2); diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp new file mode 100644 index 000000000..8be97122c --- /dev/null +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -0,0 +1,499 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation and Arie Gurfinkel + +Module Name: + + spacer_quant_generalizer.cpp + +Abstract: + + Quantified lemma generalizer. + +Author: + + + Yakir Vizel + Arie Gurfinkel + +Revision History: + +--*/ + + +#include "muz/spacer/spacer_context.h" +#include "muz/spacer/spacer_generalizers.h" +#include "muz/spacer/spacer_manager.h" +#include "ast/expr_abstract.h" +#include "ast/rewriter/var_subst.h" +#include "ast/for_each_expr.h" +#include "ast/factor_equivs.h" +#include "muz/spacer/spacer_term_graph.h" +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/substitution/matcher.h" +#include "ast/expr_functors.h" + +#include "muz/spacer/spacer_sem_matcher.h" + +using namespace spacer; + +namespace { +struct index_lt_proc : public std::binary_function { + arith_util m_arith; + index_lt_proc(ast_manager &m) : m_arith(m) {} + bool operator() (app *a, app *b) { + // XXX This order is a bit strange. + // XXX It does the job in our current application, but only because + // XXX we assume that we only compare expressions of the form (B + k), + // XXX where B is fixed and k is a number. + // XXX Might be better to specialize just for that specific use case. + rational val1, val2; + bool is_num1 = m_arith.is_numeral(a, val1); + bool is_num2 = m_arith.is_numeral(b, val2); + + if (is_num1 && is_num2) { + return val1 < val2; + } + else if (is_num1 != is_num2) { + return is_num1; + } + + is_num1 = false; + is_num2 = false; + // compare the first numeric argument of a to first numeric argument of b + // if available + for (unsigned i = 0, sz = a->get_num_args(); !is_num1 && i < sz; ++i) { + is_num1 = m_arith.is_numeral (a->get_arg(i), val1); + } + for (unsigned i = 0, sz = b->get_num_args(); !is_num2 && i < sz; ++i) { + is_num2 = m_arith.is_numeral(b->get_arg(i), val2); + } + + if (is_num1 && is_num2) { + return val1 < val2; + } + else if (is_num1 != is_num2) { + return is_num1; + } + else { + return a->get_id() < b->get_id(); + } + + } +}; + +} + +namespace spacer { + +lemma_quantifier_generalizer::lemma_quantifier_generalizer(context &ctx) : + lemma_generalizer(ctx), m(ctx.get_ast_manager()), m_arith(m) {} + +void lemma_quantifier_generalizer::collect_statistics(statistics &st) const +{ + st.update("time.spacer.solve.reach.gen.quant", m_st.watch.get_seconds()); + st.update("quantifier gen", m_st.count); + st.update("quantifier gen failures", m_st.num_failures); +} + +// XXX What does this do? +void lemma_quantifier_generalizer::find_candidates( + expr *e, app_ref_vector &candidates) +{ + if (!contains_selects(e, m)) return; + + app_ref_vector indices(m); + get_select_indices(e, indices, m); + + app_ref_vector extra(m); + expr_sparse_mark marked_args; + + // Make sure not to try and quantify already-quantified indices + for (unsigned idx=0, sz = indices.size(); idx < sz; idx++) { + // skip expressions that already contain a quantified variable + if (has_zk_const(indices.get(idx))) { + continue; + } + + app *index = indices.get(idx); + TRACE ("spacer_qgen", + tout << "Candidate: "<< mk_pp(index, m) + << " in " << mk_pp(e, m) << "\n";); + extra.push_back(index); + // XXX expand one level of arguments. Might want to go deeper. + for (unsigned j = 0, asz = index->get_num_args(); j < asz; j++) { + expr *arg = index->get_arg(j); + if (!is_app(arg) || marked_args.is_marked(arg)) {continue;} + marked_args.mark(arg); + candidates.push_back (to_app(arg)); + } + } + + std::sort(candidates.c_ptr(), candidates.c_ptr() + candidates.size(), + index_lt_proc(m)); + // keep actual select indecies in the order found at the back of + // candidate list + + // XXX this corresponds to current implementation. Probably should + // XXX be sorted together with the rest of candidates + candidates.append(extra); +} + +/* subs are the variables that might appear in the patterns */ +void lemma_quantifier_generalizer::generate_patterns( + expr_ref_vector const &cube, app_ref_vector const &candidates, + var_ref_vector &subs, expr_ref_vector &patterns, unsigned offset) +{ + if (candidates.empty()) return; + + expr_safe_replace ses(m); + + // Setup substitution + for (unsigned i=0; i < candidates.size(); i++) { + expr *cand = candidates.get(i); + var *var = m.mk_var(i+offset, get_sort(cand)); + ses.insert(cand, var); + rational val; + if (m_arith.is_numeral(cand, val)) { + bool is_int = val.is_int(); + ses.insert( + m_arith.mk_numeral(rational(val+1), is_int), + m_arith.mk_add(var, m_arith.mk_numeral(rational(1), is_int))); + ses.insert( + m_arith.mk_numeral(rational(-1*(val+1)), is_int), + m_arith.mk_add(m_arith.mk_sub(m_arith.mk_numeral(rational(0), is_int),var), m_arith.mk_numeral(rational(-1), is_int))); + } + subs.push_back(var); + } + + // Generate patterns + + // for every literal + for (unsigned j=0; j < cube.size(); j++) { + // abstract terms by variables + expr_ref pat(m); + ses(cube.get(j), pat); + + if (pat.get() != cube.get(j)) { + // if abstraction is not identity + TRACE("spacer_qgen", + tout << "Pattern is: " << mk_pp(pat, m) << "\n";); + + // store the pattern + patterns.push_back(pat); + } + } +} + +void lemma_quantifier_generalizer::find_matching_expressions( + expr_ref_vector const &cube, + var_ref_vector const &subs, expr_ref_vector &patterns, + vector &idx_instances, + vector &dirty) +{ + idx_instances.resize(subs.size(), expr_ref_vector(m)); + // -- for every pattern + for (unsigned p = 0; p < patterns.size(); p++) { + expr *pattern = patterns.get(p); + // -- for every literal + for (unsigned j = 0; j < cube.size(); j++) { + if (dirty[j] || !is_app(cube.get(j))) continue; + app *lit = to_app(cube.get(j)); + + sem_matcher match(m); + bool pos; + substitution v_sub(m); + v_sub.reserve(2, subs.size()+1); + + if (!match(pattern, lit, v_sub, pos)) { + continue; + } + // expect positive matches only + if (!pos) {continue;} + + dirty[j] = true; + for (unsigned v = 0; v < subs.size(); v++) { + expr_offset idx; + if (v_sub.find(subs.get(v), 0, idx)) { + TRACE ("spacer_qgen", tout << "INSTANCE IS: " << mk_pp(idx.get_expr(), m) << "\n";); + idx_instances[v].push_back(idx.get_expr()); + } + } + } + } +} + + +void lemma_quantifier_generalizer::find_guards( + expr_ref_vector const &indices, + expr_ref &lower, expr_ref &upper) +{ + if (indices.empty()) return; + + auto minmax = std::minmax_element((app * *) indices.c_ptr(), + (app * *) indices.c_ptr() + indices.size(), + index_lt_proc(m)); + lower = *minmax.first; + upper = *minmax.second; +} + +void lemma_quantifier_generalizer::add_lower_bounds( + var_ref_vector const &subs, + app_ref_vector const &zks, + vector const &idx_instances, + expr_ref_vector &cube) +{ + for (unsigned v = 0; v < subs.size(); v++) { + var *var = subs.get(v); + if (idx_instances[v].empty()) continue; + TRACE("spacer_qgen", + tout << "Finding lower bounds for " << mk_pp(var, m) << "\n";); + expr_ref low(m); + expr_ref up(m); + find_guards(idx_instances[v], low, up); + cube.push_back(m_arith.mk_ge(zks.get(var->get_idx()), low)); + } +} + +/// returns true if expression e contains a sub-expression of the form (select A idx) where +/// idx contains exactly one skolem from zks. Returns idx and the skolem +bool lemma_quantifier_generalizer::match_sk_idx(expr *e, app_ref_vector const &zks, expr *&idx, app *&sk) { + if (zks.size() != 1) return false; + contains_app has_zk(m, zks.get(0)); + + if (!contains_selects(e, m)) return false; + app_ref_vector indicies(m); + get_select_indices(e, indicies, m); + if (indicies.size() > 2) return false; + + unsigned i=0; + if (indicies.size() == 1) { + if (!has_zk(indicies.get(0))) return false; + } + else { + if (has_zk(indicies.get(0)) && !has_zk(indicies.get(1))) + i = 0; + else if (!has_zk(indicies.get(0)) && has_zk(indicies.get(1))) + i = 1; + else if (!has_zk(indicies.get(0)) && !has_zk(indicies.get(1))) + return false; + } + + idx = indicies.get(i); + sk = zks.get(0); + return true; +} + +expr* times_minus_one(expr *e, arith_util &arith) { + expr *r; + if (arith.is_times_minus_one (e, r)) { return r; } + + return arith.mk_mul(arith.mk_numeral(rational(-1), arith.is_int(get_sort(e))), e); +} + +/** Attempts to rewrite a cube so that quantified variable appears as + a top level argument of select-term + + Find sub-expression of the form (select A (+ sk!0 t)) and replaces + (+ sk!0 t) --> sk!0 and sk!0 --> (+ sk!0 (* (- 1) t)) + + Current implementation is an ugly hack for one special case +*/ +void lemma_quantifier_generalizer::cleanup(expr_ref_vector &cube, app_ref_vector const &zks, expr_ref &bind) { + if (zks.size() != 1) return; + + arith_util arith(m); + expr *idx = nullptr; + app *sk = nullptr; + expr_ref rep(m); + + for (expr *e : cube) { + if (match_sk_idx(e, zks, idx, sk)) { + CTRACE("spacer_qgen", idx != sk, + tout << "Possible cleanup of " << mk_pp(idx, m) << " in " + << mk_pp(e, m) << " on " << mk_pp(sk, m) << "\n";); + + if (!arith.is_add(idx)) continue; + app *a = to_app(idx); + bool found = false; + expr_ref_vector kids(m); + expr_ref_vector kids_bind(m); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + if (a->get_arg(i) == sk) { + found = true; + kids.push_back(a->get_arg(i)); + kids_bind.push_back(bind); + } + else { + kids.push_back (times_minus_one(a->get_arg(i), arith)); + kids_bind.push_back (times_minus_one(a->get_arg(i), arith)); + } + } + if (!found) continue; + + rep = arith.mk_add(kids.size(), kids.c_ptr()); + bind = arith.mk_add(kids_bind.size(), kids_bind.c_ptr()); + TRACE("spacer_qgen", + tout << "replace " << mk_pp(idx, m) << " with " << mk_pp(rep, m) << "\n";); + break; + } + } + + if (rep) { + expr_safe_replace rw(m); + rw.insert(sk, rep); + rw.insert(idx, sk); + rw(cube); + TRACE("spacer_qgen", + tout << "Cleaned cube to: " << mk_and(cube) << "\n";); + } +} + +void lemma_quantifier_generalizer::generalize_pattern_lits(expr_ref_vector &pats) { + // generalize pattern literals using 'x=t' --> 'x>=t' + for (unsigned i = 0, sz = pats.size(); i < sz; ++i) { + expr *e1, *e2; + expr *p = pats.get(i); + if (m.is_eq(p, e1, e2) && (is_var(e1) || is_var(e2))) { + if (m_arith.is_numeral(e1)) { + p = m_arith.mk_ge(e2, e1); + } + else if (m_arith.is_numeral(e2)) { + p = m_arith.mk_ge(e1, e2); + } + } + if (p != pats.get(i)) { + pats.set(i, p); + } + } +} +void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { + if (lemma->get_cube().empty()) return; + if (!lemma->has_pob()) return; + + m_st.count++; + scoped_watch _w_(m_st.watch); + + expr_ref_vector cube(m); + cube.append(lemma->get_cube()); + + TRACE("spacer_qgen", + tout << "initial cube: " << mk_and(lemma->get_cube()) << "\n";); + if (false) { + // -- re-normalize the cube + expr_ref c(m); + c = mk_and(cube); + normalize(c, c, true, true); + cube.reset(); + flatten_and(c, cube); + } + + app_ref_vector skolems(m); + lemma->get_pob()->get_skolems(skolems); + int offset = skolems.size(); + + // for every literal + for (unsigned i=0; i < cube.size(); i++) { + expr *r = cube.get(i); + + // generate candidates + app_ref_vector candidates(m); + find_candidates(r, candidates); + + // XXX Can candidates be empty and arguments not empty? + // XXX Why separate candidates and arguments? + // XXX Why are arguments processed before candidates? + if (candidates.empty()) continue; + + + // for every candidate + for (unsigned arg=0, sz = candidates.size(); arg < sz; arg++) { + app_ref_vector cand(m); + cand.push_back(to_app(candidates.get(arg))); + var_ref_vector subs(m); + expr_ref_vector patterns(m); + // generate patterns for a candidate + generate_patterns(cube, cand, subs, patterns, offset); + + // Currently, only support one variable per pattern + SASSERT(subs.size() == cand.size()); + SASSERT(cand.size() == 1); + + // Find matching expressions + vector dirty; + dirty.resize(cube.size(), false); + vector idx_instances; + find_matching_expressions(cube, subs, patterns, idx_instances, dirty); + + expr_ref_vector new_cube(m); + + // move all unmatched expressions to the new cube + for (unsigned c=0; c < cube.size(); c++) { + if (dirty[c] == false) { + new_cube.push_back(cube.get(c)); + } + } + + // everything moved, nothing left + if (new_cube.size() == cube.size()) continue; + + // -- generalize equality in patterns + generalize_pattern_lits(patterns); + + // ground quantified patterns in skolems + expr_ref gnd(m); + app_ref_vector zks(m); + ground_expr(mk_and(patterns), gnd, zks); + flatten_and(gnd, new_cube); + + // compute lower bounds for quantified variables + add_lower_bounds(subs, zks, idx_instances, new_cube); + + TRACE("spacer_qgen", + tout << "New CUBE is: " << mk_pp(mk_and(new_cube),m) << "\n";); + + // check if the result is a lemma + unsigned uses_level = 0; + unsigned weakness = lemma->weakness(); + pred_transformer &pt = lemma->get_pob()->pt(); + if (pt.check_inductive(lemma->level(), new_cube, uses_level, weakness)) { + TRACE("spacer", + tout << "Quantifier Generalization Succeeded!\n" + << "New CUBE is: " << mk_pp(mk_and(new_cube),m) << "\n";); + SASSERT(zks.size() >= offset); + SASSERT(cand.size() == 1); + + // lift quantified variables to top of select + expr_ref bind(m); + bind = cand.get(0); + cleanup(new_cube, zks, bind); + + // XXX better do that check before changing bind in cleanup() + // XXX Or not because substitution might introduce _n variable into bind + if (m_ctx.get_manager().is_n_formula(bind)) + // XXX this creates an instance, but not necessarily the needed one + + // XXX This is sound because any instance of + // XXX universal quantifier is sound + + // XXX needs better long term solution. leave + // comment here for the future + m_ctx.get_manager().formula_n2o(bind, bind, 0); + + lemma->update_cube(lemma->get_pob(), new_cube); + lemma->set_level(uses_level); + + // XXX Assumes that offset + 1 == zks.size(); + for (unsigned sk=offset; sk < zks.size(); sk++) + lemma->add_skolem(zks.get(sk), to_app(bind)); + return; + } + else { + ++m_st.num_failures; + } + } + } +} + + + +} diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 9a0148784..cb11afc9f 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -1317,9 +1317,9 @@ bool contains_selects(expr* fml, ast_manager& m) return false; } -void get_select_indices(expr* fml, app_ref_vector& indices, ast_manager& m) +void get_select_indices(expr* fml, app_ref_vector &indices, ast_manager& m) { - array_util a_util(m); + array_util a_util(m); if (!is_app(fml)) { return; } ast_mark done; ptr_vector todo; diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index 7be2ee4b3..dabfa494a 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -144,7 +144,10 @@ void compute_implicant_literals (model_evaluator_util &mev, void simplify_bounds (expr_ref_vector &lemmas); void normalize(expr *e, expr_ref &out, bool use_simplify_bounds = true, bool factor_eqs = false); -/** ground expression by replacing all free variables by skolem constants */ +/** Ground expression by replacing all free variables by skolem + ** constants. On return, out is the resulting expression, and vars is + ** a map from variable ids to corresponding skolem constants. + */ void ground_expr (expr *e, expr_ref &out, app_ref_vector &vars); From 9cdb63ae4ab6a8c869060bd1b54ac99d3cf5c2e8 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 29 Dec 2017 12:03:48 -0500 Subject: [PATCH 0965/1283] Handle conversion of quantified lemma to quantifier free When a cube is updated, a lemma might loose all of its quantified variables. In this case, it is effectively quantifier free and might be a version of an already existing lemma. For that reason, we convert it to quantifier free lemma when this happens. --- src/muz/spacer/spacer_context.cpp | 14 +++++++++++++- src/muz/spacer/spacer_quant_generalizer.cpp | 17 ++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 607bf2018..90103503b 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1300,6 +1300,18 @@ void lemma::update_cube (pob_ref const &p, expr_ref_vector &cube) { m_body.reset(); m_cube.append(cube); if (m_cube.empty()) {m_cube.push_back(m.mk_true());} + + // after the cube is updated, if there are no skolems, + // convert the lemma to quantifier-free + bool is_quant = false; + for (unsigned i = 0, sz = cube.size(); !is_quant && i < sz; ++i) { + is_quant = has_zk_const(cube.get(i)); + } + + if (!is_quant) { + m_zks.reset(); + m_bindings.reset(); + } } bool lemma::has_binding(app_ref_vector const &binding) { @@ -2272,7 +2284,7 @@ void context::init_lemma_generalizers(datalog::rule_set& rules) } if (m_params.spacer_use_quant_generalizer()) { - m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0, false)); + m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0, true)); m_lemma_generalizers.push_back(alloc(lemma_quantifier_generalizer, *this)); } diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index 8be97122c..942fbfc6a 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -202,7 +202,11 @@ void lemma_quantifier_generalizer::find_matching_expressions( sem_matcher match(m); bool pos; substitution v_sub(m); - v_sub.reserve(2, subs.size()+1); + + // allocate space for the largest variable in the pattern + unsigned max_idx = 0; + for (var* v : subs) {max_idx = std::max(max_idx, v->get_idx());} + v_sub.reserve(2, max_idx + 1); if (!match(pattern, lit, v_sub, pos)) { continue; @@ -378,13 +382,15 @@ void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { TRACE("spacer_qgen", tout << "initial cube: " << mk_and(lemma->get_cube()) << "\n";); - if (false) { + if (true) { // -- re-normalize the cube expr_ref c(m); c = mk_and(cube); normalize(c, c, true, true); cube.reset(); flatten_and(c, cube); + TRACE("spacer_qgen", + tout << "normalized cube:\n" << mk_and(cube) << "\n";); } app_ref_vector skolems(m); @@ -398,10 +404,6 @@ void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { // generate candidates app_ref_vector candidates(m); find_candidates(r, candidates); - - // XXX Can candidates be empty and arguments not empty? - // XXX Why separate candidates and arguments? - // XXX Why are arguments processed before candidates? if (candidates.empty()) continue; @@ -456,7 +458,7 @@ void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { unsigned weakness = lemma->weakness(); pred_transformer &pt = lemma->get_pob()->pt(); if (pt.check_inductive(lemma->level(), new_cube, uses_level, weakness)) { - TRACE("spacer", + TRACE("spacer_qgen", tout << "Quantifier Generalization Succeeded!\n" << "New CUBE is: " << mk_pp(mk_and(new_cube),m) << "\n";); SASSERT(zks.size() >= offset); @@ -482,6 +484,7 @@ void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { lemma->update_cube(lemma->get_pob(), new_cube); lemma->set_level(uses_level); + SASSERT(offset + 1 == zks.size()); // XXX Assumes that offset + 1 == zks.size(); for (unsigned sk=offset; sk < zks.size(); sk++) lemma->add_skolem(zks.get(sk), to_app(bind)); From 852e181fed8f5c7c5547f48af13d951e12f9340e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 4 Jan 2018 13:43:45 -0500 Subject: [PATCH 0966/1283] New quic3 lemma generalizer --- src/muz/spacer/spacer_generalizers.h | 41 +- src/muz/spacer/spacer_quant_generalizer.cpp | 532 +++++++++++--------- 2 files changed, 321 insertions(+), 252 deletions(-) diff --git a/src/muz/spacer/spacer_generalizers.h b/src/muz/spacer/spacer_generalizers.h index 46ad0c4a3..bc549a949 100644 --- a/src/muz/spacer/spacer_generalizers.h +++ b/src/muz/spacer/spacer_generalizers.h @@ -109,41 +109,30 @@ class lemma_quantifier_generalizer : public lemma_generalizer { ast_manager &m; arith_util m_arith; stats m_st; + expr_ref_vector m_cube; + + bool m_normalize_cube; + int m_offset; public: - lemma_quantifier_generalizer(context &ctx); + lemma_quantifier_generalizer(context &ctx, bool normalize_cube = true); virtual ~lemma_quantifier_generalizer() {} virtual void operator()(lemma_ref &lemma); virtual void collect_statistics(statistics& st) const; virtual void reset_statistics() {m_st.reset();} private: + bool generalize(lemma_ref &lemma, app *term); + + void find_candidates(expr *e, app_ref_vector &candidate); + bool is_ub(var *var, expr *e); + bool is_lb(var *var, expr *e); + void mk_abs_cube (app *term, var *var, + expr_ref_vector &gnd_cube, + expr_ref_vector &abs_cube, + expr *&lb, expr *&ub); + bool match_sk_idx(expr *e, app_ref_vector const &zks, expr *&idx, app *&sk); void cleanup(expr_ref_vector& cube, app_ref_vector const &zks, expr_ref &bind); - void generalize_pattern_lits(expr_ref_vector &pats); - void find_candidates( - expr *e, - app_ref_vector &candidate); - void generate_patterns( - expr_ref_vector const &cube, - app_ref_vector const &candidates, - var_ref_vector &subs, - expr_ref_vector &patterns, - unsigned offset); - void find_matching_expressions( - expr_ref_vector const &cube, - var_ref_vector const &subs, - expr_ref_vector &patterns, - vector &idx_instances, - vector &dirty); - void find_guards( - expr_ref_vector const &indices, - expr_ref &lower, - expr_ref &upper); - void add_lower_bounds( - var_ref_vector const &subs, - app_ref_vector const &zks, - vector const &idx_instances, - expr_ref_vector &cube); }; } diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index 942fbfc6a..bbd086749 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -85,8 +85,10 @@ struct index_lt_proc : public std::binary_function { namespace spacer { -lemma_quantifier_generalizer::lemma_quantifier_generalizer(context &ctx) : - lemma_generalizer(ctx), m(ctx.get_ast_manager()), m_arith(m) {} +lemma_quantifier_generalizer::lemma_quantifier_generalizer(context &ctx, + bool normalize_cube) : + lemma_generalizer(ctx), m(ctx.get_ast_manager()), m_arith(m), m_cube(m), + m_normalize_cube(normalize_cube), m_offset(0) {} void lemma_quantifier_generalizer::collect_statistics(statistics &st) const { @@ -95,10 +97,21 @@ void lemma_quantifier_generalizer::collect_statistics(statistics &st) const st.update("quantifier gen failures", m_st.num_failures); } -// XXX What does this do? -void lemma_quantifier_generalizer::find_candidates( - expr *e, app_ref_vector &candidates) -{ +/** + Finds candidates terms to be existentially abstracted. + A term t is a candidate if + (a) t is ground + + (b) t appears in an expression of the form (select A t) for some array A + + (c) t appears in an expression of the form (select A (+ t v)) + where v is ground + + The goal is to pick candidates that might result in a lemma in the + essentially uninterpreted fragment of FOL or its extensions. + */ +void lemma_quantifier_generalizer::find_candidates(expr *e, + app_ref_vector &candidates) { if (!contains_selects(e, m)) return; app_ref_vector indices(m); @@ -115,11 +128,10 @@ void lemma_quantifier_generalizer::find_candidates( } app *index = indices.get(idx); - TRACE ("spacer_qgen", - tout << "Candidate: "<< mk_pp(index, m) + TRACE ("spacer_qgen", tout << "Candidate: "<< mk_pp(index, m) << " in " << mk_pp(e, m) << "\n";); extra.push_back(index); - // XXX expand one level of arguments. Might want to go deeper. + if (m_arith.is_add(index)) { for (unsigned j = 0, asz = index->get_num_args(); j < asz; j++) { expr *arg = index->get_arg(j); if (!is_app(arg) || marked_args.is_marked(arg)) {continue;} @@ -127,136 +139,15 @@ void lemma_quantifier_generalizer::find_candidates( candidates.push_back (to_app(arg)); } } + } std::sort(candidates.c_ptr(), candidates.c_ptr() + candidates.size(), index_lt_proc(m)); // keep actual select indecies in the order found at the back of - // candidate list - - // XXX this corresponds to current implementation. Probably should - // XXX be sorted together with the rest of candidates + // candidate list. There is no particular reason for this order candidates.append(extra); } -/* subs are the variables that might appear in the patterns */ -void lemma_quantifier_generalizer::generate_patterns( - expr_ref_vector const &cube, app_ref_vector const &candidates, - var_ref_vector &subs, expr_ref_vector &patterns, unsigned offset) -{ - if (candidates.empty()) return; - - expr_safe_replace ses(m); - - // Setup substitution - for (unsigned i=0; i < candidates.size(); i++) { - expr *cand = candidates.get(i); - var *var = m.mk_var(i+offset, get_sort(cand)); - ses.insert(cand, var); - rational val; - if (m_arith.is_numeral(cand, val)) { - bool is_int = val.is_int(); - ses.insert( - m_arith.mk_numeral(rational(val+1), is_int), - m_arith.mk_add(var, m_arith.mk_numeral(rational(1), is_int))); - ses.insert( - m_arith.mk_numeral(rational(-1*(val+1)), is_int), - m_arith.mk_add(m_arith.mk_sub(m_arith.mk_numeral(rational(0), is_int),var), m_arith.mk_numeral(rational(-1), is_int))); - } - subs.push_back(var); - } - - // Generate patterns - - // for every literal - for (unsigned j=0; j < cube.size(); j++) { - // abstract terms by variables - expr_ref pat(m); - ses(cube.get(j), pat); - - if (pat.get() != cube.get(j)) { - // if abstraction is not identity - TRACE("spacer_qgen", - tout << "Pattern is: " << mk_pp(pat, m) << "\n";); - - // store the pattern - patterns.push_back(pat); - } - } -} - -void lemma_quantifier_generalizer::find_matching_expressions( - expr_ref_vector const &cube, - var_ref_vector const &subs, expr_ref_vector &patterns, - vector &idx_instances, - vector &dirty) -{ - idx_instances.resize(subs.size(), expr_ref_vector(m)); - // -- for every pattern - for (unsigned p = 0; p < patterns.size(); p++) { - expr *pattern = patterns.get(p); - // -- for every literal - for (unsigned j = 0; j < cube.size(); j++) { - if (dirty[j] || !is_app(cube.get(j))) continue; - app *lit = to_app(cube.get(j)); - - sem_matcher match(m); - bool pos; - substitution v_sub(m); - - // allocate space for the largest variable in the pattern - unsigned max_idx = 0; - for (var* v : subs) {max_idx = std::max(max_idx, v->get_idx());} - v_sub.reserve(2, max_idx + 1); - - if (!match(pattern, lit, v_sub, pos)) { - continue; - } - // expect positive matches only - if (!pos) {continue;} - - dirty[j] = true; - for (unsigned v = 0; v < subs.size(); v++) { - expr_offset idx; - if (v_sub.find(subs.get(v), 0, idx)) { - TRACE ("spacer_qgen", tout << "INSTANCE IS: " << mk_pp(idx.get_expr(), m) << "\n";); - idx_instances[v].push_back(idx.get_expr()); - } - } - } - } -} - - -void lemma_quantifier_generalizer::find_guards( - expr_ref_vector const &indices, - expr_ref &lower, expr_ref &upper) -{ - if (indices.empty()) return; - - auto minmax = std::minmax_element((app * *) indices.c_ptr(), - (app * *) indices.c_ptr() + indices.size(), - index_lt_proc(m)); - lower = *minmax.first; - upper = *minmax.second; -} - -void lemma_quantifier_generalizer::add_lower_bounds( - var_ref_vector const &subs, - app_ref_vector const &zks, - vector const &idx_instances, - expr_ref_vector &cube) -{ - for (unsigned v = 0; v < subs.size(); v++) { - var *var = subs.get(v); - if (idx_instances[v].empty()) continue; - TRACE("spacer_qgen", - tout << "Finding lower bounds for " << mk_pp(var, m) << "\n";); - expr_ref low(m); - expr_ref up(m); - find_guards(idx_instances[v], low, up); - cube.push_back(m_arith.mk_ge(zks.get(var->get_idx()), low)); - } -} /// returns true if expression e contains a sub-expression of the form (select A idx) where /// idx contains exactly one skolem from zks. Returns idx and the skolem @@ -287,12 +178,14 @@ bool lemma_quantifier_generalizer::match_sk_idx(expr *e, app_ref_vector const &z return true; } +namespace { expr* times_minus_one(expr *e, arith_util &arith) { expr *r; if (arith.is_times_minus_one (e, r)) { return r; } return arith.mk_mul(arith.mk_numeral(rational(-1), arith.is_int(get_sort(e))), e); } +} /** Attempts to rewrite a cube so that quantified variable appears as a top level argument of select-term @@ -352,126 +245,267 @@ void lemma_quantifier_generalizer::cleanup(expr_ref_vector &cube, app_ref_vector } } -void lemma_quantifier_generalizer::generalize_pattern_lits(expr_ref_vector &pats) { - // generalize pattern literals using 'x=t' --> 'x>=t' - for (unsigned i = 0, sz = pats.size(); i < sz; ++i) { - expr *e1, *e2; - expr *p = pats.get(i); - if (m.is_eq(p, e1, e2) && (is_var(e1) || is_var(e2))) { - if (m_arith.is_numeral(e1)) { - p = m_arith.mk_ge(e2, e1); - } - else if (m_arith.is_numeral(e2)) { - p = m_arith.mk_ge(e1, e2); - } +/** + Create an abstract cube by abstracting a given term with a given variable. + On return, + gnd_cube contains all ground literals from m_cube + abs_cube contains all newly quantified literals from m_cube + lb contains an expression determining the lower bound on the variable + ub contains an expression determining the upper bound on the variable + + Conjunction of gnd_cube and abs_cube is the new quantified cube + + lb and ub are null if no bound was found + */ +void lemma_quantifier_generalizer::mk_abs_cube(app *term, var *var, + expr_ref_vector &gnd_cube, + expr_ref_vector &abs_cube, + expr *&lb, expr *&ub) { + + // create an abstraction function that maps candidate term to variables + expr_safe_replace sub(m); + // term -> var + sub.insert(term , var); + rational val; + if (m_arith.is_numeral(term, val)) { + bool is_int = val.is_int(); + expr_ref minus_one(m); + minus_one = m_arith.mk_numeral(rational(-1), is_int); + + // term+1 -> var+1 if term is a number + sub.insert( + m_arith.mk_numeral(val + 1, is_int), + m_arith.mk_add(var, m_arith.mk_numeral(rational(1), is_int))); + // -term-1 -> -1*var + -1 if term is a number + sub.insert( + m_arith.mk_numeral(-1*val + -1, is_int), + m_arith.mk_add (m_arith.mk_mul (minus_one, var), minus_one)); + } + + lb = nullptr; + ub = nullptr; + + for (expr *lit : m_cube) { + expr_ref abs_lit(m); + sub (lit, abs_lit); + if (lit == abs_lit) { + gnd_cube.push_back(lit); } - if (p != pats.get(i)) { - pats.set(i, p); + else { + expr *e1, *e2; + // generalize v=num into v>=num + if (m.is_eq(abs_lit, e1, e2) && (e1 == var || e2 == var)) { + if (m_arith.is_numeral(e1)) { + abs_lit = m_arith.mk_ge (var, e1); + } else if (m_arith.is_numeral(e2)) { + abs_lit = m_arith.mk_ge(var, e2); + } + } + abs_cube.push_back(abs_lit); + if (!lb && is_lb(var, abs_lit)) { + lb = abs_lit; + } + else if (!ub && is_ub(var, abs_lit)) { + ub = abs_lit; } } } -void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { - if (lemma->get_cube().empty()) return; - if (!lemma->has_pob()) return; +} - m_st.count++; - scoped_watch _w_(m_st.watch); - - expr_ref_vector cube(m); - cube.append(lemma->get_cube()); - - TRACE("spacer_qgen", - tout << "initial cube: " << mk_and(lemma->get_cube()) << "\n";); - if (true) { - // -- re-normalize the cube - expr_ref c(m); - c = mk_and(cube); - normalize(c, c, true, true); - cube.reset(); - flatten_and(c, cube); - TRACE("spacer_qgen", - tout << "normalized cube:\n" << mk_and(cube) << "\n";); +// -- returns true if e is an upper bound for var +bool lemma_quantifier_generalizer::is_ub(var *var, expr *e) { + expr *e1, *e2; + // var <= e2 + if ((m_arith.is_le (e, e1, e2) || m_arith.is_lt(e, e1, e2)) && var == e1) { + return true; + } + // e1 >= var + if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && var == e2) { + return true; } - app_ref_vector skolems(m); - lemma->get_pob()->get_skolems(skolems); - int offset = skolems.size(); + // t <= -1*var + if ((m_arith.is_le (e, e1, e2) || m_arith.is_lt(e, e1, e2)) + && m_arith.is_times_minus_one(e2, e2) && e2 == var) { + return true; + } + // -1*var >= t + if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && + m_arith.is_times_minus_one(e1, e1) && e1 == var) { + return true; + } + // ! (var >= e2) + if (m.is_not (e, e1) && is_lb(var, e1)) { + return true; + } + // var + t1 <= t2 + if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && + m_arith.is_add(e1)) { + app *a = to_app(e1); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + expr *arg = a->get_arg(i); + if (arg == var) {return true;} + } + } + // t1 <= t2 + -1*var + if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && + m_arith.is_add(e2)) { + app *a = to_app(e2); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + expr *arg = a->get_arg(i); + if (m_arith.is_times_minus_one(arg, arg) && arg == var) + {return true;} + } + } + // t1 >= t2 + var + if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && + m_arith.is_add(e2)) { + app *a = to_app(e2); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + expr *arg = a->get_arg(i); + if (arg == var) {return true;} + } + } + // -1*var + t1 >= t2 + if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && + m_arith.is_add(e1)) { + app *a = to_app(e1); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + expr *arg = a->get_arg(i); + if (m_arith.is_times_minus_one(arg, arg) && arg == var) + {return true;} + } + } + return false; +} - // for every literal - for (unsigned i=0; i < cube.size(); i++) { - expr *r = cube.get(i); +// -- returns true if e is a lower bound for var +bool lemma_quantifier_generalizer::is_lb(var *var, expr *e) { + expr *e1, *e2; + // var >= e2 + if ((m_arith.is_ge (e, e1, e2) || m_arith.is_gt(e, e1, e2)) && var == e1) { + return true; + } + // e1 <= var + if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && var == e2) { + return true; + } + // t >= -1*var + if ((m_arith.is_ge (e, e1, e2) || m_arith.is_gt(e, e1, e2)) + && m_arith.is_times_minus_one(e2, e2) && e2 == var) { + return true; + } + // -1*var <= t + if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && + m_arith.is_times_minus_one(e1, e1) && e1 == var) { + return true; + } + // ! (var <= e2) + if (m.is_not (e, e1) && is_ub(var, e1)) { + return true; + } + // var + t1 >= t2 + if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && + m_arith.is_add(e1)) { + app *a = to_app(e1); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + expr *arg = a->get_arg(i); + if (arg == var) {return true;} + } + } + // t1 >= t2 + -1*var + if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && + m_arith.is_add(e2)) { + app *a = to_app(e2); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + expr *arg = a->get_arg(i); + if (m_arith.is_times_minus_one(arg, arg) && arg == var) + {return true;} + } + } + // t1 <= t2 + var + if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && + m_arith.is_add(e2)) { + app *a = to_app(e2); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + expr *arg = a->get_arg(i); + if (arg == var) {return true;} + } + } + // -1*var + t1 <= t2 + if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && + m_arith.is_add(e1)) { + app *a = to_app(e1); + for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { + expr *arg = a->get_arg(i); + if (m_arith.is_times_minus_one(arg, arg) && arg == var) + {return true;} + } + } - // generate candidates - app_ref_vector candidates(m); - find_candidates(r, candidates); - if (candidates.empty()) continue; + return false; +} +bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { - // for every candidate - for (unsigned arg=0, sz = candidates.size(); arg < sz; arg++) { - app_ref_vector cand(m); - cand.push_back(to_app(candidates.get(arg))); - var_ref_vector subs(m); - expr_ref_vector patterns(m); - // generate patterns for a candidate - generate_patterns(cube, cand, subs, patterns, offset); + expr *lb = nullptr, *ub = nullptr; + expr_ref_vector gnd_cube(m); + expr_ref_vector abs_cube(m); - // Currently, only support one variable per pattern - SASSERT(subs.size() == cand.size()); - SASSERT(cand.size() == 1); + var_ref var(m); + var = m.mk_var (m_offset, get_sort(term)); - // Find matching expressions - vector dirty; - dirty.resize(cube.size(), false); - vector idx_instances; - find_matching_expressions(cube, subs, patterns, idx_instances, dirty); + mk_abs_cube(term, var, gnd_cube, abs_cube, lb, ub); + if (abs_cube.empty()) {return false;} - expr_ref_vector new_cube(m); + TRACE("spacer_qgen", + tout << "abs_cube is: " << mk_and(abs_cube) << "\n"; + tout << "lb = "; + if (lb) tout << mk_pp(lb, m); else tout << "none"; + tout << "\n"; - // move all unmatched expressions to the new cube - for (unsigned c=0; c < cube.size(); c++) { - if (dirty[c] == false) { - new_cube.push_back(cube.get(c)); + tout << "ub = "; + if (ub) tout << mk_pp(ub, m); else tout << "none"; + tout << "\n";); + + if (!lb && !ub) {return false;} + + // -- guess lower or upper bound if missing + if (!lb) { + abs_cube.push_back (m_arith.mk_ge (var, term)); + lb = abs_cube.back(); } + if (!ub) { + abs_cube.push_back (m_arith.mk_lt(var, term)); + ub = abs_cube.back(); } - // everything moved, nothing left - if (new_cube.size() == cube.size()) continue; - - // -- generalize equality in patterns - generalize_pattern_lits(patterns); - - // ground quantified patterns in skolems + // skolemize expr_ref gnd(m); app_ref_vector zks(m); - ground_expr(mk_and(patterns), gnd, zks); - flatten_and(gnd, new_cube); - - // compute lower bounds for quantified variables - add_lower_bounds(subs, zks, idx_instances, new_cube); + ground_expr(mk_and(abs_cube), gnd, zks); + flatten_and(gnd, gnd_cube); TRACE("spacer_qgen", - tout << "New CUBE is: " << mk_pp(mk_and(new_cube),m) << "\n";); + tout << "New CUBE is: " << mk_pp(mk_and(gnd_cube),m) << "\n";); - // check if the result is a lemma + // check if the result is a true lemma unsigned uses_level = 0; - unsigned weakness = lemma->weakness(); pred_transformer &pt = lemma->get_pob()->pt(); - if (pt.check_inductive(lemma->level(), new_cube, uses_level, weakness)) { + if (pt.check_inductive(lemma->level(), gnd_cube, uses_level, lemma->weakness())) { TRACE("spacer_qgen", tout << "Quantifier Generalization Succeeded!\n" - << "New CUBE is: " << mk_pp(mk_and(new_cube),m) << "\n";); - SASSERT(zks.size() >= offset); - SASSERT(cand.size() == 1); + << "New CUBE is: " << mk_pp(mk_and(gnd_cube),m) << "\n";); + SASSERT(zks.size() >= m_offset); // lift quantified variables to top of select - expr_ref bind(m); - bind = cand.get(0); - cleanup(new_cube, zks, bind); + expr_ref ext_bind(m); + ext_bind = term; + cleanup(gnd_cube, zks, ext_bind); // XXX better do that check before changing bind in cleanup() // XXX Or not because substitution might introduce _n variable into bind - if (m_ctx.get_manager().is_n_formula(bind)) + if (m_ctx.get_manager().is_n_formula(ext_bind)) { // XXX this creates an instance, but not necessarily the needed one // XXX This is sound because any instance of @@ -479,15 +513,61 @@ void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { // XXX needs better long term solution. leave // comment here for the future - m_ctx.get_manager().formula_n2o(bind, bind, 0); + m_ctx.get_manager().formula_n2o(ext_bind, ext_bind, 0); + } - lemma->update_cube(lemma->get_pob(), new_cube); + lemma->update_cube(lemma->get_pob(), gnd_cube); lemma->set_level(uses_level); - SASSERT(offset + 1 == zks.size()); - // XXX Assumes that offset + 1 == zks.size(); - for (unsigned sk=offset; sk < zks.size(); sk++) - lemma->add_skolem(zks.get(sk), to_app(bind)); + SASSERT(var->get_idx() < zks.size()); + SASSERT(is_app(ext_bind)); + lemma->add_skolem(zks.get(var->get_idx()), to_app(ext_bind)); + return true; + } + + return false; +} + +void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { + if (lemma->get_cube().empty()) return; + if (!lemma->has_pob()) return; + + m_st.count++; + scoped_watch _w_(m_st.watch); + + TRACE("spacer_qgen", + tout << "initial cube: " << mk_and(lemma->get_cube()) << "\n";); + + // setup the cube + m_cube.reset(); + m_cube.append(lemma->get_cube()); + + if (m_normalize_cube) { + // -- re-normalize the cube + expr_ref c(m); + c = mk_and(m_cube); + normalize(c, c, false, true); + m_cube.reset(); + flatten_and(c, m_cube); + TRACE("spacer_qgen", + tout << "normalized cube:\n" << mk_and(m_cube) << "\n";); + } + + // first unused free variable + m_offset = lemma->get_pob()->get_free_vars_size(); + + // for every literal, find a candidate term to abstract + for (unsigned i=0; i < m_cube.size(); i++) { + expr *r = m_cube.get(i); + + // generate candidates for abstraction + app_ref_vector candidates(m); + find_candidates(r, candidates); + if (candidates.empty()) continue; + + // for every candidate + for (unsigned arg=0, sz = candidates.size(); arg < sz; arg++) { + if (generalize (lemma, candidates.get(arg))) { return; } else { From 04a778f2fd8542b14ee1308eb195e353cb533467 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 4 Jan 2018 15:59:44 -0500 Subject: [PATCH 0967/1283] Option to enable cube normalization in quic generalizer --- src/muz/base/fixedpoint_params.pyg | 1 + src/muz/spacer/spacer_context.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index e91eb86fe..277399b9f 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -189,6 +189,7 @@ def_module_params('fixedpoint', ('spacer.iuc.debug_proof', BOOL, False, 'prints proof used by unsat-core-learner for debugging purposes'), ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints'), ('spacer.use_quant_generalizer', BOOL, False, 'use quantified lemma generalizer'), + ('spacer.quic_gen_normalize', BOOL, True, 'normalize cube before quantified generalization'), )) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 90103503b..eba51c793 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2284,8 +2284,10 @@ void context::init_lemma_generalizers(datalog::rule_set& rules) } if (m_params.spacer_use_quant_generalizer()) { - m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0, true)); - m_lemma_generalizers.push_back(alloc(lemma_quantifier_generalizer, *this)); + m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, + *this, 0, true)); + m_lemma_generalizers.push_back(alloc(lemma_quantifier_generalizer, *this, + m_params.spacer_quic_gen_normalize())); } if (get_params().spacer_use_eqclass()) { From 5df7a08d1c3ac349cee2eca84b3577a7c7b0e1b3 Mon Sep 17 00:00:00 2001 From: Yakir Vizel Date: Thu, 11 Jan 2018 15:02:09 -0500 Subject: [PATCH 0968/1283] A simple version for finding the stride between different indices in a POB This current version is very limited. It assumes a pre-defined structure (namely, an ADDER). --- src/muz/spacer/spacer_generalizers.h | 6 +- src/muz/spacer/spacer_quant_generalizer.cpp | 118 ++++++++++++++++++-- 2 files changed, 112 insertions(+), 12 deletions(-) diff --git a/src/muz/spacer/spacer_generalizers.h b/src/muz/spacer/spacer_generalizers.h index bc549a949..518b09f6c 100644 --- a/src/muz/spacer/spacer_generalizers.h +++ b/src/muz/spacer/spacer_generalizers.h @@ -126,13 +126,15 @@ private: void find_candidates(expr *e, app_ref_vector &candidate); bool is_ub(var *var, expr *e); bool is_lb(var *var, expr *e); - void mk_abs_cube (app *term, var *var, + void mk_abs_cube (lemma_ref &lemma, app *term, var *var, expr_ref_vector &gnd_cube, expr_ref_vector &abs_cube, - expr *&lb, expr *&ub); + expr *&lb, expr *&ub, unsigned &stride); bool match_sk_idx(expr *e, app_ref_vector const &zks, expr *&idx, app *&sk); void cleanup(expr_ref_vector& cube, app_ref_vector const &zks, expr_ref &bind); + + bool find_stride(expr_ref_vector &c, expr_ref &pattern, unsigned &stride); }; } diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index bbd086749..cf056271d 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -257,10 +257,10 @@ void lemma_quantifier_generalizer::cleanup(expr_ref_vector &cube, app_ref_vector lb and ub are null if no bound was found */ -void lemma_quantifier_generalizer::mk_abs_cube(app *term, var *var, +void lemma_quantifier_generalizer::mk_abs_cube(lemma_ref &lemma, app *term, var *var, expr_ref_vector &gnd_cube, expr_ref_vector &abs_cube, - expr *&lb, expr *&ub) { + expr *&lb, expr *&ub, unsigned &stride) { // create an abstraction function that maps candidate term to variables expr_safe_replace sub(m); @@ -302,6 +302,12 @@ void lemma_quantifier_generalizer::mk_abs_cube(app *term, var *var, } } abs_cube.push_back(abs_lit); + if (contains_selects(abs_lit, m)) { + expr_ref_vector pob_cube(m); + flatten_and(lemma->get_pob()->post(), pob_cube); + find_stride(pob_cube, abs_lit, stride); + } + if (!lb && is_lb(var, abs_lit)) { lb = abs_lit; } @@ -449,13 +455,14 @@ bool lemma_quantifier_generalizer::is_lb(var *var, expr *e) { bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { expr *lb = nullptr, *ub = nullptr; + unsigned stride = 1; expr_ref_vector gnd_cube(m); expr_ref_vector abs_cube(m); var_ref var(m); var = m.mk_var (m_offset, get_sort(term)); - mk_abs_cube(term, var, gnd_cube, abs_cube, lb, ub); + mk_abs_cube(lemma, term, var, gnd_cube, abs_cube, lb, ub, stride); if (abs_cube.empty()) {return false;} TRACE("spacer_qgen", @@ -480,21 +487,37 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { ub = abs_cube.back(); } + rational init; + expr_ref constant(m); + if (is_var(to_app(lb)->get_arg(0))) + constant = to_app(lb)->get_arg(1); + else + constant = to_app(lb)->get_arg(0); + + if (stride > 1 && m_arith.is_numeral(constant, init)) { + unsigned mod = init.get_unsigned() % stride; + TRACE("spacer_qgen", tout << "mod=" << mod << " init=" << init << " stride=" << stride << "\n";); + tout.flush(); + abs_cube.push_back(m.mk_eq( + m_arith.mk_mod(var, m_arith.mk_numeral(rational(stride), true)), + m_arith.mk_numeral(rational(mod), true))); + } + // skolemize - expr_ref gnd(m); - app_ref_vector zks(m); + expr_ref gnd(m); + app_ref_vector zks(m); ground_expr(mk_and(abs_cube), gnd, zks); flatten_and(gnd, gnd_cube); - TRACE("spacer_qgen", + TRACE("spacer_qgen", tout << "New CUBE is: " << mk_pp(mk_and(gnd_cube),m) << "\n";); // check if the result is a true lemma - unsigned uses_level = 0; - pred_transformer &pt = lemma->get_pob()->pt(); + unsigned uses_level = 0; + pred_transformer &pt = lemma->get_pob()->pt(); if (pt.check_inductive(lemma->level(), gnd_cube, uses_level, lemma->weakness())) { - TRACE("spacer_qgen", - tout << "Quantifier Generalization Succeeded!\n" + TRACE("spacer_qgen", + tout << "Quantifier Generalization Succeeded!\n" << "New CUBE is: " << mk_pp(mk_and(gnd_cube),m) << "\n";); SASSERT(zks.size() >= m_offset); @@ -528,6 +551,81 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { return false; } +bool lemma_quantifier_generalizer::find_stride(expr_ref_vector &c, expr_ref &pattern, unsigned &stride) { + expr_ref tmp(m); + tmp = mk_and(c); + normalize(tmp, tmp, false, true); + c.reset(); + flatten_and(tmp, c); + + app_ref_vector indices(m); + get_select_indices(pattern, indices, m); + + // TODO + if (indices.size() > 1) + return false; + + app *p_index = indices.get(0); + if (is_var(p_index)) return false; + + std::vector instances; + for (unsigned i=0; i < c.size(); i++) { + expr *lit = c.get(i); + + if (!contains_selects(lit, m)) + continue; + + indices.reset(); + get_select_indices(lit, indices, m); + + // TODO: + if (indices.size() > 1) + continue; + + app *candidate = indices.get(0); + + unsigned size = p_index->get_num_args(); + unsigned matched = 0; + for (unsigned p=0; p < size; p++) { + expr *arg = p_index->get_arg(p); + if (is_var(arg)) + { + rational val; + if (p < candidate->get_num_args() && m_arith.is_numeral(candidate->get_arg(p), val)) { + instances.push_back(val.get_unsigned()); + } + } + else { + for (unsigned j=0; j < candidate->get_num_args(); j++) { + if (candidate->get_arg(j) == arg) { + matched++; + break; + } + } + } + } + + if (matched < size - 1) + continue; + + if (candidate->get_num_args() == matched) + instances.push_back(0); + + TRACE("spacer_qgen", + tout << "Match succeeded!\n";); + } + + if (instances.size() <= 1) + return false; + + std::sort(instances.begin(), instances.end()); + + stride = instances[1]-instances[0]; + TRACE("spacer_qgen", tout << "Index Stride is: " << stride << "\n";); + + return true; +} + void lemma_quantifier_generalizer::operator()(lemma_ref &lemma) { if (lemma->get_cube().empty()) return; if (!lemma->has_pob()) return; From fd7bcc7afc2c2fd635b03ab4814a4dfad0410777 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 14 May 2018 14:41:12 -0700 Subject: [PATCH 0969/1283] Format --- src/muz/spacer/spacer_generalizers.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 342e43ad3..2f9627398 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -24,12 +24,10 @@ Revision History: #include "ast/expr_abstract.h" #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" - +#include "ast/factor_equivs.h" #include "muz/spacer/spacer_term_graph.h" - #include "ast/rewriter/expr_safe_replace.h" #include "ast/substitution/matcher.h" - #include "ast/expr_functors.h" From b51251f394aefc962fb6fe71d5849a26859ef142 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 08:30:35 -0700 Subject: [PATCH 0970/1283] Move tout under TRACE --- src/muz/spacer/spacer_quant_generalizer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index cf056271d..3dace0cdd 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -496,8 +496,9 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { if (stride > 1 && m_arith.is_numeral(constant, init)) { unsigned mod = init.get_unsigned() % stride; - TRACE("spacer_qgen", tout << "mod=" << mod << " init=" << init << " stride=" << stride << "\n";); - tout.flush(); + TRACE("spacer_qgen", + tout << "mod=" << mod << " init=" << init << " stride=" << stride << "\n"; + tout.flush();); abs_cube.push_back(m.mk_eq( m_arith.mk_mod(var, m_arith.mk_numeral(rational(stride), true)), m_arith.mk_numeral(rational(mod), true))); From 3c7165780c981957dd76cc48543f3c6576f9eeda Mon Sep 17 00:00:00 2001 From: Matteo Date: Thu, 5 Oct 2017 14:07:11 +0200 Subject: [PATCH 0971/1283] Extend spacer with callback events Callback events allow the client of spacer to get events during exection. The events include new lemmas and unfolding. --- src/api/api_datalog.cpp | 17 ++++++- src/api/z3_fixedpoint.h | 10 ++++ src/muz/base/dl_context.h | 8 ++++ src/muz/base/dl_engine_base.h | 10 ++++ src/muz/base/fixedpoint_params.pyg | 4 +- src/muz/spacer/CMakeLists.txt | 1 + src/muz/spacer/spacer_callback.cpp | 38 +++++++++++++++ src/muz/spacer/spacer_callback.h | 65 ++++++++++++++++++++++++++ src/muz/spacer/spacer_context.cpp | 57 ++++++++++++++++++++-- src/muz/spacer/spacer_context.h | 39 +++++++++++++++- src/muz/spacer/spacer_dl_interface.cpp | 8 ++++ src/muz/spacer/spacer_dl_interface.h | 5 ++ 12 files changed, 254 insertions(+), 8 deletions(-) create mode 100644 src/muz/spacer/spacer_callback.cpp create mode 100644 src/muz/spacer/spacer_callback.h diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 2bc3d01e1..7d2e38269 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -603,7 +603,22 @@ extern "C" { Z3_CATCH; } - + + void Z3_API Z3_fixedpoint_add_callback(Z3_context c, Z3_fixedpoint d, + void *state, + Z3_fixedpoint_new_lemma_eh new_lemma_eh, + Z3_fixedpoint_predecessor_eh predecessor_eh, + Z3_fixedpoint_unfold_eh unfold_eh){ + Z3_TRY; + // not logged + to_fixedpoint_ref(d)->ctx().add_callback(state, + reinterpret_cast(new_lemma_eh), + reinterpret_cast(predecessor_eh), + reinterpret_cast(unfold_eh)); + + Z3_CATCH; + } + #include "api_datalog_spacer.inc" }; diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index a651993ce..6836c4766 100644 --- a/src/api/z3_fixedpoint.h +++ b/src/api/z3_fixedpoint.h @@ -367,6 +367,16 @@ extern "C" { void Z3_API Z3_fixedpoint_set_reduce_app_callback( Z3_context c, Z3_fixedpoint d, Z3_fixedpoint_reduce_app_callback_fptr cb); + typedef void (*Z3_fixedpoint_new_lemma_eh)(void *state, Z3_ast *lemma, unsigned level); + typedef void (*Z3_fixedpoint_predecessor_eh)(void *state); + typedef void (*Z3_fixedpoint_unfold_eh)(void *state); + + /** \brief set export callback for lemmas */ + void Z3_API Z3_fixedpoint_add_callback(Z3_context ctx, Z3_fixedpoint f, void *state, + Z3_fixedpoint_new_lemma_eh new_lemma_eh, + Z3_fixedpoint_predecessor_eh predecessor_eh, + Z3_fixedpoint_unfold_eh unfold_eh); + /*@}*/ /*@}*/ diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 865c746db..a8567637c 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -588,6 +588,14 @@ namespace datalog { rel_context_base* get_rel_context() { ensure_engine(); return m_rel; } + void add_callback(void *state, + const datalog::t_new_lemma_eh new_lemma_eh, + const datalog::t_predecessor_eh predecessor_eh, + const datalog::t_unfold_eh unfold_eh) { + ensure_engine(); + m_engine->add_callback(state, new_lemma_eh, predecessor_eh, unfold_eh); + } + private: /** diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index b9ac6e7b5..910dd2695 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -36,6 +36,10 @@ namespace datalog { LAST_ENGINE }; + typedef void (*t_new_lemma_eh)(void *state, expr *lemma, unsigned level); + typedef void (*t_predecessor_eh)(void *state); + typedef void (*t_unfold_eh)(void *state); + class engine_base { ast_manager& m; std::string m_name; @@ -102,6 +106,12 @@ namespace datalog { virtual proof_ref get_proof() { return proof_ref(m.mk_asserted(m.mk_true()), m); } + virtual void add_callback(void *state, + const t_new_lemma_eh new_lemma_eh, + const t_predecessor_eh predecessor_eh, + const t_unfold_eh unfold_eh) { + throw default_exception(std::string("add_lemma_exchange_callbacks is not supported for ") + m_name); + } virtual void updt_params() {} virtual void cancel() {} virtual void cleanup() {} diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 277399b9f..07b555095 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -190,7 +190,9 @@ def_module_params('fixedpoint', ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints'), ('spacer.use_quant_generalizer', BOOL, False, 'use quantified lemma generalizer'), ('spacer.quic_gen_normalize', BOOL, True, 'normalize cube before quantified generalization'), - )) + ('spacer.share_lemmas', BOOL, False, "Share frame lemmas"), + ('spacer.share_invariants', BOOL, False, "Share invariants lemmas"), +)) diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 16ce3e4f9..a351ea353 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -23,6 +23,7 @@ z3_add_component(spacer spacer_term_graph.cpp spacer_sem_matcher.cpp spacer_quant_generalizer.cpp + spacer_callback.cpp COMPONENT_DEPENDENCIES arith_tactics core_tactics diff --git a/src/muz/spacer/spacer_callback.cpp b/src/muz/spacer/spacer_callback.cpp new file mode 100644 index 000000000..9c7c88ad9 --- /dev/null +++ b/src/muz/spacer/spacer_callback.cpp @@ -0,0 +1,38 @@ +/**++ +Copyright (c) 2017 Microsoft Corporation and Matteo Marescotti + +Module Name: + + spacer_callback.cpp + +Abstract: + + SPACER plugin for handling events + +Author: + + Matteo Marescotti + +Notes: + +--*/ + +#include "spacer_callback.h" +#include "muz/spacer/spacer_context.h" + + +namespace spacer { + + void user_callback::new_lemma_eh(expr *lemma, unsigned level) { + m_new_lemma_eh(m_state, lemma, level); + } + + void user_callback::predecessor_eh() { + m_predecessor_eh(m_state); + } + + void user_callback::unfold_eh() { + m_unfold_eh(m_state); + } + +} \ No newline at end of file diff --git a/src/muz/spacer/spacer_callback.h b/src/muz/spacer/spacer_callback.h new file mode 100644 index 000000000..d5b47b90e --- /dev/null +++ b/src/muz/spacer/spacer_callback.h @@ -0,0 +1,65 @@ +/**++ +Copyright (c) 2017 Microsoft Corporation and Matteo Marescotti + +Module Name: + + spacer_callback.h + +Abstract: + + SPACER plugin for handling events + +Author: + + Matteo Marescotti + +Notes: + +--*/ + +#ifndef _SPACER_CALLBACK_H_ +#define _SPACER_CALLBACK_H_ + +#include "muz/spacer/spacer_context.h" +#include "muz/base/dl_engine_base.h" + + +namespace spacer { + + class user_callback : public spacer_callback { + private: + void *m_state; + const datalog::t_new_lemma_eh m_new_lemma_eh; + const datalog::t_predecessor_eh m_predecessor_eh; + const datalog::t_unfold_eh m_unfold_eh; + + public: + user_callback(context &context, + void *state, + const datalog::t_new_lemma_eh new_lemma_eh, + const datalog::t_predecessor_eh predecessor_eh, + const datalog::t_unfold_eh unfold_eh) : + spacer_callback(context), + m_state(state), + m_new_lemma_eh(new_lemma_eh), + m_predecessor_eh(predecessor_eh), + m_unfold_eh(unfold_eh) {} + + inline bool new_lemma() override { return true; } + + void new_lemma_eh(expr *lemma, unsigned level) override; + + inline bool predecessor() override { return true; } + + void predecessor_eh() override; + + inline bool unfold() override { return true; } + + void unfold_eh() override; + + }; + +} + + +#endif //_SPACER_CALLBACK_H_ diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index eba51c793..726edadc1 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1178,7 +1178,7 @@ lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : m_ref_count(0), m(manager), m_body(body, m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(lvl), - m_pob(nullptr) { + m_pob(nullptr), m_external(false) { SASSERT(m_body); normalize(m_body, m_body); } @@ -1187,7 +1187,7 @@ lemma::lemma(pob_ref const &p) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(p->level()), - m_pob(p) { + m_pob(p), m_external(false) { SASSERT(m_pob); m_pob->get_skolems(m_zks); add_binding(m_pob->get_binding()); @@ -1198,7 +1198,7 @@ lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : m(p->get_ast_manager()), m_body(m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(p->level()), - m_pob(p) + m_pob(p), m_external(false) { if (m_pob) { m_pob->get_skolems(m_zks); @@ -1408,6 +1408,10 @@ bool pred_transformer::frames::add_lemma(lemma *lem) m_lemmas.push_back(lem); m_sorted = false; m_pt.add_lemma_core(lem); + + if (!lem->external()) { + m_pt.get_context().new_lemma_eh(m_pt, lem); + } return true; } @@ -2726,6 +2730,11 @@ lbool context::solve_core (unsigned from_lvl) if (lvl > 0 && !get_params ().spacer_skip_propagate ()) if (propagate(m_expanded_lvl, lvl, UINT_MAX)) { return l_false; } + for (unsigned i = 0; i < m_callbacks.size(); i++){ + if (m_callbacks[i]->unfold()) + m_callbacks[i]->unfold_eh(); + } + m_pob_queue.inc_level (); lvl = m_pob_queue.max_level (); m_stats.m_max_depth = std::max(m_stats.m_max_depth, lvl); @@ -3009,6 +3018,11 @@ lbool context::expand_node(pob& n) tout << "This pob can be blocked by instantiation\n";); } + for (unsigned i = 0; i < m_callbacks.size(); i++){ + if(m_callbacks[i]->predecessor()) + m_callbacks[i]->predecessor_eh(); + } + lbool res = n.pt ().is_reachable (n, &cube, &model, uses_level, is_concrete, r, reach_pred_used, num_reuse_reach); checkpoint (); @@ -3480,6 +3494,9 @@ void context::collect_statistics(statistics& st) const // -- time in creating new predecessors st.update ("time.spacer.solve.reach.children", m_create_children_watch.get_seconds ()); + st.update("spacer.random_seed", m_params.spacer_random_seed()); + st.update("spacer.lemmas_imported", m_stats.m_num_lemmas_imported); + st.update("spacer.lemmas_discarded", m_stats.m_num_lemmas_discarded); m_pm.collect_statistics(st); for (unsigned i = 0; i < m_lemma_generalizers.size(); ++i) { @@ -3588,8 +3605,38 @@ void context::add_constraints (unsigned level, const expr_ref& c) if (m.is_implies(c, e1, e2)) { SASSERT (is_app (e1)); pred_transformer *r = nullptr; - if (m_rels.find (to_app (e1)->get_decl (), r)) - { r->add_lemma(e2, level); } + if (m_rels.find (to_app (e1)->get_decl (), r)){ + lemma_ref lem = alloc(lemma, m, e2, level); + lem.get()->set_external(true); + if (r->add_lemma(lem.get())) { + this->m_stats.m_num_lemmas_imported++; + } + else{ + this->m_stats.m_num_lemmas_discarded++; + } + } + } + } +} + +void context::new_lemma_eh(pred_transformer &pt, lemma *lem) { + bool handle=false; + for (unsigned i = 0; i < m_callbacks.size(); i++) { + handle|=m_callbacks[i]->new_lemma(); + } + if (!handle) + return; + if ((is_infty_level(lem->level()) && m_params.spacer_share_invariants()) || + (!is_infty_level(lem->level()) && m_params.spacer_share_lemmas())) { + expr_ref_vector args(m); + for (unsigned i = 0; i < pt.sig_size(); ++i) { + args.push_back(m.mk_const(pt.get_manager().o2n(pt.sig(i), 0))); + } + expr *app = m.mk_app(pt.head(), pt.sig_size(), args.c_ptr()); + expr *lemma = m.mk_implies(app, lem->get_expr()); + for (unsigned i = 0; i < m_callbacks.size(); i++) { + if (m_callbacks[i]->new_lemma()) + m_callbacks[i]->new_lemma_eh(lemma, lem->level()); } } } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index e909cd9ad..8b8055ad5 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -28,7 +28,7 @@ Notes: #undef max #endif #include - +#include "util/scoped_ptr_vector.h" #include "muz/spacer/spacer_manager.h" #include "muz/spacer/spacer_prop_solver.h" @@ -114,6 +114,7 @@ class lemma { app_ref_vector m_bindings; unsigned m_lvl; pob_ref m_pob; + bool m_external; void mk_expr_core(); void mk_cube_core(); @@ -135,6 +136,9 @@ public: void add_skolem(app *zk, app* b); + inline void set_external(bool ext){m_external = ext;} + inline bool external() { return m_external;} + unsigned level () const {return m_lvl;} void set_level (unsigned lvl) {m_lvl = lvl;} app_ref_vector& get_bindings() {return m_bindings;} @@ -685,6 +689,32 @@ public: }; +class spacer_callback { +protected: + context &m_context; + +public: + spacer_callback(context &context) : m_context(context) {} + + virtual ~spacer_callback() = default; + + context &get_context() { return m_context; } + + virtual inline bool new_lemma() { return false; } + + virtual void new_lemma_eh(expr *lemma, unsigned level) {} + + virtual inline bool predecessor() { return false; } + + virtual void predecessor_eh() {} + + virtual inline bool unfold() { return false; } + + virtual void unfold_eh() {} + +}; + + class context { struct stats { @@ -697,6 +727,8 @@ class context { unsigned m_expand_node_undef; unsigned m_num_lemmas; unsigned m_num_restarts; + unsigned m_num_lemmas_imported; + unsigned m_num_lemmas_discarded; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -731,6 +763,7 @@ class context { bool m_weak_abs; bool m_use_restarts; unsigned m_restart_initial_threshold; + scoped_ptr_vector m_callbacks; // Functions used by search. lbool solve_core (unsigned from_lvl = 0); @@ -850,6 +883,10 @@ public: expr_ref get_constraints (unsigned lvl); void add_constraints (unsigned lvl, const expr_ref& c); + + void new_lemma_eh(pred_transformer &pt, lemma *lem); + + scoped_ptr_vector &callbacks() {return m_callbacks;} }; inline bool pred_transformer::use_native_mbp () {return ctx.use_native_mbp ();} diff --git a/src/muz/spacer/spacer_dl_interface.cpp b/src/muz/spacer/spacer_dl_interface.cpp index 52209454d..571687e16 100644 --- a/src/muz/spacer/spacer_dl_interface.cpp +++ b/src/muz/spacer/spacer_dl_interface.cpp @@ -34,6 +34,7 @@ Revision History: #include "model/model_smt2_pp.h" #include "ast/scoped_proof.h" #include "muz/transforms/dl_transforms.h" +#include "muz/spacer/spacer_callback.h" using namespace spacer; @@ -352,3 +353,10 @@ proof_ref dl_interface::get_proof() { return m_context->get_proof(); } + +void dl_interface::add_callback(void *state, + const datalog::t_new_lemma_eh new_lemma_eh, + const datalog::t_predecessor_eh predecessor_eh, + const datalog::t_unfold_eh unfold_eh){ + m_context->callbacks().push_back(alloc(user_callback, *m_context, state, new_lemma_eh, predecessor_eh, unfold_eh)); +} diff --git a/src/muz/spacer/spacer_dl_interface.h b/src/muz/spacer/spacer_dl_interface.h index e5a41427d..fb5ac3803 100644 --- a/src/muz/spacer/spacer_dl_interface.h +++ b/src/muz/spacer/spacer_dl_interface.h @@ -79,6 +79,11 @@ public: proof_ref get_proof() override; + void add_callback(void *state, + const datalog::t_new_lemma_eh new_lemma_eh, + const datalog::t_predecessor_eh predecessor_eh, + const datalog::t_unfold_eh unfold_eh); + }; } From 65885f7ebad4c4e8227c248f8073e20c5262c174 Mon Sep 17 00:00:00 2001 From: Matteo Date: Tue, 17 Oct 2017 16:55:52 +0200 Subject: [PATCH 0972/1283] add_constraint API --- src/api/api_datalog.cpp | 4 +++ src/api/z3_fixedpoint.h | 4 ++- src/muz/base/dl_context.h | 5 ++++ src/muz/base/dl_engine_base.h | 3 +++ src/muz/spacer/spacer_callback.h | 6 ++--- src/muz/spacer/spacer_context.cpp | 37 +++++++++++--------------- src/muz/spacer/spacer_context.h | 2 +- src/muz/spacer/spacer_dl_interface.cpp | 4 +++ src/muz/spacer/spacer_dl_interface.h | 2 ++ 9 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 7d2e38269..fd31a65f8 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -619,6 +619,10 @@ extern "C" { Z3_CATCH; } + void Z3_API Z3_fixedpoint_add_constraint (Z3_context c, Z3_fixedpoint d, Z3_ast e, unsigned lvl){ + to_fixedpoint_ref(d)->ctx().add_constraint(to_expr(e), lvl); + } + #include "api_datalog_spacer.inc" }; diff --git a/src/api/z3_fixedpoint.h b/src/api/z3_fixedpoint.h index 6836c4766..b4c3eee49 100644 --- a/src/api/z3_fixedpoint.h +++ b/src/api/z3_fixedpoint.h @@ -367,7 +367,7 @@ extern "C" { void Z3_API Z3_fixedpoint_set_reduce_app_callback( Z3_context c, Z3_fixedpoint d, Z3_fixedpoint_reduce_app_callback_fptr cb); - typedef void (*Z3_fixedpoint_new_lemma_eh)(void *state, Z3_ast *lemma, unsigned level); + typedef void (*Z3_fixedpoint_new_lemma_eh)(void *state, Z3_ast lemma, unsigned level); typedef void (*Z3_fixedpoint_predecessor_eh)(void *state); typedef void (*Z3_fixedpoint_unfold_eh)(void *state); @@ -377,6 +377,8 @@ extern "C" { Z3_fixedpoint_predecessor_eh predecessor_eh, Z3_fixedpoint_unfold_eh unfold_eh); + void Z3_fixedpoint_add_constraint (Z3_context c, Z3_fixedpoint d, Z3_ast e, unsigned lvl); + /*@}*/ /*@}*/ diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index a8567637c..b49c7e665 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -596,6 +596,11 @@ namespace datalog { m_engine->add_callback(state, new_lemma_eh, predecessor_eh, unfold_eh); } + void add_constraint (expr *c, unsigned lvl){ + ensure_engine(); + m_engine->add_constraint(c, lvl); + } + private: /** diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index 910dd2695..9fc90ab1d 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -112,6 +112,9 @@ namespace datalog { const t_unfold_eh unfold_eh) { throw default_exception(std::string("add_lemma_exchange_callbacks is not supported for ") + m_name); } + virtual void add_constraint (expr *c, unsigned lvl){ + throw default_exception(std::string("add_constraint is not supported for ") + m_name); + } virtual void updt_params() {} virtual void cancel() {} virtual void cleanup() {} diff --git a/src/muz/spacer/spacer_callback.h b/src/muz/spacer/spacer_callback.h index d5b47b90e..35805c7bc 100644 --- a/src/muz/spacer/spacer_callback.h +++ b/src/muz/spacer/spacer_callback.h @@ -45,15 +45,15 @@ namespace spacer { m_predecessor_eh(predecessor_eh), m_unfold_eh(unfold_eh) {} - inline bool new_lemma() override { return true; } + inline bool new_lemma() override { return m_new_lemma_eh != nullptr; } void new_lemma_eh(expr *lemma, unsigned level) override; - inline bool predecessor() override { return true; } + inline bool predecessor() override { return m_predecessor_eh != nullptr; } void predecessor_eh() override; - inline bool unfold() override { return true; } + inline bool unfold() override { return m_unfold_eh != nullptr; } void unfold_eh() override; diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 726edadc1..a4faf88cf 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1229,21 +1229,21 @@ void lemma::mk_expr_core() { normalize(m_body, m_body); if (!m_zks.empty() && has_zk_const(m_body)) { - app_ref_vector zks(m); + app_ref_vector zks(m); zks.append(m_zks); - zks.reverse(); - expr_abstract(m, 0, - zks.size(), (expr* const*)zks.c_ptr(), m_body, - m_body); - ptr_buffer sorts; - svector names; - for (unsigned i=0, sz=zks.size(); i < sz; ++i) { - sorts.push_back(get_sort(zks.get(i))); - names.push_back(zks.get(i)->get_decl()->get_name()); - } - m_body = m.mk_quantifier(true, zks.size(), - sorts.c_ptr(), - names.c_ptr(), + zks.reverse(); + expr_abstract(m, 0, + zks.size(), (expr* const*)zks.c_ptr(), m_body, + m_body); + ptr_buffer sorts; + svector names; + for (unsigned i=0, sz=zks.size(); i < sz; ++i) { + sorts.push_back(get_sort(zks.get(i))); + names.push_back(zks.get(i)->get_decl()->get_name()); + } + m_body = m.mk_quantifier(true, zks.size(), + sorts.c_ptr(), + names.c_ptr(), m_body, 15, symbol(m_body->get_id())); } SASSERT(m_body); @@ -3590,17 +3590,11 @@ expr_ref context::get_constraints (unsigned level) return m_pm.mk_and (constraints); } -void context::add_constraints (unsigned level, const expr_ref& c) +void context::add_constraint (unsigned level, const expr_ref& c) { if (!c.get()) { return; } if (m.is_true(c)) { return; } - expr_ref_vector constraints (m); - constraints.push_back (c); - flatten_and (constraints); - - for (unsigned i = 0, sz = constraints.size(); i < sz; ++i) { - expr *c = constraints.get (i); expr *e1, *e2; if (m.is_implies(c, e1, e2)) { SASSERT (is_app (e1)); @@ -3613,7 +3607,6 @@ void context::add_constraints (unsigned level, const expr_ref& c) } else{ this->m_stats.m_num_lemmas_discarded++; - } } } } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 8b8055ad5..9d6d8d0a5 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -882,7 +882,7 @@ public: pob& get_root() const { return m_pob_queue.get_root(); } expr_ref get_constraints (unsigned lvl); - void add_constraints (unsigned lvl, const expr_ref& c); + void add_constraint (unsigned lvl, const expr_ref& c); void new_lemma_eh(pred_transformer &pt, lemma *lem); diff --git a/src/muz/spacer/spacer_dl_interface.cpp b/src/muz/spacer/spacer_dl_interface.cpp index 571687e16..57c225b38 100644 --- a/src/muz/spacer/spacer_dl_interface.cpp +++ b/src/muz/spacer/spacer_dl_interface.cpp @@ -360,3 +360,7 @@ void dl_interface::add_callback(void *state, const datalog::t_unfold_eh unfold_eh){ m_context->callbacks().push_back(alloc(user_callback, *m_context, state, new_lemma_eh, predecessor_eh, unfold_eh)); } + +void dl_interface::add_constraint (expr *c, unsigned lvl){ + m_context->add_constraint(c,lvl); +} diff --git a/src/muz/spacer/spacer_dl_interface.h b/src/muz/spacer/spacer_dl_interface.h index fb5ac3803..2980e2a0f 100644 --- a/src/muz/spacer/spacer_dl_interface.h +++ b/src/muz/spacer/spacer_dl_interface.h @@ -84,6 +84,8 @@ public: const datalog::t_predecessor_eh predecessor_eh, const datalog::t_unfold_eh unfold_eh); + void add_constraint (expr *c, unsigned lvl); + }; } From ff7c949be89dab7973583ee605104bc2a325b0d9 Mon Sep 17 00:00:00 2001 From: Matteo Marescotti Date: Thu, 15 Mar 2018 16:28:45 -0400 Subject: [PATCH 0973/1283] Fix: call collect_statistics() in virtual_solver --- src/muz/spacer/spacer_virtual_solver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 9dc20c241..162f56178 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -80,7 +80,7 @@ public: void get_unsat_core(ptr_vector &r) override; void assert_expr_core(expr *e) override; - void collect_statistics(statistics &st) const override {} + void collect_statistics(statistics &st) const override {m_context.collect_statistics(st);} void get_model_core(model_ref &m) override {m_context.get_model(m);} proof* get_proof() override; std::string reason_unknown() const override From 28ef9ab9d14f220268df53db721969bea9e0458e Mon Sep 17 00:00:00 2001 From: Matteo Marescotti Date: Thu, 15 Mar 2018 16:30:42 -0400 Subject: [PATCH 0974/1283] User option to enable starting spacer from a given level --- src/muz/base/fixedpoint_params.pyg | 3 ++- src/muz/spacer/spacer_dl_interface.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 07b555095..dc051bd71 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -192,7 +192,8 @@ def_module_params('fixedpoint', ('spacer.quic_gen_normalize', BOOL, True, 'normalize cube before quantified generalization'), ('spacer.share_lemmas', BOOL, False, "Share frame lemmas"), ('spacer.share_invariants', BOOL, False, "Share invariants lemmas"), -)) + ('spacer.from_level', UINT, 0, 'starting level to explore') + )) diff --git a/src/muz/spacer/spacer_dl_interface.cpp b/src/muz/spacer/spacer_dl_interface.cpp index 57c225b38..69e5d76ff 100644 --- a/src/muz/spacer/spacer_dl_interface.cpp +++ b/src/muz/spacer/spacer_dl_interface.cpp @@ -170,7 +170,7 @@ lbool dl_interface::query(expr * query) return l_false; } - return m_context->solve(); + return m_context->solve(m_ctx.get_params().spacer_from_level()); } From 3248f57434c84ad4e310aad0bbb3d8ce9d51283c Mon Sep 17 00:00:00 2001 From: Matteo Marescotti Date: Thu, 15 Mar 2018 16:31:22 -0400 Subject: [PATCH 0975/1283] Add support for printing spacer pobs in JSON --- src/muz/spacer/CMakeLists.txt | 1 + src/muz/spacer/spacer_json.cpp | 155 +++++++++++++++++++++++++++++++++ src/muz/spacer/spacer_json.h | 68 +++++++++++++++ 3 files changed, 224 insertions(+) create mode 100644 src/muz/spacer/spacer_json.cpp create mode 100644 src/muz/spacer/spacer_json.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index a351ea353..50e0c9382 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -24,6 +24,7 @@ z3_add_component(spacer spacer_sem_matcher.cpp spacer_quant_generalizer.cpp spacer_callback.cpp + spacer_json.cpp COMPONENT_DEPENDENCIES arith_tactics core_tactics diff --git a/src/muz/spacer/spacer_json.cpp b/src/muz/spacer/spacer_json.cpp new file mode 100644 index 000000000..0bfa091c1 --- /dev/null +++ b/src/muz/spacer/spacer_json.cpp @@ -0,0 +1,155 @@ +/**++ +Copyright (c) 2017 Microsoft Corporation and Matteo Marescotti + +Module Name: + + spacer_json.cpp + +Abstract: + + SPACER json marshalling support + +Author: + + Matteo Marescotti + +Notes: + +--*/ + +#include +#include "spacer_context.h" +#include "spacer_json.h" +#include "spacer_util.h" + +namespace spacer { + + std::ostream &json_marshal(std::ostream &out, ast *t, ast_manager &m) { + + mk_epp pp = mk_epp(t, m); + std::ostringstream ss; + ss << pp; + out << "\""; + for (auto &c:ss.str()) { + switch (c) { + case '"': + out << "\\\""; + break; + case '\\': + out << "\\\\"; + break; + case '\b': + out << "\\b"; + break; + case '\f': + out << "\\f"; + break; + case '\n': + out << "\\n"; + break; + case '\r': + out << "\\r"; + break; + case '\t': + out << "\\t"; + break; + default: + if ('\x00' <= c && c <= '\x1f') { + out << "\\u" + << std::hex << std::setw(4) << std::setfill('0') << (int) c; + } else { + out << c; + } + } + } + out << "\""; + return out; + } + + std::ostream &json_marshal(std::ostream &out, lemma *l) { + out << R"({"level":")" << l->level() << R"(", "expr":)"; + json_marshal(out, l->get_expr(), l->get_ast_manager()); + out << "}"; + return out; + } + + std::ostream &json_marshal(std::ostream &out, const lemma_ref_vector lemmas) { + + std::ostringstream ls; + for (auto &l:lemmas) { + ls << (ls.tellp() == 0 ? "" : ","); + json_marshal(ls, l); + } + out << "[" << ls.str() << "]"; + return out; + } + + + void json_marshaller::pob_blocked_by_lemma_eh(pob *p, lemma *l) { + //if(m_ctx->get_params().spacer_pr) + m_relations[p][p->depth()].push_back(l); + } + + void json_marshaller::new_pob_eh(pob *p) { + m_relations[p]; + } + + std::ostream &spacer::json_marshaller::marshal(std::ostream &out) const { + std::ostringstream nodes; + std::ostringstream edges; + std::ostringstream lemmas; + + unsigned pob_id = 0; + for (auto &pob_map:m_relations) { + std::ostringstream pob_lemmas; + for (auto &depth_lemmas : pob_map.second) { + pob_lemmas << (pob_lemmas.tellp() == 0 ? "" : ",") << "\"" << depth_lemmas.first << "\":"; + json_marshal(pob_lemmas, depth_lemmas.second); + } + if (pob_lemmas.tellp()) { + lemmas << (lemmas.tellp() == 0 ? "" : ",\n"); + lemmas << "\"" << pob_id << "\":{" << pob_lemmas.str() << "}"; + } + } + + unsigned depth = 0; + while (true) { + double root_expand_time = m_ctx->get_root().get_expand_time(depth); + bool a = false; + unsigned i = 0; + for (auto &pob_map:m_relations) { + pob_ref n = pob_map.first; + double expand_time = n->get_expand_time(depth); + if (expand_time > 0) { + a = true; + std::ostringstream pob_expr; + json_marshal(pob_expr, n->post(), n->get_ast_manager()); + + nodes << (nodes.tellp() == 0 ? "" : ",\n") << + "{\"id\":\"" << depth << n << + "\",\"relative_time\":\"" << expand_time / root_expand_time << + "\",\"absolute_time\":\"" << std::setprecision(2) << expand_time << + "\",\"predicate\":\"" << n->pt().head()->get_name() << + "\",\"expr_id\":\"" << n->post()->get_id() << + "\",\"pob_id\":\"" << i << + "\",\"depth\":\"" << depth << + "\",\"expr\":" << pob_expr.str() << "}"; + if (n->parent()) { + edges << (edges.tellp() == 0 ? "" : ",\n") << + "{\"from\":\"" << depth << n->parent() << + "\",\"to\":\"" << depth << n << "\"}"; + } + } + } + if (!a) { + break; + } + depth++; + } + out << "{\n\"nodes\":[\n" << nodes.str() << "\n],\n"; + out << "\"edges\":[\n" << edges.str() << "\n],\n"; + out << "\"lemmas\":{\n" << lemmas.str() << "\n}\n}\n"; + return out; + } + +} diff --git a/src/muz/spacer/spacer_json.h b/src/muz/spacer/spacer_json.h new file mode 100644 index 000000000..dc411f67c --- /dev/null +++ b/src/muz/spacer/spacer_json.h @@ -0,0 +1,68 @@ +/**++ +Copyright (c) 2017 Microsoft Corporation and Matteo Marescotti + +Module Name: + + spacer_json.h + +Abstract: + + SPACER json marshalling support + +Author: + + Matteo Marescotti + +Notes: + +--*/ + +#ifndef Z3_SPACER_JSON_H +#define Z3_SPACER_JSON_H + +#include +#include +#include "ref.h" +#include "ref_vector.h" + +class ast; + +class ast_manager; + +namespace spacer { + + class lemma; + + typedef sref_vector lemma_ref_vector; + + class context; + + class pob; + + typedef ref pob_ref; + + std::ostream &json_marshal(std::ostream &out, ast *t, ast_manager &m); + + std::ostream &json_marshal(std::ostream &out, lemma *l); + + std::ostream &json_marshal(std::ostream &out, lemma_ref_vector &lemmas); + + + class json_marshaller { + context *m_ctx; + std::map> m_relations; + + public: + json_marshaller(context *ctx) : m_ctx(ctx) {} + + void pob_blocked_by_lemma_eh(pob *p, lemma *l); + + void new_pob_eh(pob *p); + + std::ostream &marshal(std::ostream &out) const; + }; + +} + + +#endif //Z3_SPACER_JSON_H From a4e67b8bb6be95e1447f11edd0bd6fae96781146 Mon Sep 17 00:00:00 2001 From: Matteo Marescotti Date: Thu, 15 Mar 2018 19:11:47 -0400 Subject: [PATCH 0976/1283] Wire JSON printing into Spacer --- src/muz/base/fixedpoint_params.pyg | 3 ++- src/muz/spacer/spacer_context.cpp | 43 +++++++++++++++++++++++++++--- src/muz/spacer/spacer_context.h | 40 +++++++++++++++++++++++++-- src/muz/spacer/spacer_json.cpp | 21 ++++++++------- src/muz/spacer/spacer_json.h | 8 +++--- 5 files changed, 95 insertions(+), 20 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index dc051bd71..74903baf1 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -192,7 +192,8 @@ def_module_params('fixedpoint', ('spacer.quic_gen_normalize', BOOL, True, 'normalize cube before quantified generalization'), ('spacer.share_lemmas', BOOL, False, "Share frame lemmas"), ('spacer.share_invariants', BOOL, False, "Share invariants lemmas"), - ('spacer.from_level', UINT, 0, 'starting level to explore') + ('spacer.from_level', UINT, 0, 'starting level to explore'), + ('spacer.print_json', SYMBOL, '', 'print pobs tree in JSON format to a given file') )) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index a4faf88cf..75a9d7d81 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1353,6 +1353,14 @@ void lemma::instantiate(expr * const * exprs, expr_ref &result, expr *e) { vs(body, num_decls, exprs, result); } +void lemma::set_level (unsigned lvl) { + if(m_pob){ + m_pob->blocked_at(lvl); + } + m_lvl = lvl; +} + + void lemma::mk_insts(expr_ref_vector &out, expr* e) { expr *lem = e == nullptr ? get_expr() : e; @@ -1376,6 +1384,7 @@ bool pred_transformer::frames::add_lemma(lemma *lem) for (unsigned i = 0, sz = m_lemmas.size(); i < sz; ++i) { if (m_lemmas [i]->get_expr() == lem->get_expr()) { + m_pt.get_context().new_lemma_eh(m_pt, lem); // extend bindings if needed if (!lem->get_bindings().empty()) { m_lemmas [i]->add_binding(lem->get_bindings()); @@ -1879,7 +1888,8 @@ pob::pob (pob* parent, pred_transformer& pt, m_binding(m_pt.get_ast_manager()), m_new_post (m_pt.get_ast_manager ()), m_level (level), m_depth (depth), - m_open (true), m_use_farkas (true), m_weakness(0) { + m_open (true), m_use_farkas (true), m_weakness(0), + m_blocked_lvl(0) { if(add_to_parent && m_parent) { m_parent->add_child(*this); } @@ -1994,6 +2004,11 @@ void pob_queue::reset() if (m_root) { m_obligations.push(m_root); } } +void pob_queue::push(pob &n) { + m_obligations.push (&n); + n.get_context().new_pob_eh(&n); +} + // ---------------- // context @@ -2015,7 +2030,8 @@ context::context(fixedpoint_params const& params, m_use_qlemmas (params.spacer_qlemmas ()), m_weak_abs(params.spacer_weak_abs()), m_use_restarts(params.spacer_restarts()), - m_restart_initial_threshold(params.spacer_restart_initial_threshold()) + m_restart_initial_threshold(params.spacer_restart_initial_threshold()), + m_json_marshaller(this) {} context::~context() @@ -2728,7 +2744,13 @@ lbool context::solve_core (unsigned from_lvl) if (check_reachability()) { return l_true; } if (lvl > 0 && !get_params ().spacer_skip_propagate ()) - if (propagate(m_expanded_lvl, lvl, UINT_MAX)) { return l_false; } + if (propagate(m_expanded_lvl, lvl, UINT_MAX)) { dump_json(); return l_false; } + + dump_json(); + + if (is_inductive()){ + return l_false; + } for (unsigned i = 0; i < m_callbacks.size(); i++){ if (m_callbacks[i]->unfold()) @@ -2963,6 +2985,7 @@ bool context::is_reachable(pob &n) //this processes a goal and creates sub-goal lbool context::expand_node(pob& n) { + pob::on_expand_event _evt(n); TRACE ("spacer", tout << "expand-node: " << n.pt().head()->get_name() << " level: " << n.level() @@ -3613,6 +3636,8 @@ void context::add_constraint (unsigned level, const expr_ref& c) } void context::new_lemma_eh(pred_transformer &pt, lemma *lem) { + if (m_params.spacer_print_json().size()) + m_json_marshaller.register_lemma(lem); bool handle=false; for (unsigned i = 0; i < m_callbacks.size(); i++) { handle|=m_callbacks[i]->new_lemma(); @@ -3634,6 +3659,18 @@ void context::new_lemma_eh(pred_transformer &pt, lemma *lem) { } } +void context::new_pob_eh(pob *p) { + if (m_params.spacer_print_json().size()) + m_json_marshaller.register_pob(p); +} + +bool context::is_inductive() { + // check that inductive level (F infinity) of the query predicate + // contains a constant false + + return false; +} + inline bool pob_lt::operator() (const pob *pn1, const pob *pn2) const { SASSERT (pn1); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 9d6d8d0a5..ff0e90cfa 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -31,6 +31,7 @@ Notes: #include "util/scoped_ptr_vector.h" #include "muz/spacer/spacer_manager.h" #include "muz/spacer/spacer_prop_solver.h" +#include "muz/spacer/spacer_json.h" #include "muz/base/fixedpoint_params.hpp" @@ -140,7 +141,7 @@ public: inline bool external() { return m_external;} unsigned level () const {return m_lvl;} - void set_level (unsigned lvl) {m_lvl = lvl;} + void set_level (unsigned lvl); app_ref_vector& get_bindings() {return m_bindings;} bool has_binding(app_ref_vector const &binding); void add_binding(app_ref_vector const &binding); @@ -475,6 +476,10 @@ class pob { scoped_ptr m_derivation; ptr_vector m_kids; + + // depth -> watch + std::map m_expand_watches; + unsigned m_blocked_lvl; public: pob (pob* parent, pred_transformer& pt, unsigned level, unsigned depth=0, bool add_to_parent=true); @@ -504,6 +509,8 @@ public: unsigned level () const { return m_level; } unsigned depth () const {return m_depth;} + unsigned width () const {return m_kids.size();} + unsigned blocked_at(unsigned lvl=0){return (m_blocked_lvl = std::max(lvl, m_blocked_lvl)); } bool use_farkas_generalizer () const {return m_use_farkas;} void set_farkas_generalizer (bool v) {m_use_farkas = v;} @@ -537,6 +544,10 @@ public: */ void get_skolems(app_ref_vector& v); + void on_expand() { m_expand_watches[m_depth].start(); if(m_parent.get()){m_parent.get()->on_expand();} } + void off_expand() { m_expand_watches[m_depth].stop(); if(m_parent.get()){m_parent.get()->off_expand();} }; + double get_expand_time(unsigned depth) { return m_expand_watches[depth].get_seconds();} + void inc_ref () {++m_ref_count;} void dec_ref () { @@ -544,6 +555,13 @@ public: if(m_ref_count == 0) { dealloc(this); } } + class on_expand_event + { + pob &m_p; + public: + on_expand_event(pob &p) : m_p(p) {m_p.on_expand();} + ~on_expand_event() {m_p.off_expand();} + }; }; @@ -653,7 +671,7 @@ public: void reset(); pob * top (); void pop () {m_obligations.pop ();} - void push (pob &n) {m_obligations.push (&n);} + void push (pob &n); void inc_level () { @@ -712,6 +730,10 @@ public: virtual void unfold_eh() {} + virtual inline bool propagate() { return false; } + + virtual void propagate_eh() {} + }; @@ -764,6 +786,7 @@ class context { bool m_use_restarts; unsigned m_restart_initial_threshold; scoped_ptr_vector m_callbacks; + json_marshaller m_json_marshaller; // Functions used by search. lbool solve_core (unsigned from_lvl = 0); @@ -803,6 +826,15 @@ class context { unsigned get_cex_depth (); + void dump_json() { + if(m_params.spacer_print_json().size()) { + std::ofstream of; + of.open(m_params.spacer_print_json().bare_str()); + m_json_marshaller.marshal(of); + of.close(); + } + } + public: /** Initial values of predicates are stored in corresponding relations in dctx. @@ -887,6 +919,10 @@ public: void new_lemma_eh(pred_transformer &pt, lemma *lem); scoped_ptr_vector &callbacks() {return m_callbacks;} + + void new_pob_eh(pob *p); + + bool is_inductive(); }; inline bool pred_transformer::use_native_mbp () {return ctx.use_native_mbp ();} diff --git a/src/muz/spacer/spacer_json.cpp b/src/muz/spacer/spacer_json.cpp index 0bfa091c1..8b7a0878e 100644 --- a/src/muz/spacer/spacer_json.cpp +++ b/src/muz/spacer/spacer_json.cpp @@ -73,10 +73,10 @@ namespace spacer { return out; } - std::ostream &json_marshal(std::ostream &out, const lemma_ref_vector lemmas) { + std::ostream &json_marshal(std::ostream &out, const lemma_ref_vector &lemmas) { std::ostringstream ls; - for (auto &l:lemmas) { + for (auto l:lemmas) { ls << (ls.tellp() == 0 ? "" : ","); json_marshal(ls, l); } @@ -85,12 +85,13 @@ namespace spacer { } - void json_marshaller::pob_blocked_by_lemma_eh(pob *p, lemma *l) { - //if(m_ctx->get_params().spacer_pr) - m_relations[p][p->depth()].push_back(l); + void json_marshaller::register_lemma(lemma *l) { + if (l->has_pob()) { + m_relations[&*l->get_pob()][l->get_pob()->depth()].push_back(l); + } } - void json_marshaller::new_pob_eh(pob *p) { + void json_marshaller::register_pob(pob *p) { m_relations[p]; } @@ -110,15 +111,16 @@ namespace spacer { lemmas << (lemmas.tellp() == 0 ? "" : ",\n"); lemmas << "\"" << pob_id << "\":{" << pob_lemmas.str() << "}"; } + pob_id++; } unsigned depth = 0; while (true) { double root_expand_time = m_ctx->get_root().get_expand_time(depth); bool a = false; - unsigned i = 0; + pob_id = 0; for (auto &pob_map:m_relations) { - pob_ref n = pob_map.first; + pob *n = pob_map.first; double expand_time = n->get_expand_time(depth); if (expand_time > 0) { a = true; @@ -131,7 +133,7 @@ namespace spacer { "\",\"absolute_time\":\"" << std::setprecision(2) << expand_time << "\",\"predicate\":\"" << n->pt().head()->get_name() << "\",\"expr_id\":\"" << n->post()->get_id() << - "\",\"pob_id\":\"" << i << + "\",\"pob_id\":\"" << pob_id << "\",\"depth\":\"" << depth << "\",\"expr\":" << pob_expr.str() << "}"; if (n->parent()) { @@ -140,6 +142,7 @@ namespace spacer { "\",\"to\":\"" << depth << n << "\"}"; } } + pob_id++; } if (!a) { break; diff --git a/src/muz/spacer/spacer_json.h b/src/muz/spacer/spacer_json.h index dc411f67c..c75110371 100644 --- a/src/muz/spacer/spacer_json.h +++ b/src/muz/spacer/spacer_json.h @@ -39,8 +39,6 @@ namespace spacer { class pob; - typedef ref pob_ref; - std::ostream &json_marshal(std::ostream &out, ast *t, ast_manager &m); std::ostream &json_marshal(std::ostream &out, lemma *l); @@ -50,14 +48,14 @@ namespace spacer { class json_marshaller { context *m_ctx; - std::map> m_relations; + std::map> m_relations; public: json_marshaller(context *ctx) : m_ctx(ctx) {} - void pob_blocked_by_lemma_eh(pob *p, lemma *l); + void register_lemma(lemma *l); - void new_pob_eh(pob *p); + void register_pob(pob *p); std::ostream &marshal(std::ostream &out) const; }; From 247c570e6b35e5ac8dc680e71eaa2ad0a8dae308 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Mon, 27 Nov 2017 16:46:14 +0100 Subject: [PATCH 0977/1283] Debug sanity check in spacer_context Triggered by bugs in hypothesis remover only sanitycheck lemmas in debug-mode --- src/muz/spacer/spacer_context.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 75a9d7d81..f700ce83e 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -3133,7 +3133,12 @@ lbool context::expand_node(pob& n) checkpoint (); (*m_lemma_generalizers[i])(lemma); } + DEBUG_CODE( + lemma_sanity_checker sanity_checker(*this); + sanity_checker(lemma); + ); + TRACE("spacer", tout << "invariant state: " << (is_infty_level(lemma->level())?"(inductive)":"") << mk_pp(lemma->get_expr(), m) << "\n";); From 10106e8e125e011f408b91f7b45997057a5ab144 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 09:43:01 -0700 Subject: [PATCH 0978/1283] Minor fixes to ast_pp_dot --- src/ast/ast_pp_dot.cpp | 3 ++- src/ast/ast_pp_dot.h | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ast/ast_pp_dot.cpp b/src/ast/ast_pp_dot.cpp index 1dfbe9aae..47da4d4f4 100644 --- a/src/ast/ast_pp_dot.cpp +++ b/src/ast/ast_pp_dot.cpp @@ -9,7 +9,8 @@ Abstract: Pretty-printer for proofs in Graphviz format #include "ast/ast_pp_dot.h" // string escaping for DOT -std::string escape_dot(std::string const & s) { +std::string escape_dot(const std::string &s) +{ std::string res; res.reserve(s.size()); // preallocate for (auto c : s) { diff --git a/src/ast/ast_pp_dot.h b/src/ast/ast_pp_dot.h index 537754e83..d233c4be1 100644 --- a/src/ast/ast_pp_dot.h +++ b/src/ast/ast_pp_dot.h @@ -4,10 +4,11 @@ Abstract: Pretty-printer for proofs in Graphviz format --*/ -#pragma once +#ifndef _AST_PP_DOT_ +#define _AST_PP_DOT_ #include -#include "ast_pp.h" +#include "ast/ast_pp.h" class ast_pp_dot { ast_manager & m_manager; @@ -21,4 +22,8 @@ class ast_pp_dot { ast_manager & get_manager() const { return m_manager; } }; -std::ostream &operator<<(std::ostream &out, const ast_pp_dot & p); \ No newline at end of file +std::string escape_dot(std::string const & s); + +std::ostream &operator<<(std::ostream &out, const ast_pp_dot & p); + +#endif /* AST_PP_DOT */ From 56114a5f6d34e8b49fd08dab6d8dc591baff5f4d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 09:43:31 -0700 Subject: [PATCH 0979/1283] Refactor iuc_proof as a separate class This also adds DOT printing support to interpolating proofs (color for different parts) iuc_proof is a proof used for IUC computation --- src/muz/spacer/CMakeLists.txt | 1 + src/muz/spacer/spacer_itp_solver.cpp | 46 +- src/muz/spacer/spacer_iuc_proof.cpp | 235 ++++++++ src/muz/spacer/spacer_iuc_proof.h | 65 +++ src/muz/spacer/spacer_proof_utils.cpp | 535 +++++++++++++++++++ src/muz/spacer/spacer_proof_utils.h | 53 ++ src/muz/spacer/spacer_unsat_core_learner.cpp | 318 +---------- src/muz/spacer/spacer_unsat_core_learner.h | 37 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 49 +- 9 files changed, 960 insertions(+), 379 deletions(-) create mode 100644 src/muz/spacer/spacer_iuc_proof.cpp create mode 100644 src/muz/spacer/spacer_iuc_proof.h create mode 100644 src/muz/spacer/spacer_proof_utils.cpp create mode 100644 src/muz/spacer/spacer_proof_utils.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 50e0c9382..310d9a942 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -25,6 +25,7 @@ z3_add_component(spacer spacer_quant_generalizer.cpp spacer_callback.cpp spacer_json.cpp + spacer_iuc_proof.cpp COMPONENT_DEPENDENCIES arith_tactics core_tactics diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index 9cccdf43c..07c5f5871 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -23,6 +23,7 @@ Notes: #include"ast/rewriter/expr_replacer.h" #include"muz/spacer/spacer_unsat_core_learner.h" #include"muz/spacer/spacer_unsat_core_plugin.h" +#include "muz/spacer/spacer_iuc_proof.h" namespace spacer { void itp_solver::push () @@ -261,11 +262,11 @@ void itp_solver::get_itp_core (expr_ref_vector &core) B.insert (a); } - proof_ref pr(m); - pr = get_proof (); - if (m_iuc == 0) { + proof_ref pr(m); + pr = get_proof (); + // old code farkas_learner learner_old; learner_old.set_split_literals(m_split_literals); @@ -277,7 +278,19 @@ void itp_solver::get_itp_core (expr_ref_vector &core) else { // new code - unsat_core_learner learner(m, m_print_farkas_stats, m_iuc_debug_proof); + // preprocess proof in order to get a proof which is better suited for unsat-core-extraction + proof_ref pr(get_proof(), m); + + spacer::reduce_hypotheses(pr); + STRACE("spacer.unsat_core_learner", + verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n"; + ); + + // construct proof object with contains partition information + iuc_proof iuc_pr(m, get_proof(), B); + + // configure learner + unsat_core_learner learner(m, iuc_pr, m_print_farkas_stats, m_iuc_debug_proof); if (m_iuc_arith == 0 || m_iuc_arith > 3) { @@ -311,31 +324,12 @@ void itp_solver::get_itp_core (expr_ref_vector &core) learner.register_plugin(plugin_lemma); } - learner.compute_unsat_core(pr, B, core); + // compute interpolating unsat core + learner.compute_unsat_core(core); + // postprocessing, TODO: elim_proxies should be done inside iuc_proof elim_proxies (core); simplify_bounds (core); // XXX potentially redundant - -// // debug -// expr_ref_vector core2(m); -// unsat_core_learner learner2(m); -// -// unsat_core_plugin_farkas_lemma* plugin_farkas_lemma2 = alloc(unsat_core_plugin_farkas_lemma, learner2, m_split_literals); -// learner2.register_plugin(plugin_farkas_lemma2); -// unsat_core_plugin_lemma* plugin_lemma2 = alloc(unsat_core_plugin_lemma, learner2); -// learner2.register_plugin(plugin_lemma2); -// learner2.compute_unsat_core(pr, B, core2); -// -// elim_proxies (core2); -// simplify_bounds (core2); -// -// IF_VERBOSE(2, -// verbose_stream () << "Itp Core:\n" -// << mk_pp (mk_and (core), m) << "\n";); -// IF_VERBOSE(2, -// verbose_stream () << "Itp Core2:\n" -// << mk_pp (mk_and (core2), m) << "\n";); - //SASSERT(mk_and (core) == mk_and (core2)); } IF_VERBOSE(2, diff --git a/src/muz/spacer/spacer_iuc_proof.cpp b/src/muz/spacer/spacer_iuc_proof.cpp new file mode 100644 index 000000000..889f06af2 --- /dev/null +++ b/src/muz/spacer/spacer_iuc_proof.cpp @@ -0,0 +1,235 @@ + + +#include "muz/spacer/spacer_iuc_proof.h" +#include "ast/for_each_expr.h" +#include "ast/array_decl_plugin.h" +#include "muz/spacer/spacer_proof_utils.h" + +namespace spacer { + + /* + * ==================================== + * init + * ==================================== + */ + iuc_proof::iuc_proof(ast_manager& m, proof* pr, expr_set& b_conjuncts) : m(m), m_pr(pr,m) + { + // init A-marks and B-marks + collect_symbols_b(b_conjuncts); + compute_marks(b_conjuncts); + } + + proof* iuc_proof::get() + { + return m_pr.get(); + } + + /* + * ==================================== + * methods for computing symbol colors + * ==================================== + */ + class collect_pure_proc { + func_decl_set& m_symbs; + public: + collect_pure_proc(func_decl_set& s):m_symbs(s) {} + + void operator()(app* a) { + if (a->get_family_id() == null_family_id) { + m_symbs.insert(a->get_decl()); + } + } + void operator()(var*) {} + void operator()(quantifier*) {} + }; + + void iuc_proof::collect_symbols_b(expr_set& b_conjuncts) + { + expr_mark visited; + collect_pure_proc proc(m_symbols_b); + for (expr_set::iterator it = b_conjuncts.begin(); it != b_conjuncts.end(); ++it) + { + for_each_expr(proc, visited, *it); + } + } + + class is_pure_expr_proc { + func_decl_set const& m_symbs; + array_util m_au; + public: + struct non_pure {}; + + is_pure_expr_proc(func_decl_set const& s, ast_manager& m): + m_symbs(s), + m_au (m) + {} + + void operator()(app* a) { + if (a->get_family_id() == null_family_id) { + if (!m_symbs.contains(a->get_decl())) { + throw non_pure(); + } + } + else if (a->get_family_id () == m_au.get_family_id () && + a->is_app_of (a->get_family_id (), OP_ARRAY_EXT)) { + throw non_pure(); + } + } + void operator()(var*) {} + void operator()(quantifier*) {} + }; + + // requires that m_symbols_b has already been computed, which is done during initialization. + bool iuc_proof::only_contains_symbols_b(expr* expr) const + { + is_pure_expr_proc proc(m_symbols_b, m); + try { + for_each_expr(proc, expr); + } + catch (is_pure_expr_proc::non_pure) + { + return false; + } + return true; + } + + /* + * ==================================== + * methods for computing which premises + * have been used to derive the conclusions + * ==================================== + */ + + void iuc_proof::compute_marks(expr_set& b_conjuncts) + { + ProofIteratorPostOrder it(m_pr, m); + while (it.hasNext()) + { + proof* currentNode = it.next(); + + if (m.get_num_parents(currentNode) == 0) + { + switch(currentNode->get_decl_kind()) + { + + case PR_ASSERTED: // currentNode is an axiom + { + if (b_conjuncts.contains(m.get_fact(currentNode))) + { + m_b_mark.mark(currentNode, true); + } + else + { + m_a_mark.mark(currentNode, true); + } + break; + } + // currentNode is a hypothesis: + case PR_HYPOTHESIS: + { + m_h_mark.mark(currentNode, true); + break; + } + default: + { + break; + } + } + } + else + { + // collect from parents whether derivation of current node contains A-axioms, B-axioms and hypothesis + bool need_to_mark_a = false; + bool need_to_mark_b = false; + bool need_to_mark_h = false; + + for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) + { + SASSERT(m.is_proof(currentNode->get_arg(i))); + proof* premise = to_app(currentNode->get_arg(i)); + + need_to_mark_a = need_to_mark_a || m_a_mark.is_marked(premise); + need_to_mark_b = need_to_mark_b || m_b_mark.is_marked(premise); + need_to_mark_h = need_to_mark_h || m_h_mark.is_marked(premise); + } + + // if current node is application of lemma, we know that all hypothesis are removed + if(currentNode->get_decl_kind() == PR_LEMMA) + { + need_to_mark_h = false; + } + + // save results + m_a_mark.mark(currentNode, need_to_mark_a); + m_b_mark.mark(currentNode, need_to_mark_b); + m_h_mark.mark(currentNode, need_to_mark_h); + } + } + } + + bool iuc_proof::is_a_marked(proof* p) + { + return m_a_mark.is_marked(p); + } + bool iuc_proof::is_b_marked(proof* p) + { + return m_b_mark.is_marked(p); + } + bool iuc_proof::is_h_marked(proof* p) + { + return m_h_mark.is_marked(p); + } + + /* + * ==================================== + * methods for dot printing + * ==================================== + */ + void iuc_proof::pp_dot() + { + pp_proof_dot(m, m_pr, this); + } + + /* + * ==================================== + * statistics + * ==================================== + */ + + void iuc_proof::print_farkas_stats() + { + unsigned farkas_counter = 0; + unsigned farkas_counter2 = 0; + + ProofIteratorPostOrder it3(m_pr, m); + while (it3.hasNext()) + { + proof* currentNode = it3.next(); + + // if node is theory lemma + if (is_farkas_lemma(m, currentNode)) + { + farkas_counter++; + + // check whether farkas lemma is to be interpolated (could potentially miss farkas lemmas, which are interpolated, because we potentially don't want to use the lowest cut) + bool has_blue_nonred_parent = false; + for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) + { + proof* premise = to_app(currentNode->get_arg(i)); + if (!is_a_marked(premise) && is_b_marked(premise)) + { + has_blue_nonred_parent = true; + break; + } + } + if (has_blue_nonred_parent && is_a_marked(currentNode)) + { + SASSERT(is_b_marked(currentNode)); + farkas_counter2++; + } + } + } + + verbose_stream() << "\nThis proof contains " << farkas_counter << " Farkas lemmas. " << farkas_counter2 << " Farkas lemmas participate in the lowest cut\n"; + } +} diff --git a/src/muz/spacer/spacer_iuc_proof.h b/src/muz/spacer/spacer_iuc_proof.h new file mode 100644 index 000000000..205648109 --- /dev/null +++ b/src/muz/spacer/spacer_iuc_proof.h @@ -0,0 +1,65 @@ +#ifndef IUC_PROOF_H_ +#define IUC_PROOF_H_ + +#include "ast/ast.h" + +namespace spacer { + typedef obj_hashtable expr_set; + typedef obj_hashtable func_decl_set; + + /* + * an iuc_proof is a proof together with information of the coloring of the axioms. + */ + class iuc_proof + { + public: + + iuc_proof(ast_manager& m, proof* pr, expr_set& b_conjuncts); + + proof* get(); + + /* + * returns whether symbol contains only symbols which occur in B. + */ + bool only_contains_symbols_b(expr* expr) const; + + bool is_a_marked(proof* p); + bool is_b_marked(proof* p); + bool is_h_marked(proof* p); + + bool is_b_pure (proof *p) + {return !is_h_marked (p) && only_contains_symbols_b (m.get_fact (p));} + + /* + * print dot-representation to file proof.dot + * use Graphviz's dot with option -Tpdf to convert dot-representation into pdf + */ + void pp_dot(); + + void print_farkas_stats(); + private: + ast_manager& m; + proof_ref m_pr; + + ast_mark m_a_mark; + ast_mark m_b_mark; + ast_mark m_h_mark; + + func_decl_set m_symbols_b; // symbols, which occur in any b-asserted formula + + // collect symbols occuring in B + void collect_symbols_b(expr_set& b_conjuncts); + + // compute for each formula of the proof whether it derives from A and whether it derives from B + void compute_marks(expr_set& b_conjuncts); + + void pp_dot_to_stream(std::ofstream& dotstream); + std::string escape_dot(const std::string &s); + + void post_process_dot(std::string dot_filepath, std::ofstream& dotstream); + }; + + +} + +#endif /* IUC_PROOF_H_ */ diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp new file mode 100644 index 000000000..ba102e20e --- /dev/null +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -0,0 +1,535 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_proof_utils.cpp + +Abstract: + Utilities to traverse and manipulate proofs + +Author: + Bernhard Gleiss + Arie Gurfinkel + +Revision History: + +--*/ + +#include "muz/spacer/spacer_proof_utils.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" + +#include "ast/proof_checker/proof_checker.h" +#include +#include "params.h" +#include "muz/spacer/spacer_iuc_proof.h" + +namespace spacer { + + /* + * ==================================== + * methods for proof traversal + * ==================================== + */ +ProofIteratorPostOrder::ProofIteratorPostOrder(proof* root, ast_manager& manager) : m(manager) +{m_todo.push_back(root);} + +bool ProofIteratorPostOrder::hasNext() +{return !m_todo.empty();} + +/* + * iterative post-order depth-first search (DFS) through the proof DAG + */ +proof* ProofIteratorPostOrder::next() +{ + while (!m_todo.empty()) { + proof* currentNode = m_todo.back(); + + // if we haven't already visited the current unit + if (!m_visited.is_marked(currentNode)) { + bool existsUnvisitedParent = false; + + // add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result + // for currentProof now, but wait until those unprocessed premises are processed. + for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) { + SASSERT(m.is_proof(currentNode->get_arg(i))); + proof* premise = to_app(currentNode->get_arg(i)); + + // if we haven't visited the current premise yet + if (!m_visited.is_marked(premise)) { + // add it to the stack + m_todo.push_back(premise); + existsUnvisitedParent = true; + } + } + + // if we already visited all parent-inferences, we can visit the inference too + if (!existsUnvisitedParent) { + m_visited.mark(currentNode, true); + m_todo.pop_back(); + return currentNode; + } + } else { + m_todo.pop_back(); + } + } + // we have already iterated through all inferences + return NULL; +} + + /* + * ==================================== + * methods for dot printing + * ==================================== + */ + void pp_proof_dot_to_stream(ast_manager& m, std::ofstream& dotstream, proof* pr, iuc_proof* iuc_pr = nullptr); + std::string escape_dot(const std::string &s); + void pp_proof_post_process_dot(std::string dot_filepath, std::ofstream &dotstream); + + void pp_proof_dot(ast_manager& m, proof* pr, iuc_proof* iuc_pr) + { + // open temporary dot-file + std::string dotfile_path = "proof.dot"; + std::ofstream dotstream(dotfile_path); + + // dump dot representation to stream + pp_proof_dot_to_stream(m, dotstream, pr, iuc_pr); + + // post process dot-file, TODO: factor this out to a different place + pp_proof_post_process_dot(dotfile_path,dotstream); + } + + void pp_proof_dot_to_stream(ast_manager& m, std::ofstream& dotstream, proof* pr, iuc_proof* iuc_pr) + { + dotstream << "digraph proof { \n"; + std::unordered_map id_to_small_id; + unsigned counter = 0; + + ProofIteratorPostOrder it2(pr, m); + while (it2.hasNext()) + { + proof* currentNode = it2.next(); + + SASSERT(id_to_small_id.find(currentNode->get_id()) == id_to_small_id.end()); + id_to_small_id.insert(std::make_pair(currentNode->get_id(), counter)); + + std::string color = "white"; + if (iuc_pr != nullptr) + { + if (iuc_pr->is_a_marked(currentNode) && !iuc_pr->is_b_marked(currentNode)) + { + color = "red"; + } + else if(iuc_pr->is_b_marked(currentNode) && !iuc_pr->is_a_marked(currentNode)) + { + color = "blue"; + } + else if(iuc_pr->is_b_marked(currentNode) && iuc_pr->is_a_marked(currentNode)) + { + color = "purple"; + } + } + + // compute label + params_ref p; + p.set_uint("max_depth", 4294967295u); + p.set_uint("min_alias_size", 4294967295u); + + std::ostringstream label_ostream; + label_ostream << mk_pp(m.get_fact(currentNode),m,p) << "\n"; + std::string label = escape_dot(label_ostream.str()); + + // compute edge-label + std::string edge_label = ""; + if (m.get_num_parents(currentNode) == 0) + { + switch (currentNode->get_decl_kind()) + { + case PR_ASSERTED: + edge_label = "asserted:"; + break; + case PR_HYPOTHESIS: + edge_label = "hyp:"; + color = "grey"; + break; + default: + if (currentNode->get_decl_kind() == PR_TH_LEMMA) + { + edge_label = "th_axiom:"; + func_decl* d = currentNode->get_decl(); + symbol sym; + if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas") + { + edge_label = "th_axiom(farkas):"; + } + } + else + { + edge_label = "unknown axiom-type:"; + break; + } + } + } + else + { + if (currentNode->get_decl_kind() == PR_LEMMA) + { + edge_label = "lemma:"; + } + else if (currentNode->get_decl_kind() == PR_TH_LEMMA) + { + func_decl* d = currentNode->get_decl(); + symbol sym; + if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas") + { + edge_label = "th_lemma(farkas):"; + } + else + { + edge_label = "th_lemma(other):"; + } + } + } + + // generate entry for node in dot-file + dotstream << "node_" << counter << " " + << "[" + << "shape=box,style=\"filled\"," + << "label=\"" << edge_label << " " << label << "\", " + << "fillcolor=\"" << color << "\"" + << "]\n"; + + // add entry for each edge to that node + for (unsigned i = m.get_num_parents(currentNode); i > 0 ; --i) + { + proof* premise = to_app(currentNode->get_arg(i-1)); + unsigned premise_small_id = id_to_small_id[premise->get_id()]; + dotstream << "node_" << premise_small_id + << " -> " + << "node_" << counter + << ";\n"; + } + + ++counter; + } + dotstream << "\n}" << std::endl; + } + + std::string escape_dot(const std::string &s) + { + std::string res; + res.reserve(s.size()); // preallocate + for (auto c : s) { + if (c == '\n') + res.append("\\l"); + else + res.push_back(c); + } + return res; + } + + void pp_proof_post_process_dot(std::string dot_filepath, std::ofstream &dotstream) + { + // replace variables in the dotfiles with nicer descriptions (hack: hard coded replacement for now) + std::vector > predicates; + std::vector l1 = {"L1","i","n","A"}; + predicates.push_back(l1); + std::vector l2 = {"L2","j","m","B"}; + predicates.push_back(l2); + + for(auto& predicate : predicates) + { + std::string predicate_name = predicate[0]; + for (unsigned i=0; i+1 < predicate.size(); ++i) + { + std::string new_name = predicate[i+1]; + std::string substring0 = predicate_name + "_" + std::to_string(i) + "_0"; + std::string substringN = predicate_name + "_" + std::to_string(i) + "_n"; + + std::string command0 = "sed -i '.bak' 's/" + substring0 + "/" + new_name + "/g' " + dot_filepath; + verbose_stream() << command0 << std::endl; + system(command0.c_str()); + + std::string commandN = "sed -i '.bak' s/" + substringN + "/" + new_name + "\\'" + "/g " + dot_filepath; + verbose_stream() << commandN << std::endl; + system(commandN.c_str()); + } + } + + verbose_stream() << "end of postprocessing"; + } + + /* + * ==================================== + * methods for reducing hypothesis + * ==================================== + */ + +class reduce_hypotheses { + ast_manager &m; + // tracking all created expressions + expr_ref_vector m_pinned; + + // cache for the transformation + obj_map m_cache; + + // map from unit literals to their hypotheses-free derivations + obj_map m_units; + + // -- all hypotheses in the the proof + obj_hashtable m_hyps; + + // marks hypothetical proofs + ast_mark m_hypmark; + + + // stack + ptr_vector m_todo; + + void reset() + { + m_cache.reset(); + m_units.reset(); + m_hyps.reset(); + m_hypmark.reset(); + m_pinned.reset(); + } + + bool compute_mark1(proof *pr) + { + bool hyp_mark = false; + // lemmas clear all hypotheses + if (!m.is_lemma(pr)) { + for (unsigned i = 0, sz = m.get_num_parents(pr); i < sz; ++i) { + if (m_hypmark.is_marked(m.get_parent(pr, i))) { + hyp_mark = true; + break; + } + } + } + m_hypmark.mark(pr, hyp_mark); + return hyp_mark; + } + + void compute_marks(proof* pr) + { + proof *p; + ProofIteratorPostOrder pit(pr, m); + while (pit.hasNext()) { + p = pit.next(); + if (m.is_hypothesis(p)) { + m_hypmark.mark(p, true); + m_hyps.insert(m.get_fact(p)); + } else { + bool hyp_mark = compute_mark1(p); + // collect units that are hyp-free and are used as hypotheses somewhere + if (!hyp_mark && m.has_fact(p) && m_hyps.contains(m.get_fact(p))) + { m_units.insert(m.get_fact(p), p); } + } + } + } + void find_units(proof *pr) + { + // optional. not implemented yet. + } + + void reduce(proof* pf, proof_ref &out) + { + proof *res = NULL; + + m_todo.reset(); + m_todo.push_back(pf); + ptr_buffer args; + bool dirty = false; + + while (!m_todo.empty()) { + proof *p, *tmp, *pp; + unsigned todo_sz; + + p = m_todo.back(); + if (m_cache.find(p, tmp)) { + res = tmp; + m_todo.pop_back(); + continue; + } + + dirty = false; + args.reset(); + todo_sz = m_todo.size(); + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + pp = m.get_parent(p, i); + if (m_cache.find(pp, tmp)) { + args.push_back(tmp); + dirty = dirty || pp != tmp; + } else { + m_todo.push_back(pp); + } + } + + if (todo_sz < m_todo.size()) { continue; } + else { m_todo.pop_back(); } + + if (m.is_hypothesis(p)) { + // hyp: replace by a corresponding unit + if (m_units.find(m.get_fact(p), tmp)) { + res = tmp; + } else { res = p; } + } + + else if (!dirty) { res = p; } + + else if (m.is_lemma(p)) { + //lemma: reduce the premise; remove reduced consequences from conclusion + SASSERT(args.size() == 1); + res = mk_lemma_core(args.get(0), m.get_fact(p)); + compute_mark1(res); + } else if (m.is_unit_resolution(p)) { + // unit: reduce untis; reduce the first premise; rebuild unit resolution + res = mk_unit_resolution_core(args.size(), args.c_ptr()); + compute_mark1(res); + } else { + // other: reduce all premises; reapply + if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); } + SASSERT(p->get_decl()->get_arity() == args.size()); + res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); + m_pinned.push_back(res); + compute_mark1(res); + } + + SASSERT(res); + m_cache.insert(p, res); + + if (m.has_fact(res) && m.is_false(m.get_fact(res))) { break; } + } + + out = res; + } + + // returns true if (hypothesis (not a)) would be reduced + bool is_reduced(expr *a) + { + expr_ref e(m); + if (m.is_not(a)) { e = to_app(a)->get_arg(0); } + else { e = m.mk_not(a); } + + return m_units.contains(e); + } + proof *mk_lemma_core(proof *pf, expr *fact) + { + ptr_buffer args; + expr_ref lemma(m); + + if (m.is_or(fact)) { + for (unsigned i = 0, sz = to_app(fact)->get_num_args(); i < sz; ++i) { + expr *a = to_app(fact)->get_arg(i); + if (!is_reduced(a)) + { args.push_back(a); } + } + } else if (!is_reduced(fact)) + { args.push_back(fact); } + + + if (args.size() == 0) { return pf; } + else if (args.size() == 1) { + lemma = args.get(0); + } else { + lemma = m.mk_or(args.size(), args.c_ptr()); + } + proof* res = m.mk_lemma(pf, lemma); + m_pinned.push_back(res); + + // XXX this is wrong because lemma is a proof and m_hyps only + // XXX contains expressions. + // XXX Not sure this is ever needed. + if (m_hyps.contains(lemma)) { + m_units.insert(lemma, res); + } + return res; + } + + proof *mk_unit_resolution_core(unsigned num_args, proof* const *args) + { + + ptr_buffer pf_args; + pf_args.push_back(args [0]); + + app *cls_fact = to_app(m.get_fact(args[0])); + ptr_buffer cls; + if (m.is_or(cls_fact)) { + for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) + { cls.push_back(cls_fact->get_arg(i)); } + } else { cls.push_back(cls_fact); } + + // construct new resolvent + ptr_buffer new_fact_cls; + bool found; + // XXX quadratic + for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { + found = false; + for (unsigned j = 1; j < num_args; ++j) { + if (m.is_complement(cls.get(i), m.get_fact(args [j]))) { + found = true; + pf_args.push_back(args [j]); + break; + } + } + if (!found) { + new_fact_cls.push_back(cls.get(i)); + } + } + + SASSERT(new_fact_cls.size() + pf_args.size() - 1 == cls.size()); + expr_ref new_fact(m); + new_fact = mk_or(m, new_fact_cls.size(), new_fact_cls.c_ptr()); + + // create new proof step + proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); + m_pinned.push_back(res); + return res; + } + + // reduce all units, if any unit reduces to false return true and put its proof into out + bool reduce_units(proof_ref &out) + { + proof_ref res(m); + for (auto entry : m_units) { + reduce(entry.get_value(), res); + if (m.is_false(m.get_fact(res))) { + out = res; + return true; + } + res.reset(); + } + return false; + } + + +public: + reduce_hypotheses(ast_manager &m) : m(m), m_pinned(m) {} + + + void operator()(proof_ref &pr) + { + compute_marks(pr); + if (!reduce_units(pr)) { + reduce(pr.get(), pr); + } + reset(); + } +}; +void reduce_hypotheses(proof_ref &pr) +{ + ast_manager &m = pr.get_manager(); + class reduce_hypotheses hypred(m); + hypred(pr); + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(pr, side)); + ); +} +} diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h new file mode 100644 index 000000000..93b512c8f --- /dev/null +++ b/src/muz/spacer/spacer_proof_utils.h @@ -0,0 +1,53 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + spacer_proof_utils.cpp + +Abstract: + Utilities to traverse and manipulate proofs + +Author: + Bernhard Gleiss + Arie Gurfinkel + +Revision History: + +--*/ + +#ifndef _SPACER_PROOF_UTILS_H_ +#define _SPACER_PROOF_UTILS_H_ +#include "ast/ast.h" + +namespace spacer { + + bool is_farkas_lemma(ast_manager& m, proof* pr); +/* + * iterator, which traverses the proof in depth-first post-order. + */ +class ProofIteratorPostOrder { +public: + ProofIteratorPostOrder(proof* refutation, ast_manager& manager); + bool hasNext(); + proof* next(); + +private: + ptr_vector m_todo; + ast_mark m_visited; // the proof nodes we have already visited + + ast_manager& m; +}; + + /* + * prints the proof pr in dot representation to the file proof.dot + * if iuc_pr is not nullptr, then it is queried for coloring partitions + */ + class iuc_proof; + void pp_proof_dot(ast_manager& m, proof* pr, iuc_proof* iuc_pr = nullptr); + + + +void reduce_hypotheses(proof_ref &pr); +} +#endif diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index 12b2a5614..fa5e17239 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -19,16 +19,18 @@ Revision History: #include "muz/spacer/spacer_unsat_core_learner.h" #include "muz/spacer/spacer_unsat_core_plugin.h" +#include "muz/spacer/spacer_iuc_proof.h" #include "ast/for_each_expr.h" +#include "muz/spacer/spacer_util.h" + + namespace spacer { - unsat_core_learner::~unsat_core_learner() { std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc()); - } void unsat_core_learner::register_plugin(unsat_core_plugin* plugin) @@ -36,60 +38,16 @@ void unsat_core_learner::register_plugin(unsat_core_plugin* plugin) m_plugins.push_back(plugin); } -void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, expr_ref_vector& unsat_core) +void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { - // transform proof in order to get a proof which is better suited for unsat-core-extraction - proof_ref pr(root, m); - - reduce_hypotheses(pr); - STRACE("spacer.unsat_core_learner", - verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n"; - ); - - // compute symbols occurring in B - collect_symbols_b(asserted_b); - // traverse proof - proof_post_order it(root, m); + proof_post_order it(m_pr.get(), m); while (it.hasNext()) { proof* currentNode = it.next(); - if (m.get_num_parents(currentNode) == 0) + if (m.get_num_parents(currentNode) > 0) { - switch(currentNode->get_decl_kind()) - { - - case PR_ASSERTED: // currentNode is an axiom - { - if (asserted_b.contains(m.get_fact(currentNode))) - { - m_b_mark.mark(currentNode, true); - } - else - { - m_a_mark.mark(currentNode, true); - } - break; - } - // currentNode is a hypothesis: - case PR_HYPOTHESIS: - { - m_h_mark.mark(currentNode, true); - break; - } - default: - { - break; - } - } - } - else - { - // collect from parents whether derivation of current node contains A-axioms, B-axioms and hypothesis - bool need_to_mark_a = false; - bool need_to_mark_b = false; - bool need_to_mark_h = false; bool need_to_mark_closed = true; for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) @@ -97,31 +55,18 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e SASSERT(m.is_proof(currentNode->get_arg(i))); proof* premise = to_app(currentNode->get_arg(i)); - need_to_mark_a = need_to_mark_a || m_a_mark.is_marked(premise); - need_to_mark_b = need_to_mark_b || m_b_mark.is_marked(premise); - need_to_mark_h = need_to_mark_h || m_h_mark.is_marked(premise); - need_to_mark_closed = need_to_mark_closed && (!m_b_mark.is_marked(premise) || m_closed.is_marked(premise)); + need_to_mark_closed = need_to_mark_closed && (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise)); } - // if current node is application of lemma, we know that all hypothesis are removed - if(currentNode->get_decl_kind() == PR_LEMMA) - { - need_to_mark_h = false; - } - - // save results - m_a_mark.mark(currentNode, need_to_mark_a); - m_b_mark.mark(currentNode, need_to_mark_b); - m_h_mark.mark(currentNode, need_to_mark_h); + // save result m_closed.mark(currentNode, need_to_mark_closed); } // we have now collected all necessary information, so we can visit the node // if the node mixes A-reasoning and B-reasoning and contains non-closed premises - if (m_a_mark.is_marked(currentNode) && m_b_mark.is_marked(currentNode) && !m_closed.is_marked(currentNode)) + if (m_pr.is_a_marked(currentNode) && m_pr.is_b_marked(currentNode) && !m_closed.is_marked(currentNode)) { compute_partial_core(currentNode); // then we need to compute a partial core - // SASSERT(!(m_a_mark.is_marked(currentNode) && m_b_mark.is_marked(currentNode)) || m_closed.is_marked(currentNode)); TODO: doesn't hold anymore if we do the mincut-thing! } } @@ -133,170 +78,14 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e // count both number of all Farkas lemmas and number of Farkas lemmas in the cut if (m_print_farkas_stats) { - unsigned farkas_counter = 0; - unsigned farkas_counter2 = 0; - - ProofIteratorPostOrder it3(root, m); - while (it3.hasNext()) - { - proof* currentNode = it3.next(); - - // if node is theory lemma - if (currentNode->get_decl_kind() == PR_TH_LEMMA) - { - func_decl* d = currentNode->get_decl(); - symbol sym; - // and theory lemma is Farkas lemma - if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas") - { - farkas_counter++; - - // check whether farkas lemma is to be interpolated (could potentially miss farkas lemmas, which are interpolated, because we potentially don't want to use the lowest cut) - bool has_no_mixed_parents = true; - for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) - { - proof* premise = to_app(currentNode->get_arg(i)); - if (is_a_marked(premise) && is_b_marked(premise)) - { - has_no_mixed_parents = false; + m_pr.print_farkas_stats(); } - } - if (has_no_mixed_parents && is_a_marked(currentNode) && is_b_marked(currentNode)) - { - farkas_counter2++; - } - - } - } - } - - verbose_stream() << "\nThis proof contains " << farkas_counter << " Farkas lemmas. " << farkas_counter2 << " Farkas lemmas participate in the lowest cut\n"; - } - + //TODO remove this if(m_iuc_debug_proof) { - // print proof for debugging - verbose_stream() << "Proof:\n"; - std::unordered_map id_to_small_id; - unsigned counter = 0; - - proof_post_order it2(root, m); - while (it2.hasNext()) - { - proof* currentNode = it2.next(); - - SASSERT(id_to_small_id.find(currentNode->get_id()) == id_to_small_id.end()); - id_to_small_id.insert(std::make_pair(currentNode->get_id(), counter)); - - verbose_stream() << counter << " "; - verbose_stream() << "["; - if (is_a_marked(currentNode)) - { - verbose_stream() << "a"; - } - if (is_b_marked(currentNode)) - { - verbose_stream() << "b"; - } - if (is_h_marked(currentNode)) - { - verbose_stream() << "h"; - } - if (is_closed(currentNode)) - { - verbose_stream() << "c"; - } - verbose_stream() << "] "; - - if (m.get_num_parents(currentNode) == 0) - { - switch (currentNode->get_decl_kind()) - { - case PR_ASSERTED: - verbose_stream() << "asserted"; - break; - case PR_HYPOTHESIS: - verbose_stream() << "hypothesis"; - break; - default: - if (currentNode->get_decl_kind() == PR_TH_LEMMA) - { - verbose_stream() << "th_axiom"; - func_decl* d = currentNode->get_decl(); - symbol sym; - if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas") - { - verbose_stream() << "(farkas)"; - } - } - else - { - verbose_stream() << "unknown axiom-type"; - break; - } - } - } - else - { - if (currentNode->get_decl_kind() == PR_LEMMA) - { - verbose_stream() << "lemma"; - } - else if (currentNode->get_decl_kind() == PR_TH_LEMMA) - { - verbose_stream() << "th_lemma"; - func_decl* d = currentNode->get_decl(); - symbol sym; - if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas") - { - verbose_stream() << "(farkas)"; - } - else - { - verbose_stream() << "(other)"; - } - } - else - { - verbose_stream() << "step"; - } - verbose_stream() << " from "; - for (unsigned i = m.get_num_parents(currentNode); i > 0 ; --i) - { - proof* premise = to_app(currentNode->get_arg(i)); - unsigned premise_small_id = id_to_small_id[premise->get_id()]; - if (i > 1) - { - verbose_stream() << premise_small_id << ", "; - } - else - { - verbose_stream() << premise_small_id; - } - - } - } -// if (currentNode->get_decl_kind() == PR_TH_LEMMA || (is_a_marked(currentNode) && is_b_marked(currentNode)) || is_h_marked(currentNode) || (!is_a_marked(currentNode) && !is_b_marked(currentNode))) - if (false) - { - verbose_stream() << "\n"; - } - else - { - verbose_stream() << ": " << mk_pp(m.get_fact(currentNode), m) << "\n"; - } - ++counter; - } } verbose_stream() << std::endl; - // move all lemmas into vector for (expr* const* it = m_unsat_core.begin(); it != m_unsat_core.end(); ++it) { @@ -322,19 +111,6 @@ void unsat_core_learner::finalize() } } - -bool unsat_core_learner::is_a_marked(proof* p) -{ - return m_a_mark.is_marked(p); -} -bool unsat_core_learner::is_b_marked(proof* p) -{ - return m_b_mark.is_marked(p); -} -bool unsat_core_learner::is_h_marked(proof* p) -{ - return m_h_mark.is_marked(p); -} bool unsat_core_learner::is_closed(proof*p) { return m_closed.is_marked(p); @@ -344,75 +120,13 @@ void unsat_core_learner::set_closed(proof* p, bool value) m_closed.mark(p, value); } - void unsat_core_learner::add_lemma_to_core(expr* lemma) +bool unsat_core_learner::is_b_open(proof *p) { - m_unsat_core.push_back(lemma); + return m_pr.is_b_marked(p) && !is_closed (p); } - -class collect_pure_proc { - func_decl_set& m_symbs; -public: - collect_pure_proc(func_decl_set& s):m_symbs(s) {} - - void operator()(app* a) { - if (a->get_family_id() == null_family_id) { - m_symbs.insert(a->get_decl()); - } - } - void operator()(var*) {} - void operator()(quantifier*) {} -}; - -void unsat_core_learner::collect_symbols_b(const expr_set& axioms_b) +void unsat_core_learner::add_lemma_to_core(expr* lemma) { - expr_mark visited; - collect_pure_proc proc(m_symbols_b); - for (expr_set::iterator it = axioms_b.begin(); it != axioms_b.end(); ++it) - { - for_each_expr(proc, visited, *it); + m_unsat_core.push_back(lemma); } } - -class is_pure_expr_proc { - func_decl_set const& m_symbs; - array_util m_au; -public: - struct non_pure {}; - - is_pure_expr_proc(func_decl_set const& s, ast_manager& m): - m_symbs(s), - m_au (m) - {} - - void operator()(app* a) { - if (a->get_family_id() == null_family_id) { - if (!m_symbs.contains(a->get_decl())) { - throw non_pure(); - } - } - else if (a->get_family_id () == m_au.get_family_id () && - a->is_app_of (a->get_family_id (), OP_ARRAY_EXT)) { - throw non_pure(); - } - } - void operator()(var*) {} - void operator()(quantifier*) {} -}; - -bool unsat_core_learner::only_contains_symbols_b(expr* expr) const -{ - is_pure_expr_proc proc(m_symbols_b, m); - try { - for_each_expr(proc, expr); - } - catch (is_pure_expr_proc::non_pure) - { - return false; - } - return true; -} - - - -} diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 4b5ca981d..16b27f4ba 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -20,21 +20,23 @@ Revision History: #include "ast/ast.h" #include "muz/spacer/spacer_util.h" -#include "ast/proofs/proof_utils.h" +#include "muz/spacer/spacer_proof_utils.h" namespace spacer { class unsat_core_plugin; + class iuc_proof; class unsat_core_learner { typedef obj_hashtable expr_set; public: - unsat_core_learner(ast_manager& m, bool print_farkas_stats = false, bool iuc_debug_proof = false) : m(m), m_unsat_core(m), m_print_farkas_stats(print_farkas_stats), m_iuc_debug_proof(iuc_debug_proof) {}; + unsat_core_learner(ast_manager& m, iuc_proof& pr, bool print_farkas_stats = false, bool iuc_debug_proof = false) : m(m), m_pr(pr), m_unsat_core(m), m_print_farkas_stats(print_farkas_stats), m_iuc_debug_proof(iuc_debug_proof) {}; virtual ~unsat_core_learner(); ast_manager& m; + iuc_proof& m_pr; /* * register a plugin for computation of partial unsat cores @@ -45,48 +47,29 @@ namespace spacer { /* * compute unsat core using the registered unsat-core-plugins */ - void compute_unsat_core(proof* root, expr_set& asserted_b, expr_ref_vector& unsat_core); + void compute_unsat_core(expr_ref_vector& unsat_core); /* * getter/setter methods for data structures exposed to plugins - * the following invariants can be assumed and need to be maintained by the plugins: - * - a node is a-marked iff it is derived using at least one asserted proof step from A. - * - a node is b-marked iff its derivation contains no asserted proof steps from A and - * no hypothesis (with the additional complication that lemmas conceptually remove hypothesis) - * - a node is h-marked, iff it is derived using at least one hypothesis + * the following invariant can be assumed and need to be maintained by the plugins: * - a node is closed, iff it has already been interpolated, i.e. its contribution is * already covered by the unsat-core. */ - bool is_a_marked(proof* p); - bool is_b_marked(proof* p); - bool is_h_marked(proof* p); + bool is_closed(proof* p); void set_closed(proof* p, bool value); + bool is_b_open (proof *p); + /* * adds a lemma to the unsat core */ void add_lemma_to_core(expr* lemma); - /* - * helper method, which can be used by plugins - * returns true iff all symbols of expr occur in some b-asserted formula. - * must only be called after a call to collect_symbols_b. - */ - bool only_contains_symbols_b(expr* expr) const; - bool is_b_pure (proof *p) - {return !is_h_marked (p) && only_contains_symbols_b (m.get_fact (p));} - bool is_b_open (proof *p) - { return is_b_marked (p) && !is_closed (p); } + private: ptr_vector m_plugins; - func_decl_set m_symbols_b; // symbols, which occur in any b-asserted formula - void collect_symbols_b(const expr_set& axioms_b); - - ast_mark m_a_mark; - ast_mark m_b_mark; - ast_mark m_h_mark; ast_mark m_closed; expr_ref_vector m_unsat_core; // collects the lemmas of the unsat-core, will at the end be inserted into unsat_core. diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 0323fff0a..863023d5b 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -30,6 +30,7 @@ Revision History: #include "muz/spacer/spacer_matrix.h" #include "muz/spacer/spacer_unsat_core_plugin.h" #include "muz/spacer/spacer_unsat_core_learner.h" +#include "muz/spacer/spacer_iuc_proof.h" namespace spacer { @@ -37,8 +38,8 @@ namespace spacer void unsat_core_plugin_lemma::compute_partial_core(proof* step) { - SASSERT(m_learner.is_a_marked(step)); - SASSERT(m_learner.is_b_marked(step)); + SASSERT(m_learner.m_pr.is_a_marked(step)); + SASSERT(m_learner.m_pr.is_b_marked(step)); for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) { @@ -48,7 +49,7 @@ void unsat_core_plugin_lemma::compute_partial_core(proof* step) if (m_learner.is_b_open (premise)) { // by IH, premises that are AB marked are already closed - SASSERT(!m_learner.is_a_marked(premise)); + SASSERT(!m_learner.m_pr.is_a_marked(premise)); add_lowest_split_to_core(premise); } } @@ -75,13 +76,13 @@ void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const // the step is b-marked and not closed. // by I.H. the step must be already visited // so if it is also a-marked, it must be closed - SASSERT(m_learner.is_b_marked(pf)); - SASSERT(!m_learner.is_a_marked(pf)); + SASSERT(m_learner.m_pr.is_b_marked(pf)); + SASSERT(!m_learner.m_pr.is_a_marked(pf)); // the current step needs to be interpolated: expr* fact = m_learner.m.get_fact(pf); // if we trust the current step and we are able to use it - if (m_learner.is_b_pure (pf) && + if (m_learner.m_pr.is_b_pure (pf) && (m.is_asserted(pf) || is_literal(m, fact))) { // just add it to the core @@ -109,8 +110,8 @@ void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step) { ast_manager &m = m_learner.m; - SASSERT(m_learner.is_a_marked(step)); - SASSERT(m_learner.is_b_marked(step)); + SASSERT(m_learner.m_pr.is_a_marked(step)); + SASSERT(m_learner.m_pr.is_b_marked(step)); // XXX this assertion should be true so there is no need to check for it SASSERT (!m_learner.is_closed (step)); func_decl* d = step->get_decl(); @@ -162,7 +163,7 @@ void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step) rational coef; VERIFY(params[i].is_rational(coef)); - bool b_pure = m_learner.is_b_pure (prem); + bool b_pure = m_learner.m_pr.is_b_pure (prem); verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m_learner.m.get_fact(prem), m_learner.m) << "\n"; } ); @@ -176,9 +177,9 @@ void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step) if (m_learner.is_b_open (premise)) { - SASSERT(!m_learner.is_a_marked(premise)); + SASSERT(!m_learner.m_pr.is_a_marked(premise)); - if (m_learner.is_b_pure (step)) + if (m_learner.m_pr.is_b_pure (step)) { if (!m_use_constant_from_a) { @@ -287,8 +288,8 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vectorget_decl(); symbol sym; @@ -315,7 +316,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vectorget_arg(i))); proof * premise = m.get_parent (step, i); - if (m_learner.is_b_marked(premise) && !m_learner.is_closed(premise)) + if (m_learner.m_pr.is_b_marked(premise) && !m_learner.is_closed(premise)) { - SASSERT(!m_learner.is_a_marked(premise)); + SASSERT(!m_learner.m_pr.is_a_marked(premise)); - if (m_learner.only_contains_symbols_b(m_learner.m.get_fact(premise)) && !m_learner.is_h_marked(premise)) + if (m_learner.m_pr.only_contains_symbols_b(m_learner.m.get_fact(premise)) && !m_learner.m_pr.is_h_marked(premise)) { rational coefficient; VERIFY(params[i].is_rational(coefficient)); @@ -603,8 +604,8 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector todo; - SASSERT(m_learner.is_a_marked(step)); - SASSERT(m_learner.is_b_marked(step)); + SASSERT(m_learner.m_pr.is_a_marked(step)); + SASSERT(m_learner.m_pr.is_b_marked(step)); SASSERT(m.get_num_parents(step) > 0); SASSERT(!m_learner.is_closed(step)); todo.push_back(step); @@ -641,7 +642,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector Date: Mon, 27 Nov 2017 14:39:52 -0500 Subject: [PATCH 0980/1283] Fix several bugs in hyp_reducer - compute_marks didn't find all units - call to m.mk_unit_resolution expects that there is at least one unit - hyp-reduced proof wasn't used - bug in early termination - any hypothesis was replaced with the old derivation of the literal - handle the case of a single literal premise under hypothesis that is replaced by an empty clause under hypothesis --- src/muz/spacer/spacer_proof_utils.cpp | 84 +++++++++++++++++++++------ 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index ba102e20e..a8d00c142 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -326,10 +326,19 @@ class reduce_hypotheses { m_hypmark.mark(p, true); m_hyps.insert(m.get_fact(p)); } else { - bool hyp_mark = compute_mark1(p); + compute_mark1(p); + } + } + ProofIteratorPostOrder pit2(pr, m); + while (pit2.hasNext()) { + p = pit2.next(); + if (!m.is_hypothesis(p)) + { // collect units that are hyp-free and are used as hypotheses somewhere - if (!hyp_mark && m.has_fact(p) && m_hyps.contains(m.get_fact(p))) - { m_units.insert(m.get_fact(p), p); } + if (!m_hypmark.is_marked(p) && m.has_fact(p) && m_hyps.contains(m.get_fact(p))) + { + m_units.insert(m.get_fact(p), p); + } } } } @@ -348,7 +357,7 @@ class reduce_hypotheses { bool dirty = false; while (!m_todo.empty()) { - proof *p, *tmp, *pp; + proof *p, *tmp, *tmp2, *pp; unsigned todo_sz; p = m_todo.back(); @@ -377,7 +386,17 @@ class reduce_hypotheses { if (m.is_hypothesis(p)) { // hyp: replace by a corresponding unit if (m_units.find(m.get_fact(p), tmp)) { - res = tmp; + // if the transformed subproof ending in the unit has already been computed, use it + if (m_cache.find(tmp,tmp2)) + { + res = tmp2; + } + // otherwise first compute the transformed subproof ending in the unit + else + { + m_todo.push_back(tmp); + continue; + } } else { res = p; } } @@ -393,18 +412,33 @@ class reduce_hypotheses { res = mk_unit_resolution_core(args.size(), args.c_ptr()); compute_mark1(res); } else { - // other: reduce all premises; reapply - if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); } - SASSERT(p->get_decl()->get_arity() == args.size()); - res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); - m_pinned.push_back(res); - compute_mark1(res); + // if any literal is false, we don't need a step + bool has_empty_clause_premise = false; + for (unsigned i = 0; i < args.size(); ++i) + { + if (m.is_false(m.get_fact(args[i]))) + { + has_empty_clause_premise = true; + res = args[i]; + } + } + + // otherwise: + if (!has_empty_clause_premise) + { + // other: reduce all premises; reapply + if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); } + SASSERT(p->get_decl()->get_arity() == args.size()); + res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); + m_pinned.push_back(res); + compute_mark1(res); + } } SASSERT(res); m_cache.insert(p, res); - if (m.has_fact(res) && m.is_false(m.get_fact(res))) { break; } + if (!m_hypmark.is_marked(res) && m.has_fact(res) && m.is_false(m.get_fact(res))) { break; } } out = res; @@ -458,6 +492,15 @@ class reduce_hypotheses { ptr_buffer pf_args; pf_args.push_back(args [0]); + // if any literal is false, we don't need a unit resolution step + for (unsigned i = 1; i < num_args; ++i) + { + if (m.is_false(m.get_fact(args[i]))) + { + return args[i]; + } + } + app *cls_fact = to_app(m.get_fact(args[0])); ptr_buffer cls; if (m.is_or(cls_fact)) { @@ -488,9 +531,16 @@ class reduce_hypotheses { new_fact = mk_or(m, new_fact_cls.size(), new_fact_cls.c_ptr()); // create new proof step - proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); - m_pinned.push_back(res); - return res; + if (pf_args.size() == 1) // the only premise is the clause itself + { + return args[0]; + } + else + { + proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); + m_pinned.push_back(res); + return res; + } } // reduce all units, if any unit reduces to false return true and put its proof into out @@ -516,9 +566,7 @@ public: void operator()(proof_ref &pr) { compute_marks(pr); - if (!reduce_units(pr)) { - reduce(pr.get(), pr); - } + reduce(pr.get(), pr); reset(); } }; From df2eb771ef160aaa06719cb60e8ec41e86bfd30a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 09:55:04 -0700 Subject: [PATCH 0981/1283] Fix in spacer_itp_solver: use pr.get() instead of get_proof() --- src/muz/spacer/spacer_itp_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index 07c5f5871..f91cc6bb3 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -287,8 +287,8 @@ void itp_solver::get_itp_core (expr_ref_vector &core) ); // construct proof object with contains partition information - iuc_proof iuc_pr(m, get_proof(), B); - + iuc_proof iuc_pr(m, pr.get(), B); + // configure learner unsat_core_learner learner(m, iuc_pr, m_print_farkas_stats, m_iuc_debug_proof); From de31b070086a8524b310db1e5613a74353534963 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Fri, 1 Dec 2017 14:21:20 +0100 Subject: [PATCH 0982/1283] arith-theory-axiom reducer to handle arithmetic axioms --- src/muz/spacer/spacer_proof_utils.cpp | 311 +++++++++++++++++--------- src/muz/spacer/spacer_proof_utils.h | 66 +++++- 2 files changed, 270 insertions(+), 107 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index a8d00c142..81fb7286a 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -27,6 +27,38 @@ Revision History: namespace spacer { + // arith lemmas: second parameter specifies exact type of lemma, could be "farkas", "triangle-eq", "eq-propagate", "assign-bounds", maybe also something else + bool is_arith_lemma(ast_manager& m, proof* pr) + { + if (pr->get_decl_kind() == PR_TH_LEMMA) + { + func_decl* d = pr->get_decl(); + symbol sym; + if (d->get_num_parameters() >= 1 && + d->get_parameter(0).is_symbol(sym) && sym == "arith") + { + return true; + } + } + return false; + } + + bool is_farkas_lemma(ast_manager& m, proof* pr) + { + if (pr->get_decl_kind() == PR_TH_LEMMA) + { + func_decl* d = pr->get_decl(); + symbol sym; + if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas") + { + return true; + } + } + return false; + } + /* * ==================================== * methods for proof traversal @@ -153,24 +185,18 @@ proof* ProofIteratorPostOrder::next() edge_label = "hyp:"; color = "grey"; break; - default: - if (currentNode->get_decl_kind() == PR_TH_LEMMA) + case PR_TH_LEMMA: + if (is_farkas_lemma(m, currentNode)) { - edge_label = "th_axiom:"; - func_decl* d = currentNode->get_decl(); - symbol sym; - if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas") - { - edge_label = "th_axiom(farkas):"; - } + edge_label = "th_axiom(farkas):"; } else { - edge_label = "unknown axiom-type:"; - break; + edge_label = "th_axiom:"; } + break; + default: + edge_label = "unknown axiom-type:"; } } else @@ -266,32 +292,111 @@ proof* ProofIteratorPostOrder::next() /* * ==================================== - * methods for reducing hypothesis + * methods for transforming proofs * ==================================== */ -class reduce_hypotheses { - ast_manager &m; - // tracking all created expressions - expr_ref_vector m_pinned; + void theory_axiom_reducer::reset() + { + m_cache.reset(); + m_pinned.reset(); + } + + proof_ref theory_axiom_reducer::reduce(proof* pr) + { + ProofIteratorPostOrder pit(pr, m); + while (pit.hasNext()) + { + proof* p = pit.next(); + + if (m.get_num_parents(p) == 0 && is_arith_lemma(m, p)) + { + // we have an arith-theory-axiom and want to get rid of it + // we need to replace the axiom with 1a) corresponding hypothesis', 1b) a theory lemma and a 1c) a lemma. Furthermore update datastructures + app *cls_fact = to_app(m.get_fact(p)); + ptr_buffer cls; + if (m.is_or(cls_fact)) { + for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) + { cls.push_back(cls_fact->get_arg(i)); } + } else { cls.push_back(cls_fact); } + + // 1a) create hypothesis' + ptr_buffer hyps; + for (unsigned i=0; i < cls.size(); ++i) + { + expr* hyp_fact = m.is_not(cls[i]) ? to_app(cls[i])->get_arg(0) : m.mk_not(cls[i]); + proof* hyp = m.mk_hypothesis(hyp_fact); + m_pinned.push_back(hyp); + hyps.push_back(hyp); + } + + // 1b) create farkas lemma: need to rebuild parameters since mk_th_lemma adds tid as first parameter + unsigned num_params = p->get_decl()->get_num_parameters(); + parameter const* params = p->get_decl()->get_parameters(); + vector parameters; + for (unsigned i = 1; i < num_params; ++i) { + parameters.push_back(params[i]); + } + + SASSERT(params[0].is_symbol()); + family_id tid = m.mk_family_id(params[0].get_symbol()); + SASSERT(tid != null_family_id); + + proof* th_lemma = m.mk_th_lemma(tid, m.mk_false(),hyps.size(), hyps.c_ptr(), num_params-1, parameters.c_ptr()); + SASSERT(is_arith_lemma(m, th_lemma)); + + // 1c) create lemma + proof* res = m.mk_lemma(th_lemma, cls_fact); + SASSERT(m.get_fact(res) == m.get_fact(p)); + m_pinned.push_back(res); + m_cache.insert(p, res); + } + else + { + bool dirty = false; // proof is dirty, if a subproof of one of its premises has been transformed - // cache for the transformation - obj_map m_cache; + ptr_buffer args; + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) + { + proof* pp = m.get_parent(p, i); + proof* tmp; + if (m_cache.find(pp, tmp)) + { + args.push_back(tmp); + dirty = dirty || pp != tmp; + } + else + { + SASSERT(false); + } + } + if (!dirty) // if not dirty just use the old step + { + m_cache.insert(p, p); + } + else // otherwise create new step with the corresponding proofs of the premises + { + if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); } + SASSERT(p->get_decl()->get_arity() == args.size()); + proof* res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); + m_pinned.push_back(res); + m_cache.insert(p, res); + } + } + } + + proof* res; + bool found = m_cache.find(pr,res); + SASSERT(found); + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(res, side)); + ); + + return proof_ref(res,m); + } - // map from unit literals to their hypotheses-free derivations - obj_map m_units; - - // -- all hypotheses in the the proof - obj_hashtable m_hyps; - - // marks hypothetical proofs - ast_mark m_hypmark; - - - // stack - ptr_vector m_todo; - - void reset() + void hypothesis_reducer::reset() { m_cache.reset(); m_units.reset(); @@ -299,14 +404,35 @@ class reduce_hypotheses { m_hypmark.reset(); m_pinned.reset(); } + + void hypothesis_reducer::compute_hypmarks_and_hyps(proof* pr) + { + proof *p; + ProofIteratorPostOrder pit(pr, m); + while (pit.hasNext()) { + p = pit.next(); + if (m.is_hypothesis(p)) + { + m_hypmark.mark(p, true); + m_hyps.insert(m.get_fact(p)); + } + else + { + compute_hypmark_from_parents(p); + } + } + } - bool compute_mark1(proof *pr) + bool hypothesis_reducer::compute_hypmark_from_parents(proof *pr) { bool hyp_mark = false; - // lemmas clear all hypotheses - if (!m.is_lemma(pr)) { - for (unsigned i = 0, sz = m.get_num_parents(pr); i < sz; ++i) { - if (m_hypmark.is_marked(m.get_parent(pr, i))) { + + if (!m.is_lemma(pr)) // lemmas clear all hypotheses + { + for (unsigned i = 0, sz = m.get_num_parents(pr); i < sz; ++i) + { + if (m_hypmark.is_marked(m.get_parent(pr, i))) + { hyp_mark = true; break; } @@ -316,22 +442,13 @@ class reduce_hypotheses { return hyp_mark; } - void compute_marks(proof* pr) + // collect all units that are hyp-free and are used as hypotheses somewhere + // requires that m_hypmarks and m_hyps have been computed + void hypothesis_reducer::collect_units(proof* pr) { - proof *p; ProofIteratorPostOrder pit(pr, m); while (pit.hasNext()) { - p = pit.next(); - if (m.is_hypothesis(p)) { - m_hypmark.mark(p, true); - m_hyps.insert(m.get_fact(p)); - } else { - compute_mark1(p); - } - } - ProofIteratorPostOrder pit2(pr, m); - while (pit2.hasNext()) { - p = pit2.next(); + proof* p = pit.next(); if (!m.is_hypothesis(p)) { // collect units that are hyp-free and are used as hypotheses somewhere @@ -342,12 +459,25 @@ class reduce_hypotheses { } } } - void find_units(proof *pr) - { - // optional. not implemented yet. - } - void reduce(proof* pf, proof_ref &out) + proof_ref hypothesis_reducer::reduce(proof* pr) + { + compute_hypmarks_and_hyps(pr); + collect_units(pr); + proof* res = compute_transformed_proof(pr); + SASSERT(res != nullptr); + + proof_ref res_ref(res,m); + + reset(); + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(res, side)); + ); + return res_ref; + } + + proof* hypothesis_reducer::compute_transformed_proof(proof* pf) { proof *res = NULL; @@ -383,9 +513,14 @@ class reduce_hypotheses { if (todo_sz < m_todo.size()) { continue; } else { m_todo.pop_back(); } - if (m.is_hypothesis(p)) { + // here the transformation begins + // INV: for each premise of p, we have computed the transformed proof. + + if (m.is_hypothesis(p)) + { // hyp: replace by a corresponding unit - if (m_units.find(m.get_fact(p), tmp)) { + if (m_units.find(m.get_fact(p), tmp)) + { // if the transformed subproof ending in the unit has already been computed, use it if (m_cache.find(tmp,tmp2)) { @@ -406,11 +541,11 @@ class reduce_hypotheses { //lemma: reduce the premise; remove reduced consequences from conclusion SASSERT(args.size() == 1); res = mk_lemma_core(args.get(0), m.get_fact(p)); - compute_mark1(res); + compute_hypmark_from_parents(res); } else if (m.is_unit_resolution(p)) { // unit: reduce untis; reduce the first premise; rebuild unit resolution res = mk_unit_resolution_core(args.size(), args.c_ptr()); - compute_mark1(res); + compute_hypmark_from_parents(res); } else { // if any literal is false, we don't need a step bool has_empty_clause_premise = false; @@ -431,21 +566,22 @@ class reduce_hypotheses { SASSERT(p->get_decl()->get_arity() == args.size()); res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); m_pinned.push_back(res); - compute_mark1(res); + compute_hypmark_from_parents(res); } } SASSERT(res); m_cache.insert(p, res); - if (!m_hypmark.is_marked(res) && m.has_fact(res) && m.is_false(m.get_fact(res))) { break; } + if (!m_hypmark.is_marked(res) && m.has_fact(res) && m.is_false(m.get_fact(res))) + { + return res; + } } - - out = res; } // returns true if (hypothesis (not a)) would be reduced - bool is_reduced(expr *a) + bool hypothesis_reducer::is_reduced(expr *a) { expr_ref e(m); if (m.is_not(a)) { e = to_app(a)->get_arg(0); } @@ -453,7 +589,8 @@ class reduce_hypotheses { return m_units.contains(e); } - proof *mk_lemma_core(proof *pf, expr *fact) + + proof* hypothesis_reducer::mk_lemma_core(proof *pf, expr *fact) { ptr_buffer args; expr_ref lemma(m); @@ -486,7 +623,7 @@ class reduce_hypotheses { return res; } - proof *mk_unit_resolution_core(unsigned num_args, proof* const *args) + proof* hypothesis_reducer::mk_unit_resolution_core(unsigned num_args, proof* const *args) { ptr_buffer pf_args; @@ -542,42 +679,4 @@ class reduce_hypotheses { return res; } } - - // reduce all units, if any unit reduces to false return true and put its proof into out - bool reduce_units(proof_ref &out) - { - proof_ref res(m); - for (auto entry : m_units) { - reduce(entry.get_value(), res); - if (m.is_false(m.get_fact(res))) { - out = res; - return true; - } - res.reset(); - } - return false; - } - - -public: - reduce_hypotheses(ast_manager &m) : m(m), m_pinned(m) {} - - - void operator()(proof_ref &pr) - { - compute_marks(pr); - reduce(pr.get(), pr); - reset(); - } }; -void reduce_hypotheses(proof_ref &pr) -{ - ast_manager &m = pr.get_manager(); - class reduce_hypotheses hypred(m); - hypred(pr); - DEBUG_CODE(proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(pr, side)); - ); -} -} diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index 93b512c8f..a0031fc07 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -22,6 +22,7 @@ Revision History: namespace spacer { + bool is_arith_lemma(ast_manager& m, proof* pr); bool is_farkas_lemma(ast_manager& m, proof* pr); /* * iterator, which traverses the proof in depth-first post-order. @@ -46,8 +47,71 @@ private: class iuc_proof; void pp_proof_dot(ast_manager& m, proof* pr, iuc_proof* iuc_pr = nullptr); + class theory_axiom_reducer + { + public: + theory_axiom_reducer(ast_manager& m) : m(m), m_pinned(m) {} + // reduce theory axioms and return transformed proof + proof_ref reduce(proof* pr); + + private: + ast_manager &m; + + // tracking all created expressions + expr_ref_vector m_pinned; + + // maps each proof of a clause to the transformed subproof of that clause + obj_map m_cache; + + void reset(); + }; -void reduce_hypotheses(proof_ref &pr); + class hypothesis_reducer + { + public: + hypothesis_reducer(ast_manager &m) : m(m), m_pinned(m) {} + + // reduce hypothesis and return transformed proof + proof_ref reduce(proof* pf); + + private: + typedef obj_hashtable expr_set; + + ast_manager &m; + // tracking all created expressions + expr_ref_vector m_pinned; + + // maps each proof of a clause to the transformed subproof of that clause + obj_map m_cache; + + // maps each unit literals to the transformed subproof of that unit + obj_map m_units; + + // -- all hypotheses in the the proof + obj_hashtable m_hyps; + + // marks hypothetical proofs + ast_mark m_hypmark; + + std::vector m_pinned_hyp_sets; // tracking all created sets of hypothesis + obj_map m_hyp_anchestor; // maps each proof to the set of hypothesis it contains, needed to avoid creating cycles in the proof. + + // stack + ptr_vector m_todo; + + void reset(); + proof* compute_transformed_proof(proof* pf); + + void compute_hypmarks_and_hyps(proof* pr); + bool compute_hypmark_from_parents(proof *pr); + void collect_units(proof* pr); + + // returns true if (hypothesis (not a)) would be reduced + bool is_reduced(expr *a); + + proof* mk_lemma_core(proof *pf, expr *fact); + proof* mk_unit_resolution_core(unsigned num_args, proof* const *args); + }; } #endif From 0f25e9e831a85fb3647fb8cc8e45e369bc01dd21 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Fri, 1 Dec 2017 15:23:07 +0100 Subject: [PATCH 0983/1283] Moved farkas stats printing to before and after the hyp-reduction --- src/muz/spacer/spacer_itp_solver.cpp | 16 ++++++++++++++ src/muz/spacer/spacer_unsat_core_learner.cpp | 22 ++++++-------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index f91cc6bb3..9c11e0c1c 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -281,7 +281,23 @@ void itp_solver::get_itp_core (expr_ref_vector &core) // preprocess proof in order to get a proof which is better suited for unsat-core-extraction proof_ref pr(get_proof(), m); + if (m_print_farkas_stats) + { + iuc_proof iuc_before(m, pr.get(), B); + verbose_stream() << "Stats before transformation:"; + iuc_before.print_farkas_stats(); + } + spacer::reduce_hypotheses(pr); + spacer::reduce_hypotheses(pr); + + if (m_print_farkas_stats) + { + iuc_proof iuc_after(m, pr.get(), B); + verbose_stream() << "Stats after transformation:"; + iuc_after.print_farkas_stats(); + } + STRACE("spacer.unsat_core_learner", verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n"; ); diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index fa5e17239..cb7ebff76 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -41,7 +41,7 @@ void unsat_core_learner::register_plugin(unsat_core_plugin* plugin) void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { // traverse proof - proof_post_order it(m_pr.get(), m); + proof_post_order it(m_pr.get(), m); while (it.hasNext()) { proof* currentNode = it.next(); @@ -54,7 +54,7 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { SASSERT(m.is_proof(currentNode->get_arg(i))); proof* premise = to_app(currentNode->get_arg(i)); - + need_to_mark_closed = need_to_mark_closed && (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise)); } @@ -75,16 +75,6 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) // TODO: remove duplicates from unsat core? - // count both number of all Farkas lemmas and number of Farkas lemmas in the cut - if (m_print_farkas_stats) - { - m_pr.print_farkas_stats(); - } - //TODO remove this - if(m_iuc_debug_proof) - { - } - verbose_stream() << std::endl; // move all lemmas into vector for (expr* const* it = m_unsat_core.begin(); it != m_unsat_core.end(); ++it) @@ -119,14 +109,14 @@ void unsat_core_learner::set_closed(proof* p, bool value) { m_closed.mark(p, value); } - + bool unsat_core_learner::is_b_open(proof *p) - { +{ return m_pr.is_b_marked(p) && !is_closed (p); - } +} void unsat_core_learner::add_lemma_to_core(expr* lemma) { m_unsat_core.push_back(lemma); - } +} } From f0f75d525415adc8cdb309dea50353e768e32ee7 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 10:42:57 -0700 Subject: [PATCH 0984/1283] Wire in arith-axiom-reducer --- src/muz/spacer/spacer_itp_solver.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index 9c11e0c1c..187a4a30f 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -287,23 +287,29 @@ void itp_solver::get_itp_core (expr_ref_vector &core) verbose_stream() << "Stats before transformation:"; iuc_before.print_farkas_stats(); } - - spacer::reduce_hypotheses(pr); - spacer::reduce_hypotheses(pr); - + + theory_axiom_reducer ta_reducer(m); + proof_ref pr_without_theory_lemmas = ta_reducer.reduce(pr.get()); + if (m_print_farkas_stats) { - iuc_proof iuc_after(m, pr.get(), B); - verbose_stream() << "Stats after transformation:"; + iuc_proof iuc_mid(m, pr_without_theory_lemmas.get(), B); + verbose_stream() << "Stats after first transformation:"; + iuc_mid.print_farkas_stats(); + } + + hypothesis_reducer hyp_reducer(m); + proof_ref pr_with_less_hypothesis = hyp_reducer.reduce(pr_without_theory_lemmas); + + if (m_print_farkas_stats) + { + iuc_proof iuc_after(m, pr_with_less_hypothesis.get(), B); + verbose_stream() << "Stats after second transformation:"; iuc_after.print_farkas_stats(); } - STRACE("spacer.unsat_core_learner", - verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n"; - ); - // construct proof object with contains partition information - iuc_proof iuc_pr(m, pr.get(), B); + iuc_proof iuc_pr(m, pr_with_less_hypothesis, B); // configure learner unsat_core_learner learner(m, iuc_pr, m_print_farkas_stats, m_iuc_debug_proof); From 85c58e344c14073afc8e6073cd59831797b60cf5 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Mon, 18 Dec 2017 16:45:58 +0100 Subject: [PATCH 0985/1283] Add option to use old_hyp_reducer --- src/muz/base/fixedpoint_params.pyg | 3 +- src/muz/spacer/spacer_itp_solver.cpp | 72 +++++++++++++++++---------- src/muz/spacer/spacer_itp_solver.h | 6 ++- src/muz/spacer/spacer_prop_solver.cpp | 4 +- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 74903baf1..65d89e420 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -182,7 +182,8 @@ def_module_params('fixedpoint', ('spacer.instantiate', BOOL, True, 'instantiate quantified lemmas'), ('spacer.qlemmas', BOOL, True, 'allow quantified lemmas in frames'), ('spacer.iuc', UINT, 1, '0 = use old implementation of unsat-core-generation, 1 = use new implementation of IUC generation, 2 = use new implementation of IUC + min-cut optimization'), - ('spacer.iuc.arith', UINT, 2, '0 = use simple Farkas plugin, 1 = use simple Farkas plugin with constant from other partition (like old unsat-core-generation), 2 = use Gaussian elimination optimization, 3 = use additive IUC plugin'), + ('spacer.iuc.arith', UINT, 2, '0 = use simple Farkas plugin, 1 = use simple Farkas plugin with constant from other partition (like old unsat-core-generation), 2 = use Gaussian elimination optimization, 3 = use additive IUC plugin'), + ('spacer.old_hyp_reducer', BOOL, False, 'use old hyp reducer instead of new implementation, for debugging only'), ('spacer.lemma_sanity_check', BOOL, False, 'check during generalization whether lemma is actually correct'), ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), ('spacer.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index 187a4a30f..35e06f9a2 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -19,6 +19,7 @@ Notes: #include"muz/spacer/spacer_itp_solver.h" #include"ast/ast.h" #include"muz/spacer/spacer_util.h" +#include"muz/base/proof_utils.h" #include"muz/spacer/spacer_farkas_learner.h" #include"ast/rewriter/expr_replacer.h" #include"muz/spacer/spacer_unsat_core_learner.h" @@ -277,39 +278,56 @@ void itp_solver::get_itp_core (expr_ref_vector &core) } else { + proof_ref res(get_proof(),m); + // new code - // preprocess proof in order to get a proof which is better suited for unsat-core-extraction - proof_ref pr(get_proof(), m); - - if (m_print_farkas_stats) + if (m_old_hyp_reducer) { - iuc_proof iuc_before(m, pr.get(), B); - verbose_stream() << "Stats before transformation:"; - iuc_before.print_farkas_stats(); + // preprocess proof in order to get a proof which is better suited for unsat-core-extraction + if (m_print_farkas_stats) + { + iuc_proof iuc_before(m, res.get(), B); + verbose_stream() << "\nStats before transformation:"; + iuc_before.print_farkas_stats(); + } + + proof_utils::reduce_hypotheses(res); + proof_utils::permute_unit_resolution(res); + + if (m_print_farkas_stats) + { + iuc_proof iuc_after(m, res.get(), B); + verbose_stream() << "Stats after transformation:"; + iuc_after.print_farkas_stats(); + } } - - theory_axiom_reducer ta_reducer(m); - proof_ref pr_without_theory_lemmas = ta_reducer.reduce(pr.get()); - - if (m_print_farkas_stats) + else { - iuc_proof iuc_mid(m, pr_without_theory_lemmas.get(), B); - verbose_stream() << "Stats after first transformation:"; - iuc_mid.print_farkas_stats(); + // preprocess proof in order to get a proof which is better suited for unsat-core-extraction + if (m_print_farkas_stats) + { + iuc_proof iuc_before(m, res.get(), B); + verbose_stream() << "\nStats before transformation:"; + iuc_before.print_farkas_stats(); + } + + theory_axiom_reducer ta_reducer(m); + proof_ref pr_without_theory_lemmas = ta_reducer.reduce(res.get()); + + hypothesis_reducer hyp_reducer(m); + proof_ref pr_with_less_hypothesis = hyp_reducer.reduce(pr_without_theory_lemmas); + + if (m_print_farkas_stats) + { + iuc_proof iuc_after(m, pr_with_less_hypothesis.get(), B); + verbose_stream() << "Stats after transformation:"; + iuc_after.print_farkas_stats(); + } + res = pr_with_less_hypothesis; } - - hypothesis_reducer hyp_reducer(m); - proof_ref pr_with_less_hypothesis = hyp_reducer.reduce(pr_without_theory_lemmas); - - if (m_print_farkas_stats) - { - iuc_proof iuc_after(m, pr_with_less_hypothesis.get(), B); - verbose_stream() << "Stats after second transformation:"; - iuc_after.print_farkas_stats(); - } - + // construct proof object with contains partition information - iuc_proof iuc_pr(m, pr_with_less_hypothesis, B); + iuc_proof iuc_pr(m, res, B); // configure learner unsat_core_learner learner(m, iuc_pr, m_print_farkas_stats, m_iuc_debug_proof); diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 5e5c2d39e..6f6a2bf8f 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -62,13 +62,14 @@ private: unsigned m_iuc_arith; bool m_print_farkas_stats; bool m_iuc_debug_proof; + bool m_old_hyp_reducer; bool is_proxy(expr *e, app_ref &def); void undo_proxies_in_core(ptr_vector &v); app* mk_proxy(expr *v); app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - itp_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool iuc_debug_proof, bool split_literals = false) : + itp_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool iuc_debug_proof, bool old_hyp_reducer, bool split_literals = false) : m(solver.get_manager()), m_solver(solver), m_proxies(m), @@ -82,7 +83,8 @@ public: m_iuc(iuc), m_iuc_arith(iuc_arith), m_print_farkas_stats(print_farkas_stats), - m_iuc_debug_proof(iuc_debug_proof) + m_iuc_debug_proof(iuc_debug_proof), + m_old_hyp_reducer(old_hyp_reducer) {} ~itp_solver() override {} diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 60deac214..03c9b858b 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -60,8 +60,8 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_solvers[1] = pm.mk_fresh2(); m_fparams[1] = &pm.fparams2(); - m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_iuc_debug_proof(), p.spacer_split_farkas_literals()); - m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_iuc_debug_proof(), p.spacer_split_farkas_literals()); + m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_iuc_debug_proof(), p.spacer_old_hyp_reducer(), p.spacer_split_farkas_literals()); + m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_iuc_debug_proof(), p.spacer_old_hyp_reducer(), p.spacer_split_farkas_literals()); for (unsigned i = 0; i < 2; ++i) { m_contexts[i]->assert_expr(m_pm.get_background()); } From 295d16bfae929e2a1bf4498fcfe3ab0b765d0ec4 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Tue, 19 Dec 2017 15:28:53 +0100 Subject: [PATCH 0986/1283] Rewrite hyp-reducer This is a new version that conceptually addresses the bugs in all previous version. However, it had a hard-to-debug memory corruption. The bug appeared only in optimized compilation under Linux with GCC. This code is suspect and should be reviewed and further tested --- src/muz/spacer/spacer_proof_utils.cpp | 338 ++++++++++++++++---------- src/muz/spacer/spacer_proof_utils.h | 42 ++-- 2 files changed, 220 insertions(+), 160 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 81fb7286a..4625cbdac 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -18,12 +18,14 @@ Revision History: #include "muz/spacer/spacer_proof_utils.h" #include "ast/ast_util.h" + #include "ast/ast_pp.h" #include "ast/proof_checker/proof_checker.h" #include #include "params.h" #include "muz/spacer/spacer_iuc_proof.h" +#include "muz/base/dl_util.h" namespace spacer { @@ -355,7 +357,7 @@ proof* ProofIteratorPostOrder::next() { bool dirty = false; // proof is dirty, if a subproof of one of its premises has been transformed - ptr_buffer args; + ptr_buffer args; for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { proof* pp = m.get_parent(p, i); @@ -376,7 +378,7 @@ proof* ProofIteratorPostOrder::next() } else // otherwise create new step with the corresponding proofs of the premises { - if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); } + if (m.has_fact(p)) { args.push_back(m.get_fact(p)); } SASSERT(p->get_decl()->get_arity() == args.size()); proof* res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); m_pinned.push_back(res); @@ -400,59 +402,103 @@ proof* ProofIteratorPostOrder::next() { m_cache.reset(); m_units.reset(); - m_hyps.reset(); - m_hypmark.reset(); + m_active_hyps.reset(); + m_parent_hyps.reset(); + m_pinned_active_hyps.reset(); + m_pinned_parent_hyps.reset(); m_pinned.reset(); } - void hypothesis_reducer::compute_hypmarks_and_hyps(proof* pr) + void hypothesis_reducer::compute_hypsets(proof* pr) { - proof *p; - ProofIteratorPostOrder pit(pr, m); - while (pit.hasNext()) { - p = pit.next(); - if (m.is_hypothesis(p)) + ptr_vector todo; + todo.push_back(pr); + + while (!todo.empty()) + { + proof* p = todo.back(); + + if (m_active_hyps.contains(p)) { - m_hypmark.mark(p, true); - m_hyps.insert(m.get_fact(p)); + SASSERT(m_parent_hyps.contains(p)); + todo.pop_back(); } + // if we haven't already visited the current unit else { - compute_hypmark_from_parents(p); - } - } - } - - bool hypothesis_reducer::compute_hypmark_from_parents(proof *pr) - { - bool hyp_mark = false; - - if (!m.is_lemma(pr)) // lemmas clear all hypotheses - { - for (unsigned i = 0, sz = m.get_num_parents(pr); i < sz; ++i) - { - if (m_hypmark.is_marked(m.get_parent(pr, i))) + bool existsUnvisitedParent = false; + + // add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result + // for p now, but wait until those unprocessed premises are processed. + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + SASSERT(m.is_proof(p->get_arg(i))); + proof* premise = to_app(p->get_arg(i)); + + // if we haven't visited the premise yet + if (!m_active_hyps.contains(premise)) + { + SASSERT(!m_parent_hyps.contains(premise)); + // add it to the stack + todo.push_back(premise); + existsUnvisitedParent = true; + } + } + + // if we already visited all premises, we can visit p too + if (!existsUnvisitedParent) { - hyp_mark = true; - break; + todo.pop_back(); + + // create active_hyps-set and parent_hyps-set for step p + proof_set* active_hyps = alloc(proof_set); + m_pinned_active_hyps.insert(active_hyps); + m_active_hyps.insert(p, active_hyps); + + expr_set* parent_hyps = alloc(expr_set); + m_pinned_parent_hyps.insert(parent_hyps); + m_parent_hyps.insert(p, parent_hyps); + + // fill both sets + if (m.is_hypothesis(p)) + { + active_hyps->insert(p); + parent_hyps->insert(m.get_fact(p)); + } + else + { + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) + { + proof* pp = m.get_parent(p, i); + datalog::set_union(*parent_hyps, *m_parent_hyps.find(pp)); + + if (!m.is_lemma(p)) // lemmas clear all hypotheses + { + datalog::set_union(*active_hyps, *m_active_hyps.find(pp)); + } + } + } } } } - m_hypmark.mark(pr, hyp_mark); - return hyp_mark; } - + // collect all units that are hyp-free and are used as hypotheses somewhere - // requires that m_hypmarks and m_hyps have been computed + // requires that m_active_hyps and m_parent_hyps have been computed void hypothesis_reducer::collect_units(proof* pr) { + expr_set* all_hyps = m_parent_hyps.find(pr); + SASSERT(all_hyps != nullptr); + ProofIteratorPostOrder pit(pr, m); while (pit.hasNext()) { proof* p = pit.next(); if (!m.is_hypothesis(p)) { - // collect units that are hyp-free and are used as hypotheses somewhere - if (!m_hypmark.is_marked(p) && m.has_fact(p) && m_hyps.contains(m.get_fact(p))) + proof_set* active_hyps = m_active_hyps.find(p); + SASSERT(active_hyps != nullptr); + + // collect units that are hyp-free and are used as hypotheses in the proof pr + if (active_hyps->empty() && m.has_fact(p) && all_hyps->contains(m.get_fact(p))) { m_units.insert(m.get_fact(p), p); } @@ -462,8 +508,9 @@ proof* ProofIteratorPostOrder::next() proof_ref hypothesis_reducer::reduce(proof* pr) { - compute_hypmarks_and_hyps(pr); + compute_hypsets(pr); collect_units(pr); + proof* res = compute_transformed_proof(pr); SASSERT(res != nullptr); @@ -481,156 +528,162 @@ proof* ProofIteratorPostOrder::next() { proof *res = NULL; - m_todo.reset(); - m_todo.push_back(pf); + ptr_vector todo; + todo.push_back(pf); ptr_buffer args; bool dirty = false; - while (!m_todo.empty()) { - proof *p, *tmp, *tmp2, *pp; + while (!todo.empty()) { + proof *p, *tmp, *pp; unsigned todo_sz; - p = m_todo.back(); + p = todo.back(); if (m_cache.find(p, tmp)) { - res = tmp; - m_todo.pop_back(); + res = tmp; // TODO: shouldn't this line be removed? + todo.pop_back(); continue; } dirty = false; args.reset(); - todo_sz = m_todo.size(); + todo_sz = todo.size(); for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { pp = m.get_parent(p, i); if (m_cache.find(pp, tmp)) { args.push_back(tmp); dirty = dirty || pp != tmp; } else { - m_todo.push_back(pp); + todo.push_back(pp); } } - if (todo_sz < m_todo.size()) { continue; } - else { m_todo.pop_back(); } + if (todo_sz < todo.size()) { continue; } + else { todo.pop_back(); } - // here the transformation begins - // INV: for each premise of p, we have computed the transformed proof. + // here the proof transformation begins + // INV: whenever we visit p, active_hyps and parent_hyps have been computed for the args. if (m.is_hypothesis(p)) { // hyp: replace by a corresponding unit if (m_units.find(m.get_fact(p), tmp)) { - // if the transformed subproof ending in the unit has already been computed, use it - if (m_cache.find(tmp,tmp2)) + // look up the proof of the unit: + // if there is a transformed proof use that one + // otherwise use the original proof + proof* proof_of_unit; + if (!m_cache.find(tmp,proof_of_unit)) { - res = tmp2; + proof_of_unit = tmp; } - // otherwise first compute the transformed subproof ending in the unit + + // compute hypsets (have not been computed in general, since the unit can be anywhere in the proof) + compute_hypsets(proof_of_unit); + + // if the transformation doesn't create a cycle, perform it + SASSERT(m_parent_hyps.contains(proof_of_unit)); + expr_set* parent_hyps = m_parent_hyps.find(proof_of_unit); + if (!parent_hyps->contains(p)) + { + res = proof_of_unit; + // hypsets have already been computed for proof_of_unit + } + // otherwise don't transform the proof and just use the hypothesis else { - m_todo.push_back(tmp); - continue; + res = p; + // hypsets have already been computed for p } - } else { res = p; } + } + else + { + res = p; + // hypsets have already been computed for p + } } - else if (!dirty) { res = p; } - else if (m.is_lemma(p)) { + else if (m.is_lemma(p)) + { //lemma: reduce the premise; remove reduced consequences from conclusion SASSERT(args.size() == 1); - res = mk_lemma_core(args.get(0), m.get_fact(p)); - compute_hypmark_from_parents(res); - } else if (m.is_unit_resolution(p)) { + res = mk_lemma_core(args[0], m.get_fact(p)); + compute_hypsets(res); + } + else if (m.is_unit_resolution(p)) + { // unit: reduce untis; reduce the first premise; rebuild unit resolution - res = mk_unit_resolution_core(args.size(), args.c_ptr()); - compute_hypmark_from_parents(res); - } else { - // if any literal is false, we don't need a step - bool has_empty_clause_premise = false; - for (unsigned i = 0; i < args.size(); ++i) - { - if (m.is_false(m.get_fact(args[i]))) - { - has_empty_clause_premise = true; - res = args[i]; - } - } - - // otherwise: - if (!has_empty_clause_premise) - { - // other: reduce all premises; reapply - if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); } - SASSERT(p->get_decl()->get_arity() == args.size()); - res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); - m_pinned.push_back(res); - compute_hypmark_from_parents(res); - } + res = mk_unit_resolution_core(args); + compute_hypsets(res); + } + else + { + res = mk_step_core(p, args); + compute_hypsets(res); } SASSERT(res); - m_cache.insert(p, res); - - if (!m_hypmark.is_marked(res) && m.has_fact(res) && m.is_false(m.get_fact(res))) + m_cache.insert(p, res); + + SASSERT(m_active_hyps.contains(res)); + proof_set* active_hyps = m_active_hyps.find(res); + if (active_hyps->empty() && m.has_fact(res) && m.is_false(m.get_fact(res))) { return res; } } - } - - // returns true if (hypothesis (not a)) would be reduced - bool hypothesis_reducer::is_reduced(expr *a) - { - expr_ref e(m); - if (m.is_not(a)) { e = to_app(a)->get_arg(0); } - else { e = m.mk_not(a); } - - return m_units.contains(e); + UNREACHABLE(); + return nullptr; } - proof* hypothesis_reducer::mk_lemma_core(proof *pf, expr *fact) + proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { - ptr_buffer args; - expr_ref lemma(m); + SASSERT(m.is_false(m.get_fact(premise))); + + SASSERT(m_active_hyps.contains(premise)); + proof_set* active_hyps = m_active_hyps.find(premise); - if (m.is_or(fact)) { - for (unsigned i = 0, sz = to_app(fact)->get_num_args(); i < sz; ++i) { - expr *a = to_app(fact)->get_arg(i); - if (!is_reduced(a)) - { args.push_back(a); } + // if there is no active hypothesis return the premise + if (active_hyps->empty()) + { + return premise; + } + // otherwise build disjunction of the negated active hypothesis' and add lemma step. + else + { + expr_ref_buffer args(m); + for (auto hyp : *active_hyps) + { + expr* hyp_fact = m.get_fact(hyp); + expr_ref negated_hyp_fact(m); + negated_hyp_fact = m.is_not(hyp_fact) ? to_app(hyp_fact)->get_arg(0) : m.mk_not(hyp_fact); + args.push_back(negated_hyp_fact); } - } else if (!is_reduced(fact)) - { args.push_back(fact); } - - - if (args.size() == 0) { return pf; } - else if (args.size() == 1) { - lemma = args.get(0); - } else { - lemma = m.mk_or(args.size(), args.c_ptr()); + + expr_ref lemma(m); + if (args.size() == 1) + { + lemma = args[0]; + } + else + { + lemma = m.mk_or(args.size(), args.c_ptr()); + } + proof_ref res(m); + res = m.mk_lemma(premise, lemma); + m_pinned.push_back(res); + return res; } - proof* res = m.mk_lemma(pf, lemma); - m_pinned.push_back(res); - - // XXX this is wrong because lemma is a proof and m_hyps only - // XXX contains expressions. - // XXX Not sure this is ever needed. - if (m_hyps.contains(lemma)) { - m_units.insert(lemma, res); - } - return res; } - proof* hypothesis_reducer::mk_unit_resolution_core(unsigned num_args, proof* const *args) + proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) { - - ptr_buffer pf_args; - pf_args.push_back(args [0]); + ptr_buffer pf_args; // the arguments of the transformed unit resolution step + pf_args.push_back(args [0]); // the first element of args is the clause to resolve with // if any literal is false, we don't need a unit resolution step - for (unsigned i = 1; i < num_args; ++i) + // could be the case due to transformations which already have been done + for (unsigned i = 1; i < args.size(); ++i) { if (m.is_false(m.get_fact(args[i]))) { @@ -638,7 +691,7 @@ proof* ProofIteratorPostOrder::next() } } - app *cls_fact = to_app(m.get_fact(args[0])); + app *cls_fact = to_app(m.get_fact(args[0])); // BUG: I guess this shouldn't work with quantifiers (since they are no apps) ptr_buffer cls; if (m.is_or(cls_fact)) { for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) @@ -651,7 +704,7 @@ proof* ProofIteratorPostOrder::next() // XXX quadratic for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { found = false; - for (unsigned j = 1; j < num_args; ++j) { + for (unsigned j = 1; j < args.size(); ++j) { if (m.is_complement(cls.get(i), m.get_fact(args [j]))) { found = true; pf_args.push_back(args [j]); @@ -674,9 +727,30 @@ proof* ProofIteratorPostOrder::next() } else { - proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); + proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); m_pinned.push_back(res); return res; } } + + proof* hypothesis_reducer::mk_step_core(proof* old_step, ptr_buffer& args) + { + // if any of the literals is false, we don't need a step + for (unsigned i = 0; i < args.size(); ++i) + { + if (m.is_false(m.get_fact(args[i]))) + { + return args[i]; + } + } + + // otherwise build step + args.push_back(to_app(m.get_fact(old_step))); // BUG: I guess this doesn't work with quantifiers (since they are no apps) + + SASSERT(old_step->get_decl()->get_arity() == args.size()); + proof* res = m.mk_app(old_step->get_decl(), args.size(), (expr * const*)args.c_ptr()); + m_pinned.push_back(res); + return res; + } + }; diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index a0031fc07..abd612b57 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -77,41 +77,27 @@ private: private: typedef obj_hashtable expr_set; - + typedef obj_hashtable proof_set; + ast_manager &m; - // tracking all created expressions - expr_ref_vector m_pinned; - // maps each proof of a clause to the transformed subproof of that clause - obj_map m_cache; - - // maps each unit literals to the transformed subproof of that unit - obj_map m_units; - - // -- all hypotheses in the the proof - obj_hashtable m_hyps; - - // marks hypothetical proofs - ast_mark m_hypmark; - - std::vector m_pinned_hyp_sets; // tracking all created sets of hypothesis - obj_map m_hyp_anchestor; // maps each proof to the set of hypothesis it contains, needed to avoid creating cycles in the proof. - - // stack - ptr_vector m_todo; + expr_ref_vector m_pinned; // tracking all created expressions + ptr_vector m_pinned_active_hyps; // tracking all created sets of active hypothesis + ptr_vector m_pinned_parent_hyps; // tracking all created sets of parent hypothesis + + obj_map m_cache; // maps each proof of a clause to the transformed subproof of that clause + obj_map m_units; // maps each unit literal to the subproof of that unit + obj_map m_active_hyps; // maps each proof of a clause to the set of proofs of active hypothesis' of the clause + obj_map m_parent_hyps; // maps each proof of a clause to the hypothesis-fact, which are transitive parents of that clause, needed to avoid creating cycles in the proof. void reset(); + void compute_hypsets(proof* pr); // compute active_hyps and parent_hyps for pr + void collect_units(proof* pr); // compute m_units proof* compute_transformed_proof(proof* pf); - - void compute_hypmarks_and_hyps(proof* pr); - bool compute_hypmark_from_parents(proof *pr); - void collect_units(proof* pr); - - // returns true if (hypothesis (not a)) would be reduced - bool is_reduced(expr *a); proof* mk_lemma_core(proof *pf, expr *fact); - proof* mk_unit_resolution_core(unsigned num_args, proof* const *args); + proof* mk_unit_resolution_core(ptr_buffer& args); + proof* mk_step_core(proof* old_step, ptr_buffer& args); }; } #endif From 4b6921dffbbf7e6f0e41ade7db732dbb34d75ed3 Mon Sep 17 00:00:00 2001 From: Bernhard Gleiss Date: Wed, 10 Jan 2018 12:02:16 +0100 Subject: [PATCH 0987/1283] removed unnecessary assignment --- src/muz/spacer/spacer_proof_utils.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 4625cbdac..bbe53c362 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -539,7 +539,6 @@ proof* ProofIteratorPostOrder::next() p = todo.back(); if (m_cache.find(p, tmp)) { - res = tmp; // TODO: shouldn't this line be removed? todo.pop_back(); continue; } From 7c727ee9223c71a60575c1c57c145f6c0afeb864 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 12:13:18 -0700 Subject: [PATCH 0988/1283] Fix compiler warnings --- src/muz/spacer/spacer_generalizers.cpp | 1 + src/muz/spacer/spacer_itp_solver.cpp | 18 ++-- src/muz/spacer/spacer_itp_solver.h | 4 +- src/muz/spacer/spacer_proof_utils.cpp | 107 ++++++++++----------- src/muz/spacer/spacer_prop_solver.cpp | 10 +- src/muz/spacer/spacer_unsat_core_learner.h | 13 +-- 6 files changed, 79 insertions(+), 74 deletions(-) diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 2f9627398..4b0c3d15c 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -158,6 +158,7 @@ void unsat_core_generalizer::operator()(lemma_ref &lemma) unsigned old_sz = lemma->get_cube().size(); unsigned old_level = lemma->level(); + (void)old_level; unsigned uses_level; expr_ref_vector core(m); diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index 35e06f9a2..71587b4c6 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -279,7 +279,7 @@ void itp_solver::get_itp_core (expr_ref_vector &core) else { proof_ref res(get_proof(),m); - + // new code if (m_old_hyp_reducer) { @@ -290,10 +290,10 @@ void itp_solver::get_itp_core (expr_ref_vector &core) verbose_stream() << "\nStats before transformation:"; iuc_before.print_farkas_stats(); } - + proof_utils::reduce_hypotheses(res); proof_utils::permute_unit_resolution(res); - + if (m_print_farkas_stats) { iuc_proof iuc_after(m, res.get(), B); @@ -310,13 +310,13 @@ void itp_solver::get_itp_core (expr_ref_vector &core) verbose_stream() << "\nStats before transformation:"; iuc_before.print_farkas_stats(); } - + theory_axiom_reducer ta_reducer(m); proof_ref pr_without_theory_lemmas = ta_reducer.reduce(res.get()); - + hypothesis_reducer hyp_reducer(m); proof_ref pr_with_less_hypothesis = hyp_reducer.reduce(pr_without_theory_lemmas); - + if (m_print_farkas_stats) { iuc_proof iuc_after(m, pr_with_less_hypothesis.get(), B); @@ -328,9 +328,9 @@ void itp_solver::get_itp_core (expr_ref_vector &core) // construct proof object with contains partition information iuc_proof iuc_pr(m, res, B); - + // configure learner - unsat_core_learner learner(m, iuc_pr, m_print_farkas_stats, m_iuc_debug_proof); + unsat_core_learner learner(m, iuc_pr); if (m_iuc_arith == 0 || m_iuc_arith > 3) { @@ -352,7 +352,7 @@ void itp_solver::get_itp_core (expr_ref_vector &core) unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); learner.register_plugin(plugin_farkas_lemma_bounded); } - + if (m_iuc == 2) { unsat_core_plugin_min_cut* plugin_min_cut = alloc(unsat_core_plugin_min_cut, learner, m); diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index 6f6a2bf8f..0b3527bb3 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -61,7 +61,6 @@ private: unsigned m_iuc; unsigned m_iuc_arith; bool m_print_farkas_stats; - bool m_iuc_debug_proof; bool m_old_hyp_reducer; bool is_proxy(expr *e, app_ref &def); void undo_proxies_in_core(ptr_vector &v); @@ -69,7 +68,7 @@ private: app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - itp_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool iuc_debug_proof, bool old_hyp_reducer, bool split_literals = false) : + itp_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool old_hyp_reducer, bool split_literals = false) : m(solver.get_manager()), m_solver(solver), m_proxies(m), @@ -83,7 +82,6 @@ public: m_iuc(iuc), m_iuc_arith(iuc_arith), m_print_farkas_stats(print_farkas_stats), - m_iuc_debug_proof(iuc_debug_proof), m_old_hyp_reducer(old_hyp_reducer) {} diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index bbe53c362..735f94518 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -28,7 +28,7 @@ Revision History: #include "muz/base/dl_util.h" namespace spacer { - + // arith lemmas: second parameter specifies exact type of lemma, could be "farkas", "triangle-eq", "eq-propagate", "assign-bounds", maybe also something else bool is_arith_lemma(ast_manager& m, proof* pr) { @@ -44,7 +44,7 @@ namespace spacer { } return false; } - + bool is_farkas_lemma(ast_manager& m, proof* pr) { if (pr->get_decl_kind() == PR_TH_LEMMA) @@ -126,28 +126,28 @@ proof* ProofIteratorPostOrder::next() // open temporary dot-file std::string dotfile_path = "proof.dot"; std::ofstream dotstream(dotfile_path); - + // dump dot representation to stream pp_proof_dot_to_stream(m, dotstream, pr, iuc_pr); - + // post process dot-file, TODO: factor this out to a different place pp_proof_post_process_dot(dotfile_path,dotstream); } - + void pp_proof_dot_to_stream(ast_manager& m, std::ofstream& dotstream, proof* pr, iuc_proof* iuc_pr) { dotstream << "digraph proof { \n"; std::unordered_map id_to_small_id; unsigned counter = 0; - + ProofIteratorPostOrder it2(pr, m); while (it2.hasNext()) { proof* currentNode = it2.next(); - + SASSERT(id_to_small_id.find(currentNode->get_id()) == id_to_small_id.end()); id_to_small_id.insert(std::make_pair(currentNode->get_id(), counter)); - + std::string color = "white"; if (iuc_pr != nullptr) { @@ -169,11 +169,11 @@ proof* ProofIteratorPostOrder::next() params_ref p; p.set_uint("max_depth", 4294967295u); p.set_uint("min_alias_size", 4294967295u); - + std::ostringstream label_ostream; label_ostream << mk_pp(m.get_fact(currentNode),m,p) << "\n"; std::string label = escape_dot(label_ostream.str()); - + // compute edge-label std::string edge_label = ""; if (m.get_num_parents(currentNode) == 0) @@ -223,7 +223,7 @@ proof* ProofIteratorPostOrder::next() } } } - + // generate entry for node in dot-file dotstream << "node_" << counter << " " << "[" @@ -231,7 +231,7 @@ proof* ProofIteratorPostOrder::next() << "label=\"" << edge_label << " " << label << "\", " << "fillcolor=\"" << color << "\"" << "]\n"; - + // add entry for each edge to that node for (unsigned i = m.get_num_parents(currentNode); i > 0 ; --i) { @@ -242,12 +242,12 @@ proof* ProofIteratorPostOrder::next() << "node_" << counter << ";\n"; } - + ++counter; } dotstream << "\n}" << std::endl; } - + std::string escape_dot(const std::string &s) { std::string res; @@ -260,7 +260,7 @@ proof* ProofIteratorPostOrder::next() } return res; } - + void pp_proof_post_process_dot(std::string dot_filepath, std::ofstream &dotstream) { // replace variables in the dotfiles with nicer descriptions (hack: hard coded replacement for now) @@ -269,7 +269,7 @@ proof* ProofIteratorPostOrder::next() predicates.push_back(l1); std::vector l2 = {"L2","j","m","B"}; predicates.push_back(l2); - + for(auto& predicate : predicates) { std::string predicate_name = predicate[0]; @@ -278,17 +278,17 @@ proof* ProofIteratorPostOrder::next() std::string new_name = predicate[i+1]; std::string substring0 = predicate_name + "_" + std::to_string(i) + "_0"; std::string substringN = predicate_name + "_" + std::to_string(i) + "_n"; - + std::string command0 = "sed -i '.bak' 's/" + substring0 + "/" + new_name + "/g' " + dot_filepath; verbose_stream() << command0 << std::endl; system(command0.c_str()); - + std::string commandN = "sed -i '.bak' s/" + substringN + "/" + new_name + "\\'" + "/g " + dot_filepath; verbose_stream() << commandN << std::endl; system(commandN.c_str()); } } - + verbose_stream() << "end of postprocessing"; } @@ -297,20 +297,20 @@ proof* ProofIteratorPostOrder::next() * methods for transforming proofs * ==================================== */ - + void theory_axiom_reducer::reset() { m_cache.reset(); m_pinned.reset(); } - + proof_ref theory_axiom_reducer::reduce(proof* pr) { ProofIteratorPostOrder pit(pr, m); while (pit.hasNext()) { proof* p = pit.next(); - + if (m.get_num_parents(p) == 0 && is_arith_lemma(m, p)) { // we have an arith-theory-axiom and want to get rid of it @@ -321,7 +321,7 @@ proof* ProofIteratorPostOrder::next() for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) { cls.push_back(cls_fact->get_arg(i)); } } else { cls.push_back(cls_fact); } - + // 1a) create hypothesis' ptr_buffer hyps; for (unsigned i=0; i < cls.size(); ++i) @@ -331,7 +331,7 @@ proof* ProofIteratorPostOrder::next() m_pinned.push_back(hyp); hyps.push_back(hyp); } - + // 1b) create farkas lemma: need to rebuild parameters since mk_th_lemma adds tid as first parameter unsigned num_params = p->get_decl()->get_num_parameters(); parameter const* params = p->get_decl()->get_parameters(); @@ -339,14 +339,14 @@ proof* ProofIteratorPostOrder::next() for (unsigned i = 1; i < num_params; ++i) { parameters.push_back(params[i]); } - + SASSERT(params[0].is_symbol()); family_id tid = m.mk_family_id(params[0].get_symbol()); SASSERT(tid != null_family_id); - + proof* th_lemma = m.mk_th_lemma(tid, m.mk_false(),hyps.size(), hyps.c_ptr(), num_params-1, parameters.c_ptr()); SASSERT(is_arith_lemma(m, th_lemma)); - + // 1c) create lemma proof* res = m.mk_lemma(th_lemma, cls_fact); SASSERT(m.get_fact(res) == m.get_fact(p)); @@ -386,15 +386,14 @@ proof* ProofIteratorPostOrder::next() } } } - + proof* res; - bool found = m_cache.find(pr,res); - SASSERT(found); + VERIFY(m_cache.find(pr,res)); DEBUG_CODE(proof_checker pc(m); expr_ref_vector side(m); SASSERT(pc.check(res, side)); ); - + return proof_ref(res,m); } @@ -408,16 +407,16 @@ proof* ProofIteratorPostOrder::next() m_pinned_parent_hyps.reset(); m_pinned.reset(); } - + void hypothesis_reducer::compute_hypsets(proof* pr) { ptr_vector todo; todo.push_back(pr); - + while (!todo.empty()) { proof* p = todo.back(); - + if (m_active_hyps.contains(p)) { SASSERT(m_parent_hyps.contains(p)); @@ -427,13 +426,13 @@ proof* ProofIteratorPostOrder::next() else { bool existsUnvisitedParent = false; - + // add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result // for p now, but wait until those unprocessed premises are processed. for (unsigned i = 0; i < m.get_num_parents(p); ++i) { SASSERT(m.is_proof(p->get_arg(i))); proof* premise = to_app(p->get_arg(i)); - + // if we haven't visited the premise yet if (!m_active_hyps.contains(premise)) { @@ -443,7 +442,7 @@ proof* ProofIteratorPostOrder::next() existsUnvisitedParent = true; } } - + // if we already visited all premises, we can visit p too if (!existsUnvisitedParent) { @@ -453,11 +452,11 @@ proof* ProofIteratorPostOrder::next() proof_set* active_hyps = alloc(proof_set); m_pinned_active_hyps.insert(active_hyps); m_active_hyps.insert(p, active_hyps); - + expr_set* parent_hyps = alloc(expr_set); m_pinned_parent_hyps.insert(parent_hyps); m_parent_hyps.insert(p, parent_hyps); - + // fill both sets if (m.is_hypothesis(p)) { @@ -481,7 +480,7 @@ proof* ProofIteratorPostOrder::next() } } } - + // collect all units that are hyp-free and are used as hypotheses somewhere // requires that m_active_hyps and m_parent_hyps have been computed void hypothesis_reducer::collect_units(proof* pr) @@ -510,12 +509,12 @@ proof* ProofIteratorPostOrder::next() { compute_hypsets(pr); collect_units(pr); - + proof* res = compute_transformed_proof(pr); SASSERT(res != nullptr); - + proof_ref res_ref(res,m); - + reset(); DEBUG_CODE(proof_checker pc(m); expr_ref_vector side(m); @@ -523,7 +522,7 @@ proof* ProofIteratorPostOrder::next() ); return res_ref; } - + proof* hypothesis_reducer::compute_transformed_proof(proof* pf) { proof *res = NULL; @@ -559,7 +558,7 @@ proof* ProofIteratorPostOrder::next() if (todo_sz < todo.size()) { continue; } else { todo.pop_back(); } - + // here the proof transformation begins // INV: whenever we visit p, active_hyps and parent_hyps have been computed for the args. if (m.is_hypothesis(p)) @@ -578,7 +577,7 @@ proof* ProofIteratorPostOrder::next() // compute hypsets (have not been computed in general, since the unit can be anywhere in the proof) compute_hypsets(proof_of_unit); - + // if the transformation doesn't create a cycle, perform it SASSERT(m_parent_hyps.contains(proof_of_unit)); expr_set* parent_hyps = m_parent_hyps.find(proof_of_unit); @@ -622,8 +621,8 @@ proof* ProofIteratorPostOrder::next() } SASSERT(res); - m_cache.insert(p, res); - + m_cache.insert(p, res); + SASSERT(m_active_hyps.contains(res)); proof_set* active_hyps = m_active_hyps.find(res); if (active_hyps->empty() && m.has_fact(res) && m.is_false(m.get_fact(res))) @@ -634,11 +633,11 @@ proof* ProofIteratorPostOrder::next() UNREACHABLE(); return nullptr; } - + proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { SASSERT(m.is_false(m.get_fact(premise))); - + SASSERT(m_active_hyps.contains(premise)); proof_set* active_hyps = m_active_hyps.find(premise); @@ -658,7 +657,7 @@ proof* ProofIteratorPostOrder::next() negated_hyp_fact = m.is_not(hyp_fact) ? to_app(hyp_fact)->get_arg(0) : m.mk_not(hyp_fact); args.push_back(negated_hyp_fact); } - + expr_ref lemma(m); if (args.size() == 1) { @@ -731,7 +730,7 @@ proof* ProofIteratorPostOrder::next() return res; } } - + proof* hypothesis_reducer::mk_step_core(proof* old_step, ptr_buffer& args) { // if any of the literals is false, we don't need a step @@ -742,10 +741,10 @@ proof* ProofIteratorPostOrder::next() return args[i]; } } - + // otherwise build step args.push_back(to_app(m.get_fact(old_step))); // BUG: I guess this doesn't work with quantifiers (since they are no apps) - + SASSERT(old_step->get_decl()->get_arity() == args.size()); proof* res = m.mk_app(old_step->get_decl(), args.size(), (expr * const*)args.c_ptr()); m_pinned.push_back(res); diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 03c9b858b..d14cd6e91 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -60,8 +60,14 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_solvers[1] = pm.mk_fresh2(); m_fparams[1] = &pm.fparams2(); - m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_iuc_debug_proof(), p.spacer_old_hyp_reducer(), p.spacer_split_farkas_literals()); - m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_print_farkas_stats(), p.spacer_iuc_debug_proof(), p.spacer_old_hyp_reducer(), p.spacer_split_farkas_literals()); + m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), + p.spacer_iuc_arith(), + p.spacer_old_hyp_reducer(), + p.spacer_split_farkas_literals()); + m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), + p.spacer_iuc_arith(), + p.spacer_old_hyp_reducer(), + p.spacer_split_farkas_literals()); for (unsigned i = 0; i < 2; ++i) { m_contexts[i]->assert_expr(m_pm.get_background()); } diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 16b27f4ba..a8b5965fc 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -32,7 +32,8 @@ namespace spacer { typedef obj_hashtable expr_set; public: - unsat_core_learner(ast_manager& m, iuc_proof& pr, bool print_farkas_stats = false, bool iuc_debug_proof = false) : m(m), m_pr(pr), m_unsat_core(m), m_print_farkas_stats(print_farkas_stats), m_iuc_debug_proof(iuc_debug_proof) {}; + unsat_core_learner(ast_manager& m, iuc_proof& pr) : + m(m), m_pr(pr), m_unsat_core(m) {}; virtual ~unsat_core_learner(); ast_manager& m; @@ -60,7 +61,7 @@ namespace spacer { void set_closed(proof* p, bool value); bool is_b_open (proof *p); - + /* * adds a lemma to the unsat core */ @@ -72,7 +73,9 @@ namespace spacer { ptr_vector m_plugins; ast_mark m_closed; - expr_ref_vector m_unsat_core; // collects the lemmas of the unsat-core, will at the end be inserted into unsat_core. + // collects the lemmas of the unsat-core + // will at the end be inserted into unsat_core. + expr_ref_vector m_unsat_core; /* * computes partial core for step by delegating computation to plugins @@ -83,9 +86,7 @@ namespace spacer { * finalize computation of unsat-core */ void finalize(); - - bool m_print_farkas_stats; - bool m_iuc_debug_proof; + }; } From 83adb6742eca2e1b27d027f06fbb47d3d3f46a88 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 12:17:30 -0700 Subject: [PATCH 0989/1283] Remove whitespace --- src/muz/spacer/spacer_farkas_learner.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/muz/spacer/spacer_farkas_learner.h b/src/muz/spacer/spacer_farkas_learner.h index 724b18b73..0e696f4f1 100644 --- a/src/muz/spacer/spacer_farkas_learner.h +++ b/src/muz/spacer/spacer_farkas_learner.h @@ -24,12 +24,6 @@ Revision History: namespace spacer { - - - - - - class farkas_learner { typedef obj_hashtable expr_set; From 39bdecf9c283cc68966fb8aaa56aa5967e548564 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 12:26:28 -0700 Subject: [PATCH 0990/1283] Minor code cleanup --- src/muz/spacer/spacer_itp_solver.cpp | 34 +++++++++++++---------- src/muz/spacer/spacer_unsat_core_plugin.h | 7 ++++- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_itp_solver.cpp index 71587b4c6..fabe9a57f 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_itp_solver.cpp @@ -265,10 +265,10 @@ void itp_solver::get_itp_core (expr_ref_vector &core) if (m_iuc == 0) { + // ORIGINAL PDR CODE proof_ref pr(m); pr = get_proof (); - // old code farkas_learner learner_old; learner_old.set_split_literals(m_split_literals); @@ -278,9 +278,10 @@ void itp_solver::get_itp_core (expr_ref_vector &core) } else { - proof_ref res(get_proof(),m); + // NEW IUC + proof_ref res(get_proof(), m); - // new code + // -- old hypothesis reducer while the new one is broken if (m_old_hyp_reducer) { // preprocess proof in order to get a proof which is better suited for unsat-core-extraction @@ -301,7 +302,7 @@ void itp_solver::get_itp_core (expr_ref_vector &core) iuc_after.print_farkas_stats(); } } - else + else // -- new hypothesis reducer { // preprocess proof in order to get a proof which is better suited for unsat-core-extraction if (m_print_farkas_stats) @@ -312,44 +313,49 @@ void itp_solver::get_itp_core (expr_ref_vector &core) } theory_axiom_reducer ta_reducer(m); - proof_ref pr_without_theory_lemmas = ta_reducer.reduce(res.get()); + proof_ref pr1(ta_reducer.reduce (res.get()), m); hypothesis_reducer hyp_reducer(m); - proof_ref pr_with_less_hypothesis = hyp_reducer.reduce(pr_without_theory_lemmas); + proof_ref pr2(hyp_reducer.reduce(pr1), m); + + res = pr2; if (m_print_farkas_stats) { - iuc_proof iuc_after(m, pr_with_less_hypothesis.get(), B); + iuc_proof iuc_after(m, res.get(), B); verbose_stream() << "Stats after transformation:"; iuc_after.print_farkas_stats(); } - res = pr_with_less_hypothesis; } // construct proof object with contains partition information - iuc_proof iuc_pr(m, res, B); + iuc_proof iuc_pf(m, res, B); // configure learner - unsat_core_learner learner(m, iuc_pr); + unsat_core_learner learner(m, iuc_pf); if (m_iuc_arith == 0 || m_iuc_arith > 3) { - unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, false); + unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, + learner, m_split_literals, + false /* use constants from A */); learner.register_plugin(plugin_farkas_lemma); } else if (m_iuc_arith == 1) { - unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, true); + unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, + learner, m_split_literals, + true /* use constants from A */); learner.register_plugin(plugin_farkas_lemma); } else if (m_iuc_arith == 2) { - unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner,m); + unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m); learner.register_plugin(plugin_farkas_lemma_optimized); } else if(m_iuc_arith == 3) { - unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner,m); + unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m); learner.register_plugin(plugin_farkas_lemma_bounded); } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index 6b679f3f2..cd361000a 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -53,7 +53,12 @@ private: class unsat_core_plugin_farkas_lemma : public unsat_core_plugin { public: - unsat_core_plugin_farkas_lemma(unsat_core_learner& learner, bool split_literals, bool use_constant_from_a=true) : unsat_core_plugin(learner), m_split_literals(split_literals), m_use_constant_from_a(use_constant_from_a) {}; + unsat_core_plugin_farkas_lemma(unsat_core_learner& learner, + bool split_literals, + bool use_constant_from_a=true) : + unsat_core_plugin(learner), + m_split_literals(split_literals), + m_use_constant_from_a(use_constant_from_a) {}; void compute_partial_core(proof* step) override; From 5d3b515a5070859fa4566e6007a7b2f437089c6d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 12:36:54 -0700 Subject: [PATCH 0991/1283] Cleanup option names and default values --- src/muz/base/fixedpoint_params.pyg | 31 +++++++++++++++------------ src/muz/spacer/spacer_context.cpp | 14 ++++++------ src/muz/spacer/spacer_prop_solver.cpp | 8 +++---- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 65d89e420..799e06fe6 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -166,7 +166,7 @@ def_module_params('fixedpoint', ('spacer.nondet_tie_break', BOOL, False, "Break ties in obligation queue non-deterministically"), ('spacer.reach_dnf', BOOL, True, "Restrict reachability facts to DNF"), ('bmc.linear_unrolling_depth', UINT, UINT_MAX, "Maximal level to explore"), - ('spacer.split_farkas_literals', BOOL, False, "Split Farkas literals"), + ('spacer.iuc.split_farkas_literals', BOOL, False, "Split Farkas literals"), ('spacer.native_mbp', BOOL, False, "Use native mbp of Z3"), ('spacer.eq_prop', BOOL, True, "Enable equality and bound propagation in arithmetic"), ('spacer.weak_abs', BOOL, True, "Weak abstraction"), @@ -179,23 +179,26 @@ def_module_params('fixedpoint', ('spacer.vs.recheck', BOOL, False, 're-check locally during benchmark dumping'), ('spacer.mbqi', BOOL, True, 'use model-based quantifier instantiation'), ('spacer.keep_proxy', BOOL, True, 'keep proxy variables (internal parameter)'), - ('spacer.instantiate', BOOL, True, 'instantiate quantified lemmas'), - ('spacer.qlemmas', BOOL, True, 'allow quantified lemmas in frames'), - ('spacer.iuc', UINT, 1, '0 = use old implementation of unsat-core-generation, 1 = use new implementation of IUC generation, 2 = use new implementation of IUC + min-cut optimization'), - ('spacer.iuc.arith', UINT, 2, '0 = use simple Farkas plugin, 1 = use simple Farkas plugin with constant from other partition (like old unsat-core-generation), 2 = use Gaussian elimination optimization, 3 = use additive IUC plugin'), - ('spacer.old_hyp_reducer', BOOL, False, 'use old hyp reducer instead of new implementation, for debugging only'), + ('spacer.q3.instantiate', BOOL, True, 'instantiate quantified lemmas'), + ('spacer.q3', BOOL, True, 'allow quantified lemmas in frames'), + ('spacer.iuc', UINT, 0, + '0 = use old implementation of unsat-core-generation, ' + + '1 = use new implementation of IUC generation, ' + + '2 = use new implementation of IUC + min-cut optimization'), + ('spacer.iuc.arith', UINT, 0, + '0 = use simple Farkas plugin, ' + + '1 = use simple Farkas plugin with constant from other partition (like old unsat-core-generation),' + + '2 = use Gaussian elimination optimization (broken), 3 = use additive IUC plugin'), + ('spacer.iuc.old_hyp_reducer', BOOL, True, 'use old hyp reducer instead of new implementation, for debugging only'), ('spacer.lemma_sanity_check', BOOL, False, 'check during generalization whether lemma is actually correct'), ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), - ('spacer.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), + ('spacer.iuc.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), ('spacer.iuc.debug_proof', BOOL, False, 'prints proof used by unsat-core-learner for debugging purposes'), ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints'), - ('spacer.use_quant_generalizer', BOOL, False, 'use quantified lemma generalizer'), - ('spacer.quic_gen_normalize', BOOL, True, 'normalize cube before quantified generalization'), - ('spacer.share_lemmas', BOOL, False, "Share frame lemmas"), - ('spacer.share_invariants', BOOL, False, "Share invariants lemmas"), + ('spacer.q3.use_qgen', BOOL, False, 'use quantified lemma generalizer'), + ('spacer.q3.qgen.normalize', BOOL, True, 'normalize cube before quantified generalization'), + ('spacer.p3.share_lemmas', BOOL, False, 'Share frame lemmas'), + ('spacer.p3.share_invariants', BOOL, False, "Share invariants lemmas"), ('spacer.from_level', UINT, 0, 'starting level to explore'), ('spacer.print_json', SYMBOL, '', 'print pobs tree in JSON format to a given file') )) - - - diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index f700ce83e..60f6b9a85 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2026,8 +2026,8 @@ context::context(fixedpoint_params const& params, m_expanded_lvl(0), m_use_native_mbp(params.spacer_native_mbp ()), m_ground_cti (params.spacer_ground_cti ()), - m_instantiate (params.spacer_instantiate ()), - m_use_qlemmas (params.spacer_qlemmas ()), + m_instantiate (params.spacer_q3_instantiate ()), + m_use_qlemmas (params.spacer_q3()), m_weak_abs(params.spacer_weak_abs()), m_use_restarts(params.spacer_restarts()), m_restart_initial_threshold(params.spacer_restart_initial_threshold()), @@ -2303,11 +2303,11 @@ void context::init_lemma_generalizers(datalog::rule_set& rules) fparams.m_ng_lift_ite = LI_FULL; } - if (m_params.spacer_use_quant_generalizer()) { + if (m_params.spacer_q3_use_qgen()) { m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0, true)); m_lemma_generalizers.push_back(alloc(lemma_quantifier_generalizer, *this, - m_params.spacer_quic_gen_normalize())); + m_params.spacer_q3_qgen_normalize())); } if (get_params().spacer_use_eqclass()) { @@ -3138,7 +3138,7 @@ lbool context::expand_node(pob& n) sanity_checker(lemma); ); - + TRACE("spacer", tout << "invariant state: " << (is_infty_level(lemma->level())?"(inductive)":"") << mk_pp(lemma->get_expr(), m) << "\n";); @@ -3649,8 +3649,8 @@ void context::new_lemma_eh(pred_transformer &pt, lemma *lem) { } if (!handle) return; - if ((is_infty_level(lem->level()) && m_params.spacer_share_invariants()) || - (!is_infty_level(lem->level()) && m_params.spacer_share_lemmas())) { + if ((is_infty_level(lem->level()) && m_params.spacer_p3_share_invariants()) || + (!is_infty_level(lem->level()) && m_params.spacer_p3_share_lemmas())) { expr_ref_vector args(m); for (unsigned i = 0; i < pt.sig_size(); ++i) { args.push_back(m.mk_const(pt.get_manager().o2n(pt.sig(i), 0))); diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index d14cd6e91..9850f9e6e 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -62,12 +62,12 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), p.spacer_iuc_arith(), - p.spacer_old_hyp_reducer(), - p.spacer_split_farkas_literals()); + p.spacer_iuc_old_hyp_reducer(), + p.spacer_iuc_split_farkas_literals()); m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), p.spacer_iuc_arith(), - p.spacer_old_hyp_reducer(), - p.spacer_split_farkas_literals()); + p.spacer_iuc_old_hyp_reducer(), + p.spacer_iuc_split_farkas_literals()); for (unsigned i = 0; i < 2; ++i) { m_contexts[i]->assert_expr(m_pm.get_background()); } From 649bab2f58867460d5f98b78bdda15a12d6ae73e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 12:44:07 -0700 Subject: [PATCH 0992/1283] Rename itp_solver into iuc_solver IUC stands for Interpolanted UNSAT Core --- src/muz/spacer/CMakeLists.txt | 2 +- ...r_itp_solver.cpp => spacer_iuc_solver.cpp} | 60 +++++++++---------- ...pacer_itp_solver.h => spacer_iuc_solver.h} | 34 ++++++----- src/muz/spacer/spacer_prop_solver.cpp | 10 ++-- src/muz/spacer/spacer_prop_solver.h | 6 +- 5 files changed, 57 insertions(+), 55 deletions(-) rename src/muz/spacer/{spacer_itp_solver.cpp => spacer_iuc_solver.cpp} (88%) rename src/muz/spacer/{spacer_itp_solver.h => spacer_iuc_solver.h} (85%) diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 310d9a942..dad8dfa98 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -11,7 +11,7 @@ z3_add_component(spacer spacer_smt_context_manager.cpp spacer_sym_mux.cpp spacer_util.cpp - spacer_itp_solver.cpp + spacer_iuc_solver.cpp spacer_virtual_solver.cpp spacer_legacy_mbp.cpp spacer_unsat_core_learner.cpp diff --git a/src/muz/spacer/spacer_itp_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp similarity index 88% rename from src/muz/spacer/spacer_itp_solver.cpp rename to src/muz/spacer/spacer_iuc_solver.cpp index fabe9a57f..90a28c341 100644 --- a/src/muz/spacer/spacer_itp_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -3,11 +3,11 @@ Copyright (c) 2017 Arie Gurfinkel Module Name: - spacer_itp_solver.cpp + spacer_iuc_solver.cpp Abstract: - A solver that produces interpolated unsat cores + A solver that produces interpolated unsat cores (IUCs) Author: @@ -16,7 +16,7 @@ Author: Notes: --*/ -#include"muz/spacer/spacer_itp_solver.h" +#include"muz/spacer/spacer_iuc_solver.h" #include"ast/ast.h" #include"muz/spacer/spacer_util.h" #include"muz/base/proof_utils.h" @@ -27,13 +27,13 @@ Notes: #include "muz/spacer/spacer_iuc_proof.h" namespace spacer { -void itp_solver::push () +void iuc_solver::push () { m_defs.push_back (def_manager (*this)); m_solver.push (); } -void itp_solver::pop (unsigned n) +void iuc_solver::pop (unsigned n) { m_solver.pop (n); unsigned lvl = m_defs.size (); @@ -45,7 +45,7 @@ void itp_solver::pop (unsigned n) } } -app* itp_solver::fresh_proxy () +app* iuc_solver::fresh_proxy () { if (m_num_proxies == m_proxies.size()) { std::stringstream name; @@ -64,7 +64,7 @@ app* itp_solver::fresh_proxy () return m_proxies.get (m_num_proxies++); } -app* itp_solver::mk_proxy (expr *v) +app* iuc_solver::mk_proxy (expr *v) { { expr *e = v; @@ -76,7 +76,7 @@ app* itp_solver::mk_proxy (expr *v) return def.mk_proxy (v); } -bool itp_solver::mk_proxies (expr_ref_vector &v, unsigned from) +bool iuc_solver::mk_proxies (expr_ref_vector &v, unsigned from) { bool dirty = false; for (unsigned i = from, sz = v.size(); i < sz; ++i) { @@ -87,7 +87,7 @@ bool itp_solver::mk_proxies (expr_ref_vector &v, unsigned from) return dirty; } -void itp_solver::push_bg (expr *e) +void iuc_solver::push_bg (expr *e) { if (m_assumptions.size () > m_first_assumption) { m_assumptions.shrink(m_first_assumption); } @@ -95,7 +95,7 @@ void itp_solver::push_bg (expr *e) m_first_assumption = m_assumptions.size (); } -void itp_solver::pop_bg (unsigned n) +void iuc_solver::pop_bg (unsigned n) { if (n == 0) { return; } @@ -105,9 +105,9 @@ void itp_solver::pop_bg (unsigned n) m_assumptions.shrink (m_first_assumption); } -unsigned itp_solver::get_num_bg () {return m_first_assumption;} +unsigned iuc_solver::get_num_bg () {return m_first_assumption;} -lbool itp_solver::check_sat (unsigned num_assumptions, expr * const *assumptions) +lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions) { // -- remove any old assumptions if (m_assumptions.size () > m_first_assumption) @@ -128,7 +128,7 @@ lbool itp_solver::check_sat (unsigned num_assumptions, expr * const *assumptions } -app* itp_solver::def_manager::mk_proxy (expr *v) +app* iuc_solver::def_manager::mk_proxy (expr *v) { app* r; if (m_expr2proxy.find(v, r)) { return r; } @@ -146,7 +146,7 @@ app* itp_solver::def_manager::mk_proxy (expr *v) return proxy; } -bool itp_solver::def_manager::is_proxy (app *k, app_ref &def) +bool iuc_solver::def_manager::is_proxy (app *k, app_ref &def) { app *r = nullptr; bool found = m_proxy2def.find (k, r); @@ -154,20 +154,20 @@ bool itp_solver::def_manager::is_proxy (app *k, app_ref &def) return found; } -void itp_solver::def_manager::reset () +void iuc_solver::def_manager::reset () { m_expr2proxy.reset (); m_proxy2def.reset (); m_defs.reset (); } -bool itp_solver::def_manager::is_proxy_def (expr *v) +bool iuc_solver::def_manager::is_proxy_def (expr *v) { // XXX This might not be the most robust way to check return m_defs.contains (v); } -bool itp_solver::is_proxy(expr *e, app_ref &def) +bool iuc_solver::is_proxy(expr *e, app_ref &def) { if (!is_uninterp_const(e)) { return false; } @@ -183,23 +183,23 @@ bool itp_solver::is_proxy(expr *e, app_ref &def) return false; } -void itp_solver::collect_statistics (statistics &st) const +void iuc_solver::collect_statistics (statistics &st) const { m_solver.collect_statistics (st); - st.update ("time.itp_solver.itp_core", m_itp_watch.get_seconds ()); + st.update ("time.iuc_solver.iuc_core", m_iuc_watch.get_seconds ()); } -void itp_solver::reset_statistics () +void iuc_solver::reset_statistics () { - m_itp_watch.reset (); + m_iuc_watch.reset (); } -void itp_solver::get_unsat_core (ptr_vector &core) +void iuc_solver::get_unsat_core (ptr_vector &core) { m_solver.get_unsat_core (core); undo_proxies_in_core (core); } -void itp_solver::undo_proxies_in_core (ptr_vector &r) +void iuc_solver::undo_proxies_in_core (ptr_vector &r) { app_ref e(m); expr_fast_mark1 bg; @@ -222,7 +222,7 @@ void itp_solver::undo_proxies_in_core (ptr_vector &r) r.shrink (j); } -void itp_solver::undo_proxies (expr_ref_vector &r) +void iuc_solver::undo_proxies (expr_ref_vector &r) { app_ref e(m); // expand proxies @@ -233,14 +233,14 @@ void itp_solver::undo_proxies (expr_ref_vector &r) } } -void itp_solver::get_unsat_core (expr_ref_vector &_core) +void iuc_solver::get_unsat_core (expr_ref_vector &_core) { ptr_vector core; get_unsat_core (core); _core.append (core.size (), core.c_ptr ()); } -void itp_solver::elim_proxies (expr_ref_vector &v) +void iuc_solver::elim_proxies (expr_ref_vector &v) { expr_ref f = mk_and (v); scoped_ptr rep = mk_expr_simp_replacer (m); @@ -250,9 +250,9 @@ void itp_solver::elim_proxies (expr_ref_vector &v) flatten_and (f, v); } -void itp_solver::get_itp_core (expr_ref_vector &core) +void iuc_solver::get_iuc(expr_ref_vector &core) { - scoped_watch _t_ (m_itp_watch); + scoped_watch _t_ (m_iuc_watch); typedef obj_hashtable expr_set; expr_set B; @@ -379,12 +379,12 @@ void itp_solver::get_itp_core (expr_ref_vector &core) } IF_VERBOSE(2, - verbose_stream () << "Itp Core:\n" + verbose_stream () << "IUC Core:\n" << mk_pp (mk_and (core), m) << "\n";); } -void itp_solver::refresh () +void iuc_solver::refresh () { // only refresh in non-pushed state SASSERT (m_defs.size () == 0); diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_iuc_solver.h similarity index 85% rename from src/muz/spacer/spacer_itp_solver.h rename to src/muz/spacer/spacer_iuc_solver.h index 0b3527bb3..568124629 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -3,7 +3,7 @@ Copyright (c) 2017 Arie Gurfinkel Module Name: - spacer_itp_solver.h + spacer_iuc_solver.h Abstract: @@ -16,23 +16,23 @@ Author: Notes: --*/ -#ifndef SPACER_ITP_SOLVER_H_ -#define SPACER_ITP_SOLVER_H_ +#ifndef SPACER_IUC_SOLVER_H_ +#define SPACER_IUC_SOLVER_H_ #include"solver/solver.h" #include"ast/expr_substitution.h" #include"util/stopwatch.h" namespace spacer { -class itp_solver : public solver { +class iuc_solver : public solver { private: struct def_manager { - itp_solver &m_parent; + iuc_solver &m_parent; obj_map m_expr2proxy; obj_map m_proxy2def; expr_ref_vector m_defs; - def_manager(itp_solver &parent) : + def_manager(iuc_solver &parent) : m_parent(parent), m_defs(m_parent.m) {} @@ -54,7 +54,7 @@ private: unsigned m_first_assumption; bool m_is_proxied; - stopwatch m_itp_watch; + stopwatch m_iuc_watch; expr_substitution m_elim_proxies_sub; bool m_split_literals; @@ -68,7 +68,9 @@ private: app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); public: - itp_solver(solver &solver, unsigned iuc, unsigned iuc_arith, bool print_farkas_stats, bool old_hyp_reducer, bool split_literals = false) : + iuc_solver(solver &solver, unsigned iuc, unsigned iuc_arith, + bool print_farkas_stats, bool old_hyp_reducer, + bool split_literals = false) : m(solver.get_manager()), m_solver(solver), m_proxies(m), @@ -85,11 +87,11 @@ public: m_old_hyp_reducer(old_hyp_reducer) {} - ~itp_solver() override {} + ~iuc_solver() override {} - /* itp solver specific */ + /* iuc solver specific */ void get_unsat_core(expr_ref_vector &core) override; - virtual void get_itp_core(expr_ref_vector &core); + virtual void get_iuc(expr_ref_vector &core); void set_split_literals(bool v) {m_split_literals = v;} bool mk_proxies(expr_ref_vector &v, unsigned from = 0); void undo_proxies(expr_ref_vector &v); @@ -149,22 +151,22 @@ public: virtual void refresh(); class scoped_mk_proxy { - itp_solver &m_s; + iuc_solver &m_s; expr_ref_vector &m_v; public: - scoped_mk_proxy(itp_solver &s, expr_ref_vector &v) : m_s(s), m_v(v) + scoped_mk_proxy(iuc_solver &s, expr_ref_vector &v) : m_s(s), m_v(v) {m_s.mk_proxies(m_v);} ~scoped_mk_proxy() {m_s.undo_proxies(m_v);} }; class scoped_bg { - itp_solver &m_s; + iuc_solver &m_s; unsigned m_bg_sz; public: - scoped_bg(itp_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {} + scoped_bg(iuc_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {} ~scoped_bg() - {if (m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }} + {if(m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }} }; }; } diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 9850f9e6e..39db6129c 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -60,11 +60,11 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_solvers[1] = pm.mk_fresh2(); m_fparams[1] = &pm.fparams2(); - m_contexts[0] = alloc(spacer::itp_solver, *(m_solvers[0]), p.spacer_iuc(), + m_contexts[0] = alloc(spacer::iuc_solver, *(m_solvers[0]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_iuc_old_hyp_reducer(), p.spacer_iuc_split_farkas_literals()); - m_contexts[1] = alloc(spacer::itp_solver, *(m_solvers[1]), p.spacer_iuc(), + m_contexts[1] = alloc(spacer::iuc_solver, *(m_solvers[1]), p.spacer_iuc(), p.spacer_iuc_arith(), p.spacer_iuc_old_hyp_reducer(), p.spacer_iuc_split_farkas_literals()); @@ -138,7 +138,7 @@ void prop_solver::assert_expr(expr * form, unsigned level) lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft) { // replace expressions by assumption literals - itp_solver::scoped_mk_proxy _p_(*m_ctx, hard); + iuc_solver::scoped_mk_proxy _p_(*m_ctx, hard); unsigned hard_sz = hard.size(); // assume soft constraints are propositional literals (no need to proxy) hard.append(soft); @@ -234,7 +234,7 @@ lbool prop_solver::internal_check_assumptions( if (result == l_false && m_core && m.proofs_enabled() && !m_subset_based_core) { TRACE("spacer", tout << "theory core\n";); m_core->reset(); - m_ctx->get_itp_core(*m_core); + m_ctx->get_iuc(*m_core); } else if (result == l_false && m_core) { m_core->reset(); m_ctx->get_unsat_core(*m_core); @@ -263,7 +263,7 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, // can be disabled if use_push_bg == true // solver::scoped_push _s_(*m_ctx); if (!m_use_push_bg) { m_ctx->push(); } - itp_solver::scoped_bg _b_(*m_ctx); + iuc_solver::scoped_bg _b_(*m_ctx); for (unsigned i = 0; i < num_bg; ++i) if (m_use_push_bg) { m_ctx->push_bg(bg [i]); } diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index 4aedb9676..295b47982 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -31,7 +31,7 @@ Revision History: #include "util/vector.h" #include "muz/spacer/spacer_manager.h" #include "muz/spacer/spacer_smt_context_manager.h" -#include "muz/spacer/spacer_itp_solver.h" +#include "muz/spacer/spacer_iuc_solver.h" struct fixedpoint_params; @@ -45,8 +45,8 @@ private: symbol m_name; smt_params* m_fparams[2]; solver* m_solvers[2]; - scoped_ptr m_contexts[2]; - itp_solver * m_ctx; + scoped_ptr m_contexts[2]; + iuc_solver * m_ctx; smt_params * m_ctx_fparams; decl_vector m_level_preds; app_ref_vector m_pos_level_atoms; // atoms used to identify level From 3bc3b00fdd0f34b22722b07c2a72b285b4d82302 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 15 May 2018 15:29:29 -0700 Subject: [PATCH 0993/1283] Post merge compile fixes --- src/muz/spacer/CMakeLists.txt | 1 + src/muz/spacer/spacer_context.cpp | 6 +- src/muz/spacer/spacer_context.h | 2 +- src/muz/spacer/spacer_dl_interface.cpp | 2 +- src/muz/spacer/spacer_dl_interface.h | 4 +- src/muz/spacer/spacer_generalizers.cpp | 2 +- src/muz/spacer/spacer_iuc_proof.cpp | 51 ++++++------ src/muz/spacer/spacer_iuc_solver.cpp | 2 +- src/muz/spacer/spacer_json.h | 4 +- src/muz/spacer/spacer_proof_utils.cpp | 81 ++++---------------- src/muz/spacer/spacer_proof_utils.h | 35 +++------ src/muz/spacer/spacer_unsat_core_learner.cpp | 5 +- 12 files changed, 66 insertions(+), 129 deletions(-) diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index dad8dfa98..a7bc74b88 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -14,6 +14,7 @@ z3_add_component(spacer spacer_iuc_solver.cpp spacer_virtual_solver.cpp spacer_legacy_mbp.cpp + spacer_proof_utils.cpp spacer_unsat_core_learner.cpp spacer_unsat_core_plugin.cpp spacer_matrix.cpp diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 60f6b9a85..5de817435 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -40,7 +40,7 @@ Notes: #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" #include "ast/ast_util.h" -#include "ast/proof_checker/proof_checker.h" +#include "ast/proofs/proof_checker.h" #include "smt/smt_value_sort.h" #include "ast/scoped_proof.h" #include "muz/spacer/spacer_qe_project.h" @@ -3618,9 +3618,9 @@ expr_ref context::get_constraints (unsigned level) return m_pm.mk_and (constraints); } -void context::add_constraint (unsigned level, const expr_ref& c) +void context::add_constraint (expr *c, unsigned level) { - if (!c.get()) { return; } + if (!c) { return; } if (m.is_true(c)) { return; } expr *e1, *e2; diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index ff0e90cfa..596e5e047 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -914,7 +914,7 @@ public: pob& get_root() const { return m_pob_queue.get_root(); } expr_ref get_constraints (unsigned lvl); - void add_constraint (unsigned lvl, const expr_ref& c); + void add_constraint (expr *c, unsigned lvl); void new_lemma_eh(pred_transformer &pt, lemma *lem); diff --git a/src/muz/spacer/spacer_dl_interface.cpp b/src/muz/spacer/spacer_dl_interface.cpp index 69e5d76ff..b121cf50a 100644 --- a/src/muz/spacer/spacer_dl_interface.cpp +++ b/src/muz/spacer/spacer_dl_interface.cpp @@ -362,5 +362,5 @@ void dl_interface::add_callback(void *state, } void dl_interface::add_constraint (expr *c, unsigned lvl){ - m_context->add_constraint(c,lvl); + m_context->add_constraint(c, lvl); } diff --git a/src/muz/spacer/spacer_dl_interface.h b/src/muz/spacer/spacer_dl_interface.h index 2980e2a0f..9fc60dcf0 100644 --- a/src/muz/spacer/spacer_dl_interface.h +++ b/src/muz/spacer/spacer_dl_interface.h @@ -82,9 +82,9 @@ public: void add_callback(void *state, const datalog::t_new_lemma_eh new_lemma_eh, const datalog::t_predecessor_eh predecessor_eh, - const datalog::t_unfold_eh unfold_eh); + const datalog::t_unfold_eh unfold_eh) override; - void add_constraint (expr *c, unsigned lvl); + void add_constraint (expr *c, unsigned lvl) override; }; } diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 4b0c3d15c..3f6e28be6 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -162,7 +162,7 @@ void unsat_core_generalizer::operator()(lemma_ref &lemma) unsigned uses_level; expr_ref_vector core(m); - VERIFY(pt.is_invariant(old_level, lemma->get_expr(), uses_level, &core)); + VERIFY(pt.is_invariant(lemma->level(), lemma.get(), uses_level, &core)); CTRACE("spacer", old_sz > core.size(), tout << "unsat core reduced lemma from: " diff --git a/src/muz/spacer/spacer_iuc_proof.cpp b/src/muz/spacer/spacer_iuc_proof.cpp index 889f06af2..966b59df4 100644 --- a/src/muz/spacer/spacer_iuc_proof.cpp +++ b/src/muz/spacer/spacer_iuc_proof.cpp @@ -1,8 +1,7 @@ - - #include "muz/spacer/spacer_iuc_proof.h" #include "ast/for_each_expr.h" #include "ast/array_decl_plugin.h" +#include "ast/proofs/proof_utils.h" #include "muz/spacer/spacer_proof_utils.h" namespace spacer { @@ -18,7 +17,7 @@ namespace spacer { collect_symbols_b(b_conjuncts); compute_marks(b_conjuncts); } - + proof* iuc_proof::get() { return m_pr.get(); @@ -33,7 +32,7 @@ namespace spacer { func_decl_set& m_symbs; public: collect_pure_proc(func_decl_set& s):m_symbs(s) {} - + void operator()(app* a) { if (a->get_family_id() == null_family_id) { m_symbs.insert(a->get_decl()); @@ -42,7 +41,7 @@ namespace spacer { void operator()(var*) {} void operator()(quantifier*) {} }; - + void iuc_proof::collect_symbols_b(expr_set& b_conjuncts) { expr_mark visited; @@ -52,18 +51,18 @@ namespace spacer { for_each_expr(proc, visited, *it); } } - + class is_pure_expr_proc { func_decl_set const& m_symbs; array_util m_au; public: struct non_pure {}; - + is_pure_expr_proc(func_decl_set const& s, ast_manager& m): m_symbs(s), m_au (m) {} - + void operator()(app* a) { if (a->get_family_id() == null_family_id) { if (!m_symbs.contains(a->get_decl())) { @@ -78,7 +77,7 @@ namespace spacer { void operator()(var*) {} void operator()(quantifier*) {} }; - + // requires that m_symbols_b has already been computed, which is done during initialization. bool iuc_proof::only_contains_symbols_b(expr* expr) const { @@ -92,26 +91,26 @@ namespace spacer { } return true; } - + /* * ==================================== * methods for computing which premises * have been used to derive the conclusions * ==================================== */ - + void iuc_proof::compute_marks(expr_set& b_conjuncts) { - ProofIteratorPostOrder it(m_pr, m); + proof_post_order it(m_pr, m); while (it.hasNext()) { proof* currentNode = it.next(); - + if (m.get_num_parents(currentNode) == 0) { switch(currentNode->get_decl_kind()) { - + case PR_ASSERTED: // currentNode is an axiom { if (b_conjuncts.contains(m.get_fact(currentNode))) @@ -142,23 +141,23 @@ namespace spacer { bool need_to_mark_a = false; bool need_to_mark_b = false; bool need_to_mark_h = false; - + for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) { SASSERT(m.is_proof(currentNode->get_arg(i))); proof* premise = to_app(currentNode->get_arg(i)); - + need_to_mark_a = need_to_mark_a || m_a_mark.is_marked(premise); need_to_mark_b = need_to_mark_b || m_b_mark.is_marked(premise); need_to_mark_h = need_to_mark_h || m_h_mark.is_marked(premise); } - + // if current node is application of lemma, we know that all hypothesis are removed if(currentNode->get_decl_kind() == PR_LEMMA) { need_to_mark_h = false; } - + // save results m_a_mark.mark(currentNode, need_to_mark_a); m_b_mark.mark(currentNode, need_to_mark_b); @@ -166,7 +165,7 @@ namespace spacer { } } } - + bool iuc_proof::is_a_marked(proof* p) { return m_a_mark.is_marked(p); @@ -179,7 +178,7 @@ namespace spacer { { return m_h_mark.is_marked(p); } - + /* * ==================================== * methods for dot printing @@ -195,22 +194,22 @@ namespace spacer { * statistics * ==================================== */ - + void iuc_proof::print_farkas_stats() { unsigned farkas_counter = 0; unsigned farkas_counter2 = 0; - - ProofIteratorPostOrder it3(m_pr, m); + + proof_post_order it3(m_pr, m); while (it3.hasNext()) { proof* currentNode = it3.next(); - + // if node is theory lemma if (is_farkas_lemma(m, currentNode)) { farkas_counter++; - + // check whether farkas lemma is to be interpolated (could potentially miss farkas lemmas, which are interpolated, because we potentially don't want to use the lowest cut) bool has_blue_nonred_parent = false; for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) @@ -229,7 +228,7 @@ namespace spacer { } } } - + verbose_stream() << "\nThis proof contains " << farkas_counter << " Farkas lemmas. " << farkas_counter2 << " Farkas lemmas participate in the lowest cut\n"; } } diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 90a28c341..e2334f1ba 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -19,7 +19,7 @@ Notes: #include"muz/spacer/spacer_iuc_solver.h" #include"ast/ast.h" #include"muz/spacer/spacer_util.h" -#include"muz/base/proof_utils.h" +#include"ast/proofs/proof_utils.h" #include"muz/spacer/spacer_farkas_learner.h" #include"ast/rewriter/expr_replacer.h" #include"muz/spacer/spacer_unsat_core_learner.h" diff --git a/src/muz/spacer/spacer_json.h b/src/muz/spacer/spacer_json.h index c75110371..b100a87dc 100644 --- a/src/muz/spacer/spacer_json.h +++ b/src/muz/spacer/spacer_json.h @@ -22,8 +22,8 @@ Notes: #include #include -#include "ref.h" -#include "ref_vector.h" +#include "util/ref.h" +#include "util/ref_vector.h" class ast; diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 735f94518..32391db91 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -16,20 +16,22 @@ Revision History: --*/ -#include "muz/spacer/spacer_proof_utils.h" -#include "ast/ast_util.h" - -#include "ast/ast_pp.h" - -#include "ast/proof_checker/proof_checker.h" #include -#include "params.h" -#include "muz/spacer/spacer_iuc_proof.h" +#include "util/params.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/proofs/proof_checker.h" #include "muz/base/dl_util.h" +#include "muz/spacer/spacer_iuc_proof.h" + +#include "ast/proofs/proof_utils.h" +#include "muz/spacer/spacer_proof_utils.h" namespace spacer { - // arith lemmas: second parameter specifies exact type of lemma, could be "farkas", "triangle-eq", "eq-propagate", "assign-bounds", maybe also something else + // arith lemmas: second parameter specifies exact type of lemma, + // could be "farkas", "triangle-eq", "eq-propagate", + // "assign-bounds", maybe also something else bool is_arith_lemma(ast_manager& m, proof* pr) { if (pr->get_decl_kind() == PR_TH_LEMMA) @@ -61,57 +63,6 @@ namespace spacer { return false; } - /* - * ==================================== - * methods for proof traversal - * ==================================== - */ -ProofIteratorPostOrder::ProofIteratorPostOrder(proof* root, ast_manager& manager) : m(manager) -{m_todo.push_back(root);} - -bool ProofIteratorPostOrder::hasNext() -{return !m_todo.empty();} - -/* - * iterative post-order depth-first search (DFS) through the proof DAG - */ -proof* ProofIteratorPostOrder::next() -{ - while (!m_todo.empty()) { - proof* currentNode = m_todo.back(); - - // if we haven't already visited the current unit - if (!m_visited.is_marked(currentNode)) { - bool existsUnvisitedParent = false; - - // add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result - // for currentProof now, but wait until those unprocessed premises are processed. - for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) { - SASSERT(m.is_proof(currentNode->get_arg(i))); - proof* premise = to_app(currentNode->get_arg(i)); - - // if we haven't visited the current premise yet - if (!m_visited.is_marked(premise)) { - // add it to the stack - m_todo.push_back(premise); - existsUnvisitedParent = true; - } - } - - // if we already visited all parent-inferences, we can visit the inference too - if (!existsUnvisitedParent) { - m_visited.mark(currentNode, true); - m_todo.pop_back(); - return currentNode; - } - } else { - m_todo.pop_back(); - } - } - // we have already iterated through all inferences - return NULL; -} - /* * ==================================== * methods for dot printing @@ -140,7 +91,7 @@ proof* ProofIteratorPostOrder::next() std::unordered_map id_to_small_id; unsigned counter = 0; - ProofIteratorPostOrder it2(pr, m); + proof_post_order it2(pr, m); while (it2.hasNext()) { proof* currentNode = it2.next(); @@ -306,7 +257,7 @@ proof* ProofIteratorPostOrder::next() proof_ref theory_axiom_reducer::reduce(proof* pr) { - ProofIteratorPostOrder pit(pr, m); + proof_post_order pit(pr, m); while (pit.hasNext()) { proof* p = pit.next(); @@ -468,11 +419,11 @@ proof* ProofIteratorPostOrder::next() for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { proof* pp = m.get_parent(p, i); - datalog::set_union(*parent_hyps, *m_parent_hyps.find(pp)); + set_union(*parent_hyps, *m_parent_hyps.find(pp)); if (!m.is_lemma(p)) // lemmas clear all hypotheses { - datalog::set_union(*active_hyps, *m_active_hyps.find(pp)); + set_union(*active_hyps, *m_active_hyps.find(pp)); } } } @@ -488,7 +439,7 @@ proof* ProofIteratorPostOrder::next() expr_set* all_hyps = m_parent_hyps.find(pr); SASSERT(all_hyps != nullptr); - ProofIteratorPostOrder pit(pr, m); + proof_post_order pit(pr, m); while (pit.hasNext()) { proof* p = pit.next(); if (!m.is_hypothesis(p)) diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index abd612b57..e47c9882a 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -21,24 +21,9 @@ Revision History: #include "ast/ast.h" namespace spacer { - + bool is_arith_lemma(ast_manager& m, proof* pr); bool is_farkas_lemma(ast_manager& m, proof* pr); -/* - * iterator, which traverses the proof in depth-first post-order. - */ -class ProofIteratorPostOrder { -public: - ProofIteratorPostOrder(proof* refutation, ast_manager& manager); - bool hasNext(); - proof* next(); - -private: - ptr_vector m_todo; - ast_mark m_visited; // the proof nodes we have already visited - - ast_manager& m; -}; /* * prints the proof pr in dot representation to the file proof.dot @@ -46,7 +31,7 @@ private: */ class iuc_proof; void pp_proof_dot(ast_manager& m, proof* pr, iuc_proof* iuc_pr = nullptr); - + class theory_axiom_reducer { public: @@ -54,16 +39,16 @@ private: // reduce theory axioms and return transformed proof proof_ref reduce(proof* pr); - + private: ast_manager &m; - + // tracking all created expressions expr_ref_vector m_pinned; - + // maps each proof of a clause to the transformed subproof of that clause obj_map m_cache; - + void reset(); }; @@ -71,7 +56,7 @@ private: { public: hypothesis_reducer(ast_manager &m) : m(m), m_pinned(m) {} - + // reduce hypothesis and return transformed proof proof_ref reduce(proof* pf); @@ -80,7 +65,7 @@ private: typedef obj_hashtable proof_set; ast_manager &m; - + expr_ref_vector m_pinned; // tracking all created expressions ptr_vector m_pinned_active_hyps; // tracking all created sets of active hypothesis ptr_vector m_pinned_parent_hyps; // tracking all created sets of parent hypothesis @@ -89,12 +74,12 @@ private: obj_map m_units; // maps each unit literal to the subproof of that unit obj_map m_active_hyps; // maps each proof of a clause to the set of proofs of active hypothesis' of the clause obj_map m_parent_hyps; // maps each proof of a clause to the hypothesis-fact, which are transitive parents of that clause, needed to avoid creating cycles in the proof. - + void reset(); void compute_hypsets(proof* pr); // compute active_hyps and parent_hyps for pr void collect_units(proof* pr); // compute m_units proof* compute_transformed_proof(proof* pf); - + proof* mk_lemma_core(proof *pf, expr *fact); proof* mk_unit_resolution_core(ptr_buffer& args); proof* mk_step_core(proof* old_step, ptr_buffer& args); diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index cb7ebff76..bb50cc5c7 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -22,6 +22,7 @@ Revision History: #include "muz/spacer/spacer_iuc_proof.h" #include "ast/for_each_expr.h" +#include "ast/proofs/proof_utils.h" #include "muz/spacer/spacer_util.h" @@ -54,7 +55,7 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { SASSERT(m.is_proof(currentNode->get_arg(i))); proof* premise = to_app(currentNode->get_arg(i)); - + need_to_mark_closed = need_to_mark_closed && (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise)); } @@ -109,7 +110,7 @@ void unsat_core_learner::set_closed(proof* p, bool value) { m_closed.mark(p, value); } - + bool unsat_core_learner::is_b_open(proof *p) { return m_pr.is_b_marked(p) && !is_closed (p); From ffdefa4f65c9f0dbbcc9f8e8877a3066366d56e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 14 May 2018 12:51:59 -0700 Subject: [PATCH 0994/1283] add todo Signed-off-by: Nikolaj Bjorner --- todo.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 todo.txt diff --git a/todo.txt b/todo.txt new file mode 100644 index 000000000..82038c3b4 --- /dev/null +++ b/todo.txt @@ -0,0 +1,9 @@ +- consolidate virtual-solver and pool solver + +- fixup mbp/mbi + +- API additions to expose functionality + +- Equality solver + +- Generalizer index \ No newline at end of file From b649cd93cb259d357754737c26a7a57b298fa191 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 15 May 2018 07:40:37 -0700 Subject: [PATCH 0995/1283] change pool solver to enable external control of pool allocation Signed-off-by: Nikolaj Bjorner --- src/solver/solver_pool.cpp | 44 ++++++++++++++++++-------------------- src/solver/solver_pool.h | 21 +++++++++++++----- src/test/CMakeLists.txt | 1 + src/test/main.cpp | 1 + src/test/solver_pool.cpp | 34 +++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 src/test/solver_pool.cpp diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 6d08b95af..132a2bec4 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -17,10 +17,10 @@ Notes: --*/ -#include "solver/solver_pool.h" -#include "solver/solver_na2as.h" #include "ast/proofs/proof_utils.h" #include "ast/ast_util.h" +#include "solver/solver_pool.h" + class pool_solver : public solver_na2as { solver_pool& m_pool; @@ -33,7 +33,6 @@ class pool_solver : public solver_na2as { bool m_pushed; bool m_in_delayed_scope; unsigned m_dump_counter; - bool is_virtual() const { return !m.is_true(m_pred); } public: pool_solver(solver* b, solver_pool& pool, app_ref& pred): @@ -240,10 +239,8 @@ public: } }; -solver_pool::solver_pool(solver* base_solver, unsigned num_solvers_per_pool): - m_base_solver(base_solver), - m_num_solvers_per_pool(num_solvers_per_pool), - m_num_solvers_in_last_pool(0) +solver_pool::solver_pool(solver* base_solver): + m_base_solver(base_solver) {} @@ -261,10 +258,10 @@ ptr_vector solver_pool::get_base_solvers() const { void solver_pool::collect_statistics(statistics &st) const { ptr_vector solvers = get_base_solvers(); for (solver* s : solvers) s->collect_statistics(st); - st.update("time.pool_solver.smt.total", m_check_watch.get_seconds()); - st.update("time.pool_solver.smt.total.sat", m_check_sat_watch.get_seconds()); - st.update("time.pool_solver.smt.total.undef", m_check_undef_watch.get_seconds()); - st.update("time.pool_solver.proof", m_proof_watch.get_seconds()); + st.update("pool_solver.time.total", m_check_watch.get_seconds()); + st.update("pool_solver.time.total.sat", m_check_sat_watch.get_seconds()); + st.update("pool_solver.time.total.undef", m_check_undef_watch.get_seconds()); + st.update("pool_solver.time.proof", m_proof_watch.get_seconds()); st.update("pool_solver.checks", m_stats.m_num_checks); st.update("pool_solver.checks.sat", m_stats.m_num_sat_checks); st.update("pool_solver.checks.undef", m_stats.m_num_undef_checks); @@ -285,24 +282,25 @@ void solver_pool::reset_statistics() { } solver* solver_pool::mk_solver() { - ref base_solver; ast_manager& m = m_base_solver->get_manager(); - if (m_solvers.empty() || m_num_solvers_in_last_pool == m_num_solvers_per_pool) { - base_solver = m_base_solver->translate(m, m_base_solver->get_params()); - m_num_solvers_in_last_pool = 0; - } - else { - base_solver = dynamic_cast(m_solvers.back())->base_solver(); - } - m_num_solvers_in_last_pool++; - std::stringstream name; - name << "vsolver#" << m_solvers.size(); - app_ref pred(m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()), m); + ref base_solver = m_base_solver->translate(m, m_base_solver->get_params()); + app_ref pred(m.mk_true(), m); pool_solver* solver = alloc(pool_solver, base_solver.get(), *this, pred); m_solvers.push_back(solver); return solver; } +solver* solver_pool::clone_solver(solver* psolver) { + ast_manager& m = m_base_solver->get_manager(); + solver* base_solver = dynamic_cast(psolver)->base_solver(); + std::stringstream name; + name << "vsolver#" << m_solvers.size(); + app_ref pred(m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()), m); + pool_solver* solver = alloc(pool_solver, base_solver, *this, pred); + m_solvers.push_back(solver); + return solver; +} + void solver_pool::reset_solver(solver* s) { pool_solver* ps = dynamic_cast(s); SASSERT(ps); diff --git a/src/solver/solver_pool.h b/src/solver/solver_pool.h index d676ca54d..a1f650eb0 100644 --- a/src/solver/solver_pool.h +++ b/src/solver/solver_pool.h @@ -18,11 +18,20 @@ Notes: This is a revision of spacer_virtual_solver by Arie Gurfinkel + +it is not quite the same + there are good reasons to do that management at a higher level. +not the same == in spacer, there is an upper bound on the number of base solvers (i.e., number of pools). +Then the pools are distributed between different predicate transformers. I can't just switch to solver_pool, +since this, in most configuration, will result in either few solvers (which is bad for most of my benchmarks), +or one solver per predicate transformer (which is bad for a few benchmarks with many predicates). + + --*/ #ifndef SOLVER_POOL_H_ #define SOLVER_POOL_H_ #include "solver/solver.h" +#include "solver/solver_na2as.h" #include "util/stopwatch.h" class pool_solver; @@ -39,11 +48,9 @@ class solver_pool { void reset() { memset(this, 0, sizeof(*this)); } }; - ref m_base_solver; - unsigned m_num_solvers_per_pool; - unsigned m_num_solvers_in_last_pool; + ref m_base_solver; sref_vector m_solvers; - stats m_stats; + stats m_stats; stopwatch m_check_watch; stopwatch m_check_sat_watch; @@ -55,13 +62,17 @@ class solver_pool { ptr_vector get_base_solvers() const; public: - solver_pool(solver* base_solver, unsigned num_solvers_per_pool); + solver_pool(solver* base_solver); void collect_statistics(statistics &st) const; void reset_statistics(); + // create a fresh pool solver solver* mk_solver(); + // clone an existing pool solver + solver* clone_solver(solver* pool_solver); + void reset_solver(solver* s); }; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b487fe9ba..da4194a2c 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -102,6 +102,7 @@ add_executable(test-z3 small_object_allocator.cpp smt2print_parse.cpp smt_context.cpp + solver_pool.cpp sorting_network.cpp stack.cpp string_buffer.cpp diff --git a/src/test/main.cpp b/src/test/main.cpp index 64f754667..c1f169a3a 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -248,6 +248,7 @@ int main(int argc, char ** argv) { TST_ARGV(sat_local_search); TST_ARGV(cnf_backbones); TST(bdd); + TST(solver_pool); //TST_ARGV(hs); } diff --git a/src/test/solver_pool.cpp b/src/test/solver_pool.cpp new file mode 100644 index 000000000..a0b6832c2 --- /dev/null +++ b/src/test/solver_pool.cpp @@ -0,0 +1,34 @@ +#include "ast/reg_decl_plugins.h" +#include "solver/solver_pool.h" +#include "smt/smt_solver.h" + +void tst_solver_pool() { + ast_manager m; + reg_decl_plugins(m); + params_ref p; + ref base = mk_smt_solver(m, p, symbol::null); + solver_pool pool(base.get()); + + ref s1 = pool.mk_solver(); + ref s2 = pool.clone_solver(s1.get()); + ref s3 = pool.clone_solver(s1.get()); + + ref s4 = pool.mk_solver(); + ref s5 = pool.clone_solver(s4.get()); + ref s6 = pool.clone_solver(s4.get()); + + expr_ref a(m.mk_const(symbol("a"), m.mk_bool_sort()), m); + expr_ref b(m.mk_const(symbol("b"), m.mk_bool_sort()), m); + expr_ref c(m.mk_const(symbol("c"), m.mk_bool_sort()), m); + expr_ref d(m.mk_const(symbol("d"), m.mk_bool_sort()), m); + expr_ref fml(m); + fml = m.mk_or(a, b); + s1->assert_expr(fml); + fml = m.mk_and(a,b); + s2->assert_expr(fml); + expr_ref_vector asms(m); + asms.push_back(m.mk_not(a)); + std::cout << s1->check_sat(asms) << "\n"; + std::cout << s2->check_sat(asms) << "\n"; + std::cout << s3->check_sat(asms) << "\n"; +} From c893740e131eb39ee9dfdb5b187d7d45f545ac88 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 May 2018 08:57:48 -0700 Subject: [PATCH 0996/1283] Fix compilation --- src/muz/spacer/spacer_json.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/muz/spacer/spacer_json.cpp b/src/muz/spacer/spacer_json.cpp index 8b7a0878e..c1094f192 100644 --- a/src/muz/spacer/spacer_json.cpp +++ b/src/muz/spacer/spacer_json.cpp @@ -77,7 +77,7 @@ namespace spacer { std::ostringstream ls; for (auto l:lemmas) { - ls << (ls.tellp() == 0 ? "" : ","); + ls << ((unsigned)ls.tellp() == 0 ? "" : ","); json_marshal(ls, l); } out << "[" << ls.str() << "]"; @@ -104,11 +104,11 @@ namespace spacer { for (auto &pob_map:m_relations) { std::ostringstream pob_lemmas; for (auto &depth_lemmas : pob_map.second) { - pob_lemmas << (pob_lemmas.tellp() == 0 ? "" : ",") << "\"" << depth_lemmas.first << "\":"; + pob_lemmas << ((unsigned)pob_lemmas.tellp() == 0 ? "" : ",") << "\"" << depth_lemmas.first << "\":"; json_marshal(pob_lemmas, depth_lemmas.second); } if (pob_lemmas.tellp()) { - lemmas << (lemmas.tellp() == 0 ? "" : ",\n"); + lemmas << ((unsigned)lemmas.tellp() == 0 ? "" : ",\n"); lemmas << "\"" << pob_id << "\":{" << pob_lemmas.str() << "}"; } pob_id++; @@ -127,7 +127,7 @@ namespace spacer { std::ostringstream pob_expr; json_marshal(pob_expr, n->post(), n->get_ast_manager()); - nodes << (nodes.tellp() == 0 ? "" : ",\n") << + nodes << ((unsigned)nodes.tellp() == 0 ? "" : ",\n") << "{\"id\":\"" << depth << n << "\",\"relative_time\":\"" << expand_time / root_expand_time << "\",\"absolute_time\":\"" << std::setprecision(2) << expand_time << @@ -137,7 +137,7 @@ namespace spacer { "\",\"depth\":\"" << depth << "\",\"expr\":" << pob_expr.str() << "}"; if (n->parent()) { - edges << (edges.tellp() == 0 ? "" : ",\n") << + edges << ((unsigned)edges.tellp() == 0 ? "" : ",\n") << "{\"from\":\"" << depth << n->parent() << "\",\"to\":\"" << depth << n << "\"}"; } From 49821e7c91fe6931c938edf629300ee87891bef2 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 May 2018 08:58:37 -0700 Subject: [PATCH 0997/1283] Revised solver_pool --- src/solver/solver.h | 4 ++ src/solver/solver_pool.cpp | 134 +++++++++++++++++++++++-------------- src/solver/solver_pool.h | 22 ++---- src/test/solver_pool.cpp | 27 +++++--- 4 files changed, 110 insertions(+), 77 deletions(-) diff --git a/src/solver/solver.h b/src/solver/solver.h index 2c056ff90..bb330636f 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -229,4 +229,8 @@ protected: typedef ref solver_ref; +inline std::ostream& operator<<(std::ostream& out, solver const& s) { + return s.display(out); +} + #endif diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 132a2bec4..3cf39a64c 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -17,10 +17,10 @@ Notes: --*/ +#include "solver/solver_pool.h" +#include "solver/solver_na2as.h" #include "ast/proofs/proof_utils.h" #include "ast/ast_util.h" -#include "solver/solver_pool.h" - class pool_solver : public solver_na2as { solver_pool& m_pool; @@ -33,6 +33,7 @@ class pool_solver : public solver_na2as { bool m_pushed; bool m_in_delayed_scope; unsigned m_dump_counter; + bool is_virtual() const { return !m.is_true(m_pred); } public: pool_solver(solver* b, solver_pool& pool, app_ref& pred): @@ -66,6 +67,8 @@ public: void updt_params(params_ref const& p) override { solver::updt_params(p); m_base->updt_params(p); } void collect_param_descrs(param_descrs & r) override { m_base->collect_param_descrs(r); } void collect_statistics(statistics & st) const override { m_base->collect_statistics(st); } + unsigned get_num_assertions() const override { return m_base->get_num_assertions(); } + expr * get_assertion(unsigned idx) const override { return m_base->get_assertion(idx); } void get_unsat_core(ptr_vector & r) override { m_base->get_unsat_core(r); @@ -81,6 +84,7 @@ public: return is_virtual() ? sz - 1 : sz; } + proof * get_proof() override { scoped_watch _t_(m_pool.m_proof_watch); if (!m_proof.get()) { @@ -126,33 +130,7 @@ public: set_status(res); if (false /*m_dump_benchmarks && sw.get_seconds() >= m_pool.fparams().m_dump_min_time*/) { - std::stringstream file_name; - file_name << "virt_solver"; - if (is_virtual()) { file_name << "_" << m_pred->get_decl()->get_name(); } - file_name << "_" << (m_dump_counter++) << ".smt2"; - - std::ofstream out(file_name.str().c_str()); - if (!out) { verbose_stream() << "could not open file " << file_name.str() << " for output\n"; } - - out << "(set-info :status "; - switch (res) { - case l_true: out << "sat"; break; - case l_false: out << "unsat"; break; - case l_undef: out << "unknown"; break; - } - out << ")\n"; - m_base->display(out, num_assumptions, assumptions); - out << "(check-sat"; - for (unsigned i = 0; i < num_assumptions; ++i) { - out << " " << mk_pp(assumptions[i], m); - } - out << ")"; - out << "(exit)\n"; - ::statistics st; - m_base->collect_statistics(st); - st.update("time", sw.get_seconds()); - st.display_smt2(out); - out.close(); + dump_benchmark(num_assumptions, assumptions, res, sw); } return res; } @@ -171,21 +149,21 @@ public: m_in_delayed_scope = true; } else { - SASSERT(m_pushed); SASSERT(!m_in_delayed_scope); m_base->push(); } } void pop_core(unsigned n) override { - SASSERT(!m_pushed || get_scope_level() > 0); + unsigned lvl = get_scope_level(); + SASSERT(!m_pushed || lvl > 0); if (m_pushed) { SASSERT(!m_in_delayed_scope); m_base->pop(n); - m_pushed = get_scope_level() - n > 0; + m_pushed = lvl - n > 0; } else { - m_in_delayed_scope = get_scope_level() - n > 0; + m_in_delayed_scope = lvl - n > 0; } } @@ -237,11 +215,58 @@ public: m_assertions.reset(); m_pool.refresh(m_base.get()); } + +private: + + void dump_benchmark(unsigned num_assumptions, expr * const * assumptions, lbool res, stopwatch& sw) { + std::string file_name = mk_file_name(); + std::ofstream out(file_name); + if (!out) { + IF_VERBOSE(0, verbose_stream() << "could not open file " << file_name << " for output\n"); + return; + } + + out << "(set-info :status " << lbool2status(res) << ")\n"; + m_base->display(out, num_assumptions, assumptions); + out << "(check-sat"; + for (unsigned i = 0; i < num_assumptions; ++i) { + out << " " << mk_pp(assumptions[i], m); + } + out << ")"; + out << "(exit)\n"; + ::statistics st; + m_base->collect_statistics(st); + st.update("time", sw.get_seconds()); + st.display_smt2(out); + out.close(); + } + + char const* lbool2status(lbool r) const { + switch (r) { + case l_true: return "sat"; + case l_false: return "unsat"; + case l_undef: return "unknown"; + } + return "?"; + } + + std::string mk_file_name() { + std::stringstream file_name; + file_name << "virt_solver"; + if (is_virtual()) file_name << "_" << m_pred->get_decl()->get_name(); + file_name << "_" << (m_dump_counter++) << ".smt2"; + return file_name.str(); + } + }; -solver_pool::solver_pool(solver* base_solver): - m_base_solver(base_solver) -{} +solver_pool::solver_pool(solver* base_solver, unsigned num_pools): + m_base_solver(base_solver), + m_num_pools(num_pools), + m_current_pool(0) +{ + SASSERT(num_pools > 0); +} ptr_vector solver_pool::get_base_solvers() const { @@ -258,10 +283,10 @@ ptr_vector solver_pool::get_base_solvers() const { void solver_pool::collect_statistics(statistics &st) const { ptr_vector solvers = get_base_solvers(); for (solver* s : solvers) s->collect_statistics(st); - st.update("pool_solver.time.total", m_check_watch.get_seconds()); - st.update("pool_solver.time.total.sat", m_check_sat_watch.get_seconds()); - st.update("pool_solver.time.total.undef", m_check_undef_watch.get_seconds()); - st.update("pool_solver.time.proof", m_proof_watch.get_seconds()); + st.update("time.pool_solver.smt.total", m_check_watch.get_seconds()); + st.update("time.pool_solver.smt.total.sat", m_check_sat_watch.get_seconds()); + st.update("time.pool_solver.smt.total.undef", m_check_undef_watch.get_seconds()); + st.update("time.pool_solver.proof", m_proof_watch.get_seconds()); st.update("pool_solver.checks", m_stats.m_num_checks); st.update("pool_solver.checks.sat", m_stats.m_num_sat_checks); st.update("pool_solver.checks.undef", m_stats.m_num_undef_checks); @@ -281,24 +306,29 @@ void solver_pool::reset_statistics() { m_proof_watch.reset(); } +/** + \brief Create a fresh solver instance. + The first num_pools solvers are independent and + use a fresh instance of the base solver. + Subsequent solvers reuse the first num_polls base solvers, rotating + among the first num_pools. +*/ solver* solver_pool::mk_solver() { + ref base_solver; ast_manager& m = m_base_solver->get_manager(); - ref base_solver = m_base_solver->translate(m, m_base_solver->get_params()); - app_ref pred(m.mk_true(), m); - pool_solver* solver = alloc(pool_solver, base_solver.get(), *this, pred); - m_solvers.push_back(solver); - return solver; -} - -solver* solver_pool::clone_solver(solver* psolver) { - ast_manager& m = m_base_solver->get_manager(); - solver* base_solver = dynamic_cast(psolver)->base_solver(); + if (m_solvers.size() < m_num_pools) { + base_solver = m_base_solver->translate(m, m_base_solver->get_params()); + } + else { + solver* s = m_solvers[(m_current_pool++) % m_num_pools]; + base_solver = dynamic_cast(s)->base_solver(); + } std::stringstream name; name << "vsolver#" << m_solvers.size(); app_ref pred(m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()), m); - pool_solver* solver = alloc(pool_solver, base_solver, *this, pred); + pool_solver* solver = alloc(pool_solver, base_solver.get(), *this, pred); m_solvers.push_back(solver); - return solver; + return solver; } void solver_pool::reset_solver(solver* s) { diff --git a/src/solver/solver_pool.h b/src/solver/solver_pool.h index a1f650eb0..f279dfd4b 100644 --- a/src/solver/solver_pool.h +++ b/src/solver/solver_pool.h @@ -16,22 +16,16 @@ Author: Notes: - This is a revision of spacer_virtual_solver by Arie Gurfinkel - - -it is not quite the same + there are good reasons to do that management at a higher level. -not the same == in spacer, there is an upper bound on the number of base solvers (i.e., number of pools). -Then the pools are distributed between different predicate transformers. I can't just switch to solver_pool, -since this, in most configuration, will result in either few solvers (which is bad for most of my benchmarks), -or one solver per predicate transformer (which is bad for a few benchmarks with many predicates). - + This is a revision of spacer_virtual_solver + consolidated with spacer_smt_context_manager + by Arie Gurfinkel + Use this module as a replacement for spacer_smt_context_manager. --*/ #ifndef SOLVER_POOL_H_ #define SOLVER_POOL_H_ #include "solver/solver.h" -#include "solver/solver_na2as.h" #include "util/stopwatch.h" class pool_solver; @@ -49,6 +43,8 @@ class solver_pool { }; ref m_base_solver; + unsigned m_num_pools; + unsigned m_current_pool; sref_vector m_solvers; stats m_stats; @@ -62,17 +58,13 @@ class solver_pool { ptr_vector get_base_solvers() const; public: - solver_pool(solver* base_solver); + solver_pool(solver* base_solver, unsigned num_pools); void collect_statistics(statistics &st) const; void reset_statistics(); - // create a fresh pool solver solver* mk_solver(); - // clone an existing pool solver - solver* clone_solver(solver* pool_solver); - void reset_solver(solver* s); }; diff --git a/src/test/solver_pool.cpp b/src/test/solver_pool.cpp index a0b6832c2..4a2e533bf 100644 --- a/src/test/solver_pool.cpp +++ b/src/test/solver_pool.cpp @@ -7,28 +7,35 @@ void tst_solver_pool() { reg_decl_plugins(m); params_ref p; ref base = mk_smt_solver(m, p, symbol::null); - solver_pool pool(base.get()); - ref s1 = pool.mk_solver(); - ref s2 = pool.clone_solver(s1.get()); - ref s3 = pool.clone_solver(s1.get()); - - ref s4 = pool.mk_solver(); - ref s5 = pool.clone_solver(s4.get()); - ref s6 = pool.clone_solver(s4.get()); - expr_ref a(m.mk_const(symbol("a"), m.mk_bool_sort()), m); expr_ref b(m.mk_const(symbol("b"), m.mk_bool_sort()), m); expr_ref c(m.mk_const(symbol("c"), m.mk_bool_sort()), m); expr_ref d(m.mk_const(symbol("d"), m.mk_bool_sort()), m); expr_ref fml(m); fml = m.mk_or(a, b); + base->assert_expr(fml); + + solver_pool pool(base.get(), 3); + + // base solver is cloned so any assertions + // added to base after mk_solver() are ignored. + ref s1 = pool.mk_solver(); + ref s2 = pool.mk_solver(); + ref s3 = pool.mk_solver(); + ref s4 = pool.mk_solver(); + + fml = m.mk_and(b, c); s1->assert_expr(fml); - fml = m.mk_and(a,b); + fml = m.mk_and(a, b); s2->assert_expr(fml); expr_ref_vector asms(m); asms.push_back(m.mk_not(a)); + std::cout << base->check_sat(asms) << "\n"; std::cout << s1->check_sat(asms) << "\n"; std::cout << s2->check_sat(asms) << "\n"; std::cout << s3->check_sat(asms) << "\n"; + std::cout << *s1; + std::cout << *s2; + std::cout << *base; } From ebf6b1882121309be2997476c193a2d9d8d225a4 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 May 2018 08:59:11 -0700 Subject: [PATCH 0998/1283] maxsat standalone mode --- src/opt/maxsmt.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++- src/opt/maxsmt.h | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index afecf7d2b..fc5bd6bbb 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -21,6 +21,7 @@ Notes: #include "opt/maxsmt.h" #include "opt/maxres.h" #include "opt/wmax.h" +#include "opt/opt_params.hpp" #include "ast/ast_pp.h" #include "util/uint_set.h" #include "opt/opt_context.h" @@ -409,6 +410,59 @@ namespace opt { m_c.model_updated(mdl); } + class solver_maxsat_context : public maxsat_context { + params_ref m_params; + solver_ref m_solver; + model_ref m_model; + ref m_fm; + symbol m_maxsat_engine; + public: + solver_maxsat_context(params_ref& p, solver* s, model * m): + m_params(p), + m_solver(s), + m_model(m), + m_fm(alloc(generic_model_converter, s->get_manager(), "maxsmt")) { + opt_params _p(p); + m_maxsat_engine = _p.maxsat_engine(); + } + generic_model_converter& fm() override { return *m_fm.get(); } + bool sat_enabled() const override { return false; } + solver& get_solver() override { return *m_solver.get(); } + ast_manager& get_manager() const override { return m_solver->get_manager(); } + params_ref& params() override { return m_params; } + void enable_sls(bool force) override { } // no op + symbol const& maxsat_engine() const override { return m_maxsat_engine; } + void get_base_model(model_ref& _m) override { _m = m_model; }; + smt::context& smt_context() override { + throw default_exception("stand-alone maxsat context does not support wmax"); + } + unsigned num_objectives() override { return 1; } + bool verify_model(unsigned id, model* mdl, rational const& v) override { return true; }; + void set_model(model_ref& _m) override { m_model = _m; } + void model_updated(model* mdl) override { } // no-op + }; - + lbool maxsmt_wrapper::operator()(vector>& soft) { + solver_maxsat_context ctx(m_params, m_solver.get(), m_model.get()); + maxsmt maxsmt(ctx, 0); + for (auto const& p : soft) { + maxsmt.add(p.first, p.second); + } + lbool r = maxsmt(); + if (r == l_true) { + ast_manager& m = m_solver->get_manager(); + svector labels; + maxsmt.get_model(m_model, labels); + // TBD: is m_fm applied or not? + unsigned j = 0; + expr_ref tmp(m); + for (unsigned i = 0; i < soft.size(); ++i) { + if (m_model->eval(soft[i].first, tmp) && m.is_true(tmp)) { + soft[j++] = soft[i]; + } + } + soft.shrink(j); + } + return r; + } }; diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 9e52481f2..422cf26b9 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -153,6 +153,48 @@ namespace opt { solver& s(); }; + /** + \brief Standalone MaxSMT solver. + + It takes as input a solver object and provides a MaxSAT solver routine. + + It assumes the solver state is satisfiable and therefore there is a model + associated with the constraints asserted to the solver. A model of the + solver state must be supplied as a last argument. + + It assumes that the caller manages scope on the solver such that + the solver can be left in a stronger or inconsistent state upon return. + Callers should therefore use this feature under a push/pop. + */ + class maxsmt_wrapper { + params_ref m_params; + ref m_solver; + model_ref m_model; + public: + maxsmt_wrapper(params_ref & p, solver* s, model* m): + m_params(p), + m_solver(s), + m_model(m) {} + + lbool operator()(expr_ref_vector& soft) { + vector> _soft; + for (expr* e : soft) _soft.push_back(std::make_pair(e, rational::one())); + lbool r = (*this)(_soft); + soft.reset(); + for (auto const& p : _soft) soft.push_back(p.first); + return r; + } + + /** + \brief takes a vector of weighted soft constraints. + Returns a modified list of soft constraints that are + satisfied in the maximal satisfying assignment. + */ + lbool operator()(vector> & soft); + + model_ref get_model() { return m_model; } + }; + }; #endif From abe67705d3cbead80481f06bf21f3ea4a7208118 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 May 2018 10:09:26 -0700 Subject: [PATCH 0999/1283] Cleanup iuc_proof --- src/muz/spacer/spacer_iuc_proof.cpp | 345 +++++++++----------- src/muz/spacer/spacer_iuc_proof.h | 94 +++--- src/muz/spacer/spacer_iuc_solver.cpp | 8 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 24 +- 4 files changed, 211 insertions(+), 260 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_proof.cpp b/src/muz/spacer/spacer_iuc_proof.cpp index 966b59df4..4ee887df5 100644 --- a/src/muz/spacer/spacer_iuc_proof.cpp +++ b/src/muz/spacer/spacer_iuc_proof.cpp @@ -6,229 +6,182 @@ namespace spacer { - /* - * ==================================== - * init - * ==================================== - */ - iuc_proof::iuc_proof(ast_manager& m, proof* pr, expr_set& b_conjuncts) : m(m), m_pr(pr,m) - { - // init A-marks and B-marks - collect_symbols_b(b_conjuncts); - compute_marks(b_conjuncts); - } +/* + * ==================================== + * init + * ==================================== + */ +iuc_proof::iuc_proof(ast_manager& m, proof* pr, expr_set& core_lits) : + m(m), m_pr(pr,m) { + // init A-marks and B-marks + collect_core_symbols(core_lits); + compute_marks(core_lits); +} - proof* iuc_proof::get() - { - return m_pr.get(); - } +/* + * ==================================== + * methods for computing symbol colors + * ==================================== + */ +class collect_pure_proc { + func_decl_set& m_symbs; +public: + collect_pure_proc(func_decl_set& s):m_symbs(s) {} - /* - * ==================================== - * methods for computing symbol colors - * ==================================== - */ - class collect_pure_proc { - func_decl_set& m_symbs; - public: - collect_pure_proc(func_decl_set& s):m_symbs(s) {} - - void operator()(app* a) { - if (a->get_family_id() == null_family_id) { - m_symbs.insert(a->get_decl()); - } - } - void operator()(var*) {} - void operator()(quantifier*) {} - }; - - void iuc_proof::collect_symbols_b(expr_set& b_conjuncts) - { - expr_mark visited; - collect_pure_proc proc(m_symbols_b); - for (expr_set::iterator it = b_conjuncts.begin(); it != b_conjuncts.end(); ++it) - { - for_each_expr(proc, visited, *it); + void operator()(app* a) { + if (a->get_family_id() == null_family_id) { + m_symbs.insert(a->get_decl()); } } + void operator()(var*) {} + void operator()(quantifier*) {} +}; - class is_pure_expr_proc { - func_decl_set const& m_symbs; - array_util m_au; - public: - struct non_pure {}; +void iuc_proof::collect_core_symbols(expr_set& core_lits) +{ + expr_mark visited; + collect_pure_proc proc(m_core_symbols); + for (expr_set::iterator it = core_lits.begin(); it != core_lits.end(); ++it) { + for_each_expr(proc, visited, *it); + } +} - is_pure_expr_proc(func_decl_set const& s, ast_manager& m): +class is_pure_expr_proc { + func_decl_set const& m_symbs; + array_util m_au; +public: + struct non_pure {}; + + is_pure_expr_proc(func_decl_set const& s, ast_manager& m): m_symbs(s), m_au (m) {} - void operator()(app* a) { - if (a->get_family_id() == null_family_id) { - if (!m_symbs.contains(a->get_decl())) { - throw non_pure(); - } - } - else if (a->get_family_id () == m_au.get_family_id () && - a->is_app_of (a->get_family_id (), OP_ARRAY_EXT)) { + void operator()(app* a) { + if (a->get_family_id() == null_family_id) { + if (!m_symbs.contains(a->get_decl())) { throw non_pure(); } } - void operator()(var*) {} - void operator()(quantifier*) {} - }; - - // requires that m_symbols_b has already been computed, which is done during initialization. - bool iuc_proof::only_contains_symbols_b(expr* expr) const - { - is_pure_expr_proc proc(m_symbols_b, m); - try { - for_each_expr(proc, expr); + else if (a->get_family_id () == m_au.get_family_id () && + a->is_app_of (a->get_family_id (), OP_ARRAY_EXT)) { + throw non_pure(); } - catch (is_pure_expr_proc::non_pure) - { - return false; - } - return true; } + void operator()(var*) {} + void operator()(quantifier*) {} +}; - /* - * ==================================== - * methods for computing which premises - * have been used to derive the conclusions - * ==================================== - */ +bool iuc_proof::is_core_pure(expr* e) const +{ + is_pure_expr_proc proc(m_core_symbols, m); + try { + for_each_expr(proc, e); + } + catch (is_pure_expr_proc::non_pure) + {return false;} - void iuc_proof::compute_marks(expr_set& b_conjuncts) + return true; +} + +void iuc_proof::compute_marks(expr_set& core_lits) +{ + proof_post_order it(m_pr, m); + while (it.hasNext()) { - proof_post_order it(m_pr, m); - while (it.hasNext()) + proof* cur = it.next(); + if (m.get_num_parents(cur) == 0) { - proof* currentNode = it.next(); - - if (m.get_num_parents(currentNode) == 0) + switch(cur->get_decl_kind()) { - switch(currentNode->get_decl_kind()) - { - - case PR_ASSERTED: // currentNode is an axiom - { - if (b_conjuncts.contains(m.get_fact(currentNode))) - { - m_b_mark.mark(currentNode, true); - } - else - { - m_a_mark.mark(currentNode, true); - } - break; - } - // currentNode is a hypothesis: - case PR_HYPOTHESIS: - { - m_h_mark.mark(currentNode, true); - break; - } - default: - { - break; - } - } - } - else - { - // collect from parents whether derivation of current node contains A-axioms, B-axioms and hypothesis - bool need_to_mark_a = false; - bool need_to_mark_b = false; - bool need_to_mark_h = false; - - for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) - { - SASSERT(m.is_proof(currentNode->get_arg(i))); - proof* premise = to_app(currentNode->get_arg(i)); - - need_to_mark_a = need_to_mark_a || m_a_mark.is_marked(premise); - need_to_mark_b = need_to_mark_b || m_b_mark.is_marked(premise); - need_to_mark_h = need_to_mark_h || m_h_mark.is_marked(premise); - } - - // if current node is application of lemma, we know that all hypothesis are removed - if(currentNode->get_decl_kind() == PR_LEMMA) - { - need_to_mark_h = false; - } - - // save results - m_a_mark.mark(currentNode, need_to_mark_a); - m_b_mark.mark(currentNode, need_to_mark_b); - m_h_mark.mark(currentNode, need_to_mark_h); + case PR_ASSERTED: + if (core_lits.contains(m.get_fact(cur))) + m_b_mark.mark(cur, true); + else + m_a_mark.mark(cur, true); + break; + case PR_HYPOTHESIS: + m_h_mark.mark(cur, true); + break; + default: + break; } } - } - - bool iuc_proof::is_a_marked(proof* p) - { - return m_a_mark.is_marked(p); - } - bool iuc_proof::is_b_marked(proof* p) - { - return m_b_mark.is_marked(p); - } - bool iuc_proof::is_h_marked(proof* p) - { - return m_h_mark.is_marked(p); - } - - /* - * ==================================== - * methods for dot printing - * ==================================== - */ - void iuc_proof::pp_dot() - { - pp_proof_dot(m, m_pr, this); - } - - /* - * ==================================== - * statistics - * ==================================== - */ - - void iuc_proof::print_farkas_stats() - { - unsigned farkas_counter = 0; - unsigned farkas_counter2 = 0; - - proof_post_order it3(m_pr, m); - while (it3.hasNext()) + else { - proof* currentNode = it3.next(); + // collect from parents whether derivation of current node + // contains A-axioms, B-axioms and hypothesis + bool need_to_mark_a = false; + bool need_to_mark_b = false; + bool need_to_mark_h = false; - // if node is theory lemma - if (is_farkas_lemma(m, currentNode)) + for (unsigned i = 0; i < m.get_num_parents(cur); ++i) { - farkas_counter++; + SASSERT(m.is_proof(cur->get_arg(i))); + proof* premise = to_app(cur->get_arg(i)); - // check whether farkas lemma is to be interpolated (could potentially miss farkas lemmas, which are interpolated, because we potentially don't want to use the lowest cut) - bool has_blue_nonred_parent = false; - for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) - { - proof* premise = to_app(currentNode->get_arg(i)); - if (!is_a_marked(premise) && is_b_marked(premise)) - { - has_blue_nonred_parent = true; - break; - } - } - if (has_blue_nonred_parent && is_a_marked(currentNode)) - { - SASSERT(is_b_marked(currentNode)); - farkas_counter2++; - } + need_to_mark_a |= m_a_mark.is_marked(premise); + need_to_mark_b |= m_b_mark.is_marked(premise); + need_to_mark_h |= m_h_mark.is_marked(premise); } - } - verbose_stream() << "\nThis proof contains " << farkas_counter << " Farkas lemmas. " << farkas_counter2 << " Farkas lemmas participate in the lowest cut\n"; + // if current node is application of a lemma, then all + // active hypotheses are removed + if(cur->get_decl_kind() == PR_LEMMA) need_to_mark_h = false; + + // save results + m_a_mark.mark(cur, need_to_mark_a); + m_b_mark.mark(cur, need_to_mark_b); + m_h_mark.mark(cur, need_to_mark_h); + } } } + +/* + * ==================================== + * statistics + * ==================================== + */ + +// debug method +void iuc_proof::dump_farkas_stats() +{ + unsigned fl_total = 0; + unsigned fl_lowcut = 0; + + proof_post_order it(m_pr, m); + while (it.hasNext()) + { + proof* cur = it.next(); + + // if node is theory lemma + if (is_farkas_lemma(m, cur)) + { + fl_total++; + + // check whether farkas lemma is to be interpolated (could + // potentially miss farkas lemmas, which are interpolated, + // because we potentially don't want to use the lowest + // cut) + bool has_blue_nonred_parent = false; + for (unsigned i = 0; i < m.get_num_parents(cur); ++i) { + proof* premise = to_app(cur->get_arg(i)); + if (!is_a_marked(premise) && is_b_marked(premise)) { + has_blue_nonred_parent = true; + break; + } + } + + if (has_blue_nonred_parent && is_a_marked(cur)) + { + SASSERT(is_b_marked(cur)); + fl_lowcut++; + } + } + } + + IF_VERBOSE(1, verbose_stream() + << "\n total farkas lemmas " << fl_total + << " farkas lemmas in lowest cut " << fl_lowcut << "\n";); +} +} diff --git a/src/muz/spacer/spacer_iuc_proof.h b/src/muz/spacer/spacer_iuc_proof.h index 205648109..97c00ea9b 100644 --- a/src/muz/spacer/spacer_iuc_proof.h +++ b/src/muz/spacer/spacer_iuc_proof.h @@ -4,62 +4,58 @@ #include "ast/ast.h" namespace spacer { - typedef obj_hashtable expr_set; - typedef obj_hashtable func_decl_set; +typedef obj_hashtable expr_set; +typedef obj_hashtable func_decl_set; - /* - * an iuc_proof is a proof together with information of the coloring of the axioms. - */ - class iuc_proof - { - public: - - iuc_proof(ast_manager& m, proof* pr, expr_set& b_conjuncts); - - proof* get(); +/* + * An iuc_proof is a proof together with information of the + * coloring of the axioms. + */ +class iuc_proof +{ +public: - /* - * returns whether symbol contains only symbols which occur in B. - */ - bool only_contains_symbols_b(expr* expr) const; + // Constructs an iuc_proof given an ast_manager, a proof, and a set of + // literals core_lits that might be included in the unsat core + iuc_proof(ast_manager& m, proof* pr, expr_set& core_lits); - bool is_a_marked(proof* p); - bool is_b_marked(proof* p); - bool is_h_marked(proof* p); + // returns the proof object + proof* get() {return m_pr.get();} - bool is_b_pure (proof *p) - {return !is_h_marked (p) && only_contains_symbols_b (m.get_fact (p));} + // returns true if all uninterpreted symbols of e are from the core literals + // requires that m_core_symbols has already been computed + bool is_core_pure(expr* e) const; - /* - * print dot-representation to file proof.dot - * use Graphviz's dot with option -Tpdf to convert dot-representation into pdf - */ - void pp_dot(); - - void print_farkas_stats(); - private: - ast_manager& m; - proof_ref m_pr; - - ast_mark m_a_mark; - ast_mark m_b_mark; - ast_mark m_h_mark; - - func_decl_set m_symbols_b; // symbols, which occur in any b-asserted formula + bool is_a_marked(proof* p) {return m_a_mark.is_marked(p);} + bool is_b_marked(proof* p) {return m_b_mark.is_marked(p);} + bool is_h_marked(proof* p) {return m_h_mark.is_marked(p);} + + bool is_b_pure (proof *p) { + return !is_h_marked (p) && is_core_pure(m.get_fact (p)); + } + + // debug method + void dump_farkas_stats(); +private: + ast_manager& m; + proof_ref m_pr; + + ast_mark m_a_mark; + ast_mark m_b_mark; + ast_mark m_h_mark; + + // symbols that occur in any literals in the core + func_decl_set m_core_symbols; + + // collect symbols occuring in B (the core) + void collect_core_symbols(expr_set& core_lits); + + // compute for each formula of the proof whether it derives + // from A or from B + void compute_marks(expr_set& core_lits); +}; - // collect symbols occuring in B - void collect_symbols_b(expr_set& b_conjuncts); - // compute for each formula of the proof whether it derives from A and whether it derives from B - void compute_marks(expr_set& b_conjuncts); - - void pp_dot_to_stream(std::ofstream& dotstream); - std::string escape_dot(const std::string &s); - - void post_process_dot(std::string dot_filepath, std::ofstream& dotstream); - }; - - } #endif /* IUC_PROOF_H_ */ diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index e2334f1ba..7c159746f 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -289,7 +289,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core) { iuc_proof iuc_before(m, res.get(), B); verbose_stream() << "\nStats before transformation:"; - iuc_before.print_farkas_stats(); + iuc_before.dump_farkas_stats(); } proof_utils::reduce_hypotheses(res); @@ -299,7 +299,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core) { iuc_proof iuc_after(m, res.get(), B); verbose_stream() << "Stats after transformation:"; - iuc_after.print_farkas_stats(); + iuc_after.dump_farkas_stats(); } } else // -- new hypothesis reducer @@ -309,7 +309,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core) { iuc_proof iuc_before(m, res.get(), B); verbose_stream() << "\nStats before transformation:"; - iuc_before.print_farkas_stats(); + iuc_before.dump_farkas_stats(); } theory_axiom_reducer ta_reducer(m); @@ -324,7 +324,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core) { iuc_proof iuc_after(m, res.get(), B); verbose_stream() << "Stats after transformation:"; - iuc_after.print_farkas_stats(); + iuc_after.dump_farkas_stats(); } } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 863023d5b..557983628 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -331,11 +331,13 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vectorassert_expr(lb); s->assert_expr(ub); } } - + // assert: forall i,j: a_ij = sum_k w_ik * s_jk for (unsigned i=0; i < matrix.num_rows(); ++i) { @@ -563,13 +565,13 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vectorget_model(model); - + for (unsigned k=0; k < n; ++k) { ptr_vector literals; vector coefficients; for (unsigned j=0; j < matrix.num_cols(); ++j) { expr_ref evaluation(m); - + model.get()->eval(bounded_vectors[j][k].get(), evaluation, false); if (!util.is_zero(evaluation)) { literals.push_back(ordered_basis[j]); @@ -579,7 +581,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector& todo) { bool is_sink = true; @@ -709,7 +711,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector Date: Wed, 16 May 2018 12:57:35 -0700 Subject: [PATCH 1000/1283] Cleanup iuc_proof --- src/muz/spacer/spacer_iuc_proof.cpp | 25 ++++++++++++++++--------- src/muz/spacer/spacer_iuc_proof.h | 12 ++++++++---- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_proof.cpp b/src/muz/spacer/spacer_iuc_proof.cpp index 4ee887df5..1123a7c76 100644 --- a/src/muz/spacer/spacer_iuc_proof.cpp +++ b/src/muz/spacer/spacer_iuc_proof.cpp @@ -11,13 +11,21 @@ namespace spacer { * init * ==================================== */ -iuc_proof::iuc_proof(ast_manager& m, proof* pr, expr_set& core_lits) : +iuc_proof::iuc_proof(ast_manager& m, proof* pr, const expr_set& core_lits) : m(m), m_pr(pr,m) { + for (auto lit : core_lits) m_core_lits.insert(lit); // init A-marks and B-marks - collect_core_symbols(core_lits); - compute_marks(core_lits); + collect_core_symbols(); + compute_marks(); } +iuc_proof::iuc_proof(ast_manager& m, proof* pr, const expr_ref_vector& core_lits) : + m(m), m_pr(pr,m) { + for (auto lit : core_lits) m_core_lits.insert(lit); + // init A-marks and B-marks + collect_core_symbols(); + compute_marks(); +} /* * ==================================== * methods for computing symbol colors @@ -37,13 +45,12 @@ public: void operator()(quantifier*) {} }; -void iuc_proof::collect_core_symbols(expr_set& core_lits) +void iuc_proof::collect_core_symbols() { expr_mark visited; collect_pure_proc proc(m_core_symbols); - for (expr_set::iterator it = core_lits.begin(); it != core_lits.end(); ++it) { - for_each_expr(proc, visited, *it); - } + for (auto lit : m_core_lits) + for_each_expr(proc, visited, lit); } class is_pure_expr_proc { @@ -84,7 +91,7 @@ bool iuc_proof::is_core_pure(expr* e) const return true; } -void iuc_proof::compute_marks(expr_set& core_lits) +void iuc_proof::compute_marks() { proof_post_order it(m_pr, m); while (it.hasNext()) @@ -95,7 +102,7 @@ void iuc_proof::compute_marks(expr_set& core_lits) switch(cur->get_decl_kind()) { case PR_ASSERTED: - if (core_lits.contains(m.get_fact(cur))) + if (m_core_lits.contains(m.get_fact(cur))) m_b_mark.mark(cur, true); else m_a_mark.mark(cur, true); diff --git a/src/muz/spacer/spacer_iuc_proof.h b/src/muz/spacer/spacer_iuc_proof.h index 97c00ea9b..aeb18ef37 100644 --- a/src/muz/spacer/spacer_iuc_proof.h +++ b/src/muz/spacer/spacer_iuc_proof.h @@ -17,7 +17,8 @@ public: // Constructs an iuc_proof given an ast_manager, a proof, and a set of // literals core_lits that might be included in the unsat core - iuc_proof(ast_manager& m, proof* pr, expr_set& core_lits); + iuc_proof(ast_manager& m, proof* pr, const expr_set& core_lits); + iuc_proof(ast_manager& m, proof* pr, const expr_ref_vector &core_lits); // returns the proof object proof* get() {return m_pr.get();} @@ -44,15 +45,18 @@ private: ast_mark m_b_mark; ast_mark m_h_mark; + // -- literals that are part of the core + expr_set m_core_lits; + // symbols that occur in any literals in the core func_decl_set m_core_symbols; - // collect symbols occuring in B (the core) - void collect_core_symbols(expr_set& core_lits); + // collect symbols occurring in B (the core) + void collect_core_symbols(); // compute for each formula of the proof whether it derives // from A or from B - void compute_marks(expr_set& core_lits); + void compute_marks(); }; From 07ad67ebad7fda14a64bd5974b705ac3910a766e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 May 2018 13:32:28 -0700 Subject: [PATCH 1001/1283] Move proof dot printing into iuc_proof --- src/muz/spacer/spacer_iuc_proof.cpp | 88 ++- src/muz/spacer/spacer_iuc_proof.h | 2 + src/muz/spacer/spacer_proof_utils.cpp | 987 +++++++++++--------------- src/muz/spacer/spacer_proof_utils.h | 101 +-- 4 files changed, 545 insertions(+), 633 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_proof.cpp b/src/muz/spacer/spacer_iuc_proof.cpp index 1123a7c76..6033c744f 100644 --- a/src/muz/spacer/spacer_iuc_proof.cpp +++ b/src/muz/spacer/spacer_iuc_proof.cpp @@ -1,9 +1,12 @@ +#include +#include "ast/ast_pp_dot.h" + #include "muz/spacer/spacer_iuc_proof.h" #include "ast/for_each_expr.h" #include "ast/array_decl_plugin.h" #include "ast/proofs/proof_utils.h" #include "muz/spacer/spacer_proof_utils.h" - +#include "muz/spacer/spacer_util.h" namespace spacer { /* @@ -191,4 +194,87 @@ void iuc_proof::dump_farkas_stats() << "\n total farkas lemmas " << fl_total << " farkas lemmas in lowest cut " << fl_lowcut << "\n";); } + +void iuc_proof::display_dot(std::ostream& out) { + out << "digraph proof { \n"; + + std::unordered_map ids; + unsigned last_id = 0; + + proof_post_order it(m_pr, m); + while (it.hasNext()) + { + proof* curr = it.next(); + + SASSERT(ids.count(curr->get_id()) == 0); + ids.insert(std::make_pair(curr->get_id(), last_id)); + + std::string color = "white"; + if (this->is_a_marked(curr) && !this->is_b_marked(curr)) + color = "red"; + else if(!this->is_a_marked(curr) && this->is_b_marked(curr)) + color = "blue"; + else if(this->is_a_marked(curr) && this->is_b_marked(curr) ) + color = "purple"; + + // compute node label + std::ostringstream label_ostream; + label_ostream << mk_epp(m.get_fact(curr), m) << "\n"; + std::string label = escape_dot(label_ostream.str()); + + // compute edge-label + std::string edge_label = ""; + if (m.get_num_parents(curr) == 0) { + switch (curr->get_decl_kind()) + { + case PR_ASSERTED: + edge_label = "asserted:"; + break; + case PR_HYPOTHESIS: + edge_label = "hyp:"; + color = "grey"; + break; + case PR_TH_LEMMA: + if (is_farkas_lemma(m, curr)) + edge_label = "th_axiom(farkas):"; + else if (is_arith_lemma(m, curr)) + edge_label = "th_axiom(arith):"; + else + edge_label = "th_axiom:"; + break; + default: + edge_label = "unknown axiom:"; + } + } + else { + if (curr->get_decl_kind() == PR_LEMMA) + edge_label = "lemma:"; + else if (curr->get_decl_kind() == PR_TH_LEMMA) { + if (is_farkas_lemma(m, curr)) + edge_label = "th_lemma(farkas):"; + else if (is_arith_lemma(m, curr)) + edge_label = "th_lemma(arith):"; + else + edge_label = "th_lemma(other):"; + } + } + + // generate entry for node in dot-file + out << "node_" << last_id << " " << "[" + << "shape=box,style=\"filled\"," + << "label=\"" << edge_label << " " << label << "\", " + << "fillcolor=\"" << color << "\"" << "]\n"; + + // add entry for each edge to that node + for (unsigned i = m.get_num_parents(curr); i > 0 ; --i) + { + proof* premise = to_app(curr->get_arg(i-1)); + unsigned pid = ids.at(premise->get_id()); + out << "node_" << pid << " -> " << "node_" << last_id << ";\n"; + } + + ++last_id; + } + out << "\n}" << std::endl; +} } diff --git a/src/muz/spacer/spacer_iuc_proof.h b/src/muz/spacer/spacer_iuc_proof.h index aeb18ef37..a3044ca53 100644 --- a/src/muz/spacer/spacer_iuc_proof.h +++ b/src/muz/spacer/spacer_iuc_proof.h @@ -1,6 +1,7 @@ #ifndef IUC_PROOF_H_ #define IUC_PROOF_H_ +#include #include "ast/ast.h" namespace spacer { @@ -35,6 +36,7 @@ public: return !is_h_marked (p) && is_core_pure(m.get_fact (p)); } + void display_dot(std::ostream &out); // debug method void dump_farkas_stats(); private: diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 32391db91..146436db9 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -16,7 +16,6 @@ Revision History: --*/ -#include #include "util/params.h" #include "ast/ast_pp.h" #include "ast/ast_util.h" @@ -26,680 +25,498 @@ Revision History: #include "ast/proofs/proof_utils.h" #include "muz/spacer/spacer_proof_utils.h" +#include "muz/spacer/spacer_util.h" namespace spacer { +// arithmetic lemma recognizer +bool is_arith_lemma(ast_manager& m, proof* pr) +{ // arith lemmas: second parameter specifies exact type of lemma, // could be "farkas", "triangle-eq", "eq-propagate", // "assign-bounds", maybe also something else - bool is_arith_lemma(ast_manager& m, proof* pr) + if (pr->get_decl_kind() == PR_TH_LEMMA) { + func_decl* d = pr->get_decl(); + symbol sym; + return d->get_num_parameters() >= 1 && + d->get_parameter(0).is_symbol(sym) && + sym == "arith"; + } + return false; +} + +// farkas lemma recognizer +bool is_farkas_lemma(ast_manager& m, proof* pr) +{ + if (pr->get_decl_kind() == PR_TH_LEMMA) { - if (pr->get_decl_kind() == PR_TH_LEMMA) + func_decl* d = pr->get_decl(); + symbol sym; + return d->get_num_parameters() >= 2 && + d->get_parameter(0).is_symbol(sym) && sym == "arith" && + d->get_parameter(1).is_symbol(sym) && sym == "farkas"; + } + return false; +} + + +/* + * ==================================== + * methods for transforming proofs + * ==================================== + */ + +void theory_axiom_reducer::reset() +{ + m_cache.reset(); + m_pinned.reset(); +} + +proof_ref theory_axiom_reducer::reduce(proof* pr) +{ + proof_post_order pit(pr, m); + while (pit.hasNext()) + { + proof* p = pit.next(); + + if (m.get_num_parents(p) == 0 && is_arith_lemma(m, p)) { - func_decl* d = pr->get_decl(); - symbol sym; - if (d->get_num_parameters() >= 1 && - d->get_parameter(0).is_symbol(sym) && sym == "arith") - { - return true; - } - } - return false; - } + // we have an arith-theory-axiom and want to get rid of it + // we need to replace the axiom with 1a) corresponding hypothesis', 1b) a theory lemma and a 1c) a lemma. Furthermore update datastructures + app *cls_fact = to_app(m.get_fact(p)); + ptr_buffer cls; + if (m.is_or(cls_fact)) { + for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) + { cls.push_back(cls_fact->get_arg(i)); } + } else { cls.push_back(cls_fact); } - bool is_farkas_lemma(ast_manager& m, proof* pr) - { - if (pr->get_decl_kind() == PR_TH_LEMMA) + // 1a) create hypothesis' + ptr_buffer hyps; + for (unsigned i=0; i < cls.size(); ++i) + { + expr* hyp_fact = m.is_not(cls[i]) ? to_app(cls[i])->get_arg(0) : m.mk_not(cls[i]); + proof* hyp = m.mk_hypothesis(hyp_fact); + m_pinned.push_back(hyp); + hyps.push_back(hyp); + } + + // 1b) create farkas lemma: need to rebuild parameters since mk_th_lemma adds tid as first parameter + unsigned num_params = p->get_decl()->get_num_parameters(); + parameter const* params = p->get_decl()->get_parameters(); + vector parameters; + for (unsigned i = 1; i < num_params; ++i) { + parameters.push_back(params[i]); + } + + SASSERT(params[0].is_symbol()); + family_id tid = m.mk_family_id(params[0].get_symbol()); + SASSERT(tid != null_family_id); + + proof* th_lemma = m.mk_th_lemma(tid, m.mk_false(),hyps.size(), hyps.c_ptr(), num_params-1, parameters.c_ptr()); + SASSERT(is_arith_lemma(m, th_lemma)); + + // 1c) create lemma + proof* res = m.mk_lemma(th_lemma, cls_fact); + SASSERT(m.get_fact(res) == m.get_fact(p)); + m_pinned.push_back(res); + m_cache.insert(p, res); + } + else { - func_decl* d = pr->get_decl(); - symbol sym; - if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas") + bool dirty = false; // proof is dirty, if a subproof of one of its premises has been transformed + + ptr_buffer args; + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { - return true; - } - } - return false; - } - - /* - * ==================================== - * methods for dot printing - * ==================================== - */ - void pp_proof_dot_to_stream(ast_manager& m, std::ofstream& dotstream, proof* pr, iuc_proof* iuc_pr = nullptr); - std::string escape_dot(const std::string &s); - void pp_proof_post_process_dot(std::string dot_filepath, std::ofstream &dotstream); - - void pp_proof_dot(ast_manager& m, proof* pr, iuc_proof* iuc_pr) - { - // open temporary dot-file - std::string dotfile_path = "proof.dot"; - std::ofstream dotstream(dotfile_path); - - // dump dot representation to stream - pp_proof_dot_to_stream(m, dotstream, pr, iuc_pr); - - // post process dot-file, TODO: factor this out to a different place - pp_proof_post_process_dot(dotfile_path,dotstream); - } - - void pp_proof_dot_to_stream(ast_manager& m, std::ofstream& dotstream, proof* pr, iuc_proof* iuc_pr) - { - dotstream << "digraph proof { \n"; - std::unordered_map id_to_small_id; - unsigned counter = 0; - - proof_post_order it2(pr, m); - while (it2.hasNext()) - { - proof* currentNode = it2.next(); - - SASSERT(id_to_small_id.find(currentNode->get_id()) == id_to_small_id.end()); - id_to_small_id.insert(std::make_pair(currentNode->get_id(), counter)); - - std::string color = "white"; - if (iuc_pr != nullptr) - { - if (iuc_pr->is_a_marked(currentNode) && !iuc_pr->is_b_marked(currentNode)) + proof* pp = m.get_parent(p, i); + proof* tmp; + if (m_cache.find(pp, tmp)) { - color = "red"; + args.push_back(tmp); + dirty = dirty || pp != tmp; } - else if(iuc_pr->is_b_marked(currentNode) && !iuc_pr->is_a_marked(currentNode)) + else { - color = "blue"; - } - else if(iuc_pr->is_b_marked(currentNode) && iuc_pr->is_a_marked(currentNode)) - { - color = "purple"; + SASSERT(false); } } - - // compute label - params_ref p; - p.set_uint("max_depth", 4294967295u); - p.set_uint("min_alias_size", 4294967295u); - - std::ostringstream label_ostream; - label_ostream << mk_pp(m.get_fact(currentNode),m,p) << "\n"; - std::string label = escape_dot(label_ostream.str()); - - // compute edge-label - std::string edge_label = ""; - if (m.get_num_parents(currentNode) == 0) + if (!dirty) // if not dirty just use the old step { - switch (currentNode->get_decl_kind()) - { - case PR_ASSERTED: - edge_label = "asserted:"; - break; - case PR_HYPOTHESIS: - edge_label = "hyp:"; - color = "grey"; - break; - case PR_TH_LEMMA: - if (is_farkas_lemma(m, currentNode)) - { - edge_label = "th_axiom(farkas):"; - } - else - { - edge_label = "th_axiom:"; - } - break; - default: - edge_label = "unknown axiom-type:"; - } + m_cache.insert(p, p); } - else + else // otherwise create new step with the corresponding proofs of the premises { - if (currentNode->get_decl_kind() == PR_LEMMA) - { - edge_label = "lemma:"; - } - else if (currentNode->get_decl_kind() == PR_TH_LEMMA) - { - func_decl* d = currentNode->get_decl(); - symbol sym; - if (d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas") - { - edge_label = "th_lemma(farkas):"; - } - else - { - edge_label = "th_lemma(other):"; - } - } - } - - // generate entry for node in dot-file - dotstream << "node_" << counter << " " - << "[" - << "shape=box,style=\"filled\"," - << "label=\"" << edge_label << " " << label << "\", " - << "fillcolor=\"" << color << "\"" - << "]\n"; - - // add entry for each edge to that node - for (unsigned i = m.get_num_parents(currentNode); i > 0 ; --i) - { - proof* premise = to_app(currentNode->get_arg(i-1)); - unsigned premise_small_id = id_to_small_id[premise->get_id()]; - dotstream << "node_" << premise_small_id - << " -> " - << "node_" << counter - << ";\n"; - } - - ++counter; - } - dotstream << "\n}" << std::endl; - } - - std::string escape_dot(const std::string &s) - { - std::string res; - res.reserve(s.size()); // preallocate - for (auto c : s) { - if (c == '\n') - res.append("\\l"); - else - res.push_back(c); - } - return res; - } - - void pp_proof_post_process_dot(std::string dot_filepath, std::ofstream &dotstream) - { - // replace variables in the dotfiles with nicer descriptions (hack: hard coded replacement for now) - std::vector > predicates; - std::vector l1 = {"L1","i","n","A"}; - predicates.push_back(l1); - std::vector l2 = {"L2","j","m","B"}; - predicates.push_back(l2); - - for(auto& predicate : predicates) - { - std::string predicate_name = predicate[0]; - for (unsigned i=0; i+1 < predicate.size(); ++i) - { - std::string new_name = predicate[i+1]; - std::string substring0 = predicate_name + "_" + std::to_string(i) + "_0"; - std::string substringN = predicate_name + "_" + std::to_string(i) + "_n"; - - std::string command0 = "sed -i '.bak' 's/" + substring0 + "/" + new_name + "/g' " + dot_filepath; - verbose_stream() << command0 << std::endl; - system(command0.c_str()); - - std::string commandN = "sed -i '.bak' s/" + substringN + "/" + new_name + "\\'" + "/g " + dot_filepath; - verbose_stream() << commandN << std::endl; - system(commandN.c_str()); - } - } - - verbose_stream() << "end of postprocessing"; - } - - /* - * ==================================== - * methods for transforming proofs - * ==================================== - */ - - void theory_axiom_reducer::reset() - { - m_cache.reset(); - m_pinned.reset(); - } - - proof_ref theory_axiom_reducer::reduce(proof* pr) - { - proof_post_order pit(pr, m); - while (pit.hasNext()) - { - proof* p = pit.next(); - - if (m.get_num_parents(p) == 0 && is_arith_lemma(m, p)) - { - // we have an arith-theory-axiom and want to get rid of it - // we need to replace the axiom with 1a) corresponding hypothesis', 1b) a theory lemma and a 1c) a lemma. Furthermore update datastructures - app *cls_fact = to_app(m.get_fact(p)); - ptr_buffer cls; - if (m.is_or(cls_fact)) { - for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) - { cls.push_back(cls_fact->get_arg(i)); } - } else { cls.push_back(cls_fact); } - - // 1a) create hypothesis' - ptr_buffer hyps; - for (unsigned i=0; i < cls.size(); ++i) - { - expr* hyp_fact = m.is_not(cls[i]) ? to_app(cls[i])->get_arg(0) : m.mk_not(cls[i]); - proof* hyp = m.mk_hypothesis(hyp_fact); - m_pinned.push_back(hyp); - hyps.push_back(hyp); - } - - // 1b) create farkas lemma: need to rebuild parameters since mk_th_lemma adds tid as first parameter - unsigned num_params = p->get_decl()->get_num_parameters(); - parameter const* params = p->get_decl()->get_parameters(); - vector parameters; - for (unsigned i = 1; i < num_params; ++i) { - parameters.push_back(params[i]); - } - - SASSERT(params[0].is_symbol()); - family_id tid = m.mk_family_id(params[0].get_symbol()); - SASSERT(tid != null_family_id); - - proof* th_lemma = m.mk_th_lemma(tid, m.mk_false(),hyps.size(), hyps.c_ptr(), num_params-1, parameters.c_ptr()); - SASSERT(is_arith_lemma(m, th_lemma)); - - // 1c) create lemma - proof* res = m.mk_lemma(th_lemma, cls_fact); - SASSERT(m.get_fact(res) == m.get_fact(p)); + if (m.has_fact(p)) { args.push_back(m.get_fact(p)); } + SASSERT(p->get_decl()->get_arity() == args.size()); + proof* res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); m_pinned.push_back(res); m_cache.insert(p, res); } - else - { - bool dirty = false; // proof is dirty, if a subproof of one of its premises has been transformed - - ptr_buffer args; - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) - { - proof* pp = m.get_parent(p, i); - proof* tmp; - if (m_cache.find(pp, tmp)) - { - args.push_back(tmp); - dirty = dirty || pp != tmp; - } - else - { - SASSERT(false); - } - } - if (!dirty) // if not dirty just use the old step - { - m_cache.insert(p, p); - } - else // otherwise create new step with the corresponding proofs of the premises - { - if (m.has_fact(p)) { args.push_back(m.get_fact(p)); } - SASSERT(p->get_decl()->get_arity() == args.size()); - proof* res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); - m_pinned.push_back(res); - m_cache.insert(p, res); - } - } } - - proof* res; - VERIFY(m_cache.find(pr,res)); - DEBUG_CODE(proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(res, side)); - ); - - return proof_ref(res,m); } - void hypothesis_reducer::reset() - { - m_cache.reset(); - m_units.reset(); - m_active_hyps.reset(); - m_parent_hyps.reset(); - m_pinned_active_hyps.reset(); - m_pinned_parent_hyps.reset(); - m_pinned.reset(); - } + proof* res; + VERIFY(m_cache.find(pr,res)); + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(res, side)); + ); - void hypothesis_reducer::compute_hypsets(proof* pr) - { - ptr_vector todo; - todo.push_back(pr); + return proof_ref(res,m); +} - while (!todo.empty()) +void hypothesis_reducer::reset() +{ + m_cache.reset(); + m_units.reset(); + m_active_hyps.reset(); + m_parent_hyps.reset(); + m_pinned_active_hyps.reset(); + m_pinned_parent_hyps.reset(); + m_pinned.reset(); +} + +void hypothesis_reducer::compute_hypsets(proof* pr) +{ + ptr_vector todo; + todo.push_back(pr); + + while (!todo.empty()) + { + proof* p = todo.back(); + + if (m_active_hyps.contains(p)) { - proof* p = todo.back(); + SASSERT(m_parent_hyps.contains(p)); + todo.pop_back(); + } + // if we haven't already visited the current unit + else + { + bool existsUnvisitedParent = false; - if (m_active_hyps.contains(p)) - { - SASSERT(m_parent_hyps.contains(p)); - todo.pop_back(); - } - // if we haven't already visited the current unit - else - { - bool existsUnvisitedParent = false; + // add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result + // for p now, but wait until those unprocessed premises are processed. + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + SASSERT(m.is_proof(p->get_arg(i))); + proof* premise = to_app(p->get_arg(i)); - // add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result - // for p now, but wait until those unprocessed premises are processed. - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - SASSERT(m.is_proof(p->get_arg(i))); - proof* premise = to_app(p->get_arg(i)); - - // if we haven't visited the premise yet - if (!m_active_hyps.contains(premise)) - { - SASSERT(!m_parent_hyps.contains(premise)); - // add it to the stack - todo.push_back(premise); - existsUnvisitedParent = true; - } - } - - // if we already visited all premises, we can visit p too - if (!existsUnvisitedParent) + // if we haven't visited the premise yet + if (!m_active_hyps.contains(premise)) { - todo.pop_back(); + SASSERT(!m_parent_hyps.contains(premise)); + // add it to the stack + todo.push_back(premise); + existsUnvisitedParent = true; + } + } - // create active_hyps-set and parent_hyps-set for step p - proof_set* active_hyps = alloc(proof_set); - m_pinned_active_hyps.insert(active_hyps); - m_active_hyps.insert(p, active_hyps); + // if we already visited all premises, we can visit p too + if (!existsUnvisitedParent) + { + todo.pop_back(); - expr_set* parent_hyps = alloc(expr_set); - m_pinned_parent_hyps.insert(parent_hyps); - m_parent_hyps.insert(p, parent_hyps); + // create active_hyps-set and parent_hyps-set for step p + proof_set* active_hyps = alloc(proof_set); + m_pinned_active_hyps.insert(active_hyps); + m_active_hyps.insert(p, active_hyps); - // fill both sets - if (m.is_hypothesis(p)) + expr_set* parent_hyps = alloc(expr_set); + m_pinned_parent_hyps.insert(parent_hyps); + m_parent_hyps.insert(p, parent_hyps); + + // fill both sets + if (m.is_hypothesis(p)) + { + active_hyps->insert(p); + parent_hyps->insert(m.get_fact(p)); + } + else + { + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { - active_hyps->insert(p); - parent_hyps->insert(m.get_fact(p)); - } - else - { - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) + proof* pp = m.get_parent(p, i); + set_union(*parent_hyps, *m_parent_hyps.find(pp)); + + if (!m.is_lemma(p)) // lemmas clear all hypotheses { - proof* pp = m.get_parent(p, i); - set_union(*parent_hyps, *m_parent_hyps.find(pp)); - - if (!m.is_lemma(p)) // lemmas clear all hypotheses - { - set_union(*active_hyps, *m_active_hyps.find(pp)); - } + set_union(*active_hyps, *m_active_hyps.find(pp)); } } } } } } +} - // collect all units that are hyp-free and are used as hypotheses somewhere - // requires that m_active_hyps and m_parent_hyps have been computed - void hypothesis_reducer::collect_units(proof* pr) - { - expr_set* all_hyps = m_parent_hyps.find(pr); - SASSERT(all_hyps != nullptr); +// collect all units that are hyp-free and are used as hypotheses somewhere +// requires that m_active_hyps and m_parent_hyps have been computed +void hypothesis_reducer::collect_units(proof* pr) +{ + expr_set* all_hyps = m_parent_hyps.find(pr); + SASSERT(all_hyps != nullptr); - proof_post_order pit(pr, m); - while (pit.hasNext()) { - proof* p = pit.next(); - if (!m.is_hypothesis(p)) + proof_post_order pit(pr, m); + while (pit.hasNext()) { + proof* p = pit.next(); + if (!m.is_hypothesis(p)) + { + proof_set* active_hyps = m_active_hyps.find(p); + SASSERT(active_hyps != nullptr); + + // collect units that are hyp-free and are used as hypotheses in the proof pr + if (active_hyps->empty() && m.has_fact(p) && all_hyps->contains(m.get_fact(p))) { - proof_set* active_hyps = m_active_hyps.find(p); - SASSERT(active_hyps != nullptr); - - // collect units that are hyp-free and are used as hypotheses in the proof pr - if (active_hyps->empty() && m.has_fact(p) && all_hyps->contains(m.get_fact(p))) - { - m_units.insert(m.get_fact(p), p); - } + m_units.insert(m.get_fact(p), p); } } } +} - proof_ref hypothesis_reducer::reduce(proof* pr) - { - compute_hypsets(pr); - collect_units(pr); +proof_ref hypothesis_reducer::reduce(proof* pr) +{ + compute_hypsets(pr); + collect_units(pr); - proof* res = compute_transformed_proof(pr); - SASSERT(res != nullptr); + proof* res = compute_transformed_proof(pr); + SASSERT(res != nullptr); - proof_ref res_ref(res,m); + proof_ref res_ref(res,m); - reset(); - DEBUG_CODE(proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(res, side)); - ); - return res_ref; - } + reset(); + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(res, side)); + ); + return res_ref; +} - proof* hypothesis_reducer::compute_transformed_proof(proof* pf) - { - proof *res = NULL; +proof* hypothesis_reducer::compute_transformed_proof(proof* pf) +{ + proof *res = NULL; - ptr_vector todo; - todo.push_back(pf); - ptr_buffer args; - bool dirty = false; + ptr_vector todo; + todo.push_back(pf); + ptr_buffer args; + bool dirty = false; - while (!todo.empty()) { - proof *p, *tmp, *pp; - unsigned todo_sz; + while (!todo.empty()) { + proof *p, *tmp, *pp; + unsigned todo_sz; - p = todo.back(); - if (m_cache.find(p, tmp)) { - todo.pop_back(); - continue; + p = todo.back(); + if (m_cache.find(p, tmp)) { + todo.pop_back(); + continue; + } + + dirty = false; + args.reset(); + todo_sz = todo.size(); + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + pp = m.get_parent(p, i); + if (m_cache.find(pp, tmp)) { + args.push_back(tmp); + dirty = dirty || pp != tmp; + } else { + todo.push_back(pp); } + } - dirty = false; - args.reset(); - todo_sz = todo.size(); - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { - pp = m.get_parent(p, i); - if (m_cache.find(pp, tmp)) { - args.push_back(tmp); - dirty = dirty || pp != tmp; - } else { - todo.push_back(pp); - } - } - - if (todo_sz < todo.size()) { continue; } - else { todo.pop_back(); } + if (todo_sz < todo.size()) { continue; } + else { todo.pop_back(); } - // here the proof transformation begins - // INV: whenever we visit p, active_hyps and parent_hyps have been computed for the args. - if (m.is_hypothesis(p)) + // here the proof transformation begins + // INV: whenever we visit p, active_hyps and parent_hyps have been computed for the args. + if (m.is_hypothesis(p)) + { + // hyp: replace by a corresponding unit + if (m_units.find(m.get_fact(p), tmp)) { - // hyp: replace by a corresponding unit - if (m_units.find(m.get_fact(p), tmp)) + // look up the proof of the unit: + // if there is a transformed proof use that one + // otherwise use the original proof + proof* proof_of_unit; + if (!m_cache.find(tmp,proof_of_unit)) { - // look up the proof of the unit: - // if there is a transformed proof use that one - // otherwise use the original proof - proof* proof_of_unit; - if (!m_cache.find(tmp,proof_of_unit)) - { - proof_of_unit = tmp; - } - - // compute hypsets (have not been computed in general, since the unit can be anywhere in the proof) - compute_hypsets(proof_of_unit); - - // if the transformation doesn't create a cycle, perform it - SASSERT(m_parent_hyps.contains(proof_of_unit)); - expr_set* parent_hyps = m_parent_hyps.find(proof_of_unit); - if (!parent_hyps->contains(p)) - { - res = proof_of_unit; - // hypsets have already been computed for proof_of_unit - } - // otherwise don't transform the proof and just use the hypothesis - else - { - res = p; - // hypsets have already been computed for p - } + proof_of_unit = tmp; } + + // compute hypsets (have not been computed in general, since the unit can be anywhere in the proof) + compute_hypsets(proof_of_unit); + + // if the transformation doesn't create a cycle, perform it + SASSERT(m_parent_hyps.contains(proof_of_unit)); + expr_set* parent_hyps = m_parent_hyps.find(proof_of_unit); + if (!parent_hyps->contains(p)) + { + res = proof_of_unit; + // hypsets have already been computed for proof_of_unit + } + // otherwise don't transform the proof and just use the hypothesis else { res = p; // hypsets have already been computed for p } } - else if (!dirty) { res = p; } - - else if (m.is_lemma(p)) - { - //lemma: reduce the premise; remove reduced consequences from conclusion - SASSERT(args.size() == 1); - res = mk_lemma_core(args[0], m.get_fact(p)); - compute_hypsets(res); - } - else if (m.is_unit_resolution(p)) - { - // unit: reduce untis; reduce the first premise; rebuild unit resolution - res = mk_unit_resolution_core(args); - compute_hypsets(res); - } else { - res = mk_step_core(p, args); - compute_hypsets(res); - } - - SASSERT(res); - m_cache.insert(p, res); - - SASSERT(m_active_hyps.contains(res)); - proof_set* active_hyps = m_active_hyps.find(res); - if (active_hyps->empty() && m.has_fact(res) && m.is_false(m.get_fact(res))) - { - return res; + res = p; + // hypsets have already been computed for p } } - UNREACHABLE(); - return nullptr; - } + else if (!dirty) { res = p; } - proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) - { - SASSERT(m.is_false(m.get_fact(premise))); - - SASSERT(m_active_hyps.contains(premise)); - proof_set* active_hyps = m_active_hyps.find(premise); - - // if there is no active hypothesis return the premise - if (active_hyps->empty()) + else if (m.is_lemma(p)) { - return premise; + //lemma: reduce the premise; remove reduced consequences from conclusion + SASSERT(args.size() == 1); + res = mk_lemma_core(args[0], m.get_fact(p)); + compute_hypsets(res); } - // otherwise build disjunction of the negated active hypothesis' and add lemma step. - else + else if (m.is_unit_resolution(p)) { - expr_ref_buffer args(m); - for (auto hyp : *active_hyps) - { - expr* hyp_fact = m.get_fact(hyp); - expr_ref negated_hyp_fact(m); - negated_hyp_fact = m.is_not(hyp_fact) ? to_app(hyp_fact)->get_arg(0) : m.mk_not(hyp_fact); - args.push_back(negated_hyp_fact); - } - - expr_ref lemma(m); - if (args.size() == 1) - { - lemma = args[0]; - } - else - { - lemma = m.mk_or(args.size(), args.c_ptr()); - } - proof_ref res(m); - res = m.mk_lemma(premise, lemma); - m_pinned.push_back(res); - return res; - } - } - - proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) - { - ptr_buffer pf_args; // the arguments of the transformed unit resolution step - pf_args.push_back(args [0]); // the first element of args is the clause to resolve with - - // if any literal is false, we don't need a unit resolution step - // could be the case due to transformations which already have been done - for (unsigned i = 1; i < args.size(); ++i) - { - if (m.is_false(m.get_fact(args[i]))) - { - return args[i]; - } - } - - app *cls_fact = to_app(m.get_fact(args[0])); // BUG: I guess this shouldn't work with quantifiers (since they are no apps) - ptr_buffer cls; - if (m.is_or(cls_fact)) { - for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) - { cls.push_back(cls_fact->get_arg(i)); } - } else { cls.push_back(cls_fact); } - - // construct new resolvent - ptr_buffer new_fact_cls; - bool found; - // XXX quadratic - for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { - found = false; - for (unsigned j = 1; j < args.size(); ++j) { - if (m.is_complement(cls.get(i), m.get_fact(args [j]))) { - found = true; - pf_args.push_back(args [j]); - break; - } - } - if (!found) { - new_fact_cls.push_back(cls.get(i)); - } - } - - SASSERT(new_fact_cls.size() + pf_args.size() - 1 == cls.size()); - expr_ref new_fact(m); - new_fact = mk_or(m, new_fact_cls.size(), new_fact_cls.c_ptr()); - - // create new proof step - if (pf_args.size() == 1) // the only premise is the clause itself - { - return args[0]; + // unit: reduce untis; reduce the first premise; rebuild unit resolution + res = mk_unit_resolution_core(args); + compute_hypsets(res); } else { - proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); - m_pinned.push_back(res); + res = mk_step_core(p, args); + compute_hypsets(res); + } + + SASSERT(res); + m_cache.insert(p, res); + + SASSERT(m_active_hyps.contains(res)); + proof_set* active_hyps = m_active_hyps.find(res); + if (active_hyps->empty() && m.has_fact(res) && m.is_false(m.get_fact(res))) + { return res; } } + UNREACHABLE(); + return nullptr; +} - proof* hypothesis_reducer::mk_step_core(proof* old_step, ptr_buffer& args) +proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) +{ + SASSERT(m.is_false(m.get_fact(premise))); + + SASSERT(m_active_hyps.contains(premise)); + proof_set* active_hyps = m_active_hyps.find(premise); + + // if there is no active hypothesis return the premise + if (active_hyps->empty()) { - // if any of the literals is false, we don't need a step - for (unsigned i = 0; i < args.size(); ++i) + return premise; + } + // otherwise build disjunction of the negated active hypothesis' and add lemma step. + else + { + expr_ref_buffer args(m); + for (auto hyp : *active_hyps) { - if (m.is_false(m.get_fact(args[i]))) - { - return args[i]; - } + expr* hyp_fact = m.get_fact(hyp); + expr_ref negated_hyp_fact(m); + negated_hyp_fact = m.is_not(hyp_fact) ? to_app(hyp_fact)->get_arg(0) : m.mk_not(hyp_fact); + args.push_back(negated_hyp_fact); } - // otherwise build step - args.push_back(to_app(m.get_fact(old_step))); // BUG: I guess this doesn't work with quantifiers (since they are no apps) - - SASSERT(old_step->get_decl()->get_arity() == args.size()); - proof* res = m.mk_app(old_step->get_decl(), args.size(), (expr * const*)args.c_ptr()); + expr_ref lemma(m); + if (args.size() == 1) + { + lemma = args[0]; + } + else + { + lemma = m.mk_or(args.size(), args.c_ptr()); + } + proof_ref res(m); + res = m.mk_lemma(premise, lemma); m_pinned.push_back(res); return res; } +} + +proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) +{ + ptr_buffer pf_args; // the arguments of the transformed unit resolution step + pf_args.push_back(args [0]); // the first element of args is the clause to resolve with + + // if any literal is false, we don't need a unit resolution step + // could be the case due to transformations which already have been done + for (unsigned i = 1; i < args.size(); ++i) + { + if (m.is_false(m.get_fact(args[i]))) + { + return args[i]; + } + } + + app *cls_fact = to_app(m.get_fact(args[0])); // BUG: I guess this shouldn't work with quantifiers (since they are no apps) + ptr_buffer cls; + if (m.is_or(cls_fact)) { + for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) + { cls.push_back(cls_fact->get_arg(i)); } + } else { cls.push_back(cls_fact); } + + // construct new resolvent + ptr_buffer new_fact_cls; + bool found; + // XXX quadratic + for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { + found = false; + for (unsigned j = 1; j < args.size(); ++j) { + if (m.is_complement(cls.get(i), m.get_fact(args [j]))) { + found = true; + pf_args.push_back(args [j]); + break; + } + } + if (!found) { + new_fact_cls.push_back(cls.get(i)); + } + } + + SASSERT(new_fact_cls.size() + pf_args.size() - 1 == cls.size()); + expr_ref new_fact(m); + new_fact = mk_or(m, new_fact_cls.size(), new_fact_cls.c_ptr()); + + // create new proof step + if (pf_args.size() == 1) // the only premise is the clause itself + { + return args[0]; + } + else + { + proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); + m_pinned.push_back(res); + return res; + } +} + +proof* hypothesis_reducer::mk_step_core(proof* old_step, ptr_buffer& args) +{ + // if any of the literals is false, we don't need a step + for (unsigned i = 0; i < args.size(); ++i) + { + if (m.is_false(m.get_fact(args[i]))) + { + return args[i]; + } + } + + // otherwise build step + args.push_back(to_app(m.get_fact(old_step))); // BUG: I guess this doesn't work with quantifiers (since they are no apps) + + SASSERT(old_step->get_decl()->get_arity() == args.size()); + proof* res = m.mk_app(old_step->get_decl(), args.size(), (expr * const*)args.c_ptr()); + m_pinned.push_back(res); + return res; +} }; diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index e47c9882a..671fda783 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -22,67 +22,74 @@ Revision History: namespace spacer { - bool is_arith_lemma(ast_manager& m, proof* pr); - bool is_farkas_lemma(ast_manager& m, proof* pr); +bool is_arith_lemma(ast_manager& m, proof* pr); +bool is_farkas_lemma(ast_manager& m, proof* pr); - /* - * prints the proof pr in dot representation to the file proof.dot - * if iuc_pr is not nullptr, then it is queried for coloring partitions - */ - class iuc_proof; - void pp_proof_dot(ast_manager& m, proof* pr, iuc_proof* iuc_pr = nullptr); +class theory_axiom_reducer { +public: + theory_axiom_reducer(ast_manager& m) : m(m), m_pinned(m) {} - class theory_axiom_reducer - { - public: - theory_axiom_reducer(ast_manager& m) : m(m), m_pinned(m) {} + // reduce theory axioms and return transformed proof + proof_ref reduce(proof* pr); - // reduce theory axioms and return transformed proof - proof_ref reduce(proof* pr); +private: + ast_manager &m; - private: - ast_manager &m; + // tracking all created expressions + expr_ref_vector m_pinned; - // tracking all created expressions - expr_ref_vector m_pinned; + // maps each proof of a clause to the transformed subproof of + // that clause + obj_map m_cache; - // maps each proof of a clause to the transformed subproof of that clause - obj_map m_cache; + void reset(); +}; - void reset(); - }; +class hypothesis_reducer +{ +public: + hypothesis_reducer(ast_manager &m) : m(m), m_pinned(m) {} - class hypothesis_reducer - { - public: - hypothesis_reducer(ast_manager &m) : m(m), m_pinned(m) {} + // reduce hypothesis and return transformed proof + proof_ref reduce(proof* pf); - // reduce hypothesis and return transformed proof - proof_ref reduce(proof* pf); +private: + typedef obj_hashtable expr_set; + typedef obj_hashtable proof_set; - private: - typedef obj_hashtable expr_set; - typedef obj_hashtable proof_set; + ast_manager &m; - ast_manager &m; + // created expressions + expr_ref_vector m_pinned; - expr_ref_vector m_pinned; // tracking all created expressions - ptr_vector m_pinned_active_hyps; // tracking all created sets of active hypothesis - ptr_vector m_pinned_parent_hyps; // tracking all created sets of parent hypothesis + // created sets of active hypothesis + ptr_vector m_pinned_active_hyps; + // created sets of parent hypothesis + ptr_vector m_pinned_parent_hyps; - obj_map m_cache; // maps each proof of a clause to the transformed subproof of that clause - obj_map m_units; // maps each unit literal to the subproof of that unit - obj_map m_active_hyps; // maps each proof of a clause to the set of proofs of active hypothesis' of the clause - obj_map m_parent_hyps; // maps each proof of a clause to the hypothesis-fact, which are transitive parents of that clause, needed to avoid creating cycles in the proof. + // maps a proof to the transformed proof + obj_map m_cache; - void reset(); - void compute_hypsets(proof* pr); // compute active_hyps and parent_hyps for pr - void collect_units(proof* pr); // compute m_units - proof* compute_transformed_proof(proof* pf); + // maps a unit literal to its derivation + obj_map m_units; - proof* mk_lemma_core(proof *pf, expr *fact); - proof* mk_unit_resolution_core(ptr_buffer& args); - proof* mk_step_core(proof* old_step, ptr_buffer& args); - }; + // maps a proof to the set of proofs of active hypotheses + obj_map m_active_hyps; + // maps a proof to the hypothesis-fact that are transitive + // parents of that proof. Used for cycle detection and avoidance. + obj_map m_parent_hyps; + + void reset(); + + // compute active_hyps and parent_hyps for pr + void compute_hypsets(proof* pr); + // compute m_units + void collect_units(proof* pr); + proof* compute_transformed_proof(proof* pf); + + proof* mk_lemma_core(proof *pf, expr *fact); + proof* mk_unit_resolution_core(ptr_buffer& args); + proof* mk_step_core(proof* old_step, ptr_buffer& args); +}; } #endif From 2db38fedd6348d9edb28dc0bf1e6fbbf0e51feb3 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 May 2018 13:58:13 -0700 Subject: [PATCH 1002/1283] Cleanup of theory_axiom_reducer proof trasfomation --- src/muz/spacer/spacer_proof_utils.cpp | 116 ++++++++++++++------------ src/muz/spacer/spacer_proof_utils.h | 1 + 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 146436db9..749c3fbea 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -66,89 +66,96 @@ bool is_farkas_lemma(ast_manager& m, proof* pr) * ==================================== */ -void theory_axiom_reducer::reset() -{ +void theory_axiom_reducer::reset() { m_cache.reset(); m_pinned.reset(); } -proof_ref theory_axiom_reducer::reduce(proof* pr) -{ +// -- rewrite theory axioms into theory lemmas +proof_ref theory_axiom_reducer::reduce(proof* pr) { proof_post_order pit(pr, m); - while (pit.hasNext()) - { + while (pit.hasNext()) { proof* p = pit.next(); - if (m.get_num_parents(p) == 0 && is_arith_lemma(m, p)) - { + if (m.get_num_parents(p) == 0 && is_arith_lemma(m, p)) { // we have an arith-theory-axiom and want to get rid of it - // we need to replace the axiom with 1a) corresponding hypothesis', 1b) a theory lemma and a 1c) a lemma. Furthermore update datastructures - app *cls_fact = to_app(m.get_fact(p)); + // we need to replace the axiom with + // (a) corresponding hypothesis, + // (b) a theory lemma, and + // (c) a lemma. + // Furthermore update data-structures + app *fact = to_app(m.get_fact(p)); ptr_buffer cls; - if (m.is_or(cls_fact)) { - for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) - { cls.push_back(cls_fact->get_arg(i)); } - } else { cls.push_back(cls_fact); } + if (m.is_or(fact)) { + for (unsigned i = 0, sz = fact->get_num_args(); i < sz; ++i) + cls.push_back(fact->get_arg(i)); + } + else + cls.push_back(fact); - // 1a) create hypothesis' + // (a) create hypothesis ptr_buffer hyps; - for (unsigned i=0; i < cls.size(); ++i) - { - expr* hyp_fact = m.is_not(cls[i]) ? to_app(cls[i])->get_arg(0) : m.mk_not(cls[i]); + for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { + expr *c; + expr_ref hyp_fact(m); + if (m.is_not(cls[i], c)) + hyp_fact = c; + else + hyp_fact = m.mk_not (cls[i]); + proof* hyp = m.mk_hypothesis(hyp_fact); m_pinned.push_back(hyp); hyps.push_back(hyp); } - // 1b) create farkas lemma: need to rebuild parameters since mk_th_lemma adds tid as first parameter + // (b) create farkas lemma. Rebuild parameters since + // mk_th_lemma() adds tid as first parameter unsigned num_params = p->get_decl()->get_num_parameters(); parameter const* params = p->get_decl()->get_parameters(); vector parameters; - for (unsigned i = 1; i < num_params; ++i) { - parameters.push_back(params[i]); - } + for (unsigned i = 1; i < num_params; ++i) parameters.push_back(params[i]); SASSERT(params[0].is_symbol()); family_id tid = m.mk_family_id(params[0].get_symbol()); SASSERT(tid != null_family_id); - proof* th_lemma = m.mk_th_lemma(tid, m.mk_false(),hyps.size(), hyps.c_ptr(), num_params-1, parameters.c_ptr()); + proof* th_lemma = m.mk_th_lemma(tid, m.mk_false(), + hyps.size(), hyps.c_ptr(), + num_params-1, parameters.c_ptr()); + m_pinned.push_back(th_lemma); SASSERT(is_arith_lemma(m, th_lemma)); - // 1c) create lemma - proof* res = m.mk_lemma(th_lemma, cls_fact); - SASSERT(m.get_fact(res) == m.get_fact(p)); + // (c) create lemma + proof* res = m.mk_lemma(th_lemma, fact); m_pinned.push_back(res); m_cache.insert(p, res); + + SASSERT(m.get_fact(res) == m.get_fact(p)); } - else - { - bool dirty = false; // proof is dirty, if a subproof of one of its premises has been transformed + else { + // proof is dirty, if a subproof of one of its premises + // has been transformed + bool dirty = false; ptr_buffer args; - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) - { - proof* pp = m.get_parent(p, i); - proof* tmp; - if (m_cache.find(pp, tmp)) - { - args.push_back(tmp); - dirty = dirty || pp != tmp; - } - else - { - SASSERT(false); - } + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + proof *pp, *tmp; + pp = m.get_parent(p, i); + VERIFY(m_cache.find(pp, tmp)); + args.push_back(tmp); + dirty |= (pp != tmp); } - if (!dirty) // if not dirty just use the old step - { - m_cache.insert(p, p); - } - else // otherwise create new step with the corresponding proofs of the premises - { - if (m.has_fact(p)) { args.push_back(m.get_fact(p)); } + // if not dirty just use the old step + if (!dirty) m_cache.insert(p, p); + // otherwise create new proof with the corresponding proofs + // of the premises + else { + if (m.has_fact(p)) args.push_back(m.get_fact(p)); + SASSERT(p->get_decl()->get_arity() == args.size()); - proof* res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr()); + + proof* res = m.mk_app(p->get_decl(), + args.size(), (expr * const*)args.c_ptr()); m_pinned.push_back(res); m_cache.insert(p, res); } @@ -157,12 +164,13 @@ proof_ref theory_axiom_reducer::reduce(proof* pr) proof* res; VERIFY(m_cache.find(pr,res)); - DEBUG_CODE(proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(res, side)); + DEBUG_CODE( + proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(res, side)); ); - return proof_ref(res,m); + return proof_ref(res, m); } void hypothesis_reducer::reset() diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index 671fda783..c741ce19e 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -25,6 +25,7 @@ namespace spacer { bool is_arith_lemma(ast_manager& m, proof* pr); bool is_farkas_lemma(ast_manager& m, proof* pr); +/// rewrites theory axioms into theory lemmas class theory_axiom_reducer { public: theory_axiom_reducer(ast_manager& m) : m(m), m_pinned(m) {} From 8d312f9d1f78a70d77744921cef2476b934973cb Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 May 2018 16:25:49 -0700 Subject: [PATCH 1003/1283] Cleanup of hypothesis_reducer --- src/muz/spacer/spacer_proof_utils.cpp | 345 ++++++++++++-------------- src/muz/spacer/spacer_proof_utils.h | 4 +- 2 files changed, 160 insertions(+), 189 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 749c3fbea..42cdcf50b 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -133,7 +133,7 @@ proof_ref theory_axiom_reducer::reduce(proof* pr) { SASSERT(m.get_fact(res) == m.get_fact(p)); } else { - // proof is dirty, if a subproof of one of its premises + // proof is dirty, if a sub-proof of one of its premises // has been transformed bool dirty = false; @@ -173,85 +173,67 @@ proof_ref theory_axiom_reducer::reduce(proof* pr) { return proof_ref(res, m); } -void hypothesis_reducer::reset() -{ +void hypothesis_reducer::reset() { m_cache.reset(); m_units.reset(); m_active_hyps.reset(); m_parent_hyps.reset(); + for (auto t : m_pinned_active_hyps) dealloc(t); m_pinned_active_hyps.reset(); + for (auto t : m_pinned_parent_hyps) dealloc(t); m_pinned_parent_hyps.reset(); - m_pinned.reset(); } -void hypothesis_reducer::compute_hypsets(proof* pr) -{ +void hypothesis_reducer::compute_hypsets(proof *pr) { ptr_vector todo; todo.push_back(pr); - while (!todo.empty()) - { + while (!todo.empty()) { proof* p = todo.back(); - if (m_active_hyps.contains(p)) - { + if (m_active_hyps.contains(p)) { SASSERT(m_parent_hyps.contains(p)); todo.pop_back(); + continue; } - // if we haven't already visited the current unit - else - { - bool existsUnvisitedParent = false; - // add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result - // for p now, but wait until those unprocessed premises are processed. - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - SASSERT(m.is_proof(p->get_arg(i))); - proof* premise = to_app(p->get_arg(i)); + bool dirty = false; + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + SASSERT(m.is_proof(p->get_arg(i))); + proof *parent = to_app(p->get_arg(i)); - // if we haven't visited the premise yet - if (!m_active_hyps.contains(premise)) - { - SASSERT(!m_parent_hyps.contains(premise)); - // add it to the stack - todo.push_back(premise); - existsUnvisitedParent = true; - } + if (!m_active_hyps.contains(parent)) { + SASSERT(!m_parent_hyps.contains(parent)); + todo.push_back(parent); + dirty = true; } + } + if (dirty) continue; - // if we already visited all premises, we can visit p too - if (!existsUnvisitedParent) - { - todo.pop_back(); + todo.pop_back(); - // create active_hyps-set and parent_hyps-set for step p - proof_set* active_hyps = alloc(proof_set); - m_pinned_active_hyps.insert(active_hyps); - m_active_hyps.insert(p, active_hyps); + // create active_hyps-set and parent_hyps-set for step p + proof_set* active_hyps = alloc(proof_set); + m_pinned_active_hyps.insert(active_hyps); + m_active_hyps.insert(p, active_hyps); - expr_set* parent_hyps = alloc(expr_set); - m_pinned_parent_hyps.insert(parent_hyps); - m_parent_hyps.insert(p, parent_hyps); + expr_set* parent_hyps = alloc(expr_set); + m_pinned_parent_hyps.insert(parent_hyps); + m_parent_hyps.insert(p, parent_hyps); - // fill both sets - if (m.is_hypothesis(p)) - { - active_hyps->insert(p); - parent_hyps->insert(m.get_fact(p)); - } - else - { - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) - { - proof* pp = m.get_parent(p, i); - set_union(*parent_hyps, *m_parent_hyps.find(pp)); + // fill both sets + if (m.is_hypothesis(p)) { + active_hyps->insert(p); + parent_hyps->insert(m.get_fact(p)); + } + else { + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + proof* parent = m.get_parent(p, i); + set_union(*parent_hyps, *m_parent_hyps.find(parent)); - if (!m.is_lemma(p)) // lemmas clear all hypotheses - { - set_union(*active_hyps, *m_active_hyps.find(pp)); - } - } - } + if (!m.is_lemma(p)) + // lemmas clear all hypotheses + set_union(*active_hyps, *m_active_hyps.find(parent)); } } } @@ -259,48 +241,41 @@ void hypothesis_reducer::compute_hypsets(proof* pr) // collect all units that are hyp-free and are used as hypotheses somewhere // requires that m_active_hyps and m_parent_hyps have been computed -void hypothesis_reducer::collect_units(proof* pr) -{ +void hypothesis_reducer::collect_units(proof* pr) { expr_set* all_hyps = m_parent_hyps.find(pr); - SASSERT(all_hyps != nullptr); + SASSERT(all_hyps); proof_post_order pit(pr, m); while (pit.hasNext()) { proof* p = pit.next(); - if (!m.is_hypothesis(p)) - { + if (!m.is_hypothesis(p)) { proof_set* active_hyps = m_active_hyps.find(p); - SASSERT(active_hyps != nullptr); + SASSERT(active_hyps); - // collect units that are hyp-free and are used as hypotheses in the proof pr - if (active_hyps->empty() && m.has_fact(p) && all_hyps->contains(m.get_fact(p))) - { + // collect units that are hyp-free and are used as + // hypotheses in the proof pr + if (active_hyps->empty() && m.has_fact(p) && + all_hyps->contains(m.get_fact(p))) m_units.insert(m.get_fact(p), p); - } } } } -proof_ref hypothesis_reducer::reduce(proof* pr) -{ +proof_ref hypothesis_reducer::reduce(proof* pr) { compute_hypsets(pr); collect_units(pr); - proof* res = compute_transformed_proof(pr); - SASSERT(res != nullptr); - - proof_ref res_ref(res,m); - + proof_ref res(compute_transformed_proof(pr), m); + SASSERT(res); reset(); + DEBUG_CODE(proof_checker pc(m); expr_ref_vector side(m); - SASSERT(pc.check(res, side)); - ); - return res_ref; + SASSERT(pc.check(res, side));); + return res; } -proof* hypothesis_reducer::compute_transformed_proof(proof* pf) -{ +proof* hypothesis_reducer::compute_transformed_proof(proof* pf) { proof *res = NULL; ptr_vector todo; @@ -325,204 +300,198 @@ proof* hypothesis_reducer::compute_transformed_proof(proof* pf) pp = m.get_parent(p, i); if (m_cache.find(pp, tmp)) { args.push_back(tmp); - dirty = dirty || pp != tmp; + dirty |= pp != tmp; } else { todo.push_back(pp); } } - if (todo_sz < todo.size()) { continue; } - else { todo.pop_back(); } + if (todo_sz < todo.size()) continue; + todo.pop_back(); - // here the proof transformation begins - // INV: whenever we visit p, active_hyps and parent_hyps have been computed for the args. - if (m.is_hypothesis(p)) - { + // transform the proof + + // INV: whenever p is visited, active_hyps and parent_hyps + // have already been computed for everything in args. + if (m.is_hypothesis(p)) { // hyp: replace by a corresponding unit - if (m_units.find(m.get_fact(p), tmp)) - { + if (m_units.find(m.get_fact(p), tmp)) { // look up the proof of the unit: // if there is a transformed proof use that one // otherwise use the original proof proof* proof_of_unit; - if (!m_cache.find(tmp,proof_of_unit)) - { + if (!m_cache.find(tmp, proof_of_unit)) { proof_of_unit = tmp; } - // compute hypsets (have not been computed in general, since the unit can be anywhere in the proof) + // compute hypsets (have not been computed in general, + // since the unit can be anywhere in the proof) compute_hypsets(proof_of_unit); // if the transformation doesn't create a cycle, perform it SASSERT(m_parent_hyps.contains(proof_of_unit)); expr_set* parent_hyps = m_parent_hyps.find(proof_of_unit); if (!parent_hyps->contains(p)) - { - res = proof_of_unit; // hypsets have already been computed for proof_of_unit - } - // otherwise don't transform the proof and just use the hypothesis + res = proof_of_unit; + // otherwise don't transform the proof and just use + // the hypothesis else - { - res = p; // hypsets have already been computed for p - } + res = p; } else - { - res = p; // hypsets have already been computed for p - } + res = p; } - else if (!dirty) { res = p; } - - else if (m.is_lemma(p)) - { - //lemma: reduce the premise; remove reduced consequences from conclusion + else if (!dirty) + res = p; + else if (m.is_lemma(p)) { + //lemma: reduce the premise; remove reduced consequences + //from conclusion SASSERT(args.size() == 1); res = mk_lemma_core(args[0], m.get_fact(p)); compute_hypsets(res); } - else if (m.is_unit_resolution(p)) - { - // unit: reduce untis; reduce the first premise; rebuild unit resolution + else if (m.is_unit_resolution(p)) { + // unit: reduce untis; reduce the first premise; rebuild + // unit resolution res = mk_unit_resolution_core(args); compute_hypsets(res); } - else - { - res = mk_step_core(p, args); + else { + res = mk_proof_core(p, args); compute_hypsets(res); } SASSERT(res); m_cache.insert(p, res); + // bail out as soon as found a sub-proof of false SASSERT(m_active_hyps.contains(res)); proof_set* active_hyps = m_active_hyps.find(res); if (active_hyps->empty() && m.has_fact(res) && m.is_false(m.get_fact(res))) - { return res; - } } UNREACHABLE(); return nullptr; } -proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) -{ +proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { SASSERT(m.is_false(m.get_fact(premise))); - SASSERT(m_active_hyps.contains(premise)); + proof_set* active_hyps = m_active_hyps.find(premise); // if there is no active hypothesis return the premise - if (active_hyps->empty()) - { + if (active_hyps->empty()) { + // XXX just in case premise might go away + m_pinned.push_back(premise); return premise; } - // otherwise build disjunction of the negated active hypothesis' and add lemma step. - else - { - expr_ref_buffer args(m); - for (auto hyp : *active_hyps) - { - expr* hyp_fact = m.get_fact(hyp); - expr_ref negated_hyp_fact(m); - negated_hyp_fact = m.is_not(hyp_fact) ? to_app(hyp_fact)->get_arg(0) : m.mk_not(hyp_fact); - args.push_back(negated_hyp_fact); - } - expr_ref lemma(m); - if (args.size() == 1) - { - lemma = args[0]; - } + // otherwise, build a disjunction of the negated active hypotheses + // and add a lemma proof step + expr_ref_buffer args(m); + for (auto hyp : *active_hyps) { + expr *hyp_fact, *t; + hyp_fact = m.get_fact(hyp); + if (m.is_not(hyp_fact, t)) + args.push_back(t); else - { - lemma = m.mk_or(args.size(), args.c_ptr()); - } - proof_ref res(m); - res = m.mk_lemma(premise, lemma); - m_pinned.push_back(res); - return res; + args.push_back(m.mk_not(hyp_fact)); } + + expr_ref lemma(m); + lemma = mk_or(m, args.size(), args.c_ptr()); + + proof* res; + res = m.mk_lemma(premise, lemma); + m_pinned.push_back(res); + return res; } -proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) -{ - ptr_buffer pf_args; // the arguments of the transformed unit resolution step - pf_args.push_back(args [0]); // the first element of args is the clause to resolve with - +proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) { // if any literal is false, we don't need a unit resolution step - // could be the case due to transformations which already have been done - for (unsigned i = 1; i < args.size(); ++i) - { - if (m.is_false(m.get_fact(args[i]))) - { + // This can be the case due to some previous transformations + for (unsigned i = 1, sz = args.size(); i < sz; ++i) { + if (m.is_false(m.get_fact(args[i]))) { + // XXX just in case + m_pinned.push_back(args[i]); return args[i]; } } - app *cls_fact = to_app(m.get_fact(args[0])); // BUG: I guess this shouldn't work with quantifiers (since they are no apps) - ptr_buffer cls; - if (m.is_or(cls_fact)) { - for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i) - { cls.push_back(cls_fact->get_arg(i)); } - } else { cls.push_back(cls_fact); } + proof* arg0 = args[0]; + ptr_buffer pf_args; + pf_args.push_back(arg0); - // construct new resolvent - ptr_buffer new_fact_cls; + // BUG: I guess this shouldn't work with quantifiers (since they + // are not apps) + // AG: who is "I"? What is the bug? + app *fact = to_app(m.get_fact(arg0)); + ptr_buffer cls; + if (m.is_or(fact)) { + for (unsigned i = 0, sz = fact->get_num_args(); i < sz; ++i) + cls.push_back(fact->get_arg(i)); + } + else + cls.push_back(fact); + + // construct the new resolvent + ptr_buffer new_fact; bool found; - // XXX quadratic + + // -- find all literals that are resolved on + // XXX quadratic implementation for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { found = false; for (unsigned j = 1; j < args.size(); ++j) { - if (m.is_complement(cls.get(i), m.get_fact(args [j]))) { + if (m.is_complement(cls.get(i), m.get_fact(args[j]))) { found = true; - pf_args.push_back(args [j]); + pf_args.push_back(args[j]); break; } } - if (!found) { - new_fact_cls.push_back(cls.get(i)); - } + if (!found) new_fact.push_back(cls.get(i)); } - SASSERT(new_fact_cls.size() + pf_args.size() - 1 == cls.size()); - expr_ref new_fact(m); - new_fact = mk_or(m, new_fact_cls.size(), new_fact_cls.c_ptr()); + SASSERT(new_fact.size() + pf_args.size() - 1 == cls.size()); - // create new proof step - if (pf_args.size() == 1) // the only premise is the clause itself - { - return args[0]; - } - else - { - proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact); - m_pinned.push_back(res); - return res; + // unit resolution got reduced to noop + if (pf_args.size() == 1) { + // XXX just in case + m_pinned.push_back(arg0); + return arg0; } + + // make unit resolution proof step + expr_ref tmp(m); + tmp = mk_or(m, new_fact.size(), new_fact.c_ptr()); + proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), tmp); + m_pinned.push_back(res); + return res; } -proof* hypothesis_reducer::mk_step_core(proof* old_step, ptr_buffer& args) -{ - // if any of the literals is false, we don't need a step - for (unsigned i = 0; i < args.size(); ++i) - { - if (m.is_false(m.get_fact(args[i]))) - { +proof* hypothesis_reducer::mk_proof_core(proof* old, ptr_buffer& args) { + // if any of the literals are false, we don't need a step + for (unsigned i = 0; i < args.size(); ++i) { + if (m.is_false(m.get_fact(args[i]))) { + // XXX just in case + m_pinned.push_back(args[i]); return args[i]; } } // otherwise build step - args.push_back(to_app(m.get_fact(old_step))); // BUG: I guess this doesn't work with quantifiers (since they are no apps) + // BUG: I guess this doesn't work with quantifiers (since they are no apps) + args.push_back(to_app(m.get_fact(old))); - SASSERT(old_step->get_decl()->get_arity() == args.size()); - proof* res = m.mk_app(old_step->get_decl(), args.size(), (expr * const*)args.c_ptr()); + SASSERT(old->get_decl()->get_arity() == args.size()); + + proof* res = m.mk_app(old->get_decl(), args.size(), + (expr * const*)args.c_ptr()); m_pinned.push_back(res); return res; } diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index c741ce19e..f348e71a6 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -46,10 +46,12 @@ private: void reset(); }; +/// reduces the number of hypotheses in a proof class hypothesis_reducer { public: hypothesis_reducer(ast_manager &m) : m(m), m_pinned(m) {} + ~hypothesis_reducer() {reset();} // reduce hypothesis and return transformed proof proof_ref reduce(proof* pf); @@ -90,7 +92,7 @@ private: proof* mk_lemma_core(proof *pf, expr *fact); proof* mk_unit_resolution_core(ptr_buffer& args); - proof* mk_step_core(proof* old_step, ptr_buffer& args); + proof* mk_proof_core(proof* old, ptr_buffer& args); }; } #endif From ecf15ab07d006d213f8754fd5aeb8dd2e7ac7bc8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 May 2018 16:42:51 -0700 Subject: [PATCH 1004/1283] add model_evaluator_util features to model_evalautor Signed-off-by: Nikolaj Bjorner --- src/model/model_evaluator.cpp | 43 +++++++++++++++++++++++++++++++++++ src/model/model_evaluator.h | 10 +++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 0b25a250b..07ee125f8 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -562,6 +562,12 @@ void model_evaluator::reset(params_ref const & p) { updt_params(p); } +void model_evaluator::reset(model_core &model, params_ref const& p) { + dealloc(m_imp); + m_imp = alloc(imp, model, p); +} + + void model_evaluator::operator()(expr * t, expr_ref & result) { TRACE("model_evaluator", tout << mk_ismt2_pp(t, m()) << "\n";); m_imp->operator()(t, result); @@ -574,3 +580,40 @@ expr_ref model_evaluator::operator()(expr * t) { this->operator()(t, result); return result; } + +bool model_evaluator::is_true(expr* t) { + expr_ref tmp(m()); + return eval(t, tmp, true) && m().is_true(tmp); +} + +bool model_evaluator::is_false(expr* t) { + expr_ref tmp(m()); + return eval(t, tmp, true) && m().is_false(tmp); +} + +bool model_evaluator::is_true(expr_ref_vector const& ts) { + for (expr* t : ts) if (!is_true(t)) return false; + return true; +} + +bool model_evaluator::eval(expr* t, expr_ref& r, bool model_completion) { + set_model_completion(model_completion); + try { + r = (*this)(t); + return true; + } + catch (model_evaluator_exception &ex) { + (void)ex; + TRACE("model_evaluator", tout << ex.msg () << "\n";); + return false; + } +} + +bool model_evaluator::eval(expr_ref_vector const& ts, expr_ref& r, bool model_completion) { + expr_ref tmp(m()); + tmp = mk_and(ts); + return eval(tmp, r, model_completion); +} + + + diff --git a/src/model/model_evaluator.h b/src/model/model_evaluator.h index bd2b2d664..6ae7d8891 100644 --- a/src/model/model_evaluator.h +++ b/src/model/model_evaluator.h @@ -43,11 +43,19 @@ public: static void get_param_descrs(param_descrs & r); void operator()(expr * t, expr_ref & r); - expr_ref operator()(expr* t); + // exception safe + bool eval(expr* t, expr_ref& r, bool model_completion = true); + bool eval(expr_ref_vector const& ts, expr_ref& r, bool model_completion = true); + + bool is_true(expr * t); + bool is_false(expr * t); + bool is_true(expr_ref_vector const& ts); + void cleanup(params_ref const & p = params_ref()); void reset(params_ref const & p = params_ref()); + void reset(model_core& model, params_ref const & p = params_ref()); unsigned get_num_steps() const; }; From ff0f2571025cf590658fa136e71e9442e0a74cc1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 May 2018 18:35:38 -0700 Subject: [PATCH 1005/1283] remove iff Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 3 +- src/ast/ast.cpp | 24 +-- src/ast/ast.h | 19 +- src/ast/ast_smt2_pp.cpp | 4 - src/ast/ast_smt_pp.cpp | 3 - src/ast/macro_substitution.cpp | 4 +- src/ast/macros/macro_manager.cpp | 5 +- src/ast/macros/macro_util.cpp | 9 +- src/ast/macros/quasi_macros.cpp | 2 +- src/ast/normal_forms/nnf.cpp | 5 +- src/ast/proofs/proof_checker.cpp | 6 +- src/ast/proofs/proof_utils.h | 4 +- src/ast/rewriter/bool_rewriter.cpp | 5 +- src/ast/rewriter/bool_rewriter.h | 2 +- src/ast/rewriter/der.cpp | 11 +- src/ast/rewriter/quant_hoist.cpp | 2 +- src/ast/rewriter/th_rewriter.cpp | 2 +- src/ast/static_features.cpp | 8 +- src/model/model_implicant.cpp | 5 - src/muz/base/rule_properties.cpp | 6 +- src/muz/pdr/pdr_context.cpp | 2 +- src/muz/rel/udoc_relation.cpp | 2 +- src/muz/spacer/spacer_legacy_mev.cpp | 5 - src/muz/spacer/spacer_util.cpp | 192 ++++++++---------- src/muz/transforms/dl_mk_array_blast.cpp | 2 +- .../dl_mk_quantifier_instantiation.cpp | 2 +- src/nlsat/tactic/goal2nlsat.cpp | 1 - src/parsers/util/cost_parser.cpp | 2 +- src/qe/qe.cpp | 2 +- src/qe/qe_lite.cpp | 2 +- src/sat/tactic/atom2bool_var.cpp | 2 +- src/sat/tactic/goal2sat.cpp | 2 - src/smt/asserted_formulas.cpp | 7 +- src/smt/cost_evaluator.cpp | 3 +- src/smt/expr_context_simplifier.cpp | 18 +- src/smt/smt_checker.cpp | 28 +-- src/smt/smt_conflict_resolution.cpp | 4 +- src/smt/smt_internalizer.cpp | 16 +- src/smt/smt_model_finder.cpp | 3 - src/smt/smt_quantifier_stat.cpp | 12 +- src/smt/smt_quick_checker.cpp | 12 +- src/tactic/aig/aig.cpp | 4 - src/tactic/core/cofactor_elim_term_ite.cpp | 1 - src/tactic/core/dom_simplify_tactic.cpp | 2 +- src/tactic/core/elim_uncnstr_tactic.cpp | 1 - src/tactic/core/solve_eqs_tactic.cpp | 5 +- src/tactic/core/tseitin_cnf_tactic.cpp | 2 - 47 files changed, 199 insertions(+), 264 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 536b94fb2..34168f1f4 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -190,7 +190,7 @@ extern "C" { MK_UNARY(Z3_mk_not, mk_c(c)->get_basic_fid(), OP_NOT, SKIP); MK_BINARY(Z3_mk_eq, mk_c(c)->get_basic_fid(), OP_EQ, SKIP); MK_NARY(Z3_mk_distinct, mk_c(c)->get_basic_fid(), OP_DISTINCT, SKIP); - MK_BINARY(Z3_mk_iff, mk_c(c)->get_basic_fid(), OP_IFF, SKIP); + MK_BINARY(Z3_mk_iff, mk_c(c)->get_basic_fid(), OP_EQ, SKIP); MK_BINARY(Z3_mk_implies, mk_c(c)->get_basic_fid(), OP_IMPLIES, SKIP); MK_BINARY(Z3_mk_xor, mk_c(c)->get_basic_fid(), OP_XOR, SKIP); MK_NARY(Z3_mk_and, mk_c(c)->get_basic_fid(), OP_AND, SKIP); @@ -894,7 +894,6 @@ extern "C" { case OP_ITE: return Z3_OP_ITE; case OP_AND: return Z3_OP_AND; case OP_OR: return Z3_OP_OR; - case OP_IFF: return Z3_OP_IFF; case OP_XOR: return Z3_OP_XOR; case OP_NOT: return Z3_OP_NOT; case OP_IMPLIES: return Z3_OP_IMPLIES; diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index cae1618c0..681f64a25 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -643,7 +643,6 @@ basic_decl_plugin::basic_decl_plugin(): m_false_decl(nullptr), m_and_decl(nullptr), m_or_decl(nullptr), - m_iff_decl(nullptr), m_xor_decl(nullptr), m_not_decl(nullptr), m_implies_decl(nullptr), @@ -861,7 +860,6 @@ void basic_decl_plugin::set_manager(ast_manager * m, family_id id) { m_false_decl = mk_bool_op_decl("false", OP_FALSE); m_and_decl = mk_bool_op_decl("and", OP_AND, 2, true, true, true, true); m_or_decl = mk_bool_op_decl("or", OP_OR, 2, true, true, true, true); - m_iff_decl = mk_bool_op_decl("iff", OP_IFF, 2, false, true, false, false, true); m_xor_decl = mk_bool_op_decl("xor", OP_XOR, 2, true, true); m_not_decl = mk_bool_op_decl("not", OP_NOT, 1); m_implies_decl = mk_implies_decl(); @@ -892,13 +890,13 @@ void basic_decl_plugin::get_op_names(svector & op_names, symbol co if (logic == symbol::null) { // user friendly aliases op_names.push_back(builtin_name("implies", OP_IMPLIES)); - op_names.push_back(builtin_name("iff", OP_IFF)); + op_names.push_back(builtin_name("iff", OP_EQ)); op_names.push_back(builtin_name("if_then_else", OP_ITE)); op_names.push_back(builtin_name("if", OP_ITE)); op_names.push_back(builtin_name("&&", OP_AND)); op_names.push_back(builtin_name("||", OP_OR)); op_names.push_back(builtin_name("equals", OP_EQ)); - op_names.push_back(builtin_name("equiv", OP_IFF)); + op_names.push_back(builtin_name("equiv", OP_EQ)); } } @@ -919,7 +917,6 @@ void basic_decl_plugin::finalize() { DEC_REF(m_and_decl); DEC_REF(m_or_decl); DEC_REF(m_not_decl); - DEC_REF(m_iff_decl); DEC_REF(m_xor_decl); DEC_REF(m_implies_decl); DEC_ARRAY_REF(m_eq_decls); @@ -1051,7 +1048,6 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_AND: return m_and_decl; case OP_OR: return m_or_decl; case OP_NOT: return m_not_decl; - case OP_IFF: return m_iff_decl; case OP_IMPLIES: return m_implies_decl; case OP_XOR: return m_xor_decl; case OP_ITE: return arity == 3 ? mk_ite_decl(join(domain[1], domain[2])) : nullptr; @@ -1093,7 +1089,6 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_AND: return m_and_decl; case OP_OR: return m_or_decl; case OP_NOT: return m_not_decl; - case OP_IFF: return m_iff_decl; case OP_IMPLIES: return m_implies_decl; case OP_XOR: return m_xor_decl; case OP_ITE: return num_args == 3 ? mk_ite_decl(join(m_manager->get_sort(args[1]), m_manager->get_sort(args[2]))): nullptr; @@ -2636,10 +2631,10 @@ proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) { if (!p1 || !p2) return nullptr; SASSERT(has_fact(p1)); SASSERT(has_fact(p2)); - CTRACE("mk_modus_ponens", !(is_implies(get_fact(p2)) || is_iff(get_fact(p2)) || is_oeq(get_fact(p2))), + CTRACE("mk_modus_ponens", !(is_implies(get_fact(p2)) || is_eq(get_fact(p2)) || is_oeq(get_fact(p2))), tout << mk_ll_pp(p1, *this) << "\n"; tout << mk_ll_pp(p2, *this) << "\n";); - SASSERT(is_implies(get_fact(p2)) || is_iff(get_fact(p2)) || is_oeq(get_fact(p2))); + SASSERT(is_implies(get_fact(p2)) || is_eq(get_fact(p2)) || is_oeq(get_fact(p2))); CTRACE("mk_modus_ponens", to_app(get_fact(p2))->get_arg(0) != get_fact(p1), tout << mk_pp(get_fact(p1), *this) << "\n" << mk_pp(get_fact(p2), *this) << "\n";); SASSERT(to_app(get_fact(p2))->get_arg(0) == get_fact(p1)); @@ -2717,8 +2712,6 @@ proof * ast_manager::mk_transitivity(proof * p1, proof * p2) { tout << mk_pp(to_app(get_fact(p1))->get_decl(), *this) << "\n"; tout << mk_pp(to_app(get_fact(p2))->get_decl(), *this) << "\n";); SASSERT(to_app(get_fact(p1))->get_decl() == to_app(get_fact(p2))->get_decl() || - ((is_iff(get_fact(p1)) || is_eq(get_fact(p1))) && - (is_iff(get_fact(p2)) || is_eq(get_fact(p2)))) || ( (is_eq(get_fact(p1)) || is_oeq(get_fact(p1))) && (is_eq(get_fact(p2)) || is_oeq(get_fact(p2))))); CTRACE("mk_transitivity", to_app(get_fact(p1))->get_arg(1) != to_app(get_fact(p2))->get_arg(0), @@ -2797,7 +2790,7 @@ proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) if (!p) return nullptr; SASSERT(q1->get_num_decls() == q2->get_num_decls()); SASSERT(has_fact(p)); - SASSERT(is_iff(get_fact(p))); + SASSERT(is_eq(get_fact(p))); return mk_app(m_basic_family_id, PR_QUANT_INTRO, p, mk_iff(q1, q2)); } @@ -2884,8 +2877,7 @@ bool ast_manager::is_quant_inst(expr const* e, expr*& not_q_or_i, ptr_vectorget_arg(0), r1, r2) || - is_iff(to_app(e)->get_arg(0), r1, r2)); + VERIFY (is_eq(to_app(e)->get_arg(0), r1, r2)); return true; } else { @@ -2913,7 +2905,7 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro fact = mk_false(); } else { - CTRACE("mk_unit_resolution_bug", !is_or(f1), tout << mk_pp(f1, *this) << " " << mk_pp(f2, *this) << "\n";); + CTRACE("mk_unit_resolution_bug", !is_or(f1), tout << mk_ll_pp(f1, *this) << "\n" << mk_ll_pp(f2, *this) << "\n";); SASSERT(is_or(f1)); ptr_buffer new_lits; app const * cls = to_app(f1); @@ -3044,7 +3036,7 @@ proof * ast_manager::mk_iff_oeq(proof * p) { if (!p) return p; SASSERT(has_fact(p)); - SASSERT(is_iff(get_fact(p)) || is_oeq(get_fact(p))); + SASSERT(is_eq(get_fact(p)) || is_oeq(get_fact(p))); if (is_oeq(get_fact(p))) return p; diff --git a/src/ast/ast.h b/src/ast/ast.h index e85f164e1..ce193e8b1 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1041,7 +1041,7 @@ enum basic_sort_kind { }; enum basic_op_kind { - OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_IFF, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, LAST_BASIC_OP, + OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, LAST_BASIC_OP, PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO, PR_DISTRIBUTIVITY, PR_AND_ELIM, PR_NOT_OR_ELIM, PR_REWRITE, PR_REWRITE_STAR, PR_PULL_QUANT, @@ -1060,7 +1060,6 @@ protected: func_decl * m_false_decl; func_decl * m_and_decl; func_decl * m_or_decl; - func_decl * m_iff_decl; func_decl * m_xor_decl; func_decl * m_not_decl; func_decl * m_implies_decl; @@ -1344,9 +1343,9 @@ public: bool is_and(expr const * n) const { return is_app_of(n, m_fid, OP_AND); } bool is_not(expr const * n) const { return is_app_of(n, m_fid, OP_NOT); } bool is_eq(expr const * n) const { return is_app_of(n, m_fid, OP_EQ); } + bool is_iff(expr const* n) const { return is_eq(n) && is_bool(to_app(n)->get_arg(0)); } bool is_oeq(expr const * n) const { return is_app_of(n, m_fid, OP_OEQ); } bool is_distinct(expr const * n) const { return is_app_of(n, m_fid, OP_DISTINCT); } - bool is_iff(expr const * n) const { return is_app_of(n, m_fid, OP_IFF); } bool is_xor(expr const * n) const { return is_app_of(n, m_fid, OP_XOR); } bool is_ite(expr const * n) const { return is_app_of(n, m_fid, OP_ITE); } bool is_term_ite(expr const * n) const { return is_ite(n) && !is_bool(n); } @@ -1361,7 +1360,6 @@ public: bool is_and(func_decl const * d) const { return is_decl_of(d, m_fid, OP_AND); } bool is_not(func_decl const * d) const { return is_decl_of(d, m_fid, OP_NOT); } bool is_eq(func_decl const * d) const { return is_decl_of(d, m_fid, OP_EQ); } - bool is_iff(func_decl const * d) const { return is_decl_of(d, m_fid, OP_IFF); } bool is_xor(func_decl const * d) const { return is_decl_of(d, m_fid, OP_XOR); } bool is_ite(func_decl const * d) const { return is_decl_of(d, m_fid, OP_ITE); } bool is_term_ite(func_decl const * d) const { return is_ite(d) && !is_bool(d->get_range()); } @@ -1369,13 +1367,13 @@ public: MATCH_UNARY(is_not); MATCH_BINARY(is_eq); - MATCH_BINARY(is_iff); MATCH_BINARY(is_implies); MATCH_BINARY(is_and); MATCH_BINARY(is_or); MATCH_BINARY(is_xor); MATCH_TERNARY(is_and); MATCH_TERNARY(is_or); + bool is_iff(expr const* n, expr*& lhs, expr*& rhs) const { return is_eq(n, lhs, rhs) && is_bool(lhs); } bool is_ite(expr const * n, expr * & t1, expr * & t2, expr * & t3) const; }; @@ -1663,7 +1661,7 @@ public: bool is_bool(expr const * n) const; bool is_bool(sort const * s) const { return s == m_bool_sort; } - decl_kind get_eq_op(expr const * n) const { return is_bool(n) ? OP_IFF : OP_EQ; } + decl_kind get_eq_op(expr const * n) const { return OP_EQ; } private: sort * mk_sort(symbol const & name, sort_info * info); @@ -1987,9 +1985,9 @@ public: bool is_and(expr const * n) const { return is_app_of(n, m_basic_family_id, OP_AND); } bool is_not(expr const * n) const { return is_app_of(n, m_basic_family_id, OP_NOT); } bool is_eq(expr const * n) const { return is_app_of(n, m_basic_family_id, OP_EQ); } + bool is_iff(expr const * n) const { return is_eq(n) && is_bool(to_app(n)->get_arg(0)); } bool is_oeq(expr const * n) const { return is_app_of(n, m_basic_family_id, OP_OEQ); } bool is_distinct(expr const * n) const { return is_app_of(n, m_basic_family_id, OP_DISTINCT); } - bool is_iff(expr const * n) const { return is_app_of(n, m_basic_family_id, OP_IFF); } bool is_xor(expr const * n) const { return is_app_of(n, m_basic_family_id, OP_XOR); } bool is_ite(expr const * n) const { return is_app_of(n, m_basic_family_id, OP_ITE); } bool is_term_ite(expr const * n) const { return is_ite(n) && !is_bool(n); } @@ -2005,7 +2003,7 @@ public: bool is_and(func_decl const * d) const { return is_decl_of(d, m_basic_family_id, OP_AND); } bool is_not(func_decl const * d) const { return is_decl_of(d, m_basic_family_id, OP_NOT); } bool is_eq(func_decl const * d) const { return is_decl_of(d, m_basic_family_id, OP_EQ); } - bool is_iff(func_decl const * d) const { return is_decl_of(d, m_basic_family_id, OP_IFF); } + bool is_iff(func_decl const * d) const { return is_decl_of(d, m_basic_family_id, OP_EQ) && is_bool(d->get_range()); } bool is_xor(func_decl const * d) const { return is_decl_of(d, m_basic_family_id, OP_XOR); } bool is_ite(func_decl const * d) const { return is_decl_of(d, m_basic_family_id, OP_ITE); } bool is_term_ite(func_decl const * d) const { return is_ite(d) && !is_bool(d->get_range()); } @@ -2015,7 +2013,6 @@ public: MATCH_UNARY(is_not); MATCH_BINARY(is_eq); - MATCH_BINARY(is_iff); MATCH_BINARY(is_implies); MATCH_BINARY(is_and); MATCH_BINARY(is_or); @@ -2023,6 +2020,8 @@ public: MATCH_TERNARY(is_and); MATCH_TERNARY(is_or); + bool is_iff(expr const* n, expr*& lhs, expr*& rhs) const { return is_eq(n, lhs, rhs) && is_bool(lhs); } + bool is_ite(expr const* n, expr*& t1, expr*& t2, expr*& t3) const { if (is_ite(n)) { t1 = to_app(n)->get_arg(0); @@ -2035,7 +2034,7 @@ public: public: app * mk_eq(expr * lhs, expr * rhs) { return mk_app(m_basic_family_id, get_eq_op(lhs), lhs, rhs); } - app * mk_iff(expr * lhs, expr * rhs) { return mk_app(m_basic_family_id, OP_IFF, lhs, rhs); } + app * mk_iff(expr * lhs, expr * rhs) { return mk_app(m_basic_family_id, OP_EQ, lhs, rhs); } app * mk_oeq(expr * lhs, expr * rhs) { return mk_app(m_basic_family_id, OP_OEQ, lhs, rhs); } app * mk_xor(expr * lhs, expr * rhs) { return mk_app(m_basic_family_id, OP_XOR, lhs, rhs); } app * mk_ite(expr * c, expr * t, expr * e) { return mk_app(m_basic_family_id, OP_ITE, c, t, e); } diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index a2958e3c9..9d27ffb24 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -63,10 +63,6 @@ format * smt2_pp_environment::pp_fdecl_name(func_decl * f, unsigned & len) const len = 3; return mk_string(m, "ite"); } - else if (m.is_iff(f)) { - len = 1; - return mk_string(m, "="); - } else { symbol s = f->get_name(); return pp_fdecl_name(s, len, f->is_skolem()); diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 635899d23..22adf42d9 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -225,9 +225,6 @@ class smt_printer { else if (m_manager.is_ite(d)) { m_out << "ite"; } - else if (m_manager.is_iff(d)) { - m_out << "="; - } else if (m_manager.is_implies(d)) { m_out << "=>"; } diff --git a/src/ast/macro_substitution.cpp b/src/ast/macro_substitution.cpp index a51e1a066..2868a1876 100644 --- a/src/ast/macro_substitution.cpp +++ b/src/ast/macro_substitution.cpp @@ -77,7 +77,7 @@ void macro_substitution::cleanup() { void macro_substitution::insert(func_decl * f, quantifier * q, proof * pr, expr_dependency * dep) { DEBUG_CODE({ app * body = to_app(q->get_expr()); - SASSERT(m_manager.is_eq(body) || m_manager.is_iff(body)); + SASSERT(m_manager.is_eq(body)); expr * lhs = body->get_arg(0); expr * rhs = body->get_arg(1); SASSERT(is_app_of(lhs, f) || is_app_of(rhs, f)); @@ -146,7 +146,7 @@ void macro_substitution::erase(func_decl * f) { void macro_substitution::get_head_def(quantifier * q, func_decl * f, app * & head, expr * & def) { app * body = to_app(q->get_expr()); - SASSERT(m_manager.is_eq(body) || m_manager.is_iff(body)); + SASSERT(m_manager.is_eq(body)); expr * lhs = to_app(body)->get_arg(0); expr * rhs = to_app(body)->get_arg(1); SASSERT(is_app_of(lhs, f) || is_app_of(rhs, f)); diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index 71bdac0a4..2f429ccf7 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -169,9 +169,8 @@ void macro_manager::mark_forbidden(unsigned n, justified_expr const * exprs) { void macro_manager::get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def) const { app * body = to_app(q->get_expr()); - SASSERT(m.is_eq(body) || m.is_iff(body)); - expr * lhs = to_app(body)->get_arg(0); - expr * rhs = to_app(body)->get_arg(1); + expr * lhs = nullptr, *rhs = nullptr; + VERIFY(m.is_eq(body, lhs, rhs)); SASSERT(is_app_of(lhs, d) || is_app_of(rhs, d)); SASSERT(!is_app_of(lhs, d) || !is_app_of(rhs, d)); if (is_app_of(lhs, d)) { diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 77290c95f..b2f31e374 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -175,7 +175,7 @@ bool macro_util::is_macro_head(expr * n, unsigned num_decls) const { */ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const { - if (m_manager.is_eq(n) || m_manager.is_iff(n)) { + if (m_manager.is_eq(n)) { expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); if (is_macro_head(lhs, num_decls) && !is_forbidden(to_app(lhs)->get_decl()) && @@ -207,7 +207,7 @@ bool macro_util::is_left_simple_macro(expr * n, unsigned num_decls, app_ref & he */ bool macro_util::is_right_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const { - if (m_manager.is_eq(n) || m_manager.is_iff(n)) { + if (m_manager.is_eq(n)) { expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); if (is_macro_head(rhs, num_decls) && !is_forbidden(to_app(rhs)->get_decl()) && @@ -339,10 +339,9 @@ bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t TRACE("macro_util", tout << "processing: " << mk_pp(n, m_manager) << "\n";); expr * body = to_quantifier(n)->get_expr(); unsigned num_decls = to_quantifier(n)->get_num_decls(); - if (!m_manager.is_iff(body)) + expr * lhs, *rhs; + if (!m_manager.is_iff(body, lhs, rhs)) return false; - expr * lhs = to_app(body)->get_arg(0); - expr * rhs = to_app(body)->get_arg(1); if (is_pseudo_head(lhs, num_decls, head, t) && !is_forbidden(head->get_decl()) && !occurs(head->get_decl(), rhs)) { diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index a308b5b17..3a0735e25 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -158,7 +158,7 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const { if (is_quantifier(e) && to_quantifier(e)->is_forall()) { quantifier * q = to_quantifier(e); expr * qe = q->get_expr(); - if ((m_manager.is_eq(qe) || m_manager.is_iff(qe))) { + if ((m_manager.is_eq(qe))) { expr * lhs = to_app(qe)->get_arg(0); expr * rhs = to_app(qe)->get_arg(1); diff --git a/src/ast/normal_forms/nnf.cpp b/src/ast/normal_forms/nnf.cpp index 11461680d..c7f20ced6 100644 --- a/src/ast/normal_forms/nnf.cpp +++ b/src/ast/normal_forms/nnf.cpp @@ -582,7 +582,7 @@ struct nnf::imp { return true; } - bool is_eq(app * t) const { return m().is_eq(t) || m().is_iff(t); } + bool is_eq(app * t) const { return m().is_eq(t); } bool process_iff_xor(app * t, frame & fr) { SASSERT(t->get_num_args() == 2); @@ -630,7 +630,7 @@ struct nnf::imp { } bool process_eq(app * t, frame & fr) { - if (m().is_bool(t->get_arg(0))) + if (m().is_iff(t)) return process_iff_xor(t, fr); else return process_default(t, fr); @@ -725,7 +725,6 @@ struct nnf::imp { return process_implies(t, fr); case OP_ITE: return process_ite(t, fr); - case OP_IFF: case OP_XOR: return process_iff_xor(t, fr); case OP_EQ: diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 0e16abd11..24841016c 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -12,7 +12,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/rewriter/th_rewriter.h" #include "ast/rewriter/var_subst.h" -#define IS_EQUIV(_e_) (m.is_eq(_e_) || m.is_iff(_e_)) +#define IS_EQUIV(_e_) m.is_eq(_e_) #define SAME_OP(_d1_, _d2_) ((_d1_ == _d2_) || (IS_EQUIV(_d1_) && IS_EQUIV(_d2_))) @@ -1032,7 +1032,7 @@ bool proof_checker::match_and(expr const* e, expr_ref_vector& terms) const { } bool proof_checker::match_iff(expr const* e, expr_ref& t1, expr_ref& t2) const { - return match_op(e, OP_IFF, t1, t2); + return match_op(e, OP_EQ, t1, t2) && m.is_bool(t1); } bool proof_checker::match_equiv(expr const* e, expr_ref& t1, expr_ref& t2) const { @@ -1044,7 +1044,7 @@ bool proof_checker::match_implies(expr const* e, expr_ref& t1, expr_ref& t2) con } bool proof_checker::match_eq(expr const* e, expr_ref& t1, expr_ref& t2) const { - return match_op(e, OP_EQ, t1, t2) || match_iff(e, t1, t2); + return match_op(e, OP_EQ, t1, t2); } bool proof_checker::match_oeq(expr const* e, expr_ref& t1, expr_ref& t2) const { diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h index 455f39c4f..729a30eb0 100644 --- a/src/ast/proofs/proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -110,10 +110,10 @@ public: if (m.is_or(decl)) { mk_or_core(args, res); } - else if (m.is_iff(decl) && args.size() == 2) + else if (m.is_eq(decl) && args.size() == 2) // avoiding simplifying equalities. In particular, // we don't want (= (not a) (not b)) to be reduced to (= a b) - { res = m.mk_iff(args.get(0), args.get(1)); } + { res = m.mk_eq(args.get(0), args.get(1)); } else { brwr.mk_app(decl, args.size(), args.c_ptr(), res); } } diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 5cf25335b..46613a12e 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -39,7 +39,6 @@ br_status bool_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * co SASSERT(f->get_family_id() == m().get_basic_family_id()); switch (f->get_decl_kind()) { case OP_EQ: - case OP_IFF: SASSERT(num_args == 2); return mk_eq_core(args[0], args[1], result); case OP_DISTINCT: @@ -428,7 +427,7 @@ bool bool_rewriter::simp_nested_eq_ite(expr * t, expr_fast_mark1 & neg_lits, exp neg = true; t = to_app(t)->get_arg(0); } - if (m().is_iff(t) || m().is_eq(t)) { + if (m().is_eq(t)) { bool modified = false; expr * new_lhs = simp_arg(to_app(t)->get_arg(0), neg_lits, pos_lits, modified); expr * new_rhs = simp_arg(to_app(t)->get_arg(1), neg_lits, pos_lits, modified); @@ -708,7 +707,7 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { expr *la, *lb, *ra, *rb; // fold (iff (iff a b) (iff (not a) b)) to false - if (m().is_iff(lhs, la, lb) && m().is_iff(rhs, ra, rb)) { + if (m().is_eq(lhs, la, lb) && m().is_eq(rhs, ra, rb)) { expr *n; if ((la == ra && ((m().is_not(rb, n) && n == lb) || (m().is_not(lb, n) && n == rb))) || diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index 34e03c1ed..83ece2aae 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -81,7 +81,7 @@ public: bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_local_ctx_cost(0) { updt_params(p); } ast_manager & m() const { return m_manager; } family_id get_fid() const { return m().get_basic_family_id(); } - bool is_eq(expr * t) const { return m().is_eq(t) || m().is_iff(t); } + bool is_eq(expr * t) const { return m().is_eq(t); } bool flat() const { return m_flat; } void set_flat(bool f) { m_flat = f; } diff --git a/src/ast/rewriter/der.cpp b/src/ast/rewriter/der.cpp index 021943585..54409e9c2 100644 --- a/src/ast/rewriter/der.cpp +++ b/src/ast/rewriter/der.cpp @@ -40,11 +40,8 @@ static bool is_neg_var(ast_manager & m, expr * e, unsigned num_decls) { */ bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) { // (not (= VAR t)) and (not (iff VAR t)) cases - if (m_manager.is_not(e) && (m_manager.is_eq(to_app(e)->get_arg(0)) || m_manager.is_iff(to_app(e)->get_arg(0)))) { - app * eq = to_app(to_app(e)->get_arg(0)); - SASSERT(m_manager.is_eq(eq) || m_manager.is_iff(eq)); - expr * lhs = eq->get_arg(0); - expr * rhs = eq->get_arg(1); + expr *eq, * lhs, *rhs; + if (m_manager.is_not(e, eq) && m_manager.is_eq(eq, lhs, rhs)) { if (!is_var(lhs, num_decls) && !is_var(rhs, num_decls)) return false; if (!is_var(lhs, num_decls)) @@ -60,9 +57,7 @@ bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) { return true; } // (iff VAR t) and (iff (not VAR) t) cases - else if (m_manager.is_iff(e)) { - expr * lhs = to_app(e)->get_arg(0); - expr * rhs = to_app(e)->get_arg(1); + else if (m_manager.is_eq(e, lhs, rhs) && m_manager.is_bool(lhs)) { // (iff VAR t) case if (is_var(lhs, num_decls) || is_var(rhs, num_decls)) { if (!is_var(lhs, num_decls)) diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index 3592f84cd..2f1116299 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -259,7 +259,7 @@ private: result = m.mk_ite(t1, tt2, tt3); } } - else if ((m.is_eq(fml, t1, t2) && m.is_bool(t1)) || m.is_iff(fml, t1, t2)) { + else if (m.is_eq(fml, t1, t2) && m.is_bool(t1)) { expr_ref tt1(m), tt2(m), ntt1(m), ntt2(m), nt1(m), nt2(m); pull_quantifier(t1, qt, vars, tt1, use_fresh, rewrite_ok); pull_quantifier(t2, qt, vars, tt2, use_fresh, rewrite_ok); diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index f5a0ff0f7..912df0fc9 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -187,7 +187,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { if (st != BR_FAILED) return st; } - if (k == OP_EQ || k == OP_IFF) { + if (k == OP_EQ) { SASSERT(num == 2); st = apply_tamagotchi(args[0], args[1], result); if (st != BR_FAILED) diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index c8a1adcbe..e3530b4b5 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -154,8 +154,10 @@ bool static_features::is_diff_atom(expr const * e) const { bool static_features::is_gate(expr const * e) const { if (is_basic_expr(e)) { switch (to_app(e)->get_decl_kind()) { - case OP_ITE: case OP_AND: case OP_OR: case OP_IFF: case OP_XOR: case OP_IMPLIES: + case OP_ITE: case OP_AND: case OP_OR: case OP_XOR: case OP_IMPLIES: return true; + case OP_EQ: + return m_manager.is_bool(e); } } return false; @@ -207,7 +209,7 @@ void static_features::update_core(expr * e) { case OP_OR: m_num_ors++; break; - case OP_IFF: + case OP_EQ: m_num_iffs++; break; } @@ -418,7 +420,7 @@ void static_features::process(expr * e, bool form_ctx, bool or_and_ctx, bool ite form_ctx_new = true; or_and_ctx_new = true; break; - case OP_IFF: + case OP_EQ: form_ctx_new = true; break; } diff --git a/src/model/model_implicant.cpp b/src/model/model_implicant.cpp index 3456c2746..0cdd80c11 100644 --- a/src/model/model_implicant.cpp +++ b/src/model/model_implicant.cpp @@ -172,7 +172,6 @@ void model_implicant::process_formula(app* e, ptr_vector& todo, ptr_vector case OP_FALSE: break; case OP_EQ: - case OP_IFF: if (args[0] == args[1]) { SASSERT(v); // no-op @@ -742,10 +741,6 @@ void model_implicant::eval_basic(app* e) { set_x(e); } break; - case OP_IFF: - VERIFY(m.is_iff(e, arg1, arg2)); - eval_eq(e, arg1, arg2); - break; case OP_ITE: VERIFY(m.is_ite(e, argCond, argThen, argElse)); if (is_true(argCond)) { diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index 21317a07c..315765acc 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -146,12 +146,10 @@ void rule_properties::check_existential_tail() { else if (is_quantifier(e)) { tocheck.push_back(to_quantifier(e)->get_expr()); } - else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) && - m.is_true(e1)) { + else if (m.is_eq(e, e1, e2) && m.is_true(e1)) { todo.push_back(e2); } - else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) && - m.is_true(e2)) { + else if (m.is_eq(e, e1, e2) && m.is_true(e2)) { todo.push_back(e1); } else { diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 77b79ba04..c2cd94ee0 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -830,7 +830,7 @@ namespace pdr { flatten_and(state(), conjs); for (unsigned i = 0; i < conjs.size(); ++i) { expr* e = conjs[i].get(), *e1, *e2; - if (m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) { + if (m.is_eq(e, e1, e2)) { if (m.is_value(e2)) { model.insert(e1, e2); } diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index 2e9ab693c..ea292a29e 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -869,7 +869,7 @@ namespace datalog { dm.set(*d, idx, BIT_1); result.intersect(dm, *d); } - else if ((m.is_eq(g, e1, e2) || m.is_iff(g, e1, e2)) && m.is_bool(e1)) { + else if (m.is_iff(g, e1, e2)) { udoc diff1, diff2; diff1.push_back(dm.allocateX()); diff2.push_back(dm.allocateX()); diff --git a/src/muz/spacer/spacer_legacy_mev.cpp b/src/muz/spacer/spacer_legacy_mev.cpp index fc3eabc56..5feaed1fa 100644 --- a/src/muz/spacer/spacer_legacy_mev.cpp +++ b/src/muz/spacer/spacer_legacy_mev.cpp @@ -138,7 +138,6 @@ void model_evaluator::process_formula(app* e, ptr_vector& todo, ptr_vector case OP_FALSE: break; case OP_EQ: - case OP_IFF: if (args[0] == args[1]) { SASSERT(v); // no-op @@ -634,10 +633,6 @@ void model_evaluator::eval_basic(app* e) set_x(e); } break; - case OP_IFF: - VERIFY(m.is_iff(e, arg1, arg2)); - eval_eq(e, arg1, arg2); - break; case OP_XOR: VERIFY(m.is_xor(e, arg1, arg2)); eval_eq(e, arg1, arg2); diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index cb11afc9f..b4e5e7710 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -403,27 +403,26 @@ namespace spacer { public: test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} - + void test_for_utvpi() { m_test_for_utvpi = true; } - - void operator()(expr* e) - { + + void operator()(expr* e) { if (!m_is_dl) { return; } if (a.is_le(e) || a.is_ge(e)) { m_is_dl = test_ineq(e); - } else if (m.is_eq(e)) { + } else if (m.is_eq(e)) { m_is_dl = test_eq(e); - } else if (is_non_arith_or_basic(e)) { + } else if (is_non_arith_or_basic(e)) { m_is_dl = false; - } else if (is_app(e)) { + } else if (is_app(e)) { app* a = to_app(e); for (unsigned i = 0; m_is_dl && i < a->get_num_args(); ++i) { m_is_dl = test_term(a->get_arg(i)); } } - + if (!m_is_dl) { char const* msg = "non-diff: "; if (m_test_for_utvpi) { @@ -432,12 +431,11 @@ namespace spacer { IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); } } - + bool is_dl() const { return m_is_dl; } }; - -bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) -{ + + bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); expr_fast_mark1 mark; for (unsigned i = 0; i < num_fmls; ++i) { @@ -445,9 +443,8 @@ bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) } return test.is_dl(); } - -bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) -{ + + bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); test.test_for_utvpi(); expr_fast_mark1 mark; @@ -458,14 +455,13 @@ bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) } - void subst_vars (ast_manager& m, app_ref_vector const& vars, - model* M, expr_ref& fml) -{ + void subst_vars(ast_manager& m, + app_ref_vector const& vars, + model* M, expr_ref& fml) { expr_safe_replace sub (m); model_evaluator_util mev (m); mev.set_model(*M); - for (unsigned i = 0; i < vars.size (); i++) { - app* v = vars.get (i); + for (app * v : vars) { expr_ref val (m); VERIFY(mev.eval (v, val, true)); sub.insert (v, val); @@ -477,30 +473,23 @@ bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) * eliminate simple equalities using qe_lite * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays */ -void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, const model_ref& M, bool reduce_all_selects, bool use_native_mbp, - bool dont_sub) -{ + bool dont_sub) { th_rewriter rw (m); TRACE ("spacer_mbp", - tout << "Before projection:\n"; - tout << mk_pp (fml, m) << "\n"; - tout << "Vars:\n"; - for (unsigned i = 0; i < vars.size(); ++i) { - tout << mk_pp(vars.get (i), m) << "\n"; - } - ); + tout << "Before projection:\n"; + tout << mk_pp (fml, m) << "\n"; + tout << "Vars:\n"; + for (app* v : vars) tout << mk_pp(v, m) << "\n";); { - // Ensure that top-level AND of fml is flat - expr_ref_vector flat(m); - flatten_and (fml, flat); - if (flat.size () == 1) - { fml = flat.get(0); } - else if (flat.size () > 1) - { fml = m.mk_and(flat.size(), flat.c_ptr()); } + // Ensure that top-level AND of fml is flat + expr_ref_vector flat(m); + flatten_and (fml, flat); + fml = mk_and(flat); } - + app_ref_vector arith_vars (m); app_ref_vector array_vars (m); array_util arr_u (m); @@ -511,77 +500,72 @@ void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, while (true) { params_ref p; qe_lite qe(m, p, false); - qe (vars, fml); - rw (fml); + qe (vars, fml); + rw (fml); + + TRACE ("spacer_mbp", + tout << "After qe_lite:\n"; + tout << mk_pp (fml, m) << "\n"; + tout << "Vars:\n"; + for (unsigned i = 0; i < vars.size(); ++i) { + tout << mk_pp(vars.get (i), m) << "\n"; + } + ); + SASSERT (!m.is_false (fml)); - TRACE ("spacer_mbp", - tout << "After qe_lite:\n"; - tout << mk_pp (fml, m) << "\n"; - tout << "Vars:\n"; - for (unsigned i = 0; i < vars.size(); ++i) { - tout << mk_pp(vars.get (i), m) << "\n"; - } - ); - SASSERT (!m.is_false (fml)); - - bool has_bool_vars = false; - - // sort out vars into bools, arith (int/real), and arrays - for (unsigned i = 0; i < vars.size (); i++) { - if (m.is_bool (vars.get (i))) { - // obtain the interpretation of the ith var using model completion - VERIFY (M->eval (vars.get (i), bval, true)); - bool_sub.insert (vars.get (i), bval); - has_bool_vars = true; + bool has_bool_vars = false; + + // sort out vars into bools, arith (int/real), and arrays + for (unsigned i = 0; i < vars.size (); i++) { + if (m.is_bool (vars.get (i))) { + // obtain the interpretation of the ith var using model completion + VERIFY (M->eval (vars.get (i), bval, true)); + bool_sub.insert (vars.get (i), bval); + has_bool_vars = true; } else if (arr_u.is_array(vars.get(i))) { - array_vars.push_back (vars.get (i)); + array_vars.push_back (vars.get (i)); } else { - SASSERT (ari_u.is_int (vars.get (i)) || ari_u.is_real (vars.get (i))); - arith_vars.push_back (vars.get (i)); - } + SASSERT (ari_u.is_int (vars.get (i)) || ari_u.is_real (vars.get (i))); + arith_vars.push_back (vars.get (i)); } - - // substitute Booleans - if (has_bool_vars) { - bool_sub (fml); - // -- bool_sub is not simplifying - rw (fml); - SASSERT (!m.is_false (fml)); - TRACE ("spacer_mbp", - tout << "Projected Booleans:\n" << mk_pp (fml, m) << "\n"; - ); - bool_sub.reset (); - } - + } + + // substitute Booleans + if (has_bool_vars) { + bool_sub (fml); + // -- bool_sub is not simplifying + rw (fml); + SASSERT (!m.is_false (fml)); TRACE ("spacer_mbp", - tout << "Array vars:\n"; - for (unsigned i = 0; i < array_vars.size (); ++i) { - tout << mk_pp (array_vars.get (i), m) << "\n"; - } - ); - - vars.reset (); - - // project arrays - { - scoped_no_proof _sp (m); - // -- local rewriter that is aware of current proof mode - th_rewriter srw(m); - qe::array_project (*M.get (), array_vars, fml, vars, reduce_all_selects); - SASSERT (array_vars.empty ()); - srw (fml); - SASSERT (!m.is_false (fml)); - } - - TRACE ("spacer_mbp", - tout << "extended model:\n"; - model_pp (tout, *M); - tout << "Auxiliary variables of index and value sorts:\n"; - for (unsigned i = 0; i < vars.size (); i++) { - tout << mk_pp (vars.get (i), m) << "\n"; - } - ); - + tout << "Projected Booleans:\n" << mk_pp (fml, m) << "\n"; + ); + bool_sub.reset (); + } + + TRACE ("spacer_mbp", + tout << "Array vars:\n"; + tout << array_vars;); + + vars.reset (); + + // project arrays + { + scoped_no_proof _sp (m); + // -- local rewriter that is aware of current proof mode + th_rewriter srw(m); + qe::array_project (*M.get (), array_vars, fml, vars, reduce_all_selects); + SASSERT (array_vars.empty ()); + srw (fml); + SASSERT (!m.is_false (fml)); + } + + TRACE ("spacer_mbp", + tout << "extended model:\n"; + model_pp (tout, *M); + tout << "Auxiliary variables of index and value sorts:\n"; + tout << vars; + ); + if (vars.empty()) { break; } } diff --git a/src/muz/transforms/dl_mk_array_blast.cpp b/src/muz/transforms/dl_mk_array_blast.cpp index 6894cf4fa..34e739bc3 100644 --- a/src/muz/transforms/dl_mk_array_blast.cpp +++ b/src/muz/transforms/dl_mk_array_blast.cpp @@ -42,7 +42,7 @@ namespace datalog { } bool mk_array_blast::is_store_def(expr* e, expr*& x, expr*& y) { - if (m.is_iff(e, x, y) || m.is_eq(e, x, y)) { + if (m.is_eq(e, x, y)) { if (!a.is_store(y)) { std::swap(x,y); } diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 4cbcc5712..9f6302e05 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -180,7 +180,7 @@ namespace datalog { } m_terms[n] = e; visited.mark(e); - if (m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) { + if (m.is_eq(e, e1, e2)) { m_uf.merge(e1->get_id(), e2->get_id()); } if (is_app(e)) { diff --git a/src/nlsat/tactic/goal2nlsat.cpp b/src/nlsat/tactic/goal2nlsat.cpp index 133652c1d..42ae36564 100644 --- a/src/nlsat/tactic/goal2nlsat.cpp +++ b/src/nlsat/tactic/goal2nlsat.cpp @@ -198,7 +198,6 @@ struct goal2nlsat::imp { throw tactic_exception("apply simplify before applying nlsat"); case OP_AND: case OP_OR: - case OP_IFF: case OP_XOR: case OP_NOT: case OP_IMPLIES: diff --git a/src/parsers/util/cost_parser.cpp b/src/parsers/util/cost_parser.cpp index 765b8ade9..91362b37a 100644 --- a/src/parsers/util/cost_parser.cpp +++ b/src/parsers/util/cost_parser.cpp @@ -32,7 +32,7 @@ cost_parser::cost_parser(ast_manager & m): add_builtin_op("or", fid, OP_OR); add_builtin_op("ite", fid, OP_ITE); add_builtin_op("=", fid, OP_EQ); - add_builtin_op("iff", fid, OP_IFF); + add_builtin_op("iff", fid, OP_EQ); add_builtin_op("xor", fid, OP_XOR); fid = m_util.get_family_id(); diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index daed18f7a..3916e547c 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -614,7 +614,7 @@ namespace qe { else if (m.is_ite(a)) { nnf_ite(a, p); } - else if (m.is_iff(a) || (m.is_eq(a) && m.is_bool(a->get_arg(0)))) { + else if (m.is_iff(a)) { nnf_iff(a, p); } else if (m.is_xor(a)) { diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 6ecdfd835..2a14aa6f2 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -345,7 +345,7 @@ namespace eq { var* v; // (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases - if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) { + if (m.is_eq(e, lhs, rhs)) { // (iff (not VAR) t) (iff t (not VAR)) cases if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) { if (!is_neg_var(m, lhs, v)) { diff --git a/src/sat/tactic/atom2bool_var.cpp b/src/sat/tactic/atom2bool_var.cpp index e3c9b6767..b79eaa251 100644 --- a/src/sat/tactic/atom2bool_var.cpp +++ b/src/sat/tactic/atom2bool_var.cpp @@ -75,7 +75,7 @@ struct collect_boolean_interface_proc { continue; if (is_app(t) && to_app(t)->get_family_id() == m.get_basic_family_id() && to_app(t)->get_num_args() > 0) { decl_kind k = to_app(t)->get_decl_kind(); - if (k == OP_OR || k == OP_NOT || k == OP_IFF || ((k == OP_EQ || k == OP_ITE) && m.is_bool(to_app(t)->get_arg(1)))) { + if (k == OP_OR || k == OP_NOT || ((k == OP_EQ || k == OP_ITE) && m.is_bool(to_app(t)->get_arg(1)))) { unsigned num = to_app(t)->get_num_args(); for (unsigned i = 0; i < num; i++) { expr * arg = to_app(t)->get_arg(i); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index ea9c5b4ea..75290946a 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -201,7 +201,6 @@ struct goal2sat::imp { case OP_NOT: case OP_OR: case OP_AND: - case OP_IFF: m_frame_stack.push_back(frame(to_app(t), root, sign, 0)); return false; case OP_ITE: @@ -630,7 +629,6 @@ struct goal2sat::imp { case OP_ITE: convert_ite(t, root, sign); break; - case OP_IFF: case OP_EQ: convert_iff(t, root, sign); break; diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index c00fb93b1..c7ae7605f 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -500,8 +500,7 @@ unsigned asserted_formulas::propagate_values(unsigned i) { void asserted_formulas::update_substitution(expr* n, proof* pr) { expr* lhs, *rhs, *n1; - proof_ref pr1(m); - if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { + if (is_ground(n) && m.is_eq(n, lhs, rhs)) { compute_depth(lhs); compute_depth(rhs); if (is_gt(lhs, rhs)) { @@ -511,12 +510,12 @@ void asserted_formulas::update_substitution(expr* n, proof* pr) { } if (is_gt(rhs, lhs)) { TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); - pr1 = m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr; - m_scoped_substitution.insert(rhs, lhs, pr1); + m_scoped_substitution.insert(rhs, lhs, m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr); return; } TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); } + proof_ref pr1(m); if (m.is_not(n, n1)) { pr1 = m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr; m_scoped_substitution.insert(n1, m.mk_false(), pr1); diff --git a/src/smt/cost_evaluator.cpp b/src/smt/cost_evaluator.cpp index 94151f2b3..0719d0961 100644 --- a/src/smt/cost_evaluator.cpp +++ b/src/smt/cost_evaluator.cpp @@ -47,8 +47,7 @@ float cost_evaluator::eval(expr * f) const { return 1.0f; return 0.0f; case OP_ITE: return E(0) != 0.0f ? E(1) : E(2); - case OP_EQ: - case OP_IFF: return E(0) == E(1) ? 1.0f : 0.0f; + case OP_EQ: return E(0) == E(1) ? 1.0f : 0.0f; case OP_XOR: return E(0) != E(1) ? 1.0f : 0.0f; case OP_IMPLIES: if (E(0) == 0.0f) diff --git a/src/smt/expr_context_simplifier.cpp b/src/smt/expr_context_simplifier.cpp index bce28420d..a57b0299f 100644 --- a/src/smt/expr_context_simplifier.cpp +++ b/src/smt/expr_context_simplifier.cpp @@ -110,13 +110,15 @@ void expr_context_simplifier::reduce_rec(app * a, expr_ref & result) { case OP_OR: reduce_or(a->get_num_args(), a->get_args(), result); return; - case OP_IFF: { - expr_ref tmp1(m_manager), tmp2(m_manager); - reduce_rec(a->get_arg(0), tmp1); - reduce_rec(a->get_arg(1), tmp2); - m_simp.mk_iff(tmp1.get(), tmp2.get(), result); - return; - } + case OP_EQ: + if (m_manager.is_iff(a)) { + expr_ref tmp1(m_manager), tmp2(m_manager); + reduce_rec(a->get_arg(0), tmp1); + reduce_rec(a->get_arg(1), tmp2); + m_simp.mk_iff(tmp1.get(), tmp2.get(), result); + return; + } + break; case OP_XOR: { expr_ref tmp1(m_manager), tmp2(m_manager); reduce_rec(a->get_arg(0), tmp1); @@ -580,7 +582,7 @@ void expr_strong_context_simplifier::simplify_model_based(expr* fml, expr_ref& r } assignment_map.insert(a, value); } - else if (m.is_iff(a, n1, n2) || m.is_eq(a, n1, n2)) { + else if (m.is_eq(a, n1, n2)) { lbool v1 = assignment_map.find(n1); lbool v2 = assignment_map.find(n2); if (v1 == l_undef || v2 == l_undef) { diff --git a/src/smt/smt_checker.cpp b/src/smt/smt_checker.cpp index ed80eaab7..1b6a5d370 100644 --- a/src/smt/smt_checker.cpp +++ b/src/smt/smt_checker.cpp @@ -61,8 +61,20 @@ namespace smt { return is_true ? any_arg(a, true) : all_args(a, false); case OP_AND: return is_true ? all_args(a, true) : any_arg(a, false); - case OP_IFF: - if (is_true) { + case OP_EQ: + if (!m_manager.is_iff(a)) { + enode * lhs = get_enode_eq_to(a->get_arg(0)); + enode * rhs = get_enode_eq_to(a->get_arg(1)); + if (lhs && rhs && m_context.is_relevant(lhs) && m_context.is_relevant(rhs)) { + if (is_true && lhs->get_root() == rhs->get_root()) + return true; + // if (!is_true && m_context.is_ext_diseq(lhs, rhs, 2)) + if (!is_true && m_context.is_diseq(lhs, rhs)) + return true; + } + return false; + } + else if (is_true) { return (check(a->get_arg(0), true) && check(a->get_arg(1), true)) || @@ -86,18 +98,6 @@ namespace smt { } return check(a->get_arg(1), is_true) && check(a->get_arg(2), is_true); } - case OP_EQ: { - enode * lhs = get_enode_eq_to(a->get_arg(0)); - enode * rhs = get_enode_eq_to(a->get_arg(1)); - if (lhs && rhs && m_context.is_relevant(lhs) && m_context.is_relevant(rhs)) { - if (is_true && lhs->get_root() == rhs->get_root()) - return true; - // if (!is_true && m_context.is_ext_diseq(lhs, rhs, 2)) - if (!is_true && m_context.is_diseq(lhs, rhs)) - return true; - } - return false; - } default: break; } diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 379846ed7..7984fd5f0 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -771,7 +771,7 @@ namespace smt { app * fact = to_app(m_manager.get_fact(pr)); app * n1_owner = n1->get_owner(); app * n2_owner = n2->get_owner(); - bool is_eq = m_manager.is_eq(fact) || m_manager.is_iff(fact); + bool is_eq = m_manager.is_eq(fact); if (!is_eq || (fact->get_arg(0) != n2_owner && fact->get_arg(1) != n2_owner)) { CTRACE("norm_eq_proof_bug", !m_ctx.is_true(n2) && !m_ctx.is_false(n2), tout << "n1: #" << n1->get_owner_id() << ", n2: #" << n2->get_owner_id() << "\n"; @@ -794,7 +794,7 @@ namespace smt { TRACE("norm_eq_proof", tout << "#" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n"; tout << mk_ll_pp(pr, m_manager, true, false);); - SASSERT(m_manager.is_eq(fact) || m_manager.is_iff(fact)); + SASSERT(m_manager.is_eq(fact)); SASSERT((fact->get_arg(0) == n1->get_owner() && fact->get_arg(1) == n2->get_owner()) || (fact->get_arg(1) == n1->get_owner() && fact->get_arg(0) == n2->get_owner())); if (fact->get_arg(0) == n1_owner && fact->get_arg(1) == n2_owner) diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index dc7c32cc1..f9ee900ff 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -34,9 +34,10 @@ namespace smt { switch (to_app(n)->get_decl_kind()) { case OP_AND: case OP_OR: - case OP_IFF: case OP_ITE: return true; + case OP_EQ: + return m.is_bool(to_app(n)->get_arg(0)); default: return false; } @@ -229,7 +230,7 @@ namespace smt { add_or_rel_watches(to_app(n)); break; } - case OP_IFF: { + case OP_EQ: { expr * lhs = to_app(n)->get_arg(0); expr * rhs = to_app(n)->get_arg(1); internalize(lhs, true); @@ -381,7 +382,7 @@ namespace smt { return; } - if (m_manager.is_eq(n)) + if (m_manager.is_eq(n) && !m_manager.is_iff(n)) internalize_eq(to_app(n), gate_ctx); else if (m_manager.is_distinct(n)) internalize_distinct(to_app(n), gate_ctx); @@ -538,9 +539,7 @@ namespace smt { bool _is_gate = is_gate(m_manager, n) || m_manager.is_not(n); // process args - unsigned num = n->get_num_args(); - for (unsigned i = 0; i < num; i++) { - expr * arg = n->get_arg(i); + for (expr * arg : *n) { internalize(arg, _is_gate); } @@ -596,8 +595,9 @@ namespace smt { mk_or_cnstr(to_app(n)); add_or_rel_watches(to_app(n)); break; - case OP_IFF: - mk_iff_cnstr(to_app(n)); + case OP_EQ: + if (m_manager.is_iff(n)) + mk_iff_cnstr(to_app(n)); break; case OP_ITE: mk_ite_cnstr(to_app(n)); diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 5e21c0dcc..4307d3fdf 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -2315,9 +2315,6 @@ namespace smt { case OP_ITE: process_ite(to_app(curr), pol); break; - case OP_IFF: - process_iff(to_app(curr)); - break; case OP_EQ: if (m_manager.is_bool(to_app(curr)->get_arg(0))) { process_iff(to_app(curr)); diff --git a/src/smt/smt_quantifier_stat.cpp b/src/smt/smt_quantifier_stat.cpp index 7d73ea27c..8c7fd196e 100644 --- a/src/smt/smt_quantifier_stat.cpp +++ b/src/smt/smt_quantifier_stat.cpp @@ -82,11 +82,13 @@ namespace smt { if (depth > 0) m_case_split_factor *= (num_args + 1); break; - case OP_IFF: - if (depth == 0) - m_case_split_factor *= 4; - else - m_case_split_factor *= 9; + case OP_EQ: + if (m_manager.is_iff(n)) { + if (depth == 0) + m_case_split_factor *= 4; + else + m_case_split_factor *= 9; + } break; case OP_ITE: if (depth == 0) diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index 64c791a0e..72a720d98 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -311,11 +311,6 @@ namespace smt { return is_true ? any_arg(a, true) : all_args(a, false); case OP_AND: return is_true ? all_args(a, true) : any_arg(a, false); - case OP_IFF: - if (is_true) - return (check(a->get_arg(0), true) && check(a->get_arg(1), true)) || (check(a->get_arg(0), false) && check(a->get_arg(1), false)); - else - return (check(a->get_arg(0), true) && check(a->get_arg(1), false)) || (check(a->get_arg(0), false) && check(a->get_arg(1), true)); case OP_ITE: if (check(a->get_arg(0), true)) return check(a->get_arg(1), is_true); @@ -324,6 +319,13 @@ namespace smt { else return check(a->get_arg(1), is_true) && check(a->get_arg(2), is_true); case OP_EQ: + if (m_manager.is_iff(a)) { + if (is_true) + return (check(a->get_arg(0), true) && check(a->get_arg(1), true)) || (check(a->get_arg(0), false) && check(a->get_arg(1), false)); + else + return (check(a->get_arg(0), true) && check(a->get_arg(1), false)) || (check(a->get_arg(0), false) && check(a->get_arg(1), true)); + } + if (is_true) { return canonize(a->get_arg(0)) == canonize(a->get_arg(1)); } diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 89196808f..faedf0e0c 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -490,7 +490,6 @@ struct aig_manager::imp { case OP_NOT: case OP_OR: case OP_AND: - case OP_IFF: case OP_XOR: case OP_IMPLIES: case OP_ITE: @@ -582,9 +581,6 @@ struct aig_manager::imp { SASSERT(m.m().is_bool(fr.m_t->get_arg(0))); mk_iff(fr.m_spos); break; - case OP_IFF: - mk_iff(fr.m_spos); - break; case OP_XOR: mk_xor(fr.m_spos); break; diff --git a/src/tactic/core/cofactor_elim_term_ite.cpp b/src/tactic/core/cofactor_elim_term_ite.cpp index 2b3cb8414..1b435791c 100644 --- a/src/tactic/core/cofactor_elim_term_ite.cpp +++ b/src/tactic/core/cofactor_elim_term_ite.cpp @@ -87,7 +87,6 @@ struct cofactor_elim_term_ite::imp { case OP_TRUE: case OP_FALSE: case OP_ITE: - case OP_IFF: return; case OP_EQ: case OP_DISTINCT: diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 43da3bc00..27a5bdc94 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -486,7 +486,7 @@ bool expr_substitution_simplifier::is_gt(expr* lhs, expr* rhs) { void expr_substitution_simplifier::update_substitution(expr* n, proof* pr) { expr* lhs, *rhs, *n1; - if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { + if (is_ground(n) && m.is_eq(n, lhs, rhs)) { compute_depth(lhs); compute_depth(rhs); m_trail.push_back(lhs); diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index ce77f89d9..577db30cd 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -331,7 +331,6 @@ class elim_uncnstr_tactic : public tactic { return r; } return nullptr; - case OP_IFF: case OP_EQ: SASSERT(num == 2); return process_eq(f, args[0], args[1]); diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index acd75d663..f579b7b4f 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -344,10 +344,7 @@ class solve_eqs_tactic : public tactic { } return false; } - - if (m().is_iff(f)) - return trivial_solve(to_app(f)->get_arg(0), to_app(f)->get_arg(1), var, def, pr); - + #if 0 if (not_bool_eq(f, var, def, pr)) return true; diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index 2abaae0e6..9c57fe791 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -176,7 +176,6 @@ class tseitin_cnf_tactic : public tactic { sign = !sign; goto start; case OP_OR: - case OP_IFF: l = nullptr; m_cache.find(to_app(n), l); SASSERT(l != 0); @@ -223,7 +222,6 @@ class tseitin_cnf_tactic : public tactic { goto start; } case OP_OR: - case OP_IFF: visited = false; push_frame(to_app(n)); return; From 689414d0552a58e5bec84af4c3396eb89f79de6b Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 16 May 2018 21:15:40 -0700 Subject: [PATCH 1006/1283] Fix debug printing in iuc_solver --- src/muz/spacer/spacer_iuc_solver.cpp | 3 ++- src/muz/spacer/spacer_prop_solver.cpp | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 7c159746f..a01f95c71 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -284,7 +284,8 @@ void iuc_solver::get_iuc(expr_ref_vector &core) // -- old hypothesis reducer while the new one is broken if (m_old_hyp_reducer) { - // preprocess proof in order to get a proof which is better suited for unsat-core-extraction + // preprocess proof in order to get a proof which is + // better suited for unsat-core-extraction if (m_print_farkas_stats) { iuc_proof iuc_before(m, res.get(), B); diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 39db6129c..87f998486 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -60,12 +60,16 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& m_solvers[1] = pm.mk_fresh2(); m_fparams[1] = &pm.fparams2(); - m_contexts[0] = alloc(spacer::iuc_solver, *(m_solvers[0]), p.spacer_iuc(), + m_contexts[0] = alloc(spacer::iuc_solver, *(m_solvers[0]), + p.spacer_iuc(), p.spacer_iuc_arith(), + p.spacer_iuc_print_farkas_stats(), p.spacer_iuc_old_hyp_reducer(), p.spacer_iuc_split_farkas_literals()); - m_contexts[1] = alloc(spacer::iuc_solver, *(m_solvers[1]), p.spacer_iuc(), + m_contexts[1] = alloc(spacer::iuc_solver, *(m_solvers[1]), + p.spacer_iuc(), p.spacer_iuc_arith(), + p.spacer_iuc_print_farkas_stats(), p.spacer_iuc_old_hyp_reducer(), p.spacer_iuc_split_farkas_literals()); From 9d4784baf63b5d9e6b691b65f1c2b78d67f1b659 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 08:51:33 -0700 Subject: [PATCH 1007/1283] Fix dealloc order in hypotheses_reducer::reset() --- src/muz/spacer/spacer_proof_utils.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 42cdcf50b..8ed414c2b 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -174,14 +174,15 @@ proof_ref theory_axiom_reducer::reduce(proof* pr) { } void hypothesis_reducer::reset() { - m_cache.reset(); - m_units.reset(); - m_active_hyps.reset(); m_parent_hyps.reset(); - for (auto t : m_pinned_active_hyps) dealloc(t); - m_pinned_active_hyps.reset(); + m_active_hyps.reset(); + m_units.reset(); + m_cache.reset(); for (auto t : m_pinned_parent_hyps) dealloc(t); m_pinned_parent_hyps.reset(); + for (auto t : m_pinned_active_hyps) dealloc(t); + m_pinned_active_hyps.reset(); + m_pinned.reset(); } void hypothesis_reducer::compute_hypsets(proof *pr) { From fd13eb9e0ea8da1e8ed3eafac9de3472fc7876b1 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 09:19:05 -0700 Subject: [PATCH 1008/1283] Final cleanup of hypothesis_reducer --- src/muz/spacer/spacer_proof_utils.cpp | 85 +++++++++++++++------------ src/muz/spacer/spacer_proof_utils.h | 15 +++-- 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 8ed414c2b..e8f56f200 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -173,6 +173,24 @@ proof_ref theory_axiom_reducer::reduce(proof* pr) { return proof_ref(res, m); } +/* ------------------------------------------------------------------------- */ +/* hypothesis_reducer */ +/* ------------------------------------------------------------------------- */ + +proof_ref hypothesis_reducer::reduce(proof* pr) { + compute_hypsets(pr); + collect_units(pr); + + proof_ref res(reduce_core(pr), m); + SASSERT(res); + reset(); + + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(res, side));); + return res; +} + void hypothesis_reducer::reset() { m_parent_hyps.reset(); m_active_hyps.reset(); @@ -198,7 +216,7 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { continue; } - bool dirty = false; + unsigned todo_sz = todo.size(); for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { SASSERT(m.is_proof(p->get_arg(i))); proof *parent = to_app(p->get_arg(i)); @@ -206,10 +224,9 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { if (!m_active_hyps.contains(parent)) { SASSERT(!m_parent_hyps.contains(parent)); todo.push_back(parent); - dirty = true; } } - if (dirty) continue; + if (todo.size() > todo_sz) continue; todo.pop_back(); @@ -262,21 +279,10 @@ void hypothesis_reducer::collect_units(proof* pr) { } } -proof_ref hypothesis_reducer::reduce(proof* pr) { - compute_hypsets(pr); - collect_units(pr); - proof_ref res(compute_transformed_proof(pr), m); - SASSERT(res); - reset(); +proof* hypothesis_reducer::reduce_core(proof* pf) { + SASSERT(m.is_false(m.get_fact(pf))); - DEBUG_CODE(proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(res, side));); - return res; -} - -proof* hypothesis_reducer::compute_transformed_proof(proof* pf) { proof *res = NULL; ptr_vector todo; @@ -284,7 +290,7 @@ proof* hypothesis_reducer::compute_transformed_proof(proof* pf) { ptr_buffer args; bool dirty = false; - while (!todo.empty()) { + while (true) { proof *p, *tmp, *pp; unsigned todo_sz; @@ -311,58 +317,59 @@ proof* hypothesis_reducer::compute_transformed_proof(proof* pf) { todo.pop_back(); - // transform the proof + // transform the current proof node - // INV: whenever p is visited, active_hyps and parent_hyps - // have already been computed for everything in args. if (m.is_hypothesis(p)) { - // hyp: replace by a corresponding unit + // if possible, replace a hypothesis by a unit derivation if (m_units.find(m.get_fact(p), tmp)) { - // look up the proof of the unit: - // if there is a transformed proof use that one - // otherwise use the original proof + // use already transformed proof of the unit if it is available proof* proof_of_unit; if (!m_cache.find(tmp, proof_of_unit)) { proof_of_unit = tmp; } - // compute hypsets (have not been computed in general, - // since the unit can be anywhere in the proof) + // make sure hypsets for the unit are computed + // AG: is this needed? compute_hypsets(proof_of_unit); + SASSERT(m_parent_hyps.contains(proof_of_unit)); // if the transformation doesn't create a cycle, perform it - SASSERT(m_parent_hyps.contains(proof_of_unit)); expr_set* parent_hyps = m_parent_hyps.find(proof_of_unit); - if (!parent_hyps->contains(p)) - // hypsets have already been computed for proof_of_unit + if (!parent_hyps->contains(p)) { res = proof_of_unit; - // otherwise don't transform the proof and just use - // the hypothesis - else - // hypsets have already been computed for p + } + else { + // -- failed to transform the proof, perhaps bad + // -- choice of the proof of unit res = p; + } } - else - // hypsets have already been computed for p + else { + // -- no unit found to replace the hypothesis res = p; + } } - else if (!dirty) - res = p; + + else if (!dirty) {res = p;} + else if (m.is_lemma(p)) { - //lemma: reduce the premise; remove reduced consequences - //from conclusion + // lemma: reduce the premise; remove reduced consequences + // from conclusion SASSERT(args.size() == 1); res = mk_lemma_core(args[0], m.get_fact(p)); + // -- re-compute hypsets compute_hypsets(res); } else if (m.is_unit_resolution(p)) { // unit: reduce untis; reduce the first premise; rebuild // unit resolution res = mk_unit_resolution_core(args); + // -- re-compute hypsets compute_hypsets(res); } else { res = mk_proof_core(p, args); + // -- re-compute hypsets compute_hypsets(res); } diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index f348e71a6..2e1129896 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -76,19 +76,24 @@ private: // maps a unit literal to its derivation obj_map m_units; - // maps a proof to the set of proofs of active hypotheses + // maps a proof node to the set of its active (i.e., in scope) hypotheses obj_map m_active_hyps; - // maps a proof to the hypothesis-fact that are transitive - // parents of that proof. Used for cycle detection and avoidance. + + // maps a proof node to the set of all hypothesis-facts (active or + // not) that can reach it. Used for cycle detection and avoidance + // during proof transformation obj_map m_parent_hyps; void reset(); - // compute active_hyps and parent_hyps for pr + // compute active_hyps and parent_hyps for a given proof node and + // all its ancestors void compute_hypsets(proof* pr); // compute m_units void collect_units(proof* pr); - proof* compute_transformed_proof(proof* pf); + + // -- rewrite proof to reduce number of hypotheses used + proof* reduce_core(proof* pf); proof* mk_lemma_core(proof *pf, expr *fact); proof* mk_unit_resolution_core(ptr_buffer& args); From d379b14942e52c4ec4ab46919ccb577053e10c83 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 10:15:51 -0700 Subject: [PATCH 1009/1283] Cleanup spacer_iuc_solver --- src/muz/spacer/spacer_iuc_solver.cpp | 124 +++++++++++++-------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index a01f95c71..d924f36d7 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -255,61 +255,58 @@ void iuc_solver::get_iuc(expr_ref_vector &core) scoped_watch _t_ (m_iuc_watch); typedef obj_hashtable expr_set; - expr_set B; + expr_set core_lits; for (unsigned i = m_first_assumption, sz = m_assumptions.size(); i < sz; ++i) { expr *a = m_assumptions.get (i); app_ref def(m); - if (is_proxy(a, def)) { B.insert(def.get()); } - B.insert (a); + if (is_proxy(a, def)) { core_lits.insert(def.get()); } + core_lits.insert (a); } - if (m_iuc == 0) - { + if (m_iuc == 0) { // ORIGINAL PDR CODE + // AG: deprecated proof_ref pr(m); pr = get_proof (); farkas_learner learner_old; learner_old.set_split_literals(m_split_literals); - learner_old.get_lemmas (pr, B, core); + learner_old.get_lemmas (pr, core_lits, core); elim_proxies (core); simplify_bounds (core); // XXX potentially redundant } - else - { + else { // NEW IUC proof_ref res(get_proof(), m); // -- old hypothesis reducer while the new one is broken - if (m_old_hyp_reducer) - { - // preprocess proof in order to get a proof which is + if (m_old_hyp_reducer) { + // AG: deprecated + // pre-process proof in order to get a proof which is // better suited for unsat-core-extraction - if (m_print_farkas_stats) - { - iuc_proof iuc_before(m, res.get(), B); - verbose_stream() << "\nStats before transformation:"; + if (m_print_farkas_stats) { + iuc_proof iuc_before(m, res.get(), core_lits); + verbose_stream() << "\nOld reduce_hypotheses. Before:"; iuc_before.dump_farkas_stats(); } proof_utils::reduce_hypotheses(res); proof_utils::permute_unit_resolution(res); - if (m_print_farkas_stats) - { - iuc_proof iuc_after(m, res.get(), B); - verbose_stream() << "Stats after transformation:"; + if (m_print_farkas_stats) { + iuc_proof iuc_after(m, res.get(), core_lits); + verbose_stream() << "Old reduce_hypothesis. After:"; iuc_after.dump_farkas_stats(); } } - else // -- new hypothesis reducer + // -- new hypothesis reducer + else { - // preprocess proof in order to get a proof which is better suited for unsat-core-extraction - if (m_print_farkas_stats) - { - iuc_proof iuc_before(m, res.get(), B); - verbose_stream() << "\nStats before transformation:"; + // pre-process proof for better iuc extraction + if (m_print_farkas_stats) { + iuc_proof iuc_before(m, res.get(), core_lits); + verbose_stream() << "\n New hypothesis_reducer. Before:"; iuc_before.dump_farkas_stats(); } @@ -321,68 +318,67 @@ void iuc_solver::get_iuc(expr_ref_vector &core) res = pr2; - if (m_print_farkas_stats) - { - iuc_proof iuc_after(m, res.get(), B); - verbose_stream() << "Stats after transformation:"; + if (m_print_farkas_stats) { + iuc_proof iuc_after(m, res.get(), core_lits); + verbose_stream() << "New hypothesis_reducer. After:"; iuc_after.dump_farkas_stats(); } } - // construct proof object with contains partition information - iuc_proof iuc_pf(m, res, B); + iuc_proof iuc_pf(m, res, core_lits); - // configure learner unsat_core_learner learner(m, iuc_pf); - if (m_iuc_arith == 0 || m_iuc_arith > 3) - { - unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, - learner, m_split_literals, - false /* use constants from A */); - learner.register_plugin(plugin_farkas_lemma); + // -- register iuc plugins + if (m_iuc_arith == 0 || m_iuc_arith == 1) { + unsat_core_plugin_farkas_lemma* plugin = + alloc(unsat_core_plugin_farkas_lemma, + learner, m_split_literals, + (m_iuc_arith == 1) /* use constants from A */); + learner.register_plugin(plugin); } - else if (m_iuc_arith == 1) - { - unsat_core_plugin_farkas_lemma* plugin_farkas_lemma = alloc(unsat_core_plugin_farkas_lemma, - learner, m_split_literals, - true /* use constants from A */); - learner.register_plugin(plugin_farkas_lemma); + else if (m_iuc_arith == 2) { + SASSERT(false && "Broken"); + unsat_core_plugin_farkas_lemma_optimized* plugin = + alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m); + learner.register_plugin(plugin); } - else if (m_iuc_arith == 2) - { - unsat_core_plugin_farkas_lemma_optimized* plugin_farkas_lemma_optimized = alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m); - learner.register_plugin(plugin_farkas_lemma_optimized); + else if(m_iuc_arith == 3) { + unsat_core_plugin_farkas_lemma_bounded* plugin = + alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m); + learner.register_plugin(plugin); } - else if(m_iuc_arith == 3) - { - unsat_core_plugin_farkas_lemma_bounded* plugin_farkas_lemma_bounded = alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m); - learner.register_plugin(plugin_farkas_lemma_bounded); + else { + UNREACHABLE(); } - if (m_iuc == 2) - { - unsat_core_plugin_min_cut* plugin_min_cut = alloc(unsat_core_plugin_min_cut, learner, m); - learner.register_plugin(plugin_min_cut); + if (m_iuc == 1) { + // -- iuc based on the lowest cut in the proof + unsat_core_plugin_lemma* plugin = + alloc(unsat_core_plugin_lemma, learner); + learner.register_plugin(plugin); } - else - { - unsat_core_plugin_lemma* plugin_lemma = alloc(unsat_core_plugin_lemma, learner); - learner.register_plugin(plugin_lemma); + else if (m_iuc == 2) { + // -- iuc based on the smallest cut in the proof + unsat_core_plugin_min_cut* plugin = + alloc(unsat_core_plugin_min_cut, learner, m); + learner.register_plugin(plugin); + } + else { + UNREACHABLE(); } // compute interpolating unsat core learner.compute_unsat_core(core); - // postprocessing, TODO: elim_proxies should be done inside iuc_proof elim_proxies (core); - simplify_bounds (core); // XXX potentially redundant + // AG: this should be taken care of by minimizing the iuc cut + simplify_bounds (core); } IF_VERBOSE(2, verbose_stream () << "IUC Core:\n" - << mk_pp (mk_and (core), m) << "\n";); - + << mk_and(core) << "\n";); } void iuc_solver::refresh () From 33466c75a61ff2a1331936defe7b9c7eefb0b2d5 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 11:25:38 -0700 Subject: [PATCH 1010/1283] mss loop in prop_solver max sat assignment (mss) to replace core-based maxsmt() --- src/muz/spacer/spacer_prop_solver.cpp | 91 +++++++++++++++++++++++++++ src/muz/spacer/spacer_prop_solver.h | 1 + 2 files changed, 92 insertions(+) diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 87f998486..f2fcf5be7 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -35,6 +35,7 @@ Revision History: #include "muz/spacer/spacer_farkas_learner.h" #include "muz/spacer/spacer_prop_solver.h" +#include "model/model_evaluator.h" #include "muz/base/fixedpoint_params.hpp" namespace spacer { @@ -136,6 +137,96 @@ void prop_solver::assert_expr(expr * form, unsigned level) } +/// Local model guided maxsmt +lbool prop_solver::mss(expr_ref_vector &hard, expr_ref_vector &soft) { + // replace expressions by assumption literals + iuc_solver::scoped_mk_proxy _p_(*m_ctx, hard); + unsigned hard_sz = hard.size(); + + lbool res = m_ctx->check_sat(hard.size(), hard.c_ptr()); + // bail out if hard constraints are not sat, or if there are no + // soft constraints + if (res != l_true || soft.empty()) {return res;} + + // the main loop + + model_ref mdl; + m_ctx->get_model(mdl); + + // don't proxy soft literals. Assume that they are propositional. + hard.append(soft); + soft.reset(); + + + // hard is divided into 4 regions + // x < hard_sz ---> hard constraints + // hard_sz <= x < i ---> sat soft constraints + // i <= x < j ---> backbones (unsat soft constraints) + // j <= x < hard.size() ---> unprocessed soft constraints + unsigned i, j; + i = hard_sz; + j = hard_sz; + + while (j < hard.size()) { + model_evaluator mev(*mdl); + + // move all true soft constraints to [hard_sz, i) + for (unsigned k = j; k < hard.size(); ++k) { + expr_ref e(m); + e = hard.get(k); + if (!mev.is_false(e) /* true or unset */) { + expr_ref tmp(m); + tmp = hard.get(i); + hard[i] = e; + if (i < j) { + // tmp is a backbone, put it at j + if (j == k) {hard[j] = tmp;} + else /* j < k */ { + e = hard.get(j); + hard[j] = tmp; + hard[k] = e; + } + j++; + } + else { + // there are no backbone literals + hard[k] = tmp; + j++; + } + i++; + } + } + + // done with the model. Reset to avoid confusion in debugging + mdl.reset(); + + // -- grow the set of backbone literals + for (;j < hard.size(); ++j) { + res = m_ctx->check_sat(j+1, hard.c_ptr()); + if (res == l_false) { + // -- flip non-true literal to be false + hard[j] = m.mk_not(hard.get(j)); + } + else if (res == l_true) { + // -- get the model for the next iteration of the outer loop + m_ctx->get_model(mdl); + break; + } + else if (res == l_undef) { + // -- conservatively bail out + hard.resize(hard_sz); + return l_undef; + } + } + } + + // move sat soft constraints to the output vector + for (unsigned k = i; k < j; ++k) {soft.push_back(hard.get(k));} + // cleanup hard constraints + hard.resize(hard_sz); + return l_true; +} + /// Poor man's maxsat. No guarantees of maximum solution /// Runs maxsat loop on m_ctx Returns l_false if hard is unsat, /// otherwise reduces soft such that hard & soft is sat. diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index 295b47982..12d01ac40 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -71,6 +71,7 @@ private: expr_ref_vector &soft); lbool maxsmt(expr_ref_vector &hard, expr_ref_vector &soft); + lbool mss(expr_ref_vector &hard, expr_ref_vector &soft); public: From ac3bbed311548e28ecf90b2df7adfa1e5ec34a25 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 12:17:39 -0700 Subject: [PATCH 1011/1283] Remove dead code in spacer_manager - removed bg_assertions. Incompatible with mbp in spacer - removed unique number. Unused - removed mk_and() and switched to ast_util:mk_and() instead spacer_manager::mk_and() uses bool_rewriter to simplify the conjunction --- src/muz/spacer/spacer_context.cpp | 41 ++--- src/muz/spacer/spacer_context.h | 2 - src/muz/spacer/spacer_dl_interface.cpp | 15 +- src/muz/spacer/spacer_generalizers.cpp | 2 +- src/muz/spacer/spacer_manager.cpp | 126 +------------ src/muz/spacer/spacer_manager.h | 242 ++++--------------------- src/muz/spacer/spacer_prop_solver.cpp | 7 +- src/muz/spacer/spacer_prop_solver.h | 4 +- 8 files changed, 73 insertions(+), 366 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 5de817435..7d8ffc0aa 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -312,11 +312,10 @@ expr_ref pred_transformer::get_formulas(unsigned level, bool add_axioms) { expr_ref_vector res(m); if (add_axioms) { - res.push_back(pm.get_background()); res.push_back((level == 0)?initial_state():transition()); } m_frames.get_frame_geq_lemmas (level, res); - return pm.mk_and(res); + return mk_and(res); } bool pred_transformer::propagate_to_next_level (unsigned src_level) @@ -539,7 +538,7 @@ expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) expr_ref_vector lemmas (m); m_frames.get_frame_lemmas (level == -1 ? infty_level() : level, lemmas); - if (!lemmas.empty()) { result = pm.mk_and(lemmas); } + if (!lemmas.empty()) { result = mk_and(lemmas); } // replace local constants by bound variables. expr_substitution sub(m); @@ -611,7 +610,7 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, expr_ref_vector literals (m); compute_implicant_literals (mev, summary, literals); - return get_manager ().mk_and (literals); + return mk_and(literals); } @@ -857,10 +856,10 @@ bool pred_transformer::is_invariant(unsigned level, lemma* lem, bool pred_transformer::check_inductive(unsigned level, expr_ref_vector& state, unsigned& uses_level, unsigned weakness) { - manager& pm = get_manager(); expr_ref_vector conj(m), core(m); expr_ref states(m); - states = m.mk_not(pm.mk_and(state)); + states = mk_and(state); + states = m.mk_not(states); mk_assumptions(head(), states, conj); prop_solver::scoped_level _sl(m_solver, level); prop_solver::scoped_subset_core _sc (m_solver, true); @@ -972,7 +971,7 @@ void pred_transformer::init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transitions.push_back (m.mk_or (pred, m_extend_lit->get_arg (0))); if (!is_init [0]) { init_conds.push_back(m.mk_not(pred)); } - transition = pm.mk_and(transitions); + transition = mk_and(transitions); break; } default: @@ -992,11 +991,11 @@ void pred_transformer::init_rules(decl2rel const& pts, expr_ref& init, expr_ref& } } transitions.push_back(m.mk_or(disj.size(), disj.c_ptr())); - transition = pm.mk_and(transitions); + transition = mk_and(transitions); break; } // mk init condition - init = pm.mk_and (init_conds); + init = mk_and (init_conds); if (init_conds.empty ()) { // no rule has uninterpreted tail m_all_init = true; } @@ -1146,7 +1145,6 @@ void pred_transformer::init_atom( void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, expr_ref_vector& r) { - r.push_back(pm.get_background()); r.push_back((lvl == 0)?initial_state():transition()); for (unsigned i = 0; i < rules().size(); ++i) { add_premises(pts, lvl, *rules()[i], r); @@ -1736,7 +1734,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) // -- update m_trans with the pre-image of m_trans over the must summaries summaries.push_back (m_trans); - m_trans = get_manager ().mk_and (summaries); + m_trans = mk_and (summaries); summaries.reset (); if (!vars.empty()) { @@ -1765,7 +1763,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) summaries.push_back (m_trans); expr_ref post(m); - post = get_manager ().mk_and (summaries); + post = mk_and (summaries); summaries.reset (); if (!vars.empty()) { timeit _timer2 (is_trace_enabled("spacer_timeit"), @@ -1827,7 +1825,7 @@ pob *derivation::create_next_child () // if not true, bail out, the must summary of m_active is not strong enough // this is possible if m_post was weakened for some reason - if (!pt.is_must_reachable(pm.mk_and(summaries), &model)) { return nullptr; } + if (!pt.is_must_reachable(mk_and(summaries), &model)) { return nullptr; } model_evaluator_util mev (m); mev.set_model (*model); @@ -1840,7 +1838,7 @@ pob *derivation::create_next_child () u.push_back (rf->get ()); compute_implicant_literals (mev, u, lits); expr_ref v(m); - v = pm.mk_and (lits); + v = mk_and (lits); // XXX The summary is not used by anyone after this point m_premises[m_active].set_summary (v, true, &(rf->aux_vars ())); @@ -1860,7 +1858,7 @@ pob *derivation::create_next_child () summaries.reset (); summaries.push_back (v); summaries.push_back (active_trans); - m_trans = pm.mk_and (summaries); + m_trans = mk_and (summaries); // variables to eliminate vars.append (rf->aux_vars ().size (), rf->aux_vars ().c_ptr ()); @@ -3184,8 +3182,7 @@ lbool context::expand_node(pob& n) n.bump_weakness(); return expand_node(n); } - TRACE("spacer", tout << "unknown state: " - << mk_pp(m_pm.mk_and(cube), m) << "\n";); + TRACE("spacer", tout << "unknown state: " << mk_and(cube) << "\n";); throw unknown_exception(); } UNREACHABLE(); @@ -3305,14 +3302,14 @@ reach_fact *context::mk_reach_fact (pob& n, model_evaluator_util &mev, bool elim_aux = get_params ().spacer_elim_aux (); if (elim_aux) { vars.append(aux_vars.size(), aux_vars.c_ptr()); } - res = m_pm.mk_and (path_cons); + res = mk_and (path_cons); // -- pick an implicant from the path condition if (get_params().spacer_reach_dnf()) { expr_ref_vector u(m), lits(m); u.push_back (res); compute_implicant_literals (mev, u, lits); - res = m_pm.mk_and (lits); + res = mk_and (lits); } @@ -3405,7 +3402,7 @@ bool context::create_children(pob& n, datalog::rule const& r, n.get_skolems(vars); - expr_ref phi1 = m_pm.mk_and (Phi); + expr_ref phi1 = mk_and (Phi); qe_project (m, vars, phi1, mev.get_model (), true, m_use_native_mbp, !m_ground_cti); //qe::reduce_array_selects (*mev.get_model (), phi1); @@ -3413,7 +3410,7 @@ bool context::create_children(pob& n, datalog::rule const& r, TRACE ("spacer", tout << "Implicant\n"; - tout << mk_pp (m_pm.mk_and (Phi), m) << "\n"; + tout << mk_and (Phi) << "\n"; tout << "Projected Implicant\n" << mk_pp (phi1, m) << "\n"; ); @@ -3615,7 +3612,7 @@ expr_ref context::get_constraints (unsigned level) } if (constraints.empty()) { return expr_ref(m.mk_true(), m); } - return m_pm.mk_and (constraints); + return mk_and (constraints); } void context::add_constraint (expr *c, unsigned level) diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 596e5e047..9d3456f2b 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -895,8 +895,6 @@ public: void update_rules(datalog::rule_set& rules); - void set_axioms(expr* axioms) { m_pm.set_background(axioms); } - unsigned get_num_levels(func_decl* p); expr_ref get_cover_delta(int level, func_decl* p_orig, func_decl* p); diff --git a/src/muz/spacer/spacer_dl_interface.cpp b/src/muz/spacer/spacer_dl_interface.cpp index b121cf50a..cadbcfb0e 100644 --- a/src/muz/spacer/spacer_dl_interface.cpp +++ b/src/muz/spacer/spacer_dl_interface.cpp @@ -93,19 +93,14 @@ lbool dl_interface::query(expr * query) datalog::rule_set old_rules(rules0); func_decl_ref query_pred(m); rm.mk_query(query, m_ctx.get_rules()); - expr_ref bg_assertion = m_ctx.get_background_assertion(); check_reset(); TRACE("spacer", - if (!m.is_true(bg_assertion)) { - tout << "axioms:\n"; - tout << mk_pp(bg_assertion, m) << "\n"; - } - tout << "query: " << mk_pp(query, m) << "\n"; - tout << "rules:\n"; - m_ctx.display_rules(tout); - ); + tout << "query: " << mk_pp(query, m) << "\n"; + tout << "rules:\n"; + m_ctx.display_rules(tout); + ); apply_default_transformation(m_ctx); @@ -161,7 +156,6 @@ lbool dl_interface::query(expr * query) m_context->set_proof_converter(m_ctx.get_proof_converter()); m_context->set_model_converter(m_ctx.get_model_converter()); m_context->set_query(query_pred); - m_context->set_axioms(bg_assertion); m_context->update_rules(m_spacer_rules); if (m_spacer_rules.get_rules().empty()) { @@ -255,7 +249,6 @@ lbool dl_interface::query_from_lvl(expr * query, unsigned lvl) m_context->set_proof_converter(m_ctx.get_proof_converter()); m_context->set_model_converter(m_ctx.get_model_converter()); m_context->set_query(query_pred); - m_context->set_axioms(bg_assertion); m_context->update_rules(m_spacer_rules); if (m_spacer_rules.get_rules().empty()) { diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 3f6e28be6..34f1eb730 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -289,7 +289,7 @@ void lemma_array_eq_generalizer::operator() (lemma_ref &lemma) // } TRACE("core_array_eq", tout << "new possible core " - << mk_pp(pm.mk_and(lits), m) << "\n";); + << mk_and(lits) << "\n";); pred_transformer &pt = lemma->get_pob()->pt(); diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index c46c31924..04d3c09d4 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -168,8 +168,8 @@ void inductive_property::display(datalog::rule_manager& rm, ptr_vector manager::get_state_suffixes() -{ + +static std::vector state_suffixes() { std::vector res; res.push_back("_n"); return res; @@ -177,15 +177,11 @@ std::vector manager::get_state_suffixes() manager::manager(unsigned max_num_contexts, ast_manager& manager) : m(manager), - m_brwr(m), - m_mux(m, get_state_suffixes()), - m_background(m.mk_true(), m), + m_mux(m, state_suffixes()), m_contexts(m, max_num_contexts), m_contexts2(m, max_num_contexts), - m_contexts3(m, max_num_contexts), - m_next_unique_num(0) -{ -} + m_contexts3(m, max_num_contexts) +{} void manager::add_new_state(func_decl * s) @@ -195,7 +191,6 @@ void manager::add_new_state(func_decl * s) SASSERT(o_index(0) == 1); //we assume this in the number of retrieved symbols m_mux.create_tuple(s, s->get_arity(), s->get_domain(), s->get_range(), 2, vect); - m_o0_preds.push_back(vect[o_index(0)]); } func_decl * manager::get_o_pred(func_decl* s, unsigned idx) @@ -218,117 +213,6 @@ func_decl * manager::get_n_pred(func_decl* s) return res; } -void manager::mk_model_into_cube(const expr_ref_vector & mdl, expr_ref & res) -{ - m_brwr.mk_and(mdl.size(), mdl.c_ptr(), res); -} - -void manager::mk_core_into_cube(const expr_ref_vector & core, expr_ref & res) -{ - m_brwr.mk_and(core.size(), core.c_ptr(), res); -} - -void manager::mk_cube_into_lemma(expr * cube, expr_ref & res) -{ - m_brwr.mk_not(cube, res); -} - -void manager::mk_lemma_into_cube(expr * lemma, expr_ref & res) -{ - m_brwr.mk_not(lemma, res); -} - -expr_ref manager::mk_and(unsigned sz, expr* const* exprs) -{ - expr_ref result(m); - m_brwr.mk_and(sz, exprs, result); - return result; -} - -expr_ref manager::mk_or(unsigned sz, expr* const* exprs) -{ - expr_ref result(m); - m_brwr.mk_or(sz, exprs, result); - return result; -} - -expr_ref manager::mk_not_and(expr_ref_vector const& conjs) -{ - expr_ref result(m), e(m); - expr_ref_vector es(conjs); - flatten_and(es); - for (unsigned i = 0; i < es.size(); ++i) { - m_brwr.mk_not(es[i].get(), e); - es[i] = e; - } - m_brwr.mk_or(es.size(), es.c_ptr(), result); - return result; -} - -void manager::get_or(expr* e, expr_ref_vector& result) -{ - result.push_back(e); - for (unsigned i = 0; i < result.size();) { - e = result[i].get(); - if (m.is_or(e)) { - result.append(to_app(e)->get_num_args(), to_app(e)->get_args()); - result[i] = result.back(); - result.pop_back(); - } else { - ++i; - } - } -} - -bool manager::try_get_state_and_value_from_atom(expr * atom0, app *& state, app_ref& value) -{ - if (!is_app(atom0)) { - return false; - } - app * atom = to_app(atom0); - expr * arg1; - expr * arg2; - app * candidate_state; - app_ref candidate_value(m); - if (m.is_not(atom, arg1)) { - if (!is_app(arg1)) { - return false; - } - candidate_state = to_app(arg1); - candidate_value = m.mk_false(); - } else if (m.is_eq(atom, arg1, arg2)) { - if (!is_app(arg1) || !is_app(arg2)) { - return false; - } - if (!m_mux.is_muxed(to_app(arg1)->get_decl())) { - std::swap(arg1, arg2); - } - candidate_state = to_app(arg1); - candidate_value = to_app(arg2); - } else { - candidate_state = atom; - candidate_value = m.mk_true(); - } - if (!m_mux.is_muxed(candidate_state->get_decl())) { - return false; - } - state = candidate_state; - value = candidate_value; - return true; -} - -bool manager::try_get_state_decl_from_atom(expr * atom, func_decl *& state) -{ - app_ref dummy_value_holder(m); - app * s; - if (try_get_state_and_value_from_atom(atom, s, dummy_value_holder)) { - state = s->get_decl(); - return true; - } else { - return false; - } -} - /** * Create a new skolem constant */ diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index 32cf61d57..58b5aca07 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -37,9 +37,7 @@ Revision History: #include "muz/spacer/spacer_smt_context_manager.h" #include "muz/base/dl_rule.h" -namespace smt { -class context; -} +namespace smt {class context;} namespace spacer { @@ -67,32 +65,24 @@ public: m_relation_info(relations) {} std::string to_string() const; - expr_ref to_expr() const; - void to_model(model_ref& md) const; - - void display(datalog::rule_manager& rm, ptr_vector const& rules, std::ostream& out) const; + void display(datalog::rule_manager& rm, + ptr_vector const& rules, + std::ostream& out) const; }; class manager { ast_manager& m; - mutable bool_rewriter m_brwr; - + // manager of multiplexed names sym_mux m_mux; - expr_ref m_background; - decl_vector m_o0_preds; + + // three solver pools for different queries spacer::smt_context_manager m_contexts; spacer::smt_context_manager m_contexts2; spacer::smt_context_manager m_contexts3; - /** whenever we need an unique number, we get this one and increase */ - unsigned m_next_unique_num; - - - static std::vector get_state_suffixes(); - unsigned n_index() const { return 0; } unsigned o_index(unsigned i) const { return i + 1; } @@ -102,218 +92,68 @@ public: manager(unsigned max_num_contexts, ast_manager & manager); ast_manager& get_manager() const { return m; } - bool_rewriter& get_brwr() const { return m_brwr; } - expr_ref mk_and(unsigned sz, expr* const* exprs); - expr_ref mk_and(expr_ref_vector const& exprs) - { - return mk_and(exprs.size(), exprs.c_ptr()); - } - expr_ref mk_and(expr* a, expr* b) - { - expr* args[2] = { a, b }; - return mk_and(2, args); - } - expr_ref mk_or(unsigned sz, expr* const* exprs); - expr_ref mk_or(expr_ref_vector const& exprs) - { - return mk_or(exprs.size(), exprs.c_ptr()); - } - - expr_ref mk_not_and(expr_ref_vector const& exprs); - - void get_or(expr* e, expr_ref_vector& result); + // management of mux names //"o" predicates stand for the old states and "n" for the new states func_decl * get_o_pred(func_decl * s, unsigned idx); func_decl * get_n_pred(func_decl * s); - /** - Marks symbol as non-model which means it will not appear in models collected by - get_state_cube_from_model function. - This is to take care of auxiliary symbols introduced by the disjunction relations - to relativize lemmas coming from disjuncts. - */ - void mark_as_non_model(func_decl * p) - { - m_mux.mark_as_non_model(p); - } - - - func_decl * const * begin_o0_preds() const { return m_o0_preds.begin(); } - func_decl * const * end_o0_preds() const { return m_o0_preds.end(); } - - bool is_state_pred(func_decl * p) const { return m_mux.is_muxed(p); } - func_decl * to_o0(func_decl * p) { return m_mux.conv(m_mux.get_primary(p), 0, o_index(0)); } - - bool is_o(func_decl * p, unsigned idx) const - { - return m_mux.has_index(p, o_index(idx)); - } - void get_o_index(func_decl* p, unsigned& idx) const - { + void get_o_index(func_decl* p, unsigned& idx) const { m_mux.try_get_index(p, idx); SASSERT(idx != n_index()); idx--; // m_mux has indices starting at 1 } - bool is_o(expr* e, unsigned idx) const - { - return is_app(e) && is_o(to_app(e)->get_decl(), idx); - } - bool is_o(func_decl * p) const - { + + bool is_o(func_decl * p, unsigned idx) const + {return m_mux.has_index(p, o_index(idx));} + bool is_o(func_decl * p) const { unsigned idx; return m_mux.try_get_index(p, idx) && idx != n_index(); } bool is_o(expr* e) const - { - return is_app(e) && is_o(to_app(e)->get_decl()); - } + {return is_app(e) && is_o(to_app(e)->get_decl());} + bool is_o(expr* e, unsigned idx) const + {return is_app(e) && is_o(to_app(e)->get_decl(), idx);} bool is_n(func_decl * p) const - { - return m_mux.has_index(p, n_index()); - } + {return m_mux.has_index(p, n_index());} bool is_n(expr* e) const - { - return is_app(e) && is_n(to_app(e)->get_decl()); - } - - /** true if p should not appead in models propagates into child relations */ - bool is_non_model_sym(func_decl * p) const - { return m_mux.is_non_model_sym(p); } + {return is_app(e) && is_n(to_app(e)->get_decl());} /** true if f doesn't contain any n predicates */ bool is_o_formula(expr * f) const - { - return !m_mux.contains(f, n_index()); - } - + {return !m_mux.contains(f, n_index());} /** true if f contains only o state preds of index o_idx */ bool is_o_formula(expr * f, unsigned o_idx) const - { - return m_mux.is_homogenous_formula(f, o_index(o_idx)); - } + {return m_mux.is_homogenous_formula(f, o_index(o_idx));} /** true if f doesn't contain any o predicates */ bool is_n_formula(expr * f) const - { - return m_mux.is_homogenous_formula(f, n_index()); - } + {return m_mux.is_homogenous_formula(f, n_index());} func_decl * o2n(func_decl * p, unsigned o_idx) const - { - return m_mux.conv(p, o_index(o_idx), n_index()); - } + {return m_mux.conv(p, o_index(o_idx), n_index());} func_decl * o2o(func_decl * p, unsigned src_idx, unsigned tgt_idx) const - { - return m_mux.conv(p, o_index(src_idx), o_index(tgt_idx)); - } + {return m_mux.conv(p, o_index(src_idx), o_index(tgt_idx));} func_decl * n2o(func_decl * p, unsigned o_idx) const - { - return m_mux.conv(p, n_index(), o_index(o_idx)); - } + {return m_mux.conv(p, n_index(), o_index(o_idx));} void formula_o2n(expr * f, expr_ref & result, unsigned o_idx, bool homogenous = true) const - { m_mux.conv_formula(f, o_index(o_idx), n_index(), result, homogenous); } + {m_mux.conv_formula(f, o_index(o_idx), n_index(), result, homogenous);} void formula_n2o(expr * f, expr_ref & result, unsigned o_idx, bool homogenous = true) const - { m_mux.conv_formula(f, n_index(), o_index(o_idx), result, homogenous); } + {m_mux.conv_formula(f, n_index(), o_index(o_idx), result, homogenous);} void formula_n2o(unsigned o_idx, bool homogenous, expr_ref & result) const - { m_mux.conv_formula(result.get(), n_index(), o_index(o_idx), result, homogenous); } + {m_mux.conv_formula(result.get(), n_index(), o_index(o_idx), result, homogenous);} - void formula_o2o(expr * src, expr_ref & tgt, unsigned src_idx, unsigned tgt_idx, bool homogenous = true) const - { m_mux.conv_formula(src, o_index(src_idx), o_index(tgt_idx), tgt, homogenous); } - - /** - Return true if all state symbols which e contains are of one kind (either "n" or one of "o"). - */ - bool is_homogenous_formula(expr * e) const - { - return m_mux.is_homogenous_formula(e); - } - - /** - Collect indices used in expression. - */ - void collect_indices(expr* e, unsigned_vector& indices) const - { - m_mux.collect_indices(e, indices); - } - - /** - Collect used variables of each index. - */ - void collect_variables(expr* e, vector >& vars) const - { - m_mux.collect_variables(e, vars); - } - - /** - Return true iff both s1 and s2 are either "n" or "o" of the same index. - If one (or both) of them are not state symbol, return false. - */ - bool have_different_state_kinds(func_decl * s1, func_decl * s2) const - { - unsigned i1, i2; - return m_mux.try_get_index(s1, i1) && m_mux.try_get_index(s2, i2) && i1 != i2; - } - - /** - Increase indexes of state symbols in formula by dist. - The 'N' index becomes 'O' index with number dist-1. - */ - void formula_shift(expr * src, expr_ref & tgt, unsigned dist) const - { - SASSERT(n_index() == 0); - SASSERT(o_index(0) == 1); - m_mux.shift_formula(src, dist, tgt); - } - - void mk_model_into_cube(const expr_ref_vector & mdl, expr_ref & res); - void mk_core_into_cube(const expr_ref_vector & core, expr_ref & res); - void mk_cube_into_lemma(expr * cube, expr_ref & res); - void mk_lemma_into_cube(expr * lemma, expr_ref & res); - - /** - Remove from vec all atoms that do not have an "o" state. - The order of elements in vec may change. - An assumption is that atoms having "o" state of given index - do not have "o" states of other indexes or "n" states. - */ - void filter_o_atoms(expr_ref_vector& vec, unsigned o_idx) const - { m_mux.filter_idx(vec, o_index(o_idx)); } - void filter_n_atoms(expr_ref_vector& vec) const - { m_mux.filter_idx(vec, n_index()); } - - /** - Partition literals into o_lits and others. - */ - void partition_o_atoms(expr_ref_vector const& lits, - expr_ref_vector& o_lits, - expr_ref_vector& other, - unsigned o_idx) const - { - m_mux.partition_o_idx(lits, o_lits, other, o_index(o_idx)); - } - - void filter_out_non_model_atoms(expr_ref_vector& vec) const - { m_mux.filter_non_model_lits(vec); } - - bool try_get_state_and_value_from_atom(expr * atom, app *& state, app_ref& value); - bool try_get_state_decl_from_atom(expr * atom, func_decl *& state); + void formula_o2o(expr * src, expr_ref & tgt, unsigned src_idx, + unsigned tgt_idx, bool homogenous = true) const + {m_mux.conv_formula(src, o_index(src_idx), o_index(tgt_idx), tgt, homogenous);} - std::string pp_model(const model_core & mdl) const - { return m_mux.pp_model(mdl); } - - - void set_background(expr* b) { m_background = b; } - - expr* get_background() const { return m_background; } - - unsigned get_unique_num() { return m_next_unique_num++; } - + // three different solvers with three different sets of parameters + // different solvers are used for different types of queries in spacer solver* mk_fresh() {return m_contexts.mk_fresh();} smt_params& fparams() { return m_contexts.fparams(); } solver* mk_fresh2() {return m_contexts2.mk_fresh();} @@ -323,32 +163,30 @@ public: - void collect_statistics(statistics& st) const - { + void collect_statistics(statistics& st) const { m_contexts.collect_statistics(st); m_contexts2.collect_statistics(st); m_contexts3.collect_statistics(st); } - void reset_statistics() - { + void reset_statistics() { m_contexts.reset_statistics(); m_contexts2.reset_statistics(); m_contexts3.reset_statistics(); } }; +/** Skolem constants for quantified spacer */ app* mk_zk_const (ast_manager &m, unsigned idx, sort *s); int find_zk_const(expr* e, app_ref_vector &out); -inline int find_zk_const(expr_ref_vector const &v, app_ref_vector &out) { - return find_zk_const (mk_and(v), out); -} +inline int find_zk_const(expr_ref_vector const &v, app_ref_vector &out) +{return find_zk_const (mk_and(v), out);} + bool has_zk_const(expr* e); bool is_zk_const (const app *a, int &n); -struct sk_lt_proc { - bool operator()(const app* a1, const app* a2); -}; +struct sk_lt_proc {bool operator()(const app* a1, const app* a2);}; + } #endif diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index f2fcf5be7..1dd4515a7 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -40,9 +40,9 @@ Revision History: namespace spacer { -prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& name) : +prop_solver::prop_solver(spacer::manager& pm, + fixedpoint_params const& p, symbol const& name) : m(pm.get_manager()), - m_pm(pm), m_name(name), m_ctx(nullptr), m_pos_level_atoms(m), @@ -73,9 +73,6 @@ prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& p.spacer_iuc_print_farkas_stats(), p.spacer_iuc_old_hyp_reducer(), p.spacer_iuc_split_farkas_literals()); - - for (unsigned i = 0; i < 2; ++i) - { m_contexts[i]->assert_expr(m_pm.get_background()); } } void prop_solver::add_level() diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index 12d01ac40..d10ebcfcd 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -41,7 +41,6 @@ class prop_solver { private: ast_manager& m; - manager& m_pm; symbol m_name; smt_params* m_fparams[2]; solver* m_solvers[2]; @@ -75,7 +74,8 @@ private: public: - prop_solver(spacer::manager& pm, fixedpoint_params const& p, symbol const& name); + prop_solver(spacer::manager &manager, + fixedpoint_params const& p, symbol const& name); void set_core(expr_ref_vector* core) { m_core = core; } From 3f9b5bce99d0dcbc1b59fdb36d986bd73c2d83bf Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 13:22:22 -0700 Subject: [PATCH 1012/1283] Remove debug function --- src/muz/spacer/spacer_context.cpp | 17 +++++++++-------- src/muz/spacer/spacer_context.h | 2 -- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 7d8ffc0aa..eccc156de 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1001,6 +1001,14 @@ void pred_transformer::init_rules(decl2rel const& pts, expr_ref& init, expr_ref& } } +static bool is_all_non_null(app_ref_vector const& v) +{ + for (unsigned i = 0; i < v.size(); ++i) { + if (!v[i]) { return false; } + } + return true; +} + void pred_transformer::init_rule( decl2rel const& pts, datalog::rule const& rule, @@ -1035,7 +1043,7 @@ void pred_transformer::init_rule( fml = mk_and (tail); ground_free_vars (fml, var_reprs, aux_vars, ut_size == 0); - SASSERT(check_filled(var_reprs)); + SASSERT(is_all_non_null(var_reprs)); expr_ref tmp(m); var_subst (m, false)(fml, @@ -1074,13 +1082,6 @@ void pred_transformer::init_rule( tout << "\n";); } -bool pred_transformer::check_filled(app_ref_vector const& v) const -{ - for (unsigned i = 0; i < v.size(); ++i) { - if (!v[i]) { return false; } - } - return true; -} // create constants for free variables in tail. void pred_transformer::ground_free_vars(expr* e, app_ref_vector& vars, diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 9d3456f2b..0d4db2279 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -320,8 +320,6 @@ class pred_transformer { void simplify_formulas(tactic& tac, expr_ref_vector& fmls); // Debugging - bool check_filled(app_ref_vector const& v) const; - void add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r); expr* mk_fresh_reach_case_var (); From ec8f99fee79420ba334d2239715c476b69d588fb Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 13:31:28 -0700 Subject: [PATCH 1013/1283] Rename expand_node --> expand_pob --- src/muz/spacer/spacer_context.cpp | 22 +++++++++++----------- src/muz/spacer/spacer_context.h | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index eccc156de..f9603bd62 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2854,7 +2854,7 @@ bool context::check_reachability () node = m_pob_queue.top (); SASSERT (node->level () <= m_pob_queue.max_level ()); - switch (expand_node(*node)) { + switch (expand_pob(*node)) { case l_true: SASSERT (m_pob_queue.top () == node.get ()); m_pob_queue.pop (); @@ -2982,23 +2982,23 @@ bool context::is_reachable(pob &n) } //this processes a goal and creates sub-goal -lbool context::expand_node(pob& n) +lbool context::expand_pob(pob& n) { pob::on_expand_event _evt(n); TRACE ("spacer", - tout << "expand-node: " << n.pt().head()->get_name() + tout << "expand-pob: " << n.pt().head()->get_name() << " level: " << n.level() << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" << mk_pp(n.post(), m) << "\n";); STRACE ("spacer.expand-add", - tout << "expand-node: " << n.pt().head()->get_name() + tout << "expand-pob: " << n.pt().head()->get_name() << " level: " << n.level() << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" << mk_epp(n.post(), m) << "\n\n";); TRACE ("core_array_eq", - tout << "expand-node: " << n.pt().head()->get_name() + tout << "expand-pob: " << n.pt().head()->get_name() << " level: " << n.level() << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" << mk_pp(n.post(), m) << "\n";); @@ -3109,7 +3109,7 @@ lbool context::expand_node(pob& n) // n is unreachable, create new summary facts case l_false: { timeit _timer (is_trace_enabled("spacer_timeit"), - "spacer::expand_node::false", + "spacer::expand_pob::false", verbose_stream ()); // -- only update expanded level when new lemmas are generated at it. @@ -3164,7 +3164,7 @@ lbool context::expand_node(pob& n) if (n.weakness() < 100 /* MAX_WEAKENSS */) { bool has_new_child = false; SASSERT(m_weak_abs); - m_stats.m_expand_node_undef++; + m_stats.m_expand_pob_undef++; if (r && r->get_uninterpreted_tail_size() > 0) { model_evaluator_util mev(m); mev.set_model(*model); @@ -3181,7 +3181,7 @@ lbool context::expand_node(pob& n) // -- failed to create a child, bump weakness and repeat // -- the recursion is bounded by the levels of weakness supported n.bump_weakness(); - return expand_node(n); + return expand_pob(n); } TRACE("spacer", tout << "unknown state: " << mk_and(cube) << "\n";); throw unknown_exception(); @@ -3500,8 +3500,8 @@ void context::collect_statistics(statistics& st) const st.update("SPACER inductive level", m_inductive_lvl); // -- length of the counterexample st.update("SPACER cex depth", m_stats.m_cex_depth); - // -- number of times expand_node resulted in undef - st.update("SPACER expand node undef", m_stats.m_expand_node_undef); + // -- number of times expand_pobresulted in undef + st.update("SPACER expand pob undef", m_stats.m_expand_pob_undef); // -- number of distinct lemmas constructed st.update("SPACER num lemmas", m_stats.m_num_lemmas); // -- number of restarts taken @@ -3730,7 +3730,7 @@ inline bool pob_lt::operator() (const pob *pn1, const pob *pn2) const /** XXX Identical nodes. This should not happen. However, * currently, when propagating reachability, we might call - * expand_node() twice on the same node, causing it to generate + * expand_pob() twice on the same node, causing it to generate * the same proof obligation multiple times */ return &n1 < &n2; } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 0d4db2279..38543f25f 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -744,7 +744,7 @@ class context { unsigned m_max_query_lvl; unsigned m_max_depth; unsigned m_cex_depth; - unsigned m_expand_node_undef; + unsigned m_expand_pob_undef; unsigned m_num_lemmas; unsigned m_num_restarts; unsigned m_num_lemmas_imported; @@ -792,7 +792,7 @@ class context { bool propagate(unsigned min_prop_lvl, unsigned max_prop_lvl, unsigned full_prop_lvl); bool is_reachable(pob &n); - lbool expand_node(pob& n); + lbool expand_pob(pob &n); reach_fact *mk_reach_fact (pob& n, model_evaluator_util &mev, datalog::rule const& r); bool create_children(pob& n, datalog::rule const& r, From a696a40a3af335daea2732d8da358a2ec78114c3 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 13:43:35 -0700 Subject: [PATCH 1014/1283] Refactoring --- src/muz/spacer/spacer_context.cpp | 32 +++++++++++++++++++++++-------- src/muz/spacer/spacer_context.h | 11 +++-------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index f9603bd62..923ecb5b8 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2981,6 +2981,24 @@ bool context::is_reachable(pob &n) return next ? is_reachable(*next) : true; } +void context::dump_json() +{ + if(m_params.spacer_print_json().size()) { + std::ofstream of; + of.open(m_params.spacer_print_json().bare_str()); + m_json_marshaller.marshal(of); + of.close(); + } +} + +void context::predecessor_eh() +{ + for (unsigned i = 0; i < m_callbacks.size(); i++) { + if(m_callbacks[i]->predecessor()) + m_callbacks[i]->predecessor_eh(); + } +} + //this processes a goal and creates sub-goal lbool context::expand_pob(pob& n) { @@ -3040,10 +3058,7 @@ lbool context::expand_pob(pob& n) tout << "This pob can be blocked by instantiation\n";); } - for (unsigned i = 0; i < m_callbacks.size(); i++){ - if(m_callbacks[i]->predecessor()) - m_callbacks[i]->predecessor_eh(); - } + predecessor_eh(); lbool res = n.pt ().is_reachable (n, &cube, &model, uses_level, is_concrete, r, reach_pred_used, num_reuse_reach); @@ -3106,8 +3121,9 @@ lbool context::expand_pob(pob& n) return l_undef; } + case l_false: // n is unreachable, create new summary facts - case l_false: { + { timeit _timer (is_trace_enabled("spacer_timeit"), "spacer::expand_pob::false", verbose_stream ()); @@ -3133,9 +3149,9 @@ lbool context::expand_pob(pob& n) (*m_lemma_generalizers[i])(lemma); } DEBUG_CODE( - lemma_sanity_checker sanity_checker(*this); - sanity_checker(lemma); - ); + lemma_sanity_checker sanity_checker(*this); + sanity_checker(lemma); + ); TRACE("spacer", tout << "invariant state: " diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 38543f25f..5eedb1736 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -824,14 +824,9 @@ class context { unsigned get_cex_depth (); - void dump_json() { - if(m_params.spacer_print_json().size()) { - std::ofstream of; - of.open(m_params.spacer_print_json().bare_str()); - m_json_marshaller.marshal(of); - of.close(); - } - } + void dump_json(); + + void predecessor_eh(); public: /** From 05c8067392e94d22e8fa7e4314a33e94bea5e248 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 14:50:58 -0700 Subject: [PATCH 1015/1283] Changed pob queue management strategy in spacer_context --- src/muz/spacer/spacer_context.cpp | 87 ++++++++++++++++++++----------- src/muz/spacer/spacer_context.h | 7 ++- 2 files changed, 61 insertions(+), 33 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 923ecb5b8..48cbbd258 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2004,6 +2004,8 @@ void pob_queue::reset() } void pob_queue::push(pob &n) { + TRACE("pob_queue", + tout << "pob_queue::push(" << n.post()->get_id() << ")\n";); m_obligations.push (&n); n.get_context().new_pob_eh(&n); } @@ -2787,6 +2789,8 @@ bool context::check_reachability () pob_ref last_reachable; + pob_ref_buffer new_pobs; + if (get_params().spacer_reset_obligation_queue()) { m_pob_queue.reset(); } unsigned initial_size = m_stats.m_num_lemmas; @@ -2853,40 +2857,44 @@ bool context::check_reachability () } node = m_pob_queue.top (); + m_pob_queue.pop(); + unsigned old_sz = m_pob_queue.size(); SASSERT (node->level () <= m_pob_queue.max_level ()); - switch (expand_pob(*node)) { + switch (expand_pob(*node, new_pobs)) { case l_true: - SASSERT (m_pob_queue.top () == node.get ()); - m_pob_queue.pop (); + SASSERT(m_pob_queue.size() == old_sz); + SASSERT(new_pobs.empty()); last_reachable = node; last_reachable->close (); - if (m_pob_queue.is_root(*node)) { return true; } + if (m_pob_queue.is_root(*node)) {return true;} break; case l_false: - SASSERT (m_pob_queue.top () == node.get ()); - m_pob_queue.pop (); + SASSERT(m_pob_queue.size() == old_sz); + for (auto pob : new_pobs) { + if (is_requeue(*pob)) {m_pob_queue.push(*pob);} + } - if (node->is_dirty()) { node->clean(); } - - node->inc_level (); - if (get_params ().pdr_flexible_trace () && - (node->level () >= m_pob_queue.max_level () || - m_pob_queue.max_level () - node->level () - <= get_params ().pdr_flexible_trace_depth ())) - { m_pob_queue.push(*node); } - - if (m_pob_queue.is_root(*node)) { return false; } + if (m_pob_queue.is_root(*node)) {return false;} break; case l_undef: - // SASSERT (m_pob_queue.top () != node.get ()); + SASSERT(m_pob_queue.size() == old_sz); + for (auto pob : new_pobs) {m_pob_queue.push(*pob);} break; } + new_pobs.reset(); } UNREACHABLE(); return false; } +/// returns true if the given pob can be re-scheduled +bool context::is_requeue(pob &n) { + if (!get_params().pdr_flexible_trace()) {return false;} + unsigned max_depth = get_params().pdr_flexible_trace_depth(); + return (n.level() >= m_pob_queue.max_level() || + m_pob_queue.max_level() - n.level() <= max_depth); +} /// check whether node n is concretely reachable bool context::is_reachable(pob &n) { @@ -2999,8 +3007,11 @@ void context::predecessor_eh() } } -//this processes a goal and creates sub-goal -lbool context::expand_pob(pob& n) +/// Checks whether the given pob is reachable +/// returns l_true if reachable, l_false if unreachable +/// returns l_undef if reachability cannot be decided +/// out contains new pobs to add to the queue in case the result is l_undef +lbool context::expand_pob(pob& n, pob_ref_buffer &out) { pob::on_expand_event _evt(n); TRACE ("spacer", @@ -3049,11 +3060,12 @@ lbool context::expand_pob(pob& n) IF_VERBOSE (1, verbose_stream () << " K " << std::fixed << std::setprecision(2) << watch.get_seconds () << "\n";); - + n.inc_level(); + out.push_back(&n); return l_false; } - if (n.pt().is_qblocked(n)) { + if (/* XXX noop */ n.pt().is_qblocked(n)) { STRACE("spacer.expand-add", tout << "This pob can be blocked by instantiation\n";); } @@ -3099,10 +3111,8 @@ lbool context::expand_pob(pob& n) // move derivation over to the next obligation next->set_derivation (deriv.detach()); - // remove the current node from the queue if it is at the top - if (m_pob_queue.top() == &n) { m_pob_queue.pop(); } - - m_pob_queue.push (*next); + // this is the new node to add + out.push_back (next); } } @@ -3114,7 +3124,9 @@ lbool context::expand_pob(pob& n) } // create a child of n - VERIFY(create_children (n, *r, mev, reach_pred_used)); + + out.push_back(&n); + VERIFY(create_children (n, *r, mev, reach_pred_used, out)); IF_VERBOSE(1, verbose_stream () << " U " << std::fixed << std::setprecision(2) << watch.get_seconds () << "\n";); @@ -3165,7 +3177,14 @@ lbool context::expand_pob(pob& n) if (v && get_params().spacer_use_lemma_as_cti()) { n.new_post (mk_and(lemma->get_cube())); n.set_farkas_generalizer (false); + // XXX hack while refactoring is in progress + n.clean(); } + + // schedule the node to be placed back in the queue + n.inc_level(); + out.push_back(&n); + CASSERT("spacer", n.level() == 0 || check_invariant(n.level()-1)); @@ -3187,17 +3206,22 @@ lbool context::expand_pob(pob& n) // do not trust reach_pred_used for (unsigned i = 0, sz = reach_pred_used.size(); i < sz; ++i) { reach_pred_used[i] = false; } - has_new_child = create_children(n,*r,mev,reach_pred_used); + has_new_child = create_children(n,*r,mev,reach_pred_used, out); } IF_VERBOSE(1, verbose_stream() << " UNDEF " << std::fixed << std::setprecision(2) << watch.get_seconds () << "\n";); - if (has_new_child) { return l_undef; } + if (has_new_child) { + // ensure that n is placed back in the queue + out.push_back(&n); + return l_undef; + } // -- failed to create a child, bump weakness and repeat // -- the recursion is bounded by the levels of weakness supported + SASSERT(out.empty()); n.bump_weakness(); - return expand_pob(n); + return expand_pob(n, out); } TRACE("spacer", tout << "unknown state: " << mk_and(cube) << "\n";); throw unknown_exception(); @@ -3372,7 +3396,8 @@ reach_fact *context::mk_reach_fact (pob& n, model_evaluator_util &mev, */ bool context::create_children(pob& n, datalog::rule const& r, model_evaluator_util &mev, - const vector &reach_pred_used) + const vector &reach_pred_used, + pob_ref_buffer &out) { scoped_watch _w_ (m_create_children_watch); @@ -3486,7 +3511,7 @@ bool context::create_children(pob& n, datalog::rule const& r, if (m_weak_abs && (!mev.is_true(T) || !mev.is_true(phi))) { kid->reset_derivation(); } - m_pob_queue.push (*kid); + out.push_back(kid); m_stats.m_num_queries++; return true; } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 5eedb1736..475a7472c 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -53,6 +53,7 @@ typedef obj_map decl2rel; class pob; typedef ref pob_ref; typedef sref_vector pob_ref_vector; +typedef sref_buffer pob_ref_buffer; class reach_fact; typedef ref reach_fact_ref; @@ -788,16 +789,18 @@ class context { // Functions used by search. lbool solve_core (unsigned from_lvl = 0); + bool is_requeue(pob &n); bool check_reachability (); bool propagate(unsigned min_prop_lvl, unsigned max_prop_lvl, unsigned full_prop_lvl); bool is_reachable(pob &n); - lbool expand_pob(pob &n); + lbool expand_pob(pob &n, pob_ref_buffer &out); reach_fact *mk_reach_fact (pob& n, model_evaluator_util &mev, datalog::rule const& r); bool create_children(pob& n, datalog::rule const& r, model_evaluator_util &model, - const vector& reach_pred_used); + const vector& reach_pred_used, + pob_ref_buffer &out); expr_ref mk_sat_answer(); expr_ref mk_unsat_answer() const; From d1a7c0ceb053c3c29e44e66414a43bfa940c48da Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 14:55:28 -0700 Subject: [PATCH 1016/1283] Remove a print --- src/muz/spacer/spacer_unsat_core_learner.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index bb50cc5c7..a6ab01870 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -76,7 +76,6 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) // TODO: remove duplicates from unsat core? - verbose_stream() << std::endl; // move all lemmas into vector for (expr* const* it = m_unsat_core.begin(); it != m_unsat_core.end(); ++it) { From 0fe5e6c2a6a581837bf7f899df9e3263dcb6f392 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 17 May 2018 17:01:02 -0700 Subject: [PATCH 1017/1283] Fix handling of complex literals in hypothesis_reducer In Z3, an arbitrary, even propositional, formula can be a literal. This requires careful handling of restructuring of unit resolution. --- src/muz/spacer/spacer_proof_utils.cpp | 65 ++++++++++++++------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index e8f56f200..3ca9b0c25 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -432,51 +432,56 @@ proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) { } proof* arg0 = args[0]; + app *fact0 = to_app(m.get_fact(arg0)); + ptr_buffer pf_args; + ptr_buffer pf_fact; + pf_args.push_back(arg0); - // BUG: I guess this shouldn't work with quantifiers (since they - // are not apps) - // AG: who is "I"? What is the bug? - app *fact = to_app(m.get_fact(arg0)); - ptr_buffer cls; - if (m.is_or(fact)) { - for (unsigned i = 0, sz = fact->get_num_args(); i < sz; ++i) - cls.push_back(fact->get_arg(i)); - } - else - cls.push_back(fact); - - // construct the new resolvent - ptr_buffer new_fact; - bool found; - - // -- find all literals that are resolved on - // XXX quadratic implementation - for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { - found = false; - for (unsigned j = 1; j < args.size(); ++j) { - if (m.is_complement(cls.get(i), m.get_fact(args[j]))) { - found = true; - pf_args.push_back(args[j]); - break; - } + // check if fact0 can be resolved as a unit + // this is required for handling literals with OR + for (unsigned j = 1; j < args.size(); ++j) { + if (m.is_complement(fact0, m.get_fact(args[j]))) { + pf_args.push_back(args[j]); + break; } - if (!found) new_fact.push_back(cls.get(i)); } - SASSERT(new_fact.size() + pf_args.size() - 1 == cls.size()); + + // if failed to find a resolvent, and the fact is a disjunction, + // attempt to resolve each disjunct + if (pf_args.size() == 1 && m.is_or(fact0)) { + ptr_buffer cls; + for (unsigned i = 0, sz = fact0->get_num_args(); i < sz; ++i) + cls.push_back(fact0->get_arg(i)); + + // -- find all literals that are resolved on + // XXX quadratic implementation + for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { + bool found = false; + for (unsigned j = 1; j < args.size(); ++j) { + if (m.is_complement(cls.get(i), m.get_fact(args[j]))) { + found = true; + pf_args.push_back(args[j]); + break; + } + } + if (!found) pf_fact.push_back(cls.get(i)); + } + SASSERT(pf_fact.size() + pf_args.size() - 1 == cls.size()); + } // unit resolution got reduced to noop if (pf_args.size() == 1) { - // XXX just in case + // XXX pin just in case m_pinned.push_back(arg0); return arg0; } // make unit resolution proof step expr_ref tmp(m); - tmp = mk_or(m, new_fact.size(), new_fact.c_ptr()); + tmp = mk_or(m, pf_fact.size(), pf_fact.c_ptr()); proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), tmp); m_pinned.push_back(res); return res; From 7931bd1dfca80c92f27aa7351f1b8c1d9581764f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 May 2018 13:06:47 -0700 Subject: [PATCH 1018/1283] updates to mbqi Signed-off-by: Nikolaj Bjorner --- src/ast/ast_util.cpp | 7 + src/ast/ast_util.h | 2 + src/muz/spacer/spacer_util.cpp | 232 ++++++++++++------------ src/qe/qe_arith.cpp | 5 +- src/qe/qe_mbp.cpp | 313 ++++++++++++++++++++++++++++----- src/qe/qe_mbp.h | 16 +- 6 files changed, 402 insertions(+), 173 deletions(-) diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 92a539d88..e2783051a 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -307,6 +307,13 @@ void flatten_and(expr* fml, expr_ref_vector& result) { flatten_and(result); } +void flatten_and(expr_ref& fml) { + expr_ref_vector fmls(fml.get_manager()); + fmls.push_back(fml); + flatten_and(fmls); + fml = mk_and(fmls); +} + void flatten_or(expr_ref_vector& result) { ast_manager& m = result.get_manager(); expr* e1, *e2, *e3; diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index 446854f5e..12c11c141 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -150,6 +150,8 @@ expr_ref mk_distinct(expr_ref_vector const& args); void flatten_and(expr_ref_vector& result); +void flatten_and(expr_ref& fml); + void flatten_and(expr* fml, expr_ref_vector& result); void flatten_or(expr_ref_vector& result); diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index b4e5e7710..030f2a386 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -479,9 +479,8 @@ namespace spacer { th_rewriter rw (m); TRACE ("spacer_mbp", tout << "Before projection:\n"; - tout << mk_pp (fml, m) << "\n"; - tout << "Vars:\n"; - for (app* v : vars) tout << mk_pp(v, m) << "\n";); + tout << fml << "\n"; + tout << "Vars:\n" << vars;); { // Ensure that top-level AND of fml is flat @@ -498,47 +497,40 @@ namespace spacer { expr_ref bval (m); while (true) { - params_ref p; - qe_lite qe(m, p, false); - qe (vars, fml); - rw (fml); - - TRACE ("spacer_mbp", - tout << "After qe_lite:\n"; - tout << mk_pp (fml, m) << "\n"; - tout << "Vars:\n"; - for (unsigned i = 0; i < vars.size(); ++i) { - tout << mk_pp(vars.get (i), m) << "\n"; - } - ); + params_ref p; + qe_lite qe(m, p, false); + qe (vars, fml); + rw (fml); + + TRACE ("spacer_mbp", + tout << "After qe_lite:\n"; + tout << mk_pp (fml, m) << "\n"; + tout << "Vars:\n" << vars;); + SASSERT (!m.is_false (fml)); - bool has_bool_vars = false; // sort out vars into bools, arith (int/real), and arrays - for (unsigned i = 0; i < vars.size (); i++) { - if (m.is_bool (vars.get (i))) { + for (app* v : vars) { + if (m.is_bool (v)) { // obtain the interpretation of the ith var using model completion - VERIFY (M->eval (vars.get (i), bval, true)); - bool_sub.insert (vars.get (i), bval); - has_bool_vars = true; - } else if (arr_u.is_array(vars.get(i))) { - array_vars.push_back (vars.get (i)); + VERIFY (M->eval (v, bval, true)); + bool_sub.insert (v, bval); + } else if (arr_u.is_array(v)) { + array_vars.push_back (v); } else { - SASSERT (ari_u.is_int (vars.get (i)) || ari_u.is_real (vars.get (i))); - arith_vars.push_back (vars.get (i)); + SASSERT (ari_u.is_int (v) || ari_u.is_real (v)); + arith_vars.push_back (v); } } // substitute Booleans - if (has_bool_vars) { + if (!bool_sub.empty()) { bool_sub (fml); // -- bool_sub is not simplifying rw (fml); SASSERT (!m.is_false (fml)); - TRACE ("spacer_mbp", - tout << "Projected Booleans:\n" << mk_pp (fml, m) << "\n"; - ); + TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); bool_sub.reset (); } @@ -571,40 +563,31 @@ namespace spacer { // project reals and ints if (!arith_vars.empty ()) { - TRACE ("spacer_mbp", - tout << "Arith vars:\n"; - for (unsigned i = 0; i < arith_vars.size (); ++i) { - tout << mk_pp (arith_vars.get (i), m) << "\n"; - } - ); - + TRACE ("spacer_mbp", tout << "Arith vars:\n" << arith_vars;); + // XXX Does not seem to have an effect // qe_lite qe(m); // qe (arith_vars, fml); // TRACE ("spacer_mbp", // tout << "After second qelite: " << // mk_pp (fml, m) << "\n";); - - if (use_native_mbp) { - qe::mbp mbp (m); - expr_ref_vector fmls(m); - flatten_and (fml, fmls); - - mbp (true, arith_vars, *M.get (), fmls); - fml = mk_and (fmls); - SASSERT (arith_vars.empty ()); - } else { + + if (use_native_mbp) { + qe::mbp mbp (m); + expr_ref_vector fmls(m); + flatten_and (fml, fmls); + + mbp (true, arith_vars, *M.get (), fmls); + fml = mk_and (fmls); + SASSERT (arith_vars.empty ()); + } else { scoped_no_proof _sp (m); qe::arith_project (*M.get (), arith_vars, fml); } - + TRACE ("spacer_mbp", - tout << "Projected arith vars:\n" << mk_pp (fml, m) << "\n"; - tout << "Remaining arith vars:\n"; - for (unsigned i = 0; i < arith_vars.size (); i++) { - tout << mk_pp (arith_vars.get (i), m) << "\n"; - } - ); + tout << "Projected arith vars:\n" << mk_pp (fml, m) << "\n"; + tout << "Remaining arith vars:\n" << arith_vars << "\n";); SASSERT (!m.is_false (fml)); } @@ -632,8 +615,9 @@ namespace spacer { ); vars.reset (); - if (dont_sub && !arith_vars.empty ()) - { vars.append(arith_vars); } + if (dont_sub && !arith_vars.empty ()) { + vars.append(arith_vars); + } } @@ -713,15 +697,15 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) } namespace { -class implicant_picker { + class implicant_picker { model_evaluator_util &m_mev; ast_manager &m; arith_util m_arith; - + expr_ref_vector m_todo; expr_mark m_visited; - + void add_literal (expr *e, expr_ref_vector &out) { SASSERT (m.is_bool (e)); @@ -763,37 +747,37 @@ class implicant_picker { out.push_back (res); } - void process_app(app *a, expr_ref_vector &out) - { - if (m_visited.is_marked(a)) { return; } + void process_app(app *a, expr_ref_vector &out) + { + if (m_visited.is_marked(a)) { return; } SASSERT (m.is_bool (a)); expr_ref v(m); m_mev.eval (a, v, false); - - if (!m.is_true(v) && !m.is_false(v)) { return; } - + + if (!m.is_true(v) && !m.is_false(v)) { return; } + expr *na, *f1, *f2, *f3; - + if (a->get_family_id() != m.get_basic_family_id()) - { add_literal(a, out); } + { add_literal(a, out); } else if (is_uninterp_const(a)) - { add_literal(a, out); } + { add_literal(a, out); } else if (m.is_not(a, na) && m.is_not(na, na)) - { m_todo.push_back(na); } + { m_todo.push_back(na); } else if (m.is_not(a, na)) - { m_todo.push_back(na); } + { m_todo.push_back(na); } else if (m.is_distinct(a)) { if (m.is_false(v)) m_todo.push_back (qe::project_plugin::pick_equality(m, *m_mev.get_model(), a)); else if (a->get_num_args() == 2) - { add_literal(a, out); } + { add_literal(a, out); } else m_todo.push_back(m.mk_distinct_expanded(a->get_num_args(), a->get_args())); - } else if (m.is_and(a)) { + } else if (m.is_and(a)) { if (m.is_true(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } + { m_todo.append(a->get_num_args(), a->get_args()); } else if (m.is_false(v)) { for (unsigned i = 0, sz = a->get_num_args (); i < sz; ++i) { if (m_mev.is_false(a->get_arg(i))) { @@ -802,9 +786,9 @@ class implicant_picker { } } } - } else if (m.is_or(a)) { + } else if (m.is_or(a)) { if (m.is_false(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } + { m_todo.append(a->get_num_args(), a->get_args()); } else if (m.is_true(v)) { for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { if (m_mev.is_true(a->get_arg(i))) { @@ -813,52 +797,52 @@ class implicant_picker { } } } - } else if (m.is_iff(a, f1, f2) || m.is_eq(a, f1, f2) || - (m.is_true(v) && m.is_not(a, na) && m.is_xor (na, f1, f2))) { + } else if (m.is_iff(a, f1, f2) || m.is_eq(a, f1, f2) || + (m.is_true(v) && m.is_not(a, na) && m.is_xor (na, f1, f2))) { if (!m.are_equal(f1, f2) && !m.are_distinct(f1, f2)) { if (m.is_bool(f1) && (!is_uninterp_const(f1) || !is_uninterp_const(f2))) - { m_todo.append(a->get_num_args(), a->get_args()); } + { m_todo.append(a->get_num_args(), a->get_args()); } else - { add_literal(a, out); } + { add_literal(a, out); } } - } else if (m.is_ite(a, f1, f2, f3)) { - if (m.are_equal(f2, f3)) { m_todo.push_back(f2); } + } else if (m.is_ite(a, f1, f2, f3)) { + if (m.are_equal(f2, f3)) { m_todo.push_back(f2); } else if (m_mev.is_true (f2) && m_mev.is_true (f3)) { - m_todo.push_back(f2); - m_todo.push_back(f3); - } else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { - m_todo.push_back(f2); - m_todo.push_back(f3); - } else if (m_mev.is_true(f1)) { - m_todo.push_back(f1); - m_todo.push_back(f2); - } else if (m_mev.is_false(f1)) { - m_todo.push_back(f1); - m_todo.push_back(f3); + m_todo.push_back(f2); + m_todo.push_back(f3); + } else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { + m_todo.push_back(f2); + m_todo.push_back(f3); + } else if (m_mev.is_true(f1)) { + m_todo.push_back(f1); + m_todo.push_back(f2); + } else if (m_mev.is_false(f1)) { + m_todo.push_back(f1); + m_todo.push_back(f3); } - } else if (m.is_xor(a, f1, f2)) - { m_todo.append(a->get_num_args(), a->get_args()); } + } else if (m.is_xor(a, f1, f2)) + { m_todo.append(a->get_num_args(), a->get_args()); } else if (m.is_implies(a, f1, f2)) { if (m.is_true (v)) { - if (m_mev.is_true(f2)) { m_todo.push_back(f2); } - else if (m_mev.is_false(f1)) { m_todo.push_back(f1); } + if (m_mev.is_true(f2)) { m_todo.push_back(f2); } + else if (m_mev.is_false(f1)) { m_todo.push_back(f1); } } else if (m.is_false(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } - } else if (m.is_true(a) || m.is_false(a)) { /* nothing */ } + { m_todo.append(a->get_num_args(), a->get_args()); } + } else if (m.is_true(a) || m.is_false(a)) { /* nothing */ } else { verbose_stream () << "Unexpected expression: " << mk_pp(a, m) << "\n"; UNREACHABLE(); } } - - void pick_literals(expr *e, expr_ref_vector &out) - { + + void pick_literals(expr *e, expr_ref_vector &out) + { SASSERT(m_todo.empty()); - if (m_visited.is_marked(e)) { return; } + if (m_visited.is_marked(e)) { return; } SASSERT(is_app(e)); - + m_todo.push_back(e); do { app *a = to_app(m_todo.back()); @@ -867,31 +851,31 @@ class implicant_picker { m_visited.mark(a, true); } while (!m_todo.empty()); } - - bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) - { + + bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) + { m_visited.reset(); expr_ref e(m); e = mk_and (in); bool is_true = m_mev.is_true (e); - + for (unsigned i = 0, sz = in.size (); i < sz; ++i) { if (is_true || m_mev.is_true(in.get(i))) - { pick_literals(in.get(i), out); } + { pick_literals(in.get(i), out); } } - + m_visited.reset (); return is_true; } - + public: implicant_picker (model_evaluator_util &mev) : m_mev (mev), m (m_mev.get_ast_manager ()), m_arith(m), m_todo(m) {} - + void operator() (expr_ref_vector &in, expr_ref_vector& out) {pick_implicant (in, out);} }; - } +} void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, expr_ref_vector &res) @@ -1144,6 +1128,7 @@ struct adhoc_rewriter_rpp : public default_rewriter_cfg { } }; + mk_epp::mk_epp(ast *t, ast_manager &m, unsigned indent, unsigned num_vars, char const * var_prefix) : mk_pp (t, m, m_epp_params, indent, num_vars, var_prefix), m_epp_expr(m) { @@ -1189,14 +1174,13 @@ void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { index_term_finder (ast_manager &mgr, app* v, expr_ref_vector &res) : m(mgr), m_array (m), m_var (v, m), m_res (res) {} void operator() (var *n) {} void operator() (quantifier *n) {} - void operator() (app *n) - { + void operator() (app *n) { expr *e1, *e2; if (m_array.is_select (n) && n->get_arg (1) != m_var) { m_res.push_back (n->get_arg (1)); - } else if (m.is_eq(n, e1, e2)) { - if (e1 == m_var) { m_res.push_back(e2); } - else if (e2 == m_var) { m_res.push_back(e1); } + } else if (m.is_eq(n, e1, e2)) { + if (e1 == m_var) { m_res.push_back(e2); } + else if (e2 == m_var) { m_res.push_back(e1); } } } }; @@ -1204,29 +1188,29 @@ void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { bool mbqi_project_var (model_evaluator_util &mev, app* var, expr_ref &fml) { ast_manager &m = fml.get_manager (); - + expr_ref val(m); mev.eval (var, val, false); - + TRACE ("mbqi_project_verbose", tout << "MBQI: var: " << mk_pp (var, m) << "\n" << "fml: " << mk_pp (fml, m) << "\n";); expr_ref_vector terms (m); index_term_finder finder (m, var, terms); for_each_expr (finder, fml); - - + + TRACE ("mbqi_project_verbose", tout << "terms:\n"; for (unsigned i = 0, e = terms.size (); i < e; ++i) tout << i << ": " << mk_pp (terms.get (i), m) << "\n"; ); - - for (unsigned i = 0, e = terms.size(); i < e; ++i) { + + for (unsigned i = 0, e = terms.size(); i < e; ++i) { expr* term = terms.get (i); expr_ref tval (m); mev.eval (term, tval, false); - + TRACE ("mbqi_project_verbose", tout << "term: " << mk_pp (term, m) << " tval: " << mk_pp (tval, m) diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 6ea4118a0..969d22a81 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -352,10 +352,7 @@ namespace qe { real_vars.push_back(tids.find(v)); } else { - if (i != j) { - vars[j] = v; - } - ++j; + vars[j++] = v; } } vars.resize(j); diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 432569ff9..0b4574951 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -18,17 +18,20 @@ Revision History: --*/ +#include "ast/rewriter/expr_safe_replace.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/occurs.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/expr_functors.h" +#include "ast/for_each_expr.h" +#include "ast/scoped_proof.h" #include "qe/qe_mbp.h" #include "qe/qe_arith.h" #include "qe/qe_arrays.h" #include "qe/qe_datatypes.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/ast_pp.h" -#include "ast/ast_util.h" -#include "ast/rewriter/th_rewriter.h" -#include "model/model_v2_pp.h" -#include "ast/expr_functors.h" -#include "ast/for_each_expr.h" +#include "qe/qe_lite.h" +#include "model/model_pp.h" #include "model/model_evaluator.h" @@ -122,11 +125,17 @@ void project_plugin::push_back(expr_ref_vector& lits, expr* e) { class mbp::impl { - ast_manager& m; - th_rewriter m_rw; + ast_manager& m; + params_ref m_params; + th_rewriter m_rw; ptr_vector m_plugins; - expr_mark m_visited; - expr_mark m_bool_visited; + expr_mark m_visited; + expr_mark m_bool_visited; + + // parameters + bool m_reduce_all_selects; + bool m_native_mbp; + bool m_dont_sub; void add_plugin(project_plugin* p) { family_id fid = p->get_family_id(); @@ -258,42 +267,122 @@ class mbp::impl { return found_bool; } - void project_bools(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { + void project_bools(model& mdl, app_ref_vector& vars, expr_ref_vector& fmls) { expr_safe_replace sub(m); expr_ref val(m); + model_evaluator eval(mdl, m_params); + eval.set_model_completion(true); unsigned j = 0; for (unsigned i = 0; i < vars.size(); ++i) { app* var = vars[i].get(); if (m.is_bool(var)) { - VERIFY(model.eval(var, val)); - sub.insert(var, val); + sub.insert(var, eval(var)); } else { - if (j != i) { - vars[j] = vars[i].get(); - } - ++j; + vars[j++] = var; } } - if (j != vars.size()) { - vars.resize(j); - j = 0; - for (unsigned i = 0; i < fmls.size(); ++i) { - sub(fmls[i].get(), val); - m_rw(val); - if (!m.is_true(val)) { - TRACE("qe", tout << mk_pp(fmls[i].get(), m) << " -> " << val << "\n";); - fmls[i] = val; - if (j != i) { - fmls[j] = fmls[i].get(); - } - ++j; - } - } - if (j != fmls.size()) { - fmls.resize(j); + if (j == vars.size()) { + return; + } + vars.shrink(j); + j = 0; + for (unsigned i = 0; i < fmls.size(); ++i) { + expr* fml = fmls[i].get(); + sub(fml, val); + m_rw(val); + if (!m.is_true(val)) { + TRACE("qe", tout << mk_pp(fml, m) << " -> " << val << "\n";); + fmls[j++] = val; } } + fmls.shrink(j); + } + + + void subst_vars(model_evaluator& eval, app_ref_vector const& vars, expr_ref& fml) { + expr_safe_replace sub (m); + for (app * v : vars) { + sub.insert(v, eval(v)); + } + sub(fml); + } + + struct index_term_finder { + ast_manager& m; + array_util m_array; + app_ref m_var; + expr_ref_vector& m_res; + + index_term_finder (ast_manager &mgr, app* v, expr_ref_vector &res): + m(mgr), m_array (m), m_var (v, m), m_res (res) {} + + void operator() (var *n) {} + void operator() (quantifier *n) {} + void operator() (app *n) { + expr *e1, *e2; + if (m_array.is_select (n)) { + for (unsigned i = 1; i < n->get_num_args(); ++i) { + expr * arg = n->get_arg(i); + if (m.get_sort(arg) == m.get_sort(m_var) && arg != m_var) + m_res.push_back (arg); + } + } + else if (m.is_eq(n, e1, e2)) { + if (e1 == m_var) + m_res.push_back(e2); + else if (e2 == m_var) + m_res.push_back(e1); + } + } + }; + + bool project_var (model_evaluator& eval, app* var, expr_ref& fml) { + expr_ref val = eval(var); + + TRACE ("mbqi_project_verbose", tout << "MBQI: var: " << mk_pp (var, m) << "\n" << "fml: " << fml << "\n";); + expr_ref_vector terms (m); + index_term_finder finder (m, var, terms); + for_each_expr (finder, fml); + + TRACE ("mbqi_project_verbose", tout << "terms:\n" << terms;); + + for (expr * term : terms) { + expr_ref tval = eval(term); + + TRACE ("mbqi_project_verbose", tout << "term: " << mk_pp (term, m) << " tval: " << tval << " val: " << val << "\n";); + + // -- if the term does not contain an occurrence of var + // -- and is in the same equivalence class in the model + if (tval == val && !occurs (var, term)) { + TRACE ("mbqi_project", + tout << "MBQI: replacing " << mk_pp (var, m) << " with " << mk_pp (term, m) << "\n";); + expr_safe_replace sub(m); + sub.insert (var, term); + sub (fml); + return true; + } + } + + TRACE ("mbqi_project", + tout << "MBQI: failed to eliminate " << mk_pp (var, m) << " from " << fml << "\n";); + + return false; + } + + void project_vars (model &M, app_ref_vector &vars, expr_ref &fml) { + model_evaluator eval(M); + eval.set_model_completion(false); + // -- evaluate to initialize eval cache + (void) eval (fml); + unsigned j = 0; + for (unsigned i = 0; i < vars.size (); ++i) { + app* v = vars.get(i); + if (!project_var (eval, v, fml)) { + vars[j++] = v; + } + } + vars.shrink(j); } public: @@ -426,7 +515,7 @@ public: m_bool_visited.reset(); } - impl(ast_manager& m):m(m), m_rw(m) { + impl(ast_manager& m, params_ref const& p):m(m), m_params(p), m_rw(m) { add_plugin(alloc(arith_project_plugin, m)); add_plugin(alloc(datatype_project_plugin, m)); add_plugin(alloc(array_project_plugin, m)); @@ -436,13 +525,20 @@ public: std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc()); } + void updt_params(params_ref const& p) { + m_params.append(p); + m_reduce_all_selects = m_params.get_bool("reduce_all_selects", false); + m_native_mbp = m_params.get_bool("native_mbp", false); + m_dont_sub = m_params.get_bool("dont_sub", false); + } + void preprocess_solve(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { extract_literals(model, fmls); bool change = true; while (change && !vars.empty()) { change = solve(model, vars, fmls); - for (unsigned i = 0; i < m_plugins.size(); ++i) { - if (m_plugins[i] && m_plugins[i]->solve(model, vars, fmls)) { + for (auto* p : m_plugins) { + if (p && p->solve(model, vars, fmls)) { change = true; } } @@ -451,8 +547,8 @@ public: bool validate_model(model& model, expr_ref_vector const& fmls) { expr_ref val(m); - for (unsigned i = 0; i < fmls.size(); ++i) { - VERIFY(model.eval(fmls[i], val) && m.is_true(val)); + for (expr * f : fmls) { + VERIFY(model.eval(f, val) && m.is_true(val)); } return true; } @@ -469,8 +565,7 @@ public: while (progress && !vars.empty() && !fmls.empty()) { app_ref_vector new_vars(m); progress = false; - for (unsigned i = 0; i < m_plugins.size(); ++i) { - project_plugin* p = m_plugins[i]; + for (project_plugin * p : m_plugins) { if (p) { (*p)(model, vars, fmls); } @@ -517,28 +612,158 @@ public: TRACE("qe", tout << vars << " " << fmls << "\n";); } + void do_qe_lite(app_ref_vector& vars, expr_ref& fml) { + qe_lite qe(m, m_params, false); + qe (vars, fml); + m_rw (fml); + TRACE ("qe", tout << "After qe_lite:\n" << fml << "\n" << "Vars:\n" << vars;); + SASSERT (!m.is_false (fml)); + } + + void do_qe_bool(model& mdl, app_ref_vector& vars, expr_ref& fml) { + expr_ref_vector fmls(m); + fmls.push_back(fml); + project_bools(mdl, vars, fmls); + fml = mk_and(fmls); + } + + void spacer(app_ref_vector& vars, model& mdl, expr_ref& fml) { + TRACE ("qe", tout << "Before projection:\n" << fml << "\n" << "Vars:\n" << vars;); + + model_evaluator eval(mdl, m_params); + eval.set_model_completion(true); + app_ref_vector arith_vars (m); + app_ref_vector array_vars (m); + array_util arr_u (m); + arith_util ari_u (m); + + flatten_and(fml); + + do_qe_lite(vars, fml); + + while (!vars.empty()) { + + do_qe_bool(mdl, vars, fml); + + // sort out vars into bools, arith (int/real), and arrays + for (app* v : vars) { + if (arr_u.is_array(v)) { + array_vars.push_back (v); + } + else if (ari_u.is_int (v) || ari_u.is_real (v)) { + arith_vars.push_back (v); + } + else { + NOT_IMPLEMENTED_YET(); + } + } + + TRACE ("qe", tout << "Array vars:\n" << array_vars;); + + vars.reset (); + + // project arrays + if (!array_vars.empty()) { + NOT_IMPLEMENTED_YET(); + // qe::array_project (mdl, array_vars, fml, vars, m_reduce_all_selects); + SASSERT (array_vars.empty ()); + m_rw (fml); + SASSERT (!m.is_false (fml)); + } + + TRACE ("qe", + tout << "extended model:\n"; + model_pp (tout, mdl); + tout << "Auxiliary variables of index and value sorts:\n"; + tout << vars; + ); + + } + // project reals and ints + if (!arith_vars.empty ()) { + TRACE ("qe", tout << "Arith vars:\n" << arith_vars;); + + if (m_native_mbp) { + expr_ref_vector fmls(m); + flatten_and (fml, fmls); + + (*this)(true, arith_vars, mdl, fmls); + fml = mk_and (fmls); + SASSERT (arith_vars.empty ()); + } + else { + NOT_IMPLEMENTED_YET(); + // qe::arith_project (mdl, arith_vars, fml); + } + + TRACE ("qe", + tout << "Projected arith vars:\n" << fml << "\n"; + tout << "Remaining arith vars:\n" << arith_vars << "\n";); + SASSERT (!m.is_false (fml)); + } + + if (!arith_vars.empty ()) { + project_vars (mdl, arith_vars, fml); + } + + // substitute any remaining arith vars + if (!m_dont_sub && !arith_vars.empty ()) { + subst_vars (eval, arith_vars, fml); + TRACE ("qe", tout << "After substituting remaining arith vars:\n" << fml << "\n";); + // an extra round of simplification because subst_vars is not simplifying + m_rw(fml); + arith_vars.reset(); + } + + SASSERT(eval.is_true(fml)); + + vars.reset (); + vars.append(arith_vars); + } + }; -mbp::mbp(ast_manager& m) { - m_impl = alloc(impl, m); +mbp::mbp(ast_manager& m, params_ref const& p) { + scoped_no_proof _sp (m); + m_impl = alloc(impl, m, p); } mbp::~mbp() { dealloc(m_impl); } + +void mbp::updt_params(params_ref const& p) { + m_impl->updt_params(p); +} + +void mbp::get_param_descrs(param_descrs & r) { + r.insert("reduce_all_selects", CPK_BOOL, "(default: false) reduce selects"); + r.insert("native_mbp", CPK_BOOL, "(default: false) switch between native and spacer tailored mbp"); + r.insert("dont_sub", CPK_BOOL, "(default: false) disable substitution of values for free variables"); +} void mbp::operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls) { + scoped_no_proof _sp (fmls.get_manager()); (*m_impl)(force_elim, vars, mdl, fmls); } +void mbp::spacer(app_ref_vector& vars, model& mdl, expr_ref& fml) { + scoped_no_proof _sp (fml.get_manager()); + m_impl->spacer(vars, mdl, fml); +} + void mbp::solve(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { + scoped_no_proof _sp (fmls.get_manager()); m_impl->preprocess_solve(model, vars, fmls); } void mbp::extract_literals(model& model, expr_ref_vector& lits) { + scoped_no_proof _sp (lits.get_manager()); m_impl->extract_literals(model, lits); } + opt::inf_eps mbp::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { + scoped_no_proof _sp (fmls.get_manager()); return m_impl->maximize(fmls, mdl, t, ge, gt); } diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index d1695843c..12b03791a 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -52,9 +52,13 @@ namespace qe { class impl; impl * m_impl; public: - mbp(ast_manager& m); + mbp(ast_manager& m, params_ref const& p = params_ref()); ~mbp(); + + void updt_params(params_ref const& p); + + static void get_param_descrs(param_descrs & r); /** \brief @@ -80,6 +84,16 @@ namespace qe { Maximize objective t under current model for constraints in fmls. */ opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt); + + /** + \brief + Apply spacer friendly MBP. + Use parameters to control behavior. + - reduce_all_selects (false) + - native_mbp (false) - to be deprecated + - dont_sub (false) + */ + void spacer(app_ref_vector& vars, model& mdl, expr_ref& fml); }; } From b39c532f19755d8850664b84c3957abc2a97ea68 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 18 May 2018 08:39:59 -0700 Subject: [PATCH 1019/1283] Order of methods in spacer_context.cpp --- src/muz/spacer/spacer_context.cpp | 1201 +++++++++++++++-------------- 1 file changed, 602 insertions(+), 599 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 48cbbd258..2709593ad 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -54,6 +54,581 @@ Notes: #include "smt/smt_solver.h" namespace spacer { +/// pob -- proof obligation +pob::pob (pob* parent, pred_transformer& pt, + unsigned level, unsigned depth, bool add_to_parent): + m_ref_count (0), + m_parent (parent), m_pt (pt), + m_post (m_pt.get_ast_manager ()), + m_binding(m_pt.get_ast_manager()), + m_new_post (m_pt.get_ast_manager ()), + m_level (level), m_depth (depth), + m_open (true), m_use_farkas (true), m_weakness(0), + m_blocked_lvl(0) { + if(add_to_parent && m_parent) { + m_parent->add_child(*this); + } +} + + +void pob::set_post(expr* post) { + app_ref_vector b(get_ast_manager()); + set_post(post, b); +} + +void pob::set_post(expr* post, app_ref_vector const &b) { + normalize(post, m_post, + m_pt.get_context().get_params().spacer_simplify_pob(), + m_pt.get_context().get_params().spacer_use_eqclass()); + + m_binding.reset(); + if (b.empty()) return; + + m_binding.append(b); + + std::sort (m_binding.c_ptr(), m_binding.c_ptr() + m_binding.size(), sk_lt_proc()); + + // skolemize implicit existential quantifier + ast_manager &m = get_ast_manager(); + app_ref_vector pinned(m); + + expr_safe_replace sub(m); + for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { + expr* e; + e = m_binding.get(i); + pinned.push_back (mk_zk_const (m, i, get_sort(e))); + sub.insert (e, pinned.back()); + } + sub(m_post); +} + +void pob::inherit(pob const &p) { + SASSERT(m_parent == p.m_parent); + SASSERT(&m_pt == &p.m_pt); + SASSERT(m_post == p.m_post); + SASSERT(!m_new_post); + + m_binding.reset(); + m_binding.append(p.m_binding); + + m_level = p.m_level; + m_depth = p.m_depth; + m_open = p.m_open; + m_use_farkas = p.m_use_farkas; + m_weakness = p.m_weakness; + + m_derivation = nullptr; +} + +void pob::clean () { + if(m_new_post) { + m_post = m_new_post; + m_new_post.reset(); + } +} + +void pob::close () { + if(!m_open) { return; } + + reset (); + m_open = false; + for (unsigned i = 0, sz = m_kids.size (); i < sz; ++i) + { m_kids [i]->close(); } +} + +void pob::get_skolems(app_ref_vector &v) { + for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { + expr* e; + e = m_binding.get(i); + v.push_back (mk_zk_const (get_ast_manager(), i, get_sort(e))); + } +} + + + +// ---------------- +// pob_queue + +pob* pob_queue::top () +{ + /// nothing in the queue + if (m_obligations.empty()) { return nullptr; } + /// top queue element is above max level + if (m_obligations.top()->level() > m_max_level) { return nullptr; } + /// top queue element is at the max level, but at a higher than base depth + if (m_obligations.top ()->level () == m_max_level && + m_obligations.top()->depth() > m_min_depth) { return nullptr; } + + /// there is something good in the queue + return m_obligations.top ().get (); +} + +void pob_queue::set_root(pob& root) +{ + m_root = &root; + m_max_level = root.level (); + m_min_depth = root.depth (); + reset(); +} + +pob_queue::~pob_queue() {} + +void pob_queue::reset() +{ + while (!m_obligations.empty()) { m_obligations.pop(); } + if (m_root) { m_obligations.push(m_root); } +} + +void pob_queue::push(pob &n) { + TRACE("pob_queue", + tout << "pob_queue::push(" << n.post()->get_id() << ")\n";); + m_obligations.push (&n); + n.get_context().new_pob_eh(&n); +} + +// ---------------- +// derivation + +derivation::derivation (pob& parent, datalog::rule const& rule, + expr *trans, app_ref_vector const &evars) : + m_parent (parent), + m_rule (rule), + m_premises (), + m_active (0), + m_trans (trans, m_parent.get_ast_manager ()), + m_evars (evars) {} + + + +void derivation::add_premise (pred_transformer &pt, + unsigned oidx, + expr* summary, + bool must, + const ptr_vector *aux_vars) +{m_premises.push_back (premise (pt, oidx, summary, must, aux_vars));} + + + +pob *derivation::create_first_child (model_evaluator_util &mev) +{ + if (m_premises.empty()) { return nullptr; } + m_active = 0; + return create_next_child(mev); +} + +pob *derivation::create_next_child (model_evaluator_util &mev) +{ + timeit _timer (is_trace_enabled("spacer_timeit"), + "spacer::derivation::create_next_child", + verbose_stream ()); + + ast_manager &m = get_ast_manager (); + expr_ref_vector summaries (m); + app_ref_vector vars (m); + + bool use_native_mbp = get_context ().use_native_mbp (); + bool ground = get_context ().use_ground_cti (); + // -- find first may premise + while (m_active < m_premises.size() && m_premises[m_active].is_must()) { + summaries.push_back (m_premises[m_active].get_summary ()); + vars.append (m_premises[m_active].get_ovars ()); + ++m_active; + } + if (m_active >= m_premises.size()) { return nullptr; } + + // -- update m_trans with the pre-image of m_trans over the must summaries + summaries.push_back (m_trans); + m_trans = mk_and (summaries); + summaries.reset (); + + if (!vars.empty()) { + timeit _timer1 (is_trace_enabled("spacer_timeit"), + "create_next_child::qproject1", + verbose_stream ()); + qe_project (m, vars, m_trans, mev.get_model (), true, use_native_mbp, !ground); + //qe::reduce_array_selects (*mev.get_model (), m_trans); + // remember variables that need to be existentially quantified + m_evars.append (vars); + } + + if (!mev.is_true (m_premises[m_active].get_summary())) { + IF_VERBOSE(1, verbose_stream() << "Summary unexpectendly not true\n";); + return nullptr; + } + + + // create the post condition by compute post-image over summaries + // that precede currently active premise + vars.reset (); + for (unsigned i = m_active + 1; i < m_premises.size(); ++i) { + summaries.push_back (m_premises [i].get_summary ()); + vars.append (m_premises [i].get_ovars ()); + } + summaries.push_back (m_trans); + + expr_ref post(m); + post = mk_and (summaries); + summaries.reset (); + if (!vars.empty()) { + timeit _timer2 (is_trace_enabled("spacer_timeit"), + "create_next_child::qproject2", + verbose_stream ()); + qe_project (m, vars, post, mev.get_model (), true, use_native_mbp, !ground); + //qe::reduce_array_selects (*mev.get_model (), post); + + // remember variables that need to be existentially quantified + m_evars.append (vars); + } + + get_manager ().formula_o2n (post.get (), post, + m_premises [m_active].get_oidx (), m_evars.empty()); + + + /* The level and depth are taken from the parent, not the sibling. + The reasoning is that the sibling has not been checked before, + and lower level is a better starting point. */ + pob *n = m_premises[m_active].pt().mk_pob(&m_parent, + prev_level (m_parent.level ()), + m_parent.depth (), post, m_evars); + + IF_VERBOSE (1, verbose_stream () + << "\n\tcreate_child: " << n->pt ().head ()->get_name () + << " (" << n->level () << ", " << n->depth () << ") " + << (n->use_farkas_generalizer () ? "FAR " : "SUB ") + << n->post ()->get_id (); + verbose_stream().flush ();); + return n; +} + +pob *derivation::create_next_child () +{ + if (m_active + 1 >= m_premises.size()) { return nullptr; } + + bool use_native_mbp = get_context ().use_native_mbp (); + bool ground = get_context ().use_ground_cti (); + + // update the summary of the active node to some must summary + + // construct a new model consistent with the must summary of m_active premise + pred_transformer &pt = m_premises[m_active].pt (); + model_ref model; + + ast_manager &m = get_ast_manager (); + manager &pm = get_manager (); + + expr_ref_vector summaries (m); + + for (unsigned i = m_active + 1; i < m_premises.size (); ++i) + { summaries.push_back(m_premises [i].get_summary()); } + + // -- orient transition relation towards m_active premise + expr_ref active_trans (m); + pm.formula_o2n (m_trans, active_trans, + m_premises[m_active].get_oidx (), false); + summaries.push_back (active_trans); + + // if not true, bail out, the must summary of m_active is not strong enough + // this is possible if m_post was weakened for some reason + if (!pt.is_must_reachable(mk_and(summaries), &model)) { return nullptr; } + + model_evaluator_util mev (m); + mev.set_model (*model); + // find must summary used + + reach_fact *rf = pt.get_used_reach_fact (mev, true); + + // get an implicant of the summary + expr_ref_vector u(m), lits (m); + u.push_back (rf->get ()); + compute_implicant_literals (mev, u, lits); + expr_ref v(m); + v = mk_and (lits); + + // XXX The summary is not used by anyone after this point + m_premises[m_active].set_summary (v, true, &(rf->aux_vars ())); + + + /** HACK: needs a rewrite + * compute post over the new must summary this must be done here + * because the must summary is currently described over new + * variables. However, we store it over old-variables, but we do + * not update the model. So we must get rid of all of the + * new-variables at this point. + */ + { + pred_transformer &pt = m_premises[m_active].pt (); + app_ref_vector vars (m); + + summaries.reset (); + summaries.push_back (v); + summaries.push_back (active_trans); + m_trans = mk_and (summaries); + + // variables to eliminate + vars.append (rf->aux_vars ().size (), rf->aux_vars ().c_ptr ()); + for (unsigned i = 0, sz = pt.head ()->get_arity (); i < sz; ++i) + { vars.push_back(m.mk_const(pm.o2n(pt.sig(i), 0))); } + + if (!vars.empty ()) { + qe_project (m, vars, m_trans, mev.get_model (), true, use_native_mbp, + !ground); + // keep track of implicitly quantified variables + m_evars.append (vars); + } + } + + m_active++; + + return create_next_child (mev); +} + +/// derivation::premise + +derivation::premise::premise (pred_transformer &pt, unsigned oidx, + expr *summary, bool must, + const ptr_vector *aux_vars) : + m_pt (pt), m_oidx (oidx), + m_summary (summary, pt.get_ast_manager ()), m_must (must), + m_ovars (pt.get_ast_manager ()) +{ + + ast_manager &m = m_pt.get_ast_manager (); + manager &sm = m_pt.get_manager (); + + unsigned sig_sz = m_pt.head ()->get_arity (); + for (unsigned i = 0; i < sig_sz; ++i) + { m_ovars.push_back(m.mk_const(sm.o2o(pt.sig(i), 0, m_oidx))); } + + if (aux_vars) + for (unsigned i = 0, sz = aux_vars->size (); i < sz; ++i) + { m_ovars.push_back(m.mk_const(sm.n2o(aux_vars->get(i)->get_decl(), m_oidx))); } +} + +derivation::premise::premise (const derivation::premise &p) : + m_pt (p.m_pt), m_oidx (p.m_oidx), m_summary (p.m_summary), m_must (p.m_must), + m_ovars (p.m_ovars) {} + +/// \brief Updated the summary. +/// The new summary is over n-variables. +void derivation::premise::set_summary (expr * summary, bool must, + const ptr_vector *aux_vars) +{ + ast_manager &m = m_pt.get_ast_manager (); + manager &sm = m_pt.get_manager (); + unsigned sig_sz = m_pt.head ()->get_arity (); + + m_must = must; + sm.formula_n2o (summary, m_summary, m_oidx); + + m_ovars.reset (); + for (unsigned i = 0; i < sig_sz; ++i) + { m_ovars.push_back(m.mk_const(sm.o2o(m_pt.sig(i), 0, m_oidx))); } + + if (aux_vars) + for (unsigned i = 0, sz = aux_vars->size (); i < sz; ++i) + m_ovars.push_back (m.mk_const (sm.n2o (aux_vars->get (i)->get_decl (), + m_oidx))); +} + + +/// Lemma + +lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : + m_ref_count(0), m(manager), + m_body(body, m), m_cube(m), + m_zks(m), m_bindings(m), m_lvl(lvl), + m_pob(nullptr), m_external(false) { + SASSERT(m_body); + normalize(m_body, m_body); +} + +lemma::lemma(pob_ref const &p) : + m_ref_count(0), m(p->get_ast_manager()), + m_body(m), m_cube(m), + m_zks(m), m_bindings(m), m_lvl(p->level()), + m_pob(p), m_external(false) { + SASSERT(m_pob); + m_pob->get_skolems(m_zks); + add_binding(m_pob->get_binding()); +} + +lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : + m_ref_count(0), + m(p->get_ast_manager()), + m_body(m), m_cube(m), + m_zks(m), m_bindings(m), m_lvl(p->level()), + m_pob(p), m_external(false) +{ + if (m_pob) { + m_pob->get_skolems(m_zks); + add_binding(m_pob->get_binding()); + } + update_cube(p, cube); + set_level(lvl); +} + +void lemma::add_skolem(app *zk, app *b) { + SASSERT(m_bindings.size() == m_zks.size()); + // extend bindings + m_bindings.push_back(b); + // extend skolems + m_zks.push_back(zk); +} + + +void lemma::mk_expr_core() { + if (m_body) {return;} + + if (m_pob) {mk_cube_core();} + + SASSERT(!m_cube.empty()); + m_body = ::push_not(::mk_and(m_cube)); + normalize(m_body, m_body); + + if (!m_zks.empty() && has_zk_const(m_body)) { + app_ref_vector zks(m); + zks.append(m_zks); + zks.reverse(); + expr_abstract(m, 0, + zks.size(), (expr* const*)zks.c_ptr(), m_body, + m_body); + ptr_buffer sorts; + svector names; + for (unsigned i=0, sz=zks.size(); i < sz; ++i) { + sorts.push_back(get_sort(zks.get(i))); + names.push_back(zks.get(i)->get_decl()->get_name()); + } + m_body = m.mk_quantifier(true, zks.size(), + sorts.c_ptr(), + names.c_ptr(), + m_body, 15, symbol(m_body->get_id())); + } + SASSERT(m_body); +} +void lemma::mk_cube_core() { + if (!m_cube.empty()) {return;} + expr_ref cube(m); + if (m_pob || m_body) { + if(m_pob) {cube = m_pob->post();} + else if (m_body) { + // no quantifiers for now + SASSERT(!is_quantifier(m_body)); + cube = m_body; + cube = ::push_not(cube); + } + flatten_and(cube, m_cube); + if (m_cube.empty()) { + m_cube.push_back(m.mk_true()); + } + else { + std::sort(m_cube.c_ptr(), m_cube.c_ptr() + m_cube.size(), ast_lt_proc()); + } + } + else { + UNREACHABLE(); + } +} +bool lemma::is_false() { + // a lemma is false if + // 1. it is defined by a cube, and the cube contains a single literal 'true' + // 2. it is defined by a body, and the body is a single literal false + // 3. it is defined by a pob, and the pob post is false + if (m_cube.size() == 1) {return m.is_true(m_cube.get(0));} + else if (m_body) {return m.is_false(m_body);} + else if (m_pob) {return m.is_true(m_pob->post());} + + return false; +} +expr* lemma::get_expr() { + mk_expr_core(); + return m_body; +} +expr_ref_vector const &lemma::get_cube() { + mk_cube_core(); + return m_cube; +} + +void lemma::update_cube (pob_ref const &p, expr_ref_vector &cube) { + SASSERT(m_pob); + SASSERT(m_pob.get() == p.get()); + m_cube.reset(); + m_body.reset(); + m_cube.append(cube); + if (m_cube.empty()) {m_cube.push_back(m.mk_true());} + + // after the cube is updated, if there are no skolems, + // convert the lemma to quantifier-free + bool is_quant = false; + for (unsigned i = 0, sz = cube.size(); !is_quant && i < sz; ++i) { + is_quant = has_zk_const(cube.get(i)); + } + + if (!is_quant) { + m_zks.reset(); + m_bindings.reset(); + } +} + +bool lemma::has_binding(app_ref_vector const &binding) { + unsigned num_decls = m_zks.size(); + + SASSERT(binding.size() == num_decls); + + if (num_decls == 0) return true; + + for (unsigned off = 0, sz = m_bindings.size(); off < sz; off += num_decls) { + unsigned i = 0; + for (; i < num_decls; ++i) { + if (m_bindings.get(off + i) != binding.get(i)) { + break; + } + } + if (i == num_decls) return true; + } + return false; +} +void lemma::add_binding(app_ref_vector const &binding) { + if (!has_binding(binding)) { + m_bindings.append(binding); + + TRACE("spacer", + tout << "new binding: "; + for (unsigned i = 0; i < binding.size(); i++) + tout << mk_pp(binding.get(i), m) << " "; + tout << "\n";); + } +} +void lemma::instantiate(expr * const * exprs, expr_ref &result, expr *e) { + expr *lem = e == nullptr ? get_expr() : e; + if (!is_quantifier (lem) || m_bindings.empty()) {return;} + + expr *body = to_quantifier(lem)->get_expr(); + unsigned num_decls = to_quantifier(lem)->get_num_decls(); + var_subst vs(m, false); + vs(body, num_decls, exprs, result); +} + +void lemma::set_level (unsigned lvl) { + if(m_pob){m_pob->blocked_at(lvl);} + m_lvl = lvl; +} + + +void lemma::mk_insts(expr_ref_vector &out, expr* e) +{ + expr *lem = e == nullptr ? get_expr() : e; + if (!is_quantifier (lem) || m_bindings.empty()) {return;} + + unsigned num_decls = to_quantifier(lem)->get_num_decls(); + expr_ref inst(m); + for (unsigned off = 0, sz = m_bindings.size(); off < sz; off += num_decls) { + instantiate((expr * const *) m_bindings.c_ptr() + off, inst, e); + out.push_back(inst); + inst.reset(); + } +} + + // ---------------- // pred_tansformer @@ -303,9 +878,7 @@ void pred_transformer::remove_predecessors(expr_ref_vector& literals) } void pred_transformer::simplify_formulas() -{ - m_frames.simplify_formulas (); -} +{m_frames.simplify_formulas ();} expr_ref pred_transformer::get_formulas(unsigned level, bool add_axioms) @@ -528,9 +1101,7 @@ expr_ref pred_transformer::get_reachable() } expr* pred_transformer::get_last_reach_case_var () const -{ - return m_reach_case_vars.empty () ? nullptr : m_reach_case_vars.back (); -} +{return m_reach_case_vars.empty () ? nullptr : m_reach_case_vars.back ();} expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) { @@ -1168,211 +1739,32 @@ void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, datalog:: } void pred_transformer::inherit_properties(pred_transformer& other) +{m_frames.inherit_frames (other.m_frames);} + +app* pred_transformer::extend_initial (expr *e) { - m_frames.inherit_frames (other.m_frames); + // create fresh extend literal + app_ref v(m); + std::stringstream name; + name << m_head->get_name() << "_ext"; + v = m.mk_fresh_const (name.str ().c_str (), + m.mk_bool_sort ()); + v = m.mk_const (pm.get_n_pred (v->get_decl ())); + + expr_ref ic(m); + + // -- extend the initial condition + ic = m.mk_or (m_extend_lit, e, v); + m_solver.assert_expr (ic); + + // -- remember the new extend literal + m_extend_lit = m.mk_not (v); + + return m_extend_lit; } -lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : - m_ref_count(0), m(manager), - m_body(body, m), m_cube(m), - m_zks(m), m_bindings(m), m_lvl(lvl), - m_pob(nullptr), m_external(false) { - SASSERT(m_body); - normalize(m_body, m_body); -} - -lemma::lemma(pob_ref const &p) : - m_ref_count(0), m(p->get_ast_manager()), - m_body(m), m_cube(m), - m_zks(m), m_bindings(m), m_lvl(p->level()), - m_pob(p), m_external(false) { - SASSERT(m_pob); - m_pob->get_skolems(m_zks); - add_binding(m_pob->get_binding()); -} - -lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : - m_ref_count(0), - m(p->get_ast_manager()), - m_body(m), m_cube(m), - m_zks(m), m_bindings(m), m_lvl(p->level()), - m_pob(p), m_external(false) -{ - if (m_pob) { - m_pob->get_skolems(m_zks); - add_binding(m_pob->get_binding()); - } - update_cube(p, cube); - set_level(lvl); -} - -void lemma::add_skolem(app *zk, app *b) { - SASSERT(m_bindings.size() == m_zks.size()); - // extend bindings - m_bindings.push_back(b); - // extend skolems - m_zks.push_back(zk); -} - - -void lemma::mk_expr_core() { - if (m_body) return; - - if (m_pob) { - mk_cube_core(); - } - - SASSERT(!m_cube.empty()); - m_body = ::push_not(::mk_and(m_cube)); - normalize(m_body, m_body); - - if (!m_zks.empty() && has_zk_const(m_body)) { - app_ref_vector zks(m); - zks.append(m_zks); - zks.reverse(); - expr_abstract(m, 0, - zks.size(), (expr* const*)zks.c_ptr(), m_body, - m_body); - ptr_buffer sorts; - svector names; - for (unsigned i=0, sz=zks.size(); i < sz; ++i) { - sorts.push_back(get_sort(zks.get(i))); - names.push_back(zks.get(i)->get_decl()->get_name()); - } - m_body = m.mk_quantifier(true, zks.size(), - sorts.c_ptr(), - names.c_ptr(), - m_body, 15, symbol(m_body->get_id())); - } - SASSERT(m_body); -} -void lemma::mk_cube_core() { - if (!m_cube.empty()) {return;} - expr_ref cube(m); - if (m_pob || m_body) { - if(m_pob) { - cube = m_pob->post(); - } - else if (m_body) { - // no quantifiers for now - SASSERT(!is_quantifier(m_body)); - cube = m_body; - cube = ::push_not(cube); - } - flatten_and(cube, m_cube); - if (m_cube.empty()) { - m_cube.push_back(m.mk_true()); - } - else { - std::sort(m_cube.c_ptr(), m_cube.c_ptr() + m_cube.size(), ast_lt_proc()); - } - } - else { - UNREACHABLE(); - } -} -bool lemma::is_false() { - // a lemma is false if - // 1. it is defined by a cube, and the cube contains a single literal 'true' - // 2. it is defined by a body, and the body is a single literal false - // 3. it is defined by a pob, and the pob post is false - if (m_cube.size() == 1) {return m.is_true(m_cube.get(0));} - else if (m_body) {return m.is_false(m_body);} - else if (m_pob) {return m.is_true(m_pob->post());} - - return false; -} -expr* lemma::get_expr() { - mk_expr_core(); - return m_body; -} -expr_ref_vector const &lemma::get_cube() { - mk_cube_core(); - return m_cube; -} - -void lemma::update_cube (pob_ref const &p, expr_ref_vector &cube) { - SASSERT(m_pob); - SASSERT(m_pob.get() == p.get()); - m_cube.reset(); - m_body.reset(); - m_cube.append(cube); - if (m_cube.empty()) {m_cube.push_back(m.mk_true());} - - // after the cube is updated, if there are no skolems, - // convert the lemma to quantifier-free - bool is_quant = false; - for (unsigned i = 0, sz = cube.size(); !is_quant && i < sz; ++i) { - is_quant = has_zk_const(cube.get(i)); - } - - if (!is_quant) { - m_zks.reset(); - m_bindings.reset(); - } -} - -bool lemma::has_binding(app_ref_vector const &binding) { - unsigned num_decls = m_zks.size(); - - SASSERT(binding.size() == num_decls); - - if (num_decls == 0) return true; - - for (unsigned off = 0, sz = m_bindings.size(); off < sz; off += num_decls) { - unsigned i = 0; - for (; i < num_decls; ++i) { - if (m_bindings.get(off + i) != binding.get(i)) { - break; - } - } - if (i == num_decls) return true; - } - return false; -} -void lemma::add_binding(app_ref_vector const &binding) { - if (!has_binding(binding)) { - m_bindings.append(binding); - - TRACE("spacer", - tout << "new binding: "; - for (unsigned i = 0; i < binding.size(); i++) - tout << mk_pp(binding.get(i), m) << " "; - tout << "\n";); - } -} -void lemma::instantiate(expr * const * exprs, expr_ref &result, expr *e) { - expr *lem = e == nullptr ? get_expr() : e; - if (!is_quantifier (lem) || m_bindings.empty()) {return;} - - expr *body = to_quantifier(lem)->get_expr(); - unsigned num_decls = to_quantifier(lem)->get_num_decls(); - var_subst vs(m, false); - vs(body, num_decls, exprs, result); -} - -void lemma::set_level (unsigned lvl) { - if(m_pob){ - m_pob->blocked_at(lvl); - } - m_lvl = lvl; -} - - -void lemma::mk_insts(expr_ref_vector &out, expr* e) -{ - expr *lem = e == nullptr ? get_expr() : e; - if (!is_quantifier (lem) || m_bindings.empty()) {return;} - - unsigned num_decls = to_quantifier(lem)->get_num_decls(); - expr_ref inst(m); - for (unsigned off = 0, sz = m_bindings.size(); off < sz; off += num_decls) { - instantiate((expr * const *) m_bindings.c_ptr() + off, inst, e); - out.push_back(inst); - inst.reset(); - } -} +/// pred_transformer::frames bool pred_transformer::frames::add_lemma(lemma *lem) @@ -1575,6 +1967,8 @@ void pred_transformer::frames::simplify_formulas () } } +/// pred_transformer::pobs + pob* pred_transformer::pobs::mk_pob(pob *parent, unsigned level, unsigned depth, expr *post, app_ref_vector const &b) { @@ -1615,400 +2009,8 @@ pob* pred_transformer::pobs::mk_pob(pob *parent, return n; } -app* pred_transformer::extend_initial (expr *e) -{ - // create fresh extend literal - app_ref v(m); - std::stringstream name; - name << m_head->get_name() << "_ext"; - v = m.mk_fresh_const (name.str ().c_str (), - m.mk_bool_sort ()); - v = m.mk_const (pm.get_n_pred (v->get_decl ())); - expr_ref ic(m); - // -- extend the initial condition - ic = m.mk_or (m_extend_lit, e, v); - m_solver.assert_expr (ic); - - // -- remember the new extend literal - m_extend_lit = m.mk_not (v); - - return m_extend_lit; -} - - -// ---------------- -// derivation - -derivation::derivation (pob& parent, datalog::rule const& rule, - expr *trans, app_ref_vector const &evars) : - m_parent (parent), - m_rule (rule), - m_premises (), - m_active (0), - m_trans (trans, m_parent.get_ast_manager ()), - m_evars (evars) {} - -derivation::premise::premise (pred_transformer &pt, unsigned oidx, - expr *summary, bool must, - const ptr_vector *aux_vars) : - m_pt (pt), m_oidx (oidx), - m_summary (summary, pt.get_ast_manager ()), m_must (must), - m_ovars (pt.get_ast_manager ()) -{ - - ast_manager &m = m_pt.get_ast_manager (); - manager &sm = m_pt.get_manager (); - - unsigned sig_sz = m_pt.head ()->get_arity (); - for (unsigned i = 0; i < sig_sz; ++i) - { m_ovars.push_back(m.mk_const(sm.o2o(pt.sig(i), 0, m_oidx))); } - - if (aux_vars) - for (unsigned i = 0, sz = aux_vars->size (); i < sz; ++i) - { m_ovars.push_back(m.mk_const(sm.n2o(aux_vars->get(i)->get_decl(), m_oidx))); } -} - -derivation::premise::premise (const derivation::premise &p) : - m_pt (p.m_pt), m_oidx (p.m_oidx), m_summary (p.m_summary), m_must (p.m_must), - m_ovars (p.m_ovars) {} - -/// \brief Updated the summary. -/// The new summary is over n-variables. -void derivation::premise::set_summary (expr * summary, bool must, - const ptr_vector *aux_vars) -{ - ast_manager &m = m_pt.get_ast_manager (); - manager &sm = m_pt.get_manager (); - unsigned sig_sz = m_pt.head ()->get_arity (); - - m_must = must; - sm.formula_n2o (summary, m_summary, m_oidx); - - m_ovars.reset (); - for (unsigned i = 0; i < sig_sz; ++i) - { m_ovars.push_back(m.mk_const(sm.o2o(m_pt.sig(i), 0, m_oidx))); } - - if (aux_vars) - for (unsigned i = 0, sz = aux_vars->size (); i < sz; ++i) - m_ovars.push_back (m.mk_const (sm.n2o (aux_vars->get (i)->get_decl (), - m_oidx))); -} - - -void derivation::add_premise (pred_transformer &pt, - unsigned oidx, - expr* summary, - bool must, - const ptr_vector *aux_vars) -{m_premises.push_back (premise (pt, oidx, summary, must, aux_vars));} - - - -pob *derivation::create_first_child (model_evaluator_util &mev) -{ - if (m_premises.empty()) { return nullptr; } - m_active = 0; - return create_next_child(mev); -} - -pob *derivation::create_next_child (model_evaluator_util &mev) -{ - timeit _timer (is_trace_enabled("spacer_timeit"), - "spacer::derivation::create_next_child", - verbose_stream ()); - - ast_manager &m = get_ast_manager (); - expr_ref_vector summaries (m); - app_ref_vector vars (m); - - bool use_native_mbp = get_context ().use_native_mbp (); - bool ground = get_context ().use_ground_cti (); - // -- find first may premise - while (m_active < m_premises.size() && m_premises[m_active].is_must()) { - summaries.push_back (m_premises[m_active].get_summary ()); - vars.append (m_premises[m_active].get_ovars ()); - ++m_active; - } - if (m_active >= m_premises.size()) { return nullptr; } - - // -- update m_trans with the pre-image of m_trans over the must summaries - summaries.push_back (m_trans); - m_trans = mk_and (summaries); - summaries.reset (); - - if (!vars.empty()) { - timeit _timer1 (is_trace_enabled("spacer_timeit"), - "create_next_child::qproject1", - verbose_stream ()); - qe_project (m, vars, m_trans, mev.get_model (), true, use_native_mbp, !ground); - //qe::reduce_array_selects (*mev.get_model (), m_trans); - // remember variables that need to be existentially quantified - m_evars.append (vars); - } - - if (!mev.is_true (m_premises[m_active].get_summary())) { - IF_VERBOSE(1, verbose_stream() << "Summary unexpectendly not true\n";); - return nullptr; - } - - - // create the post condition by compute post-image over summaries - // that precede currently active premise - vars.reset (); - for (unsigned i = m_active + 1; i < m_premises.size(); ++i) { - summaries.push_back (m_premises [i].get_summary ()); - vars.append (m_premises [i].get_ovars ()); - } - summaries.push_back (m_trans); - - expr_ref post(m); - post = mk_and (summaries); - summaries.reset (); - if (!vars.empty()) { - timeit _timer2 (is_trace_enabled("spacer_timeit"), - "create_next_child::qproject2", - verbose_stream ()); - qe_project (m, vars, post, mev.get_model (), true, use_native_mbp, !ground); - //qe::reduce_array_selects (*mev.get_model (), post); - - // remember variables that need to be existentially quantified - m_evars.append (vars); - } - - get_manager ().formula_o2n (post.get (), post, - m_premises [m_active].get_oidx (), m_evars.empty()); - - - /* The level and depth are taken from the parent, not the sibling. - The reasoning is that the sibling has not been checked before, - and lower level is a better starting point. */ - pob *n = m_premises[m_active].pt().mk_pob(&m_parent, - prev_level (m_parent.level ()), - m_parent.depth (), post, m_evars); - - IF_VERBOSE (1, verbose_stream () - << "\n\tcreate_child: " << n->pt ().head ()->get_name () - << " (" << n->level () << ", " << n->depth () << ") " - << (n->use_farkas_generalizer () ? "FAR " : "SUB ") - << n->post ()->get_id (); - verbose_stream().flush ();); - return n; -} - -pob *derivation::create_next_child () -{ - if (m_active + 1 >= m_premises.size()) { return nullptr; } - - bool use_native_mbp = get_context ().use_native_mbp (); - bool ground = get_context ().use_ground_cti (); - - // update the summary of the active node to some must summary - - // construct a new model consistent with the must summary of m_active premise - pred_transformer &pt = m_premises[m_active].pt (); - model_ref model; - - ast_manager &m = get_ast_manager (); - manager &pm = get_manager (); - - expr_ref_vector summaries (m); - - for (unsigned i = m_active + 1; i < m_premises.size (); ++i) - { summaries.push_back(m_premises [i].get_summary()); } - - // -- orient transition relation towards m_active premise - expr_ref active_trans (m); - pm.formula_o2n (m_trans, active_trans, - m_premises[m_active].get_oidx (), false); - summaries.push_back (active_trans); - - // if not true, bail out, the must summary of m_active is not strong enough - // this is possible if m_post was weakened for some reason - if (!pt.is_must_reachable(mk_and(summaries), &model)) { return nullptr; } - - model_evaluator_util mev (m); - mev.set_model (*model); - // find must summary used - - reach_fact *rf = pt.get_used_reach_fact (mev, true); - - // get an implicant of the summary - expr_ref_vector u(m), lits (m); - u.push_back (rf->get ()); - compute_implicant_literals (mev, u, lits); - expr_ref v(m); - v = mk_and (lits); - - // XXX The summary is not used by anyone after this point - m_premises[m_active].set_summary (v, true, &(rf->aux_vars ())); - - - /** HACK: needs a rewrite - * compute post over the new must summary this must be done here - * because the must summary is currently described over new - * variables. However, we store it over old-variables, but we do - * not update the model. So we must get rid of all of the - * new-variables at this point. - */ - { - pred_transformer &pt = m_premises[m_active].pt (); - app_ref_vector vars (m); - - summaries.reset (); - summaries.push_back (v); - summaries.push_back (active_trans); - m_trans = mk_and (summaries); - - // variables to eliminate - vars.append (rf->aux_vars ().size (), rf->aux_vars ().c_ptr ()); - for (unsigned i = 0, sz = pt.head ()->get_arity (); i < sz; ++i) - { vars.push_back(m.mk_const(pm.o2n(pt.sig(i), 0))); } - - if (!vars.empty ()) { - qe_project (m, vars, m_trans, mev.get_model (), true, use_native_mbp, - !ground); - // keep track of implicitly quantified variables - m_evars.append (vars); - } - } - - m_active++; - - return create_next_child (mev); -} - -pob::pob (pob* parent, pred_transformer& pt, - unsigned level, unsigned depth, bool add_to_parent): - m_ref_count (0), - m_parent (parent), m_pt (pt), - m_post (m_pt.get_ast_manager ()), - m_binding(m_pt.get_ast_manager()), - m_new_post (m_pt.get_ast_manager ()), - m_level (level), m_depth (depth), - m_open (true), m_use_farkas (true), m_weakness(0), - m_blocked_lvl(0) { - if(add_to_parent && m_parent) { - m_parent->add_child(*this); - } -} - - -void pob::set_post(expr* post) { - app_ref_vector b(get_ast_manager()); - set_post(post, b); -} - -void pob::set_post(expr* post, app_ref_vector const &b) { - normalize(post, m_post, - m_pt.get_context().get_params().spacer_simplify_pob(), - m_pt.get_context().get_params().spacer_use_eqclass()); - - m_binding.reset(); - if (b.empty()) return; - - m_binding.append(b); - - std::sort (m_binding.c_ptr(), m_binding.c_ptr() + m_binding.size(), sk_lt_proc()); - - // skolemize implicit existential quantifier - ast_manager &m = get_ast_manager(); - app_ref_vector pinned(m); - - expr_safe_replace sub(m); - for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { - expr* e; - e = m_binding.get(i); - pinned.push_back (mk_zk_const (m, i, get_sort(e))); - sub.insert (e, pinned.back()); - } - sub(m_post); -} - -void pob::inherit(pob const &p) { - SASSERT(m_parent == p.m_parent); - SASSERT(&m_pt == &p.m_pt); - SASSERT(m_post == p.m_post); - SASSERT(!m_new_post); - - m_binding.reset(); - m_binding.append(p.m_binding); - - m_level = p.m_level; - m_depth = p.m_depth; - m_open = p.m_open; - m_use_farkas = p.m_use_farkas; - m_weakness = p.m_weakness; - - m_derivation = nullptr; -} - -void pob::clean () { - if(m_new_post) { - m_post = m_new_post; - m_new_post.reset(); - } -} - -void pob::close () { - if(!m_open) { return; } - - reset (); - m_open = false; - for (unsigned i = 0, sz = m_kids.size (); i < sz; ++i) - { m_kids [i]->close(); } -} - -void pob::get_skolems(app_ref_vector &v) { - for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { - expr* e; - e = m_binding.get(i); - v.push_back (mk_zk_const (get_ast_manager(), i, get_sort(e))); - } -} - - - -// ---------------- -// pob_queue - -pob* pob_queue::top () -{ - /// nothing in the queue - if (m_obligations.empty()) { return nullptr; } - /// top queue element is above max level - if (m_obligations.top()->level() > m_max_level) { return nullptr; } - /// top queue element is at the max level, but at a higher than base depth - if (m_obligations.top ()->level () == m_max_level && - m_obligations.top()->depth() > m_min_depth) { return nullptr; } - - /// there is something good in the queue - return m_obligations.top ().get (); -} - -void pob_queue::set_root(pob& root) -{ - m_root = &root; - m_max_level = root.level (); - m_min_depth = root.depth (); - reset(); -} - -pob_queue::~pob_queue() {} - -void pob_queue::reset() -{ - while (!m_obligations.empty()) { m_obligations.pop(); } - if (m_root) { m_obligations.push(m_root); } -} - -void pob_queue::push(pob &n) { - TRACE("pob_queue", - tout << "pob_queue::push(" << n.post()->get_id() << ")\n";); - m_obligations.push (&n); - n.get_context().new_pob_eh(&n); -} // ---------------- // context @@ -3715,6 +3717,7 @@ bool context::is_inductive() { return false; } +/// pob_lt operator inline bool pob_lt::operator() (const pob *pn1, const pob *pn2) const { SASSERT (pn1); From 5a6bd5e782689c374b7ea983c8d16de5954449d5 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 18 May 2018 14:12:15 -0700 Subject: [PATCH 1020/1283] hypothesis_reducer: worked around propositional literals propositional formulas (disjunctions) can appear as literals. This makes it tricky to recognize whether a formula is a unit clause when re-building unit resolution. Added work-around that identifies whether a formula is a literal based on its appearance in previous unit resolution step. --- src/muz/spacer/spacer_proof_utils.cpp | 72 ++++++++++++++++----------- src/muz/spacer/spacer_proof_utils.h | 2 +- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 3ca9b0c25..151446a93 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -363,7 +363,7 @@ proof* hypothesis_reducer::reduce_core(proof* pf) { else if (m.is_unit_resolution(p)) { // unit: reduce untis; reduce the first premise; rebuild // unit resolution - res = mk_unit_resolution_core(args); + res = mk_unit_resolution_core(p, args); // -- re-compute hypsets compute_hypsets(res); } @@ -420,12 +420,13 @@ proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { return res; } -proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) { +proof* hypothesis_reducer::mk_unit_resolution_core(proof *ures, + ptr_buffer& args) { // if any literal is false, we don't need a unit resolution step // This can be the case due to some previous transformations for (unsigned i = 1, sz = args.size(); i < sz; ++i) { if (m.is_false(m.get_fact(args[i]))) { - // XXX just in case + // XXX pin just in case m_pinned.push_back(args[i]); return args[i]; } @@ -434,48 +435,58 @@ proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) { proof* arg0 = args[0]; app *fact0 = to_app(m.get_fact(arg0)); + ptr_buffer pf_args; ptr_buffer pf_fact; - pf_args.push_back(arg0); - // check if fact0 can be resolved as a unit - // this is required for handling literals with OR - for (unsigned j = 1; j < args.size(); ++j) { - if (m.is_complement(fact0, m.get_fact(args[j]))) { - pf_args.push_back(args[j]); - break; + // compute literals to be resolved + ptr_buffer lits; + + // fact0 is a literal whenever the original resolution was a + // binary resolution to an empty clause + if (m.get_num_parents(ures) == 2 && m.is_false(m.get_fact(ures))) { + lits.push_back(fact0); + } + // fact0 is a literal unless it is a dijsunction + else if (!m.is_or(fact0)) { + lits.push_back(fact0); + } + // fact0 is a literal only if it appears as a literal in the + // original resolution + else { + lits.reset(); + app* ures_fact = to_app(m.get_fact(m.get_parent(ures, 0))); + for (unsigned i = 0, sz = ures_fact->get_num_args(); i < sz; ++i) { + if (ures_fact->get_arg(i) == fact0) { + lits.push_back(fact0); + break; + } } + if (lits.empty()) { + lits.append(fact0->get_num_args(), fact0->get_args()); + } + } - - // if failed to find a resolvent, and the fact is a disjunction, - // attempt to resolve each disjunct - if (pf_args.size() == 1 && m.is_or(fact0)) { - ptr_buffer cls; - for (unsigned i = 0, sz = fact0->get_num_args(); i < sz; ++i) - cls.push_back(fact0->get_arg(i)); - - // -- find all literals that are resolved on - // XXX quadratic implementation - for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { - bool found = false; - for (unsigned j = 1; j < args.size(); ++j) { - if (m.is_complement(cls.get(i), m.get_fact(args[j]))) { - found = true; - pf_args.push_back(args[j]); - break; - } + // -- find all literals that are resolved on + for (unsigned i = 0, sz = lits.size(); i < sz; ++i) { + bool found = false; + for (unsigned j = 1; j < args.size(); ++j) { + if (m.is_complement(lits.get(i), m.get_fact(args[j]))) { + found = true; + pf_args.push_back(args[j]); + break; } - if (!found) pf_fact.push_back(cls.get(i)); } - SASSERT(pf_fact.size() + pf_args.size() - 1 == cls.size()); + if (!found) {pf_fact.push_back(lits.get(i));} } // unit resolution got reduced to noop if (pf_args.size() == 1) { // XXX pin just in case m_pinned.push_back(arg0); + return arg0; } @@ -484,6 +495,7 @@ proof* hypothesis_reducer::mk_unit_resolution_core(ptr_buffer& args) { tmp = mk_or(m, pf_fact.size(), pf_fact.c_ptr()); proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), tmp); m_pinned.push_back(res); + return res; } diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index 2e1129896..7ab022814 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -96,7 +96,7 @@ private: proof* reduce_core(proof* pf); proof* mk_lemma_core(proof *pf, expr *fact); - proof* mk_unit_resolution_core(ptr_buffer& args); + proof* mk_unit_resolution_core(proof* ures, ptr_buffer& args); proof* mk_proof_core(proof* old, ptr_buffer& args); }; } From 2f369d8d4119225b137df04382bd09ee5ef4c778 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 18 May 2018 16:17:27 -0700 Subject: [PATCH 1021/1283] Simplify code using C++11 conventions --- src/muz/spacer/spacer_context.cpp | 218 ++++++++++++++---------------- src/muz/spacer/spacer_context.h | 3 +- 2 files changed, 100 insertions(+), 121 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 2709593ad..fc0246ec6 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1020,14 +1020,14 @@ void pred_transformer::add_reach_fact (reach_fact *fact) << mk_pp(fact->get (), m) << "\n";); // -- avoid duplicates - if (fact == nullptr || get_reach_fact(fact->get())) { return; } + if (fact == nullptr || get_reach_fact(fact->get())) {return;} // all initial facts are grouped together SASSERT (!fact->is_init () || m_reach_facts.empty () || m_reach_facts.back ()->is_init ()); m_reach_facts.push_back (fact); - if (fact->is_init()) { m_rf_init_sz++; } + if (fact->is_init()) {m_rf_init_sz++;} // update m_reach_ctx @@ -1035,9 +1035,9 @@ void pred_transformer::add_reach_fact (reach_fact *fact) expr_ref new_var (m); expr_ref fml (m); - if (!m_reach_case_vars.empty()) { last_var = m_reach_case_vars.back(); } + if (!m_reach_case_vars.empty()) {last_var = m_reach_case_vars.back();} if (fact->is_init () || !ctx.get_params ().spacer_reach_as_init ()) - { new_var = mk_fresh_reach_case_var(); } + {new_var = mk_fresh_reach_case_var();} else { new_var = extend_initial (fact->get ())->get_arg (0); m_reach_case_vars.push_back (new_var); @@ -1045,10 +1045,8 @@ void pred_transformer::add_reach_fact (reach_fact *fact) SASSERT (m_reach_facts.size () == m_reach_case_vars.size ()); - if (last_var) - { fml = m.mk_or(m.mk_not(last_var), fact->get(), new_var); } - else - { fml = m.mk_or(fact->get(), new_var); } + if (last_var) {fml = m.mk_or(m.mk_not(last_var), fact->get(), new_var);} + else {fml = m.mk_or(fact->get(), new_var);} m_reach_ctx->assert_expr (fml); TRACE ("spacer", @@ -1056,9 +1054,8 @@ void pred_transformer::add_reach_fact (reach_fact *fact) lemma lem(m, fml, infty_level()); // update users; reach facts are independent of levels - for (unsigned i = 0; i < m_use.size(); ++i) { - m_use[i]->add_lemma_from_child (*this, &lem, infty_level ()); - } + for (auto use : m_use) + {use->add_lemma_from_child (*this, &lem, infty_level());} } expr_ref pred_transformer::get_reachable() @@ -1503,13 +1500,12 @@ void pred_transformer::init_reach_facts () expr_ref_vector v(m); reach_fact_ref fact; - rule2expr::iterator it = m_rule2tag.begin (), end = m_rule2tag.end (); - for (; it != end; ++it) { - const datalog::rule* r = it->m_key; + for (auto &entry : m_rule2tag) { + const datalog::rule* r = entry.m_key; if (r->get_uninterpreted_tail_size() == 0) { - fact = alloc (reach_fact, m, *r, m_rule2transition.find (r), - get_aux_vars (*r), true); - add_reach_fact (fact.get ()); + fact = alloc (reach_fact, m, *r, m_rule2transition.find(r), + get_aux_vars(*r), true); + add_reach_fact(fact.get ()); } } } @@ -1517,59 +1513,54 @@ void pred_transformer::init_reach_facts () void pred_transformer::init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transition) { expr_ref_vector transitions(m); - ptr_vector tr_rules; + ptr_vector tr_rules; datalog::rule const* rule; expr_ref_vector disj(m), init_conds (m); app_ref pred(m); vector is_init; - for (unsigned i = 0; i < rules().size(); ++i) { - init_rule(pts, *rules()[i], is_init, tr_rules, transitions); - } + for (auto r : m_rules) {init_rule(pts, *r, is_init, tr_rules, transitions);} SASSERT (is_init.size () == transitions.size ()); + + std::string name; switch(transitions.size()) { case 0: transition = m.mk_false(); break; - case 1: { - std::stringstream name; + case 1: // create a dummy tag. - name << head()->get_name() << "_dummy"; - pred = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); + name = head()->get_name().str() + "_dummy"; + pred = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); + rule = tr_rules[0]; m_tag2rule.insert(pred, rule); m_rule2tag.insert(rule, pred.get()); - transitions [0] = m.mk_implies (pred, transitions.get (0)); - transitions.push_back (m.mk_or (pred, m_extend_lit->get_arg (0))); - if (!is_init [0]) { init_conds.push_back(m.mk_not(pred)); } + transitions[0] = m.mk_implies (pred, transitions.get(0)); + transitions.push_back (m.mk_or (pred, m_extend_lit->get_arg(0))); + if (!is_init[0]) {init_conds.push_back(m.mk_not(pred));} transition = mk_and(transitions); break; - } default: - disj.push_back (m_extend_lit->get_arg (0)); + disj.push_back (m_extend_lit->get_arg(0)); for (unsigned i = 0; i < transitions.size(); ++i) { - std::stringstream name; - name << head()->get_name() << "_tr" << i; - pred = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); + name = head()->get_name().str() + "__tr" + std::to_string(i); + pred = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); rule = tr_rules[i]; m_tag2rule.insert(pred, rule); m_rule2tag.insert(rule, pred); disj.push_back(pred); transitions[i] = m.mk_implies(pred, transitions[i].get()); // update init conds - if (!is_init[i]) { - init_conds.push_back (m.mk_not (pred)); - } + if (!is_init[i]) {init_conds.push_back (m.mk_not (pred));} } transitions.push_back(m.mk_or(disj.size(), disj.c_ptr())); transition = mk_and(transitions); break; } // mk init condition - init = mk_and (init_conds); - if (init_conds.empty ()) { // no rule has uninterpreted tail - m_all_init = true; - } + init = mk_and(init_conds); + // no rule has uninterpreted tail + if (init_conds.empty ()) {m_all_init = true;} } static bool is_all_non_null(app_ref_vector const& v) @@ -1580,109 +1571,100 @@ static bool is_all_non_null(app_ref_vector const& v) return true; } -void pred_transformer::init_rule( - decl2rel const& pts, - datalog::rule const& rule, - vector& is_init, - ptr_vector& rules, - expr_ref_vector& transitions) -{ +void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule, + vector& is_init, + ptr_vector& rules, + expr_ref_vector& transitions) { scoped_watch _t_(m_initialize_watch); // Predicates that are variable representatives. Other predicates at // positions the variables occur are made equivalent with these. - expr_ref_vector conj(m); - app_ref_vector& var_reprs = *(alloc(app_ref_vector, m)); + expr_ref_vector side(m); + app_ref_vector* var_reprs = alloc(app_ref_vector, m); + SASSERT(var_reprs); ptr_vector aux_vars; unsigned ut_size = rule.get_uninterpreted_tail_size(); unsigned t_size = rule.get_tail_size(); SASSERT(ut_size <= t_size); - init_atom(pts, rule.get_head(), var_reprs, conj, UINT_MAX); + init_atom(pts, rule.get_head(), *var_reprs, side, UINT_MAX); for (unsigned i = 0; i < ut_size; ++i) { if (rule.is_neg_tail(i)) { - throw default_exception("SPACER does not support negated predicates in rule tails"); + throw default_exception("SPACER does not support " + "negated predicates in rule tails"); } - init_atom(pts, rule.get_tail(i), var_reprs, conj, i); + init_atom(pts, rule.get_tail(i), *var_reprs, side, i); } // -- substitute free variables expr_ref fml(m); { expr_ref_vector tail(m); for (unsigned i = ut_size; i < t_size; ++i) - { tail.push_back(rule.get_tail(i)); } + {tail.push_back(rule.get_tail(i));} fml = mk_and (tail); - ground_free_vars (fml, var_reprs, aux_vars, ut_size == 0); - SASSERT(is_all_non_null(var_reprs)); + ground_free_vars(fml, *var_reprs, aux_vars, ut_size == 0); + SASSERT(is_all_non_null(*var_reprs)); expr_ref tmp(m); - var_subst (m, false)(fml, - var_reprs.size (), (expr*const*)var_reprs.c_ptr(), tmp); - flatten_and (tmp, conj); - fml = mk_and(conj); - conj.reset (); + var_subst (m, false)(fml, var_reprs->size (), + (expr*const*)var_reprs->c_ptr(), tmp); + flatten_and (tmp, side); + fml = mk_and(side); + side.reset (); } + // rewrite and simplify th_rewriter rw(m); rw(fml); - if (ctx.get_params().spacer_blast_term_ite()) { - blast_term_ite (fml); - rw(fml); - } + if (ctx.get_params().spacer_blast_term_ite()) {blast_term_ite(fml); rw(fml);} TRACE("spacer", tout << mk_pp(fml, m) << "\n";); // allow quantifiers in init rule SASSERT(ut_size == 0 || is_ground(fml)); - if (m.is_false(fml)) { - // no-op. - } else { + if (!m.is_false(fml)) { is_init.push_back (ut_size == 0); transitions.push_back(fml); - m.inc_ref(fml); - m_rule2transition.insert(&rule, fml.get()); rules.push_back(&rule); + + m.inc_ref(fml); + m_rule2transition.insert(&rule, fml); } - m_rule2inst.insert(&rule,&var_reprs); + // AG: shouldn't this be under the if-statement above? + m_rule2inst.insert(&rule, var_reprs); m_rule2vars.insert(&rule, aux_vars); + TRACE("spacer", tout << rule.get_decl()->get_name() << "\n"; - for (unsigned i = 0; i < var_reprs.size(); ++i) { - tout << mk_pp(var_reprs[i].get(), m) << " "; - } - tout << "\n";); + tout << *var_reprs << "\n";); } // create constants for free variables in tail. void pred_transformer::ground_free_vars(expr* e, app_ref_vector& vars, - ptr_vector& aux_vars, bool is_init) -{ + ptr_vector& aux_vars, bool is_init) { expr_free_vars fv; fv(e); - while (vars.size() < fv.size()) { - vars.push_back(nullptr); - } + while (vars.size() < fv.size()) {vars.push_back(nullptr);} + for (unsigned i = 0; i < fv.size(); ++i) { if (fv[i] && !vars[i].get()) { - vars[i] = m.mk_fresh_const("aux", fv[i]); - vars[i] = m.mk_const (pm.get_n_pred (vars.get (i)->get_decl ())); - aux_vars.push_back(vars[i].get()); + // AG: is it useful to make names unique across rules? + app_ref v(m); + v = m.mk_fresh_const("aux", fv[i]); + v = m.mk_const (pm.get_n_pred(v->get_decl ())); + vars[i] = v; + aux_vars.push_back(v); } } } // create names for variables used in relations. -void pred_transformer::init_atom( - decl2rel const& pts, - app * atom, - app_ref_vector& var_reprs, - expr_ref_vector& conj, - unsigned tail_idx - ) -{ +void pred_transformer::init_atom(decl2rel const &pts, app *atom, + app_ref_vector &var_reprs, + expr_ref_vector &side, unsigned tail_idx) { unsigned arity = atom->get_num_args(); func_decl* head = atom->get_decl(); pred_transformer& pt = *pts.find(head); @@ -1704,13 +1686,13 @@ void pred_transformer::init_atom( } expr * repr = var_reprs[var_idx].get(); if (repr) { - conj.push_back(m.mk_eq(rep, repr)); + side.push_back(m.mk_eq(rep, repr)); } else { var_reprs[var_idx] = rep; } } else { SASSERT(is_app(arg)); - conj.push_back(m.mk_eq(rep, arg)); + side.push_back(m.mk_eq(rep, arg)); } } } @@ -2061,23 +2043,22 @@ void context::init_rules(datalog::rule_set& rules, decl2rel& rels) { scoped_watch _t_(m_init_rules_watch); m_context = &rules.get_context(); + // Allocate collection of predicate transformers - datalog::rule_set::decl2rules::iterator dit = rules.begin_grouped_rules(), dend = rules.end_grouped_rules(); - decl2rel::obj_map_entry* e; - for (; dit != dend; ++dit) { + for (auto dit = rules.begin_grouped_rules(), + dend = rules.end_grouped_rules(); dit != dend; ++dit) { func_decl* pred = dit->m_key; TRACE("spacer", tout << mk_pp(pred, m) << "\n";); SASSERT(!rels.contains(pred)); - e = rels.insert_if_not_there2(pred, alloc(pred_transformer, *this, - get_manager(), pred)); + auto *e = rels.insert_if_not_there2(pred, alloc(pred_transformer, *this, + get_manager(), pred)); datalog::rule_vector const& pred_rules = *dit->m_value; - for (unsigned i = 0; i < pred_rules.size(); ++i) { - e->get_data().m_value->add_rule(pred_rules[i]); - } + for (auto rule : pred_rules) {e->get_data().m_value->add_rule(rule);} } - datalog::rule_set::iterator rit = rules.begin(), rend = rules.end(); - for (; rit != rend; ++rit) { - datalog::rule* r = *rit; + + // Allocate predicate transformers for predicates that are used + // but don't have rules + for (auto *r : rules) { pred_transformer* pt; unsigned utz = r->get_uninterpreted_tail_size(); for (unsigned i = 0; i < utz; ++i) { @@ -2088,32 +2069,28 @@ void context::init_rules(datalog::rule_set& rules, decl2rel& rels) } } } + // Initialize use list dependencies - decl2rel::iterator it = rels.begin(), end = rels.end(); - for (; it != end; ++it) { - func_decl* pred = it->m_key; - pred_transformer* pt = it->m_value, *pt_user; - obj_hashtable const& deps = rules.get_dependencies().get_deps(pred); - obj_hashtable::iterator itf = deps.begin(), endf = deps.end(); - for (; itf != endf; ++itf) { - TRACE("spacer", tout << mk_pp(pred, m) << " " << mk_pp(*itf, m) << "\n";); - pt_user = rels.find(*itf); + // for (auto it = rels.begin(), end = rels.end(); it != end; ++it) { + for (auto &entry : rels) { + func_decl* pred = entry.m_key; + pred_transformer* pt = entry.m_value, *pt_user; + for (auto dep : rules.get_dependencies().get_deps(pred)) { + TRACE("spacer", tout << mk_pp(pred, m) << " " << mk_pp(dep, m) << "\n";); + rels.find(dep, pt_user); pt_user->add_use(pt); } } // Initialize the predicate transformers. - it = rels.begin(), end = rels.end(); - for (; it != end; ++it) { - pred_transformer& rel = *it->m_value; - rel.initialize(rels); - TRACE("spacer", rel.display(tout); ); + for (auto &entry : rels) { + pred_transformer* rel = entry.m_value; + rel->initialize(rels); + TRACE("spacer", rel->display(tout); ); } // initialize reach facts - it = rels.begin (), end = rels.end (); - for (; it != end; ++it) - { it->m_value->init_reach_facts(); } + for (auto &entry : rels) {entry.m_value->init_reach_facts();} } void context::update_rules(datalog::rule_set& rules) @@ -2861,6 +2838,7 @@ bool context::check_reachability () node = m_pob_queue.top (); m_pob_queue.pop(); unsigned old_sz = m_pob_queue.size(); + (void)old_sz; SASSERT (node->level () <= m_pob_queue.max_level ()); switch (expand_pob(*node, new_pobs)) { case l_true: diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 475a7472c..9be990d8e 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -316,7 +316,8 @@ class pred_transformer { void init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transition); void init_rule(decl2rel const& pts, datalog::rule const& rule, vector& is_init, ptr_vector& rules, expr_ref_vector& transition); - void init_atom(decl2rel const& pts, app * atom, app_ref_vector& var_reprs, expr_ref_vector& conj, unsigned tail_idx); + void init_atom(decl2rel const& pts, app * atom, app_ref_vector& var_reprs, + expr_ref_vector& side, unsigned tail_idx); void simplify_formulas(tactic& tac, expr_ref_vector& fmls); From 7281616084e7b05f372d95136006ecffb26bdd32 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 19 May 2018 17:52:56 -0700 Subject: [PATCH 1022/1283] model_evaluator: optionally expand arrays as sequence of stores commit on behalf of Nikolaj --- src/model/model_evaluator.cpp | 35 ++++++++++++++-------------- src/model/model_evaluator.h | 6 +++++ src/model/model_evaluator_params.pyg | 3 ++- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 07ee125f8..eb7131406 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -53,6 +53,7 @@ struct evaluator_cfg : public default_rewriter_cfg { bool m_model_completion; bool m_cache; bool m_array_equalities; + bool m_array_as_stores; evaluator_cfg(ast_manager & m, model_core & md, params_ref const & p): m(m), @@ -87,6 +88,7 @@ struct evaluator_cfg : public default_rewriter_cfg { m_model_completion = p.completion(); m_cache = p.cache(); m_array_equalities = p.array_equalities(); + m_array_as_stores = p.array_as_stores(); } bool evaluate(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -196,20 +198,22 @@ struct evaluator_cfg : public default_rewriter_cfg { if (evaluate(a->get_decl(), a->get_num_args(), a->get_args(), result)) { return BR_REWRITE1; } + if (false && m_array_as_stores && m_ar.is_array(result)) { + expand_stores(result); + } } CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); return st; } - void expand_value(expr_ref& val) { + void expand_stores(expr_ref& val) { vector stores; expr_ref else_case(m); bool _unused; if (m_ar.is_array(val) && extract_array_func_interp(val, stores, else_case, _unused)) { sort* srt = m.get_sort(val); val = m_ar.mk_const_array(srt, else_case); - for (unsigned i = stores.size(); i > 0; ) { - --i; + for (unsigned i = stores.size(); i-- > 0; ) { expr_ref_vector args(m); args.push_back(val); args.append(stores[i].size(), stores[i].c_ptr()); @@ -288,7 +292,6 @@ struct evaluator_cfg : public default_rewriter_cfg { bool cache_results() const { return m_cache; } - br_status mk_array_eq(expr* a, expr* b, expr_ref& result) { if (a == b) { result = m.mk_true(); @@ -497,9 +500,6 @@ struct evaluator_cfg : public default_rewriter_cfg { TRACE("model_evaluator", tout << "else case: " << mk_pp(else_case, m) << "\n";); return true; } - - - }; template class rewriter_tpl; @@ -513,10 +513,7 @@ struct model_evaluator::imp : public rewriter_tpl { m_cfg(md.get_manager(), md, p) { set_cancel_check(false); } - - void expand_value (expr_ref &val) { - m_cfg.expand_value (val); - } + void expand_stores(expr_ref &val) {m_cfg.expand_stores(val);} }; model_evaluator::model_evaluator(model_core & md, params_ref const & p) { @@ -571,7 +568,7 @@ void model_evaluator::reset(model_core &model, params_ref const& p) { void model_evaluator::operator()(expr * t, expr_ref & result) { TRACE("model_evaluator", tout << mk_ismt2_pp(t, m()) << "\n";); m_imp->operator()(t, result); - m_imp->expand_value(result); + m_imp->expand_stores(result); } expr_ref model_evaluator::operator()(expr * t) { @@ -581,6 +578,13 @@ expr_ref model_evaluator::operator()(expr * t) { return result; } +expr_ref_vector model_evaluator::operator()(expr_ref_vector const& ts) { + expr_ref_vector rs(m()); + for (expr* t : ts) rs.push_back((*this)(t)); + return rs; +} + + bool model_evaluator::is_true(expr* t) { expr_ref tmp(m()); return eval(t, tmp, true) && m().is_true(tmp); @@ -601,12 +605,12 @@ bool model_evaluator::eval(expr* t, expr_ref& r, bool model_completion) { try { r = (*this)(t); return true; - } + } catch (model_evaluator_exception &ex) { (void)ex; TRACE("model_evaluator", tout << ex.msg () << "\n";); return false; - } + } } bool model_evaluator::eval(expr_ref_vector const& ts, expr_ref& r, bool model_completion) { @@ -614,6 +618,3 @@ bool model_evaluator::eval(expr_ref_vector const& ts, expr_ref& r, bool model_co tmp = mk_and(ts); return eval(tmp, r, model_completion); } - - - diff --git a/src/model/model_evaluator.h b/src/model/model_evaluator.h index 6ae7d8891..d9bf3c375 100644 --- a/src/model/model_evaluator.h +++ b/src/model/model_evaluator.h @@ -44,6 +44,7 @@ public: void operator()(expr * t, expr_ref & r); expr_ref operator()(expr* t); + expr_ref_vector operator()(expr_ref_vector const& ts); // exception safe bool eval(expr* t, expr_ref& r, bool model_completion = true); @@ -53,6 +54,11 @@ public: bool is_false(expr * t); bool is_true(expr_ref_vector const& ts); + /** + * best effort evaluator of extensional array equality. + */ + expr_ref eval_array_eq(app* e, expr* arg1, expr* arg2); + void cleanup(params_ref const & p = params_ref()); void reset(params_ref const & p = params_ref()); void reset(model_core& model, params_ref const & p = params_ref()); diff --git a/src/model/model_evaluator_params.pyg b/src/model/model_evaluator_params.pyg index b6417f7fc..509b3e7c7 100644 --- a/src/model/model_evaluator_params.pyg +++ b/src/model/model_evaluator_params.pyg @@ -4,6 +4,7 @@ def_module_params('model_evaluator', max_steps_param(), ('completion', BOOL, False, 'assigns an interptetation to symbols that do not have one in the current model, when evaluating expressions in the current model'), ('cache', BOOL, True, 'cache intermediate results in the model evaluator'), - ('array_equalities', BOOL, True, 'evaluate array equalities') + ('array_equalities', BOOL, True, 'evaluate array equalities'), + ('array_as_stores', BOOL, True, 'return array as a set of stores'), )) From 988466705c47cabb216b892b72dcf60939086a90 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 19 May 2018 17:53:28 -0700 Subject: [PATCH 1023/1283] port array projection to qe_arrays ensure it works with multi-dimensional arrays commit on behalf of Nikolaj --- src/qe/qe_arrays.cpp | 1106 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1103 insertions(+), 3 deletions(-) diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index a227d755e..ad9d5d63f 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -18,16 +18,144 @@ Revision History: --*/ -#include "qe/qe_arrays.h" +#include "util/lbool.h" #include "ast/rewriter/rewriter_def.h" #include "ast/expr_functors.h" #include "ast/rewriter/expr_safe_replace.h" -#include "util/lbool.h" +#include "ast/rewriter/th_rewriter.h" #include "ast/ast_util.h" #include "ast/ast_pp.h" +#include "model/model_evaluator.h" +#include "qe/qe_arrays.h" + + +namespace { + bool is_partial_eq (app* a); + + /** + * \brief utility class for partial equalities + * + * A partial equality (a ==I b), for two arrays a,b and a finite set of indices I holds + * iff (Forall i. i \not\in I => a[i] == b[i]); in other words, it is a + * restricted form of the extensionality axiom + * + * using this class, we denote (a =I b) as f(a,b,i0,i1,...) + * where f is an uninterpreted predicate with name PARTIAL_EQ and + * I = {i0,i1,...} + */ + + // TBD: make work for arrays with multiple arguments. + class peq { + ast_manager& m; + expr_ref m_lhs; + expr_ref m_rhs; + vector m_diff_indices; + func_decl_ref m_decl; // the partial equality declaration + app_ref m_peq; // partial equality application + app_ref m_eq; // equivalent std equality using def. of partial eq + array_util m_arr_u; + + public: + static const char* PARTIAL_EQ; + + peq (app* p, ast_manager& m): + m (m), + m_lhs (p->get_arg (0), m), + m_rhs (p->get_arg (1), m), + m_decl (p->get_decl (), m), + m_peq (p, m), + m_eq (m), + m_arr_u (m) + { + VERIFY (is_partial_eq (p)); + SASSERT (m_arr_u.is_array (m_lhs) && + m_arr_u.is_array (m_rhs) && + m.get_sort(m_lhs) == m.get_sort(m_rhs)); + unsigned arity = get_array_arity(m.get_sort(m_lhs)); + for (unsigned i = 2; i < p->get_num_args (); i += arity) { + SASSERT(arity + i <= p->get_num_args()); + expr_ref_vector vec(m); + vec.append(arity, p->get_args() + i); + m_diff_indices.push_back (vec); + } + } + + peq (expr* lhs, expr* rhs, vector const& diff_indices, ast_manager& m): + m (m), + m_lhs (lhs, m), + m_rhs (rhs, m), + m_diff_indices (diff_indices), + m_decl (m), + m_peq (m), + m_eq (m), + m_arr_u (m) { + SASSERT (m_arr_u.is_array (lhs) && + m_arr_u.is_array (rhs) && + m.get_sort(lhs) == m.get_sort(rhs)); + ptr_vector sorts; + sorts.push_back (m.get_sort (m_lhs)); + sorts.push_back (m.get_sort (m_rhs)); + for (auto const& v : diff_indices) { + SASSERT(v.size() == get_array_arity(m.get_sort(m_lhs))); + for (expr* e : v) + sorts.push_back (m.get_sort(e)); + } + m_decl = m.mk_func_decl (symbol (PARTIAL_EQ), sorts.size (), sorts.c_ptr (), m.mk_bool_sort ()); + } + + expr_ref lhs () { return m_lhs; } + + expr_ref rhs () { return m_rhs; } + + void get_diff_indices (vector& result) { result.append(m_diff_indices); } + + app_ref mk_peq () { + if (!m_peq) { + ptr_vector args; + args.push_back (m_lhs); + args.push_back (m_rhs); + for (auto const& v : m_diff_indices) { + args.append (v.size(), v.c_ptr()); + } + m_peq = m.mk_app (m_decl, args.size (), args.c_ptr ()); + } + return m_peq; + } + + app_ref mk_eq (app_ref_vector& aux_consts, bool stores_on_rhs = true) { + if (!m_eq) { + expr_ref lhs (m_lhs, m), rhs (m_rhs, m); + if (!stores_on_rhs) { + std::swap (lhs, rhs); + } + // lhs = (...(store (store rhs i0 v0) i1 v1)...) + sort* val_sort = get_array_range (m.get_sort (lhs)); + for (expr_ref_vector const& diff : m_diff_indices) { + ptr_vector store_args; + store_args.push_back (rhs); + store_args.append (diff.size(), diff.c_ptr()); + app_ref val(m.mk_fresh_const ("diff", val_sort), m); + store_args.push_back (val); + aux_consts.push_back (val); + rhs = m_arr_u.mk_store (store_args.size (), store_args.c_ptr ()); + } + m_eq = m.mk_eq (lhs, rhs); + } + return m_eq; + } + }; + + const char* peq::PARTIAL_EQ = "!partial_eq"; + + bool is_partial_eq (app* a) { + return a->get_decl ()->get_name () == peq::PARTIAL_EQ; + } +} namespace qe { + + struct array_project_plugin::imp { // rewriter or direct procedure. @@ -187,7 +315,8 @@ namespace qe { return (*m_var)(e); } - void mk_eq(indices& x, indices y, expr_ref_vector& lits) { + void mk_eq(indices const& x, indices const& y, expr_ref_vector& lits) { + SASSERT(x.m_values.size() == y.m_values.size()); unsigned n = x.m_values.size(); for (unsigned j = 0; j < n; ++j) { lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); @@ -430,5 +559,976 @@ namespace qe { return m_imp->a.get_family_id(); } + static bool is_eq(expr_ref_vector const& xs, expr_ref_vector const& ys) { + for (unsigned i = 0; i < xs.size(); ++i) if (xs[i] != ys[i]) return false; + return true; + } + + static expr_ref mk_eq(expr_ref_vector const& xs, expr_ref_vector const& ys) { + ast_manager& m = xs.get_manager(); + expr_ref_vector eqs(m); + for (unsigned i = 0; i < xs.size(); ++i) eqs.push_back(m.mk_eq(xs[i], ys[i])); + return mk_and(eqs); + } + + + class array_project_eqs_util { + ast_manager& m; + array_util m_arr_u; + model_ref M; + model_evaluator* m_mev; + app_ref m_v; // array var to eliminate + ast_mark m_has_stores_v; // has stores for m_v + expr_ref m_subst_term_v; // subst term for m_v + expr_safe_replace m_true_sub_v; // subst for true equalities + expr_safe_replace m_false_sub_v; // subst for false equalities + expr_ref_vector m_aux_lits_v; + expr_ref_vector m_idx_lits_v; + app_ref_vector m_aux_vars; + + void reset_v () { + m_v = nullptr; + m_has_stores_v.reset (); + m_subst_term_v = nullptr; + m_true_sub_v.reset (); + m_false_sub_v.reset (); + m_aux_lits_v.reset (); + m_idx_lits_v.reset (); + } + + void reset () { + M = nullptr; + m_mev = nullptr; + reset_v (); + m_aux_vars.reset (); + } + + /** + * find all array equalities on m_v or containing stores on/of m_v + * + * also mark terms containing stores on/of m_v + */ + void find_arr_eqs (expr_ref const& fml, app_ref_vector& eqs) { + if (!is_app (fml)) return; + ast_mark done; + ptr_vector todo; + todo.push_back (to_app (fml)); + while (!todo.empty ()) { + app* a = todo.back (); + if (done.is_marked (a)) { + todo.pop_back (); + continue; + } + bool all_done = true; + bool args_have_stores = false; + for (expr * arg : *a) { + if (!is_app (arg)) continue; + if (!done.is_marked (arg)) { + all_done = false; + todo.push_back (to_app (arg)); + } + else if (!args_have_stores && m_has_stores_v.is_marked (arg)) { + args_have_stores = true; + } + } + if (!all_done) continue; + todo.pop_back (); + + // mark if a has stores + if ((!m_arr_u.is_select (a) && args_have_stores) || + (m_arr_u.is_store (a) && (a->get_arg (0) == m_v))) { + m_has_stores_v.mark (a, true); + + TRACE ("qe", + tout << "has stores:\n"; + tout << mk_pp (a, m) << "\n"; + ); + } + + // check if a is a relevant array equality + expr * a0 = nullptr, *a1 = nullptr; + if (m.is_eq (a, a0, a1)) { + if (a0 == m_v || a1 == m_v || + (m_arr_u.is_array (a0) && m_has_stores_v.is_marked (a))) { + eqs.push_back (a); + } + } + // else, we can check for disequalities and handle them using extensionality, + // but it's not necessary + + done.mark (a, true); + } + } + + /** + * factor out select terms on m_v using fresh consts + */ + void factor_selects (app_ref& fml) { + expr_map sel_cache (m); + ast_mark done; + ptr_vector todo; + expr_ref_vector pinned (m); // to ensure a reference + + todo.push_back (fml); + while (!todo.empty ()) { + app* a = todo.back (); + if (done.is_marked (a)) { + todo.pop_back (); + continue; + } + expr_ref_vector args (m); + bool all_done = true; + for (expr * arg : *a) { + if (!is_app (arg)) continue; + if (!done.is_marked (arg)) { + all_done = false; + todo.push_back (to_app (arg)); + } + else if (all_done) { // all done so far.. + expr* arg_new = nullptr; proof* pr; + sel_cache.get (arg, arg_new, pr); + if (!arg_new) { + arg_new = arg; + } + args.push_back (arg_new); + } + } + if (!all_done) continue; + todo.pop_back (); + + expr_ref a_new (m.mk_app (a->get_decl (), args.size (), args.c_ptr ()), m); + + // if a_new is select on m_v, introduce new constant + if (m_arr_u.is_select (a) && + (args.get (0) == m_v || m_has_stores_v.is_marked (args.get (0)))) { + sort* val_sort = get_array_range (m.get_sort (m_v)); + app_ref val_const (m.mk_fresh_const ("sel", val_sort), m); + m_aux_vars.push_back (val_const); + // extend M to include val_const + expr_ref val = (*m_mev)(a_new); + M->register_decl (val_const->get_decl (), val); + // add equality + m_aux_lits_v.push_back (m.mk_eq (val_const, a_new)); + // replace select by const + a_new = val_const; + } + + if (a != a_new) { + sel_cache.insert (a, a_new, nullptr); + pinned.push_back (a_new); + } + done.mark (a, true); + } + expr* res = nullptr; proof* pr; + sel_cache.get (fml, res, pr); + if (res) { + fml = to_app (res); + } + } + + /** + * convert partial equality expression p_exp to an equality by + * recursively adding stores on diff indices + * + * add stores on lhs or rhs depending on whether stores_on_rhs is false/true + */ + void convert_peq_to_eq (expr* p_exp, app_ref& eq, bool stores_on_rhs = true) { + peq p (to_app (p_exp), m); + app_ref_vector diff_val_consts (m); + eq = p.mk_eq (diff_val_consts, stores_on_rhs); + m_aux_vars.append (diff_val_consts); + // extend M to include diff_val_consts + vector I; + expr_ref arr = p.lhs (); + p.get_diff_indices (I); + expr_ref val (m); + unsigned num_diff = diff_val_consts.size (); + SASSERT (num_diff == I.size ()); + for (unsigned i = 0; i < num_diff; i++) { + // mk val term + ptr_vector sel_args; + sel_args.push_back (arr); + sel_args.append(I[i].size(), I[i].c_ptr()); + expr_ref val_term (m_arr_u.mk_select (sel_args.size (), sel_args.c_ptr ()), m); + // evaluate and assign to ith diff_val_const + val = (*m_mev)(val_term); + M->register_decl (diff_val_consts.get (i)->get_decl (), val); + } + } + + /** + * mk (e0 ==indices e1) + * + * result has stores if either e0 or e1 or an index term has stores + */ + app_ref mk_peq (expr* e0, expr* e1, vector const& indices) { + peq p (e0, e1, indices, m); + return p.mk_peq (); + } + + void find_subst_term (app* eq) { + SASSERT(m.is_eq(eq)); + vector empty; + app_ref p_exp = mk_peq (eq->get_arg (0), eq->get_arg (1), empty); + bool subst_eq_found = false; + while (true) { + TRACE ("qe", tout << "processing peq:\n" << p_exp << "\n";); + + peq p (p_exp, m); + expr_ref lhs = p.lhs(), rhs = p.rhs(); + if (!m_has_stores_v.is_marked (lhs)) { + std::swap (lhs, rhs); + } + if (m_has_stores_v.is_marked (lhs)) { + /** project using the equivalence: + * + * (store(arr0,idx,x) ==I arr1) <-> + * + * (idx \in I => (arr0 ==I arr1)) /\ + * (idx \not\in I => (arr0 ==I+idx arr1) /\ (arr1[idx] == x))) + */ + vector I; + expr_ref_vector idxs (m); + p.get_diff_indices (I); + app* a_lhs = to_app (lhs); + expr* arr0 = a_lhs->get_arg (0); + idxs.append(a_lhs->get_num_args() - 2, a_lhs->get_args() + 1); + expr* x = a_lhs->get_arg (2); + expr* arr1 = rhs; + // check if (idx \in I) in M + bool idx_in_I = false; + expr_ref_vector idx_diseq (m); + if (!I.empty ()) { + expr_ref_vector vals = (*m_mev)(idxs); + for (unsigned i = 0; i < I.size () && !idx_in_I; i++) { + if (is_eq(idxs, I.get(i))) { + idx_in_I = true; + } + else { + expr_ref idx_eq = mk_eq(idxs, I[i]); + expr_ref_vector vals1 = (*m_mev)(I[i]); + if (is_eq(vals, vals1)) { + idx_in_I = true; + m_idx_lits_v.push_back (idx_eq); + } + else { + idx_diseq.push_back (m.mk_not (idx_eq)); + } + } + } + } + if (idx_in_I) { + TRACE ("qe", + tout << "store index in diff indices:\n"; + tout << mk_pp (m_idx_lits_v.back (), m) << "\n"; + ); + + // arr0 ==I arr1 + p_exp = mk_peq (arr0, arr1, I); + + TRACE ("qe", + tout << "new peq:\n"; + tout << mk_pp (p_exp, m) << "\n"; + ); + } + else { + m_idx_lits_v.append (idx_diseq); + // arr0 ==I+idx arr1 + I.push_back (idxs); + p_exp = mk_peq (arr0, arr1, I); + + TRACE ("qe", tout << "new peq:\n" << p_exp << "\n"; ); + + // arr1[idx] == x + ptr_vector sel_args; + sel_args.push_back (arr1); + sel_args.append(idxs.size(), idxs.c_ptr()); + expr_ref arr1_idx (m_arr_u.mk_select (sel_args.size (), sel_args.c_ptr ()), m); + expr_ref eq (m.mk_eq (arr1_idx, x), m); + m_aux_lits_v.push_back (eq); + + TRACE ("qe", + tout << "new eq:\n"; + tout << mk_pp (eq, m) << "\n"; + ); + } + } + else if (lhs == rhs) { // trivial peq (a ==I a) + break; + } + else if (lhs == m_v || rhs == m_v) { + subst_eq_found = true; + TRACE ("qe", + tout << "subst eq found!\n"; + ); + break; + } + else { + UNREACHABLE (); + } + } + + // factor out select terms on m_v from p_exp using fresh constants + if (subst_eq_found) { + factor_selects (p_exp); + + TRACE ("qe", + tout << "after factoring selects:\n"; + tout << mk_pp (p_exp, m) << "\n"; + for (unsigned i = m_aux_lits_v.size () - m_aux_vars.size (); i < m_aux_lits_v.size (); i++) { + tout << mk_pp (m_aux_lits_v.get (i), m) << "\n"; + } + ); + + // find subst_term + bool stores_on_rhs = true; + app* a = to_app (p_exp); + if (a->get_arg (1) == m_v) { + stores_on_rhs = false; + } + app_ref eq (m); + convert_peq_to_eq (p_exp, eq, stores_on_rhs); + m_subst_term_v = eq->get_arg (1); + + TRACE ("qe", + tout << "subst term found:\n"; + tout << mk_pp (m_subst_term_v, m) << "\n"; + ); + } + } + + /** + * compute nesting depths of stores on m_v in true_eqs, as follows: + * 0 if m_v appears on both sides of equality + * 1 if equality is (m_v=t) + * 2 if equality is (store(m_v,i,v)=t) + * ... + */ + unsigned get_nesting_depth(app* eq) { + SASSERT(m.is_eq(eq)); + expr* lhs = eq->get_arg (0); + expr* rhs = eq->get_arg (1); + bool lhs_has_v = (lhs == m_v || m_has_stores_v.is_marked (lhs)); + bool rhs_has_v = (rhs == m_v || m_has_stores_v.is_marked (rhs)); + app* store = nullptr; + + SASSERT (lhs_has_v || rhs_has_v); + + if (!lhs_has_v && is_app(rhs)) { + store = to_app (rhs); + } + else if (!rhs_has_v && is_app(lhs)) { + store = to_app (lhs); + } + else { + // v appears on both sides -- trivial equality + // put it in the beginning to simplify it away + return 0; + } + + unsigned nd = 0; // nesting depth + for (nd = 1; m_arr_u.is_store (store); nd++, store = to_app (store->get_arg (0))) + /* empty */ ; + SASSERT (store == m_v); + return nd; + } + + struct compare_nd { + bool operator()(std::pair const& x, std::pair const& y) const { + return x < y; + } + }; + + /** + * try to substitute for m_v, using array equalities + * + * compute substitution term and aux lits + */ + bool project (expr_ref const& fml) { + app_ref_vector eqs (m); + svector > true_eqs; + + find_arr_eqs (fml, eqs); + TRACE ("qe", + tout << "array equalities:\n"; + for (app * eq : eqs) tout << mk_pp(eq, m) << "\n";); + + // evaluate eqs in M + for (app * eq : eqs) { + TRACE ("qe", tout << "array equality:\n" << mk_pp (eq, m) << "\n"; ); + + if (m_mev->is_false(eq)) { + m_false_sub_v.insert (eq, m.mk_false()); + } + else { + true_eqs.push_back (std::make_pair(get_nesting_depth(eq), eq)); + } + } + std::sort(true_eqs.begin(), true_eqs.end(), compare_nd()); + DEBUG_CODE(for (unsigned i = 0; i + 1 < true_eqs.size(); ++i) SASSERT(true_eqs[i].first <= true_eqs[i+1].first);); + + // search for subst term + for (unsigned i = 0; !m_subst_term_v && i < true_eqs.size(); i++) { + app* eq = true_eqs[i].second; + m_true_sub_v.insert (eq, m.mk_true ()); + // try to find subst term + find_subst_term (eq); + } + + return true; + } + + void mk_result (expr_ref& fml) { + th_rewriter rw(m); + rw (fml); + // add in aux_lits and idx_lits + expr_ref_vector lits (m); + // TODO: eliminate possible duplicates, especially in idx_lits + // theory rewriting is a possibility, but not sure if it + // introduces unwanted terms such as ite's + lits.append (m_idx_lits_v); + lits.append (m_aux_lits_v); + lits.push_back (fml); + fml = mk_and(lits); + + if (m_subst_term_v) { + m_true_sub_v.insert (m_v, m_subst_term_v); + m_true_sub_v (fml); + } + else { + m_true_sub_v (fml); + m_false_sub_v (fml); + } + rw(fml); + SASSERT (!m.is_false (fml)); + } + + public: + + array_project_eqs_util (ast_manager& m): + m (m), + m_arr_u (m), + m_v (m), + m_subst_term_v (m), + m_true_sub_v (m), + m_false_sub_v (m), + m_aux_lits_v (m), + m_idx_lits_v (m), + m_aux_vars (m) + {} + + void operator () (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + reset (); + model_evaluator mev(mdl); + M = &mdl; + m_mev = &mev; + + unsigned j = 0; + for (unsigned i = 0; i < arr_vars.size (); i++) { + reset_v (); + m_v = arr_vars.get (i); + if (!m_arr_u.is_array (m_v)) { + TRACE ("qe", + tout << "not an array variable: " << mk_pp (m_v, m) << "\n"; + ); + aux_vars.push_back (m_v); + continue; + } + TRACE ("qe", + tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n"; + ); + + if (project (fml)) { + mk_result (fml); + + contains_app contains_v (m, m_v); + if (!m_subst_term_v || contains_v (m_subst_term_v)) { + arr_vars[j++] = m_v; + } + TRACE ("qe", + tout << "after projection: \n"; + tout << mk_pp (fml, m) << "\n"; + ); + } + else { + IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";); + TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";); + arr_vars[j++] = m_v; + } + } + arr_vars.shrink(j); + aux_vars.append (m_aux_vars); + } + }; + + + class array_select_reducer { + ast_manager& m; + array_util m_arr_u; + obj_map m_cache; + expr_ref_vector m_pinned; // to ensure a reference + expr_ref_vector m_idx_lits; + model_ref M; + model_evaluator* m_mev; + th_rewriter m_rw; + ast_mark m_arr_test; + ast_mark m_has_stores; + bool m_reduce_all_selects; + + void reset () { + m_cache.reset (); + m_pinned.reset (); + m_idx_lits.reset (); + M = nullptr; + m_mev = nullptr; + m_arr_test.reset (); + m_has_stores.reset (); + m_reduce_all_selects = false; + } + + bool is_equals (expr *e1, expr *e2) { + return e1 == e2 || (*m_mev)(e1) == (*m_mev)(e2); + } + + bool is_equals (unsigned arity, expr * const* xs, expr * const * ys) { + for (unsigned i = 0; i < arity; ++i) { + if (!is_equals(xs[i], ys[i])) return false; + } + return true; + } + + expr_ref mk_eq(unsigned arity, expr * const* xs, expr * const * ys) { + expr_ref_vector r(m); + for (unsigned i = 0; i < arity; ++i) { + r.push_back(m.mk_eq(xs[i], ys[i])); + } + return mk_and(r); + } + + void add_idx_cond (expr_ref& cond) { + m_rw (cond); + if (!m.is_true (cond)) m_idx_lits.push_back (cond); + } + + bool has_stores (expr* e) { + if (m_reduce_all_selects) return true; + return m_has_stores.is_marked (e); + } + + void mark_stores (app* a, bool args_have_stores) { + if (m_reduce_all_selects) return; + if (args_have_stores || + (m_arr_u.is_store (a) && m_arr_test.is_marked (a->get_arg (0)))) { + m_has_stores.mark (a, true); + } + } + + bool reduce (expr_ref& e) { + if (!is_app (e)) return true; + + expr *r = nullptr; + if (m_cache.find (e, r)) { + e = r; + return true; + } + + ptr_vector todo; + todo.push_back (to_app (e)); + expr_ref_vector args (m); + + while (!todo.empty ()) { + app *a = todo.back (); + unsigned sz = todo.size (); + bool dirty = false; + bool args_have_stores = false; + args.reset(); + for (expr * arg : *a) { + expr *narg = nullptr; + if (!is_app (arg)) { + args.push_back (arg); + } + else if (m_cache.find (arg, narg)) { + args.push_back (narg); + dirty |= (arg != narg); + if (!args_have_stores && has_stores (narg)) { + args_have_stores = true; + } + } + else { + todo.push_back (to_app (arg)); + } + } + + if (todo.size () > sz) continue; + todo.pop_back (); + + if (dirty) { + r = m.mk_app (a->get_decl (), args.size (), args.c_ptr ()); + m_pinned.push_back (r); + } + else { + r = a; + } + + if (m_arr_u.is_select (r) && has_stores (to_app (r)->get_arg (0))) { + r = reduce_core (to_app(r)); + } + else { + mark_stores (to_app (r), args_have_stores); + } + + m_cache.insert (a, r); + } + + SASSERT (r); + e = r; + return true; + } + + expr* reduce_core (app *a) { + if (!m_arr_u.is_store (a->get_arg (0))) return a; + unsigned arity = get_array_arity(m.get_sort(a)); + expr* array = a->get_arg (0); + expr* const* js = a->get_args() + 1; + + while (m_arr_u.is_store (array)) { + a = to_app (array); + expr* const* idxs = a->get_args() + 1; + expr_ref cond = mk_eq(arity, idxs, js); + + if (is_equals (arity, idxs, js)) { + add_idx_cond (cond); + return a->get_arg (2); + } + else { + cond = m.mk_not (cond); + add_idx_cond (cond); + array = a->get_arg (0); + } + } + ptr_vector args; + args.push_back(array); + args.append(arity, js); + expr* r = m_arr_u.mk_select (args.size(), args.c_ptr()); + m_pinned.push_back (r); + return r; + } + + void mk_result (expr_ref& fml) { + // conjoin idx lits + expr_ref_vector lits (m); + lits.append (m_idx_lits); + lits.push_back (fml); + fml = mk_and(lits); + // simplify all trivial expressions introduced + m_rw (fml); + TRACE ("qe", tout << "after reducing selects:\n" << fml << "\n";); + } + + public: + + array_select_reducer (ast_manager& m): + m (m), + m_arr_u (m), + m_pinned (m), + m_idx_lits (m), + m_rw (m), + m_reduce_all_selects (false) + {} + + void operator () (model& mdl, app_ref_vector const& arr_vars, expr_ref& fml, bool reduce_all_selects = false) { + if (!reduce_all_selects && arr_vars.empty ()) return; + + reset (); + model_evaluator mev(mdl); + M = &mdl; + m_mev = &mev; + m_reduce_all_selects = reduce_all_selects; + + // mark vars to eliminate + for (app* v : arr_vars) { + m_arr_test.mark (v, true); + } + + // assume all arr_vars are of array sort + // and assume no store equalities on arr_vars + if (reduce (fml)) { + mk_result (fml); + } + else { + IF_VERBOSE(2, verbose_stream() << "can't project arrays:" << "\n";); + TRACE ("qe", tout << "Failed to project arrays\n";); + } + } + }; + + + class array_project_selects_util { + typedef obj_map*> sel_map; + + struct idx_val { + expr_ref_vector idx, val; + idx_val(expr_ref_vector & idx, expr_ref_vector & val): idx(idx), val(val) {} + idx_val& operator=(idx_val const& o) { idx.reset(); val.reset(); idx.append(o.idx); val.append(o.val); return *this; } + }; + ast_manager& m; + array_util m_arr_u; + arith_util m_ari_u; + sel_map m_sel_terms; + // representative indices for eliminating selects + vector m_idxs; + app_ref_vector m_sel_consts; + expr_ref_vector m_idx_lits; + model_ref M; + model_evaluator* m_mev; + expr_safe_replace m_sub; + ast_mark m_arr_test; + + void reset () { + m_sel_terms.reset (); + m_idxs.reset(); + m_sel_consts.reset (); + m_idx_lits.reset (); + M = nullptr; + m_mev = nullptr; + m_sub.reset (); + m_arr_test.reset (); + } + + /** + * collect sel terms on array vars as given by m_arr_test + */ + void collect_selects (expr* fml) { + if (!is_app (fml)) return; + ast_mark done; + ptr_vector todo; + todo.push_back (to_app (fml)); + for (unsigned i = 0; i < todo.size(); ++i) { + app* a = todo[i]; + if (done.is_marked (a)) continue; + done.mark (a, true); + for (expr* arg : *a) { + if (!done.is_marked (arg) && is_app (arg)) { + todo.push_back (to_app (arg)); + } + } + if (m_arr_u.is_select (a)) { + expr* arr = a->get_arg (0); + if (m_arr_test.is_marked (arr)) { + ptr_vector* lst = m_sel_terms.find (to_app (arr));; + lst->push_back (a); + } + } + } + } + + struct compare_idx { + array_project_selects_util& u; + compare_idx(array_project_selects_util& u):u(u) {} + bool operator()(idx_val const& x, idx_val const& y) { + for (unsigned j = 0; j < x.val.size(); ++j) { + rational xv, yv; + VERIFY (u.m_ari_u.is_numeral(x.val[j], xv)); + VERIFY (u.m_ari_u.is_numeral(y.val[j], yv)); + if (xv < yv) return true; + if (xv > yv) return false; + } + return false; + } + }; + + expr_ref mk_lex_lt(expr_ref_vector const& xs, expr_ref_vector const& ys) { + SASSERT(xs.size() == ys.size()); + expr_ref result(m_ari_u.mk_lt(xs.back(), ys.back()), m); + for (unsigned i = xs.size()-1; i-- > 0; ) { + result = m.mk_or(m_ari_u.mk_lt(xs[i], ys[i]), + m.mk_and(m.mk_eq(xs[i], ys[i]), result)); + } + return result; + } + + /** + * model based ackermannization for sel terms of some array + * + * update sub with val consts for sel terms + */ + void ackermann (ptr_vector const& sel_terms) { + if (sel_terms.empty ()) return; + + expr* v = sel_terms.get (0)->get_arg (0); // array variable + sort* v_sort = m.get_sort (v); + sort* val_sort = get_array_range (v_sort); + unsigned arity = get_array_arity(v_sort); + + for (unsigned i = 0; i < arity; ++i) { + sort* srt = get_array_domain(v_sort, i); + if (!m_ari_u.is_real(srt) && !m_ari_u.is_int(srt)) { + TRACE("qe", tout << "unsupported index sort for Ackerman" << mk_pp(srt, m) << "\n";); + return; + } + } + + unsigned start = m_idxs.size (); // append at the end + + for (app * a : sel_terms) { + expr_ref_vector idxs(m, arity, a->get_args() + 1); + expr_ref_vector vals = (*m_mev)(idxs); + bool is_new = true; + for (unsigned j = start; j < m_idxs.size (); j++) { + if (!is_eq(m_idxs[j].val, vals)) continue; + // idx belongs to the jth equivalence class; + // substitute sel term with ith sel const + expr* c = m_sel_consts.get (j); + m_sub.insert (a, c); + // add equality (idx == repr) + m_idx_lits.push_back (mk_eq (idxs, m_idxs[j].idx)); + is_new = false; + break; + } + if (is_new) { + // new repr, val, and sel const + m_idxs.push_back(idx_val(idxs, vals)); + app_ref c (m.mk_fresh_const ("sel", val_sort), m); + m_sel_consts.push_back (c); + // substitute sel term with new const + m_sub.insert (a, c); + // extend M to include c + expr_ref val = (*m_mev)(a); + M->register_decl (c->get_decl (), val); + } + } + + // sort reprs by their value and add a chain of strict inequalities + + compare_idx cmp(*this); + std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); + + for (unsigned i = start; i < m_idxs.size()-1; i++) { + m_idx_lits.push_back (mk_lex_lt(m_idxs[i].idx, m_idxs[i+1].idx)); + } + } + + void mk_result (expr_ref& fml) { + // conjoin idx lits + m_idx_lits.push_back(fml); + fml = mk_and (m_idx_lits); + + // substitute for sel terms + m_sub (fml); + + TRACE ("qe", tout << "after projection of selects:\n" << fml << "\n";); + } + + /** + * project selects + * populates idx lits and obtains substitution for sel terms + */ + bool project (expr* fml) { + // collect sel terms -- populate the map m_sel_terms + collect_selects (fml); + // model based ackermannization + for (auto & kv : m_sel_terms) { + TRACE ("qe",tout << "ackermann for var: " << mk_pp (kv.m_key, m) << "\n";); + ackermann (*(kv.m_value)); + } + TRACE ("qe", tout << "idx lits:\n" << m_idx_lits; ); + return true; + } + + public: + + array_project_selects_util (ast_manager& m): + m (m), + m_arr_u (m), + m_ari_u (m), + m_sel_consts (m), + m_idx_lits (m), + m_sub (m) + {} + + void operator () (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + reset (); + model_evaluator mev(mdl); + M = &mdl; + m_mev = &mev; + + // mark vars to eliminate + // alloc empty map from array var to sel terms over it + for (app* v : arr_vars) { + m_arr_test.mark(v, true); + m_sel_terms.insert(v, alloc (ptr_vector)); + } + + // assume all arr_vars are of array sort + // and they only appear in select terms + if (project (fml)) { + mk_result (fml); + aux_vars.append (m_sel_consts); + arr_vars.reset (); + } + else { + IF_VERBOSE(2, verbose_stream() << "can't project arrays:" << "\n";); + TRACE ("qe", tout << "Failed to project arrays\n";); + } + + // dealloc + for (auto & kv : m_sel_terms) dealloc(kv.m_value); + m_sel_terms.reset (); + } + }; + + + static void array_project_eqs (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + ast_manager& m = arr_vars.get_manager (); + array_project_eqs_util ap (m); + ap (mdl, arr_vars, fml, aux_vars); + } + + static void reduce_array_selects (model& mdl, app_ref_vector const& arr_vars, expr_ref& fml, bool reduce_all_selects) { + ast_manager& m = arr_vars.get_manager (); + array_select_reducer ap (m); + ap (mdl, arr_vars, fml, reduce_all_selects); + } + + static void reduce_array_selects (model& mdl, expr_ref& fml) { + ast_manager& m = fml.get_manager (); + app_ref_vector _tmp (m); + reduce_array_selects (mdl, _tmp, fml, true); + } + + static void array_project_selects (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + ast_manager& m = arr_vars.get_manager (); + array_project_selects_util ap (m); + ap (mdl, arr_vars, fml, aux_vars); + } + + void new_array_project (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects) { + // 1. project array equalities + array_project_eqs (mdl, arr_vars, fml, aux_vars); + TRACE ("qe", + tout << "Projected array eqs:\n" << fml << "\n"; + tout << "Remaining array vars:\n" << arr_vars; + tout << "Aux vars:\n" << aux_vars; + ); + + // 2. reduce selects + if (reduce_all_selects) { + reduce_array_selects (mdl, fml); + } + else { + reduce_array_selects (mdl, arr_vars, fml, false); + } + TRACE ("qe", + tout << "Reduced selects:\n" << fml << "\n"; + ); + + // 3. project selects using model based ackermannization + array_project_selects (mdl, arr_vars, fml, aux_vars); + TRACE ("qe", + tout << "Projected array selects:\n" << fml << "\n"; + tout << "All aux vars:\n" << aux_vars; + ); + } + }; From 8ffbd5d1e54507339317d60e5146218915dbd838 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 19 May 2018 17:58:35 -0700 Subject: [PATCH 1024/1283] model_evaluator: respect array_as_stores option --- src/model/model_evaluator.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index eb7131406..377afda92 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -198,9 +198,6 @@ struct evaluator_cfg : public default_rewriter_cfg { if (evaluate(a->get_decl(), a->get_num_args(), a->get_args(), result)) { return BR_REWRITE1; } - if (false && m_array_as_stores && m_ar.is_array(result)) { - expand_stores(result); - } } CTRACE("model_evaluator", st != BR_FAILED, tout << result << "\n";); return st; @@ -210,7 +207,9 @@ struct evaluator_cfg : public default_rewriter_cfg { vector stores; expr_ref else_case(m); bool _unused; - if (m_ar.is_array(val) && extract_array_func_interp(val, stores, else_case, _unused)) { + if (m_array_as_stores && + m_ar.is_array(val) && + extract_array_func_interp(val, stores, else_case, _unused)) { sort* srt = m.get_sort(val); val = m_ar.mk_const_array(srt, else_case); for (unsigned i = stores.size(); i-- > 0; ) { From 23272f0d2f75dffb60a9560f98b003512617c1a0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 May 2018 10:38:43 -0700 Subject: [PATCH 1025/1283] array support for mbp Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arrays.cpp | 936 ++++++++++++++++++++++--------------------- src/qe/qe_arrays.h | 1 + src/qe/qe_mbp.cpp | 4 +- 3 files changed, 477 insertions(+), 464 deletions(-) diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index ad9d5d63f..712311f9d 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -155,415 +155,16 @@ namespace { namespace qe { - - struct array_project_plugin::imp { - - // rewriter or direct procedure. - struct rw_cfg : public default_rewriter_cfg { - ast_manager& m; - array_util& a; - expr_ref_vector m_lits; - model* m_model; - imp* m_imp; - - rw_cfg(ast_manager& m, array_util& a): - m(m), a(a), m_lits(m), m_model(nullptr) {} - - br_status reduce_app(func_decl* f, unsigned n, expr* const* args, expr_ref& result, proof_ref & pr) { - if (a.is_select(f) && a.is_store(args[0])) { - expr_ref val1(m), val2(m); - app* b = to_app(args[0]); - SASSERT(b->get_num_args() == n + 1); - for (unsigned i = 1; i < n; ++i) { - expr* arg1 = args[i]; - expr* arg2 = b->get_arg(i); - if (arg1 == arg2) { - val1 = val2 = arg1; - } - else { - VERIFY(m_model->eval(arg1, val1)); - VERIFY(m_model->eval(arg2, val2)); - } - switch(compare(val1, val2)) { - case l_true: - if (arg1 != arg2) { - m_lits.push_back(m.mk_eq(arg1, arg2)); - } - break; - case l_false: { - ptr_vector new_args; - if (i > 0) { - m_lits.resize(m_lits.size() - i); - } - m_lits.push_back(m.mk_not(m.mk_eq(arg1, arg2))); - new_args.push_back(b->get_arg(0)); - new_args.append(n-1, args+1); - result = m.mk_app(f, n, new_args.c_ptr()); - return BR_REWRITE1; - } - case l_undef: - return BR_FAILED; - } - } - result = b->get_arg(n); - return BR_DONE; - } - return BR_FAILED; - } - - lbool compare(expr* x, expr* y) { - NOT_IMPLEMENTED_YET(); - return l_undef; - } - }; - - struct indices { - expr_ref_vector m_values; - expr* const* m_vars; - - indices(ast_manager& m, model& model, unsigned n, expr* const* vars): - m_values(m), m_vars(vars) { - expr_ref val(m); - for (unsigned i = 0; i < n; ++i) { - VERIFY(model.eval(vars[i], val)); - m_values.push_back(val); - } - } - }; - - ast_manager& m; - array_util a; - scoped_ptr m_var; - - imp(ast_manager& m): m(m), a(m) {} - ~imp() {} - - bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - return false; - } - - bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { - - TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;); - m_var = alloc(contains_app, m, var); - - // reduce select-store redeces based on model. - // rw_cfg rw(m); - // rw(lits); - - // try first to solve for var. - if (solve_eq(model, vars, lits)) { - return true; - } - - app_ref_vector selects(m); - - // check that only non-select occurrences are in disequalities. - if (!check_diseqs(lits, selects)) { - TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";); - return false; - } - - // remove disequalities. - elim_diseqs(lits); - - // Ackerman reduction on remaining select occurrences - // either replace occurrences by model value or other node - // that is congruent to model value. - - ackermanize_select(model, selects, vars, lits); - - TRACE("qe", tout << selects << "\n" << lits << "\n";); - return true; - } - - void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) { - expr_ref_vector vals(m), reps(m); - expr_ref val(m); - expr_safe_replace sub(m); - - if (selects.empty()) { - return; - } - - app_ref sel(m); - for (unsigned i = 0; i < selects.size(); ++i) { - sel = m.mk_fresh_const("sel", m.get_sort(selects[i])); - VERIFY (model.eval(selects[i], val)); - model.register_decl(sel->get_decl(), val); - vals.push_back(to_app(val)); - reps.push_back(val); // TODO: direct pass could handle nested selects. - vars.push_back(sel); - sub.insert(selects[i], val); - } - - sub(lits); - remove_true(lits); - project_plugin::partition_args(model, selects, lits); - project_plugin::partition_values(model, reps, lits); - } - - void remove_true(expr_ref_vector& lits) { - for (unsigned i = 0; i < lits.size(); ++i) { - if (m.is_true(lits[i].get())) { - project_plugin::erase(lits, i); - } - } - } - - bool contains_x(expr* e) { - return (*m_var)(e); - } - - void mk_eq(indices const& x, indices const& y, expr_ref_vector& lits) { - SASSERT(x.m_values.size() == y.m_values.size()); - unsigned n = x.m_values.size(); - for (unsigned j = 0; j < n; ++j) { - lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); - } - } - - // check that x occurs only under selects or in disequalities. - bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) { - expr_mark mark; - ptr_vector todo; - app* e; - for (unsigned i = 0; i < lits.size(); ++i) { - e = to_app(lits[i]); - if (is_diseq_x(e)) { - continue; - } - if (contains_x(e)) { - todo.push_back(e); - } - } - while (!todo.empty()) { - e = todo.back(); - todo.pop_back(); - if (mark.is_marked(e)) { - continue; - } - mark.mark(e); - if (m_var->x() == e) { - return false; - } - unsigned start = 0; - if (a.is_select(e)) { - if (e->get_arg(0) == m_var->x()) { - start = 1; - selects.push_back(e); - } - } - for (unsigned i = start; i < e->get_num_args(); ++i) { - todo.push_back(to_app(e->get_arg(i))); - } - } - return true; - } - - void elim_diseqs(expr_ref_vector& lits) { - for (unsigned i = 0; i < lits.size(); ++i) { - if (is_diseq_x(lits[i].get())) { - project_plugin::erase(lits, i); - } - } - } - - bool is_update_x(app* e) { - do { - if (m_var->x() == e) { - return true; - } - if (a.is_store(e) && contains_x(e->get_arg(0))) { - for (unsigned i = 1; i < e->get_num_args(); ++i) { - if (contains_x(e->get_arg(i))) { - return false; - } - } - e = to_app(e->get_arg(0)); - continue; - } - } - while (false); - return false; - } - - bool is_diseq_x(expr* e) { - expr *f, * s, *t; - if (m.is_not(e, f) && m.is_eq(f, s, t)) { - if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true; - if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true; - } - return false; - } - - bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - // find an equality to solve for. - expr* s, *t; - for (unsigned i = 0; i < lits.size(); ++i) { - if (m.is_eq(lits[i].get(), s, t)) { - vector idxs; - expr_ref save(m), back(m); - save = lits[i].get(); - back = lits.back(); - lits[i] = back; - lits.pop_back(); - unsigned sz = lits.size(); - if (contains_x(s) && !contains_x(t) && is_app(s)) { - if (solve(model, to_app(s), t, idxs, vars, lits)) { - return true; - } - } - else if (contains_x(t) && !contains_x(s) && is_app(t)) { - if (solve(model, to_app(t), s, idxs, vars, lits)) { - return true; - } - } - // put back the equality literal. - lits.resize(sz); - lits.push_back(back); - lits[i] = save; - } - // TBD: not distinct? - } - return false; - } - - bool solve(model& model, app* s, expr* t, vector& idxs, app_ref_vector& vars, expr_ref_vector& lits) { - SASSERT(contains_x(s)); - SASSERT(!contains_x(t)); - - if (s == m_var->x()) { - expr_ref result(t, m); - expr_ref_vector args(m); - sort* range = get_array_range(m.get_sort(s)); - for (unsigned i = 0; i < idxs.size(); ++i) { - app_ref var(m), sel(m); - expr_ref val(m); - var = m.mk_fresh_const("value", range); - vars.push_back(var); - args.reset(); - - args.push_back (s); - args.append(idxs[i].m_values.size(), idxs[i].m_vars); - sel = a.mk_select (args.size (), args.c_ptr ()); - VERIFY (model.eval (sel, val)); - model.register_decl (var->get_decl (), val); - - args[0] = result; - args.push_back(var); - result = a.mk_store(args.size(), args.c_ptr()); - } - expr_safe_replace sub(m); - sub.insert(s, result); - for (unsigned i = 0; i < lits.size(); ++i) { - sub(lits[i].get(), result); - lits[i] = result; - } - return true; - } - - if (a.is_store(s)) { - unsigned n = s->get_num_args()-2; - indices idx(m, model, n, s->get_args()+1); - for (unsigned i = 1; i < n; ++i) { - if (contains_x(s->get_arg(i))) { - return false; - } - } - unsigned i; - expr_ref_vector args(m); - switch (contains(idx, idxs, i)) { - case l_true: - mk_eq(idx, idxs[i], lits); - return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits); - case l_false: - for (unsigned i = 0; i < idxs.size(); ++i) { - expr_ref_vector eqs(m); - mk_eq(idx, idxs[i], eqs); - lits.push_back(m.mk_not(mk_and(eqs))); // TBD: extract single index of difference based on model. - } - args.push_back(t); - args.append(n, s->get_args()+1); - lits.push_back(m.mk_eq(a.mk_select(args.size(), args.c_ptr()), s->get_arg(n+1))); - idxs.push_back(idx); - return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits); - case l_undef: - return false; - } - } - return false; - } - - lbool contains(indices const& idx, vector const& idxs, unsigned& j) { - for (unsigned i = 0; i < idxs.size(); ++i) { - switch (compare(idx, idxs[i])) { - case l_true: - j = i; - return l_true; - case l_false: - break; - case l_undef: - return l_undef; - } - } - return l_false; - } - - lbool compare(indices const& idx1, indices const& idx2) { - unsigned n = idx1.m_values.size(); - for (unsigned i = 0; i < n; ++i) { - switch (compare(idx1.m_values[i], idx2.m_values[i])) { - case l_true: - break; - case l_false: - return l_false; - case l_undef: - return l_undef; - } - } - return l_true; - } - - lbool compare(expr* val1, expr* val2) { - if (m.are_equal (val1, val2)) return l_true; - if (m.are_distinct (val1, val2)) return l_false; - - if (is_uninterp(val1) || - is_uninterp(val2)) { - // TBD chase definition of nested array. - return l_undef; - } - return l_undef; - } - }; - - - array_project_plugin::array_project_plugin(ast_manager& m) { - m_imp = alloc(imp, m); - } - - array_project_plugin::~array_project_plugin() { - dealloc(m_imp); - } - - bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { - return (*m_imp)(model, var, vars, lits); - } - - bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - return m_imp->solve(model, vars, lits); - } - - family_id array_project_plugin::get_family_id() { - return m_imp->a.get_family_id(); - } - static bool is_eq(expr_ref_vector const& xs, expr_ref_vector const& ys) { for (unsigned i = 0; i < xs.size(); ++i) if (xs[i] != ys[i]) return false; return true; } + static bool is_eq(vector const& xs, vector const& ys) { + for (unsigned i = 0; i < xs.size(); ++i) if (xs[i] != ys[i]) return false; + return true; + } + static expr_ref mk_eq(expr_ref_vector const& xs, expr_ref_vector const& ys) { ast_manager& m = xs.get_manager(); expr_ref_vector eqs(m); @@ -571,7 +172,6 @@ namespace qe { return mk_and(eqs); } - class array_project_eqs_util { ast_manager& m; array_util m_arr_u; @@ -679,8 +279,10 @@ namespace qe { expr_ref_vector args (m); bool all_done = true; for (expr * arg : *a) { - if (!is_app (arg)) continue; - if (!done.is_marked (arg)) { + if (!is_app (arg)) { + args.push_back(arg); + } + else if (!done.is_marked (arg)) { all_done = false; todo.push_back (to_app (arg)); } @@ -1267,9 +869,15 @@ namespace qe { typedef obj_map*> sel_map; struct idx_val { - expr_ref_vector idx, val; - idx_val(expr_ref_vector & idx, expr_ref_vector & val): idx(idx), val(val) {} - idx_val& operator=(idx_val const& o) { idx.reset(); val.reset(); idx.append(o.idx); val.append(o.val); return *this; } + expr_ref_vector idx; + expr_ref_vector val; + vector rval; + idx_val(expr_ref_vector & idx, expr_ref_vector & val, vector const& rval): idx(idx), val(val), rval(rval) {} + idx_val& operator=(idx_val const& o) { + idx.reset(); val.reset(); rval.reset(); + idx.append(o.idx); val.append(o.val); rval.append(o.rval); + return *this; + } }; ast_manager& m; array_util m_arr_u; @@ -1322,14 +930,24 @@ namespace qe { } } + vector to_num(expr_ref_vector const& vals) { + vector rs; + rational r; + for (expr* v : vals) { + VERIFY (m_ari_u.is_numeral(v, r)); + rs.push_back(r); + } + return rs; + } + struct compare_idx { array_project_selects_util& u; compare_idx(array_project_selects_util& u):u(u) {} bool operator()(idx_val const& x, idx_val const& y) { - for (unsigned j = 0; j < x.val.size(); ++j) { - rational xv, yv; - VERIFY (u.m_ari_u.is_numeral(x.val[j], xv)); - VERIFY (u.m_ari_u.is_numeral(y.val[j], yv)); + SASSERT(x.rval.size() == y.rval.size()); + for (unsigned j = 0; j < x.rval.size(); ++j) { + rational const& xv = x.rval[j]; + rational const& yv = y.rval[j]; if (xv < yv) return true; if (xv > yv) return false; } @@ -1338,7 +956,7 @@ namespace qe { }; expr_ref mk_lex_lt(expr_ref_vector const& xs, expr_ref_vector const& ys) { - SASSERT(xs.size() == ys.size()); + SASSERT(xs.size() == ys.size() && !xs.empty()); expr_ref result(m_ari_u.mk_lt(xs.back(), ys.back()), m); for (unsigned i = xs.size()-1; i-- > 0; ) { result = m.mk_or(m_ari_u.mk_lt(xs[i], ys[i]), @@ -1359,17 +977,17 @@ namespace qe { sort* v_sort = m.get_sort (v); sort* val_sort = get_array_range (v_sort); unsigned arity = get_array_arity(v_sort); - - for (unsigned i = 0; i < arity; ++i) { + bool is_numeric = true; + for (unsigned i = 0; i < arity && is_numeric; ++i) { sort* srt = get_array_domain(v_sort, i); if (!m_ari_u.is_real(srt) && !m_ari_u.is_int(srt)) { - TRACE("qe", tout << "unsupported index sort for Ackerman" << mk_pp(srt, m) << "\n";); - return; - } + TRACE("qe", tout << "non-arithmetic index sort for Ackerman" << mk_pp(srt, m) << "\n";); + // TBD: generalize to also bit-vectors. + is_numeric = false; + } } - + unsigned start = m_idxs.size (); // append at the end - for (app * a : sel_terms) { expr_ref_vector idxs(m, arity, a->get_args() + 1); expr_ref_vector vals = (*m_mev)(idxs); @@ -1387,7 +1005,8 @@ namespace qe { } if (is_new) { // new repr, val, and sel const - m_idxs.push_back(idx_val(idxs, vals)); + vector rvals = to_num(vals); + m_idxs.push_back(idx_val(idxs, vals, rvals)); app_ref c (m.mk_fresh_const ("sel", val_sort), m); m_sel_consts.push_back (c); // substitute sel term with new const @@ -1398,13 +1017,25 @@ namespace qe { } } - // sort reprs by their value and add a chain of strict inequalities - - compare_idx cmp(*this); - std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); - - for (unsigned i = start; i < m_idxs.size()-1; i++) { - m_idx_lits.push_back (mk_lex_lt(m_idxs[i].idx, m_idxs[i+1].idx)); + if (is_numeric) { + // sort reprs by their value and add a chain of strict inequalities + compare_idx cmp(*this); + std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); + for (unsigned i = start; i + 1 < m_idxs.size(); ++i) { + m_idx_lits.push_back (mk_lex_lt(m_idxs[i].idx, m_idxs[i+1].idx)); + } + } + else if (arity == 1) { + // create distinct constraint. + expr_ref_vector xs(m); + for (unsigned i = start; i < m_idxs.size(); ++i) { + xs.append(m_idxs[i].idx); + } + m_idx_lits.push_back(m.mk_distinct(xs.size(), xs.c_ptr())); + } + else { + NOT_IMPLEMENTED_YET(); + // use a tuple. } } @@ -1447,6 +1078,7 @@ namespace qe { {} void operator () (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { + if (arr_vars.empty()) return; reset (); model_evaluator mev(mdl); M = &mdl; @@ -1478,33 +1110,414 @@ namespace qe { }; - static void array_project_eqs (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { - ast_manager& m = arr_vars.get_manager (); - array_project_eqs_util ap (m); - ap (mdl, arr_vars, fml, aux_vars); + struct array_project_plugin::imp { + + // rewriter or direct procedure. + struct rw_cfg : public default_rewriter_cfg { + ast_manager& m; + array_util& a; + expr_ref_vector m_lits; + model* m_model; + imp* m_imp; + + rw_cfg(ast_manager& m, array_util& a): + m(m), a(a), m_lits(m), m_model(nullptr) {} + + br_status reduce_app(func_decl* f, unsigned n, expr* const* args, expr_ref& result, proof_ref & pr) { + if (a.is_select(f) && a.is_store(args[0])) { + expr_ref val1(m), val2(m); + app* b = to_app(args[0]); + SASSERT(b->get_num_args() == n + 1); + for (unsigned i = 1; i < n; ++i) { + expr* arg1 = args[i]; + expr* arg2 = b->get_arg(i); + if (arg1 == arg2) { + val1 = val2 = arg1; + } + else { + VERIFY(m_model->eval(arg1, val1)); + VERIFY(m_model->eval(arg2, val2)); + } + switch(compare(val1, val2)) { + case l_true: + if (arg1 != arg2) { + m_lits.push_back(m.mk_eq(arg1, arg2)); + } + break; + case l_false: { + ptr_vector new_args; + if (i > 0) { + m_lits.resize(m_lits.size() - i); + } + m_lits.push_back(m.mk_not(m.mk_eq(arg1, arg2))); + new_args.push_back(b->get_arg(0)); + new_args.append(n-1, args+1); + result = m.mk_app(f, n, new_args.c_ptr()); + return BR_REWRITE1; + } + case l_undef: + return BR_FAILED; + } + } + result = b->get_arg(n); + return BR_DONE; + } + return BR_FAILED; + } + + lbool compare(expr* x, expr* y) { + NOT_IMPLEMENTED_YET(); + return l_undef; + } + }; + + struct indices { + expr_ref_vector m_values; + expr* const* m_vars; + + indices(ast_manager& m, model& model, unsigned n, expr* const* vars): + m_values(m), m_vars(vars) { + expr_ref val(m); + for (unsigned i = 0; i < n; ++i) { + VERIFY(model.eval(vars[i], val)); + m_values.push_back(val); + } + } + }; + + ast_manager& m; + array_util a; + scoped_ptr m_var; + + imp(ast_manager& m): m(m), a(m) {} + ~imp() {} + + bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + return false; + } + + bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { + + TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;); + m_var = alloc(contains_app, m, var); + + // reduce select-store redeces based on model. + // rw_cfg rw(m); + // rw(lits); + + // try first to solve for var. + if (solve_eq(model, vars, lits)) { + return true; + } + + app_ref_vector selects(m); + + // check that only non-select occurrences are in disequalities. + if (!check_diseqs(lits, selects)) { + TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";); + return false; + } + + // remove disequalities. + elim_diseqs(lits); + + // Ackerman reduction on remaining select occurrences + // either replace occurrences by model value or other node + // that is congruent to model value. + + ackermanize_select(model, selects, vars, lits); + + TRACE("qe", tout << selects << "\n" << lits << "\n";); + return true; + } + + void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) { + expr_ref_vector vals(m), reps(m); + expr_ref val(m); + expr_safe_replace sub(m); + + if (selects.empty()) { + return; + } + + app_ref sel(m); + for (unsigned i = 0; i < selects.size(); ++i) { + sel = m.mk_fresh_const("sel", m.get_sort(selects[i])); + VERIFY (model.eval(selects[i], val)); + model.register_decl(sel->get_decl(), val); + vals.push_back(to_app(val)); + reps.push_back(val); // TODO: direct pass could handle nested selects. + vars.push_back(sel); + sub.insert(selects[i], val); + } + + sub(lits); + remove_true(lits); + project_plugin::partition_args(model, selects, lits); + project_plugin::partition_values(model, reps, lits); + } + + void remove_true(expr_ref_vector& lits) { + for (unsigned i = 0; i < lits.size(); ++i) { + if (m.is_true(lits[i].get())) { + project_plugin::erase(lits, i); + } + } + } + + bool contains_x(expr* e) { + return (*m_var)(e); + } + + void mk_eq(indices const& x, indices const& y, expr_ref_vector& lits) { + SASSERT(x.m_values.size() == y.m_values.size()); + unsigned n = x.m_values.size(); + for (unsigned j = 0; j < n; ++j) { + lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); + } + } + + // check that x occurs only under selects or in disequalities. + bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) { + expr_mark mark; + ptr_vector todo; + app* e; + for (unsigned i = 0; i < lits.size(); ++i) { + e = to_app(lits[i]); + if (is_diseq_x(e)) { + continue; + } + if (contains_x(e)) { + todo.push_back(e); + } + } + while (!todo.empty()) { + e = todo.back(); + todo.pop_back(); + if (mark.is_marked(e)) { + continue; + } + mark.mark(e); + if (m_var->x() == e) { + return false; + } + unsigned start = 0; + if (a.is_select(e)) { + if (e->get_arg(0) == m_var->x()) { + start = 1; + selects.push_back(e); + } + } + for (unsigned i = start; i < e->get_num_args(); ++i) { + todo.push_back(to_app(e->get_arg(i))); + } + } + return true; + } + + void elim_diseqs(expr_ref_vector& lits) { + for (unsigned i = 0; i < lits.size(); ++i) { + if (is_diseq_x(lits[i].get())) { + project_plugin::erase(lits, i); + } + } + } + + bool is_update_x(app* e) { + do { + if (m_var->x() == e) { + return true; + } + if (a.is_store(e) && contains_x(e->get_arg(0))) { + for (unsigned i = 1; i < e->get_num_args(); ++i) { + if (contains_x(e->get_arg(i))) { + return false; + } + } + e = to_app(e->get_arg(0)); + continue; + } + } + while (false); + return false; + } + + bool is_diseq_x(expr* e) { + expr *f, * s, *t; + if (m.is_not(e, f) && m.is_eq(f, s, t)) { + if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true; + if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true; + } + return false; + } + + bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + // find an equality to solve for. + expr* s, *t; + for (unsigned i = 0; i < lits.size(); ++i) { + if (m.is_eq(lits[i].get(), s, t)) { + vector idxs; + expr_ref save(m), back(m); + save = lits[i].get(); + back = lits.back(); + lits[i] = back; + lits.pop_back(); + unsigned sz = lits.size(); + if (contains_x(s) && !contains_x(t) && is_app(s)) { + if (solve(model, to_app(s), t, idxs, vars, lits)) { + return true; + } + } + else if (contains_x(t) && !contains_x(s) && is_app(t)) { + if (solve(model, to_app(t), s, idxs, vars, lits)) { + return true; + } + } + // put back the equality literal. + lits.resize(sz); + lits.push_back(back); + lits[i] = save; + } + // TBD: not distinct? + } + return false; + } + + bool solve(model& model, app* s, expr* t, vector& idxs, app_ref_vector& vars, expr_ref_vector& lits) { + SASSERT(contains_x(s)); + SASSERT(!contains_x(t)); + + if (s == m_var->x()) { + expr_ref result(t, m); + expr_ref_vector args(m); + sort* range = get_array_range(m.get_sort(s)); + for (unsigned i = 0; i < idxs.size(); ++i) { + app_ref var(m), sel(m); + expr_ref val(m); + var = m.mk_fresh_const("value", range); + vars.push_back(var); + args.reset(); + + args.push_back (s); + args.append(idxs[i].m_values.size(), idxs[i].m_vars); + sel = a.mk_select (args.size (), args.c_ptr ()); + VERIFY (model.eval (sel, val)); + model.register_decl (var->get_decl (), val); + + args[0] = result; + args.push_back(var); + result = a.mk_store(args.size(), args.c_ptr()); + } + expr_safe_replace sub(m); + sub.insert(s, result); + for (unsigned i = 0; i < lits.size(); ++i) { + sub(lits[i].get(), result); + lits[i] = result; + } + return true; + } + + if (a.is_store(s)) { + unsigned n = s->get_num_args()-2; + indices idx(m, model, n, s->get_args()+1); + for (unsigned i = 1; i < n; ++i) { + if (contains_x(s->get_arg(i))) { + return false; + } + } + unsigned i; + expr_ref_vector args(m); + switch (contains(idx, idxs, i)) { + case l_true: + mk_eq(idx, idxs[i], lits); + return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits); + case l_false: + for (unsigned i = 0; i < idxs.size(); ++i) { + expr_ref_vector eqs(m); + mk_eq(idx, idxs[i], eqs); + lits.push_back(m.mk_not(mk_and(eqs))); // TBD: extract single index of difference based on model. + } + args.push_back(t); + args.append(n, s->get_args()+1); + lits.push_back(m.mk_eq(a.mk_select(args.size(), args.c_ptr()), s->get_arg(n+1))); + idxs.push_back(idx); + return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits); + case l_undef: + return false; + } + } + return false; + } + + lbool contains(indices const& idx, vector const& idxs, unsigned& j) { + for (unsigned i = 0; i < idxs.size(); ++i) { + switch (compare(idx, idxs[i])) { + case l_true: + j = i; + return l_true; + case l_false: + break; + case l_undef: + return l_undef; + } + } + return l_false; + } + + lbool compare(indices const& idx1, indices const& idx2) { + unsigned n = idx1.m_values.size(); + for (unsigned i = 0; i < n; ++i) { + switch (compare(idx1.m_values[i], idx2.m_values[i])) { + case l_true: + break; + case l_false: + return l_false; + case l_undef: + return l_undef; + } + } + return l_true; + } + + lbool compare(expr* val1, expr* val2) { + if (m.are_equal (val1, val2)) return l_true; + if (m.are_distinct (val1, val2)) return l_false; + + if (is_uninterp(val1) || + is_uninterp(val2)) { + // TBD chase definition of nested array. + return l_undef; + } + return l_undef; + } + }; + + + array_project_plugin::array_project_plugin(ast_manager& m) { + m_imp = alloc(imp, m); + } + + array_project_plugin::~array_project_plugin() { + dealloc(m_imp); + } + + bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { + return (*m_imp)(model, var, vars, lits); } - static void reduce_array_selects (model& mdl, app_ref_vector const& arr_vars, expr_ref& fml, bool reduce_all_selects) { - ast_manager& m = arr_vars.get_manager (); - array_select_reducer ap (m); - ap (mdl, arr_vars, fml, reduce_all_selects); + bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + return m_imp->solve(model, vars, lits); + } + + family_id array_project_plugin::get_family_id() { + return m_imp->a.get_family_id(); } - static void reduce_array_selects (model& mdl, expr_ref& fml) { - ast_manager& m = fml.get_manager (); - app_ref_vector _tmp (m); - reduce_array_selects (mdl, _tmp, fml, true); - } - - static void array_project_selects (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { - ast_manager& m = arr_vars.get_manager (); - array_project_selects_util ap (m); - ap (mdl, arr_vars, fml, aux_vars); - } - - void new_array_project (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects) { + void array_project_plugin::operator()(model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects) { // 1. project array equalities - array_project_eqs (mdl, arr_vars, fml, aux_vars); + ast_manager& m = fml.get_manager(); + array_project_eqs_util pe (m); + pe (mdl, arr_vars, fml, aux_vars); TRACE ("qe", tout << "Projected array eqs:\n" << fml << "\n"; tout << "Remaining array vars:\n" << arr_vars; @@ -1512,23 +1525,22 @@ namespace qe { ); // 2. reduce selects - if (reduce_all_selects) { - reduce_array_selects (mdl, fml); - } - else { - reduce_array_selects (mdl, arr_vars, fml, false); - } - TRACE ("qe", - tout << "Reduced selects:\n" << fml << "\n"; - ); + array_select_reducer rs (m); + rs (mdl, arr_vars, fml, reduce_all_selects); + + TRACE ("qe", tout << "Reduced selects:\n" << fml << "\n"; ); // 3. project selects using model based ackermannization - array_project_selects (mdl, arr_vars, fml, aux_vars); + array_project_selects_util ps (m); + ps (mdl, arr_vars, fml, aux_vars); + TRACE ("qe", tout << "Projected array selects:\n" << fml << "\n"; tout << "All aux vars:\n" << aux_vars; ); } + + }; diff --git a/src/qe/qe_arrays.h b/src/qe/qe_arrays.h index a955250a8..f2d69b564 100644 --- a/src/qe/qe_arrays.h +++ b/src/qe/qe_arrays.h @@ -34,6 +34,7 @@ namespace qe { ~array_project_plugin() override; bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) override; bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; + void operator()(model& model, app_ref_vector& vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects); family_id get_family_id() override; }; diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 0b4574951..a6bdbd1dc 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -664,8 +664,8 @@ public: // project arrays if (!array_vars.empty()) { - NOT_IMPLEMENTED_YET(); - // qe::array_project (mdl, array_vars, fml, vars, m_reduce_all_selects); + qe::array_project_plugin ap(m); + ap(mdl, array_vars, fml, vars, m_reduce_all_selects); SASSERT (array_vars.empty ()); m_rw (fml); SASSERT (!m.is_false (fml)); From aeb2f3c4bbe09d61a8a063c764a426d6e70c7d91 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 09:24:57 -0700 Subject: [PATCH 1026/1283] factor out inherit_properties --- src/muz/spacer/spacer_context.cpp | 65 +++++++++++++++---------------- src/muz/spacer/spacer_context.h | 1 + 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index fc0246ec6..9f54ac0d8 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1749,50 +1749,51 @@ app* pred_transformer::extend_initial (expr *e) /// pred_transformer::frames -bool pred_transformer::frames::add_lemma(lemma *lem) +bool pred_transformer::frames::add_lemma(lemma *new_lemma) { - TRACE("spacer", tout << "add-lemma: " << pp_level(lem->level()) << " " + TRACE("spacer", tout << "add-lemma: " << pp_level(new_lemma->level()) << " " << m_pt.head()->get_name() << " " - << mk_pp(lem->get_expr(), m_pt.get_ast_manager()) << "\n";); + << mk_pp(new_lemma->get_expr(), m_pt.get_ast_manager()) << "\n";); for (unsigned i = 0, sz = m_lemmas.size(); i < sz; ++i) { - if (m_lemmas [i]->get_expr() == lem->get_expr()) { - m_pt.get_context().new_lemma_eh(m_pt, lem); + if (m_lemmas[i]->get_expr() == new_lemma->get_expr()) { + m_pt.get_context().new_lemma_eh(m_pt, new_lemma); // extend bindings if needed - if (!lem->get_bindings().empty()) { - m_lemmas [i]->add_binding(lem->get_bindings()); + if (!new_lemma->get_bindings().empty()) { + m_lemmas[i]->add_binding(new_lemma->get_bindings()); } // if the lemma is at a higher level, skip it, - // but still assert any new instances - if (m_lemmas [i]->level() >= lem->level()) { + if (m_lemmas[i]->level() >= new_lemma->level()) { TRACE("spacer", tout << "Already at a higher level: " - << pp_level(m_lemmas [i]->level()) << "\n";); - if (!lem->get_bindings().empty()) { + << pp_level(m_lemmas[i]->level()) << "\n";); + // but, since the instances might be new, assert the + // instances that have been copied into m_lemmas[i] + if (!new_lemma->get_bindings().empty()) { m_pt.add_lemma_core(m_lemmas[i], true); } + // no new lemma added return false; } // update level of the existing lemma - m_lemmas [i]->set_level(lem->level()); + m_lemmas[i]->set_level(new_lemma->level()); // assert lemma in the solver m_pt.add_lemma_core(m_lemmas[i], false); // move the lemma to its new place to maintain sortedness - for (unsigned j = i; (j + 1) < sz && m_lt(m_lemmas [j + 1], m_lemmas[j]); ++j) { + for (unsigned j = i; (j + 1) < sz && m_lt(m_lemmas[j + 1], m_lemmas[j]); ++j) { m_lemmas.swap (j, j+1); } - return true; } } - // did not find, create new lemma - m_lemmas.push_back(lem); + // new_lemma is really new + m_lemmas.push_back(new_lemma); m_sorted = false; - m_pt.add_lemma_core(lem); + m_pt.add_lemma_core(new_lemma); - if (!lem->external()) { - m_pt.get_context().new_lemma_eh(m_pt, lem); + if (!new_lemma->external()) { + m_pt.get_context().new_lemma_eh(m_pt, new_lemma); } return true; } @@ -2029,10 +2030,7 @@ void context::reset() { TRACE("spacer", tout << "\n";); m_pob_queue.reset(); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } + for (auto &entry: m_rels) {dealloc(entry.m_value);} m_rels.reset(); m_query = nullptr; m_last_result = l_undef; @@ -2093,22 +2091,23 @@ void context::init_rules(datalog::rule_set& rules, decl2rel& rels) for (auto &entry : rels) {entry.m_value->init_reach_facts();} } +void context::inherit_properties(const decl2rel &rels) { + for (auto &entry : rels) { + pred_transformer *pt = nullptr; + if (m_rels.find(entry.m_key, pt)) { + entry.m_value->inherit_properties(*pt); + } + } +} void context::update_rules(datalog::rule_set& rules) { decl2rel rels; init_lemma_generalizers(rules); init_rules(rules, rels); - decl2rel::iterator it = rels.begin(), end = rels.end(); - for (; it != end; ++it) { - pred_transformer* pt = nullptr; - if (m_rels.find(it->m_key, pt)) { - it->m_value->inherit_properties(*pt); - } - } + inherit_properties(rels); reset(); - it = rels.begin(), end = rels.end(); - for (; it != end; ++it) { - m_rels.insert(it->m_key, it->m_value); + for (auto &entry : rels) { + m_rels.insert(entry.m_key, entry.m_value); } } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 9be990d8e..db05df638 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -812,6 +812,7 @@ class context { // Initialization void init_lemma_generalizers(datalog::rule_set& rules); + void inherit_properties(const decl2rel& rels); bool check_invariant(unsigned lvl); bool check_invariant(unsigned lvl, func_decl* fn); From 4de58a42fe3fc6a975133947bf1f1ee7e2f334d0 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 09:46:15 -0700 Subject: [PATCH 1027/1283] Update initialization order --- src/muz/spacer/spacer_context.cpp | 39 ++++++++++++++++++++++--------- src/muz/spacer/spacer_context.h | 10 +++++--- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 9f54ac0d8..2baa70f46 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1720,7 +1720,7 @@ void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, datalog:: } } -void pred_transformer::inherit_properties(pred_transformer& other) +void pred_transformer::inherit_lemmas(pred_transformer& other) {m_frames.inherit_frames (other.m_frames);} app* pred_transformer::extend_initial (expr *e) @@ -2091,24 +2091,37 @@ void context::init_rules(datalog::rule_set& rules, decl2rel& rels) for (auto &entry : rels) {entry.m_value->init_reach_facts();} } -void context::inherit_properties(const decl2rel &rels) { +void context::inherit_lemmas(const decl2rel &rels) { for (auto &entry : rels) { pred_transformer *pt = nullptr; if (m_rels.find(entry.m_key, pt)) { - entry.m_value->inherit_properties(*pt); + entry.m_value->inherit_lemmas(*pt); } } } + void context::update_rules(datalog::rule_set& rules) { decl2rel rels; - init_lemma_generalizers(rules); + // SMT params must be set before any expression is asserted to any + // solver + init_global_smt_params(); + // constructs new pred transformers and asserts trans and init init_rules(rules, rels); - inherit_properties(rels); + // inherits lemmas from m_rels into rels + inherit_lemmas(rels); + // switch context to new rels + init(rels); + // re-initialize lemma generalizers + init_lemma_generalizers(); +} + +void context::init(const decl2rel &rels) { + // reset context. Current state is all stored in rels reset(); - for (auto &entry : rels) { - m_rels.insert(entry.m_key, entry.m_value); - } + // re-initialize context + for (auto &entry : rels) + {m_rels.insert(entry.m_key, entry.m_value);} } unsigned context::get_num_levels(func_decl* p) @@ -2250,9 +2263,8 @@ void context::reset_lemma_generalizers() m_lemma_generalizers.reset(); } -void context::init_lemma_generalizers(datalog::rule_set& rules) -{ - reset_lemma_generalizers(); +// initialize global SMT parameters shared by all solvers +void context::init_global_smt_params() { m.toggle_proof_mode(PGM_ENABLED); smt_params &fparams = m_pm.fparams (); if (!m_params.spacer_eq_prop ()) { @@ -2282,6 +2294,11 @@ void context::init_lemma_generalizers(datalog::rule_set& rules) fparams.m_ng_lift_ite = LI_FULL; } +} +void context::init_lemma_generalizers() +{ + reset_lemma_generalizers(); + if (m_params.spacer_q3_use_qgen()) { m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0, true)); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index db05df638..62d90e4c0 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -428,7 +428,7 @@ public: void add_premises(decl2rel const& pts, unsigned lvl, expr_ref_vector& r); - void inherit_properties(pred_transformer& other); + void inherit_lemmas(pred_transformer& other); void ground_free_vars(expr* e, app_ref_vector& vars, ptr_vector& aux_vars, bool is_init); @@ -811,8 +811,9 @@ class context { // Initialization - void init_lemma_generalizers(datalog::rule_set& rules); - void inherit_properties(const decl2rel& rels); + void init_lemma_generalizers(); + void inherit_lemmas(const decl2rel& rels); + void init_global_smt_params(); bool check_invariant(unsigned lvl); bool check_invariant(unsigned lvl, func_decl* fn); @@ -821,6 +822,9 @@ class context { void init_rules(datalog::rule_set& rules, decl2rel& transformers); + // (re)initialize context with new relations + void init(const decl2rel &rels); + void simplify_formulas(); void reset_lemma_generalizers(); From 9550fd1ec4d7fbae30e99ef18a9a4b55bcf422db Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 10:44:29 -0700 Subject: [PATCH 1028/1283] proof-checker: handle true-axiom --- src/ast/proofs/proof_checker.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 24841016c..fdbf768aa 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -211,6 +211,8 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { switch(k) { case PR_UNDEF: return true; + case PR_TRUE: + return true; case PR_ASSERTED: return true; case PR_GOAL: From 6514741e3fe481b1cc0f67fe41a6e463fa0a8e19 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 10:45:07 -0700 Subject: [PATCH 1029/1283] proof-checker: replace match_negated with ast_manager::is_complement is_complement matches true and false, while match_negated does not Necessary to handle uses of true-axiom --- src/ast/proofs/proof_checker.cpp | 149 +++++++++++++++---------------- 1 file changed, 74 insertions(+), 75 deletions(-) diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index fdbf768aa..d0f8a7994 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -1,4 +1,3 @@ - /*++ Copyright (c) 2015 Microsoft Corporation @@ -16,7 +15,7 @@ Copyright (c) 2015 Microsoft Corporation #define SAME_OP(_d1_, _d2_) ((_d1_ == _d2_) || (IS_EQUIV(_d1_) && IS_EQUIV(_d2_))) -proof_checker::hyp_decl_plugin::hyp_decl_plugin() : +proof_checker::hyp_decl_plugin::hyp_decl_plugin() : m_cons(nullptr), m_atom(nullptr), m_nil(nullptr), @@ -59,13 +58,13 @@ func_decl * proof_checker::hyp_decl_plugin::mk_func_decl(decl_kind k) { } func_decl * proof_checker::hyp_decl_plugin::mk_func_decl( - decl_kind k, unsigned num_parameters, parameter const * parameters, + decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { return mk_func_decl(k); } func_decl * proof_checker::hyp_decl_plugin::mk_func_decl( - decl_kind k, unsigned num_parameters, parameter const * parameters, + decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned num_args, expr * const * args, sort * range) { return mk_func_decl(k); } @@ -84,7 +83,7 @@ void proof_checker::hyp_decl_plugin::get_sort_names(svector & sort } } -proof_checker::proof_checker(ast_manager& m) : m(m), m_todo(m), m_marked(), m_pinned(m), m_nil(m), +proof_checker::proof_checker(ast_manager& m) : m(m), m_todo(m), m_marked(), m_pinned(m), m_nil(m), m_dump_lemmas(false), m_logic("AUFLIA"), m_proof_lemma_id(0) { symbol fam_name("proof_hypothesis"); if (!m.has_plugin(fam_name)) { @@ -98,16 +97,16 @@ proof_checker::proof_checker(ast_manager& m) : m(m), m_todo(m), m_marked(), m_pi bool proof_checker::check(proof* p, expr_ref_vector& side_conditions) { proof_ref curr(m); m_todo.push_back(p); - + bool result = true; while (result && !m_todo.empty()) { curr = m_todo.back(); m_todo.pop_back(); result = check1(curr.get(), side_conditions); if (!result) { - IF_VERBOSE(0, ast_ll_pp(verbose_stream() << "Proof check failed\n", m, curr.get());); + IF_VERBOSE(0, ast_ll_pp(verbose_stream() << "Proof check failed\n", m, curr.get());); UNREACHABLE(); - } + } } m_hypotheses.reset(); @@ -157,10 +156,10 @@ bool proof_checker::check1_spc(proof* p, expr_ref_vector& side_conditions) { } return false; } - case PR_SPC_REWRITE: - case PR_SUPERPOSITION: + case PR_SPC_REWRITE: + case PR_SUPERPOSITION: case PR_EQUALITY_RESOLUTION: - case PR_SPC_RESOLUTION: + case PR_SPC_RESOLUTION: case PR_FACTORING: case PR_SPC_DER: { if (match_fact(p, fact)) { @@ -176,7 +175,7 @@ bool proof_checker::check1_spc(proof* p, expr_ref_vector& side_conditions) { side_conditions.push_back(rewrite_cond.get()); return true; } - return false; + return false; } default: UNREACHABLE(); @@ -201,7 +200,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { func_decl_ref f1(m), f2(m); expr_ref_vector terms1(m), terms2(m), terms(m); sort_ref_vector decls1(m), decls2(m); - + if (match_proof(p, proofs)) { for (unsigned i = 0; i < proofs.size(); ++i) { add_premise(proofs.get(i)); @@ -231,8 +230,8 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { return false; } case PR_REFLEXIVITY: { - if (match_fact(p, fact) && - match_proof(p) && + if (match_fact(p, fact) && + match_proof(p) && (match_equiv(fact, t1, t2) || match_oeq(fact, t1, t2)) && (t1.get() == t2.get())) { return true; @@ -245,7 +244,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { match_proof(p, p1) && match_fact(p1.get(), fml) && match_binary(fact.get(), d1, l1, r1) && - match_binary(fml.get(), d2, l2, r2) && + match_binary(fml.get(), d2, l2, r2) && SAME_OP(d1.get(), d2.get()) && l1.get() == r2.get() && r1.get() == l2.get()) { @@ -273,7 +272,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } UNREACHABLE(); return false; - } + } case PR_TRANSITIVITY_STAR: { if (match_fact(p, fact) && match_binary(fact.get(), d1, t1, t2)) { @@ -294,14 +293,14 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { return false; } } - return + return vertices.size() == 2 && vertices.contains(t1->get_id()) && vertices.contains(t2->get_id()); } UNREACHABLE(); return false; - } + } case PR_MONOTONICITY: { TRACE("proof_checker", tout << mk_bounded_pp(p, m, 3) << "\n";); if (match_fact(p, fact) && @@ -317,7 +316,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { if (term1 != term2) { bool found = false; for(unsigned j = 0; j < proofs.size() && !found; ++j) { - found = + found = match_fact(proofs[j].get(), fml) && match_binary(fml.get(), d2, s1, s2) && SAME_OP(d1.get(), d2.get()) && @@ -353,7 +352,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { for (unsigned i = 0; i < q1->get_num_decls(); ++i) { if (q1->get_decl_sort(i) != q2->get_decl_sort(i)) { // term is not well-typed. - UNREACHABLE(); + UNREACHABLE(); return false; } } @@ -410,7 +409,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { side_conditions.push_back(fact.get()); return true; } - IF_VERBOSE(0, verbose_stream() << "Expected proof of equality:\n" << mk_bounded_pp(p, m);); + IF_VERBOSE(0, verbose_stream() << "Expected proof of equality:\n" << mk_bounded_pp(p, m);); return false; } case PR_REWRITE_STAR: { @@ -428,8 +427,8 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { side_conditions.push_back(rewrite_cond.get()); return true; } - IF_VERBOSE(0, verbose_stream() << "Expected proof of equality:\n" << mk_bounded_pp(p, m);); - return false; + IF_VERBOSE(0, verbose_stream() << "Expected proof of equality:\n" << mk_bounded_pp(p, m);); + return false; } case PR_PULL_QUANT: { if (match_proof(p) && @@ -439,7 +438,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { // TBD: check the enchilada. return true; } - IF_VERBOSE(0, verbose_stream() << "Expected proof of equivalence with a quantifier:\n" << mk_bounded_pp(p, m);); + IF_VERBOSE(0, verbose_stream() << "Expected proof of equivalence with a quantifier:\n" << mk_bounded_pp(p, m);); return false; } case PR_PUSH_QUANT: { @@ -459,7 +458,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } else { return false; - } + } } } UNREACHABLE(); @@ -470,7 +469,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { match_fact(p, fact) && match_iff(fact.get(), t1, t2)) { // TBD: - // match_quantifier(t1.get(), is_forall1, decls1, body1) + // match_quantifier(t1.get(), is_forall1, decls1, body1) // filter out decls1 that occur in body1. // if list is empty, then t2 could be just body1. // otherwise t2 is also a quantifier. @@ -489,7 +488,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { // TBD: check that terms are set of equalities. // t2 is an instance of a predicate in terms1 return true; - } + } IF_VERBOSE(0, verbose_stream() << "does not match last rule: " << mk_pp(p, m) << "\n";); return false; } @@ -511,7 +510,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { get_hypotheses(p1.get(), hypotheses); if (hypotheses.size() == 1 && match_negated(hypotheses.get(0), fact)) { // Suppose fact is (or a b c) and hypothesis is (not (or a b c)) - // That is, (or a b c) should be viewed as a 'quoted expression' and a unary clause, + // That is, (or a b c) should be viewed as a 'quoted expression' and a unary clause, // instead of a clause with three literals. return true; } @@ -535,7 +534,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { }); UNREACHABLE(); return false; - } + } TRACE("proof_checker", tout << "Matched:\n"; ast_ll_pp(tout, m, hypotheses[i].get()); ast_ll_pp(tout, m, ors[j-1].get());); @@ -550,7 +549,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { proofs.size() == 2 && match_fact(proofs[0].get(), fml1) && match_fact(proofs[1].get(), fml2) && - match_negated(fml1.get(), fml2.get()) && + m.is_complement(fml1.get(), fml2.get()) && m.is_false(fact.get())) { return true; } @@ -564,7 +563,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } bool found = false; for (unsigned j = 0; !found && j < terms1.size(); ++j) { - if (match_negated(terms1.get(j), fml2)) { + if (m.is_complement(terms1.get(j), fml2)) { found = true; if (j + 1 < terms1.size()) { terms1[j] = terms1.get(terms1.size()-1); @@ -573,7 +572,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } } if (!found) { - TRACE("pr_unit_bug", + TRACE("pr_unit_bug", tout << "Parents:\n"; for (unsigned i = 0; i < proofs.size(); i++) { expr_ref p(m); @@ -592,9 +591,9 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } } switch(terms1.size()) { - case 0: + case 0: return m.is_false(fact.get()); - case 1: + case 1: return fact.get() == terms1[0].get(); default: { if (match_or(fact.get(), terms2)) { @@ -617,7 +616,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { return false; } - + } } UNREACHABLE(); @@ -635,7 +634,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } UNREACHABLE(); return false; - } + } case PR_IFF_FALSE: { // iff_false(?rule(?p1, (not ?fml)), (iff ?fml false)) if (match_proof(p, p1) && @@ -678,11 +677,11 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } case PR_DEF_INTRO: { // def_intro(?fml) - // + // // ?fml: forall x . ~p(x) or e(x) and forall x . ~e(x) or p(x) // : forall x . ~cond(x) or f(x) = then(x) and forall x . cond(x) or f(x) = else(x) // : forall x . f(x) = e(x) - // + // if (match_fact(p, fact) && match_proof(p) && m.is_bool(fact.get())) { @@ -712,7 +711,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { return true; } UNREACHABLE(); - return false; + return false; } case PR_NNF_POS: { // TBD: @@ -735,9 +734,9 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { is_forall = true; } if (is_quantifier(e)) { - q = to_quantifier(e); + q = to_quantifier(e); // TBD check that quantifier is properly instantiated - return is_forall == q->is_forall(); + return is_forall == q->is_forall(); } } UNREACHABLE(); @@ -788,7 +787,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { vs(premise, sub.size(), sub.c_ptr(), premise); } fmls.push_back(premise.get()); - TRACE("proof_checker", + TRACE("proof_checker", tout << mk_pp(premise.get(), m) << "\n"; for (unsigned j = 0; j < sub.size(); ++j) { tout << mk_pp(sub[j], m) << " "; @@ -810,7 +809,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { // ok } else { - IF_VERBOSE(0, verbose_stream() << "Could not establish complementarity for:\n" << + IF_VERBOSE(0, verbose_stream() << "Could not establish complementarity for:\n" << mk_pp(lit1, m) << "\n" << mk_pp(lit2, m) << "\n" << mk_pp(p, m) << "\n";); } fmls[i] = premise1; @@ -825,7 +824,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { else { premise0 = m.mk_iff(premise0, conclusion); } - side_conditions.push_back(premise0); + side_conditions.push_back(premise0); return true; } default: @@ -841,7 +840,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { (=> (and ln+1 ln+2 .. ln+m) l0) or in the most general (ground) form: (=> (and ln+1 ln+2 .. ln+m) (or l0 l1 .. ln-1)) - In other words we use the following (Prolog style) convention for Horn + In other words we use the following (Prolog style) convention for Horn implications: The head of a Horn implication is position 0, the first conjunct in the body of an implication is position 1 @@ -853,7 +852,7 @@ void proof_checker::set_false(expr_ref& e, unsigned position, expr_ref& lit) { app* a = to_app(e); expr* head, *body; expr_ref_vector args(m); - if (m.is_or(e)) { + if (m.is_or(e)) { SASSERT(position < a->get_num_args()); args.append(a->get_num_args(), a->get_args()); lit = args[position].get(); @@ -865,13 +864,13 @@ void proof_checker::set_false(expr_ref& e, unsigned position, expr_ref& lit) { unsigned num_heads = 1; if (m.is_or(head)) { num_heads = to_app(head)->get_num_args(); - heads = to_app(head)->get_args(); + heads = to_app(head)->get_args(); } expr*const* bodies = &body; unsigned num_bodies = 1; if (m.is_and(body)) { num_bodies = to_app(body)->get_num_args(); - bodies = to_app(body)->get_args(); + bodies = to_app(body)->get_args(); } if (position < num_heads) { args.append(num_heads, heads); @@ -884,7 +883,7 @@ void proof_checker::set_false(expr_ref& e, unsigned position, expr_ref& lit) { args.append(num_bodies, bodies); lit = m.mk_not(args[position].get()); args[position] = m.mk_true(); - e = m.mk_implies(m.mk_and(args.size(), args.c_ptr()), head); + e = m.mk_implies(m.mk_and(args.size(), args.c_ptr()), head); } } else if (position == 0) { @@ -914,7 +913,7 @@ void proof_checker::add_premise(proof* p) { } bool proof_checker::match_proof(proof const* p) const { - return + return m.is_proof(p) && m.get_num_parents(p) == 0; } @@ -927,7 +926,7 @@ bool proof_checker::match_proof(proof const* p, proof_ref& p0) const { } return false; } - + bool proof_checker::match_proof(proof const* p, proof_ref& p0, proof_ref& p1) const { if (m.is_proof(p) && m.get_num_parents(p) == 2) { @@ -1055,7 +1054,7 @@ bool proof_checker::match_oeq(expr const* e, expr_ref& t1, expr_ref& t2) const { bool proof_checker::match_negated(expr const* a, expr* b) const { expr_ref t(m); - return + return (match_not(a, t) && t.get() == b) || (match_not(b, t) && t.get() == a); } @@ -1082,7 +1081,7 @@ void proof_checker::get_hypotheses(proof* p, expr_ref_vector& ante) { p = stack.back(); SASSERT(m.is_proof(p)); if (m_hypotheses.contains(p)) { - stack.pop_back(); + stack.pop_back(); continue; } if (is_hypothesis(p) && match_fact(p, hyp)) { @@ -1124,13 +1123,13 @@ void proof_checker::get_hypotheses(proof* p, expr_ref_vector& ante) { if (!m_hypotheses.find(p, h)) { UNREACHABLE(); } - + ptr_buffer hyps; ptr_buffer todo; expr_mark mark; todo.push_back(h); expr_ref a(m), b(m); - + while (!todo.empty()) { h = todo.back(); @@ -1155,14 +1154,14 @@ void proof_checker::get_hypotheses(proof* p, expr_ref_vector& ante) { ast_ll_pp(tout << "Getting hypotheses from: ", m, p); tout << "Found hypotheses:\n"; for (unsigned i = 0; i < ante.size(); ++i) { - ast_ll_pp(tout, m, ante[i].get()); + ast_ll_pp(tout, m, ante[i].get()); } }); } bool proof_checker::match_nil(expr const* e) const { - return + return is_app(e) && to_app(e)->get_family_id() == m_hyp_fid && to_app(e)->get_decl_kind() == OP_NIL; @@ -1203,7 +1202,7 @@ expr* proof_checker::mk_nil() { } bool proof_checker::is_hypothesis(proof const* p) const { - return + return m.is_proof(p) && p->get_decl_kind() == PR_HYPOTHESIS; } @@ -1225,7 +1224,7 @@ expr* proof_checker::mk_hyp(unsigned num_hyps, expr * const * hyps) { } else { return result; - } + } } void proof_checker::dump_proof(proof const* pr) { @@ -1267,7 +1266,7 @@ void proof_checker::dump_proof(unsigned num_antecedents, expr * const * antecede bool proof_checker::check_arith_literal(bool is_pos, app* lit0, rational const& coeff, expr_ref& sum, bool& is_strict) { arith_util a(m); app* lit = lit0; - + if (m.is_not(lit)) { lit = to_app(lit->get_arg(0)); is_pos = !is_pos; @@ -1307,25 +1306,25 @@ bool proof_checker::check_arith_literal(bool is_pos, app* lit0, rational const& } // - // Multiplying by coefficients over strict + // Multiplying by coefficients over strict // and non-strict inequalities: // // (a <= b) * 2 // (a - b <= 0) * 2 // (2a - 2b <= 0) - + // (a < b) * 2 <=> // (a +1 <= b) * 2 <=> // 2a + 2 <= 2b <=> // 2a+2-2b <= 0 - + bool strict_ineq = is_pos?(a.is_gt(lit) || a.is_lt(lit)):(a.is_ge(lit) || a.is_le(lit)); - + if (is_int && strict_ineq) { sum = a.mk_add(sum, sign1); } - + term = a.mk_mul(sign1, a0); sum = a.mk_add(sum, term); term = a.mk_mul(sign2, a1); @@ -1357,7 +1356,7 @@ bool proof_checker::check_arith_proof(proof* p) { } expr_ref fact(m); proof_ref_vector proofs(m); - + if (!match_fact(p, fact)) { UNREACHABLE(); return false; @@ -1386,7 +1385,7 @@ bool proof_checker::check_arith_proof(proof* p) { coeffs[i] = lc*coeffs[i]; } } - + unsigned num_parents = m.get_num_parents(p); for (unsigned i = 0; i < num_parents; i++) { proof * a = m.get_parent(p, i); @@ -1395,11 +1394,11 @@ bool proof_checker::check_arith_proof(proof* p) { return false; } } - - if (m.is_or(fact)) { + + if (m.is_or(fact)) { app* disj = to_app(fact); unsigned num_args = disj->get_num_args(); - for (unsigned i = 0; i < num_args; ++i) { + for (unsigned i = 0; i < num_args; ++i) { app* lit = to_app(disj->get_arg(i)); if (!check_arith_literal(false, lit, coeffs[offset++], sum, is_strict)) { return false; @@ -1411,13 +1410,13 @@ bool proof_checker::check_arith_proof(proof* p) { return false; } } - + if (!sum.get()) { return false; } - + sort* s = m.get_sort(sum); - + if (is_strict) { sum = autil.mk_lt(sum, autil.mk_numeral(rational(0), s)); @@ -1435,6 +1434,6 @@ bool proof_checker::check_arith_proof(proof* p) { dump_proof(p); return false; } - + return true; } From 38a45f5482a0c2ee25e971c5afee6afb2182a100 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 10:47:24 -0700 Subject: [PATCH 1030/1283] Fix typo in comment --- src/tactic/core/solve_eqs_tactic.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index f579b7b4f..f665fe509 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -636,7 +636,7 @@ class solve_eqs_tactic : public tactic { TRACE("gaussian_leak", tout << "processing:\n" << mk_ismt2_pp(f, m()) << "\n";); if (m_candidate_set.is_marked(f)) { // f may be deleted after the following update. - // so, we must remove remove the mark before doing the update + // so, we must remove the mark before doing the update m_candidate_set.mark(f, false); SASSERT(!m_candidate_set.is_marked(f)); g.update(idx, m().mk_true(), m().mk_true_proof(), nullptr); @@ -842,4 +842,3 @@ tactic * mk_solve_eqs_tactic(ast_manager & m, params_ref const & p, expr_replace else return clean(alloc(solve_eqs_tactic, m, p, r, false)); } - From 8be03f7c1f6d1bd1e9c27ded3c9942d109a63153 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 14:18:11 -0700 Subject: [PATCH 1031/1283] spacer_context: skolemize quant vars before renaming Skolemization has to be done before renaming, otherwise, can't guarantee that variable names do not clash --- src/muz/spacer/spacer_context.cpp | 73 ++++++++++++++++++------------- src/muz/spacer/spacer_context.h | 4 +- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 2baa70f46..044c0f091 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -72,34 +72,17 @@ pob::pob (pob* parent, pred_transformer& pt, void pob::set_post(expr* post) { - app_ref_vector b(get_ast_manager()); - set_post(post, b); + app_ref_vector empty_binding(get_ast_manager()); + set_post(post, empty_binding); } -void pob::set_post(expr* post, app_ref_vector const &b) { +void pob::set_post(expr* post, app_ref_vector const &binding) { normalize(post, m_post, m_pt.get_context().get_params().spacer_simplify_pob(), m_pt.get_context().get_params().spacer_use_eqclass()); m_binding.reset(); - if (b.empty()) return; - - m_binding.append(b); - - std::sort (m_binding.c_ptr(), m_binding.c_ptr() + m_binding.size(), sk_lt_proc()); - - // skolemize implicit existential quantifier - ast_manager &m = get_ast_manager(); - app_ref_vector pinned(m); - - expr_safe_replace sub(m); - for (unsigned i = 0, sz = m_binding.size(); i < sz; ++i) { - expr* e; - e = m_binding.get(i); - pinned.push_back (mk_zk_const (m, i, get_sort(e))); - sub.insert (e, pinned.back()); - } - sub(m_post); + if (!binding.empty()) {m_binding.append(binding);} } void pob::inherit(pob const &p) { @@ -216,6 +199,25 @@ pob *derivation::create_first_child (model_evaluator_util &mev) return create_next_child(mev); } +void derivation::exist_skolemize(expr* fml, app_ref_vector &vars, expr_ref &res) { + ast_manager &m = get_ast_manager(); + if (vars.empty()) {res = fml; return;} + if (m.is_true(fml) || m.is_false(fml)) {res = fml; return;} + + std::sort (vars.c_ptr(), vars.c_ptr() + vars.size(), sk_lt_proc()); + + app_ref_vector pinned(m); + + expr_safe_replace sub(m); + for (unsigned i = 0, sz = vars.size(); i < sz; ++i) { + expr* e; + e = vars.get(i); + pinned.push_back (mk_zk_const (m, i, get_sort(e))); + sub.insert (e, pinned.back()); + } + sub(fml, res); +} + pob *derivation::create_next_child (model_evaluator_util &mev) { timeit _timer (is_trace_enabled("spacer_timeit"), @@ -280,6 +282,11 @@ pob *derivation::create_next_child (model_evaluator_util &mev) m_evars.append (vars); } + if (!m_evars.empty()) { + // existentially quantify out m_evars from post and skolemize the result + exist_skolemize(post.get(), m_evars, post); + } + get_manager ().formula_o2n (post.get (), post, m_premises [m_active].get_oidx (), m_evars.empty()); @@ -290,7 +297,6 @@ pob *derivation::create_next_child (model_evaluator_util &mev) pob *n = m_premises[m_active].pt().mk_pob(&m_parent, prev_level (m_parent.level ()), m_parent.depth (), post, m_evars); - IF_VERBOSE (1, verbose_stream () << "\n\tcreate_child: " << n->pt ().head ()->get_name () << " (" << n->level () << ", " << n->depth () << ") " @@ -895,9 +901,8 @@ bool pred_transformer::propagate_to_next_level (unsigned src_level) {return m_frames.propagate_to_next_level (src_level);} -/// \brief adds a lema to the solver and to child solvers -void pred_transformer::add_lemma_core(lemma* lemma, - bool ground_only) +/// \brief adds a lemma to the solver and to child solvers +void pred_transformer::add_lemma_core(lemma* lemma, bool ground_only) { unsigned lvl = lemma->level(); expr* l = lemma->get_expr(); @@ -1859,13 +1864,13 @@ void pred_transformer::frames::simplify_formulas () // ensure that the lemmas are sorted sort(); - ast_manager &m = m_pt.get_ast_manager (); + ast_manager &m = m_pt.get_ast_manager(); - tactic_ref simplifier = mk_unit_subsumption_tactic (m); + tactic_ref simplifier = mk_unit_subsumption_tactic(m); lemma_ref_vector new_lemmas; - unsigned lemmas_size = m_lemmas.size (); - goal_ref g (alloc (goal, m, false, false, false)); + unsigned lemmas_size = m_lemmas.size(); + goal_ref g(alloc (goal, m, false, false, false)); unsigned j = 0; // for every frame + infinity frame @@ -1933,6 +1938,11 @@ void pred_transformer::frames::simplify_formulas () << mk_pp(m_lemmas[n]->get_expr(), m) << "\n"; } + + verbose_stream() << "Simplified goal is:\n"; + for (unsigned k = 0; k < r->size(); ++k) + verbose_stream() << k << ": " + << mk_pp(r->form(k), m) << "\n"; } ENSURE(found); SASSERT(found); @@ -3013,7 +3023,8 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) TRACE ("spacer", tout << "expand-pob: " << n.pt().head()->get_name() << " level: " << n.level() - << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" + << " depth: " << (n.depth () - m_pob_queue.min_depth ()) + << " fvsz: " << n.get_free_vars_size() << "\n" << mk_pp(n.post(), m) << "\n";); STRACE ("spacer.expand-add", @@ -3450,6 +3461,8 @@ bool context::create_children(pob& n, datalog::rule const& r, tout << "Implicant\n"; tout << mk_and (Phi) << "\n"; tout << "Projected Implicant\n" << mk_pp (phi1, m) << "\n"; + if (!vars.empty()) + tout << "could not eliminate: " << vars << "\n"; ); // expand literals. Ideally, we do not want to split aliasing diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 62d90e4c0..8de4a70f8 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -517,7 +517,7 @@ public: expr* post() const { return m_post.get (); } void set_post(expr *post); - void set_post(expr *post, app_ref_vector const &b); + void set_post(expr *post, app_ref_vector const &binding); /// indicate that a new post should be set for the node void new_post(expr *post) {if(post != m_post) {m_new_post = post;}} @@ -648,6 +648,8 @@ public: /// premise must be consistent with the transition relation pob *create_next_child (); + /// existentially quantify vars and skolemize the result + void exist_skolemize(expr *fml, app_ref_vector &vars, expr_ref &res); datalog::rule const& get_rule () const { return m_rule; } pob& get_parent () const { return m_parent; } ast_manager &get_ast_manager () const {return m_parent.get_ast_manager ();} From 891dcd99c2d7934e4ccf1d69c1d99b23b14a097b Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 15:22:58 -0700 Subject: [PATCH 1032/1283] Use fact-generating version of mk_unit_resolution() fact-using version of mk_unit_resolution() requires the fact to be a literal. Not sure why this restriction is placed there. --- src/muz/spacer/spacer_proof_utils.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 151446a93..a2a0ba6b6 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -491,9 +491,10 @@ proof* hypothesis_reducer::mk_unit_resolution_core(proof *ures, } // make unit resolution proof step - expr_ref tmp(m); - tmp = mk_or(m, pf_fact.size(), pf_fact.c_ptr()); - proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), tmp); + // expr_ref tmp(m); + // tmp = mk_or(m, pf_fact.size(), pf_fact.c_ptr()); + // proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), tmp); + proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr()); m_pinned.push_back(res); return res; From 56bce005a0dbbe368060961bff9c9c139377b169 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 15:47:28 -0700 Subject: [PATCH 1033/1283] virtual_solver: debug print --- src/muz/spacer/spacer_virtual_solver.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 903f82d23..873f94160 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -150,7 +150,6 @@ lbool virtual_solver::check_sat_core(unsigned num_assumptions, st.update("time", sw.get_seconds()); st.display_smt2(out); - out.close(); if (m_factory.fparams().m_dump_recheck) { scoped_no_proof _no_proof_(m); @@ -164,7 +163,13 @@ lbool virtual_solver::check_sat_core(unsigned num_assumptions, sw2.stop(); verbose_stream() << file_name.str() << " :orig " << sw.get_seconds() << " :new " << sw2.get_seconds(); + + out << ";; :orig " << sw.get_seconds() + << " :new " << sw2.get_seconds() << "\n" + << ";; :new is time to solve with fresh smt::kernel\n"; } + + out.close(); } @@ -195,9 +200,9 @@ void virtual_solver::pop_core(unsigned n) { SASSERT(!m_in_delay_scope); m_context.pop(n); m_pushed = get_scope_level() - n > 0; - } + } else { - m_in_delay_scope = get_scope_level() - n > 0; + m_in_delay_scope = get_scope_level() - n > 0; } } From 054c6196a0fa4c1b19cfcb3ab250cdb2ea1de76d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 17:39:35 -0700 Subject: [PATCH 1034/1283] Move spacer qe into spacer_qe namespace Attempt to solve compilation issues with GCC and current replication of qe namespace inside and outside spacer --- src/muz/spacer/spacer_legacy_mbp.cpp | 2 +- src/muz/spacer/spacer_qe_project.cpp | 10 +-- src/muz/spacer/spacer_qe_project.h | 2 +- src/muz/spacer/spacer_util.cpp | 114 +++++++++++++-------------- 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/muz/spacer/spacer_legacy_mbp.cpp b/src/muz/spacer/spacer_legacy_mbp.cpp index 9f03e6d2f..d52228d8a 100644 --- a/src/muz/spacer/spacer_legacy_mbp.cpp +++ b/src/muz/spacer/spacer_legacy_mbp.cpp @@ -99,7 +99,7 @@ void qe_project(ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& ); { scoped_no_proof _sp(m); - qe::arith_project(*M, arith_vars, fml, map); + spacer_qe::arith_project(*M, arith_vars, fml, map); } SASSERT(arith_vars.empty()); TRACE("spacer", diff --git a/src/muz/spacer/spacer_qe_project.cpp b/src/muz/spacer/spacer_qe_project.cpp index 753bb43b8..1bf670a7a 100644 --- a/src/muz/spacer/spacer_qe_project.cpp +++ b/src/muz/spacer/spacer_qe_project.cpp @@ -41,7 +41,7 @@ Revision History: #include "muz/spacer/spacer_mev_array.h" #include "muz/spacer/spacer_qe_project.h" -namespace +namespace spacer_qe { bool is_partial_eq (app* a); @@ -186,7 +186,7 @@ bool is_partial_eq (app* a) { } -namespace qe { +namespace spacer_qe { class is_relevant_default : public i_expr_pred { public: @@ -195,7 +195,7 @@ namespace qe { } }; - class mk_atom_default : public i_nnf_atom { + class mk_atom_default : public qe::i_nnf_atom { public: void operator()(expr* e, bool pol, expr_ref& result) override { if (pol) result = e; @@ -2254,7 +2254,7 @@ namespace qe { void arith_project(model& mdl, app_ref_vector& vars, expr_ref& fml) { ast_manager& m = vars.get_manager(); arith_project_util ap(m); - atom_set pos_lits, neg_lits; + qe::atom_set pos_lits, neg_lits; is_relevant_default is_relevant; mk_atom_default mk_atom; get_nnf (fml, is_relevant, mk_atom, pos_lits, neg_lits); @@ -2264,7 +2264,7 @@ namespace qe { void arith_project(model& mdl, app_ref_vector& vars, expr_ref& fml, expr_map& map) { ast_manager& m = vars.get_manager(); arith_project_util ap(m); - atom_set pos_lits, neg_lits; + qe::atom_set pos_lits, neg_lits; is_relevant_default is_relevant; mk_atom_default mk_atom; get_nnf (fml, is_relevant, mk_atom, pos_lits, neg_lits); diff --git a/src/muz/spacer/spacer_qe_project.h b/src/muz/spacer/spacer_qe_project.h index b923dc3c7..65848f8f3 100644 --- a/src/muz/spacer/spacer_qe_project.h +++ b/src/muz/spacer/spacer_qe_project.h @@ -23,7 +23,7 @@ Notes: #include "model/model.h" #include "ast/expr_map.h" -namespace qe { +namespace spacer_qe { /** Loos-Weispfenning model-based projection for a basic conjunction. Lits is a vector of literals. diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 030f2a386..7b1a2a07c 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -90,33 +90,33 @@ namespace spacer { if (!m_model) { return; } m_mev = alloc(model_evaluator, *m_model); } - + bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { m_mev->set_model_completion (model_completion); try { m_mev->operator() (e, result); return true; - } + } catch (model_evaluator_exception &ex) { (void)ex; TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); return false; } } - + bool model_evaluator_util::eval(const expr_ref_vector &v, expr_ref& res, bool model_completion) { expr_ref e(m); e = mk_and (v); return eval(e, res, model_completion); } - - + + bool model_evaluator_util::is_true(const expr_ref_vector &v) { expr_ref res(m); return eval (v, res, false) && m.is_true (res); } - + bool model_evaluator_util::is_false(expr *x) { expr_ref res(m); return eval(x, res, false) && m.is_false (res); @@ -126,7 +126,7 @@ namespace spacer { expr_ref res(m); return eval(x, res, false) && m.is_true (res); } - + void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { ast_manager& m = fml.get_manager(); expr_ref_vector conjs(m); @@ -172,16 +172,16 @@ namespace spacer { SASSERT(orig_size <= 1 + conjs.size()); if (i + 1 == orig_size) { // no-op. - } + } else if (orig_size <= conjs.size()) { // no-op - } + } else { SASSERT(orig_size == 1 + conjs.size()); --orig_size; --i; } - } + } else { conjs[i] = tmp; } @@ -199,7 +199,7 @@ namespace spacer { ast_manager& m; public: ite_hoister(ast_manager& m): m(m) {} - + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { if (m.is_ite(f)) { return BR_FAILED; @@ -234,7 +234,7 @@ namespace spacer { } ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} }; - + class ite_hoister_star : public rewriter_tpl { ite_hoister_cfg m_cfg; public: @@ -242,7 +242,7 @@ namespace spacer { rewriter_tpl(m, false, m_cfg), m_cfg(m, p) {} }; - + void hoist_non_bool_if(expr_ref& fml) { ast_manager& m = fml.get_manager(); scoped_no_proof _sp(m); @@ -274,7 +274,7 @@ namespace spacer { bool is_arith_expr(expr *e) const { return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); } - + bool is_offset(expr* e) const { if (a.is_numeral(e)) { return true; @@ -358,7 +358,7 @@ namespace spacer { !a.is_mul(lhs) && !a.is_mul(rhs); } - + bool test_term(expr* e) const { if (m.is_bool(e)) { return true; @@ -403,9 +403,9 @@ namespace spacer { public: test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} - + void test_for_utvpi() { m_test_for_utvpi = true; } - + void operator()(expr* e) { if (!m_is_dl) { return; @@ -422,7 +422,7 @@ namespace spacer { m_is_dl = test_term(a->get_arg(i)); } } - + if (!m_is_dl) { char const* msg = "non-diff: "; if (m_test_for_utvpi) { @@ -431,10 +431,10 @@ namespace spacer { IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); } } - + bool is_dl() const { return m_is_dl; } }; - + bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); expr_fast_mark1 mark; @@ -443,7 +443,7 @@ namespace spacer { } return test.is_dl(); } - + bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); test.test_for_utvpi(); @@ -455,7 +455,7 @@ namespace spacer { } - void subst_vars(ast_manager& m, + void subst_vars(ast_manager& m, app_ref_vector const& vars, model* M, expr_ref& fml) { expr_safe_replace sub (m); @@ -488,7 +488,7 @@ namespace spacer { flatten_and (fml, flat); fml = mk_and(flat); } - + app_ref_vector arith_vars (m); app_ref_vector array_vars (m); array_util arr_u (m); @@ -501,7 +501,7 @@ namespace spacer { qe_lite qe(m, p, false); qe (vars, fml); rw (fml); - + TRACE ("spacer_mbp", tout << "After qe_lite:\n"; tout << mk_pp (fml, m) << "\n"; @@ -509,7 +509,7 @@ namespace spacer { SASSERT (!m.is_false (fml)); - + // sort out vars into bools, arith (int/real), and arrays for (app* v : vars) { if (m.is_bool (v)) { @@ -523,7 +523,7 @@ namespace spacer { arith_vars.push_back (v); } } - + // substitute Booleans if (!bool_sub.empty()) { bool_sub (fml); @@ -533,58 +533,58 @@ namespace spacer { TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); bool_sub.reset (); } - + TRACE ("spacer_mbp", tout << "Array vars:\n"; tout << array_vars;); - + vars.reset (); - + // project arrays { scoped_no_proof _sp (m); // -- local rewriter that is aware of current proof mode th_rewriter srw(m); - qe::array_project (*M.get (), array_vars, fml, vars, reduce_all_selects); + spacer_qe::array_project (*M.get (), array_vars, fml, vars, reduce_all_selects); SASSERT (array_vars.empty ()); srw (fml); SASSERT (!m.is_false (fml)); } - + TRACE ("spacer_mbp", tout << "extended model:\n"; model_pp (tout, *M); tout << "Auxiliary variables of index and value sorts:\n"; tout << vars; ); - + if (vars.empty()) { break; } } // project reals and ints if (!arith_vars.empty ()) { TRACE ("spacer_mbp", tout << "Arith vars:\n" << arith_vars;); - + // XXX Does not seem to have an effect // qe_lite qe(m); // qe (arith_vars, fml); // TRACE ("spacer_mbp", // tout << "After second qelite: " << // mk_pp (fml, m) << "\n";); - + if (use_native_mbp) { qe::mbp mbp (m); expr_ref_vector fmls(m); flatten_and (fml, fmls); - + mbp (true, arith_vars, *M.get (), fmls); fml = mk_and (fmls); SASSERT (arith_vars.empty ()); } else { scoped_no_proof _sp (m); - qe::arith_project (*M.get (), arith_vars, fml); + spacer_qe::arith_project (*M.get (), arith_vars, fml); } - + TRACE ("spacer_mbp", tout << "Projected arith vars:\n" << mk_pp (fml, m) << "\n"; tout << "Remaining arith vars:\n" << arith_vars << "\n";); @@ -615,8 +615,8 @@ namespace spacer { ); vars.reset (); - if (dont_sub && !arith_vars.empty ()) { - vars.append(arith_vars); + if (dont_sub && !arith_vars.empty ()) { + vars.append(arith_vars); } } @@ -701,11 +701,11 @@ namespace { model_evaluator_util &m_mev; ast_manager &m; arith_util m_arith; - + expr_ref_vector m_todo; expr_mark m_visited; - + void add_literal (expr *e, expr_ref_vector &out) { SASSERT (m.is_bool (e)); @@ -753,11 +753,11 @@ namespace { SASSERT (m.is_bool (a)); expr_ref v(m); m_mev.eval (a, v, false); - + if (!m.is_true(v) && !m.is_false(v)) { return; } - + expr *na, *f1, *f2, *f3; - + if (a->get_family_id() != m.get_basic_family_id()) { add_literal(a, out); } else if (is_uninterp_const(a)) @@ -836,13 +836,13 @@ namespace { UNREACHABLE(); } } - + void pick_literals(expr *e, expr_ref_vector &out) { SASSERT(m_todo.empty()); if (m_visited.is_marked(e)) { return; } SASSERT(is_app(e)); - + m_todo.push_back(e); do { app *a = to_app(m_todo.back()); @@ -851,27 +851,27 @@ namespace { m_visited.mark(a, true); } while (!m_todo.empty()); } - + bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) { m_visited.reset(); expr_ref e(m); e = mk_and (in); bool is_true = m_mev.is_true (e); - + for (unsigned i = 0, sz = in.size (); i < sz; ++i) { if (is_true || m_mev.is_true(in.get(i))) { pick_literals(in.get(i), out); } } - + m_visited.reset (); return is_true; } - + public: implicant_picker (model_evaluator_util &mev) : m_mev (mev), m (m_mev.get_ast_manager ()), m_arith(m), m_todo(m) {} - + void operator() (expr_ref_vector &in, expr_ref_vector& out) {pick_implicant (in, out);} }; @@ -1188,29 +1188,29 @@ void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { bool mbqi_project_var (model_evaluator_util &mev, app* var, expr_ref &fml) { ast_manager &m = fml.get_manager (); - + expr_ref val(m); mev.eval (var, val, false); - + TRACE ("mbqi_project_verbose", tout << "MBQI: var: " << mk_pp (var, m) << "\n" << "fml: " << mk_pp (fml, m) << "\n";); expr_ref_vector terms (m); index_term_finder finder (m, var, terms); for_each_expr (finder, fml); - - + + TRACE ("mbqi_project_verbose", tout << "terms:\n"; for (unsigned i = 0, e = terms.size (); i < e; ++i) tout << i << ": " << mk_pp (terms.get (i), m) << "\n"; ); - + for (unsigned i = 0, e = terms.size(); i < e; ++i) { expr* term = terms.get (i); expr_ref tval (m); mev.eval (term, tval, false); - + TRACE ("mbqi_project_verbose", tout << "term: " << mk_pp (term, m) << " tval: " << mk_pp (tval, m) From e8cabdc6202b616062804e89a431a06ff61577f3 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 17:42:56 -0700 Subject: [PATCH 1035/1283] Uninitialized variable --- src/muz/spacer/spacer_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 044c0f091..df945d9bb 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2082,7 +2082,7 @@ void context::init_rules(datalog::rule_set& rules, decl2rel& rels) // for (auto it = rels.begin(), end = rels.end(); it != end; ++it) { for (auto &entry : rels) { func_decl* pred = entry.m_key; - pred_transformer* pt = entry.m_value, *pt_user; + pred_transformer* pt = entry.m_value, *pt_user = nullptr; for (auto dep : rules.get_dependencies().get_deps(pred)) { TRACE("spacer", tout << mk_pp(pred, m) << " " << mk_pp(dep, m) << "\n";); rels.find(dep, pt_user); From 402234757e073717d339d795205c2f8b192967d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 May 2018 13:06:47 -0700 Subject: [PATCH 1036/1283] updates to mbqi Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_util.cpp | 196 ++++++++++++++++----------------- src/qe/qe_mbp.cpp | 32 +++--- 2 files changed, 114 insertions(+), 114 deletions(-) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 7b1a2a07c..90e0542fa 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -90,33 +90,33 @@ namespace spacer { if (!m_model) { return; } m_mev = alloc(model_evaluator, *m_model); } - + bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { m_mev->set_model_completion (model_completion); try { m_mev->operator() (e, result); return true; - } + } catch (model_evaluator_exception &ex) { (void)ex; TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); return false; } } - + bool model_evaluator_util::eval(const expr_ref_vector &v, expr_ref& res, bool model_completion) { expr_ref e(m); e = mk_and (v); return eval(e, res, model_completion); } - - + + bool model_evaluator_util::is_true(const expr_ref_vector &v) { expr_ref res(m); return eval (v, res, false) && m.is_true (res); } - + bool model_evaluator_util::is_false(expr *x) { expr_ref res(m); return eval(x, res, false) && m.is_false (res); @@ -126,7 +126,7 @@ namespace spacer { expr_ref res(m); return eval(x, res, false) && m.is_true (res); } - + void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { ast_manager& m = fml.get_manager(); expr_ref_vector conjs(m); @@ -172,16 +172,16 @@ namespace spacer { SASSERT(orig_size <= 1 + conjs.size()); if (i + 1 == orig_size) { // no-op. - } + } else if (orig_size <= conjs.size()) { // no-op - } + } else { SASSERT(orig_size == 1 + conjs.size()); --orig_size; --i; } - } + } else { conjs[i] = tmp; } @@ -199,7 +199,7 @@ namespace spacer { ast_manager& m; public: ite_hoister(ast_manager& m): m(m) {} - + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { if (m.is_ite(f)) { return BR_FAILED; @@ -234,7 +234,7 @@ namespace spacer { } ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} }; - + class ite_hoister_star : public rewriter_tpl { ite_hoister_cfg m_cfg; public: @@ -242,7 +242,7 @@ namespace spacer { rewriter_tpl(m, false, m_cfg), m_cfg(m, p) {} }; - + void hoist_non_bool_if(expr_ref& fml) { ast_manager& m = fml.get_manager(); scoped_no_proof _sp(m); @@ -274,7 +274,7 @@ namespace spacer { bool is_arith_expr(expr *e) const { return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); } - + bool is_offset(expr* e) const { if (a.is_numeral(e)) { return true; @@ -358,7 +358,7 @@ namespace spacer { !a.is_mul(lhs) && !a.is_mul(rhs); } - + bool test_term(expr* e) const { if (m.is_bool(e)) { return true; @@ -403,9 +403,9 @@ namespace spacer { public: test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} - + void test_for_utvpi() { m_test_for_utvpi = true; } - + void operator()(expr* e) { if (!m_is_dl) { return; @@ -422,7 +422,7 @@ namespace spacer { m_is_dl = test_term(a->get_arg(i)); } } - + if (!m_is_dl) { char const* msg = "non-diff: "; if (m_test_for_utvpi) { @@ -431,10 +431,10 @@ namespace spacer { IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); } } - + bool is_dl() const { return m_is_dl; } }; - + bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); expr_fast_mark1 mark; @@ -443,7 +443,7 @@ namespace spacer { } return test.is_dl(); } - + bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); test.test_for_utvpi(); @@ -455,7 +455,7 @@ namespace spacer { } - void subst_vars(ast_manager& m, + void subst_vars(ast_manager& m, app_ref_vector const& vars, model* M, expr_ref& fml) { expr_safe_replace sub (m); @@ -488,7 +488,7 @@ namespace spacer { flatten_and (fml, flat); fml = mk_and(flat); } - + app_ref_vector arith_vars (m); app_ref_vector array_vars (m); array_util arr_u (m); @@ -497,19 +497,19 @@ namespace spacer { expr_ref bval (m); while (true) { - params_ref p; - qe_lite qe(m, p, false); - qe (vars, fml); - rw (fml); - - TRACE ("spacer_mbp", - tout << "After qe_lite:\n"; - tout << mk_pp (fml, m) << "\n"; + params_ref p; + qe_lite qe(m, p, false); + qe (vars, fml); + rw (fml); + + TRACE ("spacer_mbp", + tout << "After qe_lite:\n"; + tout << mk_pp (fml, m) << "\n"; tout << "Vars:\n" << vars;); SASSERT (!m.is_false (fml)); - + // sort out vars into bools, arith (int/real), and arrays for (app* v : vars) { if (m.is_bool (v)) { @@ -523,7 +523,7 @@ namespace spacer { arith_vars.push_back (v); } } - + // substitute Booleans if (!bool_sub.empty()) { bool_sub (fml); @@ -533,13 +533,13 @@ namespace spacer { TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); bool_sub.reset (); } - + TRACE ("spacer_mbp", tout << "Array vars:\n"; tout << array_vars;); - + vars.reset (); - + // project arrays { scoped_no_proof _sp (m); @@ -550,14 +550,14 @@ namespace spacer { srw (fml); SASSERT (!m.is_false (fml)); } - + TRACE ("spacer_mbp", tout << "extended model:\n"; model_pp (tout, *M); tout << "Auxiliary variables of index and value sorts:\n"; tout << vars; ); - + if (vars.empty()) { break; } } @@ -572,21 +572,21 @@ namespace spacer { // tout << "After second qelite: " << // mk_pp (fml, m) << "\n";); - if (use_native_mbp) { - qe::mbp mbp (m); - expr_ref_vector fmls(m); - flatten_and (fml, fmls); + if (use_native_mbp) { + qe::mbp mbp (m); + expr_ref_vector fmls(m); + flatten_and (fml, fmls); - mbp (true, arith_vars, *M.get (), fmls); - fml = mk_and (fmls); - SASSERT (arith_vars.empty ()); - } else { + mbp (true, arith_vars, *M.get (), fmls); + fml = mk_and (fmls); + SASSERT (arith_vars.empty ()); + } else { scoped_no_proof _sp (m); spacer_qe::arith_project (*M.get (), arith_vars, fml); } TRACE ("spacer_mbp", - tout << "Projected arith vars:\n" << mk_pp (fml, m) << "\n"; + tout << "Projected arith vars:\n" << mk_pp (fml, m) << "\n"; tout << "Remaining arith vars:\n" << arith_vars << "\n";); SASSERT (!m.is_false (fml)); } @@ -697,7 +697,7 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) } namespace { - class implicant_picker { +class implicant_picker { model_evaluator_util &m_mev; ast_manager &m; arith_util m_arith; @@ -747,37 +747,37 @@ namespace { out.push_back (res); } - void process_app(app *a, expr_ref_vector &out) - { - if (m_visited.is_marked(a)) { return; } + void process_app(app *a, expr_ref_vector &out) + { + if (m_visited.is_marked(a)) { return; } SASSERT (m.is_bool (a)); expr_ref v(m); m_mev.eval (a, v, false); - if (!m.is_true(v) && !m.is_false(v)) { return; } + if (!m.is_true(v) && !m.is_false(v)) { return; } expr *na, *f1, *f2, *f3; if (a->get_family_id() != m.get_basic_family_id()) - { add_literal(a, out); } + { add_literal(a, out); } else if (is_uninterp_const(a)) - { add_literal(a, out); } + { add_literal(a, out); } else if (m.is_not(a, na) && m.is_not(na, na)) - { m_todo.push_back(na); } + { m_todo.push_back(na); } else if (m.is_not(a, na)) - { m_todo.push_back(na); } + { m_todo.push_back(na); } else if (m.is_distinct(a)) { if (m.is_false(v)) m_todo.push_back (qe::project_plugin::pick_equality(m, *m_mev.get_model(), a)); else if (a->get_num_args() == 2) - { add_literal(a, out); } + { add_literal(a, out); } else m_todo.push_back(m.mk_distinct_expanded(a->get_num_args(), a->get_args())); - } else if (m.is_and(a)) { + } else if (m.is_and(a)) { if (m.is_true(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } + { m_todo.append(a->get_num_args(), a->get_args()); } else if (m.is_false(v)) { for (unsigned i = 0, sz = a->get_num_args (); i < sz; ++i) { if (m_mev.is_false(a->get_arg(i))) { @@ -786,9 +786,9 @@ namespace { } } } - } else if (m.is_or(a)) { + } else if (m.is_or(a)) { if (m.is_false(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } + { m_todo.append(a->get_num_args(), a->get_args()); } else if (m.is_true(v)) { for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { if (m_mev.is_true(a->get_arg(i))) { @@ -797,39 +797,39 @@ namespace { } } } - } else if (m.is_iff(a, f1, f2) || m.is_eq(a, f1, f2) || - (m.is_true(v) && m.is_not(a, na) && m.is_xor (na, f1, f2))) { + } else if (m.is_iff(a, f1, f2) || m.is_eq(a, f1, f2) || + (m.is_true(v) && m.is_not(a, na) && m.is_xor (na, f1, f2))) { if (!m.are_equal(f1, f2) && !m.are_distinct(f1, f2)) { if (m.is_bool(f1) && (!is_uninterp_const(f1) || !is_uninterp_const(f2))) - { m_todo.append(a->get_num_args(), a->get_args()); } - else - { add_literal(a, out); } - } - } else if (m.is_ite(a, f1, f2, f3)) { - if (m.are_equal(f2, f3)) { m_todo.push_back(f2); } - else if (m_mev.is_true (f2) && m_mev.is_true (f3)) { - m_todo.push_back(f2); - m_todo.push_back(f3); - } else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { - m_todo.push_back(f2); - m_todo.push_back(f3); - } else if (m_mev.is_true(f1)) { - m_todo.push_back(f1); - m_todo.push_back(f2); - } else if (m_mev.is_false(f1)) { - m_todo.push_back(f1); - m_todo.push_back(f3); - } - } else if (m.is_xor(a, f1, f2)) { m_todo.append(a->get_num_args(), a->get_args()); } + else + { add_literal(a, out); } + } + } else if (m.is_ite(a, f1, f2, f3)) { + if (m.are_equal(f2, f3)) { m_todo.push_back(f2); } + else if (m_mev.is_true (f2) && m_mev.is_true (f3)) { + m_todo.push_back(f2); + m_todo.push_back(f3); + } else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { + m_todo.push_back(f2); + m_todo.push_back(f3); + } else if (m_mev.is_true(f1)) { + m_todo.push_back(f1); + m_todo.push_back(f2); + } else if (m_mev.is_false(f1)) { + m_todo.push_back(f1); + m_todo.push_back(f3); + } + } else if (m.is_xor(a, f1, f2)) + { m_todo.append(a->get_num_args(), a->get_args()); } else if (m.is_implies(a, f1, f2)) { if (m.is_true (v)) { - if (m_mev.is_true(f2)) { m_todo.push_back(f2); } - else if (m_mev.is_false(f1)) { m_todo.push_back(f1); } + if (m_mev.is_true(f2)) { m_todo.push_back(f2); } + else if (m_mev.is_false(f1)) { m_todo.push_back(f1); } } else if (m.is_false(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } - } else if (m.is_true(a) || m.is_false(a)) { /* nothing */ } + { m_todo.append(a->get_num_args(), a->get_args()); } + } else if (m.is_true(a) || m.is_false(a)) { /* nothing */ } else { verbose_stream () << "Unexpected expression: " << mk_pp(a, m) << "\n"; @@ -837,10 +837,10 @@ namespace { } } - void pick_literals(expr *e, expr_ref_vector &out) - { + void pick_literals(expr *e, expr_ref_vector &out) + { SASSERT(m_todo.empty()); - if (m_visited.is_marked(e)) { return; } + if (m_visited.is_marked(e)) { return; } SASSERT(is_app(e)); m_todo.push_back(e); @@ -852,8 +852,8 @@ namespace { } while (!m_todo.empty()); } - bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) - { + bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) + { m_visited.reset(); expr_ref e(m); e = mk_and (in); @@ -861,7 +861,7 @@ namespace { for (unsigned i = 0, sz = in.size (); i < sz; ++i) { if (is_true || m_mev.is_true(in.get(i))) - { pick_literals(in.get(i), out); } + { pick_literals(in.get(i), out); } } m_visited.reset (); @@ -875,7 +875,7 @@ namespace { void operator() (expr_ref_vector &in, expr_ref_vector& out) {pick_implicant (in, out);} }; -} + } void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, expr_ref_vector &res) @@ -1178,9 +1178,9 @@ void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { expr *e1, *e2; if (m_array.is_select (n) && n->get_arg (1) != m_var) { m_res.push_back (n->get_arg (1)); - } else if (m.is_eq(n, e1, e2)) { - if (e1 == m_var) { m_res.push_back(e2); } - else if (e2 == m_var) { m_res.push_back(e1); } + } else if (m.is_eq(n, e1, e2)) { + if (e1 == m_var) { m_res.push_back(e2); } + else if (e2 == m_var) { m_res.push_back(e1); } } } }; @@ -1206,7 +1206,7 @@ void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { tout << i << ": " << mk_pp (terms.get (i), m) << "\n"; ); - for (unsigned i = 0, e = terms.size(); i < e; ++i) { + for (unsigned i = 0, e = terms.size(); i < e; ++i) { expr* term = terms.get (i); expr_ref tval (m); mev.eval (term, tval, false); diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index a6bdbd1dc..f90c32342 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -125,13 +125,13 @@ void project_plugin::push_back(expr_ref_vector& lits, expr* e) { class mbp::impl { - ast_manager& m; + ast_manager& m; params_ref m_params; - th_rewriter m_rw; + th_rewriter m_rw; ptr_vector m_plugins; - expr_mark m_visited; - expr_mark m_bool_visited; - + expr_mark m_visited; + expr_mark m_bool_visited; + // parameters bool m_reduce_all_selects; bool m_native_mbp; @@ -280,33 +280,33 @@ class mbp::impl { } else { vars[j++] = var; + } } - } if (j == vars.size()) { return; } vars.shrink(j); - j = 0; - for (unsigned i = 0; i < fmls.size(); ++i) { + j = 0; + for (unsigned i = 0; i < fmls.size(); ++i) { expr* fml = fmls[i].get(); sub(fml, val); - m_rw(val); - if (!m.is_true(val)) { + m_rw(val); + if (!m.is_true(val)) { TRACE("qe", tout << mk_pp(fml, m) << " -> " << val << "\n";); fmls[j++] = val; - } - } + } + } fmls.shrink(j); - } + } void subst_vars(model_evaluator& eval, app_ref_vector const& vars, expr_ref& fml) { expr_safe_replace sub (m); for (app * v : vars) { sub.insert(v, eval(v)); - } + } sub(fml); - } + } struct index_term_finder { ast_manager& m; @@ -731,7 +731,7 @@ mbp::mbp(ast_manager& m, params_ref const& p) { mbp::~mbp() { dealloc(m_impl); } - + void mbp::updt_params(params_ref const& p) { m_impl->updt_params(p); } From e281f855861dc9f9d653dba91cbac068181d0661 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 May 2018 14:22:00 -0700 Subject: [PATCH 1037/1283] add way to unit test mbp from command line Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 39 +++++ src/qe/qe_arrays.cpp | 185 ++---------------------- src/qe/qe_mbp.cpp | 2 + src/qe/qe_mbp.h | 2 +- 4 files changed, 54 insertions(+), 174 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index fa1d56fe2..1b378f430 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -30,6 +30,7 @@ Notes: #include "ast/used_vars.h" #include "ast/rewriter/var_subst.h" #include "util/gparams.h" +#include "qe/qe_mbp.h" BINARY_SYM_CMD(get_quantifier_body_cmd, @@ -352,6 +353,43 @@ public: void execute(cmd_context & ctx) override { ctx.display_dimacs(); } }; +class mbp_cmd : public cmd { + expr* m_fml; + ptr_vector m_vars; +public: + mbp_cmd():cmd("mbp") {} + char const * get_usage() const override { return ""; } + char const * get_descr(cmd_context & ctx) const override { return "perform model based projection"; } + unsigned get_arity() const override { return 2; } + cmd_arg_kind next_arg_kind(cmd_context& ctx) const override { + if (m_fml == nullptr) return CPK_EXPR; + return CPK_EXPR_LIST; + } + void set_next_arg(cmd_context& ctx, expr * arg) { m_fml = arg; } + void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) override { + m_vars.append(num, ts); + } + void prepare(cmd_context & ctx) override { m_fml = nullptr; } + void execute(cmd_context & ctx) override { + ast_manager& m = ctx.m(); + app_ref_vector vars(m); + model_ref mdl; + if (!ctx.is_model_available(mdl) || !ctx.get_check_sat_result()) { + throw cmd_exception("model is not available"); + } + for (expr* v : m_vars) { + if (!is_uninterp_const(v)) { + throw cmd_exception("invalid variable argument. Uninterpreted variable expected"); + } + vars.push_back(to_app(v)); + } + qe::mbp mbp(m); + expr_ref fml(m_fml, m); + mbp.spacer(vars, *mdl.get(), fml); + ctx.regular_stream() << fml << "\n"; + } +}; + void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(print_dimacs_cmd)); @@ -377,4 +415,5 @@ void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(instantiate_cmd)); ctx.insert(alloc(instantiate_nested_cmd)); ctx.insert(alloc(set_next_id)); + ctx.insert(alloc(mbp_cmd)); } diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 712311f9d..cc3952457 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -631,13 +631,13 @@ namespace qe { m_v = arr_vars.get (i); if (!m_arr_u.is_array (m_v)) { TRACE ("qe", - tout << "not an array variable: " << mk_pp (m_v, m) << "\n"; + tout << "not an array variable: " << m_v << "\n"; ); aux_vars.push_back (m_v); continue; } TRACE ("qe", - tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n"; + tout << "projecting equalities on variable: " << m_v << "\n"; ); if (project (fml)) { @@ -653,8 +653,8 @@ namespace qe { ); } else { - IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";); - TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";); + IF_VERBOSE(2, verbose_stream() << "can't project:" << m_v << "\n";); + TRACE ("qe", tout << "Failed to project: " << m_v << "\n";); arr_vars[j++] = m_v; } } @@ -1196,67 +1196,6 @@ namespace qe { return false; } - bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { - - TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;); - m_var = alloc(contains_app, m, var); - - // reduce select-store redeces based on model. - // rw_cfg rw(m); - // rw(lits); - - // try first to solve for var. - if (solve_eq(model, vars, lits)) { - return true; - } - - app_ref_vector selects(m); - - // check that only non-select occurrences are in disequalities. - if (!check_diseqs(lits, selects)) { - TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";); - return false; - } - - // remove disequalities. - elim_diseqs(lits); - - // Ackerman reduction on remaining select occurrences - // either replace occurrences by model value or other node - // that is congruent to model value. - - ackermanize_select(model, selects, vars, lits); - - TRACE("qe", tout << selects << "\n" << lits << "\n";); - return true; - } - - void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) { - expr_ref_vector vals(m), reps(m); - expr_ref val(m); - expr_safe_replace sub(m); - - if (selects.empty()) { - return; - } - - app_ref sel(m); - for (unsigned i = 0; i < selects.size(); ++i) { - sel = m.mk_fresh_const("sel", m.get_sort(selects[i])); - VERIFY (model.eval(selects[i], val)); - model.register_decl(sel->get_decl(), val); - vals.push_back(to_app(val)); - reps.push_back(val); // TODO: direct pass could handle nested selects. - vars.push_back(sel); - sub.insert(selects[i], val); - } - - sub(lits); - remove_true(lits); - project_plugin::partition_args(model, selects, lits); - project_plugin::partition_values(model, reps, lits); - } - void remove_true(expr_ref_vector& lits) { for (unsigned i = 0; i < lits.size(); ++i) { if (m.is_true(lits[i].get())) { @@ -1275,113 +1214,7 @@ namespace qe { for (unsigned j = 0; j < n; ++j) { lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); } - } - - // check that x occurs only under selects or in disequalities. - bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) { - expr_mark mark; - ptr_vector todo; - app* e; - for (unsigned i = 0; i < lits.size(); ++i) { - e = to_app(lits[i]); - if (is_diseq_x(e)) { - continue; - } - if (contains_x(e)) { - todo.push_back(e); - } - } - while (!todo.empty()) { - e = todo.back(); - todo.pop_back(); - if (mark.is_marked(e)) { - continue; - } - mark.mark(e); - if (m_var->x() == e) { - return false; - } - unsigned start = 0; - if (a.is_select(e)) { - if (e->get_arg(0) == m_var->x()) { - start = 1; - selects.push_back(e); - } - } - for (unsigned i = start; i < e->get_num_args(); ++i) { - todo.push_back(to_app(e->get_arg(i))); - } - } - return true; - } - - void elim_diseqs(expr_ref_vector& lits) { - for (unsigned i = 0; i < lits.size(); ++i) { - if (is_diseq_x(lits[i].get())) { - project_plugin::erase(lits, i); - } - } - } - - bool is_update_x(app* e) { - do { - if (m_var->x() == e) { - return true; - } - if (a.is_store(e) && contains_x(e->get_arg(0))) { - for (unsigned i = 1; i < e->get_num_args(); ++i) { - if (contains_x(e->get_arg(i))) { - return false; - } - } - e = to_app(e->get_arg(0)); - continue; - } - } - while (false); - return false; - } - - bool is_diseq_x(expr* e) { - expr *f, * s, *t; - if (m.is_not(e, f) && m.is_eq(f, s, t)) { - if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true; - if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true; - } - return false; - } - - bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - // find an equality to solve for. - expr* s, *t; - for (unsigned i = 0; i < lits.size(); ++i) { - if (m.is_eq(lits[i].get(), s, t)) { - vector idxs; - expr_ref save(m), back(m); - save = lits[i].get(); - back = lits.back(); - lits[i] = back; - lits.pop_back(); - unsigned sz = lits.size(); - if (contains_x(s) && !contains_x(t) && is_app(s)) { - if (solve(model, to_app(s), t, idxs, vars, lits)) { - return true; - } - } - else if (contains_x(t) && !contains_x(s) && is_app(t)) { - if (solve(model, to_app(t), s, idxs, vars, lits)) { - return true; - } - } - // put back the equality literal. - lits.resize(sz); - lits.push_back(back); - lits[i] = save; - } - // TBD: not distinct? - } - return false; - } + } bool solve(model& model, app* s, expr* t, vector& idxs, app_ref_vector& vars, expr_ref_vector& lits) { SASSERT(contains_x(s)); @@ -1502,7 +1335,13 @@ namespace qe { } bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { - return (*m_imp)(model, var, vars, lits); + ast_manager& m = vars.get_manager(); + app_ref_vector vvars(m, 1, &var); + expr_ref fml = mk_and(lits); + (*this)(model, vvars, fml, vars, false); + lits.reset(); + flatten_and(fml, lits); + return true; } bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index f90c32342..bc9ac8c41 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -99,6 +99,7 @@ void project_plugin::partition_values(model& model, expr_ref_vector const& vals, } } +#if 0 void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) { ast_manager& m = selects.get_manager(); if (selects.empty()) return; @@ -111,6 +112,7 @@ void project_plugin::partition_args(model& model, app_ref_vector const& selects, project_plugin::partition_values(model, args, lits); } } +#endif void project_plugin::erase(expr_ref_vector& lits, unsigned& i) { lits[i] = lits.back(); diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 12b03791a..665e25d48 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -41,7 +41,7 @@ namespace qe { static expr_ref pick_equality(ast_manager& m, model& model, expr* t); static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); - static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); + //static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); static void erase(expr_ref_vector& lits, unsigned& i); static void push_back(expr_ref_vector& lits, expr* lit); static void mark_rec(expr_mark& visited, expr* e); From d95e167d6181ef8eef48cba3f552dd58f2b9287c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 May 2018 16:53:33 -0700 Subject: [PATCH 1038/1283] updates to mbqi Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 2 +- src/qe/qe_arrays.cpp | 34 ++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 1b378f430..ceb979761 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -369,7 +369,7 @@ public: void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) override { m_vars.append(num, ts); } - void prepare(cmd_context & ctx) override { m_fml = nullptr; } + void prepare(cmd_context & ctx) override { m_fml = nullptr; m_vars.reset(); } void execute(cmd_context & ctx) override { ast_manager& m = ctx.m(); app_ref_vector vars(m); diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index cc3952457..f7b8898c1 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -1214,7 +1214,39 @@ namespace qe { for (unsigned j = 0; j < n; ++j) { lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); } - } + } + + bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + // find an equality to solve for. + expr* s, *t; + for (unsigned i = 0; i < lits.size(); ++i) { + if (m.is_eq(lits[i].get(), s, t)) { + vector idxs; + expr_ref save(m), back(m); + save = lits[i].get(); + back = lits.back(); + lits[i] = back; + lits.pop_back(); + unsigned sz = lits.size(); + if (contains_x(s) && !contains_x(t) && is_app(s)) { + if (solve(model, to_app(s), t, idxs, vars, lits)) { + return true; + } + } + else if (contains_x(t) && !contains_x(s) && is_app(t)) { + if (solve(model, to_app(t), s, idxs, vars, lits)) { + return true; + } + } + // put back the equality literal. + lits.resize(sz); + lits.push_back(back); + lits[i] = save; + } + // TBD: not distinct? + } + return false; + } bool solve(model& model, app* s, expr* t, vector& idxs, app_ref_vector& vars, expr_ref_vector& lits) { SASSERT(contains_x(s)); From efb1f50d008be7fbbdf1ea327913c4f0b070f7bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 May 2018 20:11:29 -0700 Subject: [PATCH 1039/1283] bind nested variables Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arith.cpp | 29 ++++++++----------- src/qe/qe_arrays.cpp | 10 +++---- src/qe/qe_mbp.cpp | 68 +++++++------------------------------------- src/qe/qe_mbp.h | 2 -- 4 files changed, 27 insertions(+), 82 deletions(-) diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 969d22a81..f663d1b6c 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -299,20 +299,19 @@ namespace qe { obj_map tids; expr_ref_vector pinned(m); unsigned j = 0; + TRACE("qe", tout << "fmls: " << fmls << "\n";); for (unsigned i = 0; i < fmls.size(); ++i) { - expr* fml = fmls[i].get(); + expr * fml = fmls.get(i); if (!linearize(mbo, eval, fml, fmls, tids)) { - if (i != j) { - fmls[j] = fmls[i].get(); - } - ++j; + fmls[j++] = fml; } else { - TRACE("qe", tout << mk_pp(fml, m) << "\n";); + TRACE("qe", tout << "could not linearize: " << mk_pp(fml, m) << "\n";); pinned.push_back(fml); } } - fmls.resize(j); + fmls.shrink(j); + TRACE("qe", tout << "linearized: " << fmls << "\n";); // fmls holds residue, // mbo holds linear inequalities that are in scope @@ -328,13 +327,13 @@ namespace qe { if (is_arith(v) && !tids.contains(v)) { rational r; expr_ref val = eval(v); - a.is_numeral(val, r); + VERIFY(a.is_numeral(val, r)); TRACE("qe", tout << mk_pp(v, m) << " " << val << "\n";); tids.insert(v, mbo.add_var(r, a.is_int(v))); } } for (expr* fml : fmls) { - fmls_mark.mark(fml); + mark_rec(fmls_mark, fml); } ptr_vector index2expr; for (auto& kv : tids) { @@ -346,8 +345,7 @@ namespace qe { } j = 0; unsigned_vector real_vars; - for (unsigned i = 0; i < vars.size(); ++i) { - app* v = vars[i].get(); + for (app* v : vars) { if (is_arith(v) && !fmls_mark.is_marked(v)) { real_vars.push_back(tids.find(v)); } @@ -355,7 +353,7 @@ namespace qe { vars[j++] = v; } } - vars.resize(j); + vars.shrink(j); TRACE("qe", tout << "remaining vars: " << vars << "\n"; for (unsigned v : real_vars) { tout << "v" << v << " " << mk_pp(index2expr[v], m) << "\n"; @@ -391,8 +389,7 @@ namespace qe { CTRACE("qe", !m.is_true(val), tout << "Evaluated unit " << t << " to " << val << "\n";); continue; } - for (j = 0; j < r.m_vars.size(); ++j) { - var const& v = r.m_vars[j]; + for (var const& v : r.m_vars) { t = index2expr[v.m_id]; if (!v.m_coeff.is_one()) { t = a.mk_mul(a.mk_numeral(v.m_coeff, a.is_int(t)), t); @@ -418,11 +415,9 @@ namespace qe { break; } } - fmls.push_back(t); - + fmls.push_back(t); val = eval(t); CTRACE("qe", !m.is_true(val), tout << "Evaluated " << t << " to " << val << "\n";); - } } diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index f7b8898c1..305fb47b6 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -1390,9 +1390,9 @@ namespace qe { array_project_eqs_util pe (m); pe (mdl, arr_vars, fml, aux_vars); TRACE ("qe", - tout << "Projected array eqs:\n" << fml << "\n"; - tout << "Remaining array vars:\n" << arr_vars; - tout << "Aux vars:\n" << aux_vars; + tout << "Projected array eqs: " << fml << "\n"; + tout << "Remaining array vars: " << arr_vars << "\n"; + tout << "Aux vars: " << aux_vars << "\n"; ); // 2. reduce selects @@ -1406,8 +1406,8 @@ namespace qe { ps (mdl, arr_vars, fml, aux_vars); TRACE ("qe", - tout << "Projected array selects:\n" << fml << "\n"; - tout << "All aux vars:\n" << aux_vars; + tout << "Projected array selects: " << fml << "\n"; + tout << "All aux vars: " << aux_vars << "\n"; ); } diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index bc9ac8c41..b1c92cb8c 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -77,42 +77,6 @@ expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) { return expr_ref(nullptr, m); } -void project_plugin::partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits) { - ast_manager& m = vals.get_manager(); - expr_ref val(m); - expr_ref_vector trail(m), reps(m); - obj_map roots; - for (unsigned i = 0; i < vals.size(); ++i) { - expr* v = vals[i], *root; - VERIFY (model.eval(v, val)); - if (roots.find(val, root)) { - lits.push_back(m.mk_eq(v, root)); - } - else { - roots.insert(val, v); - trail.push_back(val); - reps.push_back(v); - } - } - if (reps.size() > 1) { - lits.push_back(mk_distinct(reps)); - } -} - -#if 0 -void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) { - ast_manager& m = selects.get_manager(); - if (selects.empty()) return; - unsigned num_args = selects[0]->get_decl()->get_arity(); - for (unsigned j = 1; j < num_args; ++j) { - expr_ref_vector args(m); - for (unsigned i = 0; i < selects.size(); ++i) { - args.push_back(selects[i]->get_arg(j)); - } - project_plugin::partition_values(model, args, lits); - } -} -#endif void project_plugin::erase(expr_ref_vector& lits, unsigned& i) { lits[i] = lits.back(); @@ -136,7 +100,6 @@ class mbp::impl { // parameters bool m_reduce_all_selects; - bool m_native_mbp; bool m_dont_sub; void add_plugin(project_plugin* p) { @@ -324,8 +287,7 @@ class mbp::impl { void operator() (app *n) { expr *e1, *e2; if (m_array.is_select (n)) { - for (unsigned i = 1; i < n->get_num_args(); ++i) { - expr * arg = n->get_arg(i); + for (expr * arg : *n) { if (m.get_sort(arg) == m.get_sort(m_var) && arg != m_var) m_res.push_back (arg); } @@ -378,8 +340,7 @@ class mbp::impl { // -- evaluate to initialize eval cache (void) eval (fml); unsigned j = 0; - for (unsigned i = 0; i < vars.size (); ++i) { - app* v = vars.get(i); + for (app * v : vars) { if (!project_var (eval, v, fml)) { vars[j++] = v; } @@ -389,7 +350,6 @@ class mbp::impl { public: - opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { arith_project_plugin arith(m); return arith.maximize(fmls, mdl, t, ge, gt); @@ -530,7 +490,6 @@ public: void updt_params(params_ref const& p) { m_params.append(p); m_reduce_all_selects = m_params.get_bool("reduce_all_selects", false); - m_native_mbp = m_params.get_bool("native_mbp", false); m_dont_sub = m_params.get_bool("dont_sub", false); } @@ -549,6 +508,7 @@ public: bool validate_model(model& model, expr_ref_vector const& fmls) { expr_ref val(m); + model_evaluator eval(model); for (expr * f : fmls) { VERIFY(model.eval(f, val) && m.is_true(val)); } @@ -677,27 +637,20 @@ public: tout << "extended model:\n"; model_pp (tout, mdl); tout << "Auxiliary variables of index and value sorts:\n"; - tout << vars; + tout << vars << "\n"; ); } // project reals and ints if (!arith_vars.empty ()) { - TRACE ("qe", tout << "Arith vars:\n" << arith_vars;); + TRACE ("qe", tout << "Arith vars: " << arith_vars << "\n";); - if (m_native_mbp) { - expr_ref_vector fmls(m); - flatten_and (fml, fmls); - - (*this)(true, arith_vars, mdl, fmls); - fml = mk_and (fmls); - SASSERT (arith_vars.empty ()); - } - else { - NOT_IMPLEMENTED_YET(); - // qe::arith_project (mdl, arith_vars, fml); - } + expr_ref_vector fmls(m); + flatten_and (fml, fmls); + (*this)(true, arith_vars, mdl, fmls); + fml = mk_and (fmls); + TRACE ("qe", tout << "Projected arith vars:\n" << fml << "\n"; tout << "Remaining arith vars:\n" << arith_vars << "\n";); @@ -740,7 +693,6 @@ void mbp::updt_params(params_ref const& p) { void mbp::get_param_descrs(param_descrs & r) { r.insert("reduce_all_selects", CPK_BOOL, "(default: false) reduce selects"); - r.insert("native_mbp", CPK_BOOL, "(default: false) switch between native and spacer tailored mbp"); r.insert("dont_sub", CPK_BOOL, "(default: false) disable substitution of values for free variables"); } diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 665e25d48..25a95e885 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -40,8 +40,6 @@ namespace qe { virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { }; static expr_ref pick_equality(ast_manager& m, model& model, expr* t); - static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); - //static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); static void erase(expr_ref_vector& lits, unsigned& i); static void push_back(expr_ref_vector& lits, expr* lit); static void mark_rec(expr_mark& visited, expr* e); From bf4c35982f35831e67765589d07f28d405de00eb Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 21:28:50 -0700 Subject: [PATCH 1040/1283] Debug print --- src/qe/qe_arrays.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 305fb47b6..4a70d1fcb 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -631,13 +631,13 @@ namespace qe { m_v = arr_vars.get (i); if (!m_arr_u.is_array (m_v)) { TRACE ("qe", - tout << "not an array variable: " << m_v << "\n"; + tout << "not an array variable: " << mk_pp (m_v, m) << "\n"; ); aux_vars.push_back (m_v); continue; } TRACE ("qe", - tout << "projecting equalities on variable: " << m_v << "\n"; + tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n"; ); if (project (fml)) { @@ -653,8 +653,8 @@ namespace qe { ); } else { - IF_VERBOSE(2, verbose_stream() << "can't project:" << m_v << "\n";); - TRACE ("qe", tout << "Failed to project: " << m_v << "\n";); + IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";); + TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";); arr_vars[j++] = m_v; } } From 00f870b7ffd6bd0ea159b57c969e3a950b3cc556 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 21 May 2018 22:01:49 -0700 Subject: [PATCH 1041/1283] to_mbp_benchmark(): prints an mbp problem in benchmark format currently unused. See comment in spacer_util.c:qe_project for example usage --- src/muz/spacer/spacer_util.cpp | 84 +++++++++++++++++++++------------- src/muz/spacer/spacer_util.h | 3 ++ 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 90e0542fa..e2a1a2c3d 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -90,33 +90,33 @@ namespace spacer { if (!m_model) { return; } m_mev = alloc(model_evaluator, *m_model); } - + bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { m_mev->set_model_completion (model_completion); try { m_mev->operator() (e, result); return true; - } + } catch (model_evaluator_exception &ex) { (void)ex; TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); return false; } } - + bool model_evaluator_util::eval(const expr_ref_vector &v, expr_ref& res, bool model_completion) { expr_ref e(m); e = mk_and (v); return eval(e, res, model_completion); } - - + + bool model_evaluator_util::is_true(const expr_ref_vector &v) { expr_ref res(m); return eval (v, res, false) && m.is_true (res); } - + bool model_evaluator_util::is_false(expr *x) { expr_ref res(m); return eval(x, res, false) && m.is_false (res); @@ -126,7 +126,7 @@ namespace spacer { expr_ref res(m); return eval(x, res, false) && m.is_true (res); } - + void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { ast_manager& m = fml.get_manager(); expr_ref_vector conjs(m); @@ -172,16 +172,16 @@ namespace spacer { SASSERT(orig_size <= 1 + conjs.size()); if (i + 1 == orig_size) { // no-op. - } + } else if (orig_size <= conjs.size()) { // no-op - } + } else { SASSERT(orig_size == 1 + conjs.size()); --orig_size; --i; } - } + } else { conjs[i] = tmp; } @@ -199,7 +199,7 @@ namespace spacer { ast_manager& m; public: ite_hoister(ast_manager& m): m(m) {} - + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { if (m.is_ite(f)) { return BR_FAILED; @@ -234,7 +234,7 @@ namespace spacer { } ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} }; - + class ite_hoister_star : public rewriter_tpl { ite_hoister_cfg m_cfg; public: @@ -242,7 +242,7 @@ namespace spacer { rewriter_tpl(m, false, m_cfg), m_cfg(m, p) {} }; - + void hoist_non_bool_if(expr_ref& fml) { ast_manager& m = fml.get_manager(); scoped_no_proof _sp(m); @@ -274,7 +274,7 @@ namespace spacer { bool is_arith_expr(expr *e) const { return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); } - + bool is_offset(expr* e) const { if (a.is_numeral(e)) { return true; @@ -358,7 +358,7 @@ namespace spacer { !a.is_mul(lhs) && !a.is_mul(rhs); } - + bool test_term(expr* e) const { if (m.is_bool(e)) { return true; @@ -403,9 +403,9 @@ namespace spacer { public: test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} - + void test_for_utvpi() { m_test_for_utvpi = true; } - + void operator()(expr* e) { if (!m_is_dl) { return; @@ -422,7 +422,7 @@ namespace spacer { m_is_dl = test_term(a->get_arg(i)); } } - + if (!m_is_dl) { char const* msg = "non-diff: "; if (m_test_for_utvpi) { @@ -431,10 +431,10 @@ namespace spacer { IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); } } - + bool is_dl() const { return m_is_dl; } }; - + bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); expr_fast_mark1 mark; @@ -443,7 +443,7 @@ namespace spacer { } return test.is_dl(); } - + bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); test.test_for_utvpi(); @@ -455,7 +455,7 @@ namespace spacer { } - void subst_vars(ast_manager& m, + void subst_vars(ast_manager& m, app_ref_vector const& vars, model* M, expr_ref& fml) { expr_safe_replace sub (m); @@ -469,6 +469,24 @@ namespace spacer { sub (fml); } +void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) { + ast_manager &m = vars.m(); + ast_pp_util pp(m); + pp.collect(fml); + pp.display_decls(out); + + out << "(define-fun mbp_benchmark_fml () Bool\n "; + out << mk_pp(fml, m) << ")\n\n"; + + out << "(push)\n" + << "(assert mbp_benchmark_fml)\n" + << "(check-sat)\n" + << "(mbp mbp_benchmark_fml ("; + for (auto v : vars) {out << mk_pp(v, m) << " ";} + out << "))\n" + << "(pop)\n" + << "(exit)\n"; +} /* * eliminate simple equalities using qe_lite * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays @@ -488,7 +506,11 @@ namespace spacer { flatten_and (fml, flat); fml = mk_and(flat); } - + + + // uncomment for benchmarks + //to_mbp_benchmark(verbose_stream(), fml, vars); + app_ref_vector arith_vars (m); app_ref_vector array_vars (m); array_util arr_u (m); @@ -501,7 +523,7 @@ namespace spacer { qe_lite qe(m, p, false); qe (vars, fml); rw (fml); - + TRACE ("spacer_mbp", tout << "After qe_lite:\n"; tout << mk_pp (fml, m) << "\n"; @@ -509,7 +531,7 @@ namespace spacer { SASSERT (!m.is_false (fml)); - + // sort out vars into bools, arith (int/real), and arrays for (app* v : vars) { if (m.is_bool (v)) { @@ -523,7 +545,7 @@ namespace spacer { arith_vars.push_back (v); } } - + // substitute Booleans if (!bool_sub.empty()) { bool_sub (fml); @@ -533,13 +555,13 @@ namespace spacer { TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); bool_sub.reset (); } - + TRACE ("spacer_mbp", tout << "Array vars:\n"; tout << array_vars;); - + vars.reset (); - + // project arrays { scoped_no_proof _sp (m); @@ -550,14 +572,14 @@ namespace spacer { srw (fml); SASSERT (!m.is_false (fml)); } - + TRACE ("spacer_mbp", tout << "extended model:\n"; model_pp (tout, *M); tout << "Auxiliary variables of index and value sorts:\n"; tout << vars; ); - + if (vars.empty()) { break; } } diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index dabfa494a..ffbd81de7 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -125,6 +125,9 @@ bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); +void to_mbp_benchmark(std::ostream &out, const expr* fml, + const app_ref_vector &vars); + /** * do the following in sequence * 1. use qe_lite to cheaply eliminate vars From 4e9023b8fe9411fec29939ad426be3b1aedc76a3 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 22 May 2018 08:57:17 -0700 Subject: [PATCH 1042/1283] Remove dead code --- src/muz/spacer/spacer_context.cpp | 29 ----------------------------- src/muz/spacer/spacer_context.h | 2 -- 2 files changed, 31 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index df945d9bb..87c9580e0 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -854,35 +854,6 @@ void pred_transformer::find_predecessors(datalog::rule const& r, ptr_vector >& preds) const -{ - preds.reset(); - obj_map::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); - for (; it != end; it++) { - datalog::rule const& r = *it->m_value; - unsigned tail_sz = r.get_uninterpreted_tail_size(); - for (unsigned ti = 0; ti < tail_sz; ti++) { - preds.push_back(std::make_pair (r.get_tail(ti)->get_decl(), ti)); - } - } -} - - -void pred_transformer::remove_predecessors(expr_ref_vector& literals) -{ - // remove tags - for (unsigned i = 0; i < literals.size(); ) { - expr* l = literals[i].get(); - m.is_not(l, l); - if (m_tag2rule.contains(l)) { - literals[i] = literals.back(); - literals.pop_back(); - } else { - ++i; - } - } -} - void pred_transformer::simplify_formulas() {m_frames.simplify_formulas ();} diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 8de4a70f8..1991aa906 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -370,9 +370,7 @@ public: unsigned level, unsigned oidx, bool must, const ptr_vector **aux); - void remove_predecessors(expr_ref_vector& literals); void find_predecessors(datalog::rule const& r, ptr_vector& predicates) const; - void find_predecessors(vector >& predicates) const; datalog::rule const* find_rule(model &mev, bool& is_concrete, vector& reach_pred_used, unsigned& num_reuse_reach); From 68b7966254aeca8ed7eab70fa40026726389a700 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 22 May 2018 09:05:43 -0700 Subject: [PATCH 1043/1283] Use C++11 --- src/muz/spacer/spacer_context.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 1991aa906..0301df615 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -206,38 +206,37 @@ class pred_transformer { void get_frame_lemmas (unsigned level, expr_ref_vector &out) { - for (unsigned i = 0, sz = m_lemmas.size (); i < sz; ++i) - if(m_lemmas[i]->level() == level) { - out.push_back(m_lemmas[i]->get_expr()); + for (auto &lemma : m_lemmas) { + if (lemma->level() == level) { + out.push_back(lemma->get_expr()); } + } } void get_frame_geq_lemmas (unsigned level, expr_ref_vector &out) { - for (unsigned i = 0, sz = m_lemmas.size (); i < sz; ++i) - if(m_lemmas [i]->level() >= level) { - out.push_back(m_lemmas[i]->get_expr()); + for (auto &lemma : m_lemmas) { + if(lemma->level() >= level) { + out.push_back(lemma->get_expr()); } + } } - unsigned size () const {return m_size;} unsigned lemma_size () const {return m_lemmas.size ();} void add_frame () {m_size++;} void inherit_frames (frames &other) { - for (unsigned i = 0, sz = other.m_lemmas.size (); i < sz; ++i) { - lemma_ref lem = alloc(lemma, m_pt.get_ast_manager(), - other.m_lemmas[i]->get_expr (), - other.m_lemmas[i]->level()); - lem->add_binding(other.m_lemmas[i]->get_bindings()); - add_lemma(lem.get()); + for (auto &other_lemma : other.m_lemmas) { + lemma_ref new_lemma = alloc(lemma, m_pt.get_ast_manager(), + other_lemma->get_expr(), + other_lemma->level()); + new_lemma->add_binding(other_lemma->get_bindings()); + add_lemma(new_lemma.get()); } m_sorted = false; } - bool add_lemma (lemma *lem); + bool add_lemma (lemma *new_lemma); void propagate_to_infinity (unsigned level); bool propagate_to_next_level (unsigned level); - - }; /** From 95d820196b8b03e1bd560e8ebfaeeff49ae9d633 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 22 May 2018 09:34:01 -0700 Subject: [PATCH 1044/1283] Cleanup --- src/muz/spacer/spacer_context.cpp | 30 ++-- src/muz/spacer/spacer_context.h | 242 +++++++++++++----------------- 2 files changed, 118 insertions(+), 154 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 87c9580e0..c38015363 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -658,16 +658,8 @@ pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): m_extend_lit = m.mk_not (m.mk_const (pm.get_n_pred (v->get_decl ()))); } -pred_transformer::~pred_transformer() -{ - rule2inst::iterator it2 = m_rule2inst.begin(), end2 = m_rule2inst.end(); - for (; it2 != end2; ++it2) { - dealloc(it2->m_value); - } - rule2expr::iterator it3 = m_rule2transition.begin(), end3 = m_rule2transition.end(); - for (; it3 != end3; ++it3) { - m.dec_ref(it3->m_value); - } +pred_transformer::~pred_transformer() { + for (auto &entry : m_rule2transition) {m.dec_ref(entry.m_value);} } std::ostream& pred_transformer::display(std::ostream& out) const @@ -1556,20 +1548,19 @@ void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule, // Predicates that are variable representatives. Other predicates at // positions the variables occur are made equivalent with these. expr_ref_vector side(m); - app_ref_vector* var_reprs = alloc(app_ref_vector, m); - SASSERT(var_reprs); + app_ref_vector var_reprs(m); ptr_vector aux_vars; unsigned ut_size = rule.get_uninterpreted_tail_size(); unsigned t_size = rule.get_tail_size(); SASSERT(ut_size <= t_size); - init_atom(pts, rule.get_head(), *var_reprs, side, UINT_MAX); + init_atom(pts, rule.get_head(), var_reprs, side, UINT_MAX); for (unsigned i = 0; i < ut_size; ++i) { if (rule.is_neg_tail(i)) { throw default_exception("SPACER does not support " "negated predicates in rule tails"); } - init_atom(pts, rule.get_tail(i), *var_reprs, side, i); + init_atom(pts, rule.get_tail(i), var_reprs, side, i); } // -- substitute free variables expr_ref fml(m); @@ -1579,12 +1570,12 @@ void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule, {tail.push_back(rule.get_tail(i));} fml = mk_and (tail); - ground_free_vars(fml, *var_reprs, aux_vars, ut_size == 0); - SASSERT(is_all_non_null(*var_reprs)); + ground_free_vars(fml, var_reprs, aux_vars, ut_size == 0); + SASSERT(is_all_non_null(var_reprs)); expr_ref tmp(m); - var_subst (m, false)(fml, var_reprs->size (), - (expr*const*)var_reprs->c_ptr(), tmp); + var_subst(m, false)(fml, var_reprs.size (), + (expr*const*)var_reprs.c_ptr(), tmp); flatten_and (tmp, side); fml = mk_and(side); side.reset (); @@ -1607,12 +1598,11 @@ void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule, m_rule2transition.insert(&rule, fml); } // AG: shouldn't this be under the if-statement above? - m_rule2inst.insert(&rule, var_reprs); m_rule2vars.insert(&rule, aux_vars); TRACE("spacer", tout << rule.get_decl()->get_name() << "\n"; - tout << *var_reprs << "\n";); + tout << var_reprs << "\n";); } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 0301df615..f42309fac 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -266,32 +266,30 @@ class pred_transformer { typedef obj_map rule2expr; typedef obj_map > rule2apps; + typedef obj_map expr2rule; + manager& pm; // spacer::manager + ast_manager& m; // ast_manager + context& ctx; // spacer::context - manager& pm; // spacer-manager - ast_manager& m; // manager - context& ctx; - - func_decl_ref m_head; // predicate - func_decl_ref_vector m_sig; // signature - ptr_vector m_use; // places where 'this' is referenced. - ptr_vector m_rules; // rules used to derive transformer - prop_solver m_solver; // solver context - solver* m_reach_ctx; // context for reachability facts - pobs m_pobs; - frames m_frames; - reach_fact_ref_vector m_reach_facts; // reach facts - /// Number of initial reachability facts - unsigned m_rf_init_sz; - obj_map m_tag2rule; // map tag predicate to rule. + func_decl_ref m_head; // predicate + func_decl_ref_vector m_sig; // signature + ptr_vector m_use; // places where 'this' is referenced. + ptr_vector m_rules; // rules used to derive transformer + prop_solver m_solver; // solver context + solver* m_reach_ctx; // context for reachability facts + pobs m_pobs; // proof obligations created so far + frames m_frames; // frames with lemmas + reach_fact_ref_vector m_reach_facts; // reach facts + unsigned m_rf_init_sz; // number of reach fact from INIT + expr2rule m_tag2rule; // map tag predicate to rule. rule2expr m_rule2tag; // map rule to predicate tag. - rule2inst m_rule2inst; // map rules to instantiations of indices rule2expr m_rule2transition; // map rules to transition rule2apps m_rule2vars; // map rule to auxiliary variables expr_ref m_transition; // transition relation. expr_ref m_initial_state; // initial state. app_ref m_extend_lit; // literal to extend initial state bool m_all_init; // true if the pt has no uninterpreted body in any rule - ptr_vector m_predicates; + ptr_vector m_predicates; // temp vector used with find_predecessors() stats m_stats; stopwatch m_initialize_watch; stopwatch m_must_reachable_watch; @@ -320,7 +318,6 @@ class pred_transformer { void simplify_formulas(tactic& tac, expr_ref_vector& fmls); - // Debugging void add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r); expr* mk_fresh_reach_case_var (); @@ -330,46 +327,46 @@ public: ~pred_transformer(); inline bool use_native_mbp (); - reach_fact *get_reach_fact (expr *v) - { - for (unsigned i = 0, sz = m_reach_facts.size (); i < sz; ++i) - if(v == m_reach_facts [i]->get()) { return m_reach_facts[i]; } - return nullptr; + reach_fact *get_reach_fact (expr *v) { + for (auto *rf : m_reach_facts) { + if (v == rf->get()) {return rf;} } + return nullptr; + } + void find_predecessors(datalog::rule const& r, ptr_vector& predicates) const; - void add_rule(datalog::rule* r) { m_rules.push_back(r); } - void add_use(pred_transformer* pt) { if(!m_use.contains(pt)) { m_use.insert(pt); } } + void add_rule(datalog::rule* r) {m_rules.push_back(r);} + void add_use(pred_transformer* pt) {if(!m_use.contains(pt)) {m_use.insert(pt);}} void initialize(decl2rel const& pts); - func_decl* head() const { return m_head; } - ptr_vector const& rules() const { return m_rules; } - func_decl* sig(unsigned i) const { return m_sig[i]; } // signature - func_decl* const* sig() { return m_sig.c_ptr(); } - unsigned sig_size() const { return m_sig.size(); } - expr* transition() const { return m_transition; } - expr* initial_state() const { return m_initial_state; } - expr* rule2tag(datalog::rule const* r) { return m_rule2tag.find(r); } - unsigned get_num_levels() { return m_frames.size (); } + func_decl* head() const {return m_head;} + ptr_vector const& rules() const {return m_rules;} + func_decl* sig(unsigned i) const {return m_sig[i];} // signature + func_decl* const* sig() {return m_sig.c_ptr();} + unsigned sig_size() const {return m_sig.size();} + expr* transition() const {return m_transition;} + expr* initial_state() const {return m_initial_state;} + expr* rule2tag(datalog::rule const* r) {return m_rule2tag.find(r);} + unsigned get_num_levels() {return m_frames.size ();} expr_ref get_cover_delta(func_decl* p_orig, int level); void add_cover(unsigned level, expr* property); - expr_ref get_reachable (); + expr_ref get_reachable(); std::ostream& display(std::ostream& strm) const; void collect_statistics(statistics& st) const; void reset_statistics(); - bool is_must_reachable (expr* state, model_ref* model = nullptr); + bool is_must_reachable(expr* state, model_ref* model = nullptr); /// \brief Returns reachability fact active in the given model /// all determines whether initial reachability facts are included as well - reach_fact *get_used_reach_fact (model_evaluator_util& mev, bool all = true); + reach_fact *get_used_reach_fact(model_evaluator_util& mev, bool all = true); /// \brief Returns reachability fact active in the origin of the given model - reach_fact* get_used_origin_reach_fact (model_evaluator_util &mev, unsigned oidx); - expr_ref get_origin_summary (model_evaluator_util &mev, - unsigned level, unsigned oidx, bool must, - const ptr_vector **aux); + reach_fact* get_used_origin_reach_fact(model_evaluator_util &mev, unsigned oidx); + expr_ref get_origin_summary(model_evaluator_util &mev, + unsigned level, unsigned oidx, bool must, + const ptr_vector **aux); - void find_predecessors(datalog::rule const& r, ptr_vector& predicates) const; datalog::rule const* find_rule(model &mev, bool& is_concrete, vector& reach_pred_used, unsigned& num_reuse_reach); @@ -409,8 +406,10 @@ public: unsigned& solver_level, expr_ref_vector* core = nullptr); bool is_invariant(unsigned level, expr* lem, - unsigned& solver_level, expr_ref_vector* core = nullptr) - { UNREACHABLE(); return false; } + unsigned& solver_level, expr_ref_vector* core = nullptr) { + // XXX only needed for legacy_frames to compile + UNREACHABLE(); return false; + } bool check_inductive(unsigned level, expr_ref_vector& state, unsigned& assumes_level, unsigned weakness = UINT_MAX); @@ -420,8 +419,8 @@ public: void simplify_formulas(); context& get_context () const {return ctx;} - manager& get_manager() const { return pm; } - ast_manager& get_ast_manager() const { return m; } + manager& get_manager() const {return pm;} + ast_manager& get_ast_manager() const {return m;} void add_premises(decl2rel const& pts, unsigned lvl, expr_ref_vector& r); @@ -546,11 +545,10 @@ public: double get_expand_time(unsigned depth) { return m_expand_watches[depth].get_seconds();} void inc_ref () {++m_ref_count;} - void dec_ref () - { - --m_ref_count; - if(m_ref_count == 0) { dealloc(this); } - } + void dec_ref () { + --m_ref_count; + if(m_ref_count == 0) {dealloc(this);} + } class on_expand_event { @@ -600,16 +598,16 @@ class derivation { const ptr_vector *aux_vars = nullptr); premise (const premise &p); - bool is_must () {return m_must;} - expr * get_summary () {return m_summary.get ();} - app_ref_vector &get_ovars () {return m_ovars;} - unsigned get_oidx () {return m_oidx;} - pred_transformer &pt () {return m_pt;} + bool is_must() {return m_must;} + expr * get_summary() {return m_summary.get ();} + app_ref_vector &get_ovars() {return m_ovars;} + unsigned get_oidx() {return m_oidx;} + pred_transformer &pt() {return m_pt;} /// \brief Updated the summary. /// The new summary is over n-variables. - void set_summary (expr * summary, bool must, - const ptr_vector *aux_vars = nullptr); + void set_summary(expr * summary, bool must, + const ptr_vector *aux_vars = nullptr); }; @@ -630,6 +628,8 @@ class derivation { /// -- create next child using given model as the guide /// -- returns NULL if there is no next child pob* create_next_child (model_evaluator_util &mev); + /// existentially quantify vars and skolemize the result + void exist_skolemize(expr *fml, app_ref_vector &vars, expr_ref &res); public: derivation (pob& parent, datalog::rule const& rule, expr *trans, app_ref_vector const &evars); @@ -645,8 +645,6 @@ public: /// premise must be consistent with the transition relation pob *create_next_child (); - /// existentially quantify vars and skolemize the result - void exist_skolemize(expr *fml, app_ref_vector &vars, expr_ref &res); datalog::rule const& get_rule () const { return m_rule; } pob& get_parent () const { return m_parent; } ast_manager &get_ast_manager () const {return m_parent.get_ast_manager ();} @@ -672,22 +670,20 @@ public: void pop () {m_obligations.pop ();} void push (pob &n); - void inc_level () - { - SASSERT (!m_obligations.empty () || m_root); - m_max_level++; - m_min_depth++; - if(m_root && m_obligations.empty()) { m_obligations.push(m_root); } - } + void inc_level () { + SASSERT (!m_obligations.empty () || m_root); + m_max_level++; + m_min_depth++; + if(m_root && m_obligations.empty()) { m_obligations.push(m_root); } + } - pob& get_root() const { return *m_root.get (); } + pob& get_root() const {return *m_root.get ();} void set_root(pob& n); bool is_root (pob& n) const {return m_root.get () == &n;} - unsigned max_level () {return m_max_level;} - unsigned min_depth () {return m_min_depth;} - size_t size () {return m_obligations.size ();} - + unsigned max_level() {return m_max_level;} + unsigned min_depth() {return m_min_depth;} + size_t size() {return m_obligations.size();} }; @@ -788,21 +784,23 @@ class context { json_marshaller m_json_marshaller; // Functions used by search. - lbool solve_core (unsigned from_lvl = 0); + lbool solve_core(unsigned from_lvl = 0); bool is_requeue(pob &n); - bool check_reachability (); + bool check_reachability(); bool propagate(unsigned min_prop_lvl, unsigned max_prop_lvl, unsigned full_prop_lvl); bool is_reachable(pob &n); lbool expand_pob(pob &n, pob_ref_buffer &out); - reach_fact *mk_reach_fact (pob& n, model_evaluator_util &mev, - datalog::rule const& r); - bool create_children(pob& n, datalog::rule const& r, - model_evaluator_util &model, + reach_fact *mk_reach_fact(pob& n, model_evaluator_util &mev, + datalog::rule const& r); + bool create_children(pob& n, const datalog::rule &r, + model_evaluator_util &mdl, const vector& reach_pred_used, pob_ref_buffer &out); + expr_ref mk_sat_answer(); expr_ref mk_unsat_answer() const; + unsigned get_cex_depth (); // Generate inductive property void get_level_property(unsigned lvl, expr_ref_vector& res, @@ -811,27 +809,21 @@ class context { // Initialization void init_lemma_generalizers(); + void reset_lemma_generalizers(); void inherit_lemmas(const decl2rel& rels); void init_global_smt_params(); + void init_rules(datalog::rule_set& rules, decl2rel& transformers); + // (re)initialize context with new relations + void init(const decl2rel &rels); + bool validate(); bool check_invariant(unsigned lvl); bool check_invariant(unsigned lvl, func_decl* fn); void checkpoint(); - void init_rules(datalog::rule_set& rules, decl2rel& transformers); - - // (re)initialize context with new relations - void init(const decl2rel &rels); - void simplify_formulas(); - void reset_lemma_generalizers(); - - bool validate(); - - unsigned get_cex_depth (); - void dump_json(); void predecessor_eh(); @@ -839,86 +831,68 @@ class context { public: /** Initial values of predicates are stored in corresponding relations in dctx. - We check whether there is some reachable state of the relation checked_relation. */ - context( - fixedpoint_params const& params, - ast_manager& m); - + context(fixedpoint_params const& params, ast_manager& m); ~context(); - fixedpoint_params const& get_params() const { return m_params; } + const fixedpoint_params &get_params() const { return m_params; } bool use_native_mbp () {return m_use_native_mbp;} bool use_ground_cti () {return m_ground_cti;} - bool use_instantiate () { return m_instantiate; } + bool use_instantiate () {return m_instantiate;} bool weak_abs() {return m_weak_abs;} - bool use_qlemmas () {return m_use_qlemmas; } + bool use_qlemmas () {return m_use_qlemmas;} + + ast_manager& get_ast_manager() const {return m;} + manager& get_manager() {return m_pm;} + decl2rel const& get_pred_transformers() const {return m_rels;} + pred_transformer& get_pred_transformer(func_decl* p) const {return *m_rels.find(p);} + + datalog::context& get_datalog_context() const { + SASSERT(m_context); return *m_context; + } + + void update_rules(datalog::rule_set& rules); + lbool solve(unsigned from_lvl = 0); + lbool solve_from_lvl (unsigned from_lvl); + - ast_manager& get_ast_manager() const { return m; } - manager& get_manager() { return m_pm; } - decl2rel const& get_pred_transformers() const { return m_rels; } - pred_transformer& get_pred_transformer(func_decl* p) const - { return *m_rels.find(p); } - datalog::context& get_datalog_context() const - { SASSERT(m_context); return *m_context; } expr_ref get_answer(); /** * get bottom-up (from query) sequence of ground predicate instances * (for e.g. P(0,1,0,0,3)) that together form a ground derivation to query */ expr_ref get_ground_sat_answer (); + void get_rules_along_trace (datalog::rule_ref_vector& rules); void collect_statistics(statistics& st) const; void reset_statistics(); - - std::ostream& display(std::ostream& strm) const; - - void display_certificate(std::ostream& strm) const {} - - lbool solve(unsigned from_lvl = 0); - - lbool solve_from_lvl (unsigned from_lvl); - void reset(); - void set_query(func_decl* q) { m_query_pred = q; } - - void set_unsat() { m_last_result = l_false; } - - void set_model_converter(model_converter_ref& mc) { m_mc = mc; } - - void get_rules_along_trace (datalog::rule_ref_vector& rules); + std::ostream& display(std::ostream& out) const; + void display_certificate(std::ostream& out) const {NOT_IMPLEMENTED_YET();} + pob& get_root() const {return m_pob_queue.get_root();} + void set_query(func_decl* q) {m_query_pred = q;} + void set_unsat() {m_last_result = l_false;} + void set_model_converter(model_converter_ref& mc) {m_mc = mc;} model_converter_ref get_model_converter() { return m_mc; } - void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } - - void update_rules(datalog::rule_set& rules); + scoped_ptr_vector &callbacks() {return m_callbacks;} unsigned get_num_levels(func_decl* p); expr_ref get_cover_delta(int level, func_decl* p_orig, func_decl* p); - void add_cover(int level, func_decl* pred, expr* property); - expr_ref get_reachable (func_decl* p); - void add_invariant (func_decl *pred, expr* property); - model_ref get_model(); - proof_ref get_proof() const; - pob& get_root() const { return m_pob_queue.get_root(); } - expr_ref get_constraints (unsigned lvl); void add_constraint (expr *c, unsigned lvl); void new_lemma_eh(pred_transformer &pt, lemma *lem); - - scoped_ptr_vector &callbacks() {return m_callbacks;} - void new_pob_eh(pob *p); bool is_inductive(); From 55126692c90920870dc672258cb3c1cc7f36c7a6 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 22 May 2018 14:45:05 -0700 Subject: [PATCH 1045/1283] spacer: counterexample to pushing (ctp) Enable using fixedpoint.spacer.ctp=true For each lemma L currently at level k, keep a model M that justifies why L cannot be pushed to (k+1). L is not pushed while the model M remains valid. --- src/muz/base/fixedpoint_params.pyg | 3 +- src/muz/spacer/spacer_context.cpp | 152 +++++++++++++++++++---------- src/muz/spacer/spacer_context.h | 30 ++++-- 3 files changed, 123 insertions(+), 62 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 799e06fe6..10e319786 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -200,5 +200,6 @@ def_module_params('fixedpoint', ('spacer.p3.share_lemmas', BOOL, False, 'Share frame lemmas'), ('spacer.p3.share_invariants', BOOL, False, "Share invariants lemmas"), ('spacer.from_level', UINT, 0, 'starting level to explore'), - ('spacer.print_json', SYMBOL, '', 'print pobs tree in JSON format to a given file') + ('spacer.print_json', SYMBOL, '', 'print pobs tree in JSON format to a given file'), + ('spacer.ctp', BOOL, False, 'enable counterexample-to-pushing technique'), )) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index c38015363..7602c29b2 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -443,7 +443,7 @@ lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : m_ref_count(0), m(manager), m_body(body, m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(lvl), - m_pob(nullptr), m_external(false) { + m_pob(nullptr), m_ctp(nullptr), m_external(false) { SASSERT(m_body); normalize(m_body, m_body); } @@ -452,7 +452,7 @@ lemma::lemma(pob_ref const &p) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(p->level()), - m_pob(p), m_external(false) { + m_pob(p), m_ctp(nullptr), m_external(false) { SASSERT(m_pob); m_pob->get_skolems(m_zks); add_binding(m_pob->get_binding()); @@ -463,7 +463,7 @@ lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : m(p->get_ast_manager()), m_body(m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(p->level()), - m_pob(p), m_external(false) + m_pob(p), m_ctp(nullptr), m_external(false) { if (m_pob) { m_pob->get_skolems(m_zks); @@ -687,11 +687,15 @@ void pred_transformer::collect_statistics(statistics& st) const // -- number of proof obligations (0 if pobs are not reused) st.update("SPACER num pobs", m_pobs.size()); + st.update("SPACER num ctp", m_stats.m_num_ctp); + st.update("SPACER num is_invariant", m_stats.m_num_is_invariant); + // -- time in rule initialization st.update ("time.spacer.init_rules.pt.init", m_initialize_watch.get_seconds ()); // -- time is must_reachable() st.update ("time.spacer.solve.pt.must_reachable", m_must_reachable_watch.get_seconds ()); + st.update("time.spacer.ctp", m_ctp_watch.get_seconds()); } void pred_transformer::reset_statistics() @@ -701,6 +705,7 @@ void pred_transformer::reset_statistics() m_stats.reset(); m_initialize_watch.reset (); m_must_reachable_watch.reset (); + m_ctp_watch.reset(); } void pred_transformer::init_sig() @@ -781,20 +786,31 @@ reach_fact *pred_transformer::get_used_origin_reach_fact (model_evaluator_util& return res; } -datalog::rule const* pred_transformer::find_rule(model &model, +const datalog::rule *pred_transformer::find_rule(model &model) { + expr_ref val(m); + + for (auto &entry : m_tag2rule) { + app *tag = to_app(entry.m_key); + if (model.eval(tag->get_decl(), val) && m.is_true(val)) { + return entry.m_value; + } + } + return nullptr; +} + +const datalog::rule *pred_transformer::find_rule(model &model, bool& is_concrete, vector& reach_pred_used, unsigned& num_reuse_reach) { - typedef obj_map tag2rule; TRACE ("spacer_verbose", datalog::rule_manager& rm = ctx.get_datalog_context().get_rule_manager(); - tag2rule::iterator it = m_tag2rule.begin(); - tag2rule::iterator end = m_tag2rule.end(); - for (; it != end; ++it) { - expr* pred = it->m_key; + for (auto &entry : m_tag2rule) { + expr* pred = entry.m_key; tout << mk_pp(pred, m) << ":\n"; - if (it->m_value) { rm.display_smt2(*(it->m_value), tout) << "\n"; } + if (entry.m_value) { + rm.display_smt2(*(entry.m_value), tout) << "\n"; + } } ); @@ -802,33 +818,32 @@ datalog::rule const* pred_transformer::find_rule(model &model, // prefer a rule where the model intersects with reach facts of all predecessors; // also find how many predecessors' reach facts are true in the model expr_ref vl(m); - datalog::rule const* r = ((datalog::rule*)nullptr); - tag2rule::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); - for (; it != end; ++it) { - expr* tag = it->m_key; + const datalog::rule *r = ((datalog::rule*)nullptr); + for (auto &entry : m_tag2rule) { + expr* tag = entry.m_key; if (model.eval(to_app(tag)->get_decl(), vl) && m.is_true(vl)) { - r = it->m_value; + r = entry.m_value; is_concrete = true; num_reuse_reach = 0; - reach_pred_used.reset (); - unsigned tail_sz = r->get_uninterpreted_tail_size (); + reach_pred_used.reset(); + unsigned tail_sz = r->get_uninterpreted_tail_size(); for (unsigned i = 0; i < tail_sz; i++) { bool used = false; func_decl* d = r->get_tail(i)->get_decl(); - pred_transformer const& pt = ctx.get_pred_transformer (d); - if (!pt.has_reach_facts()) { is_concrete = false; } + const pred_transformer &pt = ctx.get_pred_transformer(d); + if (!pt.has_reach_facts()) {is_concrete = false;} else { expr_ref v(m); - pm.formula_n2o (pt.get_last_reach_case_var (), v, i); - model.eval (to_app (v.get ())->get_decl (), vl); + pm.formula_n2o(pt.get_last_reach_case_var (), v, i); + model.eval(to_app (v.get ())->get_decl (), vl); used = m.is_false (vl); is_concrete = is_concrete && used; } reach_pred_used.push_back (used); - if (used) { num_reuse_reach++; } + if (used) {num_reuse_reach++;} } - if (is_concrete) { break; } + if (is_concrete) {break;} } } // SASSERT (r); @@ -1268,30 +1283,21 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, post.push_back (n.post ()); // populate reach_assumps - - // XXX eager_reach_check must always be - // XXX enabled. Otherwise, we can get into an infinite loop in - // XXX which a model is consistent with a must-summary, but the - // XXX appropriate assumption is not set correctly by the model. - // XXX Original code handled reachability-events differently. - if (/* ctx.get_params ().eager_reach_check () && */ - n.level () > 0 && !m_all_init) { - obj_map::iterator it = m_tag2rule.begin (), - end = m_tag2rule.end (); - for (; it != end; ++it) { - datalog::rule const* r = it->m_value; - if (!r) { continue; } + if (n.level () > 0 && !m_all_init) { + for (auto &entry : m_tag2rule) { + datalog::rule const* r = entry.m_value; + if (!r) {continue;} find_predecessors(*r, m_predicates); - if (m_predicates.empty()) { continue; } + if (m_predicates.empty()) {continue;} for (unsigned i = 0; i < m_predicates.size(); i++) { const pred_transformer &pt = - ctx.get_pred_transformer (m_predicates [i]); + ctx.get_pred_transformer(m_predicates[i]); if (pt.has_reach_facts()) { expr_ref a(m); - pm.formula_n2o (pt.get_last_reach_case_var (), a, i); - reach_assumps.push_back (m.mk_not (a)); + pm.formula_n2o(pt.get_last_reach_case_var (), a, i); + reach_assumps.push_back(m.mk_not (a)); } else if (ctx.get_params().spacer_init_reach_facts()) { - reach_assumps.push_back (m.mk_not (it->m_key)); + reach_assumps.push_back(m.mk_not (entry.m_key)); break; } } @@ -1325,7 +1331,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, if (is_sat == l_true || is_sat == l_undef) { if (core) { core->reset(); } if (model) { - r = find_rule (**model, is_concrete, reach_pred_used, num_reuse_reach); + r = find_rule(**model, is_concrete, reach_pred_used, num_reuse_reach); TRACE ("spacer", tout << "reachable " << "is_concrete " << is_concrete << " rused: "; for (unsigned i = 0, sz = reach_pred_used.size (); i < sz; ++i) @@ -1352,11 +1358,47 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, return l_undef; } +/// returns true if lemma is blocked by an existing model +bool pred_transformer::is_ctp_blocked(lemma *lem) { + if (!ctx.get_params().spacer_ctp()) {return false;} + + if (!lem->has_ctp()) {return false;} + scoped_watch _t_(m_ctp_watch); + + model_ref &ctp = lem->get_ctp(); + + // -- find rule of the ctp + const datalog::rule *r; + r = find_rule(*ctp); + if (r == nullptr) {return false;} + + // -- find predicates along the rule + find_predecessors(*r, m_predicates); + + // check if any lemmas block the model + for (unsigned i = 0, sz = m_predicates.size(); i < sz; ++i) { + pred_transformer &pt = ctx.get_pred_transformer(m_predicates[i]); + expr_ref lemmas(m), val(m); + lemmas = pt.get_formulas(lem->level(), false); + pm.formula_n2o(lemmas.get(), lemmas, i); + if (ctp->eval(lemmas, val) && m.is_false(val)) {return true;} + } + + return false; +} + bool pred_transformer::is_invariant(unsigned level, lemma* lem, - unsigned& solver_level, expr_ref_vector* core) + unsigned& solver_level, + expr_ref_vector* core) { - expr_ref lemma(m); - lemma = lem->get_expr(); + m_stats.m_num_is_invariant++; + if (is_ctp_blocked(lem)) { + m_stats.m_num_ctp++; + return false; + } + + expr_ref lemma_expr(m); + lemma_expr = lem->get_expr(); expr_ref_vector conj(m), aux(m); expr_ref gnd_lemma(m); @@ -1364,28 +1406,36 @@ bool pred_transformer::is_invariant(unsigned level, lemma* lem, if (!get_context().use_qlemmas() && !lem->is_ground()) { app_ref_vector tmp(m); - ground_expr(to_quantifier(lemma)->get_expr (), gnd_lemma, tmp); - lemma = gnd_lemma.get(); + ground_expr(to_quantifier(lemma_expr)->get_expr (), gnd_lemma, tmp); + lemma_expr = gnd_lemma.get(); } - conj.push_back(mk_not(m, lemma)); + conj.push_back(mk_not(m, lemma_expr)); flatten_and (conj); prop_solver::scoped_level _sl(m_solver, level); prop_solver::scoped_subset_core _sc (m_solver, true); prop_solver::scoped_weakness _sw (m_solver, 1, ctx.weak_abs() ? lem->weakness() : UINT_MAX); + model_ref mdl; m_solver.set_core(core); - m_solver.set_model(nullptr); + m_solver.set_model(&mdl); expr * bg = m_extend_lit.get (); lbool r = m_solver.check_assumptions (conj, aux, 1, &bg, 1); if (r == l_false) { solver_level = m_solver.uses_level (); + lem->reset_ctp(); CTRACE ("spacer", level < m_solver.uses_level (), tout << "Checking at level " << level << " but only using " << m_solver.uses_level () << "\n";); SASSERT (level <= solver_level); } + else if (r == l_true) { + // optionally remove unused symbols from the model + lem->set_ctp(mdl); + } + else {lem->reset_ctp();} + return r == l_false; } @@ -1795,9 +1845,7 @@ bool pred_transformer::frames::propagate_to_next_level (unsigned level) m_pt.ensure_level (tgt_level); for (unsigned i = 0, sz = m_lemmas.size(); i < sz && m_lemmas [i]->level() <= level;) { - if (m_lemmas [i]->level () < level) - {++i; continue;} - + if (m_lemmas [i]->level () < level) {++i; continue;} unsigned solver_level; if (m_pt.is_invariant(tgt_level, m_lemmas.get(i), solver_level)) { diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index f42309fac..5cdc66ad1 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -116,6 +116,7 @@ class lemma { app_ref_vector m_bindings; unsigned m_lvl; pob_ref m_pob; + model_ref m_ctp; // counter-example to pushing bool m_external; void mk_expr_core(); @@ -127,6 +128,12 @@ public: // lemma(const lemma &other) = delete; ast_manager &get_ast_manager() {return m;} + + model_ref& get_ctp() {return m_ctp;} + bool has_ctp() {return !is_inductive() && m_ctp;} + void set_ctp(model_ref &v) {m_ctp = v;} + void reset_ctp() {m_ctp.reset();} + expr *get_expr(); bool is_false(); expr_ref_vector const &get_cube(); @@ -141,6 +148,7 @@ public: inline void set_external(bool ext){m_external = ext;} inline bool external() { return m_external;} + bool is_inductive() const {return is_infty_level(m_lvl);} unsigned level () const {return m_lvl;} void set_level (unsigned lvl); app_ref_vector& get_bindings() {return m_bindings;} @@ -151,12 +159,11 @@ public: bool is_ground () {return !is_quantifier (get_expr());} void inc_ref () {++m_ref_count;} - void dec_ref () - { - SASSERT (m_ref_count > 0); - --m_ref_count; - if(m_ref_count == 0) { dealloc(this); } - } + void dec_ref () { + SASSERT (m_ref_count > 0); + --m_ref_count; + if(m_ref_count == 0) {dealloc(this);} + } }; struct lemma_lt_proc : public std::binary_function { @@ -180,6 +187,8 @@ class pred_transformer { struct stats { unsigned m_num_propagations; unsigned m_num_invariants; + unsigned m_num_ctp; + unsigned m_num_is_invariant; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -293,7 +302,7 @@ class pred_transformer { stats m_stats; stopwatch m_initialize_watch; stopwatch m_must_reachable_watch; - + stopwatch m_ctp_watch; /// Auxiliary variables to represent different disjunctive @@ -367,7 +376,9 @@ public: unsigned level, unsigned oidx, bool must, const ptr_vector **aux); - datalog::rule const* find_rule(model &mev, bool& is_concrete, + bool is_ctp_blocked(lemma *lem); + const datalog::rule *find_rule(model &mdl); + const datalog::rule *find_rule(model &mev, bool& is_concrete, vector& reach_pred_used, unsigned& num_reuse_reach); expr* get_transition(datalog::rule const& r) { return m_rule2transition.find(&r); } @@ -403,7 +414,8 @@ public: vector& reach_pred_used, unsigned& num_reuse_reach); bool is_invariant(unsigned level, lemma* lem, - unsigned& solver_level, expr_ref_vector* core = nullptr); + unsigned& solver_level, + expr_ref_vector* core = nullptr); bool is_invariant(unsigned level, expr* lem, unsigned& solver_level, expr_ref_vector* core = nullptr) { From 40781c0b0c6fe265df8930ce782aaff5a33d697e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 22 May 2018 14:48:11 -0700 Subject: [PATCH 1046/1283] Comment on params used in spacer_context --- src/muz/spacer/spacer_context.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 7602c29b2..ed4947052 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2301,16 +2301,15 @@ void context::init_global_smt_params() { fparams.m_mbqi = m_params.spacer_mbqi(); if (!m_params.spacer_ground_cti()) { - fparams.m_pi_use_database = true; + fparams.m_pi_use_database = true; // you don't need this fparams.m_phase_selection = PS_CACHING_CONSERVATIVE2; fparams.m_restart_strategy = RS_GEOMETRIC; fparams.m_restart_factor = 1.5; fparams.m_eliminate_bounds = true; - fparams.m_qi_quick_checker = MC_UNSAT; - fparams.m_propagate_booleans = true; + fparams.m_qi_quick_checker = MC_UNSAT; // fparams.m_qi_eager_threshold = 10; fparams.m_qi_lazy_threshold = 20; - fparams.m_ng_lift_ite = LI_FULL; + fparams.m_ng_lift_ite = LI_FULL; // ? probably useless } } From 477ac4a19af43237a1c1cbb2036c97ef86d4809a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 22 May 2018 14:49:21 -0700 Subject: [PATCH 1047/1283] Remove dead m_propagate_booleans param --- src/smt/params/preprocessor_params.cpp | 1 - src/smt/params/preprocessor_params.h | 2 -- src/smt/smt_setup.cpp | 3 --- 3 files changed, 6 deletions(-) diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index ee4b7c2e4..3e1c6f0cd 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -46,7 +46,6 @@ void preprocessor_params::display(std::ostream & out) const { DISPLAY_PARAM(m_eliminate_term_ite); DISPLAY_PARAM(m_macro_finder); DISPLAY_PARAM(m_propagate_values); - DISPLAY_PARAM(m_propagate_booleans); DISPLAY_PARAM(m_refine_inj_axiom); DISPLAY_PARAM(m_eliminate_bounds); DISPLAY_PARAM(m_simplify_bit2int); diff --git a/src/smt/params/preprocessor_params.h b/src/smt/params/preprocessor_params.h index be7fd4c01..f6724fada 100644 --- a/src/smt/params/preprocessor_params.h +++ b/src/smt/params/preprocessor_params.h @@ -37,7 +37,6 @@ struct preprocessor_params : public pattern_inference_params, bool m_eliminate_term_ite; bool m_macro_finder; bool m_propagate_values; - bool m_propagate_booleans; bool m_refine_inj_axiom; bool m_eliminate_bounds; bool m_simplify_bit2int; @@ -59,7 +58,6 @@ public: m_eliminate_term_ite(false), m_macro_finder(false), m_propagate_values(true), - m_propagate_booleans(false), // TODO << check peformance m_refine_inj_axiom(true), m_eliminate_bounds(false), m_simplify_bit2int(false), diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 55ea55663..3ab40cdc3 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -574,7 +574,6 @@ namespace smt { m_params.m_bv_cc = false; m_params.m_bb_ext_gates = true; m_params.m_nnf_cnf = false; - m_params.m_propagate_booleans = true; m_context.register_plugin(alloc(smt::theory_bv, m_manager, m_params, m_params)); setup_arrays(); } @@ -644,7 +643,6 @@ namespace smt { m_params.m_restart_factor = 1.5; m_params.m_eliminate_bounds = true; m_params.m_qi_quick_checker = MC_UNSAT; - m_params.m_propagate_booleans = true; m_params.m_qi_lazy_threshold = 20; // m_params.m_qi_max_eager_multipatterns = 10; /// <<< HACK m_params.m_mbqi = true; // enabling MBQI and MACRO_FINDER by default :-) @@ -672,7 +670,6 @@ namespace smt { m_params.m_phase_selection = PS_ALWAYS_FALSE; m_params.m_eliminate_bounds = true; m_params.m_qi_quick_checker = MC_UNSAT; - m_params.m_propagate_booleans = true; m_params.m_qi_eager_threshold = 5; // Added for MBQI release m_params.m_qi_lazy_threshold = 20; From 1da002d7b1e6ced16e9871744c29b2f934f2f9b0 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 22 May 2018 14:49:52 -0700 Subject: [PATCH 1048/1283] scoped params on solver solver::push_params() saves current parameters solver::pop_params() restores previously saved parameters --- src/smt/smt_solver.cpp | 14 ++++++++++++++ src/solver/solver.cpp | 6 ++++++ src/solver/solver.h | 16 ++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index d282a59da..0bef90a48 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -118,6 +118,20 @@ namespace smt { m_core_extend_nonlocal_patterns = smth.core_extend_nonlocal_patterns(); } + params_ref m_params_save; + smt_params m_smt_params_save; + + void push_params() override { + m_params_save.reset(); + m_params_save.copy(solver::get_params()); + m_smt_params_save = m_smt_params; + } + + void pop_params() override { + m_smt_params = m_smt_params_save; + solver::reset_params(m_params_save); + } + void collect_param_descrs(param_descrs & r) override { m_context.collect_param_descrs(r); } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 4b812f83b..cc1d472ca 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -206,6 +206,12 @@ void solver::collect_param_descrs(param_descrs & r) { r.insert("solver.enforce_model_conversion", CPK_BOOL, "(default: false) enforce model conversion when asserting formulas"); } +void solver::reset_params(params_ref const & p) { + m_params.reset(); + m_params.copy(p); + m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); +} + void solver::updt_params(params_ref const & p) { m_params.copy(p); m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); diff --git a/src/solver/solver.h b/src/solver/solver.h index bb330636f..4c0c361ff 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -60,6 +60,11 @@ public: */ virtual void updt_params(params_ref const & p); + /** + \brief reset parameters. + */ + virtual void reset_params(params_ref const& p); + /** \brief Retrieve set of parameters set on solver. */ @@ -70,6 +75,17 @@ public: parameters available in this solver. */ virtual void collect_param_descrs(param_descrs & r); + + /** + \brief Push a parameter state. It is restored upon pop. + Only a single scope of push is supported. + */ + virtual void push_params() {} + + /** + \brief Pop a parameter state. \sa push_params. + */ + virtual void pop_params() {} /** \brief Enable/Disable model generation for this solver object. From 9c37bef55305cd46cd619ae6976f7c75b143137c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 23 May 2018 11:04:34 -0700 Subject: [PATCH 1049/1283] Fix bug in ctp --- src/muz/spacer/spacer_context.cpp | 23 +++++++++++++---------- src/muz/spacer/spacer_context.h | 9 +++++---- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index ed4947052..945f6686e 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -687,8 +687,9 @@ void pred_transformer::collect_statistics(statistics& st) const // -- number of proof obligations (0 if pobs are not reused) st.update("SPACER num pobs", m_pobs.size()); - st.update("SPACER num ctp", m_stats.m_num_ctp); + st.update("SPACER num ctp blocked", m_stats.m_num_ctp_blocked); st.update("SPACER num is_invariant", m_stats.m_num_is_invariant); + st.update("SPACER num lemma jumped", m_stats.m_num_lemma_level_jump); // -- time in rule initialization st.update ("time.spacer.init_rules.pt.init", m_initialize_watch.get_seconds ()); @@ -1375,16 +1376,18 @@ bool pred_transformer::is_ctp_blocked(lemma *lem) { // -- find predicates along the rule find_predecessors(*r, m_predicates); - // check if any lemmas block the model + // check if any lemma blocks the ctp model for (unsigned i = 0, sz = m_predicates.size(); i < sz; ++i) { pred_transformer &pt = ctx.get_pred_transformer(m_predicates[i]); expr_ref lemmas(m), val(m); lemmas = pt.get_formulas(lem->level(), false); pm.formula_n2o(lemmas.get(), lemmas, i); - if (ctp->eval(lemmas, val) && m.is_false(val)) {return true;} + if (ctp->eval(lemmas, val) && m.is_false(val)) {return false;} } - return false; + // lem is blocked by ctp since none of the lemmas at the previous + // level block ctp + return true; } bool pred_transformer::is_invariant(unsigned level, lemma* lem, @@ -1393,7 +1396,7 @@ bool pred_transformer::is_invariant(unsigned level, lemma* lem, { m_stats.m_num_is_invariant++; if (is_ctp_blocked(lem)) { - m_stats.m_num_ctp++; + m_stats.m_num_ctp_blocked++; return false; } @@ -1418,21 +1421,21 @@ bool pred_transformer::is_invariant(unsigned level, lemma* lem, prop_solver::scoped_weakness _sw (m_solver, 1, ctx.weak_abs() ? lem->weakness() : UINT_MAX); model_ref mdl; + model_ref *mdl_ref_ptr = nullptr; + if (ctx.get_params().spacer_ctp()) {mdl_ref_ptr = &mdl;} m_solver.set_core(core); - m_solver.set_model(&mdl); + m_solver.set_model(mdl_ref_ptr); expr * bg = m_extend_lit.get (); lbool r = m_solver.check_assumptions (conj, aux, 1, &bg, 1); if (r == l_false) { solver_level = m_solver.uses_level (); lem->reset_ctp(); - CTRACE ("spacer", level < m_solver.uses_level (), - tout << "Checking at level " << level - << " but only using " << m_solver.uses_level () << "\n";); + if (level < m_solver.uses_level()) {m_stats.m_num_lemma_level_jump++;} SASSERT (level <= solver_level); } else if (r == l_true) { // optionally remove unused symbols from the model - lem->set_ctp(mdl); + if (mdl_ref_ptr) {lem->set_ctp(*mdl_ref_ptr);} } else {lem->reset_ctp();} diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 5cdc66ad1..c1241a1bd 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -185,10 +185,11 @@ struct lemma_lt_proc : public std::binary_function { class pred_transformer { struct stats { - unsigned m_num_propagations; - unsigned m_num_invariants; - unsigned m_num_ctp; - unsigned m_num_is_invariant; + unsigned m_num_propagations; // num of times lemma is pushed higher + unsigned m_num_invariants; // num of infty lemmas found + unsigned m_num_ctp_blocked; // num of time ctp blocked lemma pushing + unsigned m_num_is_invariant; // num of times lemmas are pushed + unsigned m_num_lemma_level_jump; // lemma learned at higher level than expected stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; From df2e9d8fe249048f75fb4c685676c2afed589136 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 23 May 2018 17:12:28 -0700 Subject: [PATCH 1050/1283] Make smt_solver::updt_params() commulative --- src/smt/smt_solver.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 0bef90a48..01b78b80e 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -110,9 +110,9 @@ namespace smt { void updt_params(params_ref const & p) override { solver::updt_params(p); - m_smt_params.updt_params(p); - m_context.updt_params(p); - smt_params_helper smth(p); + m_smt_params.updt_params(solver::get_params()); + m_context.updt_params(solver::get_params()); + smt_params_helper smth(solver::get_params()); m_core_extend_patterns = smth.core_extend_patterns(); m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance(); m_core_extend_nonlocal_patterns = smth.core_extend_nonlocal_patterns(); From 4b09cefb9717a40b7bc71ff3b0e3e78f3163bb23 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 23 May 2018 14:27:32 -0700 Subject: [PATCH 1051/1283] Replace smt::kernel with smt_solver Replace all ad-hoc uses of smt::kernel with ad-hoc uses of smt_solver --- src/muz/spacer/spacer_context.cpp | 26 ++++++++++++++------------ src/muz/spacer/spacer_generalizers.cpp | 18 +++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 945f6686e..f29f73b3a 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2256,9 +2256,10 @@ bool context::validate() fv.reverse (); tmp = m.mk_exists(fv.size(), fv.c_ptr(), names.c_ptr(), tmp); } - smt::kernel solver(m, m_pm.fparams2()); - solver.assert_expr(tmp); - lbool res = solver.check(); + ref sol = + mk_smt_solver(m, params_ref::get_empty(), symbol::null); + sol->assert_expr(tmp); + lbool res = sol->check_sat(0, nullptr); if (res != l_false) { msg << "rule validation failed when checking: " << mk_pp(tmp, m); @@ -2648,7 +2649,8 @@ expr_ref context::get_ground_sat_answer() { cex.push_back(m.mk_const(preds[0])); } // smt context to obtain local cexes - scoped_ptr cex_ctx = alloc (smt::kernel, m, m_pm.fparams2 ()); + ref cex_ctx = + mk_smt_solver(m, params_ref::get_empty(), symbol::null); model_evaluator_util mev (m); // preorder traversal of the query derivation tree @@ -2689,7 +2691,7 @@ expr_ref context::get_ground_sat_answer() } cex_ctx->assert_expr (pt->transition ()); cex_ctx->assert_expr (pt->rule2tag (r)); - lbool res = cex_ctx->check (); + lbool res = cex_ctx->check_sat(0, nullptr); CTRACE("cex", res == l_false, tout << "Cex fact: " << mk_pp(cex_fact, m) << "\n"; for (unsigned i = 0; i < u_tail_sz; i++) @@ -3624,10 +3626,9 @@ void context::reset_statistics() bool context::check_invariant(unsigned lvl) { - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { + for (auto &entry : m_rels) { checkpoint(); - if (!check_invariant(lvl, it->m_key)) { + if (!check_invariant(lvl, entry.m_key)) { return false; } } @@ -3636,7 +3637,7 @@ bool context::check_invariant(unsigned lvl) bool context::check_invariant(unsigned lvl, func_decl* fn) { - smt::kernel ctx(m, m_pm.fparams2()); + ref ctx = mk_smt_solver(m, params_ref::get_empty(), symbol::null); pred_transformer& pt = *m_rels.find(fn); expr_ref_vector conj(m); expr_ref inv = pt.get_formulas(next_level(lvl), false); @@ -3644,9 +3645,10 @@ bool context::check_invariant(unsigned lvl, func_decl* fn) pt.add_premises(m_rels, lvl, conj); conj.push_back(m.mk_not(inv)); expr_ref fml(m.mk_and(conj.size(), conj.c_ptr()), m); - ctx.assert_expr(fml); - lbool result = ctx.check(); - TRACE("spacer", tout << "Check invariant level: " << lvl << " " << result << "\n" << mk_pp(fml, m) << "\n";); + ctx->assert_expr(fml); + lbool result = ctx->check_sat(0, nullptr); + TRACE("spacer", tout << "Check invariant level: " << lvl << " " << result + << "\n" << mk_pp(fml, m) << "\n";); return result == l_false; } diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 34f1eb730..7263f8264 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -29,7 +29,7 @@ Revision History: #include "ast/rewriter/expr_safe_replace.h" #include "ast/substitution/matcher.h" #include "ast/expr_functors.h" - +#include "smt/smt_solver.h" namespace spacer { void lemma_sanity_checker::operator()(lemma_ref &lemma) { @@ -249,17 +249,17 @@ void lemma_array_eq_generalizer::operator() (lemma_ref &lemma) { eqs.push_back(m.mk_eq(m.mk_const(vsymbs.get(i)), m.mk_const(vsymbs.get(j)))); } - smt::kernel solver(m, m_ctx.get_manager().fparams2()); + ref sol = mk_smt_solver(m, params_ref::get_empty(), symbol::null); expr_ref_vector lits(m); for (unsigned i = 0, core_sz = core.size(); i < core_sz; ++i) { SASSERT(lits.size() == i); - solver.push(); - solver.assert_expr(core.get(i)); + sol->push(); + sol->assert_expr(core.get(i)); for (unsigned j = 0, eqs_sz = eqs.size(); j < eqs_sz; ++j) { - solver.push(); - solver.assert_expr(eqs.get(j)); - lbool res = solver.check(); - solver.pop(1); + sol->push(); + sol->assert_expr(eqs.get(j)); + lbool res = sol->check_sat(0, nullptr); + sol->pop(1); if (res == l_false) { TRACE("core_array_eq", @@ -269,7 +269,7 @@ void lemma_array_eq_generalizer::operator() (lemma_ref &lemma) break; } } - solver.pop(1); + sol->pop(1); if (lits.size() == i) { lits.push_back(core.get(i)); } } From c2b8f25cf922b3c5cb5c708aa393e1391461d8cf Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 23 May 2018 15:03:44 -0700 Subject: [PATCH 1052/1283] Switch to using solver instead of smt::kernel all around --- src/muz/spacer/spacer_context.cpp | 61 ++++++++---- src/muz/spacer/spacer_iuc_solver.h | 6 +- src/muz/spacer/spacer_manager.h | 8 +- src/muz/spacer/spacer_prop_solver.cpp | 18 ++-- src/muz/spacer/spacer_prop_solver.h | 29 +++--- src/muz/spacer/spacer_smt_context_manager.cpp | 23 +++-- src/muz/spacer/spacer_smt_context_manager.h | 7 +- src/muz/spacer/spacer_virtual_solver.cpp | 96 +++++++------------ src/muz/spacer/spacer_virtual_solver.h | 36 ++++--- 9 files changed, 146 insertions(+), 138 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index f29f73b3a..b1ab0082a 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2289,33 +2289,56 @@ void context::reset_lemma_generalizers() // initialize global SMT parameters shared by all solvers void context::init_global_smt_params() { m.toggle_proof_mode(PGM_ENABLED); - smt_params &fparams = m_pm.fparams (); + params_ref p; if (!m_params.spacer_eq_prop ()) { - fparams.m_arith_bound_prop = BP_NONE; - fparams.m_arith_auto_config_simplex = true; - fparams.m_arith_propagate_eqs = false; - fparams.m_arith_eager_eq_axioms = false; + // arith_propagation_mode + p.set_uint("arith.propagation_mode", 0); + // fparams.m_arith_bound_prop = BP_NONE; + // NOT AVAILABLE + // fparams.m_arith_auto_config_simplex = true; + // arith_propagate_eqs + // fparams.m_arith_propagate_eqs = false; + p.set_bool("arith.propagate_eqs", false); + // NOT AVAILABLE + // fparams.m_arith_eager_eq_axioms = false; } - fparams.m_random_seed = m_params.spacer_random_seed (); + // fparams.m_random_seed = m_params.spacer_random_seed (); + p.set_uint("random_seed", m_params.spacer_random_seed()); - fparams.m_dump_benchmarks = m_params.spacer_vs_dump_benchmarks(); - fparams.m_dump_min_time = m_params.spacer_vs_dump_min_time(); - fparams.m_dump_recheck = m_params.spacer_vs_recheck(); + // fparams.m_dump_benchmarks = m_params.spacer_vs_dump_benchmarks(); + // fparams.m_dump_min_time = m_params.spacer_vs_dump_min_time(); + // fparams.m_dump_recheck = m_params.spacer_vs_recheck(); - fparams.m_mbqi = m_params.spacer_mbqi(); + // mbqi + // fparams.m_mbqi = m_params.spacer_mbqi(); + p.set_bool("mbqi", m_params.spacer_mbqi()); if (!m_params.spacer_ground_cti()) { - fparams.m_pi_use_database = true; // you don't need this - fparams.m_phase_selection = PS_CACHING_CONSERVATIVE2; - fparams.m_restart_strategy = RS_GEOMETRIC; - fparams.m_restart_factor = 1.5; - fparams.m_eliminate_bounds = true; - fparams.m_qi_quick_checker = MC_UNSAT; // - fparams.m_qi_eager_threshold = 10; - fparams.m_qi_lazy_threshold = 20; - fparams.m_ng_lift_ite = LI_FULL; // ? probably useless + // fparams.m_pi_use_database = true; // you don't need this + // phase_selection + // fparams.m_phase_selection = PS_CACHING_CONSERVATIVE2; + p.set_uint("phase_selection", 4); + // restart_strategy + // fparams.m_restart_strategy = RS_GEOMETRIC; + p.set_uint("restart_strategy", 0); + // restart factor + // fparams.m_restart_factor = 1.5; + p.set_double("restart_factor", 1.5); + // probably not needed in our use case + // fparams.m_eliminate_bounds = true; + // NONE + // fparams.m_qi_quick_checker = MC_UNSAT; // + // qi_eager_threshold + // fparams.m_qi_eager_threshold = 10; + p.set_double("qi.eager_threshold", 10.0); + // qi_lazy_threshold + // fparams.m_qi_lazy_threshold = 20; + p.set_double("qi.lazy_threshold", 20.0); + // useless + // fparams.m_ng_lift_ite = LI_FULL; } + m_pm.updt_params(p); } void context::init_lemma_generalizers() { diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 568124629..8bb0a8605 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -106,7 +106,11 @@ public: /* solver interface */ solver* translate(ast_manager &m, params_ref const &p) override { return m_solver.translate(m, p);} - void updt_params(params_ref const &p) override { m_solver.updt_params(p);} + void updt_params(params_ref const &p) override {m_solver.updt_params(p);} + void reset_params(params_ref const &p) override {m_solver.reset_params(p);} + const params_ref &get_params() const override {return m_solver.get_params();} + void push_params() override {m_solver.push_params();} + void pop_params() override {m_solver.pop_params();} void collect_param_descrs(param_descrs &r) override { m_solver.collect_param_descrs(r);} void set_produce_models(bool f) override { m_solver.set_produce_models(f);} void assert_expr_core(expr *t) override { m_solver.assert_expr(t);} diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index 58b5aca07..471090c30 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -155,11 +155,13 @@ public: // three different solvers with three different sets of parameters // different solvers are used for different types of queries in spacer solver* mk_fresh() {return m_contexts.mk_fresh();} - smt_params& fparams() { return m_contexts.fparams(); } + void updt_params(const params_ref &p) {m_contexts.updt_params(p);} + solver* mk_fresh2() {return m_contexts2.mk_fresh();} - smt_params &fparams2() { return m_contexts2.fparams(); } + void updt_params2(const params_ref &p) {m_contexts2.updt_params(p);} + solver* mk_fresh3() {return m_contexts3.mk_fresh();} - smt_params &fparams3() {return m_contexts3.fparams();} + void updt_params3(const params_ref &p) {m_contexts3.updt_params(p);} diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 1dd4515a7..a4ea79a25 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -56,10 +56,7 @@ prop_solver::prop_solver(spacer::manager& pm, { m_solvers[0] = pm.mk_fresh(); - m_fparams[0] = &pm.fparams(); - m_solvers[1] = pm.mk_fresh2(); - m_fparams[1] = &pm.fparams2(); m_contexts[0] = alloc(spacer::iuc_solver, *(m_solvers[0]), p.spacer_iuc(), @@ -293,8 +290,12 @@ lbool prop_solver::internal_check_assumptions( { // XXX Turn model generation if m_model != 0 SASSERT(m_ctx); - SASSERT(m_ctx_fparams); - flet _model(m_ctx_fparams->m_model, m_model != nullptr); + + params_ref p; + if (m_model != nullptr) { + p.set_bool("produce_models", true); + m_ctx->updt_params(p); + } if (m_in_level) { assert_level_atoms(m_current_level); } lbool result = maxsmt(hard_atoms, soft_atoms); @@ -333,6 +334,12 @@ lbool prop_solver::internal_check_assumptions( // manually undo proxies because maxsmt() call above manually adds proxies m_ctx->undo_proxies(*m_core); } + + if (m_model != nullptr) { + p.set_bool("produce_models", false); + m_ctx->updt_params(p); + } + return result; } @@ -350,7 +357,6 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, flatten_and(hard); m_ctx = m_contexts [solver_id == 0 ? 0 : 0 /* 1 */].get(); - m_ctx_fparams = m_fparams [solver_id == 0 ? 0 : 0 /* 1 */]; // can be disabled if use_push_bg == true // solver::scoped_push _s_(*m_ctx); diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index d10ebcfcd..27b2fd51d 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -42,11 +42,9 @@ class prop_solver { private: ast_manager& m; symbol m_name; - smt_params* m_fparams[2]; solver* m_solvers[2]; scoped_ptr m_contexts[2]; iuc_solver * m_ctx; - smt_params * m_ctx_fparams; decl_vector m_level_preds; app_ref_vector m_pos_level_atoms; // atoms used to identify level app_ref_vector m_neg_level_atoms; // @@ -138,25 +136,20 @@ public: }; class scoped_weakness { - - smt_params &m_params; - bool m_arith_ignore_int; - bool m_array_weak; public: - scoped_weakness(prop_solver &ps, unsigned solver_id, unsigned weakness) : - m_params(*ps.m_fparams[solver_id == 0 ? 0 : 0 /*1*/]) { - // save current values - m_arith_ignore_int = m_params.m_arith_ignore_int; - m_array_weak = m_params.m_array_weak; + solver *sol; + scoped_weakness(prop_solver &ps, unsigned solver_id, unsigned weakness) + : sol(nullptr) { + sol = ps.m_solvers[solver_id == 0 ? 0 : 0 /* 1 */]; + if (!sol) return; + sol->push_params(); - // set values based on weakness score - m_params.m_arith_ignore_int = weakness < 1; - m_params.m_array_weak = weakness < 2; - } - ~scoped_weakness() { - m_params.m_arith_ignore_int = m_arith_ignore_int; - m_params.m_array_weak = m_array_weak; + params_ref p; + p.set_bool("arith.ignore_int", weakness < 1); + p.set_bool("array.weak", weakness < 2); + sol->updt_params(p); } + ~scoped_weakness() {if (sol) {sol->pop_params();}} }; }; } diff --git a/src/muz/spacer/spacer_smt_context_manager.cpp b/src/muz/spacer/spacer_smt_context_manager.cpp index e26381afd..78f01b6e5 100644 --- a/src/muz/spacer/spacer_smt_context_manager.cpp +++ b/src/muz/spacer/spacer_smt_context_manager.cpp @@ -24,19 +24,17 @@ Revision History: #include "smt/smt_context.h" #include "smt/params/smt_params.h" +#include "smt/smt_solver.h" #include "muz/spacer/spacer_util.h" #include "muz/spacer/spacer_smt_context_manager.h" namespace spacer { - - - smt_context_manager::smt_context_manager(ast_manager &m, unsigned max_num_contexts, const params_ref &p) : - m_fparams(p), m(m), + m_params(p), m_max_num_contexts(max_num_contexts), m_num_contexts(0) { m_stats.reset();} @@ -45,6 +43,13 @@ smt_context_manager::~smt_context_manager() { std::for_each(m_solvers.begin(), m_solvers.end(), delete_proc()); + m_solvers.reset(); + m_base_solvers.reset(); +} + +void smt_context_manager::updt_params(params_ref const &p) { + m_params.append(p); + for (auto *s : m_base_solvers) {s->updt_params(m_params);} } virtual_solver* smt_context_manager::mk_fresh() @@ -53,10 +58,14 @@ virtual_solver* smt_context_manager::mk_fresh() virtual_solver_factory *solver_factory = nullptr; if (m_max_num_contexts == 0 || m_solvers.size() < m_max_num_contexts) { - m_solvers.push_back(alloc(spacer::virtual_solver_factory, m, m_fparams)); + m_base_solvers.push_back(mk_smt_solver(m, m_params, symbol::null)); + m_solvers.push_back(alloc(spacer::virtual_solver_factory, + *m_base_solvers.back())); solver_factory = m_solvers.back(); - } else - { solver_factory = m_solvers[(m_num_contexts - 1) % m_max_num_contexts]; } + } + else { + solver_factory = m_solvers[(m_num_contexts - 1) % m_max_num_contexts]; + } return solver_factory->mk_solver(); } diff --git a/src/muz/spacer/spacer_smt_context_manager.h b/src/muz/spacer/spacer_smt_context_manager.h index 0df9bc77b..a62aba6cd 100644 --- a/src/muz/spacer/spacer_smt_context_manager.h +++ b/src/muz/spacer/spacer_smt_context_manager.h @@ -37,9 +37,10 @@ class smt_context_manager { void reset() { memset(this, 0, sizeof(*this)); } }; - smt_params m_fparams; ast_manager& m; + params_ref m_params; unsigned m_max_num_contexts; + sref_vector m_base_solvers; ptr_vector m_solvers; unsigned m_num_contexts; @@ -58,8 +59,8 @@ public: void collect_statistics(statistics& st) const; void reset_statistics(); - void updt_params(params_ref const &p) { m_fparams.updt_params(p); } - smt_params& fparams() {return m_fparams;} + void updt_params(params_ref const &p); + }; diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 873f94160..a1a1a7eec 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - multi-solver view of a single smt::kernel + multi-solver view of a single solver Author: @@ -28,13 +28,14 @@ Notes: #include "ast/scoped_proof.h" +#include "smt/smt_kernel.h" + namespace spacer { -virtual_solver::virtual_solver(virtual_solver_factory &factory, - smt::kernel &context, app* pred) : - solver_na2as(context.m()), +virtual_solver::virtual_solver(virtual_solver_factory &factory, app* pred) : + solver_na2as(factory.get_manager()), m_factory(factory), - m(context.m()), - m_context(context), + m(factory.get_manager()), + m_context(factory.get_base_solver()), m_pred(pred, m), m_virtual(!m.is_true(pred)), m_assertions(m), @@ -42,7 +43,7 @@ virtual_solver::virtual_solver(virtual_solver_factory &factory, m_flat(m), m_pushed(false), m_in_delay_scope(false), - m_dump_benchmarks(factory.fparams().m_dump_benchmarks), + m_dump_benchmarks(false /*factory.fparams().m_dump_benchmarks*/), m_dump_counter(0), m_proof(m) { @@ -114,7 +115,7 @@ lbool virtual_solver::check_sat_core(unsigned num_assumptions, out << "(exit)\n"; out.close(); } - lbool res = m_context.check(num_assumptions, assumptions); + lbool res = m_context.check_sat(num_assumptions, assumptions); sw.stop(); if (res == l_true) { m_factory.m_check_sat_watch.add(sw); @@ -125,8 +126,8 @@ lbool virtual_solver::check_sat_core(unsigned num_assumptions, } set_status(res); - if (m_dump_benchmarks && - sw.get_seconds() >= m_factory.fparams().m_dump_min_time) { + if (false /*m_dump_benchmarks && + sw.get_seconds() >= m_factory.fparams().m_dump_min_time*/) { std::stringstream file_name; file_name << "virt_solver"; if (m_virtual) { file_name << "_" << m_pred->get_decl()->get_name(); } @@ -151,13 +152,13 @@ lbool virtual_solver::check_sat_core(unsigned num_assumptions, st.display_smt2(out); - if (m_factory.fparams().m_dump_recheck) { + if (false /* m_factory.fparams().m_dump_recheck */) { scoped_no_proof _no_proof_(m); smt_params p; stopwatch sw2; smt::kernel kernel(m, p); - for (unsigned i = 0, sz = m_context.size(); i < sz; ++i) - { kernel.assert_expr(m_context.get_formula(i)); } + for (unsigned i = 0, sz = m_context.get_num_assertions(); i < sz; ++i) + { kernel.assert_expr(m_context.get_assertion(i)); } sw2.start(); kernel.check(num_assumptions, assumptions); sw2.stop(); @@ -208,10 +209,12 @@ void virtual_solver::pop_core(unsigned n) { void virtual_solver::get_unsat_core(ptr_vector &r) { - for (unsigned i = 0, sz = m_context.get_unsat_core_size(); i < sz; ++i) { - expr *core = m_context.get_unsat_core_expr(i); - if (is_aux_predicate(core)) { continue; } - r.push_back(core); + ptr_vector core; + m_context.get_unsat_core(core); + + for (unsigned i = 0, sz = core.size(); i < sz; ++i) { + if (is_aux_predicate(core.get(i))) { continue; } + r.push_back(core.get(i)); } } @@ -244,40 +247,25 @@ void virtual_solver::internalize_assertions() m_context.assert_expr(f); } } -void virtual_solver::refresh() -{ - SASSERT(!m_pushed); - m_head = 0; -} - -void virtual_solver::reset() -{ - SASSERT(!m_pushed); - m_head = 0; - m_assertions.reset(); - m_factory.refresh(); -} void virtual_solver::get_labels(svector &r) -{ - r.reset(); - buffer tmp; - m_context.get_relevant_labels(nullptr, tmp); - r.append(tmp.size(), tmp.c_ptr()); -} +{m_context.get_labels(r);} solver* virtual_solver::translate(ast_manager& m, params_ref const& p) { UNREACHABLE(); return nullptr; } -void virtual_solver::updt_params(params_ref const &p) { m_factory.updt_params(p); } -void virtual_solver::collect_param_descrs(param_descrs &r) { m_factory.collect_param_descrs(r); } -void virtual_solver::set_produce_models(bool f) { m_factory.set_produce_models(f); } -smt_params &virtual_solver::fparams() {return m_factory.fparams();} +void virtual_solver::updt_params(params_ref const &p) {m_context.updt_params(p);} +void virtual_solver::reset_params(params_ref const &p) {m_context.reset_params(p);} +const params_ref &virtual_solver::get_params() const {return m_context.get_params();} +void virtual_solver::push_params(){m_context.push_params();} +void virtual_solver::pop_params(){m_context.pop_params();} +void virtual_solver::collect_param_descrs(param_descrs &r) { m_context.collect_param_descrs(r); } +void virtual_solver::set_produce_models(bool f) { m_context.set_produce_models(f); } void virtual_solver::to_smt2_benchmark(std::ostream &out, - smt::kernel &context, + solver &context, unsigned num_assumptions, expr * const * assumptions, char const * name, @@ -288,11 +276,8 @@ void virtual_solver::to_smt2_benchmark(std::ostream &out, ast_pp_util pp(m); expr_ref_vector asserts(m); - - for (unsigned i = 0, sz = context.size(); i < sz; ++i) { - asserts.push_back(context.get_formula(i)); - pp.collect(asserts.back()); - } + context.get_assertions(asserts); + pp.collect(asserts); pp.collect(num_assumptions, assumptions); pp.display_decls(out); pp.display_asserts(out, asserts); @@ -303,11 +288,8 @@ void virtual_solver::to_smt2_benchmark(std::ostream &out, } -virtual_solver_factory::virtual_solver_factory(ast_manager &mgr, smt_params &fparams) : - m_fparams(fparams), m(mgr), m_context(m, m_fparams) -{ - m_stats.reset(); -} +virtual_solver_factory::virtual_solver_factory(solver &base) : + m(base.get_manager()), m_context(base) {m_stats.reset();} virtual_solver* virtual_solver_factory::mk_solver() { @@ -316,7 +298,7 @@ virtual_solver* virtual_solver_factory::mk_solver() app_ref pred(m); pred = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); SASSERT(m_context.get_scope_level() == 0); - m_solvers.push_back(alloc(virtual_solver, *this, m_context, pred)); + m_solvers.push_back(alloc(virtual_solver, *this, pred)); return m_solvers.back(); } @@ -333,7 +315,6 @@ void virtual_solver_factory::collect_statistics(statistics &st) const } void virtual_solver_factory::reset_statistics() { - m_context.reset_statistics(); m_stats.reset(); m_check_sat_watch.reset(); m_check_undef_watch.reset(); @@ -341,17 +322,10 @@ void virtual_solver_factory::reset_statistics() m_proof_watch.reset(); } -void virtual_solver_factory::refresh() -{ - m_context.reset(); - for (unsigned i = 0, e = m_solvers.size(); i < e; ++i) - { m_solvers [i]->refresh(); } -} - virtual_solver_factory::~virtual_solver_factory() { for (unsigned i = 0, e = m_solvers.size(); i < e; ++i) - { dealloc(m_solvers [i]); } + { dealloc(m_solvers[i]); } } diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 162f56178..e5db5e396 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -7,7 +7,7 @@ Module Name: Abstract: - multi-solver view of a single smt::kernel + multi-solver view of a single solver Author: @@ -21,7 +21,6 @@ Notes: #include"ast/ast.h" #include"util/params.h" #include"solver/solver_na2as.h" -#include"smt/smt_kernel.h" #include"smt/params/smt_params.h" #include"util/stopwatch.h" namespace spacer { @@ -33,7 +32,7 @@ class virtual_solver : public solver_na2as { private: virtual_solver_factory &m_factory; ast_manager &m; - smt::kernel &m_context; + solver &m_context; app_ref m_pred; bool m_virtual; @@ -49,12 +48,12 @@ private: proof_ref m_proof; - virtual_solver(virtual_solver_factory &factory, smt::kernel &context, app* pred); + virtual_solver(virtual_solver_factory &factory, app* pred); bool is_aux_predicate(expr *p); void internalize_assertions(); void to_smt2_benchmark(std::ostream &out, - smt::kernel &context, + solver &context, unsigned num_assumptions, expr * const * assumptions, char const * name = "benchmarks", @@ -62,8 +61,6 @@ private: char const * status = "unknown", char const * attributes = ""); - void refresh(); - public: ~virtual_solver() override; unsigned get_num_assumptions() const override @@ -84,21 +81,24 @@ public: void get_model_core(model_ref &m) override {m_context.get_model(m);} proof* get_proof() override; std::string reason_unknown() const override - {return m_context.last_failure_as_string();} + {return m_context.reason_unknown();} void set_reason_unknown(char const *msg) override {m_context.set_reason_unknown(msg);} ast_manager& get_manager() const override {return m;} void get_labels(svector &r) override; void set_produce_models(bool f) override; smt_params &fparams(); - void reset(); expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void set_progress_callback(progress_callback *callback) override {UNREACHABLE();} solver *translate(ast_manager &m, params_ref const &p) override; void updt_params(params_ref const &p) override; + void reset_params(params_ref const& p) override; + params_ref const& get_params() const override; void collect_param_descrs(param_descrs &r) override; + void push_params() override; + void pop_params() override; protected: @@ -107,13 +107,12 @@ protected: void pop_core(unsigned n) override; }; -/// multi-solver abstraction on top of a single smt::kernel +/// multi-solver abstraction on top of a single solver class virtual_solver_factory { friend class virtual_solver; private: - smt_params &m_fparams; ast_manager &m; - smt::kernel m_context; + solver &m_context; /// solvers managed by this factory ptr_vector m_solvers; @@ -132,20 +131,17 @@ private: stopwatch m_proof_watch; - void refresh(); - - smt_params &fparams() { return m_fparams; } + solver &get_base_solver() {return m_context;} + ast_manager &get_manager() {return m;} public: - virtual_solver_factory(ast_manager &mgr, smt_params &fparams); + virtual_solver_factory(solver &base); virtual ~virtual_solver_factory(); virtual_solver* mk_solver(); void collect_statistics(statistics &st) const; void reset_statistics(); - void updt_params(params_ref const &p) { m_fparams.updt_params(p); } - void collect_param_descrs(param_descrs &r) { /* empty */ } - void set_produce_models(bool f) { m_fparams.m_model = f; } - bool get_produce_models() { return m_fparams.m_model; } + void updt_params(params_ref const &p) {m_context.updt_params(p);} + void collect_param_descrs(param_descrs &r) {m_context.collect_param_descrs(r);} }; } From ec8a86b78ad6119029fac03da7c612a354ea2340 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 23 May 2018 21:43:07 -0700 Subject: [PATCH 1053/1283] Removed unused m_qi_ematching parameter from smt_params --- src/smt/params/qi_params.cpp | 1 - src/smt/params/qi_params.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/smt/params/qi_params.cpp b/src/smt/params/qi_params.cpp index a9cff6e8c..deeb2b99c 100644 --- a/src/smt/params/qi_params.cpp +++ b/src/smt/params/qi_params.cpp @@ -40,7 +40,6 @@ void qi_params::updt_params(params_ref const & _p) { #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; void qi_params::display(std::ostream & out) const { - DISPLAY_PARAM(m_qi_ematching); DISPLAY_PARAM(m_qi_cost); DISPLAY_PARAM(m_qi_new_gen); DISPLAY_PARAM(m_qi_eager_threshold); diff --git a/src/smt/params/qi_params.h b/src/smt/params/qi_params.h index cc1a30673..0f6c03f5b 100644 --- a/src/smt/params/qi_params.h +++ b/src/smt/params/qi_params.h @@ -29,7 +29,6 @@ enum quick_checker_mode { }; struct qi_params { - bool m_qi_ematching; std::string m_qi_cost; std::string m_qi_new_gen; double m_qi_eager_threshold; From d06f4bd3378697d3da09993a5dfdd995b2ebc35c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 11:14:51 -0700 Subject: [PATCH 1054/1283] Fix reset of params_ref in solver params_ref is not a ref, and params_ref::reset is not ref::reset. params_ref::reset resets the params object being pointed to by params_ref. A proper way to reset a params_ref as a reference is to assign an empty params_ref object to it. --- src/smt/smt_solver.cpp | 2 +- src/solver/solver.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 01b78b80e..8e5c2aaa2 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -122,7 +122,7 @@ namespace smt { smt_params m_smt_params_save; void push_params() override { - m_params_save.reset(); + m_params_save = params_ref(); m_params_save.copy(solver::get_params()); m_smt_params_save = m_smt_params; } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index cc1d472ca..84b5eb588 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -206,14 +206,13 @@ void solver::collect_param_descrs(param_descrs & r) { r.insert("solver.enforce_model_conversion", CPK_BOOL, "(default: false) enforce model conversion when asserting formulas"); } -void solver::reset_params(params_ref const & p) { - m_params.reset(); - m_params.copy(p); +void solver::reset_params(params_ref const & p) { + m_params = p; m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); } -void solver::updt_params(params_ref const & p) { - m_params.copy(p); +void solver::updt_params(params_ref const & p) { + m_params.copy(p); m_enforce_model_conversion = m_params.get_bool("solver.enforce_model_conversion", false); } From 1c062297558e4d0b31104d45f0ed318ad362fd16 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 11:17:18 -0700 Subject: [PATCH 1055/1283] User control over qi.quick_checker smt_params option --- src/smt/params/qi_params.cpp | 1 + src/smt/params/smt_params_helper.pyg | 1 + 2 files changed, 2 insertions(+) diff --git a/src/smt/params/qi_params.cpp b/src/smt/params/qi_params.cpp index deeb2b99c..91f354eda 100644 --- a/src/smt/params/qi_params.cpp +++ b/src/smt/params/qi_params.cpp @@ -35,6 +35,7 @@ void qi_params::updt_params(params_ref const & _p) { m_qi_lazy_threshold = p.qi_lazy_threshold(); m_qi_cost = p.qi_cost(); m_qi_max_eager_multipatterns = p.qi_max_multi_patterns(); + m_qi_quick_checker = static_cast(p.qi_quick_checker()); } #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index a85365de0..151a42d24 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -36,6 +36,7 @@ def_module_params(module_name='smt', ('qi.lazy_threshold', DOUBLE, 20.0, 'threshold for lazy quantifier instantiation'), ('qi.cost', STRING, '(+ weight generation)', 'expression specifying what is the cost of a given quantifier instantiation'), ('qi.max_multi_patterns', UINT, 0, 'specify the number of extra multi patterns'), + ('qi.quick_checker', UINT, 0, 'specify quick checker mode, 0 - no quick checker, 1 - using unsat instances, 2 - using both unsat and no-sat instances'), ('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'), From c8187886cf870490004d0e9228eff90b1275e8cd Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 11:18:32 -0700 Subject: [PATCH 1056/1283] spacer: use same params for all solver pools --- src/muz/spacer/spacer_context.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index b1ab0082a..c63bb3002 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2340,6 +2340,8 @@ void context::init_global_smt_params() { m_pm.updt_params(p); } + m_pm.updt_params2(p); + m_pm.updt_params3(p); void context::init_lemma_generalizers() { reset_lemma_generalizers(); From cfeee55d4ff1c01c884216680e22af12f883145b Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 11:19:40 -0700 Subject: [PATCH 1057/1283] spacer: set qi.quick_checker to MC_UNSAT if quantifiers are expected --- src/muz/spacer/spacer_context.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index c63bb3002..6eb1b0d40 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2292,7 +2292,7 @@ void context::init_global_smt_params() { params_ref p; if (!m_params.spacer_eq_prop ()) { // arith_propagation_mode - p.set_uint("arith.propagation_mode", 0); + p.set_uint("arith.propagation_mode", BP_NONE); // fparams.m_arith_bound_prop = BP_NONE; // NOT AVAILABLE // fparams.m_arith_auto_config_simplex = true; @@ -2317,10 +2317,10 @@ void context::init_global_smt_params() { // fparams.m_pi_use_database = true; // you don't need this // phase_selection // fparams.m_phase_selection = PS_CACHING_CONSERVATIVE2; - p.set_uint("phase_selection", 4); + p.set_uint("phase_selection", PS_CACHING_CONSERVATIVE2); // restart_strategy // fparams.m_restart_strategy = RS_GEOMETRIC; - p.set_uint("restart_strategy", 0); + p.set_uint("restart_strategy", RS_GEOMETRIC); // restart factor // fparams.m_restart_factor = 1.5; p.set_double("restart_factor", 1.5); @@ -2328,6 +2328,7 @@ void context::init_global_smt_params() { // fparams.m_eliminate_bounds = true; // NONE // fparams.m_qi_quick_checker = MC_UNSAT; // + p.set_uint("qi.quick_checker", MC_UNSAT); // qi_eager_threshold // fparams.m_qi_eager_threshold = 10; p.set_double("qi.eager_threshold", 10.0); @@ -2339,9 +2340,9 @@ void context::init_global_smt_params() { } m_pm.updt_params(p); -} m_pm.updt_params2(p); m_pm.updt_params3(p); +} void context::init_lemma_generalizers() { reset_lemma_generalizers(); From b17be763d33fba0edf60a28b12412fca3e4d7d01 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 11:40:25 -0700 Subject: [PATCH 1058/1283] User control over more arith options --- src/smt/params/smt_params_helper.pyg | 2 ++ src/smt/params/theory_arith_params.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 151a42d24..816764896 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -54,6 +54,8 @@ def_module_params(module_name='smt', ('arith.ignore_int', BOOL, False, 'treat integer variables as real'), ('arith.dump_lemmas', BOOL, False, 'dump arithmetic theory lemmas to files'), ('arith.greatest_error_pivot', BOOL, False, 'Pivoting strategy'), + ('arith.eager_eq_axioms', BOOL, True, 'eager equality axioms'), + ('arith.auto_config_simplex', BOOL, False, 'force simplex solver in auto_config'), ('pb.conflict_frequency', UINT, 1000, 'conflict frequency for Pseudo-Boolean theory'), ('pb.learn_complements', BOOL, True, 'learn complement literals for Pseudo-Boolean theory'), ('pb.enable_compilation', BOOL, True, 'enable compilation into sorting circuits for Pseudo-Boolean'), diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index 250848db4..0918c9423 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -37,6 +37,9 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_bound_prop = static_cast(p.arith_propagation_mode()); m_arith_dump_lemmas = p.arith_dump_lemmas(); m_arith_reflect = p.arith_reflect(); + m_arith_eager_eq_axioms = p.arith_eager_eq_axioms(); + m_arith_auto_config_simplex = p.arith_auto_config_simplex(); + arith_rewriter_params ap(_p); m_arith_eq2ineq = ap.eq2ineq(); } From c2304e263619ef5a41afd6567d6d8b4859a894aa Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 11:40:38 -0700 Subject: [PATCH 1059/1283] spacer: Cleanup of smt parameter configuration --- src/muz/spacer/spacer_context.cpp | 35 +++++++------------------------ 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 6eb1b0d40..acc7fb268 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2290,19 +2290,12 @@ void context::reset_lemma_generalizers() void context::init_global_smt_params() { m.toggle_proof_mode(PGM_ENABLED); params_ref p; - if (!m_params.spacer_eq_prop ()) { - // arith_propagation_mode + if (!m_params.spacer_eq_prop()) { p.set_uint("arith.propagation_mode", BP_NONE); - // fparams.m_arith_bound_prop = BP_NONE; - // NOT AVAILABLE - // fparams.m_arith_auto_config_simplex = true; - // arith_propagate_eqs - // fparams.m_arith_propagate_eqs = false; + p.set_bool("arith.auto_config_simplex", true); p.set_bool("arith.propagate_eqs", false); - // NOT AVAILABLE - // fparams.m_arith_eager_eq_axioms = false; + p.set_bool("arith.eager_eq_axioms", false); } - // fparams.m_random_seed = m_params.spacer_random_seed (); p.set_uint("random_seed", m_params.spacer_random_seed()); // fparams.m_dump_benchmarks = m_params.spacer_vs_dump_benchmarks(); @@ -2310,33 +2303,21 @@ void context::init_global_smt_params() { // fparams.m_dump_recheck = m_params.spacer_vs_recheck(); // mbqi - // fparams.m_mbqi = m_params.spacer_mbqi(); p.set_bool("mbqi", m_params.spacer_mbqi()); if (!m_params.spacer_ground_cti()) { - // fparams.m_pi_use_database = true; // you don't need this - // phase_selection - // fparams.m_phase_selection = PS_CACHING_CONSERVATIVE2; p.set_uint("phase_selection", PS_CACHING_CONSERVATIVE2); - // restart_strategy - // fparams.m_restart_strategy = RS_GEOMETRIC; p.set_uint("restart_strategy", RS_GEOMETRIC); - // restart factor - // fparams.m_restart_factor = 1.5; p.set_double("restart_factor", 1.5); - // probably not needed in our use case - // fparams.m_eliminate_bounds = true; - // NONE - // fparams.m_qi_quick_checker = MC_UNSAT; // p.set_uint("qi.quick_checker", MC_UNSAT); - // qi_eager_threshold - // fparams.m_qi_eager_threshold = 10; p.set_double("qi.eager_threshold", 10.0); - // qi_lazy_threshold - // fparams.m_qi_lazy_threshold = 20; p.set_double("qi.lazy_threshold", 20.0); - // useless + + // options that we used to set, but are not user visible and + // possibly not very useful // fparams.m_ng_lift_ite = LI_FULL; + // fparams.m_eliminate_bounds = true; + // fparams.m_pi_use_database = true; } m_pm.updt_params(p); From 180d38378a2013a288d476ecc2274ed2e05a6618 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 12:12:48 -0700 Subject: [PATCH 1060/1283] Add additional API to solver_pool --- src/solver/solver_pool.cpp | 7 +++++++ src/solver/solver_pool.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 3cf39a64c..88838639e 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -65,6 +65,9 @@ public: solver* translate(ast_manager& m, params_ref const& p) override { UNREACHABLE(); return nullptr; } void updt_params(params_ref const& p) override { solver::updt_params(p); m_base->updt_params(p); } + void push_params() override {m_base->push_params();} + void pop_params() override {m_base->pop_params();} + void collect_param_descrs(param_descrs & r) override { m_base->collect_param_descrs(r); } void collect_statistics(statistics & st) const override { m_base->collect_statistics(st); } unsigned get_num_assertions() const override { return m_base->get_num_assertions(); } @@ -280,6 +283,10 @@ ptr_vector solver_pool::get_base_solvers() const { return solvers; } +void solver_pool::updt_params(const params_ref &p) { + ptr_vector solvers = get_base_solvers(); + for (solver *s : solvers) s->updt_params(p); +} void solver_pool::collect_statistics(statistics &st) const { ptr_vector solvers = get_base_solvers(); for (solver* s : solvers) s->collect_statistics(st); diff --git a/src/solver/solver_pool.h b/src/solver/solver_pool.h index f279dfd4b..42c13fc58 100644 --- a/src/solver/solver_pool.h +++ b/src/solver/solver_pool.h @@ -66,6 +66,8 @@ public: solver* mk_solver(); void reset_solver(solver* s); + void updt_params(const params_ref &p); + }; From 098e70a9e23fdd816184032941c93ee0b586aef2 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 15:31:31 -0700 Subject: [PATCH 1061/1283] spacer: switched to using solver_pool --- src/muz/spacer/spacer_context.cpp | 6 ++--- src/muz/spacer/spacer_manager.cpp | 17 +++++++----- src/muz/spacer/spacer_manager.h | 39 ++++++++++++++------------- src/muz/spacer/spacer_prop_solver.cpp | 4 +-- 4 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index acc7fb268..3c94e5521 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -642,7 +642,7 @@ pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): pm(pm), m(pm.get_manager()), ctx(ctx), m_head(head, m), m_sig(m), m_solver(pm, ctx.get_params(), head->get_name()), - m_reach_ctx (pm.mk_fresh3 ()), + m_reach_ctx (pm.mk_solver2()), m_pobs(*this), m_frames(*this), m_reach_facts(), m_rf_init_sz(0), @@ -2320,9 +2320,9 @@ void context::init_global_smt_params() { // fparams.m_pi_use_database = true; } - m_pm.updt_params(p); + m_pm.updt_params0(p); + m_pm.updt_params1(p); m_pm.updt_params2(p); - m_pm.updt_params3(p); } void context::init_lemma_generalizers() { diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index 04d3c09d4..a281cac81 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -30,6 +30,7 @@ Revision History: #include "model/model_smt2_pp.h" #include "tactic/model_converter.h" +#include "smt/smt_solver.h" namespace spacer { class collect_decls_proc { @@ -176,12 +177,16 @@ static std::vector state_suffixes() { } manager::manager(unsigned max_num_contexts, ast_manager& manager) : - m(manager), - m_mux(m, state_suffixes()), - m_contexts(m, max_num_contexts), - m_contexts2(m, max_num_contexts), - m_contexts3(m, max_num_contexts) -{} + m(manager), m_mux(m, state_suffixes()) { + + m_pool0_base = mk_smt_solver(m, params_ref::get_empty(), symbol::null); + m_pool1_base = mk_smt_solver(m, params_ref::get_empty(), symbol::null); + m_pool2_base = mk_smt_solver(m, params_ref::get_empty(), symbol::null); + + m_pool0 = alloc(solver_pool, m_pool0_base.get(), max_num_contexts); + m_pool1 = alloc(solver_pool, m_pool1_base.get(), max_num_contexts); + m_pool2 = alloc(solver_pool, m_pool2_base.get(), max_num_contexts); +} void manager::add_new_state(func_decl * s) diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index 471090c30..f7d43ccb0 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -34,9 +34,9 @@ Revision History: #include "muz/spacer/spacer_util.h" #include "muz/spacer/spacer_sym_mux.h" #include "muz/spacer/spacer_farkas_learner.h" -#include "muz/spacer/spacer_smt_context_manager.h" #include "muz/base/dl_rule.h" - +#include "solver/solver.h" +#include "solver/solver_pool.h" namespace smt {class context;} namespace spacer { @@ -78,10 +78,13 @@ class manager { // manager of multiplexed names sym_mux m_mux; + ref m_pool0_base; + ref m_pool1_base; + ref m_pool2_base; // three solver pools for different queries - spacer::smt_context_manager m_contexts; - spacer::smt_context_manager m_contexts2; - spacer::smt_context_manager m_contexts3; + scoped_ptr m_pool0; + scoped_ptr m_pool1; + scoped_ptr m_pool2; unsigned n_index() const { return 0; } unsigned o_index(unsigned i) const { return i + 1; } @@ -154,27 +157,25 @@ public: // three different solvers with three different sets of parameters // different solvers are used for different types of queries in spacer - solver* mk_fresh() {return m_contexts.mk_fresh();} - void updt_params(const params_ref &p) {m_contexts.updt_params(p);} - - solver* mk_fresh2() {return m_contexts2.mk_fresh();} - void updt_params2(const params_ref &p) {m_contexts2.updt_params(p);} - - solver* mk_fresh3() {return m_contexts3.mk_fresh();} - void updt_params3(const params_ref &p) {m_contexts3.updt_params(p);} + solver* mk_solver0() {return m_pool0->mk_solver();} + void updt_params0(const params_ref &p) {m_pool0->updt_params(p);} + solver* mk_solver1() {return m_pool1->mk_solver();} + void updt_params1(const params_ref &p) {m_pool1->updt_params(p);} + solver* mk_solver2() {return m_pool2->mk_solver();} + void updt_params2(const params_ref &p) {m_pool2->updt_params(p);} void collect_statistics(statistics& st) const { - m_contexts.collect_statistics(st); - m_contexts2.collect_statistics(st); - m_contexts3.collect_statistics(st); + m_pool0->collect_statistics(st); + m_pool1->collect_statistics(st); + m_pool2->collect_statistics(st); } void reset_statistics() { - m_contexts.reset_statistics(); - m_contexts2.reset_statistics(); - m_contexts3.reset_statistics(); + m_pool0->reset_statistics(); + m_pool1->reset_statistics(); + m_pool2->reset_statistics(); } }; diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index a4ea79a25..6b29df074 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -55,8 +55,8 @@ prop_solver::prop_solver(spacer::manager& pm, m_use_push_bg(p.spacer_keep_proxy()) { - m_solvers[0] = pm.mk_fresh(); - m_solvers[1] = pm.mk_fresh2(); + m_solvers[0] = pm.mk_solver0(); + m_solvers[1] = pm.mk_solver1(); m_contexts[0] = alloc(spacer::iuc_solver, *(m_solvers[0]), p.spacer_iuc(), From 15d0fd4b4236a66c2511048cdeae64e820d705c6 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 15:35:46 -0700 Subject: [PATCH 1062/1283] spacer: removed virtual_solver This commit removes virtual_solver and smt_context_manager that have been migrated into solver_pool --- src/muz/spacer/CMakeLists.txt | 2 - src/muz/spacer/spacer_manager.h | 1 + src/muz/spacer/spacer_prop_solver.h | 1 - src/muz/spacer/spacer_smt_context_manager.cpp | 88 ----- src/muz/spacer/spacer_smt_context_manager.h | 69 ---- src/muz/spacer/spacer_virtual_solver.cpp | 333 ------------------ src/muz/spacer/spacer_virtual_solver.h | 150 -------- 7 files changed, 1 insertion(+), 643 deletions(-) delete mode 100644 src/muz/spacer/spacer_smt_context_manager.cpp delete mode 100644 src/muz/spacer/spacer_smt_context_manager.h delete mode 100644 src/muz/spacer/spacer_virtual_solver.cpp delete mode 100644 src/muz/spacer/spacer_virtual_solver.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index a7bc74b88..68464a40d 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -8,11 +8,9 @@ z3_add_component(spacer spacer_generalizers.cpp spacer_manager.cpp spacer_prop_solver.cpp - spacer_smt_context_manager.cpp spacer_sym_mux.cpp spacer_util.cpp spacer_iuc_solver.cpp - spacer_virtual_solver.cpp spacer_legacy_mbp.cpp spacer_proof_utils.cpp spacer_unsat_core_learner.cpp diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index f7d43ccb0..4c3d861cb 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -13,6 +13,7 @@ Abstract: Author: Krystof Hoder (t-khoder) 2011-8-25. + Arie Gurfinkel Revision History: diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index 27b2fd51d..e87732e94 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -30,7 +30,6 @@ Revision History: #include "util/util.h" #include "util/vector.h" #include "muz/spacer/spacer_manager.h" -#include "muz/spacer/spacer_smt_context_manager.h" #include "muz/spacer/spacer_iuc_solver.h" struct fixedpoint_params; diff --git a/src/muz/spacer/spacer_smt_context_manager.cpp b/src/muz/spacer/spacer_smt_context_manager.cpp deleted file mode 100644 index 78f01b6e5..000000000 --- a/src/muz/spacer/spacer_smt_context_manager.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - spacer_smt_context_manager.cpp - -Abstract: - - Manager of smt contexts - -Author: - - Nikolaj Bjorner (nbjorner) 2011-11-26. - Arie Gurfinkel -Revision History: - ---*/ - - -#include "ast/ast_pp.h" -#include "ast/ast_pp_util.h" -#include "ast/ast_smt_pp.h" - -#include "smt/smt_context.h" -#include "smt/params/smt_params.h" -#include "smt/smt_solver.h" - -#include "muz/spacer/spacer_util.h" -#include "muz/spacer/spacer_smt_context_manager.h" -namespace spacer { - -smt_context_manager::smt_context_manager(ast_manager &m, - unsigned max_num_contexts, - const params_ref &p) : - m(m), - m_params(p), - m_max_num_contexts(max_num_contexts), - m_num_contexts(0) { m_stats.reset();} - - -smt_context_manager::~smt_context_manager() -{ - std::for_each(m_solvers.begin(), m_solvers.end(), - delete_proc()); - m_solvers.reset(); - m_base_solvers.reset(); -} - -void smt_context_manager::updt_params(params_ref const &p) { - m_params.append(p); - for (auto *s : m_base_solvers) {s->updt_params(m_params);} -} - -virtual_solver* smt_context_manager::mk_fresh() -{ - ++m_num_contexts; - virtual_solver_factory *solver_factory = nullptr; - - if (m_max_num_contexts == 0 || m_solvers.size() < m_max_num_contexts) { - m_base_solvers.push_back(mk_smt_solver(m, m_params, symbol::null)); - m_solvers.push_back(alloc(spacer::virtual_solver_factory, - *m_base_solvers.back())); - solver_factory = m_solvers.back(); - } - else { - solver_factory = m_solvers[(m_num_contexts - 1) % m_max_num_contexts]; - } - - return solver_factory->mk_solver(); -} - -void smt_context_manager::collect_statistics(statistics& st) const -{ - for (unsigned i = 0; i < m_solvers.size(); ++i) { - m_solvers[i]->collect_statistics(st); - } -} - -void smt_context_manager::reset_statistics() -{ - for (unsigned i = 0; i < m_solvers.size(); ++i) { - m_solvers[i]->reset_statistics(); - } -} - - -}; diff --git a/src/muz/spacer/spacer_smt_context_manager.h b/src/muz/spacer/spacer_smt_context_manager.h deleted file mode 100644 index a62aba6cd..000000000 --- a/src/muz/spacer/spacer_smt_context_manager.h +++ /dev/null @@ -1,69 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - spacer_smt_context_manager.h - -Abstract: - - Manager of smt contexts - -Author: - - Nikolaj Bjorner (nbjorner) 2011-11-26. - Arie Gurfinkel -Revision History: - ---*/ - -#ifndef _SPACER_SMT_CONTEXT_MANAGER_H_ -#define _SPACER_SMT_CONTEXT_MANAGER_H_ - -#include "util/stopwatch.h" - -#include "smt/smt_kernel.h" -#include "muz/base/dl_util.h" -#include "muz/spacer/spacer_virtual_solver.h" - -namespace spacer { - -class smt_context_manager { - - struct stats { - unsigned m_num_smt_checks; - unsigned m_num_sat_smt_checks; - stats() { reset(); } - void reset() { memset(this, 0, sizeof(*this)); } - }; - - ast_manager& m; - params_ref m_params; - unsigned m_max_num_contexts; - sref_vector m_base_solvers; - ptr_vector m_solvers; - unsigned m_num_contexts; - - - stats m_stats; - stopwatch m_check_watch; - stopwatch m_check_sat_watch; - -public: - smt_context_manager(ast_manager& m, unsigned max_num_contexts = 1, - const params_ref &p = params_ref::get_empty()); - - ~smt_context_manager(); - virtual_solver* mk_fresh(); - - void collect_statistics(statistics& st) const; - void reset_statistics(); - - void updt_params(params_ref const &p); - - -}; - -}; - -#endif diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp deleted file mode 100644 index a1a1a7eec..000000000 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/** -Copyright (c) 2017 Arie Gurfinkel - -Module Name: - - spacer_virtual_solver.cpp - -Abstract: - - multi-solver view of a single solver - -Author: - - Arie Gurfinkel - -Notes: - ---*/ - -#include "muz/spacer/spacer_virtual_solver.h" -#include "ast/ast_util.h" -#include "ast/ast_pp_util.h" -#include "muz/spacer/spacer_util.h" -#include "ast/rewriter/bool_rewriter.h" - -#include "ast/proofs/proof_checker.h" -#include "ast/proofs/proof_utils.h" - -#include "ast/scoped_proof.h" - -#include "smt/smt_kernel.h" - -namespace spacer { -virtual_solver::virtual_solver(virtual_solver_factory &factory, app* pred) : - solver_na2as(factory.get_manager()), - m_factory(factory), - m(factory.get_manager()), - m_context(factory.get_base_solver()), - m_pred(pred, m), - m_virtual(!m.is_true(pred)), - m_assertions(m), - m_head(0), - m_flat(m), - m_pushed(false), - m_in_delay_scope(false), - m_dump_benchmarks(false /*factory.fparams().m_dump_benchmarks*/), - m_dump_counter(0), - m_proof(m) -{ - // -- insert m_pred->true background assumption this will not - // -- change m_context, but will add m_pred to - // -- the private field solver_na2as::m_assumptions - if (m_virtual) - { solver_na2as::assert_expr_core2(m.mk_true(), m_pred); } -} - -virtual_solver::~virtual_solver() -{ - SASSERT(!m_pushed || get_scope_level() > 0); - if (m_pushed) { pop(get_scope_level()); } - - if (m_virtual) { - m_pred = m.mk_not(m_pred); - m_context.assert_expr(m_pred); - } -} - -namespace { - - -// TBD: move to ast/proofs/elim_aux_assertions - - -} - -proof *virtual_solver::get_proof() -{ - scoped_watch _t_(m_factory.m_proof_watch); - - if (!m_proof.get()) { - elim_aux_assertions pc(m_pred); - m_proof = m_context.get_proof(); - pc(m, m_proof.get(), m_proof); - } - return m_proof.get(); -} - -bool virtual_solver::is_aux_predicate(expr *p) -{return is_app(p) && to_app(p) == m_pred.get();} - -lbool virtual_solver::check_sat_core(unsigned num_assumptions, - expr *const * assumptions) -{ - SASSERT(!m_pushed || get_scope_level() > 0); - m_proof.reset(); - scoped_watch _t_(m_factory.m_check_watch); - m_factory.m_stats.m_num_smt_checks++; - - stopwatch sw; - sw.start(); - internalize_assertions(); - if (false) { - std::stringstream file_name; - file_name << "virt_solver"; - if (m_virtual) { file_name << "_" << m_pred->get_decl()->get_name(); } - file_name << "_" << (m_dump_counter++) << ".smt2"; - - verbose_stream() << "Dumping SMT2 benchmark: " << file_name.str() << "\n"; - - std::ofstream out(file_name.str().c_str()); - - to_smt2_benchmark(out, m_context, num_assumptions, assumptions, - "virt_solver"); - - out << "(exit)\n"; - out.close(); - } - lbool res = m_context.check_sat(num_assumptions, assumptions); - sw.stop(); - if (res == l_true) { - m_factory.m_check_sat_watch.add(sw); - m_factory.m_stats.m_num_sat_smt_checks++; - } else if (res == l_undef) { - m_factory.m_check_undef_watch.add(sw); - m_factory.m_stats.m_num_undef_smt_checks++; - } - set_status(res); - - if (false /*m_dump_benchmarks && - sw.get_seconds() >= m_factory.fparams().m_dump_min_time*/) { - std::stringstream file_name; - file_name << "virt_solver"; - if (m_virtual) { file_name << "_" << m_pred->get_decl()->get_name(); } - file_name << "_" << (m_dump_counter++) << ".smt2"; - - std::ofstream out(file_name.str().c_str()); - - - out << "(set-info :status "; - if (res == l_true) { out << "sat"; } - else if (res == l_false) { out << "unsat"; } - else { out << "unknown"; } - out << ")\n"; - - to_smt2_benchmark(out, m_context, num_assumptions, assumptions, - "virt_solver"); - - out << "(exit)\n"; - ::statistics st; - m_context.collect_statistics(st); - st.update("time", sw.get_seconds()); - st.display_smt2(out); - - - if (false /* m_factory.fparams().m_dump_recheck */) { - scoped_no_proof _no_proof_(m); - smt_params p; - stopwatch sw2; - smt::kernel kernel(m, p); - for (unsigned i = 0, sz = m_context.get_num_assertions(); i < sz; ++i) - { kernel.assert_expr(m_context.get_assertion(i)); } - sw2.start(); - kernel.check(num_assumptions, assumptions); - sw2.stop(); - verbose_stream() << file_name.str() << " :orig " - << sw.get_seconds() << " :new " << sw2.get_seconds(); - - out << ";; :orig " << sw.get_seconds() - << " :new " << sw2.get_seconds() << "\n" - << ";; :new is time to solve with fresh smt::kernel\n"; - } - - out.close(); - } - - - return res; -} - -void virtual_solver::push_core() -{ - SASSERT(!m_pushed || get_scope_level() > 0); - if (m_in_delay_scope) { - // second push - internalize_assertions(); - m_context.push(); - m_pushed = true; - m_in_delay_scope = false; - } - - if (!m_pushed) { m_in_delay_scope = true; } - else { - SASSERT(m_pushed); - SASSERT(!m_in_delay_scope); - m_context.push(); - } -} -void virtual_solver::pop_core(unsigned n) { - SASSERT(!m_pushed || get_scope_level() > 0); - if (m_pushed) { - SASSERT(!m_in_delay_scope); - m_context.pop(n); - m_pushed = get_scope_level() - n > 0; - } - else { - m_in_delay_scope = get_scope_level() - n > 0; - } -} - -void virtual_solver::get_unsat_core(ptr_vector &r) -{ - ptr_vector core; - m_context.get_unsat_core(core); - - for (unsigned i = 0, sz = core.size(); i < sz; ++i) { - if (is_aux_predicate(core.get(i))) { continue; } - r.push_back(core.get(i)); - } -} - -void virtual_solver::assert_expr_core(expr *e) -{ - SASSERT(!m_pushed || get_scope_level() > 0); - if (m.is_true(e)) { return; } - if (m_in_delay_scope) { - internalize_assertions(); - m_context.push(); - m_pushed = true; - m_in_delay_scope = false; - } - - if (m_pushed) - { m_context.assert_expr(e); } - else { - m_flat.push_back(e); - flatten_and(m_flat); - m_assertions.append(m_flat); - m_flat.reset(); - } -} -void virtual_solver::internalize_assertions() -{ - SASSERT(!m_pushed || m_head == m_assertions.size()); - for (unsigned sz = m_assertions.size(); m_head < sz; ++m_head) { - expr_ref f(m); - f = m.mk_implies(m_pred, (m_assertions.get(m_head))); - m_context.assert_expr(f); - } -} - -void virtual_solver::get_labels(svector &r) -{m_context.get_labels(r);} - -solver* virtual_solver::translate(ast_manager& m, params_ref const& p) -{ - UNREACHABLE(); - return nullptr; -} -void virtual_solver::updt_params(params_ref const &p) {m_context.updt_params(p);} -void virtual_solver::reset_params(params_ref const &p) {m_context.reset_params(p);} -const params_ref &virtual_solver::get_params() const {return m_context.get_params();} -void virtual_solver::push_params(){m_context.push_params();} -void virtual_solver::pop_params(){m_context.pop_params();} -void virtual_solver::collect_param_descrs(param_descrs &r) { m_context.collect_param_descrs(r); } -void virtual_solver::set_produce_models(bool f) { m_context.set_produce_models(f); } - -void virtual_solver::to_smt2_benchmark(std::ostream &out, - solver &context, - unsigned num_assumptions, - expr * const * assumptions, - char const * name, - symbol const &logic, - char const * status, - char const * attributes) -{ - ast_pp_util pp(m); - expr_ref_vector asserts(m); - - context.get_assertions(asserts); - pp.collect(asserts); - pp.collect(num_assumptions, assumptions); - pp.display_decls(out); - pp.display_asserts(out, asserts); - out << "(check-sat "; - for (unsigned i = 0; i < num_assumptions; ++i) - { out << mk_pp(assumptions[i], m) << " "; } - out << ")\n"; -} - - -virtual_solver_factory::virtual_solver_factory(solver &base) : - m(base.get_manager()), m_context(base) {m_stats.reset();} - -virtual_solver* virtual_solver_factory::mk_solver() -{ - std::stringstream name; - name << "vsolver#" << m_solvers.size(); - app_ref pred(m); - pred = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); - SASSERT(m_context.get_scope_level() == 0); - m_solvers.push_back(alloc(virtual_solver, *this, pred)); - return m_solvers.back(); -} - -void virtual_solver_factory::collect_statistics(statistics &st) const -{ - m_context.collect_statistics(st); - st.update("time.virtual_solver.smt.total", m_check_watch.get_seconds()); - st.update("time.virtual_solver.smt.total.sat", m_check_sat_watch.get_seconds()); - st.update("time.virtual_solver.smt.total.undef", m_check_undef_watch.get_seconds()); - st.update("time.virtual_solver.proof", m_proof_watch.get_seconds()); - st.update("virtual_solver.checks", m_stats.m_num_smt_checks); - st.update("virtual_solver.checks.sat", m_stats.m_num_sat_smt_checks); - st.update("virtual_solver.checks.undef", m_stats.m_num_undef_smt_checks); -} -void virtual_solver_factory::reset_statistics() -{ - m_stats.reset(); - m_check_sat_watch.reset(); - m_check_undef_watch.reset(); - m_check_watch.reset(); - m_proof_watch.reset(); -} - -virtual_solver_factory::~virtual_solver_factory() -{ - for (unsigned i = 0, e = m_solvers.size(); i < e; ++i) - { dealloc(m_solvers[i]); } -} - - - -} diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h deleted file mode 100644 index e5db5e396..000000000 --- a/src/muz/spacer/spacer_virtual_solver.h +++ /dev/null @@ -1,150 +0,0 @@ -/** -Copyright (c) 2017 Arie Gurfinkel - -Module Name: - - spacer_virtual_solver.h - -Abstract: - - multi-solver view of a single solver - -Author: - - Arie Gurfinkel - -Notes: - ---*/ -#ifndef SPACER_VIRTUAL_SOLVER_H_ -#define SPACER_VIRTUAL_SOLVER_H_ -#include"ast/ast.h" -#include"util/params.h" -#include"solver/solver_na2as.h" -#include"smt/params/smt_params.h" -#include"util/stopwatch.h" -namespace spacer { -class virtual_solver_factory; - -class virtual_solver : public solver_na2as { - friend class virtual_solver_factory; - -private: - virtual_solver_factory &m_factory; - ast_manager &m; - solver &m_context; - app_ref m_pred; - - bool m_virtual; - expr_ref_vector m_assertions; - unsigned m_head; - // temporary to flatten conjunction - expr_ref_vector m_flat; - - bool m_pushed; - bool m_in_delay_scope; - bool m_dump_benchmarks; - unsigned m_dump_counter; - - proof_ref m_proof; - - virtual_solver(virtual_solver_factory &factory, app* pred); - - bool is_aux_predicate(expr *p); - void internalize_assertions(); - void to_smt2_benchmark(std::ostream &out, - solver &context, - unsigned num_assumptions, - expr * const * assumptions, - char const * name = "benchmarks", - symbol const &logic = symbol::null, - char const * status = "unknown", - char const * attributes = ""); - -public: - ~virtual_solver() override; - unsigned get_num_assumptions() const override - { - unsigned sz = solver_na2as::get_num_assumptions(); - return m_virtual ? sz - 1 : sz; - } - expr* get_assumption(unsigned idx) const override - { - if(m_virtual) { idx++; } - return solver_na2as::get_assumption(idx); - } - - - void get_unsat_core(ptr_vector &r) override; - void assert_expr_core(expr *e) override; - void collect_statistics(statistics &st) const override {m_context.collect_statistics(st);} - void get_model_core(model_ref &m) override {m_context.get_model(m);} - proof* get_proof() override; - std::string reason_unknown() const override - {return m_context.reason_unknown();} - void set_reason_unknown(char const *msg) override - {m_context.set_reason_unknown(msg);} - ast_manager& get_manager() const override {return m;} - void get_labels(svector &r) override; - void set_produce_models(bool f) override; - smt_params &fparams(); - expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } - void set_progress_callback(progress_callback *callback) override {UNREACHABLE();} - - solver *translate(ast_manager &m, params_ref const &p) override; - - void updt_params(params_ref const &p) override; - void reset_params(params_ref const& p) override; - params_ref const& get_params() const override; - void collect_param_descrs(param_descrs &r) override; - void push_params() override; - void pop_params() override; - - -protected: - lbool check_sat_core(unsigned num_assumptions, expr *const * assumptions) override; - void push_core() override; - void pop_core(unsigned n) override; -}; - -/// multi-solver abstraction on top of a single solver -class virtual_solver_factory { - friend class virtual_solver; -private: - ast_manager &m; - solver &m_context; - /// solvers managed by this factory - ptr_vector m_solvers; - - struct stats { - unsigned m_num_smt_checks; - unsigned m_num_sat_smt_checks; - unsigned m_num_undef_smt_checks; - stats() { reset(); } - void reset() { memset(this, 0, sizeof(*this)); } - }; - - stats m_stats; - stopwatch m_check_watch; - stopwatch m_check_sat_watch; - stopwatch m_check_undef_watch; - stopwatch m_proof_watch; - - - solver &get_base_solver() {return m_context;} - ast_manager &get_manager() {return m;} - -public: - virtual_solver_factory(solver &base); - virtual ~virtual_solver_factory(); - virtual_solver* mk_solver(); - void collect_statistics(statistics &st) const; - void reset_statistics(); - void updt_params(params_ref const &p) {m_context.updt_params(p);} - void collect_param_descrs(param_descrs &r) {m_context.collect_param_descrs(r);} -}; - -} - - -#endif From 14b9dd2cd71c9fb7f2b036fa4aa37e31a3666006 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 16:25:55 -0700 Subject: [PATCH 1063/1283] spacer: let pool_solver own the solver --- src/muz/spacer/spacer_manager.cpp | 15 +++++++++------ src/muz/spacer/spacer_manager.h | 3 --- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index a281cac81..d55f74b90 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -179,13 +179,16 @@ static std::vector state_suffixes() { manager::manager(unsigned max_num_contexts, ast_manager& manager) : m(manager), m_mux(m, state_suffixes()) { - m_pool0_base = mk_smt_solver(m, params_ref::get_empty(), symbol::null); - m_pool1_base = mk_smt_solver(m, params_ref::get_empty(), symbol::null); - m_pool2_base = mk_smt_solver(m, params_ref::get_empty(), symbol::null); + ref pool0_base = + mk_smt_solver(m, params_ref::get_empty(), symbol::null); + ref pool1_base = + mk_smt_solver(m, params_ref::get_empty(), symbol::null); + ref pool2_base = + mk_smt_solver(m, params_ref::get_empty(), symbol::null); - m_pool0 = alloc(solver_pool, m_pool0_base.get(), max_num_contexts); - m_pool1 = alloc(solver_pool, m_pool1_base.get(), max_num_contexts); - m_pool2 = alloc(solver_pool, m_pool2_base.get(), max_num_contexts); + m_pool0 = alloc(solver_pool, pool0_base.get(), max_num_contexts); + m_pool1 = alloc(solver_pool, pool1_base.get(), max_num_contexts); + m_pool2 = alloc(solver_pool, pool2_base.get(), max_num_contexts); } diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index 4c3d861cb..b8783369d 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -79,9 +79,6 @@ class manager { // manager of multiplexed names sym_mux m_mux; - ref m_pool0_base; - ref m_pool1_base; - ref m_pool2_base; // three solver pools for different queries scoped_ptr m_pool0; scoped_ptr m_pool1; From 80c39eb037c90ab905006aa3ee08cb967c098dfa Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 24 May 2018 21:53:01 -0700 Subject: [PATCH 1064/1283] Fix solver_pool::updt_params --- src/solver/solver_pool.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 88838639e..0aee5c3dc 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -284,6 +284,7 @@ ptr_vector solver_pool::get_base_solvers() const { } void solver_pool::updt_params(const params_ref &p) { + m_base_solver->updt_params(p); ptr_vector solvers = get_base_solvers(); for (solver *s : solvers) s->updt_params(p); } From 20300bbf94b03749a68615d01f56d941e2a90583 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 May 2018 13:06:47 -0700 Subject: [PATCH 1065/1283] updates to mbqi Signed-off-by: Nikolaj Bjorner Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_util.cpp | 62 +++++------ src/qe/qe_arrays.cpp | 181 ++++++++++++++++++++++++++++----- src/qe/qe_mbp.cpp | 56 +++++++++- 3 files changed, 237 insertions(+), 62 deletions(-) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index e2a1a2c3d..b45e0de4a 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -90,33 +90,33 @@ namespace spacer { if (!m_model) { return; } m_mev = alloc(model_evaluator, *m_model); } - + bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { m_mev->set_model_completion (model_completion); try { m_mev->operator() (e, result); return true; - } + } catch (model_evaluator_exception &ex) { (void)ex; TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); return false; } } - + bool model_evaluator_util::eval(const expr_ref_vector &v, expr_ref& res, bool model_completion) { expr_ref e(m); e = mk_and (v); return eval(e, res, model_completion); } - - + + bool model_evaluator_util::is_true(const expr_ref_vector &v) { expr_ref res(m); return eval (v, res, false) && m.is_true (res); } - + bool model_evaluator_util::is_false(expr *x) { expr_ref res(m); return eval(x, res, false) && m.is_false (res); @@ -126,7 +126,7 @@ namespace spacer { expr_ref res(m); return eval(x, res, false) && m.is_true (res); } - + void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { ast_manager& m = fml.get_manager(); expr_ref_vector conjs(m); @@ -172,16 +172,16 @@ namespace spacer { SASSERT(orig_size <= 1 + conjs.size()); if (i + 1 == orig_size) { // no-op. - } + } else if (orig_size <= conjs.size()) { // no-op - } + } else { SASSERT(orig_size == 1 + conjs.size()); --orig_size; --i; } - } + } else { conjs[i] = tmp; } @@ -199,7 +199,7 @@ namespace spacer { ast_manager& m; public: ite_hoister(ast_manager& m): m(m) {} - + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { if (m.is_ite(f)) { return BR_FAILED; @@ -234,7 +234,7 @@ namespace spacer { } ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} }; - + class ite_hoister_star : public rewriter_tpl { ite_hoister_cfg m_cfg; public: @@ -242,7 +242,7 @@ namespace spacer { rewriter_tpl(m, false, m_cfg), m_cfg(m, p) {} }; - + void hoist_non_bool_if(expr_ref& fml) { ast_manager& m = fml.get_manager(); scoped_no_proof _sp(m); @@ -274,7 +274,7 @@ namespace spacer { bool is_arith_expr(expr *e) const { return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); } - + bool is_offset(expr* e) const { if (a.is_numeral(e)) { return true; @@ -358,7 +358,7 @@ namespace spacer { !a.is_mul(lhs) && !a.is_mul(rhs); } - + bool test_term(expr* e) const { if (m.is_bool(e)) { return true; @@ -403,9 +403,9 @@ namespace spacer { public: test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} - + void test_for_utvpi() { m_test_for_utvpi = true; } - + void operator()(expr* e) { if (!m_is_dl) { return; @@ -422,7 +422,7 @@ namespace spacer { m_is_dl = test_term(a->get_arg(i)); } } - + if (!m_is_dl) { char const* msg = "non-diff: "; if (m_test_for_utvpi) { @@ -431,10 +431,10 @@ namespace spacer { IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); } } - + bool is_dl() const { return m_is_dl; } }; - + bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); expr_fast_mark1 mark; @@ -443,7 +443,7 @@ namespace spacer { } return test.is_dl(); } - + bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); test.test_for_utvpi(); @@ -455,7 +455,7 @@ namespace spacer { } - void subst_vars(ast_manager& m, + void subst_vars(ast_manager& m, app_ref_vector const& vars, model* M, expr_ref& fml) { expr_safe_replace sub (m); @@ -506,7 +506,7 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) flatten_and (fml, flat); fml = mk_and(flat); } - + // uncomment for benchmarks //to_mbp_benchmark(verbose_stream(), fml, vars); @@ -523,7 +523,7 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) qe_lite qe(m, p, false); qe (vars, fml); rw (fml); - + TRACE ("spacer_mbp", tout << "After qe_lite:\n"; tout << mk_pp (fml, m) << "\n"; @@ -531,7 +531,7 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) SASSERT (!m.is_false (fml)); - + // sort out vars into bools, arith (int/real), and arrays for (app* v : vars) { if (m.is_bool (v)) { @@ -545,7 +545,7 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) arith_vars.push_back (v); } } - + // substitute Booleans if (!bool_sub.empty()) { bool_sub (fml); @@ -555,13 +555,13 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); bool_sub.reset (); } - + TRACE ("spacer_mbp", tout << "Array vars:\n"; tout << array_vars;); - + vars.reset (); - + // project arrays { scoped_no_proof _sp (m); @@ -572,14 +572,14 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) srw (fml); SASSERT (!m.is_false (fml)); } - + TRACE ("spacer_mbp", tout << "extended model:\n"; model_pp (tout, *M); tout << "Auxiliary variables of index and value sorts:\n"; tout << vars; ); - + if (vars.empty()) { break; } } diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 4a70d1fcb..df5c7f44e 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -157,8 +157,8 @@ namespace qe { static bool is_eq(expr_ref_vector const& xs, expr_ref_vector const& ys) { for (unsigned i = 0; i < xs.size(); ++i) if (xs[i] != ys[i]) return false; - return true; - } + return true; + } static bool is_eq(vector const& xs, vector const& ys) { for (unsigned i = 0; i < xs.size(); ++i) if (xs[i] != ys[i]) return false; @@ -984,9 +984,9 @@ namespace qe { TRACE("qe", tout << "non-arithmetic index sort for Ackerman" << mk_pp(srt, m) << "\n";); // TBD: generalize to also bit-vectors. is_numeric = false; - } + } } - + unsigned start = m_idxs.size (); // append at the end for (app * a : sel_terms) { expr_ref_vector idxs(m, arity, a->get_args() + 1); @@ -1018,13 +1018,13 @@ namespace qe { } if (is_numeric) { - // sort reprs by their value and add a chain of strict inequalities - compare_idx cmp(*this); - std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); + // sort reprs by their value and add a chain of strict inequalities + compare_idx cmp(*this); + std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); for (unsigned i = start; i + 1 < m_idxs.size(); ++i) { - m_idx_lits.push_back (mk_lex_lt(m_idxs[i].idx, m_idxs[i+1].idx)); - } + m_idx_lits.push_back (mk_lex_lt(m_idxs[i].idx, m_idxs[i+1].idx)); } + } else if (arity == 1) { // create distinct constraint. expr_ref_vector xs(m); @@ -1163,12 +1163,12 @@ namespace qe { return BR_DONE; } return BR_FAILED; - } + } lbool compare(expr* x, expr* y) { NOT_IMPLEMENTED_YET(); return l_undef; - } + } }; struct indices { @@ -1181,10 +1181,10 @@ namespace qe { for (unsigned i = 0; i < n; ++i) { VERIFY(model.eval(vars[i], val)); m_values.push_back(val); - } + } } }; - + ast_manager& m; array_util a; scoped_ptr m_var; @@ -1194,6 +1194,67 @@ namespace qe { bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; + } + + bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { + + TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;); + m_var = alloc(contains_app, m, var); + + // reduce select-store redeces based on model. + // rw_cfg rw(m); + // rw(lits); + + // try first to solve for var. + if (solve_eq(model, vars, lits)) { + return true; + } + + app_ref_vector selects(m); + + // check that only non-select occurrences are in disequalities. + if (!check_diseqs(lits, selects)) { + TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";); + return false; + } + + // remove disequalities. + elim_diseqs(lits); + + // Ackerman reduction on remaining select occurrences + // either replace occurrences by model value or other node + // that is congruent to model value. + + ackermanize_select(model, selects, vars, lits); + + TRACE("qe", tout << selects << "\n" << lits << "\n";); + return true; + } + + void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) { + expr_ref_vector vals(m), reps(m); + expr_ref val(m); + expr_safe_replace sub(m); + + if (selects.empty()) { + return; + } + + app_ref sel(m); + for (unsigned i = 0; i < selects.size(); ++i) { + sel = m.mk_fresh_const("sel", m.get_sort(selects[i])); + VERIFY (model.eval(selects[i], val)); + model.register_decl(sel->get_decl(), val); + vals.push_back(to_app(val)); + reps.push_back(val); // TODO: direct pass could handle nested selects. + vars.push_back(sel); + sub.insert(selects[i], val); + } + + sub(lits); + remove_true(lits); + project_plugin::partition_args(model, selects, lits); + project_plugin::partition_values(model, reps, lits); } void remove_true(expr_ref_vector& lits) { @@ -1216,6 +1277,80 @@ namespace qe { } } + // check that x occurs only under selects or in disequalities. + bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) { + expr_mark mark; + ptr_vector todo; + app* e; + for (unsigned i = 0; i < lits.size(); ++i) { + e = to_app(lits[i]); + if (is_diseq_x(e)) { + continue; + } + if (contains_x(e)) { + todo.push_back(e); + } + } + while (!todo.empty()) { + e = todo.back(); + todo.pop_back(); + if (mark.is_marked(e)) { + continue; + } + mark.mark(e); + if (m_var->x() == e) { + return false; + } + unsigned start = 0; + if (a.is_select(e)) { + if (e->get_arg(0) == m_var->x()) { + start = 1; + selects.push_back(e); + } + } + for (unsigned i = start; i < e->get_num_args(); ++i) { + todo.push_back(to_app(e->get_arg(i))); + } + } + return true; + } + + void elim_diseqs(expr_ref_vector& lits) { + for (unsigned i = 0; i < lits.size(); ++i) { + if (is_diseq_x(lits[i].get())) { + project_plugin::erase(lits, i); + } + } + } + + bool is_update_x(app* e) { + do { + if (m_var->x() == e) { + return true; + } + if (a.is_store(e) && contains_x(e->get_arg(0))) { + for (unsigned i = 1; i < e->get_num_args(); ++i) { + if (contains_x(e->get_arg(i))) { + return false; + } + } + e = to_app(e->get_arg(0)); + continue; + } + } + while (false); + return false; + } + + bool is_diseq_x(expr* e) { + expr *f, * s, *t; + if (m.is_not(e, f) && m.is_eq(f, s, t)) { + if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true; + if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true; + } + return false; + } + bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { // find an equality to solve for. expr* s, *t; @@ -1367,13 +1502,7 @@ namespace qe { } bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { - ast_manager& m = vars.get_manager(); - app_ref_vector vvars(m, 1, &var); - expr_ref fml = mk_and(lits); - (*this)(model, vvars, fml, vars, false); - lits.reset(); - flatten_and(fml, lits); - return true; + return (*m_imp)(model, var, vars, lits); } bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { @@ -1390,11 +1519,11 @@ namespace qe { array_project_eqs_util pe (m); pe (mdl, arr_vars, fml, aux_vars); TRACE ("qe", - tout << "Projected array eqs: " << fml << "\n"; - tout << "Remaining array vars: " << arr_vars << "\n"; - tout << "Aux vars: " << aux_vars << "\n"; + tout << "Projected array eqs:\n" << fml << "\n"; + tout << "Remaining array vars:\n" << arr_vars; + tout << "Aux vars:\n" << aux_vars; ); - + // 2. reduce selects array_select_reducer rs (m); rs (mdl, arr_vars, fml, reduce_all_selects); @@ -1406,8 +1535,8 @@ namespace qe { ps (mdl, arr_vars, fml, aux_vars); TRACE ("qe", - tout << "Projected array selects: " << fml << "\n"; - tout << "All aux vars: " << aux_vars << "\n"; + tout << "Projected array selects:\n" << fml << "\n"; + tout << "All aux vars:\n" << aux_vars; ); } diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index b1c92cb8c..b07e9904c 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -77,6 +77,40 @@ expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) { return expr_ref(nullptr, m); } +void project_plugin::partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits) { + ast_manager& m = vals.get_manager(); + expr_ref val(m); + expr_ref_vector trail(m), reps(m); + obj_map roots; + for (unsigned i = 0; i < vals.size(); ++i) { + expr* v = vals[i], *root; + VERIFY (model.eval(v, val)); + if (roots.find(val, root)) { + lits.push_back(m.mk_eq(v, root)); + } + else { + roots.insert(val, v); + trail.push_back(val); + reps.push_back(v); + } + } + if (reps.size() > 1) { + lits.push_back(mk_distinct(reps)); + } +} + +void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) { + ast_manager& m = selects.get_manager(); + if (selects.empty()) return; + unsigned num_args = selects[0]->get_decl()->get_arity(); + for (unsigned j = 1; j < num_args; ++j) { + expr_ref_vector args(m); + for (unsigned i = 0; i < selects.size(); ++i) { + args.push_back(selects[i]->get_arg(j)); + } + project_plugin::partition_values(model, args, lits); + } +} void project_plugin::erase(expr_ref_vector& lits, unsigned& i) { lits[i] = lits.back(); @@ -100,6 +134,7 @@ class mbp::impl { // parameters bool m_reduce_all_selects; + bool m_native_mbp; bool m_dont_sub; void add_plugin(project_plugin* p) { @@ -287,7 +322,8 @@ class mbp::impl { void operator() (app *n) { expr *e1, *e2; if (m_array.is_select (n)) { - for (expr * arg : *n) { + for (unsigned i = 1; i < n->get_num_args(); ++i) { + expr * arg = n->get_arg(i); if (m.get_sort(arg) == m.get_sort(m_var) && arg != m_var) m_res.push_back (arg); } @@ -340,7 +376,8 @@ class mbp::impl { // -- evaluate to initialize eval cache (void) eval (fml); unsigned j = 0; - for (app * v : vars) { + for (unsigned i = 0; i < vars.size (); ++i) { + app* v = vars.get(i); if (!project_var (eval, v, fml)) { vars[j++] = v; } @@ -350,6 +387,7 @@ class mbp::impl { public: + opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { arith_project_plugin arith(m); return arith.maximize(fmls, mdl, t, ge, gt); @@ -490,6 +528,7 @@ public: void updt_params(params_ref const& p) { m_params.append(p); m_reduce_all_selects = m_params.get_bool("reduce_all_selects", false); + m_native_mbp = m_params.get_bool("native_mbp", false); m_dont_sub = m_params.get_bool("dont_sub", false); } @@ -508,7 +547,6 @@ public: bool validate_model(model& model, expr_ref_vector const& fmls) { expr_ref val(m); - model_evaluator eval(model); for (expr * f : fmls) { VERIFY(model.eval(f, val) && m.is_true(val)); } @@ -637,19 +675,26 @@ public: tout << "extended model:\n"; model_pp (tout, mdl); tout << "Auxiliary variables of index and value sorts:\n"; - tout << vars << "\n"; + tout << vars; ); } // project reals and ints if (!arith_vars.empty ()) { - TRACE ("qe", tout << "Arith vars: " << arith_vars << "\n";); + TRACE ("qe", tout << "Arith vars:\n" << arith_vars;); + if (m_native_mbp) { expr_ref_vector fmls(m); flatten_and (fml, fmls); (*this)(true, arith_vars, mdl, fmls); fml = mk_and (fmls); + SASSERT (arith_vars.empty ()); + } + else { + NOT_IMPLEMENTED_YET(); + // qe::arith_project (mdl, arith_vars, fml); + } TRACE ("qe", tout << "Projected arith vars:\n" << fml << "\n"; @@ -693,6 +738,7 @@ void mbp::updt_params(params_ref const& p) { void mbp::get_param_descrs(param_descrs & r) { r.insert("reduce_all_selects", CPK_BOOL, "(default: false) reduce selects"); + r.insert("native_mbp", CPK_BOOL, "(default: false) switch between native and spacer tailored mbp"); r.insert("dont_sub", CPK_BOOL, "(default: false) disable substitution of values for free variables"); } From 7642106e73ac9c534cc3f7b1a323da1feccbf86d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 May 2018 14:22:00 -0700 Subject: [PATCH 1066/1283] add way to unit test mbp from command line Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 2 +- src/qe/qe_arrays.cpp | 185 ++---------------------- src/qe/qe_mbp.cpp | 2 + src/qe/qe_mbp.h | 2 + 4 files changed, 17 insertions(+), 174 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index ceb979761..1b378f430 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -369,7 +369,7 @@ public: void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) override { m_vars.append(num, ts); } - void prepare(cmd_context & ctx) override { m_fml = nullptr; m_vars.reset(); } + void prepare(cmd_context & ctx) override { m_fml = nullptr; } void execute(cmd_context & ctx) override { ast_manager& m = ctx.m(); app_ref_vector vars(m); diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index df5c7f44e..e582676a8 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -631,13 +631,13 @@ namespace qe { m_v = arr_vars.get (i); if (!m_arr_u.is_array (m_v)) { TRACE ("qe", - tout << "not an array variable: " << mk_pp (m_v, m) << "\n"; + tout << "not an array variable: " << m_v << "\n"; ); aux_vars.push_back (m_v); continue; } TRACE ("qe", - tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n"; + tout << "projecting equalities on variable: " << m_v << "\n"; ); if (project (fml)) { @@ -653,8 +653,8 @@ namespace qe { ); } else { - IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";); - TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";); + IF_VERBOSE(2, verbose_stream() << "can't project:" << m_v << "\n";); + TRACE ("qe", tout << "Failed to project: " << m_v << "\n";); arr_vars[j++] = m_v; } } @@ -1196,67 +1196,6 @@ namespace qe { return false; } - bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { - - TRACE("qe", tout << mk_pp(var, m) << "\n" << lits;); - m_var = alloc(contains_app, m, var); - - // reduce select-store redeces based on model. - // rw_cfg rw(m); - // rw(lits); - - // try first to solve for var. - if (solve_eq(model, vars, lits)) { - return true; - } - - app_ref_vector selects(m); - - // check that only non-select occurrences are in disequalities. - if (!check_diseqs(lits, selects)) { - TRACE("qe", tout << "Could not project " << mk_pp(var, m) << " for:\n" << lits << "\n";); - return false; - } - - // remove disequalities. - elim_diseqs(lits); - - // Ackerman reduction on remaining select occurrences - // either replace occurrences by model value or other node - // that is congruent to model value. - - ackermanize_select(model, selects, vars, lits); - - TRACE("qe", tout << selects << "\n" << lits << "\n";); - return true; - } - - void ackermanize_select(model& model, app_ref_vector const& selects, app_ref_vector& vars, expr_ref_vector& lits) { - expr_ref_vector vals(m), reps(m); - expr_ref val(m); - expr_safe_replace sub(m); - - if (selects.empty()) { - return; - } - - app_ref sel(m); - for (unsigned i = 0; i < selects.size(); ++i) { - sel = m.mk_fresh_const("sel", m.get_sort(selects[i])); - VERIFY (model.eval(selects[i], val)); - model.register_decl(sel->get_decl(), val); - vals.push_back(to_app(val)); - reps.push_back(val); // TODO: direct pass could handle nested selects. - vars.push_back(sel); - sub.insert(selects[i], val); - } - - sub(lits); - remove_true(lits); - project_plugin::partition_args(model, selects, lits); - project_plugin::partition_values(model, reps, lits); - } - void remove_true(expr_ref_vector& lits) { for (unsigned i = 0; i < lits.size(); ++i) { if (m.is_true(lits[i].get())) { @@ -1275,113 +1214,7 @@ namespace qe { for (unsigned j = 0; j < n; ++j) { lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); } - } - - // check that x occurs only under selects or in disequalities. - bool check_diseqs(expr_ref_vector const& lits, app_ref_vector& selects) { - expr_mark mark; - ptr_vector todo; - app* e; - for (unsigned i = 0; i < lits.size(); ++i) { - e = to_app(lits[i]); - if (is_diseq_x(e)) { - continue; - } - if (contains_x(e)) { - todo.push_back(e); - } - } - while (!todo.empty()) { - e = todo.back(); - todo.pop_back(); - if (mark.is_marked(e)) { - continue; - } - mark.mark(e); - if (m_var->x() == e) { - return false; - } - unsigned start = 0; - if (a.is_select(e)) { - if (e->get_arg(0) == m_var->x()) { - start = 1; - selects.push_back(e); - } - } - for (unsigned i = start; i < e->get_num_args(); ++i) { - todo.push_back(to_app(e->get_arg(i))); - } - } - return true; - } - - void elim_diseqs(expr_ref_vector& lits) { - for (unsigned i = 0; i < lits.size(); ++i) { - if (is_diseq_x(lits[i].get())) { - project_plugin::erase(lits, i); - } - } - } - - bool is_update_x(app* e) { - do { - if (m_var->x() == e) { - return true; - } - if (a.is_store(e) && contains_x(e->get_arg(0))) { - for (unsigned i = 1; i < e->get_num_args(); ++i) { - if (contains_x(e->get_arg(i))) { - return false; - } - } - e = to_app(e->get_arg(0)); - continue; - } - } - while (false); - return false; - } - - bool is_diseq_x(expr* e) { - expr *f, * s, *t; - if (m.is_not(e, f) && m.is_eq(f, s, t)) { - if (contains_x(s) && !contains_x(t) && is_update_x(to_app(s))) return true; - if (contains_x(t) && !contains_x(s) && is_update_x(to_app(t))) return true; - } - return false; - } - - bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - // find an equality to solve for. - expr* s, *t; - for (unsigned i = 0; i < lits.size(); ++i) { - if (m.is_eq(lits[i].get(), s, t)) { - vector idxs; - expr_ref save(m), back(m); - save = lits[i].get(); - back = lits.back(); - lits[i] = back; - lits.pop_back(); - unsigned sz = lits.size(); - if (contains_x(s) && !contains_x(t) && is_app(s)) { - if (solve(model, to_app(s), t, idxs, vars, lits)) { - return true; - } - } - else if (contains_x(t) && !contains_x(s) && is_app(t)) { - if (solve(model, to_app(t), s, idxs, vars, lits)) { - return true; - } - } - // put back the equality literal. - lits.resize(sz); - lits.push_back(back); - lits[i] = save; - } - // TBD: not distinct? - } - return false; - } + } bool solve(model& model, app* s, expr* t, vector& idxs, app_ref_vector& vars, expr_ref_vector& lits) { SASSERT(contains_x(s)); @@ -1502,7 +1335,13 @@ namespace qe { } bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { - return (*m_imp)(model, var, vars, lits); + ast_manager& m = vars.get_manager(); + app_ref_vector vvars(m, 1, &var); + expr_ref fml = mk_and(lits); + (*this)(model, vvars, fml, vars, false); + lits.reset(); + flatten_and(fml, lits); + return true; } bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index b07e9904c..58eb77bb4 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -99,6 +99,7 @@ void project_plugin::partition_values(model& model, expr_ref_vector const& vals, } } +#if 0 void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) { ast_manager& m = selects.get_manager(); if (selects.empty()) return; @@ -111,6 +112,7 @@ void project_plugin::partition_args(model& model, app_ref_vector const& selects, project_plugin::partition_values(model, args, lits); } } +#endif void project_plugin::erase(expr_ref_vector& lits, unsigned& i) { lits[i] = lits.back(); diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 25a95e885..665e25d48 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -40,6 +40,8 @@ namespace qe { virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { }; static expr_ref pick_equality(ast_manager& m, model& model, expr* t); + static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); + //static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); static void erase(expr_ref_vector& lits, unsigned& i); static void push_back(expr_ref_vector& lits, expr* lit); static void mark_rec(expr_mark& visited, expr* e); From 692a701516985b18eb6456e4742b4c993420d601 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 May 2018 16:53:33 -0700 Subject: [PATCH 1067/1283] updates to mbp Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 2 +- src/qe/qe_arrays.cpp | 72 ++++++++++++++++++------- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 1b378f430..ceb979761 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -369,7 +369,7 @@ public: void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) override { m_vars.append(num, ts); } - void prepare(cmd_context & ctx) override { m_fml = nullptr; } + void prepare(cmd_context & ctx) override { m_fml = nullptr; m_vars.reset(); } void execute(cmd_context & ctx) override { ast_manager& m = ctx.m(); app_ref_vector vars(m); diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index e582676a8..614aab35a 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -157,8 +157,8 @@ namespace qe { static bool is_eq(expr_ref_vector const& xs, expr_ref_vector const& ys) { for (unsigned i = 0; i < xs.size(); ++i) if (xs[i] != ys[i]) return false; - return true; - } + return true; + } static bool is_eq(vector const& xs, vector const& ys) { for (unsigned i = 0; i < xs.size(); ++i) if (xs[i] != ys[i]) return false; @@ -631,13 +631,13 @@ namespace qe { m_v = arr_vars.get (i); if (!m_arr_u.is_array (m_v)) { TRACE ("qe", - tout << "not an array variable: " << m_v << "\n"; + tout << "not an array variable: " << mk_pp (m_v, m) << "\n"; ); aux_vars.push_back (m_v); continue; } TRACE ("qe", - tout << "projecting equalities on variable: " << m_v << "\n"; + tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n"; ); if (project (fml)) { @@ -653,8 +653,8 @@ namespace qe { ); } else { - IF_VERBOSE(2, verbose_stream() << "can't project:" << m_v << "\n";); - TRACE ("qe", tout << "Failed to project: " << m_v << "\n";); + IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";); + TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";); arr_vars[j++] = m_v; } } @@ -984,9 +984,9 @@ namespace qe { TRACE("qe", tout << "non-arithmetic index sort for Ackerman" << mk_pp(srt, m) << "\n";); // TBD: generalize to also bit-vectors. is_numeric = false; - } + } } - + unsigned start = m_idxs.size (); // append at the end for (app * a : sel_terms) { expr_ref_vector idxs(m, arity, a->get_args() + 1); @@ -1018,13 +1018,13 @@ namespace qe { } if (is_numeric) { - // sort reprs by their value and add a chain of strict inequalities - compare_idx cmp(*this); - std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); + // sort reprs by their value and add a chain of strict inequalities + compare_idx cmp(*this); + std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); for (unsigned i = start; i + 1 < m_idxs.size(); ++i) { - m_idx_lits.push_back (mk_lex_lt(m_idxs[i].idx, m_idxs[i+1].idx)); + m_idx_lits.push_back (mk_lex_lt(m_idxs[i].idx, m_idxs[i+1].idx)); + } } - } else if (arity == 1) { // create distinct constraint. expr_ref_vector xs(m); @@ -1163,12 +1163,12 @@ namespace qe { return BR_DONE; } return BR_FAILED; - } + } lbool compare(expr* x, expr* y) { NOT_IMPLEMENTED_YET(); return l_undef; - } + } }; struct indices { @@ -1181,10 +1181,10 @@ namespace qe { for (unsigned i = 0; i < n; ++i) { VERIFY(model.eval(vars[i], val)); m_values.push_back(val); - } + } } }; - + ast_manager& m; array_util a; scoped_ptr m_var; @@ -1194,7 +1194,7 @@ namespace qe { bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; - } + } void remove_true(expr_ref_vector& lits) { for (unsigned i = 0; i < lits.size(); ++i) { @@ -1214,7 +1214,39 @@ namespace qe { for (unsigned j = 0; j < n; ++j) { lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); } - } + } + + bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + // find an equality to solve for. + expr* s, *t; + for (unsigned i = 0; i < lits.size(); ++i) { + if (m.is_eq(lits[i].get(), s, t)) { + vector idxs; + expr_ref save(m), back(m); + save = lits[i].get(); + back = lits.back(); + lits[i] = back; + lits.pop_back(); + unsigned sz = lits.size(); + if (contains_x(s) && !contains_x(t) && is_app(s)) { + if (solve(model, to_app(s), t, idxs, vars, lits)) { + return true; + } + } + else if (contains_x(t) && !contains_x(s) && is_app(t)) { + if (solve(model, to_app(t), s, idxs, vars, lits)) { + return true; + } + } + // put back the equality literal. + lits.resize(sz); + lits.push_back(back); + lits[i] = save; + } + // TBD: not distinct? + } + return false; + } bool solve(model& model, app* s, expr* t, vector& idxs, app_ref_vector& vars, expr_ref_vector& lits) { SASSERT(contains_x(s)); @@ -1362,7 +1394,7 @@ namespace qe { tout << "Remaining array vars:\n" << arr_vars; tout << "Aux vars:\n" << aux_vars; ); - + // 2. reduce selects array_select_reducer rs (m); rs (mdl, arr_vars, fml, reduce_all_selects); From 560a26127e17ce8f3c564cf884c8968ea83a8199 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 May 2018 20:11:29 -0700 Subject: [PATCH 1068/1283] bind nested variables Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arith.cpp | 2 +- src/qe/qe_arrays.cpp | 10 ++--- src/qe/qe_mbp.cpp | 90 +++++++++++--------------------------------- src/qe/qe_mbp.h | 2 - 4 files changed, 27 insertions(+), 77 deletions(-) diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index f663d1b6c..0623bc8bb 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -415,7 +415,7 @@ namespace qe { break; } } - fmls.push_back(t); + fmls.push_back(t); val = eval(t); CTRACE("qe", !m.is_true(val), tout << "Evaluated " << t << " to " << val << "\n";); } diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 614aab35a..4a70d1fcb 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -1390,9 +1390,9 @@ namespace qe { array_project_eqs_util pe (m); pe (mdl, arr_vars, fml, aux_vars); TRACE ("qe", - tout << "Projected array eqs:\n" << fml << "\n"; - tout << "Remaining array vars:\n" << arr_vars; - tout << "Aux vars:\n" << aux_vars; + tout << "Projected array eqs: " << fml << "\n"; + tout << "Remaining array vars: " << arr_vars << "\n"; + tout << "Aux vars: " << aux_vars << "\n"; ); // 2. reduce selects @@ -1406,8 +1406,8 @@ namespace qe { ps (mdl, arr_vars, fml, aux_vars); TRACE ("qe", - tout << "Projected array selects:\n" << fml << "\n"; - tout << "All aux vars:\n" << aux_vars; + tout << "Projected array selects: " << fml << "\n"; + tout << "All aux vars: " << aux_vars << "\n"; ); } diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 58eb77bb4..72348d457 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -77,42 +77,6 @@ expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) { return expr_ref(nullptr, m); } -void project_plugin::partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits) { - ast_manager& m = vals.get_manager(); - expr_ref val(m); - expr_ref_vector trail(m), reps(m); - obj_map roots; - for (unsigned i = 0; i < vals.size(); ++i) { - expr* v = vals[i], *root; - VERIFY (model.eval(v, val)); - if (roots.find(val, root)) { - lits.push_back(m.mk_eq(v, root)); - } - else { - roots.insert(val, v); - trail.push_back(val); - reps.push_back(v); - } - } - if (reps.size() > 1) { - lits.push_back(mk_distinct(reps)); - } -} - -#if 0 -void project_plugin::partition_args(model& model, app_ref_vector const& selects, expr_ref_vector& lits) { - ast_manager& m = selects.get_manager(); - if (selects.empty()) return; - unsigned num_args = selects[0]->get_decl()->get_arity(); - for (unsigned j = 1; j < num_args; ++j) { - expr_ref_vector args(m); - for (unsigned i = 0; i < selects.size(); ++i) { - args.push_back(selects[i]->get_arg(j)); - } - project_plugin::partition_values(model, args, lits); - } -} -#endif void project_plugin::erase(expr_ref_vector& lits, unsigned& i) { lits[i] = lits.back(); @@ -127,16 +91,15 @@ void project_plugin::push_back(expr_ref_vector& lits, expr* e) { class mbp::impl { - ast_manager& m; + ast_manager& m; params_ref m_params; - th_rewriter m_rw; + th_rewriter m_rw; ptr_vector m_plugins; - expr_mark m_visited; - expr_mark m_bool_visited; - + expr_mark m_visited; + expr_mark m_bool_visited; + // parameters bool m_reduce_all_selects; - bool m_native_mbp; bool m_dont_sub; void add_plugin(project_plugin* p) { @@ -282,33 +245,33 @@ class mbp::impl { } else { vars[j++] = var; - } } + } if (j == vars.size()) { return; } vars.shrink(j); - j = 0; - for (unsigned i = 0; i < fmls.size(); ++i) { + j = 0; + for (unsigned i = 0; i < fmls.size(); ++i) { expr* fml = fmls[i].get(); sub(fml, val); - m_rw(val); - if (!m.is_true(val)) { + m_rw(val); + if (!m.is_true(val)) { TRACE("qe", tout << mk_pp(fml, m) << " -> " << val << "\n";); fmls[j++] = val; - } - } - fmls.shrink(j); } + } + fmls.shrink(j); + } void subst_vars(model_evaluator& eval, app_ref_vector const& vars, expr_ref& fml) { expr_safe_replace sub (m); for (app * v : vars) { sub.insert(v, eval(v)); - } - sub(fml); } + sub(fml); + } struct index_term_finder { ast_manager& m; @@ -324,8 +287,7 @@ class mbp::impl { void operator() (app *n) { expr *e1, *e2; if (m_array.is_select (n)) { - for (unsigned i = 1; i < n->get_num_args(); ++i) { - expr * arg = n->get_arg(i); + for (expr * arg : *n) { if (m.get_sort(arg) == m.get_sort(m_var) && arg != m_var) m_res.push_back (arg); } @@ -378,8 +340,7 @@ class mbp::impl { // -- evaluate to initialize eval cache (void) eval (fml); unsigned j = 0; - for (unsigned i = 0; i < vars.size (); ++i) { - app* v = vars.get(i); + for (app * v : vars) { if (!project_var (eval, v, fml)) { vars[j++] = v; } @@ -389,7 +350,6 @@ class mbp::impl { public: - opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { arith_project_plugin arith(m); return arith.maximize(fmls, mdl, t, ge, gt); @@ -530,7 +490,6 @@ public: void updt_params(params_ref const& p) { m_params.append(p); m_reduce_all_selects = m_params.get_bool("reduce_all_selects", false); - m_native_mbp = m_params.get_bool("native_mbp", false); m_dont_sub = m_params.get_bool("dont_sub", false); } @@ -549,6 +508,7 @@ public: bool validate_model(model& model, expr_ref_vector const& fmls) { expr_ref val(m); + model_evaluator eval(model); for (expr * f : fmls) { VERIFY(model.eval(f, val) && m.is_true(val)); } @@ -677,26 +637,19 @@ public: tout << "extended model:\n"; model_pp (tout, mdl); tout << "Auxiliary variables of index and value sorts:\n"; - tout << vars; + tout << vars << "\n"; ); } // project reals and ints if (!arith_vars.empty ()) { - TRACE ("qe", tout << "Arith vars:\n" << arith_vars;); + TRACE ("qe", tout << "Arith vars: " << arith_vars << "\n";); - if (m_native_mbp) { expr_ref_vector fmls(m); flatten_and (fml, fmls); (*this)(true, arith_vars, mdl, fmls); fml = mk_and (fmls); - SASSERT (arith_vars.empty ()); - } - else { - NOT_IMPLEMENTED_YET(); - // qe::arith_project (mdl, arith_vars, fml); - } TRACE ("qe", tout << "Projected arith vars:\n" << fml << "\n"; @@ -733,14 +686,13 @@ mbp::mbp(ast_manager& m, params_ref const& p) { mbp::~mbp() { dealloc(m_impl); } - + void mbp::updt_params(params_ref const& p) { m_impl->updt_params(p); } void mbp::get_param_descrs(param_descrs & r) { r.insert("reduce_all_selects", CPK_BOOL, "(default: false) reduce selects"); - r.insert("native_mbp", CPK_BOOL, "(default: false) switch between native and spacer tailored mbp"); r.insert("dont_sub", CPK_BOOL, "(default: false) disable substitution of values for free variables"); } diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 665e25d48..25a95e885 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -40,8 +40,6 @@ namespace qe { virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { }; static expr_ref pick_equality(ast_manager& m, model& model, expr* t); - static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); - //static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); static void erase(expr_ref_vector& lits, unsigned& i); static void push_back(expr_ref_vector& lits, expr* lit); static void mark_rec(expr_mark& visited, expr* e); From 5eacb8122dabf1e0f753152c311c7c08ac253ea2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 08:31:19 -0700 Subject: [PATCH 1069/1283] add tuple features, remove dead code from mbp Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arrays.cpp | 170 ++++++++++++++++++++++--------------------- src/qe/qe_mbp.cpp | 12 +-- 2 files changed, 94 insertions(+), 88 deletions(-) diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 4a70d1fcb..1701ce742 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -172,6 +172,17 @@ namespace qe { return mk_and(eqs); } + /** + * 1. Extract all equalities (store (store .. (store x i1 v1) i2 v2) .. ) = ... + * where x appears and the equalities do not evaluate to false in the current model. + * 2. Track them as partial equivalence relations. + * 3. Sort them according to nesting depth. + * 4. Solve for x by potentially introducing fresh variables. + * Thus, (store x i v) = y, then + * x = (store y i w), (select y i) = v, where w is fresh and evaluates to (select x i). + * Generally, equalities are tracked as x =_idxs y, where x, y are equal up to idxs. + */ + class array_project_eqs_util { ast_manager& m; array_util m_arr_u; @@ -551,9 +562,7 @@ namespace qe { svector > true_eqs; find_arr_eqs (fml, eqs); - TRACE ("qe", - tout << "array equalities:\n"; - for (app * eq : eqs) tout << mk_pp(eq, m) << "\n";); + TRACE ("qe", tout << "array equalities:\n" << eqs << "\n";); // evaluate eqs in M for (app * eq : eqs) { @@ -625,20 +634,18 @@ namespace qe { M = &mdl; m_mev = &mev; - unsigned j = 0; + unsigned j = 0; for (unsigned i = 0; i < arr_vars.size (); i++) { reset_v (); m_v = arr_vars.get (i); if (!m_arr_u.is_array (m_v)) { TRACE ("qe", - tout << "not an array variable: " << mk_pp (m_v, m) << "\n"; + tout << "not an array variable: " << m_v << "\n"; ); aux_vars.push_back (m_v); continue; } - TRACE ("qe", - tout << "projecting equalities on variable: " << mk_pp (m_v, m) << "\n"; - ); + TRACE ("qe", tout << "projecting equalities on variable: " << m_v << "\n"; ); if (project (fml)) { mk_result (fml); @@ -647,14 +654,11 @@ namespace qe { if (!m_subst_term_v || contains_v (m_subst_term_v)) { arr_vars[j++] = m_v; } - TRACE ("qe", - tout << "after projection: \n"; - tout << mk_pp (fml, m) << "\n"; - ); + TRACE ("qe", tout << "after projection: \n" << fml << "\n";); } else { - IF_VERBOSE(2, verbose_stream() << "can't project:" << mk_pp(m_v, m) << "\n";); - TRACE ("qe", tout << "Failed to project: " << mk_pp (m_v, m) << "\n";); + IF_VERBOSE(2, verbose_stream() << "can't project:" << m_v << "\n";); + TRACE ("qe", tout << "Failed to project: " << m_v << "\n";); arr_vars[j++] = m_v; } } @@ -663,6 +667,10 @@ namespace qe { } }; + /** + * Eliminate (select (store ..) ..) redexes by evaluating indices under model M. + * This does not eliminate variables, but introduces additional constraints on index equalities. + */ class array_select_reducer { ast_manager& m; @@ -787,6 +795,11 @@ namespace qe { return true; } + /** + * \brief reduce (select (store (store x i1 v1) i2 v2) idx) under model M + * such that the result is v2 if idx = i2 under M, it is v1 if idx = i1, idx != i2 under M, + * and it is (select x idx) if idx != i1, idx !+ i2 under M. + */ expr* reduce_core (app *a) { if (!m_arr_u.is_store (a->get_arg (0))) return a; unsigned arity = get_array_arity(m.get_sort(a)); @@ -864,6 +877,17 @@ namespace qe { } }; + /** + * Perform Ackerman reduction on arrays. + * for occurrences (select a i1), (select a i2), ... assuming these are all occurrences. + * - collect i1, i2, i3, into equivalence classes according to M + * - for distinct index classes accumulate constraint i1 < i2 < i3 .. (for arithmetic) + * and generally distinct(i1, i2, i3) for arbitrary index sorts. + * - for equal indices accumulate constraint i1 = i2, i3 = i5, .. + * - introduce variables v1, v2, .., for each equivalence class. + * - replace occurrences of select by v1, v2, ... + * - update M to evaluate v1, v2, the same as (select a i1) (select a i2) + */ class array_project_selects_util { typedef obj_map*> sel_map; @@ -882,9 +906,10 @@ namespace qe { ast_manager& m; array_util m_arr_u; arith_util m_ari_u; + bv_util m_bv_u; sel_map m_sel_terms; // representative indices for eliminating selects - vector m_idxs; + vector m_idxs; app_ref_vector m_sel_consts; expr_ref_vector m_idx_lits; model_ref M; @@ -934,7 +959,15 @@ namespace qe { vector rs; rational r; for (expr* v : vals) { - VERIFY (m_ari_u.is_numeral(v, r)); + if (m_bv_u.is_bv(v)) { + VERIFY (m_bv_u.is_numeral(v, r)); + } + else if (m_ari_u.is_real(v) || m_ari_u.is_int(v)) { + VERIFY (m_ari_u.is_numeral(v, r)); + } + else { + r.reset(); + } rs.push_back(r); } return rs; @@ -955,11 +988,20 @@ namespace qe { } }; + expr* mk_lt(expr* x, expr* y) { + if (m_bv_u.is_bv(x)) { + return m.mk_not(m_bv_u.mk_ule(y, x)); + } + else { + return m_ari_u.mk_lt(x, y); + } + } + expr_ref mk_lex_lt(expr_ref_vector const& xs, expr_ref_vector const& ys) { SASSERT(xs.size() == ys.size() && !xs.empty()); - expr_ref result(m_ari_u.mk_lt(xs.back(), ys.back()), m); + expr_ref result(mk_lt(xs.back(), ys.back()), m); for (unsigned i = xs.size()-1; i-- > 0; ) { - result = m.mk_or(m_ari_u.mk_lt(xs[i], ys[i]), + result = m.mk_or(mk_lt(xs[i], ys[i]), m.mk_and(m.mk_eq(xs[i], ys[i]), result)); } return result; @@ -980,9 +1022,8 @@ namespace qe { bool is_numeric = true; for (unsigned i = 0; i < arity && is_numeric; ++i) { sort* srt = get_array_domain(v_sort, i); - if (!m_ari_u.is_real(srt) && !m_ari_u.is_int(srt)) { - TRACE("qe", tout << "non-arithmetic index sort for Ackerman" << mk_pp(srt, m) << "\n";); - // TBD: generalize to also bit-vectors. + if (!m_ari_u.is_real(srt) && !m_ari_u.is_int(srt) && !m_bv_u.is_bv_sort(srt)) { + TRACE("qe", tout << "non-numeric index sort for Ackerman" << mk_pp(srt, m) << "\n";); is_numeric = false; } } @@ -1017,7 +1058,10 @@ namespace qe { } } - if (is_numeric) { + if (start + 1 == m_idxs.size()) { + // nothing to differentiate. + } + else if (is_numeric) { // sort reprs by their value and add a chain of strict inequalities compare_idx cmp(*this); std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); @@ -1034,8 +1078,26 @@ namespace qe { m_idx_lits.push_back(m.mk_distinct(xs.size(), xs.c_ptr())); } else { - NOT_IMPLEMENTED_YET(); - // use a tuple. + datatype::util dt(m); + sort_ref_vector srts(m); + ptr_vector acc; + unsigned i = 0; + for (expr * x : m_idxs[0].idx) { + std::stringstream name; + name << "get" << (i++); + acc.push_back(mk_accessor_decl(m, symbol(name.str().c_str()), type_ref(m.get_sort(x)))); + } + constructor_decl* constrs[1] = { mk_constructor_decl(symbol("tuple"), symbol("is-tuple"), acc.size(), acc.c_ptr()) }; + datatype::def* dts = mk_datatype_decl(dt, symbol("tuple"), 0, nullptr, 1, constrs); + VERIFY(dt.get_plugin()->mk_datatypes(1, &dts, 0, nullptr, srts)); + del_datatype_decl(dts); + sort* tuple = srts.get(0); + ptr_vector const & decls = *dt.get_datatype_constructors(tuple); + expr_ref_vector xs(m); + for (unsigned i = start; i < m_idxs.size(); ++i) { + xs.push_back(m.mk_app(decls[0], m_idxs[i].idx.size(), m_idxs[i].idx.c_ptr())); + } + m_idx_lits.push_back(m.mk_distinct(xs.size(), xs.c_ptr())); } } @@ -1072,6 +1134,7 @@ namespace qe { m (m), m_arr_u (m), m_ari_u (m), + m_bv_u (m), m_sel_consts (m), m_idx_lits (m), m_sub (m) @@ -1112,65 +1175,6 @@ namespace qe { struct array_project_plugin::imp { - // rewriter or direct procedure. - struct rw_cfg : public default_rewriter_cfg { - ast_manager& m; - array_util& a; - expr_ref_vector m_lits; - model* m_model; - imp* m_imp; - - rw_cfg(ast_manager& m, array_util& a): - m(m), a(a), m_lits(m), m_model(nullptr) {} - - br_status reduce_app(func_decl* f, unsigned n, expr* const* args, expr_ref& result, proof_ref & pr) { - if (a.is_select(f) && a.is_store(args[0])) { - expr_ref val1(m), val2(m); - app* b = to_app(args[0]); - SASSERT(b->get_num_args() == n + 1); - for (unsigned i = 1; i < n; ++i) { - expr* arg1 = args[i]; - expr* arg2 = b->get_arg(i); - if (arg1 == arg2) { - val1 = val2 = arg1; - } - else { - VERIFY(m_model->eval(arg1, val1)); - VERIFY(m_model->eval(arg2, val2)); - } - switch(compare(val1, val2)) { - case l_true: - if (arg1 != arg2) { - m_lits.push_back(m.mk_eq(arg1, arg2)); - } - break; - case l_false: { - ptr_vector new_args; - if (i > 0) { - m_lits.resize(m_lits.size() - i); - } - m_lits.push_back(m.mk_not(m.mk_eq(arg1, arg2))); - new_args.push_back(b->get_arg(0)); - new_args.append(n-1, args+1); - result = m.mk_app(f, n, new_args.c_ptr()); - return BR_REWRITE1; - } - case l_undef: - return BR_FAILED; - } - } - result = b->get_arg(n); - return BR_DONE; - } - return BR_FAILED; - } - - lbool compare(expr* x, expr* y) { - NOT_IMPLEMENTED_YET(); - return l_undef; - } - }; - struct indices { expr_ref_vector m_values; expr* const* m_vars; diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 72348d457..94c2d36aa 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -578,7 +578,7 @@ public: qe_lite qe(m, m_params, false); qe (vars, fml); m_rw (fml); - TRACE ("qe", tout << "After qe_lite:\n" << fml << "\n" << "Vars:\n" << vars;); + TRACE ("qe", tout << "After qe_lite:\n" << fml << "\n" << "Vars: " << vars << "\n";); SASSERT (!m.is_false (fml)); } @@ -590,7 +590,7 @@ public: } void spacer(app_ref_vector& vars, model& mdl, expr_ref& fml) { - TRACE ("qe", tout << "Before projection:\n" << fml << "\n" << "Vars:\n" << vars;); + TRACE ("qe", tout << "Before projection:\n" << fml << "\n" << "Vars: " << vars << "\n";); model_evaluator eval(mdl, m_params); eval.set_model_completion(true); @@ -620,7 +620,7 @@ public: } } - TRACE ("qe", tout << "Array vars:\n" << array_vars;); + TRACE ("qe", tout << "Array vars: " << array_vars << "\n";); vars.reset (); @@ -636,14 +636,16 @@ public: TRACE ("qe", tout << "extended model:\n"; model_pp (tout, mdl); - tout << "Auxiliary variables of index and value sorts:\n"; + tout << "Vars: "; tout << vars << "\n"; ); } // project reals and ints if (!arith_vars.empty ()) { - TRACE ("qe", tout << "Arith vars: " << arith_vars << "\n";); + TRACE ("qe", tout << "Arith vars: " << arith_vars << "\n"; + model_pp(tout, mdl); + ); expr_ref_vector fmls(m); flatten_and (fml, fmls); From 92bac11778aa29537ccb6db4d3ff1792d4a13714 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 15:57:18 -0700 Subject: [PATCH 1070/1283] update to make variables work with other theories Signed-off-by: Nikolaj Bjorner --- src/qe/qe_bool_plugin.cpp | 24 ++++------ src/qe/qe_mbp.cpp | 99 +++++++++++++++++---------------------- 2 files changed, 51 insertions(+), 72 deletions(-) diff --git a/src/qe/qe_bool_plugin.cpp b/src/qe/qe_bool_plugin.cpp index fba76a7e6..f8bac21c8 100644 --- a/src/qe/qe_bool_plugin.cpp +++ b/src/qe/qe_bool_plugin.cpp @@ -93,10 +93,8 @@ namespace qe { bool solve_units(conj_enum& conjs, expr* _fml) { expr_ref fml(_fml, m); - conj_enum::iterator it = conjs.begin(), end = conjs.end(); unsigned idx; - for (; it != end; ++it) { - expr* e = *it; + for (expr * e : conjs) { if (!is_app(e)) { continue; } @@ -138,13 +136,11 @@ namespace qe { return false; } else if (p && !n) { - atom_set::iterator it = m_ctx.pos_atoms().begin(), end = m_ctx.pos_atoms().end(); - for (; it != end; ++it) { - if (x != *it && contains_x(*it)) return false; + for (expr* y : m_ctx.pos_atoms()) { + if (x != y && contains_x(y)) return false; } - it = m_ctx.neg_atoms().begin(), end = m_ctx.neg_atoms().end(); - for (; it != end; ++it) { - if (contains_x(*it)) return false; + for (expr* y : m_ctx.neg_atoms()) { + if (contains_x(y)) return false; } // only occurrences of 'x' must be in positive atoms def = m.mk_true(); @@ -152,13 +148,11 @@ namespace qe { return true; } else if (!p && n) { - atom_set::iterator it = m_ctx.pos_atoms().begin(), end = m_ctx.pos_atoms().end(); - for (; it != end; ++it) { - if (contains_x(*it)) return false; + for (expr* y : m_ctx.pos_atoms()) { + if (contains_x(y)) return false; } - it = m_ctx.neg_atoms().begin(), end = m_ctx.neg_atoms().end(); - for (; it != end; ++it) { - if (x != *it && contains_x(*it)) return false; + for (expr* y : m_ctx.neg_atoms()) { + if (x != y && contains_x(y)) return false; } def = m.mk_false(); m_replace.apply_substitution(x, def, fml); diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 94c2d36aa..9ca4687b5 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -64,8 +64,8 @@ expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) { expr_ref_vector vals(m); obj_map val2expr; app* alit = to_app(t); - for (unsigned i = 0; i < alit->get_num_args(); ++i) { - expr* e1 = alit->get_arg(i), *e2; + for (expr * e1 : *alit) { + expr *e2; VERIFY(model.eval(e1, val)); if (val2expr.find(val, e2)) { return expr_ref(m.mk_eq(e1, e2), m); @@ -91,13 +91,13 @@ void project_plugin::push_back(expr_ref_vector& lits, expr* e) { class mbp::impl { - ast_manager& m; + ast_manager& m; params_ref m_params; - th_rewriter m_rw; + th_rewriter m_rw; ptr_vector m_plugins; - expr_mark m_visited; - expr_mark m_bool_visited; - + expr_mark m_visited; + expr_mark m_bool_visited; + // parameters bool m_reduce_all_selects; bool m_dont_sub; @@ -140,12 +140,9 @@ class mbp::impl { } if (reduced) { unsigned j = 0; - for (unsigned i = 0; i < vars.size(); ++i) { - if (!is_rem.is_marked(vars[i].get())) { - if (i != j) { - vars[j] = vars[i].get(); - } - ++j; + for (app* v : vars) { + if (!is_rem.is_marked(v)) { + vars[j++] = v; } } vars.shrink(j); @@ -172,20 +169,13 @@ class mbp::impl { void filter_variables(model& model, app_ref_vector& vars, expr_ref_vector& lits, expr_ref_vector& unused_lits) { expr_mark lit_visited; project_plugin::mark_rec(lit_visited, lits); - unsigned j = 0; - for (unsigned i = 0; i < vars.size(); ++i) { - app* var = vars[i].get(); + for (app* var : vars) { if (lit_visited.is_marked(var)) { - if (i != j) { - vars[j] = vars[i].get(); + vars[j++] = var; } - ++j; } - } - if (vars.size() != j) { - vars.resize(j); - } + vars.shrink(j); } bool extract_bools(model_evaluator& eval, expr_ref_vector& fmls, expr* fml) { @@ -245,33 +235,33 @@ class mbp::impl { } else { vars[j++] = var; + } } - } if (j == vars.size()) { return; } vars.shrink(j); - j = 0; - for (unsigned i = 0; i < fmls.size(); ++i) { + j = 0; + for (unsigned i = 0; i < fmls.size(); ++i) { expr* fml = fmls[i].get(); sub(fml, val); - m_rw(val); - if (!m.is_true(val)) { + m_rw(val); + if (!m.is_true(val)) { TRACE("qe", tout << mk_pp(fml, m) << " -> " << val << "\n";); fmls[j++] = val; - } - } + } + } fmls.shrink(j); - } + } void subst_vars(model_evaluator& eval, app_ref_vector const& vars, expr_ref& fml) { expr_safe_replace sub (m); for (app * v : vars) { sub.insert(v, eval(v)); - } + } sub(fml); - } + } struct index_term_finder { ast_manager& m; @@ -594,7 +584,7 @@ public: model_evaluator eval(mdl, m_params); eval.set_model_completion(true); - app_ref_vector arith_vars (m); + app_ref_vector other_vars (m); app_ref_vector array_vars (m); array_util arr_u (m); arith_util ari_u (m); @@ -612,11 +602,8 @@ public: if (arr_u.is_array(v)) { array_vars.push_back (v); } - else if (ari_u.is_int (v) || ari_u.is_real (v)) { - arith_vars.push_back (v); - } else { - NOT_IMPLEMENTED_YET(); + other_vars.push_back (v); } } @@ -636,46 +623,44 @@ public: TRACE ("qe", tout << "extended model:\n"; model_pp (tout, mdl); - tout << "Vars: "; - tout << vars << "\n"; + tout << "Vars: " << vars << "\n"; ); } - // project reals and ints - if (!arith_vars.empty ()) { - TRACE ("qe", tout << "Arith vars: " << arith_vars << "\n"; - model_pp(tout, mdl); - ); + // project reals, ints and other variables. + if (!other_vars.empty ()) { + TRACE ("qe", tout << "Other vars: " << other_vars << "\n"; + model_pp(tout, mdl);); expr_ref_vector fmls(m); flatten_and (fml, fmls); - (*this)(true, arith_vars, mdl, fmls); + (*this)(false, other_vars, mdl, fmls); fml = mk_and (fmls); TRACE ("qe", - tout << "Projected arith vars:\n" << fml << "\n"; - tout << "Remaining arith vars:\n" << arith_vars << "\n";); + tout << "Projected other vars:\n" << fml << "\n"; + tout << "Remaining other vars:\n" << other_vars << "\n";); SASSERT (!m.is_false (fml)); } - if (!arith_vars.empty ()) { - project_vars (mdl, arith_vars, fml); + if (!other_vars.empty ()) { + project_vars (mdl, other_vars, fml); } - // substitute any remaining arith vars - if (!m_dont_sub && !arith_vars.empty ()) { - subst_vars (eval, arith_vars, fml); - TRACE ("qe", tout << "After substituting remaining arith vars:\n" << fml << "\n";); + // substitute any remaining other vars + if (!m_dont_sub && !other_vars.empty ()) { + subst_vars (eval, other_vars, fml); + TRACE ("qe", tout << "After substituting remaining other vars:\n" << fml << "\n";); // an extra round of simplification because subst_vars is not simplifying m_rw(fml); - arith_vars.reset(); + other_vars.reset(); } SASSERT(eval.is_true(fml)); vars.reset (); - vars.append(arith_vars); + vars.append(other_vars); } }; @@ -688,7 +673,7 @@ mbp::mbp(ast_manager& m, params_ref const& p) { mbp::~mbp() { dealloc(m_impl); } - + void mbp::updt_params(params_ref const& p) { m_impl->updt_params(p); } From 7e9f7d2cfe506b39633233a4c9e69259f1f78886 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 16:02:58 -0700 Subject: [PATCH 1071/1283] remove removed paramter from comment Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbp.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 25a95e885..bddec8065 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -88,7 +88,6 @@ namespace qe { Apply spacer friendly MBP. Use parameters to control behavior. - reduce_all_selects (false) - - native_mbp (false) - to be deprecated - dont_sub (false) */ void spacer(app_ref_vector& vars, model& mdl, expr_ref& fml); From a8438e081eaad149e20ee0c82f070246aee086f9 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 25 May 2018 11:18:26 -0700 Subject: [PATCH 1072/1283] Wired qe::mbp into spacer use option fixedpoint.spacer.native_mbp=true to use it --- src/muz/spacer/spacer_util.cpp | 87 +++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 32 deletions(-) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index b45e0de4a..3eaeb098e 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -90,33 +90,33 @@ namespace spacer { if (!m_model) { return; } m_mev = alloc(model_evaluator, *m_model); } - + bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { m_mev->set_model_completion (model_completion); try { m_mev->operator() (e, result); return true; - } + } catch (model_evaluator_exception &ex) { (void)ex; TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); return false; } } - + bool model_evaluator_util::eval(const expr_ref_vector &v, expr_ref& res, bool model_completion) { expr_ref e(m); e = mk_and (v); return eval(e, res, model_completion); } - - + + bool model_evaluator_util::is_true(const expr_ref_vector &v) { expr_ref res(m); return eval (v, res, false) && m.is_true (res); } - + bool model_evaluator_util::is_false(expr *x) { expr_ref res(m); return eval(x, res, false) && m.is_false (res); @@ -126,7 +126,7 @@ namespace spacer { expr_ref res(m); return eval(x, res, false) && m.is_true (res); } - + void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { ast_manager& m = fml.get_manager(); expr_ref_vector conjs(m); @@ -172,16 +172,16 @@ namespace spacer { SASSERT(orig_size <= 1 + conjs.size()); if (i + 1 == orig_size) { // no-op. - } + } else if (orig_size <= conjs.size()) { // no-op - } + } else { SASSERT(orig_size == 1 + conjs.size()); --orig_size; --i; } - } + } else { conjs[i] = tmp; } @@ -199,7 +199,7 @@ namespace spacer { ast_manager& m; public: ite_hoister(ast_manager& m): m(m) {} - + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { if (m.is_ite(f)) { return BR_FAILED; @@ -234,7 +234,7 @@ namespace spacer { } ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} }; - + class ite_hoister_star : public rewriter_tpl { ite_hoister_cfg m_cfg; public: @@ -242,7 +242,7 @@ namespace spacer { rewriter_tpl(m, false, m_cfg), m_cfg(m, p) {} }; - + void hoist_non_bool_if(expr_ref& fml) { ast_manager& m = fml.get_manager(); scoped_no_proof _sp(m); @@ -274,7 +274,7 @@ namespace spacer { bool is_arith_expr(expr *e) const { return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); } - + bool is_offset(expr* e) const { if (a.is_numeral(e)) { return true; @@ -358,7 +358,7 @@ namespace spacer { !a.is_mul(lhs) && !a.is_mul(rhs); } - + bool test_term(expr* e) const { if (m.is_bool(e)) { return true; @@ -403,9 +403,9 @@ namespace spacer { public: test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} - + void test_for_utvpi() { m_test_for_utvpi = true; } - + void operator()(expr* e) { if (!m_is_dl) { return; @@ -422,7 +422,7 @@ namespace spacer { m_is_dl = test_term(a->get_arg(i)); } } - + if (!m_is_dl) { char const* msg = "non-diff: "; if (m_test_for_utvpi) { @@ -431,10 +431,10 @@ namespace spacer { IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); } } - + bool is_dl() const { return m_is_dl; } }; - + bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); expr_fast_mark1 mark; @@ -443,7 +443,7 @@ namespace spacer { } return test.is_dl(); } - + bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { test_diff_logic test(m); test.test_for_utvpi(); @@ -455,7 +455,7 @@ namespace spacer { } - void subst_vars(ast_manager& m, + void subst_vars(ast_manager& m, app_ref_vector const& vars, model* M, expr_ref& fml) { expr_safe_replace sub (m); @@ -487,11 +487,25 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) << "(pop)\n" << "(exit)\n"; } + +void qe_project_z3 (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + const model_ref& M, bool reduce_all_selects, bool use_native_mbp, + bool dont_sub) { + params_ref p; + p.set_bool("reduce_all_selects", reduce_all_selects); + p.set_bool("dont_sub", dont_sub); + + qe::mbp mbp(m, p); + // TODO: deal with const + model *mdl = const_cast(M.get()); + mbp.spacer(vars, *mdl, fml); +} + /* * eliminate simple equalities using qe_lite * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays */ - void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + void qe_project_spacer (ast_manager& m, app_ref_vector& vars, expr_ref& fml, const model_ref& M, bool reduce_all_selects, bool use_native_mbp, bool dont_sub) { th_rewriter rw (m); @@ -506,7 +520,7 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) flatten_and (fml, flat); fml = mk_and(flat); } - + // uncomment for benchmarks //to_mbp_benchmark(verbose_stream(), fml, vars); @@ -523,7 +537,7 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) qe_lite qe(m, p, false); qe (vars, fml); rw (fml); - + TRACE ("spacer_mbp", tout << "After qe_lite:\n"; tout << mk_pp (fml, m) << "\n"; @@ -531,7 +545,7 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) SASSERT (!m.is_false (fml)); - + // sort out vars into bools, arith (int/real), and arrays for (app* v : vars) { if (m.is_bool (v)) { @@ -545,7 +559,7 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) arith_vars.push_back (v); } } - + // substitute Booleans if (!bool_sub.empty()) { bool_sub (fml); @@ -555,13 +569,13 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); bool_sub.reset (); } - + TRACE ("spacer_mbp", tout << "Array vars:\n"; tout << array_vars;); - + vars.reset (); - + // project arrays { scoped_no_proof _sp (m); @@ -572,14 +586,14 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) srw (fml); SASSERT (!m.is_false (fml)); } - + TRACE ("spacer_mbp", tout << "extended model:\n"; model_pp (tout, *M); tout << "Auxiliary variables of index and value sorts:\n"; tout << vars; ); - + if (vars.empty()) { break; } } @@ -656,6 +670,15 @@ void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) } } +void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + const model_ref& M, bool reduce_all_selects, bool use_native_mbp, + bool dont_sub) { + if (use_native_mbp) + qe_project_z3(m, vars, fml, M, reduce_all_selects, use_native_mbp, dont_sub); + else + qe_project_spacer(m, vars, fml, M, reduce_all_selects, use_native_mbp, dont_sub); +} + void expand_literals(ast_manager &m, expr_ref_vector& conjs) { if (conjs.empty()) { return; } From e6401908a529cfe1112edfb74ce8d09a103fc973 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 13:41:57 -0700 Subject: [PATCH 1073/1283] fix crash Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arrays.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 1701ce742..1b3bd6c20 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -802,8 +802,9 @@ namespace qe { */ expr* reduce_core (app *a) { if (!m_arr_u.is_store (a->get_arg (0))) return a; - unsigned arity = get_array_arity(m.get_sort(a)); - expr* array = a->get_arg (0); + expr* array = a->get_arg(0); + unsigned arity = get_array_arity(m.get_sort(array)); + expr* const* js = a->get_args() + 1; while (m_arr_u.is_store (array)) { From aa8dac2583d231c1c39086232d62f8e5e72b1d0b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 13:55:39 -0700 Subject: [PATCH 1074/1283] fix uninitialized variable Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 9ca4687b5..1390c0ae5 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -471,6 +471,7 @@ public: add_plugin(alloc(arith_project_plugin, m)); add_plugin(alloc(datatype_project_plugin, m)); add_plugin(alloc(array_project_plugin, m)); + updt_params(p); } ~impl() { From af57db04132dbea4fca6fd713efcaf27efcbba68 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 27 May 2018 09:34:49 -0700 Subject: [PATCH 1075/1283] Anti-unification of two ground expressions --- src/muz/spacer/spacer_antiunify.cpp | 228 +++++++--------------------- src/muz/spacer/spacer_antiunify.h | 42 ++--- 2 files changed, 80 insertions(+), 190 deletions(-) diff --git a/src/muz/spacer/spacer_antiunify.cpp b/src/muz/spacer/spacer_antiunify.cpp index 6c38e4898..8b5e9e75b 100644 --- a/src/muz/spacer/spacer_antiunify.cpp +++ b/src/muz/spacer/spacer_antiunify.cpp @@ -103,190 +103,73 @@ struct var_abs_rewriter : public default_rewriter_cfg { }; -/* -* construct m_g, which is a generalization of t, where every constant -* is replaced by a variable for any variable in m_g, remember the -* substitution to get back t and save it in m_substitutions -*/ -anti_unifier::anti_unifier(expr* t, ast_manager& man) : m(man), m_pinned(m), m_g(m) -{ - m_pinned.push_back(t); - obj_map substitution; +anti_unifier::anti_unifier(ast_manager &manager) : m(manager), m_pinned(m) {} - var_abs_rewriter var_abs_cfg(m, substitution); - rewriter_tpl var_abs_rw (m, false, var_abs_cfg); - var_abs_rw (t, m_g); - - m_substitutions.push_back(substitution); //TODO: refactor into vector, remove k +void anti_unifier::reset() { + m_subs.reset(); + m_cache.reset(); + m_todo.reset(); + m_pinned.reset(); } -/* traverses m_g and t in parallel. if they only differ in constants - * (i.e. m_g contains a variable, where t contains a constant), then - * add the substitutions, which need to be applied to m_g to get t, to - * m_substitutions. -*/ -bool anti_unifier::add_term(expr* t) { - m_pinned.push_back(t); +void anti_unifier::operator()(expr *e1, expr *e2, expr_ref &res, + substitution &s1, substitution &s2) { - ptr_vector todo; - ptr_vector todo2; - todo.push_back(m_g); - todo2.push_back(t); + reset(); + if (e1 == e2) {res = e1; s1.reset(); s2.reset(); return;} - ast_mark visited; + m_todo.push_back(expr_pair(e1, e2)); + while (!m_todo.empty()) { + const expr_pair &p = m_todo.back(); + SASSERT(is_app(p.first)); + SASSERT(is_app(p.second)); - arith_util util(m); + app * n1 = to_app(p.first); + app * n2 = to_app(p.second); - obj_map substitution; - - while (!todo.empty()) { - expr* current = todo.back(); - todo.pop_back(); - expr* current2 = todo2.back(); - todo2.pop_back(); - - if (!visited.is_marked(current)) { - visited.mark(current, true); - - if (is_var(current)) { - // TODO: for now we don't allow variables in the terms we want to antiunify - SASSERT(m_substitutions[0].contains(current)); - if (util.is_numeral(current2)) { - substitution.insert(current, current2); - } - else {return false;} - } - else { - SASSERT(is_app(current)); - - if (is_app(current2) && - to_app(current)->get_decl() == to_app(current2)->get_decl() && - to_app(current)->get_num_args() == to_app(current2)->get_num_args()) { - // TODO: what to do for numerals here? E.g. if we - // have 1 and 2, do they have the same decl or are - // the decls already different? - SASSERT (!util.is_numeral(current) || current == current2); - for (unsigned i = 0, num_args = to_app(current)->get_num_args(); - i < num_args; ++i) { - todo.push_back(to_app(current)->get_arg(i)); - todo2.push_back(to_app(current2)->get_arg(i)); - } - } - else { - return false; - } - } - } - } - - // we now know that the terms can be anti-unified, so add the cached substitution - m_substitutions.push_back(substitution); - return true; -} - -/* -* returns m_g, where additionally any variable, which has only equal -* substitutions, is substituted with that substitution -*/ -void anti_unifier::finalize() { - ptr_vector todo; - todo.push_back(m_g); - - ast_mark visited; - - obj_map generalization; - - arith_util util(m); - - // post-order traversel which ignores constants and handles them - // directly when the enclosing term of the constant is handled - while (!todo.empty()) { - expr* current = todo.back(); - SASSERT(is_app(current)); - - // if we haven't already visited current - if (!visited.is_marked(current)) { - bool existsUnvisitedParent = false; - - for (unsigned i = 0, sz = to_app(current)->get_num_args(); i < sz; ++i) { - expr* argument = to_app(current)->get_arg(i); - - if (!is_var(argument)) { - SASSERT(is_app(argument)); - // if we haven't visited the current parent yet - if(!visited.is_marked(argument)) { - // add it to the stack - todo.push_back(argument); - existsUnvisitedParent = true; - } - } - } - - // if we already visited all parents, we can visit current too - if (!existsUnvisitedParent) { - visited.mark(current, true); - todo.pop_back(); - - ptr_buffer arg_list; - for (unsigned i = 0, num_args = to_app(current)->get_num_args(); - i < num_args; ++i) { - expr* argument = to_app(current)->get_arg(i); - - if (is_var(argument)) { - // compute whether there are different - // substitutions for argument - bool containsDifferentSubstitutions = false; - - for (unsigned i=0, sz = m_substitutions.size(); i+1 < sz; ++i) { - SASSERT(m_substitutions[i].contains(argument)); - SASSERT(m_substitutions[i+1].contains(argument)); - - // TODO: how to check equality? - if (m_substitutions[i][argument] != - m_substitutions[i+1][argument]) - { - containsDifferentSubstitutions = true; - break; - } - } - - // if yes, use the variable - if (containsDifferentSubstitutions) { - arg_list.push_back(argument); - } - // otherwise use the concrete value instead - // and remove the substitutions - else - { - arg_list.push_back(m_substitutions[0][argument]); - - for (unsigned i=0, sz = m_substitutions.size(); i < sz; ++i) { - SASSERT(m_substitutions[i].contains(argument)); - m_substitutions[i].remove(argument); - } - } - } - else { - SASSERT(generalization.contains(argument)); - arg_list.push_back(generalization[argument]); - } - } - - SASSERT(to_app(current)->get_num_args() == arg_list.size()); - expr_ref application(m.mk_app(to_app(current)->get_decl(), - to_app(current)->get_num_args(), - arg_list.c_ptr()), m); - m_pinned.push_back(application); - generalization.insert(current, application); - } + unsigned num_arg1 = n1->get_num_args(); + unsigned num_arg2 = n2->get_num_args(); + if (n1->get_decl() != n2->get_decl() || num_arg1 != num_arg2) { + expr_ref v(m); + v = m.mk_var(m_subs.size(), get_sort(n1)); + m_pinned.push_back(v); + m_subs.push_back(expr_pair(n1, n2)); + m_cache.insert(n1, n2, v); } else { - todo.pop_back(); + expr *tmp; + unsigned todo_sz = m_todo.size(); + ptr_buffer kids; + for (unsigned i = 0; i < num_arg1; ++i) { + expr *arg1 = n1->get_arg(i); + expr *arg2 = n2->get_arg(i); + if (arg1 == arg2) {kids.push_back(arg1);} + else if (m_cache.find(arg1, arg2, tmp)) {kids.push_back(tmp);} + else {m_todo.push_back(expr_pair(arg1, arg2));} + } + if (m_todo.size() > todo_sz) {continue;} + + expr_ref u(m); + u = m.mk_app(n1->get_decl(), kids.size(), kids.c_ptr()); + m_pinned.push_back(u); + m_cache.insert(n1, n2, u); } } - m_g = generalization[m_g]; + expr *r; + VERIFY(m_cache.find(e1, e2, r)); + res = r; + + // create substitutions + s1.reserve(2, m_subs.size()); + s2.reserve(2, m_subs.size()); + + for (unsigned i = 0, sz = m_subs.size(); i < sz; ++i) { + expr_pair p = m_subs.get(i); + s1.insert(i, 0, expr_offset(p.first, 1)); + s2.insert(i, 0, expr_offset(p.second, 1)); + } } @@ -319,6 +202,8 @@ public: */ bool naive_convex_closure::compute_closure(anti_unifier& au, ast_manager& m, expr_ref& result) { + NOT_IMPLEMENTED_YET(); +#if 0 arith_util util(m); SASSERT(au.get_num_substitutions() > 0); @@ -412,6 +297,7 @@ bool naive_convex_closure::compute_closure(anti_unifier& au, ast_manager& m, result = expr_ref(m.mk_exists(vars.size(), sorts.c_ptr(), names.c_ptr(), body),m); return true; +#endif } bool naive_convex_closure::get_range(vector& v, diff --git a/src/muz/spacer/spacer_antiunify.h b/src/muz/spacer/spacer_antiunify.h index fb0933f0d..af7f6f825 100644 --- a/src/muz/spacer/spacer_antiunify.h +++ b/src/muz/spacer/spacer_antiunify.h @@ -22,32 +22,36 @@ Revision History: #define _SPACER_ANTIUNIFY_H_ #include "ast/ast.h" - +#include "ast/substitution/substitution.h" +#include "util/obj_pair_hashtable.h" namespace spacer { +/** +\brief Anti-unifier for ground expressions +*/ class anti_unifier { -public: - anti_unifier(expr* t, ast_manager& m); - ~anti_unifier() {} + typedef std::pair expr_pair; + typedef pair_hash, obj_ptr_hash > expr_pair_hash; + typedef obj_pair_map cache_ty; - bool add_term(expr* t); - void finalize(); - - expr* get_generalization() {return m_g;} - unsigned get_num_substitutions() {return m_substitutions.size();} - obj_map get_substitution(unsigned index){ - SASSERT(index < m_substitutions.size()); - return m_substitutions[index]; - } - -private: - ast_manager& m; - // tracking all created expressions + ast_manager &m; expr_ref_vector m_pinned; - expr_ref m_g; + svector m_todo; + cache_ty m_cache; + svector m_subs; - vector> m_substitutions; +public: + anti_unifier(ast_manager& m); + + void reset(); + + /** + \brief Computes anti-unifier of two ground expressions. Returns + the anti-unifier and the corresponding substitutions + */ + void operator() (expr *e1, expr *e2, expr_ref &res, + substitution &s1, substitution &s2); }; class naive_convex_closure From b73aa3642a54c68e020e7d32b1dfaef86d94a9eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 27 May 2018 16:54:15 -0700 Subject: [PATCH 1076/1283] check with cube and clause Signed-off-by: Nikolaj Bjorner --- src/smt/smt_clause.h | 8 +- src/smt/smt_context.cpp | 223 +++++++++++++++++++++---------------- src/smt/smt_context.h | 16 ++- src/smt/smt_context_pp.cpp | 2 +- src/smt/smt_kernel.cpp | 9 ++ src/smt/smt_kernel.h | 2 + src/smt/smt_solver.cpp | 20 ++++ src/smt/theory_pb.cpp | 2 +- src/solver/solver.cpp | 21 ++++ src/solver/solver.h | 7 ++ 10 files changed, 202 insertions(+), 108 deletions(-) diff --git a/src/smt/smt_clause.h b/src/smt/smt_clause.h index 8e843c4cf..f0b352e05 100644 --- a/src/smt/smt_clause.h +++ b/src/smt/smt_clause.h @@ -192,13 +192,13 @@ namespace smt { return m_lits[idx]; } - literal * begin_literals() { return m_lits; } + literal * begin() { return m_lits; } - literal * end_literals() { return m_lits + m_num_literals; } + literal * end() { return m_lits + m_num_literals; } - literal const * begin_literals() const { return m_lits; } + literal const * begin() const { return m_lits; } - literal const * end_literals() const { return m_lits + m_num_literals; } + literal const * end() const { return m_lits + m_num_literals; } unsigned get_activity() const { SASSERT(is_lemma()); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 14a19f824..1e2599802 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -61,6 +61,7 @@ namespace smt { m_dyn_ack_manager(*this, p), m_is_diseq_tmp(nullptr), m_units_to_reassert(m_manager), + m_clause(nullptr), m_qhead(0), m_simp_qhead(0), m_simp_counter(0), @@ -203,8 +204,8 @@ namespace smt { literal l1 = to_literal(l_idx); literal neg_l1 = ~l1; watch_list const & wl = *it; - literal const * it2 = wl.begin_literals(); - literal const * end2 = wl.end_literals(); + literal const * it2 = wl.begin(); + literal const * end2 = wl.end(); for (; it2 != end2; ++it2) { literal l2 = *it2; if (l1.index() < l2.index()) { @@ -385,8 +386,8 @@ namespace smt { it2++; } else { - literal * it3 = cls->begin_literals() + 2; - literal * end3 = cls->end_literals(); + literal * it3 = cls->begin() + 2; + literal * end3 = cls->end(); for(; it3 != end3; ++it3) { if (get_assignment(*it3) != l_false) { // swap literal *it3 with literal at position 0 @@ -1813,6 +1814,17 @@ namespace smt { more case splits to be performed. */ bool context::decide() { + + if (m_clause && at_search_level()) { + switch (decide_clause()) { + case l_true: // already satisfied + break; + case l_undef: // made a decision + return true; + case l_false: // inconsistent + break; + } + } bool_var var; lbool phase; m_case_split_queue->next_case_split(var, phase); @@ -2152,7 +2164,7 @@ namespace smt { \brief See cache_generation(unsigned new_scope_lvl) */ void context::cache_generation(clause const * cls, unsigned new_scope_lvl) { - cache_generation(cls->get_num_literals(), cls->begin_literals(), new_scope_lvl); + cache_generation(cls->get_num_literals(), cls->begin(), new_scope_lvl); } /** @@ -2907,6 +2919,8 @@ namespace smt { del_clauses(m_aux_clauses, 0); del_clauses(m_lemmas, 0); del_justifications(m_justifications, 0); + if (m_clause) del_clause(m_clause); + m_clause = nullptr; if (m_is_diseq_tmp) { m_is_diseq_tmp->del_eh(m_manager, false); m_manager.dec_ref(m_is_diseq_tmp->get_owner()); @@ -3087,6 +3101,7 @@ namespace smt { } TRACE("internalize_assertions", tout << "after internalize_assertions()...\n"; tout << "inconsistent: " << inconsistent() << "\n";); + TRACE("after_internalize_assertions", display(tout);); } bool is_valid_assumption(ast_manager & m, expr * assumption) { @@ -3109,10 +3124,10 @@ namespace smt { /** \brief Assumptions must be uninterpreted boolean constants (aka propositional variables). */ - bool context::validate_assumptions(unsigned num_assumptions, expr * const * assumptions) { - for (unsigned i = 0; i < num_assumptions; i++) { - SASSERT(assumptions[i]); - if (!is_valid_assumption(m_manager, assumptions[i])) { + bool context::validate_assumptions(expr_ref_vector const& asms) { + for (expr* a : asms) { + SASSERT(a); + if (!is_valid_assumption(m_manager, a)) { warning_msg("an assumption must be a propositional variable or the negation of one"); return false; } @@ -3120,11 +3135,55 @@ namespace smt { return true; } - void context::init_assumptions(unsigned num_assumptions, expr * const * assumptions) { + void context::init_clause(expr_ref_vector const& clause) { + if (m_clause) del_clause(m_clause); + m_clause_lits.reset(); + for (expr* lit : clause) { + internalize_formula(lit, true); + mark_as_relevant(lit); + m_clause_lits.push_back(get_literal(lit)); + } + m_clause = mk_clause(m_clause_lits.size(), m_clause_lits.c_ptr(), nullptr); + } + + lbool context::decide_clause() { + if (!m_clause) return l_true; + shuffle(m_clause_lits.size(), m_clause_lits.c_ptr(), m_random); + for (literal l : m_clause_lits) { + switch (get_assignment(l)) { + case l_false: + break; + case l_true: + return l_true; + default: + push_scope(); + assign(l, b_justification::mk_axiom(), true); + return l_undef; + } + } + for (unsigned i = m_assigned_literals.size(); i-- > 0; ) { + literal lit = m_assigned_literals[i]; + if (m_clause_lits.contains(~lit)) { + for (unsigned j = 0, sz = m_clause->get_num_literals(); j < sz; ++j) { + if (m_clause->get_literal(j) == ~lit) { + if (j > 0) m_clause->swap_lits(j, 0); + break; + } + } + b_justification js(m_clause); + set_conflict(js, ~lit); + return l_false; + } + } + UNREACHABLE(); + return l_false; + } + + void context::init_assumptions(expr_ref_vector const& asms) { reset_assumptions(); m_literal2assumption.reset(); m_unsat_core.reset(); - if (num_assumptions > 0) { + if (!asms.empty()) { // We must give a chance to the theories to propagate before we create a new scope... propagate(); // Internal backtracking scopes (created with push_scope()) must only be created when we are @@ -3134,8 +3193,7 @@ namespace smt { if (get_cancel_flag()) return; push_scope(); - for (unsigned i = 0; i < num_assumptions; i++) { - expr * curr_assumption = assumptions[i]; + for (expr * curr_assumption : asms) { if (m_manager.is_true(curr_assumption)) continue; SASSERT(is_valid_assumption(m_manager, curr_assumption)); proof * pr = m_manager.mk_asserted(curr_assumption); @@ -3155,8 +3213,9 @@ namespace smt { } } m_search_lvl = m_scope_lvl; - SASSERT(!(num_assumptions > 0) || m_search_lvl > m_base_lvl); - SASSERT(!(num_assumptions == 0) || m_search_lvl == m_base_lvl); + SASSERT(asms.empty() || m_search_lvl > m_base_lvl); + SASSERT(!asms.empty() || m_search_lvl == m_base_lvl); + TRACE("after_internalization", display(tout);); } void context::reset_assumptions() { @@ -3165,7 +3224,8 @@ namespace smt { m_assumptions.reset(); } - lbool context::mk_unsat_core() { + lbool context::mk_unsat_core(lbool r) { + if (r != l_false) return r; SASSERT(inconsistent()); if (!tracking_assumptions()) { SASSERT(m_assumptions.empty()); @@ -3217,6 +3277,12 @@ namespace smt { m_last_search_failure = MEMOUT; return false; } + + if (m_clause) del_clause(m_clause); + m_clause = nullptr; + m_unsat_core.reset(); + m_stats.m_num_checks++; + pop_to_base_lvl(); return true; } @@ -3240,8 +3306,7 @@ namespace smt { and before internalizing any formulas. */ lbool context::setup_and_check(bool reset_cancel) { - if (!check_preamble(reset_cancel)) - return l_undef; + if (!check_preamble(reset_cancel)) return l_undef; SASSERT(m_scope_lvl == 0); SASSERT(!m_setup.already_configured()); setup_context(m_fparams.m_auto_config); @@ -3254,20 +3319,8 @@ namespace smt { } internalize_assertions(); - lbool r = l_undef; TRACE("before_search", display(tout);); - if (m_asserted_formulas.inconsistent()) { - r = l_false; - } - else { - if (inconsistent()) { - VERIFY(!resolve_conflict()); // build the proof - r = l_false; - } - else { - r = search(); - } - } + lbool r = search(); r = check_finalize(r); return r; } @@ -3281,7 +3334,7 @@ namespace smt { } void context::setup_context(bool use_static_features) { - if (m_setup.already_configured()) + if (m_setup.already_configured() || inconsistent()) return; m_setup(get_config_mode(use_static_features)); setup_components(); @@ -3316,72 +3369,40 @@ namespace smt { } } - lbool context::check(unsigned ext_num_assumptions, expr * const * ext_assumptions, bool reset_cancel, bool already_did_theory_assumptions) { - m_stats.m_num_checks++; - TRACE("check_bug", tout << "STARTING check(num_assumptions, assumptions)\n"; - tout << "inconsistent: " << inconsistent() << ", m_unsat_core.empty(): " << m_unsat_core.empty() << "\n"; - m_asserted_formulas.display(tout); - tout << "-----------------------\n"; - display(tout);); - if (!m_unsat_core.empty()) - m_unsat_core.reset(); - if (!check_preamble(reset_cancel)) - return l_undef; - - TRACE("check_bug", tout << "inconsistent: " << inconsistent() << ", m_unsat_core.empty(): " << m_unsat_core.empty() << "\n";); - pop_to_base_lvl(); + lbool context::check(unsigned num_assumptions, expr * const * assumptions, bool reset_cancel, bool already_did_theory_assumptions) { + if (!check_preamble(reset_cancel)) return l_undef; TRACE("before_search", display(tout);); SASSERT(at_base_level()); - lbool r = l_undef; - if (inconsistent()) { - r = l_false; - } - else { - setup_context(false); - expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); - if (!already_did_theory_assumptions) { - add_theory_assumptions(all_assumptions); - } - - unsigned num_assumptions = all_assumptions.size(); - expr * const * assumptions = all_assumptions.c_ptr(); - - if (!validate_assumptions(num_assumptions, assumptions)) - return l_undef; - TRACE("unsat_core_bug", tout << all_assumptions << "\n";); - - internalize_assertions(); - TRACE("after_internalize_assertions", display(tout);); - if (m_asserted_formulas.inconsistent()) { - r = l_false; - } - else { - init_assumptions(num_assumptions, assumptions); - TRACE("after_internalization", display(tout);); - if (inconsistent()) { - VERIFY(!resolve_conflict()); // build the proof - lbool result = mk_unsat_core(); - if (result == l_undef) { - r = l_undef; - } else { - r = l_false; - } - } - else { - r = search(); - if (r == l_false) { - lbool result = mk_unsat_core(); - if (result == l_undef) { - r = l_undef; - } - } - } - } - } + setup_context(false); + expr_ref_vector asms(m_manager, num_assumptions, assumptions); + if (!already_did_theory_assumptions) add_theory_assumptions(asms); + if (!validate_assumptions(asms)) return l_undef; + TRACE("unsat_core_bug", tout << asms << "\n";); + internalize_assertions(); + init_assumptions(asms); + lbool r = search(); + r = mk_unsat_core(r); r = check_finalize(r); return r; } + lbool context::check(expr_ref_vector const& cube, expr_ref_vector const& clause) { + if (!check_preamble(true)) return l_undef; + TRACE("before_search", display(tout);); + setup_context(false); + expr_ref_vector asms(cube); + add_theory_assumptions(asms); + if (!validate_assumptions(asms)) return l_undef; + if (!validate_assumptions(clause)) return l_undef; + internalize_assertions(); + init_assumptions(asms); + init_clause(clause); + lbool r = search(); + r = mk_unsat_core(r); + r = check_finalize(r); + return r; + } + void context::init_search() { for (theory* th : m_theory_set) { th->init_search_eh(); @@ -3450,6 +3471,12 @@ namespace smt { exit(1); } #endif + if (m_asserted_formulas.inconsistent()) + return l_false; + if (inconsistent()) { + VERIFY(!resolve_conflict()); + return l_false; + } timeit tt(get_verbosity_level() >= 100, "smt.stats"); scoped_mk_model smk(*this); SASSERT(at_search_level()); @@ -3473,24 +3500,19 @@ namespace smt { if (!restart(status, curr_lvl)) { break; - } + } } - TRACE("search_lite", tout << "status: " << status << "\n";); TRACE("guessed_literals", expr_ref_vector guessed_lits(m_manager); get_guessed_literals(guessed_lits); - unsigned sz = guessed_lits.size(); - for (unsigned i = 0; i < sz; i++) { - tout << mk_pp(guessed_lits.get(i), m_manager) << "\n"; - }); + tout << guessed_lits << "\n";); end_search(); return status; } bool context::restart(lbool& status, unsigned curr_lvl) { - if (m_last_search_failure != OK) { if (status != l_false) { // build candidate model before returning @@ -3643,6 +3665,8 @@ namespace smt { simplify_clauses(); if (!decide()) { + if (inconsistent()) + return l_false; final_check_status fcs = final_check(); TRACE("final_check_result", tout << "fcs: " << fcs << " last_search_failure: " << m_last_search_failure << "\n";); switch (fcs) { @@ -3700,6 +3724,7 @@ namespace smt { TRACE("final_check", tout << "final_check inconsistent: " << inconsistent() << "\n"; display(tout); display_normalized_enodes(tout);); CASSERT("relevancy", check_relevancy()); + if (m_fparams.m_model_on_final_check) { mk_proto_model(l_undef); model_pp(std::cout, *m_proto_model); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 32379c353..3110ea3c1 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -168,6 +168,8 @@ namespace smt { expr_ref_vector m_units_to_reassert; svector m_units_to_reassert_sign; literal_vector m_assigned_literals; + clause* m_clause; + literal_vector m_clause_lits; unsigned m_qhead; unsigned m_simp_qhead; int m_simp_counter; //!< can become negative @@ -1104,15 +1106,21 @@ namespace smt { void assert_assumption(expr * a); - bool validate_assumptions(unsigned num_assumptions, expr * const * assumptions); + bool validate_assumptions(expr_ref_vector const& asms); - void init_assumptions(unsigned num_assumptions, expr * const * assumptions); + void init_assumptions(expr_ref_vector const& asms); + + void init_clause(expr_ref_vector const& clause); + + lbool decide_clause(); void reset_assumptions(); + void reset_clause(); + void add_theory_assumptions(expr_ref_vector & theory_assumptions); - lbool mk_unsat_core(); + lbool mk_unsat_core(lbool result); void validate_unsat_core(); @@ -1497,6 +1505,8 @@ namespace smt { lbool check(unsigned num_assumptions = 0, expr * const * assumptions = nullptr, bool reset_cancel = true, bool already_did_theory_assumptions = false); + lbool check(expr_ref_vector const& cube, expr_ref_vector const& clause); + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes); diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index a6b881d10..19247c1d9 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -583,7 +583,7 @@ namespace smt { case b_justification::CLAUSE: { clause * cls = j.get_clause(); out << "clause "; - if (cls) out << literal_vector(cls->get_num_literals(), cls->begin_literals()); + if (cls) out << literal_vector(cls->get_num_literals(), cls->begin()); break; } case b_justification::JUSTIFICATION: { diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index a6413aef9..1438efaf6 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -115,6 +115,10 @@ namespace smt { return m_kernel.check(num_assumptions, assumptions); } + lbool check(expr_ref_vector const& cube, expr_ref_vector const& clause) { + return m_kernel.check(cube, clause); + } + lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) { return m_kernel.get_consequences(assumptions, vars, conseq, unfixed); } @@ -287,6 +291,11 @@ namespace smt { return r; } + lbool kernel::check(expr_ref_vector const& cube, expr_ref_vector const& clause) { + return m_imp->check(cube, clause); + } + + lbool kernel::get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed) { return m_imp->get_consequences(assumptions, vars, conseq, unfixed); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 7b2f774ad..4174422f4 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -132,6 +132,8 @@ namespace smt { lbool check(app_ref_vector const& asms) { return check(asms.size(), (expr* const*)asms.c_ptr()); } + lbool check(expr_ref_vector const& cube, expr_ref_vector const& clause); + /** \brief extract consequences among variables. */ diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 8e5c2aaa2..77f3f32db 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -190,6 +190,26 @@ namespace smt { return m_context.check(num_assumptions, assumptions); } + lbool check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl, expr_ref_vector* core, proof_ref* pr) override { + lbool r = m_context.check(cube, clause); + switch (r) { + case l_false: + if (pr) *pr = get_proof(); + if (core) { + ptr_vector _core; + get_unsat_core(_core); + core->append(_core.size(), _core.c_ptr()); + } + break; + case l_true: + if (mdl) get_model(*mdl); + break; + default: + break; + } + return r; + } + struct scoped_minimize_core { smt_solver& s; expr_ref_vector m_assumptions; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index d45590bff..953ecea2c 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -2251,7 +2251,7 @@ namespace smt { for (unsigned i = 2; i < num_lits; ++i) { process_antecedent(cls.get_literal(i), offset); } - TRACE("pb", tout << literal_vector(cls.get_num_literals(), cls.begin_literals()) << "\n";); + TRACE("pb", tout << literal_vector(cls.get_num_literals(), cls.begin()) << "\n";); break; } case b_justification::BIN_CLAUSE: diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 84b5eb588..d295427e4 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -202,6 +202,27 @@ void solver::assert_expr(expr* f, expr* t) { assert_expr_core2(fml, a); } +lbool solver::check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl, expr_ref_vector* core, proof_ref* pr) { + ast_manager& m = clause.get_manager(); + scoped_push _push(*this); + expr_ref disj = mk_or(clause); + assert_expr(disj); + lbool r = check_sat(cube); + switch (r) { + case l_false: + if (core) get_unsat_core(*core); + if (pr) *pr = get_proof(); + break; + case l_true: + if (mdl) get_model(*mdl); + break; + default: + break; + } + return r; +} + + void solver::collect_param_descrs(param_descrs & r) { r.insert("solver.enforce_model_conversion", CPK_BOOL, "(default: false) enforce model conversion when asserting formulas"); } diff --git a/src/solver/solver.h b/src/solver/solver.h index 4c0c361ff..59a61b3c7 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -146,6 +146,13 @@ public: lbool check_sat(app_ref_vector const& asms) { return check_sat(asms.size(), (expr* const*)asms.c_ptr()); } + /** + \brief Check satisfiability modulo a cube and a clause. + + The cube corresponds to auxiliary assumptions. The clause as an auxiliary disjunction that is also + assumed for the check. + */ + virtual lbool check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl = nullptr, expr_ref_vector* core = nullptr, proof_ref* pr = nullptr); /** \brief Set a progress callback procedure that is invoked by this solver during check_sat. From 4db45473597042d454d4114d493449f260702fb4 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 27 May 2018 21:31:31 -0700 Subject: [PATCH 1077/1283] silence clang warning --- src/smt/smt_solver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 77f3f32db..0f5338ba6 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -190,6 +190,8 @@ namespace smt { return m_context.check(num_assumptions, assumptions); } + using solver_na2as::check_sat; + lbool check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl, expr_ref_vector* core, proof_ref* pr) override { lbool r = m_context.check(cube, clause); switch (r) { From 275b99e408534bfd63d7257b49f352dd5893339c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 27 May 2018 21:32:15 -0700 Subject: [PATCH 1078/1283] Add missing override --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index ceb979761..31fc4b008 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -365,7 +365,7 @@ public: if (m_fml == nullptr) return CPK_EXPR; return CPK_EXPR_LIST; } - void set_next_arg(cmd_context& ctx, expr * arg) { m_fml = arg; } + void set_next_arg(cmd_context& ctx, expr * arg) override { m_fml = arg; } void set_next_arg(cmd_context & ctx, unsigned num, expr * const * ts) override { m_vars.append(num, ts); } From ea032b56c078d211955adc287f6dcac717b544e6 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 27 May 2018 21:37:34 -0700 Subject: [PATCH 1079/1283] Return false when clause cannot be decided --- src/smt/smt_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 1e2599802..4210039b0 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1822,7 +1822,7 @@ namespace smt { case l_undef: // made a decision return true; case l_false: // inconsistent - break; + return false; } } bool_var var; From 005a6d93bb84eddedf2580c9820c163757d32bc8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 May 2018 11:29:36 -0700 Subject: [PATCH 1080/1283] cube and clause Signed-off-by: Nikolaj Bjorner --- src/smt/smt_clause.cpp | 2 +- src/smt/smt_context.cpp | 47 +++++++++++++++++++++--------- src/solver/solver_pool.cpp | 25 +++++++++++++++- src/test/CMakeLists.txt | 1 + src/test/cube_clause.cpp | 58 ++++++++++++++++++++++++++++++++++++++ src/test/main.cpp | 1 + 6 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 src/test/cube_clause.cpp diff --git a/src/smt/smt_clause.cpp b/src/smt/smt_clause.cpp index a9365fffc..4266ab246 100644 --- a/src/smt/smt_clause.cpp +++ b/src/smt/smt_clause.cpp @@ -28,7 +28,7 @@ namespace smt { clause * clause::mk(ast_manager & m, unsigned num_lits, literal * lits, clause_kind k, justification * js, clause_del_eh * del_eh, bool save_atoms, expr * const * bool_var2expr_map) { SASSERT(k == CLS_AUX || js == 0 || !js->in_region()); - SASSERT(num_lits >= 2); + SASSERT(num_lits > 2); unsigned sz = get_obj_size(num_lits, k, save_atoms, del_eh != nullptr, js != nullptr); void * mem = m.get_allocator().allocate(sz); clause * cls = new (mem) clause(); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 4210039b0..ab7e4fa35 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1815,7 +1815,7 @@ namespace smt { */ bool context::decide() { - if (m_clause && at_search_level()) { + if (at_search_level() && !m_clause_lits.empty()) { switch (decide_clause()) { case l_true: // already satisfied break; @@ -3137,17 +3137,19 @@ namespace smt { void context::init_clause(expr_ref_vector const& clause) { if (m_clause) del_clause(m_clause); + m_clause = nullptr; m_clause_lits.reset(); for (expr* lit : clause) { internalize_formula(lit, true); mark_as_relevant(lit); m_clause_lits.push_back(get_literal(lit)); } - m_clause = mk_clause(m_clause_lits.size(), m_clause_lits.c_ptr(), nullptr); + if (m_clause_lits.size() > 2) + m_clause = clause::mk(m_manager, m_clause_lits.size(), m_clause_lits.c_ptr(), CLS_AUX); } lbool context::decide_clause() { - if (!m_clause) return l_true; + if (m_clause_lits.empty()) return l_true; shuffle(m_clause_lits.size(), m_clause_lits.c_ptr(), m_random); for (literal l : m_clause_lits) { switch (get_assignment(l)) { @@ -3162,20 +3164,38 @@ namespace smt { } } for (unsigned i = m_assigned_literals.size(); i-- > 0; ) { - literal lit = m_assigned_literals[i]; - if (m_clause_lits.contains(~lit)) { - for (unsigned j = 0, sz = m_clause->get_num_literals(); j < sz; ++j) { - if (m_clause->get_literal(j) == ~lit) { - if (j > 0) m_clause->swap_lits(j, 0); - break; + literal nlit = ~m_assigned_literals[i]; + if (m_clause_lits.contains(nlit)) { + switch (m_clause_lits.size()) { + case 1: { + b_justification js; + set_conflict(js, ~nlit); + break; + } + case 2: { + if (nlit == m_clause_lits[1]) { + std::swap(m_clause_lits[0], m_clause_lits[1]); } + b_justification js(~m_clause_lits[1]); + set_conflict(js, ~nlit); + break; } - b_justification js(m_clause); - set_conflict(js, ~lit); - return l_false; + default: { + for (unsigned j = 0, sz = m_clause->get_num_literals(); j < sz; ++j) { + if (m_clause->get_literal(j) == nlit) { + if (j > 0) m_clause->swap_lits(j, 0); + break; + } + } + b_justification js(m_clause); + set_conflict(js, ~nlit); + break; + } + } + break; } } - UNREACHABLE(); + VERIFY(!resolve_conflict()); return l_false; } @@ -3280,6 +3300,7 @@ namespace smt { if (m_clause) del_clause(m_clause); m_clause = nullptr; + m_clause_lits.reset(); m_unsat_core.reset(); m_stats.m_num_checks++; pop_to_base_lvl(); diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 0aee5c3dc..dbad0999e 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -107,12 +107,35 @@ public: } } + lbool check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl, expr_ref_vector* core, proof_ref* pr) override { + SASSERT(!m_pushed || get_scope_level() > 0); + m_proof.reset(); + internalize_assertions(); + expr_ref_vector cube1(cube); + cube1.push_back(m_pred); + lbool res = m_base->check_sat(cube1, clause, mdl, core, pr); + switch (res) { + case l_true: + m_pool.m_stats.m_num_sat_checks++; + break; + case l_undef: + m_pool.m_stats.m_num_undef_checks++; + break; + default: + break; + } + set_status(res); + + return res; + } + + // NSB: seems we would add m_pred as an assumption? lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); scoped_watch _t_(m_pool.m_check_watch); m_pool.m_stats.m_num_checks++; - + stopwatch sw; sw.start(); internalize_assertions(); diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index da4194a2c..1dc0290d8 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(test-z3 chashtable.cpp check_assumptions.cpp cnf_backbones.cpp + cube_clause.cpp datalog_parser.cpp ddnf.cpp diff_logic.cpp diff --git a/src/test/cube_clause.cpp b/src/test/cube_clause.cpp new file mode 100644 index 000000000..f625789e4 --- /dev/null +++ b/src/test/cube_clause.cpp @@ -0,0 +1,58 @@ +#include "ast/reg_decl_plugins.h" +#include "solver/solver_pool.h" +#include "smt/smt_solver.h" + + +void tst_cube_clause() { + ast_manager m; + reg_decl_plugins(m); + params_ref p; + lbool r; + ref solver = mk_smt_solver(m, p, symbol::null); + + expr_ref a(m.mk_const(symbol("a"), m.mk_bool_sort()), m); + expr_ref b(m.mk_const(symbol("b"), m.mk_bool_sort()), m); + expr_ref c(m.mk_const(symbol("c"), m.mk_bool_sort()), m); + expr_ref d(m.mk_const(symbol("d"), m.mk_bool_sort()), m); + expr_ref e(m.mk_const(symbol("e"), m.mk_bool_sort()), m); + expr_ref f(m.mk_const(symbol("f"), m.mk_bool_sort()), m); + expr_ref g(m.mk_const(symbol("g"), m.mk_bool_sort()), m); + expr_ref fml(m); + fml = m.mk_not(m.mk_and(a, b)); + solver->assert_expr(fml); + fml = m.mk_not(m.mk_and(c, d)); + solver->assert_expr(fml); + fml = m.mk_not(m.mk_and(e, f)); + solver->assert_expr(fml); + expr_ref_vector cube(m), clause(m), core(m); + r = solver->check_sat(cube); + std::cout << r << "\n"; + cube.push_back(a); + r = solver->check_sat(cube); + std::cout << r << "\n"; + cube.push_back(c); + cube.push_back(e); + r = solver->check_sat(cube); + std::cout << r << "\n"; + clause.push_back(b); + r = solver->check_sat(cube, clause); + std::cout << r << "\n"; + core.reset(); + solver->get_unsat_core(core); + std::cout << core << "\n"; + clause.push_back(d); + r = solver->check_sat(cube, clause); + std::cout << r << "\n"; + core.reset(); + solver->get_unsat_core(core); + std::cout << core << "\n"; + clause.push_back(f); + r = solver->check_sat(cube, clause); + std::cout << r << "\n"; + core.reset(); + solver->get_unsat_core(core); + std::cout << core << "\n"; + clause.push_back(g); + r = solver->check_sat(cube, clause); + std::cout << r << "\n"; +} diff --git a/src/test/main.cpp b/src/test/main.cpp index c1f169a3a..41f051f24 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -172,6 +172,7 @@ int main(int argc, char ** argv) { TST(var_subst); TST(simple_parser); TST(api); + TST(cube_clause); TST(old_interval); TST(get_implied_equalities); TST(arith_simplifier_plugin); From 56a29093d00dd70fba81e572b43607defd039202 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 28 May 2018 08:28:36 -0700 Subject: [PATCH 1081/1283] Cleanup transition creation in pred_transformer --- src/muz/spacer/spacer_context.cpp | 97 ++++++++++++++++++------------- src/muz/spacer/spacer_context.h | 11 ++-- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 3c94e5521..109055076 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -646,7 +646,7 @@ pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): m_pobs(*this), m_frames(*this), m_reach_facts(), m_rf_init_sz(0), - m_transition(m), m_initial_state(m), m_extend_lit(m), + m_transition_clause(m), m_transition(m), m_init(m), m_extend_lit(m), m_all_init(false), m_reach_case_vars(m) { @@ -866,12 +866,9 @@ void pred_transformer::simplify_formulas() {m_frames.simplify_formulas ();} -expr_ref pred_transformer::get_formulas(unsigned level, bool add_axioms) +expr_ref pred_transformer::get_formulas(unsigned level) { expr_ref_vector res(m); - if (add_axioms) { - res.push_back((level == 0)?initial_state():transition()); - } m_frames.get_frame_geq_lemmas (level, res); return mk_and(res); } @@ -1141,7 +1138,7 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, expr_ref v(m); if (!must) { // use may summary - summary.push_back (get_formulas (level, false)); + summary.push_back (get_formulas (level)); // -- no auxiliary variables in lemmas *aux = nullptr; } else { // find must summary to use @@ -1380,7 +1377,7 @@ bool pred_transformer::is_ctp_blocked(lemma *lem) { for (unsigned i = 0, sz = m_predicates.size(); i < sz; ++i) { pred_transformer &pt = ctx.get_pred_transformer(m_predicates[i]); expr_ref lemmas(m), val(m); - lemmas = pt.get_formulas(lem->level(), false); + lemmas = pt.get_formulas(lem->level()); pm.formula_n2o(lemmas.get(), lemmas, i); if (ctp->eval(lemmas, val) && m.is_false(val)) {return false;} } @@ -1498,20 +1495,20 @@ void pred_transformer::mk_assumptions(func_decl* head, expr* fml, void pred_transformer::initialize(decl2rel const& pts) { - m_initial_state = m.mk_false(); + m_init = m.mk_false(); m_transition = m.mk_true(); - init_rules(pts, m_initial_state, m_transition); + init_rules(pts); th_rewriter rw(m); rw(m_transition); - rw(m_initial_state); + rw(m_init); m_solver.assert_expr (m_transition); - m_solver.assert_expr (m_initial_state, 0); + m_solver.assert_expr (m_init, 0); TRACE("spacer", - tout << "Initial state: " << mk_pp(m_initial_state, m) << "\n"; + tout << "Initial state: " << mk_pp(m_init, m) << "\n"; tout << "Transition: " << mk_pp(m_transition, m) << "\n";); - SASSERT(is_app(m_initial_state)); - //m_reachable.add_init(to_app(m_initial_state)); + SASSERT(is_app(m_init)); + //m_reachable.add_init(to_app(m_init)); } @@ -1531,13 +1528,12 @@ void pred_transformer::init_reach_facts () } } -void pred_transformer::init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transition) -{ +void pred_transformer::init_rules(decl2rel const& pts) { expr_ref_vector transitions(m); ptr_vector tr_rules; datalog::rule const* rule; - expr_ref_vector disj(m), init_conds (m); - app_ref pred(m); + expr_ref_vector init_conds (m); + app_ref tag(m); vector is_init; for (auto r : m_rules) {init_rule(pts, *r, is_init, tr_rules, transitions);} SASSERT (is_init.size () == transitions.size ()); @@ -1545,41 +1541,49 @@ void pred_transformer::init_rules(decl2rel const& pts, expr_ref& init, expr_ref& std::string name; switch(transitions.size()) { case 0: - transition = m.mk_false(); + m_transition = m.mk_false(); + m_transition_clause.reset(); break; case 1: // create a dummy tag. name = head()->get_name().str() + "_dummy"; - pred = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); + tag = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); rule = tr_rules[0]; - m_tag2rule.insert(pred, rule); - m_rule2tag.insert(rule, pred.get()); - transitions[0] = m.mk_implies (pred, transitions.get(0)); - transitions.push_back (m.mk_or (pred, m_extend_lit->get_arg(0))); - if (!is_init[0]) {init_conds.push_back(m.mk_not(pred));} + m_tag2rule.insert(tag, rule); + m_rule2tag.insert(rule, tag); + transitions[0] = m.mk_implies (tag, transitions.get(0)); - transition = mk_and(transitions); + m_transition_clause.push_back(m_extend_lit->get_arg(0)); + m_transition_clause.push_back(tag); + + transitions.push_back(mk_or(m_transition_clause)); + m_transition_clause.reset(); + + if (!is_init[0]) {init_conds.push_back(m.mk_not(tag));} + + m_transition = mk_and(transitions); break; default: - disj.push_back (m_extend_lit->get_arg(0)); + m_transition_clause.push_back (m_extend_lit->get_arg(0)); for (unsigned i = 0; i < transitions.size(); ++i) { name = head()->get_name().str() + "__tr" + std::to_string(i); - pred = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); + tag = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); rule = tr_rules[i]; - m_tag2rule.insert(pred, rule); - m_rule2tag.insert(rule, pred); - disj.push_back(pred); - transitions[i] = m.mk_implies(pred, transitions[i].get()); + m_tag2rule.insert(tag, rule); + m_rule2tag.insert(rule, tag); + m_transition_clause.push_back(tag); + transitions[i] = m.mk_implies(tag, transitions.get(i)); // update init conds - if (!is_init[i]) {init_conds.push_back (m.mk_not (pred));} + if (!is_init[i]) {init_conds.push_back (m.mk_not (tag));} } - transitions.push_back(m.mk_or(disj.size(), disj.c_ptr())); - transition = mk_and(transitions); + transitions.push_back(mk_or(m_transition_clause)); + m_transition_clause.reset(); + m_transition = mk_and(transitions); break; } // mk init condition - init = mk_and(init_conds); + m_init = mk_and(init_conds); // no rule has uninterpreted tail if (init_conds.empty ()) {m_all_init = true;} } @@ -1718,20 +1722,29 @@ void pred_transformer::init_atom(decl2rel const &pts, app *atom, void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, expr_ref_vector& r) { - r.push_back((lvl == 0)?initial_state():transition()); + if (lvl == 0) {r.push_back(m_init);} + else { + r.push_back(m_transition); + if (!m_transition_clause.empty()) { + expr_ref c(m); + c = mk_or(m_transition_clause); + r.push_back(c); + } + } for (unsigned i = 0; i < rules().size(); ++i) { add_premises(pts, lvl, *rules()[i], r); } } -void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r) +void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, + datalog::rule& rule, expr_ref_vector& r) { find_predecessors(rule, m_predicates); for (unsigned i = 0; i < m_predicates.size(); ++i) { expr_ref tmp(m); func_decl* head = m_predicates[i]; pred_transformer& pt = *pts.find(head); - expr_ref inv = pt.get_formulas(lvl, false); + expr_ref inv = pt.get_formulas(lvl); if (!m.is_true(inv)) { pm.formula_n2o(inv, tmp, i, true); r.push_back(tmp); @@ -2365,7 +2378,7 @@ void context::get_level_property(unsigned lvl, expr_ref_vector& res, if (r->head() == m_query_pred) { continue; } - expr_ref conj = r->get_formulas(lvl, false); + expr_ref conj = r->get_formulas(lvl); m_pm.formula_n2o(0, false, conj); res.push_back(conj); ptr_vector sig(r->head()->get_arity(), r->sig()); @@ -3647,7 +3660,7 @@ bool context::check_invariant(unsigned lvl, func_decl* fn) ref ctx = mk_smt_solver(m, params_ref::get_empty(), symbol::null); pred_transformer& pt = *m_rels.find(fn); expr_ref_vector conj(m); - expr_ref inv = pt.get_formulas(next_level(lvl), false); + expr_ref inv = pt.get_formulas(next_level(lvl)); if (m.is_true(inv)) { return true; } pt.add_premises(m_rels, lvl, conj); conj.push_back(m.mk_not(inv)); @@ -3667,7 +3680,7 @@ expr_ref context::get_constraints (unsigned level) decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); for (; it != end; ++it) { pred_transformer& r = *it->m_value; - expr_ref c = r.get_formulas(level, false); + expr_ref c = r.get_formulas(level); if (m.is_true(c)) { continue; } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index c1241a1bd..cb6d1fc23 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -295,8 +295,9 @@ class pred_transformer { rule2expr m_rule2tag; // map rule to predicate tag. rule2expr m_rule2transition; // map rules to transition rule2apps m_rule2vars; // map rule to auxiliary variables - expr_ref m_transition; // transition relation. - expr_ref m_initial_state; // initial state. + expr_ref_vector m_transition_clause; // extra clause for trans + expr_ref m_transition; // transition relation + expr_ref m_init; // initial condition app_ref m_extend_lit; // literal to extend initial state bool m_all_init; // true if the pt has no uninterpreted body in any rule ptr_vector m_predicates; // temp vector used with find_predecessors() @@ -320,7 +321,7 @@ class pred_transformer { void mk_assumptions(func_decl* head, expr* fml, expr_ref_vector& result); // Initialization - void init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transition); + void init_rules(decl2rel const& pts); void init_rule(decl2rel const& pts, datalog::rule const& rule, vector& is_init, ptr_vector& rules, expr_ref_vector& transition); void init_atom(decl2rel const& pts, app * atom, app_ref_vector& var_reprs, @@ -355,7 +356,7 @@ public: func_decl* const* sig() {return m_sig.c_ptr();} unsigned sig_size() const {return m_sig.size();} expr* transition() const {return m_transition;} - expr* initial_state() const {return m_initial_state;} + expr* init() const {return m_init;} expr* rule2tag(datalog::rule const* r) {return m_rule2tag.find(r);} unsigned get_num_levels() {return m_frames.size ();} expr_ref get_cover_delta(func_decl* p_orig, int level); @@ -427,7 +428,7 @@ public: bool check_inductive(unsigned level, expr_ref_vector& state, unsigned& assumes_level, unsigned weakness = UINT_MAX); - expr_ref get_formulas(unsigned level, bool add_axioms); + expr_ref get_formulas(unsigned level); void simplify_formulas(); From ef58753ae7ab40fa8b783ac7dfa1f5c052c0cfd9 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 28 May 2018 18:20:57 -0700 Subject: [PATCH 1082/1283] Silence clang warning --- src/solver/solver_pool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index dbad0999e..4b54639ec 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -107,6 +107,8 @@ public: } } + using solver_na2as::check_sat; + lbool check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl, expr_ref_vector* core, proof_ref* pr) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); From c3edf8c8fad1276ee0821aaeae4b9b83bcd42db7 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 28 May 2018 18:28:38 -0700 Subject: [PATCH 1083/1283] Restore assertion in smt_clause --- src/smt/smt_clause.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/smt/smt_clause.cpp b/src/smt/smt_clause.cpp index 4266ab246..2b9b8dd3e 100644 --- a/src/smt/smt_clause.cpp +++ b/src/smt/smt_clause.cpp @@ -25,10 +25,10 @@ namespace smt { \brief Create a new clause. bool_var2expr_map is a mapping from bool_var -> expr, it is only used if save_atoms == true. */ - clause * clause::mk(ast_manager & m, unsigned num_lits, literal * lits, clause_kind k, justification * js, + clause * clause::mk(ast_manager & m, unsigned num_lits, literal * lits, clause_kind k, justification * js, clause_del_eh * del_eh, bool save_atoms, expr * const * bool_var2expr_map) { SASSERT(k == CLS_AUX || js == 0 || !js->in_region()); - SASSERT(num_lits > 2); + SASSERT(num_lits >= 2); unsigned sz = get_obj_size(num_lits, k, save_atoms, del_eh != nullptr, js != nullptr); void * mem = m.get_allocator().allocate(sz); clause * cls = new (mem) clause(); @@ -67,7 +67,7 @@ namespace smt { }}); return cls; } - + void clause::deallocate(ast_manager & m) { clause_del_eh * del_eh = get_del_eh(); if (del_eh) @@ -115,4 +115,3 @@ namespace smt { } }; - From 723e96175b0eb1e5cad8230e8633720549d035bd Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 28 May 2018 18:28:59 -0700 Subject: [PATCH 1084/1283] spacer: prepare to use incremental clause smt_solver interface --- src/muz/base/fixedpoint_params.pyg | 21 +++++++++--------- src/muz/spacer/spacer_context.cpp | 31 +++++++++++++++++++-------- src/muz/spacer/spacer_prop_solver.cpp | 12 ++++++++++- src/muz/spacer/spacer_prop_solver.h | 1 + 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 10e319786..b32f1f586 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -4,7 +4,7 @@ def_module_params('fixedpoint', params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'auto-config', 'Select: auto-config, datalog, spacer, pdr, bmc'), - ('datalog.default_table', SYMBOL, 'sparse', + ('datalog.default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), ('datalog.default_relation', SYMBOL, 'pentagon', 'default relation implementation: external_relation, pentagon'), @@ -80,9 +80,9 @@ def_module_params('fixedpoint', "generalize lemmas using induction strengthening"), ('pdr.use_arith_inductive_generalizer', BOOL, False, "generalize lemmas using arithmetic heuristics for induction strengthening"), - ('pdr.use_convex_closure_generalizer', BOOL, False, + ('pdr.use_convex_closure_generalizer', BOOL, False, "generalize using convex closures of lemmas"), - ('pdr.use_convex_interior_generalizer', BOOL, False, + ('pdr.use_convex_interior_generalizer', BOOL, False, "generalize using convex interiors of lemmas"), ('pdr.cache_mode', UINT, 0, "use no (0), symbolic (1) or explicit " + "cache (2) for model search"), @@ -92,7 +92,7 @@ def_module_params('fixedpoint', ('pdr.max_num_contexts', UINT, 500, "maximal number of contexts to create"), ('pdr.try_minimize_core', BOOL, False, "try to reduce core size (before inductive minimization)"), - ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), + ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), ('print_fixedpoint_extensions', BOOL, True, "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, " + "when printing rules"), @@ -111,7 +111,7 @@ def_module_params('fixedpoint', ('print_statistics', BOOL, False, 'print statistics'), ('print_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), - ('tab.selection', SYMBOL, 'weight', + ('tab.selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), ('xform.bit_blast', BOOL, False, 'bit-blast bit-vectors'), @@ -128,7 +128,7 @@ def_module_params('fixedpoint', ('xform.unfold_rules', UINT, 0, "unfold rules statically using iterative squarring"), ('xform.slice', BOOL, True, "simplify clause set using slicing"), - ('xform.karr', BOOL, False, + ('xform.karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), ('spacer.use_eqclass', BOOL, False, "Generalizes equalities to equivalence classes"), ('xform.transform_arrays', BOOL, False, @@ -141,9 +141,9 @@ def_module_params('fixedpoint', "Gives the number of quantifiers per array"), ('xform.instantiate_arrays.slice_technique', SYMBOL, "no-slicing", "=> GetId(i) = i, => GetId(i) = true"), - ('xform.quantify_arrays', BOOL, False, + ('xform.quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), - ('xform.instantiate_quantifiers', BOOL, False, + ('xform.instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), ('xform.coalesce_rules', BOOL, False, "coalesce rules"), ('xform.tail_simplifier_pve', BOOL, True, "propagate_variable_equivalences"), @@ -155,9 +155,9 @@ def_module_params('fixedpoint', ('spacer.reset_obligation_queue', BOOL, True, 'SPACER: reset obligation queue when entering a new level'), ('spacer.init_reach_facts', BOOL, True, 'SPACER: initialize reachability facts with false'), ('spacer.use_array_eq_generalizer', BOOL, True, 'SPACER: attempt to generalize lemmas with array equalities'), - ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), + ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), ('xform.array_blast', BOOL, False, "try to eliminate local array terms using Ackermannization -- some array terms may remain"), - ('xform.array_blast_full', BOOL, False, "eliminate all local array variables by QE"), + ('xform.array_blast_full', BOOL, False, "eliminate all local array variables by QE"), ('spacer.skip_propagate', BOOL, False, "Skip propagate/pushing phase. Turns PDR into a BMC that returns either reachable or unknown"), ('spacer.max_level', UINT, UINT_MAX, "Maximum level to explore"), ('spacer.elim_aux', BOOL, True, "Eliminate auxiliary variables in reachability facts"), @@ -202,4 +202,5 @@ def_module_params('fixedpoint', ('spacer.from_level', UINT, 0, 'starting level to explore'), ('spacer.print_json', SYMBOL, '', 'print pobs tree in JSON format to a given file'), ('spacer.ctp', BOOL, False, 'enable counterexample-to-pushing technique'), + ('spacer.use_inc_clause', BOOL, False, 'Use incremental clause to represent trans'), )) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 109055076..5e2d0f1f4 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1199,9 +1199,13 @@ bool pred_transformer::is_blocked (pob &n, unsigned &uses_level) m_solver.set_core (nullptr); m_solver.set_model (nullptr); - expr_ref_vector post(m), aux(m); + expr_ref_vector post(m), _aux(m); post.push_back (n.post ()); - lbool res = m_solver.check_assumptions (post, aux, 0, nullptr, 0); + // this only uses the lemmas at the current level + // transition relation is irrelevant + // XXX quic3: not all lemmas are asserted at the post-condition + lbool res = m_solver.check_assumptions (post, _aux, _aux, + 0, nullptr, 0); if (res == l_false) { uses_level = m_solver.uses_level(); } return res == l_false; } @@ -1315,7 +1319,8 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, // result is either sat (with some reach assumps) or // unsat (even with no reach assumps) expr *bg = m_extend_lit.get (); - lbool is_sat = m_solver.check_assumptions (post, reach_assumps, 1, &bg, 0); + lbool is_sat = m_solver.check_assumptions (post, reach_assumps, + m_transition_clause, 1, &bg, 0); TRACE ("spacer", if (!reach_assumps.empty ()) { @@ -1423,7 +1428,8 @@ bool pred_transformer::is_invariant(unsigned level, lemma* lem, m_solver.set_core(core); m_solver.set_model(mdl_ref_ptr); expr * bg = m_extend_lit.get (); - lbool r = m_solver.check_assumptions (conj, aux, 1, &bg, 1); + lbool r = m_solver.check_assumptions (conj, aux, m_transition_clause, + 1, &bg, 1); if (r == l_false) { solver_level = m_solver.uses_level (); lem->reset_ctp(); @@ -1455,7 +1461,9 @@ bool pred_transformer::check_inductive(unsigned level, expr_ref_vector& state, m_solver.set_model (nullptr); expr_ref_vector aux (m); conj.push_back (m_extend_lit); - lbool res = m_solver.check_assumptions (state, aux, conj.size (), conj.c_ptr (), 1); + lbool res = m_solver.check_assumptions (state, aux, + m_transition_clause, + conj.size (), conj.c_ptr (), 1); if (res == l_false) { state.reset(); state.append(core); @@ -1557,8 +1565,10 @@ void pred_transformer::init_rules(decl2rel const& pts) { m_transition_clause.push_back(m_extend_lit->get_arg(0)); m_transition_clause.push_back(tag); - transitions.push_back(mk_or(m_transition_clause)); - m_transition_clause.reset(); + if (!ctx.get_params().spacer_use_inc_clause()) { + transitions.push_back(mk_or(m_transition_clause)); + m_transition_clause.reset(); + } if (!is_init[0]) {init_conds.push_back(m.mk_not(tag));} @@ -1577,8 +1587,11 @@ void pred_transformer::init_rules(decl2rel const& pts) { // update init conds if (!is_init[i]) {init_conds.push_back (m.mk_not (tag));} } - transitions.push_back(mk_or(m_transition_clause)); - m_transition_clause.reset(); + + if (!ctx.get_params().spacer_use_inc_clause()) { + transitions.push_back(mk_or(m_transition_clause)); + m_transition_clause.reset(); + } m_transition = mk_and(transitions); break; } diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 6b29df074..dcbc4bf88 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -347,9 +347,13 @@ lbool prop_solver::internal_check_assumptions( lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, expr_ref_vector& soft, + const expr_ref_vector &clause, unsigned num_bg, expr * const * bg, unsigned solver_id) { + expr_ref cls(m); + // XXX now clause is only supported when pushing is enabled + SASSERT(clause.empty() || !m_use_push_bg); // current clients expect that flattening of HARD is // done implicitly during check_assumptions expr_ref_vector hard(m); @@ -360,7 +364,13 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, // can be disabled if use_push_bg == true // solver::scoped_push _s_(*m_ctx); - if (!m_use_push_bg) { m_ctx->push(); } + if (!m_use_push_bg) { + m_ctx->push(); + if (!clause.empty()) { + cls = mk_or(clause); + m_ctx->assert_expr(cls); + } + } iuc_solver::scoped_bg _b_(*m_ctx); for (unsigned i = 0; i < num_bg; ++i) diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index e87732e94..e1c62443e 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -94,6 +94,7 @@ public: */ lbool check_assumptions(const expr_ref_vector & hard, expr_ref_vector & soft, + const expr_ref_vector &clause, unsigned num_bg = 0, expr * const *bg = nullptr, unsigned solver_id = 0); From 4477f7d32648dc420ea11e4b4594cc429d42b685 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 28 May 2018 19:03:55 -0700 Subject: [PATCH 1085/1283] Fix memory leak in asserted_formulas --- src/smt/asserted_formulas.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index c7ae7605f..d364404da 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -500,6 +500,7 @@ unsigned asserted_formulas::propagate_values(unsigned i) { void asserted_formulas::update_substitution(expr* n, proof* pr) { expr* lhs, *rhs, *n1; + proof_ref pr1(m); if (is_ground(n) && m.is_eq(n, lhs, rhs)) { compute_depth(lhs); compute_depth(rhs); @@ -510,13 +511,13 @@ void asserted_formulas::update_substitution(expr* n, proof* pr) { } if (is_gt(rhs, lhs)) { TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); - m_scoped_substitution.insert(rhs, lhs, m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr); + pr1 = m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr; + m_scoped_substitution.insert(rhs, lhs, pr1); return; } TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); } - proof_ref pr1(m); - if (m.is_not(n, n1)) { + if (m.is_not(n, n1)) { pr1 = m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr; m_scoped_substitution.insert(n1, m.mk_false(), pr1); } @@ -638,4 +639,3 @@ void pp(asserted_formulas & f) { f.display(std::cout); } #endif - From 26339119e4dd23e4e9fbf0772b1c1422cffa75df Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 29 May 2018 13:16:30 -0700 Subject: [PATCH 1086/1283] solver::check_sat_cc : check_sat assuming cube and clause Extends check_sat with an ability to assume a single clause in addition to assuming a cube of assumptions --- src/smt/smt_solver.cpp | 21 ++----------- src/solver/solver.cpp | 21 ------------- src/solver/solver.h | 5 ++- src/solver/solver_na2as.cpp | 6 ++++ src/solver/solver_na2as.h | 6 ++-- src/solver/solver_pool.cpp | 61 +++++++++++++++++++++---------------- 6 files changed, 50 insertions(+), 70 deletions(-) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 0f5338ba6..d715e4879 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -190,26 +190,9 @@ namespace smt { return m_context.check(num_assumptions, assumptions); } - using solver_na2as::check_sat; - lbool check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl, expr_ref_vector* core, proof_ref* pr) override { - lbool r = m_context.check(cube, clause); - switch (r) { - case l_false: - if (pr) *pr = get_proof(); - if (core) { - ptr_vector _core; - get_unsat_core(_core); - core->append(_core.size(), _core.c_ptr()); - } - break; - case l_true: - if (mdl) get_model(*mdl); - break; - default: - break; - } - return r; + lbool check_sat_cc_core(expr_ref_vector const& cube, expr_ref_vector const& clause) override { + return m_context.check(cube, clause); } struct scoped_minimize_core { diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index d295427e4..84b5eb588 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -202,27 +202,6 @@ void solver::assert_expr(expr* f, expr* t) { assert_expr_core2(fml, a); } -lbool solver::check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl, expr_ref_vector* core, proof_ref* pr) { - ast_manager& m = clause.get_manager(); - scoped_push _push(*this); - expr_ref disj = mk_or(clause); - assert_expr(disj); - lbool r = check_sat(cube); - switch (r) { - case l_false: - if (core) get_unsat_core(*core); - if (pr) *pr = get_proof(); - break; - case l_true: - if (mdl) get_model(*mdl); - break; - default: - break; - } - return r; -} - - void solver::collect_param_descrs(param_descrs & r) { r.insert("solver.enforce_model_conversion", CPK_BOOL, "(default: false) enforce model conversion when asserting formulas"); } diff --git a/src/solver/solver.h b/src/solver/solver.h index 59a61b3c7..3d9befdbc 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -152,7 +152,10 @@ public: The cube corresponds to auxiliary assumptions. The clause as an auxiliary disjunction that is also assumed for the check. */ - virtual lbool check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl = nullptr, expr_ref_vector* core = nullptr, proof_ref* pr = nullptr); + virtual lbool check_sat_cc(expr_ref_vector const& cube, expr_ref_vector const& clause) { + if (clause.empty()) return check_sat(cube.size(), cube.c_ptr()); + NOT_IMPLEMENTED_YET(); + } /** \brief Set a progress callback procedure that is invoked by this solver during check_sat. diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index f98e08cdb..ac241b4a2 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -67,6 +67,12 @@ lbool solver_na2as::check_sat(unsigned num_assumptions, expr * const * assumptio return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr()); } +lbool solver_na2as::check_sat_cc(const expr_ref_vector &assumptions, const expr_ref_vector &clause) { + if (clause.empty()) return check_sat(assumptions.size(), assumptions.c_ptr()); + append_assumptions app(m_assumptions, assumptions.size(), assumptions.c_ptr()); + return check_sat_cc_core(m_assumptions, clause); +} + lbool solver_na2as::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { append_assumptions app(m_assumptions, asms.size(), asms.c_ptr()); return get_consequences_core(m_assumptions, vars, consequences); diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index 75fb27189..a3ed85a9a 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -36,19 +36,21 @@ public: void assert_expr_core2(expr * t, expr * a) override; // virtual void assert_expr_core(expr * t) = 0; - + // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. lbool check_sat(unsigned num_assumptions, expr * const * assumptions) override; + lbool check_sat_cc(const expr_ref_vector &assumptions, const expr_ref_vector &clause) override; void push() override; void pop(unsigned n) override; unsigned get_scope_level() const override; - + unsigned get_num_assumptions() const override { return m_assumptions.size(); } expr * get_assumption(unsigned idx) const override { return m_assumptions[idx]; } lbool get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) override; lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; protected: virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; + virtual lbool check_sat_cc_core(const expr_ref_vector &assumptions, const expr_ref_vector &clause) {NOT_IMPLEMENTED_YET();} virtual void push_core() = 0; virtual void pop_core(unsigned n) = 0; }; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 4b54639ec..8012dd129 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -107,37 +107,12 @@ public: } } - using solver_na2as::check_sat; - - lbool check_sat(expr_ref_vector const& cube, expr_ref_vector const& clause, model_ref* mdl, expr_ref_vector* core, proof_ref* pr) override { - SASSERT(!m_pushed || get_scope_level() > 0); - m_proof.reset(); - internalize_assertions(); - expr_ref_vector cube1(cube); - cube1.push_back(m_pred); - lbool res = m_base->check_sat(cube1, clause, mdl, core, pr); - switch (res) { - case l_true: - m_pool.m_stats.m_num_sat_checks++; - break; - case l_undef: - m_pool.m_stats.m_num_undef_checks++; - break; - default: - break; - } - set_status(res); - - return res; - } - - // NSB: seems we would add m_pred as an assumption? lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); scoped_watch _t_(m_pool.m_check_watch); m_pool.m_stats.m_num_checks++; - + stopwatch sw; sw.start(); internalize_assertions(); @@ -156,13 +131,45 @@ public: break; } set_status(res); - + if (false /*m_dump_benchmarks && sw.get_seconds() >= m_pool.fparams().m_dump_min_time*/) { dump_benchmark(num_assumptions, assumptions, res, sw); } return res; } + lbool check_sat_cc_core(const expr_ref_vector &cube, + const expr_ref_vector &clause) override { + SASSERT(!m_pushed || get_scope_level() > 0); + m_proof.reset(); + scoped_watch _t_(m_pool.m_check_watch); + m_pool.m_stats.m_num_checks++; + + stopwatch sw; + sw.start(); + internalize_assertions(); + lbool res = m_base->check_sat_cc(cube, clause); + sw.stop(); + switch (res) { + case l_true: + m_pool.m_check_sat_watch.add(sw); + m_pool.m_stats.m_num_sat_checks++; + break; + case l_undef: + m_pool.m_check_undef_watch.add(sw); + m_pool.m_stats.m_num_undef_checks++; + break; + default: + break; + } + set_status(res); + + // if (false /*m_dump_benchmarks && sw.get_seconds() >= m_pool.fparams().m_dump_min_time*/) { + // dump_benchmark(num_assumptions, assumptions, res, sw); + // } + return res; + } + void push_core() override { SASSERT(!m_pushed || get_scope_level() > 0); if (m_in_delayed_scope) { From 1343b272e738df0ea8c757a2998f8f92f2291205 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 29 May 2018 13:17:42 -0700 Subject: [PATCH 1087/1283] Implement iuc_solver::check_sat_cc --- src/muz/spacer/spacer_iuc_solver.cpp | 22 ++++++++++++++++++++++ src/muz/spacer/spacer_iuc_solver.h | 1 + 2 files changed, 23 insertions(+) diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index d924f36d7..2814fc249 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -127,6 +127,28 @@ lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions return res; } +lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, + const expr_ref_vector &clause) { + if (clause.empty()) {return check_sat(cube.size(), cube.c_ptr());} + + // -- remove any old assumptions + if (m_assumptions.size() > m_first_assumption) + { m_assumptions.shrink(m_first_assumption); } + + // -- replace theory literals in background assumptions with proxies + mk_proxies(m_assumptions); + // -- in case mk_proxies added new literals, they are all background + m_first_assumption = m_assumptions.size(); + + m_assumptions.append(cube); + m_is_proxied = mk_proxies(m_assumptions, m_first_assumption); + + lbool res; + res = m_solver.check_sat_cc(m_assumptions, clause); + set_status (res); + return res; +} + app* iuc_solver::def_manager::mk_proxy (expr *v) { diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 8bb0a8605..72d995208 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -123,6 +123,7 @@ public: {return m_solver.get_scope_level();} lbool check_sat(unsigned num_assumptions, expr * const *assumptions) override; + lbool check_sat_cc(const expr_ref_vector &cube, const expr_ref_vector &clause) override; void set_progress_callback(progress_callback *callback) override {m_solver.set_progress_callback(callback);} unsigned get_num_assertions() const override From f7d015de8dd44f96a1b49e09fdb60562720310a8 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 29 May 2018 13:18:02 -0700 Subject: [PATCH 1088/1283] Switch spacer_prop_solver to check_sat_cc --- src/muz/spacer/spacer_prop_solver.cpp | 27 ++++++++++----------------- src/muz/spacer/spacer_prop_solver.h | 6 ++++-- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index dcbc4bf88..7be4443e3 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -224,7 +224,8 @@ lbool prop_solver::mss(expr_ref_vector &hard, expr_ref_vector &soft) { /// Poor man's maxsat. No guarantees of maximum solution /// Runs maxsat loop on m_ctx Returns l_false if hard is unsat, /// otherwise reduces soft such that hard & soft is sat. -lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft) +lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft, + const expr_ref_vector &clause) { // replace expressions by assumption literals iuc_solver::scoped_mk_proxy _p_(*m_ctx, hard); @@ -232,7 +233,7 @@ lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft) // assume soft constraints are propositional literals (no need to proxy) hard.append(soft); - lbool res = m_ctx->check_sat(hard.size(), hard.c_ptr()); + lbool res = m_ctx->check_sat_cc(hard, clause); // if hard constraints alone are unsat or there are no soft // constraints, we are done if (res != l_false || soft.empty()) { return res; } @@ -266,7 +267,7 @@ lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft) } // check that the NEW constraints became sat - res = m_ctx->check_sat(hard.size(), hard.c_ptr()); + res = m_ctx->check_sat_cc(hard, clause); if (res != l_false) { break; } // still unsat, update the core and repeat core.reset(); @@ -284,9 +285,9 @@ lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft) return res; } -lbool prop_solver::internal_check_assumptions( - expr_ref_vector& hard_atoms, - expr_ref_vector& soft_atoms) +lbool prop_solver::internal_check_assumptions(expr_ref_vector &hard_atoms, + expr_ref_vector &soft_atoms, + const expr_ref_vector &clause) { // XXX Turn model generation if m_model != 0 SASSERT(m_ctx); @@ -298,7 +299,7 @@ lbool prop_solver::internal_check_assumptions( } if (m_in_level) { assert_level_atoms(m_current_level); } - lbool result = maxsmt(hard_atoms, soft_atoms); + lbool result = maxsmt(hard_atoms, soft_atoms, clause); if (result != l_false && m_model) { m_ctx->get_model(*m_model); } SASSERT(result != l_false || soft_atoms.empty()); @@ -352,8 +353,6 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, unsigned solver_id) { expr_ref cls(m); - // XXX now clause is only supported when pushing is enabled - SASSERT(clause.empty() || !m_use_push_bg); // current clients expect that flattening of HARD is // done implicitly during check_assumptions expr_ref_vector hard(m); @@ -364,13 +363,7 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, // can be disabled if use_push_bg == true // solver::scoped_push _s_(*m_ctx); - if (!m_use_push_bg) { - m_ctx->push(); - if (!clause.empty()) { - cls = mk_or(clause); - m_ctx->assert_expr(cls); - } - } + if (!m_use_push_bg) {m_ctx->push();} iuc_solver::scoped_bg _b_(*m_ctx); for (unsigned i = 0; i < num_bg; ++i) @@ -379,7 +372,7 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, unsigned soft_sz = soft.size(); (void) soft_sz; - lbool res = internal_check_assumptions(hard, soft); + lbool res = internal_check_assumptions(hard, soft, clause); if (!m_use_push_bg) { m_ctx->pop(1); } TRACE("psolve_verbose", diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index e1c62443e..337f24825 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -64,9 +64,11 @@ private: void ensure_level(unsigned lvl); lbool internal_check_assumptions(expr_ref_vector &hard, - expr_ref_vector &soft); + expr_ref_vector &soft, + const expr_ref_vector &clause); - lbool maxsmt(expr_ref_vector &hard, expr_ref_vector &soft); + lbool maxsmt(expr_ref_vector &hard, expr_ref_vector &soft, + const expr_ref_vector &clause); lbool mss(expr_ref_vector &hard, expr_ref_vector &soft); From 0c2e3c0894b8bf3b59fb97c42c71dd1f90a0f5f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 May 2018 15:40:39 -0700 Subject: [PATCH 1089/1283] fixes to clause proof tracking Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_antiunify.cpp | 4 +-- src/smt/smt_conflict_resolution.cpp | 1 + src/smt/smt_conflict_resolution.h | 2 +- src/smt/smt_context.cpp | 46 ++++++++--------------------- src/smt/smt_setup.cpp | 3 +- 5 files changed, 19 insertions(+), 37 deletions(-) diff --git a/src/muz/spacer/spacer_antiunify.cpp b/src/muz/spacer/spacer_antiunify.cpp index 8b5e9e75b..0edfb6598 100644 --- a/src/muz/spacer/spacer_antiunify.cpp +++ b/src/muz/spacer/spacer_antiunify.cpp @@ -57,8 +57,8 @@ struct var_abs_rewriter : public default_rewriter_cfg { { bool contains_const_child = false; app* a = to_app(t); - for (unsigned i=0, sz = a->get_num_args(); i < sz; ++i) { - if (m_util.is_numeral(a->get_arg(i))) { + for (expr * arg : *a) { + if (m_util.is_numeral(arg)) { contains_const_child = true; } } diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 7984fd5f0..f7bc60051 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -1033,6 +1033,7 @@ namespace smt { return pr; } SASSERT(js != 0); + TRACE("proof_gen_bug", tout << js << "\n";); m_todo_pr.push_back(tp_elem(js)); return nullptr; } diff --git a/src/smt/smt_conflict_resolution.h b/src/smt/smt_conflict_resolution.h index b5b857184..90390ae7e 100644 --- a/src/smt/smt_conflict_resolution.h +++ b/src/smt/smt_conflict_resolution.h @@ -96,7 +96,7 @@ namespace smt { }; tp_elem(literal l):m_kind(LITERAL), m_lidx(l.index()) {} tp_elem(enode * lhs, enode * rhs):m_kind(EQUALITY), m_lhs(lhs), m_rhs(rhs) {} - tp_elem(justification * js):m_kind(JUSTIFICATION), m_js(js) {} + tp_elem(justification * js):m_kind(JUSTIFICATION), m_js(js) { SASSERT(js);} }; svector m_todo_pr; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index ab7e4fa35..c6f77cf1f 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3144,8 +3144,14 @@ namespace smt { mark_as_relevant(lit); m_clause_lits.push_back(get_literal(lit)); } - if (m_clause_lits.size() > 2) - m_clause = clause::mk(m_manager, m_clause_lits.size(), m_clause_lits.c_ptr(), CLS_AUX); + if (m_clause_lits.size() >= 2) { + justification* js = nullptr; + if (m_manager.proofs_enabled()) { + proof * pr = mk_clause_def_axiom(m_clause_lits.size(), m_clause_lits.c_ptr(), nullptr); + js = mk_justification(justification_proof_wrapper(*this, pr)); + } + m_clause = clause::mk(m_manager, m_clause_lits.size(), m_clause_lits.c_ptr(), CLS_AUX, js); + } } lbool context::decide_clause() { @@ -3163,38 +3169,12 @@ namespace smt { return l_undef; } } - for (unsigned i = m_assigned_literals.size(); i-- > 0; ) { - literal nlit = ~m_assigned_literals[i]; - if (m_clause_lits.contains(nlit)) { - switch (m_clause_lits.size()) { - case 1: { - b_justification js; - set_conflict(js, ~nlit); - break; - } - case 2: { - if (nlit == m_clause_lits[1]) { - std::swap(m_clause_lits[0], m_clause_lits[1]); - } - b_justification js(~m_clause_lits[1]); - set_conflict(js, ~nlit); - break; - } - default: { - for (unsigned j = 0, sz = m_clause->get_num_literals(); j < sz; ++j) { - if (m_clause->get_literal(j) == nlit) { - if (j > 0) m_clause->swap_lits(j, 0); - break; - } - } - b_justification js(m_clause); - set_conflict(js, ~nlit); - break; - } - } - break; - } + if (m_clause_lits.size() == 1) { + set_conflict(b_justification(), ~m_clause_lits[0]); } + else { + set_conflict(b_justification(m_clause), null_literal); + } VERIFY(!resolve_conflict()); return l_false; } diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 3ab40cdc3..97f5c433c 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -730,7 +730,8 @@ namespace smt { } void setup::setup_i_arith() { - m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); + m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params)); + // m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); } void setup::setup_r_arith() { From ebfb2a4a1e1c52da405673791ef5f0eea95d38e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 May 2018 18:27:45 -0700 Subject: [PATCH 1090/1283] Fix mbp to respect reduce_all_selects option Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbp.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 1390c0ae5..438f1c061 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -592,10 +592,11 @@ public: flatten_and(fml); - do_qe_lite(vars, fml); while (!vars.empty()) { + do_qe_lite(vars, fml); + do_qe_bool(mdl, vars, fml); // sort out vars into bools, arith (int/real), and arrays @@ -613,21 +614,19 @@ public: vars.reset (); // project arrays - if (!array_vars.empty()) { - qe::array_project_plugin ap(m); - ap(mdl, array_vars, fml, vars, m_reduce_all_selects); - SASSERT (array_vars.empty ()); - m_rw (fml); - SASSERT (!m.is_false (fml)); - } - + qe::array_project_plugin ap(m); + ap(mdl, array_vars, fml, vars, m_reduce_all_selects); + SASSERT (array_vars.empty ()); + m_rw (fml); + SASSERT (!m.is_false (fml)); + TRACE ("qe", tout << "extended model:\n"; model_pp (tout, mdl); tout << "Vars: " << vars << "\n"; ); - } + // project reals, ints and other variables. if (!other_vars.empty ()) { TRACE ("qe", tout << "Other vars: " << other_vars << "\n"; From 61cd74818f3fb22c5b835d732922d18b75eb3df1 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 29 May 2018 21:22:32 -0700 Subject: [PATCH 1091/1283] Pin lemmas so that they don't disappear --- src/muz/spacer/spacer_context.cpp | 3 +++ src/muz/spacer/spacer_context.h | 11 ++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 5e2d0f1f4..e826e19aa 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1834,6 +1834,9 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) // new_lemma is really new m_lemmas.push_back(new_lemma); + // XXX because m_lemmas is reduced, keep secondary vector of all lemmas + // XXX so that pob can refer to its lemmas without creating reference cycles + m_pinned_lemmas.push_back(new_lemma); m_sorted = false; m_pt.add_lemma_core(new_lemma); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index cb6d1fc23..f1b852cc3 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -198,12 +198,13 @@ class pred_transformer { #include "muz/spacer/spacer_legacy_frames.h" class frames { private: - pred_transformer &m_pt; - lemma_ref_vector m_lemmas; - unsigned m_size; + pred_transformer &m_pt; // parent pred_transformer + lemma_ref_vector m_pinned_lemmas; // all created lemmas + lemma_ref_vector m_lemmas; // active lemmas + unsigned m_size; // num of frames - bool m_sorted; - lemma_lt_proc m_lt; + bool m_sorted; // true if m_lemmas is sorted by m_lt + lemma_lt_proc m_lt; // sort order for m_lemmas void sort (); From 5072a2a869f2b312649a815a8b495009840ea92f Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 29 May 2018 21:23:32 -0700 Subject: [PATCH 1092/1283] spacer: pobs keep track of their lemmas --- src/muz/spacer/spacer_context.cpp | 33 +++++++++++++++++++++---------- src/muz/spacer/spacer_context.h | 8 ++++++++ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index e826e19aa..3d7e9a921 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -70,7 +70,6 @@ pob::pob (pob* parent, pred_transformer& pt, } } - void pob::set_post(expr* post) { app_ref_vector empty_binding(get_ast_manager()); set_post(post, empty_binding); @@ -1800,36 +1799,48 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) << m_pt.head()->get_name() << " " << mk_pp(new_lemma->get_expr(), m_pt.get_ast_manager()) << "\n";); - for (unsigned i = 0, sz = m_lemmas.size(); i < sz; ++i) { - if (m_lemmas[i]->get_expr() == new_lemma->get_expr()) { + unsigned i = 0; + for (auto *old_lemma : m_lemmas) { + if (old_lemma->get_expr() == new_lemma->get_expr()) { m_pt.get_context().new_lemma_eh(m_pt, new_lemma); + + // register existing lemma with the pob + if (new_lemma->has_pob()) { + pob_ref &pob = new_lemma->get_pob(); + if (!pob->lemmas().contains(old_lemma)) + pob->add_lemma(old_lemma); + } + // extend bindings if needed if (!new_lemma->get_bindings().empty()) { - m_lemmas[i]->add_binding(new_lemma->get_bindings()); + old_lemma->add_binding(new_lemma->get_bindings()); } // if the lemma is at a higher level, skip it, - if (m_lemmas[i]->level() >= new_lemma->level()) { + if (old_lemma->level() >= new_lemma->level()) { TRACE("spacer", tout << "Already at a higher level: " - << pp_level(m_lemmas[i]->level()) << "\n";); + << pp_level(old_lemma->level()) << "\n";); // but, since the instances might be new, assert the // instances that have been copied into m_lemmas[i] if (!new_lemma->get_bindings().empty()) { - m_pt.add_lemma_core(m_lemmas[i], true); + m_pt.add_lemma_core(old_lemma, true); } // no new lemma added return false; } // update level of the existing lemma - m_lemmas[i]->set_level(new_lemma->level()); + old_lemma->set_level(new_lemma->level()); // assert lemma in the solver - m_pt.add_lemma_core(m_lemmas[i], false); + m_pt.add_lemma_core(old_lemma, false); // move the lemma to its new place to maintain sortedness - for (unsigned j = i; (j + 1) < sz && m_lt(m_lemmas[j + 1], m_lemmas[j]); ++j) { + unsigned sz = m_lemmas.size(); + for (unsigned j = i; + (j + 1) < sz && m_lt(m_lemmas[j + 1], m_lemmas[j]); ++j) { m_lemmas.swap (j, j+1); } return true; } + i++; } // new_lemma is really new @@ -1840,6 +1851,8 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) m_sorted = false; m_pt.add_lemma_core(new_lemma); + if (new_lemma->has_pob()) {new_lemma->get_pob()->add_lemma(new_lemma);} + if (!new_lemma->external()) { m_pt.get_context().new_lemma_eh(m_pt, new_lemma); } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index f1b852cc3..2adf23007 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -486,7 +486,11 @@ class pob { /// derivation representing the position of this node in the parent's rule scoped_ptr m_derivation; + /// pobs created as children of this pob (at any time, not + /// necessarily currently active) ptr_vector m_kids; + // lemmas created to block this pob (at any time, not necessarily active) + ptr_vector m_lemmas; // depth -> watch std::map m_expand_watches; @@ -542,9 +546,13 @@ public: bool is_closed () const { return !m_open; } void close(); + const ptr_vector &children() {return m_kids;} void add_child (pob &v) {m_kids.push_back (&v);} void erase_child (pob &v) {m_kids.erase (&v);} + const ptr_vector &lemmas() {return m_lemmas;} + void add_lemma(lemma* new_lemma) {m_lemmas.push_back(new_lemma);} + bool is_ground () { return m_binding.empty (); } unsigned get_free_vars_size() { return m_binding.size(); } app_ref_vector const &get_binding() const {return m_binding;} From bfa472faece8e9ca356848adc99db2d5cc98f96f Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 29 May 2018 22:11:52 -0700 Subject: [PATCH 1093/1283] New style of json dump based on lemmas at pob --- src/muz/spacer/spacer_context.cpp | 6 +- src/muz/spacer/spacer_context.h | 4 +- src/muz/spacer/spacer_json.cpp | 234 +++++++++++++++++------------- src/muz/spacer/spacer_json.h | 39 +++-- 4 files changed, 156 insertions(+), 127 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 3d7e9a921..491349a4e 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -441,7 +441,7 @@ void derivation::premise::set_summary (expr * summary, bool must, lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : m_ref_count(0), m(manager), m_body(body, m), m_cube(m), - m_zks(m), m_bindings(m), m_lvl(lvl), + m_zks(m), m_bindings(m), m_lvl(lvl), m_init_lvl(m_lvl), m_pob(nullptr), m_ctp(nullptr), m_external(false) { SASSERT(m_body); normalize(m_body, m_body); @@ -450,7 +450,7 @@ lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : lemma::lemma(pob_ref const &p) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), - m_zks(m), m_bindings(m), m_lvl(p->level()), + m_zks(m), m_bindings(m), m_lvl(p->level()), m_init_lvl(m_lvl), m_pob(p), m_ctp(nullptr), m_external(false) { SASSERT(m_pob); m_pob->get_skolems(m_zks); @@ -461,7 +461,7 @@ lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), - m_zks(m), m_bindings(m), m_lvl(p->level()), + m_zks(m), m_bindings(m), m_lvl(p->level()), m_init_lvl(m_lvl), m_pob(p), m_ctp(nullptr), m_external(false) { if (m_pob) { diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 2adf23007..c28f69d8b 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -114,7 +114,8 @@ class lemma { expr_ref_vector m_cube; app_ref_vector m_zks; app_ref_vector m_bindings; - unsigned m_lvl; + unsigned m_lvl; // current level of the lemma + unsigned m_init_lvl; // level at which lemma was created pob_ref m_pob; model_ref m_ctp; // counter-example to pushing bool m_external; @@ -150,6 +151,7 @@ public: bool is_inductive() const {return is_infty_level(m_lvl);} unsigned level () const {return m_lvl;} + unsigned init_level() const {return m_init_lvl;} void set_level (unsigned lvl); app_ref_vector& get_bindings() {return m_bindings;} bool has_binding(app_ref_vector const &binding); diff --git a/src/muz/spacer/spacer_json.cpp b/src/muz/spacer/spacer_json.cpp index c1094f192..cf36eb899 100644 --- a/src/muz/spacer/spacer_json.cpp +++ b/src/muz/spacer/spacer_json.cpp @@ -24,56 +24,59 @@ Notes: namespace spacer { - std::ostream &json_marshal(std::ostream &out, ast *t, ast_manager &m) { +static std::ostream &json_marshal(std::ostream &out, ast *t, ast_manager &m) { - mk_epp pp = mk_epp(t, m); - std::ostringstream ss; - ss << pp; - out << "\""; - for (auto &c:ss.str()) { - switch (c) { - case '"': - out << "\\\""; - break; - case '\\': - out << "\\\\"; - break; - case '\b': - out << "\\b"; - break; - case '\f': - out << "\\f"; - break; - case '\n': - out << "\\n"; - break; - case '\r': - out << "\\r"; - break; - case '\t': - out << "\\t"; - break; - default: - if ('\x00' <= c && c <= '\x1f') { - out << "\\u" - << std::hex << std::setw(4) << std::setfill('0') << (int) c; - } else { - out << c; - } + mk_epp pp = mk_epp(t, m); + std::ostringstream ss; + ss << pp; + out << "\""; + for (auto &c:ss.str()) { + switch (c) { + case '"': + out << "\\\""; + break; + case '\\': + out << "\\\\"; + break; + case '\b': + out << "\\b"; + break; + case '\f': + out << "\\f"; + break; + case '\n': + out << "\\n"; + break; + case '\r': + out << "\\r"; + break; + case '\t': + out << "\\t"; + break; + default: + if ('\x00' <= c && c <= '\x1f') { + out << "\\u" + << std::hex << std::setw(4) << std::setfill('0') << (int) c; + } else { + out << c; } } - out << "\""; - return out; } + out << "\""; + return out; +} - std::ostream &json_marshal(std::ostream &out, lemma *l) { - out << R"({"level":")" << l->level() << R"(", "expr":)"; - json_marshal(out, l->get_expr(), l->get_ast_manager()); - out << "}"; - return out; - } +static std::ostream &json_marshal(std::ostream &out, lemma *l) { + out << "{" + << R"("init_level":")" << l->init_level() + << R"(", "level":")" << l->level() + << R"(", "expr":)"; + json_marshal(out, l->get_expr(), l->get_ast_manager()); + out << "}"; + return out; +} - std::ostream &json_marshal(std::ostream &out, const lemma_ref_vector &lemmas) { +static std::ostream &json_marshal(std::ostream &out, const lemma_ref_vector &lemmas) { std::ostringstream ls; for (auto l:lemmas) { @@ -85,74 +88,103 @@ namespace spacer { } - void json_marshaller::register_lemma(lemma *l) { - if (l->has_pob()) { - m_relations[&*l->get_pob()][l->get_pob()->depth()].push_back(l); +void json_marshaller::register_lemma(lemma *l) { + if (l->has_pob()) { + m_relations[&*l->get_pob()][l->get_pob()->depth()].push_back(l); + } +} + +void json_marshaller::register_pob(pob *p) { + m_relations[p]; +} + +void json_marshaller::marshal_lemmas_old(std::ostream &out) const { + unsigned pob_id = 0; + for (auto &pob_map:m_relations) { + std::ostringstream pob_lemmas; + for (auto &depth_lemmas : pob_map.second) { + pob_lemmas << ((unsigned)pob_lemmas.tellp() == 0 ? "" : ",") + << "\"" << depth_lemmas.first << "\":"; + json_marshal(pob_lemmas, depth_lemmas.second); } + if (pob_lemmas.tellp()) { + out << ((unsigned)out.tellp() == 0 ? "" : ",\n"); + out << "\"" << pob_id << "\":{" << pob_lemmas.str() << "}"; + } + pob_id++; } +} +void json_marshaller::marshal_lemmas_new(std::ostream &out) const { + unsigned pob_id = 0; + for (auto &pob_map:m_relations) { + std::ostringstream pob_lemmas; + pob *n = pob_map.first; + for (auto *l : n->lemmas()) { + pob_lemmas << ((unsigned)pob_lemmas.tellp() == 0 ? "" : ",") + << "\"0\":"; + lemma_ref_vector lemmas_vec; + lemmas_vec.push_back(l); + json_marshal(pob_lemmas, lemmas_vec); + } - void json_marshaller::register_pob(pob *p) { - m_relations[p]; + if (pob_lemmas.tellp()) { + out << ((unsigned)out.tellp() == 0 ? "" : ",\n"); + out << "\"" << pob_id << "\":{" << pob_lemmas.str() << "}"; + } + pob_id++; } +} - std::ostream &spacer::json_marshaller::marshal(std::ostream &out) const { - std::ostringstream nodes; - std::ostringstream edges; - std::ostringstream lemmas; +std::ostream &json_marshaller::marshal(std::ostream &out) const { + std::ostringstream nodes; + std::ostringstream edges; + std::ostringstream lemmas; - unsigned pob_id = 0; + if (m_old_style) + marshal_lemmas_old(lemmas); + else + marshal_lemmas_new(lemmas); + + unsigned pob_id = 0; + unsigned depth = 0; + while (true) { + double root_expand_time = m_ctx->get_root().get_expand_time(depth); + bool a = false; + pob_id = 0; for (auto &pob_map:m_relations) { - std::ostringstream pob_lemmas; - for (auto &depth_lemmas : pob_map.second) { - pob_lemmas << ((unsigned)pob_lemmas.tellp() == 0 ? "" : ",") << "\"" << depth_lemmas.first << "\":"; - json_marshal(pob_lemmas, depth_lemmas.second); - } - if (pob_lemmas.tellp()) { - lemmas << ((unsigned)lemmas.tellp() == 0 ? "" : ",\n"); - lemmas << "\"" << pob_id << "\":{" << pob_lemmas.str() << "}"; + pob *n = pob_map.first; + double expand_time = n->get_expand_time(depth); + if (expand_time > 0) { + a = true; + std::ostringstream pob_expr; + json_marshal(pob_expr, n->post(), n->get_ast_manager()); + + nodes << ((unsigned)nodes.tellp() == 0 ? "" : ",\n") << + "{\"id\":\"" << depth << n << + "\",\"relative_time\":\"" << expand_time / root_expand_time << + "\",\"absolute_time\":\"" << std::setprecision(2) << expand_time << + "\",\"predicate\":\"" << n->pt().head()->get_name() << + "\",\"expr_id\":\"" << n->post()->get_id() << + "\",\"pob_id\":\"" << pob_id << + "\",\"depth\":\"" << depth << + "\",\"expr\":" << pob_expr.str() << "}"; + if (n->parent()) { + edges << ((unsigned)edges.tellp() == 0 ? "" : ",\n") << + "{\"from\":\"" << depth << n->parent() << + "\",\"to\":\"" << depth << n << "\"}"; + } } pob_id++; } - - unsigned depth = 0; - while (true) { - double root_expand_time = m_ctx->get_root().get_expand_time(depth); - bool a = false; - pob_id = 0; - for (auto &pob_map:m_relations) { - pob *n = pob_map.first; - double expand_time = n->get_expand_time(depth); - if (expand_time > 0) { - a = true; - std::ostringstream pob_expr; - json_marshal(pob_expr, n->post(), n->get_ast_manager()); - - nodes << ((unsigned)nodes.tellp() == 0 ? "" : ",\n") << - "{\"id\":\"" << depth << n << - "\",\"relative_time\":\"" << expand_time / root_expand_time << - "\",\"absolute_time\":\"" << std::setprecision(2) << expand_time << - "\",\"predicate\":\"" << n->pt().head()->get_name() << - "\",\"expr_id\":\"" << n->post()->get_id() << - "\",\"pob_id\":\"" << pob_id << - "\",\"depth\":\"" << depth << - "\",\"expr\":" << pob_expr.str() << "}"; - if (n->parent()) { - edges << ((unsigned)edges.tellp() == 0 ? "" : ",\n") << - "{\"from\":\"" << depth << n->parent() << - "\",\"to\":\"" << depth << n << "\"}"; - } - } - pob_id++; - } - if (!a) { - break; - } - depth++; + if (!a) { + break; } - out << "{\n\"nodes\":[\n" << nodes.str() << "\n],\n"; - out << "\"edges\":[\n" << edges.str() << "\n],\n"; - out << "\"lemmas\":{\n" << lemmas.str() << "\n}\n}\n"; - return out; + depth++; } + out << "{\n\"nodes\":[\n" << nodes.str() << "\n],\n"; + out << "\"edges\":[\n" << edges.str() << "\n],\n"; + out << "\"lemmas\":{\n" << lemmas.str() << "\n}\n}\n"; + return out; +} } diff --git a/src/muz/spacer/spacer_json.h b/src/muz/spacer/spacer_json.h index b100a87dc..131e72678 100644 --- a/src/muz/spacer/spacer_json.h +++ b/src/muz/spacer/spacer_json.h @@ -31,34 +31,29 @@ class ast_manager; namespace spacer { - class lemma; - - typedef sref_vector lemma_ref_vector; - - class context; - - class pob; - - std::ostream &json_marshal(std::ostream &out, ast *t, ast_manager &m); - - std::ostream &json_marshal(std::ostream &out, lemma *l); - - std::ostream &json_marshal(std::ostream &out, lemma_ref_vector &lemmas); +class lemma; +typedef sref_vector lemma_ref_vector; +class context; +class pob; - class json_marshaller { - context *m_ctx; - std::map> m_relations; +class json_marshaller { + context *m_ctx; + bool m_old_style; + std::map> m_relations; - public: - json_marshaller(context *ctx) : m_ctx(ctx) {} + void marshal_lemmas_old(std::ostream &out) const; + void marshal_lemmas_new(std::ostream &out) const; +public: + json_marshaller(context *ctx, bool old_style = false) : + m_ctx(ctx), m_old_style(old_style) {} - void register_lemma(lemma *l); + void register_lemma(lemma *l); - void register_pob(pob *p); + void register_pob(pob *p); - std::ostream &marshal(std::ostream &out) const; - }; + std::ostream &marshal(std::ostream &out) const; +}; } From fce68536d3e9b09bc621af0705a318ae030e0639 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 30 May 2018 09:04:39 -0700 Subject: [PATCH 1094/1283] spacer: print all lemmas in json --- src/muz/spacer/spacer_json.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_json.cpp b/src/muz/spacer/spacer_json.cpp index cf36eb899..a99a8f298 100644 --- a/src/muz/spacer/spacer_json.cpp +++ b/src/muz/spacer/spacer_json.cpp @@ -119,9 +119,10 @@ void json_marshaller::marshal_lemmas_new(std::ostream &out) const { for (auto &pob_map:m_relations) { std::ostringstream pob_lemmas; pob *n = pob_map.first; + unsigned i = 0; for (auto *l : n->lemmas()) { pob_lemmas << ((unsigned)pob_lemmas.tellp() == 0 ? "" : ",") - << "\"0\":"; + << "\"" << i++ << "\":"; lemma_ref_vector lemmas_vec; lemmas_vec.push_back(l); json_marshal(pob_lemmas, lemmas_vec); From 3a97451f8cffbd1e7310913b0c7db19566dbd5b4 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 30 May 2018 09:05:05 -0700 Subject: [PATCH 1095/1283] spacer: normalize the cube before creating a lemma --- src/muz/spacer/spacer_context.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 491349a4e..5f8951ecb 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -487,8 +487,10 @@ void lemma::mk_expr_core() { if (m_pob) {mk_cube_core();} SASSERT(!m_cube.empty()); - m_body = ::push_not(::mk_and(m_cube)); + m_body = ::mk_and(m_cube); + // normalize works better with a cube normalize(m_body, m_body); + m_body = ::push_not(m_body); if (!m_zks.empty() && has_zk_const(m_body)) { app_ref_vector zks(m); From fb52c362107a1f41c0b1e5214a2f2a461d8cabf8 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 30 May 2018 09:11:16 -0700 Subject: [PATCH 1096/1283] spacer: switch to new IUC as default --- src/muz/base/fixedpoint_params.pyg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index b32f1f586..7b8f8fb72 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -181,11 +181,11 @@ def_module_params('fixedpoint', ('spacer.keep_proxy', BOOL, True, 'keep proxy variables (internal parameter)'), ('spacer.q3.instantiate', BOOL, True, 'instantiate quantified lemmas'), ('spacer.q3', BOOL, True, 'allow quantified lemmas in frames'), - ('spacer.iuc', UINT, 0, + ('spacer.iuc', UINT, 1, '0 = use old implementation of unsat-core-generation, ' + '1 = use new implementation of IUC generation, ' + '2 = use new implementation of IUC + min-cut optimization'), - ('spacer.iuc.arith', UINT, 0, + ('spacer.iuc.arith', UINT, 1, '0 = use simple Farkas plugin, ' + '1 = use simple Farkas plugin with constant from other partition (like old unsat-core-generation),' + '2 = use Gaussian elimination optimization (broken), 3 = use additive IUC plugin'), From b120923dd5dec11618da1f48b9a2936c8f567422 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 30 May 2018 11:54:57 -0700 Subject: [PATCH 1097/1283] qe_lite: bug fix in der::der_sort_vars() The case of VAR 1 = (+ (:var 2) 10) VAR 2 = (+ 0 foo) was not properly handled whenever VAR2 has only one reference. In that case, VAR2 is not marked as done when VAR1 is processed, causing VAR2 to be duplicated in elimination order --- src/qe/qe_lite.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 2a14aa6f2..296cb2ad2 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -142,10 +142,10 @@ namespace eq { } else { SASSERT(fr.second == 1); - visiting.reset_mark(t); + visiting.reset_mark(t); if (!done.is_marked(t)) { if (definitions.get(vidx, nullptr) != nullptr) - order.push_back(vidx); + order.push_back(vidx); done.mark(t); } } @@ -444,7 +444,7 @@ namespace eq { expr_ref r(m); m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr(), r); unsigned inx = sz - m_order[i]- 1; - SASSERT(m_subst_map[inx]==0); + SASSERT(m_subst_map[inx]==nullptr); m_subst_map[inx] = r; } } From 0452bc3d43936922de98af70f3a5f34778cd17ba Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 30 May 2018 11:59:57 -0700 Subject: [PATCH 1098/1283] qe_lite: simplify definitions before deciding on elimination order --- src/qe/qe_lite.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 296cb2ad2..715848f89 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -142,10 +142,10 @@ namespace eq { } else { SASSERT(fr.second == 1); - visiting.reset_mark(t); + visiting.reset_mark(t); if (!done.is_marked(t)) { if (definitions.get(vidx, nullptr) != nullptr) - order.push_back(vidx); + order.push_back(vidx); done.mark(t); } } From b50da20531c83f848db7ac086120150bc623fd1a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 30 May 2018 13:45:48 -0700 Subject: [PATCH 1099/1283] array_mbp: turn on model completion --- src/qe/qe_arrays.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 1b3bd6c20..bcf642fb7 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -631,6 +631,7 @@ namespace qe { void operator () (model& mdl, app_ref_vector& arr_vars, expr_ref& fml, app_ref_vector& aux_vars) { reset (); model_evaluator mev(mdl); + mev.set_model_completion(true); M = &mdl; m_mev = &mev; @@ -857,6 +858,7 @@ namespace qe { reset (); model_evaluator mev(mdl); + mev.set_model_completion(true); M = &mdl; m_mev = &mev; m_reduce_all_selects = reduce_all_selects; @@ -1167,6 +1169,7 @@ namespace qe { TRACE ("qe", tout << "Failed to project arrays\n";); } + mev.set_model_completion(true); // dealloc for (auto & kv : m_sel_terms) dealloc(kv.m_value); m_sel_terms.reset (); From bebfac047e54043f5e2acf682cd577d0ad7ea986 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 10:40:42 -0700 Subject: [PATCH 1100/1283] Dump benchmarks in pool_solver --- src/solver/solver_pool.cpp | 100 ++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 41 deletions(-) diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 8012dd129..a015c5ea2 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -32,8 +32,11 @@ class pool_solver : public solver_na2as { expr_ref_vector m_flat; bool m_pushed; bool m_in_delayed_scope; + bool m_dump_benchmarks; + double m_dump_threshold; unsigned m_dump_counter; + bool is_virtual() const { return !m.is_true(m_pred); } public: pool_solver(solver* b, solver_pool& pool, app_ref& pred): @@ -47,10 +50,13 @@ public: m_flat(m), m_pushed(false), m_in_delayed_scope(false), + m_dump_benchmarks(false), + m_dump_threshold(5.0), m_dump_counter(0) { if (is_virtual()) { solver_na2as::assert_expr_core2(m.mk_true(), pred); } + updt_params(m_base->get_params()); } ~pool_solver() override { @@ -64,7 +70,11 @@ public: solver* base_solver() { return m_base.get(); } solver* translate(ast_manager& m, params_ref const& p) override { UNREACHABLE(); return nullptr; } - void updt_params(params_ref const& p) override { solver::updt_params(p); m_base->updt_params(p); } + void updt_params(params_ref const& p) override { + solver::updt_params(p); m_base->updt_params(p); + m_dump_benchmarks = solver::get_params().get_bool("dump_benchmarks", false); + m_dump_threshold = solver::get_params().get_double("dump_threshold", 5.0); + } void push_params() override {m_base->push_params();} void pop_params() override {m_base->pop_params();} @@ -76,8 +86,8 @@ public: void get_unsat_core(ptr_vector & r) override { m_base->get_unsat_core(r); unsigned j = 0; - for (unsigned i = 0; i < r.size(); ++i) - if (m_pred != r[i]) + for (unsigned i = 0; i < r.size(); ++i) + if (m_pred != r[i]) r[j++] = r[i]; r.shrink(j); } @@ -132,8 +142,10 @@ public: } set_status(res); - if (false /*m_dump_benchmarks && sw.get_seconds() >= m_pool.fparams().m_dump_min_time*/) { - dump_benchmark(num_assumptions, assumptions, res, sw); + if (m_dump_benchmarks && sw.get_seconds() >= m_dump_threshold) { + expr_ref_vector cube(m, num_assumptions, assumptions); + expr_ref_vector clause(m); + dump_benchmark(cube, clause, res, sw.get_seconds()); } return res; } @@ -164,9 +176,9 @@ public: } set_status(res); - // if (false /*m_dump_benchmarks && sw.get_seconds() >= m_pool.fparams().m_dump_min_time*/) { - // dump_benchmark(num_assumptions, assumptions, res, sw); - // } + if (m_dump_benchmarks && sw.get_seconds() >= m_dump_threshold) { + dump_benchmark(cube, clause, res, sw.get_seconds()); + } return res; } @@ -179,9 +191,9 @@ public: m_pushed = true; m_in_delayed_scope = false; } - - if (!m_pushed) { - m_in_delayed_scope = true; + + if (!m_pushed) { + m_in_delayed_scope = true; } else { SASSERT(!m_in_delayed_scope); @@ -196,24 +208,24 @@ public: SASSERT(!m_in_delayed_scope); m_base->pop(n); m_pushed = lvl - n > 0; - } - else { - m_in_delayed_scope = lvl - n > 0; + } + else { + m_in_delayed_scope = lvl - n > 0; } } - + void assert_expr_core(expr * e) override { SASSERT(!m_pushed || get_scope_level() > 0); - if (m.is_true(e)) return; + if (m.is_true(e)) return; if (m_in_delayed_scope) { internalize_assertions(); m_base->push(); m_pushed = true; m_in_delayed_scope = false; } - + if (m_pushed) { - m_base->assert_expr(e); + m_base->assert_expr(e); } else { m_flat.push_back(e); @@ -221,7 +233,7 @@ public: m_assertions.append(m_flat); m_flat.reset(); } - } + } void get_model_core(model_ref & _m) override { m_base->get_model_core(_m); } @@ -235,7 +247,7 @@ public: void set_progress_callback(progress_callback * callback) override { m_base->set_progress_callback(callback); } expr_ref_vector cube(expr_ref_vector& vars, unsigned ) override { return expr_ref_vector(m); } - + ast_manager& get_manager() const override { return m_base->get_manager(); } void refresh(solver* new_base) { @@ -253,42 +265,49 @@ public: private: - void dump_benchmark(unsigned num_assumptions, expr * const * assumptions, lbool res, stopwatch& sw) { - std::string file_name = mk_file_name(); + void dump_benchmark(const expr_ref_vector &cube, const expr_ref_vector &clause, + lbool last_status, double last_time) { + std::string file_name = mk_file_name(); std::ofstream out(file_name); - if (!out) { + if (!out) { IF_VERBOSE(0, verbose_stream() << "could not open file " << file_name << " for output\n"); return; } - out << "(set-info :status " << lbool2status(res) << ")\n"; - m_base->display(out, num_assumptions, assumptions); - out << "(check-sat"; - for (unsigned i = 0; i < num_assumptions; ++i) { - out << " " << mk_pp(assumptions[i], m); + out << "(set-info :status " << lbool2status(last_status) << ")\n"; + m_base->display(out, cube.size(), cube.c_ptr()); + if (!clause.empty()) { + out << ";; extra clause\n"; + out << "(assert (or "; + for (auto *lit : clause) out << mk_pp(lit, m) << " "; + out << "))\n"; } - out << ")"; + + out << "(check-sat"; + for (auto * lit : cube) out << " " << mk_pp(lit, m); + out << ")\n"; + out << "(exit)\n"; ::statistics st; m_base->collect_statistics(st); - st.update("time", sw.get_seconds()); - st.display_smt2(out); - out.close(); + st.update("time", last_time); + st.display_smt2(out); + out.close(); } char const* lbool2status(lbool r) const { switch (r) { case l_true: return "sat"; case l_false: return "unsat"; - case l_undef: return "unknown"; + case l_undef: return "unknown"; } return "?"; } std::string mk_file_name() { std::stringstream file_name; - file_name << "virt_solver"; - if (is_virtual()) file_name << "_" << m_pred->get_decl()->get_name(); + file_name << "pool_solver"; + if (is_virtual()) file_name << "_" << m_pred->get_decl()->get_name(); file_name << "_" << (m_dump_counter++) << ".smt2"; return file_name.str(); } @@ -317,12 +336,11 @@ ptr_vector solver_pool::get_base_solvers() const { void solver_pool::updt_params(const params_ref &p) { m_base_solver->updt_params(p); - ptr_vector solvers = get_base_solvers(); - for (solver *s : solvers) s->updt_params(p); + for (solver *s : m_solvers) s->updt_params(p); } void solver_pool::collect_statistics(statistics &st) const { ptr_vector solvers = get_base_solvers(); - for (solver* s : solvers) s->collect_statistics(st); + for (solver* s : solvers) s->collect_statistics(st); st.update("time.pool_solver.smt.total", m_check_watch.get_seconds()); st.update("time.pool_solver.smt.total.sat", m_check_sat_watch.get_seconds()); st.update("time.pool_solver.smt.total.undef", m_check_undef_watch.get_seconds()); @@ -336,7 +354,7 @@ void solver_pool::reset_statistics() { #if 0 ptr_vector solvers = get_base_solvers(); for (solver* s : solvers) { - s->reset_statistics(); + s->reset_statistics(); } #endif m_stats.reset(); @@ -348,7 +366,7 @@ void solver_pool::reset_statistics() { /** \brief Create a fresh solver instance. - The first num_pools solvers are independent and + The first num_pools solvers are independent and use a fresh instance of the base solver. Subsequent solvers reuse the first num_polls base solvers, rotating among the first num_pools. @@ -374,7 +392,7 @@ solver* solver_pool::mk_solver() { void solver_pool::reset_solver(solver* s) { pool_solver* ps = dynamic_cast(s); SASSERT(ps); - if (ps) ps->reset(); + if (ps) ps->reset(); } void solver_pool::refresh(solver* base_solver) { From e2e1411707e4a7968caffca511b6289b73a18939 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 10:42:25 -0700 Subject: [PATCH 1101/1283] Option to dump SMT queries as benchmarks during Spacer run --- src/muz/base/fixedpoint_params.pyg | 2 ++ src/muz/spacer/spacer_context.cpp | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 7b8f8fb72..9d3ee864d 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -203,4 +203,6 @@ def_module_params('fixedpoint', ('spacer.print_json', SYMBOL, '', 'print pobs tree in JSON format to a given file'), ('spacer.ctp', BOOL, False, 'enable counterexample-to-pushing technique'), ('spacer.use_inc_clause', BOOL, False, 'Use incremental clause to represent trans'), + ('spacer.dump_benchmarks', BOOL, False, 'Dump SMT queries as benchmarks'), + ('spacer.dump_threshold', DOUBLE, 5.0, 'Threshold in seconds on dumping benchmarks'), )) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 5f8951ecb..c9fa7f72b 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2342,13 +2342,12 @@ void context::init_global_smt_params() { } p.set_uint("random_seed", m_params.spacer_random_seed()); - // fparams.m_dump_benchmarks = m_params.spacer_vs_dump_benchmarks(); - // fparams.m_dump_min_time = m_params.spacer_vs_dump_min_time(); - // fparams.m_dump_recheck = m_params.spacer_vs_recheck(); + p.set_bool("dump_benchmarks", m_params.spacer_dump_benchmarks()); + p.set_double("dump_threshold", m_params.spacer_dump_threshold()); + // mbqi p.set_bool("mbqi", m_params.spacer_mbqi()); - if (!m_params.spacer_ground_cti()) { p.set_uint("phase_selection", PS_CACHING_CONSERVATIVE2); p.set_uint("restart_strategy", RS_GEOMETRIC); From 2a2b21326b5b29de8aea9671a873f0fda77bd16b Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 10:42:49 -0700 Subject: [PATCH 1102/1283] Stats on num_proxies in iuc_solver --- src/muz/spacer/spacer_iuc_solver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 2814fc249..1043dd939 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -209,6 +209,7 @@ void iuc_solver::collect_statistics (statistics &st) const { m_solver.collect_statistics (st); st.update ("time.iuc_solver.iuc_core", m_iuc_watch.get_seconds ()); + st.update("iuc_solver.num_proxies", m_proxies.size()); } void iuc_solver::reset_statistics () From fde58664f639ca2662cfb9b46ed9757efe14d0de Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 10:43:07 -0700 Subject: [PATCH 1103/1283] Moved mk_reach_fact to pred_transformer --- src/muz/spacer/spacer_context.cpp | 48 ++++++++++++------------------- src/muz/spacer/spacer_context.h | 7 +++-- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index c9fa7f72b..9d8e3d6af 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -688,6 +688,9 @@ void pred_transformer::collect_statistics(statistics& st) const // -- number of proof obligations (0 if pobs are not reused) st.update("SPACER num pobs", m_pobs.size()); + // -- number of reach facts created + st.update("SPACER num reach queries", m_stats.m_num_reach_queries); + st.update("SPACER num ctp blocked", m_stats.m_num_ctp_blocked); st.update("SPACER num is_invariant", m_stats.m_num_is_invariant); st.update("SPACER num lemma jumped", m_stats.m_num_lemma_level_jump); @@ -2345,9 +2348,9 @@ void context::init_global_smt_params() { p.set_bool("dump_benchmarks", m_params.spacer_dump_benchmarks()); p.set_double("dump_threshold", m_params.spacer_dump_threshold()); - // mbqi p.set_bool("mbqi", m_params.spacer_mbqi()); + if (!m_params.spacer_ground_cti()) { p.set_uint("phase_selection", PS_CACHING_CONSERVATIVE2); p.set_uint("restart_strategy", RS_GEOMETRIC); @@ -3018,7 +3021,7 @@ bool context::is_reachable(pob &n) mev.set_model(*model); // -- update must summary if (r && r->get_uninterpreted_tail_size () > 0) { - reach_fact_ref rf = mk_reach_fact (n, mev, *r); + reach_fact_ref rf = n.pt().mk_reach_fact (n, mev, *r); n.pt ().add_reach_fact (rf.get ()); } @@ -3158,7 +3161,7 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) if (is_concrete) { // -- update must summary if (r && r->get_uninterpreted_tail_size() > 0) { - reach_fact_ref rf = mk_reach_fact (n, mev, *r); + reach_fact_ref rf = n.pt().mk_reach_fact (n, mev, *r); checkpoint (); n.pt ().add_reach_fact (rf.get ()); checkpoint (); @@ -3373,50 +3376,49 @@ bool context::propagate(unsigned min_prop_lvl, return false; } -reach_fact *context::mk_reach_fact (pob& n, model_evaluator_util &mev, - const datalog::rule& r) +reach_fact *pred_transformer::mk_reach_fact (pob& n, model_evaluator_util &mev, + const datalog::rule& r) { + SASSERT(&n.pt() == this); timeit _timer1 (is_trace_enabled("spacer_timeit"), "mk_reach_fact", verbose_stream ()); expr_ref res(m); reach_fact_ref_vector child_reach_facts; - pred_transformer& pt = n.pt (); - ptr_vector preds; - pt.find_predecessors (r, preds); + find_predecessors (r, preds); expr_ref_vector path_cons (m); - path_cons.push_back (pt.get_transition (r)); + path_cons.push_back (get_transition (r)); app_ref_vector vars (m); for (unsigned i = 0; i < preds.size (); i++) { func_decl* pred = preds[i]; - pred_transformer& ch_pt = get_pred_transformer (pred); + pred_transformer& ch_pt = ctx.get_pred_transformer (pred); // get a reach fact of body preds used in the model expr_ref o_ch_reach (m); reach_fact *kid = ch_pt.get_used_origin_reach_fact (mev, i); child_reach_facts.push_back (kid); - m_pm.formula_n2o (kid->get (), o_ch_reach, i); + pm.formula_n2o (kid->get (), o_ch_reach, i); path_cons.push_back (o_ch_reach); // collect o-vars to eliminate for (unsigned j = 0; j < pred->get_arity (); j++) - { vars.push_back(m.mk_const(m_pm.o2o(ch_pt.sig(j), 0, i))); } + { vars.push_back(m.mk_const(pm.o2o(ch_pt.sig(j), 0, i))); } const ptr_vector &v = kid->aux_vars (); for (unsigned j = 0, sz = v.size (); j < sz; ++j) - { vars.push_back(m.mk_const(m_pm.n2o(v [j]->get_decl(), i))); } + { vars.push_back(m.mk_const(pm.n2o(v [j]->get_decl(), i))); } } // collect aux vars to eliminate - ptr_vector& aux_vars = pt.get_aux_vars (r); - bool elim_aux = get_params ().spacer_elim_aux (); + ptr_vector& aux_vars = get_aux_vars (r); + bool elim_aux = ctx.get_params().spacer_elim_aux(); if (elim_aux) { vars.append(aux_vars.size(), aux_vars.c_ptr()); } res = mk_and (path_cons); // -- pick an implicant from the path condition - if (get_params().spacer_reach_dnf()) { + if (ctx.get_params().spacer_reach_dnf()) { expr_ref_vector u(m), lits(m); u.push_back (res); compute_implicant_literals (mev, u, lits); @@ -3437,7 +3439,7 @@ reach_fact *context::mk_reach_fact (pob& n, model_evaluator_util &mev, timeit _timer1 (is_trace_enabled("spacer_timeit"), "mk_reach_fact::qe_project", verbose_stream ()); - qe_project (m, vars, res, mev.get_model (), false, m_use_native_mbp); + qe_project (m, vars, res, mev.get_model (), false, ctx.use_native_mbp()); } @@ -3601,8 +3603,6 @@ void context::collect_statistics(statistics& st) const // -- number of times a pob for some predicate transformer has // -- been created st.update("SPACER num queries", m_stats.m_num_queries); - // -- number of reach facts created - st.update("SPACER num reach queries", m_stats.m_num_reach_queries); // -- number of times a reach fact was true in some model st.update("SPACER num reuse reach facts", m_stats.m_num_reuse_reach); // -- maximum level at which any query was asked @@ -3641,16 +3641,6 @@ void context::collect_statistics(statistics& st) const for (unsigned i = 0; i < m_lemma_generalizers.size(); ++i) { m_lemma_generalizers[i]->collect_statistics(st); } - - // brunch out - verbose_stream () << "BRUNCH_STAT max_query_lvl " << m_stats.m_max_query_lvl << "\n"; - verbose_stream () << "BRUNCH_STAT num_queries " << m_stats.m_num_queries << "\n"; - verbose_stream () << "BRUNCH_STAT num_lemmas " << m_stats.m_num_lemmas << "\n"; - verbose_stream () << "BRUNCH_STAT num_reach_queries " << m_stats.m_num_reach_queries << "\n"; - verbose_stream () << "BRUNCH_STAT num_reach_reuse " << m_stats.m_num_reuse_reach << "\n"; - verbose_stream () << "BRUNCH_STAT inductive_lvl " << m_inductive_lvl << "\n"; - verbose_stream () << "BRUNCH_STAT max_depth " << m_stats.m_max_depth << "\n"; - verbose_stream () << "BRUNCH_STAT cex_depth " << m_stats.m_cex_depth << "\n"; } void context::reset_statistics() diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index c28f69d8b..9675fad09 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -192,6 +192,8 @@ class pred_transformer { unsigned m_num_ctp_blocked; // num of time ctp blocked lemma pushing unsigned m_num_is_invariant; // num of times lemmas are pushed unsigned m_num_lemma_level_jump; // lemma learned at higher level than expected + unsigned m_num_reach_queries; + stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; @@ -399,6 +401,8 @@ public: /// initialize reachability facts using initial rules void init_reach_facts (); + reach_fact *mk_reach_fact(pob &n, model_evaluator_util &mev, + const datalog::rule &r); void add_reach_fact (reach_fact *fact); // add reachability fact reach_fact* get_last_reach_fact () const { return m_reach_facts.back (); } expr* get_last_reach_case_var () const; @@ -761,7 +765,6 @@ class context { struct stats { unsigned m_num_queries; - unsigned m_num_reach_queries; unsigned m_num_reuse_reach; unsigned m_max_query_lvl; unsigned m_max_depth; @@ -816,8 +819,6 @@ class context { unsigned full_prop_lvl); bool is_reachable(pob &n); lbool expand_pob(pob &n, pob_ref_buffer &out); - reach_fact *mk_reach_fact(pob& n, model_evaluator_util &mev, - datalog::rule const& r); bool create_children(pob& n, const datalog::rule &r, model_evaluator_util &mdl, const vector& reach_pred_used, From 16fefe850a51de6d4007cc504a95fc05c5f7e353 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 11:16:05 -0700 Subject: [PATCH 1104/1283] Factored mbp into pred_transformer and added stats --- src/muz/spacer/spacer_context.cpp | 27 +++++++++++++++------------ src/muz/spacer/spacer_context.h | 6 ++++++ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 9d8e3d6af..ba7a2cb9b 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -227,8 +227,6 @@ pob *derivation::create_next_child (model_evaluator_util &mev) expr_ref_vector summaries (m); app_ref_vector vars (m); - bool use_native_mbp = get_context ().use_native_mbp (); - bool ground = get_context ().use_ground_cti (); // -- find first may premise while (m_active < m_premises.size() && m_premises[m_active].is_must()) { summaries.push_back (m_premises[m_active].get_summary ()); @@ -246,7 +244,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) timeit _timer1 (is_trace_enabled("spacer_timeit"), "create_next_child::qproject1", verbose_stream ()); - qe_project (m, vars, m_trans, mev.get_model (), true, use_native_mbp, !ground); + pt().mbp(vars, m_trans, mev.get_model()); //qe::reduce_array_selects (*mev.get_model (), m_trans); // remember variables that need to be existentially quantified m_evars.append (vars); @@ -274,7 +272,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) timeit _timer2 (is_trace_enabled("spacer_timeit"), "create_next_child::qproject2", verbose_stream ()); - qe_project (m, vars, post, mev.get_model (), true, use_native_mbp, !ground); + pt().mbp(vars, post, mev.get_model()); //qe::reduce_array_selects (*mev.get_model (), post); // remember variables that need to be existentially quantified @@ -309,9 +307,6 @@ pob *derivation::create_next_child () { if (m_active + 1 >= m_premises.size()) { return nullptr; } - bool use_native_mbp = get_context ().use_native_mbp (); - bool ground = get_context ().use_ground_cti (); - // update the summary of the active node to some must summary // construct a new model consistent with the must summary of m_active premise @@ -375,8 +370,7 @@ pob *derivation::create_next_child () { vars.push_back(m.mk_const(pm.o2n(pt.sig(i), 0))); } if (!vars.empty ()) { - qe_project (m, vars, m_trans, mev.get_model (), true, use_native_mbp, - !ground); + this->pt().mbp(vars, m_trans, mev.get_model()); // keep track of implicitly quantified variables m_evars.append (vars); } @@ -701,6 +695,7 @@ void pred_transformer::collect_statistics(statistics& st) const st.update ("time.spacer.solve.pt.must_reachable", m_must_reachable_watch.get_seconds ()); st.update("time.spacer.ctp", m_ctp_watch.get_seconds()); + st.update("time.spacer.mbp", m_mbp_watch.get_seconds()); } void pred_transformer::reset_statistics() @@ -711,6 +706,7 @@ void pred_transformer::reset_statistics() m_initialize_watch.reset (); m_must_reachable_watch.reset (); m_ctp_watch.reset(); + m_mbp_watch.reset(); } void pred_transformer::init_sig() @@ -1255,6 +1251,14 @@ bool pred_transformer::is_qblocked (pob &n) { return res == l_false; } + +void pred_transformer::mbp(app_ref_vector &vars, expr_ref &fml, + const model_ref &mdl, bool reduce_all_selects) { + scoped_watch _t_(m_mbp_watch); + qe_project(m, vars, fml, mdl, reduce_all_selects, + use_native_mbp(), !ctx.use_ground_cti()); +} + // // check if predicate transformer has a satisfiable predecessor state. // returns either a satisfiable predecessor state or @@ -3439,7 +3443,7 @@ reach_fact *pred_transformer::mk_reach_fact (pob& n, model_evaluator_util &mev, timeit _timer1 (is_trace_enabled("spacer_timeit"), "mk_reach_fact::qe_project", verbose_stream ()); - qe_project (m, vars, res, mev.get_model (), false, ctx.use_native_mbp()); + mbp(vars, res, mev.get_model(), false /*, false */); } @@ -3517,8 +3521,7 @@ bool context::create_children(pob& n, datalog::rule const& r, n.get_skolems(vars); expr_ref phi1 = mk_and (Phi); - qe_project (m, vars, phi1, mev.get_model (), true, - m_use_native_mbp, !m_ground_cti); + n.pt().mbp(vars, phi1, mev.get_model ()); //qe::reduce_array_selects (*mev.get_model (), phi1); SASSERT (!m_ground_cti || vars.empty ()); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 9675fad09..4ece95489 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -310,6 +310,7 @@ class pred_transformer { stopwatch m_initialize_watch; stopwatch m_must_reachable_watch; stopwatch m_ctp_watch; + stopwatch m_mbp_watch; /// Auxiliary variables to represent different disjunctive @@ -458,6 +459,10 @@ public: /// \brief Returns true if the obligation is already blocked by current quantified lemmas bool is_qblocked (pob &n); + /// \brief interface to Model Based Projection + void mbp(app_ref_vector &vars, expr_ref &fml, const model_ref &mdl, + bool reduce_all_selects = true); + }; @@ -679,6 +684,7 @@ public: ast_manager &get_ast_manager () const {return m_parent.get_ast_manager ();} manager &get_manager () const {return m_parent.get_manager ();} context &get_context() const {return m_parent.get_context();} + pred_transformer &pt() const {return m_parent.pt();} }; From cdba0721e76c7f34216b428f456646d8ad3c80a2 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 11:27:52 -0700 Subject: [PATCH 1105/1283] Extra stats in iuc_solver --- src/muz/spacer/spacer_iuc_solver.cpp | 39 +++++++++++++++++++++------- src/muz/spacer/spacer_iuc_solver.h | 5 +++- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 1043dd939..d9caefb33 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -208,13 +208,20 @@ bool iuc_solver::is_proxy(expr *e, app_ref &def) void iuc_solver::collect_statistics (statistics &st) const { m_solver.collect_statistics (st); - st.update ("time.iuc_solver.iuc_core", m_iuc_watch.get_seconds ()); + st.update ("time.iuc_solver.get_iuc", m_iuc_sw.get_seconds()); + st.update ("time.iuc_solver.get_iuc.hyp_reduce1", m_hyp_reduce1_sw.get_seconds()); + st.update ("time.iuc_solver.get_iuc.hyp_reduce2", m_hyp_reduce2_sw.get_seconds()); + st.update ("time.iuc_solver.get_iuc.learn_core", m_learn_core_sw.get_seconds()); + st.update("iuc_solver.num_proxies", m_proxies.size()); } void iuc_solver::reset_statistics () { - m_iuc_watch.reset (); + m_iuc_sw.reset(); + m_hyp_reduce1_sw.reset(); + m_hyp_reduce2_sw.reset(); + m_learn_core_sw.reset(); } void iuc_solver::get_unsat_core (ptr_vector &core) @@ -275,7 +282,7 @@ void iuc_solver::elim_proxies (expr_ref_vector &v) void iuc_solver::get_iuc(expr_ref_vector &core) { - scoped_watch _t_ (m_iuc_watch); + scoped_watch _t_ (m_iuc_sw); typedef obj_hashtable expr_set; expr_set core_lits; @@ -305,6 +312,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core) // -- old hypothesis reducer while the new one is broken if (m_old_hyp_reducer) { + scoped_watch _t_ (m_hyp_reduce1_sw); // AG: deprecated // pre-process proof in order to get a proof which is // better suited for unsat-core-extraction @@ -326,6 +334,8 @@ void iuc_solver::get_iuc(expr_ref_vector &core) // -- new hypothesis reducer else { + scoped_watch _t_ (m_hyp_reduce2_sw); + // pre-process proof for better iuc extraction if (m_print_farkas_stats) { iuc_proof iuc_before(m, res.get(), core_lits); @@ -333,11 +343,19 @@ void iuc_solver::get_iuc(expr_ref_vector &core) iuc_before.dump_farkas_stats(); } - theory_axiom_reducer ta_reducer(m); - proof_ref pr1(ta_reducer.reduce (res.get()), m); + proof_ref pr1(m); + { + scoped_watch _t_ (m_hyp_reduce1_sw); + theory_axiom_reducer ta_reducer(m); + pr1 = ta_reducer.reduce (res.get()); + } - hypothesis_reducer hyp_reducer(m); - proof_ref pr2(hyp_reducer.reduce(pr1), m); + proof_ref pr2(m); + { + scoped_watch _t_ (m_hyp_reduce2_sw); + hypothesis_reducer hyp_reducer(m); + pr2 = hyp_reducer.reduce(pr1); + } res = pr2; @@ -391,8 +409,11 @@ void iuc_solver::get_iuc(expr_ref_vector &core) UNREACHABLE(); } - // compute interpolating unsat core - learner.compute_unsat_core(core); + { + scoped_watch _t_ (m_learn_core_sw); + // compute interpolating unsat core + learner.compute_unsat_core(core); + } elim_proxies (core); // AG: this should be taken care of by minimizing the iuc cut diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 72d995208..c3b16b2dd 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -54,7 +54,10 @@ private: unsigned m_first_assumption; bool m_is_proxied; - stopwatch m_iuc_watch; + stopwatch m_iuc_sw; + stopwatch m_hyp_reduce1_sw; + stopwatch m_hyp_reduce2_sw; + stopwatch m_learn_core_sw; expr_substitution m_elim_proxies_sub; bool m_split_literals; From 1e5423788054f77a5c91b05d77c0de6ab623a98f Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 11:29:39 -0700 Subject: [PATCH 1106/1283] mbp_array: Fix set_model_completion bug --- src/qe/qe_arrays.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index bcf642fb7..651c167b6 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -1147,6 +1147,7 @@ namespace qe { if (arr_vars.empty()) return; reset (); model_evaluator mev(mdl); + mev.set_model_completion(true); M = &mdl; m_mev = &mev; @@ -1169,7 +1170,6 @@ namespace qe { TRACE ("qe", tout << "Failed to project arrays\n";); } - mev.set_model_completion(true); // dealloc for (auto & kv : m_sel_terms) dealloc(kv.m_value); m_sel_terms.reset (); From 451d42319b80bf855c648813a7226356f9512243 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 14:26:21 -0700 Subject: [PATCH 1107/1283] Rename m_reach_ctx into m_reach_solver --- src/muz/spacer/spacer_context.cpp | 18 +++++++++--------- src/muz/spacer/spacer_context.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index ba7a2cb9b..0a5be7893 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -637,7 +637,7 @@ pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): pm(pm), m(pm.get_manager()), ctx(ctx), m_head(head, m), m_sig(m), m_solver(pm, ctx.get_params(), head->get_name()), - m_reach_ctx (pm.mk_solver2()), + m_reach_solver (pm.mk_solver2()), m_pobs(*this), m_frames(*this), m_reach_facts(), m_rf_init_sz(0), @@ -739,12 +739,12 @@ bool pred_transformer::is_must_reachable(expr* state, model_ref* model) // reachable using the init rule of the current transformer if (m_reach_facts.empty()) { return false; } - m_reach_ctx->push (); - m_reach_ctx->assert_expr (state); - m_reach_ctx->assert_expr (m.mk_not (m_reach_case_vars.back ())); - lbool res = m_reach_ctx->check_sat (0, nullptr); - if (model) { m_reach_ctx->get_model(*model); } - m_reach_ctx->pop (1); + m_reach_solver->push (); + m_reach_solver->assert_expr (state); + m_reach_solver->assert_expr (m.mk_not (m_reach_case_vars.back ())); + lbool res = m_reach_solver->check_sat (0, nullptr); + if (model) { m_reach_solver->get_model(*model); } + m_reach_solver->pop (1); return (res == l_true); } @@ -1011,7 +1011,7 @@ void pred_transformer::add_reach_fact (reach_fact *fact) if (fact->is_init()) {m_rf_init_sz++;} - // update m_reach_ctx + // update m_reach_solver expr_ref last_var (m); expr_ref new_var (m); expr_ref fml (m); @@ -1029,7 +1029,7 @@ void pred_transformer::add_reach_fact (reach_fact *fact) if (last_var) {fml = m.mk_or(m.mk_not(last_var), fact->get(), new_var);} else {fml = m.mk_or(fact->get(), new_var);} - m_reach_ctx->assert_expr (fml); + m_reach_solver->assert_expr (fml); TRACE ("spacer", tout << "updating reach ctx: " << mk_pp(fml, m) << "\n";); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 4ece95489..77836a389 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -291,7 +291,7 @@ class pred_transformer { ptr_vector m_use; // places where 'this' is referenced. ptr_vector m_rules; // rules used to derive transformer prop_solver m_solver; // solver context - solver* m_reach_ctx; // context for reachability facts + ref m_reach_solver; // context for reachability facts pobs m_pobs; // proof obligations created so far frames m_frames; // frames with lemmas reach_fact_ref_vector m_reach_facts; // reach facts From 0b387cd7ebc40490500aa94ef48a6363c9da0059 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 14:48:01 -0700 Subject: [PATCH 1108/1283] Moved pool_solvers from spacer::manager into spacer::context --- src/muz/spacer/spacer_context.cpp | 113 +++++++++++++++----------- src/muz/spacer/spacer_context.h | 16 +++- src/muz/spacer/spacer_manager.cpp | 13 +-- src/muz/spacer/spacer_manager.h | 29 +------ src/muz/spacer/spacer_prop_solver.cpp | 9 +- src/muz/spacer/spacer_prop_solver.h | 10 ++- 6 files changed, 94 insertions(+), 96 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 0a5be7893..b27bd724e 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -636,8 +636,8 @@ void lemma::mk_insts(expr_ref_vector &out, expr* e) pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): pm(pm), m(pm.get_manager()), ctx(ctx), m_head(head, m), - m_sig(m), m_solver(pm, ctx.get_params(), head->get_name()), - m_reach_solver (pm.mk_solver2()), + m_sig(m), + m_reach_solver (ctx.mk_solver2()), m_pobs(*this), m_frames(*this), m_reach_facts(), m_rf_init_sz(0), @@ -645,6 +645,8 @@ pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): m_all_init(false), m_reach_case_vars(m) { + m_solver = alloc(prop_solver, m, ctx.mk_solver0(), ctx.mk_solver1(), + ctx.get_params(), head->get_name()); init_sig (); app_ref v(m); std::stringstream name; @@ -670,7 +672,7 @@ std::ostream& pred_transformer::display(std::ostream& out) const void pred_transformer::collect_statistics(statistics& st) const { - m_solver.collect_statistics(st); + m_solver->collect_statistics(st); // -- number of times a lemma has been propagated to a higher level // -- during push @@ -700,7 +702,7 @@ void pred_transformer::collect_statistics(statistics& st) const void pred_transformer::reset_statistics() { - m_solver.reset_statistics(); + m_solver->reset_statistics(); //m_reachable.reset_statistics(); m_stats.reset(); m_initialize_watch.reset (); @@ -727,7 +729,7 @@ void pred_transformer::ensure_level(unsigned level) while (m_frames.size() <= level) { m_frames.add_frame (); - m_solver.add_level (); + m_solver->add_level (); } } @@ -913,10 +915,10 @@ void pred_transformer::add_lemma_core(lemma* lemma, bool ground_only) if (is_infty_level(lvl)) { m_stats.m_num_invariants++; } if (lemma->is_ground()) { - if (is_infty_level(lvl)) { m_solver.assert_expr(l); } + if (is_infty_level(lvl)) { m_solver->assert_expr(l); } else { ensure_level (lvl); - m_solver.assert_expr (l, lvl); + m_solver->assert_expr (l, lvl); } } @@ -963,10 +965,10 @@ void pred_transformer::add_lemma_from_child (pred_transformer& child, TRACE("spacer_detail", tout << "child property: " << mk_pp(inst.get (j), m) << "\n";); if (is_infty_level(lvl)) { - m_solver.assert_expr(inst.get(j)); + m_solver->assert_expr(inst.get(j)); } else { - m_solver.assert_expr(inst.get(j), lvl); + m_solver->assert_expr(inst.get(j), lvl); } } } @@ -1195,18 +1197,18 @@ void pred_transformer::propagate_to_infinity (unsigned level) bool pred_transformer::is_blocked (pob &n, unsigned &uses_level) { ensure_level (n.level ()); - prop_solver::scoped_level _sl (m_solver, n.level ()); - m_solver.set_core (nullptr); - m_solver.set_model (nullptr); + prop_solver::scoped_level _sl (*m_solver, n.level ()); + m_solver->set_core (nullptr); + m_solver->set_model (nullptr); expr_ref_vector post(m), _aux(m); post.push_back (n.post ()); // this only uses the lemmas at the current level // transition relation is irrelevant // XXX quic3: not all lemmas are asserted at the post-condition - lbool res = m_solver.check_assumptions (post, _aux, _aux, + lbool res = m_solver->check_assumptions (post, _aux, _aux, 0, nullptr, 0); - if (res == l_false) { uses_level = m_solver.uses_level(); } + if (res == l_false) { uses_level = m_solver->uses_level(); } return res == l_false; } @@ -1282,12 +1284,12 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, ensure_level(n.level()); // prepare the solver - prop_solver::scoped_level _sl(m_solver, n.level()); - prop_solver::scoped_subset_core _sc (m_solver, !n.use_farkas_generalizer ()); - prop_solver::scoped_weakness _sw(m_solver, 0, + prop_solver::scoped_level _sl(*m_solver, n.level()); + prop_solver::scoped_subset_core _sc (*m_solver, !n.use_farkas_generalizer ()); + prop_solver::scoped_weakness _sw(*m_solver, 0, ctx.weak_abs() ? n.weakness() : UINT_MAX); - m_solver.set_core(core); - m_solver.set_model(model); + m_solver->set_core(core); + m_solver->set_model(model); expr_ref_vector post (m), reach_assumps (m); post.push_back (n.post ()); @@ -1327,7 +1329,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, // result is either sat (with some reach assumps) or // unsat (even with no reach assumps) expr *bg = m_extend_lit.get (); - lbool is_sat = m_solver.check_assumptions (post, reach_assumps, + lbool is_sat = m_solver->check_assumptions (post, reach_assumps, m_transition_clause, 1, &bg, 0); TRACE ("spacer", @@ -1362,7 +1364,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, } } ); - uses_level = m_solver.uses_level(); + uses_level = m_solver->uses_level(); return l_false; } UNREACHABLE(); @@ -1426,22 +1428,22 @@ bool pred_transformer::is_invariant(unsigned level, lemma* lem, conj.push_back(mk_not(m, lemma_expr)); flatten_and (conj); - prop_solver::scoped_level _sl(m_solver, level); - prop_solver::scoped_subset_core _sc (m_solver, true); - prop_solver::scoped_weakness _sw (m_solver, 1, + prop_solver::scoped_level _sl(*m_solver, level); + prop_solver::scoped_subset_core _sc (*m_solver, true); + prop_solver::scoped_weakness _sw (*m_solver, 1, ctx.weak_abs() ? lem->weakness() : UINT_MAX); model_ref mdl; model_ref *mdl_ref_ptr = nullptr; if (ctx.get_params().spacer_ctp()) {mdl_ref_ptr = &mdl;} - m_solver.set_core(core); - m_solver.set_model(mdl_ref_ptr); + m_solver->set_core(core); + m_solver->set_model(mdl_ref_ptr); expr * bg = m_extend_lit.get (); - lbool r = m_solver.check_assumptions (conj, aux, m_transition_clause, + lbool r = m_solver->check_assumptions (conj, aux, m_transition_clause, 1, &bg, 1); if (r == l_false) { - solver_level = m_solver.uses_level (); + solver_level = m_solver->uses_level (); lem->reset_ctp(); - if (level < m_solver.uses_level()) {m_stats.m_num_lemma_level_jump++;} + if (level < m_solver->uses_level()) {m_stats.m_num_lemma_level_jump++;} SASSERT (level <= solver_level); } else if (r == l_true) { @@ -1461,21 +1463,21 @@ bool pred_transformer::check_inductive(unsigned level, expr_ref_vector& state, states = mk_and(state); states = m.mk_not(states); mk_assumptions(head(), states, conj); - prop_solver::scoped_level _sl(m_solver, level); - prop_solver::scoped_subset_core _sc (m_solver, true); - prop_solver::scoped_weakness _sw (m_solver, 1, + prop_solver::scoped_level _sl(*m_solver, level); + prop_solver::scoped_subset_core _sc (*m_solver, true); + prop_solver::scoped_weakness _sw (*m_solver, 1, ctx.weak_abs() ? weakness : UINT_MAX); - m_solver.set_core(&core); - m_solver.set_model (nullptr); + m_solver->set_core(&core); + m_solver->set_model (nullptr); expr_ref_vector aux (m); conj.push_back (m_extend_lit); - lbool res = m_solver.check_assumptions (state, aux, + lbool res = m_solver->check_assumptions (state, aux, m_transition_clause, conj.size (), conj.c_ptr (), 1); if (res == l_false) { state.reset(); state.append(core); - uses_level = m_solver.uses_level(); + uses_level = m_solver->uses_level(); } TRACE ("core_array_eq", tout << "check_inductive: " @@ -1518,8 +1520,8 @@ void pred_transformer::initialize(decl2rel const& pts) rw(m_transition); rw(m_init); - m_solver.assert_expr (m_transition); - m_solver.assert_expr (m_init, 0); + m_solver->assert_expr (m_transition); + m_solver->assert_expr (m_init, 0); TRACE("spacer", tout << "Initial state: " << mk_pp(m_init, m) << "\n"; tout << "Transition: " << mk_pp(m_transition, m) << "\n";); @@ -1790,7 +1792,7 @@ app* pred_transformer::extend_initial (expr *e) // -- extend the initial condition ic = m.mk_or (m_extend_lit, e, v); - m_solver.assert_expr (ic); + m_solver->assert_expr (ic); // -- remember the new extend literal m_extend_lit = m.mk_not (v); @@ -2076,7 +2078,7 @@ context::context(fixedpoint_params const& params, m_params(params), m(m), m_context(nullptr), - m_pm(params.pdr_max_num_contexts(), m), + m_pm(m), m_query_pred(m), m_query(nullptr), m_pob_queue(), @@ -2090,8 +2092,19 @@ context::context(fixedpoint_params const& params, m_weak_abs(params.spacer_weak_abs()), m_use_restarts(params.spacer_restarts()), m_restart_initial_threshold(params.spacer_restart_initial_threshold()), - m_json_marshaller(this) -{} + m_json_marshaller(this) { + ref pool0_base = + mk_smt_solver(m, params_ref::get_empty(), symbol::null); + ref pool1_base = + mk_smt_solver(m, params_ref::get_empty(), symbol::null); + ref pool2_base = + mk_smt_solver(m, params_ref::get_empty(), symbol::null); + + unsigned max_num_contexts = params.pdr_max_num_contexts(); + m_pool0 = alloc(solver_pool, pool0_base.get(), max_num_contexts); + m_pool1 = alloc(solver_pool, pool1_base.get(), max_num_contexts); + m_pool2 = alloc(solver_pool, pool2_base.get(), max_num_contexts); +} context::~context() { @@ -2370,9 +2383,9 @@ void context::init_global_smt_params() { // fparams.m_pi_use_database = true; } - m_pm.updt_params0(p); - m_pm.updt_params1(p); - m_pm.updt_params2(p); + m_pool0->updt_params(p); + m_pool1->updt_params(p); + m_pool2->updt_params(p); } void context::init_lemma_generalizers() { @@ -3598,6 +3611,10 @@ bool context::create_children(pob& n, datalog::rule const& r, void context::collect_statistics(statistics& st) const { + m_pool0->collect_statistics(st); + m_pool1->collect_statistics(st); + m_pool2->collect_statistics(st); + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); for (it = m_rels.begin(); it != end; ++it) { it->m_value->collect_statistics(st); @@ -3639,7 +3656,6 @@ void context::collect_statistics(statistics& st) const st.update("spacer.random_seed", m_params.spacer_random_seed()); st.update("spacer.lemmas_imported", m_stats.m_num_lemmas_imported); st.update("spacer.lemmas_discarded", m_stats.m_num_lemmas_discarded); - m_pm.collect_statistics(st); for (unsigned i = 0; i < m_lemma_generalizers.size(); ++i) { m_lemma_generalizers[i]->collect_statistics(st); @@ -3648,12 +3664,15 @@ void context::collect_statistics(statistics& st) const void context::reset_statistics() { + m_pool0->reset_statistics(); + m_pool1->reset_statistics(); + m_pool2->reset_statistics(); + decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); for (it = m_rels.begin(); it != end; ++it) { it->m_value->reset_statistics(); } m_stats.reset(); - m_pm.reset_statistics(); for (unsigned i = 0; i < m_lemma_generalizers.size(); ++i) { m_lemma_generalizers[i]->reset_statistics(); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 77836a389..55e8cbafe 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -290,7 +290,7 @@ class pred_transformer { func_decl_ref_vector m_sig; // signature ptr_vector m_use; // places where 'this' is referenced. ptr_vector m_rules; // rules used to derive transformer - prop_solver m_solver; // solver context + scoped_ptr m_solver; // solver context ref m_reach_solver; // context for reachability facts pobs m_pobs; // proof obligations created so far frames m_frames; // frames with lemmas @@ -796,6 +796,13 @@ class context { ast_manager& m; datalog::context* m_context; manager m_pm; + + // three solver pools for different queries + scoped_ptr m_pool0; + scoped_ptr m_pool1; + scoped_ptr m_pool2; + + decl2rel m_rels; // Map from relation predicate to fp-operator. func_decl_ref m_query_pred; pred_transformer* m_query; @@ -928,6 +935,13 @@ public: void new_pob_eh(pob *p); bool is_inductive(); + + + // three different solvers with three different sets of parameters + // different solvers are used for different types of queries in spacer + solver* mk_solver0() {return m_pool0->mk_solver();} + solver* mk_solver1() {return m_pool1->mk_solver();} + solver* mk_solver2() {return m_pool2->mk_solver();} }; inline bool pred_transformer::use_native_mbp () {return ctx.use_native_mbp ();} diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index d55f74b90..719bf7862 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -176,19 +176,8 @@ static std::vector state_suffixes() { return res; } -manager::manager(unsigned max_num_contexts, ast_manager& manager) : +manager::manager(ast_manager& manager) : m(manager), m_mux(m, state_suffixes()) { - - ref pool0_base = - mk_smt_solver(m, params_ref::get_empty(), symbol::null); - ref pool1_base = - mk_smt_solver(m, params_ref::get_empty(), symbol::null); - ref pool2_base = - mk_smt_solver(m, params_ref::get_empty(), symbol::null); - - m_pool0 = alloc(solver_pool, pool0_base.get(), max_num_contexts); - m_pool1 = alloc(solver_pool, pool1_base.get(), max_num_contexts); - m_pool2 = alloc(solver_pool, pool2_base.get(), max_num_contexts); } diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index b8783369d..2149395ef 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -79,10 +79,6 @@ class manager { // manager of multiplexed names sym_mux m_mux; - // three solver pools for different queries - scoped_ptr m_pool0; - scoped_ptr m_pool1; - scoped_ptr m_pool2; unsigned n_index() const { return 0; } unsigned o_index(unsigned i) const { return i + 1; } @@ -90,7 +86,7 @@ class manager { void add_new_state(func_decl * s); public: - manager(unsigned max_num_contexts, ast_manager & manager); + manager(ast_manager & manager); ast_manager& get_manager() const { return m; } @@ -152,29 +148,6 @@ public: unsigned tgt_idx, bool homogenous = true) const {m_mux.conv_formula(src, o_index(src_idx), o_index(tgt_idx), tgt, homogenous);} - - // three different solvers with three different sets of parameters - // different solvers are used for different types of queries in spacer - solver* mk_solver0() {return m_pool0->mk_solver();} - void updt_params0(const params_ref &p) {m_pool0->updt_params(p);} - - solver* mk_solver1() {return m_pool1->mk_solver();} - void updt_params1(const params_ref &p) {m_pool1->updt_params(p);} - - solver* mk_solver2() {return m_pool2->mk_solver();} - void updt_params2(const params_ref &p) {m_pool2->updt_params(p);} - - void collect_statistics(statistics& st) const { - m_pool0->collect_statistics(st); - m_pool1->collect_statistics(st); - m_pool2->collect_statistics(st); - } - - void reset_statistics() { - m_pool0->reset_statistics(); - m_pool1->reset_statistics(); - m_pool2->reset_statistics(); - } }; /** Skolem constants for quantified spacer */ diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 7be4443e3..d8d7fec97 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -40,9 +40,10 @@ Revision History: namespace spacer { -prop_solver::prop_solver(spacer::manager& pm, +prop_solver::prop_solver(ast_manager &m, + solver *solver0, solver *solver1, fixedpoint_params const& p, symbol const& name) : - m(pm.get_manager()), + m(m), m_name(name), m_ctx(nullptr), m_pos_level_atoms(m), @@ -55,8 +56,8 @@ prop_solver::prop_solver(spacer::manager& pm, m_use_push_bg(p.spacer_keep_proxy()) { - m_solvers[0] = pm.mk_solver0(); - m_solvers[1] = pm.mk_solver1(); + m_solvers[0] = solver0; + m_solvers[1] = solver1; m_contexts[0] = alloc(spacer::iuc_solver, *(m_solvers[0]), p.spacer_iuc(), diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index 337f24825..ecc838d1a 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -29,19 +29,21 @@ Revision History: #include "smt/smt_kernel.h" #include "util/util.h" #include "util/vector.h" -#include "muz/spacer/spacer_manager.h" +#include "solver/solver.h" #include "muz/spacer/spacer_iuc_solver.h" +#include "muz/spacer/spacer_util.h" struct fixedpoint_params; namespace spacer { +typedef ptr_vector decl_vector; class prop_solver { private: ast_manager& m; symbol m_name; - solver* m_solvers[2]; + ref m_solvers[2]; scoped_ptr m_contexts[2]; iuc_solver * m_ctx; decl_vector m_level_preds; @@ -73,7 +75,7 @@ private: public: - prop_solver(spacer::manager &manager, + prop_solver(ast_manager &m, solver *solver0, solver* solver1, fixedpoint_params const& p, symbol const& name); @@ -142,7 +144,7 @@ public: solver *sol; scoped_weakness(prop_solver &ps, unsigned solver_id, unsigned weakness) : sol(nullptr) { - sol = ps.m_solvers[solver_id == 0 ? 0 : 0 /* 1 */]; + sol = ps.m_solvers[solver_id == 0 ? 0 : 0 /* 1 */].get(); if (!sol) return; sol->push_params(); From ada548b5ae6aef150dc22d5a55a8d9baa8eaa4fe Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 15:18:36 -0700 Subject: [PATCH 1109/1283] Removed unused options --- src/muz/base/fixedpoint_params.pyg | 2 -- src/muz/spacer/spacer_context.cpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 9d3ee864d..69050ed71 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -153,7 +153,6 @@ def_module_params('fixedpoint', ('spacer.eager_reach_check', BOOL, True, 'SPACER: eagerly check if a query is reachable using reachability facts of predecessors'), ('spacer.use_lemma_as_cti', BOOL, False, 'SPACER: use a lemma instead of a CTI in flexible_trace'), ('spacer.reset_obligation_queue', BOOL, True, 'SPACER: reset obligation queue when entering a new level'), - ('spacer.init_reach_facts', BOOL, True, 'SPACER: initialize reachability facts with false'), ('spacer.use_array_eq_generalizer', BOOL, True, 'SPACER: attempt to generalize lemmas with array equalities'), ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), ('xform.array_blast', BOOL, False, "try to eliminate local array terms using Ackermannization -- some array terms may remain"), @@ -161,7 +160,6 @@ def_module_params('fixedpoint', ('spacer.skip_propagate', BOOL, False, "Skip propagate/pushing phase. Turns PDR into a BMC that returns either reachable or unknown"), ('spacer.max_level', UINT, UINT_MAX, "Maximum level to explore"), ('spacer.elim_aux', BOOL, True, "Eliminate auxiliary variables in reachability facts"), - ('spacer.reach_as_init', BOOL, True, "Extend initial rules with computed reachability facts"), ('spacer.blast_term_ite', BOOL, True, "Expand non-Boolean ite-terms"), ('spacer.nondet_tie_break', BOOL, False, "Break ties in obligation queue non-deterministically"), ('spacer.reach_dnf', BOOL, True, "Restrict reachability facts to DNF"), diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index b27bd724e..2349ea03a 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1019,7 +1019,7 @@ void pred_transformer::add_reach_fact (reach_fact *fact) expr_ref fml (m); if (!m_reach_case_vars.empty()) {last_var = m_reach_case_vars.back();} - if (fact->is_init () || !ctx.get_params ().spacer_reach_as_init ()) + if (fact->is_init ()) {new_var = mk_fresh_reach_case_var();} else { new_var = extend_initial (fact->get ())->get_arg (0); @@ -1308,7 +1308,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, expr_ref a(m); pm.formula_n2o(pt.get_last_reach_case_var (), a, i); reach_assumps.push_back(m.mk_not (a)); - } else if (ctx.get_params().spacer_init_reach_facts()) { + } else { reach_assumps.push_back(m.mk_not (entry.m_key)); break; } From 7a8563a34cc8d0b500e7ac9c35ec5915d93acd6a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 17:06:01 -0700 Subject: [PATCH 1110/1283] spacer: cleaner management of rf tags --- src/muz/spacer/spacer_context.cpp | 124 ++++++++++++++---------------- src/muz/spacer/spacer_context.h | 24 +++--- 2 files changed, 70 insertions(+), 78 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 2349ea03a..5a6e1eec7 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -641,18 +641,24 @@ pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): m_pobs(*this), m_frames(*this), m_reach_facts(), m_rf_init_sz(0), - m_transition_clause(m), m_transition(m), m_init(m), m_extend_lit(m), - m_all_init(false), - m_reach_case_vars(m) + m_transition_clause(m), m_transition(m), m_init(m), + m_extend_lit0(m), m_extend_lit(m), + m_all_init(false) { m_solver = alloc(prop_solver, m, ctx.mk_solver0(), ctx.mk_solver1(), ctx.get_params(), head->get_name()); init_sig (); + + m_extend_lit = mk_extend_lit(); + m_extend_lit0 = m_extend_lit; +} + +app_ref pred_transformer::mk_extend_lit() { app_ref v(m); std::stringstream name; name << m_head->get_name () << "_ext0"; v = m.mk_const (symbol(name.str().c_str()), m.mk_bool_sort()); - m_extend_lit = m.mk_not (m.mk_const (pm.get_n_pred (v->get_decl ()))); + return app_ref(m.mk_not (m.mk_const (pm.get_n_pred (v->get_decl ()))), m); } pred_transformer::~pred_transformer() { @@ -743,7 +749,7 @@ bool pred_transformer::is_must_reachable(expr* state, model_ref* model) m_reach_solver->push (); m_reach_solver->assert_expr (state); - m_reach_solver->assert_expr (m.mk_not (m_reach_case_vars.back ())); + m_reach_solver->assert_expr (m.mk_not (m_reach_facts.back()->tag())); lbool res = m_reach_solver->check_sat (0, nullptr); if (model) { m_reach_solver->get_model(*model); } m_reach_solver->pop (1); @@ -754,39 +760,29 @@ bool pred_transformer::is_must_reachable(expr* state, model_ref* model) reach_fact* pred_transformer::get_used_reach_fact (model_evaluator_util& mev, - bool all) -{ + bool all) { expr_ref v (m); - for (unsigned i = all ? 0 : m_rf_init_sz, sz = m_reach_case_vars.size (); - i < sz; i++) { - VERIFY (mev.eval (m_reach_case_vars.get (i), v, false)); - if (m.is_false (v)) { - return m_reach_facts.get (i); - } + for (auto *rf : m_reach_facts) { + if (!all && rf->is_init()) continue; + VERIFY(mev.eval (rf->tag(), v, false)); + if (m.is_false(v)) return rf; } - - UNREACHABLE (); + UNREACHABLE(); return nullptr; } reach_fact *pred_transformer::get_used_origin_reach_fact (model_evaluator_util& mev, - unsigned oidx) -{ + unsigned oidx) { expr_ref b(m), v(m); - reach_fact *res = nullptr; - for (unsigned i = 0, sz = m_reach_case_vars.size (); i < sz; i++) { - pm.formula_n2o (m_reach_case_vars.get (i), v, oidx); + for (auto *rf : m_reach_facts) { + pm.formula_n2o (rf->tag(), v, oidx); VERIFY(mev.eval (v, b, false)); - - if (m.is_false (b)) { - res = m_reach_facts.get (i); - break; - } + if (m.is_false (b)) return rf; } - SASSERT (res); - return res; + UNREACHABLE(); + return nullptr; } const datalog::rule *pred_transformer::find_rule(model &model) { @@ -837,7 +833,7 @@ const datalog::rule *pred_transformer::find_rule(model &model, if (!pt.has_reach_facts()) {is_concrete = false;} else { expr_ref v(m); - pm.formula_n2o(pt.get_last_reach_case_var (), v, i); + pm.formula_n2o(pt.get_last_reach_tag (), v, i); model.eval(to_app (v.get ())->get_decl (), vl); used = m.is_false (vl); is_concrete = is_concrete && used; @@ -975,23 +971,18 @@ void pred_transformer::add_lemma_from_child (pred_transformer& child, } -expr* pred_transformer::mk_fresh_reach_case_var () +app_ref pred_transformer::mk_fresh_reach_tag () { std::stringstream name; func_decl_ref decl(m); - name << head ()->get_name () << "#reach_case_" << m_reach_case_vars.size (); + name << head ()->get_name () << "#reach_tag_" << m_reach_facts.size (); decl = m.mk_func_decl (symbol (name.str ().c_str ()), 0, (sort*const*)nullptr, m.mk_bool_sort ()); - m_reach_case_vars.push_back (m.mk_const (pm.get_n_pred (decl))); - return m_reach_case_vars.back (); + return app_ref(m.mk_const (pm.get_n_pred (decl)), m); } -expr* pred_transformer::get_reach_case_var (unsigned idx) const -{return m_reach_case_vars.get (idx);} - - -void pred_transformer::add_reach_fact (reach_fact *fact) +void pred_transformer::add_reach_fact (reach_fact *rf) { timeit _timer (is_trace_enabled("spacer_timeit"), "spacer::pred_transformer::add_reach_fact", @@ -999,46 +990,45 @@ void pred_transformer::add_reach_fact (reach_fact *fact) TRACE ("spacer", tout << "add_reach_fact: " << head()->get_name() << " " - << (fact->is_init () ? "INIT " : "") - << mk_pp(fact->get (), m) << "\n";); + << (rf->is_init () ? "INIT " : "") + << mk_pp(rf->get (), m) << "\n";); // -- avoid duplicates - if (fact == nullptr || get_reach_fact(fact->get())) {return;} + if (!rf || get_reach_fact(rf->get())) {return;} // all initial facts are grouped together - SASSERT (!fact->is_init () || m_reach_facts.empty () || + SASSERT (!rf->is_init () || m_reach_facts.empty () || m_reach_facts.back ()->is_init ()); - m_reach_facts.push_back (fact); - if (fact->is_init()) {m_rf_init_sz++;} + // create tags + app_ref last_tag(m); + app_ref new_tag(m); + expr_ref fml(m); + if (!m_reach_facts.empty()) {last_tag = m_reach_facts.back()->tag();} + if (rf->is_init ()) + new_tag = mk_fresh_reach_tag(); + else + // side-effect: updates m_solver with rf + new_tag = to_app(extend_initial(rf->get())->get_arg(0)); + rf->set_tag(new_tag); + + // add to m_reach_facts + m_reach_facts.push_back (rf); + if (rf->is_init()) {m_rf_init_sz++;} // update m_reach_solver - expr_ref last_var (m); - expr_ref new_var (m); - expr_ref fml (m); - - if (!m_reach_case_vars.empty()) {last_var = m_reach_case_vars.back();} - if (fact->is_init ()) - {new_var = mk_fresh_reach_case_var();} - else { - new_var = extend_initial (fact->get ())->get_arg (0); - m_reach_case_vars.push_back (new_var); - } - - SASSERT (m_reach_facts.size () == m_reach_case_vars.size ()); - - if (last_var) {fml = m.mk_or(m.mk_not(last_var), fact->get(), new_var);} - else {fml = m.mk_or(fact->get(), new_var);} - + if (last_tag) {fml = m.mk_or(m.mk_not(last_tag), rf->get(), rf->tag());} + else {fml = m.mk_or(rf->get(), rf->tag());} m_reach_solver->assert_expr (fml); - TRACE ("spacer", - tout << "updating reach ctx: " << mk_pp(fml, m) << "\n";); + TRACE ("spacer", tout << "updating reach ctx: " << fml << "\n";); - lemma lem(m, fml, infty_level()); + // update solvers of other pred_transformers + // XXX wrap rf into a lemma to fit the API + lemma fake_lemma(m, fml, infty_level()); // update users; reach facts are independent of levels for (auto use : m_use) - {use->add_lemma_from_child (*this, &lem, infty_level());} + use->add_lemma_from_child (*this, &fake_lemma, infty_level()); } expr_ref pred_transformer::get_reachable() @@ -1080,8 +1070,8 @@ expr_ref pred_transformer::get_reachable() return res; } -expr* pred_transformer::get_last_reach_case_var () const -{return m_reach_case_vars.empty () ? nullptr : m_reach_case_vars.back ();} +expr* pred_transformer::get_last_reach_tag () const +{return m_reach_facts.empty() ? nullptr : m_reach_facts.back()->tag();} expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) { @@ -1306,7 +1296,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, ctx.get_pred_transformer(m_predicates[i]); if (pt.has_reach_facts()) { expr_ref a(m); - pm.formula_n2o(pt.get_last_reach_case_var (), a, i); + pm.formula_n2o(pt.get_last_reach_tag(), a, i); reach_assumps.push_back(m.mk_not (a)); } else { reach_assumps.push_back(m.mk_not (entry.m_key)); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 55e8cbafe..154f8ea07 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -68,6 +68,9 @@ class reach_fact { const datalog::rule &m_rule; reach_fact_ref_vector m_justification; + // variable used to tag this reach fact in an incremental disjunction + app_ref m_tag; + bool m_init; public: @@ -75,10 +78,10 @@ public: expr* fact, const ptr_vector &aux_vars, bool init = false) : m_ref_count (0), m_fact (fact, m), m_aux_vars (aux_vars), - m_rule(rule), m_init (init) {} + m_rule(rule), m_tag(m), m_init (init) {} reach_fact (ast_manager &m, const datalog::rule &rule, expr* fact, bool init = false) : - m_ref_count (0), m_fact (fact, m), m_rule(rule), m_init (init) {} + m_ref_count (0), m_fact (fact, m), m_rule(rule), m_tag(m), m_init (init) {} bool is_init () {return m_init;} const datalog::rule& get_rule () {return m_rule;} @@ -89,6 +92,9 @@ public: expr *get () {return m_fact.get ();} const ptr_vector &aux_vars () {return m_aux_vars;} + app* tag() const {SASSERT(m_tag); return m_tag;} + void set_tag(app* tag) {m_tag = tag;} + void inc_ref () {++m_ref_count;} void dec_ref () { @@ -303,7 +309,8 @@ class pred_transformer { expr_ref_vector m_transition_clause; // extra clause for trans expr_ref m_transition; // transition relation expr_ref m_init; // initial condition - app_ref m_extend_lit; // literal to extend initial state + app_ref m_extend_lit0; // first literal used to extend initial state + app_ref m_extend_lit; // current literal to extend initial state bool m_all_init; // true if the pt has no uninterpreted body in any rule ptr_vector m_predicates; // temp vector used with find_predecessors() stats m_stats; @@ -312,13 +319,8 @@ class pred_transformer { stopwatch m_ctp_watch; stopwatch m_mbp_watch; - - /// Auxiliary variables to represent different disjunctive - /// cases of must summaries. Stored over 'n' (a.k.a. new) - /// versions of the variables - expr_ref_vector m_reach_case_vars; - void init_sig(); + app_ref mk_extend_lit(); void ensure_level(unsigned level); void add_lemma_core (lemma *lemma, bool ground_only = false); void add_lemma_from_child (pred_transformer &child, lemma *lemma, @@ -337,7 +339,7 @@ class pred_transformer { void add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r); - expr* mk_fresh_reach_case_var (); + app_ref mk_fresh_reach_tag (); public: pred_transformer(context& ctx, manager& pm, func_decl* head); @@ -406,7 +408,7 @@ public: const datalog::rule &r); void add_reach_fact (reach_fact *fact); // add reachability fact reach_fact* get_last_reach_fact () const { return m_reach_facts.back (); } - expr* get_last_reach_case_var () const; + expr* get_last_reach_tag () const; pob* mk_pob(pob *parent, unsigned level, unsigned depth, expr *post, app_ref_vector const &b){ From cfcc0846885abd832178c36a9d0cfe61e52f27b0 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 17:12:13 -0700 Subject: [PATCH 1111/1283] reach_fact --> rf --- src/muz/spacer/spacer_context.cpp | 58 +++++++++++++++---------------- src/muz/spacer/spacer_context.h | 20 +++++------ 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 5a6e1eec7..c621757f3 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -335,7 +335,7 @@ pob *derivation::create_next_child () mev.set_model (*model); // find must summary used - reach_fact *rf = pt.get_used_reach_fact (mev, true); + reach_fact *rf = pt.get_used_rf (mev, true); // get an implicant of the summary expr_ref_vector u(m), lits (m); @@ -759,7 +759,7 @@ bool pred_transformer::is_must_reachable(expr* state, model_ref* model) -reach_fact* pred_transformer::get_used_reach_fact (model_evaluator_util& mev, +reach_fact* pred_transformer::get_used_rf (model_evaluator_util& mev, bool all) { expr_ref v (m); @@ -772,7 +772,7 @@ reach_fact* pred_transformer::get_used_reach_fact (model_evaluator_util& mev, return nullptr; } -reach_fact *pred_transformer::get_used_origin_reach_fact (model_evaluator_util& mev, +reach_fact *pred_transformer::get_used_origin_rf (model_evaluator_util& mev, unsigned oidx) { expr_ref b(m), v(m); @@ -830,10 +830,10 @@ const datalog::rule *pred_transformer::find_rule(model &model, bool used = false; func_decl* d = r->get_tail(i)->get_decl(); const pred_transformer &pt = ctx.get_pred_transformer(d); - if (!pt.has_reach_facts()) {is_concrete = false;} + if (!pt.has_rfs()) {is_concrete = false;} else { expr_ref v(m); - pm.formula_n2o(pt.get_last_reach_tag (), v, i); + pm.formula_n2o(pt.get_last_rf_tag (), v, i); model.eval(to_app (v.get ())->get_decl (), vl); used = m.is_false (vl); is_concrete = is_concrete && used; @@ -971,7 +971,7 @@ void pred_transformer::add_lemma_from_child (pred_transformer& child, } -app_ref pred_transformer::mk_fresh_reach_tag () +app_ref pred_transformer::mk_fresh_rf_tag () { std::stringstream name; func_decl_ref decl(m); @@ -982,19 +982,19 @@ app_ref pred_transformer::mk_fresh_reach_tag () return app_ref(m.mk_const (pm.get_n_pred (decl)), m); } -void pred_transformer::add_reach_fact (reach_fact *rf) +void pred_transformer::add_rf (reach_fact *rf) { timeit _timer (is_trace_enabled("spacer_timeit"), - "spacer::pred_transformer::add_reach_fact", + "spacer::pred_transformer::add_rf", verbose_stream ()); TRACE ("spacer", - tout << "add_reach_fact: " << head()->get_name() << " " + tout << "add_rf: " << head()->get_name() << " " << (rf->is_init () ? "INIT " : "") << mk_pp(rf->get (), m) << "\n";); // -- avoid duplicates - if (!rf || get_reach_fact(rf->get())) {return;} + if (!rf || get_rf(rf->get())) {return;} // all initial facts are grouped together SASSERT (!rf->is_init () || m_reach_facts.empty () || @@ -1007,7 +1007,7 @@ void pred_transformer::add_reach_fact (reach_fact *rf) if (!m_reach_facts.empty()) {last_tag = m_reach_facts.back()->tag();} if (rf->is_init ()) - new_tag = mk_fresh_reach_tag(); + new_tag = mk_fresh_rf_tag(); else // side-effect: updates m_solver with rf new_tag = to_app(extend_initial(rf->get())->get_arg(0)); @@ -1070,7 +1070,7 @@ expr_ref pred_transformer::get_reachable() return res; } -expr* pred_transformer::get_last_reach_tag () const +expr* pred_transformer::get_last_rf_tag () const {return m_reach_facts.empty() ? nullptr : m_reach_facts.back()->tag();} expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) @@ -1134,7 +1134,7 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, // -- no auxiliary variables in lemmas *aux = nullptr; } else { // find must summary to use - reach_fact *f = get_used_origin_reach_fact (mev, oidx); + reach_fact *f = get_used_origin_rf (mev, oidx); summary.push_back (f->get ()); *aux = &f->aux_vars (); } @@ -1294,9 +1294,9 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, for (unsigned i = 0; i < m_predicates.size(); i++) { const pred_transformer &pt = ctx.get_pred_transformer(m_predicates[i]); - if (pt.has_reach_facts()) { + if (pt.has_rfs()) { expr_ref a(m); - pm.formula_n2o(pt.get_last_reach_tag(), a, i); + pm.formula_n2o(pt.get_last_rf_tag(), a, i); reach_assumps.push_back(m.mk_not (a)); } else { reach_assumps.push_back(m.mk_not (entry.m_key)); @@ -1521,7 +1521,7 @@ void pred_transformer::initialize(decl2rel const& pts) } -void pred_transformer::init_reach_facts () +void pred_transformer::init_rfs () { expr_ref_vector v(m); reach_fact_ref fact; @@ -1531,7 +1531,7 @@ void pred_transformer::init_reach_facts () if (r->get_uninterpreted_tail_size() == 0) { fact = alloc (reach_fact, m, *r, m_rule2transition.find(r), get_aux_vars(*r), true); - add_reach_fact(fact.get ()); + add_rf(fact.get ()); } } } @@ -2164,7 +2164,7 @@ void context::init_rules(datalog::rule_set& rules, decl2rel& rels) } // initialize reach facts - for (auto &entry : rels) {entry.m_value->init_reach_facts();} + for (auto &entry : rels) {entry.m_value->init_rfs();} } void context::inherit_lemmas(const decl2rel &rels) { @@ -2505,7 +2505,7 @@ unsigned context::get_cex_depth() pred_transformer* pt; // get and discard query rule - fact = m_query->get_last_reach_fact (); + fact = m_query->get_last_rf (); r = &fact->get_rule (); unsigned cex_depth = 0; @@ -2580,7 +2580,7 @@ void context::get_rules_along_trace(datalog::rule_ref_vector& rules) pred_transformer* pt; // get query rule - fact = m_query->get_last_reach_fact (); + fact = m_query->get_last_rf (); r = &fact->get_rule (); rules.push_back (const_cast (r)); TRACE ("spacer", @@ -2687,7 +2687,7 @@ expr_ref context::get_ground_sat_answer() datalog::rule const* r; // get and discard query rule - reach_fact = m_query->get_last_reach_fact (); + reach_fact = m_query->get_last_rf (); r = &reach_fact->get_rule (); // initialize queues @@ -3028,8 +3028,8 @@ bool context::is_reachable(pob &n) mev.set_model(*model); // -- update must summary if (r && r->get_uninterpreted_tail_size () > 0) { - reach_fact_ref rf = n.pt().mk_reach_fact (n, mev, *r); - n.pt ().add_reach_fact (rf.get ()); + reach_fact_ref rf = n.pt().mk_rf (n, mev, *r); + n.pt ().add_rf (rf.get ()); } // if n has a derivation, create a new child and report l_undef @@ -3168,9 +3168,9 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) if (is_concrete) { // -- update must summary if (r && r->get_uninterpreted_tail_size() > 0) { - reach_fact_ref rf = n.pt().mk_reach_fact (n, mev, *r); + reach_fact_ref rf = n.pt().mk_rf (n, mev, *r); checkpoint (); - n.pt ().add_reach_fact (rf.get ()); + n.pt ().add_rf (rf.get ()); checkpoint (); } @@ -3383,12 +3383,12 @@ bool context::propagate(unsigned min_prop_lvl, return false; } -reach_fact *pred_transformer::mk_reach_fact (pob& n, model_evaluator_util &mev, +reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, const datalog::rule& r) { SASSERT(&n.pt() == this); timeit _timer1 (is_trace_enabled("spacer_timeit"), - "mk_reach_fact", + "mk_rf", verbose_stream ()); expr_ref res(m); reach_fact_ref_vector child_reach_facts; @@ -3405,7 +3405,7 @@ reach_fact *pred_transformer::mk_reach_fact (pob& n, model_evaluator_util &mev, pred_transformer& ch_pt = ctx.get_pred_transformer (pred); // get a reach fact of body preds used in the model expr_ref o_ch_reach (m); - reach_fact *kid = ch_pt.get_used_origin_reach_fact (mev, i); + reach_fact *kid = ch_pt.get_used_origin_rf (mev, i); child_reach_facts.push_back (kid); pm.formula_n2o (kid->get (), o_ch_reach, i); path_cons.push_back (o_ch_reach); @@ -3444,7 +3444,7 @@ reach_fact *pred_transformer::mk_reach_fact (pob& n, model_evaluator_util &mev, { timeit _timer1 (is_trace_enabled("spacer_timeit"), - "mk_reach_fact::qe_project", + "mk_rf::qe_project", verbose_stream ()); mbp(vars, res, mev.get_model(), false /*, false */); } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 154f8ea07..924c5f9cc 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -339,14 +339,14 @@ class pred_transformer { void add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r); - app_ref mk_fresh_reach_tag (); + app_ref mk_fresh_rf_tag (); public: pred_transformer(context& ctx, manager& pm, func_decl* head); ~pred_transformer(); inline bool use_native_mbp (); - reach_fact *get_reach_fact (expr *v) { + reach_fact *get_rf (expr *v) { for (auto *rf : m_reach_facts) { if (v == rf->get()) {return rf;} } @@ -379,9 +379,9 @@ public: bool is_must_reachable(expr* state, model_ref* model = nullptr); /// \brief Returns reachability fact active in the given model /// all determines whether initial reachability facts are included as well - reach_fact *get_used_reach_fact(model_evaluator_util& mev, bool all = true); + reach_fact *get_used_rf(model_evaluator_util& mev, bool all = true); /// \brief Returns reachability fact active in the origin of the given model - reach_fact* get_used_origin_reach_fact(model_evaluator_util &mev, unsigned oidx); + reach_fact* get_used_origin_rf(model_evaluator_util &mev, unsigned oidx); expr_ref get_origin_summary(model_evaluator_util &mev, unsigned level, unsigned oidx, bool must, const ptr_vector **aux); @@ -400,15 +400,15 @@ public: bool add_lemma(expr * lemma, unsigned lvl); bool add_lemma(lemma* lem) {return m_frames.add_lemma(lem);} expr* get_reach_case_var (unsigned idx) const; - bool has_reach_facts () const { return !m_reach_facts.empty () ;} + bool has_rfs () const { return !m_reach_facts.empty () ;} /// initialize reachability facts using initial rules - void init_reach_facts (); - reach_fact *mk_reach_fact(pob &n, model_evaluator_util &mev, + void init_rfs (); + reach_fact *mk_rf(pob &n, model_evaluator_util &mev, const datalog::rule &r); - void add_reach_fact (reach_fact *fact); // add reachability fact - reach_fact* get_last_reach_fact () const { return m_reach_facts.back (); } - expr* get_last_reach_tag () const; + void add_rf (reach_fact *fact); // add reachability fact + reach_fact* get_last_rf () const { return m_reach_facts.back (); } + expr* get_last_rf_tag () const; pob* mk_pob(pob *parent, unsigned level, unsigned depth, expr *post, app_ref_vector const &b){ From 70f4674b3a6788acb5baf17a972b0888100f6617 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 18:25:18 -0700 Subject: [PATCH 1112/1283] Code to update solver with all constraints of a pred_transformer --- src/muz/spacer/spacer_context.cpp | 79 ++++++++++++++++++++++++++++++- src/muz/spacer/spacer_context.h | 27 +++++++---- 2 files changed, 96 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index c621757f3..55f5fa2a6 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -864,7 +864,7 @@ void pred_transformer::simplify_formulas() {m_frames.simplify_formulas ();} -expr_ref pred_transformer::get_formulas(unsigned level) +expr_ref pred_transformer::get_formulas(unsigned level) const { expr_ref_vector res(m); m_frames.get_frame_geq_lemmas (level, res); @@ -1791,6 +1791,83 @@ app* pred_transformer::extend_initial (expr *e) } +/// \brief Update a given solver with all constraints representing +/// this pred_transformer +void pred_transformer::updt_solver(prop_solver *solver) { + + m_solver->assert_expr(m_transition); + m_solver->assert_expr(m_init, 0); + + // -- facts derivable at the head + expr_ref last_tag(m); + last_tag = m_extend_lit0; + for (auto *rf : m_reach_facts) { + if (rf->is_init()) continue; + m_solver->assert_expr(m.mk_or(last_tag, rf->get(), rf->tag())); + last_tag = m.mk_not(rf->tag()); + } + + + for (auto &entry : m_tag2rule) { + const datalog::rule *r = entry.m_value; + if (!r) continue; + find_predecessors(*r, m_predicates); + if (m_predicates.empty()) continue; + + for (unsigned i = 0, sz = m_predicates.size(); i < sz; ++i) { + const pred_transformer &pt = ctx.get_pred_transformer(m_predicates[i]); + // assert lemmas of pt + updt_solver_with_lemmas(solver, pt, to_app(entry.m_key), i); + // assert rfs of pt + update_solver_with_rfs(solver, pt, to_app(entry.m_key), i); + } + } +} + +void pred_transformer::updt_solver_with_lemmas(prop_solver *solver, + const pred_transformer &pt, + app* rule_tag, unsigned pos) { + expr_ref not_rule_tag(m); + not_rule_tag = m.mk_not(rule_tag); + + // XXX deal with quantified instantiations + // XXX perhaps expose lemmas, which gives better idea of what is active + expr_ref_vector fmls(m); + for (unsigned i = 0, sz = pt.get_num_levels(); i <= sz; ++i) { + expr_ref tmp(m); + if (i == sz) i = infty_level(); + tmp = pt.get_formulas(i); + flatten_and(tmp, fmls); + + for (expr *f : fmls) { + tmp = m.mk_or(not_rule_tag, f); + pm.formula_n2o(tmp, tmp, pos, !is_quantifier(f)); + m_solver->assert_expr(tmp, i); + } + } +} + +void pred_transformer::update_solver_with_rfs(prop_solver *solver, + const pred_transformer &pt, + app *rule_tag, unsigned pos) { + expr_ref last_tag(m); + expr_ref not_rule_tag(m); + not_rule_tag = m.mk_not(rule_tag); + + for (auto *rf : pt.m_reach_facts) { + expr_ref e(m); + if (last_tag) { + expr *args[4] = { m.mk_not(rule_tag), last_tag, rf->get(), rf->tag() }; + e = m.mk_or(4, args); + } + else + e = m.mk_or(m.mk_not(rule_tag), rf->get(), rf->tag()); + last_tag = m.mk_not(rf->tag()); + pm.formula_n2o(e.get(), e, pos); + solver->assert_expr(e); + } +} + /// pred_transformer::frames diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 924c5f9cc..d95f1185d 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -226,14 +226,14 @@ class pred_transformer { pred_transformer& pt () {return m_pt;} - void get_frame_lemmas (unsigned level, expr_ref_vector &out) { + void get_frame_lemmas (unsigned level, expr_ref_vector &out) const { for (auto &lemma : m_lemmas) { if (lemma->level() == level) { out.push_back(lemma->get_expr()); } } } - void get_frame_geq_lemmas (unsigned level, expr_ref_vector &out) { + void get_frame_geq_lemmas (unsigned level, expr_ref_vector &out) const { for (auto &lemma : m_lemmas) { if(lemma->level() >= level) { out.push_back(lemma->get_expr()); @@ -366,7 +366,7 @@ public: expr* transition() const {return m_transition;} expr* init() const {return m_init;} expr* rule2tag(datalog::rule const* r) {return m_rule2tag.find(r);} - unsigned get_num_levels() {return m_frames.size ();} + unsigned get_num_levels() const {return m_frames.size ();} expr_ref get_cover_delta(func_decl* p_orig, int level); void add_cover(unsigned level, expr* property); expr_ref get_reachable(); @@ -438,7 +438,7 @@ public: bool check_inductive(unsigned level, expr_ref_vector& state, unsigned& assumes_level, unsigned weakness = UINT_MAX); - expr_ref get_formulas(unsigned level); + expr_ref get_formulas(unsigned level) const; void simplify_formulas(); @@ -465,6 +465,15 @@ public: void mbp(app_ref_vector &vars, expr_ref &fml, const model_ref &mdl, bool reduce_all_selects = true); + void updt_solver(prop_solver *solver); + + void updt_solver_with_lemmas(prop_solver *solver, + const pred_transformer &pt, + app *rule_tag, unsigned pos); + void update_solver_with_rfs(prop_solver *solver, + const pred_transformer &pt, + app *rule_tag, unsigned pos); + }; @@ -566,8 +575,8 @@ public: const ptr_vector &lemmas() {return m_lemmas;} void add_lemma(lemma* new_lemma) {m_lemmas.push_back(new_lemma);} - bool is_ground () { return m_binding.empty (); } - unsigned get_free_vars_size() { return m_binding.size(); } + bool is_ground () const { return m_binding.empty (); } + unsigned get_free_vars_size() const { return m_binding.size(); } app_ref_vector const &get_binding() const {return m_binding;} /* * Returns a map from variable id to skolems that implicitly @@ -718,9 +727,9 @@ public: void set_root(pob& n); bool is_root (pob& n) const {return m_root.get () == &n;} - unsigned max_level() {return m_max_level;} - unsigned min_depth() {return m_min_depth;} - size_t size() {return m_obligations.size();} + unsigned max_level() const {return m_max_level;} + unsigned min_depth() const {return m_min_depth;} + size_t size() const {return m_obligations.size();} }; From 862eef5ec0dd3c3869564c1dbab06389c360ce6a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 18:33:20 -0700 Subject: [PATCH 1113/1283] Eliminate all existential variables from reach facts --- src/muz/spacer/spacer_context.cpp | 20 +++++++++++--------- src/muz/spacer/spacer_context.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 55f5fa2a6..a70c860f1 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -244,7 +244,8 @@ pob *derivation::create_next_child (model_evaluator_util &mev) timeit _timer1 (is_trace_enabled("spacer_timeit"), "create_next_child::qproject1", verbose_stream ()); - pt().mbp(vars, m_trans, mev.get_model()); + pt().mbp(vars, m_trans, mev.get_model(), + true, pt().get_context().use_ground_cti()); //qe::reduce_array_selects (*mev.get_model (), m_trans); // remember variables that need to be existentially quantified m_evars.append (vars); @@ -272,7 +273,8 @@ pob *derivation::create_next_child (model_evaluator_util &mev) timeit _timer2 (is_trace_enabled("spacer_timeit"), "create_next_child::qproject2", verbose_stream ()); - pt().mbp(vars, post, mev.get_model()); + pt().mbp(vars, post, mev.get_model(), + true, pt().get_context().use_ground_cti()); //qe::reduce_array_selects (*mev.get_model (), post); // remember variables that need to be existentially quantified @@ -370,7 +372,8 @@ pob *derivation::create_next_child () { vars.push_back(m.mk_const(pm.o2n(pt.sig(i), 0))); } if (!vars.empty ()) { - this->pt().mbp(vars, m_trans, mev.get_model()); + this->pt().mbp(vars, m_trans, mev.get_model(), + true, this->pt().get_context().use_ground_cti()); // keep track of implicitly quantified variables m_evars.append (vars); } @@ -1244,11 +1247,10 @@ bool pred_transformer::is_qblocked (pob &n) { } -void pred_transformer::mbp(app_ref_vector &vars, expr_ref &fml, - const model_ref &mdl, bool reduce_all_selects) { +void pred_transformer::mbp(app_ref_vector &vars, expr_ref &fml, const model_ref &mdl, + bool reduce_all_selects, bool force) { scoped_watch _t_(m_mbp_watch); - qe_project(m, vars, fml, mdl, reduce_all_selects, - use_native_mbp(), !ctx.use_ground_cti()); + qe_project(m, vars, fml, mdl, reduce_all_selects, use_native_mbp(), !force); } // @@ -3523,7 +3525,7 @@ reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, timeit _timer1 (is_trace_enabled("spacer_timeit"), "mk_rf::qe_project", verbose_stream ()); - mbp(vars, res, mev.get_model(), false /*, false */); + mbp(vars, res, mev.get_model(), false, true /* force or skolemize */); } @@ -3601,7 +3603,7 @@ bool context::create_children(pob& n, datalog::rule const& r, n.get_skolems(vars); expr_ref phi1 = mk_and (Phi); - n.pt().mbp(vars, phi1, mev.get_model ()); + n.pt().mbp(vars, phi1, mev.get_model (), true, use_ground_cti()); //qe::reduce_array_selects (*mev.get_model (), phi1); SASSERT (!m_ground_cti || vars.empty ()); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index d95f1185d..d546c3948 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -463,7 +463,7 @@ public: /// \brief interface to Model Based Projection void mbp(app_ref_vector &vars, expr_ref &fml, const model_ref &mdl, - bool reduce_all_selects = true); + bool reduce_all_selects, bool force = false); void updt_solver(prop_solver *solver); From 502e323678b27e0a00101837243f8eb00447580a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 31 May 2018 20:30:35 -0700 Subject: [PATCH 1114/1283] Fixes to pred_tranformer::updt_solver --- src/muz/spacer/spacer_context.cpp | 93 ++++++++++++++++++++------- src/muz/spacer/spacer_context.h | 3 +- src/muz/spacer/spacer_prop_solver.cpp | 2 + src/muz/spacer/spacer_prop_solver.h | 7 ++ 4 files changed, 79 insertions(+), 26 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index a70c860f1..bbedbc391 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1483,8 +1483,6 @@ void pred_transformer::mk_assumptions(func_decl* head, expr* fml, expr_ref_vector& result) { expr_ref tmp1(m), tmp2(m); - expr_substitution sub (m); - proof_ref pr (m.mk_asserted (m.mk_true ()), m); obj_map::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); for (; it != end; ++it) { @@ -1797,19 +1795,49 @@ app* pred_transformer::extend_initial (expr *e) /// this pred_transformer void pred_transformer::updt_solver(prop_solver *solver) { - m_solver->assert_expr(m_transition); - m_solver->assert_expr(m_init, 0); + solver->assert_expr(m_transition); + solver->assert_expr(m_init, 0); // -- facts derivable at the head expr_ref last_tag(m); last_tag = m_extend_lit0; for (auto *rf : m_reach_facts) { - if (rf->is_init()) continue; - m_solver->assert_expr(m.mk_or(last_tag, rf->get(), rf->tag())); + if (rf->is_init()) continue; // already in m_init + solver->assert_expr(m.mk_or(last_tag, rf->get(), rf->tag())); last_tag = m.mk_not(rf->tag()); } + SASSERT(last_tag == m_extend_lit); + // -- lemmas + app_ref_vector _unused(m); + expr_ref_vector fmls(m); + // -- assert lemmas + for (auto *u : m_frames.lemmas()) { + // instances + u->mk_insts(fmls); + // extra ground instance + if (!u->is_ground()) { + expr_ref gnd(m); + ground_expr(u->get_expr(), gnd, _unused); + fmls.push_back(gnd); + } + + // (quantified) lemma + if (u->is_ground() || get_context().use_qlemmas()) + fmls.push_back(u->get_expr()); + + // send to solver + if (is_infty_level(u->level())) + solver->assert_exprs(fmls); + else { + for (unsigned i = 0; i <= u->level(); ++i) + solver->assert_exprs(fmls, i); + } + fmls.reset(); + } + + // -- lemmas and rfs from other predicates for (auto &entry : m_tag2rule) { const datalog::rule *r = entry.m_value; if (!r) continue; @@ -1829,41 +1857,56 @@ void pred_transformer::updt_solver(prop_solver *solver) { void pred_transformer::updt_solver_with_lemmas(prop_solver *solver, const pred_transformer &pt, app* rule_tag, unsigned pos) { - expr_ref not_rule_tag(m); - not_rule_tag = m.mk_not(rule_tag); - - // XXX deal with quantified instantiations - // XXX perhaps expose lemmas, which gives better idea of what is active + app_ref_vector _unused(m); expr_ref_vector fmls(m); - for (unsigned i = 0, sz = pt.get_num_levels(); i <= sz; ++i) { - expr_ref tmp(m); - if (i == sz) i = infty_level(); - tmp = pt.get_formulas(i); - flatten_and(tmp, fmls); + for (auto *u : pt.m_frames.lemmas()) { + expr_ref e(m), gnd(m); + e = u->get_expr(); + pm.formula_n2o(e, e, pos); + u->mk_insts(fmls, e); - for (expr *f : fmls) { - tmp = m.mk_or(not_rule_tag, f); - pm.formula_n2o(tmp, tmp, pos, !is_quantifier(f)); - m_solver->assert_expr(tmp, i); + if (!u->is_ground()) { + // special ground instance + ground_expr(u->get_expr(), gnd, _unused); + pm.formula_n2o(gnd, gnd, pos); + fmls.push_back(gnd); } + + // quantified formula + if (u->is_ground() || get_context().use_qlemmas()) + fmls.push_back(e); + + // add tag + for (unsigned i = 0, sz = fmls.size(); i < sz; ++i) + fmls.set(i, m.mk_implies(rule_tag, fmls.get(i))); + + // send to solver + if (is_infty_level(u->level())) + solver->assert_exprs(fmls); + else { + for (unsigned i = 1, end = next_level(u->level()); i <= end; ++i) + solver->assert_exprs(fmls, i); + } + fmls.reset(); } } void pred_transformer::update_solver_with_rfs(prop_solver *solver, const pred_transformer &pt, app *rule_tag, unsigned pos) { - expr_ref last_tag(m); expr_ref not_rule_tag(m); not_rule_tag = m.mk_not(rule_tag); + expr_ref last_tag(m); for (auto *rf : pt.m_reach_facts) { expr_ref e(m); - if (last_tag) { - expr *args[4] = { m.mk_not(rule_tag), last_tag, rf->get(), rf->tag() }; + if (!last_tag) { + e = m.mk_or(m.mk_not(rule_tag), rf->get(), rf->tag()); + } + else { + expr *args[4] = { not_rule_tag, last_tag, rf->get(), rf->tag() }; e = m.mk_or(4, args); } - else - e = m.mk_or(m.mk_not(rule_tag), rf->get(), rf->tag()); last_tag = m.mk_not(rf->tag()); pm.formula_n2o(e.get(), e, pos); solver->assert_expr(e); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index d546c3948..120953e97 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -223,7 +223,8 @@ class pred_transformer { ~frames() {} void simplify_formulas (); - pred_transformer& pt () {return m_pt;} + pred_transformer& pt() const {return m_pt;} + const lemma_ref_vector &lemmas() const {return m_lemmas;} void get_frame_lemmas (unsigned level, expr_ref_vector &out) const { diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index d8d7fec97..1f33e2f12 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -125,6 +125,8 @@ void prop_solver::assert_expr(expr * form) void prop_solver::assert_expr(expr * form, unsigned level) { + if (is_infty_level(level)) {assert_expr(form);return;} + ensure_level(level); app * lev_atom = m_pos_level_atoms[level].get(); app_ref lform(m.mk_or(form, lev_atom), m); diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index ecc838d1a..c87277e16 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -93,6 +93,13 @@ public: void assert_expr(expr * form); void assert_expr(expr * form, unsigned level); + void assert_exprs(const expr_ref_vector &fmls) { + for (auto *f : fmls) assert_expr(f); + } + void assert_exprs(const expr_ref_vector &fmls, unsigned level) { + for (auto *f : fmls) assert_expr(f, level); + } + /** * check assumptions with a background formula */ From bfeb15b87689ede173d69fea5df3429cecb9bdf1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Jun 2018 08:09:33 -0700 Subject: [PATCH 1115/1283] move to list of clauses Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_iuc_solver.cpp | 6 +- src/muz/spacer/spacer_iuc_solver.h | 2 +- src/muz/spacer/spacer_prop_solver.cpp | 18 +++--- src/muz/spacer/spacer_prop_solver.h | 4 +- src/smt/smt_context.cpp | 91 +++++++++++++++------------ src/smt/smt_context.h | 8 ++- src/smt/smt_kernel.cpp | 6 +- src/smt/smt_kernel.h | 2 +- src/smt/smt_solver.cpp | 4 +- src/solver/solver.h | 4 +- src/solver/solver_na2as.cpp | 6 +- src/solver/solver_na2as.h | 4 +- src/solver/solver_pool.cpp | 16 ++--- src/test/cube_clause.cpp | 16 +++-- 14 files changed, 104 insertions(+), 83 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index d9caefb33..35932b2ba 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -128,8 +128,8 @@ lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions } lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, - const expr_ref_vector &clause) { - if (clause.empty()) {return check_sat(cube.size(), cube.c_ptr());} + vector const & clauses) { + if (clauses.empty()) {return check_sat(cube.size(), cube.c_ptr());} // -- remove any old assumptions if (m_assumptions.size() > m_first_assumption) @@ -144,7 +144,7 @@ lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, m_is_proxied = mk_proxies(m_assumptions, m_first_assumption); lbool res; - res = m_solver.check_sat_cc(m_assumptions, clause); + res = m_solver.check_sat_cc(m_assumptions, clauses); set_status (res); return res; } diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index c3b16b2dd..dcee54612 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -126,7 +126,7 @@ public: {return m_solver.get_scope_level();} lbool check_sat(unsigned num_assumptions, expr * const *assumptions) override; - lbool check_sat_cc(const expr_ref_vector &cube, const expr_ref_vector &clause) override; + lbool check_sat_cc(const expr_ref_vector &cube, vector const & clauses) override; void set_progress_callback(progress_callback *callback) override {m_solver.set_progress_callback(callback);} unsigned get_num_assertions() const override diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 1f33e2f12..4613cd089 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -202,7 +202,7 @@ lbool prop_solver::mss(expr_ref_vector &hard, expr_ref_vector &soft) { res = m_ctx->check_sat(j+1, hard.c_ptr()); if (res == l_false) { // -- flip non-true literal to be false - hard[j] = m.mk_not(hard.get(j)); + hard[j] = mk_not(m, hard.get(j)); } else if (res == l_true) { // -- get the model for the next iteration of the outer loop @@ -218,7 +218,7 @@ lbool prop_solver::mss(expr_ref_vector &hard, expr_ref_vector &soft) { } // move sat soft constraints to the output vector - for (unsigned k = i; k < j; ++k) {soft.push_back(hard.get(k));} + for (unsigned k = i; k < j; ++k) { soft.push_back(hard.get(k)); } // cleanup hard constraints hard.resize(hard_sz); return l_true; @@ -228,7 +228,7 @@ lbool prop_solver::mss(expr_ref_vector &hard, expr_ref_vector &soft) { /// Runs maxsat loop on m_ctx Returns l_false if hard is unsat, /// otherwise reduces soft such that hard & soft is sat. lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft, - const expr_ref_vector &clause) + vector const & clauses) { // replace expressions by assumption literals iuc_solver::scoped_mk_proxy _p_(*m_ctx, hard); @@ -236,7 +236,7 @@ lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft, // assume soft constraints are propositional literals (no need to proxy) hard.append(soft); - lbool res = m_ctx->check_sat_cc(hard, clause); + lbool res = m_ctx->check_sat_cc(hard, clauses); // if hard constraints alone are unsat or there are no soft // constraints, we are done if (res != l_false || soft.empty()) { return res; } @@ -270,7 +270,7 @@ lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft, } // check that the NEW constraints became sat - res = m_ctx->check_sat_cc(hard, clause); + res = m_ctx->check_sat_cc(hard, clauses); if (res != l_false) { break; } // still unsat, update the core and repeat core.reset(); @@ -290,7 +290,7 @@ lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft, lbool prop_solver::internal_check_assumptions(expr_ref_vector &hard_atoms, expr_ref_vector &soft_atoms, - const expr_ref_vector &clause) + vector const & clauses) { // XXX Turn model generation if m_model != 0 SASSERT(m_ctx); @@ -302,7 +302,7 @@ lbool prop_solver::internal_check_assumptions(expr_ref_vector &hard_atoms, } if (m_in_level) { assert_level_atoms(m_current_level); } - lbool result = maxsmt(hard_atoms, soft_atoms, clause); + lbool result = maxsmt(hard_atoms, soft_atoms, clauses); if (result != l_false && m_model) { m_ctx->get_model(*m_model); } SASSERT(result != l_false || soft_atoms.empty()); @@ -375,7 +375,9 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, unsigned soft_sz = soft.size(); (void) soft_sz; - lbool res = internal_check_assumptions(hard, soft, clause); + vector clauses; + clauses.push_back(clause); + lbool res = internal_check_assumptions(hard, soft, clauses); if (!m_use_push_bg) { m_ctx->pop(1); } TRACE("psolve_verbose", diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index c87277e16..042215eff 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -67,10 +67,10 @@ private: lbool internal_check_assumptions(expr_ref_vector &hard, expr_ref_vector &soft, - const expr_ref_vector &clause); + vector const & clause); lbool maxsmt(expr_ref_vector &hard, expr_ref_vector &soft, - const expr_ref_vector &clause); + vector const & clauses); lbool mss(expr_ref_vector &hard, expr_ref_vector &soft); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index c6f77cf1f..0680d7bcf 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -61,7 +61,6 @@ namespace smt { m_dyn_ack_manager(*this, p), m_is_diseq_tmp(nullptr), m_units_to_reassert(m_manager), - m_clause(nullptr), m_qhead(0), m_simp_qhead(0), m_simp_counter(0), @@ -1815,7 +1814,7 @@ namespace smt { */ bool context::decide() { - if (at_search_level() && !m_clause_lits.empty()) { + if (at_search_level() && !m_tmp_clauses.empty()) { switch (decide_clause()) { case l_true: // already satisfied break; @@ -2919,8 +2918,7 @@ namespace smt { del_clauses(m_aux_clauses, 0); del_clauses(m_lemmas, 0); del_justifications(m_justifications, 0); - if (m_clause) del_clause(m_clause); - m_clause = nullptr; + reset_tmp_clauses(); if (m_is_diseq_tmp) { m_is_diseq_tmp->del_eh(m_manager, false); m_manager.dec_ref(m_is_diseq_tmp->get_owner()); @@ -3135,48 +3133,62 @@ namespace smt { return true; } - void context::init_clause(expr_ref_vector const& clause) { - if (m_clause) del_clause(m_clause); - m_clause = nullptr; - m_clause_lits.reset(); - for (expr* lit : clause) { + void context::init_clause(expr_ref_vector const& _clause) { + literal_vector lits; + for (expr* lit : _clause) { internalize_formula(lit, true); mark_as_relevant(lit); - m_clause_lits.push_back(get_literal(lit)); + lits.push_back(get_literal(lit)); } - if (m_clause_lits.size() >= 2) { + clause* clausep = nullptr; + if (lits.size() >= 2) { justification* js = nullptr; if (m_manager.proofs_enabled()) { - proof * pr = mk_clause_def_axiom(m_clause_lits.size(), m_clause_lits.c_ptr(), nullptr); + proof * pr = mk_clause_def_axiom(lits.size(), lits.c_ptr(), nullptr); js = mk_justification(justification_proof_wrapper(*this, pr)); } - m_clause = clause::mk(m_manager, m_clause_lits.size(), m_clause_lits.c_ptr(), CLS_AUX, js); + clausep = clause::mk(m_manager, lits.size(), lits.c_ptr(), CLS_AUX, js); } + m_tmp_clauses.push_back(std::make_pair(clausep, lits)); + } + + void context::reset_tmp_clauses() { + for (auto& p : m_tmp_clauses) { + if (p.first) del_clause(p.first); + } + m_tmp_clauses.reset(); } lbool context::decide_clause() { - if (m_clause_lits.empty()) return l_true; - shuffle(m_clause_lits.size(), m_clause_lits.c_ptr(), m_random); - for (literal l : m_clause_lits) { - switch (get_assignment(l)) { - case l_false: - break; - case l_true: - return l_true; - default: - push_scope(); - assign(l, b_justification::mk_axiom(), true); - return l_undef; - } + if (m_tmp_clauses.empty()) return l_true; + for (auto & tmp_clause : m_tmp_clauses) { + literal_vector& lits = tmp_clause.second; + for (literal l : lits) { + switch (get_assignment(l)) { + case l_false: + break; + 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; + } + } + + if (lits.size() == 1) { + set_conflict(b_justification(), ~lits[0]); + } + else { + set_conflict(b_justification(tmp_clause.first), null_literal); + } + VERIFY(!resolve_conflict()); + return l_false; + next_clause: + ; } - if (m_clause_lits.size() == 1) { - set_conflict(b_justification(), ~m_clause_lits[0]); - } - else { - set_conflict(b_justification(m_clause), null_literal); - } - VERIFY(!resolve_conflict()); - return l_false; + return l_true; } void context::init_assumptions(expr_ref_vector const& asms) { @@ -3277,10 +3289,7 @@ namespace smt { m_last_search_failure = MEMOUT; return false; } - - if (m_clause) del_clause(m_clause); - m_clause = nullptr; - m_clause_lits.reset(); + reset_tmp_clauses(); m_unsat_core.reset(); m_stats.m_num_checks++; pop_to_base_lvl(); @@ -3387,17 +3396,17 @@ namespace smt { return r; } - lbool context::check(expr_ref_vector const& cube, expr_ref_vector const& clause) { + lbool context::check(expr_ref_vector const& cube, vector const& clauses) { if (!check_preamble(true)) return l_undef; TRACE("before_search", display(tout);); setup_context(false); expr_ref_vector asms(cube); add_theory_assumptions(asms); if (!validate_assumptions(asms)) return l_undef; - if (!validate_assumptions(clause)) return l_undef; + for (auto const& clause : clauses) if (!validate_assumptions(clause)) return l_undef; internalize_assertions(); init_assumptions(asms); - init_clause(clause); + for (auto const& clause : clauses) init_clause(clause); lbool r = search(); r = mk_unsat_core(r); r = check_finalize(r); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 3110ea3c1..16c1c7ac3 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -168,8 +168,8 @@ namespace smt { expr_ref_vector m_units_to_reassert; svector m_units_to_reassert_sign; literal_vector m_assigned_literals; - clause* m_clause; - literal_vector m_clause_lits; + typedef std::pair tmp_clause; + vector m_tmp_clauses; unsigned m_qhead; unsigned m_simp_qhead; int m_simp_counter; //!< can become negative @@ -1114,6 +1114,8 @@ namespace smt { lbool decide_clause(); + void reset_tmp_clauses(); + void reset_assumptions(); void reset_clause(); @@ -1505,7 +1507,7 @@ namespace smt { lbool check(unsigned num_assumptions = 0, expr * const * assumptions = nullptr, bool reset_cancel = true, bool already_did_theory_assumptions = false); - lbool check(expr_ref_vector const& cube, expr_ref_vector const& clause); + lbool check(expr_ref_vector const& cube, vector const& clauses); lbool get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& vars, expr_ref_vector& conseq, expr_ref_vector& unfixed); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index 1438efaf6..b03604b5b 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -115,7 +115,7 @@ namespace smt { return m_kernel.check(num_assumptions, assumptions); } - lbool check(expr_ref_vector const& cube, expr_ref_vector const& clause) { + lbool check(expr_ref_vector const& cube, vector const& clause) { return m_kernel.check(cube, clause); } @@ -291,8 +291,8 @@ namespace smt { return r; } - lbool kernel::check(expr_ref_vector const& cube, expr_ref_vector const& clause) { - return m_imp->check(cube, clause); + lbool kernel::check(expr_ref_vector const& cube, vector const& clauses) { + return m_imp->check(cube, clauses); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 4174422f4..d78f71e20 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -132,7 +132,7 @@ namespace smt { lbool check(app_ref_vector const& asms) { return check(asms.size(), (expr* const*)asms.c_ptr()); } - lbool check(expr_ref_vector const& cube, expr_ref_vector const& clause); + lbool check(expr_ref_vector const& cube, vector const& clauses); /** \brief extract consequences among variables. diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index d715e4879..1e49f7f87 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -191,8 +191,8 @@ namespace smt { } - lbool check_sat_cc_core(expr_ref_vector const& cube, expr_ref_vector const& clause) override { - return m_context.check(cube, clause); + lbool check_sat_cc_core(expr_ref_vector const& cube, vector const& clauses) override { + return m_context.check(cube, clauses); } struct scoped_minimize_core { diff --git a/src/solver/solver.h b/src/solver/solver.h index 3d9befdbc..c4df362e4 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -152,8 +152,8 @@ public: The cube corresponds to auxiliary assumptions. The clause as an auxiliary disjunction that is also assumed for the check. */ - virtual lbool check_sat_cc(expr_ref_vector const& cube, expr_ref_vector const& clause) { - if (clause.empty()) return check_sat(cube.size(), cube.c_ptr()); + virtual lbool check_sat_cc(expr_ref_vector const& cube, vector const& clauses) { + if (clauses.empty()) return check_sat(cube.size(), cube.c_ptr()); NOT_IMPLEMENTED_YET(); } diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index ac241b4a2..db745597c 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -67,10 +67,10 @@ lbool solver_na2as::check_sat(unsigned num_assumptions, expr * const * assumptio return check_sat_core(m_assumptions.size(), m_assumptions.c_ptr()); } -lbool solver_na2as::check_sat_cc(const expr_ref_vector &assumptions, const expr_ref_vector &clause) { - if (clause.empty()) return check_sat(assumptions.size(), assumptions.c_ptr()); +lbool solver_na2as::check_sat_cc(const expr_ref_vector &assumptions, vector const &clauses) { + if (clauses.empty()) return check_sat(assumptions.size(), assumptions.c_ptr()); append_assumptions app(m_assumptions, assumptions.size(), assumptions.c_ptr()); - return check_sat_cc_core(m_assumptions, clause); + return check_sat_cc_core(m_assumptions, clauses); } lbool solver_na2as::get_consequences(expr_ref_vector const& asms, expr_ref_vector const& vars, expr_ref_vector& consequences) { diff --git a/src/solver/solver_na2as.h b/src/solver/solver_na2as.h index a3ed85a9a..d1515a206 100644 --- a/src/solver/solver_na2as.h +++ b/src/solver/solver_na2as.h @@ -39,7 +39,7 @@ public: // Subclasses of solver_na2as should redefine the following *_core methods instead of these ones. lbool check_sat(unsigned num_assumptions, expr * const * assumptions) override; - lbool check_sat_cc(const expr_ref_vector &assumptions, const expr_ref_vector &clause) override; + lbool check_sat_cc(const expr_ref_vector &assumptions, vector const &clauses) override; void push() override; void pop(unsigned n) override; unsigned get_scope_level() const override; @@ -50,7 +50,7 @@ public: lbool find_mutexes(expr_ref_vector const& vars, vector& mutexes) override; protected: virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) = 0; - virtual lbool check_sat_cc_core(const expr_ref_vector &assumptions, const expr_ref_vector &clause) {NOT_IMPLEMENTED_YET();} + virtual lbool check_sat_cc_core(const expr_ref_vector &assumptions, vector const &clauses) { NOT_IMPLEMENTED_YET(); } virtual void push_core() = 0; virtual void pop_core(unsigned n) = 0; }; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index a015c5ea2..1d0fd0c11 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -144,14 +144,14 @@ public: if (m_dump_benchmarks && sw.get_seconds() >= m_dump_threshold) { expr_ref_vector cube(m, num_assumptions, assumptions); - expr_ref_vector clause(m); - dump_benchmark(cube, clause, res, sw.get_seconds()); + vector clauses; + dump_benchmark(cube, clauses, res, sw.get_seconds()); } return res; } - lbool check_sat_cc_core(const expr_ref_vector &cube, - const expr_ref_vector &clause) override { + lbool check_sat_cc_core(expr_ref_vector const & cube, + vector const & clauses) override { SASSERT(!m_pushed || get_scope_level() > 0); m_proof.reset(); scoped_watch _t_(m_pool.m_check_watch); @@ -160,7 +160,7 @@ public: stopwatch sw; sw.start(); internalize_assertions(); - lbool res = m_base->check_sat_cc(cube, clause); + lbool res = m_base->check_sat_cc(cube, clauses); sw.stop(); switch (res) { case l_true: @@ -177,7 +177,7 @@ public: set_status(res); if (m_dump_benchmarks && sw.get_seconds() >= m_dump_threshold) { - dump_benchmark(cube, clause, res, sw.get_seconds()); + dump_benchmark(cube, clauses, res, sw.get_seconds()); } return res; } @@ -265,7 +265,7 @@ public: private: - void dump_benchmark(const expr_ref_vector &cube, const expr_ref_vector &clause, + void dump_benchmark(const expr_ref_vector &cube, vector const & clauses, lbool last_status, double last_time) { std::string file_name = mk_file_name(); std::ofstream out(file_name); @@ -276,7 +276,7 @@ private: out << "(set-info :status " << lbool2status(last_status) << ")\n"; m_base->display(out, cube.size(), cube.c_ptr()); - if (!clause.empty()) { + for (auto const& clause : clauses) { out << ";; extra clause\n"; out << "(assert (or "; for (auto *lit : clause) out << mk_pp(lit, m) << " "; diff --git a/src/test/cube_clause.cpp b/src/test/cube_clause.cpp index f625789e4..0c783277b 100644 --- a/src/test/cube_clause.cpp +++ b/src/test/cube_clause.cpp @@ -35,24 +35,32 @@ void tst_cube_clause() { r = solver->check_sat(cube); std::cout << r << "\n"; clause.push_back(b); - r = solver->check_sat(cube, clause); + vector clauses; + clauses.push_back(clause); + r = solver->check_sat_cc(cube, clauses); std::cout << r << "\n"; core.reset(); solver->get_unsat_core(core); std::cout << core << "\n"; clause.push_back(d); - r = solver->check_sat(cube, clause); + clauses.reset(); + clauses.push_back(clause); + r = solver->check_sat_cc(cube, clauses); std::cout << r << "\n"; core.reset(); solver->get_unsat_core(core); std::cout << core << "\n"; clause.push_back(f); - r = solver->check_sat(cube, clause); + clauses.reset(); + clauses.push_back(clause); + r = solver->check_sat_cc(cube, clauses); std::cout << r << "\n"; core.reset(); solver->get_unsat_core(core); std::cout << core << "\n"; clause.push_back(g); - r = solver->check_sat(cube, clause); + clauses.reset(); + clauses.push_back(clause); + r = solver->check_sat_cc(cube, clauses); std::cout << r << "\n"; } From aa77a918cd49e7d332cfa1cc33040e2fc42aba38 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 1 Jun 2018 10:48:47 -0700 Subject: [PATCH 1116/1283] Optimizing qe_lite --- src/ast/rewriter/rewriter.h | 2 ++ src/ast/rewriter/rewriter_def.h | 11 ++++++++ src/ast/rewriter/var_subst.cpp | 4 +++ src/qe/qe_lite.cpp | 45 ++++++++++++++++++--------------- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h index 8c00f541b..c761b5ca3 100644 --- a/src/ast/rewriter/rewriter.h +++ b/src/ast/rewriter/rewriter.h @@ -346,6 +346,8 @@ public: void set_bindings(unsigned num_bindings, expr * const * bindings); void set_inv_bindings(unsigned num_bindings, expr * const * bindings); + void update_binding_at(unsigned i, expr* binding); + void update_inv_binding_at(unsigned i, expr* binding); void operator()(expr * t, expr_ref & result, proof_ref & result_pr); void operator()(expr * t, expr_ref & result) { operator()(t, result, m_pr); } void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) { diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 4d4c4f708..e8a14b953 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -639,6 +639,17 @@ void rewriter_tpl::set_inv_bindings(unsigned num_bindings, expr * const TRACE("rewriter", display_bindings(tout);); } +template +void rewriter_tpl::update_inv_binding_at(unsigned i, expr* binding) { + m_bindings[i] = binding; +} + +template +void rewriter_tpl::update_binding_at(unsigned i, expr* binding) { + m_bindings[m_bindings.size() - i - 1] = binding; +} + + template template void rewriter_tpl::main_loop(expr * t, expr_ref & result, proof_ref & result_pr) { diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp index 97e0ddb19..7877cf1d2 100644 --- a/src/ast/rewriter/var_subst.cpp +++ b/src/ast/rewriter/var_subst.cpp @@ -24,6 +24,10 @@ Notes: #include "ast/for_each_expr.h" void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result) { + if (is_ground(n)) { + result = n; + return; + } SASSERT(is_well_sorted(result.m(), n)); m_reducer.reset(); if (m_std_order) diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 715848f89..c027d2d07 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -40,14 +40,16 @@ Revision History: namespace eq { bool occurs_var(unsigned idx, expr* e) { + if (is_ground(e)) return false; ptr_buffer todo; - todo.push_back(e); + todo.push_back(e); ast_mark mark; while (!todo.empty()) { expr* e = todo.back(); todo.pop_back(); if (mark.is_marked(e)) continue; mark.mark(e, true); + if (is_ground(e)) continue; if (is_var(e)) { if (to_var(e)->get_idx() == idx) return true; } @@ -67,7 +69,8 @@ namespace eq { arith_util a; datatype_util dt; is_variable_proc* m_is_variable; - var_subst m_subst; + beta_reducer m_subst; + expr_ref_vector m_subst_map; expr_ref_vector m_new_exprs; ptr_vector m_map; @@ -75,7 +78,6 @@ namespace eq { int_vector m_var2pos; ptr_vector m_inx2var; unsigned_vector m_order; - expr_ref_vector m_subst_map; expr_ref_buffer m_new_args; th_rewriter m_rewriter; params_ref m_params; @@ -149,7 +151,7 @@ namespace eq { done.mark(t); } } - done.mark(t); + done.mark(t); todo.pop_back(); break; case AST_QUANTIFIER: @@ -426,26 +428,29 @@ namespace eq { TRACE("qe_lite", tout << "Elimination m_order:" << std::endl; - for(unsigned i=0; iget_num_patterns(); j++) { expr_ref new_pat(m); - m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_pat); + m_subst(q->get_pattern(j), new_pat); new_patterns.push_back(new_pat); } for (unsigned j = 0; j < q->get_num_no_patterns(); j++) { expr_ref new_nopat(m); - m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_nopat); + m_subst(q->get_no_pattern(j), new_nopat); new_no_patterns.push_back(new_nopat); } @@ -748,7 +753,7 @@ namespace eq { expr_ref r(m), new_r(m); r = m.mk_and(conjs.size(), conjs.c_ptr()); create_substitution(largest_vinx + 1); - m_subst(r, m_subst_map.size(), m_subst_map.c_ptr(), new_r); + m_subst(r, new_r); m_rewriter(new_r); conjs.reset(); flatten_and(new_r, conjs); @@ -776,8 +781,8 @@ namespace eq { dt(m), m_is_variable(nullptr), m_subst(m), - m_new_exprs(m), m_subst_map(m), + m_new_exprs(m), m_new_args(m), m_rewriter(m), m_params(p) {} From 6464468cd89d9ebedfbf147f768d7a393c4d97d7 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 2 Jun 2018 22:57:22 -0700 Subject: [PATCH 1117/1283] Remove dead code --- src/muz/spacer/spacer_manager.h | 41 +--- src/muz/spacer/spacer_sym_mux.cpp | 391 +----------------------------- src/muz/spacer/spacer_sym_mux.h | 107 +------- 3 files changed, 21 insertions(+), 518 deletions(-) diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index 2149395ef..a73a9a63b 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -96,35 +96,6 @@ public: func_decl * get_o_pred(func_decl * s, unsigned idx); func_decl * get_n_pred(func_decl * s); - void get_o_index(func_decl* p, unsigned& idx) const { - m_mux.try_get_index(p, idx); - SASSERT(idx != n_index()); - idx--; // m_mux has indices starting at 1 - } - - bool is_o(func_decl * p, unsigned idx) const - {return m_mux.has_index(p, o_index(idx));} - bool is_o(func_decl * p) const { - unsigned idx; - return m_mux.try_get_index(p, idx) && idx != n_index(); - } - bool is_o(expr* e) const - {return is_app(e) && is_o(to_app(e)->get_decl());} - bool is_o(expr* e, unsigned idx) const - {return is_app(e) && is_o(to_app(e)->get_decl(), idx);} - bool is_n(func_decl * p) const - {return m_mux.has_index(p, n_index());} - bool is_n(expr* e) const - {return is_app(e) && is_n(to_app(e)->get_decl());} - - - /** true if f doesn't contain any n predicates */ - bool is_o_formula(expr * f) const - {return !m_mux.contains(f, n_index());} - /** true if f contains only o state preds of index o_idx */ - bool is_o_formula(expr * f, unsigned o_idx) const - {return m_mux.is_homogenous_formula(f, o_index(o_idx));} - /** true if f doesn't contain any o predicates */ bool is_n_formula(expr * f) const {return m_mux.is_homogenous_formula(f, n_index());} @@ -135,18 +106,22 @@ public: func_decl * n2o(func_decl * p, unsigned o_idx) const {return m_mux.conv(p, n_index(), o_index(o_idx));} - void formula_o2n(expr * f, expr_ref & result, unsigned o_idx, bool homogenous = true) const + void formula_o2n(expr * f, expr_ref & result, unsigned o_idx, + bool homogenous = true) const {m_mux.conv_formula(f, o_index(o_idx), n_index(), result, homogenous);} - void formula_n2o(expr * f, expr_ref & result, unsigned o_idx, bool homogenous = true) const + void formula_n2o(expr * f, expr_ref & result, unsigned o_idx, + bool homogenous = true) const {m_mux.conv_formula(f, n_index(), o_index(o_idx), result, homogenous);} void formula_n2o(unsigned o_idx, bool homogenous, expr_ref & result) const - {m_mux.conv_formula(result.get(), n_index(), o_index(o_idx), result, homogenous);} + {m_mux.conv_formula(result.get(), n_index(), o_index(o_idx), + result, homogenous);} void formula_o2o(expr * src, expr_ref & tgt, unsigned src_idx, unsigned tgt_idx, bool homogenous = true) const - {m_mux.conv_formula(src, o_index(src_idx), o_index(tgt_idx), tgt, homogenous);} + {m_mux.conv_formula(src, o_index(src_idx), o_index(tgt_idx), + tgt, homogenous);} }; diff --git a/src/muz/spacer/spacer_sym_mux.cpp b/src/muz/spacer/spacer_sym_mux.cpp index ee1d3726d..9426ddcf7 100644 --- a/src/muz/spacer/spacer_sym_mux.cpp +++ b/src/muz/spacer/spacer_sym_mux.cpp @@ -82,7 +82,6 @@ void sym_mux::create_tuple(func_decl* prefix, unsigned arity, sort * const * dom m_prim2all.insert(tuple[0], tuple); m_prefix2prim.insert(prefix, tuple[0]); m_prim2prefix.insert(tuple[0], prefix); - m_prim_preds.push_back(tuple[0]); m_ref_holder.push_back(prefix); } @@ -122,32 +121,7 @@ func_decl * sym_mux::conv(func_decl * sym, unsigned src_idx, unsigned tgt_idx) c } -func_decl * sym_mux::get_or_create_symbol_by_prefix(func_decl* prefix, unsigned idx, - unsigned arity, sort * const * domain, sort * range) -{ - func_decl * prim = try_get_primary_by_prefix(prefix); - if (prim) { - SASSERT(prim->get_arity() == arity); - SASSERT(prim->get_range() == range); - //domain should match as well, but we won't bother checking an array equality - return conv(prim, 0, idx); - } - - decl_vector syms; - create_tuple(prefix, arity, domain, range, idx + 1, syms); - return syms[idx]; -} - -bool sym_mux::is_muxed_lit(expr * e, unsigned idx) const -{ - if (!is_app(e)) { return false; } - app * a = to_app(e); - if (m.is_not(a) && is_app(a->get_arg(0))) { - a = to_app(a->get_arg(0)); - } - return is_muxed(a->get_decl()); -} struct sym_mux::formula_checker { @@ -198,155 +172,15 @@ private: bool m_found_what_needed; }; -bool sym_mux::contains(expr * e, unsigned idx) const -{ - formula_checker chck(*this, false, idx); - for_each_expr(chck, m_visited, e); - m_visited.reset(); - return chck.some_with_idx(); -} bool sym_mux::is_homogenous_formula(expr * e, unsigned idx) const { + expr_mark visited; formula_checker chck(*this, true, idx); - for_each_expr(chck, m_visited, e); - m_visited.reset(); + for_each_expr(chck, visited, e); return chck.all_have_idx(); } -bool sym_mux::is_homogenous(const expr_ref_vector & vect, unsigned idx) const -{ - expr * const * begin = vect.c_ptr(); - expr * const * end = begin + vect.size(); - for (expr * const * it = begin; it != end; it++) { - if (!is_homogenous_formula(*it, idx)) { - return false; - } - } - return true; -} - -class sym_mux::index_collector { - sym_mux const& m_parent; - svector m_indices; -public: - index_collector(sym_mux const& s): - m_parent(s) {} - - void operator()(expr * e) - { - if (is_app(e)) { - func_decl * sym = to_app(e)->get_decl(); - unsigned idx; - if (m_parent.try_get_index(sym, idx)) { - SASSERT(idx > 0); - --idx; - if (m_indices.size() <= idx) { - m_indices.resize(idx + 1, false); - } - m_indices[idx] = true; - } - } - } - - void extract(unsigned_vector& indices) - { - for (unsigned i = 0; i < m_indices.size(); ++i) { - if (m_indices[i]) { - indices.push_back(i); - } - } - } -}; - - - -void sym_mux::collect_indices(expr* e, unsigned_vector& indices) const -{ - indices.reset(); - index_collector collector(*this); - for_each_expr(collector, m_visited, e); - m_visited.reset(); - collector.extract(indices); -} - -class sym_mux::variable_collector { - sym_mux const& m_parent; - vector >& m_vars; -public: - variable_collector(sym_mux const& s, vector >& vars): - m_parent(s), m_vars(vars) {} - - void operator()(expr * e) - { - if (is_app(e)) { - func_decl * sym = to_app(e)->get_decl(); - unsigned idx; - if (m_parent.try_get_index(sym, idx)) { - SASSERT(idx > 0); - --idx; - if (m_vars.size() <= idx) { - m_vars.resize(idx + 1, ptr_vector()); - } - m_vars[idx].push_back(to_app(e)); - } - } - } -}; - -void sym_mux::collect_variables(expr* e, vector >& vars) const -{ - vars.reset(); - variable_collector collector(*this, vars); - for_each_expr(collector, m_visited, e); - m_visited.reset(); -} - -class sym_mux::hmg_checker { - const sym_mux & m_parent; - - bool m_found_idx; - unsigned m_idx; - bool m_multiple_indexes; - -public: - hmg_checker(const sym_mux & parent) : - m_parent(parent), m_found_idx(false), m_multiple_indexes(false) - { - } - - void operator()(expr * e) - { - if (m_multiple_indexes || !is_app(e)) { return; } - - func_decl * sym = to_app(e)->get_decl(); - unsigned sym_idx; - if (!m_parent.try_get_index(sym, sym_idx)) { return; } - - if (!m_found_idx) { - m_found_idx = true; - m_idx = sym_idx; - return; - } - if (m_idx == sym_idx) { return; } - m_multiple_indexes = true; - } - - bool has_multiple_indexes() const - { - return m_multiple_indexes; - } -}; - -bool sym_mux::is_homogenous_formula(expr * e) const -{ - hmg_checker chck(*this); - for_each_expr(chck, m_visited, e); - m_visited.reset(); - return !chck.has_multiple_indexes(); -} - - struct sym_mux::conv_rewriter_cfg : public default_rewriter_cfg { private: ast_manager & m; @@ -379,8 +213,8 @@ public: } }; -void sym_mux::conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, expr_ref & res, bool homogenous) const -{ +void sym_mux::conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, + expr_ref & res, bool homogenous) const { if (src_idx == tgt_idx) { res = f; return; @@ -389,220 +223,3 @@ void sym_mux::conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, expr_re rewriter_tpl rwr(m, false, r_cfg); rwr(f, res); } - -struct sym_mux::shifting_rewriter_cfg : public default_rewriter_cfg { -private: - ast_manager & m; - const sym_mux & m_parent; - int m_shift; -public: - shifting_rewriter_cfg(const sym_mux & parent, int shift) - : m(parent.get_manager()), - m_parent(parent), - m_shift(shift) {} - - bool get_subst(expr * s, expr * & t, proof * & t_pr) - { - if (!is_app(s)) { return false; } - app * a = to_app(s); - func_decl * sym = a->get_decl(); - - unsigned idx; - if (!m_parent.try_get_index(sym, idx)) { - return false; - } - SASSERT(static_cast(idx) + m_shift >= 0); - func_decl * tgt = m_parent.conv(sym, idx, idx + m_shift); - t = m.mk_app(tgt, a->get_args()); - return true; - } -}; - -void sym_mux::shift_formula(expr * f, int dist, expr_ref & res) const -{ - if (dist == 0) { - res = f; - return; - } - shifting_rewriter_cfg r_cfg(*this, dist); - rewriter_tpl rwr(m, false, r_cfg); - rwr(f, res); -} - -void sym_mux::conv_formula_vector(const expr_ref_vector & vect, unsigned src_idx, unsigned tgt_idx, - expr_ref_vector & res) const -{ - res.reset(); - expr * const * begin = vect.c_ptr(); - expr * const * end = begin + vect.size(); - for (expr * const * it = begin; it != end; it++) { - expr_ref converted(m); - conv_formula(*it, src_idx, tgt_idx, converted); - res.push_back(converted); - } -} - -void sym_mux::filter_idx(expr_ref_vector & vect, unsigned idx) const -{ - unsigned i = 0; - while (i < vect.size()) { - expr* e = vect[i].get(); - if (contains(e, idx) && is_homogenous_formula(e, idx)) { - i++; - } else { - //we don't allow mixing states inside vector elements - SASSERT(!contains(e, idx)); - vect[i] = vect.back(); - vect.pop_back(); - } - } -} - -void sym_mux::partition_o_idx( - expr_ref_vector const& lits, - expr_ref_vector& o_lits, - expr_ref_vector& other, unsigned idx) const -{ - - for (unsigned i = 0; i < lits.size(); ++i) { - if (contains(lits[i], idx) && is_homogenous_formula(lits[i], idx)) { - o_lits.push_back(lits[i]); - } else { - other.push_back(lits[i]); - } - } -} - - - -class sym_mux::nonmodel_sym_checker { - const sym_mux & m_parent; - - bool m_found; -public: - nonmodel_sym_checker(const sym_mux & parent) : - m_parent(parent), m_found(false) - { - } - - void operator()(expr * e) - { - if (m_found || !is_app(e)) { return; } - - func_decl * sym = to_app(e)->get_decl(); - - if (m_parent.is_non_model_sym(sym)) { - m_found = true; - } - } - - bool found() const - { - return m_found; - } -}; - -bool sym_mux::has_nonmodel_symbol(expr * e) const -{ - nonmodel_sym_checker chck(*this); - for_each_expr(chck, e); - return chck.found(); -} - -void sym_mux::filter_non_model_lits(expr_ref_vector & vect) const -{ - unsigned i = 0; - while (i < vect.size()) { - if (!has_nonmodel_symbol(vect[i].get())) { - i++; - continue; - } - vect[i] = vect.back(); - vect.pop_back(); - } -} - -class sym_mux::decl_idx_comparator { - const sym_mux & m_parent; -public: - decl_idx_comparator(const sym_mux & parent) - : m_parent(parent) - { } - - bool operator()(func_decl * sym1, func_decl * sym2) - { - unsigned idx1, idx2; - if (!m_parent.try_get_index(sym1, idx1)) { idx1 = UINT_MAX; } - if (!m_parent.try_get_index(sym2, idx2)) { idx2 = UINT_MAX; } - - if (idx1 != idx2) { return idx1 < idx2; } - return lt(sym1->get_name(), sym2->get_name()); - } -}; - -std::string sym_mux::pp_model(const model_core & mdl) const -{ - decl_vector consts; - unsigned sz = mdl.get_num_constants(); - for (unsigned i = 0; i < sz; i++) { - func_decl * d = mdl.get_constant(i); - consts.push_back(d); - } - - std::sort(consts.begin(), consts.end(), decl_idx_comparator(*this)); - - std::stringstream res; - - decl_vector::iterator end = consts.end(); - for (decl_vector::iterator it = consts.begin(); it != end; it++) { - func_decl * d = *it; - std::string name = d->get_name().str(); - const char * arrow = " -> "; - res << name << arrow; - unsigned indent = static_cast(name.length() + strlen(arrow)); - res << mk_pp(mdl.get_const_interp(d), m, indent) << "\n"; - - if (it + 1 != end) { - unsigned idx1, idx2; - if (!try_get_index(*it, idx1)) { idx1 = UINT_MAX; } - if (!try_get_index(*(it + 1), idx2)) { idx2 = UINT_MAX; } - if (idx1 != idx2) { res << "\n"; } - } - } - return res.str(); -} - - -#if 0 - -class sym_mux::index_renamer_cfg : public default_rewriter_cfg { - const sym_mux & m_parent; - unsigned m_idx; - -public: - index_renamer_cfg(const sym_mux & p, unsigned idx) : m_parent(p), m_idx(idx) {} - - bool get_subst(expr * s, expr * & t, proof * & t_pr) - { - if (!is_app(s)) { return false; } - app * a = to_app(s); - if (a->get_family_id() != null_family_id) { - return false; - } - func_decl * sym = a->get_decl(); - unsigned idx; - if (!m_parent.try_get_index(sym, idx)) { - return false; - } - if (m_idx == idx) { - return false; - } - ast_manager& m = m_parent.get_manager(); - symbol name = symbol((sym->get_name().str() + "!").c_str()); - func_decl * tgt = m.mk_func_decl(name, sym->get_arity(), sym->get_domain(), sym->get_range()); - t = m.mk_app(tgt, a->get_num_args(), a->get_args()); - return true; - } -}; - -#endif diff --git a/src/muz/spacer/spacer_sym_mux.h b/src/muz/spacer/spacer_sym_mux.h index a4d10971a..97e3459d7 100644 --- a/src/muz/spacer/spacer_sym_mux.h +++ b/src/muz/spacer/spacer_sym_mux.h @@ -7,7 +7,8 @@ Module Name: Abstract: - A symbol multiplexer that helps with having multiple versions of each of a set of symbols. + A symbol multiplexer that helps with having multiple versions of + each of a set of symbols. Author: @@ -20,18 +21,17 @@ Revision History: #ifndef _SYM_MUX_H_ #define _SYM_MUX_H_ +#include +#include + #include "ast/ast.h" #include "util/map.h" #include "util/vector.h" -#include class model_core; namespace spacer { class sym_mux { -public: - typedef ptr_vector app_vector; - typedef ptr_vector decl_vector; private: typedef obj_map sym2u; typedef obj_map sym2dv; @@ -41,7 +41,6 @@ private: ast_manager & m; mutable ast_ref_vector m_ref_holder; - mutable expr_mark m_visited; mutable unsigned m_next_sym_suffix_idx; mutable symbols m_used_suffixes; @@ -75,24 +74,15 @@ private: */ sym2sym m_prim2prefix; - decl_vector m_prim_preds; - obj_hashtable m_non_model_syms; struct formula_checker; struct conv_rewriter_cfg; - struct shifting_rewriter_cfg; - class decl_idx_comparator; - class hmg_checker; - class nonmodel_sym_checker; - class index_renamer_cfg; - class index_collector; - class variable_collector; std::string get_suffix(unsigned i) const; void ensure_tuple_size(func_decl * prim, unsigned sz) const; - expr_ref isolate_o_idx(expr* e, unsigned idx) const; + // expr_ref isolate_o_idx(expr* e, unsigned idx) const; public: sym_mux(ast_manager & m, const std::vector & suffixes); @@ -101,9 +91,7 @@ public: bool is_muxed(func_decl * sym) const { return m_sym2idx.contains(sym); } bool try_get_index(func_decl * sym, unsigned & idx) const - { - return m_sym2idx.find(sym, idx); - } + {return m_sym2idx.find(sym, idx);} bool has_index(func_decl * sym, unsigned idx) const { @@ -143,30 +131,6 @@ public: return conv(prim, 0, idx); } - /** - Marks symbol as non-model which means it will not appear in models collected by - get_muxed_cube_from_model function. - This is to take care of auxiliary symbols introduced by the disjunction relations - to relativize lemmas coming from disjuncts. - */ - void mark_as_non_model(func_decl * sym) - { - SASSERT(is_muxed(sym)); - m_non_model_syms.insert(get_primary(sym)); - } - - func_decl * get_or_create_symbol_by_prefix(func_decl* prefix, unsigned idx, - unsigned arity, sort * const * domain, sort * range); - - - - bool is_muxed_lit(expr * e, unsigned idx) const; - - bool is_non_model_sym(func_decl * s) const - { - return is_muxed(s) && m_non_model_syms.contains(get_primary(s)); - } - /** Create a multiplexed tuple of propositional constants. Symbols may be suplied in the tuple vector, @@ -181,27 +145,7 @@ public: Return true if the only multiplexed symbols which e contains are of index idx. */ bool is_homogenous_formula(expr * e, unsigned idx) const; - bool is_homogenous(const expr_ref_vector & vect, unsigned idx) const; - /** - Return true if all multiplexed symbols which e contains are of one index. - */ - bool is_homogenous_formula(expr * e) const; - - /** - Return true if expression e contains a muxed symbol of index idx. - */ - bool contains(expr * e, unsigned idx) const; - - /** - Collect indices used in expression. - */ - void collect_indices(expr* e, unsigned_vector& indices) const; - - /** - Collect used variables of each index. - */ - void collect_variables(expr* e, vector >& vars) const; /** Convert symbol sym which has to be of src_idx variant into variant tgt_idx. @@ -213,43 +157,10 @@ public: Convert src_idx symbols in formula f variant into tgt_idx. If homogenous is true, formula cannot contain symbols of other variants. */ - void conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, expr_ref & res, bool homogenous = true) const; - void conv_formula_vector(const expr_ref_vector & vect, unsigned src_idx, unsigned tgt_idx, - expr_ref_vector & res) const; + void conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, + expr_ref & res, bool homogenous = true) const; - /** - Shifts the muxed symbols in f by dist. Dist can be negative, but it should never shift - symbol index to a negative value. - */ - void shift_formula(expr * f, int dist, expr_ref & res) const; - /** - Remove from vect literals (atoms or negations of atoms) of symbols - that contain multiplexed symbols with indexes other than idx. - - Each of the literals can contain only symbols multiplexed with one index - (this trivially holds if the literals are propositional). - - Order of elements in vect may be modified by this function - */ - void filter_idx(expr_ref_vector & vect, unsigned idx) const; - - /** - Partition literals into o_literals and others. - */ - void partition_o_idx(expr_ref_vector const& lits, - expr_ref_vector& o_lits, - expr_ref_vector& other, unsigned idx) const; - - bool has_nonmodel_symbol(expr * e) const; - void filter_non_model_lits(expr_ref_vector & vect) const; - - func_decl * const * begin_prim_preds() const { return m_prim_preds.begin(); } - func_decl * const * end_prim_preds() const { return m_prim_preds.end(); } - - void get_muxed_cube_from_model(const model_core & model, expr_ref_vector & res) const; - - std::string pp_model(const model_core & mdl) const; }; } From e0e435582a95a08238e6680ae3d4b9244205871e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 2 Jun 2018 23:23:56 -0700 Subject: [PATCH 1118/1283] Minor code cleanup --- src/muz/spacer/spacer_sym_mux.cpp | 63 ++++++++++++++----------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/muz/spacer/spacer_sym_mux.cpp b/src/muz/spacer/spacer_sym_mux.cpp index 9426ddcf7..776776188 100644 --- a/src/muz/spacer/spacer_sym_mux.cpp +++ b/src/muz/spacer/spacer_sym_mux.cpp @@ -55,7 +55,12 @@ std::string sym_mux::get_suffix(unsigned i) const return m_suffixes[i]; } -void sym_mux::create_tuple(func_decl* prefix, unsigned arity, sort * const * domain, sort * range, +/** + populates a vector called tuple with func_decl's + tuple[0] is called primary and is used as key in various maps + */ +void sym_mux::create_tuple(func_decl* prefix, unsigned arity, + sort * const * domain, sort * range, unsigned tuple_length, decl_vector & tuple) { SASSERT(tuple_length > 0); @@ -63,16 +68,18 @@ void sym_mux::create_tuple(func_decl* prefix, unsigned arity, sort * const * dom tuple.push_back(0); } SASSERT(tuple.size() == tuple_length); - std::string pre = prefix->get_name().str(); for (unsigned i = 0; i < tuple_length; i++) { if (tuple[i] != 0) { SASSERT(tuple[i]->get_arity() == arity); SASSERT(tuple[i]->get_range() == range); - //domain should match as well, but we won't bother checking an array equality + //domain should match as well, but we won't bother + //checking an array equality } else { - std::string name = pre + get_suffix(i); - tuple[i] = m.mk_func_decl(symbol(name.c_str()), arity, domain, range); + std::string name = prefix->get_name().str(); + name += get_suffix(i); + tuple[i] = m.mk_func_decl(symbol(name.c_str()), arity, + domain, range); } m_ref_holder.push_back(tuple[i]); m_sym2idx.insert(tuple[i], i); @@ -85,6 +92,9 @@ void sym_mux::create_tuple(func_decl* prefix, unsigned arity, sort * const * dom m_ref_holder.push_back(prefix); } +/** + extends a tuple in which prim is primary to the given size +*/ void sym_mux::ensure_tuple_size(func_decl * prim, unsigned sz) const { SASSERT(m_prim2all.contains(prim)); @@ -98,8 +108,9 @@ void sym_mux::ensure_tuple_size(func_decl * prim, unsigned sz) const std::string prefix_name = prefix->get_name().bare_str(); for (unsigned i = tuple.size(); i < sz; ++i) { std::string name = prefix_name + get_suffix(i); - func_decl * new_sym = m.mk_func_decl(symbol(name.c_str()), prefix->get_arity(), - prefix->get_domain(), prefix->get_range()); + func_decl * new_sym = + m.mk_func_decl(symbol(name.c_str()), prefix->get_arity(), + prefix->get_domain(), prefix->get_range()); tuple.push_back(new_sym); m_ref_holder.push_back(new_sym); @@ -108,8 +119,9 @@ void sym_mux::ensure_tuple_size(func_decl * prim, unsigned sz) const } } -func_decl * sym_mux::conv(func_decl * sym, unsigned src_idx, unsigned tgt_idx) const -{ +/** given a func_decl with src_idx returns its version with tgt_idx */ +func_decl * sym_mux::conv(func_decl * sym, + unsigned src_idx, unsigned tgt_idx) const { if (src_idx == tgt_idx) { return sym; } func_decl * prim = (src_idx == 0) ? sym : get_primary(sym); if (tgt_idx > src_idx) { @@ -121,15 +133,10 @@ func_decl * sym_mux::conv(func_decl * sym, unsigned src_idx, unsigned tgt_idx) c } - - - struct sym_mux::formula_checker { - formula_checker(const sym_mux & parent, bool all, unsigned idx) : - m_parent(parent), m_all(all), m_idx(idx), - m_found_what_needed(false) - { - } + formula_checker(const sym_mux & parent, unsigned idx) : + m_parent(parent), m_idx(idx), + m_found_what_needed(false) {} void operator()(expr * e) { @@ -140,28 +147,15 @@ struct sym_mux::formula_checker { if (!m_parent.try_get_index(sym, sym_idx)) { return; } bool have_idx = sym_idx == m_idx; - - if (m_all ? (!have_idx) : have_idx) { - m_found_what_needed = true; - } + m_found_what_needed = !have_idx; } - bool all_have_idx() const - { - SASSERT(m_all); //we were looking for the queried property - return !m_found_what_needed; - } + bool all_have_idx() const {return !m_found_what_needed;} - bool some_with_idx() const - { - SASSERT(!m_all); //we were looking for the queried property - return m_found_what_needed; - } private: const sym_mux & m_parent; - bool m_all; unsigned m_idx; /** @@ -176,7 +170,7 @@ private: bool sym_mux::is_homogenous_formula(expr * e, unsigned idx) const { expr_mark visited; - formula_checker chck(*this, true, idx); + formula_checker chck(*this, idx); for_each_expr(chck, visited, e); return chck.all_have_idx(); } @@ -189,7 +183,8 @@ private: unsigned m_to_idx; bool m_homogenous; public: - conv_rewriter_cfg(const sym_mux & parent, unsigned from_idx, unsigned to_idx, bool homogenous) + conv_rewriter_cfg(const sym_mux & parent, unsigned from_idx, + unsigned to_idx, bool homogenous) : m(parent.get_manager()), m_parent(parent), m_from_idx(from_idx), From 268274911a1bb91695464cc4b7f16d41b229bf2e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 3 Jun 2018 09:13:38 -0700 Subject: [PATCH 1119/1283] Fix to cube-and-clause interface in prop_solver --- src/muz/spacer/spacer_prop_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 4613cd089..64f1bfc9a 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -376,7 +376,7 @@ lbool prop_solver::check_assumptions(const expr_ref_vector & _hard, unsigned soft_sz = soft.size(); (void) soft_sz; vector clauses; - clauses.push_back(clause); + if (!clause.empty()) clauses.push_back(clause); lbool res = internal_check_assumptions(hard, soft, clauses); if (!m_use_push_bg) { m_ctx->pop(1); } From 38c2b56f0e6a0625666e5f6d67669680dc3e182c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 3 Jun 2018 16:05:29 -0700 Subject: [PATCH 1120/1283] Rewrite spacer::sym_mux Simpler implementation that only provides functionality actually used by spacer --- src/muz/spacer/spacer_manager.cpp | 43 ++---- src/muz/spacer/spacer_manager.h | 16 +-- src/muz/spacer/spacer_sym_mux.cpp | 221 ++++++++++++------------------ src/muz/spacer/spacer_sym_mux.h | 140 +++++-------------- 4 files changed, 138 insertions(+), 282 deletions(-) diff --git a/src/muz/spacer/spacer_manager.cpp b/src/muz/spacer/spacer_manager.cpp index 719bf7862..856207463 100644 --- a/src/muz/spacer/spacer_manager.cpp +++ b/src/muz/spacer/spacer_manager.cpp @@ -170,42 +170,25 @@ void inductive_property::display(datalog::rule_manager& rm, ptr_vector state_suffixes() { - std::vector res; - res.push_back("_n"); - return res; -} -manager::manager(ast_manager& manager) : - m(manager), m_mux(m, state_suffixes()) { -} +manager::manager(ast_manager& manager) : m(manager), m_mux(m) {} - -void manager::add_new_state(func_decl * s) -{ - SASSERT(s->get_arity() == 0); //we currently don't support non-constant states - decl_vector vect; - - SASSERT(o_index(0) == 1); //we assume this in the number of retrieved symbols - m_mux.create_tuple(s, s->get_arity(), s->get_domain(), s->get_range(), 2, vect); -} - -func_decl * manager::get_o_pred(func_decl* s, unsigned idx) -{ - func_decl * res = m_mux.try_get_by_prefix(s, o_index(idx)); - if (res) { return res; } - add_new_state(s); - res = m_mux.try_get_by_prefix(s, o_index(idx)); +func_decl * manager::get_o_pred(func_decl* s, unsigned idx) { + func_decl * res = m_mux.find_by_decl(s, o_index(idx)); + if (!res) { + m_mux.register_decl(s); + res = m_mux.find_by_decl(s, o_index(idx)); + } SASSERT(res); return res; } -func_decl * manager::get_n_pred(func_decl* s) -{ - func_decl * res = m_mux.try_get_by_prefix(s, n_index()); - if (res) { return res; } - add_new_state(s); - res = m_mux.try_get_by_prefix(s, n_index()); +func_decl * manager::get_n_pred(func_decl* s) { + func_decl * res = m_mux.find_by_decl(s, n_index()); + if (!res) { + m_mux.register_decl(s); + res = m_mux.find_by_decl(s, n_index()); + } SASSERT(res); return res; } diff --git a/src/muz/spacer/spacer_manager.h b/src/muz/spacer/spacer_manager.h index a73a9a63b..d592a30a8 100644 --- a/src/muz/spacer/spacer_manager.h +++ b/src/muz/spacer/spacer_manager.h @@ -83,8 +83,6 @@ class manager { unsigned n_index() const { return 0; } unsigned o_index(unsigned i) const { return i + 1; } - void add_new_state(func_decl * s); - public: manager(ast_manager & manager); @@ -100,27 +98,27 @@ public: {return m_mux.is_homogenous_formula(f, n_index());} func_decl * o2n(func_decl * p, unsigned o_idx) const - {return m_mux.conv(p, o_index(o_idx), n_index());} + {return m_mux.shift_decl(p, o_index(o_idx), n_index());} func_decl * o2o(func_decl * p, unsigned src_idx, unsigned tgt_idx) const - {return m_mux.conv(p, o_index(src_idx), o_index(tgt_idx));} + {return m_mux.shift_decl(p, o_index(src_idx), o_index(tgt_idx));} func_decl * n2o(func_decl * p, unsigned o_idx) const - {return m_mux.conv(p, n_index(), o_index(o_idx));} + {return m_mux.shift_decl(p, n_index(), o_index(o_idx));} void formula_o2n(expr * f, expr_ref & result, unsigned o_idx, bool homogenous = true) const - {m_mux.conv_formula(f, o_index(o_idx), n_index(), result, homogenous);} + {m_mux.shift_expr(f, o_index(o_idx), n_index(), result, homogenous);} void formula_n2o(expr * f, expr_ref & result, unsigned o_idx, bool homogenous = true) const - {m_mux.conv_formula(f, n_index(), o_index(o_idx), result, homogenous);} + {m_mux.shift_expr(f, n_index(), o_index(o_idx), result, homogenous);} void formula_n2o(unsigned o_idx, bool homogenous, expr_ref & result) const - {m_mux.conv_formula(result.get(), n_index(), o_index(o_idx), + {m_mux.shift_expr(result.get(), n_index(), o_index(o_idx), result, homogenous);} void formula_o2o(expr * src, expr_ref & tgt, unsigned src_idx, unsigned tgt_idx, bool homogenous = true) const - {m_mux.conv_formula(src, o_index(src_idx), o_index(tgt_idx), + {m_mux.shift_expr(src, o_index(src_idx), o_index(tgt_idx), tgt, homogenous);} }; diff --git a/src/muz/spacer/spacer_sym_mux.cpp b/src/muz/spacer/spacer_sym_mux.cpp index 776776188..5dfb3a531 100644 --- a/src/muz/spacer/spacer_sym_mux.cpp +++ b/src/muz/spacer/spacer_sym_mux.cpp @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2011 Microsoft Corporation +Copyright (c) 2018 Arie Gurfinkel and Microsoft Corporation Module Name: @@ -7,10 +7,12 @@ Module Name: Abstract: - A symbol multiplexer that helps with having multiple versions of each of a set of symbols. + A symbol multiplexer that helps with having multiple versions of + each of a set of symbols. Author: + Arie Gurfinkel Krystof Hoder (t-khoder) 2011-9-8. Revision History: @@ -22,166 +24,114 @@ Revision History: #include "ast/rewriter/rewriter.h" #include "ast/rewriter/rewriter_def.h" -#include "model/model.h" - #include "muz/spacer/spacer_util.h" #include "muz/spacer/spacer_sym_mux.h" using namespace spacer; -sym_mux::sym_mux(ast_manager & m, const std::vector & suffixes) - : m(m), m_ref_holder(m), m_next_sym_suffix_idx(0), m_suffixes(suffixes) -{ - for (std::string const& s : m_suffixes) { - m_used_suffixes.insert(symbol(s.c_str())); +sym_mux::sym_mux(ast_manager & m) : m(m) {} +sym_mux::~sym_mux() { + for (auto &entry : m_entries) { + dealloc(entry.m_value); } } -std::string sym_mux::get_suffix(unsigned i) const -{ - while (m_suffixes.size() <= i) { - std::string new_suffix; - symbol new_syffix_sym; - do { - std::stringstream stm; - stm << '_' << m_next_sym_suffix_idx; - m_next_sym_suffix_idx++; - new_suffix = stm.str(); - new_syffix_sym = symbol(new_suffix.c_str()); - } while (m_used_suffixes.contains(new_syffix_sym)); - m_used_suffixes.insert(new_syffix_sym); - m_suffixes.push_back(new_suffix); - } - return m_suffixes[i]; +func_decl_ref sym_mux::mk_variant(func_decl *fdecl, unsigned i) const { + func_decl_ref v(m); + std::string name = fdecl->get_name().str(); + std::string suffix = "_"; + suffix += i == 0 ? "n" : std::to_string(i - 1); + name += suffix; + v = m.mk_func_decl(symbol(name.c_str()), fdecl->get_arity(), + fdecl->get_domain(), fdecl->get_range()); + return v; } -/** - populates a vector called tuple with func_decl's - tuple[0] is called primary and is used as key in various maps - */ -void sym_mux::create_tuple(func_decl* prefix, unsigned arity, - sort * const * domain, sort * range, - unsigned tuple_length, decl_vector & tuple) -{ - SASSERT(tuple_length > 0); - while (tuple.size() < tuple_length) { - tuple.push_back(0); - } - SASSERT(tuple.size() == tuple_length); - for (unsigned i = 0; i < tuple_length; i++) { +void sym_mux::register_decl(func_decl *fdecl) { + sym_mux_entry *entry = alloc(sym_mux_entry, m); + entry->m_main = fdecl; + entry->m_variants.push_back(mk_variant(fdecl, 0)); + entry->m_variants.push_back(mk_variant(fdecl, 1)); - if (tuple[i] != 0) { - SASSERT(tuple[i]->get_arity() == arity); - SASSERT(tuple[i]->get_range() == range); - //domain should match as well, but we won't bother - //checking an array equality - } else { - std::string name = prefix->get_name().str(); - name += get_suffix(i); - tuple[i] = m.mk_func_decl(symbol(name.c_str()), arity, - domain, range); - } - m_ref_holder.push_back(tuple[i]); - m_sym2idx.insert(tuple[i], i); - m_sym2prim.insert(tuple[i], tuple[0]); - } - - m_prim2all.insert(tuple[0], tuple); - m_prefix2prim.insert(prefix, tuple[0]); - m_prim2prefix.insert(tuple[0], prefix); - m_ref_holder.push_back(prefix); + m_entries.insert(fdecl, entry); + m_muxes.insert(entry->m_variants.get(0), std::make_pair(entry, 0)); + m_muxes.insert(entry->m_variants.get(1), std::make_pair(entry, 1)); } - -/** - extends a tuple in which prim is primary to the given size -*/ -void sym_mux::ensure_tuple_size(func_decl * prim, unsigned sz) const -{ - SASSERT(m_prim2all.contains(prim)); - decl_vector& tuple = m_prim2all.find_core(prim)->get_data().m_value; - SASSERT(tuple[0] == prim); - - if (sz <= tuple.size()) { return; } - - func_decl * prefix; - TRUSTME(m_prim2prefix.find(prim, prefix)); - std::string prefix_name = prefix->get_name().bare_str(); - for (unsigned i = tuple.size(); i < sz; ++i) { - std::string name = prefix_name + get_suffix(i); - func_decl * new_sym = - m.mk_func_decl(symbol(name.c_str()), prefix->get_arity(), - prefix->get_domain(), prefix->get_range()); - - tuple.push_back(new_sym); - m_ref_holder.push_back(new_sym); - m_sym2idx.insert(new_sym, i); - m_sym2prim.insert(new_sym, prim); +void sym_mux::ensure_capacity(sym_mux_entry &entry, unsigned sz) { + while (entry.m_variants.size() < sz) { + unsigned idx = entry.m_variants.size(); + entry.m_variants.push_back (mk_variant(entry.m_main, idx)); + m_muxes.insert(entry.m_variants.back(), std::make_pair(&entry, idx)); } } -/** given a func_decl with src_idx returns its version with tgt_idx */ -func_decl * sym_mux::conv(func_decl * sym, - unsigned src_idx, unsigned tgt_idx) const { - if (src_idx == tgt_idx) { return sym; } - func_decl * prim = (src_idx == 0) ? sym : get_primary(sym); - if (tgt_idx > src_idx) { - ensure_tuple_size(prim, tgt_idx + 1); - } - decl_vector & sym_vect = m_prim2all.find_core(prim)->get_data().m_value; - SASSERT(sym_vect[src_idx] == sym); - return sym_vect[tgt_idx]; +bool sym_mux::find_idx(func_decl * sym, unsigned & idx) const { + std::pair entry; + if (m_muxes.find(sym, entry)) {idx = entry.second; return true;} + return false; } +func_decl * sym_mux::find_by_decl(func_decl* fdecl, unsigned idx) { + sym_mux_entry *entry = nullptr; + if (m_entries.find(fdecl, entry)) { + ensure_capacity(*entry, idx+1); + return entry->m_variants.get(idx); + } + return nullptr; +} -struct sym_mux::formula_checker { +func_decl * sym_mux::shift_decl(func_decl * decl, + unsigned src_idx, unsigned tgt_idx) const { + std::pair entry; + if (m_muxes.find(decl, entry)) { + SASSERT(entry.second == src_idx); + return entry.first->m_variants.get(tgt_idx); + } + UNREACHABLE(); + return nullptr; +} + +namespace { +struct formula_checker { formula_checker(const sym_mux & parent, unsigned idx) : - m_parent(parent), m_idx(idx), - m_found_what_needed(false) {} + m_parent(parent), m_idx(idx), m_found(false) {} - void operator()(expr * e) - { - if (m_found_what_needed || !is_app(e)) { return; } + void operator()(expr * e) { + if (m_found || !is_app(e)) { return; } func_decl * sym = to_app(e)->get_decl(); unsigned sym_idx; - if (!m_parent.try_get_index(sym, sym_idx)) { return; } + if (!m_parent.find_idx(sym, sym_idx)) { return; } bool have_idx = sym_idx == m_idx; - m_found_what_needed = !have_idx; - + m_found = !have_idx; } - bool all_have_idx() const {return !m_found_what_needed;} - + bool all_have_idx() const {return !m_found;} private: const sym_mux & m_parent; unsigned m_idx; - - /** - If we check whether all muxed symbols are of given index, we look for - counter-examples, checking whether form contains a muxed symbol of an index, - we look for symbol of index m_idx. - */ - bool m_found_what_needed; + bool m_found; }; - - -bool sym_mux::is_homogenous_formula(expr * e, unsigned idx) const -{ - expr_mark visited; - formula_checker chck(*this, idx); - for_each_expr(chck, visited, e); - return chck.all_have_idx(); } -struct sym_mux::conv_rewriter_cfg : public default_rewriter_cfg { +bool sym_mux::is_homogenous_formula(expr * e, unsigned idx) const { + expr_mark visited; + formula_checker fck(*this, idx); + for_each_expr(fck, visited, e); + return fck.all_have_idx(); +} + +namespace { +struct conv_rewriter_cfg : public default_rewriter_cfg { private: ast_manager & m; const sym_mux & m_parent; unsigned m_from_idx; unsigned m_to_idx; bool m_homogenous; + expr_ref_vector m_pinned; public: conv_rewriter_cfg(const sym_mux & parent, unsigned from_idx, unsigned to_idx, bool homogenous) @@ -189,7 +139,7 @@ public: m_parent(parent), m_from_idx(from_idx), m_to_idx(to_idx), - m_homogenous(homogenous) {} + m_homogenous(homogenous), m_pinned(m) {(void) m_homogenous;} bool get_subst(expr * s, expr * & t, proof * & t_pr) { @@ -197,24 +147,23 @@ public: app * a = to_app(s); func_decl * sym = a->get_decl(); if (!m_parent.has_index(sym, m_from_idx)) { - (void) m_homogenous; SASSERT(!m_homogenous || !m_parent.is_muxed(sym)); return false; } - func_decl * tgt = m_parent.conv(sym, m_from_idx, m_to_idx); - + func_decl * tgt = m_parent.shift_decl(sym, m_from_idx, m_to_idx); t = m.mk_app(tgt, a->get_args()); + m_pinned.push_back(t); return true; } }; - -void sym_mux::conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, - expr_ref & res, bool homogenous) const { - if (src_idx == tgt_idx) { - res = f; - return; - } - conv_rewriter_cfg r_cfg(*this, src_idx, tgt_idx, homogenous); - rewriter_tpl rwr(m, false, r_cfg); - rwr(f, res); +} + +void sym_mux::shift_expr(expr * f, unsigned src_idx, unsigned tgt_idx, + expr_ref & res, bool homogenous) const { + if (src_idx == tgt_idx) {res = f;} + else { + conv_rewriter_cfg r_cfg(*this, src_idx, tgt_idx, homogenous); + rewriter_tpl rwr(m, false, r_cfg); + rwr(f, res); + } } diff --git a/src/muz/spacer/spacer_sym_mux.h b/src/muz/spacer/spacer_sym_mux.h index 97e3459d7..9657b47d9 100644 --- a/src/muz/spacer/spacer_sym_mux.h +++ b/src/muz/spacer/spacer_sym_mux.h @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2011 Microsoft Corporation +Copyright (c) 2018 Arie Gurfinkel and Microsoft Corporation Module Name: @@ -12,6 +12,7 @@ Abstract: Author: + Arie Gurfinkel Krystof Hoder (t-khoder) 2011-9-8. Revision History: @@ -21,144 +22,69 @@ Revision History: #ifndef _SYM_MUX_H_ #define _SYM_MUX_H_ -#include #include #include "ast/ast.h" #include "util/map.h" #include "util/vector.h" -class model_core; - namespace spacer { class sym_mux { private: - typedef obj_map sym2u; - typedef obj_map sym2dv; - typedef obj_map sym2sym; - typedef obj_map sym2pred; - typedef hashtable symbols; + class sym_mux_entry { + public: + func_decl_ref m_main; + func_decl_ref_vector m_variants; + sym_mux_entry(ast_manager &m) : m_main(m), m_variants(m) {}; + }; - ast_manager & m; - mutable ast_ref_vector m_ref_holder; + typedef obj_map decl2entry_map; + typedef obj_map > mux2entry_map; - mutable unsigned m_next_sym_suffix_idx; - mutable symbols m_used_suffixes; - /** Here we have default suffixes for each of the variants */ - mutable std::vector m_suffixes; + ast_manager &m; + decl2entry_map m_entries; + mux2entry_map m_muxes; + func_decl_ref mk_variant(func_decl *fdecl, unsigned i) const; + void ensure_capacity(sym_mux_entry &entry, unsigned sz) ; - /** - Primary symbol is the 0-th variant. This member maps from primary symbol - to vector of all its variants (including the primary variant). - */ - sym2dv m_prim2all; - - /** - For each symbol contains its variant index - */ - mutable sym2u m_sym2idx; - /** - For each symbol contains its primary variant - */ - mutable sym2sym m_sym2prim; - - /** - Maps prefixes passed to the create_tuple to - the primary symbol created from it. - */ - sym2pred m_prefix2prim; - - /** - Maps pripary symbols to prefixes that were used to create them. - */ - sym2sym m_prim2prefix; - - - - struct formula_checker; - struct conv_rewriter_cfg; - - std::string get_suffix(unsigned i) const; - void ensure_tuple_size(func_decl * prim, unsigned sz) const; - - // expr_ref isolate_o_idx(expr* e, unsigned idx) const; public: - sym_mux(ast_manager & m, const std::vector & suffixes); - + sym_mux(ast_manager & m); + ~sym_mux(); ast_manager & get_manager() const { return m; } - bool is_muxed(func_decl * sym) const { return m_sym2idx.contains(sym); } - - bool try_get_index(func_decl * sym, unsigned & idx) const - {return m_sym2idx.find(sym, idx);} - + void register_decl(func_decl *fdecl); + bool find_idx(func_decl * sym, unsigned & idx) const; bool has_index(func_decl * sym, unsigned idx) const - { - unsigned actual_idx; - return try_get_index(sym, actual_idx) && idx == actual_idx; - } + {unsigned v; return find_idx(sym, v) && idx == v;} - /** Return primary symbol. sym must be muxed. */ - func_decl * get_primary(func_decl * sym) const - { - func_decl * prim; - TRUSTME(m_sym2prim.find(sym, prim)); - return prim; - } /** - Return primary symbol created from prefix, or 0 if the prefix was never used. + \brief Return symbol created from prefix, or 0 if the prefix + was never used. */ - func_decl * try_get_primary_by_prefix(func_decl* prefix) const - { - func_decl * res; - if(!m_prefix2prim.find(prefix, res)) { - return nullptr; - } - return res; - } + func_decl * find_by_decl(func_decl* fdecl, unsigned idx); /** - Return symbol created from prefix, or 0 if the prefix was never used. - */ - func_decl * try_get_by_prefix(func_decl* prefix, unsigned idx) const - { - func_decl * prim = try_get_primary_by_prefix(prefix); - if(!prim) { - return nullptr; - } - return conv(prim, 0, idx); - } - - /** - Create a multiplexed tuple of propositional constants. - Symbols may be suplied in the tuple vector, - those beyond the size of the array and those with corresponding positions - assigned to zero will be created using prefix. - Tuple length must be at least one. - */ - void create_tuple(func_decl* prefix, unsigned arity, sort * const * domain, sort * range, - unsigned tuple_length, decl_vector & tuple); - - /** - Return true if the only multiplexed symbols which e contains are of index idx. + \brief Return true if the only multiplexed symbols which e contains are + of index idx. */ bool is_homogenous_formula(expr * e, unsigned idx) const; /** - Convert symbol sym which has to be of src_idx variant into variant tgt_idx. + \brief Convert symbol sym which has to be of src_idx variant + into variant tgt_idx. */ - func_decl * conv(func_decl * sym, unsigned src_idx, unsigned tgt_idx) const; - + func_decl * shift_decl(func_decl * sym, unsigned src_idx, unsigned tgt_idx) const; /** - Convert src_idx symbols in formula f variant into tgt_idx. - If homogenous is true, formula cannot contain symbols of other variants. + \brief Convert src_idx symbols in formula f variant into + tgt_idx. If homogenous is true, formula cannot contain symbols + of other variants. */ - void conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, - expr_ref & res, bool homogenous = true) const; + void shift_expr(expr * f, unsigned src_idx, unsigned tgt_idx, + expr_ref & res, bool homogenous = true) const; }; From dd064bd8f9f7aa656a24f6f25f213c7b5c492e9c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 3 Jun 2018 16:32:06 -0700 Subject: [PATCH 1121/1283] Bug fix to spacer::sym_mux --- src/muz/spacer/spacer_sym_mux.cpp | 5 +++-- src/muz/spacer/spacer_sym_mux.h | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/muz/spacer/spacer_sym_mux.cpp b/src/muz/spacer/spacer_sym_mux.cpp index 5dfb3a531..cfe0908d6 100644 --- a/src/muz/spacer/spacer_sym_mux.cpp +++ b/src/muz/spacer/spacer_sym_mux.cpp @@ -57,7 +57,7 @@ void sym_mux::register_decl(func_decl *fdecl) { m_muxes.insert(entry->m_variants.get(0), std::make_pair(entry, 0)); m_muxes.insert(entry->m_variants.get(1), std::make_pair(entry, 1)); } -void sym_mux::ensure_capacity(sym_mux_entry &entry, unsigned sz) { +void sym_mux::ensure_capacity(sym_mux_entry &entry, unsigned sz) const { while (entry.m_variants.size() < sz) { unsigned idx = entry.m_variants.size(); entry.m_variants.push_back (mk_variant(entry.m_main, idx)); @@ -71,7 +71,7 @@ bool sym_mux::find_idx(func_decl * sym, unsigned & idx) const { return false; } -func_decl * sym_mux::find_by_decl(func_decl* fdecl, unsigned idx) { +func_decl * sym_mux::find_by_decl(func_decl* fdecl, unsigned idx) const { sym_mux_entry *entry = nullptr; if (m_entries.find(fdecl, entry)) { ensure_capacity(*entry, idx+1); @@ -85,6 +85,7 @@ func_decl * sym_mux::shift_decl(func_decl * decl, std::pair entry; if (m_muxes.find(decl, entry)) { SASSERT(entry.second == src_idx); + ensure_capacity(*entry.first, tgt_idx + 1); return entry.first->m_variants.get(tgt_idx); } UNREACHABLE(); diff --git a/src/muz/spacer/spacer_sym_mux.h b/src/muz/spacer/spacer_sym_mux.h index 9657b47d9..5690370bd 100644 --- a/src/muz/spacer/spacer_sym_mux.h +++ b/src/muz/spacer/spacer_sym_mux.h @@ -42,11 +42,11 @@ private: typedef obj_map > mux2entry_map; ast_manager &m; - decl2entry_map m_entries; - mux2entry_map m_muxes; + mutable decl2entry_map m_entries; + mutable mux2entry_map m_muxes; func_decl_ref mk_variant(func_decl *fdecl, unsigned i) const; - void ensure_capacity(sym_mux_entry &entry, unsigned sz) ; + void ensure_capacity(sym_mux_entry &entry, unsigned sz) const; public: sym_mux(ast_manager & m); @@ -58,12 +58,13 @@ public: bool has_index(func_decl * sym, unsigned idx) const {unsigned v; return find_idx(sym, v) && idx == v;} + bool is_muxed(func_decl *fdecl) const {return m_muxes.contains(fdecl);} /** \brief Return symbol created from prefix, or 0 if the prefix was never used. */ - func_decl * find_by_decl(func_decl* fdecl, unsigned idx); + func_decl * find_by_decl(func_decl* fdecl, unsigned idx) const; /** \brief Return true if the only multiplexed symbols which e contains are From 4ca734528e91bae092675f50fd87d788331661db Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:24:47 -0700 Subject: [PATCH 1122/1283] Formatting --- src/muz/spacer/spacer_util.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 3eaeb098e..ebcbb9145 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -923,11 +923,10 @@ class implicant_picker { } void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, - expr_ref_vector &res) - { + expr_ref_vector &res) { // XXX what is the point of flattening? flatten_and (formula); - if (formula.empty()) { return; } + if (formula.empty()) { return; } implicant_picker ipick (mev); ipick (formula, res); From 6b82068d8deaf560354c7419a21ed9c3133be3c7 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:26:03 -0700 Subject: [PATCH 1123/1283] Bug fix in spacer::derivation::exist_skolemize --- src/muz/spacer/spacer_context.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index bbedbc391..511df2383 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -203,7 +203,23 @@ void derivation::exist_skolemize(expr* fml, app_ref_vector &vars, expr_ref &res) if (vars.empty()) {res = fml; return;} if (m.is_true(fml) || m.is_false(fml)) {res = fml; return;} - std::sort (vars.c_ptr(), vars.c_ptr() + vars.size(), sk_lt_proc()); + { + std::stable_sort (vars.c_ptr(), vars.c_ptr() + vars.size(), sk_lt_proc()); + unsigned i, j, end; + app_ref v(m); + for (i = 1, j = 1, end = vars.size(); i < end; ++i) { + if (vars.get(j-1) != vars.get(i)) { + v = vars.get(i); // keep ref + vars.set(j++, v); + } + } + vars.shrink(j); + } + + TRACE("spacer", tout << "Skolemizing: "; + for (auto v : vars) tout << " " << mk_pp(v, m) << " "; + tout << "\nfrom " << mk_pp(fml, m) << "\n"; + ); app_ref_vector pinned(m); From b61da6fcc041cce5eff4fe40a0bcae5a9f0c10bd Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:29:18 -0700 Subject: [PATCH 1124/1283] Debug print in org-mode format --- src/muz/spacer/spacer_context.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 511df2383..1268dbede 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -911,17 +911,12 @@ void pred_transformer::add_lemma_core(lemma* lemma, bool ground_only) << " " << mk_pp (l, m) << "\n";); STRACE ("spacer.expand-add", - tout << "add-lemma: " << pp_level (lvl) << " " + tout << "** add-lemma: " << pp_level (lvl) << " " << head ()->get_name () << " " << mk_epp (l, m) << "\n"; if (!lemma->is_ground()) { - expr_ref_vector inst(m); - lemma->mk_insts(inst); - for (unsigned i = 0, sz = inst.size(); i < sz; ++i) { - tout << mk_epp(inst.get(i), m) << "\n"; - } - + tout << "Bindings: " << lemma->get_bindings() << "\n"; } tout << "\n"; ); @@ -965,8 +960,6 @@ void pred_transformer::add_lemma_from_child (pred_transformer& child, lemma->mk_insts(inst, l); // -- take ground instance of the current lemma ground_expr(to_quantifier(l)->get_expr(), grnd_lemma, tmp); - STRACE("spacer.expand-add", - tout << "Adding instance: " << mk_epp(grnd_lemma, m) << "\n";); inst.push_back(grnd_lemma); } for (unsigned j=0; j < inst.size(); j++) { @@ -3239,7 +3232,7 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) << mk_pp(n.post(), m) << "\n";); STRACE ("spacer.expand-add", - tout << "expand-pob: " << n.pt().head()->get_name() + tout << "** expand-pob: " << n.pt().head()->get_name() << " level: " << n.level() << " depth: " << (n.depth () - m_pob_queue.min_depth ()) << "\n" << mk_epp(n.post(), m) << "\n\n";); From d7dc10212e8532c69c783a5138420e250f6f3a3e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:32:59 -0700 Subject: [PATCH 1125/1283] Clean up spacer::context::create_children --- src/muz/spacer/spacer_context.cpp | 83 ++++++++++++------------------- 1 file changed, 31 insertions(+), 52 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 1268dbede..aaa379771 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -3612,93 +3612,71 @@ bool context::create_children(pob& n, datalog::rule const& r, scoped_watch _w_ (m_create_children_watch); pred_transformer& pt = n.pt(); - expr* const T = pt.get_transition(r); - expr* const phi = n.post(); TRACE("spacer", tout << "Model:\n"; model_smt2_pp(tout, m, *mev.get_model (), 0); tout << "\n"; - tout << "Transition:\n" << mk_pp(T, m) << "\n"; - tout << "Phi:\n" << mk_pp(phi, m) << "\n";); + tout << "Transition:\n" << mk_pp(pt.get_transition(r), m) << "\n"; + tout << "Pob:\n" << mk_pp(n.post(), m) << "\n";); SASSERT (r.get_uninterpreted_tail_size () > 0); ptr_vector preds; pt.find_predecessors(r, preds); - ptr_vector pred_pts; - - for (ptr_vector::iterator it = preds.begin (); - it != preds.end (); it++) { - pred_pts.push_back (&get_pred_transformer (*it)); - } - - expr_ref_vector forms(m), Phi(m); // obtain all formulas to consider for model generalization - forms.push_back(T); - forms.push_back(phi); + expr_ref_vector forms(m), lits(m); + forms.push_back(pt.get_transition(r)); + forms.push_back(n.post()); - compute_implicant_literals (mev, forms, Phi); - - //pt.remove_predecessors (Phi); + compute_implicant_literals (mev, forms, lits); + expr_ref phi = mk_and (lits); + // primed variables of the head app_ref_vector vars(m); - unsigned sig_size = pt.head()->get_arity(); - for (unsigned i = 0; i < sig_size; ++i) { + for (unsigned i = 0, sz = pt.head()->get_arity(); i < sz; ++i) { vars.push_back(m.mk_const(m_pm.o2n(pt.sig(i), 0))); } + // local variables of the rule ptr_vector& aux_vars = pt.get_aux_vars(r); vars.append(aux_vars.size(), aux_vars.c_ptr()); n.get_skolems(vars); + n.get_skolems(vars); + // skolems of the pob - expr_ref phi1 = mk_and (Phi); - n.pt().mbp(vars, phi1, mev.get_model (), true, use_ground_cti()); + n.pt().mbp(vars, phi, mev.get_model (), true, use_ground_cti()); //qe::reduce_array_selects (*mev.get_model (), phi1); SASSERT (!m_ground_cti || vars.empty ()); TRACE ("spacer", - tout << "Implicant\n"; - tout << mk_and (Phi) << "\n"; - tout << "Projected Implicant\n" << mk_pp (phi1, m) << "\n"; + tout << "Implicant:\n"; + tout << lits << "\n"; + tout << "After MBP:\n" << phi << "\n"; if (!vars.empty()) - tout << "could not eliminate: " << vars << "\n"; + tout << "Failed to eliminate: " << vars << "\n"; ); - // expand literals. Ideally, we do not want to split aliasing - // equalities. Unfortunately, the interface does not allow for - // that yet. - // XXX This mixes up with derivation. Needs more thought. - // Phi.reset (); - // flatten_and (phi1, Phi); - // if (!Phi.empty ()) - // { - // expand_literals (m, Phi); - // phi1 = m_pm.mk_and (Phi); - // } + derivation *deriv = alloc(derivation, n, r, phi, vars); - - derivation *deriv = alloc (derivation, n, r, phi1, vars); + // pick an order to process children + unsigned_vector kid_order; + kid_order.resize(preds.size(), 0); + for (unsigned i = 0, sz = preds.size(); i < sz; ++i) kid_order[i] = i; + if (get_params().spacer_order_children() == 1) kid_order.reverse(); for (unsigned i = 0, sz = preds.size(); i < sz; ++i) { - unsigned j; - if (get_params ().spacer_order_children () == 1) - // -- reverse order - { j = sz - i - 1; } - else - // -- default order - { j = i; } + unsigned j = kid_order[i]; - pred_transformer &pt = get_pred_transformer (preds [j]); + + pred_transformer &pt = get_pred_transformer(preds.get(j)); const ptr_vector *aux = nullptr; expr_ref sum(m); - // XXX This is a bit confusing. The summary is returned over - // XXX o-variables. But it is simpler if it is returned over n-variables instead. - sum = pt.get_origin_summary (mev, prev_level (n.level ()), - j, reach_pred_used [j], &aux); - deriv->add_premise (pt, j, sum, reach_pred_used [j], aux); + sum = pt.get_origin_summary (mev, prev_level(n.level()), + j, reach_pred_used[j], &aux); + deriv->add_premise (pt, j, sum, reach_pred_used[j], aux); } // create post for the first child and add to queue @@ -3719,7 +3697,8 @@ bool context::create_children(pob& n, datalog::rule const& r, // -- not satisfy 'T && phi'. It is possible to recover from // -- that more gracefully. For now, we just remove the // -- derivation completely forcing it to be recomputed - if (m_weak_abs && (!mev.is_true(T) || !mev.is_true(phi))) + if (m_weak_abs && (!mev.is_true(pt.get_transition(r)) || + !mev.is_true(n.post()))) { kid->reset_derivation(); } out.push_back(kid); From c5ff5ac2a13ae58eaedae6732e9902be7130ebb8 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:33:36 -0700 Subject: [PATCH 1126/1283] Clen up spacer::pred_transformer::get_origin_summary --- src/muz/spacer/spacer_context.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index aaa379771..adcb8c8ae 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1142,7 +1142,7 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, expr_ref v(m); if (!must) { // use may summary - summary.push_back (get_formulas (level)); + summary.push_back (get_formulas(level)); // -- no auxiliary variables in lemmas *aux = nullptr; } else { // find must summary to use @@ -1160,10 +1160,10 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, } // -- pick an implicant - expr_ref_vector literals (m); - compute_implicant_literals (mev, summary, literals); + expr_ref_vector lits(m); + compute_implicant_literals (mev, summary, lits); - return mk_and(literals); + return mk_and(lits); } From da66ad6f80c6726e05e9060e0bc6fd33fdca1af8 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:34:14 -0700 Subject: [PATCH 1127/1283] Cleanup derivation::create_next_child --- src/muz/spacer/spacer_context.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index adcb8c8ae..5512f14f0 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -191,8 +191,7 @@ void derivation::add_premise (pred_transformer &pt, -pob *derivation::create_first_child (model_evaluator_util &mev) -{ +pob *derivation::create_first_child (model_evaluator_util &mev) { if (m_premises.empty()) { return nullptr; } m_active = 0; return create_next_child(mev); @@ -262,9 +261,8 @@ pob *derivation::create_next_child (model_evaluator_util &mev) verbose_stream ()); pt().mbp(vars, m_trans, mev.get_model(), true, pt().get_context().use_ground_cti()); - //qe::reduce_array_selects (*mev.get_model (), m_trans); - // remember variables that need to be existentially quantified m_evars.append (vars); + vars.reset(); } if (!mev.is_true (m_premises[m_active].get_summary())) { @@ -273,28 +271,28 @@ pob *derivation::create_next_child (model_evaluator_util &mev) } - // create the post condition by compute post-image over summaries + // create the post-condition by computing a post-image over summaries // that precede currently active premise - vars.reset (); for (unsigned i = m_active + 1; i < m_premises.size(); ++i) { summaries.push_back (m_premises [i].get_summary ()); vars.append (m_premises [i].get_ovars ()); } summaries.push_back (m_trans); - expr_ref post(m); - post = mk_and (summaries); + post = mk_and(summaries); summaries.reset (); + if (!vars.empty()) { - timeit _timer2 (is_trace_enabled("spacer_timeit"), - "create_next_child::qproject2", - verbose_stream ()); + timeit _timer2(is_trace_enabled("spacer_timeit"), + "create_next_child::qproject2", + verbose_stream ()); pt().mbp(vars, post, mev.get_model(), true, pt().get_context().use_ground_cti()); //qe::reduce_array_selects (*mev.get_model (), post); // remember variables that need to be existentially quantified - m_evars.append (vars); + m_evars.append(vars); + vars.reset(); } if (!m_evars.empty()) { @@ -649,6 +647,7 @@ void lemma::mk_insts(expr_ref_vector &out, expr* e) } + // ---------------- // pred_tansformer @@ -3633,8 +3632,8 @@ bool context::create_children(pob& n, datalog::rule const& r, compute_implicant_literals (mev, forms, lits); expr_ref phi = mk_and (lits); - // primed variables of the head + // primed variables of the head app_ref_vector vars(m); for (unsigned i = 0, sz = pt.head()->get_arity(); i < sz; ++i) { vars.push_back(m.mk_const(m_pm.o2n(pt.sig(i), 0))); @@ -3643,9 +3642,8 @@ bool context::create_children(pob& n, datalog::rule const& r, ptr_vector& aux_vars = pt.get_aux_vars(r); vars.append(aux_vars.size(), aux_vars.c_ptr()); - n.get_skolems(vars); - n.get_skolems(vars); // skolems of the pob + n.get_skolems(vars); n.pt().mbp(vars, phi, mev.get_model (), true, use_ground_cti()); //qe::reduce_array_selects (*mev.get_model (), phi1); @@ -3666,10 +3664,10 @@ bool context::create_children(pob& n, datalog::rule const& r, kid_order.resize(preds.size(), 0); for (unsigned i = 0, sz = preds.size(); i < sz; ++i) kid_order[i] = i; if (get_params().spacer_order_children() == 1) kid_order.reverse(); + for (unsigned i = 0, sz = preds.size(); i < sz; ++i) { unsigned j = kid_order[i]; - pred_transformer &pt = get_pred_transformer(preds.get(j)); const ptr_vector *aux = nullptr; From 6fb6279f07488b2b77bf77d68bc4a76dbbd6d0db Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 11:56:45 -0700 Subject: [PATCH 1128/1283] Cleanup array_eq_generalizer --- src/muz/spacer/spacer_generalizers.cpp | 118 +++++++++++++------------ src/muz/spacer/spacer_generalizers.h | 2 + 2 files changed, 64 insertions(+), 56 deletions(-) diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 7263f8264..d7c7429ee 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -21,6 +21,7 @@ Revision History: #include "muz/spacer/spacer_context.h" #include "muz/spacer/spacer_generalizers.h" +#include "ast/ast_util.h" #include "ast/expr_abstract.h" #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" @@ -205,103 +206,108 @@ public: }; } +bool lemma_array_eq_generalizer::is_array_eq (ast_manager &m, expr* e) { + + expr *e1 = nullptr, *e2 = nullptr; + if (m.is_eq(e, e1, e2) && is_app(e1) && is_app(e2)) { + app *a1 = to_app(e1); + app *a2 = to_app(e2); + array_util au(m); + if (a1->get_family_id() == null_family_id && + a2->get_family_id() == null_family_id && + au.is_array(a1) && au.is_array(a2)) + return true; + } + return false; +} + void lemma_array_eq_generalizer::operator() (lemma_ref &lemma) { - TRACE("core_array_eq", tout << "Looking for equalities\n";); - // -- find array constants ast_manager &m = lemma->get_ast_manager(); - manager &pm = m_ctx.get_manager(); - (void)pm; - unsigned weakness = lemma->weakness(); expr_ref_vector core(m); expr_ref v(m); func_decl_set symb; collect_array_proc cap(m, symb); + + // -- find array constants core.append (lemma->get_cube()); v = mk_and(core); for_each_expr(cap, v); - TRACE("core_array_eq", + CTRACE("core_array_eq", symb.size() > 1 && symb.size() <= 8, tout << "found " << symb.size() << " array variables in: \n" - << mk_pp(v, m) << "\n";); + << v << "\n";); - // too few constants - if (symb.size() <= 1) { return; } - // too many constants, skip this - if (symb.size() >= 8) { return; } + // too few constants or too many constants + if (symb.size() <= 1 || symb.size() > 8) { return; } - // -- for every pair of variables, try an equality - typedef func_decl_set::iterator iterator; + // -- for every pair of constants (A, B), check whether the + // -- equality (A=B) generalizes a literal in the lemma + ptr_vector vsymbs; - for (iterator it = symb.begin(), end = symb.end(); - it != end; ++it) - { vsymbs.push_back(*it); } + for (auto * fdecl : symb) {vsymbs.push_back(fdecl);} + // create all equalities expr_ref_vector eqs(m); + for (unsigned i = 0, sz = vsymbs.size(); i < sz; ++i) { + for (unsigned j = i + 1; j < sz; ++j) { + eqs.push_back(m.mk_eq(m.mk_const(vsymbs.get(i)), + m.mk_const(vsymbs.get(j)))); + } + } - for (unsigned i = 0, sz = vsymbs.size(); i < sz; ++i) - for (unsigned j = i + 1; j < sz; ++j) - { eqs.push_back(m.mk_eq(m.mk_const(vsymbs.get(i)), - m.mk_const(vsymbs.get(j)))); } - + // smt-solver to check whether a literal is generalized. using + // default params. There has to be a simpler way to approximate + // this check ref sol = mk_smt_solver(m, params_ref::get_empty(), symbol::null); + // literals of the new lemma expr_ref_vector lits(m); - for (unsigned i = 0, core_sz = core.size(); i < core_sz; ++i) { - SASSERT(lits.size() == i); - sol->push(); - sol->assert_expr(core.get(i)); - for (unsigned j = 0, eqs_sz = eqs.size(); j < eqs_sz; ++j) { - sol->push(); - sol->assert_expr(eqs.get(j)); + lits.append(core); + expr *t = nullptr; + bool dirty = false; + for (unsigned i = 0, sz = core.size(); i < sz; ++i) { + // skip a literal is it is already an array equality + if (m.is_not(lits.get(i), t) && is_array_eq(m, t)) continue; + solver::scoped_push _pp_(*sol); + sol->assert_expr(lits.get(i)); + for (auto *e : eqs) { + solver::scoped_push _p_(*sol); + sol->assert_expr(e); lbool res = sol->check_sat(0, nullptr); - sol->pop(1); if (res == l_false) { TRACE("core_array_eq", - tout << "strengthened " << mk_pp(core.get(i), m) - << " with " << mk_pp(m.mk_not(eqs.get(j)), m) << "\n";); - lits.push_back(m.mk_not(eqs.get(j))); + tout << "strengthened " << mk_pp(lits.get(i), m) + << " with " << mk_pp(mk_not(m, e), m) << "\n";); + lits[i] = mk_not(m, e); + dirty = true; break; } } - sol->pop(1); - if (lits.size() == i) { lits.push_back(core.get(i)); } } - /** - HACK: if the first 3 arguments of pt are boolean, assume - they correspond to SeaHorn encoding and condition the equality on them. - */ - // pred_transformer &pt = n.pt (); - // if (pt.sig_size () >= 3 && - // m.is_bool (pt.sig (0)->get_range ()) && - // m.is_bool (pt.sig (1)->get_range ()) && - // m.is_bool (pt.sig (2)->get_range ())) - // { - // lits.push_back (m.mk_const (pm.o2n(pt.sig (0), 0))); - // lits.push_back (m.mk_not (m.mk_const (pm.o2n(pt.sig (1), 0)))); - // lits.push_back (m.mk_not (m.mk_const (pm.o2n(pt.sig (2), 0)))); - // } + // nothing changed + if (!dirty) return; - TRACE("core_array_eq", tout << "new possible core " - << mk_and(lits) << "\n";); + TRACE("core_array_eq", + tout << "new possible core " << mk_and(lits) << "\n";); pred_transformer &pt = lemma->get_pob()->pt(); - // -- check if it is consistent with the transition relation + // -- check if the generalized result is consistent with trans unsigned uses_level1; - if (pt.check_inductive(lemma->level(), lits, uses_level1, weakness)) { + if (pt.check_inductive(lemma->level(), lits, uses_level1, lemma->weakness())) { TRACE("core_array_eq", tout << "Inductive!\n";); - lemma->update_cube(lemma->get_pob(),lits); + lemma->update_cube(lemma->get_pob(), lits); lemma->set_level(uses_level1); - return; - } else - { TRACE("core_array_eq", tout << "Not-Inductive!\n";);} + } + else + {TRACE("core_array_eq", tout << "Not-Inductive!\n";);} } void lemma_eq_generalizer::operator() (lemma_ref &lemma) diff --git a/src/muz/spacer/spacer_generalizers.h b/src/muz/spacer/spacer_generalizers.h index 518b09f6c..45ae472bd 100644 --- a/src/muz/spacer/spacer_generalizers.h +++ b/src/muz/spacer/spacer_generalizers.h @@ -83,6 +83,8 @@ public: }; class lemma_array_eq_generalizer : public lemma_generalizer { +private: + bool is_array_eq(ast_manager &m, expr *e); public: lemma_array_eq_generalizer(context &ctx) : lemma_generalizer(ctx) {} ~lemma_array_eq_generalizer() override {} From 7396ad72abd2fc70e1200b6e7c6e442b4c5efe75 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:21:03 -0700 Subject: [PATCH 1129/1283] Give up when a lemma is re-discovered too many times --- src/muz/spacer/spacer_context.cpp | 30 ++++++++++++++++++++---------- src/muz/spacer/spacer_context.h | 4 ++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 5512f14f0..a36f2476f 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -453,7 +453,7 @@ lemma::lemma (ast_manager &manager, expr * body, unsigned lvl) : m_ref_count(0), m(manager), m_body(body, m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(lvl), m_init_lvl(m_lvl), - m_pob(nullptr), m_ctp(nullptr), m_external(false) { + m_pob(nullptr), m_ctp(nullptr), m_external(false), m_bumped(0) { SASSERT(m_body); normalize(m_body, m_body); } @@ -462,7 +462,7 @@ lemma::lemma(pob_ref const &p) : m_ref_count(0), m(p->get_ast_manager()), m_body(m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(p->level()), m_init_lvl(m_lvl), - m_pob(p), m_ctp(nullptr), m_external(false) { + m_pob(p), m_ctp(nullptr), m_external(false), m_bumped(0) { SASSERT(m_pob); m_pob->get_skolems(m_zks); add_binding(m_pob->get_binding()); @@ -473,7 +473,7 @@ lemma::lemma(pob_ref const &p, expr_ref_vector &cube, unsigned lvl) : m(p->get_ast_manager()), m_body(m), m_cube(m), m_zks(m), m_bindings(m), m_lvl(p->level()), m_init_lvl(m_lvl), - m_pob(p), m_ctp(nullptr), m_external(false) + m_pob(p), m_ctp(nullptr), m_external(false), m_bumped(0) { if (m_pob) { m_pob->get_skolems(m_zks); @@ -1955,6 +1955,16 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) if (!new_lemma->get_bindings().empty()) { m_pt.add_lemma_core(old_lemma, true); } + if(is_infty_level(old_lemma->level())) { + old_lemma->bump(); + if (old_lemma->get_bumped() >= 100) { + IF_VERBOSE(1, verbose_stream() << "Adding lemma to oo " + << old_lemma->get_bumped() << " " + << mk_pp(old_lemma->get_expr(), + m_pt.get_ast_manager()) << "\n";); + throw default_exception("Stuck on a lemma"); + } + } // no new lemma added return false; } @@ -1962,13 +1972,6 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) // update level of the existing lemma old_lemma->set_level(new_lemma->level()); // assert lemma in the solver - m_pt.add_lemma_core(old_lemma, false); - // move the lemma to its new place to maintain sortedness - unsigned sz = m_lemmas.size(); - for (unsigned j = i; - (j + 1) < sz && m_lt(m_lemmas[j + 1], m_lemmas[j]); ++j) { - m_lemmas.swap (j, j+1); - } return true; } i++; @@ -1976,6 +1979,13 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) // new_lemma is really new m_lemmas.push_back(new_lemma); + m_pt.add_lemma_core(old_lemma, false); + // move the lemma to its new place to maintain sortedness + unsigned sz = m_lemmas.size(); + for (unsigned j = i; + (j + 1) < sz && m_lt(m_lemmas[j + 1], m_lemmas[j]); ++j) { + m_lemmas.swap (j, j+1); + } // XXX because m_lemmas is reduced, keep secondary vector of all lemmas // XXX so that pob can refer to its lemmas without creating reference cycles m_pinned_lemmas.push_back(new_lemma); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 120953e97..e9881b3ff 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -125,6 +125,7 @@ class lemma { pob_ref m_pob; model_ref m_ctp; // counter-example to pushing bool m_external; + unsigned m_bumped; void mk_expr_core(); void mk_cube_core(); @@ -141,6 +142,9 @@ public: void set_ctp(model_ref &v) {m_ctp = v;} void reset_ctp() {m_ctp.reset();} + void bump() {m_bumped++;} + unsigned get_bumped() {return m_bumped;} + expr *get_expr(); bool is_false(); expr_ref_vector const &get_cube(); From 5756871738485a70d689effd898ae2e4a442ee93 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:22:51 -0700 Subject: [PATCH 1130/1283] Always attempt to eliminate all existential variables Sometimes variables that cannot be eliminated in one context, can be eliminated in the other. Pass all available variables to MBP to be eliminated if possible --- src/muz/spacer/spacer_context.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index a36f2476f..e32c065aa 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -240,7 +240,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) ast_manager &m = get_ast_manager (); expr_ref_vector summaries (m); - app_ref_vector vars (m); + app_ref_vector vars(m); // -- find first may premise while (m_active < m_premises.size() && m_premises[m_active].is_must()) { @@ -259,6 +259,8 @@ pob *derivation::create_next_child (model_evaluator_util &mev) timeit _timer1 (is_trace_enabled("spacer_timeit"), "create_next_child::qproject1", verbose_stream ()); + vars.append(m_evars); + m_evars.reset(); pt().mbp(vars, m_trans, mev.get_model(), true, pt().get_context().use_ground_cti()); m_evars.append (vars); @@ -286,6 +288,8 @@ pob *derivation::create_next_child (model_evaluator_util &mev) timeit _timer2(is_trace_enabled("spacer_timeit"), "create_next_child::qproject2", verbose_stream ()); + vars.append(m_evars); + m_evars.reset(); pt().mbp(vars, post, mev.get_model(), true, pt().get_context().use_ground_cti()); //qe::reduce_array_selects (*mev.get_model (), post); @@ -386,10 +390,13 @@ pob *derivation::create_next_child () { vars.push_back(m.mk_const(pm.o2n(pt.sig(i), 0))); } if (!vars.empty ()) { + vars.append(m_evars); + m_evars.reset(); this->pt().mbp(vars, m_trans, mev.get_model(), true, this->pt().get_context().use_ground_cti()); // keep track of implicitly quantified variables m_evars.append (vars); + vars.reset(); } } @@ -1972,13 +1979,6 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) // update level of the existing lemma old_lemma->set_level(new_lemma->level()); // assert lemma in the solver - return true; - } - i++; - } - - // new_lemma is really new - m_lemmas.push_back(new_lemma); m_pt.add_lemma_core(old_lemma, false); // move the lemma to its new place to maintain sortedness unsigned sz = m_lemmas.size(); @@ -1986,6 +1986,13 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) (j + 1) < sz && m_lt(m_lemmas[j + 1], m_lemmas[j]); ++j) { m_lemmas.swap (j, j+1); } + return true; + } + i++; + } + + // new_lemma is really new + m_lemmas.push_back(new_lemma); // XXX because m_lemmas is reduced, keep secondary vector of all lemmas // XXX so that pob can refer to its lemmas without creating reference cycles m_pinned_lemmas.push_back(new_lemma); From 3178f7f86d0f7ebb75a4badc797aa554199e7da0 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 12:53:45 -0700 Subject: [PATCH 1131/1283] Add random order of children in spacer --- src/muz/spacer/spacer_context.cpp | 10 +++++++++- src/muz/spacer/spacer_context.h | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index e32c065aa..7d9e6e5be 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2241,6 +2241,9 @@ context::context(fixedpoint_params const& params, m_pool0 = alloc(solver_pool, pool0_base.get(), max_num_contexts); m_pool1 = alloc(solver_pool, pool1_base.get(), max_num_contexts); m_pool2 = alloc(solver_pool, pool2_base.get(), max_num_contexts); + + m_random.set_seed(m_params.spacer_random_seed()); + m_children_order = static_cast(m_params.spacer_order_children()); } context::~context() @@ -3680,7 +3683,12 @@ bool context::create_children(pob& n, datalog::rule const& r, unsigned_vector kid_order; kid_order.resize(preds.size(), 0); for (unsigned i = 0, sz = preds.size(); i < sz; ++i) kid_order[i] = i; - if (get_params().spacer_order_children() == 1) kid_order.reverse(); + if (m_children_order == CO_REV_RULE) { + kid_order.reverse(); + } + else if (m_children_order == CO_RANDOM) { + shuffle(kid_order.size(), kid_order.c_ptr(), m_random); + } for (unsigned i = 0, sz = preds.size(); i < sz; ++i) { unsigned j = kid_order[i]; diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index e9881b3ff..ccdac2c48 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -782,6 +782,12 @@ public: }; +// order in which children are processed +enum spacer_children_order { + CO_RULE, // same order as in the rule + CO_REV_RULE, // reverse order of the rule + CO_RANDOM // random shuffle +}; class context { @@ -819,6 +825,8 @@ class context { scoped_ptr m_pool2; + random_gen m_random; + spacer_children_order m_children_order; decl2rel m_rels; // Map from relation predicate to fp-operator. func_decl_ref m_query_pred; pred_transformer* m_query; From fee7828b511722e8d7a7c8748e8a74add1fa8530 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jun 2018 14:23:46 -0700 Subject: [PATCH 1132/1283] fix solve bug Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 100 +++++++++++++++++---------- src/math/simplex/model_based_opt.h | 4 ++ 2 files changed, 68 insertions(+), 36 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index f12918bfe..86b3cfa0c 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -175,8 +175,7 @@ namespace opt { rational new_x_val; rational x_coeff, eps(0); vector const& vars = r.m_vars; - for (unsigned j = 0; j < vars.size(); ++j) { - var const& v = vars[j]; + for (var const& v : vars) { if (x == v.m_id) { x_coeff = v.m_coeff; } @@ -227,8 +226,7 @@ namespace opt { --i; unsigned x = bound_vars[i]; unsigned_vector const& row_ids = m_var2row_ids[x]; - for (unsigned j = 0; j < row_ids.size(); ++j) { - unsigned row_id = row_ids[j]; + for (unsigned row_id : row_ids) { row & r = m_rows[row_id]; r.m_value = get_row_value(r); SASSERT(invariant(row_id, r)); @@ -368,7 +366,7 @@ namespace opt { tout << a1 << " " << a2 << ": "; display(tout, m_rows[row_dst]); display(tout, m_rows[row_src]);); - if (a1.is_pos() != a2.is_pos()) { + if (a1.is_pos() != a2.is_pos() || m_rows[row_src].m_type == opt::t_eq) { mul_add(x, a1, row_src, a2, row_dst); } else { @@ -384,6 +382,18 @@ namespace opt { } } + void model_based_opt::solve(unsigned row_src, rational const& a1, unsigned row_dst, unsigned x) { + SASSERT(a1 == get_coefficient(row_src, x)); + SASSERT(a1.is_pos()); + SASSERT(row_src != row_dst); + SASSERT(m_rows[row_src].m_type == t_eq); + if (!m_rows[row_dst].m_alive) return; + rational a2 = get_coefficient(row_dst, x); + mul(row_dst, a1); + mul_add(false, row_dst, -a2, row_src); + SASSERT(get_coefficient(row_dst, x).is_zero()); + } + // resolution for integer rows. void model_based_opt::mul_add( unsigned x, rational const& src_c, unsigned row_src, rational const& dst_c, unsigned row_dst) { @@ -457,8 +467,8 @@ namespace opt { } void model_based_opt::mk_coeffs_without(vector& dst, vector const src, unsigned x) { - for (unsigned i = 0; i < src.size(); ++i) { - if (src[i].m_id != x) dst.push_back(src[i]); + for (var const & v : src) { + if (v.m_id != x) dst.push_back(v); } } @@ -469,8 +479,8 @@ namespace opt { void model_based_opt::mul(unsigned dst, rational const& c) { if (c.is_one()) return; row& r = m_rows[dst]; - for (unsigned i = 0; i < r.m_vars.size(); ++i) { - r.m_vars[i].m_coeff *= c; + for (auto & v : r.m_vars) { + v.m_coeff *= c; } r.m_coeff *= c; r.m_value *= c; @@ -674,8 +684,8 @@ namespace opt { unsigned dst = new_row(); row const& r = m_rows[src]; set_row(dst, r.m_vars, r.m_coeff, r.m_mod, r.m_type); - for (unsigned i = 0; i < r.m_vars.size(); ++i) { - m_var2row_ids[r.m_vars[i].m_id].push_back(dst); + for (auto const& v : r.m_vars) { + m_var2row_ids[v.m_id].push_back(dst); } SASSERT(invariant(dst, m_rows[dst])); return dst; @@ -692,8 +702,8 @@ namespace opt { void model_based_opt::add_constraint(vector const& coeffs, rational const& c, rational const& m, ineq_type rel) { unsigned row_id = new_row(); set_row(row_id, coeffs, c, m, rel); - for (unsigned i = 0; i < coeffs.size(); ++i) { - m_var2row_ids[coeffs[i].m_id].push_back(row_id); + for (var const& coeff : coeffs) { + m_var2row_ids[coeff.m_id].push_back(row_id); } SASSERT(invariant(row_id, m_rows[row_id])); } @@ -703,9 +713,9 @@ namespace opt { } void model_based_opt::get_live_rows(vector& rows) { - for (unsigned i = 0; i < m_rows.size(); ++i) { - if (m_rows[i].m_alive) { - rows.push_back(m_rows[i]); + for (row const& r : m_rows) { + if (r.m_alive) { + rows.push_back(r); } } } @@ -742,9 +752,9 @@ namespace opt { glb_rows.reset(); mod_rows.reset(); bool lub_is_unit = false, glb_is_unit = false; + unsigned eq_row = UINT_MAX; // select the lub and glb. - for (unsigned i = 0; i < row_ids.size(); ++i) { - unsigned row_id = row_ids[i]; + for (unsigned row_id : row_ids) { if (visited.contains(row_id)) { continue; } @@ -758,8 +768,8 @@ namespace opt { continue; } if (r.m_type == t_eq) { - solve_for(row_id, x); - return; + eq_row = row_id; + continue; } if (r.m_type == t_mod) { mod_rows.push_back(row_id); @@ -795,6 +805,11 @@ namespace opt { solve_mod(x, mod_rows); return; } + + if (eq_row != UINT_MAX) { + solve_for(eq_row, x); + return; + } unsigned lub_size = lub_rows.size(); unsigned glb_size = glb_rows.size(); @@ -803,8 +818,7 @@ namespace opt { // There are only upper or only lower bounds. if (row_index == UINT_MAX) { - for (unsigned i = 0; i < glb_rows.size(); ++i) { - unsigned row_id = glb_rows[i]; + for (unsigned row_id : glb_rows) { SASSERT(m_rows[row_id].m_alive); SASSERT(!get_coefficient(row_id, x).is_zero()); retire_row(row_id); @@ -839,8 +853,7 @@ namespace opt { // General case. rational coeff = get_coefficient(row_index, x); - for (unsigned i = 0; i < glb_rows.size(); ++i) { - unsigned row_id = glb_rows[i]; + for (unsigned row_id : glb_rows) { if (row_id != row_index) { resolve(row_index, coeff, row_id, x); } @@ -866,8 +879,8 @@ namespace opt { void model_based_opt::solve_mod(unsigned x, unsigned_vector const& mod_rows) { SASSERT(!mod_rows.empty()); rational D(1); - for (unsigned i = 0; i < mod_rows.size(); ++i) { - D = lcm(D, m_rows[mod_rows[i]].m_mod); + for (unsigned idx : mod_rows) { + D = lcm(D, m_rows[idx].m_mod); } if (D.is_zero()) { throw default_exception("modulo 0 is not defined"); @@ -876,9 +889,9 @@ namespace opt { rational val_x = m_var2value[x]; rational u = mod(val_x, D); SASSERT(u.is_nonneg() && u < D); - for (unsigned i = 0; i < mod_rows.size(); ++i) { - replace_var(mod_rows[i], x, u); - SASSERT(invariant(mod_rows[i], m_rows[mod_rows[i]])); + for (unsigned idx : mod_rows) { + replace_var(idx, x, u); + SASSERT(invariant(idx, m_rows[idx])); } // // update inequalities such that u is added to t and @@ -894,8 +907,7 @@ namespace opt { unsigned y = add_var(new_val, true); unsigned_vector const& row_ids = m_var2row_ids[x]; uint_set visited; - for (unsigned i = 0; i < row_ids.size(); ++i) { - unsigned row_id = row_ids[i]; + for (unsigned row_id : row_ids) { if (!visited.contains(row_id)) { // x |-> D*y + u replace_var(row_id, x, D, y, u); @@ -954,23 +966,39 @@ namespace opt { SASSERT(!a.is_zero()); SASSERT(m_rows[row_id1].m_type == t_eq); SASSERT(m_rows[row_id1].m_alive); - if (m_var2is_int[x] && !abs(a).is_one()) { + if (a.is_neg()) { + a.neg(); + m_rows[row_id1].neg(); + } + SASSERT(a.is_pos()); + if (m_var2is_int[x] && !a.is_one()) { row& r1 = m_rows[row_id1]; vector coeffs; mk_coeffs_without(coeffs, r1.m_vars, x); rational c = r1.m_coeff; - add_divides(coeffs, c, abs(a)); + add_divides(coeffs, c, a); } unsigned_vector const& row_ids = m_var2row_ids[x]; uint_set visited; visited.insert(row_id1); - for (unsigned i = 0; i < row_ids.size(); ++i) { - unsigned row_id2 = row_ids[i]; + for (unsigned row_id2 : row_ids) { if (!visited.contains(row_id2)) { visited.insert(row_id2); + b = get_coefficient(row_id2, x); if (!b.is_zero()) { - resolve(row_id1, a, row_id2, x); + row& dst = m_rows[row_id2]; + switch (dst.m_type) { + case t_eq: + case t_lt: + case t_le: + solve(row_id1, a, row_id2, x); + break; + case t_mod: + // mod reduction already done. + UNREACHABLE(); + break; + } } } } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index 54360d0ac..9546529f2 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -58,6 +58,8 @@ namespace opt { rational m_value; // value of m_vars + m_coeff under interpretation of m_var2value. bool m_alive; // rows can be marked dead if they have been processed. void reset() { m_vars.reset(); m_coeff.reset(); m_value.reset(); } + + void neg() { for (var & v : m_vars) v.m_coeff.neg(); m_coeff.neg(); m_value.neg(); } }; private: @@ -85,6 +87,8 @@ namespace opt { void resolve(unsigned row_src, rational const& a1, unsigned row_dst, unsigned x); + void solve(unsigned row_src, rational const& a1, unsigned row_dst, unsigned x); + void mul_add(bool same_sign, unsigned row_id1, rational const& c, unsigned row_id2); void mul_add(unsigned x, rational const& a1, unsigned row_src, rational const& a2, unsigned row_dst); From 2a243d38d10e721aca05f1a329572785208f04a5 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 15:10:57 -0700 Subject: [PATCH 1133/1283] Model based Cartesian decomposition --- src/muz/spacer/CMakeLists.txt | 1 + src/muz/spacer/spacer_mbc.cpp | 101 ++++++++++++++++++++++++++++++++++ src/muz/spacer/spacer_mbc.h | 45 +++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 src/muz/spacer/spacer_mbc.cpp create mode 100644 src/muz/spacer/spacer_mbc.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 68464a40d..162216055 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -25,6 +25,7 @@ z3_add_component(spacer spacer_callback.cpp spacer_json.cpp spacer_iuc_proof.cpp + spacer_mbc.cpp COMPONENT_DEPENDENCIES arith_tactics core_tactics diff --git a/src/muz/spacer/spacer_mbc.cpp b/src/muz/spacer/spacer_mbc.cpp new file mode 100644 index 000000000..d002998b3 --- /dev/null +++ b/src/muz/spacer/spacer_mbc.cpp @@ -0,0 +1,101 @@ +#include + +#include "muz/spacer/spacer_mbc.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/scoped_proof.h" +#include "model/model_evaluator.h" + + +namespace spacer { + +mbc::mbc(ast_manager &m) : m(m) {} + +namespace { +class mbc_rewriter_cfg : public default_rewriter_cfg { + + ast_manager &m; + const mbc::partition_map &m_pmap; + model &m_mdl; + model_evaluator m_mev; + vector &m_parts; + unsigned m_current_part; + + obj_map m_subs; +public: + mbc_rewriter_cfg(ast_manager &m, const mbc::partition_map &pmap, + model &mdl, vector &parts) : + m(m), m_pmap(pmap), m_mdl(mdl), m_mev(m_mdl), + m_parts(parts), m_current_part(UINT_MAX) + {m_mev.set_model_completion(true);} + + br_status reduce_app(func_decl *f, unsigned num, expr * const * args, + expr_ref &result, proof_ref & result_pr) { + unsigned part = UINT_MAX; + // not a constant + if (num != 0) return BR_FAILED; + // not in partition map + if (!m_pmap.find(f, part)) return BR_FAILED; + + // first part element, remember it + if (!found_partition()) { + set_partition(part); + return BR_FAILED; + } + + // decide value based on model + expr_ref e(m), val(m); + e = m.mk_app(f, num, args); + + // already in our substitution map + expr *t = nullptr; + if (m_subs.find(e, t)) { + result = t; + return BR_DONE; + } + + // eval in the model + m_mev.eval(e, val, true); + + // store decided equality + m_parts[part].push_back(m.mk_eq(e, val)); + // store substitution + m_subs.insert(e, val); + + result = val; + return BR_DONE; + } + + bool get_subst(expr * s, expr * & t, proof * & t_pr) { + return m_subs.find(s, t); + } + + void reset_partition() {m_current_part = UINT_MAX;} + unsigned partition() {return m_current_part;} + bool found_partition() {return m_current_part < UINT_MAX;} + void set_partition(unsigned v) {m_current_part = v;} +}; +} + +void mbc::operator()(const partition_map &pmap, expr_ref_vector &lits, + model &mdl, vector &res) { + scoped_no_proof _sp (m); + + mbc_rewriter_cfg cfg(m, pmap, mdl, res); + rewriter_tpl rw(m, false, cfg); + th_rewriter thrw(m); + + for (auto *lit : lits) { + expr_ref new_lit(m); + cfg.reset_partition(); + rw(lit, new_lit); + thrw(new_lit); + if (cfg.found_partition()) { + SASSERT(cfg.partition() < res.size()); + res[cfg.partition()].push_back(new_lit); + } + } +} + +} diff --git a/src/muz/spacer/spacer_mbc.h b/src/muz/spacer/spacer_mbc.h new file mode 100644 index 000000000..5dbf50f6d --- /dev/null +++ b/src/muz/spacer/spacer_mbc.h @@ -0,0 +1,45 @@ +/*++ +Copyright (c) 2018 Arie Gurfinkel + +Module Name: + + spacer_mbc.h + +Abstract: + + Model-Based Cartesian Decomposition + +Author: + + Arie Gurfinkel + +Revision History: + +--*/ + +#ifndef _SPACER_MBC_H_ +#define _SPACER_MBC_H_ + +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "model/model.h" + +namespace spacer { + +class mbc { + ast_manager &m; +public: + mbc(ast_manager &m); + + + typedef obj_map partition_map; + + /** + \Brief Model Based Cartesian projection of lits + */ + void operator()(const partition_map &pmap, expr_ref_vector &lits, model &mdl, + vector &res); +}; + +} +#endif From e860e4d0454874844c0ca4734c785bc661cd7039 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 15:54:05 -0700 Subject: [PATCH 1134/1283] Bug fix for quantified pob generation --- src/muz/spacer/spacer_context.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 7d9e6e5be..6e9f0db39 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -288,24 +288,26 @@ pob *derivation::create_next_child (model_evaluator_util &mev) timeit _timer2(is_trace_enabled("spacer_timeit"), "create_next_child::qproject2", verbose_stream ()); + // include m_evars in case they can eliminated now as well vars.append(m_evars); - m_evars.reset(); pt().mbp(vars, post, mev.get_model(), true, pt().get_context().use_ground_cti()); //qe::reduce_array_selects (*mev.get_model (), post); - - // remember variables that need to be existentially quantified - m_evars.append(vars); - vars.reset(); + } + else { + // if no variables to eliminate, don't forget about m_evars + // that occur in m_trans + vars.append(m_evars); } - if (!m_evars.empty()) { - // existentially quantify out m_evars from post and skolemize the result - exist_skolemize(post.get(), m_evars, post); + if (!vars.empty()) { + // existentially quantify out vars from post and skolemize the result + exist_skolemize(post.get(), vars, post); } get_manager ().formula_o2n (post.get (), post, - m_premises [m_active].get_oidx (), m_evars.empty()); + m_premises [m_active].get_oidx (), + vars.empty()); /* The level and depth are taken from the parent, not the sibling. @@ -313,7 +315,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) and lower level is a better starting point. */ pob *n = m_premises[m_active].pt().mk_pob(&m_parent, prev_level (m_parent.level ()), - m_parent.depth (), post, m_evars); + m_parent.depth (), post, vars); IF_VERBOSE (1, verbose_stream () << "\n\tcreate_child: " << n->pt ().head ()->get_name () << " (" << n->level () << ", " << n->depth () << ") " From 478d7c790e333b2aed5e2a264d2e4b5075a10baa Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 4 Jun 2018 16:11:27 -0700 Subject: [PATCH 1135/1283] mbc: moved code under get_subst() --- src/muz/spacer/spacer_mbc.cpp | 45 +++++++++++++++-------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/muz/spacer/spacer_mbc.cpp b/src/muz/spacer/spacer_mbc.cpp index d002998b3..4708a6a4e 100644 --- a/src/muz/spacer/spacer_mbc.cpp +++ b/src/muz/spacer/spacer_mbc.cpp @@ -30,45 +30,38 @@ public: m_parts(parts), m_current_part(UINT_MAX) {m_mev.set_model_completion(true);} - br_status reduce_app(func_decl *f, unsigned num, expr * const * args, - expr_ref &result, proof_ref & result_pr) { + bool get_subst(expr *s, expr * & t, proof * & t_pr) { + if (!is_app(s)) return false; unsigned part = UINT_MAX; - // not a constant - if (num != 0) return BR_FAILED; + // not in partition map - if (!m_pmap.find(f, part)) return BR_FAILED; + if (!m_pmap.find (to_app(s)->get_decl(), part)) return false; // first part element, remember it if (!found_partition()) { set_partition(part); - return BR_FAILED; + return false; + } + + // already in our substitution map + expr *tmp = nullptr; + if (m_subs.find(s, tmp)) { + t = tmp; + return true; } // decide value based on model - expr_ref e(m), val(m); - e = m.mk_app(f, num, args); - - // already in our substitution map - expr *t = nullptr; - if (m_subs.find(e, t)) { - result = t; - return BR_DONE; - } + expr_ref val(m); // eval in the model - m_mev.eval(e, val, true); + m_mev.eval(s, val, true); - // store decided equality - m_parts[part].push_back(m.mk_eq(e, val)); + // store decided equality (also keeps ref to s and val + m_parts[part].push_back(m.mk_eq(s, val)); // store substitution - m_subs.insert(e, val); - - result = val; - return BR_DONE; - } - - bool get_subst(expr * s, expr * & t, proof * & t_pr) { - return m_subs.find(s, t); + m_subs.insert(s, val); + t = val; + return true; } void reset_partition() {m_current_part = UINT_MAX;} From ece2e53c98c9434bbfd6a892db0b537f49e26443 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 12:00:13 -0700 Subject: [PATCH 1136/1283] Ported model_search and model_node from pdr into spacer --- src/muz/spacer/CMakeLists.txt | 1 + src/muz/spacer/spacer_pdr.cpp | 221 ++++++++++++++++++++++++++++++++++ src/muz/spacer/spacer_pdr.h | 107 ++++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 src/muz/spacer/spacer_pdr.cpp create mode 100644 src/muz/spacer/spacer_pdr.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 162216055..8e41d5ae7 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -26,6 +26,7 @@ z3_add_component(spacer spacer_json.cpp spacer_iuc_proof.cpp spacer_mbc.cpp + spacer_pdr.cpp COMPONENT_DEPENDENCIES arith_tactics core_tactics diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp new file mode 100644 index 000000000..ce3f53963 --- /dev/null +++ b/src/muz/spacer/spacer_pdr.cpp @@ -0,0 +1,221 @@ +/**++ +Copyright (c) 2018 Arie Gurfinkel + +Module Name: + + spacer_pdr.h + +Abstract: + + SPACER gPDR strategy implementation + +Author: + + Arie Gurfinkel + + Based on muz/pdr + +Notes: + +--*/ +#include "muz/spacer/spacer_pdr.h" + +namespace spacer { +model_node::model_node(model_node* parent, pob_ref &pob): + m_pob(pob), m_parent(parent), m_next(nullptr), m_prev(nullptr), + m_orig_level(m_pob->level()), m_depth(0), + m_closed(false) { + SASSERT(m_pob); + if (m_parent) m_parent->add_child(*this); +} + +void model_node::add_child(model_node &kid) { + m_children.push_back(this); + SASSERT(level() == kid.level() + 1); + SASSERT(level() > 0); + kid.m_depth = m_depth + 1; + if (is_closed()) set_open(); +} + +unsigned model_node::index_in_parent() const { + if (!m_parent) return 0; + for (unsigned i = 0, sz = m_parent->children().size(); i < sz; ++i) { + if (this == m_parent->children().get(i)) return i; + } + UNREACHABLE(); + return 0; +} + +void model_node::check_pre_closed() { + for (auto *kid : m_children) {if (kid->is_open()) return;} + + set_pre_closed(); + model_node* p = m_parent; + while (p && p->is_1closed()) { + p->set_pre_closed(); + p = p->parent(); + } +} +void model_node::set_open() { + SASSERT(m_closed); + m_closed = false; + model_node* p = parent(); + while (p && p->is_closed()) { + p->m_closed = false; + p = p->parent(); + } +} + +void model_node::detach(model_node*& qhead) { + if (!in_queue()) return; + SASSERT(children().empty()); + if (this == m_next) { + SASSERT(m_prev == this); + SASSERT(this == qhead); + qhead = nullptr; + } + else { + m_next->m_prev = m_prev; + m_prev->m_next = m_next; + if (this == qhead) qhead = m_next; + } + + // detach + m_prev = nullptr; + m_next = nullptr; +} + + +// insert node n after this in the queue +// requires: this is in a queue or this == n +void model_node::insert_after(model_node* n) { + SASSERT(!in_queue()); + if (this == n) { + m_next = n; + m_prev = n; + } + else { + n->m_next = m_next; + m_next->m_prev = n; + m_next = n; + n->m_prev = this; + } +} + +void model_search::reset() { + m_cache.reset(); + if (m_root) { + erase_children(*m_root, false); + remove_node(*m_root, false); + dealloc(m_root); + m_root = nullptr; + } +} + +model_node* model_search::pop_front() { + if (!m_qhead) return nullptr; + model_node *res = m_qhead; + res->detach(m_qhead); + return res; +} + +void model_search::add_leaf(model_node& n) { + SASSERT(n.children().empty()); + model_nodes ns; + model_nodes& nodes = cache(n).insert_if_not_there2(n.post(), ns)->get_data().m_value; + if (nodes.contains(&n)) return; + + nodes.push_back(&n); + if (nodes.size() == 1) { + SASSERT(n.is_open()); + enqueue_leaf(n); + } + else n.set_pre_closed(); +} + +void model_search::enqueue_leaf(model_node& n) { + SASSERT(n.is_open()); + // queue is empty, initialize it with n + if (!m_qhead) { + m_qhead = &n; + m_qhead->insert_after(m_qhead); + } + // insert n after m_qhead + else if (m_bfs) { + m_qhead->insert_after(&n); + } + // insert n after m_qhead()->next() + else { + m_qhead->next()->insert_after(&n); + } +} + + + +void model_search::set_root(model_node* root) { + reset(); + m_root = root; + SASSERT(m_root); + SASSERT(m_root->children().empty()); + SASSERT(cache(*root).empty()); + // XXX Don't get why 1 is legal here + cache(*root).insert(root->post(), 1); + enqueue_leaf(*root); +} + +void model_search::backtrack_level(bool uses_level, model_node& n) { + SASSERT(m_root); + if (uses_level) {NOT_IMPLEMENTED_YET();} + if (uses_level && m_root->level() > n.level()) { + n.increase_level(); + enqueue_leaf(n); + } + else { + model_node* p = n.parent(); + if (p) { + erase_children(*p, true); + enqueue_leaf(*p); + } + } +} + +obj_map >& model_search::cache(model_node const& n) { + unsigned l = n.orig_level(); + if (l >= m_cache.size()) m_cache.resize(l + 1); + return m_cache[l]; +} + +void model_search::erase_children(model_node& n, bool backtrack) { + ptr_vector todo, nodes; + todo.append(n.children()); + // detach n from queue + n.detach(m_qhead); + n.reset(); + while (!todo.empty()) { + model_node* m = todo.back(); + todo.pop_back(); + nodes.push_back(m); + todo.append(m->children()); + remove_node(*m, backtrack); + } + std::for_each(nodes.begin(), nodes.end(), delete_proc()); +} + +// removes node from the search tree and from the cache +void model_search::remove_node(model_node& n, bool backtrack) { + model_nodes& nodes = cache(n).find(n.post()); + nodes.erase(&n); + n.detach(m_qhead); + // TBD: siblings would also fail if n is not a goal. + if (!nodes.empty() && backtrack && + nodes[0]->children().empty() && nodes[0]->is_closed()) { + model_node* n1 = nodes[0]; + n1->set_open(); + enqueue_leaf(*n1); + } + + if (nodes.empty()) cache(n).remove(n.post()); +} + + +} diff --git a/src/muz/spacer/spacer_pdr.h b/src/muz/spacer/spacer_pdr.h new file mode 100644 index 000000000..dd62230bd --- /dev/null +++ b/src/muz/spacer/spacer_pdr.h @@ -0,0 +1,107 @@ +/**++ +Copyright (c) 2018 Arie Gurfinkel + +Module Name: + + spacer_pdr.h + +Abstract: + + SPACER gPDR strategy implementation + +Author: + + Arie Gurfinkel + + Based on muz/pdr + +Notes: + +--*/ +#ifndef _SPACER_PDR_H_ +#define _SPACER_PDR_H_ + +#include "muz/spacer/spacer_context.h" + +namespace spacer { +// structure for counter-example search. +class model_node { + pob_ref m_pob; // proof obligation + model_node* m_parent; // parent in the search tree + ptr_vector m_children; // children in the search tree + model_node* m_next; // next element of an in-place circular queue + model_node* m_prev; // prev element of an in-place circular queue + unsigned m_orig_level; // level at which this search node was created + unsigned m_depth; // + bool m_closed; // whether the pob is derivable +public: + model_node(model_node* parent, pob_ref &pob); + void add_child(model_node &kid); + + expr *post() const {return m_pob->post();} + unsigned level() const { return m_pob->level(); } + unsigned orig_level() const { return m_orig_level; } + unsigned depth() const { return m_depth; } + void increase_level() { m_pob->inc_level(); } + const pob_ref &pob() const { return m_pob; } + ptr_vector const& children() { return m_children; } + pred_transformer& pt() const { return m_pob->pt(); } + model_node* parent() const { return m_parent; } + // order in children of the parent + unsigned index_in_parent() const; + + bool is_closed() const { return m_closed; } + bool is_open() const { return !is_closed(); } + + // closed or has children and they are all closed + bool is_1closed() { + if (is_closed()) return true; + if (m_children.empty()) return false; + for (auto kid : m_children) {if (kid->is_open()) return false;} + return true; + } + + void check_pre_closed(); + void set_pre_closed() {m_closed = true;} + + void set_closed() {m_closed = true;} + void set_open(); + void reset() {m_children.reset();} + + /// queue + + // remove this node from the given queue + void detach(model_node*& qhead); + void insert_after(model_node* n); + model_node* next() const {return m_next;} + bool in_queue() {return m_next && m_prev;} +}; + +class model_search { + typedef ptr_vector model_nodes; + bool m_bfs; + model_node* m_root; + model_node* m_qhead; + vector > m_cache; + obj_map& cache(model_node const& n); + void erase_children(model_node& n, bool backtrack); + void remove_node(model_node& n, bool backtrack); + void add_leaf(model_node* n); // add leaf to priority queue. + +public: + model_search(bool bfs): m_bfs(bfs), m_root(nullptr), m_qhead(nullptr) {} + ~model_search() {reset();} + + void set_root(model_node* n); + + void reset(); + model_node* pop_front(); + void add_leaf(model_node& n); // add fresh node. + model_node& get_root() const { return *m_root; } + void backtrack_level(bool uses_level, model_node& n); + void remove_goal(model_node& n); + + void enqueue_leaf(model_node &n); +}; +} +#endif From ab5f579d0b41c9192208d5a8f89c8c2efd31e017 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 16:12:12 -0700 Subject: [PATCH 1137/1283] Comments in pdr_context.cpp --- src/muz/pdr/pdr_context.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index c2cd94ee0..1b1350617 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -210,7 +210,7 @@ namespace pdr { void pred_transformer::simplify_formulas() { tactic_ref us = mk_unit_subsumption_tactic(m); simplify_formulas(*us, m_invariants); - for (auto & fmls : m_levels) + for (auto & fmls : m_levels) simplify_formulas(*us, fmls); } @@ -876,6 +876,7 @@ namespace pdr { return out; } + // return order of this node in the children of its parent unsigned model_node::index() const { model_node* p = parent(); if (!p) return 0; @@ -886,7 +887,8 @@ namespace pdr { return 0; } - + // detach this node from a queue with the head root + // requires: root is a head of a queue void model_node::dequeue(model_node*& root) { TRACE("pdr", tout << this << " root: " << root << " " << state() << "\n";); if (!m_next && !m_prev) return; @@ -912,6 +914,8 @@ namespace pdr { } + // insert node n after this in the queue + // requires: this is in a queue or this == n void model_node::enqueue(model_node* n) { TRACE("pdr", tout << n << " " << n->state() << "\n";); SASSERT(!n->m_next); @@ -963,6 +967,7 @@ namespace pdr { } void model_search::set_leaf(model_node& n) { + // remove all children that n might have erase_children(n, true); SASSERT(n.is_open()); enqueue_leaf(&n); @@ -971,13 +976,16 @@ namespace pdr { void model_search::enqueue_leaf(model_node* n) { TRACE("pdr_verbose", tout << "node: " << n << " " << n->state() << " goal: " << m_goal << "\n";); SASSERT(n->is_open()); + // queue is empty, initialize it with n if (!m_goal) { m_goal = n; m_goal->enqueue(n); } + // insert n after m_goal else if (m_bfs) { m_goal->enqueue(n); } + // insert n after m_goal()->next() else { m_goal->next()->enqueue(n); } @@ -1002,7 +1010,9 @@ namespace pdr { void model_search::erase_children(model_node& n, bool backtrack) { ptr_vector todo, nodes; todo.append(n.children()); + // detach n from queue remove_goal(n); + // removes children n.reset(); while (!todo.empty()) { model_node* m = todo.back(); @@ -1014,10 +1024,12 @@ namespace pdr { std::for_each(nodes.begin(), nodes.end(), delete_proc()); } + // removes node from the search tree and from the cache void model_search::remove_node(model_node& n, bool backtrack) { TRACE("pdr_verbose", tout << "remove: " << n.level() << ": " << &n << " " << n.state() << "\n";); model_nodes& nodes = cache(n).find(n.state()); nodes.erase(&n); + // detach n from m_goals remove_goal(n); // TBD: siblings would also fail if n is not a goal. if (!nodes.empty() && backtrack && nodes[0]->children().empty() && nodes[0]->is_closed()) { @@ -1036,6 +1048,7 @@ namespace pdr { } } + // detach node n from the queue m_goal void model_search::remove_goal(model_node& n) { n.dequeue(m_goal); } @@ -1913,7 +1926,7 @@ namespace pdr { verbose_stream() << ex.to_string(); }); - // upgrade invariants that are known to be inductive. + // upgrade invariants that are known to be inductive. decl2rel::iterator it = m_rels.begin (), end = m_rels.end (); for (; m_inductive_lvl > 0 && it != end; ++it) { if (it->m_value->head() != m_query_pred) { From 521392a8f15ec4b19f273d63fb3a9ca09d9841e1 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 16:12:45 -0700 Subject: [PATCH 1138/1283] First partially working pdr strategy in spacer --- src/muz/base/fixedpoint_params.pyg | 1 + src/muz/spacer/spacer_context.cpp | 13 +++-- src/muz/spacer/spacer_context.h | 6 +++ src/muz/spacer/spacer_pdr.cpp | 86 ++++++++++++++++++++++++++---- src/muz/spacer/spacer_pdr.h | 6 +-- 5 files changed, 95 insertions(+), 17 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 69050ed71..b5231c27b 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -203,4 +203,5 @@ def_module_params('fixedpoint', ('spacer.use_inc_clause', BOOL, False, 'Use incremental clause to represent trans'), ('spacer.dump_benchmarks', BOOL, False, 'Dump SMT queries as benchmarks'), ('spacer.dump_threshold', DOUBLE, 5.0, 'Threshold in seconds on dumping benchmarks'), + ('spacer.gpdr', BOOL, False, 'Use GPDR solving strategy for non-linear CHC'), )) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 6e9f0db39..3f3433cc6 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2591,7 +2591,14 @@ lbool context::solve(unsigned from_lvl) { m_last_result = l_undef; try { - m_last_result = solve_core (from_lvl); + if (m_params.spacer_gpdr()) { + SASSERT(from_lvl == 0); + m_last_result = gpdr_solve_core(); + } + else { + m_last_result = solve_core (from_lvl); + } + if (m_last_result == l_false) { simplify_formulas(); m_last_result = l_false; @@ -2967,7 +2974,7 @@ lbool context::solve_core (unsigned from_lvl) unsigned max_level = get_params ().spacer_max_level (); - for (unsigned i = 0; i < max_level; ++i) { + for (unsigned i = from_lvl; i < max_level; ++i) { checkpoint(); m_expanded_lvl = infty_level (); m_stats.m_max_query_lvl = lvl; @@ -3244,6 +3251,7 @@ void context::predecessor_eh() /// out contains new pobs to add to the queue in case the result is l_undef lbool context::expand_pob(pob& n, pob_ref_buffer &out) { + SASSERT(out.empty()); pob::on_expand_event _evt(n); TRACE ("spacer", tout << "expand-pob: " << n.pt().head()->get_name() @@ -3630,7 +3638,6 @@ bool context::create_children(pob& n, datalog::rule const& r, const vector &reach_pred_used, pob_ref_buffer &out) { - scoped_watch _w_ (m_create_children_watch); pred_transformer& pt = n.pt(); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index ccdac2c48..bb3ad007d 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -42,6 +42,8 @@ namespace datalog { namespace spacer { +class model_search; + class pred_transformer; class derivation; class pob_queue; @@ -848,6 +850,10 @@ class context { scoped_ptr_vector m_callbacks; json_marshaller m_json_marshaller; + // Solve using gpdr strategy + lbool gpdr_solve_core(); + bool gpdr_check_reachability(unsigned lvl, model_search &ms); + // Functions used by search. lbool solve_core(unsigned from_lvl = 0); bool is_requeue(pob &n); diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index ce3f53963..e46907493 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -19,9 +19,10 @@ Notes: --*/ #include "muz/spacer/spacer_pdr.h" +#include "muz/base/dl_context.h" namespace spacer { -model_node::model_node(model_node* parent, pob_ref &pob): +model_node::model_node(model_node* parent, class pob *pob): m_pob(pob), m_parent(parent), m_next(nullptr), m_prev(nullptr), m_orig_level(m_pob->level()), m_depth(0), m_closed(false) { @@ -30,7 +31,7 @@ model_node::model_node(model_node* parent, pob_ref &pob): } void model_node::add_child(model_node &kid) { - m_children.push_back(this); + m_children.push_back(&kid); SASSERT(level() == kid.level() + 1); SASSERT(level() > 0); kid.m_depth = m_depth + 1; @@ -67,7 +68,7 @@ void model_node::set_open() { } void model_node::detach(model_node*& qhead) { - if (!in_queue()) return; + SASSERT(in_queue()); SASSERT(children().empty()); if (this == m_next) { SASSERT(m_prev == this); @@ -103,13 +104,13 @@ void model_node::insert_after(model_node* n) { } void model_search::reset() { - m_cache.reset(); if (m_root) { erase_children(*m_root, false); remove_node(*m_root, false); dealloc(m_root); m_root = nullptr; } + m_cache.reset(); } model_node* model_search::pop_front() { @@ -135,6 +136,7 @@ void model_search::add_leaf(model_node& n) { void model_search::enqueue_leaf(model_node& n) { SASSERT(n.is_open()); + SASSERT(!n.in_queue()); // queue is empty, initialize it with n if (!m_qhead) { m_qhead = &n; @@ -157,10 +159,7 @@ void model_search::set_root(model_node* root) { m_root = root; SASSERT(m_root); SASSERT(m_root->children().empty()); - SASSERT(cache(*root).empty()); - // XXX Don't get why 1 is legal here - cache(*root).insert(root->post(), 1); - enqueue_leaf(*root); + add_leaf(*root); } void model_search::backtrack_level(bool uses_level, model_node& n) { @@ -189,8 +188,8 @@ void model_search::erase_children(model_node& n, bool backtrack) { ptr_vector todo, nodes; todo.append(n.children()); // detach n from queue - n.detach(m_qhead); - n.reset(); + if (n.in_queue()) n.detach(m_qhead); + n.reset_children(); while (!todo.empty()) { model_node* m = todo.back(); todo.pop_back(); @@ -205,7 +204,7 @@ void model_search::erase_children(model_node& n, bool backtrack) { void model_search::remove_node(model_node& n, bool backtrack) { model_nodes& nodes = cache(n).find(n.post()); nodes.erase(&n); - n.detach(m_qhead); + if (n.in_queue()) n.detach(m_qhead); // TBD: siblings would also fail if n is not a goal. if (!nodes.empty() && backtrack && nodes[0]->children().empty() && nodes[0]->is_closed()) { @@ -218,4 +217,69 @@ void model_search::remove_node(model_node& n, bool backtrack) { } +lbool context::gpdr_solve_core() { + scoped_watch _w_(m_solve_watch); + //if there is no query predicate, abort + if (!m_rels.find(m_query_pred, m_query)) { return l_false; } + + model_search ms(true); + unsigned lvl = 0; + unsigned max_level = get_params ().spacer_max_level (); + for (lvl = 0; lvl < max_level; ++lvl) { + checkpoint(); + IF_VERBOSE(1,verbose_stream() << "GPDR Entering level "<< lvl << "\n";); + STRACE("spacer.expand-add", tout << "\n* LEVEL " << lvl << "\n";); + m_expanded_lvl = infty_level(); + m_stats.m_max_query_lvl = lvl; + if (gpdr_check_reachability(lvl, ms)) {return l_true;} + if (lvl > 0) { + if (propagate(m_expanded_lvl, lvl, UINT_MAX)) {return l_false;} + } + } + + // communicate failure to datalog::context + if (m_context) { m_context->set_status(datalog::BOUNDED); } + return l_undef; + } + +bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) { + pob_ref root_pob = m_query->mk_pob(nullptr, lvl, 0, m.mk_true()); + model_node *root_node = alloc(model_node, nullptr, root_pob.get()); + + ms.set_root(root_node); + pob_ref_buffer new_pobs; + + while (model_node *node = ms.pop_front()) { + IF_VERBOSE(2, verbose_stream() << "Expand node: " + << node->level() << "\n";); + new_pobs.reset(); + checkpoint(); + switch (expand_pob(*node->pob(), new_pobs)){ + case l_true: + node->set_closed(); + if (node == root_node) return true; + break; + case l_false: + ms.backtrack_level(false, *node); + if (node == root_node) return false; + break; + case l_undef: + SASSERT(!new_pobs.empty()); + for (auto pob : new_pobs) { + TRACE("spacer_pdr", + tout << "looking at pob at level " << pob->level() << " " + << mk_pp(pob->post(), m) << "\n";); + if (pob == node->pob()) {continue;} + model_node *kid = alloc(model_node, node, pob); + ms.add_leaf(*kid); + } + node->check_pre_closed(); + break; + } + } + + return root_node->is_closed(); +} + +} // spacer diff --git a/src/muz/spacer/spacer_pdr.h b/src/muz/spacer/spacer_pdr.h index dd62230bd..56900a1e8 100644 --- a/src/muz/spacer/spacer_pdr.h +++ b/src/muz/spacer/spacer_pdr.h @@ -35,7 +35,7 @@ class model_node { unsigned m_depth; // bool m_closed; // whether the pob is derivable public: - model_node(model_node* parent, pob_ref &pob); + model_node(model_node* parent, pob* pob); void add_child(model_node &kid); expr *post() const {return m_pob->post();} @@ -43,7 +43,7 @@ public: unsigned orig_level() const { return m_orig_level; } unsigned depth() const { return m_depth; } void increase_level() { m_pob->inc_level(); } - const pob_ref &pob() const { return m_pob; } + pob_ref &pob() { return m_pob; } ptr_vector const& children() { return m_children; } pred_transformer& pt() const { return m_pob->pt(); } model_node* parent() const { return m_parent; } @@ -66,7 +66,7 @@ public: void set_closed() {m_closed = true;} void set_open(); - void reset() {m_children.reset();} + void reset_children() {m_children.reset();} /// queue From cb683389f66852dabd449a234d49b67de7023d6a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 16:20:55 -0700 Subject: [PATCH 1139/1283] spacer::context: Factor params into udpt_params --- src/muz/spacer/spacer_context.cpp | 8 ++++++-- src/muz/spacer/spacer_context.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 3f3433cc6..8806afb6a 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2244,8 +2244,7 @@ context::context(fixedpoint_params const& params, m_pool1 = alloc(solver_pool, pool1_base.get(), max_num_contexts); m_pool2 = alloc(solver_pool, pool2_base.get(), max_num_contexts); - m_random.set_seed(m_params.spacer_random_seed()); - m_children_order = static_cast(m_params.spacer_order_children()); + updt_params() } context::~context() @@ -2254,6 +2253,11 @@ context::~context() reset(); } +void context::updt_params() { + m_random.set_seed(m_params.spacer_random_seed()); + m_children_order = static_cast(m_params.spacer_order_children()); +} + void context::reset() { TRACE("spacer", tout << "\n";); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index bb3ad007d..e00d479f7 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -897,6 +897,7 @@ class context { void predecessor_eh(); + void updt_params(); public: /** Initial values of predicates are stored in corresponding relations in dctx. @@ -905,6 +906,7 @@ public: context(fixedpoint_params const& params, ast_manager& m); ~context(); + const fixedpoint_params &get_params() const { return m_params; } bool use_native_mbp () {return m_use_native_mbp;} bool use_ground_cti () {return m_ground_cti;} From 8b689ae27fd90afebc123a9d3abf71724b60fdbc Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 17:11:19 -0700 Subject: [PATCH 1140/1283] Moved is_int_expr into arith_recognizers --- src/ast/arith_decl_plugin.cpp | 31 ++- src/ast/arith_decl_plugin.h | 3 +- src/smt/theory_arith_core.h | 469 ++++++++++++++++------------------ 3 files changed, 253 insertions(+), 250 deletions(-) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index 688edbcd5..fe5bc3af5 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -81,7 +81,7 @@ app * arith_decl_plugin::mk_numeral(algebraic_numbers::anum const & val, bool is return mk_numeral(rval, is_int); } else { - if (is_int) { + if (is_int) { m_manager->raise_exception("invalid irrational value passed as an integer"); } unsigned idx = aw().mk_id(val); @@ -638,6 +638,35 @@ bool arith_recognizers::is_numeral(expr const * n, rational & val, bool & is_int return true; } +#define IS_INT_EXPR_DEPTH_LIMIT 100 +bool arith_recognizers::is_int_expr(expr const *e) const { + if (is_int(e)) return true; + if (is_uninterp(e)) return false; + ptr_buffer todo; + todo.push_back(e); + rational r; + unsigned i = 0; + while (!todo.empty()) { + ++i; + if (i > IS_INT_EXPR_DEPTH_LIMIT) {return false;} + e = todo.back(); + todo.pop_back(); + if (is_to_real(e)) { + // pass + } + else if (is_numeral(e, r) && r.is_int()) { + // pass + } + else if (is_add(e) || is_mul(e)) { + todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + } + else { + return false; + } + } + return true; +} + arith_util::arith_util(ast_manager & m): arith_recognizers(m.mk_family_id("arith")), m_manager(m), diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 6cebdaded..d7340297b 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -244,6 +244,8 @@ public: return false; } + bool is_int_expr(expr const * e) const; + bool is_le(expr const * n) const { return is_app_of(n, m_afid, OP_LE); } bool is_ge(expr const * n) const { return is_app_of(n, m_afid, OP_GE); } bool is_lt(expr const * n) const { return is_app_of(n, m_afid, OP_LT); } @@ -533,4 +535,3 @@ inline app_ref operator>(app_ref const& x, app_ref const& y) { } #endif /* ARITH_DECL_PLUGIN_H_ */ - diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 46388fcf4..af761eecf 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -27,7 +27,7 @@ Revision History: #include "ast/ast_smt2_pp.h" namespace smt { - + template void theory_arith::found_unsupported_op(app * n) { if (!m_found_unsupported_op) { @@ -69,33 +69,7 @@ namespace smt { #if 0 return m_util.is_int(e); #else - if (m_util.is_int(e)) return true; - if (is_uninterp(e)) return false; - m_todo.reset(); - m_todo.push_back(e); - rational r; - unsigned i = 0; - while (!m_todo.empty()) { - ++i; - if (i > 100) { - return false; - } - e = m_todo.back(); - m_todo.pop_back(); - if (m_util.is_to_real(e)) { - // pass - } - else if (m_util.is_numeral(e, r) && r.is_int()) { - // pass - } - else if (m_util.is_add(e) || m_util.is_mul(e)) { - m_todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); - } - else { - return false; - } - } - return true; + return m_util.is_int_expr(e); #endif } @@ -133,7 +107,7 @@ namespace smt { m_nl_monomials.push_back(r); SASSERT(check_vector_sizes()); SASSERT(m_var_occs[r].empty()); - TRACE("mk_arith_var", + TRACE("mk_arith_var", tout << "#" << n->get_owner_id() << " :=\n" << mk_ll_pp(n->get_owner(), get_manager()) << "\n"; tout << "is_attached_to_var: " << is_attached_to_var(n) << ", var: " << n->get_th_var(get_id()) << "\n";); get_context().attach_th_var(n, this, r); @@ -175,15 +149,15 @@ namespace smt { } /** - \brief Create an enode for n. + \brief Create an enode for n. */ template enode * theory_arith::mk_enode(app * n) { context & ctx = get_context(); - if (ctx.e_internalized(n)) + if (ctx.e_internalized(n)) return ctx.get_enode(n); else - return ctx.mk_enode(n, !reflect(n), false, enable_cgc_for(n)); + return ctx.mk_enode(n, !reflect(n), false, enable_cgc_for(n)); } /** @@ -239,13 +213,13 @@ namespace smt { row_entry & r_entry = r.add_row_entry(r_idx); int c_idx; col_entry & c_entry = c.add_col_entry(c_idx); - + r_entry.m_var = v; r_entry.m_coeff = coeff; if (invert) r_entry.m_coeff .neg(); r_entry.m_col_idx = c_idx; - + c_entry.m_row_id = r_id; c_entry.m_row_idx = r_idx; } @@ -266,7 +240,7 @@ namespace smt { return; } } - rational _val; + rational _val; expr* arg1, *arg2; if (m_util.is_mul(m, arg1, arg2) && m_util.is_numeral(arg1, _val) && is_app(arg1) && is_app(arg2)) { SASSERT(m->get_num_args() == 2); @@ -315,7 +289,7 @@ namespace smt { // HACK: n was already internalized by the internalize_internal_monomial or internalize_internal_add call above. // This can happen when one of calls invoke (indirectly) mk_axiom. // For example, they contain a nested to_int(t) term. - // TODO: reimplement mk_axiom. The current implementation is flaky. + // TODO: reimplement mk_axiom. The current implementation is flaky. // I should cache the axioms that need to be created. They should only be internalized after we finished internalizing the // current atom. Several other theories have similar problems. del_row(r_id); @@ -348,7 +322,7 @@ namespace smt { } /** - \brief Internalize the terms of the form (* c (* t1 ... tn)) and (* t1 ... tn). + \brief Internalize the terms of the form (* c (* t1 ... tn)) and (* t1 ... tn). Return an alias for the term. */ template @@ -389,7 +363,7 @@ namespace smt { return expr2var(n); ctx.internalize(n->get_arg(0), false); ctx.internalize(n->get_arg(1), false); - enode * e = mk_enode(n); + enode * e = mk_enode(n); return mk_var(e); } @@ -479,7 +453,7 @@ namespace smt { ctx.mark_as_relevant(l_conseq); } else { - // We must mark the antecedent as relevant, otherwise the + // We must mark the antecedent as relevant, otherwise the // core will not propagate it to the theory of arithmetic. // In a previous version, we were not doing that. // The core was assigning it to true, this assignment was inconsistent with @@ -496,7 +470,7 @@ namespace smt { if (!m_util.is_zero(q)) { ast_manager & m = get_manager(); expr_ref div(m), zero(m), eqz(m), eq(m); - TRACE("div_axiom_bug", tout << "expanding div_axiom for: " << mk_pp(p, m) << " / " << mk_pp(q, m) << "\n";); + TRACE("div_axiom_bug", tout << "expanding div_axiom for: " << mk_pp(p, m) << " / " << mk_pp(q, m) << "\n";); div = m_util.mk_div(p, q); zero = m_util.mk_numeral(rational(0), false); eqz = m.mk_eq(q, zero); @@ -525,7 +499,7 @@ namespace smt { eq = m.mk_eq(m_util.mk_add(m_util.mk_mul(divisor, div), mod), dividend); lower = m_util.mk_ge(mod, zero); upper = m_util.mk_le(mod, abs_divisor); - TRACE("div_axiom_bug", + TRACE("div_axiom_bug", tout << "eqz: " << eqz << " neq: " << eq << "\n"; tout << "lower: " << lower << "\n"; tout << "upper: " << upper << "\n";); @@ -534,7 +508,7 @@ namespace smt { mk_axiom(eqz, lower, !is_numeral); mk_axiom(eqz, upper, !is_numeral); rational k; - if (m_params.m_arith_enum_const_mod && m_util.is_numeral(divisor, k) && + if (m_params.m_arith_enum_const_mod && m_util.is_numeral(divisor, k) && k.is_pos() && k < rational(8)) { rational j(0); #if 1 @@ -550,7 +524,7 @@ namespace smt { j += rational(1); } ctx.mk_th_axiom(get_id(), lits.size(), lits.begin()); - + #else // performs slightly worse. literal_buffer lits; @@ -567,7 +541,7 @@ namespace smt { j += rational(1); } #endif - } + } } } @@ -586,12 +560,12 @@ namespace smt { mk_axiom(dltz, eq1); dltz = m.mk_not(dltz); // !n < 0 || rem(a,n) = -mod(a, n) - mk_axiom(dltz, eq2); + mk_axiom(dltz, eq2); } // // create the term: s := x - to_real(to_int(x)) - // add the bounds 0 <= s < 1 + // add the bounds 0 <= s < 1 // template void theory_arith::mk_to_int_axiom(app * n) { @@ -606,7 +580,7 @@ namespace smt { } expr_ref to_r(m_util.mk_to_real(n), m); expr_ref diff(m_util.mk_add(x, m_util.mk_mul(m_util.mk_real(-1), to_r)), m); - + expr_ref lo(m_util.mk_ge(diff, m_util.mk_real(0)), m); expr_ref hi(m_util.mk_ge(diff, m_util.mk_real(1)), m); hi = m.mk_not(hi); @@ -631,7 +605,7 @@ namespace smt { // // Create the axiom (iff (is_int x) (= x (to_real (to_int x)))) - // + // template void theory_arith::mk_is_int_axiom(app * n) { @@ -718,7 +692,7 @@ namespace smt { ++m_top; } ~scoped_row_vars() { - --m_top; + --m_top; } }; @@ -738,7 +712,7 @@ namespace smt { SASSERT(!m_util.is_sub(n)); SASSERT(!m_util.is_uminus(n)); - + if (m_util.is_add(n)) return internalize_add(n); else if (m_util.is_mul(n)) @@ -747,9 +721,9 @@ namespace smt { return internalize_div(n); else if (m_util.is_idiv(n)) return internalize_idiv(n); - else if (m_util.is_mod(n)) + else if (m_util.is_mod(n)) return internalize_mod(n); - else if (m_util.is_rem(n)) + else if (m_util.is_rem(n)) return internalize_rem(n); else if (m_util.is_to_real(n)) return internalize_to_real(n); @@ -844,7 +818,7 @@ namespace smt { /** \brief Collect variables in the given row that have the given kind, but a different from the row main var (i.e., var that owns the row). - + The inv of the coefficients is also stored in result */ template @@ -864,7 +838,7 @@ namespace smt { } /** - \brief Normalize row as a quasi base row, it does not contain quasi-base + \brief Normalize row as a quasi base row, it does not contain quasi-base variables different from r.m_base_var. */ template @@ -910,7 +884,7 @@ namespace smt { // For example, consider the following scenario: // // 1) s is a quasi-base var, s depends on x, and value of x is v0 - // + // // 2) x is updated to v1, but the update does not affect s (s is a quasi-base var). // // 3) quasi_base_row2base_row is executed, and we compute the value of s using @@ -920,7 +894,7 @@ namespace smt { // // 5) if this branch is deleted, the row owned by s will not satisfy // valid_row_assignment. - // + // m_value[s] = tmp; SASSERT(!m_in_update_trail_stack.contains(s)); save_value(s); @@ -962,8 +936,8 @@ namespace smt { TRACE("mk_bound_axioms", tout << "add bound axioms for v" << v << " " << a1 << "\n";); if (!get_context().is_searching()) { // - // NB. We make an assumption that user push calls propagation - // before internal scopes are pushed. This flushes all newly + // NB. We make an assumption that user push calls propagation + // before internal scopes are pushed. This flushes all newly // asserted atoms into the right context. // m_new_atoms.push_back(a1); @@ -978,7 +952,7 @@ namespace smt { typename atoms::iterator lo_inf = end, lo_sup = end; typename atoms::iterator hi_inf = end, hi_sup = end; for (; it != end; ++it) { - atom * a2 = *it; + atom * a2 = *it; inf_numeral const & k2(a2->get_k()); atom_kind kind2 = a2->get_atom_kind(); TRACE("mk_bound_axioms", display_atom(tout << "compare " << a2 << " ", a2, true); tout << "\n";); @@ -1006,7 +980,7 @@ namespace smt { else if (hi_sup == end || k2 < (*hi_sup)->get_k()) { hi_sup = it; } - } + } if (lo_inf != end) mk_bound_axiom(a1, *lo_inf); if (lo_sup != end) mk_bound_axiom(a1, *lo_sup); if (hi_inf != end) mk_bound_axiom(a1, *hi_inf); @@ -1017,8 +991,8 @@ namespace smt { void theory_arith::mk_bound_axiom(atom* a1, atom* a2) { TRACE("mk_bound_axioms", tout << a1 << " " << a2 << "\n";); theory_var v = a1->get_var(); - literal l1(a1->get_bool_var()); - literal l2(a2->get_bool_var()); + literal l1(a1->get_bool_var()); + literal l2(a2->get_bool_var()); inf_numeral const & k1(a1->get_k()); inf_numeral const & k2(a2->get_k()); atom_kind kind1 = a1->get_atom_kind(); @@ -1027,7 +1001,7 @@ namespace smt { SASSERT(v == a2->get_var()); if (k1 == k2 && kind1 == kind2) return; SASSERT(k1 != k2 || kind1 != kind2); - parameter coeffs[3] = { parameter(symbol("farkas")), + parameter coeffs[3] = { parameter(symbol("farkas")), parameter(rational(1)), parameter(rational(1)) }; if (kind1 == A_LOWER) { @@ -1059,7 +1033,7 @@ namespace smt { } else { // k1 < k2, k2 <= x => ~(x <= k1) - mk_clause(~l1, ~l2, 3, coeffs); + mk_clause(~l1, ~l2, 3, coeffs); if (v_is_int && k1 == k2 - inf_numeral(1)) { // x <= k1 or k1+l <= x mk_clause(l1, l2, 3, coeffs); @@ -1077,7 +1051,7 @@ namespace smt { // k1 <= hi_sup , x <= k1 => x <= hi_sup mk_clause(~l1, l2, 3, coeffs); } - } + } } template @@ -1085,7 +1059,7 @@ namespace smt { CTRACE("arith_verbose", !m_new_atoms.empty(), tout << "flush bound axioms\n";); while (!m_new_atoms.empty()) { - ptr_vector atoms; + ptr_vector atoms; atoms.push_back(m_new_atoms.back()); m_new_atoms.pop_back(); theory_var v = atoms.back()->get_var(); @@ -1096,8 +1070,8 @@ namespace smt { m_new_atoms.pop_back(); --i; } - } - CTRACE("arith", atoms.size() > 1, + } + CTRACE("arith", atoms.size() > 1, for (unsigned i = 0; i < atoms.size(); ++i) { atoms[i]->display(*this, tout); tout << "\n"; }); @@ -1124,10 +1098,10 @@ namespace smt { hi_inf1 = next_inf(a1, A_UPPER, hi_inf, end, fhi_inf); lo_sup1 = next_sup(a1, A_LOWER, lo_sup, end, flo_sup); hi_sup1 = next_sup(a1, A_UPPER, hi_sup, end, fhi_sup); - if (lo_inf1 != end) lo_inf = lo_inf1; - if (lo_sup1 != end) lo_sup = lo_sup1; - if (hi_inf1 != end) hi_inf = hi_inf1; - if (hi_sup1 != end) hi_sup = hi_sup1; + if (lo_inf1 != end) lo_inf = lo_inf1; + if (lo_sup1 != end) lo_sup = lo_sup1; + if (hi_inf1 != end) hi_inf = hi_inf1; + if (hi_sup1 != end) hi_sup = hi_sup1; if (!flo_inf) lo_inf = end; if (!fhi_inf) hi_inf = end; if (!flo_sup) lo_sup = end; @@ -1137,15 +1111,15 @@ namespace smt { if (lo_sup1 != end && lo_sup != end && !visited.contains(*lo_sup)) mk_bound_axiom(a1, *lo_sup); if (hi_inf1 != end && hi_inf != end && !visited.contains(*hi_inf)) mk_bound_axiom(a1, *hi_inf); if (hi_sup1 != end && hi_sup != end && !visited.contains(*hi_sup)) mk_bound_axiom(a1, *hi_sup); - } + } } } template - typename theory_arith::atoms::iterator + typename theory_arith::atoms::iterator theory_arith::first( - atom_kind kind, - typename atoms::iterator it, + atom_kind kind, + typename atoms::iterator it, typename atoms::iterator end) { for (; it != end; ++it) { atom* a = *it; @@ -1155,18 +1129,18 @@ namespace smt { } template - typename theory_arith::atoms::iterator + typename theory_arith::atoms::iterator theory_arith::next_inf( - atom* a1, - atom_kind kind, - typename atoms::iterator it, + atom* a1, + atom_kind kind, + typename atoms::iterator it, typename atoms::iterator end, bool& found_compatible) { inf_numeral const & k1(a1->get_k()); typename atoms::iterator result = end; found_compatible = false; for (; it != end; ++it) { - atom * a2 = *it; + atom * a2 = *it; if (a1 == a2) continue; if (a2->get_atom_kind() != kind) continue; inf_numeral const & k2(a2->get_k()); @@ -1182,17 +1156,17 @@ namespace smt { } template - typename theory_arith::atoms::iterator + typename theory_arith::atoms::iterator theory_arith::next_sup( - atom* a1, - atom_kind kind, - typename atoms::iterator it, + atom* a1, + atom_kind kind, + typename atoms::iterator it, typename atoms::iterator end, bool& found_compatible) { inf_numeral const & k1(a1->get_k()); found_compatible = false; for (; it != end; ++it) { - atom * a2 = *it; + atom * a2 = *it; if (a1 == a2) continue; if (a2->get_atom_kind() != kind) continue; inf_numeral const & k2(a2->get_k()); @@ -1234,7 +1208,7 @@ namespace smt { app * rhs = to_app(n->get_arg(1)); expr * rhs2; if (m_util.is_to_real(rhs, rhs2) && is_app(rhs2)) { rhs = to_app(rhs2); } - if (!m_util.is_numeral(rhs)) { + if (!m_util.is_numeral(rhs)) { UNREACHABLE(); throw default_exception("malformed atomic constraint"); } @@ -1290,7 +1264,7 @@ namespace smt { enode * n1 = ctx.get_enode(lhs); enode * n2 = ctx.get_enode(rhs); // The expression atom may be a theory axiom. In this case, it may not be in simplified form. - // So, an atom such as (= a a) may occur. The procedure mk_axioms, expects n1 != n2. + // So, an atom such as (= a a) may occur. The procedure mk_axioms, expects n1 != n2. // So, we should check it. It doesn't make sense to create an axiom for (= a a) in the arith_eq_adapter. if (n1->get_th_var(get_id()) != null_theory_var && n2->get_th_var(get_id()) != null_theory_var && @@ -1305,7 +1279,7 @@ namespace smt { void theory_arith::apply_sort_cnstr(enode * n, sort * s) { // do nothing... } - + template void theory_arith::assign_eh(bool_var v, bool is_true) { TRACE("arith_verbose", tout << "p" << v << " := " << (is_true?"true":"false") << "\n";); @@ -1320,13 +1294,13 @@ namespace smt { template void theory_arith::relevant_eh(app * n) { TRACE("arith_relevant_eh", tout << "relevant_eh: " << mk_pp(n, get_manager()) << "\n";); - if (m_util.is_mod(n)) + if (m_util.is_mod(n)) mk_idiv_mod_axioms(n->get_arg(0), n->get_arg(1)); else if (m_util.is_rem(n)) mk_rem_axiom(n->get_arg(0), n->get_arg(1)); - else if (m_util.is_div(n)) + else if (m_util.is_div(n)) mk_div_axiom(n->get_arg(0), n->get_arg(1)); - else if (m_util.is_to_int(n)) + else if (m_util.is_to_int(n)) mk_to_int_axiom(n); else if (m_util.is_is_int(n)) mk_is_int_axiom(n); @@ -1335,16 +1309,16 @@ namespace smt { template void theory_arith::new_eq_eh(theory_var v1, theory_var v2) { TRACE("arith_new_eq_eh", tout << "#" << get_enode(v1)->get_owner_id() << " = #" << get_enode(v2)->get_owner_id() << "\n";); - TRACE("arith_new_eq_eh_detail", tout << mk_pp(get_enode(v1)->get_owner(), get_manager()) << "\n" << + TRACE("arith_new_eq_eh_detail", tout << mk_pp(get_enode(v1)->get_owner(), get_manager()) << "\n" << mk_pp(get_enode(v2)->get_owner(), get_manager()) << "\n";); enode * n1 = get_enode(v1); - - if (!m_util.is_int(n1->get_owner()) && + + if (!m_util.is_int(n1->get_owner()) && !m_util.is_real(n1->get_owner())) { return; } - if (m_params.m_arith_eq_bounds) { + if (m_params.m_arith_eq_bounds) { enode * n2 = get_enode(v2); SASSERT(n1->get_root() == n2->get_root()); if (m_util.is_numeral(n1->get_owner())) { @@ -1391,7 +1365,7 @@ namespace smt { template void theory_arith::new_diseq_eh(theory_var v1, theory_var v2) { - TRACE("arith_new_diseq_eh", tout << mk_bounded_pp(get_enode(v1)->get_owner(), get_manager()) << "\n" << + TRACE("arith_new_diseq_eh", tout << mk_bounded_pp(get_enode(v1)->get_owner(), get_manager()) << "\n" << mk_bounded_pp(get_enode(v2)->get_owner(), get_manager()) << "\n";); m_stats.m_assert_diseq++; m_arith_eq_adapter.new_diseq_eh(v1, v2); @@ -1456,8 +1430,8 @@ namespace smt { result = FC_GIVEUP; break; case FC_CONTINUE: - TRACE("arith", - tout << "continue arith..." + TRACE("arith", + tout << "continue arith..." << (get_context().inconsistent()?"inconsistent\n":"\n");); return FC_CONTINUE; } @@ -1475,8 +1449,8 @@ namespace smt { TRACE("arith_eq_adapter_info", m_arith_eq_adapter.display_already_processed(tout);); TRACE("arith", display(tout);); - if (!propagate_core()) - return FC_CONTINUE; + if (!propagate_core()) + return FC_CONTINUE; if (delayed_assume_eqs()) return FC_CONTINUE; get_context().push_trail(value_trail(m_final_check_idx)); @@ -1493,12 +1467,12 @@ namespace smt { TRACE("arith", tout << "result: " << result << "\n";); return result; } - + template bool theory_arith::can_propagate() { return process_atoms() && m_asserted_qhead < m_asserted_bounds.size(); } - + template void theory_arith::propagate() { TRACE("arith_propagate", tout << "propagate\n"; display(tout);); @@ -1512,7 +1486,7 @@ namespace smt { CASSERT("arith", wf_rows()); CASSERT("arith", wf_columns()); CASSERT("arith", valid_row_assignment()); - + flush_bound_axioms(); propagate_linear_monomials(); while (m_asserted_qhead < m_asserted_bounds.size()) { @@ -1520,7 +1494,7 @@ namespace smt { m_asserted_qhead++; if (!assert_bound(b)) { failed(); - return false; + return false; } } if (!make_feasible()) { @@ -1545,15 +1519,15 @@ namespace smt { CASSERT("arith", satisfy_bounds()); return true; } - + template void theory_arith::failed() { restore_assignment(); m_to_patch.reset(); m_to_check.reset(); m_in_to_check.reset(); - } - + } + template void theory_arith::flush_eh() { std::for_each(m_atoms.begin(), m_atoms.end(), delete_proc()); @@ -1561,7 +1535,7 @@ namespace smt { std::for_each(m_bounds_to_delete.begin(), m_bounds_to_delete.end(), delete_proc()); m_bounds_to_delete.reset(); } - + template void theory_arith::reset_eh() { m_stats.reset(); @@ -1666,7 +1640,7 @@ namespace smt { result.neg(); return is_diff; } - + template theory_arith::theory_arith(ast_manager & m, theory_arith_params & params): theory(m.mk_family_id("arith")), @@ -1702,8 +1676,8 @@ namespace smt { } template - theory* theory_arith::mk_fresh(context* new_ctx) { - return alloc(theory_arith, new_ctx->get_manager(), m_params); + theory* theory_arith::mk_fresh(context* new_ctx) { + return alloc(theory_arith, new_ctx->get_manager(), m_params); } template @@ -1717,7 +1691,7 @@ namespace smt { // Add Row // // ----------------------------------- - + /** \brief Set: row1 <- row1 + coeff * row2 */ @@ -1735,8 +1709,8 @@ namespace smt { CASSERT("arith", check_null_var_pos()); r1.save_var_pos(m_var_pos); - - // + + // // loop over variables in row2, // add terms in row2 to row1. // @@ -1785,7 +1759,7 @@ namespace smt { r_entry.m_coeff -= it->m_coeff); } else { - ADD_ROW(r_entry.m_coeff = it->m_coeff; r_entry.m_coeff *= coeff, + ADD_ROW(r_entry.m_coeff = it->m_coeff; r_entry.m_coeff *= coeff, r_entry.m_coeff += it->m_coeff * coeff); } @@ -1797,17 +1771,17 @@ namespace smt { theory_var v = r1.get_base_var(); if (is_int(v) && !get_value(v).is_int()) gcd_test(r1); - } + } } /** \brief Set r1 <- r1 + a_xs[0].m_coeff * get_var_row(a_xs[0].m_var) + ... + a_xs[0].m_coeff * get_var_row(a_xs[sz-1].m_var) - + \pre For all i in [0..sz-1]. not is_non_base(a_xs[i]) */ template void theory_arith::add_rows(unsigned r1, unsigned sz, linear_monomial * a_xs) { - if (sz == 0) + if (sz == 0) return; for (unsigned i = 0; i < sz; i++) { linear_monomial & m = a_xs[i]; @@ -1837,7 +1811,7 @@ namespace smt { } m_changed_assignment = true; } - + template void theory_arith::discard_update_trail() { m_in_update_trail_stack.reset(); @@ -1876,15 +1850,15 @@ namespace smt { } /** - \brief m_value[v] += delta, and update dependent (non-base) variables. + \brief m_value[v] += delta, and update dependent (non-base) variables. */ template void theory_arith::update_value(theory_var v, inf_numeral const & delta) { update_value_core(v, delta); - + column & c = m_columns[v]; c.compress_if_needed(m_rows); - + inf_numeral delta2; typename svector::const_iterator it = c.begin_entries(); typename svector::const_iterator end = c.end_entries(); @@ -1929,7 +1903,7 @@ namespace smt { int r_id = get_var_row(x_i); row & r = m_rows[r_id]; - + SASSERT(r.is_coeff_of(x_j, a_ij)); #define DIVIDE_ROW(_ADJUST_COEFF_) \ @@ -1953,14 +1927,14 @@ namespace smt { set_var_row(x_i, -1); set_var_row(x_j, r_id); - + SASSERT(r.m_base_var == x_i); r.m_base_var = x_j; set_var_kind(x_i, NON_BASE); set_var_kind(x_j, BASE); - - eliminate(x_j, apply_gcd_test); + + eliminate(x_j, apply_gcd_test); CASSERT("arith", wf_rows()); CASSERT("arith", wf_columns()); @@ -1979,7 +1953,7 @@ namespace smt { /** \brief Eliminate x_i from the rows different from get_var_row(x_i) - + If Lazy = true, then x_i is only eliminated from base rows. */ template @@ -1998,7 +1972,7 @@ namespace smt { unsigned r1_sz = m_rows[r_id].size(); if (it->m_row_id != static_cast(r_id)) { row & r2 = m_rows[it->m_row_id]; - theory_var s2 = r2.m_base_var; + theory_var s2 = r2.m_base_var; if (s2 != null_theory_var && (!Lazy || is_base(s2))) { a_kj = r2[it->m_row_idx].m_coeff; a_kj.neg(); @@ -2006,12 +1980,12 @@ namespace smt { get_manager().limit().inc((r1_sz + r2.size()) * (a_kj.storage_size())); } } - else { + else { s_pos = i; } } - } - CTRACE("eliminate", !Lazy && c.size() != 1, + } + CTRACE("eliminate", !Lazy && c.size() != 1, tout << "eliminating v" << x_i << ", Lazy: " << Lazy << ", c.size: " << c.size() << "\n"; display(tout);); SASSERT(Lazy || c.size() == 1); @@ -2051,7 +2025,7 @@ namespace smt { pivot(x_i, x_j, a_ij, m_eager_gcd); CASSERT("arith", valid_row_assignment()); } - + /** \brief Return the number of base variables that are non free and are v dependent. The function adds 1 to the result if v is non free. @@ -2077,9 +2051,9 @@ namespace smt { } return result; } - + /** - \brief Using Bland's rule, select a variable x_j in the row r defining the base var x_i, + \brief Using Bland's rule, select a variable x_j in the row r defining the base var x_i, s.t. x_j can be used to patch the error in x_i. Return null_theory_var if there is no x_j. Otherwise, return x_j and store its coefficient in out_a_ij. @@ -2090,29 +2064,29 @@ namespace smt { theory_var max = get_num_vars(); theory_var result = max; row const & r = m_rows[get_var_row(x_i)]; - + typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) { - if (!it->is_dead()) { - theory_var x_j = it->m_var; - numeral const & a_ij = it->m_coeff; + for (; it != end; ++it) { + if (!it->is_dead()) { + theory_var x_j = it->m_var; + numeral const & a_ij = it->m_coeff; bool is_neg = is_below ? a_ij.is_neg() : a_ij.is_pos(); - bool is_pos = !is_neg; + bool is_pos = !is_neg; if (x_i != x_j && ((is_pos && above_lower(x_j)) || (is_neg && below_upper(x_j)))) { SASSERT(is_non_base(x_j)); - if (x_j < result) { - result = x_j; - out_a_ij = a_ij; + if (x_j < result) { + result = x_j; + out_a_ij = a_ij; } } } } return result < max ? result : null_theory_var; } - + /** - \brief Select a variable x_j in the row r defining the base var x_i, + \brief Select a variable x_j in the row r defining the base var x_i, s.t. x_j can be used to patch the error in x_i. Return null_theory_var if there is no x_j. Otherwise, return x_j and store its coefficient in out_a_ij. @@ -2135,13 +2109,13 @@ namespace smt { for (; it != end; ++it) { - if (!it->is_dead()) { - theory_var x_j = it->m_var; - numeral const & a_ij = it->m_coeff; - + if (!it->is_dead()) { + theory_var x_j = it->m_var; + numeral const & a_ij = it->m_coeff; + bool is_neg = is_below ? a_ij.is_neg() : a_ij.is_pos(); - bool is_pos = !is_neg; - if (x_i != x_j && ((is_pos && above_lower(x_j)) || (is_neg && below_upper(x_j)))) { + bool is_pos = !is_neg; + if (x_i != x_j && ((is_pos && above_lower(x_j)) || (is_neg && below_upper(x_j)))) { int num = get_num_non_free_dep_vars(x_j, best_so_far); int col_sz = m_columns[x_j].size(); if (num < best_so_far || (num == best_so_far && col_sz < best_col_sz)) { @@ -2157,13 +2131,13 @@ namespace smt { result = x_j; out_a_ij = a_ij; } - } + } } } } return result < max ? result : null_theory_var; } - + /** \brief Wrapper for select_blands_pivot_core and select_pivot_core */ @@ -2184,7 +2158,7 @@ namespace smt { // Make feasible // // ----------------------------------- - + /** \brief Make the given variable feasible. This method assumes that x_i is a base var. Return false if it was not possible to @@ -2192,8 +2166,8 @@ namespace smt { */ template bool theory_arith::make_var_feasible(theory_var x_i) { - CTRACE("arith_bug", !is_base(x_i), - tout << "x_i: " << x_i << ", below_lower(x_i): " << below_lower(x_i) << + CTRACE("arith_bug", !is_base(x_i), + tout << "x_i: " << x_i << ", below_lower(x_i): " << below_lower(x_i) << ", above_upper(x_i): " << above_upper(x_i) << "\n"; display(tout);); SASSERT(is_base(x_i)); @@ -2245,7 +2219,7 @@ namespace smt { continue; SASSERT(curr_error > inf_numeral(0)); if (best == null_theory_var || (!least && curr_error > best_error) || (least && curr_error < best_error)) { - TRACE("select_pivot", tout << "best: " << best << " v" << v + TRACE("select_pivot", tout << "best: " << best << " v" << v << ", best_error: " << best_error << ", curr_error: " << curr_error << "\n";); best = v; best_error = curr_error; @@ -2266,7 +2240,7 @@ namespace smt { m_to_patch.erase(best); return best; } - + template theory_var theory_arith::select_smallest_var() { return m_to_patch.erase_min(); @@ -2277,7 +2251,7 @@ namespace smt { if (m_blands_rule) return select_smallest_var(); switch (m_params.m_arith_pivot_strategy) { - case ARITH_PIVOT_GREATEST_ERROR: + case ARITH_PIVOT_GREATEST_ERROR: return select_greatest_error_var(); case ARITH_PIVOT_LEAST_ERROR: return select_least_error_var(); @@ -2319,12 +2293,12 @@ namespace smt { m_left_basis.insert(v); } } - if (!make_var_feasible(v)) { + if (!make_var_feasible(v)) { TRACE("arith_make_feasible", tout << "make_feasible: unsat\n"; display(tout);); return false; } TRACE("arith_make_feasible_detail", display(tout);); - if (get_context().get_cancel_flag()) { + if (get_context().get_cancel_flag()) { return true; } } @@ -2339,7 +2313,7 @@ namespace smt { /** \brief A row is in a sign inconsistency when it is implying a lower (upper) bound on x_i, which is above (below) its known - upper (lower) bound. + upper (lower) bound. */ template void theory_arith::sign_row_conflict(theory_var x_i, bool is_below) { @@ -2353,7 +2327,7 @@ namespace smt { // if x_i is an integer variable, then delta can be negative: // // Example: x_i <= 0 get_value(x_i) = 1/4 - // + // // The value is above the upper bound. // Since x_i is an integer, get_epsilon(x_i) = 1, and delta = -3/4 @@ -2383,7 +2357,7 @@ namespace smt { antecedents ante(*this); explain_bound(r, idx, !is_below, delta, ante); b->push_justification(ante, numeral(1), coeffs_enabled()); - + TRACE("sign_row_conflict", tout << "v" << x_i << " is_below: " << is_below << " delta: " << delta << "\n"; display_var(tout, x_i); tout << "is_below_lower: " << below_lower(x_i) << ", is_above_upper: " << above_upper(x_i) << "\n"; ante.display(tout);); @@ -2397,7 +2371,7 @@ namespace smt { // Assert bound // // ----------------------------------- - + /** \brief Assert x >= k, return false if a conflict is detected. */ @@ -2409,7 +2383,7 @@ namespace smt { bound * u = upper(v); bound * l = lower(v); - + if (u && k > u->get_value()) { sign_bound_conflict(u, b); return false; @@ -2419,7 +2393,7 @@ namespace smt { // redundant return true; } - + switch (get_var_kind(v)) { case QUASI_BASE: quasi_base_row2base_row(get_var_row(v)); @@ -2438,10 +2412,10 @@ namespace smt { push_bound_trail(v, l, false); set_bound(b, false); - + if (propagation_mode() != BP_NONE) mark_rows_for_bound_prop(v); - + return true; } @@ -2457,12 +2431,12 @@ namespace smt { TRACE("arith", display_bound(tout, b); tout << "v" << v << " <= " << k << "\n";); bound * u = upper(v); bound * l = lower(v); - + if (l && k < l->get_value()) { sign_bound_conflict(l, b); return false; } - + if (u && k >= u->get_value()) { // redundant return true; @@ -2474,7 +2448,7 @@ namespace smt { SASSERT(get_var_kind(v) == BASE); case BASE: if (!m_to_patch.contains(v) && get_value(v) > k) { - TRACE("to_patch_bug", tout << "need to be patched (assert upper): "; display_var(tout, v);); + TRACE("to_patch_bug", tout << "need to be patched (assert upper): "; display_var(tout, v);); m_to_patch.insert(v); } break; @@ -2486,12 +2460,12 @@ namespace smt { push_bound_trail(v, u, true); set_bound(b, true); - + if (propagation_mode() != BP_NONE) mark_rows_for_bound_prop(v); return true; - } + } template bool theory_arith::assert_bound(bound * b) { @@ -2507,7 +2481,7 @@ namespace smt { bool result = true; switch (b->get_bound_kind()) { - case B_LOWER: + case B_LOWER: m_stats.m_assert_lower++; result = assert_lower(b); break; @@ -2516,7 +2490,7 @@ namespace smt { result = assert_upper(b); break; } - + TRACE("arith_bound", tout << "result: " << result << "\n"; display(tout);); return result; } @@ -2541,7 +2515,7 @@ namespace smt { // Bound propagation // // ----------------------------------- - + /** \brief Mark the row r1 for bound propagation. */ @@ -2554,7 +2528,7 @@ namespace smt { } /** - \brief Mark all rows that contain v for bound propagation. + \brief Mark all rows that contain v for bound propagation. */ template void theory_arith::mark_rows_for_bound_prop(theory_var v) { @@ -2600,7 +2574,7 @@ namespace smt { - lower_idx >= 0 : row can imply a lower bound for the monomial at 'lower_idx' - lower_idx == -1 : row can imply a lower bound for every monomial in the row. - lower_idx == -2 : row cannot be used to imply a lower bound. - + - upper_idx >= 0 : row can imply a upper bound for the monomial at 'upper_idx' - upper_idx == -1 : row can imply a upper bound for every monomial in the row. - upper_idx == -2 : row cannot be used to imply a upper bound. @@ -2608,7 +2582,7 @@ namespace smt { template void theory_arith::is_row_useful_for_bound_prop(row const & r, int & lower_idx, int & upper_idx) const { lower_idx = -1; - upper_idx = -1; + upper_idx = -1; typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); for (int i = 0; it != end; ++it, ++i) { @@ -2667,7 +2641,7 @@ namespace smt { // implied_k is a lower bound for entry.m_var bound * curr = lower(entry.m_var); if (curr == nullptr || implied_k > curr->get_value()) { - TRACE("arith_imply_bound", + TRACE("arith_imply_bound", tout << "implying lower bound for v" << entry.m_var << " " << implied_k << " using row:\n"; display_row_info(tout, r); display_var(tout, entry.m_var);); @@ -2675,21 +2649,21 @@ namespace smt { } } else { - // implied_k is an upper bound for it->m_var + // implied_k is an upper bound for it->m_var bound * curr = upper(entry.m_var); if (curr == nullptr || implied_k < curr->get_value()) { - TRACE("arith_imply_bound", + TRACE("arith_imply_bound", tout << "implying upper bound for v" << entry.m_var << " " << implied_k << " using row:\n"; display_row_info(tout, r); display_var(tout, entry.m_var);); mk_implied_bound(r, idx, is_lower, entry.m_var, B_UPPER, implied_k); } } - } + } } /** - \brief Auxiliary method. See is_row_useful_for_bound_prop + \brief Auxiliary method. See is_row_useful_for_bound_prop If is_lower = true (false), then imply a lower (upper) bound for all monomials in the row. The monomial bounds are used to compute bounds @@ -2697,7 +2671,7 @@ namespace smt { */ template void theory_arith::imply_bound_for_all_monomials(row const & r, bool is_lower) { - // Traverse the row once and compute + // Traverse the row once and compute // bb = (Sum_{a_i < 0} -a_i*lower(x_i)) + (Sum_{a_j > 0} -a_j * upper(x_j)) If is_lower = true // bb = (Sum_{a_i > 0} -a_i*lower(x_i)) + (Sum_{a_j < 0} -a_j * upper(x_j)) If is_lower = false inf_numeral bb; @@ -2710,7 +2684,7 @@ namespace smt { bb.submul(it->m_coeff, b); } } - + inf_numeral implied_k; it = r.begin_entries(); for (int idx = 0; it != end; ++it, ++idx) { @@ -2721,7 +2695,7 @@ namespace smt { implied_k.addmul(it->m_coeff, b); // implied_k is a bound for the monomial in position it implied_k /= it->m_coeff; - TRACE("arith_imply_bound", + TRACE("arith_imply_bound", display_var(tout, it->m_var); tout << "implied bound: " << (it->m_coeff.is_pos() ? ">=" : "<=") << implied_k << "\n";); if (it->m_coeff.is_pos() == is_lower) { @@ -2737,7 +2711,7 @@ namespace smt { } } else { - // implied_k is an upper bound for it->m_var + // implied_k is an upper bound for it->m_var bound * curr = upper(it->m_var); if (curr == nullptr || implied_k < curr->get_value()) { // improved upper bound @@ -2754,13 +2728,13 @@ namespace smt { /** \brief Create an explanation for the lower/upper bound of the variable at position idx. - + \remark delta is used for relaxing the explanation. That is, the implied bound can be delta weaker the the computed value. - \remark the is_lower parameter is a little bit counterintuitive. It says if the other monomials + \remark the is_lower parameter is a little bit counterintuitive. It says if the other monomials imply a lower (upper) bound for the monomial at position idx. - + Store the result in 'antecedent' */ template @@ -2770,7 +2744,7 @@ namespace smt { return; context & ctx = get_context(); row_entry const & entry = r[idx]; - numeral coeff = entry.m_coeff; + numeral coeff = entry.m_coeff; if (relax_bounds()) { // if the variable v at position idx can have a delta increase (decrease) of 'delta', then // the monomial (coeff * v) at position idx can have a delta increase (decrease) of '|coeff| * delta' @@ -2811,7 +2785,7 @@ namespace smt { // limit_k1 += delta * coeff; limit_k1.addmul(inv_coeff, delta); } - TRACE("propagate_bounds_bug", tout << "is_b_lower: " << is_b_lower << " k1: " << k_1 << " limit_k1: " + TRACE("propagate_bounds_bug", tout << "is_b_lower: " << is_b_lower << " k1: " << k_1 << " limit_k1: " << limit_k1 << " delta: " << delta << " coeff: " << coeff << "\n";); inf_numeral k_2 = k_1; atom * new_atom = nullptr; @@ -2891,7 +2865,7 @@ namespace smt { delta = k; delta -= k2; } - TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", v" << v << " >= " << k2 << ", delta: " << delta << "\n"; + TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", v" << v << " >= " << k2 << ", delta: " << delta << "\n"; display_row(tout, r);); assign_bound_literal(l, r, idx, is_lower, delta); } @@ -2901,13 +2875,13 @@ namespace smt { // example: // k = -1/5*epsilon // k2 = 0 - // Thus, v <= -1/5*epsilon + // Thus, v <= -1/5*epsilon // (not v >= 0) which is equivalent to v <= -epsilon. delta = k2; delta -= k; delta -= epsilon; if (delta.is_nonneg()) { - TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", not v" << v << " >= " << k2 << ", delta: " << delta << "\n"; + TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", not v" << v << " >= " << k2 << ", delta: " << delta << "\n"; display_row(tout, r);); assign_bound_literal(~l, r, idx, is_lower, delta); } @@ -2922,18 +2896,18 @@ namespace smt { delta -= k2; delta -= epsilon; if (delta.is_nonneg()) { - TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", not v" << v << " <= " << k2 << ", delta: " << delta << "\n"; + TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", not v" << v << " <= " << k2 << ", delta: " << delta << "\n"; display_row(tout, r);); assign_bound_literal(~l, r, idx, is_lower, delta); } } - // v <= k k <= k2 |- v <= k2 + // v <= k k <= k2 |- v <= k2 if (kind == B_UPPER && k <= k2) { if (relax_bounds()) { delta = k2; delta -= k; } - TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", v" << v << " <= " << k2 << ", delta: " << delta << "\n"; + TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", v" << v << " <= " << k2 << ", delta: " << delta << "\n"; display_row(tout, r);); assign_bound_literal(l, r, idx, is_lower, delta); } @@ -2947,7 +2921,7 @@ namespace smt { context & ctx = get_context(); if (dump_lemmas()) { TRACE("arith", ante.display(tout) << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); - 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); } } @@ -2956,7 +2930,7 @@ namespace smt { void theory_arith::dump_lemmas(literal l, derived_bound const& ante) { context & ctx = get_context(); if (dump_lemmas()) { - 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); } } @@ -2968,10 +2942,10 @@ namespace smt { antecedents ante(*this); explain_bound(r, idx, is_lower, delta, ante); dump_lemmas(l, ante); - - TRACE("propagate_bounds", + + TRACE("propagate_bounds", ante.display(tout) << " --> "; - ctx.display_detailed_literal(tout, l); + ctx.display_detailed_literal(tout, l); tout << "\n";); if (ante.lits().size() < small_lemma_size() && ante.eqs().empty()) { literal_vector & lits = m_tmp_literal_vector2; @@ -2992,8 +2966,8 @@ namespace smt { region & r = ctx.get_region(); ctx.assign(l, ctx.mk_justification( ext_theory_propagation_justification( - get_id(), r, ante.lits().size(), ante.lits().c_ptr(), - ante.eqs().size(), ante.eqs().c_ptr(), l, + get_id(), r, ante.lits().size(), ante.lits().c_ptr(), + ante.eqs().size(), ante.eqs().c_ptr(), l, ante.num_params(), ante.params("assign-bounds")))); } } @@ -3014,29 +2988,29 @@ namespace smt { int lower_idx; int upper_idx; is_row_useful_for_bound_prop(r, lower_idx, upper_idx); - + if (lower_idx >= 0) { imply_bound_for_monomial(r, lower_idx, true); } else if (lower_idx == -1) { imply_bound_for_all_monomials(r, true); } - + if (upper_idx >= 0) { imply_bound_for_monomial(r, upper_idx, false); } else if (upper_idx == -1) { imply_bound_for_all_monomials(r, false); } - - // sneaking cheap eq detection in this loop + + // sneaking cheap eq detection in this loop propagate_cheap_eq(*it); } - + #if 0 theory_var v = r.get_base_var(); if (!is_int(v) || get_value(v).is_int()) { - // If an integer value is not assigned to an integer value, then + // If an integer value is not assigned to an integer value, then // bound propagation can diverge. m_in_to_check.remove(v); } @@ -3064,15 +3038,15 @@ namespace smt { dump_lemmas(false_literal, ante); set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), bounds, proof_rule); } - + template - void theory_arith::set_conflict(unsigned num_literals, literal const * lits, unsigned num_eqs, enode_pair const * eqs, + void theory_arith::set_conflict(unsigned num_literals, literal const * lits, unsigned num_eqs, enode_pair const * eqs, antecedents& bounds, char const* proof_rule) { SASSERT(num_literals != 0 || num_eqs != 0); context & ctx = get_context(); m_stats.m_conflicts++; m_num_conflicts++; - TRACE("arith_conflict", + TRACE("arith_conflict", tout << "scope: " << ctx.get_scope_level() << "\n"; for (unsigned i = 0; i < num_literals; i++) { ctx.display_detailed_literal(tout, lits[i]); @@ -3095,13 +3069,13 @@ namespace smt { record_conflict(num_literals, lits, num_eqs, eqs, bounds.num_params(), bounds.params(proof_rule)); ctx.set_conflict( ctx.mk_justification( - ext_theory_conflict_justification(get_id(), ctx.get_region(), num_literals, lits, num_eqs, eqs, + ext_theory_conflict_justification(get_id(), ctx.get_region(), num_literals, lits, num_eqs, eqs, bounds.num_params(), bounds.params(proof_rule)))); } /** \brief Collect the proofs for the fixed variables in the given row. Store - the proofs in result. + the proofs in result. */ template void theory_arith::collect_fixed_var_justifications(row const & r, antecedents& antecedents) const { @@ -3110,7 +3084,7 @@ namespace smt { for (; it != end; ++it) { if (!it->is_dead() && is_fixed(it->m_var)) { lower(it->m_var)->push_justification(antecedents, it->m_coeff, coeffs_enabled()); - upper(it->m_var)->push_justification(antecedents, it->m_coeff, coeffs_enabled()); + upper(it->m_var)->push_justification(antecedents, it->m_coeff, coeffs_enabled()); } } } @@ -3124,33 +3098,33 @@ namespace smt { // // The arithmetic module uses infinitesimals. So, // an inf_numeral (n,k) represents n + k*epsilon - // where epsilon is a very small number. + // where epsilon is a very small number. // In order to generate a model, we need to compute // a value for epsilon in a way all bounds remain // satisfied. // // 1) Handling inequalities: (n1, k1) <= (n2, k2) - // - // The only intersting case is n1 < n2 and k1 > k2. + // + // The only intersting case is n1 < n2 and k1 > k2. // Using the definition of infinitesimal numbers // we have: // n1 + k1 * epsilon <= n2 + k2 - epsilon // Therefore: // epsilon <= (n2 - n1) / (k1 - k2) - // + // // Starting at Z3 V2.0, we split disequalities. // So, we do not need to handle them. If we decide // to support them again in the future: // // 2) Handling disequalities: (n1, k1) /= n2 - // + // // case a) k1 is positive and n1 < n2 // Thus, epsilon < (n2 - n1) / k1 // => epsilon <= (n2 - n1) / 2*k1 // // case b) k1 is negative and n1 > n2 - // Similarly, epsilon <= (n2 - n1) / 2*k1 - // + // Similarly, epsilon <= (n2 - n1) / 2*k1 + // /** \brief Update the value of epsilon using the inequality l <= u @@ -3166,7 +3140,7 @@ namespace smt { } SASSERT(m_epsilon.is_pos()); } - + template void theory_arith::compute_epsilon() { m_epsilon = numeral(1); @@ -3184,21 +3158,21 @@ namespace smt { /** The epsilon computed by compute_epsilon may accidentally make two shared - variables to have the same assignment. This method keeps dividing + variables to have the same assignment. This method keeps dividing epsilon by 2 until this "clash" does not occur. Here is an example of the problem - + Assignment: x -> 9.5 - y -> 10 - epsilon - + y -> 10 - epsilon + x and y have different assignments. However, if compute_epsilon sets epsilon to 0.5, then x and y become 9.5. However, an equality is not propagated to the core since in the assignment above they are assigned to distinct values. - - This bug was reported by Marcello Bersani. + + This bug was reported by Marcello Bersani. Remark: this is not really a soundness bug. The result sat/unsat produced by Z3 was still correct. - However, the model construction was incorrect. Perhaps, this explains why this bug was not + However, the model construction was incorrect. Perhaps, this explains why this bug was not detected before. */ template @@ -3221,7 +3195,7 @@ namespace smt { if (mapping.find(value, v2)) { SASSERT(!is_int_src(v2)); if (get_value(v) != get_value(v2)) { - // v and v2 are not known to be equal. + // v and v2 are not known to be equal. // The choice of m_epsilon is making them equal. TRACE("refine_epsilon", tout << "v" << v << " v" << v2 << " " << get_value(v) << " " << get_value(v2) << " " << value << std::endl; @@ -3274,7 +3248,7 @@ namespace smt { template bool theory_arith::to_expr(inf_numeral const& val, bool is_int, expr_ref & r) { - if (val.get_infinitesimal().is_zero()) { + if (val.get_infinitesimal().is_zero()) { numeral _val = val.get_rational(); r = m_util.mk_numeral(_val.to_rational(), is_int); return true; @@ -3292,25 +3266,25 @@ namespace smt { } template - bool theory_arith::get_lower(enode * n, expr_ref & r) { + bool theory_arith::get_lower(enode * n, expr_ref & r) { theory_var v = n->get_th_var(get_id()); bound* b = (v == null_theory_var) ? nullptr : lower(v); return b && to_expr(b->get_value(), is_int(v), r); } - + template - bool theory_arith::get_upper(enode * n, expr_ref & r) { + bool theory_arith::get_upper(enode * n, expr_ref & r) { theory_var v = n->get_th_var(get_id()); bound* b = (v == null_theory_var) ? nullptr : upper(v); return b && to_expr(b->get_value(), is_int(v), r); } - + // ----------------------------------- // // Backtracking // // ----------------------------------- - + template void theory_arith::push_scope_eh() { theory::push_scope_eh(); @@ -3415,7 +3389,7 @@ namespace smt { --it; m_unassigned_atoms[*it]++; } - + m_unassigned_atoms_trail.shrink(old_trail_size); } @@ -3432,7 +3406,7 @@ namespace smt { SASSERT(m_var_occs[v].back() == a); m_var_occs[v].pop_back(); dealloc(a); - } + } m_atoms.shrink(old_size); } @@ -3444,7 +3418,7 @@ namespace smt { --it; bound * b = *it; dealloc(b); - } + } m_bounds_to_delete.shrink(old_size); } @@ -3461,7 +3435,7 @@ namespace smt { SASSERT(m_columns[v].size() == 1); del_row(get_var_row(v)); TRACE("arith_make_feasible", tout << "del row v" << v << "\n";); - break; + break; case BASE: SASSERT(lazy_pivoting_lvl() != 0 || m_columns[v].size() == 1); if (lazy_pivoting_lvl() > 0) @@ -3519,7 +3493,7 @@ namespace smt { r.reset(); m_dead_rows.push_back(r_id); } - + /** \brief reset and retrieve built-in explanation hints for arithmetic lemmmas. */ @@ -3542,4 +3516,3 @@ namespace smt { }; #endif /* THEORY_ARITH_CORE_H_ */ - From fca0442487d1e884c443126e319fb4f00df99c3f Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 17:11:46 -0700 Subject: [PATCH 1141/1283] Fix proof_checker to use is_int_expr --- src/ast/proofs/proof_checker.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index d0f8a7994..e148299be 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -84,7 +84,7 @@ void proof_checker::hyp_decl_plugin::get_sort_names(svector & sort } proof_checker::proof_checker(ast_manager& m) : m(m), m_todo(m), m_marked(), m_pinned(m), m_nil(m), - m_dump_lemmas(false), m_logic("AUFLIA"), m_proof_lemma_id(0) { + m_dump_lemmas(false), m_logic("AUFLIRA"), m_proof_lemma_id(0) { symbol fam_name("proof_hypothesis"); if (!m.has_plugin(fam_name)) { m.register_plugin(fam_name, alloc(hyp_decl_plugin)); @@ -1245,9 +1245,9 @@ void proof_checker::dump_proof(proof const* pr) { void proof_checker::dump_proof(unsigned num_antecedents, expr * const * antecedents, expr * consequent) { char buffer[128]; #ifdef _WINDOWS - sprintf_s(buffer, ARRAYSIZE(buffer), "proof_lemma_%d.smt", m_proof_lemma_id); + sprintf_s(buffer, ARRAYSIZE(buffer), "proof_lemma_%d.smt2", m_proof_lemma_id); #else - sprintf(buffer, "proof_lemma_%d.smt", m_proof_lemma_id); + sprintf(buffer, "proof_lemma_%d.smt2", m_proof_lemma_id); #endif std::ofstream out(buffer); ast_smt_pp pp(m); @@ -1278,6 +1278,10 @@ bool proof_checker::check_arith_literal(bool is_pos, app* lit0, rational const& SASSERT(lit->get_num_args() == 2); sort* s = m.get_sort(lit->get_arg(0)); bool is_int = a.is_int(s); + if (!is_int && a.is_int_expr(lit->get_arg(0))) { + is_int = true; + s = a.mk_int(); + } if (!is_int && is_pos && (a.is_gt(lit) || a.is_lt(lit))) { is_strict = true; @@ -1394,7 +1398,6 @@ bool proof_checker::check_arith_proof(proof* p) { return false; } } - if (m.is_or(fact)) { app* disj = to_app(fact); unsigned num_args = disj->get_num_args(); From 1994f1d7e4eb3f952a062e477792cf33aaee4d65 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 17:46:23 -0700 Subject: [PATCH 1142/1283] Cleanup of spacer options --- src/muz/spacer/spacer_context.cpp | 98 +++++++++++++++++++++---------- src/muz/spacer/spacer_context.h | 34 +++++++++++ src/muz/spacer/spacer_pdr.cpp | 2 +- 3 files changed, 103 insertions(+), 31 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 8806afb6a..118a99dd3 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -77,8 +77,8 @@ void pob::set_post(expr* post) { void pob::set_post(expr* post, app_ref_vector const &binding) { normalize(post, m_post, - m_pt.get_context().get_params().spacer_simplify_pob(), - m_pt.get_context().get_params().spacer_use_eqclass()); + m_pt.get_context().simplify_pob(), + m_pt.get_context().use_eqclass()); m_binding.reset(); if (!binding.empty()) {m_binding.append(binding);} @@ -1382,7 +1382,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, /// returns true if lemma is blocked by an existing model bool pred_transformer::is_ctp_blocked(lemma *lem) { - if (!ctx.get_params().spacer_ctp()) {return false;} + if (!ctx.use_ctp()) {return false;} if (!lem->has_ctp()) {return false;} scoped_watch _t_(m_ctp_watch); @@ -1443,7 +1443,7 @@ bool pred_transformer::is_invariant(unsigned level, lemma* lem, ctx.weak_abs() ? lem->weakness() : UINT_MAX); model_ref mdl; model_ref *mdl_ref_ptr = nullptr; - if (ctx.get_params().spacer_ctp()) {mdl_ref_ptr = &mdl;} + if (ctx.use_ctp()) {mdl_ref_ptr = &mdl;} m_solver->set_core(core); m_solver->set_model(mdl_ref_ptr); expr * bg = m_extend_lit.get (); @@ -1582,7 +1582,7 @@ void pred_transformer::init_rules(decl2rel const& pts) { m_transition_clause.push_back(m_extend_lit->get_arg(0)); m_transition_clause.push_back(tag); - if (!ctx.get_params().spacer_use_inc_clause()) { + if (!ctx.use_inc_clause()) { transitions.push_back(mk_or(m_transition_clause)); m_transition_clause.reset(); } @@ -1605,7 +1605,7 @@ void pred_transformer::init_rules(decl2rel const& pts) { if (!is_init[i]) {init_conds.push_back (m.mk_not (tag));} } - if (!ctx.get_params().spacer_use_inc_clause()) { + if (!ctx.use_inc_clause()) { transitions.push_back(mk_or(m_transition_clause)); m_transition_clause.reset(); } @@ -1671,7 +1671,7 @@ void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule, // rewrite and simplify th_rewriter rw(m); rw(fml); - if (ctx.get_params().spacer_blast_term_ite()) {blast_term_ite(fml); rw(fml);} + if (ctx.blast_term_ite()) {blast_term_ite(fml); rw(fml);} TRACE("spacer", tout << mk_pp(fml, m) << "\n";); // allow quantifiers in init rule @@ -2170,7 +2170,7 @@ pob* pred_transformer::pobs::mk_pob(pob *parent, unsigned level, unsigned depth, expr *post, app_ref_vector const &b) { - if (!m_pt.ctx.get_params().spacer_reuse_pobs()) { + if (!m_pt.ctx.reuse_pobs()) { pob* n = alloc(pob, parent, m_pt, level, depth); n->set_post(post, b); return n; @@ -2244,7 +2244,7 @@ context::context(fixedpoint_params const& params, m_pool1 = alloc(solver_pool, pool1_base.get(), max_num_contexts); m_pool2 = alloc(solver_pool, pool2_base.get(), max_num_contexts); - updt_params() + updt_params(); } context::~context() @@ -2256,8 +2256,46 @@ context::~context() void context::updt_params() { m_random.set_seed(m_params.spacer_random_seed()); m_children_order = static_cast(m_params.spacer_order_children()); + m_simplify_pob = m_params.spacer_simplify_pob(); + m_use_eqclass = m_params.spacer_use_eqclass(); + m_use_ctp = m_params.spacer_ctp(); + m_use_inc_clause = m_params.spacer_use_inc_clause(); + m_blast_term_ite = m_params.spacer_blast_term_ite(); + m_reuse_pobs = m_params.spacer_reuse_pobs(); + m_use_ind_gen = m_params.pdr_use_inductive_generalizer(); + m_use_array_eq_gen = m_params.spacer_use_array_eq_generalizer(); + m_check_lemmas = m_params.spacer_lemma_sanity_check(); + m_max_level = m_params.spacer_max_level (); + m_skip_propagate = m_params.spacer_skip_propagate (); + m_reset_obligation_queue = m_params.spacer_reset_obligation_queue(); + m_flexible_trace = m_params.pdr_flexible_trace(); + m_flexible_trace_depth = m_params.pdr_flexible_trace_depth(); + m_use_lemma_as_pob = m_params.spacer_use_lemma_as_cti(); + m_elim_aux = m_params.spacer_elim_aux(); + m_reach_dnf = m_params.spacer_reach_dnf(); + m_use_derivations = m_params.spacer_use_derivations(); + m_validate_result = m_params.pdr_validate_result(); + m_use_eq_prop = m_params.spacer_eq_prop(); + m_ground_pob = m_params.spacer_ground_cti(); + m_q3_qgen = m_params.spacer_q3_use_qgen(); + m_use_gpdr = m_params.spacer_gpdr(); + m_simplify_formulas_pre = m_params.pdr_simplify_formulas_pre(); + m_simplify_formulas_post = m_params.pdr_simplify_formulas_post(); + + + if (m_use_gpdr) { + // set options to be compatible with GPDR + m_weak_abs = false; + m_flexible_trace = false; + m_use_qlemmas = false; + m_ground_pob = true; + m_reset_obligation_queue = false; + m_use_derivations = false; + m_use_lemma_as_pob = false; + } } + void context::reset() { TRACE("spacer", tout << "\n";); @@ -2403,7 +2441,7 @@ expr_ref context::get_reachable(func_decl *p) bool context::validate() { - if (!m_params.pdr_validate_result()) { return true; } + if (!m_validate_result) { return true; } std::stringstream msg; @@ -2500,7 +2538,7 @@ void context::reset_lemma_generalizers() void context::init_global_smt_params() { m.toggle_proof_mode(PGM_ENABLED); params_ref p; - if (!m_params.spacer_eq_prop()) { + if (!m_use_eq_prop) { p.set_uint("arith.propagation_mode", BP_NONE); p.set_bool("arith.auto_config_simplex", true); p.set_bool("arith.propagate_eqs", false); @@ -2514,7 +2552,7 @@ void context::init_global_smt_params() { // mbqi p.set_bool("mbqi", m_params.spacer_mbqi()); - if (!m_params.spacer_ground_cti()) { + if (!m_ground_pob) { p.set_uint("phase_selection", PS_CACHING_CONSERVATIVE2); p.set_uint("restart_strategy", RS_GEOMETRIC); p.set_double("restart_factor", 1.5); @@ -2537,29 +2575,29 @@ void context::init_lemma_generalizers() { reset_lemma_generalizers(); - if (m_params.spacer_q3_use_qgen()) { + if (m_q3_qgen) { m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0, true)); m_lemma_generalizers.push_back(alloc(lemma_quantifier_generalizer, *this, m_params.spacer_q3_qgen_normalize())); } - if (get_params().spacer_use_eqclass()) { + if (use_eqclass()) { m_lemma_generalizers.push_back (alloc(lemma_eq_generalizer, *this)); } // -- AG: commented out because it is causing performance issues at the moment //m_lemma_generalizers.push_back (alloc (unsat_core_generalizer, *this)); - if (m_params.pdr_use_inductive_generalizer()) { + if (m_use_ind_gen) { m_lemma_generalizers.push_back(alloc(lemma_bool_inductive_generalizer, *this, 0)); } - if (m_params.spacer_use_array_eq_generalizer()) { + if (m_use_array_eq_gen) { m_lemma_generalizers.push_back(alloc(lemma_array_eq_generalizer, *this)); } - if (get_params().spacer_lemma_sanity_check()) { + if (m_check_lemmas) { m_lemma_generalizers.push_back(alloc(lemma_sanity_checker, *this)); } @@ -2595,7 +2633,7 @@ lbool context::solve(unsigned from_lvl) { m_last_result = l_undef; try { - if (m_params.spacer_gpdr()) { + if (m_use_gpdr) { SASSERT(from_lvl == 0); m_last_result = gpdr_solve_core(); } @@ -2976,7 +3014,7 @@ lbool context::solve_core (unsigned from_lvl) pob *root = m_query->mk_pob(nullptr,from_lvl,0,m.mk_true()); m_pob_queue.set_root (*root); - unsigned max_level = get_params ().spacer_max_level (); + unsigned max_level = m_max_level; for (unsigned i = from_lvl; i < max_level; ++i) { checkpoint(); @@ -2985,7 +3023,7 @@ lbool context::solve_core (unsigned from_lvl) if (check_reachability()) { return l_true; } - if (lvl > 0 && !get_params ().spacer_skip_propagate ()) + if (lvl > 0 && !m_skip_propagate) if (propagate(m_expanded_lvl, lvl, UINT_MAX)) { dump_json(); return l_false; } dump_json(); @@ -3032,7 +3070,7 @@ bool context::check_reachability () pob_ref_buffer new_pobs; - if (get_params().spacer_reset_obligation_queue()) { m_pob_queue.reset(); } + if (m_reset_obligation_queue) { m_pob_queue.reset(); } unsigned initial_size = m_stats.m_num_lemmas; unsigned threshold = m_restart_initial_threshold; @@ -3132,8 +3170,8 @@ bool context::check_reachability () /// returns true if the given pob can be re-scheduled bool context::is_requeue(pob &n) { - if (!get_params().pdr_flexible_trace()) {return false;} - unsigned max_depth = get_params().pdr_flexible_trace_depth(); + if (!m_flexible_trace) {return false;} + unsigned max_depth = m_flexible_trace_depth; return (n.level() >= m_pob_queue.max_level() || m_pob_queue.max_level() - n.level() <= max_depth); } @@ -3299,7 +3337,7 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) unsigned num_reuse_reach = 0; - if (get_params().pdr_flexible_trace() && n.pt().is_blocked(n, uses_level)) { + if (m_flexible_trace && n.pt().is_blocked(n, uses_level)) { // if (!m_pob_queue.is_root (n)) n.close (); IF_VERBOSE (1, verbose_stream () << " K " << std::fixed << std::setprecision(2) @@ -3418,7 +3456,7 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) if (v) { m_stats.m_num_lemmas++; } // Optionally update the node to be the negation of the lemma - if (v && get_params().spacer_use_lemma_as_cti()) { + if (v && m_use_lemma_as_pob) { n.new_post (mk_and(lemma->get_cube())); n.set_farkas_generalizer (false); // XXX hack while refactoring is in progress @@ -3494,7 +3532,7 @@ bool context::propagate(unsigned min_prop_lvl, if (full_prop_lvl < max_prop_lvl) { full_prop_lvl = max_prop_lvl; } - if (m_params.pdr_simplify_formulas_pre()) { + if (m_simplify_formulas_pre) { simplify_formulas(); } STRACE ("spacer.expand-add", tout << "Propagating\n";); @@ -3539,7 +3577,7 @@ bool context::propagate(unsigned min_prop_lvl, return true; } else if (all_propagated && lvl > max_prop_lvl) { break; } } - if (m_params.pdr_simplify_formulas_post()) { + if (m_simplify_formulas_post) { simplify_formulas(); } @@ -3583,13 +3621,13 @@ reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, } // collect aux vars to eliminate ptr_vector& aux_vars = get_aux_vars (r); - bool elim_aux = ctx.get_params().spacer_elim_aux(); + bool elim_aux = ctx.elim_aux(); if (elim_aux) { vars.append(aux_vars.size(), aux_vars.c_ptr()); } res = mk_and (path_cons); // -- pick an implicant from the path condition - if (ctx.get_params().spacer_reach_dnf()) { + if (ctx.reach_dnf()) { expr_ref_vector u(m), lits(m); u.push_back (res); compute_implicant_literals (mev, u, lits); @@ -3727,7 +3765,7 @@ bool context::create_children(pob& n, datalog::rule const& r, kid->set_derivation (deriv); // Optionally disable derivation optimization - if (!get_params().spacer_use_derivations()) { kid->reset_derivation(); } + if (!m_use_derivations) { kid->reset_derivation(); } // -- deriviation is abstract if the current weak model does // -- not satisfy 'T && phi'. It is possible to recover from diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index e00d479f7..8bc7f36e6 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -846,6 +846,32 @@ class context { bool m_use_qlemmas; bool m_weak_abs; bool m_use_restarts; + bool m_simplify_pob; + bool m_use_eqclass; + bool m_use_ctp; + bool m_use_inc_clause; + bool m_blast_term_ite; + bool m_reuse_pobs; + bool m_use_ind_gen; + bool m_use_array_eq_gen; + bool m_check_lemmas; + bool m_skip_propagate; + bool m_reset_obligation_queue; + bool m_flexible_trace; + bool m_use_lemma_as_pob; + bool m_elim_aux; + bool m_reach_dnf; + bool m_use_derivations; + bool m_validate_result; + bool m_use_eq_prop; + bool m_ground_pob; + bool m_q3_qgen; + bool m_use_gpdr; + bool m_simplify_formulas_pre; + bool m_simplify_formulas_post; + + unsigned m_flexible_trace_depth; + unsigned m_max_level; unsigned m_restart_initial_threshold; scoped_ptr_vector m_callbacks; json_marshaller m_json_marshaller; @@ -913,6 +939,14 @@ public: bool use_instantiate () {return m_instantiate;} bool weak_abs() {return m_weak_abs;} bool use_qlemmas () {return m_use_qlemmas;} + bool use_eqclass() { return m_use_eqclass;} + bool simplify_pob() {return m_simplify_pob;} + bool use_ctp() {return m_use_ctp;} + bool use_inc_clause() {return m_use_inc_clause;} + bool blast_term_ite() {return m_blast_term_ite;} + bool reuse_pobs() {return m_reuse_pobs;} + bool elim_aux() {return m_elim_aux;} + bool reach_dnf() {return m_reach_dnf;} ast_manager& get_ast_manager() const {return m;} manager& get_manager() {return m_pm;} diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index e46907493..6c7da20a7 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -224,7 +224,7 @@ lbool context::gpdr_solve_core() { model_search ms(true); unsigned lvl = 0; - unsigned max_level = get_params ().spacer_max_level (); + unsigned max_level = m_max_level; for (lvl = 0; lvl < max_level; ++lvl) { checkpoint(); IF_VERBOSE(1,verbose_stream() << "GPDR Entering level "<< lvl << "\n";); From e1a45671b354f0ce3d9a3b8a37cdbba3774d8c91 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 18:43:10 -0700 Subject: [PATCH 1143/1283] Cleanup spacer options --- src/muz/spacer/spacer_context.cpp | 23 +++++++++++------------ src/muz/spacer/spacer_context.h | 3 +-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 118a99dd3..9e70fa3c6 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -262,7 +262,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) vars.append(m_evars); m_evars.reset(); pt().mbp(vars, m_trans, mev.get_model(), - true, pt().get_context().use_ground_cti()); + true, pt().get_context().use_ground_pob()); m_evars.append (vars); vars.reset(); } @@ -291,7 +291,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) // include m_evars in case they can eliminated now as well vars.append(m_evars); pt().mbp(vars, post, mev.get_model(), - true, pt().get_context().use_ground_cti()); + true, pt().get_context().use_ground_pob()); //qe::reduce_array_selects (*mev.get_model (), post); } else { @@ -395,7 +395,7 @@ pob *derivation::create_next_child () vars.append(m_evars); m_evars.reset(); this->pt().mbp(vars, m_trans, mev.get_model(), - true, this->pt().get_context().use_ground_cti()); + true, this->pt().get_context().use_ground_pob()); // keep track of implicitly quantified variables m_evars.append (vars); vars.reset(); @@ -2224,13 +2224,6 @@ context::context(fixedpoint_params const& params, m_last_result(l_undef), m_inductive_lvl(0), m_expanded_lvl(0), - m_use_native_mbp(params.spacer_native_mbp ()), - m_ground_cti (params.spacer_ground_cti ()), - m_instantiate (params.spacer_q3_instantiate ()), - m_use_qlemmas (params.spacer_q3()), - m_weak_abs(params.spacer_weak_abs()), - m_use_restarts(params.spacer_restarts()), - m_restart_initial_threshold(params.spacer_restart_initial_threshold()), m_json_marshaller(this) { ref pool0_base = mk_smt_solver(m, params_ref::get_empty(), symbol::null); @@ -2281,6 +2274,12 @@ void context::updt_params() { m_use_gpdr = m_params.spacer_gpdr(); m_simplify_formulas_pre = m_params.pdr_simplify_formulas_pre(); m_simplify_formulas_post = m_params.pdr_simplify_formulas_post(); + m_use_native_mbp = m_params.spacer_native_mbp (); + m_instantiate = m_params.spacer_q3_instantiate (); + m_use_qlemmas = m_params.spacer_q3(); + m_weak_abs = m_params.spacer_weak_abs(); + m_use_restarts = m_params.spacer_restarts(); + m_restart_initial_threshold = m_params.spacer_restart_initial_threshold(); if (m_use_gpdr) { @@ -3716,9 +3715,9 @@ bool context::create_children(pob& n, datalog::rule const& r, // skolems of the pob n.get_skolems(vars); - n.pt().mbp(vars, phi, mev.get_model (), true, use_ground_cti()); + n.pt().mbp(vars, phi, mev.get_model (), true, use_ground_pob()); //qe::reduce_array_selects (*mev.get_model (), phi1); - SASSERT (!m_ground_cti || vars.empty ()); + SASSERT (!m_ground_pob || vars.empty ()); TRACE ("spacer", tout << "Implicant:\n"; diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 8bc7f36e6..115dded55 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -841,7 +841,6 @@ class context { model_converter_ref m_mc; proof_converter_ref m_pc; bool m_use_native_mbp; - bool m_ground_cti; bool m_instantiate; bool m_use_qlemmas; bool m_weak_abs; @@ -935,7 +934,7 @@ public: const fixedpoint_params &get_params() const { return m_params; } bool use_native_mbp () {return m_use_native_mbp;} - bool use_ground_cti () {return m_ground_cti;} + bool use_ground_pob () {return m_ground_pob;} bool use_instantiate () {return m_instantiate;} bool weak_abs() {return m_weak_abs;} bool use_qlemmas () {return m_use_qlemmas;} From d2ae3b4025565948b300a4fba582278bae11f4df Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 5 Jun 2018 22:26:26 -0700 Subject: [PATCH 1144/1283] Create children for pdr in spacer This is first working version of gpdr strategy. Passes one test. --- src/muz/spacer/spacer_context.cpp | 5 +++ src/muz/spacer/spacer_context.h | 4 +++ src/muz/spacer/spacer_pdr.cpp | 54 ++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 9e70fa3c6..5165940d8 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -3727,6 +3727,11 @@ bool context::create_children(pob& n, datalog::rule const& r, tout << "Failed to eliminate: " << vars << "\n"; ); + if (m_use_gpdr && preds.size() > 1) { + SASSERT(vars.empty()); + return gpdr_create_split_children(n, r, phi, mev.get_model(), out); + } + derivation *deriv = alloc(derivation, n, r, phi, vars); // pick an order to process children diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 115dded55..3c6c35742 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -878,6 +878,10 @@ class context { // Solve using gpdr strategy lbool gpdr_solve_core(); bool gpdr_check_reachability(unsigned lvl, model_search &ms); + bool gpdr_create_split_children(pob &n, const datalog::rule &r, + expr *trans, + model_ref &mdl, + pob_ref_buffer &out); // Functions used by search. lbool solve_core(unsigned from_lvl = 0); diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index 6c7da20a7..e1a268c22 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -20,6 +20,7 @@ Notes: --*/ #include "muz/spacer/spacer_pdr.h" #include "muz/base/dl_context.h" +#include "muz/spacer/spacer_mbc.h" namespace spacer { model_node::model_node(model_node* parent, class pob *pob): @@ -90,7 +91,9 @@ void model_node::detach(model_node*& qhead) { // insert node n after this in the queue // requires: this is in a queue or this == n void model_node::insert_after(model_node* n) { - SASSERT(!in_queue()); + SASSERT(this == n || in_queue()); + SASSERT(n); + SASSERT(!n->in_queue()); if (this == n) { m_next = n; m_prev = n; @@ -282,4 +285,53 @@ bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) { return root_node->is_closed(); } +bool context::gpdr_create_split_children(pob &n, const datalog::rule &r, + expr *trans, + model_ref &mdl, + pob_ref_buffer &out) { + pred_transformer &pt = n.pt(); + ptr_vector preds; + pt.find_predecessors(r, preds); + SASSERT(preds.size() > 1); + + ptr_vector ppts; + for (auto *p : preds) ppts.push_back(&get_pred_transformer(p)); + + mbc::partition_map pmap; + for (unsigned i = 0, sz = preds.size(); i < sz; ++i) { + func_decl *p = preds.get(i); + pred_transformer &ppt = *ppts.get(i); + for (unsigned j = 0, jsz = p->get_arity(); j < jsz; ++j) { + pmap.insert(m_pm.o2o(ppt.sig(j), 0, i), i); + } + } + + + spacer::mbc _mbc(m); + expr_ref_vector lits(m); + flatten_and(trans, lits); + vector res(preds.size(), expr_ref_vector(m)); + _mbc(pmap, lits, *mdl.get(), res); + + + for (unsigned i = 0, sz = res.size(); i < sz; ++i) { + expr_ref post(m); + pred_transformer &ppt = *ppts.get(i); + post = mk_and(res.get(i)); + m_pm.formula_o2n(post.get(), post, i, true); + pob * k = ppt.mk_pob(&n, prev_level(n.level()), n.depth(), post); + out.push_back(k); + IF_VERBOSE (1, verbose_stream() + << "\n\tcreate_child: " << k->pt().head()->get_name() + << " (" << k->level() << ", " << k->depth() << ") " + << (k->use_farkas_generalizer() ? "FAR " : "SUB ") + << k->post()->get_id(); + verbose_stream().flush();); + + } + + return true; +} + + } // spacer From c3fb863ad17d34b274d1b9b8db5c9dab3ad5a5b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Jun 2018 22:37:35 -0700 Subject: [PATCH 1145/1283] formatting/reviewing Signed-off-by: Nikolaj Bjorner --- src/ast/ast.h | 33 + src/muz/spacer/spacer_context.cpp | 61 +- src/muz/spacer/spacer_context.h | 18 +- src/muz/spacer/spacer_iuc_solver.cpp | 132 ++-- src/muz/spacer/spacer_iuc_solver.h | 101 ++- src/muz/spacer/spacer_pdr.cpp | 45 +- src/muz/spacer/spacer_pdr.h | 22 +- src/muz/spacer/spacer_quant_generalizer.cpp | 97 ++- src/muz/spacer/spacer_unsat_core_learner.cpp | 73 +-- src/muz/spacer/spacer_unsat_core_learner.h | 19 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 627 ++++++++----------- src/muz/spacer/spacer_unsat_core_plugin.h | 16 +- src/solver/check_sat_result.h | 2 +- 13 files changed, 570 insertions(+), 676 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index ce193e8b1..b6b71c6a3 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1744,6 +1744,14 @@ public: arity, domain); } + func_decl * mk_const_decl(const char* name, sort * s) { + return mk_func_decl(symbol(name), static_cast(0), nullptr, s); + } + + func_decl * mk_const_decl(std::string const& name, sort * s) { + return mk_func_decl(symbol(name.c_str()), static_cast(0), nullptr, s); + } + func_decl * mk_const_decl(symbol const & name, sort * s) { return mk_func_decl(name, static_cast(0), nullptr, s); } @@ -1810,6 +1818,14 @@ public: return mk_const(mk_const_decl(name, s)); } + app * mk_const(std::string const & name, sort * s) { + return mk_const(mk_const_decl(name, s)); + } + + app * mk_const(char const* name, sort * s) { + return mk_const(mk_const_decl(name, s)); + } + func_decl * mk_fresh_func_decl(symbol const & prefix, symbol const & suffix, unsigned arity, sort * const * domain, sort * range); @@ -2150,6 +2166,23 @@ public: return n > 0 && get_sort(p->get_arg(n - 1)) != m_proof_sort; } expr * get_fact(proof const * p) const { SASSERT(is_proof(p)); SASSERT(has_fact(p)); return p->get_arg(p->get_num_args() - 1); } + + class proof_parents { + ast_manager& m; + proof * m_proof; + public: + proof_parents(ast_manager& m, proof * p): m(m), m_proof(p) {} + proof * const * begin() const { return (proof* const*)(m_proof->begin()); } + proof * const * end() const { + unsigned n = m_proof->get_num_args(); + return (proof* const*)(begin() + (m.has_fact(m_proof) ? n - 1 : n)); + } + }; + + proof_parents get_parents(proof* p) { + return proof_parents(*this, p); + } + unsigned get_num_parents(proof const * p) const { SASSERT(is_proof(p)); unsigned n = p->get_num_args(); diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 5165940d8..6726bb15d 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1500,11 +1500,9 @@ void pred_transformer::mk_assumptions(func_decl* head, expr* fml, expr_ref_vector& result) { expr_ref tmp1(m), tmp2(m); - obj_map::iterator it = m_tag2rule.begin(), - end = m_tag2rule.end(); - for (; it != end; ++it) { - expr* tag = it->m_key; - datalog::rule const* r = it->m_value; + for (auto& kv : m_tag2rule) { + expr* tag = kv.m_key; + datalog::rule const* r = kv.m_value; if (!r) { continue; } find_predecessors(*r, m_predicates); for (unsigned i = 0; i < m_predicates.size(); i++) { @@ -2338,7 +2336,6 @@ void context::init_rules(datalog::rule_set& rules, decl2rel& rels) } // Initialize use list dependencies - // for (auto it = rels.begin(), end = rels.end(); it != end; ++it) { for (auto &entry : rels) { func_decl* pred = entry.m_key; pred_transformer* pt = entry.m_value, *pt_user = nullptr; @@ -2464,14 +2461,13 @@ bool context::validate() get_level_property(m_inductive_lvl, refs, rs); inductive_property ex(m, mc, rs); ex.to_model(model); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); var_subst vs(m, false); - for (; it != end; ++it) { - ptr_vector const& rules = it->m_value->rules(); - TRACE ("spacer", tout << "PT: " << it->m_value->head ()->get_name ().str () + for (auto& kv : m_rels) { + ptr_vector const& rules = kv.m_value->rules(); + TRACE ("spacer", tout << "PT: " << kv.m_value->head ()->get_name ().str () << "\n";); - for (unsigned i = 0; i < rules.size(); ++i) { - datalog::rule& r = *rules[i]; + for (auto* rp : rules) { + datalog::rule& r = *rp; TRACE ("spacer", get_datalog_context (). @@ -2603,11 +2599,9 @@ void context::init_lemma_generalizers() } void context::get_level_property(unsigned lvl, expr_ref_vector& res, - vector& rs) const -{ - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - pred_transformer* r = it->m_value; + vector& rs) const { + for (auto const& kv : m_rels) { + pred_transformer* r = kv.m_value; if (r->head() == m_query_pred) { continue; } @@ -2619,12 +2613,9 @@ void context::get_level_property(unsigned lvl, expr_ref_vector& res, } } -void context::simplify_formulas() -{ - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - pred_transformer* r = it->m_value; - r->simplify_formulas(); +void context::simplify_formulas() { + for (auto& kv : m_rels) { + kv.m_value->simplify_formulas(); } } @@ -3549,18 +3540,17 @@ bool context::propagate(unsigned min_prop_lvl, tout << "In full propagation\n";); bool all_propagated = true; - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { + for (auto & kv : m_rels) { checkpoint(); - pred_transformer& r = *it->m_value; + pred_transformer& r = *kv.m_value; all_propagated = r.propagate_to_next_level(lvl) && all_propagated; } //CASSERT("spacer", check_invariant(lvl)); if (all_propagated) { - for (it = m_rels.begin(); it != end; ++it) { + for (auto& kv : m_rels) { checkpoint (); - pred_transformer& r = *it->m_value; + pred_transformer& r = *kv.m_value; r.propagate_to_infinity (lvl); } if (lvl <= max_prop_lvl) { @@ -3793,9 +3783,8 @@ void context::collect_statistics(statistics& st) const m_pool1->collect_statistics(st); m_pool2->collect_statistics(st); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (it = m_rels.begin(); it != end; ++it) { - it->m_value->collect_statistics(st); + for (auto const& kv : m_rels) { + kv.m_value->collect_statistics(st); } // -- number of times a pob for some predicate transformer has @@ -3846,9 +3835,8 @@ void context::reset_statistics() m_pool1->reset_statistics(); m_pool2->reset_statistics(); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (it = m_rels.begin(); it != end; ++it) { - it->m_value->reset_statistics(); + for (auto & kv : m_rels) { + kv.m_value->reset_statistics(); } m_stats.reset(); @@ -3897,9 +3885,8 @@ expr_ref context::get_constraints (unsigned level) expr_ref res(m); expr_ref_vector constraints(m); - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - pred_transformer& r = *it->m_value; + for (auto & kv : m_rels) { + pred_transformer& r = *kv.m_value; expr_ref c = r.get_formulas(level); if (m.is_true(c)) { continue; } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 3c6c35742..34c04d596 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -176,7 +176,7 @@ public: void dec_ref () { SASSERT (m_ref_count > 0); --m_ref_count; - if(m_ref_count == 0) {dealloc(this);} + if (m_ref_count == 0) {dealloc(this);} } }; @@ -242,7 +242,7 @@ class pred_transformer { } void get_frame_geq_lemmas (unsigned level, expr_ref_vector &out) const { for (auto &lemma : m_lemmas) { - if(lemma->level() >= level) { + if (lemma->level() >= level) { out.push_back(lemma->get_expr()); } } @@ -362,7 +362,7 @@ public: void find_predecessors(datalog::rule const& r, ptr_vector& predicates) const; void add_rule(datalog::rule* r) {m_rules.push_back(r);} - void add_use(pred_transformer* pt) {if(!m_use.contains(pt)) {m_use.insert(pt);}} + void add_use(pred_transformer* pt) {if (!m_use.contains(pt)) {m_use.insert(pt);}} void initialize(decl2rel const& pts); func_decl* head() const {return m_head;} @@ -528,7 +528,7 @@ public: pob (pob* parent, pred_transformer& pt, unsigned level, unsigned depth=0, bool add_to_parent=true); - ~pob() {if(m_parent) { m_parent->erase_child(*this); }} + ~pob() {if (m_parent) { m_parent->erase_child(*this); }} unsigned weakness() {return m_weakness;} void bump_weakness() {m_weakness++;} @@ -564,7 +564,7 @@ public: void set_post(expr *post, app_ref_vector const &binding); /// indicate that a new post should be set for the node - void new_post(expr *post) {if(post != m_post) {m_new_post = post;}} + void new_post(expr *post) {if (post != m_post) {m_new_post = post;}} /// true if the node needs to be updated outside of the priority queue bool is_dirty () {return m_new_post;} /// clean a dirty node @@ -592,14 +592,14 @@ public: */ void get_skolems(app_ref_vector& v); - void on_expand() { m_expand_watches[m_depth].start(); if(m_parent.get()){m_parent.get()->on_expand();} } - void off_expand() { m_expand_watches[m_depth].stop(); if(m_parent.get()){m_parent.get()->off_expand();} }; + void on_expand() { m_expand_watches[m_depth].start(); if (m_parent.get()){m_parent.get()->on_expand();} } + void off_expand() { m_expand_watches[m_depth].stop(); if (m_parent.get()){m_parent.get()->off_expand();} }; double get_expand_time(unsigned depth) { return m_expand_watches[depth].get_seconds();} void inc_ref () {++m_ref_count;} void dec_ref () { --m_ref_count; - if(m_ref_count == 0) {dealloc(this);} + if (m_ref_count == 0) {dealloc(this);} } class on_expand_event @@ -727,7 +727,7 @@ public: SASSERT (!m_obligations.empty () || m_root); m_max_level++; m_min_depth++; - if(m_root && m_obligations.empty()) { m_obligations.push(m_root); } + if (m_root && m_obligations.empty()) { m_obligations.push(m_root); } } pob& get_root() const {return *m_root.get ();} diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 35932b2ba..a0bc2a627 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -99,8 +99,9 @@ void iuc_solver::pop_bg (unsigned n) { if (n == 0) { return; } - if (m_assumptions.size () > m_first_assumption) - { m_assumptions.shrink(m_first_assumption); } + if (m_assumptions.size () > m_first_assumption) { + m_assumptions.shrink(m_first_assumption); + } m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0; m_assumptions.shrink (m_first_assumption); } @@ -110,9 +111,8 @@ unsigned iuc_solver::get_num_bg () {return m_first_assumption;} lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions) { // -- remove any old assumptions - if (m_assumptions.size () > m_first_assumption) - { m_assumptions.shrink(m_first_assumption); } - + m_assumptions.shrink(m_first_assumption); + // -- replace theory literals in background assumptions with proxies mk_proxies (m_assumptions); // -- in case mk_proxies added new literals, they are all background @@ -121,20 +121,17 @@ lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions m_assumptions.append (num_assumptions, assumptions); m_is_proxied = mk_proxies (m_assumptions, m_first_assumption); - lbool res; - res = m_solver.check_sat (m_assumptions.size (), m_assumptions.c_ptr ()); - set_status (res); - return res; + return set_status (m_solver.check_sat (m_assumptions)); } lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, vector const & clauses) { - if (clauses.empty()) {return check_sat(cube.size(), cube.c_ptr());} - + if (clauses.empty()) + return check_sat(cube.size(), cube.c_ptr()); + // -- remove any old assumptions - if (m_assumptions.size() > m_first_assumption) - { m_assumptions.shrink(m_first_assumption); } - + m_assumptions.shrink(m_first_assumption); + // -- replace theory literals in background assumptions with proxies mk_proxies(m_assumptions); // -- in case mk_proxies added new literals, they are all background @@ -143,28 +140,24 @@ lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, m_assumptions.append(cube); m_is_proxied = mk_proxies(m_assumptions, m_first_assumption); - lbool res; - res = m_solver.check_sat_cc(m_assumptions, clauses); - set_status (res); - return res; + return set_status (m_solver.check_sat_cc(m_assumptions, clauses)); } app* iuc_solver::def_manager::mk_proxy (expr *v) { app* r; - if (m_expr2proxy.find(v, r)) { return r; } + if (m_expr2proxy.find(v, r)) + return r; ast_manager &m = m_parent.m; - app_ref proxy(m); - app_ref def(m); - proxy = m_parent.fresh_proxy (); - def = m.mk_or (m.mk_not (proxy), v); + app* proxy = m_parent.fresh_proxy (); + app* def = m.mk_or (m.mk_not (proxy), v); m_defs.push_back (def); m_expr2proxy.insert (v, proxy); m_proxy2def.insert (proxy, def); - m_parent.assert_expr (def.get ()); + m_parent.assert_expr (def); return proxy; } @@ -191,18 +184,16 @@ bool iuc_solver::def_manager::is_proxy_def (expr *v) bool iuc_solver::is_proxy(expr *e, app_ref &def) { - if (!is_uninterp_const(e)) { return false; } + if (!is_uninterp_const(e)) + return false; - app *a = to_app (e); + app* a = to_app (e); - for (int i = m_defs.size (); i > 0; --i) - if (m_defs[i-1].is_proxy (a, def)) - { return true; } + for (int i = m_defs.size (); i-- > 0; ) + if (m_defs[i].is_proxy (a, def)) + return true; - if (m_base_defs.is_proxy (a, def)) - { return true; } - - return false; + return m_base_defs.is_proxy (a, def); } void iuc_solver::collect_statistics (statistics &st) const @@ -233,21 +224,25 @@ void iuc_solver::undo_proxies_in_core (ptr_vector &r) { app_ref e(m); expr_fast_mark1 bg; - for (unsigned i = 0; i < m_first_assumption; ++i) - { bg.mark(m_assumptions.get(i)); } + for (unsigned i = 0; i < m_first_assumption; ++i) { + bg.mark(m_assumptions.get(i)); + } // expand proxies unsigned j = 0; - for (unsigned i = 0, sz = r.size(); i < sz; ++i) { + for (expr* rr : r) { // skip background assumptions - if (bg.is_marked(r[i])) { continue; } + if (bg.is_marked(rr)) + continue; // -- undo proxies, but only if they were introduced in check_sat - if (m_is_proxied && is_proxy(r[i], e)) { + if (m_is_proxied && is_proxy(rr, e)) { SASSERT (m.is_or (e)); - r[j] = e->get_arg (1); - } else if (i != j) { r[j] = r[i]; } - j++; + r[j++] = e->get_arg (1); + } + else { + r[j++] = rr; + } } r.shrink (j); } @@ -370,65 +365,66 @@ void iuc_solver::get_iuc(expr_ref_vector &core) unsat_core_learner learner(m, iuc_pf); + unsat_core_plugin* plugin; // -- register iuc plugins - if (m_iuc_arith == 0 || m_iuc_arith == 1) { - unsat_core_plugin_farkas_lemma* plugin = + switch (m_iuc_arith) { + case 0: + case 1: + plugin = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, (m_iuc_arith == 1) /* use constants from A */); learner.register_plugin(plugin); - } - else if (m_iuc_arith == 2) { + break; + case 2: SASSERT(false && "Broken"); - unsat_core_plugin_farkas_lemma_optimized* plugin = - alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m); + plugin = alloc(unsat_core_plugin_farkas_lemma_optimized, learner, m); learner.register_plugin(plugin); - } - else if(m_iuc_arith == 3) { - unsat_core_plugin_farkas_lemma_bounded* plugin = - alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m); + break; + case 3: + plugin = alloc(unsat_core_plugin_farkas_lemma_bounded, learner, m); learner.register_plugin(plugin); - } - else { + break; + default: UNREACHABLE(); + break; } - if (m_iuc == 1) { + switch (m_iuc) { + case 1: // -- iuc based on the lowest cut in the proof - unsat_core_plugin_lemma* plugin = - alloc(unsat_core_plugin_lemma, learner); + plugin = alloc(unsat_core_plugin_lemma, learner); learner.register_plugin(plugin); - } - else if (m_iuc == 2) { + break; + case 2: // -- iuc based on the smallest cut in the proof - unsat_core_plugin_min_cut* plugin = - alloc(unsat_core_plugin_min_cut, learner, m); + plugin = alloc(unsat_core_plugin_min_cut, learner, m); learner.register_plugin(plugin); - } - else { + break; + default: UNREACHABLE(); + break; } - + { scoped_watch _t_ (m_learn_core_sw); // compute interpolating unsat core learner.compute_unsat_core(core); } - + elim_proxies (core); // AG: this should be taken care of by minimizing the iuc cut simplify_bounds (core); } - + IF_VERBOSE(2, - verbose_stream () << "IUC Core:\n" - << mk_and(core) << "\n";); + verbose_stream () << "IUC Core:\n" << core << "\n";); } void iuc_solver::refresh () { // only refresh in non-pushed state - SASSERT (m_defs.size () == 0); + SASSERT (m_defs.empty()); expr_ref_vector assertions (m); for (unsigned i = 0, e = m_solver.get_num_assertions(); i < e; ++i) { expr* a = m_solver.get_assertion (i); diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index dcee54612..0195ea134 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -26,11 +26,10 @@ namespace spacer { class iuc_solver : public solver { private: struct def_manager { - iuc_solver &m_parent; + iuc_solver & m_parent; + expr_ref_vector m_defs; obj_map m_expr2proxy; - obj_map m_proxy2def; - - expr_ref_vector m_defs; + obj_map m_proxy2def; def_manager(iuc_solver &parent) : m_parent(parent), m_defs(m_parent.m) @@ -44,15 +43,15 @@ private: }; friend struct def_manager; - ast_manager &m; - solver &m_solver; - app_ref_vector m_proxies; - unsigned m_num_proxies; + ast_manager& m; + solver& m_solver; + app_ref_vector m_proxies; + unsigned m_num_proxies; vector m_defs; - def_manager m_base_defs; - expr_ref_vector m_assumptions; - unsigned m_first_assumption; - bool m_is_proxied; + def_manager m_base_defs; + expr_ref_vector m_assumptions; + unsigned m_first_assumption; + bool m_is_proxied; stopwatch m_iuc_sw; stopwatch m_hyp_reduce1_sw; @@ -95,7 +94,7 @@ public: /* iuc solver specific */ void get_unsat_core(expr_ref_vector &core) override; virtual void get_iuc(expr_ref_vector &core); - void set_split_literals(bool v) {m_split_literals = v;} + void set_split_literals(bool v) { m_split_literals = v; } bool mk_proxies(expr_ref_vector &v, unsigned from = 0); void undo_proxies(expr_ref_vector &v); @@ -103,42 +102,40 @@ public: void pop_bg(unsigned n); unsigned get_num_bg(); - void get_full_unsat_core(ptr_vector &core) - {m_solver.get_unsat_core(core);} + void get_full_unsat_core(ptr_vector &core) { m_solver.get_unsat_core(core); } /* solver interface */ - solver* translate(ast_manager &m, params_ref const &p) override { return m_solver.translate(m, p);} - void updt_params(params_ref const &p) override {m_solver.updt_params(p);} - void reset_params(params_ref const &p) override {m_solver.reset_params(p);} - const params_ref &get_params() const override {return m_solver.get_params();} - void push_params() override {m_solver.push_params();} - void pop_params() override {m_solver.pop_params();} - void collect_param_descrs(param_descrs &r) override { m_solver.collect_param_descrs(r);} - void set_produce_models(bool f) override { m_solver.set_produce_models(f);} - void assert_expr_core(expr *t) override { m_solver.assert_expr(t);} - void assert_expr_core2(expr *t, expr *a) override { NOT_IMPLEMENTED_YET();} + solver* translate(ast_manager &m, params_ref const &p) override { + return m_solver.translate(m, p); + } + void updt_params(params_ref const &p) override { m_solver.updt_params(p); } + void reset_params(params_ref const &p) override { m_solver.reset_params(p); } + const params_ref &get_params() const override { return m_solver.get_params(); } + void push_params() override { m_solver.push_params(); } + void pop_params() override { m_solver.pop_params(); } + void collect_param_descrs(param_descrs &r) override { m_solver.collect_param_descrs(r); } + void set_produce_models(bool f) override { m_solver.set_produce_models(f); } + void assert_expr_core(expr *t) override { m_solver.assert_expr(t); } + void assert_expr_core2(expr *t, expr *a) override { NOT_IMPLEMENTED_YET(); } expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); } void push() override; void pop(unsigned n) override; - unsigned get_scope_level() const override - {return m_solver.get_scope_level();} + unsigned get_scope_level() const override { return m_solver.get_scope_level(); } lbool check_sat(unsigned num_assumptions, expr * const *assumptions) override; lbool check_sat_cc(const expr_ref_vector &cube, vector const & clauses) override; - void set_progress_callback(progress_callback *callback) override - {m_solver.set_progress_callback(callback);} - unsigned get_num_assertions() const override - {return m_solver.get_num_assertions();} - expr * get_assertion(unsigned idx) const override - {return m_solver.get_assertion(idx);} - unsigned get_num_assumptions() const override - {return m_solver.get_num_assumptions();} - expr * get_assumption(unsigned idx) const override - {return m_solver.get_assumption(idx);} - std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const override - { return m_solver.display(out, n, es); } + void set_progress_callback(progress_callback *callback) override { + m_solver.set_progress_callback(callback); + } + unsigned get_num_assertions() const override { return m_solver.get_num_assertions(); } + expr * get_assertion(unsigned idx) const override { return m_solver.get_assertion(idx); } + unsigned get_num_assumptions() const override { return m_solver.get_num_assumptions(); } + expr * get_assumption(unsigned idx) const override { return m_solver.get_assumption(idx); } + std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const override { + return m_solver.display(out, n, es); + } /* check_sat_result interface */ @@ -148,13 +145,10 @@ public: void get_unsat_core(ptr_vector &r) override; void get_model_core(model_ref &m) override {m_solver.get_model(m);} proof *get_proof() override {return m_solver.get_proof();} - std::string reason_unknown() const override - {return m_solver.reason_unknown();} - void set_reason_unknown(char const* msg) override - {m_solver.set_reason_unknown(msg);} - void get_labels(svector &r) override - {m_solver.get_labels(r);} - ast_manager &get_manager() const override {return m;} + std::string reason_unknown() const override { return m_solver.reason_unknown(); } + void set_reason_unknown(char const* msg) override { m_solver.set_reason_unknown(msg); } + void get_labels(svector &r) override { m_solver.get_labels(r); } + ast_manager& get_manager() const override { return m; } virtual void refresh(); @@ -162,10 +156,10 @@ public: iuc_solver &m_s; expr_ref_vector &m_v; public: - scoped_mk_proxy(iuc_solver &s, expr_ref_vector &v) : m_s(s), m_v(v) - {m_s.mk_proxies(m_v);} - ~scoped_mk_proxy() - {m_s.undo_proxies(m_v);} + scoped_mk_proxy(iuc_solver &s, expr_ref_vector &v) : m_s(s), m_v(v) { + m_s.mk_proxies(m_v); + } + ~scoped_mk_proxy() { m_s.undo_proxies(m_v); } }; class scoped_bg { @@ -173,8 +167,11 @@ public: unsigned m_bg_sz; public: scoped_bg(iuc_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {} - ~scoped_bg() - {if(m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }} + ~scoped_bg() { + if (m_s.get_num_bg() > m_bg_sz) { + m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); + } + } }; }; } diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index e1a268c22..89647ed02 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -28,14 +28,14 @@ model_node::model_node(model_node* parent, class pob *pob): m_orig_level(m_pob->level()), m_depth(0), m_closed(false) { SASSERT(m_pob); - if (m_parent) m_parent->add_child(*this); + if (m_parent) m_parent->add_child(this); } -void model_node::add_child(model_node &kid) { - m_children.push_back(&kid); - SASSERT(level() == kid.level() + 1); +void model_node::add_child(model_node* kid) { + m_children.push_back(kid); + SASSERT(level() == kid->level() + 1); SASSERT(level() > 0); - kid.m_depth = m_depth + 1; + kid->m_depth = m_depth + 1; if (is_closed()) set_open(); } @@ -109,7 +109,7 @@ void model_node::insert_after(model_node* n) { void model_search::reset() { if (m_root) { erase_children(*m_root, false); - remove_node(*m_root, false); + remove_node(m_root, false); dealloc(m_root); m_root = nullptr; } @@ -117,24 +117,28 @@ void model_search::reset() { } model_node* model_search::pop_front() { - if (!m_qhead) return nullptr; model_node *res = m_qhead; - res->detach(m_qhead); + if (res) { + res->detach(m_qhead); + } return res; } -void model_search::add_leaf(model_node& n) { +void model_search::add_leaf(model_node* _n) { + model_node& n = *_n; SASSERT(n.children().empty()); model_nodes ns; model_nodes& nodes = cache(n).insert_if_not_there2(n.post(), ns)->get_data().m_value; if (nodes.contains(&n)) return; - nodes.push_back(&n); + nodes.push_back(_n); if (nodes.size() == 1) { SASSERT(n.is_open()); enqueue_leaf(n); } - else n.set_pre_closed(); + else { + n.set_pre_closed(); + } } void model_search::enqueue_leaf(model_node& n) { @@ -162,7 +166,7 @@ void model_search::set_root(model_node* root) { m_root = root; SASSERT(m_root); SASSERT(m_root->children().empty()); - add_leaf(*root); + add_leaf(root); } void model_search::backtrack_level(bool uses_level, model_node& n) { @@ -198,15 +202,16 @@ void model_search::erase_children(model_node& n, bool backtrack) { todo.pop_back(); nodes.push_back(m); todo.append(m->children()); - remove_node(*m, backtrack); + remove_node(m, backtrack); } std::for_each(nodes.begin(), nodes.end(), delete_proc()); } // removes node from the search tree and from the cache -void model_search::remove_node(model_node& n, bool backtrack) { +void model_search::remove_node(model_node* _n, bool backtrack) { + model_node& n = *_n; model_nodes& nodes = cache(n).find(n.post()); - nodes.erase(&n); + nodes.erase(_n); if (n.in_queue()) n.detach(m_qhead); // TBD: siblings would also fail if n is not a goal. if (!nodes.empty() && backtrack && @@ -241,9 +246,10 @@ lbool context::gpdr_solve_core() { } // communicate failure to datalog::context - if (m_context) { m_context->set_status(datalog::BOUNDED); } + if (m_context) { + m_context->set_status(datalog::BOUNDED); + } return l_undef; - } bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) { @@ -273,9 +279,8 @@ bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) { TRACE("spacer_pdr", tout << "looking at pob at level " << pob->level() << " " << mk_pp(pob->post(), m) << "\n";); - if (pob == node->pob()) {continue;} - model_node *kid = alloc(model_node, node, pob); - ms.add_leaf(*kid); + if (pob != node->pob()) + ms.add_leaf(alloc(model_node, node, pob)); } node->check_pre_closed(); break; diff --git a/src/muz/spacer/spacer_pdr.h b/src/muz/spacer/spacer_pdr.h index 56900a1e8..36abb0bc9 100644 --- a/src/muz/spacer/spacer_pdr.h +++ b/src/muz/spacer/spacer_pdr.h @@ -36,9 +36,9 @@ class model_node { bool m_closed; // whether the pob is derivable public: model_node(model_node* parent, pob* pob); - void add_child(model_node &kid); + void add_child(model_node* kid); - expr *post() const {return m_pob->post();} + expr *post() const { return m_pob->post(); } unsigned level() const { return m_pob->level(); } unsigned orig_level() const { return m_orig_level; } unsigned depth() const { return m_depth; } @@ -57,24 +57,25 @@ public: bool is_1closed() { if (is_closed()) return true; if (m_children.empty()) return false; - for (auto kid : m_children) {if (kid->is_open()) return false;} + for (auto kid : m_children) + if (kid->is_open()) return false; return true; } void check_pre_closed(); - void set_pre_closed() {m_closed = true;} + void set_pre_closed() { m_closed = true; } - void set_closed() {m_closed = true;} + void set_closed() { m_closed = true; } void set_open(); - void reset_children() {m_children.reset();} + void reset_children() { m_children.reset(); } /// queue // remove this node from the given queue void detach(model_node*& qhead); void insert_after(model_node* n); - model_node* next() const {return m_next;} - bool in_queue() {return m_next && m_prev;} + model_node* next() const { return m_next; } + bool in_queue() { return m_next && m_prev; } }; class model_search { @@ -85,8 +86,7 @@ class model_search { vector > m_cache; obj_map& cache(model_node const& n); void erase_children(model_node& n, bool backtrack); - void remove_node(model_node& n, bool backtrack); - void add_leaf(model_node* n); // add leaf to priority queue. + void remove_node(model_node* _n, bool backtrack); public: model_search(bool bfs): m_bfs(bfs), m_root(nullptr), m_qhead(nullptr) {} @@ -96,7 +96,7 @@ public: void reset(); model_node* pop_front(); - void add_leaf(model_node& n); // add fresh node. + void add_leaf(model_node* n); // add fresh node. model_node& get_root() const { return *m_root; } void backtrack_level(bool uses_level, model_node& n); void remove_goal(model_node& n); diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index 3dace0cdd..f9525b2f6 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -132,14 +132,13 @@ void lemma_quantifier_generalizer::find_candidates(expr *e, << " in " << mk_pp(e, m) << "\n";); extra.push_back(index); if (m_arith.is_add(index)) { - for (unsigned j = 0, asz = index->get_num_args(); j < asz; j++) { - expr *arg = index->get_arg(j); - if (!is_app(arg) || marked_args.is_marked(arg)) {continue;} - marked_args.mark(arg); - candidates.push_back (to_app(arg)); + for (expr * arg : *index) { + if (!is_app(arg) || marked_args.is_marked(arg)) {continue;} + marked_args.mark(arg); + candidates.push_back (to_app(arg)); + } } } - } std::sort(candidates.c_ptr(), candidates.c_ptr() + candidates.size(), index_lt_proc(m)); @@ -214,15 +213,15 @@ void lemma_quantifier_generalizer::cleanup(expr_ref_vector &cube, app_ref_vector bool found = false; expr_ref_vector kids(m); expr_ref_vector kids_bind(m); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - if (a->get_arg(i) == sk) { + for (expr* arg : *a) { + if (arg == sk) { found = true; - kids.push_back(a->get_arg(i)); + kids.push_back(arg); kids_bind.push_back(bind); } else { - kids.push_back (times_minus_one(a->get_arg(i), arith)); - kids_bind.push_back (times_minus_one(a->get_arg(i), arith)); + kids.push_back (times_minus_one(arg, arith)); + kids_bind.push_back (times_minus_one(arg, arith)); } } if (!found) continue; @@ -292,7 +291,7 @@ void lemma_quantifier_generalizer::mk_abs_cube(lemma_ref &lemma, app *term, var gnd_cube.push_back(lit); } else { - expr *e1, *e2; + expr *e1, *e2; // generalize v=num into v>=num if (m.is_eq(abs_lit, e1, e2) && (e1 == var || e2 == var)) { if (m_arith.is_numeral(e1)) { @@ -310,13 +309,13 @@ void lemma_quantifier_generalizer::mk_abs_cube(lemma_ref &lemma, app *term, var if (!lb && is_lb(var, abs_lit)) { lb = abs_lit; - } + } else if (!ub && is_ub(var, abs_lit)) { ub = abs_lit; + } } } } -} // -- returns true if e is an upper bound for var bool lemma_quantifier_generalizer::is_ub(var *var, expr *e) { @@ -348,38 +347,34 @@ bool lemma_quantifier_generalizer::is_ub(var *var, expr *e) { if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && m_arith.is_add(e1)) { app *a = to_app(e1); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - expr *arg = a->get_arg(i); - if (arg == var) {return true;} + for (expr* arg : *a) { + if (arg == var) return true; } } // t1 <= t2 + -1*var if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && m_arith.is_add(e2)) { app *a = to_app(e2); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - expr *arg = a->get_arg(i); + for (expr* arg : *a) { if (m_arith.is_times_minus_one(arg, arg) && arg == var) - {return true;} + return true; } } // t1 >= t2 + var if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && m_arith.is_add(e2)) { app *a = to_app(e2); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - expr *arg = a->get_arg(i); - if (arg == var) {return true;} + for (expr * arg : *a) { + if (arg == var) return true; } } // -1*var + t1 >= t2 if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && m_arith.is_add(e1)) { app *a = to_app(e1); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - expr *arg = a->get_arg(i); + for (expr * arg : *a) { if (m_arith.is_times_minus_one(arg, arg) && arg == var) - {return true;} + return true; } } return false; @@ -414,38 +409,34 @@ bool lemma_quantifier_generalizer::is_lb(var *var, expr *e) { if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && m_arith.is_add(e1)) { app *a = to_app(e1); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - expr *arg = a->get_arg(i); - if (arg == var) {return true;} + for (expr * arg : *a) { + if (arg == var) return true; } } // t1 >= t2 + -1*var if ((m_arith.is_ge(e, e1, e2) || m_arith.is_gt(e, e1, e2)) && m_arith.is_add(e2)) { app *a = to_app(e2); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - expr *arg = a->get_arg(i); + for (expr * arg : *a) { if (m_arith.is_times_minus_one(arg, arg) && arg == var) - {return true;} + return true; } } // t1 <= t2 + var if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && m_arith.is_add(e2)) { app *a = to_app(e2); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - expr *arg = a->get_arg(i); - if (arg == var) {return true;} + for (expr * arg : *a) { + if (arg == var) return true; } } // -1*var + t1 <= t2 if ((m_arith.is_le(e, e1, e2) || m_arith.is_lt(e, e1, e2)) && m_arith.is_add(e1)) { app *a = to_app(e1); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - expr *arg = a->get_arg(i); + for (expr * arg : *a) { if (m_arith.is_times_minus_one(arg, arg) && arg == var) - {return true;} + return true; } } @@ -470,22 +461,22 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { tout << "lb = "; if (lb) tout << mk_pp(lb, m); else tout << "none"; tout << "\n"; - tout << "ub = "; if (ub) tout << mk_pp(ub, m); else tout << "none"; tout << "\n";); - if (!lb && !ub) {return false;} + if (!lb && !ub) + return false; // -- guess lower or upper bound if missing if (!lb) { abs_cube.push_back (m_arith.mk_ge (var, term)); lb = abs_cube.back(); - } + } if (!ub) { abs_cube.push_back (m_arith.mk_lt(var, term)); ub = abs_cube.back(); - } + } rational init; expr_ref constant(m); @@ -511,7 +502,7 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { flatten_and(gnd, gnd_cube); TRACE("spacer_qgen", - tout << "New CUBE is: " << mk_pp(mk_and(gnd_cube),m) << "\n";); + tout << "New CUBE is: " << gnd_cube << "\n";); // check if the result is a true lemma unsigned uses_level = 0; @@ -519,8 +510,8 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { if (pt.check_inductive(lemma->level(), gnd_cube, uses_level, lemma->weakness())) { TRACE("spacer_qgen", tout << "Quantifier Generalization Succeeded!\n" - << "New CUBE is: " << mk_pp(mk_and(gnd_cube),m) << "\n";); - SASSERT(zks.size() >= m_offset); + << "New CUBE is: " << gnd_cube << "\n";); + SASSERT(zks.size() >= static_cast(m_offset)); // lift quantified variables to top of select expr_ref ext_bind(m); @@ -541,7 +532,7 @@ bool lemma_quantifier_generalizer::generalize (lemma_ref &lemma, app *term) { } lemma->update_cube(lemma->get_pob(), gnd_cube); - lemma->set_level(uses_level); + lemma->set_level(uses_level); SASSERT(var->get_idx() < zks.size()); SASSERT(is_app(ext_bind)); @@ -570,8 +561,7 @@ bool lemma_quantifier_generalizer::find_stride(expr_ref_vector &c, expr_ref &pat if (is_var(p_index)) return false; std::vector instances; - for (unsigned i=0; i < c.size(); i++) { - expr *lit = c.get(i); + for (expr* lit : c) { if (!contains_selects(lit, m)) continue; @@ -589,16 +579,17 @@ bool lemma_quantifier_generalizer::find_stride(expr_ref_vector &c, expr_ref &pat unsigned matched = 0; for (unsigned p=0; p < size; p++) { expr *arg = p_index->get_arg(p); - if (is_var(arg)) - { + if (is_var(arg)) { rational val; - if (p < candidate->get_num_args() && m_arith.is_numeral(candidate->get_arg(p), val)) { + if (p < candidate->get_num_args() && + m_arith.is_numeral(candidate->get_arg(p), val) && + val.is_unsigned()) { instances.push_back(val.get_unsigned()); } } else { - for (unsigned j=0; j < candidate->get_num_args(); j++) { - if (candidate->get_arg(j) == arg) { + for (expr* cand : *candidate) { + if (cand == arg) { matched++; break; } diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index a6ab01870..5b3420800 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -17,46 +17,36 @@ Revision History: --*/ #include +#include "ast/for_each_expr.h" +#include "ast/proofs/proof_utils.h" #include "muz/spacer/spacer_unsat_core_learner.h" #include "muz/spacer/spacer_unsat_core_plugin.h" #include "muz/spacer/spacer_iuc_proof.h" -#include "ast/for_each_expr.h" - -#include "ast/proofs/proof_utils.h" #include "muz/spacer/spacer_util.h" -namespace spacer -{ +namespace spacer { -unsat_core_learner::~unsat_core_learner() -{ +unsat_core_learner::~unsat_core_learner() { std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc()); } -void unsat_core_learner::register_plugin(unsat_core_plugin* plugin) -{ +void unsat_core_learner::register_plugin(unsat_core_plugin* plugin) { m_plugins.push_back(plugin); } -void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) -{ +void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { // traverse proof proof_post_order it(m_pr.get(), m); - while (it.hasNext()) - { + while (it.hasNext()) { proof* currentNode = it.next(); - if (m.get_num_parents(currentNode) > 0) - { + if (m.get_num_parents(currentNode) > 0) { bool need_to_mark_closed = true; - for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) - { - SASSERT(m.is_proof(currentNode->get_arg(i))); - proof* premise = to_app(currentNode->get_arg(i)); - - need_to_mark_closed = need_to_mark_closed && (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise)); + for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) { + proof* premise = m.get_parent(currentNode, i); + need_to_mark_closed &= (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise)); } // save result @@ -65,8 +55,9 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) // we have now collected all necessary information, so we can visit the node // if the node mixes A-reasoning and B-reasoning and contains non-closed premises - if (m_pr.is_a_marked(currentNode) && m_pr.is_b_marked(currentNode) && !m_closed.is_marked(currentNode)) - { + if (m_pr.is_a_marked(currentNode) && + m_pr.is_b_marked(currentNode) && + !m_closed.is_marked(currentNode)) { compute_partial_core(currentNode); // then we need to compute a partial core } } @@ -77,46 +68,38 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) // TODO: remove duplicates from unsat core? // move all lemmas into vector - for (expr* const* it = m_unsat_core.begin(); it != m_unsat_core.end(); ++it) - { - unsat_core.push_back(*it); + for (expr* e : m_unsat_core) { + unsat_core.push_back(e); } } -void unsat_core_learner::compute_partial_core(proof* step) -{ - for (unsat_core_plugin** it=m_plugins.begin(), **end = m_plugins.end (); it != end && !m_closed.is_marked(step); ++it) - { - unsat_core_plugin* plugin = *it; +void unsat_core_learner::compute_partial_core(proof* step) { + for (unsat_core_plugin* plugin : m_plugins) { + if (m_closed.is_marked(step)) break; plugin->compute_partial_core(step); } } -void unsat_core_learner::finalize() -{ - for (unsat_core_plugin** it=m_plugins.begin(); it != m_plugins.end(); ++it) - { - unsat_core_plugin* plugin = *it; +void unsat_core_learner::finalize() { + for (unsat_core_plugin* plugin : m_plugins) { plugin->finalize(); } } -bool unsat_core_learner::is_closed(proof*p) -{ +bool unsat_core_learner::is_closed(proof* p) { return m_closed.is_marked(p); } -void unsat_core_learner::set_closed(proof* p, bool value) -{ + +void unsat_core_learner::set_closed(proof* p, bool value) { m_closed.mark(p, value); } -bool unsat_core_learner::is_b_open(proof *p) -{ - return m_pr.is_b_marked(p) && !is_closed (p); +bool unsat_core_learner::is_b_open(proof *p) { + return m_pr.is_b_marked(p) && !is_closed (p); } -void unsat_core_learner::add_lemma_to_core(expr* lemma) -{ +void unsat_core_learner::add_lemma_to_core(expr* lemma) { m_unsat_core.push_back(lemma); } + } diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index a8b5965fc..327b12eb6 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -6,7 +6,8 @@ Module Name: spacer_unsat_core_learner.h Abstract: - itp cores + + itp cores Author: Bernhard Gleiss @@ -27,8 +28,7 @@ namespace spacer { class unsat_core_plugin; class iuc_proof; - class unsat_core_learner - { + class unsat_core_learner { typedef obj_hashtable expr_set; public: @@ -37,7 +37,7 @@ namespace spacer { virtual ~unsat_core_learner(); ast_manager& m; - iuc_proof& m_pr; + iuc_proof& m_pr; /* * register a plugin for computation of partial unsat cores @@ -56,7 +56,6 @@ namespace spacer { * - a node is closed, iff it has already been interpolated, i.e. its contribution is * already covered by the unsat-core. */ - bool is_closed(proof* p); void set_closed(proof* p, bool value); @@ -67,14 +66,14 @@ namespace spacer { */ void add_lemma_to_core(expr* lemma); - - private: ptr_vector m_plugins; ast_mark m_closed; - // collects the lemmas of the unsat-core - // will at the end be inserted into unsat_core. + /* + * collects the lemmas of the unsat-core + * will at the end be inserted into unsat_core. + */ expr_ref_vector m_unsat_core; /* @@ -86,9 +85,7 @@ namespace spacer { * finalize computation of unsat-core */ void finalize(); - }; - } #endif diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 557983628..25b12cf25 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -6,7 +6,7 @@ Module Name: spacer_unsat_core_plugin.cpp Abstract: - plugin for itp cores + plugin for itp cores Author: Bernhard Gleiss @@ -32,259 +32,213 @@ Revision History: #include "muz/spacer/spacer_unsat_core_learner.h" #include "muz/spacer/spacer_iuc_proof.h" -namespace spacer -{ +namespace spacer { + + unsat_core_plugin::unsat_core_plugin(unsat_core_learner& learner): + m(learner.m), m_learner(learner) {}; + -void unsat_core_plugin_lemma::compute_partial_core(proof* step) -{ - SASSERT(m_learner.m_pr.is_a_marked(step)); - SASSERT(m_learner.m_pr.is_b_marked(step)); - - for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) - { - SASSERT(m_learner.m.is_proof(step->get_arg(i))); - proof* premise = to_app(step->get_arg(i)); - - if (m_learner.is_b_open (premise)) - { - // by IH, premises that are AB marked are already closed - SASSERT(!m_learner.m_pr.is_a_marked(premise)); - add_lowest_split_to_core(premise); - } - } - m_learner.set_closed(step, true); -} - -void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const -{ - SASSERT(m_learner.is_b_open(step)); - ast_manager &m = m_learner.m; - - ptr_vector todo; - todo.push_back(step); - - while (!todo.empty()) - { - proof* pf = todo.back(); - todo.pop_back(); - - // if current step hasn't been processed, - if (!m_learner.is_closed(pf)) - { - m_learner.set_closed(pf, true); - // the step is b-marked and not closed. - // by I.H. the step must be already visited - // so if it is also a-marked, it must be closed - SASSERT(m_learner.m_pr.is_b_marked(pf)); - SASSERT(!m_learner.m_pr.is_a_marked(pf)); - - // the current step needs to be interpolated: - expr* fact = m_learner.m.get_fact(pf); - // if we trust the current step and we are able to use it - if (m_learner.m_pr.is_b_pure (pf) && - (m.is_asserted(pf) || is_literal(m, fact))) - { - // just add it to the core - m_learner.add_lemma_to_core(fact); - } - // otherwise recurse on premises - else - { - for (unsigned i = 0, sz = m_learner.m.get_num_parents(pf); - i < sz; ++i) - { - SASSERT(m_learner.m.is_proof(pf->get_arg(i))); - proof* premise = m.get_parent (pf, i); - if (m_learner.is_b_open(premise)) { - todo.push_back(premise); - } - } - } - - } - } -} - - -void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step) -{ - ast_manager &m = m_learner.m; - SASSERT(m_learner.m_pr.is_a_marked(step)); - SASSERT(m_learner.m_pr.is_b_marked(step)); - // XXX this assertion should be true so there is no need to check for it - SASSERT (!m_learner.is_closed (step)); - func_decl* d = step->get_decl(); - symbol sym; - if(!m_learner.is_closed(step) && // if step is not already interpolated - step->get_decl_kind() == PR_TH_LEMMA && // and step is a Farkas lemma - d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas" && - d->get_num_parameters() >= m_learner.m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients - { - SASSERT(m_learner.m.has_fact(step)); - - ptr_vector literals; - vector coefficients; - - /* The farkas lemma represents a subproof starting from premise(-set)s A, BNP and BP(ure) and - * ending in a disjunction D. We need to compute the contribution of BP, i.e. a formula, which - * is entailed by BP and together with A and BNP entails D. - * - * Let Fark(F) be the farkas coefficient for F. We can use the fact that - * (A*Fark(A) + BNP*Fark(BNP) + BP*Fark(BP) + (neg D)*Fark(D)) => false. (E1) - * We further have that A+B => C implies (A \land B) => C. (E2) - * - * Alternative 1: - * From (E1) immediately get that BP*Fark(BP) is a solution. - * - * Alternative 2: - * We can rewrite (E2) to rewrite (E1) to - * (BP*Fark(BP)) => (neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D))) (E3) - * and since we can derive (A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) from - * A, BNP and D, we also know that it is inconsisent. Therefore - * neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) is a solution. - * - * Finally we also need the following workaround: - * 1) Although we know from theory, that the Farkas coefficients are always nonnegative, - * the Farkas coefficients provided by arith_core are sometimes negative (must be a bug) - * as workaround we take the absolute value of the provided coefficients. - */ - parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient - - STRACE("spacer.farkas", - verbose_stream() << "Farkas input: "<< "\n"; - for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) - { - SASSERT(m_learner.m.is_proof(step->get_arg(i))); - proof *prem = m.get_parent (step, i); - - rational coef; - VERIFY(params[i].is_rational(coef)); - - bool b_pure = m_learner.m_pr.is_b_pure (prem); - verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m_learner.m.get_fact(prem), m_learner.m) << "\n"; - } - ); - - bool can_be_closed = true; - - for(unsigned i = 0; i < m.get_num_parents(step); ++i) - { - SASSERT(m_learner.m.is_proof(step->get_arg(i))); - proof * premise = m.get_parent (step, i); - - if (m_learner.is_b_open (premise)) - { + void unsat_core_plugin_lemma::compute_partial_core(proof* step) { + SASSERT(m_learner.m_pr.is_a_marked(step)); + SASSERT(m_learner.m_pr.is_b_marked(step)); + + for (proof* premise : m.get_parents(step)) { + + if (m_learner.is_b_open (premise)) { + // by IH, premises that are AB marked are already closed SASSERT(!m_learner.m_pr.is_a_marked(premise)); + add_lowest_split_to_core(premise); + } + } + m_learner.set_closed(step, true); + } + + void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const + { + SASSERT(m_learner.is_b_open(step)); + + ptr_buffer todo; + todo.push_back(step); + + while (!todo.empty()) { + proof* pf = todo.back(); + todo.pop_back(); + + // if current step hasn't been processed, + if (!m_learner.is_closed(pf)) { + m_learner.set_closed(pf, true); + // the step is b-marked and not closed. + // by I.H. the step must be already visited + // so if it is also a-marked, it must be closed + SASSERT(m_learner.m_pr.is_b_marked(pf)); + SASSERT(!m_learner.m_pr.is_a_marked(pf)); + + // the current step needs to be interpolated: + expr* fact = m.get_fact(pf); + // if we trust the current step and we are able to use it + if (m_learner.m_pr.is_b_pure (pf) && + (m.is_asserted(pf) || is_literal(m, fact))) { + // just add it to the core + m_learner.add_lemma_to_core(fact); + } + // otherwise recurse on premises + else { + for (proof* premise : m.get_parents(pf)) + if (m_learner.is_b_open(premise)) + todo.push_back(premise); + } + + } + } + } - if (m_learner.m_pr.is_b_pure (step)) - { - if (!m_use_constant_from_a) - { - rational coefficient; - VERIFY(params[i].is_rational(coefficient)); - literals.push_back(to_app(m_learner.m.get_fact(premise))); - coefficients.push_back(abs(coefficient)); + + void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step) + { + SASSERT(m_learner.m_pr.is_a_marked(step)); + SASSERT(m_learner.m_pr.is_b_marked(step)); + // XXX this assertion should be true so there is no need to check for it + SASSERT (!m_learner.is_closed (step)); + func_decl* d = step->get_decl(); + symbol sym; + if (!m_learner.is_closed(step) && // if step is not already interpolated + step->get_decl_kind() == PR_TH_LEMMA && // and step is a Farkas lemma + d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step + d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", + d->get_parameter(1).is_symbol(sym) && sym == "farkas" && + d->get_num_parameters() >= m.get_num_parents(step) + 2) { // the following parameters are the Farkas coefficients + + SASSERT(m.has_fact(step)); + + coeff_lits_t coeff_lits; + expr_ref_vector pinned(m); + + /* The farkas lemma represents a subproof starting from premise(-set)s A, BNP and BP(ure) and + * ending in a disjunction D. We need to compute the contribution of BP, i.e. a formula, which + * is entailed by BP and together with A and BNP entails D. + * + * Let Fark(F) be the farkas coefficient for F. We can use the fact that + * (A*Fark(A) + BNP*Fark(BNP) + BP*Fark(BP) + (neg D)*Fark(D)) => false. (E1) + * We further have that A+B => C implies (A \land B) => C. (E2) + * + * Alternative 1: + * From (E1) immediately get that BP*Fark(BP) is a solution. + * + * Alternative 2: + * We can rewrite (E2) to rewrite (E1) to + * (BP*Fark(BP)) => (neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D))) (E3) + * and since we can derive (A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) from + * A, BNP and D, we also know that it is inconsisent. Therefore + * neg(A*Fark(A) + BNP*Fark(BNP) + (neg D)*Fark(D)) is a solution. + * + * Finally we also need the following workaround: + * 1) Although we know from theory, that the Farkas coefficients are always nonnegative, + * the Farkas coefficients provided by arith_core are sometimes negative (must be a bug) + * as workaround we take the absolute value of the provided coefficients. + */ + parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient + + STRACE("spacer.farkas", + verbose_stream() << "Farkas input: "<< "\n"; + for (unsigned i = 0; i < m.get_num_parents(step); ++i) { + proof * prem = m.get_parent(step, i); + + rational coef = params[i].get_rational(); + + bool b_pure = m_learner.m_pr.is_b_pure (prem); + verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m_learner.m) << "\n"; + } + ); + + bool can_be_closed = true; + + for (unsigned i = 0; i < m.get_num_parents(step); ++i) { + proof * premise = m.get_parent(step, i); + + if (m_learner.is_b_open (premise)) { + SASSERT(!m_learner.m_pr.is_a_marked(premise)); + + if (m_learner.m_pr.is_b_pure (step)) { + if (!m_use_constant_from_a) { + rational coefficient = params[i].get_rational(); + coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise))); + } + } + else { + can_be_closed = false; + + if (m_use_constant_from_a) { + rational coefficient = params[i].get_rational(); + coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise))); + } } } - else - { - can_be_closed = false; - - if (m_use_constant_from_a) - { - rational coefficient; - VERIFY(params[i].is_rational(coefficient)); - literals.push_back(to_app(m_learner.m.get_fact(premise))); - coefficients.push_back(abs(coefficient)); + else { + if (m_use_constant_from_a) { + rational coefficient = params[i].get_rational(); + coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise))); } } } - else - { - if (m_use_constant_from_a) - { - rational coefficient; - VERIFY(params[i].is_rational(coefficient)); - literals.push_back(to_app(m_learner.m.get_fact(premise))); - coefficients.push_back(abs(coefficient)); + + if (m_use_constant_from_a) { + params += m.get_num_parents(step); // point to the first Farkas coefficient, which corresponds to a formula in the conclusion + + // the conclusion can either be a single formula or a disjunction of several formulas, we have to deal with both situations + if (m.get_num_parents(step) + 2 < d->get_num_parameters()) { + unsigned num_args = 1; + expr* conclusion = m.get_fact(step); + expr* const* args = &conclusion; + if (m.is_or(conclusion)) { + app* _or = to_app(conclusion); + num_args = _or->get_num_args(); + args = _or->get_args(); + } + SASSERT(m.get_num_parents(step) + 2 + num_args == d->get_num_parameters()); + + bool_rewriter brw(m_learner.m); + for (unsigned i = 0; i < num_args; ++i) { + expr* premise = args[i]; + + expr_ref negatedPremise(m_learner.m); + brw.mk_not(premise, negatedPremise); + pinned.push_back(negatedPremise); + rational coefficient = params[i].get_rational(); + coeff_lits.push_back(std::make_pair(abs(coefficient), to_app(negatedPremise))); + } } } - } - if (m_use_constant_from_a) - { - params += m_learner.m.get_num_parents(step); // point to the first Farkas coefficient, which corresponds to a formula in the conclusion - - // the conclusion can either be a single formula or a disjunction of several formulas, we have to deal with both situations - if (m_learner.m.get_num_parents(step) + 2 < d->get_num_parameters()) - { - unsigned num_args = 1; - expr* conclusion = m_learner.m.get_fact(step); - expr* const* args = &conclusion; - if (m_learner.m.is_or(conclusion)) - { - app* _or = to_app(conclusion); - num_args = _or->get_num_args(); - args = _or->get_args(); - } - SASSERT(m_learner.m.get_num_parents(step) + 2 + num_args == d->get_num_parameters()); - - bool_rewriter brw(m_learner.m); - for (unsigned i = 0; i < num_args; ++i) - { - expr* premise = args[i]; - - expr_ref negatedPremise(m_learner.m); - brw.mk_not(premise, negatedPremise); - literals.push_back(to_app(negatedPremise)); - - rational coefficient; - VERIFY(params[i].is_rational(coefficient)); - coefficients.push_back(abs(coefficient)); - } + // only if all b-premises can be used directly, add the farkas core and close the step + if (can_be_closed) { + m_learner.set_closed(step, true); + + expr_ref res = compute_linear_combination(coeff_lits); + + m_learner.add_lemma_to_core(res); } } + } - // only if all b-premises can be used directly, add the farkas core and close the step - if (can_be_closed) - { - m_learner.set_closed(step, true); + expr_ref unsat_core_plugin_farkas_lemma::compute_linear_combination(const coeff_lits_t& coeff_lits) + { - expr_ref res(m_learner.m); - compute_linear_combination(coefficients, literals, res); - - m_learner.add_lemma_to_core(res); + smt::farkas_util util(m); + if (m_use_constant_from_a) { + util.set_split_literals (m_split_literals); // small optimization: if flag m_split_literals is set, then preserve diff constraints + } + for (auto& p : coeff_lits) { + util.add(p.first, p.second); + } + if (m_use_constant_from_a) { + return util.get(); + } + else { + expr_ref negated_linear_combination = util.get(); + return expr_ref(mk_not(m, negated_linear_combination), m); } } -} - -void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector& coefficients, const ptr_vector& literals, expr_ref& res) -{ - SASSERT(literals.size() == coefficients.size()); - - ast_manager& m = res.get_manager(); - smt::farkas_util util(m); - if (m_use_constant_from_a) - { - util.set_split_literals (m_split_literals); // small optimization: if flag m_split_literals is set, then preserve diff constraints - } - for(unsigned i = 0; i < literals.size(); ++i) - { - util.add(coefficients[i], literals[i]); - } - if (m_use_constant_from_a) - { - res = util.get(); - } - else - { - expr_ref negated_linear_combination = util.get(); - res = mk_not(m, negated_linear_combination); - } -} void unsat_core_plugin_farkas_lemma_optimized::compute_partial_core(proof* step) { @@ -298,34 +252,29 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vectorget_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", d->get_parameter(1).is_symbol(sym) && sym == "farkas" && - d->get_num_parameters() >= m_learner.m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients + d->get_num_parameters() >= m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients { - SASSERT(m_learner.m.has_fact(step)); + SASSERT(m.has_fact(step)); vector > linear_combination; // collects all summands of the linear combination parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient STRACE("spacer.farkas", - verbose_stream() << "Farkas input: "<< "\n"; - for (unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) - { - SASSERT(m_learner.m.is_proof(step->get_arg(i))); - proof *prem = m.get_parent (step, i); + verbose_stream() << "Farkas input: "<< "\n"; + for (unsigned i = 0; i < m.get_num_parents(step); ++i) { + proof * prem = m.get_parent(step, i); - rational coef; - VERIFY(params[i].is_rational(coef)); - - bool b_pure = m_learner.m_pr.is_b_pure (prem); - verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m_learner.m.get_fact(prem), m_learner.m) << "\n"; - } - ); + rational coef = params[i].get_rational(); + + bool b_pure = m_learner.m_pr.is_b_pure (prem); + verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m_learner.m) << "\n"; + } + ); bool can_be_closed = true; - for(unsigned i = 0; i < m_learner.m.get_num_parents(step); ++i) - { - SASSERT(m_learner.m.is_proof(step->get_arg(i))); - proof * premise = m.get_parent (step, i); + for (unsigned i = 0; i < m.get_num_parents(step); ++i) { + proof * premise = m.get_parent(step, i); if (m_learner.m_pr.is_b_marked(premise) && !m_learner.is_closed(premise)) { @@ -333,10 +282,9 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector 0); + SASSERT(!linear_combination.empty()); }); // 1. construct ordered basis ptr_vector ordered_basis; obj_map map; unsigned counter = 0; - for (const auto& linear_combination : m_linear_combinations) - { - for (const auto& pair : linear_combination) - { - if (!map.contains(pair.first)) - { + for (const auto& linear_combination : m_linear_combinations) { + for (const auto& pair : linear_combination) { + if (!map.contains(pair.first)) { ordered_basis.push_back(pair.first); map.insert(pair.first, counter++); } @@ -396,11 +341,9 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector literals; - vector coefficients; - for (unsigned l=0; l < matrix.num_cols(); ++l) - { - if (!matrix.get(k,l).is_zero()) - { - literals.push_back(ordered_basis[l]); - coefficients.push_back(matrix.get(k,l)); + coeff_lits_t coeff_lits; + for (unsigned l = 0; l < matrix.num_cols(); ++l) { + if (!matrix.get(k,l).is_zero()) { + coeff_lits.push_back(std::make_pair(matrix.get(k, l), ordered_basis[l])); + } } - } - SASSERT(literals.size() > 0); - expr_ref linear_combination(m); - compute_linear_combination(coefficients, literals, linear_combination); + SASSERT(!coeff_lits.empty()); + expr_ref linear_combination = compute_linear_combination(coeff_lits); m_learner.add_lemma_to_core(linear_combination); } } - void unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const vector& coefficients, const ptr_vector& literals, expr_ref& res) - { - SASSERT(literals.size() == coefficients.size()); + expr_ref unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const coeff_lits_t& coeff_lits) + { + + smt::farkas_util util(m); + for (auto const & p : coeff_lits) { + util.add(p.first, p.second); + } + expr_ref negated_linear_combination = util.get(); + SASSERT(m.is_not(negated_linear_combination)); + return expr_ref(mk_not(m, negated_linear_combination), m); + //TODO: rewrite the get-method to return nonnegated stuff? + } - ast_manager& m = res.get_manager(); - smt::farkas_util util(m); - for(unsigned i = 0; i < literals.size(); ++i) - { - util.add(coefficients[i], literals[i]); - } - expr_ref negated_linear_combination = util.get(); - SASSERT(m.is_not(negated_linear_combination)); - res = mk_not(m, negated_linear_combination); //TODO: rewrite the get-method to return nonnegated stuff? - } - - - void unsat_core_plugin_farkas_lemma_bounded::finalize() { + void unsat_core_plugin_farkas_lemma_bounded::finalize() { if (m_linear_combinations.empty()) { return; } @@ -486,13 +421,12 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector coeffs; - for (unsigned i=0; i < matrix.num_rows(); ++i) { + for (unsigned i = 0; i < matrix.num_rows(); ++i) { coeffs.push_back(expr_ref_vector(m)); } vector bounded_vectors; - for (unsigned j=0; j < matrix.num_cols(); ++j) - { + for (unsigned j = 0; j < matrix.num_cols(); ++j) { bounded_vectors.push_back(expr_ref_vector(m)); } @@ -501,37 +435,24 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector s = mk_smt_solver(m, p, symbol::null); // TODO: incremental version? + solver_ref s = mk_smt_solver(m, p, symbol::null); // TODO: incremental version? // add new variables w_in, - for (unsigned i=0; i < matrix.num_rows(); ++i) - { + for (unsigned i = 0; i < matrix.num_rows(); ++i) { std::string name = "w_" + std::to_string(i) + std::to_string(n); - - func_decl_ref decl(m); - decl = m.mk_func_decl(symbol(name.c_str()), 0, (sort*const*)nullptr, util.mk_int()); - coeffs[i].push_back(m.mk_const(decl)); + coeffs[i].push_back(m.mk_const(name, util.mk_int())); } // we need s_jn - for (unsigned j=0; j < matrix.num_cols(); ++j) - { + for (unsigned j = 0; j < matrix.num_cols(); ++j) { std::string name = "s_" + std::to_string(j) + std::to_string(n); - - func_decl_ref decl(m); - decl = m.mk_func_decl(symbol(name.c_str()), 0, (sort*const*)nullptr, util.mk_int()); - - expr_ref s_jn(m); - s_jn = m.mk_const(decl); - - bounded_vectors[j].push_back(s_jn); + bounded_vectors[j].push_back(m.mk_const(name, util.mk_int())); } // assert bounds for all s_jn - for (unsigned l=0; l < n; ++l) { - for (unsigned j=0; j < matrix.num_cols(); ++j) { + for (unsigned l = 0; l < n; ++l) { + for (unsigned j = 0; j < matrix.num_cols(); ++j) { expr* s_jn = bounded_vectors[j][l].get(); - expr_ref lb(util.mk_le(util.mk_int(0), s_jn), m); expr_ref ub(util.mk_le(s_jn, util.mk_int(1)), m); s->assert_expr(lb); @@ -540,47 +461,40 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vectorassert_expr(eq); } + expr_ref eq(m.mk_eq(a_ij, sum), m); + s->assert_expr(eq); } - + } + // check result - lbool res = s->check_sat(0,nullptr); + lbool res = s->check_sat(0, nullptr); // if sat extract model and add corresponding linear combinations to core if (res == lbool::l_true) { model_ref model; s->get_model(model); - for (unsigned k=0; k < n; ++k) { - ptr_vector literals; - vector coefficients; - for (unsigned j=0; j < matrix.num_cols(); ++j) { + for (unsigned k = 0; k < n; ++k) { + coeff_lits_t coeff_lits; + for (unsigned j = 0; j < matrix.num_cols(); ++j) { expr_ref evaluation(m); model.get()->eval(bounded_vectors[j][k].get(), evaluation, false); if (!util.is_zero(evaluation)) { - literals.push_back(ordered_basis[j]); - coefficients.push_back(rational(1)); + coeff_lits.push_back(std::make_pair(rational(1), ordered_basis[j])); } } - SASSERT(!literals.empty()); // since then previous outer loop would have found solution already - expr_ref linear_combination(m); - compute_linear_combination(coefficients, literals, linear_combination); + SASSERT(!coeff_lits.empty()); // since then previous outer loop would have found solution already + expr_ref linear_combination = compute_linear_combination(coeff_lits); m_learner.add_lemma_to_core(linear_combination); } @@ -589,7 +503,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector todo_subproof; + ptr_buffer todo_subproof; - for (unsigned i = 0, sz = m.get_num_parents(step); i < sz; ++i) - { - proof* premise = m.get_parent (step, i); - { - if (m_learner.m_pr.is_b_marked(premise)) - { - todo_subproof.push_back(premise); - } + for (proof* premise : m.get_parents(step)) { + if (m_learner.m_pr.is_b_marked(premise)) { + todo_subproof.push_back(premise); } } while (!todo_subproof.empty()) @@ -685,10 +593,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vectorget_arg(i))); - proof* premise = m.get_parent (current, i); + for (proof* premise : m.get_parents(current)) { todo_subproof.push_back(premise); } } @@ -790,8 +695,8 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector> coeff_lits_t; + ast_manager& m; public: - unsat_core_plugin(unsat_core_learner& learner) : m_learner(learner){}; - virtual ~unsat_core_plugin(){}; + unsat_core_plugin(unsat_core_learner& learner); + virtual ~unsat_core_plugin() {}; virtual void compute_partial_core(proof* step) = 0; virtual void finalize(){}; @@ -68,24 +70,23 @@ private: /* * compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res */ - void compute_linear_combination(const vector& coefficients, const ptr_vector& literals, expr_ref& res); + expr_ref compute_linear_combination(const coeff_lits_t& coeff_lits); }; class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin { public: - unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner), m(m) {}; + unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {}; void compute_partial_core(proof* step) override; void finalize() override; protected: vector > > m_linear_combinations; - ast_manager& m; /* * compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res */ - void compute_linear_combination(const vector& coefficients, const ptr_vector& literals, expr_ref& res); + expr_ref compute_linear_combination(const coeff_lits_t& coeff_lits); }; class unsat_core_plugin_farkas_lemma_bounded : public unsat_core_plugin_farkas_lemma_optimized { @@ -104,7 +105,6 @@ private: void compute_partial_core(proof* step) override; void finalize() override; private: - ast_manager& m; ast_mark m_visited; // saves for each node i whether the subproof with root i has already been added to the min-cut-problem obj_map m_proof_to_node_minus; // maps proof-steps to the corresponding minus-nodes (the ones which are closer to source) diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 716c68b00..762735b8d 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -47,7 +47,7 @@ public: virtual ~check_sat_result() {} void inc_ref() { m_ref_count++; } void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); } - void set_status(lbool r) { m_status = r; } + lbool set_status(lbool r) { return m_status = r; } lbool status() const { return m_status; } virtual void collect_statistics(statistics & st) const = 0; virtual void get_unsat_core(ptr_vector & r) = 0; From 54add824e900983b09d327f4a1745bec2b91f3ad Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 6 Jun 2018 09:34:03 -0700 Subject: [PATCH 1146/1283] Debug print --- src/muz/spacer/spacer_pdr.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index 89647ed02..7ead97628 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -246,8 +246,8 @@ lbool context::gpdr_solve_core() { } // communicate failure to datalog::context - if (m_context) { - m_context->set_status(datalog::BOUNDED); + if (m_context) { + m_context->set_status(datalog::BOUNDED); } return l_undef; } @@ -279,7 +279,7 @@ bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) { TRACE("spacer_pdr", tout << "looking at pob at level " << pob->level() << " " << mk_pp(pob->post(), m) << "\n";); - if (pob != node->pob()) + if (pob != node->pob()) ms.add_leaf(alloc(model_node, node, pob)); } node->check_pre_closed(); @@ -332,6 +332,13 @@ bool context::gpdr_create_split_children(pob &n, const datalog::rule &r, << (k->use_farkas_generalizer() ? "FAR " : "SUB ") << k->post()->get_id(); verbose_stream().flush();); + TRACE ("spacer", + tout << "create-pob: " << k->pt().head()->get_name() + << " level: " << k->level() + << " depth: " << k->depth () + << " fvsz: " << k->get_free_vars_size() << "\n" + << mk_pp(k->post(), m) << "\n";); + } From f74ca2f0c085a3a9406eeea1d046488a29b3bfdb Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 6 Jun 2018 09:40:59 -0700 Subject: [PATCH 1147/1283] Fix caching bug in mbc --- src/muz/spacer/spacer_mbc.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/muz/spacer/spacer_mbc.cpp b/src/muz/spacer/spacer_mbc.cpp index 4708a6a4e..df0ce1cb4 100644 --- a/src/muz/spacer/spacer_mbc.cpp +++ b/src/muz/spacer/spacer_mbc.cpp @@ -17,16 +17,17 @@ class mbc_rewriter_cfg : public default_rewriter_cfg { ast_manager &m; const mbc::partition_map &m_pmap; + obj_map &m_subs; model &m_mdl; model_evaluator m_mev; vector &m_parts; unsigned m_current_part; - obj_map m_subs; public: mbc_rewriter_cfg(ast_manager &m, const mbc::partition_map &pmap, + obj_map &subs, model &mdl, vector &parts) : - m(m), m_pmap(pmap), m_mdl(mdl), m_mev(m_mdl), + m(m), m_pmap(pmap), m_subs(subs), m_mdl(mdl), m_mev(m_mdl), m_parts(parts), m_current_part(UINT_MAX) {m_mev.set_model_completion(true);} @@ -56,7 +57,7 @@ public: // eval in the model m_mev.eval(s, val, true); - // store decided equality (also keeps ref to s and val + // store decided equality (also keeps ref to s and val) m_parts[part].push_back(m.mk_eq(s, val)); // store substitution m_subs.insert(s, val); @@ -64,6 +65,8 @@ public: return true; } + + void reset() {reset_partition();}; void reset_partition() {m_current_part = UINT_MAX;} unsigned partition() {return m_current_part;} bool found_partition() {return m_current_part < UINT_MAX;} @@ -75,13 +78,14 @@ void mbc::operator()(const partition_map &pmap, expr_ref_vector &lits, model &mdl, vector &res) { scoped_no_proof _sp (m); - mbc_rewriter_cfg cfg(m, pmap, mdl, res); + obj_map subs; + mbc_rewriter_cfg cfg(m, pmap, subs, mdl, res); rewriter_tpl rw(m, false, cfg); th_rewriter thrw(m); for (auto *lit : lits) { expr_ref new_lit(m); - cfg.reset_partition(); + rw.reset(); rw(lit, new_lit); thrw(new_lit); if (cfg.found_partition()) { @@ -89,6 +93,10 @@ void mbc::operator()(const partition_map &pmap, expr_ref_vector &lits, res[cfg.partition()].push_back(new_lit); } } + + TRACE("mbc", tout << "Input: " << lits << "\n" + << "Output: \n"; + for (auto &vec : res) tout << vec << "\n==================\n";); } } From 9fef466c634f71fca813575d4ff9b972a72728f9 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 6 Jun 2018 10:10:00 -0700 Subject: [PATCH 1148/1283] Respect children order in spacer/pdr --- src/muz/spacer/spacer_pdr.cpp | 38 +++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index 7ead97628..d1b634350 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -318,20 +318,17 @@ bool context::gpdr_create_split_children(pob &n, const datalog::rule &r, vector res(preds.size(), expr_ref_vector(m)); _mbc(pmap, lits, *mdl.get(), res); + // pick an order to process children + unsigned_vector kid_order; + kid_order.resize(preds.size(), 0); + for (unsigned i = 0, sz = preds.size(); i < sz; ++i) kid_order[i] = i; + if (m_children_order == CO_REV_RULE) { + kid_order.reverse(); + } + else if (m_children_order == CO_RANDOM) { + shuffle(kid_order.size(), kid_order.c_ptr(), m_random); + } - for (unsigned i = 0, sz = res.size(); i < sz; ++i) { - expr_ref post(m); - pred_transformer &ppt = *ppts.get(i); - post = mk_and(res.get(i)); - m_pm.formula_o2n(post.get(), post, i, true); - pob * k = ppt.mk_pob(&n, prev_level(n.level()), n.depth(), post); - out.push_back(k); - IF_VERBOSE (1, verbose_stream() - << "\n\tcreate_child: " << k->pt().head()->get_name() - << " (" << k->level() << ", " << k->depth() << ") " - << (k->use_farkas_generalizer() ? "FAR " : "SUB ") - << k->post()->get_id(); - verbose_stream().flush();); TRACE ("spacer", tout << "create-pob: " << k->pt().head()->get_name() << " level: " << k->level() @@ -346,4 +343,19 @@ bool context::gpdr_create_split_children(pob &n, const datalog::rule &r, } + + for (unsigned i = 0, sz = res.size(); i < sz; ++i) { + unsigned j = kid_order[i]; + expr_ref post(m); + pred_transformer &ppt = *ppts.get(j); + post = mk_and(res.get(j)); + m_pm.formula_o2n(post.get(), post, j, true); + pob * k = ppt.mk_pob(&n, prev_level(n.level()), n.depth(), post); + out.push_back(k); + IF_VERBOSE (1, verbose_stream() + << "\n\tcreate_child: " << k->pt().head()->get_name() + << " (" << k->level() << ", " << k->depth() << ") " + << (k->use_farkas_generalizer() ? "FAR " : "SUB ") + << k->post()->get_id(); + verbose_stream().flush();); } // spacer From cefdb8c01dbeb59cfdf1a8fc21c4620d27d63baf Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 6 Jun 2018 10:10:35 -0700 Subject: [PATCH 1149/1283] Use reachable cache --- src/muz/spacer/spacer_pdr.cpp | 42 +++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index d1b634350..6b13e82f8 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -264,6 +264,20 @@ bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) { << node->level() << "\n";); new_pobs.reset(); checkpoint(); + pred_transformer &pt = node->pt(); + + // check reachable cache + if (pt.is_must_reachable(node->pob()->post(), nullptr)) { + TRACE("spacer", + tout << "must-reachable: " << pt.head()->get_name() << " level: " + << node->level() << " depth: " << node->depth () << "\n"; + tout << mk_pp(node->pob()->post(), m) << "\n";); + + node->set_closed(); + if (node == root_node) return true; + continue; + } + switch (expand_pob(*node->pob(), new_pobs)){ case l_true: node->set_closed(); @@ -329,20 +343,6 @@ bool context::gpdr_create_split_children(pob &n, const datalog::rule &r, shuffle(kid_order.size(), kid_order.c_ptr(), m_random); } - TRACE ("spacer", - tout << "create-pob: " << k->pt().head()->get_name() - << " level: " << k->level() - << " depth: " << k->depth () - << " fvsz: " << k->get_free_vars_size() << "\n" - << mk_pp(k->post(), m) << "\n";); - - - } - - return true; -} - - for (unsigned i = 0, sz = res.size(); i < sz; ++i) { unsigned j = kid_order[i]; @@ -358,4 +358,18 @@ bool context::gpdr_create_split_children(pob &n, const datalog::rule &r, << (k->use_farkas_generalizer() ? "FAR " : "SUB ") << k->post()->get_id(); verbose_stream().flush();); + TRACE ("spacer", + tout << "create-pob: " << k->pt().head()->get_name() + << " level: " << k->level() + << " depth: " << k->depth () + << " fvsz: " << k->get_free_vars_size() << "\n" + << mk_pp(k->post(), m) << "\n";); + + + } + + return true; +} + + } // spacer From 6adaed718f52a5f8a8d819453f6dcff91402e43d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 13:11:48 -0700 Subject: [PATCH 1150/1283] remove pdr Signed-off-by: Nikolaj Bjorner --- src/CMakeLists.txt | 1 - src/muz/base/dl_context.cpp | 31 +- src/muz/base/dl_engine_base.h | 2 - src/muz/base/fixedpoint_params.pyg | 132 +- src/muz/fp/CMakeLists.txt | 1 - src/muz/fp/dl_register_engine.cpp | 4 - src/muz/pdr/CMakeLists.txt | 20 - src/muz/pdr/pdr_closure.cpp | 177 -- src/muz/pdr/pdr_closure.h | 67 - src/muz/pdr/pdr_context.cpp | 2431 ----------------------- src/muz/pdr/pdr_context.h | 448 ----- src/muz/pdr/pdr_dl_interface.cpp | 225 --- src/muz/pdr/pdr_dl_interface.h | 78 - src/muz/pdr/pdr_farkas_learner.cpp | 1012 ---------- src/muz/pdr/pdr_farkas_learner.h | 128 -- src/muz/pdr/pdr_generalizers.cpp | 777 -------- src/muz/pdr/pdr_generalizers.h | 110 - src/muz/pdr/pdr_manager.cpp | 321 --- src/muz/pdr/pdr_manager.h | 304 --- src/muz/pdr/pdr_prop_solver.cpp | 459 ----- src/muz/pdr/pdr_prop_solver.h | 139 -- src/muz/pdr/pdr_reachable_cache.cpp | 132 -- src/muz/pdr/pdr_reachable_cache.h | 66 - src/muz/pdr/pdr_smt_context_manager.cpp | 167 -- src/muz/pdr/pdr_smt_context_manager.h | 92 - src/muz/pdr/pdr_sym_mux.cpp | 601 ------ src/muz/pdr/pdr_sym_mux.h | 247 --- src/muz/pdr/pdr_util.cpp | 508 ----- src/muz/pdr/pdr_util.h | 81 - 29 files changed, 70 insertions(+), 8691 deletions(-) delete mode 100644 src/muz/pdr/CMakeLists.txt delete mode 100644 src/muz/pdr/pdr_closure.cpp delete mode 100644 src/muz/pdr/pdr_closure.h delete mode 100644 src/muz/pdr/pdr_context.cpp delete mode 100644 src/muz/pdr/pdr_context.h delete mode 100644 src/muz/pdr/pdr_dl_interface.cpp delete mode 100644 src/muz/pdr/pdr_dl_interface.h delete mode 100644 src/muz/pdr/pdr_farkas_learner.cpp delete mode 100644 src/muz/pdr/pdr_farkas_learner.h delete mode 100644 src/muz/pdr/pdr_generalizers.cpp delete mode 100644 src/muz/pdr/pdr_generalizers.h delete mode 100644 src/muz/pdr/pdr_manager.cpp delete mode 100644 src/muz/pdr/pdr_manager.h delete mode 100644 src/muz/pdr/pdr_prop_solver.cpp delete mode 100644 src/muz/pdr/pdr_prop_solver.h delete mode 100644 src/muz/pdr/pdr_reachable_cache.cpp delete mode 100644 src/muz/pdr/pdr_reachable_cache.h delete mode 100644 src/muz/pdr/pdr_smt_context_manager.cpp delete mode 100644 src/muz/pdr/pdr_smt_context_manager.h delete mode 100644 src/muz/pdr/pdr_sym_mux.cpp delete mode 100644 src/muz/pdr/pdr_sym_mux.h delete mode 100644 src/muz/pdr/pdr_util.cpp delete mode 100644 src/muz/pdr/pdr_util.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9020c9e4b..7dee4039a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,7 +81,6 @@ add_subdirectory(muz/base) add_subdirectory(muz/dataflow) add_subdirectory(muz/transforms) add_subdirectory(muz/rel) -add_subdirectory(muz/pdr) add_subdirectory(muz/clp) add_subdirectory(muz/tab) add_subdirectory(muz/bmc) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index cc14de5ce..2b0987be7 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -188,9 +188,7 @@ namespace datalog { if (m_trail.get_num_scopes() == 0) { throw default_exception("there are no backtracking points to pop to"); } - if (m_engine.get()) { - throw default_exception("pop operation is only supported by duality engine"); - } + throw default_exception("pop operation is not supported"); m_trail.pop_scope(1); } @@ -576,17 +574,11 @@ namespace datalog { m_rule_properties.check_infinite_sorts(); break; case SPACER_ENGINE: - case PDR_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_existential_tail(); m_rule_properties.check_for_negated_predicates(); m_rule_properties.check_uninterpreted_free(); break; - case QPDR_ENGINE: - m_rule_properties.collect(r); - m_rule_properties.check_for_negated_predicates(); - m_rule_properties.check_uninterpreted_free(); - break; case BMC_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_for_negated_predicates(); @@ -776,19 +768,14 @@ namespace datalog { DL_ENGINE get_engine() const { return m_engine_type; } void operator()(expr* e) { - if (is_quantifier(e)) { - m_engine_type = QPDR_ENGINE; - } - else if (m_engine_type != QPDR_ENGINE) { if (a.is_int_real(e)) { - m_engine_type = PDR_ENGINE; + m_engine_type = SPACER_ENGINE; } else if (is_var(e) && m.is_bool(e)) { - m_engine_type = PDR_ENGINE; + m_engine_type = SPACER_ENGINE; } else if (dt.is_datatype(m.get_sort(e))) { - m_engine_type = PDR_ENGINE; - } + m_engine_type = SPACER_ENGINE; } } }; @@ -805,12 +792,6 @@ namespace datalog { else if (e == symbol("spacer")) { m_engine_type = SPACER_ENGINE; } - else if (e == symbol("pdr")) { - m_engine_type = PDR_ENGINE; - } - else if (e == symbol("qpdr")) { - m_engine_type = QPDR_ENGINE; - } else if (e == symbol("bmc")) { m_engine_type = BMC_ENGINE; } @@ -858,8 +839,6 @@ namespace datalog { switch (get_engine()) { case DATALOG_ENGINE: case SPACER_ENGINE: - case PDR_ENGINE: - case QPDR_ENGINE: case BMC_ENGINE: case QBMC_ENGINE: case TAB_ENGINE: @@ -882,8 +861,6 @@ namespace datalog { switch (get_engine()) { case DATALOG_ENGINE: case SPACER_ENGINE: - case PDR_ENGINE: - case QPDR_ENGINE: case BMC_ENGINE: case QBMC_ENGINE: case TAB_ENGINE: diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index 9fc90ab1d..d6099e04c 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -25,9 +25,7 @@ Revision History: namespace datalog { enum DL_ENGINE { DATALOG_ENGINE, - PDR_ENGINE, SPACER_ENGINE, - QPDR_ENGINE, BMC_ENGINE, QBMC_ENGINE, TAB_ENGINE, diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index b5231c27b..f11e2faf9 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -1,37 +1,37 @@ -def_module_params('fixedpoint', +def_module_params('fixedpoint', description='fixedpoint parameters', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), - ('engine', SYMBOL, 'auto-config', - 'Select: auto-config, datalog, spacer, pdr, bmc'), - ('datalog.default_table', SYMBOL, 'sparse', + ('engine', SYMBOL, 'auto-config', + 'Select: auto-config, datalog, bmc, spacer'), + ('datalog.default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), - ('datalog.default_relation', SYMBOL, 'pentagon', + ('datalog.default_relation', SYMBOL, 'pentagon', 'default relation implementation: external_relation, pentagon'), - ('datalog.generate_explanations', BOOL, False, + ('datalog.generate_explanations', BOOL, False, 'produce explanations for produced facts when using the datalog engine'), - ('datalog.use_map_names', BOOL, True, + ('datalog.use_map_names', BOOL, True, "use names from map files when displaying tuples"), - ('datalog.magic_sets_for_queries', BOOL, False, + ('datalog.magic_sets_for_queries', BOOL, False, "magic set transformation will be used for queries"), - ('datalog.explanations_on_relation_level', BOOL, False, - 'if true, explanations are generated as history of each relation, ' + - 'rather than per fact (generate_explanations must be set to true for ' + + ('datalog.explanations_on_relation_level', BOOL, False, + 'if true, explanations are generated as history of each relation, ' + + 'rather than per fact (generate_explanations must be set to true for ' + 'this option to have any effect)'), - ('datalog.unbound_compressor', BOOL, True, - "auxiliary relations will be introduced to avoid unbound variables " + + ('datalog.unbound_compressor', BOOL, True, + "auxiliary relations will be introduced to avoid unbound variables " + "in rule heads"), - ('datalog.similarity_compressor', BOOL, True, - "rules that differ only in values of constants will be merged into " + + ('datalog.similarity_compressor', BOOL, True, + "rules that differ only in values of constants will be merged into " + "a single rule"), - ('datalog.similarity_compressor_threshold', UINT, 11, - "if similarity_compressor is on, this value determines how many " + + ('datalog.similarity_compressor_threshold', UINT, 11, + "if similarity_compressor is on, this value determines how many " + "similar rules there must be in order for them to be merged"), - ('datalog.all_or_nothing_deltas', BOOL, False, + ('datalog.all_or_nothing_deltas', BOOL, False, "compile rules so that it is enough for the delta relation in " + - "union and widening operations to determine only whether the " + + "union and widening operations to determine only whether the " + "updated relation was modified or not"), - ('datalog.compile_with_widening', BOOL, False, + ('datalog.compile_with_widening', BOOL, False, "widening will be used to compile recursive rules"), ('datalog.default_table_checked', BOOL, False, "if true, the default " + 'table will be default_table inside a wrapper that checks that its results ' + @@ -39,15 +39,15 @@ def_module_params('fixedpoint', ('datalog.default_table_checker', SYMBOL, 'null', "see default_table_checked"), ('datalog.check_relation',SYMBOL,'null', "name of default relation to check. " + "operations on the default relation will be verified using SMT solving"), - ('datalog.initial_restart_timeout', UINT, 0, - "length of saturation run before the first restart (in ms), " + + ('datalog.initial_restart_timeout', UINT, 0, + "length of saturation run before the first restart (in ms), " + "zero means no restarts"), - ('datalog.output_profile', BOOL, False, - "determines whether profile information should be " + + ('datalog.output_profile', BOOL, False, + "determines whether profile information should be " + "output when outputting Datalog rules or instructions"), - ('datalog.print.tuples', BOOL, True, + ('datalog.print.tuples', BOOL, True, "determines whether tuples for output predicates should be output"), - ('datalog.profile_timeout_milliseconds', UINT, 0, + ('datalog.profile_timeout_milliseconds', UINT, 0, "instructions and rules that took less than the threshold " + "will not be printed when printed the instruction/rule list"), ('datalog.dbg_fpr_nonempty_relation_signature', BOOL, False, @@ -56,94 +56,94 @@ def_module_params('fixedpoint', "table columns, if it would have been empty otherwise"), ('datalog.subsumption', BOOL, True, "if true, removes/filters predicates with total transitions"), - ('pdr.bfs_model_search', BOOL, True, - "use BFS strategy for expanding model search"), - ('pdr.farkas', BOOL, True, + ('pdr.bfs_model_search', BOOL, True, + "use BFS strategy for expanding model search"), + ('pdr.farkas', BOOL, True, "use lemma generator based on Farkas (for linear real arithmetic)"), ('generate_proof_trace', BOOL, False, "trace for 'sat' answer as proof object"), - ('pdr.flexible_trace', BOOL, False, + ('pdr.flexible_trace', BOOL, False, "allow PDR generate long counter-examples " + "by extending candidate trace within search area"), - ('pdr.flexible_trace_depth', UINT, UINT_MAX, + ('pdr.flexible_trace_depth', UINT, UINT_MAX, 'Controls the depth (below the current level) at which flexible trace can be applied'), - ('pdr.use_model_generalizer', BOOL, False, + ('pdr.use_model_generalizer', BOOL, False, "use model for backwards propagation (instead of symbolic simulation)"), - ('pdr.validate_result', BOOL, False, + ('pdr.validate_result', BOOL, False, "validate result (by proof checking or model checking)"), - ('pdr.simplify_formulas_pre', BOOL, False, + ('pdr.simplify_formulas_pre', BOOL, False, "simplify derived formulas before inductive propagation"), - ('pdr.simplify_formulas_post', BOOL, False, + ('pdr.simplify_formulas_post', BOOL, False, "simplify derived formulas after inductive propagation"), - ('pdr.use_multicore_generalizer', BOOL, False, + ('pdr.use_multicore_generalizer', BOOL, False, "extract multiple cores for blocking states"), - ('pdr.use_inductive_generalizer', BOOL, True, + ('pdr.use_inductive_generalizer', BOOL, True, "generalize lemmas using induction strengthening"), - ('pdr.use_arith_inductive_generalizer', BOOL, False, + ('pdr.use_arith_inductive_generalizer', BOOL, False, "generalize lemmas using arithmetic heuristics for induction strengthening"), - ('pdr.use_convex_closure_generalizer', BOOL, False, + ('pdr.use_convex_closure_generalizer', BOOL, False, "generalize using convex closures of lemmas"), - ('pdr.use_convex_interior_generalizer', BOOL, False, + ('pdr.use_convex_interior_generalizer', BOOL, False, "generalize using convex interiors of lemmas"), - ('pdr.cache_mode', UINT, 0, "use no (0), symbolic (1) or explicit " + + ('pdr.cache_mode', UINT, 0, "use no (0), symbolic (1) or explicit " + "cache (2) for model search"), - ('pdr.inductive_reachability_check', BOOL, False, + ('pdr.inductive_reachability_check', BOOL, False, "assume negation of the cube on the previous level when " + "checking for reachability (not only during cube weakening)"), ('pdr.max_num_contexts', UINT, 500, "maximal number of contexts to create"), - ('pdr.try_minimize_core', BOOL, False, + ('pdr.try_minimize_core', BOOL, False, "try to reduce core size (before inductive minimization)"), ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), - ('print_fixedpoint_extensions', BOOL, True, - "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, " + + ('print_fixedpoint_extensions', BOOL, True, + "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, " + "when printing rules"), - ('print_low_level_smt2', BOOL, False, - "use (faster) low-level SMT2 printer (the printer is scalable " + + ('print_low_level_smt2', BOOL, False, + "use (faster) low-level SMT2 printer (the printer is scalable " + "but the result may not be as readable)"), - ('print_with_variable_declarations', BOOL, True, + ('print_with_variable_declarations', BOOL, True, "use variable declarations when displaying rules " + "(instead of attempting to use original names)"), ('print_answer', BOOL, False, 'print answer instance(s) to query'), - ('print_certificate', BOOL, False, + ('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'), - ('print_boogie_certificate', BOOL, False, + ('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, '', + ('print_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), ('tab.selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), - ('xform.bit_blast', BOOL, False, + ('xform.bit_blast', BOOL, False, 'bit-blast bit-vectors'), - ('xform.magic', BOOL, False, + ('xform.magic', BOOL, False, "perform symbolic magic set transformation"), - ('xform.scale', BOOL, False, + ('xform.scale', BOOL, False, "add scaling variable to linear real arithmetic clauses"), ('xform.inline_linear', BOOL, True, "try linear inlining method"), ('xform.inline_eager', BOOL, True, "try eager inlining of rules"), - ('xform.inline_linear_branch', BOOL, False, + ('xform.inline_linear_branch', BOOL, False, "try linear inlining method with potential expansion"), ('xform.compress_unbound', BOOL, True, "compress tails with unbound variables"), ('xform.fix_unbound_vars', BOOL, False, "fix unbound variables in tail"), - ('xform.unfold_rules', UINT, 0, + ('xform.unfold_rules', UINT, 0, "unfold rules statically using iterative squarring"), ('xform.slice', BOOL, True, "simplify clause set using slicing"), - ('xform.karr', BOOL, False, + ('xform.karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), ('spacer.use_eqclass', BOOL, False, "Generalizes equalities to equivalence classes"), - ('xform.transform_arrays', BOOL, False, + ('xform.transform_arrays', BOOL, False, "Rewrites arrays equalities and applies select over store"), - ('xform.instantiate_arrays', BOOL, False, + ('xform.instantiate_arrays', BOOL, False, "Transforms P(a) into P(i, a[i] a)"), - ('xform.instantiate_arrays.enforce', BOOL, False, + ('xform.instantiate_arrays.enforce', BOOL, False, "Transforms P(a) into P(i, a[i]), discards a from predicate"), - ('xform.instantiate_arrays.nb_quantifier', UINT, 1, + ('xform.instantiate_arrays.nb_quantifier', UINT, 1, "Gives the number of quantifiers per array"), - ('xform.instantiate_arrays.slice_technique', SYMBOL, "no-slicing", + ('xform.instantiate_arrays.slice_technique', SYMBOL, "no-slicing", "=> GetId(i) = i, => GetId(i) = true"), - ('xform.quantify_arrays', BOOL, False, + ('xform.quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), - ('xform.instantiate_quantifiers', BOOL, False, + ('xform.instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), ('xform.coalesce_rules', BOOL, False, "coalesce rules"), ('xform.tail_simplifier_pve', BOOL, True, "propagate_variable_equivalences"), @@ -154,8 +154,8 @@ def_module_params('fixedpoint', ('spacer.use_lemma_as_cti', BOOL, False, 'SPACER: use a lemma instead of a CTI in flexible_trace'), ('spacer.reset_obligation_queue', BOOL, True, 'SPACER: reset obligation queue when entering a new level'), ('spacer.use_array_eq_generalizer', BOOL, True, 'SPACER: attempt to generalize lemmas with array equalities'), - ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), - ('xform.array_blast', BOOL, False, "try to eliminate local array terms using Ackermannization -- some array terms may remain"), + ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), + ('xform.array_blast', BOOL, False, "try to eliminate local array terms using Ackermannization -- some array terms may remain"), ('xform.array_blast_full', BOOL, False, "eliminate all local array variables by QE"), ('spacer.skip_propagate', BOOL, False, "Skip propagate/pushing phase. Turns PDR into a BMC that returns either reachable or unknown"), ('spacer.max_level', UINT, UINT_MAX, "Maximum level to explore"), diff --git a/src/muz/fp/CMakeLists.txt b/src/muz/fp/CMakeLists.txt index 41262813a..4837df81b 100644 --- a/src/muz/fp/CMakeLists.txt +++ b/src/muz/fp/CMakeLists.txt @@ -9,7 +9,6 @@ z3_add_component(fp clp ddnf muz - pdr rel spacer tab diff --git a/src/muz/fp/dl_register_engine.cpp b/src/muz/fp/dl_register_engine.cpp index a2270d774..28a2a1c5e 100644 --- a/src/muz/fp/dl_register_engine.cpp +++ b/src/muz/fp/dl_register_engine.cpp @@ -21,7 +21,6 @@ Revision History: #include "muz/clp/clp_context.h" #include "muz/tab/tab_context.h" #include "muz/rel/rel_context.h" -#include "muz/pdr/pdr_dl_interface.h" #include "muz/ddnf/ddnf.h" #include "muz/spacer/spacer_dl_interface.h" @@ -30,9 +29,6 @@ namespace datalog { engine_base* register_engine::mk_engine(DL_ENGINE engine_type) { switch(engine_type) { - case PDR_ENGINE: - case QPDR_ENGINE: - return alloc(pdr::dl_interface, *m_ctx); case SPACER_ENGINE: return alloc(spacer::dl_interface, *m_ctx); case DATALOG_ENGINE: diff --git a/src/muz/pdr/CMakeLists.txt b/src/muz/pdr/CMakeLists.txt deleted file mode 100644 index ca2992b97..000000000 --- a/src/muz/pdr/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -z3_add_component(pdr - SOURCES - pdr_closure.cpp - pdr_context.cpp - pdr_dl_interface.cpp - pdr_farkas_learner.cpp - pdr_generalizers.cpp - pdr_manager.cpp - pdr_prop_solver.cpp - pdr_reachable_cache.cpp - pdr_smt_context_manager.cpp - pdr_sym_mux.cpp - pdr_util.cpp - COMPONENT_DEPENDENCIES - arith_tactics - core_tactics - muz - smt_tactic - transforms -) diff --git a/src/muz/pdr/pdr_closure.cpp b/src/muz/pdr/pdr_closure.cpp deleted file mode 100644 index 82caf285b..000000000 --- a/src/muz/pdr/pdr_closure.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - pdr_closure.cpp - -Abstract: - - Utility functions for computing closures. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-9-1. - -Revision History: - ---*/ - -#include "muz/pdr/pdr_closure.h" -#include "muz/pdr/pdr_context.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/ast_util.h" - -namespace pdr { - - expr_ref scaler::operator()(expr* e, expr* k, obj_map* translate) { - m_cache[0].reset(); - m_cache[1].reset(); - m_translate = translate; - m_k = k; - return scale(e, false); - } - - expr_ref scaler::scale(expr* e, bool is_mul) { - expr* r; - if (m_cache[is_mul].find(e, r)) { - return expr_ref(r, m); - } - if (!is_app(e)) { - return expr_ref(e, m); - } - app* ap = to_app(e); - if (m_translate && m_translate->find(ap->get_decl(), r)) { - return expr_ref(r, m); - } - if (!is_mul && a.is_numeral(e)) { - return expr_ref(a.mk_mul(m_k, e), m); - } - expr_ref_vector args(m); - bool is_mul_rec = is_mul || a.is_mul(e); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - args.push_back(scale(ap->get_arg(i), is_mul_rec)); - } - expr_ref result(m); - result = m.mk_app(ap->get_decl(), args.size(), args.c_ptr()); - m_cache[is_mul].insert(e, result); - return result; - } - - expr_ref scaler::undo_k(expr* e, expr* k) { - expr_safe_replace sub(m); - th_rewriter rw(m); - expr_ref result(e, m); - sub.insert(k, a.mk_numeral(rational(1), false)); - sub(result); - rw(result); - return result; - } - - - closure::closure(pred_transformer& p, bool is_closure): - m(p.get_manager()), m_pt(p), a(m), - m_is_closure(is_closure), m_sigma(m), m_trail(m) {} - - - void closure::add_variables(unsigned num_vars, expr_ref_vector& fmls) { - manager& pm = m_pt.get_pdr_manager(); - SASSERT(num_vars > 0); - while (m_vars.size() < num_vars) { - m_vars.resize(m_vars.size()+1); - m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); - } - - unsigned sz = m_pt.sig_size(); - - for (unsigned i = 0; i < sz; ++i) { - expr* var; - ptr_vector vars; - func_decl* fn0 = m_pt.sig(i); - func_decl* fn1 = pm.o2n(fn0, 0); - sort* srt = fn0->get_range(); - if (a.is_int_real(srt)) { - for (unsigned j = 0; j < num_vars; ++j) { - if (!m_vars[j].find(fn1, var)) { - var = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); - m_trail.push_back(var); - m_vars[j].insert(fn1, var); - } - vars.push_back(var); - } - fmls.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(num_vars, vars.c_ptr()))); - } - } - if (m_is_closure) { - for (unsigned i = 0; i < num_vars; ++i) { - fmls.push_back(a.mk_ge(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); - } - } - else { - // is interior: - for (unsigned i = 0; i < num_vars; ++i) { - fmls.push_back(a.mk_gt(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); - } - } - fmls.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(num_vars, m_sigma.c_ptr()))); - } - - expr_ref closure::close_fml(expr* e) { - expr* e0, *e1, *e2; - expr_ref result(m); - if (a.is_lt(e, e1, e2)) { - result = a.mk_le(e1, e2); - } - else if (a.is_gt(e, e1, e2)) { - result = a.mk_ge(e1, e2); - } - else if (m.is_not(e, e0) && a.is_ge(e0, e1, e2)) { - result = a.mk_le(e1, e2); - } - else if (m.is_not(e, e0) && a.is_le(e0, e1, e2)) { - result = a.mk_ge(e1, e2); - } - else if (a.is_ge(e) || a.is_le(e) || m.is_eq(e) || - (m.is_not(e, e0) && (a.is_gt(e0) || a.is_lt(e0)))) { - result = e; - } - else { - IF_VERBOSE(1, verbose_stream() << "Cannot close: " << mk_pp(e, m) << "\n";); - result = m.mk_true(); - } - return result; - } - - expr_ref closure::close_conjunction(expr* fml) { - expr_ref_vector fmls(m); - flatten_and(fml, fmls); - for (unsigned i = 0; i < fmls.size(); ++i) { - fmls[i] = close_fml(fmls[i].get()); - } - return expr_ref(mk_and(fmls), m); - } - - expr_ref closure::relax(unsigned i, expr* fml) { - scaler sc(m); - expr_ref result = sc(fml, m_sigma[i].get(), &m_vars[i]); - return close_conjunction(result); - } - - expr_ref closure::operator()(expr_ref_vector const& As) { - if (As.empty()) { - return expr_ref(m.mk_false(), m); - } - if (As.size() == 1) { - return expr_ref(As[0], m); - } - expr_ref_vector fmls(m); - expr_ref B(m); - add_variables(As.size(), fmls); - for (unsigned i = 0; i < As.size(); ++i) { - fmls.push_back(relax(i, As[i])); - } - B = mk_and(fmls); - return B; - } - -} diff --git a/src/muz/pdr/pdr_closure.h b/src/muz/pdr/pdr_closure.h deleted file mode 100644 index c41e83389..000000000 --- a/src/muz/pdr/pdr_closure.h +++ /dev/null @@ -1,67 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - pdr_closure.h - -Abstract: - - Utility functions for computing closures. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-9-1. - -Revision History: - ---*/ - -#ifndef PDR_CLOSURE_H_ -#define PDR_CLOSURE_H_ - -#include "ast/arith_decl_plugin.h" - -namespace pdr { - - // Arithmetic scaling functor. - // Variables are replaced using - // m_translate. Constants are replaced by - // multiplication with a variable 'k' (scale factor). - class scaler { - ast_manager& m; - arith_util a; - obj_map m_cache[2]; - expr* m_k; - obj_map* m_translate; - public: - scaler(ast_manager& m): m(m), a(m), m_translate(nullptr) {} - expr_ref operator()(expr* e, expr* k, obj_map* translate = nullptr); - expr_ref undo_k(expr* e, expr* k); - private: - expr_ref scale(expr* e, bool is_mul); - }; - - class pred_transformer; - - class closure { - ast_manager& m; - pred_transformer& m_pt; - arith_util a; - bool m_is_closure; - expr_ref_vector m_sigma; - expr_ref_vector m_trail; - vector > m_vars; - - expr_ref relax(unsigned i, expr* fml); - expr_ref close_conjunction(expr* fml); - expr_ref close_fml(expr* fml); - void add_variables(unsigned num_vars, expr_ref_vector& fmls); - public: - closure(pred_transformer& pt, bool is_closure); - expr_ref operator()(expr_ref_vector const& As); - - }; -} - -#endif diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp deleted file mode 100644 index 1b1350617..000000000 --- a/src/muz/pdr/pdr_context.cpp +++ /dev/null @@ -1,2431 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_context.cpp - -Abstract: - - PDR predicate transformers and search context. - -Author: - - Nikolaj Bjorner (nbjorner) 2011-11-20. - -Revision History: - - Based on pdr_dl.cpp by - Krystof Hoder (t-khoder) 2011-9-19. - -Notes: - - ---*/ - - -#include -#include "muz/base/dl_util.h" -#include "ast/rewriter/rewriter.h" -#include "ast/rewriter/rewriter_def.h" -#include "ast/rewriter/var_subst.h" -#include "util/util.h" -#include "muz/pdr/pdr_prop_solver.h" -#include "muz/pdr/pdr_context.h" -#include "muz/pdr/pdr_generalizers.h" -#include "ast/for_each_expr.h" -#include "muz/base/dl_rule_set.h" -#include "smt/tactic/unit_subsumption_tactic.h" -#include "model/model_smt2_pp.h" -#include "muz/transforms/dl_mk_rule_inliner.h" -#include "ast/ast_smt2_pp.h" -#include "qe/qe_lite.h" -#include "ast/ast_ll_pp.h" -#include "ast/proofs/proof_checker.h" -#include "smt/smt_value_sort.h" -#include "muz/base/dl_boogie_proof.h" -#include "ast/scoped_proof.h" -#include "tactic/core/blast_term_ite_tactic.h" -#include "model/model_implicant.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/ast_util.h" - -namespace pdr { - - - static const unsigned infty_level = UINT_MAX; - - static bool is_infty_level(unsigned lvl) { return lvl == infty_level; } - - static unsigned next_level(unsigned lvl) { return is_infty_level(lvl)?lvl:(lvl+1); } - - struct pp_level { - unsigned m_level; - pp_level(unsigned l): m_level(l) {} - }; - - static std::ostream& operator<<(std::ostream& out, pp_level const& p) { - if (is_infty_level(p.m_level)) { - return out << "oo"; - } - else { - return out << p.m_level; - } - } - - // ---------------- - // pred_tansformer - - pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): - pm(pm), m(pm.get_manager()), - ctx(ctx), m_head(head, m), - m_sig(m), m_solver(pm, head->get_name()), - m_invariants(m), m_transition(m), m_initial_state(m), - m_reachable(pm, (datalog::PDR_CACHE_MODE)ctx.get_params().pdr_cache_mode()) {} - - pred_transformer::~pred_transformer() { - rule2inst::iterator it2 = m_rule2inst.begin(), end2 = m_rule2inst.end(); - for (; it2 != end2; ++it2) { - dealloc(it2->m_value); - } - rule2expr::iterator it3 = m_rule2transition.begin(), end3 = m_rule2transition.end(); - for (; it3 != end3; ++it3) { - m.dec_ref(it3->m_value); - } - } - - std::ostream& pred_transformer::display(std::ostream& out) const { - if (!rules().empty()) out << "rules\n"; - datalog::rule_manager& rm = ctx.get_context().get_rule_manager(); - for (unsigned i = 0; i < rules().size(); ++i) { - rm.display_smt2(*rules()[i], out) << "\n"; - } - out << "transition\n" << mk_pp(transition(), m) << "\n"; - return out; - } - - void pred_transformer::collect_statistics(statistics& st) const { - m_solver.collect_statistics(st); - m_reachable.collect_statistics(st); - st.update("PDR num propagations", m_stats.m_num_propagations); - unsigned np = m_invariants.size(); - for (unsigned i = 0; i < m_levels.size(); ++i) { - np += m_levels[i].size(); - } - st.update("PDR num properties", np); - } - - void pred_transformer::reset_statistics() { - m_solver.reset_statistics(); - m_reachable.reset_statistics(); - m_stats.reset(); - } - - void pred_transformer::init_sig() { - if (m_sig.empty()) { - for (unsigned i = 0; i < m_head->get_arity(); ++i) { - sort * arg_sort = m_head->get_domain(i); - std::stringstream name_stm; - name_stm << m_head->get_name() << '_' << i; - func_decl_ref stm(m); - stm = m.mk_func_decl(symbol(name_stm.str().c_str()), 0, (sort*const*)nullptr, arg_sort); - m_sig.push_back(pm.get_o_pred(stm, 0)); - } - } - } - - void pred_transformer::ensure_level(unsigned level) { - if (is_infty_level(level)) { - return; - } - while (m_levels.size() <= level) { - m_solver.add_level(); - m_levels.push_back(expr_ref_vector(m)); - } - } - - bool pred_transformer::is_reachable(expr* state) { - return m_reachable.is_reachable(state); - } - - datalog::rule const& pred_transformer::find_rule(model_core const& model) const { - TRACE("pdr_verbose", - datalog::rule_manager& rm = ctx.get_context().get_rule_manager(); - for (auto const& kv : m_tag2rule) { - expr* pred = kv.m_key; - tout << mk_pp(pred, m) << ":\n"; - if (kv.m_value) rm.display_smt2(*kv.m_value, tout) << "\n"; - } - ); - - if (m_tag2rule.size() == 1) { - return *m_tag2rule.begin()->m_value; - } - - expr_ref vl(m); - for (auto const& kv : m_tag2rule) { - expr* pred = kv.m_key; - if (model.eval(to_app(pred)->get_decl(), vl) && m.is_true(vl)) { - return *kv.m_value; - } - } - throw default_exception("could not find rule"); - } - - void pred_transformer::find_predecessors(datalog::rule const& r, ptr_vector& preds) const { - preds.reset(); - unsigned tail_sz = r.get_uninterpreted_tail_size(); - for (unsigned ti = 0; ti < tail_sz; ti++) { - preds.push_back(r.get_tail(ti)->get_decl()); - } - } - - - void pred_transformer::remove_predecessors(expr_ref_vector& literals) { - // remove tags - for (unsigned i = 0; i < literals.size(); ) { - expr* l = literals[i].get(); - m.is_not(l, l); - if (m_tag2rule.contains(l)) { - literals[i] = literals.back(); - literals.pop_back(); - } - else { - ++i; - } - } - } - - void pred_transformer::simplify_formulas(tactic& tac, expr_ref_vector& v) { - goal_ref g(alloc(goal, m, false, false, false)); - for (expr* e : v) g->assert_expr(e); - goal_ref_buffer result; - tac(g, result); - SASSERT(result.size() == 1); - goal* r = result[0]; - v.reset(); - for (unsigned j = 0; j < r->size(); ++j) v.push_back(r->form(j)); - } - - void pred_transformer::simplify_formulas() { - tactic_ref us = mk_unit_subsumption_tactic(m); - simplify_formulas(*us, m_invariants); - for (auto & fmls : m_levels) - simplify_formulas(*us, fmls); - } - - expr_ref pred_transformer::get_formulas(unsigned level, bool add_axioms) { - expr_ref_vector res(m); - if (add_axioms) { - res.push_back(pm.get_background()); - res.push_back((level == 0)?initial_state():transition()); - } - res.append(m_invariants); - for (unsigned i = level; i < m_levels.size(); ++i) { - res.append(m_levels[i]); - } - return pm.mk_and(res); - } - - expr_ref pred_transformer::get_propagation_formula(decl2rel const& pts, unsigned level) { - expr_ref result(m), tmp1(m), tmp2(m); - expr_ref_vector conj(m); - if (level == 0) { - conj.push_back(initial_state()); - } - else { - conj.push_back(transition()); - } - conj.push_back(get_formulas(level, true)); - obj_map::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); - for (; level > 0 && it != end; ++it) { - expr* tag = it->m_key; - datalog::rule const* r = it->m_value; - if (!r) continue; - find_predecessors(*r, m_predicates); - for (unsigned i = 0; i < m_predicates.size(); ++i) { - func_decl* d = m_predicates[i]; - pred_transformer & pt = *pts.find(d); - tmp1 = pt.get_formulas(level-1, false); - TRACE("pdr", tout << mk_pp(tmp1, m) << "\n";); - pm.formula_n2o(tmp1, tmp2, i, false); - conj.push_back(m.mk_implies(tag, tmp2)); - } - } - return pm.mk_and(conj); - } - - bool pred_transformer::propagate_to_next_level(unsigned src_level) { - unsigned tgt_level = next_level(src_level); - ensure_level(next_level(tgt_level)); - expr_ref_vector& src = m_levels[src_level]; - - CTRACE("pdr", !src.empty(), - tout << "propagating " << src_level << " to " << tgt_level; - tout << " for relation " << head()->get_name() << "\n";); - - for (unsigned i = 0; i < src.size(); ) { - expr * curr = src[i].get(); - unsigned stored_lvl = 0; - VERIFY(m_prop2level.find(curr, stored_lvl)); - SASSERT(stored_lvl >= src_level); - bool assumes_level; - if (stored_lvl > src_level) { - TRACE("pdr", tout << "at level: "<< stored_lvl << " " << mk_pp(curr, m) << "\n";); - src[i] = src.back(); - src.pop_back(); - } - else if (is_invariant(tgt_level, curr, false, assumes_level)) { - - add_property(curr, assumes_level?tgt_level:infty_level); - TRACE("pdr", tout << "is invariant: "<< pp_level(tgt_level) << " " << mk_pp(curr, m) << "\n";); - src[i] = src.back(); - src.pop_back(); - ++m_stats.m_num_propagations; - } - else { - TRACE("pdr", tout << "not propagated: " << mk_pp(curr, m) << "\n";); - ++i; - } - } - IF_VERBOSE(3, verbose_stream() << "propagate: " << pp_level(src_level) << "\n"; - for (unsigned i = 0; i < src.size(); ++i) { - verbose_stream() << mk_pp(src[i].get(), m) << "\n"; - }); - return src.empty(); - } - - bool pred_transformer::add_property1(expr * lemma, unsigned lvl) { - if (is_infty_level(lvl)) { - if (!m_invariants.contains(lemma)) { - TRACE("pdr", tout << "property1: " << head()->get_name() << " " << mk_pp(lemma, m) << "\n";); - m_invariants.push_back(lemma); - m_prop2level.insert(lemma, lvl); - m_solver.add_formula(lemma); - return true; - } - else { - TRACE("pdr", tout << "already contained: " << head()->get_name() << " " << mk_pp(lemma, m) << "\n";); - return false; - } - } - ensure_level(lvl); - unsigned old_level; - if (!m_prop2level.find(lemma, old_level) || old_level < lvl) { - TRACE("pdr", tout << "property1: " << pp_level(lvl) << " " << head()->get_name() << " " << mk_pp(lemma, m) << "\n";); - m_levels[lvl].push_back(lemma); - m_prop2level.insert(lemma, lvl); - m_solver.add_level_formula(lemma, lvl); - return true; - } - else { - TRACE("pdr", tout << "old-level: " << pp_level(old_level) << " " << head()->get_name() << " " << mk_pp(lemma, m) << "\n";); - return false; - } - } - - void pred_transformer::add_child_property(pred_transformer& child, expr* lemma, unsigned lvl) { - ensure_level(lvl); - expr_ref_vector fmls(m); - mk_assumptions(child.head(), lemma, fmls); - for (unsigned i = 0; i < fmls.size(); ++i) { - TRACE("pdr", tout << "child property: " << mk_pp(fmls[i].get(), m) << "\n";); - if (is_infty_level(lvl)) { - m_solver.add_formula(fmls[i].get()); - } - else { - m_solver.add_level_formula(fmls[i].get(), lvl); - } - } - } - - void pred_transformer::add_property(expr* lemma, unsigned lvl) { - expr_ref_vector lemmas(m); - flatten_and(lemma, lemmas); - for (unsigned i = 0; i < lemmas.size(); ++i) { - expr* lemma_i = lemmas[i].get(); - if (add_property1(lemma_i, lvl)) { - IF_VERBOSE(2, verbose_stream() << pp_level(lvl) << " " << mk_pp(lemma_i, m) << "\n";); - for (unsigned j = 0; j < m_use.size(); ++j) { - m_use[j]->add_child_property(*this, lemma_i, next_level(lvl)); - } - } - } - } - - expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) { - expr_ref result(m.mk_true(), m), v(m), c(m); - if (level == -1) { - result = pm.mk_and(m_invariants); - } - else if ((unsigned)level < m_levels.size()) { - result = pm.mk_and(m_levels[level]); - } - // replace local constants by bound variables. - expr_substitution sub(m); - for (unsigned i = 0; i < sig_size(); ++i) { - c = m.mk_const(pm.o2n(sig(i), 0)); - v = m.mk_var(i, sig(i)->get_range()); - sub.insert(c, v); - } - scoped_ptr rep = mk_default_expr_replacer(m); - rep->set_substitution(&sub); - (*rep)(result); - - // adjust result according to model converter. - unsigned arity = m_head->get_arity(); - model_ref md = alloc(model, m); - if (arity == 0) { - md->register_decl(m_head, result); - } - else { - func_interp* fi = alloc(func_interp, m, arity); - fi->set_else(result); - md->register_decl(m_head, fi); - } - model_converter_ref mc = ctx.get_model_converter(); - apply(mc, md); - if (p_orig->get_arity() == 0) { - result = md->get_const_interp(p_orig); - } - else { - result = md->get_func_interp(p_orig)->get_interp(); - } - return result; - } - - void pred_transformer::add_cover(unsigned level, expr* property) { - // replace bound variables by local constants. - expr_ref result(property, m), v(m), c(m); - expr_substitution sub(m); - for (unsigned i = 0; i < sig_size(); ++i) { - c = m.mk_const(pm.o2n(sig(i), 0)); - v = m.mk_var(i, sig(i)->get_range()); - sub.insert(v, c); - } - scoped_ptr rep = mk_default_expr_replacer(m); - rep->set_substitution(&sub); - (*rep)(result); - TRACE("pdr", tout << "cover:\n" << mk_pp(result, m) << "\n";); - // add the property. - add_property(result, level); - } - - void pred_transformer::propagate_to_infinity(unsigned invariant_level) { - expr_ref inv = get_formulas(invariant_level, false); - add_property(inv, infty_level); - // cleanup - for (unsigned i = invariant_level; i < m_levels.size(); ++i) { - m_levels[i].reset(); - } - } - - lbool pred_transformer::is_reachable(model_node& n, expr_ref_vector* core, bool& uses_level) { - TRACE("pdr", - tout << "is-reachable: " << head()->get_name() << " level: " << n.level() << "\n"; - tout << mk_pp(n.state(), m) << "\n";); - ensure_level(n.level()); - model_ref model; - prop_solver::scoped_level _sl(m_solver, n.level()); - m_solver.set_core(core); - m_solver.set_model(&model); - lbool is_sat = m_solver.check_conjunction_as_assumptions(n.state()); - if (is_sat == l_true && core) { - core->reset(); - TRACE("pdr", tout << "updating model\n"; - model_smt2_pp(tout, m, *model, 0); - tout << mk_pp(n.state(), m) << "\n";); - n.set_model(model); - } - else if (is_sat == l_false) { - uses_level = m_solver.assumes_level(); - } - m_solver.set_model(nullptr); - return is_sat; - } - - bool pred_transformer::is_invariant(unsigned level, expr* states, bool inductive, bool& assumes_level, expr_ref_vector* core) { - expr_ref_vector conj(m); - expr_ref tmp(m); - - conj.push_back(m.mk_not(states)); - - if (inductive) { - mk_assumptions(head(), states, conj); - } - tmp = pm.mk_and(conj); - prop_solver::scoped_level _sl(m_solver, level); - m_solver.set_core(core); - m_solver.set_model(nullptr); - lbool r = m_solver.check_conjunction_as_assumptions(tmp); - if (r == l_false) { - assumes_level = m_solver.assumes_level(); - } - return r == l_false; - } - - bool pred_transformer::check_inductive(unsigned level, expr_ref_vector& lits, bool& assumes_level) { - manager& pm = get_pdr_manager(); - expr_ref_vector conj(m), core(m); - expr_ref fml(m), states(m); - states = m.mk_not(pm.mk_and(lits)); - mk_assumptions(head(), states, conj); - fml = pm.mk_and(conj); - prop_solver::scoped_level _sl(m_solver, level); - m_solver.set_core(&core); - m_solver.set_subset_based_core(true); - m_solver.set_model(nullptr); - lbool res = m_solver.check_assumptions_and_formula(lits, fml); - if (res == l_false) { - lits.reset(); - lits.append(core); - assumes_level = m_solver.assumes_level(); - } - return res == l_false; - } - - void pred_transformer::mk_assumptions(func_decl* head, expr* fml, expr_ref_vector& result) { - expr_ref tmp1(m), tmp2(m); - obj_map::iterator it = m_tag2rule.begin(), end = m_tag2rule.end(); - for (; it != end; ++it) { - expr* pred = it->m_key; - datalog::rule const* r = it->m_value; - if (!r) continue; - find_predecessors(*r, m_predicates); - for (unsigned i = 0; i < m_predicates.size(); i++) { - func_decl* d = m_predicates[i]; - if (d == head) { - tmp1 = m.mk_implies(pred, fml); - pm.formula_n2o(tmp1, tmp2, i); - result.push_back(tmp2); - } - } - } - } - - void pred_transformer::initialize(decl2rel const& pts) { - m_initial_state = m.mk_false(); - m_transition = m.mk_true(); - init_rules(pts, m_initial_state, m_transition); - th_rewriter rw(m); - rw(m_transition); - rw(m_initial_state); - - m_solver.add_formula(m_transition); - m_solver.add_level_formula(m_initial_state, 0); - TRACE("pdr", - tout << "Initial state: " << mk_pp(m_initial_state, m) << "\n"; - tout << "Transition: " << mk_pp(m_transition, m) << "\n";); - SASSERT(is_app(m_initial_state)); - m_reachable.add_init(to_app(m_initial_state)); - } - - void pred_transformer::init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transition) { - expr_ref_vector transitions(m); - ptr_vector tr_rules; - datalog::rule const* rule; - expr_ref_vector disj(m); - app_ref pred(m); - for (unsigned i = 0; i < rules().size(); ++i) { - init_rule(pts, *rules()[i], init, tr_rules, transitions); - } - switch(transitions.size()) { - case 0: - transition = m.mk_false(); - break; - case 1: - // create a dummy tag. - pred = m.mk_fresh_const(head()->get_name().str().c_str(), m.mk_bool_sort()); - rule = tr_rules[0]; - m_tag2rule.insert(pred, rule); - m_rule2tag.insert(rule, pred.get()); - transitions.push_back(pred); - transition = pm.mk_and(transitions); - break; - default: - for (unsigned i = 0; i < transitions.size(); ++i) { - pred = m.mk_fresh_const(head()->get_name().str().c_str(), m.mk_bool_sort()); - rule = tr_rules[i]; - m_tag2rule.insert(pred, rule); - m_rule2tag.insert(rule, pred); - disj.push_back(pred); - transitions[i] = m.mk_implies(pred, transitions[i].get()); - } - transitions.push_back(m.mk_or(disj.size(), disj.c_ptr())); - transition = pm.mk_and(transitions); - break; - } - } - - void pred_transformer::init_rule( - decl2rel const& pts, - datalog::rule const& rule, - expr_ref& init, - ptr_vector& rules, - expr_ref_vector& transitions) - { - // Predicates that are variable representatives. Other predicates at - // positions the variables occur are made equivalent with these. - expr_ref_vector conj(m); - app_ref_vector var_reprs(m); - ptr_vector aux_vars; - - unsigned ut_size = rule.get_uninterpreted_tail_size(); - unsigned t_size = rule.get_tail_size(); - SASSERT(ut_size <= t_size); - init_atom(pts, rule.get_head(), var_reprs, conj, UINT_MAX); - for (unsigned i = 0; i < ut_size; ++i) { - if (rule.is_neg_tail(i)) { - char const* msg = "PDR does not supported negated predicates in rule tails"; - IF_VERBOSE(0, verbose_stream() << msg << "\n";); - throw default_exception(msg); - } - init_atom(pts, rule.get_tail(i), var_reprs, conj, i); - } - for (unsigned i = ut_size; i < t_size; ++i) { - ground_free_vars(rule.get_tail(i), var_reprs, aux_vars); - } - SASSERT(check_filled(var_reprs)); - expr_ref_vector tail(m); - for (unsigned i = ut_size; i < t_size; ++i) { - tail.push_back(rule.get_tail(i)); - } - flatten_and(tail); - for (unsigned i = 0; i < tail.size(); ++i) { - expr_ref tmp(m); - var_subst vs(m, false); - vs(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); - conj.push_back(tmp); - TRACE("pdr", tout << mk_pp(tail[i].get(), m) << "\n" << mk_pp(tmp, m) << "\n";); - if (!is_ground(tmp)) { - std::stringstream msg; - msg << "PDR cannot solve non-ground tails: " << tmp; - IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - throw default_exception(msg.str()); - } - } - expr_ref fml = pm.mk_and(conj); - th_rewriter rw(m); - rw(fml); - if (ctx.is_dl() || ctx.is_utvpi()) { - blast_term_ite(fml); - } - TRACE("pdr", tout << mk_pp(fml, m) << "\n";); - SASSERT(is_ground(fml)); - if (m.is_false(fml)) { - // no-op. - } - else { - if (ut_size == 0) { - init = m.mk_or(init, fml); - } - transitions.push_back(fml); - m.inc_ref(fml); - m_rule2transition.insert(&rule, fml.get()); - rules.push_back(&rule); - } - m_rule2inst.insert(&rule, alloc(app_ref_vector, var_reprs)); - m_rule2vars.insert(&rule, aux_vars); - TRACE("pdr", - tout << rule.get_decl()->get_name() << "\n"; - for (unsigned i = 0; i < var_reprs.size(); ++i) { - tout << mk_pp(var_reprs[i].get(), m) << " "; - } - if (!var_reprs.empty()) tout << "\n";); - } - - bool pred_transformer::check_filled(app_ref_vector const& v) const { - for (unsigned i = 0; i < v.size(); ++i) { - if (!v[i]) return false; - } - return true; - } - - // create constants for free variables in tail. - void pred_transformer::ground_free_vars(expr* e, app_ref_vector& vars, ptr_vector& aux_vars) { - expr_free_vars fv; - fv(e); - while (vars.size() < fv.size()) { - vars.push_back(nullptr); - } - for (unsigned i = 0; i < fv.size(); ++i) { - if (fv[i] && !vars[i].get()) { - vars[i] = m.mk_fresh_const("aux", fv[i]); - aux_vars.push_back(vars[i].get()); - } - } - } - - // create names for variables used in relations. - void pred_transformer::init_atom( - decl2rel const& pts, - app * atom, - app_ref_vector& var_reprs, - expr_ref_vector& conj, - unsigned tail_idx - ) - { - unsigned arity = atom->get_num_args(); - func_decl* head = atom->get_decl(); - pred_transformer& pt = *pts.find(head); - for (unsigned i = 0; i < arity; i++) { - app_ref rep(m); - - if (tail_idx == UINT_MAX) { - rep = m.mk_const(pm.o2n(pt.sig(i), 0)); - } - else { - rep = m.mk_const(pm.o2o(pt.sig(i), 0, tail_idx)); - } - - expr * arg = atom->get_arg(i); - if (is_var(arg)) { - var * v = to_var(arg); - unsigned var_idx = v->get_idx(); - if (var_idx >= var_reprs.size()) { - var_reprs.resize(var_idx+1); - } - expr * repr = var_reprs[var_idx].get(); - if (repr) { - conj.push_back(m.mk_eq(rep, repr)); - } - else { - var_reprs[var_idx] = rep; - } - } - else { - SASSERT(is_app(arg)); - conj.push_back(m.mk_eq(rep, arg)); - } - } - } - - void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, expr_ref_vector& r) { - r.push_back(pm.get_background()); - r.push_back((lvl == 0)?initial_state():transition()); - for (unsigned i = 0; i < rules().size(); ++i) { - add_premises(pts, lvl, *rules()[i], r); - } - } - - void pred_transformer::close(expr* e) { - m_reachable.add_reachable(e); - } - - void pred_transformer::add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r) { - find_predecessors(rule, m_predicates); - for (unsigned i = 0; i < m_predicates.size(); ++i) { - expr_ref tmp(m); - func_decl* head = m_predicates[i]; - pred_transformer& pt = *pts.find(head); - expr_ref inv = pt.get_formulas(lvl, false); - if (!m.is_true(inv)) { - pm.formula_n2o(inv, tmp, i, true); - r.push_back(tmp); - } - } - } - - void pred_transformer::inherit_properties(pred_transformer& other) { - SASSERT(m_head == other.m_head); - obj_map::iterator it = other.m_prop2level.begin(); - obj_map::iterator end = other.m_prop2level.end(); - for (; it != end; ++it) { - IF_VERBOSE(2, verbose_stream() << "(pdr-inherit: " << mk_pp(it->m_key, m) << ")\n";); - add_property(it->m_key, it->m_value); - } - } - - // ---------------- - // model_node - - void model_node::set_closed() { - TRACE("pdr", tout << state() << "\n";); - pt().close(state()); - m_closed = true; - } - - void model_node::set_open() { - SASSERT(m_closed); - m_closed = false; - model_node* p = parent(); - while (p && p->is_closed()) { - p->m_closed = false; - p = p->parent(); - } - } - - void model_node::check_pre_closed() { - for (unsigned i = 0; i < children().size(); ++i) { - if (children()[i]->is_open()) return; - } - set_pre_closed(); - model_node* p = parent(); - while (p && p->is_1closed()) { - p->set_pre_closed(); - p = p->parent(); - } - } - - static bool is_ini(datalog::rule const& r) { - return r.get_uninterpreted_tail_size() == 0; - } - - datalog::rule* model_node::get_rule() { - if (m_rule) { - return const_cast(m_rule); - } - // only initial states are not set by the PDR search. - SASSERT(m_model.get()); - if (!m_model.get()) { - std::stringstream msg; - msg << "no model for node " << state(); - IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - throw default_exception(msg.str()); - } - - datalog::rule const& rl1 = pt().find_rule(*m_model); - if (is_ini(rl1)) { - set_rule(&rl1); - return const_cast(m_rule); - } - ast_manager& m = pt().get_manager(); - // otherwise, the initial state is reachable. - ptr_vector const& rules = pt().rules(); - ptr_vector ini_rules; - expr_ref_vector tags(m); - expr_ref ini_tags(m), ini_state(m); - for (unsigned i = 0; i < rules.size(); ++i) { - datalog::rule* rl = rules[i]; - if (is_ini(*rl)) { - tags.push_back(pt().rule2tag(rl)); - } - } - SASSERT(!tags.empty()); - ini_tags = ::mk_or(tags); - ini_state = m.mk_and(ini_tags, pt().initial_state(), state()); - model_ref mdl; - pt().get_solver().set_model(&mdl); - TRACE("pdr", tout << ini_state << "\n";); - if (l_true != pt().get_solver().check_conjunction_as_assumptions(ini_state)) { - std::stringstream msg; - msg << "Unsatisfiable initial state: " << ini_state << "\n"; - display(msg, 2); - IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - throw default_exception(msg.str()); - } - SASSERT(mdl.get()); - datalog::rule const& rl2 = pt().find_rule(*mdl); - SASSERT(is_ini(rl2)); - set_rule(&rl2); - pt().get_solver().set_model(nullptr); - return const_cast(m_rule); - } - - - void model_node::mk_instantiate(datalog::rule_ref& r0, datalog::rule_ref& r1, expr_ref_vector& binding) { - ast_manager& m = pt().get_manager(); - expr_ref_vector conjs(m); - obj_map model; - flatten_and(state(), conjs); - for (unsigned i = 0; i < conjs.size(); ++i) { - expr* e = conjs[i].get(), *e1, *e2; - if (m.is_eq(e, e1, e2)) { - if (m.is_value(e2)) { - model.insert(e1, e2); - } - else if (m.is_value(e1)) { - model.insert(e2, e1); - } - } - else if (m.is_not(e, e1)) { - model.insert(e1, m.mk_false()); - } - else { - model.insert(e, m.mk_true()); - } - } - r0 = get_rule(); - app_ref_vector& inst = pt().get_inst(r0); - TRACE("pdr", tout << state() << " instance: " << inst.size() << "\n";); - for (unsigned i = 0; i < inst.size(); ++i) { - expr* v; - if (model.find(inst[i].get(), v)) { - binding.push_back(v); - } - else { - binding.push_back(m.mk_var(i, m.get_sort(inst[i].get()))); - } - } - r1 = r0; - if (!inst.empty()) { - r1.get_manager().substitute(r1, binding.size(), binding.c_ptr()); - } - } - - - - std::ostream& model_node::display(std::ostream& out, unsigned indent) { - for (unsigned i = 0; i < indent; ++i) out << " "; - out << m_level << " " << m_pt.head()->get_name() << " " << (m_closed?"closed":"open") << "\n"; - for (unsigned i = 0; i < indent; ++i) out << " "; - out << " " << mk_pp(m_state, m_state.get_manager(), indent) << " " << m_state->get_id() << "\n"; - for (unsigned i = 0; i < children().size(); ++i) { - children()[i]->display(out, indent + 1); - } - return out; - } - - // return order of this node in the children of its parent - unsigned model_node::index() const { - model_node* p = parent(); - if (!p) return 0; - for (unsigned i = 0; i < p->children().size(); ++i) { - if (this == p->children()[i]) return i; - } - UNREACHABLE(); - return 0; - } - - // detach this node from a queue with the head root - // requires: root is a head of a queue - void model_node::dequeue(model_node*& root) { - TRACE("pdr", tout << this << " root: " << root << " " << state() << "\n";); - if (!m_next && !m_prev) return; - SASSERT(m_next); - SASSERT(m_prev); - SASSERT(children().empty()); - if (this == m_next) { - SASSERT(m_prev == this); - if (root == this) { - root = nullptr; - } - } - else { - m_next->m_prev = m_prev; - m_prev->m_next = m_next; - if (this == root) { - root = m_next; - } - } - TRACE("pdr", tout << "new root: " << root << "\n";); - m_prev = nullptr; - m_next = nullptr; - } - - - // insert node n after this in the queue - // requires: this is in a queue or this == n - void model_node::enqueue(model_node* n) { - TRACE("pdr", tout << n << " " << n->state() << "\n";); - SASSERT(!n->m_next); - SASSERT(!n->m_prev); - if (this == n) { - m_next = n; - m_prev = n; - } - else { - n->m_next = m_next; - m_next->m_prev = n; - m_next = n; - n->m_prev = this; - } - } - // ---------------- - // model_search - - /** - \brief Dequeue the next goal. - */ - model_node* model_search::next() { - if (!m_goal) { - return nullptr; - } - else { - model_node* result = m_goal; - result->dequeue(m_goal); - return result; - } - } - - - void model_search::add_leaf(model_node& n) { - SASSERT(n.children().empty()); - model_nodes ns; - model_nodes& nodes = cache(n).insert_if_not_there2(n.state(), ns)->get_data().m_value; - if (nodes.contains(&n)) { - return; - } - nodes.push_back(&n); - TRACE("pdr_verbose", tout << "add: " << n.level() << ": " << &n << " " << n.state() << "\n";); - if (nodes.size() == 1) { - set_leaf(n); - } - else { - n.set_pre_closed(); - } - } - - void model_search::set_leaf(model_node& n) { - // remove all children that n might have - erase_children(n, true); - SASSERT(n.is_open()); - enqueue_leaf(&n); - } - - void model_search::enqueue_leaf(model_node* n) { - TRACE("pdr_verbose", tout << "node: " << n << " " << n->state() << " goal: " << m_goal << "\n";); - SASSERT(n->is_open()); - // queue is empty, initialize it with n - if (!m_goal) { - m_goal = n; - m_goal->enqueue(n); - } - // insert n after m_goal - else if (m_bfs) { - m_goal->enqueue(n); - } - // insert n after m_goal()->next() - else { - m_goal->next()->enqueue(n); - } - } - - void model_search::set_root(model_node* root) { - reset(); - m_root = root; - SASSERT(cache(*root).empty()); - cache(*root).insert(root->state(), 1); - set_leaf(*root); - } - - obj_map >& model_search::cache(model_node const& n) { - unsigned l = n.orig_level(); - if (l >= m_cache.size()) { - m_cache.resize(l + 1); - } - return m_cache[l]; - } - - void model_search::erase_children(model_node& n, bool backtrack) { - ptr_vector todo, nodes; - todo.append(n.children()); - // detach n from queue - remove_goal(n); - // removes children - n.reset(); - while (!todo.empty()) { - model_node* m = todo.back(); - todo.pop_back(); - nodes.push_back(m); - todo.append(m->children()); - remove_node(*m, backtrack); - } - std::for_each(nodes.begin(), nodes.end(), delete_proc()); - } - - // removes node from the search tree and from the cache - void model_search::remove_node(model_node& n, bool backtrack) { - TRACE("pdr_verbose", tout << "remove: " << n.level() << ": " << &n << " " << n.state() << "\n";); - model_nodes& nodes = cache(n).find(n.state()); - nodes.erase(&n); - // detach n from m_goals - remove_goal(n); - // TBD: siblings would also fail if n is not a goal. - if (!nodes.empty() && backtrack && nodes[0]->children().empty() && nodes[0]->is_closed()) { - TRACE("pdr_verbose", for (unsigned i = 0; i < nodes.size(); ++i) n.display(tout << &n << "\n", 2);); - model_node* n1 = nodes[0]; - n1->set_open(); - enqueue_leaf(n1); - } - - if (!nodes.empty() && n.get_model_ptr() && backtrack) { - model_ref mr(n.get_model_ptr()); - nodes[0]->set_model(mr); - } - if (nodes.empty()) { - cache(n).remove(n.state()); - } - } - - // detach node n from the queue m_goal - void model_search::remove_goal(model_node& n) { - n.dequeue(m_goal); - } - - void model_search::well_formed() { - // each open leaf is in the set of m_goal. - ptr_vector nodes; - nodes.push_back(&get_root()); - for (unsigned i = 0; i < nodes.size(); ++i) { - model_node* n = nodes[i]; - if (!n->children().empty()) { - nodes.append(n->children()); - } - else if (n->is_open() && !n->is_goal() && n->parent()) { - TRACE("pdr", n->display(tout << "node " << n << " not found among leaves\n", 0); display(tout);); - UNREACHABLE(); - return; - } - } - if (m_goal) { - model_node* n = m_goal; - do { - if (!n->is_open() || !n->children().empty()) { - TRACE("pdr", n->display(tout << "invalid leaf\n", 0); - display(tout);); - UNREACHABLE(); - return; - } - n = n->next(); - } - while (m_goal != n); - } - - // each state appears in at most one goal per level. - bool found = true; - for (unsigned l = 0; m_goal && found; ++l) { - found = false; - obj_hashtable open_states; - model_node* n = m_goal; - do { - if (n->level() == l) { - found = true; - if (n->is_open()) { - if (open_states.contains(n->state())) { - TRACE("pdr", n->display(tout << "repeated leaf\n", 0); display(tout);); - UNREACHABLE(); - } - open_states.insert(n->state()); - } - } - n = n->next(); - } - while (m_goal != n); - } - // a node is open if and only if it contains an - // open child which is a goal. - for (unsigned i = 0; i < nodes.size(); ++i) { - model_node* n = nodes[i]; - if (!n->children().empty() && n->parent()) { - found = false; - for (unsigned j = 0; !found && j < n->children().size(); ++j) { - found = n->children()[j]->is_open(); - } - if (n->is_open() != found) { - TRACE("pdr", n->display(tout << "node in inconsistent state\n", 0); display(tout);); - UNREACHABLE(); - } - } - } - } - - unsigned model_search::num_goals() const { - model_node* n = m_goal; - unsigned num = 0; - if (n) { - do { - ++num; - n = n->next(); - } - while (n != m_goal); - } - return num; - } - - std::ostream& model_search::display(std::ostream& out) const { - if (m_root) { - m_root->display(out, 0); - } - out << "goals " << num_goals() << "\n"; - model_node* n = m_goal; - if (n) { - do { - n->display(out, 1); - n = n->next(); - } - while (n != m_goal); - } - return out; - } - - /** - \brief Ensure that all nodes in the tree have associated models. - get_trace and get_proof_trace rely on models to extract rules. - */ - void model_search::update_models() { - obj_map models; - obj_map rules; - ptr_vector todo; - todo.push_back(m_root); - while (!todo.empty()) { - model_node* n = todo.back(); - if (n->get_model_ptr()) { - models.insert(n->state(), n->get_model_ptr()); - rules.insert(n->state(), n->get_rule()); - } - todo.pop_back(); - todo.append(n->children().size(), n->children().c_ptr()); - } - - todo.push_back(m_root); - while (!todo.empty()) { - model_node* n = todo.back(); - model* md = nullptr; - if (!n->get_model_ptr()) { - if (models.find(n->state(), md)) { - TRACE("pdr", tout << n->state() << "\n";); - model_ref mr(md); - n->set_model(mr); - datalog::rule const* rule = rules.find(n->state()); - n->set_rule(rule); - } - else { - TRACE("pdr", tout << "no model for " << n->state() << "\n";); - IF_VERBOSE(1, n->display(verbose_stream() << "no model:\n", 0); - verbose_stream() << n->state() << "\n";); - } - } - else { - TRACE("pdr", tout << n->state() << "\n";); - } - todo.pop_back(); - todo.append(n->children().size(), n->children().c_ptr()); - } - } - - /** - Extract trace comprising of constraints - and predicates that are satisfied from facts to the query. - The resulting trace - */ - expr_ref model_search::get_trace(context const& ctx) { - pred_transformer& pt = get_root().pt(); - ast_manager& m = pt.get_manager(); - manager& pm = pt.get_pdr_manager(); - datalog::context& dctx = ctx.get_context(); - datalog::rule_manager& rm = dctx.get_rule_manager(); - expr_ref_vector constraints(m), predicates(m); - expr_ref tmp(m); - ptr_vector children; - unsigned deltas[2]; - datalog::rule_ref rule(rm), r0(rm); - model_node* n = m_root; - datalog::rule_counter& vc = rm.get_counter(); - substitution subst(m); - unifier unif(m); - rule = n->get_rule(); - unsigned max_var = vc.get_max_rule_var(*rule); - predicates.push_back(rule->get_head()); - children.push_back(n); - bool first = true; - update_models(); - while (!children.empty()) { - SASSERT(children.size() == predicates.size()); - expr_ref_vector binding(m); - n = children.back(); - children.pop_back(); - TRACE("pdr", n->display(tout, 0);); - n->mk_instantiate(r0, rule, binding); - - max_var = std::max(max_var, vc.get_max_rule_var(*rule)); - subst.reset(); - subst.reserve(2, max_var+1); - deltas[0] = 0; - deltas[1] = max_var+1; - - VERIFY(unif(predicates.back(), rule->get_head(), subst)); - for (unsigned i = 0; i < constraints.size(); ++i) { - subst.apply(2, deltas, expr_offset(constraints[i].get(), 0), tmp); - dctx.get_rewriter()(tmp); - constraints[i] = tmp; - } - for (unsigned i = 0; i < predicates.size(); ++i) { - subst.apply(2, deltas, expr_offset(predicates[i].get(), 0), tmp); - predicates[i] = tmp; - } - if (!first) { - constraints.push_back(predicates.back()); - } - first = false; - predicates.pop_back(); - for (unsigned i = rule->get_uninterpreted_tail_size(); i < rule->get_tail_size(); ++i) { - subst.apply(2, deltas, expr_offset(rule->get_tail(i), 1), tmp); - constraints.push_back(tmp); - } - for (unsigned i = 0; i < constraints.size(); ++i) { - max_var = std::max(vc.get_max_var(constraints[i].get()), max_var); - } - if (n->children().empty()) { - // nodes whose states are repeated - // in the search tree do not have children. - continue; - } - - SASSERT(n->children().size() == rule->get_uninterpreted_tail_size()); - - for (unsigned i = 0; i < rule->get_uninterpreted_tail_size(); ++i) { - subst.apply(2, deltas, expr_offset(rule->get_tail(i), 1), tmp); - predicates.push_back(tmp); - } - for (unsigned i = 0; i < predicates.size(); ++i) { - max_var = std::max(vc.get_max_var(predicates[i].get()), max_var); - } - - children.append(n->children()); - } - expr_safe_replace repl(m); - for (unsigned i = 0; i < constraints.size(); ++i) { - expr* e = constraints[i].get(), *e1, *e2; - if (m.is_eq(e, e1, e2) && is_var(e1) && is_ground(e2)) { - repl.insert(e1, e2); - } - else if (m.is_eq(e, e1, e2) && is_var(e2) && is_ground(e1)) { - repl.insert(e2, e1); - } - } - expr_ref_vector result(m); - for (unsigned i = 0; i < constraints.size(); ++i) { - expr_ref tmp(m); - tmp = constraints[i].get(); - repl(tmp); - dctx.get_rewriter()(tmp); - if (!m.is_true(tmp)) { - result.push_back(tmp); - } - } - return pm.mk_and(result); - } - - proof_ref model_search::get_proof_trace(context const& ctx) { - pred_transformer& pt = get_root().pt(); - ast_manager& m = pt.get_manager(); - datalog::context& dctx = ctx.get_context(); - datalog::rule_manager& rm = dctx.get_rule_manager(); - datalog::rule_unifier unif(dctx); - datalog::dl_decl_util util(m); - datalog::rule_ref r0(rm), r1(rm); - obj_map cache; - obj_map rules; - ptr_vector todo; - proof_ref_vector trail(m); - datalog::rule_ref_vector rules_trail(rm); - proof* pr = nullptr; - unif.set_normalize(true); - todo.push_back(m_root); - update_models(); - while (!todo.empty()) { - model_node* n = todo.back(); - TRACE("pdr", n->display(tout, 0);); - if (cache.find(n->state(), pr)) { - todo.pop_back(); - continue; - } - ptr_vector pfs; - ptr_vector rls; - ptr_vector const& chs = n->children(); - pfs.push_back(0); - rls.push_back(0); - for (unsigned i = 0; i < chs.size(); ++i) { - if (cache.find(chs[i]->state(), pr)) { - pfs.push_back(pr); - rls.push_back(rules.find(chs[i]->state())); - } - else { - todo.push_back(chs[i]); - } - } - if (pfs.size() != 1 + chs.size()) { - continue; - } - proof_ref rl(m); - expr_ref_vector binding(m); - n->mk_instantiate(r0, r1, binding); - proof_ref p1(m), p2(m); - p1 = r0->get_proof(); - IF_VERBOSE(0, if (!p1) r0->display(dctx, verbose_stream());); - SASSERT(p1); - pfs[0] = p1; - rls[0] = r1; - TRACE("pdr", - tout << "root: " << mk_pp(p1.get(), m) << "\n"; - for (unsigned i = 0; i < binding.size(); ++i) { - tout << mk_pp(binding[i].get(), m) << "\n"; - } - for (unsigned i = 1; i < pfs.size(); ++i) { - tout << mk_pp(pfs[i], m) << "\n"; - } - ); - datalog::rule_ref reduced_rule(rm), r3(rm); - reduced_rule = rls[0]; - // check if binding is identity. - bool binding_is_id = true; - for (unsigned i = 0; binding_is_id && i < binding.size(); ++i) { - expr* v = binding[i].get(); - binding_is_id = is_var(v) && to_var(v)->get_idx() == i; - } - if (rls.size() > 1 || !binding_is_id) { - expr_ref tmp(m); - vector substs; - svector > positions; - substs.push_back(binding); // TODO base substitution. - for (unsigned i = 1; i < rls.size(); ++i) { - datalog::rule& src = *rls[i]; - bool unified = unif.unify_rules(*reduced_rule, 0, src); - if (!unified) { - IF_VERBOSE(0, - verbose_stream() << "Could not unify rules: "; - reduced_rule->display(dctx, verbose_stream()); - src.display(dctx, verbose_stream());); - } - expr_ref_vector sub1 = unif.get_rule_subst(*reduced_rule, true); - TRACE("pdr", - for (unsigned k = 0; k < sub1.size(); ++k) { - tout << mk_pp(sub1[k].get(), m) << " "; - } - tout << "\n"; - ); - - for (unsigned j = 0; j < substs.size(); ++j) { - for (unsigned k = 0; k < substs[j].size(); ++k) { - var_subst(m, false)(substs[j][k].get(), sub1.size(), sub1.c_ptr(), tmp); - substs[j][k] = tmp; - } - while (substs[j].size() < sub1.size()) { - substs[j].push_back(sub1[substs[j].size()].get()); - } - } - - positions.push_back(std::make_pair(i,0)); - substs.push_back(unif.get_rule_subst(src, false)); - VERIFY(unif.apply(*reduced_rule.get(), 0, src, r3)); - reduced_rule = r3; - } - - expr_ref fml_concl(m); - rm.to_formula(*reduced_rule.get(), fml_concl); - p1 = m.mk_hyper_resolve(pfs.size(), pfs.c_ptr(), fml_concl, positions, substs); - - } - cache.insert(n->state(), p1); - rules.insert(n->state(), reduced_rule); - trail.push_back(p1); - rules_trail.push_back(reduced_rule); - todo.pop_back(); - } - return proof_ref(cache.find(m_root->state()), m); - } - - model_search::~model_search() { - TRACE("pdr", tout << "\n";); - reset(); - } - - void model_search::reset() { - if (m_root) { - erase_children(*m_root, false); - remove_node(*m_root, false); - dealloc(m_root); - m_root = nullptr; - } - m_cache.reset(); - } - - void model_search::backtrack_level(bool uses_level, model_node& n) { - SASSERT(m_root); - if (uses_level && m_root->level() > n.level()) { - IF_VERBOSE(2, verbose_stream() << "Increase level " << n.level() << "\n";); - n.increase_level(); - enqueue_leaf(&n); - } - else { - model_node* p = n.parent(); - if (p) { - set_leaf(*p); - } - } - DEBUG_CODE(well_formed();); - } - - // ---------------- - // context - - context::context( - smt_params& fparams, - fixedpoint_params const& params, - ast_manager& m - ) - : m_fparams(fparams), - m_params(params), - m(m), - m_context(nullptr), - m_pm(m_fparams, params.pdr_max_num_contexts(), m), - m_query_pred(m), - m_query(nullptr), - m_search(m_params.pdr_bfs_model_search()), - m_last_result(l_undef), - m_inductive_lvl(0), - m_expanded_lvl(0) - { - } - - context::~context() { - reset_core_generalizers(); - reset(); - } - - void context::reset(decl2rel& rels) { - decl2rel::iterator it = rels.begin(), end = rels.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - rels.reset(); - } - - void context::reset(bool full) { - TRACE("pdr", tout << "reset\n";); - reset(m_rels); - if (full) { - reset(m_rels_tmp); - } - m_search.reset(); - m_query = nullptr; - m_last_result = l_undef; - m_inductive_lvl = 0; - } - - void context::init_rules(datalog::rule_set& rules, decl2rel& rels) { - m_context = &rules.get_context(); - // Allocate collection of predicate transformers - datalog::rule_set::decl2rules::iterator dit = rules.begin_grouped_rules(), dend = rules.end_grouped_rules(); - decl2rel::obj_map_entry* e; - for (; dit != dend; ++dit) { - func_decl* pred = dit->m_key; - TRACE("pdr", tout << mk_pp(pred, m) << "\n";); - SASSERT(!rels.contains(pred)); - e = rels.insert_if_not_there2(pred, alloc(pred_transformer, *this, get_pdr_manager(), pred)); - datalog::rule_vector const& pred_rules = *dit->m_value; - for (unsigned i = 0; i < pred_rules.size(); ++i) { - e->get_data().m_value->add_rule(pred_rules[i]); - } - } - TRACE("pdr", tout << "adding rules\n";); - datalog::rule_set::iterator rit = rules.begin(), rend = rules.end(); - for (; rit != rend; ++rit) { - datalog::rule* r = *rit; - pred_transformer* pt; - unsigned utz = r->get_uninterpreted_tail_size(); - for (unsigned i = 0; i < utz; ++i) { - func_decl* pred = r->get_decl(i); - if (!rels.find(pred, pt)) { - pt = alloc(pred_transformer, *this, get_pdr_manager(), pred); - rels.insert(pred, pt); - } - } - } - // Initialize use list dependencies - TRACE("pdr", tout << "initialize use list dependencies\n";); - decl2rel::iterator it = rels.begin(), end = rels.end(); - for (; it != end; ++it) { - func_decl* pred = it->m_key; - pred_transformer* pt = it->m_value, *pt_user; - obj_hashtable const& deps = rules.get_dependencies().get_deps(pred); - obj_hashtable::iterator itf = deps.begin(), endf = deps.end(); - for (; itf != endf; ++itf) { - TRACE("pdr", tout << mk_pp(pred, m) << " " << mk_pp(*itf, m) << "\n";); - pt_user = rels.find(*itf); - pt_user->add_use(pt); - } - } - - TRACE("pdr", tout << "initialize predicate transformers\n";); - // Initialize the predicate transformers. - it = rels.begin(), end = rels.end(); - for (; it != end; ++it) { - SASSERT(it->m_value); - pred_transformer& rel = *it->m_value; - rel.initialize(rels); - TRACE("pdr", rel.display(tout); ); - } - } - - void context::update_rules(datalog::rule_set& rules) { - TRACE("pdr", tout << "update rules\n";); - reset(m_rels_tmp); - init_core_generalizers(rules); - init_rules(rules, m_rels_tmp); - decl2rel::iterator it = m_rels_tmp.begin(), end = m_rels_tmp.end(); - for (; it != end; ++it) { - pred_transformer* pt = nullptr; - if (m_rels.find(it->m_key, pt)) { - it->m_value->inherit_properties(*pt); - } - } - reset(false); - it = m_rels_tmp.begin(), end = m_rels_tmp.end(); - for (; it != end; ++it) { - m_rels.insert(it->m_key, it->m_value); - } - m_rels_tmp.reset(); - TRACE("pdr", tout << "done update rules\n";); - } - - unsigned context::get_num_levels(func_decl* p) { - pred_transformer* pt = nullptr; - if (m_rels.find(p, pt)) { - return pt->get_num_levels(); - } - else { - IF_VERBOSE(10, verbose_stream() << "did not find predicate " << p->get_name() << "\n";); - return 0; - } - } - - expr_ref context::get_cover_delta(int level, func_decl* p_orig, func_decl* p) { - pred_transformer* pt = nullptr; - if (m_rels.find(p, pt)) { - return pt->get_cover_delta(p_orig, level); - } - else { - IF_VERBOSE(10, verbose_stream() << "did not find predicate " << p->get_name() << "\n";); - return expr_ref(m.mk_true(), m); - } - } - - void context::add_cover(int level, func_decl* p, expr* property) { - pred_transformer* pt = nullptr; - if (!m_rels.find(p, pt)) { - pt = alloc(pred_transformer, *this, get_pdr_manager(), p); - m_rels.insert(p, pt); - IF_VERBOSE(10, verbose_stream() << "did not find predicate " << p->get_name() << "\n";); - } - unsigned lvl = (level == -1)?infty_level:((unsigned)level); - pt->add_cover(lvl, property); - } - - class context::classifier_proc { - ast_manager& m; - arith_util a; - bool m_is_bool; - bool m_is_bool_arith; - bool m_has_arith; - bool m_is_dl; - bool m_is_utvpi; - public: - classifier_proc(ast_manager& m, datalog::rule_set& rules): - m(m), a(m), m_is_bool(true), m_is_bool_arith(true), m_has_arith(false), m_is_dl(false), m_is_utvpi(false) { - classify(rules); - } - void operator()(expr* e) { - if (m_is_bool) { - if (!m.is_bool(e)) { - m_is_bool = false; - } - else if (is_var(e)) { - // no-op. - } - else if (!is_app(e)) { - m_is_bool = false; - } - else if (to_app(e)->get_num_args() > 0 && - to_app(e)->get_family_id() != m.get_basic_family_id()) { - m_is_bool = false; - } - } - - m_has_arith = m_has_arith || a.is_int_real(e); - - if (m_is_bool_arith) { - if (!m.is_bool(e) && !a.is_int_real(e)) { - m_is_bool_arith = false; - } - else if (is_var(e)) { - // no-op - } - else if (!is_app(e)) { - m_is_bool_arith = false; - } - else if (to_app(e)->get_num_args() > 0 && - to_app(e)->get_family_id() != m.get_basic_family_id() && - to_app(e)->get_family_id() != a.get_family_id()) { - m_is_bool_arith = false; - } - } - } - - bool is_bool() const { return m_is_bool; } - - bool is_bool_arith() const { return m_is_bool_arith; } - - bool is_dl() const { return m_is_dl; } - - bool is_utvpi() const { return m_is_utvpi; } - - private: - - void classify(datalog::rule_set& rules) { - expr_fast_mark1 mark; - datalog::rule_set::iterator it = rules.begin(), end = rules.end(); - for (; it != end; ++it) { - datalog::rule& r = *(*it); - classify_pred(mark, r.get_head()); - unsigned utsz = r.get_uninterpreted_tail_size(); - for (unsigned i = 0; i < utsz; ++i) { - classify_pred(mark, r.get_tail(i)); - } - for (unsigned i = utsz; i < r.get_tail_size(); ++i) { - quick_for_each_expr(*this, mark, r.get_tail(i)); - } - } - mark.reset(); - - m_is_dl = false; - m_is_utvpi = false; - if (m_has_arith) { - ptr_vector forms; - for (it = rules.begin(); it != end; ++it) { - datalog::rule& r = *(*it); - unsigned utsz = r.get_uninterpreted_tail_size(); - forms.push_back(r.get_head()); - for (unsigned i = utsz; i < r.get_tail_size(); ++i) { - forms.push_back(r.get_tail(i)); - } - } - m_is_dl = is_difference_logic(m, forms.size(), forms.c_ptr()); - m_is_utvpi = m_is_dl || is_utvpi_logic(m, forms.size(), forms.c_ptr()); - } - } - - void classify_pred(expr_fast_mark1& mark, app* pred) { - for (unsigned i = 0; i < pred->get_num_args(); ++i) { - quick_for_each_expr(*this, mark, pred->get_arg(i)); - } - } - }; - - void context::validate_proof() { - std::stringstream msg; - proof_ref pr = get_proof(); - proof_checker checker(m); - expr_ref_vector side_conditions(m); - bool ok = checker.check(pr, side_conditions); - if (!ok) { - msg << "proof validation failed"; - IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - throw default_exception(msg.str()); - } - for (unsigned i = 0; i < side_conditions.size(); ++i) { - expr* cond = side_conditions[i].get(); - expr_ref tmp(m); - - tmp = m.mk_not(cond); - IF_VERBOSE(2, verbose_stream() << "checking side-condition:\n" << mk_pp(cond, m) << "\n";); - smt::kernel solver(m, get_fparams()); - solver.assert_expr(tmp); - lbool res = solver.check(); - if (res != l_false) { - msg << "rule validation failed when checking: " << mk_pp(cond, m); - IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - throw default_exception(msg.str()); - } - } - } - - void context::validate_search() { - expr_ref tr = m_search.get_trace(*this); - TRACE("pdr", tout << tr << "\n";); - smt::kernel solver(m, get_fparams()); - solver.assert_expr(tr); - lbool res = solver.check(); - if (res != l_true) { - std::stringstream msg; - msg << "rule validation failed when checking: " << tr; - IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - throw default_exception(msg.str()); - } - } - - void context::validate_model() { - IF_VERBOSE(1, verbose_stream() << "(pdr.validate_model)\n";); - std::stringstream msg; - expr_ref_vector refs(m); - expr_ref tmp(m); - model_ref model; - vector rs; - model_converter_ref mc; - get_level_property(m_inductive_lvl, refs, rs); - inductive_property ex(m, mc, rs); - ex.to_model(model); - var_subst vs(m, false); - expr_free_vars fv; - for (auto const& kv : m_rels) { - ptr_vector const& rules = kv.m_value->rules(); - for (unsigned i = 0; i < rules.size(); ++i) { - datalog::rule& r = *rules[i]; - model->eval(r.get_head(), tmp); - expr_ref_vector fmls(m); - fmls.push_back(m.mk_not(tmp)); - unsigned utsz = r.get_uninterpreted_tail_size(); - unsigned tsz = r.get_tail_size(); - for (unsigned j = 0; j < utsz; ++j) { - model->eval(r.get_tail(j), tmp); - fmls.push_back(tmp); - } - for (unsigned j = utsz; j < tsz; ++j) { - fmls.push_back(r.get_tail(j)); - } - tmp = m.mk_and(fmls.size(), fmls.c_ptr()); - svector names; - fv(tmp); - fv.set_default_sort(m.mk_bool_sort()); - for (unsigned i = 0; i < fv.size(); ++i) { - names.push_back(symbol(i)); - } - fv.reverse(); - if (!fv.empty()) { - tmp = m.mk_exists(fv.size(), fv.c_ptr(), names.c_ptr(), tmp); - } - smt::kernel solver(m, get_fparams()); - solver.assert_expr(tmp); - lbool res = solver.check(); - TRACE("pdr", tout << tmp << " " << res << "\n";); - if (res != l_false) { - msg << "rule validation failed when checking: " << mk_pp(tmp, m); - IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); - throw default_exception(msg.str()); - } - } - } - } - - void context::validate() { - if (!m_params.pdr_validate_result()) { - return; - } - switch(m_last_result) { - case l_true: - if (m_params.generate_proof_trace()) { - validate_proof(); - } - validate_search(); - break; - case l_false: - validate_model(); - break; - default: - break; - } - } - - void context::reset_core_generalizers() { - std::for_each(m_core_generalizers.begin(), m_core_generalizers.end(), delete_proc()); - m_core_generalizers.reset(); - } - - void context::init_core_generalizers(datalog::rule_set& rules) { - reset_core_generalizers(); - classifier_proc classify(m, rules); - bool use_mc = m_params.pdr_use_multicore_generalizer(); - if (use_mc) { - m_core_generalizers.push_back(alloc(core_multi_generalizer, *this, 0)); - } - if (!classify.is_bool()) { - m.toggle_proof_mode(PGM_ENABLED); - m_fparams.m_arith_bound_prop = BP_NONE; - m_fparams.m_arith_auto_config_simplex = true; - m_fparams.m_arith_propagate_eqs = false; - m_fparams.m_arith_eager_eq_axioms = false; - if (m_params.pdr_utvpi() && - !m_params.pdr_use_convex_closure_generalizer() && - !m_params.pdr_use_convex_interior_generalizer()) { - if (classify.is_dl()) { - m_fparams.m_arith_mode = AS_DIFF_LOGIC; - m_fparams.m_arith_eq2ineq = true; - } - else if (classify.is_utvpi()) { - IF_VERBOSE(1, verbose_stream() << "UTVPI\n";); - m_fparams.m_arith_mode = AS_UTVPI; - m_fparams.m_arith_eq2ineq = true; - } - else { - m_fparams.m_arith_mode = AS_ARITH; - m_fparams.m_arith_eq2ineq = false; - } - } - } - if (m_params.pdr_use_convex_closure_generalizer()) { - m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this, true)); - } - if (m_params.pdr_use_convex_interior_generalizer()) { - m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this, false)); - } - if (!use_mc && m_params.pdr_use_inductive_generalizer()) { - m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0)); - } - if (m_params.pdr_inductive_reachability_check()) { - m_core_generalizers.push_back(alloc(core_induction_generalizer, *this)); - } - if (m_params.pdr_use_arith_inductive_generalizer()) { - m_core_generalizers.push_back(alloc(core_arith_inductive_generalizer, *this)); - } - - } - - void context::get_level_property(unsigned lvl, expr_ref_vector& res, vector& rs) { - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - pred_transformer* r = it->m_value; - if (r->head() == m_query_pred) { - continue; - } - expr_ref conj = r->get_formulas(lvl, false); - m_pm.formula_n2o(0, false, conj); - res.push_back(conj); - ptr_vector sig(r->head()->get_arity(), r->sig()); - rs.push_back(relation_info(m, r->head(), sig, conj)); - } - } - - void context::simplify_formulas() { - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - pred_transformer* r = it->m_value; - r->simplify_formulas(); - } - } - - lbool context::solve() { - TRACE("pdr", tout << "solve\n";); - m_last_result = l_undef; - try { - solve_impl(); - UNREACHABLE(); - } - catch (model_exception) { - IF_VERBOSE(1, verbose_stream() << "\n"; m_search.display(verbose_stream());); - m_last_result = l_true; - validate(); - - IF_VERBOSE(1, - if (m_params.print_boogie_certificate()) { - display_certificate(verbose_stream()); - }); - - return l_true; - } - catch (inductive_exception) { - simplify_formulas(); - m_last_result = l_false; - TRACE("pdr", display_certificate(tout);); - IF_VERBOSE(1, { - expr_ref_vector refs(m); - vector rs; - get_level_property(m_inductive_lvl, refs, rs); - model_converter_ref mc; - inductive_property ex(m, mc, rs); - verbose_stream() << ex.to_string(); - }); - - // upgrade invariants that are known to be inductive. - decl2rel::iterator it = m_rels.begin (), end = m_rels.end (); - for (; m_inductive_lvl > 0 && it != end; ++it) { - if (it->m_value->head() != m_query_pred) { - it->m_value->propagate_to_infinity (m_inductive_lvl); - } - } - validate(); - return l_false; - } - catch (unknown_exception) { - return l_undef; - } - UNREACHABLE(); - return l_undef; - } - - void context::checkpoint() { - if (m.canceled()) { - throw default_exception(Z3_CANCELED_MSG); - } - } - - /** - \brief retrieve answer. - */ - expr_ref context::get_answer() { - switch(m_last_result) { - case l_true: return mk_sat_answer(); - case l_false: return mk_unsat_answer(); - default: return expr_ref(m.mk_true(), m); - } - } - - model_ref context::get_model() { - SASSERT(m_last_result == l_false); - expr_ref_vector refs(m); - vector rs; - model_ref md; - get_level_property(m_inductive_lvl, refs, rs); - inductive_property ex(m, m_mc, rs); - ex.to_model(md); - return md; - } - - proof_ref context::get_proof() const { - scoped_proof _sc(m); - proof_ref proof(m); - SASSERT(m_last_result == l_true); - proof = m_search.get_proof_trace(*this); - TRACE("pdr", tout << "PDR trace: " << proof << "\n";); - apply(m, m_pc.get(), proof); - TRACE("pdr", tout << "PDR trace: " << proof << "\n";); - // proof_utils::push_instantiations_up(proof); - // TRACE("pdr", tout << "PDR up: " << proof << "\n";); - return proof; - } - - - /** - \brief Retrieve satisfying assignment with explanation. - */ - expr_ref context::mk_sat_answer() const { - if (m_params.generate_proof_trace()) { - proof_ref pr = get_proof(); - return expr_ref(pr.get(), m); - } - return m_search.get_trace(*this); - } - - expr_ref context::mk_unsat_answer() { - expr_ref_vector refs(m); - vector rs; - get_level_property(m_inductive_lvl, refs, rs); - inductive_property ex(m, const_cast(m_mc), rs); - return ex.to_expr(); - } - - void context::solve_impl() { - if (!m_rels.find(m_query_pred, m_query)) { - throw inductive_exception(); - } - unsigned lvl = 0; - bool reachable; - while (true) { - checkpoint(); - m_expanded_lvl = lvl; - reachable = check_reachability(lvl); - if (reachable) { - throw model_exception(); - } - if (lvl != 0) { - propagate(lvl); - } - lvl++; - m_stats.m_max_depth = std::max(m_stats.m_max_depth, lvl); - IF_VERBOSE(1,verbose_stream() << "Entering level "<level() << "\n";); - checkpoint(); - expand_node(*node); - } - return root->is_closed(); - } - - void context::close_node(model_node& n) { - n.set_closed(); - model_node* p = n.parent(); - while (p && p->is_1closed()) { - p->set_closed(); - p = p->parent(); - } - } - - - void context::expand_node(model_node& n) { - SASSERT(n.is_open()); - expr_ref_vector cube(m); - - if (n.level() < m_expanded_lvl) { - m_expanded_lvl = n.level(); - } - - pred_transformer::scoped_farkas sf (n.pt(), m_params.pdr_farkas()); - if (n.pt().is_reachable(n.state())) { - TRACE("pdr", tout << "reachable\n";); - close_node(n); - } - else { - bool uses_level = true; - switch (expand_state(n, cube, uses_level)) { - case l_true: - if (n.level() == 0) { - TRACE("pdr", n.display(tout << "reachable at level 0\n", 0);); - close_node(n); - } - else { - TRACE("pdr", n.display(tout, 0);); - create_children(n); - } - break; - case l_false: { - core_generalizer::cores cores; - cores.push_back(std::make_pair(cube, uses_level)); - TRACE("pdr", tout << "cube:\n"; - for (unsigned j = 0; j < cube.size(); ++j) tout << mk_pp(cube[j].get(), m) << "\n";); - for (unsigned i = 0; !cores.empty() && i < m_core_generalizers.size(); ++i) { - core_generalizer::cores new_cores; - for (unsigned j = 0; j < cores.size(); ++j) { - (*m_core_generalizers[i])(n, cores[j].first, cores[j].second, new_cores); - } - cores.reset(); - cores.append(new_cores); - } - bool found_invariant = false; - for (unsigned i = 0; i < cores.size(); ++i) { - expr_ref_vector const& core = cores[i].first; - uses_level = cores[i].second; - found_invariant = !uses_level || found_invariant; - expr_ref ncore(m_pm.mk_not_and(core), m); - TRACE("pdr", tout << "invariant state: " << (uses_level?"":"(inductive) ") << mk_pp(ncore, m) << "\n";); - n.pt().add_property(ncore, uses_level?n.level():infty_level); - } - CASSERT("pdr",n.level() == 0 || check_invariant(n.level()-1)); - m_search.backtrack_level(!found_invariant && m_params.pdr_flexible_trace(), n); - break; - } - case l_undef: { - TRACE("pdr", tout << "unknown state: " << mk_pp(m_pm.mk_and(cube), m) << "\n";); - IF_VERBOSE(1, verbose_stream() << "unknown state\n";); - throw unknown_exception(); - } - } - } - } - - // - // check if predicate transformer has a satisfiable predecessor state. - // returns either a satisfiable predecessor state or - // return a property that blocks state and is implied by the - // predicate transformer (or some unfolding of it). - // - lbool context::expand_state(model_node& n, expr_ref_vector& result, bool& uses_level) { - TRACE("pdr", - tout << "expand_state: " << n.pt().head()->get_name(); - tout << " level: " << n.level() << "\n"; - tout << mk_pp(n.state(), m) << "\n";); - - return n.pt().is_reachable(n, &result, uses_level); - } - - void context::propagate(unsigned max_prop_lvl) { - if (m_params.pdr_simplify_formulas_pre()) { - simplify_formulas(); - } - for (unsigned lvl = m_expanded_lvl; lvl <= max_prop_lvl; lvl++) { - checkpoint(); - bool all_propagated = true; - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - checkpoint(); - pred_transformer& r = *it->m_value; - all_propagated = r.propagate_to_next_level(lvl) && all_propagated; - } - CASSERT("pdr", check_invariant(lvl)); - - if (all_propagated && lvl == max_prop_lvl) { - m_inductive_lvl = lvl; - throw inductive_exception(); - } - } - if (m_params.pdr_simplify_formulas_post()) { - simplify_formulas(); - } - } - - - /** - \brief create children states from model cube. - - Introduce the shorthands: - - - T(x0,x1,x) for transition - - phi(x) for n.state() - - M(x0,x1,x) for n.model() - - Assumptions: - M => phi & T - - In other words, - 1. phi & T is implied by M - - Goal is to find phi0(x0), phi1(x1) such that: - - phi(x) & phi0(x0) & phi1(x1) => T(x0, x1, x) - - Strategy: - - - Extract literals from T & phi using ternary simulation with M. - - resulting formula is Phi. - - - perform cheap existential quantifier elimination on - Phi <- exists x . Phi(x0,x1,x) - (e.g., destructive equality resolution) - - - Sub-strategy 1: rename remaining x to fresh variables. - - Sub-strategy 2: replace remaining x to M(x). - - - For each literal L in result: - - - if L is x0 pure, add L to L0 - - if L is x1 pure, add L to L1 - - if L mixes x0, x1, add x1 = M(x1) to L1, add L(x1 |-> M(x1)) to L0 - - - Create sub-goals for L0 and L1. - - */ - void context::create_children(model_node& n) { - SASSERT(n.level() > 0); - bool use_model_generalizer = m_params.pdr_use_model_generalizer(); - scoped_no_proof _sc(m); - - pred_transformer& pt = n.pt(); - model_ref M = n.get_model_ptr(); - SASSERT(M.get()); - datalog::rule const& r = pt.find_rule(*M); - expr* T = pt.get_transition(r); - expr* phi = n.state(); - - n.set_rule(&r); - - - TRACE("pdr", - tout << "Model:\n"; - model_smt2_pp(tout, m, *M, 0); - tout << "\n"; - tout << "Transition:\n" << mk_pp(T, m) << "\n"; - tout << "Phi:\n" << mk_pp(phi, m) << "\n";); - - model_implicant mev(m); - expr_ref_vector mdl(m), forms(m), Phi(m); - forms.push_back(T); - forms.push_back(phi); - flatten_and(forms); - ptr_vector forms1(forms.size(), forms.c_ptr()); - if (use_model_generalizer) { - Phi.append(mev.minimize_model(forms1, M)); - } - else { - Phi.append(mev.minimize_literals(forms1, M)); - } - ptr_vector preds; - pt.find_predecessors(r, preds); - pt.remove_predecessors(Phi); - - app_ref_vector vars(m); - unsigned sig_size = pt.head()->get_arity(); - for (unsigned i = 0; i < sig_size; ++i) { - vars.push_back(m.mk_const(m_pm.o2n(pt.sig(i), 0))); - } - ptr_vector& aux_vars = pt.get_aux_vars(r); - vars.append(aux_vars.size(), aux_vars.c_ptr()); - - scoped_ptr rep; - qe_lite qe(m, m_params.p); - expr_ref phi1 = m_pm.mk_and(Phi); - qe(vars, phi1); - TRACE("pdr", tout << "Eliminated\n" << mk_pp(phi1, m) << "\n";); - if (!use_model_generalizer) { - reduce_disequalities(*M, 3, phi1); - TRACE("pdr", tout << "Reduced-eq\n" << mk_pp(phi1, m) << "\n";); - } - get_context().get_rewriter()(phi1); - - TRACE("pdr", - tout << "Vars:\n"; - for (unsigned i = 0; i < vars.size(); ++i) { - tout << mk_pp(vars[i].get(), m) << "\n"; - } - tout << "Literals\n"; - tout << mk_pp(m_pm.mk_and(Phi), m) << "\n"; - tout << "Reduced\n" << mk_pp(phi1, m) << "\n";); - - if (!vars.empty()) { - // also fresh names for auxiliary variables in body? - expr_substitution sub(m); - expr_ref tmp(m); - proof_ref pr(m); - pr = m.mk_asserted(m.mk_true()); - for (unsigned i = 0; i < vars.size(); ++i) { - tmp = mev.eval(M, vars[i].get()); - sub.insert(vars[i].get(), tmp, pr); - } - if (!rep) rep = mk_expr_simp_replacer(m); - rep->set_substitution(&sub); - (*rep)(phi1); - TRACE("pdr", tout << "Projected:\n" << mk_pp(phi1, m) << "\n";); - } - Phi.reset(); - flatten_and(phi1, Phi); - unsigned_vector indices; - vector child_states; - child_states.resize(preds.size(), expr_ref_vector(m)); - for (unsigned i = 0; i < Phi.size(); ++i) { - m_pm.collect_indices(Phi[i].get(), indices); - if (indices.size() == 0) { - IF_VERBOSE(3, verbose_stream() << "Skipping " << mk_pp(Phi[i].get(), m) << "\n";); - } - else if (indices.size() == 1) { - child_states[indices.back()].push_back(Phi[i].get()); - } - else { - expr_substitution sub(m); - expr_ref tmp(m); - proof_ref pr(m); - pr = m.mk_asserted(m.mk_true()); - vector > vars; - m_pm.collect_variables(Phi[i].get(), vars); - SASSERT(vars.size() == indices.back()+1); - for (unsigned j = 1; j < indices.size(); ++j) { - ptr_vector const& vs = vars[indices[j]]; - for (unsigned k = 0; k < vs.size(); ++k) { - tmp = mev.eval(M, vs[k]); - sub.insert(vs[k], tmp, pr); - child_states[indices[j]].push_back(m.mk_eq(vs[k], tmp)); - } - } - tmp = Phi[i].get(); - if (!rep) rep = mk_expr_simp_replacer(m); - rep->set_substitution(&sub); - (*rep)(tmp); - child_states[indices[0]].push_back(tmp); - } - - } - - expr_ref n_cube(m); - for (unsigned i = 0; i < preds.size(); ++i) { - pred_transformer& pt = *m_rels.find(preds[i]); - SASSERT(pt.head() == preds[i]); - expr_ref o_cube = m_pm.mk_and(child_states[i]); - m_pm.formula_o2n(o_cube, n_cube, i); - model_node* child = alloc(model_node, &n, n_cube, pt, n.level()-1); - ++m_stats.m_num_nodes; - m_search.add_leaf(*child); - IF_VERBOSE(2, verbose_stream() << "Predecessor: " << mk_pp(n_cube, m) << " " << (child->is_closed()?"closed":"open") << "\n";); - m_stats.m_max_depth = std::max(m_stats.m_max_depth, child->depth()); - } - n.check_pre_closed(); - TRACE("pdr", m_search.display(tout);); - } - - void context::collect_statistics(statistics& st) const { - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (it = m_rels.begin(); it != end; ++it) { - it->m_value->collect_statistics(st); - } - st.update("PDR num unfoldings", m_stats.m_num_nodes); - st.update("PDR max depth", m_stats.m_max_depth); - st.update("PDR inductive level", m_inductive_lvl); - m_pm.collect_statistics(st); - - for (unsigned i = 0; i < m_core_generalizers.size(); ++i) { - m_core_generalizers[i]->collect_statistics(st); - } - } - - void context::reset_statistics() { - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (it = m_rels.begin(); it != end; ++it) { - it->m_value->reset_statistics(); - } - m_stats.reset(); - m_pm.reset_statistics(); - - for (unsigned i = 0; i < m_core_generalizers.size(); ++i) { - m_core_generalizers[i]->reset_statistics(); - } - - } - - - std::ostream& context::display(std::ostream& out) const { - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - it->m_value->display(out); - } - m_search.display(out); - return out; - } - - bool context::check_invariant(unsigned lvl) { - decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); - for (; it != end; ++it) { - checkpoint(); - if (!check_invariant(lvl, it->m_key)) { - return false; - } - } - return true; - } - - bool context::check_invariant(unsigned lvl, func_decl* fn) { - smt::kernel ctx(m, m_fparams); - pred_transformer& pt = *m_rels.find(fn); - expr_ref_vector conj(m); - expr_ref inv = pt.get_formulas(next_level(lvl), false); - if (m.is_true(inv)) return true; - pt.add_premises(m_rels, lvl, conj); - conj.push_back(m.mk_not(inv)); - expr_ref fml(m.mk_and(conj.size(), conj.c_ptr()), m); - ctx.assert_expr(fml); - lbool result = ctx.check(); - TRACE("pdr", tout << "Check invariant level: " << lvl << " " << result << "\n" << mk_pp(fml, m) << "\n";); - return result == l_false; - } - - void context::display_certificate(std::ostream& strm) { - switch(m_last_result) { - case l_false: { - expr_ref_vector refs(m); - vector rs; - get_level_property(m_inductive_lvl, refs, rs); - inductive_property ex(m, const_cast(m_mc), rs); - strm << ex.to_string(); - break; - } - case l_true: { - if (m_params.print_boogie_certificate()) { - datalog::boogie_proof bp(m); - bp.set_proof(get_proof()); - bp.set_model(nullptr); - bp.pp(strm); - } - else { - strm << mk_pp(mk_sat_answer(), m); - } - break; - } - case l_undef: { - strm << "unknown"; - break; - } - } - } - -} diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h deleted file mode 100644 index ebaa3f257..000000000 --- a/src/muz/pdr/pdr_context.h +++ /dev/null @@ -1,448 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_context.h - -Abstract: - - PDR for datalog - -Author: - - Nikolaj Bjorner (nbjorner) 2011-11-20. - -Revision History: - ---*/ - -#ifndef PDR_CONTEXT_H_ -#define PDR_CONTEXT_H_ - -#ifdef _CYGWIN -#undef min -#undef max -#endif -#include -#include "muz/pdr/pdr_manager.h" -#include "muz/pdr/pdr_prop_solver.h" -#include "muz/pdr/pdr_reachable_cache.h" -#include "muz/base/fixedpoint_params.hpp" - - -namespace datalog { - class rule_set; - class context; -}; - -namespace pdr { - - class pred_transformer; - class model_node; - class context; - - typedef obj_map rule2inst; - typedef obj_map decl2rel; - - - // - // Predicate transformer state. - // A predicate transformer corresponds to the - // set of rules that have the same head predicates. - // - - class pred_transformer { - - struct stats { - unsigned m_num_propagations; - stats() { reset(); } - void reset() { memset(this, 0, sizeof(*this)); } - }; - - typedef obj_map rule2expr; - typedef obj_map > rule2apps; - - manager& pm; // pdr-manager - ast_manager& m; // manager - context& ctx; - - func_decl_ref m_head; // predicate - func_decl_ref_vector m_sig; // signature - ptr_vector m_use; // places where 'this' is referenced. - ptr_vector m_rules; // rules used to derive transformer - prop_solver m_solver; // solver context - vector m_levels; // level formulas - expr_ref_vector m_invariants; // properties that are invariant. - obj_map m_prop2level; // map property to level where it occurs. - obj_map m_tag2rule; // map tag predicate to rule. - rule2expr m_rule2tag; // map rule to predicate tag. - rule2inst m_rule2inst; // map rules to instantiations of indices - rule2expr m_rule2transition; // map rules to transition - rule2apps m_rule2vars; // map rule to auxiliary variables - expr_ref m_transition; // transition relation. - expr_ref m_initial_state; // initial state. - reachable_cache m_reachable; - ptr_vector m_predicates; - stats m_stats; - - void init_sig(); - void ensure_level(unsigned level); - bool add_property1(expr * lemma, unsigned lvl); // add property 'p' to state at level lvl. - void add_child_property(pred_transformer& child, expr* lemma, unsigned lvl); - void mk_assumptions(func_decl* head, expr* fml, expr_ref_vector& result); - - // Initialization - void init_rules(decl2rel const& pts, expr_ref& init, expr_ref& transition); - void init_rule(decl2rel const& pts, datalog::rule const& rule, expr_ref& init, - ptr_vector& rules, expr_ref_vector& transition); - void init_atom(decl2rel const& pts, app * atom, app_ref_vector& var_reprs, expr_ref_vector& conj, unsigned tail_idx); - - void simplify_formulas(tactic& tac, expr_ref_vector& fmls); - - // Debugging - bool check_filled(app_ref_vector const& v) const; - - void add_premises(decl2rel const& pts, unsigned lvl, datalog::rule& rule, expr_ref_vector& r); - - public: - pred_transformer(context& ctx, manager& pm, func_decl* head); - ~pred_transformer(); - - void add_rule(datalog::rule* r) { m_rules.push_back(r); } - void add_use(pred_transformer* pt) { if (!m_use.contains(pt)) m_use.insert(pt); } - void initialize(decl2rel const& pts); - - func_decl* head() const { return m_head; } - ptr_vector const& rules() const { return m_rules; } - func_decl* sig(unsigned i) { init_sig(); return m_sig[i].get(); } // signature - func_decl* const* sig() { init_sig(); return m_sig.c_ptr(); } - unsigned sig_size() { init_sig(); return m_sig.size(); } - expr* transition() const { return m_transition; } - expr* initial_state() const { return m_initial_state; } - expr* rule2tag(datalog::rule const* r) { return m_rule2tag.find(r); } - unsigned get_num_levels() { return m_levels.size(); } - expr_ref get_cover_delta(func_decl* p_orig, int level); - void add_cover(unsigned level, expr* property); - context& get_context() { return ctx; } - - std::ostream& display(std::ostream& strm) const; - - void collect_statistics(statistics& st) const; - void reset_statistics(); - - bool is_reachable(expr* state); - void remove_predecessors(expr_ref_vector& literals); - void find_predecessors(datalog::rule const& r, ptr_vector& predicates) const; - datalog::rule const& find_rule(model_core const& model) const; - expr* get_transition(datalog::rule const& r) { return m_rule2transition.find(&r); } - ptr_vector& get_aux_vars(datalog::rule const& r) { return m_rule2vars.find(&r); } - - bool propagate_to_next_level(unsigned level); - void propagate_to_infinity(unsigned level); - void add_property(expr * lemma, unsigned lvl); // add property 'p' to state at level. - - lbool is_reachable(model_node& n, expr_ref_vector* core, bool& uses_level); - bool is_invariant(unsigned level, expr* co_state, bool inductive, bool& assumes_level, expr_ref_vector* core = nullptr); - bool check_inductive(unsigned level, expr_ref_vector& state, bool& assumes_level); - - expr_ref get_formulas(unsigned level, bool add_axioms); - - void simplify_formulas(); - - expr_ref get_propagation_formula(decl2rel const& pts, unsigned level); - - manager& get_pdr_manager() const { return pm; } - ast_manager& get_manager() const { return m; } - - void add_premises(decl2rel const& pts, unsigned lvl, expr_ref_vector& r); - - void close(expr* e); - - app_ref_vector& get_inst(datalog::rule const* r) { return *m_rule2inst.find(r);} - - void inherit_properties(pred_transformer& other); - - void ground_free_vars(expr* e, app_ref_vector& vars, ptr_vector& aux_vars); - - prop_solver& get_solver() { return m_solver; } - prop_solver const& get_solver() const { return m_solver; } - - void set_use_farkas(bool f) { get_solver().set_use_farkas(f); } - bool get_use_farkas() const { return get_solver().get_use_farkas(); } - class scoped_farkas { - bool m_old; - pred_transformer& m_p; - public: - scoped_farkas(pred_transformer& p, bool v): m_old(p.get_use_farkas()), m_p(p) { - p.set_use_farkas(v); - } - ~scoped_farkas() { m_p.set_use_farkas(m_old); } - }; - - }; - - - // structure for counter-example search. - class model_node { - model_node* m_parent; - model_node* m_next; - model_node* m_prev; - pred_transformer& m_pt; - expr_ref m_state; - model_ref m_model; - ptr_vector m_children; - unsigned m_level; - unsigned m_orig_level; - unsigned m_depth; - bool m_closed; - datalog::rule const* m_rule; - public: - model_node(model_node* parent, expr_ref& state, pred_transformer& pt, unsigned level): - m_parent(parent), m_next(nullptr), m_prev(nullptr), m_pt(pt), m_state(state), m_model(nullptr), - m_level(level), m_orig_level(level), m_depth(0), m_closed(false), m_rule(nullptr) { - model_node* p = m_parent; - if (p) { - p->m_children.push_back(this); - SASSERT(p->m_level == level+1); - SASSERT(p->m_level > 0); - m_depth = p->m_depth+1; - if (p && p->is_closed()) { - p->set_open(); - } - } - } - void set_model(model_ref& m) { m_model = m; } - unsigned level() const { return m_level; } - unsigned orig_level() const { return m_orig_level; } - unsigned depth() const { return m_depth; } - void increase_level() { ++m_level; } - expr_ref const& state() const { return m_state; } - ptr_vector const& children() { return m_children; } - pred_transformer& pt() const { return m_pt; } - model_node* parent() const { return m_parent; } - model* get_model_ptr() const { return m_model.get(); } - model const& get_model() const { return *m_model; } - unsigned index() const; - - bool is_closed() const { return m_closed; } - bool is_open() const { return !is_closed(); } - - bool is_1closed() { - if (is_closed()) return true; - if (m_children.empty()) return false; - for (unsigned i = 0; i < m_children.size(); ++i) { - if (m_children[i]->is_open()) return false; - } - return true; - } - - void check_pre_closed(); - void set_closed(); - void set_open(); - void set_pre_closed() { TRACE("pdr", tout << state() << "\n";); m_closed = true; } - void reset() { m_children.reset(); } - - void set_rule(datalog::rule const* r) { m_rule = r; } - datalog::rule* get_rule(); - - void mk_instantiate(datalog::rule_ref& r0, datalog::rule_ref& r1, expr_ref_vector& binding); - - std::ostream& display(std::ostream& out, unsigned indent); - - void dequeue(model_node*& root); - void enqueue(model_node* n); - model_node* next() const { return m_next; } - bool is_goal() const { return nullptr != next(); } - }; - - class model_search { - typedef ptr_vector model_nodes; - bool m_bfs; - model_node* m_root; - model_node* m_goal; - vector > m_cache; - obj_map& cache(model_node const& n); - void erase_children(model_node& n, bool backtrack); - void remove_node(model_node& n, bool backtrack); - void enqueue_leaf(model_node* n); // add leaf to priority queue. - void update_models(); - void set_leaf(model_node& n); // Set node as leaf, remove children. - unsigned num_goals() const; - - public: - model_search(bool bfs): m_bfs(bfs), m_root(nullptr), m_goal(nullptr) {} - ~model_search(); - - void reset(); - model_node* next(); - void add_leaf(model_node& n); // add fresh node. - - void set_root(model_node* n); - model_node& get_root() const { return *m_root; } - std::ostream& display(std::ostream& out) const; - expr_ref get_trace(context const& ctx); - proof_ref get_proof_trace(context const& ctx); - void backtrack_level(bool uses_level, model_node& n); - void remove_goal(model_node& n); - - void well_formed(); - }; - - struct model_exception { }; - struct inductive_exception {}; - - - // 'state' is unsatisfiable at 'level' with 'core'. - // Minimize or weaken core. - class core_generalizer { - protected: - context& m_ctx; - public: - typedef vector > cores; - core_generalizer(context& ctx): m_ctx(ctx) {} - virtual ~core_generalizer() {} - virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) = 0; - virtual void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - new_cores.push_back(std::make_pair(core, uses_level)); - if (!core.empty()) { - (*this)(n, new_cores.back().first, new_cores.back().second); - } - } - virtual void collect_statistics(statistics& st) const {} - virtual void reset_statistics() {} - }; - - class context { - - struct stats { - unsigned m_num_nodes; - unsigned m_max_depth; - stats() { reset(); } - void reset() { memset(this, 0, sizeof(*this)); } - }; - - smt_params& m_fparams; - fixedpoint_params const& m_params; - ast_manager& m; - datalog::context* m_context; - manager m_pm; - decl2rel m_rels; // Map from relation predicate to fp-operator. - decl2rel m_rels_tmp; - func_decl_ref m_query_pred; - pred_transformer* m_query; - mutable model_search m_search; - lbool m_last_result; - unsigned m_inductive_lvl; - unsigned m_expanded_lvl; - ptr_vector m_core_generalizers; - stats m_stats; - model_converter_ref m_mc; - proof_converter_ref m_pc; - - // Functions used by search. - void solve_impl(); - bool check_reachability(unsigned level); - void propagate(unsigned max_prop_lvl); - void close_node(model_node& n); - void check_pre_closed(model_node& n); - void expand_node(model_node& n); - lbool expand_state(model_node& n, expr_ref_vector& cube, bool& uses_level); - void create_children(model_node& n); - expr_ref mk_sat_answer() const; - expr_ref mk_unsat_answer(); - - // Generate inductive property - void get_level_property(unsigned lvl, expr_ref_vector& res, vector & rs); - - - // Initialization - class classifier_proc; - void init_core_generalizers(datalog::rule_set& rules); - - bool check_invariant(unsigned lvl); - bool check_invariant(unsigned lvl, func_decl* fn); - - void checkpoint(); - - void init_rules(datalog::rule_set& rules, decl2rel& transformers); - - void simplify_formulas(); - - void reset_core_generalizers(); - - void reset(decl2rel& rels); - - void validate(); - void validate_proof(); - void validate_search(); - void validate_model(); - - public: - - /** - Initial values of predicates are stored in corresponding relations in dctx. - - We check whether there is some reachable state of the relation checked_relation. - */ - context( - smt_params& fparams, - fixedpoint_params const& params, - ast_manager& m); - - ~context(); - - smt_params& get_fparams() const { return m_fparams; } - fixedpoint_params const& get_params() const { return m_params; } - ast_manager& get_manager() const { return m; } - manager& get_pdr_manager() { return m_pm; } - decl2rel const& get_pred_transformers() const { return m_rels; } - pred_transformer& get_pred_transformer(func_decl* p) const { return *m_rels.find(p); } - datalog::context& get_context() const { SASSERT(m_context); return *m_context; } - expr_ref get_answer(); - - bool is_dl() const { return m_fparams.m_arith_mode == AS_DIFF_LOGIC; } - bool is_utvpi() const { return m_fparams.m_arith_mode == AS_UTVPI; } - - void collect_statistics(statistics& st) const; - void reset_statistics(); - - std::ostream& display(std::ostream& strm) const; - - void display_certificate(std::ostream& strm); - - lbool solve(); - - void reset(bool full = true); - - void set_query(func_decl* q) { m_query_pred = q; } - - void set_unsat() { m_last_result = l_false; } - - void set_model_converter(model_converter_ref& mc) { m_mc = mc; } - - model_converter_ref get_model_converter() { return m_mc; } - - void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } - - void update_rules(datalog::rule_set& rules); - - void set_axioms(expr* axioms) { m_pm.set_background(axioms); } - - unsigned get_num_levels(func_decl* p); - - expr_ref get_cover_delta(int level, func_decl* p_orig, func_decl* p); - - void add_cover(int level, func_decl* pred, expr* property); - - model_ref get_model(); - - proof_ref get_proof() const; - - model_node& get_root() const { return m_search.get_root(); } - - }; - -}; - -#endif diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp deleted file mode 100644 index 27ce0500c..000000000 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_dl.cpp - -Abstract: - - SMT2 interface for the datalog PDR - -Author: - - Krystof Hoder (t-khoder) 2011-9-22. - -Revision History: - ---*/ - -#include "muz/base/dl_context.h" -#include "muz/transforms/dl_mk_coi_filter.h" -#include "muz/base/dl_rule.h" -#include "muz/base/dl_rule_transformer.h" -#include "muz/pdr/pdr_context.h" -#include "muz/pdr/pdr_dl_interface.h" -#include "muz/base/dl_rule_set.h" -#include "muz/transforms/dl_mk_slice.h" -#include "muz/transforms/dl_mk_unfold.h" -#include "muz/transforms/dl_mk_coalesce.h" -#include "muz/transforms/dl_transforms.h" -#include "ast/scoped_proof.h" -#include "model/model_smt2_pp.h" - -using namespace pdr; - -dl_interface::dl_interface(datalog::context& ctx) : - engine_base(ctx.get_manager(), "pdr"), - m_ctx(ctx), - m_pdr_rules(ctx), - m_old_rules(ctx), - m_context(nullptr), - m_refs(ctx.get_manager()) { - m_context = alloc(pdr::context, ctx.get_fparams(), ctx.get_params(), ctx.get_manager()); -} - - -dl_interface::~dl_interface() { - dealloc(m_context); -} - - -// -// Check if the new rules are weaker so that we can -// re-use existing context. -// -void dl_interface::check_reset() { - datalog::rule_set const& new_rules = m_ctx.get_rules(); - datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules(); - bool is_subsumed = !old_rules.empty(); - for (unsigned i = 0; is_subsumed && i < new_rules.get_num_rules(); ++i) { - is_subsumed = false; - for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) { - if (m_ctx.check_subsumes(*old_rules[j], *new_rules.get_rule(i))) { - is_subsumed = true; - } - } - if (!is_subsumed) { - TRACE("pdr", new_rules.get_rule(i)->display(m_ctx, tout << "Fresh rule ");); - m_context->reset(); - } - } - m_old_rules.replace_rules(new_rules); -} - - -lbool dl_interface::query(expr * query) { - //we restore the initial state in the datalog context - m_ctx.ensure_opened(); - m_refs.reset(); - m_pred2slice.reset(); - ast_manager& m = m_ctx.get_manager(); - datalog::rule_manager& rm = m_ctx.get_rule_manager(); - datalog::rule_set& rules0 = m_ctx.get_rules(); - - datalog::rule_set old_rules(rules0); - func_decl_ref query_pred(m); - rm.mk_query(query, rules0); - expr_ref bg_assertion = m_ctx.get_background_assertion(); - - check_reset(); - - TRACE("pdr", - if (!m.is_true(bg_assertion)) { - tout << "axioms:\n"; - tout << mk_pp(bg_assertion, m) << "\n"; - } - tout << "query: " << mk_pp(query, m) << "\n"; - tout << "rules:\n"; - m_ctx.display_rules(tout); - ); - - - apply_default_transformation(m_ctx); - - if (m_ctx.get_params().xform_slice()) { - datalog::rule_transformer transformer(m_ctx); - datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); - transformer.register_plugin(slice); - m_ctx.transform_rules(transformer); - - // track sliced predicates. - obj_map const& preds = slice->get_predicates(); - obj_map::iterator it = preds.begin(); - obj_map::iterator end = preds.end(); - for (; it != end; ++it) { - m_pred2slice.insert(it->m_key, it->m_value); - m_refs.push_back(it->m_key); - m_refs.push_back(it->m_value); - } - } - - if (m_ctx.get_params().xform_unfold_rules() > 0) { - unsigned num_unfolds = m_ctx.get_params().xform_unfold_rules(); - datalog::rule_transformer transf1(m_ctx), transf2(m_ctx); - transf1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); - transf2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); - if (m_ctx.get_params().xform_coalesce_rules()) { - m_ctx.transform_rules(transf1); - } - while (num_unfolds > 0) { - m_ctx.transform_rules(transf2); - --num_unfolds; - } - } - - const datalog::rule_set& rules = m_ctx.get_rules(); - if (rules.get_output_predicates().empty()) { - m_context->set_unsat(); - return l_false; - } - - query_pred = rules.get_output_predicate(); - - TRACE("pdr", - tout << "rules:\n"; - m_ctx.display_rules(tout); - m_ctx.display_smt2(0, 0, tout); - ); - - IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); - m_pdr_rules.replace_rules(rules); - m_pdr_rules.close(); - m_ctx.record_transformed_rules(); - m_ctx.reopen(); - m_ctx.replace_rules(old_rules); - - - scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. - - m_context->set_proof_converter(m_ctx.get_proof_converter()); - m_context->set_model_converter(m_ctx.get_model_converter()); - m_context->set_query(query_pred); - m_context->set_axioms(bg_assertion); - m_context->update_rules(m_pdr_rules); - - if (m_pdr_rules.get_rules().empty()) { - m_context->set_unsat(); - IF_VERBOSE(1, model_smt2_pp(verbose_stream(), m, *m_context->get_model(),0);); - return l_false; - } - - return m_context->solve(); - -} - -expr_ref dl_interface::get_cover_delta(int level, func_decl* pred_orig) { - func_decl* pred = pred_orig; - m_pred2slice.find(pred_orig, pred); - SASSERT(pred); - return m_context->get_cover_delta(level, pred_orig, pred); -} - -void dl_interface::add_cover(int level, func_decl* pred, expr* property) { - if (m_ctx.get_params().xform_slice()) { - throw default_exception("Covers are incompatible with slicing. Disable slicing before using covers"); - } - m_context->add_cover(level, pred, property); -} - -unsigned dl_interface::get_num_levels(func_decl* pred) { - m_pred2slice.find(pred, pred); - SASSERT(pred); - return m_context->get_num_levels(pred); -} - -void dl_interface::collect_statistics(statistics& st) const { - m_context->collect_statistics(st); -} - -void dl_interface::reset_statistics() { - m_context->reset_statistics(); -} - -void dl_interface::display_certificate(std::ostream& out) const { - m_context->display_certificate(out); -} - -expr_ref dl_interface::get_answer() { - return m_context->get_answer(); -} - - - -void dl_interface::updt_params() { - dealloc(m_context); - m_context = alloc(pdr::context, m_ctx.get_fparams(), m_ctx.get_params(), m_ctx.get_manager()); -} - -model_ref dl_interface::get_model() { - return m_context->get_model(); -} - -proof_ref dl_interface::get_proof() { - return m_context->get_proof(); -} diff --git a/src/muz/pdr/pdr_dl_interface.h b/src/muz/pdr/pdr_dl_interface.h deleted file mode 100644 index 1a0b04635..000000000 --- a/src/muz/pdr/pdr_dl_interface.h +++ /dev/null @@ -1,78 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_dl_interface.h - -Abstract: - - SMT2 interface for the datalog PDR - -Author: - - Krystof Hoder (t-khoder) 2011-9-22. - -Revision History: - ---*/ - -#ifndef PDR_DL_INTERFACE_H_ -#define PDR_DL_INTERFACE_H_ - -#include "util/lbool.h" -#include "muz/base/dl_rule.h" -#include "muz/base/dl_rule_set.h" -#include "muz/base/dl_util.h" -#include "muz/base/dl_engine_base.h" -#include "util/statistics.h" - -namespace datalog { - class context; -} - -namespace pdr { - - class context; - - class dl_interface : public datalog::engine_base { - datalog::context& m_ctx; - datalog::rule_set m_pdr_rules; - datalog::rule_set m_old_rules; - context* m_context; - obj_map m_pred2slice; - ast_ref_vector m_refs; - - void check_reset(); - - public: - dl_interface(datalog::context& ctx); - ~dl_interface() override; - - lbool query(expr* query) override; - - void display_certificate(std::ostream& out) const override; - - void collect_statistics(statistics& st) const override; - - void reset_statistics() override; - - expr_ref get_answer() override; - - unsigned get_num_levels(func_decl* pred) override; - - expr_ref get_cover_delta(int level, func_decl* pred) override; - - void add_cover(int level, func_decl* pred, expr* property) override; - - void updt_params() override; - - model_ref get_model() override; - - proof_ref get_proof() override; - - }; -} - - -#endif diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp deleted file mode 100644 index 6695788c2..000000000 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ /dev/null @@ -1,1012 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_farkas_learner.cpp - -Abstract: - - Proviced abstract interface and some inplementations of algorithms - for strenghtning lemmas - -Author: - - Krystof Hoder (t-khoder) 2011-11-1. - -Revision History: - ---*/ - -#include "ast/ast_smt2_pp.h" -#include "ast/array_decl_plugin.h" -#include "ast/rewriter/bool_rewriter.h" -#include "ast/dl_decl_plugin.h" -#include "ast/for_each_expr.h" -#include "muz/base/dl_util.h" -#include "ast/rewriter/rewriter.h" -#include "ast/rewriter/rewriter_def.h" -#include "muz/pdr/pdr_util.h" -#include "muz/pdr/pdr_farkas_learner.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/ast_ll_pp.h" -#include "tactic/arith/arith_bounds_tactic.h" -#include "ast/proofs/proof_utils.h" -#include "ast/reg_decl_plugins.h" - - -namespace pdr { - - class farkas_learner::constr { - - ast_manager& m; - arith_util a; - app_ref_vector m_ineqs; - vector m_coeffs; - - unsigned m_time; - unsigned_vector m_roots, m_size, m_his, m_reps, m_ts; - - void mk_coerce(expr*& e1, expr*& e2) { - if (a.is_int(e1) && a.is_real(e2)) { - e1 = a.mk_to_real(e1); - } - else if (a.is_int(e2) && a.is_real(e1)) { - e2 = a.mk_to_real(e2); - } - } - - app* mk_add(expr* e1, expr* e2) { - mk_coerce(e1, e2); - return a.mk_add(e1, e2); - } - - app* mk_mul(expr* e1, expr* e2) { - mk_coerce(e1, e2); - return a.mk_mul(e1, e2); - } - - app* mk_le(expr* e1, expr* e2) { - mk_coerce(e1, e2); - return a.mk_le(e1, e2); - } - - app* mk_ge(expr* e1, expr* e2) { - mk_coerce(e1, e2); - return a.mk_ge(e1, e2); - } - - app* mk_gt(expr* e1, expr* e2) { - mk_coerce(e1, e2); - return a.mk_gt(e1, e2); - } - - app* mk_lt(expr* e1, expr* e2) { - mk_coerce(e1, e2); - return a.mk_lt(e1, e2); - } - - void mul(rational const& c, expr* e, expr_ref& res) { - expr_ref tmp(m); - if (c.is_one()) { - tmp = e; - } - else { - tmp = mk_mul(a.mk_numeral(c, c.is_int() && a.is_int(e)), e); - } - res = mk_add(res, tmp); - } - - bool is_int_sort(app* c) { - SASSERT(m.is_eq(c) || a.is_le(c) || a.is_lt(c) || a.is_gt(c) || a.is_ge(c)); - SASSERT(a.is_int(c->get_arg(0)) || a.is_real(c->get_arg(0))); - return a.is_int(c->get_arg(0)); - } - - bool is_int_sort() { - SASSERT(!m_ineqs.empty()); - return is_int_sort(m_ineqs[0].get()); - } - - void normalize_coeffs() { - rational l(1); - for (unsigned i = 0; i < m_coeffs.size(); ++i) { - l = lcm(l, denominator(m_coeffs[i])); - } - if (!l.is_one()) { - for (unsigned i = 0; i < m_coeffs.size(); ++i) { - m_coeffs[i] *= l; - } - } - } - - app* mk_one() { - return a.mk_numeral(rational(1), true); - } - - app* fix_sign(bool is_pos, app* c) { - expr* x, *y; - SASSERT(m.is_eq(c) || a.is_le(c) || a.is_lt(c) || a.is_gt(c) || a.is_ge(c)); - bool is_int = is_int_sort(c); - if (is_int && is_pos && (a.is_lt(c, x, y) || a.is_gt(c, y, x))) { - return mk_le(mk_add(x, mk_one()), y); - } - if (is_int && !is_pos && (a.is_le(c, x, y) || a.is_ge(c, y, x))) { - // !(x <= y) <=> x > y <=> x >= y + 1 - return mk_ge(x, mk_add(y, mk_one())); - } - if (is_pos) { - return c; - } - if (a.is_le(c, x, y)) return mk_gt(x, y); - if (a.is_lt(c, x, y)) return mk_ge(x, y); - if (a.is_ge(c, x, y)) return mk_lt(x, y); - if (a.is_gt(c, x, y)) return mk_le(x, y); - UNREACHABLE(); - return c; - } - - public: - constr(ast_manager& m) : m(m), a(m), m_ineqs(m), m_time(0) {} - - void reset() { - m_ineqs.reset(); - m_coeffs.reset(); - } - - /** add a multiple of constraint c to the current constr */ - void add(rational const & coef, app * c) { - bool is_pos = true; - expr* e; - while (m.is_not(c, e)) { - is_pos = !is_pos; - c = to_app(e); - } - - if (!coef.is_zero() && !m.is_true(c)) { - m_coeffs.push_back(coef); - m_ineqs.push_back(fix_sign(is_pos, c)); - } - } - - // - // Extract the complement of premises multiplied by Farkas coefficients. - // - void get(expr_ref& res) { - if (m_coeffs.empty()) { - res = m.mk_false(); - return; - } - bool is_int = is_int_sort(); - if (is_int) { - normalize_coeffs(); - } - TRACE("pdr", - for (unsigned i = 0; i < m_coeffs.size(); ++i) { - tout << m_coeffs[i] << ": " << mk_pp(m_ineqs[i].get(), m) << "\n"; - } - ); - - res = extract_consequence(0, m_coeffs.size()); - -#if 1 - // partition equalities into variable disjoint sets. - // take the conjunction of these instead of the - // linear combination. - partition_ineqs(); - expr_ref_vector lits(m); - unsigned lo = 0; - for (unsigned i = 0; i < m_his.size(); ++i) { - unsigned hi = m_his[i]; - lits.push_back(extract_consequence(lo, hi)); - lo = hi; - } - res = mk_or(lits); - IF_VERBOSE(2, { if (lits.size() > 1) { verbose_stream() << "combined lemma: " << mk_pp(res, m) << "\n"; } }); -#endif - } - - private: - - // partition inequalities into variable disjoint sets. - void partition_ineqs() { - m_reps.reset(); - m_his.reset(); - ++m_time; - for (unsigned i = 0; i < m_ineqs.size(); ++i) { - m_reps.push_back(process_term(m_ineqs[i].get())); - } - unsigned head = 0; - while (head < m_ineqs.size()) { - unsigned r = find(m_reps[head]); - unsigned tail = head; - for (unsigned i = head+1; i < m_ineqs.size(); ++i) { - if (find(m_reps[i]) == r) { - ++tail; - if (tail != i) { - SASSERT(tail < i); - std::swap(m_reps[tail], m_reps[i]); - app_ref tmp(m); - tmp = m_ineqs[i].get(); - m_ineqs[i] = m_ineqs[tail].get(); - m_ineqs[tail] = tmp; - std::swap(m_coeffs[tail], m_coeffs[i]); - } - } - } - head = tail + 1; - m_his.push_back(head); - } - } - - unsigned find(unsigned idx) { - if (m_ts.size() <= idx) { - m_roots.resize(idx+1); - m_size.resize(idx+1); - m_ts.resize(idx+1); - m_roots[idx] = idx; - m_ts[idx] = m_time; - m_size[idx] = 1; - return idx; - } - if (m_ts[idx] != m_time) { - m_size[idx] = 1; - m_ts[idx] = m_time; - m_roots[idx] = idx; - return idx; - } - while (true) { - if (m_roots[idx] == idx) { - return idx; - } - idx = m_roots[idx]; - } - } - - void merge(unsigned i, unsigned j) { - i = find(i); - j = find(j); - if (i == j) { - return; - } - if (m_size[i] > m_size[j]) { - std::swap(i, j); - } - m_roots[i] = j; - m_size[j] += m_size[i]; - } - - unsigned process_term(expr* e) { - unsigned r = e->get_id(); - ptr_vector todo; - ast_mark mark; - todo.push_back(e); - while (!todo.empty()) { - e = todo.back(); - todo.pop_back(); - if (mark.is_marked(e)) { - continue; - } - mark.mark(e, true); - if (is_uninterp(e)) { - merge(r, e->get_id()); - } - if (is_app(e)) { - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - todo.push_back(a->get_arg(i)); - } - } - } - return r; - } - - expr_ref extract_consequence(unsigned lo, unsigned hi) { - bool is_int = is_int_sort(); - app_ref zero(a.mk_numeral(rational::zero(), is_int), m); - expr_ref res(m); - res = zero; - bool is_strict = false; - bool is_eq = true; - expr* x, *y; - for (unsigned i = lo; i < hi; ++i) { - app* c = m_ineqs[i].get(); - if (m.is_eq(c, x, y)) { - mul(m_coeffs[i], x, res); - mul(-m_coeffs[i], y, res); - } - if (a.is_lt(c, x, y) || a.is_gt(c, y, x)) { - mul(m_coeffs[i], x, res); - mul(-m_coeffs[i], y, res); - is_strict = true; - is_eq = false; - } - if (a.is_le(c, x, y) || a.is_ge(c, y, x)) { - mul(m_coeffs[i], x, res); - mul(-m_coeffs[i], y, res); - is_eq = false; - } - } - - zero = a.mk_numeral(rational::zero(), a.is_int(res)); - if (is_eq) { - res = m.mk_eq(res, zero); - } - else if (is_strict) { - res = mk_lt(res, zero); - } - else { - res = mk_le(res, zero); - } - res = m.mk_not(res); - th_rewriter rw(m); - params_ref params; - params.set_bool("gcd_rounding", true); - rw.updt_params(params); - proof_ref pr(m); - expr_ref result(m); - rw(res, result, pr); - fix_dl(result); - return result; - } - - // patch: swap addends to make static - // features recognize difference constraint. - void fix_dl(expr_ref& r) { - expr* e; - if (m.is_not(r, e)) { - r = e; - fix_dl(r); - r = m.mk_not(r); - return; - } - expr* e1, *e2, *e3, *e4; - if ((m.is_eq(r, e1, e2) || a.is_lt(r, e1, e2) || a.is_gt(r, e1, e2) || - a.is_le(r, e1, e2) || a.is_ge(r, e1, e2))) { - if (a.is_add(e1, e3, e4) && a.is_mul(e3)) { - r = m.mk_app(to_app(r)->get_decl(), a.mk_add(e4,e3), e2); - } - } - } - }; - - farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr) - : m_proof_params(get_proof_params(params)), - m_pr(PGM_ENABLED), - m_constr(nullptr), - m_combine_farkas_coefficients(true), - p2o(m_pr, outer_mgr), - o2p(outer_mgr, m_pr) - { - reg_decl_plugins(m_pr); - m_ctx = alloc(smt::kernel, m_pr, m_proof_params); - } - - farkas_learner::~farkas_learner() { - dealloc(m_constr); - } - - smt_params farkas_learner::get_proof_params(smt_params& orig_params) { - smt_params res(orig_params); - res.m_arith_bound_prop = BP_NONE; - // temp hack to fix the build - // res.m_conflict_resolution_strategy = CR_ALL_DECIDED; - res.m_arith_auto_config_simplex = true; - res.m_arith_propagate_eqs = false; - res.m_arith_eager_eq_axioms = false; - res.m_arith_eq_bounds = false; - return res; - } - - class farkas_learner::equality_expander_cfg : public default_rewriter_cfg - { - ast_manager& m; - arith_util m_ar; - public: - equality_expander_cfg(ast_manager& m) : m(m), m_ar(m) {} - - bool get_subst(expr * s, expr * & t, proof * & t_pr) { - expr * x, *y; - if (m.is_eq(s, x, y) && (m_ar.is_int(x) || m_ar.is_real(x))) { - t = m.mk_and(m_ar.mk_ge(x, y), m_ar.mk_le(x, y)); - return true; - } - else { - return false; - } - } - - }; - - class collect_pure_proc { - func_decl_set& m_symbs; - public: - collect_pure_proc(func_decl_set& s):m_symbs(s) {} - - void operator()(app* a) { - if (a->get_family_id() == null_family_id) { - m_symbs.insert(a->get_decl()); - } - } - void operator()(var*) {} - void operator()(quantifier*) {} - }; - - - bool farkas_learner::get_lemma_guesses(expr * A_ext, expr * B_ext, expr_ref_vector& lemmas) - { - expr_ref A(o2p(A_ext), m_pr); - expr_ref B(o2p(B_ext), m_pr); - proof_ref pr(m_pr); - expr_ref tmp(m_pr); - expr_ref_vector ilemmas(m_pr); - equality_expander_cfg ee_rwr_cfg(m_pr); - rewriter_tpl ee_rwr(m_pr, false, ee_rwr_cfg); - - lemmas.reset(); - - ee_rwr(A, A); - ee_rwr(B, B); - - expr_set bs; - expr_ref_vector blist(m_pr); - flatten_and(B, blist); - for (unsigned i = 0; i < blist.size(); ++i) { - bs.insert(blist[i].get()); - } - - - if (!m_ctx) { - m_ctx = alloc(smt::kernel, m_pr, m_proof_params); - } - - m_ctx->push(); - m_ctx->assert_expr(A); - expr_set::iterator it = bs.begin(), end = bs.end(); - for (; it != end; ++it) { - m_ctx->assert_expr(*it); - } - lbool res = m_ctx->check(); - bool is_unsat = res == l_false; - if (is_unsat) { - pr = m_ctx->get_proof(); - get_lemmas(m_ctx->get_proof(), bs, ilemmas); - for (unsigned i = 0; i < ilemmas.size(); ++i) { - lemmas.push_back(p2o(ilemmas[i].get())); - } - } - m_ctx->pop(1); - - IF_VERBOSE(3, { - for (unsigned i = 0; i < ilemmas.size(); ++i) { - verbose_stream() << "B': " << mk_pp(ilemmas[i].get(), m_pr) << "\n"; - } - }); - - TRACE("farkas_learner", - tout << (is_unsat?"unsat":"sat") << "\n"; - tout << "A: " << mk_pp(A_ext, m_ctx->m()) << "\n"; - tout << "B: " << mk_pp(B_ext, m_ctx->m()) << "\n"; - for (unsigned i = 0; i < lemmas.size(); ++i) { - tout << "B': " << mk_pp(ilemmas[i].get(), m_pr) << "\n"; - }); - DEBUG_CODE( - if (is_unsat) { - m_ctx->push(); - m_ctx->assert_expr(A); - for (unsigned i = 0; i < ilemmas.size(); ++i) { - m_ctx->assert_expr(ilemmas[i].get()); - } - lbool res2 = m_ctx->check(); - SASSERT(l_false == res2); - m_ctx->pop(1); - } - ); - return is_unsat; - } - - // - // Perform simple subsumption check of lemmas. - // - void farkas_learner::simplify_lemmas(expr_ref_vector& lemmas) { - ast_manager& m = lemmas.get_manager(); - goal_ref g(alloc(goal, m, false, false, false)); - TRACE("farkas_simplify_lemmas", - for (unsigned i = 0; i < lemmas.size(); ++i) { - tout << mk_pp(lemmas[i].get(), m) << "\n"; - }); - - for (unsigned i = 0; i < lemmas.size(); ++i) { - g->assert_expr(lemmas[i].get()); - } - expr_ref tmp(m); - goal_ref_buffer result; - tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result); - lemmas.reset(); - SASSERT(result.size() == 1); - goal* r = result[0]; - for (unsigned i = 0; i < r->size(); ++i) { - lemmas.push_back(r->form(i)); - } - TRACE("farkas_simplify_lemmas", - tout << "simplified:\n"; - for (unsigned i = 0; i < lemmas.size(); ++i) { - tout << mk_pp(lemmas[i].get(), m) << "\n"; - }); - } - - - void farkas_learner::combine_constraints(unsigned n, app * const * lits, rational const * coeffs, expr_ref& res) - { - ast_manager& m = res.get_manager(); - if (m_combine_farkas_coefficients) { - if (!m_constr) { - m_constr = alloc(constr, m); - } - m_constr->reset(); - for (unsigned i = 0; i < n; ++i) { - m_constr->add(coeffs[i], lits[i]); - } - m_constr->get(res); - } - else { - bool_rewriter rw(m); - rw.mk_or(n, (expr*const*)(lits), res); - res = m.mk_not(res); - } - } - - class farkas_learner::constant_replacer_cfg : public default_rewriter_cfg - { - const obj_map& m_translation; - public: - constant_replacer_cfg(const obj_map& translation) - : m_translation(translation) - { } - - bool get_subst(expr * s, expr * & t, proof * & t_pr) { - return m_translation.find(s, t); - } - }; - - // every uninterpreted symbol is in symbs - class is_pure_expr_proc { - func_decl_set const& m_symbs; - public: - struct non_pure {}; - - is_pure_expr_proc(func_decl_set const& s):m_symbs(s) {} - - void operator()(app* a) { - if (a->get_family_id() == null_family_id) { - if (!m_symbs.contains(a->get_decl())) { - throw non_pure(); - } - } - } - void operator()(var*) {} - void operator()(quantifier*) {} - }; - - bool farkas_learner::is_pure_expr(func_decl_set const& symbs, expr* e) const { - is_pure_expr_proc proc(symbs); - try { - for_each_expr(proc, e); - } - catch (is_pure_expr_proc::non_pure) { - return false; - } - return true; - }; - - - /** - Revised version of Farkas strengthener. - 1. Mark B-pure nodes as derivations that depend only on B. - 2. Collect B-influenced nodes - 3. (optional) Permute B-pure units over resolution steps to narrow dependencies on B. - 4. Weaken B-pure units for resolution with Farkas Clauses. - 5. Add B-pure units elsewhere. - - Rules: - - hypothesis h |- h - - H |- false - - lemma ---------- - |- not H - - Th |- L \/ C H |- not L - - th-lemma ------------------------- - H |- C - - Note: C is false for theory axioms, C is unit literal for propagation. - - - rewrite |- t = s - - H |- t = s - - monotonicity ---------------- - H |- f(t) = f(s) - - H |- t = s H' |- s = u - - trans ---------------------- - H, H' |- t = u - - H |- C \/ L H' |- not L - - unit_resolve ------------------------ - H, H' |- C - - H |- a ~ b H' |- a - - mp -------------------- - H, H' |- b - - - def-axiom |- C - - - asserted |- f - - Mark nodes by: - - Hypotheses - - Dependency on bs - - Dependency on A - - A node is unit derivable from bs if: - - It has no hypotheses. - - It depends on bs. - - It does not depend on A. - - NB: currently unit derivable is not symmetric: A clause can be - unit derivable, but a unit literal with hypotheses is not. - This is clearly wrong, because hypotheses are just additional literals - in a clausal version. - - NB: the routine is not interpolating, though an interpolating variant would - be preferrable because then we can also use it for model propagation. - - We collect the unit derivable nodes from bs. - These are the weakenings of bs, besides the - units under Farkas. - - */ - -#define INSERT(_x_) if (!lemma_set.contains(_x_)) { lemma_set.insert(_x_); lemmas.push_back(_x_); } - - void farkas_learner::get_lemmas(proof* root, expr_set const& bs, expr_ref_vector& lemmas) { - ast_manager& m = lemmas.get_manager(); - bool_rewriter brwr(m); - func_decl_set Bsymbs; - collect_pure_proc collect_proc(Bsymbs); - expr_set::iterator it = bs.begin(), end = bs.end(); - for (; it != end; ++it) { - for_each_expr(collect_proc, *it); - } - - proof_ref pr(root, m); - proof_utils::reduce_hypotheses(pr); - proof_utils::permute_unit_resolution(pr); - IF_VERBOSE(3, verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n";); - - ptr_vector hyprefs; - obj_map hypmap; - obj_hashtable lemma_set; - ast_mark b_depend, a_depend, visited, b_closed; - expr_set* empty_set = alloc(expr_set); - hyprefs.push_back(empty_set); - ptr_vector todo; - TRACE("pdr_verbose", tout << mk_pp(pr, m) << "\n";); - todo.push_back(pr); - while (!todo.empty()) { - proof* p = todo.back(); - SASSERT(m.is_proof(p)); - if (visited.is_marked(p)) { - todo.pop_back(); - continue; - } - bool all_visit = true; - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - expr* arg = p->get_arg(i); - SASSERT(m.is_proof(arg)); - if (!visited.is_marked(arg)) { - all_visit = false; - todo.push_back(to_app(arg)); - } - } - if (!all_visit) { - continue; - } - visited.mark(p, true); - todo.pop_back(); - - // retrieve hypotheses and dependencies on A, bs. - bool b_dep = false, a_dep = false; - expr_set* hyps = empty_set; - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - expr* arg = p->get_arg(i); - a_dep = a_dep || a_depend.is_marked(arg); - b_dep = b_dep || b_depend.is_marked(arg); - expr_set* hyps2 = hypmap.find(arg); - if (hyps != hyps2 && !hyps2->empty()) { - if (hyps->empty()) { - hyps = hyps2; - } - else { - expr_set* hyps3 = alloc(expr_set); - set_union(*hyps3, *hyps); - set_union(*hyps3, *hyps2); - hyps = hyps3; - hyprefs.push_back(hyps); - } - } - } - hypmap.insert(p, hyps); - a_depend.mark(p, a_dep); - b_depend.mark(p, b_dep); - -#define IS_B_PURE(_p) (b_depend.is_marked(_p) && !a_depend.is_marked(_p) && hypmap.find(_p)->empty()) - - - // Add lemmas that depend on bs, have no hypotheses, don't depend on A. - if ((!hyps->empty() || a_depend.is_marked(p)) && - b_depend.is_marked(p) && !is_farkas_lemma(m, p)) { - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - app* arg = to_app(p->get_arg(i)); - if (IS_B_PURE(arg)) { - expr* fact = m.get_fact(arg); - if (is_pure_expr(Bsymbs, fact)) { - TRACE("farkas_learner", - tout << "Add: " << mk_pp(m.get_fact(arg), m) << "\n"; - tout << mk_pp(arg, m) << "\n"; - ); - INSERT(fact); - } - else { - get_asserted(p, bs, b_closed, lemma_set, lemmas); - b_closed.mark(p, true); - } - } - } - } - - switch(p->get_decl_kind()) { - case PR_ASSERTED: - if (bs.contains(m.get_fact(p))) { - b_depend.mark(p, true); - } - else { - a_depend.mark(p, true); - } - break; - case PR_HYPOTHESIS: { - SASSERT(hyps == empty_set); - hyps = alloc(expr_set); - hyps->insert(m.get_fact(p)); - hyprefs.push_back(hyps); - hypmap.insert(p, hyps); - break; - } - case PR_DEF_AXIOM: { - if (!is_pure_expr(Bsymbs, m.get_fact(p))) { - a_depend.mark(p, true); - } - break; - } - case PR_LEMMA: { - expr_set* hyps2 = alloc(expr_set); - hyprefs.push_back(hyps2); - set_union(*hyps2, *hyps); - hyps = hyps2; - expr* fml = m.get_fact(p); - hyps->remove(fml); - if (m.is_or(fml)) { - for (unsigned i = 0; i < to_app(fml)->get_num_args(); ++i) { - expr* f = to_app(fml)->get_arg(i); - expr_ref hyp(m); - brwr.mk_not(f, hyp); - hyps->remove(hyp); - } - } - hypmap.insert(p, hyps); - break; - } - case PR_TH_LEMMA: { - if (!is_farkas_lemma(m, p)) break; - - SASSERT(m.has_fact(p)); - unsigned prem_cnt = m.get_num_parents(p); - func_decl * d = p->get_decl(); - SASSERT(d->get_num_parameters() >= prem_cnt+2); - SASSERT(d->get_parameter(0).get_symbol() == "arith"); - SASSERT(d->get_parameter(1).get_symbol() == "farkas"); - parameter const* params = d->get_parameters() + 2; - - app_ref_vector lits(m); - expr_ref tmp(m); - unsigned num_b_pures = 0; - rational coef; - vector coeffs; - - TRACE("farkas_learner", - for (unsigned i = 0; i < prem_cnt; ++i) { - VERIFY(params[i].is_rational(coef)); - proof* prem = to_app(p->get_arg(i)); - bool b_pure = IS_B_PURE(prem); - tout << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; - } - tout << mk_pp(m.get_fact(p), m) << "\n"; - ); - - // NB. Taking 'abs' of coefficients is a workaround. - // The Farkas coefficient extraction in arith_core must be wrong. - // The coefficients would be always positive relative to the theory lemma. - - for(unsigned i = 0; i < prem_cnt; ++i) { - expr * prem_e = p->get_arg(i); - SASSERT(is_app(prem_e)); - proof * prem = to_app(prem_e); - - if(IS_B_PURE(prem)) { - ++num_b_pures; - } - else { - VERIFY(params[i].is_rational(coef)); - lits.push_back(to_app(m.get_fact(prem))); - coeffs.push_back(abs(coef)); - } - } - params += prem_cnt; - if (prem_cnt + 2 < d->get_num_parameters()) { - unsigned num_args = 1; - expr* fact = m.get_fact(p); - expr* const* args = &fact; - if (m.is_or(fact)) { - app* _or = to_app(fact); - num_args = _or->get_num_args(); - args = _or->get_args(); - } - SASSERT(prem_cnt + 2 + num_args == d->get_num_parameters()); - for (unsigned i = 0; i < num_args; ++i) { - expr* prem_e = args[i]; - brwr.mk_not(prem_e, tmp); - VERIFY(params[i].is_rational(coef)); - SASSERT(is_app(tmp)); - lits.push_back(to_app(tmp)); - coeffs.push_back(abs(coef)); - } - - } - SASSERT(coeffs.size() == lits.size()); - if (num_b_pures > 0) { - expr_ref res(m); - combine_constraints(coeffs.size(), lits.c_ptr(), coeffs.c_ptr(), res); - TRACE("farkas_learner", tout << "Add: " << mk_pp(res, m) << "\n";); - INSERT(res); - b_closed.mark(p, true); - } - } - default: - break; - } - } - - std::for_each(hyprefs.begin(), hyprefs.end(), delete_proc()); - simplify_lemmas(lemmas); - } - - void farkas_learner::get_consequences(proof* root, expr_set const& bs, expr_ref_vector& consequences) { - TRACE("farkas_learner", tout << "get consequences\n";); - m_combine_farkas_coefficients = false; - get_lemmas(root, bs, consequences); - m_combine_farkas_coefficients = true; - } - - void farkas_learner::get_asserted(proof* p, expr_set const& bs, ast_mark& b_closed, obj_hashtable& lemma_set, expr_ref_vector& lemmas) { - ast_manager& m = lemmas.get_manager(); - ast_mark visited; - proof* p0 = p; - ptr_vector todo; - todo.push_back(p); - - while (!todo.empty()) { - p = todo.back(); - todo.pop_back(); - if (visited.is_marked(p) || b_closed.is_marked(p)) { - continue; - } - visited.mark(p, true); - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - expr* arg = p->get_arg(i); - SASSERT(m.is_proof(arg)); - todo.push_back(to_app(arg)); - } - if (p->get_decl_kind() == PR_ASSERTED && - bs.contains(m.get_fact(p))) { - expr* fact = m.get_fact(p); - (void)p0; - TRACE("farkas_learner", - tout << mk_ll_pp(p0,m) << "\n"; - tout << "Add: " << mk_pp(p,m) << "\n";); - INSERT(fact); - b_closed.mark(p, true); - } - } - } - - - bool farkas_learner::is_farkas_lemma(ast_manager& m, expr* e) { - app * a; - func_decl* d; - symbol sym; - return - is_app(e) && - (a = to_app(e), d = a->get_decl(), true) && - PR_TH_LEMMA == a->get_decl_kind() && - d->get_num_parameters() >= 2 && - d->get_parameter(0).is_symbol(sym) && sym == "arith" && - d->get_parameter(1).is_symbol(sym) && sym == "farkas" && - d->get_num_parameters() >= m.get_num_parents(to_app(e)) + 2; - }; - - - void farkas_learner::test() { - smt_params params; - enable_trace("farkas_learner"); - - bool res; - ast_manager m; - reg_decl_plugins(m); - arith_util a(m); - pdr::farkas_learner fl(params, m); - expr_ref_vector lemmas(m); - - sort_ref int_s(a.mk_int(), m); - expr_ref x(m.mk_const(symbol("x"), int_s), m); - expr_ref y(m.mk_const(symbol("y"), int_s), m); - expr_ref z(m.mk_const(symbol("z"), int_s), m); - expr_ref u(m.mk_const(symbol("u"), int_s), m); - expr_ref v(m.mk_const(symbol("v"), int_s), m); - - // A: x > y >= z - // B: x < z - // Farkas: x <= z - expr_ref A(m.mk_and(a.mk_gt(x,y), a.mk_ge(y,z)),m); - expr_ref B(a.mk_gt(z,x),m); - res = fl.get_lemma_guesses(A, B, lemmas); - std::cout << "\nres: " << res << "\nlemmas: " << pp_cube(lemmas, m) << "\n"; - - // A: x > y >= z + 2 - // B: x = 1, z = 8 - // Farkas: x <= z + 2 - expr_ref one(a.mk_numeral(rational(1), true), m); - expr_ref two(a.mk_numeral(rational(2), true), m); - expr_ref eight(a.mk_numeral(rational(8), true), m); - A = m.mk_and(a.mk_gt(x,y),a.mk_ge(y,a.mk_add(z,two))); - B = m.mk_and(m.mk_eq(x,one), m.mk_eq(z, eight)); - res = fl.get_lemma_guesses(A, B, lemmas); - std::cout << "\nres: " << res << "\nlemmas: " << pp_cube(lemmas, m) << "\n"; - - // A: x > y >= z \/ x >= u > z - // B: z > x + 1 - // Farkas: z >= x - A = m.mk_or(m.mk_and(a.mk_gt(x,y),a.mk_ge(y,z)),m.mk_and(a.mk_ge(x,u),a.mk_gt(u,z))); - B = a.mk_gt(z, a.mk_add(x,one)); - res = fl.get_lemma_guesses(A, B, lemmas); - std::cout << "\nres: " << res << "\nlemmas: " << pp_cube(lemmas, m) << "\n"; - - // A: (x > y >= z \/ x >= u > z \/ u > v) - // B: z > x + 1 & not (u > v) - // Farkas: z >= x & not (u > v) - A = m.mk_or(m.mk_and(a.mk_gt(x,y),a.mk_ge(y,z)),m.mk_and(a.mk_ge(x,u),a.mk_gt(u,z)), a.mk_gt(u, v)); - B = m.mk_and(a.mk_gt(z, a.mk_add(x,one)), m.mk_not(a.mk_gt(u, v))); - res = fl.get_lemma_guesses(A, B, lemmas); - std::cout << "\nres: " << res << "\nlemmas: " << pp_cube(lemmas, m) << "\n"; - - } - - void farkas_learner::collect_statistics(statistics& st) const { - if (m_ctx) { - m_ctx->collect_statistics(st); - } - } - - -}; - diff --git a/src/muz/pdr/pdr_farkas_learner.h b/src/muz/pdr/pdr_farkas_learner.h deleted file mode 100644 index a5f3482e6..000000000 --- a/src/muz/pdr/pdr_farkas_learner.h +++ /dev/null @@ -1,128 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_farkas_learner.h - -Abstract: - - SMT2 interface for the datalog PDR - -Author: - - Krystof Hoder (t-khoder) 2011-11-1. - -Revision History: - ---*/ - -#ifndef PDR_FARKAS_LEARNER_H_ -#define PDR_FARKAS_LEARNER_H_ - -#include "ast/arith_decl_plugin.h" -#include "ast/ast_translation.h" -#include "ast/bv_decl_plugin.h" -#include "smt/smt_kernel.h" -#include "ast/rewriter/bool_rewriter.h" -#include "muz/pdr/pdr_util.h" -#include "smt/params/smt_params.h" -#include "tactic/tactic.h" - -namespace pdr { - -class farkas_learner { - class farkas_collector; - class constant_replacer_cfg; - class equality_expander_cfg; - class constr; - - typedef obj_hashtable expr_set; - - smt_params m_proof_params; - ast_manager m_pr; - scoped_ptr m_ctx; - constr* m_constr; - - // - // true: produce a combined constraint by applying Farkas coefficients. - // false: produce a conjunction of the negated literals from the theory lemmas. - // - bool m_combine_farkas_coefficients; - - - static smt_params get_proof_params(smt_params& orig_params); - - // - // all ast objects passed to private functions have m_proof_mgs as their ast_manager - // - - ast_translation p2o; /** Translate expression from inner ast_manager to outer one */ - ast_translation o2p; /** Translate expression from outer ast_manager to inner one */ - - - /** All ast opbjects here are in the m_proof_mgs */ - void get_lemma_guesses_internal(proof * p, expr* A, expr * B, expr_ref_vector& lemmas); - - bool farkas2lemma(proof * fstep, expr* A, expr * B, expr_ref& res); - - void combine_constraints(unsigned cnt, app * const * constrs, rational const * coeffs, expr_ref& res); - - bool try_ensure_lemma_in_language(expr_ref& lemma, expr* A, const func_decl_set& lang); - - bool is_farkas_lemma(ast_manager& m, expr* e); - - void get_asserted(proof* p, expr_set const& bs, ast_mark& b_closed, obj_hashtable& lemma_set, expr_ref_vector& lemmas); - - bool is_pure_expr(func_decl_set const& symbs, expr* e) const; - - static void test(); - -public: - farkas_learner(smt_params& params, ast_manager& m); - - ~farkas_learner(); - - /** - All ast objects have the ast_manager which was passed as - an argument to the constructor (i.e. m_outer_mgr) - - B is a conjunction of literals. - A && B is unsat, equivalently A => ~B is valid - Find a weakened B' such that - A && B' is unsat and B' uses vocabulary (and constants) in common with A. - return lemmas to weaken B. - */ - - bool get_lemma_guesses(expr * A, expr * B, expr_ref_vector& lemmas); - - /** - Traverse a proof and retrieve lemmas using the vocabulary from bs. - */ - void get_lemmas(proof* root, expr_set const& bs, expr_ref_vector& lemmas); - - /** - Traverse a proof and retrieve consequences of A that are used to establish ~B. - The assumption is that: - - A => \/ ~consequences[i] and \/ ~consequences[i] => ~B - - e.g., the second implication can be rewritten as: - - B => /\ consequences[i] - */ - void get_consequences(proof* root, expr_set const& bs, expr_ref_vector& consequences); - - /** - \brief Simplify lemmas using subsumption. - */ - void simplify_lemmas(expr_ref_vector& lemmas); - - void collect_statistics(statistics& st) const; - -}; - - -} - -#endif diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp deleted file mode 100644 index 8e52cb6f4..000000000 --- a/src/muz/pdr/pdr_generalizers.cpp +++ /dev/null @@ -1,777 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_generalizers.cpp - -Abstract: - - Generalizers of satisfiable states and unsat cores. - -Author: - - Nikolaj Bjorner (nbjorner) 2011-11-20. - -Revision History: - ---*/ - - -#include "muz/pdr/pdr_context.h" -#include "muz/pdr/pdr_farkas_learner.h" -#include "muz/pdr/pdr_generalizers.h" -#include "ast/expr_abstract.h" -#include "ast/rewriter/var_subst.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "model/model_smt2_pp.h" - - -namespace pdr { - - - // ------------------------ - // core_bool_inductive_generalizer - - // main propositional induction generalizer. - // drop literals one by one from the core and check if the core is still inductive. - // - void core_bool_inductive_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { - if (core.size() <= 1) { - return; - } - ast_manager& m = core.get_manager(); - TRACE("pdr", for (unsigned i = 0; i < core.size(); ++i) { tout << mk_pp(core[i].get(), m) << "\n"; }); - unsigned num_failures = 0, i = 0, old_core_size = core.size(); - ptr_vector processed; - - while (i < core.size() && 1 < core.size() && (!m_failure_limit || num_failures <= m_failure_limit)) { - expr_ref lit(m); - lit = core[i].get(); - core[i] = m.mk_true(); - if (n.pt().check_inductive(n.level(), core, uses_level)) { - num_failures = 0; - for (i = 0; i < core.size() && processed.contains(core[i].get()); ++i); - } - else { - core[i] = lit; - processed.push_back(lit); - ++num_failures; - ++i; - } - } - IF_VERBOSE(2, verbose_stream() << "old size: " << old_core_size << " new size: " << core.size() << "\n";); - TRACE("pdr", tout << "old size: " << old_core_size << " new size: " << core.size() << "\n";); - } - - - void core_multi_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { - UNREACHABLE(); - } - - /** - \brief Find minimal cores. - Apply a simple heuristic: find a minimal core, then find minimal cores that exclude at least one - literal from each of the literals in the minimal cores. - */ - void core_multi_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - ast_manager& m = core.get_manager(); - expr_ref_vector old_core(m), core0(core); - bool uses_level1 = uses_level; - m_gen(n, core0, uses_level1); - new_cores.push_back(std::make_pair(core0, uses_level1)); - obj_hashtable core_exprs, core1_exprs; - set_union(core_exprs, core0); - for (unsigned i = 0; i < old_core.size(); ++i) { - expr* lit = old_core[i].get(); - if (core_exprs.contains(lit)) { - expr_ref_vector core1(old_core); - core1[i] = core1.back(); - core1.pop_back(); - uses_level1 = uses_level; - m_gen(n, core1, uses_level1); - SASSERT(core1.size() <= old_core.size()); - if (core1.size() < old_core.size()) { - new_cores.push_back(std::make_pair(core1, uses_level1)); - core1_exprs.reset(); - set_union(core1_exprs, core1); - set_intersection(core_exprs, core1_exprs); - } - } - } - } - - // ------------------------ - // core_farkas_generalizer - - // - // for each disjunct of core: - // weaken predecessor. - // - - core_farkas_generalizer::core_farkas_generalizer(context& ctx, ast_manager& m, smt_params& p): - core_generalizer(ctx), - m_farkas_learner(p, m) - {} - - void core_farkas_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { - ast_manager& m = n.pt().get_manager(); - if (core.empty()) return; - expr_ref A(m), B(mk_and(core)), C(m); - expr_ref_vector Bs(m); - flatten_or(B, Bs); - A = n.pt().get_propagation_formula(m_ctx.get_pred_transformers(), n.level()); - - bool change = false; - for (unsigned i = 0; i < Bs.size(); ++i) { - expr_ref_vector lemmas(m); - C = Bs[i].get(); - if (m_farkas_learner.get_lemma_guesses(A, B, lemmas)) { - TRACE("pdr", - tout << "Old core:\n" << mk_pp(B, m) << "\n"; - tout << "New core:\n" << mk_and(lemmas) << "\n";); - Bs[i] = mk_and(lemmas); - change = true; - } - } - if (change) { - C = mk_or(Bs); - TRACE("pdr", tout << "prop:\n" << mk_pp(A,m) << "\ngen:" << mk_pp(B, m) << "\nto: " << mk_pp(C, m) << "\n";); - core.reset(); - flatten_and(C, core); - uses_level = true; - } - } - - void core_farkas_generalizer::collect_statistics(statistics& st) const { - m_farkas_learner.collect_statistics(st); - } - - - core_convex_hull_generalizer::core_convex_hull_generalizer(context& ctx, bool is_closure): - core_generalizer(ctx), - m(ctx.get_manager()), - m_is_closure(is_closure) { - } - - void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - // method3(n, core, uses_level, new_cores); - method1(n, core, uses_level, new_cores); - } - - void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { - UNREACHABLE(); - } - - // use the entire region as starting point for generalization. - // - // Constraints: - // add_variables: y = y1 + y2 - // core: Ay <= b -> conv1: A*y1 <= b*sigma1 - // sigma1 > 0 - // sigma2 > 0 - // 1 = sigma1 + sigma2 - // A'y <= b' -> conv2: A'*y2 <= b'*sigma2 - // - // If Constraints & Transition(y0, y) is unsat, then - // update with new core. - // - void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - expr_ref_vector conv2(m), fmls(m), fml1_2(m); - bool change = false; - - if (core.empty()) { - new_cores.push_back(std::make_pair(core, uses_level)); - return; - } - closure cl(n.pt(), m_is_closure); - - expr_ref fml1 = mk_and(core); - expr_ref fml2 = n.pt().get_formulas(n.level(), false); - fml1_2.push_back(fml1); - fml1_2.push_back(nullptr); - flatten_and(fml2, fmls); - for (unsigned i = 0; i < fmls.size(); ++i) { - fml2 = m.mk_not(fmls[i].get()); - fml1_2[1] = fml2; - expr_ref state = cl(fml1_2); - TRACE("pdr", - tout << "Check states:\n" << mk_pp(state, m) << "\n"; - tout << "Old states:\n" << mk_pp(fml2, m) << "\n"; - ); - model_node nd(nullptr, state, n.pt(), n.level()); - pred_transformer::scoped_farkas sf(n.pt(), true); - bool uses_level1 = uses_level; - if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) { - new_cores.push_back(std::make_pair(conv2, uses_level1)); - change = true; - expr_ref state1 = mk_and(conv2); - TRACE("pdr", - tout << mk_pp(state, m) << "\n"; - tout << "Generalized to:\n" << mk_pp(state1, m) << "\n";); - IF_VERBOSE(0, - verbose_stream() << mk_pp(state, m) << "\n"; - verbose_stream() << "Generalized to:\n" << mk_pp(state1, m) << "\n";); - } - } - if (!m_is_closure || !change) { - new_cores.push_back(std::make_pair(core, uses_level)); - } - } - - /* - Extract the lemmas from the transition relation that were used to establish unsatisfiability. - Take convex closures of conbinations of these lemmas. - */ - void core_convex_hull_generalizer::method3(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - TRACE("dl", tout << "method: generalize consequences of F(R)\n"; - for (unsigned i = 0; i < core.size(); ++i) { - tout << "B:" << mk_pp(core[i], m) << "\n"; - }); - bool uses_level1; - expr_ref_vector core1(m); - core1.append(core); - expr_ref_vector consequences(m); - { - n.pt().get_solver().set_consequences(&consequences); - pred_transformer::scoped_farkas sf (n.pt(), true); - VERIFY(l_false == n.pt().is_reachable(n, &core1, uses_level1)); - n.pt().get_solver().set_consequences(nullptr); - } - IF_VERBOSE(0, - verbose_stream() << "Consequences: " << consequences.size() << "\n"; - for (unsigned i = 0; i < consequences.size(); ++i) { - verbose_stream() << mk_pp(consequences[i].get(), m) << "\n"; - } - verbose_stream() << "core: " << core1.size() << "\n"; - for (unsigned i = 0; i < core1.size(); ++i) { - verbose_stream() << mk_pp(core1[i].get(), m) << "\n"; - }); - - expr_ref tmp(m); - - // Check that F(R) => \/ consequences - { - expr_ref_vector cstate(m); - for (unsigned i = 0; i < consequences.size(); ++i) { - cstate.push_back(m.mk_not(consequences[i].get())); - } - tmp = m.mk_and(cstate.size(), cstate.c_ptr()); - model_node nd(nullptr, tmp, n.pt(), n.level()); - pred_transformer::scoped_farkas sf (n.pt(), false); - VERIFY(l_false == n.pt().is_reachable(nd, &core1, uses_level1)); - } - - // Create disjunction. - tmp = m.mk_and(core.size(), core.c_ptr()); - - // Check that \/ consequences => not (core) - if (!is_unsat(consequences, tmp)) { - IF_VERBOSE(0, verbose_stream() << "Consequences don't contradict the core\n";); - return; - } - IF_VERBOSE(0, verbose_stream() << "Consequences contradict core\n";); - - if (!strengthen_consequences(n, consequences, tmp)) { - return; - } - - IF_VERBOSE(0, verbose_stream() << "consequences strengthened\n";); - // Use the resulting formula to find Farkas lemmas from core. - } - - bool core_convex_hull_generalizer::strengthen_consequences(model_node& n, expr_ref_vector& As, expr* B) { - expr_ref A(m), tmp(m), convA(m); - unsigned sz = As.size(); - closure cl(n.pt(), m_is_closure); - for (unsigned i = 0; i < As.size(); ++i) { - expr_ref_vector Hs(m); - Hs.push_back(As[i].get()); - for (unsigned j = i + 1; j < As.size(); ++j) { - Hs.push_back(As[j].get()); - bool unsat = false; - A = cl(Hs); - tmp = As[i].get(); - As[i] = A; - unsat = is_unsat(As, B); - As[i] = tmp; - if (unsat) { - IF_VERBOSE(0, verbose_stream() << "New convex: " << mk_pp(convA, m) << "\n";); - convA = A; - As[j] = As.back(); - As.pop_back(); - --j; - } - else { - Hs.pop_back(); - } - } - if (Hs.size() > 1) { - As[i] = convA; - } - } - return sz > As.size(); - } - - - bool core_convex_hull_generalizer::is_unsat(expr_ref_vector const& As, expr* B) { - smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); - expr_ref disj(m); - disj = m.mk_or(As.size(), As.c_ptr()); - ctx.assert_expr(disj); - ctx.assert_expr(B); - std::cout << "Checking\n" << mk_pp(disj, m) << "\n" << mk_pp(B, m) << "\n"; - return l_false == ctx.check(); - } - - - // --------------------------------- - // core_arith_inductive_generalizer - // NB. this is trying out some ideas for generalization in - // an ad hoc specialized way. arith_inductive_generalizer should - // not be used by default. It is a place-holder for a general purpose - // extrapolator of a lattice basis. - - core_arith_inductive_generalizer::core_arith_inductive_generalizer(context& ctx): - core_generalizer(ctx), - m(ctx.get_manager()), - a(m), - m_refs(m) {} - - void core_arith_inductive_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { - if (core.size() <= 1) { - return; - } - reset(); - expr_ref e(m), t1(m), t2(m), t3(m); - rational r; - - TRACE("pdr", for (unsigned i = 0; i < core.size(); ++i) { tout << mk_pp(core[i].get(), m) << "\n"; }); - - svector eqs; - get_eqs(core, eqs); - - if (eqs.empty()) { - return; - } - - expr_ref_vector new_core(m); - new_core.append(core); - - for (unsigned eq = 0; eq < eqs.size(); ++eq) { - rational r = eqs[eq].m_value; - expr* x = eqs[eq].m_term; - unsigned k = eqs[eq].m_i; - unsigned l = eqs[eq].m_j; - - new_core[l] = m.mk_true(); - new_core[k] = m.mk_true(); - - for (unsigned i = 0; i < new_core.size(); ++i) { - if (substitute_alias(r, x, new_core[i].get(), e)) { - new_core[i] = e; - } - } - if (abs(r) >= rational(2) && a.is_int(x)) { - new_core[k] = m.mk_eq(a.mk_mod(x, a.mk_numeral(rational(2), true)), a.mk_numeral(rational(0), true)); - new_core[l] = a.mk_le(x, a.mk_numeral(rational(0), true)); - } - } - - bool inductive = n.pt().check_inductive(n.level(), new_core, uses_level); - - IF_VERBOSE(1, - verbose_stream() << (inductive?"":"non") << "inductive\n"; - verbose_stream() << "old\n"; - for (unsigned j = 0; j < core.size(); ++j) { - verbose_stream() << mk_pp(core[j].get(), m) << "\n"; - } - verbose_stream() << "new\n"; - for (unsigned j = 0; j < new_core.size(); ++j) { - verbose_stream() << mk_pp(new_core[j].get(), m) << "\n"; - }); - - if (inductive) { - core.reset(); - core.append(new_core); - } - } - - void core_arith_inductive_generalizer::insert_bound(bool is_lower, expr* x, rational const& r, unsigned i) { - if (r.is_neg()) { - expr_ref e(m); - e = a.mk_uminus(x); - m_refs.push_back(e); - x = e; - is_lower = !is_lower; - } - - vector bound; - bound.push_back(std::make_pair(x, i)); - if (is_lower) { - m_lb.insert(abs(r), bound); - } - else { - m_ub.insert(abs(r), bound); - } - } - - void core_arith_inductive_generalizer::reset() { - m_refs.reset(); - m_lb.reset(); - m_ub.reset(); - } - - void core_arith_inductive_generalizer::get_eqs(expr_ref_vector const& core, svector& eqs) { - expr* e1, *x, *y; - expr_ref e(m); - rational r; - - for (unsigned i = 0; i < core.size(); ++i) { - e = core[i]; - if (m.is_not(e, e1) && a.is_le(e1, x, y) && a.is_numeral(y, r) && a.is_int(x)) { - // not (<= x r) <=> x >= r + 1 - insert_bound(true, x, r + rational(1), i); - } - else if (m.is_not(e, e1) && a.is_ge(e1, x, y) && a.is_numeral(y, r) && a.is_int(x)) { - // not (>= x r) <=> x <= r - 1 - insert_bound(false, x, r - rational(1), i); - } - else if (a.is_le(e, x, y) && a.is_numeral(y, r)) { - insert_bound(false, x, r, i); - } - else if (a.is_ge(e, x, y) && a.is_numeral(y, r)) { - insert_bound(true, x, r, i); - } - } - bounds_t::iterator it = m_lb.begin(), end = m_lb.end(); - for (; it != end; ++it) { - rational r = it->m_key; - vector & terms1 = it->m_value; - vector terms2; - if (r >= rational(2) && m_ub.find(r, terms2)) { - for (unsigned i = 0; i < terms1.size(); ++i) { - bool done = false; - for (unsigned j = 0; !done && j < terms2.size(); ++j) { - expr* t1 = terms1[i].first; - expr* t2 = terms2[j].first; - if (t1 == t2) { - eqs.push_back(eq(t1, r, terms1[i].second, terms2[j].second)); - done = true; - } - else { - e = m.mk_eq(t1, t2); - th_rewriter rw(m); - rw(e); - if (m.is_true(e)) { - eqs.push_back(eq(t1, r, terms1[i].second, terms2[j].second)); - done = true; - } - } - } - } - } - } - } - - bool core_arith_inductive_generalizer::substitute_alias(rational const& r, expr* x, expr* e, expr_ref& result) { - rational r2; - expr* y, *z, *e1; - if (m.is_not(e, e1) && substitute_alias(r, x, e1, result)) { - result = m.mk_not(result); - return true; - } - if (a.is_le(e, y, z) && a.is_numeral(z, r2)) { - if (r == r2) { - result = a.mk_le(y, x); - return true; - } - if (r == r2 + rational(1)) { - result = a.mk_lt(y, x); - return true; - } - if (r == r2 - rational(1)) { - result = a.mk_le(y, a.mk_sub(x, a.mk_numeral(rational(1), a.is_int(x)))); - return true; - } - - } - if (a.is_ge(e, y, z) && a.is_numeral(z, r2)) { - if (r == r2) { - result = a.mk_ge(y, x); - return true; - } - if (r2 == r + rational(1)) { - result = a.mk_gt(y, x); - return true; - } - if (r2 == r - rational(1)) { - result = a.mk_ge(y, a.mk_sub(x, a.mk_numeral(rational(1), a.is_int(x)))); - return true; - } - } - return false; - } - - - // - // < F, phi, i + 1> - // | - // < G, psi, i > - // - // where: - // - // p(x) <- F(x,y,p,q) - // q(x) <- G(x,y) - // - // Hyp: - // Q_k(x) => phi(x) j <= k <= i - // Q_k(x) => R_k(x) j <= k <= i + 1 - // Q_k(x) <=> Trans(Q_{k-1}) j < k <= i + 1 - // Conclusion: - // Q_{i+1}(x) => phi(x) - // - class core_induction_generalizer::imp { - context& m_ctx; - manager& pm; - ast_manager& m; - - // - // Create predicate Q_level - // - func_decl_ref mk_pred(unsigned level, func_decl* f) { - func_decl_ref result(m); - std::ostringstream name; - name << f->get_name() << "_" << level; - symbol sname(name.str().c_str()); - result = m.mk_func_decl(sname, f->get_arity(), f->get_domain(), f->get_range()); - return result; - } - - // - // Create formula exists y . z . F[Q_{level-1}, x, y, z] - // - expr_ref mk_transition_rule( - expr_ref_vector const& reps, - unsigned level, - datalog::rule const& rule) - { - expr_ref_vector conj(m), sub(m); - expr_ref result(m); - svector names; - unsigned ut_size = rule.get_uninterpreted_tail_size(); - unsigned t_size = rule.get_tail_size(); - if (0 == level && 0 < ut_size) { - result = m.mk_false(); - return result; - } - app* atom = rule.get_head(); - SASSERT(atom->get_num_args() == reps.size()); - - for (unsigned i = 0; i < reps.size(); ++i) { - expr* arg = atom->get_arg(i); - if (is_var(arg)) { - unsigned idx = to_var(arg)->get_idx(); - if (idx >= sub.size()) sub.resize(idx+1); - if (sub[idx].get()) { - conj.push_back(m.mk_eq(sub[idx].get(), reps[i])); - } - else { - sub[idx] = reps[i]; - } - } - else { - conj.push_back(m.mk_eq(arg, reps[i])); - } - } - for (unsigned i = 0; 0 < level && i < ut_size; i++) { - app* atom = rule.get_tail(i); - func_decl* head = atom->get_decl(); - func_decl_ref fn = mk_pred(level-1, head); - conj.push_back(m.mk_app(fn, atom->get_num_args(), atom->get_args())); - } - for (unsigned i = ut_size; i < t_size; i++) { - conj.push_back(rule.get_tail(i)); - } - result = mk_and(conj); - if (!sub.empty()) { - expr_ref tmp = result; - var_subst(m, false)(tmp, sub.size(), sub.c_ptr(), result); - } - expr_free_vars fv; - fv(result); - fv.set_default_sort(m.mk_bool_sort()); - for (unsigned i = 0; i < fv.size(); ++i) { - names.push_back(symbol(fv.size() - i - 1)); - } - if (!fv.empty()) { - fv.reverse(); - result = m.mk_exists(fv.size(), fv.c_ptr(), names.c_ptr(), result); - } - return result; - } - - expr_ref bind_head(expr_ref_vector const& reps, expr* fml) { - expr_ref result(m); - expr_abstract(m, 0, reps.size(), reps.c_ptr(), fml, result); - ptr_vector sorts; - svector names; - unsigned sz = reps.size(); - for (unsigned i = 0; i < sz; ++i) { - sorts.push_back(m.get_sort(reps[sz-i-1])); - names.push_back(symbol(sz-i-1)); - } - if (sz > 0) { - result = m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), result); - } - return result; - } - - expr_ref_vector mk_reps(pred_transformer& pt) { - expr_ref_vector reps(m); - expr_ref rep(m); - for (unsigned i = 0; i < pt.head()->get_arity(); ++i) { - rep = m.mk_const(pm.o2n(pt.sig(i), 0)); - reps.push_back(rep); - } - return reps; - } - - // - // extract transition axiom: - // - // forall x . p_lvl(x) <=> exists y z . F[p_{lvl-1}(y), q_{lvl-1}(z), x] - // - expr_ref mk_transition_axiom(pred_transformer& pt, unsigned level) { - expr_ref fml(m.mk_false(), m), tr(m); - expr_ref_vector reps = mk_reps(pt); - ptr_vector const& rules = pt.rules(); - for (unsigned i = 0; i < rules.size(); ++i) { - tr = mk_transition_rule(reps, level, *rules[i]); - fml = (i == 0)?tr.get():m.mk_or(fml, tr); - } - func_decl_ref fn = mk_pred(level, pt.head()); - fml = m.mk_iff(m.mk_app(fn, reps.size(), reps.c_ptr()), fml); - fml = bind_head(reps, fml); - return fml; - } - - // - // Create implication: - // Q_level(x) => phi(x) - // - expr_ref mk_predicate_property(unsigned level, pred_transformer& pt, expr* phi) { - expr_ref_vector reps = mk_reps(pt); - func_decl_ref fn = mk_pred(level, pt.head()); - expr_ref fml(m); - fml = m.mk_implies(m.mk_app(fn, reps.size(), reps.c_ptr()), phi); - fml = bind_head(reps, fml); - return fml; - } - - - - public: - imp(context& ctx): m_ctx(ctx), pm(ctx.get_pdr_manager()), m(ctx.get_manager()) {} - - // - // not exists y . F(x,y) - // - expr_ref mk_blocked_transition(pred_transformer& pt, unsigned level) { - SASSERT(level > 0); - expr_ref fml(m.mk_true(), m); - expr_ref_vector reps = mk_reps(pt), fmls(m); - ptr_vector const& rules = pt.rules(); - for (unsigned i = 0; i < rules.size(); ++i) { - fmls.push_back(m.mk_not(mk_transition_rule(reps, level, *rules[i]))); - } - fml = mk_and(fmls); - TRACE("pdr", tout << mk_pp(fml, m) << "\n";); - return fml; - } - - expr_ref mk_induction_goal(pred_transformer& pt, unsigned level, unsigned depth) { - SASSERT(level >= depth); - expr_ref_vector conjs(m); - ptr_vector pts; - unsigned_vector levels; - // negated goal - expr_ref phi = mk_blocked_transition(pt, level); - conjs.push_back(m.mk_not(mk_predicate_property(level, pt, phi))); - pts.push_back(&pt); - levels.push_back(level); - // Add I.H. - for (unsigned lvl = level-depth; lvl < level; ++lvl) { - if (lvl > 0) { - expr_ref psi = mk_blocked_transition(pt, lvl); - conjs.push_back(mk_predicate_property(lvl, pt, psi)); - pts.push_back(&pt); - levels.push_back(lvl); - } - } - // Transitions: - for (unsigned qhead = 0; qhead < pts.size(); ++qhead) { - pred_transformer& qt = *pts[qhead]; - unsigned lvl = levels[qhead]; - - // Add transition definition and properties at level. - conjs.push_back(mk_transition_axiom(qt, lvl)); - conjs.push_back(mk_predicate_property(lvl, qt, qt.get_formulas(lvl, true))); - - // Enqueue additional hypotheses - ptr_vector const& rules = qt.rules(); - if (lvl + depth < level || lvl == 0) { - continue; - } - for (unsigned i = 0; i < rules.size(); ++i) { - datalog::rule& r = *rules[i]; - unsigned ut_size = r.get_uninterpreted_tail_size(); - for (unsigned j = 0; j < ut_size; ++j) { - func_decl* f = r.get_tail(j)->get_decl(); - pred_transformer* rt = m_ctx.get_pred_transformers().find(f); - bool found = false; - for (unsigned k = 0; !found && k < levels.size(); ++k) { - found = (rt == pts[k] && levels[k] + 1 == lvl); - } - if (!found) { - levels.push_back(lvl-1); - pts.push_back(rt); - } - } - } - } - - expr_ref result = mk_and(conjs); - TRACE("pdr", tout << mk_pp(result, m) << "\n";); - return result; - } - }; - - // - // Instantiate Peano induction schema. - // - void core_induction_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { - model_node* p = n.parent(); - if (p == nullptr) { - return; - } - unsigned depth = 2; - imp imp(m_ctx); - ast_manager& m = core.get_manager(); - expr_ref goal = imp.mk_induction_goal(p->pt(), p->level(), depth); - smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); - ctx.assert_expr(goal); - lbool r = ctx.check(); - TRACE("pdr", tout << r << "\n"; - for (unsigned i = 0; i < core.size(); ++i) { - tout << mk_pp(core[i].get(), m) << "\n"; - }); - if (r == l_false) { - core.reset(); - expr_ref phi = imp.mk_blocked_transition(p->pt(), p->level()); - core.push_back(m.mk_not(phi)); - uses_level = true; - } - } -}; - diff --git a/src/muz/pdr/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h deleted file mode 100644 index a75b347a4..000000000 --- a/src/muz/pdr/pdr_generalizers.h +++ /dev/null @@ -1,110 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_generalizers.h - -Abstract: - - Generalizer plugins. - -Author: - - Nikolaj Bjorner (nbjorner) 2011-11-22. - -Revision History: - ---*/ - -#ifndef PDR_GENERALIZERS_H_ -#define PDR_GENERALIZERS_H_ - -#include "muz/pdr/pdr_context.h" -#include "muz/pdr/pdr_closure.h" -#include "ast/arith_decl_plugin.h" - -namespace pdr { - - class core_bool_inductive_generalizer : public core_generalizer { - unsigned m_failure_limit; - public: - core_bool_inductive_generalizer(context& ctx, unsigned failure_limit) : core_generalizer(ctx), m_failure_limit(failure_limit) {} - ~core_bool_inductive_generalizer() override {} - void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; - }; - - template - class r_map : public map { - }; - - class core_arith_inductive_generalizer : public core_generalizer { - typedef std::pair term_loc_t; - typedef r_map > bounds_t; - - ast_manager& m; - arith_util a; - expr_ref_vector m_refs; - bounds_t m_lb; - bounds_t m_ub; - - struct eq { - expr* m_term; - rational m_value; - unsigned m_i; - unsigned m_j; - eq(expr* t, rational const& r, unsigned i, unsigned j): m_term(t), m_value(r), m_i(i), m_j(j) {} - }; - void reset(); - void insert_bound(bool is_lower, expr* x, rational const& r, unsigned i); - void get_eqs(expr_ref_vector const& core, svector& eqs); - bool substitute_alias(rational const&r, expr* x, expr* e, expr_ref& result); - public: - core_arith_inductive_generalizer(context& ctx); - ~core_arith_inductive_generalizer() override {} - void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; - }; - - class core_farkas_generalizer : public core_generalizer { - farkas_learner m_farkas_learner; - public: - core_farkas_generalizer(context& ctx, ast_manager& m, smt_params& p); - ~core_farkas_generalizer() override {} - void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; - void collect_statistics(statistics& st) const override; - }; - - - class core_convex_hull_generalizer : public core_generalizer { - ast_manager& m; - obj_map m_models; - bool m_is_closure; - void method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); - void method3(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); - bool strengthen_consequences(model_node& n, expr_ref_vector& As, expr* B); - bool is_unsat(expr_ref_vector const& As, expr* B); - public: - core_convex_hull_generalizer(context& ctx, bool is_closure); - ~core_convex_hull_generalizer() override {} - void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) override; - void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; - }; - - class core_multi_generalizer : public core_generalizer { - core_bool_inductive_generalizer m_gen; - public: - core_multi_generalizer(context& ctx, unsigned max_failures): core_generalizer(ctx), m_gen(ctx, max_failures) {} - ~core_multi_generalizer() override {} - void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; - void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) override; - }; - - class core_induction_generalizer : public core_generalizer { - class imp; - public: - core_induction_generalizer(context& ctx): core_generalizer(ctx) {} - ~core_induction_generalizer() override {} - void operator()(model_node& n, expr_ref_vector& core, bool& uses_level) override; - }; -}; -#endif diff --git a/src/muz/pdr/pdr_manager.cpp b/src/muz/pdr/pdr_manager.cpp deleted file mode 100644 index da15bf094..000000000 --- a/src/muz/pdr/pdr_manager.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_manager.cpp - -Abstract: - - A manager class for PDR, taking care of creating of AST - objects and conversions between them. - -Author: - - Krystof Hoder (t-khoder) 2011-8-25. - -Revision History: - ---*/ - -#include -#include "muz/pdr/pdr_manager.h" -#include "ast/ast_smt2_pp.h" -#include "ast/for_each_expr.h" -#include "ast/has_free_vars.h" -#include "ast/rewriter/expr_replacer.h" -#include "ast/expr_abstract.h" -#include "model/model2expr.h" -#include "model/model_smt2_pp.h" -#include "tactic/model_converter.h" - -namespace pdr { - - class collect_decls_proc { - func_decl_set& m_bound_decls; - func_decl_set& m_aux_decls; - public: - collect_decls_proc(func_decl_set& bound_decls, func_decl_set& aux_decls): - m_bound_decls(bound_decls), - m_aux_decls(aux_decls) { - } - - void operator()(app* a) { - if (a->get_family_id() == null_family_id) { - func_decl* f = a->get_decl(); - if (!m_bound_decls.contains(f)) { - m_aux_decls.insert(f); - } - } - } - void operator()(var* v) {} - void operator()(quantifier* q) {} - }; - - typedef hashtable symbol_set; - - expr_ref inductive_property::fixup_clause(expr* fml) const { - expr_ref_vector disjs(m); - flatten_or(fml, disjs); - expr_ref result(m); - bool_rewriter(m).mk_or(disjs.size(), disjs.c_ptr(), result); - return result; - } - - expr_ref inductive_property::fixup_clauses(expr* fml) const { - expr_ref_vector conjs(m); - expr_ref result(m); - flatten_and(fml, conjs); - for (unsigned i = 0; i < conjs.size(); ++i) { - conjs[i] = fixup_clause(conjs[i].get()); - } - bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), result); - return result; - } - - std::string inductive_property::to_string() const { - std::stringstream stm; - model_ref md; - expr_ref result(m); - to_model(md); - model_smt2_pp(stm, m, *md.get(), 0); - return stm.str(); - } - - void inductive_property::to_model(model_ref& md) const { - md = alloc(model, m); - vector const& rs = m_relation_info; - expr_ref_vector conjs(m); - for (unsigned i = 0; i < rs.size(); ++i) { - relation_info ri(rs[i]); - func_decl * pred = ri.m_pred; - expr_ref prop = fixup_clauses(ri.m_body); - func_decl_ref_vector const& sig = ri.m_vars; - expr_ref q(m); - expr_ref_vector sig_vars(m); - for (unsigned j = 0; j < sig.size(); ++j) { - sig_vars.push_back(m.mk_const(sig[sig.size()-j-1])); - } - expr_abstract(m, 0, sig_vars.size(), sig_vars.c_ptr(), prop, q); - if (sig.empty()) { - md->register_decl(pred, q); - } - else { - func_interp* fi = alloc(func_interp, m, sig.size()); - fi->set_else(q); - md->register_decl(pred, fi); - } - } - TRACE("pdr", model_smt2_pp(tout, m, *md, 0);); - apply(const_cast(m_mc), md); - } - - expr_ref inductive_property::to_expr() const { - model_ref md; - expr_ref result(m); - to_model(md); - model2expr(md, result); - return result; - } - - - void inductive_property::display(datalog::rule_manager& rm, ptr_vector const& rules, std::ostream& out) const { - func_decl_set bound_decls, aux_decls; - collect_decls_proc collect_decls(bound_decls, aux_decls); - - for (unsigned i = 0; i < m_relation_info.size(); ++i) { - bound_decls.insert(m_relation_info[i].m_pred); - func_decl_ref_vector const& sig = m_relation_info[i].m_vars; - for (unsigned j = 0; j < sig.size(); ++j) { - bound_decls.insert(sig[j]); - } - for_each_expr(collect_decls, m_relation_info[i].m_body); - } - for (unsigned i = 0; i < rules.size(); ++i) { - bound_decls.insert(rules[i]->get_decl()); - } - for (unsigned i = 0; i < rules.size(); ++i) { - unsigned u_sz = rules[i]->get_uninterpreted_tail_size(); - unsigned t_sz = rules[i]->get_tail_size(); - for (unsigned j = u_sz; j < t_sz; ++j) { - for_each_expr(collect_decls, rules[i]->get_tail(j)); - } - } - smt2_pp_environment_dbg env(m); - func_decl_set::iterator it = aux_decls.begin(), end = aux_decls.end(); - for (; it != end; ++it) { - func_decl* f = *it; - ast_smt2_pp(out, f, env); - out << "\n"; - } - - out << to_string() << "\n"; - for (unsigned i = 0; i < rules.size(); ++i) { - out << "(push)\n"; - out << "(assert (not\n"; - rm.display_smt2(*rules[i], out); - out << "))\n"; - out << "(check-sat)\n"; - out << "(pop)\n"; - } - } - - manager::manager(smt_params& fparams, unsigned max_num_contexts, ast_manager& manager) : - m(manager), - m_fparams(fparams), - m_brwr(m), - m_mux(m), - m_background(m.mk_true(), m), - m_contexts(fparams, max_num_contexts, m), - m_next_unique_num(0) - { - } - - - void manager::add_new_state(func_decl * s) { - SASSERT(s->get_arity()==0); //we currently don't support non-constant states - decl_vector vect; - SASSERT(o_index(0)==1); //we assume this in the number of retrieved symbols - m_mux.create_tuple(s, s->get_arity(), s->get_domain(), s->get_range(), 2, vect); - m_o0_preds.push_back(vect[o_index(0)]); - } - - func_decl * manager::get_o_pred(func_decl* s, unsigned idx) - { - func_decl * res = m_mux.try_get_by_prefix(s, o_index(idx)); - if(res) { return res; } - add_new_state(s); - res = m_mux.try_get_by_prefix(s, o_index(idx)); - SASSERT(res); - return res; - } - - func_decl * manager::get_n_pred(func_decl* s) - { - func_decl * res = m_mux.try_get_by_prefix(s, n_index()); - if(res) { return res; } - add_new_state(s); - res = m_mux.try_get_by_prefix(s, n_index()); - SASSERT(res); - return res; - } - - void manager::mk_model_into_cube(const expr_ref_vector & mdl, expr_ref & res) { - m_brwr.mk_and(mdl.size(), mdl.c_ptr(), res); - } - - void manager::mk_core_into_cube(const expr_ref_vector & core, expr_ref & res) { - m_brwr.mk_and(core.size(), core.c_ptr(), res); - } - - void manager::mk_cube_into_lemma(expr * cube, expr_ref & res) { - m_brwr.mk_not(cube, res); - } - - void manager::mk_lemma_into_cube(expr * lemma, expr_ref & res) { - m_brwr.mk_not(lemma, res); - } - - expr_ref manager::mk_and(unsigned sz, expr* const* exprs) { - expr_ref result(m); - m_brwr.mk_and(sz, exprs, result); - return result; - } - - expr_ref manager::mk_or(unsigned sz, expr* const* exprs) { - expr_ref result(m); - m_brwr.mk_or(sz, exprs, result); - return result; - } - - expr_ref manager::mk_not_and(expr_ref_vector const& conjs) { - expr_ref result(m), e(m); - expr_ref_vector es(conjs); - flatten_and(es); - for (unsigned i = 0; i < es.size(); ++i) { - m_brwr.mk_not(es[i].get(), e); - es[i] = e; - } - m_brwr.mk_or(es.size(), es.c_ptr(), result); - return result; - } - - void manager::get_or(expr* e, expr_ref_vector& result) { - result.push_back(e); - for (unsigned i = 0; i < result.size(); ) { - e = result[i].get(); - if (m.is_or(e)) { - result.append(to_app(e)->get_num_args(), to_app(e)->get_args()); - result[i] = result.back(); - result.pop_back(); - } - else { - ++i; - } - } - } - - bool manager::try_get_state_and_value_from_atom(expr * atom0, app *& state, app_ref& value) - { - if(!is_app(atom0)) { - return false; - } - app * atom = to_app(atom0); - expr * arg1; - expr * arg2; - app * candidate_state; - app_ref candidate_value(m); - if(m.is_not(atom, arg1)) { - if(!is_app(arg1)) { - return false; - } - candidate_state = to_app(arg1); - candidate_value = m.mk_false(); - } - else if(m.is_eq(atom, arg1, arg2)) { - if(!is_app(arg1) || !is_app(arg2)) { - return false; - } - if(!m_mux.is_muxed(to_app(arg1)->get_decl())) { - std::swap(arg1, arg2); - } - candidate_state = to_app(arg1); - candidate_value = to_app(arg2); - } - else { - candidate_state = atom; - candidate_value = m.mk_true(); - } - if(!m_mux.is_muxed(candidate_state->get_decl())) { - return false; - } - state = candidate_state; - value = candidate_value; - return true; - } - - bool manager::try_get_state_decl_from_atom(expr * atom, func_decl *& state) { - app_ref dummy_value_holder(m); - app * s; - if(try_get_state_and_value_from_atom(atom, s, dummy_value_holder)) { - state = s->get_decl(); - return true; - } - else { - return false; - } - } - - bool manager::implication_surely_holds(expr * lhs, expr * rhs, expr * bg) { - smt::kernel sctx(m, get_fparams()); - if(bg) { - sctx.assert_expr(bg); - } - sctx.assert_expr(lhs); - expr_ref neg_rhs(m.mk_not(rhs),m); - sctx.assert_expr(neg_rhs); - lbool smt_res = sctx.check(); - return smt_res==l_false; - } - -}; diff --git a/src/muz/pdr/pdr_manager.h b/src/muz/pdr/pdr_manager.h deleted file mode 100644 index ccbbbe356..000000000 --- a/src/muz/pdr/pdr_manager.h +++ /dev/null @@ -1,304 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_manager.h - -Abstract: - - A manager class for PDR, taking care of creating of AST - objects and conversions between them. - -Author: - - Krystof Hoder (t-khoder) 2011-8-25. - -Revision History: - ---*/ - -#ifndef PDR_MANAGER_H_ -#define PDR_MANAGER_H_ - -#include -#include -#include "ast/rewriter/bool_rewriter.h" -#include "ast/rewriter/expr_replacer.h" -#include "ast/expr_substitution.h" -#include "util/map.h" -#include "util/ref_vector.h" -#include "smt/smt_kernel.h" -#include "muz/pdr/pdr_util.h" -#include "muz/pdr/pdr_sym_mux.h" -#include "muz/pdr/pdr_farkas_learner.h" -#include "muz/pdr/pdr_smt_context_manager.h" -#include "muz/base/dl_rule.h" - - -namespace smt { - class context; -} - -namespace pdr { - - struct relation_info { - func_decl_ref m_pred; - func_decl_ref_vector m_vars; - expr_ref m_body; - relation_info(ast_manager& m, func_decl* pred, ptr_vector const& vars, expr* b): - m_pred(pred, m), m_vars(m, vars.size(), vars.c_ptr()), m_body(b, m) {} - relation_info(relation_info const& other): m_pred(other.m_pred), m_vars(other.m_vars), m_body(other.m_body) {} - }; - - class unknown_exception {}; - - class inductive_property { - ast_manager& m; - model_converter_ref m_mc; - vector m_relation_info; - expr_ref fixup_clauses(expr* property) const; - expr_ref fixup_clause(expr* clause) const; - public: - inductive_property(ast_manager& m, model_converter_ref& mc, vector const& relations): - m(m), - m_mc(mc), - m_relation_info(relations) {} - - std::string to_string() const; - - expr_ref to_expr() const; - - void to_model(model_ref& md) const; - - void display(datalog::rule_manager& rm, ptr_vector const& rules, std::ostream& out) const; - }; - - class manager - { - ast_manager& m; - smt_params& m_fparams; - - mutable bool_rewriter m_brwr; - - sym_mux m_mux; - expr_ref m_background; - decl_vector m_o0_preds; - pdr::smt_context_manager m_contexts; - - /** whenever we need an unique number, we get this one and increase */ - unsigned m_next_unique_num; - - - unsigned n_index() const { return 0; } - unsigned o_index(unsigned i) const { return i+1; } - - void add_new_state(func_decl * s); - - public: - manager(smt_params& fparams, unsigned max_num_contexts, ast_manager & manager); - - ast_manager& get_manager() const { return m; } - smt_params& get_fparams() const { return m_fparams; } - bool_rewriter& get_brwr() const { return m_brwr; } - - expr_ref mk_and(unsigned sz, expr* const* exprs); - expr_ref mk_and(expr_ref_vector const& exprs) { - return mk_and(exprs.size(), exprs.c_ptr()); - } - expr_ref mk_and(expr* a, expr* b) { - expr* args[2] = { a, b }; - return mk_and(2, args); - } - expr_ref mk_or(unsigned sz, expr* const* exprs); - expr_ref mk_or(expr_ref_vector const& exprs) { - return mk_or(exprs.size(), exprs.c_ptr()); - } - - expr_ref mk_not_and(expr_ref_vector const& exprs); - - void get_or(expr* e, expr_ref_vector& result); - - //"o" predicates stand for the old states and "n" for the new states - func_decl * get_o_pred(func_decl * s, unsigned idx); - func_decl * get_n_pred(func_decl * s); - - /** - Marks symbol as non-model which means it will not appear in models collected by - get_state_cube_from_model function. - This is to take care of auxiliary symbols introduced by the disjunction relations - to relativize lemmas coming from disjuncts. - */ - void mark_as_non_model(func_decl * p) { - m_mux.mark_as_non_model(p); - } - - - func_decl * const * begin_o0_preds() const { return m_o0_preds.begin(); } - func_decl * const * end_o0_preds() const { return m_o0_preds.end(); } - - bool is_state_pred(func_decl * p) const { return m_mux.is_muxed(p); } - func_decl * to_o0(func_decl * p) { return m_mux.conv(m_mux.get_primary(p), 0, o_index(0)); } - - bool is_o(func_decl * p, unsigned idx) const { - return m_mux.has_index(p, o_index(idx)); - } - bool is_o(expr* e, unsigned idx) const { - return is_app(e) && is_o(to_app(e)->get_decl(), idx); - } - bool is_o(func_decl * p) const { - unsigned idx; - return m_mux.try_get_index(p, idx) && idx!=n_index(); - } - bool is_o(expr* e) const { - return is_app(e) && is_o(to_app(e)->get_decl()); - } - bool is_n(func_decl * p) const { - return m_mux.has_index(p, n_index()); - } - bool is_n(expr* e) const { - return is_app(e) && is_n(to_app(e)->get_decl()); - } - - /** true if p should not appead in models propagates into child relations */ - bool is_non_model_sym(func_decl * p) const - { return m_mux.is_non_model_sym(p); } - - - /** true if f doesn't contain any n predicates */ - bool is_o_formula(expr * f) const { - return !m_mux.contains(f, n_index()); - } - - /** true if f contains only o state preds of index o_idx */ - bool is_o_formula(expr * f, unsigned o_idx) const { - return m_mux.is_homogenous_formula(f, o_index(o_idx)); - } - /** true if f doesn't contain any o predicates */ - bool is_n_formula(expr * f) const { - return m_mux.is_homogenous_formula(f, n_index()); - } - - func_decl * o2n(func_decl * p, unsigned o_idx) { - return m_mux.conv(p, o_index(o_idx), n_index()); - } - func_decl * o2o(func_decl * p, unsigned src_idx, unsigned tgt_idx) { - return m_mux.conv(p, o_index(src_idx), o_index(tgt_idx)); - } - func_decl * n2o(func_decl * p, unsigned o_idx) { - return m_mux.conv(p, n_index(), o_index(o_idx)); - } - - void formula_o2n(expr * f, expr_ref & result, unsigned o_idx, bool homogenous=true) - { m_mux.conv_formula(f, o_index(o_idx), n_index(), result, homogenous); } - - void formula_n2o(expr * f, expr_ref & result, unsigned o_idx, bool homogenous=true) - { m_mux.conv_formula(f, n_index(), o_index(o_idx), result, homogenous); } - - void formula_n2o(unsigned o_idx, bool homogenous, expr_ref & result) - { m_mux.conv_formula(result.get(), n_index(), o_index(o_idx), result, homogenous); } - - void formula_o2o(expr * src, expr_ref & tgt, unsigned src_idx, unsigned tgt_idx, bool homogenous=true) - { m_mux.conv_formula(src, o_index(src_idx), o_index(tgt_idx), tgt, homogenous); } - - /** - Return true if all state symbols which e contains are of one kind (either "n" or one of "o"). - */ - bool is_homogenous_formula(expr * e) const { - return m_mux.is_homogenous_formula(e); - } - - /** - Collect indices used in expression. - */ - void collect_indices(expr* e, unsigned_vector& indices) const { - m_mux.collect_indices(e, indices); - } - - /** - Collect used variables of each index. - */ - void collect_variables(expr* e, vector >& vars) const { - m_mux.collect_variables(e, vars); - } - - /** - Return true iff both s1 and s2 are either "n" or "o" of the same index. - If one (or both) of them are not state symbol, return false. - */ - bool have_different_state_kinds(func_decl * s1, func_decl * s2) const { - unsigned i1, i2; - return m_mux.try_get_index(s1, i1) && m_mux.try_get_index(s2, i2) && i1!=i2; - } - - /** - Increase indexes of state symbols in formula by dist. - The 'N' index becomes 'O' index with number dist-1. - */ - void formula_shift(expr * src, expr_ref & tgt, unsigned dist) { - SASSERT(n_index()==0); - SASSERT(o_index(0)==1); - m_mux.shift_formula(src, dist, tgt); - } - - void mk_model_into_cube(const expr_ref_vector & mdl, expr_ref & res); - void mk_core_into_cube(const expr_ref_vector & core, expr_ref & res); - void mk_cube_into_lemma(expr * cube, expr_ref & res); - void mk_lemma_into_cube(expr * lemma, expr_ref & res); - - /** - Remove from vec all atoms that do not have an "o" state. - The order of elements in vec may change. - An assumption is that atoms having "o" state of given index - do not have "o" states of other indexes or "n" states. - */ - void filter_o_atoms(expr_ref_vector& vec, unsigned o_idx) const - { m_mux.filter_idx(vec, o_index(o_idx)); } - void filter_n_atoms(expr_ref_vector& vec) const - { m_mux.filter_idx(vec, n_index()); } - - /** - Partition literals into o_lits and others. - */ - void partition_o_atoms(expr_ref_vector const& lits, - expr_ref_vector& o_lits, - expr_ref_vector& other, - unsigned o_idx) const { - m_mux.partition_o_idx(lits, o_lits, other, o_index(o_idx)); - } - - void filter_out_non_model_atoms(expr_ref_vector& vec) const - { m_mux.filter_non_model_lits(vec); } - - bool try_get_state_and_value_from_atom(expr * atom, app *& state, app_ref& value); - bool try_get_state_decl_from_atom(expr * atom, func_decl *& state); - - - std::string pp_model(const model_core & mdl) const - { return m_mux.pp_model(mdl); } - - - void set_background(expr* b) { m_background = b; } - - expr* get_background() const { return m_background; } - - - /** - Return true if we can show that lhs => rhs. The function can have false negatives - (i.e. when smt::context returns unknown), but no false positives. - - bg is background knowledge and can be null - */ - bool implication_surely_holds(expr * lhs, expr * rhs, expr * bg=nullptr); - - unsigned get_unique_num() { return m_next_unique_num++; } - - pdr::smt_context* mk_fresh() { return m_contexts.mk_fresh(); } - - void collect_statistics(statistics& st) const { m_contexts.collect_statistics(st); } - - void reset_statistics() { m_contexts.reset_statistics(); } - }; -} - -#endif diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp deleted file mode 100644 index 8ebc9b9cb..000000000 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - prop_solver.cpp - -Abstract: - - SMT solver abstraction for PDR. - -Author: - - Krystof Hoder (t-khoder) 2011-8-17. - -Revision History: - ---*/ - -#include -#include "model/model.h" -#include "muz/pdr/pdr_util.h" -#include "muz/pdr/pdr_prop_solver.h" -#include "ast/ast_smt2_pp.h" -#include "muz/base/dl_util.h" -#include "model/model_pp.h" -#include "smt/params/smt_params.h" -#include "ast/datatype_decl_plugin.h" -#include "ast/bv_decl_plugin.h" -#include "muz/pdr/pdr_farkas_learner.h" -#include "ast/ast_smt2_pp.h" -#include "ast/rewriter/expr_replacer.h" - -// -// Auxiliary structure to introduce propositional names for assumptions that are not -// propositional. It is to work with the smt::context's restriction -// that assumptions be propositional literals. -// - -namespace pdr { - - class prop_solver::safe_assumptions { - prop_solver& s; - ast_manager& m; - expr_ref_vector m_atoms; - expr_ref_vector m_assumptions; - obj_map m_proxies2expr; - obj_map m_expr2proxies; - unsigned m_num_proxies; - - app * mk_proxy(expr* literal) { - app* res; - SASSERT(!is_var(literal)); //it doesn't make sense to introduce names to variables - if (m_expr2proxies.find(literal, res)) { - return res; - } - SASSERT(s.m_proxies.size() >= m_num_proxies); - if (m_num_proxies == s.m_proxies.size()) { - std::stringstream name; - name << "pdr_proxy_" << s.m_proxies.size(); - res = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); - s.m_proxies.push_back(res); - s.m_aux_symbols.insert(res->get_decl()); - } - else { - res = s.m_proxies[m_num_proxies].get(); - } - ++m_num_proxies; - m_expr2proxies.insert(literal, res); - m_proxies2expr.insert(res, literal); - expr_ref implies(m.mk_or(m.mk_not(res), literal), m); - s.m_ctx->assert_expr(implies); - m_assumptions.push_back(implies); - TRACE("pdr_verbose", tout << "name asserted " << mk_pp(implies, m) << "\n";); - return res; - } - - void mk_safe(expr_ref_vector& conjs) { - flatten_and(conjs); - expand_literals(conjs); - for (unsigned i = 0; i < conjs.size(); ++i) { - expr * lit = conjs[i].get(); - expr * lit_core = lit; - m.is_not(lit, lit_core); - SASSERT(!m.is_true(lit)); - if (!is_uninterp(lit_core) || to_app(lit_core)->get_num_args() != 0) { - conjs[i] = mk_proxy(lit); - } - } - m_assumptions.append(conjs); - } - - expr* apply_accessor( - ptr_vector const& acc, - unsigned j, - func_decl* f, - expr* c) { - if (is_app(c) && to_app(c)->get_decl() == f) { - return to_app(c)->get_arg(j); - } - else { - return m.mk_app(acc[j], c); - } - } - - void expand_literals(expr_ref_vector& conjs) { - arith_util arith(m); - datatype_util dt(m); - bv_util bv(m); - expr* e1, *e2, *c, *val; - rational r; - unsigned bv_size; - - TRACE("pdr", - tout << "begin expand\n"; - for (unsigned i = 0; i < conjs.size(); ++i) { - tout << mk_pp(conjs[i].get(), m) << "\n"; - }); - - for (unsigned i = 0; i < conjs.size(); ++i) { - expr* e = conjs[i].get(); - if (m.is_eq(e, e1, e2) && arith.is_int_real(e1)) { - conjs[i] = arith.mk_le(e1,e2); - if (i+1 == conjs.size()) { - conjs.push_back(arith.mk_ge(e1, e2)); - } - else { - conjs.push_back(conjs[i+1].get()); - conjs[i+1] = arith.mk_ge(e1, e2); - } - ++i; - } - else if ((m.is_eq(e, c, val) && is_app(val) && dt.is_constructor(to_app(val))) || - (m.is_eq(e, val, c) && is_app(val) && dt.is_constructor(to_app(val)))){ - func_decl* f = to_app(val)->get_decl(); - func_decl* r = dt.get_constructor_is(f); - conjs[i] = m.mk_app(r, c); - ptr_vector const& acc = *dt.get_constructor_accessors(f); - for (unsigned j = 0; j < acc.size(); ++j) { - conjs.push_back(m.mk_eq(apply_accessor(acc, j, f, c), to_app(val)->get_arg(j))); - } - } - else if ((m.is_eq(e, c, val) && bv.is_numeral(val, r, bv_size)) || - (m.is_eq(e, val, c) && bv.is_numeral(val, r, bv_size))) { - rational two(2); - for (unsigned j = 0; j < bv_size; ++j) { - parameter p(j); - //expr* e = m.mk_app(bv.get_family_id(), OP_BIT2BOOL, 1, &p, 1, &c); - expr* e = m.mk_eq(m.mk_app(bv.get_family_id(), OP_BIT1), bv.mk_extract(j, j, c)); - if ((r % two).is_zero()) { - e = m.mk_not(e); - } - r = div(r, two); - if (j == 0) { - conjs[i] = e; - } - else { - conjs.push_back(e); - } - } - } - } - TRACE("pdr", - tout << "end expand\n"; - for (unsigned i = 0; i < conjs.size(); ++i) { - tout << mk_pp(conjs[i].get(), m) << "\n"; - }); - } - - public: - safe_assumptions(prop_solver& s, expr_ref_vector const& assumptions): - s(s), m(s.m), m_atoms(assumptions), m_assumptions(m), m_num_proxies(0) { - mk_safe(m_atoms); - } - - ~safe_assumptions() { - } - - expr_ref_vector const& atoms() const { return m_atoms; } - - unsigned assumptions_size() const { return m_assumptions.size(); } - - expr* assumptions(unsigned i) const { return m_assumptions[i]; } - - void undo_proxies(expr_ref_vector& es) { - expr_ref e(m); - expr* r; - for (unsigned i = 0; i < es.size(); ++i) { - e = es[i].get(); - if (is_app(e) && m_proxies2expr.find(to_app(e), r)) { - es[i] = r; - } - } - } - - void elim_proxies(expr_ref_vector& es) { - expr_substitution sub(m, false, m.proofs_enabled()); - proof_ref pr(m); - if (m.proofs_enabled()) { - pr = m.mk_asserted(m.mk_true()); - } - obj_map::iterator it = m_proxies2expr.begin(), end = m_proxies2expr.end(); - for (; it != end; ++it) { - sub.insert(it->m_key, m.mk_true(), pr); - } - scoped_ptr rep = mk_default_expr_replacer(m); - rep->set_substitution(&sub); - replace_proxies(*rep, es); - } - private: - - void replace_proxies(expr_replacer& rep, expr_ref_vector& es) { - expr_ref e(m); - for (unsigned i = 0; i < es.size(); ++i) { - e = es[i].get(); - rep(e); - es[i] = e; - if (m.is_true(e)) { - es[i] = es.back(); - es.pop_back(); - --i; - } - } - } - }; - - - prop_solver::prop_solver(manager& pm, symbol const& name) : - m_fparams(pm.get_fparams()), - m(pm.get_manager()), - m_pm(pm), - m_name(name), - m_ctx(pm.mk_fresh()), - m_pos_level_atoms(m), - m_neg_level_atoms(m), - m_proxies(m), - m_core(nullptr), - m_model(nullptr), - m_consequences(nullptr), - m_subset_based_core(false), - m_use_farkas(false), - m_in_level(false), - m_current_level(0) - { - m_ctx->assert_expr(m_pm.get_background()); - } - - void prop_solver::add_level() { - unsigned idx = level_cnt(); - std::stringstream name; - name << m_name << "#level_" << idx; - func_decl * lev_pred = m.mk_fresh_func_decl(name.str().c_str(), 0, nullptr,m.mk_bool_sort()); - m_aux_symbols.insert(lev_pred); - m_level_preds.push_back(lev_pred); - - app_ref pos_la(m.mk_const(lev_pred), m); - app_ref neg_la(m.mk_not(pos_la.get()), m); - - m_pos_level_atoms.push_back(pos_la); - m_neg_level_atoms.push_back(neg_la); - - m_level_atoms_set.insert(pos_la.get()); - m_level_atoms_set.insert(neg_la.get()); - } - - void prop_solver::ensure_level(unsigned lvl) { - while (lvl>=level_cnt()) { - add_level(); - } - } - - unsigned prop_solver::level_cnt() const { - return m_level_preds.size(); - } - - void prop_solver::push_level_atoms(unsigned level, expr_ref_vector& tgt) const { - unsigned lev_cnt = level_cnt(); - for (unsigned i=0; i=level; - app * lev_atom = active ? m_neg_level_atoms[i] : m_pos_level_atoms[i]; - tgt.push_back(lev_atom); - } - } - - void prop_solver::add_formula(expr * form) { - SASSERT(!m_in_level); - m_ctx->assert_expr(form); - IF_VERBOSE(21, verbose_stream() << "$ asserted " << mk_pp(form, m) << "\n";); - TRACE("pdr", tout << "add_formula: " << mk_pp(form, m) << "\n";); - } - - void prop_solver::add_level_formula(expr * form, unsigned level) { - ensure_level(level); - app * lev_atom = m_pos_level_atoms[level].get(); - app_ref lform(m.mk_or(form, lev_atom), m); - add_formula(lform.get()); - } - - - lbool prop_solver::check_safe_assumptions( - safe_assumptions& safe, - const expr_ref_vector& atoms) - { - flet _model(m_fparams.m_model, m_model != nullptr); - expr_ref_vector expr_atoms(m); - expr_atoms.append(atoms.size(), atoms.c_ptr()); - - if (m_in_level) { - push_level_atoms(m_current_level, expr_atoms); - } - - lbool result = m_ctx->check(expr_atoms); - - TRACE("pdr", - tout << mk_pp(m_pm.mk_and(expr_atoms), m) << "\n"; - tout << result << "\n";); - - if (result == l_true && m_model) { - m_ctx->get_model(*m_model); - TRACE("pdr_verbose", model_pp(tout, **m_model); ); - } - - if (result == l_false) { - unsigned core_size = m_ctx->get_unsat_core_size(); - m_assumes_level = false; - for (unsigned i = 0; i < core_size; ++i) { - if (m_level_atoms_set.contains(m_ctx->get_unsat_core_expr(i))) { - m_assumes_level = true; - break; - } - } - } - - if (result == l_false && - m_core && - m.proofs_enabled() && - m_use_farkas && - !m_subset_based_core) { - extract_theory_core(safe); - } - else if (result == l_false && m_core) { - extract_subset_core(safe); - SASSERT(expr_atoms.size() >= m_core->size()); - } - m_core = nullptr; - m_model = nullptr; - m_subset_based_core = false; - return result; - } - - void prop_solver::extract_subset_core(safe_assumptions& safe) { - unsigned core_size = m_ctx->get_unsat_core_size(); - m_core->reset(); - for (unsigned i = 0; i < core_size; ++i) { - expr * core_expr = m_ctx->get_unsat_core_expr(i); - SASSERT(is_app(core_expr)); - - if (m_level_atoms_set.contains(core_expr)) { - continue; - } - if (m_ctx->is_aux_predicate(core_expr)) { - continue; - } - m_core->push_back(to_app(core_expr)); - } - - safe.undo_proxies(*m_core); - - TRACE("pdr", - tout << "core_exprs: "; - for (unsigned i = 0; i < core_size; ++i) { - tout << mk_pp(m_ctx->get_unsat_core_expr(i), m) << " "; - } - tout << "\n"; - tout << "core: " << mk_pp(m_pm.mk_and(*m_core), m) << "\n"; - ); - } - - - void prop_solver::extract_theory_core(safe_assumptions& safe) { - proof_ref pr(m); - pr = m_ctx->get_proof(); - IF_VERBOSE(21, verbose_stream() << mk_ismt2_pp(pr, m) << "\n";); - farkas_learner fl(m_fparams, m); - expr_ref_vector lemmas(m); - obj_hashtable bs; - for (unsigned i = 0; i < safe.assumptions_size(); ++i) { - bs.insert(safe.assumptions(i)); - } - fl.get_lemmas(pr, bs, lemmas); - safe.elim_proxies(lemmas); - fl.simplify_lemmas(lemmas); // redundant? - - bool outside_of_logic = - (m_fparams.m_arith_mode == AS_DIFF_LOGIC && - !is_difference_logic(m, lemmas.size(), lemmas.c_ptr())) || - (m_fparams.m_arith_mode == AS_UTVPI && - !is_utvpi_logic(m, lemmas.size(), lemmas.c_ptr())); - - if (outside_of_logic) { - IF_VERBOSE(2, - verbose_stream() << "not diff\n"; - for (unsigned i = 0; i < lemmas.size(); ++i) { - verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n"; - }); - extract_subset_core(safe); - } - else { - - IF_VERBOSE(2, - verbose_stream() << "Lemmas\n"; - for (unsigned i = 0; i < lemmas.size(); ++i) { - verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n"; - }); - - m_core->reset(); - m_core->append(lemmas); - - if (m_consequences) { - fl.get_consequences(pr, bs, *m_consequences); - } - } - } - - lbool prop_solver::check_assumptions(const expr_ref_vector & atoms) { - return check_assumptions_and_formula(atoms, m.mk_true()); - } - - lbool prop_solver::check_conjunction_as_assumptions(expr * conj) { - expr_ref_vector asmp(m); - asmp.push_back(conj); - return check_assumptions(asmp); - } - - lbool prop_solver::check_assumptions_and_formula(const expr_ref_vector & atoms, expr * form) - { - pdr::smt_context::scoped _scoped(*m_ctx); - safe_assumptions safe(*this, atoms); - m_ctx->assert_expr(form); - CTRACE("pdr", !m.is_true(form), tout << "check with formula: " << mk_pp(form, m) << "\n";); - lbool res = check_safe_assumptions(safe, safe.atoms()); - - // - // we don't have to undo model naming, as from the model - // we extract the values for state variables directly - // - return res; - } - - void prop_solver::collect_statistics(statistics& st) const { - } - - void prop_solver::reset_statistics() { - } - - - - -} diff --git a/src/muz/pdr/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h deleted file mode 100644 index 463163fbd..000000000 --- a/src/muz/pdr/pdr_prop_solver.h +++ /dev/null @@ -1,139 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - prop_solver.h - -Abstract: - - SAT solver abstraction for PDR. - -Author: - - Krystof Hoder (t-khoder) 2011-8-17. - -Revision History: - ---*/ - -#ifndef PROP_SOLVER_H_ -#define PROP_SOLVER_H_ - -#include -#include -#include -#include "ast/ast.h" -#include "util/obj_hashtable.h" -#include "smt/smt_kernel.h" -#include "util/util.h" -#include "util/vector.h" -#include "muz/pdr/pdr_manager.h" -#include "muz/pdr/pdr_smt_context_manager.h" - - -namespace pdr { - class prop_solver { - - private: - smt_params& m_fparams; - ast_manager& m; - manager& m_pm; - symbol m_name; - scoped_ptr m_ctx; - decl_vector m_level_preds; - app_ref_vector m_pos_level_atoms; // atoms used to identify level - app_ref_vector m_neg_level_atoms; // - obj_hashtable m_level_atoms_set; - app_ref_vector m_proxies; // predicates for assumptions - expr_ref_vector* m_core; - model_ref* m_model; - expr_ref_vector* m_consequences; - bool m_subset_based_core; - bool m_assumes_level; - bool m_use_farkas; - func_decl_set m_aux_symbols; - bool m_in_level; - unsigned m_current_level; // set when m_in_level - - /** Add level atoms activating certain level into a vector */ - void push_level_atoms(unsigned level, expr_ref_vector & tgt) const; - - void ensure_level(unsigned lvl); - - class safe_assumptions; - - void extract_theory_core(safe_assumptions& assumptions); - - void extract_subset_core(safe_assumptions& assumptions); - - lbool check_safe_assumptions( - safe_assumptions& assumptions, - expr_ref_vector const& atoms); - - - public: - prop_solver(pdr::manager& pm, symbol const& name); - - /** return true is s is a symbol introduced by prop_solver */ - bool is_aux_symbol(func_decl * s) const { - return - m_aux_symbols.contains(s) || - m_ctx->is_aux_predicate(s); - } - - void set_core(expr_ref_vector* core) { m_core = core; } - void set_model(model_ref* mdl) { m_model = mdl; } - void set_subset_based_core(bool f) { m_subset_based_core = f; } - void set_consequences(expr_ref_vector* consequences) { m_consequences = consequences; } - - bool assumes_level() const { return m_assumes_level; } - - void add_level(); - unsigned level_cnt() const; - - class scoped_level { - bool& m_lev; - public: - scoped_level(prop_solver& ps, unsigned lvl):m_lev(ps.m_in_level) { - SASSERT(!m_lev); m_lev = true; ps.m_current_level = lvl; - } - ~scoped_level() { m_lev = false; } - }; - - void set_use_farkas(bool f) { m_use_farkas = f; } - bool get_use_farkas() const { return m_use_farkas; } - - void add_formula(expr * form); - void add_level_formula(expr * form, unsigned level); - - /** - * Return true iff conjunction of atoms is consistent with the current state of - * the solver. - * - * If the conjunction of atoms is inconsistent with the solver state and core is non-zero, - * core will contain an unsatisfiable core of atoms. - * - * If the conjunction of atoms is consistent with the solver state and o_model is non-zero, - * o_model will contain the "o" literals true in the assignment. - */ - lbool check_assumptions(const expr_ref_vector & atoms); - - lbool check_conjunction_as_assumptions(expr * conj); - - /** - * Like check_assumptions, except it also asserts an extra formula - */ - lbool check_assumptions_and_formula( - const expr_ref_vector & atoms, - expr * form); - - void collect_statistics(statistics& st) const; - - void reset_statistics(); - - }; -} - - -#endif diff --git a/src/muz/pdr/pdr_reachable_cache.cpp b/src/muz/pdr/pdr_reachable_cache.cpp deleted file mode 100644 index 5d553df4d..000000000 --- a/src/muz/pdr/pdr_reachable_cache.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - reachable_cache.cpp - -Abstract: - - Object for caching of reachable states. - -Author: - - Krystof Hoder (t-khoder) 2011-9-14. - -Revision History: - ---*/ - -#include "muz/pdr/pdr_reachable_cache.h" - -namespace pdr { - - reachable_cache::reachable_cache(pdr::manager & pm, datalog::PDR_CACHE_MODE cm) - : m(pm.get_manager()), - m_pm(pm), - m_ctx(nullptr), - m_ref_holder(m), - m_disj_connector(m), - m_cache_mode(cm) { - if (m_cache_mode == datalog::CONSTRAINT_CACHE) { - m_ctx = pm.mk_fresh(); - m_ctx->assert_expr(m_pm.get_background()); - } - } - - - void reachable_cache::add_disjuncted_formula(expr * f) { - app_ref new_connector(m.mk_fresh_const("disj_conn", m.mk_bool_sort()), m); - app_ref neg_new_connector(m.mk_not(new_connector), m); - app_ref extended_form(m); - - if(m_disj_connector) { - extended_form = m.mk_or(m_disj_connector, neg_new_connector, f); - } - else { - extended_form = m.mk_or(neg_new_connector, f); - } - if (m_ctx) { - m_ctx->assert_expr(extended_form); - } - - m_disj_connector = new_connector; - } - - void reachable_cache::add_reachable(expr * cube) { - - switch (m_cache_mode) { - case datalog::NO_CACHE: - break; - - case datalog::HASH_CACHE: - m_stats.m_inserts++; - m_cache.insert(cube); - m_ref_holder.push_back(cube); - break; - - case datalog::CONSTRAINT_CACHE: - m_stats.m_inserts++; - TRACE("pdr", tout << mk_pp(cube, m) << "\n";); - add_disjuncted_formula(cube); - break; - - default: - UNREACHABLE(); - } - } - - bool reachable_cache::is_reachable(expr * cube) { - bool found = false; - switch (m_cache_mode) { - case datalog::NO_CACHE: - return false; - - case datalog::HASH_CACHE: - found = m_cache.contains(cube); - break; - - case datalog::CONSTRAINT_CACHE: { - if(!m_disj_connector) { - found = false; - break; - } - expr * connector = m_disj_connector.get(); - expr_ref_vector assms(m); - assms.push_back(connector); - m_ctx->push(); - m_ctx->assert_expr(cube); - lbool res = m_ctx->check(assms); - m_ctx->pop(); - - TRACE("pdr", tout << "is_reachable: " << res << " " << mk_pp(cube, m) << "\n";); - - found = res == l_true; - break; - } - - default: - UNREACHABLE(); - break; - } - if (found) { - m_stats.m_hits++; - } - else { - m_stats.m_miss++; - } - return found; - } - - void reachable_cache::collect_statistics(statistics& st) const { - st.update("cache inserts", m_stats.m_inserts); - st.update("cache miss", m_stats.m_miss); - st.update("cache hits", m_stats.m_hits); - } - - void reachable_cache::reset_statistics() { - m_stats.reset(); - } - - -} diff --git a/src/muz/pdr/pdr_reachable_cache.h b/src/muz/pdr/pdr_reachable_cache.h deleted file mode 100644 index 0833541ba..000000000 --- a/src/muz/pdr/pdr_reachable_cache.h +++ /dev/null @@ -1,66 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - reachable_cache.h - -Abstract: - - Object for caching of reachable states. - -Author: - - Krystof Hoder (t-khoder) 2011-9-14. - -Revision History: - ---*/ - - -#ifndef REACHABLE_CACHE_H_ -#define REACHABLE_CACHE_H_ -#include "ast/ast.h" -#include "util/ref_vector.h" -#include "muz/pdr/pdr_manager.h" -#include "muz/pdr/pdr_smt_context_manager.h" - -namespace pdr { - class reachable_cache { - struct stats { - unsigned m_hits; - unsigned m_miss; - unsigned m_inserts; - stats() { reset(); } - void reset() { memset(this, 0, sizeof(*this)); } - }; - - ast_manager & m; - manager & m_pm; - scoped_ptr m_ctx; - ast_ref_vector m_ref_holder; - app_ref m_disj_connector; - obj_hashtable m_cache; - stats m_stats; - datalog::PDR_CACHE_MODE m_cache_mode; - - void add_disjuncted_formula(expr * f); - - public: - reachable_cache(pdr::manager & pm, datalog::PDR_CACHE_MODE cm); - - void add_init(app * f) { add_disjuncted_formula(f); } - - /** add cube whose all models are reachable */ - void add_reachable(expr * cube); - - /** return true if there is a model of cube which is reachable */ - bool is_reachable(expr * cube); - - void collect_statistics(statistics& st) const; - - void reset_statistics(); - }; -} - -#endif diff --git a/src/muz/pdr/pdr_smt_context_manager.cpp b/src/muz/pdr/pdr_smt_context_manager.cpp deleted file mode 100644 index 88734049b..000000000 --- a/src/muz/pdr/pdr_smt_context_manager.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_smt_context_manager.cpp - -Abstract: - - Manager of smt contexts - -Author: - - Nikolaj Bjorner (nbjorner) 2011-11-26. - -Revision History: - ---*/ - -#include "muz/pdr/pdr_smt_context_manager.h" -#include "ast/has_free_vars.h" -#include "ast/ast_pp.h" -#include "ast/ast_smt_pp.h" -#include -#include "smt/params/smt_params.h" - -namespace pdr { - - smt_context::smt_context(smt_context_manager& p, ast_manager& m, app* pred): - m_pred(pred, m), - m_parent(p), - m_in_delay_scope(false), - m_pushed(false) - {} - - bool smt_context::is_aux_predicate(func_decl* p) { - return m_parent.is_aux_predicate(p); - } - - smt_context::scoped::scoped(smt_context& ctx): m_ctx(ctx) { - SASSERT(!m_ctx.m_in_delay_scope); - SASSERT(!m_ctx.m_pushed); - m_ctx.m_in_delay_scope = true; - } - - smt_context::scoped::~scoped() { - SASSERT(m_ctx.m_in_delay_scope); - if (m_ctx.m_pushed) { - m_ctx.pop(); - m_ctx.m_pushed = false; - } - m_ctx.m_in_delay_scope = false; - } - - - _smt_context::_smt_context(smt::kernel & ctx, smt_context_manager& p, app* pred): - smt_context(p, ctx.m(), pred), - m_context(ctx) - {} - - void _smt_context::assert_expr(expr* e) { - ast_manager& m = m_context.m(); - if (m.is_true(e)) { - return; - } - CTRACE("pdr", has_free_vars(e), tout << mk_pp(e, m) << "\n";); - SASSERT(!has_free_vars(e)); - if (m_in_delay_scope && !m_pushed) { - m_context.push(); - m_pushed = true; - } - expr_ref fml(m); - fml = m_pushed?e:m.mk_implies(m_pred, e); - m_context.assert_expr(fml); - } - - lbool _smt_context::check(expr_ref_vector& assumptions) { - ast_manager& m = m_pred.get_manager(); - if (!m.is_true(m_pred)) { - assumptions.push_back(m_pred); - } - TRACE("pdr_check", - { - ast_smt_pp pp(m); - for (unsigned i = 0; i < m_context.size(); ++i) { - pp.add_assumption(m_context.get_formula(i)); - } - for (unsigned i = 0; i < assumptions.size(); ++i) { - pp.add_assumption(assumptions[i].get()); - } - - static unsigned lemma_id = 0; - std::ostringstream strm; - strm << "pdr-lemma-" << lemma_id << ".smt2"; - std::ofstream out(strm.str().c_str()); - pp.display_smt2(out, m.mk_true()); - out.close(); - lemma_id++; - tout << "pdr_check: " << strm.str() << "\n"; - }); - lbool result = m_context.check(assumptions.size(), assumptions.c_ptr()); - if (!m.is_true(m_pred)) { - assumptions.pop_back(); - } - return result; - } - - void _smt_context::get_model(model_ref& model) { - m_context.get_model(model); - } - - proof* _smt_context::get_proof() { - return m_context.get_proof(); - } - - smt_context_manager::smt_context_manager(smt_params& fp, unsigned max_num_contexts, ast_manager& m): - m_fparams(fp), - m(m), - m_max_num_contexts(max_num_contexts), - m_num_contexts(0), - m_predicate_list(m) { - } - - - smt_context_manager::~smt_context_manager() { - TRACE("pdr",tout << "\n";); - std::for_each(m_contexts.begin(), m_contexts.end(), delete_proc()); - } - - smt_context* smt_context_manager::mk_fresh() { - ++m_num_contexts; - app_ref pred(m); - smt::kernel * ctx = nullptr; - if (m_max_num_contexts == 0) { - m_contexts.push_back(alloc(smt::kernel, m, m_fparams)); - pred = m.mk_true(); - ctx = m_contexts[m_num_contexts-1]; - } - else { - if (m_contexts.size() < m_max_num_contexts) { - m_contexts.push_back(alloc(smt::kernel, m, m_fparams)); - } - std::stringstream name; - name << "#context" << m_num_contexts; - pred = m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()); - m_predicate_list.push_back(pred); - m_predicate_set.insert(pred->get_decl()); - ctx = m_contexts[(m_num_contexts-1)%m_max_num_contexts]; - } - return alloc(_smt_context, *ctx, *this, pred); - } - - void smt_context_manager::collect_statistics(statistics& st) const { - for (unsigned i = 0; i < m_contexts.size(); ++i) { - m_contexts[i]->collect_statistics(st); - } - } - - void smt_context_manager::reset_statistics() { - for (unsigned i = 0; i < m_contexts.size(); ++i) { - m_contexts[i]->reset_statistics(); - } - } - - -}; - diff --git a/src/muz/pdr/pdr_smt_context_manager.h b/src/muz/pdr/pdr_smt_context_manager.h deleted file mode 100644 index 747cd6457..000000000 --- a/src/muz/pdr/pdr_smt_context_manager.h +++ /dev/null @@ -1,92 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_smt_context_manager.h - -Abstract: - - Manager of smt contexts - -Author: - - Nikolaj Bjorner (nbjorner) 2011-11-26. - -Revision History: - ---*/ - -#ifndef PDR_SMT_CONTEXT_MANAGER_H_ -#define PDR_SMT_CONTEXT_MANAGER_H_ - -#include "smt/smt_kernel.h" -#include "ast/func_decl_dependencies.h" -#include "muz/base/dl_util.h" - -namespace pdr { - - class smt_context_manager; - - class smt_context { - protected: - app_ref m_pred; - smt_context_manager& m_parent; - bool m_in_delay_scope; - bool m_pushed; - public: - smt_context(smt_context_manager& p, ast_manager& m, app* pred); - virtual ~smt_context() {} - virtual void assert_expr(expr* e) = 0; - virtual lbool check(expr_ref_vector& assumptions) = 0; - virtual void get_model(model_ref& model) = 0; - virtual proof* get_proof() = 0; - virtual unsigned get_unsat_core_size() = 0; - virtual expr* get_unsat_core_expr(unsigned i) = 0; - virtual void push() = 0; - virtual void pop() = 0; - bool is_aux_predicate(func_decl* p); - bool is_aux_predicate(expr* p) { return is_app(p) && is_aux_predicate(to_app(p)->get_decl()); } - class scoped { - smt_context& m_ctx; - public: - scoped(smt_context& ctx); - ~scoped(); - }; - }; - - class _smt_context : public smt_context { - smt::kernel & m_context; - public: - _smt_context(smt::kernel & ctx, smt_context_manager& p, app* pred); - ~_smt_context() override {} - void assert_expr(expr* e) override; - lbool check(expr_ref_vector& assumptions) override; - void get_model(model_ref& model) override; - proof* get_proof() override; - void push() override { m_context.push(); } - void pop() override { m_context.pop(1); } - unsigned get_unsat_core_size() override { return m_context.get_unsat_core_size(); } - expr* get_unsat_core_expr(unsigned i) override { return m_context.get_unsat_core_expr(i); } - }; - - class smt_context_manager { - smt_params& m_fparams; - ast_manager& m; - unsigned m_max_num_contexts; - ptr_vector m_contexts; - unsigned m_num_contexts; - app_ref_vector m_predicate_list; - func_decl_set m_predicate_set; - public: - smt_context_manager(smt_params& fp, unsigned max_num_contexts, ast_manager& m); - ~smt_context_manager(); - smt_context* mk_fresh(); - void collect_statistics(statistics& st) const; - void reset_statistics(); - bool is_aux_predicate(func_decl* p) const { return m_predicate_set.contains(p); } - }; - -}; - -#endif diff --git a/src/muz/pdr/pdr_sym_mux.cpp b/src/muz/pdr/pdr_sym_mux.cpp deleted file mode 100644 index 72549f2d6..000000000 --- a/src/muz/pdr/pdr_sym_mux.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - sym_mux.cpp - -Abstract: - - A symbol multiplexer that helps with having multiple versions of each of a set of symbols. - -Author: - - Krystof Hoder (t-khoder) 2011-9-8. - -Revision History: - ---*/ - -#include -#include "ast/ast_pp.h" -#include "ast/for_each_expr.h" -#include "model/model.h" -#include "ast/rewriter/rewriter.h" -#include "ast/rewriter/rewriter_def.h" -#include "muz/pdr/pdr_util.h" -#include "muz/pdr/pdr_sym_mux.h" - -using namespace pdr; - -sym_mux::sym_mux(ast_manager & m) - : m(m), m_ref_holder(m), - m_next_sym_suffix_idx(0) { - m_suffixes.push_back("_n"); - size_t suf_sz = m_suffixes.size(); - for(unsigned i = 0; i < suf_sz; ++i) { - symbol suff_sym = symbol(m_suffixes[i].c_str()); - m_used_suffixes.insert(suff_sym); - } -} - -std::string sym_mux::get_suffix(unsigned i) { - while(m_suffixes.size() <= i) { - std::string new_suffix; - symbol new_syffix_sym; - do { - std::stringstream stm; - stm<<'_'<0); - while(tuple.size()get_name().str(); - for(unsigned i=0; iget_arity()==arity); - SASSERT(tuple[i]->get_range()==range); - //domain should match as well, but we won't bother checking an array equality - } - else { - std::string name = pre+get_suffix(i); - tuple[i] = m.mk_func_decl(symbol(name.c_str()), arity, domain, range); - } - m_ref_holder.push_back(tuple[i]); - m_sym2idx.insert(tuple[i], i); - m_sym2prim.insert(tuple[i], tuple[0]); - } - - m_prim2all.insert(tuple[0], tuple); - m_prefix2prim.insert(prefix, tuple[0]); - m_prim2prefix.insert(tuple[0], prefix); - m_prim_preds.push_back(tuple[0]); - m_ref_holder.push_back(prefix); -} - -void sym_mux::ensure_tuple_size(func_decl * prim, unsigned sz) { - SASSERT(m_prim2all.contains(prim)); - decl_vector& tuple = m_prim2all.find_core(prim)->get_data().m_value; - SASSERT(tuple[0]==prim); - - if(sz <= tuple.size()) { return; } - - func_decl * prefix; - TRUSTME(m_prim2prefix.find(prim, prefix)); - std::string prefix_name = prefix->get_name().bare_str(); - for(unsigned i = tuple.size(); i < sz; ++i) { - std::string name = prefix_name + get_suffix(i); - func_decl * new_sym = m.mk_func_decl(symbol(name.c_str()), prefix->get_arity(), - prefix->get_domain(), prefix->get_range()); - - tuple.push_back(new_sym); - m_ref_holder.push_back(new_sym); - m_sym2idx.insert(new_sym, i); - m_sym2prim.insert(new_sym, prim); - } -} - -func_decl * sym_mux::conv(func_decl * sym, unsigned src_idx, unsigned tgt_idx) -{ - if(src_idx==tgt_idx) { return sym; } - func_decl * prim = (src_idx==0) ? sym : get_primary(sym); - if(tgt_idx>src_idx) { - ensure_tuple_size(prim, tgt_idx+1); - } - decl_vector & sym_vect = m_prim2all.find_core(prim)->get_data().m_value; - SASSERT(sym_vect[src_idx]==sym); - return sym_vect[tgt_idx]; -} - - -func_decl * sym_mux::get_or_create_symbol_by_prefix(func_decl* prefix, unsigned idx, - unsigned arity, sort * const * domain, sort * range) -{ - func_decl * prim = try_get_primary_by_prefix(prefix); - if(prim) { - SASSERT(prim->get_arity()==arity); - SASSERT(prim->get_range()==range); - //domain should match as well, but we won't bother checking an array equality - - return conv(prim, 0, idx); - } - - decl_vector syms; - create_tuple(prefix, arity, domain, range, idx+1, syms); - return syms[idx]; -} - -bool sym_mux::is_muxed_lit(expr * e, unsigned idx) const -{ - if(!is_app(e)) { return false; } - app * a = to_app(e); - if(m.is_not(a) && is_app(a->get_arg(0))) { - a = to_app(a->get_arg(0)); - } - return is_muxed(a->get_decl()); -} - - -struct sym_mux::formula_checker -{ - formula_checker(const sym_mux & parent, bool all, unsigned idx) : - m_parent(parent), m_all(all), m_idx(idx), - m_found_what_needed(false) - { - } - - void operator()(expr * e) - { - if(m_found_what_needed || !is_app(e)) { return; } - - func_decl * sym = to_app(e)->get_decl(); - unsigned sym_idx; - if(!m_parent.try_get_index(sym, sym_idx)) { return; } - - bool have_idx = sym_idx==m_idx; - - if( m_all ? (!have_idx) : have_idx ) { - m_found_what_needed = true; - } - - } - - bool all_have_idx() const - { - SASSERT(m_all); //we were looking for the queried property - return !m_found_what_needed; - } - - bool some_with_idx() const - { - SASSERT(!m_all); //we were looking for the queried property - return m_found_what_needed; - } - -private: - const sym_mux & m_parent; - bool m_all; - unsigned m_idx; - - /** - If we check whether all muxed symbols are of given index, we look for - counter-examples, checking whether form contains a muxed symbol of an index, - we look for symbol of index m_idx. - */ - bool m_found_what_needed; -}; - -bool sym_mux::contains(expr * e, unsigned idx) const -{ - formula_checker chck(*this, false, idx); - for_each_expr(chck, m_visited, e); - m_visited.reset(); - return chck.some_with_idx(); -} - -bool sym_mux::is_homogenous_formula(expr * e, unsigned idx) const -{ - formula_checker chck(*this, true, idx); - for_each_expr(chck, m_visited, e); - m_visited.reset(); - return chck.all_have_idx(); -} - -bool sym_mux::is_homogenous(const expr_ref_vector & vect, unsigned idx) const -{ - expr * const * begin = vect.c_ptr(); - expr * const * end = begin + vect.size(); - for(expr * const * it = begin; it!=end; it++) { - if(!is_homogenous_formula(*it, idx)) { - return false; - } - } - return true; -} - -class sym_mux::index_collector { - sym_mux const& m_parent; - svector m_indices; -public: - index_collector(sym_mux const& s): - m_parent(s) {} - - void operator()(expr * e) { - if (is_app(e)) { - func_decl * sym = to_app(e)->get_decl(); - unsigned idx; - if (m_parent.try_get_index(sym, idx)) { - SASSERT(idx > 0); - --idx; - if (m_indices.size() <= idx) { - m_indices.resize(idx+1, false); - } - m_indices[idx] = true; - } - } - } - - void extract(unsigned_vector& indices) { - for (unsigned i = 0; i < m_indices.size(); ++i) { - if (m_indices[i]) { - indices.push_back(i); - } - } - } -}; - - - -void sym_mux::collect_indices(expr* e, unsigned_vector& indices) const { - indices.reset(); - index_collector collector(*this); - for_each_expr(collector, m_visited, e); - m_visited.reset(); - collector.extract(indices); -} - -class sym_mux::variable_collector { - sym_mux const& m_parent; - vector >& m_vars; -public: - variable_collector(sym_mux const& s, vector >& vars): - m_parent(s), m_vars(vars) {} - - void operator()(expr * e) { - if (is_app(e)) { - func_decl * sym = to_app(e)->get_decl(); - unsigned idx; - if (m_parent.try_get_index(sym, idx)) { - SASSERT(idx > 0); - --idx; - if (m_vars.size() <= idx) { - m_vars.resize(idx+1, ptr_vector()); - } - m_vars[idx].push_back(to_app(e)); - } - } - } -}; - -void sym_mux::collect_variables(expr* e, vector >& vars) const { - vars.reset(); - variable_collector collector(*this, vars); - for_each_expr(collector, m_visited, e); - m_visited.reset(); -} - -class sym_mux::hmg_checker { - const sym_mux & m_parent; - - bool m_found_idx; - unsigned m_idx; - bool m_multiple_indexes; - -public: - hmg_checker(const sym_mux & parent) : - m_parent(parent), m_found_idx(false), m_multiple_indexes(false) - { - } - - void operator()(expr * e) - { - if(m_multiple_indexes || !is_app(e)) { return; } - - func_decl * sym = to_app(e)->get_decl(); - unsigned sym_idx; - if(!m_parent.try_get_index(sym, sym_idx)) { return; } - - if(!m_found_idx) { - m_found_idx = true; - m_idx = sym_idx; - return; - } - if(m_idx==sym_idx) { return; } - m_multiple_indexes = true; - } - - bool has_multiple_indexes() const - { - return m_multiple_indexes; - } -}; - -bool sym_mux::is_homogenous_formula(expr * e) const { - hmg_checker chck(*this); - for_each_expr(chck, m_visited, e); - m_visited.reset(); - return !chck.has_multiple_indexes(); -} - - -struct sym_mux::conv_rewriter_cfg : public default_rewriter_cfg -{ -private: - ast_manager & m; - sym_mux & m_parent; - unsigned m_from_idx; - unsigned m_to_idx; - bool m_homogenous; -public: - conv_rewriter_cfg(sym_mux & parent, unsigned from_idx, unsigned to_idx, bool homogenous) - : m(parent.get_manager()), - m_parent(parent), - m_from_idx(from_idx), - m_to_idx(to_idx), - m_homogenous(homogenous) {} - - bool get_subst(expr * s, expr * & t, proof * & t_pr) { - if(!is_app(s)) { return false; } - app * a = to_app(s); - func_decl * sym = a->get_decl(); - if(!m_parent.has_index(sym, m_from_idx)) { - (void) m_homogenous; - SASSERT(!m_homogenous || !m_parent.is_muxed(sym)); - return false; - } - func_decl * tgt = m_parent.conv(sym, m_from_idx, m_to_idx); - - t = m.mk_app(tgt, a->get_args()); - return true; - } -}; - -void sym_mux::conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, expr_ref & res, bool homogenous) -{ - if(src_idx==tgt_idx) { - res = f; - return; - } - conv_rewriter_cfg r_cfg(*this, src_idx, tgt_idx, homogenous); - rewriter_tpl rwr(m, false, r_cfg); - rwr(f, res); -} - -struct sym_mux::shifting_rewriter_cfg : public default_rewriter_cfg -{ -private: - ast_manager & m; - sym_mux & m_parent; - int m_shift; -public: - shifting_rewriter_cfg(sym_mux & parent, int shift) - : m(parent.get_manager()), - m_parent(parent), - m_shift(shift) {} - - bool get_subst(expr * s, expr * & t, proof * & t_pr) { - if(!is_app(s)) { return false; } - app * a = to_app(s); - func_decl * sym = a->get_decl(); - - unsigned idx; - if(!m_parent.try_get_index(sym, idx)) { - return false; - } - SASSERT(static_cast(idx)+m_shift>=0); - func_decl * tgt = m_parent.conv(sym, idx, idx+m_shift); - t = m.mk_app(tgt, a->get_args()); - return true; - } -}; - -void sym_mux::shift_formula(expr * f, int dist, expr_ref & res) -{ - if(dist==0) { - res = f; - return; - } - shifting_rewriter_cfg r_cfg(*this, dist); - rewriter_tpl rwr(m, false, r_cfg); - rwr(f, res); -} - -void sym_mux::conv_formula_vector(const expr_ref_vector & vect, unsigned src_idx, unsigned tgt_idx, - expr_ref_vector & res) -{ - res.reset(); - expr * const * begin = vect.c_ptr(); - expr * const * end = begin + vect.size(); - for(expr * const * it = begin; it!=end; it++) { - expr_ref converted(m); - conv_formula(*it, src_idx, tgt_idx, converted); - res.push_back(converted); - } -} - -void sym_mux::filter_idx(expr_ref_vector & vect, unsigned idx) const { - unsigned i = 0; - while (i < vect.size()) { - expr* e = vect[i].get(); - if (contains(e, idx) && is_homogenous_formula(e, idx)) { - i++; - } - else { - // we don't allow mixing states inside vector elements - SASSERT(!contains(e, idx)); - vect[i] = vect.back(); - vect.pop_back(); - } - } -} - -void sym_mux::partition_o_idx( - expr_ref_vector const& lits, - expr_ref_vector& o_lits, - expr_ref_vector& other, unsigned idx) const { - - for (unsigned i = 0; i < lits.size(); ++i) { - if (contains(lits[i], idx) && is_homogenous_formula(lits[i], idx)) { - o_lits.push_back(lits[i]); - } - else { - other.push_back(lits[i]); - } - } -} - - - -class sym_mux::nonmodel_sym_checker { - const sym_mux & m_parent; - - bool m_found; -public: - nonmodel_sym_checker(const sym_mux & parent) : - m_parent(parent), m_found(false) { - } - - void operator()(expr * e) { - if(m_found || !is_app(e)) { return; } - - func_decl * sym = to_app(e)->get_decl(); - - if(m_parent.is_non_model_sym(sym)) { - m_found = true; - } - } - - bool found() const { - return m_found; - } -}; - -bool sym_mux::has_nonmodel_symbol(expr * e) const { - nonmodel_sym_checker chck(*this); - for_each_expr(chck, e); - return chck.found(); -} - -void sym_mux::filter_non_model_lits(expr_ref_vector & vect) const { - unsigned i = 0; - while (i < vect.size()) { - if (!has_nonmodel_symbol(vect[i].get())) { - i++; - } - else { - vect[i] = vect.back(); - vect.pop_back(); - } - } -} - -class sym_mux::decl_idx_comparator -{ - const sym_mux & m_parent; -public: - decl_idx_comparator(const sym_mux & parent) - : m_parent(parent) - { } - - bool operator()(func_decl * sym1, func_decl * sym2) - { - unsigned idx1, idx2; - if (!m_parent.try_get_index(sym1, idx1)) { idx1 = UINT_MAX; } - if (!m_parent.try_get_index(sym2, idx2)) { idx2 = UINT_MAX; } - - if (idx1 != idx2) { return idx1get_name(), sym2->get_name()); - } -}; - -std::string sym_mux::pp_model(const model_core & mdl) const { - decl_vector consts; - unsigned sz = mdl.get_num_constants(); - for (unsigned i = 0; i < sz; i++) { - func_decl * d = mdl.get_constant(i); - consts.push_back(d); - } - - std::sort(consts.begin(), consts.end(), decl_idx_comparator(*this)); - - std::stringstream res; - - decl_vector::iterator end = consts.end(); - for (decl_vector::iterator it = consts.begin(); it!=end; it++) { - func_decl * d = *it; - std::string name = d->get_name().str(); - const char * arrow = " -> "; - res << name << arrow; - unsigned indent = static_cast(name.length() + strlen(arrow)); - res << mk_pp(mdl.get_const_interp(d), m, indent) << "\n"; - - if (it+1 != end) { - unsigned idx1, idx2; - if (!try_get_index(*it, idx1)) { idx1 = UINT_MAX; } - if (!try_get_index(*(it+1), idx2)) { idx2 = UINT_MAX; } - if (idx1 != idx2) { res << "\n"; } - } - } - return res.str(); -} - - -#if 0 - -class sym_mux::index_renamer_cfg : public default_rewriter_cfg{ - const sym_mux & m_parent; - unsigned m_idx; - -public: - index_renamer_cfg(const sym_mux & p, unsigned idx) : m_parent(p), m_idx(idx) {} - - bool get_subst(expr * s, expr * & t, proof * & t_pr) { - if (!is_app(s)) return false; - app * a = to_app(s); - if (a->get_family_id() != null_family_id) { - return false; - } - func_decl * sym = a->get_decl(); - unsigned idx; - if(!m_parent.try_get_index(sym, idx)) { - return false; - } - if (m_idx == idx) { - return false; - } - ast_manager& m = m_parent.get_manager(); - symbol name = symbol((sym->get_name().str() + "!").c_str()); - func_decl * tgt = m.mk_func_decl(name, sym->get_arity(), sym->get_domain(), sym->get_range()); - t = m.mk_app(tgt, a->get_num_args(), a->get_args()); - return true; - } -}; - -#endif diff --git a/src/muz/pdr/pdr_sym_mux.h b/src/muz/pdr/pdr_sym_mux.h deleted file mode 100644 index 64a2878a9..000000000 --- a/src/muz/pdr/pdr_sym_mux.h +++ /dev/null @@ -1,247 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - sym_mux.h - -Abstract: - - A symbol multiplexer that helps with having multiple versions of each of a set of symbols. - -Author: - - Krystof Hoder (t-khoder) 2011-9-8. - -Revision History: - ---*/ - -#ifndef SYM_MUX_H_ -#define SYM_MUX_H_ - -#include "ast/ast.h" -#include "util/map.h" -#include "util/vector.h" -#include - -class model_core; - -namespace pdr { -class sym_mux -{ -public: - typedef ptr_vector app_vector; - typedef ptr_vector decl_vector; -private: - typedef obj_map sym2u; - typedef obj_map sym2dv; - typedef obj_map sym2sym; - typedef obj_map sym2pred; - typedef hashtable symbols; - - ast_manager & m; - mutable ast_ref_vector m_ref_holder; - mutable expr_mark m_visited; - - mutable unsigned m_next_sym_suffix_idx; - mutable symbols m_used_suffixes; - /** Here we have default suffixes for each of the variants */ - std::vector m_suffixes; - - - /** - Primary symbol is the 0-th variant. This member maps from primary symbol - to vector of all its variants (including the primary variant). - */ - sym2dv m_prim2all; - - /** - For each symbol contains its variant index - */ - mutable sym2u m_sym2idx; - /** - For each symbol contains its primary variant - */ - mutable sym2sym m_sym2prim; - - /** - Maps prefixes passed to the create_tuple to - the primary symbol created from it. - */ - sym2pred m_prefix2prim; - - /** - Maps pripary symbols to prefixes that were used to create them. - */ - sym2sym m_prim2prefix; - - decl_vector m_prim_preds; - - obj_hashtable m_non_model_syms; - - struct formula_checker; - struct conv_rewriter_cfg; - struct shifting_rewriter_cfg; - class decl_idx_comparator; - class hmg_checker; - class nonmodel_sym_checker; - class index_renamer_cfg; - class index_collector; - class variable_collector; - - std::string get_suffix(unsigned i); - void ensure_tuple_size(func_decl * prim, unsigned sz); - -public: - sym_mux(ast_manager & m); - - ast_manager & get_manager() const { return m; } - - bool is_muxed(func_decl * sym) const { return m_sym2idx.contains(sym); } - - bool try_get_index(func_decl * sym, unsigned & idx) const { - return m_sym2idx.find(sym,idx); - } - - bool has_index(func_decl * sym, unsigned idx) const { - unsigned actual_idx; - return try_get_index(sym, actual_idx) && idx==actual_idx; - } - - /** Return primary symbol. sym must be muxed. */ - func_decl * get_primary(func_decl * sym) const { - func_decl * prim; - TRUSTME(m_sym2prim.find(sym, prim)); - return prim; - } - - /** - Return primary symbol created from prefix, or 0 if the prefix was never used. - */ - func_decl * try_get_primary_by_prefix(func_decl* prefix) const { - func_decl * res; - if(!m_prefix2prim.find(prefix, res)) { - return nullptr; - } - return res; - } - - /** - Return symbol created from prefix, or 0 if the prefix was never used. - */ - func_decl * try_get_by_prefix(func_decl* prefix, unsigned idx) { - func_decl * prim = try_get_primary_by_prefix(prefix); - if(!prim) { - return nullptr; - } - return conv(prim, 0, idx); - } - - /** - Marks symbol as non-model which means it will not appear in models collected by - get_muxed_cube_from_model function. - This is to take care of auxiliary symbols introduced by the disjunction relations - to relativize lemmas coming from disjuncts. - */ - void mark_as_non_model(func_decl * sym) { - SASSERT(is_muxed(sym)); - m_non_model_syms.insert(get_primary(sym)); - } - - func_decl * get_or_create_symbol_by_prefix(func_decl* prefix, unsigned idx, - unsigned arity, sort * const * domain, sort * range); - - - - bool is_muxed_lit(expr * e, unsigned idx) const; - - bool is_non_model_sym(func_decl * s) const { - return is_muxed(s) && m_non_model_syms.contains(get_primary(s)); - } - - /** - Create a multiplexed tuple of propositional constants. - Symbols may be suplied in the tuple vector, - those beyond the size of the array and those with corresponding positions - assigned to zero will be created using prefix. - Tuple length must be at least one. - */ - void create_tuple(func_decl* prefix, unsigned arity, sort * const * domain, sort * range, - unsigned tuple_length, decl_vector & tuple); - - /** - Return true if the only multiplexed symbols which e contains are of index idx. - */ - bool is_homogenous_formula(expr * e, unsigned idx) const; - bool is_homogenous(const expr_ref_vector & vect, unsigned idx) const; - - /** - Return true if all multiplexed symbols which e contains are of one index. - */ - bool is_homogenous_formula(expr * e) const; - - /** - Return true if expression e contains a muxed symbol of index idx. - */ - bool contains(expr * e, unsigned idx) const; - - /** - Collect indices used in expression. - */ - void collect_indices(expr* e, unsigned_vector& indices) const; - - /** - Collect used variables of each index. - */ - void collect_variables(expr* e, vector >& vars) const; - - /** - Convert symbol sym which has to be of src_idx variant into variant tgt_idx. - */ - func_decl * conv(func_decl * sym, unsigned src_idx, unsigned tgt_idx); - - - /** - Convert src_idx symbols in formula f variant into tgt_idx. - If homogenous is true, formula cannot contain symbols of other variants. - */ - void conv_formula(expr * f, unsigned src_idx, unsigned tgt_idx, expr_ref & res, bool homogenous=true); - void conv_formula_vector(const expr_ref_vector & vect, unsigned src_idx, unsigned tgt_idx, - expr_ref_vector & res); - - /** - Shifts the muxed symbols in f by dist. Dist can be negative, but it should never shift - symbol index to a negative value. - */ - void shift_formula(expr * f, int dist, expr_ref & res); - - /** - Remove from vect literals (atoms or negations of atoms) of symbols - that contain multiplexed symbols with indexes other than idx. - - Each of the literals can contain only symbols multiplexed with one index - (this trivially holds if the literals are propositional). - - Order of elements in vect may be modified by this function - */ - void filter_idx(expr_ref_vector & vect, unsigned idx) const; - - /** - Partition literals into o_literals and others. - */ - void partition_o_idx(expr_ref_vector const& lits, - expr_ref_vector& o_lits, - expr_ref_vector& other, unsigned idx) const; - - bool has_nonmodel_symbol(expr * e) const; - void filter_non_model_lits(expr_ref_vector & vect) const; - - func_decl * const * begin_prim_preds() const { return m_prim_preds.begin(); } - func_decl * const * end_prim_preds() const { return m_prim_preds.end(); } - - std::string pp_model(const model_core & mdl) const; -}; -} - -#endif diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp deleted file mode 100644 index ad75ae799..000000000 --- a/src/muz/pdr/pdr_util.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_util.cpp - -Abstract: - - Utility functions for PDR. - -Author: - - Krystof Hoder (t-khoder) 2011-8-19. - -Revision History: - - -Notes: - - ---*/ - -#include -#include "util/util.h" -#include "util/ref_vector.h" -#include "ast/array_decl_plugin.h" -#include "ast/ast_pp.h" -#include "ast/for_each_expr.h" -#include "ast/scoped_proof.h" -#include "ast/arith_decl_plugin.h" -#include "ast/rewriter/expr_replacer.h" -#include "ast/rewriter/bool_rewriter.h" -#include "ast/rewriter/poly_rewriter.h" -#include "ast/rewriter/poly_rewriter_def.h" -#include "ast/rewriter/arith_rewriter.h" -#include "ast/rewriter/rewriter.h" -#include "ast/rewriter/rewriter_def.h" -#include "smt/params/smt_params.h" -#include "model/model.h" -#include "muz/base/dl_util.h" -#include "muz/pdr/pdr_manager.h" -#include "muz/pdr/pdr_util.h" -#include "model/model_smt2_pp.h" - - - -namespace pdr { - - unsigned ceil_log2(unsigned u) { - if (u == 0) { return 0; } - unsigned pow2 = next_power_of_two(u); - return get_num_1bits(pow2-1); - } - - std::string pp_cube(const ptr_vector& model, ast_manager& m) { - return pp_cube(model.size(), model.c_ptr(), m); - } - - std::string pp_cube(const expr_ref_vector& model, ast_manager& m) { - return pp_cube(model.size(), model.c_ptr(), m); - } - - std::string pp_cube(const app_ref_vector& model, ast_manager& m) { - return pp_cube(model.size(), model.c_ptr(), m); - } - - std::string pp_cube(const app_vector& model, ast_manager& m) { - return pp_cube(model.size(), model.c_ptr(), m); - } - - std::string pp_cube(unsigned sz, app * const * lits, ast_manager& m) { - return pp_cube(sz, (expr * const *)(lits), m); - } - - std::string pp_cube(unsigned sz, expr * const * lits, ast_manager& m) { - std::stringstream res; - res << "("; - expr * const * end = lits+sz; - for (expr * const * it = lits; it!=end; it++) { - res << mk_pp(*it, m); - if (it+1!=end) { - res << ", "; - } - } - res << ")"; - return res.str(); - } - - void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { - ast_manager& m = fml.get_manager(); - expr_ref_vector conjs(m); - flatten_and(fml, conjs); - obj_map diseqs; - expr* n, *lhs, *rhs; - for (unsigned i = 0; i < conjs.size(); ++i) { - if (m.is_not(conjs[i].get(), n) && - m.is_eq(n, lhs, rhs)) { - if (!m.is_value(rhs)) { - std::swap(lhs, rhs); - } - if (!m.is_value(rhs)) { - continue; - } - diseqs.insert_if_not_there2(lhs, 0)->get_data().m_value++; - } - } - expr_substitution sub(m); - - unsigned orig_size = conjs.size(); - unsigned num_deleted = 0; - expr_ref val(m), tmp(m); - proof_ref pr(m); - pr = m.mk_asserted(m.mk_true()); - obj_map::iterator it = diseqs.begin(); - obj_map::iterator end = diseqs.end(); - for (; it != end; ++it) { - if (it->m_value >= threshold) { - model.eval(it->m_key, val); - sub.insert(it->m_key, val, pr); - conjs.push_back(m.mk_eq(it->m_key, val)); - num_deleted += it->m_value; - } - } - if (orig_size < conjs.size()) { - scoped_ptr rep = mk_expr_simp_replacer(m); - rep->set_substitution(&sub); - for (unsigned i = 0; i < orig_size; ++i) { - tmp = conjs[i].get(); - (*rep)(tmp); - if (m.is_true(tmp)) { - conjs[i] = conjs.back(); - SASSERT(orig_size <= conjs.size()); - conjs.pop_back(); - SASSERT(orig_size <= 1 + conjs.size()); - if (i + 1 == orig_size) { - // no-op. - } - else if (orig_size <= conjs.size()) { - // no-op - } - else { - SASSERT(orig_size == 1 + conjs.size()); - --orig_size; - --i; - } - } - else { - conjs[i] = tmp; - } - } - IF_VERBOSE(2, verbose_stream() << "Deleted " << num_deleted << " disequalities " << conjs.size() << " conjuncts\n";); - } - fml = m.mk_and(conjs.size(), conjs.c_ptr()); - } - - class test_diff_logic { - ast_manager& m; - arith_util a; - bv_util bv; - bool m_is_dl; - bool m_test_for_utvpi; - - bool is_numeric(expr* e) const { - if (a.is_numeral(e)) { - return true; - } - expr* cond, *th, *el; - if (m.is_ite(e, cond, th, el)) { - return is_numeric(th) && is_numeric(el); - } - return false; - } - - bool is_arith_expr(expr *e) const { - return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); - } - - bool is_offset(expr* e) const { - if (a.is_numeral(e)) { - return true; - } - expr* cond, *th, *el, *e1, *e2; - if (m.is_ite(e, cond, th, el)) { - return is_offset(th) && is_offset(el); - } - // recognize offsets. - if (a.is_add(e, e1, e2)) { - if (is_numeric(e1)) { - return is_offset(e2); - } - if (is_numeric(e2)) { - return is_offset(e1); - } - return false; - } - if (m_test_for_utvpi) { - if (a.is_mul(e, e1, e2)) { - if (is_minus_one(e1)) { - return is_offset(e2); - } - if (is_minus_one(e2)) { - return is_offset(e1); - } - } - } - return !is_arith_expr(e); - } - - bool is_minus_one(expr const * e) const { - rational r; return a.is_numeral(e, r) && r.is_minus_one(); - } - - bool test_ineq(expr* e) const { - SASSERT(a.is_le(e) || a.is_ge(e) || m.is_eq(e)); - SASSERT(to_app(e)->get_num_args() == 2); - expr * lhs = to_app(e)->get_arg(0); - expr * rhs = to_app(e)->get_arg(1); - if (is_offset(lhs) && is_offset(rhs)) - return true; - if (!is_numeric(rhs)) - std::swap(lhs, rhs); - if (!is_numeric(rhs)) - return false; - // lhs can be 'x' or '(+ x (* -1 y))' - if (is_offset(lhs)) - return true; - expr* arg1, *arg2; - if (!a.is_add(lhs, arg1, arg2)) - return false; - // x - if (m_test_for_utvpi) { - return is_offset(arg1) && is_offset(arg2); - } - if (is_arith_expr(arg1)) - std::swap(arg1, arg2); - if (is_arith_expr(arg1)) - return false; - // arg2: (* -1 y) - expr* m1, *m2; - if (!a.is_mul(arg2, m1, m2)) - return false; - return is_minus_one(m1) && is_offset(m2); - } - - bool test_eq(expr* e) const { - expr* lhs = nullptr, *rhs = nullptr; - VERIFY(m.is_eq(e, lhs, rhs)); - if (!a.is_int_real(lhs)) { - return true; - } - if (a.is_numeral(lhs) || a.is_numeral(rhs)) { - return test_ineq(e); - } - return - test_term(lhs) && - test_term(rhs) && - !a.is_mul(lhs) && - !a.is_mul(rhs); - } - - bool test_term(expr* e) const { - if (m.is_bool(e)) { - return true; - } - if (a.is_numeral(e)) { - return true; - } - if (is_offset(e)) { - return true; - } - expr* lhs, *rhs; - if (a.is_add(e, lhs, rhs)) { - if (!a.is_numeral(lhs)) { - std::swap(lhs, rhs); - } - return a.is_numeral(lhs) && is_offset(rhs); - } - if (a.is_mul(e, lhs, rhs)) { - return is_minus_one(lhs) || is_minus_one(rhs); - } - return false; - } - - bool is_non_arith_or_basic(expr* e) { - if (!is_app(e)) { - return false; - } - family_id fid = to_app(e)->get_family_id(); - - if (fid == null_family_id && - !m.is_bool(e) && - to_app(e)->get_num_args() > 0) { - return true; - } - return - fid != m.get_basic_family_id() && - fid != null_family_id && - fid != a.get_family_id() && - fid != bv.get_family_id(); - } - - public: - test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} - - void test_for_utvpi() { m_test_for_utvpi = true; } - - void operator()(expr* e) { - if (!m_is_dl) { - return; - } - if (a.is_le(e) || a.is_ge(e)) { - m_is_dl = test_ineq(e); - } - else if (m.is_eq(e)) { - m_is_dl = test_eq(e); - } - else if (is_non_arith_or_basic(e)) { - m_is_dl = false; - } - else if (is_app(e)) { - app* a = to_app(e); - for (unsigned i = 0; m_is_dl && i < a->get_num_args(); ++i) { - m_is_dl = test_term(a->get_arg(i)); - } - } - - if (!m_is_dl) { - char const* msg = "non-diff: "; - if (m_test_for_utvpi) { - msg = "non-utvpi: "; - } - IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); - } - } - - bool is_dl() const { return m_is_dl; } - }; - - bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { - test_diff_logic test(m); - expr_fast_mark1 mark; - for (unsigned i = 0; i < num_fmls; ++i) { - quick_for_each_expr(test, mark, fmls[i]); - } - return test.is_dl(); - } - - bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { - test_diff_logic test(m); - test.test_for_utvpi(); - expr_fast_mark1 mark; - for (unsigned i = 0; i < num_fmls; ++i) { - quick_for_each_expr(test, mark, fmls[i]); - } - return test.is_dl(); - } - - class arith_normalizer : public poly_rewriter { - ast_manager& m; - arith_util m_util; - enum op_kind { LE, GE, EQ }; - public: - arith_normalizer(ast_manager& m, params_ref const& p = params_ref()): poly_rewriter(m, p), m(m), m_util(m) {} - - br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { - br_status st = BR_FAILED; - if (m.is_eq(f)) { - SASSERT(num_args == 2); return mk_eq_core(args[0], args[1], result); - } - - if (f->get_family_id() != get_fid()) { - return st; - } - switch (f->get_decl_kind()) { - case OP_NUM: st = BR_FAILED; break; - case OP_IRRATIONAL_ALGEBRAIC_NUM: st = BR_FAILED; break; - case OP_LE: SASSERT(num_args == 2); st = mk_le_core(args[0], args[1], result); break; - case OP_GE: SASSERT(num_args == 2); st = mk_ge_core(args[0], args[1], result); break; - case OP_LT: SASSERT(num_args == 2); st = mk_lt_core(args[0], args[1], result); break; - case OP_GT: SASSERT(num_args == 2); st = mk_gt_core(args[0], args[1], result); break; - default: st = BR_FAILED; break; - } - return st; - } - - private: - - br_status mk_eq_core(expr* arg1, expr* arg2, expr_ref& result) { - return mk_le_ge_eq_core(arg1, arg2, EQ, result); - } - br_status mk_le_core(expr* arg1, expr* arg2, expr_ref& result) { - return mk_le_ge_eq_core(arg1, arg2, LE, result); - } - br_status mk_ge_core(expr* arg1, expr* arg2, expr_ref& result) { - return mk_le_ge_eq_core(arg1, arg2, GE, result); - } - br_status mk_lt_core(expr* arg1, expr* arg2, expr_ref& result) { - result = m.mk_not(m_util.mk_ge(arg1, arg2)); - return BR_REWRITE2; - } - br_status mk_gt_core(expr* arg1, expr* arg2, expr_ref& result) { - result = m.mk_not(m_util.mk_le(arg1, arg2)); - return BR_REWRITE2; - } - - br_status mk_le_ge_eq_core(expr* arg1, expr* arg2, op_kind kind, expr_ref& result) { - if (m_util.is_real(arg1)) { - numeral g(0); - get_coeffs(arg1, g); - get_coeffs(arg2, g); - if (!g.is_one() && !g.is_zero()) { - SASSERT(g.is_pos()); - expr_ref new_arg1 = rdiv_polynomial(arg1, g); - expr_ref new_arg2 = rdiv_polynomial(arg2, g); - switch(kind) { - case LE: result = m_util.mk_le(new_arg1, new_arg2); return BR_DONE; - case GE: result = m_util.mk_ge(new_arg1, new_arg2); return BR_DONE; - case EQ: result = m_util.mk_eq(new_arg1, new_arg2); return BR_DONE; - } - } - } - return BR_FAILED; - } - - void update_coeff(numeral const& r, numeral& g) { - if (g.is_zero() || abs(r) < g) { - g = abs(r); - } - } - - void get_coeffs(expr* e, numeral& g) { - rational r; - unsigned sz; - expr* const* args = get_monomials(e, sz); - for (unsigned i = 0; i < sz; ++i) { - expr* arg = args[i]; - if (!m_util.is_numeral(arg, r)) { - get_power_product(arg, r); - } - update_coeff(r, g); - } - } - - expr_ref rdiv_polynomial(expr* e, numeral const& g) { - rational r; - SASSERT(g.is_pos()); - SASSERT(!g.is_one()); - expr_ref_vector monomes(m); - unsigned sz; - expr* const* args = get_monomials(e, sz); - for (unsigned i = 0; i < sz; ++i) { - expr* arg = args[i]; - if (m_util.is_numeral(arg, r)) { - monomes.push_back(m_util.mk_numeral(r/g, false)); - } - else { - expr* p = get_power_product(arg, r); - r /= g; - if (r.is_one()) { - monomes.push_back(p); - } - else { - monomes.push_back(m_util.mk_mul(m_util.mk_numeral(r, false), p)); - } - } - } - expr_ref result(m); - mk_add(monomes.size(), monomes.c_ptr(), result); - return result; - } - - }; - - - struct arith_normalizer_cfg: public default_rewriter_cfg { - arith_normalizer m_r; - bool rewrite_patterns() const { return false; } - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - return m_r.mk_app_core(f, num, args, result); - } - arith_normalizer_cfg(ast_manager & m, params_ref const & p):m_r(m,p) {} - }; - - class arith_normalizer_star : public rewriter_tpl { - arith_normalizer_cfg m_cfg; - public: - arith_normalizer_star(ast_manager & m, params_ref const & p): - rewriter_tpl(m, false, m_cfg), - m_cfg(m, p) {} - }; - - - void normalize_arithmetic(expr_ref& t) { - ast_manager& m = t.get_manager(); - scoped_no_proof _sp(m); - params_ref p; - arith_normalizer_star rw(m, p); - expr_ref tmp(m); - rw(t, tmp); - t = tmp; - } - -} - -template class rewriter_tpl; - - diff --git a/src/muz/pdr/pdr_util.h b/src/muz/pdr/pdr_util.h deleted file mode 100644 index 51f6978ec..000000000 --- a/src/muz/pdr/pdr_util.h +++ /dev/null @@ -1,81 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - pdr_util.h - -Abstract: - - Utility functions for PDR. - -Author: - - Krystof Hoder (t-khoder) 2011-8-19. - -Revision History: - ---*/ - -#ifndef PDR_UTIL_H_ -#define PDR_UTIL_H_ - -#include "ast/ast.h" -#include "ast/ast_pp.h" -#include "ast/ast_util.h" -#include "util/obj_hashtable.h" -#include "util/ref_vector.h" -#include "util/trace.h" -#include "util/vector.h" -#include "ast/arith_decl_plugin.h" -#include "ast/array_decl_plugin.h" -#include "ast/bv_decl_plugin.h" - - -class model; -class model_core; - -namespace pdr { - - /** - * Return the ceiling of base 2 logarithm of a number, - * or zero if the nmber is zero. - */ - unsigned ceil_log2(unsigned u); - - typedef ptr_vector app_vector; - typedef ptr_vector decl_vector; - typedef obj_hashtable func_decl_set; - - std::string pp_cube(const ptr_vector& model, ast_manager& manager); - std::string pp_cube(const expr_ref_vector& model, ast_manager& manager); - std::string pp_cube(const ptr_vector& model, ast_manager& manager); - std::string pp_cube(const app_ref_vector& model, ast_manager& manager); - std::string pp_cube(unsigned sz, app * const * lits, ast_manager& manager); - std::string pp_cube(unsigned sz, expr * const * lits, ast_manager& manager); - - - /** - \brief replace variables that are used in many disequalities by - an equality using the model. - - Assumption: the model satisfies the conjunctions. - */ - void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml); - - /** - \brief normalize coefficients in polynomials so that least coefficient is 1. - */ - void normalize_arithmetic(expr_ref& t); - - - /** - \brief determine if formulas belong to difference logic or UTVPI fragment. - */ - bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); - - bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); - -} - -#endif From 4b2196f114b4db60fbd48fb3f389e324c1e5667f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jun 2018 16:28:07 -0700 Subject: [PATCH 1151/1283] nits Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_unsat_core_learner.cpp | 3 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 82 +++++++---------- src/muz/spacer/spacer_unsat_core_plugin.h | 96 ++++++++------------ 3 files changed, 73 insertions(+), 108 deletions(-) diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index 5b3420800..da0d6ec34 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -44,8 +44,7 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { if (m.get_num_parents(currentNode) > 0) { bool need_to_mark_closed = true; - for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) { - proof* premise = m.get_parent(currentNode, i); + for (proof* premise : m.get_parents(currentNode)) { need_to_mark_closed &= (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise)); } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 25b12cf25..eff05762b 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -37,8 +37,6 @@ namespace spacer { unsat_core_plugin::unsat_core_plugin(unsat_core_learner& learner): m(learner.m), m_learner(learner) {}; - - void unsat_core_plugin_lemma::compute_partial_core(proof* step) { SASSERT(m_learner.m_pr.is_a_marked(step)); SASSERT(m_learner.m_pr.is_b_marked(step)); @@ -103,12 +101,10 @@ namespace spacer { func_decl* d = step->get_decl(); symbol sym; if (!m_learner.is_closed(step) && // if step is not already interpolated - step->get_decl_kind() == PR_TH_LEMMA && // and step is a Farkas lemma - d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas" && - d->get_num_parameters() >= m.get_num_parents(step) + 2) { // the following parameters are the Farkas coefficients + is_farkas_lemma(m, step)) { + // weaker check: d->get_num_parameters() >= m.get_num_parents(step) + 2 + SASSERT(d->get_num_parameters() == m.get_num_parents(step) + 2); SASSERT(m.has_fact(step)); coeff_lits_t coeff_lits; @@ -142,12 +138,10 @@ namespace spacer { STRACE("spacer.farkas", verbose_stream() << "Farkas input: "<< "\n"; for (unsigned i = 0; i < m.get_num_parents(step); ++i) { - proof * prem = m.get_parent(step, i); - - rational coef = params[i].get_rational(); - + proof * prem = m.get_parent(step, i); + rational coef = params[i].get_rational(); bool b_pure = m_learner.m_pr.is_b_pure (prem); - verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m_learner.m) << "\n"; + verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; } ); @@ -197,11 +191,11 @@ namespace spacer { } SASSERT(m.get_num_parents(step) + 2 + num_args == d->get_num_parameters()); - bool_rewriter brw(m_learner.m); + bool_rewriter brw(m); for (unsigned i = 0; i < num_args; ++i) { expr* premise = args[i]; - expr_ref negatedPremise(m_learner.m); + expr_ref negatedPremise(m); brw.mk_not(premise, negatedPremise); pinned.push_back(negatedPremise); rational coefficient = params[i].get_rational(); @@ -235,8 +229,7 @@ namespace spacer { return util.get(); } else { - expr_ref negated_linear_combination = util.get(); - return expr_ref(mk_not(m, negated_linear_combination), m); + return expr_ref(mk_not(m, util.get()), m); } } @@ -248,15 +241,11 @@ namespace spacer { func_decl* d = step->get_decl(); symbol sym; if(!m_learner.is_closed(step) && // if step is not already interpolated - step->get_decl_kind() == PR_TH_LEMMA && // and step is a Farkas lemma - d->get_num_parameters() >= 2 && // the Farkas coefficients are saved in the parameters of step - d->get_parameter(0).is_symbol(sym) && sym == "arith" && // the first two parameters are "arith", "farkas", - d->get_parameter(1).is_symbol(sym) && sym == "farkas" && - d->get_num_parameters() >= m.get_num_parents(step) + 2) // the following parameters are the Farkas coefficients - { + is_farkas_lemma(m, step)) { + SASSERT(d->get_num_parameters() == m.get_num_parents(step) + 2); SASSERT(m.has_fact(step)); - vector > linear_combination; // collects all summands of the linear combination + coeff_lits_t linear_combination; // collects all summands of the linear combination parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient @@ -264,9 +253,7 @@ namespace spacer { verbose_stream() << "Farkas input: "<< "\n"; for (unsigned i = 0; i < m.get_num_parents(step); ++i) { proof * prem = m.get_parent(step, i); - - rational coef = params[i].get_rational(); - + rational coef = params[i].get_rational(); bool b_pure = m_learner.m_pr.is_b_pure (prem); verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m_learner.m) << "\n"; } @@ -284,8 +271,7 @@ namespace spacer { { rational coefficient = params[i].get_rational(); linear_combination.push_back - (std::make_pair(to_app(m.get_fact(premise)), - abs(coefficient))); + (std::make_pair(abs(coefficient), to_app(m.get_fact(premise)))); } else { @@ -308,15 +294,15 @@ namespace spacer { struct farkas_optimized_less_than_pairs { - inline bool operator() (const std::pair& pair1, const std::pair& pair2) const + inline bool operator() (const std::pair& pair1, const std::pair& pair2) const { - return (pair1.first->get_id() < pair2.first->get_id()); + return (pair1.second->get_id() < pair2.second->get_id()); } }; void unsat_core_plugin_farkas_lemma_optimized::finalize() { - if(m_linear_combinations.empty()) + if (m_linear_combinations.empty()) { return; } @@ -331,9 +317,9 @@ namespace spacer { unsigned counter = 0; for (const auto& linear_combination : m_linear_combinations) { for (const auto& pair : linear_combination) { - if (!map.contains(pair.first)) { - ordered_basis.push_back(pair.first); - map.insert(pair.first, counter++); + if (!map.contains(pair.second)) { + ordered_basis.push_back(pair.second); + map.insert(pair.second, counter++); } } } @@ -344,7 +330,7 @@ namespace spacer { for (unsigned i = 0; i < m_linear_combinations.size(); ++i) { auto linear_combination = m_linear_combinations[i]; for (const auto& pair : linear_combination) { - matrix.set(i, map[pair.first], pair.second); + matrix.set(i, map[pair.second], pair.first); } } @@ -368,9 +354,7 @@ namespace spacer { } - expr_ref unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const coeff_lits_t& coeff_lits) - { - + expr_ref unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const coeff_lits_t& coeff_lits) { smt::farkas_util util(m); for (auto const & p : coeff_lits) { util.add(p.first, p.second); @@ -387,7 +371,7 @@ namespace spacer { } DEBUG_CODE( for (auto& linear_combination : m_linear_combinations) { - SASSERT(linear_combination.size() > 0); + SASSERT(!linear_combination.empty()); }); // 1. construct ordered basis @@ -396,9 +380,9 @@ namespace spacer { unsigned counter = 0; for (const auto& linear_combination : m_linear_combinations) { for (const auto& pair : linear_combination) { - if (!map.contains(pair.first)) { - ordered_basis.push_back(pair.first); - map.insert(pair.first, counter++); + if (!map.contains(pair.second)) { + ordered_basis.push_back(pair.second); + map.insert(pair.second, counter++); } } } @@ -409,7 +393,7 @@ namespace spacer { for (unsigned i=0; i < m_linear_combinations.size(); ++i) { auto linear_combination = m_linear_combinations[i]; for (const auto& pair : linear_combination) { - matrix.set(i, map[pair.first], pair.second); + matrix.set(i, map[pair.second], pair.first); } } matrix.print_matrix(); @@ -695,14 +679,12 @@ namespace spacer { * computes min-cut on the graph constructed by compute_partial_core-method * and adds the corresponding lemmas to the core */ -void unsat_core_plugin_min_cut::finalize() -{ + void unsat_core_plugin_min_cut::finalize() { unsigned_vector cut_nodes; m_min_cut.compute_min_cut(cut_nodes); - - for (unsigned cut_node : cut_nodes) - { + + for (unsigned cut_node : cut_nodes) { m_learner.add_lemma_to_core(m_node_to_formula[cut_node]); - } - } + } + } } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index 44a3678b6..c05bcc5b9 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -23,66 +23,55 @@ Revision History: namespace spacer { -class unsat_core_learner; + class unsat_core_learner; -class unsat_core_plugin { -protected: - typedef vector> coeff_lits_t; - ast_manager& m; -public: - unsat_core_plugin(unsat_core_learner& learner); - virtual ~unsat_core_plugin() {}; - virtual void compute_partial_core(proof* step) = 0; - virtual void finalize(){}; + class unsat_core_plugin { + protected: + typedef vector> coeff_lits_t; + ast_manager& m; + public: + unsat_core_plugin(unsat_core_learner& learner); + virtual ~unsat_core_plugin() {}; + virtual void compute_partial_core(proof* step) = 0; + virtual void finalize(){}; + + unsat_core_learner& m_learner; + }; - unsat_core_learner& m_learner; -}; - - -class unsat_core_plugin_lemma : public unsat_core_plugin { - -public: - unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){}; - - void compute_partial_core(proof* step) override; - -private: - void add_lowest_split_to_core(proof* step) const; -}; - - -class unsat_core_plugin_farkas_lemma : public unsat_core_plugin { - -public: - unsat_core_plugin_farkas_lemma(unsat_core_learner& learner, - bool split_literals, - bool use_constant_from_a=true) : - unsat_core_plugin(learner), - m_split_literals(split_literals), - m_use_constant_from_a(use_constant_from_a) {}; - - void compute_partial_core(proof* step) override; - -private: - bool m_split_literals; - bool m_use_constant_from_a; - /* - * compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res - */ - expr_ref compute_linear_combination(const coeff_lits_t& coeff_lits); -}; - - class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin { + class unsat_core_plugin_lemma : public unsat_core_plugin { + public: + unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){}; + void compute_partial_core(proof* step) override; + private: + void add_lowest_split_to_core(proof* step) const; + }; + class unsat_core_plugin_farkas_lemma : public unsat_core_plugin { + public: + unsat_core_plugin_farkas_lemma(unsat_core_learner& learner, + bool split_literals, + bool use_constant_from_a=true) : + unsat_core_plugin(learner), + m_split_literals(split_literals), + m_use_constant_from_a(use_constant_from_a) {}; + void compute_partial_core(proof* step) override; + private: + bool m_split_literals; + bool m_use_constant_from_a; + /* + * compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res + */ + expr_ref compute_linear_combination(const coeff_lits_t& coeff_lits); + }; + + class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin { public: unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {}; - void compute_partial_core(proof* step) override; void finalize() override; - protected: - vector > > m_linear_combinations; + vector m_linear_combinations; /* * compute linear combination of literals 'literals' having coefficients 'coefficients' and save result in res */ @@ -90,22 +79,17 @@ private: }; class unsat_core_plugin_farkas_lemma_bounded : public unsat_core_plugin_farkas_lemma_optimized { - public: unsat_core_plugin_farkas_lemma_bounded(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin_farkas_lemma_optimized(learner, m) {}; - void finalize() override; }; class unsat_core_plugin_min_cut : public unsat_core_plugin { - public: unsat_core_plugin_min_cut(unsat_core_learner& learner, ast_manager& m); - void compute_partial_core(proof* step) override; void finalize() override; private: - ast_mark m_visited; // saves for each node i whether the subproof with root i has already been added to the min-cut-problem obj_map m_proof_to_node_minus; // maps proof-steps to the corresponding minus-nodes (the ones which are closer to source) obj_map m_proof_to_node_plus; // maps proof-steps to the corresponding plus-nodes (the ones which are closer to sink) From 2a6b69437354433037c77a9900cc3ff8fff9d01c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 6 Jun 2018 21:32:08 -0700 Subject: [PATCH 1152/1283] Imrove hypothesis_reducer --- src/muz/spacer/spacer_proof_utils.cpp | 18 ++++++++++++------ src/muz/spacer/spacer_proof_utils.h | 4 ++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index a2a0ba6b6..bd011b3d6 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -201,10 +201,11 @@ void hypothesis_reducer::reset() { for (auto t : m_pinned_active_hyps) dealloc(t); m_pinned_active_hyps.reset(); m_pinned.reset(); + m_hyp_mark.reset(); } void hypothesis_reducer::compute_hypsets(proof *pr) { - ptr_vector todo; + ptr_buffer todo; todo.push_back(pr); while (!todo.empty()) { @@ -243,6 +244,7 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { if (m.is_hypothesis(p)) { active_hyps->insert(p); parent_hyps->insert(m.get_fact(p)); + m_hyp_mark.mark(m.get_fact(p)); } else { for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { @@ -260,8 +262,6 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { // collect all units that are hyp-free and are used as hypotheses somewhere // requires that m_active_hyps and m_parent_hyps have been computed void hypothesis_reducer::collect_units(proof* pr) { - expr_set* all_hyps = m_parent_hyps.find(pr); - SASSERT(all_hyps); proof_post_order pit(pr, m); while (pit.hasNext()) { @@ -273,12 +273,19 @@ void hypothesis_reducer::collect_units(proof* pr) { // collect units that are hyp-free and are used as // hypotheses in the proof pr if (active_hyps->empty() && m.has_fact(p) && - all_hyps->contains(m.get_fact(p))) + m_hyp_mark.is_marked(m.get_fact(p))) m_units.insert(m.get_fact(p), p); } } } +/** + \brief returns true if p is an ancestor of q + */ +bool hypothesis_reducer::is_ancestor(proof *p, proof *q) { + expr_set* parent_hyps = m_parent_hyps.find(q); + return parent_hyps->contains(m.get_fact(p)); +} proof* hypothesis_reducer::reduce_core(proof* pf) { SASSERT(m.is_false(m.get_fact(pf))); @@ -334,8 +341,7 @@ proof* hypothesis_reducer::reduce_core(proof* pf) { SASSERT(m_parent_hyps.contains(proof_of_unit)); // if the transformation doesn't create a cycle, perform it - expr_set* parent_hyps = m_parent_hyps.find(proof_of_unit); - if (!parent_hyps->contains(p)) { + if (!is_ancestor(p, proof_of_unit)) { res = proof_of_unit; } else { diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index 7ab022814..6c56c204e 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -84,8 +84,12 @@ private: // during proof transformation obj_map m_parent_hyps; + expr_mark m_hyp_mark; + void reset(); + /// true if p is an ancestor of q + bool is_ancestor(proof *p, proof *q); // compute active_hyps and parent_hyps for a given proof node and // all its ancestors void compute_hypsets(proof* pr); From a40e0dce0cee87a29f58d41d985e59cae5065d6d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 7 Jun 2018 08:50:31 -0700 Subject: [PATCH 1153/1283] proof_utils: use expr_mark instead of hashtable --- src/muz/spacer/spacer_proof_utils.cpp | 28 +++++++++++++-------------- src/muz/spacer/spacer_proof_utils.h | 4 ++++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index bd011b3d6..ca0e67f46 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -202,6 +202,8 @@ void hypothesis_reducer::reset() { m_pinned_active_hyps.reset(); m_pinned.reset(); m_hyp_mark.reset(); + m_open_mark.reset(); + m_visited.reset(); } void hypothesis_reducer::compute_hypsets(proof *pr) { @@ -211,8 +213,7 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { while (!todo.empty()) { proof* p = todo.back(); - if (m_active_hyps.contains(p)) { - SASSERT(m_parent_hyps.contains(p)); + if (m_visited.is_marked(p)) { todo.pop_back(); continue; } @@ -222,15 +223,15 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { SASSERT(m.is_proof(p->get_arg(i))); proof *parent = to_app(p->get_arg(i)); - if (!m_active_hyps.contains(parent)) { - SASSERT(!m_parent_hyps.contains(parent)); + if (!m_visited.is_marked(parent)) todo.push_back(parent); - } } if (todo.size() > todo_sz) continue; todo.pop_back(); + m_visited.mark(p); + // create active_hyps-set and parent_hyps-set for step p proof_set* active_hyps = alloc(proof_set); m_pinned_active_hyps.insert(active_hyps); @@ -243,6 +244,8 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { // fill both sets if (m.is_hypothesis(p)) { active_hyps->insert(p); + m_open_mark.mark(p); + parent_hyps->insert(m.get_fact(p)); m_hyp_mark.mark(m.get_fact(p)); } @@ -251,9 +254,11 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { proof* parent = m.get_parent(p, i); set_union(*parent_hyps, *m_parent_hyps.find(parent)); - if (!m.is_lemma(p)) + if (!m.is_lemma(p)) { // lemmas clear all hypotheses set_union(*active_hyps, *m_active_hyps.find(parent)); + m_open_mark.mark(p, !active_hyps->empty()); + } } } } @@ -267,12 +272,9 @@ void hypothesis_reducer::collect_units(proof* pr) { while (pit.hasNext()) { proof* p = pit.next(); if (!m.is_hypothesis(p)) { - proof_set* active_hyps = m_active_hyps.find(p); - SASSERT(active_hyps); - // collect units that are hyp-free and are used as // hypotheses in the proof pr - if (active_hyps->empty() && m.has_fact(p) && + if (!m_open_mark.is_marked(p) && m.has_fact(p) && m_hyp_mark.is_marked(m.get_fact(p))) m_units.insert(m.get_fact(p), p); } @@ -383,9 +385,7 @@ proof* hypothesis_reducer::reduce_core(proof* pf) { m_cache.insert(p, res); // bail out as soon as found a sub-proof of false - SASSERT(m_active_hyps.contains(res)); - proof_set* active_hyps = m_active_hyps.find(res); - if (active_hyps->empty() && m.has_fact(res) && m.is_false(m.get_fact(res))) + if (!m_open_mark.is_marked(res) && m.has_fact(res) && m.is_false(m.get_fact(res))) return res; } UNREACHABLE(); @@ -399,7 +399,7 @@ proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { proof_set* active_hyps = m_active_hyps.find(premise); // if there is no active hypothesis return the premise - if (active_hyps->empty()) { + if (!m_open_mark.is_marked(premise)) { // XXX just in case premise might go away m_pinned.push_back(premise); return premise; diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index 6c56c204e..c418d932b 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -84,7 +84,11 @@ private: // during proof transformation obj_map m_parent_hyps; + /// marks if an expression is ever used as a hypothesis in a proof expr_mark m_hyp_mark; + /// marks a proof as open, i.e., has a non-discharged hypothesis as ancestor + expr_mark m_open_mark; + expr_mark m_visited; void reset(); From e84ca25f05dc6ec9eb368d0b6219c915d3586eb6 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 7 Jun 2018 09:07:17 -0700 Subject: [PATCH 1154/1283] Check whether one proof node is an ancestor of another on-demand Instead of pre-computing sets --- src/muz/spacer/spacer_proof_utils.cpp | 34 +++++++++++++++++---------- src/muz/spacer/spacer_proof_utils.h | 7 ------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index ca0e67f46..a8a90fa2b 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -192,12 +192,9 @@ proof_ref hypothesis_reducer::reduce(proof* pr) { } void hypothesis_reducer::reset() { - m_parent_hyps.reset(); m_active_hyps.reset(); m_units.reset(); m_cache.reset(); - for (auto t : m_pinned_parent_hyps) dealloc(t); - m_pinned_parent_hyps.reset(); for (auto t : m_pinned_active_hyps) dealloc(t); m_pinned_active_hyps.reset(); m_pinned.reset(); @@ -237,22 +234,16 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { m_pinned_active_hyps.insert(active_hyps); m_active_hyps.insert(p, active_hyps); - expr_set* parent_hyps = alloc(expr_set); - m_pinned_parent_hyps.insert(parent_hyps); - m_parent_hyps.insert(p, parent_hyps); - // fill both sets if (m.is_hypothesis(p)) { active_hyps->insert(p); m_open_mark.mark(p); - parent_hyps->insert(m.get_fact(p)); m_hyp_mark.mark(m.get_fact(p)); } else { for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { proof* parent = m.get_parent(p, i); - set_union(*parent_hyps, *m_parent_hyps.find(parent)); if (!m.is_lemma(p)) { // lemmas clear all hypotheses @@ -265,7 +256,7 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { } // collect all units that are hyp-free and are used as hypotheses somewhere -// requires that m_active_hyps and m_parent_hyps have been computed +// requires that m_active_hyps has been computed void hypothesis_reducer::collect_units(proof* pr) { proof_post_order pit(pr, m); @@ -285,8 +276,26 @@ void hypothesis_reducer::collect_units(proof* pr) { \brief returns true if p is an ancestor of q */ bool hypothesis_reducer::is_ancestor(proof *p, proof *q) { - expr_set* parent_hyps = m_parent_hyps.find(q); - return parent_hyps->contains(m.get_fact(p)); + if (p == q) return true; + ptr_vector todo; + todo.push_back(q); + + expr_mark visited; + while (!todo.empty()) { + proof *cur; + cur = todo.back(); + todo.pop_back(); + + if (visited.is_marked(cur)) continue; + + if (cur == p) return true; + visited.mark(cur); + + for (unsigned i = 0, sz = m.get_num_parents(cur); i < sz; ++i) { + todo.push_back(m.get_parent(cur, i)); + } + } + return false; } proof* hypothesis_reducer::reduce_core(proof* pf) { @@ -340,7 +349,6 @@ proof* hypothesis_reducer::reduce_core(proof* pf) { // make sure hypsets for the unit are computed // AG: is this needed? compute_hypsets(proof_of_unit); - SASSERT(m_parent_hyps.contains(proof_of_unit)); // if the transformation doesn't create a cycle, perform it if (!is_ancestor(p, proof_of_unit)) { diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index c418d932b..f8d8d263b 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -67,8 +67,6 @@ private: // created sets of active hypothesis ptr_vector m_pinned_active_hyps; - // created sets of parent hypothesis - ptr_vector m_pinned_parent_hyps; // maps a proof to the transformed proof obj_map m_cache; @@ -79,11 +77,6 @@ private: // maps a proof node to the set of its active (i.e., in scope) hypotheses obj_map m_active_hyps; - // maps a proof node to the set of all hypothesis-facts (active or - // not) that can reach it. Used for cycle detection and avoidance - // during proof transformation - obj_map m_parent_hyps; - /// marks if an expression is ever used as a hypothesis in a proof expr_mark m_hyp_mark; /// marks a proof as open, i.e., has a non-discharged hypothesis as ancestor From c5fb1c1223f6123d0e2ac9b762344c7b600ecd24 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 7 Jun 2018 09:45:17 -0700 Subject: [PATCH 1155/1283] Use vector instead of a hashtable to represent a set --- src/muz/spacer/spacer_proof_utils.cpp | 42 ++++++++++++++++++--------- src/muz/spacer/spacer_proof_utils.h | 9 +++--- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index a8a90fa2b..4a64f3d08 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -229,29 +229,43 @@ void hypothesis_reducer::compute_hypsets(proof *pr) { m_visited.mark(p); - // create active_hyps-set and parent_hyps-set for step p - proof_set* active_hyps = alloc(proof_set); - m_pinned_active_hyps.insert(active_hyps); - m_active_hyps.insert(p, active_hyps); + proof_ptr_vector* active_hyps = nullptr; // fill both sets if (m.is_hypothesis(p)) { - active_hyps->insert(p); + // create active_hyps-set for step p + proof_ptr_vector* active_hyps = alloc(proof_ptr_vector); + m_pinned_active_hyps.insert(active_hyps); + m_active_hyps.insert(p, active_hyps); + active_hyps->push_back(p); m_open_mark.mark(p); - m_hyp_mark.mark(m.get_fact(p)); + continue; } - else { - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { - proof* parent = m.get_parent(p, i); - if (!m.is_lemma(p)) { - // lemmas clear all hypotheses - set_union(*active_hyps, *m_active_hyps.find(parent)); - m_open_mark.mark(p, !active_hyps->empty()); + ast_fast_mark1 seen; + + active_hyps = alloc(proof_ptr_vector); + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + proof* parent = m.get_parent(p, i); + // lemmas clear all hypotheses above them + if (m.is_lemma(p)) continue; + for (auto *x : *m_active_hyps.find(parent)) { + if (!seen.is_marked(x)) { + seen.mark(x); + active_hyps->push_back(x); + m_open_mark.mark(p); } } } + if (active_hyps->empty()) { + dealloc(active_hyps); + m_active_hyps.insert(p, &m_empty_vector); + } + else { + m_pinned_active_hyps.push_back(active_hyps); + m_active_hyps.insert(p, active_hyps); + } } } @@ -404,7 +418,7 @@ proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { SASSERT(m.is_false(m.get_fact(premise))); SASSERT(m_active_hyps.contains(premise)); - proof_set* active_hyps = m_active_hyps.find(premise); + proof_ptr_vector* active_hyps = m_active_hyps.find(premise); // if there is no active hypothesis return the premise if (!m_open_mark.is_marked(premise)) { diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/muz/spacer/spacer_proof_utils.h index f8d8d263b..ead85f885 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/muz/spacer/spacer_proof_utils.h @@ -57,16 +57,17 @@ public: proof_ref reduce(proof* pf); private: - typedef obj_hashtable expr_set; - typedef obj_hashtable proof_set; + typedef ptr_vector proof_ptr_vector; ast_manager &m; + proof_ptr_vector m_empty_vector; + // created expressions expr_ref_vector m_pinned; // created sets of active hypothesis - ptr_vector m_pinned_active_hyps; + ptr_vector m_pinned_active_hyps; // maps a proof to the transformed proof obj_map m_cache; @@ -75,7 +76,7 @@ private: obj_map m_units; // maps a proof node to the set of its active (i.e., in scope) hypotheses - obj_map m_active_hyps; + obj_map m_active_hyps; /// marks if an expression is ever used as a hypothesis in a proof expr_mark m_hyp_mark; From 0534b72c4dd53949c6f10c12b08a1448b35340dd Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 7 Jun 2018 09:54:44 -0700 Subject: [PATCH 1156/1283] sort hypotheses --- src/muz/spacer/spacer_proof_utils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 4a64f3d08..082cc4b5d 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -427,6 +427,8 @@ proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { return premise; } + // add some stability + std::stable_sort(active_hyps->begin(), active_hyps->end(), ast_lt_proc()); // otherwise, build a disjunction of the negated active hypotheses // and add a lemma proof step expr_ref_buffer args(m); From 1f0fd38c99da27cf3d4f94c1a56eb5f4e2e59466 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 7 Jun 2018 17:14:26 -0700 Subject: [PATCH 1157/1283] ground sat refutation from spacer (wip) --- src/muz/spacer/CMakeLists.txt | 1 + src/muz/spacer/spacer_context.cpp | 71 ++++++----- src/muz/spacer/spacer_context.h | 3 +- src/muz/spacer/spacer_sat_answer.cpp | 168 +++++++++++++++++++++++++++ src/muz/spacer/spacer_sat_answer.h | 55 +++++++++ 5 files changed, 267 insertions(+), 31 deletions(-) create mode 100644 src/muz/spacer/spacer_sat_answer.cpp create mode 100644 src/muz/spacer/spacer_sat_answer.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 8e41d5ae7..22218f25f 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -27,6 +27,7 @@ z3_add_component(spacer spacer_iuc_proof.cpp spacer_mbc.cpp spacer_pdr.cpp + spacer_sat_answer.cpp COMPONENT_DEPENDENCIES arith_tactics core_tactics diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 6726bb15d..2e199c6e4 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -36,6 +36,7 @@ Notes: #include "muz/base/dl_rule_set.h" #include "smt/tactic/unit_subsumption_tactic.h" #include "model/model_smt2_pp.h" +#include "model/model_evaluator.h" #include "muz/transforms/dl_mk_rule_inliner.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" @@ -52,6 +53,9 @@ Notes: #include "ast/expr_abstract.h" #include "smt/smt_solver.h" + +#include "muz/spacer/spacer_sat_answer.h" + namespace spacer { /// pob -- proof obligation @@ -2857,19 +2861,31 @@ expr_ref context::mk_unsat_answer() const return ex.to_expr(); } + +proof_ref context::get_ground_refutation() { + if (m_last_result != l_true) { + IF_VERBOSE(0, verbose_stream() + << "Sat answer unavailable when result is false\n";); + return proof_ref(m); + } + + ground_sat_answer_op op(*this); + return op(*m_query); +} expr_ref context::get_ground_sat_answer() { if (m_last_result != l_true) { - verbose_stream () << "Sat answer unavailable when result is false\n"; - return expr_ref (m); + IF_VERBOSE(0, verbose_stream() + << "Sat answer unavailable when result is false\n";); + return expr_ref(m); } // treat the following as queues: read from left to right and insert at the right reach_fact_ref_vector reach_facts; ptr_vector preds; ptr_vector pts; - expr_ref_vector cex (m), // pre-order list of ground instances of predicates - cex_facts (m); // equalities for the ground cex using signature constants + expr_ref_vector cex (m); // pre-order list of ground instances of predicates + expr_ref_vector cex_facts (m); // equalities for the ground cex using signature constants // temporary reach_fact *reach_fact; @@ -2921,6 +2937,7 @@ expr_ref context::get_ground_sat_answer() // get child pts preds.reset(); pt->find_predecessors(*r, preds); + for (unsigned j = 0; j < preds.size (); j++) { child_pts.push_back (&(get_pred_transformer (preds[j]))); } @@ -2936,12 +2953,11 @@ expr_ref context::get_ground_sat_answer() SASSERT (child_reach_facts.size () == u_tail_sz); for (unsigned i = 0; i < u_tail_sz; i++) { expr_ref ofml (m); - child_pts.get (i)->get_manager ().formula_n2o - (child_reach_facts[i]->get (), ofml, i); + m_pm.formula_n2o(child_reach_facts[i]->get(), ofml, i); cex_ctx->assert_expr (ofml); } - cex_ctx->assert_expr (pt->transition ()); - cex_ctx->assert_expr (pt->rule2tag (r)); + cex_ctx->assert_expr(pt->transition()); + cex_ctx->assert_expr(pt->rule2tag(r)); lbool res = cex_ctx->check_sat(0, nullptr); CTRACE("cex", res == l_false, tout << "Cex fact: " << mk_pp(cex_fact, m) << "\n"; @@ -2956,40 +2972,35 @@ expr_ref context::get_ground_sat_answer() cex_ctx->get_model (local_mdl); cex_ctx->pop (1); - model_evaluator_util mev (m); - mev.set_model (*local_mdl); - for (unsigned i = 0; i < child_pts.size (); i++) { - pred_transformer& ch_pt = *(child_pts.get (i)); - unsigned sig_size = ch_pt.sig_size (); - expr_ref_vector ground_fact_conjs (m); - expr_ref_vector ground_arg_vals (m); + model_evaluator mev(*local_mdl); + for (unsigned i = 0; i < child_pts.size(); i++) { + pred_transformer& ch_pt = *(child_pts.get(i)); + unsigned sig_size = ch_pt.sig_size(); + expr_ref_vector ground_fact_conjs(m); + expr_ref_vector ground_arg_vals(m); for (unsigned j = 0; j < sig_size; j++) { - expr_ref sig_arg (m), sig_val (m); - sig_arg = m.mk_const (ch_pt.get_manager ().o2o (ch_pt.sig (j), 0, i)); + expr_ref sig_arg(m), sig_val(m); + sig_arg = m.mk_const (m_pm.o2o(ch_pt.sig(j), 0, i)); VERIFY(mev.eval (sig_arg, sig_val, true)); - ground_fact_conjs.push_back (m.mk_eq (sig_arg, sig_val)); - ground_arg_vals.push_back (sig_val); + ground_fact_conjs.push_back(m.mk_eq(sig_arg, sig_val)); + ground_arg_vals.push_back(sig_val); } if (ground_fact_conjs.size () > 0) { - expr_ref ground_fact (m); - ground_fact = m.mk_and (ground_fact_conjs.size (), ground_fact_conjs.c_ptr ()); - ch_pt.get_manager ().formula_o2n (ground_fact, ground_fact, i); + expr_ref ground_fact(m); + ground_fact = mk_and(ground_fact_conjs); + m_pm.formula_o2n(ground_fact, ground_fact, i); cex_facts.push_back (ground_fact); } else { cex_facts.push_back (m.mk_true ()); } - cex.push_back (m.mk_app (ch_pt.head (), sig_size, ground_arg_vals.c_ptr ())); + cex.push_back(m.mk_app(ch_pt.head(), + sig_size, ground_arg_vals.c_ptr())); } } - TRACE ("spacer", - tout << "ground cex\n"; - for (unsigned i = 0; i < cex.size (); i++) { - tout << mk_pp (cex.get (i), m) << "\n"; - } - ); + TRACE ("spacer", tout << "ground cex\n" << cex << "\n";); - return expr_ref (m.mk_and (cex.size (), cex.c_ptr ()), m); + return expr_ref(m.mk_and(cex.size(), cex.c_ptr()), m); } ///this is where everything starts diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 34c04d596..e95ddc8ec 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -970,7 +970,8 @@ public: * get bottom-up (from query) sequence of ground predicate instances * (for e.g. P(0,1,0,0,3)) that together form a ground derivation to query */ - expr_ref get_ground_sat_answer (); + expr_ref get_ground_sat_answer (); + proof_ref get_ground_refutation(); void get_rules_along_trace (datalog::rule_ref_vector& rules); void collect_statistics(statistics& st) const; diff --git a/src/muz/spacer/spacer_sat_answer.cpp b/src/muz/spacer/spacer_sat_answer.cpp new file mode 100644 index 000000000..8382133d8 --- /dev/null +++ b/src/muz/spacer/spacer_sat_answer.cpp @@ -0,0 +1,168 @@ +#include "muz/spacer/spacer_sat_answer.h" +#include "muz/base/dl_context.h" +#include "muz/base/dl_rule.h" + +#include "smt/smt_solver.h" + +namespace spacer { + +struct ground_sat_answer_op::frame { + reach_fact *m_rf; + pred_transformer &m_pt; + expr_ref_vector m_gnd_subst; + expr_ref m_gnd_eq; + expr_ref m_fact; + unsigned m_visit; + expr_ref_vector m_kids; + + frame(reach_fact *rf, pred_transformer &pt, const expr_ref_vector &gnd_subst) : + m_rf(rf), m_pt(pt), + m_gnd_subst(gnd_subst), + m_gnd_eq(pt.get_ast_manager()), + m_fact(pt.get_ast_manager()), + m_visit(0), + m_kids(pt.get_ast_manager()) { + + ast_manager &m = pt.get_ast_manager(); + spacer::manager &pm = pt.get_manager(); + + m_fact = m.mk_app(head(), m_gnd_subst.size(), m_gnd_subst.c_ptr()); + if (pt.head()->get_arity() == 0) + m_gnd_eq = m.mk_true(); + else { + SASSERT(m_gnd_subst.size() == pt.head()->get_arity()); + for (unsigned i = 0, sz = pt.sig_size(); i < sz; ++i) { + m_gnd_eq = m.mk_eq(m.mk_const(pm.o2n(pt.sig(i), 0)), + m_gnd_subst.get(i)); + } + } + } + + func_decl* head() {return m_pt.head();} + expr* fact() {return m_fact;} + const datalog::rule &rule() {return m_rf->get_rule();} + pred_transformer &pt() {return m_pt;} +}; + +ground_sat_answer_op::ground_sat_answer_op(context &ctx) : + m_ctx(ctx), m(m_ctx.get_ast_manager()), m_pm(m_ctx.get_manager()), + m_pinned(m) { + m_solver = mk_smt_solver(m, params_ref::get_empty(), symbol::null); +} + +proof_ref ground_sat_answer_op::operator()(pred_transformer &query) { + + + vector todo; + + // -- find substitution for a query if query is not nullary + expr_ref_vector qsubst(m); + if (query.head()->get_arity() > 0) { + solver::scoped_push _s_(*m_solver); + m_solver->assert_expr(query.get_last_rf()->get()); + lbool res = m_solver->check_sat(0, nullptr); + (void)res; + SASSERT(res == l_true); + model_ref mdl; + m_solver->get_model(mdl); + for (unsigned i = 0, sz = query.sig_size(); i < sz; ++i) { + expr_ref arg(m), val(m); + arg = m.mk_const(m_pm.o2n(query.sig(i), 0)); + mdl->eval(arg, val, true); + qsubst.push_back(val); + } + } + + frame root(query.get_last_rf(), query, qsubst); + todo.push_back(root); + + while (!todo.empty()) { + frame &curr = todo.back(); + if (m_cache.contains(curr.fact())) + { + todo.pop_back(); + continue; + } + + if (curr.m_visit == 0) { + mk_children(curr, todo); + curr.m_visit = 1; + } + else { + proof* pf = mk_proof_step(curr); + m_cache.insert(curr.fact(), pf); + todo.pop_back(); + } + + } + return proof_ref(m_cache.find(root.fact()), m); +} + + +void ground_sat_answer_op::mk_children(frame &fr, vector &todo) { + const datalog::rule &r = fr.rule(); + ptr_vector preds; + fr.pt().find_predecessors(r, preds); + + if (preds.empty()) return; + + const reach_fact_ref_vector &kid_rfs = fr.m_rf->get_justifications(); + solver::scoped_push _s_(*m_solver); + m_solver->assert_expr(fr.m_gnd_eq); + unsigned ut_sz = r.get_uninterpreted_tail_size(); + for (unsigned i = 0; i < ut_sz; ++i) { + expr_ref f(m); + m_pm.formula_n2o(kid_rfs.get(i)->get(), f, i); + m_solver->assert_expr(f); + } + m_solver->assert_expr(fr.pt().transition()); + m_solver->assert_expr(fr.pt().rule2tag(&r)); + + lbool res = m_solver->check_sat(0, nullptr); + (void)res; + SASSERT(res == l_true); + + model_ref mdl; + m_solver->get_model(mdl); + expr_ref_vector subst(m); + for (unsigned i = 0, sz = preds.size(); i < sz; ++i) { + subst.reset(); + mk_child_subst_from_model(preds.get(i), i, mdl, subst); + todo.push_back(frame(kid_rfs.get(i), + m_ctx.get_pred_transformer(preds.get(i)), subst)); + fr.m_kids.push_back(todo.back().fact()); + } +} + + +void ground_sat_answer_op::mk_child_subst_from_model(func_decl *pred, + unsigned j, model_ref &mdl, + expr_ref_vector &subst) { + pred_transformer &pt = m_ctx.get_pred_transformer(pred); + for (unsigned i = 0, sz = pt.sig_size(); i < sz; ++i) { + expr_ref arg(m), val(m); + arg = m.mk_const(m_pm.o2o(pt.sig(i), 0, j)); + mdl->eval(arg, val, true); + subst.push_back(val); + } +} + +proof *ground_sat_answer_op::mk_proof_step(frame &fr) { + svector> positions; + vector substs; + + proof_ref_vector premises(m); + datalog::rule_manager &rm = m_ctx.get_datalog_context().get_rule_manager(); + expr_ref rule_fml(m); + rm.to_formula(fr.rule(), rule_fml); + premises.push_back(m.mk_asserted(rule_fml)); + for (auto &k : fr.m_kids) {premises.push_back(m_cache.find(k));} + + m_pinned.push_back(m.mk_hyper_resolve(premises.size(), + premises.c_ptr(), + fr.fact(), + positions, substs)); + return to_app(m_pinned.back()); +} + +} diff --git a/src/muz/spacer/spacer_sat_answer.h b/src/muz/spacer/spacer_sat_answer.h new file mode 100644 index 000000000..6cfd3b14c --- /dev/null +++ b/src/muz/spacer/spacer_sat_answer.h @@ -0,0 +1,55 @@ +/*++ +Copyright (c) 2018 Arie Gurfinkel + +Module Name: + + spacer_sat_answer.h + +Abstract: + + Compute refutation proof for CHC + +Author: + + Arie Gurfinkel + +Revision History: + +--*/ + +#ifndef _SPACER_SAT_ANSWER_H_ +#define _SPACER_SAT_ANSWER_H_ + +#include "muz/spacer/spacer_context.h" +#include "ast/ast.h" +#include "util/obj_hashtable.h" +#include "model/model.h" +#include "solver/solver.h" + +namespace spacer { + +class ground_sat_answer_op { + context &m_ctx; + ast_manager &m; + manager &m_pm; + + expr_ref_vector m_pinned; + obj_map m_cache; + + ref m_solver; + + struct frame; + + proof *mk_proof_step(frame &fr); + void mk_children(frame &fr, vector &todo); + void mk_child_subst_from_model(func_decl *pred, unsigned i, + model_ref &mdl, expr_ref_vector &subst); + +public: + ground_sat_answer_op(context &ctx); + + proof_ref operator() (pred_transformer &query); +}; +} + +#endif From 1920450f98b1bf354bc22a54970d5cac9a4715c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Jun 2018 09:58:27 -0700 Subject: [PATCH 1158/1283] throttle ite-blasting Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_context.cpp | 2 +- src/tactic/core/blast_term_ite_tactic.cpp | 79 ++++++++++++++++------- src/tactic/core/blast_term_ite_tactic.h | 2 +- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 2e199c6e4..5806c08fb 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1673,7 +1673,7 @@ void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule, // rewrite and simplify th_rewriter rw(m); rw(fml); - if (ctx.blast_term_ite()) {blast_term_ite(fml); rw(fml);} + if (ctx.blast_term_ite()) {blast_term_ite(fml, 3); rw(fml);} TRACE("spacer", tout << mk_pp(fml, m) << "\n";); // allow quantifiers in init rule diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index 3c4684cb8..eefb9418e 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -33,50 +33,65 @@ Notes: class blast_term_ite_tactic : public tactic { struct rw_cfg : public default_rewriter_cfg { - ast_manager& m; - unsigned long long m_max_memory; // in bytes - unsigned m_num_fresh; // number of expansions + ast_manager& m; + unsigned long long m_max_memory; // in bytes + unsigned m_num_fresh; // number of expansions + unsigned m_max_steps; + unsigned m_max_inflation; + unsigned m_init_term_size; rw_cfg(ast_manager & _m, params_ref const & p): m(_m), - m_num_fresh(0) { + m_num_fresh(0), + m_max_steps(UINT_MAX), + m_max_inflation(UINT_MAX), + m_init_term_size(0) { updt_params(p); } void updt_params(params_ref const & p) { - m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); + m_max_steps = p.get_uint("max_steps", UINT_MAX); + m_max_inflation = p.get_uint("max_inflation", UINT_MAX); // multiplicative factor of initial term size. } + + bool max_steps_exceeded(unsigned num_steps) const { cooperate("blast term ite"); // if (memory::get_allocation_size() > m_max_memory) // throw tactic_exception(TACTIC_MAX_MEMORY_MSG); - return false; + return num_steps >= m_max_steps; } br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { if (m.is_ite(f)) { return BR_FAILED; } + if (m_max_inflation < UINT_MAX && + m_init_term_size > 0 && + m_max_inflation * m_init_term_size < m_num_fresh) + return BR_FAILED; + for (unsigned i = 0; i < num_args; ++i) { expr* c, *t, *e; if (!m.is_bool(args[i]) && m.is_ite(args[i], c, t, e)) { - // enable_trace("blast_term_ite"); TRACE("blast_term_ite", result = m.mk_app(f, num_args, args); tout << result << "\n";); expr_ref e1(m), e2(m); ptr_vector args1(num_args, args); args1[i] = t; - ++m_num_fresh; e1 = m.mk_app(f, num_args, args1.c_ptr()); - if (m.are_equal(t,e)) { + if (m.are_equal(t, e)) { result = e1; return BR_REWRITE1; } - args1[i] = e; - e2 = m.mk_app(f, num_args, args1.c_ptr()); - result = m.mk_app(f, num_args, args); - result = m.mk_ite(c, e1, e2); - return BR_REWRITE3; + else { + args1[i] = e; + e2 = m.mk_app(f, num_args, args1.c_ptr()); + result = m.mk_ite(c, e1, e2); + ++m_num_fresh; + return BR_REWRITE3; + } } } return BR_FAILED; @@ -107,10 +122,9 @@ class blast_term_ite_tactic : public tactic { m(_m), m_rw(m, p) { } - - + void updt_params(params_ref const & p) { - m_rw.cfg().updt_params(p); + m_rw.m_cfg.updt_params(p); } void operator()(goal_ref const & g, goal_ref_buffer & result) { @@ -121,8 +135,14 @@ class blast_term_ite_tactic : public tactic { expr_ref new_curr(m); proof_ref new_pr(m); unsigned size = g->size(); + unsigned num_fresh = 0; for (unsigned idx = 0; idx < size; idx++) { expr * curr = g->form(idx); + if (m_rw.m_cfg.m_max_inflation < UINT_MAX) { + m_rw.m_cfg.m_init_term_size = get_num_exprs(curr); + num_fresh += m_rw.m_cfg.m_num_fresh; + m_rw.m_cfg.m_num_fresh = 0; + } m_rw(curr, new_curr, new_pr); if (produce_proofs) { proof * pr = g->pr(idx); @@ -130,7 +150,7 @@ class blast_term_ite_tactic : public tactic { } g->update(idx, new_curr, new_pr, g->dep(idx)); } - report_tactic_progress(":blast-term-ite-consts", m_rw.m_cfg.m_num_fresh); + report_tactic_progress(":blast-term-ite-consts", m_rw.m_cfg.m_num_fresh + num_fresh); g->inc_depth(); result.push_back(g.get()); TRACE("blast_term_ite", g->display(tout);); @@ -156,7 +176,7 @@ public: void updt_params(params_ref const & p) override { m_params = p; - m_imp->m_rw.cfg().updt_params(p); + m_imp->m_rw.m_cfg.updt_params(p); } void collect_param_descrs(param_descrs & r) override { @@ -176,14 +196,23 @@ public: m_imp = alloc(imp, m, m_params); } - static void blast_term_ite(expr_ref& fml) { + static void blast_term_ite(expr_ref& fml, unsigned max_inflation) { ast_manager& m = fml.get_manager(); scoped_no_proof _sp(m); params_ref p; rw ite_rw(m, p); - expr_ref tmp(m); - ite_rw(fml, tmp); - fml = tmp; + ite_rw.m_cfg.m_max_inflation = max_inflation; + if (max_inflation < UINT_MAX) { + ite_rw.m_cfg.m_init_term_size = get_num_exprs(fml); + } + try { + expr_ref tmp(m); + ite_rw(fml, tmp); + fml = tmp; + } + catch (z3_exception &) { + // max steps exceeded. + } } }; @@ -191,6 +220,6 @@ tactic * mk_blast_term_ite_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(blast_term_ite_tactic, m, p)); } -void blast_term_ite(expr_ref& fml) { - blast_term_ite_tactic::blast_term_ite(fml); +void blast_term_ite(expr_ref& fml, unsigned max_inflation) { + blast_term_ite_tactic::blast_term_ite(fml, max_inflation); } diff --git a/src/tactic/core/blast_term_ite_tactic.h b/src/tactic/core/blast_term_ite_tactic.h index 1ecab98be..fcad6c068 100644 --- a/src/tactic/core/blast_term_ite_tactic.h +++ b/src/tactic/core/blast_term_ite_tactic.h @@ -33,6 +33,6 @@ tactic * mk_blast_term_ite_tactic(ast_manager & m, params_ref const & p = params ADD_TACTIC("blast-term-ite", "blast term if-then-else by hoisting them.", "mk_blast_term_ite_tactic(m, p)") */ -void blast_term_ite(expr_ref& fml); +void blast_term_ite(expr_ref& fml, unsigned max_inflation); #endif From f3466bb3e4874216265c54c3da4fb1d5bcebf074 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Jun 2018 21:07:46 -0700 Subject: [PATCH 1159/1283] tidy Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_util.cpp | 1344 +++++++++++--------------------- src/muz/spacer/spacer_util.h | 221 +++--- 2 files changed, 573 insertions(+), 992 deletions(-) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index ebcbb9145..8941c511a 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -87,8 +87,8 @@ namespace spacer { m_mev = nullptr; } m_model = model; - if (!m_model) { return; } - m_mev = alloc(model_evaluator, *m_model); + if (m_model) + m_mev = alloc(model_evaluator, *m_model); } bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { @@ -127,334 +127,6 @@ namespace spacer { return eval(x, res, false) && m.is_true (res); } - void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { - ast_manager& m = fml.get_manager(); - expr_ref_vector conjs(m); - flatten_and(fml, conjs); - obj_map diseqs; - expr* n, *lhs, *rhs; - for (unsigned i = 0; i < conjs.size(); ++i) { - if (m.is_not(conjs[i].get(), n) && m.is_eq(n, lhs, rhs)) { - if (!m.is_value(rhs)) { - std::swap(lhs, rhs); - } - if (!m.is_value(rhs)) { - continue; - } - diseqs.insert_if_not_there2(lhs, 0)->get_data().m_value++; - } - } - expr_substitution sub(m); - - unsigned orig_size = conjs.size(); - unsigned num_deleted = 0; - expr_ref val(m), tmp(m); - proof_ref pr(m); - pr = m.mk_asserted(m.mk_true()); - for (auto const& kv : diseqs) { - if (kv.m_value >= threshold) { - model.eval(kv.m_key, val); - sub.insert(kv.m_key, val, pr); - conjs.push_back(m.mk_eq(kv.m_key, val)); - num_deleted += kv.m_value; - } - } - if (orig_size < conjs.size()) { - scoped_ptr rep = mk_expr_simp_replacer(m); - rep->set_substitution(&sub); - for (unsigned i = 0; i < orig_size; ++i) { - tmp = conjs[i].get(); - (*rep)(tmp); - if (m.is_true(tmp)) { - conjs[i] = conjs.back(); - SASSERT(orig_size <= conjs.size()); - conjs.pop_back(); - SASSERT(orig_size <= 1 + conjs.size()); - if (i + 1 == orig_size) { - // no-op. - } - else if (orig_size <= conjs.size()) { - // no-op - } - else { - SASSERT(orig_size == 1 + conjs.size()); - --orig_size; - --i; - } - } - else { - conjs[i] = tmp; - } - } - IF_VERBOSE(2, verbose_stream() << "Deleted " << num_deleted << " disequalities " << conjs.size() << " conjuncts\n";); - } - fml = m.mk_and(conjs.size(), conjs.c_ptr()); - } - - // - // (f (if c1 (if c2 e1 e2) e3) b c) -> - // (if c1 (if c2 (f e1 b c) - - class ite_hoister { - ast_manager& m; - public: - ite_hoister(ast_manager& m): m(m) {} - - br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { - if (m.is_ite(f)) { - return BR_FAILED; - } - for (unsigned i = 0; i < num_args; ++i) { - expr* c, *t, *e; - if (!m.is_bool(args[i]) && m.is_ite(args[i], c, t, e)) { - expr_ref e1(m), e2(m); - ptr_vector args1(num_args, args); - args1[i] = t; - e1 = m.mk_app(f, num_args, args1.c_ptr()); - if (t == e) { - result = e1; - return BR_REWRITE1; - } - args1[i] = e; - e2 = m.mk_app(f, num_args, args1.c_ptr()); - result = m.mk_app(f, num_args, args); - result = m.mk_ite(c, e1, e2); - return BR_REWRITE3; - } - } - return BR_FAILED; - } - }; - - struct ite_hoister_cfg: public default_rewriter_cfg { - ite_hoister m_r; - bool rewrite_patterns() const { return false; } - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - return m_r.mk_app_core(f, num, args, result); - } - ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} - }; - - class ite_hoister_star : public rewriter_tpl { - ite_hoister_cfg m_cfg; - public: - ite_hoister_star(ast_manager & m, params_ref const & p): - rewriter_tpl(m, false, m_cfg), - m_cfg(m, p) {} - }; - - void hoist_non_bool_if(expr_ref& fml) { - ast_manager& m = fml.get_manager(); - scoped_no_proof _sp(m); - params_ref p; - ite_hoister_star ite_rw(m, p); - expr_ref tmp(m); - ite_rw(fml, tmp); - fml = tmp; - } - - class test_diff_logic { - ast_manager& m; - arith_util a; - bv_util bv; - bool m_is_dl; - bool m_test_for_utvpi; - - bool is_numeric(expr* e) const { - if (a.is_numeral(e)) { - return true; - } - expr* cond, *th, *el; - if (m.is_ite(e, cond, th, el)) { - return is_numeric(th) && is_numeric(el); - } - return false; - } - - bool is_arith_expr(expr *e) const { - return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); - } - - bool is_offset(expr* e) const { - if (a.is_numeral(e)) { - return true; - } - expr* cond, *th, *el, *e1, *e2; - if (m.is_ite(e, cond, th, el)) { - return is_offset(th) && is_offset(el); - } - // recognize offsets. - if (a.is_add(e, e1, e2)) { - if (is_numeric(e1)) { - return is_offset(e2); - } - if (is_numeric(e2)) { - return is_offset(e1); - } - return false; - } - if (m_test_for_utvpi) { - if (a.is_mul(e, e1, e2)) { - if (is_minus_one(e1)) { - return is_offset(e2); - } - if (is_minus_one(e2)) { - return is_offset(e1); - } - } - } - return !is_arith_expr(e); - } - - bool is_minus_one(expr const * e) const { - rational r; - return a.is_numeral(e, r) && r.is_minus_one(); - } - - bool test_ineq(expr* e) const { - SASSERT(a.is_le(e) || a.is_ge(e) || m.is_eq(e)); - SASSERT(to_app(e)->get_num_args() == 2); - expr * lhs = to_app(e)->get_arg(0); - expr * rhs = to_app(e)->get_arg(1); - if (is_offset(lhs) && is_offset(rhs)) - { return true; } - if (!is_numeric(rhs)) - { std::swap(lhs, rhs); } - if (!is_numeric(rhs)) - { return false; } - // lhs can be 'x' or '(+ x (* -1 y))' - if (is_offset(lhs)) - { return true; } - expr* arg1, *arg2; - if (!a.is_add(lhs, arg1, arg2)) - { return false; } - // x - if (m_test_for_utvpi) { - return is_offset(arg1) && is_offset(arg2); - } - if (is_arith_expr(arg1)) - { std::swap(arg1, arg2); } - if (is_arith_expr(arg1)) - { return false; } - // arg2: (* -1 y) - expr* m1, *m2; - if (!a.is_mul(arg2, m1, m2)) - { return false; } - return is_minus_one(m1) && is_offset(m2); - } - - bool test_eq(expr* e) const { - expr* lhs, *rhs; - VERIFY(m.is_eq(e, lhs, rhs)); - if (!a.is_int_real(lhs)) { - return true; - } - if (a.is_numeral(lhs) || a.is_numeral(rhs)) { - return test_ineq(e); - } - return - test_term(lhs) && - test_term(rhs) && - !a.is_mul(lhs) && - !a.is_mul(rhs); - } - - bool test_term(expr* e) const { - if (m.is_bool(e)) { - return true; - } - if (a.is_numeral(e)) { - return true; - } - if (is_offset(e)) { - return true; - } - expr* lhs, *rhs; - if (a.is_add(e, lhs, rhs)) { - if (!a.is_numeral(lhs)) { - std::swap(lhs, rhs); - } - return a.is_numeral(lhs) && is_offset(rhs); - } - if (a.is_mul(e, lhs, rhs)) { - return is_minus_one(lhs) || is_minus_one(rhs); - } - return false; - } - - bool is_non_arith_or_basic(expr* e) - { - if (!is_app(e)) { - return false; - } - family_id fid = to_app(e)->get_family_id(); - - if (fid == null_family_id && - !m.is_bool(e) && - to_app(e)->get_num_args() > 0) { - return true; - } - return - fid != m.get_basic_family_id() && - fid != null_family_id && - fid != a.get_family_id() && - fid != bv.get_family_id(); - } - - public: - test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} - - void test_for_utvpi() { m_test_for_utvpi = true; } - - void operator()(expr* e) { - if (!m_is_dl) { - return; - } - if (a.is_le(e) || a.is_ge(e)) { - m_is_dl = test_ineq(e); - } else if (m.is_eq(e)) { - m_is_dl = test_eq(e); - } else if (is_non_arith_or_basic(e)) { - m_is_dl = false; - } else if (is_app(e)) { - app* a = to_app(e); - for (unsigned i = 0; m_is_dl && i < a->get_num_args(); ++i) { - m_is_dl = test_term(a->get_arg(i)); - } - } - - if (!m_is_dl) { - char const* msg = "non-diff: "; - if (m_test_for_utvpi) { - msg = "non-utvpi: "; - } - IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); - } - } - - bool is_dl() const { return m_is_dl; } - }; - - bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { - test_diff_logic test(m); - expr_fast_mark1 mark; - for (unsigned i = 0; i < num_fmls; ++i) { - quick_for_each_expr(test, mark, fmls[i]); - } - return test.is_dl(); - } - - bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { - test_diff_logic test(m); - test.test_for_utvpi(); - expr_fast_mark1 mark; - for (unsigned i = 0; i < num_fmls; ++i) { - quick_for_each_expr(test, mark, fmls[i]); - } - return test.is_dl(); - } - - void subst_vars(ast_manager& m, app_ref_vector const& vars, model* M, expr_ref& fml) { @@ -469,45 +141,45 @@ namespace spacer { sub (fml); } -void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) { - ast_manager &m = vars.m(); - ast_pp_util pp(m); - pp.collect(fml); - pp.display_decls(out); + void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) { + ast_manager &m = vars.m(); + ast_pp_util pp(m); + pp.collect(fml); + pp.display_decls(out); - out << "(define-fun mbp_benchmark_fml () Bool\n "; - out << mk_pp(fml, m) << ")\n\n"; + out << "(define-fun mbp_benchmark_fml () Bool\n "; + out << mk_pp(fml, m) << ")\n\n"; + + out << "(push)\n" + << "(assert mbp_benchmark_fml)\n" + << "(check-sat)\n" + << "(mbp mbp_benchmark_fml ("; + for (auto v : vars) {out << mk_pp(v, m) << " ";} + out << "))\n" + << "(pop)\n" + << "(exit)\n"; + } - out << "(push)\n" - << "(assert mbp_benchmark_fml)\n" - << "(check-sat)\n" - << "(mbp mbp_benchmark_fml ("; - for (auto v : vars) {out << mk_pp(v, m) << " ";} - out << "))\n" - << "(pop)\n" - << "(exit)\n"; -} - -void qe_project_z3 (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + void qe_project_z3 (ast_manager& m, app_ref_vector& vars, expr_ref& fml, const model_ref& M, bool reduce_all_selects, bool use_native_mbp, bool dont_sub) { - params_ref p; - p.set_bool("reduce_all_selects", reduce_all_selects); - p.set_bool("dont_sub", dont_sub); - - qe::mbp mbp(m, p); - // TODO: deal with const - model *mdl = const_cast(M.get()); - mbp.spacer(vars, *mdl, fml); -} - + params_ref p; + p.set_bool("reduce_all_selects", reduce_all_selects); + p.set_bool("dont_sub", dont_sub); + + qe::mbp mbp(m, p); + // TODO: deal with const + model *mdl = const_cast(M.get()); + mbp.spacer(vars, *mdl, fml); + } + /* * eliminate simple equalities using qe_lite * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays */ void qe_project_spacer (ast_manager& m, app_ref_vector& vars, expr_ref& fml, - const model_ref& M, bool reduce_all_selects, bool use_native_mbp, - bool dont_sub) { + const model_ref& M, bool reduce_all_selects, bool use_native_mbp, + bool dont_sub) { th_rewriter rw (m); TRACE ("spacer_mbp", tout << "Before projection:\n"; @@ -533,70 +205,70 @@ void qe_project_z3 (ast_manager& m, app_ref_vector& vars, expr_ref& fml, expr_ref bval (m); while (true) { - params_ref p; - qe_lite qe(m, p, false); - qe (vars, fml); - rw (fml); - - TRACE ("spacer_mbp", - tout << "After qe_lite:\n"; - tout << mk_pp (fml, m) << "\n"; - tout << "Vars:\n" << vars;); - - SASSERT (!m.is_false (fml)); - - - // sort out vars into bools, arith (int/real), and arrays - for (app* v : vars) { - if (m.is_bool (v)) { - // obtain the interpretation of the ith var using model completion - VERIFY (M->eval (v, bval, true)); - bool_sub.insert (v, bval); - } else if (arr_u.is_array(v)) { - array_vars.push_back (v); - } else { - SASSERT (ari_u.is_int (v) || ari_u.is_real (v)); - arith_vars.push_back (v); - } - } - - // substitute Booleans - if (!bool_sub.empty()) { - bool_sub (fml); - // -- bool_sub is not simplifying + params_ref p; + qe_lite qe(m, p, false); + qe (vars, fml); rw (fml); + + TRACE ("spacer_mbp", + tout << "After qe_lite:\n"; + tout << mk_pp (fml, m) << "\n"; + tout << "Vars:\n" << vars;); + SASSERT (!m.is_false (fml)); - TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); - bool_sub.reset (); + + + // sort out vars into bools, arith (int/real), and arrays + for (app* v : vars) { + if (m.is_bool (v)) { + // obtain the interpretation of the ith var using model completion + VERIFY (M->eval (v, bval, true)); + bool_sub.insert (v, bval); + } else if (arr_u.is_array(v)) { + array_vars.push_back (v); + } else { + SASSERT (ari_u.is_int (v) || ari_u.is_real (v)); + arith_vars.push_back (v); + } + } + + // substitute Booleans + if (!bool_sub.empty()) { + bool_sub (fml); + // -- bool_sub is not simplifying + rw (fml); + SASSERT (!m.is_false (fml)); + TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); + bool_sub.reset (); + } + + TRACE ("spacer_mbp", + tout << "Array vars:\n"; + tout << array_vars;); + + vars.reset (); + + // project arrays + { + scoped_no_proof _sp (m); + // -- local rewriter that is aware of current proof mode + th_rewriter srw(m); + spacer_qe::array_project (*M.get (), array_vars, fml, vars, reduce_all_selects); + SASSERT (array_vars.empty ()); + srw (fml); + SASSERT (!m.is_false (fml)); + } + + TRACE ("spacer_mbp", + tout << "extended model:\n"; + model_pp (tout, *M); + tout << "Auxiliary variables of index and value sorts:\n"; + tout << vars; + ); + + if (vars.empty()) { break; } } - - TRACE ("spacer_mbp", - tout << "Array vars:\n"; - tout << array_vars;); - - vars.reset (); - - // project arrays - { - scoped_no_proof _sp (m); - // -- local rewriter that is aware of current proof mode - th_rewriter srw(m); - spacer_qe::array_project (*M.get (), array_vars, fml, vars, reduce_all_selects); - SASSERT (array_vars.empty ()); - srw (fml); - SASSERT (!m.is_false (fml)); - } - - TRACE ("spacer_mbp", - tout << "extended model:\n"; - model_pp (tout, *M); - tout << "Auxiliary variables of index and value sorts:\n"; - tout << vars; - ); - - if (vars.empty()) { break; } - } - + // project reals and ints if (!arith_vars.empty ()) { TRACE ("spacer_mbp", tout << "Arith vars:\n" << arith_vars;); @@ -661,27 +333,26 @@ void qe_project_z3 (ast_manager& m, app_ref_vector& vars, expr_ref& fml, ptr_vector const& acc, unsigned j, func_decl* f, - expr* c) -{ + expr* c) + { if (is_app(c) && to_app(c)->get_decl() == f) { return to_app(c)->get_arg(j); - } else { + } else { return m.mk_app(acc[j], c); } } -void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, - const model_ref& M, bool reduce_all_selects, bool use_native_mbp, - bool dont_sub) { - if (use_native_mbp) - qe_project_z3(m, vars, fml, M, reduce_all_selects, use_native_mbp, dont_sub); - else - qe_project_spacer(m, vars, fml, M, reduce_all_selects, use_native_mbp, dont_sub); -} + void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + const model_ref& M, bool reduce_all_selects, bool use_native_mbp, + bool dont_sub) { + if (use_native_mbp) + qe_project_z3(m, vars, fml, M, reduce_all_selects, use_native_mbp, dont_sub); + else + qe_project_spacer(m, vars, fml, M, reduce_all_selects, use_native_mbp, dont_sub); + } -void expand_literals(ast_manager &m, expr_ref_vector& conjs) -{ - if (conjs.empty()) { return; } + void expand_literals(ast_manager &m, expr_ref_vector& conjs) { + if (conjs.empty()) { return; } arith_util arith(m); datatype_util dt(m); bv_util bv(m); @@ -689,11 +360,7 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) rational r; unsigned bv_size; - TRACE("spacer_expand", - tout << "begin expand\n"; - for (unsigned i = 0; i < conjs.size(); ++i) { - tout << mk_pp(conjs[i].get(), m) << "\n"; - }); + TRACE("spacer_expand", tout << "begin expand\n" << conjs << "\n";); for (unsigned i = 0; i < conjs.size(); ++i) { expr* e = conjs[i].get(); @@ -701,13 +368,13 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) conjs[i] = arith.mk_le(e1,e2); if (i+1 == conjs.size()) { conjs.push_back(arith.mk_ge(e1, e2)); - } else { + } else { conjs.push_back(conjs[i+1].get()); conjs[i+1] = arith.mk_ge(e1, e2); } ++i; - } else if ((m.is_eq(e, c, val) && is_app(val) && dt.is_constructor(to_app(val))) || - (m.is_eq(e, val, c) && is_app(val) && dt.is_constructor(to_app(val)))){ + } else if ((m.is_eq(e, c, val) && is_app(val) && dt.is_constructor(to_app(val))) || + (m.is_eq(e, val, c) && is_app(val) && dt.is_constructor(to_app(val)))) { func_decl* f = to_app(val)->get_decl(); func_decl* r = dt.get_constructor_is(f); conjs[i] = m.mk_app(r, c); @@ -715,12 +382,11 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) for (unsigned j = 0; j < acc.size(); ++j) { conjs.push_back(m.mk_eq(apply_accessor(m, acc, j, f, c), to_app(val)->get_arg(j))); } - } else if ((m.is_eq(e, c, val) && bv.is_numeral(val, r, bv_size)) || - (m.is_eq(e, val, c) && bv.is_numeral(val, r, bv_size))) { + } else if ((m.is_eq(e, c, val) && bv.is_numeral(val, r, bv_size)) || + (m.is_eq(e, val, c) && bv.is_numeral(val, r, bv_size))) { rational two(2); for (unsigned j = 0; j < bv_size; ++j) { parameter p(j); - //expr* e = m.mk_app(bv.get_family_id(), OP_BIT2BOOL, 1, &p, 1, &c); expr* e = m.mk_eq(m.mk_app(bv.get_family_id(), OP_BIT1), bv.mk_extract(j, j, c)); if ((r % two).is_zero()) { e = m.mk_not(e); @@ -728,21 +394,17 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) r = div(r, two); if (j == 0) { conjs[i] = e; - } else { + } else { conjs.push_back(e); } } } } - TRACE("spacer_expand", - tout << "end expand\n"; - for (unsigned i = 0; i < conjs.size(); ++i) { - tout << mk_pp(conjs[i].get(), m) << "\n"; - }); + TRACE("spacer_expand", tout << "end expand\n" << conjs << "\n";); } namespace { -class implicant_picker { + class implicant_picker { model_evaluator_util &m_mev; ast_manager &m; arith_util m_arith; @@ -751,8 +413,7 @@ class implicant_picker { expr_mark m_visited; - void add_literal (expr *e, expr_ref_vector &out) - { + void add_literal (expr *e, expr_ref_vector &out) { SASSERT (m.is_bool (e)); expr_ref res (m), v(m); @@ -773,251 +434,245 @@ class implicant_picker { if (m.is_not(res, nres)) { // -- (not (xor a b)) == (= a b) if (m.is_xor(nres, f1, f2)) - { res = m.mk_eq(f1, f2); } - + { res = m.mk_eq(f1, f2); } + // -- split arithmetic inequality else if (m.is_eq (nres, f1, f2) && m_arith.is_int_real (f1)) { expr_ref u(m); u = m_arith.mk_lt(f1, f2); if (m_mev.eval (u, v, false) && m.is_true (v)) - { res = u; } + { res = u; } else - { res = m_arith.mk_lt(f2, f1); } + { res = m_arith.mk_lt(f2, f1); } } } - if (!m_mev.is_true (res)) - { verbose_stream() << "Bad literal: " << mk_pp(res, m) << "\n"; } + if (!m_mev.is_true (res)) { + verbose_stream() << "Bad literal: " << mk_pp(res, m) << "\n"; + } SASSERT (m_mev.is_true (res)); out.push_back (res); } - void process_app(app *a, expr_ref_vector &out) - { - if (m_visited.is_marked(a)) { return; } + void process_app(app *a, expr_ref_vector &out) { + if (m_visited.is_marked(a)) { return; } SASSERT (m.is_bool (a)); expr_ref v(m); m_mev.eval (a, v, false); - - if (!m.is_true(v) && !m.is_false(v)) { return; } - + bool is_true = m.is_true(v); + + if (!is_true && !m.is_false(v)) return; + expr *na, *f1, *f2, *f3; - - if (a->get_family_id() != m.get_basic_family_id()) - { add_literal(a, out); } - else if (is_uninterp_const(a)) - { add_literal(a, out); } - else if (m.is_not(a, na) && m.is_not(na, na)) - { m_todo.push_back(na); } - else if (m.is_not(a, na)) - { m_todo.push_back(na); } + + if (a->get_family_id() != m.get_basic_family_id()) { + add_literal(a, out); + } + else if (is_uninterp_const(a)) { + add_literal(a, out); + } + else if (m.is_not(a, na)) { + m_todo.push_back(na); + } else if (m.is_distinct(a)) { - if (m.is_false(v)) - m_todo.push_back - (qe::project_plugin::pick_equality(m, *m_mev.get_model(), a)); - else if (a->get_num_args() == 2) - { add_literal(a, out); } - else - m_todo.push_back(m.mk_distinct_expanded(a->get_num_args(), - a->get_args())); - } else if (m.is_and(a)) { - if (m.is_true(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } - else if (m.is_false(v)) { - for (unsigned i = 0, sz = a->get_num_args (); i < sz; ++i) { - if (m_mev.is_false(a->get_arg(i))) { - m_todo.push_back(a->get_arg(i)); + if (!is_true) { + f1 = qe::project_plugin::pick_equality(m, *m_mev.get_model(), a); + m_todo.push_back(f1); + } + else if (a->get_num_args() == 2) { + add_literal(a, out); + } + else { + m_todo.push_back(m.mk_distinct_expanded(a->get_num_args(), a->get_args())); + } + } + else if (m.is_and(a)) { + if (is_true) { + m_todo.append(a->get_num_args(), a->get_args()); + } + else { + for (expr* e : *a) { + if (m_mev.is_false(e)) { + m_todo.push_back(e); break; } } } - } else if (m.is_or(a)) { - if (m.is_false(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } - else if (m.is_true(v)) { - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - if (m_mev.is_true(a->get_arg(i))) { - m_todo.push_back(a->get_arg(i)); + } + else if (m.is_or(a)) { + if (!is_true) + m_todo.append(a->get_num_args(), a->get_args()); + else { + for (expr * e : *a) { + if (m_mev.is_true(e)) { + m_todo.push_back(e); break; } } } - } else if (m.is_iff(a, f1, f2) || m.is_eq(a, f1, f2) || - (m.is_true(v) && m.is_not(a, na) && m.is_xor (na, f1, f2))) { + } + else if (m.is_eq(a, f1, f2) || (is_true && m.is_not(a, na) && m.is_xor (na, f1, f2))) { if (!m.are_equal(f1, f2) && !m.are_distinct(f1, f2)) { - if (m.is_bool(f1) && - (!is_uninterp_const(f1) || !is_uninterp_const(f2))) - { m_todo.append(a->get_num_args(), a->get_args()); } + if (m.is_bool(f1) && (!is_uninterp_const(f1) || !is_uninterp_const(f2))) + m_todo.append(a->get_num_args(), a->get_args()); else - { add_literal(a, out); } + add_literal(a, out); + } + } + else if (m.is_ite(a, f1, f2, f3)) { + if (m.are_equal(f2, f3)) { + m_todo.push_back(f2); } - } else if (m.is_ite(a, f1, f2, f3)) { - if (m.are_equal(f2, f3)) { m_todo.push_back(f2); } else if (m_mev.is_true (f2) && m_mev.is_true (f3)) { - m_todo.push_back(f2); - m_todo.push_back(f3); - } else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { - m_todo.push_back(f2); - m_todo.push_back(f3); - } else if (m_mev.is_true(f1)) { - m_todo.push_back(f1); - m_todo.push_back(f2); - } else if (m_mev.is_false(f1)) { - m_todo.push_back(f1); - m_todo.push_back(f3); + m_todo.push_back(f2); + m_todo.push_back(f3); + } + else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { + m_todo.push_back(f2); + m_todo.push_back(f3); + } + else if (m_mev.is_true(f1)) { + m_todo.push_back(f1); + m_todo.push_back(f2); + } + else if (m_mev.is_false(f1)) { + m_todo.push_back(f1); + m_todo.push_back(f3); } - } else if (m.is_xor(a, f1, f2)) - { m_todo.append(a->get_num_args(), a->get_args()); } + } + else if (m.is_xor(a, f1, f2)) { + m_todo.append(a->get_num_args(), a->get_args()); + } else if (m.is_implies(a, f1, f2)) { - if (m.is_true (v)) { - if (m_mev.is_true(f2)) { m_todo.push_back(f2); } - else if (m_mev.is_false(f1)) { m_todo.push_back(f1); } - } else if (m.is_false(v)) - { m_todo.append(a->get_num_args(), a->get_args()); } - } else if (m.is_true(a) || m.is_false(a)) { /* nothing */ } + if (is_true) { + if (m_mev.is_true(f2)) + m_todo.push_back(f2); + else if (m_mev.is_false(f1)) + m_todo.push_back(f1); + } + else + m_todo.append(a->get_num_args(), a->get_args()); + } else { - verbose_stream () << "Unexpected expression: " - << mk_pp(a, m) << "\n"; + IF_VERBOSE(0, verbose_stream () << "Unexpected expression: " << mk_pp(a, m) << "\n"); UNREACHABLE(); } } - - void pick_literals(expr *e, expr_ref_vector &out) - { + + void pick_literals(expr *e, expr_ref_vector &out) { SASSERT(m_todo.empty()); - if (m_visited.is_marked(e)) { return; } - SASSERT(is_app(e)); - + if (m_visited.is_marked(e) || !is_app(e)) return; + m_todo.push_back(e); do { - app *a = to_app(m_todo.back()); + e = m_todo.back(); + if (!is_app(e)) continue; + app * a = to_app(e); m_todo.pop_back(); process_app(a, out); m_visited.mark(a, true); } while (!m_todo.empty()); } - - bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) - { + + bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) { m_visited.reset(); - expr_ref e(m); - e = mk_and (in); - bool is_true = m_mev.is_true (e); - - for (unsigned i = 0, sz = in.size (); i < sz; ++i) { - if (is_true || m_mev.is_true(in.get(i))) - { pick_literals(in.get(i), out); } + bool is_true = m_mev.is_true (in); + + for (expr* e : in) { + if (is_true || m_mev.is_true(e)) { + pick_literals(e, out); + } } - m_visited.reset (); return is_true; } public: + implicant_picker (model_evaluator_util &mev) : m_mev (mev), m (m_mev.get_ast_manager ()), m_arith(m), m_todo(m) {} - - void operator() (expr_ref_vector &in, expr_ref_vector& out) - {pick_implicant (in, out);} - }; - } - - void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, - expr_ref_vector &res) { - // XXX what is the point of flattening? - flatten_and (formula); - if (formula.empty()) { return; } - - implicant_picker ipick (mev); - ipick (formula, res); - } - -void simplify_bounds_old(expr_ref_vector& cube) { - ast_manager& m = cube.m(); - - scoped_no_proof _no_pf_(m); - goal_ref g(alloc(goal, m, false, false, false)); - - for (unsigned i = 0; i < cube.size(); ++i) { - g->assert_expr(cube.get(i)); - } - - expr_ref tmp(m); - goal_ref_buffer result; - tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result); - SASSERT(result.size() == 1); - goal* r = result[0]; - - cube.reset(); - for (unsigned i = 0; i < r->size(); ++i) { - cube.push_back(r->form(i)); - } -} - -void simplify_bounds_new (expr_ref_vector &cube) { - ast_manager &m = cube.m(); - - - scoped_no_proof _no_pf_(m); - - goal_ref g(alloc(goal, m, false, false, false)); - for (unsigned i = 0, sz = cube.size(); i < sz; ++i) { - g->assert_expr(cube.get(i)); - } - - goal_ref_buffer goals; - tactic_ref prop_values = mk_propagate_values_tactic(m); - tactic_ref prop_bounds = mk_propagate_ineqs_tactic(m); - tactic_ref t = and_then(prop_values.get(), prop_bounds.get()); - - (*t)(g, goals); - SASSERT(goals.size() == 1); - - g = goals[0]; - cube.reset(); - for (unsigned i = 0; i < g->size(); ++i) { - cube.push_back(g->form(i)); - } -} - -void simplify_bounds(expr_ref_vector &cube) { - simplify_bounds_new(cube); -} - -/// Adhoc rewriting of arithmetic expressions -struct adhoc_rewriter_cfg : public default_rewriter_cfg { - ast_manager &m; - arith_util m_util; - - adhoc_rewriter_cfg (ast_manager &manager) : m(manager), m_util(m) {} - - bool is_le(func_decl const * n) const - { return is_decl_of(n, m_util.get_family_id (), OP_LE); } - bool is_ge(func_decl const * n) const - { return is_decl_of(n, m_util.get_family_id (), OP_GE); } - - br_status reduce_app (func_decl * f, unsigned num, expr * const * args, - expr_ref & result, proof_ref & result_pr) - { - expr * e; - br_status st = BR_FAILED; - if (is_le(f)) { - st = mk_le_core (args[0], args[1], result); - } else if (is_ge(f)) { - st = mk_ge_core (args[0], args[1], result); - } else if (m.is_not(f)) { - if (m.is_not (args[0], e)) { - result = e; - st = BR_DONE; - } - } - - return st; + + void operator() (expr_ref_vector &in, expr_ref_vector& out) { + pick_implicant (in, out); } + }; +} - br_status mk_le_core (expr *arg1, expr * arg2, expr_ref & result) - { + void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, + expr_ref_vector &res) { + implicant_picker ipick (mev); + ipick (formula, res); + } + + void simplify_bounds_old(expr_ref_vector& cube) { + ast_manager& m = cube.m(); + scoped_no_proof _no_pf_(m); + goal_ref g(alloc(goal, m, false, false, false)); + for (expr* c : cube) + g->assert_expr(c); + + goal_ref_buffer result; + tactic_ref simplifier = mk_arith_bounds_tactic(m); + (*simplifier)(g, result); + SASSERT(result.size() == 1); + goal* r = result[0]; + cube.reset(); + for (unsigned i = 0; i < r->size(); ++i) { + cube.push_back(r->form(i)); + } + } + + void simplify_bounds_new (expr_ref_vector &cube) { + ast_manager &m = cube.m(); + scoped_no_proof _no_pf_(m); + goal_ref g(alloc(goal, m, false, false, false)); + for (expr* c : cube) + g->assert_expr(c); + + goal_ref_buffer goals; + tactic_ref prop_values = mk_propagate_values_tactic(m); + tactic_ref prop_bounds = mk_propagate_ineqs_tactic(m); + tactic_ref t = and_then(prop_values.get(), prop_bounds.get()); + + (*t)(g, goals); + SASSERT(goals.size() == 1); + + g = goals[0]; + cube.reset(); + for (unsigned i = 0; i < g->size(); ++i) { + cube.push_back(g->form(i)); + } + } + + void simplify_bounds(expr_ref_vector &cube) { + simplify_bounds_new(cube); + } + + /// Adhoc rewriting of arithmetic expressions + struct adhoc_rewriter_cfg : public default_rewriter_cfg { + ast_manager &m; + arith_util m_util; + + adhoc_rewriter_cfg (ast_manager &manager) : m(manager), m_util(m) {} + + bool is_le(func_decl const * n) const { return m_util.is_le(n); } + bool is_ge(func_decl const * n) const { return m_util.is_ge(n); } + + br_status reduce_app (func_decl * f, unsigned num, expr * const * args, + expr_ref & result, proof_ref & result_pr) { + expr * e; + if (is_le(f)) + return mk_le_core (args[0], args[1], result); + if (is_ge(f)) + return mk_ge_core (args[0], args[1], result); + if (m.is_not(f) && m.is_not (args[0], e)) { + result = e; + return BR_DONE; + } + return BR_FAILED; + } + + br_status mk_le_core (expr *arg1, expr * arg2, expr_ref & result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) if (m_util.is_int (arg1) && m_util.is_minus_one (arg2)) { result = m.mk_not (m_util.mk_ge (arg1, mk_zero ())); @@ -1025,63 +680,63 @@ struct adhoc_rewriter_cfg : public default_rewriter_cfg { } return BR_FAILED; } - br_status mk_ge_core (expr * arg1, expr * arg2, expr_ref & result) - { + br_status mk_ge_core (expr * arg1, expr * arg2, expr_ref & result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) if (m_util.is_int (arg1) && is_one (arg2)) { - + result = m.mk_not (m_util.mk_le (arg1, mk_zero ())); return BR_DONE; } return BR_FAILED; } - expr * mk_zero () {return m_util.mk_numeral (rational (0), true);} - bool is_one (expr const * n) const - {rational val; return m_util.is_numeral (n, val) && val.is_one ();} -}; + expr * mk_zero () {return m_util.mk_numeral (rational (0), true);} + bool is_one (expr const * n) const { + rational val; return m_util.is_numeral (n, val) && val.is_one (); + } + }; -void normalize (expr *e, expr_ref &out, - bool use_simplify_bounds, - bool use_factor_eqs) -{ - - params_ref params; - // arith_rewriter - params.set_bool ("sort_sums", true); - params.set_bool ("gcd_rounding", true); - params.set_bool ("arith_lhs", true); - // poly_rewriter - params.set_bool ("som", true); - params.set_bool ("flat", true); - - // apply rewriter - th_rewriter rw(out.m(), params); - rw (e, out); - - adhoc_rewriter_cfg adhoc_cfg(out.m ()); - rewriter_tpl adhoc_rw (out.m (), false, adhoc_cfg); - adhoc_rw (out.get (), out); - - if (out.m().is_and(out)) { - expr_ref_vector v(out.m()); - flatten_and (out, v); - - if (v.size() > 1) { - // sort arguments of the top-level and - std::stable_sort (v.c_ptr(), v.c_ptr () + v.size (), ast_lt_proc()); - - if (use_simplify_bounds) { - // remove redundant inequalities - simplify_bounds (v); - } - if (use_factor_eqs) { - // -- refactor equivalence classes and choose a representative - spacer::term_graph egraph(out.m()); - egraph.add_lits (v); - v.reset(); - egraph.to_lits(v); - } + void normalize (expr *e, expr_ref &out, + bool use_simplify_bounds, + bool use_factor_eqs) + { + + params_ref params; + // arith_rewriter + params.set_bool ("sort_sums", true); + params.set_bool ("gcd_rounding", true); + params.set_bool ("arith_lhs", true); + // poly_rewriter + params.set_bool ("som", true); + params.set_bool ("flat", true); + + // apply rewriter + th_rewriter rw(out.m(), params); + rw (e, out); + + adhoc_rewriter_cfg adhoc_cfg(out.m ()); + rewriter_tpl adhoc_rw (out.m (), false, adhoc_cfg); + adhoc_rw (out.get (), out); + if (out.m().is_and(out)) { + expr_ref_vector v(out.m()); + flatten_and (out, v); + + if (v.size() > 1) { + // sort arguments of the top-level and + std::stable_sort (v.c_ptr(), v.c_ptr() + v.size(), ast_lt_proc()); + + if (use_simplify_bounds) { + // remove redundant inequalities + simplify_bounds (v); + } + if (use_factor_eqs) { + // -- refactor equivalence classes and choose a representative + spacer::term_graph egraph(out.m()); + egraph.add_lits (v); + v.reset(); + egraph.to_lits(v); + } + TRACE("spacer_normalize", tout << "Normalized:\n" << out << "\n" @@ -1089,39 +744,33 @@ void normalize (expr *e, expr_ref &out, << mk_and(v) << "\n";); TRACE("spacer_normalize", spacer::term_graph egraph(out.m()); - for (unsigned i = 0, sz = v.size(); i < sz; ++i) - egraph.add_lit (to_app(v.get(i))); + for (expr* e : v) egraph.add_lit (to_app(e)); tout << "Reduced app:\n" << mk_pp(egraph.to_app(), out.m()) << "\n";); - out = mk_and (v); + out = mk_and (v); + } } } -} -// rewrite term such that the pretty printing is easier to read -struct adhoc_rewriter_rpp : public default_rewriter_cfg { - ast_manager &m; - arith_util m_arith; - - adhoc_rewriter_rpp (ast_manager &manager) : m(manager), m_arith(m) {} - - bool is_le(func_decl const * n) const - { return is_decl_of(n, m_arith.get_family_id (), OP_LE); } - bool is_ge(func_decl const * n) const - { return is_decl_of(n, m_arith.get_family_id (), OP_GE); } - bool is_lt(func_decl const * n) const - { return is_decl_of(n, m_arith.get_family_id (), OP_LT); } - bool is_gt(func_decl const * n) const - { return is_decl_of(n, m_arith.get_family_id (), OP_GT); } - bool is_zero (expr const * n) const - {rational val; return m_arith.is_numeral(n, val) && val.is_zero();} - - br_status reduce_app (func_decl * f, unsigned num, expr * const * args, - expr_ref & result, proof_ref & result_pr) + // rewrite term such that the pretty printing is easier to read + struct adhoc_rewriter_rpp : public default_rewriter_cfg { + ast_manager &m; + arith_util m_arith; + + adhoc_rewriter_rpp (ast_manager &manager) : m(manager), m_arith(m) {} + + bool is_le(func_decl const * n) const { return m_arith.is_le(n); } + bool is_ge(func_decl const * n) const { return m_arith.is_ge(n); } + bool is_lt(func_decl const * n) const { return m_arith.is_lt(n); } + bool is_gt(func_decl const * n) const { return m_arith.is_gt(n); } + bool is_zero (expr const * n) const {rational val; return m_arith.is_numeral(n, val) && val.is_zero();} + + br_status reduce_app (func_decl * f, unsigned num, expr * const * args, + expr_ref & result, proof_ref & result_pr) { br_status st = BR_FAILED; expr *e1, *e2, *e3, *e4; - + // rewrites (= (+ A (* -1 B)) 0) into (= A B) if (m.is_eq (f) && is_zero (args [1]) && m_arith.is_add (args[0], e1, e2) && @@ -1170,67 +819,63 @@ struct adhoc_rewriter_rpp : public default_rewriter_cfg { } return st; } + }; -}; - -mk_epp::mk_epp(ast *t, ast_manager &m, unsigned indent, - unsigned num_vars, char const * var_prefix) : - mk_pp (t, m, m_epp_params, indent, num_vars, var_prefix), m_epp_expr(m) { - m_epp_params.set_uint("min_alias_size", UINT_MAX); - m_epp_params.set_uint("max_depth", UINT_MAX); - - if (is_expr (m_ast)) { - rw(to_expr(m_ast), m_epp_expr); - m_ast = m_epp_expr; + mk_epp::mk_epp(ast *t, ast_manager &m, unsigned indent, + unsigned num_vars, char const * var_prefix) : + mk_pp (t, m, m_epp_params, indent, num_vars, var_prefix), m_epp_expr(m) { + m_epp_params.set_uint("min_alias_size", UINT_MAX); + m_epp_params.set_uint("max_depth", UINT_MAX); + + if (is_expr (m_ast)) { + rw(to_expr(m_ast), m_epp_expr); + m_ast = m_epp_expr; + } } -} - -void mk_epp::rw(expr *e, expr_ref &out) -{ - adhoc_rewriter_rpp cfg(out.m()); - rewriter_tpl arw(out.m(), false, cfg); - arw(e, out); -} - -void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { - expr_free_vars fv; - ast_manager &m = out.get_manager(); - - fv(e); - if (vars.size() < fv.size()) { - vars.resize(fv.size()); + + void mk_epp::rw(expr *e, expr_ref &out) { + adhoc_rewriter_rpp cfg(out.m()); + rewriter_tpl arw(out.m(), false, cfg); + arw(e, out); } - for (unsigned i = 0, sz = fv.size(); i < sz; ++i) { - sort *s = fv[i] ? fv[i] : m.mk_bool_sort(); - vars[i] = mk_zk_const(m, i, s); - var_subst vs(m, false); - vs(e, vars.size(), (expr * *) vars.c_ptr(), out); + + void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { + expr_free_vars fv; + ast_manager &m = out.get_manager(); + + fv(e); + if (vars.size() < fv.size()) { + vars.resize(fv.size()); + } + for (unsigned i = 0, sz = fv.size(); i < sz; ++i) { + sort *s = fv[i] ? fv[i] : m.mk_bool_sort(); + vars[i] = mk_zk_const(m, i, s); + var_subst vs(m, false); + vs(e, vars.size(), (expr * *) vars.c_ptr(), out); + } } -} - struct index_term_finder { - ast_manager &m; - array_util m_array; - app_ref m_var; + ast_manager &m; + array_util m_array; + app_ref m_var; expr_ref_vector &m_res; index_term_finder (ast_manager &mgr, app* v, expr_ref_vector &res) : m(mgr), m_array (m), m_var (v, m), m_res (res) {} void operator() (var *n) {} void operator() (quantifier *n) {} void operator() (app *n) { - expr *e1, *e2; - if (m_array.is_select (n) && n->get_arg (1) != m_var) { - m_res.push_back (n->get_arg (1)); - } else if (m.is_eq(n, e1, e2)) { - if (e1 == m_var) { m_res.push_back(e2); } - else if (e2 == m_var) { m_res.push_back(e1); } - } + if (m_array.is_select (n) || m.is_eq(n)) { + unsigned i = 0; + for (expr * arg : *n) { + if ((m.is_eq(n) || i > 0) && m_var != arg) m_res.push_back (arg); + ++i; + } + } } }; - bool mbqi_project_var (model_evaluator_util &mev, app* var, expr_ref &fml) - { + bool mbqi_project_var (model_evaluator_util &mev, app* var, expr_ref &fml) { ast_manager &m = fml.get_manager (); expr_ref val(m); @@ -1238,26 +883,21 @@ void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { TRACE ("mbqi_project_verbose", tout << "MBQI: var: " << mk_pp (var, m) << "\n" - << "fml: " << mk_pp (fml, m) << "\n";); + << "fml: " << fml << "\n";); expr_ref_vector terms (m); index_term_finder finder (m, var, terms); for_each_expr (finder, fml); - TRACE ("mbqi_project_verbose", - tout << "terms:\n"; - for (unsigned i = 0, e = terms.size (); i < e; ++i) - tout << i << ": " << mk_pp (terms.get (i), m) << "\n"; - ); - - for (unsigned i = 0, e = terms.size(); i < e; ++i) { - expr* term = terms.get (i); + tout << "terms:\n" << terms << "\n";); + + for (expr * term : terms) { expr_ref tval (m); mev.eval (term, tval, false); TRACE ("mbqi_project_verbose", tout << "term: " << mk_pp (term, m) - << " tval: " << mk_pp (tval, m) + << " tval: " << tval << " val: " << mk_pp (val, m) << "\n";); // -- if the term does not contain an occurrence of var @@ -1273,13 +913,12 @@ void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { } TRACE ("mbqi_project", - tout << "MBQI: failed to eliminate " << mk_pp (var, m) << " from " << mk_pp (fml, m) << "\n";); + tout << "MBQI: failed to eliminate " << mk_pp (var, m) << " from " << fml << "\n";); return false; } - void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml) - { + void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml) { ast_manager &m = fml.get_manager (); model_evaluator_util mev(m); mev.set_model (M); @@ -1288,110 +927,67 @@ void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { mev.eval (fml, tmp, false); tmp.reset (); - for (unsigned idx = 0; idx < vars.size (); ) { - if (mbqi_project_var (mev, vars.get (idx), fml)) { - vars[idx] = vars.back (); - vars.pop_back (); - } else { - idx++; - } + unsigned j = 0; + for (app* v : vars) + if (!mbqi_project_var (mev, v, fml)) + vars[j++] = v; + vars.shrink(j); + } + + struct found {}; + struct check_select { + array_util a; + check_select(ast_manager& m): a(m) {} + void operator()(expr* n) {} + void operator()(app* n) { if (a.is_select(n)) throw found(); } + }; + + bool contains_selects(expr* fml, ast_manager& m) { + check_select cs(m); + try { + for_each_expr(cs, fml); + return false; + } + catch (found) { + return true; } } -bool contains_selects(expr* fml, ast_manager& m) -{ - array_util a_util(m); - if (!is_app(fml)) { return false; } - ast_mark done; - ptr_vector todo; - todo.push_back (to_app (fml)); - while (!todo.empty ()) { - app* a = todo.back (); - if (done.is_marked (a)) { - todo.pop_back (); - continue; - } - unsigned num_args = a->get_num_args (); - bool all_done = true; - for (unsigned i = 0; i < num_args; i++) { - expr* arg = a->get_arg (i); - if (!done.is_marked (arg) && is_app (arg)) { - todo.push_back (to_app (arg)); - all_done = false; - } - } - if (!all_done) { continue; } - todo.pop_back (); - if (a_util.is_select (a)) - { return true; } - done.mark (a, true); + struct collect_indices { + app_ref_vector& m_indices; + array_util a; + collect_indices(app_ref_vector& indices): m_indices(indices), a(indices.get_manager()) {} + void operator()(expr* n) {} + void operator()(app* n) { + if (a.is_select (n)) + for (unsigned i = 1; i < n->get_num_args(); ++i) + if (is_app(n->get_arg(i))) + m_indices.push_back(to_app(n->get_arg(i))); } - return false; + }; + + void get_select_indices(expr* fml, app_ref_vector &indices, ast_manager& m) { + collect_indices ci(indices); + for_each_expr(ci, fml); + } + + struct collect_decls { + app_ref_vector& m_decls; + std::string& prefix; + collect_decls(app_ref_vector& decls, std::string& p): m_decls(decls), prefix(p) {} + void operator()(expr* n) {} + void operator()(app* n) { + if (n->get_decl()->get_name().str().find(prefix) != std::string::npos) + m_decls.push_back(n); + } + }; + + void find_decls(expr* fml, app_ref_vector& decls, std::string& prefix) { + collect_decls cd(decls, prefix); + for_each_expr(cd, fml); } -void get_select_indices(expr* fml, app_ref_vector &indices, ast_manager& m) -{ - array_util a_util(m); - if (!is_app(fml)) { return; } - ast_mark done; - ptr_vector todo; - todo.push_back (to_app (fml)); - while (!todo.empty ()) { - app* a = todo.back (); - if (done.is_marked (a)) { - todo.pop_back (); - continue; - } - unsigned num_args = a->get_num_args (); - bool all_done = true; - for (unsigned i = 0; i < num_args; i++) { - expr* arg = a->get_arg (i); - if (!done.is_marked (arg) && is_app (arg)) { - todo.push_back (to_app (arg)); - all_done = false; - } - } - if (!all_done) { continue; } - todo.pop_back (); - if (a_util.is_select (a)) { - SASSERT(a->get_num_args() == 2); - indices.push_back(to_app(a->get_arg(1))); - } - done.mark (a, true); - } - } - -void find_decls(expr* fml, app_ref_vector& decls, std::string& prefix) -{ - if (!is_app(fml)) { return; } - ast_mark done; - ptr_vector todo; - todo.push_back (to_app (fml)); - while (!todo.empty ()) { - app* a = todo.back (); - if (done.is_marked (a)) { - todo.pop_back (); - continue; - } - unsigned num_args = a->get_num_args (); - bool all_done = true; - for (unsigned i = 0; i < num_args; i++) { - expr* arg = a->get_arg (i); - if (!done.is_marked (arg) && is_app (arg)) { - todo.push_back (to_app (arg)); - all_done = false; - } - } - if (!all_done) { continue; } - todo.pop_back (); - if (a->get_decl()->get_name().str().find(prefix) != std::string::npos) - { decls.push_back(a); } - done.mark (a, true); - } - return; } -} template class rewriter_tpl; template class rewriter_tpl; -template class rewriter_tpl; diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index ffbd81de7..f43195a97 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -44,135 +44,120 @@ class model_evaluator; namespace spacer { -inline unsigned infty_level () {return UINT_MAX;} - -inline bool is_infty_level(unsigned lvl) -{ return lvl == infty_level (); } - -inline unsigned next_level(unsigned lvl) -{ return is_infty_level(lvl)?lvl:(lvl+1); } - -inline unsigned prev_level (unsigned lvl) -{ - if(is_infty_level(lvl)) { return infty_level(); } - if(lvl == 0) { return 0; } - return lvl -1; -} - -struct pp_level { - unsigned m_level; - pp_level(unsigned l): m_level(l) {} -}; - -inline std::ostream& operator<<(std::ostream& out, pp_level const& p) -{ - if (is_infty_level(p.m_level)) { - return out << "oo"; - } else { - return out << p.m_level; + inline unsigned infty_level () { + return UINT_MAX; } -} + inline bool is_infty_level(unsigned lvl) { + return lvl == infty_level (); + } + inline unsigned next_level(unsigned lvl) { + return is_infty_level(lvl)?lvl:(lvl+1); + } + inline unsigned prev_level (unsigned lvl) { + if (is_infty_level(lvl)) return infty_level(); + if (lvl == 0) return 0; + return lvl - 1; + } -typedef ptr_vector app_vector; -typedef ptr_vector decl_vector; -typedef obj_hashtable func_decl_set; + struct pp_level { + unsigned m_level; + pp_level(unsigned l): m_level(l) {} + }; + inline std::ostream& operator<<(std::ostream& out, pp_level const& p) { + if (is_infty_level(p.m_level)) { + return out << "oo"; + } else { + return out << p.m_level; + } + } -class model_evaluator_util { - ast_manager& m; - model_ref m_model; - model_evaluator* m_mev; + typedef ptr_vector app_vector; + typedef ptr_vector decl_vector; + typedef obj_hashtable func_decl_set; + + // TBD: deprecate + class model_evaluator_util { + ast_manager& m; + model_ref m_model; + model_evaluator* m_mev; + + /// initialize with a given model. All previous state is lost. model can be NULL + void reset (model *model); + public: + model_evaluator_util(ast_manager& m); + ~model_evaluator_util(); + + void set_model(model &model) {reset (&model);} + model_ref &get_model() {return m_model;} + ast_manager& get_ast_manager() const {return m;} + + public: + bool is_true (const expr_ref_vector &v); + bool is_false(expr* x); + bool is_true(expr* x); + + bool eval (const expr_ref_vector &v, expr_ref &result, bool model_completion); + /// evaluates an expression + bool eval (expr *e, expr_ref &result, bool model_completion); + // expr_ref eval(expr* e, bool complete=true); + }; - /// initialize with a given model. All previous state is lost. model can be NULL - void reset (model *model); -public: - model_evaluator_util(ast_manager& m); - ~model_evaluator_util(); + /** + \brief hoist non-boolean if expressions. + */ + + void to_mbp_benchmark(std::ostream &out, const expr* fml, const app_ref_vector &vars); - void set_model(model &model) {reset (&model);} - model_ref &get_model() {return m_model;} - ast_manager& get_ast_manager() const {return m;} + + // TBD: deprecate by qe::mbp + /** + * do the following in sequence + * 1. use qe_lite to cheaply eliminate vars + * 2. for remaining boolean vars, substitute using M + * 3. use MBP for remaining array and arith variables + * 4. for any remaining arith variables, substitute using M + */ + void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + const model_ref& M, bool reduce_all_selects=false, bool native_mbp=false, + bool dont_sub=false); -public: - bool is_true (const expr_ref_vector &v); - bool is_false(expr* x); - bool is_true(expr* x); - - bool eval (const expr_ref_vector &v, expr_ref &result, bool model_completion); - /// evaluates an expression - bool eval (expr *e, expr_ref &result, bool model_completion); - // expr_ref eval(expr* e, bool complete=true); -}; - - -/** - \brief replace variables that are used in many disequalities by - an equality using the model. - - Assumption: the model satisfies the conjunctions. -*/ -void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml); - -/** - \brief hoist non-boolean if expressions. -*/ -void hoist_non_bool_if(expr_ref& fml); - -bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); - -bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); - -void to_mbp_benchmark(std::ostream &out, const expr* fml, - const app_ref_vector &vars); - -/** - * do the following in sequence - * 1. use qe_lite to cheaply eliminate vars - * 2. for remaining boolean vars, substitute using M - * 3. use MBP for remaining array and arith variables - * 4. for any remaining arith variables, substitute using M - */ -void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, - const model_ref& M, bool reduce_all_selects=false, bool native_mbp=false, - bool dont_sub=false); - -void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& M, expr_map& map); - -void expand_literals(ast_manager &m, expr_ref_vector& conjs); -void compute_implicant_literals (model_evaluator_util &mev, - expr_ref_vector &formula, expr_ref_vector &res); -void simplify_bounds (expr_ref_vector &lemmas); -void normalize(expr *e, expr_ref &out, bool use_simplify_bounds = true, bool factor_eqs = false); - -/** Ground expression by replacing all free variables by skolem - ** constants. On return, out is the resulting expression, and vars is - ** a map from variable ids to corresponding skolem constants. - */ -void ground_expr (expr *e, expr_ref &out, app_ref_vector &vars); - - -void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml); - -bool contains_selects (expr* fml, ast_manager& m); -void get_select_indices (expr* fml, app_ref_vector& indices, ast_manager& m); - -void find_decls (expr* fml, app_ref_vector& decls, std::string& prefix); - -/** extended pretty-printer - * used for debugging - * disables aliasing of common sub-expressions -*/ -struct mk_epp : public mk_pp { - params_ref m_epp_params; - expr_ref m_epp_expr; + void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& M, expr_map& map); + + // TBD: sort out + void expand_literals(ast_manager &m, expr_ref_vector& conjs); + void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, expr_ref_vector &res); + void simplify_bounds (expr_ref_vector &lemmas); + void normalize(expr *e, expr_ref &out, bool use_simplify_bounds = true, bool factor_eqs = false); + + /** + * Ground expression by replacing all free variables by skolem + * constants. On return, out is the resulting expression, and vars is + * a map from variable ids to corresponding skolem constants. + */ + void ground_expr (expr *e, expr_ref &out, app_ref_vector &vars); + + void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml); + + bool contains_selects (expr* fml, ast_manager& m); + void get_select_indices (expr* fml, app_ref_vector& indices, ast_manager& m); + + void find_decls (expr* fml, app_ref_vector& decls, std::string& prefix); + + /** + * extended pretty-printer + * used for debugging + * disables aliasing of common sub-expressions + */ + struct mk_epp : public mk_pp { + params_ref m_epp_params; + expr_ref m_epp_expr; mk_epp(ast *t, ast_manager &m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = nullptr); - void rw(expr *e, expr_ref &out); - -}; - + void rw(expr *e, expr_ref &out); + }; } #endif From 18e3c7b13d0832b29ed6de72d90d38a4eae14863 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 8 Jun 2018 08:22:14 -0700 Subject: [PATCH 1160/1283] Fix bug introduced by formatting --- src/muz/spacer/spacer_util.cpp | 209 +++++++++++++++++---------------- 1 file changed, 106 insertions(+), 103 deletions(-) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 8941c511a..876a6528a 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -87,7 +87,7 @@ namespace spacer { m_mev = nullptr; } m_model = model; - if (m_model) + if (m_model) m_mev = alloc(model_evaluator, *m_model); } @@ -149,7 +149,7 @@ namespace spacer { out << "(define-fun mbp_benchmark_fml () Bool\n "; out << mk_pp(fml, m) << ")\n\n"; - + out << "(push)\n" << "(assert mbp_benchmark_fml)\n" << "(check-sat)\n" @@ -166,13 +166,13 @@ namespace spacer { params_ref p; p.set_bool("reduce_all_selects", reduce_all_selects); p.set_bool("dont_sub", dont_sub); - + qe::mbp mbp(m, p); // TODO: deal with const model *mdl = const_cast(M.get()); mbp.spacer(vars, *mdl, fml); } - + /* * eliminate simple equalities using qe_lite * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays @@ -209,14 +209,14 @@ namespace spacer { qe_lite qe(m, p, false); qe (vars, fml); rw (fml); - + TRACE ("spacer_mbp", tout << "After qe_lite:\n"; tout << mk_pp (fml, m) << "\n"; tout << "Vars:\n" << vars;); - + SASSERT (!m.is_false (fml)); - + // sort out vars into bools, arith (int/real), and arrays for (app* v : vars) { @@ -231,7 +231,7 @@ namespace spacer { arith_vars.push_back (v); } } - + // substitute Booleans if (!bool_sub.empty()) { bool_sub (fml); @@ -241,13 +241,13 @@ namespace spacer { TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); bool_sub.reset (); } - + TRACE ("spacer_mbp", tout << "Array vars:\n"; tout << array_vars;); - + vars.reset (); - + // project arrays { scoped_no_proof _sp (m); @@ -258,17 +258,17 @@ namespace spacer { srw (fml); SASSERT (!m.is_false (fml)); } - + TRACE ("spacer_mbp", tout << "extended model:\n"; model_pp (tout, *M); tout << "Auxiliary variables of index and value sorts:\n"; tout << vars; ); - + if (vars.empty()) { break; } } - + // project reals and ints if (!arith_vars.empty ()) { TRACE ("spacer_mbp", tout << "Arith vars:\n" << arith_vars;); @@ -435,7 +435,7 @@ namespace { // -- (not (xor a b)) == (= a b) if (m.is_xor(nres, f1, f2)) { res = m.mk_eq(f1, f2); } - + // -- split arithmetic inequality else if (m.is_eq (nres, f1, f2) && m_arith.is_int_real (f1)) { expr_ref u(m); @@ -447,8 +447,8 @@ namespace { } } - if (!m_mev.is_true (res)) { - verbose_stream() << "Bad literal: " << mk_pp(res, m) << "\n"; + if (!m_mev.is_true (res)) { + verbose_stream() << "Bad literal: " << mk_pp(res, m) << "\n"; } SASSERT (m_mev.is_true (res)); out.push_back (res); @@ -460,35 +460,38 @@ namespace { expr_ref v(m); m_mev.eval (a, v, false); bool is_true = m.is_true(v); - + if (!is_true && !m.is_false(v)) return; - + expr *na, *f1, *f2, *f3; - - if (a->get_family_id() != m.get_basic_family_id()) { - add_literal(a, out); + + if (m.is_true(a) || m.is_false(a)) { + // noop } - else if (is_uninterp_const(a)) { - add_literal(a, out); + else if (a->get_family_id() != m.get_basic_family_id()) { + add_literal(a, out); } - else if (m.is_not(a, na)) { - m_todo.push_back(na); + else if (is_uninterp_const(a)) { + add_literal(a, out); + } + else if (m.is_not(a, na)) { + m_todo.push_back(na); } else if (m.is_distinct(a)) { if (!is_true) { f1 = qe::project_plugin::pick_equality(m, *m_mev.get_model(), a); m_todo.push_back(f1); } - else if (a->get_num_args() == 2) { - add_literal(a, out); + else if (a->get_num_args() == 2) { + add_literal(a, out); } else { m_todo.push_back(m.mk_distinct_expanded(a->get_num_args(), a->get_args())); } - } + } else if (m.is_and(a)) { - if (is_true) { - m_todo.append(a->get_num_args(), a->get_args()); + if (is_true) { + m_todo.append(a->get_num_args(), a->get_args()); } else { for (expr* e : *a) { @@ -498,10 +501,10 @@ namespace { } } } - } + } else if (m.is_or(a)) { if (!is_true) - m_todo.append(a->get_num_args(), a->get_args()); + m_todo.append(a->get_num_args(), a->get_args()); else { for (expr * e : *a) { if (m_mev.is_true(e)) { @@ -510,59 +513,59 @@ namespace { } } } - } + } else if (m.is_eq(a, f1, f2) || (is_true && m.is_not(a, na) && m.is_xor (na, f1, f2))) { if (!m.are_equal(f1, f2) && !m.are_distinct(f1, f2)) { if (m.is_bool(f1) && (!is_uninterp_const(f1) || !is_uninterp_const(f2))) - m_todo.append(a->get_num_args(), a->get_args()); + m_todo.append(a->get_num_args(), a->get_args()); else - add_literal(a, out); + add_literal(a, out); } - } + } else if (m.is_ite(a, f1, f2, f3)) { - if (m.are_equal(f2, f3)) { - m_todo.push_back(f2); + if (m.are_equal(f2, f3)) { + m_todo.push_back(f2); } else if (m_mev.is_true (f2) && m_mev.is_true (f3)) { m_todo.push_back(f2); m_todo.push_back(f3); - } + } else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { m_todo.push_back(f2); m_todo.push_back(f3); - } + } else if (m_mev.is_true(f1)) { m_todo.push_back(f1); m_todo.push_back(f2); - } + } else if (m_mev.is_false(f1)) { m_todo.push_back(f1); m_todo.push_back(f3); } - } - else if (m.is_xor(a, f1, f2)) { - m_todo.append(a->get_num_args(), a->get_args()); + } + else if (m.is_xor(a, f1, f2)) { + m_todo.append(a->get_num_args(), a->get_args()); } else if (m.is_implies(a, f1, f2)) { if (is_true) { - if (m_mev.is_true(f2)) - m_todo.push_back(f2); - else if (m_mev.is_false(f1)) - m_todo.push_back(f1); - } - else - m_todo.append(a->get_num_args(), a->get_args()); - } + if (m_mev.is_true(f2)) + m_todo.push_back(f2); + else if (m_mev.is_false(f1)) + m_todo.push_back(f1); + } + else + m_todo.append(a->get_num_args(), a->get_args()); + } else { IF_VERBOSE(0, verbose_stream () << "Unexpected expression: " << mk_pp(a, m) << "\n"); UNREACHABLE(); } } - + void pick_literals(expr *e, expr_ref_vector &out) { SASSERT(m_todo.empty()); - if (m_visited.is_marked(e) || !is_app(e)) return; - + if (m_visited.is_marked(e) || !is_app(e)) return; + m_todo.push_back(e); do { e = m_todo.back(); @@ -573,14 +576,14 @@ namespace { m_visited.mark(a, true); } while (!m_todo.empty()); } - + bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) { m_visited.reset(); bool is_true = m_mev.is_true (in); - + for (expr* e : in) { if (is_true || m_mev.is_true(e)) { - pick_literals(e, out); + pick_literals(e, out); } } m_visited.reset (); @@ -591,7 +594,7 @@ namespace { implicant_picker (model_evaluator_util &mev) : m_mev (mev), m (m_mev.get_ast_manager ()), m_arith(m), m_todo(m) {} - + void operator() (expr_ref_vector &in, expr_ref_vector& out) { pick_implicant (in, out); } @@ -605,17 +608,17 @@ namespace { } void simplify_bounds_old(expr_ref_vector& cube) { - ast_manager& m = cube.m(); + ast_manager& m = cube.m(); scoped_no_proof _no_pf_(m); - goal_ref g(alloc(goal, m, false, false, false)); - for (expr* c : cube) + goal_ref g(alloc(goal, m, false, false, false)); + for (expr* c : cube) g->assert_expr(c); - + goal_ref_buffer result; tactic_ref simplifier = mk_arith_bounds_tactic(m); (*simplifier)(g, result); SASSERT(result.size() == 1); - goal* r = result[0]; + goal* r = result[0]; cube.reset(); for (unsigned i = 0; i < r->size(); ++i) { cube.push_back(r->form(i)); @@ -624,19 +627,19 @@ namespace { void simplify_bounds_new (expr_ref_vector &cube) { ast_manager &m = cube.m(); - scoped_no_proof _no_pf_(m); + scoped_no_proof _no_pf_(m); goal_ref g(alloc(goal, m, false, false, false)); - for (expr* c : cube) + for (expr* c : cube) g->assert_expr(c); goal_ref_buffer goals; tactic_ref prop_values = mk_propagate_values_tactic(m); tactic_ref prop_bounds = mk_propagate_ineqs_tactic(m); tactic_ref t = and_then(prop_values.get(), prop_bounds.get()); - + (*t)(g, goals); SASSERT(goals.size() == 1); - + g = goals[0]; cube.reset(); for (unsigned i = 0; i < g->size(); ++i) { @@ -652,26 +655,26 @@ namespace { struct adhoc_rewriter_cfg : public default_rewriter_cfg { ast_manager &m; arith_util m_util; - + adhoc_rewriter_cfg (ast_manager &manager) : m(manager), m_util(m) {} - + bool is_le(func_decl const * n) const { return m_util.is_le(n); } bool is_ge(func_decl const * n) const { return m_util.is_ge(n); } - + br_status reduce_app (func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { expr * e; - if (is_le(f)) + if (is_le(f)) return mk_le_core (args[0], args[1], result); - if (is_ge(f)) + if (is_ge(f)) return mk_ge_core (args[0], args[1], result); if (m.is_not(f) && m.is_not (args[0], e)) { result = e; return BR_DONE; - } + } return BR_FAILED; } - + br_status mk_le_core (expr *arg1, expr * arg2, expr_ref & result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) if (m_util.is_int (arg1) && m_util.is_minus_one (arg2)) { @@ -683,7 +686,7 @@ namespace { br_status mk_ge_core (expr * arg1, expr * arg2, expr_ref & result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) if (m_util.is_int (arg1) && is_one (arg2)) { - + result = m.mk_not (m_util.mk_le (arg1, mk_zero ())); return BR_DONE; } @@ -699,7 +702,7 @@ namespace { bool use_simplify_bounds, bool use_factor_eqs) { - + params_ref params; // arith_rewriter params.set_bool ("sort_sums", true); @@ -708,11 +711,11 @@ namespace { // poly_rewriter params.set_bool ("som", true); params.set_bool ("flat", true); - + // apply rewriter th_rewriter rw(out.m(), params); rw (e, out); - + adhoc_rewriter_cfg adhoc_cfg(out.m ()); rewriter_tpl adhoc_rw (out.m (), false, adhoc_cfg); adhoc_rw (out.get (), out); @@ -720,11 +723,11 @@ namespace { if (out.m().is_and(out)) { expr_ref_vector v(out.m()); flatten_and (out, v); - + if (v.size() > 1) { // sort arguments of the top-level and std::stable_sort (v.c_ptr(), v.c_ptr() + v.size(), ast_lt_proc()); - + if (use_simplify_bounds) { // remove redundant inequalities simplify_bounds (v); @@ -736,7 +739,7 @@ namespace { v.reset(); egraph.to_lits(v); } - + TRACE("spacer_normalize", tout << "Normalized:\n" << out << "\n" @@ -756,21 +759,21 @@ namespace { struct adhoc_rewriter_rpp : public default_rewriter_cfg { ast_manager &m; arith_util m_arith; - + adhoc_rewriter_rpp (ast_manager &manager) : m(manager), m_arith(m) {} - + bool is_le(func_decl const * n) const { return m_arith.is_le(n); } bool is_ge(func_decl const * n) const { return m_arith.is_ge(n); } bool is_lt(func_decl const * n) const { return m_arith.is_lt(n); } bool is_gt(func_decl const * n) const { return m_arith.is_gt(n); } bool is_zero (expr const * n) const {rational val; return m_arith.is_numeral(n, val) && val.is_zero();} - + br_status reduce_app (func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { br_status st = BR_FAILED; expr *e1, *e2, *e3, *e4; - + // rewrites (= (+ A (* -1 B)) 0) into (= A B) if (m.is_eq (f) && is_zero (args [1]) && m_arith.is_add (args[0], e1, e2) && @@ -826,23 +829,23 @@ namespace { mk_pp (t, m, m_epp_params, indent, num_vars, var_prefix), m_epp_expr(m) { m_epp_params.set_uint("min_alias_size", UINT_MAX); m_epp_params.set_uint("max_depth", UINT_MAX); - + if (is_expr (m_ast)) { rw(to_expr(m_ast), m_epp_expr); m_ast = m_epp_expr; } } - + void mk_epp::rw(expr *e, expr_ref &out) { adhoc_rewriter_rpp cfg(out.m()); rewriter_tpl arw(out.m(), false, cfg); arw(e, out); } - + void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) { expr_free_vars fv; ast_manager &m = out.get_manager(); - + fv(e); if (vars.size() < fv.size()) { vars.resize(fv.size()); @@ -871,7 +874,7 @@ namespace { if ((m.is_eq(n) || i > 0) && m_var != arg) m_res.push_back (arg); ++i; } - } + } } }; @@ -890,7 +893,7 @@ namespace { TRACE ("mbqi_project_verbose", tout << "terms:\n" << terms << "\n";); - + for (expr * term : terms) { expr_ref tval (m); mev.eval (term, tval, false); @@ -928,8 +931,8 @@ namespace { tmp.reset (); unsigned j = 0; - for (app* v : vars) - if (!mbqi_project_var (mev, v, fml)) + for (app* v : vars) + if (!mbqi_project_var (mev, v, fml)) vars[j++] = v; vars.shrink(j); } @@ -958,11 +961,11 @@ namespace { array_util a; collect_indices(app_ref_vector& indices): m_indices(indices), a(indices.get_manager()) {} void operator()(expr* n) {} - void operator()(app* n) { - if (a.is_select (n)) - for (unsigned i = 1; i < n->get_num_args(); ++i) - if (is_app(n->get_arg(i))) - m_indices.push_back(to_app(n->get_arg(i))); + void operator()(app* n) { + if (a.is_select (n)) + for (unsigned i = 1; i < n->get_num_args(); ++i) + if (is_app(n->get_arg(i))) + m_indices.push_back(to_app(n->get_arg(i))); } }; @@ -970,15 +973,15 @@ namespace { collect_indices ci(indices); for_each_expr(ci, fml); } - + struct collect_decls { app_ref_vector& m_decls; std::string& prefix; collect_decls(app_ref_vector& decls, std::string& p): m_decls(decls), prefix(p) {} void operator()(expr* n) {} - void operator()(app* n) { + void operator()(app* n) { if (n->get_decl()->get_name().str().find(prefix) != std::string::npos) - m_decls.push_back(n); + m_decls.push_back(n); } }; From 4099f31f4f09dfb9741220390ef6290e779f0e63 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 8 Jun 2018 09:45:19 -0700 Subject: [PATCH 1161/1283] Fix refutation generation --- src/muz/spacer/spacer_sat_answer.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/muz/spacer/spacer_sat_answer.cpp b/src/muz/spacer/spacer_sat_answer.cpp index 8382133d8..09553de89 100644 --- a/src/muz/spacer/spacer_sat_answer.cpp +++ b/src/muz/spacer/spacer_sat_answer.cpp @@ -53,7 +53,7 @@ ground_sat_answer_op::ground_sat_answer_op(context &ctx) : proof_ref ground_sat_answer_op::operator()(pred_transformer &query) { - vector todo; + vector todo, new_todo; // -- find substitution for a query if query is not nullary expr_ref_vector qsubst(m); @@ -73,29 +73,32 @@ proof_ref ground_sat_answer_op::operator()(pred_transformer &query) { } } - frame root(query.get_last_rf(), query, qsubst); - todo.push_back(root); + todo.push_back(frame(query.get_last_rf(), query, qsubst)); + expr_ref root_fact(m); + root_fact = todo.back().fact(); while (!todo.empty()) { frame &curr = todo.back(); - if (m_cache.contains(curr.fact())) - { + if (m_cache.contains(curr.fact())) { todo.pop_back(); continue; } if (curr.m_visit == 0) { - mk_children(curr, todo); + new_todo.reset(); + mk_children(curr, new_todo); curr.m_visit = 1; + // curr becomes invalid + todo.append(new_todo); } else { proof* pf = mk_proof_step(curr); + m_pinned.push_back(curr.fact()); m_cache.insert(curr.fact(), pf); todo.pop_back(); } - } - return proof_ref(m_cache.find(root.fact()), m); + return proof_ref(m_cache.find(root_fact), m); } @@ -120,7 +123,7 @@ void ground_sat_answer_op::mk_children(frame &fr, vector &todo) { lbool res = m_solver->check_sat(0, nullptr); (void)res; - SASSERT(res == l_true); + VERIFY(res == l_true); model_ref mdl; m_solver->get_model(mdl); @@ -155,9 +158,16 @@ proof *ground_sat_answer_op::mk_proof_step(frame &fr) { datalog::rule_manager &rm = m_ctx.get_datalog_context().get_rule_manager(); expr_ref rule_fml(m); rm.to_formula(fr.rule(), rule_fml); + // premises.push_back(fr.rule().get_proof()); premises.push_back(m.mk_asserted(rule_fml)); for (auto &k : fr.m_kids) {premises.push_back(m_cache.find(k));} + for (unsigned i = 0; i < premises.size(); i++) { + positions.push_back(std::make_pair(0,i)); + } + for (unsigned i = 0; i <= premises.size(); i++) { + substs.push_back(expr_ref_vector(m)); + } m_pinned.push_back(m.mk_hyper_resolve(premises.size(), premises.c_ptr(), fr.fact(), From df7ab0e4964c592a8dc061cf013e6890988a936f Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 8 Jun 2018 18:58:28 -0700 Subject: [PATCH 1162/1283] pred_transformer: factor rule bookkeeping to a separate class --- src/muz/spacer/spacer_context.cpp | 219 +++++++++++++----------------- src/muz/spacer/spacer_context.h | 84 ++++++++++-- 2 files changed, 167 insertions(+), 136 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 5806c08fb..a8a904aa1 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -659,10 +659,18 @@ void lemma::mk_insts(expr_ref_vector &out, expr* e) } } - - // ---------------- // pred_tansformer +pred_transformer::pt_rule &pred_transformer::pt_rules::mk_rule(const pred_transformer::pt_rule &v) { + pt_rule *p = nullptr; + if (find_by_rule(v.rule(), p)) + return *p; + + p = alloc(pt_rule, v); + m_rules.insert(&p->rule(), p); + if (p->tag()) m_tags.insert(p->tag(), p); + return *p; +} pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): pm(pm), m(pm.get_manager()), @@ -692,9 +700,6 @@ app_ref pred_transformer::mk_extend_lit() { return app_ref(m.mk_not (m.mk_const (pm.get_n_pred (v->get_decl ()))), m); } -pred_transformer::~pred_transformer() { - for (auto &entry : m_rule2transition) {m.dec_ref(entry.m_value);} -} std::ostream& pred_transformer::display(std::ostream& out) const { @@ -819,10 +824,10 @@ reach_fact *pred_transformer::get_used_origin_rf (model_evaluator_util& mev, const datalog::rule *pred_transformer::find_rule(model &model) { expr_ref val(m); - for (auto &entry : m_tag2rule) { - app *tag = to_app(entry.m_key); + for (auto &kv : m_pt_rules) { + app *tag = kv.m_value->tag(); if (model.eval(tag->get_decl(), val) && m.is_true(val)) { - return entry.m_value; + return &kv.m_value->rule(); } } return nullptr; @@ -833,26 +838,16 @@ const datalog::rule *pred_transformer::find_rule(model &model, vector& reach_pred_used, unsigned& num_reuse_reach) { - TRACE ("spacer_verbose", - datalog::rule_manager& rm = ctx.get_datalog_context().get_rule_manager(); - for (auto &entry : m_tag2rule) { - expr* pred = entry.m_key; - tout << mk_pp(pred, m) << ":\n"; - if (entry.m_value) { - rm.display_smt2(*(entry.m_value), tout) << "\n"; - } - } - ); - // find a rule whose tag is true in the model; // prefer a rule where the model intersects with reach facts of all predecessors; // also find how many predecessors' reach facts are true in the model expr_ref vl(m); const datalog::rule *r = ((datalog::rule*)nullptr); - for (auto &entry : m_tag2rule) { - expr* tag = entry.m_key; - if (model.eval(to_app(tag)->get_decl(), vl) && m.is_true(vl)) { - r = entry.m_value; + //for (auto &entry : m_tag2rule) { + for (auto &kv : m_pt_rules) { + app* tag = kv.m_value->tag(); + if (model.eval(tag->get_decl(), vl) && m.is_true(vl)) { + r = &kv.m_value->rule(); is_concrete = true; num_reuse_reach = 0; reach_pred_used.reset(); @@ -1309,9 +1304,8 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, // populate reach_assumps if (n.level () > 0 && !m_all_init) { - for (auto &entry : m_tag2rule) { - datalog::rule const* r = entry.m_value; - if (!r) {continue;} + for (auto &kv : m_pt_rules) { + datalog::rule const* r = &kv.m_value->rule(); find_predecessors(*r, m_predicates); if (m_predicates.empty()) {continue;} for (unsigned i = 0; i < m_predicates.size(); i++) { @@ -1322,7 +1316,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, pm.formula_n2o(pt.get_last_rf_tag(), a, i); reach_assumps.push_back(m.mk_not (a)); } else { - reach_assumps.push_back(m.mk_not (entry.m_key)); + reach_assumps.push_back(m.mk_not (kv.m_value->tag())); break; } } @@ -1504,11 +1498,10 @@ void pred_transformer::mk_assumptions(func_decl* head, expr* fml, expr_ref_vector& result) { expr_ref tmp1(m), tmp2(m); - for (auto& kv : m_tag2rule) { - expr* tag = kv.m_key; - datalog::rule const* r = kv.m_value; - if (!r) { continue; } - find_predecessors(*r, m_predicates); + for (auto& kv : m_pt_rules) { + expr* tag = kv.m_value->tag(); + datalog::rule const& r = kv.m_value->rule(); + find_predecessors(r, m_predicates); for (unsigned i = 0; i < m_predicates.size(); i++) { func_decl* d = m_predicates[i]; if (d == head) { @@ -1545,79 +1538,52 @@ void pred_transformer::init_rfs () expr_ref_vector v(m); reach_fact_ref fact; - for (auto &entry : m_rule2tag) { - const datalog::rule* r = entry.m_key; - if (r->get_uninterpreted_tail_size() == 0) { - fact = alloc (reach_fact, m, *r, m_rule2transition.find(r), - get_aux_vars(*r), true); - add_rf(fact.get ()); + for (auto &kv : m_pt_rules) { + pt_rule &ptr = *kv.m_value; + const datalog::rule& r = ptr.rule(); + if (ptr.is_init()) { + fact = alloc(reach_fact, m, r, ptr.trans(), ptr.auxs(), true); + add_rf(fact.get()); } } } void pred_transformer::init_rules(decl2rel const& pts) { - expr_ref_vector transitions(m); - ptr_vector tr_rules; - datalog::rule const* rule; - expr_ref_vector init_conds (m); + expr_ref_vector transitions(m), not_inits(m); app_ref tag(m); - vector is_init; - for (auto r : m_rules) {init_rule(pts, *r, is_init, tr_rules, transitions);} - SASSERT (is_init.size () == transitions.size ()); + for (auto r : m_rules) { + init_rule(pts, *r); + } - std::string name; - switch(transitions.size()) { - case 0: + if (m_pt_rules.empty()) { m_transition = m.mk_false(); m_transition_clause.reset(); - break; - case 1: - // create a dummy tag. - name = head()->get_name().str() + "_dummy"; - tag = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); - - rule = tr_rules[0]; - m_tag2rule.insert(tag, rule); - m_rule2tag.insert(rule, tag); - transitions[0] = m.mk_implies (tag, transitions.get(0)); - - m_transition_clause.push_back(m_extend_lit->get_arg(0)); - m_transition_clause.push_back(tag); - - if (!ctx.use_inc_clause()) { - transitions.push_back(mk_or(m_transition_clause)); - m_transition_clause.reset(); - } - - if (!is_init[0]) {init_conds.push_back(m.mk_not(tag));} - - m_transition = mk_and(transitions); - break; - default: - m_transition_clause.push_back (m_extend_lit->get_arg(0)); - for (unsigned i = 0; i < transitions.size(); ++i) { - name = head()->get_name().str() + "__tr" + std::to_string(i); - tag = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); - rule = tr_rules[i]; - m_tag2rule.insert(tag, rule); - m_rule2tag.insert(rule, tag); - m_transition_clause.push_back(tag); - transitions[i] = m.mk_implies(tag, transitions.get(i)); - // update init conds - if (!is_init[i]) {init_conds.push_back (m.mk_not (tag));} - } - - if (!ctx.use_inc_clause()) { - transitions.push_back(mk_or(m_transition_clause)); - m_transition_clause.reset(); - } - m_transition = mk_and(transitions); - break; } - // mk init condition - m_init = mk_and(init_conds); + else { + unsigned i = 0; + expr_ref_vector transitions(m); + m_transition_clause.push_back (m_extend_lit->get_arg(0)); + for (auto &kv : m_pt_rules) { + pt_rule &r = *kv.m_value; + std::string name = head()->get_name().str() + "__tr" + std::to_string(i); + tag = m.mk_const(symbol(name.c_str()), m.mk_bool_sort()); + m_pt_rules.set_tag(tag, r); + m_transition_clause.push_back(tag); + transitions.push_back(m.mk_implies(r.tag(), r.trans())); + if (!r.is_init()) {not_inits.push_back(m.mk_not(tag));} + ++i; + } + + if (!ctx.use_inc_clause()) { + transitions.push_back(mk_or(m_transition_clause)); + m_transition_clause.reset(); + } + m_transition = mk_and(transitions); + } + // mk init condition -- disables all non-initial transitions + m_init = mk_and(not_inits); // no rule has uninterpreted tail - if (init_conds.empty ()) {m_all_init = true;} + if (not_inits.empty ()) {m_all_init = true;} } static bool is_all_non_null(app_ref_vector const& v) @@ -1628,10 +1594,7 @@ static bool is_all_non_null(app_ref_vector const& v) return true; } -void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule, - vector& is_init, - ptr_vector& rules, - expr_ref_vector& transitions) { +void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule) { scoped_watch _t_(m_initialize_watch); // Predicates that are variable representatives. Other predicates at @@ -1652,46 +1615,42 @@ void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule, init_atom(pts, rule.get_tail(i), var_reprs, side, i); } // -- substitute free variables - expr_ref fml(m); + expr_ref trans(m); { expr_ref_vector tail(m); for (unsigned i = ut_size; i < t_size; ++i) - {tail.push_back(rule.get_tail(i));} - fml = mk_and (tail); + tail.push_back(rule.get_tail(i)); + trans= mk_and (tail); - ground_free_vars(fml, var_reprs, aux_vars, ut_size == 0); + ground_free_vars(trans, var_reprs, aux_vars, ut_size == 0); SASSERT(is_all_non_null(var_reprs)); expr_ref tmp(m); - var_subst(m, false)(fml, var_reprs.size (), + var_subst(m, false)(trans, var_reprs.size (), (expr*const*)var_reprs.c_ptr(), tmp); flatten_and (tmp, side); - fml = mk_and(side); + trans = mk_and(side); side.reset (); } // rewrite and simplify th_rewriter rw(m); - rw(fml); - if (ctx.blast_term_ite()) {blast_term_ite(fml, 3); rw(fml);} - TRACE("spacer", tout << mk_pp(fml, m) << "\n";); + rw(trans); + if (ctx.blast_term_ite()) {blast_term_ite(trans, 3); rw(trans);} + TRACE("spacer_init_rule", tout << mk_pp(trans, m) << "\n";); // allow quantifiers in init rule - SASSERT(ut_size == 0 || is_ground(fml)); - if (!m.is_false(fml)) { - is_init.push_back (ut_size == 0); - transitions.push_back(fml); - rules.push_back(&rule); - - m.inc_ref(fml); - m_rule2transition.insert(&rule, fml); + SASSERT(ut_size == 0 || is_ground(trans)); + if (!m.is_false(trans)) { + pt_rule &ptr = m_pt_rules.mk_rule(m, rule); + ptr.set_trans(trans); + ptr.set_auxs(aux_vars); + ptr.set_reps(var_reprs); } - // AG: shouldn't this be under the if-statement above? - m_rule2vars.insert(&rule, aux_vars); - TRACE("spacer", - tout << rule.get_decl()->get_name() << "\n"; - tout << var_reprs << "\n";); + // TRACE("spacer", + // tout << rule.get_decl()->get_name() << "\n"; + // tout << var_reprs << "\n";); } @@ -1857,18 +1816,17 @@ void pred_transformer::updt_solver(prop_solver *solver) { } // -- lemmas and rfs from other predicates - for (auto &entry : m_tag2rule) { - const datalog::rule *r = entry.m_value; - if (!r) continue; - find_predecessors(*r, m_predicates); + for (auto &kv : m_pt_rules) { + const datalog::rule &r = kv.m_value->rule(); + find_predecessors(r, m_predicates); if (m_predicates.empty()) continue; for (unsigned i = 0, sz = m_predicates.size(); i < sz; ++i) { const pred_transformer &pt = ctx.get_pred_transformer(m_predicates[i]); // assert lemmas of pt - updt_solver_with_lemmas(solver, pt, to_app(entry.m_key), i); + updt_solver_with_lemmas(solver, pt, to_app(kv.m_value->tag()), i); // assert rfs of pt - update_solver_with_rfs(solver, pt, to_app(entry.m_key), i); + update_solver_with_rfs(solver, pt, to_app(kv.m_value->tag()), i); } } } @@ -2447,6 +2405,7 @@ bool context::validate() switch(m_last_result) { case l_true: { +#if 0 expr_ref cex(m); cex = get_ground_sat_answer(); if (!cex.get()) { @@ -2454,6 +2413,14 @@ bool context::validate() throw default_exception("Cex validation failed\n"); return false; } +#endif + proof_ref cex(m); + cex = get_ground_refutation(); + if (!cex.get()) { + IF_VERBOSE(0, verbose_stream() << "Cex validation failed\n";); + throw default_exception("Cex validation failed\n"); + return false; + } break; } case l_false: { diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index e95ddc8ec..402cb63cc 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -292,6 +292,64 @@ class pred_transformer { }; + class pt_rule { + const datalog::rule &m_rule; + expr_ref m_trans; // ground version of m_rule + ptr_vector m_auxs; // auxiliary variables in m_trans + app_ref_vector m_reps; // map from fv in m_rule to ground constants + app_ref m_tag; // a unique tag for the rule + + public: + pt_rule(ast_manager &m, const datalog::rule &r) : + m_rule(r), m_trans(m), m_reps(m), m_tag(m) {} + + const datalog::rule &rule() const {return m_rule;} + + void set_tag(expr *tag) {SASSERT(is_app(tag)); set_tag(to_app(tag));} + void set_tag(app* tag) {m_tag = tag;} + app* tag() const {return m_tag;} + ptr_vector &auxs() {return m_auxs;} + void set_auxs(ptr_vector &v) {m_auxs.reset(); m_auxs.append(v);} + void set_reps(app_ref_vector &v) {m_reps.reset(); m_reps.append(v);} + + void set_trans(expr_ref &v) {m_trans=v;} + expr* trans() const {return m_trans;} + bool is_init() const {return m_rule.get_uninterpreted_tail_size() == 0;} + }; + + class pt_rules { + typedef obj_map rule2ptrule; + typedef obj_map tag2ptrule; + typedef rule2ptrule::iterator iterator; + rule2ptrule m_rules; + tag2ptrule m_tags; + public: + pt_rules() {} + ~pt_rules() {for (auto &kv : m_rules) {dealloc(kv.m_value);}} + + bool find_by_rule(const datalog::rule &r, pt_rule* &ptr) { + return m_rules.find(&r, ptr); + } + bool find_by_tag(const expr* tag, pt_rule* &ptr) { + return m_tags.find(tag, ptr); + } + pt_rule &mk_rule(ast_manager &m, const datalog::rule &r) { + return mk_rule(pt_rule(m, r)); + } + pt_rule &mk_rule(const pt_rule &v); + void set_tag(expr* tag, pt_rule &v) { + pt_rule *p; + VERIFY(find_by_rule(v.rule(), p)); + p->set_tag(tag); + m_tags.insert(tag, p); + } + + bool empty() {return m_rules.empty();} + iterator begin() {return m_rules.begin();} + iterator end() {return m_rules.end();} + + }; + typedef obj_map rule2expr; typedef obj_map > rule2apps; typedef obj_map expr2rule; @@ -302,6 +360,7 @@ class pred_transformer { func_decl_ref m_head; // predicate func_decl_ref_vector m_sig; // signature ptr_vector m_use; // places where 'this' is referenced. + pt_rules m_pt_rules; // pt rules used to derive transformer ptr_vector m_rules; // rules used to derive transformer scoped_ptr m_solver; // solver context ref m_reach_solver; // context for reachability facts @@ -309,10 +368,6 @@ class pred_transformer { frames m_frames; // frames with lemmas reach_fact_ref_vector m_reach_facts; // reach facts unsigned m_rf_init_sz; // number of reach fact from INIT - expr2rule m_tag2rule; // map tag predicate to rule. - rule2expr m_rule2tag; // map rule to predicate tag. - rule2expr m_rule2transition; // map rules to transition - rule2apps m_rule2vars; // map rule to auxiliary variables expr_ref_vector m_transition_clause; // extra clause for trans expr_ref m_transition; // transition relation expr_ref m_init; // initial condition @@ -337,8 +392,7 @@ class pred_transformer { // Initialization void init_rules(decl2rel const& pts); - void init_rule(decl2rel const& pts, datalog::rule const& rule, vector& is_init, - ptr_vector& rules, expr_ref_vector& transition); + void init_rule(decl2rel const& pts, datalog::rule const& rule); void init_atom(decl2rel const& pts, app * atom, app_ref_vector& var_reprs, expr_ref_vector& side, unsigned tail_idx); @@ -350,7 +404,7 @@ class pred_transformer { public: pred_transformer(context& ctx, manager& pm, func_decl* head); - ~pred_transformer(); + ~pred_transformer() {} inline bool use_native_mbp (); reach_fact *get_rf (expr *v) { @@ -372,7 +426,10 @@ public: unsigned sig_size() const {return m_sig.size();} expr* transition() const {return m_transition;} expr* init() const {return m_init;} - expr* rule2tag(datalog::rule const* r) {return m_rule2tag.find(r);} + expr* rule2tag(datalog::rule const* r) { + pt_rule *p; + return m_pt_rules.find_by_rule(*r, p) ? p->tag() : nullptr; + } unsigned get_num_levels() const {return m_frames.size ();} expr_ref get_cover_delta(func_decl* p_orig, int level); void add_cover(unsigned level, expr* property); @@ -398,8 +455,15 @@ public: const datalog::rule *find_rule(model &mev, bool& is_concrete, vector& reach_pred_used, unsigned& num_reuse_reach); - expr* get_transition(datalog::rule const& r) { return m_rule2transition.find(&r); } - ptr_vector& get_aux_vars(datalog::rule const& r) { return m_rule2vars.find(&r); } + expr* get_transition(datalog::rule const& r) { + pt_rule *p; + return m_pt_rules.find_by_rule(r, p) ? p->trans() : nullptr; + } + ptr_vector& get_aux_vars(datalog::rule const& r) { + pt_rule *p = nullptr; + VERIFY(m_pt_rules.find_by_rule(r, p)); + return p->auxs(); + } bool propagate_to_next_level(unsigned level); void propagate_to_infinity(unsigned level); From 8445e2a7a2e41d43b0f157eaeb13dd8f1f50723b Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 8 Jun 2018 23:37:16 -0700 Subject: [PATCH 1163/1283] Fix bug in weak abs Must ensure that weak model makes all summaries true. Otherwise, it is possible to get stuck discovering the same lemma forever. --- src/muz/spacer/spacer_context.cpp | 8 ++++++++ src/muz/spacer/spacer_context.h | 3 --- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index a8a904aa1..64d047d73 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1166,6 +1166,10 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, summary[i] = v; } + // bail out of if the model is insufficient + if (!mev.is_true(summary)) + return expr_ref(m); + // -- pick an implicant expr_ref_vector lits(m); compute_implicant_literals (mev, summary, lits); @@ -3722,6 +3726,10 @@ bool context::create_children(pob& n, datalog::rule const& r, expr_ref sum(m); sum = pt.get_origin_summary (mev, prev_level(n.level()), j, reach_pred_used[j], &aux); + if (!sum) { + dealloc(deriv); + return false; + } deriv->add_premise (pt, j, sum, reach_pred_used[j], aux); } diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 402cb63cc..fcd396a62 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -350,9 +350,6 @@ class pred_transformer { }; - typedef obj_map rule2expr; - typedef obj_map > rule2apps; - typedef obj_map expr2rule; manager& pm; // spacer::manager ast_manager& m; // ast_manager context& ctx; // spacer::context From 4a2eb909bfb96fceb6b61b3bee4a3b15b5f31eb9 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 9 Jun 2018 10:34:05 -0700 Subject: [PATCH 1164/1283] Re-fixing a bug in compute_implicant_literals() --- src/muz/spacer/spacer_util.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 876a6528a..da946e211 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -603,6 +603,14 @@ namespace { void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, expr_ref_vector &res) { + // flatten the formula and remove all trivial literals + + // TBD: not clear why there is a dependence on it (other than + // not handling of Boolean constants by implicant_picker), however, + // it was a source of a problem on a benchmark + flatten_and(formula); + if (formula.empty()) {return;} + implicant_picker ipick (mev); ipick (formula, res); } From 5fc0f56281318080be0fb1cf67af869b40aaaaed Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Jun 2018 17:03:24 -0700 Subject: [PATCH 1165/1283] sketch mbi Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 62 ++++++++++++++++++++++++++++++++ src/qe/qe_mbi.h | 90 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 src/qe/qe_mbi.cpp create mode 100644 src/qe/qe_mbi.h diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp new file mode 100644 index 000000000..13b9067ee --- /dev/null +++ b/src/qe/qe_mbi.cpp @@ -0,0 +1,62 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + qe_mbi.cpp + +Abstract: + + Model-based interpolation utilities + +Author: + + Nikolaj Bjorner (nbjorner), Arie Gurfinkel 2018-6-8 + +Revision History: + + +--*/ + + +namespace qe { + + lbool interpolator::binary(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { + ast_manager& m = vars.get_manager(); + model_ref mdl; + literal_vector lits(m); + bool a_turn = true; + expr_ref_vector itp_a(m), itp_b(m); + mbi_result last_res = mbi_undef; + while (true) { + auto* t1 = a_turn ? &a : &b; + auto* t2 = a_turn ? &b : &a; + mbi_result next_res = (*t1)(vars, lits, mdl); + switch (next_res) { + case mbi_sat: + if (last_res == mbi_sat) { + itp = nullptr; + return l_true; + } + break; // continue + case mbi_unsat: + if (last_res == mbi_unsat) { + // TBD, extract the interpolants + // of what was blocked. + return l_false; + } + t2->block(lits); + lits.reset(); // or find a prefix of lits? + next_res = mbi_undef; + a_turn = !a_turn; + break; + case mbi_augment: + a_turn = !a_turn; + break; + case mbi_undef: + return l_undef; + } + last_res = next_res; + } + } +}; diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h new file mode 100644 index 000000000..4aad92f82 --- /dev/null +++ b/src/qe/qe_mbi.h @@ -0,0 +1,90 @@ +/*++ +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + qe_mbi.h + +Abstract: + + Model-based interpolation utilities + +Author: + + Nikolaj Bjorner (nbjorner), Arie Gurfinkel 2018-6-8 + +Revision History: + + +--*/ + +#pragma once + +namespace qe { + enum mbi_result { + mbi_sat, + mbi_unsat, + mbi_augment, + mbi_undef, + }; + + class mbi_plugin { + virtual ~mbi_plugin(); + /** + * \brief Utility that works modulo a background state. + * - vars + * variables to preferrably project onto (other variables would require quantification to fit interpolation signature) + * - lits + * set of literals to check satisfiability with respect to. + * - mdl + * optional model for caller. + * on return: + * - mbi_sat: + * populates mdl with a satisfying state, and lits with implicant for background state. + * - mbi_unsat: + * populates lits to be inconsistent with background state. + * For all practical purposes it is a weakening of lits or even a subset of lits. + * - mbi_augment: + * populates lits with strengthening of lits (superset) + * - mbi_undef: + * inconclusive, + */ + virtual mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) = 0; + + /** + * \brief Block conjunction of lits from future mbi_augment or mbi_sat. + */ + virtual void block(expr_ref_vector const& lits) = 0; + }; + + class euf_mbi_plugin : mbi_plugin { + solver_ref m_solver; + public: + euf_mbi_plugin(solver* s); + ~euf_mbi_plugin() override {} + mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; + void block(expr_ref_vector const& lits) override; + }; + + /** + * use cases for interpolation. + */ + class interpolator { + static lbool binary(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); + }; + +#if 0 + TBD some other scenario, e.g., Farkas, Cute/Beautiful/maybe even Selfless + + class solver_mbi_plugin : public mbi_plugin { + solver_ref m_solver; + public: + solver_mbi_plugin(solver* s); + ~solver_mbi_plugin() override {} + mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; + void block(expr_ref_vector const& lits) override; + }; + + +#endif +}; From e6468726f5dba1d1822d1948865124238e8d6987 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 8 Jun 2018 18:52:04 -0700 Subject: [PATCH 1166/1283] more code Signed-off-by: Nikolaj Bjorner --- src/ast/ast_util.cpp | 5 ++++ src/ast/ast_util.h | 2 ++ src/qe/qe_mbi.cpp | 54 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index e2783051a..0e5cf12a5 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -195,6 +195,11 @@ expr * mk_not(ast_manager & m, expr * arg) { return m.mk_not(arg); } +expr_ref mk_not(expr_ref& e) { + return expr_ref(mk_not(e.m(), e), e.m()); +} + + expr_ref push_not(const expr_ref& e) { ast_manager& m = e.get_manager(); if (!is_app(e)) { diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index 12c11c141..1383be157 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -127,6 +127,8 @@ inline expr_ref mk_or(expr_ref_vector const& args) { return expr_ref(mk_or(args. */ expr * mk_not(ast_manager & m, expr * arg); +expr_ref mk_not(expr_ref& e); + /** Negate and push over conjunction or disjunction. */ diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 13b9067ee..eda233c14 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -20,17 +20,52 @@ Revision History: namespace qe { + + euf_mbi_plugin::euf_mbi_plugin(solver* s): m_solver(s) {} + + euf_mbi_plugin::~euf_mbi_plugin() {} + + mbi_result euf_mbi_plugin::operator()( + func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override { + // really just a sketch of propositional at this point + scoped_push _sp(m_solver); + lbool r = m_solver->check_sat(lits); + switch (r) { + case l_false: + lits.reset(); + m_solver->get_unsat_core(lits); + return mbi_unsat; + case l_true: + m_solver->get_model(mdl); + // update lits? to be all propositioal literals or an implicant. + // mdl will have map of all constants that we can walk over. + return mbi_sat; + case l_undef: + return mbi_undef; + } + } + + void euf_mbi_plugin::block(expr_ref_vector const& lits) override { + m_solver->assert_expr(mk_not(mk_and(lits))); + } + /** + * ping-pong interpolation of Gurfinkel & Vizel + */ lbool interpolator::binary(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { ast_manager& m = vars.get_manager(); model_ref mdl; literal_vector lits(m); - bool a_turn = true; - expr_ref_vector itp_a(m), itp_b(m); + bool turn = true; + vector itps, blocks; + ipts.push_back(expr_ref_vector(m)); + ipts.push_back(expr_ref_vector(m)); + blocks.push_back(expr_ref_vector(m)); + blocks.push_back(expr_ref_vector(m)); mbi_result last_res = mbi_undef; while (true) { - auto* t1 = a_turn ? &a : &b; - auto* t2 = a_turn ? &b : &a; + auto* t1 = turn ? &a : &b; + auto* t2 = turn ? &b : &a; mbi_result next_res = (*t1)(vars, lits, mdl); switch (next_res) { case mbi_sat: @@ -41,21 +76,22 @@ namespace qe { break; // continue case mbi_unsat: if (last_res == mbi_unsat) { - // TBD, extract the interpolants - // of what was blocked. + itp = mk_and(itps[turn]); return l_false; } t2->block(lits); + expr_ref lemma(m.mk_not(mk_and(lits)), m); + blocks[turn].push_back(lemma); + itps[turn].push_back(m.mk_implies(mk_and(blocks[!turn]), lemma)); lits.reset(); // or find a prefix of lits? - next_res = mbi_undef; - a_turn = !a_turn; + next_res = mbi_undef; // hard restart. break; case mbi_augment: - a_turn = !a_turn; break; case mbi_undef: return l_undef; } + turn = !turn; last_res = next_res; } } From 688cf79619fbc291938f63d16ffbe7ee368d23cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 09:55:32 -0700 Subject: [PATCH 1167/1283] working on mbi Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 50 ++++++++++++- src/qe/CMakeLists.txt | 1 + src/qe/qe_mbi.cpp | 93 ++++++++++++++++++++----- src/qe/qe_mbi.h | 16 ++++- src/smt/smt_context.cpp | 66 ++++++++++++------ src/smt/smt_context.h | 2 + 6 files changed, 184 insertions(+), 44 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 31fc4b008..c6cd1020e 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -31,6 +31,7 @@ Notes: #include "ast/rewriter/var_subst.h" #include "util/gparams.h" #include "qe/qe_mbp.h" +#include "qe/qe_mbi.h" BINARY_SYM_CMD(get_quantifier_body_cmd, @@ -358,7 +359,7 @@ class mbp_cmd : public cmd { ptr_vector m_vars; public: mbp_cmd():cmd("mbp") {} - char const * get_usage() const override { return ""; } + char const * get_usage() const override { return " ()"; } char const * get_descr(cmd_context & ctx) const override { return "perform model based projection"; } unsigned get_arity() const override { return 2; } cmd_arg_kind next_arg_kind(cmd_context& ctx) const override { @@ -390,6 +391,52 @@ public: } }; +class mbi_cmd : public cmd { + expr* m_a; + expr* m_b; + ptr_vector m_vars; +public: + mbi_cmd():cmd("mbi") {} + char const * get_usage() const override { return " (vars)"; } + char const * get_descr(cmd_context & ctx) const override { return "perform model based interpolation"; } + unsigned get_arity() const override { return 3; } + cmd_arg_kind next_arg_kind(cmd_context& ctx) const override { + if (m_a == nullptr) return CPK_EXPR; + if (m_b == nullptr) return CPK_EXPR; + return CPK_FUNC_DECL_LIST; + } + void set_next_arg(cmd_context& ctx, expr * arg) override { + if (m_a == nullptr) + m_a = arg; + else + m_b = arg; + } + void set_next_arg(cmd_context & ctx, unsigned num, func_decl * const * ts) override { + m_vars.append(num, ts); + } + void prepare(cmd_context & ctx) override { m_a = nullptr; m_b = nullptr; m_vars.reset(); } + void execute(cmd_context & ctx) override { + ast_manager& m = ctx.m(); + func_decl_ref_vector vars(m); + for (func_decl* v : m_vars) { + vars.push_back(v); + } + qe::interpolator mbi; + expr_ref a(m_a, m); + expr_ref b(m_b, m); + expr_ref itp(m); + solver_factory& sf = ctx.get_solver_factory(); + params_ref p; + solver_ref sA = sf(m, p, false /* no proofs */, true, true, symbol::null); + solver_ref sB = sf(m, p, false /* no proofs */, true, true, symbol::null); + qe::prop_mbi_plugin pA(sA.get()); + qe::prop_mbi_plugin pB(sB.get()); + lbool res = mbi.binary(pA, pB, vars, itp); + ctx.regular_stream() << res << " " << itp << "\n"; + } + +}; + void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(print_dimacs_cmd)); @@ -416,4 +463,5 @@ void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(instantiate_nested_cmd)); ctx.insert(alloc(set_next_id)); ctx.insert(alloc(mbp_cmd)); + ctx.insert(alloc(mbi_cmd)); } diff --git a/src/qe/CMakeLists.txt b/src/qe/CMakeLists.txt index 2e6052382..d43db34f0 100644 --- a/src/qe/CMakeLists.txt +++ b/src/qe/CMakeLists.txt @@ -15,6 +15,7 @@ z3_add_component(qe qe_dl_plugin.cpp qe_lite.cpp qe_mbp.cpp + qe_mbi.cpp qe_sat_tactic.cpp qe_tactic.cpp qsat.cpp diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index eda233c14..f149af764 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -18,17 +18,22 @@ Revision History: --*/ +#include "ast/ast_util.h" +#include "solver/solver.h" +#include "qe/qe_mbi.h" + namespace qe { - euf_mbi_plugin::euf_mbi_plugin(solver* s): m_solver(s) {} + // ------------------------------- + // prop_mbi - euf_mbi_plugin::~euf_mbi_plugin() {} + prop_mbi_plugin::prop_mbi_plugin(solver* s): m_solver(s) {} - mbi_result euf_mbi_plugin::operator()( - func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override { - // really just a sketch of propositional at this point - scoped_push _sp(m_solver); + // sketch of propositional + + mbi_result prop_mbi_plugin::operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { + ast_manager& m = lits.m(); lbool r = m_solver->check_sat(lits); switch (r) { case l_false: @@ -37,29 +42,77 @@ namespace qe { return mbi_unsat; case l_true: m_solver->get_model(mdl); - // update lits? to be all propositioal literals or an implicant. - // mdl will have map of all constants that we can walk over. + lits.reset(); + for (unsigned i = 0, sz = mdl->get_num_constants(); i < sz; ++i) { + func_decl* c = mdl->get_constant(i); + if (vars.contains(c)) { + if (m.is_true(mdl->get_const_interp(c))) { + lits.push_back(m.mk_const(c)); + } + else { + lits.push_back(m.mk_not(m.mk_const(c))); + } + } + } return mbi_sat; - case l_undef: + default: return mbi_undef; } } - void euf_mbi_plugin::block(expr_ref_vector const& lits) override { + void prop_mbi_plugin::block(expr_ref_vector const& lits) { + m_solver->assert_expr(mk_not(mk_and(lits))); + } + + // ------------------------------- + // euf_mbi, TBD + + euf_mbi_plugin::euf_mbi_plugin(solver* s): m(s->get_manager()), m_solver(s) {} + + mbi_result euf_mbi_plugin::operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { + lbool r = m_solver->check_sat(lits); + switch (r) { + case l_false: + lits.reset(); + m_solver->get_unsat_core(lits); + return mbi_unsat; + case l_true: + m_solver->get_model(mdl); + lits.reset(); + for (unsigned i = 0, sz = mdl->get_num_constants(); i < sz; ++i) { + func_decl* c = mdl->get_constant(i); + if (vars.contains(c)) { + if (m.is_true(mdl->get_const_interp(c))) { + lits.push_back(m.mk_const(c)); + } + else { + lits.push_back(m.mk_not(m.mk_const(c))); + } + } + } + return mbi_sat; + default: + return mbi_undef; + } + } + + void euf_mbi_plugin::block(expr_ref_vector const& lits) { m_solver->assert_expr(mk_not(mk_and(lits))); } - /** + + /** -------------------------------------------------------------- * ping-pong interpolation of Gurfinkel & Vizel + * compute a binary interpolant. */ lbool interpolator::binary(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { ast_manager& m = vars.get_manager(); model_ref mdl; - literal_vector lits(m); + expr_ref_vector lits(m); bool turn = true; vector itps, blocks; - ipts.push_back(expr_ref_vector(m)); - ipts.push_back(expr_ref_vector(m)); + itps.push_back(expr_ref_vector(m)); + itps.push_back(expr_ref_vector(m)); blocks.push_back(expr_ref_vector(m)); blocks.push_back(expr_ref_vector(m)); mbi_result last_res = mbi_undef; @@ -74,18 +127,20 @@ namespace qe { return l_true; } break; // continue - case mbi_unsat: - if (last_res == mbi_unsat) { + case mbi_unsat: { + if (lits.empty()) { itp = mk_and(itps[turn]); return l_false; } t2->block(lits); - expr_ref lemma(m.mk_not(mk_and(lits)), m); + expr_ref lemma(mk_not(mk_and(lits))); blocks[turn].push_back(lemma); - itps[turn].push_back(m.mk_implies(mk_and(blocks[!turn]), lemma)); + itp = m.mk_implies(mk_and(blocks[!turn]), lemma); + // TBD: compute closure over variables not in vars + itps[turn].push_back(itp); lits.reset(); // or find a prefix of lits? - next_res = mbi_undef; // hard restart. break; + } case mbi_augment: break; case mbi_undef: diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 4aad92f82..dad29167f 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -29,7 +29,8 @@ namespace qe { }; class mbi_plugin { - virtual ~mbi_plugin(); + public: + virtual ~mbi_plugin() {} /** * \brief Utility that works modulo a background state. * - vars @@ -57,8 +58,18 @@ namespace qe { virtual void block(expr_ref_vector const& lits) = 0; }; - class euf_mbi_plugin : mbi_plugin { + class prop_mbi_plugin : public mbi_plugin { solver_ref m_solver; + public: + prop_mbi_plugin(solver* s); + ~prop_mbi_plugin() override {} + mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; + void block(expr_ref_vector const& lits) override; + }; + + class euf_mbi_plugin : public mbi_plugin { + ast_manager& m; + solver_ref m_solver; public: euf_mbi_plugin(solver* s); ~euf_mbi_plugin() override {} @@ -70,6 +81,7 @@ namespace qe { * use cases for interpolation. */ class interpolator { + public: static lbool binary(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); }; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 0680d7bcf..8dec3335e 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3067,6 +3067,41 @@ namespace smt { return m_asserted_formulas.inconsistent(); } + static bool is_valid_assumption(ast_manager & m, expr * assumption) { + expr* arg; + if (!m.is_bool(assumption)) + return false; + if (is_uninterp_const(assumption)) + return true; + if (m.is_not(assumption, arg) && is_uninterp_const(arg)) + return true; + if (!is_app(assumption)) + return false; + if (to_app(assumption)->get_num_args() == 0) + return true; + if (m.is_not(assumption, arg) && is_app(arg) && to_app(arg)->get_num_args() == 0) + return true; + return false; + } + + void context::internalize_proxies(expr_ref_vector const& asms, vector>& asm2proxy) { + for (expr* e : asms) { + if (is_valid_assumption(m_manager, e)) { + asm2proxy.push_back(std::make_pair(e, expr_ref(e, m_manager))); + } + else { + expr_ref proxy(m_manager), fml(m_manager); + proxy = m_manager.mk_fresh_const("proxy", m_manager.mk_bool_sort()); + fml = m_manager.mk_implies(proxy, e); + m_asserted_formulas.assert_expr(fml); + asm2proxy.push_back(std::make_pair(e, proxy)); + } + } + // The new assertions are of the form 'proxy => assumption' + // so clause simplification is sound even as these are removed after pop_scope. + internalize_assertions(); + } + void context::internalize_assertions() { if (get_cancel_flag()) return; TRACE("internalize_assertions", tout << "internalize_assertions()...\n";); @@ -3102,23 +3137,6 @@ namespace smt { TRACE("after_internalize_assertions", display(tout);); } - bool is_valid_assumption(ast_manager & m, expr * assumption) { - expr* arg; - if (!m.is_bool(assumption)) - return false; - if (is_uninterp_const(assumption)) - return true; - if (m.is_not(assumption, arg) && is_uninterp_const(arg)) - return true; - if (!is_app(assumption)) - return false; - if (to_app(assumption)->get_num_args() == 0) - return true; - if (m.is_not(assumption, arg) && is_app(arg) && to_app(arg)->get_num_args() == 0) - return true; - return false; - } - /** \brief Assumptions must be uninterpreted boolean constants (aka propositional variables). */ @@ -3205,17 +3223,21 @@ namespace smt { if (get_cancel_flag()) return; push_scope(); - for (expr * curr_assumption : asms) { + vector> asm2proxy; + internalize_proxies(asms, asm2proxy); + for (auto const& p: asm2proxy) { + expr_ref curr_assumption = p.second; + expr* orig_assumption = p.first; if (m_manager.is_true(curr_assumption)) continue; SASSERT(is_valid_assumption(m_manager, curr_assumption)); proof * pr = m_manager.mk_asserted(curr_assumption); internalize_assertion(curr_assumption, pr, 0); literal l = get_literal(curr_assumption); - m_literal2assumption.insert(l.index(), curr_assumption); + m_literal2assumption.insert(l.index(), orig_assumption); // mark_as_relevant(l); <<< not needed // internalize_assertion marked l as relevant. SASSERT(is_relevant(l)); - TRACE("assumptions", tout << l << ":" << mk_pp(curr_assumption, m_manager) << "\n";); + TRACE("assumptions", tout << l << ":" << curr_assumption << " " << mk_pp(orig_assumption, m_manager) << "\n";); if (m_manager.proofs_enabled()) assign(l, mk_justification(justification_proof_wrapper(*this, pr))); else @@ -3386,7 +3408,7 @@ namespace smt { setup_context(false); expr_ref_vector asms(m_manager, num_assumptions, assumptions); if (!already_did_theory_assumptions) add_theory_assumptions(asms); - if (!validate_assumptions(asms)) return l_undef; + // introducing proxies: if (!validate_assumptions(asms)) return l_undef; TRACE("unsat_core_bug", tout << asms << "\n";); internalize_assertions(); init_assumptions(asms); @@ -3402,7 +3424,7 @@ namespace smt { setup_context(false); expr_ref_vector asms(cube); add_theory_assumptions(asms); - if (!validate_assumptions(asms)) return l_undef; + // introducing proxies: if (!validate_assumptions(asms)) return l_undef; for (auto const& clause : clauses) if (!validate_assumptions(clause)) return l_undef; internalize_assertions(); init_assumptions(asms); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 16c1c7ac3..7e09c3be2 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1536,6 +1536,8 @@ namespace smt { void internalize_assertion(expr * n, proof * pr, unsigned generation); + void internalize_proxies(expr_ref_vector const& asms, vector>& asm2proxy); + void internalize_instance(expr * body, proof * pr, unsigned generation) { internalize_assertion(body, pr, generation); if (relevancy()) From 0784074b674c5ad348a22feba03fa476e8a8d637 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 10:18:18 -0700 Subject: [PATCH 1168/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 2 ++ src/qe/qe_mbi.cpp | 7 ++++++- src/smt/smt_context.cpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index c6cd1020e..5e8a687c7 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -429,6 +429,8 @@ public: params_ref p; solver_ref sA = sf(m, p, false /* no proofs */, true, true, symbol::null); solver_ref sB = sf(m, p, false /* no proofs */, true, true, symbol::null); + sA->assert_expr(a); + sB->assert_expr(b); qe::prop_mbi_plugin pA(sA.get()); qe::prop_mbi_plugin pB(sB.get()); lbool res = mbi.binary(pA, pB, vars, itp); diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index f149af764..8be15ed7f 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -104,6 +104,7 @@ namespace qe { /** -------------------------------------------------------------- * ping-pong interpolation of Gurfinkel & Vizel * compute a binary interpolant. + * TBD: also implement the one-sided versions that create clausal interpolants. */ lbool interpolator::binary(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { ast_manager& m = vars.get_manager(); @@ -126,14 +127,18 @@ namespace qe { itp = nullptr; return l_true; } + TRACE("mbi", tout << "new lits " << lits << "\n";); break; // continue case mbi_unsat: { if (lits.empty()) { - itp = mk_and(itps[turn]); + // TBD, either a => itp and itp => !b + // or b => itp and itp => !a + itp = mk_and(itps[!turn]); return l_false; } t2->block(lits); expr_ref lemma(mk_not(mk_and(lits))); + TRACE("mbi", tout << lemma << "\n";); blocks[turn].push_back(lemma); itp = m.mk_implies(mk_and(blocks[!turn]), lemma); // TBD: compute closure over variables not in vars diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 8dec3335e..b60a9db71 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3061,7 +3061,7 @@ namespace smt { bool context::reduce_assertions() { if (!m_asserted_formulas.inconsistent()) { - SASSERT(at_base_level()); + // SASSERT(at_base_level()); m_asserted_formulas.reduce(); } return m_asserted_formulas.inconsistent(); From 2e44850df9134cd3c1cb6309fe7a126515e1a103 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 10:50:40 -0700 Subject: [PATCH 1169/1283] move term graph closer to qe Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/CMakeLists.txt | 1 - src/muz/spacer/spacer_generalizers.cpp | 4 +- src/muz/spacer/spacer_quant_generalizer.cpp | 2 +- src/muz/spacer/spacer_term_graph.cpp | 519 -------------------- src/muz/spacer/spacer_term_graph.h | 97 ---- src/muz/spacer/spacer_util.cpp | 6 +- src/qe/CMakeLists.txt | 1 + src/qe/qe_mbi.cpp | 25 +- 8 files changed, 20 insertions(+), 635 deletions(-) delete mode 100644 src/muz/spacer/spacer_term_graph.cpp delete mode 100644 src/muz/spacer/spacer_term_graph.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 22218f25f..43fffd9fb 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -19,7 +19,6 @@ z3_add_component(spacer spacer_antiunify.cpp spacer_mev_array.cpp spacer_qe_project.cpp - spacer_term_graph.cpp spacer_sem_matcher.cpp spacer_quant_generalizer.cpp spacer_callback.cpp diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index d7c7429ee..4e5b60698 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -26,11 +26,11 @@ Revision History: #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" #include "ast/factor_equivs.h" -#include "muz/spacer/spacer_term_graph.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/substitution/matcher.h" #include "ast/expr_functors.h" #include "smt/smt_solver.h" +#include "qe/qe_term_graph.h" namespace spacer { void lemma_sanity_checker::operator()(lemma_ref &lemma) { @@ -317,7 +317,7 @@ void lemma_eq_generalizer::operator() (lemma_ref &lemma) if (lemma->get_cube().empty()) return; ast_manager &m = m_ctx.get_ast_manager(); - spacer::term_graph egraph(m); + qe::term_graph egraph(m); egraph.add_lits(lemma->get_cube()); // -- expand the cube with all derived equalities diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index f9525b2f6..f3425817b 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -27,7 +27,7 @@ Revision History: #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" #include "ast/factor_equivs.h" -#include "muz/spacer/spacer_term_graph.h" +#include "qe/qe_term_graph.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/substitution/matcher.h" #include "ast/expr_functors.h" diff --git a/src/muz/spacer/spacer_term_graph.cpp b/src/muz/spacer/spacer_term_graph.cpp deleted file mode 100644 index 0dc29a7c5..000000000 --- a/src/muz/spacer/spacer_term_graph.cpp +++ /dev/null @@ -1,519 +0,0 @@ -#include "muz/spacer/spacer_term_graph.h" -#include "util/util.h" -#include "ast/ast_pp.h" -#include "ast/ast_util.h" -#include "ast/for_each_expr.h" - -namespace spacer { - -class term { - // -- an app represented by this term - app* m_app; - // -- root of the equivalence class - term* m_root; - // -- next element in the equivalence class (cyclic linked list) - term* m_next; - // -- eq class size - unsigned m_class_size; - - // -- general purpose mark - unsigned m_mark:1; - // -- general purpose second mark - unsigned m_mark2:1; - // -- is an interpreted constant - unsigned m_interpreted:1; - - // -- terms that contain this term as a child - //ptr_vector m_uses; - - // ptr_vector m_args; - -public: - term(app* a) : m_app(a), m_root(this), m_next(this), - m_class_size(1), m_mark(false), m_mark2(false), - m_interpreted(false) {} - - ~term() {} - - unsigned get_id() const {return m_app->get_id();} - - bool is_marked() const {return m_mark;} - void set_mark(bool v){m_mark = v;} - bool is_marked2() const {return m_mark2;} - void set_mark2(bool v){m_mark2 = v;} - - bool is_interpreted() const {return m_interpreted;} - void mark_as_interpreted() {m_interpreted=true;} - app* get_app() const {return m_app;} - - term &get_root() const {return *m_root;} - bool is_root() const {return m_root == this;} - void set_root(term &r) {m_root = &r;} - term &get_next() const {return *m_next;} - - unsigned get_class_size() const {return m_class_size;} - - void merge_eq_class(term &b) { - std::swap(this->m_next, b.m_next); - m_class_size += b.get_class_size(); - // -- reset (useful for debugging) - b.m_class_size = 0; - } - - // -- make this term the root of its equivalence class - void mk_root() { - if (is_root()) return; - - term *curr = this; - do { - if (curr->is_root()) { - // found previous root - SASSERT(curr != this); - m_class_size = curr->get_class_size(); - curr->m_class_size = 0; - } - curr->set_root(*this); - curr = &curr->get_next(); - } - while (curr != this); - } -}; - -class arith_term_graph_plugin : public term_graph_plugin { - term_graph &m_g; - ast_manager &m; - arith_util m_arith; - -public: - arith_term_graph_plugin(term_graph &g) : - term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), - m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} - - virtual ~arith_term_graph_plugin() {} - - bool mk_eq_core (expr *_e1, expr *_e2, app_ref &res) { - expr *e1, *e2; - e1 = _e1; - e2 = _e2; - - if (m_arith.is_zero(e1)) { - std::swap(e1, e2); - } - // y + -1*x == 0 --> y = x - expr *a0 = 0, *a1 = 0, *x = 0; - if (m_arith.is_zero(e2) && m_arith.is_add(e1, a0, a1)) { - if (m_arith.is_times_minus_one(a1, x)) { - e1 = a0; - e2 = x; - } - else if (m_arith.is_times_minus_one(a0, x)) { - e1 = a1; - e2 = x; - } - } - res = m.mk_eq(e1, e2); - return true; - } - - app* mk_le_zero(expr *arg) { - expr *e1, *e2, *e3; - // XXX currently disabled - if (m_arith.is_add(arg, e1, e2)) { - // e1-e2<=0 --> e1<=e2 - if (m_arith.is_times_minus_one(e2, e3)) { - return m_arith.mk_le(e1, e3); - } - // -e1+e2<=0 --> e2<=e1 - else if (m_arith.is_times_minus_one(e1, e3)) { - return m_arith.mk_le(e2, e3); - } - } - return m_arith.mk_le(arg, mk_zero()); - } - app* mk_ge_zero(expr *arg) { - expr *e1, *e2, *e3; - // XXX currently disabled - if (m_arith.is_add(arg, e1, e2)) { - // e1-e2>=0 --> e1>=e2 - if (m_arith.is_times_minus_one(e2, e3)) { - return m_arith.mk_ge(e1, e3); - } - // -e1+e2>=0 --> e2>=e1 - else if (m_arith.is_times_minus_one(e1, e3)) { - return m_arith.mk_ge(e2, e3); - } - } - return m_arith.mk_ge(arg, mk_zero()); - } - - bool mk_le_core (expr *arg1, expr * arg2, app_ref &result) { - // t <= -1 ==> t < 0 ==> ! (t >= 0) - rational n; - if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { - result = m.mk_not (mk_ge_zero (arg1)); - return true; - } - else if (m_arith.is_zero(arg2)) { - result = mk_le_zero(arg1); - return true; - } - else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n < 0) { - // t <= n ==> t < n + 1 ==> ! (t >= n + 1) - result = m.mk_not(m_arith.mk_ge(arg1, m_arith.mk_numeral(n+1, true))); - return true; - } - return false; - } - - expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} - bool is_one (expr const * n) const { - rational val; - return m_arith.is_numeral (n, val) && val.is_one (); - } - - bool mk_ge_core (expr * arg1, expr * arg2, app_ref &result) { - // t >= 1 ==> t > 0 ==> ! (t <= 0) - rational n; - if (m_arith.is_int (arg1) && is_one (arg2)) { - result = m.mk_not (mk_le_zero (arg1)); - return true; - } - else if (m_arith.is_zero(arg2)) { - result = mk_ge_zero(arg1); - return true; - } - else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n > 0) { - // t >= n ==> t > n - 1 ==> ! (t <= n - 1) - result = m.mk_not(m_arith.mk_le(arg1, m_arith.mk_numeral(n-1, true))); - return true; - } - return false; - } - - virtual app_ref process_lit (app *_lit) { - app *lit = _lit; - expr *e1, *e2; - - // strip negation - bool is_neg = m.is_not(lit); - if (is_neg) { - lit = to_app(to_app(lit)->get_arg(0)); - } - - app_ref res(m); - res = lit; - if (m.is_eq (lit, e1, e2)) { - mk_eq_core(e1, e2, res); - } - else if (m_arith.is_le(lit, e1, e2)) { - mk_le_core(e1, e2, res); - } - else if (m_arith.is_ge(lit, e1, e2)) { - mk_ge_core(e1, e2, res); - } - - // restore negation - if (is_neg) { - res = m.mk_not(res); - } - - return res; - } -}; - -term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { - m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); -} -term_graph::~term_graph() { - std::for_each(m_terms.begin(), m_terms.end(), delete_proc()); -} - -static family_id get_family_id(ast_manager &m, app *lit) { - family_id fid = null_family_id; - - expr *e1, *e2, *e3; - // strip negation - if (!m.is_not (lit, e1)) { e1 = lit; } - - // deal with equality using sort of range - if (m.is_eq (e1, e2, e3)) { - fid = get_sort (e2)->get_family_id(); - } - // extract family_id of top level app - else { - fid = to_app(e1)->get_decl()->get_family_id(); - } - - return fid; -} - -void term_graph::add_lit(app *l) { - app_ref lit(m); - - family_id fid = get_family_id (m, l); - term_graph_plugin *pin = m_plugins.get_plugin(fid); - if (pin) { - lit = pin->process_lit(l); - } else { - lit = l; - } - m_lits.push_back(lit); - internalize_lit(lit); -} - -bool term_graph::is_internalized(app *a) { - return m_app2term.contains(a->get_id()); -} - -term* term_graph::get_term(app *a) { - term *res; - return m_app2term.find (a->get_id(), res) ? res : nullptr; -} - -term *term_graph::mk_term(app *a) { - term *t; - t = alloc(term, a); - if (a->get_num_args() == 0 && m.is_unique_value(a)){ - t->mark_as_interpreted(); - } - - m_terms.push_back(t); - m_app2term.insert(a->get_id(), t); - return t; -} - -term *term_graph::internalize_term(app *t) { - term *res = get_term(t); - - if (!res) { - for (unsigned i=0, sz=t->get_num_args(); i < sz; ++i) { - expr *arg = t->get_arg(i); - SASSERT(is_app(arg)); - internalize_term(::to_app(arg)); - } - res = mk_term(t); - } - return res; -} - -void term_graph::internalize_eq(app *a1, app* a2) { - internalize_lit(a1); - internalize_lit(a2); - - term *t1, *t2; - t1 = get_term(a1); - t2 = get_term(a2); - SASSERT(t1); - SASSERT(t2); - - merge(t1->get_root(), t2->get_root()); -} - -void term_graph::internalize_lit(app* lit) { - if (is_internalized(lit)) return; - - expr *e1, *e2; - if (m.is_eq (lit, e1, e2)) { - SASSERT(is_app(e1)); - SASSERT(is_app(e2)); - internalize_eq (::to_app(e1), ::to_app(e2)); - } - else { - internalize_term(lit); - } -} - -void term_graph::merge (term &t1, term &t2) { - SASSERT(t1.is_root()); - SASSERT(t2.is_root()); - - if (&t1 == &t2) return; - - term *a = &t1; - term *b = &t2; - if (a->get_class_size() > b->get_class_size()) { - std::swap(a, b); - } - - // make 'a' be the root of the equivalence class of 'b' - b->set_root(*a); - for (term *it = &b->get_next(); it != b; it = &it->get_next()) { - it->set_root(*a); - } - - // merge equivalence classes - a->merge_eq_class(*b); - - // -- merge might have invalidated term2map cache - m_term2app.reset(); - m_pinned.reset(); -} - -app* term_graph::mk_app_core (app *a) { - expr_ref_vector kids(m); - for (unsigned i = 0, sz = a->get_num_args(); i < sz; ++i) { - kids.push_back (mk_app(::to_app(a->get_arg(i)))); - } - - app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); - m_pinned.push_back(res); - - return res; -} - -app_ref term_graph::mk_app(term const &r) { - SASSERT(r.is_root()); - - if (r.get_app()->get_num_args() == 0) { - return app_ref(r.get_app(), m); - } - - app* res; - if (m_term2app.find(r.get_id(), res)) { - return app_ref(res, m); - } - - res = mk_app_core (r.get_app()); - m_term2app.insert(r.get_id(), res); - return app_ref(res, m); - -} -app_ref term_graph::mk_app(app *a) { - term *t = get_term(a); - if (!t) {return app_ref(a, m);} - - term &r = t->get_root(); - return mk_app(r); - -} - -void term_graph::mk_equalities(term const &t, app_ref_vector &out) { - SASSERT(t.is_root()); - app_ref rep(m); - rep = mk_app(t); - - for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { - app* mem; - mem = mk_app_core(it->get_app()); - out.push_back (m.mk_eq (rep, mem)); - } -} - -void term_graph::mk_all_equalities(term const &t, app_ref_vector &out) { - mk_equalities(t, out); - - for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { - app* a1; - a1 = mk_app_core (it->get_app()); - for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { - app *a2; - a2 = mk_app_core(it2->get_app()); - out.push_back (m.mk_eq (a1, a2)); - } - } -} - -void term_graph::reset_marks() { - for (unsigned i = 0, sz = m_terms.size(); i < sz; ++i) { - term *t = m_terms.get(i); - t->set_mark(false); - } -} - -/// Order of preference for roots of equivalence classes -/// XXX This should be factored out to let clients control the preference -bool term_graph::term_le(term const &t1, term const &t2) { - - // prefer constants over applications - // prefer uninterpreted constants over values - // prefer smaller expressions over larger ones - app *a1, *a2; - a1 = t1.get_app(); - a2 = t2.get_app(); - if (a1->get_num_args() == 0 && a2->get_num_args() > 0) { - return true; - } - if (a1->get_num_args() == a2->get_num_args()) { - return m.is_value(a2); - } - - unsigned sz1 = get_num_exprs(a1); - unsigned sz2 = get_num_exprs(a2); - return sz1 < sz2; -} - -void term_graph::pick_root (term &t) { - term *r = &t; - for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { - it->set_mark(true); - if (term_le(*it, *r)) { r = it; } - } - - // -- if found something better, make it the new root - if (r != &t) { - r->mk_root(); - } -} -/// Choose better roots for equivalence classes -void term_graph::pick_roots() { - for (unsigned i = 0, sz = m_terms.size(); i < sz; ++i) { - term *t = m_terms.get(i); - if (t->is_marked() || !t->is_root()) {continue;} - pick_root(*t); - } - reset_marks(); -} - -void term_graph::display(std::ostream &out) { - for (unsigned i = 0, sz = m_terms.size(); i < sz; ++i) { - term *t = m_terms.get(i); - out << mk_pp(t->get_app(), m) << " is root " << t->is_root() - << " cls sz " << t->get_class_size() - << " term " << t - << "\n"; - } -} -void term_graph::to_lits (app_ref_vector &lits, bool all_equalities) { - pick_roots(); - - for (unsigned i = 0, sz = m_lits.size(); i < sz; ++i) { - app *a = m_lits.get(i); - if (is_internalized(a)) { - lits.push_back (mk_app(a)); - } - } - - for (unsigned i = 0, sz = m_terms.size(); i < sz; ++i) { - term *t = m_terms.get(i); - if (!t->is_root()) {continue;} - - if (all_equalities) { - mk_all_equalities (*t, lits); - } else { - mk_equalities(*t, lits); - } - } -} -void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { - app_ref_vector out(m); - to_lits (out, all_equalities); - for (unsigned i = 0, sz = out.size(); i < sz; ++i) { - lits.push_back(out.get(i)); - } -} - -app_ref term_graph::to_app() { - app_ref_vector lits(m); - to_lits(lits); - return mk_and(lits); -} - -void term_graph::reset() { - m_term2app.reset(); - m_pinned.reset(); - m_app2term.reset(); - m_terms.reset(); - m_lits.reset(); -} - -} diff --git a/src/muz/spacer/spacer_term_graph.h b/src/muz/spacer/spacer_term_graph.h deleted file mode 100644 index b547adef3..000000000 --- a/src/muz/spacer/spacer_term_graph.h +++ /dev/null @@ -1,97 +0,0 @@ -/**++ -Copyright (c) Arie Gurfinkel - -Module Name: - - spacer_term_graph.h - -Abstract: - - Equivalence graph of terms - -Author: - - Arie Gurfinkel - -Notes: - ---*/ -#ifndef _SPACER_TERM_GRAPH_H_ -#define _SPACER_TERM_GRAPH_H_ - -#include "ast/ast.h" - -#include "util/plugin_manager.h" - -namespace spacer { - -class term; - -class term_graph_plugin { - family_id m_id; -public: - term_graph_plugin(family_id fid) : m_id(fid) {} - virtual ~term_graph_plugin() {} - - family_id get_family_id() const {return m_id;} - - /// Process (and potentially augment) a literal - virtual app_ref process_lit (app *lit) = 0; -}; - -class term_graph { - ast_manager &m; - ptr_vector m_terms; - app_ref_vector m_lits; - u_map m_app2term; - - app_ref_vector m_pinned; - u_map m_term2app; - - plugin_manager m_plugins; - - void merge(term &t1, term &t2); - - term *mk_term(app *t); - term *get_term(app *t); - - term *internalize_term(app *t); - void internalize_eq(app *a1, app *a2); - void internalize_lit(app *lit); - - bool is_internalized(app *a); - - bool term_le(term const &t1, term const &t2); - void pick_root (term &t); - void pick_roots(); - - void reset_marks(); - - app *mk_app_core(app* a); - app_ref mk_app(term const &t); - app_ref mk_app(app *a); - void mk_equalities(term const &t, app_ref_vector &out); - void mk_all_equalities(term const &t, app_ref_vector &out); - void display(std::ostream &out); -public: - term_graph(ast_manager &man); - ~term_graph(); - - ast_manager &get_ast_manager() const {return m;} - - void add_lit(app *lit); - void add_lits(expr_ref_vector const &lits) { - for (unsigned i = 0, sz = lits.size(); i < sz; ++i) { - add_lit(::to_app(lits.get(i))); - } - } - - void reset(); - void to_lits(app_ref_vector &lits, bool all_equalities = false); - void to_lits(expr_ref_vector &lits, bool all_equalities = false); - app_ref to_app(); - -}; - -} -#endif diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index da946e211..29d72fabd 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -65,7 +65,7 @@ Notes: #include "tactic/arith/arith_bounds_tactic.h" #include "ast/factor_equivs.h" -#include "muz/spacer/spacer_term_graph.h" +#include "qe/qe_term_graph.h" namespace spacer { @@ -742,7 +742,7 @@ namespace { } if (use_factor_eqs) { // -- refactor equivalence classes and choose a representative - spacer::term_graph egraph(out.m()); + qe::term_graph egraph(out.m()); egraph.add_lits (v); v.reset(); egraph.to_lits(v); @@ -754,7 +754,7 @@ namespace { << "to\n" << mk_and(v) << "\n";); TRACE("spacer_normalize", - spacer::term_graph egraph(out.m()); + qe::term_graph egraph(out.m()); for (expr* e : v) egraph.add_lit (to_app(e)); tout << "Reduced app:\n" << mk_pp(egraph.to_app(), out.m()) << "\n";); diff --git a/src/qe/CMakeLists.txt b/src/qe/CMakeLists.txt index d43db34f0..d771ec62e 100644 --- a/src/qe/CMakeLists.txt +++ b/src/qe/CMakeLists.txt @@ -18,6 +18,7 @@ z3_add_component(qe qe_mbi.cpp qe_sat_tactic.cpp qe_tactic.cpp + qe_term_graph.cpp qsat.cpp COMPONENT_DEPENDENCIES nlsat_tactic diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 8be15ed7f..aea5ad978 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -76,22 +76,23 @@ namespace qe { lits.reset(); m_solver->get_unsat_core(lits); return mbi_unsat; - case l_true: + case l_true: { + expr_ref_vector fmls(m); m_solver->get_model(mdl); lits.reset(); - for (unsigned i = 0, sz = mdl->get_num_constants(); i < sz; ++i) { - func_decl* c = mdl->get_constant(i); - if (vars.contains(c)) { - if (m.is_true(mdl->get_const_interp(c))) { - lits.push_back(m.mk_const(c)); - } - else { - lits.push_back(m.mk_not(m.mk_const(c))); - } - } - } + // 1. extract formulas from solver + // 2. extract implicant over formulas + // 3. extract equalities or other assignments over the congruence classes + m_solver->get_assertions(fmls); + NOT_IMPLEMENTED_YET(); return mbi_sat; + } default: + // TBD: if not running solver to completion, then: + // 1. extract unit literals from m_solver. + // 2. run a cc over the units + // 3. extract equalities or other assignments over the congruence classes + // 4. ensure that at least some progress is made over original lits. return mbi_undef; } } From 14696f03f724ed09b7707175f3acb87786971703 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 10:57:57 -0700 Subject: [PATCH 1170/1283] add some review comments Signed-off-by: Nikolaj Bjorner --- src/qe/qe_term_graph.cpp | 525 +++++++++++++++++++++++++++++++++++++++ src/qe/qe_term_graph.h | 94 +++++++ 2 files changed, 619 insertions(+) create mode 100644 src/qe/qe_term_graph.cpp create mode 100644 src/qe/qe_term_graph.h diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp new file mode 100644 index 000000000..d0bcc11c4 --- /dev/null +++ b/src/qe/qe_term_graph.cpp @@ -0,0 +1,525 @@ +/**++ +Copyright (c) Arie Gurfinkel + +Module Name: + + qe_term_graph.cpp + +Abstract: + + Equivalence graph of terms + +Author: + + Arie Gurfinkel + +Notes: + +--*/ + +#include "util/util.h" +#include "ast/ast_pp.h" +#include "ast/ast_util.h" +#include "ast/for_each_expr.h" +#include "qe/qe_term_graph.h" + +namespace qe { + +class term { + // -- an app represented by this term + app* m_app; + // -- root of the equivalence class + term* m_root; + // -- next element in the equivalence class (cyclic linked list) + term* m_next; + // -- eq class size + unsigned m_class_size; + + // -- general purpose mark + unsigned m_mark:1; + // -- general purpose second mark + unsigned m_mark2:1; + // -- is an interpreted constant + unsigned m_interpreted:1; + + // -- terms that contain this term as a child + //ptr_vector m_uses; + + // ptr_vector m_args; + +public: + term(app* a) : m_app(a), m_root(this), m_next(this), + m_class_size(1), m_mark(false), m_mark2(false), + m_interpreted(false) {} + + ~term() {} + + unsigned get_id() const {return m_app->get_id();} + + bool is_marked() const {return m_mark;} + void set_mark(bool v){m_mark = v;} + bool is_marked2() const {return m_mark2;} + void set_mark2(bool v){m_mark2 = v;} + + bool is_interpreted() const {return m_interpreted;} + void mark_as_interpreted() {m_interpreted=true;} + app* get_app() const {return m_app;} + + term &get_root() const {return *m_root;} + bool is_root() const {return m_root == this;} + void set_root(term &r) {m_root = &r;} + term &get_next() const {return *m_next;} + + unsigned get_class_size() const {return m_class_size;} + + void merge_eq_class(term &b) { + std::swap(this->m_next, b.m_next); + m_class_size += b.get_class_size(); + // -- reset (useful for debugging) + b.m_class_size = 0; + } + + // -- make this term the root of its equivalence class + void mk_root() { + if (is_root()) return; + + term *curr = this; + do { + if (curr->is_root()) { + // found previous root + SASSERT(curr != this); + m_class_size = curr->get_class_size(); + curr->m_class_size = 0; + } + curr->set_root(*this); + curr = &curr->get_next(); + } + while (curr != this); + } +}; + +class arith_term_graph_plugin : public term_graph_plugin { + term_graph &m_g; + ast_manager &m; + arith_util m_arith; + +public: + arith_term_graph_plugin(term_graph &g) : + term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), + m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} + + virtual ~arith_term_graph_plugin() {} + + bool mk_eq_core (expr *_e1, expr *_e2, app_ref &res) { + expr *e1, *e2; + e1 = _e1; + e2 = _e2; + + if (m_arith.is_zero(e1)) { + std::swap(e1, e2); + } + // y + -1*x == 0 --> y = x + expr *a0 = 0, *a1 = 0, *x = 0; + if (m_arith.is_zero(e2) && m_arith.is_add(e1, a0, a1)) { + if (m_arith.is_times_minus_one(a1, x)) { + e1 = a0; + e2 = x; + } + else if (m_arith.is_times_minus_one(a0, x)) { + e1 = a1; + e2 = x; + } + } + res = m.mk_eq(e1, e2); + return true; + } + + app* mk_le_zero(expr *arg) { + expr *e1, *e2, *e3; + // XXX currently disabled + if (m_arith.is_add(arg, e1, e2)) { + // e1-e2<=0 --> e1<=e2 + if (m_arith.is_times_minus_one(e2, e3)) { + return m_arith.mk_le(e1, e3); + } + // -e1+e2<=0 --> e2<=e1 + else if (m_arith.is_times_minus_one(e1, e3)) { + return m_arith.mk_le(e2, e3); + } + } + return m_arith.mk_le(arg, mk_zero()); + } + + app* mk_ge_zero(expr *arg) { + expr *e1, *e2, *e3; + // XXX currently disabled + if (m_arith.is_add(arg, e1, e2)) { + // e1-e2>=0 --> e1>=e2 + if (m_arith.is_times_minus_one(e2, e3)) { + return m_arith.mk_ge(e1, e3); + } + // -e1+e2>=0 --> e2>=e1 + else if (m_arith.is_times_minus_one(e1, e3)) { + return m_arith.mk_ge(e2, e3); + } + } + return m_arith.mk_ge(arg, mk_zero()); + } + + bool mk_le_core (expr *arg1, expr * arg2, app_ref &result) { + // t <= -1 ==> t < 0 ==> ! (t >= 0) + rational n; + if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { + result = m.mk_not (mk_ge_zero (arg1)); + return true; + } + else if (m_arith.is_zero(arg2)) { + result = mk_le_zero(arg1); + return true; + } + else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n < 0) { + // t <= n ==> t < n + 1 ==> ! (t >= n + 1) + result = m.mk_not(m_arith.mk_ge(arg1, m_arith.mk_numeral(n+1, true))); + return true; + } + return false; + } + + expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} + bool is_one (expr const * n) const { + rational val; + return m_arith.is_numeral (n, val) && val.is_one (); + } + + bool mk_ge_core (expr * arg1, expr * arg2, app_ref &result) { + // t >= 1 ==> t > 0 ==> ! (t <= 0) + rational n; + if (m_arith.is_int (arg1) && is_one (arg2)) { + result = m.mk_not (mk_le_zero (arg1)); + return true; + } + else if (m_arith.is_zero(arg2)) { + result = mk_ge_zero(arg1); + return true; + } + else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n > 0) { + // t >= n ==> t > n - 1 ==> ! (t <= n - 1) + result = m.mk_not(m_arith.mk_le(arg1, m_arith.mk_numeral(n-1, true))); + return true; + } + return false; + } + + virtual app_ref process_lit (app *_lit) { + app *lit = _lit; + expr *e1, *e2; + + // strip negation + bool is_neg = m.is_not(lit); + if (is_neg) { + lit = to_app(to_app(lit)->get_arg(0)); + } + + app_ref res(m); + res = lit; + if (m.is_eq (lit, e1, e2)) { + mk_eq_core(e1, e2, res); + } + else if (m_arith.is_le(lit, e1, e2)) { + mk_le_core(e1, e2, res); + } + else if (m_arith.is_ge(lit, e1, e2)) { + mk_ge_core(e1, e2, res); + } + + // restore negation + if (is_neg) { + res = m.mk_not(res); + } + + return res; + } +}; + +term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { + m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); +} +term_graph::~term_graph() { + reset(); +} + +static family_id get_family_id(ast_manager &m, app *lit) { + family_id fid = null_family_id; + + expr *e1, *e2, *e3; + // strip negation + if (!m.is_not (lit, e1)) { e1 = lit; } + + // deal with equality using sort of range + if (m.is_eq (e1, e2, e3)) { + fid = get_sort (e2)->get_family_id(); + } + // extract family_id of top level app + else { + fid = to_app(e1)->get_decl()->get_family_id(); + } + + return fid; +} + +void term_graph::add_lit(app *l) { + app_ref lit(m); + + family_id fid = get_family_id (m, l); + term_graph_plugin *pin = m_plugins.get_plugin(fid); + if (pin) { + lit = pin->process_lit(l); + } else { + lit = l; + } + m_lits.push_back(lit); + internalize_lit(lit); +} + +bool term_graph::is_internalized(app *a) { + return m_app2term.contains(a->get_id()); +} + +term* term_graph::get_term(app *a) { + term *res; + return m_app2term.find (a->get_id(), res) ? res : nullptr; +} + +term *term_graph::mk_term(app *a) { + term * t = alloc(term, a); + if (a->get_num_args() == 0 && m.is_unique_value(a)){ + t->mark_as_interpreted(); + } + + m_terms.push_back(t); + m_app2term.insert(a->get_id(), t); + return t; +} + +term *term_graph::internalize_term(app *t) { + term *res = get_term(t); + + if (!res) { + for (expr * arg : *t) { + SASSERT(is_app(arg)); + internalize_term(::to_app(arg)); + } + res = mk_term(t); + } + return res; +} + +void term_graph::internalize_eq(app *a1, app* a2) { + internalize_lit(a1); + internalize_lit(a2); + merge(get_term(a1)->get_root(), get_term(a2)->get_root()); +} + +void term_graph::internalize_lit(app* lit) { + if (is_internalized(lit)) return; + + expr *e1, *e2; + if (m.is_eq (lit, e1, e2)) { + SASSERT(is_app(e1)); + SASSERT(is_app(e2)); + internalize_eq (::to_app(e1), ::to_app(e2)); + } + else { + // NSB: this is thrown away. + // Is caller responsible for maintaining other predicates than equalities? + internalize_term(lit); + } +} + +void term_graph::merge (term &t1, term &t2) { + SASSERT(t1.is_root()); + SASSERT(t2.is_root()); + + if (&t1 == &t2) return; + + term *a = &t1; + term *b = &t2; + if (a->get_class_size() > b->get_class_size()) { + std::swap(a, b); + } + + // make 'a' be the root of the equivalence class of 'b' + b->set_root(*a); + for (term *it = &b->get_next(); it != b; it = &it->get_next()) { + it->set_root(*a); + } + + // merge equivalence classes + a->merge_eq_class(*b); + + // -- merge might have invalidated term2map cache + m_term2app.reset(); + m_pinned.reset(); +} + +app* term_graph::mk_app_core (app *a) { + expr_ref_vector kids(m); + for (expr * arg : *a) { + kids.push_back (mk_app(::to_app(arg))); + } + + app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); + m_pinned.push_back(res); + + return res; +} + +app_ref term_graph::mk_app(term const &r) { + SASSERT(r.is_root()); + + if (r.get_app()->get_num_args() == 0) { + return app_ref(r.get_app(), m); + } + + app* res; + if (m_term2app.find(r.get_id(), res)) { + return app_ref(res, m); + } + + res = mk_app_core (r.get_app()); + m_term2app.insert(r.get_id(), res); + return app_ref(res, m); + +} +app_ref term_graph::mk_app(app *a) { + term *t = get_term(a); + if (!t) + return app_ref(a, m); + else + return mk_app(t->get_root()); + +} + +void term_graph::mk_equalities(term const &t, app_ref_vector &out) { + SASSERT(t.is_root()); + app_ref rep(mk_app(t), m); + + for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { + app* mem = mk_app_core(it->get_app()); + out.push_back (m.mk_eq (rep, mem)); + } +} + +void term_graph::mk_all_equalities(term const &t, app_ref_vector &out) { + mk_equalities(t, out); + + for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { + app* a1 = mk_app_core (it->get_app()); + for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { + app *a2; + a2 = mk_app_core(it2->get_app()); + out.push_back (m.mk_eq (a1, a2)); + } + } +} + +void term_graph::reset_marks() { + for (term * t : m_terms) { + t->set_mark(false); + } +} + +/// Order of preference for roots of equivalence classes +/// XXX This should be factored out to let clients control the preference +bool term_graph::term_le(term const &t1, term const &t2) { + + // prefer constants over applications + // prefer uninterpreted constants over values + // prefer smaller expressions over larger ones + app *a1, *a2; + a1 = t1.get_app(); + a2 = t2.get_app(); + if (a1->get_num_args() == 0 && a2->get_num_args() > 0) { + return true; + } + // NSB: how does this possibly define an order? + if (a1->get_num_args() == a2->get_num_args()) { + return m.is_value(a2); + } + + unsigned sz1 = get_num_exprs(a1); + unsigned sz2 = get_num_exprs(a2); + return sz1 < sz2; +} + +void term_graph::pick_root (term &t) { + term *r = &t; + for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { + it->set_mark(true); + if (term_le(*it, *r)) { r = it; } + } + + // -- if found something better, make it the new root + if (r != &t) { + r->mk_root(); + } +} +/// Choose better roots for equivalence classes +void term_graph::pick_roots() { + for (term* t : m_terms) { + if (!t->is_marked() && t->is_root()) + pick_root(*t); + } + reset_marks(); +} + +void term_graph::display(std::ostream &out) { + for (term * t : m_terms) { + out << mk_pp(t->get_app(), m) << " is root " << t->is_root() + << " cls sz " << t->get_class_size() + << " term " << t + << "\n"; + } +} +void term_graph::to_lits (app_ref_vector &lits, bool all_equalities) { + pick_roots(); + + for (app * a : m_lits) { + if (is_internalized(a)) { + lits.push_back (mk_app(a)); + } + } + + for (term * t : m_terms) { + if (!t->is_root()) + continue; + else if (all_equalities) + mk_all_equalities (*t, lits); + else + mk_equalities(*t, lits); + } +} +void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { + app_ref_vector out(m); + to_lits (out, all_equalities); + for (app* a : out) { + lits.push_back(a); + } +} + +app_ref term_graph::to_app() { + app_ref_vector lits(m); + to_lits(lits); + return mk_and(lits); +} + +void term_graph::reset() { + m_term2app.reset(); + m_pinned.reset(); + m_app2term.reset(); + std::for_each(m_terms.begin(), m_terms.end(), delete_proc()); + m_terms.reset(); + m_lits.reset(); +} + +} diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h new file mode 100644 index 000000000..76d793e59 --- /dev/null +++ b/src/qe/qe_term_graph.h @@ -0,0 +1,94 @@ +/**++ +Copyright (c) Arie Gurfinkel + +Module Name: + + qe_term_graph.h + +Abstract: + + Equivalence graph of terms + +Author: + + Arie Gurfinkel + +Notes: + +--*/ +#ifndef QE_TERM_GRAPH_H__ +#define QE_TERM_GRAPH_H__ + +#include "ast/ast.h" +#include "util/plugin_manager.h" + +namespace qe { + + class term; + + class term_graph_plugin { + family_id m_id; + public: + term_graph_plugin(family_id fid) : m_id(fid) {} + virtual ~term_graph_plugin() {} + + family_id get_family_id() const {return m_id;} + + /// Process (and potentially augment) a literal + virtual app_ref process_lit (app *lit) = 0; + }; + + class term_graph { + ast_manager &m; + ptr_vector m_terms; + app_ref_vector m_lits; + u_map m_app2term; + + app_ref_vector m_pinned; + u_map m_term2app; + + plugin_manager m_plugins; + + void merge(term &t1, term &t2); + + term *mk_term(app *t); + term *get_term(app *t); + + term *internalize_term(app *t); + void internalize_eq(app *a1, app *a2); + void internalize_lit(app *lit); + + bool is_internalized(app *a); + + bool term_le(term const &t1, term const &t2); + void pick_root (term &t); + void pick_roots(); + + void reset_marks(); + + app *mk_app_core(app* a); + app_ref mk_app(term const &t); + app_ref mk_app(app *a); + void mk_equalities(term const &t, app_ref_vector &out); + void mk_all_equalities(term const &t, app_ref_vector &out); + void display(std::ostream &out); + public: + term_graph(ast_manager &man); + ~term_graph(); + + ast_manager &get_ast_manager() const { return m;} + + void add_lit(app *lit); + void add_lits(expr_ref_vector const &lits) { + for (expr* e : lits) add_lit(::to_app(e)); + } + + void reset(); + void to_lits(app_ref_vector &lits, bool all_equalities = false); + void to_lits(expr_ref_vector &lits, bool all_equalities = false); + app_ref to_app(); + + }; + +} +#endif From d26609ebdd6ade1087e2a7ace6552c74c87f1e82 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 14:50:46 -0700 Subject: [PATCH 1171/1283] prepare term-graph for cc Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 4 +- src/qe/qe_mbi.cpp | 16 +- src/qe/qe_mbi.h | 5 +- src/qe/qe_term_graph.cpp | 209 ++++++++++++++++-------- src/qe/qe_term_graph.h | 37 +++-- src/smt/smt_context.cpp | 18 +- 6 files changed, 193 insertions(+), 96 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 5e8a687c7..3a2f6fc85 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -421,7 +421,7 @@ public: for (func_decl* v : m_vars) { vars.push_back(v); } - qe::interpolator mbi; + qe::interpolator mbi(m); expr_ref a(m_a, m); expr_ref b(m_b, m); expr_ref itp(m); @@ -433,7 +433,7 @@ public: sB->assert_expr(b); qe::prop_mbi_plugin pA(sA.get()); qe::prop_mbi_plugin pB(sB.get()); - lbool res = mbi.binary(pA, pB, vars, itp); + lbool res = mbi.pingpong(pA, pB, vars, itp); ctx.regular_stream() << res << " " << itp << "\n"; } diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index aea5ad978..eea3087e2 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -49,8 +49,8 @@ namespace qe { if (m.is_true(mdl->get_const_interp(c))) { lits.push_back(m.mk_const(c)); } - else { - lits.push_back(m.mk_not(m.mk_const(c))); + else if (m.is_false(mdl->get_const_interp(c))) { + lits.push_back(m.mk_const(c)); } } } @@ -105,10 +105,8 @@ namespace qe { /** -------------------------------------------------------------- * ping-pong interpolation of Gurfinkel & Vizel * compute a binary interpolant. - * TBD: also implement the one-sided versions that create clausal interpolants. */ - lbool interpolator::binary(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { - ast_manager& m = vars.get_manager(); + lbool interpolator::pingpong(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { model_ref mdl; expr_ref_vector lits(m); bool turn = true; @@ -156,4 +154,12 @@ namespace qe { last_res = next_res; } } + + /** + * TBD: also implement the one-sided versions that create clausal interpolants. + */ + lbool interpolator::pogo(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { + NOT_IMPLEMENTED_YET(); + return l_undef; + } }; diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index dad29167f..d9af62bd0 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -81,8 +81,11 @@ namespace qe { * use cases for interpolation. */ class interpolator { + ast_manager& m; public: - static lbool binary(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); + interpolator(ast_manager& m):m(m) {} + lbool pingpong(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); + lbool pogo(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); }; #if 0 diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index d0bcc11c4..73412c50b 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -27,7 +27,7 @@ namespace qe { class term { // -- an app represented by this term - app* m_app; + expr* m_app; // NSB: to make usable with exprs // -- root of the equivalence class term* m_root; // -- next element in the equivalence class (cyclic linked list) @@ -43,27 +43,87 @@ class term { unsigned m_interpreted:1; // -- terms that contain this term as a child - //ptr_vector m_uses; + ptr_vector m_parents; - // ptr_vector m_args; + // arguments of term. + ptr_vector m_children; public: - term(app* a) : m_app(a), m_root(this), m_next(this), - m_class_size(1), m_mark(false), m_mark2(false), - m_interpreted(false) {} + term(expr* a, u_map& app2term) : + m_app(a), + m_root(this), + m_next(this), + m_class_size(1), + m_mark(false), + m_mark2(false), + m_interpreted(false) { + if (!is_app(a)) return; + for (expr* e : *to_app(a)) { + term* t = app2term[e->get_id()]; + t->m_parents.push_back(this); + m_children.push_back(t); + } + } ~term() {} - unsigned get_id() const {return m_app->get_id();} + class parents { + term const& t; + public: + parents(term const& _t):t(_t) {} + parents(term const* _t):t(*_t) {} + ptr_vector::const_iterator begin() const { return t.m_parents.begin(); } + ptr_vector::const_iterator end() const { return t.m_parents.end(); } + }; + + class children { + term const& t; + public: + children(term const& _t):t(_t) {} + children(term const* _t):t(*_t) {} + ptr_vector::const_iterator begin() const { return t.m_children.begin(); } + ptr_vector::const_iterator end() const { return t.m_children.end(); } + }; + + // Congruence table hash function is based on + // roots of children and function declaration. + + struct cg_hash { + unsigned operator()(term const* t) const { + unsigned a, b, c; + a = b = c = t->get_decl_id(); + for (term * ch : children(t)) { + a = ch->get_root().get_id(); + mix(a, b, c); + } + return c; + } + }; + + struct cg_eq { + bool operator()(term * t1, term * t2) const { + if (t1->get_decl_id() != t2->get_decl_id()) return false; + if (t1->m_children.size() != t2->m_children.size()) return false; + for (unsigned i = 0, sz = t1->m_children.size(); i < sz; ++ i) { + if (t1->m_children[i]->get_root().get_id() != t2->m_children[i]->get_root().get_id()) return false; + } + return true; + } + }; + + unsigned get_id() const { return m_app->get_id();} + + unsigned get_decl_id() const { return is_app(m_app) ? to_app(m_app)->get_decl()->get_id() : m_app->get_id(); } bool is_marked() const {return m_mark;} void set_mark(bool v){m_mark = v;} - bool is_marked2() const {return m_mark2;} - void set_mark2(bool v){m_mark2 = v;} + bool is_marked2() const {return m_mark2;} // NSB: where is this used? + void set_mark2(bool v){m_mark2 = v;} // NSB: where is this used? bool is_interpreted() const {return m_interpreted;} void mark_as_interpreted() {m_interpreted=true;} - app* get_app() const {return m_app;} + expr* get_app() const {return m_app;} + unsigned get_num_args() const { return is_app(m_app) ? to_app(m_app)->get_num_args() : 0; } term &get_root() const {return *m_root;} bool is_root() const {return m_root == this;} @@ -98,6 +158,8 @@ public: } }; + + class arith_term_graph_plugin : public term_graph_plugin { term_graph &m_g; ast_manager &m; @@ -244,6 +306,7 @@ public: term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); } + term_graph::~term_graph() { reset(); } @@ -251,7 +314,7 @@ term_graph::~term_graph() { static family_id get_family_id(ast_manager &m, app *lit) { family_id fid = null_family_id; - expr *e1, *e2, *e3; + expr *e1 = nullptr, *e2 = nullptr, *e3 = nullptr; // strip negation if (!m.is_not (lit, e1)) { e1 = lit; } @@ -285,14 +348,14 @@ bool term_graph::is_internalized(app *a) { return m_app2term.contains(a->get_id()); } -term* term_graph::get_term(app *a) { +term* term_graph::get_term(expr *a) { term *res; return m_app2term.find (a->get_id(), res) ? res : nullptr; } -term *term_graph::mk_term(app *a) { - term * t = alloc(term, a); - if (a->get_num_args() == 0 && m.is_unique_value(a)){ +term *term_graph::mk_term(expr *a) { + term * t = alloc(term, a, m_app2term); + if (t->get_num_args() == 0 && m.is_unique_value(a)){ t->mark_as_interpreted(); } @@ -301,37 +364,32 @@ term *term_graph::mk_term(app *a) { return t; } -term *term_graph::internalize_term(app *t) { +term *term_graph::internalize_term(expr *t) { term *res = get_term(t); if (!res) { - for (expr * arg : *t) { - SASSERT(is_app(arg)); - internalize_term(::to_app(arg)); + if (is_app(t)) { + for (expr * arg : *::to_app(t)) { + internalize_term(arg); + } } res = mk_term(t); } return res; } -void term_graph::internalize_eq(app *a1, app* a2) { - internalize_lit(a1); - internalize_lit(a2); +void term_graph::internalize_eq(expr *a1, expr* a2) { + internalize_term(a1); + internalize_term(a2); merge(get_term(a1)->get_root(), get_term(a2)->get_root()); } void term_graph::internalize_lit(app* lit) { - if (is_internalized(lit)) return; - - expr *e1, *e2; - if (m.is_eq (lit, e1, e2)) { - SASSERT(is_app(e1)); - SASSERT(is_app(e2)); - internalize_eq (::to_app(e1), ::to_app(e2)); + expr *e1 = nullptr, *e2 = nullptr; + if (m.is_eq (lit, e1, e2)) { + internalize_eq (e1, e2); } else { - // NSB: this is thrown away. - // Is caller responsible for maintaining other predicates than equalities? internalize_term(lit); } } @@ -351,50 +409,61 @@ void term_graph::merge (term &t1, term &t2) { // make 'a' be the root of the equivalence class of 'b' b->set_root(*a); for (term *it = &b->get_next(); it != b; it = &it->get_next()) { + // TBD: remove parents of it from the cg table. it->set_root(*a); } // merge equivalence classes a->merge_eq_class(*b); + // TBD: insert parents of b's old equilvalence class into the cg table + // and propagate equalities. + // -- merge might have invalidated term2map cache + + // NSB: ??? what is ownership model of pinned in m_terms? m_term2app.reset(); - m_pinned.reset(); + m_pinned.reset(); } -app* term_graph::mk_app_core (app *a) { - expr_ref_vector kids(m); - for (expr * arg : *a) { - kids.push_back (mk_app(::to_app(arg))); +expr* term_graph::mk_app_core (expr *e) { + if (is_app(e)) { + expr_ref_vector kids(m); + app* a = ::to_app(e); + for (expr * arg : *a) { + kids.push_back (mk_app(arg)); + } + app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); + m_pinned.push_back(res); + return res; + } + else { + return e; } - - app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); - m_pinned.push_back(res); - - return res; } -app_ref term_graph::mk_app(term const &r) { +expr_ref term_graph::mk_app(term const &r) { SASSERT(r.is_root()); - if (r.get_app()->get_num_args() == 0) { - return app_ref(r.get_app(), m); + if (r.get_num_args() == 0) { + return expr_ref(r.get_app(), m); } - app* res; + expr* res = nullptr; if (m_term2app.find(r.get_id(), res)) { - return app_ref(res, m); + return expr_ref(res, m); } res = mk_app_core (r.get_app()); m_term2app.insert(r.get_id(), res); - return app_ref(res, m); + return expr_ref(res, m); } -app_ref term_graph::mk_app(app *a) { + +expr_ref term_graph::mk_app(expr *a) { term *t = get_term(a); if (!t) - return app_ref(a, m); + return expr_ref(a, m); else return mk_app(t->get_root()); @@ -402,10 +471,10 @@ app_ref term_graph::mk_app(app *a) { void term_graph::mk_equalities(term const &t, app_ref_vector &out) { SASSERT(t.is_root()); - app_ref rep(mk_app(t), m); + expr_ref rep(mk_app(t), m); for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { - app* mem = mk_app_core(it->get_app()); + expr* mem = mk_app_core(it->get_app()); out.push_back (m.mk_eq (rep, mem)); } } @@ -414,10 +483,9 @@ void term_graph::mk_all_equalities(term const &t, app_ref_vector &out) { mk_equalities(t, out); for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { - app* a1 = mk_app_core (it->get_app()); + expr* a1 = mk_app_core (it->get_app()); for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { - app *a2; - a2 = mk_app_core(it2->get_app()); + expr* a2 = mk_app_core(it2->get_app()); out.push_back (m.mk_eq (a1, a2)); } } @@ -436,19 +504,16 @@ bool term_graph::term_le(term const &t1, term const &t2) { // prefer constants over applications // prefer uninterpreted constants over values // prefer smaller expressions over larger ones - app *a1, *a2; - a1 = t1.get_app(); - a2 = t2.get_app(); - if (a1->get_num_args() == 0 && a2->get_num_args() > 0) { + if (t1.get_num_args() == 0 && t2.get_num_args() > 0) { return true; } - // NSB: how does this possibly define an order? - if (a1->get_num_args() == a2->get_num_args()) { - return m.is_value(a2); + if (t1.get_num_args() == t2.get_num_args()) { + // NSB: how does this possibly define an order? + return m.is_value(t2.get_app()); } - unsigned sz1 = get_num_exprs(a1); - unsigned sz2 = get_num_exprs(a2); + unsigned sz1 = get_num_exprs(t1.get_app()); + unsigned sz2 = get_num_exprs(t1.get_app()); return sz1 < sz2; } @@ -481,12 +546,13 @@ void term_graph::display(std::ostream &out) { << "\n"; } } + void term_graph::to_lits (app_ref_vector &lits, bool all_equalities) { pick_roots(); for (app * a : m_lits) { if (is_internalized(a)) { - lits.push_back (mk_app(a)); + lits.push_back (::to_app(mk_app(a))); } } @@ -499,6 +565,7 @@ void term_graph::to_lits (app_ref_vector &lits, bool all_equalities) { mk_equalities(*t, lits); } } + void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { app_ref_vector out(m); to_lits (out, all_equalities); @@ -522,4 +589,18 @@ void term_graph::reset() { m_lits.reset(); } +expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { + obj_hashtable _decls; + for (func_decl* f : decls) _decls.insert(f); + // . propagate representatives up over parents. + // use work-list + marking to propagate. + // . produce equalities over represented classes. + // . produce other literals over represented classes + // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) + + expr_ref_vector result(m); + NOT_IMPLEMENTED_YET(); + return result; +} + } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 76d793e59..0879fb386 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -39,23 +39,22 @@ namespace qe { }; class term_graph { - ast_manager &m; + ast_manager & m; ptr_vector m_terms; - app_ref_vector m_lits; - u_map m_app2term; - - app_ref_vector m_pinned; - u_map m_term2app; + app_ref_vector m_lits; + u_map m_app2term; + app_ref_vector m_pinned; + u_map m_term2app; plugin_manager m_plugins; void merge(term &t1, term &t2); - term *mk_term(app *t); - term *get_term(app *t); + term *mk_term(expr *t); + term *get_term(expr *t); - term *internalize_term(app *t); - void internalize_eq(app *a1, app *a2); + term *internalize_term(expr *t); + void internalize_eq(expr *a1, expr *a2); void internalize_lit(app *lit); bool is_internalized(app *a); @@ -66,27 +65,35 @@ namespace qe { void reset_marks(); - app *mk_app_core(app* a); - app_ref mk_app(term const &t); - app_ref mk_app(app *a); + expr* mk_app_core(expr* a); + expr_ref mk_app(term const &t); + expr_ref mk_app(expr *a); void mk_equalities(term const &t, app_ref_vector &out); void mk_all_equalities(term const &t, app_ref_vector &out); - void display(std::ostream &out); + void display(std::ostream &out); public: term_graph(ast_manager &man); ~term_graph(); - ast_manager &get_ast_manager() const { return m;} + ast_manager& get_ast_manager() const { return m;} void add_lit(app *lit); void add_lits(expr_ref_vector const &lits) { for (expr* e : lits) add_lit(::to_app(e)); } + void add_eq(expr* a, expr* b); void reset(); void to_lits(app_ref_vector &lits, bool all_equalities = false); void to_lits(expr_ref_vector &lits, bool all_equalities = false); app_ref to_app(); + + /** + * Return literals obtained by projecting added literals + * onto the vocabulary of decls (if exclude is false) or outside the + * vocabulary of decls (if exclude is true). + */ + expr_ref_vector project(func_decl_ref_vector const& decls, bool exclude); }; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index b60a9db71..bc5814186 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -627,7 +627,7 @@ namespace smt { */ void context::remove_parents_from_cg_table(enode * r1) { // Remove parents from the congruence table - for (enode * parent : r1->get_parents()) { + for (enode * parent : enode::parents(r1)) { #if 0 { static unsigned num_eqs = 0; @@ -672,7 +672,7 @@ namespace smt { */ void context::reinsert_parents_into_cg_table(enode * r1, enode * r2, enode * n1, enode * n2, eq_justification js) { enode_vector & r2_parents = r2->m_parents; - for (enode * parent : r1->get_parents()) { + for (enode * parent : enode::parents(r1)) { if (!parent->is_marked()) continue; parent->unset_mark(); @@ -1002,7 +1002,7 @@ namespace smt { r2->m_parents.shrink(r2_num_parents); // try to reinsert parents of r1 that are not cgr - for (enode * parent : r1->get_parents()) { + for (enode * parent : enode::parents(r1)) { TRACE("add_eq_parents", tout << "visiting: #" << parent->get_owner_id() << "\n";); if (parent->is_cgc_enabled()) { enode * cg = parent->m_cg; @@ -1197,7 +1197,7 @@ namespace smt { bool context::is_diseq_slow(enode * n1, enode * n2) const { if (n1->get_num_parents() > n2->get_num_parents()) std::swap(n1, n2); - for (enode * parent : n1->get_parents()) { + for (enode * parent : enode::parents(n1)) { if (parent->is_eq() && is_relevant(parent->get_owner()) && get_assignment(enode2bool_var(parent)) == l_false && ((parent->get_arg(0)->get_root() == n1->get_root() && parent->get_arg(1)->get_root() == n2->get_root()) || (parent->get_arg(1)->get_root() == n1->get_root() && parent->get_arg(0)->get_root() == n2->get_root()))) { @@ -1229,7 +1229,7 @@ namespace smt { return false; if (r1->get_num_parents() < SMALL_NUM_PARENTS) { TRACE("is_ext_diseq", tout << mk_bounded_pp(n1->get_owner(), m_manager) << " " << mk_bounded_pp(n2->get_owner(), m_manager) << " " << depth << "\n";); - for (enode* p1 : r1->get_parents()) { + for (enode * p1 : enode::parents(r1)) { if (!is_relevant(p1)) continue; if (p1->is_eq()) @@ -1239,7 +1239,7 @@ namespace smt { func_decl * f = p1->get_decl(); TRACE("is_ext_diseq", tout << "p1: " << mk_bounded_pp(p1->get_owner(), m_manager) << "\n";); unsigned num_args = p1->get_num_args(); - for (enode * p2 : r2->get_parents()) { + for (enode * p2 : enode::parents(r2)) { if (!is_relevant(p2)) continue; if (p2->is_eq()) @@ -1277,7 +1277,7 @@ namespace smt { } almost_cg_table & table = *(m_almost_cg_tables[depth]); table.reset(r1, r2); - for (enode* p1 : r1->get_parents()) { + for (enode * p1 : enode::parents(r1)) { if (!is_relevant(p1)) continue; if (p1->is_eq()) @@ -1288,7 +1288,7 @@ namespace smt { } if (table.empty()) return false; - for (enode * p2 : r2->get_parents()) { + for (enode * p2 : enode::parents(r2)) { if (!is_relevant(p2)) continue; if (p2->is_eq()) @@ -4285,7 +4285,7 @@ namespace smt { theory_var_list * l = n->get_th_var_list(); theory_id th_id = l->get_th_id(); - for (enode* parent : n->get_parents()) { + for (enode * parent : enode::parents(n)) { family_id fid = parent->get_owner()->get_family_id(); if (fid != th_id && fid != m_manager.get_basic_family_id()) { TRACE("is_shared", tout << mk_pp(n->get_owner(), m_manager) << "\nis shared because of:\n" << mk_pp(parent->get_owner(), m_manager) << "\n";); From 362d9258a497596a6534363400da513821b7d822 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 15:24:06 -0700 Subject: [PATCH 1172/1283] prepare term-graph for cc Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 2 +- src/qe/qe_term_graph.cpp | 65 ++++++++++++++++++++++++++++++++++------ src/qe/qe_term_graph.h | 20 ++++++------- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index eea3087e2..c6927f7d2 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -50,7 +50,7 @@ namespace qe { lits.push_back(m.mk_const(c)); } else if (m.is_false(mdl->get_const_interp(c))) { - lits.push_back(m.mk_const(c)); + lits.push_back(m.mk_not(m.mk_const(c))); } } } diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 73412c50b..5ef543868 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -18,6 +18,7 @@ Notes: --*/ #include "util/util.h" +#include "util/uint_set.h" #include "ast/ast_pp.h" #include "ast/ast_util.h" #include "ast/for_each_expr.h" @@ -344,7 +345,7 @@ void term_graph::add_lit(app *l) { internalize_lit(lit); } -bool term_graph::is_internalized(app *a) { +bool term_graph::is_internalized(expr *a) { return m_app2term.contains(a->get_id()); } @@ -365,14 +366,24 @@ term *term_graph::mk_term(expr *a) { } term *term_graph::internalize_term(expr *t) { - term *res = get_term(t); - - if (!res) { + ptr_buffer todo; + todo.push_back(t); + term* res = nullptr; + while (!todo.empty()) { + term* res = get_term(t); + if (res) { + todo.pop_back(); + continue; + } + unsigned sz = todo.size(); if (is_app(t)) { for (expr * arg : *::to_app(t)) { - internalize_term(arg); + if (!get_term(arg)) + todo.push_back(arg); } } + if (sz < todo.size()) continue; + todo.pop_back(); res = mk_term(t); } return res; @@ -384,7 +395,7 @@ void term_graph::internalize_eq(expr *a1, expr* a2) { merge(get_term(a1)->get_root(), get_term(a2)->get_root()); } -void term_graph::internalize_lit(app* lit) { +void term_graph::internalize_lit(expr* lit) { expr *e1 = nullptr, *e2 = nullptr; if (m.is_eq (lit, e1, e2)) { internalize_eq (e1, e2); @@ -590,15 +601,51 @@ void term_graph::reset() { } expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { - obj_hashtable _decls; - for (func_decl* f : decls) _decls.insert(f); + uint_set _decls; + for (func_decl* f : decls) _decls.insert(f->get_id()); // . propagate representatives up over parents. // use work-list + marking to propagate. // . produce equalities over represented classes. // . produce other literals over represented classes // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) - + ptr_vector worklist(m_terms); + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + if (t->get_root().is_marked()) continue; + // if exclude = true, but t in decls, then skip + // if exclude = false, but t not in decls, then skip + if (exclude != _decls.contains(t->get_decl_id())) { + continue; + } + // + // if all children roots are marked + // then mark this as well, reorganize root + // and add parents to worklist + // + bool all_marked = true; + for (term* ch : term::children(t)) { + all_marked &= ch->get_root().is_marked(); + } + if (!all_marked) continue; + + // make this the new root. + term* r = t; + do { + r->set_root(*t); + for (term* p : term::parents(r)) { + worklist.push_back(p); + } + r = &r->get_next(); + } + while (t != r); + t->set_mark(true); + } + // Now, marked roots in m_terms can be used in projection + expr_ref_vector result(m); + + reset_marks(); NOT_IMPLEMENTED_YET(); return result; } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 0879fb386..5319c410a 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -39,11 +39,11 @@ namespace qe { }; class term_graph { - ast_manager & m; - ptr_vector m_terms; - app_ref_vector m_lits; - u_map m_app2term; - app_ref_vector m_pinned; + ast_manager & m; + ptr_vector m_terms; + app_ref_vector m_lits; // NSB: expr_ref_vector? + u_map m_app2term; + ast_ref_vector m_pinned; u_map m_term2app; plugin_manager m_plugins; @@ -55,9 +55,9 @@ namespace qe { term *internalize_term(expr *t); void internalize_eq(expr *a1, expr *a2); - void internalize_lit(app *lit); + void internalize_lit(expr *lit); - bool is_internalized(app *a); + bool is_internalized(expr *a); bool term_le(term const &t1, term const &t2); void pick_root (term &t); @@ -77,16 +77,16 @@ namespace qe { ast_manager& get_ast_manager() const { return m;} - void add_lit(app *lit); + void add_lit(app *lit); // NSB: replace by expr* void add_lits(expr_ref_vector const &lits) { for (expr* e : lits) add_lit(::to_app(e)); } void add_eq(expr* a, expr* b); void reset(); - void to_lits(app_ref_vector &lits, bool all_equalities = false); + void to_lits(app_ref_vector &lits, bool all_equalities = false); // NSB: swap roles void to_lits(expr_ref_vector &lits, bool all_equalities = false); - app_ref to_app(); + app_ref to_app(); /** * Return literals obtained by projecting added literals From da18f0e0b7458f68504b200111b8f09933b7dfe4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 17:59:49 -0700 Subject: [PATCH 1173/1283] prepare term-graph unit testing Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 37 ++++++++++++ src/qe/qe_term_graph.cpp | 76 +++++++++++++++++++++---- src/qe/qe_term_graph.h | 3 +- 3 files changed, 103 insertions(+), 13 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 3a2f6fc85..534e3740b 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -32,6 +32,7 @@ Notes: #include "util/gparams.h" #include "qe/qe_mbp.h" #include "qe/qe_mbi.h" +#include "qe/qe_term_graph.h" BINARY_SYM_CMD(get_quantifier_body_cmd, @@ -440,6 +441,42 @@ public: }; +class euf_project_cmd : public cmd { + unsigned m_arg_index; + ptr_vector m_lits; + ptr_vector m_vars; +public: + euf_project_cmd():cmd("euf-project") {} + char const * get_usage() const override { return "(exprs) (vars)"; } + char const * get_descr(cmd_context & ctx) const override { return "perform congruence projection"; } + unsigned get_arity() const override { return 2; } + cmd_arg_kind next_arg_kind(cmd_context& ctx) const override { + if (m_arg_index == 0) return CPK_EXPR_LIST; + return CPK_FUNC_DECL_LIST; + } + void set_next_arg(cmd_context& ctx, unsigned num, expr * const* args) override { + m_lits.append(num, args); + m_arg_index = 1; + } + void set_next_arg(cmd_context & ctx, unsigned num, func_decl * const * ts) override { + m_vars.append(num, ts); + } + void prepare(cmd_context & ctx) override { m_arg_index = 0; m_lits.reset(); m_vars.reset(); } + void execute(cmd_context & ctx) override { + ast_manager& m = ctx.m(); + func_decl_ref_vector vars(m); + expr_ref_vector lits(m); + for (func_decl* v : m_vars) vars.push_back(v); + for (expr* e : m_lits) lits.push_back(e); + qe::term_graph tg(m); + tg.add_lits(lits); + expr_ref_vector p = tg.project(vars, false); + ctx.regular_stream() << p << "\n"; + } + +}; + + void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(print_dimacs_cmd)); ctx.insert(alloc(get_quantifier_body_cmd)); diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 5ef543868..03d2f082e 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -365,10 +365,12 @@ term *term_graph::mk_term(expr *a) { return t; } -term *term_graph::internalize_term(expr *t) { +term* term_graph::internalize_term(expr *t) { + + term* res = get_term(t); + if (res) return res; ptr_buffer todo; todo.push_back(t); - term* res = nullptr; while (!todo.empty()) { term* res = get_term(t); if (res) { @@ -390,9 +392,7 @@ term *term_graph::internalize_term(expr *t) { } void term_graph::internalize_eq(expr *a1, expr* a2) { - internalize_term(a1); - internalize_term(a2); - merge(get_term(a1)->get_root(), get_term(a2)->get_root()); + merge(internalize_term(a1)->get_root(), internalize_term(a2)->get_root()); } void term_graph::internalize_lit(expr* lit) { @@ -600,9 +600,25 @@ void term_graph::reset() { m_lits.reset(); } +expr_ref term_graph::mk_pure(term& t) { + expr* e = t.get_app(); + if (m_term2app.find(t.get_id(), e)) return expr_ref(e, m); + if (!is_app(e)) return expr_ref(m); + app* a = ::to_app(e); + expr_ref_vector kids(m); + for (term* ch : term::children(t)) { + if (!ch->get_root().is_marked()) return expr_ref(m); + kids.push_back(mk_pure(ch->get_root())); + } + expr_ref result(m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()), m); + m_pinned.push_back(result); + m_term2app.insert(t.get_id(), result); + return result; +} + expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { - uint_set _decls; - for (func_decl* f : decls) _decls.insert(f->get_id()); + u_map _decls; + for (func_decl* f : decls) _decls.insert(f->get_id(), true); // . propagate representatives up over parents. // use work-list + marking to propagate. // . produce equalities over represented classes. @@ -632,7 +648,8 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl // make this the new root. term* r = t; do { - r->set_root(*t); + r->set_root(*t); // TBD: invalidates hash-table, only one-shot + // TBD: optimize worklist traversal? for (term* p : term::parents(r)) { worklist.push_back(p); } @@ -641,12 +658,47 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl while (t != r); t->set_mark(true); } - // Now, marked roots in m_terms can be used in projection - + // marked roots in m_terms can be used in projection + // walk each root. Then traverse each term in the equivalence class + // create pure variant of the terms (if possible) + // equate t0 (that comes from the root, which can be purified) + // with any other t1. expr_ref_vector result(m); - + m_term2app.reset(); + m_pinned.reset(); + for (term * t : m_terms) { + if (!t->is_root() || !t->is_marked() || t->get_class_size() == 1) continue; + term* r = t; + expr_ref t0 = mk_pure(*t); + SASSERT(t0); + obj_hashtable roots; + roots.insert(t0); + for (term* r = &t->get_next(); r != t; r = &r->get_next()) { + // main symbol of term must be consistent with what is included/excluded + if (exclude != _decls.contains(r->get_decl_id())) { + continue; + } + expr_ref t1 = mk_pure(*r); + if (t1 && !roots.contains(t1)) { + result.push_back(m.mk_eq(t0, t1)); + roots.insert(t1); + } + } + } + // walk disequalities and expose projected disequality + for (expr* e : m_lits) { + expr* e1 = nullptr, *e2 = nullptr; + if (m.is_not(e, e) && m.is_eq(e, e1, e2)) { + expr_ref t1 = mk_pure(*get_term(e1)); + expr_ref t2 = mk_pure(*get_term(e2)); + if (t1 && t2) { + result.push_back(m.mk_not(m.mk_eq(t1, t2))); + } + } + } reset_marks(); - NOT_IMPLEMENTED_YET(); + m_term2app.reset(); + m_pinned.reset(); return result; } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 5319c410a..8e8f54c8c 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -67,12 +67,13 @@ namespace qe { expr* mk_app_core(expr* a); expr_ref mk_app(term const &t); + expr_ref mk_pure(term& t); expr_ref mk_app(expr *a); void mk_equalities(term const &t, app_ref_vector &out); void mk_all_equalities(term const &t, app_ref_vector &out); void display(std::ostream &out); public: - term_graph(ast_manager &man); + term_graph(ast_manager &m); ~term_graph(); ast_manager& get_ast_manager() const { return m;} From 008f003aa0e575fefa42ad8dd20f11aecf6b12b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 20:58:41 -0700 Subject: [PATCH 1174/1283] initial working version Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 1 + src/qe/qe_term_graph.cpp | 832 ++++++++++++------------ src/qe/qe_term_graph.h | 9 +- 3 files changed, 438 insertions(+), 404 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 534e3740b..bedbf84aa 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -503,4 +503,5 @@ void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(set_next_id)); ctx.insert(alloc(mbp_cmd)); ctx.insert(alloc(mbi_cmd)); + ctx.insert(alloc(euf_project_cmd)); } diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 03d2f082e..5e8c22919 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -26,83 +26,80 @@ Notes: namespace qe { -class term { - // -- an app represented by this term - expr* m_app; // NSB: to make usable with exprs - // -- root of the equivalence class - term* m_root; - // -- next element in the equivalence class (cyclic linked list) - term* m_next; - // -- eq class size - unsigned m_class_size; - - // -- general purpose mark - unsigned m_mark:1; - // -- general purpose second mark - unsigned m_mark2:1; - // -- is an interpreted constant - unsigned m_interpreted:1; - - // -- terms that contain this term as a child - ptr_vector m_parents; - - // arguments of term. - ptr_vector m_children; - -public: - term(expr* a, u_map& app2term) : - m_app(a), - m_root(this), - m_next(this), - m_class_size(1), - m_mark(false), - m_mark2(false), - m_interpreted(false) { - if (!is_app(a)) return; - for (expr* e : *to_app(a)) { - term* t = app2term[e->get_id()]; - t->m_parents.push_back(this); - m_children.push_back(t); + class term { + // -- an app represented by this term + expr* m_app; // NSB: to make usable with exprs + // -- root of the equivalence class + term* m_root; + // -- next element in the equivalence class (cyclic linked list) + term* m_next; + // -- eq class size + unsigned m_class_size; + + // -- general purpose mark + unsigned m_mark:1; + // -- general purpose second mark + unsigned m_mark2:1; + // -- is an interpreted constant + unsigned m_interpreted:1; + + // -- terms that contain this term as a child + ptr_vector m_parents; + + // arguments of term. + ptr_vector m_children; + + public: + term(expr* a, u_map& app2term) : + m_app(a), + m_root(this), + m_next(this), + m_class_size(1), + m_mark(false), + m_mark2(false), + m_interpreted(false) { + if (!is_app(a)) return; + for (expr* e : *to_app(a)) { + term* t = app2term[e->get_id()]; + t->m_parents.push_back(this); + m_children.push_back(t); + } } - } - - ~term() {} - - class parents { + + ~term() {} + + class parents { + term const& t; + public: + parents(term const& _t):t(_t) {} + parents(term const* _t):t(*_t) {} + ptr_vector::const_iterator begin() const { return t.m_parents.begin(); } + ptr_vector::const_iterator end() const { return t.m_parents.end(); } + }; + + class children { term const& t; - public: - parents(term const& _t):t(_t) {} - parents(term const* _t):t(*_t) {} - ptr_vector::const_iterator begin() const { return t.m_parents.begin(); } - ptr_vector::const_iterator end() const { return t.m_parents.end(); } - }; - - class children { - term const& t; - public: - children(term const& _t):t(_t) {} - children(term const* _t):t(*_t) {} - ptr_vector::const_iterator begin() const { return t.m_children.begin(); } - ptr_vector::const_iterator end() const { return t.m_children.end(); } - }; - - // Congruence table hash function is based on - // roots of children and function declaration. - - struct cg_hash { - unsigned operator()(term const* t) const { + public: + children(term const& _t):t(_t) {} + children(term const* _t):t(*_t) {} + ptr_vector::const_iterator begin() const { return t.m_children.begin(); } + ptr_vector::const_iterator end() const { return t.m_children.end(); } + }; + + // Congruence table hash function is based on + // roots of children and function declaration. + + unsigned get_hash() const { unsigned a, b, c; - a = b = c = t->get_decl_id(); - for (term * ch : children(t)) { + a = b = c = get_decl_id(); + for (term * ch : children(this)) { a = ch->get_root().get_id(); mix(a, b, c); } return c; } - }; - - struct cg_eq { - bool operator()(term * t1, term * t2) const { + + static bool cg_eq(term const * t1, term const * t2) { if (t1->get_decl_id() != t2->get_decl_id()) return false; if (t1->m_children.size() != t2->m_children.size()) return false; for (unsigned i = 0, sz = t1->m_children.size(); i < sz; ++ i) { @@ -110,348 +107,378 @@ public: } return true; } + + unsigned get_id() const { return m_app->get_id();} + + unsigned get_decl_id() const { return is_app(m_app) ? to_app(m_app)->get_decl()->get_id() : m_app->get_id(); } + + bool is_marked() const {return m_mark;} + void set_mark(bool v){m_mark = v;} + bool is_marked2() const {return m_mark2;} // NSB: where is this used? + void set_mark2(bool v){m_mark2 = v;} // NSB: where is this used? + + bool is_interpreted() const {return m_interpreted;} + void mark_as_interpreted() {m_interpreted=true;} + expr* get_app() const {return m_app;} + unsigned get_num_args() const { return is_app(m_app) ? to_app(m_app)->get_num_args() : 0; } + + term &get_root() const {return *m_root;} + bool is_root() const {return m_root == this;} + void set_root(term &r) {m_root = &r;} + term &get_next() const {return *m_next;} + void add_parent(term* p) { m_parents.push_back(p); } + + unsigned get_class_size() const {return m_class_size;} + + void merge_eq_class(term &b) { + std::swap(this->m_next, b.m_next); + m_class_size += b.get_class_size(); + // -- reset (useful for debugging) + b.m_class_size = 0; + } + + // -- make this term the root of its equivalence class + void mk_root() { + if (is_root()) return; + + term *curr = this; + do { + if (curr->is_root()) { + // found previous root + SASSERT(curr != this); + m_class_size = curr->get_class_size(); + curr->m_class_size = 0; + } + curr->set_root(*this); + curr = &curr->get_next(); + } + while (curr != this); + } + }; + + + + class arith_term_graph_plugin : public term_graph_plugin { + term_graph &m_g; + ast_manager &m; + arith_util m_arith; + + public: + arith_term_graph_plugin(term_graph &g) : + term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), + m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} + + virtual ~arith_term_graph_plugin() {} + + bool mk_eq_core (expr *_e1, expr *_e2, app_ref &res) { + expr *e1, *e2; + e1 = _e1; + e2 = _e2; + + if (m_arith.is_zero(e1)) { + std::swap(e1, e2); + } + // y + -1*x == 0 --> y = x + expr *a0 = 0, *a1 = 0, *x = 0; + if (m_arith.is_zero(e2) && m_arith.is_add(e1, a0, a1)) { + if (m_arith.is_times_minus_one(a1, x)) { + e1 = a0; + e2 = x; + } + else if (m_arith.is_times_minus_one(a0, x)) { + e1 = a1; + e2 = x; + } + } + res = m.mk_eq(e1, e2); + return true; + } + + app* mk_le_zero(expr *arg) { + expr *e1, *e2, *e3; + // XXX currently disabled + if (m_arith.is_add(arg, e1, e2)) { + // e1-e2<=0 --> e1<=e2 + if (m_arith.is_times_minus_one(e2, e3)) { + return m_arith.mk_le(e1, e3); + } + // -e1+e2<=0 --> e2<=e1 + else if (m_arith.is_times_minus_one(e1, e3)) { + return m_arith.mk_le(e2, e3); + } + } + return m_arith.mk_le(arg, mk_zero()); + } + + app* mk_ge_zero(expr *arg) { + expr *e1, *e2, *e3; + // XXX currently disabled + if (m_arith.is_add(arg, e1, e2)) { + // e1-e2>=0 --> e1>=e2 + if (m_arith.is_times_minus_one(e2, e3)) { + return m_arith.mk_ge(e1, e3); + } + // -e1+e2>=0 --> e2>=e1 + else if (m_arith.is_times_minus_one(e1, e3)) { + return m_arith.mk_ge(e2, e3); + } + } + return m_arith.mk_ge(arg, mk_zero()); + } + + bool mk_le_core (expr *arg1, expr * arg2, app_ref &result) { + // t <= -1 ==> t < 0 ==> ! (t >= 0) + rational n; + if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { + result = m.mk_not (mk_ge_zero (arg1)); + return true; + } + else if (m_arith.is_zero(arg2)) { + result = mk_le_zero(arg1); + return true; + } + else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n < 0) { + // t <= n ==> t < n + 1 ==> ! (t >= n + 1) + result = m.mk_not(m_arith.mk_ge(arg1, m_arith.mk_numeral(n+1, true))); + return true; + } + return false; + } + + expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} + bool is_one (expr const * n) const { + rational val; + return m_arith.is_numeral (n, val) && val.is_one (); + } + + bool mk_ge_core (expr * arg1, expr * arg2, app_ref &result) { + // t >= 1 ==> t > 0 ==> ! (t <= 0) + rational n; + if (m_arith.is_int (arg1) && is_one (arg2)) { + result = m.mk_not (mk_le_zero (arg1)); + return true; + } + else if (m_arith.is_zero(arg2)) { + result = mk_ge_zero(arg1); + return true; + } + else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n > 0) { + // t >= n ==> t > n - 1 ==> ! (t <= n - 1) + result = m.mk_not(m_arith.mk_le(arg1, m_arith.mk_numeral(n-1, true))); + return true; + } + return false; + } + + virtual app_ref process_lit (app *_lit) { + app *lit = _lit; + expr *e1, *e2; + + // strip negation + bool is_neg = m.is_not(lit); + if (is_neg) { + lit = to_app(to_app(lit)->get_arg(0)); + } + + app_ref res(m); + res = lit; + if (m.is_eq (lit, e1, e2)) { + mk_eq_core(e1, e2, res); + } + else if (m_arith.is_le(lit, e1, e2)) { + mk_le_core(e1, e2, res); + } + else if (m_arith.is_ge(lit, e1, e2)) { + mk_ge_core(e1, e2, res); + } + + // restore negation + if (is_neg) { + res = m.mk_not(res); + } + + return res; + } }; - unsigned get_id() const { return m_app->get_id();} + unsigned term_graph::term_hash::operator()(term const* t) const { return t->get_hash(); } - unsigned get_decl_id() const { return is_app(m_app) ? to_app(m_app)->get_decl()->get_id() : m_app->get_id(); } + bool term_graph::term_eq::operator()(term const* a, term const* b) const { return term::cg_eq(a, b); } - bool is_marked() const {return m_mark;} - void set_mark(bool v){m_mark = v;} - bool is_marked2() const {return m_mark2;} // NSB: where is this used? - void set_mark2(bool v){m_mark2 = v;} // NSB: where is this used? - - bool is_interpreted() const {return m_interpreted;} - void mark_as_interpreted() {m_interpreted=true;} - expr* get_app() const {return m_app;} - unsigned get_num_args() const { return is_app(m_app) ? to_app(m_app)->get_num_args() : 0; } - - term &get_root() const {return *m_root;} - bool is_root() const {return m_root == this;} - void set_root(term &r) {m_root = &r;} - term &get_next() const {return *m_next;} - - unsigned get_class_size() const {return m_class_size;} - - void merge_eq_class(term &b) { - std::swap(this->m_next, b.m_next); - m_class_size += b.get_class_size(); - // -- reset (useful for debugging) - b.m_class_size = 0; + term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { + m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); } - - // -- make this term the root of its equivalence class - void mk_root() { - if (is_root()) return; - - term *curr = this; - do { - if (curr->is_root()) { - // found previous root - SASSERT(curr != this); - m_class_size = curr->get_class_size(); - curr->m_class_size = 0; - } - curr->set_root(*this); - curr = &curr->get_next(); - } - while (curr != this); - } -}; - - - -class arith_term_graph_plugin : public term_graph_plugin { - term_graph &m_g; - ast_manager &m; - arith_util m_arith; - -public: - arith_term_graph_plugin(term_graph &g) : - term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), - m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} - - virtual ~arith_term_graph_plugin() {} - - bool mk_eq_core (expr *_e1, expr *_e2, app_ref &res) { - expr *e1, *e2; - e1 = _e1; - e2 = _e2; - - if (m_arith.is_zero(e1)) { - std::swap(e1, e2); - } - // y + -1*x == 0 --> y = x - expr *a0 = 0, *a1 = 0, *x = 0; - if (m_arith.is_zero(e2) && m_arith.is_add(e1, a0, a1)) { - if (m_arith.is_times_minus_one(a1, x)) { - e1 = a0; - e2 = x; - } - else if (m_arith.is_times_minus_one(a0, x)) { - e1 = a1; - e2 = x; - } - } - res = m.mk_eq(e1, e2); - return true; - } - - app* mk_le_zero(expr *arg) { - expr *e1, *e2, *e3; - // XXX currently disabled - if (m_arith.is_add(arg, e1, e2)) { - // e1-e2<=0 --> e1<=e2 - if (m_arith.is_times_minus_one(e2, e3)) { - return m_arith.mk_le(e1, e3); - } - // -e1+e2<=0 --> e2<=e1 - else if (m_arith.is_times_minus_one(e1, e3)) { - return m_arith.mk_le(e2, e3); - } - } - return m_arith.mk_le(arg, mk_zero()); - } - - app* mk_ge_zero(expr *arg) { - expr *e1, *e2, *e3; - // XXX currently disabled - if (m_arith.is_add(arg, e1, e2)) { - // e1-e2>=0 --> e1>=e2 - if (m_arith.is_times_minus_one(e2, e3)) { - return m_arith.mk_ge(e1, e3); - } - // -e1+e2>=0 --> e2>=e1 - else if (m_arith.is_times_minus_one(e1, e3)) { - return m_arith.mk_ge(e2, e3); - } - } - return m_arith.mk_ge(arg, mk_zero()); - } - - bool mk_le_core (expr *arg1, expr * arg2, app_ref &result) { - // t <= -1 ==> t < 0 ==> ! (t >= 0) - rational n; - if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { - result = m.mk_not (mk_ge_zero (arg1)); - return true; - } - else if (m_arith.is_zero(arg2)) { - result = mk_le_zero(arg1); - return true; - } - else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n < 0) { - // t <= n ==> t < n + 1 ==> ! (t >= n + 1) - result = m.mk_not(m_arith.mk_ge(arg1, m_arith.mk_numeral(n+1, true))); - return true; - } - return false; - } - - expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} - bool is_one (expr const * n) const { - rational val; - return m_arith.is_numeral (n, val) && val.is_one (); - } - - bool mk_ge_core (expr * arg1, expr * arg2, app_ref &result) { - // t >= 1 ==> t > 0 ==> ! (t <= 0) - rational n; - if (m_arith.is_int (arg1) && is_one (arg2)) { - result = m.mk_not (mk_le_zero (arg1)); - return true; - } - else if (m_arith.is_zero(arg2)) { - result = mk_ge_zero(arg1); - return true; - } - else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n > 0) { - // t >= n ==> t > n - 1 ==> ! (t <= n - 1) - result = m.mk_not(m_arith.mk_le(arg1, m_arith.mk_numeral(n-1, true))); - return true; - } - return false; - } - - virtual app_ref process_lit (app *_lit) { - app *lit = _lit; - expr *e1, *e2; - - // strip negation - bool is_neg = m.is_not(lit); - if (is_neg) { - lit = to_app(to_app(lit)->get_arg(0)); - } - - app_ref res(m); - res = lit; - if (m.is_eq (lit, e1, e2)) { - mk_eq_core(e1, e2, res); - } - else if (m_arith.is_le(lit, e1, e2)) { - mk_le_core(e1, e2, res); - } - else if (m_arith.is_ge(lit, e1, e2)) { - mk_ge_core(e1, e2, res); - } - - // restore negation - if (is_neg) { - res = m.mk_not(res); - } - - return res; - } -}; - -term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { - m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); -} - -term_graph::~term_graph() { - reset(); -} - -static family_id get_family_id(ast_manager &m, app *lit) { - family_id fid = null_family_id; - - expr *e1 = nullptr, *e2 = nullptr, *e3 = nullptr; - // strip negation - if (!m.is_not (lit, e1)) { e1 = lit; } - - // deal with equality using sort of range - if (m.is_eq (e1, e2, e3)) { - fid = get_sort (e2)->get_family_id(); - } - // extract family_id of top level app - else { - fid = to_app(e1)->get_decl()->get_family_id(); - } - - return fid; -} - -void term_graph::add_lit(app *l) { - app_ref lit(m); - - family_id fid = get_family_id (m, l); - term_graph_plugin *pin = m_plugins.get_plugin(fid); - if (pin) { - lit = pin->process_lit(l); - } else { - lit = l; - } - m_lits.push_back(lit); - internalize_lit(lit); -} - -bool term_graph::is_internalized(expr *a) { - return m_app2term.contains(a->get_id()); -} - -term* term_graph::get_term(expr *a) { - term *res; - return m_app2term.find (a->get_id(), res) ? res : nullptr; -} - -term *term_graph::mk_term(expr *a) { - term * t = alloc(term, a, m_app2term); - if (t->get_num_args() == 0 && m.is_unique_value(a)){ - t->mark_as_interpreted(); - } - - m_terms.push_back(t); - m_app2term.insert(a->get_id(), t); - return t; -} - -term* term_graph::internalize_term(expr *t) { - term* res = get_term(t); - if (res) return res; - ptr_buffer todo; - todo.push_back(t); - while (!todo.empty()) { + term_graph::~term_graph() { + reset(); + } + + static family_id get_family_id(ast_manager &m, app *lit) { + family_id fid = null_family_id; + + expr *e1 = nullptr, *e2 = nullptr, *e3 = nullptr; + // strip negation + if (!m.is_not (lit, e1)) { e1 = lit; } + + // deal with equality using sort of range + if (m.is_eq (e1, e2, e3)) { + fid = get_sort (e2)->get_family_id(); + } + // extract family_id of top level app + else { + fid = to_app(e1)->get_decl()->get_family_id(); + } + + return fid; + } + + void term_graph::add_lit(app *l) { + app_ref lit(m); + + family_id fid = get_family_id (m, l); + term_graph_plugin *pin = m_plugins.get_plugin(fid); + if (pin) { + lit = pin->process_lit(l); + } else { + lit = l; + } + m_lits.push_back(lit); + internalize_lit(lit); + } + + bool term_graph::is_internalized(expr *a) { + return m_app2term.contains(a->get_id()); + } + + term* term_graph::get_term(expr *a) { + term *res; + return m_app2term.find (a->get_id(), res) ? res : nullptr; + } + + term *term_graph::mk_term(expr *a) { + term * t = alloc(term, a, m_app2term); + if (t->get_num_args() == 0 && m.is_unique_value(a)){ + t->mark_as_interpreted(); + } + + m_terms.push_back(t); + m_app2term.insert(a->get_id(), t); + return t; + } + + term* term_graph::internalize_term(expr *t) { term* res = get_term(t); - if (res) { - todo.pop_back(); - continue; - } - unsigned sz = todo.size(); - if (is_app(t)) { - for (expr * arg : *::to_app(t)) { - if (!get_term(arg)) - todo.push_back(arg); + if (res) return res; + ptr_buffer todo; + todo.push_back(t); + while (!todo.empty()) { + res = get_term(t); + if (res) { + todo.pop_back(); + continue; } + unsigned sz = todo.size(); + if (is_app(t)) { + for (expr * arg : *::to_app(t)) { + if (!get_term(arg)) + todo.push_back(arg); + } + } + if (sz < todo.size()) continue; + todo.pop_back(); + res = mk_term(t); } - if (sz < todo.size()) continue; - todo.pop_back(); - res = mk_term(t); - } - return res; -} - -void term_graph::internalize_eq(expr *a1, expr* a2) { - merge(internalize_term(a1)->get_root(), internalize_term(a2)->get_root()); -} - -void term_graph::internalize_lit(expr* lit) { - expr *e1 = nullptr, *e2 = nullptr; - if (m.is_eq (lit, e1, e2)) { - internalize_eq (e1, e2); - } - else { - internalize_term(lit); - } -} - -void term_graph::merge (term &t1, term &t2) { - SASSERT(t1.is_root()); - SASSERT(t2.is_root()); - - if (&t1 == &t2) return; - - term *a = &t1; - term *b = &t2; - if (a->get_class_size() > b->get_class_size()) { - std::swap(a, b); - } - - // make 'a' be the root of the equivalence class of 'b' - b->set_root(*a); - for (term *it = &b->get_next(); it != b; it = &it->get_next()) { - // TBD: remove parents of it from the cg table. - it->set_root(*a); - } - - // merge equivalence classes - a->merge_eq_class(*b); - - // TBD: insert parents of b's old equilvalence class into the cg table - // and propagate equalities. - - // -- merge might have invalidated term2map cache - - // NSB: ??? what is ownership model of pinned in m_terms? - m_term2app.reset(); - m_pinned.reset(); -} - -expr* term_graph::mk_app_core (expr *e) { - if (is_app(e)) { - expr_ref_vector kids(m); - app* a = ::to_app(e); - for (expr * arg : *a) { - kids.push_back (mk_app(arg)); - } - app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); - m_pinned.push_back(res); + SASSERT(res); return res; } - else { - return e; + + void term_graph::internalize_eq(expr *a1, expr* a2) { + SASSERT(m_merge.empty()); + merge(internalize_term(a1)->get_root(), internalize_term(a2)->get_root()); + merge_flush(); + SASSERT(m_merge.empty()); + } + + void term_graph::internalize_lit(expr* lit) { + expr *e1 = nullptr, *e2 = nullptr; + if (m.is_eq (lit, e1, e2)) { + internalize_eq (e1, e2); + } + else { + internalize_term(lit); + } + } + + void term_graph::merge_flush() { + while (!m_merge.empty()) { + term* t1 = m_merge.back().first; + term* t2 = m_merge.back().second; + m_merge.pop_back(); + merge(*t1, *t2); + } + } + + void term_graph::merge(term &t1, term &t2) { + // -- merge might invalidate term2map cache + m_term2app.reset(); + m_pinned.reset(); + + SASSERT(t1.is_root()); + SASSERT(t2.is_root()); + + if (&t1 == &t2) return; + + term *a = &t1; + term *b = &t2; + if (a->get_class_size() > b->get_class_size()) { + std::swap(a, b); + } + + // Remove parents of it from the cg table. + for (term* p : term::parents(b)) { + if (!p->is_marked()) { + p->set_mark(true); + m_cg_table.erase(p); + } + } + // make 'a' be the root of the equivalence class of 'b' + b->set_root(*a); + for (term *it = &b->get_next(); it != b; it = &it->get_next()) { + it->set_root(*a); + } + + // merge equivalence classes + a->merge_eq_class(*b); + + // Insert parents of b's old equilvalence class into the cg table + for (term* p : term::parents(a)) { + if (p->is_marked()) { + term* p_old = m_cg_table.insert_if_not_there(p); + p->set_mark(false); + a->add_parent(p); + // propagate new equalities. + if (p->get_root().get_id() != p_old->get_root().get_id()) { + m_merge.push_back(std::make_pair(p, p_old)); + } + } + } + } + + expr* term_graph::mk_app_core (expr *e) { + if (is_app(e)) { + expr_ref_vector kids(m); + app* a = ::to_app(e); + for (expr * arg : *a) { + kids.push_back (mk_app(arg)); + } + app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); + m_pinned.push_back(res); + return res; + } + else { + return e; + } } -} expr_ref term_graph::mk_app(term const &r) { SASSERT(r.is_root()); @@ -598,6 +625,7 @@ void term_graph::reset() { std::for_each(m_terms.begin(), m_terms.end(), delete_proc()); m_terms.reset(); m_lits.reset(); + m_cg_table.reset(); } expr_ref term_graph::mk_pure(term& t) { @@ -631,7 +659,7 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl if (t->get_root().is_marked()) continue; // if exclude = true, but t in decls, then skip // if exclude = false, but t not in decls, then skip - if (exclude != _decls.contains(t->get_decl_id())) { + if (exclude == _decls.contains(t->get_decl_id())) { continue; } // @@ -662,7 +690,7 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl // walk each root. Then traverse each term in the equivalence class // create pure variant of the terms (if possible) // equate t0 (that comes from the root, which can be purified) - // with any other t1. + // with any other purifiable t1. expr_ref_vector result(m); m_term2app.reset(); m_pinned.reset(); @@ -675,7 +703,7 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl roots.insert(t0); for (term* r = &t->get_next(); r != t; r = &r->get_next()) { // main symbol of term must be consistent with what is included/excluded - if (exclude != _decls.contains(r->get_decl_id())) { + if (exclude == _decls.contains(r->get_decl_id())) { continue; } expr_ref t1 = mk_pure(*r); diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 8e8f54c8c..c3f1e21aa 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -37,18 +37,23 @@ namespace qe { /// Process (and potentially augment) a literal virtual app_ref process_lit (app *lit) = 0; }; - + + class term_graph { + struct term_hash { unsigned operator()(term const* t) const; }; + struct term_eq { bool operator()(term const* a, term const* b) const; }; ast_manager & m; ptr_vector m_terms; app_ref_vector m_lits; // NSB: expr_ref_vector? u_map m_app2term; ast_ref_vector m_pinned; u_map m_term2app; - plugin_manager m_plugins; + ptr_hashtable m_cg_table; + vector> m_merge; void merge(term &t1, term &t2); + void merge_flush(); term *mk_term(expr *t); term *get_term(expr *t); From 1f634efe0447e23a3d52997052951fcddf495da6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 21:11:55 -0700 Subject: [PATCH 1175/1283] initial working version Signed-off-by: Nikolaj Bjorner --- src/qe/qe_term_graph.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 5e8c22919..7244f4e22 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -372,6 +372,7 @@ namespace qe { ptr_buffer todo; todo.push_back(t); while (!todo.empty()) { + t = todo.back(); res = get_term(t); if (res) { todo.pop_back(); From c4188fc4be9b542339ca430b05f4d6c28bdf6073 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 9 Jun 2018 21:27:30 -0700 Subject: [PATCH 1176/1283] initial working version Signed-off-by: Nikolaj Bjorner --- src/qe/qe_term_graph.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 7244f4e22..e7d13824c 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -118,6 +118,7 @@ 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(m_app) || to_app(m_app)->get_family_id() != null_family_id; } void mark_as_interpreted() {m_interpreted=true;} expr* get_app() const {return m_app;} unsigned get_num_args() const { return is_app(m_app) ? to_app(m_app)->get_num_args() : 0; } @@ -660,7 +661,8 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl if (t->get_root().is_marked()) continue; // if exclude = true, but t in decls, then skip // if exclude = false, but t not in decls, then skip - if (exclude == _decls.contains(t->get_decl_id())) { + + if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) { continue; } // @@ -704,7 +706,7 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl roots.insert(t0); for (term* r = &t->get_next(); r != t; r = &r->get_next()) { // main symbol of term must be consistent with what is included/excluded - if (exclude == _decls.contains(r->get_decl_id())) { + if (!r->is_theory() && exclude == _decls.contains(r->get_decl_id())) { continue; } expr_ref t1 = mk_pure(*r); @@ -716,12 +718,10 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl } // walk disequalities and expose projected disequality for (expr* e : m_lits) { - expr* e1 = nullptr, *e2 = nullptr; - if (m.is_not(e, e) && m.is_eq(e, e1, e2)) { - expr_ref t1 = mk_pure(*get_term(e1)); - expr_ref t2 = mk_pure(*get_term(e2)); - if (t1 && t2) { - result.push_back(m.mk_not(m.mk_eq(t1, t2))); + if (!m.is_eq(e)) { + expr_ref t = mk_pure(*get_term(e)); + if (t) { + result.push_back(t); } } } From a6848c79b7600525be23ac03dffb581bb82e6022 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Jun 2018 05:41:15 -0700 Subject: [PATCH 1177/1283] redo representative generator to respect stratification Signed-off-by: Nikolaj Bjorner --- src/qe/qe_term_graph.cpp | 125 +++++++++++++++++++-------------------- src/qe/qe_term_graph.h | 2 +- 2 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index e7d13824c..d8670089a 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -630,17 +630,17 @@ void term_graph::reset() { m_cg_table.reset(); } -expr_ref term_graph::mk_pure(term& t) { +expr* term_graph::mk_pure(term& t) { expr* e = t.get_app(); - if (m_term2app.find(t.get_id(), e)) return expr_ref(e, m); - if (!is_app(e)) return expr_ref(m); + if (m_term2app.find(t.get_id(), e)) e; + if (!is_app(e)) return nullptr; app* a = ::to_app(e); expr_ref_vector kids(m); for (term* ch : term::children(t)) { - if (!ch->get_root().is_marked()) return expr_ref(m); - kids.push_back(mk_pure(ch->get_root())); + if (!m_term2app.find(ch->get_root().get_id(), e)) return nullptr; + kids.push_back(e); } - expr_ref result(m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()), m); + expr* result = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); m_pinned.push_back(result); m_term2app.insert(t.get_id(), result); return result; @@ -654,78 +654,75 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl // . produce equalities over represented classes. // . produce other literals over represented classes // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) - ptr_vector worklist(m_terms); - while (!worklist.empty()) { - term* t = worklist.back(); - worklist.pop_back(); - if (t->get_root().is_marked()) continue; - // if exclude = true, but t in decls, then skip - // if exclude = false, but t not in decls, then skip - if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) { - continue; - } - // - // if all children roots are marked - // then mark this as well, reorganize root - // and add parents to worklist - // - bool all_marked = true; - for (term* ch : term::children(t)) { - all_marked &= ch->get_root().is_marked(); - } - if (!all_marked) continue; - - // make this the new root. - term* r = t; - do { - r->set_root(*t); // TBD: invalidates hash-table, only one-shot - // TBD: optimize worklist traversal? - for (term* p : term::parents(r)) { - worklist.push_back(p); - } - r = &r->get_next(); - } - while (t != r); - t->set_mark(true); - } - // marked roots in m_terms can be used in projection - // walk each root. Then traverse each term in the equivalence class - // create pure variant of the terms (if possible) - // equate t0 (that comes from the root, which can be purified) - // with any other purifiable t1. expr_ref_vector result(m); m_term2app.reset(); m_pinned.reset(); - for (term * t : m_terms) { - if (!t->is_root() || !t->is_marked() || t->get_class_size() == 1) continue; + + ptr_vector worklist(m_terms); + obj_hashtable roots; + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + if (!t->is_root() || m_term2app.contains(t->get_id())) continue; term* r = t; - expr_ref t0 = mk_pure(*t); - SASSERT(t0); - obj_hashtable roots; - roots.insert(t0); - for (term* r = &t->get_next(); r != t; r = &r->get_next()) { - // main symbol of term must be consistent with what is included/excluded + roots.reset(); + expr_ref rep(m), other(m); + // walk the equivalence class of t to produce + // a representative. + do { + // if exclude = true, but t in decls, then skip + // if exclude = false, but t not in decls, then skip if (!r->is_theory() && exclude == _decls.contains(r->get_decl_id())) { + r = &r->get_next(); continue; } - expr_ref t1 = mk_pure(*r); - if (t1 && !roots.contains(t1)) { - result.push_back(m.mk_eq(t0, t1)); - roots.insert(t1); + other = mk_pure(*r); + if (other) { + if (!rep) { + rep = other; + roots.insert(other); + } + else if (!roots.contains(other)) { + roots.insert(other); + result.push_back(m.mk_eq(rep, other)); + // give preference to non-values as roots. + if (m.is_unique_value(rep)) { + std::swap(other, rep); + } + } } + r = &r->get_next(); + } + while (r != t); + + if (rep) { + // update the representative of t to the preferred one. + // used by mk_pure to determine representative of child. + m_term2app.insert(t->get_id(), rep); + // TBD: add_parent in merge ensures that + // congruence closure root t contains all parents. + // TBD: could tune this by using marking to only add roots to worklist if not already there. + r = t; + do { + for (term * p : term::parents(r)) { + worklist.push_back(p); + } + r = &r->get_next(); + } + while (r != t); } } - // walk disequalities and expose projected disequality + // walk other predicates than equalities for (expr* e : m_lits) { - if (!m.is_eq(e)) { - expr_ref t = mk_pure(*get_term(e)); - if (t) { - result.push_back(t); - } + if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { + result.push_back(e); } } - reset_marks(); + // Here we could also walk equivalence classes that contain interpreted values by sort and + // extract disequalities bewteen non-unique value representatives. + // these disequalities are implied and can be mined using other means, such as + // theory aware core minimization m_term2app.reset(); m_pinned.reset(); return result; diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index c3f1e21aa..4f0430812 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -72,7 +72,7 @@ namespace qe { expr* mk_app_core(expr* a); expr_ref mk_app(term const &t); - expr_ref mk_pure(term& t); + expr* mk_pure(term& t); expr_ref mk_app(expr *a); void mk_equalities(term const &t, app_ref_vector &out); void mk_all_equalities(term const &t, app_ref_vector &out); From ad153592a2f298c62b3eabfffdfd6890e52dac97 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Jun 2018 06:07:05 -0700 Subject: [PATCH 1178/1283] fix parent list Signed-off-by: Nikolaj Bjorner --- src/qe/qe_term_graph.cpp | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index d8670089a..95a024de6 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -61,7 +61,7 @@ namespace qe { if (!is_app(a)) return; for (expr* e : *to_app(a)) { term* t = app2term[e->get_id()]; - t->m_parents.push_back(this); + t->get_root().m_parents.push_back(this); m_children.push_back(t); } } @@ -659,12 +659,20 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl m_term2app.reset(); m_pinned.reset(); - ptr_vector worklist(m_terms); obj_hashtable roots; + ptr_vector worklist; + for (term * t : m_terms) { + if (t->is_root()) { + worklist.push_back(t); + t->set_mark(true); + } + } while (!worklist.empty()) { term* t = worklist.back(); worklist.pop_back(); - if (!t->is_root() || m_term2app.contains(t->get_id())) continue; + SASSERT(t->is_root()); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) continue; term* r = t; roots.reset(); expr_ref rep(m), other(m); @@ -700,17 +708,29 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl // update the representative of t to the preferred one. // used by mk_pure to determine representative of child. m_term2app.insert(t->get_id(), rep); - // TBD: add_parent in merge ensures that - // congruence closure root t contains all parents. - // TBD: could tune this by using marking to only add roots to worklist if not already there. +#if 1 + // The root should contain all parents relative to the equivalence class. + // To ensure this, merge uses add_parent on the chosen root with respect to the old root. + // To enable adding terms after merge the constructor for terms also has to ensure + // that new terms are added as parents of the roots of their children. + + for (term * p : term::parents(t)) { + p = &p->get_root(); + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); + } + } +#else r = t; do { for (term * p : term::parents(r)) { - worklist.push_back(p); + worklist.push_back(&p->get_root()); } r = &r->get_next(); } - while (r != t); + while (r != t); +#endif } } // walk other predicates than equalities @@ -725,6 +745,7 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl // theory aware core minimization m_term2app.reset(); m_pinned.reset(); + reset_marks(); return result; } From 0d71d850691d48fdca84203e89d7bc495476bb20 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Jun 2018 10:59:09 -0700 Subject: [PATCH 1179/1283] redo representative algorithm Signed-off-by: Nikolaj Bjorner --- src/qe/qe_term_graph.cpp | 108 ++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 95a024de6..fa91eced6 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -373,7 +373,7 @@ namespace qe { ptr_buffer todo; todo.push_back(t); while (!todo.empty()) { - t = todo.back(); + t = todo.back(); res = get_term(t); if (res) { todo.pop_back(); @@ -659,78 +659,70 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl m_term2app.reset(); m_pinned.reset(); - obj_hashtable roots; + obj_hashtable eqs; + expr_ref eq(m); ptr_vector worklist; for (term * t : m_terms) { - if (t->is_root()) { - worklist.push_back(t); - t->set_mark(true); - } + worklist.push_back(t); + t->set_mark(true); } + while (!worklist.empty()) { term* t = worklist.back(); worklist.pop_back(); - SASSERT(t->is_root()); t->set_mark(false); - if (m_term2app.contains(t->get_id())) continue; - term* r = t; - roots.reset(); - expr_ref rep(m), other(m); - // walk the equivalence class of t to produce - // a representative. - do { - // if exclude = true, but t in decls, then skip - // if exclude = false, but t not in decls, then skip - if (!r->is_theory() && exclude == _decls.contains(r->get_decl_id())) { - r = &r->get_next(); - continue; - } - other = mk_pure(*r); - if (other) { - if (!rep) { - rep = other; - roots.insert(other); - } - else if (!roots.contains(other)) { - roots.insert(other); - result.push_back(m.mk_eq(rep, other)); - // give preference to non-values as roots. - if (m.is_unique_value(rep)) { - std::swap(other, rep); - } - } - } - r = &r->get_next(); + if (m_term2app.contains(t->get_id())) + continue; + if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) + continue; + + term& root = t->get_root(); + bool has_rep = m_term2app.contains(root.get_id()); + expr* pure = mk_pure(*t); + if (!pure) continue; + + // ensure that the root has a representative + // either by looking up cached version, + // computing it for the first time, or + // inheriting pure. + expr* rep = nullptr; + if (root.is_theory() || exclude != _decls.contains(root.get_decl_id())) { + rep = mk_pure(root); } - while (r != t); + else if (has_rep) { + rep = m_term2app.find(root.get_id()); + } + else { + rep = pure; + m_term2app.insert(root.get_id(), pure); + } + bool update_rep = false; - if (rep) { - // update the representative of t to the preferred one. - // used by mk_pure to determine representative of child. - m_term2app.insert(t->get_id(), rep); -#if 1 - // The root should contain all parents relative to the equivalence class. - // To ensure this, merge uses add_parent on the chosen root with respect to the old root. - // To enable adding terms after merge the constructor for terms also has to ensure - // that new terms are added as parents of the roots of their children. + // Add equations between pure and rep, + // optionally swap the roles of rep and pure if + // pure makes a better representative. + if (rep != pure) { + if (m.is_unique_value(rep) && !m.is_unique_value(pure)) { + m_term2app.insert(root.get_id(), pure); + update_rep = true; + } + eq = m.mk_eq(rep, pure); + if (!eqs.contains(eq)) { + eqs.insert(eq); + result.push_back(eq); + } + } - for (term * p : term::parents(t)) { - p = &p->get_root(); + // update the worklist if this is the first + // representative or pure was swapped into rep. + if (!has_rep || update_rep) { + for (term * p : term::parents(root)) { + if (update_rep) m_term2app.remove(p->get_id()); if (!p->is_marked()) { p->set_mark(true); worklist.push_back(p); } } -#else - r = t; - do { - for (term * p : term::parents(r)) { - worklist.push_back(&p->get_root()); - } - r = &r->get_next(); - } - while (r != t); -#endif } } // walk other predicates than equalities From 9a0406d181f010b6026071f001b0dab2442b2f91 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Jun 2018 11:28:38 -0700 Subject: [PATCH 1180/1283] replace app by expr Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_quant_generalizer.cpp | 1 - src/qe/qe_term_graph.cpp | 521 ++++++++++---------- src/qe/qe_term_graph.h | 22 +- 3 files changed, 268 insertions(+), 276 deletions(-) diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index f3425817b..fb2964c40 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -27,7 +27,6 @@ Revision History: #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" #include "ast/factor_equivs.h" -#include "qe/qe_term_graph.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/substitution/matcher.h" #include "ast/expr_functors.h" diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index fa91eced6..e723542a2 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -171,7 +171,7 @@ namespace qe { virtual ~arith_term_graph_plugin() {} - bool mk_eq_core (expr *_e1, expr *_e2, app_ref &res) { + bool mk_eq_core (expr *_e1, expr *_e2, expr_ref &res) { expr *e1, *e2; e1 = _e1; e2 = _e2; @@ -227,7 +227,7 @@ namespace qe { return m_arith.mk_ge(arg, mk_zero()); } - bool mk_le_core (expr *arg1, expr * arg2, app_ref &result) { + bool mk_le_core (expr *arg1, expr * arg2, expr_ref &result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) rational n; if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { @@ -252,7 +252,7 @@ namespace qe { return m_arith.is_numeral (n, val) && val.is_one (); } - bool mk_ge_core (expr * arg1, expr * arg2, app_ref &result) { + bool mk_ge_core (expr * arg1, expr * arg2, expr_ref &result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) rational n; if (m_arith.is_int (arg1) && is_one (arg2)) { @@ -271,8 +271,8 @@ namespace qe { return false; } - virtual app_ref process_lit (app *_lit) { - app *lit = _lit; + expr_ref process_lit (expr *_lit) override { + expr *lit = _lit; expr *e1, *e2; // strip negation @@ -281,7 +281,7 @@ namespace qe { lit = to_app(to_app(lit)->get_arg(0)); } - app_ref res(m); + expr_ref res(m); res = lit; if (m.is_eq (lit, e1, e2)) { mk_eq_core(e1, e2, res); @@ -295,10 +295,10 @@ namespace qe { // restore negation if (is_neg) { - res = m.mk_not(res); + res = mk_not(m, res); } - return res; + return res; } }; @@ -314,27 +314,26 @@ namespace qe { reset(); } - static family_id get_family_id(ast_manager &m, app *lit) { - family_id fid = null_family_id; - - expr *e1 = nullptr, *e2 = nullptr, *e3 = nullptr; - // strip negation - if (!m.is_not (lit, e1)) { e1 = lit; } - + static family_id get_family_id(ast_manager &m, expr *lit) { + if (m.is_not(lit, lit)) + return get_family_id(m, lit); + + expr *a = nullptr, *b = nullptr; // deal with equality using sort of range - if (m.is_eq (e1, e2, e3)) { - fid = get_sort (e2)->get_family_id(); + if (m.is_eq (lit, a, b)) { + return get_sort (a)->get_family_id(); } // extract family_id of top level app - else { - fid = to_app(e1)->get_decl()->get_family_id(); + else if (is_app(lit)) { + return to_app(lit)->get_decl()->get_family_id(); + } + else { + return null_family_id; } - - return fid; } - void term_graph::add_lit(app *l) { - app_ref lit(m); + void term_graph::add_lit(expr *l) { + expr_ref lit(m); family_id fid = get_family_id (m, l); term_graph_plugin *pin = m_plugins.get_plugin(fid); @@ -482,263 +481,257 @@ namespace qe { } } -expr_ref term_graph::mk_app(term const &r) { - SASSERT(r.is_root()); - - if (r.get_num_args() == 0) { - return expr_ref(r.get_app(), m); - } - - expr* res = nullptr; - if (m_term2app.find(r.get_id(), res)) { + expr_ref term_graph::mk_app(term const &r) { + SASSERT(r.is_root()); + + if (r.get_num_args() == 0) { + return expr_ref(r.get_app(), m); + } + + expr* res = nullptr; + if (m_term2app.find(r.get_id(), res)) { + return expr_ref(res, m); + } + + res = mk_app_core (r.get_app()); + m_term2app.insert(r.get_id(), res); return expr_ref(res, m); + } - res = mk_app_core (r.get_app()); - m_term2app.insert(r.get_id(), res); - return expr_ref(res, m); - -} - -expr_ref term_graph::mk_app(expr *a) { - term *t = get_term(a); - if (!t) - return expr_ref(a, m); - else - return mk_app(t->get_root()); - -} - -void term_graph::mk_equalities(term const &t, app_ref_vector &out) { - 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()); - out.push_back (m.mk_eq (rep, mem)); - } -} - -void term_graph::mk_all_equalities(term const &t, app_ref_vector &out) { - mk_equalities(t, out); - - for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { - expr* a1 = mk_app_core (it->get_app()); - for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { - expr* a2 = mk_app_core(it2->get_app()); - out.push_back (m.mk_eq (a1, a2)); - } - } -} - -void term_graph::reset_marks() { - for (term * t : m_terms) { - t->set_mark(false); - } -} - -/// Order of preference for roots of equivalence classes -/// XXX This should be factored out to let clients control the preference -bool term_graph::term_le(term const &t1, term const &t2) { - - // prefer constants over applications - // prefer uninterpreted constants over values - // prefer smaller expressions over larger ones - if (t1.get_num_args() == 0 && t2.get_num_args() > 0) { - return true; - } - if (t1.get_num_args() == t2.get_num_args()) { - // NSB: how does this possibly define an order? - return m.is_value(t2.get_app()); - } - - unsigned sz1 = get_num_exprs(t1.get_app()); - unsigned sz2 = get_num_exprs(t1.get_app()); - return sz1 < sz2; -} - -void term_graph::pick_root (term &t) { - term *r = &t; - for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { - it->set_mark(true); - if (term_le(*it, *r)) { r = it; } - } - - // -- if found something better, make it the new root - if (r != &t) { - r->mk_root(); - } -} -/// Choose better roots for equivalence classes -void term_graph::pick_roots() { - for (term* t : m_terms) { - if (!t->is_marked() && t->is_root()) - pick_root(*t); - } - reset_marks(); -} - -void term_graph::display(std::ostream &out) { - for (term * t : m_terms) { - out << mk_pp(t->get_app(), m) << " is root " << t->is_root() - << " cls sz " << t->get_class_size() - << " term " << t - << "\n"; - } -} - -void term_graph::to_lits (app_ref_vector &lits, bool all_equalities) { - pick_roots(); - - for (app * a : m_lits) { - if (is_internalized(a)) { - lits.push_back (::to_app(mk_app(a))); - } - } - - for (term * t : m_terms) { - if (!t->is_root()) - continue; - else if (all_equalities) - mk_all_equalities (*t, lits); + expr_ref term_graph::mk_app(expr *a) { + term *t = get_term(a); + if (!t) + return expr_ref(a, m); else - mk_equalities(*t, lits); - } -} - -void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { - app_ref_vector out(m); - to_lits (out, all_equalities); - for (app* a : out) { - lits.push_back(a); - } -} - -app_ref term_graph::to_app() { - app_ref_vector lits(m); - to_lits(lits); - return mk_and(lits); -} - -void term_graph::reset() { - m_term2app.reset(); - m_pinned.reset(); - m_app2term.reset(); - std::for_each(m_terms.begin(), m_terms.end(), delete_proc()); - m_terms.reset(); - m_lits.reset(); - m_cg_table.reset(); -} - -expr* term_graph::mk_pure(term& t) { - expr* e = t.get_app(); - if (m_term2app.find(t.get_id(), e)) e; - if (!is_app(e)) return nullptr; - app* a = ::to_app(e); - expr_ref_vector kids(m); - for (term* ch : term::children(t)) { - if (!m_term2app.find(ch->get_root().get_id(), e)) return nullptr; - kids.push_back(e); - } - expr* result = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); - m_pinned.push_back(result); - m_term2app.insert(t.get_id(), result); - return result; -} - -expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { - u_map _decls; - for (func_decl* f : decls) _decls.insert(f->get_id(), true); - // . propagate representatives up over parents. - // use work-list + marking to propagate. - // . produce equalities over represented classes. - // . produce other literals over represented classes - // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) - - expr_ref_vector result(m); - m_term2app.reset(); - m_pinned.reset(); - - obj_hashtable eqs; - expr_ref eq(m); - ptr_vector worklist; - for (term * t : m_terms) { - worklist.push_back(t); - t->set_mark(true); + return mk_app(t->get_root()); + } - while (!worklist.empty()) { - term* t = worklist.back(); - worklist.pop_back(); - t->set_mark(false); - if (m_term2app.contains(t->get_id())) - continue; - if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) - continue; - - term& root = t->get_root(); - bool has_rep = m_term2app.contains(root.get_id()); - expr* pure = mk_pure(*t); - if (!pure) continue; - - // ensure that the root has a representative - // either by looking up cached version, - // computing it for the first time, or - // inheriting pure. - expr* rep = nullptr; - if (root.is_theory() || exclude != _decls.contains(root.get_decl_id())) { - rep = mk_pure(root); + void term_graph::mk_equalities(term const &t, expr_ref_vector &out) { + 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()); + out.push_back (m.mk_eq (rep, mem)); } - else if (has_rep) { - rep = m_term2app.find(root.get_id()); + } + + void term_graph::mk_all_equalities(term const &t, expr_ref_vector &out) { + mk_equalities(t, out); + + for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { + expr* a1 = mk_app_core (it->get_app()); + for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { + expr* a2 = mk_app_core(it2->get_app()); + out.push_back (m.mk_eq (a1, a2)); + } } - else { - rep = pure; - m_term2app.insert(root.get_id(), pure); + } + + void term_graph::reset_marks() { + for (term * t : m_terms) { + t->set_mark(false); } - bool update_rep = false; + } + + /// Order of preference for roots of equivalence classes + /// XXX This should be factored out to let clients control the preference + bool term_graph::term_le(term const &t1, term const &t2) { + + // prefer constants over applications + // prefer uninterpreted constants over values + // prefer smaller expressions over larger ones + if (t1.get_num_args() == 0 && t2.get_num_args() > 0) { + return true; + } + if (t1.get_num_args() == t2.get_num_args()) { + // NSB: how does this possibly define an order? + return m.is_value(t2.get_app()); + } + + unsigned sz1 = get_num_exprs(t1.get_app()); + unsigned sz2 = get_num_exprs(t1.get_app()); + return sz1 < sz2; + } - // Add equations between pure and rep, - // optionally swap the roles of rep and pure if - // pure makes a better representative. - if (rep != pure) { - if (m.is_unique_value(rep) && !m.is_unique_value(pure)) { + void term_graph::pick_root (term &t) { + term *r = &t; + for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { + it->set_mark(true); + if (term_le(*it, *r)) { r = it; } + } + + // -- if found something better, make it the new root + if (r != &t) { + r->mk_root(); + } + } + + /// Choose better roots for equivalence classes + void term_graph::pick_roots() { + for (term* t : m_terms) { + if (!t->is_marked() && t->is_root()) + pick_root(*t); + } + reset_marks(); + } + + void term_graph::display(std::ostream &out) { + for (term * t : m_terms) { + out << mk_pp(t->get_app(), m) << " is root " << t->is_root() + << " cls sz " << t->get_class_size() + << " term " << t + << "\n"; + } + } + + void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { + pick_roots(); + + for (expr * a : m_lits) { + if (is_internalized(a)) { + lits.push_back (::to_app(mk_app(a))); + } + } + + for (term * t : m_terms) { + if (!t->is_root()) + continue; + else if (all_equalities) + mk_all_equalities (*t, lits); + else + mk_equalities(*t, lits); + } + } + + + expr_ref term_graph::to_app() { + expr_ref_vector lits(m); + to_lits(lits); + return mk_and(lits); + } + + void term_graph::reset() { + m_term2app.reset(); + m_pinned.reset(); + m_app2term.reset(); + std::for_each(m_terms.begin(), m_terms.end(), delete_proc()); + m_terms.reset(); + m_lits.reset(); + m_cg_table.reset(); + } + + expr* term_graph::mk_pure(term& t) { + expr* e = t.get_app(); + if (m_term2app.find(t.get_id(), e)) e; + if (!is_app(e)) return nullptr; + app* a = ::to_app(e); + expr_ref_vector kids(m); + for (term* ch : term::children(t)) { + if (!m_term2app.find(ch->get_root().get_id(), e)) return nullptr; + kids.push_back(e); + } + expr* result = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); + m_pinned.push_back(result); + m_term2app.insert(t.get_id(), result); + return result; + } + + expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { + u_map _decls; + for (func_decl* f : decls) _decls.insert(f->get_id(), true); + // . propagate representatives up over parents. + // use work-list + marking to propagate. + // . produce equalities over represented classes. + // . produce other literals over represented classes + // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) + + expr_ref_vector result(m); + m_term2app.reset(); + m_pinned.reset(); + + obj_hashtable eqs; + expr_ref eq(m); + ptr_vector worklist; + for (term * t : m_terms) { + worklist.push_back(t); + t->set_mark(true); + } + + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) + continue; + if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) + continue; + + term& root = t->get_root(); + bool has_rep = m_term2app.contains(root.get_id()); + expr* pure = mk_pure(*t); + if (!pure) continue; + + // ensure that the root has a representative + // either by looking up cached version, + // computing it for the first time, or + // inheriting pure. + expr* rep = nullptr; + if (root.is_theory() || exclude != _decls.contains(root.get_decl_id())) { + rep = mk_pure(root); + } + else if (has_rep) { + rep = m_term2app.find(root.get_id()); + } + else { + rep = pure; m_term2app.insert(root.get_id(), pure); - update_rep = true; } - eq = m.mk_eq(rep, pure); - if (!eqs.contains(eq)) { - eqs.insert(eq); - result.push_back(eq); - } - } + bool update_rep = false; - // update the worklist if this is the first - // representative or pure was swapped into rep. - if (!has_rep || update_rep) { - for (term * p : term::parents(root)) { - if (update_rep) m_term2app.remove(p->get_id()); - if (!p->is_marked()) { - p->set_mark(true); - worklist.push_back(p); + // Add equations between pure and rep, + // optionally swap the roles of rep and pure if + // pure makes a better representative. + if (rep != pure) { + if (m.is_unique_value(rep) && !m.is_unique_value(pure)) { + m_term2app.insert(root.get_id(), pure); + update_rep = true; + } + eq = m.mk_eq(rep, pure); + if (!eqs.contains(eq)) { + eqs.insert(eq); + result.push_back(eq); + } + } + + // update the worklist if this is the first + // representative or pure was swapped into rep. + if (!has_rep || update_rep) { + for (term * p : term::parents(root)) { + if (update_rep) m_term2app.remove(p->get_id()); + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); + } } } } + // walk other predicates than equalities + for (expr* e : m_lits) { + if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { + result.push_back(e); + } + } + // Here we could also walk equivalence classes that contain interpreted values by sort and + // extract disequalities bewteen non-unique value representatives. + // these disequalities are implied and can be mined using other means, such as + // theory aware core minimization + m_term2app.reset(); + m_pinned.reset(); + reset_marks(); + return result; } - // walk other predicates than equalities - for (expr* e : m_lits) { - if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { - result.push_back(e); - } - } - // Here we could also walk equivalence classes that contain interpreted values by sort and - // extract disequalities bewteen non-unique value representatives. - // these disequalities are implied and can be mined using other means, such as - // theory aware core minimization - m_term2app.reset(); - m_pinned.reset(); - reset_marks(); - return result; -} } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 4f0430812..4c2c2c6ff 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -35,7 +35,7 @@ namespace qe { family_id get_family_id() const {return m_id;} /// Process (and potentially augment) a literal - virtual app_ref process_lit (app *lit) = 0; + virtual expr_ref process_lit (expr *lit) = 0; }; @@ -44,7 +44,7 @@ namespace qe { struct term_eq { bool operator()(term const* a, term const* b) const; }; ast_manager & m; ptr_vector m_terms; - app_ref_vector m_lits; // NSB: expr_ref_vector? + expr_ref_vector m_lits; // NSB: expr_ref_vector? u_map m_app2term; ast_ref_vector m_pinned; u_map m_term2app; @@ -74,25 +74,25 @@ namespace qe { expr_ref mk_app(term const &t); expr* mk_pure(term& t); expr_ref mk_app(expr *a); - void mk_equalities(term const &t, app_ref_vector &out); - void mk_all_equalities(term const &t, app_ref_vector &out); + void mk_equalities(term const &t, expr_ref_vector &out); + void mk_all_equalities(term const &t, expr_ref_vector &out); void display(std::ostream &out); + public: term_graph(ast_manager &m); ~term_graph(); ast_manager& get_ast_manager() const { return m;} - void add_lit(app *lit); // NSB: replace by expr* - void add_lits(expr_ref_vector const &lits) { - for (expr* e : lits) add_lit(::to_app(e)); - } - void add_eq(expr* a, expr* b); + void add_lit(expr *lit); + void add_lits(expr_ref_vector const &lits) { for (expr* e : lits) add_lit(e); } + void add_eq(expr* a, expr* b) { internalize_eq(a, b); } void reset(); - void to_lits(app_ref_vector &lits, bool all_equalities = false); // NSB: swap roles + + // deprecate? void to_lits(expr_ref_vector &lits, bool all_equalities = false); - app_ref to_app(); + expr_ref to_app(); /** * Return literals obtained by projecting added literals From dda65fdd2e9207d6a9e1ea2d3c72c2157844effb Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 11:11:44 -0700 Subject: [PATCH 1181/1283] mk_not: fix clang compilation issue --- src/ast/ast_util.cpp | 24 ++++++++++++------------ src/ast/ast_util.h | 3 +-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 0e5cf12a5..42c0d698b 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -98,7 +98,7 @@ bool is_atom(ast_manager & m, expr * n) { return true; SASSERT(is_app(n)); if (to_app(n)->get_family_id() != m.get_basic_family_id()) { - return true; + return true; } // the other operators of the basic family are not considered atomic: distinct, ite, and, or, iff, xor, not, implies. return (m.is_eq(n) && !m.is_bool(to_app(n)->get_arg(0))) || m.is_true(n) || m.is_false(n); @@ -106,7 +106,7 @@ bool is_atom(ast_manager & m, expr * n) { bool is_literal(ast_manager & m, expr * n) { - return + return is_atom(m, n) || (m.is_not(n) && is_atom(m, to_app(n)->get_arg(0))); } @@ -187,7 +187,7 @@ expr * mk_not(ast_manager & m, expr * arg) { expr * atom; if (m.is_not(arg, atom)) return atom; - else if (m.is_true(arg)) + else if (m.is_true(arg)) return m.mk_false(); else if (m.is_false(arg)) return m.mk_true(); @@ -195,7 +195,7 @@ expr * mk_not(ast_manager & m, expr * arg) { return m.mk_not(arg); } -expr_ref mk_not(expr_ref& e) { +expr_ref mk_not(const expr_ref& e) { return expr_ref(mk_not(e.m(), e), e.m()); } @@ -226,7 +226,7 @@ expr_ref push_not(const expr_ref& e) { } return mk_and(args); } - return expr_ref(mk_not(m, e), m); + return expr_ref(mk_not(m, e), m); } expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args) { @@ -282,7 +282,7 @@ void flatten_and(expr_ref_vector& result) { } result[i] = result.back(); result.pop_back(); - --i; + --i; } else if (m.is_not(result[i].get(), e1) && m.is_implies(e1,e2,e3)) { result.push_back(e2); @@ -294,7 +294,7 @@ void flatten_and(expr_ref_vector& result) { m.is_false(e1))) { result[i] = result.back(); result.pop_back(); - --i; + --i; } else if (m.is_false(result[i].get()) || (m.is_not(result[i].get(), e1) && @@ -308,7 +308,7 @@ void flatten_and(expr_ref_vector& result) { void flatten_and(expr* fml, expr_ref_vector& result) { SASSERT(result.get_manager().is_bool(fml)); - result.push_back(fml); + result.push_back(fml); flatten_and(result); } @@ -345,7 +345,7 @@ void flatten_or(expr_ref_vector& result) { } result[i] = result.back(); result.pop_back(); - --i; + --i; } else if (m.is_implies(result[i].get(),e2,e3)) { result.push_back(e3); @@ -357,7 +357,7 @@ void flatten_or(expr_ref_vector& result) { m.is_true(e1))) { result[i] = result.back(); result.pop_back(); - --i; + --i; } else if (m.is_true(result[i].get()) || (m.is_not(result[i].get(), e1) && @@ -366,12 +366,12 @@ void flatten_or(expr_ref_vector& result) { result.push_back(m.mk_true()); return; } - } + } } void flatten_or(expr* fml, expr_ref_vector& result) { SASSERT(result.get_manager().is_bool(fml)); - result.push_back(fml); + result.push_back(fml); flatten_or(result); } diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index 1383be157..23c2205bb 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -127,7 +127,7 @@ inline expr_ref mk_or(expr_ref_vector const& args) { return expr_ref(mk_or(args. */ expr * mk_not(ast_manager & m, expr * arg); -expr_ref mk_not(expr_ref& e); +expr_ref mk_not(const expr_ref& e); /** Negate and push over conjunction or disjunction. @@ -162,4 +162,3 @@ void flatten_or(expr* fml, expr_ref_vector& result); #endif /* AST_UTIL_H_ */ - From 9c7d9818d304ab0212d946d7d7c59c3dbfb63ad9 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 11:36:46 -0700 Subject: [PATCH 1182/1283] get_app --> get_expr + fix term_lt() --- src/qe/qe_term_graph.cpp | 257 ++++++++++++++++++++------------------- src/qe/qe_term_graph.h | 40 +++--- 2 files changed, 151 insertions(+), 146 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index e723542a2..b951244f3 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -28,46 +28,46 @@ namespace qe { class term { // -- an app represented by this term - expr* m_app; // NSB: to make usable with exprs + expr* m_expr; // NSB: to make usable with exprs // -- root of the equivalence class term* m_root; // -- next element in the equivalence class (cyclic linked list) term* m_next; // -- eq class size unsigned m_class_size; - + // -- general purpose mark unsigned m_mark:1; // -- general purpose second mark unsigned m_mark2:1; // -- is an interpreted constant unsigned m_interpreted:1; - + // -- terms that contain this term as a child ptr_vector m_parents; - + // arguments of term. ptr_vector m_children; - + public: - term(expr* a, u_map& app2term) : - m_app(a), - m_root(this), + term(expr* v, u_map& app2term) : + m_expr(v), + m_root(this), m_next(this), - m_class_size(1), - m_mark(false), + m_class_size(1), + m_mark(false), m_mark2(false), m_interpreted(false) { - if (!is_app(a)) return; - for (expr* e : *to_app(a)) { + if (!is_app()) return; + for (expr* e : *to_app(m_expr)) { term* t = app2term[e->get_id()]; t->get_root().m_parents.push_back(this); m_children.push_back(t); } } - + ~term() {} - + class parents { term const& t; public: @@ -76,7 +76,7 @@ namespace qe { ptr_vector::const_iterator begin() const { return t.m_parents.begin(); } ptr_vector::const_iterator end() const { return t.m_parents.end(); } }; - + class children { term const& t; public: @@ -85,20 +85,20 @@ namespace qe { ptr_vector::const_iterator begin() const { return t.m_children.begin(); } ptr_vector::const_iterator end() const { return t.m_children.end(); } }; - + // Congruence table hash function is based on // roots of children and function declaration. - + unsigned get_hash() const { unsigned a, b, c; - a = b = c = get_decl_id(); + a = b = c = get_decl_id(); for (term * ch : children(this)) { a = ch->get_root().get_id(); mix(a, b, c); } return c; } - + static bool cg_eq(term const * t1, term const * t2) { if (t1->get_decl_id() != t2->get_decl_id()) return false; if (t1->m_children.size() != t2->m_children.size()) return false; @@ -107,41 +107,43 @@ namespace qe { } return true; } - - unsigned get_id() const { return m_app->get_id();} - - unsigned get_decl_id() const { return is_app(m_app) ? to_app(m_app)->get_decl()->get_id() : m_app->get_id(); } - + + 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(); } + bool is_marked() const {return m_mark;} void set_mark(bool v){m_mark = v;} bool is_marked2() const {return m_mark2;} // NSB: where is this used? 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(m_app) || to_app(m_app)->get_family_id() != null_family_id; } + bool is_theory() const { return !is_app() || get_app()->get_family_id() != null_family_id; } void mark_as_interpreted() {m_interpreted=true;} - expr* get_app() const {return m_app;} - unsigned get_num_args() const { return is_app(m_app) ? to_app(m_app)->get_num_args() : 0; } - + 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; } + term &get_root() const {return *m_root;} bool is_root() const {return m_root == this;} void set_root(term &r) {m_root = &r;} term &get_next() const {return *m_next;} void add_parent(term* p) { m_parents.push_back(p); } - + unsigned get_class_size() const {return m_class_size;} - + void merge_eq_class(term &b) { std::swap(this->m_next, b.m_next); m_class_size += b.get_class_size(); // -- reset (useful for debugging) b.m_class_size = 0; } - + // -- make this term the root of its equivalence class void mk_root() { if (is_root()) return; - + term *curr = this; do { if (curr->is_root()) { @@ -156,26 +158,26 @@ namespace qe { while (curr != this); } }; - + class arith_term_graph_plugin : public term_graph_plugin { term_graph &m_g; ast_manager &m; arith_util m_arith; - + public: arith_term_graph_plugin(term_graph &g) : term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} - + virtual ~arith_term_graph_plugin() {} - + bool mk_eq_core (expr *_e1, expr *_e2, expr_ref &res) { expr *e1, *e2; e1 = _e1; e2 = _e2; - + if (m_arith.is_zero(e1)) { std::swap(e1, e2); } @@ -194,7 +196,7 @@ namespace qe { res = m.mk_eq(e1, e2); return true; } - + app* mk_le_zero(expr *arg) { expr *e1, *e2, *e3; // XXX currently disabled @@ -226,7 +228,7 @@ namespace qe { } return m_arith.mk_ge(arg, mk_zero()); } - + bool mk_le_core (expr *arg1, expr * arg2, expr_ref &result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) rational n; @@ -245,13 +247,13 @@ namespace qe { } return false; } - + expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} bool is_one (expr const * n) const { rational val; return m_arith.is_numeral (n, val) && val.is_one (); } - + bool mk_ge_core (expr * arg1, expr * arg2, expr_ref &result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) rational n; @@ -270,17 +272,17 @@ namespace qe { } return false; } - + expr_ref process_lit (expr *_lit) override { expr *lit = _lit; expr *e1, *e2; - + // strip negation bool is_neg = m.is_not(lit); if (is_neg) { lit = to_app(to_app(lit)->get_arg(0)); } - + expr_ref res(m); res = lit; if (m.is_eq (lit, e1, e2)) { @@ -292,12 +294,12 @@ namespace qe { else if (m_arith.is_ge(lit, e1, e2)) { mk_ge_core(e1, e2, res); } - + // restore negation if (is_neg) { res = mk_not(m, res); } - + return res; } }; @@ -309,16 +311,16 @@ namespace qe { term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); } - + term_graph::~term_graph() { reset(); } static family_id get_family_id(ast_manager &m, expr *lit) { - if (m.is_not(lit, lit)) + if (m.is_not(lit, lit)) return get_family_id(m, lit); - expr *a = nullptr, *b = nullptr; + expr *a = nullptr, *b = nullptr; // deal with equality using sort of range if (m.is_eq (lit, a, b)) { return get_sort (a)->get_family_id(); @@ -331,10 +333,10 @@ namespace qe { return null_family_id; } } - + void term_graph::add_lit(expr *l) { expr_ref lit(m); - + family_id fid = get_family_id (m, l); term_graph_plugin *pin = m_plugins.get_plugin(fid); if (pin) { @@ -345,16 +347,16 @@ namespace qe { m_lits.push_back(lit); internalize_lit(lit); } - + bool term_graph::is_internalized(expr *a) { return m_app2term.contains(a->get_id()); } - + term* term_graph::get_term(expr *a) { term *res; return m_app2term.find (a->get_id(), res) ? res : nullptr; } - + term *term_graph::mk_term(expr *a) { term * t = alloc(term, a, m_app2term); if (t->get_num_args() == 0 && m.is_unique_value(a)){ @@ -365,8 +367,8 @@ namespace qe { m_app2term.insert(a->get_id(), t); return t; } - - term* term_graph::internalize_term(expr *t) { + + term* term_graph::internalize_term(expr *t) { term* res = get_term(t); if (res) return res; ptr_buffer todo; @@ -381,7 +383,7 @@ namespace qe { unsigned sz = todo.size(); if (is_app(t)) { for (expr * arg : *::to_app(t)) { - if (!get_term(arg)) + if (!get_term(arg)) todo.push_back(arg); } } @@ -392,7 +394,7 @@ namespace qe { SASSERT(res); return res; } - + void term_graph::internalize_eq(expr *a1, expr* a2) { SASSERT(m_merge.empty()); merge(internalize_term(a1)->get_root(), internalize_term(a2)->get_root()); @@ -402,7 +404,7 @@ namespace qe { void term_graph::internalize_lit(expr* lit) { expr *e1 = nullptr, *e2 = nullptr; - if (m.is_eq (lit, e1, e2)) { + if (m.is_eq (lit, e1, e2)) { internalize_eq (e1, e2); } else { @@ -422,19 +424,19 @@ namespace qe { void term_graph::merge(term &t1, term &t2) { // -- merge might invalidate term2map cache m_term2app.reset(); - m_pinned.reset(); - + m_pinned.reset(); + SASSERT(t1.is_root()); SASSERT(t2.is_root()); - + if (&t1 == &t2) return; - + term *a = &t1; term *b = &t2; if (a->get_class_size() > b->get_class_size()) { std::swap(a, b); } - + // Remove parents of it from the cg table. for (term* p : term::parents(b)) { if (!p->is_marked()) { @@ -442,15 +444,15 @@ namespace qe { m_cg_table.erase(p); } } - // make 'a' be the root of the equivalence class of 'b' + // make 'a' be the root of the equivalence class of 'b' b->set_root(*a); for (term *it = &b->get_next(); it != b; it = &it->get_next()) { it->set_root(*a); } - + // merge equivalence classes a->merge_eq_class(*b); - + // Insert parents of b's old equilvalence class into the cg table for (term* p : term::parents(a)) { if (p->is_marked()) { @@ -462,16 +464,16 @@ namespace qe { m_merge.push_back(std::make_pair(p, p_old)); } } - } + } } - + expr* term_graph::mk_app_core (expr *e) { if (is_app(e)) { - expr_ref_vector kids(m); + expr_ref_vector kids(m); app* a = ::to_app(e); for (expr * arg : *a) { kids.push_back (mk_app(arg)); - } + } app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); m_pinned.push_back(res); return res; @@ -483,44 +485,44 @@ namespace qe { expr_ref term_graph::mk_app(term const &r) { SASSERT(r.is_root()); - + if (r.get_num_args() == 0) { - return expr_ref(r.get_app(), m); + return expr_ref(r.get_expr(), m); } - + expr* res = nullptr; if (m_term2app.find(r.get_id(), res)) { return expr_ref(res, m); } - + res = mk_app_core (r.get_app()); m_term2app.insert(r.get_id(), res); return expr_ref(res, m); - + } expr_ref term_graph::mk_app(expr *a) { term *t = get_term(a); - if (!t) + if (!t) return expr_ref(a, m); - else + else return mk_app(t->get_root()); - + } void term_graph::mk_equalities(term const &t, expr_ref_vector &out) { 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()); out.push_back (m.mk_eq (rep, mem)); } } - + void term_graph::mk_all_equalities(term const &t, expr_ref_vector &out) { mk_equalities(t, out); - + for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { expr* a1 = mk_app_core (it->get_app()); for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { @@ -529,30 +531,32 @@ namespace qe { } } } - + void term_graph::reset_marks() { for (term * t : m_terms) { t->set_mark(false); } } - + /// Order of preference for roots of equivalence classes /// XXX This should be factored out to let clients control the preference - bool term_graph::term_le(term const &t1, term const &t2) { - + bool term_graph::term_lt(term const &t1, term const &t2) { + // prefer constants over applications // prefer uninterpreted constants over values // prefer smaller expressions over larger ones - if (t1.get_num_args() == 0 && t2.get_num_args() > 0) { - return true; + if (t1.get_num_args() == 0 || t2.get_num_args() == 0) { + if (t1.get_num_args() == t2.get_num_args()) { + // t1.get_num_args() == t2.get_num_args() == 0 + if (m.is_value(t1.get_expr()) == m.is_value(t2.get_expr())) + return t1.get_id() < t2.get_id(); + return m.is_value(t2.get_expr()); + } + return t1.get_num_args() < t2.get_num_args(); } - if (t1.get_num_args() == t2.get_num_args()) { - // NSB: how does this possibly define an order? - return m.is_value(t2.get_app()); - } - - unsigned sz1 = get_num_exprs(t1.get_app()); - unsigned sz2 = get_num_exprs(t1.get_app()); + + unsigned sz1 = get_num_exprs(t1.get_expr()); + unsigned sz2 = get_num_exprs(t1.get_expr()); return sz1 < sz2; } @@ -560,9 +564,9 @@ namespace qe { term *r = &t; for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { it->set_mark(true); - if (term_le(*it, *r)) { r = it; } + if (term_lt(*it, *r)) { r = it; } } - + // -- if found something better, make it the new root if (r != &t) { r->mk_root(); @@ -572,47 +576,47 @@ namespace qe { /// Choose better roots for equivalence classes void term_graph::pick_roots() { for (term* t : m_terms) { - if (!t->is_marked() && t->is_root()) + if (!t->is_marked() && t->is_root()) pick_root(*t); } reset_marks(); } - + void term_graph::display(std::ostream &out) { for (term * t : m_terms) { - out << mk_pp(t->get_app(), m) << " is root " << t->is_root() + out << mk_pp(t->get_expr(), m) << " is root " << t->is_root() << " cls sz " << t->get_class_size() << " term " << t << "\n"; } } - + void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { pick_roots(); - + for (expr * a : m_lits) { if (is_internalized(a)) { lits.push_back (::to_app(mk_app(a))); } } - + for (term * t : m_terms) { - if (!t->is_root()) + if (!t->is_root()) continue; - else if (all_equalities) - mk_all_equalities (*t, lits); - else + else if (all_equalities) + mk_all_equalities (*t, lits); + else mk_equalities(*t, lits); } } - - + + expr_ref term_graph::to_app() { expr_ref_vector lits(m); to_lits(lits); return mk_and(lits); } - + void term_graph::reset() { m_term2app.reset(); m_pinned.reset(); @@ -622,9 +626,10 @@ namespace qe { m_lits.reset(); m_cg_table.reset(); } - + expr* term_graph::mk_pure(term& t) { - expr* e = t.get_app(); + expr* e = t.get_expr(); + // AG: the if-statement looks wrong if (m_term2app.find(t.get_id(), e)) e; if (!is_app(e)) return nullptr; app* a = ::to_app(e); @@ -638,35 +643,35 @@ namespace qe { m_term2app.insert(t.get_id(), result); return result; } - + expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { u_map _decls; for (func_decl* f : decls) _decls.insert(f->get_id(), true); // . propagate representatives up over parents. // use work-list + marking to propagate. // . produce equalities over represented classes. - // . produce other literals over represented classes + // . produce other literals over represented classes // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) - + expr_ref_vector result(m); m_term2app.reset(); m_pinned.reset(); - + obj_hashtable eqs; expr_ref eq(m); ptr_vector worklist; for (term * t : m_terms) { worklist.push_back(t); - t->set_mark(true); + t->set_mark(true); } - + while (!worklist.empty()) { term* t = worklist.back(); worklist.pop_back(); t->set_mark(false); - if (m_term2app.contains(t->get_id())) + if (m_term2app.contains(t->get_id())) continue; - if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) + if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) continue; term& root = t->get_root(); @@ -675,7 +680,7 @@ namespace qe { if (!pure) continue; // ensure that the root has a representative - // either by looking up cached version, + // either by looking up cached version, // computing it for the first time, or // inheriting pure. expr* rep = nullptr; @@ -691,7 +696,7 @@ namespace qe { } bool update_rep = false; - // Add equations between pure and rep, + // Add equations between pure and rep, // optionally swap the roles of rep and pure if // pure makes a better representative. if (rep != pure) { @@ -706,7 +711,7 @@ namespace qe { } } - // update the worklist if this is the first + // update the worklist if this is the first // representative or pure was swapped into rep. if (!has_rep || update_rep) { for (term * p : term::parents(root)) { @@ -723,10 +728,10 @@ namespace qe { if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { result.push_back(e); } - } + } // Here we could also walk equivalence classes that contain interpreted values by sort and // extract disequalities bewteen non-unique value representatives. - // these disequalities are implied and can be mined using other means, such as + // these disequalities are implied and can be mined using other means, such as // theory aware core minimization m_term2app.reset(); m_pinned.reset(); diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 4c2c2c6ff..e32f7271c 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -33,11 +33,11 @@ namespace qe { virtual ~term_graph_plugin() {} family_id get_family_id() const {return m_id;} - + /// Process (and potentially augment) a literal virtual expr_ref process_lit (expr *lit) = 0; }; - + class term_graph { struct term_hash { unsigned operator()(term const* t) const; }; @@ -45,62 +45,62 @@ namespace qe { ast_manager & m; ptr_vector m_terms; expr_ref_vector m_lits; // NSB: expr_ref_vector? - u_map m_app2term; + u_map m_app2term; ast_ref_vector m_pinned; u_map m_term2app; plugin_manager m_plugins; ptr_hashtable m_cg_table; vector> m_merge; - + void merge(term &t1, term &t2); void merge_flush(); - + term *mk_term(expr *t); term *get_term(expr *t); - + term *internalize_term(expr *t); void internalize_eq(expr *a1, expr *a2); void internalize_lit(expr *lit); - + bool is_internalized(expr *a); - - bool term_le(term const &t1, term const &t2); + + bool term_lt(term const &t1, term const &t2); void pick_root (term &t); void pick_roots(); - + void reset_marks(); - + expr* mk_app_core(expr* a); expr_ref mk_app(term const &t); expr* mk_pure(term& t); expr_ref mk_app(expr *a); void mk_equalities(term const &t, expr_ref_vector &out); void mk_all_equalities(term const &t, expr_ref_vector &out); - void display(std::ostream &out); + void display(std::ostream &out); public: term_graph(ast_manager &m); ~term_graph(); - + ast_manager& get_ast_manager() const { return m;} - - void add_lit(expr *lit); + + void add_lit(expr *lit); void add_lits(expr_ref_vector const &lits) { for (expr* e : lits) add_lit(e); } void add_eq(expr* a, expr* b) { internalize_eq(a, b); } - + void reset(); // deprecate? void to_lits(expr_ref_vector &lits, bool all_equalities = false); - expr_ref to_app(); + expr_ref to_app(); /** - * Return literals obtained by projecting added literals - * onto the vocabulary of decls (if exclude is false) or outside the + * Return literals obtained by projecting added literals + * onto the vocabulary of decls (if exclude is false) or outside the * vocabulary of decls (if exclude is true). */ expr_ref_vector project(func_decl_ref_vector const& decls, bool exclude); - + }; } From 73486be590472ff40bfe77618c2adc4fee764126 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 13:46:27 -0700 Subject: [PATCH 1183/1283] fix typo in mk_pure --- src/qe/qe_term_graph.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index b951244f3..6ea2194b7 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -78,7 +78,7 @@ namespace qe { }; class children { - term const& t; + term const& t; public: children(term const& _t):t(_t) {} children(term const* _t):t(*_t) {} @@ -628,9 +628,9 @@ namespace qe { } expr* term_graph::mk_pure(term& t) { - expr* e = t.get_expr(); - // AG: the if-statement looks wrong - if (m_term2app.find(t.get_id(), e)) e; + expr* e = nullptr; + if (m_term2app.find(t.get_id(), e)) return e; + e = t.get_expr(); if (!is_app(e)) return nullptr; app* a = ::to_app(e); expr_ref_vector kids(m); @@ -647,11 +647,11 @@ namespace qe { expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { u_map _decls; for (func_decl* f : decls) _decls.insert(f->get_id(), true); - // . propagate representatives up over parents. + // - propagate representatives up over parents. // use work-list + marking to propagate. - // . produce equalities over represented classes. - // . produce other literals over represented classes - // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) + // - produce equalities over represented classes. + // - produce other literals over represented classes + // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) expr_ref_vector result(m); m_term2app.reset(); From 6e61a7c1b282caf68399a2ab4ba1de3a8161f6ca Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 14:40:53 -0700 Subject: [PATCH 1184/1283] minor --- src/qe/qe_term_graph.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 6ea2194b7..412db2909 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -199,7 +199,6 @@ namespace qe { app* mk_le_zero(expr *arg) { expr *e1, *e2, *e3; - // XXX currently disabled if (m_arith.is_add(arg, e1, e2)) { // e1-e2<=0 --> e1<=e2 if (m_arith.is_times_minus_one(e2, e3)) { @@ -215,7 +214,6 @@ namespace qe { app* mk_ge_zero(expr *arg) { expr *e1, *e2, *e3; - // XXX currently disabled if (m_arith.is_add(arg, e1, e2)) { // e1-e2>=0 --> e1>=e2 if (m_arith.is_times_minus_one(e2, e3)) { @@ -422,7 +420,7 @@ namespace qe { } void term_graph::merge(term &t1, term &t2) { - // -- merge might invalidate term2map cache + // -- merge might invalidate term2app cache m_term2app.reset(); m_pinned.reset(); @@ -469,7 +467,7 @@ namespace qe { expr* term_graph::mk_app_core (expr *e) { if (is_app(e)) { - expr_ref_vector kids(m); + expr_ref_buffer kids(m); app* a = ::to_app(e); for (expr * arg : *a) { kids.push_back (mk_app(arg)); From 44a32bc076e79840edd3530d658d065a752378f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 13:55:04 -0700 Subject: [PATCH 1185/1283] updates Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 49 ++++++++- src/qe/qe_mbi.h | 6 ++ src/qe/qe_term_graph.cpp | 218 +++++++++++++++++++-------------------- 3 files changed, 160 insertions(+), 113 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index c6927f7d2..0fe2d49c7 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -19,12 +19,32 @@ Revision History: --*/ #include "ast/ast_util.h" +#include "ast/rewriter/bool_rewriter.h" #include "solver/solver.h" #include "qe/qe_mbi.h" namespace qe { + lbool mbi_plugin::check(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { + SASSERT(lits.empty()); + while (true) { + switch ((*this)(vars, lits, mdl)) { + case mbi_sat: + return l_true; + case mbi_unsat: + if (lits.empty()) return l_false; + block(lits); + break; + case mbi_undef: + return l_undef; + case mbi_augment: + break; + } + } + } + + // ------------------------------- // prop_mbi @@ -116,6 +136,7 @@ namespace qe { blocks.push_back(expr_ref_vector(m)); blocks.push_back(expr_ref_vector(m)); mbi_result last_res = mbi_undef; + bool_rewriter rw(m); while (true) { auto* t1 = turn ? &a : &b; auto* t2 = turn ? &b : &a; @@ -156,10 +177,32 @@ namespace qe { } /** - * TBD: also implement the one-sided versions that create clausal interpolants. + * One-sided pogo creates clausal interpolants. + * It creates a set of consequences of b that are inconsistent with a. */ lbool interpolator::pogo(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { - NOT_IMPLEMENTED_YET(); - return l_undef; + expr_ref_vector lits(m), itps(m); + while (true) { + model_ref mdl; + lits.reset(); + switch (a.check(vars, lits, mdl)) { + case l_true: + switch (b.check(vars, lits, mdl)) { + case l_true: + return l_true; + case l_false: + a.block(lits); + itps.push_back(mk_not(mk_and(lits))); + break; + case l_undef: + return l_undef; + } + case l_false: + itp = mk_and(itps); + return l_false; + case l_undef: + return l_undef; + } + } } }; diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index d9af62bd0..d58430602 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -56,6 +56,12 @@ namespace qe { * \brief Block conjunction of lits from future mbi_augment or mbi_sat. */ virtual void block(expr_ref_vector const& lits) = 0; + + /** + * \brief perform a full check, consume internal auguments if necessary. + */ + lbool check(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl); + }; class prop_mbi_plugin : public mbi_plugin { diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 412db2909..eaf5a372d 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -35,27 +35,27 @@ namespace qe { term* m_next; // -- eq class size unsigned m_class_size; - + // -- general purpose mark unsigned m_mark:1; // -- general purpose second mark unsigned m_mark2:1; // -- is an interpreted constant unsigned m_interpreted:1; - + // -- terms that contain this term as a child ptr_vector m_parents; - + // arguments of term. ptr_vector m_children; - + public: term(expr* v, u_map& app2term) : m_expr(v), - m_root(this), + m_root(this), m_next(this), - m_class_size(1), - m_mark(false), + m_class_size(1), + m_mark(false), m_mark2(false), m_interpreted(false) { if (!is_app()) return; @@ -65,9 +65,9 @@ namespace qe { m_children.push_back(t); } } - + ~term() {} - + class parents { term const& t; public: @@ -76,29 +76,29 @@ namespace qe { ptr_vector::const_iterator begin() const { return t.m_parents.begin(); } ptr_vector::const_iterator end() const { return t.m_parents.end(); } }; - + class children { - term const& t; + term const& t; public: children(term const& _t):t(_t) {} children(term const* _t):t(*_t) {} ptr_vector::const_iterator begin() const { return t.m_children.begin(); } ptr_vector::const_iterator end() const { return t.m_children.end(); } }; - + // Congruence table hash function is based on // roots of children and function declaration. - + unsigned get_hash() const { unsigned a, b, c; - a = b = c = get_decl_id(); + a = b = c = get_decl_id(); for (term * ch : children(this)) { a = ch->get_root().get_id(); mix(a, b, c); } return c; } - + static bool cg_eq(term const * t1, term const * t2) { if (t1->get_decl_id() != t2->get_decl_id()) return false; if (t1->m_children.size() != t2->m_children.size()) return false; @@ -107,16 +107,16 @@ namespace qe { } return true; } - + 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(); } - + bool is_marked() const {return m_mark;} void set_mark(bool v){m_mark = v;} bool is_marked2() const {return m_mark2;} // NSB: where is this used? 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; } void mark_as_interpreted() {m_interpreted=true;} @@ -124,26 +124,26 @@ namespace qe { 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; } - + term &get_root() const {return *m_root;} bool is_root() const {return m_root == this;} void set_root(term &r) {m_root = &r;} term &get_next() const {return *m_next;} void add_parent(term* p) { m_parents.push_back(p); } - + unsigned get_class_size() const {return m_class_size;} - + void merge_eq_class(term &b) { std::swap(this->m_next, b.m_next); m_class_size += b.get_class_size(); // -- reset (useful for debugging) b.m_class_size = 0; } - + // -- make this term the root of its equivalence class void mk_root() { if (is_root()) return; - + term *curr = this; do { if (curr->is_root()) { @@ -158,26 +158,26 @@ namespace qe { while (curr != this); } }; - + class arith_term_graph_plugin : public term_graph_plugin { term_graph &m_g; ast_manager &m; arith_util m_arith; - + public: arith_term_graph_plugin(term_graph &g) : term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} - + virtual ~arith_term_graph_plugin() {} - + bool mk_eq_core (expr *_e1, expr *_e2, expr_ref &res) { expr *e1, *e2; e1 = _e1; e2 = _e2; - + if (m_arith.is_zero(e1)) { std::swap(e1, e2); } @@ -196,7 +196,7 @@ namespace qe { res = m.mk_eq(e1, e2); return true; } - + app* mk_le_zero(expr *arg) { expr *e1, *e2, *e3; if (m_arith.is_add(arg, e1, e2)) { @@ -226,7 +226,7 @@ namespace qe { } return m_arith.mk_ge(arg, mk_zero()); } - + bool mk_le_core (expr *arg1, expr * arg2, expr_ref &result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) rational n; @@ -245,13 +245,13 @@ namespace qe { } return false; } - + expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} bool is_one (expr const * n) const { rational val; return m_arith.is_numeral (n, val) && val.is_one (); } - + bool mk_ge_core (expr * arg1, expr * arg2, expr_ref &result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) rational n; @@ -270,17 +270,17 @@ namespace qe { } return false; } - + expr_ref process_lit (expr *_lit) override { expr *lit = _lit; expr *e1, *e2; - + // strip negation bool is_neg = m.is_not(lit); if (is_neg) { lit = to_app(to_app(lit)->get_arg(0)); } - + expr_ref res(m); res = lit; if (m.is_eq (lit, e1, e2)) { @@ -292,12 +292,12 @@ namespace qe { else if (m_arith.is_ge(lit, e1, e2)) { mk_ge_core(e1, e2, res); } - + // restore negation if (is_neg) { res = mk_not(m, res); } - + return res; } }; @@ -309,16 +309,16 @@ namespace qe { term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); } - + term_graph::~term_graph() { reset(); } static family_id get_family_id(ast_manager &m, expr *lit) { - if (m.is_not(lit, lit)) + if (m.is_not(lit, lit)) return get_family_id(m, lit); - expr *a = nullptr, *b = nullptr; + expr *a = nullptr, *b = nullptr; // deal with equality using sort of range if (m.is_eq (lit, a, b)) { return get_sort (a)->get_family_id(); @@ -331,10 +331,10 @@ namespace qe { return null_family_id; } } - + void term_graph::add_lit(expr *l) { expr_ref lit(m); - + family_id fid = get_family_id (m, l); term_graph_plugin *pin = m_plugins.get_plugin(fid); if (pin) { @@ -345,16 +345,16 @@ namespace qe { m_lits.push_back(lit); internalize_lit(lit); } - + bool term_graph::is_internalized(expr *a) { return m_app2term.contains(a->get_id()); } - + term* term_graph::get_term(expr *a) { term *res; return m_app2term.find (a->get_id(), res) ? res : nullptr; } - + term *term_graph::mk_term(expr *a) { term * t = alloc(term, a, m_app2term); if (t->get_num_args() == 0 && m.is_unique_value(a)){ @@ -365,8 +365,8 @@ namespace qe { m_app2term.insert(a->get_id(), t); return t; } - - term* term_graph::internalize_term(expr *t) { + + term* term_graph::internalize_term(expr *t) { term* res = get_term(t); if (res) return res; ptr_buffer todo; @@ -381,7 +381,7 @@ namespace qe { unsigned sz = todo.size(); if (is_app(t)) { for (expr * arg : *::to_app(t)) { - if (!get_term(arg)) + if (!get_term(arg)) todo.push_back(arg); } } @@ -392,17 +392,17 @@ namespace qe { SASSERT(res); return res; } - + void term_graph::internalize_eq(expr *a1, expr* a2) { SASSERT(m_merge.empty()); - merge(internalize_term(a1)->get_root(), internalize_term(a2)->get_root()); + merge(*internalize_term(a1), *internalize_term(a2)); merge_flush(); SASSERT(m_merge.empty()); } void term_graph::internalize_lit(expr* lit) { expr *e1 = nullptr, *e2 = nullptr; - if (m.is_eq (lit, e1, e2)) { + if (m.is_eq (lit, e1, e2)) { internalize_eq (e1, e2); } else { @@ -422,19 +422,17 @@ namespace qe { void term_graph::merge(term &t1, term &t2) { // -- merge might invalidate term2app cache m_term2app.reset(); - m_pinned.reset(); - - SASSERT(t1.is_root()); - SASSERT(t2.is_root()); - - if (&t1 == &t2) return; - - term *a = &t1; - term *b = &t2; + m_pinned.reset(); + + term *a = &t1.get_root(); + term *b = &t2.get_root(); + + if (a == b) return; + if (a->get_class_size() > b->get_class_size()) { std::swap(a, b); } - + // Remove parents of it from the cg table. for (term* p : term::parents(b)) { if (!p->is_marked()) { @@ -442,15 +440,15 @@ namespace qe { m_cg_table.erase(p); } } - // make 'a' be the root of the equivalence class of 'b' + // make 'a' be the root of the equivalence class of 'b' b->set_root(*a); for (term *it = &b->get_next(); it != b; it = &it->get_next()) { it->set_root(*a); } - + // merge equivalence classes a->merge_eq_class(*b); - + // Insert parents of b's old equilvalence class into the cg table for (term* p : term::parents(a)) { if (p->is_marked()) { @@ -462,16 +460,16 @@ namespace qe { m_merge.push_back(std::make_pair(p, p_old)); } } - } + } } - + expr* term_graph::mk_app_core (expr *e) { if (is_app(e)) { expr_ref_buffer kids(m); app* a = ::to_app(e); for (expr * arg : *a) { kids.push_back (mk_app(arg)); - } + } app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); m_pinned.push_back(res); return res; @@ -483,44 +481,44 @@ namespace qe { expr_ref term_graph::mk_app(term const &r) { SASSERT(r.is_root()); - + if (r.get_num_args() == 0) { return expr_ref(r.get_expr(), m); } - + expr* res = nullptr; if (m_term2app.find(r.get_id(), res)) { return expr_ref(res, m); } - + res = mk_app_core (r.get_app()); m_term2app.insert(r.get_id(), res); return expr_ref(res, m); - + } expr_ref term_graph::mk_app(expr *a) { term *t = get_term(a); - if (!t) + if (!t) return expr_ref(a, m); - else + else return mk_app(t->get_root()); - + } void term_graph::mk_equalities(term const &t, expr_ref_vector &out) { 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()); out.push_back (m.mk_eq (rep, mem)); } } - + void term_graph::mk_all_equalities(term const &t, expr_ref_vector &out) { mk_equalities(t, out); - + for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { expr* a1 = mk_app_core (it->get_app()); for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { @@ -529,22 +527,22 @@ namespace qe { } } } - + void term_graph::reset_marks() { for (term * t : m_terms) { t->set_mark(false); } } - + /// Order of preference for roots of equivalence classes /// XXX This should be factored out to let clients control the preference bool term_graph::term_lt(term const &t1, term const &t2) { - + // prefer constants over applications // prefer uninterpreted constants over values // prefer smaller expressions over larger ones if (t1.get_num_args() == 0 || t2.get_num_args() == 0) { - if (t1.get_num_args() == t2.get_num_args()) { + if (t1.get_num_args() == t2.get_num_args()) { // t1.get_num_args() == t2.get_num_args() == 0 if (m.is_value(t1.get_expr()) == m.is_value(t2.get_expr())) return t1.get_id() < t2.get_id(); @@ -552,7 +550,7 @@ namespace qe { } return t1.get_num_args() < t2.get_num_args(); } - + unsigned sz1 = get_num_exprs(t1.get_expr()); unsigned sz2 = get_num_exprs(t1.get_expr()); return sz1 < sz2; @@ -564,7 +562,7 @@ namespace qe { it->set_mark(true); if (term_lt(*it, *r)) { r = it; } } - + // -- if found something better, make it the new root if (r != &t) { r->mk_root(); @@ -574,12 +572,12 @@ namespace qe { /// Choose better roots for equivalence classes void term_graph::pick_roots() { for (term* t : m_terms) { - if (!t->is_marked() && t->is_root()) + if (!t->is_marked() && t->is_root()) pick_root(*t); } reset_marks(); } - + void term_graph::display(std::ostream &out) { for (term * t : m_terms) { out << mk_pp(t->get_expr(), m) << " is root " << t->is_root() @@ -588,33 +586,33 @@ namespace qe { << "\n"; } } - + void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { pick_roots(); - + for (expr * a : m_lits) { if (is_internalized(a)) { lits.push_back (::to_app(mk_app(a))); } } - + for (term * t : m_terms) { - if (!t->is_root()) + if (!t->is_root()) continue; - else if (all_equalities) - mk_all_equalities (*t, lits); - else + else if (all_equalities) + mk_all_equalities (*t, lits); + else mk_equalities(*t, lits); } } - - + + expr_ref term_graph::to_app() { expr_ref_vector lits(m); to_lits(lits); return mk_and(lits); } - + void term_graph::reset() { m_term2app.reset(); m_pinned.reset(); @@ -624,7 +622,7 @@ namespace qe { m_lits.reset(); m_cg_table.reset(); } - + expr* term_graph::mk_pure(term& t) { expr* e = nullptr; if (m_term2app.find(t.get_id(), e)) return e; @@ -641,7 +639,7 @@ namespace qe { m_term2app.insert(t.get_id(), result); return result; } - + expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { u_map _decls; for (func_decl* f : decls) _decls.insert(f->get_id(), true); @@ -649,27 +647,27 @@ namespace qe { // use work-list + marking to propagate. // - produce equalities over represented classes. // - produce other literals over represented classes - // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) - + // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) + expr_ref_vector result(m); m_term2app.reset(); m_pinned.reset(); - + obj_hashtable eqs; expr_ref eq(m); ptr_vector worklist; for (term * t : m_terms) { worklist.push_back(t); - t->set_mark(true); + t->set_mark(true); } - + while (!worklist.empty()) { term* t = worklist.back(); worklist.pop_back(); t->set_mark(false); - if (m_term2app.contains(t->get_id())) + if (m_term2app.contains(t->get_id())) continue; - if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) + if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) continue; term& root = t->get_root(); @@ -678,7 +676,7 @@ namespace qe { if (!pure) continue; // ensure that the root has a representative - // either by looking up cached version, + // either by looking up cached version, // computing it for the first time, or // inheriting pure. expr* rep = nullptr; @@ -694,7 +692,7 @@ namespace qe { } bool update_rep = false; - // Add equations between pure and rep, + // Add equations between pure and rep, // optionally swap the roles of rep and pure if // pure makes a better representative. if (rep != pure) { @@ -709,7 +707,7 @@ namespace qe { } } - // update the worklist if this is the first + // update the worklist if this is the first // representative or pure was swapped into rep. if (!has_rep || update_rep) { for (term * p : term::parents(root)) { @@ -726,10 +724,10 @@ namespace qe { if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { result.push_back(e); } - } + } // Here we could also walk equivalence classes that contain interpreted values by sort and // extract disequalities bewteen non-unique value representatives. - // these disequalities are implied and can be mined using other means, such as + // these disequalities are implied and can be mined using other means, such as // theory aware core minimization m_term2app.reset(); m_pinned.reset(); From f963fc06f40c6b762f45e22a6fd4aa3a10654f6f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 14:28:24 -0700 Subject: [PATCH 1186/1283] sketch out euf-solver based on complete projection Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 66 ++++++++++++++++++++++++++++++++++++---- src/qe/qe_mbi.h | 5 ++- src/qe/qe_term_graph.cpp | 10 ------ 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 0fe2d49c7..d47c2ab2c 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -19,9 +19,12 @@ Revision History: --*/ #include "ast/ast_util.h" +#include "ast/for_each_expr.h" #include "ast/rewriter/bool_rewriter.h" +#include "model/model_evaluator.h" #include "solver/solver.h" #include "qe/qe_mbi.h" +#include "qe/qe_term_graph.h" namespace qe { @@ -87,7 +90,35 @@ namespace qe { // ------------------------------- // euf_mbi, TBD - euf_mbi_plugin::euf_mbi_plugin(solver* s): m(s->get_manager()), m_solver(s) {} + struct euf_mbi_plugin::is_atom_proc { + ast_manager& m; + expr_ref_vector& m_atoms; + is_atom_proc(expr_ref_vector& atoms): m(atoms.m()), m_atoms(atoms) {} + void operator()(app* a) { + if (m.is_eq(a)) { + m_atoms.push_back(a); + } + else if (m.is_bool(a) && a->get_family_id() != m.get_basic_family_id()) { + m_atoms.push_back(a); + } + } + void operator()(expr*) {} + }; + + euf_mbi_plugin::euf_mbi_plugin(solver* s, solver* sNot): + m(s->get_manager()), + m_atoms(m), + m_solver(s), + m_dual_solver(sNot) + { + expr_ref_vector fmls(m); + m_solver->get_assertions(fmls); + expr_fast_mark1 marks; + is_atom_proc proc(m_atoms); + for (expr* e : fmls) { + quick_for_each_expr(proc, marks, e); + } + } mbi_result euf_mbi_plugin::operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { lbool r = m_solver->check_sat(lits); @@ -95,16 +126,39 @@ namespace qe { case l_false: lits.reset(); m_solver->get_unsat_core(lits); + // optionally minimize core using superposition. return mbi_unsat; case l_true: { expr_ref_vector fmls(m); m_solver->get_model(mdl); + model_evaluator mev(*mdl.get()); lits.reset(); - // 1. extract formulas from solver - // 2. extract implicant over formulas - // 3. extract equalities or other assignments over the congruence classes - m_solver->get_assertions(fmls); - NOT_IMPLEMENTED_YET(); + for (expr* e : m_atoms) { + if (mev.is_true(e)) { + lits.push_back(e); + } + else if (mev.is_false(e)) { + lits.push_back(m.mk_not(e)); + } + } + r = m_dual_solver->check_sat(lits); + expr_ref_vector core(m); + term_graph tg(m); + switch (r) { + case l_false: + // use the dual solver to find a 'small' implicant + m_dual_solver->get_unsat_core(core); + // project the implicant onto vars + tg.add_lits(core); + lits.reset(); + lits.append(tg.project(vars, false)); + return mbi_sat; + case l_undef: + return mbi_undef; + case l_true: + UNREACHABLE(); + return mbi_undef; + } return mbi_sat; } default: diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index d58430602..8ecb6532e 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -76,8 +76,11 @@ namespace qe { class euf_mbi_plugin : public mbi_plugin { ast_manager& m; solver_ref m_solver; + solver_ref m_dual_solver; + expr_ref_vector m_atoms; + struct is_atom_proc; public: - euf_mbi_plugin(solver* s); + euf_mbi_plugin(solver* s, solver* sNot); ~euf_mbi_plugin() override {} mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; void block(expr_ref_vector const& lits) override; diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index eaf5a372d..a5e45d389 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -35,7 +35,6 @@ namespace qe { term* m_next; // -- eq class size unsigned m_class_size; - // -- general purpose mark unsigned m_mark:1; // -- general purpose second mark @@ -160,12 +159,10 @@ namespace qe { }; - class arith_term_graph_plugin : public term_graph_plugin { term_graph &m_g; ast_manager &m; arith_util m_arith; - public: arith_term_graph_plugin(term_graph &g) : term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), @@ -177,7 +174,6 @@ namespace qe { expr *e1, *e2; e1 = _e1; e2 = _e2; - if (m_arith.is_zero(e1)) { std::swap(e1, e2); } @@ -245,7 +241,6 @@ namespace qe { } return false; } - expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} bool is_one (expr const * n) const { rational val; @@ -292,12 +287,10 @@ namespace qe { else if (m_arith.is_ge(lit, e1, e2)) { mk_ge_core(e1, e2, res); } - // restore negation if (is_neg) { res = mk_not(m, res); } - return res; } }; @@ -331,7 +324,6 @@ namespace qe { return null_family_id; } } - void term_graph::add_lit(expr *l) { expr_ref lit(m); @@ -509,7 +501,6 @@ namespace qe { void term_graph::mk_equalities(term const &t, expr_ref_vector &out) { 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()); out.push_back (m.mk_eq (rep, mem)); @@ -606,7 +597,6 @@ namespace qe { } } - expr_ref term_graph::to_app() { expr_ref_vector lits(m); to_lits(lits); From 5ab6d6ca16b081ba1903ab3a18c32e8c821512ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 14:31:20 -0700 Subject: [PATCH 1187/1283] term_le -> term_lt Signed-off-by: Nikolaj Bjorner --- src/qe/qe_term_graph.cpp | 164 +++++++++++++++++++-------------------- src/qe/qe_term_graph.h | 38 ++++----- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index a5e45d389..4101d6d56 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -41,20 +41,20 @@ namespace qe { unsigned m_mark2:1; // -- is an interpreted constant unsigned m_interpreted:1; - + // -- terms that contain this term as a child ptr_vector m_parents; - + // arguments of term. ptr_vector m_children; - + public: term(expr* v, u_map& app2term) : m_expr(v), - m_root(this), + m_root(this), m_next(this), - m_class_size(1), - m_mark(false), + m_class_size(1), + m_mark(false), m_mark2(false), m_interpreted(false) { if (!is_app()) return; @@ -75,29 +75,29 @@ namespace qe { ptr_vector::const_iterator begin() const { return t.m_parents.begin(); } ptr_vector::const_iterator end() const { return t.m_parents.end(); } }; - + class children { - term const& t; + term const& t; public: children(term const& _t):t(_t) {} children(term const* _t):t(*_t) {} ptr_vector::const_iterator begin() const { return t.m_children.begin(); } ptr_vector::const_iterator end() const { return t.m_children.end(); } }; - + // Congruence table hash function is based on // roots of children and function declaration. - + unsigned get_hash() const { unsigned a, b, c; - a = b = c = get_decl_id(); + a = b = c = get_decl_id(); for (term * ch : children(this)) { a = ch->get_root().get_id(); mix(a, b, c); } return c; } - + static bool cg_eq(term const * t1, term const * t2) { if (t1->get_decl_id() != t2->get_decl_id()) return false; if (t1->m_children.size() != t2->m_children.size()) return false; @@ -106,16 +106,16 @@ namespace qe { } return true; } - + 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(); } - + bool is_marked() const {return m_mark;} void set_mark(bool v){m_mark = v;} bool is_marked2() const {return m_mark2;} // NSB: where is this used? 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; } void mark_as_interpreted() {m_interpreted=true;} @@ -123,26 +123,26 @@ namespace qe { 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; } - + term &get_root() const {return *m_root;} bool is_root() const {return m_root == this;} void set_root(term &r) {m_root = &r;} term &get_next() const {return *m_next;} void add_parent(term* p) { m_parents.push_back(p); } - + unsigned get_class_size() const {return m_class_size;} - + void merge_eq_class(term &b) { std::swap(this->m_next, b.m_next); m_class_size += b.get_class_size(); // -- reset (useful for debugging) b.m_class_size = 0; } - + // -- make this term the root of its equivalence class void mk_root() { if (is_root()) return; - + term *curr = this; do { if (curr->is_root()) { @@ -157,7 +157,7 @@ namespace qe { while (curr != this); } }; - + class arith_term_graph_plugin : public term_graph_plugin { term_graph &m_g; @@ -192,7 +192,7 @@ namespace qe { res = m.mk_eq(e1, e2); return true; } - + app* mk_le_zero(expr *arg) { expr *e1, *e2, *e3; if (m_arith.is_add(arg, e1, e2)) { @@ -222,7 +222,7 @@ namespace qe { } return m_arith.mk_ge(arg, mk_zero()); } - + bool mk_le_core (expr *arg1, expr * arg2, expr_ref &result) { // t <= -1 ==> t < 0 ==> ! (t >= 0) rational n; @@ -246,7 +246,7 @@ namespace qe { rational val; return m_arith.is_numeral (n, val) && val.is_one (); } - + bool mk_ge_core (expr * arg1, expr * arg2, expr_ref &result) { // t >= 1 ==> t > 0 ==> ! (t <= 0) rational n; @@ -265,17 +265,17 @@ namespace qe { } return false; } - + expr_ref process_lit (expr *_lit) override { expr *lit = _lit; expr *e1, *e2; - + // strip negation bool is_neg = m.is_not(lit); if (is_neg) { lit = to_app(to_app(lit)->get_arg(0)); } - + expr_ref res(m); res = lit; if (m.is_eq (lit, e1, e2)) { @@ -302,16 +302,16 @@ namespace qe { term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); } - + term_graph::~term_graph() { reset(); } static family_id get_family_id(ast_manager &m, expr *lit) { - if (m.is_not(lit, lit)) + if (m.is_not(lit, lit)) return get_family_id(m, lit); - expr *a = nullptr, *b = nullptr; + expr *a = nullptr, *b = nullptr; // deal with equality using sort of range if (m.is_eq (lit, a, b)) { return get_sort (a)->get_family_id(); @@ -326,7 +326,7 @@ namespace qe { } void term_graph::add_lit(expr *l) { expr_ref lit(m); - + family_id fid = get_family_id (m, l); term_graph_plugin *pin = m_plugins.get_plugin(fid); if (pin) { @@ -337,16 +337,16 @@ namespace qe { m_lits.push_back(lit); internalize_lit(lit); } - + bool term_graph::is_internalized(expr *a) { return m_app2term.contains(a->get_id()); } - + term* term_graph::get_term(expr *a) { term *res; return m_app2term.find (a->get_id(), res) ? res : nullptr; } - + term *term_graph::mk_term(expr *a) { term * t = alloc(term, a, m_app2term); if (t->get_num_args() == 0 && m.is_unique_value(a)){ @@ -357,8 +357,8 @@ namespace qe { m_app2term.insert(a->get_id(), t); return t; } - - term* term_graph::internalize_term(expr *t) { + + term* term_graph::internalize_term(expr *t) { term* res = get_term(t); if (res) return res; ptr_buffer todo; @@ -373,7 +373,7 @@ namespace qe { unsigned sz = todo.size(); if (is_app(t)) { for (expr * arg : *::to_app(t)) { - if (!get_term(arg)) + if (!get_term(arg)) todo.push_back(arg); } } @@ -394,7 +394,7 @@ namespace qe { void term_graph::internalize_lit(expr* lit) { expr *e1 = nullptr, *e2 = nullptr; - if (m.is_eq (lit, e1, e2)) { + if (m.is_eq (lit, e1, e2)) { internalize_eq (e1, e2); } else { @@ -432,15 +432,15 @@ namespace qe { m_cg_table.erase(p); } } - // make 'a' be the root of the equivalence class of 'b' + // make 'a' be the root of the equivalence class of 'b' b->set_root(*a); for (term *it = &b->get_next(); it != b; it = &it->get_next()) { it->set_root(*a); } - + // merge equivalence classes a->merge_eq_class(*b); - + // Insert parents of b's old equilvalence class into the cg table for (term* p : term::parents(a)) { if (p->is_marked()) { @@ -452,16 +452,16 @@ namespace qe { m_merge.push_back(std::make_pair(p, p_old)); } } - } + } } - + expr* term_graph::mk_app_core (expr *e) { if (is_app(e)) { expr_ref_buffer kids(m); app* a = ::to_app(e); for (expr * arg : *a) { kids.push_back (mk_app(arg)); - } + } app* res = m.mk_app(a->get_decl(), a->get_num_args(), kids.c_ptr()); m_pinned.push_back(res); return res; @@ -473,29 +473,29 @@ namespace qe { expr_ref term_graph::mk_app(term const &r) { SASSERT(r.is_root()); - + if (r.get_num_args() == 0) { return expr_ref(r.get_expr(), m); } - + expr* res = nullptr; if (m_term2app.find(r.get_id(), res)) { return expr_ref(res, m); } - + res = mk_app_core (r.get_app()); m_term2app.insert(r.get_id(), res); return expr_ref(res, m); - + } expr_ref term_graph::mk_app(expr *a) { term *t = get_term(a); - if (!t) + if (!t) return expr_ref(a, m); - else + else return mk_app(t->get_root()); - + } void term_graph::mk_equalities(term const &t, expr_ref_vector &out) { @@ -506,10 +506,10 @@ namespace qe { out.push_back (m.mk_eq (rep, mem)); } } - + void term_graph::mk_all_equalities(term const &t, expr_ref_vector &out) { mk_equalities(t, out); - + for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { expr* a1 = mk_app_core (it->get_app()); for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { @@ -518,22 +518,22 @@ namespace qe { } } } - + void term_graph::reset_marks() { for (term * t : m_terms) { t->set_mark(false); } } - + /// Order of preference for roots of equivalence classes /// XXX This should be factored out to let clients control the preference bool term_graph::term_lt(term const &t1, term const &t2) { - + // prefer constants over applications // prefer uninterpreted constants over values // prefer smaller expressions over larger ones if (t1.get_num_args() == 0 || t2.get_num_args() == 0) { - if (t1.get_num_args() == t2.get_num_args()) { + if (t1.get_num_args() == t2.get_num_args()) { // t1.get_num_args() == t2.get_num_args() == 0 if (m.is_value(t1.get_expr()) == m.is_value(t2.get_expr())) return t1.get_id() < t2.get_id(); @@ -541,7 +541,7 @@ namespace qe { } return t1.get_num_args() < t2.get_num_args(); } - + unsigned sz1 = get_num_exprs(t1.get_expr()); unsigned sz2 = get_num_exprs(t1.get_expr()); return sz1 < sz2; @@ -553,7 +553,7 @@ namespace qe { it->set_mark(true); if (term_lt(*it, *r)) { r = it; } } - + // -- if found something better, make it the new root if (r != &t) { r->mk_root(); @@ -563,12 +563,12 @@ namespace qe { /// Choose better roots for equivalence classes void term_graph::pick_roots() { for (term* t : m_terms) { - if (!t->is_marked() && t->is_root()) + if (!t->is_marked() && t->is_root()) pick_root(*t); } reset_marks(); } - + void term_graph::display(std::ostream &out) { for (term * t : m_terms) { out << mk_pp(t->get_expr(), m) << " is root " << t->is_root() @@ -577,32 +577,32 @@ namespace qe { << "\n"; } } - + void term_graph::to_lits (expr_ref_vector &lits, bool all_equalities) { pick_roots(); - + for (expr * a : m_lits) { if (is_internalized(a)) { lits.push_back (::to_app(mk_app(a))); } } - + for (term * t : m_terms) { - if (!t->is_root()) + if (!t->is_root()) continue; - else if (all_equalities) - mk_all_equalities (*t, lits); - else + else if (all_equalities) + mk_all_equalities (*t, lits); + else mk_equalities(*t, lits); } } - + expr_ref term_graph::to_app() { expr_ref_vector lits(m); to_lits(lits); return mk_and(lits); } - + void term_graph::reset() { m_term2app.reset(); m_pinned.reset(); @@ -612,7 +612,7 @@ namespace qe { m_lits.reset(); m_cg_table.reset(); } - + expr* term_graph::mk_pure(term& t) { expr* e = nullptr; if (m_term2app.find(t.get_id(), e)) return e; @@ -629,7 +629,7 @@ namespace qe { m_term2app.insert(t.get_id(), result); return result; } - + expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { u_map _decls; for (func_decl* f : decls) _decls.insert(f->get_id(), true); @@ -637,27 +637,27 @@ namespace qe { // use work-list + marking to propagate. // - produce equalities over represented classes. // - produce other literals over represented classes - // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) - + // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) + expr_ref_vector result(m); m_term2app.reset(); m_pinned.reset(); - + obj_hashtable eqs; expr_ref eq(m); ptr_vector worklist; for (term * t : m_terms) { worklist.push_back(t); - t->set_mark(true); + t->set_mark(true); } - + while (!worklist.empty()) { term* t = worklist.back(); worklist.pop_back(); t->set_mark(false); - if (m_term2app.contains(t->get_id())) + if (m_term2app.contains(t->get_id())) continue; - if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) + if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) continue; term& root = t->get_root(); @@ -714,10 +714,10 @@ namespace qe { if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { result.push_back(e); } - } + } // Here we could also walk equivalence classes that contain interpreted values by sort and // extract disequalities bewteen non-unique value representatives. - // these disequalities are implied and can be mined using other means, such as + // these disequalities are implied and can be mined using other means, such as // theory aware core minimization m_term2app.reset(); m_pinned.reset(); diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index e32f7271c..fbb2ceb16 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -33,11 +33,11 @@ namespace qe { virtual ~term_graph_plugin() {} family_id get_family_id() const {return m_id;} - + /// Process (and potentially augment) a literal virtual expr_ref process_lit (expr *lit) = 0; }; - + class term_graph { struct term_hash { unsigned operator()(term const* t) const; }; @@ -45,62 +45,62 @@ namespace qe { ast_manager & m; ptr_vector m_terms; expr_ref_vector m_lits; // NSB: expr_ref_vector? - u_map m_app2term; + u_map m_app2term; ast_ref_vector m_pinned; u_map m_term2app; plugin_manager m_plugins; ptr_hashtable m_cg_table; vector> m_merge; - + void merge(term &t1, term &t2); void merge_flush(); - + term *mk_term(expr *t); term *get_term(expr *t); - + term *internalize_term(expr *t); void internalize_eq(expr *a1, expr *a2); void internalize_lit(expr *lit); - + bool is_internalized(expr *a); - + bool term_lt(term const &t1, term const &t2); void pick_root (term &t); void pick_roots(); - + void reset_marks(); - + expr* mk_app_core(expr* a); expr_ref mk_app(term const &t); expr* mk_pure(term& t); expr_ref mk_app(expr *a); void mk_equalities(term const &t, expr_ref_vector &out); void mk_all_equalities(term const &t, expr_ref_vector &out); - void display(std::ostream &out); + void display(std::ostream &out); public: term_graph(ast_manager &m); ~term_graph(); - + ast_manager& get_ast_manager() const { return m;} - - void add_lit(expr *lit); + + void add_lit(expr *lit); void add_lits(expr_ref_vector const &lits) { for (expr* e : lits) add_lit(e); } void add_eq(expr* a, expr* b) { internalize_eq(a, b); } - + void reset(); // deprecate? void to_lits(expr_ref_vector &lits, bool all_equalities = false); - expr_ref to_app(); + expr_ref to_app(); /** - * Return literals obtained by projecting added literals - * onto the vocabulary of decls (if exclude is false) or outside the + * Return literals obtained by projecting added literals + * onto the vocabulary of decls (if exclude is false) or outside the * vocabulary of decls (if exclude is true). */ expr_ref_vector project(func_decl_ref_vector const& decls, bool exclude); - + }; } From 5566b5689c288fc843b76d389b47b364e99cbb4a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 15:22:44 -0700 Subject: [PATCH 1188/1283] Silence clang warning --- src/qe/qe_mbi.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 8ecb6532e..671099015 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -35,20 +35,20 @@ namespace qe { * \brief Utility that works modulo a background state. * - vars * variables to preferrably project onto (other variables would require quantification to fit interpolation signature) - * - lits + * - lits * set of literals to check satisfiability with respect to. * - mdl - * optional model for caller. + * optional model for caller. * on return: * - mbi_sat: * populates mdl with a satisfying state, and lits with implicant for background state. * - mbi_unsat: - * populates lits to be inconsistent with background state. + * populates lits to be inconsistent with background state. * For all practical purposes it is a weakening of lits or even a subset of lits. * - mbi_augment: - * populates lits with strengthening of lits (superset) + * populates lits with strengthening of lits (superset) * - mbi_undef: - * inconclusive, + * inconclusive, */ virtual mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) = 0; @@ -72,12 +72,12 @@ namespace qe { mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; void block(expr_ref_vector const& lits) override; }; - + class euf_mbi_plugin : public mbi_plugin { ast_manager& m; + expr_ref_vector m_atoms; solver_ref m_solver; solver_ref m_dual_solver; - expr_ref_vector m_atoms; struct is_atom_proc; public: euf_mbi_plugin(solver* s, solver* sNot); From 2e616c482b6954b1771ef31864b1c3f0b1604cce Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 15:25:20 -0700 Subject: [PATCH 1189/1283] plugin work Signed-off-by: Nikolaj Bjorner --- src/qe/CMakeLists.txt | 1 + src/qe/qe_solve_plugin.cpp | 305 +++++++++++++++++++++++++++++++++++++ src/qe/qe_solve_plugin.h | 52 +++++++ 3 files changed, 358 insertions(+) create mode 100644 src/qe/qe_solve_plugin.cpp create mode 100644 src/qe/qe_solve_plugin.h diff --git a/src/qe/CMakeLists.txt b/src/qe/CMakeLists.txt index d771ec62e..e9f91ae3e 100644 --- a/src/qe/CMakeLists.txt +++ b/src/qe/CMakeLists.txt @@ -17,6 +17,7 @@ z3_add_component(qe qe_mbp.cpp qe_mbi.cpp qe_sat_tactic.cpp + qe_solve_plugin.cpp qe_tactic.cpp qe_term_graph.cpp qsat.cpp diff --git a/src/qe/qe_solve_plugin.cpp b/src/qe/qe_solve_plugin.cpp new file mode 100644 index 000000000..7a4dd97f4 --- /dev/null +++ b/src/qe/qe_solve_plugin.cpp @@ -0,0 +1,305 @@ +/** +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + qe_solve.cpp + +Abstract: + + Light-weight variable solving plugin model for qe-lite and term_graph. + +Author: + + Nikolaj Bjorner (nbjorner), Arie Gurfinkel 2018-6-8 + +Revision History: + + +--*/ + +#pragma once + +#include "ast/arith_decl_plugin.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "qe/qe_solve_plugin.h" + +namespace qe { + + expr_ref solve_plugin::operator()(expr* lit) { + if (m.is_not(lit, lit)) + return solve(lit, false); + else + return solve(lit, true); + } + + class arith_solve_plugin : public solve_plugin { + arith_util a; + public: + arith_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("arith"), is_var), a(m) {} + + typedef std::pair signed_expr; + + /** + *\brief + * return r * (sum_{(sign,e) \in exprs} sign * e) + */ + expr_ref mk_term(bool is_int, rational const& r, bool sign, svector const& exprs) { + expr_ref_vector result(m); + for (auto const& kv : exprs) { + bool sign2 = kv.first; + expr* e = kv.second; + rational r2(r); + if (sign == sign2) { + r2.neg(); + } + if (!r2.is_one()) { + result.push_back(a.mk_mul(a.mk_numeral(r2, is_int), e)); + } + else { + result.push_back(e); + } + } + return a.mk_add_simplify(result); + } + + /** + * \brief return true if lhs = rhs can be solved as v = t, where v is a variable. + */ + bool solve_arith(expr* lhs, expr* rhs, expr_ref& v, expr_ref& t) { + if (!a.is_int(lhs) && !a.is_real(rhs)) { + return false; + } + rational a_val; + bool is_int = a.is_int(lhs); + svector todo, done; + todo.push_back(std::make_pair(true, lhs)); + todo.push_back(std::make_pair(false, rhs)); + while (!todo.empty()) { + expr* e = todo.back().second; + bool sign = todo.back().first; + todo.pop_back(); + if (a.is_add(e)) { + for (expr* e : *to_app(e)) { + todo.push_back(std::make_pair(sign, e)); + } + } + else if (is_invertible_mul(is_int, e, a_val)) { + done.append(todo); + v = e; + a_val = rational(1)/a_val; + t = mk_term(is_int, a_val, sign, done); + TRACE("qe", tout << mk_pp(lhs, m) << " " << mk_pp(rhs, m) << " " << e << " := " << t << "\n";); + return true; + } + else { + done.push_back(std::make_pair(sign, e)); + } + } + return false; + } + + // can we solve for a variable by ... + bool is_invertible_const(bool is_int, expr* x, rational& a_val) { + expr* y; + if (a.is_uminus(x, y) && is_invertible_const(is_int, y, a_val)) { + a_val.neg(); + return true; + } + else if (a.is_numeral(x, a_val) && !a_val.is_zero()) { + if (!is_int || a_val.is_one() || a_val.is_minus_one()) { + return true; + } + } + return false; + } + + bool is_invertible_mul(bool is_int, expr*& arg, rational& a_val) { + if (is_variable(arg)) { + a_val = rational(1); + return true; + } + expr* x, *y; + if (a.is_mul(arg, x, y)) { + if (is_variable(x) && is_invertible_const(is_int, y, a_val)) { + arg = x; + return true; + } + if (is_variable(y) && is_invertible_const(is_int, x, a_val)) { + arg = y; + return true; + } + } + return false; + } + + + expr_ref mk_eq_core (expr *_e1, expr *_e2) { + expr *e1, *e2; + e1 = _e1; + e2 = _e2; + + if (a.is_zero(e1)) { + std::swap(e1, e2); + } + // y + -1*x == 0 --> y = x + expr *a0 = 0, *a1 = 0, *x = 0; + if (a.is_zero(e2) && a.is_add(e1, a0, a1)) { + if (a.is_times_minus_one(a1, x)) { + e1 = a0; + e2 = x; + } + else if (a.is_times_minus_one(a0, x)) { + e1 = a1; + e2 = x; + } + } + return expr_ref(m.mk_eq(e1, e2), m); + } + + app* mk_le_zero(expr *arg) { + expr *e1, *e2, *e3; + // XXX currently disabled + if (a.is_add(arg, e1, e2)) { + // e1-e2<=0 --> e1<=e2 + if (a.is_times_minus_one(e2, e3)) { + return a.mk_le(e1, e3); + } + // -e1+e2<=0 --> e2<=e1 + else if (a.is_times_minus_one(e1, e3)) { + return a.mk_le(e2, e3); + } + } + return a.mk_le(arg, mk_zero()); + } + + app* mk_ge_zero(expr *arg) { + expr *e1, *e2, *e3; + // XXX currently disabled + if (a.is_add(arg, e1, e2)) { + // e1-e2>=0 --> e1>=e2 + if (a.is_times_minus_one(e2, e3)) { + return a.mk_ge(e1, e3); + } + // -e1+e2>=0 --> e2>=e1 + else if (a.is_times_minus_one(e1, e3)) { + return a.mk_ge(e2, e3); + } + } + return a.mk_ge(arg, mk_zero()); + } + + bool mk_le_core (expr *arg1, expr * arg2, expr_ref &result) { + // t <= -1 ==> t < 0 ==> ! (t >= 0) + rational n; + if (a.is_int (arg1) && a.is_minus_one (arg2)) { + result = m.mk_not (mk_ge_zero (arg1)); + return true; + } + else if (a.is_zero(arg2)) { + result = mk_le_zero(arg1); + return true; + } + else if (a.is_int(arg1) && a.is_numeral(arg2, n) && n < 0) { + // t <= n ==> t < n + 1 ==> ! (t >= n + 1) + result = m.mk_not(a.mk_ge(arg1, a.mk_numeral(n+1, true))); + return true; + } + return false; + } + + expr * mk_zero () { + return a.mk_numeral (rational (0), true); + } + + bool is_one (expr const * n) const { + rational val; + return a.is_numeral (n, val) && val.is_one (); + } + + bool mk_ge_core (expr * arg1, expr * arg2, expr_ref &result) { + // t >= 1 ==> t > 0 ==> ! (t <= 0) + rational n; + if (a.is_int (arg1) && is_one (arg2)) { + result = m.mk_not (mk_le_zero (arg1)); + return true; + } + else if (a.is_zero(arg2)) { + result = mk_ge_zero(arg1); + return true; + } + else if (a.is_int(arg1) && a.is_numeral(arg2, n) && n > 0) { + // t >= n ==> t > n - 1 ==> ! (t <= n - 1) + result = m.mk_not(a.mk_le(arg1, a.mk_numeral(n-1, true))); + return true; + } + return false; + } + + expr_ref solve(expr* lit, bool is_pos) override { + expr *e1, *e2; + + expr_ref res(lit, m); + if (m.is_eq (lit, e1, e2)) { + res = mk_eq_core(e1, e2); + } + else if (a.is_le(lit, e1, e2)) { + mk_le_core(e1, e2, res); + } + else if (a.is_ge(lit, e1, e2)) { + mk_ge_core(e1, e2, res); + } + + // restore negation + if (!is_pos) { + res = mk_not(m, res); + } + return res; + } + }; + + class bv_solve_plugin : public solve_plugin { + public: + bv_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("bv"), is_var) {} + expr_ref solve(expr *atom, bool is_pos) override { + expr_ref res(atom, m); + return is_pos ? res : mk_not(res); + } + }; + + class dt_solve_plugin : public solve_plugin { + public: + dt_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("dt"), is_var) {} + expr_ref solve(expr *atom, bool is_pos) override { + expr_ref res(atom, m); + return is_pos ? res : mk_not(res); + } + }; + + class array_solve_plugin : public solve_plugin { + public: + array_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("array"), is_var) {} + expr_ref solve(expr *atom, bool is_pos) override { + expr_ref res(atom, m); + return is_pos ? res : mk_not(res); + } + }; + + + solve_plugin* mk_arith_solve_plugin(ast_manager& m, is_variable_proc& is_var) { + return alloc(arith_solve_plugin, m, is_var); + } + + solve_plugin* mk_dt_solve_plugin(ast_manager& m, is_variable_proc& is_var) { + return alloc(dt_solve_plugin, m, is_var); + } + + solve_plugin* mk_bv_solve_plugin(ast_manager& m, is_variable_proc& is_var) { + return alloc(bv_solve_plugin, m, is_var); + } + + solve_plugin* mk_array_solve_plugin(ast_manager& m, is_variable_proc& is_var) { + return alloc(array_solve_plugin, m, is_var); + } +} diff --git a/src/qe/qe_solve_plugin.h b/src/qe/qe_solve_plugin.h new file mode 100644 index 000000000..064d3b84d --- /dev/null +++ b/src/qe/qe_solve_plugin.h @@ -0,0 +1,52 @@ +/** +Copyright (c) 2018 Microsoft Corporation + +Module Name: + + qe_solve.h + +Abstract: + + Light-weight variable solving plugin model for qe-lite and term_graph. + +Author: + + Nikolaj Bjorner (nbjorner), Arie Gurfinkel 2018-6-8 + +Revision History: + + +--*/ + +#pragma once + +#include "ast/ast.h" +#include "util/plugin_manager.h" +#include "qe/qe_vartest.h" + +namespace qe { + + class solve_plugin { + protected: + ast_manager& m; + family_id m_id; + is_variable_proc& m_is_var; + + virtual expr_ref solve(expr* atom, bool is_pos) = 0; + bool is_variable(expr* e) const { return m_is_var(e); } + public: + solve_plugin(ast_manager& m, family_id fid, is_variable_proc& is_var) : m(m), m_id(fid), m_is_var(is_var) {} + virtual ~solve_plugin() {} + family_id get_family_id() const { return m_id; } + /// Process (and potentially augment) a literal + expr_ref operator() (expr *lit); + }; + + solve_plugin* mk_arith_solve_plugin(ast_manager& m, is_variable_proc& is_var); + + solve_plugin* mk_dt_solve_plugin(ast_manager& m, is_variable_proc& is_var); + + solve_plugin* mk_bv_solve_plugin(ast_manager& m, is_variable_proc& is_var); + + solve_plugin* mk_array_solve_plugin(ast_manager& m, is_variable_proc& is_var); +} From e226b39914182af59ee6196228f07668bc4f6924 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 15:29:06 -0700 Subject: [PATCH 1190/1283] Remove pragma once from cpp --- src/qe/qe_solve_plugin.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qe/qe_solve_plugin.cpp b/src/qe/qe_solve_plugin.cpp index 7a4dd97f4..bbaf15325 100644 --- a/src/qe/qe_solve_plugin.cpp +++ b/src/qe/qe_solve_plugin.cpp @@ -18,8 +18,6 @@ Revision History: --*/ -#pragma once - #include "ast/arith_decl_plugin.h" #include "ast/ast_util.h" #include "ast/ast_pp.h" From 7714d05c1ab45182f98814918b0766b3dcc9a01a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 18:30:36 -0700 Subject: [PATCH 1191/1283] fill out qe_solve_plugin functionality Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.h | 2 + src/qe/qe_lite.cpp | 169 +++++---------------------------- src/qe/qe_solve_plugin.cpp | 125 +++++++++++++++++++++--- src/qe/qe_solve_plugin.h | 6 +- src/util/plugin_manager.h | 5 + 5 files changed, 144 insertions(+), 163 deletions(-) diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 88b50af82..17602efcf 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -358,8 +358,10 @@ namespace datatype { bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); } bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); } bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); } + bool is_constructor(expr* e) const { return is_app(e) && is_constructor(to_app(e)); } bool is_recognizer0(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER);} bool is_is(app * f) const { return is_app_of(f, m_family_id, OP_DT_IS);} + bool is_is(expr * e) const { return is_app(e) && is_is(to_app(e)); } bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); } bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index c027d2d07..3b8d41316 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -36,6 +36,7 @@ Revision History: #include "ast/datatype_decl_plugin.h" #include "qe/qe_vartest.h" +#include "qe/qe_solve_plugin.h" namespace eq { @@ -72,6 +73,7 @@ namespace eq { beta_reducer m_subst; expr_ref_vector m_subst_map; expr_ref_vector m_new_exprs; + plugin_manager m_solvers; ptr_vector m_map; int_vector m_pos2var; @@ -221,97 +223,6 @@ namespace eq { } } - bool is_invertible_const(bool is_int, expr* x, rational& a_val) { - expr* y; - if (a.is_uminus(x, y) && is_invertible_const(is_int, y, a_val)) { - a_val.neg(); - return true; - } - else if (a.is_numeral(x, a_val) && !a_val.is_zero()) { - if (!is_int || a_val.is_one() || a_val.is_minus_one()) { - return true; - } - } - return false; - } - - bool is_invertible_mul(bool is_int, expr*& arg, rational& a_val) { - if (is_variable(arg)) { - a_val = rational(1); - return true; - } - expr* x, *y; - if (a.is_mul(arg, x, y)) { - if (is_variable(x) && is_invertible_const(is_int, y, a_val)) { - arg = x; - return true; - } - if (is_variable(y) && is_invertible_const(is_int, x, a_val)) { - arg = y; - return true; - } - } - return false; - } - - typedef std::pair signed_expr; - - expr_ref solve_arith(bool is_int, rational const& r, bool sign, svector const& exprs) { - expr_ref_vector result(m); - for (unsigned i = 0; i < exprs.size(); ++i) { - bool sign2 = exprs[i].first; - expr* e = exprs[i].second; - rational r2(r); - if (sign == sign2) { - r2.neg(); - } - if (!r2.is_one()) { - result.push_back(a.mk_mul(a.mk_numeral(r2, is_int), e)); - } - else { - result.push_back(e); - } - } - return expr_ref(a.mk_add(result.size(), result.c_ptr()), m); - } - - bool solve_arith(expr* lhs, expr* rhs, ptr_vector& vs, expr_ref_vector& ts) { - if (!a.is_int(lhs) && !a.is_real(rhs)) { - return false; - } - rational a_val; - bool is_int = a.is_int(lhs); - svector todo, done; - todo.push_back(std::make_pair(true, lhs)); - todo.push_back(std::make_pair(false, rhs)); - while (!todo.empty()) { - expr* e = todo.back().second; - bool sign = todo.back().first; - todo.pop_back(); - if (a.is_add(e)) { - for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { - todo.push_back(std::make_pair(sign, to_app(e)->get_arg(i))); - } - } - else if (is_invertible_mul(is_int, e, a_val)) { - done.append(todo); - vs.push_back(to_var(e)); - a_val = rational(1)/a_val; - ts.push_back(solve_arith(is_int, a_val, sign, done)); - TRACE("qe_lite", tout << mk_pp(lhs, m) << " " << mk_pp(rhs, m) << " " << mk_pp(e, m) << " := " << mk_pp(ts.back(), m) << "\n";); - return true; - } - else { - done.push_back(std::make_pair(sign, e)); - } - } - return false; - } - - bool arith_solve(expr * lhs, expr * rhs, expr * eq, ptr_vector& vs, expr_ref_vector& ts) { - return solve_arith(lhs, rhs, vs, ts); - } - bool trivial_solve(expr* lhs, expr* rhs, expr* eq, ptr_vector& vs, expr_ref_vector& ts) { if (!is_variable(lhs)) { std::swap(lhs, rhs); @@ -343,65 +254,25 @@ namespace eq { */ bool is_var_eq(expr * e, ptr_vector& vs, expr_ref_vector & ts) { - expr* lhs, *rhs; - var* v; + expr* lhs = nullptr, *rhs = nullptr; // (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases + if (m.is_eq(e, lhs, rhs) && trivial_solve(lhs, rhs, e, vs, ts)) { + return true; + } + family_id fid = get_sort(e)->get_family_id(); if (m.is_eq(e, lhs, rhs)) { - // (iff (not VAR) t) (iff t (not VAR)) cases - if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) { - if (!is_neg_var(m, lhs, v)) { - std::swap(lhs, rhs); - } - if (!is_neg_var(m, lhs, v)) { - return false; - } - vs.push_back(v); - ts.push_back(m.mk_not(rhs)); - TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); + fid = get_sort(lhs)->get_family_id(); + } + qe::solve_plugin* p = m_solvers.get_plugin(fid); + if (p) { + expr_ref res = (*p)(e); + if (res != e && m.is_eq(res, lhs, rhs) && is_variable(lhs)) { + vs.push_back(to_var(lhs)); + ts.push_back(rhs); return true; } - if (trivial_solve(lhs, rhs, e, vs, ts)) { - return true; - } - if (arith_solve(lhs, rhs, e, vs, ts)) { - return true; - } - return false; } - - // (ite cond (= VAR t) (= VAR t2)) case - expr* cond, *e2, *e3; - if (m.is_ite(e, cond, e2, e3)) { - if (is_var_eq(e2, vs, ts)) { - expr_ref_vector ts2(m); - ptr_vector vs2; - if (is_var_eq(e3, vs2, ts2) && same_vars(vs, vs2)) { - for (unsigned i = 0; i < vs.size(); ++i) { - ts[i] = m.mk_ite(cond, ts[i].get(), ts2[i].get()); - } - return true; - } - } - return false; - } - - // VAR = true case - if (is_variable(e)) { - ts.push_back(m.mk_true()); - vs.push_back(to_var(e)); - TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); - return true; - } - - // VAR = false case - if (is_neg_var(m, e, v)) { - ts.push_back(m.mk_false()); - vs.push_back(v); - TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); - return true; - } - return false; } @@ -785,9 +656,15 @@ namespace eq { m_new_exprs(m), m_new_args(m), m_rewriter(m), - m_params(p) {} + m_params(p) { + } - void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;} + void set_is_variable_proc(is_variable_proc& proc) { + m_is_variable = &proc; + m_solvers.reset(); + m_solvers.register_plugin(qe::mk_arith_solve_plugin(m, proc)); + m_solvers.register_plugin(qe::mk_basic_solve_plugin(m, proc)); + } void operator()(quantifier * q, expr_ref & r, proof_ref & pr) { TRACE("qe_lite", tout << mk_pp(q, m) << "\n";); diff --git a/src/qe/qe_solve_plugin.cpp b/src/qe/qe_solve_plugin.cpp index bbaf15325..ad4a03b5d 100644 --- a/src/qe/qe_solve_plugin.cpp +++ b/src/qe/qe_solve_plugin.cpp @@ -19,6 +19,7 @@ Revision History: --*/ #include "ast/arith_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" #include "ast/ast_util.h" #include "ast/ast_pp.h" #include "qe/qe_solve_plugin.h" @@ -65,7 +66,7 @@ namespace qe { /** * \brief return true if lhs = rhs can be solved as v = t, where v is a variable. */ - bool solve_arith(expr* lhs, expr* rhs, expr_ref& v, expr_ref& t) { + bool solve(expr* lhs, expr* rhs, expr_ref& v, expr_ref& t) { if (!a.is_int(lhs) && !a.is_real(rhs)) { return false; } @@ -83,6 +84,16 @@ namespace qe { todo.push_back(std::make_pair(sign, e)); } } + else if (a.is_sub(e)) { + app* sub = to_app(e); + todo.push_back(std::make_pair(sign, sub->get_arg(0))); + for (unsigned i = 1; i < sub->get_num_args(); ++i) { + todo.push_back(std::make_pair(!sign, sub->get_arg(i))); + } + } + else if (a.is_uminus(e)) { + todo.push_back(std::make_pair(!sign, to_app(e)->get_arg(0))); + } else if (is_invertible_mul(is_int, e, a_val)) { done.append(todo); v = e; @@ -98,7 +109,7 @@ namespace qe { return false; } - // can we solve for a variable by ... + // is x a constant and can we safely divide by x to solve for a variable? bool is_invertible_const(bool is_int, expr* x, rational& a_val) { expr* y; if (a.is_uminus(x, y) && is_invertible_const(is_int, y, a_val)) { @@ -113,6 +124,8 @@ namespace qe { return false; } + // is arg of the form a_val * v, where a_val + // is a constant that we can safely divide by. bool is_invertible_mul(bool is_int, expr*& arg, rational& a_val) { if (is_variable(arg)) { a_val = rational(1); @@ -133,10 +146,11 @@ namespace qe { } - expr_ref mk_eq_core (expr *_e1, expr *_e2) { - expr *e1, *e2; - e1 = _e1; - e2 = _e2; + expr_ref mk_eq_core (expr *e1, expr *e2) { + expr_ref v(m), t(m); + if (solve(e1, e2, v, t)) { + return expr_ref(m.mk_eq(v, t), m); + } if (a.is_zero(e1)) { std::swap(e1, e2); @@ -257,6 +271,90 @@ namespace qe { } }; + class basic_solve_plugin : public solve_plugin { + public: + basic_solve_plugin(ast_manager& m, is_variable_proc& is_var): + solve_plugin(m, m.get_basic_family_id(), is_var) {} + + expr_ref solve(expr *atom, bool is_pos) override { + expr_ref res(atom, m); + expr* lhs = nullptr, *rhs = nullptr, *n = nullptr; + if (m.is_eq(atom, lhs, rhs)) { + if (m.is_not(lhs, n) && is_variable(n)) { + res = m.mk_eq(n, mk_not(m, rhs)); + } + else if (m.is_not(rhs, n) && is_variable(n)) { + res = m.mk_eq(n, mk_not(m, lhs)); + } + else if (is_variable(rhs) && !is_variable(lhs)) { + res = m.mk_eq(rhs, lhs); + } + } + // (ite cond (= VAR t) (= VAR t2)) case + expr* cond = nullptr, *th = nullptr, *el = nullptr; + if (m.is_ite(atom, cond, th, el)) { + expr_ref r1 = solve(th, true); + expr_ref r2 = solve(el, true); + expr* v1 = nullptr, *t1 = nullptr, *v2 = nullptr, *t2 = nullptr; + if (m.is_eq(r1, v1, t1) && m.is_eq(r2, v2, t2) && v1 == v2) { + res = m.mk_eq(v1, m.mk_ite(cond, t1, t2)); + } + } + + if (is_variable(atom) && m.is_bool(atom)) { + res = m.mk_eq(atom, m.mk_bool_val(is_pos)); + return res; + } + + return is_pos ? res : mk_not(res); + } + }; + + class dt_solve_plugin : public solve_plugin { + datatype_util dt; + public: + dt_solve_plugin(ast_manager& m, is_variable_proc& is_var): + solve_plugin(m, m.get_family_id("datatype"), is_var), + dt(m) {} + + expr_ref solve(expr *atom, bool is_pos) override { + expr_ref res(atom, m); + expr* lhs = nullptr, *rhs = nullptr; + if (m.is_eq(atom, lhs, rhs)) { + if (dt.is_constructor(rhs)) { + std::swap(lhs, rhs); + } + if (dt.is_constructor(lhs) && dt.is_constructor(rhs)) { + app* l = to_app(lhs), *r = to_app(rhs); + if (l->get_decl() == r->get_decl()) { + expr_ref_vector eqs(m); + for (unsigned i = 0, sz = l->get_num_args(); i < sz; ++i) { + eqs.push_back(m.mk_eq(l->get_arg(i), r->get_arg(i))); + } + res = mk_and(eqs); + } + else { + res = m.mk_false(); + } + } + else if (dt.is_constructor(lhs)) { + app* l = to_app(lhs); + func_decl* d = l->get_decl(); + expr_ref_vector conjs(m); + conjs.push_back(dt.mk_is(d, rhs)); + ptr_vector const& acc = *dt.get_constructor_accessors(d); + for (unsigned i = 0; i < acc.size(); ++i) { + conjs.push_back(m.mk_eq(l->get_arg(i), m.mk_app(acc[i], rhs))); + } + res = mk_and(conjs); + } + } + // TBD: can also solve for is_nil(x) by x = nil + // + return is_pos ? res : mk_not(res); + } + }; + class bv_solve_plugin : public solve_plugin { public: bv_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("bv"), is_var) {} @@ -266,15 +364,6 @@ namespace qe { } }; - class dt_solve_plugin : public solve_plugin { - public: - dt_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("dt"), is_var) {} - expr_ref solve(expr *atom, bool is_pos) override { - expr_ref res(atom, m); - return is_pos ? res : mk_not(res); - } - }; - class array_solve_plugin : public solve_plugin { public: array_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("array"), is_var) {} @@ -284,6 +373,9 @@ namespace qe { } }; + solve_plugin* mk_basic_solve_plugin(ast_manager& m, is_variable_proc& is_var) { + return alloc(basic_solve_plugin, m, is_var); + } solve_plugin* mk_arith_solve_plugin(ast_manager& m, is_variable_proc& is_var) { return alloc(arith_solve_plugin, m, is_var); @@ -293,6 +385,7 @@ namespace qe { return alloc(dt_solve_plugin, m, is_var); } +#if 0 solve_plugin* mk_bv_solve_plugin(ast_manager& m, is_variable_proc& is_var) { return alloc(bv_solve_plugin, m, is_var); } @@ -300,4 +393,6 @@ namespace qe { solve_plugin* mk_array_solve_plugin(ast_manager& m, is_variable_proc& is_var) { return alloc(array_solve_plugin, m, is_var); } +#endif + } diff --git a/src/qe/qe_solve_plugin.h b/src/qe/qe_solve_plugin.h index 064d3b84d..571d568f1 100644 --- a/src/qe/qe_solve_plugin.h +++ b/src/qe/qe_solve_plugin.h @@ -42,11 +42,13 @@ namespace qe { expr_ref operator() (expr *lit); }; + solve_plugin* mk_basic_solve_plugin(ast_manager& m, is_variable_proc& is_var); + solve_plugin* mk_arith_solve_plugin(ast_manager& m, is_variable_proc& is_var); solve_plugin* mk_dt_solve_plugin(ast_manager& m, is_variable_proc& is_var); - solve_plugin* mk_bv_solve_plugin(ast_manager& m, is_variable_proc& is_var); + // solve_plugin* mk_bv_solve_plugin(ast_manager& m, is_variable_proc& is_var); - solve_plugin* mk_array_solve_plugin(ast_manager& m, is_variable_proc& is_var); + // solve_plugin* mk_array_solve_plugin(ast_manager& m, is_variable_proc& is_var); } diff --git a/src/util/plugin_manager.h b/src/util/plugin_manager.h index c8908fd57..2c4223eeb 100644 --- a/src/util/plugin_manager.h +++ b/src/util/plugin_manager.h @@ -27,7 +27,12 @@ class plugin_manager { ptr_vector m_plugins; public: ~plugin_manager() { + reset(); + } + + void reset() { std::for_each(m_plugins.begin(), m_plugins.end(), delete_proc()); + release(); } /** From 771d3b1349a255e2653023cfccf3a862f81d868d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 17:38:14 -0700 Subject: [PATCH 1192/1283] wip: term_graph::project and term_graph::solve --- src/qe/qe_term_graph.cpp | 134 ++++++++++++++++++++++++++++++++------- src/qe/qe_term_graph.h | 43 +++++++------ 2 files changed, 136 insertions(+), 41 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 4101d6d56..eccb7669f 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -22,6 +22,7 @@ Notes: #include "ast/ast_pp.h" #include "ast/ast_util.h" #include "ast/for_each_expr.h" +#include "ast/occurs.h" #include "qe/qe_term_graph.h" namespace qe { @@ -64,9 +65,9 @@ namespace qe { m_children.push_back(t); } } - + ~term() {} - + class parents { term const& t; public: @@ -167,9 +168,9 @@ namespace qe { arith_term_graph_plugin(term_graph &g) : term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} - + virtual ~arith_term_graph_plugin() {} - + bool mk_eq_core (expr *_e1, expr *_e2, expr_ref &res) { expr *e1, *e2; e1 = _e1; @@ -384,7 +385,7 @@ namespace qe { SASSERT(res); return res; } - + void term_graph::internalize_eq(expr *a1, expr* a2) { SASSERT(m_merge.empty()); merge(*internalize_term(a1), *internalize_term(a2)); @@ -414,17 +415,17 @@ namespace qe { void term_graph::merge(term &t1, term &t2) { // -- merge might invalidate term2app cache m_term2app.reset(); - m_pinned.reset(); - + m_pinned.reset(); + term *a = &t1.get_root(); term *b = &t2.get_root(); - + if (a == b) return; - + if (a->get_class_size() > b->get_class_size()) { std::swap(a, b); } - + // Remove parents of it from the cg table. for (term* p : term::parents(b)) { if (!p->is_marked()) { @@ -630,7 +631,9 @@ namespace qe { return result; } - expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { + void term_graph::project_core(func_decl_ref_vector const& decls, + bool exclude, + expr_ref_vector &result) { u_map _decls; for (func_decl* f : decls) _decls.insert(f->get_id(), true); // - propagate representatives up over parents. @@ -639,10 +642,6 @@ namespace qe { // - produce other literals over represented classes // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) - expr_ref_vector result(m); - m_term2app.reset(); - m_pinned.reset(); - obj_hashtable eqs; expr_ref eq(m); ptr_vector worklist; @@ -666,7 +665,7 @@ namespace qe { if (!pure) continue; // ensure that the root has a representative - // either by looking up cached version, + // either by looking up cached version, // computing it for the first time, or // inheriting pure. expr* rep = nullptr; @@ -682,7 +681,10 @@ namespace qe { } bool update_rep = false; - // Add equations between pure and rep, + // AG: can rep be null at this point? + // AG: why mk_pure(root) is guaranteed to return non-null? + + // Add equations between pure and rep, // optionally swap the roles of rep and pure if // pure makes a better representative. if (rep != pure) { @@ -697,7 +699,7 @@ namespace qe { } } - // update the worklist if this is the first + // update the worklist if this is the first // representative or pure was swapped into rep. if (!has_rep || update_rep) { for (term * p : term::parents(root)) { @@ -709,19 +711,107 @@ namespace qe { } } } + // Here we could also walk equivalence classes that contain interpreted values by sort and + // extract disequalities bewteen non-unique value representatives. + // these disequalities are implied and can be mined using other means, such as + // theory aware core minimization + reset_marks(); + } + + expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { + expr_ref_vector result(m); + m_term2app.reset(); + m_pinned.reset(); + project_core(decls, exclude, result); // walk other predicates than equalities for (expr* e : m_lits) { if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { result.push_back(e); } } - // Here we could also walk equivalence classes that contain interpreted values by sort and - // extract disequalities bewteen non-unique value representatives. - // these disequalities are implied and can be mined using other means, such as - // theory aware core minimization + m_term2app.reset(); m_pinned.reset(); + return result; + } + + bool term_graph::is_solved_eq(expr *_lhs, expr* _rhs) { + if (!is_app(_lhs) || !is_app(_rhs)) return false; + app *lhs, *rhs; + lhs = ::to_app(_lhs); + rhs = ::to_app(_rhs); + + if (rhs->get_num_args() > 0) return false; + if (rhs->get_family_id() != null_family_id) return false; + + return !occurs(rhs, lhs); + } + void term_graph::solve_core(func_decl_ref_vector const &decls, bool exclude, + expr_ref_vector &result) { + u_map _decls; + for (func_decl* f : decls) _decls.insert(f->get_id(), true); + obj_hashtable eqs; + expr_ref eq(m); + ptr_vector worklist; + for (term * t : m_terms) { + worklist.push_back(t); + t->set_mark(true); + } + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) + continue; + term &root = t->get_root(); + bool has_rep = m_term2app.contains(root.get_id()); + expr *pure = mk_pure(*t); + if (!pure) continue; + + if (has_rep) { + // add equality if needed + expr* rep = m_term2app.find(root.get_id()); + if (exclude != _decls.contains(t->get_decl_id()) || !is_solved_eq(rep, pure)) { + eq = m.mk_eq(rep, pure); + if (!eqs.contains(eq)) { + eqs.insert(eq); + result.push_back(eq); + } + } + } + else { + // let pure be the representative + m_term2app.insert(root.get_id(), pure); + // schedule parents of root to be processed again + for (term * p : term::parents(root)) { + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); + } + } + SASSERT(false); + // TBD: deal with root + } + } + reset_marks(); + } + + + expr_ref_vector term_graph::solve(func_decl_ref_vector const &decls, bool exclude) { + expr_ref_vector result(m); + m_term2app.reset(); + m_pinned.reset(); + project_core(decls, exclude, result); + solve_core(decls, exclude, result); + // walk other predicates than equalities + for (expr* e : m_lits) { + if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { + result.push_back(e); + } + } + m_term2app.reset(); + m_pinned.reset(); return result; } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index fbb2ceb16..f3564f0e9 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -33,11 +33,11 @@ namespace qe { virtual ~term_graph_plugin() {} family_id get_family_id() const {return m_id;} - + /// Process (and potentially augment) a literal virtual expr_ref process_lit (expr *lit) = 0; }; - + class term_graph { struct term_hash { unsigned operator()(term const* t) const; }; @@ -45,62 +45,67 @@ namespace qe { ast_manager & m; ptr_vector m_terms; expr_ref_vector m_lits; // NSB: expr_ref_vector? - u_map m_app2term; + u_map m_app2term; ast_ref_vector m_pinned; u_map m_term2app; plugin_manager m_plugins; ptr_hashtable m_cg_table; vector> m_merge; - + void merge(term &t1, term &t2); void merge_flush(); - + term *mk_term(expr *t); term *get_term(expr *t); - + term *internalize_term(expr *t); void internalize_eq(expr *a1, expr *a2); void internalize_lit(expr *lit); - + bool is_internalized(expr *a); - + bool term_lt(term const &t1, term const &t2); void pick_root (term &t); void pick_roots(); - + void reset_marks(); - + expr* mk_app_core(expr* a); expr_ref mk_app(term const &t); expr* mk_pure(term& t); expr_ref mk_app(expr *a); void mk_equalities(term const &t, expr_ref_vector &out); void mk_all_equalities(term const &t, expr_ref_vector &out); - void display(std::ostream &out); + void display(std::ostream &out); + void project_core(func_decl_ref_vector const &decls, bool exclude, expr_ref_vector &result); + void solve_core(func_decl_ref_vector const &decls, bool exclude, expr_ref_vector &result); + bool is_solved_eq(expr *lhs, expr *rhs); public: term_graph(ast_manager &m); ~term_graph(); - + ast_manager& get_ast_manager() const { return m;} - - void add_lit(expr *lit); + + void add_lit(expr *lit); void add_lits(expr_ref_vector const &lits) { for (expr* e : lits) add_lit(e); } void add_eq(expr* a, expr* b) { internalize_eq(a, b); } - + void reset(); // deprecate? void to_lits(expr_ref_vector &lits, bool all_equalities = false); - expr_ref to_app(); + expr_ref to_app(); /** - * Return literals obtained by projecting added literals - * onto the vocabulary of decls (if exclude is false) or outside the + * Return literals obtained by projecting added literals + * onto the vocabulary of decls (if exclude is false) or outside the * vocabulary of decls (if exclude is true). */ expr_ref_vector project(func_decl_ref_vector const& decls, bool exclude); - + expr_ref_vector solve(func_decl_ref_vector const& decls, bool exclude); + + }; } From 144d8df5d5476f10df68d2a2d7bbfeb11bea4a0d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 21:16:49 -0700 Subject: [PATCH 1193/1283] Rewrite term_graph::project and term_graph::solve --- src/qe/qe_term_graph.cpp | 407 +++++++++++++++++++++------------------ src/qe/qe_term_graph.h | 3 + 2 files changed, 226 insertions(+), 184 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index eccb7669f..2dc9bd739 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -614,205 +614,244 @@ namespace qe { m_cg_table.reset(); } - expr* term_graph::mk_pure(term& t) { - expr* e = nullptr; - if (m_term2app.find(t.get_id(), e)) return e; - e = t.get_expr(); - if (!is_app(e)) return nullptr; - app* a = ::to_app(e); - expr_ref_vector kids(m); - for (term* ch : term::children(t)) { - if (!m_term2app.find(ch->get_root().get_id(), e)) return nullptr; - kids.push_back(e); - } - expr* result = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); - m_pinned.push_back(result); - m_term2app.insert(t.get_id(), result); - return result; - } + namespace { + class projector { + term_graph &m_tg; + ast_manager &m; + u_map m_term2app; + u_map m_root2rep; + u_map m_decls; + bool m_exclude; - void term_graph::project_core(func_decl_ref_vector const& decls, - bool exclude, - expr_ref_vector &result) { - u_map _decls; - for (func_decl* f : decls) _decls.insert(f->get_id(), true); - // - propagate representatives up over parents. - // use work-list + marking to propagate. - // - produce equalities over represented classes. - // - produce other literals over represented classes - // (walk disequalities in m_lits and represent lhs/rhs over decls or excluding decls) + expr_ref_vector m_pinned; // tracks expr in the maps - obj_hashtable eqs; - expr_ref eq(m); - ptr_vector worklist; - for (term * t : m_terms) { - worklist.push_back(t); - t->set_mark(true); - } - - while (!worklist.empty()) { - term* t = worklist.back(); - worklist.pop_back(); - t->set_mark(false); - if (m_term2app.contains(t->get_id())) - continue; - if (!t->is_theory() && exclude == _decls.contains(t->get_decl_id())) - continue; - - term& root = t->get_root(); - bool has_rep = m_term2app.contains(root.get_id()); - expr* pure = mk_pure(*t); - if (!pure) continue; - - // ensure that the root has a representative - // either by looking up cached version, - // computing it for the first time, or - // inheriting pure. - expr* rep = nullptr; - if (root.is_theory() || exclude != _decls.contains(root.get_decl_id())) { - rep = mk_pure(root); - } - else if (has_rep) { - rep = m_term2app.find(root.get_id()); - } - else { - rep = pure; - m_term2app.insert(root.get_id(), pure); - } - bool update_rep = false; - - // AG: can rep be null at this point? - // AG: why mk_pure(root) is guaranteed to return non-null? - - // Add equations between pure and rep, - // optionally swap the roles of rep and pure if - // pure makes a better representative. - if (rep != pure) { - if (m.is_unique_value(rep) && !m.is_unique_value(pure)) { - m_term2app.insert(root.get_id(), pure); - update_rep = true; + expr* mk_pure(term& t) { + expr* e = nullptr; + if (m_term2app.find(t.get_id(), e)) return e; + e = t.get_expr(); + if (!is_app(e)) return nullptr; + app* a = ::to_app(e); + expr_ref_buffer kids(m); + for (term* ch : term::children(t)) { + if (!m_root2rep.find(ch->get_root().get_id(), e)) return nullptr; + kids.push_back(e); } - eq = m.mk_eq(rep, pure); - if (!eqs.contains(eq)) { - eqs.insert(eq); - result.push_back(eq); + expr* pure = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); + m_pinned.push_back(pure); + m_term2app.insert(t.get_id(), pure); + return pure; + } + + bool is_better_rep(expr *t1, expr *t2) { + if (!t2) return t1; + return m.is_unique_value(t1) && !m.is_unique_value(t2); + } + + void purify() { + // - propagate representatives up over parents. + // use work-list + marking to propagate. + // - produce equalities over represented classes. + // - produce other literals over represented classes + // (walk disequalities in m_lits and represent + // lhs/rhs over decls or excluding decls) + + ptr_vector worklist; + for (term * t : m_tg.m_terms) { + worklist.push_back(t); + t->set_mark(true); + } + + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) + continue; + if (!t->is_theory() && is_projected(*t)) + continue; + + expr* pure = mk_pure(*t); + if (!pure) continue; + + m_term2app.insert(t->get_id(), pure); + expr* rep = nullptr; + // ensure that the root has a representative + m_root2rep.find(t->get_root().get_id(), rep); + + // update rep with pure if it is better + if (pure != rep && is_better_rep(pure, rep)) { + m_root2rep.insert(t->get_root().get_id(), pure); + for (term * p : term::parents(t->get_root())) { + m_term2app.remove(p->get_id()); + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); + } + } + } + } + + // Here we could also walk equivalence classes that + // contain interpreted values by sort and extract + // disequalities bewteen non-unique value + // representatives. these disequalities are implied + // and can be mined using other means, such as theory + // aware core minimization + m_tg.reset_marks(); + } + + void solve() { + ptr_vector worklist; + for (term * t : m_tg.m_terms) { + // skip pure terms + if (m_term2app.contains(t->get_id())) continue; + worklist.push_back(t); + t->set_mark(true); + } + + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) + continue; + + expr* pure = mk_pure(*t); + if (!pure) continue; + + m_term2app.insert(t->get_id(), pure); + expr* rep = nullptr; + // ensure that the root has a representative + m_root2rep.find(t->get_root().get_id(), rep); + + if (!rep) { + m_root2rep.insert(t->get_root().get_id(), pure); + for (term * p : term::parents(t->get_root())) { + SASSERT(!m_term2app.contains(p->get_id())); + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); + } + } + } + } + m_tg.reset_marks(); + } + + bool find_app(term &t, expr *&res) { + return m_root2rep.find(t.get_root().get_id(), res); + } + + bool find_app(expr *lit, expr *&res) { + return m_root2rep.find(m_tg.get_term(lit)->get_root().get_id(), res); + } + + void mk_lits(expr_ref_vector &res) { + expr *e = nullptr; + for (auto *lit : m_tg.m_lits) { + if (!m.is_eq(lit) && find_app(lit, e)) + res.push_back(e); } } - // update the worklist if this is the first - // representative or pure was swapped into rep. - if (!has_rep || update_rep) { - for (term * p : term::parents(root)) { - if (update_rep) m_term2app.remove(p->get_id()); - if (!p->is_marked()) { - p->set_mark(true); - worklist.push_back(p); + void mk_pure_equalities(const term &t, expr_ref_vector &res) { + expr *rep = nullptr; + if (!m_root2rep.find(t.get_id(), rep)) return; + for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { + expr* member = mk_pure(*it); + if (member) + res.push_back (m.mk_eq (rep, member)); + } + } + + bool is_projected(const term &t) { + return m_exclude == m_decls.contains(t.get_decl_id()); + } + + void mk_unpure_equalities(const term &t, expr_ref_vector &res) { + expr *rep = nullptr; + if (!m_root2rep.find(t.get_id(), rep)) return; + for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { + expr* member = mk_pure(*it); + SASSERT(member); + if (!is_projected(*it) || !is_solved_eq(rep, member)) { + res.push_back(m.mk_eq(rep, member)); } } } - } - // Here we could also walk equivalence classes that contain interpreted values by sort and - // extract disequalities bewteen non-unique value representatives. - // these disequalities are implied and can be mined using other means, such as - // theory aware core minimization - reset_marks(); + + void mk_equalities(bool pure, expr_ref_vector &res) { + for (term *t : m_tg.m_terms) { + if (!t->is_root()) continue; + if (!m_root2rep.contains(t->get_id())) continue; + if (pure) + mk_pure_equalities(*t, res); + else + mk_unpure_equalities(*t, res); + } + } + + void mk_pure_equalities(expr_ref_vector &res) { + return mk_equalities(true, res); + } + + void mk_unpure_equalities(expr_ref_vector &res) { + return mk_equalities(false, res); + } + + bool is_solved_eq(expr *_lhs, expr* _rhs) { + if (!is_app(_lhs) || !is_app(_rhs)) return false; + app *lhs, *rhs; + lhs = ::to_app(_lhs); + rhs = ::to_app(_rhs); + + if (rhs->get_num_args() > 0) return false; + if (rhs->get_family_id() != null_family_id) return false; + + return !occurs(rhs, lhs); + } + + public: + projector(term_graph &tg) : m_tg(tg), m(m_tg.m), m_pinned(m) {} + + void reset() { + m_tg.reset_marks(); + m_term2app.reset(); + m_root2rep.reset(); + m_decls.reset(); + m_pinned.reset(); + } + expr_ref_vector project(func_decl_ref_vector const &decls, bool exclude) { + expr_ref_vector res(m); + m_exclude = exclude; + for (auto *d : decls) {m_decls.insert(d->get_id(), true);} + purify(); + mk_lits(res); + mk_pure_equalities(res); + reset(); + return res; + } + expr_ref_vector solve(func_decl_ref_vector const &decls, bool exclude) { + expr_ref_vector res(m); + m_exclude = exclude; + purify(); + solve(); + mk_lits(res); + mk_unpure_equalities(res); + reset(); + return res; + } + }; } expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { - expr_ref_vector result(m); - m_term2app.reset(); - m_pinned.reset(); - project_core(decls, exclude, result); - // walk other predicates than equalities - for (expr* e : m_lits) { - if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { - result.push_back(e); - } - } - - m_term2app.reset(); - m_pinned.reset(); - return result; + projector p(*this); + return p.project(decls, exclude); } - bool term_graph::is_solved_eq(expr *_lhs, expr* _rhs) { - if (!is_app(_lhs) || !is_app(_rhs)) return false; - app *lhs, *rhs; - lhs = ::to_app(_lhs); - rhs = ::to_app(_rhs); - - if (rhs->get_num_args() > 0) return false; - if (rhs->get_family_id() != null_family_id) return false; - - return !occurs(rhs, lhs); - } - void term_graph::solve_core(func_decl_ref_vector const &decls, bool exclude, - expr_ref_vector &result) { - u_map _decls; - for (func_decl* f : decls) _decls.insert(f->get_id(), true); - obj_hashtable eqs; - expr_ref eq(m); - ptr_vector worklist; - for (term * t : m_terms) { - worklist.push_back(t); - t->set_mark(true); - } - while (!worklist.empty()) { - term* t = worklist.back(); - worklist.pop_back(); - t->set_mark(false); - if (m_term2app.contains(t->get_id())) - continue; - term &root = t->get_root(); - bool has_rep = m_term2app.contains(root.get_id()); - expr *pure = mk_pure(*t); - if (!pure) continue; - - if (has_rep) { - // add equality if needed - expr* rep = m_term2app.find(root.get_id()); - if (exclude != _decls.contains(t->get_decl_id()) || !is_solved_eq(rep, pure)) { - eq = m.mk_eq(rep, pure); - if (!eqs.contains(eq)) { - eqs.insert(eq); - result.push_back(eq); - } - } - } - else { - // let pure be the representative - m_term2app.insert(root.get_id(), pure); - // schedule parents of root to be processed again - for (term * p : term::parents(root)) { - if (!p->is_marked()) { - p->set_mark(true); - worklist.push_back(p); - } - } - SASSERT(false); - // TBD: deal with root - } - } - - reset_marks(); - } - - expr_ref_vector term_graph::solve(func_decl_ref_vector const &decls, bool exclude) { - expr_ref_vector result(m); - m_term2app.reset(); - m_pinned.reset(); - project_core(decls, exclude, result); - solve_core(decls, exclude, result); - // walk other predicates than equalities - for (expr* e : m_lits) { - if (!m.is_eq(e) && m_term2app.find(get_term(e)->get_root().get_id(), e)) { - result.push_back(e); - } - } - m_term2app.reset(); - m_pinned.reset(); - return result; + projector p(*this); + return p.solve(decls, exclude); } } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index f3564f0e9..210941dac 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -26,6 +26,8 @@ namespace qe { class term; + namespace {class projector;} + class term_graph_plugin { family_id m_id; public: @@ -40,6 +42,7 @@ namespace qe { class term_graph { + friend class projector; struct term_hash { unsigned operator()(term const* t) const; }; struct term_eq { bool operator()(term const* a, term const* b) const; }; ast_manager & m; From e0aaf4452bfaaa445b6e4fbd78f7bd60481b2f1c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 17:38:14 -0700 Subject: [PATCH 1194/1283] wip: term_graph::project and term_graph::solve --- src/qe/qe_term_graph.cpp | 120 +++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 2dc9bd739..40f3998e7 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -65,9 +65,9 @@ namespace qe { m_children.push_back(t); } } - + ~term() {} - + class parents { term const& t; public: @@ -168,9 +168,9 @@ namespace qe { arith_term_graph_plugin(term_graph &g) : term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} - + virtual ~arith_term_graph_plugin() {} - + bool mk_eq_core (expr *_e1, expr *_e2, expr_ref &res) { expr *e1, *e2; e1 = _e1; @@ -385,7 +385,7 @@ namespace qe { SASSERT(res); return res; } - + void term_graph::internalize_eq(expr *a1, expr* a2) { SASSERT(m_merge.empty()); merge(*internalize_term(a1), *internalize_term(a2)); @@ -415,17 +415,17 @@ namespace qe { void term_graph::merge(term &t1, term &t2) { // -- merge might invalidate term2app cache m_term2app.reset(); - m_pinned.reset(); - + m_pinned.reset(); + term *a = &t1.get_root(); term *b = &t2.get_root(); - + if (a == b) return; - + if (a->get_class_size() > b->get_class_size()) { std::swap(a, b); } - + // Remove parents of it from the cg table. for (term* p : term::parents(b)) { if (!p->is_marked()) { @@ -626,21 +626,21 @@ namespace qe { expr_ref_vector m_pinned; // tracks expr in the maps expr* mk_pure(term& t) { - expr* e = nullptr; - if (m_term2app.find(t.get_id(), e)) return e; - e = t.get_expr(); - if (!is_app(e)) return nullptr; - app* a = ::to_app(e); + expr* e = nullptr; + if (m_term2app.find(t.get_id(), e)) return e; + e = t.get_expr(); + if (!is_app(e)) return nullptr; + app* a = ::to_app(e); expr_ref_buffer kids(m); - for (term* ch : term::children(t)) { + for (term* ch : term::children(t)) { if (!m_root2rep.find(ch->get_root().get_id(), e)) return nullptr; - kids.push_back(e); - } + kids.push_back(e); + } expr* pure = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); m_pinned.push_back(pure); m_term2app.insert(t.get_id(), pure); return pure; - } + } bool is_better_rep(expr *t1, expr *t2) { if (!t2) return t1; @@ -648,34 +648,34 @@ namespace qe { } void purify() { - // - propagate representatives up over parents. - // use work-list + marking to propagate. - // - produce equalities over represented classes. - // - produce other literals over represented classes + // - propagate representatives up over parents. + // use work-list + marking to propagate. + // - produce equalities over represented classes. + // - produce other literals over represented classes // (walk disequalities in m_lits and represent // lhs/rhs over decls or excluding decls) - ptr_vector worklist; + ptr_vector worklist; for (term * t : m_tg.m_terms) { - worklist.push_back(t); - t->set_mark(true); - } + worklist.push_back(t); + t->set_mark(true); + } - while (!worklist.empty()) { - term* t = worklist.back(); - worklist.pop_back(); - t->set_mark(false); - if (m_term2app.contains(t->get_id())) - continue; + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) + continue; if (!t->is_theory() && is_projected(*t)) - continue; + continue; - expr* pure = mk_pure(*t); - if (!pure) continue; + expr* pure = mk_pure(*t); + if (!pure) continue; m_term2app.insert(t->get_id(), pure); expr* rep = nullptr; - // ensure that the root has a representative + // ensure that the root has a representative m_root2rep.find(t->get_root().get_id(), rep); // update rep with pure if it is better @@ -686,9 +686,9 @@ namespace qe { if (!p->is_marked()) { p->set_mark(true); worklist.push_back(p); - } - } - } + } + } + } } // Here we could also walk equivalence classes that @@ -698,7 +698,7 @@ namespace qe { // and can be mined using other means, such as theory // aware core minimization m_tg.reset_marks(); - } + } void solve() { ptr_vector worklist; @@ -707,7 +707,7 @@ namespace qe { if (m_term2app.contains(t->get_id())) continue; worklist.push_back(t); t->set_mark(true); - } + } while (!worklist.empty()) { term* t = worklist.back(); @@ -728,13 +728,13 @@ namespace qe { m_root2rep.insert(t->get_root().get_id(), pure); for (term * p : term::parents(t->get_root())) { SASSERT(!m_term2app.contains(p->get_id())); - if (!p->is_marked()) { - p->set_mark(true); - worklist.push_back(p); - } - } + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); } } + } + } m_tg.reset_marks(); } @@ -744,7 +744,7 @@ namespace qe { bool find_app(expr *lit, expr *&res) { return m_root2rep.find(m_tg.get_term(lit)->get_root().get_id(), res); - } + } void mk_lits(expr_ref_vector &res) { expr *e = nullptr; @@ -800,16 +800,16 @@ namespace qe { } bool is_solved_eq(expr *_lhs, expr* _rhs) { - if (!is_app(_lhs) || !is_app(_rhs)) return false; - app *lhs, *rhs; - lhs = ::to_app(_lhs); - rhs = ::to_app(_rhs); + if (!is_app(_lhs) || !is_app(_rhs)) return false; + app *lhs, *rhs; + lhs = ::to_app(_lhs); + rhs = ::to_app(_rhs); - if (rhs->get_num_args() > 0) return false; - if (rhs->get_family_id() != null_family_id) return false; + if (rhs->get_num_args() > 0) return false; + if (rhs->get_family_id() != null_family_id) return false; - return !occurs(rhs, lhs); - } + return !occurs(rhs, lhs); + } public: projector(term_graph &tg) : m_tg(tg), m(m_tg.m), m_pinned(m) {} @@ -820,7 +820,7 @@ namespace qe { m_root2rep.reset(); m_decls.reset(); m_pinned.reset(); - } + } expr_ref_vector project(func_decl_ref_vector const &decls, bool exclude) { expr_ref_vector res(m); m_exclude = exclude; @@ -830,7 +830,7 @@ namespace qe { mk_pure_equalities(res); reset(); return res; - } + } expr_ref_vector solve(func_decl_ref_vector const &decls, bool exclude) { expr_ref_vector res(m); m_exclude = exclude; @@ -842,12 +842,12 @@ namespace qe { return res; } }; - } + } expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { projector p(*this); return p.project(decls, exclude); - } + } expr_ref_vector term_graph::solve(func_decl_ref_vector const &decls, bool exclude) { projector p(*this); From ba504e4243908ea2074fc6f2cdaa8894be78ed22 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 21:22:53 -0700 Subject: [PATCH 1195/1283] debugging mbi Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 54 +++++++++++++++++++++++++ src/qe/qe_mbi.cpp | 13 +++++- src/qe/qe_term_graph.cpp | 30 +++++++------- src/smt/smt_solver.cpp | 2 +- 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index bedbf84aa..62d5ea3ea 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -29,6 +29,7 @@ Notes: #include "tactic/arith/bound_manager.h" #include "ast/used_vars.h" #include "ast/rewriter/var_subst.h" +#include "ast/ast_util.h" #include "util/gparams.h" #include "qe/qe_mbp.h" #include "qe/qe_mbi.h" @@ -437,7 +438,58 @@ public: lbool res = mbi.pingpong(pA, pB, vars, itp); ctx.regular_stream() << res << " " << itp << "\n"; } +}; + +class eufi_cmd : public cmd { + expr* m_a; + expr* m_b; + ptr_vector m_vars; +public: + eufi_cmd():cmd("eufi") {} + char const * get_usage() const override { return " (vars)"; } + char const * get_descr(cmd_context & ctx) const override { return "perform model based interpolation"; } + unsigned get_arity() const override { return 3; } + cmd_arg_kind next_arg_kind(cmd_context& ctx) const override { + if (m_a == nullptr) return CPK_EXPR; + if (m_b == nullptr) return CPK_EXPR; + return CPK_FUNC_DECL_LIST; + } + void set_next_arg(cmd_context& ctx, expr * arg) override { + if (m_a == nullptr) + m_a = arg; + else + m_b = arg; + } + void set_next_arg(cmd_context & ctx, unsigned num, func_decl * const * ts) override { + m_vars.append(num, ts); + } + void prepare(cmd_context & ctx) override { m_a = nullptr; m_b = nullptr; m_vars.reset(); } + void execute(cmd_context & ctx) override { + ast_manager& m = ctx.m(); + func_decl_ref_vector vars(m); + for (func_decl* v : m_vars) { + vars.push_back(v); + } + qe::interpolator mbi(m); + expr_ref a(m_a, m); + expr_ref b(m_b, m); + expr_ref itp(m); + solver_factory& sf = ctx.get_solver_factory(); + params_ref p; + solver_ref sA = sf(m, p, false /* no proofs */, true, true, symbol::null); + solver_ref sB = sf(m, p, false /* no proofs */, true, true, symbol::null); + solver_ref sNotA = sf(m, p, false /* no proofs */, true, true, symbol::null); + solver_ref sNotB = sf(m, p, false /* no proofs */, true, true, symbol::null); + sA->assert_expr(a); + sNotA->assert_expr(m.mk_not(a)); + sB->assert_expr(b); + sNotB->assert_expr(m.mk_not(b)); + qe::euf_mbi_plugin pA(sA.get(), sNotA.get()); + qe::euf_mbi_plugin pB(sB.get(), sNotB.get()); + lbool res = mbi.pogo(pA, pB, vars, itp); + ctx.regular_stream() << res << " " << itp << "\n"; + } }; @@ -468,6 +520,7 @@ public: expr_ref_vector lits(m); for (func_decl* v : m_vars) vars.push_back(v); for (expr* e : m_lits) lits.push_back(e); + flatten_and(lits); qe::term_graph tg(m); tg.add_lits(lits); expr_ref_vector p = tg.project(vars, false); @@ -504,4 +557,5 @@ void install_dbg_cmds(cmd_context & ctx) { ctx.insert(alloc(mbp_cmd)); ctx.insert(alloc(mbi_cmd)); ctx.insert(alloc(euf_project_cmd)); + ctx.insert(alloc(eufi_cmd)); } diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index d47c2ab2c..4b86a10a4 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -30,13 +30,17 @@ Revision History: namespace qe { lbool mbi_plugin::check(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { - SASSERT(lits.empty()); + ast_manager& m = lits.get_manager(); + expr_ref_vector lits0(lits); while (true) { + lits.reset(); + lits.append(lits0); switch ((*this)(vars, lits, mdl)) { case mbi_sat: return l_true; case mbi_unsat: if (lits.empty()) return l_false; + TRACE("qe", tout << "block: " << lits << "\n";); block(lits); break; case mbi_undef: @@ -111,6 +115,10 @@ namespace qe { m_solver(s), m_dual_solver(sNot) { + params_ref p; + p.set_bool("smt.core.minimize", true); + m_solver->updt_params(p); + m_dual_solver->updt_params(p); expr_ref_vector fmls(m); m_solver->get_assertions(fmls); expr_fast_mark1 marks; @@ -141,6 +149,7 @@ namespace qe { lits.push_back(m.mk_not(e)); } } + TRACE("qe", tout << "atoms from model: " << lits << "\n";); r = m_dual_solver->check_sat(lits); expr_ref_vector core(m); term_graph tg(m); @@ -148,10 +157,12 @@ namespace qe { case l_false: // use the dual solver to find a 'small' implicant m_dual_solver->get_unsat_core(core); + TRACE("qe", tout << "core: " << core << "\n";); // project the implicant onto vars tg.add_lits(core); lits.reset(); lits.append(tg.project(vars, false)); + TRACE("qe", tout << "project: " << lits << "\n";); return mbi_sat; case l_undef: return mbi_undef; diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 40f3998e7..8e3981e64 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -65,9 +65,9 @@ namespace qe { m_children.push_back(t); } } - + ~term() {} - + class parents { term const& t; public: @@ -168,9 +168,9 @@ namespace qe { arith_term_graph_plugin(term_graph &g) : term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} - + virtual ~arith_term_graph_plugin() {} - + bool mk_eq_core (expr *_e1, expr *_e2, expr_ref &res) { expr *e1, *e2; e1 = _e1; @@ -385,7 +385,7 @@ namespace qe { SASSERT(res); return res; } - + void term_graph::internalize_eq(expr *a1, expr* a2) { SASSERT(m_merge.empty()); merge(*internalize_term(a1), *internalize_term(a2)); @@ -415,17 +415,17 @@ namespace qe { void term_graph::merge(term &t1, term &t2) { // -- merge might invalidate term2app cache m_term2app.reset(); - m_pinned.reset(); - + m_pinned.reset(); + term *a = &t1.get_root(); term *b = &t2.get_root(); - + if (a == b) return; - + if (a->get_class_size() > b->get_class_size()) { std::swap(a, b); } - + // Remove parents of it from the cg table. for (term* p : term::parents(b)) { if (!p->is_marked()) { @@ -736,7 +736,7 @@ namespace qe { } } m_tg.reset_marks(); - } + } bool find_app(term &t, expr *&res) { return m_root2rep.find(t.get_root().get_id(), res); @@ -744,7 +744,7 @@ namespace qe { bool find_app(expr *lit, expr *&res) { return m_root2rep.find(m_tg.get_term(lit)->get_root().get_id(), res); - } + } void mk_lits(expr_ref_vector &res) { expr *e = nullptr; @@ -752,7 +752,7 @@ namespace qe { if (!m.is_eq(lit) && find_app(lit, e)) res.push_back(e); } - } + } void mk_pure_equalities(const term &t, expr_ref_vector &res) { expr *rep = nullptr; @@ -842,12 +842,12 @@ namespace qe { return res; } }; - } + } expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { projector p(*this); return p.project(decls, exclude); - } + } expr_ref_vector term_graph::solve(func_decl_ref_vector const &decls, bool exclude) { projector p(*this); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 1e49f7f87..b0a8153a5 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -215,7 +215,7 @@ namespace smt { r.push_back(m_context.get_unsat_core_expr(i)); } - if (m_minimizing_core && smt_params_helper(get_params()).core_minimize()) { + if (!m_minimizing_core && smt_params_helper(get_params()).core_minimize()) { scoped_minimize_core scm(*this); mus mus(*this); mus.add_soft(r.size(), r.c_ptr()); From 6d79b191703ea9b85fbb1304ee97fd5b7832b4ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 22:08:50 -0700 Subject: [PATCH 1196/1283] fix a few bugs, debugging eufi Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 2 +- src/qe/qe_term_graph.cpp | 28 ++++++++++++++++++++-------- src/solver/mus.cpp | 4 ++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 4b86a10a4..298a1da99 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -116,7 +116,7 @@ namespace qe { m_dual_solver(sNot) { params_ref p; - p.set_bool("smt.core.minimize", true); + p.set_bool("core.minimize", true); m_solver->updt_params(p); m_dual_solver->updt_params(p); expr_ref_vector fmls(m); diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 8e3981e64..f537c5da8 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -625,7 +625,7 @@ namespace qe { expr_ref_vector m_pinned; // tracks expr in the maps - expr* mk_pure(term& t) { + expr* mk_pure(term const& t) { expr* e = nullptr; if (m_term2app.find(t.get_id(), e)) return e; e = t.get_expr(); @@ -643,7 +643,7 @@ namespace qe { } bool is_better_rep(expr *t1, expr *t2) { - if (!t2) return t1; + if (!t2) return t1 != nullptr; return m.is_unique_value(t1) && !m.is_unique_value(t2); } @@ -755,13 +755,21 @@ namespace qe { } void mk_pure_equalities(const term &t, expr_ref_vector &res) { + SASSERT(t.is_root()); expr *rep = nullptr; if (!m_root2rep.find(t.get_id(), rep)) return; - for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { - expr* member = mk_pure(*it); - if (member) + obj_hashtable members; + members.insert(rep); + term const * r = &t; + do { + expr* member = nullptr; + if (m_term2app.find(r->get_id(), member) && !members.contains(member)) { res.push_back (m.mk_eq (rep, member)); + members.insert(member); + } + r = &r->get_next(); } + while (r != &t); } bool is_projected(const term &t) { @@ -771,13 +779,17 @@ namespace qe { void mk_unpure_equalities(const term &t, expr_ref_vector &res) { expr *rep = nullptr; if (!m_root2rep.find(t.get_id(), rep)) return; - for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { - expr* member = mk_pure(*it); + obj_hashtable members; + term const * r = &t; + do { + expr* member = mk_pure(*r); SASSERT(member); - if (!is_projected(*it) || !is_solved_eq(rep, member)) { + if (member != rep && (!is_projected(*r) || !is_solved_eq(rep, member))) { res.push_back(m.mk_eq(rep, member)); } + r = &r->get_next(); } + while (r != &t); } void mk_equalities(bool pure, expr_ref_vector &res) { diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index e4ebd7e3b..a7925f268 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -50,12 +50,12 @@ struct mus::imp { } bool is_literal(expr* lit) const { - expr* l; + expr* l; return is_uninterp_const(lit) || (m.is_not(lit, l) && is_uninterp_const(l)); } unsigned add_soft(expr* lit) { - SASSERT(is_literal(lit)); + //SASSERT(is_literal(lit)); unsigned idx = m_lit2expr.size(); m_expr2lit.insert(lit, idx); m_lit2expr.push_back(lit); From 0f799eb2ae609d737c74131bafd54b1b45641de4 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 22:44:11 -0700 Subject: [PATCH 1197/1283] formatting. no change to code --- src/qe/qe_term_graph.cpp | 104 +++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index f537c5da8..a0ebf6f33 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -626,21 +626,21 @@ namespace qe { expr_ref_vector m_pinned; // tracks expr in the maps expr* mk_pure(term const& t) { - expr* e = nullptr; - if (m_term2app.find(t.get_id(), e)) return e; - e = t.get_expr(); - if (!is_app(e)) return nullptr; - app* a = ::to_app(e); + expr* e = nullptr; + if (m_term2app.find(t.get_id(), e)) return e; + e = t.get_expr(); + if (!is_app(e)) return nullptr; + app* a = ::to_app(e); expr_ref_buffer kids(m); - for (term* ch : term::children(t)) { + for (term* ch : term::children(t)) { if (!m_root2rep.find(ch->get_root().get_id(), e)) return nullptr; - kids.push_back(e); - } + kids.push_back(e); + } expr* pure = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); m_pinned.push_back(pure); m_term2app.insert(t.get_id(), pure); return pure; - } + } bool is_better_rep(expr *t1, expr *t2) { if (!t2) return t1 != nullptr; @@ -648,34 +648,34 @@ namespace qe { } void purify() { - // - propagate representatives up over parents. - // use work-list + marking to propagate. - // - produce equalities over represented classes. - // - produce other literals over represented classes + // - propagate representatives up over parents. + // use work-list + marking to propagate. + // - produce equalities over represented classes. + // - produce other literals over represented classes // (walk disequalities in m_lits and represent // lhs/rhs over decls or excluding decls) - ptr_vector worklist; + ptr_vector worklist; for (term * t : m_tg.m_terms) { - worklist.push_back(t); - t->set_mark(true); - } + worklist.push_back(t); + t->set_mark(true); + } - while (!worklist.empty()) { - term* t = worklist.back(); - worklist.pop_back(); - t->set_mark(false); - if (m_term2app.contains(t->get_id())) - continue; + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) + continue; if (!t->is_theory() && is_projected(*t)) - continue; + continue; - expr* pure = mk_pure(*t); - if (!pure) continue; + expr* pure = mk_pure(*t); + if (!pure) continue; m_term2app.insert(t->get_id(), pure); expr* rep = nullptr; - // ensure that the root has a representative + // ensure that the root has a representative m_root2rep.find(t->get_root().get_id(), rep); // update rep with pure if it is better @@ -686,9 +686,9 @@ namespace qe { if (!p->is_marked()) { p->set_mark(true); worklist.push_back(p); - } - } - } + } + } + } } // Here we could also walk equivalence classes that @@ -698,16 +698,16 @@ namespace qe { // and can be mined using other means, such as theory // aware core minimization m_tg.reset_marks(); - } + } void solve() { - ptr_vector worklist; + ptr_vector worklist; for (term * t : m_tg.m_terms) { // skip pure terms if (m_term2app.contains(t->get_id())) continue; worklist.push_back(t); t->set_mark(true); - } + } while (!worklist.empty()) { term* t = worklist.back(); @@ -728,15 +728,15 @@ namespace qe { m_root2rep.insert(t->get_root().get_id(), pure); for (term * p : term::parents(t->get_root())) { SASSERT(!m_term2app.contains(p->get_id())); - if (!p->is_marked()) { - p->set_mark(true); - worklist.push_back(p); + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); + } + } } } - } - } m_tg.reset_marks(); - } + } bool find_app(term &t, expr *&res) { return m_root2rep.find(t.get_root().get_id(), res); @@ -744,7 +744,7 @@ namespace qe { bool find_app(expr *lit, expr *&res) { return m_root2rep.find(m_tg.get_term(lit)->get_root().get_id(), res); - } + } void mk_lits(expr_ref_vector &res) { expr *e = nullptr; @@ -752,7 +752,7 @@ namespace qe { if (!m.is_eq(lit) && find_app(lit, e)) res.push_back(e); } - } + } void mk_pure_equalities(const term &t, expr_ref_vector &res) { SASSERT(t.is_root()); @@ -812,16 +812,16 @@ namespace qe { } bool is_solved_eq(expr *_lhs, expr* _rhs) { - if (!is_app(_lhs) || !is_app(_rhs)) return false; - app *lhs, *rhs; - lhs = ::to_app(_lhs); - rhs = ::to_app(_rhs); + if (!is_app(_lhs) || !is_app(_rhs)) return false; + app *lhs, *rhs; + lhs = ::to_app(_lhs); + rhs = ::to_app(_rhs); - if (rhs->get_num_args() > 0) return false; - if (rhs->get_family_id() != null_family_id) return false; + if (rhs->get_num_args() > 0) return false; + if (rhs->get_family_id() != null_family_id) return false; - return !occurs(rhs, lhs); - } + return !occurs(rhs, lhs); + } public: projector(term_graph &tg) : m_tg(tg), m(m_tg.m), m_pinned(m) {} @@ -832,7 +832,7 @@ namespace qe { m_root2rep.reset(); m_decls.reset(); m_pinned.reset(); - } + } expr_ref_vector project(func_decl_ref_vector const &decls, bool exclude) { expr_ref_vector res(m); m_exclude = exclude; @@ -842,7 +842,7 @@ namespace qe { mk_pure_equalities(res); reset(); return res; - } + } expr_ref_vector solve(func_decl_ref_vector const &decls, bool exclude) { expr_ref_vector res(m); m_exclude = exclude; @@ -854,7 +854,7 @@ namespace qe { return res; } }; - } + } expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { projector p(*this); From 2288931b4669e2f13b9892a1d9bbc0c1e6268370 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Mon, 11 Jun 2018 22:48:24 -0700 Subject: [PATCH 1198/1283] fix mk_unpure_equalities --- src/qe/qe_term_graph.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index a0ebf6f33..084391368 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -780,12 +780,15 @@ namespace qe { expr *rep = nullptr; if (!m_root2rep.find(t.get_id(), rep)) return; obj_hashtable members; + members.insert(rep); term const * r = &t; do { expr* member = mk_pure(*r); SASSERT(member); - if (member != rep && (!is_projected(*r) || !is_solved_eq(rep, member))) { + if (!members.contains(member) && + (!is_projected(*r) || !is_solved_eq(rep, member))) { res.push_back(m.mk_eq(rep, member)); + members.insert(member); } r = &r->get_next(); } From 74621e0b7d366bd83c1b88ea3aba64a5f17d57b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 23:28:50 -0700 Subject: [PATCH 1199/1283] first eufi example running Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 22 +++++++------- src/cmd_context/basic_cmds.cpp | 2 +- src/muz/spacer/spacer_iuc_solver.cpp | 12 ++------ src/muz/spacer/spacer_iuc_solver.h | 9 ++++-- src/muz/spacer/spacer_prop_solver.cpp | 2 +- src/opt/maxres.cpp | 13 ++++---- src/opt/opt_context.cpp | 2 +- src/opt/opt_context.h | 2 +- src/opt/opt_solver.cpp | 3 +- src/opt/opt_solver.h | 2 +- src/qe/qe_mbi.cpp | 13 ++------ src/qe/qe_term_graph.cpp | 6 ++-- src/sat/sat_solver/inc_sat_solver.cpp | 2 +- src/smt/smt_context.cpp | 14 ++++----- src/smt/smt_solver.cpp | 14 ++++----- src/solver/check_sat_result.cpp | 6 ++-- src/solver/check_sat_result.h | 9 ++---- src/solver/combined_solver.cpp | 2 +- src/solver/mus.cpp | 30 ++++++------------- src/solver/mus.h | 2 -- src/solver/solver2tactic.cpp | 2 +- src/solver/solver_pool.cpp | 6 ++-- src/solver/tactic2solver.cpp | 4 +-- .../portfolio/bounded_int2bv_solver.cpp | 2 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- 26 files changed, 80 insertions(+), 105 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 657ff025c..ad5e7731d 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -460,12 +460,12 @@ extern "C" { LOG_Z3_solver_get_unsat_core(c, s); RESET_ERROR_CODE(); init_solver(c, s); - ptr_vector core; + expr_ref_vector core(mk_c(c)->m()); to_solver_ref(s)->get_unsat_core(core); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); - for (unsigned i = 0; i < core.size(); i++) { - v->m_ast_vector.push_back(core[i]); + for (expr* e : core) { + v->m_ast_vector.push_back(e); } RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(nullptr); @@ -537,23 +537,23 @@ extern "C" { expr_ref_vector _assumptions(m), _consequences(m), _variables(m); ast_ref_vector const& __assumptions = to_ast_vector_ref(assumptions); unsigned sz = __assumptions.size(); - for (unsigned i = 0; i < sz; ++i) { - if (!is_expr(__assumptions[i])) { + for (ast* e : __assumptions) { + if (!is_expr(e)) { _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); SET_ERROR_CODE(Z3_INVALID_USAGE); return Z3_L_UNDEF; } - _assumptions.push_back(to_expr(__assumptions[i])); + _assumptions.push_back(to_expr(e)); } ast_ref_vector const& __variables = to_ast_vector_ref(variables); sz = __variables.size(); - for (unsigned i = 0; i < sz; ++i) { - if (!is_expr(__variables[i])) { + for (ast* a : __variables) { + if (!is_expr(a)) { _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); SET_ERROR_CODE(Z3_INVALID_USAGE); return Z3_L_UNDEF; } - _variables.push_back(to_expr(__variables[i])); + _variables.push_back(to_expr(a)); } lbool result = l_undef; unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); @@ -578,8 +578,8 @@ extern "C" { if (result == l_undef) { to_solver_ref(s)->set_reason_unknown(eh); } - for (unsigned i = 0; i < _consequences.size(); ++i) { - to_ast_vector_ref(consequences).push_back(_consequences[i].get()); + for (expr* e : _consequences) { + to_ast_vector_ref(consequences).push_back(e); } return static_cast(result); Z3_CATCH_RETURN(Z3_L_UNDEF); diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 1d8fdb3de..4e5202fd8 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -223,7 +223,7 @@ ATOMIC_CMD(get_proof_graph_cmd, "get-proof-graph", "retrieve proof and print it }); static void print_core(cmd_context& ctx) { - ptr_vector core; + expr_ref_vector core(ctx.m()); ctx.get_check_sat_result()->get_unsat_core(core); ctx.regular_stream() << "("; bool first = true; diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index a0bc2a627..6d824a1f2 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -215,10 +215,11 @@ void iuc_solver::reset_statistics () m_learn_core_sw.reset(); } -void iuc_solver::get_unsat_core (ptr_vector &core) +void iuc_solver::get_unsat_core (expr_ref_vector &core) { m_solver.get_unsat_core (core); - undo_proxies_in_core (core); + ptr_vector _core(core.size(), core.c_ptr()); + undo_proxies_in_core (_core); } void iuc_solver::undo_proxies_in_core (ptr_vector &r) { @@ -258,13 +259,6 @@ void iuc_solver::undo_proxies (expr_ref_vector &r) } } -void iuc_solver::get_unsat_core (expr_ref_vector &_core) -{ - ptr_vector core; - get_unsat_core (core); - _core.append (core.size (), core.c_ptr ()); -} - void iuc_solver::elim_proxies (expr_ref_vector &v) { expr_ref f = mk_and (v); diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 0195ea134..3c6251be0 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -92,7 +92,6 @@ public: ~iuc_solver() override {} /* iuc solver specific */ - void get_unsat_core(expr_ref_vector &core) override; virtual void get_iuc(expr_ref_vector &core); void set_split_literals(bool v) { m_split_literals = v; } bool mk_proxies(expr_ref_vector &v, unsigned from = 0); @@ -102,7 +101,11 @@ public: void pop_bg(unsigned n); unsigned get_num_bg(); - void get_full_unsat_core(ptr_vector &core) { m_solver.get_unsat_core(core); } + void get_full_unsat_core(ptr_vector &core) { + expr_ref_vector _core(m); + m_solver.get_unsat_core(_core); + core.append(_core.size(), _core.c_ptr()); + } /* solver interface */ @@ -142,7 +145,7 @@ public: void collect_statistics(statistics &st) const override ; virtual void reset_statistics(); - void get_unsat_core(ptr_vector &r) override; + void get_unsat_core(expr_ref_vector &r) override; void get_model_core(model_ref &m) override {m_solver.get_model(m);} proof *get_proof() override {return m_solver.get_proof();} std::string reason_unknown() const override { return m_solver.reason_unknown(); } diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 64f1bfc9a..435f0af3a 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -245,7 +245,7 @@ lbool prop_solver::maxsmt(expr_ref_vector &hard, expr_ref_vector &soft, soft.reset(); expr_ref saved(m); - ptr_vector core; + expr_ref_vector core(m); m_ctx->get_unsat_core(core); // while there are soft constraints diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d49044d8d..e86b20820 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -88,7 +88,7 @@ private: expr_ref_vector m_asms; expr_ref_vector m_defs; obj_map m_asm2weight; - ptr_vector m_new_core; + expr_ref_vector m_new_core; mus m_mus; expr_ref_vector m_trail; strategy_t m_st; @@ -119,6 +119,7 @@ public: maxsmt_solver_base(c, ws, soft), m_index(index), m_B(m), m_asms(m), m_defs(m), + m_new_core(m), m_mus(c.get_solver()), m_trail(m), m_st(st), @@ -351,11 +352,13 @@ public: exprs core; while (is_sat == l_false) { core.reset(); - s().get_unsat_core(core); - // verify_core(core); + expr_ref_vector _core(m); + s().get_unsat_core(_core); model_ref mdl; get_mus_model(mdl); - is_sat = minimize_core(core); + is_sat = minimize_core(_core); + core.append(_core.size(), _core.c_ptr()); + // verify_core(core); ++m_stats.m_num_cores; if (is_sat != l_true) { IF_VERBOSE(100, verbose_stream() << "(opt.maxres minimization failed)\n";); @@ -538,7 +541,7 @@ public: return nullptr != mdl.get(); } - lbool minimize_core(exprs& core) { + lbool minimize_core(expr_ref_vector& core) { if (core.empty()) { return l_true; } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2850dd59c..37dbd0817 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -172,7 +172,7 @@ namespace opt { r.append(m_labels); } - void context::get_unsat_core(ptr_vector & r) { + void context::get_unsat_core(expr_ref_vector & r) { throw default_exception("Unsat cores are not supported with optimization"); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 29b327855..1172e68b6 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -195,7 +195,7 @@ namespace opt { void collect_statistics(statistics& stats) const override; proof* get_proof() override { return nullptr; } void get_labels(svector & r) override; - void get_unsat_core(ptr_vector & r) override; + void get_unsat_core(expr_ref_vector & r) override; std::string reason_unknown() const override; void set_reason_unknown(char const* msg) override { m_unknown = msg; } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 1a6587585..ca0474314 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -294,7 +294,8 @@ namespace opt { return r; } - void opt_solver::get_unsat_core(ptr_vector & r) { + void opt_solver::get_unsat_core(expr_ref_vector & r) { + r.reset(); unsigned sz = m_context.get_unsat_core_size(); for (unsigned i = 0; i < sz; i++) { r.push_back(m_context.get_unsat_core_expr(i)); diff --git a/src/opt/opt_solver.h b/src/opt/opt_solver.h index 7ffb531be..39562ec54 100644 --- a/src/opt/opt_solver.h +++ b/src/opt/opt_solver.h @@ -96,7 +96,7 @@ namespace opt { void push_core() override; void pop_core(unsigned n) override; lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override; - void get_unsat_core(ptr_vector & r) override; + void get_unsat_core(expr_ref_vector & r) override; void get_model_core(model_ref & _m) override; proof * get_proof() override; std::string reason_unknown() const override; diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 298a1da99..31b6001ea 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -30,19 +30,12 @@ Revision History: namespace qe { lbool mbi_plugin::check(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { - ast_manager& m = lits.get_manager(); - expr_ref_vector lits0(lits); while (true) { - lits.reset(); - lits.append(lits0); switch ((*this)(vars, lits, mdl)) { case mbi_sat: return l_true; case mbi_unsat: - if (lits.empty()) return l_false; - TRACE("qe", tout << "block: " << lits << "\n";); - block(lits); - break; + return l_false; case mbi_undef: return l_undef; case mbi_augment: @@ -113,8 +106,7 @@ namespace qe { m(s->get_manager()), m_atoms(m), m_solver(s), - m_dual_solver(sNot) - { + m_dual_solver(sNot) { params_ref p; p.set_bool("core.minimize", true); m_solver->updt_params(p); @@ -256,6 +248,7 @@ namespace qe { case l_true: return l_true; case l_false: + std::cout << lits << "\n"; a.block(lits); itps.push_back(mk_not(mk_and(lits))); break; diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 084391368..2fa652828 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -701,7 +701,7 @@ namespace qe { } void solve() { - ptr_vector worklist; + ptr_vector worklist; for (term * t : m_tg.m_terms) { // skip pure terms if (m_term2app.contains(t->get_id())) continue; @@ -785,8 +785,7 @@ namespace qe { do { expr* member = mk_pure(*r); SASSERT(member); - if (!members.contains(member) && - (!is_projected(*r) || !is_solved_eq(rep, member))) { + if (!members.contains(member) && (!is_projected(*r) || !is_solved_eq(rep, member))) { res.push_back(m.mk_eq(rep, member)); members.insert(member); } @@ -814,6 +813,7 @@ namespace qe { return mk_equalities(false, res); } + // TBD: generalize for also the case of a (:var n) bool is_solved_eq(expr *_lhs, expr* _rhs) { if (!is_app(_lhs) || !is_app(_rhs)) return false; app *lhs, *rhs; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index e1e0e0b0a..8b7e2e63c 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -299,7 +299,7 @@ public: if (m_preprocess) m_preprocess->collect_statistics(st); m_solver.collect_statistics(st); } - void get_unsat_core(ptr_vector & r) override { + void get_unsat_core(expr_ref_vector & r) override { r.reset(); r.append(m_core.size(), m_core.c_ptr()); } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index bc5814186..0bc21d627 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3258,7 +3258,7 @@ namespace smt { m_assumptions.reset(); } - lbool context::mk_unsat_core(lbool r) { + lbool context::mk_unsat_core(lbool r) { if (r != l_false) return r; SASSERT(inconsistent()); if (!tracking_assumptions()) { @@ -3276,18 +3276,16 @@ namespace smt { SASSERT(m_literal2assumption.contains(l.index())); if (!already_found_assumptions.contains(l.index())) { already_found_assumptions.insert(l.index()); - m_unsat_core.push_back(m_literal2assumption[l.index()]); + expr* orig_assumption = m_literal2assumption[l.index()]; + m_unsat_core.push_back(orig_assumption); + TRACE("assumptions", tout << l << ": " << mk_pp(orig_assumption, m_manager) << "\n";); } } reset_assumptions(); pop_to_base_lvl(); // undo the push_scope() performed by init_assumptions m_search_lvl = m_base_lvl; std::sort(m_unsat_core.c_ptr(), m_unsat_core.c_ptr() + m_unsat_core.size(), ast_lt_proc()); - TRACE("unsat_core_bug", tout << "unsat core:\n"; - unsigned sz = m_unsat_core.size(); - for (unsigned i = 0; i < sz; i++) { - tout << mk_pp(m_unsat_core.get(i), m_manager) << "\n"; - }); + TRACE("unsat_core_bug", tout << "unsat core:\n" << m_unsat_core << "\n";); validate_unsat_core(); // theory validation of unsat core for (theory* th : m_theory_set) { @@ -3403,7 +3401,6 @@ namespace smt { lbool context::check(unsigned num_assumptions, expr * const * assumptions, bool reset_cancel, bool already_did_theory_assumptions) { if (!check_preamble(reset_cancel)) return l_undef; - TRACE("before_search", display(tout);); SASSERT(at_base_level()); setup_context(false); expr_ref_vector asms(m_manager, num_assumptions, assumptions); @@ -3412,6 +3409,7 @@ namespace smt { TRACE("unsat_core_bug", tout << asms << "\n";); internalize_assertions(); init_assumptions(asms); + TRACE("before_search", display(tout);); lbool r = search(); r = mk_unsat_core(r); r = check_finalize(r); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index b0a8153a5..48f6053fc 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -209,7 +209,7 @@ namespace smt { } }; - void get_unsat_core(ptr_vector & r) override { + void get_unsat_core(expr_ref_vector & r) override { unsigned sz = m_context.get_unsat_core_size(); for (unsigned i = 0; i < sz; i++) { r.push_back(m_context.get_unsat_core_expr(i)); @@ -219,7 +219,7 @@ namespace smt { scoped_minimize_core scm(*this); mus mus(*this); mus.add_soft(r.size(), r.c_ptr()); - ptr_vector r2; + expr_ref_vector r2(m); if (l_true == mus.get_mus(r2)) { r.reset(); r.append(r2); @@ -333,7 +333,7 @@ namespace smt { for_each_expr(p, visited, e); } - void compute_assrtn_fds(ptr_vector & core, vector & assrtn_fds) { + void compute_assrtn_fds(expr_ref_vector & core, vector & assrtn_fds) { assrtn_fds.resize(m_name2assertion.size()); unsigned i = 0; for (auto & kv : m_name2assertion) { @@ -354,7 +354,7 @@ namespace smt { return false; } - void add_pattern_literals_to_core(ptr_vector & core) { + void add_pattern_literals_to_core(expr_ref_vector & core) { ast_manager & m = get_manager(); expr_ref_vector new_core_literals(m); @@ -413,7 +413,7 @@ namespace smt { for_each_expr(p, visited, e); } - void add_nonlocal_pattern_literals_to_core(ptr_vector & core) { + void add_nonlocal_pattern_literals_to_core(expr_ref_vector & core) { ast_manager & m = get_manager(); for (auto const& kv : m_name2assertion) { expr_ref name(kv.m_key, m); @@ -425,8 +425,8 @@ namespace smt { collect_body_func_decls(assrtn, body_fds); for (func_decl *fd : pattern_fds) { - if (!body_fds.contains(fd)) { - core.insert(name); + if (!body_fds.contains(fd) && !core.contains(name)) { + core.push_back(name); break; } } diff --git a/src/solver/check_sat_result.cpp b/src/solver/check_sat_result.cpp index 0d3c112b3..28e6afeca 100644 --- a/src/solver/check_sat_result.cpp +++ b/src/solver/check_sat_result.cpp @@ -48,9 +48,11 @@ void simple_check_sat_result::collect_statistics(statistics & st) const { st.copy(m_stats); } -void simple_check_sat_result::get_unsat_core(ptr_vector & r) { - if (m_status == l_false) +void simple_check_sat_result::get_unsat_core(expr_ref_vector & r) { + if (m_status == l_false) { + r.reset(); r.append(m_core.size(), m_core.c_ptr()); + } } void simple_check_sat_result::get_model_core(model_ref & m) { diff --git a/src/solver/check_sat_result.h b/src/solver/check_sat_result.h index 762735b8d..7e698b806 100644 --- a/src/solver/check_sat_result.h +++ b/src/solver/check_sat_result.h @@ -50,12 +50,7 @@ public: lbool set_status(lbool r) { return m_status = r; } lbool status() const { return m_status; } virtual void collect_statistics(statistics & st) const = 0; - virtual void get_unsat_core(ptr_vector & r) = 0; - virtual void get_unsat_core(expr_ref_vector & r) { - ptr_vector core; - get_unsat_core(core); - r.append(core.size(), core.c_ptr()); - } + virtual void get_unsat_core(expr_ref_vector & r) = 0; void set_model_converter(model_converter* mc) { m_mc0 = mc; } model_converter* mc0() const { return m_mc0.get(); } virtual void get_model_core(model_ref & m) = 0; @@ -87,7 +82,7 @@ struct simple_check_sat_result : public check_sat_result { ~simple_check_sat_result() override; ast_manager& get_manager() const override { return m_proof.get_manager(); } void collect_statistics(statistics & st) const override; - void get_unsat_core(ptr_vector & r) override; + void get_unsat_core(expr_ref_vector & r) override; void get_model_core(model_ref & m) override; proof * get_proof() override; std::string reason_unknown() const override; diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index a47302f5d..ad166d425 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -298,7 +298,7 @@ public: m_solver1->collect_statistics(st); } - void get_unsat_core(ptr_vector & r) override { + void get_unsat_core(expr_ref_vector & r) override { if (m_use_solver1_results) m_solver1->get_unsat_core(r); else diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index a7925f268..b3d6c9ad9 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -64,7 +64,6 @@ struct mus::imp { } void add_assumption(expr* lit) { - SASSERT(is_literal(lit)); m_assumptions.push_back(lit); } @@ -78,17 +77,9 @@ struct mus::imp { return get_mus1(mus); } - lbool get_mus(ptr_vector& mus) { - mus.reset(); - expr_ref_vector result(m); - lbool r = get_mus(result); - mus.append(result.size(), result.c_ptr()); - return r; - } - lbool get_mus1(expr_ref_vector& mus) { ptr_vector unknown(m_lit2expr.size(), m_lit2expr.c_ptr()); - ptr_vector core_exprs; + expr_ref_vector core_exprs(m); TRACE("mus", m_solver.display(tout);); while (!unknown.empty()) { IF_VERBOSE(12, verbose_stream() << "(mus reducing core: " << unknown.size() << " new core: " << mus.size() << ")\n";); @@ -116,12 +107,12 @@ struct mus::imp { if (!core_exprs.contains(not_lit)) { // unknown := core_exprs \ mus unknown.reset(); - for (unsigned i = 0; i < core_exprs.size(); ++i) { - if (!mus.contains(core_exprs[i])) { - unknown.push_back(core_exprs[i]); + for (expr* c : core_exprs) { + if (!mus.contains(c)) { + unknown.push_back(c); } } - TRACE("mus", display_vec(tout << "core exprs:", core_exprs); + TRACE("mus", tout << "core exprs:" << core_exprs << "\n"; display_vec(tout << "core:", unknown); display_vec(tout << "mus:", mus); ); @@ -242,11 +233,11 @@ struct mus::imp { void get_core(expr_set& core) { core.reset(); - ptr_vector core_exprs; + expr_ref_vector core_exprs(m); m_solver.get_unsat_core(core_exprs); - for (unsigned i = 0; i < core_exprs.size(); ++i) { - if (m_expr2lit.contains(core_exprs[i])) { - core.insert(core_exprs[i]); + for (expr* c : core_exprs) { + if (m_expr2lit.contains(c)) { + core.insert(c); } } } @@ -375,9 +366,6 @@ void mus::add_assumption(expr* lit) { return m_imp->add_assumption(lit); } -lbool mus::get_mus(ptr_vector& mus) { - return m_imp->get_mus(mus); -} lbool mus::get_mus(expr_ref_vector& mus) { return m_imp->get_mus(mus); diff --git a/src/solver/mus.h b/src/solver/mus.h index f2e543f04..807b07873 100644 --- a/src/solver/mus.h +++ b/src/solver/mus.h @@ -47,8 +47,6 @@ class mus { */ void add_assumption(expr* lit); - lbool get_mus(ptr_vector& mus); - lbool get_mus(expr_ref_vector& mus); void reset(); diff --git a/src/solver/solver2tactic.cpp b/src/solver/solver2tactic.cpp index 68d4b11f6..3c4f291a5 100644 --- a/src/solver/solver2tactic.cpp +++ b/src/solver/solver2tactic.cpp @@ -134,7 +134,7 @@ public: in->set(proof2proof_converter(m, pr)); } if (in->unsat_core_enabled()) { - ptr_vector core; + expr_ref_vector core(m); local_solver->get_unsat_core(core); for (expr* c : core) { lcore = m.mk_join(lcore, m.mk_leaf(bool2dep.find(c))); diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp index 1d0fd0c11..9dacfb5ce 100644 --- a/src/solver/solver_pool.cpp +++ b/src/solver/solver_pool.cpp @@ -83,12 +83,12 @@ public: unsigned get_num_assertions() const override { return m_base->get_num_assertions(); } expr * get_assertion(unsigned idx) const override { return m_base->get_assertion(idx); } - void get_unsat_core(ptr_vector & r) override { + void get_unsat_core(expr_ref_vector& r) override { m_base->get_unsat_core(r); unsigned j = 0; for (unsigned i = 0; i < r.size(); ++i) - if (m_pred != r[i]) - r[j++] = r[i]; + if (m_pred != r.get(i)) + r[j++] = r.get(i); r.shrink(j); } diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 9118bb658..94509e3f6 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -62,7 +62,7 @@ public: lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) override; void collect_statistics(statistics & st) const override; - void get_unsat_core(ptr_vector & r) override; + void get_unsat_core(expr_ref_vector & r) override; void get_model_core(model_ref & m) override; proof * get_proof() override; std::string reason_unknown() const override; @@ -219,7 +219,7 @@ void tactic2solver::collect_statistics(statistics & st) const { //SASSERT(m_stats.size() > 0); } -void tactic2solver::get_unsat_core(ptr_vector & r) { +void tactic2solver::get_unsat_core(expr_ref_vector & r) { if (m_result.get()) { m_result->get_unsat_core(r); } diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 8767644f3..6389ed739 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -148,7 +148,7 @@ public: void set_produce_models(bool f) override { m_solver->set_produce_models(f); } void set_progress_callback(progress_callback * callback) override { m_solver->set_progress_callback(callback); } void collect_statistics(statistics & st) const override { m_solver->collect_statistics(st); } - void get_unsat_core(ptr_vector & r) override { m_solver->get_unsat_core(r); } + void get_unsat_core(expr_ref_vector & r) override { m_solver->get_unsat_core(r); } void get_model_core(model_ref & mdl) override { m_solver->get_model(mdl); if (mdl) { diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 6b5fe9056..29c6aeb39 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -88,7 +88,7 @@ public: void set_produce_models(bool f) override { m_solver->set_produce_models(f); } void set_progress_callback(progress_callback * callback) override { m_solver->set_progress_callback(callback); } void collect_statistics(statistics & st) const override { m_solver->collect_statistics(st); } - void get_unsat_core(ptr_vector & r) override { m_solver->get_unsat_core(r); } + void get_unsat_core(expr_ref_vector & r) override { m_solver->get_unsat_core(r); } void get_model_core(model_ref & mdl) override { m_solver->get_model(mdl); if (mdl) { diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index f8794ca41..60ca6a5dc 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -87,7 +87,7 @@ public: m_rewriter.collect_statistics(st); m_solver->collect_statistics(st); } - void get_unsat_core(ptr_vector & r) override { m_solver->get_unsat_core(r); } + void get_unsat_core(expr_ref_vector & r) override { m_solver->get_unsat_core(r); } void get_model_core(model_ref & mdl) override { m_solver->get_model(mdl); if (mdl) { From 5dc2b7172d7a55278b40b92b58d3d2213b74a50c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 23:31:40 -0700 Subject: [PATCH 1200/1283] merge Signed-off-by: Nikolaj Bjorner --- src/qe/qe_term_graph.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 2fa652828..396b5f092 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -701,7 +701,7 @@ namespace qe { } void solve() { - ptr_vector worklist; + ptr_vector worklist; for (term * t : m_tg.m_terms) { // skip pure terms if (m_term2app.contains(t->get_id())) continue; @@ -785,7 +785,8 @@ namespace qe { do { expr* member = mk_pure(*r); SASSERT(member); - if (!members.contains(member) && (!is_projected(*r) || !is_solved_eq(rep, member))) { + if (!members.contains(member) && + (!is_projected(*r) || !is_solved_eq(rep, member))) { res.push_back(m.mk_eq(rep, member)); members.insert(member); } From 8da84ec69e5fbbf9e1505b0ad92563fd4cb2e1df Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Jun 2018 23:31:52 -0700 Subject: [PATCH 1201/1283] merge Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 31b6001ea..d9b62fb96 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -248,7 +248,6 @@ namespace qe { case l_true: return l_true; case l_false: - std::cout << lits << "\n"; a.block(lits); itps.push_back(mk_not(mk_and(lits))); break; From d5081a48b0778441383b2e5b546957540a53b61b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Jun 2018 07:27:50 -0700 Subject: [PATCH 1202/1283] merge while skyping Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 30 +++++++++++---------- src/qe/qe_mbi.cpp | 58 ++++++++++++++++++++++++++++++++++++++++- src/smt/smt_context.cpp | 1 - src/smt/smt_context.h | 1 - 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index e86b20820..a8a4dfa71 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -383,8 +383,8 @@ public: } TRACE("opt", tout << "num cores: " << cores.size() << "\n"; - for (unsigned i = 0; i < cores.size(); ++i) { - display_vec(tout, cores[i]); + for (auto const& c : cores) { + display_vec(tout, c); } tout << "num satisfying: " << asms.size() << "\n";); @@ -476,8 +476,8 @@ public: } void process_unsat(vector const& cores) { - for (unsigned i = 0; i < cores.size(); ++i) { - process_unsat(cores[i]); + for (auto const & c : cores) { + process_unsat(c); } } @@ -602,8 +602,7 @@ public: } void display(std::ostream& out) { - for (unsigned i = 0; i < m_asms.size(); ++i) { - expr* a = m_asms[i].get(); + for (expr * a : m_asms) { out << mk_pp(a, m) << " : " << get_weight(a) << "\n"; } } @@ -710,8 +709,8 @@ public: void update_assignment(model* mdl) { unsigned correction_set_size = 0; - for (unsigned i = 0; i < m_asms.size(); ++i) { - if (is_false(mdl, m_asms[i].get())) { + for (expr* a : m_asms) { + if (is_false(mdl, a)) { ++correction_set_size; } } @@ -722,10 +721,12 @@ public: rational upper(0); expr_ref tmp(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { - if (!is_true(mdl, m_soft[i])) { + unsigned i = 0; + for (expr* s : m_soft) { + if (!is_true(mdl, s)) { upper += m_weights[i]; } + ++i; } if (upper > m_upper) { @@ -741,8 +742,9 @@ public: TRACE("opt", model_smt2_pp(tout << "updated model\n", m, *m_model, 0);); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = is_true(m_soft[i]); + i = 0; + for (expr* s : m_soft) { + m_assignment[i++] = is_true(s); } // DEBUG_CODE(verify_assignment();); @@ -759,8 +761,8 @@ public: pb_util u(m); expr_ref_vector nsoft(m); expr_ref fml(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { - nsoft.push_back(mk_not(m, m_soft[i])); + for (expr* s : m_soft) { + nsoft.push_back(mk_not(m, s)); } fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); TRACE("opt", tout << "block upper bound " << fml << "\n";);; diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index d9b62fb96..509800c62 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -16,6 +16,62 @@ Author: Revision History: +Notes: + + Reduction into: + T_EUF + T_LIRA + + Other theories: DT, ARR reduced to EUF + BV is EUF/Boolean. + + Purify EUF1 & LIRA1 & EUF2 & LIRA2 + + Then EUF1 & EUF2 |- false + LIRA1 & LIRA2 |- false + + Sketch of approach by example: + + A: s <= 2a <= t & f(a) = q + + B: t <= 2b <= s + 1 & f(b) != q + + 1. Extract arithmetic consequences of A over shared vocabulary. + + A -> s <= t & (even(t) | s < t) + + 2a. Send to B, have B solve shared variables with EUF_B. + epsilon b . B & A_pure + epsilon b . t <= 2b <= s + 1 & s <= t & (even(t) | s < t) + = t <= s + 1 & (even(t) | t <= s) & s <= t & (even(t) | s < t) + = even(t) & t = s + b := t div 2 + + B & A_pure -> B[b/t div 2] = f(t div 2) != q & t <= s + 1 + + 3a. Send purified result to A + A & B_pure -> false + + Invoke the ping-pong principle to extract interpolant. + + 2b. Solve for shared variables with EUF. + + epsilon a . A + = a := (s + 1) div 2 & s < t & f((s + 1) div 2) = q + + 3b. Send to B. Produces core + s < t & f((s + 1) div 2) = q + + 4b Solve again in arithmetic for shared variables with EUF. + + epsion a . A & (s >= t | f((s + 1) div 2) != q) + + a := t div 2 | s = t & f(t div 2) = q & even(t) + + Send to B, produces core (s != t | f(t div 2) != q) + + 5b. There is no longer a solution for A. A is unsat. + --*/ #include "ast/ast_util.h" @@ -129,7 +185,6 @@ namespace qe { // optionally minimize core using superposition. return mbi_unsat; case l_true: { - expr_ref_vector fmls(m); m_solver->get_model(mdl); model_evaluator mev(*mdl.get()); lits.reset(); @@ -263,3 +318,4 @@ namespace qe { } } }; + diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 0bc21d627..54fd1cb2b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3438,7 +3438,6 @@ namespace smt { th->init_search_eh(); } m_qmanager->init_search_eh(); - m_assumption_core.reset(); m_incomplete_theories.reset(); m_num_conflicts = 0; m_num_conflicts_since_restart = 0; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 7e09c3be2..e85348a07 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -894,7 +894,6 @@ namespace smt { failure m_last_search_failure; ptr_vector m_incomplete_theories; //!< theories that failed to produce a model bool m_searching; - ptr_vector m_assumption_core; unsigned m_num_conflicts; unsigned m_num_conflicts_since_restart; unsigned m_num_conflicts_since_lemma_gc; From 5fce4a1d1af81cd912a12d0f7dbb57acb7783a9d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 12 Jun 2018 11:59:18 -0700 Subject: [PATCH 1203/1283] Wire qe_solve_plugin into qe_term_graph Compiles. Not tested. --- src/qe/qe_solve_plugin.cpp | 45 +++---- src/qe/qe_term_graph.cpp | 241 +++++++++++++------------------------ src/qe/qe_term_graph.h | 41 ++++--- src/qe/qe_vartest.h | 7 +- 4 files changed, 136 insertions(+), 198 deletions(-) diff --git a/src/qe/qe_solve_plugin.cpp b/src/qe/qe_solve_plugin.cpp index ad4a03b5d..0a499d3b8 100644 --- a/src/qe/qe_solve_plugin.cpp +++ b/src/qe/qe_solve_plugin.cpp @@ -27,7 +27,7 @@ Revision History: namespace qe { expr_ref solve_plugin::operator()(expr* lit) { - if (m.is_not(lit, lit)) + if (m.is_not(lit, lit)) return solve(lit, false); else return solve(lit, true); @@ -39,9 +39,9 @@ namespace qe { arith_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("arith"), is_var), a(m) {} typedef std::pair signed_expr; - + /** - *\brief + *\brief * return r * (sum_{(sign,e) \in exprs} sign * e) */ expr_ref mk_term(bool is_int, rational const& r, bool sign, svector const& exprs) { @@ -124,7 +124,7 @@ namespace qe { return false; } - // is arg of the form a_val * v, where a_val + // is arg of the form a_val * v, where a_val // is a constant that we can safely divide by. bool is_invertible_mul(bool is_int, expr*& arg, rational& a_val) { if (is_variable(arg)) { @@ -144,9 +144,9 @@ namespace qe { } return false; } - - expr_ref mk_eq_core (expr *e1, expr *e2) { + + expr_ref mk_eq_core (expr *e1, expr *e2) { expr_ref v(m), t(m); if (solve(e1, e2, v, t)) { return expr_ref(m.mk_eq(v, t), m); @@ -172,7 +172,6 @@ namespace qe { app* mk_le_zero(expr *arg) { expr *e1, *e2, *e3; - // XXX currently disabled if (a.is_add(arg, e1, e2)) { // e1-e2<=0 --> e1<=e2 if (a.is_times_minus_one(e2, e3)) { @@ -188,7 +187,6 @@ namespace qe { app* mk_ge_zero(expr *arg) { expr *e1, *e2, *e3; - // XXX currently disabled if (a.is_add(arg, e1, e2)) { // e1-e2>=0 --> e1>=e2 if (a.is_times_minus_one(e2, e3)) { @@ -249,17 +247,22 @@ namespace qe { return false; } - expr_ref solve(expr* lit, bool is_pos) override { + expr_ref solve(expr* atom, bool is_pos) override { expr *e1, *e2; - expr_ref res(lit, m); - if (m.is_eq (lit, e1, e2)) { - res = mk_eq_core(e1, e2); + expr_ref res(atom, m); + if (m.is_eq (atom, e1, e2)) { + expr_ref v(m), t(m); + v = e1; t = e2; + // -- attempt to solve using arithmetic + solve(e1, e2, v, t); + // -- normalize equality + res = mk_eq_core(v, t); } - else if (a.is_le(lit, e1, e2)) { + else if (a.is_le(atom, e1, e2)) { mk_le_core(e1, e2, res); } - else if (a.is_ge(lit, e1, e2)) { + else if (a.is_ge(atom, e1, e2)) { mk_ge_core(e1, e2, res); } @@ -273,7 +276,7 @@ namespace qe { class basic_solve_plugin : public solve_plugin { public: - basic_solve_plugin(ast_manager& m, is_variable_proc& is_var): + basic_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_basic_family_id(), is_var) {} expr_ref solve(expr *atom, bool is_pos) override { @@ -288,7 +291,7 @@ namespace qe { } else if (is_variable(rhs) && !is_variable(lhs)) { res = m.mk_eq(rhs, lhs); - } + } } // (ite cond (= VAR t) (= VAR t2)) case expr* cond = nullptr, *th = nullptr, *el = nullptr; @@ -296,7 +299,7 @@ namespace qe { expr_ref r1 = solve(th, true); expr_ref r2 = solve(el, true); expr* v1 = nullptr, *t1 = nullptr, *v2 = nullptr, *t2 = nullptr; - if (m.is_eq(r1, v1, t1) && m.is_eq(r2, v2, t2) && v1 == v2) { + if (m.is_eq(r1, v1, t1) && m.is_eq(r2, v2, t2) && v1 == v2) { res = m.mk_eq(v1, m.mk_ite(cond, t1, t2)); } } @@ -313,8 +316,8 @@ namespace qe { class dt_solve_plugin : public solve_plugin { datatype_util dt; public: - dt_solve_plugin(ast_manager& m, is_variable_proc& is_var): - solve_plugin(m, m.get_family_id("datatype"), is_var), + dt_solve_plugin(ast_manager& m, is_variable_proc& is_var): + solve_plugin(m, m.get_family_id("datatype"), is_var), dt(m) {} expr_ref solve(expr *atom, bool is_pos) override { @@ -350,11 +353,11 @@ namespace qe { } } // TBD: can also solve for is_nil(x) by x = nil - // + // return is_pos ? res : mk_not(res); } }; - + class bv_solve_plugin : public solve_plugin { public: bv_solve_plugin(ast_manager& m, is_variable_proc& is_var): solve_plugin(m, m.get_family_id("bv"), is_var) {} diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 396b5f092..9bf007428 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -27,6 +27,28 @@ Notes: namespace qe { + namespace is_pure_ns { + struct found{}; + struct proc { + is_variable_proc &m_is_var; + proc(is_variable_proc &is_var) : m_is_var(is_var) {} + void operator()(var *n) const {if (m_is_var(n)) throw found();} + void operator()(app const *n) const {if (m_is_var(n)) throw found();} + void operator()(quantifier *n) const {} + }; + } + + bool is_pure(is_variable_proc &is_var, expr *e) { + try { + is_pure_ns::proc v(is_var); + quick_for_each_expr(v, e); + } + catch (is_pure_ns::found) { + return false; + } + return true; + } + class term { // -- an app represented by this term expr* m_expr; // NSB: to make usable with exprs @@ -160,154 +182,46 @@ namespace qe { }; - class arith_term_graph_plugin : public term_graph_plugin { - term_graph &m_g; - ast_manager &m; - arith_util m_arith; - public: - arith_term_graph_plugin(term_graph &g) : - term_graph_plugin (g.get_ast_manager().mk_family_id("arith")), - m_g(g), m(g.get_ast_manager()), m_arith(m) {(void)m_g;} + bool term_graph::is_variable_proc::operator()(const expr * e) const { + if (!is_app(e)) return false; + const app *a = ::to_app(e); + if (a->get_family_id() != null_family_id) return false; + if (m_solved.contains(a->get_decl()->get_id())) return false; + return m_exclude == m_decls.contains(a->get_decl()->get_id()); + } + bool term_graph::is_variable_proc::operator()(const term &t) const { + return !t.is_theory() && m_exclude == m_decls.contains(t.get_decl_id()); + } - virtual ~arith_term_graph_plugin() {} + void term_graph::is_variable_proc::set_decls(const func_decl_ref_vector &decls, bool exclude) { + reset(); + m_exclude = exclude; + for (auto *d : decls) m_decls.insert(d->get_id(), true); + } + void term_graph::is_variable_proc::mark_solved(const expr *e) { + if ((*this)(e)) + m_solved.insert(::to_app(e)->get_decl()->get_id(), true); + } - bool mk_eq_core (expr *_e1, expr *_e2, expr_ref &res) { - expr *e1, *e2; - e1 = _e1; - e2 = _e2; - if (m_arith.is_zero(e1)) { - std::swap(e1, e2); - } - // y + -1*x == 0 --> y = x - expr *a0 = 0, *a1 = 0, *x = 0; - if (m_arith.is_zero(e2) && m_arith.is_add(e1, a0, a1)) { - if (m_arith.is_times_minus_one(a1, x)) { - e1 = a0; - e2 = x; - } - else if (m_arith.is_times_minus_one(a0, x)) { - e1 = a1; - e2 = x; - } - } - res = m.mk_eq(e1, e2); - return true; - } - - app* mk_le_zero(expr *arg) { - expr *e1, *e2, *e3; - if (m_arith.is_add(arg, e1, e2)) { - // e1-e2<=0 --> e1<=e2 - if (m_arith.is_times_minus_one(e2, e3)) { - return m_arith.mk_le(e1, e3); - } - // -e1+e2<=0 --> e2<=e1 - else if (m_arith.is_times_minus_one(e1, e3)) { - return m_arith.mk_le(e2, e3); - } - } - return m_arith.mk_le(arg, mk_zero()); - } - - app* mk_ge_zero(expr *arg) { - expr *e1, *e2, *e3; - if (m_arith.is_add(arg, e1, e2)) { - // e1-e2>=0 --> e1>=e2 - if (m_arith.is_times_minus_one(e2, e3)) { - return m_arith.mk_ge(e1, e3); - } - // -e1+e2>=0 --> e2>=e1 - else if (m_arith.is_times_minus_one(e1, e3)) { - return m_arith.mk_ge(e2, e3); - } - } - return m_arith.mk_ge(arg, mk_zero()); - } - - bool mk_le_core (expr *arg1, expr * arg2, expr_ref &result) { - // t <= -1 ==> t < 0 ==> ! (t >= 0) - rational n; - if (m_arith.is_int (arg1) && m_arith.is_minus_one (arg2)) { - result = m.mk_not (mk_ge_zero (arg1)); - return true; - } - else if (m_arith.is_zero(arg2)) { - result = mk_le_zero(arg1); - return true; - } - else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n < 0) { - // t <= n ==> t < n + 1 ==> ! (t >= n + 1) - result = m.mk_not(m_arith.mk_ge(arg1, m_arith.mk_numeral(n+1, true))); - return true; - } - return false; - } - expr * mk_zero () {return m_arith.mk_numeral (rational (0), true);} - bool is_one (expr const * n) const { - rational val; - return m_arith.is_numeral (n, val) && val.is_one (); - } - - bool mk_ge_core (expr * arg1, expr * arg2, expr_ref &result) { - // t >= 1 ==> t > 0 ==> ! (t <= 0) - rational n; - if (m_arith.is_int (arg1) && is_one (arg2)) { - result = m.mk_not (mk_le_zero (arg1)); - return true; - } - else if (m_arith.is_zero(arg2)) { - result = mk_ge_zero(arg1); - return true; - } - else if (m_arith.is_int(arg1) && m_arith.is_numeral(arg2, n) && n > 0) { - // t >= n ==> t > n - 1 ==> ! (t <= n - 1) - result = m.mk_not(m_arith.mk_le(arg1, m_arith.mk_numeral(n-1, true))); - return true; - } - return false; - } - - expr_ref process_lit (expr *_lit) override { - expr *lit = _lit; - expr *e1, *e2; - - // strip negation - bool is_neg = m.is_not(lit); - if (is_neg) { - lit = to_app(to_app(lit)->get_arg(0)); - } - - expr_ref res(m); - res = lit; - if (m.is_eq (lit, e1, e2)) { - mk_eq_core(e1, e2, res); - } - else if (m_arith.is_le(lit, e1, e2)) { - mk_le_core(e1, e2, res); - } - else if (m_arith.is_ge(lit, e1, e2)) { - mk_ge_core(e1, e2, res); - } - // restore negation - if (is_neg) { - res = mk_not(m, res); - } - return res; - } - }; unsigned term_graph::term_hash::operator()(term const* t) const { return t->get_hash(); } bool term_graph::term_eq::operator()(term const* a, term const* b) const { return term::cg_eq(a, b); } term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { - m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); + m_plugins.register_plugin(mk_basic_solve_plugin(m, m_is_var)); + m_plugins.register_plugin(mk_arith_solve_plugin(m, m_is_var)); } term_graph::~term_graph() { reset(); } + bool term_graph::is_pure_def(expr *atom, expr *v) { + expr *e = nullptr; + return m.is_eq(atom, v, e) && m_is_var(v) && is_pure(m_is_var, e); + } + static family_id get_family_id(ast_manager &m, expr *lit) { if (m.is_not(lit, lit)) return get_family_id(m, lit); @@ -328,13 +242,9 @@ namespace qe { void term_graph::add_lit(expr *l) { expr_ref lit(m); - family_id fid = get_family_id (m, l); - term_graph_plugin *pin = m_plugins.get_plugin(fid); - if (pin) { - lit = pin->process_lit(l); - } else { - lit = l; - } + family_id fid = get_family_id(m, l); + qe::solve_plugin *pin = m_plugins.get_plugin(fid); + lit = pin ? (*pin)(l) : l; m_lits.push_back(lit); internalize_lit(lit); } @@ -620,8 +530,6 @@ namespace qe { ast_manager &m; u_map m_term2app; u_map m_root2rep; - u_map m_decls; - bool m_exclude; expr_ref_vector m_pinned; // tracks expr in the maps @@ -700,7 +608,7 @@ namespace qe { m_tg.reset_marks(); } - void solve() { + void solve_core() { ptr_vector worklist; for (term * t : m_tg.m_terms) { // skip pure terms @@ -772,9 +680,7 @@ namespace qe { while (r != &t); } - bool is_projected(const term &t) { - return m_exclude == m_decls.contains(t.get_decl_id()); - } + bool is_projected(const term &t) {return m_tg.m_is_var(t);} void mk_unpure_equalities(const term &t, expr_ref_vector &res) { expr *rep = nullptr; @@ -834,24 +740,20 @@ namespace qe { m_tg.reset_marks(); m_term2app.reset(); m_root2rep.reset(); - m_decls.reset(); m_pinned.reset(); } - expr_ref_vector project(func_decl_ref_vector const &decls, bool exclude) { + expr_ref_vector project() { expr_ref_vector res(m); - m_exclude = exclude; - for (auto *d : decls) {m_decls.insert(d->get_id(), true);} purify(); mk_lits(res); mk_pure_equalities(res); reset(); return res; } - expr_ref_vector solve(func_decl_ref_vector const &decls, bool exclude) { + expr_ref_vector solve() { expr_ref_vector res(m); - m_exclude = exclude; purify(); - solve(); + solve_core(); mk_lits(res); mk_unpure_equalities(res); reset(); @@ -860,14 +762,41 @@ namespace qe { }; } + void term_graph::solve_for_vars() { + expr_ref new_lit(m); + expr *old_lit = nullptr, *v = nullptr; + for (unsigned i = 0, sz = m_lits.size(); i < sz; ++i) { + old_lit = m_lits.get(i); + qe::solve_plugin *pin = m_plugins.get_plugin(get_family_id(m, old_lit)); + if (pin) { + new_lit = (*pin)(old_lit); + if (new_lit.get() != old_lit) { + m_lits.set(i, new_lit); + internalize_lit(new_lit); + } + if (is_pure_def(new_lit, v)) { + m_is_var.mark_solved(v); + } + } + } + m_is_var.reset_solved(); + } expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { + m_is_var.set_decls(decls, exclude); + solve_for_vars(); projector p(*this); - return p.project(decls, exclude); + m_is_var.reset(); + expr_ref_vector v = p.project(); + return v; } expr_ref_vector term_graph::solve(func_decl_ref_vector const &decls, bool exclude) { + m_is_var.set_decls(decls, exclude); + solve_for_vars(); projector p(*this); - return p.solve(decls, exclude); + expr_ref_vector v = p.solve(); + m_is_var.reset(); + return v; } } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 210941dac..e60b535c0 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -21,28 +21,31 @@ Notes: #include "ast/ast.h" #include "util/plugin_manager.h" +#include "qe/qe_solve_plugin.h" +#include "qe/qe_vartest.h" namespace qe { class term; - namespace {class projector;} - class term_graph_plugin { - family_id m_id; - public: - term_graph_plugin(family_id fid) : m_id(fid) {} - virtual ~term_graph_plugin() {} - - family_id get_family_id() const {return m_id;} - - /// Process (and potentially augment) a literal - virtual expr_ref process_lit (expr *lit) = 0; - }; - - class term_graph { friend class projector; + + class is_variable_proc : public ::is_variable_proc { + bool m_exclude; + u_map m_decls; + u_map m_solved; + public: + bool operator()(const expr *e) const override; + bool operator()(const term &t) const; + + void set_decls(const func_decl_ref_vector &decls, bool exclude); + void mark_solved(const expr *e); + void reset_solved() {m_solved.reset();} + void reset() {m_decls.reset(); m_solved.reset(); m_exclude = true;} + }; + struct term_hash { unsigned operator()(term const* t) const; }; struct term_eq { bool operator()(term const* a, term const* b) const; }; ast_manager & m; @@ -51,10 +54,11 @@ namespace qe { u_map m_app2term; ast_ref_vector m_pinned; u_map m_term2app; - plugin_manager m_plugins; + plugin_manager m_plugins; ptr_hashtable m_cg_table; vector> m_merge; + term_graph::is_variable_proc m_is_var; void merge(term &t1, term &t2); void merge_flush(); @@ -80,9 +84,10 @@ namespace qe { void mk_equalities(term const &t, expr_ref_vector &out); void mk_all_equalities(term const &t, expr_ref_vector &out); void display(std::ostream &out); - void project_core(func_decl_ref_vector const &decls, bool exclude, expr_ref_vector &result); - void solve_core(func_decl_ref_vector const &decls, bool exclude, expr_ref_vector &result); - bool is_solved_eq(expr *lhs, expr *rhs); + + bool is_pure_def(expr* atom, expr *v); + void solve_for_vars(); + public: term_graph(ast_manager &m); diff --git a/src/qe/qe_vartest.h b/src/qe/qe_vartest.h index 56d9229b8..52609893f 100644 --- a/src/qe/qe_vartest.h +++ b/src/qe/qe_vartest.h @@ -22,9 +22,10 @@ Revision History: #include "ast/ast.h" #include "util/uint_set.h" -class is_variable_proc { +// TBD: move under qe namespace +class is_variable_proc : public std::unary_function { public: - virtual bool operator()(expr* e) const = 0; + virtual bool operator()(const expr* e) const = 0; }; class is_variable_test : public is_variable_proc { @@ -42,7 +43,7 @@ public: m_num_decls(num_decls), m_var_kind(BY_NUM_DECLS) {} - bool operator()(expr* e) const override { + bool operator()(const expr* e) const override { if (!is_var(e)) { return false; } From 0ae246ad2b858f422ca0595de56cc758126f1345 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Jun 2018 12:41:01 -0700 Subject: [PATCH 1204/1283] add defs to arith solver Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 278 ++++++++++++++++++++------- src/math/simplex/model_based_opt.h | 33 +++- src/qe/qe_arith.cpp | 51 ++++- src/qe/qe_arith.h | 2 +- src/qe/qe_arrays.cpp | 4 +- src/qe/qe_arrays.h | 1 + src/qe/qe_datatypes.cpp | 3 + src/qe/qe_datatypes.h | 1 + src/qe/qe_mbp.h | 18 ++ src/test/CMakeLists.txt | 1 - src/test/arith_rewriter.cpp | 5 - src/test/main.cpp | 1 - src/test/model_based_opt.cpp | 25 ++- src/test/pdr.cpp | 128 ------------ 14 files changed, 326 insertions(+), 225 deletions(-) delete mode 100644 src/test/pdr.cpp diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 86b3cfa0c..2b175506f 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -35,11 +35,113 @@ std::ostream& operator<<(std::ostream& out, opt::ineq_type ie) { namespace opt { + /** + * Convert a row ax + coeffs + coeff = 0 into a definition for x + * x = -(coeffs + coeff)/a + * For rows ax + coeffs + coeff < 0 convert into + * x = -(coeffs + coeff - a)/a + */ + model_based_opt::def::def(row const& r, unsigned x) { + rational c = r.get_coefficient(x); + bool is_pos = c.is_pos(); + for (var const & v : r.m_vars) { + if (v.m_id != x) { + m_vars.push_back(v); + if (is_pos) m_vars.back().m_coeff.neg(); + } + } + m_coeff = r.m_coeff; + if (is_pos) m_coeff.neg(); + if (r.m_type == opt::t_lt) m_coeff += abs(c); + m_div = abs(c); + normalize(); + SASSERT(m_div.is_pos()); + } + + model_based_opt::def model_based_opt::def::operator+(def const& other) const { + def result; + vector const& vs1 = m_vars; + vector const& vs2 = other.m_vars; + vector & vs = result.m_vars; + rational c1(1), c2(1); + if (m_div != other.m_div) { + c1 = other.m_div; + c2 = m_div; + } + unsigned i = 0, j = 0; + while (i < vs1.size() || j < vs2.size()) { + unsigned v1 = UINT_MAX, v2 = UINT_MAX; + if (i < vs1.size()) v1 = vs1[i].m_id; + if (j < vs2.size()) v2 = vs2[j].m_id; + if (v1 == v2) { + vs.push_back(vs1[i]); + vs.back().m_coeff *= c1; + vs.back().m_coeff += c2 * vs2[j].m_coeff; + ++i; ++j; + if (vs.back().m_coeff.is_zero()) { + vs.pop_back(); + } + } + else if (v1 < v2) { + vs.push_back(vs1[i]); + vs.back().m_coeff *= c1; + } + else { + vs.push_back(vs2[j]); + vs.back().m_coeff *= c2; + } + } + result.m_div = c1*m_div; + result.m_coeff = (m_coeff*c1) + (other.m_coeff*c2); + result.normalize(); + return result; + } + + model_based_opt::def model_based_opt::def::operator/(rational const& r) const { + def result(*this); + result.m_div *= r; + result.normalize(); + return result; + } + + model_based_opt::def model_based_opt::def::operator*(rational const& n) const { + def result(*this); + for (var& v : result.m_vars) { + v.m_coeff *= n; + } + result.m_coeff *= n; + result.normalize(); + return result; + } + + model_based_opt::def model_based_opt::def::operator+(rational const& n) const { + def result(*this); + result.m_coeff += n * result.m_div; + result.normalize(); + return result; + } + + void model_based_opt::def::normalize() { + if (m_div.is_one()) return; + rational g(m_div); + g = gcd(g, m_coeff); + for (var const& v : m_vars) { + g = gcd(g, abs(v.m_coeff)); + if (g.is_one()) break; + } + if (!g.is_one()) { + for (var& v : m_vars) { + v.m_coeff /= g; + } + m_coeff /= g; + m_div /= g; + } + } + model_based_opt::model_based_opt() { m_rows.push_back(row()); } - bool model_based_opt::invariant() { for (unsigned i = 0; i < m_rows.size(); ++i) { @@ -105,14 +207,14 @@ namespace opt { if (find_bound(x, bound_row_index, bound_coeff, coeff.is_pos())) { SASSERT(!bound_coeff.is_zero()); TRACE("opt", display(tout << "update: " << v << " ", objective()); - for (unsigned i = 0; i < m_above.size(); ++i) { - display(tout << "resolve: ", m_rows[m_above[i]]); + for (unsigned above : m_above) { + display(tout << "resolve: ", m_rows[above]); }); - for (unsigned i = 0; i < m_above.size(); ++i) { - resolve(bound_row_index, bound_coeff, m_above[i], x); + for (unsigned above : m_above) { + resolve(bound_row_index, bound_coeff, above, x); } - for (unsigned i = 0; i < m_below.size(); ++i) { - resolve(bound_row_index, bound_coeff, m_below[i], x); + for (unsigned below : m_below) { + resolve(bound_row_index, bound_coeff, below, x); } // coeff*x + objective <= ub // a2*x + t2 <= 0 @@ -151,8 +253,7 @@ namespace opt { rational old_val = m_var2value[x]; m_var2value[x] = val; unsigned_vector const& row_ids = m_var2row_ids[x]; - for (unsigned i = 0; i < row_ids.size(); ++i) { - unsigned row_id = row_ids[i]; + for (unsigned row_id : row_ids) { rational coeff = get_coefficient(row_id, x); if (coeff.is_zero()) { continue; @@ -166,8 +267,7 @@ namespace opt { void model_based_opt::update_values(unsigned_vector const& bound_vars, unsigned_vector const& bound_trail) { - for (unsigned i = bound_trail.size(); i > 0; ) { - --i; + for (unsigned i = bound_trail.size(); i-- > 0; ) { unsigned x = bound_vars[i]; row& r = m_rows[bound_trail[i]]; rational val = r.m_coeff; @@ -222,8 +322,7 @@ namespace opt { } // update and check bounds for all other affected rows. - for (unsigned i = bound_trail.size(); i > 0; ) { - --i; + for (unsigned i = bound_trail.size(); i-- > 0; ) { unsigned x = bound_vars[i]; unsigned_vector const& row_ids = m_var2row_ids[x]; for (unsigned row_id : row_ids) { @@ -243,8 +342,7 @@ namespace opt { uint_set visited; m_above.reset(); m_below.reset(); - for (unsigned i = 0; i < row_ids.size(); ++i) { - unsigned row_id = row_ids[i]; + for (unsigned row_id : row_ids) { SASSERT(row_id != m_objective_id); if (visited.contains(row_id)) { continue; @@ -291,8 +389,7 @@ namespace opt { rational model_based_opt::get_row_value(row const& r) const { vector const& vars = r.m_vars; rational val = r.m_coeff; - for (unsigned i = 0; i < vars.size(); ++i) { - var const& v = vars[i]; + for (var const& v : vars) { val += v.m_coeff * m_var2value[v.m_id]; } return val; @@ -300,14 +397,18 @@ namespace opt { rational model_based_opt::get_coefficient(unsigned row_id, unsigned var_id) const { row const& r = m_rows[row_id]; - if (r.m_vars.empty()) { + return r.get_coefficient(var_id); + } + + rational model_based_opt::row::get_coefficient(unsigned var_id) const { + if (m_vars.empty()) { return rational::zero(); } - unsigned lo = 0, hi = r.m_vars.size(); + unsigned lo = 0, hi = m_vars.size(); while (lo < hi) { unsigned mid = lo + (hi - lo)/2; SASSERT(mid < hi); - unsigned id = r.m_vars[mid].m_id; + unsigned id = m_vars[mid].m_id; if (id == var_id) { lo = mid; break; @@ -319,12 +420,12 @@ namespace opt { hi = mid; } } - if (lo == r.m_vars.size()) { + if (lo == m_vars.size()) { return rational::zero(); } - unsigned id = r.m_vars[lo].m_id; + unsigned id = m_vars[lo].m_id; if (id == var_id) { - return r.m_vars[lo].m_coeff; + return m_vars[lo].m_coeff; } else { return rational::zero(); @@ -386,7 +487,6 @@ namespace opt { SASSERT(a1 == get_coefficient(row_src, x)); SASSERT(a1.is_pos()); SASSERT(row_src != row_dst); - SASSERT(m_rows[row_src].m_type == t_eq); if (!m_rows[row_dst].m_alive) return; rational a2 = get_coefficient(row_dst, x); mul(row_dst, a1); @@ -593,40 +693,52 @@ namespace opt { } void model_based_opt::display(std::ostream& out) const { - for (unsigned i = 0; i < m_rows.size(); ++i) { - display(out, m_rows[i]); + for (auto const& r : m_rows) { + display(out, r); } for (unsigned i = 0; i < m_var2row_ids.size(); ++i) { unsigned_vector const& rows = m_var2row_ids[i]; out << i << ": "; - for (unsigned j = 0; j < rows.size(); ++j) { - out << rows[j] << " "; + for (auto const& r : rows) { + out << r << " "; } out << "\n"; } } - void model_based_opt::display(std::ostream& out, row const& r) const { - vector const& vars = r.m_vars; - out << (r.m_alive?"+":"-") << " "; + void model_based_opt::display(std::ostream& out, vector const& vars, rational const& coeff) { for (unsigned i = 0; i < vars.size(); ++i) { if (i > 0 && vars[i].m_coeff.is_pos()) { out << "+ "; } out << vars[i].m_coeff << "* v" << vars[i].m_id << " "; } - if (r.m_coeff.is_pos()) { - out << " + " << r.m_coeff << " "; + if (coeff.is_pos()) { + out << " + " << coeff << " "; } - else if (r.m_coeff.is_neg()) { - out << r.m_coeff << " "; - } + else if (coeff.is_neg()) { + out << coeff << " "; + } + } + + std::ostream& model_based_opt::display(std::ostream& out, row const& r) { + out << (r.m_alive?"+":"-") << " "; + display(out, r.m_vars, r.m_coeff); if (r.m_type == opt::t_mod) { out << r.m_type << " " << r.m_mod << " = 0; value: " << r.m_value << "\n"; } else { out << r.m_type << " 0; value: " << r.m_value << "\n"; } + return out; + } + + std::ostream& model_based_opt::display(std::ostream& out, def const& r) { + display(out, r.m_vars, r.m_coeff); + if (!r.m_div.is_one()) { + out << " / " << r.m_div; + } + return out; } unsigned model_based_opt::add_var(rational const& value, bool is_int) { @@ -648,10 +760,10 @@ namespace opt { r.m_vars.append(coeffs.size(), coeffs.c_ptr()); bool is_int_row = true; std::sort(r.m_vars.begin(), r.m_vars.end(), var::compare()); - for (unsigned i = 0; i < coeffs.size(); ++i) { - val += m_var2value[coeffs[i].m_id] * coeffs[i].m_coeff; - SASSERT(!is_int(coeffs[i].m_id) || coeffs[i].m_coeff.is_int()); - is_int_row &= is_int(coeffs[i].m_id); + for (auto const& c : coeffs) { + val += m_var2value[c.m_id] * c.m_coeff; + SASSERT(!is_int(c.m_id) || c.m_coeff.is_int()); + is_int_row &= is_int(c.m_id); } r.m_alive = true; r.m_coeff = c; @@ -738,7 +850,7 @@ namespace opt { // t0 <= s for each s (M inequalities). // If N >= M the construction is symmetric. // - void model_based_opt::project(unsigned x) { + model_based_opt::def model_based_opt::project(unsigned x, bool compute_def) { unsigned_vector& lub_rows = m_lub; unsigned_vector& glb_rows = m_glb; unsigned_vector& mod_rows = m_mod; @@ -802,28 +914,41 @@ namespace opt { } if (!mod_rows.empty()) { - solve_mod(x, mod_rows); - return; + return solve_mod(x, mod_rows, compute_def); } if (eq_row != UINT_MAX) { - solve_for(eq_row, x); - return; + return solve_for(eq_row, x, compute_def); } - + + def result; unsigned lub_size = lub_rows.size(); unsigned glb_size = glb_rows.size(); unsigned row_index = (lub_size <= glb_size) ? lub_index : glb_index; - glb_rows.append(lub_rows); // There are only upper or only lower bounds. if (row_index == UINT_MAX) { - for (unsigned row_id : glb_rows) { - SASSERT(m_rows[row_id].m_alive); - SASSERT(!get_coefficient(row_id, x).is_zero()); - retire_row(row_id); + if (compute_def) { + if (lub_index != UINT_MAX) { + result = solve_for(lub_index, x, true); + } + else if (glb_index != UINT_MAX) { + result = solve_for(glb_index, x, true); + } } - return; + else { + for (unsigned row_id : lub_rows) retire_row(row_id); + for (unsigned row_id : glb_rows) retire_row(row_id); + } + return result; + } + + SASSERT(lub_index != UINT_MAX); + SASSERT(glb_index != UINT_MAX); + if (compute_def) { + def d1(m_rows[lub_index], x); + def d2(m_rows[lub_index], x); + result = (d1 + d2)/2; } // The number of matching lower and upper bounds is small. @@ -832,10 +957,9 @@ namespace opt { (!is_int(x) || lub_is_unit || glb_is_unit)) { for (unsigned i = 0; i < lub_size; ++i) { unsigned row_id1 = lub_rows[i]; - bool last = i + 1 == lub_rows.size(); + bool last = i + 1 == lub_size; rational coeff = get_coefficient(row_id1, x); - for (unsigned j = 0; j < glb_size; ++j) { - unsigned row_id2 = glb_rows[j]; + for (unsigned row_id2 : glb_rows) { if (last) { resolve(row_id1, coeff, row_id2, x); } @@ -845,20 +969,25 @@ namespace opt { } } } - for (unsigned i = 0; i < lub_size; ++i) { - retire_row(lub_rows[i]); - } - return; + for (unsigned row_id : lub_rows) retire_row(row_id); + + return result; } // General case. rational coeff = get_coefficient(row_index, x); + for (unsigned row_id : lub_rows) { + if (row_id != row_index) { + resolve(row_index, coeff, row_id, x); + } + } for (unsigned row_id : glb_rows) { if (row_id != row_index) { resolve(row_index, coeff, row_id, x); } } retire_row(row_index); + return result; } // @@ -876,7 +1005,7 @@ namespace opt { // x := D*x' + u // - void model_based_opt::solve_mod(unsigned x, unsigned_vector const& mod_rows) { + model_based_opt::def model_based_opt::solve_mod(unsigned x, unsigned_vector const& mod_rows, bool compute_def) { SASSERT(!mod_rows.empty()); rational D(1); for (unsigned idx : mod_rows) { @@ -914,7 +1043,11 @@ namespace opt { visited.insert(row_id); } } - project(y); + def result = project(y, compute_def); + if (compute_def) { + result = (result * D) + u; + } + return result; } // update row with: x |-> C @@ -961,16 +1094,21 @@ namespace opt { // 3x + t = 0 & 7 | (c*x + s) & ax <= u // 3 | -t & 21 | (-ct + 3s) & a-t <= 3u - void model_based_opt::solve_for(unsigned row_id1, unsigned x) { + model_based_opt::def model_based_opt::solve_for(unsigned row_id1, unsigned x, bool compute_def) { + TRACE("opt", tout << "v" << x << "\n" << m_rows[row_id1] << "\n";); rational a = get_coefficient(row_id1, x), b; + ineq_type ty = m_rows[row_id1].m_type; SASSERT(!a.is_zero()); - SASSERT(m_rows[row_id1].m_type == t_eq); SASSERT(m_rows[row_id1].m_alive); if (a.is_neg()) { a.neg(); m_rows[row_id1].neg(); } SASSERT(a.is_pos()); + if (ty == t_lt) { + SASSERT(compute_def); + m_rows[row_id1].m_coeff += a; + } if (m_var2is_int[x] && !a.is_one()) { row& r1 = m_rows[row_id1]; vector coeffs; @@ -983,8 +1121,7 @@ namespace opt { visited.insert(row_id1); for (unsigned row_id2 : row_ids) { if (!visited.contains(row_id2)) { - visited.insert(row_id2); - + visited.insert(row_id2); b = get_coefficient(row_id2, x); if (!b.is_zero()) { row& dst = m_rows[row_id2]; @@ -1002,14 +1139,19 @@ namespace opt { } } } + // TBD: -t div a + def result(m_rows[row_id1], x); retire_row(row_id1); + return result; } - - void model_based_opt::project(unsigned num_vars, unsigned const* vars) { + + vector model_based_opt::project(unsigned num_vars, unsigned const* vars, bool compute_def) { + vector result; for (unsigned i = 0; i < num_vars; ++i) { - project(vars[i]); + result.push_back(project(vars[i], compute_def)); TRACE("opt", display(tout << "After projecting: v" << vars[i] << "\n");); } + return result; } } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index 9546529f2..268d3d81d 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -60,6 +60,23 @@ namespace opt { void reset() { m_vars.reset(); m_coeff.reset(); m_value.reset(); } void neg() { for (var & v : m_vars) v.m_coeff.neg(); m_coeff.neg(); m_value.neg(); } + rational get_coefficient(unsigned x) const; + }; + + // A definition is a linear term of the form (vars + coeff) / div + struct def { + def(): m_div(1) {} + def(row const& r, unsigned x); + def(def const& other): m_vars(other.m_vars), m_coeff(other.m_coeff), m_div(other.m_div) {} + vector m_vars; + rational m_coeff; + rational m_div; + def operator+(def const& other) const; + def operator/(unsigned n) const { return *this / rational(n); } + def operator/(rational const& n) const; + def operator*(rational const& n) const; + def operator+(rational const& n) const; + void normalize(); }; private: @@ -121,12 +138,12 @@ namespace opt { void update_value(unsigned x, rational const& val); - void project(unsigned var); + def project(unsigned var, bool compute_def); - void solve_for(unsigned row_id, unsigned x); - - void solve_mod(unsigned x, unsigned_vector const& mod_rows); + def solve_for(unsigned row_id, unsigned x, bool compute_def); + def solve_mod(unsigned x, unsigned_vector const& mod_rows, bool compute_def); + bool is_int(unsigned x) const { return m_var2is_int[x]; } void retire_row(unsigned row_id); @@ -163,7 +180,7 @@ namespace opt { // // Project set of variables from inequalities. // - void project(unsigned num_vars, unsigned const* vars); + vector project(unsigned num_vars, unsigned const* vars, bool compute_def); // // Extract current rows (after projection). @@ -171,13 +188,17 @@ namespace opt { void get_live_rows(vector& rows); void display(std::ostream& out) const; - void display(std::ostream& out, row const& r) const; + static std::ostream& display(std::ostream& out, row const& r); + static std::ostream& display(std::ostream& out, def const& r); + static void display(std::ostream& out, vector const& vars, rational const& coeff); }; } std::ostream& operator<<(std::ostream& out, opt::ineq_type ie); +inline std::ostream& operator<<(std::ostream& out, opt::model_based_opt::def const& d) { return opt::model_based_opt::display(out, d); } +inline std::ostream& operator<<(std::ostream& out, opt::model_based_opt::row const& r) { return opt::model_based_opt::display(out, r); } inline std::ostream& operator<<(std::ostream& out, opt::model_based_opt::var const v) { return out << "v" << v.m_id; } diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 0623bc8bb..0b5ad72ca 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -283,14 +283,29 @@ namespace qe { typedef opt::model_based_opt::row row; typedef vector vars; + vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + return project(model, vars, lits, true); + } + void operator()(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { + project(model, vars, fmls, false); + } + + expr_ref var2expr(ptr_vector const& index2expr, var const& v) { + expr_ref t(index2expr[v.m_id], m); + if (!v.m_coeff.is_one()) { + t = a.mk_mul(a.mk_numeral(v.m_coeff, a.is_int(t)), t); + } + return t; + } + + vector project(model& model, app_ref_vector& vars, expr_ref_vector& fmls, bool compute_def) { bool has_arith = false; - for (unsigned i = 0; !has_arith && i < vars.size(); ++i) { - expr* v = vars[i].get(); + for (expr* v : vars) { has_arith |= is_arith(v); } if (!has_arith) { - return; + return vector(); } model_evaluator eval(model); // eval.set_model_completion(true); @@ -359,7 +374,7 @@ namespace qe { tout << "v" << v << " " << mk_pp(index2expr[v], m) << "\n"; } mbo.display(tout);); - mbo.project(real_vars.size(), real_vars.c_ptr()); + vector defs = mbo.project(real_vars.size(), real_vars.c_ptr(), compute_def); TRACE("qe", mbo.display(tout);); vector rows; mbo.get_live_rows(rows); @@ -419,6 +434,30 @@ namespace qe { val = eval(t); CTRACE("qe", !m.is_true(val), tout << "Evaluated " << t << " to " << val << "\n";); } + vector result; + if (compute_def) { + SASSERT(defs.size() == real_vars.size()); + for (unsigned i = 0; i < defs.size(); ++i) { + auto const& d = defs[i]; + expr* x = index2expr[real_vars[i]]; + bool is_int = a.is_int(x); + expr_ref_vector ts(m); + expr_ref t(m); + for (var const& v : d.m_vars) { + ts.push_back(var2expr(index2expr, v)); + } + ts.push_back(a.mk_numeral(d.m_coeff, is_int)); + t = a.mk_add(ts.size(), ts.c_ptr()); + if (!d.m_div.is_one() && is_int) { + t = a.mk_idiv(t, a.mk_numeral(d.m_div, is_int)); + } + else if (!d.m_div.is_one() && !is_int) { + t = a.mk_div(t, a.mk_numeral(d.m_div, is_int)); + } + result.push_back(def(expr_ref(x, m), t)); + } + } + return result; } opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { @@ -534,6 +573,10 @@ namespace qe { (*m_imp)(model, vars, lits); } + vector arith_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + return m_imp->project(model, vars, lits); + } + bool arith_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return m_imp->solve(model, vars, lits); } diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index 8e2400ac7..c01d7bbb6 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -30,7 +30,7 @@ namespace qe { bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; family_id get_family_id() override; void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; - + vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt); }; diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 651c167b6..138aed1df 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -1419,7 +1419,9 @@ namespace qe { ); } - + vector array_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + return vector(); + } }; diff --git a/src/qe/qe_arrays.h b/src/qe/qe_arrays.h index f2d69b564..3bb90335d 100644 --- a/src/qe/qe_arrays.h +++ b/src/qe/qe_arrays.h @@ -36,6 +36,7 @@ namespace qe { bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; void operator()(model& model, app_ref_vector& vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects); family_id get_family_id() override; + vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; }; }; diff --git a/src/qe/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index 770beb59d..87ae97857 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -300,6 +300,9 @@ namespace qe { return m_imp->solve(model, vars, lits); } + vector datatype_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + return vector(); + } family_id datatype_project_plugin::get_family_id() { return m_imp->dt.get_family_id(); diff --git a/src/qe/qe_datatypes.h b/src/qe/qe_datatypes.h index 9c8eb5a76..0483f4cce 100644 --- a/src/qe/qe_datatypes.h +++ b/src/qe/qe_datatypes.h @@ -35,6 +35,7 @@ namespace qe { bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) override; bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; family_id get_family_id() override; + vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; }; }; diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index bddec8065..c35351fb3 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -31,14 +31,32 @@ namespace qe { struct cant_project {}; + struct def { + expr_ref var, term; + def(expr_ref& v, expr_ref& t): var(v), term(t) {} + }; + class project_plugin { public: virtual ~project_plugin() {} virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) = 0; + /** + \brief partial solver. + */ virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) = 0; virtual family_id get_family_id() = 0; + virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { }; + /** + \brief project vars modulo model, return set of definitions for eliminated variables. + - vars in/out: returns variables that were not eliminated + - lits in/out: returns projected literals + - returns set of definitions + (TBD: in triangular form, the last definition can be substituted into definitions that come before) + */ + virtual vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) = 0; + static expr_ref pick_equality(ast_manager& m, model& model, expr* t); static void erase(expr_ref_vector& lits, unsigned& i); static void push_back(expr_ref_vector& lits, expr* lit); diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 1dc0290d8..7367a52ff 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -81,7 +81,6 @@ add_executable(test-z3 optional.cpp parray.cpp pb2bv.cpp - pdr.cpp permutation.cpp polynomial.cpp polynorm.cpp diff --git a/src/test/arith_rewriter.cpp b/src/test/arith_rewriter.cpp index a279d58b2..d0a110c4f 100644 --- a/src/test/arith_rewriter.cpp +++ b/src/test/arith_rewriter.cpp @@ -10,7 +10,6 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/reg_decl_plugins.h" #include "ast/rewriter/th_rewriter.h" #include "model/model.h" -#include "muz/pdr/pdr_util.h" #include "parsers/smt2/smt2parser.h" @@ -53,13 +52,9 @@ void tst_arith_rewriter() { expr_ref fml = parse_fml(m, example1); rw(fml); std::cout << mk_pp(fml, m) << "\n"; - pdr::normalize_arithmetic(fml); - std::cout << mk_pp(fml, m) << "\n"; fml = parse_fml(m, example2); rw(fml); std::cout << mk_pp(fml, m) << "\n"; - pdr::normalize_arithmetic(fml); - std::cout << mk_pp(fml, m) << "\n"; } diff --git a/src/test/main.cpp b/src/test/main.cpp index 41f051f24..d330610d9 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -239,7 +239,6 @@ int main(int argc, char ** argv) { TST(theory_pb); TST(simplex); TST(sat_user_scope); - TST(pdr); TST_ARGV(ddnf); TST(ddnf1); TST(model_evaluator); diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index 7b3b95afd..f2f6004ff 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -218,6 +218,12 @@ static void test4() { std::cout << "u: " << mbo.get_value(u) << "\n"; } +static void display_project(vector const& defs) { + for (auto const& d : defs) { + std::cout << d << "\n"; + } +} + static void test5() { opt::model_based_opt mbo; unsigned x = mbo.add_var(rational(2)); @@ -231,13 +237,13 @@ static void test5() { add_ineq(mbo, z, 1, u, -1, 1, opt::t_le); unsigned vars[2] = { y, z }; - mbo.project(1, vars); + display_project(mbo.project(1, vars, true)); mbo.display(std::cout); - mbo.project(1, vars); + display_project(mbo.project(1, vars, true)); mbo.display(std::cout); - mbo.project(1, vars+1); + display_project(mbo.project(1, vars+1, true)); mbo.display(std::cout); vector rows; @@ -263,7 +269,7 @@ static void test6() { add_ineq(mbo, y, 1, w, -1, 1, opt::t_le); mbo.display(std::cout); - mbo.project(1, &y); + display_project(mbo.project(1, &y, true)); mbo.display(std::cout); } @@ -285,7 +291,7 @@ static void test7() { add_ineq(mbo, y, 1, w, -1, 1, opt::t_lt); mbo.display(std::cout); - mbo.project(1, &y); + display_project(mbo.project(1, &y, true)); mbo.display(std::cout); } @@ -306,7 +312,7 @@ static void test8() { add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); mbo.display(std::cout); - mbo.project(1, &y); + display_project(mbo.project(1, &y, true)); mbo.display(std::cout); } @@ -327,7 +333,7 @@ static void test9() { add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); mbo.display(std::cout); - mbo.project(1, &y); + display_project(mbo.project(1, &y, true)); mbo.display(std::cout); } @@ -348,9 +354,9 @@ static void test10() { add_ineq(mbo, y, 3, v, -6, 1, opt::t_le); mbo.display(std::cout); - mbo.project(1, &y); + display_project(mbo.project(1, &y, true)); mbo.display(std::cout); - mbo.project(1, &x0); + display_project(mbo.project(1, &x0, true)); mbo.display(std::cout); } @@ -358,7 +364,6 @@ static void test10() { void tst_model_based_opt() { test10(); - return; check_random_ineqs(); test1(); test2(); diff --git a/src/test/pdr.cpp b/src/test/pdr.cpp deleted file mode 100644 index 45d9eea7e..000000000 --- a/src/test/pdr.cpp +++ /dev/null @@ -1,128 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - -#include "muz/pdr/pdr_context.h" -#include "ast/reg_decl_plugins.h" - - -using namespace pdr; - -static expr_ref mk_state(expr_ref_vector const& states, random_gen& rand) { - expr_ref result(states.get_manager()); - result = states[rand(states.size())]; - return result; -} - - -struct test_model_search { - struct init_test { - init_test(func_decl_ref& fn) { - ast_manager& m = fn.get_manager(); - reg_decl_plugins(m); - fn = m.mk_const_decl(symbol("f"), m.mk_bool_sort()); - } - }; - - ast_manager m; - smt_params m_smt_params; - fixedpoint_params fp_params; - context ctx; - manager pm; - func_decl_ref fn; - init_test initt; - pred_transformer pt; - random_gen rand; - model_search search; - expr_ref_vector states; - - - test_model_search(): - ctx(m_smt_params, fp_params, m), - pm(m_smt_params, 10, m), - fn(m), - initt(fn), - pt(ctx, pm, fn), - rand(10), - search(true), - states(m) { - } - - void add_tree(model_node* parent, bool force_goal) { - unsigned level = parent->level(); - search.add_leaf(*parent); - expr_ref state(m); - if (level > 0 && (force_goal || parent->is_goal())) { - search.remove_goal(*parent); - - state = mk_state(states, rand); - add_tree(alloc(model_node, parent, state, pt, level-1), false); - - state = mk_state(states, rand); - add_tree(alloc(model_node, parent, state, pt, level-1), false); - parent->check_pre_closed(); - } - } - - bool mutate() { - model_node* leaf = search.next(); - if (!leaf) return false; - unsigned level = leaf->level(); - if (level == 0) { - if (rand(2) == 0) { - leaf->display(std::cout << "backtrack to grandparent\n", 1); - search.backtrack_level(false, *leaf->parent()); - } - else { - leaf->display(std::cout << "backtrack to parent\n", 1); - search.backtrack_level(false, *leaf); - } - } - else { - leaf->display(std::cout << "grow tree\n", 1); - add_tree(leaf, true); - } - return true; - } - - void init() { - std::cout << "pdr state-hash search tree\n"; - - expr_ref state(m); - func_decl_ref fn(m); - for (unsigned i = 0; i < 10; ++i) { - std::ostringstream strm; - strm << "s" << i; - state = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort()); - fn = to_app(state)->get_decl(); - states.push_back(state); - } - state = states[0].get(); - unsigned level = 4; - for(unsigned n = 0; n < 100; ++n) { - state = mk_state(states, rand); - model_node* root = alloc(model_node, nullptr, state, pt, level); - search.set_root(root); - add_tree(root, false); - search.display(std::cout); - - while (true) { - search.well_formed(); - if (!mutate()) break; - search.display(std::cout); - } - search.reset(); - //++level; - } - search.reset(); - } - -}; - -void tst_pdr() { - test_model_search test; - - test.init(); -} From ec8e3f2aeef9c9c3bfe6ee76bf8de92450c1a525 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 12 Jun 2018 13:09:06 -0700 Subject: [PATCH 1205/1283] consolidate use of plugin by moving declarations up front (separate from constructor at this point) Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 3 +- src/qe/qe_mbi.cpp | 3 +- src/qe/qe_term_graph.cpp | 103 +++++++++++------------- src/qe/qe_term_graph.h | 14 ++-- 4 files changed, 56 insertions(+), 67 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 62d5ea3ea..d45cb9df9 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -522,8 +522,9 @@ public: for (expr* e : m_lits) lits.push_back(e); flatten_and(lits); qe::term_graph tg(m); + tg.set_vars(vars, false); tg.add_lits(lits); - expr_ref_vector p = tg.project(vars, false); + expr_ref_vector p = tg.project(); ctx.regular_stream() << p << "\n"; } diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 509800c62..09ab76559 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -206,9 +206,10 @@ namespace qe { m_dual_solver->get_unsat_core(core); TRACE("qe", tout << "core: " << core << "\n";); // project the implicant onto vars + tg.set_vars(vars, false); tg.add_lits(core); lits.reset(); - lits.append(tg.project(vars, false)); + lits.append(tg.project()); TRACE("qe", tout << "project: " << lits << "\n";); return mbi_sat; case l_undef: diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 9bf007428..d4cde6b4f 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -51,7 +51,7 @@ namespace qe { class term { // -- an app represented by this term - expr* m_expr; // NSB: to make usable with exprs + expr_ref m_expr; // NSB: to make usable with exprs // -- root of the equivalence class term* m_root; // -- next element in the equivalence class (cyclic linked list) @@ -72,7 +72,7 @@ namespace qe { ptr_vector m_children; public: - term(expr* v, u_map& app2term) : + term(expr_ref const& v, u_map& app2term) : m_expr(v), m_root(this), m_next(this), @@ -185,22 +185,24 @@ namespace qe { bool term_graph::is_variable_proc::operator()(const expr * e) const { if (!is_app(e)) return false; const app *a = ::to_app(e); - if (a->get_family_id() != null_family_id) return false; - if (m_solved.contains(a->get_decl()->get_id())) return false; - return m_exclude == m_decls.contains(a->get_decl()->get_id()); + return + a->get_family_id() == null_family_id && + !m_solved.contains(a->get_decl()) && + m_exclude == m_decls.contains(a->get_decl()); } + bool term_graph::is_variable_proc::operator()(const term &t) const { - return !t.is_theory() && m_exclude == m_decls.contains(t.get_decl_id()); + return (*this)(t.get_app()); } void term_graph::is_variable_proc::set_decls(const func_decl_ref_vector &decls, bool exclude) { reset(); m_exclude = exclude; - for (auto *d : decls) m_decls.insert(d->get_id(), true); + for (auto *d : decls) m_decls.insert(d); } void term_graph::is_variable_proc::mark_solved(const expr *e) { - if ((*this)(e)) - m_solved.insert(::to_app(e)->get_decl()->get_id(), true); + if ((*this)(e) && is_app(e)) + m_solved.insert(::to_app(e)->get_decl()); } @@ -217,7 +219,7 @@ namespace qe { reset(); } - bool term_graph::is_pure_def(expr *atom, expr *v) { + bool term_graph::is_pure_def(expr *atom, expr*& v) { expr *e = nullptr; return m.is_eq(atom, v, e) && m_is_var(v) && is_pure(m_is_var, e); } @@ -241,12 +243,21 @@ namespace qe { } void term_graph::add_lit(expr *l) { expr_ref lit(m); - - family_id fid = get_family_id(m, l); - qe::solve_plugin *pin = m_plugins.get_plugin(fid); - lit = pin ? (*pin)(l) : l; - m_lits.push_back(lit); - internalize_lit(lit); + expr_ref_vector lits(m); + lits.push_back(l); + for (unsigned i = 0; i < lits.size(); ++i) { + l = lits.get(i); + family_id fid = get_family_id(m, l); + qe::solve_plugin *pin = m_plugins.get_plugin(fid); + lit = pin ? (*pin)(l) : l; + if (m.is_and(lit)) { + lits.append(::to_app(lit)->get_num_args(), ::to_app(lit)->get_args()); + } + else { + m_lits.push_back(lit); + internalize_lit(lit); + } + } } bool term_graph::is_internalized(expr *a) { @@ -259,7 +270,8 @@ namespace qe { } term *term_graph::mk_term(expr *a) { - term * t = alloc(term, a, m_app2term); + expr_ref e(a, m); + term * t = alloc(term, e, m_app2term); if (t->get_num_args() == 0 && m.is_unique_value(a)){ t->mark_as_interpreted(); } @@ -304,13 +316,16 @@ namespace qe { } void term_graph::internalize_lit(expr* lit) { - expr *e1 = nullptr, *e2 = nullptr; + expr *e1 = nullptr, *e2 = nullptr, *v = nullptr; if (m.is_eq (lit, e1, e2)) { internalize_eq (e1, e2); } else { internalize_term(lit); } + if (is_pure_def(lit, v)) { + m_is_var.mark_solved(v); + } } void term_graph::merge_flush() { @@ -721,16 +736,8 @@ namespace qe { } // TBD: generalize for also the case of a (:var n) - bool is_solved_eq(expr *_lhs, expr* _rhs) { - if (!is_app(_lhs) || !is_app(_rhs)) return false; - app *lhs, *rhs; - lhs = ::to_app(_lhs); - rhs = ::to_app(_rhs); - - if (rhs->get_num_args() > 0) return false; - if (rhs->get_family_id() != null_family_id) return false; - - return !occurs(rhs, lhs); + bool is_solved_eq(expr *lhs, expr* rhs) { + return is_uninterp_const(rhs) && !occurs(rhs, lhs); } public: @@ -762,41 +769,21 @@ namespace qe { }; } - void term_graph::solve_for_vars() { - expr_ref new_lit(m); - expr *old_lit = nullptr, *v = nullptr; - for (unsigned i = 0, sz = m_lits.size(); i < sz; ++i) { - old_lit = m_lits.get(i); - qe::solve_plugin *pin = m_plugins.get_plugin(get_family_id(m, old_lit)); - if (pin) { - new_lit = (*pin)(old_lit); - if (new_lit.get() != old_lit) { - m_lits.set(i, new_lit); - internalize_lit(new_lit); - } - if (is_pure_def(new_lit, v)) { - m_is_var.mark_solved(v); - } - } - } - m_is_var.reset_solved(); - } - expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool exclude) { + void term_graph::set_vars(func_decl_ref_vector const& decls, bool exclude) { m_is_var.set_decls(decls, exclude); - solve_for_vars(); - projector p(*this); - m_is_var.reset(); - expr_ref_vector v = p.project(); - return v; } - expr_ref_vector term_graph::solve(func_decl_ref_vector const &decls, bool exclude) { - m_is_var.set_decls(decls, exclude); - solve_for_vars(); + expr_ref_vector term_graph::project() { + m_is_var.reset_solved(); projector p(*this); - expr_ref_vector v = p.solve(); m_is_var.reset(); - return v; + return p.project(); + } + + expr_ref_vector term_graph::solve() { + m_is_var.reset_solved(); + projector p(*this); + return p.solve(); } } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index e60b535c0..ac13e1e44 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -34,8 +34,7 @@ namespace qe { class is_variable_proc : public ::is_variable_proc { bool m_exclude; - u_map m_decls; - u_map m_solved; + obj_hashtable m_decls, m_solved; public: bool operator()(const expr *e) const override; bool operator()(const term &t) const; @@ -85,7 +84,7 @@ namespace qe { void mk_all_equalities(term const &t, expr_ref_vector &out); void display(std::ostream &out); - bool is_pure_def(expr* atom, expr *v); + bool is_pure_def(expr* atom, expr *& v); void solve_for_vars(); @@ -93,6 +92,8 @@ namespace qe { term_graph(ast_manager &m); ~term_graph(); + void set_vars(func_decl_ref_vector const& decls, bool exclude); + ast_manager& get_ast_manager() const { return m;} void add_lit(expr *lit); @@ -110,10 +111,9 @@ namespace qe { * onto the vocabulary of decls (if exclude is false) or outside the * vocabulary of decls (if exclude is true). */ - expr_ref_vector project(func_decl_ref_vector const& decls, bool exclude); - expr_ref_vector solve(func_decl_ref_vector const& decls, bool exclude); - - + expr_ref_vector project(); + expr_ref_vector solve(); + }; } From 5e198f4119097b8718baae4f37ca9768ce159753 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 12 Jun 2018 13:28:49 -0700 Subject: [PATCH 1206/1283] Fix clang compilation issues --- src/qe/qe_mbp.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index c35351fb3..0bb8ba00f 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -33,7 +33,7 @@ namespace qe { struct def { expr_ref var, term; - def(expr_ref& v, expr_ref& t): var(v), term(t) {} + def(const expr_ref& v, expr_ref& t): var(v), term(t) {} }; class project_plugin { @@ -69,17 +69,17 @@ namespace qe { impl * m_impl; public: mbp(ast_manager& m, params_ref const& p = params_ref()); - + ~mbp(); void updt_params(params_ref const& p); - + static void get_param_descrs(param_descrs & r); - + /** \brief - Apply model-based qe on constants provided as vector of variables. - Return the updated formula and updated set of variables that were not eliminated. + Apply model-based qe on constants provided as vector of variables. + Return the updated formula and updated set of variables that were not eliminated. */ void operator()(bool force_elim, app_ref_vector& vars, model& mdl, expr_ref_vector& fmls); @@ -90,13 +90,13 @@ namespace qe { void solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); /** - \brief + \brief Extract literals from formulas based on model. */ void extract_literals(model& model, expr_ref_vector& lits); /** - \brief + \brief Maximize objective t under current model for constraints in fmls. */ opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt); @@ -105,11 +105,11 @@ namespace qe { \brief Apply spacer friendly MBP. Use parameters to control behavior. - - reduce_all_selects (false) - - dont_sub (false) + - reduce_all_selects (false) + - dont_sub (false) */ void spacer(app_ref_vector& vars, model& mdl, expr_ref& fml); }; } -#endif +#endif From b246389267eba16a14415650f41c91b0eddef301 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 12 Jun 2018 13:41:45 -0700 Subject: [PATCH 1207/1283] Don't reset m_is_var in project --- src/qe/qe_term_graph.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index d4cde6b4f..82b6e9d2e 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -185,9 +185,9 @@ namespace qe { bool term_graph::is_variable_proc::operator()(const expr * e) const { if (!is_app(e)) return false; const app *a = ::to_app(e); - return + return a->get_family_id() == null_family_id && - !m_solved.contains(a->get_decl()) && + !m_solved.contains(a->get_decl()) && m_exclude == m_decls.contains(a->get_decl()); } @@ -774,13 +774,14 @@ namespace qe { } expr_ref_vector term_graph::project() { + // reset solved vars so that they are not considered pure by projector m_is_var.reset_solved(); projector p(*this); - m_is_var.reset(); return p.project(); } expr_ref_vector term_graph::solve() { + // reset solved vars so that they are not considered pure by projector m_is_var.reset_solved(); projector p(*this); return p.solve(); From 535b8893aea4d13669944e527041f2bd2d910779 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Tue, 12 Jun 2018 17:23:46 -0700 Subject: [PATCH 1208/1283] Complete euf project with eq and diseq on pure representatives --- src/qe/qe_mbi.cpp | 43 ++++++++++++++++++++-------------------- src/qe/qe_term_graph.cpp | 39 ++++++++++++++++++++++++++++++++++++ src/qe/qe_term_graph.h | 10 +++++----- 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 09ab76559..ae989ba02 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -33,18 +33,18 @@ Notes: Sketch of approach by example: A: s <= 2a <= t & f(a) = q - + B: t <= 2b <= s + 1 & f(b) != q 1. Extract arithmetic consequences of A over shared vocabulary. - A -> s <= t & (even(t) | s < t) - + A -> s <= t & (even(t) | s < t) + 2a. Send to B, have B solve shared variables with EUF_B. epsilon b . B & A_pure - epsilon b . t <= 2b <= s + 1 & s <= t & (even(t) | s < t) - = t <= s + 1 & (even(t) | t <= s) & s <= t & (even(t) | s < t) - = even(t) & t = s + epsilon b . t <= 2b <= s + 1 & s <= t & (even(t) | s < t) + = t <= s + 1 & (even(t) | t <= s) & s <= t & (even(t) | s < t) + = even(t) & t = s b := t div 2 B & A_pure -> B[b/t div 2] = f(t div 2) != q & t <= s + 1 @@ -53,13 +53,13 @@ Notes: A & B_pure -> false Invoke the ping-pong principle to extract interpolant. - + 2b. Solve for shared variables with EUF. - epsilon a . A + epsilon a . A = a := (s + 1) div 2 & s < t & f((s + 1) div 2) = q - 3b. Send to B. Produces core + 3b. Send to B. Produces core s < t & f((s + 1) div 2) = q 4b Solve again in arithmetic for shared variables with EUF. @@ -71,7 +71,7 @@ Notes: Send to B, produces core (s != t | f(t div 2) != q) 5b. There is no longer a solution for A. A is unsat. - + --*/ #include "ast/ast_util.h" @@ -138,7 +138,7 @@ namespace qe { void prop_mbi_plugin::block(expr_ref_vector const& lits) { m_solver->assert_expr(mk_not(mk_and(lits))); - } + } // ------------------------------- // euf_mbi, TBD @@ -158,8 +158,8 @@ namespace qe { void operator()(expr*) {} }; - euf_mbi_plugin::euf_mbi_plugin(solver* s, solver* sNot): - m(s->get_manager()), + euf_mbi_plugin::euf_mbi_plugin(solver* s, solver* sNot): + m(s->get_manager()), m_atoms(m), m_solver(s), m_dual_solver(sNot) { @@ -205,11 +205,11 @@ namespace qe { // use the dual solver to find a 'small' implicant m_dual_solver->get_unsat_core(core); TRACE("qe", tout << "core: " << core << "\n";); - // project the implicant onto vars + // project the implicant onto vars tg.set_vars(vars, false); tg.add_lits(core); - lits.reset(); - lits.append(tg.project()); + lits.reset(); + lits.append(tg.project(*mdl)); TRACE("qe", tout << "project: " << lits << "\n";); return mbi_sat; case l_undef: @@ -232,8 +232,8 @@ namespace qe { void euf_mbi_plugin::block(expr_ref_vector const& lits) { m_solver->assert_expr(mk_not(mk_and(lits))); - } - + } + /** -------------------------------------------------------------- * ping-pong interpolation of Gurfinkel & Vizel @@ -255,7 +255,7 @@ namespace qe { auto* t2 = turn ? &b : &a; mbi_result next_res = (*t1)(vars, lits, mdl); switch (next_res) { - case mbi_sat: + case mbi_sat: if (last_res == mbi_sat) { itp = nullptr; return l_true; @@ -264,7 +264,7 @@ namespace qe { break; // continue case mbi_unsat: { if (lits.empty()) { - // TBD, either a => itp and itp => !b + // TBD, either a => itp and itp => !b // or b => itp and itp => !a itp = mk_and(itps[!turn]); return l_false; @@ -282,7 +282,7 @@ namespace qe { case mbi_augment: break; case mbi_undef: - return l_undef; + return l_undef; } turn = !turn; last_res = next_res; @@ -319,4 +319,3 @@ namespace qe { } } }; - diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 82b6e9d2e..467a0cc48 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -24,6 +24,7 @@ Notes: #include "ast/for_each_expr.h" #include "ast/occurs.h" #include "qe/qe_term_graph.h" +#include "model/model_evaluator.h" namespace qe { @@ -546,6 +547,7 @@ namespace qe { u_map m_term2app; u_map m_root2rep; + model_ref m_model; expr_ref_vector m_pinned; // tracks expr in the maps expr* mk_pure(term const& t) { @@ -565,6 +567,7 @@ namespace qe { return pure; } + bool is_better_rep(expr *t1, expr *t2) { if (!t2) return t1 != nullptr; return m.is_unique_value(t1) && !m.is_unique_value(t2); @@ -740,20 +743,49 @@ namespace qe { return is_uninterp_const(rhs) && !occurs(rhs, lhs); } + /// Add equalities and disequalities for all pure representatives + /// based on their equivalence in the model + void model_complete(expr_ref_vector &res) { + if (!m_model) return; + obj_map val2rep; + model_evaluator mev(*m_model); + for (auto &kv : m_root2rep) { + expr *rep = kv.m_value; + expr_ref val(m); + expr *u = nullptr; + if (!mev.eval(rep, val)) continue; + if (val2rep.find(val, u)) { + res.push_back(m.mk_eq(u, rep)); + } + else { + val2rep.insert(val, rep); + } + } + ptr_buffer reps; + for (auto &kv : val2rep) { + reps.push_back(kv.m_value); + } + res.push_back(m.mk_distinct(reps.size(), reps.c_ptr())); + } + public: projector(term_graph &tg) : m_tg(tg), m(m_tg.m), m_pinned(m) {} + void set_model(model &mdl) { m_model = &mdl; } + void reset() { m_tg.reset_marks(); m_term2app.reset(); m_root2rep.reset(); m_pinned.reset(); + m_model.reset(); } expr_ref_vector project() { expr_ref_vector res(m); purify(); mk_lits(res); mk_pure_equalities(res); + model_complete(res); reset(); return res; } @@ -780,6 +812,13 @@ namespace qe { return p.project(); } + expr_ref_vector term_graph::project(model &mdl) { + m_is_var.reset_solved(); + projector p(*this); + p.set_model(mdl); + return p.project(); + } + expr_ref_vector term_graph::solve() { // reset solved vars so that they are not considered pure by projector m_is_var.reset_solved(); diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index ac13e1e44..97e14dc62 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -23,6 +23,7 @@ Notes: #include "util/plugin_manager.h" #include "qe/qe_solve_plugin.h" #include "qe/qe_vartest.h" +#include "model/model.h" namespace qe { @@ -85,8 +86,6 @@ namespace qe { void display(std::ostream &out); bool is_pure_def(expr* atom, expr *& v); - void solve_for_vars(); - public: term_graph(ast_manager &m); @@ -111,9 +110,10 @@ namespace qe { * onto the vocabulary of decls (if exclude is false) or outside the * vocabulary of decls (if exclude is true). */ - expr_ref_vector project(); - expr_ref_vector solve(); - + expr_ref_vector project(); + expr_ref_vector solve(); + expr_ref_vector project(model &mdl); + }; } From 81575fae7c3b35a0c4cdf59c9d450a8ff445c078 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Jun 2018 13:34:31 -0700 Subject: [PATCH 1209/1283] Remove unused function --- src/qe/qe_arrays.cpp | 108 ++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 57 deletions(-) diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index 138aed1df..a4da829a0 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -54,10 +54,10 @@ namespace { app_ref m_peq; // partial equality application app_ref m_eq; // equivalent std equality using def. of partial eq array_util m_arr_u; - + public: static const char* PARTIAL_EQ; - + peq (app* p, ast_manager& m): m (m), m_lhs (p->get_arg (0), m), @@ -79,7 +79,7 @@ namespace { m_diff_indices.push_back (vec); } } - + peq (expr* lhs, expr* rhs, vector const& diff_indices, ast_manager& m): m (m), m_lhs (lhs, m), @@ -102,13 +102,13 @@ namespace { } m_decl = m.mk_func_decl (symbol (PARTIAL_EQ), sorts.size (), sorts.c_ptr (), m.mk_bool_sort ()); } - + expr_ref lhs () { return m_lhs; } - + expr_ref rhs () { return m_rhs; } - + void get_diff_indices (vector& result) { result.append(m_diff_indices); } - + app_ref mk_peq () { if (!m_peq) { ptr_vector args; @@ -121,18 +121,18 @@ namespace { } return m_peq; } - + app_ref mk_eq (app_ref_vector& aux_consts, bool stores_on_rhs = true) { if (!m_eq) { expr_ref lhs (m_lhs, m), rhs (m_rhs, m); if (!stores_on_rhs) { std::swap (lhs, rhs); - } + } // lhs = (...(store (store rhs i0 v0) i1 v1)...) sort* val_sort = get_array_range (m.get_sort (lhs)); for (expr_ref_vector const& diff : m_diff_indices) { ptr_vector store_args; - store_args.push_back (rhs); + store_args.push_back (rhs); store_args.append (diff.size(), diff.c_ptr()); app_ref val(m.mk_fresh_const ("diff", val_sort), m); store_args.push_back (val); @@ -145,8 +145,8 @@ namespace { } }; - const char* peq::PARTIAL_EQ = "!partial_eq"; - + const char* peq::PARTIAL_EQ = "!partial_eq"; + bool is_partial_eq (app* a) { return a->get_decl ()->get_name () == peq::PARTIAL_EQ; } @@ -160,11 +160,6 @@ namespace qe { return true; } - static bool is_eq(vector const& xs, vector const& ys) { - for (unsigned i = 0; i < xs.size(); ++i) if (xs[i] != ys[i]) return false; - return true; - } - static expr_ref mk_eq(expr_ref_vector const& xs, expr_ref_vector const& ys) { ast_manager& m = xs.get_manager(); expr_ref_vector eqs(m); @@ -177,9 +172,9 @@ namespace qe { * where x appears and the equalities do not evaluate to false in the current model. * 2. Track them as partial equivalence relations. * 3. Sort them according to nesting depth. - * 4. Solve for x by potentially introducing fresh variables. - * Thus, (store x i v) = y, then - * x = (store y i w), (select y i) = v, where w is fresh and evaluates to (select x i). + * 4. Solve for x by potentially introducing fresh variables. + * Thus, (store x i v) = y, then + * x = (store y i w), (select y i) = v, where w is fresh and evaluates to (select x i). * Generally, equalities are tracked as x =_idxs y, where x, y are equal up to idxs. */ @@ -524,9 +519,9 @@ namespace qe { bool lhs_has_v = (lhs == m_v || m_has_stores_v.is_marked (lhs)); bool rhs_has_v = (rhs == m_v || m_has_stores_v.is_marked (rhs)); app* store = nullptr; - + SASSERT (lhs_has_v || rhs_has_v); - + if (!lhs_has_v && is_app(rhs)) { store = to_app (rhs); } @@ -538,7 +533,7 @@ namespace qe { // put it in the beginning to simplify it away return 0; } - + unsigned nd = 0; // nesting depth for (nd = 1; m_arr_u.is_store (store); nd++, store = to_app (store->get_arg (0))) /* empty */ ; @@ -635,7 +630,7 @@ namespace qe { M = &mdl; m_mev = &mev; - unsigned j = 0; + unsigned j = 0; for (unsigned i = 0; i < arr_vars.size (); i++) { reset_v (); m_v = arr_vars.get (i); @@ -798,14 +793,14 @@ namespace qe { /** * \brief reduce (select (store (store x i1 v1) i2 v2) idx) under model M - * such that the result is v2 if idx = i2 under M, it is v1 if idx = i1, idx != i2 under M, + * such that the result is v2 if idx = i2 under M, it is v1 if idx = i1, idx != i2 under M, * and it is (select x idx) if idx != i1, idx !+ i2 under M. */ expr* reduce_core (app *a) { if (!m_arr_u.is_store (a->get_arg (0))) return a; - expr* array = a->get_arg(0); + expr* array = a->get_arg(0); unsigned arity = get_array_arity(m.get_sort(array)); - + expr* const* js = a->get_args() + 1; while (m_arr_u.is_store (array)) { @@ -888,7 +883,7 @@ namespace qe { * and generally distinct(i1, i2, i3) for arbitrary index sorts. * - for equal indices accumulate constraint i1 = i2, i3 = i5, .. * - introduce variables v1, v2, .., for each equivalence class. - * - replace occurrences of select by v1, v2, ... + * - replace occurrences of select by v1, v2, ... * - update M to evaluate v1, v2, the same as (select a i1) (select a i2) */ @@ -900,10 +895,10 @@ namespace qe { expr_ref_vector val; vector rval; idx_val(expr_ref_vector & idx, expr_ref_vector & val, vector const& rval): idx(idx), val(val), rval(rval) {} - idx_val& operator=(idx_val const& o) { + idx_val& operator=(idx_val const& o) { idx.reset(); val.reset(); rval.reset(); idx.append(o.idx); val.append(o.val); rval.append(o.rval); - return *this; + return *this; } }; ast_manager& m; @@ -981,7 +976,7 @@ namespace qe { compare_idx(array_project_selects_util& u):u(u) {} bool operator()(idx_val const& x, idx_val const& y) { SASSERT(x.rval.size() == y.rval.size()); - for (unsigned j = 0; j < x.rval.size(); ++j) { + for (unsigned j = 0; j < x.rval.size(); ++j) { rational const& xv = x.rval[j]; rational const& yv = y.rval[j]; if (xv < yv) return true; @@ -1004,7 +999,7 @@ namespace qe { SASSERT(xs.size() == ys.size() && !xs.empty()); expr_ref result(mk_lt(xs.back(), ys.back()), m); for (unsigned i = xs.size()-1; i-- > 0; ) { - result = m.mk_or(mk_lt(xs[i], ys[i]), + result = m.mk_or(mk_lt(xs[i], ys[i]), m.mk_and(m.mk_eq(xs[i], ys[i]), result)); } return result; @@ -1028,9 +1023,9 @@ namespace qe { if (!m_ari_u.is_real(srt) && !m_ari_u.is_int(srt) && !m_bv_u.is_bv_sort(srt)) { TRACE("qe", tout << "non-numeric index sort for Ackerman" << mk_pp(srt, m) << "\n";); is_numeric = false; - } + } } - + unsigned start = m_idxs.size (); // append at the end for (app * a : sel_terms) { expr_ref_vector idxs(m, arity, a->get_args() + 1); @@ -1045,7 +1040,7 @@ namespace qe { // add equality (idx == repr) m_idx_lits.push_back (mk_eq (idxs, m_idxs[j].idx)); is_new = false; - break; + break; } if (is_new) { // new repr, val, and sel const @@ -1067,7 +1062,7 @@ namespace qe { else if (is_numeric) { // sort reprs by their value and add a chain of strict inequalities compare_idx cmp(*this); - std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); + std::sort(m_idxs.begin() + start, m_idxs.end(), cmp); for (unsigned i = start; i + 1 < m_idxs.size(); ++i) { m_idx_lits.push_back (mk_lex_lt(m_idxs[i].idx, m_idxs[i+1].idx)); } @@ -1183,7 +1178,7 @@ namespace qe { expr_ref_vector m_values; expr* const* m_vars; - indices(ast_manager& m, model& model, unsigned n, expr* const* vars): + indices(ast_manager& m, model& model, unsigned n, expr* const* vars): m_values(m), m_vars(vars) { expr_ref val(m); for (unsigned i = 0; i < n; ++i) { @@ -1192,11 +1187,11 @@ namespace qe { } } }; - + ast_manager& m; array_util a; scoped_ptr m_var; - + imp(ast_manager& m): m(m), a(m) {} ~imp() {} @@ -1209,7 +1204,7 @@ namespace qe { if (m.is_true(lits[i].get())) { project_plugin::erase(lits, i); } - } + } } bool contains_x(expr* e) { @@ -1223,7 +1218,7 @@ namespace qe { lits.push_back(m.mk_eq(x.m_vars[j], y.m_vars[j])); } } - + bool solve_eq(model& model, app_ref_vector& vars, expr_ref_vector& lits) { // find an equality to solve for. expr* s, *t; @@ -1270,13 +1265,13 @@ namespace qe { var = m.mk_fresh_const("value", range); vars.push_back(var); args.reset(); - + args.push_back (s); args.append(idxs[i].m_values.size(), idxs[i].m_vars); sel = a.mk_select (args.size (), args.c_ptr ()); VERIFY (model.eval (sel, val)); model.register_decl (var->get_decl (), val); - + args[0] = result; args.push_back(var); result = a.mk_store(args.size(), args.c_ptr()); @@ -1297,7 +1292,7 @@ namespace qe { if (contains_x(s->get_arg(i))) { return false; } - } + } unsigned i; expr_ref_vector args(m); switch (contains(idx, idxs, i)) { @@ -1317,7 +1312,7 @@ namespace qe { return solve(model, to_app(s->get_arg(0)), t, idxs, vars, lits); case l_undef: return false; - } + } } return false; } @@ -1325,13 +1320,13 @@ namespace qe { lbool contains(indices const& idx, vector const& idxs, unsigned& j) { for (unsigned i = 0; i < idxs.size(); ++i) { switch (compare(idx, idxs[i])) { - case l_true: + case l_true: j = i; return l_true; case l_false: break; case l_undef: - return l_undef; + return l_undef; } } return l_false; @@ -1355,25 +1350,25 @@ namespace qe { lbool compare(expr* val1, expr* val2) { if (m.are_equal (val1, val2)) return l_true; if (m.are_distinct (val1, val2)) return l_false; - + if (is_uninterp(val1) || is_uninterp(val2)) { // TBD chase definition of nested array. return l_undef; } return l_undef; - } + } }; - - + + array_project_plugin::array_project_plugin(ast_manager& m) { m_imp = alloc(imp, m); } - + array_project_plugin::~array_project_plugin() { dealloc(m_imp); } - + bool array_project_plugin::operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { ast_manager& m = vars.get_manager(); app_ref_vector vvars(m, 1, &var); @@ -1387,7 +1382,7 @@ namespace qe { bool array_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return m_imp->solve(model, vars, lits); } - + family_id array_project_plugin::get_family_id() { return m_imp->a.get_family_id(); } @@ -1406,9 +1401,9 @@ namespace qe { // 2. reduce selects array_select_reducer rs (m); rs (mdl, arr_vars, fml, reduce_all_selects); - + TRACE ("qe", tout << "Reduced selects:\n" << fml << "\n"; ); - + // 3. project selects using model based ackermannization array_project_selects_util ps (m); ps (mdl, arr_vars, fml, aux_vars); @@ -1424,4 +1419,3 @@ namespace qe { } }; - From d38879e478546151ee7cb46cd7a0583e678a043c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Jun 2018 13:35:27 -0700 Subject: [PATCH 1210/1283] Renamed spacer options --- src/muz/base/fixedpoint_params.pyg | 92 +++++++++----------------- src/muz/spacer/spacer_context.cpp | 51 +++++++------- src/muz/spacer/spacer_context.h | 14 ++-- src/muz/spacer/spacer_dl_interface.cpp | 2 +- src/muz/spacer/spacer_pdr.cpp | 2 +- 5 files changed, 67 insertions(+), 94 deletions(-) diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index f11e2faf9..7e92b0d2c 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -56,43 +56,19 @@ def_module_params('fixedpoint', "table columns, if it would have been empty otherwise"), ('datalog.subsumption', BOOL, True, "if true, removes/filters predicates with total transitions"), - ('pdr.bfs_model_search', BOOL, True, - "use BFS strategy for expanding model search"), - ('pdr.farkas', BOOL, True, - "use lemma generator based on Farkas (for linear real arithmetic)"), ('generate_proof_trace', BOOL, False, "trace for 'sat' answer as proof object"), - ('pdr.flexible_trace', BOOL, False, - "allow PDR generate long counter-examples " + - "by extending candidate trace within search area"), - ('pdr.flexible_trace_depth', UINT, UINT_MAX, - 'Controls the depth (below the current level) at which flexible trace can be applied'), - ('pdr.use_model_generalizer', BOOL, False, - "use model for backwards propagation (instead of symbolic simulation)"), - ('pdr.validate_result', BOOL, False, + ('spacer.push_pob', BOOL, False, "push blocked pobs to higher level"), + ('spacer.push_pob_max_depth', UINT, UINT_MAX, + 'Maximum depth at which push_pob is enabled'), + ('validate', BOOL, False, "validate result (by proof checking or model checking)"), - ('pdr.simplify_formulas_pre', BOOL, False, - "simplify derived formulas before inductive propagation"), - ('pdr.simplify_formulas_post', BOOL, False, - "simplify derived formulas after inductive propagation"), - ('pdr.use_multicore_generalizer', BOOL, False, - "extract multiple cores for blocking states"), - ('pdr.use_inductive_generalizer', BOOL, True, + ('spacer.simplify_lemmas_pre', BOOL, False, + "simplify derived lemmas before inductive propagation"), + ('spacer.simplify_lemmas_post', BOOL, False, + "simplify derived lemmas after inductive propagation"), + ('spacer.use_inductive_generalizer', BOOL, True, "generalize lemmas using induction strengthening"), - ('pdr.use_arith_inductive_generalizer', BOOL, False, - "generalize lemmas using arithmetic heuristics for induction strengthening"), - ('pdr.use_convex_closure_generalizer', BOOL, False, - "generalize using convex closures of lemmas"), - ('pdr.use_convex_interior_generalizer', BOOL, False, - "generalize using convex interiors of lemmas"), - ('pdr.cache_mode', UINT, 0, "use no (0), symbolic (1) or explicit " + - "cache (2) for model search"), - ('pdr.inductive_reachability_check', BOOL, False, - "assume negation of the cube on the previous level when " + - "checking for reachability (not only during cube weakening)"), - ('pdr.max_num_contexts', UINT, 500, "maximal number of contexts to create"), - ('pdr.try_minimize_core', BOOL, False, - "try to reduce core size (before inductive minimization)"), - ('pdr.utvpi', BOOL, True, 'Enable UTVPI strategy'), + ('spacer.max_num_contexts', UINT, 500, "maximal number of contexts to create"), ('print_fixedpoint_extensions', BOOL, True, "use SMT-LIB2 fixedpoint extensions, instead of pure SMT2, " + "when printing rules"), @@ -126,11 +102,11 @@ def_module_params('fixedpoint', ('xform.compress_unbound', BOOL, True, "compress tails with unbound variables"), ('xform.fix_unbound_vars', BOOL, False, "fix unbound variables in tail"), ('xform.unfold_rules', UINT, 0, - "unfold rules statically using iterative squarring"), + "unfold rules statically using iterative squaring"), ('xform.slice', BOOL, True, "simplify clause set using slicing"), ('xform.karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), - ('spacer.use_eqclass', BOOL, False, "Generalizes equalities to equivalence classes"), + ('spacer.use_euf_gen', BOOL, False, 'Generalize lemmas and pobs using implied equalities'), ('xform.transform_arrays', BOOL, False, "Rewrites arrays equalities and applies select over store"), ('xform.instantiate_arrays', BOOL, False, @@ -149,36 +125,31 @@ def_module_params('fixedpoint', ('xform.tail_simplifier_pve', BOOL, True, "propagate_variable_equivalences"), ('xform.subsumption_checker', BOOL, True, "Enable subsumption checker (no support for model conversion)"), ('xform.coi', BOOL, True, "use cone of influence simplification"), - ('spacer.order_children', UINT, 0, 'SPACER: order of enqueuing children in non-linear rules : 0 (original), 1 (reverse)'), - ('spacer.eager_reach_check', BOOL, True, 'SPACER: eagerly check if a query is reachable using reachability facts of predecessors'), + ('spacer.order_children', UINT, 0, 'SPACER: order of enqueuing children in non-linear rules : 0 (original), 1 (reverse), 2 (random)'), ('spacer.use_lemma_as_cti', BOOL, False, 'SPACER: use a lemma instead of a CTI in flexible_trace'), - ('spacer.reset_obligation_queue', BOOL, True, 'SPACER: reset obligation queue when entering a new level'), + ('spacer.reset_pob_queue', BOOL, True, 'SPACER: reset pob obligation queue when entering a new level'), ('spacer.use_array_eq_generalizer', BOOL, True, 'SPACER: attempt to generalize lemmas with array equalities'), ('spacer.use_derivations', BOOL, True, 'SPACER: using derivation mechanism to cache intermediate results for non-linear rules'), ('xform.array_blast', BOOL, False, "try to eliminate local array terms using Ackermannization -- some array terms may remain"), ('xform.array_blast_full', BOOL, False, "eliminate all local array variables by QE"), - ('spacer.skip_propagate', BOOL, False, "Skip propagate/pushing phase. Turns PDR into a BMC that returns either reachable or unknown"), + ('spacer.propagate', BOOL, True, 'Enable propagate/pushing phase'), ('spacer.max_level', UINT, UINT_MAX, "Maximum level to explore"), ('spacer.elim_aux', BOOL, True, "Eliminate auxiliary variables in reachability facts"), ('spacer.blast_term_ite', BOOL, True, "Expand non-Boolean ite-terms"), - ('spacer.nondet_tie_break', BOOL, False, "Break ties in obligation queue non-deterministically"), ('spacer.reach_dnf', BOOL, True, "Restrict reachability facts to DNF"), ('bmc.linear_unrolling_depth', UINT, UINT_MAX, "Maximal level to explore"), ('spacer.iuc.split_farkas_literals', BOOL, False, "Split Farkas literals"), - ('spacer.native_mbp', BOOL, False, "Use native mbp of Z3"), + ('spacer.native_mbp', BOOL, True, "Use native mbp of Z3"), ('spacer.eq_prop', BOOL, True, "Enable equality and bound propagation in arithmetic"), ('spacer.weak_abs', BOOL, True, "Weak abstraction"), ('spacer.restarts', BOOL, False, "Enable reseting obligation queue"), ('spacer.restart_initial_threshold', UINT, 10, "Intial threshold for restarts"), ('spacer.random_seed', UINT, 0, "Random seed to be used by SMT solver"), - ('spacer.ground_cti', BOOL, True, "Require CTI to be ground"), - ('spacer.vs.dump_benchmarks', BOOL, False, 'dump benchmarks in virtual solver'), - ('spacer.vs.dump_min_time', DOUBLE, 5.0, 'min time to dump benchmark'), - ('spacer.vs.recheck', BOOL, False, 're-check locally during benchmark dumping'), - ('spacer.mbqi', BOOL, True, 'use model-based quantifier instantiation'), + + ('spacer.mbqi', BOOL, True, 'Enable mbqi'), ('spacer.keep_proxy', BOOL, True, 'keep proxy variables (internal parameter)'), - ('spacer.q3.instantiate', BOOL, True, 'instantiate quantified lemmas'), - ('spacer.q3', BOOL, True, 'allow quantified lemmas in frames'), + ('spacer.q3', BOOL, True, 'Allow quantified lemmas in frames'), + ('spacer.q3.instantiate', BOOL, True, 'Instantiate quantified lemmas'), ('spacer.iuc', UINT, 1, '0 = use old implementation of unsat-core-generation, ' + '1 = use new implementation of IUC generation, ' + @@ -187,21 +158,24 @@ def_module_params('fixedpoint', '0 = use simple Farkas plugin, ' + '1 = use simple Farkas plugin with constant from other partition (like old unsat-core-generation),' + '2 = use Gaussian elimination optimization (broken), 3 = use additive IUC plugin'), - ('spacer.iuc.old_hyp_reducer', BOOL, True, 'use old hyp reducer instead of new implementation, for debugging only'), - ('spacer.lemma_sanity_check', BOOL, False, 'check during generalization whether lemma is actually correct'), - ('spacer.reuse_pobs', BOOL, True, 'reuse POBs'), - ('spacer.iuc.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut'), - ('spacer.iuc.debug_proof', BOOL, False, 'prints proof used by unsat-core-learner for debugging purposes'), - ('spacer.simplify_pob', BOOL, False, 'simplify POBs by removing redundant constraints'), + ('spacer.iuc.old_hyp_reducer', BOOL, False, 'use old hyp reducer instead of new implementation, for debugging only'), + ('spacer.validate_lemmas', BOOL, False, 'Validate each lemma after generalization'), + ('spacer.reuse_pobs', BOOL, True, 'Reuse pobs'), + ('spacer.ground_pobs', BOOL, True, 'Ground pobs by using values from a model'), + ('spacer.iuc.print_farkas_stats', BOOL, False, 'prints for each proof how many Farkas lemmas it contains and how many of these participate in the cut (for debugging)'), + ('spacer.iuc.debug_proof', BOOL, False, 'prints proof used by unsat-core-learner for debugging purposes (debugging)'), + ('spacer.simplify_pob', BOOL, False, 'simplify pobs by removing redundant constraints'), ('spacer.q3.use_qgen', BOOL, False, 'use quantified lemma generalizer'), ('spacer.q3.qgen.normalize', BOOL, True, 'normalize cube before quantified generalization'), ('spacer.p3.share_lemmas', BOOL, False, 'Share frame lemmas'), ('spacer.p3.share_invariants', BOOL, False, "Share invariants lemmas"), - ('spacer.from_level', UINT, 0, 'starting level to explore'), - ('spacer.print_json', SYMBOL, '', 'print pobs tree in JSON format to a given file'), - ('spacer.ctp', BOOL, False, 'enable counterexample-to-pushing technique'), - ('spacer.use_inc_clause', BOOL, False, 'Use incremental clause to represent trans'), + ('spacer.min_level', UINT, 0, 'Minimal level to explore'), + ('spacer.print_json', SYMBOL, '', 'Print pobs tree in JSON format to a given file'), + ('spacer.ctp', BOOL, True, 'Enable counterexample-to-pushing'), + ('spacer.use_inc_clause', BOOL, True, 'Use incremental clause to represent trans'), ('spacer.dump_benchmarks', BOOL, False, 'Dump SMT queries as benchmarks'), ('spacer.dump_threshold', DOUBLE, 5.0, 'Threshold in seconds on dumping benchmarks'), ('spacer.gpdr', BOOL, False, 'Use GPDR solving strategy for non-linear CHC'), + ('spacer.gpdr.bfs', BOOL, True, 'Use BFS exploration strategy for expanding model search'), + )) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 64d047d73..40c42015b 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -82,7 +82,7 @@ void pob::set_post(expr* post) { void pob::set_post(expr* post, app_ref_vector const &binding) { normalize(post, m_post, m_pt.get_context().simplify_pob(), - m_pt.get_context().use_eqclass()); + m_pt.get_context().use_euf_gen()); m_binding.reset(); if (!binding.empty()) {m_binding.append(binding);} @@ -1590,13 +1590,12 @@ void pred_transformer::init_rules(decl2rel const& pts) { if (not_inits.empty ()) {m_all_init = true;} } -static bool is_all_non_null(app_ref_vector const& v) -{ - for (unsigned i = 0; i < v.size(); ++i) { - if (!v[i]) { return false; } - } +#ifdef Z3DEBUG +static bool is_all_non_null(app_ref_vector const& apps) { + for (auto *a : apps) if (!a) return false; return true; } +#endif void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule) { scoped_watch _t_(m_initialize_watch); @@ -2196,7 +2195,7 @@ context::context(fixedpoint_params const& params, ref pool2_base = mk_smt_solver(m, params_ref::get_empty(), symbol::null); - unsigned max_num_contexts = params.pdr_max_num_contexts(); + unsigned max_num_contexts = params.spacer_max_num_contexts(); m_pool0 = alloc(solver_pool, pool0_base.get(), max_num_contexts); m_pool1 = alloc(solver_pool, pool1_base.get(), max_num_contexts); m_pool2 = alloc(solver_pool, pool2_base.get(), max_num_contexts); @@ -2214,42 +2213,42 @@ void context::updt_params() { m_random.set_seed(m_params.spacer_random_seed()); m_children_order = static_cast(m_params.spacer_order_children()); m_simplify_pob = m_params.spacer_simplify_pob(); - m_use_eqclass = m_params.spacer_use_eqclass(); + m_use_euf_gen = m_params.spacer_use_euf_gen(); m_use_ctp = m_params.spacer_ctp(); m_use_inc_clause = m_params.spacer_use_inc_clause(); m_blast_term_ite = m_params.spacer_blast_term_ite(); m_reuse_pobs = m_params.spacer_reuse_pobs(); - m_use_ind_gen = m_params.pdr_use_inductive_generalizer(); + m_use_ind_gen = m_params.spacer_use_inductive_generalizer(); m_use_array_eq_gen = m_params.spacer_use_array_eq_generalizer(); - m_check_lemmas = m_params.spacer_lemma_sanity_check(); + m_validate_lemmas = m_params.spacer_validate_lemmas(); m_max_level = m_params.spacer_max_level (); - m_skip_propagate = m_params.spacer_skip_propagate (); - m_reset_obligation_queue = m_params.spacer_reset_obligation_queue(); - m_flexible_trace = m_params.pdr_flexible_trace(); - m_flexible_trace_depth = m_params.pdr_flexible_trace_depth(); + m_use_propagate = m_params.spacer_propagate (); + m_reset_obligation_queue = m_params.spacer_reset_pob_queue(); + m_push_pob = m_params.spacer_push_pob(); + m_push_pob_max_depth = m_params.spacer_push_pob_max_depth(); m_use_lemma_as_pob = m_params.spacer_use_lemma_as_cti(); m_elim_aux = m_params.spacer_elim_aux(); m_reach_dnf = m_params.spacer_reach_dnf(); m_use_derivations = m_params.spacer_use_derivations(); - m_validate_result = m_params.pdr_validate_result(); + m_validate_result = m_params.validate(); m_use_eq_prop = m_params.spacer_eq_prop(); - m_ground_pob = m_params.spacer_ground_cti(); + m_ground_pob = m_params.spacer_ground_pobs(); m_q3_qgen = m_params.spacer_q3_use_qgen(); m_use_gpdr = m_params.spacer_gpdr(); - m_simplify_formulas_pre = m_params.pdr_simplify_formulas_pre(); - m_simplify_formulas_post = m_params.pdr_simplify_formulas_post(); + m_simplify_formulas_pre = m_params.spacer_simplify_lemmas_pre(); + m_simplify_formulas_post = m_params.spacer_simplify_lemmas_post(); m_use_native_mbp = m_params.spacer_native_mbp (); m_instantiate = m_params.spacer_q3_instantiate (); m_use_qlemmas = m_params.spacer_q3(); m_weak_abs = m_params.spacer_weak_abs(); m_use_restarts = m_params.spacer_restarts(); m_restart_initial_threshold = m_params.spacer_restart_initial_threshold(); - + m_pdr_bfs = m_params.spacer_gpdr_bfs(); if (m_use_gpdr) { // set options to be compatible with GPDR m_weak_abs = false; - m_flexible_trace = false; + m_push_pob = false; m_use_qlemmas = false; m_ground_pob = true; m_reset_obligation_queue = false; @@ -2552,7 +2551,7 @@ void context::init_lemma_generalizers() m_params.spacer_q3_qgen_normalize())); } - if (use_eqclass()) { + if (m_use_euf_gen) { m_lemma_generalizers.push_back (alloc(lemma_eq_generalizer, *this)); } @@ -2567,7 +2566,7 @@ void context::init_lemma_generalizers() m_lemma_generalizers.push_back(alloc(lemma_array_eq_generalizer, *this)); } - if (m_check_lemmas) { + if (m_validate_lemmas) { m_lemma_generalizers.push_back(alloc(lemma_sanity_checker, *this)); } @@ -2995,7 +2994,7 @@ lbool context::solve_core (unsigned from_lvl) if (check_reachability()) { return l_true; } - if (lvl > 0 && !m_skip_propagate) + if (lvl > 0 && m_use_propagate) if (propagate(m_expanded_lvl, lvl, UINT_MAX)) { dump_json(); return l_false; } dump_json(); @@ -3142,8 +3141,8 @@ bool context::check_reachability () /// returns true if the given pob can be re-scheduled bool context::is_requeue(pob &n) { - if (!m_flexible_trace) {return false;} - unsigned max_depth = m_flexible_trace_depth; + if (!m_push_pob) {return false;} + unsigned max_depth = m_push_pob_max_depth; return (n.level() >= m_pob_queue.max_level() || m_pob_queue.max_level() - n.level() <= max_depth); } @@ -3309,7 +3308,7 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) unsigned num_reuse_reach = 0; - if (m_flexible_trace && n.pt().is_blocked(n, uses_level)) { + if (m_push_pob && n.pt().is_blocked(n, uses_level)) { // if (!m_pob_queue.is_root (n)) n.close (); IF_VERBOSE (1, verbose_stream () << " K " << std::fixed << std::setprecision(2) diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index fcd396a62..f3d00a857 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -907,17 +907,17 @@ class context { bool m_weak_abs; bool m_use_restarts; bool m_simplify_pob; - bool m_use_eqclass; + bool m_use_euf_gen; bool m_use_ctp; bool m_use_inc_clause; bool m_blast_term_ite; bool m_reuse_pobs; bool m_use_ind_gen; bool m_use_array_eq_gen; - bool m_check_lemmas; - bool m_skip_propagate; + bool m_validate_lemmas; + bool m_use_propagate; bool m_reset_obligation_queue; - bool m_flexible_trace; + bool m_push_pob; bool m_use_lemma_as_pob; bool m_elim_aux; bool m_reach_dnf; @@ -929,8 +929,8 @@ class context { bool m_use_gpdr; bool m_simplify_formulas_pre; bool m_simplify_formulas_post; - - unsigned m_flexible_trace_depth; + bool m_pdr_bfs; + unsigned m_push_pob_max_depth; unsigned m_max_level; unsigned m_restart_initial_threshold; scoped_ptr_vector m_callbacks; @@ -1003,7 +1003,7 @@ public: bool use_instantiate () {return m_instantiate;} bool weak_abs() {return m_weak_abs;} bool use_qlemmas () {return m_use_qlemmas;} - bool use_eqclass() { return m_use_eqclass;} + bool use_euf_gen() {return m_use_euf_gen;} bool simplify_pob() {return m_simplify_pob;} bool use_ctp() {return m_use_ctp;} bool use_inc_clause() {return m_use_inc_clause;} diff --git a/src/muz/spacer/spacer_dl_interface.cpp b/src/muz/spacer/spacer_dl_interface.cpp index cadbcfb0e..807e9b751 100644 --- a/src/muz/spacer/spacer_dl_interface.cpp +++ b/src/muz/spacer/spacer_dl_interface.cpp @@ -164,7 +164,7 @@ lbool dl_interface::query(expr * query) return l_false; } - return m_context->solve(m_ctx.get_params().spacer_from_level()); + return m_context->solve(m_ctx.get_params().spacer_min_level()); } diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index 6b13e82f8..ad2b6200d 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -230,7 +230,7 @@ lbool context::gpdr_solve_core() { //if there is no query predicate, abort if (!m_rels.find(m_query_pred, m_query)) { return l_false; } - model_search ms(true); + model_search ms(m_pdr_bfs); unsigned lvl = 0; unsigned max_level = m_max_level; for (lvl = 0; lvl < max_level; ++lvl) { From 619f681d2844ca16d5353a9956f3253ec675eae2 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Jun 2018 15:11:35 -0700 Subject: [PATCH 1211/1283] Fix bug in iuc_solver::get_unsat_core() that prevented clean cores --- src/muz/spacer/spacer_iuc_solver.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 6d824a1f2..5a3a53f0b 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -215,32 +215,31 @@ void iuc_solver::reset_statistics () m_learn_core_sw.reset(); } -void iuc_solver::get_unsat_core (expr_ref_vector &core) -{ +void iuc_solver::get_unsat_core (expr_ref_vector &core) { m_solver.get_unsat_core (core); - ptr_vector _core(core.size(), core.c_ptr()); - undo_proxies_in_core (_core); + undo_proxies_in_core (core); } -void iuc_solver::undo_proxies_in_core (ptr_vector &r) + +void iuc_solver::undo_proxies_in_core (expr_ref_vector &r) { app_ref e(m); expr_fast_mark1 bg; - for (unsigned i = 0; i < m_first_assumption; ++i) { - bg.mark(m_assumptions.get(i)); + for (unsigned i = 0; i < m_first_assumption; ++i) { + bg.mark(m_assumptions.get(i)); } // expand proxies unsigned j = 0; for (expr* rr : r) { // skip background assumptions - if (bg.is_marked(rr)) + if (bg.is_marked(rr)) continue; // -- undo proxies, but only if they were introduced in check_sat if (m_is_proxied && is_proxy(rr, e)) { SASSERT (m.is_or (e)); r[j++] = e->get_arg (1); - } + } else { r[j++] = rr; } From 9109968e5541d58159139773ffeda20e661781a5 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Jun 2018 15:29:34 -0700 Subject: [PATCH 1212/1283] Cleanup fixedpoint options Replace pdr options with spacer Repace fixedpoint module with fp --- src/muz/base/CMakeLists.txt | 2 +- src/muz/base/dl_context.cpp | 103 +++++++------- src/muz/base/dl_context.h | 63 +++++---- .../{fixedpoint_params.pyg => fp_params.pyg} | 2 +- src/muz/bmc/dl_bmc_engine.cpp | 2 +- src/muz/fp/dl_cmds.cpp | 68 ++++----- src/muz/fp/horn_tactic.cpp | 59 ++++---- src/muz/spacer/spacer_context.cpp | 3 +- src/muz/spacer/spacer_context.h | 8 +- src/muz/spacer/spacer_iuc_solver.cpp | 40 +++--- src/muz/spacer/spacer_iuc_solver.h | 20 +-- src/muz/spacer/spacer_prop_solver.cpp | 7 +- src/muz/spacer/spacer_prop_solver.h | 4 +- src/muz/tab/tab_context.cpp | 2 +- src/muz/transforms/dl_mk_array_eq_rewrite.cpp | 2 +- .../transforms/dl_mk_array_instantiation.cpp | 2 +- src/muz/transforms/dl_mk_bit_blast.cpp | 52 +++---- .../dl_mk_interp_tail_simplifier.cpp | 31 ++--- .../dl_mk_quantifier_abstraction.cpp | 49 ++++--- src/muz/transforms/dl_mk_rule_inliner.cpp | 129 +++++++++--------- src/muz/transforms/dl_mk_scale.cpp | 20 +-- .../transforms/dl_mk_subsumption_checker.cpp | 25 ++-- src/muz/transforms/dl_transforms.cpp | 4 +- 23 files changed, 344 insertions(+), 353 deletions(-) rename src/muz/base/{fixedpoint_params.pyg => fp_params.pyg} (99%) diff --git a/src/muz/base/CMakeLists.txt b/src/muz/base/CMakeLists.txt index 6b0334664..8c21e1557 100644 --- a/src/muz/base/CMakeLists.txt +++ b/src/muz/base/CMakeLists.txt @@ -18,5 +18,5 @@ z3_add_component(muz smt smt2parser PYG_FILES - fixedpoint_params.pyg + fp_params.pyg ) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 2b0987be7..220b2516d 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -27,7 +27,7 @@ Revision History: #include "ast/ast_smt2_pp.h" #include "ast/datatype_decl_plugin.h" #include "ast/scoped_proof.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" #include "ast/ast_pp_util.h" @@ -152,15 +152,15 @@ namespace datalog { class context::restore_rules : public trail { rule_set* m_old_rules; - void reset() { - dealloc(m_old_rules); + void reset() { + dealloc(m_old_rules); m_old_rules = nullptr; } public: restore_rules(rule_set& r): m_old_rules(alloc(rule_set, r)) {} ~restore_rules() override {} - + void undo(context& ctx) override { ctx.replace_rules(*m_old_rules); reset(); @@ -189,7 +189,7 @@ namespace datalog { throw default_exception("there are no backtracking points to pop to"); } throw default_exception("pop operation is not supported"); - m_trail.pop_scope(1); + m_trail.pop_scope(1); } // ----------------------------------- @@ -203,7 +203,7 @@ namespace datalog { m_register_engine(re), m_fparams(fp), m_params_ref(pa), - m_params(alloc(fixedpoint_params, m_params_ref)), + m_params(alloc(fp_params, m_params_ref)), m_decl_util(m), m_rewriter(m), m_var_subst(m), @@ -235,7 +235,7 @@ namespace datalog { context::~context() { reset(); - dealloc(m_params); + dealloc(m_params); } void context::reset() { @@ -291,14 +291,14 @@ namespace datalog { bool context::similarity_compressor() const { return m_params->datalog_similarity_compressor(); } unsigned context::similarity_compressor_threshold() const { return m_params->datalog_similarity_compressor_threshold(); } unsigned context::soft_timeout() const { return m_fparams.m_timeout; } - unsigned context::initial_restart_timeout() const { return m_params->datalog_initial_restart_timeout(); } + unsigned context::initial_restart_timeout() const { return m_params->datalog_initial_restart_timeout(); } bool context::generate_explanations() const { return m_params->datalog_generate_explanations(); } bool context::explanations_on_relation_level() const { return m_params->datalog_explanations_on_relation_level(); } bool context::magic_sets_for_queries() const { return m_params->datalog_magic_sets_for_queries(); } symbol context::tab_selection() const { return m_params->tab_selection(); } bool context::xform_coi() const { return m_params->xform_coi(); } bool context::xform_slice() const { return m_params->xform_slice(); } - bool context::xform_bit_blast() const { return m_params->xform_bit_blast(); } + bool context::xform_bit_blast() const { return m_params->xform_bit_blast(); } bool context::karr() const { return m_params->xform_karr(); } bool context::scale() const { return m_params->xform_scale(); } bool context::magic() const { return m_params->xform_magic(); } @@ -428,7 +428,7 @@ namespace datalog { } - void context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, + void context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names) { if (relation_name_cnt > 0) { ensure_engine(); @@ -438,9 +438,9 @@ namespace datalog { } } - func_decl * context::mk_fresh_head_predicate(symbol const & prefix, symbol const & suffix, + func_decl * context::mk_fresh_head_predicate(symbol const & prefix, symbol const & suffix, unsigned arity, sort * const * domain, func_decl* orig_pred) { - func_decl* new_pred = + func_decl* new_pred = m.mk_fresh_func_decl(prefix, suffix, arity, domain, m.mk_bool_sort()); register_predicate(new_pred, true); @@ -473,7 +473,7 @@ namespace datalog { // // Update a rule with a new. // It requires basic subsumption. - // + // void context::update_rule(expr* rl, symbol const& name) { datalog::rule_manager& rm = get_rule_manager(); proof* p = nullptr; @@ -494,13 +494,13 @@ namespace datalog { rule* old_rule = nullptr; for (unsigned i = 0; i < size_before; ++i) { if (rls[i]->name() == name) { - if (old_rule) { + if (old_rule) { std::stringstream strm; strm << "Rule " << name << " occurs twice. It cannot be modified"; m_rule_set.del_rule(r); throw default_exception(strm.str()); } - old_rule = rls[i]; + old_rule = rls[i]; } } if (old_rule) { @@ -556,7 +556,7 @@ namespace datalog { ensure_engine(); m_engine->add_cover(level, pred, property); } - + void context::add_invariant(func_decl* pred, expr *property) { ensure_engine(); @@ -566,11 +566,11 @@ namespace datalog { void context::check_rules(rule_set& r) { m_rule_properties.set_generate_proof(generate_proof_trace()); switch(get_engine()) { - case DATALOG_ENGINE: + case DATALOG_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_quantifier_free(); m_rule_properties.check_uninterpreted_free(); - m_rule_properties.check_nested_free(); + m_rule_properties.check_nested_free(); m_rule_properties.check_infinite_sorts(); break; case SPACER_ENGINE: @@ -582,12 +582,12 @@ namespace datalog { case BMC_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_for_negated_predicates(); - break; + break; case QBMC_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_existential_tail(); m_rule_properties.check_for_negated_predicates(); - break; + break; case TAB_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_existential_tail(); @@ -650,7 +650,7 @@ namespace datalog { add_fact(pred, rfact); } } - + void context::add_table_fact(func_decl * pred, unsigned num_args, unsigned args[]) { if (pred->get_arity() != num_args) { std::ostringstream out; @@ -682,7 +682,7 @@ namespace datalog { reopen(); } } - + void context::reopen() { SASSERT(m_closed); m_rule_set.reopen(); @@ -695,7 +695,7 @@ namespace datalog { transformer.register_plugin(plugin); transform_rules(transformer); } - + void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); @@ -724,7 +724,7 @@ namespace datalog { } void context::collect_params(param_descrs& p) { - fixedpoint_params::collect_param_descrs(p); + fp_params::collect_param_descrs(p); insert_timeout(p); } @@ -732,8 +732,8 @@ namespace datalog { m_params_ref.copy(p); if (m_engine.get()) m_engine->updt_params(); m_generate_proof_trace = m_params->generate_proof_trace(); - m_unbound_compressor = m_params->datalog_unbound_compressor(); - m_default_relation = m_params->datalog_default_relation(); + m_unbound_compressor = m_params->datalog_unbound_compressor(); + m_default_relation = m_params->datalog_default_relation(); } expr_ref context::get_background_assertion() { @@ -748,7 +748,7 @@ namespace datalog { void context::assert_expr(expr* e) { TRACE("dl", tout << mk_ismt2_pp(e, m) << "\n";); - m_background.push_back(e); + m_background.push_back(e); } void context::cleanup() { @@ -785,7 +785,7 @@ namespace datalog { return; } symbol e = m_params->engine(); - + if (e == symbol("datalog")) { m_engine_type = DATALOG_ENGINE; } @@ -811,7 +811,7 @@ namespace datalog { if (m_engine_type == LAST_ENGINE) { expr_fast_mark1 mark; engine_type_proc proc(m); - m_engine_type = DATALOG_ENGINE; + m_engine_type = DATALOG_ENGINE; for (unsigned i = 0; m_engine_type == DATALOG_ENGINE && i < m_rule_set.get_num_rules(); ++i) { rule * r = m_rule_set.get_rule(i); quick_for_each_expr(proc, mark, r->get_head()); @@ -893,15 +893,15 @@ namespace datalog { m_rel = dynamic_cast(m_engine.get()); } - } + } } - lbool context::rel_query(unsigned num_rels, func_decl * const* rels) { + lbool context::rel_query(unsigned num_rels, func_decl * const* rels) { m_last_answer = nullptr; ensure_engine(); return m_engine->query(num_rels, rels); } - + expr* context::get_answer_as_formula() { if (m_last_answer) { return m_last_answer.get(); @@ -954,7 +954,7 @@ namespace datalog { void context::display(std::ostream & out) const { display_rules(out); - if (m_rel) m_rel->display_facts(out); + if (m_rel) m_rel->display_facts(out); } void context::display_profile(std::ostream& out) const { @@ -990,10 +990,10 @@ namespace datalog { bool context::result_contains_fact(relation_fact const& f) { return m_rel && m_rel->result_contains_fact(f); } - + // NB: algebraic data-types declarations will not be printed. - static void collect_free_funcs(unsigned sz, expr* const* exprs, + static void collect_free_funcs(unsigned sz, expr* const* exprs, ast_pp_util& v, mk_fresh_name& fresh_names) { v.collect(sz, exprs); @@ -1005,7 +1005,7 @@ namespace datalog { fresh_names.add(e); } } - + void context::get_raw_rule_formulas(expr_ref_vector& rules, svector& names, unsigned_vector &bounds) { for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { expr_ref r = bind_vars(m_rule_fmls[i].get(), true); @@ -1018,7 +1018,7 @@ namespace datalog { void context::get_rules_as_formulas(expr_ref_vector& rules, expr_ref_vector& queries, svector& names) { expr_ref fml(m); rule_manager& rm = get_rule_manager(); - + // ensure that rules are all using bound variables. for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { m_free_vars(m_rule_fmls[i].get()); @@ -1067,7 +1067,7 @@ namespace datalog { } for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { rules.push_back(m_rule_fmls[i].get()); - names.push_back(m_rule_names[i]); + names.push_back(m_rule_names[i]); } } @@ -1080,7 +1080,7 @@ namespace datalog { } return out; } - + void context::display_smt2(unsigned num_queries, expr* const* qs, std::ostream& out) { ast_manager& m = get_manager(); ast_pp_util visitor(m); @@ -1109,7 +1109,7 @@ namespace datalog { for (unsigned i = 0; i < sz; ++i) { func_decl* f = visitor.coll.get_func_decls()[i]; if (f->get_family_id() != null_family_id) { - // + // } else if (is_predicate(f) && use_fixedpoint_extensions) { rels.insert(f); @@ -1122,12 +1122,12 @@ namespace datalog { if (!use_fixedpoint_extensions) { out << "(set-logic HORN)\n"; } - for (func_decl * f : rels) + for (func_decl * f : rels) visitor.remove_decl(f); visitor.display_decls(out); - for (func_decl * f : rels) + for (func_decl * f : rels) display_rel_decl(out, f); if (use_fixedpoint_extensions && do_declare_vars) { @@ -1143,7 +1143,7 @@ namespace datalog { PP(axioms[i]); out << ")\n"; } - for (unsigned i = 0; i < rules.size(); ++i) { + for (unsigned i = 0; i < rules.size(); ++i) { out << (use_fixedpoint_extensions?"(rule ":"(assert "); expr* r = rules[i].get(); symbol nm = names[i]; @@ -1156,7 +1156,7 @@ namespace datalog { while (fresh_names.contains(nm)) { std::ostringstream s; s << nm << "!"; - nm = symbol(s.str().c_str()); + nm = symbol(s.str().c_str()); } fresh_names.add(nm); display_symbol(out, nm) << ")"; @@ -1182,7 +1182,7 @@ namespace datalog { args.push_back(m.mk_var(j, m_free_vars[j])); } qfn = m.mk_implies(q, m.mk_app(fn, args.size(), args.c_ptr())); - + out << "(assert "; PP(qfn); out << ")\n"; @@ -1209,7 +1209,7 @@ namespace datalog { smt2_pp_environment_dbg env(m); out << "(declare-rel "; display_symbol(out, f->get_name()) << " ("; - for (unsigned i = 0; i < f->get_arity(); ++i) { + for (unsigned i = 0; i < f->get_arity(); ++i) { ast_smt2_pp(out, f->get_domain(i), env); if (i + 1 < f->get_arity()) { out << " "; @@ -1239,12 +1239,12 @@ namespace datalog { void context::declare_vars(expr_ref_vector& rules, mk_fresh_name& fresh_names, std::ostream& out) { // // replace bound variables in rules by 'var declarations' - // First remove quantifers, then replace bound variables + // First remove quantifers, then replace bound variables // by fresh constants. - // + // smt2_pp_environment_dbg env(m); var_subst vsubst(m, false); - + expr_ref_vector fresh_vars(m), subst(m); expr_ref res(m); obj_map var_idxs; @@ -1257,7 +1257,7 @@ namespace datalog { quantifier* q = to_quantifier(r); if (!q->is_forall()) { continue; - } + } if (has_quantifiers(q->get_expr())) { continue; } @@ -1287,7 +1287,7 @@ namespace datalog { fresh_vars.push_back(m.mk_const(name, s)); out << "(declare-var " << name << " "; ast_smt2_pp(out, s, env); - out << ")\n"; + out << ")\n"; } subst.push_back(fresh_vars[vars[max_var]].get()); } @@ -1299,4 +1299,3 @@ namespace datalog { }; - diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index b49c7e665..6e6bc80dc 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -44,7 +44,7 @@ Revision History: #include "muz/base/bind_variables.h" #include "muz/base/rule_properties.h" -struct fixedpoint_params; +struct fp_params; namespace datalog { @@ -98,7 +98,7 @@ namespace datalog { relation_fact(ast_manager & m) : app_ref_vector(m) {} relation_fact(ast_manager & m, unsigned sz) : app_ref_vector(m) { resize(sz); } relation_fact(context & ctx); - + iterator begin() const { return c_ptr(); } iterator end() const { return c_ptr()+size(); } @@ -126,7 +126,7 @@ namespace datalog { virtual bool has_facts(func_decl * pred) const = 0; virtual void store_relation(func_decl * pred, relation_base * rel) = 0; virtual void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred) = 0; - virtual void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, + virtual void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names) = 0; virtual bool output_profile() const = 0; virtual void collect_non_empty_predicates(func_decl_set& preds) = 0; @@ -147,7 +147,7 @@ namespace datalog { public: contains_pred(context& ctx): ctx(ctx) {} ~contains_pred() override {} - + bool operator()(expr* e) override { return ctx.is_predicate(e); } @@ -170,7 +170,7 @@ namespace datalog { register_engine_base& m_register_engine; smt_params & m_fparams; params_ref m_params_ref; - fixedpoint_params* m_params; + fp_params* m_params; bool m_generate_proof_trace; // cached configuration parameter bool m_unbound_compressor; // cached configuration parameter symbol m_default_relation; // cached configuration parameter @@ -227,7 +227,7 @@ namespace datalog { void push(); void pop(); - + bool saturation_was_run() const { return m_saturation_was_run; } void notify_saturation_was_run() { m_saturation_was_run = true; } @@ -236,7 +236,7 @@ namespace datalog { ast_manager & get_manager() const { return m; } rule_manager & get_rule_manager() { return m_rule_manager; } smt_params & get_fparams() const { return m_fparams; } - fixedpoint_params const& get_params() const { return *m_params; } + fp_params const& get_params() const { return *m_params; } DL_ENGINE get_engine() { configure_engine(); return m_engine_type; } register_engine_base& get_register_engine() { return m_register_engine; } th_rewriter& get_rewriter() { return m_rewriter; } @@ -251,7 +251,7 @@ namespace datalog { symbol default_table() const; symbol default_relation() const; void set_default_relation(symbol const& s); - symbol default_table_checker() const; + symbol default_table_checker() const; symbol check_relation() const; bool default_table_checked() const; bool dbg_fpr_nonempty_relation_signature() const; @@ -275,7 +275,7 @@ namespace datalog { bool compress_unbound() const; bool quantify_arrays() const; bool instantiate_quantifiers() const; - bool xform_bit_blast() const; + bool xform_bit_blast() const; bool xform_slice() const; bool xform_coi() const; bool array_blast() const; @@ -291,9 +291,9 @@ namespace datalog { void register_variable(func_decl* var); /* - Replace constants that have been registered as + Replace constants that have been registered as variables by de-Bruijn indices and corresponding - universal (if is_forall is true) or existential + universal (if is_forall is true) or existential quantifier. */ expr_ref bind_vars(expr* fml, bool is_forall); @@ -303,7 +303,7 @@ namespace datalog { /** Register datalog relation. - If named is true, we associate the predicate with its name, so that it can be + If named is true, we associate the predicate with its name, so that it can be retrieved by the try_get_predicate_decl() function. Auxiliary predicates introduced e.g. by rule transformations do not need to be named. */ @@ -326,7 +326,7 @@ namespace datalog { /** \brief If a predicate name has a \c func_decl object assigned, return pointer to it; otherwise return 0. - + Not all \c func_decl object used as relation identifiers need to be assigned to their names. Generally, the names coming from the parses are registered here. */ @@ -334,13 +334,13 @@ namespace datalog { func_decl * res = nullptr; m_preds_by_name.find(pred_name, res); return res; - } + } /** \brief Create a fresh head predicate declaration. */ - func_decl * mk_fresh_head_predicate(symbol const & prefix, symbol const & suffix, + func_decl * mk_fresh_head_predicate(symbol const & prefix, symbol const & suffix, unsigned arity, sort * const * domain, func_decl* orig_pred=nullptr); @@ -365,13 +365,13 @@ namespace datalog { /** \brief Assign names of variables used in the declaration of a predicate. - These names are used when printing out the relations to make the output conform + These names are used when printing out the relations to make the output conform to the one of bddbddb. */ void set_argument_names(const func_decl * pred, const svector & var_names); symbol get_argument_name(const func_decl * pred, unsigned arg_index); - void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, + void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names); void set_output_predicate(func_decl * pred) { m_rule_set.set_output_predicate(pred); } @@ -385,9 +385,9 @@ namespace datalog { void add_fact(func_decl * pred, const relation_fact & fact); bool has_facts(func_decl * pred) const; - + void add_rule(rule_ref& r); - + void assert_expr(expr* e); expr_ref get_background_assertion(); unsigned get_num_assertions() { return m_background.size(); } @@ -397,7 +397,7 @@ namespace datalog { Method exposed from API for adding rules. */ void add_rule(expr* rl, symbol const& name, unsigned bound = UINT_MAX); - + /** Update a named rule. @@ -421,9 +421,9 @@ namespace datalog { at 'level+1', 'level+2' etc, and include level=-1. */ expr_ref get_cover_delta(int level, func_decl* pred); - + /** - Add a property of predicate 'pred' at 'level'. + Add a property of predicate 'pred' at 'level'. It gets pushed forward when possible. */ void add_cover(int level, func_decl* pred, expr* property); @@ -432,7 +432,7 @@ namespace datalog { Add an invariant of predicate 'pred'. */ void add_invariant (func_decl *pred, expr *property); - + /** \brief Check rule subsumption. */ @@ -471,15 +471,15 @@ namespace datalog { proof_converter_ref& get_proof_converter() { return m_pc; } void add_proof_converter(proof_converter* pc) { m_pc = concat(m_pc.get(), pc); } - void transform_rules(rule_transformer& transf); + void transform_rules(rule_transformer& transf); void transform_rules(rule_transformer::plugin* plugin); void replace_rules(rule_set const& rs); void record_transformed_rules(); - void apply_default_transformation(); + void apply_default_transformation(); void collect_params(param_descrs& r); - + void updt_params(params_ref const& p); void display_rules(std::ostream & out) const { @@ -507,7 +507,7 @@ namespace datalog { /** \brief check if query 'q' is satisfied under asserted rules and background. - If successful, return OK and into \c result assign a relation with all + If successful, return OK and into \c result assign a relation with all tuples matching the query. Otherwise return reason for failure and do not modify \c result. @@ -515,7 +515,7 @@ namespace datalog { starting from zero. The caller becomes an owner of the relation object returned in \c result. The - relation object, however, should not outlive the datalog context since it is + relation object, however, should not outlive the datalog context since it is linked to a relation plugin in the context. */ @@ -524,7 +524,7 @@ namespace datalog { lbool query_from_lvl (expr* q, unsigned lvl); /** \brief retrieve model from inductive invariant that shows query is unsat. - + \pre engine == 'pdr' || engine == 'duality' - this option is only supported for PDR mode and Duality mode. */ @@ -532,7 +532,7 @@ namespace datalog { /** \brief retrieve proof from derivation of the query. - + \pre engine == 'pdr' || engine == 'duality'- this option is only supported for PDR mode and Duality mode. */ @@ -606,7 +606,7 @@ namespace datalog { /** Just reset all tables. */ - void reset_tables(); + void reset_tables(); void flush_add_rules(); @@ -627,4 +627,3 @@ namespace datalog { }; #endif /* DL_CONTEXT_H_ */ - diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fp_params.pyg similarity index 99% rename from src/muz/base/fixedpoint_params.pyg rename to src/muz/base/fp_params.pyg index 7e92b0d2c..c96a12ca2 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fp_params.pyg @@ -1,4 +1,4 @@ -def_module_params('fixedpoint', +def_module_params('fp', description='fixedpoint parameters', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 56b7e449d..c7657a0d7 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -33,7 +33,7 @@ Revision History: #include "muz/transforms/dl_mk_rule_inliner.h" #include "ast/scoped_proof.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" namespace datalog { diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index ba12c849c..4605826ba 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -30,23 +30,23 @@ Notes: #include "util/scoped_ctrl_c.h" #include "util/scoped_timer.h" #include "util/trail.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" #include struct dl_context { smt_params m_fparams; params_ref m_params_ref; - fixedpoint_params m_params; + fp_params m_params; cmd_context & m_cmd; datalog::register_engine m_register_engine; dl_collected_cmds* m_collected_cmds; unsigned m_ref_count; datalog::dl_decl_plugin* m_decl_plugin; - scoped_ptr m_context; + scoped_ptr m_context; trail_stack m_trail; - fixedpoint_params const& get_params() { + fp_params const& get_params() { init(); return m_context->get_params(); } @@ -58,18 +58,18 @@ struct dl_context { m_ref_count(0), m_decl_plugin(nullptr), m_trail(*this) {} - + void inc_ref() { ++m_ref_count; } - + void dec_ref() { --m_ref_count; if (0 == m_ref_count) { dealloc(this); } } - + void init() { ast_manager& m = m_cmd.m(); if (!m_context) { @@ -83,10 +83,10 @@ struct dl_context { else { m_decl_plugin = alloc(datalog::dl_decl_plugin); m.register_plugin(symbol("datalog_relation"), m_decl_plugin); - } + } } } - + void reset() { m_context = nullptr; } @@ -97,9 +97,9 @@ struct dl_context { m_trail.push(push_back_vector(m_collected_cmds->m_rels)); } dlctx().register_predicate(pred, false); - dlctx().set_predicate_representation(pred, num_kinds, kinds); + dlctx().set_predicate_representation(pred, num_kinds, kinds); } - + void add_rule(expr * rule, symbol const& name, unsigned bound) { init(); if (m_collected_cmds) { @@ -112,7 +112,7 @@ struct dl_context { else { m_context->add_rule(rule, name, bound); } - } + } bool collect_query(func_decl* q) { if (m_collected_cmds) { @@ -127,7 +127,7 @@ struct dl_context { m_collected_cmds->m_queries.push_back(qr); m_trail.push(push_back_vector(m_collected_cmds->m_queries)); return true; - } + } else { return false; } @@ -142,7 +142,7 @@ struct dl_context { m_trail.pop_scope(1); dlctx().pop(); } - + datalog::context & dlctx() { init(); return *m_context; @@ -162,7 +162,7 @@ class dl_rule_cmd : public cmd { public: dl_rule_cmd(dl_context * dl_ctx): cmd("rule"), - m_dl_ctx(dl_ctx), + m_dl_ctx(dl_ctx), m_arg_idx(0), m_t(nullptr), m_bound(UINT_MAX) {} @@ -210,7 +210,7 @@ public: } char const * get_usage() const override { return "predicate"; } char const * get_main_descr() const override { - return "pose a query to a predicate based on the Horn rules."; + return "pose a query to a predicate based on the Horn rules."; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { @@ -243,9 +243,9 @@ public: return; } datalog::context& dlctx = m_dl_ctx->dlctx(); - set_background(ctx); + set_background(ctx); dlctx.updt_params(m_params); - unsigned timeout = m_dl_ctx->get_params().timeout(); + unsigned timeout = m_dl_ctx->get_params().timeout(); cancel_eh eh(ctx.m().limit()); bool query_exn = false; lbool status = l_undef; @@ -271,12 +271,12 @@ public: ctx.regular_stream() << "unsat\n"; print_certificate(ctx); break; - case l_true: + case l_true: ctx.regular_stream() << "sat\n"; print_answer(ctx); print_certificate(ctx); break; - case l_undef: + case l_undef: if (dlctx.get_status() == datalog::BOUNDED){ ctx.regular_stream() << "bounded\n"; print_certificate(ctx); @@ -287,7 +287,7 @@ public: case datalog::INPUT_ERROR: ctx.regular_stream() << "input error\n"; break; - + case datalog::MEMOUT: ctx.regular_stream() << "memory bounds exceeded\n"; break; @@ -295,12 +295,12 @@ public: case datalog::TIMEOUT: ctx.regular_stream() << "timeout\n"; break; - + case datalog::APPROX: ctx.regular_stream() << "approximated relations\n"; break; - case datalog::OK: + case datalog::OK: (void)query_exn; SASSERT(query_exn); break; @@ -324,7 +324,7 @@ public: void init_pdescrs(cmd_context & ctx, param_descrs & p) override { m_dl_ctx->dlctx().collect_params(p); } - + private: void set_background(cmd_context& ctx) { @@ -356,8 +356,8 @@ private: statistics st; datalog::context& dlctx = m_dl_ctx->dlctx(); dlctx.collect_statistics(st); - st.update("time", ctx.get_seconds()); - st.display_smt2(ctx.regular_stream()); + st.update("time", ctx.get_seconds()); + st.display_smt2(ctx.regular_stream()); } } @@ -391,8 +391,8 @@ public: void prepare(cmd_context & ctx) override { ctx.m(); // ensure manager is initialized. - m_arg_idx = 0; - m_query_arg_idx = 0; + m_arg_idx = 0; + m_query_arg_idx = 0; m_domain.reset(); m_kinds.reset(); } @@ -443,21 +443,21 @@ public: m_arg_idx(0), m_dl_ctx(dl_ctx) {} - + char const * get_usage() const override { return " "; } char const * get_descr(cmd_context & ctx) const override { return "declare constant as variable"; } unsigned get_arity() const override { return 2; } void prepare(cmd_context & ctx) override { ctx.m(); // ensure manager is initialized. - m_arg_idx = 0; + m_arg_idx = 0; } cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { SASSERT(m_arg_idx <= 1); if (m_arg_idx == 0) { - return CPK_SYMBOL; + return CPK_SYMBOL; } - return CPK_SORT; + return CPK_SORT; } void set_next_arg(cmd_context & ctx, sort* s) override { @@ -466,7 +466,7 @@ public: } void set_next_arg(cmd_context & ctx, symbol const & s) override { - m_var_name = s; + m_var_name = s; ++m_arg_idx; } @@ -523,7 +523,7 @@ static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_c ctx.insert(alloc(dl_query_cmd, dl_ctx)); ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx)); ctx.insert(alloc(dl_declare_var_cmd, dl_ctx)); - ctx.insert(alloc(dl_push_cmd, dl_ctx)); + ctx.insert(alloc(dl_push_cmd, dl_ctx)); ctx.insert(alloc(dl_pop_cmd, dl_ctx)); } diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index 4843a2623..eef95915d 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -27,7 +27,7 @@ Revision History: #include "muz/transforms/dl_mk_slice.h" #include "tactic/generic_model_converter.h" #include "muz/transforms/dl_transforms.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" #include "ast/ast_util.h" #include "ast/rewriter/var_subst.h" @@ -71,7 +71,7 @@ class horn_tactic : public tactic { f = to_quantifier(f)->get_expr(); } else if (is_exists(f) && !is_positive) { - f = to_quantifier(f)->get_expr(); + f = to_quantifier(f)->get_expr(); } else if (m.is_not(f, e)) { is_positive = !is_positive; @@ -84,7 +84,7 @@ class horn_tactic : public tactic { if (!is_positive) { f = m.mk_not(f); } - + } bool is_predicate(expr* a) { @@ -144,7 +144,7 @@ class horn_tactic : public tactic { expr* a = nullptr, *a1 = nullptr; flatten_or(tmp, args); for (unsigned i = 0; i < args.size(); ++i) { - a = args[i].get(); + a = args[i].get(); check_predicate(mark, a); if (m.is_not(a, a1)) { body.push_back(a1); @@ -176,13 +176,13 @@ class horn_tactic : public tactic { return expr_ref(m.mk_implies(body, head), m); } - void operator()(goal_ref const & g, + void operator()(goal_ref const & g, goal_ref_buffer & result) { SASSERT(g->is_well_sorted()); tactic_report report("horn", *g); bool produce_proofs = g->proofs_enabled(); - if (produce_proofs) { + if (produce_proofs) { if (!m_ctx.generate_proof_trace()) { params_ref params = m_ctx.get_params().p; params.set_bool("generate_proof_trace", true); @@ -208,7 +208,7 @@ class horn_tactic : public tactic { case IS_QUERY: queries.push_back(f); break; - default: + default: msg << "formula is not in Horn fragment: " << mk_pp(g->form(i), m) << "\n"; TRACE("horn", tout << msg.str();); throw tactic_exception(msg.str().c_str()); @@ -243,10 +243,10 @@ class horn_tactic : public tactic { g->set(mc.get()); } - void verify(expr* q, + void verify(expr* q, goal_ref const& g, - goal_ref_buffer & result, - model_converter_ref & mc, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc) { lbool is_reachable = l_undef; @@ -275,9 +275,9 @@ class horn_tactic : public tactic { else { g->assert_expr(m.mk_false()); } - break; + break; } - case l_false: { + case l_false: { // goal is sat g->reset(); if (produce_models) { @@ -290,11 +290,11 @@ class horn_tactic : public tactic { mc = mc2; } } - break; + break; } - case l_undef: + case l_undef: // subgoal is unchanged. - break; + break; } TRACE("horn", g->display(tout);); SASSERT(g->is_well_sorted()); @@ -314,20 +314,20 @@ class horn_tactic : public tactic { } } - void simplify(expr* q, + void simplify(expr* q, goal_ref const& g, - goal_ref_buffer & result, - model_converter_ref & mc, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc) { - expr_ref fml(m); + expr_ref fml(m); func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); m_ctx.get_rules(); // flush adding rules. apply_default_transformation(m_ctx); - + if (m_ctx.xform_slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); @@ -351,7 +351,7 @@ class horn_tactic : public tactic { g->assert_expr(fml); } } - + }; bool m_is_simplify; @@ -368,7 +368,7 @@ public: tactic * translate(ast_manager & m) override { return alloc(horn_tactic, m_is_simplify, m, m_params); } - + ~horn_tactic() override { dealloc(m_imp); } @@ -378,16 +378,16 @@ public: m_imp->updt_params(p); } - + void collect_param_descrs(param_descrs & r) override { m_imp->collect_param_descrs(r); } - - void operator()(goal_ref const & in, + + void operator()(goal_ref const & in, goal_ref_buffer & result) override { (*m_imp)(in, result); } - + void collect_statistics(statistics & st) const override { m_imp->collect_statistics(st); st.copy(m_stats); @@ -397,15 +397,15 @@ public: m_stats.reset(); m_imp->reset_statistics(); } - + void cleanup() override { ast_manager & m = m_imp->m; m_imp->collect_statistics(m_stats); dealloc(m_imp); m_imp = alloc(imp, m_is_simplify, m, m_params); - + } - + }; @@ -416,4 +416,3 @@ tactic * mk_horn_tactic(ast_manager & m, params_ref const & p) { tactic * mk_horn_simplify_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(horn_tactic, true, m, p)); } - diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 40c42015b..03093ab63 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2175,8 +2175,7 @@ pob* pred_transformer::pobs::mk_pob(pob *parent, // ---------------- // context -context::context(fixedpoint_params const& params, - ast_manager& m) : +context::context(fp_params const& params, ast_manager& m) : m_params(params), m(m), m_context(nullptr), diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index f3d00a857..760f38f69 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -33,7 +33,7 @@ Notes: #include "muz/spacer/spacer_prop_solver.h" #include "muz/spacer/spacer_json.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" namespace datalog { class rule_set; @@ -877,7 +877,7 @@ class context { stopwatch m_create_children_watch; stopwatch m_init_rules_watch; - fixedpoint_params const& m_params; + fp_params const& m_params; ast_manager& m; datalog::context* m_context; manager m_pm; @@ -993,11 +993,11 @@ public: Initial values of predicates are stored in corresponding relations in dctx. We check whether there is some reachable state of the relation checked_relation. */ - context(fixedpoint_params const& params, ast_manager& m); + context(fp_params const& params, ast_manager& m); ~context(); - const fixedpoint_params &get_params() const { return m_params; } + const fp_params &get_params() const { return m_params; } bool use_native_mbp () {return m_use_native_mbp;} bool use_ground_pob () {return m_ground_pob;} bool use_instantiate () {return m_instantiate;} diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 5a3a53f0b..a68db4c0a 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -99,8 +99,8 @@ void iuc_solver::pop_bg (unsigned n) { if (n == 0) { return; } - if (m_assumptions.size () > m_first_assumption) { - m_assumptions.shrink(m_first_assumption); + if (m_assumptions.size () > m_first_assumption) { + m_assumptions.shrink(m_first_assumption); } m_first_assumption = m_first_assumption > n ? m_first_assumption - n : 0; m_assumptions.shrink (m_first_assumption); @@ -111,8 +111,8 @@ unsigned iuc_solver::get_num_bg () {return m_first_assumption;} lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions) { // -- remove any old assumptions - m_assumptions.shrink(m_first_assumption); - + m_assumptions.shrink(m_first_assumption); + // -- replace theory literals in background assumptions with proxies mk_proxies (m_assumptions); // -- in case mk_proxies added new literals, they are all background @@ -126,12 +126,12 @@ lbool iuc_solver::check_sat (unsigned num_assumptions, expr * const *assumptions lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, vector const & clauses) { - if (clauses.empty()) + if (clauses.empty()) return check_sat(cube.size(), cube.c_ptr()); - + // -- remove any old assumptions - m_assumptions.shrink(m_first_assumption); - + m_assumptions.shrink(m_first_assumption); + // -- replace theory literals in background assumptions with proxies mk_proxies(m_assumptions); // -- in case mk_proxies added new literals, they are all background @@ -147,8 +147,8 @@ lbool iuc_solver::check_sat_cc(const expr_ref_vector &cube, app* iuc_solver::def_manager::mk_proxy (expr *v) { app* r; - if (m_expr2proxy.find(v, r)) - return r; + if (m_expr2proxy.find(v, r)) + return r; ast_manager &m = m_parent.m; app* proxy = m_parent.fresh_proxy (); @@ -184,14 +184,14 @@ bool iuc_solver::def_manager::is_proxy_def (expr *v) bool iuc_solver::is_proxy(expr *e, app_ref &def) { - if (!is_uninterp_const(e)) - return false; + if (!is_uninterp_const(e)) + return false; app* a = to_app (e); for (int i = m_defs.size (); i-- > 0; ) if (m_defs[i].is_proxy (a, def)) - return true; + return true; return m_base_defs.is_proxy (a, def); } @@ -263,9 +263,9 @@ void iuc_solver::elim_proxies (expr_ref_vector &v) expr_ref f = mk_and (v); scoped_ptr rep = mk_expr_simp_replacer (m); rep->set_substitution (&m_elim_proxies_sub); - (*rep) (f); - v.reset (); - flatten_and (f, v); + (*rep)(f); + v.reset(); + flatten_and(f, v); } void iuc_solver::get_iuc(expr_ref_vector &core) @@ -362,7 +362,7 @@ void iuc_solver::get_iuc(expr_ref_vector &core) // -- register iuc plugins switch (m_iuc_arith) { case 0: - case 1: + case 1: plugin = alloc(unsat_core_plugin_farkas_lemma, learner, m_split_literals, @@ -398,18 +398,18 @@ void iuc_solver::get_iuc(expr_ref_vector &core) UNREACHABLE(); break; } - + { scoped_watch _t_ (m_learn_core_sw); // compute interpolating unsat core learner.compute_unsat_core(core); } - + elim_proxies (core); // AG: this should be taken care of by minimizing the iuc cut simplify_bounds (core); } - + IF_VERBOSE(2, verbose_stream () << "IUC Core:\n" << core << "\n";); } diff --git a/src/muz/spacer/spacer_iuc_solver.h b/src/muz/spacer/spacer_iuc_solver.h index 3c6251be0..c0a0072ed 100644 --- a/src/muz/spacer/spacer_iuc_solver.h +++ b/src/muz/spacer/spacer_iuc_solver.h @@ -65,7 +65,7 @@ private: bool m_print_farkas_stats; bool m_old_hyp_reducer; bool is_proxy(expr *e, app_ref &def); - void undo_proxies_in_core(ptr_vector &v); + void undo_proxies_in_core(expr_ref_vector &v); app* mk_proxy(expr *v); app* fresh_proxy(); void elim_proxies(expr_ref_vector &v); @@ -101,16 +101,16 @@ public: void pop_bg(unsigned n); unsigned get_num_bg(); - void get_full_unsat_core(ptr_vector &core) { + void get_full_unsat_core(ptr_vector &core) { expr_ref_vector _core(m); - m_solver.get_unsat_core(_core); + m_solver.get_unsat_core(_core); core.append(_core.size(), _core.c_ptr()); } /* solver interface */ - solver* translate(ast_manager &m, params_ref const &p) override { - return m_solver.translate(m, p); + solver* translate(ast_manager &m, params_ref const &p) override { + return m_solver.translate(m, p); } void updt_params(params_ref const &p) override { m_solver.updt_params(p); } void reset_params(params_ref const &p) override { m_solver.reset_params(p); } @@ -136,8 +136,8 @@ public: expr * get_assertion(unsigned idx) const override { return m_solver.get_assertion(idx); } unsigned get_num_assumptions() const override { return m_solver.get_num_assumptions(); } expr * get_assumption(unsigned idx) const override { return m_solver.get_assumption(idx); } - std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const override { - return m_solver.display(out, n, es); + std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const override { + return m_solver.display(out, n, es); } /* check_sat_result interface */ @@ -159,7 +159,7 @@ public: iuc_solver &m_s; expr_ref_vector &m_v; public: - scoped_mk_proxy(iuc_solver &s, expr_ref_vector &v) : m_s(s), m_v(v) { + scoped_mk_proxy(iuc_solver &s, expr_ref_vector &v) : m_s(s), m_v(v) { m_s.mk_proxies(m_v); } ~scoped_mk_proxy() { m_s.undo_proxies(m_v); } @@ -171,8 +171,8 @@ public: public: scoped_bg(iuc_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {} ~scoped_bg() { - if (m_s.get_num_bg() > m_bg_sz) { - m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); + if (m_s.get_num_bg() > m_bg_sz) { + m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); } } }; diff --git a/src/muz/spacer/spacer_prop_solver.cpp b/src/muz/spacer/spacer_prop_solver.cpp index 435f0af3a..7bd21a1b5 100644 --- a/src/muz/spacer/spacer_prop_solver.cpp +++ b/src/muz/spacer/spacer_prop_solver.cpp @@ -36,13 +36,13 @@ Revision History: #include "muz/spacer/spacer_prop_solver.h" #include "model/model_evaluator.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" namespace spacer { prop_solver::prop_solver(ast_manager &m, solver *solver0, solver *solver1, - fixedpoint_params const& p, symbol const& name) : + fp_params const& p, symbol const& name) : m(m), m_name(name), m_ctx(nullptr), @@ -329,13 +329,14 @@ lbool prop_solver::internal_check_assumptions(expr_ref_vector &hard_atoms, } if (result == l_false && m_core && m.proofs_enabled() && !m_subset_based_core) { - TRACE("spacer", tout << "theory core\n";); + TRACE("spacer", tout << "Using IUC core\n";); m_core->reset(); m_ctx->get_iuc(*m_core); } else if (result == l_false && m_core) { m_core->reset(); m_ctx->get_unsat_core(*m_core); // manually undo proxies because maxsmt() call above manually adds proxies + // AG: don't think this is needed. maxsmt() undoes the proxies already m_ctx->undo_proxies(*m_core); } diff --git a/src/muz/spacer/spacer_prop_solver.h b/src/muz/spacer/spacer_prop_solver.h index 042215eff..1db65dc3e 100644 --- a/src/muz/spacer/spacer_prop_solver.h +++ b/src/muz/spacer/spacer_prop_solver.h @@ -33,7 +33,7 @@ Revision History: #include "muz/spacer/spacer_iuc_solver.h" #include "muz/spacer/spacer_util.h" -struct fixedpoint_params; +struct fp_params; namespace spacer { typedef ptr_vector decl_vector; @@ -76,7 +76,7 @@ private: public: prop_solver(ast_manager &m, solver *solver0, solver* solver1, - fixedpoint_params const& p, symbol const& name); + fp_params const& p, symbol const& name); void set_core(expr_ref_vector* core) { m_core = core; } diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index 39b7af634..2fb329ff4 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -30,7 +30,7 @@ Revision History: #include "ast/for_each_expr.h" #include "ast/substitution/matcher.h" #include "ast/scoped_proof.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" #include "ast/ast_util.h" namespace tb { diff --git a/src/muz/transforms/dl_mk_array_eq_rewrite.cpp b/src/muz/transforms/dl_mk_array_eq_rewrite.cpp index c33cecda9..61eafae64 100644 --- a/src/muz/transforms/dl_mk_array_eq_rewrite.cpp +++ b/src/muz/transforms/dl_mk_array_eq_rewrite.cpp @@ -20,7 +20,7 @@ Revision History: #include "ast/expr_abstract.h" #include "muz/base/dl_context.h" #include "muz/base/dl_context.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" #include "muz/transforms/dl_mk_array_eq_rewrite.h" #include "ast/factor_equivs.h" diff --git a/src/muz/transforms/dl_mk_array_instantiation.cpp b/src/muz/transforms/dl_mk_array_instantiation.cpp index 362d83865..6a8f0ce81 100644 --- a/src/muz/transforms/dl_mk_array_instantiation.cpp +++ b/src/muz/transforms/dl_mk_array_instantiation.cpp @@ -23,7 +23,7 @@ Revision History: #include "muz/base/dl_context.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/expr_abstract.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 8a21bc37c..992b8f51b 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -24,7 +24,7 @@ Revision History: #include "ast/rewriter/expr_safe_replace.h" #include "tactic/generic_model_converter.h" #include "muz/transforms/dl_mk_interp_tail_simplifier.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" #include "ast/scoped_proof.h" #include "model/model_v2_pp.h" @@ -32,9 +32,9 @@ namespace datalog { // // P(v) :- Q(extract[1:1]v ++ 0), R(1 ++ extract[0:0]v). - // -> + // -> // P(bv(x,y)) :- Q(bv(x,0)), R(bv(1,y)) . - // + // // Introduce P_bv: // P_bv(x,y) :- Q_bv(x,0), R_bv(1,y) // P(bv(x,y)) :- P_bv(x,y) @@ -51,7 +51,7 @@ namespace datalog { bit_blast_model_converter(ast_manager& m): m(m), m_bv(m), - m_old_funcs(m), + m_old_funcs(m), m_new_funcs(m) {} void insert(func_decl* old_f, func_decl* new_f) { @@ -73,7 +73,7 @@ namespace datalog { func_decl* q = m_old_funcs[i].get(); func_interp* f = model->get_func_interp(p); if (!f) continue; - expr_ref body(m); + expr_ref body(m); unsigned arity_q = q->get_arity(); TRACE("dl", model_v2_pp(tout, *model); @@ -87,10 +87,10 @@ namespace datalog { if (f) { body = f->get_interp(); SASSERT(!f->is_partial()); - SASSERT(body); + SASSERT(body); } else { - body = m.mk_false(); + body = m.mk_false(); } unsigned idx = 0; expr_ref arg(m), proj(m); @@ -104,18 +104,18 @@ namespace datalog { for (unsigned k = 0; k < sz; ++k) { parameter p(k); proj = m.mk_app(m_bv.get_family_id(), OP_BIT2BOOL, 1, &p, 1, &t); - sub.insert(m.mk_var(idx++, m.mk_bool_sort()), proj); + sub.insert(m.mk_var(idx++, m.mk_bool_sort()), proj); } } else { sub.insert(m.mk_var(idx++, s), arg); } } - sub(body); + sub(body); g->set_else(body); model->register_decl(q, g); - } - } + } + } }; class expand_mkbv_cfg : public default_rewriter_cfg { @@ -134,10 +134,10 @@ namespace datalog { public: expand_mkbv_cfg(context& ctx): - m_context(ctx), + m_context(ctx), m(ctx.get_manager()), m_util(m), - m_args(m), + m_args(m), m_f_vars(m), m_g_vars(m), m_old_funcs(m), @@ -152,8 +152,8 @@ namespace datalog { void set_dst(rule_set* dst) { m_dst = dst; } func_decl_ref_vector const& old_funcs() const { return m_old_funcs; } func_decl_ref_vector const& new_funcs() const { return m_new_funcs; } - - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { if (num == 0) { if (m_src->is_output_predicate(f)) m_dst->set_output_predicate(f); @@ -165,9 +165,9 @@ namespace datalog { return BR_FAILED; } - // + // // f(mk_bv(args),...) - // + // m_args.reset(); m_g_vars.reset(); m_f_vars.reset(); @@ -191,9 +191,9 @@ namespace datalog { } } func_decl* g = nullptr; - + if (!m_pred2blast.find(f, g)) { - + ptr_vector domain; for (unsigned i = 0; i < m_args.size(); ++i) { domain.push_back(m.get_sort(m_args[i].get())); @@ -262,7 +262,7 @@ namespace datalog { m_params.set_bool("blast_quant", true); m_blaster.updt_params(m_params); } - + rule_set * operator()(rule_set const & source) { // TODO pc if (!m_context.xform_bit_blast()) { @@ -270,8 +270,8 @@ namespace datalog { } rule_manager& rm = m_context.get_rule_manager(); unsigned sz = source.get_num_rules(); - expr_ref fml(m); - rule_set * result = alloc(rule_set, m_context); + expr_ref fml(m); + rule_set * result = alloc(rule_set, m_context); m_rewriter.m_cfg.set_src(&source); m_rewriter.m_cfg.set_dst(result); for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) { @@ -299,8 +299,8 @@ namespace datalog { if (!source.contains(*I)) result->set_output_predicate(*I); } - - if (m_context.get_model_converter()) { + + if (m_context.get_model_converter()) { generic_model_converter* fmc = alloc(generic_model_converter, m, "dl_mk_bit_blast"); bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); func_decl_ref_vector const& old_funcs = m_rewriter.m_cfg.old_funcs(); @@ -311,7 +311,7 @@ namespace datalog { } m_context.add_model_converter(concat(bvmc, fmc)); } - + return result; } }; @@ -326,6 +326,6 @@ namespace datalog { rule_set * mk_bit_blast::operator()(rule_set const & source) { return (*m_impl)(source); - } + } }; diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp index 38000c65a..c1abd7bef 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp @@ -27,7 +27,7 @@ Revision History: #include "muz/transforms/dl_mk_interp_tail_simplifier.h" #include "ast/ast_util.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" namespace datalog { // ----------------------------------- @@ -46,7 +46,7 @@ namespace datalog { bool mk_interp_tail_simplifier::rule_substitution::unify(expr * e1, expr * e2) { SASSERT(m_rule); - //we need to apply the current substitution in order to ensure the unifier + //we need to apply the current substitution in order to ensure the unifier //works in an incremental way expr_ref e1_s(m); expr_ref e2_s(m); @@ -268,7 +268,7 @@ namespace datalog { if (neq) { have_pair = false; v[prev_pair_idx] = neq; - + read_idx++; continue; } @@ -294,7 +294,7 @@ namespace datalog { //bool detect_same_variable_conj_pairs - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { if (m.is_not(f) && (m.is_and(args[0]) || m.is_or(args[0]))) { @@ -307,15 +307,15 @@ namespace datalog { m_app_args.push_back(tmp); } if (m.is_and(args[0])) { - result = mk_or(m_app_args); + result = mk_or(m_app_args); } else { - result = mk_and(m_app_args); + result = mk_and(m_app_args); } return BR_REWRITE2; } - if (!m.is_and(f) && !m.is_or(f)) { - return BR_FAILED; + if (!m.is_and(f) && !m.is_or(f)) { + return BR_FAILED; } if (num == 0) { if (m.is_and(f)) { @@ -375,7 +375,7 @@ namespace datalog { m_simp(ctx.get_rewriter()), a(m), m_rule_subst(ctx), - m_tail(m), + m_tail(m), m_itail_members(m), m_conj(m) { m_cfg = alloc(normalizer_cfg, m); @@ -386,7 +386,7 @@ namespace datalog { dealloc(m_rw); dealloc(m_cfg); } - + void mk_interp_tail_simplifier::simplify_expr(app * a, expr_ref& res) { @@ -537,7 +537,7 @@ namespace datalog { simplify_expr(itail.get(), simp_res); modified |= itail.get() != simp_res.get(); - + if (m.is_false(simp_res)) { TRACE("dl", r->display(m_context, tout << "rule is infeasible\n");); return false; @@ -568,7 +568,7 @@ namespace datalog { rule_ref pro_var_eq_result(m_context.get_rule_manager()); if (propagate_variable_equivalences(res, pro_var_eq_result)) { - SASSERT(rule_counter().get_max_rule_var(*r.get())==0 || + SASSERT(rule_counter().get_max_rule_var(*r.get())==0 || rule_counter().get_max_rule_var(*r.get()) > rule_counter().get_max_rule_var(*pro_var_eq_result.get())); r = pro_var_eq_result; goto start; @@ -607,8 +607,8 @@ namespace datalog { rule_set * res = alloc(rule_set, m_context); if (transform_rules(source, *res)) { res->inherit_predicates(source); - TRACE("dl", - source.display(tout); + TRACE("dl", + source.display(tout); res->display(tout);); } else { dealloc(res); @@ -616,6 +616,5 @@ namespace datalog { } return res; } - -}; +}; diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index e9a4f2f54..dafb0ddd5 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -11,7 +11,7 @@ Abstract: Author: - Ken McMillan + Ken McMillan Andrey Rybalchenko Nikolaj Bjorner (nbjorner) 2013-04-02 @@ -23,13 +23,12 @@ Revision History: #include "muz/base/dl_context.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/expr_abstract.h" -#include "muz/base/fixedpoint_params.hpp" namespace datalog { - // model converter: + // model converter: // Given model for P^(x, y, i, a[i]) // create model: P(x,y,a) == forall i . P^(x,y,i,a[i]) // requires substitution and list of bound variables. @@ -55,7 +54,7 @@ namespace datalog { void display(std::ostream& out) override { display_add(out, m); } - void get_units(obj_map& units) override { units.reset(); } + void get_units(obj_map& units) override { units.reset(); } void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector const& bound) { m_old_funcs.push_back(old_p); @@ -74,7 +73,7 @@ namespace datalog { sort_ref_vector const& sorts = m_sorts[i]; svector const& is_bound = m_bound[i]; func_interp* f = old_model->get_func_interp(p); - expr_ref body(m); + expr_ref body(m); unsigned arity_q = q->get_arity(); SASSERT(0 < p->get_arity()); func_interp* g = alloc(func_interp, m, arity_q); @@ -82,7 +81,7 @@ namespace datalog { if (f) { body = f->get_interp(); SASSERT(!f->is_partial()); - SASSERT(body); + SASSERT(body); } else { expr_ref_vector args(m); @@ -94,7 +93,7 @@ namespace datalog { // Create quantifier wrapper around body. TRACE("dl", tout << mk_pp(body, m) << "\n";); - // 1. replace variables by the compound terms from + // 1. replace variables by the compound terms from // the original predicate. expr_safe_replace rep(m); for (unsigned i = 0; i < sub.size(); ++i) { @@ -121,7 +120,7 @@ namespace datalog { _free.push_back(consts.back()); } } - rep(body); + rep(body); rep.reset(); TRACE("dl", tout << mk_pp(body, m) << "\n";); @@ -130,18 +129,18 @@ namespace datalog { body = m.mk_forall(names.size(), bound_sorts.c_ptr(), names.c_ptr(), body); TRACE("dl", tout << mk_pp(body, m) << "\n";); - // 4. replace remaining constants by variables. + // 4. replace remaining constants by variables. for (unsigned i = 0; i < _free.size(); ++i) { rep.insert(_free[i].get(), m.mk_var(i, m.get_sort(_free[i].get()))); } - rep(body); + rep(body); g->set_else(body); TRACE("dl", tout << mk_pp(body, m) << "\n";); new_model->register_decl(q, g); - } + } old_model = new_model; - } + } }; mk_quantifier_abstraction::mk_quantifier_abstraction( @@ -154,7 +153,7 @@ namespace datalog { m_mc(nullptr) { } - mk_quantifier_abstraction::~mk_quantifier_abstraction() { + mk_quantifier_abstraction::~mk_quantifier_abstraction() { } func_decl* mk_quantifier_abstraction::declare_pred(rule_set const& rules, rule_set& dst, func_decl* old_p) { @@ -178,7 +177,7 @@ namespace datalog { func_decl* new_p = nullptr; if (!m_old2new.find(old_p, new_p)) { expr_ref_vector sub(m), vars(m); - svector bound; + svector bound; sort_ref_vector domain(m), sorts(m); expr_ref arg(m); for (unsigned i = 0; i < sz; ++i) { @@ -208,7 +207,7 @@ namespace datalog { bound.push_back(false); sub.push_back(arg); sorts.push_back(s0); - } + } SASSERT(old_p->get_range() == m.mk_bool_sort()); new_p = m.mk_func_decl(old_p->get_name(), domain.size(), domain.c_ptr(), old_p->get_range()); m_refs.push_back(new_p); @@ -242,12 +241,12 @@ namespace datalog { } args.push_back(arg); } - TRACE("dl", + TRACE("dl", tout << mk_pp(new_p, m) << "\n"; for (unsigned i = 0; i < args.size(); ++i) { tout << mk_pp(args[i].get(), m) << "\n"; }); - return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m); + return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m); } app_ref mk_quantifier_abstraction::mk_tail(rule_set const& rules, rule_set& dst, app* p) { @@ -272,7 +271,7 @@ namespace datalog { for (unsigned i = 0; i < sz; ++i) { arg = ps->get_arg(i); sort* s = m.get_sort(arg); - bool is_pattern = false; + bool is_pattern = false; while (a.is_array(s)) { is_pattern = true; unsigned arity = get_array_arity(s); @@ -304,9 +303,9 @@ namespace datalog { ptr_vector args2; args2.push_back(arg); args2.append(num_args, args); - return a.mk_select(args2.size(), args2.c_ptr()); + return a.mk_select(args2.size(), args2.c_ptr()); } - + rule_set * mk_quantifier_abstraction::operator()(rule_set const & source) { if (!m_ctx.quantify_arrays()) { return nullptr; @@ -334,10 +333,10 @@ namespace datalog { } rule_set * result = alloc(rule_set, m_ctx); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; i < sz; ++i) { tail.reset(); rule & r = *source.get_rule(i); - TRACE("dl", r.display(m_ctx, tout); ); + TRACE("dl", r.display(m_ctx, tout); ); unsigned cnt = vc.get_max_rule_var(r)+1; unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); @@ -352,8 +351,8 @@ namespace datalog { proof_ref pr(m); rm.mk_rule(fml, pr, *result, r.name()); TRACE("dl", result->last()->display(m_ctx, tout);); - } - + } + // proof converter: proofs are not necessarily preserved using this transformation. if (m_old2new.empty()) { @@ -371,5 +370,3 @@ namespace datalog { }; - - diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 584f44303..317f13ff8 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -18,7 +18,7 @@ Revision History: Added linear_inline 2012-9-10 (nbjorner) Disable inliner for quantified rules 2012-10-31 (nbjorner) - + Notes: Resolution transformation (resolve): @@ -27,7 +27,7 @@ Resolution transformation (resolve): -------------------------------------------------- P(x) :- R(z), phi(x,y), psi(y,z) - Proof converter: + Proof converter: replace assumption (*) by rule and upper assumptions. @@ -37,9 +37,9 @@ Subsumption transformation (remove rule): P(x) :- Q(y), phi(x,y) Rules --------------------------------- Rules - - - Model converter: + + + Model converter: P(x) := P(x) or (exists y . Q(y) & phi(x,y)) @@ -52,7 +52,7 @@ Subsumption transformation (remove rule): #include "ast/rewriter/rewriter.h" #include "ast/rewriter/rewriter_def.h" #include "muz/transforms/dl_mk_rule_inliner.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" namespace datalog { @@ -67,15 +67,15 @@ namespace datalog { unsigned var_cnt = std::max(vc.get_max_rule_var(tgt), vc.get_max_rule_var(src))+1; m_subst.reset(); m_subst.reserve(2, var_cnt); - + m_ready = m_unif(tgt.get_tail(tgt_idx), src.get_head(), m_subst); if (m_ready) { m_deltas[0] = 0; m_deltas[1] = var_cnt; - TRACE("dl", - output_predicate(m_context, src.get_head(), tout << "unify rules "); - output_predicate(m_context, tgt.get_head(), tout << "\n"); + TRACE("dl", + output_predicate(m_context, src.get_head(), tout << "unify rules "); + output_predicate(m_context, tgt.get_head(), tout << "\n"); tout << "\n";); } return m_ready; @@ -90,7 +90,7 @@ namespace datalog { } void rule_unifier::apply( - rule const& r, bool is_tgt, unsigned skipped_index, + rule const& r, bool is_tgt, unsigned skipped_index, app_ref_vector& res, svector& res_neg) { unsigned rule_len = r.get_tail_size(); for (unsigned i = 0; i < rule_len; i++) { @@ -127,7 +127,7 @@ namespace datalog { ); if (m_normalize) { - m_rm.fix_unbound_vars(res, true); + m_rm.fix_unbound_vars(res, true); if (m_interp_simplifier.transform_rule(res.get(), simpl_rule)) { res = simpl_rule; return true; @@ -150,8 +150,8 @@ namespace datalog { for (unsigned i = 0; i < sorts.size(); ++i) { v = m.mk_var(i, sorts[i]); m_subst.apply(2, m_deltas, expr_offset(v, is_tgt?0:1), w); - result.push_back(w); - } + result.push_back(w); + } return result; } @@ -184,7 +184,7 @@ namespace datalog { expr_ref_vector s2 = m_unifier.get_rule_subst(src, false); datalog::resolve_rule(m_rm, tgt, src, tail_index, s1, s2, *res.get()); } - return true; + return true; } else { TRACE("dl", res->display(m_context, tout << "interpreted tail is unsat\n");); @@ -240,12 +240,12 @@ namespace datalog { return false; } - // - // these conditions are optional, they avoid possible exponential increase + // + // these conditions are optional, they avoid possible exponential increase // in the size of the problem - // + // - return + return //m_head_pred_non_empty_tails_ctr.get(pred)<=1 m_head_pred_ctr.get(pred) <= 1 || (m_tail_pred_ctr.get(pred) <= 1 && m_head_pred_ctr.get(pred) <= 4) @@ -253,7 +253,7 @@ namespace datalog { } /** Caller has to dealloc the returned object */ - rule_set * mk_rule_inliner::create_allowed_rule_set(rule_set const & orig) + rule_set * mk_rule_inliner::create_allowed_rule_set(rule_set const & orig) { rule_set * res = alloc(rule_set, m_context); for (rule * r : orig) { @@ -268,7 +268,7 @@ namespace datalog { /** Try to make the set of inlined predicates acyclic by forbidding inlining of one - predicate from each strongly connected component. Return true if we did forbide some + predicate from each strongly connected component. Return true if we did forbide some predicate, and false if the set of rules is already acyclic. */ bool mk_rule_inliner::forbid_preds_from_cycles(rule_set const & r) @@ -276,7 +276,7 @@ namespace datalog { SASSERT(r.is_closed()); bool something_forbidden = false; - + const rule_stratifier::comp_vector& comps = r.get_stratifier().get_strats(); for (rule_stratifier::item_set * stratum : comps) { @@ -293,12 +293,12 @@ namespace datalog { return something_forbidden; } - bool mk_rule_inliner::forbid_multiple_multipliers(const rule_set & orig, + bool mk_rule_inliner::forbid_multiple_multipliers(const rule_set & orig, rule_set const & proposed_inlined_rules) { bool something_forbidden = false; - const rule_stratifier::comp_vector& comps = + const rule_stratifier::comp_vector& comps = proposed_inlined_rules.get_stratifier().get_strats(); for (rule_stratifier::item_set * stratum : comps) { @@ -332,7 +332,7 @@ namespace datalog { } else { is_multi_head_pred = true; - m_head_pred_ctr.get(head_pred) = + m_head_pred_ctr.get(head_pred) = m_head_pred_ctr.get(head_pred)*tail_pred_head_cnt; } } @@ -379,7 +379,7 @@ namespace datalog { void mk_rule_inliner::plan_inlining(rule_set const & orig) { count_pred_occurrences(orig); - + scoped_ptr candidate_inlined_set = create_allowed_rule_set(orig); while (forbid_preds_from_cycles(*candidate_inlined_set)) { candidate_inlined_set = create_allowed_rule_set(orig); @@ -458,8 +458,8 @@ namespace datalog { rule_ref r(rl, m_rm); func_decl * pred = r->get_decl(); - // if inlining is allowed, then we are eliminating - // this relation through inlining, + // if inlining is allowed, then we are eliminating + // this relation through inlining, // so we don't add its rules to the result something_done |= !inlining_allowed(orig, pred) && transform_rule(orig, r, tgt); @@ -472,14 +472,14 @@ namespace datalog { } } } - + return something_done; } /** Check whether rule r is oriented in a particular ordering. This is to avoid infinite cycle of inlining in the eager inliner. - + Out ordering is lexicographic, comparing atoms first on stratum they are in, then on arity and then on ast ID of their func_decl. */ @@ -488,7 +488,7 @@ namespace datalog { unsigned head_strat = strat.get_predicate_strat(head_pred); unsigned head_arity = head_pred->get_arity(); unsigned pt_len = r->get_positive_tail_size(); - for (unsigned ti=0; ti < pt_len; ++ti) { + for (unsigned ti=0; ti < pt_len; ++ti) { func_decl * pred = r->get_decl(ti); unsigned pred_strat = strat.get_predicate_strat(pred); SASSERT(pred_strat <= head_strat); @@ -516,7 +516,7 @@ namespace datalog { unsigned pt_len = r->get_positive_tail_size(); for (unsigned ti = 0; ti < pt_len; ++ti) { - + func_decl * pred = r->get_decl(ti); if (pred == head_pred || m_preds_with_facts.contains(pred)) { continue; } @@ -532,7 +532,7 @@ namespace datalog { } else { inlining_candidate = nullptr; - + for (unsigned ri = 0; ri < rule_cnt; ++ri) { rule * pred_rule = pred_rules[ri]; if (!m_unifier.unify_rules(*r, ti, *pred_rule)) { @@ -540,9 +540,9 @@ namespace datalog { continue; } if (inlining_candidate != nullptr) { - // We have two rules that can be inlined into the current + // We have two rules that can be inlined into the current // tail predicate. In this situation we don't do inlinning - // on this tail atom, as we don't want the overall number + // on this tail atom, as we don't want the overall number // of rules to increase. goto process_next_tail; } @@ -608,14 +608,14 @@ namespace datalog { P(1,x) :- P(1,z), phi(x,y), psi(y,z) - whenever P(0,x) is not unifiable with the + whenever P(0,x) is not unifiable with the body of the rule where it appears (P(1,z)) - and P(0,x) is unifiable with at most one (?) + and P(0,x) is unifiable with at most one (?) other rule (and it does not occur negatively). */ bool mk_rule_inliner::visitor::operator()(expr* e) { m_unifiers.append(m_positions.find(e)); - TRACE("dl", + TRACE("dl", tout << "unifier: " << (m_unifiers.empty()?0:m_unifiers.back()); tout << " num unifiers: " << m_unifiers.size(); tout << " num positions: " << m_positions.find(e).size() << "\n"; @@ -640,7 +640,7 @@ namespace datalog { } unsigned_vector const& mk_rule_inliner::visitor::del_position(expr* e, unsigned j) { - obj_map::obj_map_entry * et = m_positions.find_core(e); + obj_map::obj_map_entry * et = m_positions.find_core(e); SASSERT(et && et->get_data().m_value.contains(j)); et->get_data().m_value.erase(j); return et->get_data().m_value; @@ -654,7 +654,7 @@ namespace datalog { m_head_visitor.add_position(head, i); m_head_index.insert(head); m_pinned.push_back(r); - + if (source.is_output_predicate(headd) || m_preds_with_facts.contains(headd)) { can_remove.set(i, false); @@ -667,10 +667,10 @@ namespace datalog { m_tail_visitor.add_position(tail, i); m_tail_index.insert(tail); } - bool can_exp = + bool can_exp = tl_sz == 1 - && r->get_positive_tail_size() == 1 - && !m_preds_with_facts.contains(r->get_decl(0)) + && r->get_positive_tail_size() == 1 + && !m_preds_with_facts.contains(r->get_decl(0)) && !source.is_output_predicate(r->get_decl(0)); can_expand.set(i, can_exp); } @@ -682,14 +682,14 @@ namespace datalog { for (unsigned j = 0; j < tl_sz; ++j) { app* tail = r->get_tail(j); m_tail_visitor.del_position(tail, i); - } + } } #define PRT(_x_) ((_x_)?"T":"F") bool mk_rule_inliner::inline_linear(scoped_ptr& rules) { - bool done_something = false; + bool done_something = false; unsigned sz = rules->get_num_rules(); m_head_visitor.reset(sz); @@ -704,7 +704,7 @@ namespace datalog { acc.push_back(rules->get_rule(i)); } - // set up unification index. + // set up unification index. svector& can_remove = m_head_visitor.can_remove(); svector& can_expand = m_head_visitor.can_expand(); @@ -729,7 +729,7 @@ namespace datalog { svector valid; valid.reset(); - valid.resize(sz, true); + valid.resize(sz, true); bool allow_branching = m_context.get_params().xform_inline_linear_branch(); @@ -738,9 +738,9 @@ namespace datalog { while (true) { rule_ref r(acc[i].get(), m_rm); - + TRACE("dl", r->display(m_context, tout << "processing: " << i << "\n");); - + if (!valid.get(i)) { TRACE("dl", tout << "invalid: " << i << "\n";); break; @@ -762,9 +762,9 @@ namespace datalog { TRACE("dl", tout << PRT(can_remove.get(j)) << " " << PRT(valid.get(j)) << " " << PRT(i != j) << "\n";); break; } - + rule* r2 = acc[j].get(); - + // check that the head of r2 only unifies with this single body position. TRACE("dl", output_predicate(m_context, r2->get_head(), tout << "unify head: "); tout << "\n";); m_tail_visitor.reset(); @@ -776,7 +776,7 @@ namespace datalog { TRACE("dl", tout << "too many tails " << num_tail_unifiers << "\n";); break; } - + rule_ref rl_res(m_rm); if (!try_to_inline_rule(*r.get(), *r2, 0, rl_res)) { TRACE("dl", r->display(m_context, tout << "inlining failed\n"); r2->display(m_context, tout); ); @@ -787,12 +787,12 @@ namespace datalog { del_rule(r, i); add_rule(*rules, rl_res.get(), i); - + r = rl_res; acc[i] = r.get(); can_expand.set(i, can_expand.get(j)); - + if (num_tail_unifiers == 1) { TRACE("dl", tout << "setting invalid: " << j << "\n";); valid.set(j, false); @@ -815,22 +815,22 @@ namespace datalog { res->inherit_predicates(*rules); TRACE("dl", res->display(tout);); rules = res.detach(); - } + } return done_something; } rule_set * mk_rule_inliner::operator()(rule_set const & source) { bool something_done = false; - ref hsmc; + ref hsmc; if (source.get_num_rules() == 0) { return nullptr; } - for (rule const* r : source) - if (has_quantifier(*r)) - return nullptr; + for (rule const* r : source) + if (has_quantifier(*r)) + return nullptr; if (m_context.get_model_converter()) { hsmc = alloc(horn_subsume_model_converter, m); @@ -841,15 +841,15 @@ namespace datalog { if (m_context.get_params().xform_inline_eager()) { TRACE("dl", source.display(tout << "before eager inlining\n");); - plan_inlining(source); - something_done = transform_rules(source, *res); + plan_inlining(source); + something_done = transform_rules(source, *res); VERIFY(res->close()); //this transformation doesn't break the negation stratification // try eager inlining if (do_eager_inlining(res)) { something_done = true; - } + } TRACE("dl", res->display(tout << "after eager inlining\n");); - } + } if (something_done) { res->inherit_predicates(source); } @@ -870,6 +870,5 @@ namespace datalog { return res.detach(); } - -}; +}; diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index 0144948bd..9ceaeeab3 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -18,7 +18,7 @@ Revision History: #include "muz/transforms/dl_mk_scale.h" #include "muz/base/dl_context.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" namespace datalog { @@ -37,7 +37,7 @@ namespace datalog { m_trail.push_back(new_f); m_new2old.insert(new_f, old_f); } - + void get_units(obj_map& units) override { units.reset(); } void operator()(model_ref& md) override { @@ -74,7 +74,7 @@ namespace datalog { old_model->register_decl(old_p, old_fi); } } - + // register values that have not been scaled. unsigned sz = md->get_num_constants(); for (unsigned i = 0; i < sz; ++i) { @@ -111,12 +111,12 @@ namespace datalog { m_ctx(ctx), a(m), m_trail(m), - m_eqs(m) { + m_eqs(m) { } - mk_scale::~mk_scale() { + mk_scale::~mk_scale() { } - + rule_set * mk_scale::operator()(rule_set const & source) { if (!m_ctx.scale()) { return nullptr; @@ -135,7 +135,7 @@ namespace datalog { } m_mc = smc.get(); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; i < sz; ++i) { rule & r = *source.get_rule(i); unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); @@ -157,10 +157,10 @@ namespace datalog { tail.push_back(a.mk_gt(m.mk_var(num_vars, a.mk_real()), a.mk_numeral(rational(0), false))); neg.resize(tail.size(), false); new_rule = rm.mk(new_pred, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); - result->add_rule(new_rule); + result->add_rule(new_rule); if (source.is_output_predicate(r.get_decl())) { result->set_output_predicate(new_rule->get_decl()); - } + } } TRACE("dl", result->display(tout);); if (m_mc) { @@ -227,7 +227,7 @@ namespace datalog { a.is_lt(e) || a.is_gt(e)) { expr_ref_vector args(m); for (unsigned i = 0; i < ap->get_num_args(); ++i) { - args.push_back(linearize(sigma_idx, ap->get_arg(i))); + args.push_back(linearize(sigma_idx, ap->get_arg(i))); } result = m.mk_app(ap->get_decl(), args.size(), args.c_ptr()); } diff --git a/src/muz/transforms/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp index 56883460a..da41b4ba4 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -24,7 +24,7 @@ Revision History: #include "ast/rewriter/rewriter.h" #include "ast/rewriter/rewriter_def.h" #include "muz/transforms/dl_mk_subsumption_checker.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" #include "tactic/generic_model_converter.h" @@ -39,8 +39,8 @@ namespace datalog { bool mk_subsumption_checker::is_total_rule(const rule * r) { - if (r->get_tail_size() != 0) { - return false; + if (r->get_tail_size() != 0) { + return false; } unsigned pt_len = r->get_positive_tail_size(); @@ -113,7 +113,7 @@ namespace datalog { } - bool mk_subsumption_checker::transform_rule(rule * r, + bool mk_subsumption_checker::transform_rule(rule * r, rule_subsumption_index& subs_index, rule_ref & res) { unsigned u_len = r->get_uninterpreted_tail_size(); @@ -133,7 +133,7 @@ namespace datalog { if(m_total_relations.contains(tail_atom->get_decl()) || subs_index.is_subsumed(tail_atom)) { if(neg) { - //rule contains negated total relation, this means that it is unsatisfiable + //rule contains negated total relation, this means that it is unsatisfiable //and can be removed return false; } @@ -143,8 +143,8 @@ namespace datalog { } } if(!neg && head.get()==tail_atom) { - //rule contains its head positively in the tail, therefore - //it will never add any new facts to the relation, so it + //rule contains its head positively in the tail, therefore + //it will never add any new facts to the relation, so it //can be removed return false; } @@ -197,9 +197,9 @@ namespace datalog { if (m_total_relations.contains(head_pred)) { if (!orig.is_output_predicate(head_pred) || total_relations_with_included_rules.contains(head_pred)) { - //We just skip definitions of total non-output relations as + //We just skip definitions of total non-output relations as //we'll eliminate them from the problem. - //We also skip rules of total output relations for which we have + //We also skip rules of total output relations for which we have //already output the rule which implies their totality. modified = true; continue; @@ -286,7 +286,7 @@ namespace datalog { obj_hashtable * head_store; if(m_ground_unconditional_rule_heads.find(pred, head_store)) { //Some relations may receive facts by ground unconditioned rules. - //We scanned for those earlier, so now we check whether we cannot get a + //We scanned for those earlier, so now we check whether we cannot get a //better estimate of relation size from these. unsigned gnd_rule_cnt = head_store->size(); @@ -334,7 +334,7 @@ namespace datalog { rule_set * mk_subsumption_checker::operator()(rule_set const & source) { // TODO mc - if (!m_context.get_params ().xform_subsumption_checker()) + if (!m_context.get_params ().xform_subsumption_checker()) return nullptr; m_have_new_total_rule = false; @@ -366,6 +366,5 @@ namespace datalog { return res; } - -}; +}; diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp index d456d95f9..d4b9506e8 100644 --- a/src/muz/transforms/dl_transforms.cpp +++ b/src/muz/transforms/dl_transforms.cpp @@ -35,7 +35,7 @@ Revision History: #include "muz/transforms/dl_mk_scale.h" #include "muz/transforms/dl_mk_array_eq_rewrite.h" #include "muz/transforms/dl_mk_array_instantiation.h" -#include "muz/base/fixedpoint_params.hpp" +#include "muz/base/fp_params.hpp" namespace datalog { @@ -72,7 +72,7 @@ namespace datalog { transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34970)); transf.register_plugin(alloc(datalog::mk_coi_filter, ctx, 34960)); transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx, 34950)); - + if (ctx.get_params().datalog_subsumption()) { transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34940)); transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34930)); From b62d73f20958fe295d2ec728dd10e2d19218d0c9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jun 2018 07:55:45 -0700 Subject: [PATCH 1213/1283] first round for combined mbi Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 95 ++++++++++++------ src/math/simplex/model_based_opt.h | 6 +- src/qe/qe_arith.cpp | 53 ++++++---- src/qe/qe_arith.h | 6 ++ src/qe/qe_mbi.cpp | 139 ++++++++++++++++++++++++++- src/qe/qe_mbi.h | 30 +++--- src/test/model_based_opt.cpp | 32 ++++++ 7 files changed, 297 insertions(+), 64 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 2b175506f..56d51648d 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -36,24 +36,22 @@ std::ostream& operator<<(std::ostream& out, opt::ineq_type ie) { namespace opt { /** - * Convert a row ax + coeffs + coeff = 0 into a definition for x - * x = -(coeffs + coeff)/a - * For rows ax + coeffs + coeff < 0 convert into - * x = -(coeffs + coeff - a)/a + * Convert a row ax + coeffs + coeff = value into a definition for x + * x = (value - coeffs - coeff)/a + * as backdrop we have existing assignments to x and other variables that + * satisfy the equality with value, and such that value satisfies + * the row constraint ( = , <= , < , mod) */ model_based_opt::def::def(row const& r, unsigned x) { - rational c = r.get_coefficient(x); - bool is_pos = c.is_pos(); for (var const & v : r.m_vars) { if (v.m_id != x) { m_vars.push_back(v); - if (is_pos) m_vars.back().m_coeff.neg(); + } + else { + m_div = -v.m_coeff; } } - m_coeff = r.m_coeff; - if (is_pos) m_coeff.neg(); - if (r.m_type == opt::t_lt) m_coeff += abs(c); - m_div = abs(c); + m_coeff = r.m_coeff - r.m_value; normalize(); SASSERT(m_div.is_pos()); } @@ -129,6 +127,9 @@ namespace opt { g = gcd(g, abs(v.m_coeff)); if (g.is_one()) break; } + if (m_div.is_neg()) { + g.neg(); + } if (!g.is_one()) { for (var& v : m_vars) { v.m_coeff /= g; @@ -138,7 +139,6 @@ namespace opt { } } - model_based_opt::model_based_opt() { m_rows.push_back(row()); } @@ -163,7 +163,7 @@ namespace opt { PASSERT(index == 0 || m_var2row_ids[vars[i].m_id].contains(index)); } - PASSERT(r.m_value == get_row_value(r)); + PASSERT(r.m_value == eval(r)); PASSERT(r.m_type != t_eq || r.m_value.is_zero()); // values satisfy constraints PASSERT(index == 0 || r.m_type != t_lt || r.m_value.is_neg()); @@ -317,7 +317,7 @@ namespace opt { << " eps: " << eps << " ", r); ); m_var2value[x] = new_x_val; - r.m_value = get_row_value(r); + r.m_value = eval(r); SASSERT(invariant(bound_trail[i], r)); } @@ -327,7 +327,7 @@ namespace opt { unsigned_vector const& row_ids = m_var2row_ids[x]; for (unsigned row_id : row_ids) { row & r = m_rows[row_id]; - r.m_value = get_row_value(r); + r.m_value = eval(r); SASSERT(invariant(row_id, r)); } } @@ -385,19 +385,32 @@ namespace opt { m_rows[row_id].m_alive = false; m_retired_rows.push_back(row_id); } + + rational model_based_opt::eval(unsigned x) const { + return m_var2value[x]; + } + + rational model_based_opt::eval(def const& d) const { + vector const& vars = d.m_vars; + rational val = d.m_coeff; + for (var const& v : vars) { + val += v.m_coeff * eval(v.m_id); + } + val /= d.m_div; + return val; + } - rational model_based_opt::get_row_value(row const& r) const { + rational model_based_opt::eval(row const& r) const { vector const& vars = r.m_vars; rational val = r.m_coeff; for (var const& v : vars) { - val += v.m_coeff * m_var2value[v.m_id]; + val += v.m_coeff * eval(v.m_id); } return val; } rational model_based_opt::get_coefficient(unsigned row_id, unsigned var_id) const { - row const& r = m_rows[row_id]; - return r.get_coefficient(var_id); + return m_rows[row_id].get_coefficient(var_id); } rational model_based_opt::row::get_coefficient(unsigned var_id) const { @@ -639,7 +652,7 @@ namespace opt { row& r1 = m_rows[row_id1]; row const& r2 = m_rows[row_id2]; unsigned i = 0, j = 0; - for(; i < r1.m_vars.size() || j < r2.m_vars.size(); ) { + while (i < r1.m_vars.size() || j < r2.m_vars.size()) { if (j == r2.m_vars.size()) { m_new_vars.append(r1.m_vars.size() - i, r1.m_vars.c_ptr() + i); break; @@ -707,11 +720,18 @@ namespace opt { } void model_based_opt::display(std::ostream& out, vector const& vars, rational const& coeff) { - for (unsigned i = 0; i < vars.size(); ++i) { - if (i > 0 && vars[i].m_coeff.is_pos()) { + unsigned i = 0; + for (var const& v : vars) { + if (i > 0 && v.m_coeff.is_pos()) { out << "+ "; } - out << vars[i].m_coeff << "* v" << vars[i].m_id << " "; + ++i; + if (v.m_coeff.is_one()) { + out << "v" << v.m_id << " "; + } + else { + out << v.m_coeff << "*v" << v.m_id << " "; + } } if (coeff.is_pos()) { out << " + " << coeff << " "; @@ -921,7 +941,7 @@ namespace opt { return solve_for(eq_row, x, compute_def); } - def result; + def result; unsigned lub_size = lub_rows.size(); unsigned glb_size = glb_rows.size(); unsigned row_index = (lub_size <= glb_size) ? lub_index : glb_index; @@ -935,6 +955,11 @@ namespace opt { else if (glb_index != UINT_MAX) { result = solve_for(glb_index, x, true); } + else { + result = def(); + result.m_coeff = eval(x); + } + SASSERT(eval(result) == eval(x)); } else { for (unsigned row_id : lub_rows) retire_row(row_id); @@ -946,9 +971,19 @@ namespace opt { SASSERT(lub_index != UINT_MAX); SASSERT(glb_index != UINT_MAX); if (compute_def) { +#if 0 def d1(m_rows[lub_index], x); - def d2(m_rows[lub_index], x); + def d2(m_rows[glb_index], x); result = (d1 + d2)/2; +#else + if (lub_size <= glb_size) { + result = def(m_rows[lub_index], x); + } + else { + result = def(m_rows[glb_index], x); + } +#endif + SASSERT(eval(result) == eval(x)); } // The number of matching lower and upper bounds is small. @@ -1045,8 +1080,9 @@ namespace opt { } def result = project(y, compute_def); if (compute_def) { - result = (result * D) + u; + result = (result * D) + u; } + SASSERT(!compute_def || eval(result) == eval(x)); return result; } @@ -1139,8 +1175,11 @@ namespace opt { } } } - // TBD: -t div a - def result(m_rows[row_id1], x); + def result; + if (compute_def) { + result = def(m_rows[row_id1], x); + SASSERT(eval(result) == eval(x)); + } retire_row(row_id1); return result; } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index 268d3d81d..a1137d2fa 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -100,7 +100,11 @@ namespace opt { rational get_coefficient(unsigned row_id, unsigned var_id) const; - rational get_row_value(row const& r) const; + rational eval(row const& r) const; + + rational eval(unsigned x) const; + + rational eval(def const& d) const; void resolve(unsigned row_src, rational const& a1, unsigned row_dst, unsigned x); diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 0b5ad72ca..1709711d7 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -37,6 +37,7 @@ namespace qe { ast_manager& m; arith_util a; + bool m_check_purified; // check that variables are properly pure void insert_mul(expr* x, rational const& v, obj_map& ts) { TRACE("qe", tout << "Adding variable " << mk_pp(x, m) << " " << v << "\n";); @@ -264,7 +265,7 @@ namespace qe { } imp(ast_manager& m): - m(m), a(m) {} + m(m), a(m), m_check_purified(true) {} ~imp() {} @@ -347,17 +348,23 @@ namespace qe { tids.insert(v, mbo.add_var(r, a.is_int(v))); } } - for (expr* fml : fmls) { - mark_rec(fmls_mark, fml); + if (m_check_purified) { + for (expr* fml : fmls) { + mark_rec(fmls_mark, fml); + } + for (auto& kv : tids) { + expr* e = kv.m_key; + if (!var_mark.is_marked(e)) { + mark_rec(fmls_mark, e); + } + } } + ptr_vector index2expr; for (auto& kv : tids) { - expr* e = kv.m_key; - if (!var_mark.is_marked(e)) { - mark_rec(fmls_mark, e); - } - index2expr.setx(kv.m_value, e, 0); + index2expr.setx(kv.m_value, kv.m_key, 0); } + j = 0; unsigned_vector real_vars; for (app* v : vars) { @@ -369,6 +376,7 @@ namespace qe { } } vars.shrink(j); + TRACE("qe", tout << "remaining vars: " << vars << "\n"; for (unsigned v : real_vars) { tout << "v" << v << " " << mk_pp(index2expr[v], m) << "\n"; @@ -379,10 +387,9 @@ namespace qe { vector rows; mbo.get_live_rows(rows); - for (unsigned i = 0; i < rows.size(); ++i) { + for (row const& r : rows) { expr_ref_vector ts(m); expr_ref t(m), s(m), val(m); - row const& r = rows[i]; if (r.m_vars.size() == 0) { continue; } @@ -411,25 +418,19 @@ namespace qe { } ts.push_back(t); } + t = mk_add(ts); s = a.mk_numeral(-r.m_coeff, a.is_int(t)); - if (ts.size() == 1) { - t = ts[0].get(); - } - else { - t = a.mk_add(ts.size(), ts.c_ptr()); - } switch (r.m_type) { case opt::t_lt: t = a.mk_lt(t, s); break; case opt::t_le: t = a.mk_le(t, s); break; case opt::t_eq: t = a.mk_eq(t, s); break; - case opt::t_mod: { + case opt::t_mod: if (!r.m_coeff.is_zero()) { t = a.mk_sub(t, s); } t = a.mk_eq(a.mk_mod(t, a.mk_numeral(r.m_mod, true)), a.mk_int(0)); break; } - } fmls.push_back(t); val = eval(t); CTRACE("qe", !m.is_true(val), tout << "Evaluated " << t << " to " << val << "\n";); @@ -447,19 +448,29 @@ namespace qe { ts.push_back(var2expr(index2expr, v)); } ts.push_back(a.mk_numeral(d.m_coeff, is_int)); - t = a.mk_add(ts.size(), ts.c_ptr()); + t = mk_add(ts); if (!d.m_div.is_one() && is_int) { t = a.mk_idiv(t, a.mk_numeral(d.m_div, is_int)); } else if (!d.m_div.is_one() && !is_int) { t = a.mk_div(t, a.mk_numeral(d.m_div, is_int)); } + SASSERT(eval(t) == eval(x)); result.push_back(def(expr_ref(x, m), t)); } } return result; } + expr_ref mk_add(expr_ref_vector const& ts) { + if (ts.size() == 1) { + return expr_ref(ts.get(0), m); + } + else { + return expr_ref(a.mk_add(ts.size(), ts.c_ptr()), m); + } + } + opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& ge, expr_ref& gt) { SASSERT(a.is_real(t)); expr_ref_vector fmls(fmls0); @@ -577,6 +588,10 @@ namespace qe { return m_imp->project(model, vars, lits); } + void arith_project_plugin::set_check_purified(bool check_purified) { + m_imp->m_check_purified = check_purified; + } + bool arith_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return m_imp->solve(model, vars, lits); } diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index c01d7bbb6..b55e63fcf 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -33,6 +33,12 @@ namespace qe { vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt); + + /** + * \brief check if formulas are purified, or leave it to caller to ensure that + * arithmetic variables nested under foreign functions are handled properly. + */ + void set_check_purified(bool check_purified); }; bool arith_project(model& model, app* var, expr_ref_vector& lits); diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index ae989ba02..20eaf9675 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -77,10 +77,12 @@ Notes: #include "ast/ast_util.h" #include "ast/for_each_expr.h" #include "ast/rewriter/bool_rewriter.h" +#include "ast/arith_decl_plugin.h" #include "model/model_evaluator.h" #include "solver/solver.h" #include "qe/qe_mbi.h" #include "qe/qe_term_graph.h" +#include "qe/qe_arith.h" namespace qe { @@ -141,7 +143,7 @@ namespace qe { } // ------------------------------- - // euf_mbi, TBD + // euf_mbi struct euf_mbi_plugin::is_atom_proc { ast_manager& m; @@ -235,6 +237,140 @@ namespace qe { } + // ------------------------------- + // euf_arith_mbi + + struct euf_arith_mbi_plugin::is_atom_proc { + ast_manager& m; + expr_ref_vector& m_atoms; + is_atom_proc(expr_ref_vector& atoms): m(atoms.m()), m_atoms(atoms) {} + void operator()(app* a) { + if (m.is_eq(a)) { + m_atoms.push_back(a); + } + else if (m.is_bool(a) && a->get_family_id() != m.get_basic_family_id()) { + m_atoms.push_back(a); + } + } + void operator()(expr*) {} + }; + + struct euf_arith_mbi_plugin::is_arith_var_proc { + ast_manager& m; + app_ref_vector& m_vars; + arith_util arith; + obj_hashtable m_exclude; + is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& excl): + m(vars.m()), m_vars(vars), arith(m) { + for (func_decl* f : excl) m_exclude.insert(f); + } + void operator()(app* a) { + if (arith.is_int_real(a) && a->get_family_id() != a->get_family_id() && !m_exclude.contains(a->get_decl())) { + m_vars.push_back(a); + } + } + void operator()(expr*) {} + + }; + + euf_arith_mbi_plugin::euf_arith_mbi_plugin(solver* s, solver* sNot): + m(s->get_manager()), + m_atoms(m), + m_solver(s), + m_dual_solver(sNot) { + params_ref p; + p.set_bool("core.minimize", true); + m_solver->updt_params(p); + m_dual_solver->updt_params(p); + expr_ref_vector fmls(m); + m_solver->get_assertions(fmls); + expr_fast_mark1 marks; + is_atom_proc proc(m_atoms); + for (expr* e : fmls) { + quick_for_each_expr(proc, marks, e); + } + } + + mbi_result euf_arith_mbi_plugin::operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { + lbool r = m_solver->check_sat(lits); + + // populate set of arithmetic variables to be projected. + app_ref_vector avars(m); + is_arith_var_proc _proc(avars, vars); + for (expr* l : lits) quick_for_each_expr(_proc, l); + switch (r) { + case l_false: + lits.reset(); + m_solver->get_unsat_core(lits); + // optionally minimize core using superposition. + return mbi_unsat; + case l_true: { + m_solver->get_model(mdl); + model_evaluator mev(*mdl.get()); + lits.reset(); + for (expr* e : m_atoms) { + if (mev.is_true(e)) { + lits.push_back(e); + } + else if (mev.is_false(e)) { + lits.push_back(m.mk_not(e)); + } + } + TRACE("qe", tout << "atoms from model: " << lits << "\n";); + r = m_dual_solver->check_sat(lits); + expr_ref_vector core(m); + term_graph tg(m); + switch (r) { + case l_false: { + // use the dual solver to find a 'small' implicant + m_dual_solver->get_unsat_core(core); + TRACE("qe", tout << "core: " << core << "\n";); + lits.reset(); + lits.append(core); + arith_util a(m); + + // 1. project arithmetic variables using mdl that satisfies core. + // ground any remaining arithmetic variables using model. + arith_project_plugin ap(m); + ap.set_check_purified(false); + + auto defs = ap.project(*mdl.get(), avars, lits); + // 2. Add the projected definitions to the remaining (euf) literals + for (auto const& def : defs) { + lits.push_back(m.mk_eq(def.var, def.term)); + } + + // 3. Project the remaining literals with respect to EUF. + tg.set_vars(vars, false); + tg.add_lits(lits); + lits.reset(); + lits.append(tg.project(*mdl)); + TRACE("qe", tout << "project: " << lits << "\n";); + return mbi_sat; + } + case l_undef: + return mbi_undef; + case l_true: + UNREACHABLE(); + return mbi_undef; + } + return mbi_sat; + } + default: + // TBD: if not running solver to completion, then: + // 1. extract unit literals from m_solver. + // 2. run a cc over the units + // 3. extract equalities or other assignments over the congruence classes + // 4. ensure that at least some progress is made over original lits. + return mbi_undef; + } + } + + void euf_arith_mbi_plugin::block(expr_ref_vector const& lits) { + m_solver->assert_expr(mk_not(mk_and(lits))); + } + + /** -------------------------------------------------------------- * ping-pong interpolation of Gurfinkel & Vizel * compute a binary interpolant. @@ -318,4 +454,5 @@ namespace qe { } } } + }; diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 671099015..6d0d8dcf6 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -86,29 +86,29 @@ namespace qe { void block(expr_ref_vector const& lits) override; }; + class euf_arith_mbi_plugin : mbi_plugin { + ast_manager& m; + expr_ref_vector m_atoms; + solver_ref m_solver; + solver_ref m_dual_solver; + struct is_atom_proc; + struct is_arith_var_proc; + public: + euf_arith_mbi_plugin(solver* s, solver* sNot); + ~euf_arith_mbi_plugin() override {} + mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; + void block(expr_ref_vector const& lits) override; + }; + /** * use cases for interpolation. */ class interpolator { - ast_manager& m; + ast_manager& m; public: interpolator(ast_manager& m):m(m) {} lbool pingpong(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); lbool pogo(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); }; -#if 0 - TBD some other scenario, e.g., Farkas, Cute/Beautiful/maybe even Selfless - - class solver_mbi_plugin : public mbi_plugin { - solver_ref m_solver; - public: - solver_mbi_plugin(solver* s); - ~solver_mbi_plugin() override {} - mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; - void block(expr_ref_vector const& lits) override; - }; - - -#endif }; diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index f2f6004ff..1bae7435f 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -360,6 +360,37 @@ static void test10() { mbo.display(std::cout); } +static void test11() { + { + opt::model_based_opt mbo; + unsigned s = mbo.add_var(rational(2), true); + unsigned a = mbo.add_var(rational(1), true); + unsigned t = mbo.add_var(rational(3), true); + + add_ineq(mbo, s, 1, a, -2, 0, opt::t_le); // s - 2a <= 0 + add_ineq(mbo, a, 2, t, -1, 0, opt::t_le); // 2a - t <= 0 + + mbo.display(std::cout); + display_project(mbo.project(1, &a, true)); + mbo.display(std::cout); + } + + { + opt::model_based_opt mbo; + unsigned s = mbo.add_var(rational(3), true); + unsigned a = mbo.add_var(rational(2), true); + unsigned t = mbo.add_var(rational(4), true); + + add_ineq(mbo, s, 1, a, -2, 0, opt::t_le); // s - 2a <= 0 + add_ineq(mbo, a, 2, t, -1, 0, opt::t_le); // 2a - t <= 0 + + mbo.display(std::cout); + display_project(mbo.project(1, &a, true)); + mbo.display(std::cout); + } + +} + // test with mix of upper and lower bounds void tst_model_based_opt() { @@ -374,4 +405,5 @@ void tst_model_based_opt() { test7(); test8(); test9(); + test11(); } From 9ba76a13326641dff18e52343617e852a278edb8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jun 2018 14:43:38 -0700 Subject: [PATCH 1214/1283] fixing eufi Signed-off-by: Nikolaj Bjorner --- src/cmd_context/extra_cmds/dbg_cmds.cpp | 12 ++++-- src/qe/qe_arith.cpp | 16 ++------ src/qe/qe_mbi.cpp | 50 +++++++++++++------------ src/qe/qe_mbi.h | 31 ++++++++++----- src/qe/qe_term_graph.cpp | 6 ++- 5 files changed, 64 insertions(+), 51 deletions(-) diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index d45cb9df9..64eeac42e 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -435,7 +435,9 @@ public: sB->assert_expr(b); qe::prop_mbi_plugin pA(sA.get()); qe::prop_mbi_plugin pB(sB.get()); - lbool res = mbi.pingpong(pA, pB, vars, itp); + pA.set_shared(vars); + pB.set_shared(vars); + lbool res = mbi.pingpong(pA, pB, itp); ctx.regular_stream() << res << " " << itp << "\n"; } }; @@ -485,9 +487,11 @@ public: sNotA->assert_expr(m.mk_not(a)); sB->assert_expr(b); sNotB->assert_expr(m.mk_not(b)); - qe::euf_mbi_plugin pA(sA.get(), sNotA.get()); - qe::euf_mbi_plugin pB(sB.get(), sNotB.get()); - lbool res = mbi.pogo(pA, pB, vars, itp); + qe::euf_arith_mbi_plugin pA(sA.get(), sNotA.get()); + qe::euf_arith_mbi_plugin pB(sB.get(), sNotB.get()); + pA.set_shared(vars); + pB.set_shared(vars); + lbool res = mbi.pogo(pA, pB, itp); ctx.regular_stream() << res << " " << itp << "\n"; } }; diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 1709711d7..cd11d4635 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -257,7 +257,7 @@ namespace qe { }; bool is_arith(expr* e) { - return a.is_int(e) || a.is_real(e); + return a.is_int_real(e); } rational n_sign(rational const& b) { @@ -276,7 +276,7 @@ namespace qe { bool operator()(model& model, app* v, app_ref_vector& vars, expr_ref_vector& lits) { app_ref_vector vs(m); vs.push_back(v); - (*this)(model, vs, lits); + project(model, vs, lits, false); return vs.empty(); } @@ -284,14 +284,6 @@ namespace qe { typedef opt::model_based_opt::row row; typedef vector vars; - vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - return project(model, vars, lits, true); - } - - void operator()(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { - project(model, vars, fmls, false); - } - expr_ref var2expr(ptr_vector const& index2expr, var const& v) { expr_ref t(index2expr[v.m_id], m); if (!v.m_coeff.is_one()) { @@ -581,11 +573,11 @@ namespace qe { } void arith_project_plugin::operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - (*m_imp)(model, vars, lits); + m_imp->project(model, vars, lits, false); } vector arith_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - return m_imp->project(model, vars, lits); + return m_imp->project(model, vars, lits, true); } void arith_project_plugin::set_check_purified(bool check_purified) { diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 20eaf9675..e3bd5e17f 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -87,9 +87,9 @@ Notes: namespace qe { - lbool mbi_plugin::check(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { + lbool mbi_plugin::check(expr_ref_vector& lits, model_ref& mdl) { while (true) { - switch ((*this)(vars, lits, mdl)) { + switch ((*this)(lits, mdl)) { case mbi_sat: return l_true; case mbi_unsat: @@ -106,12 +106,11 @@ namespace qe { // ------------------------------- // prop_mbi - prop_mbi_plugin::prop_mbi_plugin(solver* s): m_solver(s) {} + prop_mbi_plugin::prop_mbi_plugin(solver* s): mbi_plugin(s->get_manager()), m_solver(s) {} // sketch of propositional - mbi_result prop_mbi_plugin::operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { - ast_manager& m = lits.m(); + mbi_result prop_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) { lbool r = m_solver->check_sat(lits); switch (r) { case l_false: @@ -123,7 +122,7 @@ namespace qe { lits.reset(); for (unsigned i = 0, sz = mdl->get_num_constants(); i < sz; ++i) { func_decl* c = mdl->get_constant(i); - if (vars.contains(c)) { + if (m_shared.contains(c)) { if (m.is_true(mdl->get_const_interp(c))) { lits.push_back(m.mk_const(c)); } @@ -161,7 +160,7 @@ namespace qe { }; euf_mbi_plugin::euf_mbi_plugin(solver* s, solver* sNot): - m(s->get_manager()), + mbi_plugin(s->get_manager()), m_atoms(m), m_solver(s), m_dual_solver(sNot) { @@ -178,7 +177,7 @@ namespace qe { } } - mbi_result euf_mbi_plugin::operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { + mbi_result euf_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) { lbool r = m_solver->check_sat(lits); switch (r) { case l_false: @@ -208,7 +207,7 @@ namespace qe { m_dual_solver->get_unsat_core(core); TRACE("qe", tout << "core: " << core << "\n";); // project the implicant onto vars - tg.set_vars(vars, false); + tg.set_vars(m_shared, false); tg.add_lits(core); lits.reset(); lits.append(tg.project(*mdl)); @@ -260,12 +259,13 @@ namespace qe { app_ref_vector& m_vars; arith_util arith; obj_hashtable m_exclude; - is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& excl): + is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): m(vars.m()), m_vars(vars), arith(m) { - for (func_decl* f : excl) m_exclude.insert(f); + for (func_decl* f : shared) m_exclude.insert(f); } void operator()(app* a) { - if (arith.is_int_real(a) && a->get_family_id() != a->get_family_id() && !m_exclude.contains(a->get_decl())) { + TRACE("qe", tout << expr_ref(a, m) << " " << arith.is_int_real(a) << " " << a->get_family_id() << "\n";); + if (arith.is_int_real(a) && a->get_family_id() != arith.get_family_id() && !m_exclude.contains(a->get_decl())) { m_vars.push_back(a); } } @@ -274,7 +274,7 @@ namespace qe { }; euf_arith_mbi_plugin::euf_arith_mbi_plugin(solver* s, solver* sNot): - m(s->get_manager()), + mbi_plugin(s->get_manager()), m_atoms(m), m_solver(s), m_dual_solver(sNot) { @@ -291,13 +291,9 @@ namespace qe { } } - mbi_result euf_arith_mbi_plugin::operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) { + mbi_result euf_arith_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) { lbool r = m_solver->check_sat(lits); - // populate set of arithmetic variables to be projected. - app_ref_vector avars(m); - is_arith_var_proc _proc(avars, vars); - for (expr* l : lits) quick_for_each_expr(_proc, l); switch (r) { case l_false: lits.reset(); @@ -328,6 +324,11 @@ namespace qe { lits.reset(); lits.append(core); arith_util a(m); + // populate set of arithmetic variables to be projected. + app_ref_vector avars(m); + is_arith_var_proc _proc(avars, m_shared); + for (expr* l : lits) quick_for_each_expr(_proc, l); + TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); // 1. project arithmetic variables using mdl that satisfies core. // ground any remaining arithmetic variables using model. @@ -339,9 +340,10 @@ namespace qe { for (auto const& def : defs) { lits.push_back(m.mk_eq(def.var, def.term)); } + TRACE("qe", tout << "# arith defs" << defs.size() << " avars: " << avars << " " << lits << "\n";); // 3. Project the remaining literals with respect to EUF. - tg.set_vars(vars, false); + tg.set_vars(m_shared, false); tg.add_lits(lits); lits.reset(); lits.append(tg.project(*mdl)); @@ -375,7 +377,7 @@ namespace qe { * ping-pong interpolation of Gurfinkel & Vizel * compute a binary interpolant. */ - lbool interpolator::pingpong(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { + lbool interpolator::pingpong(mbi_plugin& a, mbi_plugin& b, expr_ref& itp) { model_ref mdl; expr_ref_vector lits(m); bool turn = true; @@ -389,7 +391,7 @@ namespace qe { while (true) { auto* t1 = turn ? &a : &b; auto* t2 = turn ? &b : &a; - mbi_result next_res = (*t1)(vars, lits, mdl); + mbi_result next_res = (*t1)(lits, mdl); switch (next_res) { case mbi_sat: if (last_res == mbi_sat) { @@ -429,14 +431,14 @@ namespace qe { * One-sided pogo creates clausal interpolants. * It creates a set of consequences of b that are inconsistent with a. */ - lbool interpolator::pogo(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp) { + lbool interpolator::pogo(mbi_plugin& a, mbi_plugin& b, expr_ref& itp) { expr_ref_vector lits(m), itps(m); while (true) { model_ref mdl; lits.reset(); - switch (a.check(vars, lits, mdl)) { + switch (a.check(lits, mdl)) { case l_true: - switch (b.check(vars, lits, mdl)) { + switch (b.check(lits, mdl)) { case l_true: return l_true; case l_false: diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 6d0d8dcf6..e0e2021d8 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -29,8 +29,21 @@ namespace qe { }; class mbi_plugin { + protected: + ast_manager& m; + func_decl_ref_vector m_shared; public: + mbi_plugin(ast_manager& m): m(m), m_shared(m) {} virtual ~mbi_plugin() {} + + /** + * Set the shared symbols. + */ + virtual void set_shared(func_decl_ref_vector const& vars) { + m_shared.reset(); + m_shared.append(vars); + } + /** * \brief Utility that works modulo a background state. * - vars @@ -50,7 +63,7 @@ namespace qe { * - mbi_undef: * inconclusive, */ - virtual mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) = 0; + virtual mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) = 0; /** * \brief Block conjunction of lits from future mbi_augment or mbi_sat. @@ -60,7 +73,7 @@ namespace qe { /** * \brief perform a full check, consume internal auguments if necessary. */ - lbool check(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl); + lbool check(expr_ref_vector& lits, model_ref& mdl); }; @@ -69,12 +82,11 @@ namespace qe { public: prop_mbi_plugin(solver* s); ~prop_mbi_plugin() override {} - mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; + mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) override; void block(expr_ref_vector const& lits) override; }; class euf_mbi_plugin : public mbi_plugin { - ast_manager& m; expr_ref_vector m_atoms; solver_ref m_solver; solver_ref m_dual_solver; @@ -82,12 +94,11 @@ namespace qe { public: euf_mbi_plugin(solver* s, solver* sNot); ~euf_mbi_plugin() override {} - mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; + mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) override; void block(expr_ref_vector const& lits) override; }; - class euf_arith_mbi_plugin : mbi_plugin { - ast_manager& m; + class euf_arith_mbi_plugin : public mbi_plugin { expr_ref_vector m_atoms; solver_ref m_solver; solver_ref m_dual_solver; @@ -96,7 +107,7 @@ namespace qe { public: euf_arith_mbi_plugin(solver* s, solver* sNot); ~euf_arith_mbi_plugin() override {} - mbi_result operator()(func_decl_ref_vector const& vars, expr_ref_vector& lits, model_ref& mdl) override; + mbi_result operator()(expr_ref_vector& lits, model_ref& mdl) override; void block(expr_ref_vector const& lits) override; }; @@ -107,8 +118,8 @@ namespace qe { ast_manager& m; public: interpolator(ast_manager& m):m(m) {} - lbool pingpong(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); - lbool pogo(mbi_plugin& a, mbi_plugin& b, func_decl_ref_vector const& vars, expr_ref& itp); + lbool pingpong(mbi_plugin& a, mbi_plugin& b, expr_ref& itp); + lbool pogo(mbi_plugin& a, mbi_plugin& b, expr_ref& itp); }; }; diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 467a0cc48..ac68516c3 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -761,11 +761,15 @@ namespace qe { val2rep.insert(val, rep); } } + // TBD: this ignores types, need one use of 'distinct' per sort. + // TBD: probably ignore distinct on values + // TBD: ignore distinct on Booleans ptr_buffer reps; for (auto &kv : val2rep) { reps.push_back(kv.m_value); + std::cout << mk_pp(kv.m_value, m) << "\n"; } - res.push_back(m.mk_distinct(reps.size(), reps.c_ptr())); + // res.push_back(m.mk_distinct(reps.size(), reps.c_ptr())); } public: From f0e105612c7bc7f208a12609fa06c4ca476c811a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jun 2018 15:09:45 -0700 Subject: [PATCH 1215/1283] adding dbg Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arith.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index cd11d4635..e9653bf14 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -30,6 +30,7 @@ Revision History: #include "ast/rewriter/expr_safe_replace.h" #include "math/simplex/model_based_opt.h" #include "model/model_evaluator.h" +#include "model/model_smt2_pp.h" namespace qe { @@ -91,6 +92,8 @@ namespace qe { rational r1, r2; expr_ref val1 = eval(e1); expr_ref val2 = eval(e2); + TRACE("qe", tout << mk_pp(e1, m) << " " << val1 << "\n";); + TRACE("qe", tout << mk_pp(e2, m) << " " << val2 << "\n";); if (!a.is_numeral(val1, r1)) return false; if (!a.is_numeral(val2, r2)) return false; SASSERT(r1 != r2); @@ -108,6 +111,7 @@ namespace qe { vector > nums; for (expr* arg : *alit) { val = eval(arg); + TRACE("qe", tout << mk_pp(arg, m) << " " << val << "\n";); if (!a.is_numeral(val, r)) return false; nums.push_back(std::make_pair(arg, r)); } @@ -130,6 +134,7 @@ namespace qe { expr* arg1 = to_app(lit)->get_arg(i), *arg2 = nullptr; rational r; expr_ref val = eval(arg1); + TRACE("qe", tout << mk_pp(arg1, m) << " " << val << "\n";); if (!a.is_numeral(val, r)) return false; if (values.find(r, arg2)) { ty = opt::t_eq; @@ -301,6 +306,7 @@ namespace qe { return vector(); } model_evaluator eval(model); + TRACE("qe", model_smt2_pp(tout, m, model, 0);); // eval.set_model_completion(true); opt::model_based_opt mbo; @@ -311,10 +317,10 @@ namespace qe { for (unsigned i = 0; i < fmls.size(); ++i) { expr * fml = fmls.get(i); if (!linearize(mbo, eval, fml, fmls, tids)) { + TRACE("qe", tout << "could not linearize: " << mk_pp(fml, m) << "\n";); fmls[j++] = fml; } else { - TRACE("qe", tout << "could not linearize: " << mk_pp(fml, m) << "\n";); pinned.push_back(fml); } } From a56c9faedbe20cd296b09cfc8071e1b4c5066490 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Jun 2018 19:33:18 -0700 Subject: [PATCH 1216/1283] A sketch of vurtego --- src/qe/qe_mbi.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++++-- src/qe/qe_mbi.h | 12 +++++-- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index e3bd5e17f..57dfff941 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -259,7 +259,7 @@ namespace qe { app_ref_vector& m_vars; arith_util arith; obj_hashtable m_exclude; - is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): + is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): m(vars.m()), m_vars(vars), arith(m) { for (func_decl* f : shared) m_exclude.insert(f); } @@ -326,7 +326,7 @@ namespace qe { arith_util a(m); // populate set of arithmetic variables to be projected. app_ref_vector avars(m); - is_arith_var_proc _proc(avars, m_shared); + is_arith_var_proc _proc(avars, m_shared); for (expr* l : lits) quick_for_each_expr(_proc, l); TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); @@ -457,4 +457,79 @@ namespace qe { } } + lbool interpolator::vurtego(mbi_plugin& a, mbi_plugin& b, expr_ref& itp, model_ref &mdl) { + /** + Assumptions on mbi_plugin() + Let local be assertions local to the plugin + Let blocked be clauses added by blocked, kept separately from local + mbi_plugin::check(lits, mdl, bool force_model): + if lits.empty() and mdl == nullptr then + if is_sat(local & blocked) then + return l_true, mbp of local, mdl of local & blocked + else + return l_false + else if !lits.empty() then + if is_sat(local & mdl & blocked) + return l_true, lits, extension of mdl to local + else if is_sat(local & lits & blocked) + if (force_model) then + return l_false, core of model, nullptr + else + return l_true, mbp of local, mdl of local & blocked + else if !is_sat(local & lits) then + return l_false, mbp of local, nullptr + else if is_sat(local & lits) && !is_sat(local & lits & blocked) + MISSING CASE. IS IT POSSIBLE? + MUST PRODUCE AN IMPLICANT OF LOCAL that is inconsistent with lits & blocked + + mbi_plugin::block(phi): add phi to blocked + + probably should use the operator() instead of check. + mbi_augment -- means consistent with lits but not with the mdl + mbi_sat -- means consistent with lits and mdl + + */ + expr_ref_vector lits(m), itps(m); + while (true) { + // when lits.empty(), this picks an A-implicant consistent with B + // when !lits.empty(), checks whether mdl of shared vocab extends to A + switch (a.check_ag(lits, mdl, !lits.empty())) { + case l_true: + if (!lits.empty()) + // mdl is a model for a && b + return l_true; + switch (b.check_ag(lits, mdl, false)) { + case l_true: + /* can return true if know that b did not change + the model. For now, cycle back to A. */ + SASSERT(!lits.empty()); + SASSERT(mdl); + break; + case l_false: + // Force a different A-implicant + a.block(lits); + lits.reset(); + mdl.reset(); + break; + case l_undef: + return l_undef; + } + case l_false: + if (lits.empty()) { + // no more A-implicants, terminate + itp = mk_and(itps); + return l_false; + } + // force B to pick a different model or a different implicant + b.block(lits); + itps.push_back(mk_not(mk_and(lits))); + lits.reset(); + mdl.reset(); + break; + case l_undef: + return l_undef; + } + } + } + }; diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index e0e2021d8..5e43a6412 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -39,9 +39,9 @@ namespace qe { /** * Set the shared symbols. */ - virtual void set_shared(func_decl_ref_vector const& vars) { - m_shared.reset(); - m_shared.append(vars); + virtual void set_shared(func_decl_ref_vector const& vars) { + m_shared.reset(); + m_shared.append(vars); } /** @@ -75,6 +75,11 @@ namespace qe { */ lbool check(expr_ref_vector& lits, model_ref& mdl); + virtual lbool check_ag(expr_ref_vector& lits, model_ref& mdl, bool force_model) { + return l_undef; + } + + }; class prop_mbi_plugin : public mbi_plugin { @@ -120,6 +125,7 @@ namespace qe { interpolator(ast_manager& m):m(m) {} lbool pingpong(mbi_plugin& a, mbi_plugin& b, expr_ref& itp); lbool pogo(mbi_plugin& a, mbi_plugin& b, expr_ref& itp); + lbool vurtego(mbi_plugin &a, mbi_plugin &b, expr_ref &itp, model_ref &mdl); }; }; From 732a8149d8b3662e6482f3070319c1de40120b12 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 13 Jun 2018 19:46:12 -0700 Subject: [PATCH 1217/1283] vurtego update --- src/qe/qe_mbi.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 57dfff941..6f2c346f0 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -479,8 +479,11 @@ namespace qe { else if !is_sat(local & lits) then return l_false, mbp of local, nullptr else if is_sat(local & lits) && !is_sat(local & lits & blocked) - MISSING CASE. IS IT POSSIBLE? + MISSING CASE MUST PRODUCE AN IMPLICANT OF LOCAL that is inconsistent with lits & blocked + in this case !is_sat(local & lits & mdl) so + return l_false, core of lits & mdl, nullptr + this will force a new mdl mbi_plugin::block(phi): add phi to blocked From 49279d70470d9acd5ab018a0058570835486b097 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jun 2018 21:17:35 -0700 Subject: [PATCH 1218/1283] debugging mbi Signed-off-by: Nikolaj Bjorner --- src/ast/for_each_expr.h | 14 ++++ src/math/simplex/model_based_opt.cpp | 36 ++++++++-- src/math/simplex/model_based_opt.h | 2 + src/qe/qe_arith.cpp | 13 ++-- src/qe/qe_mbi.cpp | 102 ++++++++++++++------------- src/qe/qe_mbi.h | 4 ++ 6 files changed, 112 insertions(+), 59 deletions(-) diff --git a/src/ast/for_each_expr.h b/src/ast/for_each_expr.h index 50a4089dc..6e203ccee 100644 --- a/src/ast/for_each_expr.h +++ b/src/ast/for_each_expr.h @@ -128,6 +128,20 @@ void for_each_expr(ForEachProc & proc, expr * n) { for_each_expr_core(proc, visited, n); } +template +void for_each_expr(ForEachProc & proc, unsigned n, expr * const* es) { + expr_mark visited; + for (unsigned i = 0; i < n; ++i) + for_each_expr_core(proc, visited, es[i]); +} + +template +void for_each_expr(ForEachProc & proc, expr_ref_vector const& es) { + expr_mark visited; + for (expr* e : es) + for_each_expr_core(proc, visited, e); +} + template void quick_for_each_expr(ForEachProc & proc, expr_fast_mark1 & visited, expr * n) { for_each_expr_core(proc, visited, n); diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 56d51648d..93e55bedd 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -523,18 +523,26 @@ 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; - bool use_case1 = - (src_c * dst_val + dst_c * src_val + slack).is_nonpos() - || abs_src_c.is_one() - || abs_dst_c.is_one(); + rational distance = src_c * dst_val + dst_c * src_val + slack; + bool use_case1 = distance.is_nonpos() || abs_src_c.is_one() || abs_dst_c.is_one(); + + if (distance.is_nonpos() && !abs_src_c.is_one() && !abs_dst_c.is_one()) { + unsigned r = copy_row(row_src); + mul_add(false, r, rational::one(), row_dst); + del_var(r, x); + add(r, slack); + TRACE("qe", tout << m_rows[r];); + SASSERT(!m_rows[r].m_value.is_pos()); + } if (use_case1) { + TRACE("opt", tout << "slack: " << slack << " " << src_c << " " << dst_val << " " << dst_c << " " << src_val << "\n";); // dst <- abs_src_c*dst + abs_dst_c*src - slack mul(row_dst, abs_src_c); sub(row_dst, slack); - mul_add(false, row_dst, abs_dst_c, row_src); + mul_add(false, row_dst, abs_dst_c, row_src); return; - } + } // // create finite disjunction for |b|. @@ -555,6 +563,7 @@ namespace opt { // exists z in [0 .. |b|-2] . |b| | (z + s) && a*n_sign(b)(s + z) + |b|t <= 0 // + TRACE("qe", tout << "finite disjunction " << distance << " " << src_c << " " << dst_c << "\n";); vector coeffs; if (abs_dst_c <= abs_src_c) { rational z = mod(dst_val, abs_dst_c); @@ -611,6 +620,21 @@ namespace opt { r.m_value -= c; } + void model_based_opt::del_var(unsigned dst, unsigned x) { + row& r = m_rows[dst]; + unsigned j = 0; + for (var & v : r.m_vars) { + if (v.m_id == x) { + r.m_value -= eval(x)*r.m_coeff; + } + else { + r.m_vars[j++] = v; + } + } + r.m_vars.shrink(j); + } + + void model_based_opt::normalize(unsigned row_id) { row& r = m_rows[row_id]; if (r.m_vars.empty()) return; diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index a1137d2fa..e52d0cfe0 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -120,6 +120,8 @@ namespace opt { void sub(unsigned dst, rational const& c); + void del_var(unsigned dst, unsigned x); + void set_row(unsigned row_id, vector const& coeffs, rational const& c, rational const& m, ineq_type rel); void add_constraint(vector const& coeffs, rational const& c, rational const& m, ineq_type r); diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index e9653bf14..7e619ccd5 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -417,7 +417,7 @@ namespace qe { ts.push_back(t); } t = mk_add(ts); - s = a.mk_numeral(-r.m_coeff, a.is_int(t)); + s = a.mk_numeral(-r.m_coeff, r.m_coeff.is_int() && a.is_int(t)); switch (r.m_type) { case opt::t_lt: t = a.mk_lt(t, s); break; case opt::t_le: t = a.mk_le(t, s); break; @@ -445,7 +445,8 @@ namespace qe { for (var const& v : d.m_vars) { ts.push_back(var2expr(index2expr, v)); } - ts.push_back(a.mk_numeral(d.m_coeff, is_int)); + if (!d.m_coeff.is_zero()) + ts.push_back(a.mk_numeral(d.m_coeff, is_int)); t = mk_add(ts); if (!d.m_div.is_one() && is_int) { t = a.mk_idiv(t, a.mk_numeral(d.m_div, is_int)); @@ -461,10 +462,12 @@ namespace qe { } expr_ref mk_add(expr_ref_vector const& ts) { - if (ts.size() == 1) { + switch (ts.size()) { + case 0: + return expr_ref(a.mk_int(0), m); + case 1: return expr_ref(ts.get(0), m); - } - else { + default: return expr_ref(a.mk_add(ts.size(), ts.c_ptr()), m); } } diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 6f2c346f0..070c5279c 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -259,12 +259,11 @@ namespace qe { app_ref_vector& m_vars; arith_util arith; obj_hashtable m_exclude; - is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): + is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): m(vars.m()), m_vars(vars), arith(m) { for (func_decl* f : shared) m_exclude.insert(f); } void operator()(app* a) { - TRACE("qe", tout << expr_ref(a, m) << " " << arith.is_int_real(a) << " " << a->get_family_id() << "\n";); if (arith.is_int_real(a) && a->get_family_id() != arith.get_family_id() && !m_exclude.contains(a->get_decl())) { m_vars.push_back(a); } @@ -291,17 +290,7 @@ namespace qe { } } - mbi_result euf_arith_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) { - lbool r = m_solver->check_sat(lits); - - switch (r) { - case l_false: - lits.reset(); - m_solver->get_unsat_core(lits); - // optionally minimize core using superposition. - return mbi_unsat; - case l_true: { - m_solver->get_model(mdl); + bool euf_arith_mbi_plugin::get_literals(model_ref& mdl, expr_ref_vector& lits) { model_evaluator mev(*mdl.get()); lits.reset(); for (expr* e : m_atoms) { @@ -313,49 +302,65 @@ namespace qe { } } TRACE("qe", tout << "atoms from model: " << lits << "\n";); - r = m_dual_solver->check_sat(lits); - expr_ref_vector core(m); - term_graph tg(m); - switch (r) { - case l_false: { + lbool r = m_dual_solver->check_sat(lits); + if (l_false == r) { // use the dual solver to find a 'small' implicant - m_dual_solver->get_unsat_core(core); - TRACE("qe", tout << "core: " << core << "\n";); lits.reset(); - lits.append(core); + m_dual_solver->get_unsat_core(lits); + return true; + } + else { + return false; + } + } + + app_ref_vector euf_arith_mbi_plugin::get_arith_vars(expr_ref_vector const& lits) { arith_util a(m); - // populate set of arithmetic variables to be projected. app_ref_vector avars(m); - is_arith_var_proc _proc(avars, m_shared); - for (expr* l : lits) quick_for_each_expr(_proc, l); - TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); + is_arith_var_proc _proc(avars, m_shared); + for_each_expr(_proc, lits); + return avars; + } - // 1. project arithmetic variables using mdl that satisfies core. - // ground any remaining arithmetic variables using model. - arith_project_plugin ap(m); - ap.set_check_purified(false); + mbi_result euf_arith_mbi_plugin::operator()(expr_ref_vector& lits, model_ref& mdl) { + lbool r = m_solver->check_sat(lits); - auto defs = ap.project(*mdl.get(), avars, lits); - // 2. Add the projected definitions to the remaining (euf) literals - for (auto const& def : defs) { - lits.push_back(m.mk_eq(def.var, def.term)); - } - TRACE("qe", tout << "# arith defs" << defs.size() << " avars: " << avars << " " << lits << "\n";); - - // 3. Project the remaining literals with respect to EUF. - tg.set_vars(m_shared, false); - tg.add_lits(lits); - lits.reset(); - lits.append(tg.project(*mdl)); - TRACE("qe", tout << "project: " << lits << "\n";); - return mbi_sat; - } - case l_undef: - return mbi_undef; - case l_true: - UNREACHABLE(); + switch (r) { + case l_false: + lits.reset(); + m_solver->get_unsat_core(lits); + TRACE("qe", tout << "unsat core: " << lits << "\n";); + // optionally minimize core using superposition. + return mbi_unsat; + case l_true: { + m_solver->get_model(mdl); + if (!get_literals(mdl, lits)) { return mbi_undef; } + app_ref_vector avars = get_arith_vars(lits); + + TRACE("qe", tout << "vars: " << avars << " lits: " << lits << "\n";); + + // 1. project arithmetic variables using mdl that satisfies core. + // ground any remaining arithmetic variables using model. + arith_project_plugin ap(m); + ap.set_check_purified(false); + + auto defs = ap.project(*mdl.get(), avars, lits); + // 2. Add the projected definitions to the remaining (euf) literals + for (auto const& def : defs) { + lits.push_back(m.mk_eq(def.var, def.term)); + } + TRACE("qe", tout << "# arith defs" << defs.size() << " avars: " << avars << " " << lits << "\n";); + + // 3. Project the remaining literals with respect to EUF. + term_graph tg(m); + tg.set_vars(m_shared, false); + tg.add_lits(lits); + lits.reset(); + //lits.append(tg.project(*mdl)); + lits.append(tg.project()); + TRACE("qe", tout << "project: " << lits << "\n";); return mbi_sat; } default: @@ -448,6 +453,7 @@ namespace qe { case l_undef: return l_undef; } + break; case l_false: itp = mk_and(itps); return l_false; diff --git a/src/qe/qe_mbi.h b/src/qe/qe_mbi.h index 5e43a6412..22a0864ba 100644 --- a/src/qe/qe_mbi.h +++ b/src/qe/qe_mbi.h @@ -109,6 +109,10 @@ namespace qe { solver_ref m_dual_solver; struct is_atom_proc; struct is_arith_var_proc; + + app_ref_vector get_arith_vars(expr_ref_vector const& lits); + bool get_literals(model_ref& mdl, expr_ref_vector& lits); + public: euf_arith_mbi_plugin(solver* s, solver* sNot); ~euf_arith_mbi_plugin() override {} From 19023603612b75cc921e2cae031b45086dbd5acb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Jun 2018 21:33:21 -0700 Subject: [PATCH 1219/1283] debugging mbi Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 93e55bedd..4efab1935 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -526,6 +526,7 @@ namespace opt { rational distance = src_c * dst_val + dst_c * src_val + slack; bool use_case1 = distance.is_nonpos() || abs_src_c.is_one() || abs_dst_c.is_one(); +#if 0 if (distance.is_nonpos() && !abs_src_c.is_one() && !abs_dst_c.is_one()) { unsigned r = copy_row(row_src); mul_add(false, r, rational::one(), row_dst); @@ -534,12 +535,13 @@ namespace opt { TRACE("qe", tout << m_rows[r];); SASSERT(!m_rows[r].m_value.is_pos()); } +#endif if (use_case1) { TRACE("opt", tout << "slack: " << slack << " " << src_c << " " << dst_val << " " << dst_c << " " << src_val << "\n";); - // dst <- abs_src_c*dst + abs_dst_c*src - slack + // dst <- abs_src_c*dst + abs_dst_c*src + slack mul(row_dst, abs_src_c); - sub(row_dst, slack); + add(row_dst, slack); mul_add(false, row_dst, abs_dst_c, row_src); return; } From bbd917a0e66b90ab237f6076d8c88d83abd977cb Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 14 Jun 2018 06:36:44 -0700 Subject: [PATCH 1220/1283] Remove dead comment --- src/sat/ba_solver.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 669389d2a..d7cdea132 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -527,14 +527,12 @@ namespace sat { bool ba_solver::init_watch(pb& p) { clear_watch(p); if (p.lit() != null_literal && value(p.lit()) == l_false) { - //IF_VERBOSE(0, verbose_stream() << "negate: " << p.k() << "\n"); p.negate(); } VERIFY(p.lit() == null_literal || value(p.lit()) == l_true); unsigned sz = p.size(), bound = p.k(); - //IF_VERBOSE(0, verbose_stream() << "bound: " << p.k() << "\n"); - + // put the non-false literals into the head. unsigned slack = 0, slack1 = 0, num_watch = 0, j = 0; for (unsigned i = 0; i < sz; ++i) { From e355123e372551606ca96c550501e0d0876bde2e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 14 Jun 2018 06:37:09 -0700 Subject: [PATCH 1221/1283] Change declaration of projector --- src/qe/qe_term_graph.cpp | 470 +++++++++++++++++++-------------------- src/qe/qe_term_graph.h | 3 +- 2 files changed, 235 insertions(+), 238 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index ac68516c3..f12d51b9d 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -540,270 +540,268 @@ namespace qe { m_cg_table.reset(); } - namespace { - class projector { - term_graph &m_tg; - ast_manager &m; - u_map m_term2app; - u_map m_root2rep; + class term_graph::projector { + term_graph &m_tg; + ast_manager &m; + u_map m_term2app; + u_map m_root2rep; - model_ref m_model; - expr_ref_vector m_pinned; // tracks expr in the maps + model_ref m_model; + expr_ref_vector m_pinned; // tracks expr in the maps - expr* mk_pure(term const& t) { - expr* e = nullptr; - if (m_term2app.find(t.get_id(), e)) return e; - e = t.get_expr(); - if (!is_app(e)) return nullptr; - app* a = ::to_app(e); - expr_ref_buffer kids(m); - for (term* ch : term::children(t)) { - if (!m_root2rep.find(ch->get_root().get_id(), e)) return nullptr; - kids.push_back(e); - } - expr* pure = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); - m_pinned.push_back(pure); - m_term2app.insert(t.get_id(), pure); - return pure; + expr* mk_pure(term const& t) { + expr* e = nullptr; + if (m_term2app.find(t.get_id(), e)) return e; + e = t.get_expr(); + if (!is_app(e)) return nullptr; + app* a = ::to_app(e); + expr_ref_buffer kids(m); + for (term* ch : term::children(t)) { + if (!m_root2rep.find(ch->get_root().get_id(), e)) return nullptr; + kids.push_back(e); + } + expr* pure = m.mk_app(a->get_decl(), kids.size(), kids.c_ptr()); + m_pinned.push_back(pure); + m_term2app.insert(t.get_id(), pure); + return pure; + } + + + bool is_better_rep(expr *t1, expr *t2) { + if (!t2) return t1 != nullptr; + return m.is_unique_value(t1) && !m.is_unique_value(t2); + } + + void purify() { + // - propagate representatives up over parents. + // use work-list + marking to propagate. + // - produce equalities over represented classes. + // - produce other literals over represented classes + // (walk disequalities in m_lits and represent + // lhs/rhs over decls or excluding decls) + + ptr_vector worklist; + for (term * t : m_tg.m_terms) { + worklist.push_back(t); + t->set_mark(true); } + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) + continue; + if (!t->is_theory() && is_projected(*t)) + continue; - bool is_better_rep(expr *t1, expr *t2) { - if (!t2) return t1 != nullptr; - return m.is_unique_value(t1) && !m.is_unique_value(t2); - } + expr* pure = mk_pure(*t); + if (!pure) continue; - void purify() { - // - propagate representatives up over parents. - // use work-list + marking to propagate. - // - produce equalities over represented classes. - // - produce other literals over represented classes - // (walk disequalities in m_lits and represent - // lhs/rhs over decls or excluding decls) + m_term2app.insert(t->get_id(), pure); + expr* rep = nullptr; + // ensure that the root has a representative + m_root2rep.find(t->get_root().get_id(), rep); - ptr_vector worklist; - for (term * t : m_tg.m_terms) { - worklist.push_back(t); - t->set_mark(true); - } - - while (!worklist.empty()) { - term* t = worklist.back(); - worklist.pop_back(); - t->set_mark(false); - if (m_term2app.contains(t->get_id())) - continue; - if (!t->is_theory() && is_projected(*t)) - continue; - - expr* pure = mk_pure(*t); - if (!pure) continue; - - m_term2app.insert(t->get_id(), pure); - expr* rep = nullptr; - // ensure that the root has a representative - m_root2rep.find(t->get_root().get_id(), rep); - - // update rep with pure if it is better - if (pure != rep && is_better_rep(pure, rep)) { - m_root2rep.insert(t->get_root().get_id(), pure); - for (term * p : term::parents(t->get_root())) { - m_term2app.remove(p->get_id()); - if (!p->is_marked()) { - p->set_mark(true); - worklist.push_back(p); - } + // update rep with pure if it is better + if (pure != rep && is_better_rep(pure, rep)) { + m_root2rep.insert(t->get_root().get_id(), pure); + for (term * p : term::parents(t->get_root())) { + m_term2app.remove(p->get_id()); + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); } } } - - // Here we could also walk equivalence classes that - // contain interpreted values by sort and extract - // disequalities bewteen non-unique value - // representatives. these disequalities are implied - // and can be mined using other means, such as theory - // aware core minimization - m_tg.reset_marks(); } - void solve_core() { - ptr_vector worklist; - for (term * t : m_tg.m_terms) { - // skip pure terms - if (m_term2app.contains(t->get_id())) continue; - worklist.push_back(t); - t->set_mark(true); - } + // Here we could also walk equivalence classes that + // contain interpreted values by sort and extract + // disequalities bewteen non-unique value + // representatives. these disequalities are implied + // and can be mined using other means, such as theory + // aware core minimization + m_tg.reset_marks(); + } - while (!worklist.empty()) { - term* t = worklist.back(); - worklist.pop_back(); - t->set_mark(false); - if (m_term2app.contains(t->get_id())) - continue; + void solve_core() { + ptr_vector worklist; + for (term * t : m_tg.m_terms) { + // skip pure terms + if (m_term2app.contains(t->get_id())) continue; + worklist.push_back(t); + t->set_mark(true); + } - expr* pure = mk_pure(*t); - if (!pure) continue; + while (!worklist.empty()) { + term* t = worklist.back(); + worklist.pop_back(); + t->set_mark(false); + if (m_term2app.contains(t->get_id())) + continue; - m_term2app.insert(t->get_id(), pure); - expr* rep = nullptr; - // ensure that the root has a representative - m_root2rep.find(t->get_root().get_id(), rep); + expr* pure = mk_pure(*t); + if (!pure) continue; - if (!rep) { - m_root2rep.insert(t->get_root().get_id(), pure); - for (term * p : term::parents(t->get_root())) { - SASSERT(!m_term2app.contains(p->get_id())); - if (!p->is_marked()) { - p->set_mark(true); - worklist.push_back(p); - } + m_term2app.insert(t->get_id(), pure); + expr* rep = nullptr; + // ensure that the root has a representative + m_root2rep.find(t->get_root().get_id(), rep); + + if (!rep) { + m_root2rep.insert(t->get_root().get_id(), pure); + for (term * p : term::parents(t->get_root())) { + SASSERT(!m_term2app.contains(p->get_id())); + if (!p->is_marked()) { + p->set_mark(true); + worklist.push_back(p); } } } - m_tg.reset_marks(); } + m_tg.reset_marks(); + } - bool find_app(term &t, expr *&res) { - return m_root2rep.find(t.get_root().get_id(), res); + bool find_app(term &t, expr *&res) { + return m_root2rep.find(t.get_root().get_id(), res); + } + + bool find_app(expr *lit, expr *&res) { + return m_root2rep.find(m_tg.get_term(lit)->get_root().get_id(), res); + } + + void mk_lits(expr_ref_vector &res) { + expr *e = nullptr; + for (auto *lit : m_tg.m_lits) { + if (!m.is_eq(lit) && find_app(lit, e)) + res.push_back(e); } + } - bool find_app(expr *lit, expr *&res) { - return m_root2rep.find(m_tg.get_term(lit)->get_root().get_id(), res); + void mk_pure_equalities(const term &t, expr_ref_vector &res) { + SASSERT(t.is_root()); + expr *rep = nullptr; + if (!m_root2rep.find(t.get_id(), rep)) return; + obj_hashtable members; + members.insert(rep); + term const * r = &t; + do { + expr* member = nullptr; + if (m_term2app.find(r->get_id(), member) && !members.contains(member)) { + res.push_back (m.mk_eq (rep, member)); + members.insert(member); + } + r = &r->get_next(); } + while (r != &t); + } - void mk_lits(expr_ref_vector &res) { - expr *e = nullptr; - for (auto *lit : m_tg.m_lits) { - if (!m.is_eq(lit) && find_app(lit, e)) - res.push_back(e); + bool is_projected(const term &t) {return m_tg.m_is_var(t);} + + void mk_unpure_equalities(const term &t, expr_ref_vector &res) { + expr *rep = nullptr; + if (!m_root2rep.find(t.get_id(), rep)) return; + obj_hashtable members; + members.insert(rep); + term const * r = &t; + do { + expr* member = mk_pure(*r); + SASSERT(member); + if (!members.contains(member) && + (!is_projected(*r) || !is_solved_eq(rep, member))) { + res.push_back(m.mk_eq(rep, member)); + members.insert(member); + } + r = &r->get_next(); + } + while (r != &t); + } + + void mk_equalities(bool pure, expr_ref_vector &res) { + for (term *t : m_tg.m_terms) { + if (!t->is_root()) continue; + if (!m_root2rep.contains(t->get_id())) continue; + if (pure) + mk_pure_equalities(*t, res); + else + mk_unpure_equalities(*t, res); + } + } + + void mk_pure_equalities(expr_ref_vector &res) { + return mk_equalities(true, res); + } + + void mk_unpure_equalities(expr_ref_vector &res) { + return mk_equalities(false, res); + } + + // TBD: generalize for also the case of a (:var n) + bool is_solved_eq(expr *lhs, expr* rhs) { + return is_uninterp_const(rhs) && !occurs(rhs, lhs); + } + + /// Add equalities and disequalities for all pure representatives + /// based on their equivalence in the model + void model_complete(expr_ref_vector &res) { + if (!m_model) return; + obj_map val2rep; + model_evaluator mev(*m_model); + for (auto &kv : m_root2rep) { + expr *rep = kv.m_value; + expr_ref val(m); + expr *u = nullptr; + if (!mev.eval(rep, val)) continue; + if (val2rep.find(val, u)) { + res.push_back(m.mk_eq(u, rep)); + } + else { + val2rep.insert(val, rep); } } - - void mk_pure_equalities(const term &t, expr_ref_vector &res) { - SASSERT(t.is_root()); - expr *rep = nullptr; - if (!m_root2rep.find(t.get_id(), rep)) return; - obj_hashtable members; - members.insert(rep); - term const * r = &t; - do { - expr* member = nullptr; - if (m_term2app.find(r->get_id(), member) && !members.contains(member)) { - res.push_back (m.mk_eq (rep, member)); - members.insert(member); - } - r = &r->get_next(); - } - while (r != &t); + // TBD: this ignores types, need one use of 'distinct' per sort. + // TBD: probably ignore distinct on values + // TBD: ignore distinct on Booleans + ptr_buffer reps; + for (auto &kv : val2rep) { + reps.push_back(kv.m_value); + std::cout << mk_pp(kv.m_value, m) << "\n"; } + // res.push_back(m.mk_distinct(reps.size(), reps.c_ptr())); + } - bool is_projected(const term &t) {return m_tg.m_is_var(t);} + public: + projector(term_graph &tg) : m_tg(tg), m(m_tg.m), m_pinned(m) {} - void mk_unpure_equalities(const term &t, expr_ref_vector &res) { - expr *rep = nullptr; - if (!m_root2rep.find(t.get_id(), rep)) return; - obj_hashtable members; - members.insert(rep); - term const * r = &t; - do { - expr* member = mk_pure(*r); - SASSERT(member); - if (!members.contains(member) && - (!is_projected(*r) || !is_solved_eq(rep, member))) { - res.push_back(m.mk_eq(rep, member)); - members.insert(member); - } - r = &r->get_next(); - } - while (r != &t); - } + void set_model(model &mdl) { m_model = &mdl; } - void mk_equalities(bool pure, expr_ref_vector &res) { - for (term *t : m_tg.m_terms) { - if (!t->is_root()) continue; - if (!m_root2rep.contains(t->get_id())) continue; - if (pure) - mk_pure_equalities(*t, res); - else - mk_unpure_equalities(*t, res); - } - } - - void mk_pure_equalities(expr_ref_vector &res) { - return mk_equalities(true, res); - } - - void mk_unpure_equalities(expr_ref_vector &res) { - return mk_equalities(false, res); - } - - // TBD: generalize for also the case of a (:var n) - bool is_solved_eq(expr *lhs, expr* rhs) { - return is_uninterp_const(rhs) && !occurs(rhs, lhs); - } - - /// Add equalities and disequalities for all pure representatives - /// based on their equivalence in the model - void model_complete(expr_ref_vector &res) { - if (!m_model) return; - obj_map val2rep; - model_evaluator mev(*m_model); - for (auto &kv : m_root2rep) { - expr *rep = kv.m_value; - expr_ref val(m); - expr *u = nullptr; - if (!mev.eval(rep, val)) continue; - if (val2rep.find(val, u)) { - res.push_back(m.mk_eq(u, rep)); - } - else { - val2rep.insert(val, rep); - } - } - // TBD: this ignores types, need one use of 'distinct' per sort. - // TBD: probably ignore distinct on values - // TBD: ignore distinct on Booleans - ptr_buffer reps; - for (auto &kv : val2rep) { - reps.push_back(kv.m_value); - std::cout << mk_pp(kv.m_value, m) << "\n"; - } - // res.push_back(m.mk_distinct(reps.size(), reps.c_ptr())); - } - - public: - projector(term_graph &tg) : m_tg(tg), m(m_tg.m), m_pinned(m) {} - - void set_model(model &mdl) { m_model = &mdl; } - - void reset() { - m_tg.reset_marks(); - m_term2app.reset(); - m_root2rep.reset(); - m_pinned.reset(); - m_model.reset(); - } - expr_ref_vector project() { - expr_ref_vector res(m); - purify(); - mk_lits(res); - mk_pure_equalities(res); - model_complete(res); - reset(); - return res; - } - expr_ref_vector solve() { - expr_ref_vector res(m); - purify(); - solve_core(); - mk_lits(res); - mk_unpure_equalities(res); - reset(); - return res; - } - }; - } + void reset() { + m_tg.reset_marks(); + m_term2app.reset(); + m_root2rep.reset(); + m_pinned.reset(); + m_model.reset(); + } + expr_ref_vector project() { + expr_ref_vector res(m); + purify(); + mk_lits(res); + mk_pure_equalities(res); + model_complete(res); + reset(); + return res; + } + expr_ref_vector solve() { + expr_ref_vector res(m); + purify(); + solve_core(); + mk_lits(res); + mk_unpure_equalities(res); + reset(); + return res; + } + }; void term_graph::set_vars(func_decl_ref_vector const& decls, bool exclude) { m_is_var.set_decls(decls, exclude); @@ -812,13 +810,13 @@ namespace qe { expr_ref_vector term_graph::project() { // reset solved vars so that they are not considered pure by projector m_is_var.reset_solved(); - projector p(*this); + term_graph::projector p(*this); return p.project(); } expr_ref_vector term_graph::project(model &mdl) { m_is_var.reset_solved(); - projector p(*this); + term_graph::projector p(*this); p.set_model(mdl); return p.project(); } @@ -826,7 +824,7 @@ namespace qe { expr_ref_vector term_graph::solve() { // reset solved vars so that they are not considered pure by projector m_is_var.reset_solved(); - projector p(*this); + term_graph::projector p(*this); return p.solve(); } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 97e14dc62..19b694a76 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -28,10 +28,9 @@ Notes: namespace qe { class term; - namespace {class projector;} class term_graph { - friend class projector; + class projector; class is_variable_proc : public ::is_variable_proc { bool m_exclude; From bc8ddedc54e8492d5caed5a3fe7c1224bf4fdbfd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Jun 2018 08:34:52 -0700 Subject: [PATCH 1222/1283] fix a few build regressions Signed-off-by: Nikolaj Bjorner --- src/api/api_solver.cpp | 2 -- src/ast/arith_decl_plugin.cpp | 1 + src/qe/qe_solve_plugin.cpp | 4 ++-- src/smt/smt_setup.cpp | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index ad5e7731d..951b9e51e 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -536,7 +536,6 @@ extern "C" { init_solver(c, s); expr_ref_vector _assumptions(m), _consequences(m), _variables(m); ast_ref_vector const& __assumptions = to_ast_vector_ref(assumptions); - unsigned sz = __assumptions.size(); for (ast* e : __assumptions) { if (!is_expr(e)) { _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); @@ -546,7 +545,6 @@ extern "C" { _assumptions.push_back(to_expr(e)); } ast_ref_vector const& __variables = to_ast_vector_ref(variables); - sz = __variables.size(); for (ast* a : __variables) { if (!is_expr(a)) { _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index fe5bc3af5..d2b17daa0 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -401,6 +401,7 @@ inline decl_kind arith_decl_plugin::fix_kind(decl_kind k, unsigned arity) { app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) { if (is_int && !val.is_int()) { + SASSERT(false); m_manager->raise_exception("invalid rational value passed as an integer"); } if (val.is_unsigned()) { diff --git a/src/qe/qe_solve_plugin.cpp b/src/qe/qe_solve_plugin.cpp index 0a499d3b8..1f314848f 100644 --- a/src/qe/qe_solve_plugin.cpp +++ b/src/qe/qe_solve_plugin.cpp @@ -80,8 +80,8 @@ namespace qe { bool sign = todo.back().first; todo.pop_back(); if (a.is_add(e)) { - for (expr* e : *to_app(e)) { - todo.push_back(std::make_pair(sign, e)); + for (expr* arg : *to_app(e)) { + todo.push_back(std::make_pair(sign, arg)); } } else if (a.is_sub(e)) { diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 97f5c433c..b90f08cd3 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -730,8 +730,8 @@ namespace smt { } void setup::setup_i_arith() { - m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params)); - // m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); + // m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params)); + m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); } void setup::setup_r_arith() { From 2a6b7e54825790012fbc316c2392f88c88536970 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Jun 2018 08:48:28 -0700 Subject: [PATCH 1223/1283] fixes Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index d2b17daa0..fe5bc3af5 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -401,7 +401,6 @@ inline decl_kind arith_decl_plugin::fix_kind(decl_kind k, unsigned arity) { app * arith_decl_plugin::mk_numeral(rational const & val, bool is_int) { if (is_int && !val.is_int()) { - SASSERT(false); m_manager->raise_exception("invalid rational value passed as an integer"); } if (val.is_unsigned()) { From 87715620d943186b1306d49ab30fbb7f7668257e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 14 Jun 2018 16:02:19 -0700 Subject: [PATCH 1224/1283] Fix mk_distict in term_graph --- src/qe/qe_term_graph.cpp | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index f12d51b9d..0f1f75b39 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -28,6 +28,13 @@ Notes: namespace qe { + namespace { + struct sort_lt_proc { + bool operator()(const expr* a, const expr *b) const { + return get_sort(a)->get_id() < get_sort(b)->get_id(); + } + }; + } namespace is_pure_ns { struct found{}; struct proc { @@ -760,15 +767,29 @@ namespace qe { val2rep.insert(val, rep); } } - // TBD: this ignores types, need one use of 'distinct' per sort. - // TBD: probably ignore distinct on values // TBD: ignore distinct on Booleans ptr_buffer reps; for (auto &kv : val2rep) { - reps.push_back(kv.m_value); - std::cout << mk_pp(kv.m_value, m) << "\n"; + expr *val = kv.m_value; + if (!m.is_unique_value(val)) + reps.push_back(kv.m_value); + } + + if (reps.size() <= 1) return; + + // -- sort representatives, call mk_distinct on any range + // -- of the same sort longer than 1 + std::sort(reps.c_ptr(), reps.c_ptr() + reps.size(), sort_lt_proc()); + unsigned i = 0; + unsigned sz = res.size(); + while (i < sz) { + sort* last_sort = get_sort(reps.get(i)); + unsigned j = i + 1; + while (j < sz && last_sort == get_sort(reps.get(j))) {++j;} + if (j - i > 1) + res.push_back(m.mk_distinct(j - i, reps.c_ptr() + i)); + i = j; } - // res.push_back(m.mk_distinct(reps.size(), reps.c_ptr())); } public: From 83cee9e81fe91f76c1569b764f5a205b2acf5e33 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 14 Jun 2018 16:02:57 -0700 Subject: [PATCH 1225/1283] Comments --- src/qe/qe_mbi.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 070c5279c..3af377371 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -259,7 +259,7 @@ namespace qe { app_ref_vector& m_vars; arith_util arith; obj_hashtable m_exclude; - is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): + is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): m(vars.m()), m_vars(vars), arith(m) { for (func_decl* f : shared) m_exclude.insert(f); } @@ -317,8 +317,8 @@ namespace qe { app_ref_vector euf_arith_mbi_plugin::get_arith_vars(expr_ref_vector const& lits) { arith_util a(m); app_ref_vector avars(m); - is_arith_var_proc _proc(avars, m_shared); - for_each_expr(_proc, lits); + is_arith_var_proc _proc(avars, m_shared); + for_each_expr(_proc, lits); return avars; } @@ -487,9 +487,9 @@ namespace qe { else if is_sat(local & lits) && !is_sat(local & lits & blocked) MISSING CASE MUST PRODUCE AN IMPLICANT OF LOCAL that is inconsistent with lits & blocked - in this case !is_sat(local & lits & mdl) so - return l_false, core of lits & mdl, nullptr - this will force a new mdl + in this case !is_sat(local & lits & mdl) and is_sat(mdl, blocked) + let mdl_blocked be lits of blocked that are true in mdl + return l_false, core of lits & mdl_blocked, nullptr mbi_plugin::block(phi): add phi to blocked @@ -502,9 +502,10 @@ namespace qe { while (true) { // when lits.empty(), this picks an A-implicant consistent with B // when !lits.empty(), checks whether mdl of shared vocab extends to A - switch (a.check_ag(lits, mdl, !lits.empty())) { + bool force_model = !lits.empty(); + switch (a.check_ag(lits, mdl, force_model)) { case l_true: - if (!lits.empty()) + if (force_model) // mdl is a model for a && b return l_true; switch (b.check_ag(lits, mdl, false)) { From a3de478c9300c7b57910c4c85348ebf567167f5e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 14 Jun 2018 16:13:53 -0700 Subject: [PATCH 1226/1283] typo --- src/qe/qe_term_graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 0f1f75b39..4a08eeb89 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -781,7 +781,7 @@ namespace qe { // -- of the same sort longer than 1 std::sort(reps.c_ptr(), reps.c_ptr() + reps.size(), sort_lt_proc()); unsigned i = 0; - unsigned sz = res.size(); + unsigned sz = reps.size(); while (i < sz) { sort* last_sort = get_sort(reps.get(i)); unsigned j = i + 1; From 05abf190098d8dea5f9bdc8957a049171bb99c0e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 14 Jun 2018 16:38:27 -0700 Subject: [PATCH 1227/1283] comment --- src/qe/qe_term_graph.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 4a08eeb89..6018d763a 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -767,11 +767,15 @@ namespace qe { val2rep.insert(val, rep); } } - // TBD: ignore distinct on Booleans + + // TBD: optimize further based on implied values (e.g., + // some literals are forced to be true/false) and based on + // unique_values (e.g., (x=1 & y=1) does not require + // (x!=y) to be added ptr_buffer reps; for (auto &kv : val2rep) { - expr *val = kv.m_value; - if (!m.is_unique_value(val)) + expr *rep = kv.m_value; + if (!m.is_unique_value(rep)) reps.push_back(kv.m_value); } From a0af3383db03d07a0ce337c5009c38616ebfba54 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Jun 2018 16:49:04 -0700 Subject: [PATCH 1228/1283] fixes to bdd Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 8 ++++---- src/sat/ba_solver.cpp | 2 +- src/sat/sat_bdd.cpp | 10 +++++----- src/sat/sat_bdd.h | 2 ++ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 3af377371..6b777aa02 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -259,7 +259,7 @@ namespace qe { app_ref_vector& m_vars; arith_util arith; obj_hashtable m_exclude; - is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): + is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): m(vars.m()), m_vars(vars), arith(m) { for (func_decl* f : shared) m_exclude.insert(f); } @@ -317,8 +317,8 @@ namespace qe { app_ref_vector euf_arith_mbi_plugin::get_arith_vars(expr_ref_vector const& lits) { arith_util a(m); app_ref_vector avars(m); - is_arith_var_proc _proc(avars, m_shared); - for_each_expr(_proc, lits); + is_arith_var_proc _proc(avars, m_shared); + for_each_expr(_proc, lits); return avars; } @@ -484,7 +484,7 @@ namespace qe { return l_true, mbp of local, mdl of local & blocked else if !is_sat(local & lits) then return l_false, mbp of local, nullptr - else if is_sat(local & lits) && !is_sat(local & lits & blocked) + else // is_sat(local & lits) && !is_sat(local & lits & blocked) MISSING CASE MUST PRODUCE AN IMPLICANT OF LOCAL that is inconsistent with lits & blocked in this case !is_sat(local & lits & mdl) and is_sat(mdl, blocked) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index d7cdea132..930617301 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -556,7 +556,7 @@ namespace sat { bool is_false = false; for (unsigned k = 0; k < sz; ++k) { SASSERT(!is_false || value(p[k].second) == l_false); - SASSERT(k < j == (value(p[k].second) != l_false)); + SASSERT((k < j) == (value(p[k].second) != l_false)); is_false = value(p[k].second) == l_false; }); diff --git a/src/sat/sat_bdd.cpp b/src/sat/sat_bdd.cpp index 74af4bf5e..bd1745765 100644 --- a/src/sat/sat_bdd.cpp +++ b/src/sat/sat_bdd.cpp @@ -108,7 +108,7 @@ namespace sat { bool bdd_manager::check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c) { if (e1 != e2) { - SASSERT(e2->m_result != -1); + SASSERT(e2->m_result != null_bdd); push_entry(e1); e1 = nullptr; return true; @@ -117,7 +117,7 @@ namespace sat { e1->m_bdd1 = a; e1->m_bdd2 = b; e1->m_op = c; - SASSERT(e1->m_result == -1); + SASSERT(e1->m_result == null_bdd); return false; } } @@ -203,7 +203,7 @@ namespace sat { void * mem = m_alloc.allocate(sizeof(op_entry)); result = new (mem) op_entry(l, r, op); } - result->m_result = -1; + result->m_result = null_bdd; return result; } @@ -667,7 +667,7 @@ namespace sat { r = e2->m_result; } else { - SASSERT(e1->m_result == -1); + SASSERT(e1->m_result == null_bdd); push(mk_quant_rec(l, lo(b), op)); push(mk_quant_rec(l, hi(b), op)); r = make_node(lvl, read(2), read(1)); @@ -782,7 +782,7 @@ namespace sat { ptr_vector to_delete, to_keep; for (auto* e : m_op_cache) { - if (e->m_result != -1) { + if (e->m_result != null_bdd) { to_delete.push_back(e); } else { diff --git a/src/sat/sat_bdd.h b/src/sat/sat_bdd.h index 41d1115b9..70f6960fe 100644 --- a/src/sat/sat_bdd.h +++ b/src/sat/sat_bdd.h @@ -32,6 +32,8 @@ namespace sat { typedef unsigned BDD; + const BDD null_bdd = UINT_MAX; + enum bdd_op { bdd_and_op = 2, bdd_or_op = 3, From baa96909cca4fd81e48e1d51d6b35103e60ae77c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Jun 2018 17:13:10 -0700 Subject: [PATCH 1229/1283] mb-skolem for arithmetic with model repair The contract is that users of mb-skolem ensure that interface equalities are preserved (by adding a sufficient set of disequalities, such as a chain x1 < x2 < x3 .., to force that solutions for x_i does not clash). Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 12 +++++++----- src/model/model_core.cpp | 8 ++++---- src/qe/qe_arith.cpp | 20 +++++++++++++++++++- src/qe/qe_mbi.cpp | 4 ++-- src/qe/qe_term_graph.cpp | 3 ++- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 4efab1935..09f6d5c2d 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -51,7 +51,8 @@ namespace opt { m_div = -v.m_coeff; } } - m_coeff = r.m_coeff - r.m_value; + m_coeff = r.m_coeff; + if (r.m_type == opt::t_lt) m_coeff += m_div; normalize(); SASSERT(m_div.is_pos()); } @@ -983,7 +984,7 @@ namespace opt { } else { result = def(); - result.m_coeff = eval(x); + m_var2value[x] = rational::zero(); } SASSERT(eval(result) == eval(x)); } @@ -1008,8 +1009,8 @@ namespace opt { else { result = def(m_rows[glb_index], x); } + m_var2value[x] = eval(result); #endif - SASSERT(eval(result) == eval(x)); } // The number of matching lower and upper bounds is small. @@ -1106,7 +1107,8 @@ namespace opt { } def result = project(y, compute_def); if (compute_def) { - result = (result * D) + u; + result = (result * D) + u; + m_var2value[x] = eval(result); } SASSERT(!compute_def || eval(result) == eval(x)); return result; @@ -1204,7 +1206,7 @@ namespace opt { def result; if (compute_def) { result = def(m_rows[row_id1], x); - SASSERT(eval(result) == eval(x)); + m_var2value[x] = eval(result); } retire_row(row_id1); return result; diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 648768bf3..d41854c22 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -47,8 +47,8 @@ bool model_core::eval(func_decl* f, expr_ref & r) const { void model_core::register_decl(func_decl * d, expr * v) { SASSERT(d->get_arity() == 0); - decl2expr::obj_map_entry * entry = m_interp.insert_if_not_there2(d, 0); - if (entry->get_data().m_value == 0) { + decl2expr::obj_map_entry * entry = m_interp.insert_if_not_there2(d, nullptr); + if (entry->get_data().m_value == nullptr) { // new entry m_decls.push_back(d); m_const_decls.push_back(d); @@ -67,8 +67,8 @@ void model_core::register_decl(func_decl * d, expr * v) { void model_core::register_decl(func_decl * d, func_interp * fi) { SASSERT(d->get_arity() > 0); SASSERT(&fi->m() == &m_manager); - decl2finterp::obj_map_entry * entry = m_finterp.insert_if_not_there2(d, 0); - if (entry->get_data().m_value == 0) { + decl2finterp::obj_map_entry * entry = m_finterp.insert_if_not_there2(d, nullptr); + if (entry->get_data().m_value == nullptr) { // new entry m_decls.push_back(d); m_func_decls.push_back(d); diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 7e619ccd5..ff4c7dc52 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -360,7 +360,7 @@ namespace qe { ptr_vector index2expr; for (auto& kv : tids) { - index2expr.setx(kv.m_value, kv.m_key, 0); + index2expr.setx(kv.m_value, kv.m_key, nullptr); } j = 0; @@ -454,6 +454,8 @@ namespace qe { else if (!d.m_div.is_one() && !is_int) { t = a.mk_div(t, a.mk_numeral(d.m_div, is_int)); } + update_model(model, to_app(x), eval(t)); + SASSERT(eval(t) == eval(x)); result.push_back(def(expr_ref(x, m), t)); } @@ -461,6 +463,22 @@ namespace qe { return result; } + void update_model(model& mdl, app* x, expr_ref const& val) { + if (is_uninterp_const(x)) { + mdl.register_decl(x->get_decl(), val); + } + else { + func_interp* fi = mdl.get_func_interp(x->get_decl()); + if (!fi) return; + model_evaluator eval(mdl); + expr_ref_vector args(m); + for (expr* arg : *x) { + args.push_back(eval(arg)); + } + fi->insert_entry(args.c_ptr(), val); + } + } + expr_ref mk_add(expr_ref_vector const& ts) { switch (ts.size()) { case 0: diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 6b777aa02..60fb0f6f0 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -259,7 +259,7 @@ namespace qe { app_ref_vector& m_vars; arith_util arith; obj_hashtable m_exclude; - is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): + is_arith_var_proc(app_ref_vector& vars, func_decl_ref_vector const& shared): m(vars.m()), m_vars(vars), arith(m) { for (func_decl* f : shared) m_exclude.insert(f); } @@ -484,7 +484,7 @@ namespace qe { return l_true, mbp of local, mdl of local & blocked else if !is_sat(local & lits) then return l_false, mbp of local, nullptr - else // is_sat(local & lits) && !is_sat(local & lits & blocked) + else if is_sat(local & lits) && !is_sat(local & lits & blocked) MISSING CASE MUST PRODUCE AN IMPLICANT OF LOCAL that is inconsistent with lits & blocked in this case !is_sat(local & lits & mdl) and is_sat(mdl, blocked) diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 6018d763a..95518d7fc 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -35,6 +35,7 @@ namespace qe { } }; } + namespace is_pure_ns { struct found{}; struct proc { @@ -776,7 +777,7 @@ namespace qe { for (auto &kv : val2rep) { expr *rep = kv.m_value; if (!m.is_unique_value(rep)) - reps.push_back(kv.m_value); + reps.push_back(kv.m_value); } if (reps.size() <= 1) return; From f936c92efc111639de507def47b5612b7843e98e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 14 Jun 2018 22:27:57 -0700 Subject: [PATCH 1230/1283] Improve distinct constraint generation still many more optimizations possible --- src/qe/qe_mbi.cpp | 12 ++++++------ src/qe/qe_term_graph.cpp | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 60fb0f6f0..86fc1ac3c 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -315,10 +315,10 @@ namespace qe { } app_ref_vector euf_arith_mbi_plugin::get_arith_vars(expr_ref_vector const& lits) { - arith_util a(m); - app_ref_vector avars(m); - is_arith_var_proc _proc(avars, m_shared); - for_each_expr(_proc, lits); + arith_util a(m); + app_ref_vector avars(m); + is_arith_var_proc _proc(avars, m_shared); + for_each_expr(_proc, lits); return avars; } @@ -358,8 +358,8 @@ namespace qe { tg.set_vars(m_shared, false); tg.add_lits(lits); lits.reset(); - //lits.append(tg.project(*mdl)); - lits.append(tg.project()); + lits.append(tg.project(*mdl)); + //lits.append(tg.project()); TRACE("qe", tout << "project: " << lits << "\n";); return mbi_sat; } diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 95518d7fc..510868366 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -28,6 +28,16 @@ Notes: namespace qe { + static expr_ref mk_neq(ast_manager &m, expr *e1, expr *e2) { + expr *t = nullptr; + // x != !x == true + if ((m.is_not(e1, t) && t == e2) || (m.is_not(e2, t) && t == e1)) + return expr_ref(m.mk_true(), m); + else if (m.are_distinct(e1, e2)) + return expr_ref(m.mk_true(), m); + return expr_ref(m.mk_not(m.mk_eq(e1, e2)), m); + } + namespace { struct sort_lt_proc { bool operator()(const expr* a, const expr *b) const { @@ -791,10 +801,16 @@ namespace qe { sort* last_sort = get_sort(reps.get(i)); unsigned j = i + 1; while (j < sz && last_sort == get_sort(reps.get(j))) {++j;} - if (j - i > 1) + if (j - i == 2) { + expr_ref d(m); + d = mk_neq(m, reps.get(i), reps.get(i+1)); + if (!m.is_true(d)) res.push_back(d); + } + else if (j - i > 2) res.push_back(m.mk_distinct(j - i, reps.c_ptr() + i)); i = j; } + TRACE("qe", tout << "after distinct: " << res << "\n";); } public: From a51d6cbcbc8d72db4b6ea5199a92d36e1fe18816 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jun 2018 14:58:02 -0700 Subject: [PATCH 1231/1283] debug model evaluator Signed-off-by: Nikolaj Bjorner --- src/model/model_evaluator.cpp | 9 +++++++-- src/muz/rel/dl_sparse_table.h | 32 ++++++++++++++++---------------- src/smt/smt_model_checker.cpp | 2 +- src/util/util.h | 4 +++- 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 0b25a250b..fcff20afc 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -290,6 +290,7 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status mk_array_eq(expr* a, expr* b, expr_ref& result) { + TRACE("model_evaluator", tout << "mk_array_eq " << m_array_equalities << "\n";); if (a == b) { result = m.mk_true(); return BR_DONE; @@ -315,6 +316,7 @@ struct evaluator_cfg : public default_rewriter_cfg { conj.push_back(m.mk_eq(else1, else2)); } if (args_are_unique1 && args_are_unique2 && !stores1.empty()) { + TRACE("model_evalator", tout << "argss are unique";); return mk_array_eq_core(stores1, else1, stores2, else2, conj, result); } @@ -329,7 +331,10 @@ struct evaluator_cfg : public default_rewriter_cfg { expr_ref s2(m_ar.mk_select(args2.size(), args2.c_ptr()), m); conj.push_back(m.mk_eq(s1, s2)); } - result = m.mk_and(conj.size(), conj.c_ptr()); + result = mk_and(conj); + TRACE("model_evaluator", tout << mk_pp(a, m) << " == " << mk_pp(b, m) << " -> " << conj << "\n"; + for (auto& s : stores1) tout << "store: " << s << "\n"; + ); return BR_REWRITE_FULL; } return BR_FAILED; @@ -454,7 +459,7 @@ struct evaluator_cfg : public default_rewriter_cfg { func_decl* f = m_ar.get_as_array_func_decl(to_app(a)); func_interp* g = m_model.get_func_interp(f); - if (!g) return false; + if (!g) return false; unsigned sz = g->num_entries(); unsigned arity = f->get_arity(); unsigned base_sz = stores.size(); diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index fbbbd12f8..43a967729 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -326,29 +326,29 @@ namespace datalog { public: unsigned m_offset; //!< in bits unsigned m_length; //!< in bits - - column_info(unsigned offset, unsigned length) \ - : m_big_offset(offset/8), - m_small_offset(offset%8), - m_mask( length==64 ? ULLONG_MAX : (static_cast(1)<(1)<(rec+m_big_offset); + const uint64_t * ptr = reinterpret_cast(rec + m_big_offset); uint64_t res = *ptr; - res>>=m_small_offset; - res&=m_mask; + res >>= m_small_offset; + res &= m_mask; return res; } void set(char * rec, table_element val) const { SASSERT( (val&~m_mask)==0 ); //the value fits into the column - uint64_t * ptr = reinterpret_cast(rec+m_big_offset); - *ptr&=m_write_mask; - *ptr|=val<(rec + m_big_offset); + *ptr &= m_write_mask; + *ptr |= val << m_small_offset; } unsigned next_ofs() const { return m_offset+m_length; } }; diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 765cc87f5..5ab52b57c 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -438,7 +438,7 @@ namespace smt { } else if (!check(q)) { if (m_params.m_mbqi_trace || get_verbosity_level() >= 5) { - verbose_stream() << "(smt.mbqi :failed " << q->get_qid() << ")\n"; + IF_VERBOSE(0, verbose_stream() << "(smt.mbqi :failed " << q->get_qid() << ")\n"); } TRACE("model_checker", tout << "checking quantifier " << mk_pp(q, m) << " failed\n";); num_failures++; diff --git a/src/util/util.h b/src/util/util.h index 6e7ee5ce5..77204977e 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -193,8 +193,10 @@ bool is_threaded(); #ifdef _MSC_VER #define DO_PRAGMA(x) __pragma(x) +#define PRAGMA_LOCK __pragma(omp critical (verbose_lock)) #else #define DO_PRAGMA(x) _Pragma(#x) +#define PRAGMA_LOCK _Pragma("omp critical (verbose_lock){) #endif #ifdef _NO_OMP_ @@ -202,7 +204,7 @@ bool is_threaded(); #else #define LOCK_CODE(CODE) \ { \ - DO_PRAGMA(omp critical (verbose_lock)) \ + PRAGMA_LOCK \ { \ CODE; \ } \ From 1debbc29c4695d5046cad7828fdc5b17a681a9e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jun 2018 14:59:33 -0700 Subject: [PATCH 1232/1283] release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 7439342de..e55b329db 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -26,12 +26,16 @@ Version 4.8.0 (known as ACCE, ABCE, CCE). Asymmetric branching also uses features introduced in Lingeling by exploiting binary implication graphs. Use sat.acce=true to enable the full repertoire of inprocessing methods. By default, clauses that are "eliminated" by acce are tagged as lemmas (redundant) and are garbage collected if their glue level is high. + - Substantial overhaul of the spacer horn clause engine. - Removed features: - interpolation API - duality engine for constrained Horn clauses. + - pdr engine for constrained Horn clauses. The engine's functionality has been + folded into spacer as one of optional strategies. - long deprecated API functions have been removed from z3_api.h + Version 4.7.1 ============= From 6e27ad42c8a1ba7ce91fa4f918bd59db037821ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jun 2018 15:02:50 -0700 Subject: [PATCH 1233/1283] remove pdr reference from legacy build script Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index f2720c893..22b640305 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -59,13 +59,12 @@ def init_project_def(): add_lib('dataflow', ['muz'], 'muz/dataflow') add_lib('transforms', ['muz', 'hilbert', 'dataflow'], 'muz/transforms') add_lib('rel', ['muz', 'transforms'], 'muz/rel') - add_lib('pdr', ['muz', 'transforms', 'arith_tactics', 'core_tactics', 'smt_tactic'], 'muz/pdr') 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('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'ddnf', 'spacer'], 'muz/fp') + 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') From 3ad14465971a27c28d6c291262952f466532828e Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Fri, 15 Jun 2018 15:09:25 -0700 Subject: [PATCH 1234/1283] Remove spurious quote --- src/util/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/util.h b/src/util/util.h index 77204977e..994faf6a3 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -196,7 +196,7 @@ bool is_threaded(); #define PRAGMA_LOCK __pragma(omp critical (verbose_lock)) #else #define DO_PRAGMA(x) _Pragma(#x) -#define PRAGMA_LOCK _Pragma("omp critical (verbose_lock){) +#define PRAGMA_LOCK _Pragma(omp critical (verbose_lock){) #endif #ifdef _NO_OMP_ From b6c43f6143f07de5eae4a76fc62fe26d8d1b41b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jun 2018 15:13:55 -0700 Subject: [PATCH 1235/1283] move files for build script Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/ast/CMakeLists.txt | 1 - src/ast/rewriter/CMakeLists.txt | 1 + src/ast/{ => rewriter}/factor_equivs.cpp | 3 ++- src/ast/{ => rewriter}/factor_equivs.h | 0 src/muz/spacer/spacer_generalizers.cpp | 2 +- src/muz/spacer/spacer_legacy_frames.cpp | 2 +- src/muz/spacer/spacer_quant_generalizer.cpp | 2 +- src/muz/spacer/spacer_util.cpp | 2 +- 9 files changed, 8 insertions(+), 7 deletions(-) rename src/ast/{ => rewriter}/factor_equivs.cpp (98%) rename src/ast/{ => rewriter}/factor_equivs.h (100%) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 22b640305..dada93069 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -41,7 +41,6 @@ def init_project_def(): add_lib('aig_tactic', ['tactic'], 'tactic/aig') add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') add_lib('cmd_context', ['solver', 'rewriter']) - add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds') add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') @@ -74,6 +73,7 @@ def init_project_def(): 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'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) + add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'qe', 'arith_tactics'], 'cmd_context/extra_cmds') add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3') add_exe('test', ['api', 'fuzzing', 'simplex'], exe_name='test-z3', install=False) _libz3Component = add_dll('api_dll', ['api', 'sat', 'extra_cmds'], 'api/dll', diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 4dcdd2a35..80543bb05 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -24,7 +24,6 @@ z3_add_component(ast expr_map.cpp expr_stat.cpp expr_substitution.cpp - factor_equivs.cpp for_each_ast.cpp for_each_expr.cpp format.cpp diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index f030e2704..9d80fd5ac 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -16,6 +16,7 @@ z3_add_component(rewriter enum2bv_rewriter.cpp expr_replacer.cpp expr_safe_replace.cpp + factor_equivs.cpp factor_rewriter.cpp fpa_rewriter.cpp inj_axiom.cpp diff --git a/src/ast/factor_equivs.cpp b/src/ast/rewriter/factor_equivs.cpp similarity index 98% rename from src/ast/factor_equivs.cpp rename to src/ast/rewriter/factor_equivs.cpp index be402e628..6384ad8ce 100644 --- a/src/ast/factor_equivs.cpp +++ b/src/ast/rewriter/factor_equivs.cpp @@ -25,11 +25,12 @@ Revision History: */ -#include "ast/factor_equivs.h" #include "ast/arith_decl_plugin.h" #include "ast/for_each_expr.h" #include "ast/ast_pp.h" #include "ast/rewriter/expr_safe_replace.h" +#include "ast/rewriter/factor_equivs.h" + /** Factors input vector v into equivalence classes and the rest */ diff --git a/src/ast/factor_equivs.h b/src/ast/rewriter/factor_equivs.h similarity index 100% rename from src/ast/factor_equivs.h rename to src/ast/rewriter/factor_equivs.h diff --git a/src/muz/spacer/spacer_generalizers.cpp b/src/muz/spacer/spacer_generalizers.cpp index 4e5b60698..b0fb6c2d3 100644 --- a/src/muz/spacer/spacer_generalizers.cpp +++ b/src/muz/spacer/spacer_generalizers.cpp @@ -25,7 +25,7 @@ Revision History: #include "ast/expr_abstract.h" #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" -#include "ast/factor_equivs.h" +#include "ast/rewriter/factor_equivs.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/substitution/matcher.h" #include "ast/expr_functors.h" diff --git a/src/muz/spacer/spacer_legacy_frames.cpp b/src/muz/spacer/spacer_legacy_frames.cpp index 49157a085..a21df5038 100644 --- a/src/muz/spacer/spacer_legacy_frames.cpp +++ b/src/muz/spacer/spacer_legacy_frames.cpp @@ -34,7 +34,7 @@ #include "util/luby.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/expr_abstract.h" -#include "ast/factor_equivs.h" +#include "ast/rewriter/factor_equivs.h" namespace spacer { diff --git a/src/muz/spacer/spacer_quant_generalizer.cpp b/src/muz/spacer/spacer_quant_generalizer.cpp index fb2964c40..f66fe7b29 100644 --- a/src/muz/spacer/spacer_quant_generalizer.cpp +++ b/src/muz/spacer/spacer_quant_generalizer.cpp @@ -26,7 +26,7 @@ Revision History: #include "ast/expr_abstract.h" #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" -#include "ast/factor_equivs.h" +#include "ast/rewriter/factor_equivs.h" #include "ast/rewriter/expr_safe_replace.h" #include "ast/substitution/matcher.h" #include "ast/expr_functors.h" diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 29d72fabd..f53577b5b 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -64,7 +64,7 @@ Notes: #include "tactic/arith/propagate_ineqs_tactic.h" #include "tactic/arith/arith_bounds_tactic.h" -#include "ast/factor_equivs.h" +#include "ast/rewriter/factor_equivs.h" #include "qe/qe_term_graph.h" namespace spacer { From caca07c85f5ca8174102bc2e842efbb7bd213877 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jun 2018 15:28:18 -0700 Subject: [PATCH 1236/1283] fix path to moved header file Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_array_eq_rewrite.cpp | 2 +- src/muz/transforms/dl_mk_array_instantiation.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/transforms/dl_mk_array_eq_rewrite.cpp b/src/muz/transforms/dl_mk_array_eq_rewrite.cpp index 61eafae64..c8a3d4357 100644 --- a/src/muz/transforms/dl_mk_array_eq_rewrite.cpp +++ b/src/muz/transforms/dl_mk_array_eq_rewrite.cpp @@ -22,7 +22,7 @@ Revision History: #include "muz/base/dl_context.h" #include "muz/base/fp_params.hpp" #include "muz/transforms/dl_mk_array_eq_rewrite.h" -#include "ast/factor_equivs.h" +#include "ast/rewriter/factor_equivs.h" namespace datalog { diff --git a/src/muz/transforms/dl_mk_array_instantiation.h b/src/muz/transforms/dl_mk_array_instantiation.h index b2e80ab84..51a818a3f 100644 --- a/src/muz/transforms/dl_mk_array_instantiation.h +++ b/src/muz/transforms/dl_mk_array_instantiation.h @@ -70,7 +70,7 @@ Revision History: #define DL_MK_ARRAY_INSTANTIATION_H_ -#include "ast/factor_equivs.h" +#include "ast/rewriter/factor_equivs.h" #include "muz/base/dl_rule_transformer.h" namespace datalog { From c0e378b0453e42331ca92c842288fdd4e7d0b8d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jun 2018 15:44:33 -0700 Subject: [PATCH 1237/1283] remove { Signed-off-by: Nikolaj Bjorner --- src/util/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/util.h b/src/util/util.h index 994faf6a3..4b18ec5e6 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -196,7 +196,7 @@ bool is_threaded(); #define PRAGMA_LOCK __pragma(omp critical (verbose_lock)) #else #define DO_PRAGMA(x) _Pragma(#x) -#define PRAGMA_LOCK _Pragma(omp critical (verbose_lock){) +#define PRAGMA_LOCK _Pragma(omp critical (verbose_lock)) #endif #ifdef _NO_OMP_ From 9149048f348b57c0f13c6019b6477786fc3e0589 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jun 2018 15:53:47 -0700 Subject: [PATCH 1238/1283] use quotes Signed-off-by: Nikolaj Bjorner --- src/util/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/util.h b/src/util/util.h index 4b18ec5e6..12fd2fe3b 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -196,7 +196,7 @@ bool is_threaded(); #define PRAGMA_LOCK __pragma(omp critical (verbose_lock)) #else #define DO_PRAGMA(x) _Pragma(#x) -#define PRAGMA_LOCK _Pragma(omp critical (verbose_lock)) +#define PRAGMA_LOCK _Pragma("omp critical (verbose_lock)") #endif #ifdef _NO_OMP_ From 450da5ea0c93719c63ef3629149d10e5e2f58dac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Jun 2018 17:40:54 -0700 Subject: [PATCH 1239/1283] moving model_evaluator to model Signed-off-by: Nikolaj Bjorner --- src/model/model.cpp | 79 ++++++++++++++++++++-------------- src/model/model.h | 36 ++++++++++++++++ src/model/model_core.h | 1 + src/model/model_evaluator.cpp | 6 ++- src/model/model_evaluator.h | 1 + src/tactic/arith/fm_tactic.cpp | 15 +++---- 6 files changed, 96 insertions(+), 42 deletions(-) diff --git a/src/model/model.cpp b/src/model/model.cpp index e6c7b74a0..9ac971afe 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -26,16 +26,15 @@ Revision History: #include "model/model_evaluator.h" model::model(ast_manager & m): - model_core(m) { + model_core(m), + m_mev(*this) { } model::~model() { - sort2universe::iterator it3 = m_usort2universe.begin(); - sort2universe::iterator end3 = m_usort2universe.end(); - for (; it3 != end3; ++it3) { - m_manager.dec_ref(it3->m_key); - m_manager.dec_array_ref(it3->m_value->size(), it3->m_value->c_ptr()); - dealloc(it3->m_value); + for (auto & kv : m_usort2universe) { + m_manager.dec_ref(kv.m_key); + m_manager.dec_array_ref(kv.m_value->size(), kv.m_value->c_ptr()); + dealloc(kv.m_value); } } @@ -48,19 +47,13 @@ void model::copy_const_interps(model const & source) { } void model::copy_func_interps(model const & source) { - decl2finterp::iterator it2 = source.m_finterp.begin(); - decl2finterp::iterator end2 = source.m_finterp.end(); - for (; it2 != end2; ++it2) { - register_decl(it2->m_key, it2->m_value->copy()); - } + for (auto const& kv : source.m_finterp) + register_decl(kv.m_key, kv.m_value->copy()); } void model::copy_usort_interps(model const & source) { - sort2universe::iterator it3 = source.m_usort2universe.begin(); - sort2universe::iterator end3 = source.m_usort2universe.end(); - for (; it3 != end3; ++it3) { - register_usort(it3->m_key, it3->m_value->size(), it3->m_value->c_ptr()); - } + for (auto const& kv : source.m_usort2universe) + register_usort(kv.m_key, kv.m_value->size(), kv.m_value->c_ptr()); } model * model::copy() const { @@ -151,28 +144,21 @@ model * model::translate(ast_translation & translator) const { model * res = alloc(model, translator.to()); // Translate const interps - decl2expr::iterator it1 = m_interp.begin(); - decl2expr::iterator end1 = m_interp.end(); - for (; it1 != end1; ++it1) { - res->register_decl(translator(it1->m_key), translator(it1->m_value)); - } + for (auto const& kv : m_interp) + res->register_decl(translator(kv.m_key), translator(kv.m_value)); // Translate func interps - decl2finterp::iterator it2 = m_finterp.begin(); - decl2finterp::iterator end2 = m_finterp.end(); - for (; it2 != end2; ++it2) { - func_interp * fi = it2->m_value; - res->register_decl(translator(it2->m_key), fi->translate(translator)); + for (auto const& kv : m_finterp) { + func_interp * fi = kv.m_value; + res->register_decl(translator(kv.m_key), fi->translate(translator)); } // Translate usort interps - sort2universe::iterator it3 = m_usort2universe.begin(); - sort2universe::iterator end3 = m_usort2universe.end(); - for (; it3 != end3; ++it3) { + for (auto const& kv : m_usort2universe) { ptr_vector new_universe; - for (unsigned i=0; im_value->size(); i++) - new_universe.push_back(translator(it3->m_value->get(i))); - res->register_usort(translator(it3->m_key), + for (unsigned i=0; i < kv.m_value->size(); i++) + new_universe.push_back(translator(kv.m_value->get(i))); + res->register_usort(translator(kv.m_key), new_universe.size(), new_universe.c_ptr()); } @@ -180,3 +166,30 @@ model * model::translate(ast_translation & translator) const { return res; } +expr_ref model::operator()(expr* t) { + return m_mev(t); +} + +expr_ref_vector model::operator()(expr_ref_vector const& ts) { + expr_ref_vector rs(m()); + for (expr* t : ts) rs.push_back((*this)(t)); + return rs; +} + +bool model::is_true(expr* t) { + return m().is_true((*this)(t)); +} + +bool model::is_false(expr* t) { + return m().is_false((*this)(t)); +} + +bool model::is_true(expr_ref_vector const& ts) { + for (expr* t : ts) if (!is_true(t)) return false; + return true; +} + +void model::reset_eval_cache() { + m_mev.reset(); +} + diff --git a/src/model/model.h b/src/model/model.h index 758d3d451..3fda2832f 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -20,6 +20,7 @@ Revision History: #define MODEL_H_ #include "model/model_core.h" +#include "model/model_evaluator.h" #include "util/ref.h" #include "ast/ast_translation.h" @@ -29,6 +30,7 @@ protected: ptr_vector m_usorts; sort2universe m_usort2universe; + model_evaluator m_mev; struct value_proc; public: @@ -58,6 +60,40 @@ public: // Model translation // model * translate(ast_translation & translator) const; + + void set_model_completion(bool f) { m_mev.set_model_completion(f); } + void updt_params(params_ref const & p) { m_mev.updt_params(p); } + + /** + * evaluation using the model evaluator. Caches results. + */ + expr_ref operator()(expr* t); + expr_ref_vector operator()(expr_ref_vector const& ts); + bool is_true(expr* t); + bool is_false(expr* t); + bool is_true(expr_ref_vector const& ts); + void reset_eval_cache(); + + class scoped_model_completion { + bool m_old_completion; + model& m_model; + public: + scoped_model_completion(model& m, bool c): + m_old_completion(m.m_mev.get_model_completion()), m_model(m) { + m.set_model_completion(c); + } +#if 0 + scoped_model_completion(model_ref& m, bool c): + m_old_completion(m->m_mev.get_model_completion()), m_model(*m.get()) { + m->set_model_completion(c); + } +#endif + ~scoped_model_completion() { + m_model.set_model_completion(m_old_completion); + } + }; + + }; typedef ref model_ref; diff --git a/src/model/model_core.h b/src/model/model_core.h index ce211c0b8..400b2fcab 100644 --- a/src/model/model_core.h +++ b/src/model/model_core.h @@ -40,6 +40,7 @@ public: virtual ~model_core(); ast_manager & get_manager() const { return m_manager; } + ast_manager& m() { return m_manager; } unsigned get_num_decls() const { return m_decls.size(); } func_decl * get_decl(unsigned i) const { return m_decls[i]; } diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 250b28ff2..f7c7fa74d 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -85,8 +85,8 @@ struct evaluator_cfg : public default_rewriter_cfg { model_evaluator_params p(_p); m_max_memory = megabytes_to_bytes(p.max_memory()); m_max_steps = p.max_steps(); - m_model_completion = p.completion(); m_cache = p.cache(); + m_model_completion = p.completion(); m_array_equalities = p.array_equalities(); m_array_as_stores = p.array_as_stores(); } @@ -544,6 +544,10 @@ void model_evaluator::set_model_completion(bool f) { m_imp->cfg().m_model_completion = f; } +bool model_evaluator::get_model_completion() const { + return m_imp->cfg().m_model_completion; +} + void model_evaluator::set_expand_array_equalities(bool f) { m_imp->cfg().m_array_equalities = f; } diff --git a/src/model/model_evaluator.h b/src/model/model_evaluator.h index d9bf3c375..8666e3519 100644 --- a/src/model/model_evaluator.h +++ b/src/model/model_evaluator.h @@ -37,6 +37,7 @@ public: ast_manager & m () const; void set_model_completion(bool f); + bool get_model_completion() const; void set_expand_array_equalities(bool f); void updt_params(params_ref const & p); diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 679adb2dd..fc41f54a4 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -62,7 +62,7 @@ class fm_tactic : public tactic { return m.is_false(val); } - r_kind process(func_decl * x, expr * cls, arith_util & u, model_evaluator & ev, rational & r) { + r_kind process(func_decl * x, expr * cls, arith_util & u, model& ev, rational & r) { unsigned num_lits; expr * const * lits; if (m.is_or(cls)) { @@ -80,9 +80,7 @@ class fm_tactic : public tactic { expr * l = lits[i]; expr * atom; if (is_uninterp_const(l) || (m.is_not(l, atom) && is_uninterp_const(atom))) { - expr_ref val(m); - ev(l, val); - if (m.is_true(val)) + if (ev.is_true(l)) return NONE; // clause was satisfied } else { @@ -131,7 +129,7 @@ class fm_tactic : public tactic { } else { expr_ref val(m); - ev(monomial, val); + val = ev(monomial); SASSERT(u.is_numeral(val)); rational tmp; u.is_numeral(val, tmp); @@ -184,8 +182,9 @@ class fm_tactic : public tactic { void operator()(model_ref & md) override { TRACE("fm_mc", model_v2_pp(tout, *md); display(tout);); - model_evaluator ev(*(md.get())); - ev.set_model_completion(true); + model::scoped_model_completion _sc(*md, true); + //model_evaluator ev(*(md.get())); + //ev.set_model_completion(true); arith_util u(m); unsigned i = m_xs.size(); while (i > 0) { @@ -201,7 +200,7 @@ class fm_tactic : public tactic { clauses::iterator end = m_clauses[i].end(); for (; it != end; ++it) { if (m.canceled()) throw tactic_exception(m.limit().get_cancel_msg()); - switch (process(x, *it, u, ev, val)) { + switch (process(x, *it, u, *md, val)) { case NONE: TRACE("fm_mc", tout << "no bound for:\n" << mk_ismt2_pp(*it, m) << "\n";); break; From c64321c2e466e58d8df49b2ed1fa6a8416ef2bc0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 16 Jun 2018 11:22:58 -0700 Subject: [PATCH 1240/1283] debugging maxres bug report Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index d49044d8d..e3777ee9b 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -781,9 +781,8 @@ public: bool is_true(expr_ref_vector const& es) { unsigned i = 0; for (; i < es.size() && is_true(es[i]); ++i) { } - CTRACE("opt", i < es.size(), tout << mk_pp(es[i], m) << "\n"; - model_smt2_pp(tout, m, *m_model, 0); - ); + CTRACE("opt_bug", i < es.size(), tout << mk_pp(es[i], m) << "\n"; + model_smt2_pp(tout, m, *m_model, 0);); return i == es.size(); } From 60888a93eb24d4f5ce0b3defaaeccfba2c977af7 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 16 Jun 2018 13:42:26 -0700 Subject: [PATCH 1241/1283] Minor fixes to model --- src/model/model.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/model/model.h b/src/model/model.h index 3fda2832f..429e7b51a 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -24,10 +24,13 @@ Revision History: #include "util/ref.h" #include "ast/ast_translation.h" +class model; +typedef ref model_ref; + class model : public model_core { protected: typedef obj_map*> sort2universe; - + ptr_vector m_usorts; sort2universe m_usort2universe; model_evaluator m_mev; @@ -42,10 +45,10 @@ public: void copy_usort_interps(model const & source); model * copy() const; - + bool eval(func_decl * f, expr_ref & r) const { return model_core::eval(f, r); } bool eval(expr * e, expr_ref & result, bool model_completion = false); - + expr * get_some_value(sort * s) override; ptr_vector const & get_universe(sort * s) const override; unsigned get_num_uninterpreted_sorts() const override; @@ -78,25 +81,21 @@ public: bool m_old_completion; model& m_model; public: - scoped_model_completion(model& m, bool c): + scoped_model_completion(model& m, bool c): m_old_completion(m.m_mev.get_model_completion()), m_model(m) { m.set_model_completion(c); } -#if 0 - scoped_model_completion(model_ref& m, bool c): + scoped_model_completion(model_ref& m, bool c): m_old_completion(m->m_mev.get_model_completion()), m_model(*m.get()) { m->set_model_completion(c); } -#endif ~scoped_model_completion() { m_model.set_model_completion(m_old_completion); } }; - + }; -typedef ref model_ref; #endif /* MODEL_H_ */ - From fffc8489bff01631591aea95be1e5b18e4c938dd Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 16 Jun 2018 13:43:30 -0700 Subject: [PATCH 1242/1283] Switched compute_implicant_literals to use new model API --- src/api/api_qe.cpp | 7 +- src/muz/spacer/spacer_context.cpp | 8 +- src/muz/spacer/spacer_util.cpp | 309 +++++++++++++++--------------- src/muz/spacer/spacer_util.h | 46 ++--- 4 files changed, 188 insertions(+), 182 deletions(-) diff --git a/src/api/api_qe.cpp b/src/api/api_qe.cpp index 2516aacfb..0073ef274 100644 --- a/src/api/api_qe.cpp +++ b/src/api/api_qe.cpp @@ -52,7 +52,7 @@ extern "C" Z3_TRY; LOG_Z3_qe_model_project (c, m, num_bounds, bound, body); RESET_ERROR_CODE(); - + app_ref_vector vars(mk_c(c)->m ()); if (!to_apps(num_bounds, bound, vars)) { SET_ERROR_CODE (Z3_INVALID_ARG); @@ -119,11 +119,8 @@ extern "C" facts.push_back (to_expr (fml)); flatten_and (facts); - spacer::model_evaluator_util mev (mk_c(c)->m()); - mev.set_model (*model); - expr_ref_vector lits (mk_c(c)->m()); - spacer::compute_implicant_literals (mev, facts, lits); + spacer::compute_implicant_literals (*model, facts, lits); expr_ref result (mk_c(c)->m ()); result = mk_and (lits); diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 03093ab63..db1153de3 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -366,7 +366,7 @@ pob *derivation::create_next_child () // get an implicant of the summary expr_ref_vector u(m), lits (m); u.push_back (rf->get ()); - compute_implicant_literals (mev, u, lits); + compute_implicant_literals (*model, u, lits); expr_ref v(m); v = mk_and (lits); @@ -1172,7 +1172,7 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, // -- pick an implicant expr_ref_vector lits(m); - compute_implicant_literals (mev, summary, lits); + compute_implicant_literals (*mev.get_model(), summary, lits); return mk_and(lits); } @@ -3599,7 +3599,7 @@ reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, if (ctx.reach_dnf()) { expr_ref_vector u(m), lits(m); u.push_back (res); - compute_implicant_literals (mev, u, lits); + compute_implicant_literals (*mev.get_model(), u, lits); res = mk_and (lits); } @@ -3670,7 +3670,7 @@ bool context::create_children(pob& n, datalog::rule const& r, forms.push_back(pt.get_transition(r)); forms.push_back(n.post()); - compute_implicant_literals (mev, forms, lits); + compute_implicant_literals (*mev.get_model(), forms, lits); expr_ref phi = mk_and (lits); // primed variables of the head diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index f53577b5b..3eb18b0e5 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -405,67 +405,67 @@ namespace spacer { namespace { class implicant_picker { - model_evaluator_util &m_mev; + model &m_model; ast_manager &m; arith_util m_arith; expr_ref_vector m_todo; expr_mark m_visited; + // add literal to the implicant + // applies lightweight normalization + void add_literal(expr *e, expr_ref_vector &out) { + SASSERT(m.is_bool(e)); - void add_literal (expr *e, expr_ref_vector &out) { - SASSERT (m.is_bool (e)); + expr_ref res(m), v(m); + v = m_model(e); + // the literal must have a value + SASSERT(m.is_true(v) || m.is_false(v)); - expr_ref res (m), v(m); - m_mev.eval (e, v, false); - SASSERT (m.is_true (v) || m.is_false (v)); + res = m.is_false(v) ? m.mk_not(e) : e; - res = m.is_false (v) ? m.mk_not (e) : e; - - if (m.is_distinct (res)) { - // -- (distinct a b) == (not (= a b)) + if (m.is_distinct(res)) { + // --(distinct a b) == (not (= a b)) if (to_app(res)->get_num_args() == 2) { - res = m.mk_eq (to_app(res)->get_arg(0), to_app(res)->get_arg(1)); - res = m.mk_not (res); + res = m.mk_eq(to_app(res)->get_arg(0), + to_app(res)->get_arg(1)); + res = m.mk_not(res); } } expr *nres, *f1, *f2; if (m.is_not(res, nres)) { - // -- (not (xor a b)) == (= a b) + // --(not (xor a b)) == (= a b) if (m.is_xor(nres, f1, f2)) - { res = m.mk_eq(f1, f2); } - + res = m.mk_eq(f1, f2); // -- split arithmetic inequality - else if (m.is_eq (nres, f1, f2) && m_arith.is_int_real (f1)) { + else if (m.is_eq(nres, f1, f2) && m_arith.is_int_real(f1)) { expr_ref u(m); u = m_arith.mk_lt(f1, f2); - if (m_mev.eval (u, v, false) && m.is_true (v)) - { res = u; } - else - { res = m_arith.mk_lt(f2, f1); } + res = m_model.is_true(u) ? u : m_arith.mk_lt(f2, f1); } } - if (!m_mev.is_true (res)) { - verbose_stream() << "Bad literal: " << mk_pp(res, m) << "\n"; + if (!m_model.is_true(res)) { + verbose_stream() << "Bad literal: " << res << "\n"; } - SASSERT (m_mev.is_true (res)); - out.push_back (res); + SASSERT(m_model.is_true(res)); + out.push_back(res); } void process_app(app *a, expr_ref_vector &out) { - if (m_visited.is_marked(a)) { return; } - SASSERT (m.is_bool (a)); + if (m_visited.is_marked(a)) return; + SASSERT(m.is_bool(a)); expr_ref v(m); - m_mev.eval (a, v, false); + v = m_model(a); bool is_true = m.is_true(v); if (!is_true && !m.is_false(v)) return; expr *na, *f1, *f2, *f3; - if (m.is_true(a) || m.is_false(a)) { + SASSERT(!m.is_false(a)); + if (m.is_true(a)) { // noop } else if (a->get_family_id() != m.get_basic_family_id()) { @@ -479,14 +479,15 @@ namespace { } else if (m.is_distinct(a)) { if (!is_true) { - f1 = qe::project_plugin::pick_equality(m, *m_mev.get_model(), a); + f1 = qe::project_plugin::pick_equality(m, m_model, a); m_todo.push_back(f1); } else if (a->get_num_args() == 2) { add_literal(a, out); } else { - m_todo.push_back(m.mk_distinct_expanded(a->get_num_args(), a->get_args())); + m_todo.push_back(m.mk_distinct_expanded(a->get_num_args(), + a->get_args())); } } else if (m.is_and(a)) { @@ -494,8 +495,8 @@ namespace { m_todo.append(a->get_num_args(), a->get_args()); } else { - for (expr* e : *a) { - if (m_mev.is_false(e)) { + for(expr* e : *a) { + if (m_model.is_false(e)) { m_todo.push_back(e); break; } @@ -506,17 +507,19 @@ namespace { if (!is_true) m_todo.append(a->get_num_args(), a->get_args()); else { - for (expr * e : *a) { - if (m_mev.is_true(e)) { + for(expr * e : *a) { + if (m_model.is_true(e)) { m_todo.push_back(e); break; } } } } - else if (m.is_eq(a, f1, f2) || (is_true && m.is_not(a, na) && m.is_xor (na, f1, f2))) { + else if (m.is_eq(a, f1, f2) || + (is_true && m.is_not(a, na) && m.is_xor(na, f1, f2))) { if (!m.are_equal(f1, f2) && !m.are_distinct(f1, f2)) { - if (m.is_bool(f1) && (!is_uninterp_const(f1) || !is_uninterp_const(f2))) + if (m.is_bool(f1) && + (!is_uninterp_const(f1) || !is_uninterp_const(f2))) m_todo.append(a->get_num_args(), a->get_args()); else add_literal(a, out); @@ -526,19 +529,19 @@ namespace { if (m.are_equal(f2, f3)) { m_todo.push_back(f2); } - else if (m_mev.is_true (f2) && m_mev.is_true (f3)) { + else if (m_model.is_true(f2) && m_model.is_true(f3)) { m_todo.push_back(f2); m_todo.push_back(f3); } - else if (m_mev.is_false(f2) && m_mev.is_false(f3)) { + else if (m_model.is_false(f2) && m_model.is_false(f3)) { m_todo.push_back(f2); m_todo.push_back(f3); } - else if (m_mev.is_true(f1)) { + else if (m_model.is_true(f1)) { m_todo.push_back(f1); m_todo.push_back(f2); } - else if (m_mev.is_false(f1)) { + else if (m_model.is_false(f1)) { m_todo.push_back(f1); m_todo.push_back(f3); } @@ -548,16 +551,18 @@ namespace { } else if (m.is_implies(a, f1, f2)) { if (is_true) { - if (m_mev.is_true(f2)) + if (m_model.is_true(f2)) m_todo.push_back(f2); - else if (m_mev.is_false(f1)) + else if (m_model.is_false(f1)) m_todo.push_back(f1); } else m_todo.append(a->get_num_args(), a->get_args()); } else { - IF_VERBOSE(0, verbose_stream () << "Unexpected expression: " << mk_pp(a, m) << "\n"); + IF_VERBOSE(0, + verbose_stream() << "Unexpected expression: " + << mk_pp(a, m) << "\n"); UNREACHABLE(); } } @@ -574,70 +579,72 @@ namespace { m_todo.pop_back(); process_app(a, out); m_visited.mark(a, true); - } while (!m_todo.empty()); + } while(!m_todo.empty()); } bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) { m_visited.reset(); - bool is_true = m_mev.is_true (in); + bool is_true = m_model.is_true(in); - for (expr* e : in) { - if (is_true || m_mev.is_true(e)) { + for(expr* e : in) { + if (is_true || m_model.is_true(e)) { pick_literals(e, out); } } - m_visited.reset (); + m_visited.reset(); return is_true; } public: - implicant_picker (model_evaluator_util &mev) : - m_mev (mev), m (m_mev.get_ast_manager ()), m_arith(m), m_todo(m) {} + implicant_picker(model &mdl) : + m_model(mdl), m(m_model.get_manager()), m_arith(m), m_todo(m) {} - void operator() (expr_ref_vector &in, expr_ref_vector& out) { - pick_implicant (in, out); + void operator()(expr_ref_vector &in, expr_ref_vector& out) { + model::scoped_model_completion _sc_(m_model, false); + pick_implicant(in, out); } }; } - void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, + void compute_implicant_literals(model &mdl, + expr_ref_vector &formula, expr_ref_vector &res) { // flatten the formula and remove all trivial literals - // TBD: not clear why there is a dependence on it (other than + // TBD: not clear why there is a dependence on it(other than // not handling of Boolean constants by implicant_picker), however, // it was a source of a problem on a benchmark flatten_and(formula); if (formula.empty()) {return;} - implicant_picker ipick (mev); - ipick (formula, res); + implicant_picker ipick(mdl); + ipick(formula, res); } void simplify_bounds_old(expr_ref_vector& cube) { ast_manager& m = cube.m(); scoped_no_proof _no_pf_(m); goal_ref g(alloc(goal, m, false, false, false)); - for (expr* c : cube) + for(expr* c : cube) g->assert_expr(c); goal_ref_buffer result; tactic_ref simplifier = mk_arith_bounds_tactic(m); - (*simplifier)(g, result); + (*simplifier)(g, result); SASSERT(result.size() == 1); goal* r = result[0]; cube.reset(); - for (unsigned i = 0; i < r->size(); ++i) { + for(unsigned i = 0; i < r->size(); ++i) { cube.push_back(r->form(i)); } } - void simplify_bounds_new (expr_ref_vector &cube) { + void simplify_bounds_new(expr_ref_vector &cube) { ast_manager &m = cube.m(); scoped_no_proof _no_pf_(m); goal_ref g(alloc(goal, m, false, false, false)); - for (expr* c : cube) + for(expr* c : cube) g->assert_expr(c); goal_ref_buffer goals; @@ -645,12 +652,12 @@ namespace { tactic_ref prop_bounds = mk_propagate_ineqs_tactic(m); tactic_ref t = and_then(prop_values.get(), prop_bounds.get()); - (*t)(g, goals); + (*t)(g, goals); SASSERT(goals.size() == 1); g = goals[0]; cube.reset(); - for (unsigned i = 0; i < g->size(); ++i) { + for(unsigned i = 0; i < g->size(); ++i) { cube.push_back(g->form(i)); } } @@ -664,86 +671,86 @@ namespace { ast_manager &m; arith_util m_util; - adhoc_rewriter_cfg (ast_manager &manager) : m(manager), m_util(m) {} + adhoc_rewriter_cfg(ast_manager &manager) : m(manager), m_util(m) {} bool is_le(func_decl const * n) const { return m_util.is_le(n); } bool is_ge(func_decl const * n) const { return m_util.is_ge(n); } - br_status reduce_app (func_decl * f, unsigned num, expr * const * args, + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { expr * e; if (is_le(f)) - return mk_le_core (args[0], args[1], result); + return mk_le_core(args[0], args[1], result); if (is_ge(f)) - return mk_ge_core (args[0], args[1], result); - if (m.is_not(f) && m.is_not (args[0], e)) { + return mk_ge_core(args[0], args[1], result); + if (m.is_not(f) && m.is_not(args[0], e)) { result = e; return BR_DONE; } return BR_FAILED; } - br_status mk_le_core (expr *arg1, expr * arg2, expr_ref & result) { - // t <= -1 ==> t < 0 ==> ! (t >= 0) - if (m_util.is_int (arg1) && m_util.is_minus_one (arg2)) { - result = m.mk_not (m_util.mk_ge (arg1, mk_zero ())); + br_status mk_le_core(expr *arg1, expr * arg2, expr_ref & result) { + // t <= -1 ==> t < 0 ==> !(t >= 0) + if (m_util.is_int(arg1) && m_util.is_minus_one(arg2)) { + result = m.mk_not(m_util.mk_ge(arg1, mk_zero())); return BR_DONE; } return BR_FAILED; } - br_status mk_ge_core (expr * arg1, expr * arg2, expr_ref & result) { - // t >= 1 ==> t > 0 ==> ! (t <= 0) - if (m_util.is_int (arg1) && is_one (arg2)) { + br_status mk_ge_core(expr * arg1, expr * arg2, expr_ref & result) { + // t >= 1 ==> t > 0 ==> !(t <= 0) + if (m_util.is_int(arg1) && is_one(arg2)) { - result = m.mk_not (m_util.mk_le (arg1, mk_zero ())); + result = m.mk_not(m_util.mk_le(arg1, mk_zero())); return BR_DONE; } return BR_FAILED; } - expr * mk_zero () {return m_util.mk_numeral (rational (0), true);} - bool is_one (expr const * n) const { - rational val; return m_util.is_numeral (n, val) && val.is_one (); + expr * mk_zero() {return m_util.mk_numeral(rational(0), true);} + bool is_one(expr const * n) const { + rational val; return m_util.is_numeral(n, val) && val.is_one(); } }; - void normalize (expr *e, expr_ref &out, + void normalize(expr *e, expr_ref &out, bool use_simplify_bounds, bool use_factor_eqs) { params_ref params; // arith_rewriter - params.set_bool ("sort_sums", true); - params.set_bool ("gcd_rounding", true); - params.set_bool ("arith_lhs", true); + params.set_bool("sort_sums", true); + params.set_bool("gcd_rounding", true); + params.set_bool("arith_lhs", true); // poly_rewriter - params.set_bool ("som", true); - params.set_bool ("flat", true); + params.set_bool("som", true); + params.set_bool("flat", true); // apply rewriter th_rewriter rw(out.m(), params); - rw (e, out); + rw(e, out); - adhoc_rewriter_cfg adhoc_cfg(out.m ()); - rewriter_tpl adhoc_rw (out.m (), false, adhoc_cfg); - adhoc_rw (out.get (), out); + adhoc_rewriter_cfg adhoc_cfg(out.m()); + rewriter_tpl adhoc_rw(out.m(), false, adhoc_cfg); + adhoc_rw(out.get(), out); if (out.m().is_and(out)) { expr_ref_vector v(out.m()); - flatten_and (out, v); + flatten_and(out, v); if (v.size() > 1) { // sort arguments of the top-level and - std::stable_sort (v.c_ptr(), v.c_ptr() + v.size(), ast_lt_proc()); + std::stable_sort(v.c_ptr(), v.c_ptr() + v.size(), ast_lt_proc()); if (use_simplify_bounds) { // remove redundant inequalities - simplify_bounds (v); + simplify_bounds(v); } if (use_factor_eqs) { // -- refactor equivalence classes and choose a representative qe::term_graph egraph(out.m()); - egraph.add_lits (v); + egraph.add_lits(v); v.reset(); egraph.to_lits(v); } @@ -755,10 +762,10 @@ namespace { << mk_and(v) << "\n";); TRACE("spacer_normalize", qe::term_graph egraph(out.m()); - for (expr* e : v) egraph.add_lit (to_app(e)); + for(expr* e : v) egraph.add_lit(to_app(e)); tout << "Reduced app:\n" << mk_pp(egraph.to_app(), out.m()) << "\n";); - out = mk_and (v); + out = mk_and(v); } } } @@ -768,34 +775,34 @@ namespace { ast_manager &m; arith_util m_arith; - adhoc_rewriter_rpp (ast_manager &manager) : m(manager), m_arith(m) {} + adhoc_rewriter_rpp(ast_manager &manager) : m(manager), m_arith(m) {} bool is_le(func_decl const * n) const { return m_arith.is_le(n); } bool is_ge(func_decl const * n) const { return m_arith.is_ge(n); } bool is_lt(func_decl const * n) const { return m_arith.is_lt(n); } bool is_gt(func_decl const * n) const { return m_arith.is_gt(n); } - bool is_zero (expr const * n) const {rational val; return m_arith.is_numeral(n, val) && val.is_zero();} + bool is_zero(expr const * n) const {rational val; return m_arith.is_numeral(n, val) && val.is_zero();} - br_status reduce_app (func_decl * f, unsigned num, expr * const * args, + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { br_status st = BR_FAILED; expr *e1, *e2, *e3, *e4; - // rewrites (= (+ A (* -1 B)) 0) into (= A B) - if (m.is_eq (f) && is_zero (args [1]) && - m_arith.is_add (args[0], e1, e2) && - m_arith.is_mul (e2, e3, e4) && m_arith.is_minus_one (e3)) { - result = m.mk_eq (e1, e4); + // rewrites(=(+ A(* -1 B)) 0) into(= A B) + if (m.is_eq(f) && is_zero(args [1]) && + m_arith.is_add(args[0], e1, e2) && + m_arith.is_mul(e2, e3, e4) && m_arith.is_minus_one(e3)) { + result = m.mk_eq(e1, e4); return BR_DONE; } // simplify normalized leq, where right side is different from 0 - // rewrites (<= (+ A (* -1 B)) C) into (<= A B+C) + // rewrites(<=(+ A(* -1 B)) C) into(<= A B+C) else if ((is_le(f) || is_lt(f) || is_ge(f) || is_gt(f)) && - m_arith.is_add (args[0], e1, e2) && - m_arith.is_mul (e2, e3, e4) && m_arith.is_minus_one (e3)) { + m_arith.is_add(args[0], e1, e2) && + m_arith.is_mul(e2, e3, e4) && m_arith.is_minus_one(e3)) { expr_ref rhs(m); - rhs = is_zero (args[1]) ? e4 : m_arith.mk_add(e4, args[1]); + rhs = is_zero(args[1]) ? e4 : m_arith.mk_add(e4, args[1]); if (is_le(f)) { result = m_arith.mk_le(e1, rhs); @@ -813,7 +820,7 @@ namespace { { UNREACHABLE(); } } // simplify negation of ordering predicate - else if (m.is_not (f)) { + else if (m.is_not(f)) { if (m_arith.is_lt(args[0], e1, e2)) { result = m_arith.mk_ge(e1, e2); st = BR_DONE; @@ -834,11 +841,11 @@ namespace { mk_epp::mk_epp(ast *t, ast_manager &m, unsigned indent, unsigned num_vars, char const * var_prefix) : - mk_pp (t, m, m_epp_params, indent, num_vars, var_prefix), m_epp_expr(m) { + mk_pp(t, m, m_epp_params, indent, num_vars, var_prefix), m_epp_expr(m) { m_epp_params.set_uint("min_alias_size", UINT_MAX); m_epp_params.set_uint("max_depth", UINT_MAX); - if (is_expr (m_ast)) { + if (is_expr(m_ast)) { rw(to_expr(m_ast), m_epp_expr); m_ast = m_epp_expr; } @@ -858,11 +865,11 @@ namespace { if (vars.size() < fv.size()) { vars.resize(fv.size()); } - for (unsigned i = 0, sz = fv.size(); i < sz; ++i) { + for(unsigned i = 0, sz = fv.size(); i < sz; ++i) { sort *s = fv[i] ? fv[i] : m.mk_bool_sort(); vars[i] = mk_zk_const(m, i, s); var_subst vs(m, false); - vs(e, vars.size(), (expr * *) vars.c_ptr(), out); + vs(e, vars.size(),(expr * *) vars.c_ptr(), out); } } @@ -872,75 +879,75 @@ namespace { app_ref m_var; expr_ref_vector &m_res; - index_term_finder (ast_manager &mgr, app* v, expr_ref_vector &res) : m(mgr), m_array (m), m_var (v, m), m_res (res) {} - void operator() (var *n) {} - void operator() (quantifier *n) {} - void operator() (app *n) { - if (m_array.is_select (n) || m.is_eq(n)) { + index_term_finder(ast_manager &mgr, app* v, expr_ref_vector &res) : m(mgr), m_array(m), m_var(v, m), m_res(res) {} + void operator()(var *n) {} + void operator()(quantifier *n) {} + void operator()(app *n) { + if (m_array.is_select(n) || m.is_eq(n)) { unsigned i = 0; - for (expr * arg : *n) { - if ((m.is_eq(n) || i > 0) && m_var != arg) m_res.push_back (arg); + for(expr * arg : *n) { + if ((m.is_eq(n) || i > 0) && m_var != arg) m_res.push_back(arg); ++i; } } } }; - bool mbqi_project_var (model_evaluator_util &mev, app* var, expr_ref &fml) { - ast_manager &m = fml.get_manager (); + bool mbqi_project_var(model_evaluator_util &mev, app* var, expr_ref &fml) { + ast_manager &m = fml.get_manager(); expr_ref val(m); - mev.eval (var, val, false); + mev.eval(var, val, false); - TRACE ("mbqi_project_verbose", - tout << "MBQI: var: " << mk_pp (var, m) << "\n" + TRACE("mbqi_project_verbose", + tout << "MBQI: var: " << mk_pp(var, m) << "\n" << "fml: " << fml << "\n";); - expr_ref_vector terms (m); - index_term_finder finder (m, var, terms); - for_each_expr (finder, fml); + expr_ref_vector terms(m); + index_term_finder finder(m, var, terms); + for_each_expr(finder, fml); - TRACE ("mbqi_project_verbose", + TRACE("mbqi_project_verbose", tout << "terms:\n" << terms << "\n";); - for (expr * term : terms) { - expr_ref tval (m); - mev.eval (term, tval, false); + for(expr * term : terms) { + expr_ref tval(m); + mev.eval(term, tval, false); - TRACE ("mbqi_project_verbose", - tout << "term: " << mk_pp (term, m) + TRACE("mbqi_project_verbose", + tout << "term: " << mk_pp(term, m) << " tval: " << tval - << " val: " << mk_pp (val, m) << "\n";); + << " val: " << mk_pp(val, m) << "\n";); // -- if the term does not contain an occurrence of var // -- and is in the same equivalence class in the model - if (tval == val && !occurs (var, term)) { - TRACE ("mbqi_project", - tout << "MBQI: replacing " << mk_pp (var, m) << " with " << mk_pp (term, m) << "\n";); + if (tval == val && !occurs(var, term)) { + TRACE("mbqi_project", + tout << "MBQI: replacing " << mk_pp(var, m) << " with " << mk_pp(term, m) << "\n";); expr_safe_replace sub(m); - sub.insert (var, term); - sub (fml); + sub.insert(var, term); + sub(fml); return true; } } - TRACE ("mbqi_project", - tout << "MBQI: failed to eliminate " << mk_pp (var, m) << " from " << fml << "\n";); + TRACE("mbqi_project", + tout << "MBQI: failed to eliminate " << mk_pp(var, m) << " from " << fml << "\n";); return false; } - void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml) { - ast_manager &m = fml.get_manager (); + void mbqi_project(model &M, app_ref_vector &vars, expr_ref &fml) { + ast_manager &m = fml.get_manager(); model_evaluator_util mev(m); - mev.set_model (M); + mev.set_model(M); expr_ref tmp(m); // -- evaluate to initialize mev cache - mev.eval (fml, tmp, false); - tmp.reset (); + mev.eval(fml, tmp, false); + tmp.reset(); unsigned j = 0; - for (app* v : vars) - if (!mbqi_project_var (mev, v, fml)) + for(app* v : vars) + if (!mbqi_project_var(mev, v, fml)) vars[j++] = v; vars.shrink(j); } @@ -959,7 +966,7 @@ namespace { for_each_expr(cs, fml); return false; } - catch (found) { + catch(found) { return true; } } @@ -970,8 +977,8 @@ namespace { collect_indices(app_ref_vector& indices): m_indices(indices), a(indices.get_manager()) {} void operator()(expr* n) {} void operator()(app* n) { - if (a.is_select (n)) - for (unsigned i = 1; i < n->get_num_args(); ++i) + if (a.is_select(n)) + for(unsigned i = 1; i < n->get_num_args(); ++i) if (is_app(n->get_arg(i))) m_indices.push_back(to_app(n->get_arg(i))); } diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index f43195a97..a66d2dd5a 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -48,17 +48,17 @@ namespace spacer { return UINT_MAX; } - inline bool is_infty_level(unsigned lvl) { - return lvl == infty_level (); + inline bool is_infty_level(unsigned lvl) { + return lvl == infty_level (); } - inline unsigned next_level(unsigned lvl) { - return is_infty_level(lvl)?lvl:(lvl+1); + inline unsigned next_level(unsigned lvl) { + return is_infty_level(lvl)?lvl:(lvl+1); } inline unsigned prev_level (unsigned lvl) { - if (is_infty_level(lvl)) return infty_level(); - if (lvl == 0) return 0; + if (is_infty_level(lvl)) return infty_level(); + if (lvl == 0) return 0; return lvl - 1; } @@ -78,28 +78,28 @@ namespace spacer { typedef ptr_vector app_vector; typedef ptr_vector decl_vector; typedef obj_hashtable func_decl_set; - + // TBD: deprecate class model_evaluator_util { ast_manager& m; model_ref m_model; model_evaluator* m_mev; - + /// initialize with a given model. All previous state is lost. model can be NULL void reset (model *model); public: model_evaluator_util(ast_manager& m); ~model_evaluator_util(); - + void set_model(model &model) {reset (&model);} model_ref &get_model() {return m_model;} ast_manager& get_ast_manager() const {return m;} - + public: bool is_true (const expr_ref_vector &v); bool is_false(expr* x); bool is_true(expr* x); - + bool eval (const expr_ref_vector &v, expr_ref &result, bool model_completion); /// evaluates an expression bool eval (expr *e, expr_ref &result, bool model_completion); @@ -109,10 +109,10 @@ namespace spacer { /** \brief hoist non-boolean if expressions. */ - + void to_mbp_benchmark(std::ostream &out, const expr* fml, const app_ref_vector &vars); - + // TBD: deprecate by qe::mbp /** * do the following in sequence @@ -126,27 +126,29 @@ namespace spacer { bool dont_sub=false); void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& M, expr_map& map); - + // TBD: sort out void expand_literals(ast_manager &m, expr_ref_vector& conjs); - void compute_implicant_literals (model_evaluator_util &mev, expr_ref_vector &formula, expr_ref_vector &res); + void compute_implicant_literals(model &mdl, + expr_ref_vector &formula, + expr_ref_vector &res); void simplify_bounds (expr_ref_vector &lemmas); void normalize(expr *e, expr_ref &out, bool use_simplify_bounds = true, bool factor_eqs = false); - - /** + + /** * Ground expression by replacing all free variables by skolem * constants. On return, out is the resulting expression, and vars is * a map from variable ids to corresponding skolem constants. */ void ground_expr (expr *e, expr_ref &out, app_ref_vector &vars); - + void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml); - + bool contains_selects (expr* fml, ast_manager& m); void get_select_indices (expr* fml, app_ref_vector& indices, ast_manager& m); - + void find_decls (expr* fml, app_ref_vector& decls, std::string& prefix); - + /** * extended pretty-printer * used for debugging @@ -156,7 +158,7 @@ namespace spacer { params_ref m_epp_params; expr_ref m_epp_expr; mk_epp(ast *t, ast_manager &m, unsigned indent = 0, unsigned num_vars = 0, char const * var_prefix = nullptr); - void rw(expr *e, expr_ref &out); + void rw(expr *e, expr_ref &out); }; } From 5e65b37f25d4a536adc99ec25a561d9100d1c68b Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 16 Jun 2018 13:58:58 -0700 Subject: [PATCH 1243/1283] Switch spacer::qe_project to new model API --- src/api/api_qe.cpp | 2 +- src/muz/spacer/spacer_context.cpp | 12 ++-- src/muz/spacer/spacer_context.h | 2 +- src/muz/spacer/spacer_util.cpp | 95 +++++++++++++------------------ src/muz/spacer/spacer_util.h | 10 +++- 5 files changed, 54 insertions(+), 67 deletions(-) diff --git a/src/api/api_qe.cpp b/src/api/api_qe.cpp index 0073ef274..92517b02b 100644 --- a/src/api/api_qe.cpp +++ b/src/api/api_qe.cpp @@ -62,7 +62,7 @@ extern "C" expr_ref result (mk_c(c)->m ()); result = to_expr (body); model_ref model (to_model_ref (m)); - spacer::qe_project (mk_c(c)->m (), vars, result, model); + spacer::qe_project (mk_c(c)->m (), vars, result, *model); mk_c(c)->save_ast_trail (result.get ()); return of_expr (result.get ()); diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index db1153de3..8853a2e45 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -265,7 +265,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) verbose_stream ()); vars.append(m_evars); m_evars.reset(); - pt().mbp(vars, m_trans, mev.get_model(), + pt().mbp(vars, m_trans, *mev.get_model(), true, pt().get_context().use_ground_pob()); m_evars.append (vars); vars.reset(); @@ -294,7 +294,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) verbose_stream ()); // include m_evars in case they can eliminated now as well vars.append(m_evars); - pt().mbp(vars, post, mev.get_model(), + pt().mbp(vars, post, *mev.get_model(), true, pt().get_context().use_ground_pob()); //qe::reduce_array_selects (*mev.get_model (), post); } @@ -398,7 +398,7 @@ pob *derivation::create_next_child () if (!vars.empty ()) { vars.append(m_evars); m_evars.reset(); - this->pt().mbp(vars, m_trans, mev.get_model(), + this->pt().mbp(vars, m_trans, *mev.get_model(), true, this->pt().get_context().use_ground_pob()); // keep track of implicitly quantified variables m_evars.append (vars); @@ -1267,7 +1267,7 @@ bool pred_transformer::is_qblocked (pob &n) { } -void pred_transformer::mbp(app_ref_vector &vars, expr_ref &fml, const model_ref &mdl, +void pred_transformer::mbp(app_ref_vector &vars, expr_ref &fml, model &mdl, bool reduce_all_selects, bool force) { scoped_watch _t_(m_mbp_watch); qe_project(m, vars, fml, mdl, reduce_all_selects, use_native_mbp(), !force); @@ -3617,7 +3617,7 @@ reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, timeit _timer1 (is_trace_enabled("spacer_timeit"), "mk_rf::qe_project", verbose_stream ()); - mbp(vars, res, mev.get_model(), false, true /* force or skolemize */); + mbp(vars, res, *mev.get_model(), false, true /* force or skolemize */); } @@ -3685,7 +3685,7 @@ bool context::create_children(pob& n, datalog::rule const& r, // skolems of the pob n.get_skolems(vars); - n.pt().mbp(vars, phi, mev.get_model (), true, use_ground_pob()); + n.pt().mbp(vars, phi, *mev.get_model (), true, use_ground_pob()); //qe::reduce_array_selects (*mev.get_model (), phi1); SASSERT (!m_ground_pob || vars.empty ()); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 760f38f69..c502baa63 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -530,7 +530,7 @@ public: bool is_qblocked (pob &n); /// \brief interface to Model Based Projection - void mbp(app_ref_vector &vars, expr_ref &fml, const model_ref &mdl, + void mbp(app_ref_vector &vars, expr_ref &fml, model &mdl, bool reduce_all_selects, bool force = false); void updt_solver(prop_solver *solver); diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 3eb18b0e5..b9768f4be 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -128,17 +128,11 @@ namespace spacer { } void subst_vars(ast_manager& m, - app_ref_vector const& vars, - model* M, expr_ref& fml) { - expr_safe_replace sub (m); - model_evaluator_util mev (m); - mev.set_model(*M); - for (app * v : vars) { - expr_ref val (m); - VERIFY(mev.eval (v, val, true)); - sub.insert (v, val); - } - sub (fml); + app_ref_vector const& vars, model& mdl, expr_ref& fml) { + model::scoped_model_completion _sc_(mdl, true); + expr_safe_replace sub(m); + for (app * v : vars) sub.insert (v, mdl(v)); + sub(fml); } void to_mbp_benchmark(std::ostream &out, expr* fml, const app_ref_vector &vars) { @@ -161,16 +155,14 @@ namespace spacer { } void qe_project_z3 (ast_manager& m, app_ref_vector& vars, expr_ref& fml, - const model_ref& M, bool reduce_all_selects, bool use_native_mbp, + model & mdl, bool reduce_all_selects, bool use_native_mbp, bool dont_sub) { params_ref p; p.set_bool("reduce_all_selects", reduce_all_selects); p.set_bool("dont_sub", dont_sub); qe::mbp mbp(m, p); - // TODO: deal with const - model *mdl = const_cast(M.get()); - mbp.spacer(vars, *mdl, fml); + mbp.spacer(vars, mdl, fml); } /* @@ -178,7 +170,7 @@ namespace spacer { * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays */ void qe_project_spacer (ast_manager& m, app_ref_vector& vars, expr_ref& fml, - const model_ref& M, bool reduce_all_selects, bool use_native_mbp, + model& mdl, bool reduce_all_selects, bool use_native_mbp, bool dont_sub) { th_rewriter rw (m); TRACE ("spacer_mbp", @@ -221,30 +213,29 @@ namespace spacer { // sort out vars into bools, arith (int/real), and arrays for (app* v : vars) { if (m.is_bool (v)) { - // obtain the interpretation of the ith var using model completion - VERIFY (M->eval (v, bval, true)); - bool_sub.insert (v, bval); + // obtain the interpretation of the ith var + // using model completion + model::scoped_model_completion _sc_(mdl, true); + bool_sub.insert (v, mdl(v)); } else if (arr_u.is_array(v)) { - array_vars.push_back (v); + array_vars.push_back(v); } else { - SASSERT (ari_u.is_int (v) || ari_u.is_real (v)); - arith_vars.push_back (v); + SASSERT (ari_u.is_int(v) || ari_u.is_real(v)); + arith_vars.push_back(v); } } // substitute Booleans if (!bool_sub.empty()) { - bool_sub (fml); + bool_sub(fml); // -- bool_sub is not simplifying rw (fml); - SASSERT (!m.is_false (fml)); - TRACE ("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); - bool_sub.reset (); + SASSERT(!m.is_false (fml)); + TRACE("spacer_mbp", tout << "Projected Booleans:\n" << fml << "\n"; ); + bool_sub.reset(); } - TRACE ("spacer_mbp", - tout << "Array vars:\n"; - tout << array_vars;); + TRACE ("spacer_mbp", tout << "Array vars:\n"; tout << array_vars;); vars.reset (); @@ -253,7 +244,7 @@ namespace spacer { scoped_no_proof _sp (m); // -- local rewriter that is aware of current proof mode th_rewriter srw(m); - spacer_qe::array_project (*M.get (), array_vars, fml, vars, reduce_all_selects); + spacer_qe::array_project (mdl, array_vars, fml, vars, reduce_all_selects); SASSERT (array_vars.empty ()); srw (fml); SASSERT (!m.is_false (fml)); @@ -261,10 +252,9 @@ namespace spacer { TRACE ("spacer_mbp", tout << "extended model:\n"; - model_pp (tout, *M); + model_pp (tout, mdl); tout << "Auxiliary variables of index and value sorts:\n"; - tout << vars; - ); + tout << vars;); if (vars.empty()) { break; } } @@ -273,39 +263,32 @@ namespace spacer { if (!arith_vars.empty ()) { TRACE ("spacer_mbp", tout << "Arith vars:\n" << arith_vars;); - // XXX Does not seem to have an effect - // qe_lite qe(m); - // qe (arith_vars, fml); - // TRACE ("spacer_mbp", - // tout << "After second qelite: " << - // mk_pp (fml, m) << "\n";); - if (use_native_mbp) { qe::mbp mbp (m); expr_ref_vector fmls(m); flatten_and (fml, fmls); - mbp (true, arith_vars, *M.get (), fmls); - fml = mk_and (fmls); - SASSERT (arith_vars.empty ()); + mbp (true, arith_vars, mdl, fmls); + fml = mk_and(fmls); + SASSERT(arith_vars.empty ()); } else { scoped_no_proof _sp (m); - spacer_qe::arith_project (*M.get (), arith_vars, fml); - } + spacer_qe::arith_project (mdl, arith_vars, fml); + } TRACE ("spacer_mbp", - tout << "Projected arith vars:\n" << mk_pp (fml, m) << "\n"; + tout << "Projected arith vars:\n" << fml << "\n"; tout << "Remaining arith vars:\n" << arith_vars << "\n";); SASSERT (!m.is_false (fml)); } if (!arith_vars.empty ()) { - mbqi_project (*M.get(), arith_vars, fml); + mbqi_project (mdl, arith_vars, fml); } // substitute any remaining arith vars if (!dont_sub && !arith_vars.empty ()) { - subst_vars (m, arith_vars, M.get(), fml); + subst_vars (m, arith_vars, mdl, fml); TRACE ("spacer_mbp", tout << "After substituting remaining arith vars:\n"; tout << mk_pp (fml, m) << "\n"; @@ -315,11 +298,9 @@ namespace spacer { } DEBUG_CODE ( - model_evaluator_util mev (m); - expr_ref v(m); - mev.set_model(*M.get()); - SASSERT (mev.eval (fml, v, false)); - SASSERT (m.is_true (v)); + model_evaluator mev(mdl); + mev.set_model_completion(false); + SASSERT(mev.is_true(fml)); ); vars.reset (); @@ -343,12 +324,14 @@ namespace spacer { } void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, - const model_ref& M, bool reduce_all_selects, bool use_native_mbp, + model &mdl, bool reduce_all_selects, bool use_native_mbp, bool dont_sub) { if (use_native_mbp) - qe_project_z3(m, vars, fml, M, reduce_all_selects, use_native_mbp, dont_sub); + qe_project_z3(m, vars, fml, mdl, + reduce_all_selects, use_native_mbp, dont_sub); else - qe_project_spacer(m, vars, fml, M, reduce_all_selects, use_native_mbp, dont_sub); + qe_project_spacer(m, vars, fml, mdl, + reduce_all_selects, use_native_mbp, dont_sub); } void expand_literals(ast_manager &m, expr_ref_vector& conjs) { diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index a66d2dd5a..c3dbbd042 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -121,11 +121,15 @@ namespace spacer { * 3. use MBP for remaining array and arith variables * 4. for any remaining arith variables, substitute using M */ - void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, - const model_ref& M, bool reduce_all_selects=false, bool native_mbp=false, + void qe_project (ast_manager& m, app_ref_vector& vars, + expr_ref& fml, model &mdl, + bool reduce_all_selects=false, + bool native_mbp=false, bool dont_sub=false); - void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& M, expr_map& map); + // deprecate + void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, + model_ref& M, expr_map& map); // TBD: sort out void expand_literals(ast_manager &m, expr_ref_vector& conjs); From f226c6682bbf1545cc666177f7696af937d3971d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 16 Jun 2018 14:09:24 -0700 Subject: [PATCH 1244/1283] Switched derivation to new model API --- src/muz/spacer/spacer_context.cpp | 28 ++++++++++++++-------------- src/muz/spacer/spacer_context.h | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 8853a2e45..496672b96 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -195,10 +195,10 @@ void derivation::add_premise (pred_transformer &pt, -pob *derivation::create_first_child (model_evaluator_util &mev) { +pob *derivation::create_first_child (model &mdl) { if (m_premises.empty()) { return nullptr; } m_active = 0; - return create_next_child(mev); + return create_next_child(mdl); } void derivation::exist_skolemize(expr* fml, app_ref_vector &vars, expr_ref &res) { @@ -236,7 +236,7 @@ void derivation::exist_skolemize(expr* fml, app_ref_vector &vars, expr_ref &res) sub(fml, res); } -pob *derivation::create_next_child (model_evaluator_util &mev) +pob *derivation::create_next_child(model &mdl) { timeit _timer (is_trace_enabled("spacer_timeit"), "spacer::derivation::create_next_child", @@ -265,13 +265,13 @@ pob *derivation::create_next_child (model_evaluator_util &mev) verbose_stream ()); vars.append(m_evars); m_evars.reset(); - pt().mbp(vars, m_trans, *mev.get_model(), + pt().mbp(vars, m_trans, mdl, true, pt().get_context().use_ground_pob()); m_evars.append (vars); vars.reset(); } - if (!mev.is_true (m_premises[m_active].get_summary())) { + if (!mdl.is_true(m_premises[m_active].get_summary())) { IF_VERBOSE(1, verbose_stream() << "Summary unexpectendly not true\n";); return nullptr; } @@ -294,7 +294,7 @@ pob *derivation::create_next_child (model_evaluator_util &mev) verbose_stream ()); // include m_evars in case they can eliminated now as well vars.append(m_evars); - pt().mbp(vars, post, *mev.get_model(), + pt().mbp(vars, post, mdl, true, pt().get_context().use_ground_pob()); //qe::reduce_array_selects (*mev.get_model (), post); } @@ -337,7 +337,6 @@ pob *derivation::create_next_child () // construct a new model consistent with the must summary of m_active premise pred_transformer &pt = m_premises[m_active].pt (); - model_ref model; ast_manager &m = get_ast_manager (); manager &pm = get_manager (); @@ -355,18 +354,19 @@ pob *derivation::create_next_child () // if not true, bail out, the must summary of m_active is not strong enough // this is possible if m_post was weakened for some reason - if (!pt.is_must_reachable(mk_and(summaries), &model)) { return nullptr; } + model_ref mdl; + if (!pt.is_must_reachable(mk_and(summaries), &mdl)) { return nullptr; } model_evaluator_util mev (m); - mev.set_model (*model); + mev.set_model (*mdl); // find must summary used reach_fact *rf = pt.get_used_rf (mev, true); // get an implicant of the summary - expr_ref_vector u(m), lits (m); + expr_ref_vector u(m), lits(m); u.push_back (rf->get ()); - compute_implicant_literals (*model, u, lits); + compute_implicant_literals (*mdl, u, lits); expr_ref v(m); v = mk_and (lits); @@ -398,7 +398,7 @@ pob *derivation::create_next_child () if (!vars.empty ()) { vars.append(m_evars); m_evars.reset(); - this->pt().mbp(vars, m_trans, *mev.get_model(), + this->pt().mbp(vars, m_trans, *mdl, true, this->pt().get_context().use_ground_pob()); // keep track of implicitly quantified variables m_evars.append (vars); @@ -408,7 +408,7 @@ pob *derivation::create_next_child () m_active++; - return create_next_child (mev); + return create_next_child (*mdl); } /// derivation::premise @@ -3732,7 +3732,7 @@ bool context::create_children(pob& n, datalog::rule const& r, } // create post for the first child and add to queue - pob* kid = deriv->create_first_child (mev); + pob* kid = deriv->create_first_child (*mev.get_model()); // -- failed to create derivation, cleanup and bail out if (!kid) { diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index c502baa63..93704aefc 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -740,7 +740,7 @@ class derivation { app_ref_vector m_evars; /// -- create next child using given model as the guide /// -- returns NULL if there is no next child - pob* create_next_child (model_evaluator_util &mev); + pob* create_next_child (model &mdl); /// existentially quantify vars and skolemize the result void exist_skolemize(expr *fml, app_ref_vector &vars, expr_ref &res); public: @@ -752,7 +752,7 @@ public: /// creates the first child. Must be called after all the premises /// are added. The model must be valid for the premises /// Returns NULL if no child exits - pob *create_first_child (model_evaluator_util &mev); + pob *create_first_child (model &mdl); /// Create the next child. Must summary of the currently active /// premise must be consistent with the transition relation From a222b6d41f1a8e5573eae52d8fb984ec47640821 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 16 Jun 2018 14:17:33 -0700 Subject: [PATCH 1245/1283] Switch reach_fact to new model API --- src/muz/spacer/spacer_context.cpp | 43 ++++++++++++++----------------- src/muz/spacer/spacer_context.h | 9 +++---- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 496672b96..89d438b73 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -361,7 +361,7 @@ pob *derivation::create_next_child () mev.set_model (*mdl); // find must summary used - reach_fact *rf = pt.get_used_rf (mev, true); + reach_fact *rf = pt.get_used_rf (*mev.get_model(), true); // get an implicant of the summary expr_ref_vector u(m), lits(m); @@ -795,27 +795,24 @@ bool pred_transformer::is_must_reachable(expr* state, model_ref* model) -reach_fact* pred_transformer::get_used_rf (model_evaluator_util& mev, - bool all) { +reach_fact* pred_transformer::get_used_rf (model& mdl, bool all) { expr_ref v (m); + model::scoped_model_completion _sc_(mdl, false); for (auto *rf : m_reach_facts) { if (!all && rf->is_init()) continue; - VERIFY(mev.eval (rf->tag(), v, false)); - if (m.is_false(v)) return rf; + if (mdl.is_false(rf->tag())) return rf; } UNREACHABLE(); return nullptr; } -reach_fact *pred_transformer::get_used_origin_rf (model_evaluator_util& mev, - unsigned oidx) { +reach_fact *pred_transformer::get_used_origin_rf(model& mdl, unsigned oidx) { expr_ref b(m), v(m); - + model::scoped_model_completion _sc_(mdl, false); for (auto *rf : m_reach_facts) { pm.formula_n2o (rf->tag(), v, oidx); - VERIFY(mev.eval (v, b, false)); - if (m.is_false (b)) return rf; + if (mdl.is_false(v)) return rf; } UNREACHABLE(); return nullptr; @@ -1139,12 +1136,13 @@ expr_ref pred_transformer::get_cover_delta(func_decl* p_orig, int level) * * returns an implicant of the summary */ -expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, +expr_ref pred_transformer::get_origin_summary (model &mdl, unsigned level, unsigned oidx, bool must, const ptr_vector **aux) { + model::scoped_model_completion _sc_(mdl, false); expr_ref_vector summary (m); expr_ref v(m); @@ -1153,7 +1151,7 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, // -- no auxiliary variables in lemmas *aux = nullptr; } else { // find must summary to use - reach_fact *f = get_used_origin_rf (mev, oidx); + reach_fact *f = get_used_origin_rf(mdl, oidx); summary.push_back (f->get ()); *aux = &f->aux_vars (); } @@ -1167,13 +1165,11 @@ expr_ref pred_transformer::get_origin_summary (model_evaluator_util &mev, } // bail out of if the model is insufficient - if (!mev.is_true(summary)) - return expr_ref(m); + if (!mdl.is_true(summary)) return expr_ref(m); // -- pick an implicant expr_ref_vector lits(m); - compute_implicant_literals (*mev.get_model(), summary, lits); - + compute_implicant_literals (mdl, summary, lits); return mk_and(lits); } @@ -3199,7 +3195,7 @@ bool context::is_reachable(pob &n) mev.set_model(*model); // -- update must summary if (r && r->get_uninterpreted_tail_size () > 0) { - reach_fact_ref rf = n.pt().mk_rf (n, mev, *r); + reach_fact_ref rf = n.pt().mk_rf (n, *mev.get_model(), *r); n.pt ().add_rf (rf.get ()); } @@ -3340,7 +3336,7 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) if (is_concrete) { // -- update must summary if (r && r->get_uninterpreted_tail_size() > 0) { - reach_fact_ref rf = n.pt().mk_rf (n, mev, *r); + reach_fact_ref rf = n.pt().mk_rf (n, *mev.get_model(), *r); checkpoint (); n.pt ().add_rf (rf.get ()); checkpoint (); @@ -3554,8 +3550,7 @@ bool context::propagate(unsigned min_prop_lvl, return false; } -reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, - const datalog::rule& r) +reach_fact *pred_transformer::mk_rf(pob& n, model &mdl, const datalog::rule& r) { SASSERT(&n.pt() == this); timeit _timer1 (is_trace_enabled("spacer_timeit"), @@ -3576,7 +3571,7 @@ reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, pred_transformer& ch_pt = ctx.get_pred_transformer (pred); // get a reach fact of body preds used in the model expr_ref o_ch_reach (m); - reach_fact *kid = ch_pt.get_used_origin_rf (mev, i); + reach_fact *kid = ch_pt.get_used_origin_rf(mdl, i); child_reach_facts.push_back (kid); pm.formula_n2o (kid->get (), o_ch_reach, i); path_cons.push_back (o_ch_reach); @@ -3599,7 +3594,7 @@ reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, if (ctx.reach_dnf()) { expr_ref_vector u(m), lits(m); u.push_back (res); - compute_implicant_literals (*mev.get_model(), u, lits); + compute_implicant_literals (mdl, u, lits); res = mk_and (lits); } @@ -3617,7 +3612,7 @@ reach_fact *pred_transformer::mk_rf (pob& n, model_evaluator_util &mev, timeit _timer1 (is_trace_enabled("spacer_timeit"), "mk_rf::qe_project", verbose_stream ()); - mbp(vars, res, *mev.get_model(), false, true /* force or skolemize */); + mbp(vars, res, mdl, false, true /* force or skolemize */); } @@ -3722,7 +3717,7 @@ bool context::create_children(pob& n, datalog::rule const& r, const ptr_vector *aux = nullptr; expr_ref sum(m); - sum = pt.get_origin_summary (mev, prev_level(n.level()), + sum = pt.get_origin_summary (*mev.get_model(), prev_level(n.level()), j, reach_pred_used[j], &aux); if (!sum) { dealloc(deriv); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 93704aefc..394dbf7e2 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -440,10 +440,10 @@ public: bool is_must_reachable(expr* state, model_ref* model = nullptr); /// \brief Returns reachability fact active in the given model /// all determines whether initial reachability facts are included as well - reach_fact *get_used_rf(model_evaluator_util& mev, bool all = true); + reach_fact *get_used_rf(model& mdl, bool all = true); /// \brief Returns reachability fact active in the origin of the given model - reach_fact* get_used_origin_rf(model_evaluator_util &mev, unsigned oidx); - expr_ref get_origin_summary(model_evaluator_util &mev, + reach_fact* get_used_origin_rf(model &mdl, unsigned oidx); + expr_ref get_origin_summary(model &mdl, unsigned level, unsigned oidx, bool must, const ptr_vector **aux); @@ -472,8 +472,7 @@ public: /// initialize reachability facts using initial rules void init_rfs (); - reach_fact *mk_rf(pob &n, model_evaluator_util &mev, - const datalog::rule &r); + reach_fact *mk_rf(pob &n, model &mdl, const datalog::rule &r); void add_rf (reach_fact *fact); // add reachability fact reach_fact* get_last_rf () const { return m_reach_facts.back (); } expr* get_last_rf_tag () const; From 4204b6ede25e227574e431131e9fbdf2008fefbd Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 16 Jun 2018 14:40:17 -0700 Subject: [PATCH 1246/1283] Switch rest of spacer to new model API and remove mev_util --- src/muz/spacer/spacer_context.cpp | 50 +++++++---------- src/muz/spacer/spacer_context.h | 4 +- src/muz/spacer/spacer_pdr.cpp | 4 +- src/muz/spacer/spacer_util.cpp | 90 ++++++------------------------- src/muz/spacer/spacer_util.h | 30 +---------- 5 files changed, 41 insertions(+), 137 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 89d438b73..5d3ecb3fe 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -36,7 +36,6 @@ Notes: #include "muz/base/dl_rule_set.h" #include "smt/tactic/unit_subsumption_tactic.h" #include "model/model_smt2_pp.h" -#include "model/model_evaluator.h" #include "muz/transforms/dl_mk_rule_inliner.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" @@ -356,12 +355,10 @@ pob *derivation::create_next_child () // this is possible if m_post was weakened for some reason model_ref mdl; if (!pt.is_must_reachable(mk_and(summaries), &mdl)) { return nullptr; } + mdl->set_model_completion(false); - model_evaluator_util mev (m); - mev.set_model (*mdl); // find must summary used - - reach_fact *rf = pt.get_used_rf (*mev.get_model(), true); + reach_fact *rf = pt.get_used_rf (*mdl, true); // get an implicant of the summary expr_ref_vector u(m), lits(m); @@ -2883,7 +2880,6 @@ expr_ref context::get_ground_sat_answer() // smt context to obtain local cexes ref cex_ctx = mk_smt_solver(m, params_ref::get_empty(), symbol::null); - model_evaluator_util mev (m); // preorder traversal of the query derivation tree for (unsigned curr = 0; curr < pts.size (); curr++) { @@ -2936,8 +2932,7 @@ expr_ref context::get_ground_sat_answer() model_ref local_mdl; cex_ctx->get_model (local_mdl); cex_ctx->pop (1); - - model_evaluator mev(*local_mdl); + local_mdl->set_model_completion(true); for (unsigned i = 0; i < child_pts.size(); i++) { pred_transformer& ch_pt = *(child_pts.get(i)); unsigned sig_size = ch_pt.sig_size(); @@ -2946,7 +2941,7 @@ expr_ref context::get_ground_sat_answer() for (unsigned j = 0; j < sig_size; j++) { expr_ref sig_arg(m), sig_val(m); sig_arg = m.mk_const (m_pm.o2o(ch_pt.sig(j), 0, i)); - VERIFY(mev.eval (sig_arg, sig_val, true)); + sig_val = (*local_mdl)(sig_arg); ground_fact_conjs.push_back(m.mk_eq(sig_arg, sig_val)); ground_arg_vals.push_back(sig_val); } @@ -3166,7 +3161,7 @@ bool context::is_reachable(pob &n) // used in case n is unreachable unsigned uses_level = infty_level (); - model_ref model; + model_ref mdl; // used in case n is reachable bool is_concrete; @@ -3177,7 +3172,7 @@ bool context::is_reachable(pob &n) unsigned saved = n.level (); n.m_level = infty_level (); - lbool res = n.pt().is_reachable(n, nullptr, &model, + lbool res = n.pt().is_reachable(n, nullptr, &mdl, uses_level, is_concrete, r, reach_pred_used, num_reuse_reach); n.m_level = saved; @@ -3191,11 +3186,9 @@ bool context::is_reachable(pob &n) SASSERT(res == l_true); SASSERT(is_concrete); - model_evaluator_util mev (m); - mev.set_model(*model); // -- update must summary if (r && r->get_uninterpreted_tail_size () > 0) { - reach_fact_ref rf = n.pt().mk_rf (n, *mev.get_model(), *r); + reach_fact_ref rf = n.pt().mk_rf (n, *mdl, *r); n.pt ().add_rf (rf.get ()); } @@ -3322,6 +3315,7 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) lbool res = n.pt ().is_reachable (n, &cube, &model, uses_level, is_concrete, r, reach_pred_used, num_reuse_reach); + if (model) model->set_model_completion(false); checkpoint (); IF_VERBOSE (1, verbose_stream () << "." << std::flush;); switch (res) { @@ -3330,13 +3324,11 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) // update stats m_stats.m_num_reuse_reach += num_reuse_reach; - model_evaluator_util mev (m); - mev.set_model (*model); // must-reachable if (is_concrete) { // -- update must summary if (r && r->get_uninterpreted_tail_size() > 0) { - reach_fact_ref rf = n.pt().mk_rf (n, *mev.get_model(), *r); + reach_fact_ref rf = n.pt().mk_rf (n, *model, *r); checkpoint (); n.pt ().add_rf (rf.get ()); checkpoint (); @@ -3374,7 +3366,7 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) // create a child of n out.push_back(&n); - VERIFY(create_children (n, *r, mev, reach_pred_used, out)); + VERIFY(create_children (n, *r, *model, reach_pred_used, out)); IF_VERBOSE(1, verbose_stream () << " U " << std::fixed << std::setprecision(2) << watch.get_seconds () << "\n";); @@ -3449,12 +3441,10 @@ lbool context::expand_pob(pob& n, pob_ref_buffer &out) SASSERT(m_weak_abs); m_stats.m_expand_pob_undef++; if (r && r->get_uninterpreted_tail_size() > 0) { - model_evaluator_util mev(m); - mev.set_model(*model); // do not trust reach_pred_used for (unsigned i = 0, sz = reach_pred_used.size(); i < sz; ++i) { reach_pred_used[i] = false; } - has_new_child = create_children(n,*r,mev,reach_pred_used, out); + has_new_child = create_children(n, *r, *model, reach_pred_used, out); } IF_VERBOSE(1, verbose_stream() << " UNDEF " << std::fixed << std::setprecision(2) @@ -3640,7 +3630,7 @@ reach_fact *pred_transformer::mk_rf(pob& n, model &mdl, const datalog::rule& r) \brief create children states from model cube. */ bool context::create_children(pob& n, datalog::rule const& r, - model_evaluator_util &mev, + model &mdl, const vector &reach_pred_used, pob_ref_buffer &out) { @@ -3649,7 +3639,7 @@ bool context::create_children(pob& n, datalog::rule const& r, TRACE("spacer", tout << "Model:\n"; - model_smt2_pp(tout, m, *mev.get_model (), 0); + model_smt2_pp(tout, m, mdl, 0); tout << "\n"; tout << "Transition:\n" << mk_pp(pt.get_transition(r), m) << "\n"; tout << "Pob:\n" << mk_pp(n.post(), m) << "\n";); @@ -3665,7 +3655,7 @@ bool context::create_children(pob& n, datalog::rule const& r, forms.push_back(pt.get_transition(r)); forms.push_back(n.post()); - compute_implicant_literals (*mev.get_model(), forms, lits); + compute_implicant_literals (mdl, forms, lits); expr_ref phi = mk_and (lits); // primed variables of the head @@ -3680,7 +3670,7 @@ bool context::create_children(pob& n, datalog::rule const& r, // skolems of the pob n.get_skolems(vars); - n.pt().mbp(vars, phi, *mev.get_model (), true, use_ground_pob()); + n.pt().mbp(vars, phi, mdl, true, use_ground_pob()); //qe::reduce_array_selects (*mev.get_model (), phi1); SASSERT (!m_ground_pob || vars.empty ()); @@ -3694,7 +3684,7 @@ bool context::create_children(pob& n, datalog::rule const& r, if (m_use_gpdr && preds.size() > 1) { SASSERT(vars.empty()); - return gpdr_create_split_children(n, r, phi, mev.get_model(), out); + return gpdr_create_split_children(n, r, phi, mdl, out); } derivation *deriv = alloc(derivation, n, r, phi, vars); @@ -3717,7 +3707,7 @@ bool context::create_children(pob& n, datalog::rule const& r, const ptr_vector *aux = nullptr; expr_ref sum(m); - sum = pt.get_origin_summary (*mev.get_model(), prev_level(n.level()), + sum = pt.get_origin_summary (mdl, prev_level(n.level()), j, reach_pred_used[j], &aux); if (!sum) { dealloc(deriv); @@ -3727,7 +3717,7 @@ bool context::create_children(pob& n, datalog::rule const& r, } // create post for the first child and add to queue - pob* kid = deriv->create_first_child (*mev.get_model()); + pob* kid = deriv->create_first_child (mdl); // -- failed to create derivation, cleanup and bail out if (!kid) { @@ -3744,8 +3734,8 @@ bool context::create_children(pob& n, datalog::rule const& r, // -- not satisfy 'T && phi'. It is possible to recover from // -- that more gracefully. For now, we just remove the // -- derivation completely forcing it to be recomputed - if (m_weak_abs && (!mev.is_true(pt.get_transition(r)) || - !mev.is_true(n.post()))) + if (m_weak_abs && (!mdl.is_true(pt.get_transition(r)) || + !mdl.is_true(n.post()))) { kid->reset_derivation(); } out.push_back(kid); diff --git a/src/muz/spacer/spacer_context.h b/src/muz/spacer/spacer_context.h index 394dbf7e2..37b035b98 100644 --- a/src/muz/spacer/spacer_context.h +++ b/src/muz/spacer/spacer_context.h @@ -940,7 +940,7 @@ class context { bool gpdr_check_reachability(unsigned lvl, model_search &ms); bool gpdr_create_split_children(pob &n, const datalog::rule &r, expr *trans, - model_ref &mdl, + model &mdl, pob_ref_buffer &out); // Functions used by search. @@ -952,7 +952,7 @@ class context { bool is_reachable(pob &n); lbool expand_pob(pob &n, pob_ref_buffer &out); bool create_children(pob& n, const datalog::rule &r, - model_evaluator_util &mdl, + model &mdl, const vector& reach_pred_used, pob_ref_buffer &out); diff --git a/src/muz/spacer/spacer_pdr.cpp b/src/muz/spacer/spacer_pdr.cpp index ad2b6200d..4e6b37a0a 100644 --- a/src/muz/spacer/spacer_pdr.cpp +++ b/src/muz/spacer/spacer_pdr.cpp @@ -306,7 +306,7 @@ bool context::gpdr_check_reachability(unsigned lvl, model_search &ms) { bool context::gpdr_create_split_children(pob &n, const datalog::rule &r, expr *trans, - model_ref &mdl, + model &mdl, pob_ref_buffer &out) { pred_transformer &pt = n.pt(); ptr_vector preds; @@ -330,7 +330,7 @@ bool context::gpdr_create_split_children(pob &n, const datalog::rule &r, expr_ref_vector lits(m); flatten_and(trans, lits); vector res(preds.size(), expr_ref_vector(m)); - _mbc(pmap, lits, *mdl.get(), res); + _mbc(pmap, lits, mdl, res); // pick an order to process children unsigned_vector kid_order; diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index b9768f4be..f63fc02d0 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -69,64 +69,6 @@ Notes: namespace spacer { - ///////////////////////// - // model_evaluator_util - // - - model_evaluator_util::model_evaluator_util(ast_manager& m) : - m(m), m_mev(nullptr) { - reset (nullptr); - } - - model_evaluator_util::~model_evaluator_util() {reset (nullptr);} - - - void model_evaluator_util::reset(model* model) { - if (m_mev) { - dealloc(m_mev); - m_mev = nullptr; - } - m_model = model; - if (m_model) - m_mev = alloc(model_evaluator, *m_model); - } - - bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { - m_mev->set_model_completion (model_completion); - try { - m_mev->operator() (e, result); - return true; - } - catch (model_evaluator_exception &ex) { - (void)ex; - TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); - return false; - } - } - - bool model_evaluator_util::eval(const expr_ref_vector &v, - expr_ref& res, bool model_completion) { - expr_ref e(m); - e = mk_and (v); - return eval(e, res, model_completion); - } - - - bool model_evaluator_util::is_true(const expr_ref_vector &v) { - expr_ref res(m); - return eval (v, res, false) && m.is_true (res); - } - - bool model_evaluator_util::is_false(expr *x) { - expr_ref res(m); - return eval(x, res, false) && m.is_false (res); - } - - bool model_evaluator_util::is_true(expr *x) { - expr_ref res(m); - return eval(x, res, false) && m.is_true (res); - } - void subst_vars(ast_manager& m, app_ref_vector const& vars, model& mdl, expr_ref& fml) { model::scoped_model_completion _sc_(mdl, true); @@ -876,36 +818,36 @@ namespace { } }; - bool mbqi_project_var(model_evaluator_util &mev, app* var, expr_ref &fml) { + bool mbqi_project_var(model &mdl, app* var, expr_ref &fml) { ast_manager &m = fml.get_manager(); + model::scoped_model_completion _sc_(mdl, false); expr_ref val(m); - mev.eval(var, val, false); + val = mdl(var); TRACE("mbqi_project_verbose", - tout << "MBQI: var: " << mk_pp(var, m) << "\n" - << "fml: " << fml << "\n";); + tout << "MBQI: var: " << mk_pp(var, m) << "\n" + << "fml: " << fml << "\n";); expr_ref_vector terms(m); index_term_finder finder(m, var, terms); for_each_expr(finder, fml); - TRACE("mbqi_project_verbose", - tout << "terms:\n" << terms << "\n";); + TRACE("mbqi_project_verbose", tout << "terms:\n" << terms << "\n";); for(expr * term : terms) { expr_ref tval(m); - mev.eval(term, tval, false); + tval = mdl(term); TRACE("mbqi_project_verbose", tout << "term: " << mk_pp(term, m) - << " tval: " << tval - << " val: " << mk_pp(val, m) << "\n";); + << " tval: " << tval << " val: " << val << "\n";); // -- if the term does not contain an occurrence of var // -- and is in the same equivalence class in the model if (tval == val && !occurs(var, term)) { TRACE("mbqi_project", - tout << "MBQI: replacing " << mk_pp(var, m) << " with " << mk_pp(term, m) << "\n";); + tout << "MBQI: replacing " << mk_pp(var, m) + << " with " << mk_pp(term, m) << "\n";); expr_safe_replace sub(m); sub.insert(var, term); sub(fml); @@ -914,23 +856,23 @@ namespace { } TRACE("mbqi_project", - tout << "MBQI: failed to eliminate " << mk_pp(var, m) << " from " << fml << "\n";); + tout << "MBQI: failed to eliminate " << mk_pp(var, m) + << " from " << fml << "\n";); return false; } - void mbqi_project(model &M, app_ref_vector &vars, expr_ref &fml) { + void mbqi_project(model &mdl, app_ref_vector &vars, expr_ref &fml) { ast_manager &m = fml.get_manager(); - model_evaluator_util mev(m); - mev.set_model(M); expr_ref tmp(m); + model::scoped_model_completion _sc_(mdl, false); // -- evaluate to initialize mev cache - mev.eval(fml, tmp, false); + tmp = mdl(fml); tmp.reset(); unsigned j = 0; for(app* v : vars) - if (!mbqi_project_var(mev, v, fml)) + if (!mbqi_project_var(mdl, v, fml)) vars[j++] = v; vars.shrink(j); } diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index c3dbbd042..9912769c5 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -40,7 +40,6 @@ Revision History: class model; class model_core; -class model_evaluator; namespace spacer { @@ -79,33 +78,6 @@ namespace spacer { typedef ptr_vector decl_vector; typedef obj_hashtable func_decl_set; - // TBD: deprecate - class model_evaluator_util { - ast_manager& m; - model_ref m_model; - model_evaluator* m_mev; - - /// initialize with a given model. All previous state is lost. model can be NULL - void reset (model *model); - public: - model_evaluator_util(ast_manager& m); - ~model_evaluator_util(); - - void set_model(model &model) {reset (&model);} - model_ref &get_model() {return m_model;} - ast_manager& get_ast_manager() const {return m;} - - public: - bool is_true (const expr_ref_vector &v); - bool is_false(expr* x); - bool is_true(expr* x); - - bool eval (const expr_ref_vector &v, expr_ref &result, bool model_completion); - /// evaluates an expression - bool eval (expr *e, expr_ref &result, bool model_completion); - // expr_ref eval(expr* e, bool complete=true); - }; - /** \brief hoist non-boolean if expressions. */ @@ -146,7 +118,7 @@ namespace spacer { */ void ground_expr (expr *e, expr_ref &out, app_ref_vector &vars); - void mbqi_project (model &M, app_ref_vector &vars, expr_ref &fml); + void mbqi_project(model &mdl, app_ref_vector &vars, expr_ref &fml); bool contains_selects (expr* fml, ast_manager& m); void get_select_indices (expr* fml, app_ref_vector& indices, ast_manager& m); From 0adf66dc0acda02437b3d25608a1fc660ebd02bc Mon Sep 17 00:00:00 2001 From: Wojciech Nawrocki Date: Sun, 17 Jun 2018 13:16:36 +0200 Subject: [PATCH 1247/1283] python: fix usage of fpa_get_numeral_significand_uint64 --- src/api/python/z3/z3.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index bd954d8ff..5e83a4181 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8858,7 +8858,10 @@ class FPNumRef(FPRef): 1.25 """ def significand_as_long(self): - return Z3_fpa_get_numeral_significand_uint64(self.ctx.ref(), self.as_ast()) + ptr = (ctypes.c_ulonglong * 1)() + if not Z3_fpa_get_numeral_significand_uint64(self.ctx.ref(), self.as_ast(), ptr): + raise Z3Exception("error retrieving the significand of a numeral.") + return ptr[0] """The significand of the numeral as a bit-vector expression. From 035baf7cb9de60a3f0e6e2e6c29316c8ef0bb191 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Jun 2018 09:43:40 -0700 Subject: [PATCH 1248/1283] align use of spaces before for/if/while Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_context.cpp | 16 ++++++------ src/muz/spacer/spacer_iuc_proof.cpp | 6 ++--- src/muz/spacer/spacer_unsat_core_plugin.cpp | 4 +-- src/muz/spacer/spacer_util.cpp | 29 +++++++++++---------- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 5d3ecb3fe..c926017b6 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -68,7 +68,7 @@ pob::pob (pob* parent, pred_transformer& pt, m_level (level), m_depth (depth), m_open (true), m_use_farkas (true), m_weakness(0), m_blocked_lvl(0) { - if(add_to_parent && m_parent) { + if (add_to_parent && m_parent) { m_parent->add_child(*this); } } @@ -106,14 +106,14 @@ void pob::inherit(pob const &p) { } void pob::clean () { - if(m_new_post) { + if (m_new_post) { m_post = m_new_post; m_new_post.reset(); } } void pob::close () { - if(!m_open) { return; } + if (!m_open) { return; } reset (); m_open = false; @@ -537,7 +537,7 @@ void lemma::mk_cube_core() { if (!m_cube.empty()) {return;} expr_ref cube(m); if (m_pob || m_body) { - if(m_pob) {cube = m_pob->post();} + if (m_pob) {cube = m_pob->post();} else if (m_body) { // no quantifiers for now SASSERT(!is_quantifier(m_body)); @@ -637,7 +637,7 @@ void lemma::instantiate(expr * const * exprs, expr_ref &result, expr *e) { } void lemma::set_level (unsigned lvl) { - if(m_pob){m_pob->blocked_at(lvl);} + if (m_pob){m_pob->blocked_at(lvl);} m_lvl = lvl; } @@ -1920,7 +1920,7 @@ bool pred_transformer::frames::add_lemma(lemma *new_lemma) if (!new_lemma->get_bindings().empty()) { m_pt.add_lemma_core(old_lemma, true); } - if(is_infty_level(old_lemma->level())) { + if (is_infty_level(old_lemma->level())) { old_lemma->bump(); if (old_lemma->get_bumped() >= 100) { IF_VERBOSE(1, verbose_stream() << "Adding lemma to oo " @@ -3230,7 +3230,7 @@ bool context::is_reachable(pob &n) void context::dump_json() { - if(m_params.spacer_print_json().size()) { + if (m_params.spacer_print_json().size()) { std::ofstream of; of.open(m_params.spacer_print_json().bare_str()); m_json_marshaller.marshal(of); @@ -3241,7 +3241,7 @@ void context::dump_json() void context::predecessor_eh() { for (unsigned i = 0; i < m_callbacks.size(); i++) { - if(m_callbacks[i]->predecessor()) + if (m_callbacks[i]->predecessor()) m_callbacks[i]->predecessor_eh(); } } diff --git a/src/muz/spacer/spacer_iuc_proof.cpp b/src/muz/spacer/spacer_iuc_proof.cpp index 6033c744f..b6a522b76 100644 --- a/src/muz/spacer/spacer_iuc_proof.cpp +++ b/src/muz/spacer/spacer_iuc_proof.cpp @@ -137,7 +137,7 @@ void iuc_proof::compute_marks() // if current node is application of a lemma, then all // active hypotheses are removed - if(cur->get_decl_kind() == PR_LEMMA) need_to_mark_h = false; + if (cur->get_decl_kind() == PR_LEMMA) need_to_mark_h = false; // save results m_a_mark.mark(cur, need_to_mark_a); @@ -212,9 +212,9 @@ void iuc_proof::display_dot(std::ostream& out) { std::string color = "white"; if (this->is_a_marked(curr) && !this->is_b_marked(curr)) color = "red"; - else if(!this->is_a_marked(curr) && this->is_b_marked(curr)) + else if (!this->is_a_marked(curr) && this->is_b_marked(curr)) color = "blue"; - else if(this->is_a_marked(curr) && this->is_b_marked(curr) ) + else if (this->is_a_marked(curr) && this->is_b_marked(curr) ) color = "purple"; // compute node label diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index eff05762b..b96ef3037 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -240,7 +240,7 @@ namespace spacer { func_decl* d = step->get_decl(); symbol sym; - if(!m_learner.is_closed(step) && // if step is not already interpolated + if (!m_learner.is_closed(step) && // if step is not already interpolated is_farkas_lemma(m, step)) { SASSERT(d->get_num_parameters() == m.get_num_parents(step) + 2); SASSERT(m.has_fact(step)); @@ -415,7 +415,7 @@ namespace spacer { } // 4. find smallest n using guess and check algorithm - for(unsigned n = 1; true; ++n) + for (unsigned n = 1; true; ++n) { params_ref p; p.set_bool("model", true); diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index f63fc02d0..246410921 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -420,7 +420,7 @@ namespace { m_todo.append(a->get_num_args(), a->get_args()); } else { - for(expr* e : *a) { + for (expr* e : *a) { if (m_model.is_false(e)) { m_todo.push_back(e); break; @@ -432,7 +432,7 @@ namespace { if (!is_true) m_todo.append(a->get_num_args(), a->get_args()); else { - for(expr * e : *a) { + for (expr * e : *a) { if (m_model.is_true(e)) { m_todo.push_back(e); break; @@ -504,14 +504,15 @@ namespace { m_todo.pop_back(); process_app(a, out); m_visited.mark(a, true); - } while(!m_todo.empty()); + } + while (!m_todo.empty()); } bool pick_implicant(const expr_ref_vector &in, expr_ref_vector &out) { m_visited.reset(); bool is_true = m_model.is_true(in); - for(expr* e : in) { + for (expr* e : in) { if (is_true || m_model.is_true(e)) { pick_literals(e, out); } @@ -551,7 +552,7 @@ namespace { ast_manager& m = cube.m(); scoped_no_proof _no_pf_(m); goal_ref g(alloc(goal, m, false, false, false)); - for(expr* c : cube) + for (expr* c : cube) g->assert_expr(c); goal_ref_buffer result; @@ -560,7 +561,7 @@ namespace { SASSERT(result.size() == 1); goal* r = result[0]; cube.reset(); - for(unsigned i = 0; i < r->size(); ++i) { + for (unsigned i = 0; i < r->size(); ++i) { cube.push_back(r->form(i)); } } @@ -569,7 +570,7 @@ namespace { ast_manager &m = cube.m(); scoped_no_proof _no_pf_(m); goal_ref g(alloc(goal, m, false, false, false)); - for(expr* c : cube) + for (expr* c : cube) g->assert_expr(c); goal_ref_buffer goals; @@ -582,7 +583,7 @@ namespace { g = goals[0]; cube.reset(); - for(unsigned i = 0; i < g->size(); ++i) { + for (unsigned i = 0; i < g->size(); ++i) { cube.push_back(g->form(i)); } } @@ -687,7 +688,7 @@ namespace { << mk_and(v) << "\n";); TRACE("spacer_normalize", qe::term_graph egraph(out.m()); - for(expr* e : v) egraph.add_lit(to_app(e)); + for (expr* e : v) egraph.add_lit(to_app(e)); tout << "Reduced app:\n" << mk_pp(egraph.to_app(), out.m()) << "\n";); out = mk_and(v); @@ -790,7 +791,7 @@ namespace { if (vars.size() < fv.size()) { vars.resize(fv.size()); } - for(unsigned i = 0, sz = fv.size(); i < sz; ++i) { + for (unsigned i = 0, sz = fv.size(); i < sz; ++i) { sort *s = fv[i] ? fv[i] : m.mk_bool_sort(); vars[i] = mk_zk_const(m, i, s); var_subst vs(m, false); @@ -810,7 +811,7 @@ namespace { void operator()(app *n) { if (m_array.is_select(n) || m.is_eq(n)) { unsigned i = 0; - for(expr * arg : *n) { + for (expr * arg : *n) { if ((m.is_eq(n) || i > 0) && m_var != arg) m_res.push_back(arg); ++i; } @@ -834,7 +835,7 @@ namespace { TRACE("mbqi_project_verbose", tout << "terms:\n" << terms << "\n";); - for(expr * term : terms) { + for (expr * term : terms) { expr_ref tval(m); tval = mdl(term); @@ -871,7 +872,7 @@ namespace { tmp.reset(); unsigned j = 0; - for(app* v : vars) + for (app* v : vars) if (!mbqi_project_var(mdl, v, fml)) vars[j++] = v; vars.shrink(j); @@ -903,7 +904,7 @@ namespace { void operator()(expr* n) {} void operator()(app* n) { if (a.is_select(n)) - for(unsigned i = 1; i < n->get_num_args(); ++i) + for (unsigned i = 1; i < n->get_num_args(); ++i) if (is_app(n->get_arg(i))) m_indices.push_back(to_app(n->get_arg(i))); } From c81f25a1c8309fe72e358e78d42f19a2ab63064c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Jun 2018 09:59:03 -0700 Subject: [PATCH 1249/1283] fix build issue Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_context.cpp | 2 +- src/muz/spacer/spacer_util.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index c926017b6..b917f8cc1 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -3098,7 +3098,7 @@ bool context::check_reachability () node = m_pob_queue.top (); m_pob_queue.pop(); - unsigned old_sz = m_pob_queue.size(); + size_t old_sz = m_pob_queue.size(); (void)old_sz; SASSERT (node->level () <= m_pob_queue.max_level ()); switch (expand_pob(*node, new_pobs)) { diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 246410921..aaa203c5e 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -358,16 +358,16 @@ namespace { } } - expr *nres, *f1, *f2; + expr *nres = nullptr, *f1 = nullptr, *f2 = nullptr; if (m.is_not(res, nres)) { // --(not (xor a b)) == (= a b) if (m.is_xor(nres, f1, f2)) res = m.mk_eq(f1, f2); // -- split arithmetic inequality else if (m.is_eq(nres, f1, f2) && m_arith.is_int_real(f1)) { - expr_ref u(m); - u = m_arith.mk_lt(f1, f2); - res = m_model.is_true(u) ? u : m_arith.mk_lt(f2, f1); + res = m_arith.mk_lt(f1, f2); + if (!m_model.is_true(res)) + res = m_arith.mk_lt(f2, f1); } } @@ -387,7 +387,7 @@ namespace { if (!is_true && !m.is_false(v)) return; - expr *na, *f1, *f2, *f3; + expr *na = nullptr, *f1 = nullptr, *f2 = nullptr, *f3 = nullptr; SASSERT(!m.is_false(a)); if (m.is_true(a)) { From cd890bd993ccc534df415f1335bb8ec2011754e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 09:34:53 -0700 Subject: [PATCH 1250/1283] fix bug in order for model conversion in normalize_bounds Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 3 ++- src/tactic/arith/lia2pb_tactic.cpp | 18 +++++------------- src/tactic/arith/normalize_bounds_tactic.cpp | 2 +- src/tactic/generic_model_converter.cpp | 2 +- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 0bb4b091e..6dd7fbcaa 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1826,8 +1826,9 @@ void cmd_context::validate_model() { catch (contains_underspecified_op_proc::found) { continue; } - TRACE("model_validate", model_smt2_pp(tout, *this, *(md.get()), 0);); + TRACE("model_validate", model_smt2_pp(tout, *this, *md, 0);); IF_VERBOSE(10, verbose_stream() << "model check failed on: " << mk_pp(a, m()) << "\n";); + IF_VERBOSE(11, model_smt2_pp(verbose_stream(), *this, *md, 0);); invalid_model = true; } } diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index 178ace7fd..db1c22866 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -162,10 +162,8 @@ class lia2pb_tactic : public tactic { } bool has_target() { - bound_manager::iterator it = m_bm.begin(); - bound_manager::iterator end = m_bm.end(); - for (; it != end; ++it) { - if (is_target(*it)) + for (expr * x : m_bm) { + if (is_target(x)) return true; } return false; @@ -174,10 +172,7 @@ class lia2pb_tactic : public tactic { bool check_num_bits() { unsigned num_bits = 0; rational u; - bound_manager::iterator it = m_bm.begin(); - bound_manager::iterator end = m_bm.end(); - for (; it != end; ++it) { - expr * x = *it; + for (expr * x : m_bm) { if (is_target_core(x, u) && u > rational(1)) { num_bits += u.get_num_bits(); if (num_bits > m_total_bits) @@ -234,10 +229,7 @@ class lia2pb_tactic : public tactic { expr_substitution subst(m, m_produce_unsat_cores, false); rational u; ptr_buffer def_args; - bound_manager::iterator it = m_bm.begin(); - bound_manager::iterator end = m_bm.end(); - for (; it != end; ++it) { - expr * x = *it; + for (expr * x : m_bm) { if (is_target_core(x, u) && u > rational(1)) { num_converted++; def_args.reset(); @@ -251,7 +243,7 @@ class lia2pb_tactic : public tactic { def_args.push_back(x_prime); else def_args.push_back(m_util.mk_mul(m_util.mk_numeral(a, true), x_prime)); - if (m_produce_models) + if (m_produce_models) gmc->hide(x_prime->get_decl()); a *= rational(2); } diff --git a/src/tactic/arith/normalize_bounds_tactic.cpp b/src/tactic/arith/normalize_bounds_tactic.cpp index 907c7af8c..60d583798 100644 --- a/src/tactic/arith/normalize_bounds_tactic.cpp +++ b/src/tactic/arith/normalize_bounds_tactic.cpp @@ -109,8 +109,8 @@ class normalize_bounds_tactic : public tactic { expr * def = m_util.mk_add(x_prime, m_util.mk_numeral(val, s)); subst.insert(x, def); if (produce_models) { - gmc->add(to_app(x)->get_decl(), def); gmc->hide(x_prime->get_decl()); + gmc->add(to_app(x)->get_decl(), def); } } } diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 9e2a7b9b2..1911edf3b 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -41,7 +41,7 @@ void generic_model_converter::add(func_decl * d, expr* e) { void generic_model_converter::operator()(model_ref & md) { TRACE("model_converter", tout << "before generic_model_converter\n"; model_v2_pp(tout, *md); display(tout);); - // IF_VERBOSE(0, verbose_stream() << "Apply converter " << m_orig << "\n";); + model_evaluator ev(*(md.get())); ev.set_model_completion(true); ev.set_expand_array_equalities(false); From 55ebf696489537565a10359b084abd9d1acc971a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 09:42:05 -0700 Subject: [PATCH 1251/1283] move comment to fix #1682 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 54fd1cb2b..b2adfff8d 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2647,10 +2647,11 @@ namespace smt { } TRACE("simplify_clauses_detail", tout << "before:\n"; display_clauses(tout, m_lemmas);); + IF_VERBOSE(2, verbose_stream() << "(smt.simplifying-clause-set"; verbose_stream().flush();); + SASSERT(check_clauses(m_lemmas)); SASSERT(check_clauses(m_aux_clauses)); - IF_VERBOSE(2, verbose_stream() << "(smt.simplifying-clause-set"; verbose_stream().flush();); // m_simp_counter is used to balance the cost of simplify_clause. // From c3b27903f8c13073e2bcb66b81a699599ee86a60 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 11:22:01 -0700 Subject: [PATCH 1252/1283] fix #1677 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 6 ++---- src/smt/theory_seq.cpp | 9 ++++++--- src/smt/theory_str.cpp | 7 +++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 3ead59833..8f7b56381 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1206,8 +1206,7 @@ bool seq_rewriter::is_sequence(expr* e, expr_ref_vector& seq) { e = todo.back(); todo.pop_back(); if (m_util.str.is_string(e, s)) { - for (unsigned i = s.length(); i > 0; ) { - --i; + for (unsigned i = 0; i < s.length(); ++i) { seq.push_back(m_util.str.mk_char(s, i)); } } @@ -1218,14 +1217,13 @@ bool seq_rewriter::is_sequence(expr* e, expr_ref_vector& seq) { seq.push_back(e1); } else if (m_util.str.is_concat(e, e1, e2)) { - todo.push_back(e1); todo.push_back(e2); + todo.push_back(e1); } else { return false; } } - seq.reverse(); return true; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index b704795b2..2b2c35466 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2251,7 +2251,9 @@ bool theory_seq::internalize_term(app* term) { e = ctx.mk_enode(term, false, m.is_bool(term), true); } mk_var(e); - + if (m_util.str.is_string(term)) { + add_elim_string_axiom(term); + } return true; } @@ -3086,6 +3088,7 @@ void theory_seq::propagate() { void theory_seq::enque_axiom(expr* e) { if (!m_axiom_set.contains(e)) { + TRACE("seq", tout << "add axiom " << mk_pp(e, m) << "\n";); m_axioms.push_back(e); m_axiom_set.insert(e); m_trail_stack.push(push_back_vector(m_axioms)); @@ -3285,13 +3288,13 @@ void theory_seq::add_replace_axiom(expr* r) { void theory_seq::add_elim_string_axiom(expr* n) { zstring s; + TRACE("seq", tout << mk_pp(n, m) << "\n";); VERIFY(m_util.str.is_string(n, s)); if (s.length() == 0) { return; } expr_ref result(m_util.str.mk_unit(m_util.str.mk_char(s, s.length()-1)), m); - for (unsigned i = s.length()-1; i > 0; ) { - --i; + for (unsigned i = s.length()-1; i-- > 0; ) { result = mk_concat(m_util.str.mk_unit(m_util.str.mk_char(s, i)), result); } add_axiom(mk_eq(n, result, false)); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0ef008927..f2432b4fb 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -8388,13 +8388,12 @@ namespace smt { lbool theory_str::validate_unsat_core(expr_ref_vector & unsat_core) { app * target_term = to_app(get_manager().mk_not(m_theoryStrOverlapAssumption_term)); get_context().internalize(target_term, false); + enode* e1 = get_context().get_enode(target_term); for (unsigned i = 0; i < unsat_core.size(); ++i) { app * core_term = to_app(unsat_core.get(i)); // not sure if this is the correct way to compare terms in this context - enode * e1; - enode * e2; - e1 = get_context().get_enode(target_term); - e2 = get_context().get_enode(core_term); + if (!get_context().e_internalized(core_term)) continue; + enode *e2 = get_context().get_enode(core_term); if (e1 == e2) { TRACE("str", tout << "overlap detected in unsat core, changing UNSAT to UNKNOWN" << std::endl;); return l_undef; From 8040eddf6580be69ea02880fbf918978211ab40f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 16:41:04 -0700 Subject: [PATCH 1253/1283] fix #1658 fix #1689 Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_explain.cpp | 47 ++++++++----- src/nlsat/nlsat_scoped_literal_vector.h | 7 +- src/nlsat/nlsat_solver.cpp | 87 ++++++++++++++----------- src/nlsat/nlsat_solver.h | 10 +-- src/qe/nlqsat.cpp | 37 +++++------ 5 files changed, 105 insertions(+), 83 deletions(-) diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 2278e53dd..420174506 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -574,7 +574,7 @@ namespace nlsat { if (is_const(p)) return; if (m_factor) { - TRACE("nlsat_explain", tout << "adding factors of\n"; display(tout, p); tout << "\n";); + TRACE("nlsat_explain", display(tout << "adding factors of\n", p); tout << "\n";); factor(p, m_factors); polynomial_ref f(m_pm); for (unsigned i = 0; i < m_factors.size(); i++) { @@ -1457,7 +1457,7 @@ namespace nlsat { process(num, ls); reset_already_added(); m_result = nullptr; - TRACE("nlsat_explain", tout << "[explain] result\n"; display(tout, result);); + TRACE("nlsat_explain", display(tout << "[explain] result\n", result);); CASSERT("nlsat", check_already_added()); } @@ -1466,7 +1466,12 @@ namespace nlsat { m_result = &result; svector lits; - TRACE("nlsat", tout << "project x" << x << "\n"; m_solver.display(tout);); + TRACE("nlsat", tout << "project x" << x << "\n"; + for (unsigned i = 0; i < num; ++i) { + m_solver.display(tout, ls[i]) << " "; + } + tout << "\n"; + m_solver.display(tout);); DEBUG_CODE( for (unsigned i = 0; i < num; ++i) { @@ -1509,8 +1514,15 @@ namespace nlsat { result.set(i, ~result[i]); } DEBUG_CODE( - for (unsigned i = 0; i < result.size(); ++i) { - SASSERT(l_true == m_solver.value(result[i])); + TRACE("nlsat", + for (literal l : result) { + m_solver.display(tout << " ", l); + } + tout << "\n"; + ); + for (literal l : result) { + CTRACE("nlsat", l_true != m_solver.value(l), m_solver.display(tout, l) << " " << m_solver.value(l) << "\n";); + SASSERT(l_true == m_solver.value(l)); }); } @@ -1621,21 +1633,21 @@ namespace nlsat { roots.reset(); m_am.isolate_roots(p, undef_var_assignment(m_assignment, x), roots); bool glb_valid = false, lub_valid = false; - for (unsigned j = 0; j < roots.size(); ++j) { - int s = m_am.compare(x_val, roots[j]); + for (auto const& r : roots) { + int s = m_am.compare(x_val, r); SASSERT(s != 0); + + if (s < 0 && (!lub_valid || m_am.lt(r, lub))) { + lub_index = i; + m_am.set(lub, r); + } + + if (s > 0 && (!glb_valid || m_am.lt(glb, r))) { + glb_index = i; + m_am.set(glb, r); + } lub_valid |= s < 0; glb_valid |= s > 0; - - if (s < 0 && m_am.lt(roots[j], lub)) { - lub_index = i; - m_am.set(lub, roots[j]); - } - - if (s > 0 && m_am.lt(glb, roots[j])) { - glb_index = i; - m_am.set(glb, roots[j]); - } } if (glb_valid) { ++num_glb; @@ -1701,6 +1713,7 @@ namespace nlsat { } void project_pairs(var x, unsigned idx, polynomial_ref_vector const& ps) { + TRACE("nlsat_explain", tout << "project pairs\n";); polynomial_ref p(m_pm); p = ps.get(idx); for (unsigned i = 0; i < ps.size(); ++i) { diff --git a/src/nlsat/nlsat_scoped_literal_vector.h b/src/nlsat/nlsat_scoped_literal_vector.h index 61760f06d..dffaa169f 100644 --- a/src/nlsat/nlsat_scoped_literal_vector.h +++ b/src/nlsat/nlsat_scoped_literal_vector.h @@ -34,9 +34,8 @@ namespace nlsat { bool empty() const { return m_lits.empty(); } literal operator[](unsigned i) const { return m_lits[i]; } void reset() { - unsigned sz = m_lits.size(); - for (unsigned i = 0; i < sz; i++) { - m_solver.dec_ref(m_lits[i]); + for (literal l : m_lits) { + m_solver.dec_ref(l); } m_lits.reset(); } @@ -50,6 +49,8 @@ namespace nlsat { m_lits[i] = l; } literal const * c_ptr() const { return m_lits.c_ptr(); } + literal const * begin() const { return m_lits.begin(); } + literal const * end() const { return m_lits.end(); } void shrink(unsigned new_sz) { SASSERT(new_sz <= m_lits.size()); unsigned sz = m_lits.size(); diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 9767448b1..f430f3a0c 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -270,7 +270,7 @@ namespace nlsat { TRACE("ref", tout << "inc: " << b << "\n";); if (b == null_bool_var) return; - if (m_atoms[b] == 0) + if (m_atoms[b] == nullptr) return; m_atoms[b]->inc_ref(); } @@ -395,7 +395,7 @@ namespace nlsat { bool_var mk_bool_var_core() { bool_var b = m_bid_gen.mk(); m_num_bool_vars++; - m_atoms .setx(b, 0, 0); + m_atoms .setx(b, nullptr, nullptr); m_bvalues .setx(b, l_undef, l_undef); m_levels .setx(b, UINT_MAX, UINT_MAX); m_justifications.setx(b, null_justification, null_justification); @@ -469,7 +469,7 @@ namespace nlsat { //SASSERT(m_bvalues[b] == l_undef); m_num_bool_vars--; m_dead[b] = true; - m_atoms[b] = 0; + m_atoms[b] = nullptr; m_bid_gen.recycle(b); } @@ -494,6 +494,7 @@ namespace nlsat { void del(atom * a) { if (a == nullptr) return ; + TRACE("nlsat", display(tout << "del: b" << a->m_bool_var << " ", *a) << "\n";); if (a->is_ineq_atom()) del(to_ineq_atom(a)); else @@ -555,6 +556,7 @@ namespace nlsat { bool_var b = mk_bool_var_core(); m_atoms[b] = atom; atom->m_bool_var = b; + TRACE("nlsat", display(tout << "create: b" << atom->m_bool_var << " ", *atom) << "\n";); return b; } } @@ -749,7 +751,7 @@ namespace nlsat { m_levels[b] = UINT_MAX; del_jst(m_allocator, m_justifications[b]); m_justifications[b] = null_justification; - if (m_atoms[b] == 0 && b < m_bk) + if (m_atoms[b] == nullptr && b < m_bk) m_bk = b; } @@ -895,7 +897,7 @@ namespace nlsat { \brief Assign literal using the given justification */ void assign(literal l, justification j) { - TRACE("nlsat", tout << "assigning literal:\n"; display(tout, l); + TRACE("nlsat", tout << "assigning literal: "; display(tout, l); tout << "\njustification kind: " << j.get_kind() << "\n";); SASSERT(assigned_value(l) == l_undef); SASSERT(j != null_justification); @@ -926,6 +928,7 @@ namespace nlsat { */ lbool value(literal l) { lbool val = assigned_value(l); + TRACE("nlsat_verbose", display(tout << " assigned value " << val << " for ", l) << "\n";); if (val != l_undef) { return val; } @@ -941,7 +944,7 @@ namespace nlsat { val = to_lbool(m_evaluator.eval(a, l.sign())); TRACE("value_bug", tout << "value of: "; display(tout, l); tout << " := " << val << "\n"; tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n"; - display_assignment(tout);); + display_assignment(tout);); return val; } @@ -2011,9 +2014,9 @@ namespace nlsat { } bool can_reorder() const { - for (unsigned i = 0; i < m_atoms.size(); ++i) { - if (m_atoms[i]) { - if (m_atoms[i]->is_root_atom()) return false; + for (atom * a : m_atoms) { + if (a) { + if (a->is_root_atom()) return false; } } return true; @@ -2100,16 +2103,13 @@ namespace nlsat { \brief After variable reordering some lemmas containing root atoms may be ill-formed. */ void del_ill_formed_lemmas() { - unsigned sz = m_learned.size(); unsigned j = 0; - for (unsigned i = 0; i < sz; i++) { - clause * c = m_learned[i]; + for (clause* c : m_learned) { if (ill_formed(*c)) { del_clause(c); } else { - m_learned[j] = c; - j++; + m_learned[j++] = c; } } m_learned.shrink(j); @@ -2119,9 +2119,8 @@ namespace nlsat { \brief Return true if the clause contains an ill formed root atom */ bool ill_formed(clause const & c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - bool_var b = c[i].var(); + for (literal lit : c) { + bool_var b = lit.var(); atom * a = m_atoms[b]; if (a == nullptr) continue; @@ -2139,19 +2138,16 @@ namespace nlsat { void reinit_cache() { reinit_cache(m_clauses); reinit_cache(m_learned); - for (unsigned i = 0; i < m_atoms.size(); ++i) { - reinit_cache(m_atoms[i]); - } + for (atom* a : m_atoms) + reinit_cache(a); } void reinit_cache(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) - reinit_cache(*(cs[i])); + for (clause* c : cs) + reinit_cache(*c); } void reinit_cache(clause const & c) { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) - reinit_cache(c[i]); + for (literal l : c) + reinit_cache(l); } void reinit_cache(literal l) { bool_var b = l.var(); @@ -2566,9 +2562,12 @@ namespace nlsat { std::ostream& display_bool_assignment(std::ostream & out) const { unsigned sz = m_atoms.size(); for (bool_var b = 0; b < sz; b++) { - if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) { + if (m_atoms[b] == nullptr && m_bvalues[b] != l_undef) { out << "b" << b << " -> " << (m_bvalues[b] == l_true ? "true" : "false") << "\n"; } + else if (m_atoms[b] != nullptr && m_bvalues[b] != l_undef) { + display(out << "b" << b << " ", *m_atoms[b]) << " -> " << (m_bvalues[b] == l_true ? "true" : "false") << "\n"; + } } TRACE("nlsat_bool_assignment", for (bool_var b = 0; b < sz; b++) { @@ -3035,7 +3034,7 @@ namespace nlsat { std::ostream& display_smt2_bool_decls(std::ostream & out) const { unsigned sz = m_atoms.size(); for (unsigned i = 0; i < sz; i++) { - if (m_atoms[i] == 0) + if (m_atoms[i] == nullptr) out << "(declare-fun b" << i << " () Bool)\n"; } return out; @@ -3162,13 +3161,24 @@ namespace nlsat { void solver::get_bvalues(svector& vs) { vs.reset(); - vs.append(m_imp->m_bvalues); + unsigned sz = m_imp->m_bvalues.size(); + for (bool_var b = 0; b < sz; ++b) { + if (m_imp->m_atoms[b] == nullptr) { + vs.push_back(m_imp->m_bvalues[b]); + } + else { + vs.push_back(l_undef); // don't save values from atoms. + } + } + TRACE("nlsat", display(tout);); } void solver::set_bvalues(svector const& vs) { + TRACE("nlsat", display(tout);); m_imp->m_bvalues.reset(); m_imp->m_bvalues.append(vs); m_imp->m_bvalues.resize(m_imp->m_atoms.size(), l_undef); + TRACE("nlsat", display(tout);); } var solver::mk_var(bool is_int) { @@ -3199,27 +3209,28 @@ namespace nlsat { return m_imp->mk_clause(num_lits, lits, a); } - void solver::display(std::ostream & out) const { - m_imp->display(out); + std::ostream& solver::display(std::ostream & out) const { + return m_imp->display(out); } - void solver::display(std::ostream & out, literal l) const { - m_imp->display(out, l); + std::ostream& solver::display(std::ostream & out, literal l) const { + return m_imp->display(out, l); } - void solver::display(std::ostream & out, unsigned n, literal const* ls) const { + std::ostream& solver::display(std::ostream & out, unsigned n, literal const* ls) const { for (unsigned i = 0; i < n; ++i) { display(out, ls[i]); out << "; "; } + return out; } - void solver::display(std::ostream & out, var x) const { - m_imp->m_display_var(out, x); + std::ostream& solver::display(std::ostream & out, var x) const { + return m_imp->m_display_var(out, x); } - void solver::display(std::ostream & out, atom const& a) const { - m_imp->display(out, a, m_imp->m_display_var); + std::ostream& solver::display(std::ostream & out, atom const& a) const { + return m_imp->display(out, a, m_imp->m_display_var); } display_var_proc const & solver::display_proc() const { diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index e7b250f64..4ba1225bd 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -225,21 +225,21 @@ namespace nlsat { /** \brief Display solver's state. */ - void display(std::ostream & out) const; + std::ostream& display(std::ostream & out) const; /** \brief Display literal */ - void display(std::ostream & out, literal l) const; + std::ostream& display(std::ostream & out, literal l) const; - void display(std::ostream & out, unsigned n, literal const* ls) const; + std::ostream& display(std::ostream & out, unsigned n, literal const* ls) const; - void display(std::ostream & out, atom const& a) const; + std::ostream& display(std::ostream & out, atom const& a) const; /** \brief Display variable */ - void display(std::ostream & out, var x) const; + std::ostream& display(std::ostream & out, var x) const; display_var_proc const & display_proc() const; }; diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index d8d6705fe..95f6b9b21 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -205,8 +205,7 @@ namespace qe { nlsat::scoped_literal_vector new_result(m_solver); result.reset(); // project quantified Boolean variables. - for (unsigned i = 0; i < m_asms.size(); ++i) { - nlsat::literal lit = m_asms[i]; + for (nlsat::literal lit : m_asms) { if (!m_b2a.contains(lit.var()) || fvars.contains(lit.var())) { result.push_back(lit); } @@ -215,12 +214,13 @@ namespace qe { // project quantified real variables. // They are sorted by size, so we project the largest variables first to avoid // renaming variables. - for (unsigned i = vars.size(); i > 0;) { - --i; + for (unsigned i = vars.size(); i-- > 0;) { new_result.reset(); + TRACE("qe", m_solver.display(tout << "project: ", vars[i]) << "\n";); ex.project(vars[i], result.size(), result.c_ptr(), new_result); result.swap(new_result); - TRACE("qe", m_solver.display(tout, result.size(), result.c_ptr()); tout << "\n";); + TRACE("qe", m_solver.display(tout, vars[i]) << ": "; + m_solver.display(tout, result.size(), result.c_ptr()); tout << "\n";); } negate_clause(result); } @@ -596,6 +596,7 @@ namespace qe { } void display(std::ostream& out) { + out << "level " << level() << "\n"; display_preds(out); display_assumptions(out); m_solver.display(out << "solver:\n"); @@ -682,7 +683,7 @@ namespace qe { } else if (m_t2x.is_var(v)) { nlsat::var w = m_t2x.to_var(v); - TRACE("qe", tout << mk_pp(v, m) << " |-> " << w << "\n";); + TRACE("qe", tout << mk_pp(v, m) << " |-> x" << w << "\n";); m_bound_rvars.back().push_back(w); m_rvar2level.setx(w, lvl, max_level()); } @@ -724,13 +725,11 @@ namespace qe { } void init_var2expr() { - expr2var::iterator it = m_t2x.begin(), end = m_t2x.end(); - for (; it != end; ++it) { - m_x2t.insert(it->m_value, it->m_key); + for (auto const& kv : m_t2x) { + m_x2t.insert(kv.m_value, kv.m_key); } - it = m_a2b.begin(), end = m_a2b.end(); - for (; it != end; ++it) { - m_b2a.insert(it->m_value, it->m_key); + for (auto const& kv : m_a2b) { + m_b2a.insert(kv.m_value, kv.m_key); } } @@ -741,10 +740,9 @@ namespace qe { bool ok = true; model_ref md = alloc(model, m); arith_util util(m); - expr2var::iterator it = m_t2x.begin(), end = m_t2x.end(); - for (; it != end; ++it) { - nlsat::var x = it->m_value; - expr * t = it->m_key; + for (auto const& kv : m_t2x) { + nlsat::var x = kv.m_value; + expr * t = kv.m_key; if (!is_uninterp_const(t) || !m_free_vars.contains(t) || m_aux_vars.contains(t)) continue; expr * v; @@ -760,10 +758,9 @@ namespace qe { } md->register_decl(to_app(t)->get_decl(), v); } - it = m_a2b.begin(), end = m_a2b.end(); - for (; it != end; ++it) { - expr * a = it->m_key; - nlsat::bool_var b = it->m_value; + for (auto const& kv : m_a2b) { + expr * a = kv.m_key; + nlsat::bool_var b = kv.m_value; if (a == nullptr || !is_uninterp_const(a) || b == m_is_true.var() || !m_free_vars.contains(a) || m_aux_vars.contains(a)) continue; lbool val = m_bmodel0.get(b, l_undef); From 4634d1daed5a173b5bca26995dba51256bad521f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 20:37:39 -0700 Subject: [PATCH 1254/1283] selective expansion of strings for canonizer to fix #1690 regression Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 14 ++++++++------ src/smt/theory_seq.h | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 2b2c35466..91da5a078 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2251,9 +2251,6 @@ bool theory_seq::internalize_term(app* term) { e = ctx.mk_enode(term, false, m.is_bool(term), true); } mk_var(e); - if (m_util.str.is_string(term)) { - add_elim_string_axiom(term); - } return true; } @@ -2901,12 +2898,16 @@ expr_ref theory_seq::expand(expr* e, dependency*& eqs) { expr_ref theory_seq::try_expand(expr* e, dependency*& eqs){ expr_ref result(m); expr_dep ed; + zstring s; if (m_rep.find_cache(e, ed)) { if (e != ed.first) { eqs = m_dm.mk_join(eqs, ed.second); } result = ed.first; } + else if (m_util.str.is_string(e, s) && s.length() > 0) { + result = add_elim_string_axiom(e); + } else { m_expand_todo.push_back(e); } @@ -2929,7 +2930,7 @@ expr_ref theory_seq::expand1(expr* e0, dependency*& eqs) { } else if (m_util.str.is_empty(e) || m_util.str.is_string(e)) { result = e; - } + } else if (m_util.str.is_prefix(e, e1, e2)) { arg1 = try_expand(e1, deps); arg2 = try_expand(e2, deps); @@ -3286,12 +3287,12 @@ void theory_seq::add_replace_axiom(expr* r) { tightest_prefix(s, x); } -void theory_seq::add_elim_string_axiom(expr* n) { +expr_ref theory_seq::add_elim_string_axiom(expr* n) { zstring s; TRACE("seq", tout << mk_pp(n, m) << "\n";); VERIFY(m_util.str.is_string(n, s)); if (s.length() == 0) { - return; + return expr_ref(n, m); } expr_ref result(m_util.str.mk_unit(m_util.str.mk_char(s, s.length()-1)), m); for (unsigned i = s.length()-1; i-- > 0; ) { @@ -3300,6 +3301,7 @@ void theory_seq::add_elim_string_axiom(expr* n) { add_axiom(mk_eq(n, result, false)); m_rep.update(n, result, nullptr); m_new_solution = true; + return result; } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index b6b553dec..3cacf3326 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -504,7 +504,7 @@ namespace smt { void add_int_string(expr* e); bool check_int_string(); - void add_elim_string_axiom(expr* n); + expr_ref add_elim_string_axiom(expr* n); void add_at_axiom(expr* n); void add_in_re_axiom(expr* n); void add_itos_axiom(expr* n); From 6a0b70ee5cb3664fafee08068626b9a68778bf78 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 20:42:53 -0700 Subject: [PATCH 1255/1283] selective expansion of strings for canonizer to fix #1690 regression Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 91da5a078..03bf81d45 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2898,14 +2898,13 @@ expr_ref theory_seq::expand(expr* e, dependency*& eqs) { expr_ref theory_seq::try_expand(expr* e, dependency*& eqs){ expr_ref result(m); expr_dep ed; - zstring s; if (m_rep.find_cache(e, ed)) { if (e != ed.first) { eqs = m_dm.mk_join(eqs, ed.second); } result = ed.first; } - else if (m_util.str.is_string(e, s) && s.length() > 0) { + else if (m_util.str.is_string(e)) { result = add_elim_string_axiom(e); } else { From c15eca66d6c0df6b51ac3e7a5a83dbcdd2e0687b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 20:53:33 -0700 Subject: [PATCH 1256/1283] fix #1685 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 4fd9b08be..d19cd14d4 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -338,8 +338,7 @@ namespace sat { if (sz == 0) { s.set_conflict(justification()); for (; it != end; ++it, ++it2) { - *it2 = *it; - ++it2; + *it2 = *it; } break; } From b4aac1ab5594419346d18278fcccbb24f02a8a5a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 21:23:13 -0700 Subject: [PATCH 1257/1283] revert fix to #1677 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context_inv.cpp | 83 ++++++++++++------------------------- src/smt/theory_seq.cpp | 2 +- 2 files changed, 27 insertions(+), 58 deletions(-) diff --git a/src/smt/smt_context_inv.cpp b/src/smt/smt_context_inv.cpp index cf09c996a..7f409622b 100644 --- a/src/smt/smt_context_inv.cpp +++ b/src/smt/smt_context_inv.cpp @@ -43,13 +43,9 @@ namespace smt { } bool context::check_clauses(clause_vector const & v) const { - clause_vector::const_iterator it = v.begin(); - clause_vector::const_iterator end = v.end(); - for (; it != end; ++it) { - clause * cls = *it; + for (clause* cls : v) if (!cls->deleted()) check_clause(cls); - } return true; } @@ -92,10 +88,7 @@ namespace smt { bool context::check_lit_occs(literal l) const { clause_set const & v = m_lit_occs[l.index()]; - clause_set::iterator it = v.begin(); - clause_set::iterator end = v.end(); - for (; it != end; ++it) { - clause * cls = *it; + for (clause * cls : v) { unsigned num = cls->get_num_literals(); unsigned i = 0; for (; i < num; i++) @@ -138,10 +131,8 @@ namespace smt { } bool context::check_enodes() const { - ptr_vector::const_iterator it = m_enodes.begin(); - ptr_vector::const_iterator end = m_enodes.end(); - for (; it != end; ++it) { - check_enode(*it); + for (enode* n : m_enodes) { + check_enode(n); } return true; } @@ -157,11 +148,9 @@ namespace smt { } bool context::check_missing_clause_propagation(clause_vector const & v) const { - clause_vector::const_iterator it = v.begin(); - clause_vector::const_iterator end = v.end(); - for (; it != end; ++it) { - CTRACE("missing_propagation", is_unit_clause(*it), display_clause_detail(tout, *it); tout << "\n";); - SASSERT(!is_unit_clause(*it)); + for (clause * cls : v) { + CTRACE("missing_propagation", is_unit_clause(cls), display_clause_detail(tout, cls); tout << "\n";); + SASSERT(!is_unit_clause(cls)); } return true; } @@ -188,10 +177,7 @@ namespace smt { } bool context::check_missing_eq_propagation() const { - ptr_vector::const_iterator it = m_enodes.begin(); - ptr_vector::const_iterator end = m_enodes.end(); - for (; it != end; ++it) { - enode * n = *it; + for (enode* n : m_enodes) { SASSERT(!n->is_true_eq() || get_assignment(n) == l_true); if (n->is_eq() && get_assignment(n) == l_true) { SASSERT(n->is_true_eq()); @@ -201,13 +187,8 @@ namespace smt { } bool context::check_missing_congruence() const { - ptr_vector::const_iterator it = m_enodes.begin(); - ptr_vector::const_iterator end = m_enodes.end(); - for (; it != end; ++it) { - enode * n = *it; - ptr_vector::const_iterator it2 = m_enodes.begin(); - for (; it2 != end; ++it2) { - enode * n2 = *it2; + for (enode* n : m_enodes) { + for (enode* n2 : m_enodes) { if (n->get_root() != n2->get_root()) { if (n->is_true_eq() && n2->is_true_eq()) continue; @@ -222,10 +203,7 @@ namespace smt { } bool context::check_missing_bool_enode_propagation() const { - ptr_vector::const_iterator it = m_enodes.begin(); - ptr_vector::const_iterator end = m_enodes.end(); - for (; it != end; ++it) { - enode * n = *it; + for (enode* n : m_enodes) { if (m_manager.is_bool(n->get_owner()) && get_assignment(n) == l_undef) { enode * first = n; do { @@ -286,10 +264,7 @@ namespace smt { For all a, b. root(a) == root(b) ==> get_assignment(a) == get_assignment(b) */ bool context::check_eqc_bool_assignment() const { - ptr_vector::const_iterator it = m_enodes.begin(); - ptr_vector::const_iterator end = m_enodes.end(); - for (; it != end; ++it) { - enode * e = *it; + for (enode* e : m_enodes) { if (m_manager.is_bool(e->get_owner())) { enode * r = e->get_root(); CTRACE("eqc_bool", get_assignment(e) != get_assignment(r), @@ -343,24 +318,24 @@ namespace smt { TRACE("check_th_diseq_propagation", tout << "checking theory: " << m_manager.get_family_name(th_id) << "\n";); // if the theory doesn't use diseqs, then the diseqs are not propagated. if (th->use_diseqs() && rhs->get_th_var(th_id) != null_theory_var) { + bool found = false; // lhs and rhs are attached to theory th_id - svector::const_iterator it = m_propagated_th_diseqs.begin(); - svector::const_iterator end = m_propagated_th_diseqs.end(); - for (; it != end; ++it) { - if (it->m_th_id == th_id) { - enode * lhs_prime = th->get_enode(it->m_lhs)->get_root(); - enode * rhs_prime = th->get_enode(it->m_rhs)->get_root(); + for (new_th_eq const& eq : m_propagated_th_diseqs) { + if (eq.m_th_id == th_id) { + enode * lhs_prime = th->get_enode(eq.m_lhs)->get_root(); + enode * rhs_prime = th->get_enode(eq.m_rhs)->get_root(); TRACE("check_th_diseq_propagation", - tout << m_manager.get_family_name(it->m_th_id) << "\n";); + tout << m_manager.get_family_name(eq.m_th_id) << "\n";); if ((lhs == lhs_prime && rhs == rhs_prime) || (rhs == lhs_prime && lhs == rhs_prime)) { TRACE("check_th_diseq_propagation", tout << "ok v" << v << " " << get_assignment(v) << "\n";); + found = true; break; } } } - if (it == end) { + if (!found) { // missed theory diseq propagation display(std::cout); std::cout << "checking theory: " << m_manager.get_family_name(th_id) << "\n"; @@ -369,8 +344,7 @@ namespace smt { std::cout << "lhs: #" << lhs->get_owner_id() << ", rhs: #" << rhs->get_owner_id() << "\n"; std::cout << mk_bounded_pp(lhs->get_owner(), m_manager) << " " << mk_bounded_pp(rhs->get_owner(), m_manager) << "\n"; } - - SASSERT(it != end); + VERIFY(found); } l = l->get_next(); } @@ -381,11 +355,9 @@ namespace smt { } bool context::check_missing_diseq_conflict() const { - svector::const_iterator it = m_diseq_vector.begin(); - svector::const_iterator end = m_diseq_vector.end(); - for (; it != end; ++it) { - enode * n1 = it->first; - enode * n2 = it->second; + for (enode_pair const& p : m_diseq_vector) { + enode * n1 = p.first; + enode * n2 = p.second; if (n1->get_root() == n2->get_root()) { TRACE("diseq_bug", tout << "n1: #" << n1->get_owner_id() << ", n2: #" << n2->get_owner_id() << @@ -420,10 +392,7 @@ namespace smt { return true; } ast_manager& m = m_manager; - literal_vector::const_iterator it = m_assigned_literals.begin(); - literal_vector::const_iterator end = m_assigned_literals.end(); - for (; it != end; ++it) { - literal lit = *it; + for (literal lit : m_assigned_literals) { if (!is_relevant(lit)) { continue; } @@ -435,7 +404,7 @@ namespace smt { if (is_quantifier(n) && m.is_rec_fun_def(to_quantifier(n))) { continue; } - switch (get_assignment(*it)) { + switch (get_assignment(lit)) { case l_undef: break; case l_true: diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 03bf81d45..3b81a35dc 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2904,7 +2904,7 @@ expr_ref theory_seq::try_expand(expr* e, dependency*& eqs){ } result = ed.first; } - else if (m_util.str.is_string(e)) { + else if (false && m_util.str.is_string(e)) { result = add_elim_string_axiom(e); } else { From 86c39c971d12be7e063e05d26582a53e7f10194a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Jun 2018 21:53:45 -0700 Subject: [PATCH 1258/1283] fix #1681 Signed-off-by: Nikolaj Bjorner --- src/smt/proto_model/proto_model.cpp | 16 +++++++++++----- src/smt/proto_model/proto_model.h | 4 ++-- src/smt/smt_context.cpp | 2 +- src/smt/smt_model_finder.cpp | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index 688ded834..493948f32 100644 --- a/src/smt/proto_model/proto_model.cpp +++ b/src/smt/proto_model/proto_model.cpp @@ -342,10 +342,16 @@ void proto_model::compress() { \brief Complete the interpretation fi of f if it is partial. If f does not have an interpretation in the given model, then this is a noop. */ -void proto_model::complete_partial_func(func_decl * f) { +void proto_model::complete_partial_func(func_decl * f, bool use_fresh) { func_interp * fi = get_func_interp(f); if (fi && fi->is_partial()) { - expr * else_value = fi->get_max_occ_result(); + expr * else_value; + if (use_fresh) { + else_value = get_fresh_value(f->get_range()); + } + else { + else_value = fi->get_max_occ_result(); + } if (else_value == nullptr) else_value = get_some_value(f->get_range()); fi->set_else(else_value); @@ -355,14 +361,14 @@ void proto_model::complete_partial_func(func_decl * f) { /** \brief Set the (else) field of function interpretations... */ -void proto_model::complete_partial_funcs() { +void proto_model::complete_partial_funcs(bool use_fresh) { if (m_model_partial) return; // m_func_decls may be "expanded" when we invoke get_some_value. // So, we must not use iterators to traverse it. - for (unsigned i = 0; i < m_func_decls.size(); i++) { - complete_partial_func(m_func_decls[i]); + for (func_decl* f : m_func_decls) { + complete_partial_func(f, use_fresh); } } diff --git a/src/smt/proto_model/proto_model.h b/src/smt/proto_model/proto_model.h index d92d459e4..04e3a90fe 100644 --- a/src/smt/proto_model/proto_model.h +++ b/src/smt/proto_model/proto_model.h @@ -100,8 +100,8 @@ public: // // Complete partial function interps // - void complete_partial_func(func_decl * f); - void complete_partial_funcs(); + void complete_partial_func(func_decl * f, bool use_fresh); + void complete_partial_funcs(bool use_fresh); // // Create final model object. diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index b2adfff8d..48033f9b5 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4364,7 +4364,7 @@ namespace smt { m_proto_model = m_model_generator->mk_model(); m_qmanager->adjust_model(m_proto_model.get()); TRACE("mbqi_bug", tout << "before complete_partial_funcs:\n"; model_pp(tout, *m_proto_model);); - m_proto_model->complete_partial_funcs(); + m_proto_model->complete_partial_funcs(false); TRACE("mbqi_bug", tout << "before cleanup:\n"; model_pp(tout, *m_proto_model);); m_proto_model->cleanup(); if (m_fparams.m_model_compact) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 4307d3fdf..73f85faf6 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -1028,7 +1028,7 @@ namespace smt { void complete_partial_funcs(func_decl_set const & partial_funcs) { for (func_decl * f : partial_funcs) { // Complete the current interpretation - m_model->complete_partial_func(f); + m_model->complete_partial_func(f, true); unsigned arity = f->get_arity(); func_interp * fi = m_model->get_func_interp(f); From 8a29c2803c1852683bdbfc4bf5ff170b92b0ce91 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Jun 2018 07:04:39 -0700 Subject: [PATCH 1259/1283] improvements to arithmetic preprocessing simplificaiton and axiom generation for #1683 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 129 ++++++++++++++++++++-------- src/ast/rewriter/arith_rewriter.h | 5 +- src/smt/mam.cpp | 32 ++----- src/smt/theory_arith_core.h | 28 +++++- 4 files changed, 131 insertions(+), 63 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 9824884a4..379020331 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -800,52 +800,105 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu result = m_util.mk_numeral(div(v1, v2), is_int); return BR_DONE; } - expr_ref quot(m()); - if (divides(arg1, arg2, quot)) { - result = m_util.mk_mul(quot, m_util.mk_idiv(arg1, arg1)); - return BR_REWRITE2; + if (m_util.is_numeral(arg2, v2, is_int) && v2.is_one()) { + result = arg1; + return BR_DONE; + } + if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) { + return BR_FAILED; + } + if (arg1 == arg2) { + expr_ref zero(m_util.mk_int(0), m()); + result = m().mk_ite(m().mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1)); + return BR_REWRITE3; + } + if (divides(arg1, arg2, result)) { + return BR_REWRITE_FULL; } return BR_FAILED; } -bool arith_rewriter::divides(expr* d, expr* n, expr_ref& quot) { - if (d == n) { - quot = m_util.mk_numeral(rational(1), m_util.is_int(d)); + +// +// implement div ab ac = floor( ab / ac) = floor (b / c) = div b c +// +bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) { + expr_fast_mark1 mark; + rational num_r(1), den_r(1); + expr* num_e = nullptr, *den_e = nullptr; + ptr_buffer args1, args2; + flat_mul(num, args1); + flat_mul(den, args2); + for (expr * arg : args1) { + mark.mark(arg); + if (m_util.is_numeral(arg, num_r)) num_e = arg; + } + for (expr* arg : args2) { + if (mark.is_marked(arg)) { + result = remove_divisor(arg, num, den); + return true; + } + if (m_util.is_numeral(arg, den_r)) den_e = arg; + } + rational g = gcd(num_r, den_r); + if (!g.is_one()) { + SASSERT(g.is_pos()); + // replace num_e, den_e by their gcd reduction. + for (unsigned i = 0; i < args1.size(); ++i) { + if (args1[i] == num_e) { + args1[i] = m_util.mk_numeral(num_r / g, true); + break; + } + } + for (unsigned i = 0; i < args2.size(); ++i) { + if (args2[i] == den_e) { + args2[i] = m_util.mk_numeral(den_r / g, true); + break; + } + } + + num = m_util.mk_mul(args1.size(), args1.c_ptr()); + den = m_util.mk_mul(args2.size(), args2.c_ptr()); + result = m_util.mk_idiv(num, den); return true; } - if (m_util.is_mul(n)) { - expr_ref_vector muls(m()); - muls.push_back(n); - expr* n1, *n2; - rational r1, r2; - for (unsigned i = 0; i < muls.size(); ++i) { - if (m_util.is_mul(muls[i].get(), n1, n2)) { - muls[i] = n1; - muls.push_back(n2); - --i; - } - } - if (m_util.is_numeral(d, r1) && !r1.is_zero()) { - for (unsigned i = 0; i < muls.size(); ++i) { - if (m_util.is_numeral(muls[i].get(), r2) && (r2 / r1).is_int()) { - muls[i] = m_util.mk_numeral(r2 / r1, m_util.is_int(d)); - quot = m_util.mk_mul(muls.size(), muls.c_ptr()); - return true; - } - } - } - else { - for (unsigned i = 0; i < muls.size(); ++i) { - if (d == muls[i].get()) { - muls[i] = muls.back(); - muls.pop_back(); - quot = m_util.mk_mul(muls.size(), muls.c_ptr()); - return true; - } - } + return false; +} + +expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) { + ptr_buffer args1, args2; + flat_mul(num, args1); + flat_mul(den, args2); + remove_divisor(arg, args1); + remove_divisor(arg, args2); + expr_ref zero(m_util.mk_int(0), m()); + num = args1.empty() ? m_util.mk_int(1) : m_util.mk_mul(args1.size(), args1.c_ptr()); + den = args2.empty() ? m_util.mk_int(1) : m_util.mk_mul(args2.size(), args2.c_ptr()); + return expr_ref(m().mk_ite(m().mk_eq(zero, arg), m_util.mk_idiv(zero, zero), m_util.mk_idiv(num, den)), m()); +} + +void arith_rewriter::flat_mul(expr* e, ptr_buffer& args) { + args.push_back(e); + for (unsigned i = 0; i < args.size(); ++i) { + e = args[i]; + if (m_util.is_mul(e)) { + args.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + args[i] = args.back(); + args.shrink(args.size()-1); + --i; + } + } +} + +void arith_rewriter::remove_divisor(expr* d, ptr_buffer& args) { + for (unsigned i = 0; i < args.size(); ++i) { + if (args[i] == d) { + args[i] = args.back(); + args.shrink(args.size()-1); + return; } } - return false; + UNREACHABLE(); } br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & result) { diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 65fbfb43f..fa8677941 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -95,7 +95,10 @@ class arith_rewriter : public poly_rewriter { expr_ref neg_monomial(expr * e) const; expr * mk_sin_value(rational const & k); app * mk_sqrt(rational const & k); - bool divides(expr* d, expr* n, expr_ref& quot); + bool divides(expr* d, expr* n, expr_ref& result); + expr_ref remove_divisor(expr* arg, expr* num, expr* den); + void flat_mul(expr* e, ptr_buffer& args); + void remove_divisor(expr* d, ptr_buffer& args); public: arith_rewriter(ast_manager & m, params_ref const & p = params_ref()): diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index d31cbc905..ff62dacec 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -865,9 +865,7 @@ namespace smt { That is, during execution time, the variables will be already bound */ bool all_args_are_bound_vars(app * n) { - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = n->get_arg(i); + for (expr* arg : *n) { if (!is_var(arg)) return false; if (m_vars[to_var(arg)->get_idx()] == -1) @@ -884,9 +882,7 @@ namespace smt { if (n->is_ground()) { return; } - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = n->get_arg(i); + for (expr* arg : *n) { if (is_var(arg)) { sz++; unsigned var_id = to_var(arg)->get_idx(); @@ -928,10 +924,7 @@ namespace smt { unsigned first_app_sz; unsigned first_app_num_unbound_vars; // generate first the non-BIND operations - unsigned_vector::iterator it = m_todo.begin(); - unsigned_vector::iterator end = m_todo.end(); - for (; it != end; ++it) { - unsigned reg = *it; + for (unsigned reg : m_todo) { expr * p = m_registers[reg]; SASSERT(!is_quantifier(p)); if (is_var(p)) { @@ -1249,10 +1242,7 @@ namespace smt { SASSERT(head->m_next == 0); m_seq.push_back(m_ct_manager.mk_yield(m_qa, m_mp, m_qa->get_num_decls(), reinterpret_cast(m_vars.begin()))); - ptr_vector::iterator it = m_seq.begin(); - ptr_vector::iterator end = m_seq.end(); - for (; it != end; ++it) { - instruction * curr = *it; + for (instruction * curr : m_seq) { head->m_next = curr; head = curr; } @@ -1495,10 +1485,8 @@ namespace smt { } if (num_instr > SIMPLE_SEQ_THRESHOLD || (curr != nullptr && curr->m_opcode == CHOOSE)) simple = false; - unsigned_vector::iterator it = m_to_reset.begin(); - unsigned_vector::iterator end = m_to_reset.end(); - for (; it != end; ++it) - m_registers[*it] = 0; + for (unsigned reg : m_to_reset) + m_registers[reg] = 0; return weight; } @@ -1716,11 +1704,9 @@ namespace smt { m_num_choices++; // set: head -> c1 -> c2 -> c3 -> new_child_head1 curr = head; - ptr_vector::iterator it1 = m_compatible.begin(); - ptr_vector::iterator end1 = m_compatible.end(); - for (; it1 != end1; ++it1) { - set_next(curr, *it1); - curr = *it1; + for (instruction* instr : m_compatible) { + set_next(curr, instr); + curr = instr; } set_next(curr, new_child_head1); // set: new_child_head1:CHOOSE(new_child_head2) -> i1 -> i2 -> first_child_head diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index af761eecf..a052d1f98 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -508,13 +508,14 @@ namespace smt { mk_axiom(eqz, lower, !is_numeral); mk_axiom(eqz, upper, !is_numeral); rational k; + context& ctx = get_context(); + (void)ctx; if (m_params.m_arith_enum_const_mod && m_util.is_numeral(divisor, k) && k.is_pos() && k < rational(8)) { rational j(0); #if 1 literal_buffer lits; expr_ref mod_j(m); - context& ctx = get_context(); while(j < k) { mod_j = m.mk_eq(mod, m_util.mk_numeral(j, true)); ctx.internalize(mod_j, false); @@ -542,6 +543,31 @@ namespace smt { } #endif } + if (!m_util.is_numeral(divisor)) { + // + // forall x . (or (= y 0) (= (div (* x y) y) x)) + // forall x . (=> (= y 0) (= (div (* x y) y) (div 0 0))) + // + sort* intS = m_util.mk_int(); + var_ref v(m.mk_var(0, intS), m); + app_ref mul(m_util.mk_mul(divisor, v), m); + app_ref div(m_util.mk_idiv(mul, divisor), m); + expr_ref divp1(m.mk_pattern(div), m); + app_ref mul2(m_util.mk_mul(v, divisor), m); + app_ref div2(m_util.mk_idiv(mul2, divisor), m); + expr_ref divp2(m.mk_pattern(div2), m); + expr_ref fml1(m.mk_or(m.mk_not(eqz), m.mk_eq(div, m_util.mk_idiv(zero, zero))), m); + expr_ref fml2(m.mk_or(eqz, m.mk_eq(div, v)), m); + symbol name("?x"); + expr* pats[2] = { divp1, divp2 }; + expr_ref fml(m); + fml = m.mk_forall(1, &intS, &name, fml1, 0, symbol::null, symbol::null, 2, pats, 0, nullptr); + proof_ref pr(m.mk_asserted(fml), m); + ctx.internalize_assertion(fml, pr, 0); + fml = m.mk_forall(1, &intS, &name, fml2, 0, symbol::null, symbol::null, 2, pats, 0, nullptr); + pr = m.mk_asserted(fml); + ctx.internalize_assertion(fml, pr, 0); + } } } From 9b6a99794bc394adb29b4f4347f6de8df93bda8c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Jun 2018 10:02:31 -0700 Subject: [PATCH 1260/1283] add default method for fresh fp value, try to address OsX build Signed-off-by: Nikolaj Bjorner --- cmake/modules/FindDotNetToolchain.cmake | 2 +- src/smt/theory_fpa.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/FindDotNetToolchain.cmake b/cmake/modules/FindDotNetToolchain.cmake index abc4ff21c..7f86534c3 100644 --- a/cmake/modules/FindDotNetToolchain.cmake +++ b/cmake/modules/FindDotNetToolchain.cmake @@ -39,7 +39,7 @@ if (DOTNET_CSC_EXECUTABLE) set(DOTNET_TOOLCHAIN_IS_WINDOWS TRUE) message(STATUS ".NET toolchain is Windows native") else() - message(STATUS ".NET toolchain is unknown") + message(STATUS ".NET toolchain is unknown: ${CSC_STD_OUT}") endif() endif() endif() diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 8cd01d2e9..75bcec13c 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -62,7 +62,7 @@ namespace smt { return true; } - expr * get_fresh_value(sort * s) override { NOT_IMPLEMENTED_YET(); } + expr * get_fresh_value(sort * s) override { return get_some_value(s); } void register_value(expr * n) override { /* Ignore */ } app * mk_value(mpf const & x) { From 245651305356de89c61e919257fcc747b9e6c743 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Jun 2018 10:43:51 -0700 Subject: [PATCH 1261/1283] sometimes comments are worth reading Signed-off-by: Nikolaj Bjorner --- src/smt/proto_model/proto_model.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index 493948f32..8af3af277 100644 --- a/src/smt/proto_model/proto_model.cpp +++ b/src/smt/proto_model/proto_model.cpp @@ -367,8 +367,8 @@ void proto_model::complete_partial_funcs(bool use_fresh) { // m_func_decls may be "expanded" when we invoke get_some_value. // So, we must not use iterators to traverse it. - for (func_decl* f : m_func_decls) { - complete_partial_func(f, use_fresh); + for (unsigned i = 0; i < m_func_decls.size(); ++i) { + complete_partial_func(m_func_decls.get(i), use_fresh); } } From eeba30a27756f64c1dcdbbe239d738d6427a1458 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Jun 2018 10:56:45 -0700 Subject: [PATCH 1262/1283] fix #1677 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 47 ++++++++++++++++++++++++++++++------------ src/smt/theory_seq.h | 1 + 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 3b81a35dc..d5fe54fae 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -712,12 +712,30 @@ unsigned theory_seq::find_branch_start(unsigned k) { return 0; } -bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs) { +expr_ref_vector theory_seq::expand_strings(expr_ref_vector const& es) { + expr_ref_vector ls(m); + for (expr* e : es) { + zstring s; + if (m_util.str.is_string(e, s)) { + for (unsigned i = 0; i < s.length(); ++i) { + ls.push_back(m_util.str.mk_unit(m_util.str.mk_char(s, i))); + } + } + else { + ls.push_back(e); + } + } + return ls; +} + +bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& _ls, expr_ref_vector const& _rs) { + expr_ref_vector ls = expand_strings(_ls); + expr_ref_vector rs = expand_strings(_rs); if (ls.empty()) { return false; } - expr* l = ls[0]; + expr* l = ls.get(0); if (!is_var(l)) { return false; @@ -735,9 +753,9 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re } for (; start < rs.size(); ++start) { unsigned j = start; - SASSERT(!m_util.str.is_concat(rs[j])); - SASSERT(!m_util.str.is_string(rs[j])); - if (l == rs[j]) { + SASSERT(!m_util.str.is_concat(rs.get(j))); + SASSERT(!m_util.str.is_string(rs.get(j))); + if (l == rs.get(j)) { return false; } if (!can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size() - j - 1, rs.c_ptr() + j + 1)) { @@ -752,8 +770,11 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re } bool all_units = true; - for (unsigned j = 0; all_units && j < rs.size(); ++j) { - all_units &= m_util.str.is_unit(rs[j]); + for (expr* r : rs) { + if (!m_util.str.is_unit(r)) { + all_units = false; + break; + } } if (all_units) { context& ctx = get_context(); @@ -765,20 +786,20 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re lits.push_back(~mk_eq(l, v0, false)); } } - for (unsigned i = 0; i < lits.size(); ++i) { - switch (ctx.get_assignment(lits[i])) { + for (literal lit : lits) { + switch (ctx.get_assignment(lit)) { case l_true: break; case l_false: start = 0; return true; - case l_undef: ctx.force_phase(~lits[i]); start = 0; return true; + case l_undef: ctx.force_phase(~lit); start = 0; return true; } } set_conflict(dep, lits); TRACE("seq", tout << "start: " << start << "\n"; - for (unsigned i = 0; i < lits.size(); ++i) { - ctx.display_literal_verbose(tout << lits[i] << ": ", lits[i]); + for (literal lit : lits) { + ctx.display_literal_verbose(tout << lit << ": ", lit); tout << "\n"; - ctx.display(tout, ctx.get_justification(lits[i].var())); + ctx.display(tout, ctx.get_justification(lit.var())); tout << "\n"; }); return true; diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 3cacf3326..2f7cfd2b3 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -447,6 +447,7 @@ namespace smt { void insert_branch_start(unsigned k, unsigned s); unsigned find_branch_start(unsigned k); bool find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs); + expr_ref_vector expand_strings(expr_ref_vector const& es); bool can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const; lbool assume_equality(expr* l, expr* r); From b5614bc93e09d857ee2b1b96c28240d16ffdeab7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Jun 2018 10:58:43 -0700 Subject: [PATCH 1263/1283] going Turbo Signed-off-by: Nikolaj Bjorner --- cmake/modules/FindDotNetToolchain.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/modules/FindDotNetToolchain.cmake b/cmake/modules/FindDotNetToolchain.cmake index 7f86534c3..6e8cc7610 100644 --- a/cmake/modules/FindDotNetToolchain.cmake +++ b/cmake/modules/FindDotNetToolchain.cmake @@ -33,6 +33,11 @@ if (DOTNET_CSC_EXECUTABLE) set(DOTNET_TOOLCHAIN_IS_MONO TRUE) set(DOTNET_TOOLCHAIN_IS_WINDOWS FALSE) message(STATUS ".NET toolchain is Mono") + elseif ("${CSC_STD_OUT}" MATCHES "^Turbo[ ]+C#") + set(DOTNET_DETERMINED_VENDOR TRUE) + set(DOTNET_TOOLCHAIN_IS_MONO TRUE) + set(DOTNET_TOOLCHAIN_IS_WINDOWS FALSE) + message(STATUS ".NET toolchain is Mono") elseif ("${CSC_STD_OUT}" MATCHES "^Microsoft.+Visual[ ]+C#") set(DOTNET_DETERMINED_VENDOR TRUE) set(DOTNET_TOOLCHAIN_IS_MONO FALSE) From 341f7ceb1732c8abd617b158087821c396c0c8ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Jun 2018 13:19:48 -0700 Subject: [PATCH 1264/1283] remove quantified lemmas for idiv/mod Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_core.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index a052d1f98..cbd41f08c 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -543,6 +543,10 @@ namespace smt { } #endif } +#if 0 + // e-matching is too restrictive for multiplication. + // also suffers from use-after free so formulas have to be pinned in solver. + // if (!m_util.is_numeral(divisor)) { // // forall x . (or (= y 0) (= (div (* x y) y) x)) @@ -568,6 +572,7 @@ namespace smt { pr = m.mk_asserted(fml); ctx.internalize_assertion(fml, pr, 0); } +#endif } } From 26e9321517e1ca68a1c73ccd5522ea3f14e0e1e5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Jun 2018 14:58:21 -0700 Subject: [PATCH 1265/1283] disable dot-net for osx Signed-off-by: Nikolaj Bjorner --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a3ffb221e..9ec6132b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -84,7 +84,7 @@ matrix: - os: osx osx_image: xcode8.3 # Note: Apple Clang does not support OpenMP - env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 + env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 DOTNET_BINDINGS=0 script: # Use `travis_wait` when doing LTO builds because this configuration will # have long link times during which it will not show any output which From 335d672bf1f923b8782d89da2b60339a29c742e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Jun 2018 23:23:19 -0700 Subject: [PATCH 1266/1283] fix #1675, regression in core processing in maxres Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 3 +- src/cmd_context/basic_cmds.cpp | 4 +- src/model/model.cpp | 8 +- src/model/model.h | 5 +- src/model/model_core.h | 2 +- src/model/model_implicant.cpp | 18 ++- src/model/model_smt2_pp.cpp | 5 + src/model/model_smt2_pp.h | 1 + src/muz/bmc/dl_bmc_engine.cpp | 25 ++-- src/muz/spacer/spacer_context.cpp | 6 +- src/muz/spacer/spacer_legacy_mbp.cpp | 5 +- src/muz/spacer/spacer_legacy_mev.cpp | 17 ++- src/muz/spacer/spacer_qe_project.cpp | 18 ++- src/muz/spacer/spacer_sat_answer.cpp | 7 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 2 +- src/muz/tab/tab_context.cpp | 3 +- src/nlsat/tactic/nlsat_tactic.cpp | 5 +- src/opt/maxres.cpp | 146 ++++++++------------ src/opt/maxsmt.cpp | 15 +- src/opt/opt_context.cpp | 63 ++++----- src/opt/optsmt.cpp | 2 +- src/opt/pb_sls.cpp | 10 +- src/opt/sortmax.cpp | 6 +- src/opt/wmax.cpp | 8 +- src/parsers/smt2/smt2parser.cpp | 4 +- src/qe/qe_arrays.cpp | 7 +- src/qe/qe_datatypes.cpp | 3 +- src/qe/qe_mbp.cpp | 6 +- src/qe/qsat.cpp | 20 +-- src/sat/tactic/goal2sat.cpp | 4 +- src/sat/tactic/goal2sat.h | 2 +- src/shell/opt_frontend.cpp | 6 +- src/smt/mam.cpp | 38 ++--- src/smt/smt_consequences.cpp | 7 +- src/smt/smt_implied_equalities.cpp | 2 +- src/solver/mus.cpp | 3 +- src/solver/solver.cpp | 3 +- src/tactic/generic_model_converter.cpp | 15 +- src/tactic/generic_model_converter.h | 2 +- src/tactic/horn_subsume_model_converter.cpp | 3 +- src/tactic/model_converter.cpp | 21 ++- src/tactic/model_converter.h | 2 +- src/tactic/sls/sls_engine.cpp | 35 ++--- 43 files changed, 246 insertions(+), 321 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 6318283c6..7eb7d2fdd 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -166,7 +166,8 @@ extern "C" { CHECK_IS_EXPR(t, Z3_FALSE); model * _m = to_model_ref(m); expr_ref result(mk_c(c)->m()); - _m->eval(to_expr(t), result, model_completion == Z3_TRUE); + model::scoped_model_completion _scm(*_m, model_completion == Z3_TRUE); + result = (*_m)(to_expr(t)); mk_c(c)->save_ast_trail(result.get()); *v = of_ast(result.get()); RETURN_Z3_model_eval Z3_TRUE; diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 4e5202fd8..846fb1ded 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -138,8 +138,8 @@ ATOMIC_CMD(get_assignment_cmd, "get-assignment", "retrieve assignment", { macro_decls const & _m = kv.m_value; for (auto md : _m) { if (md.m_domain.size() == 0 && ctx.m().is_bool(md.m_body)) { - expr_ref val(ctx.m()); - m->eval(md.m_body, val, true); + model::scoped_model_completion _scm(*m, true); + expr_ref val = (*m)(md.m_body); if (ctx.m().is_true(val) || ctx.m().is_false(val)) { if (first) first = false; diff --git a/src/model/model.cpp b/src/model/model.cpp index 9ac971afe..6ddf9765c 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -66,12 +66,10 @@ model * model::copy() const { return m; } -// Remark: eval is for backward compatibility. We should use model_evaluator. -bool model::eval(expr * e, expr_ref & result, bool model_completion) { - model_evaluator ev(*this); - ev.set_model_completion(model_completion); +bool model::eval_expr(expr * e, expr_ref & result, bool model_completion) { + scoped_model_completion _smc(*this, model_completion); try { - ev(e, result); + result = (*this)(e); return true; } catch (model_evaluator_exception & ex) { diff --git a/src/model/model.h b/src/model/model.h index 429e7b51a..9399be285 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -46,8 +46,7 @@ public: model * copy() const; - bool eval(func_decl * f, expr_ref & r) const { return model_core::eval(f, r); } - bool eval(expr * e, expr_ref & result, bool model_completion = false); + bool eval_expr(expr * e, expr_ref & result, bool model_completion = false); expr * get_some_value(sort * s) override; ptr_vector const & get_universe(sort * s) const override; @@ -93,8 +92,6 @@ public: m_model.set_model_completion(m_old_completion); } }; - - }; diff --git a/src/model/model_core.h b/src/model/model_core.h index 400b2fcab..3f1e92bad 100644 --- a/src/model/model_core.h +++ b/src/model/model_core.h @@ -40,7 +40,7 @@ public: virtual ~model_core(); ast_manager & get_manager() const { return m_manager; } - ast_manager& m() { return m_manager; } + ast_manager& m() const { return m_manager; } unsigned get_num_decls() const { return m_decls.size(); } func_decl * get_decl(unsigned i) const { return m_decls[i]; } diff --git a/src/model/model_implicant.cpp b/src/model/model_implicant.cpp index 0cdd80c11..375834477 100644 --- a/src/model/model_implicant.cpp +++ b/src/model/model_implicant.cpp @@ -535,9 +535,8 @@ bool model_implicant::extract_array_func_interp(expr* a, vector */ void model_implicant::eval_array_eq(app* e, expr* arg1, expr* arg2) { TRACE("pdr", tout << "array equality: " << mk_pp(e, m) << "\n";); - expr_ref v1(m), v2(m); - m_model->eval(arg1, v1); - m_model->eval(arg2, v2); + expr_ref v1 = (*m_model)(arg1); + expr_ref v2 = (*m_model)(arg2); if (v1 == v2) { set_true(e); return; @@ -587,8 +586,8 @@ void model_implicant::eval_array_eq(app* e, expr* arg1, expr* arg2) { args2.append(store[i].size()-1, store[i].c_ptr()); s1 = m_array.mk_select(args1.size(), args1.c_ptr()); s2 = m_array.mk_select(args2.size(), args2.c_ptr()); - m_model->eval(s1, w1); - m_model->eval(s2, w2); + w1 = (*m_model)(s1); + w2 = (*m_model)(s2); if (w1 == w2) { continue; } @@ -621,9 +620,9 @@ void model_implicant::eval_eq(app* e, expr* arg1, expr* arg2) { eval_array_eq(e, arg1, arg2); } else if (is_x(arg1) || is_x(arg2)) { - expr_ref eq(m), vl(m); + expr_ref eq(m); eq = m.mk_eq(arg1, arg2); - m_model->eval(eq, vl); + expr_ref vl = (*m_model)(eq); if (m.is_true(vl)) { set_bool(e, true); } @@ -837,8 +836,7 @@ bool model_implicant::check_model(ptr_vector const& formulas) { eval_basic(curr); } else { - expr_ref vl(m); - m_model->eval(curr, vl); + expr_ref vl = (*m_model)(curr); assign_value(curr, vl); } @@ -884,7 +882,7 @@ expr_ref model_implicant::eval(model_ref& model, func_decl* d) { expr_ref model_implicant::eval(model_ref& model, expr* e) { expr_ref result(m); m_model = model; - VERIFY(m_model->eval(e, result, true)); + result = (*m_model)(e); if (m_array.is_array(e)) { vector stores; expr_ref_vector args(m); diff --git a/src/model/model_smt2_pp.cpp b/src/model/model_smt2_pp.cpp index 152cbc8d3..bc1900ba7 100644 --- a/src/model/model_smt2_pp.cpp +++ b/src/model/model_smt2_pp.cpp @@ -302,3 +302,8 @@ void model_smt2_pp(std::ostream & out, ast_manager & m, model_core const & md, u pp_consts(out, *(ctx.get()), md, indent); pp_funs(out, *(ctx.get()), md, indent); } + +std::ostream& operator<<(std::ostream& out, model_core const& m) { + model_smt2_pp(out, m.m(), m, 0); + return out; +} diff --git a/src/model/model_smt2_pp.h b/src/model/model_smt2_pp.h index c43e26ca6..b38bd631d 100644 --- a/src/model/model_smt2_pp.h +++ b/src/model/model_smt2_pp.h @@ -25,5 +25,6 @@ Revision History: void model_smt2_pp(std::ostream & out, ast_printer_context & ctx, model_core const & m, unsigned indent); void model_smt2_pp(std::ostream & out, ast_manager & m, model_core const & md, unsigned indent); +std::ostream& operator<<(std::ostream& out, model_core const& m); #endif diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index c7657a0d7..97432f544 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -228,10 +228,9 @@ namespace datalog { expr_ref eval_q(model_ref& model, func_decl* f, unsigned i) { func_decl_ref fn = mk_q_func_decl(f); - expr_ref t(m), result(m); + expr_ref t(m); t = m.mk_app(mk_q_func_decl(f).get(), mk_q_num(i)); - model->eval(t, result); - return result; + return (*model)(t); } expr_ref eval_q(model_ref& model, expr* t, unsigned i) { @@ -240,8 +239,7 @@ namespace datalog { num = mk_q_num(i); expr* nums[1] = { num }; vs(t, 1, nums, tmp); - model->eval(tmp, result); - return result; + return (*model)(tmp); } lbool get_model() { @@ -258,7 +256,7 @@ namespace datalog { func_decl* pred = b.m_query_pred; dl_decl_util util(m); T = m.mk_const(symbol("T"), mk_index_sort()); - md->eval(T, vl); + vl = (*md)(T); VERIFY (m_bv.is_numeral(vl, num, bv_size)); SASSERT(num.is_unsigned()); level = num.get_unsigned(); @@ -505,8 +503,7 @@ namespace datalog { func_decl_ref rule_i = mk_level_rule(pred, i, level); TRACE("bmc", rls[i]->display(b.m_ctx, tout << "Checking rule " << mk_pp(rule_i, m) << " ");); prop_r = m.mk_app(rule_i, prop->get_num_args(), prop->get_args()); - md->eval(prop_r, prop_v); - if (m.is_true(prop_v)) { + if (md->is_true(prop_r)) { r = rls[i]; break; } @@ -527,8 +524,7 @@ namespace datalog { return pr; } for (unsigned j = 0; j < sub.size(); ++j) { - md->eval(sub[j].get(), tmp); - sub[j] = tmp; + sub[j] = (*md)(sub[j].get()); } svector > positions; @@ -1062,8 +1058,7 @@ namespace datalog { return pr; } for (unsigned j = 0; j < sub.size(); ++j) { - md->eval(sub[j].get(), tmp); - sub[j] = tmp; + sub[j] = (*md)(sub.get(j)); } rule_ref rl(b.m_ctx.get_rule_manager()); rl = rules[i]; @@ -1116,7 +1111,7 @@ namespace datalog { bool check_model(model_ref& md, expr* trace) { expr_ref trace_val(m), eq(m); - md->eval(trace, trace_val); + trace_val = (*md)(trace); eq = m.mk_eq(trace, trace_val); b.m_solver.push(); b.m_solver.assert_expr(eq); @@ -1135,8 +1130,8 @@ namespace datalog { void mk_answer(model_ref& md, expr_ref& trace, expr_ref& path) { IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0);); - md->eval(trace, trace); - md->eval(path, path); + 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"; diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index b917f8cc1..f3ceee9c8 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1398,7 +1398,7 @@ bool pred_transformer::is_ctp_blocked(lemma *lem) { expr_ref lemmas(m), val(m); lemmas = pt.get_formulas(lem->level()); pm.formula_n2o(lemmas.get(), lemmas, i); - if (ctp->eval(lemmas, val) && m.is_false(val)) {return false;} + if (ctp->is_false(lemmas)) return false; } // lem is blocked by ctp since none of the lemmas at the previous @@ -2440,13 +2440,13 @@ bool context::validate() get_rule_manager (). display_smt2(r, tout) << "\n";); - model->eval(r.get_head(), tmp); + tmp = (*model)(r.get_head()); expr_ref_vector fmls(m); fmls.push_back(m.mk_not(tmp)); unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < utsz; ++j) { - model->eval(r.get_tail(j), tmp); + tmp = (*model)(r.get_tail(j)); fmls.push_back(tmp); } for (unsigned j = utsz; j < tsz; ++j) { diff --git a/src/muz/spacer/spacer_legacy_mbp.cpp b/src/muz/spacer/spacer_legacy_mbp.cpp index d52228d8a..76b543f04 100644 --- a/src/muz/spacer/spacer_legacy_mbp.cpp +++ b/src/muz/spacer/spacer_legacy_mbp.cpp @@ -71,10 +71,11 @@ void qe_project(ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& expr_substitution sub(m); proof_ref pr(m.mk_asserted(m.mk_true()), m); expr_ref bval(m); + model::scoped_model_completion _scm(*M, true); for (unsigned i = 0; i < vars.size(); i++) { if (m.is_bool(vars.get(i))) { // obtain the interpretation of the ith var using model completion - VERIFY(M->eval(vars.get(i), bval, true)); + bval = (*M)(vars.get(i)); sub.insert(vars.get(i), bval, pr); } else { arith_vars.push_back(vars.get(i)); @@ -106,7 +107,7 @@ void qe_project(ast_manager& m, app_ref_vector& vars, expr_ref& fml, model_ref& tout << "Projected arith vars:\n" << mk_pp(fml, m) << "\n"; ); } - SASSERT(M->eval(fml, bval, true) && m.is_true(bval)); // M |= fml + SASSERT(M->is_true(fml)); vars.reset(); vars.append(arith_vars); } diff --git a/src/muz/spacer/spacer_legacy_mev.cpp b/src/muz/spacer/spacer_legacy_mev.cpp index 5feaed1fa..b62b24b0d 100644 --- a/src/muz/spacer/spacer_legacy_mev.cpp +++ b/src/muz/spacer/spacer_legacy_mev.cpp @@ -461,8 +461,8 @@ void model_evaluator::eval_array_eq(app* e, expr* arg1, expr* arg2) { TRACE("old_spacer", tout << "array equality: " << mk_pp(e, m) << "\n";); expr_ref v1(m), v2(m); - m_model->eval(arg1, v1); - m_model->eval(arg2, v2); + v1 = (*m_model)(arg1); + v2 = (*m_model)(arg2); if (v1 == v2) { set_true(e); return; @@ -510,8 +510,8 @@ void model_evaluator::eval_array_eq(app* e, expr* arg1, expr* arg2) args2.append(store[i].size() - 1, store[i].c_ptr()); s1 = m_array.mk_select(args1.size(), args1.c_ptr()); s2 = m_array.mk_select(args2.size(), args2.c_ptr()); - m_model->eval(s1, w1); - m_model->eval(s2, w2); + w1 = (*m_model)(s1); + w2 = (*m_model)(s2); if (w1 == w2) { continue; } @@ -729,7 +729,7 @@ void model_evaluator::eval_fmls(ptr_vector const& formulas) eval_basic(curr); } else { expr_ref vl(m); - m_model->eval(curr, vl); + vl = eval(m_model, curr); assign_value(curr, vl); } @@ -798,11 +798,10 @@ expr_ref model_evaluator::eval(const model_ref& model, func_decl* d) return result; } -expr_ref model_evaluator::eval(const model_ref& model, expr* e) -{ - expr_ref result(m); +expr_ref model_evaluator::eval(const model_ref& model, expr* e){ m_model = model.get(); - VERIFY(m_model->eval(e, result, true)); + model::scoped_model_completion _scm(m_model, true); + expr_ref result = (*m_model)(e); if (m_array.is_array(e)) { vector stores; expr_ref_vector args(m); diff --git a/src/muz/spacer/spacer_qe_project.cpp b/src/muz/spacer/spacer_qe_project.cpp index 1bf670a7a..ed5a0215c 100644 --- a/src/muz/spacer/spacer_qe_project.cpp +++ b/src/muz/spacer/spacer_qe_project.cpp @@ -378,7 +378,7 @@ namespace spacer_qe { rational r; cx = mk_mul (c, m_var->x()); cxt = mk_add (cx, t); - VERIFY(mdl.eval(cxt, val, true)); + val = mdl(cxt); VERIFY(a.is_numeral(val, r)); SASSERT (r > rational::zero () || r < rational::zero ()); if (r > rational::zero ()) { @@ -464,8 +464,7 @@ namespace spacer_qe { m_strict.reset(); m_eq.reset (); - expr_ref var_val (m); - VERIFY (mdl.eval (m_var->x(), var_val, true)); + expr_ref var_val = mdl(m_var->x()); unsigned eq_idx = lits.size (); for (unsigned i = 0; i < lits.size(); ++i) { @@ -492,7 +491,7 @@ namespace spacer_qe { rational r; cx = mk_mul (c, m_var->x()); cxt = mk_add (cx, t); - VERIFY(mdl.eval(cxt, val, true)); + val = mdl(cxt); VERIFY(a.is_numeral(val, r)); if (is_eq) { @@ -738,7 +737,7 @@ namespace spacer_qe { rational r; cx = mk_mul (m_coeffs[max_t], m_var->x()); cxt = mk_add (cx, m_terms.get (max_t)); - VERIFY(mdl.eval(cxt, val, true)); + val = mdl(cxt); VERIFY(a.is_numeral(val, r)); // get the offset from the smallest/largest possible value for x @@ -796,13 +795,13 @@ namespace spacer_qe { // evaluate x in mdl rational r_x; - VERIFY(mdl.eval(m_var->x (), val, true)); + val = mdl(m_var->x ()); VERIFY(a.is_numeral (val, r_x)); for (unsigned i = 0; i < m_terms.size(); ++i) { rational const& ac = m_coeffs[i]; if (!m_eq[i] && ac.is_pos() == do_pos) { - VERIFY(mdl.eval(m_terms.get (i), val, true)); + val = mdl(m_terms.get (i)); VERIFY(a.is_numeral(val, r)); r /= abs(ac); // skip the literal if false in the model @@ -955,8 +954,7 @@ namespace spacer_qe { new_var = m.mk_fresh_const ("mod_var", d->get_range ()); eqs.push_back (m.mk_eq (new_var, new_term)); // obtain value of new_term in mdl - expr_ref val (m); - mdl.eval (new_term, val, true); + expr_ref val = mdl(new_term); // use the variable from now on new_term = new_var; changed = true; @@ -1413,7 +1411,7 @@ namespace spacer_qe { app_ref val_const (m.mk_fresh_const ("sel", val_sort), m); m_aux_vars.push_back (val_const); // extend M to include val_const - expr_ref val (m); + expr_ref val(m); m_mev.eval (*M, a_new, val); M->register_decl (val_const->get_decl (), val); // add equality diff --git a/src/muz/spacer/spacer_sat_answer.cpp b/src/muz/spacer/spacer_sat_answer.cpp index 09553de89..30241230f 100644 --- a/src/muz/spacer/spacer_sat_answer.cpp +++ b/src/muz/spacer/spacer_sat_answer.cpp @@ -65,10 +65,11 @@ proof_ref ground_sat_answer_op::operator()(pred_transformer &query) { SASSERT(res == l_true); model_ref mdl; m_solver->get_model(mdl); + model::scoped_model_completion _scm(mdl, true); for (unsigned i = 0, sz = query.sig_size(); i < sz; ++i) { expr_ref arg(m), val(m); arg = m.mk_const(m_pm.o2n(query.sig(i), 0)); - mdl->eval(arg, val, true); + val = (*mdl)(arg); qsubst.push_back(val); } } @@ -141,11 +142,13 @@ void ground_sat_answer_op::mk_children(frame &fr, vector &todo) { void ground_sat_answer_op::mk_child_subst_from_model(func_decl *pred, unsigned j, model_ref &mdl, expr_ref_vector &subst) { + + model::scoped_model_completion _scm(mdl, true); pred_transformer &pt = m_ctx.get_pred_transformer(pred); for (unsigned i = 0, sz = pt.sig_size(); i < sz; ++i) { expr_ref arg(m), val(m); arg = m.mk_const(m_pm.o2o(pt.sig(i), 0, j)); - mdl->eval(arg, val, true); + val = (*mdl)(arg); subst.push_back(val); } } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index b96ef3037..8fb5feeef 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -472,7 +472,7 @@ namespace spacer { for (unsigned j = 0; j < matrix.num_cols(); ++j) { expr_ref evaluation(m); - model.get()->eval(bounded_vectors[j][k].get(), evaluation, false); + evaluation = (*model)(bounded_vectors[j][k].get()); if (!util.is_zero(evaluation)) { coeff_lits.push_back(std::make_pair(rational(1), ordered_basis[j])); } diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index 2fb329ff4..7200b3522 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -693,13 +693,12 @@ namespace tb { m_solver.assert_expr(postcond); lbool is_sat = m_solver.check(); if (is_sat == l_true) { - expr_ref tmp(m); expr* n; model_ref mdl; m_solver.get_model(mdl); for (unsigned i = 0; i < fmls.size(); ++i) { n = fmls[i].get(); - if (mdl->eval(n, tmp) && m.is_false(tmp)) { + if (mdl->is_false(n)) { m_refs.push_back(normalize(n)); m_sat_lits.insert(m_refs.back()); } diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 1392df3f6..5e536bbe6 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -83,9 +83,8 @@ class nlsat_tactic : public tactic { bool eval_model(model& model, goal& g) { unsigned sz = g.size(); for (unsigned i = 0; i < sz; i++) { - expr_ref val(m); - if (model.eval(g.form(i), val) && !m.is_true(val)) { - TRACE("nlsat", tout << mk_pp(g.form(i), m) << " -> " << val << "\n";); + if (!model.is_true(g.form(i))) { + TRACE("nlsat", tout << mk_pp(g.form(i), m) << " -> " << model(g.form(i)) << "\n";); return false; } } diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 6c71c6238..912a64038 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -175,10 +175,11 @@ public: void new_assumption(expr* e, rational const& w) { IF_VERBOSE(13, verbose_stream() << "new assumption " << mk_pp(e, m) << " " << w << "\n";); - TRACE("opt", tout << "insert: " << mk_pp(e, m) << " : " << w << "\n";); m_asm2weight.insert(e, w); m_asms.push_back(e); m_trail.push_back(e); + TRACE("opt", tout << "insert: " << mk_pp(e, m) << " : " << w << "\n"; + tout << m_asms << " " << "\n"; ); } void trace() { @@ -192,7 +193,7 @@ public: trace(); if (is_sat != l_true) return is_sat; while (m_lower < m_upper) { - TRACE("opt", + TRACE("opt_verbose", display_vec(tout, m_asms); s().display(tout); tout << "\n"; @@ -204,7 +205,12 @@ public: } switch (is_sat) { case l_true: - SASSERT(is_true(m_asms)); + CTRACE("opt", !m_model->is_true(m_asms), + tout << *m_model; + tout << "assumptions: "; + for (expr* a : m_asms) tout << mk_pp(a, m) << " -> " << (*m_model)(a) << " "; + tout << "\n";); + SASSERT(m_model->is_true(m_asms)); found_optimum(); return l_true; case l_false: @@ -276,8 +282,7 @@ public: /** Give preference to cores that have large minmal values. */ - sort_assumptions(asms); - + sort_assumptions(asms); m_last_index = std::min(m_last_index, asms.size()-1); m_last_index = 0; unsigned index = m_last_index>0?m_last_index-1:0; @@ -290,8 +295,6 @@ public: index = next_index(asms, index); } first = false; - IF_VERBOSE(3, verbose_stream() << "hill climb " << index << "\n";); - // IF_VERBOSE(3, verbose_stream() << "weight: " << get_weight(asms[0].get()) << " " << get_weight(asms[index-1].get()) << " num soft: " << index << "\n";); m_last_index = index; is_sat = check_sat(index, asms.c_ptr()); } @@ -307,8 +310,9 @@ public: if (r == l_true) { model_ref mdl; s().get_model(mdl); + TRACE("opt", tout << *mdl;); if (mdl.get()) { - update_assignment(mdl.get()); + update_assignment(mdl); } } return r; @@ -318,7 +322,7 @@ public: IF_VERBOSE(1, verbose_stream() << "found optimum\n";); m_lower.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = is_true(m_soft[i]); + m_assignment[i] = m_model->is_true(m_soft[i]); if (!m_assignment[i]) { m_lower += m_weights[i]; } @@ -347,7 +351,6 @@ public: lbool get_cores(vector& cores) { // assume m_s is unsat. lbool is_sat = l_false; - expr_ref_vector asms(m_asms); cores.reset(); exprs core; while (is_sat == l_false) { @@ -370,6 +373,10 @@ public: m_lower = m_upper; return l_true; } + // 1. remove all core literals from m_asms + // 2. re-add literals of higher weight than min-weight. + // 3. 'core' stores the core literals that are split afterwards + remove_soft(core, m_asms); split_core(core); cores.push_back(core); if (core.size() >= m_max_core_size) { @@ -378,15 +385,14 @@ public: if (cores.size() >= m_max_num_cores) { break; } - remove_soft(core, asms); - is_sat = check_sat_hill_climb(asms); + is_sat = check_sat_hill_climb(m_asms); } TRACE("opt", tout << "num cores: " << cores.size() << "\n"; for (auto const& c : cores) { display_vec(tout, c); } - tout << "num satisfying: " << asms.size() << "\n";); + tout << "num satisfying: " << m_asms.size() << "\n";); return is_sat; } @@ -394,7 +400,7 @@ public: void get_current_correction_set(exprs& cs) { model_ref mdl; s().get_model(mdl); - update_assignment(mdl.get()); + update_assignment(mdl); get_current_correction_set(mdl.get(), cs); } @@ -402,10 +408,10 @@ public: cs.reset(); if (!mdl) return; for (expr* a : m_asms) { - if (is_false(mdl, a)) { + if (mdl->is_false(a)) { cs.push_back(a); } - TRACE("opt", expr_ref tmp(m); mdl->eval(a, tmp, true); tout << mk_pp(a, m) << ": " << tmp << "\n";); + // TRACE("opt", tout << mk_pp(a, m) << ": " << (*mdl)(a) << "\n";); } TRACE("opt", display_vec(tout << "new correction set: ", cs);); } @@ -444,7 +450,7 @@ public: ++m_stats.m_num_cs; expr_ref fml(m), tmp(m); TRACE("opt", display_vec(tout << "corr_set: ", corr_set);); - remove_core(corr_set); + remove_soft(corr_set, m_asms); rational w = split_core(corr_set); cs_max_resolve(corr_set, w); IF_VERBOSE(2, verbose_stream() << "(opt.maxres.correction-set " << corr_set.size() << ")\n";); @@ -484,18 +490,13 @@ public: void update_model(expr* def, expr* value) { SASSERT(is_uninterp_const(def)); if (m_csmodel) { - expr_ref val(m); - SASSERT(m_csmodel.get()); - if (m_csmodel->eval(value, val, true)) { - m_csmodel->register_decl(to_app(def)->get_decl(), val); - } + m_csmodel->register_decl(to_app(def)->get_decl(), (*m_csmodel)(value)); } } void process_unsat(exprs const& core) { IF_VERBOSE(3, verbose_stream() << "(maxres cs model valid: " << (m_csmodel.get() != nullptr) << " cs size:" << m_correction_set_size << " core: " << core.size() << ")\n";); expr_ref fml(m); - remove_core(core); SASSERT(!core.empty()); rational w = core_weight(core); TRACE("opt", display_vec(tout << "minimized core: ", core);); @@ -536,7 +537,7 @@ public: w = m_mus.get_best_model(mdl); } if (mdl.get() && w < m_upper) { - update_assignment(mdl.get()); + update_assignment(mdl); } return nullptr != mdl.get(); } @@ -707,10 +708,11 @@ public: s().assert_expr(fml); } - void update_assignment(model* mdl) { + void update_assignment(model_ref & mdl) { + mdl->set_model_completion(true); unsigned correction_set_size = 0; for (expr* a : m_asms) { - if (is_false(mdl, a)) { + if (mdl->is_false(a)) { ++correction_set_size; } } @@ -719,41 +721,45 @@ public: m_correction_set_size = correction_set_size; } + TRACE("opt", tout << *mdl;); + rational upper(0); - expr_ref tmp(m); + unsigned i = 0; for (expr* s : m_soft) { - if (!is_true(mdl, s)) { + TRACE("opt", tout << mk_pp(s, m) << ": " << (*mdl)(s) << " " << m_weights[i] << "\n";); + if (!mdl->is_true(s)) { upper += m_weights[i]; } ++i; } if (upper > m_upper) { + TRACE("opt", tout << "new upper: " << upper << " vs existing upper: " << m_upper << "\n";); return; } - if (!m_c.verify_model(m_index, mdl, upper)) { + if (!m_c.verify_model(m_index, mdl.get(), upper)) { return; } m_model = mdl; - m_c.model_updated(mdl); + m_c.model_updated(mdl.get()); - TRACE("opt", model_smt2_pp(tout << "updated model\n", m, *m_model, 0);); + TRACE("opt", tout << "updated upper: " << upper << "\nmodel\n" << *m_model;); i = 0; for (expr* s : m_soft) { - m_assignment[i++] = is_true(s); + m_assignment[i++] = m_model->is_true(s); } // DEBUG_CODE(verify_assignment();); m_upper = upper; + trace(); add_upper_bound_block(); - } void add_upper_bound_block() { @@ -769,54 +775,28 @@ public: s().assert_expr(fml); } - bool is_true(model* mdl, expr* e) { - expr_ref tmp(m); - return mdl->eval(e, tmp, true) && m.is_true(tmp); - } - - bool is_false(model* mdl, expr* e) { - expr_ref tmp(m); - return mdl->eval(e, tmp, true) && m.is_false(tmp); - } - - bool is_true(expr* e) { - return is_true(m_model.get(), e); - } - - bool is_true(expr_ref_vector const& es) { - unsigned i = 0; - for (; i < es.size() && is_true(es[i]); ++i) { } - CTRACE("opt_bug", i < es.size(), tout << mk_pp(es[i], m) << "\n"; - model_smt2_pp(tout, m, *m_model, 0);); - return i == es.size(); - } - void remove_soft(exprs const& core, expr_ref_vector& asms) { - for (unsigned i = 0; i < asms.size(); ++i) { - if (core.contains(asms[i].get())) { - asms[i] = asms.back(); - asms.pop_back(); - --i; - } - } + TRACE("opt", tout << "before remove: " << asms << "\n";); + unsigned j = 0; + for (expr* a : asms) + if (!core.contains(a)) + asms[j++] = a; + asms.shrink(j); + TRACE("opt", tout << "after remove: " << asms << "\n";); } - void remove_core(exprs const& core) { - remove_soft(core, m_asms); - } - - virtual void updt_params(params_ref& p) { - maxsmt_solver_base::updt_params(p); - opt_params _p(p); - m_hill_climb = _p.maxres_hill_climb(); - m_add_upper_bound_block = _p.maxres_add_upper_bound_block(); - m_max_num_cores = _p.maxres_max_num_cores(); - m_max_core_size = _p.maxres_max_core_size(); - m_maximize_assignment = _p.maxres_maximize_assignment(); - m_max_correction_set_size = _p.maxres_max_correction_set_size(); - m_pivot_on_cs = _p.maxres_pivot_on_correction_set(); - m_wmax = _p.maxres_wmax(); - m_dump_benchmarks = _p.dump_benchmarks(); + virtual void updt_params(params_ref& _p) { + maxsmt_solver_base::updt_params(_p); + opt_params p(_p); + m_hill_climb = p.maxres_hill_climb(); + m_add_upper_bound_block = p.maxres_add_upper_bound_block(); + m_max_num_cores = p.maxres_max_num_cores(); + m_max_core_size = p.maxres_max_core_size(); + m_maximize_assignment = p.maxres_maximize_assignment(); + m_max_correction_set_size = p.maxres_max_correction_set_size(); + m_pivot_on_cs = p.maxres_pivot_on_correction_set(); + m_wmax = p.maxres_wmax(); + m_dump_benchmarks = p.dump_benchmarks(); } lbool init_local() { @@ -828,9 +808,8 @@ public: if (is_sat != l_true) { return is_sat; } - obj_map::iterator it = new_soft.begin(), end = new_soft.end(); - for (; it != end; ++it) { - add_soft(it->m_key, it->m_value); + for (auto const& kv : new_soft) { + add_soft(kv.m_key, kv.m_value); } m_max_upper = m_upper; m_found_feasible_optimum = false; @@ -843,10 +822,7 @@ public: virtual void commit_assignment() { if (m_found_feasible_optimum) { - TRACE("opt", tout << "Committing feasible solution\n"; - tout << m_defs; - tout << m_asms; - ); + TRACE("opt", tout << "Committing feasible solution\n" << m_defs << " " << m_asms;); s().assert_expr(m_defs); s().assert_expr(m_asms); } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index fc5bd6bbb..c97b818cf 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -76,9 +76,7 @@ namespace opt { m_upper.reset(); m_assignment.reset(); for (unsigned i = 0; i < m_weights.size(); ++i) { - expr_ref val(m); - if (!m_model->eval(m_soft[i], val)) return false; - m_assignment.push_back(m.is_true(val)); + m_assignment.push_back(m.is_true(m_soft[i])); if (!m_assignment.back()) { m_upper += m_weights[i]; } @@ -232,9 +230,7 @@ namespace opt { m_msolver = nullptr; symbol const& maxsat_engine = m_c.maxsat_engine(); IF_VERBOSE(1, verbose_stream() << "(maxsmt)\n";); - TRACE("opt", tout << "maxsmt\n"; - s().display(tout); tout << "\n"; - ); + TRACE("opt_verbose", s().display(tout << "maxsmt\n") << "\n";); if (m_soft_constraints.empty() || maxsat_engine == symbol("maxres") || maxsat_engine == symbol::null) { m_msolver = mk_maxres(m_c, m_index, m_weights, m_soft_constraints); } @@ -455,10 +451,9 @@ namespace opt { maxsmt.get_model(m_model, labels); // TBD: is m_fm applied or not? unsigned j = 0; - expr_ref tmp(m); - for (unsigned i = 0; i < soft.size(); ++i) { - if (m_model->eval(soft[i].first, tmp) && m.is_true(tmp)) { - soft[j++] = soft[i]; + for (auto const& p : soft) { + if (m_model->is_true(p.first)) { + soft[j++] = p; } } soft.shrink(j); diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 37dbd0817..af28d2254 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -341,6 +341,7 @@ namespace opt { void context::fix_model(model_ref& mdl) { if (mdl && !m_model_fixed.contains(mdl.get())) { + TRACE("opt", tout << "fix-model\n";); (*m_fm)(mdl); apply(m_model_converter, mdl); m_model_fixed.push_back(mdl.get()); @@ -350,7 +351,7 @@ namespace opt { void context::get_model_core(model_ref& mdl) { mdl = m_model; fix_model(mdl); - TRACE("opt", model_smt2_pp(tout, m, *mdl.get(), 0);); + TRACE("opt", tout << *mdl;); } void context::get_box_model(model_ref& mdl, unsigned index) { @@ -502,7 +503,8 @@ namespace opt { case O_MINIMIZE: is_ge = !is_ge; case O_MAXIMIZE: - if (mdl->eval(obj.m_term, val, true) && is_numeral(val, k)) { + val = (*mdl)(obj.m_term); + if (is_numeral(val, k)) { if (is_ge) { result = mk_ge(obj.m_term, val); } @@ -522,7 +524,7 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { terms.push_back(obj.m_terms[i]); coeffs.push_back(obj.m_weights[i]); - if (mdl->eval(obj.m_terms[i], val, true) && m.is_true(val)) { + if (mdl->is_true(obj.m_terms[i])) { k += obj.m_weights[i]; } else { @@ -1036,7 +1038,7 @@ namespace opt { buffer << prefix << (m_model_counter++) << ".smt2"; std::ofstream out(buffer.str()); if (out) { - model_smt2_pp(out, m, *mdl, 0); + out << *mdl; out.close(); } } @@ -1052,11 +1054,7 @@ namespace opt { expr_ref val(m); model_ref mdl = md->copy(); fix_model(mdl); - - if (!mdl->eval(term, val, true)) { - TRACE("opt", tout << "Term does not evaluate " << term << "\n";); - return false; - } + val = (*mdl)(term); unsigned bvsz; if (!m_arith.is_numeral(val, r) && !m_bv.is_numeral(val, r, bvsz)) { TRACE("opt", tout << "model does not evaluate objective to a value\n";); @@ -1195,9 +1193,9 @@ namespace opt { rational r; switch(obj.m_type) { case O_MINIMIZE: { - bool evaluated = m_model->eval(obj.m_term, val, true); - TRACE("opt", tout << obj.m_term << " " << val << " " << evaluated << " " << is_numeral(val, r) << "\n";); - if (evaluated && is_numeral(val, r)) { + val = (*m_model)(obj.m_term); + TRACE("opt", tout << obj.m_term << " " << val << " " << is_numeral(val, r) << "\n";); + if (is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); TRACE("opt", tout << "adjusted value: " << val << "\n";); if (is_lower) { @@ -1210,9 +1208,9 @@ namespace opt { break; } case O_MAXIMIZE: { - bool evaluated = m_model->eval(obj.m_term, val, true); + val = (*m_model)(obj.m_term); TRACE("opt", tout << obj.m_term << " " << val << "\n";); - if (evaluated && is_numeral(val, r)) { + if (is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); TRACE("opt", tout << "adjusted value: " << val << "\n";); if (is_lower) { @@ -1227,15 +1225,10 @@ namespace opt { case O_MAXSMT: { bool ok = true; for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { - bool evaluated = m_model->eval(obj.m_terms[j], val, true); + val = (*m_model)(obj.m_terms[j]); TRACE("opt", tout << mk_pp(obj.m_terms[j], m) << " " << val << "\n";); - if (evaluated) { - if (!m.is_true(val)) { - r += obj.m_weights[j]; - } - } - else { - ok = false; + if (!m.is_true(val)) { + r += obj.m_weights[j]; } } if (ok) { @@ -1485,7 +1478,7 @@ namespace opt { } if (is_internal && mc) { - mc->collect(visitor); + mc->set_env(&visitor); } param_descrs descrs; @@ -1531,7 +1524,9 @@ namespace opt { if (is_internal && mc) { mc->display(out); } - + if (is_internal && mc) { + mc->set_env(nullptr); + } out << "(check-sat)\n"; return out.str(); } @@ -1545,7 +1540,7 @@ namespace opt { model_ref mdl; get_model(mdl); for (expr * f : fmls) { - if (!mdl->eval(f, tmp) || !m.is_true(tmp)) { + if (!mdl->is_true(f)) { //IF_VERBOSE(0, m_fm->display(verbose_stream() << "fm\n")); IF_VERBOSE(0, m_model_converter->display(verbose_stream() << "mc\n")); IF_VERBOSE(0, verbose_stream() << "Failed to validate " << mk_pp(f, m) << "\n" << tmp << "\n"); @@ -1559,18 +1554,14 @@ namespace opt { void context::validate_maxsat(symbol const& id) { maxsmt& ms = *m_maxsmts.find(id); TRACE("opt", tout << "Validate: " << id << "\n";); - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; + for (objective const& obj : m_objectives) { if (obj.m_id == id && obj.m_type == O_MAXSMT) { SASSERT(obj.m_type == O_MAXSMT); rational value(0); expr_ref val(m); for (unsigned i = 0; i < obj.m_terms.size(); ++i) { - bool evaluated = m_model->eval(obj.m_terms[i], val); - SASSERT(evaluated); - CTRACE("opt", evaluated && !m.is_true(val) && !m.is_false(val), tout << mk_pp(obj.m_terms[i], m) << " " << val << "\n";); - CTRACE("opt", !evaluated, tout << mk_pp(obj.m_terms[i], m) << "\n";); - if (evaluated && !m.is_true(val)) { + auto const& t = obj.m_terms[i]; + if (!m_model->is_true(t)) { value += obj.m_weights[i]; } // TBD: check that optimal was not changed. @@ -1595,14 +1586,13 @@ namespace opt { if (m_optsmt.objective_is_model_valid(obj.m_index) && n.get_infinity().is_zero() && n.get_infinitesimal().is_zero() && - m_model->eval(obj.m_term, val) && - is_numeral(val, r1)) { + is_numeral((*m_model)(obj.m_term), r1)) { rational r2 = n.get_rational(); if (obj.m_type == O_MINIMIZE) { r1.neg(); } CTRACE("opt", r1 != r2, tout << obj.m_term << " evaluates to " << r1 << " but has objective " << r2 << "\n";); - CTRACE("opt", r1 != r2, model_smt2_pp(tout, m, *m_model, 0);); + CTRACE("opt", r1 != r2, tout << *m_model;); SASSERT(r1 == r2); } break; @@ -1610,8 +1600,7 @@ namespace opt { case O_MAXSMT: { rational value(0); for (unsigned i = 0; i < obj.m_terms.size(); ++i) { - bool evaluated = m_model->eval(obj.m_terms[i], val); - if (evaluated && !m.is_true(val)) { + if (!m_model->is_true(obj.m_terms[i])) { value += obj.m_weights[i]; } // TBD: check that optimal was not changed. diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 702702ef4..a461d4a22 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -318,7 +318,7 @@ namespace opt { m_s->get_labels(m_labels); for (unsigned i = 0; i < ors.size(); ++i) { expr_ref tmp(m); - if (m_model->eval(ors[i].get(), tmp) && m.is_true(tmp)) { + if (m_model->is_true(ors[i].get())) { m_lower[i] = m_upper[i]; ors[i] = m.mk_false(); disj[i] = m.mk_false(); diff --git a/src/opt/pb_sls.cpp b/src/opt/pb_sls.cpp index e28c3cd3d..9054e2b00 100644 --- a/src/opt/pb_sls.cpp +++ b/src/opt/pb_sls.cpp @@ -179,7 +179,7 @@ namespace smt { m_orig_model = mdl; for (unsigned i = 0; i < m_var2decl.size(); ++i) { expr_ref tmp(m); - m_assignment[i] = mdl->eval(m_var2decl[i], tmp) && m.is_true(tmp); + m_assignment[i] = mdl->is_true(m_var2decl[i]); } } @@ -343,10 +343,7 @@ namespace smt { for (unsigned i = 0; i < m_clauses.size(); ++i) { if (!eval(m_clauses[i])) { m_hard_false.insert(i); - expr_ref tmp(m); - if (!m_orig_model->eval(m_orig_clauses[i].get(), tmp)) { - return; - } + expr_ref tmp = (*m_orig_model)(m_orig_clauses[i].get()); IF_VERBOSE(0, verbose_stream() << "original evaluation: " << tmp << "\n"; verbose_stream() << mk_pp(m_orig_clauses[i].get(), m) << "\n"; @@ -521,14 +518,13 @@ namespace smt { literal mk_aux_literal(expr* f) { unsigned var; - expr_ref tmp(m); if (!m_decl2var.find(f, var)) { var = m_hard_occ.size(); SASSERT(m_var2decl.size() == var); SASSERT(m_soft_occ.size() == var); m_hard_occ.push_back(unsigned_vector()); m_soft_occ.push_back(unsigned_vector()); - m_assignment.push_back(m_orig_model->eval(f, tmp) && m.is_true(tmp)); + m_assignment.push_back(m_orig_model->is_true(f)); m_decl2var.insert(f, var); m_var2decl.push_back(f); } diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 9c45e42a2..6e7e6ec78 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -73,8 +73,7 @@ namespace opt { unsigned first = 0; it = soft.begin(); for (; it != end; ++it) { - expr_ref tmp(m); - if (m_model->eval(it->m_key, tmp) && m.is_true(tmp)) { + if (m_model->is_true(it->m_key)) { unsigned n = it->m_value.get_unsigned(); while (n > 0) { s().assert_expr(out[first]); @@ -121,8 +120,7 @@ namespace opt { } bool is_true(expr* e) { - expr_ref tmp(m); - return m_model->eval(e, tmp) && m.is_true(tmp); + return m_model->is_true(e); } // definitions used for sorting network diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 513c68d6e..97231f69e 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -120,8 +120,7 @@ namespace opt { } bool is_true(expr* e) { - expr_ref tmp(m); - return m_model->eval(e, tmp) && m.is_true(tmp); + return m_model->is_true(e); } void update_assignment() { @@ -307,9 +306,8 @@ namespace opt { } void update_model(expr* def, expr* value) { - expr_ref val(m); - if (m_model && m_model->eval(value, val, true)) { - m_model->register_decl(to_app(def)->get_decl(), val); + if (m_model) { + m_model->register_decl(to_app(def)->get_decl(), (*m_model)(value)); } } diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 9276b60cd..016c6f4e5 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -2611,8 +2611,8 @@ namespace smt2 { expr ** expr_it = expr_stack().c_ptr() + spos; expr ** expr_end = expr_it + m_cached_strings.size(); for (unsigned i = 0; expr_it < expr_end; expr_it++, i++) { - expr_ref v(m()); - md->eval(*expr_it, v, true); + model::scoped_model_completion _scm(md, true); + expr_ref v = (*md)(*expr_it); if (i > 0) m_ctx.regular_stream() << "\n "; m_ctx.regular_stream() << "(" << m_cached_strings[i] << " "; diff --git a/src/qe/qe_arrays.cpp b/src/qe/qe_arrays.cpp index a4da829a0..4c81418b6 100644 --- a/src/qe/qe_arrays.cpp +++ b/src/qe/qe_arrays.cpp @@ -1181,9 +1181,8 @@ namespace qe { indices(ast_manager& m, model& model, unsigned n, expr* const* vars): m_values(m), m_vars(vars) { expr_ref val(m); - for (unsigned i = 0; i < n; ++i) { - VERIFY(model.eval(vars[i], val)); - m_values.push_back(val); + for (unsigned i = 0; i < n; ++i) { + m_values.push_back(model(vars[i])); } } }; @@ -1269,7 +1268,7 @@ namespace qe { args.push_back (s); args.append(idxs[i].m_values.size(), idxs[i].m_vars); sel = a.mk_select (args.size (), args.c_ptr ()); - VERIFY (model.eval (sel, val)); + val = model(sel); model.register_decl (var->get_decl (), val); args[0] = result; diff --git a/src/qe/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index 87ae97857..5499d638d 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -42,8 +42,7 @@ namespace qe { } bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) { - expr_ref val(m); - VERIFY(model.eval(var, val)); + expr_ref val = model(var); SASSERT(is_app(val)); TRACE("qe", tout << mk_pp(var, m) << " := " << val << "\n";); m_val = to_app(val); diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 438f1c061..78dcbfd16 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -66,7 +66,7 @@ expr_ref project_plugin::pick_equality(ast_manager& m, model& model, expr* t) { app* alit = to_app(t); for (expr * e1 : *alit) { expr *e2; - VERIFY(model.eval(e1, val)); + val = model(e1); if (val2expr.find(val, e2)) { return expr_ref(m.mk_eq(e1, e2), m); } @@ -501,7 +501,7 @@ public: expr_ref val(m); model_evaluator eval(model); for (expr * f : fmls) { - VERIFY(model.eval(f, val) && m.is_true(val)); + VERIFY(model.is_true(f)); } return true; } @@ -538,7 +538,7 @@ public: var = new_vars.back(); new_vars.pop_back(); expr_safe_replace sub(m); - VERIFY(model.eval(var, val)); + val = model(var); sub.insert(var, val); for (unsigned i = 0; i < fmls.size(); ++i) { sub(fmls[i].get(), tmp); diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 64cde4b1d..a2e8fd8b1 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -516,8 +516,8 @@ namespace qe { expr_ref val_a(m), val_b(m); expr* a = it->m_key; expr* b = it->m_value; - VERIFY(model.eval(a, val_a)); - VERIFY(model.eval(b, val_b)); + val_a = model(a); + val_b = model(b); if (val_a != val_b) { TRACE("qe", tout << mk_pp(a, m) << " := " << val_a << "\n"; @@ -1060,11 +1060,9 @@ namespace qe { } bool validate_assumptions(model& mdl, expr_ref_vector const& core) { - for (unsigned i = 0; i < core.size(); ++i) { - expr_ref val(m); - VERIFY(mdl.eval(core[i], val)); - if (!m.is_true(val)) { - TRACE("qe", tout << "component of core is not true: " << mk_pp(core[i], m) << "\n";); + for (expr* c : core) { + if (!mdl.is_true(c)) { + TRACE("qe", tout << "component of core is not true: " << mk_pp(c, m) << "\n";); return false; } } @@ -1111,14 +1109,10 @@ namespace qe { bool validate_model(model& mdl, unsigned sz, expr* const* fmls) { expr_ref val(m); for (unsigned i = 0; i < sz; ++i) { - if (!m_model->eval(fmls[i], val) && !m.canceled()) { - TRACE("qe", tout << "Formula does not evaluate in model: " << mk_pp(fmls[i], m) << "\n";); + if (!m_model->is_true(fmls[i]) && !m.canceled()) { + TRACE("qe", tout << "Formula does not evaluate to true in model: " << mk_pp(fmls[i], m) << "\n";); return false; } - if (!m.is_true(val)) { - TRACE("qe", tout << mk_pp(fmls[i], m) << " evaluates to " << val << " in model\n";); - return false; - } } return true; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 75290946a..5f0fbec16 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -968,9 +968,9 @@ model_converter* sat2goal::mc::translate(ast_translation& translator) { return result; } -void sat2goal::mc::collect(ast_pp_util& visitor) { +void sat2goal::mc::set_env(ast_pp_util* visitor) { flush_gmc(); - if (m_gmc) m_gmc->collect(visitor); + if (m_gmc) m_gmc->set_env(visitor); } void sat2goal::mc::display(std::ostream& out) { diff --git a/src/sat/tactic/goal2sat.h b/src/sat/tactic/goal2sat.h index 32b89fe5d..d86b2d7e4 100644 --- a/src/sat/tactic/goal2sat.h +++ b/src/sat/tactic/goal2sat.h @@ -92,7 +92,7 @@ public: void operator()(model_ref& md) override; void operator()(expr_ref& fml) override; model_converter* translate(ast_translation& translator) override; - void collect(ast_pp_util& visitor) override; + void set_env(ast_pp_util* visitor) override; void display(std::ostream& out) override; void get_units(obj_map& units) override; app* var2expr(sat::bool_var v) const { return m_var2expr.get(v, nullptr); } diff --git a/src/shell/opt_frontend.cpp b/src/shell/opt_frontend.cpp index 5af5bfdd7..0a2a8f4a1 100644 --- a/src/shell/opt_frontend.cpp +++ b/src/shell/opt_frontend.cpp @@ -121,10 +121,8 @@ static unsigned parse_opt(std::istream& in, opt_format f) { expr_ref_vector hard(m); opt.get_hard_constraints(hard); for (expr* h : hard) { - expr_ref tmp(m); - VERIFY(mdl->eval(h, tmp)); - if (!m.is_true(tmp)) { - std::cout << mk_pp(h, m) << " " << tmp << "\n"; + if (!mdl->is_true(h)) { + std::cout << mk_pp(h, m) << " evaluates to: " << (*mdl)(h) << "\n"; } } } diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index ff62dacec..c35a0b180 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -569,10 +569,9 @@ namespace smt { if (m_context) { ast_manager & m = m_context->get_manager(); out << "patterns:\n"; - ptr_vector::const_iterator it = m_patterns.begin(); - ptr_vector::const_iterator end = m_patterns.end(); - for (; it != end; ++it) - out << mk_pp(*it, m) << "\n"; + for (expr* p : m_patterns) { + out << mk_pp(p, m) << "\n"; + } } #endif out << "function: " << m_root_lbl->get_name(); @@ -831,10 +830,8 @@ namespace smt { void init(code_tree * t, quantifier * qa, app * mp, unsigned first_idx) { SASSERT(m_ast_manager.is_pattern(mp)); #ifdef Z3DEBUG - svector::iterator it = m_mark.begin(); - svector::iterator end = m_mark.end(); - for (; it != end; ++it) { - SASSERT(*it == NOT_CHECKED); + for (auto cm : m_mark) { + SASSERT(cm == NOT_CHECKED); } #endif m_tree = t; @@ -1711,14 +1708,12 @@ namespace smt { set_next(curr, new_child_head1); // set: new_child_head1:CHOOSE(new_child_head2) -> i1 -> i2 -> first_child_head curr = new_child_head1; - ptr_vector::iterator it2 = m_incompatible.begin(); - ptr_vector::iterator end2 = m_incompatible.end(); - for (; it2 != end2; ++it2) { + for (instruction* inc : m_incompatible) { if (curr == new_child_head1) - curr->m_next = *it2; // new_child_head1 is a new node, I don't need to save trail + curr->m_next = inc; // new_child_head1 is a new node, I don't need to save trail else - set_next(curr, *it2); - curr = *it2; + set_next(curr, inc); + curr = inc; } set_next(curr, first_child_head); // build new_child_head2:NOOP -> linearise() @@ -3353,10 +3348,7 @@ namespace smt { void update_vars(unsigned short var_id, path * p, quantifier * qa, app * mp) { paths & var_paths = m_var_paths[var_id]; bool found = false; - paths::iterator it = var_paths.begin(); - paths::iterator end = var_paths.end(); - for (; it != end; ++it) { - path * curr_path = *it; + for (path* curr_path : var_paths) { if (is_equal(p, curr_path)) found = true; func_decl * lbl1 = curr_path->m_label; @@ -3647,18 +3639,12 @@ namespace smt { TRACE("incremental_matcher", tout << "pp: plbls1: " << plbls1 << ", plbls2: " << plbls2 << "\n";); TRACE("mam_info", tout << "pp: " << plbls1.size() * plbls2.size() << "\n";); if (!plbls1.empty() && !plbls2.empty()) { - approx_set::iterator it1 = plbls1.begin(); - approx_set::iterator end1 = plbls1.end(); - for (; it1 != end1; ++it1) { + for (unsigned plbl1 : plbls1) { if (m_context.get_cancel_flag()) { break; } - unsigned plbl1 = *it1; SASSERT(plbls1.may_contain(plbl1)); - approx_set::iterator it2 = plbls2.begin(); - approx_set::iterator end2 = plbls2.end(); - for (; it2 != end2; ++it2) { - unsigned plbl2 = *it2; + for (unsigned plbl2 : plbls2) { SASSERT(plbls2.may_contain(plbl2)); unsigned n_plbl1 = plbl1; unsigned n_plbl2 = plbl2; diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 13fd9e6ea..4cb331661 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -637,15 +637,14 @@ namespace smt { model_ref mdl; for (unsigned i = 0; i < unfixed.size(); ++i) { push(); - for (unsigned j = 0; j < assumptions.size(); ++j) { - assert_expr(assumptions[j]); - } + for (expr* a : assumptions) + assert_expr(a); TRACE("context", tout << "checking unfixed: " << mk_pp(unfixed[i], m) << "\n";); lbool is_sat = check(); SASSERT(is_sat != l_false); if (is_sat == l_true) { get_model(mdl); - mdl->eval(unfixed[i], tmp); + tmp = (*mdl)(unfixed[i]); if (m.is_value(tmp)) { tmp = m.mk_not(m.mk_eq(unfixed[i], tmp)); assert_expr(tmp); diff --git a/src/smt/smt_implied_equalities.cpp b/src/smt/smt_implied_equalities.cpp index 0b944c145..9119119d3 100644 --- a/src/smt/smt_implied_equalities.cpp +++ b/src/smt/smt_implied_equalities.cpp @@ -199,7 +199,7 @@ namespace smt { for (unsigned i = 0; i < terms.size(); ++i) { expr* t = terms[i].term; - model->eval(t, vl); + vl = (*model)(t); TRACE("get_implied_equalities", tout << mk_pp(t, m) << " |-> " << mk_pp(vl, m) << "\n";); reduce_value(model, vl); if (!m.is_value(vl)) { diff --git a/src/solver/mus.cpp b/src/solver/mus.cpp index b3d6c9ad9..094b27ed3 100644 --- a/src/solver/mus.cpp +++ b/src/solver/mus.cpp @@ -332,8 +332,7 @@ struct mus::imp { m_solver.get_model(mdl); rational w; for (unsigned i = 0; i < m_soft.size(); ++i) { - mdl->eval(m_soft[i].get(), tmp); - if (!m.is_true(tmp)) { + if (!mdl->is_true(m_soft.get(i))) { w += m_weights[i]; } } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 84b5eb588..186449545 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -44,7 +44,7 @@ std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assum ast_pp_util visitor(get_manager()); model_converter_ref mc = get_model_converter(); if (mc.get()) { - mc->collect(visitor); + mc->set_env(&visitor); } visitor.collect(fmls); visitor.collect(n, assumptions); @@ -52,6 +52,7 @@ std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assum visitor.display_asserts(out, fmls, true); if (mc.get()) { mc->display(out); + mc->set_env(nullptr); } return out; } diff --git a/src/tactic/generic_model_converter.cpp b/src/tactic/generic_model_converter.cpp index 1911edf3b..0790c962a 100644 --- a/src/tactic/generic_model_converter.cpp +++ b/src/tactic/generic_model_converter.cpp @@ -114,11 +114,16 @@ model_converter * generic_model_converter::translate(ast_translation & translato return res; } -void generic_model_converter::collect(ast_pp_util& visitor) { - m_env = &visitor.env(); - for (entry const& e : m_entries) { - visitor.coll.visit_func(e.m_f); - if (e.m_def) visitor.coll.visit(e.m_def); +void generic_model_converter::set_env(ast_pp_util* visitor) { + if (!visitor) { + m_env = nullptr; + } + else { + m_env = &visitor->env(); + for (entry const& e : m_entries) { + visitor->coll.visit_func(e.m_f); + if (e.m_def) visitor->coll.visit(e.m_def); + } } } diff --git a/src/tactic/generic_model_converter.h b/src/tactic/generic_model_converter.h index d303fb2e3..a190b8525 100644 --- a/src/tactic/generic_model_converter.h +++ b/src/tactic/generic_model_converter.h @@ -68,7 +68,7 @@ public: model_converter * translate(ast_translation & translator) override; - void collect(ast_pp_util& visitor) override; + void set_env(ast_pp_util* visitor) override; void operator()(expr_ref& fml) override; diff --git a/src/tactic/horn_subsume_model_converter.cpp b/src/tactic/horn_subsume_model_converter.cpp index 0d49a769e..eeb2967f2 100644 --- a/src/tactic/horn_subsume_model_converter.cpp +++ b/src/tactic/horn_subsume_model_converter.cpp @@ -195,8 +195,7 @@ void horn_subsume_model_converter::operator()(model_ref& mr) { SASSERT(m.is_bool(body)); TRACE("mc", tout << "eval: " << h->get_name() << "\n" << body << "\n";); - expr_ref tmp(body); - mr->eval(tmp, body); + body = (*mr)(body); TRACE("mc", tout << "to:\n" << body << "\n";); diff --git a/src/tactic/model_converter.cpp b/src/tactic/model_converter.cpp index b39940366..89e2b6602 100644 --- a/src/tactic/model_converter.cpp +++ b/src/tactic/model_converter.cpp @@ -43,6 +43,16 @@ void model_converter::display_del(std::ostream& out, func_decl* f) const { } } +void model_converter::set_env(ast_pp_util* visitor) { + if (visitor) { + m_env = &visitor->env(); + } + else { + m_env = nullptr; + } +} + + void model_converter::display_add(std::ostream& out, ast_manager& m) { // default printer for converter that adds entries model_ref mdl = alloc(model, m); @@ -91,9 +101,9 @@ public: return this->translate_core(translator); } - void collect(ast_pp_util& visitor) override { - this->m_c1->collect(visitor); - this->m_c2->collect(visitor); + void set_env(ast_pp_util* visitor) override { + this->m_c1->set_env(visitor); + this->m_c2->set_env(visitor); } }; @@ -125,9 +135,8 @@ public: } void operator()(expr_ref& fml) override { - expr_ref r(m_model->get_manager()); - m_model->eval(fml, r, false); - fml = r; + model::scoped_model_completion _scm(m_model, false); + fml = (*m_model)(fml); } void get_units(obj_map& fmls) override { diff --git a/src/tactic/model_converter.h b/src/tactic/model_converter.h index cd8fb5ee3..9c5b72830 100644 --- a/src/tactic/model_converter.h +++ b/src/tactic/model_converter.h @@ -80,7 +80,7 @@ public: virtual model_converter * translate(ast_translation & translator) = 0; - virtual void collect(ast_pp_util& visitor) { m_env = &visitor.env(); } + virtual void set_env(ast_pp_util* visitor); /** \brief we are adding a formula to the context of the model converter. diff --git a/src/tactic/sls/sls_engine.cpp b/src/tactic/sls/sls_engine.cpp index 7836ab70f..f5b5ec1b2 100644 --- a/src/tactic/sls/sls_engine.cpp +++ b/src/tactic/sls/sls_engine.cpp @@ -100,36 +100,27 @@ void sls_engine::checkpoint() { } bool sls_engine::full_eval(model & mdl) { - bool res = true; - - unsigned sz = m_assertions.size(); - for (unsigned i = 0; i < sz && res; i++) { - checkpoint(); - expr_ref o(m_manager); - - if (!mdl.eval(m_assertions[i], o, true)) - exit(ERR_INTERNAL_FATAL); - - res = m_manager.is_true(o.get()); - } - - TRACE("sls", tout << "Evaluation: " << res << std::endl;); - - return res; + model::scoped_model_completion _scm(mdl, true); + for (expr* a : m_assertions) { + checkpoint(); + if (!mdl.is_true(a)) { + TRACE("sls", tout << "Evaluation: false\n";); + return false; + } + } + return true; } double sls_engine::top_score() { double top_sum = 0.0; - unsigned sz = m_assertions.size(); - for (unsigned i = 0; i < sz; i++) { - expr * e = m_assertions[i]; + for (expr* e : m_assertions) { top_sum += m_tracker.get_score(e); } TRACE("sls_top", tout << "Score distribution:"; - for (unsigned i = 0; i < sz; i++) - tout << " " << m_tracker.get_score(m_assertions[i]); - tout << " AVG: " << top_sum / (double)sz << std::endl;); + for (expr* e : m_assertions) + tout << " " << m_tracker.get_score(e); + tout << " AVG: " << top_sum / (double)m_assertions.size() << std::endl;); m_tracker.set_top_sum(top_sum); From 792bf6c10b3fba2a77001e930d1d5796f15a105d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jun 2018 08:22:15 -0700 Subject: [PATCH 1267/1283] fix tests Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 72 +++++++++++++++++++------------------------ src/opt/maxsmt.cpp | 43 ++++++++++++++------------ src/opt/maxsmt.h | 19 +++++++++--- src/opt/sortmax.cpp | 4 +-- src/opt/wmax.cpp | 5 +-- src/solver/solver.cpp | 7 +++++ src/solver/solver.h | 2 ++ src/test/qe_arith.cpp | 3 +- 8 files changed, 81 insertions(+), 74 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 912a64038..f52c56a60 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -321,10 +321,10 @@ public: void found_optimum() { IF_VERBOSE(1, verbose_stream() << "found optimum\n";); m_lower.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = m_model->is_true(m_soft[i]); - if (!m_assignment[i]) { - m_lower += m_weights[i]; + for (soft& s : m_soft) { + s.is_true = m_model->is_true(s.s); + if (!s.is_true) { + m_lower += s.weight; } } m_upper = m_lower; @@ -375,24 +375,22 @@ public: } // 1. remove all core literals from m_asms // 2. re-add literals of higher weight than min-weight. - // 3. 'core' stores the core literals that are split afterwards + // 3. 'core' stores the core literals that are + // re-encoded as assumptions, afterwards remove_soft(core, m_asms); split_core(core); cores.push_back(core); - if (core.size() >= m_max_core_size) { - break; - } - if (cores.size() >= m_max_num_cores) { - break; - } + + if (core.size() >= m_max_core_size) break; + if (cores.size() >= m_max_num_cores) break; + is_sat = check_sat_hill_climb(m_asms); } + TRACE("opt", - tout << "num cores: " << cores.size() << "\n"; - for (auto const& c : cores) { - display_vec(tout, c); - } - tout << "num satisfying: " << m_asms.size() << "\n";); + tout << "sat: " << is_sat << " num cores: " << cores.size() << "\n"; + for (auto const& c : cores) display_vec(tout, c); + tout << "num assumptions: " << m_asms.size() << "\n";); return is_sat; } @@ -411,7 +409,6 @@ public: if (mdl->is_false(a)) { cs.push_back(a); } - // TRACE("opt", tout << mk_pp(a, m) << ": " << (*mdl)(a) << "\n";); } TRACE("opt", display_vec(tout << "new correction set: ", cs);); } @@ -475,8 +472,8 @@ public: unsigned max_core_size(vector const& cores) { unsigned result = 0; - for (unsigned i = 0; i < cores.size(); ++i) { - result = std::max(cores[i].size(), result); + for (auto const& c : cores) { + result = std::max(c.size(), result); } return result; } @@ -725,13 +722,11 @@ public: rational upper(0); - unsigned i = 0; - for (expr* s : m_soft) { - TRACE("opt", tout << mk_pp(s, m) << ": " << (*mdl)(s) << " " << m_weights[i] << "\n";); - if (!mdl->is_true(s)) { - upper += m_weights[i]; + for (soft& s : m_soft) { + TRACE("opt", tout << s.s << ": " << (*mdl)(s.s) << " " << s.weight << "\n";); + if (!mdl->is_true(s.s)) { + upper += s.weight; } - ++i; } if (upper > m_upper) { @@ -748,9 +743,8 @@ public: TRACE("opt", tout << "updated upper: " << upper << "\nmodel\n" << *m_model;); - i = 0; - for (expr* s : m_soft) { - m_assignment[i++] = m_model->is_true(s); + for (soft& s : m_soft) { + s.is_true = m_model->is_true(s.s); } // DEBUG_CODE(verify_assignment();); @@ -766,11 +760,13 @@ public: if (!m_add_upper_bound_block) return; pb_util u(m); expr_ref_vector nsoft(m); + vector weights; expr_ref fml(m); - for (expr* s : m_soft) { - nsoft.push_back(mk_not(m, s)); + for (soft& s : m_soft) { + nsoft.push_back(mk_not(m, s.s)); + weights.push_back(s.weight); } - fml = u.mk_lt(nsoft.size(), m_weights.c_ptr(), nsoft.c_ptr(), m_upper); + fml = u.mk_lt(nsoft.size(), weights.c_ptr(), nsoft.c_ptr(), m_upper); TRACE("opt", tout << "block upper bound " << fml << "\n";);; s().assert_expr(fml); } @@ -832,9 +828,7 @@ public: void verify_core(exprs const& core) { IF_VERBOSE(3, verbose_stream() << "verify core\n";); ref smt_solver = mk_smt_solver(m, m_params, symbol()); - for (unsigned i = 0; i < s().get_num_assertions(); ++i) { - smt_solver->assert_expr(s().get_assertion(i)); - } + smt_solver->assert_expr(s().get_assertions()); smt_solver->assert_expr(core); lbool is_sat = smt_solver->check_sat(0, nullptr); if (is_sat == l_true) { @@ -845,13 +839,11 @@ public: void verify_assignment() { IF_VERBOSE(1, verbose_stream() << "verify assignment\n";); ref smt_solver = mk_smt_solver(m, m_params, symbol()); - for (unsigned i = 0; i < s().get_num_assertions(); ++i) { - smt_solver->assert_expr(s().get_assertion(i)); - } + smt_solver->assert_expr(s().get_assertions()); expr_ref n(m); - for (unsigned i = 0; i < m_soft.size(); ++i) { - n = m_soft[i]; - if (!m_assignment[i]) { + for (soft& s : m_soft) { + n = s.s; + if (!s.is_true) { n = mk_not(m, n); } smt_solver->assert_expr(n); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index c97b818cf..1b44b578b 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -34,16 +34,17 @@ Notes: namespace opt { maxsmt_solver_base::maxsmt_solver_base( - maxsat_context& c, vector const& ws, expr_ref_vector const& soft): + maxsat_context& c, vector const& ws, expr_ref_vector const& softs): m(c.get_manager()), m_c(c), - m_soft(soft), - m_weights(ws), m_assertions(m), m_trail(m) { c.get_base_model(m_model); SASSERT(m_model); updt_params(c.params()); + for (unsigned i = 0; i < ws.size(); ++i) { + m_soft.push_back(soft(expr_ref(softs.get(i), m), ws[i], false)); + } } void maxsmt_solver_base::updt_params(params_ref& p) { @@ -56,17 +57,21 @@ namespace opt { void maxsmt_solver_base::commit_assignment() { expr_ref tmp(m); + expr_ref_vector fmls(m); rational k(0), cost(0); - for (unsigned i = 0; i < m_soft.size(); ++i) { - if (get_assignment(i)) { - k += m_weights[i]; + vector weights; + for (soft const& s : m_soft) { + if (s.is_true) { + k += s.weight; } else { - cost += m_weights[i]; + cost += s.weight; } + weights.push_back(s.weight); + fmls.push_back(s.s); } pb_util pb(m); - tmp = pb.mk_ge(m_weights.size(), m_weights.c_ptr(), m_soft.c_ptr(), k); + tmp = pb.mk_ge(weights.size(), weights.c_ptr(), fmls.c_ptr(), k); TRACE("opt", tout << "cost: " << cost << "\n" << tmp << "\n";); s().assert_expr(tmp); } @@ -74,19 +79,14 @@ namespace opt { bool maxsmt_solver_base::init() { m_lower.reset(); m_upper.reset(); - m_assignment.reset(); - for (unsigned i = 0; i < m_weights.size(); ++i) { - m_assignment.push_back(m.is_true(m_soft[i])); - if (!m_assignment.back()) { - m_upper += m_weights[i]; - } + for (soft& s : m_soft) { + s.is_true = m.is_true(s.s); + if (!s.is_true) m_upper += s.weight; } TRACE("opt", tout << "upper: " << m_upper << " assignments: "; - for (unsigned i = 0; i < m_weights.size(); ++i) { - tout << (m_assignment[i]?"T":"F"); - } + for (soft& s : m_soft) tout << (s.is_true?"T":"F"); tout << "\n";); return true; } @@ -141,6 +141,7 @@ namespace opt { maxsmt_solver_base::scoped_ensure_theory::scoped_ensure_theory(maxsmt_solver_base& s) { m_wth = s.ensure_wmax_theory(); } + maxsmt_solver_base::scoped_ensure_theory::~scoped_ensure_theory() { if (m_wth) { m_wth->reset_local(); @@ -159,11 +160,13 @@ namespace opt { lbool maxsmt_solver_base::find_mutexes(obj_map& new_soft) { m_lower.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - new_soft.insert(m_soft[i], m_weights[i]); + expr_ref_vector fmls(m); + for (soft& s : m_soft) { + new_soft.insert(s.s, s.weight); + fmls.push_back(s.s); } vector mutexes; - lbool is_sat = s().find_mutexes(m_soft, mutexes); + lbool is_sat = s().find_mutexes(fmls, mutexes); if (is_sat != l_true) { return is_sat; } diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index 422cf26b9..de38baf32 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -56,17 +56,26 @@ namespace opt { // class maxsmt_solver_base : public maxsmt_solver { protected: + struct soft { + expr_ref s; + rational weight; + bool is_true; + soft(expr_ref& s, rational const& w, bool t): s(s), weight(w), is_true(t) {} + soft(soft const& other):s(other.s), weight(other.weight), is_true(other.is_true) {} + soft& operator=(soft const& other) { s = other.s; weight = other.weight; is_true = other.is_true; return *this; } + }; ast_manager& m; - maxsat_context& m_c; - const expr_ref_vector m_soft; - vector m_weights; + maxsat_context& m_c; + vector m_soft; expr_ref_vector m_assertions; expr_ref_vector m_trail; rational m_lower; rational m_upper; model_ref m_model; svector m_labels; - svector m_assignment; // truth assignment to soft constraints + //const expr_ref_vector m_soft; + //vector m_weights; + //svector m_assignment; // truth assignment to soft constraints params_ref m_params; // config public: @@ -75,7 +84,7 @@ namespace opt { ~maxsmt_solver_base() override {} rational get_lower() const override { return m_lower; } rational get_upper() const override { return m_upper; } - bool get_assignment(unsigned index) const override { return m_assignment[index]; } + bool get_assignment(unsigned index) const override { return m_soft[index].is_true; } void collect_statistics(statistics& st) const override { } void get_model(model_ref& mdl, svector& labels) override { mdl = m_model.get(); labels = m_labels;} virtual void commit_assignment(); diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 6e7e6ec78..4313cfbec 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -114,9 +114,7 @@ namespace opt { } void update_assignment() { - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment[i] = is_true(m_soft[i]); - } + for (soft& s : m_soft) s.is_true = is_true(s.s); } bool is_true(expr* e) { diff --git a/src/opt/wmax.cpp b/src/opt/wmax.cpp index 97231f69e..e4eb7e06b 100644 --- a/src/opt/wmax.cpp +++ b/src/opt/wmax.cpp @@ -124,10 +124,7 @@ namespace opt { } void update_assignment() { - m_assignment.reset(); - for (unsigned i = 0; i < m_soft.size(); ++i) { - m_assignment.push_back(is_true(m_soft[i])); - } + for (soft& s : m_soft) s.is_true = is_true(s.s); } struct compare_asm { diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index 186449545..4044c4a85 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -64,6 +64,13 @@ void solver::get_assertions(expr_ref_vector& fmls) const { } } +expr_ref_vector solver::get_assertions() const { + expr_ref_vector result(get_manager()); + get_assertions(result); + return result; +} + + struct scoped_assumption_push { expr_ref_vector& m_vec; scoped_assumption_push(expr_ref_vector& v, expr* e): m_vec(v) { v.push_back(e); } diff --git a/src/solver/solver.h b/src/solver/solver.h index c4df362e4..c371be284 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -179,6 +179,8 @@ public: */ void get_assertions(expr_ref_vector& fmls) const; + expr_ref_vector get_assertions() const; + /** \brief The number of tracked assumptions (see assert_expr(t, a)). */ diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index d18e0f717..031912c46 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -88,8 +88,7 @@ static void test(app* var, expr_ref& fml) { std::cout << "projected: " << mk_pp(pr, m) << "\n"; // projection is consistent with model. - expr_ref tmp(m); - VERIFY(md->eval(pr, tmp) && m.is_true(tmp)); + VERIFY(md->is_true(pr)); // projection implies E x. fml { From 0c32989144709ca7fddff62737990a05b4d22242 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jun 2018 15:07:21 -0700 Subject: [PATCH 1268/1283] change to const qualifier on constructor Signed-off-by: Nikolaj Bjorner --- src/opt/maxsmt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/maxsmt.h b/src/opt/maxsmt.h index de38baf32..b61d876b3 100644 --- a/src/opt/maxsmt.h +++ b/src/opt/maxsmt.h @@ -60,7 +60,7 @@ namespace opt { expr_ref s; rational weight; bool is_true; - soft(expr_ref& s, rational const& w, bool t): s(s), weight(w), is_true(t) {} + soft(expr_ref const& s, rational const& w, bool t): s(s), weight(w), is_true(t) {} soft(soft const& other):s(other.s), weight(other.weight), is_true(other.is_true) {} soft& operator=(soft const& other) { s = other.s; weight = other.weight; is_true = other.is_true; return *this; } }; From 19e2f8c9d5281772e75f087dfde7c0883418852b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Jun 2018 17:35:41 -0700 Subject: [PATCH 1269/1283] fix #1694 Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_explain.cpp | 23 ++++++++++-------- src/qe/nlqsat.cpp | 10 ++------ src/tactic/core/tseitin_cnf_tactic.cpp | 33 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 420174506..a93935fb6 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -216,9 +216,10 @@ namespace nlsat { max_var(p) must be assigned in the current interpretation. */ int sign(polynomial_ref const & p) { - TRACE("nlsat_explain", tout << "p: " << p << " var: " << max_var(p) << "\n";); SASSERT(max_var(p) == null_var || m_assignment.is_assigned(max_var(p))); - return m_am.eval_sign_at(p, m_assignment); + int s = m_am.eval_sign_at(p, m_assignment); + TRACE("nlsat_explain", tout << "p: " << p << " var: " << max_var(p) << " sign: " << s << "\n";); + return s; } /** @@ -1452,7 +1453,6 @@ namespace nlsat { SASSERT(check_already_added()); SASSERT(num > 0); TRACE("nlsat_explain", tout << "[explain] set of literals is infeasible in the current interpretation\n"; display(tout, num, ls);); - // exit(0); m_result = &result; process(num, ls); reset_already_added(); @@ -1738,11 +1738,13 @@ namespace nlsat { void solve_eq(var x, unsigned idx, polynomial_ref_vector const& ps) { polynomial_ref p(m_pm), A(m_pm), B(m_pm), C(m_pm), D(m_pm), E(m_pm), q(m_pm), r(m_pm); - polynomial_ref_vector qs(m_pm); + polynomial_ref_vector As(m_pm), Bs(m_pm); p = ps.get(idx); SASSERT(degree(p, x) == 1); A = m_pm.coeff(p, x, 1); B = m_pm.coeff(p, x, 0); + As.push_back(m_pm.mk_const(rational(1))); + Bs.push_back(m_pm.mk_const(rational(1))); B = neg(B); TRACE("nlsat_explain", tout << "p: " << p << " A: " << A << " B: " << B << "\n";); // x = B/A @@ -1753,20 +1755,21 @@ namespace nlsat { D = m_pm.mk_const(rational(1)); E = D; r = m_pm.mk_zero(); - for (unsigned j = 0; j <= d; ++j) { - qs.push_back(D); - D = D*A; + for (unsigned j = As.size(); j <= d; ++j) { + D = As.back(); As.push_back(A * D); + D = Bs.back(); Bs.push_back(B * D); } for (unsigned j = 0; j <= d; ++j) { // A^d*p0 + A^{d-1}*B*p1 + ... + B^j*A^{d-j}*pj + ... + B^d*p_d C = m_pm.coeff(q, x, j); + TRACE("nlsat_explain", tout << "coeff: q" << j << ": " << C << "\n";); if (!is_zero(C)) { - D = qs.get(d-j); + D = As.get(d - j); + E = Bs.get(j); r = r + D*E*C; } - E = E*B; } - TRACE("nlsat_explain", tout << "q: " << q << " r: " << r << "\n";); + TRACE("nlsat_explain", tout << "p: " << p << " q: " << q << " r: " << r << "\n";); ensure_sign(r); } else { diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 95f6b9b21..1ae9723c9 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -646,12 +646,8 @@ namespace qe { while (!vars.empty()); SASSERT(qvars.size() >= 2); SASSERT(qvars.back().empty()); - ackermanize_div(is_forall, qvars, fml); - init_expr2var(qvars); - - goal2nlsat g2s; expr_ref is_true(m), fml1(m), fml2(m); @@ -672,9 +668,7 @@ namespace qe { m_bound_rvars.push_back(nlsat::var_vector()); max_level lvl; if (is_exists(i)) lvl.m_ex = i; else lvl.m_fa = i; - for (unsigned j = 0; j < qvars[i].size(); ++j) { - app* v = qvars[i][j].get(); - + for (app* v : qvars[i]) { if (m_a2b.is_var(v)) { SASSERT(m.is_bool(v)); nlsat::bool_var b = m_a2b.to_var(v); @@ -696,7 +690,7 @@ namespace qe { m_is_true = nlsat::literal(m_a2b.to_var(is_true), false); // insert literals from arithmetical sub-formulas nlsat::atom_vector const& atoms = m_solver.get_atoms(); - TRACE("qe", m_solver.display(tout); ); + TRACE("qe", m_solver.display(tout);); for (unsigned i = 0; i < atoms.size(); ++i) { if (atoms[i]) { get_level(nlsat::literal(i, false)); diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index 9c57fe791..b29a80927 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -466,6 +466,38 @@ class tseitin_cnf_tactic : public tactic { } return NO; } + + mres match_iff_or(app * t, bool first, bool root) { + expr * a = nullptr, * _b = nullptr; + if (!root) return NO; + if (!is_iff(m, t, a, _b)) return NO; + bool sign = m.is_not(_b, _b); + if (!m.is_or(_b)) return NO; + app* b = to_app(_b); + unsigned num = b->get_num_args(); + if (first) { + bool visited = true; + visit(a, visited); + for (expr* arg : *b) { + visit(arg, visited); + } + if (!visited) + return CONT; + } + expr_ref la(m), nla(m), nlb(m), lb(m); + get_lit(a, sign, la); + inv(la, nla); + expr_ref_buffer lits(m); + lits.push_back(nla); + for (expr* arg : *b) { + get_lit(arg, false, lb); + lits.push_back(lb); + inv(lb, nlb); + mk_clause(la, nlb); + } + mk_clause(lits.size(), lits.c_ptr()); + return DONE; + } mres match_iff(app * t, bool first, bool root) { expr * a, * b; @@ -784,6 +816,7 @@ class tseitin_cnf_tactic : public tactic { TRY(match_or_3and); TRY(match_or); TRY(match_iff3); + // TRY(match_iff_or); TRY(match_iff); TRY(match_ite); TRY(match_not); From fc8b1d9a7dab2489f593379f398f057ab2289281 Mon Sep 17 00:00:00 2001 From: rainoftime Date: Fri, 22 Jun 2018 16:46:47 +0800 Subject: [PATCH 1270/1283] Refine default_tactic: if the constraint is an SAT instance and proof is not enabled, then use the qffd tactic --- src/tactic/portfolio/default_tactic.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 51cda17cd..7f71114f4 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -31,9 +31,11 @@ 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" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), + cond(mk_is_propositional_probe(), if_no_proofs(mk_fd_tactic(m, p)), cond(mk_is_qfbv_probe(), mk_qfbv_tactic(m), cond(mk_is_qfaufbv_probe(), mk_qfaufbv_tactic(m), cond(mk_is_qflia_probe(), mk_qflia_tactic(m), @@ -46,7 +48,7 @@ tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), cond(mk_is_qffplra_probe(), mk_qffplra_tactic(m, p), //cond(mk_is_qfufnra_probe(), mk_qfufnra_tactic(m, p), - mk_smt_tactic())))))))))))), + mk_smt_tactic()))))))))))))), p); return st; } From e1870233041a5a8cfb4fc7a0ab0c406e80d56eef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Jun 2018 21:57:10 -0700 Subject: [PATCH 1271/1283] fix #1699 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 4 +++- src/opt/opt_pareto.cpp | 2 ++ src/tactic/sine_filter.cpp | 26 ++++++++------------------ 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index af28d2254..566aaa1f6 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -351,6 +351,7 @@ namespace opt { void context::get_model_core(model_ref& mdl) { mdl = m_model; fix_model(mdl); + mdl->set_model_completion(true); TRACE("opt", tout << *mdl;); } @@ -528,7 +529,7 @@ namespace opt { k += obj.m_weights[i]; } else { - TRACE("opt", tout << val << "\n";); + TRACE("opt", tout << (*mdl)(obj.m_terms[i]) << "\n";); } } if (is_ge) { @@ -1539,6 +1540,7 @@ namespace opt { expr_ref tmp(m); model_ref mdl; get_model(mdl); + mdl->set_model_completion(true); for (expr * f : fmls) { if (!mdl->is_true(f)) { //IF_VERBOSE(0, m_fm->display(verbose_stream() << "fm\n")); diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index 56eed72ac..fe92c3ba6 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -40,6 +40,7 @@ namespace opt { } m_solver->get_model(m_model); m_solver->get_labels(m_labels); + m_model->set_model_completion(true); IF_VERBOSE(1, model_ref mdl(m_model); cb.fix_model(mdl); @@ -99,6 +100,7 @@ namespace opt { if (is_sat == l_true) { m_solver->get_model(m_model); m_solver->get_labels(m_labels); + m_model->set_model_completion(true); mk_not_dominated_by(); } return is_sat; diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 0ac726986..647791784 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -93,11 +93,8 @@ private: obj_hashtable const & consts, ptr_vector & next_consts) { TRACE("sine", - tout << "size of consts is "; tout << consts.size(); tout << "\n"; - obj_hashtable::iterator it = consts.begin(); - obj_hashtable::iterator end = consts.end(); - for (; it != end; it++) - tout << *it << "\n"; ); + tout << "size of consts is "; tout << consts.size(); tout << "\n"; + for (func_decl* f : consts) tout << f->get_name() << "\n";); bool matched = false; for (unsigned i = 0; i < q->get_num_patterns(); i++) { @@ -156,10 +153,8 @@ private: if (!consts.contains(f)) { consts.insert(f); if (const2quantifier.contains(f)) { - obj_pair_hashtable::iterator it = const2quantifier[f].begin(); - obj_pair_hashtable::iterator end = const2quantifier[f].end(); - for (; it != end; it++) - stack.push_back(*it); + for (auto const& p : const2quantifier[f]) + stack.push_back(p); const2quantifier.remove(f); } } @@ -220,16 +215,11 @@ private: visiting = to_visit.back(); to_visit.pop_back(); visited.insert(visiting); - obj_hashtable::iterator it = exp2const[visiting].begin(); - obj_hashtable::iterator end = exp2const[visiting].end(); - for (; it != end; it++) { - obj_hashtable::iterator exprit = const2exp[*it].begin(); - obj_hashtable::iterator exprend = const2exp[*it].end(); - for (; exprit != exprend; exprit++) { - if (!visited.contains(*exprit)) - to_visit.push_back(*exprit); + for (func_decl* f : exp2const[visiting]) + for (expr* e : const2exp[f]) { + if (!visited.contains(e)) + to_visit.push_back(e); } - } } for (unsigned i = 0; i < g->size(); i++) { From c32bfb5ecd6e23b402f6cba8337ac2a2e11dea81 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Jun 2018 15:29:40 -0700 Subject: [PATCH 1272/1283] fix crash during cancelation Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index f3ceee9c8..a8d6d5ebe 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1347,7 +1347,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, if (is_sat == l_true || is_sat == l_undef) { if (core) { core->reset(); } - if (model) { + if (model && *model) { r = find_rule(**model, is_concrete, reach_pred_used, num_reuse_reach); TRACE ("spacer", tout << "reachable " << "is_concrete " << is_concrete << " rused: "; From 915983821b07729156e30a20140121ea6caab2d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Jun 2018 17:06:49 -0700 Subject: [PATCH 1273/1283] add rewrite to each branch of mbp Signed-off-by: Nikolaj Bjorner --- src/model/model.h | 2 ++ src/model/model_smt2_pp.h | 1 - src/muz/spacer/spacer_context.cpp | 2 +- src/qe/qe_mbp.cpp | 13 ++++++------- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/model/model.h b/src/model/model.h index 9399be285..cfc44a8fc 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -94,5 +94,7 @@ public: }; }; +std::ostream& operator<<(std::ostream& out, model_core const& m); + #endif /* MODEL_H_ */ diff --git a/src/model/model_smt2_pp.h b/src/model/model_smt2_pp.h index b38bd631d..c43e26ca6 100644 --- a/src/model/model_smt2_pp.h +++ b/src/model/model_smt2_pp.h @@ -25,6 +25,5 @@ Revision History: void model_smt2_pp(std::ostream & out, ast_printer_context & ctx, model_core const & m, unsigned indent); void model_smt2_pp(std::ostream & out, ast_manager & m, model_core const & md, unsigned indent); -std::ostream& operator<<(std::ostream& out, model_core const& m); #endif diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index a8d6d5ebe..acfee574a 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -1347,7 +1347,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core, if (is_sat == l_true || is_sat == l_undef) { if (core) { core->reset(); } - if (model && *model) { + if (model && model->get()) { r = find_rule(**model, is_concrete, reach_pred_used, num_reuse_reach); TRACE ("spacer", tout << "reachable " << "is_concrete " << is_concrete << " rused: "; diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 78dcbfd16..2f44983ff 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -31,7 +31,6 @@ Revision History: #include "qe/qe_arrays.h" #include "qe/qe_datatypes.h" #include "qe/qe_lite.h" -#include "model/model_pp.h" #include "model/model_evaluator.h" @@ -617,26 +616,25 @@ public: qe::array_project_plugin ap(m); ap(mdl, array_vars, fml, vars, m_reduce_all_selects); SASSERT (array_vars.empty ()); - m_rw (fml); + m_rw(fml); SASSERT (!m.is_false (fml)); TRACE ("qe", - tout << "extended model:\n"; - model_pp (tout, mdl); + tout << "extended model:\n" << mdl; tout << "Vars: " << vars << "\n"; ); } // project reals, ints and other variables. if (!other_vars.empty ()) { - TRACE ("qe", tout << "Other vars: " << other_vars << "\n"; - model_pp(tout, mdl);); + TRACE ("qe", tout << "Other vars: " << other_vars << "\n" << mdl;); expr_ref_vector fmls(m); flatten_and (fml, fmls); (*this)(false, other_vars, mdl, fmls); fml = mk_and (fmls); + m_rw(fml); TRACE ("qe", tout << "Projected other vars:\n" << fml << "\n"; @@ -646,14 +644,15 @@ public: if (!other_vars.empty ()) { project_vars (mdl, other_vars, fml); + m_rw(fml); } // substitute any remaining other vars if (!m_dont_sub && !other_vars.empty ()) { subst_vars (eval, other_vars, fml); - TRACE ("qe", tout << "After substituting remaining other vars:\n" << fml << "\n";); // an extra round of simplification because subst_vars is not simplifying m_rw(fml); + TRACE ("qe", tout << "After substituting remaining other vars:\n" << fml << "\n";); other_vars.reset(); } From fcfa6baeca651c11ef9aa1892753350cab6139b3 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 20 Jun 2018 21:15:13 -0400 Subject: [PATCH 1274/1283] Refactor mk_th_lemma --- src/muz/spacer/spacer_proof_utils.cpp | 33 +++++++++++++++------------ 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 082cc4b5d..995a4b8b3 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -71,6 +71,21 @@ void theory_axiom_reducer::reset() { m_pinned.reset(); } +static proof* mk_th_lemma(ast_manager &m, ptr_buffer const &parents, + unsigned num_params, parameter const *params) { + buffer v; + for (unsigned i = 1; i < num_params; ++i) + v.push_back(params[i]); + + SASSERT(params[0].is_symbol()); + family_id tid = m.mk_family_id(params[0].get_symbol()); + SASSERT(tid != null_family_id); + + return m.mk_th_lemma(tid, m.mk_false(), + parents.size(), parents.c_ptr(), + num_params-1, v.c_ptr()); +} + // -- rewrite theory axioms into theory lemmas proof_ref theory_axiom_reducer::reduce(proof* pr) { proof_post_order pit(pr, m); @@ -108,20 +123,10 @@ proof_ref theory_axiom_reducer::reduce(proof* pr) { hyps.push_back(hyp); } - // (b) create farkas lemma. Rebuild parameters since - // mk_th_lemma() adds tid as first parameter - unsigned num_params = p->get_decl()->get_num_parameters(); - parameter const* params = p->get_decl()->get_parameters(); - vector parameters; - for (unsigned i = 1; i < num_params; ++i) parameters.push_back(params[i]); - - SASSERT(params[0].is_symbol()); - family_id tid = m.mk_family_id(params[0].get_symbol()); - SASSERT(tid != null_family_id); - - proof* th_lemma = m.mk_th_lemma(tid, m.mk_false(), - hyps.size(), hyps.c_ptr(), - num_params-1, parameters.c_ptr()); + // (b) Create a theory lemma + proof *th_lemma; + func_decl *d = p->get_decl(); + th_lemma = mk_th_lemma(m, hyps, d->get_num_parameters(), d->get_parameters()); m_pinned.push_back(th_lemma); SASSERT(is_arith_lemma(m, th_lemma)); From 4ed6783aff22015b1e93a9b9751757b068595344 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 20 Jun 2018 21:15:59 -0400 Subject: [PATCH 1275/1283] Formatting only. No change to code --- src/muz/spacer/spacer_proof_utils.cpp | 890 +++++++++++++------------- 1 file changed, 445 insertions(+), 445 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 995a4b8b3..8dee2ad44 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -29,35 +29,35 @@ Revision History: namespace spacer { -// arithmetic lemma recognizer -bool is_arith_lemma(ast_manager& m, proof* pr) -{ - // arith lemmas: second parameter specifies exact type of lemma, - // could be "farkas", "triangle-eq", "eq-propagate", - // "assign-bounds", maybe also something else - if (pr->get_decl_kind() == PR_TH_LEMMA) { - func_decl* d = pr->get_decl(); - symbol sym; - return d->get_num_parameters() >= 1 && - d->get_parameter(0).is_symbol(sym) && - sym == "arith"; + // arithmetic lemma recognizer + bool is_arith_lemma(ast_manager& m, proof* pr) + { + // arith lemmas: second parameter specifies exact type of lemma, + // could be "farkas", "triangle-eq", "eq-propagate", + // "assign-bounds", maybe also something else + if (pr->get_decl_kind() == PR_TH_LEMMA) { + func_decl* d = pr->get_decl(); + symbol sym; + return d->get_num_parameters() >= 1 && + d->get_parameter(0).is_symbol(sym) && + sym == "arith"; + } + return false; } - return false; -} // farkas lemma recognizer -bool is_farkas_lemma(ast_manager& m, proof* pr) -{ - if (pr->get_decl_kind() == PR_TH_LEMMA) + bool is_farkas_lemma(ast_manager& m, proof* pr) { - func_decl* d = pr->get_decl(); - symbol sym; - return d->get_num_parameters() >= 2 && - d->get_parameter(0).is_symbol(sym) && sym == "arith" && - d->get_parameter(1).is_symbol(sym) && sym == "farkas"; + if (pr->get_decl_kind() == PR_TH_LEMMA) + { + func_decl* d = pr->get_decl(); + symbol sym; + return d->get_num_parameters() >= 2 && + d->get_parameter(0).is_symbol(sym) && sym == "arith" && + d->get_parameter(1).is_symbol(sym) && sym == "farkas"; + } + return false; } - return false; -} /* @@ -66,495 +66,495 @@ bool is_farkas_lemma(ast_manager& m, proof* pr) * ==================================== */ -void theory_axiom_reducer::reset() { - m_cache.reset(); - m_pinned.reset(); -} - -static proof* mk_th_lemma(ast_manager &m, ptr_buffer const &parents, - unsigned num_params, parameter const *params) { - buffer v; - for (unsigned i = 1; i < num_params; ++i) - v.push_back(params[i]); - - SASSERT(params[0].is_symbol()); - family_id tid = m.mk_family_id(params[0].get_symbol()); - SASSERT(tid != null_family_id); - - return m.mk_th_lemma(tid, m.mk_false(), - parents.size(), parents.c_ptr(), - num_params-1, v.c_ptr()); -} - -// -- rewrite theory axioms into theory lemmas -proof_ref theory_axiom_reducer::reduce(proof* pr) { - proof_post_order pit(pr, m); - while (pit.hasNext()) { - proof* p = pit.next(); - - if (m.get_num_parents(p) == 0 && is_arith_lemma(m, p)) { - // we have an arith-theory-axiom and want to get rid of it - // we need to replace the axiom with - // (a) corresponding hypothesis, - // (b) a theory lemma, and - // (c) a lemma. - // Furthermore update data-structures - app *fact = to_app(m.get_fact(p)); - ptr_buffer cls; - if (m.is_or(fact)) { - for (unsigned i = 0, sz = fact->get_num_args(); i < sz; ++i) - cls.push_back(fact->get_arg(i)); - } - else - cls.push_back(fact); - - // (a) create hypothesis - ptr_buffer hyps; - for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { - expr *c; - expr_ref hyp_fact(m); - if (m.is_not(cls[i], c)) - hyp_fact = c; - else - hyp_fact = m.mk_not (cls[i]); - - proof* hyp = m.mk_hypothesis(hyp_fact); - m_pinned.push_back(hyp); - hyps.push_back(hyp); - } - - // (b) Create a theory lemma - proof *th_lemma; - func_decl *d = p->get_decl(); - th_lemma = mk_th_lemma(m, hyps, d->get_num_parameters(), d->get_parameters()); - m_pinned.push_back(th_lemma); - SASSERT(is_arith_lemma(m, th_lemma)); - - // (c) create lemma - proof* res = m.mk_lemma(th_lemma, fact); - m_pinned.push_back(res); - m_cache.insert(p, res); - - SASSERT(m.get_fact(res) == m.get_fact(p)); - } - else { - // proof is dirty, if a sub-proof of one of its premises - // has been transformed - bool dirty = false; - - ptr_buffer args; - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { - proof *pp, *tmp; - pp = m.get_parent(p, i); - VERIFY(m_cache.find(pp, tmp)); - args.push_back(tmp); - dirty |= (pp != tmp); - } - // if not dirty just use the old step - if (!dirty) m_cache.insert(p, p); - // otherwise create new proof with the corresponding proofs - // of the premises - else { - if (m.has_fact(p)) args.push_back(m.get_fact(p)); - - SASSERT(p->get_decl()->get_arity() == args.size()); - - proof* res = m.mk_app(p->get_decl(), - args.size(), (expr * const*)args.c_ptr()); - m_pinned.push_back(res); - m_cache.insert(p, res); - } - } + void theory_axiom_reducer::reset() { + m_cache.reset(); + m_pinned.reset(); } - proof* res; - VERIFY(m_cache.find(pr,res)); - DEBUG_CODE( - proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(res, side)); - ); + static proof* mk_th_lemma(ast_manager &m, ptr_buffer const &parents, + unsigned num_params, parameter const *params) { + buffer v; + for (unsigned i = 1; i < num_params; ++i) + v.push_back(params[i]); - return proof_ref(res, m); -} + SASSERT(params[0].is_symbol()); + family_id tid = m.mk_family_id(params[0].get_symbol()); + SASSERT(tid != null_family_id); + + return m.mk_th_lemma(tid, m.mk_false(), + parents.size(), parents.c_ptr(), + num_params-1, v.c_ptr()); + } + +// -- rewrite theory axioms into theory lemmas + proof_ref theory_axiom_reducer::reduce(proof* pr) { + proof_post_order pit(pr, m); + while (pit.hasNext()) { + proof* p = pit.next(); + + if (m.get_num_parents(p) == 0 && is_arith_lemma(m, p)) { + // we have an arith-theory-axiom and want to get rid of it + // we need to replace the axiom with + // (a) corresponding hypothesis, + // (b) a theory lemma, and + // (c) a lemma. + // Furthermore update data-structures + app *fact = to_app(m.get_fact(p)); + ptr_buffer cls; + if (m.is_or(fact)) { + for (unsigned i = 0, sz = fact->get_num_args(); i < sz; ++i) + cls.push_back(fact->get_arg(i)); + } + else + cls.push_back(fact); + + // (a) create hypothesis + ptr_buffer hyps; + for (unsigned i = 0, sz = cls.size(); i < sz; ++i) { + expr *c; + expr_ref hyp_fact(m); + if (m.is_not(cls[i], c)) + hyp_fact = c; + else + hyp_fact = m.mk_not (cls[i]); + + proof* hyp = m.mk_hypothesis(hyp_fact); + m_pinned.push_back(hyp); + hyps.push_back(hyp); + } + + // (b) Create a theory lemma + proof *th_lemma; + func_decl *d = p->get_decl(); + th_lemma = mk_th_lemma(m, hyps, d->get_num_parameters(), d->get_parameters()); + m_pinned.push_back(th_lemma); + SASSERT(is_arith_lemma(m, th_lemma)); + + // (c) create lemma + proof* res = m.mk_lemma(th_lemma, fact); + m_pinned.push_back(res); + m_cache.insert(p, res); + + SASSERT(m.get_fact(res) == m.get_fact(p)); + } + else { + // proof is dirty, if a sub-proof of one of its premises + // has been transformed + bool dirty = false; + + ptr_buffer args; + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + proof *pp, *tmp; + pp = m.get_parent(p, i); + VERIFY(m_cache.find(pp, tmp)); + args.push_back(tmp); + dirty |= (pp != tmp); + } + // if not dirty just use the old step + if (!dirty) m_cache.insert(p, p); + // otherwise create new proof with the corresponding proofs + // of the premises + else { + if (m.has_fact(p)) args.push_back(m.get_fact(p)); + + SASSERT(p->get_decl()->get_arity() == args.size()); + + proof* res = m.mk_app(p->get_decl(), + args.size(), (expr * const*)args.c_ptr()); + m_pinned.push_back(res); + m_cache.insert(p, res); + } + } + } + + proof* res; + VERIFY(m_cache.find(pr,res)); + DEBUG_CODE( + proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(res, side)); + ); + + return proof_ref(res, m); + } /* ------------------------------------------------------------------------- */ /* hypothesis_reducer */ /* ------------------------------------------------------------------------- */ -proof_ref hypothesis_reducer::reduce(proof* pr) { - compute_hypsets(pr); - collect_units(pr); + proof_ref hypothesis_reducer::reduce(proof* pr) { + compute_hypsets(pr); + collect_units(pr); - proof_ref res(reduce_core(pr), m); - SASSERT(res); - reset(); + proof_ref res(reduce_core(pr), m); + SASSERT(res); + reset(); - DEBUG_CODE(proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(res, side));); - return res; -} + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(res, side));); + return res; + } -void hypothesis_reducer::reset() { - m_active_hyps.reset(); - m_units.reset(); - m_cache.reset(); - for (auto t : m_pinned_active_hyps) dealloc(t); - m_pinned_active_hyps.reset(); - m_pinned.reset(); - m_hyp_mark.reset(); - m_open_mark.reset(); - m_visited.reset(); -} + void hypothesis_reducer::reset() { + m_active_hyps.reset(); + m_units.reset(); + m_cache.reset(); + for (auto t : m_pinned_active_hyps) dealloc(t); + m_pinned_active_hyps.reset(); + m_pinned.reset(); + m_hyp_mark.reset(); + m_open_mark.reset(); + m_visited.reset(); + } -void hypothesis_reducer::compute_hypsets(proof *pr) { - ptr_buffer todo; - todo.push_back(pr); + void hypothesis_reducer::compute_hypsets(proof *pr) { + ptr_buffer todo; + todo.push_back(pr); - while (!todo.empty()) { - proof* p = todo.back(); + while (!todo.empty()) { + proof* p = todo.back(); + + if (m_visited.is_marked(p)) { + todo.pop_back(); + continue; + } + + unsigned todo_sz = todo.size(); + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + SASSERT(m.is_proof(p->get_arg(i))); + proof *parent = to_app(p->get_arg(i)); + + if (!m_visited.is_marked(parent)) + todo.push_back(parent); + } + if (todo.size() > todo_sz) continue; - if (m_visited.is_marked(p)) { todo.pop_back(); - continue; - } - unsigned todo_sz = todo.size(); - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { - SASSERT(m.is_proof(p->get_arg(i))); - proof *parent = to_app(p->get_arg(i)); - - if (!m_visited.is_marked(parent)) - todo.push_back(parent); - } - if (todo.size() > todo_sz) continue; - - todo.pop_back(); - - m_visited.mark(p); + m_visited.mark(p); - proof_ptr_vector* active_hyps = nullptr; - // fill both sets - if (m.is_hypothesis(p)) { - // create active_hyps-set for step p - proof_ptr_vector* active_hyps = alloc(proof_ptr_vector); - m_pinned_active_hyps.insert(active_hyps); - m_active_hyps.insert(p, active_hyps); - active_hyps->push_back(p); - m_open_mark.mark(p); - m_hyp_mark.mark(m.get_fact(p)); - continue; - } + proof_ptr_vector* active_hyps = nullptr; + // fill both sets + if (m.is_hypothesis(p)) { + // create active_hyps-set for step p + proof_ptr_vector* active_hyps = alloc(proof_ptr_vector); + m_pinned_active_hyps.insert(active_hyps); + m_active_hyps.insert(p, active_hyps); + active_hyps->push_back(p); + m_open_mark.mark(p); + m_hyp_mark.mark(m.get_fact(p)); + continue; + } - ast_fast_mark1 seen; + ast_fast_mark1 seen; - active_hyps = alloc(proof_ptr_vector); - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { - proof* parent = m.get_parent(p, i); - // lemmas clear all hypotheses above them - if (m.is_lemma(p)) continue; - for (auto *x : *m_active_hyps.find(parent)) { - if (!seen.is_marked(x)) { - seen.mark(x); - active_hyps->push_back(x); - m_open_mark.mark(p); + active_hyps = alloc(proof_ptr_vector); + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + proof* parent = m.get_parent(p, i); + // lemmas clear all hypotheses above them + if (m.is_lemma(p)) continue; + for (auto *x : *m_active_hyps.find(parent)) { + if (!seen.is_marked(x)) { + seen.mark(x); + active_hyps->push_back(x); + m_open_mark.mark(p); + } } } - } - if (active_hyps->empty()) { - dealloc(active_hyps); - m_active_hyps.insert(p, &m_empty_vector); - } - else { - m_pinned_active_hyps.push_back(active_hyps); - m_active_hyps.insert(p, active_hyps); + if (active_hyps->empty()) { + dealloc(active_hyps); + m_active_hyps.insert(p, &m_empty_vector); + } + else { + m_pinned_active_hyps.push_back(active_hyps); + m_active_hyps.insert(p, active_hyps); + } } } -} // collect all units that are hyp-free and are used as hypotheses somewhere // requires that m_active_hyps has been computed -void hypothesis_reducer::collect_units(proof* pr) { + void hypothesis_reducer::collect_units(proof* pr) { - proof_post_order pit(pr, m); - while (pit.hasNext()) { - proof* p = pit.next(); - if (!m.is_hypothesis(p)) { - // collect units that are hyp-free and are used as - // hypotheses in the proof pr - if (!m_open_mark.is_marked(p) && m.has_fact(p) && - m_hyp_mark.is_marked(m.get_fact(p))) - m_units.insert(m.get_fact(p), p); + proof_post_order pit(pr, m); + while (pit.hasNext()) { + proof* p = pit.next(); + if (!m.is_hypothesis(p)) { + // collect units that are hyp-free and are used as + // hypotheses in the proof pr + if (!m_open_mark.is_marked(p) && m.has_fact(p) && + m_hyp_mark.is_marked(m.get_fact(p))) + m_units.insert(m.get_fact(p), p); + } } } -} /** \brief returns true if p is an ancestor of q - */ -bool hypothesis_reducer::is_ancestor(proof *p, proof *q) { - if (p == q) return true; - ptr_vector todo; - todo.push_back(q); +*/ + bool hypothesis_reducer::is_ancestor(proof *p, proof *q) { + if (p == q) return true; + ptr_vector todo; + todo.push_back(q); - expr_mark visited; - while (!todo.empty()) { - proof *cur; - cur = todo.back(); - todo.pop_back(); - - if (visited.is_marked(cur)) continue; - - if (cur == p) return true; - visited.mark(cur); - - for (unsigned i = 0, sz = m.get_num_parents(cur); i < sz; ++i) { - todo.push_back(m.get_parent(cur, i)); - } - } - return false; -} - -proof* hypothesis_reducer::reduce_core(proof* pf) { - SASSERT(m.is_false(m.get_fact(pf))); - - proof *res = NULL; - - ptr_vector todo; - todo.push_back(pf); - ptr_buffer args; - bool dirty = false; - - while (true) { - proof *p, *tmp, *pp; - unsigned todo_sz; - - p = todo.back(); - if (m_cache.find(p, tmp)) { + expr_mark visited; + while (!todo.empty()) { + proof *cur; + cur = todo.back(); todo.pop_back(); - continue; - } - dirty = false; - args.reset(); - todo_sz = todo.size(); - for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { - pp = m.get_parent(p, i); - if (m_cache.find(pp, tmp)) { - args.push_back(tmp); - dirty |= pp != tmp; - } else { - todo.push_back(pp); + if (visited.is_marked(cur)) continue; + + if (cur == p) return true; + visited.mark(cur); + + for (unsigned i = 0, sz = m.get_num_parents(cur); i < sz; ++i) { + todo.push_back(m.get_parent(cur, i)); } } + return false; + } - if (todo_sz < todo.size()) continue; + proof* hypothesis_reducer::reduce_core(proof* pf) { + SASSERT(m.is_false(m.get_fact(pf))); - todo.pop_back(); + proof *res = NULL; - // transform the current proof node + ptr_vector todo; + todo.push_back(pf); + ptr_buffer args; + bool dirty = false; - if (m.is_hypothesis(p)) { - // if possible, replace a hypothesis by a unit derivation - if (m_units.find(m.get_fact(p), tmp)) { - // use already transformed proof of the unit if it is available - proof* proof_of_unit; - if (!m_cache.find(tmp, proof_of_unit)) { - proof_of_unit = tmp; + while (true) { + proof *p, *tmp, *pp; + unsigned todo_sz; + + p = todo.back(); + if (m_cache.find(p, tmp)) { + todo.pop_back(); + continue; + } + + dirty = false; + args.reset(); + todo_sz = todo.size(); + for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) { + pp = m.get_parent(p, i); + if (m_cache.find(pp, tmp)) { + args.push_back(tmp); + dirty |= pp != tmp; + } else { + todo.push_back(pp); } + } - // make sure hypsets for the unit are computed - // AG: is this needed? - compute_hypsets(proof_of_unit); + if (todo_sz < todo.size()) continue; - // if the transformation doesn't create a cycle, perform it - if (!is_ancestor(p, proof_of_unit)) { - res = proof_of_unit; + todo.pop_back(); + + // transform the current proof node + + if (m.is_hypothesis(p)) { + // if possible, replace a hypothesis by a unit derivation + if (m_units.find(m.get_fact(p), tmp)) { + // use already transformed proof of the unit if it is available + proof* proof_of_unit; + if (!m_cache.find(tmp, proof_of_unit)) { + proof_of_unit = tmp; + } + + // make sure hypsets for the unit are computed + // AG: is this needed? + compute_hypsets(proof_of_unit); + + // if the transformation doesn't create a cycle, perform it + if (!is_ancestor(p, proof_of_unit)) { + res = proof_of_unit; + } + else { + // -- failed to transform the proof, perhaps bad + // -- choice of the proof of unit + res = p; + } } else { - // -- failed to transform the proof, perhaps bad - // -- choice of the proof of unit + // -- no unit found to replace the hypothesis res = p; } } + + else if (!dirty) {res = p;} + + else if (m.is_lemma(p)) { + // lemma: reduce the premise; remove reduced consequences + // from conclusion + SASSERT(args.size() == 1); + res = mk_lemma_core(args[0], m.get_fact(p)); + // -- re-compute hypsets + compute_hypsets(res); + } + else if (m.is_unit_resolution(p)) { + // unit: reduce untis; reduce the first premise; rebuild + // unit resolution + res = mk_unit_resolution_core(p, args); + // -- re-compute hypsets + compute_hypsets(res); + } else { - // -- no unit found to replace the hypothesis - res = p; + res = mk_proof_core(p, args); + // -- re-compute hypsets + compute_hypsets(res); + } + + SASSERT(res); + m_cache.insert(p, res); + + // bail out as soon as found a sub-proof of false + if (!m_open_mark.is_marked(res) && m.has_fact(res) && m.is_false(m.get_fact(res))) + return res; + } + UNREACHABLE(); + return nullptr; + } + + proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { + SASSERT(m.is_false(m.get_fact(premise))); + SASSERT(m_active_hyps.contains(premise)); + + proof_ptr_vector* active_hyps = m_active_hyps.find(premise); + + // if there is no active hypothesis return the premise + if (!m_open_mark.is_marked(premise)) { + // XXX just in case premise might go away + m_pinned.push_back(premise); + return premise; + } + + // add some stability + std::stable_sort(active_hyps->begin(), active_hyps->end(), ast_lt_proc()); + // otherwise, build a disjunction of the negated active hypotheses + // and add a lemma proof step + expr_ref_buffer args(m); + for (auto hyp : *active_hyps) { + expr *hyp_fact, *t; + hyp_fact = m.get_fact(hyp); + if (m.is_not(hyp_fact, t)) + args.push_back(t); + else + args.push_back(m.mk_not(hyp_fact)); + } + + expr_ref lemma(m); + lemma = mk_or(m, args.size(), args.c_ptr()); + + proof* res; + res = m.mk_lemma(premise, lemma); + m_pinned.push_back(res); + return res; + } + + proof* hypothesis_reducer::mk_unit_resolution_core(proof *ures, + ptr_buffer& args) { + // if any literal is false, we don't need a unit resolution step + // This can be the case due to some previous transformations + for (unsigned i = 1, sz = args.size(); i < sz; ++i) { + if (m.is_false(m.get_fact(args[i]))) { + // XXX pin just in case + m_pinned.push_back(args[i]); + return args[i]; } } - else if (!dirty) {res = p;} + proof* arg0 = args[0]; + app *fact0 = to_app(m.get_fact(arg0)); - else if (m.is_lemma(p)) { - // lemma: reduce the premise; remove reduced consequences - // from conclusion - SASSERT(args.size() == 1); - res = mk_lemma_core(args[0], m.get_fact(p)); - // -- re-compute hypsets - compute_hypsets(res); + + ptr_buffer pf_args; + ptr_buffer pf_fact; + pf_args.push_back(arg0); + + // compute literals to be resolved + ptr_buffer lits; + + // fact0 is a literal whenever the original resolution was a + // binary resolution to an empty clause + if (m.get_num_parents(ures) == 2 && m.is_false(m.get_fact(ures))) { + lits.push_back(fact0); } - else if (m.is_unit_resolution(p)) { - // unit: reduce untis; reduce the first premise; rebuild - // unit resolution - res = mk_unit_resolution_core(p, args); - // -- re-compute hypsets - compute_hypsets(res); + // fact0 is a literal unless it is a dijsunction + else if (!m.is_or(fact0)) { + lits.push_back(fact0); } + // fact0 is a literal only if it appears as a literal in the + // original resolution else { - res = mk_proof_core(p, args); - // -- re-compute hypsets - compute_hypsets(res); + lits.reset(); + app* ures_fact = to_app(m.get_fact(m.get_parent(ures, 0))); + for (unsigned i = 0, sz = ures_fact->get_num_args(); i < sz; ++i) { + if (ures_fact->get_arg(i) == fact0) { + lits.push_back(fact0); + break; + } + } + if (lits.empty()) { + lits.append(fact0->get_num_args(), fact0->get_args()); + } + } - SASSERT(res); - m_cache.insert(p, res); + // -- find all literals that are resolved on + for (unsigned i = 0, sz = lits.size(); i < sz; ++i) { + bool found = false; + for (unsigned j = 1; j < args.size(); ++j) { + if (m.is_complement(lits.get(i), m.get_fact(args[j]))) { + found = true; + pf_args.push_back(args[j]); + break; + } + } + if (!found) {pf_fact.push_back(lits.get(i));} + } - // bail out as soon as found a sub-proof of false - if (!m_open_mark.is_marked(res) && m.has_fact(res) && m.is_false(m.get_fact(res))) - return res; - } - UNREACHABLE(); - return nullptr; -} - -proof* hypothesis_reducer::mk_lemma_core(proof* premise, expr *fact) { - SASSERT(m.is_false(m.get_fact(premise))); - SASSERT(m_active_hyps.contains(premise)); - - proof_ptr_vector* active_hyps = m_active_hyps.find(premise); - - // if there is no active hypothesis return the premise - if (!m_open_mark.is_marked(premise)) { - // XXX just in case premise might go away - m_pinned.push_back(premise); - return premise; - } - - // add some stability - std::stable_sort(active_hyps->begin(), active_hyps->end(), ast_lt_proc()); - // otherwise, build a disjunction of the negated active hypotheses - // and add a lemma proof step - expr_ref_buffer args(m); - for (auto hyp : *active_hyps) { - expr *hyp_fact, *t; - hyp_fact = m.get_fact(hyp); - if (m.is_not(hyp_fact, t)) - args.push_back(t); - else - args.push_back(m.mk_not(hyp_fact)); - } - - expr_ref lemma(m); - lemma = mk_or(m, args.size(), args.c_ptr()); - - proof* res; - res = m.mk_lemma(premise, lemma); - m_pinned.push_back(res); - return res; -} - -proof* hypothesis_reducer::mk_unit_resolution_core(proof *ures, - ptr_buffer& args) { - // if any literal is false, we don't need a unit resolution step - // This can be the case due to some previous transformations - for (unsigned i = 1, sz = args.size(); i < sz; ++i) { - if (m.is_false(m.get_fact(args[i]))) { + // unit resolution got reduced to noop + if (pf_args.size() == 1) { // XXX pin just in case - m_pinned.push_back(args[i]); - return args[i]; + m_pinned.push_back(arg0); + + return arg0; } + + // make unit resolution proof step + // expr_ref tmp(m); + // tmp = mk_or(m, pf_fact.size(), pf_fact.c_ptr()); + // proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), tmp); + proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr()); + m_pinned.push_back(res); + + return res; } - proof* arg0 = args[0]; - app *fact0 = to_app(m.get_fact(arg0)); - - - ptr_buffer pf_args; - ptr_buffer pf_fact; - pf_args.push_back(arg0); - - // compute literals to be resolved - ptr_buffer lits; - - // fact0 is a literal whenever the original resolution was a - // binary resolution to an empty clause - if (m.get_num_parents(ures) == 2 && m.is_false(m.get_fact(ures))) { - lits.push_back(fact0); - } - // fact0 is a literal unless it is a dijsunction - else if (!m.is_or(fact0)) { - lits.push_back(fact0); - } - // fact0 is a literal only if it appears as a literal in the - // original resolution - else { - lits.reset(); - app* ures_fact = to_app(m.get_fact(m.get_parent(ures, 0))); - for (unsigned i = 0, sz = ures_fact->get_num_args(); i < sz; ++i) { - if (ures_fact->get_arg(i) == fact0) { - lits.push_back(fact0); - break; + proof* hypothesis_reducer::mk_proof_core(proof* old, ptr_buffer& args) { + // if any of the literals are false, we don't need a step + for (unsigned i = 0; i < args.size(); ++i) { + if (m.is_false(m.get_fact(args[i]))) { + // XXX just in case + m_pinned.push_back(args[i]); + return args[i]; } } - if (lits.empty()) { - lits.append(fact0->get_num_args(), fact0->get_args()); - } + // otherwise build step + // BUG: I guess this doesn't work with quantifiers (since they are no apps) + args.push_back(to_app(m.get_fact(old))); + + SASSERT(old->get_decl()->get_arity() == args.size()); + + proof* res = m.mk_app(old->get_decl(), args.size(), + (expr * const*)args.c_ptr()); + m_pinned.push_back(res); + return res; } - // -- find all literals that are resolved on - for (unsigned i = 0, sz = lits.size(); i < sz; ++i) { - bool found = false; - for (unsigned j = 1; j < args.size(); ++j) { - if (m.is_complement(lits.get(i), m.get_fact(args[j]))) { - found = true; - pf_args.push_back(args[j]); - break; - } - } - if (!found) {pf_fact.push_back(lits.get(i));} - } - - // unit resolution got reduced to noop - if (pf_args.size() == 1) { - // XXX pin just in case - m_pinned.push_back(arg0); - - return arg0; - } - - // make unit resolution proof step - // expr_ref tmp(m); - // tmp = mk_or(m, pf_fact.size(), pf_fact.c_ptr()); - // proof* res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), tmp); - proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr()); - m_pinned.push_back(res); - - return res; -} - -proof* hypothesis_reducer::mk_proof_core(proof* old, ptr_buffer& args) { - // if any of the literals are false, we don't need a step - for (unsigned i = 0; i < args.size(); ++i) { - if (m.is_false(m.get_fact(args[i]))) { - // XXX just in case - m_pinned.push_back(args[i]); - return args[i]; - } - } - - // otherwise build step - // BUG: I guess this doesn't work with quantifiers (since they are no apps) - args.push_back(to_app(m.get_fact(old))); - - SASSERT(old->get_decl()->get_arity() == args.size()); - - proof* res = m.mk_app(old->get_decl(), args.size(), - (expr * const*)args.c_ptr()); - m_pinned.push_back(res); - return res; -} - }; From ac23002dce7ca21e7504d911738bf9e7f68a5c3a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 20 Jun 2018 23:04:44 -0400 Subject: [PATCH 1276/1283] Fix bugs in iuc generation --- src/muz/spacer/spacer_iuc_proof.h | 2 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 83 +++++++++++---------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/muz/spacer/spacer_iuc_proof.h b/src/muz/spacer/spacer_iuc_proof.h index a3044ca53..ed36dbf5b 100644 --- a/src/muz/spacer/spacer_iuc_proof.h +++ b/src/muz/spacer/spacer_iuc_proof.h @@ -33,7 +33,7 @@ public: bool is_h_marked(proof* p) {return m_h_mark.is_marked(p);} bool is_b_pure (proof *p) { - return !is_h_marked (p) && is_core_pure(m.get_fact (p)); + return !is_h_marked(p) && !this->is_a_marked(p) && is_core_pure(m.get_fact(p)); } void display_dot(std::ostream &out); diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 8fb5feeef..79bafdfeb 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -34,15 +34,15 @@ Revision History: namespace spacer { - unsat_core_plugin::unsat_core_plugin(unsat_core_learner& learner): + unsat_core_plugin::unsat_core_plugin(unsat_core_learner& learner): m(learner.m), m_learner(learner) {}; - + void unsat_core_plugin_lemma::compute_partial_core(proof* step) { SASSERT(m_learner.m_pr.is_a_marked(step)); SASSERT(m_learner.m_pr.is_b_marked(step)); - + for (proof* premise : m.get_parents(step)) { - + if (m_learner.is_b_open (premise)) { // by IH, premises that are AB marked are already closed SASSERT(!m_learner.m_pr.is_a_marked(premise)); @@ -51,18 +51,18 @@ namespace spacer { } m_learner.set_closed(step, true); } - + void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const { SASSERT(m_learner.is_b_open(step)); - + ptr_buffer todo; todo.push_back(step); - + while (!todo.empty()) { proof* pf = todo.back(); todo.pop_back(); - + // if current step hasn't been processed, if (!m_learner.is_closed(pf)) { m_learner.set_closed(pf, true); @@ -71,7 +71,7 @@ namespace spacer { // so if it is also a-marked, it must be closed SASSERT(m_learner.m_pr.is_b_marked(pf)); SASSERT(!m_learner.m_pr.is_a_marked(pf)); - + // the current step needs to be interpolated: expr* fact = m.get_fact(pf); // if we trust the current step and we are able to use it @@ -82,11 +82,11 @@ namespace spacer { } // otherwise recurse on premises else { - for (proof* premise : m.get_parents(pf)) - if (m_learner.is_b_open(premise)) + for (proof* premise : m.get_parents(pf)) + if (m_learner.is_b_open(premise)) todo.push_back(premise); } - + } } } @@ -101,15 +101,15 @@ namespace spacer { func_decl* d = step->get_decl(); symbol sym; if (!m_learner.is_closed(step) && // if step is not already interpolated - is_farkas_lemma(m, step)) { - // weaker check: d->get_num_parameters() >= m.get_num_parents(step) + 2 - + is_farkas_lemma(m, step)) { + // weaker check : d->get_num_parameters() >= m.get_num_parents(step) + 2 + SASSERT(d->get_num_parameters() == m.get_num_parents(step) + 2); SASSERT(m.has_fact(step)); - + coeff_lits_t coeff_lits; expr_ref_vector pinned(m); - + /* The farkas lemma represents a subproof starting from premise(-set)s A, BNP and BP(ure) and * ending in a disjunction D. We need to compute the contribution of BP, i.e. a formula, which * is entailed by BP and together with A and BNP entails D. @@ -134,34 +134,35 @@ namespace spacer { * as workaround we take the absolute value of the provided coefficients. */ parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient - - STRACE("spacer.farkas", - verbose_stream() << "Farkas input: "<< "\n"; + + TRACE("spacer.farkas", + tout << "Farkas input: "<< "\n"; for (unsigned i = 0; i < m.get_num_parents(step); ++i) { - proof * prem = m.get_parent(step, i); - rational coef = params[i].get_rational(); + proof * prem = m.get_parent(step, i); + rational coef = params[i].get_rational(); bool b_pure = m_learner.m_pr.is_b_pure (prem); - verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; + tout << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; } ); - + bool can_be_closed = true; - + for (unsigned i = 0; i < m.get_num_parents(step); ++i) { proof * premise = m.get_parent(step, i); - + if (m_learner.is_b_open (premise)) { SASSERT(!m_learner.m_pr.is_a_marked(premise)); - - if (m_learner.m_pr.is_b_pure (step)) { + + if (m_learner.m_pr.is_b_pure (premise)) { if (!m_use_constant_from_a) { rational coefficient = params[i].get_rational(); coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise))); } } else { + // -- mixed premise, won't be able to close this proof step can_be_closed = false; - + if (m_use_constant_from_a) { rational coefficient = params[i].get_rational(); coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise))); @@ -175,10 +176,10 @@ namespace spacer { } } } - + if (m_use_constant_from_a) { params += m.get_num_parents(step); // point to the first Farkas coefficient, which corresponds to a formula in the conclusion - + // the conclusion can either be a single formula or a disjunction of several formulas, we have to deal with both situations if (m.get_num_parents(step) + 2 < d->get_num_parameters()) { unsigned num_args = 1; @@ -190,7 +191,7 @@ namespace spacer { args = _or->get_args(); } SASSERT(m.get_num_parents(step) + 2 + num_args == d->get_num_parameters()); - + bool_rewriter brw(m); for (unsigned i = 0; i < num_args; ++i) { expr* premise = args[i]; @@ -205,11 +206,11 @@ namespace spacer { } // only if all b-premises can be used directly, add the farkas core and close the step + // AG: this decision needs to be re-evaluated. If the proof cannot be closed, literals above + // AG: it will go into the core. However, it does not mean that this literal should/could not be added. if (can_be_closed) { m_learner.set_closed(step, true); - expr_ref res = compute_linear_combination(coeff_lits); - m_learner.add_lemma_to_core(res); } } @@ -253,7 +254,7 @@ namespace spacer { verbose_stream() << "Farkas input: "<< "\n"; for (unsigned i = 0; i < m.get_num_parents(step); ++i) { proof * prem = m.get_parent(step, i); - rational coef = params[i].get_rational(); + rational coef = params[i].get_rational(); bool b_pure = m_learner.m_pr.is_b_pure (prem); verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m_learner.m) << "\n"; } @@ -340,7 +341,7 @@ namespace spacer { // 4. extract linear combinations from matrix and add result to core for (unsigned k = 0; k < i; ++k)// i points to the row after the last row which is non-zero { - coeff_lits_t coeff_lits; + coeff_lits_t coeff_lits; for (unsigned l = 0; l < matrix.num_cols(); ++l) { if (!matrix.get(k,l).is_zero()) { coeff_lits.push_back(std::make_pair(matrix.get(k, l), ordered_basis[l])); @@ -354,14 +355,14 @@ namespace spacer { } - expr_ref unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const coeff_lits_t& coeff_lits) { + expr_ref unsat_core_plugin_farkas_lemma_optimized::compute_linear_combination(const coeff_lits_t& coeff_lits) { smt::farkas_util util(m); for (auto const & p : coeff_lits) { util.add(p.first, p.second); } expr_ref negated_linear_combination = util.get(); SASSERT(m.is_not(negated_linear_combination)); - return expr_ref(mk_not(m, negated_linear_combination), m); + return expr_ref(mk_not(m, negated_linear_combination), m); //TODO: rewrite the get-method to return nonnegated stuff? } @@ -449,7 +450,7 @@ namespace spacer { for (unsigned j = 0; j < matrix.num_cols(); ++j) { SASSERT(matrix.get(i, j).is_int()); app_ref a_ij(util.mk_numeral(matrix.get(i,j), true), m); - + app_ref sum(util.mk_int(0), m); for (unsigned k = 0; k < n; ++k) { sum = util.mk_add(sum, util.mk_mul(coeffs[i][k].get(), bounded_vectors[j][k].get())); @@ -458,7 +459,7 @@ namespace spacer { s->assert_expr(eq); } } - + // check result lbool res = s->check_sat(0, nullptr); @@ -682,7 +683,7 @@ namespace spacer { void unsat_core_plugin_min_cut::finalize() { unsigned_vector cut_nodes; m_min_cut.compute_min_cut(cut_nodes); - + for (unsigned cut_node : cut_nodes) { m_learner.add_lemma_to_core(m_node_to_formula[cut_node]); } From 9c9d0d084007d804610029ccbce7b802ed34bb8c Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Wed, 20 Jun 2018 23:07:01 -0400 Subject: [PATCH 1277/1283] convert assign-bounds axioms to farkas lemmas --- src/muz/spacer/spacer_proof_utils.cpp | 74 +++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 8dee2ad44..c7d7ffb54 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -45,7 +45,7 @@ namespace spacer { return false; } -// farkas lemma recognizer + // farkas lemma recognizer bool is_farkas_lemma(ast_manager& m, proof* pr) { if (pr->get_decl_kind() == PR_TH_LEMMA) @@ -59,6 +59,19 @@ namespace spacer { return false; } + static bool is_assign_bounds_lemma(ast_manager &m, proof *pr) { + if (pr->get_decl_kind() == PR_TH_LEMMA) + { + func_decl* d = pr->get_decl(); + symbol sym; + return d->get_num_parameters() >= 2 && + d->get_parameter(0).is_symbol(sym) && sym == "arith" && + d->get_parameter(1).is_symbol(sym) && sym == "assign-bounds"; + } + return false; + } + + /* * ==================================== @@ -71,8 +84,8 @@ namespace spacer { m_pinned.reset(); } - static proof* mk_th_lemma(ast_manager &m, ptr_buffer const &parents, - unsigned num_params, parameter const *params) { + static proof_ref mk_th_lemma(ast_manager &m, ptr_buffer const &parents, + unsigned num_params, parameter const *params) { buffer v; for (unsigned i = 1; i < num_params; ++i) v.push_back(params[i]); @@ -81,12 +94,45 @@ namespace spacer { family_id tid = m.mk_family_id(params[0].get_symbol()); SASSERT(tid != null_family_id); - return m.mk_th_lemma(tid, m.mk_false(), - parents.size(), parents.c_ptr(), - num_params-1, v.c_ptr()); + proof *pf = m.mk_th_lemma(tid, m.mk_false(), + parents.size(), parents.c_ptr(), + v.size(), v.c_ptr()); + return proof_ref(pf, m); } -// -- rewrite theory axioms into theory lemmas + // convert assign-bounds lemma to a farkas lemma by adding missing coeff + // assume that missing coeff is for premise at position 0 + static proof_ref mk_fk_from_ab(ast_manager &m, + ptr_buffer const &parents, + unsigned num_params, + parameter const *params) { + SASSERT(num_params == parents.size() + 1 /* one param is missing */); + buffer v; + v.push_back(parameter(symbol("farkas"))); + v.push_back(parameter(rational(1))); + for (unsigned i = 2; i < num_params; ++i) + v.push_back(params[i]); + + SASSERT(params[0].is_symbol()); + family_id tid = m.mk_family_id(params[0].get_symbol()); + SASSERT(tid != null_family_id); + + proof_ref pf(m); + pf = m.mk_th_lemma(tid, m.mk_false(), + parents.size(), parents.c_ptr(), + v.size(), v.c_ptr()); + + SASSERT(is_arith_lemma(m, pf)); + DEBUG_CODE( + proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(pf, side)); + ); + return pf; + + } + + /// -- rewrite theory axioms into theory lemmas proof_ref theory_axiom_reducer::reduce(proof* pr) { proof_post_order pit(pr, m); while (pit.hasNext()) { @@ -124,9 +170,19 @@ namespace spacer { } // (b) Create a theory lemma - proof *th_lemma; + proof_ref th_lemma(m); func_decl *d = p->get_decl(); - th_lemma = mk_th_lemma(m, hyps, d->get_num_parameters(), d->get_parameters()); + if (is_assign_bounds_lemma(m, p)) { + + th_lemma = mk_fk_from_ab(m, hyps, + d->get_num_parameters(), + d->get_parameters()); + } + else { + th_lemma = mk_th_lemma(m, hyps, + d->get_num_parameters(), + d->get_parameters()); + } m_pinned.push_back(th_lemma); SASSERT(is_arith_lemma(m, th_lemma)); From 58dc5451e159866f4655184837de7fbf233d5dc2 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 21 Jun 2018 17:16:23 -0400 Subject: [PATCH 1278/1283] iuc code cleanup --- src/muz/spacer/spacer_unsat_core_learner.cpp | 33 ++-- src/muz/spacer/spacer_unsat_core_learner.h | 25 +-- src/muz/spacer/spacer_unsat_core_plugin.cpp | 152 +++++++++---------- src/muz/spacer/spacer_unsat_core_plugin.h | 16 +- 4 files changed, 114 insertions(+), 112 deletions(-) diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index da0d6ec34..08f7f7ce8 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -36,28 +36,27 @@ void unsat_core_learner::register_plugin(unsat_core_plugin* plugin) { } void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { - // traverse proof proof_post_order it(m_pr.get(), m); while (it.hasNext()) { - proof* currentNode = it.next(); + proof* curr = it.next(); - if (m.get_num_parents(currentNode) > 0) { - bool need_to_mark_closed = true; + bool done = is_closed(curr); + if (done) continue; - for (proof* premise : m.get_parents(currentNode)) { - need_to_mark_closed &= (!m_pr.is_b_marked(premise) || m_closed.is_marked(premise)); - } - - // save result - m_closed.mark(currentNode, need_to_mark_closed); + if (m.get_num_parents(curr) > 0) { + done = true; + for (proof* p : m.get_parents(curr)) done &= !is_b_open(p); + set_closed(curr, done); } - // we have now collected all necessary information, so we can visit the node - // if the node mixes A-reasoning and B-reasoning and contains non-closed premises - if (m_pr.is_a_marked(currentNode) && - m_pr.is_b_marked(currentNode) && - !m_closed.is_marked(currentNode)) { - compute_partial_core(currentNode); // then we need to compute a partial core + // we have now collected all necessary information, + // so we can visit the node + // if the node mixes A-reasoning and B-reasoning + // and contains non-closed premises + if (!done) { + if (m_pr.is_a_marked(curr) && m_pr.is_b_marked(curr)) { + compute_partial_core(curr); + } } } @@ -74,7 +73,7 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { void unsat_core_learner::compute_partial_core(proof* step) { for (unsat_core_plugin* plugin : m_plugins) { - if (m_closed.is_marked(step)) break; + if (is_closed(step)) break; plugin->compute_partial_core(step); } } diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 327b12eb6..42ad71501 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -22,6 +22,7 @@ Revision History: #include "ast/ast.h" #include "muz/spacer/spacer_util.h" #include "muz/spacer/spacer_proof_utils.h" +#include "muz/spacer/spacer_iuc_proof.h" namespace spacer { @@ -31,13 +32,25 @@ namespace spacer { class unsat_core_learner { typedef obj_hashtable expr_set; + ast_manager& m; + iuc_proof& m_pr; + + ptr_vector m_plugins; + ast_mark m_closed; + + expr_ref_vector m_unsat_core; + public: unsat_core_learner(ast_manager& m, iuc_proof& pr) : m(m), m_pr(pr), m_unsat_core(m) {}; virtual ~unsat_core_learner(); - ast_manager& m; - iuc_proof& m_pr; + ast_manager& get_manager() {return m;} + + bool is_a(proof *pr) {return m_pr.is_a_marked(pr);} + bool is_b(proof *pr) {return m_pr.is_b_marked(pr);} + bool is_h(proof *pr) {return m_pr.is_h_marked(pr);} + bool is_b_pure(proof *pr) { return m_pr.is_b_pure(pr);} /* * register a plugin for computation of partial unsat cores @@ -67,14 +80,6 @@ namespace spacer { void add_lemma_to_core(expr* lemma); private: - ptr_vector m_plugins; - ast_mark m_closed; - - /* - * collects the lemmas of the unsat-core - * will at the end be inserted into unsat_core. - */ - expr_ref_vector m_unsat_core; /* * computes partial core for step by delegating computation to plugins diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 79bafdfeb..ef97d81df 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -34,27 +34,25 @@ Revision History: namespace spacer { - unsat_core_plugin::unsat_core_plugin(unsat_core_learner& learner): - m(learner.m), m_learner(learner) {}; + unsat_core_plugin::unsat_core_plugin(unsat_core_learner& ctx): + m(ctx.get_manager()), m_ctx(ctx) {}; void unsat_core_plugin_lemma::compute_partial_core(proof* step) { - SASSERT(m_learner.m_pr.is_a_marked(step)); - SASSERT(m_learner.m_pr.is_b_marked(step)); + SASSERT(m_ctx.is_a(step)); + SASSERT(m_ctx.is_b(step)); - for (proof* premise : m.get_parents(step)) { - - if (m_learner.is_b_open (premise)) { + for (auto* p : m.get_parents(step)) { + if (m_ctx.is_b_open (p)) { // by IH, premises that are AB marked are already closed - SASSERT(!m_learner.m_pr.is_a_marked(premise)); - add_lowest_split_to_core(premise); + SASSERT(!m_ctx.is_a(p)); + add_lowest_split_to_core(p); } } - m_learner.set_closed(step, true); + m_ctx.set_closed(step, true); } - void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const - { - SASSERT(m_learner.is_b_open(step)); + void unsat_core_plugin_lemma::add_lowest_split_to_core(proof* step) const { + SASSERT(m_ctx.is_b_open(step)); ptr_buffer todo; todo.push_back(step); @@ -64,44 +62,45 @@ namespace spacer { todo.pop_back(); // if current step hasn't been processed, - if (!m_learner.is_closed(pf)) { - m_learner.set_closed(pf, true); + if (!m_ctx.is_closed(pf)) { + m_ctx.set_closed(pf, true); // the step is b-marked and not closed. // by I.H. the step must be already visited // so if it is also a-marked, it must be closed - SASSERT(m_learner.m_pr.is_b_marked(pf)); - SASSERT(!m_learner.m_pr.is_a_marked(pf)); + SASSERT(m_ctx.is_b(pf)); + SASSERT(!m_ctx.is_a(pf)); // the current step needs to be interpolated: expr* fact = m.get_fact(pf); // if we trust the current step and we are able to use it - if (m_learner.m_pr.is_b_pure (pf) && - (m.is_asserted(pf) || is_literal(m, fact))) { + if (m_ctx.is_b_pure (pf) && (m.is_asserted(pf) || is_literal(m, fact))) { // just add it to the core - m_learner.add_lemma_to_core(fact); + m_ctx.add_lemma_to_core(fact); } // otherwise recurse on premises else { for (proof* premise : m.get_parents(pf)) - if (m_learner.is_b_open(premise)) + if (m_ctx.is_b_open(premise)) todo.push_back(premise); } - } } } - void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step) - { - SASSERT(m_learner.m_pr.is_a_marked(step)); - SASSERT(m_learner.m_pr.is_b_marked(step)); + /*** + * FARKAS + */ + void unsat_core_plugin_farkas_lemma::compute_partial_core(proof* step) { + SASSERT(m_ctx.is_a(step)); + SASSERT(m_ctx.is_b(step)); // XXX this assertion should be true so there is no need to check for it - SASSERT (!m_learner.is_closed (step)); + SASSERT (!m_ctx.is_closed (step)); func_decl* d = step->get_decl(); symbol sym; - if (!m_learner.is_closed(step) && // if step is not already interpolated - is_farkas_lemma(m, step)) { + TRACE("spacer.farkas", + tout << "looking at: " << mk_pp(step, m) << "\n";); + if (!m_ctx.is_closed(step) && is_farkas_lemma(m, step)) { // weaker check : d->get_num_parameters() >= m.get_num_parents(step) + 2 SASSERT(d->get_num_parameters() == m.get_num_parents(step) + 2); @@ -136,24 +135,24 @@ namespace spacer { parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient TRACE("spacer.farkas", - tout << "Farkas input: "<< "\n"; - for (unsigned i = 0; i < m.get_num_parents(step); ++i) { - proof * prem = m.get_parent(step, i); - rational coef = params[i].get_rational(); - bool b_pure = m_learner.m_pr.is_b_pure (prem); - tout << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; - } - ); + tout << "Farkas input: "<< "\n"; + for (unsigned i = 0; i < m.get_num_parents(step); ++i) { + proof * prem = m.get_parent(step, i); + rational coef = params[i].get_rational(); + bool b_pure = m_ctx.is_b_pure (prem); + tout << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; + } + ); - bool can_be_closed = true; + bool done = true; for (unsigned i = 0; i < m.get_num_parents(step); ++i) { proof * premise = m.get_parent(step, i); - if (m_learner.is_b_open (premise)) { - SASSERT(!m_learner.m_pr.is_a_marked(premise)); + if (m_ctx.is_b_open (premise)) { + SASSERT(!m_ctx.is_a(premise)); - if (m_learner.m_pr.is_b_pure (premise)) { + if (m_ctx.is_b_pure (premise)) { if (!m_use_constant_from_a) { rational coefficient = params[i].get_rational(); coeff_lits.push_back(std::make_pair(abs(coefficient), (app*)m.get_fact(premise))); @@ -161,7 +160,7 @@ namespace spacer { } else { // -- mixed premise, won't be able to close this proof step - can_be_closed = false; + done = false; if (m_use_constant_from_a) { rational coefficient = params[i].get_rational(); @@ -177,6 +176,7 @@ namespace spacer { } } + // TBD: factor into another method if (m_use_constant_from_a) { params += m.get_num_parents(step); // point to the first Farkas coefficient, which corresponds to a formula in the conclusion @@ -208,11 +208,9 @@ namespace spacer { // only if all b-premises can be used directly, add the farkas core and close the step // AG: this decision needs to be re-evaluated. If the proof cannot be closed, literals above // AG: it will go into the core. However, it does not mean that this literal should/could not be added. - if (can_be_closed) { - m_learner.set_closed(step, true); - expr_ref res = compute_linear_combination(coeff_lits); - m_learner.add_lemma_to_core(res); - } + m_ctx.set_closed(step, done); + expr_ref res = compute_linear_combination(coeff_lits); + m_ctx.add_lemma_to_core(res); } } @@ -236,12 +234,12 @@ namespace spacer { void unsat_core_plugin_farkas_lemma_optimized::compute_partial_core(proof* step) { - SASSERT(m_learner.m_pr.is_a_marked(step)); - SASSERT(m_learner.m_pr.is_b_marked(step)); + SASSERT(m_ctx.is_a(step)); + SASSERT(m_ctx.is_b(step)); func_decl* d = step->get_decl(); symbol sym; - if (!m_learner.is_closed(step) && // if step is not already interpolated + if (!m_ctx.is_closed(step) && // if step is not already interpolated is_farkas_lemma(m, step)) { SASSERT(d->get_num_parameters() == m.get_num_parents(step) + 2); SASSERT(m.has_fact(step)); @@ -250,25 +248,25 @@ namespace spacer { parameter const* params = d->get_parameters() + 2; // point to the first Farkas coefficient - STRACE("spacer.farkas", - verbose_stream() << "Farkas input: "<< "\n"; - for (unsigned i = 0; i < m.get_num_parents(step); ++i) { - proof * prem = m.get_parent(step, i); - rational coef = params[i].get_rational(); - bool b_pure = m_learner.m_pr.is_b_pure (prem); - verbose_stream() << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m_learner.m) << "\n"; - } - ); + TRACE("spacer.farkas", + tout << "Farkas input: "<< "\n"; + for (unsigned i = 0; i < m.get_num_parents(step); ++i) { + proof * prem = m.get_parent(step, i); + rational coef = params[i].get_rational(); + bool b_pure = m_ctx.is_b_pure (prem); + tout << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; + } + ); bool can_be_closed = true; for (unsigned i = 0; i < m.get_num_parents(step); ++i) { proof * premise = m.get_parent(step, i); - if (m_learner.m_pr.is_b_marked(premise) && !m_learner.is_closed(premise)) + if (m_ctx.is_b(premise) && !m_ctx.is_closed(premise)) { - SASSERT(!m_learner.m_pr.is_a_marked(premise)); + SASSERT(!m_ctx.is_a(premise)); - if (m_learner.m_pr.is_b_pure(premise)) + if (m_ctx.is_b_pure(premise)) { rational coefficient = params[i].get_rational(); linear_combination.push_back @@ -284,7 +282,7 @@ namespace spacer { // only if all b-premises can be used directly, close the step and add linear combinations for later processing if (can_be_closed) { - m_learner.set_closed(step, true); + m_ctx.set_closed(step, true); if (!linear_combination.empty()) { m_linear_combinations.push_back(linear_combination); @@ -350,7 +348,7 @@ namespace spacer { SASSERT(!coeff_lits.empty()); expr_ref linear_combination = compute_linear_combination(coeff_lits); - m_learner.add_lemma_to_core(linear_combination); + m_ctx.add_lemma_to_core(linear_combination); } } @@ -481,7 +479,7 @@ namespace spacer { SASSERT(!coeff_lits.empty()); // since then previous outer loop would have found solution already expr_ref linear_combination = compute_linear_combination(coeff_lits); - m_learner.add_lemma_to_core(linear_combination); + m_ctx.add_lemma_to_core(linear_combination); } return; } @@ -505,10 +503,10 @@ namespace spacer { { ptr_vector todo; - SASSERT(m_learner.m_pr.is_a_marked(step)); - SASSERT(m_learner.m_pr.is_b_marked(step)); + SASSERT(m_ctx.is_a(step)); + SASSERT(m_ctx.is_b(step)); SASSERT(m.get_num_parents(step) > 0); - SASSERT(!m_learner.is_closed(step)); + SASSERT(!m_ctx.is_closed(step)); todo.push_back(step); while (!todo.empty()) @@ -517,7 +515,7 @@ namespace spacer { todo.pop_back(); // if we need to deal with the node and if we haven't added the corresponding edges so far - if (!m_learner.is_closed(current) && !m_visited.is_marked(current)) + if (!m_ctx.is_closed(current) && !m_visited.is_marked(current)) { // compute smallest subproof rooted in current, which has only good edges // add an edge from current to each leaf of that subproof @@ -528,7 +526,7 @@ namespace spacer { } } - m_learner.set_closed(step, true); + m_ctx.set_closed(step, true); } @@ -539,7 +537,7 @@ namespace spacer { ptr_buffer todo_subproof; for (proof* premise : m.get_parents(step)) { - if (m_learner.m_pr.is_b_marked(premise)) { + if (m_ctx.is_b(premise)) { todo_subproof.push_back(premise); } } @@ -549,21 +547,21 @@ namespace spacer { todo_subproof.pop_back(); // if we need to deal with the node - if (!m_learner.is_closed(current)) + if (!m_ctx.is_closed(current)) { - SASSERT(!m_learner.m_pr.is_a_marked(current)); // by I.H. the step must be already visited + SASSERT(!m_ctx.is_a(current)); // by I.H. the step must be already visited // and the current step needs to be interpolated: - if (m_learner.m_pr.is_b_marked(current)) + if (m_ctx.is_b(current)) { // if we trust the current step and we are able to use it - if (m_learner.m_pr.is_b_pure (current) && + if (m_ctx.is_b_pure (current) && (m.is_asserted(current) || is_literal(m, m.get_fact(current)))) { // we found a leaf of the subproof, so // 1) we add corresponding edges - if (m_learner.m_pr.is_a_marked(step)) + if (m_ctx.is_a(step)) { add_edge(nullptr, current); // current is sink } @@ -685,7 +683,7 @@ namespace spacer { m_min_cut.compute_min_cut(cut_nodes); for (unsigned cut_node : cut_nodes) { - m_learner.add_lemma_to_core(m_node_to_formula[cut_node]); + m_ctx.add_lemma_to_core(m_node_to_formula[cut_node]); } } } diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index c05bcc5b9..746f21b19 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -35,14 +35,14 @@ namespace spacer { virtual ~unsat_core_plugin() {}; virtual void compute_partial_core(proof* step) = 0; virtual void finalize(){}; - - unsat_core_learner& m_learner; + + unsat_core_learner& m_ctx; }; - class unsat_core_plugin_lemma : public unsat_core_plugin { + class unsat_core_plugin_lemma : public unsat_core_plugin { public: - unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){}; - void compute_partial_core(proof* step) override; + unsat_core_plugin_lemma(unsat_core_learner& learner) : unsat_core_plugin(learner){}; + void compute_partial_core(proof* step) override; private: void add_lowest_split_to_core(proof* step) const; }; @@ -54,7 +54,7 @@ namespace spacer { bool use_constant_from_a=true) : unsat_core_plugin(learner), m_split_literals(split_literals), - m_use_constant_from_a(use_constant_from_a) {}; + m_use_constant_from_a(use_constant_from_a) {}; void compute_partial_core(proof* step) override; private: bool m_split_literals; @@ -64,8 +64,8 @@ namespace spacer { */ expr_ref compute_linear_combination(const coeff_lits_t& coeff_lits); }; - - class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin { + + class unsat_core_plugin_farkas_lemma_optimized : public unsat_core_plugin { public: unsat_core_plugin_farkas_lemma_optimized(unsat_core_learner& learner, ast_manager& m) : unsat_core_plugin(learner) {}; void compute_partial_core(proof* step) override; From 7b2ca769ef75b46a5fff7fa4fd32f5673f7f8b61 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Thu, 21 Jun 2018 23:36:37 -0400 Subject: [PATCH 1279/1283] Cleanup --- src/muz/spacer/spacer_proof_utils.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index c7d7ffb54..aa7f611c8 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -94,10 +94,11 @@ namespace spacer { family_id tid = m.mk_family_id(params[0].get_symbol()); SASSERT(tid != null_family_id); - proof *pf = m.mk_th_lemma(tid, m.mk_false(), - parents.size(), parents.c_ptr(), - v.size(), v.c_ptr()); - return proof_ref(pf, m); + proof_ref pf(m); + pf = m.mk_th_lemma(tid, m.mk_false(), + parents.size(), parents.c_ptr(), + v.size(), v.c_ptr()); + return pf; } // convert assign-bounds lemma to a farkas lemma by adding missing coeff From 1764bb8785ed7b1c9262236198672b7042a42d9f Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 23 Jun 2018 00:05:14 -0400 Subject: [PATCH 1280/1283] Cleaning up unsat_core_learner --- src/muz/spacer/spacer_unsat_core_learner.cpp | 5 +---- src/muz/spacer/spacer_unsat_core_learner.h | 10 ++++++++-- src/muz/spacer/spacer_unsat_core_plugin.cpp | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index 08f7f7ce8..730ef1629 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -54,7 +54,7 @@ void unsat_core_learner::compute_unsat_core(expr_ref_vector& unsat_core) { // if the node mixes A-reasoning and B-reasoning // and contains non-closed premises if (!done) { - if (m_pr.is_a_marked(curr) && m_pr.is_b_marked(curr)) { + if (is_a(curr) && is_b(curr)) { compute_partial_core(curr); } } @@ -92,9 +92,6 @@ void unsat_core_learner::set_closed(proof* p, bool value) { m_closed.mark(p, value); } -bool unsat_core_learner::is_b_open(proof *p) { - return m_pr.is_b_marked(p) && !is_closed (p); -} void unsat_core_learner::add_lemma_to_core(expr* lemma) { m_unsat_core.push_back(lemma); diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 42ad71501..ead430ca0 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -47,10 +47,17 @@ namespace spacer { ast_manager& get_manager() {return m;} - bool is_a(proof *pr) {return m_pr.is_a_marked(pr);} + + bool is_a(proof *pr) { + // AG: treat hypotheses as A + // AG: assume that all B-hyp have been eliminated + // AG: this is not yet true in case of arithmetic eq_prop + return m_pr.is_a_marked(pr) || is_h(pr); + } bool is_b(proof *pr) {return m_pr.is_b_marked(pr);} bool is_h(proof *pr) {return m_pr.is_h_marked(pr);} bool is_b_pure(proof *pr) { return m_pr.is_b_pure(pr);} + bool is_b_open(proof *p) {return m_pr.is_b_marked(p) && !is_closed (p);} /* * register a plugin for computation of partial unsat cores @@ -72,7 +79,6 @@ namespace spacer { bool is_closed(proof* p); void set_closed(proof* p, bool value); - bool is_b_open (proof *p); /* * adds a lemma to the unsat core diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index ef97d81df..aeb509c2e 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -210,6 +210,7 @@ namespace spacer { // AG: it will go into the core. However, it does not mean that this literal should/could not be added. m_ctx.set_closed(step, done); expr_ref res = compute_linear_combination(coeff_lits); + TRACE("spacer.farkas", tout << "Farkas core: " << res << "\n";); m_ctx.add_lemma_to_core(res); } } From 8e57ab5d9753f4eb1b650e25656dde694efdd74d Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 23 Jun 2018 00:05:53 -0400 Subject: [PATCH 1281/1283] Computing missing coeff for assign-bounds lemma --- src/muz/spacer/spacer_proof_utils.cpp | 222 +++++++++++++++++++++++++- 1 file changed, 218 insertions(+), 4 deletions(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index aa7f611c8..ea91a7d04 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -73,6 +73,129 @@ namespace spacer { + class linear_combinator { + struct scaled_lit { + bool is_pos; + app *lit; + rational coeff; + scaled_lit(bool is_pos, app *lit, const rational &coeff) : + is_pos(is_pos), lit(lit), coeff(coeff) {} + }; + ast_manager &m; + th_rewriter m_rw; + arith_util m_arith; + expr_ref m_sum; + bool m_is_strict; + rational m_lc; + vector m_lits; + public: + linear_combinator(ast_manager &m) : m(m), m_rw(m), m_arith(m), + m_sum(m), m_is_strict(false), + m_lc(1) {} + + void add_lit(app* lit, rational const &coeff, bool is_pos = true) { + m_lits.push_back(scaled_lit(is_pos, lit, coeff)); + } + + void normalize_coeff() { + for (auto &lit : m_lits) + m_lc = lcm(m_lc, denominator(lit.coeff)); + if (!m_lc.is_one()) { + for (auto &lit : m_lits) + lit.coeff *= m_lc; + } + } + + rational const &lc() const {return m_lc;} + + bool process_lit(scaled_lit &lit0) { + arith_util a(m); + app* lit = lit0.lit; + rational &coeff = lit0.coeff; + bool is_pos = lit0.is_pos; + + + if (m.is_not(lit)) { + lit = to_app(lit->get_arg(0)); + is_pos = !is_pos; + } + if (!m_arith.is_le(lit) && !m_arith.is_lt(lit) && + !m_arith.is_ge(lit) && !m_arith.is_gt(lit) && !m.is_eq(lit)) { + return false; + } + SASSERT(lit->get_num_args() == 2); + sort* s = m.get_sort(lit->get_arg(0)); + bool is_int = m_arith.is_int(s); + if (!is_int && m_arith.is_int_expr(lit->get_arg(0))) { + is_int = true; + s = m_arith.mk_int(); + } + + if (!is_int && is_pos && (m_arith.is_gt(lit) || m_arith.is_lt(lit))) { + m_is_strict = true; + } + if (!is_int && !is_pos && (m_arith.is_ge(lit) || m_arith.is_le(lit))) { + m_is_strict = true; + } + + + SASSERT(m_arith.is_int(s) || m_arith.is_real(s)); + expr_ref sign1(m), sign2(m), term(m); + sign1 = m_arith.mk_numeral(m.is_eq(lit)?coeff:abs(coeff), s); + sign2 = m_arith.mk_numeral(m.is_eq(lit)?-coeff:-abs(coeff), s); + if (!m_sum.get()) { + m_sum = m_arith.mk_numeral(rational(0), s); + } + + expr* a0 = lit->get_arg(0); + expr* a1 = lit->get_arg(1); + + if (is_pos && (m_arith.is_ge(lit) || m_arith.is_gt(lit))) { + std::swap(a0, a1); + } + if (!is_pos && (m_arith.is_le(lit) || m_arith.is_lt(lit))) { + std::swap(a0, a1); + } + + // + // Multiplying by coefficients over strict + // and non-strict inequalities: + // + // (a <= b) * 2 + // (a - b <= 0) * 2 + // (2a - 2b <= 0) + + // (a < b) * 2 <=> + // (a +1 <= b) * 2 <=> + // 2a + 2 <= 2b <=> + // 2a+2-2b <= 0 + + bool strict_ineq = + is_pos?(m_arith.is_gt(lit) || m_arith.is_lt(lit)):(m_arith.is_ge(lit) || m_arith.is_le(lit)); + + if (is_int && strict_ineq) { + m_sum = m_arith.mk_add(m_sum, sign1); + } + + term = m_arith.mk_mul(sign1, a0); + m_sum = m_arith.mk_add(m_sum, term); + term = m_arith.mk_mul(sign2, a1); + m_sum = m_arith.mk_add(m_sum, term); + + m_rw(m_sum); + return true; + } + + expr_ref operator()(){ + if (!m_sum) normalize_coeff(); + m_sum.reset(); + for (auto &lit : m_lits) { + if (!process_lit(lit)) return expr_ref(m); + } + return m_sum; + } + }; + /* * ==================================== * methods for transforming proofs @@ -101,6 +224,60 @@ namespace spacer { return pf; } + static bool match_mul(expr *e, expr_ref &var, expr_ref &val, arith_util &a) { + expr *e1 = nullptr, *e2 = nullptr; + if (!a.is_mul(e, e1, e2)) { + if (a.is_numeral(e)) return false; + if (!var || var == e) { + var = e; + val = a.mk_numeral(rational(1), get_sort(e)); + return true; + } + return false; + } + + if (!a.is_numeral(e1)) std::swap(e1, e2); + if (!a.is_numeral(e1)) return false; + + // if variable is given, match it as well + if (!var || var == e2) { + var = e2; + val = e1; + return true; + } + return false; + } + + static expr_ref get_coeff(expr *lit0, expr_ref &var) { + ast_manager &m = var.m(); + arith_util a(m); + + expr *lit = nullptr; + if (!m.is_not(lit0, lit)) lit = lit0; + + expr *e1 = nullptr, *e2 = nullptr; + // assume e2 is numeral and ignore it + if ((a.is_le(lit, e1, e2) || a.is_lt(lit, e1, e2) || + a.is_ge(lit, e1, e2) || a.is_gt(lit, e1, e2) || + m.is_eq(lit, e1, e2))) { + if (a.is_numeral(e1)) std::swap(e1, e2); + } + else { + e1 = lit; + } + + expr_ref val(m); + if (!a.is_add(e1)) { + if (match_mul(e1, var, val, a)) return val; + } + else { + for (auto *arg : *to_app(e1)) { + if (match_mul(arg, var, val, a)) return val; + } + } + return expr_ref(m); + } + // convert assign-bounds lemma to a farkas lemma by adding missing coeff // assume that missing coeff is for premise at position 0 static proof_ref mk_fk_from_ab(ast_manager &m, @@ -108,9 +285,44 @@ namespace spacer { unsigned num_params, parameter const *params) { SASSERT(num_params == parents.size() + 1 /* one param is missing */); + + // compute missing coefficient + linear_combinator lcb(m); + for (unsigned i = 1, sz = parents.size(); i < sz; ++i) { + app *p = to_app(m.get_fact(parents.get(i))); + rational const &r = params[i+1].get_rational(); + lcb.add_lit(p, r); + } + + TRACE("spacer.fkab", + tout << "lit0 is: " << mk_pp(m.get_fact(parents.get(0)), m) << "\n" + << "LCB is: " << lcb() << "\n";); + + expr_ref var(m), val1(m), val2(m); + val1 = get_coeff(m.get_fact(parents.get(0)), var); + val2 = get_coeff(lcb(), var); + TRACE("spacer.fkab", + tout << "var: " << var + << " val1: " << val1 << " val2: " << val2 << "\n";); + + rational rat1, rat2, coeff0; + arith_util a(m); + if (a.is_numeral(val1, rat1) && a.is_numeral(val2, rat2)) { + coeff0 = abs(rat2/rat1); + coeff0 = coeff0 / lcb.lc(); + TRACE("spacer.fkab", tout << "coeff0: " << coeff0 << "\n";); + } + else { + IF_VERBOSE(1, verbose_stream() + << "\n\n\nFAILED TO FIND COEFFICIENT\n\n\n";); + // failed to find a coefficient + return proof_ref(m); + } + + buffer v; v.push_back(parameter(symbol("farkas"))); - v.push_back(parameter(rational(1))); + v.push_back(parameter(coeff0)); for (unsigned i = 2; i < num_params; ++i) v.push_back(params[i]); @@ -124,11 +336,11 @@ namespace spacer { v.size(), v.c_ptr()); SASSERT(is_arith_lemma(m, pf)); + DEBUG_CODE( proof_checker pc(m); expr_ref_vector side(m); - SASSERT(pc.check(pf, side)); - ); + ENSURE(pc.check(pf, side));); return pf; } @@ -179,7 +391,9 @@ namespace spacer { d->get_num_parameters(), d->get_parameters()); } - else { + + // fall back to th-lemma + if (!th_lemma) { th_lemma = mk_th_lemma(m, hyps, d->get_num_parameters(), d->get_parameters()); From e9069309229259f9c13b38d01f4ca00104351772 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 23 Jun 2018 00:06:27 -0400 Subject: [PATCH 1282/1283] Debug code --- src/muz/spacer/spacer_iuc_solver.cpp | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index a68db4c0a..27b8ee357 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -322,6 +322,24 @@ void iuc_solver::get_iuc(expr_ref_vector &core) // -- new hypothesis reducer else { +#if 0 + static unsigned bcnt = 0; + { + bcnt++; + TRACE("spacer", tout << "Dumping pf bcnt: " << bcnt << "\n";); + if (bcnt == 123) { + std::ofstream ofs; + ofs.open("/tmp/bpf_" + std::to_string(bcnt) + ".dot"); + iuc_proof iuc_pf_before(m, res.get(), core_lits); + iuc_pf_before.display_dot(ofs); + ofs.close(); + + proof_checker pc(m); + expr_ref_vector side(m); + ENSURE(pc.check(res, side)); + } + } +#endif scoped_watch _t_ (m_hyp_reduce2_sw); // pre-process proof for better iuc extraction @@ -356,6 +374,22 @@ void iuc_solver::get_iuc(expr_ref_vector &core) iuc_proof iuc_pf(m, res, core_lits); +#if 0 + static unsigned cnt = 0; + { + cnt++; + TRACE("spacer", tout << "Dumping pf cnt: " << cnt << "\n";); + if (cnt == 123) { + std::ofstream ofs; + ofs.open("/tmp/pf_" + std::to_string(cnt) + ".dot"); + iuc_pf.display_dot(ofs); + ofs.close(); + proof_checker pc(m); + expr_ref_vector side(m); + ENSURE(pc.check(res, side)); + } + } +#endif unsat_core_learner learner(m, iuc_pf); unsat_core_plugin* plugin; From f330b96a3555b485a12acfc5c3a2f597b4c4313a Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sun, 24 Jun 2018 21:03:09 -0400 Subject: [PATCH 1283/1283] Gracefully failing in assign-bounds to farkas --- src/muz/spacer/spacer_proof_utils.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index ea91a7d04..dc3bbf30c 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -307,7 +307,10 @@ namespace spacer { rational rat1, rat2, coeff0; arith_util a(m); - if (a.is_numeral(val1, rat1) && a.is_numeral(val2, rat2)) { + CTRACE("spacer.fkab", !(val1 && val2), + tout << "Failed to match variables\n";); + if (val1 && val2 && + a.is_numeral(val1, rat1) && a.is_numeral(val2, rat2)) { coeff0 = abs(rat2/rat1); coeff0 = coeff0 / lcb.lc(); TRACE("spacer.fkab", tout << "coeff0: " << coeff0 << "\n";);